Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save abhik1368/636e6c34393ad6c00356ec476aae77ad to your computer and use it in GitHub Desktop.
Save abhik1368/636e6c34393ad6c00356ec476aae77ad to your computer and use it in GitHub Desktop.
Reverie Transformer
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Reverie Transformer",
"provenance": [],
"collapsed_sections": [],
"toc_visible": true,
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/gabegrand/36000dff03968cb26a49462755a5abb0/reverie-transformer.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "AUZLz0xcqi2F",
"colab_type": "text"
},
"source": [
"Copyright (c) 2020 Reverie Labs. All rights reserved.\n",
"This work is licensed under the terms of the MIT license <https://opensource.org/licenses/MIT>."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "OE7QgQ6iSvfC",
"colab_type": "text"
},
"source": [
"# **Training Transformers for Practical Drug Discovery with Tensor2Tensor**\n",
"\n",
"This Colab is designed to take you end-to-end with the Transformer on a toy problem from the [QM9 dataset](http://quantum-machine.org/datasets/). We'll walk through everything from data preprocessing and tokenization, to training a Transformer model, to decoding predictions on new SMILES strings.\n",
"\n",
"For a full intro, please see our [blog post](https://blog.reverielabs.com/) that accompanies this Colab."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Evb4tFxY_wHt",
"colab_type": "text"
},
"source": [
"## Setup"
]
},
{
"cell_type": "code",
"metadata": {
"id": "iALD89upaFNH",
"colab_type": "code",
"outputId": "955b4faf-5850-4e6c-91ad-e538f54a299d",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 51
}
},
"source": [
"# Tensor2Tensor is not currently fully compatible with TF 2.0\n",
"%tensorflow_version 1.x\n",
"import tensorflow as tf\n",
"print(tf.__version__)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"TensorFlow 1.x selected.\n",
"1.15.2\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nuogReE8_zx3",
"colab_type": "text"
},
"source": [
"### Configure Colab for GPU\n",
"\n",
"To train the Transformer, we'll want to use a GPU-enabled Colab runtime. To set this up, select `Runtime > Change runtime type` and set `Hardware accelerator` to `GPU`.\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "FNmhY5NZazXp",
"colab_type": "code",
"outputId": "c6bcb311-61fd-4500-9814-9d133c50aace",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"# Check GPU is available\n",
"device_name = tf.test.gpu_device_name()\n",
"if device_name != \"/device:GPU:0\":\n",
" raise SystemError(\n",
" \"GPU device not found. \"\n",
" \"Please select Runtime > Change runtime type and set Hardware acceletator to GPU.\"\n",
" )\n",
"print(f\"Found GPU at: {device_name}\")"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"Found GPU at: /device:GPU:0\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ZswuSVWtTLqA",
"colab_type": "text"
},
"source": [
"### Setup Tensor2Tensor"
]
},
{
"cell_type": "code",
"metadata": {
"id": "UYmwePjTRNL9",
"colab_type": "code",
"colab": {}
},
"source": [
"!pip install tensor2tensor==1.15.0"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "adVXsQ1OQRQ8",
"colab_type": "code",
"colab": {}
},
"source": [
"# Check that T2T installed correctly. \n",
"# This command should print a list of Models, HParams, and Problems that come pre-installed with T2T.\n",
"!t2t-trainer --registry_help"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "-_Iun1qBePsg",
"colab_type": "text"
},
"source": [
"### Package imports\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "vXvJDVRVeXt8",
"colab_type": "code",
"colab": {}
},
"source": [
"import os\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import s3fs\n",
"import seaborn as sns\n",
"\n",
"from scipy.stats import pearsonr\n",
"from sklearn.metrics import mean_squared_error\n",
"from tensor2tensor.data_generators.problem import Problem\n",
"from tensor2tensor.data_generators.text_encoder import TokenTextEncoder\n",
"from tqdm import tqdm"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "QwMs6QiFhk9x",
"colab_type": "text"
},
"source": [
"## Problem definition\n",
"\n",
"Tensor2Tensor uses environment variables to configure what dataset to train on (a.k.a., a \"Problem\"), what model architecture to use, and what hyperparameter set to use.\n",
"\n",
"Here, we'll call our Problem `homo_lumo_gap` (more info on this later). We'll use the `transformer` architecture with the `transformer_tiny` HParams set, which has about 1M parameters. One nice aspect of T2T is that we can easily scale up the model by swapping out the HParams set for a larger model. For large-scale training, you'll likely see best performance with 10s or even 100s of millions of parameters!"
]
},
{
"cell_type": "code",
"metadata": {
"id": "76t7w2ppi2s7",
"colab_type": "code",
"colab": {}
},
"source": [
"# T2T setup\n",
"os.environ[\"PROBLEM\"] = \"homo_lumo_gap\"\n",
"os.environ[\"MODEL\"] = \"transformer\"\n",
"os.environ[\"HPARAMS\"] = \"transformer_tiny\"\n",
"\n",
"# Define directories that T2T uses\n",
"os.environ[\"USR_DIR\"] = \"reverie/problems\"\n",
"os.environ[\"DATA_DIR\"] = os.path.join(\"t2t_data\", os.environ[\"PROBLEM\"])\n",
"os.environ[\"TRAIN_DIR\"] = os.path.join(\"t2t_train\", os.environ[\"HPARAMS\"])\n",
"os.environ[\"TMP_DIR\"] = \"/tmp/t2t_datagen\""
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "sJMCuMCaiaff",
"colab_type": "code",
"outputId": "a17d49f3-23ad-4b91-f79e-4932ca968674",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 85
}
},
"source": [
"%%bash\n",
"mkdir -p $USR_DIR $DATA_DIR $TRAIN_DIR $TMP_DIR\n",
"echo $USR_DIR\n",
"echo $DATA_DIR\n",
"echo $TRAIN_DIR\n",
"echo $TMP_DIR"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"reverie/problems\n",
"t2t_data/homo_lumo_gap\n",
"t2t_train/transformer_tiny\n",
"/tmp/t2t_datagen\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "7QVPeEwNB0fy",
"colab_type": "text"
},
"source": [
"## Dataset preprocessing\n",
"\n",
"In this section, we'll load up a dataset and preprocess it with the Reverie SmilesTokenizer to produce TFRecords that our T2T model can ingest."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "NJhgwBi7e3eo",
"colab_type": "text"
},
"source": [
"### Load QM9 Dataset\n",
"\n",
"For this Colab, we'll be using the popular [QM9 dataset](http://quantum-machine.org/datasets/), which contains 134K molecular structures and various properties that were computed to a high degree of accuracy using quantum-mechanical (QM) calclations.\n",
"\n",
"In this exercise, we'll focus on predicting the HOMO-LUMO gap, which refers to the energy difference between the *highest occupied molecular orbital* (HOMO) and *lowest unoccupied molecular orbital* (LUMO) of a molecule. The HOMO-LUMO gap is a key index of organic reactivity, and has important applications to materials science — in particular, in the field of [organic photovoltaics](https://dash.harvard.edu/bitstream/handle/1/8364968/Harvard_Clean_Energy_Project.pdf?sequence=1) it is used to design renewable energy sources.\n",
"\n",
"It can take hours or days to compute the HOMO-LUMO gap of a single molecule using denisty functional theory (DFT) calculations. However, as we'll see, a well-tuned ML model can approximate this computation to a high degree of accuracy in milliseconds."
]
},
{
"cell_type": "code",
"metadata": {
"id": "sU_xJOtue8z7",
"colab_type": "code",
"colab": {}
},
"source": [
"df = pd.read_csv(\"https://reverie-public.s3.amazonaws.com/transformer/qm9.csv\")"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "qbAtE437ZT5W",
"colab_type": "code",
"outputId": "a67afcb4-25e5-437c-d916-ffb3bc542bf4",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 204
}
},
"source": [
"df.head()"
],
"execution_count": 0,
"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>mol_id</th>\n",
" <th>smiles</th>\n",
" <th>C</th>\n",
" <th>mu</th>\n",
" <th>alpha</th>\n",
" <th>homo</th>\n",
" <th>lumo</th>\n",
" <th>gap</th>\n",
" <th>r2</th>\n",
" <th>zpve</th>\n",
" <th>u0</th>\n",
" <th>u298</th>\n",
" <th>h298</th>\n",
" <th>g298</th>\n",
" <th>cv</th>\n",
" <th>u0_atom</th>\n",
" <th>u298_atom</th>\n",
" <th>h298_atom</th>\n",
" <th>g298_atom</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>gdb_1</td>\n",
" <td>C</td>\n",
" <td>157.706990</td>\n",
" <td>0.0000</td>\n",
" <td>13.21</td>\n",
" <td>-0.3877</td>\n",
" <td>0.1171</td>\n",
" <td>0.5048</td>\n",
" <td>35.3641</td>\n",
" <td>0.044749</td>\n",
" <td>-40.478930</td>\n",
" <td>-40.476062</td>\n",
" <td>-40.475117</td>\n",
" <td>-40.498597</td>\n",
" <td>6.469</td>\n",
" <td>-395.999595</td>\n",
" <td>-398.643290</td>\n",
" <td>-401.014647</td>\n",
" <td>-372.471772</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>gdb_2</td>\n",
" <td>N</td>\n",
" <td>191.393970</td>\n",
" <td>1.6256</td>\n",
" <td>9.46</td>\n",
" <td>-0.2570</td>\n",
" <td>0.0829</td>\n",
" <td>0.3399</td>\n",
" <td>26.1563</td>\n",
" <td>0.034358</td>\n",
" <td>-56.525887</td>\n",
" <td>-56.523026</td>\n",
" <td>-56.522082</td>\n",
" <td>-56.544961</td>\n",
" <td>6.316</td>\n",
" <td>-276.861363</td>\n",
" <td>-278.620271</td>\n",
" <td>-280.399259</td>\n",
" <td>-259.338802</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>gdb_3</td>\n",
" <td>O</td>\n",
" <td>282.945450</td>\n",
" <td>1.8511</td>\n",
" <td>6.31</td>\n",
" <td>-0.2928</td>\n",
" <td>0.0687</td>\n",
" <td>0.3615</td>\n",
" <td>19.0002</td>\n",
" <td>0.021375</td>\n",
" <td>-76.404702</td>\n",
" <td>-76.401867</td>\n",
" <td>-76.400922</td>\n",
" <td>-76.422349</td>\n",
" <td>6.002</td>\n",
" <td>-213.087624</td>\n",
" <td>-213.974294</td>\n",
" <td>-215.159658</td>\n",
" <td>-201.407171</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>gdb_4</td>\n",
" <td>C#C</td>\n",
" <td>35.610036</td>\n",
" <td>0.0000</td>\n",
" <td>16.28</td>\n",
" <td>-0.2845</td>\n",
" <td>0.0506</td>\n",
" <td>0.3351</td>\n",
" <td>59.5248</td>\n",
" <td>0.026841</td>\n",
" <td>-77.308427</td>\n",
" <td>-77.305527</td>\n",
" <td>-77.304583</td>\n",
" <td>-77.327429</td>\n",
" <td>8.574</td>\n",
" <td>-385.501997</td>\n",
" <td>-387.237686</td>\n",
" <td>-389.016047</td>\n",
" <td>-365.800724</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>gdb_5</td>\n",
" <td>C#N</td>\n",
" <td>44.593883</td>\n",
" <td>2.8937</td>\n",
" <td>12.99</td>\n",
" <td>-0.3604</td>\n",
" <td>0.0191</td>\n",
" <td>0.3796</td>\n",
" <td>48.7476</td>\n",
" <td>0.016601</td>\n",
" <td>-93.411888</td>\n",
" <td>-93.409370</td>\n",
" <td>-93.408425</td>\n",
" <td>-93.431246</td>\n",
" <td>6.278</td>\n",
" <td>-301.820534</td>\n",
" <td>-302.906752</td>\n",
" <td>-304.091489</td>\n",
" <td>-288.720028</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" mol_id smiles C ... u298_atom h298_atom g298_atom\n",
"0 gdb_1 C 157.706990 ... -398.643290 -401.014647 -372.471772\n",
"1 gdb_2 N 191.393970 ... -278.620271 -280.399259 -259.338802\n",
"2 gdb_3 O 282.945450 ... -213.974294 -215.159658 -201.407171\n",
"3 gdb_4 C#C 35.610036 ... -387.237686 -389.016047 -365.800724\n",
"4 gdb_5 C#N 44.593883 ... -302.906752 -304.091489 -288.720028\n",
"\n",
"[5 rows x 19 columns]"
]
},
"metadata": {
"tags": []
},
"execution_count": 9
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "9Aez5YX3Ym8r",
"colab_type": "code",
"outputId": "6a2e40ad-4e47-42c1-ba6d-f7b8127216e3",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 170
}
},
"source": [
"# Some summary statistics of the HOMO-LUMO gap values in QM9\n",
"df[\"gap\"].describe()"
],
"execution_count": 0,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"count 133885.000000\n",
"mean 0.251100\n",
"std 0.047519\n",
"min 0.024600\n",
"25% 0.216300\n",
"50% 0.249400\n",
"75% 0.288200\n",
"max 0.622100\n",
"Name: gap, dtype: float64"
]
},
"metadata": {
"tags": []
},
"execution_count": 10
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "Ypt56axlqMTj",
"colab_type": "code",
"outputId": "bf0b95be-603d-4db2-e0b7-425d40b0ca0e",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 296
}
},
"source": [
"sns.distplot(df[\"gap\"])"
],
"execution_count": 0,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x7fc73b5fb7f0>"
]
},
"metadata": {
"tags": []
},
"execution_count": 11
},
{
"output_type": "display_data",
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAWoAAAEGCAYAAABM7t/CAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0\ndHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nO3deXCb933n8fcXJwnwFG/qli1bthw7\ndpQ4jXPVSTNukzhJ03bTNJ1JL093k6a7yUzTnSbT7XZn0mO3s5lttxk3bdJMo1yO23Wdo7Udp2nc\nWrZs2ZJ1+NBFUSTF+yZAAvjtHyAoSiJFUCbwPMDzec1oBgQB6guB/PCn7/M7zDmHiIj4V8jrAkRE\n5OoU1CIiPqegFhHxOQW1iIjPKahFRHwuUoov2tra6nbs2FGKLy0iUpWeeeaZYedc20qfK0lQ79ix\ng4MHD5biS4uIVCUzO7va59T6EBHxOQW1iIjPKahFRHxOQS0i4nMKahERn1NQi4j4nIJaRMTnFNQi\nIj6noBYR8bmSrEyU6rH/QM8V9334zm0eVCISXBpRi4j4nIJaRMTnFNQiIj6noJY15ZzjS0+c5slT\nI16XIhJICmpZ0/Pnxnl5cJqXL0x5XYpIICmo5aqyOcdjJwYBGJtd8LgakWBSUMtVHTw7yujMPO31\nccZm53HOeV2SSOAoqGVVqYUsj58YZNumBPt2bCKdyTE3n/W6LJHAUVDLqn700hCTqQx372lnUyIK\nwOjsvMdViQSPVibKqs6PzwHQ3VTLVCrfn1afWqT8FNSyqv6JFJGQkYyFiYQMgLEZjahFyk2tD1lV\n/0SKhtooZkZNNExtNMyYWh8iZaegllX1j8/RWBtd+rg5GVVQi3hAQS2r6p9IXRrUiRhjM+pRi5Sb\nglpWlM05LkyuENSaSy1SdgpqWdHwdJpMzl3W+oiRyTmGptIeViYSPApqWVH/RArgshF1/va5sTlP\nahIJKgW1rKh/cQ715a0PgN6xWU9qEgkqBbWsaOURdT6oz40qqEXKSUEtK+qfmCMeCZGIhZfui0VC\nJOMRetX6ECkrBbWsqG8iRVdjDWZ2yf2bElHOqfUhUlYKalnRwESKrsbaK+5vTsY4N6oRtUg5Kahl\nRf3jc3Q11Vxxf3MiRt/4HLmc5lKLlIuCWq6QzTkuTKXparwyqOtrImRyTkvJRcqoqKA2s/9iZkfN\n7AUz+5qZXfkTLFVjaCpNNudWbH3UxfMbLg5PK6hFymXNoDazzcAngH3OuVuAMPChUhcm3umfyPeg\nVx5R56fraXWiSPkU2/qIALVmFgESQF/pShKvFeZQrzSirl8cUQ9Np8pak0iQrRnUzrnzwP8EeoB+\nYMI598+XP87M7jOzg2Z2cGhoaOMrlbLpWzrZ5coRdV3NYutjSq0PkXIppvXRDLwP2Al0A0kz+8jl\nj3PO3e+c2+ec29fW1rbxlUrZDEykqImGLlmVWBCPhIhHQgxNq/UhUi7FtD7eCZx2zg055xaAB4E3\nlbYs8VL/4hzqyxe7AJgZrXVx9ahFyqiYoO4B3mhmCcv/5L4DOF7assRLFyZTdDTEV/18W32cYY2o\nRcqmmB71AeAB4FngyOJz7i9xXeKhoek07fWrz8Bsq9eIWqScijqF3Dn3+8Dvl7gW8QHnHIOTadrr\nVx9Rt9bFOdQzVsaqRIJNKxPlEtPpDHMLWdquEtRt9XFGZubJZHNlrEwkuBTUcolCS6N9jR61czA6\noyl6IuWgoJZLDBaC+mo96rr8AQKaoidSHgpquUQhqNdqfYCWkYuUi4JaLrHU+ljjYuLyx4pIaSmo\n5RKDUyli4ZVXJRYUglo76ImUh4JaLjE0maatPr7iqsSCZDxCMhbWiFqkTBTUcomh6fRV+9MFrVqd\nKFI2Cmq5xFqLXQratN+HSNkUtTJRqt/+Az0AnBubpTERXfp4NW31cV4enC5HaSKBpxG1LMnkcszO\nZ6mvWfv3d2udWh8i5aKgliXTqQwADfHVZ3wUtNXHGZ9dIJ3JlroskcBTUMuSqcWgrityRA0woil6\nIiWnoJYl0+l8UBfT+ijMDFH7Q6T0FNSyZDK1AFw8afxqtIxcpHwU1LJkKpXBgLr42iPqwhS+gUmd\nRi5SagpqWTKdypCIhQmHVl+VWNDZUEMiFublC5qiJ1JqCmpZMpVaKKrtARAKGTd01PPiwFSJqxIR\nLXiRJVPpTFEXEgtu7Kjn0eMXrvnv+8zfv8DjLw7y9hvb2NvduHT/h+/cds1fU6QaaUQtS6ZS6wzq\nznpGZuav6YLiw4f72P/UWQanUnz1QA/7n+phdnHWiYhcSkEtQP5Q2+lUpujWB+SDGuClC+trf/z9\noV4+8bVDbNuU4NP37OFdN3dwvG+SR17F6FykmimoBYDZ+SxZ54qa8VFQCOoT6+hTf+PpHj75zed5\n464WPvqmnSRiEd5+Yzu7O+p4RXuHiKxIQS1Avj8NxS12KWiti9OSjPFSEUGdyeb40hOn+fS3j/DW\n3W38zUdfTyxy8dtvV2uSkZl5JuYW1l+8SJXTxUQB8jM+oLjFLst31mtMRHni5DD7D/RccRHQOccP\nTgzy7Wd7+fHLw0ymMrzzpnb+4pfuIB4JX/LYnW11AJwe1qha5HIKagEu7vOxnhE1QEdDDc+cGSPn\n3CX3P35ikD/+/glODEzRXh/nnls6edsN7bxrbwfR8JX/ketqrKEmGuLU0My1vwiRKqWgFuDiznnr\nDerOhhrmsznGZy+2LE4Pz/AbXznItpYEf/YLt/He27pXDOflQmbsbElyalhBLXI5BbUA+dZHLBK6\noiWxlo6GGgAuTKaWWiL7n+rBDP7Dvq2kFnJ862BvUV9rV1sdxwem6Bufo7updn0vQKSK6WKiADCZ\nylC/jhkfBR2X7flxbnSWF85P8Obr29Y11Q9gZ2sSgAOnR9Zdh0g1U1ALkN/idL1tD4B4NExzIsrJ\nwWn6xuf4/tEBkrEwb93duu6v1dlYQ200zL+fVFCLLKegFmB9+3xcbmdrvrf854+/wunhGe7e0048\nur4WCiz2qVuTPHlq9JrqEKlW6lELkJ/1sbvj2r4dfvaOLbx1dxv9kylm0xnesLPlmuvY2lzLPx27\nwGRqgYZr/MUhUm0U1MLsfIZ0JkfDNfSoIT8Sbm+ooX3xwuKr0Vaf/xqnhmZ47damV/31RKqBWh+y\ntKnStbY+NlLh5BgtJxe5SEEtDC4GdTGH2pbapmSMaNg4OaSgFilQUMuyEbX3QR0OGdtbkhpRiyyj\noBYGF+dA+6H1AXB9W51G1CLLFBXUZtZkZg+Y2QkzO25mP1HqwqR8BqfShAwSsfVPqSuF69vrODsy\ny3wm53UpIr5Q7Ij688D3nXN7gNuA46UrScptaCpNXTxCyNY+1LYcrmtPks05eka174cIFBHUZtYI\nvBX4awDn3LxzbrzUhUn5DE6lfdP2ALi+LX8ggfrUInnFjKh3AkPAl8zskJl90cySlz/IzO4zs4Nm\ndnBoaGjDC5XSyQe19xcSC3a15b+9TmrLUxGguKCOAHcAf+mcux2YAX738gc55+53zu1zzu1ra2vb\n4DKllIZ8FtTJeITuxhqNqEUWFRPUvUCvc+7A4scPkA9uqQKZbI6RGX+1PgCua9fMD5GCNYPaOTcA\nnDOzGxfvegdwrKRVSdmMzMzjHOs61LYcrmur4+TgNO6yk2NEgqjYn87fAr5qZjHgFPArpStJyqmw\n2KXBR60PyI+oZ+az9E+kdIiABF5RP53OueeAfSWuRTwwOOWvxS6QPzz37OKRXH/1o1Ps7sjPArn8\n8FyRoNDKxIAbnPTPPh/LFXbiK5wcsxbnHI+/OMixvkmyObVLpLr466dTyq6wIdO1HMNVSnXxCI21\nUfrG5676uMI5jc/2jPHAM/mzGeOREJ961w3c99brSl6nSDloRB1wA5MpNiVjRNY4JdwL3U219I2v\nPaKenc/w3SP9bG2u5Rf2baGzoYbPP/oyc/PZMlQpUnr+++mUsrowkaJzAzb8L4XuphqGp9OkM1cP\n3H86OkBqIcv7b9/Ma7c281N7O5iZz/LI8QtlqlSktBTUAdc/kaKr0Z9BvbmxFgcMTKw+qu4ZmeHp\nM2PcdV0rXY352SE7WpJ0N9bwD4fOl6lSkdJSUAfcwGSKDp8GdWFa3vmr9KmfODlCMhbm7pval+4L\nmfG+2zfzLy8NMTKdLnmdIqWmoA6w1EKW0Zl5unza+qiviVAXj6x6QXE+k+OlC1Pc1NVAPHLpFq0f\nuH0z2Zzj4cP95ShVpKQU1AFWmJrX6dMRtZmx+SoXFA+eGSWdyXFTV8MVn7uho56buxp4UO0PqQIK\n6gDrn8iPVAu9XT/qbqphcCrFQvbKQwQePT5IJGRc11a34nPf99punj83vuYUPxG/U1AHWGExSWdj\n3ONKVtfdVEvOXXlB0TnHYycucF1bHbHIyt/G+3Y0A3C8f7LkdYqUkr9WOUhZ9U8UgroWGPO2mFUU\nLij2TVw6Kj45NMPZkVnuva17xeftP9BDaiE/re8bT5/jwmKbR8vQpRJpRB1gAxMp6uMR3+2ct1xT\nbZTaaPiK9sUPTuTnSO/prF/1uTXRME21US4UuQxdxK8U1AE2MJHy7YXEAjNje0uCFwemLln48tjx\nQW7qaqApEbvq8zsaapZG0yKVSkEdYP2T/g9qgJ/Y1cJkKrO0gOVw7zhPnRnlnr2daz63o6GGoam0\nNmqSiqagDrCBiTnfLh9f7vr2OrqbavjCv5wik83x3x46Sksyzq++eceaz+1sjJN1jmEtfJEKpqAO\nqEw2x9BU2rfLx5czM952Qzunh2f4ra8d4tmecT59z41F7aHdsc7tUkX8SEEdUEPTaXKuMOPD//Z2\nN7CrNcn3Xhjgtq1NfPCOLUU9r60uTsjym0+JVCoFdUBdnJrn3znUy4XM+Pjd1xMJGX9w715CISvq\neZFwiNa6uGZ+SEXz77wsKanCApLOhsoYUQP87B1beMeeDhoT6zs2rKOhht6x2RJVJVJ6CuqAKgR1\nJfSoCwqnuaxXR0MNR85PrLmvtYhfqfURUAOTKeKREE3rHJ1Wos6GfHtnUPOppUIpqAOqf3Gxi1lx\nvd5KppkfUukU1AFVKXOoN0JzMkY0bAwqqKVCKagDqr8Clo9vlJAZm5IxRmbmvS5F5JooqANoPpOj\nb3yO7ZsSXpdSNi3JOKMKaqlQmvURMPsP9DA4lSLn8qPqa51JUWlakjFeujBFLueKnoMt4hcaUQfQ\nyHR+ZNlaVxmLXTbCproYmZzTBUWpSArqACpsUBSkoG5J5l/rmZEZjysRWT8FdQANT6dJxMLUxsJr\nP7hKtCTz+1b3jGiFolQeBXUADU/PB2o0DdCYiBI244yCWiqQgjqARqbTgQvqkBnNyShn1fqQCqSg\nDph0JstkKkNr3dWPsKpGLcm4RtRSkRTUAVOY8dESsBE15Gd+9IzM4JyO5ZLKoqAOmIszPoI4oo4x\nM59leFoLX6SyKKgDphDUhelqQVKY+aE+tVSaooPazMJmdsjMHi5lQVJaI9PzNNZGiUWC9zv64lxq\n9amlsqznp/W3geOlKkTKY3g6Hci2B0BTMkrIoEcjaqkwRQW1mW0B3g18sbTlSCk55xiaTgfyQiJA\nJBRic3OtRtRScYodUf9v4HeAXAlrkRIbm10gtZAL3Bzq5Xa0JNWjloqzZlCb2XuAQefcM2s87j4z\nO2hmB4eGhjasQNk4p4engWDO+CjYtimhEbVUnGJG1HcB95rZGeDrwN1m9neXP8g5d79zbp9zbl9b\nW9sGlykb4cTAFADt9cE4MGAlWzclmJhbYCq14HUpIkVbM6idc//VObfFObcD+BDwA+fcR0pemWy4\nF85PUhsN0xyAA21Xs6W5FoDz43MeVyJSvODN0Qqwo30TdDUF40Db1Wxpzp9q0zuqoJbKsa6gds79\n0Dn3nlIVI6WzkM1xYmCKzY21XpfiqcKIundMfWqpHBpRB8Qrg9PMZ3J0NQU7qFuSMWqiIXrHNKKW\nyqGgDoijfZMAdDcF90IigJmxpTmhoJaKoqAOiBfOT5CIhQM9h7pgS3MtveNqfUjlUFAHxNG+CW7q\naiAU4AuJBVuaazWiloqioA6AXM5xrG+SW7obvC7FF7Y0Jxif1VxqqRwK6gA4MzLDzHyWvZsbvS7F\nFzSXWiqNgjoAXli8kLhXI2pAc6ml8iioA+Bo3wSxcIjd7fVel+ILm5s0l1oqS8TrAqT0nj83zp6u\n+kAeFnC5/Qd6cM4RCRmPHh8kFgkD8OE7t3lcmcjq9JNb5eYzOQ71jLNv+yavS/ENM6M5EWNsVmcn\nSmVQUFe5I+fHSWdyvGFns9el+EpzMqqgloqhoK5yT50eA+D1OzSiXq4pEWNsRtPzpDIoqKvcU6dH\nuK4tGdjjt1bTnIgxt5AlvZD1uhSRNeliYpXaf6CHnHP8+6kRXrO5kf0HerwuyVcKe3KPzS3QGQ17\nXI3I1WlEXcUuTKZILeTY0ZL0uhTfaU7kjyMbn1GfWvxPQV3FTg/nD3Hd0aqgvlxTYUStC4pSARTU\nVezMyCxNtdGl0aNcVBePEAkZY7O6oCj+p6CuUs45zgzPaDS9Cs2llkqioK5Sg1NpptMZdqo/varm\nZJRxjailAiioq9Tx/vxGTDd0an+P1TRpRC0VQkFdpY73T7K5qZbG2qjXpfhWcyLG7LzmUov/Kair\n0OBUit6xOW7q0mj6apbPpRbxMwV1FXr8xCAOuKlL+09fjeZSS6VQUFehR44N0lQbpbMh2CeOr0Vz\nqaVSKKirTGohy49fGWJPVwOmg2yvSnOppVIoqKvME68Mk1rIqT9dBM2llkqhoK4y339hgPp4hJ1a\n6FIUzaWWSqCgriIL2Rz/fOwCP3VzB5GQ3tpiaC61VAL9NFeRJ14ZZmJugZ95TZfXpVSMwlzq6XTG\n61JEVqWgriLfPdJPfTzCW25o9bqUilGYS31+bM7jSkRWp6CuEoW2xztv7iAe0Ub4xSrMpe4dm/W4\nEpHVKairxL+dHGF8Vm2P9SrMpe7ViFp8TEdxVbjCEVsPPttLPBKib3xOx26tQ2EutUbU4mcaUVeB\nhWyOo32T3NTVQDSst3Q9CnOpz41qRC3+pZ/qKnCkd4K5hSz7tjd7XUpFak5GOacRtfiYgroKHDg9\nQltdXItcrtGmZJyekVmcc16XIrKiNYPazLaa2eNmdszMjprZb5ejMClO3/gc58bmeMPOTdrb4xq1\nJGNMpTOMahc98aliRtQZ4FPOuZuBNwIfM7ObS1uWFOup06NEQsYd29T2uFabkvkpemdH1f4Qf1oz\nqJ1z/c65ZxdvTwHHgc2lLkzWNp3O8FzvOLduaaI2prnT16oQ1D0jCmrxp3X1qM1sB3A7cGCFz91n\nZgfN7ODQ0NDGVCdX9Q+HzjOfyXHnzk1el1LRlkbUCmrxqaKD2szqgG8D/9k5N3n5551z9zvn9jnn\n9rW1tW1kjbIC5xx/9+RZuhtr2NJc63U5FS0aDtHZUMPZ0RmvSxFZUVFBbWZR8iH9Vefcg6UtSYrx\nbM84JwameMPOFl1E3ADbWhJqfYhvFTPrw4C/Bo475/6s9CVJMb564Cx18Qi3bWn0upSqsH1TQhcT\nxbeKGVHfBfwycLeZPbf452dKXJdcxdjMPA8f7uf9t3cTj+oi4kbY3pJgaCrN7Ly2OxX/WXOvD+fc\njwH939pHvv1sL/OZHL9053YO9Yx7XU5V2N6SXyx0dmRWp7eL72hlYgV64JleXru1SYGygba3JADN\n/BB/UlBXmFcGpzkxMMW9t3V7XUpV2b4pP6Lu0cwP8SFtc1pB9h/o4bHjFzBgPpPTdqYbqDERpbE2\nqhG1+JJG1BXEOcfh3gl2tCZpqI16XU7V2d6SoEczP8SHFNQVZGAyxdB0mls1Ja8ktm1KaEQtvqSg\nriBHeicIGeztVlCXwvaWBOfH51jI5rwuReQSCuoK4Zzj8PkJdrXVURfXpYVS2NGSJJtznFP7Q3xG\nQV0hjpyfYHRmnls3azRdKns689MdXxyY8rgSkUspqCvEw4f7CZup7VFCuzvqCBkcV1CLzyioK0Au\n53j4+T52d9Rp3+kSqomG2dma5Hj/FZtDinhKzc4KcOjcGH0TKe66vtXrUqpWYU56Ihbh4JnRpY8/\nfOc2L8sSATSirgj/+Hw/sUhIS8bLoLOxhrHZBVILWa9LEVmioPa5bM7xnSP93H1jOzXaKa/kOhtq\nALgwmfK4EpGLFNQ+99TpUYam0rznti6vSwmEzsZ8UA8oqMVHFNQ+99Dz50nEwty9p93rUgKhqTZK\nPBJiYEJBLf6hoPaxdCbLdw73c8/eThIxXfctBzOjs7FGQS2+oqD2scdPDDGZyvD+2zd7XUqgdDbU\nMDCZwjnndSkigILa1/7h0Hla6+K86boWr0sJlM7GGtKZHOOzC16XIgIoqH1rYnaBH5wY5N7buomE\n9TaVU1eDLiiKv6jx6UP7D/Tw9OlR5rM5aqNhHRBQZh0NNRhwfnzO61JEAI2ofevQuTHa6uJ0N9V4\nXUrgxKNhNjfX8tIF7fkh/qCg9qGByRRnRmZ53fZmzHQAvBdu6mqgd2yOwSm1P8R7CmofOnBqhEjI\neN32Zq9LCaw9nfUAPH5i0ONKRBTUvjOZWuBQzzi3bmkiqQMCPNPZUENTbZRHjimoxXsKap958Jle\n5rM53rhrk9elBJqZsaergR+/MqQNmsRzCmofcc7xlSfPsrW5li3NCa/LCbybOutJLeT4t5PDXpci\nAaeg9pFHjw9yamiGN+7SAhc/2NmaJBkLq/0hnlNQ+8R8JsfnvnucXW1Jbt3S5HU5AkTCId52Yxv/\nfHSAmXTG63IkwBTUPvGVfz/DqeEZPvvumwmHNCXPL379LbsYmZnnL3940utSJMAU1D4wOjPP5x97\nmbfd0MZPajtTX7ljWzPvf2039//rKXrHZr0uRwJKQe0x5xz/4+FjzM5n+cy7b/K6HFnBp396DyGD\nz33vhNelSEBpoq6H9h/o4ccvD/HdFwa4e087T58Z4+kzY16XJcsU9lm567pWvnO4n0T0ef7052/z\nuCoJGo2oPXSif5LvvTDA3u4GneDic2/Z3cbO1iTfeqaX//PYy9qrWspKQe2Rhw/38fWnz9HVWMPP\nv24rIe3p4WuxSIhfuWsHt29t4n898hK/+uWnefrMqAJbysJK8Y22b98+d/DgwQ3/utUgtZDlj753\ngi//2xm2bUrw4Tu30VAT9bosKZJzjpn5DP/3hycZn13g1i2N/NzrtvCeW7vZlIx5XZ5UMDN7xjm3\nb8XPKajLo39ijq89dY6vPnmWkZl5fu3NO9nRktRUvAo1n8lx6NwYB06NMjCZImRw954OfvaOzdy9\np52aaNjrEqXCXC2oi7qYaGb3AJ8HwsAXnXN/tIH1VZ1sznFmZIYXzk/w3LlxvnO4n8GpNJDfle0D\nt29mV1udx1XKqxGLhLhzZwt37myhf2KOQz3jHO4d59HjF6iPR3jX3k7ec2sXd+7apIOJ5VVbc0Rt\nZmHgJeCngF7gaeAXnXPHVntOuUfUzjmcA1e4DYsf5+9n2ceF25mcYz6TI53Jks7kSC9cvL2QzREy\nI2RGOGSEQ/lNesJmmMF0KsPE3AKTqQUm5hYYnVmgf2KOvvE5+sZTDEymyObyf1c8EmJrc4Lr2+u4\nubuB1rp42f5dpLxyznFycJrneyc41j9BaiFHyOCWzY3sbq+ntT5GazJOa32MlmScRCxMLBIiGg4R\ni4SIhUOYQWjx+yxkhgEsu21mhAwMW7w/f59x8Xksu738fu1t7m+vdkT9BuAV59ypxS/2deB9wKpB\nfa1e94ePMDufXQpYB7AscC8PYr8Im9FQG6EpEaO9Ps7u9jpa6mJ0N9XSXl+j9kZAhMzY3VHP7o56\nMtluTg3PcGZkhrMjszx6/ALT6czSL3CvXBHeFEJ8Mfx9zu+/a1rr4vzod35yw79uMUG9GTi37ONe\n4M7LH2Rm9wH3LX44bWYvFvG1W4FK3pqs0usHvQY/qPT6ofJfw4bVb5++5qduX+0TG9Y8c87dD9y/\nnueY2cHVhvqVoNLrB70GP6j0+qHyX4Pf6y9mHvV5YOuyj7cs3iciImVQTFA/Dew2s51mFgM+BDxU\n2rJERKRgzdaHcy5jZh8H/on89Ly/cc4d3aC/f12tEh+q9PpBr8EPKr1+qPzX4Ov6S7LgRURENo72\n+hAR8TkFtYiIz5UlqM3sHjN70cxeMbPfXeHzcTP7xuLnD5jZjnLUVawi6n+rmT1rZhkz+zkvalxL\nEa/hk2Z2zMwOm9ljZrbqnE4vFFH/b5rZETN7zsx+bGY3e1Hn1az1GpY97oNm5szMd9PFingfPmpm\nQ4vvw3Nm9ute1LmaYt4DM/uFxZ+Fo2a2v9w1rii//Lp0f8hfgDwJ7AJiwPPAzZc95j8BX1i8/SHg\nG6Wua4Pr3wHcCnwF+Dmva77G1/CTQGLx9n+swPegYdnte4Hve133el/D4uPqgR8BTwL7vK77Gt6H\njwJ/7nWtr6L+3cAhoHnx43av63bOlWVEvbQE3Tk3DxSWoC/3PuBvF28/ALzD/LMxwZr1O+fOOOcO\nAzkvCixCMa/hcedc4VDAJ8nPl/eLYuqfXPZhksUdCHykmJ8DgD8E/hhIlbO4IhX7GvyqmPp/A/gL\n59wYgHNusMw1rqgcQb3SEvTNqz3GOZcBJoCWMtRWjGLq97v1voZfA75X0orWp6j6zexjZnYS+BPg\nE2WqrVhrvgYzuwPY6pz7TjkLW4div48+uNhCe8DMtq7wea8UU/8NwA1m9oSZPbm4c6jndDFRLmFm\nHwH2AX/qdS3r5Zz7C+fcdcCngc94Xc96mFkI+DPgU17X8ir9I7DDOXcr8AgX/6dcKSLk2x9vB34R\n+Csza/K0IsoT1MUsQV96jJlFgEZgpAy1FaMaltAX9RrM7J3A7wH3OufSZaqtGOt9D74OvL+kFa3f\nWq+hHrgF+KGZnQHeCDzkswuKa74PzrmRZd87XwReV6bailHM91Ev8JBzbsE5d5r8Fs+7y1Tf6srQ\nwI8Ap4CdXGzg773sMR/j0ouJ3/S6eb+e+pc99sv482JiMe/B7eQvtOz2ut5rrH/3stvvBQ56Xfe1\nfh8tPv6H+O9iYjHvQ9ey29fInvsAAAISSURBVB8AnvS67nXWfw/wt4u3W8m3Slo8r71M/0A/Q/43\n00ng9xbv++/kR24ANcC3gFeAp4BdXv/DrLP+15P/TTxD/n8CR72u+Rpew6PABeC5xT8PeV3zOuv/\nPHB0sfbHrxaCfn0Nlz3Wd0Fd5PvwucX34fnF92GP1zWvs34j34I6BhwBPuR1zc45LSEXEfE7XUwU\nEfE5BbWIiM8pqEVEfE5BLSLicwpqERGfU1CLiPicglpExOfWPDNRpJKY2WeBjwBD5FeVPUN+k6/7\nyK9GewX4ZefcrJl9mfwudfuABuCTzrmHvahb5Go0opaqYWavBz4I3Ab8NPkABnjQOfd659xtwHHy\nuwMW7CC//eW7gS+YWU35KhYpjoJaqsldwP9zzqWcc1Pkd3IDuMXM/tXMjgC/BOxd9pxvOudyzrmX\nye8Dsae8JYusTUEtQfBl4OPOudcAf0B+b5mCy/dQ0J4K4jsKaqkmTwDvNbMaM6sD3rN4fz3Qb2ZR\n8iPq5X7ezEJmdh35I5peLF+5IsXRxUSpGs65p83sIeAw+Z0Aj5C/kPhZ4AD5C4wHyAd3QQ/5HRsb\ngN90zvnxCCwJOO2eJ1XFzOqcc9NmliB/SOx9zrlnV3nsl4GHnXMPlLNGkfXSiFqqzf1mdjP5PvTf\nrhbSIpVEI2oREZ/TxUQREZ9TUIuI+JyCWkTE5xTUIiI+p6AWEfG5/w8bi8hQCGjG8wAAAABJRU5E\nrkJggg==\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "bgwlcBYQTz-X",
"colab_type": "text"
},
"source": [
"### Reverie SMILES Tokenizer\n",
"\n",
"In a typical NLP setup, we feed the model a series of tokens corresponding to individual words (or [WordPieces](https://blog.floydhub.com/tokenization-nlp/) in a sentence.\n",
"\n",
"We can view a SMILES string as a sentence, and atoms as words. However, whereas natural language sentences are (for most languages) space-separated into words, SMILES strings don't have a built-in delimiter. Moreover, while some atoms are encoded as single characters, many are encoded as two characters, so we can't just separate SMILES letter-by-letter.\n",
"\n",
"Once you start to dig into the syntax, you'll find a number of complexities and corner-cases that make SMILES tokenization a non-trivial problem. For instance:\n",
"\n",
"* SMILES commonly contain bracketized ions like `[NH2+]` or `[C-]` that should be treated as a single token.\n",
"* SMILES can contain stereochemical information, which is also specified in brackets, like `[N@@H]`.\n",
"* SMILES use numbers to indicate the start and end of rings, as in `C[C@@H]1NCCc2cc(O)c(O)cc12`, where there are two rings labeled `1` and `2` that start at different points in the string, and terminate at the end of the string.\n",
"* Atoms that are part of aromatic rings are written in lowercase, so `C` is a non-aromatic carbon, while `c` is aromatic. This syntax can produce ambiguity with some character combinations. For instance, `co` could be a carbon and nitrogen on a ring, or it could be an aromatic cobalt. (While the latter is very unlikely to be found on a real molecule, it is permitted by the SMILES syntax and therefore possible in theory.) There exist several other two-letter combinations that could also (however implausibly) be aromatic metals: `cn, cs, sc, no, sn, se, np, te`.\n",
"\n",
"Even though there exist many good libraries for parsing SMILES, these solutions (e.g., RDKit) are typically aimed at creating rich molecular representations that can be manipulated downstream. Since machine learning and chemistry have only recently crossed paths, it's actually quite hard to come by a robust NLP-style tokenizer for SMILES strings.\n",
"\n",
"To that end, we're releasing our SMILES tokenizer with this Colab. While it's by no means perfect, we've found that our tokenizer does reasonable things in most cases, and is smart enough to handle the above corner cases. More importantly, our tokenizer has clean APIs and is written in Python so as to be easily applicable to NLP / data science projects."
]
},
{
"cell_type": "code",
"metadata": {
"id": "DOIThf34VRYl",
"colab_type": "code",
"outputId": "527341f7-3912-4d29-b284-82b3419be576",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"%%writefile reverie/tokenizer.py\n",
"\"\"\"\n",
"Copyright (c) 2020 Reverie Labs. All rights reserved.\n",
"This work is licensed under the terms of the MIT license <https://opensource.org/licenses/MIT>.\n",
"\"\"\"\n",
"\n",
"from enum import Enum\n",
"from typing import Iterable, List, Union\n",
"\n",
"import numpy as np\n",
"from tqdm import tqdm\n",
"\n",
"UNK_TOKEN = \"<UNK>\"\n",
"MASK_TOKEN = \"[*]\"\n",
"\n",
"element_abbreviations = [\n",
" 'H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl',\n",
" 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As',\n",
" 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In',\n",
" 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb',\n",
" 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl',\n",
" 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk',\n",
" 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh',\n",
" 'Fl', 'Mc', 'Lv', 'Ts', 'Og'\n",
"]\n",
"\n",
"\n",
"class TokenizerStatus(Enum):\n",
" OK = 1\n",
" INVALID_OTHER = 2\n",
" INVALID_BRACKET = 3\n",
"\n",
"\n",
"class SmilesTokenizer:\n",
" \"\"\"General purpose NLP-style tokenizer for SMILES strings.\n",
"\n",
" Args:\n",
" separator: When `return_type = str`, return strings will be joined by this separator. \n",
" Defaults to a single space.\n",
" skip_invalid: If False (default), raises an error when a SMILES cannot be tokenized. If\n",
" True, prints errors and returns TokenizerStatus.INVALID, but does not raise errors.\n",
" \"\"\"\n",
"\n",
" def __init__(self,\n",
" separator: str = \" \",\n",
" skip_invalid: bool = False,\n",
" use_multiprocessing: bool = True):\n",
" self.separator = separator\n",
" self.skip_invalid = skip_invalid\n",
"\n",
" # List of element abbreviations\n",
" self.abbrevs = element_abbreviations\n",
" self.two_letter_abbrevs = list(filter(lambda x: len(x) == 2, self.abbrevs))\n",
"\n",
" def tokenize(self, smiles: Union[str, Iterable], return_type: Union[list, str] = list):\n",
" \"\"\"Main API method. Tokenizes a single SMILES string or iterable of SMILES.\"\"\"\n",
" if isinstance(smiles, str):\n",
" tokens_list = self._tokenize(smiles)\n",
" if isinstance(tokens_list, TokenizerStatus):\n",
" return tokens_list\n",
" if return_type == str:\n",
" return self.tokens_to_string(tokens_list)\n",
" elif return_type == list:\n",
" return tokens_list\n",
" else:\n",
" raise ValueError(f\"Unknown return_type {return_type}\")\n",
"\n",
" # Assume smiles is an iterable\n",
" for s in smiles:\n",
" assert (isinstance(s, str))\n",
" results = [self.tokenize(s, return_type) for s in tqdm(smiles)]\n",
" return results\n",
"\n",
" def tokens_to_string(self, tokens_list: List[str]):\n",
" \"\"\"Converts a list of tokens to a string using `separator`.\"\"\"\n",
" return self.separator.join(tokens_list)\n",
"\n",
" def _tokenize(self, smiles: str):\n",
" \"\"\"Efficient, O(n) SMILES tokenizer.\n",
" Anything in square brackets is considered a single token (e.g., [C@@H], [Na2+], etc.).\n",
" Args:\n",
" smiles: Single SMILES string.\n",
" Returns:\n",
" List of tokens.\n",
" \"\"\"\n",
" assert (isinstance(smiles, str))\n",
" tokens = []\n",
"\n",
" smiles += \"&\"\n",
" buf = \"\"\n",
" bracket_mode = False\n",
"\n",
" for char1, char2 in zip(smiles[0:-1], smiles[1:]):\n",
" if char1 == \"[\":\n",
" if buf:\n",
" return self._handle_error(smiles, TokenizerStatus.INVALID_OTHER)\n",
" if bracket_mode:\n",
" return self._handle_error(smiles, TokenizerStatus.INVALID_BRACKET)\n",
" bracket_mode = True\n",
" buf += char1\n",
" elif char1 == \"]\":\n",
" if not bracket_mode:\n",
" return self._handle_error(smiles, TokenizerStatus.INVALID_BRACKET)\n",
" bracket_mode = False\n",
" buf += char1\n",
" tokens.append(buf)\n",
" buf = \"\"\n",
" elif bracket_mode:\n",
" buf += char1\n",
" elif buf:\n",
" tokens.append(buf + char1)\n",
" buf = \"\"\n",
" elif char1 + char2 in self.two_letter_abbrevs:\n",
" buf += char1\n",
" else:\n",
" tokens.append(char1)\n",
" return tokens\n",
"\n",
" def _handle_error(self, smiles: str, err: TokenizerStatus):\n",
" \"\"\"Raises or returns an error, depending on `skip_invalid` setting.\"\"\"\n",
" if self.skip_invalid:\n",
" print(err, smiles)\n",
" return err\n",
" else:\n",
" raise ValueError(err, smiles)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"Writing reverie/tokenizer.py\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "YA67RcXMv83W",
"colab_type": "text"
},
"source": [
"You'll notice that when you run the above cell, it doesn't execute any code! That's because we used the `%%writefile` magic to instead write the tokenizer code to its own file `reverie/tokenizer.py` (which you can view in Colab's file browser). This way, when we define our T2T problem (coming up in a bit), we can import the tokenizer as a Python module!\n",
"\n",
"Now, let's try out the tokenizer on a few toy examples."
]
},
{
"cell_type": "code",
"metadata": {
"id": "k54q4qt3V_j8",
"colab_type": "code",
"outputId": "a890dc20-6adc-42ad-dfe0-4ceed8a4d6a9",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 88
}
},
"source": [
"from reverie.tokenizer import SmilesTokenizer, TokenizerStatus, UNK_TOKEN\n",
"\n",
"# Let's verify that the tokenizer works!\n",
"tokenizer = SmilesTokenizer()\n",
"\n",
"# Some SMILES from drugbank.ca\n",
"drugs_list = [\n",
" \"CC(=O)NC1=CC=C(O)C=C1\", # acetaminophen (Tylenol)\n",
" \"CC(=O)OC1=CC=CC=C1C(O)=O\", # acetylsalicylic acid (Asprin)\n",
" \"CC(C)(C)NCC(O)C1=CC(CO)=C(O)C=C1\", # salbutamol (Albuterol)\n",
"]\n",
"\n",
"# Tokenize a single SMILES\n",
"print(tokenizer.tokenize(drugs_list[0]))\n",
"\n",
"# Tokenize a list of SMILES\n",
"print(tokenizer.tokenize(drugs_list))"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"100%|██████████| 3/3 [00:00<00:00, 6052.39it/s]"
],
"name": "stderr"
},
{
"output_type": "stream",
"text": [
"['C', 'C', '(', '=', 'O', ')', 'N', 'C', '1', '=', 'C', 'C', '=', 'C', '(', 'O', ')', 'C', '=', 'C', '1']\n",
"[['C', 'C', '(', '=', 'O', ')', 'N', 'C', '1', '=', 'C', 'C', '=', 'C', '(', 'O', ')', 'C', '=', 'C', '1'], ['C', 'C', '(', '=', 'O', ')', 'O', 'C', '1', '=', 'C', 'C', '=', 'C', 'C', '=', 'C', '1', 'C', '(', 'O', ')', '=', 'O'], ['C', 'C', '(', 'C', ')', '(', 'C', ')', 'N', 'C', 'C', '(', 'O', ')', 'C', '1', '=', 'C', 'C', '(', 'C', 'O', ')', '=', 'C', '(', 'O', ')', 'C', '=', 'C', '1']]\n"
],
"name": "stdout"
},
{
"output_type": "stream",
"text": [
"\n"
],
"name": "stderr"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ytJtxsJne6ra",
"colab_type": "text"
},
"source": [
"### Generate a vocab file\n",
"\n",
"Since we're using a custom tokenizer to define our own vocabulary over SMILES, we need to let T2T know what our vocab looks like. The below utilities take a list of SMILES and compile a set of all unique tokens that can be written to a vocab file that we'll pass to T2T."
]
},
{
"cell_type": "code",
"metadata": {
"id": "uciuwWY0d5wm",
"colab_type": "code",
"colab": {}
},
"source": [
"def get_vocab_from_smiles(smiles_list):\n",
" \"\"\"Returns a sorted list of all unique tokens in smiles_list.\"\"\"\n",
" tokenizer = SmilesTokenizer()\n",
"\n",
" all_tokens = set()\n",
" for smiles in tqdm(smiles_list):\n",
" tokens_list = tokenizer.tokenize(smiles)\n",
" if not isinstance(tokens_list, TokenizerStatus):\n",
" all_tokens.update(tokens_list)\n",
" return sorted(list(all_tokens))\n",
"\n",
"\n",
"def write_vocab_to_file(vocab_list, vocab_filepath, replace_oov=UNK_TOKEN):\n",
" \"\"\"Write vocab_list to vocab_filepath.\"\"\"\n",
"\n",
" # Add the UNK token to the vocab\n",
" if replace_oov is not None:\n",
" if replace_oov not in vocab_list:\n",
" vocab_list = [replace_oov] + vocab_list\n",
"\n",
" encoder = TokenTextEncoder(vocab_filename=None, vocab_list=vocab_list, replace_oov=replace_oov)\n",
" encoder.store_to_file(vocab_filepath)\n",
" print(f\"Wrote vocab file to {vocab_filepath}\")"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "UQ4r5jV_ZZzB",
"colab_type": "code",
"outputId": "57c6eddf-a945-4ae4-bcba-0134e01b016d",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 85
}
},
"source": [
"# Build a vocab for QM9\n",
"vocab = get_vocab_from_smiles(df[\"smiles\"])\n",
"print(f\"\\nGenerated vocab with {len(vocab)} tokens.\")\n",
"print(vocab)"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"100%|██████████| 133885/133885 [00:04<00:00, 33178.76it/s]"
],
"name": "stderr"
},
{
"output_type": "stream",
"text": [
"\n",
"Generated vocab with 26 tokens.\n",
"['#', '(', ')', '-', '1', '2', '3', '4', '5', '=', 'C', 'Cn', 'F', 'N', 'O', '[C-]', '[CH-]', '[N-]', '[NH+]', '[NH2+]', '[NH3+]', '[O-]', '[nH]', 'c', 'n', 'o']\n"
],
"name": "stdout"
},
{
"output_type": "stream",
"text": [
"\n"
],
"name": "stderr"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "b68ALusGcOjh",
"colab_type": "code",
"outputId": "137b843e-3d48-4395-b2fc-6ae3e15374a3",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 88
}
},
"source": [
"# Write vocab file to DATA_DIR\n",
"os.makedirs(os.environ.get(\"DATA_DIR\"), exist_ok=True)\n",
"write_vocab_to_file(vocab, os.path.join(os.environ.get(\"DATA_DIR\"), \"vocab.txt\"))"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensor2tensor/data_generators/text_encoder.py:395: The name tf.gfile.Open is deprecated. Please use tf.io.gfile.GFile instead.\n",
"\n",
"Wrote vocab file to t2t_data/homo_lumo_gap/vocab.txt\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "iKCCYCQ1ch23",
"colab_type": "text"
},
"source": [
"### Define SmilesRegressionProblem as a t2t.Problem\n",
"\n",
"Tasks in T2T are defined using the `t2t.Problem` interface. The `Problem` class defines how raw data are transformed into TFRecords files, specifies how the data should be divided into different splits, and also allows for more advanced configuration of things like evaluation metrics and hooks. The [T2T README](https://github.com/tensorflow/tensor2tensor#problems) is a good starting point if you want to learn more about how `Problem` works.\n",
"\n",
"One really neat feature of `Problem` is that it's designed to be subclassed to define custom ML tasks in a hierarchical manner. In particular, we can take advantage of Tensor2Tensor's existing infrastructure for text-based problems. In our case, we've set up our problem using the following inheritance structure:\n",
"\n",
"[`Problem`](https://github.com/tensorflow/tensor2tensor/blob/598eace7707d77b7c5117a2235ac3c4924796ca2/tensor2tensor/data_generators/problem.py#L172) > [`Text2TextProblem`](https://github.com/tensorflow/tensor2tensor/blob/598eace7707d77b7c5117a2235ac3c4924796ca2/tensor2tensor/data_generators/text_problems.py#L53) > [`Text2RealProblem`](https://github.com/tensorflow/tensor2tensor/blob/598eace7707d77b7c5117a2235ac3c4924796ca2/tensor2tensor/data_generators/text_problems.py#L609) > `SmilesRegressionProblem` > `HomoLumoGap`\n",
"\n",
"The great thing about Tensor2Tensor being an open-source project is that the set of Problems is always growing. In fact, the intermediate class [`Text2RealProblem`](https://github.com/tensorflow/tensor2tensor/blob/598eace7707d77b7c5117a2235ac3c4924796ca2/tensor2tensor/data_generators/text_problems.py#L609), which is now part of T2T, was originally written by us at Reverie to facilitate training text models to predict real-valued targets for regression problems.\n",
"\n",
"The final two classes are defined by us below in this Colab. (We'll use the `%%writefile` trick again here so we can pass these definitions to T2T via the `--t2t_usr_dir` flag). "
]
},
{
"cell_type": "code",
"metadata": {
"id": "HgeToXcNZNwl",
"colab_type": "code",
"outputId": "caee856b-0dcf-494c-d690-df1cbb860481",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"%%writefile reverie/problems/problem.py\n",
"import pandas as pd\n",
"import tensorflow as tf\n",
"\n",
"from tensor2tensor.data_generators import problem\n",
"from tensor2tensor.data_generators.text_problems import (Text2RealProblem, VocabType)\n",
"from tensor2tensor.utils import registry\n",
"\n",
"from tokenizer import SmilesTokenizer, TokenizerStatus, UNK_TOKEN\n",
"\n",
"\n",
"class SmilesRegressionProblem(Text2RealProblem):\n",
" \"\"\"Converts CSV-based SMILES datasets to Text2RealProblem for use in T2T.\"\"\"\n",
"\n",
" # Specify via subclass\n",
" @property\n",
" def dataset_path(self):\n",
" pass\n",
"\n",
" # Specify via subclass\n",
" @property\n",
" def targets_col(self):\n",
" pass\n",
" \n",
" @property\n",
" def smiles_col(self):\n",
" return \"smiles\"\n",
"\n",
" @property\n",
" def use_pregenerated_vocab(self):\n",
" return True\n",
"\n",
" @property\n",
" def data_dir(self):\n",
" return DATA_DIR\n",
"\n",
" @property\n",
" def vocab_filename(self):\n",
" return \"vocab.txt\"\n",
"\n",
" @property\n",
" def vocab_type(self):\n",
" return VocabType.TOKEN\n",
"\n",
" @property\n",
" def oov_token(self):\n",
" return UNK_TOKEN\n",
"\n",
" @property\n",
" def is_generate_per_split(self):\n",
" return False\n",
"\n",
" @property\n",
" def dataset_splits(self):\n",
" \"\"\"Splits of data to produce and number of output shards for each.\"\"\"\n",
" return [{\n",
" \"split\": problem.DatasetSplit.TRAIN,\n",
" \"shards\": 10,\n",
" }, {\n",
" \"split\": problem.DatasetSplit.EVAL,\n",
" \"shards\": 1,\n",
" }, {\n",
" \"split\": problem.DatasetSplit.TEST,\n",
" \"shards\": 1,\n",
" }]\n",
"\n",
" def generate_samples(self, data_dir, tmp_dir, dataset_split):\n",
" df = pd.read_csv(self.dataset_path)\n",
" assert(self.smiles_col in df.columns)\n",
" assert(self.targets_col in df.columns)\n",
"\n",
" # Tokenize each SMILES\n",
" tokenizer = SmilesTokenizer(skip_invalid=True)\n",
" for s, t in zip(df[self.smiles_col], df[self.targets_col]):\n",
" tokens_list = tokenizer.tokenize(s)\n",
" if isinstance(tokens_list, TokenizerStatus):\n",
" # Skip failed examples\n",
" continue\n",
" yield {\"inputs\": tokenizer.tokens_to_string(tokens_list), \"targets\": [float(t)]}\n",
"\n",
"\n",
"@registry.register_problem\n",
"class HomoLumoGap(SmilesRegressionProblem):\n",
" dataset_path = \"https://reverie-public.s3.amazonaws.com/transformer/qm9.csv\"\n",
" targets_col = \"gap\""
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"Writing reverie/problems/problem.py\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "BIf2BAF7WR4Y",
"colab_type": "code",
"outputId": "4ac4952e-a3d0-41b3-8749-f9197b8e4281",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
}
},
"source": [
"%%writefile reverie/problems/__init__.py\n",
"from . import problem"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"Writing reverie/problems/__init__.py\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nxIfzF-qnJ-u",
"colab_type": "text"
},
"source": [
"### Generate T2T data"
]
},
{
"cell_type": "code",
"metadata": {
"id": "rZqI1YK2qcGF",
"colab_type": "code",
"colab": {}
},
"source": [
"# Delete any previously-generated records\n",
"!rm -rf $DATA_DIR/$PROBLEM-*\n",
"\n",
"# Run data generation\n",
"!t2t-datagen \\\n",
" --t2t_usr_dir=$USR_DIR \\\n",
" --data_dir=$DATA_DIR \\\n",
" --tmp_dir=$TMP_DIR \\\n",
" --problem=$PROBLEM"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "oxd9TrrRuSQA",
"colab_type": "code",
"outputId": "23499b15-aba0-4995-c12a-f0f29dd5fdf1",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 136
}
},
"source": [
"# train, dev, and test files are ready!\n",
"!ls $DATA_DIR"
],
"execution_count": 0,
"outputs": [
{
"output_type": "stream",
"text": [
"homo_lumo_gap-dev-00000-of-00001 homo_lumo_gap-train-00005-of-00010\n",
"homo_lumo_gap-test-00000-of-00001 homo_lumo_gap-train-00006-of-00010\n",
"homo_lumo_gap-train-00000-of-00010 homo_lumo_gap-train-00007-of-00010\n",
"homo_lumo_gap-train-00001-of-00010 homo_lumo_gap-train-00008-of-00010\n",
"homo_lumo_gap-train-00002-of-00010 homo_lumo_gap-train-00009-of-00010\n",
"homo_lumo_gap-train-00003-of-00010 vocab.txt\n",
"homo_lumo_gap-train-00004-of-00010\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "O3qZDjjDql5q",
"colab_type": "text"
},
"source": [
"## Train a Transformer model\n",
"\n",
"Now that we've generated our TFRecords, we can begin training! Since we're using the `transformer_tiny` HParams set, training should only take about five minutes (assuming you're using a GPU runtime)."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "qK9s8mTPE5v1",
"colab_type": "text"
},
"source": [
"### Launch training"
]
},
{
"cell_type": "code",
"metadata": {
"id": "4qzZAc_3nOA5",
"colab_type": "code",
"colab": {}
},
"source": [
"!t2t-trainer \\\n",
" --t2t_usr_dir=$USR_DIR \\\n",
" --data_dir=$DATA_DIR \\\n",
" --problem=$PROBLEM \\\n",
" --model=$MODEL \\\n",
" --hparams_set=$HPARAMS \\\n",
" --output_dir=$TRAIN_DIR \\\n",
" --worker_gpu=1 \\\n",
" --train_steps=2000 \\\n",
" |& tee $TRAIN_DIR/t2t-trainer.txt"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "r919o9yKE9g9",
"colab_type": "text"
},
"source": [
"### Track progress with Tensorboard\n",
"\n",
"We can view the results of our training using the Tensorboard Colab extension. Note that this extension can be a bit finnicky and might not display until after training is complete (even if you run it during training)."
]
},
{
"cell_type": "code",
"metadata": {
"id": "Nb_8aenYN6WU",
"colab_type": "code",
"colab": {}
},
"source": [
"# Hack to make Tensorboard work with TF 1.x\n",
"# See: https://github.com/tensorflow/tensorboard/issues/3460\n",
"!pip uninstall tensorboard-plugin-wit -y"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "jA7xEOh-EoaN",
"colab_type": "code",
"outputId": "047dde1d-4332-4782-cb0d-09accdd8fe7b",
"colab": {
"resources": {
"http://localhost:6006/": {
"data": "PCFkb2N0eXBlIGh0bWw+PCEtLQpAbGljZW5zZQpDb3B5cmlnaHQgMjAxNiBUaGUgVGVuc29yRmxvdyBBdXRob3JzLiBBbGwgUmlnaHRzIFJlc2VydmVkLgoKTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CgogICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgpVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgpTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgotLT48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+Cjx0aXRsZT5UZW5zb3JCb2FyZDwvdGl0bGU+CjxsaW5rIHJlbD0ic2hvcnRjdXQgaWNvbiIgaHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFNUUFBQURFQ0FNQUFBRDNlSDVaQUFBQUJHZEJUVUVBQUxHUEMveGhCUUFBQUFGelVrZENBSzdPSE9rQUFBRC9VRXhVUmZGbEtmYUVMdkZtS2ZOeUsvNjdOdldBTGY2OE52NjlOdk54Sy8yME5meXlOUDIyTmZOMEsvSnJLdnFoTXYyek5mMjVOZjI0TmYyM05mZU9ML3l6TlB5dk5QSm9LdmlXTVBtZU1mTjFLL1dCTGZlUEwvRm5LZmVNTC9xbE12UjdMUG1jTWZlTEwvYUpMdlI1TFBGb0tmSnVLdlIzTFA2Nk52eXdOUGVOTC9WL0xmYUlMdjIxTmYyNk5mTnpLL052Sy9SNkxQbWFNZnl4TlBxZk12VitMZnVyTS9pU01QbWJNZkp2S3ZtZE1mdW1NL3FpTXZtWk1meXROUEpxS3Z5c05QTjJLL2lZTVBOd0svdXBNL0p0S3ZKc0t2aVZNUGFITHZhR0x2SnBLdlI4TFBhS0x2cWtNdnVxTS9hRkx2UjRMUHVvTS9pVE1QV0RMZmlSTVBtWU1YUzBuZ2tBQUFMb1NVUkJWSGphN2RybmN0cEFGSWJoRlVJU1NLSjNNS1lhMCt5NHhUVzk5MzcvMTVKa0pobFRqaHJTckhSbXZ1Zi9hczZMMFlMRkNnRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU1CSjZuamVucXNwemduUHJzckdYOVpwaTJ0Q3JtbmM2K2RZTnRoVlk1V3BNbXhRTFdQZE1zT3VZVnd6TmozZWkydDNtUXdhVjQzQkpQRENTMk5iSjVhRWV1WC8rOXFjalFPdGZGSWtJa3J2WTJnNE1WY21PQnNGV2Jvd0tPL2tOeWo2MmdScEpjRGFQQmx4THIxQjB6ZEcwQy84THpiSmlKcnNodXZ5MWd6bEE5K3JEOG1Ja3V5SUpqRkUzL2Rxbll3b1NtN0lVRVBvRC93dXQ4aUlndVNJRGpsRnhlL3lmWEw1dnVTSTIxQlRaTExoWG9PSUxNTzhIeHdhL0w4YkkwTGZtVWRoR293YjJadlQwZTU3cEZORGdCMDZJbFZ5am1tSUJsMlQvbmw5Unc2U0Q5R2dTRy9RMHVRa2FXM1hobW92S1EzZUZRNE4yVW85T1ExZUZac05lcmY3dlArck80cmhtWTFMZzN2RlZvUDgrOEJYZzFzRm53Ym5DazROVGhXOEd1aUtCRGRrVlZ0VE5Gdk5lbFZzTnFUYnlXbklPTTJvZVRSb3lXdndtcEpIZy91Y1hCcmNKdVhUNER3cnB3WmkydnkwVkN4OFl0WGcvRDJiVTRPZml1UTNlRmZFMktENGJmQ3FpTE5COTkzZ1hzR2x3YTJDVDROekJhY0dJVlE2WXNpcFFkaDB4RWRPRFVLakl4clNwODhvblo4emJiRkxnMURvaUZPNUJYdkRHdjJNeTkvSmhVVDhKVVpUSTB5RGFOSExCeklidnFURE5ZaFVpVncva2RqUTFrTTJDSEZEUGpLVytLenlSVEYwZy9nYTl3OXkrZkFOUXB4dlg4Q1UrTnk3RlVXRGVGM1krZzNsUk9JZjRrMFVEWDllQ3l2TzUzMVB5WWhIZ2E5enZQWkpVNWI3M1kvZVhqOEh2OUQ0OG42SGFGNUxiY2pSdDhUWlR0ZGE1TTFEZlhuYmtYMUMwU0hDRkt6UUI1RmU4b3A0R05HTkhhdnZaRVNiVndUNXI2VzF4eXVDUEJZM1k5WWdEcXprbkgvZTNZZk56enVMMzBsMEllYnJaNWtLdHVESVh0MW44NjhFVDZrZjMvNDl0THZyQ2NaeUY4UHUyMTVkQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFjUEliTnJCaE9hQlh1Y29BQUFBQVNVVk9SSzVDWUlJPSI+CjxsaW5rIHJlbD0iYXBwbGUtdG91Y2gtaWNvbiIgaHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFNUUFBQURFQ0FNQUFBRDNlSDVaQUFBQUJHZEJUVUVBQUxHUEMveGhCUUFBQUFGelVrZENBSzdPSE9rQUFBRC9VRXhVUmZGbEtmYUVMdkZtS2ZOeUsvNjdOdldBTGY2OE52NjlOdk54Sy8yME5meXlOUDIyTmZOMEsvSnJLdnFoTXYyek5mMjVOZjI0TmYyM05mZU9ML3l6TlB5dk5QSm9LdmlXTVBtZU1mTjFLL1dCTGZlUEwvRm5LZmVNTC9xbE12UjdMUG1jTWZlTEwvYUpMdlI1TFBGb0tmSnVLdlIzTFA2Nk52eXdOUGVOTC9WL0xmYUlMdjIxTmYyNk5mTnpLL052Sy9SNkxQbWFNZnl4TlBxZk12VitMZnVyTS9pU01QbWJNZkp2S3ZtZE1mdW1NL3FpTXZtWk1meXROUEpxS3Z5c05QTjJLL2lZTVBOd0svdXBNL0p0S3ZKc0t2aVZNUGFITHZhR0x2SnBLdlI4TFBhS0x2cWtNdnVxTS9hRkx2UjRMUHVvTS9pVE1QV0RMZmlSTVBtWU1YUzBuZ2tBQUFMb1NVUkJWSGphN2RybmN0cEFGSWJoRlVJU1NLSjNNS1lhMCt5NHhUVzk5MzcvMTVKa0pobFRqaHJTckhSbXZ1Zi9hczZMMFlMRkNnRUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU1CSjZuamVucXNwemduUHJzckdYOVpwaTJ0Q3JtbmM2K2RZTnRoVlk1V3BNbXhRTFdQZE1zT3VZVnd6TmozZWkydDNtUXdhVjQzQkpQRENTMk5iSjVhRWV1WC8rOXFjalFPdGZGSWtJa3J2WTJnNE1WY21PQnNGV2Jvd0tPL2tOeWo2MmdScEpjRGFQQmx4THIxQjB6ZEcwQy84THpiSmlKcnNodXZ5MWd6bEE5K3JEOG1Ja3V5SUpqRkUzL2Rxbll3b1NtN0lVRVBvRC93dXQ4aUlndVNJRGpsRnhlL3lmWEw1dnVTSTIxQlRaTExoWG9PSUxNTzhIeHdhL0w4YkkwTGZtVWRoR293YjJadlQwZTU3cEZORGdCMDZJbFZ5am1tSUJsMlQvbmw5Unc2U0Q5R2dTRy9RMHVRa2FXM1hobW92S1EzZUZRNE4yVW85T1ExZUZac05lcmY3dlArck80cmhtWTFMZzN2RlZvUDgrOEJYZzFzRm53Ym5DazROVGhXOEd1aUtCRGRrVlZ0VE5Gdk5lbFZzTnFUYnlXbklPTTJvZVRSb3lXdndtcEpIZy91Y1hCcmNKdVhUNER3cnB3WmkydnkwVkN4OFl0WGcvRDJiVTRPZml1UTNlRmZFMktENGJmQ3FpTE5COTkzZ1hzR2x3YTJDVDROekJhY0dJVlE2WXNpcFFkaDB4RWRPRFVLakl4clNwODhvblo4emJiRkxnMURvaUZPNUJYdkRHdjJNeTkvSmhVVDhKVVpUSTB5RGFOSExCeklidnFURE5ZaFVpVncva2RqUTFrTTJDSEZEUGpLVytLenlSVEYwZy9nYTl3OXkrZkFOUXB4dlg4Q1UrTnk3RlVXRGVGM1krZzNsUk9JZjRrMFVEWDllQ3l2TzUzMVB5WWhIZ2E5enZQWkpVNWI3M1kvZVhqOEh2OUQ0OG42SGFGNUxiY2pSdDhUWlR0ZGE1TTFEZlhuYmtYMUMwU0hDRkt6UUI1RmU4b3A0R05HTkhhdnZaRVNiVndUNXI2VzF4eXVDUEJZM1k5WWdEcXprbkgvZTNZZk56enVMMzBsMEllYnJaNWtLdHVESVh0MW44NjhFVDZrZjMvNDl0THZyQ2NaeUY4UHUyMTVkQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFjUEliTnJCaE9hQlh1Y29BQUFBQVNVVk9SSzVDWUlJPSI+CjxzY3JpcHQ+Ly8gQ29weXJpZ2h0IDIwMTQgR29vZ2xlIEluYy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KLy8KLy8gTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7Ci8vIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KLy8gICAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAovLwovLyBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKLy8KLy8gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQovLyBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAovLyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KLy8gICAgIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKLy8gbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCgohZnVuY3Rpb24oYSxiKXt2YXIgYz17fSxkPXt9LGU9e30sZj1udWxsOyFmdW5jdGlvbihhLGIpe2Z1bmN0aW9uIGMoYSl7aWYoIm51bWJlciI9PXR5cGVvZiBhKXJldHVybiBhO3ZhciBiPXt9O2Zvcih2YXIgYyBpbiBhKWJbY109YVtjXTtyZXR1cm4gYn1mdW5jdGlvbiBkKCl7dGhpcy5fZGVsYXk9MCx0aGlzLl9lbmREZWxheT0wLHRoaXMuX2ZpbGw9Im5vbmUiLHRoaXMuX2l0ZXJhdGlvblN0YXJ0PTAsdGhpcy5faXRlcmF0aW9ucz0xLHRoaXMuX2R1cmF0aW9uPTAsdGhpcy5fcGxheWJhY2tSYXRlPTEsdGhpcy5fZGlyZWN0aW9uPSJub3JtYWwiLHRoaXMuX2Vhc2luZz0ibGluZWFyIix0aGlzLl9lYXNpbmdGdW5jdGlvbj13fWZ1bmN0aW9uIGUoKXtyZXR1cm4gYS5pc0RlcHJlY2F0ZWQoIkludmFsaWQgdGltaW5nIGlucHV0cyIsIjIwMTYtMDMtMDIiLCJUeXBlRXJyb3IgZXhjZXB0aW9ucyB3aWxsIGJlIHRocm93biBpbnN0ZWFkLiIsITApfWZ1bmN0aW9uIGYoYixjLGUpe3ZhciBmPW5ldyBkO3JldHVybiBjJiYoZi5maWxsPSJib3RoIixmLmR1cmF0aW9uPSJhdXRvIiksIm51bWJlciIhPXR5cGVvZiBifHxpc05hTihiKT92b2lkIDAhPT1iJiZPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhiKS5mb3JFYWNoKGZ1bmN0aW9uKGMpe2lmKCJhdXRvIiE9YltjXSl7aWYoKCJudW1iZXIiPT10eXBlb2YgZltjXXx8ImR1cmF0aW9uIj09YykmJigibnVtYmVyIiE9dHlwZW9mIGJbY118fGlzTmFOKGJbY10pKSlyZXR1cm47aWYoImZpbGwiPT1jJiYtMT09dS5pbmRleE9mKGJbY10pKXJldHVybjtpZigiZGlyZWN0aW9uIj09YyYmLTE9PXYuaW5kZXhPZihiW2NdKSlyZXR1cm47aWYoInBsYXliYWNrUmF0ZSI9PWMmJjEhPT1iW2NdJiZhLmlzRGVwcmVjYXRlZCgiQW5pbWF0aW9uRWZmZWN0VGltaW5nLnBsYXliYWNrUmF0ZSIsIjIwMTQtMTEtMjgiLCJVc2UgQW5pbWF0aW9uLnBsYXliYWNrUmF0ZSBpbnN0ZWFkLiIpKXJldHVybjtmW2NdPWJbY119fSk6Zi5kdXJhdGlvbj1iLGZ9ZnVuY3Rpb24gZyhhKXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGEmJihhPWlzTmFOKGEpP3tkdXJhdGlvbjowfTp7ZHVyYXRpb246YX0pLGF9ZnVuY3Rpb24gaChiLGMpe3JldHVybiBiPWEubnVtZXJpY1RpbWluZ1RvT2JqZWN0KGIpLGYoYixjKX1mdW5jdGlvbiBpKGEsYixjLGQpe3JldHVybiAwPmF8fGE+MXx8MD5jfHxjPjE/dzpmdW5jdGlvbihlKXtmdW5jdGlvbiBmKGEsYixjKXtyZXR1cm4gMyphKigxLWMpKigxLWMpKmMrMypiKigxLWMpKmMqYytjKmMqY31pZigwPT1lfHwxPT1lKXJldHVybiBlO2Zvcih2YXIgZz0wLGg9MTs7KXt2YXIgaT0oZytoKS8yLGo9ZihhLGMsaSk7aWYoTWF0aC5hYnMoZS1qKTwxZS00KXJldHVybiBmKGIsZCxpKTtlPmo/Zz1pOmg9aX19fWZ1bmN0aW9uIGooYSxiKXtyZXR1cm4gZnVuY3Rpb24oYyl7aWYoYz49MSlyZXR1cm4gMTt2YXIgZD0xL2E7cmV0dXJuIGMrPWIqZCxjLWMlZH19ZnVuY3Rpb24gayhhKXtCfHwoQj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKS5zdHlsZSksQi5hbmltYXRpb25UaW1pbmdGdW5jdGlvbj0iIixCLmFuaW1hdGlvblRpbWluZ0Z1bmN0aW9uPWE7dmFyIGI9Qi5hbmltYXRpb25UaW1pbmdGdW5jdGlvbjtpZigiIj09YiYmZSgpKXRocm93IG5ldyBUeXBlRXJyb3IoYSsiIGlzIG5vdCBhIHZhbGlkIHZhbHVlIGZvciBlYXNpbmciKTt2YXIgYz1ELmV4ZWMoYik7aWYoYylyZXR1cm4gaS5hcHBseSh0aGlzLGMuc2xpY2UoMSkubWFwKE51bWJlcikpO3ZhciBkPUUuZXhlYyhiKTtpZihkKXJldHVybiBqKE51bWJlcihkWzFdKSx7c3RhcnQ6eCxtaWRkbGU6eSxlbmQ6en1bZFsyXV0pO3ZhciBmPUFbYl07cmV0dXJuIGY/Zjp3fWZ1bmN0aW9uIGwoYSl7cmV0dXJuIE1hdGguYWJzKG0oYSkvYS5wbGF5YmFja1JhdGUpfWZ1bmN0aW9uIG0oYSl7cmV0dXJuIGEuZHVyYXRpb24qYS5pdGVyYXRpb25zfWZ1bmN0aW9uIG4oYSxiLGMpe3JldHVybiBudWxsPT1iP0Y6YjxjLmRlbGF5P0c6Yj49Yy5kZWxheSthP0g6SX1mdW5jdGlvbiBvKGEsYixjLGQsZSl7c3dpdGNoKGQpe2Nhc2UgRzpyZXR1cm4iYmFja3dhcmRzIj09Ynx8ImJvdGgiPT1iPzA6bnVsbDtjYXNlIEk6cmV0dXJuIGMtZTtjYXNlIEg6cmV0dXJuImZvcndhcmRzIj09Ynx8ImJvdGgiPT1iP2E6bnVsbDtjYXNlIEY6cmV0dXJuIG51bGx9fWZ1bmN0aW9uIHAoYSxiLGMsZCl7cmV0dXJuKGQucGxheWJhY2tSYXRlPDA/Yi1hOmIpKmQucGxheWJhY2tSYXRlK2N9ZnVuY3Rpb24gcShhLGIsYyxkLGUpe3JldHVybiBjPT09MS8wfHxjPT09LSgxLzApfHxjLWQ9PWImJmUuaXRlcmF0aW9ucyYmKGUuaXRlcmF0aW9ucytlLml0ZXJhdGlvblN0YXJ0KSUxPT0wP2E6YyVhfWZ1bmN0aW9uIHIoYSxiLGMsZCl7cmV0dXJuIDA9PT1jPzA6Yj09YT9kLml0ZXJhdGlvblN0YXJ0K2QuaXRlcmF0aW9ucy0xOk1hdGguZmxvb3IoYy9hKX1mdW5jdGlvbiBzKGEsYixjLGQpe3ZhciBlPWElMj49MSxmPSJub3JtYWwiPT1kLmRpcmVjdGlvbnx8ZC5kaXJlY3Rpb249PShlPyJhbHRlcm5hdGUtcmV2ZXJzZSI6ImFsdGVybmF0ZSIpLGc9Zj9jOmItYyxoPWcvYjtyZXR1cm4gYipkLl9lYXNpbmdGdW5jdGlvbihoKX1mdW5jdGlvbiB0KGEsYixjKXt2YXIgZD1uKGEsYixjKSxlPW8oYSxjLmZpbGwsYixkLGMuZGVsYXkpO2lmKG51bGw9PT1lKXJldHVybiBudWxsO2lmKDA9PT1hKXJldHVybiBkPT09Rz8wOjE7dmFyIGY9Yy5pdGVyYXRpb25TdGFydCpjLmR1cmF0aW9uLGc9cChhLGUsZixjKSxoPXEoYy5kdXJhdGlvbixtKGMpLGcsZixjKSxpPXIoYy5kdXJhdGlvbixoLGcsYyk7cmV0dXJuIHMoaSxjLmR1cmF0aW9uLGgsYykvYy5kdXJhdGlvbn12YXIgdT0iYmFja3dhcmRzfGZvcndhcmRzfGJvdGh8bm9uZSIuc3BsaXQoInwiKSx2PSJyZXZlcnNlfGFsdGVybmF0ZXxhbHRlcm5hdGUtcmV2ZXJzZSIuc3BsaXQoInwiKSx3PWZ1bmN0aW9uKGEpe3JldHVybiBhfTtkLnByb3RvdHlwZT17X3NldE1lbWJlcjpmdW5jdGlvbihiLGMpe3RoaXNbIl8iK2JdPWMsdGhpcy5fZWZmZWN0JiYodGhpcy5fZWZmZWN0Ll90aW1pbmdJbnB1dFtiXT1jLHRoaXMuX2VmZmVjdC5fdGltaW5nPWEubm9ybWFsaXplVGltaW5nSW5wdXQodGhpcy5fZWZmZWN0Ll90aW1pbmdJbnB1dCksdGhpcy5fZWZmZWN0LmFjdGl2ZUR1cmF0aW9uPWEuY2FsY3VsYXRlQWN0aXZlRHVyYXRpb24odGhpcy5fZWZmZWN0Ll90aW1pbmcpLHRoaXMuX2VmZmVjdC5fYW5pbWF0aW9uJiZ0aGlzLl9lZmZlY3QuX2FuaW1hdGlvbi5fcmVidWlsZFVuZGVybHlpbmdBbmltYXRpb24oKSl9LGdldCBwbGF5YmFja1JhdGUoKXtyZXR1cm4gdGhpcy5fcGxheWJhY2tSYXRlfSxzZXQgZGVsYXkoYSl7dGhpcy5fc2V0TWVtYmVyKCJkZWxheSIsYSl9LGdldCBkZWxheSgpe3JldHVybiB0aGlzLl9kZWxheX0sc2V0IGVuZERlbGF5KGEpe3RoaXMuX3NldE1lbWJlcigiZW5kRGVsYXkiLGEpfSxnZXQgZW5kRGVsYXkoKXtyZXR1cm4gdGhpcy5fZW5kRGVsYXl9LHNldCBmaWxsKGEpe3RoaXMuX3NldE1lbWJlcigiZmlsbCIsYSl9LGdldCBmaWxsKCl7cmV0dXJuIHRoaXMuX2ZpbGx9LHNldCBpdGVyYXRpb25TdGFydChhKXtpZigoaXNOYU4oYSl8fDA+YSkmJmUoKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJpdGVyYXRpb25TdGFydCBtdXN0IGJlIGEgbm9uLW5lZ2F0aXZlIG51bWJlciwgcmVjZWl2ZWQ6ICIrdGltaW5nLml0ZXJhdGlvblN0YXJ0KTt0aGlzLl9zZXRNZW1iZXIoIml0ZXJhdGlvblN0YXJ0IixhKX0sZ2V0IGl0ZXJhdGlvblN0YXJ0KCl7cmV0dXJuIHRoaXMuX2l0ZXJhdGlvblN0YXJ0fSxzZXQgZHVyYXRpb24oYSl7aWYoImF1dG8iIT1hJiYoaXNOYU4oYSl8fDA+YSkmJmUoKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJkdXJhdGlvbiBtdXN0IGJlIG5vbi1uZWdhdGl2ZSBvciBhdXRvLCByZWNlaXZlZDogIithKTt0aGlzLl9zZXRNZW1iZXIoImR1cmF0aW9uIixhKX0sZ2V0IGR1cmF0aW9uKCl7cmV0dXJuIHRoaXMuX2R1cmF0aW9ufSxzZXQgZGlyZWN0aW9uKGEpe3RoaXMuX3NldE1lbWJlcigiZGlyZWN0aW9uIixhKX0sZ2V0IGRpcmVjdGlvbigpe3JldHVybiB0aGlzLl9kaXJlY3Rpb259LHNldCBlYXNpbmcoYSl7dGhpcy5fZWFzaW5nRnVuY3Rpb249ayhhKSx0aGlzLl9zZXRNZW1iZXIoImVhc2luZyIsYSl9LGdldCBlYXNpbmcoKXtyZXR1cm4gdGhpcy5fZWFzaW5nfSxzZXQgaXRlcmF0aW9ucyhhKXtpZigoaXNOYU4oYSl8fDA+YSkmJmUoKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJpdGVyYXRpb25zIG11c3QgYmUgbm9uLW5lZ2F0aXZlLCByZWNlaXZlZDogIithKTt0aGlzLl9zZXRNZW1iZXIoIml0ZXJhdGlvbnMiLGEpfSxnZXQgaXRlcmF0aW9ucygpe3JldHVybiB0aGlzLl9pdGVyYXRpb25zfX07dmFyIHg9MSx5PS41LHo9MCxBPXtlYXNlOmkoLjI1LC4xLC4yNSwxKSwiZWFzZS1pbiI6aSguNDIsMCwxLDEpLCJlYXNlLW91dCI6aSgwLDAsLjU4LDEpLCJlYXNlLWluLW91dCI6aSguNDIsMCwuNTgsMSksInN0ZXAtc3RhcnQiOmooMSx4KSwic3RlcC1taWRkbGUiOmooMSx5KSwic3RlcC1lbmQiOmooMSx6KX0sQj1udWxsLEM9IlxccyooLT9cXGQrXFwuP1xcZCp8LT9cXC5cXGQrKVxccyoiLEQ9bmV3IFJlZ0V4cCgiY3ViaWMtYmV6aWVyXFwoIitDKyIsIitDKyIsIitDKyIsIitDKyJcXCkiKSxFPS9zdGVwc1woXHMqKFxkKylccyosXHMqKHN0YXJ0fG1pZGRsZXxlbmQpXHMqXCkvLEY9MCxHPTEsSD0yLEk9MzthLmNsb25lVGltaW5nSW5wdXQ9YyxhLm1ha2VUaW1pbmc9ZixhLm51bWVyaWNUaW1pbmdUb09iamVjdD1nLGEubm9ybWFsaXplVGltaW5nSW5wdXQ9aCxhLmNhbGN1bGF0ZUFjdGl2ZUR1cmF0aW9uPWwsYS5jYWxjdWxhdGVUaW1lRnJhY3Rpb249dCxhLmNhbGN1bGF0ZVBoYXNlPW4sYS50b1RpbWluZ0Z1bmN0aW9uPWt9KGMsZiksZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7cmV0dXJuIGEgaW4gaj9qW2FdW2JdfHxiOmJ9ZnVuY3Rpb24gZChhLGIsZCl7dmFyIGU9Z1thXTtpZihlKXtoLnN0eWxlW2FdPWI7Zm9yKHZhciBmIGluIGUpe3ZhciBpPWVbZl0saj1oLnN0eWxlW2ldO2RbaV09YyhpLGopfX1lbHNlIGRbYV09YyhhLGIpfWZ1bmN0aW9uIGUoYSl7dmFyIGI9W107Zm9yKHZhciBjIGluIGEpaWYoIShjIGluWyJlYXNpbmciLCJvZmZzZXQiLCJjb21wb3NpdGUiXSkpe3ZhciBkPWFbY107QXJyYXkuaXNBcnJheShkKXx8KGQ9W2RdKTtmb3IodmFyIGUsZj1kLmxlbmd0aCxnPTA7Zj5nO2crKyllPXt9LCJvZmZzZXQiaW4gYT9lLm9mZnNldD1hLm9mZnNldDoxPT1mP2Uub2Zmc2V0PTE6ZS5vZmZzZXQ9Zy8oZi0xKSwiZWFzaW5nImluIGEmJihlLmVhc2luZz1hLmVhc2luZyksImNvbXBvc2l0ZSJpbiBhJiYoZS5jb21wb3NpdGU9YS5jb21wb3NpdGUpLGVbY109ZFtnXSxiLnB1c2goZSl9cmV0dXJuIGIuc29ydChmdW5jdGlvbihhLGIpe3JldHVybiBhLm9mZnNldC1iLm9mZnNldH0pLGJ9ZnVuY3Rpb24gZihhKXtmdW5jdGlvbiBiKCl7dmFyIGE9Yy5sZW5ndGg7bnVsbD09Y1thLTFdLm9mZnNldCYmKGNbYS0xXS5vZmZzZXQ9MSksYT4xJiZudWxsPT1jWzBdLm9mZnNldCYmKGNbMF0ub2Zmc2V0PTApO2Zvcih2YXIgYj0wLGQ9Y1swXS5vZmZzZXQsZT0xO2E+ZTtlKyspe3ZhciBmPWNbZV0ub2Zmc2V0O2lmKG51bGwhPWYpe2Zvcih2YXIgZz0xO2UtYj5nO2crKyljW2IrZ10ub2Zmc2V0PWQrKGYtZCkqZy8oZS1iKTtiPWUsZD1mfX19aWYobnVsbD09YSlyZXR1cm5bXTt3aW5kb3cuU3ltYm9sJiZTeW1ib2wuaXRlcmF0b3ImJkFycmF5LnByb3RvdHlwZS5mcm9tJiZhW1N5bWJvbC5pdGVyYXRvcl0mJihhPUFycmF5LmZyb20oYSkpLEFycmF5LmlzQXJyYXkoYSl8fChhPWUoYSkpO2Zvcih2YXIgYz1hLm1hcChmdW5jdGlvbihhKXt2YXIgYj17fTtmb3IodmFyIGMgaW4gYSl7dmFyIGU9YVtjXTtpZigib2Zmc2V0Ij09Yyl7aWYobnVsbCE9ZSYmKGU9TnVtYmVyKGUpLCFpc0Zpbml0ZShlKSkpdGhyb3cgbmV3IFR5cGVFcnJvcigia2V5ZnJhbWUgb2Zmc2V0cyBtdXN0IGJlIG51bWJlcnMuIil9ZWxzZXtpZigiY29tcG9zaXRlIj09Yyl0aHJvd3t0eXBlOkRPTUV4Y2VwdGlvbi5OT1RfU1VQUE9SVEVEX0VSUixuYW1lOiJOb3RTdXBwb3J0ZWRFcnJvciIsbWVzc2FnZToiYWRkIGNvbXBvc2l0aW5nIGlzIG5vdCBzdXBwb3J0ZWQifTtlPSIiK2V9ZChjLGUsYil9cmV0dXJuIHZvaWQgMD09Yi5vZmZzZXQmJihiLm9mZnNldD1udWxsKSxifSksZj0hMCxnPS0oMS8wKSxoPTA7aDxjLmxlbmd0aDtoKyspe3ZhciBpPWNbaF0ub2Zmc2V0O2lmKG51bGwhPWkpe2lmKGc+aSl0aHJvd3tjb2RlOkRPTUV4Y2VwdGlvbi5JTlZBTElEX01PRElGSUNBVElPTl9FUlIsbmFtZToiSW52YWxpZE1vZGlmaWNhdGlvbkVycm9yIixtZXNzYWdlOiJLZXlmcmFtZXMgYXJlIG5vdCBsb29zZWx5IHNvcnRlZCBieSBvZmZzZXQuIFNvcnQgb3Igc3BlY2lmeSBvZmZzZXRzLiJ9O2c9aX1lbHNlIGY9ITF9cmV0dXJuIGM9Yy5maWx0ZXIoZnVuY3Rpb24oYSl7cmV0dXJuIGEub2Zmc2V0Pj0wJiZhLm9mZnNldDw9MX0pLGZ8fGIoKSxjfXZhciBnPXtiYWNrZ3JvdW5kOlsiYmFja2dyb3VuZEltYWdlIiwiYmFja2dyb3VuZFBvc2l0aW9uIiwiYmFja2dyb3VuZFNpemUiLCJiYWNrZ3JvdW5kUmVwZWF0IiwiYmFja2dyb3VuZEF0dGFjaG1lbnQiLCJiYWNrZ3JvdW5kT3JpZ2luIiwiYmFja2dyb3VuZENsaXAiLCJiYWNrZ3JvdW5kQ29sb3IiXSxib3JkZXI6WyJib3JkZXJUb3BDb2xvciIsImJvcmRlclRvcFN0eWxlIiwiYm9yZGVyVG9wV2lkdGgiLCJib3JkZXJSaWdodENvbG9yIiwiYm9yZGVyUmlnaHRTdHlsZSIsImJvcmRlclJpZ2h0V2lkdGgiLCJib3JkZXJCb3R0b21Db2xvciIsImJvcmRlckJvdHRvbVN0eWxlIiwiYm9yZGVyQm90dG9tV2lkdGgiLCJib3JkZXJMZWZ0Q29sb3IiLCJib3JkZXJMZWZ0U3R5bGUiLCJib3JkZXJMZWZ0V2lkdGgiXSxib3JkZXJCb3R0b206WyJib3JkZXJCb3R0b21XaWR0aCIsImJvcmRlckJvdHRvbVN0eWxlIiwiYm9yZGVyQm90dG9tQ29sb3IiXSxib3JkZXJDb2xvcjpbImJvcmRlclRvcENvbG9yIiwiYm9yZGVyUmlnaHRDb2xvciIsImJvcmRlckJvdHRvbUNvbG9yIiwiYm9yZGVyTGVmdENvbG9yIl0sYm9yZGVyTGVmdDpbImJvcmRlckxlZnRXaWR0aCIsImJvcmRlckxlZnRTdHlsZSIsImJvcmRlckxlZnRDb2xvciJdLGJvcmRlclJhZGl1czpbImJvcmRlclRvcExlZnRSYWRpdXMiLCJib3JkZXJUb3BSaWdodFJhZGl1cyIsImJvcmRlckJvdHRvbVJpZ2h0UmFkaXVzIiwiYm9yZGVyQm90dG9tTGVmdFJhZGl1cyJdLGJvcmRlclJpZ2h0OlsiYm9yZGVyUmlnaHRXaWR0aCIsImJvcmRlclJpZ2h0U3R5bGUiLCJib3JkZXJSaWdodENvbG9yIl0sYm9yZGVyVG9wOlsiYm9yZGVyVG9wV2lkdGgiLCJib3JkZXJUb3BTdHlsZSIsImJvcmRlclRvcENvbG9yIl0sYm9yZGVyV2lkdGg6WyJib3JkZXJUb3BXaWR0aCIsImJvcmRlclJpZ2h0V2lkdGgiLCJib3JkZXJCb3R0b21XaWR0aCIsImJvcmRlckxlZnRXaWR0aCJdLGZsZXg6WyJmbGV4R3JvdyIsImZsZXhTaHJpbmsiLCJmbGV4QmFzaXMiXSxmb250OlsiZm9udEZhbWlseSIsImZvbnRTaXplIiwiZm9udFN0eWxlIiwiZm9udFZhcmlhbnQiLCJmb250V2VpZ2h0IiwibGluZUhlaWdodCJdLG1hcmdpbjpbIm1hcmdpblRvcCIsIm1hcmdpblJpZ2h0IiwibWFyZ2luQm90dG9tIiwibWFyZ2luTGVmdCJdLG91dGxpbmU6WyJvdXRsaW5lQ29sb3IiLCJvdXRsaW5lU3R5bGUiLCJvdXRsaW5lV2lkdGgiXSxwYWRkaW5nOlsicGFkZGluZ1RvcCIsInBhZGRpbmdSaWdodCIsInBhZGRpbmdCb3R0b20iLCJwYWRkaW5nTGVmdCJdfSxoPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUygiaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIsImRpdiIpLGk9e3RoaW46IjFweCIsbWVkaXVtOiIzcHgiLHRoaWNrOiI1cHgifSxqPXtib3JkZXJCb3R0b21XaWR0aDppLGJvcmRlckxlZnRXaWR0aDppLGJvcmRlclJpZ2h0V2lkdGg6aSxib3JkZXJUb3BXaWR0aDppLGZvbnRTaXplOnsieHgtc21hbGwiOiI2MCUiLCJ4LXNtYWxsIjoiNzUlIixzbWFsbDoiODklIixtZWRpdW06IjEwMCUiLGxhcmdlOiIxMjAlIiwieC1sYXJnZSI6IjE1MCUiLCJ4eC1sYXJnZSI6IjIwMCUifSxmb250V2VpZ2h0Ontub3JtYWw6IjQwMCIsYm9sZDoiNzAwIn0sb3V0bGluZVdpZHRoOmksdGV4dFNoYWRvdzp7bm9uZToiMHB4IDBweCAwcHggdHJhbnNwYXJlbnQifSxib3hTaGFkb3c6e25vbmU6IjBweCAwcHggMHB4IDBweCB0cmFuc3BhcmVudCJ9fTthLmNvbnZlcnRUb0FycmF5Rm9ybT1lLGEubm9ybWFsaXplS2V5ZnJhbWVzPWZ9KGMsZiksZnVuY3Rpb24oYSl7dmFyIGI9e307YS5pc0RlcHJlY2F0ZWQ9ZnVuY3Rpb24oYSxjLGQsZSl7dmFyIGY9ZT8iYXJlIjoiaXMiLGc9bmV3IERhdGUsaD1uZXcgRGF0ZShjKTtyZXR1cm4gaC5zZXRNb250aChoLmdldE1vbnRoKCkrMyksaD5nPyhhIGluIGJ8fGNvbnNvbGUud2FybigiV2ViIEFuaW1hdGlvbnM6ICIrYSsiICIrZisiIGRlcHJlY2F0ZWQgYW5kIHdpbGwgc3RvcCB3b3JraW5nIG9uICIraC50b0RhdGVTdHJpbmcoKSsiLiAiK2QpLGJbYV09ITAsITEpOiEwfSxhLmRlcHJlY2F0ZWQ9ZnVuY3Rpb24oYixjLGQsZSl7dmFyIGY9ZT8iYXJlIjoiaXMiO2lmKGEuaXNEZXByZWNhdGVkKGIsYyxkLGUpKXRocm93IG5ldyBFcnJvcihiKyIgIitmKyIgbm8gbG9uZ2VyIHN1cHBvcnRlZC4gIitkKX19KGMpLGZ1bmN0aW9uKCl7aWYoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmFuaW1hdGUpe3ZhciBhPWRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5hbmltYXRlKFtdLDApLGI9ITA7aWYoYSYmKGI9ITEsInBsYXl8Y3VycmVudFRpbWV8cGF1c2V8cmV2ZXJzZXxwbGF5YmFja1JhdGV8Y2FuY2VsfGZpbmlzaHxzdGFydFRpbWV8cGxheVN0YXRlIi5zcGxpdCgifCIpLmZvckVhY2goZnVuY3Rpb24oYyl7dm9pZCAwPT09YVtjXSYmKGI9ITApfSkpLCFiKXJldHVybn0hZnVuY3Rpb24oYSxiLGMpe2Z1bmN0aW9uIGQoYSl7Zm9yKHZhciBiPXt9LGM9MDtjPGEubGVuZ3RoO2MrKylmb3IodmFyIGQgaW4gYVtjXSlpZigib2Zmc2V0IiE9ZCYmImVhc2luZyIhPWQmJiJjb21wb3NpdGUiIT1kKXt2YXIgZT17b2Zmc2V0OmFbY10ub2Zmc2V0LGVhc2luZzphW2NdLmVhc2luZyx2YWx1ZTphW2NdW2RdfTtiW2RdPWJbZF18fFtdLGJbZF0ucHVzaChlKX1mb3IodmFyIGYgaW4gYil7dmFyIGc9YltmXTtpZigwIT1nWzBdLm9mZnNldHx8MSE9Z1tnLmxlbmd0aC0xXS5vZmZzZXQpdGhyb3d7dHlwZTpET01FeGNlcHRpb24uTk9UX1NVUFBPUlRFRF9FUlIsbmFtZToiTm90U3VwcG9ydGVkRXJyb3IiLG1lc3NhZ2U6IlBhcnRpYWwga2V5ZnJhbWVzIGFyZSBub3Qgc3VwcG9ydGVkIn19cmV0dXJuIGJ9ZnVuY3Rpb24gZShjKXt2YXIgZD1bXTtmb3IodmFyIGUgaW4gYylmb3IodmFyIGY9Y1tlXSxnPTA7ZzxmLmxlbmd0aC0xO2crKyl7dmFyIGg9ZltnXS5vZmZzZXQsaT1mW2crMV0ub2Zmc2V0LGo9ZltnXS52YWx1ZSxrPWZbZysxXS52YWx1ZSxsPWZbZ10uZWFzaW5nO2g9PWkmJigxPT1pP2o9azprPWopLGQucHVzaCh7c3RhcnRUaW1lOmgsZW5kVGltZTppLGVhc2luZzphLnRvVGltaW5nRnVuY3Rpb24obD9sOiJsaW5lYXIiKSxwcm9wZXJ0eTplLGludGVycG9sYXRpb246Yi5wcm9wZXJ0eUludGVycG9sYXRpb24oZSxqLGspfSl9cmV0dXJuIGQuc29ydChmdW5jdGlvbihhLGIpe3JldHVybiBhLnN0YXJ0VGltZS1iLnN0YXJ0VGltZX0pLGR9Yi5jb252ZXJ0RWZmZWN0SW5wdXQ9ZnVuY3Rpb24oYyl7dmFyIGY9YS5ub3JtYWxpemVLZXlmcmFtZXMoYyksZz1kKGYpLGg9ZShnKTtyZXR1cm4gZnVuY3Rpb24oYSxjKXtpZihudWxsIT1jKWguZmlsdGVyKGZ1bmN0aW9uKGEpe3JldHVybiAwPj1jJiYwPT1hLnN0YXJ0VGltZXx8Yz49MSYmMT09YS5lbmRUaW1lfHxjPj1hLnN0YXJ0VGltZSYmYzw9YS5lbmRUaW1lfSkuZm9yRWFjaChmdW5jdGlvbihkKXt2YXIgZT1jLWQuc3RhcnRUaW1lLGY9ZC5lbmRUaW1lLWQuc3RhcnRUaW1lLGc9MD09Zj8wOmQuZWFzaW5nKGUvZik7Yi5hcHBseShhLGQucHJvcGVydHksZC5pbnRlcnBvbGF0aW9uKGcpKX0pO2Vsc2UgZm9yKHZhciBkIGluIGcpIm9mZnNldCIhPWQmJiJlYXNpbmciIT1kJiYiY29tcG9zaXRlIiE9ZCYmYi5jbGVhcihhLGQpfX19KGMsZCxmKSxmdW5jdGlvbihhLGIsYyl7ZnVuY3Rpb24gZChhKXtyZXR1cm4gYS5yZXBsYWNlKC8tKC4pL2csZnVuY3Rpb24oYSxiKXtyZXR1cm4gYi50b1VwcGVyQ2FzZSgpfSl9ZnVuY3Rpb24gZShhLGIsYyl7aFtjXT1oW2NdfHxbXSxoW2NdLnB1c2goW2EsYl0pfWZ1bmN0aW9uIGYoYSxiLGMpe2Zvcih2YXIgZj0wO2Y8Yy5sZW5ndGg7ZisrKXt2YXIgZz1jW2ZdO2UoYSxiLGQoZykpfX1mdW5jdGlvbiBnKGMsZSxmKXt2YXIgZz1jOy8tLy50ZXN0KGMpJiYhYS5pc0RlcHJlY2F0ZWQoIkh5cGhlbmF0ZWQgcHJvcGVydHkgbmFtZXMiLCIyMDE2LTAzLTIyIiwiVXNlIGNhbWVsQ2FzZSBpbnN0ZWFkLiIsITApJiYoZz1kKGMpKSwiaW5pdGlhbCIhPWUmJiJpbml0aWFsIiE9Znx8KCJpbml0aWFsIj09ZSYmKGU9aVtnXSksImluaXRpYWwiPT1mJiYoZj1pW2ddKSk7Zm9yKHZhciBqPWU9PWY/W106aFtnXSxrPTA7aiYmazxqLmxlbmd0aDtrKyspe3ZhciBsPWpba11bMF0oZSksbT1qW2tdWzBdKGYpO2lmKHZvaWQgMCE9PWwmJnZvaWQgMCE9PW0pe3ZhciBuPWpba11bMV0obCxtKTtpZihuKXt2YXIgbz1iLkludGVycG9sYXRpb24uYXBwbHkobnVsbCxuKTtyZXR1cm4gZnVuY3Rpb24oYSl7cmV0dXJuIDA9PWE/ZToxPT1hP2Y6byhhKX19fX1yZXR1cm4gYi5JbnRlcnBvbGF0aW9uKCExLCEwLGZ1bmN0aW9uKGEpe3JldHVybiBhP2Y6ZX0pfXZhciBoPXt9O2IuYWRkUHJvcGVydGllc0hhbmRsZXI9Zjt2YXIgaT17YmFja2dyb3VuZENvbG9yOiJ0cmFuc3BhcmVudCIsYmFja2dyb3VuZFBvc2l0aW9uOiIwJSAwJSIsYm9yZGVyQm90dG9tQ29sb3I6ImN1cnJlbnRDb2xvciIsYm9yZGVyQm90dG9tTGVmdFJhZGl1czoiMHB4Iixib3JkZXJCb3R0b21SaWdodFJhZGl1czoiMHB4Iixib3JkZXJCb3R0b21XaWR0aDoiM3B4Iixib3JkZXJMZWZ0Q29sb3I6ImN1cnJlbnRDb2xvciIsYm9yZGVyTGVmdFdpZHRoOiIzcHgiLGJvcmRlclJpZ2h0Q29sb3I6ImN1cnJlbnRDb2xvciIsYm9yZGVyUmlnaHRXaWR0aDoiM3B4Iixib3JkZXJTcGFjaW5nOiIycHgiLGJvcmRlclRvcENvbG9yOiJjdXJyZW50Q29sb3IiLGJvcmRlclRvcExlZnRSYWRpdXM6IjBweCIsYm9yZGVyVG9wUmlnaHRSYWRpdXM6IjBweCIsYm9yZGVyVG9wV2lkdGg6IjNweCIsYm90dG9tOiJhdXRvIixjbGlwOiJyZWN0KDBweCwgMHB4LCAwcHgsIDBweCkiLGNvbG9yOiJibGFjayIsZm9udFNpemU6IjEwMCUiLGZvbnRXZWlnaHQ6IjQwMCIsaGVpZ2h0OiJhdXRvIixsZWZ0OiJhdXRvIixsZXR0ZXJTcGFjaW5nOiJub3JtYWwiLGxpbmVIZWlnaHQ6IjEyMCUiLG1hcmdpbkJvdHRvbToiMHB4IixtYXJnaW5MZWZ0OiIwcHgiLG1hcmdpblJpZ2h0OiIwcHgiLG1hcmdpblRvcDoiMHB4IixtYXhIZWlnaHQ6Im5vbmUiLG1heFdpZHRoOiJub25lIixtaW5IZWlnaHQ6IjBweCIsbWluV2lkdGg6IjBweCIsb3BhY2l0eToiMS4wIixvdXRsaW5lQ29sb3I6ImludmVydCIsb3V0bGluZU9mZnNldDoiMHB4IixvdXRsaW5lV2lkdGg6IjNweCIscGFkZGluZ0JvdHRvbToiMHB4IixwYWRkaW5nTGVmdDoiMHB4IixwYWRkaW5nUmlnaHQ6IjBweCIscGFkZGluZ1RvcDoiMHB4IixyaWdodDoiYXV0byIsdGV4dEluZGVudDoiMHB4Iix0ZXh0U2hhZG93OiIwcHggMHB4IDBweCB0cmFuc3BhcmVudCIsdG9wOiJhdXRvIix0cmFuc2Zvcm06IiIsdmVydGljYWxBbGlnbjoiMHB4Iix2aXNpYmlsaXR5OiJ2aXNpYmxlIix3aWR0aDoiYXV0byIsd29yZFNwYWNpbmc6Im5vcm1hbCIsekluZGV4OiJhdXRvIn07Yi5wcm9wZXJ0eUludGVycG9sYXRpb249Z30oYyxkLGYpLGZ1bmN0aW9uKGEsYixjKXtmdW5jdGlvbiBkKGIpe3ZhciBjPWEuY2FsY3VsYXRlQWN0aXZlRHVyYXRpb24oYiksZD1mdW5jdGlvbihkKXtyZXR1cm4gYS5jYWxjdWxhdGVUaW1lRnJhY3Rpb24oYyxkLGIpfTtyZXR1cm4gZC5fdG90YWxEdXJhdGlvbj1iLmRlbGF5K2MrYi5lbmREZWxheSxkLl9pc0N1cnJlbnQ9ZnVuY3Rpb24oZCl7dmFyIGU9YS5jYWxjdWxhdGVQaGFzZShjLGQsYik7cmV0dXJuIGU9PT1QaGFzZUFjdGl2ZXx8ZT09PVBoYXNlQmVmb3JlfSxkfWIuS2V5ZnJhbWVFZmZlY3Q9ZnVuY3Rpb24oYyxlLGYsZyl7dmFyIGgsaT1kKGEubm9ybWFsaXplVGltaW5nSW5wdXQoZikpLGo9Yi5jb252ZXJ0RWZmZWN0SW5wdXQoZSksaz1mdW5jdGlvbigpe2ooYyxoKX07cmV0dXJuIGsuX3VwZGF0ZT1mdW5jdGlvbihhKXtyZXR1cm4gaD1pKGEpLG51bGwhPT1ofSxrLl9jbGVhcj1mdW5jdGlvbigpe2ooYyxudWxsKX0say5faGFzU2FtZVRhcmdldD1mdW5jdGlvbihhKXtyZXR1cm4gYz09PWF9LGsuX2lzQ3VycmVudD1pLl9pc0N1cnJlbnQsay5fdG90YWxEdXJhdGlvbj1pLl90b3RhbER1cmF0aW9uLGsuX2lkPWcsa30sYi5OdWxsRWZmZWN0PWZ1bmN0aW9uKGEpe3ZhciBiPWZ1bmN0aW9uKCl7YSYmKGEoKSxhPW51bGwpfTtyZXR1cm4gYi5fdXBkYXRlPWZ1bmN0aW9uKCl7cmV0dXJuIG51bGx9LGIuX3RvdGFsRHVyYXRpb249MCxiLl9pc0N1cnJlbnQ9ZnVuY3Rpb24oKXtyZXR1cm4hMX0sYi5faGFzU2FtZVRhcmdldD1mdW5jdGlvbigpe3JldHVybiExfSxifX0oYyxkLGYpLGZ1bmN0aW9uKGEsYil7YS5hcHBseT1mdW5jdGlvbihiLGMsZCl7Yi5zdHlsZVthLnByb3BlcnR5TmFtZShjKV09ZH0sYS5jbGVhcj1mdW5jdGlvbihiLGMpe2Iuc3R5bGVbYS5wcm9wZXJ0eU5hbWUoYyldPSIifX0oZCxmKSxmdW5jdGlvbihhKXt3aW5kb3cuRWxlbWVudC5wcm90b3R5cGUuYW5pbWF0ZT1mdW5jdGlvbihiLGMpe3ZhciBkPSIiO3JldHVybiBjJiZjLmlkJiYoZD1jLmlkKSxhLnRpbWVsaW5lLl9wbGF5KGEuS2V5ZnJhbWVFZmZlY3QodGhpcyxiLGMsZCkpfX0oZCksZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYixkKXtpZigibnVtYmVyIj09dHlwZW9mIGEmJiJudW1iZXIiPT10eXBlb2YgYilyZXR1cm4gYSooMS1kKStiKmQ7aWYoImJvb2xlYW4iPT10eXBlb2YgYSYmImJvb2xlYW4iPT10eXBlb2YgYilyZXR1cm4uNT5kP2E6YjtpZihhLmxlbmd0aD09Yi5sZW5ndGgpe2Zvcih2YXIgZT1bXSxmPTA7ZjxhLmxlbmd0aDtmKyspZS5wdXNoKGMoYVtmXSxiW2ZdLGQpKTtyZXR1cm4gZX10aHJvdyJNaXNtYXRjaGVkIGludGVycG9sYXRpb24gYXJndW1lbnRzICIrYSsiOiIrYn1hLkludGVycG9sYXRpb249ZnVuY3Rpb24oYSxiLGQpe3JldHVybiBmdW5jdGlvbihlKXtyZXR1cm4gZChjKGEsYixlKSl9fX0oZCxmKSxmdW5jdGlvbihhLGIsYyl7YS5zZXF1ZW5jZU51bWJlcj0wO3ZhciBkPWZ1bmN0aW9uKGEsYixjKXt0aGlzLnRhcmdldD1hLHRoaXMuY3VycmVudFRpbWU9Yix0aGlzLnRpbWVsaW5lVGltZT1jLHRoaXMudHlwZT0iZmluaXNoIix0aGlzLmJ1YmJsZXM9ITEsdGhpcy5jYW5jZWxhYmxlPSExLHRoaXMuY3VycmVudFRhcmdldD1hLHRoaXMuZGVmYXVsdFByZXZlbnRlZD0hMSx0aGlzLmV2ZW50UGhhc2U9RXZlbnQuQVRfVEFSR0VULHRoaXMudGltZVN0YW1wPURhdGUubm93KCl9O2IuQW5pbWF0aW9uPWZ1bmN0aW9uKGIpe3RoaXMuaWQ9IiIsYiYmYi5faWQmJih0aGlzLmlkPWIuX2lkKSx0aGlzLl9zZXF1ZW5jZU51bWJlcj1hLnNlcXVlbmNlTnVtYmVyKyssdGhpcy5fY3VycmVudFRpbWU9MCx0aGlzLl9zdGFydFRpbWU9bnVsbCx0aGlzLl9wYXVzZWQ9ITEsdGhpcy5fcGxheWJhY2tSYXRlPTEsdGhpcy5faW5UaW1lbGluZT0hMCx0aGlzLl9maW5pc2hlZEZsYWc9ITAsdGhpcy5vbmZpbmlzaD1udWxsLHRoaXMuX2ZpbmlzaEhhbmRsZXJzPVtdLHRoaXMuX2VmZmVjdD1iLHRoaXMuX2luRWZmZWN0PXRoaXMuX2VmZmVjdC5fdXBkYXRlKDApLHRoaXMuX2lkbGU9ITAsdGhpcy5fY3VycmVudFRpbWVQZW5kaW5nPSExfSxiLkFuaW1hdGlvbi5wcm90b3R5cGU9e19lbnN1cmVBbGl2ZTpmdW5jdGlvbigpe3RoaXMucGxheWJhY2tSYXRlPDAmJjA9PT10aGlzLmN1cnJlbnRUaW1lP3RoaXMuX2luRWZmZWN0PXRoaXMuX2VmZmVjdC5fdXBkYXRlKC0xKTp0aGlzLl9pbkVmZmVjdD10aGlzLl9lZmZlY3QuX3VwZGF0ZSh0aGlzLmN1cnJlbnRUaW1lKSx0aGlzLl9pblRpbWVsaW5lfHwhdGhpcy5faW5FZmZlY3QmJnRoaXMuX2ZpbmlzaGVkRmxhZ3x8KHRoaXMuX2luVGltZWxpbmU9ITAsYi50aW1lbGluZS5fYW5pbWF0aW9ucy5wdXNoKHRoaXMpKX0sX3RpY2tDdXJyZW50VGltZTpmdW5jdGlvbihhLGIpe2EhPXRoaXMuX2N1cnJlbnRUaW1lJiYodGhpcy5fY3VycmVudFRpbWU9YSx0aGlzLl9pc0ZpbmlzaGVkJiYhYiYmKHRoaXMuX2N1cnJlbnRUaW1lPXRoaXMuX3BsYXliYWNrUmF0ZT4wP3RoaXMuX3RvdGFsRHVyYXRpb246MCksdGhpcy5fZW5zdXJlQWxpdmUoKSl9LGdldCBjdXJyZW50VGltZSgpe3JldHVybiB0aGlzLl9pZGxlfHx0aGlzLl9jdXJyZW50VGltZVBlbmRpbmc/bnVsbDp0aGlzLl9jdXJyZW50VGltZX0sc2V0IGN1cnJlbnRUaW1lKGEpe2E9K2EsaXNOYU4oYSl8fChiLnJlc3RhcnQoKSx0aGlzLl9wYXVzZWR8fG51bGw9PXRoaXMuX3N0YXJ0VGltZXx8KHRoaXMuX3N0YXJ0VGltZT10aGlzLl90aW1lbGluZS5jdXJyZW50VGltZS1hL3RoaXMuX3BsYXliYWNrUmF0ZSksdGhpcy5fY3VycmVudFRpbWVQZW5kaW5nPSExLHRoaXMuX2N1cnJlbnRUaW1lIT1hJiYodGhpcy5fdGlja0N1cnJlbnRUaW1lKGEsITApLGIuaW52YWxpZGF0ZUVmZmVjdHMoKSkpfSxnZXQgc3RhcnRUaW1lKCl7cmV0dXJuIHRoaXMuX3N0YXJ0VGltZX0sc2V0IHN0YXJ0VGltZShhKXthPSthLGlzTmFOKGEpfHx0aGlzLl9wYXVzZWR8fHRoaXMuX2lkbGV8fCh0aGlzLl9zdGFydFRpbWU9YSx0aGlzLl90aWNrQ3VycmVudFRpbWUoKHRoaXMuX3RpbWVsaW5lLmN1cnJlbnRUaW1lLXRoaXMuX3N0YXJ0VGltZSkqdGhpcy5wbGF5YmFja1JhdGUpLGIuaW52YWxpZGF0ZUVmZmVjdHMoKSl9LGdldCBwbGF5YmFja1JhdGUoKXtyZXR1cm4gdGhpcy5fcGxheWJhY2tSYXRlfSxzZXQgcGxheWJhY2tSYXRlKGEpe2lmKGEhPXRoaXMuX3BsYXliYWNrUmF0ZSl7dmFyIGI9dGhpcy5jdXJyZW50VGltZTt0aGlzLl9wbGF5YmFja1JhdGU9YSx0aGlzLl9zdGFydFRpbWU9bnVsbCwicGF1c2VkIiE9dGhpcy5wbGF5U3RhdGUmJiJpZGxlIiE9dGhpcy5wbGF5U3RhdGUmJnRoaXMucGxheSgpLG51bGwhPWImJih0aGlzLmN1cnJlbnRUaW1lPWIpfX0sZ2V0IF9pc0ZpbmlzaGVkKCl7cmV0dXJuIXRoaXMuX2lkbGUmJih0aGlzLl9wbGF5YmFja1JhdGU+MCYmdGhpcy5fY3VycmVudFRpbWU+PXRoaXMuX3RvdGFsRHVyYXRpb258fHRoaXMuX3BsYXliYWNrUmF0ZTwwJiZ0aGlzLl9jdXJyZW50VGltZTw9MCl9LGdldCBfdG90YWxEdXJhdGlvbigpe3JldHVybiB0aGlzLl9lZmZlY3QuX3RvdGFsRHVyYXRpb259LGdldCBwbGF5U3RhdGUoKXtyZXR1cm4gdGhpcy5faWRsZT8iaWRsZSI6bnVsbD09dGhpcy5fc3RhcnRUaW1lJiYhdGhpcy5fcGF1c2VkJiYwIT10aGlzLnBsYXliYWNrUmF0ZXx8dGhpcy5fY3VycmVudFRpbWVQZW5kaW5nPyJwZW5kaW5nIjp0aGlzLl9wYXVzZWQ/InBhdXNlZCI6dGhpcy5faXNGaW5pc2hlZD8iZmluaXNoZWQiOiJydW5uaW5nIn0scGxheTpmdW5jdGlvbigpe3RoaXMuX3BhdXNlZD0hMSwodGhpcy5faXNGaW5pc2hlZHx8dGhpcy5faWRsZSkmJih0aGlzLl9jdXJyZW50VGltZT10aGlzLl9wbGF5YmFja1JhdGU+MD8wOnRoaXMuX3RvdGFsRHVyYXRpb24sdGhpcy5fc3RhcnRUaW1lPW51bGwpLHRoaXMuX2ZpbmlzaGVkRmxhZz0hMSx0aGlzLl9pZGxlPSExLHRoaXMuX2Vuc3VyZUFsaXZlKCksYi5pbnZhbGlkYXRlRWZmZWN0cygpfSxwYXVzZTpmdW5jdGlvbigpe3RoaXMuX2lzRmluaXNoZWR8fHRoaXMuX3BhdXNlZHx8dGhpcy5faWRsZXx8KHRoaXMuX2N1cnJlbnRUaW1lUGVuZGluZz0hMCksdGhpcy5fc3RhcnRUaW1lPW51bGwsdGhpcy5fcGF1c2VkPSEwfSxmaW5pc2g6ZnVuY3Rpb24oKXt0aGlzLl9pZGxlfHwodGhpcy5jdXJyZW50VGltZT10aGlzLl9wbGF5YmFja1JhdGU+MD90aGlzLl90b3RhbER1cmF0aW9uOjAsdGhpcy5fc3RhcnRUaW1lPXRoaXMuX3RvdGFsRHVyYXRpb24tdGhpcy5jdXJyZW50VGltZSx0aGlzLl9jdXJyZW50VGltZVBlbmRpbmc9ITEsYi5pbnZhbGlkYXRlRWZmZWN0cygpKX0sY2FuY2VsOmZ1bmN0aW9uKCl7dGhpcy5faW5FZmZlY3QmJih0aGlzLl9pbkVmZmVjdD0hMSx0aGlzLl9pZGxlPSEwLHRoaXMuX2ZpbmlzaGVkRmxhZz0hMCx0aGlzLmN1cnJlbnRUaW1lPTAsdGhpcy5fc3RhcnRUaW1lPW51bGwsdGhpcy5fZWZmZWN0Ll91cGRhdGUobnVsbCksYi5pbnZhbGlkYXRlRWZmZWN0cygpKX0scmV2ZXJzZTpmdW5jdGlvbigpe3RoaXMucGxheWJhY2tSYXRlKj0tMSx0aGlzLnBsYXkoKX0sYWRkRXZlbnRMaXN0ZW5lcjpmdW5jdGlvbihhLGIpeyJmdW5jdGlvbiI9PXR5cGVvZiBiJiYiZmluaXNoIj09YSYmdGhpcy5fZmluaXNoSGFuZGxlcnMucHVzaChiKX0scmVtb3ZlRXZlbnRMaXN0ZW5lcjpmdW5jdGlvbihhLGIpe2lmKCJmaW5pc2giPT1hKXt2YXIgYz10aGlzLl9maW5pc2hIYW5kbGVycy5pbmRleE9mKGIpO2M+PTAmJnRoaXMuX2ZpbmlzaEhhbmRsZXJzLnNwbGljZShjLDEpfX0sX2ZpcmVFdmVudHM6ZnVuY3Rpb24oYSl7aWYodGhpcy5faXNGaW5pc2hlZCl7aWYoIXRoaXMuX2ZpbmlzaGVkRmxhZyl7dmFyIGI9bmV3IGQodGhpcyx0aGlzLl9jdXJyZW50VGltZSxhKSxjPXRoaXMuX2ZpbmlzaEhhbmRsZXJzLmNvbmNhdCh0aGlzLm9uZmluaXNoP1t0aGlzLm9uZmluaXNoXTpbXSk7c2V0VGltZW91dChmdW5jdGlvbigpe2MuZm9yRWFjaChmdW5jdGlvbihhKXthLmNhbGwoYi50YXJnZXQsYil9KX0sMCksdGhpcy5fZmluaXNoZWRGbGFnPSEwfX1lbHNlIHRoaXMuX2ZpbmlzaGVkRmxhZz0hMX0sX3RpY2s6ZnVuY3Rpb24oYSxiKXt0aGlzLl9pZGxlfHx0aGlzLl9wYXVzZWR8fChudWxsPT10aGlzLl9zdGFydFRpbWU/YiYmKHRoaXMuc3RhcnRUaW1lPWEtdGhpcy5fY3VycmVudFRpbWUvdGhpcy5wbGF5YmFja1JhdGUpOnRoaXMuX2lzRmluaXNoZWR8fHRoaXMuX3RpY2tDdXJyZW50VGltZSgoYS10aGlzLl9zdGFydFRpbWUpKnRoaXMucGxheWJhY2tSYXRlKSksYiYmKHRoaXMuX2N1cnJlbnRUaW1lUGVuZGluZz0hMSx0aGlzLl9maXJlRXZlbnRzKGEpKX0sZ2V0IF9uZWVkc1RpY2soKXtyZXR1cm4gdGhpcy5wbGF5U3RhdGUgaW57cGVuZGluZzoxLHJ1bm5pbmc6MX18fCF0aGlzLl9maW5pc2hlZEZsYWd9fX0oYyxkLGYpLGZ1bmN0aW9uKGEsYixjKXtmdW5jdGlvbiBkKGEpe3ZhciBiPWo7aj1bXSxhPHAuY3VycmVudFRpbWUmJihhPXAuY3VycmVudFRpbWUpLGgoYSwhMCksYi5mb3JFYWNoKGZ1bmN0aW9uKGIpe2JbMV0oYSl9KSxnKCksbD12b2lkIDB9ZnVuY3Rpb24gZShhLGIpe3JldHVybiBhLl9zZXF1ZW5jZU51bWJlci1iLl9zZXF1ZW5jZU51bWJlcn1mdW5jdGlvbiBmKCl7dGhpcy5fYW5pbWF0aW9ucz1bXSx0aGlzLmN1cnJlbnRUaW1lPXdpbmRvdy5wZXJmb3JtYW5jZSYmcGVyZm9ybWFuY2Uubm93P3BlcmZvcm1hbmNlLm5vdygpOjB9ZnVuY3Rpb24gZygpe28uZm9yRWFjaChmdW5jdGlvbihhKXthKCl9KSxvLmxlbmd0aD0wfWZ1bmN0aW9uIGgoYSxjKXtuPSExO3ZhciBkPWIudGltZWxpbmU7ZC5jdXJyZW50VGltZT1hLGQuX2FuaW1hdGlvbnMuc29ydChlKSxtPSExO3ZhciBmPWQuX2FuaW1hdGlvbnM7ZC5fYW5pbWF0aW9ucz1bXTt2YXIgZz1bXSxoPVtdO2Y9Zi5maWx0ZXIoZnVuY3Rpb24oYil7Yi5fdGljayhhLGMpLGIuX2luRWZmZWN0P2gucHVzaChiLl9lZmZlY3QpOmcucHVzaChiLl9lZmZlY3QpLGIuX25lZWRzVGljayYmKG09ITApO3ZhciBkPWIuX2luRWZmZWN0fHxiLl9uZWVkc1RpY2s7cmV0dXJuIGIuX2luVGltZWxpbmU9ZCxkfSksby5wdXNoLmFwcGx5KG8sZyksby5wdXNoLmFwcGx5KG8saCksZC5fYW5pbWF0aW9ucy5wdXNoLmFwcGx5KGQuX2FuaW1hdGlvbnMsZiksbSYmcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uKCl7fSl9dmFyIGk9d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSxqPVtdLGs9MDt3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lPWZ1bmN0aW9uKGEpe3ZhciBiPWsrKztyZXR1cm4gMD09ai5sZW5ndGgmJmkoZCksai5wdXNoKFtiLGFdKSxifSx3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWU9ZnVuY3Rpb24oYSl7ai5mb3JFYWNoKGZ1bmN0aW9uKGIpe2JbMF09PWEmJihiWzFdPWZ1bmN0aW9uKCl7fSl9KX0sZi5wcm90b3R5cGU9e19wbGF5OmZ1bmN0aW9uKGMpe2MuX3RpbWluZz1hLm5vcm1hbGl6ZVRpbWluZ0lucHV0KGMudGltaW5nKTt2YXIgZD1uZXcgYi5BbmltYXRpb24oYyk7cmV0dXJuIGQuX2lkbGU9ITEsZC5fdGltZWxpbmU9dGhpcyx0aGlzLl9hbmltYXRpb25zLnB1c2goZCksYi5yZXN0YXJ0KCksYi5pbnZhbGlkYXRlRWZmZWN0cygpLGR9fTt2YXIgbD12b2lkIDAsbT0hMSxuPSExO2IucmVzdGFydD1mdW5jdGlvbigpe3JldHVybiBtfHwobT0hMCxyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24oKXt9KSxuPSEwKSxufSxiLmludmFsaWRhdGVFZmZlY3RzPWZ1bmN0aW9uKCl7aChiLnRpbWVsaW5lLmN1cnJlbnRUaW1lLCExKSxnKCl9O3ZhciBvPVtdLHA9bmV3IGY7Yi50aW1lbGluZT1wfShjLGQsZiksZnVuY3Rpb24oYSl7ZnVuY3Rpb24gYihhLGIpe3ZhciBjPWEuZXhlYyhiKTtyZXR1cm4gYz8oYz1hLmlnbm9yZUNhc2U/Y1swXS50b0xvd2VyQ2FzZSgpOmNbMF0sW2MsYi5zdWJzdHIoYy5sZW5ndGgpXSk6dm9pZCAwfWZ1bmN0aW9uIGMoYSxiKXtiPWIucmVwbGFjZSgvXlxzKi8sIiIpO3ZhciBjPWEoYik7cmV0dXJuIGM/W2NbMF0sY1sxXS5yZXBsYWNlKC9eXHMqLywiIildOnZvaWQgMH1mdW5jdGlvbiBkKGEsZCxlKXthPWMuYmluZChudWxsLGEpO2Zvcih2YXIgZj1bXTs7KXt2YXIgZz1hKGUpO2lmKCFnKXJldHVybltmLGVdO2lmKGYucHVzaChnWzBdKSxlPWdbMV0sZz1iKGQsZSksIWd8fCIiPT1nWzFdKXJldHVybltmLGVdO2U9Z1sxXX19ZnVuY3Rpb24gZShhLGIpe2Zvcih2YXIgYz0wLGQ9MDtkPGIubGVuZ3RoJiYoIS9cc3wsLy50ZXN0KGJbZF0pfHwwIT1jKTtkKyspaWYoIigiPT1iW2RdKWMrKztlbHNlIGlmKCIpIj09YltkXSYmKGMtLSwwPT1jJiZkKyssMD49YykpYnJlYWs7dmFyIGU9YShiLnN1YnN0cigwLGQpKTtyZXR1cm4gdm9pZCAwPT1lP3ZvaWQgMDpbZSxiLnN1YnN0cihkKV19ZnVuY3Rpb24gZihhLGIpe2Zvcih2YXIgYz1hLGQ9YjtjJiZkOyljPmQ/YyU9ZDpkJT1jO3JldHVybiBjPWEqYi8oYytkKX1mdW5jdGlvbiBnKGEpe3JldHVybiBmdW5jdGlvbihiKXt2YXIgYz1hKGIpO3JldHVybiBjJiYoY1swXT12b2lkIDApLGN9fWZ1bmN0aW9uIGgoYSxiKXtyZXR1cm4gZnVuY3Rpb24oYyl7dmFyIGQ9YShjKTtyZXR1cm4gZD9kOltiLGNdfX1mdW5jdGlvbiBpKGIsYyl7Zm9yKHZhciBkPVtdLGU9MDtlPGIubGVuZ3RoO2UrKyl7dmFyIGY9YS5jb25zdW1lVHJpbW1lZChiW2VdLGMpO2lmKCFmfHwiIj09ZlswXSlyZXR1cm47dm9pZCAwIT09ZlswXSYmZC5wdXNoKGZbMF0pLGM9ZlsxXX1yZXR1cm4iIj09Yz9kOnZvaWQgMH1mdW5jdGlvbiBqKGEsYixjLGQsZSl7Zm9yKHZhciBnPVtdLGg9W10saT1bXSxqPWYoZC5sZW5ndGgsZS5sZW5ndGgpLGs9MDtqPms7aysrKXt2YXIgbD1iKGRbayVkLmxlbmd0aF0sZVtrJWUubGVuZ3RoXSk7aWYoIWwpcmV0dXJuO2cucHVzaChsWzBdKSxoLnB1c2gobFsxXSksaS5wdXNoKGxbMl0pfXJldHVybltnLGgsZnVuY3Rpb24oYil7dmFyIGQ9Yi5tYXAoZnVuY3Rpb24oYSxiKXtyZXR1cm4gaVtiXShhKX0pLmpvaW4oYyk7cmV0dXJuIGE/YShkKTpkfV19ZnVuY3Rpb24gayhhLGIsYyl7Zm9yKHZhciBkPVtdLGU9W10sZj1bXSxnPTAsaD0wO2g8Yy5sZW5ndGg7aCsrKWlmKCJmdW5jdGlvbiI9PXR5cGVvZiBjW2hdKXt2YXIgaT1jW2hdKGFbZ10sYltnKytdKTtkLnB1c2goaVswXSksZS5wdXNoKGlbMV0pLGYucHVzaChpWzJdKX1lbHNlIWZ1bmN0aW9uKGEpe2QucHVzaCghMSksZS5wdXNoKCExKSxmLnB1c2goZnVuY3Rpb24oKXtyZXR1cm4gY1thXX0pfShoKTtyZXR1cm5bZCxlLGZ1bmN0aW9uKGEpe2Zvcih2YXIgYj0iIixjPTA7YzxhLmxlbmd0aDtjKyspYis9ZltjXShhW2NdKTtyZXR1cm4gYn1dfWEuY29uc3VtZVRva2VuPWIsYS5jb25zdW1lVHJpbW1lZD1jLGEuY29uc3VtZVJlcGVhdGVkPWQsYS5jb25zdW1lUGFyZW50aGVzaXNlZD1lLGEuaWdub3JlPWcsYS5vcHRpb25hbD1oLGEuY29uc3VtZUxpc3Q9aSxhLm1lcmdlTmVzdGVkUmVwZWF0ZWQ9ai5iaW5kKG51bGwsbnVsbCksYS5tZXJnZVdyYXBwZWROZXN0ZWRSZXBlYXRlZD1qLGEubWVyZ2VMaXN0PWt9KGQpLGZ1bmN0aW9uKGEpe2Z1bmN0aW9uIGIoYil7ZnVuY3Rpb24gYyhiKXt2YXIgYz1hLmNvbnN1bWVUb2tlbigvXmluc2V0L2ksYik7aWYoYylyZXR1cm4gZC5pbnNldD0hMCxjO3ZhciBjPWEuY29uc3VtZUxlbmd0aE9yUGVyY2VudChiKTtpZihjKXJldHVybiBkLmxlbmd0aHMucHVzaChjWzBdKSxjO3ZhciBjPWEuY29uc3VtZUNvbG9yKGIpO3JldHVybiBjPyhkLmNvbG9yPWNbMF0sYyk6dm9pZCAwfXZhciBkPXtpbnNldDohMSxsZW5ndGhzOltdLGNvbG9yOm51bGx9LGU9YS5jb25zdW1lUmVwZWF0ZWQoYywvXi8sYik7cmV0dXJuIGUmJmVbMF0ubGVuZ3RoP1tkLGVbMV1dOnZvaWQgMH1mdW5jdGlvbiBjKGMpe3ZhciBkPWEuY29uc3VtZVJlcGVhdGVkKGIsL14sLyxjKTtyZXR1cm4gZCYmIiI9PWRbMV0/ZFswXTp2b2lkIDB9ZnVuY3Rpb24gZChiLGMpe2Zvcig7Yi5sZW5ndGhzLmxlbmd0aDxNYXRoLm1heChiLmxlbmd0aHMubGVuZ3RoLGMubGVuZ3Rocy5sZW5ndGgpOyliLmxlbmd0aHMucHVzaCh7cHg6MH0pO2Zvcig7Yy5sZW5ndGhzLmxlbmd0aDxNYXRoLm1heChiLmxlbmd0aHMubGVuZ3RoLGMubGVuZ3Rocy5sZW5ndGgpOyljLmxlbmd0aHMucHVzaCh7cHg6MH0pO2lmKGIuaW5zZXQ9PWMuaW5zZXQmJiEhYi5jb2xvcj09ISFjLmNvbG9yKXtmb3IodmFyIGQsZT1bXSxmPVtbXSwwXSxnPVtbXSwwXSxoPTA7aDxiLmxlbmd0aHMubGVuZ3RoO2grKyl7dmFyIGk9YS5tZXJnZURpbWVuc2lvbnMoYi5sZW5ndGhzW2hdLGMubGVuZ3Roc1toXSwyPT1oKTtmWzBdLnB1c2goaVswXSksZ1swXS5wdXNoKGlbMV0pLGUucHVzaChpWzJdKX1pZihiLmNvbG9yJiZjLmNvbG9yKXt2YXIgaj1hLm1lcmdlQ29sb3JzKGIuY29sb3IsYy5jb2xvcik7ZlsxXT1qWzBdLGdbMV09alsxXSxkPWpbMl19cmV0dXJuW2YsZyxmdW5jdGlvbihhKXtmb3IodmFyIGM9Yi5pbnNldD8iaW5zZXQgIjoiICIsZj0wO2Y8ZS5sZW5ndGg7ZisrKWMrPWVbZl0oYVswXVtmXSkrIiAiO3JldHVybiBkJiYoYys9ZChhWzFdKSksY31dfX1mdW5jdGlvbiBlKGIsYyxkLGUpe2Z1bmN0aW9uIGYoYSl7cmV0dXJue2luc2V0OmEsY29sb3I6WzAsMCwwLDBdLGxlbmd0aHM6W3tweDowfSx7cHg6MH0se3B4OjB9LHtweDowfV19fWZvcih2YXIgZz1bXSxoPVtdLGk9MDtpPGQubGVuZ3RofHxpPGUubGVuZ3RoO2krKyl7dmFyIGo9ZFtpXXx8ZihlW2ldLmluc2V0KSxrPWVbaV18fGYoZFtpXS5pbnNldCk7Zy5wdXNoKGopLGgucHVzaChrKX1yZXR1cm4gYS5tZXJnZU5lc3RlZFJlcGVhdGVkKGIsYyxnLGgpfXZhciBmPWUuYmluZChudWxsLGQsIiwgIik7YS5hZGRQcm9wZXJ0aWVzSGFuZGxlcihjLGYsWyJib3gtc2hhZG93IiwidGV4dC1zaGFkb3ciXSl9KGQpLGZ1bmN0aW9uKGEsYil7ZnVuY3Rpb24gYyhhKXtyZXR1cm4gYS50b0ZpeGVkKDMpLnJlcGxhY2UoIi4wMDAiLCIiKX1mdW5jdGlvbiBkKGEsYixjKXtyZXR1cm4gTWF0aC5taW4oYixNYXRoLm1heChhLGMpKX1mdW5jdGlvbiBlKGEpe3JldHVybi9eXHMqWy0rXT8oXGQqXC4pP1xkK1xzKiQvLnRlc3QoYSk/TnVtYmVyKGEpOnZvaWQgMH1mdW5jdGlvbiBmKGEsYil7cmV0dXJuW2EsYixjXX1mdW5jdGlvbiBnKGEsYil7cmV0dXJuIDAhPWE/aSgwLDEvMCkoYSxiKTp2b2lkIDB9ZnVuY3Rpb24gaChhLGIpe3JldHVyblthLGIsZnVuY3Rpb24oYSl7cmV0dXJuIE1hdGgucm91bmQoZCgxLDEvMCxhKSl9XX1mdW5jdGlvbiBpKGEsYil7cmV0dXJuIGZ1bmN0aW9uKGUsZil7cmV0dXJuW2UsZixmdW5jdGlvbihlKXtyZXR1cm4gYyhkKGEsYixlKSl9XX19ZnVuY3Rpb24gaihhLGIpe3JldHVyblthLGIsTWF0aC5yb3VuZF19YS5jbGFtcD1kLGEuYWRkUHJvcGVydGllc0hhbmRsZXIoZSxpKDAsMS8wKSxbImJvcmRlci1pbWFnZS13aWR0aCIsImxpbmUtaGVpZ2h0Il0pLGEuYWRkUHJvcGVydGllc0hhbmRsZXIoZSxpKDAsMSksWyJvcGFjaXR5Iiwic2hhcGUtaW1hZ2UtdGhyZXNob2xkIl0pLGEuYWRkUHJvcGVydGllc0hhbmRsZXIoZSxnLFsiZmxleC1ncm93IiwiZmxleC1zaHJpbmsiXSksYS5hZGRQcm9wZXJ0aWVzSGFuZGxlcihlLGgsWyJvcnBoYW5zIiwid2lkb3dzIl0pLGEuYWRkUHJvcGVydGllc0hhbmRsZXIoZSxqLFsiei1pbmRleCJdKSxhLnBhcnNlTnVtYmVyPWUsYS5tZXJnZU51bWJlcnM9ZixhLm51bWJlclRvU3RyaW5nPWN9KGQsZiksZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7cmV0dXJuInZpc2libGUiPT1hfHwidmlzaWJsZSI9PWI/WzAsMSxmdW5jdGlvbihjKXtyZXR1cm4gMD49Yz9hOmM+PTE/YjoidmlzaWJsZSJ9XTp2b2lkIDB9YS5hZGRQcm9wZXJ0aWVzSGFuZGxlcihTdHJpbmcsYyxbInZpc2liaWxpdHkiXSl9KGQpLGZ1bmN0aW9uKGEsYil7ZnVuY3Rpb24gYyhhKXthPWEudHJpbSgpLGYuZmlsbFN0eWxlPSIjMDAwIixmLmZpbGxTdHlsZT1hO3ZhciBiPWYuZmlsbFN0eWxlO2lmKGYuZmlsbFN0eWxlPSIjZmZmIixmLmZpbGxTdHlsZT1hLGI9PWYuZmlsbFN0eWxlKXtmLmZpbGxSZWN0KDAsMCwxLDEpO3ZhciBjPWYuZ2V0SW1hZ2VEYXRhKDAsMCwxLDEpLmRhdGE7Zi5jbGVhclJlY3QoMCwwLDEsMSk7dmFyIGQ9Y1szXS8yNTU7cmV0dXJuW2NbMF0qZCxjWzFdKmQsY1syXSpkLGRdfX1mdW5jdGlvbiBkKGIsYyl7cmV0dXJuW2IsYyxmdW5jdGlvbihiKXtmdW5jdGlvbiBjKGEpe3JldHVybiBNYXRoLm1heCgwLE1hdGgubWluKDI1NSxhKSl9aWYoYlszXSlmb3IodmFyIGQ9MDszPmQ7ZCsrKWJbZF09TWF0aC5yb3VuZChjKGJbZF0vYlszXSkpO3JldHVybiBiWzNdPWEubnVtYmVyVG9TdHJpbmcoYS5jbGFtcCgwLDEsYlszXSkpLCJyZ2JhKCIrYi5qb2luKCIsIikrIikifV19dmFyIGU9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKCJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiwiY2FudmFzIik7ZS53aWR0aD1lLmhlaWdodD0xO3ZhciBmPWUuZ2V0Q29udGV4dCgiMmQiKTthLmFkZFByb3BlcnRpZXNIYW5kbGVyKGMsZCxbImJhY2tncm91bmQtY29sb3IiLCJib3JkZXItYm90dG9tLWNvbG9yIiwiYm9yZGVyLWxlZnQtY29sb3IiLCJib3JkZXItcmlnaHQtY29sb3IiLCJib3JkZXItdG9wLWNvbG9yIiwiY29sb3IiLCJvdXRsaW5lLWNvbG9yIiwidGV4dC1kZWNvcmF0aW9uLWNvbG9yIl0pLGEuY29uc3VtZUNvbG9yPWEuY29uc3VtZVBhcmVudGhlc2lzZWQuYmluZChudWxsLGMpLGEubWVyZ2VDb2xvcnM9ZH0oZCxmKSxmdW5jdGlvbihhLGIpe2Z1bmN0aW9uIGMoYSxiKXtpZihiPWIudHJpbSgpLnRvTG93ZXJDYXNlKCksIjAiPT1iJiYicHgiLnNlYXJjaChhKT49MClyZXR1cm57cHg6MH07aWYoL15bXihdKiR8XmNhbGMvLnRlc3QoYikpe2I9Yi5yZXBsYWNlKC9jYWxjXCgvZywiKCIpO3ZhciBjPXt9O2I9Yi5yZXBsYWNlKGEsZnVuY3Rpb24oYSl7cmV0dXJuIGNbYV09bnVsbCwiVSIrYX0pO2Zvcih2YXIgZD0iVSgiK2Euc291cmNlKyIpIixlPWIucmVwbGFjZSgvWy0rXT8oXGQqXC4pP1xkKy9nLCJOIikucmVwbGFjZShuZXcgUmVnRXhwKCJOIitkLCJnIiksIkQiKS5yZXBsYWNlKC9cc1srLV1ccy9nLCJPIikucmVwbGFjZSgvXHMvZywiIiksZj1bL05cKihEKS9nLC8oTnxEKVsqXC9dTi9nLC8oTnxEKU9cMS9nLC9cKChOfEQpXCkvZ10sZz0wO2c8Zi5sZW5ndGg7KWZbZ10udGVzdChlKT8oZT1lLnJlcGxhY2UoZltnXSwiJDEiKSxnPTApOmcrKztpZigiRCI9PWUpe2Zvcih2YXIgaCBpbiBjKXt2YXIgaT1ldmFsKGIucmVwbGFjZShuZXcgUmVnRXhwKCJVIitoLCJnIiksIiIpLnJlcGxhY2UobmV3IFJlZ0V4cChkLCJnIiksIiowIikpO2lmKCFpc0Zpbml0ZShpKSlyZXR1cm47Y1toXT1pfXJldHVybiBjfX19ZnVuY3Rpb24gZChhLGIpe3JldHVybiBlKGEsYiwhMCl9ZnVuY3Rpb24gZShiLGMsZCl7dmFyIGUsZj1bXTtmb3IoZSBpbiBiKWYucHVzaChlKTtmb3IoZSBpbiBjKWYuaW5kZXhPZihlKTwwJiZmLnB1c2goZSk7cmV0dXJuIGI9Zi5tYXAoZnVuY3Rpb24oYSl7cmV0dXJuIGJbYV18fDB9KSxjPWYubWFwKGZ1bmN0aW9uKGEpe3JldHVybiBjW2FdfHwwfSksW2IsYyxmdW5jdGlvbihiKXt2YXIgYz1iLm1hcChmdW5jdGlvbihjLGUpe3JldHVybiAxPT1iLmxlbmd0aCYmZCYmKGM9TWF0aC5tYXgoYywwKSksYS5udW1iZXJUb1N0cmluZyhjKStmW2VdfSkuam9pbigiICsgIik7cmV0dXJuIGIubGVuZ3RoPjE/ImNhbGMoIitjKyIpIjpjfV19dmFyIGY9InB4fGVtfGV4fGNofHJlbXx2d3x2aHx2bWlufHZtYXh8Y218bW18aW58cHR8cGMiLGc9Yy5iaW5kKG51bGwsbmV3IFJlZ0V4cChmLCJnIikpLGg9Yy5iaW5kKG51bGwsbmV3IFJlZ0V4cChmKyJ8JSIsImciKSksaT1jLmJpbmQobnVsbCwvZGVnfHJhZHxncmFkfHR1cm4vZyk7YS5wYXJzZUxlbmd0aD1nLGEucGFyc2VMZW5ndGhPclBlcmNlbnQ9aCxhLmNvbnN1bWVMZW5ndGhPclBlcmNlbnQ9YS5jb25zdW1lUGFyZW50aGVzaXNlZC5iaW5kKG51bGwsaCksYS5wYXJzZUFuZ2xlPWksYS5tZXJnZURpbWVuc2lvbnM9ZTt2YXIgaj1hLmNvbnN1bWVQYXJlbnRoZXNpc2VkLmJpbmQobnVsbCxnKSxrPWEuY29uc3VtZVJlcGVhdGVkLmJpbmQodm9pZCAwLGosL14vKSxsPWEuY29uc3VtZVJlcGVhdGVkLmJpbmQodm9pZCAwLGssL14sLyk7YS5jb25zdW1lU2l6ZVBhaXJMaXN0PWw7dmFyIG09ZnVuY3Rpb24oYSl7dmFyIGI9bChhKTtyZXR1cm4gYiYmIiI9PWJbMV0/YlswXTp2b2lkIDB9LG49YS5tZXJnZU5lc3RlZFJlcGVhdGVkLmJpbmQodm9pZCAwLGQsIiAiKSxvPWEubWVyZ2VOZXN0ZWRSZXBlYXRlZC5iaW5kKHZvaWQgMCxuLCIsIik7YS5tZXJnZU5vbk5lZ2F0aXZlU2l6ZVBhaXI9bixhLmFkZFByb3BlcnRpZXNIYW5kbGVyKG0sbyxbImJhY2tncm91bmQtc2l6ZSJdKSxhLmFkZFByb3BlcnRpZXNIYW5kbGVyKGgsZCxbImJvcmRlci1ib3R0b20td2lkdGgiLCJib3JkZXItaW1hZ2Utd2lkdGgiLCJib3JkZXItbGVmdC13aWR0aCIsImJvcmRlci1yaWdodC13aWR0aCIsImJvcmRlci10b3Atd2lkdGgiLCJmbGV4LWJhc2lzIiwiZm9udC1zaXplIiwiaGVpZ2h0IiwibGluZS1oZWlnaHQiLCJtYXgtaGVpZ2h0IiwibWF4LXdpZHRoIiwib3V0bGluZS13aWR0aCIsIndpZHRoIl0pLGEuYWRkUHJvcGVydGllc0hhbmRsZXIoaCxlLFsiYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1cyIsImJvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzIiwiYm9yZGVyLXRvcC1sZWZ0LXJhZGl1cyIsImJvcmRlci10b3AtcmlnaHQtcmFkaXVzIiwiYm90dG9tIiwibGVmdCIsImxldHRlci1zcGFjaW5nIiwibWFyZ2luLWJvdHRvbSIsIm1hcmdpbi1sZWZ0IiwibWFyZ2luLXJpZ2h0IiwibWFyZ2luLXRvcCIsIm1pbi1oZWlnaHQiLCJtaW4td2lkdGgiLCJvdXRsaW5lLW9mZnNldCIsInBhZGRpbmctYm90dG9tIiwicGFkZGluZy1sZWZ0IiwicGFkZGluZy1yaWdodCIsInBhZGRpbmctdG9wIiwicGVyc3BlY3RpdmUiLCJyaWdodCIsInNoYXBlLW1hcmdpbiIsInRleHQtaW5kZW50IiwidG9wIiwidmVydGljYWwtYWxpZ24iLCJ3b3JkLXNwYWNpbmciXSl9KGQsZiksZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGIpe3JldHVybiBhLmNvbnN1bWVMZW5ndGhPclBlcmNlbnQoYil8fGEuY29uc3VtZVRva2VuKC9eYXV0by8sYil9ZnVuY3Rpb24gZChiKXt2YXIgZD1hLmNvbnN1bWVMaXN0KFthLmlnbm9yZShhLmNvbnN1bWVUb2tlbi5iaW5kKG51bGwsL15yZWN0LykpLGEuaWdub3JlKGEuY29uc3VtZVRva2VuLmJpbmQobnVsbCwvXlwoLykpLGEuY29uc3VtZVJlcGVhdGVkLmJpbmQobnVsbCxjLC9eLC8pLGEuaWdub3JlKGEuY29uc3VtZVRva2VuLmJpbmQobnVsbCwvXlwpLykpXSxiKTtyZXR1cm4gZCYmND09ZFswXS5sZW5ndGg/ZFswXTp2b2lkIDB9ZnVuY3Rpb24gZShiLGMpe3JldHVybiJhdXRvIj09Ynx8ImF1dG8iPT1jP1shMCwhMSxmdW5jdGlvbihkKXt2YXIgZT1kP2I6YztpZigiYXV0byI9PWUpcmV0dXJuImF1dG8iO3ZhciBmPWEubWVyZ2VEaW1lbnNpb25zKGUsZSk7cmV0dXJuIGZbMl0oZlswXSl9XTphLm1lcmdlRGltZW5zaW9ucyhiLGMpfWZ1bmN0aW9uIGYoYSl7cmV0dXJuInJlY3QoIithKyIpIn12YXIgZz1hLm1lcmdlV3JhcHBlZE5lc3RlZFJlcGVhdGVkLmJpbmQobnVsbCxmLGUsIiwgIik7YS5wYXJzZUJveD1kLGEubWVyZ2VCb3hlcz1nLGEuYWRkUHJvcGVydGllc0hhbmRsZXIoZCxnLFsiY2xpcCJdKX0oZCxmKSxmdW5jdGlvbihhLGIpe2Z1bmN0aW9uIGMoYSl7cmV0dXJuIGZ1bmN0aW9uKGIpe3ZhciBjPTA7cmV0dXJuIGEubWFwKGZ1bmN0aW9uKGEpe3JldHVybiBhPT09az9iW2MrK106YX0pfX1mdW5jdGlvbiBkKGEpe3JldHVybiBhfWZ1bmN0aW9uIGUoYil7aWYoYj1iLnRvTG93ZXJDYXNlKCkudHJpbSgpLCJub25lIj09YilyZXR1cm5bXTtmb3IodmFyIGMsZD0vXHMqKFx3KylcKChbXildKilcKS9nLGU9W10sZj0wO2M9ZC5leGVjKGIpOyl7aWYoYy5pbmRleCE9ZilyZXR1cm47Zj1jLmluZGV4K2NbMF0ubGVuZ3RoO3ZhciBnPWNbMV0saD1uW2ddO2lmKCFoKXJldHVybjt2YXIgaT1jWzJdLnNwbGl0KCIsIiksaj1oWzBdO2lmKGoubGVuZ3RoPGkubGVuZ3RoKXJldHVybjtmb3IodmFyIGs9W10sbz0wO288ai5sZW5ndGg7bysrKXt2YXIgcCxxPWlbb10scj1qW29dO2lmKHA9cT97QTpmdW5jdGlvbihiKXtyZXR1cm4iMCI9PWIudHJpbSgpP206YS5wYXJzZUFuZ2xlKGIpfSxOOmEucGFyc2VOdW1iZXIsVDphLnBhcnNlTGVuZ3RoT3JQZXJjZW50LEw6YS5wYXJzZUxlbmd0aH1bci50b1VwcGVyQ2FzZSgpXShxKTp7YTptLG46a1swXSx0Omx9W3JdLHZvaWQgMD09PXApcmV0dXJuO2sucHVzaChwKX1pZihlLnB1c2goe3Q6ZyxkOmt9KSxkLmxhc3RJbmRleD09Yi5sZW5ndGgpcmV0dXJuIGV9fWZ1bmN0aW9uIGYoYSl7cmV0dXJuIGEudG9GaXhlZCg2KS5yZXBsYWNlKCIuMDAwMDAwIiwiIil9ZnVuY3Rpb24gZyhiLGMpe2lmKGIuZGVjb21wb3NpdGlvblBhaXIhPT1jKXtiLmRlY29tcG9zaXRpb25QYWlyPWM7dmFyIGQ9YS5tYWtlTWF0cml4RGVjb21wb3NpdGlvbihiKX1pZihjLmRlY29tcG9zaXRpb25QYWlyIT09Yil7Yy5kZWNvbXBvc2l0aW9uUGFpcj1iO3ZhciBlPWEubWFrZU1hdHJpeERlY29tcG9zaXRpb24oYyl9cmV0dXJuIG51bGw9PWRbMF18fG51bGw9PWVbMF0/W1shMV0sWyEwXSxmdW5jdGlvbihhKXtyZXR1cm4gYT9jWzBdLmQ6YlswXS5kfV06KGRbMF0ucHVzaCgwKSxlWzBdLnB1c2goMSksW2QsZSxmdW5jdGlvbihiKXt2YXIgYz1hLnF1YXQoZFswXVszXSxlWzBdWzNdLGJbNV0pLGc9YS5jb21wb3NlTWF0cml4KGJbMF0sYlsxXSxiWzJdLGMsYls0XSksaD1nLm1hcChmKS5qb2luKCIsIik7cmV0dXJuIGh9XSl9ZnVuY3Rpb24gaChhKXtyZXR1cm4gYS5yZXBsYWNlKC9beHldLywiIil9ZnVuY3Rpb24gaShhKXtyZXR1cm4gYS5yZXBsYWNlKC8oeHx5fHp8M2QpPyQvLCIzZCIpfWZ1bmN0aW9uIGooYixjKXt2YXIgZD1hLm1ha2VNYXRyaXhEZWNvbXBvc2l0aW9uJiYhMCxlPSExO2lmKCFiLmxlbmd0aHx8IWMubGVuZ3RoKXtiLmxlbmd0aHx8KGU9ITAsYj1jLGM9W10pO2Zvcih2YXIgZj0wO2Y8Yi5sZW5ndGg7ZisrKXt2YXIgaj1iW2ZdLnQsaz1iW2ZdLmQsbD0ic2NhbGUiPT1qLnN1YnN0cigwLDUpPzE6MDtjLnB1c2goe3Q6aixkOmsubWFwKGZ1bmN0aW9uKGEpe2lmKCJudW1iZXIiPT10eXBlb2YgYSlyZXR1cm4gbDt2YXIgYj17fTtmb3IodmFyIGMgaW4gYSliW2NdPWw7cmV0dXJuIGJ9KX0pfX12YXIgbT1mdW5jdGlvbihhLGIpe3JldHVybiJwZXJzcGVjdGl2ZSI9PWEmJiJwZXJzcGVjdGl2ZSI9PWJ8fCgibWF0cml4Ij09YXx8Im1hdHJpeDNkIj09YSkmJigibWF0cml4Ij09Ynx8Im1hdHJpeDNkIj09Yil9LG89W10scD1bXSxxPVtdO2lmKGIubGVuZ3RoIT1jLmxlbmd0aCl7aWYoIWQpcmV0dXJuO3ZhciByPWcoYixjKTtvPVtyWzBdXSxwPVtyWzFdXSxxPVtbIm1hdHJpeCIsW3JbMl1dXV19ZWxzZSBmb3IodmFyIGY9MDtmPGIubGVuZ3RoO2YrKyl7dmFyIGoscz1iW2ZdLnQsdD1jW2ZdLnQsdT1iW2ZdLmQsdj1jW2ZdLmQsdz1uW3NdLHg9blt0XTtpZihtKHMsdCkpe2lmKCFkKXJldHVybjt2YXIgcj1nKFtiW2ZdXSxbY1tmXV0pO28ucHVzaChyWzBdKSxwLnB1c2goclsxXSkscS5wdXNoKFsibWF0cml4IixbclsyXV1dKX1lbHNle2lmKHM9PXQpaj1zO2Vsc2UgaWYod1syXSYmeFsyXSYmaChzKT09aCh0KSlqPWgocyksdT13WzJdKHUpLHY9eFsyXSh2KTtlbHNle2lmKCF3WzFdfHwheFsxXXx8aShzKSE9aSh0KSl7aWYoIWQpcmV0dXJuO3ZhciByPWcoYixjKTtvPVtyWzBdXSxwPVtyWzFdXSxxPVtbIm1hdHJpeCIsW3JbMl1dXV07YnJlYWt9aj1pKHMpLHU9d1sxXSh1KSx2PXhbMV0odil9Zm9yKHZhciB5PVtdLHo9W10sQT1bXSxCPTA7Qjx1Lmxlbmd0aDtCKyspe3ZhciBDPSJudW1iZXIiPT10eXBlb2YgdVtCXT9hLm1lcmdlTnVtYmVyczphLm1lcmdlRGltZW5zaW9ucyxyPUModVtCXSx2W0JdKTt5W0JdPXJbMF0seltCXT1yWzFdLEEucHVzaChyWzJdKX1vLnB1c2goeSkscC5wdXNoKHopLHEucHVzaChbaixBXSl9fWlmKGUpe3ZhciBEPW87bz1wLHA9RH1yZXR1cm5bbyxwLGZ1bmN0aW9uKGEpe3JldHVybiBhLm1hcChmdW5jdGlvbihhLGIpe3ZhciBjPWEubWFwKGZ1bmN0aW9uKGEsYyl7cmV0dXJuIHFbYl1bMV1bY10oYSl9KS5qb2luKCIsIik7cmV0dXJuIm1hdHJpeCI9PXFbYl1bMF0mJjE2PT1jLnNwbGl0KCIsIikubGVuZ3RoJiYocVtiXVswXT0ibWF0cml4M2QiKSxxW2JdWzBdKyIoIitjKyIpIn0pLmpvaW4oIiAiKX1dfXZhciBrPW51bGwsbD17cHg6MH0sbT17ZGVnOjB9LG49e21hdHJpeDpbIk5OTk5OTiIsW2ssaywwLDAsayxrLDAsMCwwLDAsMSwwLGssaywwLDFdLGRdLG1hdHJpeDNkOlsiTk5OTk5OTk5OTk5OTk5OTiIsZF0scm90YXRlOlsiQSJdLHJvdGF0ZXg6WyJBIl0scm90YXRleTpbIkEiXSxyb3RhdGV6OlsiQSJdLHJvdGF0ZTNkOlsiTk5OQSJdLHBlcnNwZWN0aXZlOlsiTCJdLHNjYWxlOlsiTm4iLGMoW2ssaywxXSksZF0sc2NhbGV4OlsiTiIsYyhbaywxLDFdKSxjKFtrLDFdKV0sc2NhbGV5OlsiTiIsYyhbMSxrLDFdKSxjKFsxLGtdKV0sc2NhbGV6OlsiTiIsYyhbMSwxLGtdKV0sc2NhbGUzZDpbIk5OTiIsZF0sc2tldzpbIkFhIixudWxsLGRdLHNrZXd4OlsiQSIsbnVsbCxjKFtrLG1dKV0sc2tld3k6WyJBIixudWxsLGMoW20sa10pXSx0cmFuc2xhdGU6WyJUdCIsYyhbayxrLGxdKSxkXSx0cmFuc2xhdGV4OlsiVCIsYyhbayxsLGxdKSxjKFtrLGxdKV0sdHJhbnNsYXRleTpbIlQiLGMoW2wsayxsXSksYyhbbCxrXSldLHRyYW5zbGF0ZXo6WyJMIixjKFtsLGwsa10pXSx0cmFuc2xhdGUzZDpbIlRUTCIsZF19O2EuYWRkUHJvcGVydGllc0hhbmRsZXIoZSxqLFsidHJhbnNmb3JtIl0pfShkLGYpLGZ1bmN0aW9uKGEsYil7ZnVuY3Rpb24gYyhhLGIpe2IuY29uY2F0KFthXSkuZm9yRWFjaChmdW5jdGlvbihiKXtiIGluIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZSYmKGRbYV09Yil9KX12YXIgZD17fTtjKCJ0cmFuc2Zvcm0iLFsid2Via2l0VHJhbnNmb3JtIiwibXNUcmFuc2Zvcm0iXSksYygidHJhbnNmb3JtT3JpZ2luIixbIndlYmtpdFRyYW5zZm9ybU9yaWdpbiJdKSxjKCJwZXJzcGVjdGl2ZSIsWyJ3ZWJraXRQZXJzcGVjdGl2ZSJdKSxjKCJwZXJzcGVjdGl2ZU9yaWdpbiIsWyJ3ZWJraXRQZXJzcGVjdGl2ZU9yaWdpbiJdKSxhLnByb3BlcnR5TmFtZT1mdW5jdGlvbihhKXtyZXR1cm4gZFthXXx8YX19KGQsZil9KCksIWZ1bmN0aW9uKCl7aWYodm9pZCAwPT09ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IikuYW5pbWF0ZShbXSkub25jYW5jZWwpe3ZhciBhO2lmKHdpbmRvdy5wZXJmb3JtYW5jZSYmcGVyZm9ybWFuY2Uubm93KXZhciBhPWZ1bmN0aW9uKCl7cmV0dXJuIHBlcmZvcm1hbmNlLm5vdygpfTtlbHNlIHZhciBhPWZ1bmN0aW9uKCl7cmV0dXJuIERhdGUubm93KCl9O3ZhciBiPWZ1bmN0aW9uKGEsYixjKXt0aGlzLnRhcmdldD1hLHRoaXMuY3VycmVudFRpbWU9Yix0aGlzLnRpbWVsaW5lVGltZT1jLHRoaXMudHlwZT0iY2FuY2VsIix0aGlzLmJ1YmJsZXM9ITEsdGhpcy5jYW5jZWxhYmxlPSExLHRoaXMuY3VycmVudFRhcmdldD1hLHRoaXMuZGVmYXVsdFByZXZlbnRlZD0hMSx0aGlzLmV2ZW50UGhhc2U9RXZlbnQuQVRfVEFSR0VULHRoaXMudGltZVN0YW1wPURhdGUubm93KCl9LGM9d2luZG93LkVsZW1lbnQucHJvdG90eXBlLmFuaW1hdGU7d2luZG93LkVsZW1lbnQucHJvdG90eXBlLmFuaW1hdGU9ZnVuY3Rpb24oZCxlKXt2YXIgZj1jLmNhbGwodGhpcyxkLGUpO2YuX2NhbmNlbEhhbmRsZXJzPVtdLGYub25jYW5jZWw9bnVsbDt2YXIgZz1mLmNhbmNlbDtmLmNhbmNlbD1mdW5jdGlvbigpe2cuY2FsbCh0aGlzKTt2YXIgYz1uZXcgYih0aGlzLG51bGwsYSgpKSxkPXRoaXMuX2NhbmNlbEhhbmRsZXJzLmNvbmNhdCh0aGlzLm9uY2FuY2VsP1t0aGlzLm9uY2FuY2VsXTpbXSk7c2V0VGltZW91dChmdW5jdGlvbigpe2QuZm9yRWFjaChmdW5jdGlvbihhKXthLmNhbGwoYy50YXJnZXQsYyl9KX0sMCl9O3ZhciBoPWYuYWRkRXZlbnRMaXN0ZW5lcjtmLmFkZEV2ZW50TGlzdGVuZXI9ZnVuY3Rpb24oYSxiKXsiZnVuY3Rpb24iPT10eXBlb2YgYiYmImNhbmNlbCI9PWE/dGhpcy5fY2FuY2VsSGFuZGxlcnMucHVzaChiKTpoLmNhbGwodGhpcyxhLGIpfTt2YXIgaT1mLnJlbW92ZUV2ZW50TGlzdGVuZXI7cmV0dXJuIGYucmVtb3ZlRXZlbnRMaXN0ZW5lcj1mdW5jdGlvbihhLGIpe2lmKCJjYW5jZWwiPT1hKXt2YXIgYz10aGlzLl9jYW5jZWxIYW5kbGVycy5pbmRleE9mKGIpO2M+PTAmJnRoaXMuX2NhbmNlbEhhbmRsZXJzLnNwbGljZShjLDEpfWVsc2UgaS5jYWxsKHRoaXMsYSxiKX0sZn19fSgpLGZ1bmN0aW9uKGEpe3ZhciBiPWRvY3VtZW50LmRvY3VtZW50RWxlbWVudCxjPW51bGwsZD0hMTt0cnl7dmFyIGU9Z2V0Q29tcHV0ZWRTdHlsZShiKS5nZXRQcm9wZXJ0eVZhbHVlKCJvcGFjaXR5IiksZj0iMCI9PWU/IjEiOiIwIjtjPWIuYW5pbWF0ZSh7b3BhY2l0eTpbZixmXX0se2R1cmF0aW9uOjF9KSxjLmN1cnJlbnRUaW1lPTAsZD1nZXRDb21wdXRlZFN0eWxlKGIpLmdldFByb3BlcnR5VmFsdWUoIm9wYWNpdHkiKT09Zn1jYXRjaChnKXt9ZmluYWxseXtjJiZjLmNhbmNlbCgpfWlmKCFkKXt2YXIgaD13aW5kb3cuRWxlbWVudC5wcm90b3R5cGUuYW5pbWF0ZTt3aW5kb3cuRWxlbWVudC5wcm90b3R5cGUuYW5pbWF0ZT1mdW5jdGlvbihiLGMpe3JldHVybiB3aW5kb3cuU3ltYm9sJiZTeW1ib2wuaXRlcmF0b3ImJkFycmF5LnByb3RvdHlwZS5mcm9tJiZiW1N5bWJvbC5pdGVyYXRvcl0mJihiPUFycmF5LmZyb20oYikpLEFycmF5LmlzQXJyYXkoYil8fG51bGw9PT1ifHwoYj1hLmNvbnZlcnRUb0FycmF5Rm9ybShiKSksaC5jYWxsKHRoaXMsYixjKX19fShjKSwhZnVuY3Rpb24oYSxiLGMpe2Z1bmN0aW9uIGQoYSl7dmFyIGI9d2luZG93LmRvY3VtZW50LnRpbWVsaW5lO2IuY3VycmVudFRpbWU9YSxiLl9kaXNjYXJkQW5pbWF0aW9ucygpLDA9PWIuX2FuaW1hdGlvbnMubGVuZ3RoP2Y9ITE6cmVxdWVzdEFuaW1hdGlvbkZyYW1lKGQpOwp9dmFyIGU9d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZTt3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lPWZ1bmN0aW9uKGEpe3JldHVybiBlKGZ1bmN0aW9uKGIpe3dpbmRvdy5kb2N1bWVudC50aW1lbGluZS5fdXBkYXRlQW5pbWF0aW9uc1Byb21pc2VzKCksYShiKSx3aW5kb3cuZG9jdW1lbnQudGltZWxpbmUuX3VwZGF0ZUFuaW1hdGlvbnNQcm9taXNlcygpfSl9LGIuQW5pbWF0aW9uVGltZWxpbmU9ZnVuY3Rpb24oKXt0aGlzLl9hbmltYXRpb25zPVtdLHRoaXMuY3VycmVudFRpbWU9dm9pZCAwfSxiLkFuaW1hdGlvblRpbWVsaW5lLnByb3RvdHlwZT17Z2V0QW5pbWF0aW9uczpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9kaXNjYXJkQW5pbWF0aW9ucygpLHRoaXMuX2FuaW1hdGlvbnMuc2xpY2UoKX0sX3VwZGF0ZUFuaW1hdGlvbnNQcm9taXNlczpmdW5jdGlvbigpe2IuYW5pbWF0aW9uc1dpdGhQcm9taXNlcz1iLmFuaW1hdGlvbnNXaXRoUHJvbWlzZXMuZmlsdGVyKGZ1bmN0aW9uKGEpe3JldHVybiBhLl91cGRhdGVQcm9taXNlcygpfSl9LF9kaXNjYXJkQW5pbWF0aW9uczpmdW5jdGlvbigpe3RoaXMuX3VwZGF0ZUFuaW1hdGlvbnNQcm9taXNlcygpLHRoaXMuX2FuaW1hdGlvbnM9dGhpcy5fYW5pbWF0aW9ucy5maWx0ZXIoZnVuY3Rpb24oYSl7cmV0dXJuImZpbmlzaGVkIiE9YS5wbGF5U3RhdGUmJiJpZGxlIiE9YS5wbGF5U3RhdGV9KX0sX3BsYXk6ZnVuY3Rpb24oYSl7dmFyIGM9bmV3IGIuQW5pbWF0aW9uKGEsdGhpcyk7cmV0dXJuIHRoaXMuX2FuaW1hdGlvbnMucHVzaChjKSxiLnJlc3RhcnRXZWJBbmltYXRpb25zTmV4dFRpY2soKSxjLl91cGRhdGVQcm9taXNlcygpLGMuX2FuaW1hdGlvbi5wbGF5KCksYy5fdXBkYXRlUHJvbWlzZXMoKSxjfSxwbGF5OmZ1bmN0aW9uKGEpe3JldHVybiBhJiZhLnJlbW92ZSgpLHRoaXMuX3BsYXkoYSl9fTt2YXIgZj0hMTtiLnJlc3RhcnRXZWJBbmltYXRpb25zTmV4dFRpY2s9ZnVuY3Rpb24oKXtmfHwoZj0hMCxyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZCkpfTt2YXIgZz1uZXcgYi5BbmltYXRpb25UaW1lbGluZTtiLnRpbWVsaW5lPWc7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuZG9jdW1lbnQsInRpbWVsaW5lIix7Y29uZmlndXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBnfX0pfWNhdGNoKGgpe310cnl7d2luZG93LmRvY3VtZW50LnRpbWVsaW5lPWd9Y2F0Y2goaCl7fX0oYyxlLGYpLGZ1bmN0aW9uKGEsYixjKXtiLmFuaW1hdGlvbnNXaXRoUHJvbWlzZXM9W10sYi5BbmltYXRpb249ZnVuY3Rpb24oYixjKXtpZih0aGlzLmlkPSIiLGImJmIuX2lkJiYodGhpcy5pZD1iLl9pZCksdGhpcy5lZmZlY3Q9YixiJiYoYi5fYW5pbWF0aW9uPXRoaXMpLCFjKXRocm93IG5ldyBFcnJvcigiQW5pbWF0aW9uIHdpdGggbnVsbCB0aW1lbGluZSBpcyBub3Qgc3VwcG9ydGVkIik7dGhpcy5fdGltZWxpbmU9Yyx0aGlzLl9zZXF1ZW5jZU51bWJlcj1hLnNlcXVlbmNlTnVtYmVyKyssdGhpcy5faG9sZFRpbWU9MCx0aGlzLl9wYXVzZWQ9ITEsdGhpcy5faXNHcm91cD0hMSx0aGlzLl9hbmltYXRpb249bnVsbCx0aGlzLl9jaGlsZEFuaW1hdGlvbnM9W10sdGhpcy5fY2FsbGJhY2s9bnVsbCx0aGlzLl9vbGRQbGF5U3RhdGU9ImlkbGUiLHRoaXMuX3JlYnVpbGRVbmRlcmx5aW5nQW5pbWF0aW9uKCksdGhpcy5fYW5pbWF0aW9uLmNhbmNlbCgpLHRoaXMuX3VwZGF0ZVByb21pc2VzKCl9LGIuQW5pbWF0aW9uLnByb3RvdHlwZT17X3VwZGF0ZVByb21pc2VzOmZ1bmN0aW9uKCl7dmFyIGE9dGhpcy5fb2xkUGxheVN0YXRlLGI9dGhpcy5wbGF5U3RhdGU7cmV0dXJuIHRoaXMuX3JlYWR5UHJvbWlzZSYmYiE9PWEmJigiaWRsZSI9PWI/KHRoaXMuX3JlamVjdFJlYWR5UHJvbWlzZSgpLHRoaXMuX3JlYWR5UHJvbWlzZT12b2lkIDApOiJwZW5kaW5nIj09YT90aGlzLl9yZXNvbHZlUmVhZHlQcm9taXNlKCk6InBlbmRpbmciPT1iJiYodGhpcy5fcmVhZHlQcm9taXNlPXZvaWQgMCkpLHRoaXMuX2ZpbmlzaGVkUHJvbWlzZSYmYiE9PWEmJigiaWRsZSI9PWI/KHRoaXMuX3JlamVjdEZpbmlzaGVkUHJvbWlzZSgpLHRoaXMuX2ZpbmlzaGVkUHJvbWlzZT12b2lkIDApOiJmaW5pc2hlZCI9PWI/dGhpcy5fcmVzb2x2ZUZpbmlzaGVkUHJvbWlzZSgpOiJmaW5pc2hlZCI9PWEmJih0aGlzLl9maW5pc2hlZFByb21pc2U9dm9pZCAwKSksdGhpcy5fb2xkUGxheVN0YXRlPXRoaXMucGxheVN0YXRlLHRoaXMuX3JlYWR5UHJvbWlzZXx8dGhpcy5fZmluaXNoZWRQcm9taXNlfSxfcmVidWlsZFVuZGVybHlpbmdBbmltYXRpb246ZnVuY3Rpb24oKXt0aGlzLl91cGRhdGVQcm9taXNlcygpO3ZhciBhLGMsZCxlLGY9ISF0aGlzLl9hbmltYXRpb247ZiYmKGE9dGhpcy5wbGF5YmFja1JhdGUsYz10aGlzLl9wYXVzZWQsZD10aGlzLnN0YXJ0VGltZSxlPXRoaXMuY3VycmVudFRpbWUsdGhpcy5fYW5pbWF0aW9uLmNhbmNlbCgpLHRoaXMuX2FuaW1hdGlvbi5fd3JhcHBlcj1udWxsLHRoaXMuX2FuaW1hdGlvbj1udWxsKSwoIXRoaXMuZWZmZWN0fHx0aGlzLmVmZmVjdCBpbnN0YW5jZW9mIHdpbmRvdy5LZXlmcmFtZUVmZmVjdCkmJih0aGlzLl9hbmltYXRpb249Yi5uZXdVbmRlcmx5aW5nQW5pbWF0aW9uRm9yS2V5ZnJhbWVFZmZlY3QodGhpcy5lZmZlY3QpLGIuYmluZEFuaW1hdGlvbkZvcktleWZyYW1lRWZmZWN0KHRoaXMpKSwodGhpcy5lZmZlY3QgaW5zdGFuY2VvZiB3aW5kb3cuU2VxdWVuY2VFZmZlY3R8fHRoaXMuZWZmZWN0IGluc3RhbmNlb2Ygd2luZG93Lkdyb3VwRWZmZWN0KSYmKHRoaXMuX2FuaW1hdGlvbj1iLm5ld1VuZGVybHlpbmdBbmltYXRpb25Gb3JHcm91cCh0aGlzLmVmZmVjdCksYi5iaW5kQW5pbWF0aW9uRm9yR3JvdXAodGhpcykpLHRoaXMuZWZmZWN0JiZ0aGlzLmVmZmVjdC5fb25zYW1wbGUmJmIuYmluZEFuaW1hdGlvbkZvckN1c3RvbUVmZmVjdCh0aGlzKSxmJiYoMSE9YSYmKHRoaXMucGxheWJhY2tSYXRlPWEpLG51bGwhPT1kP3RoaXMuc3RhcnRUaW1lPWQ6bnVsbCE9PWU/dGhpcy5jdXJyZW50VGltZT1lOm51bGwhPT10aGlzLl9ob2xkVGltZSYmKHRoaXMuY3VycmVudFRpbWU9dGhpcy5faG9sZFRpbWUpLGMmJnRoaXMucGF1c2UoKSksdGhpcy5fdXBkYXRlUHJvbWlzZXMoKX0sX3VwZGF0ZUNoaWxkcmVuOmZ1bmN0aW9uKCl7aWYodGhpcy5lZmZlY3QmJiJpZGxlIiE9dGhpcy5wbGF5U3RhdGUpe3ZhciBhPXRoaXMuZWZmZWN0Ll90aW1pbmcuZGVsYXk7dGhpcy5fY2hpbGRBbmltYXRpb25zLmZvckVhY2goZnVuY3Rpb24oYyl7dGhpcy5fYXJyYW5nZUNoaWxkcmVuKGMsYSksdGhpcy5lZmZlY3QgaW5zdGFuY2VvZiB3aW5kb3cuU2VxdWVuY2VFZmZlY3QmJihhKz1iLmdyb3VwQ2hpbGREdXJhdGlvbihjLmVmZmVjdCkpfS5iaW5kKHRoaXMpKX19LF9zZXRFeHRlcm5hbEFuaW1hdGlvbjpmdW5jdGlvbihhKXtpZih0aGlzLmVmZmVjdCYmdGhpcy5faXNHcm91cClmb3IodmFyIGI9MDtiPHRoaXMuZWZmZWN0LmNoaWxkcmVuLmxlbmd0aDtiKyspdGhpcy5lZmZlY3QuY2hpbGRyZW5bYl0uX2FuaW1hdGlvbj1hLHRoaXMuX2NoaWxkQW5pbWF0aW9uc1tiXS5fc2V0RXh0ZXJuYWxBbmltYXRpb24oYSl9LF9jb25zdHJ1Y3RDaGlsZEFuaW1hdGlvbnM6ZnVuY3Rpb24oKXtpZih0aGlzLmVmZmVjdCYmdGhpcy5faXNHcm91cCl7dmFyIGE9dGhpcy5lZmZlY3QuX3RpbWluZy5kZWxheTt0aGlzLl9yZW1vdmVDaGlsZEFuaW1hdGlvbnMoKSx0aGlzLmVmZmVjdC5jaGlsZHJlbi5mb3JFYWNoKGZ1bmN0aW9uKGMpe3ZhciBkPXdpbmRvdy5kb2N1bWVudC50aW1lbGluZS5fcGxheShjKTt0aGlzLl9jaGlsZEFuaW1hdGlvbnMucHVzaChkKSxkLnBsYXliYWNrUmF0ZT10aGlzLnBsYXliYWNrUmF0ZSx0aGlzLl9wYXVzZWQmJmQucGF1c2UoKSxjLl9hbmltYXRpb249dGhpcy5lZmZlY3QuX2FuaW1hdGlvbix0aGlzLl9hcnJhbmdlQ2hpbGRyZW4oZCxhKSx0aGlzLmVmZmVjdCBpbnN0YW5jZW9mIHdpbmRvdy5TZXF1ZW5jZUVmZmVjdCYmKGErPWIuZ3JvdXBDaGlsZER1cmF0aW9uKGMpKX0uYmluZCh0aGlzKSl9fSxfYXJyYW5nZUNoaWxkcmVuOmZ1bmN0aW9uKGEsYil7bnVsbD09PXRoaXMuc3RhcnRUaW1lP2EuY3VycmVudFRpbWU9dGhpcy5jdXJyZW50VGltZS1iL3RoaXMucGxheWJhY2tSYXRlOmEuc3RhcnRUaW1lIT09dGhpcy5zdGFydFRpbWUrYi90aGlzLnBsYXliYWNrUmF0ZSYmKGEuc3RhcnRUaW1lPXRoaXMuc3RhcnRUaW1lK2IvdGhpcy5wbGF5YmFja1JhdGUpfSxnZXQgdGltZWxpbmUoKXtyZXR1cm4gdGhpcy5fdGltZWxpbmV9LGdldCBwbGF5U3RhdGUoKXtyZXR1cm4gdGhpcy5fYW5pbWF0aW9uP3RoaXMuX2FuaW1hdGlvbi5wbGF5U3RhdGU6ImlkbGUifSxnZXQgZmluaXNoZWQoKXtyZXR1cm4gd2luZG93LlByb21pc2U/KHRoaXMuX2ZpbmlzaGVkUHJvbWlzZXx8KC0xPT1iLmFuaW1hdGlvbnNXaXRoUHJvbWlzZXMuaW5kZXhPZih0aGlzKSYmYi5hbmltYXRpb25zV2l0aFByb21pc2VzLnB1c2godGhpcyksdGhpcy5fZmluaXNoZWRQcm9taXNlPW5ldyBQcm9taXNlKGZ1bmN0aW9uKGEsYil7dGhpcy5fcmVzb2x2ZUZpbmlzaGVkUHJvbWlzZT1mdW5jdGlvbigpe2EodGhpcyl9LHRoaXMuX3JlamVjdEZpbmlzaGVkUHJvbWlzZT1mdW5jdGlvbigpe2Ioe3R5cGU6RE9NRXhjZXB0aW9uLkFCT1JUX0VSUixuYW1lOiJBYm9ydEVycm9yIn0pfX0uYmluZCh0aGlzKSksImZpbmlzaGVkIj09dGhpcy5wbGF5U3RhdGUmJnRoaXMuX3Jlc29sdmVGaW5pc2hlZFByb21pc2UoKSksdGhpcy5fZmluaXNoZWRQcm9taXNlKTooY29uc29sZS53YXJuKCJBbmltYXRpb24gUHJvbWlzZXMgcmVxdWlyZSBKYXZhU2NyaXB0IFByb21pc2UgY29uc3RydWN0b3IiKSxudWxsKX0sZ2V0IHJlYWR5KCl7cmV0dXJuIHdpbmRvdy5Qcm9taXNlPyh0aGlzLl9yZWFkeVByb21pc2V8fCgtMT09Yi5hbmltYXRpb25zV2l0aFByb21pc2VzLmluZGV4T2YodGhpcykmJmIuYW5pbWF0aW9uc1dpdGhQcm9taXNlcy5wdXNoKHRoaXMpLHRoaXMuX3JlYWR5UHJvbWlzZT1uZXcgUHJvbWlzZShmdW5jdGlvbihhLGIpe3RoaXMuX3Jlc29sdmVSZWFkeVByb21pc2U9ZnVuY3Rpb24oKXthKHRoaXMpfSx0aGlzLl9yZWplY3RSZWFkeVByb21pc2U9ZnVuY3Rpb24oKXtiKHt0eXBlOkRPTUV4Y2VwdGlvbi5BQk9SVF9FUlIsbmFtZToiQWJvcnRFcnJvciJ9KX19LmJpbmQodGhpcykpLCJwZW5kaW5nIiE9PXRoaXMucGxheVN0YXRlJiZ0aGlzLl9yZXNvbHZlUmVhZHlQcm9taXNlKCkpLHRoaXMuX3JlYWR5UHJvbWlzZSk6KGNvbnNvbGUud2FybigiQW5pbWF0aW9uIFByb21pc2VzIHJlcXVpcmUgSmF2YVNjcmlwdCBQcm9taXNlIGNvbnN0cnVjdG9yIiksbnVsbCl9LGdldCBvbmZpbmlzaCgpe3JldHVybiB0aGlzLl9hbmltYXRpb24ub25maW5pc2h9LHNldCBvbmZpbmlzaChhKXsiZnVuY3Rpb24iPT10eXBlb2YgYT90aGlzLl9hbmltYXRpb24ub25maW5pc2g9ZnVuY3Rpb24oYil7Yi50YXJnZXQ9dGhpcyxhLmNhbGwodGhpcyxiKX0uYmluZCh0aGlzKTp0aGlzLl9hbmltYXRpb24ub25maW5pc2g9YX0sZ2V0IG9uY2FuY2VsKCl7cmV0dXJuIHRoaXMuX2FuaW1hdGlvbi5vbmNhbmNlbH0sc2V0IG9uY2FuY2VsKGEpeyJmdW5jdGlvbiI9PXR5cGVvZiBhP3RoaXMuX2FuaW1hdGlvbi5vbmNhbmNlbD1mdW5jdGlvbihiKXtiLnRhcmdldD10aGlzLGEuY2FsbCh0aGlzLGIpfS5iaW5kKHRoaXMpOnRoaXMuX2FuaW1hdGlvbi5vbmNhbmNlbD1hfSxnZXQgY3VycmVudFRpbWUoKXt0aGlzLl91cGRhdGVQcm9taXNlcygpO3ZhciBhPXRoaXMuX2FuaW1hdGlvbi5jdXJyZW50VGltZTtyZXR1cm4gdGhpcy5fdXBkYXRlUHJvbWlzZXMoKSxhfSxzZXQgY3VycmVudFRpbWUoYSl7dGhpcy5fdXBkYXRlUHJvbWlzZXMoKSx0aGlzLl9hbmltYXRpb24uY3VycmVudFRpbWU9aXNGaW5pdGUoYSk/YTpNYXRoLnNpZ24oYSkqTnVtYmVyLk1BWF9WQUxVRSx0aGlzLl9yZWdpc3RlcigpLHRoaXMuX2ZvckVhY2hDaGlsZChmdW5jdGlvbihiLGMpe2IuY3VycmVudFRpbWU9YS1jfSksdGhpcy5fdXBkYXRlUHJvbWlzZXMoKX0sZ2V0IHN0YXJ0VGltZSgpe3JldHVybiB0aGlzLl9hbmltYXRpb24uc3RhcnRUaW1lfSxzZXQgc3RhcnRUaW1lKGEpe3RoaXMuX3VwZGF0ZVByb21pc2VzKCksdGhpcy5fYW5pbWF0aW9uLnN0YXJ0VGltZT1pc0Zpbml0ZShhKT9hOk1hdGguc2lnbihhKSpOdW1iZXIuTUFYX1ZBTFVFLHRoaXMuX3JlZ2lzdGVyKCksdGhpcy5fZm9yRWFjaENoaWxkKGZ1bmN0aW9uKGIsYyl7Yi5zdGFydFRpbWU9YStjfSksdGhpcy5fdXBkYXRlUHJvbWlzZXMoKX0sZ2V0IHBsYXliYWNrUmF0ZSgpe3JldHVybiB0aGlzLl9hbmltYXRpb24ucGxheWJhY2tSYXRlfSxzZXQgcGxheWJhY2tSYXRlKGEpe3RoaXMuX3VwZGF0ZVByb21pc2VzKCk7dmFyIGI9dGhpcy5jdXJyZW50VGltZTt0aGlzLl9hbmltYXRpb24ucGxheWJhY2tSYXRlPWEsdGhpcy5fZm9yRWFjaENoaWxkKGZ1bmN0aW9uKGIpe2IucGxheWJhY2tSYXRlPWF9KSwicGF1c2VkIiE9dGhpcy5wbGF5U3RhdGUmJiJpZGxlIiE9dGhpcy5wbGF5U3RhdGUmJnRoaXMucGxheSgpLG51bGwhPT1iJiYodGhpcy5jdXJyZW50VGltZT1iKSx0aGlzLl91cGRhdGVQcm9taXNlcygpfSxwbGF5OmZ1bmN0aW9uKCl7dGhpcy5fdXBkYXRlUHJvbWlzZXMoKSx0aGlzLl9wYXVzZWQ9ITEsdGhpcy5fYW5pbWF0aW9uLnBsYXkoKSwtMT09dGhpcy5fdGltZWxpbmUuX2FuaW1hdGlvbnMuaW5kZXhPZih0aGlzKSYmdGhpcy5fdGltZWxpbmUuX2FuaW1hdGlvbnMucHVzaCh0aGlzKSx0aGlzLl9yZWdpc3RlcigpLGIuYXdhaXRTdGFydFRpbWUodGhpcyksdGhpcy5fZm9yRWFjaENoaWxkKGZ1bmN0aW9uKGEpe3ZhciBiPWEuY3VycmVudFRpbWU7YS5wbGF5KCksYS5jdXJyZW50VGltZT1ifSksdGhpcy5fdXBkYXRlUHJvbWlzZXMoKX0scGF1c2U6ZnVuY3Rpb24oKXt0aGlzLl91cGRhdGVQcm9taXNlcygpLHRoaXMuY3VycmVudFRpbWUmJih0aGlzLl9ob2xkVGltZT10aGlzLmN1cnJlbnRUaW1lKSx0aGlzLl9hbmltYXRpb24ucGF1c2UoKSx0aGlzLl9yZWdpc3RlcigpLHRoaXMuX2ZvckVhY2hDaGlsZChmdW5jdGlvbihhKXthLnBhdXNlKCl9KSx0aGlzLl9wYXVzZWQ9ITAsdGhpcy5fdXBkYXRlUHJvbWlzZXMoKX0sZmluaXNoOmZ1bmN0aW9uKCl7dGhpcy5fdXBkYXRlUHJvbWlzZXMoKSx0aGlzLl9hbmltYXRpb24uZmluaXNoKCksdGhpcy5fcmVnaXN0ZXIoKSx0aGlzLl91cGRhdGVQcm9taXNlcygpfSxjYW5jZWw6ZnVuY3Rpb24oKXt0aGlzLl91cGRhdGVQcm9taXNlcygpLHRoaXMuX2FuaW1hdGlvbi5jYW5jZWwoKSx0aGlzLl9yZWdpc3RlcigpLHRoaXMuX3JlbW92ZUNoaWxkQW5pbWF0aW9ucygpLHRoaXMuX3VwZGF0ZVByb21pc2VzKCl9LHJldmVyc2U6ZnVuY3Rpb24oKXt0aGlzLl91cGRhdGVQcm9taXNlcygpO3ZhciBhPXRoaXMuY3VycmVudFRpbWU7dGhpcy5fYW5pbWF0aW9uLnJldmVyc2UoKSx0aGlzLl9mb3JFYWNoQ2hpbGQoZnVuY3Rpb24oYSl7YS5yZXZlcnNlKCl9KSxudWxsIT09YSYmKHRoaXMuY3VycmVudFRpbWU9YSksdGhpcy5fdXBkYXRlUHJvbWlzZXMoKX0sYWRkRXZlbnRMaXN0ZW5lcjpmdW5jdGlvbihhLGIpe3ZhciBjPWI7ImZ1bmN0aW9uIj09dHlwZW9mIGImJihjPWZ1bmN0aW9uKGEpe2EudGFyZ2V0PXRoaXMsYi5jYWxsKHRoaXMsYSl9LmJpbmQodGhpcyksYi5fd3JhcHBlcj1jKSx0aGlzLl9hbmltYXRpb24uYWRkRXZlbnRMaXN0ZW5lcihhLGMpfSxyZW1vdmVFdmVudExpc3RlbmVyOmZ1bmN0aW9uKGEsYil7dGhpcy5fYW5pbWF0aW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoYSxiJiZiLl93cmFwcGVyfHxiKX0sX3JlbW92ZUNoaWxkQW5pbWF0aW9uczpmdW5jdGlvbigpe2Zvcig7dGhpcy5fY2hpbGRBbmltYXRpb25zLmxlbmd0aDspdGhpcy5fY2hpbGRBbmltYXRpb25zLnBvcCgpLmNhbmNlbCgpfSxfZm9yRWFjaENoaWxkOmZ1bmN0aW9uKGIpe3ZhciBjPTA7aWYodGhpcy5lZmZlY3QuY2hpbGRyZW4mJnRoaXMuX2NoaWxkQW5pbWF0aW9ucy5sZW5ndGg8dGhpcy5lZmZlY3QuY2hpbGRyZW4ubGVuZ3RoJiZ0aGlzLl9jb25zdHJ1Y3RDaGlsZEFuaW1hdGlvbnMoKSx0aGlzLl9jaGlsZEFuaW1hdGlvbnMuZm9yRWFjaChmdW5jdGlvbihhKXtiLmNhbGwodGhpcyxhLGMpLHRoaXMuZWZmZWN0IGluc3RhbmNlb2Ygd2luZG93LlNlcXVlbmNlRWZmZWN0JiYoYys9YS5lZmZlY3QuYWN0aXZlRHVyYXRpb24pfS5iaW5kKHRoaXMpKSwicGVuZGluZyIhPXRoaXMucGxheVN0YXRlKXt2YXIgZD10aGlzLmVmZmVjdC5fdGltaW5nLGU9dGhpcy5jdXJyZW50VGltZTtudWxsIT09ZSYmKGU9YS5jYWxjdWxhdGVUaW1lRnJhY3Rpb24oYS5jYWxjdWxhdGVBY3RpdmVEdXJhdGlvbihkKSxlLGQpKSwobnVsbD09ZXx8aXNOYU4oZSkpJiZ0aGlzLl9yZW1vdmVDaGlsZEFuaW1hdGlvbnMoKX19fSx3aW5kb3cuQW5pbWF0aW9uPWIuQW5pbWF0aW9ufShjLGUsZiksZnVuY3Rpb24oYSxiLGMpe2Z1bmN0aW9uIGQoYil7dGhpcy5fZnJhbWVzPWEubm9ybWFsaXplS2V5ZnJhbWVzKGIpfWZ1bmN0aW9uIGUoKXtmb3IodmFyIGE9ITE7aS5sZW5ndGg7KXt2YXIgYj1pLnNoaWZ0KCk7Yi5fdXBkYXRlQ2hpbGRyZW4oKSxhPSEwfXJldHVybiBhfXZhciBmPWZ1bmN0aW9uKGEpe2lmKGEuX2FuaW1hdGlvbj12b2lkIDAsYSBpbnN0YW5jZW9mIHdpbmRvdy5TZXF1ZW5jZUVmZmVjdHx8YSBpbnN0YW5jZW9mIHdpbmRvdy5Hcm91cEVmZmVjdClmb3IodmFyIGI9MDtiPGEuY2hpbGRyZW4ubGVuZ3RoO2IrKylmKGEuY2hpbGRyZW5bYl0pfTtiLnJlbW92ZU11bHRpPWZ1bmN0aW9uKGEpe2Zvcih2YXIgYj1bXSxjPTA7YzxhLmxlbmd0aDtjKyspe3ZhciBkPWFbY107ZC5fcGFyZW50PygtMT09Yi5pbmRleE9mKGQuX3BhcmVudCkmJmIucHVzaChkLl9wYXJlbnQpLGQuX3BhcmVudC5jaGlsZHJlbi5zcGxpY2UoZC5fcGFyZW50LmNoaWxkcmVuLmluZGV4T2YoZCksMSksZC5fcGFyZW50PW51bGwsZihkKSk6ZC5fYW5pbWF0aW9uJiZkLl9hbmltYXRpb24uZWZmZWN0PT1kJiYoZC5fYW5pbWF0aW9uLmNhbmNlbCgpLGQuX2FuaW1hdGlvbi5lZmZlY3Q9bmV3IEtleWZyYW1lRWZmZWN0KG51bGwsW10pLGQuX2FuaW1hdGlvbi5fY2FsbGJhY2smJihkLl9hbmltYXRpb24uX2NhbGxiYWNrLl9hbmltYXRpb249bnVsbCksZC5fYW5pbWF0aW9uLl9yZWJ1aWxkVW5kZXJseWluZ0FuaW1hdGlvbigpLGYoZCkpfWZvcihjPTA7YzxiLmxlbmd0aDtjKyspYltjXS5fcmVidWlsZCgpfSxiLktleWZyYW1lRWZmZWN0PWZ1bmN0aW9uKGIsYyxlLGYpe3JldHVybiB0aGlzLnRhcmdldD1iLHRoaXMuX3BhcmVudD1udWxsLGU9YS5udW1lcmljVGltaW5nVG9PYmplY3QoZSksdGhpcy5fdGltaW5nSW5wdXQ9YS5jbG9uZVRpbWluZ0lucHV0KGUpLHRoaXMuX3RpbWluZz1hLm5vcm1hbGl6ZVRpbWluZ0lucHV0KGUpLHRoaXMudGltaW5nPWEubWFrZVRpbWluZyhlLCExLHRoaXMpLHRoaXMudGltaW5nLl9lZmZlY3Q9dGhpcywiZnVuY3Rpb24iPT10eXBlb2YgYz8oYS5kZXByZWNhdGVkKCJDdXN0b20gS2V5ZnJhbWVFZmZlY3QiLCIyMDE1LTA2LTIyIiwiVXNlIEtleWZyYW1lRWZmZWN0Lm9uc2FtcGxlIGluc3RlYWQuIiksdGhpcy5fbm9ybWFsaXplZEtleWZyYW1lcz1jKTp0aGlzLl9ub3JtYWxpemVkS2V5ZnJhbWVzPW5ldyBkKGMpLHRoaXMuX2tleWZyYW1lcz1jLHRoaXMuYWN0aXZlRHVyYXRpb249YS5jYWxjdWxhdGVBY3RpdmVEdXJhdGlvbih0aGlzLl90aW1pbmcpLHRoaXMuX2lkPWYsdGhpc30sYi5LZXlmcmFtZUVmZmVjdC5wcm90b3R5cGU9e2dldEZyYW1lczpmdW5jdGlvbigpe3JldHVybiJmdW5jdGlvbiI9PXR5cGVvZiB0aGlzLl9ub3JtYWxpemVkS2V5ZnJhbWVzP3RoaXMuX25vcm1hbGl6ZWRLZXlmcmFtZXM6dGhpcy5fbm9ybWFsaXplZEtleWZyYW1lcy5fZnJhbWVzfSxzZXQgb25zYW1wbGUoYSl7aWYoImZ1bmN0aW9uIj09dHlwZW9mIHRoaXMuZ2V0RnJhbWVzKCkpdGhyb3cgbmV3IEVycm9yKCJTZXR0aW5nIG9uc2FtcGxlIG9uIGN1c3RvbSBlZmZlY3QgS2V5ZnJhbWVFZmZlY3QgaXMgbm90IHN1cHBvcnRlZC4iKTt0aGlzLl9vbnNhbXBsZT1hLHRoaXMuX2FuaW1hdGlvbiYmdGhpcy5fYW5pbWF0aW9uLl9yZWJ1aWxkVW5kZXJseWluZ0FuaW1hdGlvbigpfSxnZXQgcGFyZW50KCl7cmV0dXJuIHRoaXMuX3BhcmVudH0sY2xvbmU6ZnVuY3Rpb24oKXtpZigiZnVuY3Rpb24iPT10eXBlb2YgdGhpcy5nZXRGcmFtZXMoKSl0aHJvdyBuZXcgRXJyb3IoIkNsb25pbmcgY3VzdG9tIGVmZmVjdHMgaXMgbm90IHN1cHBvcnRlZC4iKTt2YXIgYj1uZXcgS2V5ZnJhbWVFZmZlY3QodGhpcy50YXJnZXQsW10sYS5jbG9uZVRpbWluZ0lucHV0KHRoaXMuX3RpbWluZ0lucHV0KSx0aGlzLl9pZCk7cmV0dXJuIGIuX25vcm1hbGl6ZWRLZXlmcmFtZXM9dGhpcy5fbm9ybWFsaXplZEtleWZyYW1lcyxiLl9rZXlmcmFtZXM9dGhpcy5fa2V5ZnJhbWVzLGJ9LHJlbW92ZTpmdW5jdGlvbigpe2IucmVtb3ZlTXVsdGkoW3RoaXNdKX19O3ZhciBnPUVsZW1lbnQucHJvdG90eXBlLmFuaW1hdGU7RWxlbWVudC5wcm90b3R5cGUuYW5pbWF0ZT1mdW5jdGlvbihhLGMpe3ZhciBkPSIiO3JldHVybiBjJiZjLmlkJiYoZD1jLmlkKSxiLnRpbWVsaW5lLl9wbGF5KG5ldyBiLktleWZyYW1lRWZmZWN0KHRoaXMsYSxjLGQpKX07dmFyIGg9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKCJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiwiZGl2Iik7Yi5uZXdVbmRlcmx5aW5nQW5pbWF0aW9uRm9yS2V5ZnJhbWVFZmZlY3Q9ZnVuY3Rpb24oYSl7aWYoYSl7dmFyIGI9YS50YXJnZXR8fGgsYz1hLl9rZXlmcmFtZXM7ImZ1bmN0aW9uIj09dHlwZW9mIGMmJihjPVtdKTt2YXIgZD1hLl90aW1pbmdJbnB1dDtkLmlkPWEuX2lkfWVsc2UgdmFyIGI9aCxjPVtdLGQ9MDtyZXR1cm4gZy5hcHBseShiLFtjLGRdKX0sYi5iaW5kQW5pbWF0aW9uRm9yS2V5ZnJhbWVFZmZlY3Q9ZnVuY3Rpb24oYSl7YS5lZmZlY3QmJiJmdW5jdGlvbiI9PXR5cGVvZiBhLmVmZmVjdC5fbm9ybWFsaXplZEtleWZyYW1lcyYmYi5iaW5kQW5pbWF0aW9uRm9yQ3VzdG9tRWZmZWN0KGEpfTt2YXIgaT1bXTtiLmF3YWl0U3RhcnRUaW1lPWZ1bmN0aW9uKGEpe251bGw9PT1hLnN0YXJ0VGltZSYmYS5faXNHcm91cCYmKDA9PWkubGVuZ3RoJiZyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZSksaS5wdXNoKGEpKX07dmFyIGo9d2luZG93LmdldENvbXB1dGVkU3R5bGU7T2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdywiZ2V0Q29tcHV0ZWRTdHlsZSIse2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLHZhbHVlOmZ1bmN0aW9uKCl7d2luZG93LmRvY3VtZW50LnRpbWVsaW5lLl91cGRhdGVBbmltYXRpb25zUHJvbWlzZXMoKTt2YXIgYT1qLmFwcGx5KHRoaXMsYXJndW1lbnRzKTtyZXR1cm4gZSgpJiYoYT1qLmFwcGx5KHRoaXMsYXJndW1lbnRzKSksd2luZG93LmRvY3VtZW50LnRpbWVsaW5lLl91cGRhdGVBbmltYXRpb25zUHJvbWlzZXMoKSxhfX0pLHdpbmRvdy5LZXlmcmFtZUVmZmVjdD1iLktleWZyYW1lRWZmZWN0LHdpbmRvdy5FbGVtZW50LnByb3RvdHlwZS5nZXRBbmltYXRpb25zPWZ1bmN0aW9uKCl7cmV0dXJuIGRvY3VtZW50LnRpbWVsaW5lLmdldEFuaW1hdGlvbnMoKS5maWx0ZXIoZnVuY3Rpb24oYSl7cmV0dXJuIG51bGwhPT1hLmVmZmVjdCYmYS5lZmZlY3QudGFyZ2V0PT10aGlzfS5iaW5kKHRoaXMpKX19KGMsZSxmKSxmdW5jdGlvbihhLGIsYyl7ZnVuY3Rpb24gZChhKXthLl9yZWdpc3RlcmVkfHwoYS5fcmVnaXN0ZXJlZD0hMCxnLnB1c2goYSksaHx8KGg9ITAscmVxdWVzdEFuaW1hdGlvbkZyYW1lKGUpKSl9ZnVuY3Rpb24gZShhKXt2YXIgYj1nO2c9W10sYi5zb3J0KGZ1bmN0aW9uKGEsYil7cmV0dXJuIGEuX3NlcXVlbmNlTnVtYmVyLWIuX3NlcXVlbmNlTnVtYmVyfSksYj1iLmZpbHRlcihmdW5jdGlvbihhKXthKCk7dmFyIGI9YS5fYW5pbWF0aW9uP2EuX2FuaW1hdGlvbi5wbGF5U3RhdGU6ImlkbGUiO3JldHVybiJydW5uaW5nIiE9YiYmInBlbmRpbmciIT1iJiYoYS5fcmVnaXN0ZXJlZD0hMSksYS5fcmVnaXN0ZXJlZH0pLGcucHVzaC5hcHBseShnLGIpLGcubGVuZ3RoPyhoPSEwLHJlcXVlc3RBbmltYXRpb25GcmFtZShlKSk6aD0hMX12YXIgZj0oZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKCJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiwiZGl2IiksMCk7Yi5iaW5kQW5pbWF0aW9uRm9yQ3VzdG9tRWZmZWN0PWZ1bmN0aW9uKGIpe3ZhciBjLGU9Yi5lZmZlY3QudGFyZ2V0LGc9ImZ1bmN0aW9uIj09dHlwZW9mIGIuZWZmZWN0LmdldEZyYW1lcygpO2M9Zz9iLmVmZmVjdC5nZXRGcmFtZXMoKTpiLmVmZmVjdC5fb25zYW1wbGU7dmFyIGg9Yi5lZmZlY3QudGltaW5nLGk9bnVsbDtoPWEubm9ybWFsaXplVGltaW5nSW5wdXQoaCk7dmFyIGo9ZnVuY3Rpb24oKXt2YXIgZD1qLl9hbmltYXRpb24/ai5fYW5pbWF0aW9uLmN1cnJlbnRUaW1lOm51bGw7bnVsbCE9PWQmJihkPWEuY2FsY3VsYXRlVGltZUZyYWN0aW9uKGEuY2FsY3VsYXRlQWN0aXZlRHVyYXRpb24oaCksZCxoKSxpc05hTihkKSYmKGQ9bnVsbCkpLGQhPT1pJiYoZz9jKGQsZSxiLmVmZmVjdCk6YyhkLGIuZWZmZWN0LGIuZWZmZWN0Ll9hbmltYXRpb24pKSxpPWR9O2ouX2FuaW1hdGlvbj1iLGouX3JlZ2lzdGVyZWQ9ITEsai5fc2VxdWVuY2VOdW1iZXI9ZisrLGIuX2NhbGxiYWNrPWosZChqKX07dmFyIGc9W10saD0hMTtiLkFuaW1hdGlvbi5wcm90b3R5cGUuX3JlZ2lzdGVyPWZ1bmN0aW9uKCl7dGhpcy5fY2FsbGJhY2smJmQodGhpcy5fY2FsbGJhY2spfX0oYyxlLGYpLGZ1bmN0aW9uKGEsYixjKXtmdW5jdGlvbiBkKGEpe3JldHVybiBhLl90aW1pbmcuZGVsYXkrYS5hY3RpdmVEdXJhdGlvbithLl90aW1pbmcuZW5kRGVsYXl9ZnVuY3Rpb24gZShiLGMsZCl7dGhpcy5faWQ9ZCx0aGlzLl9wYXJlbnQ9bnVsbCx0aGlzLmNoaWxkcmVuPWJ8fFtdLHRoaXMuX3JlcGFyZW50KHRoaXMuY2hpbGRyZW4pLGM9YS5udW1lcmljVGltaW5nVG9PYmplY3QoYyksdGhpcy5fdGltaW5nSW5wdXQ9YS5jbG9uZVRpbWluZ0lucHV0KGMpLHRoaXMuX3RpbWluZz1hLm5vcm1hbGl6ZVRpbWluZ0lucHV0KGMsITApLHRoaXMudGltaW5nPWEubWFrZVRpbWluZyhjLCEwLHRoaXMpLHRoaXMudGltaW5nLl9lZmZlY3Q9dGhpcywiYXV0byI9PT10aGlzLl90aW1pbmcuZHVyYXRpb24mJih0aGlzLl90aW1pbmcuZHVyYXRpb249dGhpcy5hY3RpdmVEdXJhdGlvbil9d2luZG93LlNlcXVlbmNlRWZmZWN0PWZ1bmN0aW9uKCl7ZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl9LHdpbmRvdy5Hcm91cEVmZmVjdD1mdW5jdGlvbigpe2UuYXBwbHkodGhpcyxhcmd1bWVudHMpfSxlLnByb3RvdHlwZT17X2lzQW5jZXN0b3I6ZnVuY3Rpb24oYSl7Zm9yKHZhciBiPXRoaXM7bnVsbCE9PWI7KXtpZihiPT1hKXJldHVybiEwO2I9Yi5fcGFyZW50fXJldHVybiExfSxfcmVidWlsZDpmdW5jdGlvbigpe2Zvcih2YXIgYT10aGlzO2E7KSJhdXRvIj09PWEudGltaW5nLmR1cmF0aW9uJiYoYS5fdGltaW5nLmR1cmF0aW9uPWEuYWN0aXZlRHVyYXRpb24pLGE9YS5fcGFyZW50O3RoaXMuX2FuaW1hdGlvbiYmdGhpcy5fYW5pbWF0aW9uLl9yZWJ1aWxkVW5kZXJseWluZ0FuaW1hdGlvbigpfSxfcmVwYXJlbnQ6ZnVuY3Rpb24oYSl7Yi5yZW1vdmVNdWx0aShhKTtmb3IodmFyIGM9MDtjPGEubGVuZ3RoO2MrKylhW2NdLl9wYXJlbnQ9dGhpc30sX3B1dENoaWxkOmZ1bmN0aW9uKGEsYil7Zm9yKHZhciBjPWI/IkNhbm5vdCBhcHBlbmQgYW4gYW5jZXN0b3Igb3Igc2VsZiI6IkNhbm5vdCBwcmVwZW5kIGFuIGFuY2VzdG9yIG9yIHNlbGYiLGQ9MDtkPGEubGVuZ3RoO2QrKylpZih0aGlzLl9pc0FuY2VzdG9yKGFbZF0pKXRocm93e3R5cGU6RE9NRXhjZXB0aW9uLkhJRVJBUkNIWV9SRVFVRVNUX0VSUixuYW1lOiJIaWVyYXJjaHlSZXF1ZXN0RXJyb3IiLG1lc3NhZ2U6Y307Zm9yKHZhciBkPTA7ZDxhLmxlbmd0aDtkKyspYj90aGlzLmNoaWxkcmVuLnB1c2goYVtkXSk6dGhpcy5jaGlsZHJlbi51bnNoaWZ0KGFbZF0pO3RoaXMuX3JlcGFyZW50KGEpLHRoaXMuX3JlYnVpbGQoKX0sYXBwZW5kOmZ1bmN0aW9uKCl7dGhpcy5fcHV0Q2hpbGQoYXJndW1lbnRzLCEwKX0scHJlcGVuZDpmdW5jdGlvbigpe3RoaXMuX3B1dENoaWxkKGFyZ3VtZW50cywhMSl9LGdldCBwYXJlbnQoKXtyZXR1cm4gdGhpcy5fcGFyZW50fSxnZXQgZmlyc3RDaGlsZCgpe3JldHVybiB0aGlzLmNoaWxkcmVuLmxlbmd0aD90aGlzLmNoaWxkcmVuWzBdOm51bGx9LGdldCBsYXN0Q2hpbGQoKXtyZXR1cm4gdGhpcy5jaGlsZHJlbi5sZW5ndGg/dGhpcy5jaGlsZHJlblt0aGlzLmNoaWxkcmVuLmxlbmd0aC0xXTpudWxsfSxjbG9uZTpmdW5jdGlvbigpe2Zvcih2YXIgYj1hLmNsb25lVGltaW5nSW5wdXQodGhpcy5fdGltaW5nSW5wdXQpLGM9W10sZD0wO2Q8dGhpcy5jaGlsZHJlbi5sZW5ndGg7ZCsrKWMucHVzaCh0aGlzLmNoaWxkcmVuW2RdLmNsb25lKCkpO3JldHVybiB0aGlzIGluc3RhbmNlb2YgR3JvdXBFZmZlY3Q/bmV3IEdyb3VwRWZmZWN0KGMsYik6bmV3IFNlcXVlbmNlRWZmZWN0KGMsYil9LHJlbW92ZTpmdW5jdGlvbigpe2IucmVtb3ZlTXVsdGkoW3RoaXNdKX19LHdpbmRvdy5TZXF1ZW5jZUVmZmVjdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlLnByb3RvdHlwZSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5TZXF1ZW5jZUVmZmVjdC5wcm90b3R5cGUsImFjdGl2ZUR1cmF0aW9uIix7Z2V0OmZ1bmN0aW9uKCl7dmFyIGE9MDtyZXR1cm4gdGhpcy5jaGlsZHJlbi5mb3JFYWNoKGZ1bmN0aW9uKGIpe2ErPWQoYil9KSxNYXRoLm1heChhLDApfX0pLHdpbmRvdy5Hcm91cEVmZmVjdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlLnByb3RvdHlwZSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5Hcm91cEVmZmVjdC5wcm90b3R5cGUsImFjdGl2ZUR1cmF0aW9uIix7Z2V0OmZ1bmN0aW9uKCl7dmFyIGE9MDtyZXR1cm4gdGhpcy5jaGlsZHJlbi5mb3JFYWNoKGZ1bmN0aW9uKGIpe2E9TWF0aC5tYXgoYSxkKGIpKX0pLGF9fSksYi5uZXdVbmRlcmx5aW5nQW5pbWF0aW9uRm9yR3JvdXA9ZnVuY3Rpb24oYyl7dmFyIGQsZT1udWxsLGY9ZnVuY3Rpb24oYil7dmFyIGM9ZC5fd3JhcHBlcjtyZXR1cm4gYyYmInBlbmRpbmciIT1jLnBsYXlTdGF0ZSYmYy5lZmZlY3Q/bnVsbD09Yj92b2lkIGMuX3JlbW92ZUNoaWxkQW5pbWF0aW9ucygpOjA9PWImJmMucGxheWJhY2tSYXRlPDAmJihlfHwoZT1hLm5vcm1hbGl6ZVRpbWluZ0lucHV0KGMuZWZmZWN0LnRpbWluZykpLGI9YS5jYWxjdWxhdGVUaW1lRnJhY3Rpb24oYS5jYWxjdWxhdGVBY3RpdmVEdXJhdGlvbihlKSwtMSxlKSxpc05hTihiKXx8bnVsbD09Yik/KGMuX2ZvckVhY2hDaGlsZChmdW5jdGlvbihhKXthLmN1cnJlbnRUaW1lPS0xfSksdm9pZCBjLl9yZW1vdmVDaGlsZEFuaW1hdGlvbnMoKSk6dm9pZCAwOnZvaWQgMH0sZz1uZXcgS2V5ZnJhbWVFZmZlY3QobnVsbCxbXSxjLl90aW1pbmcsYy5faWQpO3JldHVybiBnLm9uc2FtcGxlPWYsZD1iLnRpbWVsaW5lLl9wbGF5KGcpfSxiLmJpbmRBbmltYXRpb25Gb3JHcm91cD1mdW5jdGlvbihhKXthLl9hbmltYXRpb24uX3dyYXBwZXI9YSxhLl9pc0dyb3VwPSEwLGIuYXdhaXRTdGFydFRpbWUoYSksYS5fY29uc3RydWN0Q2hpbGRBbmltYXRpb25zKCksYS5fc2V0RXh0ZXJuYWxBbmltYXRpb24oYSl9LGIuZ3JvdXBDaGlsZER1cmF0aW9uPWR9KGMsZSxmKSxiWyJ0cnVlIl09YX0oe30sZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30oKSk7Cjwvc2NyaXB0PjxzY3JpcHQ+LyoqCkBsaWNlbnNlIEBub2NvbXBpbGUKQ29weXJpZ2h0IChjKSAyMDE4IFRoZSBQb2x5bWVyIFByb2plY3QgQXV0aG9ycy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KVGhpcyBjb2RlIG1heSBvbmx5IGJlIHVzZWQgdW5kZXIgdGhlIEJTRCBzdHlsZSBsaWNlbnNlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9MSUNFTlNFLnR4dApUaGUgY29tcGxldGUgc2V0IG9mIGF1dGhvcnMgbWF5IGJlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9BVVRIT1JTLnR4dApUaGUgY29tcGxldGUgc2V0IG9mIGNvbnRyaWJ1dG9ycyBtYXkgYmUgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL0NPTlRSSUJVVE9SUy50eHQKQ29kZSBkaXN0cmlidXRlZCBieSBHb29nbGUgYXMgcGFydCBvZiB0aGUgcG9seW1lciBwcm9qZWN0IGlzIGFsc28Kc3ViamVjdCB0byBhbiBhZGRpdGlvbmFsIElQIHJpZ2h0cyBncmFudCBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vUEFURU5UUy50eHQKKi8KKGZ1bmN0aW9uKCl7LyoKCiBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFBvbHltZXIgUHJvamVjdCBBdXRob3JzLiBBbGwgcmlnaHRzIHJlc2VydmVkLgogVGhpcyBjb2RlIG1heSBvbmx5IGJlIHVzZWQgdW5kZXIgdGhlIEJTRCBzdHlsZSBsaWNlbnNlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9MSUNFTlNFLnR4dAogVGhlIGNvbXBsZXRlIHNldCBvZiBhdXRob3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQVVUSE9SUy50eHQKIFRoZSBjb21wbGV0ZSBzZXQgb2YgY29udHJpYnV0b3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQ09OVFJJQlVUT1JTLnR4dAogQ29kZSBkaXN0cmlidXRlZCBieSBHb29nbGUgYXMgcGFydCBvZiB0aGUgcG9seW1lciBwcm9qZWN0IGlzIGFsc28KIHN1YmplY3QgdG8gYW4gYWRkaXRpb25hbCBJUCByaWdodHMgZ3JhbnQgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL1BBVEVOVFMudHh0CiovCid1c2Ugc3RyaWN0Jzt2YXIgbixwPSJ1bmRlZmluZWQiIT10eXBlb2Ygd2luZG93JiZ3aW5kb3c9PT10aGlzP3RoaXM6InVuZGVmaW5lZCIhPXR5cGVvZiBnbG9iYWwmJm51bGwhPWdsb2JhbD9nbG9iYWw6dGhpcyxhYT0iZnVuY3Rpb24iPT10eXBlb2YgT2JqZWN0LmRlZmluZVByb3BlcnRpZXM/T2JqZWN0LmRlZmluZVByb3BlcnR5OmZ1bmN0aW9uKGEsYixjKXthIT1BcnJheS5wcm90b3R5cGUmJmEhPU9iamVjdC5wcm90b3R5cGUmJihhW2JdPWMudmFsdWUpfTtmdW5jdGlvbiBiYSgpe2JhPWZ1bmN0aW9uKCl7fTtwLlN5bWJvbHx8KHAuU3ltYm9sPWNhKX12YXIgY2E9ZnVuY3Rpb24oKXt2YXIgYT0wO3JldHVybiBmdW5jdGlvbihiKXtyZXR1cm4ianNjb21wX3N5bWJvbF8iKyhifHwiIikrYSsrfX0oKTsKZnVuY3Rpb24gZGEoKXtiYSgpO3ZhciBhPXAuU3ltYm9sLml0ZXJhdG9yO2F8fChhPXAuU3ltYm9sLml0ZXJhdG9yPXAuU3ltYm9sKCJpdGVyYXRvciIpKTsiZnVuY3Rpb24iIT10eXBlb2YgQXJyYXkucHJvdG90eXBlW2FdJiZhYShBcnJheS5wcm90b3R5cGUsYSx7Y29uZmlndXJhYmxlOiEwLHdyaXRhYmxlOiEwLHZhbHVlOmZ1bmN0aW9uKCl7cmV0dXJuIGVhKHRoaXMpfX0pO2RhPWZ1bmN0aW9uKCl7fX1mdW5jdGlvbiBlYShhKXt2YXIgYj0wO3JldHVybiBmYShmdW5jdGlvbigpe3JldHVybiBiPGEubGVuZ3RoP3tkb25lOiExLHZhbHVlOmFbYisrXX06e2RvbmU6ITB9fSl9ZnVuY3Rpb24gZmEoYSl7ZGEoKTthPXtuZXh0OmF9O2FbcC5TeW1ib2wuaXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9O3JldHVybiBhfWZ1bmN0aW9uIGlhKGEpe2RhKCk7dmFyIGI9YVtTeW1ib2wuaXRlcmF0b3JdO3JldHVybiBiP2IuY2FsbChhKTplYShhKX0KZnVuY3Rpb24gamEoYSl7Zm9yKHZhciBiLGM9W107IShiPWEubmV4dCgpKS5kb25lOyljLnB1c2goYi52YWx1ZSk7cmV0dXJuIGN9CihmdW5jdGlvbigpe2lmKCFmdW5jdGlvbigpe3ZhciBhPWRvY3VtZW50LmNyZWF0ZUV2ZW50KCJFdmVudCIpO2EuaW5pdEV2ZW50KCJmb28iLCEwLCEwKTthLnByZXZlbnREZWZhdWx0KCk7cmV0dXJuIGEuZGVmYXVsdFByZXZlbnRlZH0oKSl7dmFyIGE9RXZlbnQucHJvdG90eXBlLnByZXZlbnREZWZhdWx0O0V2ZW50LnByb3RvdHlwZS5wcmV2ZW50RGVmYXVsdD1mdW5jdGlvbigpe3RoaXMuY2FuY2VsYWJsZSYmKGEuY2FsbCh0aGlzKSxPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywiZGVmYXVsdFByZXZlbnRlZCIse2dldDpmdW5jdGlvbigpe3JldHVybiEwfSxjb25maWd1cmFibGU6ITB9KSl9fXZhciBiPS9UcmlkZW50Ly50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO2lmKCF3aW5kb3cuQ3VzdG9tRXZlbnR8fGImJiJmdW5jdGlvbiIhPT10eXBlb2Ygd2luZG93LkN1c3RvbUV2ZW50KXdpbmRvdy5DdXN0b21FdmVudD1mdW5jdGlvbihhLGIpe2I9Ynx8e307dmFyIGM9ZG9jdW1lbnQuY3JlYXRlRXZlbnQoIkN1c3RvbUV2ZW50Iik7CmMuaW5pdEN1c3RvbUV2ZW50KGEsISFiLmJ1YmJsZXMsISFiLmNhbmNlbGFibGUsYi5kZXRhaWwpO3JldHVybiBjfSx3aW5kb3cuQ3VzdG9tRXZlbnQucHJvdG90eXBlPXdpbmRvdy5FdmVudC5wcm90b3R5cGU7aWYoIXdpbmRvdy5FdmVudHx8YiYmImZ1bmN0aW9uIiE9PXR5cGVvZiB3aW5kb3cuRXZlbnQpe3ZhciBjPXdpbmRvdy5FdmVudDt3aW5kb3cuRXZlbnQ9ZnVuY3Rpb24oYSxiKXtiPWJ8fHt9O3ZhciBjPWRvY3VtZW50LmNyZWF0ZUV2ZW50KCJFdmVudCIpO2MuaW5pdEV2ZW50KGEsISFiLmJ1YmJsZXMsISFiLmNhbmNlbGFibGUpO3JldHVybiBjfTtpZihjKWZvcih2YXIgZCBpbiBjKXdpbmRvdy5FdmVudFtkXT1jW2RdO3dpbmRvdy5FdmVudC5wcm90b3R5cGU9Yy5wcm90b3R5cGV9aWYoIXdpbmRvdy5Nb3VzZUV2ZW50fHxiJiYiZnVuY3Rpb24iIT09dHlwZW9mIHdpbmRvdy5Nb3VzZUV2ZW50KXtiPXdpbmRvdy5Nb3VzZUV2ZW50O3dpbmRvdy5Nb3VzZUV2ZW50PWZ1bmN0aW9uKGEsCmIpe2I9Ynx8e307dmFyIGM9ZG9jdW1lbnQuY3JlYXRlRXZlbnQoIk1vdXNlRXZlbnQiKTtjLmluaXRNb3VzZUV2ZW50KGEsISFiLmJ1YmJsZXMsISFiLmNhbmNlbGFibGUsYi52aWV3fHx3aW5kb3csYi5kZXRhaWwsYi5zY3JlZW5YLGIuc2NyZWVuWSxiLmNsaWVudFgsYi5jbGllbnRZLGIuY3RybEtleSxiLmFsdEtleSxiLnNoaWZ0S2V5LGIubWV0YUtleSxiLmJ1dHRvbixiLnJlbGF0ZWRUYXJnZXQpO3JldHVybiBjfTtpZihiKWZvcihkIGluIGIpd2luZG93Lk1vdXNlRXZlbnRbZF09YltkXTt3aW5kb3cuTW91c2VFdmVudC5wcm90b3R5cGU9Yi5wcm90b3R5cGV9QXJyYXkuZnJvbXx8KEFycmF5LmZyb209ZnVuY3Rpb24oYSl7cmV0dXJuW10uc2xpY2UuY2FsbChhKX0pO09iamVjdC5hc3NpZ258fChPYmplY3QuYXNzaWduPWZ1bmN0aW9uKGEsYil7Zm9yKHZhciBjPVtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLDEpLGQ9MCxlO2Q8Yy5sZW5ndGg7ZCsrKWlmKGU9Y1tkXSlmb3IodmFyIGY9CmEsbT1lLHE9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMobSkseD0wO3g8cS5sZW5ndGg7eCsrKWU9cVt4XSxmW2VdPW1bZV07cmV0dXJuIGF9KX0pKHdpbmRvdy5XZWJDb21wb25lbnRzKTsoZnVuY3Rpb24oKXtmdW5jdGlvbiBhKCl7fWZ1bmN0aW9uIGIoYSxiKXtpZighYS5jaGlsZE5vZGVzLmxlbmd0aClyZXR1cm5bXTtzd2l0Y2goYS5ub2RlVHlwZSl7Y2FzZSBOb2RlLkRPQ1VNRU5UX05PREU6cmV0dXJuIHVhLmNhbGwoYSxiKTtjYXNlIE5vZGUuRE9DVU1FTlRfRlJBR01FTlRfTk9ERTpyZXR1cm4gbGIuY2FsbChhLGIpO2RlZmF1bHQ6cmV0dXJuIFUuY2FsbChhLGIpfX12YXIgYz0idW5kZWZpbmVkIj09PXR5cGVvZiBIVE1MVGVtcGxhdGVFbGVtZW50LGQ9IShkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCkuY2xvbmVOb2RlKClpbnN0YW5jZW9mIERvY3VtZW50RnJhZ21lbnQpLGU9ITE7L1RyaWRlbnQvLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCkmJmZ1bmN0aW9uKCl7ZnVuY3Rpb24gYShhLGIpe2lmKGEgaW5zdGFuY2VvZiBEb2N1bWVudEZyYWdtZW50KWZvcih2YXIgZDtkPWEuZmlyc3RDaGlsZDspYy5jYWxsKHRoaXMsZCxiKTtlbHNlIGMuY2FsbCh0aGlzLAphLGIpO3JldHVybiBhfWU9ITA7dmFyIGI9Tm9kZS5wcm90b3R5cGUuY2xvbmVOb2RlO05vZGUucHJvdG90eXBlLmNsb25lTm9kZT1mdW5jdGlvbihhKXthPWIuY2FsbCh0aGlzLGEpO3RoaXMgaW5zdGFuY2VvZiBEb2N1bWVudEZyYWdtZW50JiYoYS5fX3Byb3RvX189RG9jdW1lbnRGcmFnbWVudC5wcm90b3R5cGUpO3JldHVybiBhfTtEb2N1bWVudEZyYWdtZW50LnByb3RvdHlwZS5xdWVyeVNlbGVjdG9yQWxsPUhUTUxFbGVtZW50LnByb3RvdHlwZS5xdWVyeVNlbGVjdG9yQWxsO0RvY3VtZW50RnJhZ21lbnQucHJvdG90eXBlLnF1ZXJ5U2VsZWN0b3I9SFRNTEVsZW1lbnQucHJvdG90eXBlLnF1ZXJ5U2VsZWN0b3I7T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoRG9jdW1lbnRGcmFnbWVudC5wcm90b3R5cGUse25vZGVUeXBlOntnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gTm9kZS5ET0NVTUVOVF9GUkFHTUVOVF9OT0RFfSxjb25maWd1cmFibGU6ITB9LGxvY2FsTmFtZTp7Z2V0OmZ1bmN0aW9uKCl7fSwKY29uZmlndXJhYmxlOiEwfSxub2RlTmFtZTp7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIiNkb2N1bWVudC1mcmFnbWVudCJ9LGNvbmZpZ3VyYWJsZTohMH19KTt2YXIgYz1Ob2RlLnByb3RvdHlwZS5pbnNlcnRCZWZvcmU7Tm9kZS5wcm90b3R5cGUuaW5zZXJ0QmVmb3JlPWE7dmFyIGQ9Tm9kZS5wcm90b3R5cGUuYXBwZW5kQ2hpbGQ7Tm9kZS5wcm90b3R5cGUuYXBwZW5kQ2hpbGQ9ZnVuY3Rpb24oYil7YiBpbnN0YW5jZW9mIERvY3VtZW50RnJhZ21lbnQ/YS5jYWxsKHRoaXMsYixudWxsKTpkLmNhbGwodGhpcyxiKTtyZXR1cm4gYn07dmFyIGY9Tm9kZS5wcm90b3R5cGUucmVtb3ZlQ2hpbGQsZz1Ob2RlLnByb3RvdHlwZS5yZXBsYWNlQ2hpbGQ7Tm9kZS5wcm90b3R5cGUucmVwbGFjZUNoaWxkPWZ1bmN0aW9uKGIsYyl7YiBpbnN0YW5jZW9mIERvY3VtZW50RnJhZ21lbnQ/KGEuY2FsbCh0aGlzLGIsYyksZi5jYWxsKHRoaXMsYykpOmcuY2FsbCh0aGlzLGIsYyk7cmV0dXJuIGN9O0RvY3VtZW50LnByb3RvdHlwZS5jcmVhdGVEb2N1bWVudEZyYWdtZW50PQpmdW5jdGlvbigpe3ZhciBhPXRoaXMuY3JlYXRlRWxlbWVudCgiZGYiKTthLl9fcHJvdG9fXz1Eb2N1bWVudEZyYWdtZW50LnByb3RvdHlwZTtyZXR1cm4gYX07dmFyIGg9RG9jdW1lbnQucHJvdG90eXBlLmltcG9ydE5vZGU7RG9jdW1lbnQucHJvdG90eXBlLmltcG9ydE5vZGU9ZnVuY3Rpb24oYSxiKXtiPWguY2FsbCh0aGlzLGEsYnx8ITEpO2EgaW5zdGFuY2VvZiBEb2N1bWVudEZyYWdtZW50JiYoYi5fX3Byb3RvX189RG9jdW1lbnRGcmFnbWVudC5wcm90b3R5cGUpO3JldHVybiBifX0oKTt2YXIgZj1Ob2RlLnByb3RvdHlwZS5jbG9uZU5vZGUsZz1Eb2N1bWVudC5wcm90b3R5cGUuY3JlYXRlRWxlbWVudCxoPURvY3VtZW50LnByb3RvdHlwZS5pbXBvcnROb2RlLGs9Tm9kZS5wcm90b3R5cGUucmVtb3ZlQ2hpbGQsbD1Ob2RlLnByb3RvdHlwZS5hcHBlbmRDaGlsZCxtPU5vZGUucHJvdG90eXBlLnJlcGxhY2VDaGlsZCxxPURPTVBhcnNlci5wcm90b3R5cGUucGFyc2VGcm9tU3RyaW5nLAp4PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3Iod2luZG93LkhUTUxFbGVtZW50LnByb3RvdHlwZSwiaW5uZXJIVE1MIil8fHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5pbm5lckhUTUx9LHNldDpmdW5jdGlvbihhKXt0aGlzLmlubmVySFRNTD1hfX0sTT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHdpbmRvdy5Ob2RlLnByb3RvdHlwZSwiY2hpbGROb2RlcyIpfHx7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuY2hpbGROb2Rlc319LFU9RWxlbWVudC5wcm90b3R5cGUucXVlcnlTZWxlY3RvckFsbCx1YT1Eb2N1bWVudC5wcm90b3R5cGUucXVlcnlTZWxlY3RvckFsbCxsYj1Eb2N1bWVudEZyYWdtZW50LnByb3RvdHlwZS5xdWVyeVNlbGVjdG9yQWxsLG1iPWZ1bmN0aW9uKCl7aWYoIWMpe3ZhciBhPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInRlbXBsYXRlIiksYj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJ0ZW1wbGF0ZSIpO2IuY29udGVudC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKSk7CmEuY29udGVudC5hcHBlbmRDaGlsZChiKTthPWEuY2xvbmVOb2RlKCEwKTtyZXR1cm4gMD09PWEuY29udGVudC5jaGlsZE5vZGVzLmxlbmd0aHx8MD09PWEuY29udGVudC5maXJzdENoaWxkLmNvbnRlbnQuY2hpbGROb2Rlcy5sZW5ndGh8fGR9fSgpO2lmKGMpe3ZhciBTPWRvY3VtZW50LmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgidGVtcGxhdGUiKSxDPSEwLFY9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3R5bGUiKTtWLnRleHRDb250ZW50PSJ0ZW1wbGF0ZXtkaXNwbGF5Om5vbmU7fSI7dmFyIGhhPWRvY3VtZW50LmhlYWQ7aGEuaW5zZXJ0QmVmb3JlKFYsaGEuZmlyc3RFbGVtZW50Q2hpbGQpO2EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoSFRNTEVsZW1lbnQucHJvdG90eXBlKTt2YXIgdmE9IWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpLmhhc093blByb3BlcnR5KCJpbm5lckhUTUwiKTthLkc9ZnVuY3Rpb24oYil7aWYoIWIuY29udGVudCYmYi5uYW1lc3BhY2VVUkk9PT0KZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50Lm5hbWVzcGFjZVVSSSl7Yi5jb250ZW50PVMuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO2Zvcih2YXIgYztjPWIuZmlyc3RDaGlsZDspbC5jYWxsKGIuY29udGVudCxjKTtpZih2YSliLl9fcHJvdG9fXz1hLnByb3RvdHlwZTtlbHNlIGlmKGIuY2xvbmVOb2RlPWZ1bmN0aW9uKGIpe3JldHVybiBhLmEodGhpcyxiKX0sQyl0cnl7UChiKSxXKGIpfWNhdGNoKFRnKXtDPSExfWEuQyhiLmNvbnRlbnQpfX07dmFyIFg9e29wdGlvbjpbInNlbGVjdCJdLHRoZWFkOlsidGFibGUiXSxjb2w6WyJjb2xncm91cCIsInRhYmxlIl0sdHI6WyJ0Ym9keSIsInRhYmxlIl0sdGg6WyJ0ciIsInRib2R5IiwidGFibGUiXSx0ZDpbInRyIiwidGJvZHkiLCJ0YWJsZSJdfSxQPWZ1bmN0aW9uKGIpe09iamVjdC5kZWZpbmVQcm9wZXJ0eShiLCJpbm5lckhUTUwiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbmIodGhpcyl9LHNldDpmdW5jdGlvbihiKXt2YXIgYz1YWygvPChbYS16XVteL1wwPlx4MjBcdFxyXG5cZl0rKS9pLmV4ZWMoYil8fApbIiIsIiJdKVsxXS50b0xvd2VyQ2FzZSgpXTtpZihjKWZvcih2YXIgZD0wO2Q8Yy5sZW5ndGg7ZCsrKWI9IjwiK2NbZF0rIj4iK2IrIjwvIitjW2RdKyI+IjtTLmJvZHkuaW5uZXJIVE1MPWI7Zm9yKGEuQyhTKTt0aGlzLmNvbnRlbnQuZmlyc3RDaGlsZDspay5jYWxsKHRoaXMuY29udGVudCx0aGlzLmNvbnRlbnQuZmlyc3RDaGlsZCk7Yj1TLmJvZHk7aWYoYylmb3IoZD0wO2Q8Yy5sZW5ndGg7ZCsrKWI9Yi5sYXN0Q2hpbGQ7Zm9yKDtiLmZpcnN0Q2hpbGQ7KWwuY2FsbCh0aGlzLmNvbnRlbnQsYi5maXJzdENoaWxkKX0sY29uZmlndXJhYmxlOiEwfSl9LFc9ZnVuY3Rpb24oYSl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGEsIm91dGVySFRNTCIse2dldDpmdW5jdGlvbigpe3JldHVybiI8dGVtcGxhdGU+Iit0aGlzLmlubmVySFRNTCsiPC90ZW1wbGF0ZT4ifSxzZXQ6ZnVuY3Rpb24oYSl7aWYodGhpcy5wYXJlbnROb2RlKXtTLmJvZHkuaW5uZXJIVE1MPWE7Zm9yKGE9dGhpcy5vd25lckRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtTLmJvZHkuZmlyc3RDaGlsZDspbC5jYWxsKGEsClMuYm9keS5maXJzdENoaWxkKTttLmNhbGwodGhpcy5wYXJlbnROb2RlLGEsdGhpcyl9ZWxzZSB0aHJvdyBFcnJvcigiRmFpbGVkIHRvIHNldCB0aGUgJ291dGVySFRNTCcgcHJvcGVydHkgb24gJ0VsZW1lbnQnOiBUaGlzIGVsZW1lbnQgaGFzIG5vIHBhcmVudCBub2RlLiIpO30sY29uZmlndXJhYmxlOiEwfSl9O1AoYS5wcm90b3R5cGUpO1coYS5wcm90b3R5cGUpO2EuQz1mdW5jdGlvbihjKXtjPWIoYywidGVtcGxhdGUiKTtmb3IodmFyIGQ9MCxlPWMubGVuZ3RoLGY7ZDxlJiYoZj1jW2RdKTtkKyspYS5HKGYpfTtkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJET01Db250ZW50TG9hZGVkIixmdW5jdGlvbigpe2EuQyhkb2N1bWVudCl9KTtEb2N1bWVudC5wcm90b3R5cGUuY3JlYXRlRWxlbWVudD1mdW5jdGlvbigpe3ZhciBiPWcuYXBwbHkodGhpcyxhcmd1bWVudHMpOyJ0ZW1wbGF0ZSI9PT1iLmxvY2FsTmFtZSYmYS5HKGIpO3JldHVybiBifTtET01QYXJzZXIucHJvdG90eXBlLnBhcnNlRnJvbVN0cmluZz0KZnVuY3Rpb24oKXt2YXIgYj1xLmFwcGx5KHRoaXMsYXJndW1lbnRzKTthLkMoYik7cmV0dXJuIGJ9O09iamVjdC5kZWZpbmVQcm9wZXJ0eShIVE1MRWxlbWVudC5wcm90b3R5cGUsImlubmVySFRNTCIse2dldDpmdW5jdGlvbigpe3JldHVybiBuYih0aGlzKX0sc2V0OmZ1bmN0aW9uKGIpe3guc2V0LmNhbGwodGhpcyxiKTthLkModGhpcyl9LGNvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwfSk7dmFyIFZlPS9bJlx1MDBBMCJdL2cseWM9L1smXHUwMEEwPD5dL2csemM9ZnVuY3Rpb24oYSl7c3dpdGNoKGEpe2Nhc2UgIiYiOnJldHVybiImYW1wOyI7Y2FzZSAiPCI6cmV0dXJuIiZsdDsiO2Nhc2UgIj4iOnJldHVybiImZ3Q7IjtjYXNlICciJzpyZXR1cm4iJnF1b3Q7IjtjYXNlICJcdTAwYTAiOnJldHVybiImbmJzcDsifX07Vj1mdW5jdGlvbihhKXtmb3IodmFyIGI9e30sYz0wO2M8YS5sZW5ndGg7YysrKWJbYVtjXV09ITA7cmV0dXJuIGJ9O3ZhciBXZT1WKCJhcmVhIGJhc2UgYnIgY29sIGNvbW1hbmQgZW1iZWQgaHIgaW1nIGlucHV0IGtleWdlbiBsaW5rIG1ldGEgcGFyYW0gc291cmNlIHRyYWNrIHdiciIuc3BsaXQoIiAiKSksClhlPVYoInN0eWxlIHNjcmlwdCB4bXAgaWZyYW1lIG5vZW1iZWQgbm9mcmFtZXMgcGxhaW50ZXh0IG5vc2NyaXB0Ii5zcGxpdCgiICIpKSxuYj1mdW5jdGlvbihhLGIpeyJ0ZW1wbGF0ZSI9PT1hLmxvY2FsTmFtZSYmKGE9YS5jb250ZW50KTtmb3IodmFyIGM9IiIsZD1iP2IoYSk6TS5nZXQuY2FsbChhKSxlPTAsZj1kLmxlbmd0aCxnO2U8ZiYmKGc9ZFtlXSk7ZSsrKXthOnt2YXIgaD1nO3ZhciBrPWE7dmFyIGw9Yjtzd2l0Y2goaC5ub2RlVHlwZSl7Y2FzZSBOb2RlLkVMRU1FTlRfTk9ERTpmb3IodmFyIFA9aC5sb2NhbE5hbWUsbT0iPCIrUCxXPWguYXR0cmlidXRlcyxxPTA7az1XW3FdO3ErKyltKz0iICIray5uYW1lKyc9Iicray52YWx1ZS5yZXBsYWNlKFZlLHpjKSsnIic7bSs9Ij4iO2g9V2VbUF0/bTptK25iKGgsbCkrIjwvIitQKyI+IjticmVhayBhO2Nhc2UgTm9kZS5URVhUX05PREU6aD1oLmRhdGE7aD1rJiZYZVtrLmxvY2FsTmFtZV0/aDpoLnJlcGxhY2UoeWMsemMpO2JyZWFrIGE7CmNhc2UgTm9kZS5DT01NRU5UX05PREU6aD0iXHgzYyEtLSIraC5kYXRhKyItLVx4M2UiO2JyZWFrIGE7ZGVmYXVsdDp0aHJvdyB3aW5kb3cuY29uc29sZS5lcnJvcihoKSxFcnJvcigibm90IGltcGxlbWVudGVkIik7fX1jKz1ofXJldHVybiBjfX1pZihjfHxtYil7YS5hPWZ1bmN0aW9uKGEsYil7dmFyIGM9Zi5jYWxsKGEsITEpO3RoaXMuRyYmdGhpcy5HKGMpO2ImJihsLmNhbGwoYy5jb250ZW50LGYuY2FsbChhLmNvbnRlbnQsITApKSxvYihjLmNvbnRlbnQsYS5jb250ZW50KSk7cmV0dXJuIGN9O3ZhciBvYj1mdW5jdGlvbihjLGQpe2lmKGQucXVlcnlTZWxlY3RvckFsbCYmKGQ9YihkLCJ0ZW1wbGF0ZSIpLDAhPT1kLmxlbmd0aCkpe2M9YihjLCJ0ZW1wbGF0ZSIpO2Zvcih2YXIgZT0wLGY9Yy5sZW5ndGgsZyxoO2U8ZjtlKyspaD1kW2VdLGc9Y1tlXSxhJiZhLkcmJmEuRyhoKSxtLmNhbGwoZy5wYXJlbnROb2RlLFllLmNhbGwoaCwhMCksZyl9fSxZZT1Ob2RlLnByb3RvdHlwZS5jbG9uZU5vZGU9CmZ1bmN0aW9uKGIpe2lmKCFlJiZkJiZ0aGlzIGluc3RhbmNlb2YgRG9jdW1lbnRGcmFnbWVudClpZihiKXZhciBjPVplLmNhbGwodGhpcy5vd25lckRvY3VtZW50LHRoaXMsITApO2Vsc2UgcmV0dXJuIHRoaXMub3duZXJEb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7ZWxzZSB0aGlzLm5vZGVUeXBlPT09Tm9kZS5FTEVNRU5UX05PREUmJiJ0ZW1wbGF0ZSI9PT10aGlzLmxvY2FsTmFtZSYmdGhpcy5uYW1lc3BhY2VVUkk9PWRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5uYW1lc3BhY2VVUkk/Yz1hLmEodGhpcyxiKTpjPWYuY2FsbCh0aGlzLGIpO2ImJm9iKGMsdGhpcyk7cmV0dXJuIGN9LFplPURvY3VtZW50LnByb3RvdHlwZS5pbXBvcnROb2RlPWZ1bmN0aW9uKGMsZCl7ZD1kfHwhMTtpZigidGVtcGxhdGUiPT09Yy5sb2NhbE5hbWUpcmV0dXJuIGEuYShjLGQpO3ZhciBlPWguY2FsbCh0aGlzLGMsZCk7aWYoZCl7b2IoZSxjKTtjPWIoZSwnc2NyaXB0Om5vdChbdHlwZV0pLHNjcmlwdFt0eXBlPSJhcHBsaWNhdGlvbi9qYXZhc2NyaXB0Il0sc2NyaXB0W3R5cGU9InRleHQvamF2YXNjcmlwdCJdJyk7CmZvcih2YXIgZixrPTA7azxjLmxlbmd0aDtrKyspe2Y9Y1trXTtkPWcuY2FsbChkb2N1bWVudCwic2NyaXB0Iik7ZC50ZXh0Q29udGVudD1mLnRleHRDb250ZW50O2Zvcih2YXIgbD1mLmF0dHJpYnV0ZXMsUD0wLFc7UDxsLmxlbmd0aDtQKyspVz1sW1BdLGQuc2V0QXR0cmlidXRlKFcubmFtZSxXLnZhbHVlKTttLmNhbGwoZi5wYXJlbnROb2RlLGQsZil9fXJldHVybiBlfX1jJiYod2luZG93LkhUTUxUZW1wbGF0ZUVsZW1lbnQ9YSl9KSgpO3ZhciBrYT1zZXRUaW1lb3V0O2Z1bmN0aW9uIGxhKCl7fWZ1bmN0aW9uIG1hKGEsYil7cmV0dXJuIGZ1bmN0aW9uKCl7YS5hcHBseShiLGFyZ3VtZW50cyl9fWZ1bmN0aW9uIHIoYSl7aWYoISh0aGlzIGluc3RhbmNlb2YgcikpdGhyb3cgbmV3IFR5cGVFcnJvcigiUHJvbWlzZXMgbXVzdCBiZSBjb25zdHJ1Y3RlZCB2aWEgbmV3Iik7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiBhKXRocm93IG5ldyBUeXBlRXJyb3IoIm5vdCBhIGZ1bmN0aW9uIik7dGhpcy51PTA7dGhpcy5tYT0hMTt0aGlzLmg9dm9pZCAwO3RoaXMuST1bXTtuYShhLHRoaXMpfQpmdW5jdGlvbiBvYShhLGIpe2Zvcig7Mz09PWEudTspYT1hLmg7MD09PWEudT9hLkkucHVzaChiKTooYS5tYT0hMCxwYShmdW5jdGlvbigpe3ZhciBjPTE9PT1hLnU/Yi5OYTpiLk9hO2lmKG51bGw9PT1jKSgxPT09YS51P3FhOnJhKShiLmdhLGEuaCk7ZWxzZXt0cnl7dmFyIGQ9YyhhLmgpfWNhdGNoKGUpe3JhKGIuZ2EsZSk7cmV0dXJufXFhKGIuZ2EsZCl9fSkpfWZ1bmN0aW9uIHFhKGEsYil7dHJ5e2lmKGI9PT1hKXRocm93IG5ldyBUeXBlRXJyb3IoIkEgcHJvbWlzZSBjYW5ub3QgYmUgcmVzb2x2ZWQgd2l0aCBpdHNlbGYuIik7aWYoYiYmKCJvYmplY3QiPT09dHlwZW9mIGJ8fCJmdW5jdGlvbiI9PT10eXBlb2YgYikpe3ZhciBjPWIudGhlbjtpZihiIGluc3RhbmNlb2Ygcil7YS51PTM7YS5oPWI7c2EoYSk7cmV0dXJufWlmKCJmdW5jdGlvbiI9PT10eXBlb2YgYyl7bmEobWEoYyxiKSxhKTtyZXR1cm59fWEudT0xO2EuaD1iO3NhKGEpfWNhdGNoKGQpe3JhKGEsZCl9fQpmdW5jdGlvbiByYShhLGIpe2EudT0yO2EuaD1iO3NhKGEpfWZ1bmN0aW9uIHNhKGEpezI9PT1hLnUmJjA9PT1hLkkubGVuZ3RoJiZwYShmdW5jdGlvbigpe2EubWF8fCJ1bmRlZmluZWQiIT09dHlwZW9mIGNvbnNvbGUmJmNvbnNvbGUmJmNvbnNvbGUud2FybigiUG9zc2libGUgVW5oYW5kbGVkIFByb21pc2UgUmVqZWN0aW9uOiIsYS5oKX0pO2Zvcih2YXIgYj0wLGM9YS5JLmxlbmd0aDtiPGM7YisrKW9hKGEsYS5JW2JdKTthLkk9bnVsbH1mdW5jdGlvbiB0YShhLGIsYyl7dGhpcy5OYT0iZnVuY3Rpb24iPT09dHlwZW9mIGE/YTpudWxsO3RoaXMuT2E9ImZ1bmN0aW9uIj09PXR5cGVvZiBiP2I6bnVsbDt0aGlzLmdhPWN9ZnVuY3Rpb24gbmEoYSxiKXt2YXIgYz0hMTt0cnl7YShmdW5jdGlvbihhKXtjfHwoYz0hMCxxYShiLGEpKX0sZnVuY3Rpb24oYSl7Y3x8KGM9ITAscmEoYixhKSl9KX1jYXRjaChkKXtjfHwoYz0hMCxyYShiLGQpKX19CnIucHJvdG90eXBlWyJjYXRjaCJdPWZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLnRoZW4obnVsbCxhKX07ci5wcm90b3R5cGUudGhlbj1mdW5jdGlvbihhLGIpe3ZhciBjPW5ldyB0aGlzLmNvbnN0cnVjdG9yKGxhKTtvYSh0aGlzLG5ldyB0YShhLGIsYykpO3JldHVybiBjfTtyLnByb3RvdHlwZVsiZmluYWxseSJdPWZ1bmN0aW9uKGEpe3ZhciBiPXRoaXMuY29uc3RydWN0b3I7cmV0dXJuIHRoaXMudGhlbihmdW5jdGlvbihjKXtyZXR1cm4gYi5yZXNvbHZlKGEoKSkudGhlbihmdW5jdGlvbigpe3JldHVybiBjfSl9LGZ1bmN0aW9uKGMpe3JldHVybiBiLnJlc29sdmUoYSgpKS50aGVuKGZ1bmN0aW9uKCl7cmV0dXJuIGIucmVqZWN0KGMpfSl9KX07CmZ1bmN0aW9uIHdhKGEpe3JldHVybiBuZXcgcihmdW5jdGlvbihiLGMpe2Z1bmN0aW9uIGQoYSxnKXt0cnl7aWYoZyYmKCJvYmplY3QiPT09dHlwZW9mIGd8fCJmdW5jdGlvbiI9PT10eXBlb2YgZykpe3ZhciBoPWcudGhlbjtpZigiZnVuY3Rpb24iPT09dHlwZW9mIGgpe2guY2FsbChnLGZ1bmN0aW9uKGIpe2QoYSxiKX0sYyk7cmV0dXJufX1lW2FdPWc7MD09PS0tZiYmYihlKX1jYXRjaChtKXtjKG0pfX1pZighYXx8InVuZGVmaW5lZCI9PT10eXBlb2YgYS5sZW5ndGgpdGhyb3cgbmV3IFR5cGVFcnJvcigiUHJvbWlzZS5hbGwgYWNjZXB0cyBhbiBhcnJheSIpO3ZhciBlPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGEpO2lmKDA9PT1lLmxlbmd0aClyZXR1cm4gYihbXSk7Zm9yKHZhciBmPWUubGVuZ3RoLGc9MDtnPGUubGVuZ3RoO2crKylkKGcsZVtnXSl9KX0KZnVuY3Rpb24geGEoYSl7cmV0dXJuIGEmJiJvYmplY3QiPT09dHlwZW9mIGEmJmEuY29uc3RydWN0b3I9PT1yP2E6bmV3IHIoZnVuY3Rpb24oYil7YihhKX0pfWZ1bmN0aW9uIHlhKGEpe3JldHVybiBuZXcgcihmdW5jdGlvbihiLGMpe2MoYSl9KX1mdW5jdGlvbiB6YShhKXtyZXR1cm4gbmV3IHIoZnVuY3Rpb24oYixjKXtmb3IodmFyIGQ9MCxlPWEubGVuZ3RoO2Q8ZTtkKyspYVtkXS50aGVuKGIsYyl9KX12YXIgcGE9ImZ1bmN0aW9uIj09PXR5cGVvZiBzZXRJbW1lZGlhdGUmJmZ1bmN0aW9uKGEpe3NldEltbWVkaWF0ZShhKX18fGZ1bmN0aW9uKGEpe2thKGEsMCl9Oy8qCgpDb3B5cmlnaHQgKGMpIDIwMTcgVGhlIFBvbHltZXIgUHJvamVjdCBBdXRob3JzLiBBbGwgcmlnaHRzIHJlc2VydmVkLgpUaGlzIGNvZGUgbWF5IG9ubHkgYmUgdXNlZCB1bmRlciB0aGUgQlNEIHN0eWxlIGxpY2Vuc2UgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL0xJQ0VOU0UudHh0ClRoZSBjb21wbGV0ZSBzZXQgb2YgYXV0aG9ycyBtYXkgYmUgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL0FVVEhPUlMudHh0ClRoZSBjb21wbGV0ZSBzZXQgb2YgY29udHJpYnV0b3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQ09OVFJJQlVUT1JTLnR4dApDb2RlIGRpc3RyaWJ1dGVkIGJ5IEdvb2dsZSBhcyBwYXJ0IG9mIHRoZSBwb2x5bWVyIHByb2plY3QgaXMgYWxzbwpzdWJqZWN0IHRvIGFuIGFkZGl0aW9uYWwgSVAgcmlnaHRzIGdyYW50IGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9QQVRFTlRTLnR4dAoqLwppZighd2luZG93LlByb21pc2Upe3dpbmRvdy5Qcm9taXNlPXI7ci5wcm90b3R5cGUudGhlbj1yLnByb3RvdHlwZS50aGVuO3IuYWxsPXdhO3IucmFjZT16YTtyLnJlc29sdmU9eGE7ci5yZWplY3Q9eWE7dmFyIEFhPWRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCIiKSxCYT1bXTsobmV3IE11dGF0aW9uT2JzZXJ2ZXIoZnVuY3Rpb24oKXtmb3IodmFyIGE9QmEubGVuZ3RoLGI9MDtiPGE7YisrKUJhW2JdKCk7QmEuc3BsaWNlKDAsYSl9KSkub2JzZXJ2ZShBYSx7Y2hhcmFjdGVyRGF0YTohMH0pO3BhPWZ1bmN0aW9uKGEpe0JhLnB1c2goYSk7QWEudGV4dENvbnRlbnQ9MDxBYS50ZXh0Q29udGVudC5sZW5ndGg/IiI6ImEifX07KGZ1bmN0aW9uKGEpe2Z1bmN0aW9uIGIoYSxiKXtpZigiZnVuY3Rpb24iPT09dHlwZW9mIHdpbmRvdy5DdXN0b21FdmVudClyZXR1cm4gbmV3IEN1c3RvbUV2ZW50KGEsYik7dmFyIGM9ZG9jdW1lbnQuY3JlYXRlRXZlbnQoIkN1c3RvbUV2ZW50Iik7Yy5pbml0Q3VzdG9tRXZlbnQoYSwhIWIuYnViYmxlcywhIWIuY2FuY2VsYWJsZSxiLmRldGFpbCk7cmV0dXJuIGN9ZnVuY3Rpb24gYyhhKXtpZihNKXJldHVybiBhLm93bmVyRG9jdW1lbnQhPT1kb2N1bWVudD9hLm93bmVyRG9jdW1lbnQ6bnVsbDt2YXIgYj1hLl9faW1wb3J0RG9jO2lmKCFiJiZhLnBhcmVudE5vZGUpe2I9YS5wYXJlbnROb2RlO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgYi5jbG9zZXN0KWI9Yi5jbG9zZXN0KCJsaW5rW3JlbD1pbXBvcnRdIik7ZWxzZSBmb3IoOyFoKGIpJiYoYj1iLnBhcmVudE5vZGUpOyk7YS5fX2ltcG9ydERvYz1ifXJldHVybiBifWZ1bmN0aW9uIGQoYSl7dmFyIGI9bShkb2N1bWVudCwibGlua1tyZWw9aW1wb3J0XTpub3QoW2ltcG9ydC1kZXBlbmRlbmN5XSkiKSwKYz1iLmxlbmd0aDtjP3EoYixmdW5jdGlvbihiKXtyZXR1cm4gZyhiLGZ1bmN0aW9uKCl7MD09PS0tYyYmYSgpfSl9KTphKCl9ZnVuY3Rpb24gZShhKXtmdW5jdGlvbiBiKCl7ImxvYWRpbmciIT09ZG9jdW1lbnQucmVhZHlTdGF0ZSYmZG9jdW1lbnQuYm9keSYmKGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoInJlYWR5c3RhdGVjaGFuZ2UiLGIpLGEoKSl9ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigicmVhZHlzdGF0ZWNoYW5nZSIsYik7YigpfWZ1bmN0aW9uIGYoYSl7ZShmdW5jdGlvbigpe3JldHVybiBkKGZ1bmN0aW9uKCl7cmV0dXJuIGEmJmEoKX0pfSl9ZnVuY3Rpb24gZyhhLGIpe2lmKGEuX19sb2FkZWQpYiYmYigpO2Vsc2UgaWYoInNjcmlwdCI9PT1hLmxvY2FsTmFtZSYmIWEuc3JjfHwic3R5bGUiPT09YS5sb2NhbE5hbWUmJiFhLmZpcnN0Q2hpbGQpYS5fX2xvYWRlZD0hMCxiJiZiKCk7ZWxzZXt2YXIgYz1mdW5jdGlvbihkKXthLnJlbW92ZUV2ZW50TGlzdGVuZXIoZC50eXBlLApjKTthLl9fbG9hZGVkPSEwO2ImJmIoKX07YS5hZGRFdmVudExpc3RlbmVyKCJsb2FkIixjKTtoYSYmInN0eWxlIj09PWEubG9jYWxOYW1lfHxhLmFkZEV2ZW50TGlzdGVuZXIoImVycm9yIixjKX19ZnVuY3Rpb24gaChhKXtyZXR1cm4gYS5ub2RlVHlwZT09PU5vZGUuRUxFTUVOVF9OT0RFJiYibGluayI9PT1hLmxvY2FsTmFtZSYmImltcG9ydCI9PT1hLnJlbH1mdW5jdGlvbiBrKCl7dmFyIGE9dGhpczt0aGlzLmE9e307dGhpcy5iPTA7dGhpcy5jPW5ldyBNdXRhdGlvbk9ic2VydmVyKGZ1bmN0aW9uKGIpe3JldHVybiBhLkphKGIpfSk7dGhpcy5jLm9ic2VydmUoZG9jdW1lbnQuaGVhZCx7Y2hpbGRMaXN0OiEwLHN1YnRyZWU6ITB9KTt0aGlzLmxvYWRJbXBvcnRzKGRvY3VtZW50KX1mdW5jdGlvbiBsKGEpe3EobShhLCJ0ZW1wbGF0ZSIpLGZ1bmN0aW9uKGEpe3EobShhLmNvbnRlbnQsJ3NjcmlwdDpub3QoW3R5cGVdKSxzY3JpcHRbdHlwZT0iYXBwbGljYXRpb24vamF2YXNjcmlwdCJdLHNjcmlwdFt0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiXSxzY3JpcHRbdHlwZT0ibW9kdWxlIl0nKSwKZnVuY3Rpb24oYSl7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7cShhLmF0dHJpYnV0ZXMsZnVuY3Rpb24oYSl7cmV0dXJuIGIuc2V0QXR0cmlidXRlKGEubmFtZSxhLnZhbHVlKX0pO2IudGV4dENvbnRlbnQ9YS50ZXh0Q29udGVudDthLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGIsYSl9KTtsKGEuY29udGVudCl9KX1mdW5jdGlvbiBtKGEsYil7cmV0dXJuIGEuY2hpbGROb2Rlcy5sZW5ndGg/YS5xdWVyeVNlbGVjdG9yQWxsKGIpOlV9ZnVuY3Rpb24gcShhLGIsYyl7dmFyIGQ9YT9hLmxlbmd0aDowLGU9Yz8tMToxO2ZvcihjPWM/ZC0xOjA7YzxkJiYwPD1jO2MrPWUpYihhW2NdLGMpfXZhciB4PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImxpbmsiKSxNPSJpbXBvcnQiaW4geCxVPXgucXVlcnlTZWxlY3RvckFsbCgiKiIpLHVhPW51bGw7ITE9PT0iY3VycmVudFNjcmlwdCJpbiBkb2N1bWVudCYmT2JqZWN0LmRlZmluZVByb3BlcnR5KGRvY3VtZW50LCJjdXJyZW50U2NyaXB0IiwKe2dldDpmdW5jdGlvbigpe3JldHVybiB1YXx8KCJjb21wbGV0ZSIhPT1kb2N1bWVudC5yZWFkeVN0YXRlP2RvY3VtZW50LnNjcmlwdHNbZG9jdW1lbnQuc2NyaXB0cy5sZW5ndGgtMV06bnVsbCl9LGNvbmZpZ3VyYWJsZTohMH0pO3ZhciBsYj0vKHVybFwoKShbXildKikoXCkpL2csbWI9LyhAaW1wb3J0W1xzXSsoPyF1cmxcKCkpKFteO10qKSg7KS9nLFM9Lyg8bGlua1tePl0qKShyZWw9Wyd8Il0/c3R5bGVzaGVldFsnfCJdP1tePl0qPikvZyxDPXtFYTpmdW5jdGlvbihhLGIpe2EuaHJlZiYmYS5zZXRBdHRyaWJ1dGUoImhyZWYiLEMuWChhLmdldEF0dHJpYnV0ZSgiaHJlZiIpLGIpKTthLnNyYyYmYS5zZXRBdHRyaWJ1dGUoInNyYyIsQy5YKGEuZ2V0QXR0cmlidXRlKCJzcmMiKSxiKSk7aWYoInN0eWxlIj09PWEubG9jYWxOYW1lKXt2YXIgYz1DLnFhKGEudGV4dENvbnRlbnQsYixsYik7YS50ZXh0Q29udGVudD1DLnFhKGMsYixtYil9fSxxYTpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGEucmVwbGFjZShjLApmdW5jdGlvbihhLGMsZCxlKXthPWQucmVwbGFjZSgvWyInXS9nLCIiKTtiJiYoYT1DLlgoYSxiKSk7cmV0dXJuIGMrIiciK2ErIiciK2V9KX0sWDpmdW5jdGlvbihhLGIpe2lmKHZvaWQgMD09PUMuYWEpe0MuYWE9ITE7dHJ5e3ZhciBjPW5ldyBVUkwoImIiLCJodHRwOi8vYSIpO2MucGF0aG5hbWU9ImMlMjBkIjtDLmFhPSJodHRwOi8vYS9jJTIwZCI9PT1jLmhyZWZ9Y2F0Y2goeWMpe319aWYoQy5hYSlyZXR1cm4obmV3IFVSTChhLGIpKS5ocmVmO2M9Qy54YTtjfHwoYz1kb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnQoInRlbXAiKSxDLnhhPWMsYy5qYT1jLmNyZWF0ZUVsZW1lbnQoImJhc2UiKSxjLmhlYWQuYXBwZW5kQ2hpbGQoYy5qYSksYy5pYT1jLmNyZWF0ZUVsZW1lbnQoImEiKSk7Yy5qYS5ocmVmPWI7Yy5pYS5ocmVmPWE7cmV0dXJuIGMuaWEuaHJlZnx8YX19LFY9e2FzeW5jOiEwLGxvYWQ6ZnVuY3Rpb24oYSxiLGMpe2lmKGEpaWYoYS5tYXRjaCgvXmRhdGE6Lykpe2E9CmEuc3BsaXQoIiwiKTt2YXIgZD1hWzFdO2Q9LTE8YVswXS5pbmRleE9mKCI7YmFzZTY0Iik/YXRvYihkKTpkZWNvZGVVUklDb21wb25lbnQoZCk7YihkKX1lbHNle3ZhciBlPW5ldyBYTUxIdHRwUmVxdWVzdDtlLm9wZW4oIkdFVCIsYSxWLmFzeW5jKTtlLm9ubG9hZD1mdW5jdGlvbigpe3ZhciBhPWUucmVzcG9uc2VVUkx8fGUuZ2V0UmVzcG9uc2VIZWFkZXIoIkxvY2F0aW9uIik7YSYmMD09PWEuaW5kZXhPZigiLyIpJiYoYT0obG9jYXRpb24ub3JpZ2lufHxsb2NhdGlvbi5wcm90b2NvbCsiLy8iK2xvY2F0aW9uLmhvc3QpK2EpO3ZhciBkPWUucmVzcG9uc2V8fGUucmVzcG9uc2VUZXh0OzMwND09PWUuc3RhdHVzfHwwPT09ZS5zdGF0dXN8fDIwMDw9ZS5zdGF0dXMmJjMwMD5lLnN0YXR1cz9iKGQsYSk6YyhkKX07ZS5zZW5kKCl9ZWxzZSBjKCJlcnJvcjogaHJlZiBtdXN0IGJlIHNwZWNpZmllZCIpfX0saGE9L1RyaWRlbnQvLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCl8fC9FZGdlXC9cZC4vaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpOwprLnByb3RvdHlwZS5sb2FkSW1wb3J0cz1mdW5jdGlvbihhKXt2YXIgYj10aGlzO2E9bShhLCJsaW5rW3JlbD1pbXBvcnRdIik7cShhLGZ1bmN0aW9uKGEpe3JldHVybiBiLmcoYSl9KX07ay5wcm90b3R5cGUuZz1mdW5jdGlvbihhKXt2YXIgYj10aGlzLGM9YS5ocmVmO2lmKHZvaWQgMCE9PXRoaXMuYVtjXSl7dmFyIGQ9dGhpcy5hW2NdO2QmJmQuX19sb2FkZWQmJihhLl9faW1wb3J0PWQsdGhpcy5mKGEpKX1lbHNlIHRoaXMuYisrLHRoaXMuYVtjXT0icGVuZGluZyIsVi5sb2FkKGMsZnVuY3Rpb24oYSxkKXthPWIuS2EoYSxkfHxjKTtiLmFbY109YTtiLmItLTtiLmxvYWRJbXBvcnRzKGEpO2IubCgpfSxmdW5jdGlvbigpe2IuYVtjXT1udWxsO2IuYi0tO2IubCgpfSl9O2sucHJvdG90eXBlLkthPWZ1bmN0aW9uKGEsYil7aWYoIWEpcmV0dXJuIGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtoYSYmKGE9YS5yZXBsYWNlKFMsZnVuY3Rpb24oYSxiLGMpe3JldHVybi0xPT09CmEuaW5kZXhPZigidHlwZT0iKT9iKyIgdHlwZT1pbXBvcnQtZGlzYWJsZSAiK2M6YX0pKTt2YXIgYz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJ0ZW1wbGF0ZSIpO2MuaW5uZXJIVE1MPWE7aWYoYy5jb250ZW50KWE9Yy5jb250ZW50LGwoYSk7ZWxzZSBmb3IoYT1kb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7Yy5maXJzdENoaWxkOylhLmFwcGVuZENoaWxkKGMuZmlyc3RDaGlsZCk7aWYoYz1hLnF1ZXJ5U2VsZWN0b3IoImJhc2UiKSliPUMuWChjLmdldEF0dHJpYnV0ZSgiaHJlZiIpLGIpLGMucmVtb3ZlQXR0cmlidXRlKCJocmVmIik7Yz1tKGEsJ2xpbmtbcmVsPWltcG9ydF0sbGlua1tyZWw9c3R5bGVzaGVldF1baHJlZl1bdHlwZT1pbXBvcnQtZGlzYWJsZV0sc3R5bGU6bm90KFt0eXBlXSksbGlua1tyZWw9c3R5bGVzaGVldF1baHJlZl06bm90KFt0eXBlXSksc2NyaXB0Om5vdChbdHlwZV0pLHNjcmlwdFt0eXBlPSJhcHBsaWNhdGlvbi9qYXZhc2NyaXB0Il0sc2NyaXB0W3R5cGU9InRleHQvamF2YXNjcmlwdCJdLHNjcmlwdFt0eXBlPSJtb2R1bGUiXScpOwp2YXIgZD0wO3EoYyxmdW5jdGlvbihhKXtnKGEpO0MuRWEoYSxiKTthLnNldEF0dHJpYnV0ZSgiaW1wb3J0LWRlcGVuZGVuY3kiLCIiKTtpZigic2NyaXB0Ij09PWEubG9jYWxOYW1lJiYhYS5zcmMmJmEudGV4dENvbnRlbnQpe2lmKCJtb2R1bGUiPT09YS50eXBlKXRocm93IEVycm9yKCJJbmxpbmUgbW9kdWxlIHNjcmlwdHMgYXJlIG5vdCBzdXBwb3J0ZWQgaW4gSFRNTCBJbXBvcnRzLiIpO2Euc2V0QXR0cmlidXRlKCJzcmMiLCJkYXRhOnRleHQvamF2YXNjcmlwdDtjaGFyc2V0PXV0Zi04LCIrZW5jb2RlVVJJQ29tcG9uZW50KGEudGV4dENvbnRlbnQrKCJcbi8vIyBzb3VyY2VVUkw9IitiKyhkPyItIitkOiIiKSsiLmpzXG4iKSkpO2EudGV4dENvbnRlbnQ9IiI7ZCsrfX0pO3JldHVybiBhfTtrLnByb3RvdHlwZS5sPWZ1bmN0aW9uKCl7dmFyIGE9dGhpcztpZighdGhpcy5iKXt0aGlzLmMuZGlzY29ubmVjdCgpO3RoaXMuZmxhdHRlbihkb2N1bWVudCk7dmFyIGI9ITEsYz0hMSxkPWZ1bmN0aW9uKCl7YyYmCmImJihhLmxvYWRJbXBvcnRzKGRvY3VtZW50KSxhLmJ8fChhLmMub2JzZXJ2ZShkb2N1bWVudC5oZWFkLHtjaGlsZExpc3Q6ITAsc3VidHJlZTohMH0pLGEuZGEoKSkpfTt0aGlzLk1hKGZ1bmN0aW9uKCl7Yz0hMDtkKCl9KTt0aGlzLkxhKGZ1bmN0aW9uKCl7Yj0hMDtkKCl9KX19O2sucHJvdG90eXBlLmZsYXR0ZW49ZnVuY3Rpb24oYSl7dmFyIGI9dGhpczthPW0oYSwibGlua1tyZWw9aW1wb3J0XSIpO3EoYSxmdW5jdGlvbihhKXt2YXIgYz1iLmFbYS5ocmVmXTsoYS5fX2ltcG9ydD1jKSYmYy5ub2RlVHlwZT09PU5vZGUuRE9DVU1FTlRfRlJBR01FTlRfTk9ERSYmKGIuYVthLmhyZWZdPWEsYS5yZWFkeVN0YXRlPSJsb2FkaW5nIixhLl9faW1wb3J0PWEsYi5mbGF0dGVuKGMpLGEuYXBwZW5kQ2hpbGQoYykpfSl9O2sucHJvdG90eXBlLkxhPWZ1bmN0aW9uKGEpe2Z1bmN0aW9uIGIoZSl7aWYoZTxkKXt2YXIgZj1jW2VdLGg9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7Zi5yZW1vdmVBdHRyaWJ1dGUoImltcG9ydC1kZXBlbmRlbmN5Iik7CnEoZi5hdHRyaWJ1dGVzLGZ1bmN0aW9uKGEpe3JldHVybiBoLnNldEF0dHJpYnV0ZShhLm5hbWUsYS52YWx1ZSl9KTt1YT1oO2YucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoaCxmKTtnKGgsZnVuY3Rpb24oKXt1YT1udWxsO2IoZSsxKX0pfWVsc2UgYSgpfXZhciBjPW0oZG9jdW1lbnQsInNjcmlwdFtpbXBvcnQtZGVwZW5kZW5jeV0iKSxkPWMubGVuZ3RoO2IoMCl9O2sucHJvdG90eXBlLk1hPWZ1bmN0aW9uKGEpe3ZhciBiPW0oZG9jdW1lbnQsInN0eWxlW2ltcG9ydC1kZXBlbmRlbmN5XSxsaW5rW3JlbD1zdHlsZXNoZWV0XVtpbXBvcnQtZGVwZW5kZW5jeV0iKSxkPWIubGVuZ3RoO2lmKGQpe3ZhciBlPWhhJiYhIWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoImxpbmtbcmVsPXN0eWxlc2hlZXRdW2hyZWZdW3R5cGU9aW1wb3J0LWRpc2FibGVdIik7cShiLGZ1bmN0aW9uKGIpe2coYixmdW5jdGlvbigpe2IucmVtb3ZlQXR0cmlidXRlKCJpbXBvcnQtZGVwZW5kZW5jeSIpOzA9PT0tLWQmJgphKCl9KTtpZihlJiZiLnBhcmVudE5vZGUhPT1kb2N1bWVudC5oZWFkKXt2YXIgZj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KGIubG9jYWxOYW1lKTtmLl9fYXBwbGllZEVsZW1lbnQ9YjtmLnNldEF0dHJpYnV0ZSgidHlwZSIsImltcG9ydC1wbGFjZWhvbGRlciIpO2IucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoZixiLm5leHRTaWJsaW5nKTtmb3IoZj1jKGIpO2YmJmMoZik7KWY9YyhmKTtmLnBhcmVudE5vZGUhPT1kb2N1bWVudC5oZWFkJiYoZj1udWxsKTtkb2N1bWVudC5oZWFkLmluc2VydEJlZm9yZShiLGYpO2IucmVtb3ZlQXR0cmlidXRlKCJ0eXBlIil9fSl9ZWxzZSBhKCl9O2sucHJvdG90eXBlLmRhPWZ1bmN0aW9uKCl7dmFyIGE9dGhpcyxiPW0oZG9jdW1lbnQsImxpbmtbcmVsPWltcG9ydF0iKTtxKGIsZnVuY3Rpb24oYil7cmV0dXJuIGEuZihiKX0sITApfTtrLnByb3RvdHlwZS5mPWZ1bmN0aW9uKGEpe2EuX19sb2FkZWR8fChhLl9fbG9hZGVkPSEwLGEuaW1wb3J0JiYoYS5pbXBvcnQucmVhZHlTdGF0ZT0KImNvbXBsZXRlIiksYS5kaXNwYXRjaEV2ZW50KGIoYS5pbXBvcnQ/ImxvYWQiOiJlcnJvciIse2J1YmJsZXM6ITEsY2FuY2VsYWJsZTohMSxkZXRhaWw6dm9pZCAwfSkpKX07ay5wcm90b3R5cGUuSmE9ZnVuY3Rpb24oYSl7dmFyIGI9dGhpcztxKGEsZnVuY3Rpb24oYSl7cmV0dXJuIHEoYS5hZGRlZE5vZGVzLGZ1bmN0aW9uKGEpe2EmJmEubm9kZVR5cGU9PT1Ob2RlLkVMRU1FTlRfTk9ERSYmKGgoYSk/Yi5nKGEpOmIubG9hZEltcG9ydHMoYSkpfSl9KX07dmFyIHZhPW51bGw7aWYoTSl4PW0oZG9jdW1lbnQsImxpbmtbcmVsPWltcG9ydF0iKSxxKHgsZnVuY3Rpb24oYSl7YS5pbXBvcnQmJiJsb2FkaW5nIj09PWEuaW1wb3J0LnJlYWR5U3RhdGV8fChhLl9fbG9hZGVkPSEwKX0pLHg9ZnVuY3Rpb24oYSl7YT1hLnRhcmdldDtoKGEpJiYoYS5fX2xvYWRlZD0hMCl9LGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoImxvYWQiLHgsITApLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoImVycm9yIiwKeCwhMCk7ZWxzZXt2YXIgWD1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKE5vZGUucHJvdG90eXBlLCJiYXNlVVJJIik7T2JqZWN0LmRlZmluZVByb3BlcnR5KCghWHx8WC5jb25maWd1cmFibGU/Tm9kZTpFbGVtZW50KS5wcm90b3R5cGUsImJhc2VVUkkiLHtnZXQ6ZnVuY3Rpb24oKXt2YXIgYT1oKHRoaXMpP3RoaXM6Yyh0aGlzKTtyZXR1cm4gYT9hLmhyZWY6WCYmWC5nZXQ/WC5nZXQuY2FsbCh0aGlzKTooZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiYmFzZSIpfHx3aW5kb3cubG9jYXRpb24pLmhyZWZ9LGNvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwfSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KEhUTUxMaW5rRWxlbWVudC5wcm90b3R5cGUsImltcG9ydCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9faW1wb3J0fHxudWxsfSxjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMH0pO2UoZnVuY3Rpb24oKXt2YT1uZXcga30pfWYoZnVuY3Rpb24oKXtyZXR1cm4gZG9jdW1lbnQuZGlzcGF0Y2hFdmVudChiKCJIVE1MSW1wb3J0c0xvYWRlZCIsCntjYW5jZWxhYmxlOiEwLGJ1YmJsZXM6ITAsZGV0YWlsOnZvaWQgMH0pKX0pO2EudXNlTmF0aXZlPU07YS53aGVuUmVhZHk9ZjthLmltcG9ydEZvckVsZW1lbnQ9YzthLmxvYWRJbXBvcnRzPWZ1bmN0aW9uKGEpe3ZhJiZ2YS5sb2FkSW1wb3J0cyhhKX19KSh3aW5kb3cuSFRNTEltcG9ydHM9d2luZG93LkhUTUxJbXBvcnRzfHx7fSk7LyoKCiBDb3B5cmlnaHQgKGMpIDIwMTQgVGhlIFBvbHltZXIgUHJvamVjdCBBdXRob3JzLiBBbGwgcmlnaHRzIHJlc2VydmVkLgogVGhpcyBjb2RlIG1heSBvbmx5IGJlIHVzZWQgdW5kZXIgdGhlIEJTRCBzdHlsZSBsaWNlbnNlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9MSUNFTlNFLnR4dAogVGhlIGNvbXBsZXRlIHNldCBvZiBhdXRob3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQVVUSE9SUy50eHQKIFRoZSBjb21wbGV0ZSBzZXQgb2YgY29udHJpYnV0b3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQ09OVFJJQlVUT1JTLnR4dAogQ29kZSBkaXN0cmlidXRlZCBieSBHb29nbGUgYXMgcGFydCBvZiB0aGUgcG9seW1lciBwcm9qZWN0IGlzIGFsc28KIHN1YmplY3QgdG8gYW4gYWRkaXRpb25hbCBJUCByaWdodHMgZ3JhbnQgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL1BBVEVOVFMudHh0CiovCndpbmRvdy5XZWJDb21wb25lbnRzPXdpbmRvdy5XZWJDb21wb25lbnRzfHx7ZmxhZ3M6e319O3ZhciBDYT1kb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdzY3JpcHRbc3JjKj0id2ViY29tcG9uZW50cy1saXRlLmpzIl0nKSxEYT0vd2MtKC4rKS8sdD17fTtpZighdC5ub09wdHMpe2xvY2F0aW9uLnNlYXJjaC5zbGljZSgxKS5zcGxpdCgiJiIpLmZvckVhY2goZnVuY3Rpb24oYSl7YT1hLnNwbGl0KCI9Iik7dmFyIGI7YVswXSYmKGI9YVswXS5tYXRjaChEYSkpJiYodFtiWzFdXT1hWzFdfHwhMCl9KTtpZihDYSlmb3IodmFyIEVhPTAsRmE9dm9pZCAwO0ZhPUNhLmF0dHJpYnV0ZXNbRWFdO0VhKyspInNyYyIhPT1GYS5uYW1lJiYodFtGYS5uYW1lXT1GYS52YWx1ZXx8ITApO2lmKHQubG9nJiZ0LmxvZy5zcGxpdCl7dmFyIEdhPXQubG9nLnNwbGl0KCIsIik7dC5sb2c9e307R2EuZm9yRWFjaChmdW5jdGlvbihhKXt0LmxvZ1thXT0hMH0pfWVsc2UgdC5sb2c9e319CndpbmRvdy5XZWJDb21wb25lbnRzLmZsYWdzPXQ7dmFyIEhhPXQuc2hhZHlkb207SGEmJih3aW5kb3cuU2hhZHlET009d2luZG93LlNoYWR5RE9NfHx7fSx3aW5kb3cuU2hhZHlET00uZm9yY2U9SGEpO3ZhciBJYT10LnJlZ2lzdGVyfHx0LmNlO0lhJiZ3aW5kb3cuY3VzdG9tRWxlbWVudHMmJih3aW5kb3cuY3VzdG9tRWxlbWVudHMuZm9yY2VQb2x5ZmlsbD1JYSk7LyoKCkNvcHlyaWdodCAoYykgMjAxNiBUaGUgUG9seW1lciBQcm9qZWN0IEF1dGhvcnMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuClRoaXMgY29kZSBtYXkgb25seSBiZSB1c2VkIHVuZGVyIHRoZSBCU0Qgc3R5bGUgbGljZW5zZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vTElDRU5TRS50eHQKVGhlIGNvbXBsZXRlIHNldCBvZiBhdXRob3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQVVUSE9SUy50eHQKVGhlIGNvbXBsZXRlIHNldCBvZiBjb250cmlidXRvcnMgbWF5IGJlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9DT05UUklCVVRPUlMudHh0CkNvZGUgZGlzdHJpYnV0ZWQgYnkgR29vZ2xlIGFzIHBhcnQgb2YgdGhlIHBvbHltZXIgcHJvamVjdCBpcyBhbHNvCnN1YmplY3QgdG8gYW4gYWRkaXRpb25hbCBJUCByaWdodHMgZ3JhbnQgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL1BBVEVOVFMudHh0CiovCmZ1bmN0aW9uIEphKCl7dGhpcy5wYT10aGlzLnJvb3Q9bnVsbDt0aGlzLlQ9ITE7dGhpcy5EPXRoaXMuUD10aGlzLmNhPXRoaXMuYXNzaWduZWRTbG90PXRoaXMuYXNzaWduZWROb2Rlcz10aGlzLkg9bnVsbDt0aGlzLmNoaWxkTm9kZXM9dGhpcy5uZXh0U2libGluZz10aGlzLnByZXZpb3VzU2libGluZz10aGlzLmxhc3RDaGlsZD10aGlzLmZpcnN0Q2hpbGQ9dGhpcy5wYXJlbnROb2RlPXRoaXMuSz12b2lkIDA7dGhpcy5rYT10aGlzLmxhPSExO3RoaXMuTz17fX1KYS5wcm90b3R5cGUudG9KU09OPWZ1bmN0aW9uKCl7cmV0dXJue319O2Z1bmN0aW9uIHUoYSl7YS5fX3NoYWR5fHwoYS5fX3NoYWR5PW5ldyBKYSk7cmV0dXJuIGEuX19zaGFkeX1mdW5jdGlvbiB2KGEpe3JldHVybiBhJiZhLl9fc2hhZHl9O3ZhciB3PXdpbmRvdy5TaGFkeURPTXx8e307dy5HYT0hKCFFbGVtZW50LnByb3RvdHlwZS5hdHRhY2hTaGFkb3d8fCFOb2RlLnByb3RvdHlwZS5nZXRSb290Tm9kZSk7dmFyIEthPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoTm9kZS5wcm90b3R5cGUsImZpcnN0Q2hpbGQiKTt3Lm09ISEoS2EmJkthLmNvbmZpZ3VyYWJsZSYmS2EuZ2V0KTt3LmVhPXcuZm9yY2V8fCF3LkdhO3cuSj13Lm5vUGF0Y2h8fCExO3cub2E9dy5wcmVmZXJQZXJmb3JtYW5jZTtmdW5jdGlvbiB5KGEpe3JldHVybihhPXYoYSkpJiZ2b2lkIDAhPT1hLmZpcnN0Q2hpbGR9ZnVuY3Rpb24geihhKXtyZXR1cm4iU2hhZHlSb290Ij09PWEuemF9ZnVuY3Rpb24gTGEoYSl7cmV0dXJuKGE9KGE9dihhKSkmJmEucm9vdCkmJk1hKGEpfQp2YXIgTmE9RWxlbWVudC5wcm90b3R5cGUsT2E9TmEubWF0Y2hlc3x8TmEubWF0Y2hlc1NlbGVjdG9yfHxOYS5tb3pNYXRjaGVzU2VsZWN0b3J8fE5hLm1zTWF0Y2hlc1NlbGVjdG9yfHxOYS5vTWF0Y2hlc1NlbGVjdG9yfHxOYS53ZWJraXRNYXRjaGVzU2VsZWN0b3IsUGE9ZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIiIpLFFhPTAsUmE9W107KG5ldyBNdXRhdGlvbk9ic2VydmVyKGZ1bmN0aW9uKCl7Zm9yKDtSYS5sZW5ndGg7KXRyeXtSYS5zaGlmdCgpKCl9Y2F0Y2goYSl7dGhyb3cgUGEudGV4dENvbnRlbnQ9UWErKyxhO319KSkub2JzZXJ2ZShQYSx7Y2hhcmFjdGVyRGF0YTohMH0pO2Z1bmN0aW9uIFNhKGEpe1JhLnB1c2goYSk7UGEudGV4dENvbnRlbnQ9UWErK312YXIgVGE9ISFkb2N1bWVudC5jb250YWlucztmdW5jdGlvbiBVYShhLGIpe2Zvcig7Yjspe2lmKGI9PWEpcmV0dXJuITA7Yj1iLl9fc2hhZHlfcGFyZW50Tm9kZX1yZXR1cm4hMX0KZnVuY3Rpb24gVmEoYSl7Zm9yKHZhciBiPWEubGVuZ3RoLTE7MDw9YjtiLS0pe3ZhciBjPWFbYl0sZD1jLmdldEF0dHJpYnV0ZSgiaWQiKXx8Yy5nZXRBdHRyaWJ1dGUoIm5hbWUiKTtkJiYibGVuZ3RoIiE9PWQmJmlzTmFOKGQpJiYoYVtkXT1jKX1hLml0ZW09ZnVuY3Rpb24oYil7cmV0dXJuIGFbYl19O2EubmFtZWRJdGVtPWZ1bmN0aW9uKGIpe2lmKCJsZW5ndGgiIT09YiYmaXNOYU4oYikmJmFbYl0pcmV0dXJuIGFbYl07Zm9yKHZhciBjPWlhKGEpLGQ9Yy5uZXh0KCk7IWQuZG9uZTtkPWMubmV4dCgpKWlmKGQ9ZC52YWx1ZSwoZC5nZXRBdHRyaWJ1dGUoImlkIil8fGQuZ2V0QXR0cmlidXRlKCJuYW1lIikpPT1iKXJldHVybiBkO3JldHVybiBudWxsfTtyZXR1cm4gYX0KZnVuY3Rpb24gQShhLGIsYyxkKXtjPXZvaWQgMD09PWM/IiI6Yztmb3IodmFyIGUgaW4gYil7dmFyIGY9YltlXTtpZighKGQmJjA8PWQuaW5kZXhPZihlKSkpe2YuY29uZmlndXJhYmxlPSEwO3ZhciBnPWMrZTtpZihmLnZhbHVlKWFbZ109Zi52YWx1ZTtlbHNlIHRyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkoYSxnLGYpfWNhdGNoKGgpe319fX1mdW5jdGlvbiBCKGEpe3ZhciBiPXt9O09iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGEpLmZvckVhY2goZnVuY3Rpb24oYyl7YltjXT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGEsYyl9KTtyZXR1cm4gYn07dmFyIFdhPVtdLFhhO2Z1bmN0aW9uIFlhKGEpe1hhfHwoWGE9ITAsU2EoWmEpKTtXYS5wdXNoKGEpfWZ1bmN0aW9uIFphKCl7WGE9ITE7Zm9yKHZhciBhPSEhV2EubGVuZ3RoO1dhLmxlbmd0aDspV2Euc2hpZnQoKSgpO3JldHVybiBhfVphLmxpc3Q9V2E7ZnVuY3Rpb24gJGEoKXt0aGlzLmE9ITE7dGhpcy5hZGRlZE5vZGVzPVtdO3RoaXMucmVtb3ZlZE5vZGVzPVtdO3RoaXMuUz1uZXcgU2V0fWZ1bmN0aW9uIGFiKGEpe2EuYXx8KGEuYT0hMCxTYShmdW5jdGlvbigpe2EuZmx1c2goKX0pKX0kYS5wcm90b3R5cGUuZmx1c2g9ZnVuY3Rpb24oKXtpZih0aGlzLmEpe3RoaXMuYT0hMTt2YXIgYT10aGlzLnRha2VSZWNvcmRzKCk7YS5sZW5ndGgmJnRoaXMuUy5mb3JFYWNoKGZ1bmN0aW9uKGIpe2IoYSl9KX19OyRhLnByb3RvdHlwZS50YWtlUmVjb3Jkcz1mdW5jdGlvbigpe2lmKHRoaXMuYWRkZWROb2Rlcy5sZW5ndGh8fHRoaXMucmVtb3ZlZE5vZGVzLmxlbmd0aCl7dmFyIGE9W3thZGRlZE5vZGVzOnRoaXMuYWRkZWROb2RlcyxyZW1vdmVkTm9kZXM6dGhpcy5yZW1vdmVkTm9kZXN9XTt0aGlzLmFkZGVkTm9kZXM9W107dGhpcy5yZW1vdmVkTm9kZXM9W107cmV0dXJuIGF9cmV0dXJuW119OwpmdW5jdGlvbiBiYihhLGIpe3ZhciBjPXUoYSk7Yy5IfHwoYy5IPW5ldyAkYSk7Yy5ILlMuYWRkKGIpO3ZhciBkPWMuSDtyZXR1cm57eWE6YixGOmQsQWE6YSx0YWtlUmVjb3JkczpmdW5jdGlvbigpe3JldHVybiBkLnRha2VSZWNvcmRzKCl9fX1mdW5jdGlvbiBjYihhKXt2YXIgYj1hJiZhLkY7YiYmKGIuUy5kZWxldGUoYS55YSksYi5TLnNpemV8fCh1KGEuQWEpLkg9bnVsbCkpfQpmdW5jdGlvbiBkYihhLGIpe3ZhciBjPWIuZ2V0Um9vdE5vZGUoKTtyZXR1cm4gYS5tYXAoZnVuY3Rpb24oYSl7dmFyIGI9Yz09PWEudGFyZ2V0LmdldFJvb3ROb2RlKCk7aWYoYiYmYS5hZGRlZE5vZGVzKXtpZihiPUFycmF5LmZyb20oYS5hZGRlZE5vZGVzKS5maWx0ZXIoZnVuY3Rpb24oYSl7cmV0dXJuIGM9PT1hLmdldFJvb3ROb2RlKCl9KSxiLmxlbmd0aClyZXR1cm4gYT1PYmplY3QuY3JlYXRlKGEpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShhLCJhZGRlZE5vZGVzIix7dmFsdWU6Yixjb25maWd1cmFibGU6ITB9KSxhfWVsc2UgaWYoYilyZXR1cm4gYX0pLmZpbHRlcihmdW5jdGlvbihhKXtyZXR1cm4gYX0pfTt2YXIgZWI9L1smXHUwMEEwIl0vZyxmYj0vWyZcdTAwQTA8Pl0vZztmdW5jdGlvbiBnYihhKXtzd2l0Y2goYSl7Y2FzZSAiJiI6cmV0dXJuIiZhbXA7IjtjYXNlICI8IjpyZXR1cm4iJmx0OyI7Y2FzZSAiPiI6cmV0dXJuIiZndDsiO2Nhc2UgJyInOnJldHVybiImcXVvdDsiO2Nhc2UgIlx1MDBhMCI6cmV0dXJuIiZuYnNwOyJ9fWZ1bmN0aW9uIGhiKGEpe2Zvcih2YXIgYj17fSxjPTA7YzxhLmxlbmd0aDtjKyspYlthW2NdXT0hMDtyZXR1cm4gYn12YXIgaWI9aGIoImFyZWEgYmFzZSBiciBjb2wgY29tbWFuZCBlbWJlZCBociBpbWcgaW5wdXQga2V5Z2VuIGxpbmsgbWV0YSBwYXJhbSBzb3VyY2UgdHJhY2sgd2JyIi5zcGxpdCgiICIpKSxqYj1oYigic3R5bGUgc2NyaXB0IHhtcCBpZnJhbWUgbm9lbWJlZCBub2ZyYW1lcyBwbGFpbnRleHQgbm9zY3JpcHQiLnNwbGl0KCIgIikpOwpmdW5jdGlvbiBrYihhLGIpeyJ0ZW1wbGF0ZSI9PT1hLmxvY2FsTmFtZSYmKGE9YS5jb250ZW50KTtmb3IodmFyIGM9IiIsZD1iP2IoYSk6YS5jaGlsZE5vZGVzLGU9MCxmPWQubGVuZ3RoLGc9dm9pZCAwO2U8ZiYmKGc9ZFtlXSk7ZSsrKXthOnt2YXIgaD1nO3ZhciBrPWEsbD1iO3N3aXRjaChoLm5vZGVUeXBlKXtjYXNlIE5vZGUuRUxFTUVOVF9OT0RFOms9aC5sb2NhbE5hbWU7Zm9yKHZhciBtPSI8IitrLHE9aC5hdHRyaWJ1dGVzLHg9MCxNO009cVt4XTt4KyspbSs9IiAiK00ubmFtZSsnPSInK00udmFsdWUucmVwbGFjZShlYixnYikrJyInO20rPSI+IjtoPWliW2tdP206bStrYihoLGwpKyI8LyIraysiPiI7YnJlYWsgYTtjYXNlIE5vZGUuVEVYVF9OT0RFOmg9aC5kYXRhO2g9ayYmamJbay5sb2NhbE5hbWVdP2g6aC5yZXBsYWNlKGZiLGdiKTticmVhayBhO2Nhc2UgTm9kZS5DT01NRU5UX05PREU6aD0iXHgzYyEtLSIraC5kYXRhKyItLVx4M2UiO2JyZWFrIGE7ZGVmYXVsdDp0aHJvdyB3aW5kb3cuY29uc29sZS5lcnJvcihoKSwKRXJyb3IoIm5vdCBpbXBsZW1lbnRlZCIpO319Yys9aH1yZXR1cm4gY307dmFyIHBiPXcubSxxYj17cXVlcnlTZWxlY3RvcjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5fX3NoYWR5X25hdGl2ZV9xdWVyeVNlbGVjdG9yKGEpfSxxdWVyeVNlbGVjdG9yQWxsOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLl9fc2hhZHlfbmF0aXZlX3F1ZXJ5U2VsZWN0b3JBbGwoYSl9fSxyYj17fTtmdW5jdGlvbiBzYihhKXtyYlthXT1mdW5jdGlvbihiKXtyZXR1cm4gYlsiX19zaGFkeV9uYXRpdmVfIithXX19ZnVuY3Rpb24gdGIoYSxiKXtBKGEsYiwiX19zaGFkeV9uYXRpdmVfIik7Zm9yKHZhciBjIGluIGIpc2IoYyl9ZnVuY3Rpb24gRChhLGIpe2I9dm9pZCAwPT09Yj9bXTpiO2Zvcih2YXIgYz0wO2M8Yi5sZW5ndGg7YysrKXt2YXIgZD1iW2NdLGU9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihhLGQpO2UmJihPYmplY3QuZGVmaW5lUHJvcGVydHkoYSwiX19zaGFkeV9uYXRpdmVfIitkLGUpLGUudmFsdWU/cWJbZF18fChxYltkXT1lLnZhbHVlKTpzYihkKSl9fQp2YXIgRT1kb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKGRvY3VtZW50LE5vZGVGaWx0ZXIuU0hPV19BTEwsbnVsbCwhMSksRj1kb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKGRvY3VtZW50LE5vZGVGaWx0ZXIuU0hPV19FTEVNRU5ULG51bGwsITEpLHViPWRvY3VtZW50LmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgiaW5lcnQiKTtmdW5jdGlvbiB2YihhKXtmb3IodmFyIGI7Yj1hLl9fc2hhZHlfbmF0aXZlX2ZpcnN0Q2hpbGQ7KWEuX19zaGFkeV9uYXRpdmVfcmVtb3ZlQ2hpbGQoYil9dmFyIHdiPVsiZmlyc3RFbGVtZW50Q2hpbGQiLCJsYXN0RWxlbWVudENoaWxkIiwiY2hpbGRyZW4iLCJjaGlsZEVsZW1lbnRDb3VudCJdLHhiPVsicXVlcnlTZWxlY3RvciIsInF1ZXJ5U2VsZWN0b3JBbGwiXTsKZnVuY3Rpb24geWIoKXt2YXIgYT1bImRpc3BhdGNoRXZlbnQiLCJhZGRFdmVudExpc3RlbmVyIiwicmVtb3ZlRXZlbnRMaXN0ZW5lciJdO3dpbmRvdy5FdmVudFRhcmdldD9EKHdpbmRvdy5FdmVudFRhcmdldC5wcm90b3R5cGUsYSk6KEQoTm9kZS5wcm90b3R5cGUsYSksRChXaW5kb3cucHJvdG90eXBlLGEpKTtwYj9EKE5vZGUucHJvdG90eXBlLCJwYXJlbnROb2RlIGZpcnN0Q2hpbGQgbGFzdENoaWxkIHByZXZpb3VzU2libGluZyBuZXh0U2libGluZyBjaGlsZE5vZGVzIHBhcmVudEVsZW1lbnQgdGV4dENvbnRlbnQiLnNwbGl0KCIgIikpOnRiKE5vZGUucHJvdG90eXBlLHtwYXJlbnROb2RlOntnZXQ6ZnVuY3Rpb24oKXtFLmN1cnJlbnROb2RlPXRoaXM7cmV0dXJuIEUucGFyZW50Tm9kZSgpfX0sZmlyc3RDaGlsZDp7Z2V0OmZ1bmN0aW9uKCl7RS5jdXJyZW50Tm9kZT10aGlzO3JldHVybiBFLmZpcnN0Q2hpbGQoKX19LGxhc3RDaGlsZDp7Z2V0OmZ1bmN0aW9uKCl7RS5jdXJyZW50Tm9kZT0KdGhpcztyZXR1cm4gRS5sYXN0Q2hpbGQoKX19LHByZXZpb3VzU2libGluZzp7Z2V0OmZ1bmN0aW9uKCl7RS5jdXJyZW50Tm9kZT10aGlzO3JldHVybiBFLnByZXZpb3VzU2libGluZygpfX0sbmV4dFNpYmxpbmc6e2dldDpmdW5jdGlvbigpe0UuY3VycmVudE5vZGU9dGhpcztyZXR1cm4gRS5uZXh0U2libGluZygpfX0sY2hpbGROb2Rlczp7Z2V0OmZ1bmN0aW9uKCl7dmFyIGE9W107RS5jdXJyZW50Tm9kZT10aGlzO2Zvcih2YXIgYz1FLmZpcnN0Q2hpbGQoKTtjOylhLnB1c2goYyksYz1FLm5leHRTaWJsaW5nKCk7cmV0dXJuIGF9fSxwYXJlbnRFbGVtZW50OntnZXQ6ZnVuY3Rpb24oKXtGLmN1cnJlbnROb2RlPXRoaXM7cmV0dXJuIEYucGFyZW50Tm9kZSgpfX0sdGV4dENvbnRlbnQ6e2dldDpmdW5jdGlvbigpe3N3aXRjaCh0aGlzLm5vZGVUeXBlKXtjYXNlIE5vZGUuRUxFTUVOVF9OT0RFOmNhc2UgTm9kZS5ET0NVTUVOVF9GUkFHTUVOVF9OT0RFOmZvcih2YXIgYT1kb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKHRoaXMsCk5vZGVGaWx0ZXIuU0hPV19URVhULG51bGwsITEpLGM9IiIsZDtkPWEubmV4dE5vZGUoKTspYys9ZC5ub2RlVmFsdWU7cmV0dXJuIGM7ZGVmYXVsdDpyZXR1cm4gdGhpcy5ub2RlVmFsdWV9fSxzZXQ6ZnVuY3Rpb24oYSl7aWYoInVuZGVmaW5lZCI9PT10eXBlb2YgYXx8bnVsbD09PWEpYT0iIjtzd2l0Y2godGhpcy5ub2RlVHlwZSl7Y2FzZSBOb2RlLkVMRU1FTlRfTk9ERTpjYXNlIE5vZGUuRE9DVU1FTlRfRlJBR01FTlRfTk9ERTp2Yih0aGlzKTsoMDxhLmxlbmd0aHx8dGhpcy5ub2RlVHlwZT09PU5vZGUuRUxFTUVOVF9OT0RFKSYmdGhpcy5fX3NoYWR5X25hdGl2ZV9pbnNlcnRCZWZvcmUoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoYSksdm9pZCAwKTticmVhaztkZWZhdWx0OnRoaXMubm9kZVZhbHVlPWF9fX19KTtEKE5vZGUucHJvdG90eXBlLCJhcHBlbmRDaGlsZCBpbnNlcnRCZWZvcmUgcmVtb3ZlQ2hpbGQgcmVwbGFjZUNoaWxkIGNsb25lTm9kZSBjb250YWlucyIuc3BsaXQoIiAiKSk7CmE9e2ZpcnN0RWxlbWVudENoaWxkOntnZXQ6ZnVuY3Rpb24oKXtGLmN1cnJlbnROb2RlPXRoaXM7cmV0dXJuIEYuZmlyc3RDaGlsZCgpfX0sbGFzdEVsZW1lbnRDaGlsZDp7Z2V0OmZ1bmN0aW9uKCl7Ri5jdXJyZW50Tm9kZT10aGlzO3JldHVybiBGLmxhc3RDaGlsZCgpfX0sY2hpbGRyZW46e2dldDpmdW5jdGlvbigpe3ZhciBhPVtdO0YuY3VycmVudE5vZGU9dGhpcztmb3IodmFyIGM9Ri5maXJzdENoaWxkKCk7YzspYS5wdXNoKGMpLGM9Ri5uZXh0U2libGluZygpO3JldHVybiBWYShhKX19LGNoaWxkRWxlbWVudENvdW50OntnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5jaGlsZHJlbj90aGlzLmNoaWxkcmVuLmxlbmd0aDowfX19O3BiPyhEKEVsZW1lbnQucHJvdG90eXBlLHdiKSxEKEVsZW1lbnQucHJvdG90eXBlLFsicHJldmlvdXNFbGVtZW50U2libGluZyIsIm5leHRFbGVtZW50U2libGluZyIsImlubmVySFRNTCJdKSxPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKEhUTUxFbGVtZW50LnByb3RvdHlwZSwKImNoaWxkcmVuIikmJkQoSFRNTEVsZW1lbnQucHJvdG90eXBlLFsiY2hpbGRyZW4iXSksT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihIVE1MRWxlbWVudC5wcm90b3R5cGUsImlubmVySFRNTCIpJiZEKEhUTUxFbGVtZW50LnByb3RvdHlwZSxbImlubmVySFRNTCJdKSk6KHRiKEVsZW1lbnQucHJvdG90eXBlLGEpLHRiKEVsZW1lbnQucHJvdG90eXBlLHtwcmV2aW91c0VsZW1lbnRTaWJsaW5nOntnZXQ6ZnVuY3Rpb24oKXtGLmN1cnJlbnROb2RlPXRoaXM7cmV0dXJuIEYucHJldmlvdXNTaWJsaW5nKCl9fSxuZXh0RWxlbWVudFNpYmxpbmc6e2dldDpmdW5jdGlvbigpe0YuY3VycmVudE5vZGU9dGhpcztyZXR1cm4gRi5uZXh0U2libGluZygpfX0saW5uZXJIVE1MOntnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4ga2IodGhpcyxmdW5jdGlvbihhKXtyZXR1cm4gYS5fX3NoYWR5X25hdGl2ZV9jaGlsZE5vZGVzfSl9LHNldDpmdW5jdGlvbihhKXt2YXIgYj0idGVtcGxhdGUiPT09dGhpcy5sb2NhbE5hbWU/CnRoaXMuY29udGVudDp0aGlzO3ZiKGIpO3ZhciBkPXRoaXMubG9jYWxOYW1lfHwiZGl2IjtkPXRoaXMubmFtZXNwYWNlVVJJJiZ0aGlzLm5hbWVzcGFjZVVSSSE9PXViLm5hbWVzcGFjZVVSST91Yi5jcmVhdGVFbGVtZW50TlModGhpcy5uYW1lc3BhY2VVUkksZCk6dWIuY3JlYXRlRWxlbWVudChkKTtkLmlubmVySFRNTD1hO2ZvcihhPSJ0ZW1wbGF0ZSI9PT10aGlzLmxvY2FsTmFtZT9kLmNvbnRlbnQ6ZDtkPWEuX19zaGFkeV9uYXRpdmVfZmlyc3RDaGlsZDspYi5fX3NoYWR5X25hdGl2ZV9pbnNlcnRCZWZvcmUoZCx2b2lkIDApfX19KSk7RChFbGVtZW50LnByb3RvdHlwZSwic2V0QXR0cmlidXRlIGdldEF0dHJpYnV0ZSBoYXNBdHRyaWJ1dGUgcmVtb3ZlQXR0cmlidXRlIGZvY3VzIGJsdXIiLnNwbGl0KCIgIikpO0QoRWxlbWVudC5wcm90b3R5cGUseGIpO0QoSFRNTEVsZW1lbnQucHJvdG90eXBlLFsiZm9jdXMiLCJibHVyIiwiY29udGFpbnMiXSk7cGImJkQoSFRNTEVsZW1lbnQucHJvdG90eXBlLApbInBhcmVudEVsZW1lbnQiLCJjaGlsZHJlbiIsImlubmVySFRNTCJdKTt3aW5kb3cuSFRNTFRlbXBsYXRlRWxlbWVudCYmRCh3aW5kb3cuSFRNTFRlbXBsYXRlRWxlbWVudC5wcm90b3R5cGUsWyJpbm5lckhUTUwiXSk7cGI/RChEb2N1bWVudEZyYWdtZW50LnByb3RvdHlwZSx3Yik6dGIoRG9jdW1lbnRGcmFnbWVudC5wcm90b3R5cGUsYSk7RChEb2N1bWVudEZyYWdtZW50LnByb3RvdHlwZSx4Yik7cGI/KEQoRG9jdW1lbnQucHJvdG90eXBlLHdiKSxEKERvY3VtZW50LnByb3RvdHlwZSxbImFjdGl2ZUVsZW1lbnQiXSkpOnRiKERvY3VtZW50LnByb3RvdHlwZSxhKTtEKERvY3VtZW50LnByb3RvdHlwZSxbImltcG9ydE5vZGUiLCJnZXRFbGVtZW50QnlJZCJdKTtEKERvY3VtZW50LnByb3RvdHlwZSx4Yil9O3ZhciB6Yj1CKHtnZXQgY2hpbGROb2Rlcygpe3JldHVybiB0aGlzLl9fc2hhZHlfY2hpbGROb2Rlc30sZ2V0IGZpcnN0Q2hpbGQoKXtyZXR1cm4gdGhpcy5fX3NoYWR5X2ZpcnN0Q2hpbGR9LGdldCBsYXN0Q2hpbGQoKXtyZXR1cm4gdGhpcy5fX3NoYWR5X2xhc3RDaGlsZH0sZ2V0IHRleHRDb250ZW50KCl7cmV0dXJuIHRoaXMuX19zaGFkeV90ZXh0Q29udGVudH0sc2V0IHRleHRDb250ZW50KGEpe3RoaXMuX19zaGFkeV90ZXh0Q29udGVudD1hfSxnZXQgY2hpbGRFbGVtZW50Q291bnQoKXtyZXR1cm4gdGhpcy5fX3NoYWR5X2NoaWxkRWxlbWVudENvdW50fSxnZXQgY2hpbGRyZW4oKXtyZXR1cm4gdGhpcy5fX3NoYWR5X2NoaWxkcmVufSxnZXQgZmlyc3RFbGVtZW50Q2hpbGQoKXtyZXR1cm4gdGhpcy5fX3NoYWR5X2ZpcnN0RWxlbWVudENoaWxkfSxnZXQgbGFzdEVsZW1lbnRDaGlsZCgpe3JldHVybiB0aGlzLl9fc2hhZHlfbGFzdEVsZW1lbnRDaGlsZH0sZ2V0IGlubmVySFRNTCgpe3JldHVybiB0aGlzLl9fc2hhZHlfaW5uZXJIVE1MfSwKc2V0IGlubmVySFRNTChhKXtyZXR1cm4gdGhpcy5fX3NoYWR5X2lubmVySFRNTD1hfSxnZXQgc2hhZG93Um9vdCgpe3JldHVybiB0aGlzLl9fc2hhZHlfc2hhZG93Um9vdH19KSxBYj1CKHtnZXQgcGFyZW50RWxlbWVudCgpe3JldHVybiB0aGlzLl9fc2hhZHlfcGFyZW50RWxlbWVudH0sZ2V0IHBhcmVudE5vZGUoKXtyZXR1cm4gdGhpcy5fX3NoYWR5X3BhcmVudE5vZGV9LGdldCBuZXh0U2libGluZygpe3JldHVybiB0aGlzLl9fc2hhZHlfbmV4dFNpYmxpbmd9LGdldCBwcmV2aW91c1NpYmxpbmcoKXtyZXR1cm4gdGhpcy5fX3NoYWR5X3ByZXZpb3VzU2libGluZ30sZ2V0IG5leHRFbGVtZW50U2libGluZygpe3JldHVybiB0aGlzLl9fc2hhZHlfbmV4dEVsZW1lbnRTaWJsaW5nfSxnZXQgcHJldmlvdXNFbGVtZW50U2libGluZygpe3JldHVybiB0aGlzLl9fc2hhZHlfcHJldmlvdXNFbGVtZW50U2libGluZ30sZ2V0IGNsYXNzTmFtZSgpe3JldHVybiB0aGlzLl9fc2hhZHlfY2xhc3NOYW1lfSwKc2V0IGNsYXNzTmFtZShhKXtyZXR1cm4gdGhpcy5fX3NoYWR5X2NsYXNzTmFtZT1hfX0pLEJiO2ZvcihCYiBpbiB6Yil6YltCYl0uZW51bWVyYWJsZT0hMTtmb3IodmFyIENiIGluIEFiKUFiW0NiXS5lbnVtZXJhYmxlPSExO3ZhciBEYj13Lm18fHcuSixFYj1EYj9mdW5jdGlvbigpe306ZnVuY3Rpb24oYSl7dmFyIGI9dShhKTtiLmxhfHwoYi5sYT0hMCxBKGEsQWIpKX0sRmI9RGI/ZnVuY3Rpb24oKXt9OmZ1bmN0aW9uKGEpe3ZhciBiPXUoYSk7Yi5rYXx8KGIua2E9ITAsQShhLHpiKSl9O3ZhciBHYj0iX19ldmVudFdyYXBwZXJzIitEYXRlLm5vdygpLEhiPWZ1bmN0aW9uKCl7dmFyIGE9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihFdmVudC5wcm90b3R5cGUsImNvbXBvc2VkIik7cmV0dXJuIGE/ZnVuY3Rpb24oYil7cmV0dXJuIGEuZ2V0LmNhbGwoYil9Om51bGx9KCksSWI9e2JsdXI6ITAsZm9jdXM6ITAsZm9jdXNpbjohMCxmb2N1c291dDohMCxjbGljazohMCxkYmxjbGljazohMCxtb3VzZWRvd246ITAsbW91c2VlbnRlcjohMCxtb3VzZWxlYXZlOiEwLG1vdXNlbW92ZTohMCxtb3VzZW91dDohMCxtb3VzZW92ZXI6ITAsbW91c2V1cDohMCx3aGVlbDohMCxiZWZvcmVpbnB1dDohMCxpbnB1dDohMCxrZXlkb3duOiEwLGtleXVwOiEwLGNvbXBvc2l0aW9uc3RhcnQ6ITAsY29tcG9zaXRpb251cGRhdGU6ITAsY29tcG9zaXRpb25lbmQ6ITAsdG91Y2hzdGFydDohMCx0b3VjaGVuZDohMCx0b3VjaG1vdmU6ITAsdG91Y2hjYW5jZWw6ITAscG9pbnRlcm92ZXI6ITAsCnBvaW50ZXJlbnRlcjohMCxwb2ludGVyZG93bjohMCxwb2ludGVybW92ZTohMCxwb2ludGVydXA6ITAscG9pbnRlcmNhbmNlbDohMCxwb2ludGVyb3V0OiEwLHBvaW50ZXJsZWF2ZTohMCxnb3Rwb2ludGVyY2FwdHVyZTohMCxsb3N0cG9pbnRlcmNhcHR1cmU6ITAsZHJhZ3N0YXJ0OiEwLGRyYWc6ITAsZHJhZ2VudGVyOiEwLGRyYWdsZWF2ZTohMCxkcmFnb3ZlcjohMCxkcm9wOiEwLGRyYWdlbmQ6ITAsRE9NQWN0aXZhdGU6ITAsRE9NRm9jdXNJbjohMCxET01Gb2N1c091dDohMCxrZXlwcmVzczohMH0sSmI9e0RPTUF0dHJNb2RpZmllZDohMCxET01BdHRyaWJ1dGVOYW1lQ2hhbmdlZDohMCxET01DaGFyYWN0ZXJEYXRhTW9kaWZpZWQ6ITAsRE9NRWxlbWVudE5hbWVDaGFuZ2VkOiEwLERPTU5vZGVJbnNlcnRlZDohMCxET01Ob2RlSW5zZXJ0ZWRJbnRvRG9jdW1lbnQ6ITAsRE9NTm9kZVJlbW92ZWQ6ITAsRE9NTm9kZVJlbW92ZWRGcm9tRG9jdW1lbnQ6ITAsRE9NU3VidHJlZU1vZGlmaWVkOiEwfTsKZnVuY3Rpb24gS2IoYSl7cmV0dXJuIGEgaW5zdGFuY2VvZiBOb2RlP2EuX19zaGFkeV9nZXRSb290Tm9kZSgpOmF9ZnVuY3Rpb24gTGIoYSxiKXt2YXIgYz1bXSxkPWE7Zm9yKGE9S2IoYSk7ZDspYy5wdXNoKGQpLGQuX19zaGFkeV9hc3NpZ25lZFNsb3Q/ZD1kLl9fc2hhZHlfYXNzaWduZWRTbG90OmQubm9kZVR5cGU9PT1Ob2RlLkRPQ1VNRU5UX0ZSQUdNRU5UX05PREUmJmQuaG9zdCYmKGJ8fGQhPT1hKT9kPWQuaG9zdDpkPWQuX19zaGFkeV9wYXJlbnROb2RlO2NbYy5sZW5ndGgtMV09PT1kb2N1bWVudCYmYy5wdXNoKHdpbmRvdyk7cmV0dXJuIGN9ZnVuY3Rpb24gTWIoYSl7YS5fX2NvbXBvc2VkUGF0aHx8KGEuX19jb21wb3NlZFBhdGg9TGIoYS50YXJnZXQsITApKTtyZXR1cm4gYS5fX2NvbXBvc2VkUGF0aH0KZnVuY3Rpb24gTmIoYSxiKXtpZigheilyZXR1cm4gYTthPUxiKGEsITApO2Zvcih2YXIgYz0wLGQsZT12b2lkIDAsZixnPXZvaWQgMDtjPGIubGVuZ3RoO2MrKylpZihkPWJbY10sZj1LYihkKSxmIT09ZSYmKGc9YS5pbmRleE9mKGYpLGU9ZiksIXooZil8fC0xPGcpcmV0dXJuIGR9ZnVuY3Rpb24gT2IoYSl7ZnVuY3Rpb24gYihiLGQpe2I9bmV3IGEoYixkKTtiLl9fY29tcG9zZWQ9ZCYmISFkLmNvbXBvc2VkO3JldHVybiBifWIuX19wcm90b19fPWE7Yi5wcm90b3R5cGU9YS5wcm90b3R5cGU7cmV0dXJuIGJ9dmFyIFBiPXtmb2N1czohMCxibHVyOiEwfTtmdW5jdGlvbiBRYihhKXtyZXR1cm4gYS5fX3RhcmdldCE9PWEudGFyZ2V0fHxhLl9fcmVsYXRlZFRhcmdldCE9PWEucmVsYXRlZFRhcmdldH0KZnVuY3Rpb24gUmIoYSxiLGMpe2lmKGM9Yi5fX2hhbmRsZXJzJiZiLl9faGFuZGxlcnNbYS50eXBlXSYmYi5fX2hhbmRsZXJzW2EudHlwZV1bY10pZm9yKHZhciBkPTAsZTsoZT1jW2RdKSYmKCFRYihhKXx8YS50YXJnZXQhPT1hLnJlbGF0ZWRUYXJnZXQpJiYoZS5jYWxsKGIsYSksIWEuX19pbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQpO2QrKyk7fQpmdW5jdGlvbiBTYihhKXt2YXIgYj1hLmNvbXBvc2VkUGF0aCgpO09iamVjdC5kZWZpbmVQcm9wZXJ0eShhLCJjdXJyZW50VGFyZ2V0Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGR9LGNvbmZpZ3VyYWJsZTohMH0pO2Zvcih2YXIgYz1iLmxlbmd0aC0xOzA8PWM7Yy0tKXt2YXIgZD1iW2NdO1JiKGEsZCwiY2FwdHVyZSIpO2lmKGEuWilyZXR1cm59T2JqZWN0LmRlZmluZVByb3BlcnR5KGEsImV2ZW50UGhhc2UiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gRXZlbnQuQVRfVEFSR0VUfX0pO3ZhciBlO2ZvcihjPTA7YzxiLmxlbmd0aDtjKyspe2Q9YltjXTt2YXIgZj12KGQpO2Y9ZiYmZi5yb290O2lmKDA9PT1jfHxmJiZmPT09ZSlpZihSYihhLGQsImJ1YmJsZSIpLGQhPT13aW5kb3cmJihlPWQuX19zaGFkeV9nZXRSb290Tm9kZSgpKSxhLlopYnJlYWt9fQpmdW5jdGlvbiBUYihhLGIsYyxkLGUsZil7Zm9yKHZhciBnPTA7ZzxhLmxlbmd0aDtnKyspe3ZhciBoPWFbZ10saz1oLnR5cGUsbD1oLmNhcHR1cmUsbT1oLm9uY2UscT1oLnBhc3NpdmU7aWYoYj09PWgubm9kZSYmYz09PWsmJmQ9PT1sJiZlPT09bSYmZj09PXEpcmV0dXJuIGd9cmV0dXJuLTF9CmZ1bmN0aW9uIFViKGEsYixjKXtpZihiKXt2YXIgZD10eXBlb2YgYjtpZigiZnVuY3Rpb24iPT09ZHx8Im9iamVjdCI9PT1kKWlmKCJvYmplY3QiIT09ZHx8Yi5oYW5kbGVFdmVudCYmImZ1bmN0aW9uIj09PXR5cGVvZiBiLmhhbmRsZUV2ZW50KXtpZihKYlthXSlyZXR1cm4gdGhpcy5fX3NoYWR5X25hdGl2ZV9hZGRFdmVudExpc3RlbmVyKGEsYixjKTtpZihjJiYib2JqZWN0Ij09PXR5cGVvZiBjKXt2YXIgZT0hIWMuY2FwdHVyZTt2YXIgZj0hIWMub25jZTt2YXIgZz0hIWMucGFzc2l2ZX1lbHNlIGU9ISFjLGc9Zj0hMTt2YXIgaD1jJiZjLiR8fHRoaXMsaz1iW0diXTtpZihrKXtpZigtMTxUYihrLGgsYSxlLGYsZykpcmV0dXJufWVsc2UgYltHYl09W107az1mdW5jdGlvbihlKXtmJiZ0aGlzLl9fc2hhZHlfcmVtb3ZlRXZlbnRMaXN0ZW5lcihhLGIsYyk7ZS5fX3RhcmdldHx8VmIoZSk7aWYoaCE9PXRoaXMpe3ZhciBnPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoZSwiY3VycmVudFRhcmdldCIpOwpPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwiY3VycmVudFRhcmdldCIse2dldDpmdW5jdGlvbigpe3JldHVybiBofSxjb25maWd1cmFibGU6ITB9KX1lLl9fcHJldmlvdXNDdXJyZW50VGFyZ2V0PWUuY3VycmVudFRhcmdldDtpZigheihoKXx8LTEhPWUuY29tcG9zZWRQYXRoKCkuaW5kZXhPZihoKSlpZihlLmNvbXBvc2VkfHwtMTxlLmNvbXBvc2VkUGF0aCgpLmluZGV4T2YoaCkpaWYoUWIoZSkmJmUudGFyZ2V0PT09ZS5yZWxhdGVkVGFyZ2V0KWUuZXZlbnRQaGFzZT09PUV2ZW50LkJVQkJMSU5HX1BIQVNFJiZlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpO2Vsc2UgaWYoZS5ldmVudFBoYXNlPT09RXZlbnQuQ0FQVFVSSU5HX1BIQVNFfHxlLmJ1YmJsZXN8fGUudGFyZ2V0PT09aHx8aCBpbnN0YW5jZW9mIFdpbmRvdyl7dmFyIGs9ImZ1bmN0aW9uIj09PWQ/Yi5jYWxsKGgsZSk6Yi5oYW5kbGVFdmVudCYmYi5oYW5kbGVFdmVudChlKTtoIT09dGhpcyYmKGc/KE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLAoiY3VycmVudFRhcmdldCIsZyksZz1udWxsKTpkZWxldGUgZS5jdXJyZW50VGFyZ2V0KTtyZXR1cm4ga319O2JbR2JdLnB1c2goe25vZGU6aCx0eXBlOmEsY2FwdHVyZTplLG9uY2U6ZixwYXNzaXZlOmcsWWE6a30pO1BiW2FdPyh0aGlzLl9faGFuZGxlcnM9dGhpcy5fX2hhbmRsZXJzfHx7fSx0aGlzLl9faGFuZGxlcnNbYV09dGhpcy5fX2hhbmRsZXJzW2FdfHx7Y2FwdHVyZTpbXSxidWJibGU6W119LHRoaXMuX19oYW5kbGVyc1thXVtlPyJjYXB0dXJlIjoiYnViYmxlIl0ucHVzaChrKSk6dGhpcy5fX3NoYWR5X25hdGl2ZV9hZGRFdmVudExpc3RlbmVyKGEsayxjKX19fQpmdW5jdGlvbiBXYihhLGIsYyl7aWYoYil7aWYoSmJbYV0pcmV0dXJuIHRoaXMuX19zaGFkeV9uYXRpdmVfcmVtb3ZlRXZlbnRMaXN0ZW5lcihhLGIsYyk7aWYoYyYmIm9iamVjdCI9PT10eXBlb2YgYyl7dmFyIGQ9ISFjLmNhcHR1cmU7dmFyIGU9ISFjLm9uY2U7dmFyIGY9ISFjLnBhc3NpdmV9ZWxzZSBkPSEhYyxmPWU9ITE7dmFyIGc9YyYmYy4kfHx0aGlzLGg9dm9pZCAwO3ZhciBrPW51bGw7dHJ5e2s9YltHYl19Y2F0Y2gobCl7fWsmJihlPVRiKGssZyxhLGQsZSxmKSwtMTxlJiYoaD1rLnNwbGljZShlLDEpWzBdLllhLGsubGVuZ3RofHwoYltHYl09dm9pZCAwKSkpO3RoaXMuX19zaGFkeV9uYXRpdmVfcmVtb3ZlRXZlbnRMaXN0ZW5lcihhLGh8fGIsYyk7aCYmUGJbYV0mJnRoaXMuX19oYW5kbGVycyYmdGhpcy5fX2hhbmRsZXJzW2FdJiYoYT10aGlzLl9faGFuZGxlcnNbYV1bZD8iY2FwdHVyZSI6ImJ1YmJsZSJdLGg9YS5pbmRleE9mKGgpLC0xPGgmJmEuc3BsaWNlKGgsMSkpfX0KZnVuY3Rpb24gWGIoKXtmb3IodmFyIGEgaW4gUGIpd2luZG93Ll9fc2hhZHlfbmF0aXZlX2FkZEV2ZW50TGlzdGVuZXIoYSxmdW5jdGlvbihhKXthLl9fdGFyZ2V0fHwoVmIoYSksU2IoYSkpfSwhMCl9CnZhciBZYj1CKHtnZXQgY29tcG9zZWQoKXt2b2lkIDA9PT10aGlzLl9fY29tcG9zZWQmJihIYj90aGlzLl9fY29tcG9zZWQ9ImZvY3VzaW4iPT09dGhpcy50eXBlfHwiZm9jdXNvdXQiPT09dGhpcy50eXBlfHxIYih0aGlzKTohMSE9PXRoaXMuaXNUcnVzdGVkJiYodGhpcy5fX2NvbXBvc2VkPUliW3RoaXMudHlwZV0pKTtyZXR1cm4gdGhpcy5fX2NvbXBvc2VkfHwhMX0sY29tcG9zZWRQYXRoOmZ1bmN0aW9uKCl7dGhpcy5fX2NvbXBvc2VkUGF0aHx8KHRoaXMuX19jb21wb3NlZFBhdGg9TGIodGhpcy5fX3RhcmdldCx0aGlzLmNvbXBvc2VkKSk7cmV0dXJuIHRoaXMuX19jb21wb3NlZFBhdGh9LGdldCB0YXJnZXQoKXtyZXR1cm4gTmIodGhpcy5jdXJyZW50VGFyZ2V0fHx0aGlzLl9fcHJldmlvdXNDdXJyZW50VGFyZ2V0LHRoaXMuY29tcG9zZWRQYXRoKCkpfSxnZXQgcmVsYXRlZFRhcmdldCgpe2lmKCF0aGlzLl9fcmVsYXRlZFRhcmdldClyZXR1cm4gbnVsbDt0aGlzLl9fcmVsYXRlZFRhcmdldENvbXBvc2VkUGF0aHx8Cih0aGlzLl9fcmVsYXRlZFRhcmdldENvbXBvc2VkUGF0aD1MYih0aGlzLl9fcmVsYXRlZFRhcmdldCwhMCkpO3JldHVybiBOYih0aGlzLmN1cnJlbnRUYXJnZXR8fHRoaXMuX19wcmV2aW91c0N1cnJlbnRUYXJnZXQsdGhpcy5fX3JlbGF0ZWRUYXJnZXRDb21wb3NlZFBhdGgpfSxzdG9wUHJvcGFnYXRpb246ZnVuY3Rpb24oKXtFdmVudC5wcm90b3R5cGUuc3RvcFByb3BhZ2F0aW9uLmNhbGwodGhpcyk7dGhpcy5aPSEwfSxzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb246ZnVuY3Rpb24oKXtFdmVudC5wcm90b3R5cGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uLmNhbGwodGhpcyk7dGhpcy5aPXRoaXMuX19pbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQ9ITB9fSk7CmZ1bmN0aW9uIFZiKGEpe2EuX190YXJnZXQ9YS50YXJnZXQ7YS5fX3JlbGF0ZWRUYXJnZXQ9YS5yZWxhdGVkVGFyZ2V0O2lmKHcubSl7dmFyIGI9T2JqZWN0LmdldFByb3RvdHlwZU9mKGEpO2lmKCFPYmplY3QuaGFzT3duUHJvcGVydHkoYiwiX19zaGFkeV9wYXRjaGVkUHJvdG8iKSl7dmFyIGM9T2JqZWN0LmNyZWF0ZShiKTtjLl9fc2hhZHlfc291cmNlUHJvdG89YjtBKGMsWWIpO2IuX19zaGFkeV9wYXRjaGVkUHJvdG89Y31hLl9fcHJvdG9fXz1iLl9fc2hhZHlfcGF0Y2hlZFByb3RvfWVsc2UgQShhLFliKX12YXIgWmI9T2IoRXZlbnQpLCRiPU9iKEN1c3RvbUV2ZW50KSxhYz1PYihNb3VzZUV2ZW50KTsKZnVuY3Rpb24gYmMoKXtpZighSGImJk9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoRXZlbnQucHJvdG90eXBlLCJpc1RydXN0ZWQiKSl7dmFyIGE9ZnVuY3Rpb24oKXt2YXIgYT1uZXcgTW91c2VFdmVudCgiY2xpY2siLHtidWJibGVzOiEwLGNhbmNlbGFibGU6ITAsY29tcG9zZWQ6ITB9KTt0aGlzLl9fc2hhZHlfZGlzcGF0Y2hFdmVudChhKX07RWxlbWVudC5wcm90b3R5cGUuY2xpY2s/RWxlbWVudC5wcm90b3R5cGUuY2xpY2s9YTpIVE1MRWxlbWVudC5wcm90b3R5cGUuY2xpY2smJihIVE1MRWxlbWVudC5wcm90b3R5cGUuY2xpY2s9YSl9fXZhciBjYz1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhEb2N1bWVudC5wcm90b3R5cGUpLmZpbHRlcihmdW5jdGlvbihhKXtyZXR1cm4ib24iPT09YS5zdWJzdHJpbmcoMCwyKX0pO2Z1bmN0aW9uIGRjKGEsYil7cmV0dXJue2luZGV4OmEsTDpbXSxSOmJ9fQpmdW5jdGlvbiBlYyhhLGIsYyxkKXt2YXIgZT0wLGY9MCxnPTAsaD0wLGs9TWF0aC5taW4oYi1lLGQtZik7aWYoMD09ZSYmMD09ZilhOntmb3IoZz0wO2c8aztnKyspaWYoYVtnXSE9PWNbZ10pYnJlYWsgYTtnPWt9aWYoYj09YS5sZW5ndGgmJmQ9PWMubGVuZ3RoKXtoPWEubGVuZ3RoO2Zvcih2YXIgbD1jLmxlbmd0aCxtPTA7bTxrLWcmJmZjKGFbLS1oXSxjWy0tbF0pOyltKys7aD1tfWUrPWc7Zis9ZztiLT1oO2QtPWg7aWYoMD09Yi1lJiYwPT1kLWYpcmV0dXJuW107aWYoZT09Yil7Zm9yKGI9ZGMoZSwwKTtmPGQ7KWIuTC5wdXNoKGNbZisrXSk7cmV0dXJuW2JdfWlmKGY9PWQpcmV0dXJuW2RjKGUsYi1lKV07az1lO2c9ZjtkPWQtZysxO2g9Yi1rKzE7Yj1BcnJheShkKTtmb3IobD0wO2w8ZDtsKyspYltsXT1BcnJheShoKSxiW2xdWzBdPWw7Zm9yKGw9MDtsPGg7bCsrKWJbMF1bbF09bDtmb3IobD0xO2w8ZDtsKyspZm9yKG09MTttPGg7bSsrKWlmKGFbayttLTFdPT09Y1tnK2wtMV0pYltsXVttXT0KYltsLTFdW20tMV07ZWxzZXt2YXIgcT1iW2wtMV1bbV0rMSx4PWJbbF1bbS0xXSsxO2JbbF1bbV09cTx4P3E6eH1rPWIubGVuZ3RoLTE7Zz1iWzBdLmxlbmd0aC0xO2Q9YltrXVtnXTtmb3IoYT1bXTswPGt8fDA8ZzspMD09az8oYS5wdXNoKDIpLGctLSk6MD09Zz8oYS5wdXNoKDMpLGstLSk6KGg9YltrLTFdW2ctMV0sbD1iW2stMV1bZ10sbT1iW2tdW2ctMV0scT1sPG0/bDxoP2w6aDptPGg/bTpoLHE9PWg/KGg9PWQ/YS5wdXNoKDApOihhLnB1c2goMSksZD1oKSxrLS0sZy0tKTpxPT1sPyhhLnB1c2goMyksay0tLGQ9bCk6KGEucHVzaCgyKSxnLS0sZD1tKSk7YS5yZXZlcnNlKCk7Yj12b2lkIDA7az1bXTtmb3IoZz0wO2c8YS5sZW5ndGg7ZysrKXN3aXRjaChhW2ddKXtjYXNlIDA6YiYmKGsucHVzaChiKSxiPXZvaWQgMCk7ZSsrO2YrKzticmVhaztjYXNlIDE6Ynx8KGI9ZGMoZSwwKSk7Yi5SKys7ZSsrO2IuTC5wdXNoKGNbZl0pO2YrKzticmVhaztjYXNlIDI6Ynx8KGI9ZGMoZSwwKSk7CmIuUisrO2UrKzticmVhaztjYXNlIDM6Ynx8KGI9ZGMoZSwwKSksYi5MLnB1c2goY1tmXSksZisrfWImJmsucHVzaChiKTtyZXR1cm4ga31mdW5jdGlvbiBmYyhhLGIpe3JldHVybiBhPT09Yn07ZnVuY3Rpb24gZ2MoYSxiLGMpe0ViKGEpO2M9Y3x8bnVsbDt2YXIgZD11KGEpLGU9dShiKSxmPWM/dShjKTpudWxsO2QucHJldmlvdXNTaWJsaW5nPWM/Zi5wcmV2aW91c1NpYmxpbmc6Yi5fX3NoYWR5X2xhc3RDaGlsZDtpZihmPXYoZC5wcmV2aW91c1NpYmxpbmcpKWYubmV4dFNpYmxpbmc9YTtpZihmPXYoZC5uZXh0U2libGluZz1jKSlmLnByZXZpb3VzU2libGluZz1hO2QucGFyZW50Tm9kZT1iO2M/Yz09PWUuZmlyc3RDaGlsZCYmKGUuZmlyc3RDaGlsZD1hKTooZS5sYXN0Q2hpbGQ9YSxlLmZpcnN0Q2hpbGR8fChlLmZpcnN0Q2hpbGQ9YSkpO2UuY2hpbGROb2Rlcz1udWxsfQpmdW5jdGlvbiBoYyhhLGIsYyl7RmIoYik7dmFyIGQ9dShiKTt2b2lkIDAhPT1kLmZpcnN0Q2hpbGQmJihkLmNoaWxkTm9kZXM9bnVsbCk7aWYoYS5ub2RlVHlwZT09PU5vZGUuRE9DVU1FTlRfRlJBR01FTlRfTk9ERSl7ZD1hLl9fc2hhZHlfY2hpbGROb2Rlcztmb3IodmFyIGU9MDtlPGQubGVuZ3RoO2UrKylnYyhkW2VdLGIsYyk7YT11KGEpO2I9dm9pZCAwIT09YS5maXJzdENoaWxkP251bGw6dm9pZCAwO2EuZmlyc3RDaGlsZD1hLmxhc3RDaGlsZD1iO2EuY2hpbGROb2Rlcz1ifWVsc2UgZ2MoYSxiLGMpfQpmdW5jdGlvbiBpYyhhLGIpe3ZhciBjPXUoYSk7Yj11KGIpO2E9PT1iLmZpcnN0Q2hpbGQmJihiLmZpcnN0Q2hpbGQ9Yy5uZXh0U2libGluZyk7YT09PWIubGFzdENoaWxkJiYoYi5sYXN0Q2hpbGQ9Yy5wcmV2aW91c1NpYmxpbmcpO2E9Yy5wcmV2aW91c1NpYmxpbmc7dmFyIGQ9Yy5uZXh0U2libGluZzthJiYodShhKS5uZXh0U2libGluZz1kKTtkJiYodShkKS5wcmV2aW91c1NpYmxpbmc9YSk7Yy5wYXJlbnROb2RlPWMucHJldmlvdXNTaWJsaW5nPWMubmV4dFNpYmxpbmc9dm9pZCAwO3ZvaWQgMCE9PWIuY2hpbGROb2RlcyYmKGIuY2hpbGROb2Rlcz1udWxsKX0KZnVuY3Rpb24gamMoYSl7dmFyIGI9dShhKTtpZih2b2lkIDA9PT1iLmZpcnN0Q2hpbGQpe2IuY2hpbGROb2Rlcz1udWxsO3ZhciBjPWIuZmlyc3RDaGlsZD1hLl9fc2hhZHlfbmF0aXZlX2ZpcnN0Q2hpbGR8fG51bGw7Yi5sYXN0Q2hpbGQ9YS5fX3NoYWR5X25hdGl2ZV9sYXN0Q2hpbGR8fG51bGw7RmIoYSk7Yj1jO2ZvcihjPXZvaWQgMDtiO2I9Yi5fX3NoYWR5X25hdGl2ZV9uZXh0U2libGluZyl7dmFyIGQ9dShiKTtkLnBhcmVudE5vZGU9YTtkLm5leHRTaWJsaW5nPWIuX19zaGFkeV9uYXRpdmVfbmV4dFNpYmxpbmd8fG51bGw7ZC5wcmV2aW91c1NpYmxpbmc9Y3x8bnVsbDtjPWI7RWIoYil9fX07dmFyIGtjPW51bGw7ZnVuY3Rpb24gRygpe2tjfHwoa2M9d2luZG93LlNoYWR5Q1NTJiZ3aW5kb3cuU2hhZHlDU1MuU2NvcGluZ1NoaW0pO3JldHVybiBrY3x8bnVsbH1mdW5jdGlvbiBsYyhhLGIpe3ZhciBjPUcoKTtjJiZjLnVuc2NvcGVOb2RlKGEsYil9ZnVuY3Rpb24gbWMoYSxiKXt2YXIgYz1HKCk7aWYoIWMpcmV0dXJuITA7aWYoYS5ub2RlVHlwZT09PU5vZGUuRE9DVU1FTlRfRlJBR01FTlRfTk9ERSl7Yz0hMDthPWEuX19zaGFkeV9jaGlsZE5vZGVzO2Zvcih2YXIgZD0wO2MmJmQ8YS5sZW5ndGg7ZCsrKWM9YyYmbWMoYVtkXSxiKTtyZXR1cm4gY31yZXR1cm4gYS5ub2RlVHlwZSE9PU5vZGUuRUxFTUVOVF9OT0RFPyEwOmMuY3VycmVudFNjb3BlRm9yTm9kZShhKT09PWJ9ZnVuY3Rpb24gbmMoYSl7aWYoYS5ub2RlVHlwZSE9PU5vZGUuRUxFTUVOVF9OT0RFKXJldHVybiIiO3ZhciBiPUcoKTtyZXR1cm4gYj9iLmN1cnJlbnRTY29wZUZvck5vZGUoYSk6IiJ9CmZ1bmN0aW9uIG9jKGEsYil7aWYoYSl7YS5ub2RlVHlwZT09PU5vZGUuRUxFTUVOVF9OT0RFJiZiKGEpO2E9YS5fX3NoYWR5X2NoaWxkTm9kZXM7Zm9yKHZhciBjPTAsZDtjPGEubGVuZ3RoO2MrKylkPWFbY10sZC5ub2RlVHlwZT09PU5vZGUuRUxFTUVOVF9OT0RFJiZvYyhkLGIpfX07dmFyIHBjPXdpbmRvdy5kb2N1bWVudCxxYz13Lm9hLHJjPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoTm9kZS5wcm90b3R5cGUsImlzQ29ubmVjdGVkIiksc2M9cmMmJnJjLmdldDtmdW5jdGlvbiB0YyhhKXtmb3IodmFyIGI7Yj1hLl9fc2hhZHlfZmlyc3RDaGlsZDspYS5fX3NoYWR5X3JlbW92ZUNoaWxkKGIpfWZ1bmN0aW9uIHVjKGEpe3ZhciBiPXYoYSk7aWYoYiYmdm9pZCAwIT09Yi5LKXtiPWEuX19zaGFkeV9jaGlsZE5vZGVzO2Zvcih2YXIgYz0wLGQ9Yi5sZW5ndGgsZT12b2lkIDA7YzxkJiYoZT1iW2NdKTtjKyspdWMoZSl9aWYoYT12KGEpKWEuSz12b2lkIDB9ZnVuY3Rpb24gdmMoYSl7dmFyIGI9YTthJiYic2xvdCI9PT1hLmxvY2FsTmFtZSYmKGI9KGI9KGI9dihhKSkmJmIuRCkmJmIubGVuZ3RoP2JbMF06dmMoYS5fX3NoYWR5X25leHRTaWJsaW5nKSk7cmV0dXJuIGJ9CmZ1bmN0aW9uIHdjKGEsYixjKXtpZihhPShhPXYoYSkpJiZhLkgpYiYmYS5hZGRlZE5vZGVzLnB1c2goYiksYyYmYS5yZW1vdmVkTm9kZXMucHVzaChjKSxhYihhKX0KdmFyIENjPUIoe2dldCBwYXJlbnROb2RlKCl7dmFyIGE9dih0aGlzKTthPWEmJmEucGFyZW50Tm9kZTtyZXR1cm4gdm9pZCAwIT09YT9hOnRoaXMuX19zaGFkeV9uYXRpdmVfcGFyZW50Tm9kZX0sZ2V0IGZpcnN0Q2hpbGQoKXt2YXIgYT12KHRoaXMpO2E9YSYmYS5maXJzdENoaWxkO3JldHVybiB2b2lkIDAhPT1hP2E6dGhpcy5fX3NoYWR5X25hdGl2ZV9maXJzdENoaWxkfSxnZXQgbGFzdENoaWxkKCl7dmFyIGE9dih0aGlzKTthPWEmJmEubGFzdENoaWxkO3JldHVybiB2b2lkIDAhPT1hP2E6dGhpcy5fX3NoYWR5X25hdGl2ZV9sYXN0Q2hpbGR9LGdldCBuZXh0U2libGluZygpe3ZhciBhPXYodGhpcyk7YT1hJiZhLm5leHRTaWJsaW5nO3JldHVybiB2b2lkIDAhPT1hP2E6dGhpcy5fX3NoYWR5X25hdGl2ZV9uZXh0U2libGluZ30sZ2V0IHByZXZpb3VzU2libGluZygpe3ZhciBhPXYodGhpcyk7YT1hJiZhLnByZXZpb3VzU2libGluZztyZXR1cm4gdm9pZCAwIT09YT9hOnRoaXMuX19zaGFkeV9uYXRpdmVfcHJldmlvdXNTaWJsaW5nfSwKZ2V0IGNoaWxkTm9kZXMoKXtpZih5KHRoaXMpKXt2YXIgYT12KHRoaXMpO2lmKCFhLmNoaWxkTm9kZXMpe2EuY2hpbGROb2Rlcz1bXTtmb3IodmFyIGI9dGhpcy5fX3NoYWR5X2ZpcnN0Q2hpbGQ7YjtiPWIuX19zaGFkeV9uZXh0U2libGluZylhLmNoaWxkTm9kZXMucHVzaChiKX12YXIgYz1hLmNoaWxkTm9kZXN9ZWxzZSBjPXRoaXMuX19zaGFkeV9uYXRpdmVfY2hpbGROb2RlcztjLml0ZW09ZnVuY3Rpb24oYSl7cmV0dXJuIGNbYV19O3JldHVybiBjfSxnZXQgcGFyZW50RWxlbWVudCgpe3ZhciBhPXYodGhpcyk7KGE9YSYmYS5wYXJlbnROb2RlKSYmYS5ub2RlVHlwZSE9PU5vZGUuRUxFTUVOVF9OT0RFJiYoYT1udWxsKTtyZXR1cm4gdm9pZCAwIT09YT9hOnRoaXMuX19zaGFkeV9uYXRpdmVfcGFyZW50RWxlbWVudH0sZ2V0IGlzQ29ubmVjdGVkKCl7aWYoc2MmJnNjLmNhbGwodGhpcykpcmV0dXJuITA7aWYodGhpcy5ub2RlVHlwZT09Tm9kZS5ET0NVTUVOVF9GUkFHTUVOVF9OT0RFKXJldHVybiExOwp2YXIgYT10aGlzLm93bmVyRG9jdW1lbnQ7aWYoVGEpe2lmKGEuX19zaGFkeV9uYXRpdmVfY29udGFpbnModGhpcykpcmV0dXJuITB9ZWxzZSBpZihhLmRvY3VtZW50RWxlbWVudCYmYS5kb2N1bWVudEVsZW1lbnQuX19zaGFkeV9uYXRpdmVfY29udGFpbnModGhpcykpcmV0dXJuITA7Zm9yKGE9dGhpczthJiYhKGEgaW5zdGFuY2VvZiBEb2N1bWVudCk7KWE9YS5fX3NoYWR5X3BhcmVudE5vZGV8fCh6KGEpP2EuaG9zdDp2b2lkIDApO3JldHVybiEhKGEmJmEgaW5zdGFuY2VvZiBEb2N1bWVudCl9LGdldCB0ZXh0Q29udGVudCgpe2lmKHkodGhpcykpe2Zvcih2YXIgYT1bXSxiPTAsYz10aGlzLl9fc2hhZHlfY2hpbGROb2RlcyxkO2Q9Y1tiXTtiKyspZC5ub2RlVHlwZSE9PU5vZGUuQ09NTUVOVF9OT0RFJiZhLnB1c2goZC5fX3NoYWR5X3RleHRDb250ZW50KTtyZXR1cm4gYS5qb2luKCIiKX1yZXR1cm4gdGhpcy5fX3NoYWR5X25hdGl2ZV90ZXh0Q29udGVudH0sc2V0IHRleHRDb250ZW50KGEpe2lmKCJ1bmRlZmluZWQiPT09CnR5cGVvZiBhfHxudWxsPT09YSlhPSIiO3N3aXRjaCh0aGlzLm5vZGVUeXBlKXtjYXNlIE5vZGUuRUxFTUVOVF9OT0RFOmNhc2UgTm9kZS5ET0NVTUVOVF9GUkFHTUVOVF9OT0RFOmlmKCF5KHRoaXMpJiZ3Lm0pe3ZhciBiPXRoaXMuX19zaGFkeV9maXJzdENoaWxkOyhiIT10aGlzLl9fc2hhZHlfbGFzdENoaWxkfHxiJiZiLm5vZGVUeXBlIT1Ob2RlLlRFWFRfTk9ERSkmJnRjKHRoaXMpO3RoaXMuX19zaGFkeV9uYXRpdmVfdGV4dENvbnRlbnQ9YX1lbHNlIHRjKHRoaXMpLCgwPGEubGVuZ3RofHx0aGlzLm5vZGVUeXBlPT09Tm9kZS5FTEVNRU5UX05PREUpJiZ0aGlzLl9fc2hhZHlfaW5zZXJ0QmVmb3JlKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGEpKTticmVhaztkZWZhdWx0OnRoaXMubm9kZVZhbHVlPWF9fSxpbnNlcnRCZWZvcmU6ZnVuY3Rpb24oYSxiKXtpZih0aGlzLm93bmVyRG9jdW1lbnQhPT1wYyYmYS5vd25lckRvY3VtZW50IT09cGMpcmV0dXJuIHRoaXMuX19zaGFkeV9uYXRpdmVfaW5zZXJ0QmVmb3JlKGEsCmIpLGE7aWYoYT09PXRoaXMpdGhyb3cgRXJyb3IoIkZhaWxlZCB0byBleGVjdXRlICdhcHBlbmRDaGlsZCcgb24gJ05vZGUnOiBUaGUgbmV3IGNoaWxkIGVsZW1lbnQgY29udGFpbnMgdGhlIHBhcmVudC4iKTtpZihiKXt2YXIgYz12KGIpO2M9YyYmYy5wYXJlbnROb2RlO2lmKHZvaWQgMCE9PWMmJmMhPT10aGlzfHx2b2lkIDA9PT1jJiZiLl9fc2hhZHlfbmF0aXZlX3BhcmVudE5vZGUhPT10aGlzKXRocm93IEVycm9yKCJGYWlsZWQgdG8gZXhlY3V0ZSAnaW5zZXJ0QmVmb3JlJyBvbiAnTm9kZSc6IFRoZSBub2RlIGJlZm9yZSB3aGljaCB0aGUgbmV3IG5vZGUgaXMgdG8gYmUgaW5zZXJ0ZWQgaXMgbm90IGEgY2hpbGQgb2YgdGhpcyBub2RlLiIpO31pZihiPT09YSlyZXR1cm4gYTt2YXIgZD1bXSxlPShjPXhjKHRoaXMpKT9jLmhvc3QubG9jYWxOYW1lOm5jKHRoaXMpLGY9YS5fX3NoYWR5X3BhcmVudE5vZGU7aWYoZil7dmFyIGc9bmMoYSk7Zi5fX3NoYWR5X3JlbW92ZUNoaWxkKGEsISFjfHwKIXhjKGEpKX1mPSEwO3ZhciBoPSghcWN8fHZvaWQgMD09PWEuX19ub0luc2VydGlvblBvaW50KSYmIW1jKGEsZSksaz1jJiYhYS5fX25vSW5zZXJ0aW9uUG9pbnQmJighcWN8fGEubm9kZVR5cGU9PT1Ob2RlLkRPQ1VNRU5UX0ZSQUdNRU5UX05PREUpO2lmKGt8fGgpaCYmKGc9Z3x8bmMoYSkpLG9jKGEsZnVuY3Rpb24oYSl7ayYmInNsb3QiPT09YS5sb2NhbE5hbWUmJmQucHVzaChhKTtpZihoKXt2YXIgYj1nO0coKSYmKGImJmxjKGEsYiksKGI9RygpKSYmYi5zY29wZU5vZGUoYSxlKSl9fSk7aWYoInNsb3QiPT09dGhpcy5sb2NhbE5hbWV8fGQubGVuZ3RoKWQubGVuZ3RoJiYoYy5jPWMuY3x8W10sYy5hPWMuYXx8W10sYy5iPWMuYnx8e30sYy5jLnB1c2guYXBwbHkoYy5jLGQgaW5zdGFuY2VvZiBBcnJheT9kOmphKGlhKGQpKSkpLGMmJkFjKGMpO3kodGhpcykmJihoYyhhLHRoaXMsYiksYz12KHRoaXMpLExhKHRoaXMpPyhBYyhjLnJvb3QpLGY9ITEpOmMucm9vdCYmKGY9ITEpKTtmPwooYz16KHRoaXMpP3RoaXMuaG9zdDp0aGlzLGI/KGI9dmMoYiksYy5fX3NoYWR5X25hdGl2ZV9pbnNlcnRCZWZvcmUoYSxiKSk6Yy5fX3NoYWR5X25hdGl2ZV9hcHBlbmRDaGlsZChhKSk6YS5vd25lckRvY3VtZW50IT09dGhpcy5vd25lckRvY3VtZW50JiZ0aGlzLm93bmVyRG9jdW1lbnQuYWRvcHROb2RlKGEpO3djKHRoaXMsYSk7cmV0dXJuIGF9LGFwcGVuZENoaWxkOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLl9fc2hhZHlfaW5zZXJ0QmVmb3JlKGEpfSxyZW1vdmVDaGlsZDpmdW5jdGlvbihhLGIpe2I9dm9pZCAwPT09Yj8hMTpiO2lmKHRoaXMub3duZXJEb2N1bWVudCE9PXBjKXJldHVybiB0aGlzLl9fc2hhZHlfbmF0aXZlX3JlbW92ZUNoaWxkKGEpO2lmKGEuX19zaGFkeV9wYXJlbnROb2RlIT09dGhpcyl0aHJvdyBFcnJvcigiVGhlIG5vZGUgdG8gYmUgcmVtb3ZlZCBpcyBub3QgYSBjaGlsZCBvZiB0aGlzIG5vZGU6ICIrYSk7dmFyIGM9eGMoYSksZD1jJiZCYyhjLGEpLGU9dih0aGlzKTsKaWYoeSh0aGlzKSYmKGljKGEsdGhpcyksTGEodGhpcykpKXtBYyhlLnJvb3QpO3ZhciBmPSEwfWlmKEcoKSYmIWImJmMpe3ZhciBnPW5jKGEpO29jKGEsZnVuY3Rpb24oYSl7bGMoYSxnKX0pfXVjKGEpO2MmJigoYj10aGlzJiYic2xvdCI9PT10aGlzLmxvY2FsTmFtZSkmJihmPSEwKSwoZHx8YikmJkFjKGMpKTtmfHwoZj16KHRoaXMpP3RoaXMuaG9zdDp0aGlzLCghZS5yb290JiYic2xvdCIhPT1hLmxvY2FsTmFtZXx8Zj09PWEuX19zaGFkeV9uYXRpdmVfcGFyZW50Tm9kZSkmJmYuX19zaGFkeV9uYXRpdmVfcmVtb3ZlQ2hpbGQoYSkpO3djKHRoaXMsbnVsbCxhKTtyZXR1cm4gYX0scmVwbGFjZUNoaWxkOmZ1bmN0aW9uKGEsYil7dGhpcy5fX3NoYWR5X2luc2VydEJlZm9yZShhLGIpO3RoaXMuX19zaGFkeV9yZW1vdmVDaGlsZChiKTtyZXR1cm4gYX0sY2xvbmVOb2RlOmZ1bmN0aW9uKGEpe2lmKCJ0ZW1wbGF0ZSI9PXRoaXMubG9jYWxOYW1lKXJldHVybiB0aGlzLl9fc2hhZHlfbmF0aXZlX2Nsb25lTm9kZShhKTsKdmFyIGI9dGhpcy5fX3NoYWR5X25hdGl2ZV9jbG9uZU5vZGUoITEpO2lmKGEmJmIubm9kZVR5cGUhPT1Ob2RlLkFUVFJJQlVURV9OT0RFKXthPXRoaXMuX19zaGFkeV9jaGlsZE5vZGVzO2Zvcih2YXIgYz0wLGQ7YzxhLmxlbmd0aDtjKyspZD1hW2NdLl9fc2hhZHlfY2xvbmVOb2RlKCEwKSxiLl9fc2hhZHlfYXBwZW5kQ2hpbGQoZCl9cmV0dXJuIGJ9LGdldFJvb3ROb2RlOmZ1bmN0aW9uKGEpe2lmKHRoaXMmJnRoaXMubm9kZVR5cGUpe3ZhciBiPXUodGhpcyksYz1iLks7dm9pZCAwPT09YyYmKHoodGhpcyk/KGM9dGhpcyxiLks9Yyk6KGM9KGM9dGhpcy5fX3NoYWR5X3BhcmVudE5vZGUpP2MuX19zaGFkeV9nZXRSb290Tm9kZShhKTp0aGlzLGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5fX3NoYWR5X25hdGl2ZV9jb250YWlucyh0aGlzKSYmKGIuSz1jKSkpO3JldHVybiBjfX0sY29udGFpbnM6ZnVuY3Rpb24oYSl7cmV0dXJuIFVhKHRoaXMsYSl9fSk7ZnVuY3Rpb24gRGMoYSxiLGMpe3ZhciBkPVtdO0VjKGEuX19zaGFkeV9jaGlsZE5vZGVzLGIsYyxkKTtyZXR1cm4gZH1mdW5jdGlvbiBFYyhhLGIsYyxkKXtmb3IodmFyIGU9MCxmPWEubGVuZ3RoLGc9dm9pZCAwO2U8ZiYmKGc9YVtlXSk7ZSsrKXt2YXIgaDtpZihoPWcubm9kZVR5cGU9PT1Ob2RlLkVMRU1FTlRfTk9ERSl7aD1nO3ZhciBrPWIsbD1jLG09ZCxxPWsoaCk7cSYmbS5wdXNoKGgpO2wmJmwocSk/aD1xOihFYyhoLl9fc2hhZHlfY2hpbGROb2RlcyxrLGwsbSksaD12b2lkIDApfWlmKGgpYnJlYWt9fQp2YXIgRmM9Qih7Z2V0IGZpcnN0RWxlbWVudENoaWxkKCl7dmFyIGE9dih0aGlzKTtpZihhJiZ2b2lkIDAhPT1hLmZpcnN0Q2hpbGQpe2ZvcihhPXRoaXMuX19zaGFkeV9maXJzdENoaWxkO2EmJmEubm9kZVR5cGUhPT1Ob2RlLkVMRU1FTlRfTk9ERTspYT1hLl9fc2hhZHlfbmV4dFNpYmxpbmc7cmV0dXJuIGF9cmV0dXJuIHRoaXMuX19zaGFkeV9uYXRpdmVfZmlyc3RFbGVtZW50Q2hpbGR9LGdldCBsYXN0RWxlbWVudENoaWxkKCl7dmFyIGE9dih0aGlzKTtpZihhJiZ2b2lkIDAhPT1hLmxhc3RDaGlsZCl7Zm9yKGE9dGhpcy5fX3NoYWR5X2xhc3RDaGlsZDthJiZhLm5vZGVUeXBlIT09Tm9kZS5FTEVNRU5UX05PREU7KWE9YS5fX3NoYWR5X3ByZXZpb3VzU2libGluZztyZXR1cm4gYX1yZXR1cm4gdGhpcy5fX3NoYWR5X25hdGl2ZV9sYXN0RWxlbWVudENoaWxkfSxnZXQgY2hpbGRyZW4oKXtyZXR1cm4geSh0aGlzKT9WYShBcnJheS5wcm90b3R5cGUuZmlsdGVyLmNhbGwodGhpcy5fX3NoYWR5X2NoaWxkTm9kZXMsCmZ1bmN0aW9uKGEpe3JldHVybiBhLm5vZGVUeXBlPT09Tm9kZS5FTEVNRU5UX05PREV9KSk6dGhpcy5fX3NoYWR5X25hdGl2ZV9jaGlsZHJlbn0sZ2V0IGNoaWxkRWxlbWVudENvdW50KCl7dmFyIGE9dGhpcy5fX3NoYWR5X2NoaWxkcmVuO3JldHVybiBhP2EubGVuZ3RoOjB9fSksR2M9Qih7cXVlcnlTZWxlY3RvcjpmdW5jdGlvbihhKXtyZXR1cm4gRGModGhpcyxmdW5jdGlvbihiKXtyZXR1cm4gT2EuY2FsbChiLGEpfSxmdW5jdGlvbihhKXtyZXR1cm4hIWF9KVswXXx8bnVsbH0scXVlcnlTZWxlY3RvckFsbDpmdW5jdGlvbihhLGIpe2lmKGIpe2I9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fX3NoYWR5X25hdGl2ZV9xdWVyeVNlbGVjdG9yQWxsKGEpKTt2YXIgYz10aGlzLl9fc2hhZHlfZ2V0Um9vdE5vZGUoKTtyZXR1cm4gYi5maWx0ZXIoZnVuY3Rpb24oYSl7cmV0dXJuIGEuX19zaGFkeV9nZXRSb290Tm9kZSgpPT1jfSl9cmV0dXJuIERjKHRoaXMsZnVuY3Rpb24oYil7cmV0dXJuIE9hLmNhbGwoYiwKYSl9KX19KSxIYz13Lm9hP09iamVjdC5hc3NpZ24oe30sRmMpOkZjO09iamVjdC5hc3NpZ24oRmMsR2MpO3ZhciBJYz1CKHtnZXRFbGVtZW50QnlJZDpmdW5jdGlvbihhKXtyZXR1cm4iIj09PWE/bnVsbDpEYyh0aGlzLGZ1bmN0aW9uKGIpe3JldHVybiBiLmlkPT1hfSxmdW5jdGlvbihhKXtyZXR1cm4hIWF9KVswXXx8bnVsbH19KTt2YXIgSmM9Qih7Z2V0IGFjdGl2ZUVsZW1lbnQoKXt2YXIgYT13Lm0/ZG9jdW1lbnQuX19zaGFkeV9uYXRpdmVfYWN0aXZlRWxlbWVudDpkb2N1bWVudC5hY3RpdmVFbGVtZW50O2lmKCFhfHwhYS5ub2RlVHlwZSlyZXR1cm4gbnVsbDt2YXIgYj0hIXoodGhpcyk7aWYoISh0aGlzPT09ZG9jdW1lbnR8fGImJnRoaXMuaG9zdCE9PWEmJnRoaXMuaG9zdC5fX3NoYWR5X25hdGl2ZV9jb250YWlucyhhKSkpcmV0dXJuIG51bGw7Zm9yKGI9eGMoYSk7YiYmYiE9PXRoaXM7KWE9Yi5ob3N0LGI9eGMoYSk7cmV0dXJuIHRoaXM9PT1kb2N1bWVudD9iP251bGw6YTpiPT09dGhpcz9hOm51bGx9fSk7dmFyIEtjPWRvY3VtZW50LmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgiaW5lcnQiKSxMYz1CKHtnZXQgaW5uZXJIVE1MKCl7cmV0dXJuIHkodGhpcyk/a2IoInRlbXBsYXRlIj09PXRoaXMubG9jYWxOYW1lP3RoaXMuY29udGVudDp0aGlzLGZ1bmN0aW9uKGEpe3JldHVybiBhLl9fc2hhZHlfY2hpbGROb2Rlc30pOnRoaXMuX19zaGFkeV9uYXRpdmVfaW5uZXJIVE1MfSxzZXQgaW5uZXJIVE1MKGEpe2lmKCJ0ZW1wbGF0ZSI9PT10aGlzLmxvY2FsTmFtZSl0aGlzLl9fc2hhZHlfbmF0aXZlX2lubmVySFRNTD1hO2Vsc2V7dGModGhpcyk7dmFyIGI9dGhpcy5sb2NhbE5hbWV8fCJkaXYiO2I9dGhpcy5uYW1lc3BhY2VVUkkmJnRoaXMubmFtZXNwYWNlVVJJIT09S2MubmFtZXNwYWNlVVJJP0tjLmNyZWF0ZUVsZW1lbnROUyh0aGlzLm5hbWVzcGFjZVVSSSxiKTpLYy5jcmVhdGVFbGVtZW50KGIpO2Zvcih3Lm0/Yi5fX3NoYWR5X25hdGl2ZV9pbm5lckhUTUw9YTpiLmlubmVySFRNTD0KYTthPWIuX19zaGFkeV9maXJzdENoaWxkOyl0aGlzLl9fc2hhZHlfaW5zZXJ0QmVmb3JlKGEpfX19KTt2YXIgTWM9Qih7YWRkRXZlbnRMaXN0ZW5lcjpmdW5jdGlvbihhLGIsYyl7Im9iamVjdCIhPT10eXBlb2YgYyYmKGM9e2NhcHR1cmU6ISFjfSk7Yy4kPXRoaXM7dGhpcy5ob3N0Ll9fc2hhZHlfYWRkRXZlbnRMaXN0ZW5lcihhLGIsYyl9LHJlbW92ZUV2ZW50TGlzdGVuZXI6ZnVuY3Rpb24oYSxiLGMpeyJvYmplY3QiIT09dHlwZW9mIGMmJihjPXtjYXB0dXJlOiEhY30pO2MuJD10aGlzO3RoaXMuaG9zdC5fX3NoYWR5X3JlbW92ZUV2ZW50TGlzdGVuZXIoYSxiLGMpfX0pO2Z1bmN0aW9uIE5jKGEsYil7QShhLE1jLGIpO0EoYSxKYyxiKTtBKGEsTGMsYik7QShhLEZjLGIpO3cuSiYmIWI/KEEoYSxDYyxiKSxBKGEsSWMsYikpOncubXx8KEEoYSxBYiksQShhLHpiKSl9O3ZhciBPYz17fSxQYz13LmRlZmVyQ29ubmVjdGlvbkNhbGxiYWNrcyYmImxvYWRpbmciPT09ZG9jdW1lbnQucmVhZHlTdGF0ZSxRYztmdW5jdGlvbiBSYyhhKXt2YXIgYj1bXTtkbyBiLnVuc2hpZnQoYSk7d2hpbGUoYT1hLl9fc2hhZHlfcGFyZW50Tm9kZSk7cmV0dXJuIGJ9CmZ1bmN0aW9uIFNjKGEsYixjKXtpZihhIT09T2MpdGhyb3cgbmV3IFR5cGVFcnJvcigiSWxsZWdhbCBjb25zdHJ1Y3RvciIpO3RoaXMuemE9IlNoYWR5Um9vdCI7dGhpcy5ob3N0PWI7dGhpcy5tb2RlPWMmJmMubW9kZTtqYyhiKTthPXUoYik7YS5yb290PXRoaXM7YS5wYT0iY2xvc2VkIiE9PXRoaXMubW9kZT90aGlzOm51bGw7YT11KHRoaXMpO2EuZmlyc3RDaGlsZD1hLmxhc3RDaGlsZD1hLnBhcmVudE5vZGU9YS5uZXh0U2libGluZz1hLnByZXZpb3VzU2libGluZz1udWxsO2EuY2hpbGROb2Rlcz1bXTt0aGlzLmJhPXRoaXMuQj0hMTt0aGlzLmM9dGhpcy5iPXRoaXMuYT1udWxsO2lmKHcucHJlZmVyUGVyZm9ybWFuY2UpZm9yKDthPWIuX19zaGFkeV9uYXRpdmVfZmlyc3RDaGlsZDspYi5fX3NoYWR5X25hdGl2ZV9yZW1vdmVDaGlsZChhKTtlbHNlIEFjKHRoaXMpfWZ1bmN0aW9uIEFjKGEpe2EuQnx8KGEuQj0hMCxZYShmdW5jdGlvbigpe3JldHVybiBUYyhhKX0pKX0KZnVuY3Rpb24gVGMoYSl7dmFyIGI7aWYoYj1hLkIpe2Zvcih2YXIgYzthOylhOnthLkImJihjPWEpLGI9YTthPWIuaG9zdC5fX3NoYWR5X2dldFJvb3ROb2RlKCk7aWYoeihhKSYmKGI9dihiLmhvc3QpKSYmMDxiLk4pYnJlYWsgYTthPXZvaWQgMH1iPWN9KGM9YikmJmMuX3JlbmRlclNlbGYoKX0KU2MucHJvdG90eXBlLl9yZW5kZXJTZWxmPWZ1bmN0aW9uKCl7dmFyIGE9UGM7UGM9ITA7dGhpcy5CPSExO2lmKHRoaXMuYSl7VWModGhpcyk7Zm9yKHZhciBiPTAsYztiPHRoaXMuYS5sZW5ndGg7YisrKXtjPXRoaXMuYVtiXTt2YXIgZD12KGMpLGU9ZC5hc3NpZ25lZE5vZGVzO2QuYXNzaWduZWROb2Rlcz1bXTtkLkQ9W107aWYoZC5jYT1lKWZvcihkPTA7ZDxlLmxlbmd0aDtkKyspe3ZhciBmPXYoZVtkXSk7Zi5QPWYuYXNzaWduZWRTbG90O2YuYXNzaWduZWRTbG90PT09YyYmKGYuYXNzaWduZWRTbG90PW51bGwpfX1mb3IoYj10aGlzLmhvc3QuX19zaGFkeV9maXJzdENoaWxkO2I7Yj1iLl9fc2hhZHlfbmV4dFNpYmxpbmcpVmModGhpcyxiKTtmb3IoYj0wO2I8dGhpcy5hLmxlbmd0aDtiKyspe2M9dGhpcy5hW2JdO2U9dihjKTtpZighZS5hc3NpZ25lZE5vZGVzLmxlbmd0aClmb3IoZD1jLl9fc2hhZHlfZmlyc3RDaGlsZDtkO2Q9ZC5fX3NoYWR5X25leHRTaWJsaW5nKVZjKHRoaXMsCmQsYyk7KGQ9KGQ9dihjLl9fc2hhZHlfcGFyZW50Tm9kZSkpJiZkLnJvb3QpJiYoTWEoZCl8fGQuQikmJmQuX3JlbmRlclNlbGYoKTtXYyh0aGlzLGUuRCxlLmFzc2lnbmVkTm9kZXMpO2lmKGQ9ZS5jYSl7Zm9yKGY9MDtmPGQubGVuZ3RoO2YrKyl2KGRbZl0pLlA9bnVsbDtlLmNhPW51bGw7ZC5sZW5ndGg+ZS5hc3NpZ25lZE5vZGVzLmxlbmd0aCYmKGUuVD0hMCl9ZS5UJiYoZS5UPSExLFhjKHRoaXMsYykpfWM9dGhpcy5hO2I9W107Zm9yKGU9MDtlPGMubGVuZ3RoO2UrKylkPWNbZV0uX19zaGFkeV9wYXJlbnROb2RlLChmPXYoZCkpJiZmLnJvb3R8fCEoMD5iLmluZGV4T2YoZCkpfHxiLnB1c2goZCk7Zm9yKGM9MDtjPGIubGVuZ3RoO2MrKyl7Zj1iW2NdO2U9Zj09PXRoaXM/dGhpcy5ob3N0OmY7ZD1bXTtmPWYuX19zaGFkeV9jaGlsZE5vZGVzO2Zvcih2YXIgZz0wO2c8Zi5sZW5ndGg7ZysrKXt2YXIgaD1mW2ddO2lmKCJzbG90Ij09aC5sb2NhbE5hbWUpe2g9dihoKS5EO2Zvcih2YXIgaz0KMDtrPGgubGVuZ3RoO2srKylkLnB1c2goaFtrXSl9ZWxzZSBkLnB1c2goaCl9Zj1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChlLl9fc2hhZHlfbmF0aXZlX2NoaWxkTm9kZXMpO2c9ZWMoZCxkLmxlbmd0aCxmLGYubGVuZ3RoKTtrPWg9MDtmb3IodmFyIGw9dm9pZCAwO2g8Zy5sZW5ndGgmJihsPWdbaF0pO2grKyl7Zm9yKHZhciBtPTAscT12b2lkIDA7bTxsLkwubGVuZ3RoJiYocT1sLkxbbV0pO20rKylxLl9fc2hhZHlfbmF0aXZlX3BhcmVudE5vZGU9PT1lJiZlLl9fc2hhZHlfbmF0aXZlX3JlbW92ZUNoaWxkKHEpLGYuc3BsaWNlKGwuaW5kZXgraywxKTtrLT1sLlJ9az0wO2ZvcihsPXZvaWQgMDtrPGcubGVuZ3RoJiYobD1nW2tdKTtrKyspZm9yKGg9ZltsLmluZGV4XSxtPWwuaW5kZXg7bTxsLmluZGV4K2wuUjttKyspcT1kW21dLGUuX19zaGFkeV9uYXRpdmVfaW5zZXJ0QmVmb3JlKHEsaCksZi5zcGxpY2UobSwwLHEpfX1pZighdy5wcmVmZXJQZXJmb3JtYW5jZSYmIXRoaXMuYmEpZm9yKGI9CnRoaXMuaG9zdC5fX3NoYWR5X2NoaWxkTm9kZXMsYz0wLGU9Yi5sZW5ndGg7YzxlO2MrKylkPWJbY10sZj12KGQpLGQuX19zaGFkeV9uYXRpdmVfcGFyZW50Tm9kZSE9PXRoaXMuaG9zdHx8InNsb3QiIT09ZC5sb2NhbE5hbWUmJmYuYXNzaWduZWRTbG90fHx0aGlzLmhvc3QuX19zaGFkeV9uYXRpdmVfcmVtb3ZlQ2hpbGQoZCk7dGhpcy5iYT0hMDtQYz1hO1FjJiZRYygpfTtmdW5jdGlvbiBWYyhhLGIsYyl7dmFyIGQ9dShiKSxlPWQuUDtkLlA9bnVsbDtjfHwoYz0oYT1hLmJbYi5fX3NoYWR5X3Nsb3R8fCJfX2NhdGNoYWxsIl0pJiZhWzBdKTtjPyh1KGMpLmFzc2lnbmVkTm9kZXMucHVzaChiKSxkLmFzc2lnbmVkU2xvdD1jKTpkLmFzc2lnbmVkU2xvdD12b2lkIDA7ZSE9PWQuYXNzaWduZWRTbG90JiZkLmFzc2lnbmVkU2xvdCYmKHUoZC5hc3NpZ25lZFNsb3QpLlQ9ITApfQpmdW5jdGlvbiBXYyhhLGIsYyl7Zm9yKHZhciBkPTAsZT12b2lkIDA7ZDxjLmxlbmd0aCYmKGU9Y1tkXSk7ZCsrKWlmKCJzbG90Ij09ZS5sb2NhbE5hbWUpe3ZhciBmPXYoZSkuYXNzaWduZWROb2RlcztmJiZmLmxlbmd0aCYmV2MoYSxiLGYpfWVsc2UgYi5wdXNoKGNbZF0pfWZ1bmN0aW9uIFhjKGEsYil7Yi5fX3NoYWR5X25hdGl2ZV9kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgic2xvdGNoYW5nZSIpKTtiPXYoYik7Yi5hc3NpZ25lZFNsb3QmJlhjKGEsYi5hc3NpZ25lZFNsb3QpfQpmdW5jdGlvbiBVYyhhKXtpZihhLmMmJmEuYy5sZW5ndGgpe2Zvcih2YXIgYj1hLmMsYyxkPTA7ZDxiLmxlbmd0aDtkKyspe3ZhciBlPWJbZF07amMoZSk7dmFyIGY9ZS5fX3NoYWR5X3BhcmVudE5vZGU7amMoZik7Zj12KGYpO2YuTj0oZi5OfHwwKSsxO2Y9WWMoZSk7YS5iW2ZdPyhjPWN8fHt9LGNbZl09ITAsYS5iW2ZdLnB1c2goZSkpOmEuYltmXT1bZV07YS5hLnB1c2goZSl9aWYoYylmb3IodmFyIGcgaW4gYylhLmJbZ109WmMoYS5iW2ddKTthLmM9W119fWZ1bmN0aW9uIFljKGEpe3ZhciBiPWEubmFtZXx8YS5nZXRBdHRyaWJ1dGUoIm5hbWUiKXx8Il9fY2F0Y2hhbGwiO3JldHVybiBhLndhPWJ9CmZ1bmN0aW9uIFpjKGEpe3JldHVybiBhLnNvcnQoZnVuY3Rpb24oYSxjKXthPVJjKGEpO2Zvcih2YXIgYj1SYyhjKSxlPTA7ZTxhLmxlbmd0aDtlKyspe2M9YVtlXTt2YXIgZj1iW2VdO2lmKGMhPT1mKXJldHVybiBhPUFycmF5LmZyb20oYy5fX3NoYWR5X3BhcmVudE5vZGUuX19zaGFkeV9jaGlsZE5vZGVzKSxhLmluZGV4T2YoYyktYS5pbmRleE9mKGYpfX0pfQpmdW5jdGlvbiBCYyhhLGIpe2lmKGEuYSl7VWMoYSk7dmFyIGM9YS5iLGQ7Zm9yKGQgaW4gYylmb3IodmFyIGU9Y1tkXSxmPTA7ZjxlLmxlbmd0aDtmKyspe3ZhciBnPWVbZl07aWYoVWEoYixnKSl7ZS5zcGxpY2UoZiwxKTt2YXIgaD1hLmEuaW5kZXhPZihnKTswPD1oJiYoYS5hLnNwbGljZShoLDEpLChoPXYoZy5fX3NoYWR5X3BhcmVudE5vZGUpKSYmaC5OJiZoLk4tLSk7Zi0tO2c9dihnKTtpZihoPWcuRClmb3IodmFyIGs9MDtrPGgubGVuZ3RoO2srKyl7dmFyIGw9aFtrXSxtPWwuX19zaGFkeV9uYXRpdmVfcGFyZW50Tm9kZTttJiZtLl9fc2hhZHlfbmF0aXZlX3JlbW92ZUNoaWxkKGwpfWcuRD1bXTtnLmFzc2lnbmVkTm9kZXM9W107aD0hMH19cmV0dXJuIGh9fWZ1bmN0aW9uIE1hKGEpe1VjKGEpO3JldHVybiEoIWEuYXx8IWEuYS5sZW5ndGgpfQooZnVuY3Rpb24oYSl7YS5fX3Byb3RvX189RG9jdW1lbnRGcmFnbWVudC5wcm90b3R5cGU7TmMoYSwiX19zaGFkeV8iKTtOYyhhKTtPYmplY3QuZGVmaW5lUHJvcGVydGllcyhhLHtub2RlVHlwZTp7dmFsdWU6Tm9kZS5ET0NVTUVOVF9GUkFHTUVOVF9OT0RFLGNvbmZpZ3VyYWJsZTohMH0sbm9kZU5hbWU6e3ZhbHVlOiIjZG9jdW1lbnQtZnJhZ21lbnQiLGNvbmZpZ3VyYWJsZTohMH0sbm9kZVZhbHVlOnt2YWx1ZTpudWxsLGNvbmZpZ3VyYWJsZTohMH19KTtbImxvY2FsTmFtZSIsIm5hbWVzcGFjZVVSSSIsInByZWZpeCJdLmZvckVhY2goZnVuY3Rpb24oYil7T2JqZWN0LmRlZmluZVByb3BlcnR5KGEsYix7dmFsdWU6dm9pZCAwLGNvbmZpZ3VyYWJsZTohMH0pfSk7WyJvd25lckRvY3VtZW50IiwiYmFzZVVSSSIsImlzQ29ubmVjdGVkIl0uZm9yRWFjaChmdW5jdGlvbihiKXtPYmplY3QuZGVmaW5lUHJvcGVydHkoYSxiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ob3N0W2JdfSwKY29uZmlndXJhYmxlOiEwfSl9KX0pKFNjLnByb3RvdHlwZSk7CmlmKHdpbmRvdy5jdXN0b21FbGVtZW50cyYmdy5lYSYmIXcucHJlZmVyUGVyZm9ybWFuY2Upe3ZhciAkYz1uZXcgTWFwO1FjPWZ1bmN0aW9uKCl7dmFyIGE9W107JGMuZm9yRWFjaChmdW5jdGlvbihiLGMpe2EucHVzaChbYyxiXSl9KTskYy5jbGVhcigpO2Zvcih2YXIgYj0wO2I8YS5sZW5ndGg7YisrKXt2YXIgYz1hW2JdWzBdO2FbYl1bMV0/Yy51YSgpOmMudmEoKX19O1BjJiZkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJyZWFkeXN0YXRlY2hhbmdlIixmdW5jdGlvbigpe1BjPSExO1FjKCl9LHtvbmNlOiEwfSk7dmFyIGFkPWZ1bmN0aW9uKGEsYixjKXt2YXIgZD0wLGU9Il9faXNDb25uZWN0ZWQiK2QrKztpZihifHxjKWEucHJvdG90eXBlLmNvbm5lY3RlZENhbGxiYWNrPWEucHJvdG90eXBlLnVhPWZ1bmN0aW9uKCl7UGM/JGMuc2V0KHRoaXMsITApOnRoaXNbZV18fCh0aGlzW2VdPSEwLGImJmIuY2FsbCh0aGlzKSl9LGEucHJvdG90eXBlLmRpc2Nvbm5lY3RlZENhbGxiYWNrPQphLnByb3RvdHlwZS52YT1mdW5jdGlvbigpe1BjP3RoaXMuaXNDb25uZWN0ZWR8fCRjLnNldCh0aGlzLCExKTp0aGlzW2VdJiYodGhpc1tlXT0hMSxjJiZjLmNhbGwodGhpcykpfTtyZXR1cm4gYX0sYmQ9d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZTtPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LkN1c3RvbUVsZW1lbnRSZWdpc3RyeS5wcm90b3R5cGUsImRlZmluZSIse3ZhbHVlOmZ1bmN0aW9uKGEsYil7dmFyIGM9Yi5wcm90b3R5cGUuY29ubmVjdGVkQ2FsbGJhY2ssZD1iLnByb3RvdHlwZS5kaXNjb25uZWN0ZWRDYWxsYmFjaztiZC5jYWxsKHdpbmRvdy5jdXN0b21FbGVtZW50cyxhLGFkKGIsYyxkKSk7Yi5wcm90b3R5cGUuY29ubmVjdGVkQ2FsbGJhY2s9YztiLnByb3RvdHlwZS5kaXNjb25uZWN0ZWRDYWxsYmFjaz1kfX0pfWZ1bmN0aW9uIHhjKGEpe2E9YS5fX3NoYWR5X2dldFJvb3ROb2RlKCk7aWYoeihhKSlyZXR1cm4gYX07ZnVuY3Rpb24gY2QoYSl7dGhpcy5ub2RlPWF9bj1jZC5wcm90b3R5cGU7bi5hZGRFdmVudExpc3RlbmVyPWZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfYWRkRXZlbnRMaXN0ZW5lcihhLGIsYyl9O24ucmVtb3ZlRXZlbnRMaXN0ZW5lcj1mdW5jdGlvbihhLGIsYyl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X3JlbW92ZUV2ZW50TGlzdGVuZXIoYSxiLGMpfTtuLmFwcGVuZENoaWxkPWZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9hcHBlbmRDaGlsZChhKX07bi5pbnNlcnRCZWZvcmU9ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfaW5zZXJ0QmVmb3JlKGEsYil9O24ucmVtb3ZlQ2hpbGQ9ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X3JlbW92ZUNoaWxkKGEpfTtuLnJlcGxhY2VDaGlsZD1mdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9yZXBsYWNlQ2hpbGQoYSxiKX07Cm4uY2xvbmVOb2RlPWZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9jbG9uZU5vZGUoYSl9O24uZ2V0Um9vdE5vZGU9ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X2dldFJvb3ROb2RlKGEpfTtuLmNvbnRhaW5zPWZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9jb250YWlucyhhKX07bi5kaXNwYXRjaEV2ZW50PWZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9kaXNwYXRjaEV2ZW50KGEpfTtuLnNldEF0dHJpYnV0ZT1mdW5jdGlvbihhLGIpe3RoaXMubm9kZS5fX3NoYWR5X3NldEF0dHJpYnV0ZShhLGIpfTtuLmdldEF0dHJpYnV0ZT1mdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfbmF0aXZlX2dldEF0dHJpYnV0ZShhKX07bi5oYXNBdHRyaWJ1dGU9ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X25hdGl2ZV9oYXNBdHRyaWJ1dGUoYSl9O24ucmVtb3ZlQXR0cmlidXRlPWZ1bmN0aW9uKGEpe3RoaXMubm9kZS5fX3NoYWR5X3JlbW92ZUF0dHJpYnV0ZShhKX07Cm4uYXR0YWNoU2hhZG93PWZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9hdHRhY2hTaGFkb3coYSl9O24uZm9jdXM9ZnVuY3Rpb24oKXt0aGlzLm5vZGUuX19zaGFkeV9uYXRpdmVfZm9jdXMoKX07bi5ibHVyPWZ1bmN0aW9uKCl7dGhpcy5ub2RlLl9fc2hhZHlfYmx1cigpfTtuLmltcG9ydE5vZGU9ZnVuY3Rpb24oYSxiKXtpZih0aGlzLm5vZGUubm9kZVR5cGU9PT1Ob2RlLkRPQ1VNRU5UX05PREUpcmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X2ltcG9ydE5vZGUoYSxiKX07bi5nZXRFbGVtZW50QnlJZD1mdW5jdGlvbihhKXtpZih0aGlzLm5vZGUubm9kZVR5cGU9PT1Ob2RlLkRPQ1VNRU5UX05PREUpcmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X2dldEVsZW1lbnRCeUlkKGEpfTtuLnF1ZXJ5U2VsZWN0b3I9ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X3F1ZXJ5U2VsZWN0b3IoYSl9OwpuLnF1ZXJ5U2VsZWN0b3JBbGw9ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfcXVlcnlTZWxlY3RvckFsbChhLGIpfTtuLmFzc2lnbmVkTm9kZXM9ZnVuY3Rpb24oYSl7aWYoInNsb3QiPT09dGhpcy5ub2RlLmxvY2FsTmFtZSlyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfYXNzaWduZWROb2RlcyhhKX07CnAuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoY2QucHJvdG90eXBlLHthY3RpdmVFbGVtZW50Ontjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtpZih6KHRoaXMubm9kZSl8fHRoaXMubm9kZS5ub2RlVHlwZT09PU5vZGUuRE9DVU1FTlRfTk9ERSlyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfYWN0aXZlRWxlbWVudH19LF9hY3RpdmVFbGVtZW50Ontjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5hY3RpdmVFbGVtZW50fX0saG9zdDp7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7aWYoeih0aGlzLm5vZGUpKXJldHVybiB0aGlzLm5vZGUuaG9zdH19LHBhcmVudE5vZGU6e2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9wYXJlbnROb2RlfX0sZmlyc3RDaGlsZDp7Y29uZmlndXJhYmxlOiEwLAplbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9maXJzdENoaWxkfX0sbGFzdENoaWxkOntjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfbGFzdENoaWxkfX0sbmV4dFNpYmxpbmc6e2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9uZXh0U2libGluZ319LHByZXZpb3VzU2libGluZzp7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X3ByZXZpb3VzU2libGluZ319LGNoaWxkTm9kZXM6e2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9jaGlsZE5vZGVzfX0scGFyZW50RWxlbWVudDp7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITAsCmdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9wYXJlbnRFbGVtZW50fX0sZmlyc3RFbGVtZW50Q2hpbGQ6e2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9maXJzdEVsZW1lbnRDaGlsZH19LGxhc3RFbGVtZW50Q2hpbGQ6e2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9sYXN0RWxlbWVudENoaWxkfX0sbmV4dEVsZW1lbnRTaWJsaW5nOntjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfbmV4dEVsZW1lbnRTaWJsaW5nfX0scHJldmlvdXNFbGVtZW50U2libGluZzp7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X3ByZXZpb3VzRWxlbWVudFNpYmxpbmd9fSwKY2hpbGRyZW46e2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9jaGlsZHJlbn19LGNoaWxkRWxlbWVudENvdW50Ontjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfY2hpbGRFbGVtZW50Q291bnR9fSxzaGFkb3dSb290Ontjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfc2hhZG93Um9vdH19LGFzc2lnbmVkU2xvdDp7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X2Fzc2lnbmVkU2xvdH19LGlzQ29ubmVjdGVkOntjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfaXNDb25uZWN0ZWR9fSxpbm5lckhUTUw6e2NvbmZpZ3VyYWJsZTohMCwKZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ub2RlLl9fc2hhZHlfaW5uZXJIVE1MfSxzZXQ6ZnVuY3Rpb24oYSl7dGhpcy5ub2RlLl9fc2hhZHlfaW5uZXJIVE1MPWF9fSx0ZXh0Q29udGVudDp7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubm9kZS5fX3NoYWR5X3RleHRDb250ZW50fSxzZXQ6ZnVuY3Rpb24oYSl7dGhpcy5ub2RlLl9fc2hhZHlfdGV4dENvbnRlbnQ9YX19LHNsb3Q6e2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUuX19zaGFkeV9zbG90fSxzZXQ6ZnVuY3Rpb24oYSl7dGhpcy5ub2RlLl9fc2hhZHlfc2xvdD1hfX19KTsKY2MuZm9yRWFjaChmdW5jdGlvbihhKXtPYmplY3QuZGVmaW5lUHJvcGVydHkoY2QucHJvdG90eXBlLGEse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGVbIl9fc2hhZHlfIithXX0sc2V0OmZ1bmN0aW9uKGIpe3RoaXMubm9kZVsiX19zaGFkeV8iK2FdPWJ9LGNvbmZpZ3VyYWJsZTohMH0pfSk7dmFyIGRkPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIGVkKGEpe2lmKHooYSl8fGEgaW5zdGFuY2VvZiBjZClyZXR1cm4gYTt2YXIgYj1kZC5nZXQoYSk7Ynx8KGI9bmV3IGNkKGEpLGRkLnNldChhLGIpKTtyZXR1cm4gYn07dmFyIGZkPUIoe2Rpc3BhdGNoRXZlbnQ6ZnVuY3Rpb24oYSl7WmEoKTtyZXR1cm4gdGhpcy5fX3NoYWR5X25hdGl2ZV9kaXNwYXRjaEV2ZW50KGEpfSxhZGRFdmVudExpc3RlbmVyOlViLHJlbW92ZUV2ZW50TGlzdGVuZXI6V2J9KTt2YXIgZ2Q9Qih7Z2V0IGFzc2lnbmVkU2xvdCgpe3ZhciBhPXRoaXMuX19zaGFkeV9wYXJlbnROb2RlOyhhPWEmJmEuX19zaGFkeV9zaGFkb3dSb290KSYmVGMoYSk7cmV0dXJuKGE9dih0aGlzKSkmJmEuYXNzaWduZWRTbG90fHxudWxsfX0pO3ZhciBoZD13aW5kb3cuZG9jdW1lbnQ7ZnVuY3Rpb24gaWQoYSxiKXtpZigic2xvdCI9PT1iKWE9YS5fX3NoYWR5X3BhcmVudE5vZGUsTGEoYSkmJkFjKHYoYSkucm9vdCk7ZWxzZSBpZigic2xvdCI9PT1hLmxvY2FsTmFtZSYmIm5hbWUiPT09YiYmKGI9eGMoYSkpKXtpZihiLmEpe1VjKGIpO3ZhciBjPWEud2EsZD1ZYyhhKTtpZihkIT09Yyl7Yz1iLmJbY107dmFyIGU9Yy5pbmRleE9mKGEpOzA8PWUmJmMuc3BsaWNlKGUsMSk7Yz1iLmJbZF18fChiLmJbZF09W10pO2MucHVzaChhKTsxPGMubGVuZ3RoJiYoYi5iW2RdPVpjKGMpKX19QWMoYil9fQp2YXIgamQ9Qih7Z2V0IHByZXZpb3VzRWxlbWVudFNpYmxpbmcoKXt2YXIgYT12KHRoaXMpO2lmKGEmJnZvaWQgMCE9PWEucHJldmlvdXNTaWJsaW5nKXtmb3IoYT10aGlzLl9fc2hhZHlfcHJldmlvdXNTaWJsaW5nO2EmJmEubm9kZVR5cGUhPT1Ob2RlLkVMRU1FTlRfTk9ERTspYT1hLl9fc2hhZHlfcHJldmlvdXNTaWJsaW5nO3JldHVybiBhfXJldHVybiB0aGlzLl9fc2hhZHlfbmF0aXZlX3ByZXZpb3VzRWxlbWVudFNpYmxpbmd9LGdldCBuZXh0RWxlbWVudFNpYmxpbmcoKXt2YXIgYT12KHRoaXMpO2lmKGEmJnZvaWQgMCE9PWEubmV4dFNpYmxpbmcpe2ZvcihhPXRoaXMuX19zaGFkeV9uZXh0U2libGluZzthJiZhLm5vZGVUeXBlIT09Tm9kZS5FTEVNRU5UX05PREU7KWE9YS5fX3NoYWR5X25leHRTaWJsaW5nO3JldHVybiBhfXJldHVybiB0aGlzLl9fc2hhZHlfbmF0aXZlX25leHRFbGVtZW50U2libGluZ30sZ2V0IHNsb3QoKXtyZXR1cm4gdGhpcy5nZXRBdHRyaWJ1dGUoInNsb3QiKX0sCnNldCBzbG90KGEpe3RoaXMuX19zaGFkeV9zZXRBdHRyaWJ1dGUoInNsb3QiLGEpfSxnZXQgc2hhZG93Um9vdCgpe3ZhciBhPXYodGhpcyk7cmV0dXJuIGEmJmEucGF8fG51bGx9LGdldCBjbGFzc05hbWUoKXtyZXR1cm4gdGhpcy5nZXRBdHRyaWJ1dGUoImNsYXNzIil8fCIifSxzZXQgY2xhc3NOYW1lKGEpe3RoaXMuX19zaGFkeV9zZXRBdHRyaWJ1dGUoImNsYXNzIixhKX0sc2V0QXR0cmlidXRlOmZ1bmN0aW9uKGEsYil7aWYodGhpcy5vd25lckRvY3VtZW50IT09aGQpdGhpcy5fX3NoYWR5X25hdGl2ZV9zZXRBdHRyaWJ1dGUoYSxiKTtlbHNle3ZhciBjOyhjPUcoKSkmJiJjbGFzcyI9PT1hPyhjLnNldEVsZW1lbnRDbGFzcyh0aGlzLGIpLGM9ITApOmM9ITE7Y3x8KHRoaXMuX19zaGFkeV9uYXRpdmVfc2V0QXR0cmlidXRlKGEsYiksaWQodGhpcyxhKSl9fSxyZW1vdmVBdHRyaWJ1dGU6ZnVuY3Rpb24oYSl7dGhpcy5fX3NoYWR5X25hdGl2ZV9yZW1vdmVBdHRyaWJ1dGUoYSk7aWQodGhpcywKYSl9LGF0dGFjaFNoYWRvdzpmdW5jdGlvbihhKXtpZighdGhpcyl0aHJvdyBFcnJvcigiTXVzdCBwcm92aWRlIGEgaG9zdC4iKTtpZighYSl0aHJvdyBFcnJvcigiTm90IGVub3VnaCBhcmd1bWVudHMuIik7cmV0dXJuIG5ldyBTYyhPYyx0aGlzLGEpfX0pO3ZhciBrZD1CKHtibHVyOmZ1bmN0aW9uKCl7dmFyIGE9dih0aGlzKTsoYT0oYT1hJiZhLnJvb3QpJiZhLmFjdGl2ZUVsZW1lbnQpP2EuX19zaGFkeV9ibHVyKCk6dGhpcy5fX3NoYWR5X25hdGl2ZV9ibHVyKCl9fSk7Y2MuZm9yRWFjaChmdW5jdGlvbihhKXtrZFthXT17c2V0OmZ1bmN0aW9uKGIpe3ZhciBjPXUodGhpcyksZD1hLnN1YnN0cmluZygyKTtjLk9bYV0mJnRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcihkLGMuT1thXSk7dGhpcy5fX3NoYWR5X2FkZEV2ZW50TGlzdGVuZXIoZCxiKTtjLk9bYV09Yn0sZ2V0OmZ1bmN0aW9uKCl7dmFyIGI9dih0aGlzKTtyZXR1cm4gYiYmYi5PW2FdfSxjb25maWd1cmFibGU6ITB9fSk7dmFyIGxkPUIoe2Fzc2lnbmVkTm9kZXM6ZnVuY3Rpb24oYSl7aWYoInNsb3QiPT09dGhpcy5sb2NhbE5hbWUpe3ZhciBiPXRoaXMuX19zaGFkeV9nZXRSb290Tm9kZSgpO2ImJnooYikmJlRjKGIpO3JldHVybihiPXYodGhpcykpPyhhJiZhLmZsYXR0ZW4/Yi5EOmIuYXNzaWduZWROb2Rlcyl8fFtdOltdfX19KTt2YXIgbWQ9d2luZG93LmRvY3VtZW50LG5kPUIoe2ltcG9ydE5vZGU6ZnVuY3Rpb24oYSxiKXtpZihhLm93bmVyRG9jdW1lbnQhPT1tZHx8InRlbXBsYXRlIj09PWEubG9jYWxOYW1lKXJldHVybiB0aGlzLl9fc2hhZHlfbmF0aXZlX2ltcG9ydE5vZGUoYSxiKTt2YXIgYz10aGlzLl9fc2hhZHlfbmF0aXZlX2ltcG9ydE5vZGUoYSwhMSk7aWYoYil7YT1hLl9fc2hhZHlfY2hpbGROb2RlcztiPTA7Zm9yKHZhciBkO2I8YS5sZW5ndGg7YisrKWQ9dGhpcy5fX3NoYWR5X2ltcG9ydE5vZGUoYVtiXSwhMCksYy5fX3NoYWR5X2FwcGVuZENoaWxkKGQpfXJldHVybiBjfX0pO3ZhciBvZD1CKHthZGRFdmVudExpc3RlbmVyOlViLmJpbmQod2luZG93KSxyZW1vdmVFdmVudExpc3RlbmVyOldiLmJpbmQod2luZG93KX0pO3ZhciBwZD17fTtPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKEhUTUxFbGVtZW50LnByb3RvdHlwZSwicGFyZW50RWxlbWVudCIpJiYocGQucGFyZW50RWxlbWVudD1DYy5wYXJlbnRFbGVtZW50KTtPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKEhUTUxFbGVtZW50LnByb3RvdHlwZSwiY29udGFpbnMiKSYmKHBkLmNvbnRhaW5zPUNjLmNvbnRhaW5zKTtPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKEhUTUxFbGVtZW50LnByb3RvdHlwZSwiY2hpbGRyZW4iKSYmKHBkLmNoaWxkcmVuPUZjLmNoaWxkcmVuKTtPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKEhUTUxFbGVtZW50LnByb3RvdHlwZSwiaW5uZXJIVE1MIikmJihwZC5pbm5lckhUTUw9TGMuaW5uZXJIVE1MKTtPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKEhUTUxFbGVtZW50LnByb3RvdHlwZSwiY2xhc3NOYW1lIikmJihwZC5jbGFzc05hbWU9amQuY2xhc3NOYW1lKTsKdmFyIHFkPXtFdmVudFRhcmdldDpbZmRdLE5vZGU6W0NjLHdpbmRvdy5FdmVudFRhcmdldD9udWxsOmZkXSxUZXh0OltnZF0sRWxlbWVudDpbamQsRmMsZ2QsIXcubXx8ImlubmVySFRNTCJpbiBFbGVtZW50LnByb3RvdHlwZT9MYzpudWxsLHdpbmRvdy5IVE1MU2xvdEVsZW1lbnQ/bnVsbDpsZF0sSFRNTEVsZW1lbnQ6W2tkLHBkXSxIVE1MU2xvdEVsZW1lbnQ6W2xkXSxEb2N1bWVudEZyYWdtZW50OltIYyxJY10sRG9jdW1lbnQ6W25kLEhjLEljLEpjXSxXaW5kb3c6W29kXX0scmQ9dy5tP251bGw6WyJpbm5lckhUTUwiLCJ0ZXh0Q29udGVudCJdO2Z1bmN0aW9uIHNkKGEpe3ZhciBiPWE/bnVsbDpyZCxjPXt9LGQ7Zm9yKGQgaW4gcWQpYy5XPXdpbmRvd1tkXSYmd2luZG93W2RdLnByb3RvdHlwZSxxZFtkXS5mb3JFYWNoKGZ1bmN0aW9uKGMpe3JldHVybiBmdW5jdGlvbihkKXtyZXR1cm4gYy5XJiZkJiZBKGMuVyxkLGEsYil9fShjKSksYz17VzpjLld9fTtpZih3LmVhKXt2YXIgU2hhZHlET009e2luVXNlOncuZWEscGF0Y2g6ZnVuY3Rpb24oYSl7RmIoYSk7RWIoYSk7cmV0dXJuIGF9LGlzU2hhZHlSb290OnosZW5xdWV1ZTpZYSxmbHVzaDpaYSxmbHVzaEluaXRpYWw6ZnVuY3Rpb24oYSl7IWEuYmEmJmEuQiYmVGMoYSl9LHNldHRpbmdzOncsZmlsdGVyTXV0YXRpb25zOmRiLG9ic2VydmVDaGlsZHJlbjpiYix1bm9ic2VydmVDaGlsZHJlbjpjYixkZWZlckNvbm5lY3Rpb25DYWxsYmFja3M6dy5kZWZlckNvbm5lY3Rpb25DYWxsYmFja3MscHJlZmVyUGVyZm9ybWFuY2U6dy5wcmVmZXJQZXJmb3JtYW5jZSxoYW5kbGVzRHluYW1pY1Njb3Bpbmc6ITAsd3JhcDp3Lko/ZWQ6ZnVuY3Rpb24oYSl7cmV0dXJuIGF9LFdyYXBwZXI6Y2QsY29tcG9zZWRQYXRoOk1iLG5vUGF0Y2g6dy5KLG5hdGl2ZU1ldGhvZHM6cWIsbmF0aXZlVHJlZTpyYn07d2luZG93LlNoYWR5RE9NPVNoYWR5RE9NO3liKCk7c2QoIl9fc2hhZHlfIik7T2JqZWN0LmRlZmluZVByb3BlcnR5KGRvY3VtZW50LAoiX2FjdGl2ZUVsZW1lbnQiLEpjLmFjdGl2ZUVsZW1lbnQpO0EoV2luZG93LnByb3RvdHlwZSxvZCwiX19zaGFkeV8iKTt3Lkp8fChzZCgpLGJjKCkpO1hiKCk7d2luZG93LkV2ZW50PVpiO3dpbmRvdy5DdXN0b21FdmVudD0kYjt3aW5kb3cuTW91c2VFdmVudD1hYzt3aW5kb3cuU2hhZG93Um9vdD1TY307dmFyIHRkPW5ldyBTZXQoImFubm90YXRpb24teG1sIGNvbG9yLXByb2ZpbGUgZm9udC1mYWNlIGZvbnQtZmFjZS1zcmMgZm9udC1mYWNlLXVyaSBmb250LWZhY2UtZm9ybWF0IGZvbnQtZmFjZS1uYW1lIG1pc3NpbmctZ2x5cGgiLnNwbGl0KCIgIikpO2Z1bmN0aW9uIHVkKGEpe3ZhciBiPXRkLmhhcyhhKTthPS9eW2Etel1bLjAtOV9hLXpdKi1bXC0uMC05X2Etel0qJC8udGVzdChhKTtyZXR1cm4hYiYmYX1mdW5jdGlvbiBIKGEpe3ZhciBiPWEuaXNDb25uZWN0ZWQ7aWYodm9pZCAwIT09YilyZXR1cm4gYjtmb3IoO2EmJiEoYS5fX0NFX2lzSW1wb3J0RG9jdW1lbnR8fGEgaW5zdGFuY2VvZiBEb2N1bWVudCk7KWE9YS5wYXJlbnROb2RlfHwod2luZG93LlNoYWRvd1Jvb3QmJmEgaW5zdGFuY2VvZiBTaGFkb3dSb290P2EuaG9zdDp2b2lkIDApO3JldHVybiEoIWF8fCEoYS5fX0NFX2lzSW1wb3J0RG9jdW1lbnR8fGEgaW5zdGFuY2VvZiBEb2N1bWVudCkpfQpmdW5jdGlvbiB2ZChhLGIpe2Zvcig7YiYmYiE9PWEmJiFiLm5leHRTaWJsaW5nOyliPWIucGFyZW50Tm9kZTtyZXR1cm4gYiYmYiE9PWE/Yi5uZXh0U2libGluZzpudWxsfQpmdW5jdGlvbiB3ZChhLGIsYyl7Yz12b2lkIDA9PT1jP25ldyBTZXQ6Yztmb3IodmFyIGQ9YTtkOyl7aWYoZC5ub2RlVHlwZT09PU5vZGUuRUxFTUVOVF9OT0RFKXt2YXIgZT1kO2IoZSk7dmFyIGY9ZS5sb2NhbE5hbWU7aWYoImxpbmsiPT09ZiYmImltcG9ydCI9PT1lLmdldEF0dHJpYnV0ZSgicmVsIikpe2Q9ZS5pbXBvcnQ7aWYoZCBpbnN0YW5jZW9mIE5vZGUmJiFjLmhhcyhkKSlmb3IoYy5hZGQoZCksZD1kLmZpcnN0Q2hpbGQ7ZDtkPWQubmV4dFNpYmxpbmcpd2QoZCxiLGMpO2Q9dmQoYSxlKTtjb250aW51ZX1lbHNlIGlmKCJ0ZW1wbGF0ZSI9PT1mKXtkPXZkKGEsZSk7Y29udGludWV9aWYoZT1lLl9fQ0Vfc2hhZG93Um9vdClmb3IoZT1lLmZpcnN0Q2hpbGQ7ZTtlPWUubmV4dFNpYmxpbmcpd2QoZSxiLGMpfWQ9ZC5maXJzdENoaWxkP2QuZmlyc3RDaGlsZDp2ZChhLGQpfX1mdW5jdGlvbiBJKGEsYixjKXthW2JdPWN9O2Z1bmN0aW9uIHhkKCl7dGhpcy5hPW5ldyBNYXA7dGhpcy5nPW5ldyBNYXA7dGhpcy5mPVtdO3RoaXMuYz0hMX1mdW5jdGlvbiB5ZChhLGIsYyl7YS5hLnNldChiLGMpO2EuZy5zZXQoYy5jb25zdHJ1Y3RvckZ1bmN0aW9uLGMpfWZ1bmN0aW9uIHpkKGEsYil7YS5jPSEwO2EuZi5wdXNoKGIpfWZ1bmN0aW9uIEFkKGEsYil7YS5jJiZ3ZChiLGZ1bmN0aW9uKGIpe3JldHVybiBhLmIoYil9KX14ZC5wcm90b3R5cGUuYj1mdW5jdGlvbihhKXtpZih0aGlzLmMmJiFhLl9fQ0VfcGF0Y2hlZCl7YS5fX0NFX3BhdGNoZWQ9ITA7Zm9yKHZhciBiPTA7Yjx0aGlzLmYubGVuZ3RoO2IrKyl0aGlzLmZbYl0oYSl9fTtmdW5jdGlvbiBKKGEsYil7dmFyIGM9W107d2QoYixmdW5jdGlvbihhKXtyZXR1cm4gYy5wdXNoKGEpfSk7Zm9yKGI9MDtiPGMubGVuZ3RoO2IrKyl7dmFyIGQ9Y1tiXTsxPT09ZC5fX0NFX3N0YXRlP2EuY29ubmVjdGVkQ2FsbGJhY2soZCk6QmQoYSxkKX19CmZ1bmN0aW9uIEsoYSxiKXt2YXIgYz1bXTt3ZChiLGZ1bmN0aW9uKGEpe3JldHVybiBjLnB1c2goYSl9KTtmb3IoYj0wO2I8Yy5sZW5ndGg7YisrKXt2YXIgZD1jW2JdOzE9PT1kLl9fQ0Vfc3RhdGUmJmEuZGlzY29ubmVjdGVkQ2FsbGJhY2soZCl9fQpmdW5jdGlvbiBMKGEsYixjKXtjPXZvaWQgMD09PWM/e306Yzt2YXIgZD1jLlhhfHxuZXcgU2V0LGU9Yy5ZfHxmdW5jdGlvbihiKXtyZXR1cm4gQmQoYSxiKX0sZj1bXTt3ZChiLGZ1bmN0aW9uKGIpe2lmKCJsaW5rIj09PWIubG9jYWxOYW1lJiYiaW1wb3J0Ij09PWIuZ2V0QXR0cmlidXRlKCJyZWwiKSl7dmFyIGM9Yi5pbXBvcnQ7YyBpbnN0YW5jZW9mIE5vZGUmJihjLl9fQ0VfaXNJbXBvcnREb2N1bWVudD0hMCxjLl9fQ0VfaGFzUmVnaXN0cnk9ITApO2MmJiJjb21wbGV0ZSI9PT1jLnJlYWR5U3RhdGU/Yy5fX0NFX2RvY3VtZW50TG9hZEhhbmRsZWQ9ITA6Yi5hZGRFdmVudExpc3RlbmVyKCJsb2FkIixmdW5jdGlvbigpe3ZhciBjPWIuaW1wb3J0O2lmKCFjLl9fQ0VfZG9jdW1lbnRMb2FkSGFuZGxlZCl7Yy5fX0NFX2RvY3VtZW50TG9hZEhhbmRsZWQ9ITA7dmFyIGY9bmV3IFNldChkKTtmLmRlbGV0ZShjKTtMKGEsYyx7WGE6ZixZOmV9KX19KX1lbHNlIGYucHVzaChiKX0sZCk7aWYoYS5jKWZvcihiPQowO2I8Zi5sZW5ndGg7YisrKWEuYihmW2JdKTtmb3IoYj0wO2I8Zi5sZW5ndGg7YisrKWUoZltiXSl9CmZ1bmN0aW9uIEJkKGEsYil7aWYodm9pZCAwPT09Yi5fX0NFX3N0YXRlKXt2YXIgYz1iLm93bmVyRG9jdW1lbnQ7aWYoYy5kZWZhdWx0Vmlld3x8Yy5fX0NFX2lzSW1wb3J0RG9jdW1lbnQmJmMuX19DRV9oYXNSZWdpc3RyeSlpZihjPWEuYS5nZXQoYi5sb2NhbE5hbWUpKXtjLmNvbnN0cnVjdGlvblN0YWNrLnB1c2goYik7dmFyIGQ9Yy5jb25zdHJ1Y3RvckZ1bmN0aW9uO3RyeXt0cnl7aWYobmV3IGQhPT1iKXRocm93IEVycm9yKCJUaGUgY3VzdG9tIGVsZW1lbnQgY29uc3RydWN0b3IgZGlkIG5vdCBwcm9kdWNlIHRoZSBlbGVtZW50IGJlaW5nIHVwZ3JhZGVkLiIpO31maW5hbGx5e2MuY29uc3RydWN0aW9uU3RhY2sucG9wKCl9fWNhdGNoKGcpe3Rocm93IGIuX19DRV9zdGF0ZT0yLGc7fWIuX19DRV9zdGF0ZT0xO2IuX19DRV9kZWZpbml0aW9uPWM7aWYoYy5hdHRyaWJ1dGVDaGFuZ2VkQ2FsbGJhY2spZm9yKGM9Yy5vYnNlcnZlZEF0dHJpYnV0ZXMsZD0wO2Q8Yy5sZW5ndGg7ZCsrKXt2YXIgZT0KY1tkXSxmPWIuZ2V0QXR0cmlidXRlKGUpO251bGwhPT1mJiZhLmF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFjayhiLGUsbnVsbCxmLG51bGwpfUgoYikmJmEuY29ubmVjdGVkQ2FsbGJhY2soYil9fX14ZC5wcm90b3R5cGUuY29ubmVjdGVkQ2FsbGJhY2s9ZnVuY3Rpb24oYSl7dmFyIGI9YS5fX0NFX2RlZmluaXRpb247Yi5jb25uZWN0ZWRDYWxsYmFjayYmYi5jb25uZWN0ZWRDYWxsYmFjay5jYWxsKGEpfTt4ZC5wcm90b3R5cGUuZGlzY29ubmVjdGVkQ2FsbGJhY2s9ZnVuY3Rpb24oYSl7dmFyIGI9YS5fX0NFX2RlZmluaXRpb247Yi5kaXNjb25uZWN0ZWRDYWxsYmFjayYmYi5kaXNjb25uZWN0ZWRDYWxsYmFjay5jYWxsKGEpfTsKeGQucHJvdG90eXBlLmF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFjaz1mdW5jdGlvbihhLGIsYyxkLGUpe3ZhciBmPWEuX19DRV9kZWZpbml0aW9uO2YuYXR0cmlidXRlQ2hhbmdlZENhbGxiYWNrJiYtMTxmLm9ic2VydmVkQXR0cmlidXRlcy5pbmRleE9mKGIpJiZmLmF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFjay5jYWxsKGEsYixjLGQsZSl9O2Z1bmN0aW9uIENkKGEpe3ZhciBiPWRvY3VtZW50O3RoaXMuYj1hO3RoaXMuYT1iO3RoaXMuRj12b2lkIDA7TCh0aGlzLmIsdGhpcy5hKTsibG9hZGluZyI9PT10aGlzLmEucmVhZHlTdGF0ZSYmKHRoaXMuRj1uZXcgTXV0YXRpb25PYnNlcnZlcih0aGlzLmMuYmluZCh0aGlzKSksdGhpcy5GLm9ic2VydmUodGhpcy5hLHtjaGlsZExpc3Q6ITAsc3VidHJlZTohMH0pKX1mdW5jdGlvbiBEZChhKXthLkYmJmEuRi5kaXNjb25uZWN0KCl9Q2QucHJvdG90eXBlLmM9ZnVuY3Rpb24oYSl7dmFyIGI9dGhpcy5hLnJlYWR5U3RhdGU7ImludGVyYWN0aXZlIiE9PWImJiJjb21wbGV0ZSIhPT1ifHxEZCh0aGlzKTtmb3IoYj0wO2I8YS5sZW5ndGg7YisrKWZvcih2YXIgYz1hW2JdLmFkZGVkTm9kZXMsZD0wO2Q8Yy5sZW5ndGg7ZCsrKUwodGhpcy5iLGNbZF0pfTtmdW5jdGlvbiBFZCgpe3ZhciBhPXRoaXM7dGhpcy5hPXRoaXMuaD12b2lkIDA7dGhpcy5iPW5ldyBQcm9taXNlKGZ1bmN0aW9uKGIpe2EuYT1iO2EuaCYmYihhLmgpfSl9RWQucHJvdG90eXBlLnJlc29sdmU9ZnVuY3Rpb24oYSl7aWYodGhpcy5oKXRocm93IEVycm9yKCJBbHJlYWR5IHJlc29sdmVkLiIpO3RoaXMuaD1hO3RoaXMuYSYmdGhpcy5hKGEpfTtmdW5jdGlvbiBOKGEpe3RoaXMuYz0hMTt0aGlzLmE9YTt0aGlzLmw9bmV3IE1hcDt0aGlzLmY9ZnVuY3Rpb24oYSl7cmV0dXJuIGEoKX07dGhpcy5iPSExO3RoaXMuZz1bXTt0aGlzLmRhPW5ldyBDZChhKX1uPU4ucHJvdG90eXBlOwpuLnNhPWZ1bmN0aW9uKGEsYil7dmFyIGM9dGhpcztpZighKGIgaW5zdGFuY2VvZiBGdW5jdGlvbikpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ3VzdG9tIGVsZW1lbnQgY29uc3RydWN0b3JzIG11c3QgYmUgZnVuY3Rpb25zLiIpO2lmKCF1ZChhKSl0aHJvdyBuZXcgU3ludGF4RXJyb3IoIlRoZSBlbGVtZW50IG5hbWUgJyIrYSsiJyBpcyBub3QgdmFsaWQuIik7aWYodGhpcy5hLmEuZ2V0KGEpKXRocm93IEVycm9yKCJBIGN1c3RvbSBlbGVtZW50IHdpdGggbmFtZSAnIithKyInIGhhcyBhbHJlYWR5IGJlZW4gZGVmaW5lZC4iKTtpZih0aGlzLmMpdGhyb3cgRXJyb3IoIkEgY3VzdG9tIGVsZW1lbnQgaXMgYWxyZWFkeSBiZWluZyBkZWZpbmVkLiIpO3RoaXMuYz0hMDt0cnl7dmFyIGQ9ZnVuY3Rpb24oYSl7dmFyIGI9ZVthXTtpZih2b2lkIDAhPT1iJiYhKGIgaW5zdGFuY2VvZiBGdW5jdGlvbikpdGhyb3cgRXJyb3IoIlRoZSAnIithKyInIGNhbGxiYWNrIG11c3QgYmUgYSBmdW5jdGlvbi4iKTsKcmV0dXJuIGJ9LGU9Yi5wcm90b3R5cGU7aWYoIShlIGluc3RhbmNlb2YgT2JqZWN0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJUaGUgY3VzdG9tIGVsZW1lbnQgY29uc3RydWN0b3IncyBwcm90b3R5cGUgaXMgbm90IGFuIG9iamVjdC4iKTt2YXIgZj1kKCJjb25uZWN0ZWRDYWxsYmFjayIpO3ZhciBnPWQoImRpc2Nvbm5lY3RlZENhbGxiYWNrIik7dmFyIGg9ZCgiYWRvcHRlZENhbGxiYWNrIik7dmFyIGs9ZCgiYXR0cmlidXRlQ2hhbmdlZENhbGxiYWNrIik7dmFyIGw9Yi5vYnNlcnZlZEF0dHJpYnV0ZXN8fFtdfWNhdGNoKG0pe3JldHVybn1maW5hbGx5e3RoaXMuYz0hMX1iPXtsb2NhbE5hbWU6YSxjb25zdHJ1Y3RvckZ1bmN0aW9uOmIsY29ubmVjdGVkQ2FsbGJhY2s6ZixkaXNjb25uZWN0ZWRDYWxsYmFjazpnLGFkb3B0ZWRDYWxsYmFjazpoLGF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFjazprLG9ic2VydmVkQXR0cmlidXRlczpsLGNvbnN0cnVjdGlvblN0YWNrOltdfTt5ZCh0aGlzLmEsCmEsYik7dGhpcy5nLnB1c2goYik7dGhpcy5ifHwodGhpcy5iPSEwLHRoaXMuZihmdW5jdGlvbigpe3JldHVybiBGZChjKX0pKX07bi5ZPWZ1bmN0aW9uKGEpe0wodGhpcy5hLGEpfTsKZnVuY3Rpb24gRmQoYSl7aWYoITEhPT1hLmIpe2EuYj0hMTtmb3IodmFyIGI9YS5nLGM9W10sZD1uZXcgTWFwLGU9MDtlPGIubGVuZ3RoO2UrKylkLnNldChiW2VdLmxvY2FsTmFtZSxbXSk7TChhLmEsZG9jdW1lbnQse1k6ZnVuY3Rpb24oYil7aWYodm9pZCAwPT09Yi5fX0NFX3N0YXRlKXt2YXIgZT1iLmxvY2FsTmFtZSxmPWQuZ2V0KGUpO2Y/Zi5wdXNoKGIpOmEuYS5hLmdldChlKSYmYy5wdXNoKGIpfX19KTtmb3IoZT0wO2U8Yy5sZW5ndGg7ZSsrKUJkKGEuYSxjW2VdKTtmb3IoOzA8Yi5sZW5ndGg7KXt2YXIgZj1iLnNoaWZ0KCk7ZT1mLmxvY2FsTmFtZTtmPWQuZ2V0KGYubG9jYWxOYW1lKTtmb3IodmFyIGc9MDtnPGYubGVuZ3RoO2crKylCZChhLmEsZltnXSk7KGU9YS5sLmdldChlKSkmJmUucmVzb2x2ZSh2b2lkIDApfX19bi5nZXQ9ZnVuY3Rpb24oYSl7aWYoYT10aGlzLmEuYS5nZXQoYSkpcmV0dXJuIGEuY29uc3RydWN0b3JGdW5jdGlvbn07Cm4udGE9ZnVuY3Rpb24oYSl7aWYoIXVkKGEpKXJldHVybiBQcm9taXNlLnJlamVjdChuZXcgU3ludGF4RXJyb3IoIiciK2ErIicgaXMgbm90IGEgdmFsaWQgY3VzdG9tIGVsZW1lbnQgbmFtZS4iKSk7dmFyIGI9dGhpcy5sLmdldChhKTtpZihiKXJldHVybiBiLmI7Yj1uZXcgRWQ7dGhpcy5sLnNldChhLGIpO3RoaXMuYS5hLmdldChhKSYmIXRoaXMuZy5zb21lKGZ1bmN0aW9uKGIpe3JldHVybiBiLmxvY2FsTmFtZT09PWF9KSYmYi5yZXNvbHZlKHZvaWQgMCk7cmV0dXJuIGIuYn07bi5QYT1mdW5jdGlvbihhKXtEZCh0aGlzLmRhKTt2YXIgYj10aGlzLmY7dGhpcy5mPWZ1bmN0aW9uKGMpe3JldHVybiBhKGZ1bmN0aW9uKCl7cmV0dXJuIGIoYyl9KX19O3dpbmRvdy5DdXN0b21FbGVtZW50UmVnaXN0cnk9TjtOLnByb3RvdHlwZS5kZWZpbmU9Ti5wcm90b3R5cGUuc2E7Ti5wcm90b3R5cGUudXBncmFkZT1OLnByb3RvdHlwZS5ZO04ucHJvdG90eXBlLmdldD1OLnByb3RvdHlwZS5nZXQ7Ck4ucHJvdG90eXBlLndoZW5EZWZpbmVkPU4ucHJvdG90eXBlLnRhO04ucHJvdG90eXBlLnBvbHlmaWxsV3JhcEZsdXNoQ2FsbGJhY2s9Ti5wcm90b3R5cGUuUGE7dmFyIEdkPXdpbmRvdy5Eb2N1bWVudC5wcm90b3R5cGUuY3JlYXRlRWxlbWVudCxIZD13aW5kb3cuRG9jdW1lbnQucHJvdG90eXBlLmNyZWF0ZUVsZW1lbnROUyxJZD13aW5kb3cuRG9jdW1lbnQucHJvdG90eXBlLmltcG9ydE5vZGUsSmQ9d2luZG93LkRvY3VtZW50LnByb3RvdHlwZS5wcmVwZW5kLEtkPXdpbmRvdy5Eb2N1bWVudC5wcm90b3R5cGUuYXBwZW5kLExkPXdpbmRvdy5Eb2N1bWVudEZyYWdtZW50LnByb3RvdHlwZS5wcmVwZW5kLE1kPXdpbmRvdy5Eb2N1bWVudEZyYWdtZW50LnByb3RvdHlwZS5hcHBlbmQsTmQ9d2luZG93Lk5vZGUucHJvdG90eXBlLmNsb25lTm9kZSxPZD13aW5kb3cuTm9kZS5wcm90b3R5cGUuYXBwZW5kQ2hpbGQsUGQ9d2luZG93Lk5vZGUucHJvdG90eXBlLmluc2VydEJlZm9yZSxRZD13aW5kb3cuTm9kZS5wcm90b3R5cGUucmVtb3ZlQ2hpbGQsUmQ9d2luZG93Lk5vZGUucHJvdG90eXBlLnJlcGxhY2VDaGlsZCxTZD1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHdpbmRvdy5Ob2RlLnByb3RvdHlwZSwKInRleHRDb250ZW50IiksVGQ9d2luZG93LkVsZW1lbnQucHJvdG90eXBlLmF0dGFjaFNoYWRvdyxVZD1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHdpbmRvdy5FbGVtZW50LnByb3RvdHlwZSwiaW5uZXJIVE1MIiksVmQ9d2luZG93LkVsZW1lbnQucHJvdG90eXBlLmdldEF0dHJpYnV0ZSxXZD13aW5kb3cuRWxlbWVudC5wcm90b3R5cGUuc2V0QXR0cmlidXRlLFhkPXdpbmRvdy5FbGVtZW50LnByb3RvdHlwZS5yZW1vdmVBdHRyaWJ1dGUsWWQ9d2luZG93LkVsZW1lbnQucHJvdG90eXBlLmdldEF0dHJpYnV0ZU5TLFpkPXdpbmRvdy5FbGVtZW50LnByb3RvdHlwZS5zZXRBdHRyaWJ1dGVOUywkZD13aW5kb3cuRWxlbWVudC5wcm90b3R5cGUucmVtb3ZlQXR0cmlidXRlTlMsYWU9d2luZG93LkVsZW1lbnQucHJvdG90eXBlLmluc2VydEFkamFjZW50RWxlbWVudCxiZT13aW5kb3cuRWxlbWVudC5wcm90b3R5cGUuaW5zZXJ0QWRqYWNlbnRIVE1MLGNlPXdpbmRvdy5FbGVtZW50LnByb3RvdHlwZS5wcmVwZW5kLApkZT13aW5kb3cuRWxlbWVudC5wcm90b3R5cGUuYXBwZW5kLGVlPXdpbmRvdy5FbGVtZW50LnByb3RvdHlwZS5iZWZvcmUsZmU9d2luZG93LkVsZW1lbnQucHJvdG90eXBlLmFmdGVyLGdlPXdpbmRvdy5FbGVtZW50LnByb3RvdHlwZS5yZXBsYWNlV2l0aCxoZT13aW5kb3cuRWxlbWVudC5wcm90b3R5cGUucmVtb3ZlLGllPXdpbmRvdy5IVE1MRWxlbWVudCxqZT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHdpbmRvdy5IVE1MRWxlbWVudC5wcm90b3R5cGUsImlubmVySFRNTCIpLGtlPXdpbmRvdy5IVE1MRWxlbWVudC5wcm90b3R5cGUuaW5zZXJ0QWRqYWNlbnRFbGVtZW50LGxlPXdpbmRvdy5IVE1MRWxlbWVudC5wcm90b3R5cGUuaW5zZXJ0QWRqYWNlbnRIVE1MO3ZhciBtZT1uZXcgZnVuY3Rpb24oKXt9O2Z1bmN0aW9uIG5lKCl7dmFyIGE9b2U7d2luZG93LkhUTUxFbGVtZW50PWZ1bmN0aW9uKCl7ZnVuY3Rpb24gYigpe3ZhciBiPXRoaXMuY29uc3RydWN0b3IsZD1hLmcuZ2V0KGIpO2lmKCFkKXRocm93IEVycm9yKCJUaGUgY3VzdG9tIGVsZW1lbnQgYmVpbmcgY29uc3RydWN0ZWQgd2FzIG5vdCByZWdpc3RlcmVkIHdpdGggYGN1c3RvbUVsZW1lbnRzYC4iKTt2YXIgZT1kLmNvbnN0cnVjdGlvblN0YWNrO2lmKDA9PT1lLmxlbmd0aClyZXR1cm4gZT1HZC5jYWxsKGRvY3VtZW50LGQubG9jYWxOYW1lKSxPYmplY3Quc2V0UHJvdG90eXBlT2YoZSxiLnByb3RvdHlwZSksZS5fX0NFX3N0YXRlPTEsZS5fX0NFX2RlZmluaXRpb249ZCxhLmIoZSksZTtkPWUubGVuZ3RoLTE7dmFyIGY9ZVtkXTtpZihmPT09bWUpdGhyb3cgRXJyb3IoIlRoZSBIVE1MRWxlbWVudCBjb25zdHJ1Y3RvciB3YXMgZWl0aGVyIGNhbGxlZCByZWVudHJhbnRseSBmb3IgdGhpcyBjb25zdHJ1Y3RvciBvciBjYWxsZWQgbXVsdGlwbGUgdGltZXMuIik7CmVbZF09bWU7T2JqZWN0LnNldFByb3RvdHlwZU9mKGYsYi5wcm90b3R5cGUpO2EuYihmKTtyZXR1cm4gZn1iLnByb3RvdHlwZT1pZS5wcm90b3R5cGU7T2JqZWN0LmRlZmluZVByb3BlcnR5KGIucHJvdG90eXBlLCJjb25zdHJ1Y3RvciIse3dyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiExLHZhbHVlOmJ9KTtyZXR1cm4gYn0oKX07ZnVuY3Rpb24gcGUoYSxiLGMpe2Z1bmN0aW9uIGQoYil7cmV0dXJuIGZ1bmN0aW9uKGMpe2Zvcih2YXIgZD1bXSxlPTA7ZTxhcmd1bWVudHMubGVuZ3RoOysrZSlkW2VdPWFyZ3VtZW50c1tlXTtlPVtdO2Zvcih2YXIgZj1bXSxsPTA7bDxkLmxlbmd0aDtsKyspe3ZhciBtPWRbbF07bSBpbnN0YW5jZW9mIEVsZW1lbnQmJkgobSkmJmYucHVzaChtKTtpZihtIGluc3RhbmNlb2YgRG9jdW1lbnRGcmFnbWVudClmb3IobT1tLmZpcnN0Q2hpbGQ7bTttPW0ubmV4dFNpYmxpbmcpZS5wdXNoKG0pO2Vsc2UgZS5wdXNoKG0pfWIuYXBwbHkodGhpcyxkKTtmb3IoZD0wO2Q8Zi5sZW5ndGg7ZCsrKUsoYSxmW2RdKTtpZihIKHRoaXMpKWZvcihkPTA7ZDxlLmxlbmd0aDtkKyspZj1lW2RdLGYgaW5zdGFuY2VvZiBFbGVtZW50JiZKKGEsZil9fXZvaWQgMCE9PWMuViYmKGIucHJlcGVuZD1kKGMuVikpO3ZvaWQgMCE9PWMuYXBwZW5kJiYoYi5hcHBlbmQ9ZChjLmFwcGVuZCkpfTtmdW5jdGlvbiBxZSgpe3ZhciBhPW9lO0koRG9jdW1lbnQucHJvdG90eXBlLCJjcmVhdGVFbGVtZW50IixmdW5jdGlvbihiKXtpZih0aGlzLl9fQ0VfaGFzUmVnaXN0cnkpe3ZhciBjPWEuYS5nZXQoYik7aWYoYylyZXR1cm4gbmV3IGMuY29uc3RydWN0b3JGdW5jdGlvbn1iPUdkLmNhbGwodGhpcyxiKTthLmIoYik7cmV0dXJuIGJ9KTtJKERvY3VtZW50LnByb3RvdHlwZSwiaW1wb3J0Tm9kZSIsZnVuY3Rpb24oYixjKXtiPUlkLmNhbGwodGhpcyxiLCEhYyk7dGhpcy5fX0NFX2hhc1JlZ2lzdHJ5P0woYSxiKTpBZChhLGIpO3JldHVybiBifSk7SShEb2N1bWVudC5wcm90b3R5cGUsImNyZWF0ZUVsZW1lbnROUyIsZnVuY3Rpb24oYixjKXtpZih0aGlzLl9fQ0VfaGFzUmVnaXN0cnkmJihudWxsPT09Ynx8Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPT09Yikpe3ZhciBkPWEuYS5nZXQoYyk7aWYoZClyZXR1cm4gbmV3IGQuY29uc3RydWN0b3JGdW5jdGlvbn1iPUhkLmNhbGwodGhpcywKYixjKTthLmIoYik7cmV0dXJuIGJ9KTtwZShhLERvY3VtZW50LnByb3RvdHlwZSx7VjpKZCxhcHBlbmQ6S2R9KX07ZnVuY3Rpb24gcmUoKXtmdW5jdGlvbiBhKGEsZCl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGEsInRleHRDb250ZW50Iix7ZW51bWVyYWJsZTpkLmVudW1lcmFibGUsY29uZmlndXJhYmxlOiEwLGdldDpkLmdldCxzZXQ6ZnVuY3Rpb24oYSl7aWYodGhpcy5ub2RlVHlwZT09PU5vZGUuVEVYVF9OT0RFKWQuc2V0LmNhbGwodGhpcyxhKTtlbHNle3ZhciBjPXZvaWQgMDtpZih0aGlzLmZpcnN0Q2hpbGQpe3ZhciBlPXRoaXMuY2hpbGROb2RlcyxoPWUubGVuZ3RoO2lmKDA8aCYmSCh0aGlzKSl7Yz1BcnJheShoKTtmb3IodmFyIGs9MDtrPGg7aysrKWNba109ZVtrXX19ZC5zZXQuY2FsbCh0aGlzLGEpO2lmKGMpZm9yKGE9MDthPGMubGVuZ3RoO2ErKylLKGIsY1thXSl9fX0pfXZhciBiPW9lO0koTm9kZS5wcm90b3R5cGUsImluc2VydEJlZm9yZSIsZnVuY3Rpb24oYSxkKXtpZihhIGluc3RhbmNlb2YgRG9jdW1lbnRGcmFnbWVudCl7dmFyIGM9QXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGEuY2hpbGROb2Rlcyk7CmE9UGQuY2FsbCh0aGlzLGEsZCk7aWYoSCh0aGlzKSlmb3IoZD0wO2Q8Yy5sZW5ndGg7ZCsrKUooYixjW2RdKTtyZXR1cm4gYX1jPUgoYSk7ZD1QZC5jYWxsKHRoaXMsYSxkKTtjJiZLKGIsYSk7SCh0aGlzKSYmSihiLGEpO3JldHVybiBkfSk7SShOb2RlLnByb3RvdHlwZSwiYXBwZW5kQ2hpbGQiLGZ1bmN0aW9uKGEpe2lmKGEgaW5zdGFuY2VvZiBEb2N1bWVudEZyYWdtZW50KXt2YXIgYz1BcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYS5jaGlsZE5vZGVzKTthPU9kLmNhbGwodGhpcyxhKTtpZihIKHRoaXMpKWZvcih2YXIgZT0wO2U8Yy5sZW5ndGg7ZSsrKUooYixjW2VdKTtyZXR1cm4gYX1jPUgoYSk7ZT1PZC5jYWxsKHRoaXMsYSk7YyYmSyhiLGEpO0godGhpcykmJkooYixhKTtyZXR1cm4gZX0pO0koTm9kZS5wcm90b3R5cGUsImNsb25lTm9kZSIsZnVuY3Rpb24oYSl7YT1OZC5jYWxsKHRoaXMsISFhKTt0aGlzLm93bmVyRG9jdW1lbnQuX19DRV9oYXNSZWdpc3RyeT9MKGIsYSk6CkFkKGIsYSk7cmV0dXJuIGF9KTtJKE5vZGUucHJvdG90eXBlLCJyZW1vdmVDaGlsZCIsZnVuY3Rpb24oYSl7dmFyIGM9SChhKSxlPVFkLmNhbGwodGhpcyxhKTtjJiZLKGIsYSk7cmV0dXJuIGV9KTtJKE5vZGUucHJvdG90eXBlLCJyZXBsYWNlQ2hpbGQiLGZ1bmN0aW9uKGEsZCl7aWYoYSBpbnN0YW5jZW9mIERvY3VtZW50RnJhZ21lbnQpe3ZhciBjPUFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhLmNoaWxkTm9kZXMpO2E9UmQuY2FsbCh0aGlzLGEsZCk7aWYoSCh0aGlzKSlmb3IoSyhiLGQpLGQ9MDtkPGMubGVuZ3RoO2QrKylKKGIsY1tkXSk7cmV0dXJuIGF9Yz1IKGEpO3ZhciBmPVJkLmNhbGwodGhpcyxhLGQpLGc9SCh0aGlzKTtnJiZLKGIsZCk7YyYmSyhiLGEpO2cmJkooYixhKTtyZXR1cm4gZn0pO1NkJiZTZC5nZXQ/YShOb2RlLnByb3RvdHlwZSxTZCk6emQoYixmdW5jdGlvbihiKXthKGIse2VudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe2Zvcih2YXIgYT0KW10sYj0wO2I8dGhpcy5jaGlsZE5vZGVzLmxlbmd0aDtiKyspYS5wdXNoKHRoaXMuY2hpbGROb2Rlc1tiXS50ZXh0Q29udGVudCk7cmV0dXJuIGEuam9pbigiIil9LHNldDpmdW5jdGlvbihhKXtmb3IoO3RoaXMuZmlyc3RDaGlsZDspUWQuY2FsbCh0aGlzLHRoaXMuZmlyc3RDaGlsZCk7T2QuY2FsbCh0aGlzLGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGEpKX19KX0pfTtmdW5jdGlvbiBzZShhKXtmdW5jdGlvbiBiKGIpe3JldHVybiBmdW5jdGlvbihjKXtmb3IodmFyIGQ9W10sZT0wO2U8YXJndW1lbnRzLmxlbmd0aDsrK2UpZFtlXT1hcmd1bWVudHNbZV07ZT1bXTtmb3IodmFyIGg9W10saz0wO2s8ZC5sZW5ndGg7aysrKXt2YXIgbD1kW2tdO2wgaW5zdGFuY2VvZiBFbGVtZW50JiZIKGwpJiZoLnB1c2gobCk7aWYobCBpbnN0YW5jZW9mIERvY3VtZW50RnJhZ21lbnQpZm9yKGw9bC5maXJzdENoaWxkO2w7bD1sLm5leHRTaWJsaW5nKWUucHVzaChsKTtlbHNlIGUucHVzaChsKX1iLmFwcGx5KHRoaXMsZCk7Zm9yKGQ9MDtkPGgubGVuZ3RoO2QrKylLKGEsaFtkXSk7aWYoSCh0aGlzKSlmb3IoZD0wO2Q8ZS5sZW5ndGg7ZCsrKWg9ZVtkXSxoIGluc3RhbmNlb2YgRWxlbWVudCYmSihhLGgpfX12YXIgYz1FbGVtZW50LnByb3RvdHlwZTt2b2lkIDAhPT1lZSYmKGMuYmVmb3JlPWIoZWUpKTt2b2lkIDAhPT1lZSYmKGMuYWZ0ZXI9YihmZSkpO3ZvaWQgMCE9PWdlJiYKSShjLCJyZXBsYWNlV2l0aCIsZnVuY3Rpb24oYil7Zm9yKHZhciBjPVtdLGQ9MDtkPGFyZ3VtZW50cy5sZW5ndGg7KytkKWNbZF09YXJndW1lbnRzW2RdO2Q9W107Zm9yKHZhciBnPVtdLGg9MDtoPGMubGVuZ3RoO2grKyl7dmFyIGs9Y1toXTtrIGluc3RhbmNlb2YgRWxlbWVudCYmSChrKSYmZy5wdXNoKGspO2lmKGsgaW5zdGFuY2VvZiBEb2N1bWVudEZyYWdtZW50KWZvcihrPWsuZmlyc3RDaGlsZDtrO2s9ay5uZXh0U2libGluZylkLnB1c2goayk7ZWxzZSBkLnB1c2goayl9aD1IKHRoaXMpO2dlLmFwcGx5KHRoaXMsYyk7Zm9yKGM9MDtjPGcubGVuZ3RoO2MrKylLKGEsZ1tjXSk7aWYoaClmb3IoSyhhLHRoaXMpLGM9MDtjPGQubGVuZ3RoO2MrKylnPWRbY10sZyBpbnN0YW5jZW9mIEVsZW1lbnQmJkooYSxnKX0pO3ZvaWQgMCE9PWhlJiZJKGMsInJlbW92ZSIsZnVuY3Rpb24oKXt2YXIgYj1IKHRoaXMpO2hlLmNhbGwodGhpcyk7YiYmSyhhLHRoaXMpfSl9O2Z1bmN0aW9uIHRlKCl7ZnVuY3Rpb24gYShhLGIpe09iamVjdC5kZWZpbmVQcm9wZXJ0eShhLCJpbm5lckhUTUwiLHtlbnVtZXJhYmxlOmIuZW51bWVyYWJsZSxjb25maWd1cmFibGU6ITAsZ2V0OmIuZ2V0LHNldDpmdW5jdGlvbihhKXt2YXIgYz10aGlzLGU9dm9pZCAwO0godGhpcykmJihlPVtdLHdkKHRoaXMsZnVuY3Rpb24oYSl7YSE9PWMmJmUucHVzaChhKX0pKTtiLnNldC5jYWxsKHRoaXMsYSk7aWYoZSlmb3IodmFyIGY9MDtmPGUubGVuZ3RoO2YrKyl7dmFyIGc9ZVtmXTsxPT09Zy5fX0NFX3N0YXRlJiZkLmRpc2Nvbm5lY3RlZENhbGxiYWNrKGcpfXRoaXMub3duZXJEb2N1bWVudC5fX0NFX2hhc1JlZ2lzdHJ5P0woZCx0aGlzKTpBZChkLHRoaXMpO3JldHVybiBhfX0pfWZ1bmN0aW9uIGIoYSxiKXtJKGEsImluc2VydEFkamFjZW50RWxlbWVudCIsZnVuY3Rpb24oYSxjKXt2YXIgZT1IKGMpO2E9Yi5jYWxsKHRoaXMsYSxjKTtlJiZLKGQsYyk7SChhKSYmSihkLGMpO3JldHVybiBhfSl9CmZ1bmN0aW9uIGMoYSxiKXtmdW5jdGlvbiBjKGEsYil7Zm9yKHZhciBjPVtdO2EhPT1iO2E9YS5uZXh0U2libGluZyljLnB1c2goYSk7Zm9yKGI9MDtiPGMubGVuZ3RoO2IrKylMKGQsY1tiXSl9SShhLCJpbnNlcnRBZGphY2VudEhUTUwiLGZ1bmN0aW9uKGEsZCl7YT1hLnRvTG93ZXJDYXNlKCk7aWYoImJlZm9yZWJlZ2luIj09PWEpe3ZhciBlPXRoaXMucHJldmlvdXNTaWJsaW5nO2IuY2FsbCh0aGlzLGEsZCk7YyhlfHx0aGlzLnBhcmVudE5vZGUuZmlyc3RDaGlsZCx0aGlzKX1lbHNlIGlmKCJhZnRlcmJlZ2luIj09PWEpZT10aGlzLmZpcnN0Q2hpbGQsYi5jYWxsKHRoaXMsYSxkKSxjKHRoaXMuZmlyc3RDaGlsZCxlKTtlbHNlIGlmKCJiZWZvcmVlbmQiPT09YSllPXRoaXMubGFzdENoaWxkLGIuY2FsbCh0aGlzLGEsZCksYyhlfHx0aGlzLmZpcnN0Q2hpbGQsbnVsbCk7ZWxzZSBpZigiYWZ0ZXJlbmQiPT09YSllPXRoaXMubmV4dFNpYmxpbmcsYi5jYWxsKHRoaXMsYSxkKSxjKHRoaXMubmV4dFNpYmxpbmcsCmUpO2Vsc2UgdGhyb3cgbmV3IFN5bnRheEVycm9yKCJUaGUgdmFsdWUgcHJvdmlkZWQgKCIrU3RyaW5nKGEpKyIpIGlzIG5vdCBvbmUgb2YgJ2JlZm9yZWJlZ2luJywgJ2FmdGVyYmVnaW4nLCAnYmVmb3JlZW5kJywgb3IgJ2FmdGVyZW5kJy4iKTt9KX12YXIgZD1vZTtUZCYmSShFbGVtZW50LnByb3RvdHlwZSwiYXR0YWNoU2hhZG93IixmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5fX0NFX3NoYWRvd1Jvb3Q9YT1UZC5jYWxsKHRoaXMsYSl9KTtVZCYmVWQuZ2V0P2EoRWxlbWVudC5wcm90b3R5cGUsVWQpOmplJiZqZS5nZXQ/YShIVE1MRWxlbWVudC5wcm90b3R5cGUsamUpOnpkKGQsZnVuY3Rpb24oYil7YShiLHtlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gTmQuY2FsbCh0aGlzLCEwKS5pbm5lckhUTUx9LHNldDpmdW5jdGlvbihhKXt2YXIgYj0idGVtcGxhdGUiPT09dGhpcy5sb2NhbE5hbWUsYz1iP3RoaXMuY29udGVudDp0aGlzLGQ9SGQuY2FsbChkb2N1bWVudCwKdGhpcy5uYW1lc3BhY2VVUkksdGhpcy5sb2NhbE5hbWUpO2ZvcihkLmlubmVySFRNTD1hOzA8Yy5jaGlsZE5vZGVzLmxlbmd0aDspUWQuY2FsbChjLGMuY2hpbGROb2Rlc1swXSk7Zm9yKGE9Yj9kLmNvbnRlbnQ6ZDswPGEuY2hpbGROb2Rlcy5sZW5ndGg7KU9kLmNhbGwoYyxhLmNoaWxkTm9kZXNbMF0pfX0pfSk7SShFbGVtZW50LnByb3RvdHlwZSwic2V0QXR0cmlidXRlIixmdW5jdGlvbihhLGIpe2lmKDEhPT10aGlzLl9fQ0Vfc3RhdGUpcmV0dXJuIFdkLmNhbGwodGhpcyxhLGIpO3ZhciBjPVZkLmNhbGwodGhpcyxhKTtXZC5jYWxsKHRoaXMsYSxiKTtiPVZkLmNhbGwodGhpcyxhKTtkLmF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFjayh0aGlzLGEsYyxiLG51bGwpfSk7SShFbGVtZW50LnByb3RvdHlwZSwic2V0QXR0cmlidXRlTlMiLGZ1bmN0aW9uKGEsYixjKXtpZigxIT09dGhpcy5fX0NFX3N0YXRlKXJldHVybiBaZC5jYWxsKHRoaXMsYSxiLGMpO3ZhciBlPVlkLmNhbGwodGhpcyxhLApiKTtaZC5jYWxsKHRoaXMsYSxiLGMpO2M9WWQuY2FsbCh0aGlzLGEsYik7ZC5hdHRyaWJ1dGVDaGFuZ2VkQ2FsbGJhY2sodGhpcyxiLGUsYyxhKX0pO0koRWxlbWVudC5wcm90b3R5cGUsInJlbW92ZUF0dHJpYnV0ZSIsZnVuY3Rpb24oYSl7aWYoMSE9PXRoaXMuX19DRV9zdGF0ZSlyZXR1cm4gWGQuY2FsbCh0aGlzLGEpO3ZhciBiPVZkLmNhbGwodGhpcyxhKTtYZC5jYWxsKHRoaXMsYSk7bnVsbCE9PWImJmQuYXR0cmlidXRlQ2hhbmdlZENhbGxiYWNrKHRoaXMsYSxiLG51bGwsbnVsbCl9KTtJKEVsZW1lbnQucHJvdG90eXBlLCJyZW1vdmVBdHRyaWJ1dGVOUyIsZnVuY3Rpb24oYSxiKXtpZigxIT09dGhpcy5fX0NFX3N0YXRlKXJldHVybiAkZC5jYWxsKHRoaXMsYSxiKTt2YXIgYz1ZZC5jYWxsKHRoaXMsYSxiKTskZC5jYWxsKHRoaXMsYSxiKTt2YXIgZT1ZZC5jYWxsKHRoaXMsYSxiKTtjIT09ZSYmZC5hdHRyaWJ1dGVDaGFuZ2VkQ2FsbGJhY2sodGhpcyxiLGMsZSxhKX0pO2tlP2IoSFRNTEVsZW1lbnQucHJvdG90eXBlLAprZSk6YWU/YihFbGVtZW50LnByb3RvdHlwZSxhZSk6Y29uc29sZS53YXJuKCJDdXN0b20gRWxlbWVudHM6IGBFbGVtZW50I2luc2VydEFkamFjZW50RWxlbWVudGAgd2FzIG5vdCBwYXRjaGVkLiIpO2xlP2MoSFRNTEVsZW1lbnQucHJvdG90eXBlLGxlKTpiZT9jKEVsZW1lbnQucHJvdG90eXBlLGJlKTpjb25zb2xlLndhcm4oIkN1c3RvbSBFbGVtZW50czogYEVsZW1lbnQjaW5zZXJ0QWRqYWNlbnRIVE1MYCB3YXMgbm90IHBhdGNoZWQuIik7cGUoZCxFbGVtZW50LnByb3RvdHlwZSx7VjpjZSxhcHBlbmQ6ZGV9KTtzZShkKX07dmFyIHVlPXdpbmRvdy5jdXN0b21FbGVtZW50cztpZighdWV8fHVlLmZvcmNlUG9seWZpbGx8fCJmdW5jdGlvbiIhPXR5cGVvZiB1ZS5kZWZpbmV8fCJmdW5jdGlvbiIhPXR5cGVvZiB1ZS5nZXQpe3ZhciBvZT1uZXcgeGQ7bmUoKTtxZSgpO3BlKG9lLERvY3VtZW50RnJhZ21lbnQucHJvdG90eXBlLHtWOkxkLGFwcGVuZDpNZH0pO3JlKCk7dGUoKTtkb2N1bWVudC5fX0NFX2hhc1JlZ2lzdHJ5PSEwO3ZhciBjdXN0b21FbGVtZW50cz1uZXcgTihvZSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdywiY3VzdG9tRWxlbWVudHMiLHtjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMCx2YWx1ZTpjdXN0b21FbGVtZW50c30pfTtmdW5jdGlvbiB2ZSgpe3RoaXMuZW5kPXRoaXMuc3RhcnQ9MDt0aGlzLnJ1bGVzPXRoaXMucGFyZW50PXRoaXMucHJldmlvdXM9bnVsbDt0aGlzLmNzc1RleHQ9dGhpcy5wYXJzZWRDc3NUZXh0PSIiO3RoaXMuYXRSdWxlPSExO3RoaXMudHlwZT0wO3RoaXMucGFyc2VkU2VsZWN0b3I9dGhpcy5zZWxlY3Rvcj10aGlzLmtleWZyYW1lc05hbWU9IiJ9CmZ1bmN0aW9uIHdlKGEpe2E9YS5yZXBsYWNlKHhlLCIiKS5yZXBsYWNlKHllLCIiKTt2YXIgYj16ZSxjPWEsZD1uZXcgdmU7ZC5zdGFydD0wO2QuZW5kPWMubGVuZ3RoO2Zvcih2YXIgZT1kLGY9MCxnPWMubGVuZ3RoO2Y8ZztmKyspaWYoInsiPT09Y1tmXSl7ZS5ydWxlc3x8KGUucnVsZXM9W10pO3ZhciBoPWUsaz1oLnJ1bGVzW2gucnVsZXMubGVuZ3RoLTFdfHxudWxsO2U9bmV3IHZlO2Uuc3RhcnQ9ZisxO2UucGFyZW50PWg7ZS5wcmV2aW91cz1rO2gucnVsZXMucHVzaChlKX1lbHNlIn0iPT09Y1tmXSYmKGUuZW5kPWYrMSxlPWUucGFyZW50fHxkKTtyZXR1cm4gYihkLGEpfQpmdW5jdGlvbiB6ZShhLGIpe3ZhciBjPWIuc3Vic3RyaW5nKGEuc3RhcnQsYS5lbmQtMSk7YS5wYXJzZWRDc3NUZXh0PWEuY3NzVGV4dD1jLnRyaW0oKTthLnBhcmVudCYmKGM9Yi5zdWJzdHJpbmcoYS5wcmV2aW91cz9hLnByZXZpb3VzLmVuZDphLnBhcmVudC5zdGFydCxhLnN0YXJ0LTEpLGM9QWUoYyksYz1jLnJlcGxhY2UoQmUsIiAiKSxjPWMuc3Vic3RyaW5nKGMubGFzdEluZGV4T2YoIjsiKSsxKSxjPWEucGFyc2VkU2VsZWN0b3I9YS5zZWxlY3Rvcj1jLnRyaW0oKSxhLmF0UnVsZT0wPT09Yy5pbmRleE9mKCJAIiksYS5hdFJ1bGU/MD09PWMuaW5kZXhPZigiQG1lZGlhIik/YS50eXBlPUNlOmMubWF0Y2goRGUpJiYoYS50eXBlPUVlLGEua2V5ZnJhbWVzTmFtZT1hLnNlbGVjdG9yLnNwbGl0KEJlKS5wb3AoKSk6YS50eXBlPTA9PT1jLmluZGV4T2YoIi0tIik/RmU6R2UpO2lmKGM9YS5ydWxlcylmb3IodmFyIGQ9MCxlPWMubGVuZ3RoLGY9dm9pZCAwO2Q8ZSYmKGY9Y1tkXSk7ZCsrKXplKGYsCmIpO3JldHVybiBhfWZ1bmN0aW9uIEFlKGEpe3JldHVybiBhLnJlcGxhY2UoL1xcKFswLTlhLWZdezEsNn0pXHMvZ2ksZnVuY3Rpb24oYSxjKXthPWM7Zm9yKGM9Ni1hLmxlbmd0aDtjLS07KWE9IjAiK2E7cmV0dXJuIlxcIithfSl9CmZ1bmN0aW9uIEhlKGEsYixjKXtjPXZvaWQgMD09PWM/IiI6Yzt2YXIgZD0iIjtpZihhLmNzc1RleHR8fGEucnVsZXMpe3ZhciBlPWEucnVsZXMsZjtpZihmPWUpZj1lWzBdLGY9IShmJiZmLnNlbGVjdG9yJiYwPT09Zi5zZWxlY3Rvci5pbmRleE9mKCItLSIpKTtpZihmKXtmPTA7Zm9yKHZhciBnPWUubGVuZ3RoLGg9dm9pZCAwO2Y8ZyYmKGg9ZVtmXSk7ZisrKWQ9SGUoaCxiLGQpfWVsc2UgYj9iPWEuY3NzVGV4dDooYj1hLmNzc1RleHQsYj1iLnJlcGxhY2UoSWUsIiIpLnJlcGxhY2UoSmUsIiIpLGI9Yi5yZXBsYWNlKEtlLCIiKS5yZXBsYWNlKExlLCIiKSksKGQ9Yi50cmltKCkpJiYoZD0iICAiK2QrIlxuIil9ZCYmKGEuc2VsZWN0b3ImJihjKz1hLnNlbGVjdG9yKyIge1xuIiksYys9ZCxhLnNlbGVjdG9yJiYoYys9In1cblxuIikpO3JldHVybiBjfQp2YXIgR2U9MSxFZT03LENlPTQsRmU9MUUzLHhlPS9cL1wqW14qXSpcKisoW14vKl1bXipdKlwqKykqXC8vZ2ltLHllPS9AaW1wb3J0W147XSo7L2dpbSxJZT0vKD86XlteO1wtXHN9XSspPy0tW147e31dKj86W157fTtdKj8oPzpbO1xuXXwkKS9naW0sSmU9Lyg/Ol5bXjtcLVxzfV0rKT8tLVteO3t9XSo/Oltee307XSo/e1tefV0qP30oPzpbO1xuXXwkKT8vZ2ltLEtlPS9AYXBwbHlccypcKD9bXik7XSpcKT9ccyooPzpbO1xuXXwkKT8vZ2ltLExlPS9bXjs6XSo/OlteO10qP3ZhclwoW147XSpcKSg/Ols7XG5dfCQpPy9naW0sRGU9L15AW15cc10qa2V5ZnJhbWVzLyxCZT0vXHMrL2c7dmFyIE89ISh3aW5kb3cuU2hhZHlET00mJndpbmRvdy5TaGFkeURPTS5pblVzZSksTWU7ZnVuY3Rpb24gTmUoYSl7TWU9YSYmYS5zaGltY3NzcHJvcGVydGllcz8hMTpPfHwhKG5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goL0FwcGxlV2ViS2l0XC82MDF8RWRnZVwvMTUvKXx8IXdpbmRvdy5DU1N8fCFDU1Muc3VwcG9ydHN8fCFDU1Muc3VwcG9ydHMoImJveC1zaGFkb3ciLCIwIDAgMCB2YXIoLS1mb28pIikpfXZhciBPZTt3aW5kb3cuU2hhZHlDU1MmJnZvaWQgMCE9PXdpbmRvdy5TaGFkeUNTUy5jc3NCdWlsZCYmKE9lPXdpbmRvdy5TaGFkeUNTUy5jc3NCdWlsZCk7dmFyIFBlPSEoIXdpbmRvdy5TaGFkeUNTU3x8IXdpbmRvdy5TaGFkeUNTUy5kaXNhYmxlUnVudGltZSk7CndpbmRvdy5TaGFkeUNTUyYmdm9pZCAwIT09d2luZG93LlNoYWR5Q1NTLm5hdGl2ZUNzcz9NZT13aW5kb3cuU2hhZHlDU1MubmF0aXZlQ3NzOndpbmRvdy5TaGFkeUNTUz8oTmUod2luZG93LlNoYWR5Q1NTKSx3aW5kb3cuU2hhZHlDU1M9dm9pZCAwKTpOZSh3aW5kb3cuV2ViQ29tcG9uZW50cyYmd2luZG93LldlYkNvbXBvbmVudHMuZmxhZ3MpO3ZhciBRPU1lLFFlPU9lO3ZhciBSZT0vKD86XnxbO1xze11ccyopKC0tW1x3LV0qPylccyo6XHMqKD86KCg/OicoPzpcXCd8LikqPyd8Iig/OlxcInwuKSo/InxcKFteKV0qP1wpfFtefTt7XSkrKXxceyhbXn1dKilcfSg/Oig/PVs7XHN9XSl8JCkpL2dpLFNlPS8oPzpefFxXKylAYXBwbHlccypcKD8oW14pO1xuXSopXCk/L2dpLFRlPS8oLS1bXHctXSspXHMqKFs6LDspXXwkKS9naSxVZT0vKGFuaW1hdGlvblxzKjopfChhbmltYXRpb24tbmFtZVxzKjopLywkZT0vQG1lZGlhXHMoLiopLyxhZj0vXHtbXn1dKlx9L2c7dmFyIGJmPW5ldyBTZXQ7ZnVuY3Rpb24gY2YoYSxiKXtpZighYSlyZXR1cm4iIjsic3RyaW5nIj09PXR5cGVvZiBhJiYoYT13ZShhKSk7YiYmZGYoYSxiKTtyZXR1cm4gSGUoYSxRKX1mdW5jdGlvbiBlZihhKXshYS5fX2Nzc1J1bGVzJiZhLnRleHRDb250ZW50JiYoYS5fX2Nzc1J1bGVzPXdlKGEudGV4dENvbnRlbnQpKTtyZXR1cm4gYS5fX2Nzc1J1bGVzfHxudWxsfWZ1bmN0aW9uIGZmKGEpe3JldHVybiEhYS5wYXJlbnQmJmEucGFyZW50LnR5cGU9PT1FZX1mdW5jdGlvbiBkZihhLGIsYyxkKXtpZihhKXt2YXIgZT0hMSxmPWEudHlwZTtpZihkJiZmPT09Q2Upe3ZhciBnPWEuc2VsZWN0b3IubWF0Y2goJGUpO2cmJih3aW5kb3cubWF0Y2hNZWRpYShnWzFdKS5tYXRjaGVzfHwoZT0hMCkpfWY9PT1HZT9iKGEpOmMmJmY9PT1FZT9jKGEpOmY9PT1GZSYmKGU9ITApO2lmKChhPWEucnVsZXMpJiYhZSlmb3IoZT0wLGY9YS5sZW5ndGgsZz12b2lkIDA7ZTxmJiYoZz1hW2VdKTtlKyspZGYoZyxiLGMsZCl9fQpmdW5jdGlvbiBnZihhLGIsYyxkKXt2YXIgZT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzdHlsZSIpO2ImJmUuc2V0QXR0cmlidXRlKCJzY29wZSIsYik7ZS50ZXh0Q29udGVudD1hO2hmKGUsYyxkKTtyZXR1cm4gZX12YXIgamY9bnVsbDtmdW5jdGlvbiBrZihhKXthPWRvY3VtZW50LmNyZWF0ZUNvbW1lbnQoIiBTaGFkeSBET00gc3R5bGVzIGZvciAiK2ErIiAiKTt2YXIgYj1kb2N1bWVudC5oZWFkO2IuaW5zZXJ0QmVmb3JlKGEsKGpmP2pmLm5leHRTaWJsaW5nOm51bGwpfHxiLmZpcnN0Q2hpbGQpO3JldHVybiBqZj1hfWZ1bmN0aW9uIGhmKGEsYixjKXtiPWJ8fGRvY3VtZW50LmhlYWQ7Yi5pbnNlcnRCZWZvcmUoYSxjJiZjLm5leHRTaWJsaW5nfHxiLmZpcnN0Q2hpbGQpO2pmP2EuY29tcGFyZURvY3VtZW50UG9zaXRpb24oamYpPT09Tm9kZS5ET0NVTUVOVF9QT1NJVElPTl9QUkVDRURJTkcmJihqZj1hKTpqZj1hfQpmdW5jdGlvbiBsZihhLGIpe2Zvcih2YXIgYz0wLGQ9YS5sZW5ndGg7YjxkO2IrKylpZigiKCI9PT1hW2JdKWMrKztlbHNlIGlmKCIpIj09PWFbYl0mJjA9PT0tLWMpcmV0dXJuIGI7cmV0dXJuLTF9ZnVuY3Rpb24gbWYoYSxiKXt2YXIgYz1hLmluZGV4T2YoInZhcigiKTtpZigtMT09PWMpcmV0dXJuIGIoYSwiIiwiIiwiIik7dmFyIGQ9bGYoYSxjKzMpLGU9YS5zdWJzdHJpbmcoYys0LGQpO2M9YS5zdWJzdHJpbmcoMCxjKTthPW1mKGEuc3Vic3RyaW5nKGQrMSksYik7ZD1lLmluZGV4T2YoIiwiKTtyZXR1cm4tMT09PWQ/YihjLGUudHJpbSgpLCIiLGEpOmIoYyxlLnN1YnN0cmluZygwLGQpLnRyaW0oKSxlLnN1YnN0cmluZyhkKzEpLnRyaW0oKSxhKX1mdW5jdGlvbiBuZihhLGIpe08/YS5zZXRBdHRyaWJ1dGUoImNsYXNzIixiKTp3aW5kb3cuU2hhZHlET00ubmF0aXZlTWV0aG9kcy5zZXRBdHRyaWJ1dGUuY2FsbChhLCJjbGFzcyIsYil9CnZhciBvZj13aW5kb3cuU2hhZHlET00mJndpbmRvdy5TaGFkeURPTS53cmFwfHxmdW5jdGlvbihhKXtyZXR1cm4gYX07ZnVuY3Rpb24gcGYoYSl7dmFyIGI9YS5sb2NhbE5hbWUsYz0iIjtiPy0xPGIuaW5kZXhPZigiLSIpfHwoYz1iLGI9YS5nZXRBdHRyaWJ1dGUmJmEuZ2V0QXR0cmlidXRlKCJpcyIpfHwiIik6KGI9YS5pcyxjPWEuZXh0ZW5kcyk7cmV0dXJue2lzOmIsTTpjfX1mdW5jdGlvbiBxZihhKXtmb3IodmFyIGI9W10sYz0iIixkPTA7MDw9ZCYmZDxhLmxlbmd0aDtkKyspaWYoIigiPT09YVtkXSl7dmFyIGU9bGYoYSxkKTtjKz1hLnNsaWNlKGQsZSsxKTtkPWV9ZWxzZSIsIj09PWFbZF0/KGIucHVzaChjKSxjPSIiKTpjKz1hW2RdO2MmJmIucHVzaChjKTtyZXR1cm4gYn0KZnVuY3Rpb24gcmYoYSl7aWYodm9pZCAwIT09UWUpcmV0dXJuIFFlO2lmKHZvaWQgMD09PWEuX19jc3NCdWlsZCl7dmFyIGI9YS5nZXRBdHRyaWJ1dGUoImNzcy1idWlsZCIpO2lmKGIpYS5fX2Nzc0J1aWxkPWI7ZWxzZXthOntiPSJ0ZW1wbGF0ZSI9PT1hLmxvY2FsTmFtZT9hLmNvbnRlbnQuZmlyc3RDaGlsZDphLmZpcnN0Q2hpbGQ7aWYoYiBpbnN0YW5jZW9mIENvbW1lbnQmJihiPWIudGV4dENvbnRlbnQudHJpbSgpLnNwbGl0KCI6IiksImNzcy1idWlsZCI9PT1iWzBdKSl7Yj1iWzFdO2JyZWFrIGF9Yj0iIn1pZigiIiE9PWIpe3ZhciBjPSJ0ZW1wbGF0ZSI9PT1hLmxvY2FsTmFtZT9hLmNvbnRlbnQuZmlyc3RDaGlsZDphLmZpcnN0Q2hpbGQ7Yy5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGMpfWEuX19jc3NCdWlsZD1ifX1yZXR1cm4gYS5fX2Nzc0J1aWxkfHwiIn0KZnVuY3Rpb24gc2YoYSl7YT12b2lkIDA9PT1hPyIiOmE7cmV0dXJuIiIhPT1hJiZRP08/InNoYWRvdyI9PT1hOiJzaGFkeSI9PT1hOiExfTtmdW5jdGlvbiB0Zigpe31mdW5jdGlvbiB1ZihhLGIpe3ZmKFIsYSxmdW5jdGlvbihhKXt3ZihhLGJ8fCIiKX0pfWZ1bmN0aW9uIHZmKGEsYixjKXtiLm5vZGVUeXBlPT09Tm9kZS5FTEVNRU5UX05PREUmJmMoYik7dmFyIGQ7InRlbXBsYXRlIj09PWIubG9jYWxOYW1lP2Q9KGIuY29udGVudHx8Yi5fY29udGVudHx8YikuY2hpbGROb2RlczpkPWIuY2hpbGRyZW58fGIuY2hpbGROb2RlcztpZihkKWZvcihiPTA7YjxkLmxlbmd0aDtiKyspdmYoYSxkW2JdLGMpfQpmdW5jdGlvbiB3ZihhLGIsYyl7aWYoYilpZihhLmNsYXNzTGlzdCljPyhhLmNsYXNzTGlzdC5yZW1vdmUoInN0eWxlLXNjb3BlIiksYS5jbGFzc0xpc3QucmVtb3ZlKGIpKTooYS5jbGFzc0xpc3QuYWRkKCJzdHlsZS1zY29wZSIpLGEuY2xhc3NMaXN0LmFkZChiKSk7ZWxzZSBpZihhLmdldEF0dHJpYnV0ZSl7dmFyIGQ9YS5nZXRBdHRyaWJ1dGUoImNsYXNzIik7Yz9kJiYoYj1kLnJlcGxhY2UoInN0eWxlLXNjb3BlIiwiIikucmVwbGFjZShiLCIiKSxuZihhLGIpKTpuZihhLChkP2QrIiAiOiIiKSsic3R5bGUtc2NvcGUgIitiKX19ZnVuY3Rpb24geGYoYSxiLGMpe3ZmKFIsYSxmdW5jdGlvbihhKXt3ZihhLGIsITApO3dmKGEsYyl9KX1mdW5jdGlvbiB5ZihhLGIpe3ZmKFIsYSxmdW5jdGlvbihhKXt3ZihhLGJ8fCIiLCEwKX0pfQpmdW5jdGlvbiB6ZihhLGIsYyxkLGUpe3ZhciBmPVI7ZT12b2lkIDA9PT1lPyIiOmU7IiI9PT1lJiYoT3x8InNoYWR5Ij09PSh2b2lkIDA9PT1kPyIiOmQpP2U9Y2YoYixjKTooYT1wZihhKSxlPUFmKGYsYixhLmlzLGEuTSxjKSsiXG5cbiIpKTtyZXR1cm4gZS50cmltKCl9ZnVuY3Rpb24gQWYoYSxiLGMsZCxlKXt2YXIgZj1CZihjLGQpO2M9Yz8iLiIrYzoiIjtyZXR1cm4gY2YoYixmdW5jdGlvbihiKXtiLmN8fChiLnNlbGVjdG9yPWIuaj1DZihhLGIsYS5iLGMsZiksYi5jPSEwKTtlJiZlKGIsYyxmKX0pfWZ1bmN0aW9uIEJmKGEsYil7cmV0dXJuIGI/Iltpcz0iK2ErIl0iOmF9CmZ1bmN0aW9uIENmKGEsYixjLGQsZSl7dmFyIGY9cWYoYi5zZWxlY3Rvcik7aWYoIWZmKGIpKXtiPTA7Zm9yKHZhciBnPWYubGVuZ3RoLGg9dm9pZCAwO2I8ZyYmKGg9ZltiXSk7YisrKWZbYl09Yy5jYWxsKGEsaCxkLGUpfXJldHVybiBmLmZpbHRlcihmdW5jdGlvbihhKXtyZXR1cm4hIWF9KS5qb2luKCIsIil9ZnVuY3Rpb24gRGYoYSl7cmV0dXJuIGEucmVwbGFjZShFZixmdW5jdGlvbihhLGMsZCl7LTE8ZC5pbmRleE9mKCIrIik/ZD1kLnJlcGxhY2UoL1wrL2csIl9fXyIpOi0xPGQuaW5kZXhPZigiX19fIikmJihkPWQucmVwbGFjZSgvX19fL2csIisiKSk7cmV0dXJuIjoiK2MrIigiK2QrIikifSl9CmZ1bmN0aW9uIEZmKGEpe2Zvcih2YXIgYj1bXSxjO2M9YS5tYXRjaChHZik7KXt2YXIgZD1jLmluZGV4LGU9bGYoYSxkKTtpZigtMT09PWUpdGhyb3cgRXJyb3IoYy5pbnB1dCsiIHNlbGVjdG9yIG1pc3NpbmcgJyknIik7Yz1hLnNsaWNlKGQsZSsxKTthPWEucmVwbGFjZShjLCJcdWUwMDAiKTtiLnB1c2goYyl9cmV0dXJue2hhOmEsbWF0Y2hlczpifX1mdW5jdGlvbiBIZihhLGIpe3ZhciBjPWEuc3BsaXQoIlx1ZTAwMCIpO3JldHVybiBiLnJlZHVjZShmdW5jdGlvbihhLGIsZil7cmV0dXJuIGErYitjW2YrMV19LGNbMF0pfQp0Zi5wcm90b3R5cGUuYj1mdW5jdGlvbihhLGIsYyl7dmFyIGQ9ITE7YT1hLnRyaW0oKTt2YXIgZT1FZi50ZXN0KGEpO2UmJihhPWEucmVwbGFjZShFZixmdW5jdGlvbihhLGIsYyl7cmV0dXJuIjoiK2IrIigiK2MucmVwbGFjZSgvXHMvZywiIikrIikifSksYT1EZihhKSk7dmFyIGY9R2YudGVzdChhKTtpZihmKXt2YXIgZz1GZihhKTthPWcuaGE7Zz1nLm1hdGNoZXN9YT1hLnJlcGxhY2UoSWYsIjpob3N0ICQxIik7YT1hLnJlcGxhY2UoSmYsZnVuY3Rpb24oYSxlLGYpe2R8fChhPUtmKGYsZSxiLGMpLGQ9ZHx8YS5zdG9wLGU9YS5DYSxmPWEudmFsdWUpO3JldHVybiBlK2Z9KTtmJiYoYT1IZihhLGcpKTtlJiYoYT1EZihhKSk7cmV0dXJuIGF9OwpmdW5jdGlvbiBLZihhLGIsYyxkKXt2YXIgZT1hLmluZGV4T2YoIjo6c2xvdHRlZCIpOzA8PWEuaW5kZXhPZigiOmhvc3QiKT9hPUxmKGEsZCk6MCE9PWUmJihhPWM/TWYoYSxjKTphKTtjPSExOzA8PWUmJihiPSIiLGM9ITApO2lmKGMpe3ZhciBmPSEwO2MmJihhPWEucmVwbGFjZShOZixmdW5jdGlvbihhLGIpe3JldHVybiIgPiAiK2J9KSl9YT1hLnJlcGxhY2UoT2YsZnVuY3Rpb24oYSxiLGMpe3JldHVybidbZGlyPSInK2MrJyJdICcrYisiLCAiK2IrJ1tkaXI9IicrYysnIl0nfSk7cmV0dXJue3ZhbHVlOmEsQ2E6YixzdG9wOmZ9fQpmdW5jdGlvbiBNZihhLGIpe2E9YS5zcGxpdCgvKFxbLis/XF0pLyk7Zm9yKHZhciBjPVtdLGQ9MDtkPGEubGVuZ3RoO2QrKylpZigxPT09ZCUyKWMucHVzaChhW2RdKTtlbHNle3ZhciBlPWFbZF07aWYoIiIhPT1lfHxkIT09YS5sZW5ndGgtMSllPWUuc3BsaXQoIjoiKSxlWzBdKz1iLGMucHVzaChlLmpvaW4oIjoiKSl9cmV0dXJuIGMuam9pbigiIil9ZnVuY3Rpb24gTGYoYSxiKXt2YXIgYz1hLm1hdGNoKFBmKTtyZXR1cm4oYz1jJiZjWzJdLnRyaW0oKXx8IiIpP2NbMF0ubWF0Y2goUWYpP2EucmVwbGFjZShQZixmdW5jdGlvbihhLGMsZil7cmV0dXJuIGIrZn0pOmMuc3BsaXQoUWYpWzBdPT09Yj9jOiJzaG91bGRfbm90X21hdGNoIjphLnJlcGxhY2UoIjpob3N0IixiKX1mdW5jdGlvbiBSZihhKXsiOnJvb3QiPT09YS5zZWxlY3RvciYmKGEuc2VsZWN0b3I9Imh0bWwiKX0KdGYucHJvdG90eXBlLmM9ZnVuY3Rpb24oYSl7cmV0dXJuIGEubWF0Y2goIjpob3N0Iik/IiI6YS5tYXRjaCgiOjpzbG90dGVkIik/dGhpcy5iKGEsIjpub3QoLnN0eWxlLXNjb3BlKSIpOk1mKGEudHJpbSgpLCI6bm90KC5zdHlsZS1zY29wZSkiKX07cC5PYmplY3QuZGVmaW5lUHJvcGVydGllcyh0Zi5wcm90b3R5cGUse2E6e2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiJzdHlsZS1zY29wZSJ9fX0pOwp2YXIgRWY9LzoobnRoWy1cd10rKVwoKFteKV0rKVwpLyxKZj0vKF58W1xzPit+XSspKCg/OlxbLis/XF18W15ccz4rfj1bXSkrKS9nLFFmPS9bWy46IypdLyxJZj0vXig6OnNsb3R0ZWQpLyxQZj0vKDpob3N0KSg/OlwoKCg/OlwoW14pKF0qXCl8W14pKF0qKSs/KVwpKS8sTmY9Lyg/Ojo6c2xvdHRlZCkoPzpcKCgoPzpcKFteKShdKlwpfFteKShdKikrPylcKSkvLE9mPS8oLiopOmRpclwoKD86KGx0cnxydGwpKVwpLyxHZj0vOig/Om1hdGNoZXN8YW55fC0oPzp3ZWJraXR8bW96KS1hbnkpLyxSPW5ldyB0ZjtmdW5jdGlvbiBTZihhLGIsYyxkLGUpe3RoaXMuQT1hfHxudWxsO3RoaXMuYj1ifHxudWxsO3RoaXMuZmE9Y3x8W107dGhpcy5vPW51bGw7dGhpcy5jc3NCdWlsZD1lfHwiIjt0aGlzLk09ZHx8IiI7dGhpcy5hPXRoaXMucz10aGlzLnc9bnVsbH1mdW5jdGlvbiBUKGEpe3JldHVybiBhP2EuX19zdHlsZUluZm86bnVsbH1mdW5jdGlvbiBUZihhLGIpe3JldHVybiBhLl9fc3R5bGVJbmZvPWJ9U2YucHJvdG90eXBlLmM9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5BfTtTZi5wcm90b3R5cGUuX2dldFN0eWxlUnVsZXM9U2YucHJvdG90eXBlLmM7ZnVuY3Rpb24gVWYoYSl7dmFyIGI9dGhpcy5tYXRjaGVzfHx0aGlzLm1hdGNoZXNTZWxlY3Rvcnx8dGhpcy5tb3pNYXRjaGVzU2VsZWN0b3J8fHRoaXMubXNNYXRjaGVzU2VsZWN0b3J8fHRoaXMub01hdGNoZXNTZWxlY3Rvcnx8dGhpcy53ZWJraXRNYXRjaGVzU2VsZWN0b3I7cmV0dXJuIGImJmIuY2FsbCh0aGlzLGEpfXZhciBWZj1uYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKCJUcmlkZW50Iik7ZnVuY3Rpb24gV2YoKXt9ZnVuY3Rpb24gWGYoYSl7dmFyIGI9e30sYz1bXSxkPTA7ZGYoYSxmdW5jdGlvbihhKXtZZihhKTthLmluZGV4PWQrKzthPWEuaS5jc3NUZXh0O2Zvcih2YXIgYztjPVRlLmV4ZWMoYSk7KXt2YXIgZT1jWzFdOyI6IiE9PWNbMl0mJihiW2VdPSEwKX19LGZ1bmN0aW9uKGEpe2MucHVzaChhKX0pO2EuYj1jO2E9W107Zm9yKHZhciBlIGluIGIpYS5wdXNoKGUpO3JldHVybiBhfQpmdW5jdGlvbiBZZihhKXtpZighYS5pKXt2YXIgYj17fSxjPXt9O1pmKGEsYykmJihiLnY9YyxhLnJ1bGVzPW51bGwpO2IuY3NzVGV4dD1hLnBhcnNlZENzc1RleHQucmVwbGFjZShhZiwiIikucmVwbGFjZShSZSwiIik7YS5pPWJ9fWZ1bmN0aW9uIFpmKGEsYil7dmFyIGM9YS5pO2lmKGMpe2lmKGMudilyZXR1cm4gT2JqZWN0LmFzc2lnbihiLGMudiksITB9ZWxzZXtjPWEucGFyc2VkQ3NzVGV4dDtmb3IodmFyIGQ7YT1SZS5leGVjKGMpOyl7ZD0oYVsyXXx8YVszXSkudHJpbSgpO2lmKCJpbmhlcml0IiE9PWR8fCJ1bnNldCIhPT1kKWJbYVsxXS50cmltKCldPWQ7ZD0hMH1yZXR1cm4gZH19CmZ1bmN0aW9uICRmKGEsYixjKXtiJiYoYj0wPD1iLmluZGV4T2YoIjsiKT9hZyhhLGIsYyk6bWYoYixmdW5jdGlvbihiLGUsZixnKXtpZighZSlyZXR1cm4gYitnOyhlPSRmKGEsY1tlXSxjKSkmJiJpbml0aWFsIiE9PWU/ImFwcGx5LXNoaW0taW5oZXJpdCI9PT1lJiYoZT0iaW5oZXJpdCIpOmU9JGYoYSxjW2ZdfHxmLGMpfHxmO3JldHVybiBiKyhlfHwiIikrZ30pKTtyZXR1cm4gYiYmYi50cmltKCl8fCIifQpmdW5jdGlvbiBhZyhhLGIsYyl7Yj1iLnNwbGl0KCI7Iik7Zm9yKHZhciBkPTAsZSxmO2Q8Yi5sZW5ndGg7ZCsrKWlmKGU9YltkXSl7U2UubGFzdEluZGV4PTA7aWYoZj1TZS5leGVjKGUpKWU9JGYoYSxjW2ZbMV1dLGMpO2Vsc2UgaWYoZj1lLmluZGV4T2YoIjoiKSwtMSE9PWYpe3ZhciBnPWUuc3Vic3RyaW5nKGYpO2c9Zy50cmltKCk7Zz0kZihhLGcsYyl8fGc7ZT1lLnN1YnN0cmluZygwLGYpK2d9YltkXT1lJiZlLmxhc3RJbmRleE9mKCI7Iik9PT1lLmxlbmd0aC0xP2Uuc2xpY2UoMCwtMSk6ZXx8IiJ9cmV0dXJuIGIuam9pbigiOyIpfQpmdW5jdGlvbiBiZyhhLGIpe3ZhciBjPXt9LGQ9W107ZGYoYSxmdW5jdGlvbihhKXthLml8fFlmKGEpO3ZhciBlPWEuanx8YS5wYXJzZWRTZWxlY3RvcjtiJiZhLmkudiYmZSYmVWYuY2FsbChiLGUpJiYoWmYoYSxjKSxhPWEuaW5kZXgsZT1wYXJzZUludChhLzMyLDEwKSxkW2VdPShkW2VdfHwwKXwxPDxhJTMyKX0sbnVsbCwhMCk7cmV0dXJue3Y6YyxrZXk6ZH19CmZ1bmN0aW9uIGNnKGEsYixjLGQpe2IuaXx8WWYoYik7aWYoYi5pLnYpe3ZhciBlPXBmKGEpO2E9ZS5pcztlPWUuTTtlPWE/QmYoYSxlKToiaHRtbCI7dmFyIGY9Yi5wYXJzZWRTZWxlY3RvcixnPSI6aG9zdCA+ICoiPT09Znx8Imh0bWwiPT09ZixoPTA9PT1mLmluZGV4T2YoIjpob3N0IikmJiFnOyJzaGFkeSI9PT1jJiYoZz1mPT09ZSsiID4gKi4iK2V8fC0xIT09Zi5pbmRleE9mKCJodG1sIiksaD0hZyYmMD09PWYuaW5kZXhPZihlKSk7aWYoZ3x8aCljPWUsaCYmKGIuanx8KGIuaj1DZihSLGIsUi5iLGE/Ii4iK2E6IiIsZSkpLGM9Yi5qfHxlKSxkKHtoYTpjLElhOmgsWmE6Z30pfX1mdW5jdGlvbiBkZyhhLGIsYyl7dmFyIGQ9e30sZT17fTtkZihiLGZ1bmN0aW9uKGIpe2NnKGEsYixjLGZ1bmN0aW9uKGMpe1VmLmNhbGwoYS5fZWxlbWVudHx8YSxjLmhhKSYmKGMuSWE/WmYoYixkKTpaZihiLGUpKX0pfSxudWxsLCEwKTtyZXR1cm57UmE6ZSxIYTpkfX0KZnVuY3Rpb24gZWcoYSxiLGMsZCl7dmFyIGU9cGYoYiksZj1CZihlLmlzLGUuTSksZz1uZXcgUmVnRXhwKCIoPzpefFteLiNbOl0pIisoYi5leHRlbmRzPyJcXCIrZi5zbGljZSgwLC0xKSsiXFxdIjpmKSsiKCR8Wy46W1xccz4rfl0pIiksaD1UKGIpO2U9aC5BO2g9aC5jc3NCdWlsZDt2YXIgaz1mZyhlLGQpO3JldHVybiB6ZihiLGUsZnVuY3Rpb24oYil7dmFyIGU9IiI7Yi5pfHxZZihiKTtiLmkuY3NzVGV4dCYmKGU9YWcoYSxiLmkuY3NzVGV4dCxjKSk7Yi5jc3NUZXh0PWU7aWYoIU8mJiFmZihiKSYmYi5jc3NUZXh0KXt2YXIgaD1lPWIuY3NzVGV4dDtudWxsPT1iLm5hJiYoYi5uYT1VZS50ZXN0KGUpKTtpZihiLm5hKWlmKG51bGw9PWIuVSl7Yi5VPVtdO2Zvcih2YXIgbCBpbiBrKWg9a1tsXSxoPWgoZSksZSE9PWgmJihlPWgsYi5VLnB1c2gobCkpfWVsc2V7Zm9yKGw9MDtsPGIuVS5sZW5ndGg7KytsKWg9a1tiLlVbbF1dLGU9aChlKTtoPWV9Yi5jc3NUZXh0PWg7Yi5qPWIuanx8CmIuc2VsZWN0b3I7ZT0iLiIrZDtsPXFmKGIuaik7aD0wO2Zvcih2YXIgTT1sLmxlbmd0aCxVPXZvaWQgMDtoPE0mJihVPWxbaF0pO2grKylsW2hdPVUubWF0Y2goZyk/VS5yZXBsYWNlKGYsZSk6ZSsiICIrVTtiLnNlbGVjdG9yPWwuam9pbigiLCIpfX0saCl9ZnVuY3Rpb24gZmcoYSxiKXthPWEuYjt2YXIgYz17fTtpZighTyYmYSlmb3IodmFyIGQ9MCxlPWFbZF07ZDxhLmxlbmd0aDtlPWFbKytkXSl7dmFyIGY9ZSxnPWI7Zi5mPW5ldyBSZWdFeHAoIlxcYiIrZi5rZXlmcmFtZXNOYW1lKyIoPyFcXEJ8LSkiLCJnIik7Zi5hPWYua2V5ZnJhbWVzTmFtZSsiLSIrZztmLmo9Zi5qfHxmLnNlbGVjdG9yO2Yuc2VsZWN0b3I9Zi5qLnJlcGxhY2UoZi5rZXlmcmFtZXNOYW1lLGYuYSk7Y1tlLmtleWZyYW1lc05hbWVdPWdnKGUpfXJldHVybiBjfWZ1bmN0aW9uIGdnKGEpe3JldHVybiBmdW5jdGlvbihiKXtyZXR1cm4gYi5yZXBsYWNlKGEuZixhLmEpfX0KZnVuY3Rpb24gaGcoYSxiKXt2YXIgYz1pZyxkPWVmKGEpO2EudGV4dENvbnRlbnQ9Y2YoZCxmdW5jdGlvbihhKXt2YXIgZD1hLmNzc1RleHQ9YS5wYXJzZWRDc3NUZXh0O2EuaSYmYS5pLmNzc1RleHQmJihkPWQucmVwbGFjZShJZSwiIikucmVwbGFjZShKZSwiIiksYS5jc3NUZXh0PWFnKGMsZCxiKSl9KX1wLk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFdmLnByb3RvdHlwZSx7YTp7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIngtc2NvcGUifX19KTt2YXIgaWc9bmV3IFdmO3ZhciBqZz17fSxrZz13aW5kb3cuY3VzdG9tRWxlbWVudHM7aWYoa2cmJiFPJiYhUGUpe3ZhciBsZz1rZy5kZWZpbmU7a2cuZGVmaW5lPWZ1bmN0aW9uKGEsYixjKXtqZ1thXXx8KGpnW2FdPWtmKGEpKTtsZy5jYWxsKGtnLGEsYixjKX19O2Z1bmN0aW9uIG1nKCl7dGhpcy5jYWNoZT17fX1tZy5wcm90b3R5cGUuc3RvcmU9ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIGU9dGhpcy5jYWNoZVthXXx8W107ZS5wdXNoKHt2OmIsc3R5bGVFbGVtZW50OmMsczpkfSk7MTAwPGUubGVuZ3RoJiZlLnNoaWZ0KCk7dGhpcy5jYWNoZVthXT1lfTtmdW5jdGlvbiBuZygpe312YXIgb2c9bmV3IFJlZ0V4cChSLmErIlxccyooW15cXHNdKikiKTtmdW5jdGlvbiBwZyhhKXtyZXR1cm4oYT0oYS5jbGFzc0xpc3QmJmEuY2xhc3NMaXN0LnZhbHVlP2EuY2xhc3NMaXN0LnZhbHVlOmEuZ2V0QXR0cmlidXRlKCJjbGFzcyIpfHwiIikubWF0Y2gob2cpKT9hWzFdOiIifWZ1bmN0aW9uIHFnKGEpe3ZhciBiPW9mKGEpLmdldFJvb3ROb2RlKCk7cmV0dXJuIGI9PT1hfHxiPT09YS5vd25lckRvY3VtZW50PyIiOihhPWIuaG9zdCk/cGYoYSkuaXM6IiJ9CmZ1bmN0aW9uIHJnKGEpe2Zvcih2YXIgYj0wO2I8YS5sZW5ndGg7YisrKXt2YXIgYz1hW2JdO2lmKGMudGFyZ2V0IT09ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50JiZjLnRhcmdldCE9PWRvY3VtZW50LmhlYWQpZm9yKHZhciBkPTA7ZDxjLmFkZGVkTm9kZXMubGVuZ3RoO2QrKyl7dmFyIGU9Yy5hZGRlZE5vZGVzW2RdO2lmKGUubm9kZVR5cGU9PT1Ob2RlLkVMRU1FTlRfTk9ERSl7dmFyIGY9ZS5nZXRSb290Tm9kZSgpLGc9cGcoZSk7aWYoZyYmZj09PWUub3duZXJEb2N1bWVudCYmKCJzdHlsZSIhPT1lLmxvY2FsTmFtZSYmInRlbXBsYXRlIiE9PWUubG9jYWxOYW1lfHwiIj09PXJmKGUpKSl5ZihlLGcpO2Vsc2UgaWYoZiBpbnN0YW5jZW9mIFNoYWRvd1Jvb3QpZm9yKGY9cWcoZSksZiE9PWcmJnhmKGUsZyxmKSxlPXdpbmRvdy5TaGFkeURPTS5uYXRpdmVNZXRob2RzLnF1ZXJ5U2VsZWN0b3JBbGwuY2FsbChlLCI6bm90KC4iK1IuYSsiKSIpLGc9MDtnPGUubGVuZ3RoO2crKyl7Zj1lW2ddOwp2YXIgaD1xZyhmKTtoJiZ3ZihmLGgpfX19fX0KaWYoIShPfHx3aW5kb3cuU2hhZHlET00mJndpbmRvdy5TaGFkeURPTS5oYW5kbGVzRHluYW1pY1Njb3BpbmcpKXt2YXIgc2c9bmV3IE11dGF0aW9uT2JzZXJ2ZXIocmcpLHRnPWZ1bmN0aW9uKGEpe3NnLm9ic2VydmUoYSx7Y2hpbGRMaXN0OiEwLHN1YnRyZWU6ITB9KX07aWYod2luZG93LmN1c3RvbUVsZW1lbnRzJiYhd2luZG93LmN1c3RvbUVsZW1lbnRzLnBvbHlmaWxsV3JhcEZsdXNoQ2FsbGJhY2spdGcoZG9jdW1lbnQpO2Vsc2V7dmFyIHVnPWZ1bmN0aW9uKCl7dGcoZG9jdW1lbnQuYm9keSl9O3dpbmRvdy5IVE1MSW1wb3J0cz93aW5kb3cuSFRNTEltcG9ydHMud2hlblJlYWR5KHVnKTpyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24oKXtpZigibG9hZGluZyI9PT1kb2N1bWVudC5yZWFkeVN0YXRlKXt2YXIgYT1mdW5jdGlvbigpe3VnKCk7ZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigicmVhZHlzdGF0ZWNoYW5nZSIsYSl9O2RvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInJlYWR5c3RhdGVjaGFuZ2UiLAphKX1lbHNlIHVnKCl9KX1uZz1mdW5jdGlvbigpe3JnKHNnLnRha2VSZWNvcmRzKCkpfX12YXIgdmc9bmc7dmFyIHdnPXt9O3ZhciB4Zz1Qcm9taXNlLnJlc29sdmUoKTtmdW5jdGlvbiB5ZyhhKXtpZihhPXdnW2FdKWEuX2FwcGx5U2hpbUN1cnJlbnRWZXJzaW9uPWEuX2FwcGx5U2hpbUN1cnJlbnRWZXJzaW9ufHwwLGEuX2FwcGx5U2hpbVZhbGlkYXRpbmdWZXJzaW9uPWEuX2FwcGx5U2hpbVZhbGlkYXRpbmdWZXJzaW9ufHwwLGEuX2FwcGx5U2hpbU5leHRWZXJzaW9uPShhLl9hcHBseVNoaW1OZXh0VmVyc2lvbnx8MCkrMX1mdW5jdGlvbiB6ZyhhKXtyZXR1cm4gYS5fYXBwbHlTaGltQ3VycmVudFZlcnNpb249PT1hLl9hcHBseVNoaW1OZXh0VmVyc2lvbn1mdW5jdGlvbiBBZyhhKXthLl9hcHBseVNoaW1WYWxpZGF0aW5nVmVyc2lvbj1hLl9hcHBseVNoaW1OZXh0VmVyc2lvbjthLl92YWxpZGF0aW5nfHwoYS5fdmFsaWRhdGluZz0hMCx4Zy50aGVuKGZ1bmN0aW9uKCl7YS5fYXBwbHlTaGltQ3VycmVudFZlcnNpb249YS5fYXBwbHlTaGltTmV4dFZlcnNpb247YS5fdmFsaWRhdGluZz0hMX0pKX07dmFyIEJnPXt9LENnPW5ldyBtZztmdW5jdGlvbiBZKCl7dGhpcy5sPXt9O3RoaXMuYz1kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7dmFyIGE9bmV3IHZlO2EucnVsZXM9W107dGhpcy5mPVRmKHRoaXMuYyxuZXcgU2YoYSkpO3RoaXMuZz0hMTt0aGlzLmI9dGhpcy5hPW51bGx9bj1ZLnByb3RvdHlwZTtuLmZsdXNoPWZ1bmN0aW9uKCl7dmcoKX07bi5GYT1mdW5jdGlvbihhKXtyZXR1cm4gZWYoYSl9O24uVmE9ZnVuY3Rpb24oYSl7cmV0dXJuIGNmKGEpfTtuLnByZXBhcmVUZW1wbGF0ZT1mdW5jdGlvbihhLGIsYyl7dGhpcy5wcmVwYXJlVGVtcGxhdGVEb20oYSxiKTt0aGlzLnByZXBhcmVUZW1wbGF0ZVN0eWxlcyhhLGIsYyl9OwpuLnByZXBhcmVUZW1wbGF0ZVN0eWxlcz1mdW5jdGlvbihhLGIsYyl7aWYoIWEuX3ByZXBhcmVkJiYhUGUpe098fGpnW2JdfHwoamdbYl09a2YoYikpO2EuX3ByZXBhcmVkPSEwO2EubmFtZT1iO2EuZXh0ZW5kcz1jO3dnW2JdPWE7dmFyIGQ9cmYoYSksZT1zZihkKTtjPXtpczpiLGV4dGVuZHM6Y307Zm9yKHZhciBmPVtdLGc9YS5jb250ZW50LnF1ZXJ5U2VsZWN0b3JBbGwoInN0eWxlIiksaD0wO2g8Zy5sZW5ndGg7aCsrKXt2YXIgaz1nW2hdO2lmKGsuaGFzQXR0cmlidXRlKCJzaGFkeS11bnNjb3BlZCIpKXtpZighTyl7dmFyIGw9ay50ZXh0Q29udGVudDtiZi5oYXMobCl8fChiZi5hZGQobCksbD1rLmNsb25lTm9kZSghMCksZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChsKSk7ay5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGspfX1lbHNlIGYucHVzaChrLnRleHRDb250ZW50KSxrLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoayl9Zj1mLmpvaW4oIiIpLnRyaW0oKSsoQmdbYl18fCIiKTsKRGcodGhpcyk7aWYoIWUpe2lmKGc9IWQpZz1TZS50ZXN0KGYpfHxSZS50ZXN0KGYpLFNlLmxhc3RJbmRleD0wLFJlLmxhc3RJbmRleD0wO2g9d2UoZik7ZyYmUSYmdGhpcy5hJiZ0aGlzLmEudHJhbnNmb3JtUnVsZXMoaCxiKTthLl9zdHlsZUFzdD1ofWc9W107UXx8KGc9WGYoYS5fc3R5bGVBc3QpKTtpZighZy5sZW5ndGh8fFEpaD1PP2EuY29udGVudDpudWxsLGI9amdbYl18fG51bGwsZD16ZihjLGEuX3N0eWxlQXN0LG51bGwsZCxlP2Y6IiIpLGQ9ZC5sZW5ndGg/Z2YoZCxjLmlzLGgsYik6bnVsbCxhLl9zdHlsZT1kO2EuYT1nfX07bi5RYT1mdW5jdGlvbihhLGIpe0JnW2JdPWEuam9pbigiICIpfTtuLnByZXBhcmVUZW1wbGF0ZURvbT1mdW5jdGlvbihhLGIpe2lmKCFQZSl7dmFyIGM9cmYoYSk7T3x8InNoYWR5Ij09PWN8fGEuX2RvbVByZXBhcmVkfHwoYS5fZG9tUHJlcGFyZWQ9ITAsdWYoYS5jb250ZW50LGIpKX19OwpmdW5jdGlvbiBFZyhhKXt2YXIgYj1wZihhKSxjPWIuaXM7Yj1iLk07dmFyIGQ9amdbY118fG51bGwsZT13Z1tjXTtpZihlKXtjPWUuX3N0eWxlQXN0O3ZhciBmPWUuYTtlPXJmKGUpO2I9bmV3IFNmKGMsZCxmLGIsZSk7VGYoYSxiKTtyZXR1cm4gYn19ZnVuY3Rpb24gRmcoYSl7IWEuYiYmd2luZG93LlNoYWR5Q1NTJiZ3aW5kb3cuU2hhZHlDU1MuQ3VzdG9tU3R5bGVJbnRlcmZhY2UmJihhLmI9d2luZG93LlNoYWR5Q1NTLkN1c3RvbVN0eWxlSW50ZXJmYWNlLGEuYi50cmFuc2Zvcm1DYWxsYmFjaz1mdW5jdGlvbihiKXthLnJhKGIpfSxhLmIudmFsaWRhdGVDYWxsYmFjaz1mdW5jdGlvbigpe3JlcXVlc3RBbmltYXRpb25GcmFtZShmdW5jdGlvbigpeyhhLmIuZW5xdWV1ZWR8fGEuZykmJmEuZmx1c2hDdXN0b21TdHlsZXMoKX0pfSl9CmZ1bmN0aW9uIERnKGEpeyFhLmEmJndpbmRvdy5TaGFkeUNTUyYmd2luZG93LlNoYWR5Q1NTLkFwcGx5U2hpbSYmKGEuYT13aW5kb3cuU2hhZHlDU1MuQXBwbHlTaGltLGEuYS5pbnZhbGlkQ2FsbGJhY2s9eWcpO0ZnKGEpfQpuLmZsdXNoQ3VzdG9tU3R5bGVzPWZ1bmN0aW9uKCl7aWYoIVBlJiYoRGcodGhpcyksdGhpcy5iKSl7dmFyIGE9dGhpcy5iLnByb2Nlc3NTdHlsZXMoKTtpZih0aGlzLmIuZW5xdWV1ZWQmJiFzZih0aGlzLmYuY3NzQnVpbGQpKXtpZihRKXtpZighdGhpcy5mLmNzc0J1aWxkKWZvcih2YXIgYj0wO2I8YS5sZW5ndGg7YisrKXt2YXIgYz10aGlzLmIuZ2V0U3R5bGVGb3JDdXN0b21TdHlsZShhW2JdKTtpZihjJiZRJiZ0aGlzLmEpe3ZhciBkPWVmKGMpO0RnKHRoaXMpO3RoaXMuYS50cmFuc2Zvcm1SdWxlcyhkKTtjLnRleHRDb250ZW50PWNmKGQpfX19ZWxzZXtHZyh0aGlzLHRoaXMuYyx0aGlzLmYpO2ZvcihiPTA7YjxhLmxlbmd0aDtiKyspKGM9dGhpcy5iLmdldFN0eWxlRm9yQ3VzdG9tU3R5bGUoYVtiXSkpJiZoZyhjLHRoaXMuZi53KTt0aGlzLmcmJnRoaXMuc3R5bGVEb2N1bWVudCgpfXRoaXMuYi5lbnF1ZXVlZD0hMX19fTsKbi5zdHlsZUVsZW1lbnQ9ZnVuY3Rpb24oYSxiKXtpZihQZSl7aWYoYil7VChhKXx8VGYoYSxuZXcgU2YobnVsbCkpO3ZhciBjPVQoYSk7Yy5vPWMub3x8e307T2JqZWN0LmFzc2lnbihjLm8sYik7SGcodGhpcyxhLGMpfX1lbHNlIGlmKGM9VChhKXx8RWcoYSkpaWYoYSE9PXRoaXMuYyYmKHRoaXMuZz0hMCksYiYmKGMubz1jLm98fHt9LE9iamVjdC5hc3NpZ24oYy5vLGIpKSxRKUhnKHRoaXMsYSxjKTtlbHNlIGlmKHRoaXMuZmx1c2goKSxHZyh0aGlzLGEsYyksYy5mYSYmYy5mYS5sZW5ndGgpe2I9cGYoYSkuaXM7dmFyIGQ7YTp7aWYoZD1DZy5jYWNoZVtiXSlmb3IodmFyIGU9ZC5sZW5ndGgtMTswPD1lO2UtLSl7dmFyIGY9ZFtlXTtiOnt2YXIgZz1jLmZhO2Zvcih2YXIgaD0wO2g8Zy5sZW5ndGg7aCsrKXt2YXIgaz1nW2hdO2lmKGYudltrXSE9PWMud1trXSl7Zz0hMTticmVhayBifX1nPSEwfWlmKGcpe2Q9ZjticmVhayBhfX1kPXZvaWQgMH1nPWQ/ZC5zdHlsZUVsZW1lbnQ6bnVsbDsKZT1jLnM7KGY9ZCYmZC5zKXx8KGY9dGhpcy5sW2JdPSh0aGlzLmxbYl18fDApKzEsZj1iKyItIitmKTtjLnM9ZjtmPWMucztoPWlnO2g9Zz9nLnRleHRDb250ZW50fHwiIjplZyhoLGEsYy53LGYpO2s9VChhKTt2YXIgbD1rLmE7bCYmIU8mJmwhPT1nJiYobC5fdXNlQ291bnQtLSwwPj1sLl91c2VDb3VudCYmbC5wYXJlbnROb2RlJiZsLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQobCkpO08/ay5hPyhrLmEudGV4dENvbnRlbnQ9aCxnPWsuYSk6aCYmKGc9Z2YoaCxmLGEuc2hhZG93Um9vdCxrLmIpKTpnP2cucGFyZW50Tm9kZXx8KFZmJiYtMTxoLmluZGV4T2YoIkBtZWRpYSIpJiYoZy50ZXh0Q29udGVudD1oKSxoZihnLG51bGwsay5iKSk6aCYmKGc9Z2YoaCxmLG51bGwsay5iKSk7ZyYmKGcuX3VzZUNvdW50PWcuX3VzZUNvdW50fHwwLGsuYSE9ZyYmZy5fdXNlQ291bnQrKyxrLmE9Zyk7Zj1nO098fChnPWMucyxrPWg9YS5nZXRBdHRyaWJ1dGUoImNsYXNzIil8fCIiLGUmJihrPWgucmVwbGFjZShuZXcgUmVnRXhwKCJcXHMqeC1zY29wZVxccyoiKwplKyJcXHMqIiwiZyIpLCIgIikpLGsrPShrPyIgIjoiIikrIngtc2NvcGUgIitnLGghPT1rJiZuZihhLGspKTtkfHxDZy5zdG9yZShiLGMudyxmLGMucyl9fTsKZnVuY3Rpb24gSGcoYSxiLGMpe3ZhciBkPXBmKGIpLmlzO2lmKGMubyl7dmFyIGU9Yy5vLGY7Zm9yKGYgaW4gZSludWxsPT09Zj9iLnN0eWxlLnJlbW92ZVByb3BlcnR5KGYpOmIuc3R5bGUuc2V0UHJvcGVydHkoZixlW2ZdKX1lPXdnW2RdO2lmKCEoIWUmJmIhPT1hLmN8fGUmJiIiIT09cmYoZSkpJiZlJiZlLl9zdHlsZSYmIXpnKGUpKXtpZih6ZyhlKXx8ZS5fYXBwbHlTaGltVmFsaWRhdGluZ1ZlcnNpb24hPT1lLl9hcHBseVNoaW1OZXh0VmVyc2lvbilEZyhhKSxhLmEmJmEuYS50cmFuc2Zvcm1SdWxlcyhlLl9zdHlsZUFzdCxkKSxlLl9zdHlsZS50ZXh0Q29udGVudD16ZihiLGMuQSksQWcoZSk7TyYmKGE9Yi5zaGFkb3dSb290KSYmKGE9YS5xdWVyeVNlbGVjdG9yKCJzdHlsZSIpKSYmKGEudGV4dENvbnRlbnQ9emYoYixjLkEpKTtjLkE9ZS5fc3R5bGVBc3R9fQpmdW5jdGlvbiBJZyhhLGIpe3JldHVybihiPW9mKGIpLmdldFJvb3ROb2RlKCkuaG9zdCk/VChiKXx8RWcoYik/YjpJZyhhLGIpOmEuY31mdW5jdGlvbiBHZyhhLGIsYyl7dmFyIGQ9SWcoYSxiKSxlPVQoZCksZj1lLnc7ZD09PWEuY3x8Znx8KEdnKGEsZCxlKSxmPWUudyk7YT1PYmplY3QuY3JlYXRlKGZ8fG51bGwpO2Q9ZGcoYixjLkEsYy5jc3NCdWlsZCk7Yj1iZyhlLkEsYikudjtPYmplY3QuYXNzaWduKGEsZC5IYSxiLGQuUmEpO2I9Yy5vO2Zvcih2YXIgZyBpbiBiKWlmKChlPWJbZ10pfHwwPT09ZSlhW2ddPWU7Zz1pZztiPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGEpO2ZvcihlPTA7ZTxiLmxlbmd0aDtlKyspZD1iW2VdLGFbZF09JGYoZyxhW2RdLGEpO2Mudz1hfW4uc3R5bGVEb2N1bWVudD1mdW5jdGlvbihhKXt0aGlzLnN0eWxlU3VidHJlZSh0aGlzLmMsYSl9OwpuLnN0eWxlU3VidHJlZT1mdW5jdGlvbihhLGIpe3ZhciBjPW9mKGEpLGQ9Yy5zaGFkb3dSb290OyhkfHxhPT09dGhpcy5jKSYmdGhpcy5zdHlsZUVsZW1lbnQoYSxiKTtpZihhPWQmJihkLmNoaWxkcmVufHxkLmNoaWxkTm9kZXMpKWZvcihjPTA7YzxhLmxlbmd0aDtjKyspdGhpcy5zdHlsZVN1YnRyZWUoYVtjXSk7ZWxzZSBpZihjPWMuY2hpbGRyZW58fGMuY2hpbGROb2Rlcylmb3IoYT0wO2E8Yy5sZW5ndGg7YSsrKXRoaXMuc3R5bGVTdWJ0cmVlKGNbYV0pfTsKbi5yYT1mdW5jdGlvbihhKXt2YXIgYj10aGlzLGM9cmYoYSk7YyE9PXRoaXMuZi5jc3NCdWlsZCYmKHRoaXMuZi5jc3NCdWlsZD1jKTtpZighc2YoYykpe3ZhciBkPWVmKGEpO2RmKGQsZnVuY3Rpb24oYSl7aWYoTylSZihhKTtlbHNle3ZhciBkPVI7YS5zZWxlY3Rvcj1hLnBhcnNlZFNlbGVjdG9yO1JmKGEpO2Euc2VsZWN0b3I9YS5qPUNmKGQsYSxkLmMsdm9pZCAwLHZvaWQgMCl9USYmIiI9PT1jJiYoRGcoYiksYi5hJiZiLmEudHJhbnNmb3JtUnVsZShhKSl9KTtRP2EudGV4dENvbnRlbnQ9Y2YoZCk6dGhpcy5mLkEucnVsZXMucHVzaChkKX19O24uZ2V0Q29tcHV0ZWRTdHlsZVZhbHVlPWZ1bmN0aW9uKGEsYil7dmFyIGM7UXx8KGM9KFQoYSl8fFQoSWcodGhpcyxhKSkpLndbYl0pO3JldHVybihjPWN8fHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGEpLmdldFByb3BlcnR5VmFsdWUoYikpP2MudHJpbSgpOiIifTsKbi5VYT1mdW5jdGlvbihhLGIpe3ZhciBjPW9mKGEpLmdldFJvb3ROb2RlKCk7Yj1iP2Iuc3BsaXQoL1xzLyk6W107Yz1jLmhvc3QmJmMuaG9zdC5sb2NhbE5hbWU7aWYoIWMpe3ZhciBkPWEuZ2V0QXR0cmlidXRlKCJjbGFzcyIpO2lmKGQpe2Q9ZC5zcGxpdCgvXHMvKTtmb3IodmFyIGU9MDtlPGQubGVuZ3RoO2UrKylpZihkW2VdPT09Ui5hKXtjPWRbZSsxXTticmVha319fWMmJmIucHVzaChSLmEsYyk7UXx8KGM9VChhKSkmJmMucyYmYi5wdXNoKGlnLmEsYy5zKTtuZihhLGIuam9pbigiICIpKX07bi5CYT1mdW5jdGlvbihhKXtyZXR1cm4gVChhKX07bi5UYT1mdW5jdGlvbihhLGIpe3dmKGEsYil9O24uV2E9ZnVuY3Rpb24oYSxiKXt3ZihhLGIsITApfTtuLlNhPWZ1bmN0aW9uKGEpe3JldHVybiBxZyhhKX07bi5EYT1mdW5jdGlvbihhKXtyZXR1cm4gcGcoYSl9O1kucHJvdG90eXBlLmZsdXNoPVkucHJvdG90eXBlLmZsdXNoO1kucHJvdG90eXBlLnByZXBhcmVUZW1wbGF0ZT1ZLnByb3RvdHlwZS5wcmVwYXJlVGVtcGxhdGU7ClkucHJvdG90eXBlLnN0eWxlRWxlbWVudD1ZLnByb3RvdHlwZS5zdHlsZUVsZW1lbnQ7WS5wcm90b3R5cGUuc3R5bGVEb2N1bWVudD1ZLnByb3RvdHlwZS5zdHlsZURvY3VtZW50O1kucHJvdG90eXBlLnN0eWxlU3VidHJlZT1ZLnByb3RvdHlwZS5zdHlsZVN1YnRyZWU7WS5wcm90b3R5cGUuZ2V0Q29tcHV0ZWRTdHlsZVZhbHVlPVkucHJvdG90eXBlLmdldENvbXB1dGVkU3R5bGVWYWx1ZTtZLnByb3RvdHlwZS5zZXRFbGVtZW50Q2xhc3M9WS5wcm90b3R5cGUuVWE7WS5wcm90b3R5cGUuX3N0eWxlSW5mb0Zvck5vZGU9WS5wcm90b3R5cGUuQmE7WS5wcm90b3R5cGUudHJhbnNmb3JtQ3VzdG9tU3R5bGVGb3JEb2N1bWVudD1ZLnByb3RvdHlwZS5yYTtZLnByb3RvdHlwZS5nZXRTdHlsZUFzdD1ZLnByb3RvdHlwZS5GYTtZLnByb3RvdHlwZS5zdHlsZUFzdFRvU3RyaW5nPVkucHJvdG90eXBlLlZhO1kucHJvdG90eXBlLmZsdXNoQ3VzdG9tU3R5bGVzPVkucHJvdG90eXBlLmZsdXNoQ3VzdG9tU3R5bGVzOwpZLnByb3RvdHlwZS5zY29wZU5vZGU9WS5wcm90b3R5cGUuVGE7WS5wcm90b3R5cGUudW5zY29wZU5vZGU9WS5wcm90b3R5cGUuV2E7WS5wcm90b3R5cGUuc2NvcGVGb3JOb2RlPVkucHJvdG90eXBlLlNhO1kucHJvdG90eXBlLmN1cnJlbnRTY29wZUZvck5vZGU9WS5wcm90b3R5cGUuRGE7WS5wcm90b3R5cGUucHJlcGFyZUFkb3B0ZWRDc3NUZXh0PVkucHJvdG90eXBlLlFhO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFkucHJvdG90eXBlLHtuYXRpdmVTaGFkb3c6e2dldDpmdW5jdGlvbigpe3JldHVybiBPfX0sbmF0aXZlQ3NzOntnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gUX19fSk7dmFyIFo9bmV3IFksSmcsS2c7d2luZG93LlNoYWR5Q1NTJiYoSmc9d2luZG93LlNoYWR5Q1NTLkFwcGx5U2hpbSxLZz13aW5kb3cuU2hhZHlDU1MuQ3VzdG9tU3R5bGVJbnRlcmZhY2UpOwp3aW5kb3cuU2hhZHlDU1M9e1Njb3BpbmdTaGltOloscHJlcGFyZVRlbXBsYXRlOmZ1bmN0aW9uKGEsYixjKXtaLmZsdXNoQ3VzdG9tU3R5bGVzKCk7Wi5wcmVwYXJlVGVtcGxhdGUoYSxiLGMpfSxwcmVwYXJlVGVtcGxhdGVEb206ZnVuY3Rpb24oYSxiKXtaLnByZXBhcmVUZW1wbGF0ZURvbShhLGIpfSxwcmVwYXJlVGVtcGxhdGVTdHlsZXM6ZnVuY3Rpb24oYSxiLGMpe1ouZmx1c2hDdXN0b21TdHlsZXMoKTtaLnByZXBhcmVUZW1wbGF0ZVN0eWxlcyhhLGIsYyl9LHN0eWxlU3VidHJlZTpmdW5jdGlvbihhLGIpe1ouZmx1c2hDdXN0b21TdHlsZXMoKTtaLnN0eWxlU3VidHJlZShhLGIpfSxzdHlsZUVsZW1lbnQ6ZnVuY3Rpb24oYSl7Wi5mbHVzaEN1c3RvbVN0eWxlcygpO1ouc3R5bGVFbGVtZW50KGEpfSxzdHlsZURvY3VtZW50OmZ1bmN0aW9uKGEpe1ouZmx1c2hDdXN0b21TdHlsZXMoKTtaLnN0eWxlRG9jdW1lbnQoYSl9LGZsdXNoQ3VzdG9tU3R5bGVzOmZ1bmN0aW9uKCl7Wi5mbHVzaEN1c3RvbVN0eWxlcygpfSwKZ2V0Q29tcHV0ZWRTdHlsZVZhbHVlOmZ1bmN0aW9uKGEsYil7cmV0dXJuIFouZ2V0Q29tcHV0ZWRTdHlsZVZhbHVlKGEsYil9LG5hdGl2ZUNzczpRLG5hdGl2ZVNoYWRvdzpPLGNzc0J1aWxkOlFlLGRpc2FibGVSdW50aW1lOlBlfTtKZyYmKHdpbmRvdy5TaGFkeUNTUy5BcHBseVNoaW09SmcpO0tnJiYod2luZG93LlNoYWR5Q1NTLkN1c3RvbVN0eWxlSW50ZXJmYWNlPUtnKTt2YXIgTGc9d2luZG93LmN1c3RvbUVsZW1lbnRzLE1nPXdpbmRvdy5IVE1MSW1wb3J0cyxOZz13aW5kb3cuSFRNTFRlbXBsYXRlRWxlbWVudDt3aW5kb3cuV2ViQ29tcG9uZW50cz13aW5kb3cuV2ViQ29tcG9uZW50c3x8e307aWYoTGcmJkxnLnBvbHlmaWxsV3JhcEZsdXNoQ2FsbGJhY2spe3ZhciBPZyxQZz1mdW5jdGlvbigpe2lmKE9nKXtOZy5DJiZOZy5DKHdpbmRvdy5kb2N1bWVudCk7dmFyIGE9T2c7T2c9bnVsbDthKCk7cmV0dXJuITB9fSxRZz1NZy53aGVuUmVhZHk7TGcucG9seWZpbGxXcmFwRmx1c2hDYWxsYmFjayhmdW5jdGlvbihhKXtPZz1hO1FnKFBnKX0pO01nLndoZW5SZWFkeT1mdW5jdGlvbihhKXtRZyhmdW5jdGlvbigpe1BnKCk/TWcud2hlblJlYWR5KGEpOmEoKX0pfX0KTWcud2hlblJlYWR5KGZ1bmN0aW9uKCl7cmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uKCl7d2luZG93LldlYkNvbXBvbmVudHMucmVhZHk9ITA7ZG9jdW1lbnQuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoIldlYkNvbXBvbmVudHNSZWFkeSIse2J1YmJsZXM6ITB9KSl9KX0pO3ZhciBSZz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzdHlsZSIpO1JnLnRleHRDb250ZW50PSJib2R5IHt0cmFuc2l0aW9uOiBvcGFjaXR5IGVhc2UtaW4gMC4yczsgfSBcbmJvZHlbdW5yZXNvbHZlZF0ge29wYWNpdHk6IDA7IGRpc3BsYXk6IGJsb2NrOyBvdmVyZmxvdzogaGlkZGVuOyBwb3NpdGlvbjogcmVsYXRpdmU7IH0gXG4iO3ZhciBTZz1kb2N1bWVudC5xdWVyeVNlbGVjdG9yKCJoZWFkIik7U2cuaW5zZXJ0QmVmb3JlKFJnLFNnLmZpcnN0Q2hpbGQpO30pLmNhbGwodGhpcyk7CgoKPC9zY3JpcHQ+PHNjcmlwdD4oZnVuY3Rpb24oKXsvKgoKQ29weXJpZ2h0IChjKSAyMDE3IFRoZSBQb2x5bWVyIFByb2plY3QgQXV0aG9ycy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KVGhpcyBjb2RlIG1heSBvbmx5IGJlIHVzZWQgdW5kZXIgdGhlIEJTRCBzdHlsZSBsaWNlbnNlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9MSUNFTlNFLnR4dApUaGUgY29tcGxldGUgc2V0IG9mIGF1dGhvcnMgbWF5IGJlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9BVVRIT1JTLnR4dApUaGUgY29tcGxldGUgc2V0IG9mIGNvbnRyaWJ1dG9ycyBtYXkgYmUgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL0NPTlRSSUJVVE9SUy50eHQKQ29kZSBkaXN0cmlidXRlZCBieSBHb29nbGUgYXMgcGFydCBvZiB0aGUgcG9seW1lciBwcm9qZWN0IGlzIGFsc28Kc3ViamVjdCB0byBhbiBhZGRpdGlvbmFsIElQIHJpZ2h0cyBncmFudCBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vUEFURU5UUy50eHQKKi8KJ3VzZSBzdHJpY3QnO3ZhciBsPSEod2luZG93LlNoYWR5RE9NJiZ3aW5kb3cuU2hhZHlET00uaW5Vc2UpLHA7ZnVuY3Rpb24gcihhKXtwPWEmJmEuc2hpbWNzc3Byb3BlcnRpZXM/ITE6bHx8IShuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9BcHBsZVdlYktpdFwvNjAxfEVkZ2VcLzE1Lyl8fCF3aW5kb3cuQ1NTfHwhQ1NTLnN1cHBvcnRzfHwhQ1NTLnN1cHBvcnRzKCJib3gtc2hhZG93IiwiMCAwIDAgdmFyKC0tZm9vKSIpKX12YXIgdDt3aW5kb3cuU2hhZHlDU1MmJnZvaWQgMCE9PXdpbmRvdy5TaGFkeUNTUy5jc3NCdWlsZCYmKHQ9d2luZG93LlNoYWR5Q1NTLmNzc0J1aWxkKTt2YXIgYWE9ISghd2luZG93LlNoYWR5Q1NTfHwhd2luZG93LlNoYWR5Q1NTLmRpc2FibGVSdW50aW1lKTsKd2luZG93LlNoYWR5Q1NTJiZ2b2lkIDAhPT13aW5kb3cuU2hhZHlDU1MubmF0aXZlQ3NzP3A9d2luZG93LlNoYWR5Q1NTLm5hdGl2ZUNzczp3aW5kb3cuU2hhZHlDU1M/KHIod2luZG93LlNoYWR5Q1NTKSx3aW5kb3cuU2hhZHlDU1M9dm9pZCAwKTpyKHdpbmRvdy5XZWJDb21wb25lbnRzJiZ3aW5kb3cuV2ViQ29tcG9uZW50cy5mbGFncyk7dmFyIHU9cCx2PXQ7ZnVuY3Rpb24gdygpe3RoaXMuZW5kPXRoaXMuc3RhcnQ9MDt0aGlzLnJ1bGVzPXRoaXMucGFyZW50PXRoaXMucHJldmlvdXM9bnVsbDt0aGlzLmNzc1RleHQ9dGhpcy5wYXJzZWRDc3NUZXh0PSIiO3RoaXMuYXRSdWxlPSExO3RoaXMudHlwZT0wO3RoaXMucGFyc2VkU2VsZWN0b3I9dGhpcy5zZWxlY3Rvcj10aGlzLmtleWZyYW1lc05hbWU9IiJ9CmZ1bmN0aW9uIHgoYSl7YT1hLnJlcGxhY2UoYmEsIiIpLnJlcGxhY2UoY2EsIiIpO3ZhciBiPXksYz1hLGU9bmV3IHc7ZS5zdGFydD0wO2UuZW5kPWMubGVuZ3RoO2Zvcih2YXIgZD1lLGY9MCxnPWMubGVuZ3RoO2Y8ZztmKyspaWYoInsiPT09Y1tmXSl7ZC5ydWxlc3x8KGQucnVsZXM9W10pO3ZhciBoPWQsaz1oLnJ1bGVzW2gucnVsZXMubGVuZ3RoLTFdfHxudWxsO2Q9bmV3IHc7ZC5zdGFydD1mKzE7ZC5wYXJlbnQ9aDtkLnByZXZpb3VzPWs7aC5ydWxlcy5wdXNoKGQpfWVsc2UifSI9PT1jW2ZdJiYoZC5lbmQ9ZisxLGQ9ZC5wYXJlbnR8fGUpO3JldHVybiBiKGUsYSl9CmZ1bmN0aW9uIHkoYSxiKXt2YXIgYz1iLnN1YnN0cmluZyhhLnN0YXJ0LGEuZW5kLTEpO2EucGFyc2VkQ3NzVGV4dD1hLmNzc1RleHQ9Yy50cmltKCk7YS5wYXJlbnQmJihjPWIuc3Vic3RyaW5nKGEucHJldmlvdXM/YS5wcmV2aW91cy5lbmQ6YS5wYXJlbnQuc3RhcnQsYS5zdGFydC0xKSxjPWRhKGMpLGM9Yy5yZXBsYWNlKHosIiAiKSxjPWMuc3Vic3RyaW5nKGMubGFzdEluZGV4T2YoIjsiKSsxKSxjPWEucGFyc2VkU2VsZWN0b3I9YS5zZWxlY3Rvcj1jLnRyaW0oKSxhLmF0UnVsZT0wPT09Yy5pbmRleE9mKCJAIiksYS5hdFJ1bGU/MD09PWMuaW5kZXhPZigiQG1lZGlhIik/YS50eXBlPUE6Yy5tYXRjaChlYSkmJihhLnR5cGU9QixhLmtleWZyYW1lc05hbWU9YS5zZWxlY3Rvci5zcGxpdCh6KS5wb3AoKSk6YS50eXBlPTA9PT1jLmluZGV4T2YoIi0tIik/QzpEKTtpZihjPWEucnVsZXMpZm9yKHZhciBlPTAsZD1jLmxlbmd0aCxmPXZvaWQgMDtlPGQmJihmPWNbZV0pO2UrKyl5KGYsYik7CnJldHVybiBhfWZ1bmN0aW9uIGRhKGEpe3JldHVybiBhLnJlcGxhY2UoL1xcKFswLTlhLWZdezEsNn0pXHMvZ2ksZnVuY3Rpb24oYSxjKXthPWM7Zm9yKGM9Ni1hLmxlbmd0aDtjLS07KWE9IjAiK2E7cmV0dXJuIlxcIithfSl9CmZ1bmN0aW9uIEUoYSxiLGMpe2M9dm9pZCAwPT09Yz8iIjpjO3ZhciBlPSIiO2lmKGEuY3NzVGV4dHx8YS5ydWxlcyl7dmFyIGQ9YS5ydWxlcyxmO2lmKGY9ZClmPWRbMF0sZj0hKGYmJmYuc2VsZWN0b3ImJjA9PT1mLnNlbGVjdG9yLmluZGV4T2YoIi0tIikpO2lmKGYpe2Y9MDtmb3IodmFyIGc9ZC5sZW5ndGgsaD12b2lkIDA7ZjxnJiYoaD1kW2ZdKTtmKyspZT1FKGgsYixlKX1lbHNlIGI/Yj1hLmNzc1RleHQ6KGI9YS5jc3NUZXh0LGI9Yi5yZXBsYWNlKGZhLCIiKS5yZXBsYWNlKGhhLCIiKSxiPWIucmVwbGFjZShpYSwiIikucmVwbGFjZShqYSwiIikpLChlPWIudHJpbSgpKSYmKGU9IiAgIitlKyJcbiIpfWUmJihhLnNlbGVjdG9yJiYoYys9YS5zZWxlY3RvcisiIHtcbiIpLGMrPWUsYS5zZWxlY3RvciYmKGMrPSJ9XG5cbiIpKTtyZXR1cm4gY30KdmFyIEQ9MSxCPTcsQT00LEM9MUUzLGJhPS9cL1wqW14qXSpcKisoW14vKl1bXipdKlwqKykqXC8vZ2ltLGNhPS9AaW1wb3J0W147XSo7L2dpbSxmYT0vKD86XlteO1wtXHN9XSspPy0tW147e31dKj86W157fTtdKj8oPzpbO1xuXXwkKS9naW0saGE9Lyg/Ol5bXjtcLVxzfV0rKT8tLVteO3t9XSo/Oltee307XSo/e1tefV0qP30oPzpbO1xuXXwkKT8vZ2ltLGlhPS9AYXBwbHlccypcKD9bXik7XSpcKT9ccyooPzpbO1xuXXwkKT8vZ2ltLGphPS9bXjs6XSo/OlteO10qP3ZhclwoW147XSpcKSg/Ols7XG5dfCQpPy9naW0sZWE9L15AW15cc10qa2V5ZnJhbWVzLyx6PS9ccysvZzt2YXIgRz0vKD86XnxbO1xze11ccyopKC0tW1x3LV0qPylccyo6XHMqKD86KCg/OicoPzpcXCd8LikqPyd8Iig/OlxcInwuKSo/InxcKFteKV0qP1wpfFtefTt7XSkrKXxceyhbXn1dKilcfSg/Oig/PVs7XHN9XSl8JCkpL2dpLEg9Lyg/Ol58XFcrKUBhcHBseVxzKlwoPyhbXik7XG5dKilcKT8vZ2ksa2E9L0BtZWRpYVxzKC4qKS87dmFyIEk9bmV3IFNldDtmdW5jdGlvbiBKKGEpe2lmKCFhKXJldHVybiIiOyJzdHJpbmciPT09dHlwZW9mIGEmJihhPXgoYSkpO3JldHVybiBFKGEsdSl9ZnVuY3Rpb24gSyhhKXshYS5fX2Nzc1J1bGVzJiZhLnRleHRDb250ZW50JiYoYS5fX2Nzc1J1bGVzPXgoYS50ZXh0Q29udGVudCkpO3JldHVybiBhLl9fY3NzUnVsZXN8fG51bGx9ZnVuY3Rpb24gTChhLGIsYyxlKXtpZihhKXt2YXIgZD0hMSxmPWEudHlwZTtpZihlJiZmPT09QSl7dmFyIGc9YS5zZWxlY3Rvci5tYXRjaChrYSk7ZyYmKHdpbmRvdy5tYXRjaE1lZGlhKGdbMV0pLm1hdGNoZXN8fChkPSEwKSl9Zj09PUQ/YihhKTpjJiZmPT09Qj9jKGEpOmY9PT1DJiYoZD0hMCk7aWYoKGE9YS5ydWxlcykmJiFkKWZvcihkPTAsZj1hLmxlbmd0aCxnPXZvaWQgMDtkPGYmJihnPWFbZF0pO2QrKylMKGcsYixjLGUpfX0KZnVuY3Rpb24gTShhLGIpe3ZhciBjPWEuaW5kZXhPZigidmFyKCIpO2lmKC0xPT09YylyZXR1cm4gYihhLCIiLCIiLCIiKTthOnt2YXIgZT0wO3ZhciBkPWMrMztmb3IodmFyIGY9YS5sZW5ndGg7ZDxmO2QrKylpZigiKCI9PT1hW2RdKWUrKztlbHNlIGlmKCIpIj09PWFbZF0mJjA9PT0tLWUpYnJlYWsgYTtkPS0xfWU9YS5zdWJzdHJpbmcoYys0LGQpO2M9YS5zdWJzdHJpbmcoMCxjKTthPU0oYS5zdWJzdHJpbmcoZCsxKSxiKTtkPWUuaW5kZXhPZigiLCIpO3JldHVybi0xPT09ZD9iKGMsZS50cmltKCksIiIsYSk6YihjLGUuc3Vic3RyaW5nKDAsZCkudHJpbSgpLGUuc3Vic3RyaW5nKGQrMSkudHJpbSgpLGEpfQpmdW5jdGlvbiBOKGEpe2lmKHZvaWQgMCE9PXYpcmV0dXJuIHY7aWYodm9pZCAwPT09YS5fX2Nzc0J1aWxkKXt2YXIgYj1hLmdldEF0dHJpYnV0ZSgiY3NzLWJ1aWxkIik7aWYoYilhLl9fY3NzQnVpbGQ9YjtlbHNle2E6e2I9InRlbXBsYXRlIj09PWEubG9jYWxOYW1lP2EuY29udGVudC5maXJzdENoaWxkOmEuZmlyc3RDaGlsZDtpZihiIGluc3RhbmNlb2YgQ29tbWVudCYmKGI9Yi50ZXh0Q29udGVudC50cmltKCkuc3BsaXQoIjoiKSwiY3NzLWJ1aWxkIj09PWJbMF0pKXtiPWJbMV07YnJlYWsgYX1iPSIifWlmKCIiIT09Yil7dmFyIGM9InRlbXBsYXRlIj09PWEubG9jYWxOYW1lP2EuY29udGVudC5maXJzdENoaWxkOmEuZmlyc3RDaGlsZDtjLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoYyl9YS5fX2Nzc0J1aWxkPWJ9fXJldHVybiBhLl9fY3NzQnVpbGR8fCIifTt2YXIgbGE9LztccyovbSxtYT0vXlxzKihpbml0aWFsKXwoaW5oZXJpdClccyokLyxPPS9ccyohaW1wb3J0YW50LztmdW5jdGlvbiBQKCl7dGhpcy5hPXt9fVAucHJvdG90eXBlLnNldD1mdW5jdGlvbihhLGIpe2E9YS50cmltKCk7dGhpcy5hW2FdPXtoOmIsaTp7fX19O1AucHJvdG90eXBlLmdldD1mdW5jdGlvbihhKXthPWEudHJpbSgpO3JldHVybiB0aGlzLmFbYV18fG51bGx9O3ZhciBRPW51bGw7ZnVuY3Rpb24gUigpe3RoaXMuYj10aGlzLmM9bnVsbDt0aGlzLmE9bmV3IFB9Ui5wcm90b3R5cGUubz1mdW5jdGlvbihhKXthPUgudGVzdChhKXx8Ry50ZXN0KGEpO0gubGFzdEluZGV4PTA7Ry5sYXN0SW5kZXg9MDtyZXR1cm4gYX07ClIucHJvdG90eXBlLm09ZnVuY3Rpb24oYSxiKXtpZih2b2lkIDA9PT1hLl9nYXRoZXJlZFN0eWxlKXt2YXIgYz1bXTtmb3IodmFyIGU9YS5jb250ZW50LnF1ZXJ5U2VsZWN0b3JBbGwoInN0eWxlIiksZD0wO2Q8ZS5sZW5ndGg7ZCsrKXt2YXIgZj1lW2RdO2lmKGYuaGFzQXR0cmlidXRlKCJzaGFkeS11bnNjb3BlZCIpKXtpZighbCl7dmFyIGc9Zi50ZXh0Q29udGVudDtJLmhhcyhnKXx8KEkuYWRkKGcpLGc9Zi5jbG9uZU5vZGUoITApLGRvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQoZykpO2YucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChmKX19ZWxzZSBjLnB1c2goZi50ZXh0Q29udGVudCksZi5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGYpfShjPWMuam9pbigiIikudHJpbSgpKT8oZT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzdHlsZSIpLGUudGV4dENvbnRlbnQ9YyxhLmNvbnRlbnQuaW5zZXJ0QmVmb3JlKGUsYS5jb250ZW50LmZpcnN0Q2hpbGQpLGM9ZSk6Yz1udWxsO2EuX2dhdGhlcmVkU3R5bGU9CmN9cmV0dXJuKGE9YS5fZ2F0aGVyZWRTdHlsZSk/dGhpcy5qKGEsYik6bnVsbH07Ui5wcm90b3R5cGUuaj1mdW5jdGlvbihhLGIpe2I9dm9pZCAwPT09Yj8iIjpiO3ZhciBjPUsoYSk7dGhpcy5sKGMsYik7YS50ZXh0Q29udGVudD1KKGMpO3JldHVybiBjfTtSLnByb3RvdHlwZS5mPWZ1bmN0aW9uKGEpe3ZhciBiPXRoaXMsYz1LKGEpO0woYyxmdW5jdGlvbihhKXsiOnJvb3QiPT09YS5zZWxlY3RvciYmKGEuc2VsZWN0b3I9Imh0bWwiKTtiLmcoYSl9KTthLnRleHRDb250ZW50PUooYyk7cmV0dXJuIGN9O1IucHJvdG90eXBlLmw9ZnVuY3Rpb24oYSxiKXt2YXIgYz10aGlzO3RoaXMuYz1iO0woYSxmdW5jdGlvbihhKXtjLmcoYSl9KTt0aGlzLmM9bnVsbH07Ui5wcm90b3R5cGUuZz1mdW5jdGlvbihhKXthLmNzc1RleHQ9bmEodGhpcyxhLnBhcnNlZENzc1RleHQsYSk7Ijpyb290Ij09PWEuc2VsZWN0b3ImJihhLnNlbGVjdG9yPSI6aG9zdCA+ICoiKX07CmZ1bmN0aW9uIG5hKGEsYixjKXtiPWIucmVwbGFjZShHLGZ1bmN0aW9uKGIsZCxmLGcpe3JldHVybiBvYShhLGIsZCxmLGcsYyl9KTtyZXR1cm4gUyhhLGIsYyl9ZnVuY3Rpb24gcGEoYSxiKXtmb3IodmFyIGM9YjtjLnBhcmVudDspYz1jLnBhcmVudDt2YXIgZT17fSxkPSExO0woYyxmdW5jdGlvbihjKXsoZD1kfHxjPT09Yil8fGMuc2VsZWN0b3I9PT1iLnNlbGVjdG9yJiZPYmplY3QuYXNzaWduKGUsVChhLGMucGFyc2VkQ3NzVGV4dCkpfSk7cmV0dXJuIGV9CmZ1bmN0aW9uIFMoYSxiLGMpe2Zvcih2YXIgZTtlPUguZXhlYyhiKTspe3ZhciBkPWVbMF0sZj1lWzFdO2U9ZS5pbmRleDt2YXIgZz1iLnNsaWNlKDAsZStkLmluZGV4T2YoIkBhcHBseSIpKTtiPWIuc2xpY2UoZStkLmxlbmd0aCk7dmFyIGg9Yz9wYShhLGMpOnt9O09iamVjdC5hc3NpZ24oaCxUKGEsZykpO2Q9dm9pZCAwO3ZhciBrPWE7Zj1mLnJlcGxhY2UobGEsIiIpO3ZhciBuPVtdO3ZhciBtPWsuYS5nZXQoZik7bXx8KGsuYS5zZXQoZix7fSksbT1rLmEuZ2V0KGYpKTtpZihtKXtrLmMmJihtLmlbay5jXT0hMCk7dmFyIHE9bS5oO2ZvcihkIGluIHEpaz1oJiZoW2RdLG09W2QsIjogdmFyKCIsZiwiXy1fIixkXSxrJiZtLnB1c2goIiwiLGsucmVwbGFjZShPLCIiKSksbS5wdXNoKCIpIiksTy50ZXN0KHFbZF0pJiZtLnB1c2goIiAhaW1wb3J0YW50Iiksbi5wdXNoKG0uam9pbigiIikpfWQ9bi5qb2luKCI7ICIpO2I9ZytkK2I7SC5sYXN0SW5kZXg9ZStkLmxlbmd0aH1yZXR1cm4gYn0KZnVuY3Rpb24gVChhLGIsYyl7Yz12b2lkIDA9PT1jPyExOmM7Yj1iLnNwbGl0KCI7Iik7Zm9yKHZhciBlLGQsZj17fSxnPTAsaDtnPGIubGVuZ3RoO2crKylpZihlPWJbZ10paWYoaD1lLnNwbGl0KCI6IiksMTxoLmxlbmd0aCl7ZT1oWzBdLnRyaW0oKTtkPWguc2xpY2UoMSkuam9pbigiOiIpO2lmKGMpe3ZhciBrPWE7aD1lO3ZhciBuPW1hLmV4ZWMoZCk7biYmKG5bMV0/KGsuYnx8KGsuYj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJtZXRhIiksay5iLnNldEF0dHJpYnV0ZSgiYXBwbHktc2hpbS1tZWFzdXJlIiwiIiksay5iLnN0eWxlLmFsbD0iaW5pdGlhbCIsZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChrLmIpKSxoPXdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGsuYikuZ2V0UHJvcGVydHlWYWx1ZShoKSk6aD0iYXBwbHktc2hpbS1pbmhlcml0IixkPWgpfWZbZV09ZH1yZXR1cm4gZn1mdW5jdGlvbiBxYShhLGIpe2lmKFEpZm9yKHZhciBjIGluIGIuaSljIT09YS5jJiZRKGMpfQpmdW5jdGlvbiBvYShhLGIsYyxlLGQsZil7ZSYmTShlLGZ1bmN0aW9uKGIsYyl7YyYmYS5hLmdldChjKSYmKGQ9IkBhcHBseSAiK2MrIjsiKX0pO2lmKCFkKXJldHVybiBiO3ZhciBnPVMoYSwiIitkLGYpO2Y9Yi5zbGljZSgwLGIuaW5kZXhPZigiLS0iKSk7dmFyIGg9Zz1UKGEsZywhMCksaz1hLmEuZ2V0KGMpLG49ayYmay5oO24/aD1PYmplY3QuYXNzaWduKE9iamVjdC5jcmVhdGUobiksZyk6YS5hLnNldChjLGgpO3ZhciBtPVtdLHEsWj0hMTtmb3IocSBpbiBoKXt2YXIgRj1nW3FdO3ZvaWQgMD09PUYmJihGPSJpbml0aWFsIik7IW58fHEgaW4gbnx8KFo9ITApO20ucHVzaChjKyJfLV8iK3ErIjogIitGKX1aJiZxYShhLGspO2smJihrLmg9aCk7ZSYmKGY9YisiOyIrZik7cmV0dXJuIGYrbS5qb2luKCI7ICIpKyI7In1SLnByb3RvdHlwZS5kZXRlY3RNaXhpbj1SLnByb3RvdHlwZS5vO1IucHJvdG90eXBlLnRyYW5zZm9ybVN0eWxlPVIucHJvdG90eXBlLmo7ClIucHJvdG90eXBlLnRyYW5zZm9ybUN1c3RvbVN0eWxlPVIucHJvdG90eXBlLmY7Ui5wcm90b3R5cGUudHJhbnNmb3JtUnVsZXM9Ui5wcm90b3R5cGUubDtSLnByb3RvdHlwZS50cmFuc2Zvcm1SdWxlPVIucHJvdG90eXBlLmc7Ui5wcm90b3R5cGUudHJhbnNmb3JtVGVtcGxhdGU9Ui5wcm90b3R5cGUubTtSLnByb3RvdHlwZS5fc2VwYXJhdG9yPSJfLV8iO09iamVjdC5kZWZpbmVQcm9wZXJ0eShSLnByb3RvdHlwZSwiaW52YWxpZENhbGxiYWNrIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIFF9LHNldDpmdW5jdGlvbihhKXtRPWF9fSk7dmFyIFU9e307dmFyIHJhPVByb21pc2UucmVzb2x2ZSgpO2Z1bmN0aW9uIHNhKGEpe2lmKGE9VVthXSlhLl9hcHBseVNoaW1DdXJyZW50VmVyc2lvbj1hLl9hcHBseVNoaW1DdXJyZW50VmVyc2lvbnx8MCxhLl9hcHBseVNoaW1WYWxpZGF0aW5nVmVyc2lvbj1hLl9hcHBseVNoaW1WYWxpZGF0aW5nVmVyc2lvbnx8MCxhLl9hcHBseVNoaW1OZXh0VmVyc2lvbj0oYS5fYXBwbHlTaGltTmV4dFZlcnNpb258fDApKzF9ZnVuY3Rpb24gdGEoYSl7cmV0dXJuIGEuX2FwcGx5U2hpbUN1cnJlbnRWZXJzaW9uPT09YS5fYXBwbHlTaGltTmV4dFZlcnNpb259ZnVuY3Rpb24gdWEoYSl7YS5fYXBwbHlTaGltVmFsaWRhdGluZ1ZlcnNpb249YS5fYXBwbHlTaGltTmV4dFZlcnNpb247YS5fdmFsaWRhdGluZ3x8KGEuX3ZhbGlkYXRpbmc9ITAscmEudGhlbihmdW5jdGlvbigpe2EuX2FwcGx5U2hpbUN1cnJlbnRWZXJzaW9uPWEuX2FwcGx5U2hpbU5leHRWZXJzaW9uO2EuX3ZhbGlkYXRpbmc9ITF9KSl9O3ZhciBWPW5ldyBSO2Z1bmN0aW9uIFcoKXt0aGlzLmE9bnVsbDtWLmludmFsaWRDYWxsYmFjaz1zYX1mdW5jdGlvbiBYKGEpeyFhLmEmJndpbmRvdy5TaGFkeUNTUy5DdXN0b21TdHlsZUludGVyZmFjZSYmKGEuYT13aW5kb3cuU2hhZHlDU1MuQ3VzdG9tU3R5bGVJbnRlcmZhY2UsYS5hLnRyYW5zZm9ybUNhbGxiYWNrPWZ1bmN0aW9uKGEpe1YuZihhKX0sYS5hLnZhbGlkYXRlQ2FsbGJhY2s9ZnVuY3Rpb24oKXtyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24oKXthLmEuZW5xdWV1ZWQmJmEuZmx1c2hDdXN0b21TdHlsZXMoKX0pfSl9Vy5wcm90b3R5cGUucHJlcGFyZVRlbXBsYXRlPWZ1bmN0aW9uKGEsYil7WCh0aGlzKTsiIj09PU4oYSkmJihVW2JdPWEsYj1WLm0oYSxiKSxhLl9zdHlsZUFzdD1iKX07ClcucHJvdG90eXBlLmZsdXNoQ3VzdG9tU3R5bGVzPWZ1bmN0aW9uKCl7WCh0aGlzKTtpZih0aGlzLmEpe3ZhciBhPXRoaXMuYS5wcm9jZXNzU3R5bGVzKCk7aWYodGhpcy5hLmVucXVldWVkKXtmb3IodmFyIGI9MDtiPGEubGVuZ3RoO2IrKyl7dmFyIGM9dGhpcy5hLmdldFN0eWxlRm9yQ3VzdG9tU3R5bGUoYVtiXSk7YyYmVi5mKGMpfXRoaXMuYS5lbnF1ZXVlZD0hMX19fTsKVy5wcm90b3R5cGUuc3R5bGVTdWJ0cmVlPWZ1bmN0aW9uKGEsYil7WCh0aGlzKTtpZihiKWZvcih2YXIgYyBpbiBiKW51bGw9PT1jP2Euc3R5bGUucmVtb3ZlUHJvcGVydHkoYyk6YS5zdHlsZS5zZXRQcm9wZXJ0eShjLGJbY10pO2lmKGEuc2hhZG93Um9vdClmb3IodGhpcy5zdHlsZUVsZW1lbnQoYSksYT1hLnNoYWRvd1Jvb3QuY2hpbGRyZW58fGEuc2hhZG93Um9vdC5jaGlsZE5vZGVzLGI9MDtiPGEubGVuZ3RoO2IrKyl0aGlzLnN0eWxlU3VidHJlZShhW2JdKTtlbHNlIGZvcihhPWEuY2hpbGRyZW58fGEuY2hpbGROb2RlcyxiPTA7YjxhLmxlbmd0aDtiKyspdGhpcy5zdHlsZVN1YnRyZWUoYVtiXSl9OwpXLnByb3RvdHlwZS5zdHlsZUVsZW1lbnQ9ZnVuY3Rpb24oYSl7WCh0aGlzKTt2YXIgYj1hLmxvY2FsTmFtZSxjO2I/LTE8Yi5pbmRleE9mKCItIik/Yz1iOmM9YS5nZXRBdHRyaWJ1dGUmJmEuZ2V0QXR0cmlidXRlKCJpcyIpfHwiIjpjPWEuaXM7Yj1VW2NdO2lmKCEoYiYmIiIhPT1OKGIpfHwhYnx8dGEoYikpKXtpZih0YShiKXx8Yi5fYXBwbHlTaGltVmFsaWRhdGluZ1ZlcnNpb24hPT1iLl9hcHBseVNoaW1OZXh0VmVyc2lvbil0aGlzLnByZXBhcmVUZW1wbGF0ZShiLGMpLHVhKGIpO2lmKGE9YS5zaGFkb3dSb290KWlmKGE9YS5xdWVyeVNlbGVjdG9yKCJzdHlsZSIpKWEuX19jc3NSdWxlcz1iLl9zdHlsZUFzdCxhLnRleHRDb250ZW50PUooYi5fc3R5bGVBc3QpfX07Vy5wcm90b3R5cGUuc3R5bGVEb2N1bWVudD1mdW5jdGlvbihhKXtYKHRoaXMpO3RoaXMuc3R5bGVTdWJ0cmVlKGRvY3VtZW50LmJvZHksYSl9OwppZighd2luZG93LlNoYWR5Q1NTfHwhd2luZG93LlNoYWR5Q1NTLlNjb3BpbmdTaGltKXt2YXIgWT1uZXcgVyx2YT13aW5kb3cuU2hhZHlDU1MmJndpbmRvdy5TaGFkeUNTUy5DdXN0b21TdHlsZUludGVyZmFjZTt3aW5kb3cuU2hhZHlDU1M9e3ByZXBhcmVUZW1wbGF0ZTpmdW5jdGlvbihhLGIpe1kuZmx1c2hDdXN0b21TdHlsZXMoKTtZLnByZXBhcmVUZW1wbGF0ZShhLGIpfSxwcmVwYXJlVGVtcGxhdGVTdHlsZXM6ZnVuY3Rpb24oYSxiLGMpe3dpbmRvdy5TaGFkeUNTUy5wcmVwYXJlVGVtcGxhdGUoYSxiLGMpfSxwcmVwYXJlVGVtcGxhdGVEb206ZnVuY3Rpb24oKXt9LHN0eWxlU3VidHJlZTpmdW5jdGlvbihhLGIpe1kuZmx1c2hDdXN0b21TdHlsZXMoKTtZLnN0eWxlU3VidHJlZShhLGIpfSxzdHlsZUVsZW1lbnQ6ZnVuY3Rpb24oYSl7WS5mbHVzaEN1c3RvbVN0eWxlcygpO1kuc3R5bGVFbGVtZW50KGEpfSxzdHlsZURvY3VtZW50OmZ1bmN0aW9uKGEpe1kuZmx1c2hDdXN0b21TdHlsZXMoKTsKWS5zdHlsZURvY3VtZW50KGEpfSxnZXRDb21wdXRlZFN0eWxlVmFsdWU6ZnVuY3Rpb24oYSxiKXtyZXR1cm4oYT13aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShhKS5nZXRQcm9wZXJ0eVZhbHVlKGIpKT9hLnRyaW0oKToiIn0sZmx1c2hDdXN0b21TdHlsZXM6ZnVuY3Rpb24oKXtZLmZsdXNoQ3VzdG9tU3R5bGVzKCl9LG5hdGl2ZUNzczp1LG5hdGl2ZVNoYWRvdzpsLGNzc0J1aWxkOnYsZGlzYWJsZVJ1bnRpbWU6YWF9O3ZhJiYod2luZG93LlNoYWR5Q1NTLkN1c3RvbVN0eWxlSW50ZXJmYWNlPXZhKX13aW5kb3cuU2hhZHlDU1MuQXBwbHlTaGltPVY7fSkuY2FsbCh0aGlzKTsKCgo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CiAgJ3VzZSBzdHJpY3QnOwoKICBjb25zdCB1c2VyUG9seW1lciA9IHdpbmRvdy5Qb2x5bWVyOwoKICAvKioKICAgKiBAbmFtZXNwYWNlIFBvbHltZXIKICAgKiBAc3VtbWFyeSBQb2x5bWVyIGlzIGEgbGlnaHR3ZWlnaHQgbGlicmFyeSBidWlsdCBvbiB0b3Agb2YgdGhlIHdlYgogICAqICAgc3RhbmRhcmRzLWJhc2VkIFdlYiBDb21wb25lbnRzIEFQSSdzLCBhbmQgbWFrZXMgaXQgZWFzeSB0byBidWlsZCB5b3VyCiAgICogICBvd24gY3VzdG9tIEhUTUwgZWxlbWVudHMuCiAgICogQHBhcmFtIHshUG9seW1lckluaXR9IGluZm8gUHJvdG90eXBlIGZvciB0aGUgY3VzdG9tIGVsZW1lbnQuIEl0IG11c3QgY29udGFpbgogICAqICAgYW4gYGlzYCBwcm9wZXJ0eSB0byBzcGVjaWZ5IHRoZSBlbGVtZW50IG5hbWUuIE90aGVyIHByb3BlcnRpZXMgcG9wdWxhdGUKICAgKiAgIHRoZSBlbGVtZW50IHByb3RvdHlwZS4gVGhlIGBwcm9wZXJ0aWVzYCwgYG9ic2VydmVyc2AsIGBob3N0QXR0cmlidXRlc2AsCiAgICogICBhbmQgYGxpc3RlbmVyc2AgcHJvcGVydGllcyBhcmUgcHJvY2Vzc2VkIHRvIGNyZWF0ZSBlbGVtZW50IGZlYXR1cmVzLgogICAqIEByZXR1cm4geyFPYmplY3R9IFJldHVybnMgYSBjdXN0b20gZWxlbWVudCBjbGFzcyBmb3IgdGhlIGdpdmVuIHByb3ZpZGVkCiAgICogICBwcm90b3R5cGUgYGluZm9gIG9iamVjdC4gVGhlIG5hbWUgb2YgdGhlIGVsZW1lbnQgaWYgZ2l2ZW4gYnkgYGluZm8uaXNgLgogICAqLwogIHdpbmRvdy5Qb2x5bWVyID0gZnVuY3Rpb24oaW5mbykgewogICAgcmV0dXJuIHdpbmRvdy5Qb2x5bWVyLl9wb2x5bWVyRm4oaW5mbyk7CiAgfTsKCiAgLy8gc3VwcG9ydCB1c2VyIHNldHRpbmdzIG9uIHRoZSBQb2x5bWVyIG9iamVjdAogIGlmICh1c2VyUG9seW1lcikgewogICAgT2JqZWN0LmFzc2lnbihQb2x5bWVyLCB1c2VyUG9seW1lcik7CiAgfQoKICAvLyBUbyBiZSBwbHVnZ2VkIGJ5IGxlZ2FjeSBpbXBsZW1lbnRhdGlvbiBpZiBsb2FkZWQKICAvKiBlc2xpbnQtZGlzYWJsZSB2YWxpZC1qc2RvYyAqLwogIC8qKgogICAqIEBwYXJhbSB7IVBvbHltZXJJbml0fSBpbmZvIFByb3RvdHlwZSBmb3IgdGhlIGN1c3RvbSBlbGVtZW50LiBJdCBtdXN0IGNvbnRhaW4KICAgKiAgIGFuIGBpc2AgcHJvcGVydHkgdG8gc3BlY2lmeSB0aGUgZWxlbWVudCBuYW1lLiBPdGhlciBwcm9wZXJ0aWVzIHBvcHVsYXRlCiAgICogICB0aGUgZWxlbWVudCBwcm90b3R5cGUuIFRoZSBgcHJvcGVydGllc2AsIGBvYnNlcnZlcnNgLCBgaG9zdEF0dHJpYnV0ZXNgLAogICAqICAgYW5kIGBsaXN0ZW5lcnNgIHByb3BlcnRpZXMgYXJlIHByb2Nlc3NlZCB0byBjcmVhdGUgZWxlbWVudCBmZWF0dXJlcy4KICAgKiBAcmV0dXJuIHshT2JqZWN0fSBSZXR1cm5zIGEgY3VzdG9tIGVsZW1lbnQgY2xhc3MgZm9yIHRoZSBnaXZlbiBwcm92aWRlZAogICAqICAgcHJvdG90eXBlIGBpbmZvYCBvYmplY3QuIFRoZSBuYW1lIG9mIHRoZSBlbGVtZW50IGlmIGdpdmVuIGJ5IGBpbmZvLmlzYC4KICAgKi8KICB3aW5kb3cuUG9seW1lci5fcG9seW1lckZuID0gZnVuY3Rpb24oaW5mbykgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzCiAgICB0aHJvdyBuZXcgRXJyb3IoJ0xvYWQgcG9seW1lci5odG1sIHRvIHVzZSB0aGUgUG9seW1lcigpIGZ1bmN0aW9uLicpOwogIH07CiAgLyogZXNsaW50LWVuYWJsZSAqLwoKICB3aW5kb3cuUG9seW1lci52ZXJzaW9uID0gJzIuNy4wJzsKCiAgLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi8KICAvKgogIFdoZW4gdXNpbmcgQ2xvc3VyZSBDb21waWxlciwgSlNDb21waWxlcl9yZW5hbWVQcm9wZXJ0eShwcm9wZXJ0eSwgb2JqZWN0KSBpcyByZXBsYWNlZCBieSB0aGUgbXVuZ2VkIG5hbWUgZm9yIG9iamVjdFtwcm9wZXJ0eV0KICBXZSBjYW5ub3QgYWxpYXMgdGhpcyBmdW5jdGlvbiwgc28gd2UgaGF2ZSB0byB1c2UgYSBzbWFsbCBzaGltIHRoYXQgaGFzIHRoZSBzYW1lIGJlaGF2aW9yIHdoZW4gbm90IGNvbXBpbGluZy4KICAqLwogIHdpbmRvdy5KU0NvbXBpbGVyX3JlbmFtZVByb3BlcnR5ID0gZnVuY3Rpb24ocHJvcCwgb2JqKSB7CiAgICByZXR1cm4gcHJvcDsKICB9OwogIC8qIGVzbGludC1lbmFibGUgKi8KCn0pKCk7Cjwvc2NyaXB0PjxzY3JpcHQ+CgogIChmdW5jdGlvbigpIHsKICAgICd1c2Ugc3RyaWN0JzsKCiAgICBsZXQgQ1NTX1VSTF9SWCA9IC8odXJsXCgpKFteKV0qKShcKSkvZzsKICAgIGxldCBBQlNfVVJMID0gLyheXC8pfCheIyl8KF5bXHctXGRdKjopLzsKICAgIGxldCB3b3JraW5nVVJMOwogICAgbGV0IHJlc29sdmVEb2M7CiAgICAvKioKICAgICAqIFJlc29sdmVzIHRoZSBnaXZlbiBVUkwgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYGJhc2VVcmknLgogICAgICogCiAgICAgKiBOb3RlIHRoYXQgdGhpcyBmdW5jdGlvbiBwZXJmb3JtcyBubyByZXNvbHV0aW9uIGZvciBVUkxzIHRoYXQgc3RhcnQKICAgICAqIHdpdGggYC9gIChhYnNvbHV0ZSBVUkxzKSBvciBgI2AgKGhhc2ggaWRlbnRpZmllcnMpLiAgRm9yIGdlbmVyYWwgcHVycG9zZQogICAgICogVVJMIHJlc29sdXRpb24sIHVzZSBgd2luZG93LlVSTGAuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuUmVzb2x2ZVVybAogICAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBJbnB1dCBVUkwgdG8gcmVzb2x2ZQogICAgICogQHBhcmFtIHs/c3RyaW5nPX0gYmFzZVVSSSBCYXNlIFVSSSB0byByZXNvbHZlIHRoZSBVUkwgYWdhaW5zdAogICAgICogQHJldHVybiB7c3RyaW5nfSByZXNvbHZlZCBVUkwKICAgICAqLwogICAgZnVuY3Rpb24gcmVzb2x2ZVVybCh1cmwsIGJhc2VVUkkpIHsKICAgICAgaWYgKHVybCAmJiBBQlNfVVJMLnRlc3QodXJsKSkgewogICAgICAgIHJldHVybiB1cmw7CiAgICAgIH0KICAgICAgLy8gTGF6eSBmZWF0dXJlIGRldGVjdGlvbi4KICAgICAgaWYgKHdvcmtpbmdVUkwgPT09IHVuZGVmaW5lZCkgewogICAgICAgIHdvcmtpbmdVUkwgPSBmYWxzZTsKICAgICAgICB0cnkgewogICAgICAgICAgY29uc3QgdSA9IG5ldyBVUkwoJ2InLCAnaHR0cDovL2EnKTsKICAgICAgICAgIHUucGF0aG5hbWUgPSAnYyUyMGQnOwogICAgICAgICAgd29ya2luZ1VSTCA9ICh1LmhyZWYgPT09ICdodHRwOi8vYS9jJTIwZCcpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIC8vIHNpbGVudGx5IGZhaWwKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKCFiYXNlVVJJKSB7CiAgICAgICAgYmFzZVVSSSA9IGRvY3VtZW50LmJhc2VVUkkgfHwgd2luZG93LmxvY2F0aW9uLmhyZWY7CiAgICAgIH0KICAgICAgaWYgKHdvcmtpbmdVUkwpIHsKICAgICAgICByZXR1cm4gKG5ldyBVUkwodXJsLCBiYXNlVVJJKSkuaHJlZjsKICAgICAgfQogICAgICAvLyBGYWxsYmFjayB0byBjcmVhdGluZyBhbiBhbmNob3IgaW50byBhIGRpc2Nvbm5lY3RlZCBkb2N1bWVudC4KICAgICAgaWYgKCFyZXNvbHZlRG9jKSB7CiAgICAgICAgcmVzb2x2ZURvYyA9IGRvY3VtZW50LmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgndGVtcCcpOwogICAgICAgIHJlc29sdmVEb2MuYmFzZSA9IHJlc29sdmVEb2MuY3JlYXRlRWxlbWVudCgnYmFzZScpOwogICAgICAgIHJlc29sdmVEb2MuaGVhZC5hcHBlbmRDaGlsZChyZXNvbHZlRG9jLmJhc2UpOwogICAgICAgIHJlc29sdmVEb2MuYW5jaG9yID0gcmVzb2x2ZURvYy5jcmVhdGVFbGVtZW50KCdhJyk7CiAgICAgICAgcmVzb2x2ZURvYy5ib2R5LmFwcGVuZENoaWxkKHJlc29sdmVEb2MuYW5jaG9yKTsKICAgICAgfQogICAgICByZXNvbHZlRG9jLmJhc2UuaHJlZiA9IGJhc2VVUkk7CiAgICAgIHJlc29sdmVEb2MuYW5jaG9yLmhyZWYgPSB1cmw7CiAgICAgIHJldHVybiByZXNvbHZlRG9jLmFuY2hvci5ocmVmIHx8IHVybDsKCiAgICB9CgogICAgLyoqCiAgICAgKiBSZXNvbHZlcyBhbnkgcmVsYXRpdmUgVVJMJ3MgaW4gdGhlIGdpdmVuIENTUyB0ZXh0IGFnYWluc3QgdGhlIHByb3ZpZGVkCiAgICAgKiBgb3duZXJEb2N1bWVudGAncyBgYmFzZVVSSWAuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuUmVzb2x2ZVVybAogICAgICogQHBhcmFtIHtzdHJpbmd9IGNzc1RleHQgQ1NTIHRleHQgdG8gcHJvY2VzcwogICAgICogQHBhcmFtIHtzdHJpbmd9IGJhc2VVUkkgQmFzZSBVUkkgdG8gcmVzb2x2ZSB0aGUgVVJMIGFnYWluc3QKICAgICAqIEByZXR1cm4ge3N0cmluZ30gUHJvY2Vzc2VkIENTUyB0ZXh0IHdpdGggcmVzb2x2ZWQgVVJMJ3MKICAgICAqLwogICAgZnVuY3Rpb24gcmVzb2x2ZUNzcyhjc3NUZXh0LCBiYXNlVVJJKSB7CiAgICAgIHJldHVybiBjc3NUZXh0LnJlcGxhY2UoQ1NTX1VSTF9SWCwgZnVuY3Rpb24obSwgcHJlLCB1cmwsIHBvc3QpIHsKICAgICAgICByZXR1cm4gcHJlICsgJ1wnJyArCiAgICAgICAgICByZXNvbHZlVXJsKHVybC5yZXBsYWNlKC9bIiddL2csICcnKSwgYmFzZVVSSSkgKwogICAgICAgICAgJ1wnJyArIHBvc3Q7CiAgICAgIH0pOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIHBhdGggZnJvbSBhIGdpdmVuIGB1cmxgLiBUaGUgcGF0aCBpbmNsdWRlcyB0aGUgdHJhaWxpbmcKICAgICAqIGAvYCBmcm9tIHRoZSB1cmwuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuUmVzb2x2ZVVybAogICAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBJbnB1dCBVUkwgdG8gdHJhbnNmb3JtCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IHJlc29sdmVkIHBhdGgKICAgICAqLwogICAgZnVuY3Rpb24gcGF0aEZyb21VcmwodXJsKSB7CiAgICAgIHJldHVybiB1cmwuc3Vic3RyaW5nKDAsIHVybC5sYXN0SW5kZXhPZignLycpICsgMSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBNb2R1bGUgd2l0aCB1dGlsaXRpZXMgZm9yIHJlc29sdmluZyByZWxhdGl2ZSBVUkwncy4KICAgICAqCiAgICAgKiBAbmFtZXNwYWNlCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAgICogQHN1bW1hcnkgTW9kdWxlIHdpdGggdXRpbGl0aWVzIGZvciByZXNvbHZpbmcgcmVsYXRpdmUgVVJMJ3MuCiAgICAgKi8KICAgIFBvbHltZXIuUmVzb2x2ZVVybCA9IHsKICAgICAgcmVzb2x2ZUNzczogcmVzb2x2ZUNzcywKICAgICAgcmVzb2x2ZVVybDogcmVzb2x2ZVVybCwKICAgICAgcGF0aEZyb21Vcmw6IHBhdGhGcm9tVXJsCiAgICB9OwoKICB9KSgpOwoKPC9zY3JpcHQ+PHNjcmlwdD4KLyoqIEBzdXBwcmVzcyB7ZGVwcmVjYXRlZH0gKi8KKGZ1bmN0aW9uKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgLyoqCiAgICogU2V0cyB0aGUgZ2xvYmFsLCBsZWdhY3kgc2V0dGluZ3MuCiAgICoKICAgKiBAZGVwcmVjYXRlZAogICAqIEBuYW1lc3BhY2UKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqLwogIFBvbHltZXIuU2V0dGluZ3MgPSBQb2x5bWVyLlNldHRpbmdzIHx8IHt9OwoKICBQb2x5bWVyLlNldHRpbmdzLnVzZVNoYWRvdyA9ICEod2luZG93LlNoYWR5RE9NKTsKICBQb2x5bWVyLlNldHRpbmdzLnVzZU5hdGl2ZUNTU1Byb3BlcnRpZXMgPQogICAgQm9vbGVhbighd2luZG93LlNoYWR5Q1NTIHx8IHdpbmRvdy5TaGFkeUNTUy5uYXRpdmVDc3MpOwogIFBvbHltZXIuU2V0dGluZ3MudXNlTmF0aXZlQ3VzdG9tRWxlbWVudHMgPQogICAgISh3aW5kb3cuY3VzdG9tRWxlbWVudHMucG9seWZpbGxXcmFwRmx1c2hDYWxsYmFjayk7CgoKICAvKioKICAgKiBHbG9iYWxseSBzZXR0YWJsZSBwcm9wZXJ0eSB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgYXNzaWduZWQgdG8KICAgKiBgUG9seW1lci5FbGVtZW50TWl4aW5gIGluc3RhbmNlcywgdXNlZnVsIGZvciBiaW5kaW5nIGluIHRlbXBsYXRlcyB0bwogICAqIG1ha2UgVVJMJ3MgcmVsYXRpdmUgdG8gYW4gYXBwbGljYXRpb24ncyByb290LiAgRGVmYXVsdHMgdG8gdGhlIG1haW4KICAgKiBkb2N1bWVudCBVUkwsIGJ1dCBjYW4gYmUgb3ZlcnJpZGRlbiBieSB1c2Vycy4gIEl0IG1heSBiZSB1c2VmdWwgdG8gc2V0CiAgICogYFBvbHltZXIucm9vdFBhdGhgIHRvIHByb3ZpZGUgYSBzdGFibGUgYXBwbGljYXRpb24gbW91bnQgcGF0aCB3aGVuCiAgICogdXNpbmcgY2xpZW50IHNpZGUgcm91dGluZy4KICAgKgogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICovCiAgUG9seW1lci5yb290UGF0aCA9IFBvbHltZXIucm9vdFBhdGggfHwKICAgIFBvbHltZXIuUmVzb2x2ZVVybC5wYXRoRnJvbVVybChkb2N1bWVudC5iYXNlVVJJIHx8IHdpbmRvdy5sb2NhdGlvbi5ocmVmKTsKCiAgLyoqCiAgICogU2V0cyB0aGUgZ2xvYmFsIHJvb3RQYXRoIHByb3BlcnR5IHVzZWQgYnkgYFBvbHltZXIuRWxlbWVudE1peGluYCBhbmQKICAgKiBhdmFpbGFibGUgdmlhIGBQb2x5bWVyLnJvb3RQYXRoYC4KICAgKgogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggVGhlIG5ldyByb290IHBhdGgKICAgKiBAcmV0dXJuIHt2b2lkfQogICAqLwogIFBvbHltZXIuc2V0Um9vdFBhdGggPSBmdW5jdGlvbihwYXRoKSB7CiAgICBQb2x5bWVyLnJvb3RQYXRoID0gcGF0aDsKICB9OwoKICAvKioKICAgKiBBIGdsb2JhbCBjYWxsYmFjayB1c2VkIHRvIHNhbml0aXplIGFueSB2YWx1ZSBiZWZvcmUgaW5zZXJ0aW5nIGl0IGludG8gdGhlIERPTS4gVGhlIGNhbGxiYWNrIHNpZ25hdHVyZSBpczoKICAgKgogICAqICAgICBQb2x5bWVyID0gewogICAqICAgICAgIHNhbml0aXplRE9NVmFsdWU6IGZ1bmN0aW9uKHZhbHVlLCBuYW1lLCB0eXBlLCBub2RlKSB7IC4uLiB9CiAgICogICAgIH0KICAgKgogICAqIFdoZXJlOgogICAqCiAgICogYHZhbHVlYCBpcyB0aGUgdmFsdWUgdG8gc2FuaXRpemUuCiAgICogYG5hbWVgIGlzIHRoZSBuYW1lIG9mIGFuIGF0dHJpYnV0ZSBvciBwcm9wZXJ0eSAoZm9yIGV4YW1wbGUsIGhyZWYpLgogICAqIGB0eXBlYCBpbmRpY2F0ZXMgd2hlcmUgdGhlIHZhbHVlIGlzIGJlaW5nIGluc2VydGVkOiBvbmUgb2YgcHJvcGVydHksIGF0dHJpYnV0ZSwgb3IgdGV4dC4KICAgKiBgbm9kZWAgaXMgdGhlIG5vZGUgd2hlcmUgdGhlIHZhbHVlIGlzIGJlaW5nIGluc2VydGVkLgogICAqCiAgICogQHR5cGUgeyhmdW5jdGlvbigqLHN0cmluZyxzdHJpbmcsTm9kZSk6Kil8dW5kZWZpbmVkfQogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICovCiAgUG9seW1lci5zYW5pdGl6ZURPTVZhbHVlID0gUG9seW1lci5zYW5pdGl6ZURPTVZhbHVlIHx8IG51bGw7CgogIC8qKgogICAqIFNldHMgdGhlIGdsb2JhbCBzYW5pdGl6ZURPTVZhbHVlIGF2YWlsYWJsZSB2aWEgYFBvbHltZXIuc2FuaXRpemVET01WYWx1ZWAuCiAgICoKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBwYXJhbSB7KGZ1bmN0aW9uKCosc3RyaW5nLHN0cmluZyxOb2RlKToqKXx1bmRlZmluZWR9IG5ld1Nhbml0aXplRE9NVmFsdWUgdGhlIGdsb2JhbCBzYW5pdGl6ZURPTVZhbHVlIGNhbGxiYWNrCiAgICogQHJldHVybiB7dm9pZH0KICAgKi8KICBQb2x5bWVyLnNldFNhbml0aXplRE9NVmFsdWUgPSBmdW5jdGlvbihuZXdTYW5pdGl6ZURPTVZhbHVlKSB7CiAgICBQb2x5bWVyLnNhbml0aXplRE9NVmFsdWUgPSBuZXdTYW5pdGl6ZURPTVZhbHVlOwogIH07CgogIC8qKgogICAqIEdsb2JhbGx5IHNldHRhYmxlIHByb3BlcnR5IHRvIG1ha2UgUG9seW1lciBHZXN0dXJlcyB1c2UgcGFzc2l2ZSBUb3VjaEV2ZW50IGxpc3RlbmVycyB3aGVuIHJlY29nbml6aW5nIGdlc3R1cmVzLgogICAqIFdoZW4gc2V0IHRvIGB0cnVlYCwgZ2VzdHVyZXMgbWFkZSBmcm9tIHRvdWNoIHdpbGwgbm90IGJlIGFibGUgdG8gcHJldmVudCBzY3JvbGxpbmcsIGFsbG93aW5nIGZvciBzbW9vdGhlcgogICAqIHNjcm9sbGluZyBwZXJmb3JtYW5jZS4KICAgKiBEZWZhdWx0cyB0byBgZmFsc2VgIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS4KICAgKgogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICovCiAgUG9seW1lci5wYXNzaXZlVG91Y2hHZXN0dXJlcyA9IFBvbHltZXIucGFzc2l2ZVRvdWNoR2VzdHVyZXMgfHwgZmFsc2U7CgogIC8qKgogICAqIFNldHMgYHBhc3NpdmVUb3VjaEdlc3R1cmVzYCBnbG9iYWxseSBmb3IgYWxsIGVsZW1lbnRzIHVzaW5nIFBvbHltZXIgR2VzdHVyZXMuCiAgICoKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBwYXJhbSB7Ym9vbGVhbn0gdXNlUGFzc2l2ZSBlbmFibGUgb3IgZGlzYWJsZSBwYXNzaXZlIHRvdWNoIGdlc3R1cmVzIGdsb2JhbGx5CiAgICogQHJldHVybiB7dm9pZH0KICAgKi8KICBQb2x5bWVyLnNldFBhc3NpdmVUb3VjaEdlc3R1cmVzID0gZnVuY3Rpb24odXNlUGFzc2l2ZSkgewogICAgUG9seW1lci5wYXNzaXZlVG91Y2hHZXN0dXJlcyA9IHVzZVBhc3NpdmU7CiAgfTsKCiAgUG9seW1lci5sZWdhY3lPcHRpbWl6YXRpb25zID0gUG9seW1lci5sZWdhY3lPcHRpbWl6YXRpb25zIHx8CiAgICAgIHdpbmRvdy5Qb2x5bWVyU2V0dGluZ3MgJiYgd2luZG93LlBvbHltZXJTZXR0aW5ncy5sZWdhY3lPcHRpbWl6YXRpb25zIHx8IGZhbHNlOwoKICAvKioKICAgKiBTZXRzIGBsZWdhY3lPcHRpbWl6YXRpb25zYCBnbG9iYWxseSBmb3IgYWxsIGVsZW1lbnRzLiBFbmFibGVzCiAgICogb3B0aW1pemF0aW9ucyB3aGVuIG9ubHkgbGVnYWN5IFBvbHltZXIoKSBzdHlsZSBlbGVtZW50cyBhcmUgdXNlZC4KICAgKgogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICogQHBhcmFtIHtib29sZWFufSB1c2VMZWdhY3lPcHRpbWl6YXRpb25zIGVuYWJsZSBvciBkaXNhYmxlIGxlZ2FjeSBvcHRpbWl6YXRpb25zIGdsb2JhbGx5LgogICAqIEByZXR1cm4ge3ZvaWR9CiAgICovCiAgUG9seW1lci5zZXRMZWdhY3lPcHRpbWl6YXRpb25zID0gZnVuY3Rpb24odXNlTGVnYWN5T3B0aW1pemF0aW9ucykgewogICAgUG9seW1lci5sZWdhY3lPcHRpbWl6YXRpb25zID0gdXNlTGVnYWN5T3B0aW1pemF0aW9uczsKICB9Owp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgoKKGZ1bmN0aW9uKCkgewoKICAndXNlIHN0cmljdCc7CgogIC8vIHVuaXF1ZSBnbG9iYWwgaWQgZm9yIGRlZHVwaW5nIG1peGlucy4KICBsZXQgZGVkdXBlSWQgPSAwOwoKICAvKioKICAgKiBAY29uc3RydWN0b3IKICAgKiBAZXh0ZW5kcyB7RnVuY3Rpb259CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBNaXhpbkZ1bmN0aW9uKCl7fQogIC8qKiBAdHlwZSB7KFdlYWtNYXAgfCB1bmRlZmluZWQpfSAqLwogIE1peGluRnVuY3Rpb24ucHJvdG90eXBlLl9fbWl4aW5BcHBsaWNhdGlvbnM7CiAgLyoqIEB0eXBlIHsoT2JqZWN0IHwgdW5kZWZpbmVkKX0gKi8KICBNaXhpbkZ1bmN0aW9uLnByb3RvdHlwZS5fX21peGluU2V0OwoKICAvKiBlc2xpbnQtZGlzYWJsZSB2YWxpZC1qc2RvYyAqLwogIC8qKgogICAqIFdyYXBzIGFuIEVTNiBjbGFzcyBleHByZXNzaW9uIG1peGluIHN1Y2ggdGhhdCB0aGUgbWl4aW4gaXMgb25seSBhcHBsaWVkCiAgICogaWYgaXQgaGFzIG5vdCBhbHJlYWR5IGJlZW4gYXBwbGllZCBpdHMgYmFzZSBhcmd1bWVudC4gQWxzbyBtZW1vaXplcyBtaXhpbgogICAqIGFwcGxpY2F0aW9ucy4KICAgKgogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICogQHRlbXBsYXRlIFQKICAgKiBAcGFyYW0ge1R9IG1peGluIEVTNiBjbGFzcyBleHByZXNzaW9uIG1peGluIHRvIHdyYXAKICAgKiBAcmV0dXJuIHtUfQogICAqIEBzdXBwcmVzcyB7aW52YWxpZENhc3RzfQogICAqLwogIFBvbHltZXIuZGVkdXBpbmdNaXhpbiA9IGZ1bmN0aW9uKG1peGluKSB7CiAgICBsZXQgbWl4aW5BcHBsaWNhdGlvbnMgPSAvKiogQHR5cGUgeyFNaXhpbkZ1bmN0aW9ufSAqLyhtaXhpbikuX19taXhpbkFwcGxpY2F0aW9uczsKICAgIGlmICghbWl4aW5BcHBsaWNhdGlvbnMpIHsKICAgICAgbWl4aW5BcHBsaWNhdGlvbnMgPSBuZXcgV2Vha01hcCgpOwogICAgICAvKiogQHR5cGUgeyFNaXhpbkZ1bmN0aW9ufSAqLyhtaXhpbikuX19taXhpbkFwcGxpY2F0aW9ucyA9IG1peGluQXBwbGljYXRpb25zOwogICAgfQogICAgLy8gbWFpbnRhaW4gYSB1bmlxdWUgaWQgZm9yIGVhY2ggbWl4aW4KICAgIGxldCBtaXhpbkRlZHVwZUlkID0gZGVkdXBlSWQrKzsKICAgIGZ1bmN0aW9uIGRlZHVwaW5nTWl4aW4oYmFzZSkgewogICAgICBsZXQgYmFzZVNldCA9IC8qKiBAdHlwZSB7IU1peGluRnVuY3Rpb259ICovKGJhc2UpLl9fbWl4aW5TZXQ7CiAgICAgIGlmIChiYXNlU2V0ICYmIGJhc2VTZXRbbWl4aW5EZWR1cGVJZF0pIHsKICAgICAgICByZXR1cm4gYmFzZTsKICAgICAgfQogICAgICBsZXQgbWFwID0gbWl4aW5BcHBsaWNhdGlvbnM7CiAgICAgIGxldCBleHRlbmRlZCA9IG1hcC5nZXQoYmFzZSk7CiAgICAgIGlmICghZXh0ZW5kZWQpIHsKICAgICAgICBleHRlbmRlZCA9IC8qKiBAdHlwZSB7IUZ1bmN0aW9ufSAqLyhtaXhpbikoYmFzZSk7CiAgICAgICAgbWFwLnNldChiYXNlLCBleHRlbmRlZCk7CiAgICAgIH0KICAgICAgLy8gY29weSBpbmhlcml0ZWQgbWl4aW4gc2V0IGZyb20gdGhlIGV4dGVuZGVkIGNsYXNzLCBvciB0aGUgYmFzZSBjbGFzcwogICAgICAvLyBOT1RFOiB3ZSBhdm9pZCB1c2Ugb2YgU2V0IGhlcmUgYmVjYXVzZSBzb21lIGJyb3dzZXIgKElFMTEpCiAgICAgIC8vIGNhbm5vdCBleHRlbmQgYSBiYXNlIFNldCB2aWEgdGhlIGNvbnN0cnVjdG9yLgogICAgICBsZXQgbWl4aW5TZXQgPSBPYmplY3QuY3JlYXRlKC8qKiBAdHlwZSB7IU1peGluRnVuY3Rpb259ICovKGV4dGVuZGVkKS5fX21peGluU2V0IHx8IGJhc2VTZXQgfHwgbnVsbCk7CiAgICAgIG1peGluU2V0W21peGluRGVkdXBlSWRdID0gdHJ1ZTsKICAgICAgLyoqIEB0eXBlIHshTWl4aW5GdW5jdGlvbn0gKi8oZXh0ZW5kZWQpLl9fbWl4aW5TZXQgPSBtaXhpblNldDsKICAgICAgcmV0dXJuIGV4dGVuZGVkOwogICAgfQoKICAgIHJldHVybiAvKiogQHR5cGUge1R9ICovIChkZWR1cGluZ01peGluKTsKICB9OwogIC8qIGVzbGludC1lbmFibGUgdmFsaWQtanNkb2MgKi8KCn0pKCk7Cgo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CiAgJ3VzZSBzdHJpY3QnOwoKICBjb25zdCBNT0RVTEVfU1RZTEVfTElOS19TRUxFQ1RPUiA9ICdsaW5rW3JlbD1pbXBvcnRdW3R5cGV+PWNzc10nOwogIGNvbnN0IElOQ0xVREVfQVRUUiA9ICdpbmNsdWRlJzsKICBjb25zdCBTSEFEWV9VTlNDT1BFRF9BVFRSID0gJ3NoYWR5LXVuc2NvcGVkJzsKCiAgZnVuY3Rpb24gaW1wb3J0TW9kdWxlKG1vZHVsZUlkKSB7CiAgICBjb25zdCAvKiogUG9seW1lci5Eb21Nb2R1bGUgKi8gUG9seW1lckRvbU1vZHVsZSA9IGN1c3RvbUVsZW1lbnRzLmdldCgnZG9tLW1vZHVsZScpOwogICAgaWYgKCFQb2x5bWVyRG9tTW9kdWxlKSB7CiAgICAgIHJldHVybiBudWxsOwogICAgfQogICAgcmV0dXJuIFBvbHltZXJEb21Nb2R1bGUuaW1wb3J0KG1vZHVsZUlkKTsKICB9CgogIGZ1bmN0aW9uIHN0eWxlRm9ySW1wb3J0KGltcG9ydERvYykgewogICAgLy8gTk9URTogcG9seWZpbGwgYWZmb3JkYW5jZS4KICAgIC8vIHVuZGVyIHRoZSBIVE1MSW1wb3J0cyBwb2x5ZmlsbCwgdGhlcmUgd2lsbCBiZSBubyAnYm9keScsCiAgICAvLyBidXQgdGhlIGltcG9ydCBwc2V1ZG8tZG9jIGNhbiBiZSB1c2VkIGRpcmVjdGx5LgogICAgbGV0IGNvbnRhaW5lciA9IGltcG9ydERvYy5ib2R5ID8gaW1wb3J0RG9jLmJvZHkgOiBpbXBvcnREb2M7CiAgICBjb25zdCBpbXBvcnRDc3MgPSBQb2x5bWVyLlJlc29sdmVVcmwucmVzb2x2ZUNzcyhjb250YWluZXIudGV4dENvbnRlbnQsCiAgICAgIGltcG9ydERvYy5iYXNlVVJJKTsKICAgIGNvbnN0IHN0eWxlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3R5bGUnKTsKICAgIHN0eWxlLnRleHRDb250ZW50ID0gaW1wb3J0Q3NzOwogICAgcmV0dXJuIHN0eWxlOwogIH0KCiAgLyoqIEB0eXBlZGVmIHt7YXNzZXRwYXRoOiBzdHJpbmd9fSAqLwogIGxldCB0ZW1wbGF0ZVdpdGhBc3NldFBhdGg7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnMKCiAgLyoqCiAgICogTW9kdWxlIHdpdGggdXRpbGl0aWVzIGZvciBjb2xsZWN0aW9uIENTUyB0ZXh0IGZyb20gYDx0ZW1wbGF0ZXM+YCwgZXh0ZXJuYWwKICAgKiBzdHlsZXNoZWV0cywgYW5kIGBkb20tbW9kdWxlYHMuCiAgICoKICAgKiBAbmFtZXNwYWNlCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBNb2R1bGUgd2l0aCB1dGlsaXRpZXMgZm9yIGNvbGxlY3Rpb24gQ1NTIHRleHQgZnJvbSB2YXJpb3VzIHNvdXJjZXMuCiAgICovCiAgY29uc3QgU3R5bGVHYXRoZXIgPSB7CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgbGlzdCBvZiA8c3R5bGU+IGVsZW1lbnRzIGluIGEgc3BhY2Utc2VwYXJhdGVkIGxpc3Qgb2YgYGRvbS1tb2R1bGVgcy4KICAgICAqCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5TdHlsZUdhdGhlcgogICAgICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZUlkcyBMaXN0IG9mIGRvbS1tb2R1bGUgaWQncyB3aXRoaW4gd2hpY2ggdG8KICAgICAqIHNlYXJjaCBmb3IgY3NzLgogICAgICogQHJldHVybiB7IUFycmF5PCFIVE1MU3R5bGVFbGVtZW50Pn0gQXJyYXkgb2YgY29udGFpbmVkIDxzdHlsZT4gZWxlbWVudHMKICAgICAqIEB0aGlzIHtTdHlsZUdhdGhlcn0KICAgICAqLwogICAgIHN0eWxlc0Zyb21Nb2R1bGVzKG1vZHVsZUlkcykgewogICAgICBjb25zdCBtb2R1bGVzID0gbW9kdWxlSWRzLnRyaW0oKS5zcGxpdCgvXHMrLyk7CiAgICAgIGNvbnN0IHN0eWxlcyA9IFtdOwogICAgICBmb3IgKGxldCBpPTA7IGkgPCBtb2R1bGVzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgc3R5bGVzLnB1c2goLi4udGhpcy5zdHlsZXNGcm9tTW9kdWxlKG1vZHVsZXNbaV0pKTsKICAgICAgfQogICAgICByZXR1cm4gc3R5bGVzOwogICAgfSwKCiAgICAvKioKICAgICAqIFJldHVybnMgYSBsaXN0IG9mIDxzdHlsZT4gZWxlbWVudHMgaW4gYSBnaXZlbiBgZG9tLW1vZHVsZWAuCiAgICAgKiBTdHlsZXMgaW4gYSBgZG9tLW1vZHVsZWAgY2FuIGNvbWUgZWl0aGVyIGZyb20gYDxzdHlsZT5gcyB3aXRoaW4gdGhlCiAgICAgKiBmaXJzdCBgPHRlbXBsYXRlPmAsIG9yIGVsc2UgZnJvbSBvbmUgb3IgbW9yZQogICAgICogYDxsaW5rIHJlbD0iaW1wb3J0IiB0eXBlPSJjc3MiPmAgbGlua3Mgb3V0c2lkZSB0aGUgdGVtcGxhdGUuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuU3R5bGVHYXRoZXIKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtb2R1bGVJZCBkb20tbW9kdWxlIGlkIHRvIGdhdGhlciBzdHlsZXMgZnJvbQogICAgICogQHJldHVybiB7IUFycmF5PCFIVE1MU3R5bGVFbGVtZW50Pn0gQXJyYXkgb2YgY29udGFpbmVkIHN0eWxlcy4KICAgICAqIEB0aGlzIHtTdHlsZUdhdGhlcn0KICAgICAqLwogICAgc3R5bGVzRnJvbU1vZHVsZShtb2R1bGVJZCkgewogICAgICBjb25zdCBtID0gaW1wb3J0TW9kdWxlKG1vZHVsZUlkKTsKCiAgICAgIGlmICghbSkgewogICAgICAgIGNvbnNvbGUud2FybignQ291bGQgbm90IGZpbmQgc3R5bGUgZGF0YSBpbiBtb2R1bGUgbmFtZWQnLCBtb2R1bGVJZCk7CiAgICAgICAgcmV0dXJuIFtdOwogICAgICB9CgogICAgICBpZiAobS5fc3R5bGVzID09PSB1bmRlZmluZWQpIHsKICAgICAgICBjb25zdCBzdHlsZXMgPSBbXTsKICAgICAgICAvLyBtb2R1bGUgaW1wb3J0czogPGxpbmsgcmVsPSJpbXBvcnQiIHR5cGU9ImNzcyI+CiAgICAgICAgc3R5bGVzLnB1c2goLi4udGhpcy5fc3R5bGVzRnJvbU1vZHVsZUltcG9ydHMobSkpOwogICAgICAgIC8vIGluY2x1ZGUgY3NzIGZyb20gdGhlIGZpcnN0IHRlbXBsYXRlIGluIHRoZSBtb2R1bGUKICAgICAgICBjb25zdCB0ZW1wbGF0ZSA9IG0ucXVlcnlTZWxlY3RvcigndGVtcGxhdGUnKTsKICAgICAgICBpZiAodGVtcGxhdGUpIHsKICAgICAgICAgIHN0eWxlcy5wdXNoKC4uLnRoaXMuc3R5bGVzRnJvbVRlbXBsYXRlKHRlbXBsYXRlLAogICAgICAgICAgICAvKiogQHR5cGUge3RlbXBsYXRlV2l0aEFzc2V0UGF0aH0gKi8obSkuYXNzZXRwYXRoKSk7CiAgICAgICAgfQoKICAgICAgICBtLl9zdHlsZXMgPSBzdHlsZXM7CiAgICAgIH0KCiAgICAgIHJldHVybiBtLl9zdHlsZXM7CiAgICB9LAoKICAgIC8qKgogICAgICogUmV0dXJucyB0aGUgYDxzdHlsZT5gIGVsZW1lbnRzIHdpdGhpbiBhIGdpdmVuIHRlbXBsYXRlLgogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlN0eWxlR2F0aGVyCiAgICAgKiBAcGFyYW0geyFIVE1MVGVtcGxhdGVFbGVtZW50fSB0ZW1wbGF0ZSBUZW1wbGF0ZSB0byBnYXRoZXIgc3R5bGVzIGZyb20KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBiYXNlVVJJIGJhc2VVUkkgZm9yIHN0eWxlIGNvbnRlbnQKICAgICAqIEByZXR1cm4geyFBcnJheTwhSFRNTFN0eWxlRWxlbWVudD59IEFycmF5IG9mIHN0eWxlcwogICAgICogQHRoaXMge1N0eWxlR2F0aGVyfQogICAgICovCiAgICBzdHlsZXNGcm9tVGVtcGxhdGUodGVtcGxhdGUsIGJhc2VVUkkpIHsKICAgICAgaWYgKCF0ZW1wbGF0ZS5fc3R5bGVzKSB7CiAgICAgICAgY29uc3Qgc3R5bGVzID0gW107CiAgICAgICAgLy8gaWYgZWxlbWVudCBpcyBhIHRlbXBsYXRlLCBnZXQgY29udGVudCBmcm9tIGl0cyAuY29udGVudAogICAgICAgIGNvbnN0IGUkID0gdGVtcGxhdGUuY29udGVudC5xdWVyeVNlbGVjdG9yQWxsKCdzdHlsZScpOwogICAgICAgIGZvciAobGV0IGk9MDsgaSA8IGUkLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICBsZXQgZSA9IGUkW2ldOwogICAgICAgICAgLy8gc3VwcG9ydCBzdHlsZSBzaGFyaW5nIGJ5IGFsbG93aW5nIHN0eWxlcyB0byAiaW5jbHVkZSIKICAgICAgICAgIC8vIG90aGVyIGRvbS1tb2R1bGVzIHRoYXQgY29udGFpbiBzdHlsaW5nCiAgICAgICAgICBsZXQgaW5jbHVkZSA9IGUuZ2V0QXR0cmlidXRlKElOQ0xVREVfQVRUUik7CiAgICAgICAgICBpZiAoaW5jbHVkZSkgewogICAgICAgICAgICBzdHlsZXMucHVzaCguLi50aGlzLnN0eWxlc0Zyb21Nb2R1bGVzKGluY2x1ZGUpLmZpbHRlcihmdW5jdGlvbihpdGVtLCBpbmRleCwgc2VsZikgewogICAgICAgICAgICAgIHJldHVybiBzZWxmLmluZGV4T2YoaXRlbSkgPT09IGluZGV4OwogICAgICAgICAgICB9KSk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoYmFzZVVSSSkgewogICAgICAgICAgICBlLnRleHRDb250ZW50ID0gUG9seW1lci5SZXNvbHZlVXJsLnJlc29sdmVDc3MoZS50ZXh0Q29udGVudCwgYmFzZVVSSSk7CiAgICAgICAgICB9CiAgICAgICAgICBzdHlsZXMucHVzaChlKTsKICAgICAgICB9CiAgICAgICAgdGVtcGxhdGUuX3N0eWxlcyA9IHN0eWxlczsKICAgICAgfQogICAgICByZXR1cm4gdGVtcGxhdGUuX3N0eWxlczsKICAgIH0sCgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgbGlzdCBvZiA8c3R5bGU+IGVsZW1lbnRzICBmcm9tIHN0eWxlc2hlZXRzIGxvYWRlZCB2aWEgYDxsaW5rIHJlbD0iaW1wb3J0IiB0eXBlPSJjc3MiPmAgbGlua3Mgd2l0aGluIHRoZSBzcGVjaWZpZWQgYGRvbS1tb2R1bGVgLgogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlN0eWxlR2F0aGVyCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlSWQgSWQgb2YgYGRvbS1tb2R1bGVgIHRvIGdhdGhlciBDU1MgZnJvbQogICAgICogQHJldHVybiB7IUFycmF5PCFIVE1MU3R5bGVFbGVtZW50Pn0gQXJyYXkgb2YgY29udGFpbmVkIHN0eWxlcy4KICAgICAqIEB0aGlzIHtTdHlsZUdhdGhlcn0KICAgICAqLwogICAgIHN0eWxlc0Zyb21Nb2R1bGVJbXBvcnRzKG1vZHVsZUlkKSB7CiAgICAgIGxldCBtID0gaW1wb3J0TW9kdWxlKG1vZHVsZUlkKTsKICAgICAgcmV0dXJuIG0gPyB0aGlzLl9zdHlsZXNGcm9tTW9kdWxlSW1wb3J0cyhtKSA6IFtdOwogICAgfSwKCiAgICAvKioKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlN0eWxlR2F0aGVyCiAgICAgKiBAdGhpcyB7U3R5bGVHYXRoZXJ9CiAgICAgKiBAcGFyYW0geyFIVE1MRWxlbWVudH0gbW9kdWxlIGRvbS1tb2R1bGUgZWxlbWVudCB0aGF0IGNvdWxkIGNvbnRhaW4gYDxsaW5rIHJlbD0iaW1wb3J0IiB0eXBlPSJjc3MiPmAgc3R5bGVzCiAgICAgKiBAcmV0dXJuIHshQXJyYXk8IUhUTUxTdHlsZUVsZW1lbnQ+fSBBcnJheSBvZiBjb250YWluZWQgc3R5bGVzCiAgICAgKi8KICAgIF9zdHlsZXNGcm9tTW9kdWxlSW1wb3J0cyhtb2R1bGUpIHsKICAgICAgY29uc3Qgc3R5bGVzID0gW107CiAgICAgIGNvbnN0IHAkID0gbW9kdWxlLnF1ZXJ5U2VsZWN0b3JBbGwoTU9EVUxFX1NUWUxFX0xJTktfU0VMRUNUT1IpOwogICAgICBmb3IgKGxldCBpPTA7IGkgPCBwJC5sZW5ndGg7IGkrKykgewogICAgICAgIGxldCBwID0gcCRbaV07CiAgICAgICAgaWYgKHAuaW1wb3J0KSB7CiAgICAgICAgICBjb25zdCBpbXBvcnREb2MgPSBwLmltcG9ydDsKICAgICAgICAgIGNvbnN0IHVuc2NvcGVkID0gcC5oYXNBdHRyaWJ1dGUoU0hBRFlfVU5TQ09QRURfQVRUUik7CiAgICAgICAgICBpZiAodW5zY29wZWQgJiYgIWltcG9ydERvYy5fdW5zY29wZWRTdHlsZSkgewogICAgICAgICAgICBjb25zdCBzdHlsZSA9IHN0eWxlRm9ySW1wb3J0KGltcG9ydERvYyk7CiAgICAgICAgICAgIHN0eWxlLnNldEF0dHJpYnV0ZShTSEFEWV9VTlNDT1BFRF9BVFRSLCAnJyk7CiAgICAgICAgICAgIGltcG9ydERvYy5fdW5zY29wZWRTdHlsZSA9IHN0eWxlOwogICAgICAgICAgfSBlbHNlIGlmICghaW1wb3J0RG9jLl9zdHlsZSkgewogICAgICAgICAgICBpbXBvcnREb2MuX3N0eWxlID0gc3R5bGVGb3JJbXBvcnQoaW1wb3J0RG9jKTsKICAgICAgICAgIH0KICAgICAgICAgIHN0eWxlcy5wdXNoKHVuc2NvcGVkID8gaW1wb3J0RG9jLl91bnNjb3BlZFN0eWxlIDogaW1wb3J0RG9jLl9zdHlsZSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIHJldHVybiBzdHlsZXM7CiAgICB9LAoKICAgIC8qKgogICAgICoKICAgICAqIFJldHVybnMgQ1NTIHRleHQgb2Ygc3R5bGVzIGluIGEgc3BhY2Utc2VwYXJhdGVkIGxpc3Qgb2YgYGRvbS1tb2R1bGVgcy4KICAgICAqIE5vdGU6IFRoaXMgbWV0aG9kIGlzIGRlcHJlY2F0ZWQsIHVzZSBgc3R5bGVzRnJvbU1vZHVsZXNgIGluc3RlYWQuCiAgICAgKgogICAgICogQGRlcHJlY2F0ZWQKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlN0eWxlR2F0aGVyCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlSWRzIExpc3Qgb2YgZG9tLW1vZHVsZSBpZCdzIHdpdGhpbiB3aGljaCB0bwogICAgICogc2VhcmNoIGZvciBjc3MuCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IENvbmNhdGVuYXRlZCBDU1MgY29udGVudCBmcm9tIHNwZWNpZmllZCBgZG9tLW1vZHVsZWBzCiAgICAgKiBAdGhpcyB7U3R5bGVHYXRoZXJ9CiAgICAgKi8KICAgICBjc3NGcm9tTW9kdWxlcyhtb2R1bGVJZHMpIHsKICAgICAgbGV0IG1vZHVsZXMgPSBtb2R1bGVJZHMudHJpbSgpLnNwbGl0KC9ccysvKTsKICAgICAgbGV0IGNzc1RleHQgPSAnJzsKICAgICAgZm9yIChsZXQgaT0wOyBpIDwgbW9kdWxlcy5sZW5ndGg7IGkrKykgewogICAgICAgIGNzc1RleHQgKz0gdGhpcy5jc3NGcm9tTW9kdWxlKG1vZHVsZXNbaV0pOwogICAgICB9CiAgICAgIHJldHVybiBjc3NUZXh0OwogICAgfSwKCiAgICAvKioKICAgICAqIFJldHVybnMgQ1NTIHRleHQgb2Ygc3R5bGVzIGluIGEgZ2l2ZW4gYGRvbS1tb2R1bGVgLiAgQ1NTIGluIGEgYGRvbS1tb2R1bGVgCiAgICAgKiBjYW4gY29tZSBlaXRoZXIgZnJvbSBgPHN0eWxlPmBzIHdpdGhpbiB0aGUgZmlyc3QgYDx0ZW1wbGF0ZT5gLCBvciBlbHNlCiAgICAgKiBmcm9tIG9uZSBvciBtb3JlIGA8bGluayByZWw9ImltcG9ydCIgdHlwZT0iY3NzIj5gIGxpbmtzIG91dHNpZGUgdGhlCiAgICAgKiB0ZW1wbGF0ZS4KICAgICAqCiAgICAgKiBBbnkgYDxzdHlsZXM+YCBwcm9jZXNzZWQgYXJlIHJlbW92ZWQgZnJvbSB0aGVpciBvcmlnaW5hbCBsb2NhdGlvbi4KICAgICAqIE5vdGU6IFRoaXMgbWV0aG9kIGlzIGRlcHJlY2F0ZWQsIHVzZSBgc3R5bGVGcm9tTW9kdWxlYCBpbnN0ZWFkLgogICAgICoKICAgICAqIEBkZXByZWNhdGVkCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5TdHlsZUdhdGhlcgogICAgICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZUlkIGRvbS1tb2R1bGUgaWQgdG8gZ2F0aGVyIHN0eWxlcyBmcm9tCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IENvbmNhdGVuYXRlZCBDU1MgY29udGVudCBmcm9tIHNwZWNpZmllZCBgZG9tLW1vZHVsZWAKICAgICAqIEB0aGlzIHtTdHlsZUdhdGhlcn0KICAgICAqLwogICAgY3NzRnJvbU1vZHVsZShtb2R1bGVJZCkgewogICAgICBsZXQgbSA9IGltcG9ydE1vZHVsZShtb2R1bGVJZCk7CiAgICAgIGlmIChtICYmIG0uX2Nzc1RleHQgPT09IHVuZGVmaW5lZCkgewogICAgICAgIC8vIG1vZHVsZSBpbXBvcnRzOiA8bGluayByZWw9ImltcG9ydCIgdHlwZT0iY3NzIj4KICAgICAgICBsZXQgY3NzVGV4dCA9IHRoaXMuX2Nzc0Zyb21Nb2R1bGVJbXBvcnRzKG0pOwogICAgICAgIC8vIGluY2x1ZGUgY3NzIGZyb20gdGhlIGZpcnN0IHRlbXBsYXRlIGluIHRoZSBtb2R1bGUKICAgICAgICBsZXQgdCA9IG0ucXVlcnlTZWxlY3RvcigndGVtcGxhdGUnKTsKICAgICAgICBpZiAodCkgewogICAgICAgICAgY3NzVGV4dCArPSB0aGlzLmNzc0Zyb21UZW1wbGF0ZSh0LAogICAgICAgICAgICAvKiogQHR5cGUge3RlbXBsYXRlV2l0aEFzc2V0UGF0aH0gKi8obSkuYXNzZXRwYXRoKTsKICAgICAgICB9CiAgICAgICAgbS5fY3NzVGV4dCA9IGNzc1RleHQgfHwgbnVsbDsKICAgICAgfQogICAgICBpZiAoIW0pIHsKICAgICAgICBjb25zb2xlLndhcm4oJ0NvdWxkIG5vdCBmaW5kIHN0eWxlIGRhdGEgaW4gbW9kdWxlIG5hbWVkJywgbW9kdWxlSWQpOwogICAgICB9CiAgICAgIHJldHVybiBtICYmIG0uX2Nzc1RleHQgfHwgJyc7CiAgICB9LAoKICAgIC8qKgogICAgICogUmV0dXJucyBDU1MgdGV4dCBvZiBgPHN0eWxlcz5gIHdpdGhpbiBhIGdpdmVuIHRlbXBsYXRlLgogICAgICoKICAgICAqIEFueSBgPHN0eWxlcz5gIHByb2Nlc3NlZCBhcmUgcmVtb3ZlZCBmcm9tIHRoZWlyIG9yaWdpbmFsIGxvY2F0aW9uLgogICAgICogTm90ZTogVGhpcyBtZXRob2QgaXMgZGVwcmVjYXRlZCwgdXNlIGBzdHlsZUZyb21UZW1wbGF0ZWAgaW5zdGVhZC4KICAgICAqCiAgICAgKiBAZGVwcmVjYXRlZAogICAgICogQG1lbWJlcm9mIFBvbHltZXIuU3R5bGVHYXRoZXIKICAgICAqIEBwYXJhbSB7IUhUTUxUZW1wbGF0ZUVsZW1lbnR9IHRlbXBsYXRlIFRlbXBsYXRlIHRvIGdhdGhlciBzdHlsZXMgZnJvbQogICAgICogQHBhcmFtIHtzdHJpbmd9IGJhc2VVUkkgQmFzZSBVUkkgdG8gcmVzb2x2ZSB0aGUgVVJMIGFnYWluc3QKICAgICAqIEByZXR1cm4ge3N0cmluZ30gQ29uY2F0ZW5hdGVkIENTUyBjb250ZW50IGZyb20gc3BlY2lmaWVkIHRlbXBsYXRlCiAgICAgKiBAdGhpcyB7U3R5bGVHYXRoZXJ9CiAgICAgKi8KICAgIGNzc0Zyb21UZW1wbGF0ZSh0ZW1wbGF0ZSwgYmFzZVVSSSkgewogICAgICBsZXQgY3NzVGV4dCA9ICcnOwogICAgICBjb25zdCBlJCA9IHRoaXMuc3R5bGVzRnJvbVRlbXBsYXRlKHRlbXBsYXRlLCBiYXNlVVJJKTsKICAgICAgLy8gaWYgZWxlbWVudCBpcyBhIHRlbXBsYXRlLCBnZXQgY29udGVudCBmcm9tIGl0cyAuY29udGVudAogICAgICBmb3IgKGxldCBpPTA7IGkgPCBlJC5sZW5ndGg7IGkrKykgewogICAgICAgIGxldCBlID0gZSRbaV07CiAgICAgICAgaWYgKGUucGFyZW50Tm9kZSkgewogICAgICAgICAgZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGUpOwogICAgICAgIH0KICAgICAgICBjc3NUZXh0ICs9IGUudGV4dENvbnRlbnQ7CiAgICAgIH0KICAgICAgcmV0dXJuIGNzc1RleHQ7CiAgICB9LAoKICAgIC8qKgogICAgICogUmV0dXJucyBDU1MgdGV4dCBmcm9tIHN0eWxlc2hlZXRzIGxvYWRlZCB2aWEgYDxsaW5rIHJlbD0iaW1wb3J0IiB0eXBlPSJjc3MiPmAKICAgICAqIGxpbmtzIHdpdGhpbiB0aGUgc3BlY2lmaWVkIGBkb20tbW9kdWxlYC4KICAgICAqCiAgICAgKiBOb3RlOiBUaGlzIG1ldGhvZCBpcyBkZXByZWNhdGVkLCB1c2UgYHN0eWxlc0Zyb21Nb2R1bGVJbXBvcnRzYCBpbnN0ZWFkLgogICAgICoKICAgICAqIEBkZXByZWNhdGVkCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuU3R5bGVHYXRoZXIKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtb2R1bGVJZCBJZCBvZiBgZG9tLW1vZHVsZWAgdG8gZ2F0aGVyIENTUyBmcm9tCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IENvbmNhdGVuYXRlZCBDU1MgY29udGVudCBmcm9tIGxpbmtzIGluIHNwZWNpZmllZCBgZG9tLW1vZHVsZWAKICAgICAqIEB0aGlzIHtTdHlsZUdhdGhlcn0KICAgICAqLwogICAgY3NzRnJvbU1vZHVsZUltcG9ydHMobW9kdWxlSWQpIHsKICAgICAgbGV0IG0gPSBpbXBvcnRNb2R1bGUobW9kdWxlSWQpOwogICAgICByZXR1cm4gbSA/IHRoaXMuX2Nzc0Zyb21Nb2R1bGVJbXBvcnRzKG0pIDogJyc7CiAgICB9LAoKICAgIC8qKgogICAgICogQGRlcHJlY2F0ZWQKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlN0eWxlR2F0aGVyCiAgICAgKiBAdGhpcyB7U3R5bGVHYXRoZXJ9CiAgICAgKiBAcGFyYW0geyFIVE1MRWxlbWVudH0gbW9kdWxlIGRvbS1tb2R1bGUgZWxlbWVudCB0aGF0IGNvdWxkIGNvbnRhaW4gYDxsaW5rIHJlbD0iaW1wb3J0IiB0eXBlPSJjc3MiPmAgc3R5bGVzCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IENvbmNhdGVuYXRlZCBDU1MgY29udGVudCBmcm9tIGxpbmtzIGluIHRoZSBkb20tbW9kdWxlCiAgICAgKi8KICAgICBfY3NzRnJvbU1vZHVsZUltcG9ydHMobW9kdWxlKSB7CiAgICAgIGxldCBjc3NUZXh0ID0gJyc7CiAgICAgIGxldCBzdHlsZXMgPSB0aGlzLl9zdHlsZXNGcm9tTW9kdWxlSW1wb3J0cyhtb2R1bGUpOwogICAgICBmb3IgKGxldCBpPTA7IGkgPCBzdHlsZXMubGVuZ3RoOyBpKyspIHsKICAgICAgICBjc3NUZXh0ICs9IHN0eWxlc1tpXS50ZXh0Q29udGVudDsKICAgICAgfQogICAgICByZXR1cm4gY3NzVGV4dDsKICAgIH0KICB9OwoKICBQb2x5bWVyLlN0eWxlR2F0aGVyID0gU3R5bGVHYXRoZXI7Cn0pKCk7Cjwvc2NyaXB0PjxzY3JpcHQ+CihmdW5jdGlvbigpIHsKICAndXNlIHN0cmljdCc7CgogIGxldCBtb2R1bGVzID0ge307CiAgbGV0IGxjTW9kdWxlcyA9IHt9OwogIGZ1bmN0aW9uIHNldE1vZHVsZShpZCwgbW9kdWxlKSB7CiAgICAvLyBzdG9yZSBpZCBzZXBhcmF0ZSBmcm9tIGxvd2VyY2FzZWQgaWQgc28gdGhhdAogICAgLy8gaW4gYWxsIGNhc2VzIG1peGVkQ2FzZSBpZCB3aWxsIHN0b3JlZCBkaXN0aW5jdGx5CiAgICAvLyBhbmQgbG93ZXJjYXNlIHZlcnNpb24gaXMgYSBmYWxsYmFjawogICAgbW9kdWxlc1tpZF0gPSBsY01vZHVsZXNbaWQudG9Mb3dlckNhc2UoKV0gPSBtb2R1bGU7CiAgfQogIGZ1bmN0aW9uIGZpbmRNb2R1bGUoaWQpIHsKICAgIHJldHVybiBtb2R1bGVzW2lkXSB8fCBsY01vZHVsZXNbaWQudG9Mb3dlckNhc2UoKV07CiAgfQoKICBmdW5jdGlvbiBzdHlsZU91dHNpZGVUZW1wbGF0ZUNoZWNrKGluc3QpIHsKICAgIGlmIChpbnN0LnF1ZXJ5U2VsZWN0b3IoJ3N0eWxlJykpIHsKICAgICAgY29uc29sZS53YXJuKCdkb20tbW9kdWxlICVzIGhhcyBzdHlsZSBvdXRzaWRlIHRlbXBsYXRlJywgaW5zdC5pZCk7CiAgICB9CiAgfQoKICAvKioKICAgKiBUaGUgYGRvbS1tb2R1bGVgIGVsZW1lbnQgcmVnaXN0ZXJzIHRoZSBkb20gaXQgY29udGFpbnMgdG8gdGhlIG5hbWUgZ2l2ZW4KICAgKiBieSB0aGUgbW9kdWxlJ3MgaWQgYXR0cmlidXRlLiBJdCBwcm92aWRlcyBhIHVuaWZpZWQgZGF0YWJhc2Ugb2YgZG9tCiAgICogYWNjZXNzaWJsZSB2aWEgaXRzIHN0YXRpYyBgaW1wb3J0YCBBUEkuCiAgICoKICAgKiBBIGtleSB1c2UgY2FzZSBvZiBgZG9tLW1vZHVsZWAgaXMgZm9yIHByb3ZpZGluZyBjdXN0b20gZWxlbWVudCBgPHRlbXBsYXRlPmBzCiAgICogdmlhIEhUTUwgaW1wb3J0cyB0aGF0IGFyZSBwYXJzZWQgYnkgdGhlIG5hdGl2ZSBIVE1MIHBhcnNlciwgdGhhdCBjYW4gYmUKICAgKiByZWxvY2F0ZWQgZHVyaW5nIGEgYnVuZGxpbmcgcGFzcyBhbmQgc3RpbGwgbG9va2VkIHVwIGJ5IGBpZGAuCiAgICoKICAgKiBFeGFtcGxlOgogICAqCiAgICogICAgIDxkb20tbW9kdWxlIGlkPSJmb28iPgogICAqICAgICAgIDxpbWcgc3JjPSJzdHVmZi5wbmciPgogICAqICAgICA8L2RvbS1tb2R1bGU+CiAgICoKICAgKiBUaGVuIGluIGNvZGUgaW4gc29tZSBvdGhlciBsb2NhdGlvbiB0aGF0IGNhbm5vdCBhY2Nlc3MgdGhlIGRvbS1tb2R1bGUgYWJvdmUKICAgKgogICAqICAgICBsZXQgaW1nID0gY3VzdG9tRWxlbWVudHMuZ2V0KCdkb20tbW9kdWxlJykuaW1wb3J0KCdmb28nLCAnaW1nJyk7CiAgICoKICAgKiBAY3VzdG9tRWxlbWVudAogICAqIEBleHRlbmRzIEhUTUxFbGVtZW50CiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBDdXN0b20gZWxlbWVudCB0aGF0IHByb3ZpZGVzIGEgcmVnaXN0cnkgb2YgcmVsb2NhdGFibGUgRE9NIGNvbnRlbnQKICAgKiAgIGJ5IGBpZGAgdGhhdCBpcyBhZ25vc3RpYyB0byBidW5kbGluZy4KICAgKiBAdW5yZXN0cmljdGVkCiAgICovCiAgY2xhc3MgRG9tTW9kdWxlIGV4dGVuZHMgSFRNTEVsZW1lbnQgewoKICAgIHN0YXRpYyBnZXQgb2JzZXJ2ZWRBdHRyaWJ1dGVzKCkgeyByZXR1cm4gWydpZCddOyB9CgogICAgLyoqCiAgICAgKiBSZXRyaWV2ZXMgdGhlIGVsZW1lbnQgc3BlY2lmaWVkIGJ5IHRoZSBjc3MgYHNlbGVjdG9yYCBpbiB0aGUgbW9kdWxlCiAgICAgKiByZWdpc3RlcmVkIGJ5IGBpZGAuIEZvciBleGFtcGxlLCB0aGlzLmltcG9ydCgnZm9vJywgJ2ltZycpOwogICAgICogQHBhcmFtIHtzdHJpbmd9IGlkIFRoZSBpZCBvZiB0aGUgZG9tLW1vZHVsZSBpbiB3aGljaCB0byBzZWFyY2guCiAgICAgKiBAcGFyYW0ge3N0cmluZz19IHNlbGVjdG9yIFRoZSBjc3Mgc2VsZWN0b3IgYnkgd2hpY2ggdG8gZmluZCB0aGUgZWxlbWVudC4KICAgICAqIEByZXR1cm4ge0VsZW1lbnR9IFJldHVybnMgdGhlIGVsZW1lbnQgd2hpY2ggbWF0Y2hlcyBgc2VsZWN0b3JgIGluIHRoZQogICAgICogbW9kdWxlIHJlZ2lzdGVyZWQgYXQgdGhlIHNwZWNpZmllZCBgaWRgLgogICAgICovCiAgICBzdGF0aWMgaW1wb3J0KGlkLCBzZWxlY3RvcikgewogICAgICBpZiAoaWQpIHsKICAgICAgICBsZXQgbSA9IGZpbmRNb2R1bGUoaWQpOwogICAgICAgIGlmIChtICYmIHNlbGVjdG9yKSB7CiAgICAgICAgICByZXR1cm4gbS5xdWVyeVNlbGVjdG9yKHNlbGVjdG9yKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG07CiAgICAgIH0KICAgICAgcmV0dXJuIG51bGw7CiAgICB9CgogICAgLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi8KICAgIC8qKgogICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgTmFtZSBvZiBhdHRyaWJ1dGUuCiAgICAgKiBAcGFyYW0gez9zdHJpbmd9IG9sZCBPbGQgdmFsdWUgb2YgYXR0cmlidXRlLgogICAgICogQHBhcmFtIHs/c3RyaW5nfSB2YWx1ZSBDdXJyZW50IHZhbHVlIG9mIGF0dHJpYnV0ZS4KICAgICAqIEBwYXJhbSB7P3N0cmluZ30gbmFtZXNwYWNlIEF0dHJpYnV0ZSBuYW1lc3BhY2UuCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBhdHRyaWJ1dGVDaGFuZ2VkQ2FsbGJhY2sobmFtZSwgb2xkLCB2YWx1ZSwgbmFtZXNwYWNlKSB7CiAgICAgIGlmIChvbGQgIT09IHZhbHVlKSB7CiAgICAgICAgdGhpcy5yZWdpc3RlcigpOwogICAgICB9CiAgICB9CiAgICAvKiBlc2xpbnQtZW5hYmxlIG5vLXVudXNlZC1hcmdzICovCgogICAgLyoqCiAgICAgKiBUaGUgYWJzb2x1dGUgVVJMIG9mIHRoZSBvcmlnaW5hbCBsb2NhdGlvbiBvZiB0aGlzIGBkb20tbW9kdWxlYC4KICAgICAqCiAgICAgKiBUaGlzIHZhbHVlIHdpbGwgZGlmZmVyIGZyb20gdGhpcyBlbGVtZW50J3MgYG93bmVyRG9jdW1lbnRgIGluIHRoZQogICAgICogZm9sbG93aW5nIHdheXM6CiAgICAgKiAtIFRha2VzIGludG8gYWNjb3VudCBhbnkgYGFzc2V0cGF0aGAgYXR0cmlidXRlIGFkZGVkIGR1cmluZyBidW5kbGluZwogICAgICogICB0byBpbmRpY2F0ZSB0aGUgb3JpZ2luYWwgbG9jYXRpb24gcmVsYXRpdmUgdG8gdGhlIGJ1bmRsZWQgbG9jYXRpb24KICAgICAqIC0gVXNlcyB0aGUgSFRNTEltcG9ydHMgcG9seWZpbGwncyBgaW1wb3J0Rm9yRWxlbWVudGAgQVBJIHRvIGVuc3VyZQogICAgICogICB0aGUgcGF0aCBpcyByZWxhdGl2ZSB0byB0aGUgaW1wb3J0IGRvY3VtZW50J3MgbG9jYXRpb24gc2luY2UKICAgICAqICAgYG93bmVyRG9jdW1lbnRgIGlzIG5vdCBjdXJyZW50bHkgcG9seWZpbGxlZAogICAgICovCiAgICBnZXQgYXNzZXRwYXRoKCkgewogICAgICAvLyBEb24ndCBvdmVycmlkZSBleGlzdGluZyBhc3NldHBhdGguCiAgICAgIGlmICghdGhpcy5fX2Fzc2V0cGF0aCkgewogICAgICAgIC8vIG5vdGU6IGFzc2V0cGF0aCBzZXQgdmlhIGFuIGF0dHJpYnV0ZSBtdXN0IGJlIHJlbGF0aXZlIHRvIHRoaXMKICAgICAgICAvLyBlbGVtZW50J3MgbG9jYXRpb247IGFjY29tb2RhdGUgcG9seWZpbGxlZCBIVE1MSW1wb3J0cwogICAgICAgIGNvbnN0IG93bmVyID0gd2luZG93LkhUTUxJbXBvcnRzICYmIEhUTUxJbXBvcnRzLmltcG9ydEZvckVsZW1lbnQgPwogICAgICAgICAgSFRNTEltcG9ydHMuaW1wb3J0Rm9yRWxlbWVudCh0aGlzKSB8fCBkb2N1bWVudCA6IHRoaXMub3duZXJEb2N1bWVudDsKICAgICAgICBjb25zdCB1cmwgPSBQb2x5bWVyLlJlc29sdmVVcmwucmVzb2x2ZVVybCgKICAgICAgICAgIHRoaXMuZ2V0QXR0cmlidXRlKCdhc3NldHBhdGgnKSB8fCAnJywgb3duZXIuYmFzZVVSSSk7CiAgICAgICAgdGhpcy5fX2Fzc2V0cGF0aCA9IFBvbHltZXIuUmVzb2x2ZVVybC5wYXRoRnJvbVVybCh1cmwpOwogICAgICB9CiAgICAgIHJldHVybiB0aGlzLl9fYXNzZXRwYXRoOwogICAgfQoKICAgIC8qKgogICAgICogUmVnaXN0ZXJzIHRoZSBkb20tbW9kdWxlIGF0IGEgZ2l2ZW4gaWQuIFRoaXMgbWV0aG9kIHNob3VsZCBvbmx5IGJlIGNhbGxlZAogICAgICogd2hlbiBhIGRvbS1tb2R1bGUgaXMgaW1wZXJhdGl2ZWx5IGNyZWF0ZWQuIEZvcgogICAgICogZXhhbXBsZSwgYGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RvbS1tb2R1bGUnKS5yZWdpc3RlcignZm9vJylgLgogICAgICogQHBhcmFtIHtzdHJpbmc9fSBpZCBUaGUgaWQgYXQgd2hpY2ggdG8gcmVnaXN0ZXIgdGhlIGRvbS1tb2R1bGUuCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICByZWdpc3RlcihpZCkgewogICAgICBpZCA9IGlkIHx8IHRoaXMuaWQ7CiAgICAgIGlmIChpZCkgewogICAgICAgIC8vIFVuZGVyIHN0cmljdFRlbXBsYXRlUG9saWN5LCByZWplY3QgYW5kIG51bGwgb3V0IGFueSByZS1yZWdpc3RlcmVkCiAgICAgICAgLy8gZG9tLW1vZHVsZSBzaW5jZSBpdCBpcyBhbWJpZ3VvdXMgd2hldGhlciBmaXJzdC1pbiBvciBsYXN0LWluIGlzIHRydXN0ZWQgCiAgICAgICAgaWYgKFBvbHltZXIuc3RyaWN0VGVtcGxhdGVQb2xpY3kgJiYgZmluZE1vZHVsZShpZCkgIT09IHVuZGVmaW5lZCkgewogICAgICAgICAgc2V0TW9kdWxlKGlkLCBudWxsKTsKICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgc3RyaWN0VGVtcGxhdGVQb2xpY3k6IGRvbS1tb2R1bGUgJHtpZH0gcmUtcmVnaXN0ZXJlZGApOwogICAgICAgIH0KICAgICAgICB0aGlzLmlkID0gaWQ7CiAgICAgICAgc2V0TW9kdWxlKGlkLCB0aGlzKTsKICAgICAgICBzdHlsZU91dHNpZGVUZW1wbGF0ZUNoZWNrKHRoaXMpOwogICAgICB9CiAgICB9CiAgfQoKICBEb21Nb2R1bGUucHJvdG90eXBlWydtb2R1bGVzJ10gPSBtb2R1bGVzOwoKICBjdXN0b21FbGVtZW50cy5kZWZpbmUoJ2RvbS1tb2R1bGUnLCBEb21Nb2R1bGUpOwoKICAvKiogQGNvbnN0ICovCiAgUG9seW1lci5Eb21Nb2R1bGUgPSBEb21Nb2R1bGU7Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CiAgJ3VzZSBzdHJpY3QnOwoKICAvKioKICAgKiBNb2R1bGUgd2l0aCB1dGlsaXRpZXMgZm9yIG1hbmlwdWxhdGluZyBzdHJ1Y3R1cmVkIGRhdGEgcGF0aCBzdHJpbmdzLgogICAqCiAgICogQG5hbWVzcGFjZQogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICogQHN1bW1hcnkgTW9kdWxlIHdpdGggdXRpbGl0aWVzIGZvciBtYW5pcHVsYXRpbmcgc3RydWN0dXJlZCBkYXRhIHBhdGggc3RyaW5ncy4KICAgKi8KICBjb25zdCBQYXRoID0gewoKICAgIC8qKgogICAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBnaXZlbiBzdHJpbmcgaXMgYSBzdHJ1Y3R1cmVkIGRhdGEgcGF0aCAoaGFzIGRvdHMpLgogICAgICoKICAgICAqIEV4YW1wbGU6CiAgICAgKgogICAgICogYGBgCiAgICAgKiBQb2x5bWVyLlBhdGguaXNQYXRoKCdmb28uYmFyLmJheicpIC8vIHRydWUKICAgICAqIFBvbHltZXIuUGF0aC5pc1BhdGgoJ2ZvbycpICAgICAgICAgLy8gZmFsc2UKICAgICAqIGBgYAogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlBhdGgKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFBhdGggc3RyaW5nCiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBzdHJpbmcgY29udGFpbmVkIG9uZSBvciBtb3JlIGRvdHMKICAgICAqLwogICAgaXNQYXRoOiBmdW5jdGlvbihwYXRoKSB7CiAgICAgIHJldHVybiBwYXRoLmluZGV4T2YoJy4nKSA+PSAwOwogICAgfSwKCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIHJvb3QgcHJvcGVydHkgbmFtZSBmb3IgdGhlIGdpdmVuIHBhdGguCiAgICAgKgogICAgICogRXhhbXBsZToKICAgICAqCiAgICAgKiBgYGAKICAgICAqIFBvbHltZXIuUGF0aC5yb290KCdmb28uYmFyLmJheicpIC8vICdmb28nCiAgICAgKiBQb2x5bWVyLlBhdGgucm9vdCgnZm9vJykgICAgICAgICAvLyAnZm9vJwogICAgICogYGBgCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuUGF0aAogICAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggUGF0aCBzdHJpbmcKICAgICAqIEByZXR1cm4ge3N0cmluZ30gUm9vdCBwcm9wZXJ0eSBuYW1lCiAgICAgKi8KICAgIHJvb3Q6IGZ1bmN0aW9uKHBhdGgpIHsKICAgICAgbGV0IGRvdEluZGV4ID0gcGF0aC5pbmRleE9mKCcuJyk7CiAgICAgIGlmIChkb3RJbmRleCA9PT0gLTEpIHsKICAgICAgICByZXR1cm4gcGF0aDsKICAgICAgfQogICAgICByZXR1cm4gcGF0aC5zbGljZSgwLCBkb3RJbmRleCk7CiAgICB9LAoKICAgIC8qKgogICAgICogR2l2ZW4gYGJhc2VgIGlzIGBmb28uYmFyYCwgYGZvb2AgaXMgYW4gYW5jZXN0b3IsIGBmb28uYmFyYCBpcyBub3QKICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgZ2l2ZW4gcGF0aCBpcyBhbiBhbmNlc3RvciBvZiB0aGUgYmFzZSBwYXRoLgogICAgICoKICAgICAqIEV4YW1wbGU6CiAgICAgKgogICAgICogYGBgCiAgICAgKiBQb2x5bWVyLlBhdGguaXNBbmNlc3RvcignZm9vLmJhcicsICdmb28nKSAgICAgICAgIC8vIHRydWUKICAgICAqIFBvbHltZXIuUGF0aC5pc0FuY2VzdG9yKCdmb28uYmFyJywgJ2Zvby5iYXInKSAgICAgLy8gZmFsc2UKICAgICAqIFBvbHltZXIuUGF0aC5pc0FuY2VzdG9yKCdmb28uYmFyJywgJ2Zvby5iYXIuYmF6JykgLy8gZmFsc2UKICAgICAqIGBgYAogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlBhdGgKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBiYXNlIFBhdGggc3RyaW5nIHRvIHRlc3QgYWdhaW5zdC4KICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFBhdGggc3RyaW5nIHRvIHRlc3QuCiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIGBwYXRoYCBpcyBhbiBhbmNlc3RvciBvZiBgYmFzZWAuCiAgICAgKi8KICAgIGlzQW5jZXN0b3I6IGZ1bmN0aW9uKGJhc2UsIHBhdGgpIHsKICAgICAgLy8gICAgIGJhc2Uuc3RhcnRzV2l0aChwYXRoICsgJy4nKTsKICAgICAgcmV0dXJuIGJhc2UuaW5kZXhPZihwYXRoICsgJy4nKSA9PT0gMDsKICAgIH0sCgogICAgLyoqCiAgICAgKiBHaXZlbiBgYmFzZWAgaXMgYGZvby5iYXJgLCBgZm9vLmJhci5iYXpgIGlzIGFuIGRlc2NlbmRhbnQKICAgICAqCiAgICAgKiBFeGFtcGxlOgogICAgICoKICAgICAqIGBgYAogICAgICogUG9seW1lci5QYXRoLmlzRGVzY2VuZGFudCgnZm9vLmJhcicsICdmb28uYmFyLmJheicpIC8vIHRydWUKICAgICAqIFBvbHltZXIuUGF0aC5pc0Rlc2NlbmRhbnQoJ2Zvby5iYXInLCAnZm9vLmJhcicpICAgICAvLyBmYWxzZQogICAgICogUG9seW1lci5QYXRoLmlzRGVzY2VuZGFudCgnZm9vLmJhcicsICdmb28nKSAgICAgICAgIC8vIGZhbHNlCiAgICAgKiBgYGAKICAgICAqCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5QYXRoCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYmFzZSBQYXRoIHN0cmluZyB0byB0ZXN0IGFnYWluc3QuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aCBQYXRoIHN0cmluZyB0byB0ZXN0LgogICAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBgcGF0aGAgaXMgYSBkZXNjZW5kYW50IG9mIGBiYXNlYC4KICAgICAqLwogICAgaXNEZXNjZW5kYW50OiBmdW5jdGlvbihiYXNlLCBwYXRoKSB7CiAgICAgIC8vICAgICBwYXRoLnN0YXJ0c1dpdGgoYmFzZSArICcuJyk7CiAgICAgIHJldHVybiBwYXRoLmluZGV4T2YoYmFzZSArICcuJykgPT09IDA7CiAgICB9LAoKICAgIC8qKgogICAgICogUmVwbGFjZXMgYSBwcmV2aW91cyBiYXNlIHBhdGggd2l0aCBhIG5ldyBiYXNlIHBhdGgsIHByZXNlcnZpbmcgdGhlCiAgICAgKiByZW1haW5kZXIgb2YgdGhlIHBhdGguCiAgICAgKgogICAgICogVXNlciBtdXN0IGVuc3VyZSBgcGF0aGAgaGFzIGEgcHJlZml4IG9mIGBiYXNlYC4KICAgICAqCiAgICAgKiBFeGFtcGxlOgogICAgICoKICAgICAqIGBgYAogICAgICogUG9seW1lci5QYXRoLnRyYW5zbGF0ZSgnZm9vLmJhcicsICd6b3QnLCAnZm9vLmJhci5iYXonKSAvLyAnem90LmJheicKICAgICAqIGBgYAogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlBhdGgKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBiYXNlIEN1cnJlbnQgYmFzZSBzdHJpbmcgdG8gcmVtb3ZlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmV3QmFzZSBOZXcgYmFzZSBzdHJpbmcgdG8gcmVwbGFjZSB3aXRoCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aCBQYXRoIHRvIHRyYW5zbGF0ZQogICAgICogQHJldHVybiB7c3RyaW5nfSBUcmFuc2xhdGVkIHN0cmluZwogICAgICovCiAgICB0cmFuc2xhdGU6IGZ1bmN0aW9uKGJhc2UsIG5ld0Jhc2UsIHBhdGgpIHsKICAgICAgcmV0dXJuIG5ld0Jhc2UgKyBwYXRoLnNsaWNlKGJhc2UubGVuZ3RoKTsKICAgIH0sCgogICAgLyoqCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYmFzZSBQYXRoIHN0cmluZyB0byB0ZXN0IGFnYWluc3QKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFBhdGggc3RyaW5nIHRvIHRlc3QKICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgYHBhdGhgIGlzIGVxdWFsIHRvIGBiYXNlYAogICAgICogQHRoaXMge1BhdGh9CiAgICAgKi8KICAgIG1hdGNoZXM6IGZ1bmN0aW9uKGJhc2UsIHBhdGgpIHsKICAgICAgcmV0dXJuIChiYXNlID09PSBwYXRoKSB8fAogICAgICAgICAgICAgdGhpcy5pc0FuY2VzdG9yKGJhc2UsIHBhdGgpIHx8CiAgICAgICAgICAgICB0aGlzLmlzRGVzY2VuZGFudChiYXNlLCBwYXRoKTsKICAgIH0sCgogICAgLyoqCiAgICAgKiBDb252ZXJ0cyBhcnJheS1iYXNlZCBwYXRocyB0byBmbGF0dGVuZWQgcGF0aC4gIFN0cmluZy1iYXNlZCBwYXRocwogICAgICogYXJlIHJldHVybmVkIGFzLWlzLgogICAgICoKICAgICAqIEV4YW1wbGU6CiAgICAgKgogICAgICogYGBgCiAgICAgKiBQb2x5bWVyLlBhdGgubm9ybWFsaXplKFsnZm9vLmJhcicsIDAsICdiYXonXSkgIC8vICdmb28uYmFyLjAuYmF6JwogICAgICogUG9seW1lci5QYXRoLm5vcm1hbGl6ZSgnZm9vLmJhci4wLmJheicpICAgICAgICAvLyAnZm9vLmJhci4wLmJheicKICAgICAqIGBgYAogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlBhdGgKICAgICAqIEBwYXJhbSB7c3RyaW5nIHwgIUFycmF5PHN0cmluZ3xudW1iZXI+fSBwYXRoIElucHV0IHBhdGgKICAgICAqIEByZXR1cm4ge3N0cmluZ30gRmxhdHRlbmVkIHBhdGgKICAgICAqLwogICAgbm9ybWFsaXplOiBmdW5jdGlvbihwYXRoKSB7CiAgICAgIGlmIChBcnJheS5pc0FycmF5KHBhdGgpKSB7CiAgICAgICAgbGV0IHBhcnRzID0gW107CiAgICAgICAgZm9yIChsZXQgaT0wOyBpPHBhdGgubGVuZ3RoOyBpKyspIHsKICAgICAgICAgIGxldCBhcmdzID0gcGF0aFtpXS50b1N0cmluZygpLnNwbGl0KCcuJyk7CiAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8YXJncy5sZW5ndGg7IGorKykgewogICAgICAgICAgICBwYXJ0cy5wdXNoKGFyZ3Nbal0pOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gcGFydHMuam9pbignLicpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBwYXRoOwogICAgICB9CiAgICB9LAoKICAgIC8qKgogICAgICogU3BsaXRzIGEgcGF0aCBpbnRvIGFuIGFycmF5IG9mIHByb3BlcnR5IG5hbWVzLiBBY2NlcHRzIGVpdGhlciBhcnJheXMKICAgICAqIG9mIHBhdGggcGFydHMgb3Igc3RyaW5ncy4KICAgICAqCiAgICAgKiBFeGFtcGxlOgogICAgICoKICAgICAqIGBgYAogICAgICogUG9seW1lci5QYXRoLnNwbGl0KFsnZm9vLmJhcicsIDAsICdiYXonXSkgIC8vIFsnZm9vJywgJ2JhcicsICcwJywgJ2JheiddCiAgICAgKiBQb2x5bWVyLlBhdGguc3BsaXQoJ2Zvby5iYXIuMC5iYXonKSAgICAgICAgLy8gWydmb28nLCAnYmFyJywgJzAnLCAnYmF6J10KICAgICAqIGBgYAogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlBhdGgKICAgICAqIEBwYXJhbSB7c3RyaW5nIHwgIUFycmF5PHN0cmluZ3xudW1iZXI+fSBwYXRoIElucHV0IHBhdGgKICAgICAqIEByZXR1cm4geyFBcnJheTxzdHJpbmc+fSBBcnJheSBvZiBwYXRoIHBhcnRzCiAgICAgKiBAdGhpcyB7UGF0aH0KICAgICAqIEBzdXBwcmVzcyB7Y2hlY2tUeXBlc30KICAgICAqLwogICAgc3BsaXQ6IGZ1bmN0aW9uKHBhdGgpIHsKICAgICAgaWYgKEFycmF5LmlzQXJyYXkocGF0aCkpIHsKICAgICAgICByZXR1cm4gdGhpcy5ub3JtYWxpemUocGF0aCkuc3BsaXQoJy4nKTsKICAgICAgfQogICAgICByZXR1cm4gcGF0aC50b1N0cmluZygpLnNwbGl0KCcuJyk7CiAgICB9LAoKICAgIC8qKgogICAgICogUmVhZHMgYSB2YWx1ZSBmcm9tIGEgcGF0aC4gIElmIGFueSBzdWItcHJvcGVydHkgaW4gdGhlIHBhdGggaXMgYHVuZGVmaW5lZGAsCiAgICAgKiB0aGlzIG1ldGhvZCByZXR1cm5zIGB1bmRlZmluZWRgICh3aWxsIG5ldmVyIHRocm93LgogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlBhdGgKICAgICAqIEBwYXJhbSB7T2JqZWN0fSByb290IE9iamVjdCBmcm9tIHdoaWNoIHRvIGRlcmVmZXJlbmNlIHBhdGggZnJvbQogICAgICogQHBhcmFtIHtzdHJpbmcgfCAhQXJyYXk8c3RyaW5nfG51bWJlcj59IHBhdGggUGF0aCB0byByZWFkCiAgICAgKiBAcGFyYW0ge09iamVjdD19IGluZm8gSWYgYW4gb2JqZWN0IGlzIHByb3ZpZGVkIHRvIGBpbmZvYCwgdGhlIG5vcm1hbGl6ZWQKICAgICAqICAoZmxhdHRlbmVkKSBwYXRoIHdpbGwgYmUgc2V0IHRvIGBpbmZvLnBhdGhgLgogICAgICogQHJldHVybiB7Kn0gVmFsdWUgYXQgcGF0aCwgb3IgYHVuZGVmaW5lZGAgaWYgdGhlIHBhdGggY291bGQgbm90IGJlCiAgICAgKiAgZnVsbHkgZGVyZWZlcmVuY2VkLgogICAgICogQHRoaXMge1BhdGh9CiAgICAgKi8KICAgIGdldDogZnVuY3Rpb24ocm9vdCwgcGF0aCwgaW5mbykgewogICAgICBsZXQgcHJvcCA9IHJvb3Q7CiAgICAgIGxldCBwYXJ0cyA9IHRoaXMuc3BsaXQocGF0aCk7CiAgICAgIC8vIExvb3Agb3ZlciBwYXRoIHBhcnRzWzAuLm4tMV0gYW5kIGRlcmVmZXJlbmNlCiAgICAgIGZvciAobGV0IGk9MDsgaTxwYXJ0cy5sZW5ndGg7IGkrKykgewogICAgICAgIGlmICghcHJvcCkgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBsZXQgcGFydCA9IHBhcnRzW2ldOwogICAgICAgIHByb3AgPSBwcm9wW3BhcnRdOwogICAgICB9CiAgICAgIGlmIChpbmZvKSB7CiAgICAgICAgaW5mby5wYXRoID0gcGFydHMuam9pbignLicpOwogICAgICB9CiAgICAgIHJldHVybiBwcm9wOwogICAgfSwKCiAgICAvKioKICAgICAqIFNldHMgYSB2YWx1ZSB0byBhIHBhdGguICBJZiBhbnkgc3ViLXByb3BlcnR5IGluIHRoZSBwYXRoIGlzIGB1bmRlZmluZWRgLAogICAgICogdGhpcyBtZXRob2Qgd2lsbCBuby1vcC4KICAgICAqCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5QYXRoCiAgICAgKiBAcGFyYW0ge09iamVjdH0gcm9vdCBPYmplY3QgZnJvbSB3aGljaCB0byBkZXJlZmVyZW5jZSBwYXRoIGZyb20KICAgICAqIEBwYXJhbSB7c3RyaW5nIHwgIUFycmF5PHN0cmluZ3xudW1iZXI+fSBwYXRoIFBhdGggdG8gc2V0CiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFZhbHVlIHRvIHNldCB0byBwYXRoCiAgICAgKiBAcmV0dXJuIHtzdHJpbmcgfCB1bmRlZmluZWR9IFRoZSBub3JtYWxpemVkIHZlcnNpb24gb2YgdGhlIGlucHV0IHBhdGgKICAgICAqIEB0aGlzIHtQYXRofQogICAgICovCiAgICBzZXQ6IGZ1bmN0aW9uKHJvb3QsIHBhdGgsIHZhbHVlKSB7CiAgICAgIGxldCBwcm9wID0gcm9vdDsKICAgICAgbGV0IHBhcnRzID0gdGhpcy5zcGxpdChwYXRoKTsKICAgICAgbGV0IGxhc3QgPSBwYXJ0c1twYXJ0cy5sZW5ndGgtMV07CiAgICAgIGlmIChwYXJ0cy5sZW5ndGggPiAxKSB7CiAgICAgICAgLy8gTG9vcCBvdmVyIHBhdGggcGFydHNbMC4ubi0yXSBhbmQgZGVyZWZlcmVuY2UKICAgICAgICBmb3IgKGxldCBpPTA7IGk8cGFydHMubGVuZ3RoLTE7IGkrKykgewogICAgICAgICAgbGV0IHBhcnQgPSBwYXJ0c1tpXTsKICAgICAgICAgIHByb3AgPSBwcm9wW3BhcnRdOwogICAgICAgICAgaWYgKCFwcm9wKSB7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8gU2V0IHZhbHVlIHRvIG9iamVjdCBhdCBlbmQgb2YgcGF0aAogICAgICAgIHByb3BbbGFzdF0gPSB2YWx1ZTsKICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBTaW1wbGUgcHJvcGVydHkgc2V0CiAgICAgICAgcHJvcFtwYXRoXSA9IHZhbHVlOwogICAgICB9CiAgICAgIHJldHVybiBwYXJ0cy5qb2luKCcuJyk7CiAgICB9CgogIH07CgogIC8qKgogICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgZ2l2ZW4gc3RyaW5nIGlzIGEgc3RydWN0dXJlZCBkYXRhIHBhdGggKGhhcyBkb3RzKS4KICAgKgogICAqIFRoaXMgZnVuY3Rpb24gaXMgZGVwcmVjYXRlZC4gIFVzZSBgUG9seW1lci5QYXRoLmlzUGF0aGAgaW5zdGVhZC4KICAgKgogICAqIEV4YW1wbGU6CiAgICoKICAgKiBgYGAKICAgKiBQb2x5bWVyLlBhdGguaXNEZWVwKCdmb28uYmFyLmJheicpIC8vIHRydWUKICAgKiBQb2x5bWVyLlBhdGguaXNEZWVwKCdmb28nKSAgICAgICAgIC8vIGZhbHNlCiAgICogYGBgCiAgICoKICAgKiBAZGVwcmVjYXRlZAogICAqIEBtZW1iZXJvZiBQb2x5bWVyLlBhdGgKICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aCBQYXRoIHN0cmluZwogICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIHN0cmluZyBjb250YWluZWQgb25lIG9yIG1vcmUgZG90cwogICAqLwogIFBhdGguaXNEZWVwID0gUGF0aC5pc1BhdGg7CgogIFBvbHltZXIuUGF0aCA9IFBhdGg7Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CiAgJ3VzZSBzdHJpY3QnOwoKICBjb25zdCBjYXNlTWFwID0ge307CiAgY29uc3QgREFTSF9UT19DQU1FTCA9IC8tW2Etel0vZzsKICBjb25zdCBDQU1FTF9UT19EQVNIID0gLyhbQS1aXSkvZzsKCiAgLyoqCiAgICogTW9kdWxlIHdpdGggdXRpbGl0aWVzIGZvciBjb252ZXJ0aW5nIGJldHdlZW4gImRhc2gtY2FzZSIgYW5kICJjYW1lbENhc2UiCiAgICogaWRlbnRpZmllcnMuCiAgICoKICAgKiBAbmFtZXNwYWNlCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBNb2R1bGUgdGhhdCBwcm92aWRlcyB1dGlsaXRpZXMgZm9yIGNvbnZlcnRpbmcgYmV0d2VlbiAiZGFzaC1jYXNlIgogICAqICAgYW5kICJjYW1lbENhc2UiLgogICAqLwogIGNvbnN0IENhc2VNYXAgPSB7CgogICAgLyoqCiAgICAgKiBDb252ZXJ0cyAiZGFzaC1jYXNlIiBpZGVudGlmaWVyIChlLmcuIGBmb28tYmFyLWJhemApIHRvICJjYW1lbENhc2UiCiAgICAgKiAoZS5nLiBgZm9vQmFyQmF6YCkuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuQ2FzZU1hcAogICAgICogQHBhcmFtIHtzdHJpbmd9IGRhc2ggRGFzaC1jYXNlIGlkZW50aWZpZXIKICAgICAqIEByZXR1cm4ge3N0cmluZ30gQ2FtZWwtY2FzZSByZXByZXNlbnRhdGlvbiBvZiB0aGUgaWRlbnRpZmllcgogICAgICovCiAgICBkYXNoVG9DYW1lbENhc2UoZGFzaCkgewogICAgICByZXR1cm4gY2FzZU1hcFtkYXNoXSB8fCAoCiAgICAgICAgY2FzZU1hcFtkYXNoXSA9IGRhc2guaW5kZXhPZignLScpIDwgMCA/IGRhc2ggOiBkYXNoLnJlcGxhY2UoREFTSF9UT19DQU1FTCwKICAgICAgICAgIChtKSA9PiBtWzFdLnRvVXBwZXJDYXNlKCkKICAgICAgICApCiAgICAgICk7CiAgICB9LAoKICAgIC8qKgogICAgICogQ29udmVydHMgImNhbWVsQ2FzZSIgaWRlbnRpZmllciAoZS5nLiBgZm9vQmFyQmF6YCkgdG8gImRhc2gtY2FzZSIKICAgICAqIChlLmcuIGBmb28tYmFyLWJhemApLgogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLkNhc2VNYXAKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjYW1lbCBDYW1lbC1jYXNlIGlkZW50aWZpZXIKICAgICAqIEByZXR1cm4ge3N0cmluZ30gRGFzaC1jYXNlIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpZGVudGlmaWVyCiAgICAgKi8KICAgIGNhbWVsVG9EYXNoQ2FzZShjYW1lbCkgewogICAgICByZXR1cm4gY2FzZU1hcFtjYW1lbF0gfHwgKAogICAgICAgIGNhc2VNYXBbY2FtZWxdID0gY2FtZWwucmVwbGFjZShDQU1FTF9UT19EQVNILCAnLSQxJykudG9Mb3dlckNhc2UoKQogICAgICApOwogICAgfQoKICB9OwoKICBQb2x5bWVyLkNhc2VNYXAgPSBDYXNlTWFwOwp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CgogICd1c2Ugc3RyaWN0JzsKCiAgLy8gTWljcm90YXNrIGltcGxlbWVudGVkIHVzaW5nIE11dGF0aW9uIE9ic2VydmVyCiAgbGV0IG1pY3JvdGFza0N1cnJIYW5kbGUgPSAwOwogIGxldCBtaWNyb3Rhc2tMYXN0SGFuZGxlID0gMDsKICBsZXQgbWljcm90YXNrQ2FsbGJhY2tzID0gW107CiAgbGV0IG1pY3JvdGFza05vZGVDb250ZW50ID0gMDsKICBsZXQgbWljcm90YXNrTm9kZSA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCcnKTsKICBuZXcgd2luZG93Lk11dGF0aW9uT2JzZXJ2ZXIobWljcm90YXNrRmx1c2gpLm9ic2VydmUobWljcm90YXNrTm9kZSwge2NoYXJhY3RlckRhdGE6IHRydWV9KTsKCiAgZnVuY3Rpb24gbWljcm90YXNrRmx1c2goKSB7CiAgICBjb25zdCBsZW4gPSBtaWNyb3Rhc2tDYWxsYmFja3MubGVuZ3RoOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykgewogICAgICBsZXQgY2IgPSBtaWNyb3Rhc2tDYWxsYmFja3NbaV07CiAgICAgIGlmIChjYikgewogICAgICAgIHRyeSB7CiAgICAgICAgICBjYigpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4geyB0aHJvdyBlOyB9KTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIG1pY3JvdGFza0NhbGxiYWNrcy5zcGxpY2UoMCwgbGVuKTsKICAgIG1pY3JvdGFza0xhc3RIYW5kbGUgKz0gbGVuOwogIH0KCiAgLyoqCiAgICogTW9kdWxlIHRoYXQgcHJvdmlkZXMgYSBudW1iZXIgb2Ygc3RyYXRlZ2llcyBmb3IgZW5xdWV1aW5nIGFzeW5jaHJvbm91cwogICAqIHRhc2tzLiAgRWFjaCBzdWItbW9kdWxlIHByb3ZpZGVzIGEgc3RhbmRhcmQgYHJ1bihmbilgIGludGVyZmFjZSB0aGF0IHJldHVybnMgYQogICAqIGhhbmRsZSwgYW5kIGEgYGNhbmNlbChoYW5kbGUpYCBpbnRlcmZhY2UgZm9yIGNhbmNlbGluZyBhc3luYyB0YXNrcyBiZWZvcmUKICAgKiB0aGV5IHJ1bi4KICAgKgogICAqIEBuYW1lc3BhY2UKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBzdW1tYXJ5IE1vZHVsZSB0aGF0IHByb3ZpZGVzIGEgbnVtYmVyIG9mIHN0cmF0ZWdpZXMgZm9yIGVucXVldWluZyBhc3luY2hyb25vdXMKICAgKiB0YXNrcy4KICAgKi8KICBQb2x5bWVyLkFzeW5jID0gewoKICAgIC8qKgogICAgICogQXN5bmMgaW50ZXJmYWNlIHdyYXBwZXIgYXJvdW5kIGBzZXRUaW1lb3V0YC4KICAgICAqCiAgICAgKiBAbmFtZXNwYWNlCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5Bc3luYwogICAgICogQHN1bW1hcnkgQXN5bmMgaW50ZXJmYWNlIHdyYXBwZXIgYXJvdW5kIGBzZXRUaW1lb3V0YC4KICAgICAqLwogICAgdGltZU91dDogewogICAgICAvKioKICAgICAgICogUmV0dXJucyBhIHN1Yi1tb2R1bGUgd2l0aCB0aGUgYXN5bmMgaW50ZXJmYWNlIHByb3ZpZGluZyB0aGUgcHJvdmlkZWQKICAgICAgICogZGVsYXkuCiAgICAgICAqCiAgICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLkFzeW5jLnRpbWVPdXQKICAgICAgICogQHBhcmFtIHtudW1iZXI9fSBkZWxheSBUaW1lIHRvIHdhaXQgYmVmb3JlIGNhbGxpbmcgY2FsbGJhY2tzIGluIG1zCiAgICAgICAqIEByZXR1cm4geyFBc3luY0ludGVyZmFjZX0gQW4gYXN5bmMgdGltZW91dCBpbnRlcmZhY2UKICAgICAgICovCiAgICAgIGFmdGVyKGRlbGF5KSB7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIHJ1bihmbikgeyByZXR1cm4gd2luZG93LnNldFRpbWVvdXQoZm4sIGRlbGF5KTsgfSwKICAgICAgICAgIGNhbmNlbChoYW5kbGUpIHsKICAgICAgICAgICAgd2luZG93LmNsZWFyVGltZW91dChoYW5kbGUpOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgIH0sCiAgICAgIC8qKgogICAgICAgKiBFbnF1ZXVlcyBhIGZ1bmN0aW9uIGNhbGxlZCBpbiB0aGUgbmV4dCB0YXNrLgogICAgICAgKgogICAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5Bc3luYy50aW1lT3V0CiAgICAgICAqIEBwYXJhbSB7IUZ1bmN0aW9ufSBmbiBDYWxsYmFjayB0byBydW4KICAgICAgICogQHBhcmFtIHtudW1iZXI9fSBkZWxheSBEZWxheSBpbiBtaWxsaXNlY29uZHMKICAgICAgICogQHJldHVybiB7bnVtYmVyfSBIYW5kbGUgdXNlZCBmb3IgY2FuY2VsaW5nIHRhc2sKICAgICAgICovCiAgICAgIHJ1bihmbiwgZGVsYXkpIHsKICAgICAgICByZXR1cm4gd2luZG93LnNldFRpbWVvdXQoZm4sIGRlbGF5KTsKICAgICAgfSwKICAgICAgLyoqCiAgICAgICAqIENhbmNlbHMgYSBwcmV2aW91c2x5IGVucXVldWVkIGB0aW1lT3V0YCBjYWxsYmFjay4KICAgICAgICoKICAgICAgICogQG1lbWJlcm9mIFBvbHltZXIuQXN5bmMudGltZU91dAogICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGFuZGxlIEhhbmRsZSByZXR1cm5lZCBmcm9tIGBydW5gIG9mIGNhbGxiYWNrIHRvIGNhbmNlbAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgY2FuY2VsKGhhbmRsZSkgewogICAgICAgIHdpbmRvdy5jbGVhclRpbWVvdXQoaGFuZGxlKTsKICAgICAgfQogICAgfSwKCiAgICAvKioKICAgICAqIEFzeW5jIGludGVyZmFjZSB3cmFwcGVyIGFyb3VuZCBgcmVxdWVzdEFuaW1hdGlvbkZyYW1lYC4KICAgICAqCiAgICAgKiBAbmFtZXNwYWNlCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5Bc3luYwogICAgICogQHN1bW1hcnkgQXN5bmMgaW50ZXJmYWNlIHdyYXBwZXIgYXJvdW5kIGByZXF1ZXN0QW5pbWF0aW9uRnJhbWVgLgogICAgICovCiAgICBhbmltYXRpb25GcmFtZTogewogICAgICAvKioKICAgICAgICogRW5xdWV1ZXMgYSBmdW5jdGlvbiBjYWxsZWQgYXQgYHJlcXVlc3RBbmltYXRpb25GcmFtZWAgdGltaW5nLgogICAgICAgKgogICAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5Bc3luYy5hbmltYXRpb25GcmFtZQogICAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKG51bWJlcik6dm9pZH0gZm4gQ2FsbGJhY2sgdG8gcnVuCiAgICAgICAqIEByZXR1cm4ge251bWJlcn0gSGFuZGxlIHVzZWQgZm9yIGNhbmNlbGluZyB0YXNrCiAgICAgICAqLwogICAgICBydW4oZm4pIHsKICAgICAgICByZXR1cm4gd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZShmbik7CiAgICAgIH0sCiAgICAgIC8qKgogICAgICAgKiBDYW5jZWxzIGEgcHJldmlvdXNseSBlbnF1ZXVlZCBgYW5pbWF0aW9uRnJhbWVgIGNhbGxiYWNrLgogICAgICAgKgogICAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5Bc3luYy5hbmltYXRpb25GcmFtZQogICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGFuZGxlIEhhbmRsZSByZXR1cm5lZCBmcm9tIGBydW5gIG9mIGNhbGxiYWNrIHRvIGNhbmNlbAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgY2FuY2VsKGhhbmRsZSkgewogICAgICAgIHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZShoYW5kbGUpOwogICAgICB9CiAgICB9LAoKICAgIC8qKgogICAgICogQXN5bmMgaW50ZXJmYWNlIHdyYXBwZXIgYXJvdW5kIGByZXF1ZXN0SWRsZUNhbGxiYWNrYC4gIEZhbGxzIGJhY2sgdG8KICAgICAqIGBzZXRUaW1lb3V0YCBvbiBicm93c2VycyB0aGF0IGRvIG5vdCBzdXBwb3J0IGByZXF1ZXN0SWRsZUNhbGxiYWNrYC4KICAgICAqCiAgICAgKiBAbmFtZXNwYWNlCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5Bc3luYwogICAgICogQHN1bW1hcnkgQXN5bmMgaW50ZXJmYWNlIHdyYXBwZXIgYXJvdW5kIGByZXF1ZXN0SWRsZUNhbGxiYWNrYC4KICAgICAqLwogICAgaWRsZVBlcmlvZDogewogICAgICAvKioKICAgICAgICogRW5xdWV1ZXMgYSBmdW5jdGlvbiBjYWxsZWQgYXQgYHJlcXVlc3RJZGxlQ2FsbGJhY2tgIHRpbWluZy4KICAgICAgICoKICAgICAgICogQG1lbWJlcm9mIFBvbHltZXIuQXN5bmMuaWRsZVBlcmlvZAogICAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKCFJZGxlRGVhZGxpbmUpOnZvaWR9IGZuIENhbGxiYWNrIHRvIHJ1bgogICAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IEhhbmRsZSB1c2VkIGZvciBjYW5jZWxpbmcgdGFzawogICAgICAgKi8KICAgICAgcnVuKGZuKSB7CiAgICAgICAgcmV0dXJuIHdpbmRvdy5yZXF1ZXN0SWRsZUNhbGxiYWNrID8KICAgICAgICAgIHdpbmRvdy5yZXF1ZXN0SWRsZUNhbGxiYWNrKGZuKSA6CiAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dChmbiwgMTYpOwogICAgICB9LAogICAgICAvKioKICAgICAgICogQ2FuY2VscyBhIHByZXZpb3VzbHkgZW5xdWV1ZWQgYGlkbGVQZXJpb2RgIGNhbGxiYWNrLgogICAgICAgKgogICAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5Bc3luYy5pZGxlUGVyaW9kCiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoYW5kbGUgSGFuZGxlIHJldHVybmVkIGZyb20gYHJ1bmAgb2YgY2FsbGJhY2sgdG8gY2FuY2VsCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBjYW5jZWwoaGFuZGxlKSB7CiAgICAgICAgd2luZG93LmNhbmNlbElkbGVDYWxsYmFjayA/CiAgICAgICAgICB3aW5kb3cuY2FuY2VsSWRsZUNhbGxiYWNrKGhhbmRsZSkgOgogICAgICAgICAgd2luZG93LmNsZWFyVGltZW91dChoYW5kbGUpOwogICAgICB9CiAgICB9LAoKICAgIC8qKgogICAgICogQXN5bmMgaW50ZXJmYWNlIGZvciBlbnF1ZXVpbmcgY2FsbGJhY2tzIHRoYXQgcnVuIGF0IG1pY3JvdGFzayB0aW1pbmcuCiAgICAgKgogICAgICogTm90ZSB0aGF0IG1pY3JvdGFzayB0aW1pbmcgaXMgYWNoaWV2ZWQgdmlhIGEgc2luZ2xlIGBNdXRhdGlvbk9ic2VydmVyYCwKICAgICAqIGFuZCB0aHVzIGNhbGxiYWNrcyBlbnF1ZXVlZCB3aXRoIHRoaXMgQVBJIHdpbGwgYWxsIHJ1biBpbiBhIHNpbmdsZQogICAgICogYmF0Y2gsIGFuZCBub3QgaW50ZXJsZWF2ZWQgd2l0aCBvdGhlciBtaWNyb3Rhc2tzIHN1Y2ggYXMgcHJvbWlzZXMuCiAgICAgKiBQcm9taXNlcyBhcmUgYXZvaWRlZCBhcyBhbiBpbXBsZW1lbnRhdGlvbiBjaG9pY2UgZm9yIHRoZSB0aW1lIGJlaW5nCiAgICAgKiBkdWUgdG8gU2FmYXJpIGJ1Z3MgdGhhdCBjYXVzZSBQcm9taXNlcyB0byBsYWNrIG1pY3JvdGFzayBndWFyYW50ZWVzLgogICAgICoKICAgICAqIEBuYW1lc3BhY2UKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLkFzeW5jCiAgICAgKiBAc3VtbWFyeSBBc3luYyBpbnRlcmZhY2UgZm9yIGVucXVldWluZyBjYWxsYmFja3MgdGhhdCBydW4gYXQgbWljcm90YXNrCiAgICAgKiAgIHRpbWluZy4KICAgICAqLwogICAgbWljcm9UYXNrOiB7CgogICAgICAvKioKICAgICAgICogRW5xdWV1ZXMgYSBmdW5jdGlvbiBjYWxsZWQgYXQgbWljcm90YXNrIHRpbWluZy4KICAgICAgICoKICAgICAgICogQG1lbWJlcm9mIFBvbHltZXIuQXN5bmMubWljcm9UYXNrCiAgICAgICAqIEBwYXJhbSB7IUZ1bmN0aW9uPX0gY2FsbGJhY2sgQ2FsbGJhY2sgdG8gcnVuCiAgICAgICAqIEByZXR1cm4ge251bWJlcn0gSGFuZGxlIHVzZWQgZm9yIGNhbmNlbGluZyB0YXNrCiAgICAgICAqLwogICAgICBydW4oY2FsbGJhY2spIHsKICAgICAgICBtaWNyb3Rhc2tOb2RlLnRleHRDb250ZW50ID0gbWljcm90YXNrTm9kZUNvbnRlbnQrKzsKICAgICAgICBtaWNyb3Rhc2tDYWxsYmFja3MucHVzaChjYWxsYmFjayk7CiAgICAgICAgcmV0dXJuIG1pY3JvdGFza0N1cnJIYW5kbGUrKzsKICAgICAgfSwKCiAgICAgIC8qKgogICAgICAgKiBDYW5jZWxzIGEgcHJldmlvdXNseSBlbnF1ZXVlZCBgbWljcm9UYXNrYCBjYWxsYmFjay4KICAgICAgICoKICAgICAgICogQG1lbWJlcm9mIFBvbHltZXIuQXN5bmMubWljcm9UYXNrCiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoYW5kbGUgSGFuZGxlIHJldHVybmVkIGZyb20gYHJ1bmAgb2YgY2FsbGJhY2sgdG8gY2FuY2VsCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBjYW5jZWwoaGFuZGxlKSB7CiAgICAgICAgY29uc3QgaWR4ID0gaGFuZGxlIC0gbWljcm90YXNrTGFzdEhhbmRsZTsKICAgICAgICBpZiAoaWR4ID49IDApIHsKICAgICAgICAgIGlmICghbWljcm90YXNrQ2FsbGJhY2tzW2lkeF0pIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGFzeW5jIGhhbmRsZTogJyArIGhhbmRsZSk7CiAgICAgICAgICB9CiAgICAgICAgICBtaWNyb3Rhc2tDYWxsYmFja3NbaWR4XSA9IG51bGw7CiAgICAgICAgfQogICAgICB9CgogICAgfQogIH07Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgogIChmdW5jdGlvbiAoKSB7CgogICAgJ3VzZSBzdHJpY3QnOwoKICAgIC8qKiBAY29uc3QgeyFBc3luY0ludGVyZmFjZX0gKi8KICAgIGNvbnN0IG1pY3JvdGFzayA9IFBvbHltZXIuQXN5bmMubWljcm9UYXNrOwoKICAgIC8qKgogICAgICogRWxlbWVudCBjbGFzcyBtaXhpbiB0aGF0IHByb3ZpZGVzIGJhc2ljIG1ldGEtcHJvZ3JhbW1pbmcgZm9yIGNyZWF0aW5nIG9uZQogICAgICogb3IgbW9yZSBwcm9wZXJ0eSBhY2Nlc3NvcnMgKGdldHRlci9zZXR0ZXIgcGFpcikgdGhhdCBlbnF1ZXVlIGFuIGFzeW5jCiAgICAgKiAoYmF0Y2hlZCkgYF9wcm9wZXJ0aWVzQ2hhbmdlZGAgY2FsbGJhY2suCiAgICAgKgogICAgICogRm9yIGJhc2ljIHVzYWdlIG9mIHRoaXMgbWl4aW4sIGNhbGwgYE15Q2xhc3MuY3JlYXRlUHJvcGVydGllcyhwcm9wcylgCiAgICAgKiBvbmNlIGF0IGNsYXNzIGRlZmluaXRpb24gdGltZSB0byBjcmVhdGUgcHJvcGVydHkgYWNjZXNzb3JzIGZvciBwcm9wZXJ0aWVzCiAgICAgKiBuYW1lZCBpbiBwcm9wcywgaW1wbGVtZW50IGBfcHJvcGVydGllc0NoYW5nZWRgIHRvIHJlYWN0IGFzIGRlc2lyZWQgdG8KICAgICAqIHByb3BlcnR5IGNoYW5nZXMsIGFuZCBpbXBsZW1lbnQgYHN0YXRpYyBnZXQgb2JzZXJ2ZWRBdHRyaWJ1dGVzKClgIGFuZAogICAgICogaW5jbHVkZSBsb3dlcmNhc2UgdmVyc2lvbnMgb2YgYW55IHByb3BlcnR5IG5hbWVzIHRoYXQgc2hvdWxkIGJlIHNldCBmcm9tCiAgICAgKiBhdHRyaWJ1dGVzLiBMYXN0LCBjYWxsIGB0aGlzLl9lbmFibGVQcm9wZXJ0aWVzKClgIGluIHRoZSBlbGVtZW50J3MKICAgICAqIGBjb25uZWN0ZWRDYWxsYmFja2AgdG8gZW5hYmxlIHRoZSBhY2Nlc3NvcnMuCiAgICAgKgogICAgICogQG1peGluRnVuY3Rpb24KICAgICAqIEBwb2x5bWVyCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAgICogQHN1bW1hcnkgRWxlbWVudCBjbGFzcyBtaXhpbiBmb3IgcmVhY3RpbmcgdG8gcHJvcGVydHkgY2hhbmdlcyBmcm9tCiAgICAgKiAgIGdlbmVyYXRlZCBwcm9wZXJ0eSBhY2Nlc3NvcnMuCiAgICAgKi8KICAgIFBvbHltZXIuUHJvcGVydGllc0NoYW5nZWQgPSBQb2x5bWVyLmRlZHVwaW5nTWl4aW4oc3VwZXJDbGFzcyA9PiB7CgogICAgICAvKioKICAgICAgICogQHBvbHltZXIKICAgICAgICogQG1peGluQ2xhc3MKICAgICAgICogQGV4dGVuZHMge3N1cGVyQ2xhc3N9CiAgICAgICAqIEBpbXBsZW1lbnRzIHtQb2x5bWVyX1Byb3BlcnRpZXNDaGFuZ2VkfQogICAgICAgKiBAdW5yZXN0cmljdGVkCiAgICAgICAqLwogICAgICBjbGFzcyBQcm9wZXJ0aWVzQ2hhbmdlZCBleHRlbmRzIHN1cGVyQ2xhc3MgewoKICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIHByb3BlcnR5IGFjY2Vzc29ycyBmb3IgdGhlIGdpdmVuIHByb3BlcnR5IG5hbWVzLgogICAgICAgICAqIEBwYXJhbSB7IU9iamVjdH0gcHJvcHMgT2JqZWN0IHdob3NlIGtleXMgYXJlIG5hbWVzIG9mIGFjY2Vzc29ycy4KICAgICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY3JlYXRlUHJvcGVydGllcyhwcm9wcykgewogICAgICAgICAgY29uc3QgcHJvdG8gPSB0aGlzLnByb3RvdHlwZTsKICAgICAgICAgIGZvciAobGV0IHByb3AgaW4gcHJvcHMpIHsKICAgICAgICAgICAgLy8gZG9uJ3Qgc3RvbXAgYW4gZXhpc3RpbmcgYWNjZXNzb3IKICAgICAgICAgICAgaWYgKCEocHJvcCBpbiBwcm90bykpIHsKICAgICAgICAgICAgICBwcm90by5fY3JlYXRlUHJvcGVydHlBY2Nlc3Nvcihwcm9wKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyBhbiBhdHRyaWJ1dGUgbmFtZSB0aGF0IGNvcnJlc3BvbmRzIHRvIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICAgKiBUaGUgYXR0cmlidXRlIG5hbWUgaXMgdGhlIGxvd2VyY2FzZWQgcHJvcGVydHkgbmFtZS4gT3ZlcnJpZGUgdG8KICAgICAgICAgKiBjdXN0b21pemUgdGhpcyBtYXBwaW5nLgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSB0byBjb252ZXJ0CiAgICAgICAgICogQHJldHVybiB7c3RyaW5nfSBBdHRyaWJ1dGUgbmFtZSBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICAgKgogICAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgYXR0cmlidXRlTmFtZUZvclByb3BlcnR5KHByb3BlcnR5KSB7CiAgICAgICAgICByZXR1cm4gcHJvcGVydHkudG9Mb3dlckNhc2UoKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIE92ZXJyaWRlIHBvaW50IHRvIHByb3ZpZGUgYSB0eXBlIHRvIHdoaWNoIHRvIGRlc2VyaWFsaXplIGEgdmFsdWUgdG8KICAgICAgICAgKiBhIGdpdmVuIHByb3BlcnR5LgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIE5hbWUgb2YgcHJvcGVydHkKICAgICAgICAgKgogICAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdHlwZUZvclByb3BlcnR5KG5hbWUpIHsgfSAvL2VzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnMKCiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHNldHRlci9nZXR0ZXIgcGFpciBmb3IgdGhlIG5hbWVkIHByb3BlcnR5IHdpdGggaXRzIG93bgogICAgICAgICAqIGxvY2FsIHN0b3JhZ2UuICBUaGUgZ2V0dGVyIHJldHVybnMgdGhlIHZhbHVlIGluIHRoZSBsb2NhbCBzdG9yYWdlLAogICAgICAgICAqIGFuZCB0aGUgc2V0dGVyIGNhbGxzIGBfc2V0UHJvcGVydHlgLCB3aGljaCB1cGRhdGVzIHRoZSBsb2NhbCBzdG9yYWdlCiAgICAgICAgICogZm9yIHRoZSBwcm9wZXJ0eSBhbmQgZW5xdWV1ZXMgYSBgX3Byb3BlcnRpZXNDaGFuZ2VkYCBjYWxsYmFjay4KICAgICAgICAgKgogICAgICAgICAqIFRoaXMgbWV0aG9kIG1heSBiZSBjYWxsZWQgb24gYSBwcm90b3R5cGUgb3IgYW4gaW5zdGFuY2UuICBDYWxsaW5nCiAgICAgICAgICogdGhpcyBtZXRob2QgbWF5IG92ZXJ3cml0ZSBhIHByb3BlcnR5IHZhbHVlIHRoYXQgYWxyZWFkeSBleGlzdHMgb24KICAgICAgICAgKiB0aGUgcHJvdG90eXBlL2luc3RhbmNlIGJ5IGNyZWF0aW5nIHRoZSBhY2Nlc3Nvci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBOYW1lIG9mIHRoZSBwcm9wZXJ0eQogICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbj19IHJlYWRPbmx5IFdoZW4gdHJ1ZSwgbm8gc2V0dGVyIGlzIGNyZWF0ZWQ7IHRoZQogICAgICAgICAqICAgcHJvdGVjdGVkIGBfc2V0UHJvcGVydHlgIGZ1bmN0aW9uIG11c3QgYmUgdXNlZCB0byBzZXQgdGhlIHByb3BlcnR5CiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAgICovCiAgICAgICAgX2NyZWF0ZVByb3BlcnR5QWNjZXNzb3IocHJvcGVydHksIHJlYWRPbmx5KSB7CiAgICAgICAgICB0aGlzLl9hZGRQcm9wZXJ0eVRvQXR0cmlidXRlTWFwKHByb3BlcnR5KTsKICAgICAgICAgIGlmICghdGhpcy5oYXNPd25Qcm9wZXJ0eSgnX19kYXRhSGFzQWNjZXNzb3InKSkgewogICAgICAgICAgICB0aGlzLl9fZGF0YUhhc0FjY2Vzc29yID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5fX2RhdGFIYXNBY2Nlc3Nvcik7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIXRoaXMuX19kYXRhSGFzQWNjZXNzb3JbcHJvcGVydHldKSB7CiAgICAgICAgICAgIHRoaXMuX19kYXRhSGFzQWNjZXNzb3JbcHJvcGVydHldID0gdHJ1ZTsKICAgICAgICAgICAgdGhpcy5fZGVmaW5lUHJvcGVydHlBY2Nlc3Nvcihwcm9wZXJ0eSwgcmVhZE9ubHkpOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyB0aGUgZ2l2ZW4gYHByb3BlcnR5YCB0byBhIG1hcCBtYXRjaGluZyBhdHRyaWJ1dGUgbmFtZXMKICAgICAgICAgKiB0byBwcm9wZXJ0eSBuYW1lcywgdXNpbmcgYGF0dHJpYnV0ZU5hbWVGb3JQcm9wZXJ0eWAuIFRoaXMgbWFwIGlzCiAgICAgICAgICogdXNlZCB3aGVuIGRlc2VyaWFsaXppbmcgYXR0cmlidXRlIHZhbHVlcyB0byBwcm9wZXJ0aWVzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgdGhlIHByb3BlcnR5CiAgICAgICAgICovCiAgICAgICAgX2FkZFByb3BlcnR5VG9BdHRyaWJ1dGVNYXAocHJvcGVydHkpIHsKICAgICAgICAgIGlmICghdGhpcy5oYXNPd25Qcm9wZXJ0eSgnX19kYXRhQXR0cmlidXRlcycpKSB7CiAgICAgICAgICAgIHRoaXMuX19kYXRhQXR0cmlidXRlcyA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMuX19kYXRhQXR0cmlidXRlcyk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIXRoaXMuX19kYXRhQXR0cmlidXRlc1twcm9wZXJ0eV0pIHsKICAgICAgICAgICAgY29uc3QgYXR0ciA9IHRoaXMuY29uc3RydWN0b3IuYXR0cmlidXRlTmFtZUZvclByb3BlcnR5KHByb3BlcnR5KTsKICAgICAgICAgICAgdGhpcy5fX2RhdGFBdHRyaWJ1dGVzW2F0dHJdID0gcHJvcGVydHk7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBEZWZpbmVzIGEgcHJvcGVydHkgYWNjZXNzb3IgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgTmFtZSBvZiB0aGUgcHJvcGVydHkKICAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW49fSByZWFkT25seSBXaGVuIHRydWUsIG5vIHNldHRlciBpcyBjcmVhdGVkCiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKi8KICAgICAgICAgX2RlZmluZVByb3BlcnR5QWNjZXNzb3IocHJvcGVydHksIHJlYWRPbmx5KSB7CiAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgcHJvcGVydHksIHsKICAgICAgICAgICAgLyogZXNsaW50LWRpc2FibGUgdmFsaWQtanNkb2MgKi8KICAgICAgICAgICAgLyoqIEB0aGlzIHtQcm9wZXJ0aWVzQ2hhbmdlZH0gKi8KICAgICAgICAgICAgZ2V0KCkgewogICAgICAgICAgICAgIHJldHVybiB0aGlzLl9nZXRQcm9wZXJ0eShwcm9wZXJ0eSk7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIC8qKiBAdGhpcyB7UHJvcGVydGllc0NoYW5nZWR9ICovCiAgICAgICAgICAgIHNldDogcmVhZE9ubHkgPyBmdW5jdGlvbiAoKSB7fSA6IGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgICAgIHRoaXMuX3NldFByb3BlcnR5KHByb3BlcnR5LCB2YWx1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLyogZXNsaW50LWVuYWJsZSAqLwogICAgICAgICAgfSk7CiAgICAgICAgfQoKICAgICAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICB0aGlzLl9fZGF0YUVuYWJsZWQgPSBmYWxzZTsKICAgICAgICAgIHRoaXMuX19kYXRhUmVhZHkgPSBmYWxzZTsKICAgICAgICAgIHRoaXMuX19kYXRhSW52YWxpZCA9IGZhbHNlOwogICAgICAgICAgdGhpcy5fX2RhdGEgPSB7fTsKICAgICAgICAgIHRoaXMuX19kYXRhUGVuZGluZyA9IG51bGw7CiAgICAgICAgICB0aGlzLl9fZGF0YU9sZCA9IG51bGw7CiAgICAgICAgICB0aGlzLl9fZGF0YUluc3RhbmNlUHJvcHMgPSBudWxsOwogICAgICAgICAgdGhpcy5fX3NlcmlhbGl6aW5nID0gZmFsc2U7CiAgICAgICAgICB0aGlzLl9pbml0aWFsaXplUHJvcGVydGllcygpOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogTGlmZWN5Y2xlIGNhbGxiYWNrIGNhbGxlZCB3aGVuIHByb3BlcnRpZXMgYXJlIGVuYWJsZWQgdmlhCiAgICAgICAgICogYF9lbmFibGVQcm9wZXJ0aWVzYC4KICAgICAgICAgKgogICAgICAgICAqIFVzZXJzIG1heSBvdmVycmlkZSB0aGlzIGZ1bmN0aW9uIHRvIGltcGxlbWVudCBiZWhhdmlvciB0aGF0IGlzCiAgICAgICAgICogZGVwZW5kZW50IG9uIHRoZSBlbGVtZW50IGhhdmluZyBpdHMgcHJvcGVydHkgZGF0YSBpbml0aWFsaXplZCwgZS5nLgogICAgICAgICAqIGZyb20gZGVmYXVsdHMgKGluaXRpYWxpemVkIGZyb20gYGNvbnN0cnVjdG9yYCwgYF9pbml0aWFsaXplUHJvcGVydGllc2ApLAogICAgICAgICAqIGBhdHRyaWJ1dGVDaGFuZ2VkQ2FsbGJhY2tgLCBvciB2YWx1ZXMgcHJvcGFnYXRlZCBmcm9tIGhvc3QgZS5nLiB2aWEKICAgICAgICAgKiBiaW5kaW5ncy4gIGBzdXBlci5yZWFkeSgpYCBtdXN0IGJlIGNhbGxlZCB0byBlbnN1cmUgdGhlIGRhdGEgc3lzdGVtCiAgICAgICAgICogYmVjb21lcyBlbmFibGVkLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKiBAcHVibGljCiAgICAgICAgICovCiAgICAgICAgcmVhZHkoKSB7CiAgICAgICAgICB0aGlzLl9fZGF0YVJlYWR5ID0gdHJ1ZTsKICAgICAgICAgIHRoaXMuX2ZsdXNoUHJvcGVydGllcygpOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogSW5pdGlhbGl6ZXMgdGhlIGxvY2FsIHN0b3JhZ2UgZm9yIHByb3BlcnR5IGFjY2Vzc29ycy4KICAgICAgICAgKgogICAgICAgICAqIFByb3ZpZGVkIGFzIGFuIG92ZXJyaWRlIHBvaW50IGZvciBwZXJmb3JtaW5nIGFueSBzZXR1cCB3b3JrIHByaW9yCiAgICAgICAgICogdG8gaW5pdGlhbGl6aW5nIHRoZSBwcm9wZXJ0eSBhY2Nlc3NvciBzeXN0ZW0uCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICAgKi8KICAgICAgICBfaW5pdGlhbGl6ZVByb3BlcnRpZXMoKSB7CiAgICAgICAgICAvLyBDYXB0dXJlIGluc3RhbmNlIHByb3BlcnRpZXM7IHRoZXNlIHdpbGwgYmUgc2V0IGludG8gYWNjZXNzb3JzCiAgICAgICAgICAvLyBkdXJpbmcgZmlyc3QgZmx1c2guIERvbid0IHNldCB0aGVtIGhlcmUsIHNpbmNlIHdlIHdhbnQKICAgICAgICAgIC8vIHRoZXNlIHRvIG92ZXJ3cml0ZSBkZWZhdWx0cy9jb25zdHJ1Y3RvciBhc3NpZ25tZW50cwogICAgICAgICAgZm9yIChsZXQgcCBpbiB0aGlzLl9fZGF0YUhhc0FjY2Vzc29yKSB7CiAgICAgICAgICAgIGlmICh0aGlzLmhhc093blByb3BlcnR5KHApKSB7CiAgICAgICAgICAgICAgdGhpcy5fX2RhdGFJbnN0YW5jZVByb3BzID0gdGhpcy5fX2RhdGFJbnN0YW5jZVByb3BzIHx8IHt9OwogICAgICAgICAgICAgIHRoaXMuX19kYXRhSW5zdGFuY2VQcm9wc1twXSA9IHRoaXNbcF07CiAgICAgICAgICAgICAgZGVsZXRlIHRoaXNbcF07CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENhbGxlZCBhdCByZWFkeSB0aW1lIHdpdGggYmFnIG9mIGluc3RhbmNlIHByb3BlcnRpZXMgdGhhdCBvdmVyd3JvdGUKICAgICAgICAgKiBhY2Nlc3NvcnMgd2hlbiB0aGUgZWxlbWVudCB1cGdyYWRlZC4KICAgICAgICAgKgogICAgICAgICAqIFRoZSBkZWZhdWx0IGltcGxlbWVudGF0aW9uIHNldHMgdGhlc2UgcHJvcGVydGllcyBiYWNrIGludG8gdGhlCiAgICAgICAgICogc2V0dGVyIGF0IHJlYWR5IHRpbWUuICBUaGlzIG1ldGhvZCBpcyBwcm92aWRlZCBhcyBhbiBvdmVycmlkZQogICAgICAgICAqIHBvaW50IGZvciBjdXN0b21pemluZyBvciBwcm92aWRpbmcgbW9yZSBlZmZpY2llbnQgaW5pdGlhbGl6YXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcHMgQmFnIG9mIHByb3BlcnR5IHZhbHVlcyB0aGF0IHdlcmUgb3ZlcndyaXR0ZW4KICAgICAgICAgKiAgIHdoZW4gY3JlYXRpbmcgcHJvcGVydHkgYWNjZXNzb3JzLgogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICogQHByb3RlY3RlZAogICAgICAgICAqLwogICAgICAgIF9pbml0aWFsaXplSW5zdGFuY2VQcm9wZXJ0aWVzKHByb3BzKSB7CiAgICAgICAgICBPYmplY3QuYXNzaWduKHRoaXMsIHByb3BzKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIFVwZGF0ZXMgdGhlIGxvY2FsIHN0b3JhZ2UgZm9yIGEgcHJvcGVydHkgKHZpYSBgX3NldFBlbmRpbmdQcm9wZXJ0eWApCiAgICAgICAgICogYW5kIGVucXVldWVzIGEgYF9wcm9lcHJ0aWVzQ2hhbmdlZGAgY2FsbGJhY2suCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgTmFtZSBvZiB0aGUgcHJvcGVydHkKICAgICAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFZhbHVlIHRvIHNldAogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICogQHByb3RlY3RlZAogICAgICAgICAqLwogICAgICAgIF9zZXRQcm9wZXJ0eShwcm9wZXJ0eSwgdmFsdWUpIHsKICAgICAgICAgIGlmICh0aGlzLl9zZXRQZW5kaW5nUHJvcGVydHkocHJvcGVydHksIHZhbHVlKSkgewogICAgICAgICAgICB0aGlzLl9pbnZhbGlkYXRlUHJvcGVydGllcygpOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgdmFsdWUgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgTmFtZSBvZiBwcm9wZXJ0eQogICAgICAgICAqIEByZXR1cm4geyp9IFZhbHVlIGZvciB0aGUgZ2l2ZW4gcHJvcGVydHkKICAgICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAgICovCiAgICAgICAgX2dldFByb3BlcnR5KHByb3BlcnR5KSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fX2RhdGFbcHJvcGVydHldOwogICAgICAgIH0KCiAgICAgICAgLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi8KICAgICAgICAvKioKICAgICAgICAgKiBVcGRhdGVzIHRoZSBsb2NhbCBzdG9yYWdlIGZvciBhIHByb3BlcnR5LCByZWNvcmRzIHRoZSBwcmV2aW91cyB2YWx1ZSwKICAgICAgICAgKiBhbmQgYWRkcyBpdCB0byB0aGUgc2V0IG9mICJwZW5kaW5nIGNoYW5nZXMiIHRoYXQgd2lsbCBiZSBwYXNzZWQgdG8gdGhlCiAgICAgICAgICogYF9wcm9wZXJ0aWVzQ2hhbmdlZGAgY2FsbGJhY2suICBUaGlzIG1ldGhvZCBkb2VzIG5vdCBlbnF1ZXVlIHRoZQogICAgICAgICAqIGBfcHJvcGVydGllc0NoYW5nZWRgIGNhbGxiYWNrLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgdGhlIHByb3BlcnR5CiAgICAgICAgICogQHBhcmFtIHsqfSB2YWx1ZSBWYWx1ZSB0byBzZXQKICAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW49fSBleHQgTm90IHVzZWQgaGVyZTsgYWZmb3JkYW5jZSBmb3IgY2xvc3VyZQogICAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFJldHVybnMgdHJ1ZSBpZiB0aGUgcHJvcGVydHkgY2hhbmdlZAogICAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICAgKi8KICAgICAgICBfc2V0UGVuZGluZ1Byb3BlcnR5KHByb3BlcnR5LCB2YWx1ZSwgZXh0KSB7CiAgICAgICAgICBsZXQgb2xkID0gdGhpcy5fX2RhdGFbcHJvcGVydHldOwogICAgICAgICAgbGV0IGNoYW5nZWQgPSB0aGlzLl9zaG91bGRQcm9wZXJ0eUNoYW5nZShwcm9wZXJ0eSwgdmFsdWUsIG9sZCk7CiAgICAgICAgICBpZiAoY2hhbmdlZCkgewogICAgICAgICAgICBpZiAoIXRoaXMuX19kYXRhUGVuZGluZykgewogICAgICAgICAgICAgIHRoaXMuX19kYXRhUGVuZGluZyA9IHt9OwogICAgICAgICAgICAgIHRoaXMuX19kYXRhT2xkID0ge307CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gRW5zdXJlIG9sZCBpcyBjYXB0dXJlZCBmcm9tIHRoZSBsYXN0IHR1cm4KICAgICAgICAgICAgaWYgKHRoaXMuX19kYXRhT2xkICYmICEocHJvcGVydHkgaW4gdGhpcy5fX2RhdGFPbGQpKSB7CiAgICAgICAgICAgICAgdGhpcy5fX2RhdGFPbGRbcHJvcGVydHldID0gb2xkOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuX19kYXRhW3Byb3BlcnR5XSA9IHZhbHVlOwogICAgICAgICAgICB0aGlzLl9fZGF0YVBlbmRpbmdbcHJvcGVydHldID0gdmFsdWU7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gY2hhbmdlZDsKICAgICAgICB9CiAgICAgICAgLyogZXNsaW50LWVuYWJsZSAqLwoKICAgICAgICAvKioKICAgICAgICAgKiBNYXJrcyB0aGUgcHJvcGVydGllcyBhcyBpbnZhbGlkLCBhbmQgZW5xdWV1ZXMgYW4gYXN5bmMKICAgICAgICAgKiBgX3Byb3BlcnRpZXNDaGFuZ2VkYCBjYWxsYmFjay4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICogQHByb3RlY3RlZAogICAgICAgICAqLwogICAgICAgIF9pbnZhbGlkYXRlUHJvcGVydGllcygpIHsKICAgICAgICAgIGlmICghdGhpcy5fX2RhdGFJbnZhbGlkICYmIHRoaXMuX19kYXRhUmVhZHkpIHsKICAgICAgICAgICAgdGhpcy5fX2RhdGFJbnZhbGlkID0gdHJ1ZTsKICAgICAgICAgICAgbWljcm90YXNrLnJ1bigoKSA9PiB7CiAgICAgICAgICAgICAgaWYgKHRoaXMuX19kYXRhSW52YWxpZCkgewogICAgICAgICAgICAgICAgdGhpcy5fX2RhdGFJbnZhbGlkID0gZmFsc2U7CiAgICAgICAgICAgICAgICB0aGlzLl9mbHVzaFByb3BlcnRpZXMoKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsbCB0byBlbmFibGUgcHJvcGVydHkgYWNjZXNzb3IgcHJvY2Vzc2luZy4gQmVmb3JlIHRoaXMgbWV0aG9kIGlzCiAgICAgICAgICogY2FsbGVkIGFjY2Vzc29yIHZhbHVlcyB3aWxsIGJlIHNldCBidXQgc2lkZSBlZmZlY3RzIGFyZQogICAgICAgICAqIHF1ZXVlZC4gV2hlbiBjYWxsZWQsIGFueSBwZW5kaW5nIHNpZGUgZWZmZWN0cyBvY2N1ciBpbW1lZGlhdGVseS4KICAgICAgICAgKiBGb3IgZWxlbWVudHMsIGdlbmVyYWxseSBgY29ubmVjdGVkQ2FsbGJhY2tgIGlzIGEgbm9ybWFsIHNwb3QgdG8gZG8gc28uCiAgICAgICAgICogSXQgaXMgc2FmZSB0byBjYWxsIHRoaXMgbWV0aG9kIG11bHRpcGxlIHRpbWVzIGFzIGl0IG9ubHkgdHVybnMgb24KICAgICAgICAgKiBwcm9wZXJ0eSBhY2Nlc3NvcnMgb25jZS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICogQHByb3RlY3RlZAogICAgICAgICAqLwogICAgICAgIF9lbmFibGVQcm9wZXJ0aWVzKCkgewogICAgICAgICAgaWYgKCF0aGlzLl9fZGF0YUVuYWJsZWQpIHsKICAgICAgICAgICAgdGhpcy5fX2RhdGFFbmFibGVkID0gdHJ1ZTsKICAgICAgICAgICAgaWYgKHRoaXMuX19kYXRhSW5zdGFuY2VQcm9wcykgewogICAgICAgICAgICAgIHRoaXMuX2luaXRpYWxpemVJbnN0YW5jZVByb3BlcnRpZXModGhpcy5fX2RhdGFJbnN0YW5jZVByb3BzKTsKICAgICAgICAgICAgICB0aGlzLl9fZGF0YUluc3RhbmNlUHJvcHMgPSBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMucmVhZHkoKTsKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENhbGxzIHRoZSBgX3Byb3BlcnRpZXNDaGFuZ2VkYCBjYWxsYmFjayB3aXRoIHRoZSBjdXJyZW50IHNldCBvZgogICAgICAgICAqIHBlbmRpbmcgY2hhbmdlcyAoYW5kIG9sZCB2YWx1ZXMgcmVjb3JkZWQgd2hlbiBwZW5kaW5nIGNoYW5nZXMgd2VyZQogICAgICAgICAqIHNldCksIGFuZCByZXNldHMgdGhlIHBlbmRpbmcgc2V0IG9mIGNoYW5nZXMuIEdlbmVyYWxseSwgdGhpcyBtZXRob2QKICAgICAgICAgKiBzaG91bGQgbm90IGJlIGNhbGxlZCBpbiB1c2VyIGNvZGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICAgKi8KICAgICAgICBfZmx1c2hQcm9wZXJ0aWVzKCkgewogICAgICAgICAgY29uc3QgcHJvcHMgPSB0aGlzLl9fZGF0YTsKICAgICAgICAgIGNvbnN0IGNoYW5nZWRQcm9wcyA9IHRoaXMuX19kYXRhUGVuZGluZzsKICAgICAgICAgIGNvbnN0IG9sZCA9IHRoaXMuX19kYXRhT2xkOwogICAgICAgICAgaWYgKHRoaXMuX3Nob3VsZFByb3BlcnRpZXNDaGFuZ2UocHJvcHMsIGNoYW5nZWRQcm9wcywgb2xkKSkgewogICAgICAgICAgICB0aGlzLl9fZGF0YVBlbmRpbmcgPSBudWxsOwogICAgICAgICAgICB0aGlzLl9fZGF0YU9sZCA9IG51bGw7CiAgICAgICAgICAgIHRoaXMuX3Byb3BlcnRpZXNDaGFuZ2VkKHByb3BzLCBjaGFuZ2VkUHJvcHMsIG9sZCk7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBDYWxsZWQgaW4gYF9mbHVzaFByb3BlcnRpZXNgIHRvIGRldGVybWluZSBpZiBgX3Byb3BlcnRpZXNDaGFuZ2VkYAogICAgICAgICAqIHNob3VsZCBiZSBjYWxsZWQuIFRoZSBkZWZhdWx0IGltcGxlbWVudGF0aW9uIHJldHVybnMgdHJ1ZSBpZgogICAgICAgICAqIHByb3BlcnRpZXMgYXJlIHBlbmRpbmcuIE92ZXJyaWRlIHRvIGN1c3RvbWl6ZSB3aGVuCiAgICAgICAgICogYF9wcm9wZXJ0aWVzQ2hhbmdlZGAgaXMgY2FsbGVkLgogICAgICAgICAqIEBwYXJhbSB7IU9iamVjdH0gY3VycmVudFByb3BzIEJhZyBvZiBhbGwgY3VycmVudCBhY2Nlc3NvciB2YWx1ZXMKICAgICAgICAgKiBAcGFyYW0geyFPYmplY3R9IGNoYW5nZWRQcm9wcyBCYWcgb2YgcHJvcGVydGllcyBjaGFuZ2VkIHNpbmNlIHRoZSBsYXN0CiAgICAgICAgICogICBjYWxsIHRvIGBfcHJvcGVydGllc0NoYW5nZWRgCiAgICAgICAgICogQHBhcmFtIHshT2JqZWN0fSBvbGRQcm9wcyBCYWcgb2YgcHJldmlvdXMgdmFsdWVzIGZvciBlYWNoIHByb3BlcnR5CiAgICAgICAgICogICBpbiBgY2hhbmdlZFByb3BzYAogICAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgY2hhbmdlZFByb3BzIGlzIHRydXRoeQogICAgICAgICAqLwogICAgICAgIF9zaG91bGRQcm9wZXJ0aWVzQ2hhbmdlKGN1cnJlbnRQcm9wcywgY2hhbmdlZFByb3BzLCBvbGRQcm9wcykgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzCiAgICAgICAgICByZXR1cm4gQm9vbGVhbihjaGFuZ2VkUHJvcHMpOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsbGJhY2sgY2FsbGVkIHdoZW4gYW55IHByb3BlcnRpZXMgd2l0aCBhY2Nlc3NvcnMgY3JlYXRlZCB2aWEKICAgICAgICAgKiBgX2NyZWF0ZVByb3BlcnR5QWNjZXNzb3JgIGhhdmUgYmVlbiBzZXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0geyFPYmplY3R9IGN1cnJlbnRQcm9wcyBCYWcgb2YgYWxsIGN1cnJlbnQgYWNjZXNzb3IgdmFsdWVzCiAgICAgICAgICogQHBhcmFtIHshT2JqZWN0fSBjaGFuZ2VkUHJvcHMgQmFnIG9mIHByb3BlcnRpZXMgY2hhbmdlZCBzaW5jZSB0aGUgbGFzdAogICAgICAgICAqICAgY2FsbCB0byBgX3Byb3BlcnRpZXNDaGFuZ2VkYAogICAgICAgICAqIEBwYXJhbSB7IU9iamVjdH0gb2xkUHJvcHMgQmFnIG9mIHByZXZpb3VzIHZhbHVlcyBmb3IgZWFjaCBwcm9wZXJ0eQogICAgICAgICAqICAgaW4gYGNoYW5nZWRQcm9wc2AKICAgICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICAgKi8KICAgICAgICBfcHJvcGVydGllc0NoYW5nZWQoY3VycmVudFByb3BzLCBjaGFuZ2VkUHJvcHMsIG9sZFByb3BzKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnMKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIE1ldGhvZCBjYWxsZWQgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgYSBwcm9wZXJ0eSB2YWx1ZSBzaG91bGQgYmUKICAgICAgICAgKiBjb25zaWRlcmVkIGFzIGEgY2hhbmdlIGFuZCBjYXVzZSB0aGUgYF9wcm9wZXJ0aWVzQ2hhbmdlZGAgY2FsbGJhY2sKICAgICAgICAgKiB0byBiZSBlbnF1ZXVlZC4KICAgICAgICAgKgogICAgICAgICAqIFRoZSBkZWZhdWx0IGltcGxlbWVudGF0aW9uIHJldHVybnMgYHRydWVgIGlmIGEgc3RyaWN0IGVxdWFsaXR5CiAgICAgICAgICogY2hlY2sgZmFpbHMuIFRoZSBtZXRob2QgYWx3YXlzIHJldHVybnMgZmFsc2UgZm9yIGBOYU5gLgogICAgICAgICAqCiAgICAgICAgICogT3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gZS5nLiBwcm92aWRlIHN0cmljdGVyIGNoZWNraW5nIGZvcgogICAgICAgICAqIE9iamVjdHMvQXJyYXlzIHdoZW4gdXNpbmcgaW1tdXRhYmxlIHBhdHRlcm5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICAgKiBAcGFyYW0geyp9IHZhbHVlIE5ldyBwcm9wZXJ0eSB2YWx1ZQogICAgICAgICAqIEBwYXJhbSB7Kn0gb2xkIFByZXZpb3VzIHByb3BlcnR5IHZhbHVlCiAgICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgcHJvcGVydHkgc2hvdWxkIGJlIGNvbnNpZGVyZWQgYSBjaGFuZ2UKICAgICAgICAgKiAgIGFuZCBlbnF1ZXVlIGEgYF9wcm9lcHJ0aWVzQ2hhbmdlZGAgY2FsbGJhY2sKICAgICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAgICovCiAgICAgICAgX3Nob3VsZFByb3BlcnR5Q2hhbmdlKHByb3BlcnR5LCB2YWx1ZSwgb2xkKSB7CiAgICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAvLyBTdHJpY3QgZXF1YWxpdHkgY2hlY2sKICAgICAgICAgICAgKG9sZCAhPT0gdmFsdWUgJiYKICAgICAgICAgICAgICAvLyBUaGlzIGVuc3VyZXMgKG9sZD09TmFOLCB2YWx1ZT09TmFOKSBhbHdheXMgcmV0dXJucyBmYWxzZQogICAgICAgICAgICAgIChvbGQgPT09IG9sZCB8fCB2YWx1ZSA9PT0gdmFsdWUpKQogICAgICAgICAgKTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEltcGxlbWVudHMgbmF0aXZlIEN1c3RvbSBFbGVtZW50cyBgYXR0cmlidXRlQ2hhbmdlZENhbGxiYWNrYCB0bwogICAgICAgICAqIHNldCBhbiBhdHRyaWJ1dGUgdmFsdWUgdG8gYSBwcm9wZXJ0eSB2aWEgYF9hdHRyaWJ1dGVUb1Byb3BlcnR5YC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIE5hbWUgb2YgYXR0cmlidXRlIHRoYXQgY2hhbmdlZAogICAgICAgICAqIEBwYXJhbSB7P3N0cmluZ30gb2xkIE9sZCBhdHRyaWJ1dGUgdmFsdWUKICAgICAgICAgKiBAcGFyYW0gez9zdHJpbmd9IHZhbHVlIE5ldyBhdHRyaWJ1dGUgdmFsdWUKICAgICAgICAgKiBAcGFyYW0gez9zdHJpbmd9IG5hbWVzcGFjZSBBdHRyaWJ1dGUgbmFtZXNwYWNlLgogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICogQHN1cHByZXNzIHttaXNzaW5nUHJvcGVydGllc30gU3VwZXIgbWF5IG9yIG1heSBub3QgaW1wbGVtZW50IHRoZSBjYWxsYmFjawogICAgICAgICAqLwogICAgICAgIGF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFjayhuYW1lLCBvbGQsIHZhbHVlLCBuYW1lc3BhY2UpIHsKICAgICAgICAgIGlmIChvbGQgIT09IHZhbHVlKSB7CiAgICAgICAgICAgIHRoaXMuX2F0dHJpYnV0ZVRvUHJvcGVydHkobmFtZSwgdmFsdWUpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHN1cGVyLmF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFjaykgewogICAgICAgICAgICBzdXBlci5hdHRyaWJ1dGVDaGFuZ2VkQ2FsbGJhY2sobmFtZSwgb2xkLCB2YWx1ZSwgbmFtZXNwYWNlKTsKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIERlc2VyaWFsaXplcyBhbiBhdHRyaWJ1dGUgdG8gaXRzIGFzc29jaWF0ZWQgcHJvcGVydHkuCiAgICAgICAgICoKICAgICAgICAgKiBUaGlzIG1ldGhvZCBjYWxscyB0aGUgYF9kZXNlcmlhbGl6ZVZhbHVlYCBtZXRob2QgdG8gY29udmVydCB0aGUgc3RyaW5nIHRvCiAgICAgICAgICogYSB0eXBlZCB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBhdHRyaWJ1dGUgTmFtZSBvZiBhdHRyaWJ1dGUgdG8gZGVzZXJpYWxpemUuCiAgICAgICAgICogQHBhcmFtIHs/c3RyaW5nfSB2YWx1ZSBvZiB0aGUgYXR0cmlidXRlLgogICAgICAgICAqIEBwYXJhbSB7Kj19IHR5cGUgdHlwZSB0byBkZXNlcmlhbGl6ZSB0bywgZGVmYXVsdHMgdG8gdGhlIHZhbHVlCiAgICAgICAgICogcmV0dXJuZWQgZnJvbSBgdHlwZUZvclByb3BlcnR5YAogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICovCiAgICAgICAgX2F0dHJpYnV0ZVRvUHJvcGVydHkoYXR0cmlidXRlLCB2YWx1ZSwgdHlwZSkgewogICAgICAgICAgaWYgKCF0aGlzLl9fc2VyaWFsaXppbmcpIHsKICAgICAgICAgICAgY29uc3QgbWFwID0gdGhpcy5fX2RhdGFBdHRyaWJ1dGVzOwogICAgICAgICAgICBjb25zdCBwcm9wZXJ0eSA9IG1hcCAmJiBtYXBbYXR0cmlidXRlXSB8fCBhdHRyaWJ1dGU7CiAgICAgICAgICAgIHRoaXNbcHJvcGVydHldID0gdGhpcy5fZGVzZXJpYWxpemVWYWx1ZSh2YWx1ZSwgdHlwZSB8fAogICAgICAgICAgICAgIHRoaXMuY29uc3RydWN0b3IudHlwZUZvclByb3BlcnR5KHByb3BlcnR5KSk7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBTZXJpYWxpemVzIGEgcHJvcGVydHkgdG8gaXRzIGFzc29jaWF0ZWQgYXR0cmlidXRlLgogICAgICAgICAqCiAgICAgICAgICogQHN1cHByZXNzIHtpbnZhbGlkQ2FzdHN9IENsb3N1cmUgY2FuJ3QgZmlndXJlIG91dCBgdGhpc2AgaXMgYW4gZWxlbWVudC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSBuYW1lIHRvIHJlZmxlY3QuCiAgICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSBhdHRyaWJ1dGUgQXR0cmlidXRlIG5hbWUgdG8gcmVmbGVjdCB0by4KICAgICAgICAgKiBAcGFyYW0geyo9fSB2YWx1ZSBQcm9wZXJ0eSB2YWx1ZSB0byByZWZlY3QuCiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKi8KICAgICAgICBfcHJvcGVydHlUb0F0dHJpYnV0ZShwcm9wZXJ0eSwgYXR0cmlidXRlLCB2YWx1ZSkgewogICAgICAgICAgdGhpcy5fX3NlcmlhbGl6aW5nID0gdHJ1ZTsKICAgICAgICAgIHZhbHVlID0gKGFyZ3VtZW50cy5sZW5ndGggPCAzKSA/IHRoaXNbcHJvcGVydHldIDogdmFsdWU7CiAgICAgICAgICB0aGlzLl92YWx1ZVRvTm9kZUF0dHJpYnV0ZSgvKiogQHR5cGUgeyFIVE1MRWxlbWVudH0gKi8odGhpcyksIHZhbHVlLAogICAgICAgICAgICBhdHRyaWJ1dGUgfHwgdGhpcy5jb25zdHJ1Y3Rvci5hdHRyaWJ1dGVOYW1lRm9yUHJvcGVydHkocHJvcGVydHkpKTsKICAgICAgICAgIHRoaXMuX19zZXJpYWxpemluZyA9IGZhbHNlOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyBhIHR5cGVkIHZhbHVlIHRvIGFuIEhUTUwgYXR0cmlidXRlIG9uIGEgbm9kZS4KICAgICAgICAgKgogICAgICAgICAqIFRoaXMgbWV0aG9kIGNhbGxzIHRoZSBgX3NlcmlhbGl6ZVZhbHVlYCBtZXRob2QgdG8gY29udmVydCB0aGUgdHlwZWQKICAgICAgICAgKiB2YWx1ZSB0byBhIHN0cmluZy4gIElmIHRoZSBgX3NlcmlhbGl6ZVZhbHVlYCBtZXRob2QgcmV0dXJucyBgdW5kZWZpbmVkYCwKICAgICAgICAgKiB0aGUgYXR0cmlidXRlIHdpbGwgYmUgcmVtb3ZlZCAodGhpcyBpcyB0aGUgZGVmYXVsdCBmb3IgYm9vbGVhbgogICAgICAgICAqIHR5cGUgYGZhbHNlYCkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0VsZW1lbnR9IG5vZGUgRWxlbWVudCB0byBzZXQgYXR0cmlidXRlIHRvLgogICAgICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVmFsdWUgdG8gc2VyaWFsaXplLgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBhdHRyaWJ1dGUgQXR0cmlidXRlIG5hbWUgdG8gc2VyaWFsaXplIHRvLgogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICovCiAgICAgICAgX3ZhbHVlVG9Ob2RlQXR0cmlidXRlKG5vZGUsIHZhbHVlLCBhdHRyaWJ1dGUpIHsKICAgICAgICAgIGNvbnN0IHN0ciA9IHRoaXMuX3NlcmlhbGl6ZVZhbHVlKHZhbHVlKTsKICAgICAgICAgIGlmIChzdHIgPT09IHVuZGVmaW5lZCkgewogICAgICAgICAgICBub2RlLnJlbW92ZUF0dHJpYnV0ZShhdHRyaWJ1dGUpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgbm9kZS5zZXRBdHRyaWJ1dGUoYXR0cmlidXRlLCBzdHIpOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydHMgYSB0eXBlZCBKYXZhU2NyaXB0IHZhbHVlIHRvIGEgc3RyaW5nLgogICAgICAgICAqCiAgICAgICAgICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIHdoZW4gc2V0dGluZyBKUyBwcm9wZXJ0eSB2YWx1ZXMgdG8KICAgICAgICAgKiBIVE1MIGF0dHJpYnV0ZXMuICBVc2VycyBtYXkgb3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gcHJvdmlkZQogICAgICAgICAqIHNlcmlhbGl6YXRpb24gZm9yIGN1c3RvbSB0eXBlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgUHJvcGVydHkgdmFsdWUgdG8gc2VyaWFsaXplLgogICAgICAgICAqIEByZXR1cm4ge3N0cmluZyB8IHVuZGVmaW5lZH0gU3RyaW5nIHNlcmlhbGl6ZWQgZnJvbSB0aGUgcHJvdmlkZWQKICAgICAgICAgKiBwcm9wZXJ0eSAgdmFsdWUuCiAgICAgICAgICovCiAgICAgICAgX3NlcmlhbGl6ZVZhbHVlKHZhbHVlKSB7CiAgICAgICAgICBzd2l0Y2ggKHR5cGVvZiB2YWx1ZSkgewogICAgICAgICAgICBjYXNlICdib29sZWFuJzoKICAgICAgICAgICAgICByZXR1cm4gdmFsdWUgPyAnJyA6IHVuZGVmaW5lZDsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICByZXR1cm4gdmFsdWUgIT0gbnVsbCA/IHZhbHVlLnRvU3RyaW5nKCkgOiB1bmRlZmluZWQ7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyBhIHN0cmluZyB0byBhIHR5cGVkIEphdmFTY3JpcHQgdmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgd2hlbiByZWFkaW5nIEhUTUwgYXR0cmlidXRlIHZhbHVlcyB0bwogICAgICAgICAqIEpTIHByb3BlcnRpZXMuICBVc2VycyBtYXkgb3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gcHJvdmlkZQogICAgICAgICAqIGRlc2VyaWFsaXphdGlvbiBmb3IgY3VzdG9tIGB0eXBlYHMuIFR5cGVzIGZvciBgQm9vbGVhbmAsIGBTdHJpbmdgLAogICAgICAgICAqIGFuZCBgTnVtYmVyYCBjb252ZXJ0IGF0dHJpYnV0ZXMgdG8gdGhlIGV4cGVjdGVkIHR5cGVzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHs/c3RyaW5nfSB2YWx1ZSBWYWx1ZSB0byBkZXNlcmlhbGl6ZS4KICAgICAgICAgKiBAcGFyYW0geyo9fSB0eXBlIFR5cGUgdG8gZGVzZXJpYWxpemUgdGhlIHN0cmluZyB0by4KICAgICAgICAgKiBAcmV0dXJuIHsqfSBUeXBlZCB2YWx1ZSBkZXNlcmlhbGl6ZWQgZnJvbSB0aGUgcHJvdmlkZWQgc3RyaW5nLgogICAgICAgICAqLwogICAgICAgIF9kZXNlcmlhbGl6ZVZhbHVlKHZhbHVlLCB0eXBlKSB7CiAgICAgICAgICBzd2l0Y2ggKHR5cGUpIHsKICAgICAgICAgICAgY2FzZSBCb29sZWFuOgogICAgICAgICAgICAgIHJldHVybiAodmFsdWUgIT09IG51bGwpOwogICAgICAgICAgICBjYXNlIE51bWJlcjoKICAgICAgICAgICAgICByZXR1cm4gTnVtYmVyKHZhbHVlKTsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgfQoKICAgICAgcmV0dXJuIFByb3BlcnRpZXNDaGFuZ2VkOwogICAgfSk7CgoKICB9KSgpOwoKPC9zY3JpcHQ+PHNjcmlwdD4KKGZ1bmN0aW9uKCkgewoKICAndXNlIHN0cmljdCc7CgogIGxldCBjYXNlTWFwID0gUG9seW1lci5DYXNlTWFwOwoKICAvLyBTYXZlIG1hcCBvZiBuYXRpdmUgcHJvcGVydGllczsgdGhpcyBmb3JtcyBhIGJsYWNrbGlzdCBvciBwcm9wZXJ0aWVzCiAgLy8gdGhhdCB3b24ndCBoYXZlIHRoZWlyIHZhbHVlcyAic2F2ZWQiIGJ5IGBzYXZlQWNjZXNzb3JWYWx1ZWAsIHNpbmNlCiAgLy8gcmVhZGluZyBmcm9tIGFuIEhUTUxFbGVtZW50IGFjY2Vzc29yIGZyb20gdGhlIGNvbnRleHQgb2YgYSBwcm90b3R5cGUgdGhyb3dzCiAgY29uc3QgbmF0aXZlUHJvcGVydGllcyA9IHt9OwogIGxldCBwcm90byA9IEhUTUxFbGVtZW50LnByb3RvdHlwZTsKICB3aGlsZSAocHJvdG8pIHsKICAgIGxldCBwcm9wcyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHByb3RvKTsKICAgIGZvciAobGV0IGk9MDsgaTxwcm9wcy5sZW5ndGg7IGkrKykgewogICAgICBuYXRpdmVQcm9wZXJ0aWVzW3Byb3BzW2ldXSA9IHRydWU7CiAgICB9CiAgICBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihwcm90byk7CiAgfQoKICAvKioKICAgKiBVc2VkIHRvIHNhdmUgdGhlIHZhbHVlIG9mIGEgcHJvcGVydHkgdGhhdCB3aWxsIGJlIG92ZXJyaWRkZW4gd2l0aAogICAqIGFuIGFjY2Vzc29yLiBJZiB0aGUgYG1vZGVsYCBpcyBhIHByb3RvdHlwZSwgdGhlIHZhbHVlcyB3aWxsIGJlIHNhdmVkCiAgICogaW4gYF9fZGF0YVByb3RvYCwgYW5kIGl0J3MgdXAgdG8gdGhlIHVzZXIgKG9yIGRvd25zdHJlYW0gbWl4aW4pIHRvCiAgICogZGVjaWRlIGhvdy93aGVuIHRvIHNldCB0aGVzZSB2YWx1ZXMgYmFjayBpbnRvIHRoZSBhY2Nlc3NvcnMuCiAgICogSWYgYG1vZGVsYCBpcyBhbHJlYWR5IGFuIGluc3RhbmNlIChpdCBoYXMgYSBgX19kYXRhYCBwcm9wZXJ0eSksIHRoZW4KICAgKiB0aGUgdmFsdWUgd2lsbCBiZSBzZXQgYXMgYSBwZW5kaW5nIHByb3BlcnR5LCBtZWFuaW5nIHRoZSB1c2VyIHNob3VsZAogICAqIGNhbGwgYF9pbnZhbGlkYXRlUHJvcGVydGllc2Agb3IgYF9mbHVzaFByb3BlcnRpZXNgIHRvIHRha2UgZWZmZWN0CiAgICoKICAgKiBAcGFyYW0ge09iamVjdH0gbW9kZWwgUHJvdG90eXBlIG9yIGluc3RhbmNlCiAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgcHJvcGVydHkKICAgKiBAcmV0dXJuIHt2b2lkfQogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gc2F2ZUFjY2Vzc29yVmFsdWUobW9kZWwsIHByb3BlcnR5KSB7CiAgICAvLyBEb24ndCByZWFkL3N0b3JlIHZhbHVlIGZvciBhbnkgbmF0aXZlIHByb3BlcnRpZXMgc2luY2UgdGhleSBjb3VsZCB0aHJvdwogICAgaWYgKCFuYXRpdmVQcm9wZXJ0aWVzW3Byb3BlcnR5XSkgewogICAgICBsZXQgdmFsdWUgPSBtb2RlbFtwcm9wZXJ0eV07CiAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgaWYgKG1vZGVsLl9fZGF0YSkgewogICAgICAgICAgLy8gQWRkaW5nIGFjY2Vzc29yIHRvIGluc3RhbmNlOyB1cGRhdGUgdGhlIHByb3BlcnR5CiAgICAgICAgICAvLyBJdCBpcyB0aGUgdXNlcidzIHJlc3BvbnNpYmlsaXR5IHRvIGNhbGwgX2ZsdXNoUHJvcGVydGllcwogICAgICAgICAgbW9kZWwuX3NldFBlbmRpbmdQcm9wZXJ0eShwcm9wZXJ0eSwgdmFsdWUpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAvLyBBZGRpbmcgYWNjZXNzb3IgdG8gcHJvdG87IHNhdmUgcHJvdG8ncyB2YWx1ZSBmb3IgaW5zdGFuY2UtdGltZSB1c2UKICAgICAgICAgIGlmICghbW9kZWwuX19kYXRhUHJvdG8pIHsKICAgICAgICAgICAgbW9kZWwuX19kYXRhUHJvdG8gPSB7fTsKICAgICAgICAgIH0gZWxzZSBpZiAoIW1vZGVsLmhhc093blByb3BlcnR5KEpTQ29tcGlsZXJfcmVuYW1lUHJvcGVydHkoJ19fZGF0YVByb3RvJywgbW9kZWwpKSkgewogICAgICAgICAgICBtb2RlbC5fX2RhdGFQcm90byA9IE9iamVjdC5jcmVhdGUobW9kZWwuX19kYXRhUHJvdG8pOwogICAgICAgICAgfQogICAgICAgICAgbW9kZWwuX19kYXRhUHJvdG9bcHJvcGVydHldID0gdmFsdWU7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfQoKICAvKioKICAgKiBFbGVtZW50IGNsYXNzIG1peGluIHRoYXQgcHJvdmlkZXMgYmFzaWMgbWV0YS1wcm9ncmFtbWluZyBmb3IgY3JlYXRpbmcgb25lCiAgICogb3IgbW9yZSBwcm9wZXJ0eSBhY2Nlc3NvcnMgKGdldHRlci9zZXR0ZXIgcGFpcikgdGhhdCBlbnF1ZXVlIGFuIGFzeW5jCiAgICogKGJhdGNoZWQpIGBfcHJvcGVydGllc0NoYW5nZWRgIGNhbGxiYWNrLgogICAqCiAgICogRm9yIGJhc2ljIHVzYWdlIG9mIHRoaXMgbWl4aW46CiAgICogCiAgICogLSAgIERlY2xhcmUgYXR0cmlidXRlcyB0byBvYnNlcnZlIHZpYSB0aGUgc3RhbmRhcmQgYHN0YXRpYyBnZXQgb2JzZXJ2ZWRBdHRyaWJ1dGVzKClgLiBVc2UKICAgKiAgICAgYGRhc2gtY2FzZWAgYXR0cmlidXRlIG5hbWVzIHRvIHJlcHJlc2VudCBgY2FtZWxDYXNlYCBwcm9wZXJ0eSBuYW1lcy4gCiAgICogLSAgIEltcGxlbWVudCB0aGUgYF9wcm9wZXJ0aWVzQ2hhbmdlZGAgY2FsbGJhY2sgb24gdGhlIGNsYXNzLgogICAqIC0gICBDYWxsIGBNeUNsYXNzLmNyZWF0ZVByb3BlcnRpZXNGb3JBdHRyaWJ1dGVzKClgICoqb25jZSoqIG9uIHRoZSBjbGFzcyB0byBnZW5lcmF0ZSAKICAgKiAgICAgcHJvcGVydHkgYWNjZXNzb3JzIGZvciBlYWNoIG9ic2VydmVkIGF0dHJpYnV0ZS4gVGhpcyBtdXN0IGJlIGNhbGxlZCBiZWZvcmUgdGhlIGZpcnN0IAogICAqICAgICBpbnN0YW5jZSBpcyBjcmVhdGVkLCBmb3IgZXhhbXBsZSwgYnkgY2FsbGluZyBpdCBiZWZvcmUgY2FsbGluZyBgY3VzdG9tRWxlbWVudHMuZGVmaW5lYC4KICAgKiAgICAgSXQgY2FuIGFsc28gYmUgY2FsbGVkIGxhemlseSBmcm9tIHRoZSBlbGVtZW50J3MgYGNvbnN0cnVjdG9yYCwgYXMgbG9uZyBhcyBpdCdzIGd1YXJkZWQgc28KICAgKiAgICAgdGhhdCB0aGUgY2FsbCBpcyBvbmx5IG1hZGUgb25jZSwgd2hlbiB0aGUgZmlyc3QgaW5zdGFuY2UgaXMgY3JlYXRlZC4KICAgKiAtICAgQ2FsbCBgdGhpcy5fZW5hYmxlUHJvcGVydGllcygpYCBpbiB0aGUgZWxlbWVudCdzIGBjb25uZWN0ZWRDYWxsYmFja2AgdG8gZW5hYmxlIAogICAqICAgICB0aGUgYWNjZXNzb3JzLgogICAqCiAgICogQW55IGBvYnNlcnZlZEF0dHJpYnV0ZXNgIHdpbGwgYXV0b21hdGljYWxseSBiZQogICAqIGRlc2VyaWFsaXplZCB2aWEgYGF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFja2AgYW5kIHNldCB0byB0aGUgYXNzb2NpYXRlZAogICAqIHByb3BlcnR5IHVzaW5nIGBkYXNoLWNhc2VgLXRvLWBjYW1lbENhc2VgIGNvbnZlbnRpb24uCiAgICoKICAgKiBAbWl4aW5GdW5jdGlvbgogICAqIEBwb2x5bWVyCiAgICogQGFwcGxpZXNNaXhpbiBQb2x5bWVyLlByb3BlcnRpZXNDaGFuZ2VkCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBFbGVtZW50IGNsYXNzIG1peGluIGZvciByZWFjdGluZyB0byBwcm9wZXJ0eSBjaGFuZ2VzIGZyb20KICAgKiAgIGdlbmVyYXRlZCBwcm9wZXJ0eSBhY2Nlc3NvcnMuCiAgICovCiAgUG9seW1lci5Qcm9wZXJ0eUFjY2Vzc29ycyA9IFBvbHltZXIuZGVkdXBpbmdNaXhpbihzdXBlckNsYXNzID0+IHsKCiAgICAvKioKICAgICAqIEBjb25zdHJ1Y3RvcgogICAgICogQGV4dGVuZHMge3N1cGVyQ2xhc3N9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9Qcm9wZXJ0aWVzQ2hhbmdlZH0KICAgICAqIEB1bnJlc3RyaWN0ZWQKICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgICBjb25zdCBiYXNlID0gUG9seW1lci5Qcm9wZXJ0aWVzQ2hhbmdlZChzdXBlckNsYXNzKTsKCiAgICAvKioKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAbWl4aW5DbGFzcwogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfUHJvcGVydHlBY2Nlc3NvcnN9CiAgICAgKiBAZXh0ZW5kcyB7YmFzZX0KICAgICAqIEB1bnJlc3RyaWN0ZWQKICAgICAqLwogICAgY2xhc3MgUHJvcGVydHlBY2Nlc3NvcnMgZXh0ZW5kcyBiYXNlIHsKCiAgICAgIC8qKgogICAgICAgKiBHZW5lcmF0ZXMgcHJvcGVydHkgYWNjZXNzb3JzIGZvciBhbGwgYXR0cmlidXRlcyBpbiB0aGUgc3RhbmRhcmQKICAgICAgICogc3RhdGljIGBvYnNlcnZlZEF0dHJpYnV0ZXNgIGFycmF5LgogICAgICAgKgogICAgICAgKiBBdHRyaWJ1dGUgbmFtZXMgYXJlIG1hcHBlZCB0byBwcm9wZXJ0eSBuYW1lcyB1c2luZyB0aGUgYGRhc2gtY2FzZWAgdG8KICAgICAgICogYGNhbWVsQ2FzZWAgY29udmVudGlvbgogICAgICAgKgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgc3RhdGljIGNyZWF0ZVByb3BlcnRpZXNGb3JBdHRyaWJ1dGVzKCkgewogICAgICAgIGxldCBhJCA9IHRoaXMub2JzZXJ2ZWRBdHRyaWJ1dGVzOwogICAgICAgIGZvciAobGV0IGk9MDsgaSA8IGEkLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICB0aGlzLnByb3RvdHlwZS5fY3JlYXRlUHJvcGVydHlBY2Nlc3NvcihjYXNlTWFwLmRhc2hUb0NhbWVsQ2FzZShhJFtpXSkpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgYW4gYXR0cmlidXRlIG5hbWUgdGhhdCBjb3JyZXNwb25kcyB0byB0aGUgZ2l2ZW4gcHJvcGVydHkuCiAgICAgICAqIEJ5IGRlZmF1bHQsIGNvbnZlcnRzIGNhbWVsIHRvIGRhc2ggY2FzZSwgZS5nLiBgZm9vQmFyYCB0byBgZm9vLWJhcmAuCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSB0byBjb252ZXJ0CiAgICAgICAqIEByZXR1cm4ge3N0cmluZ30gQXR0cmlidXRlIG5hbWUgY29ycmVzcG9uZGluZyB0byB0aGUgZ2l2ZW4gcHJvcGVydHkuCiAgICAgICAqCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIHN0YXRpYyBhdHRyaWJ1dGVOYW1lRm9yUHJvcGVydHkocHJvcGVydHkpIHsKICAgICAgICByZXR1cm4gY2FzZU1hcC5jYW1lbFRvRGFzaENhc2UocHJvcGVydHkpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGVzIFByb3BlcnRpZXNDaGFuZ2VkIGltcGxlbWVudGF0aW9uIHRvIGluaXRpYWxpemUgdmFsdWVzIGZvcgogICAgICAgKiBhY2Nlc3NvcnMgY3JlYXRlZCBmb3IgdmFsdWVzIHRoYXQgYWxyZWFkeSBleGlzdGVkIG9uIHRoZSBlbGVtZW50CiAgICAgICAqIHByb3RvdHlwZS4KICAgICAgICoKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX2luaXRpYWxpemVQcm9wZXJ0aWVzKCkgewogICAgICAgIGlmICh0aGlzLl9fZGF0YVByb3RvKSB7CiAgICAgICAgICB0aGlzLl9pbml0aWFsaXplUHJvdG9Qcm9wZXJ0aWVzKHRoaXMuX19kYXRhUHJvdG8pOwogICAgICAgICAgdGhpcy5fX2RhdGFQcm90byA9IG51bGw7CiAgICAgICAgfQogICAgICAgIHN1cGVyLl9pbml0aWFsaXplUHJvcGVydGllcygpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ2FsbGVkIGF0IGluc3RhbmNlIHRpbWUgd2l0aCBiYWcgb2YgcHJvcGVydGllcyB0aGF0IHdlcmUgb3ZlcndyaXR0ZW4KICAgICAgICogYnkgYWNjZXNzb3JzIG9uIHRoZSBwcm90b3R5cGUgd2hlbiBhY2Nlc3NvcnMgd2VyZSBjcmVhdGVkLgogICAgICAgKgogICAgICAgKiBUaGUgZGVmYXVsdCBpbXBsZW1lbnRhdGlvbiBzZXRzIHRoZXNlIHByb3BlcnRpZXMgYmFjayBpbnRvIHRoZQogICAgICAgKiBzZXR0ZXIgYXQgaW5zdGFuY2UgdGltZS4gIFRoaXMgbWV0aG9kIGlzIHByb3ZpZGVkIGFzIGFuIG92ZXJyaWRlCiAgICAgICAqIHBvaW50IGZvciBjdXN0b21pemluZyBvciBwcm92aWRpbmcgbW9yZSBlZmZpY2llbnQgaW5pdGlhbGl6YXRpb24uCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwcm9wcyBCYWcgb2YgcHJvcGVydHkgdmFsdWVzIHRoYXQgd2VyZSBvdmVyd3JpdHRlbgogICAgICAgKiAgIHdoZW4gY3JlYXRpbmcgcHJvcGVydHkgYWNjZXNzb3JzLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBfaW5pdGlhbGl6ZVByb3RvUHJvcGVydGllcyhwcm9wcykgewogICAgICAgIGZvciAobGV0IHAgaW4gcHJvcHMpIHsKICAgICAgICAgIHRoaXMuX3NldFByb3BlcnR5KHAsIHByb3BzW3BdKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBFbnN1cmVzIHRoZSBlbGVtZW50IGhhcyB0aGUgZ2l2ZW4gYXR0cmlidXRlLiBJZiBpdCBkb2VzIG5vdCwKICAgICAgICogYXNzaWducyB0aGUgZ2l2ZW4gdmFsdWUgdG8gdGhlIGF0dHJpYnV0ZS4KICAgICAgICoKICAgICAgICogQHN1cHByZXNzIHtpbnZhbGlkQ2FzdHN9IENsb3N1cmUgY2FuJ3QgZmlndXJlIG91dCBgdGhpc2AgaXMgaW5mYWN0IGFuIGVsZW1lbnQKICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGF0dHJpYnV0ZSBOYW1lIG9mIGF0dHJpYnV0ZSB0byBlbnN1cmUgaXMgc2V0LgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgb2YgdGhlIGF0dHJpYnV0ZS4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9lbnN1cmVBdHRyaWJ1dGUoYXR0cmlidXRlLCB2YWx1ZSkgewogICAgICAgIGNvbnN0IGVsID0gLyoqIEB0eXBlIHshSFRNTEVsZW1lbnR9ICovKHRoaXMpOwogICAgICAgIGlmICghZWwuaGFzQXR0cmlidXRlKGF0dHJpYnV0ZSkpIHsKICAgICAgICAgIHRoaXMuX3ZhbHVlVG9Ob2RlQXR0cmlidXRlKGVsLCB2YWx1ZSwgYXR0cmlidXRlKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZXMgUHJvcGVydGllc0NoYW5nZWQgaW1wbGVtZW50aW9uIHRvIHNlcmlhbGl6ZSBvYmplY3RzIGFzIEpTT04uCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgUHJvcGVydHkgdmFsdWUgdG8gc2VyaWFsaXplLgogICAgICAgKiBAcmV0dXJuIHtzdHJpbmcgfCB1bmRlZmluZWR9IFN0cmluZyBzZXJpYWxpemVkIGZyb20gdGhlIHByb3ZpZGVkIHByb3BlcnR5IHZhbHVlLgogICAgICAgKi8KICAgICAgX3NlcmlhbGl6ZVZhbHVlKHZhbHVlKSB7CiAgICAgICAgLyogZXNsaW50LWRpc2FibGUgbm8tZmFsbHRocm91Z2ggKi8KICAgICAgICBzd2l0Y2ggKHR5cGVvZiB2YWx1ZSkgewogICAgICAgICAgY2FzZSAnb2JqZWN0JzoKICAgICAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgRGF0ZSkgewogICAgICAgICAgICAgIHJldHVybiB2YWx1ZS50b1N0cmluZygpOwogICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlKSB7CiAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7CiAgICAgICAgICAgICAgfSBjYXRjaCh4KSB7CiAgICAgICAgICAgICAgICByZXR1cm4gJyc7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgcmV0dXJuIHN1cGVyLl9zZXJpYWxpemVWYWx1ZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogQ29udmVydHMgYSBzdHJpbmcgdG8gYSB0eXBlZCBKYXZhU2NyaXB0IHZhbHVlLgogICAgICAgKgogICAgICAgKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgYnkgUG9seW1lciB3aGVuIHJlYWRpbmcgSFRNTCBhdHRyaWJ1dGUgdmFsdWVzIHRvCiAgICAgICAqIEpTIHByb3BlcnRpZXMuICBVc2VycyBtYXkgb3ZlcnJpZGUgdGhpcyBtZXRob2Qgb24gUG9seW1lciBlbGVtZW50CiAgICAgICAqIHByb3RvdHlwZXMgdG8gcHJvdmlkZSBkZXNlcmlhbGl6YXRpb24gZm9yIGN1c3RvbSBgdHlwZWBzLiAgTm90ZSwKICAgICAgICogdGhlIGB0eXBlYCBhcmd1bWVudCBpcyB0aGUgdmFsdWUgb2YgdGhlIGB0eXBlYCBmaWVsZCBwcm92aWRlZCBpbiB0aGUKICAgICAgICogYHByb3BlcnRpZXNgIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciBhIGdpdmVuIHByb3BlcnR5LCBhbmQgaXMKICAgICAgICogYnkgY29udmVudGlvbiB0aGUgY29uc3RydWN0b3IgZm9yIHRoZSB0eXBlIHRvIGRlc2VyaWFsaXplLgogICAgICAgKgogICAgICAgKgogICAgICAgKiBAcGFyYW0gez9zdHJpbmd9IHZhbHVlIEF0dHJpYnV0ZSB2YWx1ZSB0byBkZXNlcmlhbGl6ZS4KICAgICAgICogQHBhcmFtIHsqPX0gdHlwZSBUeXBlIHRvIGRlc2VyaWFsaXplIHRoZSBzdHJpbmcgdG8uCiAgICAgICAqIEByZXR1cm4geyp9IFR5cGVkIHZhbHVlIGRlc2VyaWFsaXplZCBmcm9tIHRoZSBwcm92aWRlZCBzdHJpbmcuCiAgICAgICAqLwogICAgICBfZGVzZXJpYWxpemVWYWx1ZSh2YWx1ZSwgdHlwZSkgewogICAgICAgIC8qKgogICAgICAgICAqIEB0eXBlIHsqfQogICAgICAgICAqLwogICAgICAgIGxldCBvdXRWYWx1ZTsKICAgICAgICBzd2l0Y2ggKHR5cGUpIHsKICAgICAgICAgIGNhc2UgT2JqZWN0OgogICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgIG91dFZhbHVlID0gSlNPTi5wYXJzZSgvKiogQHR5cGUge3N0cmluZ30gKi8odmFsdWUpKTsKICAgICAgICAgICAgfSBjYXRjaCh4KSB7CiAgICAgICAgICAgICAgLy8gYWxsb3cgbm9uLUpTT04gbGl0ZXJhbHMgbGlrZSBTdHJpbmdzIGFuZCBOdW1iZXJzCiAgICAgICAgICAgICAgb3V0VmFsdWUgPSB2YWx1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgQXJyYXk6CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgb3V0VmFsdWUgPSBKU09OLnBhcnNlKC8qKiBAdHlwZSB7c3RyaW5nfSAqLyh2YWx1ZSkpOwogICAgICAgICAgICB9IGNhdGNoKHgpIHsKICAgICAgICAgICAgICBvdXRWYWx1ZSA9IG51bGw7CiAgICAgICAgICAgICAgY29uc29sZS53YXJuKGBQb2x5bWVyOjpBdHRyaWJ1dGVzOiBjb3VsZG4ndCBkZWNvZGUgQXJyYXkgYXMgSlNPTjogJHt2YWx1ZX1gKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgRGF0ZToKICAgICAgICAgICAgb3V0VmFsdWUgPSBpc05hTih2YWx1ZSkgPyBTdHJpbmcodmFsdWUpIDogTnVtYmVyKHZhbHVlKTsKICAgICAgICAgICAgb3V0VmFsdWUgPSBuZXcgRGF0ZShvdXRWYWx1ZSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgb3V0VmFsdWUgPSBzdXBlci5fZGVzZXJpYWxpemVWYWx1ZSh2YWx1ZSwgdHlwZSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICByZXR1cm4gb3V0VmFsdWU7CiAgICAgIH0KICAgICAgLyogZXNsaW50LWVuYWJsZSBuby1mYWxsdGhyb3VnaCAqLwoKICAgICAgLyoqCiAgICAgICAqIE92ZXJyaWRlcyBQcm9wZXJ0aWVzQ2hhbmdlZCBpbXBsZW1lbnRhdGlvbiB0byBzYXZlIGV4aXN0aW5nIHByb3RvdHlwZQogICAgICAgKiBwcm9wZXJ0eSB2YWx1ZSBzbyB0aGF0IGl0IGNhbiBiZSByZXNldC4KICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgdGhlIHByb3BlcnR5CiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbj19IHJlYWRPbmx5IFdoZW4gdHJ1ZSwgbm8gc2V0dGVyIGlzIGNyZWF0ZWQKICAgICAgICoKICAgICAgICogV2hlbiBjYWxsaW5nIG9uIGEgcHJvdG90eXBlLCBhbnkgb3ZlcndyaXR0ZW4gdmFsdWVzIGFyZSBzYXZlZCBpbgogICAgICAgKiBgX19kYXRhUHJvdG9gLCBhbmQgaXQgaXMgdXAgdG8gdGhlIHN1YmNsYXNzZXIgdG8gZGVjaWRlIGhvdy93aGVuCiAgICAgICAqIHRvIHNldCB0aG9zZSBwcm9wZXJ0aWVzIGJhY2sgaW50byB0aGUgYWNjZXNzb3IuICBXaGVuIGNhbGxpbmcgb24gYW4KICAgICAgICogaW5zdGFuY2UsIHRoZSBvdmVyd3JpdHRlbiB2YWx1ZSBpcyBzZXQgdmlhIGBfc2V0UGVuZGluZ1Byb3BlcnR5YCwKICAgICAgICogYW5kIHRoZSB1c2VyIHNob3VsZCBjYWxsIGBfaW52YWxpZGF0ZVByb3BlcnRpZXNgIG9yIGBfZmx1c2hQcm9wZXJ0aWVzYAogICAgICAgKiBmb3IgdGhlIHZhbHVlcyB0byB0YWtlIGVmZmVjdC4KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX2RlZmluZVByb3BlcnR5QWNjZXNzb3IocHJvcGVydHksIHJlYWRPbmx5KSB7CiAgICAgICAgc2F2ZUFjY2Vzc29yVmFsdWUodGhpcywgcHJvcGVydHkpOwogICAgICAgIHN1cGVyLl9kZWZpbmVQcm9wZXJ0eUFjY2Vzc29yKHByb3BlcnR5LCByZWFkT25seSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBsaWJyYXJ5IGNyZWF0ZWQgYW4gYWNjZXNzb3IgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBhbiBhY2Nlc3NvciB3YXMgY3JlYXRlZAogICAgICAgKi8KICAgICAgX2hhc0FjY2Vzc29yKHByb3BlcnR5KSB7CiAgICAgICAgcmV0dXJuIHRoaXMuX19kYXRhSGFzQWNjZXNzb3IgJiYgdGhpcy5fX2RhdGFIYXNBY2Nlc3Nvcltwcm9wZXJ0eV07CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIHNwZWNpZmllZCBwcm9wZXJ0eSBoYXMgYSBwZW5kaW5nIGNoYW5nZS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3AgUHJvcGVydHkgbmFtZQogICAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHByb3BlcnR5IGhhcyBhIHBlbmRpbmcgY2hhbmdlCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9pc1Byb3BlcnR5UGVuZGluZyhwcm9wKSB7CiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGhpcy5fX2RhdGFQZW5kaW5nICYmIChwcm9wIGluIHRoaXMuX19kYXRhUGVuZGluZykpOwogICAgICB9CgogICAgfQoKICAgIHJldHVybiBQcm9wZXJ0eUFjY2Vzc29yczsKCiAgfSk7Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CgogICd1c2Ugc3RyaWN0JzsKCiAgY29uc3Qgd2Fsa2VyID0gZG9jdW1lbnQuY3JlYXRlVHJlZVdhbGtlcihkb2N1bWVudCwgTm9kZUZpbHRlci5TSE9XX0FMTCwKICAgICAgbnVsbCwgZmFsc2UpOwoKICAvLyAxLnggYmFja3dhcmRzLWNvbXBhdGlibGUgYXV0by13cmFwcGVyIGZvciB0ZW1wbGF0ZSB0eXBlIGV4dGVuc2lvbnMKICAvLyBUaGlzIGlzIGEgY2xlYXIgbGF5ZXJpbmcgdmlvbGF0aW9uIGFuZCBnaXZlcyBmYXZvcmVkLW5hdGlvbiBzdGF0dXMgdG8KICAvLyBkb20taWYgYW5kIGRvbS1yZXBlYXQgdGVtcGxhdGVzLiAgVGhpcyBpcyBhIGNvbmNlaXQgd2UncmUgY2hvb3NpbmcgdG8ga2VlcAogIC8vIGEuKSB0byBlYXNlIDEueCBiYWNrd2FyZHMtY29tcGF0aWJpbGl0eSBkdWUgdG8gbG9zcyBvZiBgaXNgLCBhbmQKICAvLyBiLikgdG8gbWFpbnRhaW4gaWYvcmVwZWF0IGNhcGFiaWxpdHkgaW4gcGFyc2VyLWNvbnN0cmFpbmVkIGVsZW1lbnRzCiAgLy8gICAgIChlLmcuIHRhYmxlLCBzZWxlY3QpIGluIGxpZXUgb2YgbmF0aXZlIENFIHR5cGUgZXh0ZW5zaW9ucyB3aXRob3V0CiAgLy8gICAgIG1hc3NpdmUgbmV3IGludmVudGlvbiBpbiB0aGlzIHNwYWNlIChlLmcuIGRpcmVjdGl2ZSBzeXN0ZW0pCiAgY29uc3QgdGVtcGxhdGVFeHRlbnNpb25zID0gewogICAgJ2RvbS1pZic6IHRydWUsCiAgICAnZG9tLXJlcGVhdCc6IHRydWUKICB9OwogIGZ1bmN0aW9uIHdyYXBUZW1wbGF0ZUV4dGVuc2lvbihub2RlKSB7CiAgICBsZXQgaXMgPSBub2RlLmdldEF0dHJpYnV0ZSgnaXMnKTsKICAgIGlmIChpcyAmJiB0ZW1wbGF0ZUV4dGVuc2lvbnNbaXNdKSB7CiAgICAgIGxldCB0ID0gbm9kZTsKICAgICAgdC5yZW1vdmVBdHRyaWJ1dGUoJ2lzJyk7CiAgICAgIG5vZGUgPSB0Lm93bmVyRG9jdW1lbnQuY3JlYXRlRWxlbWVudChpcyk7CiAgICAgIHQucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobm9kZSwgdCk7CiAgICAgIG5vZGUuYXBwZW5kQ2hpbGQodCk7CiAgICAgIHdoaWxlKHQuYXR0cmlidXRlcy5sZW5ndGgpIHsKICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSh0LmF0dHJpYnV0ZXNbMF0ubmFtZSwgdC5hdHRyaWJ1dGVzWzBdLnZhbHVlKTsKICAgICAgICB0LnJlbW92ZUF0dHJpYnV0ZSh0LmF0dHJpYnV0ZXNbMF0ubmFtZSk7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBub2RlOwogIH0KCiAgZnVuY3Rpb24gZmluZFRlbXBsYXRlTm9kZShyb290LCBub2RlSW5mbykgewogICAgLy8gcmVjdXJzaXZlbHkgYXNjZW5kIHRyZWUgdW50aWwgd2UgaGl0IHJvb3QKICAgIGxldCBwYXJlbnQgPSBub2RlSW5mby5wYXJlbnRJbmZvICYmIGZpbmRUZW1wbGF0ZU5vZGUocm9vdCwgbm9kZUluZm8ucGFyZW50SW5mbyk7CiAgICAvLyB1bndpbmQgdGhlIHN0YWNrLCByZXR1cm5pbmcgdGhlIGluZGV4ZWQgbm9kZSBhdCBlYWNoIGxldmVsCiAgICBpZiAocGFyZW50KSB7CiAgICAgIC8vIG5vdGU6IG1hcmdpbmFsbHkgZmFzdGVyIHRoYW4gaW5kZXhpbmcgdmlhIGNoaWxkTm9kZXMKICAgICAgLy8gKGh0dHA6Ly9qc3BlcmYuY29tL2NoaWxkbm9kZXMtbG9va3VwKQogICAgICB3YWxrZXIuY3VycmVudE5vZGUgPSBwYXJlbnQ7CiAgICAgIGZvciAobGV0IG49d2Fsa2VyLmZpcnN0Q2hpbGQoKSwgaT0wOyBuOyBuPXdhbGtlci5uZXh0U2libGluZygpKSB7CiAgICAgICAgaWYgKG5vZGVJbmZvLnBhcmVudEluZGV4ID09PSBpKyspIHsKICAgICAgICAgIHJldHVybiBuOwogICAgICAgIH0KICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuIHJvb3Q7CiAgICB9CiAgfQoKICAvLyBjb25zdHJ1Y3QgYCRgIG1hcCAoZnJvbSBpZCBhbm5vdGF0aW9ucykKICBmdW5jdGlvbiBhcHBseUlkVG9NYXAoaW5zdCwgbWFwLCBub2RlLCBub2RlSW5mbykgewogICAgaWYgKG5vZGVJbmZvLmlkKSB7CiAgICAgIG1hcFtub2RlSW5mby5pZF0gPSBub2RlOwogICAgfQogIH0KCiAgLy8gaW5zdGFsbCBldmVudCBsaXN0ZW5lcnMgKGZyb20gZXZlbnQgYW5ub3RhdGlvbnMpCiAgZnVuY3Rpb24gYXBwbHlFdmVudExpc3RlbmVyKGluc3QsIG5vZGUsIG5vZGVJbmZvKSB7CiAgICBpZiAobm9kZUluZm8uZXZlbnRzICYmIG5vZGVJbmZvLmV2ZW50cy5sZW5ndGgpIHsKICAgICAgZm9yIChsZXQgaj0wLCBlJD1ub2RlSW5mby5ldmVudHMsIGU7IChqPGUkLmxlbmd0aCkgJiYgKGU9ZSRbal0pOyBqKyspIHsKICAgICAgICBpbnN0Ll9hZGRNZXRob2RFdmVudExpc3RlbmVyVG9Ob2RlKG5vZGUsIGUubmFtZSwgZS52YWx1ZSwgaW5zdCk7CiAgICAgIH0KICAgIH0KICB9CgogIC8vIHB1c2ggY29uZmlndXJhdGlvbiByZWZlcmVuY2VzIGF0IGNvbmZpZ3VyZSB0aW1lCiAgZnVuY3Rpb24gYXBwbHlUZW1wbGF0ZUNvbnRlbnQoaW5zdCwgbm9kZSwgbm9kZUluZm8pIHsKICAgIGlmIChub2RlSW5mby50ZW1wbGF0ZUluZm8pIHsKICAgICAgbm9kZS5fdGVtcGxhdGVJbmZvID0gbm9kZUluZm8udGVtcGxhdGVJbmZvOwogICAgfQogIH0KCiAgZnVuY3Rpb24gY3JlYXRlTm9kZUV2ZW50SGFuZGxlcihjb250ZXh0LCBldmVudE5hbWUsIG1ldGhvZE5hbWUpIHsKICAgIC8vIEluc3RhbmNlcyBjYW4gb3B0aW9uYWxseSBoYXZlIGEgX21ldGhvZEhvc3Qgd2hpY2ggYWxsb3dzIHJlZGlyZWN0aW5nIHdoZXJlCiAgICAvLyB0byBmaW5kIG1ldGhvZHMuIEN1cnJlbnRseSB1c2VkIGJ5IGB0ZW1wbGF0aXplYC4KICAgIGNvbnRleHQgPSBjb250ZXh0Ll9tZXRob2RIb3N0IHx8IGNvbnRleHQ7CiAgICBsZXQgaGFuZGxlciA9IGZ1bmN0aW9uKGUpIHsKICAgICAgaWYgKGNvbnRleHRbbWV0aG9kTmFtZV0pIHsKICAgICAgICBjb250ZXh0W21ldGhvZE5hbWVdKGUsIGUuZGV0YWlsKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBjb25zb2xlLndhcm4oJ2xpc3RlbmVyIG1ldGhvZCBgJyArIG1ldGhvZE5hbWUgKyAnYCBub3QgZGVmaW5lZCcpOwogICAgICB9CiAgICB9OwogICAgcmV0dXJuIGhhbmRsZXI7CiAgfQoKICAvKioKICAgKiBFbGVtZW50IG1peGluIHRoYXQgcHJvdmlkZXMgYmFzaWMgdGVtcGxhdGUgcGFyc2luZyBhbmQgc3RhbXBpbmcsIGluY2x1ZGluZwogICAqIHRoZSBmb2xsb3dpbmcgdGVtcGxhdGUtcmVsYXRlZCBmZWF0dXJlcyBmb3Igc3RhbXBlZCB0ZW1wbGF0ZXM6CiAgICoKICAgKiAtIERlY2xhcmF0aXZlIGV2ZW50IGxpc3RlbmVycyAoYG9uLWV2ZW50bmFtZT0ibGlzdGVuZXIiYCkKICAgKiAtIE1hcCBvZiBub2RlIGlkJ3MgdG8gc3RhbXBlZCBub2RlIGluc3RhbmNlcyAoYHRoaXMuJC5pZGApCiAgICogLSBOZXN0ZWQgdGVtcGxhdGUgY29udGVudCBjYWNoaW5nL3JlbW92YWwgYW5kIHJlLWluc3RhbGxhdGlvbiAocGVyZm9ybWFuY2UKICAgKiAgIG9wdGltaXphdGlvbikKICAgKgogICAqIEBtaXhpbkZ1bmN0aW9uCiAgICogQHBvbHltZXIKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBzdW1tYXJ5IEVsZW1lbnQgY2xhc3MgbWl4aW4gdGhhdCBwcm92aWRlcyBiYXNpYyB0ZW1wbGF0ZSBwYXJzaW5nIGFuZCBzdGFtcGluZwogICAqLwogIFBvbHltZXIuVGVtcGxhdGVTdGFtcCA9IFBvbHltZXIuZGVkdXBpbmdNaXhpbihzdXBlckNsYXNzID0+IHsKCiAgICAvKioKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAbWl4aW5DbGFzcwogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfVGVtcGxhdGVTdGFtcH0KICAgICAqLwogICAgY2xhc3MgVGVtcGxhdGVTdGFtcCBleHRlbmRzIHN1cGVyQ2xhc3MgewoKICAgICAgLyoqCiAgICAgICAqIFNjYW5zIGEgdGVtcGxhdGUgdG8gcHJvZHVjZSB0ZW1wbGF0ZSBtZXRhZGF0YS4KICAgICAgICoKICAgICAgICogVGVtcGxhdGUtc3BlY2lmaWMgbWV0YWRhdGEgYXJlIHN0b3JlZCBpbiB0aGUgb2JqZWN0IHJldHVybmVkLCBhbmQgbm9kZS0KICAgICAgICogc3BlY2lmaWMgbWV0YWRhdGEgYXJlIHN0b3JlZCBpbiBvYmplY3RzIGluIGl0cyBmbGF0dGVuZWQgYG5vZGVJbmZvTGlzdGAKICAgICAgICogYXJyYXkuICBPbmx5IG5vZGVzIGluIHRoZSB0ZW1wbGF0ZSB0aGF0IHdlcmUgcGFyc2VkIGFzIG5vZGVzIG9mCiAgICAgICAqIGludGVyZXN0IGNvbnRhaW4gYW4gb2JqZWN0IGluIGBub2RlSW5mb0xpc3RgLiAgRWFjaCBgbm9kZUluZm9gIG9iamVjdAogICAgICAgKiBjb250YWlucyBhbiBgaW5kZXhgIChgY2hpbGROb2Rlc2AgaW5kZXggaW4gcGFyZW50KSBhbmQgb3B0aW9uYWxseQogICAgICAgKiBgcGFyZW50YCwgd2hpY2ggcG9pbnRzIHRvIG5vZGUgaW5mbyBvZiBpdHMgcGFyZW50IChpbmNsdWRpbmcgaXRzIGluZGV4KS4KICAgICAgICoKICAgICAgICogVGhlIHRlbXBsYXRlIG1ldGFkYXRhIG9iamVjdCByZXR1cm5lZCBmcm9tIHRoaXMgbWV0aG9kIGhhcyB0aGUgZm9sbG93aW5nCiAgICAgICAqIHN0cnVjdHVyZSAobWFueSBmaWVsZHMgb3B0aW9uYWwpOgogICAgICAgKgogICAgICAgKiBgYGBqcwogICAgICAgKiAgIHsKICAgICAgICogICAgIC8vIEZsYXR0ZW5lZCBsaXN0IG9mIG5vZGUgbWV0YWRhdGEgKGZvciBub2RlcyB0aGF0IGdlbmVyYXRlZCBtZXRhZGF0YSkKICAgICAgICogICAgIG5vZGVJbmZvTGlzdDogWwogICAgICAgKiAgICAgICB7CiAgICAgICAqICAgICAgICAgLy8gYGlkYCBhdHRyaWJ1dGUgZm9yIGFueSBub2RlcyB3aXRoIGlkJ3MgZm9yIGdlbmVyYXRpbmcgYCRgIG1hcAogICAgICAgKiAgICAgICAgIGlkOiB7c3RyaW5nfSwKICAgICAgICogICAgICAgICAvLyBgb24tZXZlbnQ9ImhhbmRsZXIiYCBtZXRhZGF0YQogICAgICAgKiAgICAgICAgIGV2ZW50czogWwogICAgICAgKiAgICAgICAgICAgewogICAgICAgKiAgICAgICAgICAgICBuYW1lOiB7c3RyaW5nfSwgICAvLyBldmVudCBuYW1lCiAgICAgICAqICAgICAgICAgICAgIHZhbHVlOiB7c3RyaW5nfSwgIC8vIGhhbmRsZXIgbWV0aG9kIG5hbWUKICAgICAgICogICAgICAgICAgIH0sIC4uLgogICAgICAgKiAgICAgICAgIF0sCiAgICAgICAqICAgICAgICAgLy8gTm90ZXMgd2hlbiB0aGUgdGVtcGxhdGUgY29udGFpbmVkIGEgYDxzbG90PmAgZm9yIHNoYWR5IERPTQogICAgICAgKiAgICAgICAgIC8vIG9wdGltaXphdGlvbiBwdXJwb3NlcwogICAgICAgKiAgICAgICAgIGhhc0luc2VydGlvblBvaW50OiB7Ym9vbGVhbn0sCiAgICAgICAqICAgICAgICAgLy8gRm9yIG5lc3RlZCBgPHRlbXBsYXRlPmBgIG5vZGVzLCBuZXN0ZWQgdGVtcGxhdGUgbWV0YWRhdGEKICAgICAgICogICAgICAgICB0ZW1wbGF0ZUluZm86IHtvYmplY3R9LCAvLyBuZXN0ZWQgdGVtcGxhdGUgbWV0YWRhdGEKICAgICAgICogICAgICAgICAvLyBNZXRhZGF0YSB0byBhbGxvdyBlZmZpY2llbnQgcmV0cmlldmFsIG9mIGluc3RhbmNlZCBub2RlCiAgICAgICAqICAgICAgICAgLy8gY29ycmVzcG9uZGluZyB0byB0aGlzIG1ldGFkYXRhCiAgICAgICAqICAgICAgICAgcGFyZW50SW5mbzoge251bWJlcn0sICAgLy8gcmVmZXJlbmNlIHRvIHBhcmVudCBub2RlSW5mbz4KICAgICAgICogICAgICAgICBwYXJlbnRJbmRleDoge251bWJlcn0sICAvLyBpbmRleCBpbiBwYXJlbnQncyBgY2hpbGROb2Rlc2AgY29sbGVjdGlvbgogICAgICAgKiAgICAgICAgIGluZm9JbmRleDoge251bWJlcn0sICAgIC8vIGluZGV4IG9mIHRoaXMgYG5vZGVJbmZvYCBpbiBgdGVtcGxhdGVJbmZvLm5vZGVJbmZvTGlzdGAKICAgICAgICogICAgICAgfSwKICAgICAgICogICAgICAgLi4uCiAgICAgICAqICAgICBdLAogICAgICAgKiAgICAgLy8gV2hlbiB0cnVlLCB0aGUgdGVtcGxhdGUgaGFkIHRoZSBgc3RyaXAtd2hpdGVzcGFjZWAgYXR0cmlidXRlCiAgICAgICAqICAgICAvLyBvciB3YXMgbmVzdGVkIGluIGEgdGVtcGxhdGUgd2l0aCB0aGF0IHNldHRpbmcKICAgICAgICogICAgIHN0cmlwV2hpdGVzcGFjZToge2Jvb2xlYW59LAogICAgICAgKiAgICAgLy8gRm9yIG5lc3RlZCB0ZW1wbGF0ZXMsIG5lc3RlZCB0ZW1wbGF0ZSBjb250ZW50IGlzIG1vdmVkIGludG8KICAgICAgICogICAgIC8vIGEgZG9jdW1lbnQgZnJhZ21lbnQgc3RvcmVkIGhlcmU7IHRoaXMgaXMgYW4gb3B0aW1pemF0aW9uIHRvCiAgICAgICAqICAgICAvLyBhdm9pZCB0aGUgY29zdCBvZiBuZXN0ZWQgdGVtcGxhdGUgY2xvbmluZwogICAgICAgKiAgICAgY29udGVudDoge0RvY3VtZW50RnJhZ21lbnR9CiAgICAgICAqICAgfQogICAgICAgKiBgYGAKICAgICAgICoKICAgICAgICogVGhpcyBtZXRob2Qga2lja3Mgb2ZmIGEgcmVjdXJzaXZlIHRyZWV3YWxrIGFzIGZvbGxvd3M6CiAgICAgICAqCiAgICAgICAqIGBgYAogICAgICAgKiAgICBfcGFyc2VUZW1wbGF0ZSA8LS0tLS0tLS0tLS0tLS0tLS0tLS0tKwogICAgICAgKiAgICAgIF9wYXJzZVRlbXBsYXRlQ29udGVudCAgICAgICAgICAgICAgfAogICAgICAgKiAgICAgICAgX3BhcnNlVGVtcGxhdGVOb2RlICA8LS0tLS0tLS0tLS0tfC0tKwogICAgICAgKiAgICAgICAgICBfcGFyc2VUZW1wbGF0ZU5lc3RlZFRlbXBsYXRlIC0tKyAgfAogICAgICAgKiAgICAgICAgICBfcGFyc2VUZW1wbGF0ZUNoaWxkTm9kZXMgLS0tLS0tLS0tKwogICAgICAgKiAgICAgICAgICBfcGFyc2VUZW1wbGF0ZU5vZGVBdHRyaWJ1dGVzCiAgICAgICAqICAgICAgICAgICAgX3BhcnNlVGVtcGxhdGVOb2RlQXR0cmlidXRlCiAgICAgICAqCiAgICAgICAqIGBgYAogICAgICAgKgogICAgICAgKiBUaGVzZSBtZXRob2RzIG1heSBiZSBvdmVycmlkZGVuIHRvIGFkZCBjdXN0b20gbWV0YWRhdGEgYWJvdXQgdGVtcGxhdGVzCiAgICAgICAqIHRvIGVpdGhlciBgdGVtcGxhdGVJbmZvYCBvciBgbm9kZUluZm9gLgogICAgICAgKgogICAgICAgKiBOb3RlIHRoYXQgdGhpcyBtZXRob2QgbWF5IGJlIGRlc3RydWN0aXZlIHRvIHRoZSB0ZW1wbGF0ZSwgaW4gdGhhdAogICAgICAgKiBlLmcuIGV2ZW50IGFubm90YXRpb25zIG1heSBiZSByZW1vdmVkIGFmdGVyIGJlaW5nIG5vdGVkIGluIHRoZQogICAgICAgKiB0ZW1wbGF0ZSBtZXRhZGF0YS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHshSFRNTFRlbXBsYXRlRWxlbWVudH0gdGVtcGxhdGUgVGVtcGxhdGUgdG8gcGFyc2UKICAgICAgICogQHBhcmFtIHtUZW1wbGF0ZUluZm89fSBvdXRlclRlbXBsYXRlSW5mbyBUZW1wbGF0ZSBtZXRhZGF0YSBmcm9tIHRoZSBvdXRlcgogICAgICAgKiAgIHRlbXBsYXRlLCBmb3IgcGFyc2luZyBuZXN0ZWQgdGVtcGxhdGVzCiAgICAgICAqIEByZXR1cm4geyFUZW1wbGF0ZUluZm99IFBhcnNlZCB0ZW1wbGF0ZSBtZXRhZGF0YQogICAgICAgKi8KICAgICAgc3RhdGljIF9wYXJzZVRlbXBsYXRlKHRlbXBsYXRlLCBvdXRlclRlbXBsYXRlSW5mbykgewogICAgICAgIC8vIHNpbmNlIGEgdGVtcGxhdGUgbWF5IGJlIHJlLXVzZWQsIG1lbW8taXplIG1ldGFkYXRhCiAgICAgICAgaWYgKCF0ZW1wbGF0ZS5fdGVtcGxhdGVJbmZvKSB7CiAgICAgICAgICBsZXQgdGVtcGxhdGVJbmZvID0gdGVtcGxhdGUuX3RlbXBsYXRlSW5mbyA9IHt9OwogICAgICAgICAgdGVtcGxhdGVJbmZvLm5vZGVJbmZvTGlzdCA9IFtdOwogICAgICAgICAgdGVtcGxhdGVJbmZvLnN0cmlwV2hpdGVTcGFjZSA9IFBvbHltZXIubGVnYWN5T3B0aW1pemF0aW9ucyB8fAogICAgICAgICAgICAob3V0ZXJUZW1wbGF0ZUluZm8gJiYgb3V0ZXJUZW1wbGF0ZUluZm8uc3RyaXBXaGl0ZVNwYWNlKSB8fAogICAgICAgICAgICB0ZW1wbGF0ZS5oYXNBdHRyaWJ1dGUoJ3N0cmlwLXdoaXRlc3BhY2UnKTsKICAgICAgICAgIHRoaXMuX3BhcnNlVGVtcGxhdGVDb250ZW50KHRlbXBsYXRlLCB0ZW1wbGF0ZUluZm8sIHtwYXJlbnQ6IG51bGx9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRlbXBsYXRlLl90ZW1wbGF0ZUluZm87CiAgICAgIH0KCiAgICAgIHN0YXRpYyBfcGFyc2VUZW1wbGF0ZUNvbnRlbnQodGVtcGxhdGUsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8pIHsKICAgICAgICByZXR1cm4gdGhpcy5fcGFyc2VUZW1wbGF0ZU5vZGUodGVtcGxhdGUuY29udGVudCwgdGVtcGxhdGVJbmZvLCBub2RlSW5mbyk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBQYXJzZXMgdGVtcGxhdGUgbm9kZSBhbmQgYWRkcyB0ZW1wbGF0ZSBhbmQgbm9kZSBtZXRhZGF0YSBiYXNlZCBvbgogICAgICAgKiB0aGUgY3VycmVudCBub2RlLCBhbmQgaXRzIGBjaGlsZE5vZGVzYCBhbmQgYGF0dHJpYnV0ZXNgLgogICAgICAgKgogICAgICAgKiBUaGlzIG1ldGhvZCBtYXkgYmUgb3ZlcnJpZGRlbiB0byBhZGQgY3VzdG9tIG5vZGUgb3IgdGVtcGxhdGUgc3BlY2lmaWMKICAgICAgICogbWV0YWRhdGEgYmFzZWQgb24gdGhpcyBub2RlLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge05vZGV9IG5vZGUgTm9kZSB0byBwYXJzZQogICAgICAgKiBAcGFyYW0geyFUZW1wbGF0ZUluZm99IHRlbXBsYXRlSW5mbyBUZW1wbGF0ZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZQogICAgICAgKiBAcGFyYW0geyFOb2RlSW5mb30gbm9kZUluZm8gTm9kZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZS4KICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gYHRydWVgIGlmIHRoZSB2aXNpdGVkIG5vZGUgYWRkZWQgbm9kZS1zcGVjaWZpYwogICAgICAgKiAgIG1ldGFkYXRhIHRvIGBub2RlSW5mb2AKICAgICAgICovCiAgICAgIHN0YXRpYyBfcGFyc2VUZW1wbGF0ZU5vZGUobm9kZSwgdGVtcGxhdGVJbmZvLCBub2RlSW5mbykgewogICAgICAgIGxldCBub3RlZDsKICAgICAgICBsZXQgZWxlbWVudCA9IC8qKiBAdHlwZSB7RWxlbWVudH0gKi8obm9kZSk7CiAgICAgICAgaWYgKGVsZW1lbnQubG9jYWxOYW1lID09ICd0ZW1wbGF0ZScgJiYgIWVsZW1lbnQuaGFzQXR0cmlidXRlKCdwcmVzZXJ2ZS1jb250ZW50JykpIHsKICAgICAgICAgIG5vdGVkID0gdGhpcy5fcGFyc2VUZW1wbGF0ZU5lc3RlZFRlbXBsYXRlKGVsZW1lbnQsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8pIHx8IG5vdGVkOwogICAgICAgIH0gZWxzZSBpZiAoZWxlbWVudC5sb2NhbE5hbWUgPT09ICdzbG90JykgewogICAgICAgICAgLy8gRm9yIFNoYWR5RG9tIG9wdGltaXphdGlvbiwgaW5kaWNhdGluZyB0aGVyZSBpcyBhbiBpbnNlcnRpb24gcG9pbnQKICAgICAgICAgIHRlbXBsYXRlSW5mby5oYXNJbnNlcnRpb25Qb2ludCA9IHRydWU7CiAgICAgICAgfQogICAgICAgIHdhbGtlci5jdXJyZW50Tm9kZSA9IGVsZW1lbnQ7CiAgICAgICAgaWYgKHdhbGtlci5maXJzdENoaWxkKCkpIHsKICAgICAgICAgIG5vdGVkID0gdGhpcy5fcGFyc2VUZW1wbGF0ZUNoaWxkTm9kZXMoZWxlbWVudCwgdGVtcGxhdGVJbmZvLCBub2RlSW5mbykgfHwgbm90ZWQ7CiAgICAgICAgfQogICAgICAgIGlmIChlbGVtZW50Lmhhc0F0dHJpYnV0ZXMgJiYgZWxlbWVudC5oYXNBdHRyaWJ1dGVzKCkpIHsKICAgICAgICAgIG5vdGVkID0gdGhpcy5fcGFyc2VUZW1wbGF0ZU5vZGVBdHRyaWJ1dGVzKGVsZW1lbnQsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8pIHx8IG5vdGVkOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbm90ZWQ7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBQYXJzZXMgdGVtcGxhdGUgY2hpbGQgbm9kZXMgZm9yIHRoZSBnaXZlbiByb290IG5vZGUuCiAgICAgICAqCiAgICAgICAqIFRoaXMgbWV0aG9kIGFsc28gd3JhcHMgd2hpdGVsaXN0ZWQgbGVnYWN5IHRlbXBsYXRlIGV4dGVuc2lvbnMKICAgICAgICogKGBpcz0iZG9tLWlmImAgYW5kIGBpcz0iZG9tLXJlcGVhdCJgKSB3aXRoIHRoZWlyIGVxdWl2YWxlbnQgZWxlbWVudAogICAgICAgKiB3cmFwcGVycywgY29sbGFwc2VzIHRleHQgbm9kZXMsIGFuZCBzdHJpcHMgd2hpdGVzcGFjZSBmcm9tIHRoZSB0ZW1wbGF0ZQogICAgICAgKiBpZiB0aGUgYHRlbXBsYXRlSW5mby5zdHJpcFdoaXRlc3BhY2VgIHNldHRpbmcgd2FzIHByb3ZpZGVkLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge05vZGV9IHJvb3QgUm9vdCBub2RlIHdob3NlIGBjaGlsZE5vZGVzYCB3aWxsIGJlIHBhcnNlZAogICAgICAgKiBAcGFyYW0geyFUZW1wbGF0ZUluZm99IHRlbXBsYXRlSW5mbyBUZW1wbGF0ZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZQogICAgICAgKiBAcGFyYW0geyFOb2RlSW5mb30gbm9kZUluZm8gTm9kZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZS4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIHN0YXRpYyBfcGFyc2VUZW1wbGF0ZUNoaWxkTm9kZXMocm9vdCwgdGVtcGxhdGVJbmZvLCBub2RlSW5mbykgewogICAgICAgIGlmIChyb290LmxvY2FsTmFtZSA9PT0gJ3NjcmlwdCcgfHwgcm9vdC5sb2NhbE5hbWUgPT09ICdzdHlsZScpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgd2Fsa2VyLmN1cnJlbnROb2RlID0gcm9vdDsKICAgICAgICBmb3IgKGxldCBub2RlPXdhbGtlci5maXJzdENoaWxkKCksIHBhcmVudEluZGV4PTAsIG5leHQ7IG5vZGU7IG5vZGU9bmV4dCkgewogICAgICAgICAgLy8gV3JhcCB0ZW1wbGF0ZXMKICAgICAgICAgIGlmIChub2RlLmxvY2FsTmFtZSA9PSAndGVtcGxhdGUnKSB7CiAgICAgICAgICAgIG5vZGUgPSB3cmFwVGVtcGxhdGVFeHRlbnNpb24obm9kZSk7CiAgICAgICAgICB9CiAgICAgICAgICAvLyBjb2xsYXBzZSBhZGphY2VudCB0ZXh0Tm9kZXM6IGZpeGVzIGFuIElFIGlzc3VlIHRoYXQgY2FuIGNhdXNlCiAgICAgICAgICAvLyB0ZXh0IG5vZGVzIHRvIGJlIGluZXhwbGljYWJseSBzcGxpdCA9KAogICAgICAgICAgLy8gbm90ZSB0aGF0IHJvb3Qubm9ybWFsaXplKCkgc2hvdWxkIHdvcmsgYnV0IGRvZXMgbm90IHNvIHdlIGRvIHRoaXMKICAgICAgICAgIC8vIG1hbnVhbGx5LgogICAgICAgICAgd2Fsa2VyLmN1cnJlbnROb2RlID0gbm9kZTsKICAgICAgICAgIG5leHQgPSB3YWxrZXIubmV4dFNpYmxpbmcoKTsKICAgICAgICAgIGlmIChub2RlLm5vZGVUeXBlID09PSBOb2RlLlRFWFRfTk9ERSkgewogICAgICAgICAgICBsZXQgLyoqIE5vZGUgKi8gbiA9IG5leHQ7CiAgICAgICAgICAgIHdoaWxlIChuICYmIChuLm5vZGVUeXBlID09PSBOb2RlLlRFWFRfTk9ERSkpIHsKICAgICAgICAgICAgICBub2RlLnRleHRDb250ZW50ICs9IG4udGV4dENvbnRlbnQ7CiAgICAgICAgICAgICAgbmV4dCA9IHdhbGtlci5uZXh0U2libGluZygpOwogICAgICAgICAgICAgIHJvb3QucmVtb3ZlQ2hpbGQobik7CiAgICAgICAgICAgICAgbiA9IG5leHQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gb3B0aW9uYWxseSBzdHJpcCB3aGl0ZXNwYWNlCiAgICAgICAgICAgIGlmICh0ZW1wbGF0ZUluZm8uc3RyaXBXaGl0ZVNwYWNlICYmICFub2RlLnRleHRDb250ZW50LnRyaW0oKSkgewogICAgICAgICAgICAgIHJvb3QucmVtb3ZlQ2hpbGQobm9kZSk7CiAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGxldCBjaGlsZEluZm8gPSB7IHBhcmVudEluZGV4LCBwYXJlbnRJbmZvOiBub2RlSW5mbyB9OwogICAgICAgICAgaWYgKHRoaXMuX3BhcnNlVGVtcGxhdGVOb2RlKG5vZGUsIHRlbXBsYXRlSW5mbywgY2hpbGRJbmZvKSkgewogICAgICAgICAgICBjaGlsZEluZm8uaW5mb0luZGV4ID0gdGVtcGxhdGVJbmZvLm5vZGVJbmZvTGlzdC5wdXNoKC8qKiBAdHlwZSB7IU5vZGVJbmZvfSAqLyhjaGlsZEluZm8pKSAtIDE7CiAgICAgICAgICB9CiAgICAgICAgICAvLyBJbmNyZW1lbnQgaWYgbm90IHJlbW92ZWQKICAgICAgICAgIHdhbGtlci5jdXJyZW50Tm9kZSA9IG5vZGU7CiAgICAgICAgICBpZiAod2Fsa2VyLnBhcmVudE5vZGUoKSkgewogICAgICAgICAgICBwYXJlbnRJbmRleCsrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFBhcnNlcyB0ZW1wbGF0ZSBjb250ZW50IGZvciB0aGUgZ2l2ZW4gbmVzdGVkIGA8dGVtcGxhdGU+YC4KICAgICAgICoKICAgICAgICogTmVzdGVkIHRlbXBsYXRlIGluZm8gaXMgc3RvcmVkIGFzIGB0ZW1wbGF0ZUluZm9gIGluIHRoZSBjdXJyZW50IG5vZGUncwogICAgICAgKiBgbm9kZUluZm9gLiBgdGVtcGxhdGUuY29udGVudGAgaXMgcmVtb3ZlZCBhbmQgc3RvcmVkIGluIGB0ZW1wbGF0ZUluZm9gLgogICAgICAgKiBJdCB3aWxsIHRoZW4gYmUgdGhlIHJlc3BvbnNpYmlsaXR5IG9mIHRoZSBob3N0IHRvIHNldCBpdCBiYWNrIHRvIHRoZQogICAgICAgKiB0ZW1wbGF0ZSBhbmQgZm9yIHVzZXJzIHN0YW1waW5nIG5lc3RlZCB0ZW1wbGF0ZXMgdG8gdXNlIHRoZQogICAgICAgKiBgX2NvbnRlbnRGb3JUZW1wbGF0ZWAgbWV0aG9kIHRvIHJldHJpZXZlIHRoZSBjb250ZW50IGZvciB0aGlzIHRlbXBsYXRlCiAgICAgICAqIChhbiBvcHRpbWl6YXRpb24gdG8gYXZvaWQgdGhlIGNvc3Qgb2YgY2xvbmluZyBuZXN0ZWQgdGVtcGxhdGUgY29udGVudCkuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7SFRNTFRlbXBsYXRlRWxlbWVudH0gbm9kZSBOb2RlIHRvIHBhcnNlIChhIDx0ZW1wbGF0ZT4pCiAgICAgICAqIEBwYXJhbSB7VGVtcGxhdGVJbmZvfSBvdXRlclRlbXBsYXRlSW5mbyBUZW1wbGF0ZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZQogICAgICAgKiAgIHRoYXQgaW5jbHVkZXMgdGhlIHRlbXBsYXRlIGBub2RlYAogICAgICAgKiBAcGFyYW0geyFOb2RlSW5mb30gbm9kZUluZm8gTm9kZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZS4KICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gYHRydWVgIGlmIHRoZSB2aXNpdGVkIG5vZGUgYWRkZWQgbm9kZS1zcGVjaWZpYwogICAgICAgKiAgIG1ldGFkYXRhIHRvIGBub2RlSW5mb2AKICAgICAgICovCiAgICAgIHN0YXRpYyBfcGFyc2VUZW1wbGF0ZU5lc3RlZFRlbXBsYXRlKG5vZGUsIG91dGVyVGVtcGxhdGVJbmZvLCBub2RlSW5mbykgewogICAgICAgIGxldCB0ZW1wbGF0ZUluZm8gPSB0aGlzLl9wYXJzZVRlbXBsYXRlKG5vZGUsIG91dGVyVGVtcGxhdGVJbmZvKTsKICAgICAgICBsZXQgY29udGVudCA9IHRlbXBsYXRlSW5mby5jb250ZW50ID0KICAgICAgICAgIG5vZGUuY29udGVudC5vd25lckRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTsKICAgICAgICBjb250ZW50LmFwcGVuZENoaWxkKG5vZGUuY29udGVudCk7CiAgICAgICAgbm9kZUluZm8udGVtcGxhdGVJbmZvID0gdGVtcGxhdGVJbmZvOwogICAgICAgIHJldHVybiB0cnVlOwogICAgICB9CgogICAgICAvKioKICAgICAgICogUGFyc2VzIHRlbXBsYXRlIG5vZGUgYXR0cmlidXRlcyBhbmQgYWRkcyBub2RlIG1ldGFkYXRhIHRvIGBub2RlSW5mb2AKICAgICAgICogZm9yIG5vZGVzIG9mIGludGVyZXN0LgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge0VsZW1lbnR9IG5vZGUgTm9kZSB0byBwYXJzZQogICAgICAgKiBAcGFyYW0ge1RlbXBsYXRlSW5mb30gdGVtcGxhdGVJbmZvIFRlbXBsYXRlIG1ldGFkYXRhIGZvciBjdXJyZW50IHRlbXBsYXRlCiAgICAgICAqIEBwYXJhbSB7Tm9kZUluZm99IG5vZGVJbmZvIE5vZGUgbWV0YWRhdGEgZm9yIGN1cnJlbnQgdGVtcGxhdGUuCiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IGB0cnVlYCBpZiB0aGUgdmlzaXRlZCBub2RlIGFkZGVkIG5vZGUtc3BlY2lmaWMKICAgICAgICogICBtZXRhZGF0YSB0byBgbm9kZUluZm9gCiAgICAgICAqLwogICAgICBzdGF0aWMgX3BhcnNlVGVtcGxhdGVOb2RlQXR0cmlidXRlcyhub2RlLCB0ZW1wbGF0ZUluZm8sIG5vZGVJbmZvKSB7CiAgICAgICAgLy8gTWFrZSBjb3B5IG9mIG9yaWdpbmFsIGF0dHJpYnV0ZSBsaXN0LCBzaW5jZSB0aGUgb3JkZXIgbWF5IGNoYW5nZQogICAgICAgIC8vIGFzIGF0dHJpYnV0ZXMgYXJlIGFkZGVkIGFuZCByZW1vdmVkCiAgICAgICAgbGV0IG5vdGVkID0gZmFsc2U7CiAgICAgICAgbGV0IGF0dHJzID0gQXJyYXkuZnJvbShub2RlLmF0dHJpYnV0ZXMpOwogICAgICAgIGZvciAobGV0IGk9YXR0cnMubGVuZ3RoLTEsIGE7IChhPWF0dHJzW2ldKTsgaS0tKSB7CiAgICAgICAgICBub3RlZCA9IHRoaXMuX3BhcnNlVGVtcGxhdGVOb2RlQXR0cmlidXRlKG5vZGUsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8sIGEubmFtZSwgYS52YWx1ZSkgfHwgbm90ZWQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiBub3RlZDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFBhcnNlcyBhIHNpbmdsZSB0ZW1wbGF0ZSBub2RlIGF0dHJpYnV0ZSBhbmQgYWRkcyBub2RlIG1ldGFkYXRhIHRvCiAgICAgICAqIGBub2RlSW5mb2AgZm9yIGF0dHJpYnV0ZXMgb2YgaW50ZXJlc3QuCiAgICAgICAqCiAgICAgICAqIFRoaXMgaW1wbGVtZW50YXRpb24gYWRkcyBtZXRhZGF0YSBmb3IgYG9uLWV2ZW50PSJoYW5kbGVyImAgYXR0cmlidXRlcwogICAgICAgKiBhbmQgYGlkYCBhdHRyaWJ1dGVzLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge0VsZW1lbnR9IG5vZGUgTm9kZSB0byBwYXJzZQogICAgICAgKiBAcGFyYW0geyFUZW1wbGF0ZUluZm99IHRlbXBsYXRlSW5mbyBUZW1wbGF0ZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZQogICAgICAgKiBAcGFyYW0geyFOb2RlSW5mb30gbm9kZUluZm8gTm9kZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZS4KICAgICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgQXR0cmlidXRlIG5hbWUKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIEF0dHJpYnV0ZSB2YWx1ZQogICAgICAgKiBAcmV0dXJuIHtib29sZWFufSBgdHJ1ZWAgaWYgdGhlIHZpc2l0ZWQgbm9kZSBhZGRlZCBub2RlLXNwZWNpZmljCiAgICAgICAqICAgbWV0YWRhdGEgdG8gYG5vZGVJbmZvYAogICAgICAgKi8KICAgICAgc3RhdGljIF9wYXJzZVRlbXBsYXRlTm9kZUF0dHJpYnV0ZShub2RlLCB0ZW1wbGF0ZUluZm8sIG5vZGVJbmZvLCBuYW1lLCB2YWx1ZSkgewogICAgICAgIC8vIGV2ZW50cyAob24tKikKICAgICAgICBpZiAobmFtZS5zbGljZSgwLCAzKSA9PT0gJ29uLScpIHsKICAgICAgICAgIG5vZGUucmVtb3ZlQXR0cmlidXRlKG5hbWUpOwogICAgICAgICAgbm9kZUluZm8uZXZlbnRzID0gbm9kZUluZm8uZXZlbnRzIHx8IFtdOwogICAgICAgICAgbm9kZUluZm8uZXZlbnRzLnB1c2goewogICAgICAgICAgICBuYW1lOiBuYW1lLnNsaWNlKDMpLAogICAgICAgICAgICB2YWx1ZQogICAgICAgICAgfSk7CiAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgLy8gc3RhdGljIGlkCiAgICAgICAgZWxzZSBpZiAobmFtZSA9PT0gJ2lkJykgewogICAgICAgICAgbm9kZUluZm8uaWQgPSB2YWx1ZTsKICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHRoZSBgY29udGVudGAgZG9jdW1lbnQgZnJhZ21lbnQgZm9yIGEgZ2l2ZW4gdGVtcGxhdGUuCiAgICAgICAqCiAgICAgICAqIEZvciBuZXN0ZWQgdGVtcGxhdGVzLCBQb2x5bWVyIHBlcmZvcm1zIGFuIG9wdGltaXphdGlvbiB0byBjYWNoZSBuZXN0ZWQKICAgICAgICogdGVtcGxhdGUgY29udGVudCB0byBhdm9pZCB0aGUgY29zdCBvZiBjbG9uaW5nIGRlZXBseSBuZXN0ZWQgdGVtcGxhdGVzLgogICAgICAgKiBUaGlzIG1ldGhvZCByZXRyaWV2ZXMgdGhlIGNhY2hlZCBjb250ZW50IGZvciBhIGdpdmVuIHRlbXBsYXRlLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge0hUTUxUZW1wbGF0ZUVsZW1lbnR9IHRlbXBsYXRlIFRlbXBsYXRlIHRvIHJldHJpZXZlIGBjb250ZW50YCBmb3IKICAgICAgICogQHJldHVybiB7RG9jdW1lbnRGcmFnbWVudH0gQ29udGVudCBmcmFnbWVudAogICAgICAgKi8KICAgICAgc3RhdGljIF9jb250ZW50Rm9yVGVtcGxhdGUodGVtcGxhdGUpIHsKICAgICAgICBsZXQgdGVtcGxhdGVJbmZvID0gLyoqIEB0eXBlIHtIVE1MVGVtcGxhdGVFbGVtZW50V2l0aEluZm99ICovICh0ZW1wbGF0ZSkuX3RlbXBsYXRlSW5mbzsKICAgICAgICByZXR1cm4gKHRlbXBsYXRlSW5mbyAmJiB0ZW1wbGF0ZUluZm8uY29udGVudCkgfHwgdGVtcGxhdGUuY29udGVudDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENsb25lcyB0aGUgcHJvdmlkZWQgdGVtcGxhdGUgY29udGVudCBhbmQgcmV0dXJucyBhIGRvY3VtZW50IGZyYWdtZW50CiAgICAgICAqIGNvbnRhaW5pbmcgdGhlIGNsb25lZCBkb20uCiAgICAgICAqCiAgICAgICAqIFRoZSB0ZW1wbGF0ZSBpcyBwYXJzZWQgKG9uY2UgYW5kIG1lbW9pemVkKSB1c2luZyB0aGlzIGxpYnJhcnkncwogICAgICAgKiB0ZW1wbGF0ZSBwYXJzaW5nIGZlYXR1cmVzLCBhbmQgcHJvdmlkZXMgdGhlIGZvbGxvd2luZyB2YWx1ZS1hZGRlZAogICAgICAgKiBmZWF0dXJlczoKICAgICAgICogKiBBZGRzIGRlY2xhcmF0aXZlIGV2ZW50IGxpc3RlbmVycyBmb3IgYG9uLWV2ZW50PSJoYW5kbGVyImAgYXR0cmlidXRlcwogICAgICAgKiAqIEdlbmVyYXRlcyBhbiAiaWQgbWFwIiBmb3IgYWxsIG5vZGVzIHdpdGggaWQncyB1bmRlciBgJGAgb24gcmV0dXJuZWQKICAgICAgICogICBkb2N1bWVudCBmcmFnbWVudAogICAgICAgKiAqIFBhc3NlcyB0ZW1wbGF0ZSBpbmZvIGluY2x1ZGluZyBgY29udGVudGAgYmFjayB0byB0ZW1wbGF0ZXMgYXMKICAgICAgICogICBgX3RlbXBsYXRlSW5mb2AgKGEgcGVyZm9ybWFuY2Ugb3B0aW1pemF0aW9uIHRvIGF2b2lkIGRlZXAgdGVtcGxhdGUKICAgICAgICogICBjbG9uaW5nKQogICAgICAgKgogICAgICAgKiBOb3RlIHRoYXQgdGhlIG1lbW9pemVkIHRlbXBsYXRlIHBhcnNpbmcgcHJvY2VzcyBpcyBkZXN0cnVjdGl2ZSB0byB0aGUKICAgICAgICogdGVtcGxhdGU6IGF0dHJpYnV0ZXMgZm9yIGJpbmRpbmdzIGFuZCBkZWNsYXJhdGl2ZSBldmVudCBsaXN0ZW5lcnMgYXJlCiAgICAgICAqIHJlbW92ZWQgYWZ0ZXIgYmVpbmcgbm90ZWQgaW4gbm90ZXMsIGFuZCBhbnkgbmVzdGVkIGA8dGVtcGxhdGU+LmNvbnRlbnRgCiAgICAgICAqIGlzIHJlbW92ZWQgYW5kIHN0b3JlZCBpbiBub3RlcyBhcyB3ZWxsLgogICAgICAgKgogICAgICAgKiBAcGFyYW0geyFIVE1MVGVtcGxhdGVFbGVtZW50fSB0ZW1wbGF0ZSBUZW1wbGF0ZSB0byBzdGFtcAogICAgICAgKiBAcmV0dXJuIHshU3RhbXBlZFRlbXBsYXRlfSBDbG9uZWQgdGVtcGxhdGUgY29udGVudAogICAgICAgKi8KICAgICAgX3N0YW1wVGVtcGxhdGUodGVtcGxhdGUpIHsKICAgICAgICAvLyBQb2x5ZmlsbCBzdXBwb3J0OiBib290c3RyYXAgdGhlIHRlbXBsYXRlIGlmIGl0IGhhcyBub3QgYWxyZWFkeSBiZWVuCiAgICAgICAgaWYgKHRlbXBsYXRlICYmICF0ZW1wbGF0ZS5jb250ZW50ICYmCiAgICAgICAgICAgIHdpbmRvdy5IVE1MVGVtcGxhdGVFbGVtZW50ICYmIEhUTUxUZW1wbGF0ZUVsZW1lbnQuZGVjb3JhdGUpIHsKICAgICAgICAgIEhUTUxUZW1wbGF0ZUVsZW1lbnQuZGVjb3JhdGUodGVtcGxhdGUpOwogICAgICAgIH0KICAgICAgICBsZXQgdGVtcGxhdGVJbmZvID0gdGhpcy5jb25zdHJ1Y3Rvci5fcGFyc2VUZW1wbGF0ZSh0ZW1wbGF0ZSk7CiAgICAgICAgbGV0IG5vZGVJbmZvID0gdGVtcGxhdGVJbmZvLm5vZGVJbmZvTGlzdDsKICAgICAgICBsZXQgY29udGVudCA9IHRlbXBsYXRlSW5mby5jb250ZW50IHx8IHRlbXBsYXRlLmNvbnRlbnQ7CiAgICAgICAgbGV0IGRvbSA9IC8qKiBAdHlwZSB7RG9jdW1lbnRGcmFnbWVudH0gKi8gKGRvY3VtZW50LmltcG9ydE5vZGUoY29udGVudCwgdHJ1ZSkpOwogICAgICAgIC8vIE5PVEU6IFNoYWR5RG9tIG9wdGltaXphdGlvbiBpbmRpY2F0aW5nIHRoZXJlIGlzIGFuIGluc2VydGlvbiBwb2ludAogICAgICAgIGRvbS5fX25vSW5zZXJ0aW9uUG9pbnQgPSAhdGVtcGxhdGVJbmZvLmhhc0luc2VydGlvblBvaW50OwogICAgICAgIGxldCBub2RlcyA9IGRvbS5ub2RlTGlzdCA9IG5ldyBBcnJheShub2RlSW5mby5sZW5ndGgpOwogICAgICAgIGRvbS4kID0ge307CiAgICAgICAgZm9yIChsZXQgaT0wLCBsPW5vZGVJbmZvLmxlbmd0aCwgaW5mbzsgKGk8bCkgJiYgKGluZm89bm9kZUluZm9baV0pOyBpKyspIHsKICAgICAgICAgIGxldCBub2RlID0gbm9kZXNbaV0gPSBmaW5kVGVtcGxhdGVOb2RlKGRvbSwgaW5mbyk7CiAgICAgICAgICBhcHBseUlkVG9NYXAodGhpcywgZG9tLiQsIG5vZGUsIGluZm8pOwogICAgICAgICAgYXBwbHlUZW1wbGF0ZUNvbnRlbnQodGhpcywgbm9kZSwgaW5mbyk7CiAgICAgICAgICBhcHBseUV2ZW50TGlzdGVuZXIodGhpcywgbm9kZSwgaW5mbyk7CiAgICAgICAgfQogICAgICAgIGRvbSA9IC8qKiBAdHlwZSB7IVN0YW1wZWRUZW1wbGF0ZX0gKi8oZG9tKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1zZWxmLWFzc2lnbgogICAgICAgIHJldHVybiBkb207CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBBZGRzIGFuIGV2ZW50IGxpc3RlbmVyIGJ5IG1ldGhvZCBuYW1lIGZvciB0aGUgZXZlbnQgcHJvdmlkZWQuCiAgICAgICAqCiAgICAgICAqIFRoaXMgbWV0aG9kIGdlbmVyYXRlcyBhIGhhbmRsZXIgZnVuY3Rpb24gdGhhdCBsb29rcyB1cCB0aGUgbWV0aG9kCiAgICAgICAqIG5hbWUgYXQgaGFuZGxpbmcgdGltZS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHshTm9kZX0gbm9kZSBOb2RlIHRvIGFkZCBsaXN0ZW5lciBvbgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lIE5hbWUgb2YgZXZlbnQKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZE5hbWUgTmFtZSBvZiBtZXRob2QKICAgICAgICogQHBhcmFtIHsqPX0gY29udGV4dCBDb250ZXh0IHRoZSBtZXRob2Qgd2lsbCBiZSBjYWxsZWQgb24gKGRlZmF1bHRzCiAgICAgICAqICAgdG8gYG5vZGVgKQogICAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbn0gR2VuZXJhdGVkIGhhbmRsZXIgZnVuY3Rpb24KICAgICAgICovCiAgICAgIF9hZGRNZXRob2RFdmVudExpc3RlbmVyVG9Ob2RlKG5vZGUsIGV2ZW50TmFtZSwgbWV0aG9kTmFtZSwgY29udGV4dCkgewogICAgICAgIGNvbnRleHQgPSBjb250ZXh0IHx8IG5vZGU7CiAgICAgICAgbGV0IGhhbmRsZXIgPSBjcmVhdGVOb2RlRXZlbnRIYW5kbGVyKGNvbnRleHQsIGV2ZW50TmFtZSwgbWV0aG9kTmFtZSk7CiAgICAgICAgdGhpcy5fYWRkRXZlbnRMaXN0ZW5lclRvTm9kZShub2RlLCBldmVudE5hbWUsIGhhbmRsZXIpOwogICAgICAgIHJldHVybiBoYW5kbGVyOwogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGUgcG9pbnQgZm9yIGFkZGluZyBjdXN0b20gb3Igc2ltdWxhdGVkIGV2ZW50IGhhbmRsaW5nLgogICAgICAgKgogICAgICAgKiBAcGFyYW0geyFOb2RlfSBub2RlIE5vZGUgdG8gYWRkIGV2ZW50IGxpc3RlbmVyIHRvCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWUgTmFtZSBvZiBldmVudAogICAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKCFFdmVudCk6dm9pZH0gaGFuZGxlciBMaXN0ZW5lciBmdW5jdGlvbiB0byBhZGQKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9hZGRFdmVudExpc3RlbmVyVG9Ob2RlKG5vZGUsIGV2ZW50TmFtZSwgaGFuZGxlcikgewogICAgICAgIG5vZGUuYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGhhbmRsZXIpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGUgcG9pbnQgZm9yIGFkZGluZyBjdXN0b20gb3Igc2ltdWxhdGVkIGV2ZW50IGhhbmRsaW5nLgogICAgICAgKgogICAgICAgKiBAcGFyYW0geyFOb2RlfSBub2RlIE5vZGUgdG8gcmVtb3ZlIGV2ZW50IGxpc3RlbmVyIGZyb20KICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZSBOYW1lIG9mIGV2ZW50CiAgICAgICAqIEBwYXJhbSB7ZnVuY3Rpb24oIUV2ZW50KTp2b2lkfSBoYW5kbGVyIExpc3RlbmVyIGZ1bmN0aW9uIHRvIHJlbW92ZQogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX3JlbW92ZUV2ZW50TGlzdGVuZXJGcm9tTm9kZShub2RlLCBldmVudE5hbWUsIGhhbmRsZXIpIHsKICAgICAgICBub2RlLnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBoYW5kbGVyKTsKICAgICAgfQoKICAgIH0KCiAgICByZXR1cm4gVGVtcGxhdGVTdGFtcDsKCiAgfSk7Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CgogICd1c2Ugc3RyaWN0JzsKCiAgLyoqIEBjb25zdCB7T2JqZWN0fSAqLwogIGNvbnN0IENhc2VNYXAgPSBQb2x5bWVyLkNhc2VNYXA7CgogIC8vIE1vbm90b25pY2FsbHkgaW5jcmVhc2luZyB1bmlxdWUgSUQgdXNlZCBmb3IgZGUtZHVwaW5nIGVmZmVjdHMgdHJpZ2dlcmVkCiAgLy8gZnJvbSBtdWx0aXBsZSBwcm9wZXJ0aWVzIGluIHRoZSBzYW1lIHR1cm4KICBsZXQgZGVkdXBlSWQgPSAwOwoKICAvKioKICAgKiBQcm9wZXJ0eSBlZmZlY3QgdHlwZXM7IGVmZmVjdHMgYXJlIHN0b3JlZCBvbiB0aGUgcHJvdG90eXBlIHVzaW5nIHRoZXNlIGtleXMKICAgKiBAZW51bSB7c3RyaW5nfQogICAqLwogIGNvbnN0IFRZUEVTID0gewogICAgQ09NUFVURTogJ19fY29tcHV0ZUVmZmVjdHMnLAogICAgUkVGTEVDVDogJ19fcmVmbGVjdEVmZmVjdHMnLAogICAgTk9USUZZOiAnX19ub3RpZnlFZmZlY3RzJywKICAgIFBST1BBR0FURTogJ19fcHJvcGFnYXRlRWZmZWN0cycsCiAgICBPQlNFUlZFOiAnX19vYnNlcnZlRWZmZWN0cycsCiAgICBSRUFEX09OTFk6ICdfX3JlYWRPbmx5JwogIH07CgogIC8qKiBAY29uc3Qge1JlZ0V4cH0gKi8KICBjb25zdCBjYXBpdGFsQXR0cmlidXRlUmVnZXggPSAvW0EtWl0vOwoKICAvKioKICAgKiBAdHlwZWRlZiB7ewogICAqIG5hbWU6IChzdHJpbmcgfCB1bmRlZmluZWQpLAogICAqIHN0cnVjdHVyZWQ6IChib29sZWFuIHwgdW5kZWZpbmVkKSwKICAgKiB3aWxkY2FyZDogKGJvb2xlYW4gfCB1bmRlZmluZWQpCiAgICogfX0KICAgKi8KICBsZXQgRGF0YVRyaWdnZXI7IC8vZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFycwoKICAvKioKICAgKiBAdHlwZWRlZiB7ewogICAqIGluZm86ID8sCiAgICogdHJpZ2dlcjogKCFEYXRhVHJpZ2dlciB8IHVuZGVmaW5lZCksCiAgICogZm46ICghRnVuY3Rpb24gfCB1bmRlZmluZWQpCiAgICogfX0KICAgKi8KICBsZXQgRGF0YUVmZmVjdDsgLy9lc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzCgogIGxldCBQcm9wZXJ0eUVmZmVjdHNUeXBlOyAvL2VzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnMKCiAgLyoqCiAgICogRW5zdXJlcyB0aGF0IHRoZSBtb2RlbCBoYXMgYW4gb3duLXByb3BlcnR5IG1hcCBvZiBlZmZlY3RzIGZvciB0aGUgZ2l2ZW4gdHlwZS4KICAgKiBUaGUgbW9kZWwgbWF5IGJlIGEgcHJvdG90eXBlIG9yIGFuIGluc3RhbmNlLgogICAqCiAgICogUHJvcGVydHkgZWZmZWN0cyBhcmUgc3RvcmVkIGFzIGFycmF5cyBvZiBlZmZlY3RzIGJ5IHByb3BlcnR5IGluIGEgbWFwLAogICAqIGJ5IG5hbWVkIHR5cGUgb24gdGhlIG1vZGVsLiBlLmcuCiAgICoKICAgKiAgIF9fY29tcHV0ZUVmZmVjdHM6IHsKICAgKiAgICAgZm9vOiBbIC4uLiBdLAogICAqICAgICBiYXI6IFsgLi4uIF0KICAgKiAgIH0KICAgKgogICAqIElmIHRoZSBtb2RlbCBkb2VzIG5vdCB5ZXQgaGF2ZSBhbiBlZmZlY3QgbWFwIGZvciB0aGUgdHlwZSwgb25lIGlzIGNyZWF0ZWQKICAgKiBhbmQgcmV0dXJuZWQuICBJZiBpdCBkb2VzLCBidXQgaXQgaXMgbm90IGFuIG93biBwcm9wZXJ0eSAoaS5lLiB0aGUKICAgKiBwcm90b3R5cGUgaGFkIGVmZmVjdHMpLCB0aGUgdGhlIG1hcCBpcyBkZWVwbHkgY2xvbmVkIGFuZCB0aGUgY29weSBpcwogICAqIHNldCBvbiB0aGUgbW9kZWwgYW5kIHJldHVybmVkLCByZWFkeSBmb3IgbmV3IGVmZmVjdHMgdG8gYmUgYWRkZWQuCiAgICoKICAgKiBAcGFyYW0ge09iamVjdH0gbW9kZWwgUHJvdG90eXBlIG9yIGluc3RhbmNlCiAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgUHJvcGVydHkgZWZmZWN0IHR5cGUKICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBvd24tcHJvcGVydHkgbWFwIG9mIGVmZmVjdHMgZm9yIHRoZSBnaXZlbiB0eXBlCiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBlbnN1cmVPd25FZmZlY3RNYXAobW9kZWwsIHR5cGUpIHsKICAgIGxldCBlZmZlY3RzID0gbW9kZWxbdHlwZV07CiAgICBpZiAoIWVmZmVjdHMpIHsKICAgICAgZWZmZWN0cyA9IG1vZGVsW3R5cGVdID0ge307CiAgICB9IGVsc2UgaWYgKCFtb2RlbC5oYXNPd25Qcm9wZXJ0eSh0eXBlKSkgewogICAgICBlZmZlY3RzID0gbW9kZWxbdHlwZV0gPSBPYmplY3QuY3JlYXRlKG1vZGVsW3R5cGVdKTsKICAgICAgZm9yIChsZXQgcCBpbiBlZmZlY3RzKSB7CiAgICAgICAgbGV0IHByb3RvRnggPSBlZmZlY3RzW3BdOwogICAgICAgIGxldCBpbnN0RnggPSBlZmZlY3RzW3BdID0gQXJyYXkocHJvdG9GeC5sZW5ndGgpOwogICAgICAgIGZvciAobGV0IGk9MDsgaTxwcm90b0Z4Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICBpbnN0RnhbaV0gPSBwcm90b0Z4W2ldOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIGVmZmVjdHM7CiAgfQoKICAvLyAtLSBlZmZlY3RzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiAgLyoqCiAgICogUnVucyBhbGwgZWZmZWN0cyBvZiBhIGdpdmVuIHR5cGUgZm9yIHRoZSBnaXZlbiBzZXQgb2YgcHJvcGVydHkgY2hhbmdlcwogICAqIG9uIGFuIGluc3RhbmNlLgogICAqCiAgICogQHBhcmFtIHshUHJvcGVydHlFZmZlY3RzVHlwZX0gaW5zdCBUaGUgaW5zdGFuY2Ugd2l0aCBlZmZlY3RzIHRvIHJ1bgogICAqIEBwYXJhbSB7T2JqZWN0fSBlZmZlY3RzIE9iamVjdCBtYXAgb2YgcHJvcGVydHktdG8tQXJyYXkgb2YgZWZmZWN0cwogICAqIEBwYXJhbSB7T2JqZWN0fSBwcm9wcyBCYWcgb2YgY3VycmVudCBwcm9wZXJ0eSBjaGFuZ2VzCiAgICogQHBhcmFtIHtPYmplY3Q9fSBvbGRQcm9wcyBCYWcgb2YgcHJldmlvdXMgdmFsdWVzIGZvciBjaGFuZ2VkIHByb3BlcnRpZXMKICAgKiBAcGFyYW0ge2Jvb2xlYW49fSBoYXNQYXRocyBUcnVlIHdpdGggYHByb3BzYCBjb250YWlucyBvbmUgb3IgbW9yZSBwYXRocwogICAqIEBwYXJhbSB7Kj19IGV4dHJhQXJncyBBZGRpdGlvbmFsIG1ldGFkYXRhIHRvIHBhc3MgdG8gZWZmZWN0IGZ1bmN0aW9uCiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBhbiBlZmZlY3QgcmFuIGZvciB0aGlzIHByb3BlcnR5CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBydW5FZmZlY3RzKGluc3QsIGVmZmVjdHMsIHByb3BzLCBvbGRQcm9wcywgaGFzUGF0aHMsIGV4dHJhQXJncykgewogICAgaWYgKGVmZmVjdHMpIHsKICAgICAgbGV0IHJhbiA9IGZhbHNlOwogICAgICBsZXQgaWQgPSBkZWR1cGVJZCsrOwogICAgICBmb3IgKGxldCBwcm9wIGluIHByb3BzKSB7CiAgICAgICAgaWYgKHJ1bkVmZmVjdHNGb3JQcm9wZXJ0eShpbnN0LCBlZmZlY3RzLCBpZCwgcHJvcCwgcHJvcHMsIG9sZFByb3BzLCBoYXNQYXRocywgZXh0cmFBcmdzKSkgewogICAgICAgICAgcmFuID0gdHJ1ZTsKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIHJhbjsKICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CgogIC8qKgogICAqIFJ1bnMgYSBsaXN0IG9mIGVmZmVjdHMgZm9yIGEgZ2l2ZW4gcHJvcGVydHkuCiAgICoKICAgKiBAcGFyYW0geyFQcm9wZXJ0eUVmZmVjdHNUeXBlfSBpbnN0IFRoZSBpbnN0YW5jZSB3aXRoIGVmZmVjdHMgdG8gcnVuCiAgICogQHBhcmFtIHtPYmplY3R9IGVmZmVjdHMgT2JqZWN0IG1hcCBvZiBwcm9wZXJ0eS10by1BcnJheSBvZiBlZmZlY3RzCiAgICogQHBhcmFtIHtudW1iZXJ9IGRlZHVwZUlkIENvdW50ZXIgdXNlZCBmb3IgZGUtZHVwaW5nIGVmZmVjdHMKICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcCBOYW1lIG9mIGNoYW5nZWQgcHJvcGVydHkKICAgKiBAcGFyYW0geyp9IHByb3BzIENoYW5nZWQgcHJvcGVydGllcwogICAqIEBwYXJhbSB7Kn0gb2xkUHJvcHMgT2xkIHByb3BlcnRpZXMKICAgKiBAcGFyYW0ge2Jvb2xlYW49fSBoYXNQYXRocyBUcnVlIHdpdGggYHByb3BzYCBjb250YWlucyBvbmUgb3IgbW9yZSBwYXRocwogICAqIEBwYXJhbSB7Kj19IGV4dHJhQXJncyBBZGRpdGlvbmFsIG1ldGFkYXRhIHRvIHBhc3MgdG8gZWZmZWN0IGZ1bmN0aW9uCiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBhbiBlZmZlY3QgcmFuIGZvciB0aGlzIHByb3BlcnR5CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBydW5FZmZlY3RzRm9yUHJvcGVydHkoaW5zdCwgZWZmZWN0cywgZGVkdXBlSWQsIHByb3AsIHByb3BzLCBvbGRQcm9wcywgaGFzUGF0aHMsIGV4dHJhQXJncykgewogICAgbGV0IHJhbiA9IGZhbHNlOwogICAgbGV0IHJvb3RQcm9wZXJ0eSA9IGhhc1BhdGhzID8gUG9seW1lci5QYXRoLnJvb3QocHJvcCkgOiBwcm9wOwogICAgbGV0IGZ4cyA9IGVmZmVjdHNbcm9vdFByb3BlcnR5XTsKICAgIGlmIChmeHMpIHsKICAgICAgZm9yIChsZXQgaT0wLCBsPWZ4cy5sZW5ndGgsIGZ4OyAoaTxsKSAmJiAoZng9ZnhzW2ldKTsgaSsrKSB7CiAgICAgICAgaWYgKCghZnguaW5mbyB8fCBmeC5pbmZvLmxhc3RSdW4gIT09IGRlZHVwZUlkKSAmJgogICAgICAgICAgICAoIWhhc1BhdGhzIHx8IHBhdGhNYXRjaGVzVHJpZ2dlcihwcm9wLCBmeC50cmlnZ2VyKSkpIHsKICAgICAgICAgIGlmIChmeC5pbmZvKSB7CiAgICAgICAgICAgIGZ4LmluZm8ubGFzdFJ1biA9IGRlZHVwZUlkOwogICAgICAgICAgfQogICAgICAgICAgZnguZm4oaW5zdCwgcHJvcCwgcHJvcHMsIG9sZFByb3BzLCBmeC5pbmZvLCBoYXNQYXRocywgZXh0cmFBcmdzKTsKICAgICAgICAgIHJhbiA9IHRydWU7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4gcmFuOwogIH0KCiAgLyoqCiAgICogRGV0ZXJtaW5lcyB3aGV0aGVyIGEgcHJvcGVydHkvcGF0aCB0aGF0IGhhcyBjaGFuZ2VkIG1hdGNoZXMgdGhlIHRyaWdnZXIKICAgKiBjcml0ZXJpYSBmb3IgYW4gZWZmZWN0LiAgQSB0cmlnZ2VyIGlzIGEgZGVzY3JpcHRvciB3aXRoIHRoZSBmb2xsb3dpbmcKICAgKiBzdHJ1Y3R1cmUsIHdoaWNoIG1hdGNoZXMgdGhlIGRlc2NyaXB0b3JzIHJldHVybmVkIGZyb20gYHBhcnNlQXJnYC4KICAgKiBlLmcuIGZvciBgZm9vLmJhci4qYDoKICAgKiBgYGAKICAgKiB0cmlnZ2VyOiB7CiAgICogICBuYW1lOiAnYS5iJywKICAgKiAgIHN0cnVjdHVyZWQ6IHRydWUsCiAgICogICB3aWxkY2FyZDogdHJ1ZQogICAqIH0KICAgKiBgYGAKICAgKiBJZiBubyB0cmlnZ2VyIGlzIGdpdmVuLCB0aGUgcGF0aCBpcyBkZWVtZWQgdG8gbWF0Y2guCiAgICoKICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aCBQYXRoIG9yIHByb3BlcnR5IHRoYXQgY2hhbmdlZAogICAqIEBwYXJhbSB7RGF0YVRyaWdnZXJ9IHRyaWdnZXIgRGVzY3JpcHRvcgogICAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHBhdGggbWF0Y2hlZCB0aGUgdHJpZ2dlcgogICAqLwogIGZ1bmN0aW9uIHBhdGhNYXRjaGVzVHJpZ2dlcihwYXRoLCB0cmlnZ2VyKSB7CiAgICBpZiAodHJpZ2dlcikgewogICAgICBsZXQgdHJpZ2dlclBhdGggPSB0cmlnZ2VyLm5hbWU7CiAgICAgIHJldHVybiAodHJpZ2dlclBhdGggPT0gcGF0aCkgfHwKICAgICAgICAodHJpZ2dlci5zdHJ1Y3R1cmVkICYmIFBvbHltZXIuUGF0aC5pc0FuY2VzdG9yKHRyaWdnZXJQYXRoLCBwYXRoKSkgfHwKICAgICAgICAodHJpZ2dlci53aWxkY2FyZCAmJiBQb2x5bWVyLlBhdGguaXNEZXNjZW5kYW50KHRyaWdnZXJQYXRoLCBwYXRoKSk7CiAgICB9IGVsc2UgewogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICB9CgogIC8qKgogICAqIEltcGxlbWVudHMgdGhlICJvYnNlcnZlciIgZWZmZWN0LgogICAqCiAgICogQ2FsbHMgdGhlIG1ldGhvZCB3aXRoIGBpbmZvLm1ldGhvZE5hbWVgIG9uIHRoZSBpbnN0YW5jZSwgcGFzc2luZyB0aGUKICAgKiBuZXcgYW5kIG9sZCB2YWx1ZXMuCiAgICoKICAgKiBAcGFyYW0geyFQcm9wZXJ0eUVmZmVjdHNUeXBlfSBpbnN0IFRoZSBpbnN0YW5jZSB0aGUgZWZmZWN0IHdpbGwgYmUgcnVuIG9uCiAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgcHJvcGVydHkKICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcHMgQmFnIG9mIGN1cnJlbnQgcHJvcGVydHkgY2hhbmdlcwogICAqIEBwYXJhbSB7T2JqZWN0fSBvbGRQcm9wcyBCYWcgb2YgcHJldmlvdXMgdmFsdWVzIGZvciBjaGFuZ2VkIHByb3BlcnRpZXMKICAgKiBAcGFyYW0gez99IGluZm8gRWZmZWN0IG1ldGFkYXRhCiAgICogQHJldHVybiB7dm9pZH0KICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIHJ1bk9ic2VydmVyRWZmZWN0KGluc3QsIHByb3BlcnR5LCBwcm9wcywgb2xkUHJvcHMsIGluZm8pIHsKICAgIGxldCBmbiA9IHR5cGVvZiBpbmZvLm1ldGhvZCA9PT0gInN0cmluZyIgPyBpbnN0W2luZm8ubWV0aG9kXSA6IGluZm8ubWV0aG9kOwogICAgbGV0IGNoYW5nZWRQcm9wID0gaW5mby5wcm9wZXJ0eTsKICAgIGlmIChmbikgewogICAgICBmbi5jYWxsKGluc3QsIGluc3QuX19kYXRhW2NoYW5nZWRQcm9wXSwgb2xkUHJvcHNbY2hhbmdlZFByb3BdKTsKICAgIH0gZWxzZSBpZiAoIWluZm8uZHluYW1pY0ZuKSB7CiAgICAgIGNvbnNvbGUud2Fybignb2JzZXJ2ZXIgbWV0aG9kIGAnICsgaW5mby5tZXRob2QgKyAnYCBub3QgZGVmaW5lZCcpOwogICAgfQogIH0KCiAgLyoqCiAgICogUnVucyAibm90aWZ5IiBlZmZlY3RzIGZvciBhIHNldCBvZiBjaGFuZ2VkIHByb3BlcnRpZXMuCiAgICoKICAgKiBUaGlzIG1ldGhvZCBkaWZmZXJzIGZyb20gdGhlIGdlbmVyaWMgYHJ1bkVmZmVjdHNgIG1ldGhvZCBpbiB0aGF0IGl0CiAgICogd2lsbCBkaXNwYXRjaCBwYXRoIG5vdGlmaWNhdGlvbiBldmVudHMgaW4gdGhlIGNhc2UgdGhhdCB0aGUgcHJvcGVydHkKICAgKiBjaGFuZ2VkIHdhcyBhIHBhdGggYW5kIHRoZSByb290IHByb3BlcnR5IGZvciB0aGF0IHBhdGggZGlkbid0IGhhdmUgYQogICAqICJub3RpZnkiIGVmZmVjdC4gIFRoaXMgaXMgdG8gbWFpbnRhaW4gMS4wIGJlaGF2aW9yIHRoYXQgZGlkIG5vdCByZXF1aXJlCiAgICogYG5vdGlmeTogdHJ1ZWAgdG8gZW5zdXJlIG9iamVjdCBzdWItcHJvcGVydHkgbm90aWZpY2F0aW9ucyB3ZXJlCiAgICogc2VudC4KICAgKgogICAqIEBwYXJhbSB7IVByb3BlcnR5RWZmZWN0c1R5cGV9IGluc3QgVGhlIGluc3RhbmNlIHdpdGggZWZmZWN0cyB0byBydW4KICAgKiBAcGFyYW0ge09iamVjdH0gbm90aWZ5UHJvcHMgQmFnIG9mIHByb3BlcnRpZXMgdG8gbm90aWZ5CiAgICogQHBhcmFtIHtPYmplY3R9IHByb3BzIEJhZyBvZiBjdXJyZW50IHByb3BlcnR5IGNoYW5nZXMKICAgKiBAcGFyYW0ge09iamVjdH0gb2xkUHJvcHMgQmFnIG9mIHByZXZpb3VzIHZhbHVlcyBmb3IgY2hhbmdlZCBwcm9wZXJ0aWVzCiAgICogQHBhcmFtIHtib29sZWFufSBoYXNQYXRocyBUcnVlIHdpdGggYHByb3BzYCBjb250YWlucyBvbmUgb3IgbW9yZSBwYXRocwogICAqIEByZXR1cm4ge3ZvaWR9CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBydW5Ob3RpZnlFZmZlY3RzKGluc3QsIG5vdGlmeVByb3BzLCBwcm9wcywgb2xkUHJvcHMsIGhhc1BhdGhzKSB7CiAgICAvLyBOb3RpZnkKICAgIGxldCBmeHMgPSBpbnN0W1RZUEVTLk5PVElGWV07CiAgICBsZXQgbm90aWZpZWQ7CiAgICBsZXQgaWQgPSBkZWR1cGVJZCsrOwogICAgLy8gVHJ5IG5vcm1hbCBub3RpZnkgZWZmZWN0czsgaWYgbm9uZSwgZmFsbCBiYWNrIHRvIHRyeSBwYXRoIG5vdGlmaWNhdGlvbgogICAgZm9yIChsZXQgcHJvcCBpbiBub3RpZnlQcm9wcykgewogICAgICBpZiAobm90aWZ5UHJvcHNbcHJvcF0pIHsKICAgICAgICBpZiAoZnhzICYmIHJ1bkVmZmVjdHNGb3JQcm9wZXJ0eShpbnN0LCBmeHMsIGlkLCBwcm9wLCBwcm9wcywgb2xkUHJvcHMsIGhhc1BhdGhzKSkgewogICAgICAgICAgbm90aWZpZWQgPSB0cnVlOwogICAgICAgIH0gZWxzZSBpZiAoaGFzUGF0aHMgJiYgbm90aWZ5UGF0aChpbnN0LCBwcm9wLCBwcm9wcykpIHsKICAgICAgICAgIG5vdGlmaWVkID0gdHJ1ZTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIC8vIEZsdXNoIGhvc3QgaWYgd2UgYWN0dWFsbHkgbm90aWZpZWQgYW5kIGhvc3Qgd2FzIGJhdGNoaW5nCiAgICAvLyBBbmQgdGhlIGhvc3QgaGFzIGFscmVhZHkgaW5pdGlhbGl6ZWQgY2xpZW50czsgdGhpcyBwcmV2ZW50cwogICAgLy8gYW4gaXNzdWUgd2l0aCBhIGhvc3Qgb2JzZXJ2aW5nIGRhdGEgY2hhbmdlcyBiZWZvcmUgY2xpZW50cyBhcmUgcmVhZHkuCiAgICBsZXQgaG9zdDsKICAgIGlmIChub3RpZmllZCAmJiAoaG9zdCA9IGluc3QuX19kYXRhSG9zdCkgJiYgaG9zdC5faW52YWxpZGF0ZVByb3BlcnRpZXMpIHsKICAgICAgaG9zdC5faW52YWxpZGF0ZVByb3BlcnRpZXMoKTsKICAgIH0KICB9CgogIC8qKgogICAqIERpc3BhdGNoZXMge3Byb3BlcnR5fS1jaGFuZ2VkIGV2ZW50cyB3aXRoIHBhdGggaW5mb3JtYXRpb24gaW4gdGhlIGRldGFpbAogICAqIG9iamVjdCB0byBpbmRpY2F0ZSBhIHN1Yi1wYXRoIG9mIHRoZSBwcm9wZXJ0eSB3YXMgY2hhbmdlZC4KICAgKgogICAqIEBwYXJhbSB7IVByb3BlcnR5RWZmZWN0c1R5cGV9IGluc3QgVGhlIGVsZW1lbnQgZnJvbSB3aGljaCB0byBmaXJlIHRoZSBldmVudAogICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFRoZSBwYXRoIHRoYXQgd2FzIGNoYW5nZWQKICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcHMgQmFnIG9mIGN1cnJlbnQgcHJvcGVydHkgY2hhbmdlcwogICAqIEByZXR1cm4ge2Jvb2xlYW59IFJldHVybnMgdHJ1ZSBpZiB0aGUgcGF0aCB3YXMgbm90aWZpZWQKICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIG5vdGlmeVBhdGgoaW5zdCwgcGF0aCwgcHJvcHMpIHsKICAgIGxldCByb290UHJvcGVydHkgPSBQb2x5bWVyLlBhdGgucm9vdChwYXRoKTsKICAgIGlmIChyb290UHJvcGVydHkgIT09IHBhdGgpIHsKICAgICAgbGV0IGV2ZW50TmFtZSA9IFBvbHltZXIuQ2FzZU1hcC5jYW1lbFRvRGFzaENhc2Uocm9vdFByb3BlcnR5KSArICctY2hhbmdlZCc7CiAgICAgIGRpc3BhdGNoTm90aWZ5RXZlbnQoaW5zdCwgZXZlbnROYW1lLCBwcm9wc1twYXRoXSwgcGF0aCk7CiAgICAgIHJldHVybiB0cnVlOwogICAgfQogICAgcmV0dXJuIGZhbHNlOwogIH0KCiAgLyoqCiAgICogRGlzcGF0Y2hlcyB7cHJvcGVydHl9LWNoYW5nZWQgZXZlbnRzIHRvIGluZGljYXRlIGEgcHJvcGVydHkgKG9yIHBhdGgpCiAgICogY2hhbmdlZC4KICAgKgogICAqIEBwYXJhbSB7IVByb3BlcnR5RWZmZWN0c1R5cGV9IGluc3QgVGhlIGVsZW1lbnQgZnJvbSB3aGljaCB0byBmaXJlIHRoZSBldmVudAogICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWUgVGhlIG5hbWUgb2YgdGhlIGV2ZW50IHRvIHNlbmQgKCd7cHJvcGVydHl9LWNoYW5nZWQnKQogICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIG9mIHRoZSBjaGFuZ2VkIHByb3BlcnR5CiAgICogQHBhcmFtIHtzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkfSBwYXRoIElmIGEgc3ViLXBhdGggb2YgdGhpcyBwcm9wZXJ0eSBjaGFuZ2VkLCB0aGUgcGF0aAogICAqICAgdGhhdCBjaGFuZ2VkIChvcHRpb25hbCkuCiAgICogQHJldHVybiB7dm9pZH0KICAgKiBAcHJpdmF0ZQogICAqIEBzdXBwcmVzcyB7aW52YWxpZENhc3RzfQogICAqLwogIGZ1bmN0aW9uIGRpc3BhdGNoTm90aWZ5RXZlbnQoaW5zdCwgZXZlbnROYW1lLCB2YWx1ZSwgcGF0aCkgewogICAgbGV0IGRldGFpbCA9IHsKICAgICAgdmFsdWU6IHZhbHVlLAogICAgICBxdWV1ZVByb3BlcnR5OiB0cnVlCiAgICB9OwogICAgaWYgKHBhdGgpIHsKICAgICAgZGV0YWlsLnBhdGggPSBwYXRoOwogICAgfQogICAgLyoqIEB0eXBlIHshSFRNTEVsZW1lbnR9ICovKGluc3QpLmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KGV2ZW50TmFtZSwgeyBkZXRhaWwgfSkpOwogIH0KCiAgLyoqCiAgICogSW1wbGVtZW50cyB0aGUgIm5vdGlmeSIgZWZmZWN0LgogICAqCiAgICogRGlzcGF0Y2hlcyBhIG5vbi1idWJibGluZyBldmVudCBuYW1lZCBgaW5mby5ldmVudE5hbWVgIG9uIHRoZSBpbnN0YW5jZQogICAqIHdpdGggYSBkZXRhaWwgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIG5ldyBgdmFsdWVgLgogICAqCiAgICogQHBhcmFtIHshUHJvcGVydHlFZmZlY3RzVHlwZX0gaW5zdCBUaGUgaW5zdGFuY2UgdGhlIGVmZmVjdCB3aWxsIGJlIHJ1biBvbgogICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBOYW1lIG9mIHByb3BlcnR5CiAgICogQHBhcmFtIHtPYmplY3R9IHByb3BzIEJhZyBvZiBjdXJyZW50IHByb3BlcnR5IGNoYW5nZXMKICAgKiBAcGFyYW0ge09iamVjdH0gb2xkUHJvcHMgQmFnIG9mIHByZXZpb3VzIHZhbHVlcyBmb3IgY2hhbmdlZCBwcm9wZXJ0aWVzCiAgICogQHBhcmFtIHs/fSBpbmZvIEVmZmVjdCBtZXRhZGF0YQogICAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFzUGF0aHMgVHJ1ZSB3aXRoIGBwcm9wc2AgY29udGFpbnMgb25lIG9yIG1vcmUgcGF0aHMKICAgKiBAcmV0dXJuIHt2b2lkfQogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gcnVuTm90aWZ5RWZmZWN0KGluc3QsIHByb3BlcnR5LCBwcm9wcywgb2xkUHJvcHMsIGluZm8sIGhhc1BhdGhzKSB7CiAgICBsZXQgcm9vdFByb3BlcnR5ID0gaGFzUGF0aHMgPyBQb2x5bWVyLlBhdGgucm9vdChwcm9wZXJ0eSkgOiBwcm9wZXJ0eTsKICAgIGxldCBwYXRoID0gcm9vdFByb3BlcnR5ICE9IHByb3BlcnR5ID8gcHJvcGVydHkgOiBudWxsOwogICAgbGV0IHZhbHVlID0gcGF0aCA/IFBvbHltZXIuUGF0aC5nZXQoaW5zdCwgcGF0aCkgOiBpbnN0Ll9fZGF0YVtwcm9wZXJ0eV07CiAgICBpZiAocGF0aCAmJiB2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgIHZhbHVlID0gcHJvcHNbcHJvcGVydHldOyAgLy8gc3BlY2lmaWNhbGx5IGZvciAuc3BsaWNlcwogICAgfQogICAgZGlzcGF0Y2hOb3RpZnlFdmVudChpbnN0LCBpbmZvLmV2ZW50TmFtZSwgdmFsdWUsIHBhdGgpOwogIH0KCiAgLyoqCiAgICogSGFuZGxlciBmdW5jdGlvbiBmb3IgMi13YXkgbm90aWZpY2F0aW9uIGV2ZW50cy4gUmVjZWl2ZXMgY29udGV4dAogICAqIGluZm9ybWF0aW9uIGNhcHR1cmVkIGluIHRoZSBgYWRkTm90aWZ5TGlzdGVuZXJgIGNsb3N1cmUgZnJvbSB0aGUKICAgKiBgX19ub3RpZnlMaXN0ZW5lcnNgIG1ldGFkYXRhLgogICAqCiAgICogU2V0cyB0aGUgdmFsdWUgb2YgdGhlIG5vdGlmaWVkIHByb3BlcnR5IHRvIHRoZSBob3N0IHByb3BlcnR5IG9yIHBhdGguICBJZgogICAqIHRoZSBldmVudCBjb250YWluZWQgcGF0aCBpbmZvcm1hdGlvbiwgdHJhbnNsYXRlIHRoYXQgcGF0aCB0byB0aGUgaG9zdAogICAqIHNjb3BlJ3MgbmFtZSBmb3IgdGhhdCBwYXRoIGZpcnN0LgogICAqCiAgICogQHBhcmFtIHtDdXN0b21FdmVudH0gZXZlbnQgTm90aWZpY2F0aW9uIGV2ZW50IChlLmcuICc8cHJvcGVydHk+LWNoYW5nZWQnKQogICAqIEBwYXJhbSB7IVByb3BlcnR5RWZmZWN0c1R5cGV9IGluc3QgSG9zdCBlbGVtZW50IGluc3RhbmNlIGhhbmRsaW5nIHRoZSBub3RpZmljYXRpb24gZXZlbnQKICAgKiBAcGFyYW0ge3N0cmluZ30gZnJvbVByb3AgQ2hpbGQgZWxlbWVudCBwcm9wZXJ0eSB0aGF0IHdhcyBib3VuZAogICAqIEBwYXJhbSB7c3RyaW5nfSB0b1BhdGggSG9zdCBwcm9wZXJ0eS9wYXRoIHRoYXQgd2FzIGJvdW5kCiAgICogQHBhcmFtIHtib29sZWFufSBuZWdhdGUgV2hldGhlciB0aGUgYmluZGluZyB3YXMgbmVnYXRlZAogICAqIEByZXR1cm4ge3ZvaWR9CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBoYW5kbGVOb3RpZmljYXRpb24oZXZlbnQsIGluc3QsIGZyb21Qcm9wLCB0b1BhdGgsIG5lZ2F0ZSkgewogICAgbGV0IHZhbHVlOwogICAgbGV0IGRldGFpbCA9IC8qKiBAdHlwZSB7T2JqZWN0fSAqLyhldmVudC5kZXRhaWwpOwogICAgbGV0IGZyb21QYXRoID0gZGV0YWlsICYmIGRldGFpbC5wYXRoOwogICAgaWYgKGZyb21QYXRoKSB7CiAgICAgIHRvUGF0aCA9IFBvbHltZXIuUGF0aC50cmFuc2xhdGUoZnJvbVByb3AsIHRvUGF0aCwgZnJvbVBhdGgpOwogICAgICB2YWx1ZSA9IGRldGFpbCAmJiBkZXRhaWwudmFsdWU7CiAgICB9IGVsc2UgewogICAgICB2YWx1ZSA9IGV2ZW50LmN1cnJlbnRUYXJnZXRbZnJvbVByb3BdOwogICAgfQogICAgdmFsdWUgPSBuZWdhdGUgPyAhdmFsdWUgOiB2YWx1ZTsKICAgIGlmICghaW5zdFtUWVBFUy5SRUFEX09OTFldIHx8ICFpbnN0W1RZUEVTLlJFQURfT05MWV1bdG9QYXRoXSkgewogICAgICBpZiAoaW5zdC5fc2V0UGVuZGluZ1Byb3BlcnR5T3JQYXRoKHRvUGF0aCwgdmFsdWUsIHRydWUsIEJvb2xlYW4oZnJvbVBhdGgpKQogICAgICAgICYmICghZGV0YWlsIHx8ICFkZXRhaWwucXVldWVQcm9wZXJ0eSkpIHsKICAgICAgICBpbnN0Ll9pbnZhbGlkYXRlUHJvcGVydGllcygpOwogICAgICB9CiAgICB9CiAgfQoKICAvKioKICAgKiBJbXBsZW1lbnRzIHRoZSAicmVmbGVjdCIgZWZmZWN0LgogICAqCiAgICogU2V0cyB0aGUgYXR0cmlidXRlIG5hbWVkIGBpbmZvLmF0dHJOYW1lYCB0byB0aGUgZ2l2ZW4gcHJvcGVydHkgdmFsdWUuCiAgICoKICAgKiBAcGFyYW0geyFQcm9wZXJ0eUVmZmVjdHNUeXBlfSBpbnN0IFRoZSBpbnN0YW5jZSB0aGUgZWZmZWN0IHdpbGwgYmUgcnVuIG9uCiAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgcHJvcGVydHkKICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcHMgQmFnIG9mIGN1cnJlbnQgcHJvcGVydHkgY2hhbmdlcwogICAqIEBwYXJhbSB7T2JqZWN0fSBvbGRQcm9wcyBCYWcgb2YgcHJldmlvdXMgdmFsdWVzIGZvciBjaGFuZ2VkIHByb3BlcnRpZXMKICAgKiBAcGFyYW0gez99IGluZm8gRWZmZWN0IG1ldGFkYXRhCiAgICogQHJldHVybiB7dm9pZH0KICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIHJ1blJlZmxlY3RFZmZlY3QoaW5zdCwgcHJvcGVydHksIHByb3BzLCBvbGRQcm9wcywgaW5mbykgewogICAgbGV0IHZhbHVlID0gaW5zdC5fX2RhdGFbcHJvcGVydHldOwogICAgaWYgKFBvbHltZXIuc2FuaXRpemVET01WYWx1ZSkgewogICAgICB2YWx1ZSA9IFBvbHltZXIuc2FuaXRpemVET01WYWx1ZSh2YWx1ZSwgaW5mby5hdHRyTmFtZSwgJ2F0dHJpYnV0ZScsIC8qKiBAdHlwZSB7Tm9kZX0gKi8oaW5zdCkpOwogICAgfQogICAgaW5zdC5fcHJvcGVydHlUb0F0dHJpYnV0ZShwcm9wZXJ0eSwgaW5mby5hdHRyTmFtZSwgdmFsdWUpOwogIH0KCiAgLyoqCiAgICogUnVucyAiY29tcHV0ZWQiIGVmZmVjdHMgZm9yIGEgc2V0IG9mIGNoYW5nZWQgcHJvcGVydGllcy4KICAgKgogICAqIFRoaXMgbWV0aG9kIGRpZmZlcnMgZnJvbSB0aGUgZ2VuZXJpYyBgcnVuRWZmZWN0c2AgbWV0aG9kIGluIHRoYXQgaXQKICAgKiBjb250aW51ZXMgdG8gcnVuIGNvbXB1dGVkIGVmZmVjdHMgYmFzZWQgb24gdGhlIG91dHB1dCBvZiBlYWNoIHBhc3MgdW50aWwKICAgKiB0aGVyZSBhcmUgbm8gbW9yZSBuZXdseSBjb21wdXRlZCBwcm9wZXJ0aWVzLiAgVGhpcyBlbnN1cmVzIHRoYXQgYWxsCiAgICogcHJvcGVydGllcyB0aGF0IHdpbGwgYmUgY29tcHV0ZWQgYnkgdGhlIGluaXRpYWwgc2V0IG9mIGNoYW5nZXMgYXJlCiAgICogY29tcHV0ZWQgYmVmb3JlIG90aGVyIGVmZmVjdHMgKGJpbmRpbmcgcHJvcGFnYXRpb24sIG9ic2VydmVycywgYW5kIG5vdGlmeSkKICAgKiBydW4uCiAgICoKICAgKiBAcGFyYW0geyFQcm9wZXJ0eUVmZmVjdHNUeXBlfSBpbnN0IFRoZSBpbnN0YW5jZSB0aGUgZWZmZWN0IHdpbGwgYmUgcnVuIG9uCiAgICogQHBhcmFtIHshT2JqZWN0fSBjaGFuZ2VkUHJvcHMgQmFnIG9mIGNoYW5nZWQgcHJvcGVydGllcwogICAqIEBwYXJhbSB7IU9iamVjdH0gb2xkUHJvcHMgQmFnIG9mIHByZXZpb3VzIHZhbHVlcyBmb3IgY2hhbmdlZCBwcm9wZXJ0aWVzCiAgICogQHBhcmFtIHtib29sZWFufSBoYXNQYXRocyBUcnVlIHdpdGggYHByb3BzYCBjb250YWlucyBvbmUgb3IgbW9yZSBwYXRocwogICAqIEByZXR1cm4ge3ZvaWR9CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBydW5Db21wdXRlZEVmZmVjdHMoaW5zdCwgY2hhbmdlZFByb3BzLCBvbGRQcm9wcywgaGFzUGF0aHMpIHsKICAgIGxldCBjb21wdXRlRWZmZWN0cyA9IGluc3RbVFlQRVMuQ09NUFVURV07CiAgICBpZiAoY29tcHV0ZUVmZmVjdHMpIHsKICAgICAgbGV0IGlucHV0UHJvcHMgPSBjaGFuZ2VkUHJvcHM7CiAgICAgIHdoaWxlIChydW5FZmZlY3RzKGluc3QsIGNvbXB1dGVFZmZlY3RzLCBpbnB1dFByb3BzLCBvbGRQcm9wcywgaGFzUGF0aHMpKSB7CiAgICAgICAgT2JqZWN0LmFzc2lnbihvbGRQcm9wcywgaW5zdC5fX2RhdGFPbGQpOwogICAgICAgIE9iamVjdC5hc3NpZ24oY2hhbmdlZFByb3BzLCBpbnN0Ll9fZGF0YVBlbmRpbmcpOwogICAgICAgIGlucHV0UHJvcHMgPSBpbnN0Ll9fZGF0YVBlbmRpbmc7CiAgICAgICAgaW5zdC5fX2RhdGFQZW5kaW5nID0gbnVsbDsKICAgICAgfQogICAgfQogIH0KCiAgLyoqCiAgICogSW1wbGVtZW50cyB0aGUgImNvbXB1dGVkIHByb3BlcnR5IiBlZmZlY3QgYnkgcnVubmluZyB0aGUgbWV0aG9kIHdpdGggdGhlCiAgICogdmFsdWVzIG9mIHRoZSBhcmd1bWVudHMgc3BlY2lmaWVkIGluIHRoZSBgaW5mb2Agb2JqZWN0IGFuZCBzZXR0aW5nIHRoZQogICAqIHJldHVybiB2YWx1ZSB0byB0aGUgY29tcHV0ZWQgcHJvcGVydHkgc3BlY2lmaWVkLgogICAqCiAgICogQHBhcmFtIHshUHJvcGVydHlFZmZlY3RzVHlwZX0gaW5zdCBUaGUgaW5zdGFuY2UgdGhlIGVmZmVjdCB3aWxsIGJlIHJ1biBvbgogICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBOYW1lIG9mIHByb3BlcnR5CiAgICogQHBhcmFtIHtPYmplY3R9IHByb3BzIEJhZyBvZiBjdXJyZW50IHByb3BlcnR5IGNoYW5nZXMKICAgKiBAcGFyYW0ge09iamVjdH0gb2xkUHJvcHMgQmFnIG9mIHByZXZpb3VzIHZhbHVlcyBmb3IgY2hhbmdlZCBwcm9wZXJ0aWVzCiAgICogQHBhcmFtIHs/fSBpbmZvIEVmZmVjdCBtZXRhZGF0YQogICAqIEByZXR1cm4ge3ZvaWR9CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBydW5Db21wdXRlZEVmZmVjdChpbnN0LCBwcm9wZXJ0eSwgcHJvcHMsIG9sZFByb3BzLCBpbmZvKSB7CiAgICBsZXQgcmVzdWx0ID0gcnVuTWV0aG9kRWZmZWN0KGluc3QsIHByb3BlcnR5LCBwcm9wcywgb2xkUHJvcHMsIGluZm8pOwogICAgbGV0IGNvbXB1dGVkUHJvcCA9IGluZm8ubWV0aG9kSW5mbzsKICAgIGlmIChpbnN0Ll9fZGF0YUhhc0FjY2Vzc29yICYmIGluc3QuX19kYXRhSGFzQWNjZXNzb3JbY29tcHV0ZWRQcm9wXSkgewogICAgICBpbnN0Ll9zZXRQZW5kaW5nUHJvcGVydHkoY29tcHV0ZWRQcm9wLCByZXN1bHQsIHRydWUpOwogICAgfSBlbHNlIHsKICAgICAgaW5zdFtjb21wdXRlZFByb3BdID0gcmVzdWx0OwogICAgfQogIH0KCiAgLyoqCiAgICogQ29tcHV0ZXMgcGF0aCBjaGFuZ2VzIGJhc2VkIG9uIHBhdGggbGlua3Mgc2V0IHVwIHVzaW5nIHRoZSBgbGlua1BhdGhzYAogICAqIEFQSS4KICAgKgogICAqIEBwYXJhbSB7IVByb3BlcnR5RWZmZWN0c1R5cGV9IGluc3QgVGhlIGluc3RhbmNlIHdob3NlIHByb3BzIGFyZSBjaGFuZ2luZwogICAqIEBwYXJhbSB7c3RyaW5nIHwgIUFycmF5PChzdHJpbmd8bnVtYmVyKT59IHBhdGggUGF0aCB0aGF0IGhhcyBjaGFuZ2VkCiAgICogQHBhcmFtIHsqfSB2YWx1ZSBWYWx1ZSBvZiBjaGFuZ2VkIHBhdGgKICAgKiBAcmV0dXJuIHt2b2lkfQogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gY29tcHV0ZUxpbmtlZFBhdGhzKGluc3QsIHBhdGgsIHZhbHVlKSB7CiAgICBsZXQgbGlua3MgPSBpbnN0Ll9fZGF0YUxpbmtlZFBhdGhzOwogICAgaWYgKGxpbmtzKSB7CiAgICAgIGxldCBsaW5rOwogICAgICBmb3IgKGxldCBhIGluIGxpbmtzKSB7CiAgICAgICAgbGV0IGIgPSBsaW5rc1thXTsKICAgICAgICBpZiAoUG9seW1lci5QYXRoLmlzRGVzY2VuZGFudChhLCBwYXRoKSkgewogICAgICAgICAgbGluayA9IFBvbHltZXIuUGF0aC50cmFuc2xhdGUoYSwgYiwgcGF0aCk7CiAgICAgICAgICBpbnN0Ll9zZXRQZW5kaW5nUHJvcGVydHlPclBhdGgobGluaywgdmFsdWUsIHRydWUsIHRydWUpOwogICAgICAgIH0gZWxzZSBpZiAoUG9seW1lci5QYXRoLmlzRGVzY2VuZGFudChiLCBwYXRoKSkgewogICAgICAgICAgbGluayA9IFBvbHltZXIuUGF0aC50cmFuc2xhdGUoYiwgYSwgcGF0aCk7CiAgICAgICAgICBpbnN0Ll9zZXRQZW5kaW5nUHJvcGVydHlPclBhdGgobGluaywgdmFsdWUsIHRydWUsIHRydWUpOwogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KCiAgLy8gLS0gYmluZGluZ3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKICAvKioKICAgKiBBZGRzIGJpbmRpbmcgbWV0YWRhdGEgdG8gdGhlIGN1cnJlbnQgYG5vZGVJbmZvYCwgYW5kIGJpbmRpbmcgZWZmZWN0cwogICAqIGZvciBhbGwgcGFydCBkZXBlbmRlbmNpZXMgdG8gYHRlbXBsYXRlSW5mb2AuCiAgICoKICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjb25zdHJ1Y3RvciBDbGFzcyB0aGF0IGBfcGFyc2VUZW1wbGF0ZWAgaXMgY3VycmVudGx5CiAgICogICBydW5uaW5nIG9uCiAgICogQHBhcmFtIHtUZW1wbGF0ZUluZm99IHRlbXBsYXRlSW5mbyBUZW1wbGF0ZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZQogICAqIEBwYXJhbSB7Tm9kZUluZm99IG5vZGVJbmZvIE5vZGUgbWV0YWRhdGEgZm9yIGN1cnJlbnQgdGVtcGxhdGUgbm9kZQogICAqIEBwYXJhbSB7c3RyaW5nfSBraW5kIEJpbmRpbmcga2luZCwgZWl0aGVyICdwcm9wZXJ0eScsICdhdHRyaWJ1dGUnLCBvciAndGV4dCcKICAgKiBAcGFyYW0ge3N0cmluZ30gdGFyZ2V0IFRhcmdldCBwcm9wZXJ0eSBuYW1lCiAgICogQHBhcmFtIHshQXJyYXk8IUJpbmRpbmdQYXJ0Pn0gcGFydHMgQXJyYXkgb2YgYmluZGluZyBwYXJ0IG1ldGFkYXRhCiAgICogQHBhcmFtIHtzdHJpbmc9fSBsaXRlcmFsIExpdGVyYWwgdGV4dCBzdXJyb3VuZGluZyBiaW5kaW5nIHBhcnRzIChzcGVjaWZpZWQKICAgKiAgIG9ubHkgZm9yICdwcm9wZXJ0eScgYmluZGluZ3MsIHNpbmNlIHRoZXNlIG11c3QgYmUgaW5pdGlhbGl6ZWQgYXMgcGFydAogICAqICAgb2YgYm9vdC11cCkKICAgKiBAcmV0dXJuIHt2b2lkfQogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gYWRkQmluZGluZyhjb25zdHJ1Y3RvciwgdGVtcGxhdGVJbmZvLCBub2RlSW5mbywga2luZCwgdGFyZ2V0LCBwYXJ0cywgbGl0ZXJhbCkgewogICAgLy8gQ3JlYXRlIGJpbmRpbmcgbWV0YWRhdGEgYW5kIGFkZCB0byBub2RlSW5mbwogICAgbm9kZUluZm8uYmluZGluZ3MgPSBub2RlSW5mby5iaW5kaW5ncyB8fCBbXTsKICAgIGxldCAvKiogQmluZGluZyAqLyBiaW5kaW5nID0geyBraW5kLCB0YXJnZXQsIHBhcnRzLCBsaXRlcmFsLCBpc0NvbXBvdW5kOiAocGFydHMubGVuZ3RoICE9PSAxKSB9OwogICAgbm9kZUluZm8uYmluZGluZ3MucHVzaChiaW5kaW5nKTsKICAgIC8vIEFkZCBsaXN0ZW5lciBpbmZvIHRvIGJpbmRpbmcgbWV0YWRhdGEKICAgIGlmIChzaG91bGRBZGRMaXN0ZW5lcihiaW5kaW5nKSkgewogICAgICBsZXQge2V2ZW50LCBuZWdhdGV9ID0gYmluZGluZy5wYXJ0c1swXTsKICAgICAgYmluZGluZy5saXN0ZW5lckV2ZW50ID0gZXZlbnQgfHwgKENhc2VNYXAuY2FtZWxUb0Rhc2hDYXNlKHRhcmdldCkgKyAnLWNoYW5nZWQnKTsKICAgICAgYmluZGluZy5saXN0ZW5lck5lZ2F0ZSA9IG5lZ2F0ZTsKICAgIH0KICAgIC8vIEFkZCAicHJvcGFnYXRlIiBwcm9wZXJ0eSBlZmZlY3RzIHRvIHRlbXBsYXRlSW5mbwogICAgbGV0IGluZGV4ID0gdGVtcGxhdGVJbmZvLm5vZGVJbmZvTGlzdC5sZW5ndGg7CiAgICBmb3IgKGxldCBpPTA7IGk8YmluZGluZy5wYXJ0cy5sZW5ndGg7IGkrKykgewogICAgICBsZXQgcGFydCA9IGJpbmRpbmcucGFydHNbaV07CiAgICAgIHBhcnQuY29tcG91bmRJbmRleCA9IGk7CiAgICAgIGFkZEVmZmVjdEZvckJpbmRpbmdQYXJ0KGNvbnN0cnVjdG9yLCB0ZW1wbGF0ZUluZm8sIGJpbmRpbmcsIHBhcnQsIGluZGV4KTsKICAgIH0KICB9CgogIC8qKgogICAqIEFkZHMgcHJvcGVydHkgZWZmZWN0cyB0byB0aGUgZ2l2ZW4gYHRlbXBsYXRlSW5mb2AgZm9yIHRoZSBnaXZlbiBiaW5kaW5nCiAgICogcGFydC4KICAgKgogICAqIEBwYXJhbSB7RnVuY3Rpb259IGNvbnN0cnVjdG9yIENsYXNzIHRoYXQgYF9wYXJzZVRlbXBsYXRlYCBpcyBjdXJyZW50bHkKICAgKiAgIHJ1bm5pbmcgb24KICAgKiBAcGFyYW0ge1RlbXBsYXRlSW5mb30gdGVtcGxhdGVJbmZvIFRlbXBsYXRlIG1ldGFkYXRhIGZvciBjdXJyZW50IHRlbXBsYXRlCiAgICogQHBhcmFtIHshQmluZGluZ30gYmluZGluZyBCaW5kaW5nIG1ldGFkYXRhCiAgICogQHBhcmFtIHshQmluZGluZ1BhcnR9IHBhcnQgQmluZGluZyBwYXJ0IG1ldGFkYXRhCiAgICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IEluZGV4IGludG8gYG5vZGVJbmZvTGlzdGAgZm9yIHRoaXMgbm9kZQogICAqIEByZXR1cm4ge3ZvaWR9CiAgICovCiAgZnVuY3Rpb24gYWRkRWZmZWN0Rm9yQmluZGluZ1BhcnQoY29uc3RydWN0b3IsIHRlbXBsYXRlSW5mbywgYmluZGluZywgcGFydCwgaW5kZXgpIHsKICAgIGlmICghcGFydC5saXRlcmFsKSB7CiAgICAgIGlmIChiaW5kaW5nLmtpbmQgPT09ICdhdHRyaWJ1dGUnICYmIGJpbmRpbmcudGFyZ2V0WzBdID09PSAnLScpIHsKICAgICAgICBjb25zb2xlLndhcm4oJ0Nhbm5vdCBzZXQgYXR0cmlidXRlICcgKyBiaW5kaW5nLnRhcmdldCArCiAgICAgICAgICAnIGJlY2F1c2UgIi0iIGlzIG5vdCBhIHZhbGlkIGF0dHJpYnV0ZSBzdGFydGluZyBjaGFyYWN0ZXInKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBsZXQgZGVwZW5kZW5jaWVzID0gcGFydC5kZXBlbmRlbmNpZXM7CiAgICAgICAgbGV0IGluZm8gPSB7IGluZGV4LCBiaW5kaW5nLCBwYXJ0LCBldmFsdWF0b3I6IGNvbnN0cnVjdG9yIH07CiAgICAgICAgZm9yIChsZXQgaj0wOyBqPGRlcGVuZGVuY2llcy5sZW5ndGg7IGorKykgewogICAgICAgICAgbGV0IHRyaWdnZXIgPSBkZXBlbmRlbmNpZXNbal07CiAgICAgICAgICBpZiAodHlwZW9mIHRyaWdnZXIgPT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgdHJpZ2dlciA9IHBhcnNlQXJnKHRyaWdnZXIpOwogICAgICAgICAgICB0cmlnZ2VyLndpbGRjYXJkID0gdHJ1ZTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0cnVjdG9yLl9hZGRUZW1wbGF0ZVByb3BlcnR5RWZmZWN0KHRlbXBsYXRlSW5mbywgdHJpZ2dlci5yb290UHJvcGVydHksIHsKICAgICAgICAgICAgZm46IHJ1bkJpbmRpbmdFZmZlY3QsCiAgICAgICAgICAgIGluZm8sIHRyaWdnZXIKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KCiAgLyoqCiAgICogSW1wbGVtZW50cyB0aGUgImJpbmRpbmciIChwcm9wZXJ0eS9wYXRoIGJpbmRpbmcpIGVmZmVjdC4KICAgKgogICAqIE5vdGUgdGhhdCBiaW5kaW5nIHN5bnRheCBpcyBvdmVycmlkYWJsZSB2aWEgYF9wYXJzZUJpbmRpbmdzYCBhbmQKICAgKiBgX2V2YWx1YXRlQmluZGluZ2AuICBUaGlzIG1ldGhvZCB3aWxsIGNhbGwgYF9ldmFsdWF0ZUJpbmRpbmdgIGZvciBhbnkKICAgKiBub24tbGl0ZXJhbCBwYXJ0cyByZXR1cm5lZCBmcm9tIGBfcGFyc2VCaW5kaW5nc2AuICBIb3dldmVyLAogICAqIHRoZXJlIGlzIG5vIHN1cHBvcnQgZm9yIF9wYXRoXyBiaW5kaW5ncyB2aWEgY3VzdG9tIGJpbmRpbmcgcGFydHMsCiAgICogYXMgdGhpcyBpcyBzcGVjaWZpYyB0byBQb2x5bWVyJ3MgcGF0aCBiaW5kaW5nIHN5bnRheC4KICAgKgogICAqIEBwYXJhbSB7IVByb3BlcnR5RWZmZWN0c1R5cGV9IGluc3QgVGhlIGluc3RhbmNlIHRoZSBlZmZlY3Qgd2lsbCBiZSBydW4gb24KICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aCBOYW1lIG9mIHByb3BlcnR5CiAgICogQHBhcmFtIHtPYmplY3R9IHByb3BzIEJhZyBvZiBjdXJyZW50IHByb3BlcnR5IGNoYW5nZXMKICAgKiBAcGFyYW0ge09iamVjdH0gb2xkUHJvcHMgQmFnIG9mIHByZXZpb3VzIHZhbHVlcyBmb3IgY2hhbmdlZCBwcm9wZXJ0aWVzCiAgICogQHBhcmFtIHs/fSBpbmZvIEVmZmVjdCBtZXRhZGF0YQogICAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFzUGF0aHMgVHJ1ZSB3aXRoIGBwcm9wc2AgY29udGFpbnMgb25lIG9yIG1vcmUgcGF0aHMKICAgKiBAcGFyYW0ge0FycmF5fSBub2RlTGlzdCBMaXN0IG9mIG5vZGVzIGFzc29jaWF0ZWQgd2l0aCBgbm9kZUluZm9MaXN0YCB0ZW1wbGF0ZQogICAqICAgbWV0YWRhdGEKICAgKiBAcmV0dXJuIHt2b2lkfQogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gcnVuQmluZGluZ0VmZmVjdChpbnN0LCBwYXRoLCBwcm9wcywgb2xkUHJvcHMsIGluZm8sIGhhc1BhdGhzLCBub2RlTGlzdCkgewogICAgbGV0IG5vZGUgPSBub2RlTGlzdFtpbmZvLmluZGV4XTsKICAgIGxldCBiaW5kaW5nID0gaW5mby5iaW5kaW5nOwogICAgbGV0IHBhcnQgPSBpbmZvLnBhcnQ7CiAgICAvLyBTdWJwYXRoIG5vdGlmaWNhdGlvbjogdHJhbnNmb3JtIHBhdGggYW5kIHNldCB0byBjbGllbnQKICAgIC8vIGUuZy46IGZvbz0ie3tvYmouc3VifX0iLCBwYXRoOiAnb2JqLnN1Yi5wcm9wJywgc2V0ICdmb28ucHJvcCc9b2JqLnN1Yi5wcm9wCiAgICBpZiAoaGFzUGF0aHMgJiYgcGFydC5zb3VyY2UgJiYgKHBhdGgubGVuZ3RoID4gcGFydC5zb3VyY2UubGVuZ3RoKSAmJgogICAgICAgIChiaW5kaW5nLmtpbmQgPT0gJ3Byb3BlcnR5JykgJiYgIWJpbmRpbmcuaXNDb21wb3VuZCAmJgogICAgICAgIG5vZGUuX19pc1Byb3BlcnR5RWZmZWN0c0NsaWVudCAmJgogICAgICAgIG5vZGUuX19kYXRhSGFzQWNjZXNzb3IgJiYgbm9kZS5fX2RhdGFIYXNBY2Nlc3NvcltiaW5kaW5nLnRhcmdldF0pIHsKICAgICAgbGV0IHZhbHVlID0gcHJvcHNbcGF0aF07CiAgICAgIHBhdGggPSBQb2x5bWVyLlBhdGgudHJhbnNsYXRlKHBhcnQuc291cmNlLCBiaW5kaW5nLnRhcmdldCwgcGF0aCk7CiAgICAgIGlmIChub2RlLl9zZXRQZW5kaW5nUHJvcGVydHlPclBhdGgocGF0aCwgdmFsdWUsIGZhbHNlLCB0cnVlKSkgewogICAgICAgIGluc3QuX2VucXVldWVDbGllbnQobm9kZSk7CiAgICAgIH0KICAgIH0gZWxzZSB7CiAgICAgIGxldCB2YWx1ZSA9IGluZm8uZXZhbHVhdG9yLl9ldmFsdWF0ZUJpbmRpbmcoaW5zdCwgcGFydCwgcGF0aCwgcHJvcHMsIG9sZFByb3BzLCBoYXNQYXRocyk7CiAgICAgIC8vIFByb3BhZ2F0ZSB2YWx1ZSB0byBjaGlsZAogICAgICBhcHBseUJpbmRpbmdWYWx1ZShpbnN0LCBub2RlLCBiaW5kaW5nLCBwYXJ0LCB2YWx1ZSk7CiAgICB9CiAgfQoKICAvKioKICAgKiBTZXRzIHRoZSB2YWx1ZSBmb3IgYW4gImJpbmRpbmciIChiaW5kaW5nKSBlZmZlY3QgdG8gYSBub2RlLAogICAqIGVpdGhlciBhcyBhIHByb3BlcnR5IG9yIGF0dHJpYnV0ZS4KICAgKgogICAqIEBwYXJhbSB7IVByb3BlcnR5RWZmZWN0c1R5cGV9IGluc3QgVGhlIGluc3RhbmNlIG93bmluZyB0aGUgYmluZGluZyBlZmZlY3QKICAgKiBAcGFyYW0ge05vZGV9IG5vZGUgVGFyZ2V0IG5vZGUgZm9yIGJpbmRpbmcKICAgKiBAcGFyYW0geyFCaW5kaW5nfSBiaW5kaW5nIEJpbmRpbmcgbWV0YWRhdGEKICAgKiBAcGFyYW0geyFCaW5kaW5nUGFydH0gcGFydCBCaW5kaW5nIHBhcnQgbWV0YWRhdGEKICAgKiBAcGFyYW0geyp9IHZhbHVlIFZhbHVlIHRvIHNldAogICAqIEByZXR1cm4ge3ZvaWR9CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBhcHBseUJpbmRpbmdWYWx1ZShpbnN0LCBub2RlLCBiaW5kaW5nLCBwYXJ0LCB2YWx1ZSkgewogICAgdmFsdWUgPSBjb21wdXRlQmluZGluZ1ZhbHVlKG5vZGUsIHZhbHVlLCBiaW5kaW5nLCBwYXJ0KTsKICAgIGlmIChQb2x5bWVyLnNhbml0aXplRE9NVmFsdWUpIHsKICAgICAgdmFsdWUgPSBQb2x5bWVyLnNhbml0aXplRE9NVmFsdWUodmFsdWUsIGJpbmRpbmcudGFyZ2V0LCBiaW5kaW5nLmtpbmQsIG5vZGUpOwogICAgfQogICAgaWYgKGJpbmRpbmcua2luZCA9PSAnYXR0cmlidXRlJykgewogICAgICAvLyBBdHRyaWJ1dGUgYmluZGluZwogICAgICBpbnN0Ll92YWx1ZVRvTm9kZUF0dHJpYnV0ZSgvKiogQHR5cGUge0VsZW1lbnR9ICovKG5vZGUpLCB2YWx1ZSwgYmluZGluZy50YXJnZXQpOwogICAgfSBlbHNlIHsKICAgICAgLy8gUHJvcGVydHkgYmluZGluZwogICAgICBsZXQgcHJvcCA9IGJpbmRpbmcudGFyZ2V0OwogICAgICBpZiAobm9kZS5fX2lzUHJvcGVydHlFZmZlY3RzQ2xpZW50ICYmCiAgICAgICAgICBub2RlLl9fZGF0YUhhc0FjY2Vzc29yICYmIG5vZGUuX19kYXRhSGFzQWNjZXNzb3JbcHJvcF0pIHsKICAgICAgICBpZiAoIW5vZGVbVFlQRVMuUkVBRF9PTkxZXSB8fCAhbm9kZVtUWVBFUy5SRUFEX09OTFldW3Byb3BdKSB7CiAgICAgICAgICBpZiAobm9kZS5fc2V0UGVuZGluZ1Byb3BlcnR5KHByb3AsIHZhbHVlKSkgewogICAgICAgICAgICBpbnN0Ll9lbnF1ZXVlQ2xpZW50KG5vZGUpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSBlbHNlICB7CiAgICAgICAgaW5zdC5fc2V0VW5tYW5hZ2VkUHJvcGVydHlUb05vZGUobm9kZSwgcHJvcCwgdmFsdWUpOwogICAgICB9CiAgICB9CiAgfQoKICAvKioKICAgKiBUcmFuc2Zvcm1zIGFuICJiaW5kaW5nIiBlZmZlY3QgdmFsdWUgYmFzZWQgb24gY29tcG91bmQgJiBuZWdhdGlvbgogICAqIGVmZmVjdCBtZXRhZGF0YSwgYXMgd2VsbCBhcyBoYW5kbGluZyBmb3Igc3BlY2lhbC1jYXNlIHByb3BlcnRpZXMKICAgKgogICAqIEBwYXJhbSB7Tm9kZX0gbm9kZSBOb2RlIHRoZSB2YWx1ZSB3aWxsIGJlIHNldCB0bwogICAqIEBwYXJhbSB7Kn0gdmFsdWUgVmFsdWUgdG8gc2V0CiAgICogQHBhcmFtIHshQmluZGluZ30gYmluZGluZyBCaW5kaW5nIG1ldGFkYXRhCiAgICogQHBhcmFtIHshQmluZGluZ1BhcnR9IHBhcnQgQmluZGluZyBwYXJ0IG1ldGFkYXRhCiAgICogQHJldHVybiB7Kn0gVHJhbnNmb3JtZWQgdmFsdWUgdG8gc2V0CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBjb21wdXRlQmluZGluZ1ZhbHVlKG5vZGUsIHZhbHVlLCBiaW5kaW5nLCBwYXJ0KSB7CiAgICBpZiAoYmluZGluZy5pc0NvbXBvdW5kKSB7CiAgICAgIGxldCBzdG9yYWdlID0gbm9kZS5fX2RhdGFDb21wb3VuZFN0b3JhZ2VbYmluZGluZy50YXJnZXRdOwogICAgICBzdG9yYWdlW3BhcnQuY29tcG91bmRJbmRleF0gPSB2YWx1ZTsKICAgICAgdmFsdWUgPSBzdG9yYWdlLmpvaW4oJycpOwogICAgfQogICAgaWYgKGJpbmRpbmcua2luZCAhPT0gJ2F0dHJpYnV0ZScpIHsKICAgICAgLy8gU29tZSBicm93c2VycyBzZXJpYWxpemUgYHVuZGVmaW5lZGAgdG8gYCJ1bmRlZmluZWQiYAogICAgICBpZiAoYmluZGluZy50YXJnZXQgPT09ICd0ZXh0Q29udGVudCcgfHwKICAgICAgICAgIChiaW5kaW5nLnRhcmdldCA9PT0gJ3ZhbHVlJyAmJgogICAgICAgICAgICAobm9kZS5sb2NhbE5hbWUgPT09ICdpbnB1dCcgfHwgbm9kZS5sb2NhbE5hbWUgPT09ICd0ZXh0YXJlYScpKSkgewogICAgICAgIHZhbHVlID0gdmFsdWUgPT0gdW5kZWZpbmVkID8gJycgOiB2YWx1ZTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHZhbHVlOwogIH0KCiAgLyoqCiAgICogUmV0dXJucyB0cnVlIGlmIGEgYmluZGluZydzIG1ldGFkYXRhIG1lZXRzIGFsbCB0aGUgcmVxdWlyZW1lbnRzIHRvIGFsbG93CiAgICogMi13YXkgYmluZGluZywgYW5kIHRoZXJlZm9yZSBhIGA8cHJvcGVydHk+LWNoYW5nZWRgIGV2ZW50IGxpc3RlbmVyIHNob3VsZCBiZQogICAqIGFkZGVkOgogICAqIC0gdXNlZCBjdXJseSBicmFjZXMKICAgKiAtIGlzIGEgcHJvcGVydHkgKG5vdCBhdHRyaWJ1dGUpIGJpbmRpbmcKICAgKiAtIGlzIG5vdCBhIHRleHRDb250ZW50IGJpbmRpbmcKICAgKiAtIGlzIG5vdCBjb21wb3VuZAogICAqCiAgICogQHBhcmFtIHshQmluZGluZ30gYmluZGluZyBCaW5kaW5nIG1ldGFkYXRhCiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiAyLXdheSBsaXN0ZW5lciBzaG91bGQgYmUgYWRkZWQKICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIHNob3VsZEFkZExpc3RlbmVyKGJpbmRpbmcpIHsKICAgIHJldHVybiBCb29sZWFuKGJpbmRpbmcudGFyZ2V0KSAmJgogICAgICAgICAgIGJpbmRpbmcua2luZCAhPSAnYXR0cmlidXRlJyAmJgogICAgICAgICAgIGJpbmRpbmcua2luZCAhPSAndGV4dCcgJiYKICAgICAgICAgICAhYmluZGluZy5pc0NvbXBvdW5kICYmCiAgICAgICAgICAgYmluZGluZy5wYXJ0c1swXS5tb2RlID09PSAneyc7CiAgfQoKICAvKioKICAgKiBTZXR1cCBjb21wb3VuZCBiaW5kaW5nIHN0b3JhZ2Ugc3RydWN0dXJlcywgbm90aWZ5IGxpc3RlbmVycywgYW5kIGRhdGFIb3N0CiAgICogcmVmZXJlbmNlcyBvbnRvIHRoZSBib3VuZCBub2RlTGlzdC4KICAgKgogICAqIEBwYXJhbSB7IVByb3BlcnR5RWZmZWN0c1R5cGV9IGluc3QgSW5zdGFuY2UgdGhhdCBiYXMgYmVlbiBwcmV2aW91c2x5IGJvdW5kCiAgICogQHBhcmFtIHtUZW1wbGF0ZUluZm99IHRlbXBsYXRlSW5mbyBUZW1wbGF0ZSBtZXRhZGF0YQogICAqIEByZXR1cm4ge3ZvaWR9CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBzZXR1cEJpbmRpbmdzKGluc3QsIHRlbXBsYXRlSW5mbykgewogICAgLy8gU2V0dXAgY29tcG91bmQgc3RvcmFnZSwgZGF0YUhvc3QsIGFuZCBub3RpZnkgbGlzdGVuZXJzCiAgICBsZXQge25vZGVMaXN0LCBub2RlSW5mb0xpc3R9ID0gdGVtcGxhdGVJbmZvOwogICAgaWYgKG5vZGVJbmZvTGlzdC5sZW5ndGgpIHsKICAgICAgZm9yIChsZXQgaT0wOyBpIDwgbm9kZUluZm9MaXN0Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgbGV0IGluZm8gPSBub2RlSW5mb0xpc3RbaV07CiAgICAgICAgbGV0IG5vZGUgPSBub2RlTGlzdFtpXTsKICAgICAgICBsZXQgYmluZGluZ3MgPSBpbmZvLmJpbmRpbmdzOwogICAgICAgIGlmIChiaW5kaW5ncykgewogICAgICAgICAgZm9yIChsZXQgaT0wOyBpPGJpbmRpbmdzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIGxldCBiaW5kaW5nID0gYmluZGluZ3NbaV07CiAgICAgICAgICAgIHNldHVwQ29tcG91bmRTdG9yYWdlKG5vZGUsIGJpbmRpbmcpOwogICAgICAgICAgICBhZGROb3RpZnlMaXN0ZW5lcihub2RlLCBpbnN0LCBiaW5kaW5nKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgbm9kZS5fX2RhdGFIb3N0ID0gaW5zdDsKICAgICAgfQogICAgfQogIH0KCiAgLyoqCiAgICogSW5pdGlhbGl6ZXMgYF9fZGF0YUNvbXBvdW5kU3RvcmFnZWAgbG9jYWwgc3RvcmFnZSBvbiBhIGJvdW5kIG5vZGUgd2l0aAogICAqIGluaXRpYWwgbGl0ZXJhbCBkYXRhIGZvciBjb21wb3VuZCBiaW5kaW5ncywgYW5kIHNldHMgdGhlIGpvaW5lZAogICAqIGxpdGVyYWwgcGFydHMgdG8gdGhlIGJvdW5kIHByb3BlcnR5LgogICAqCiAgICogV2hlbiBjaGFuZ2VzIHRvIGNvbXBvdW5kIHBhcnRzIG9jY3VyLCB0aGV5IGFyZSBmaXJzdCBzZXQgaW50byB0aGUgY29tcG91bmQKICAgKiBzdG9yYWdlIGFycmF5IGZvciB0aGF0IHByb3BlcnR5LCBhbmQgdGhlbiB0aGUgYXJyYXkgaXMgam9pbmVkIHRvIHJlc3VsdCBpbgogICAqIHRoZSBmaW5hbCB2YWx1ZSBzZXQgdG8gdGhlIHByb3BlcnR5L2F0dHJpYnV0ZS4KICAgKgogICAqIEBwYXJhbSB7Tm9kZX0gbm9kZSBCb3VuZCBub2RlIHRvIGluaXRpYWxpemUKICAgKiBAcGFyYW0ge0JpbmRpbmd9IGJpbmRpbmcgQmluZGluZyBtZXRhZGF0YQogICAqIEByZXR1cm4ge3ZvaWR9CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBzZXR1cENvbXBvdW5kU3RvcmFnZShub2RlLCBiaW5kaW5nKSB7CiAgICBpZiAoYmluZGluZy5pc0NvbXBvdW5kKSB7CiAgICAgIC8vIENyZWF0ZSBjb21wb3VuZCBzdG9yYWdlIG1hcAogICAgICBsZXQgc3RvcmFnZSA9IG5vZGUuX19kYXRhQ29tcG91bmRTdG9yYWdlIHx8CiAgICAgICAgKG5vZGUuX19kYXRhQ29tcG91bmRTdG9yYWdlID0ge30pOwogICAgICBsZXQgcGFydHMgPSBiaW5kaW5nLnBhcnRzOwogICAgICAvLyBDb3B5IGxpdGVyYWxzIGZyb20gcGFydHMgaW50byBzdG9yYWdlIGZvciB0aGlzIGJpbmRpbmcKICAgICAgbGV0IGxpdGVyYWxzID0gbmV3IEFycmF5KHBhcnRzLmxlbmd0aCk7CiAgICAgIGZvciAobGV0IGo9MDsgajxwYXJ0cy5sZW5ndGg7IGorKykgewogICAgICAgIGxpdGVyYWxzW2pdID0gcGFydHNbal0ubGl0ZXJhbDsKICAgICAgfQogICAgICBsZXQgdGFyZ2V0ID0gYmluZGluZy50YXJnZXQ7CiAgICAgIHN0b3JhZ2VbdGFyZ2V0XSA9IGxpdGVyYWxzOwogICAgICAvLyBDb25maWd1cmUgcHJvcGVydGllcyB3aXRoIHRoZWlyIGxpdGVyYWwgcGFydHMKICAgICAgaWYgKGJpbmRpbmcubGl0ZXJhbCAmJiBiaW5kaW5nLmtpbmQgPT0gJ3Byb3BlcnR5JykgewogICAgICAgIG5vZGVbdGFyZ2V0XSA9IGJpbmRpbmcubGl0ZXJhbDsKICAgICAgfQogICAgfQogIH0KCiAgLyoqCiAgICogQWRkcyBhIDItd2F5IGJpbmRpbmcgbm90aWZpY2F0aW9uIGV2ZW50IGxpc3RlbmVyIHRvIHRoZSBub2RlIHNwZWNpZmllZAogICAqCiAgICogQHBhcmFtIHtPYmplY3R9IG5vZGUgQ2hpbGQgZWxlbWVudCB0byBhZGQgbGlzdGVuZXIgdG8KICAgKiBAcGFyYW0geyFQcm9wZXJ0eUVmZmVjdHNUeXBlfSBpbnN0IEhvc3QgZWxlbWVudCBpbnN0YW5jZSB0byBoYW5kbGUgbm90aWZpY2F0aW9uIGV2ZW50CiAgICogQHBhcmFtIHtCaW5kaW5nfSBiaW5kaW5nIEJpbmRpbmcgbWV0YWRhdGEKICAgKiBAcmV0dXJuIHt2b2lkfQogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gYWRkTm90aWZ5TGlzdGVuZXIobm9kZSwgaW5zdCwgYmluZGluZykgewogICAgaWYgKGJpbmRpbmcubGlzdGVuZXJFdmVudCkgewogICAgICBsZXQgcGFydCA9IGJpbmRpbmcucGFydHNbMF07CiAgICAgIG5vZGUuYWRkRXZlbnRMaXN0ZW5lcihiaW5kaW5nLmxpc3RlbmVyRXZlbnQsIGZ1bmN0aW9uKGUpIHsKICAgICAgICBoYW5kbGVOb3RpZmljYXRpb24oZSwgaW5zdCwgYmluZGluZy50YXJnZXQsIHBhcnQuc291cmNlLCBwYXJ0Lm5lZ2F0ZSk7CiAgICAgIH0pOwogICAgfQogIH0KCiAgLy8gLS0gZm9yIG1ldGhvZC1iYXNlZCBlZmZlY3RzIChjb21wbGV4T2JzZXJ2ZXIgJiBjb21wdXRlZCkgLS0tLS0tLS0tLS0tLS0KCiAgLyoqCiAgICogQWRkcyBwcm9wZXJ0eSBlZmZlY3RzIGZvciBlYWNoIGFyZ3VtZW50IGluIHRoZSBtZXRob2Qgc2lnbmF0dXJlIChhbmQKICAgKiBvcHRpb25hbGx5LCBmb3IgdGhlIG1ldGhvZCBuYW1lIGlmIGBkeW5hbWljYCBpcyB0cnVlKSB0aGF0IGNhbGxzIHRoZQogICAqIHByb3ZpZGVkIGVmZmVjdCBmdW5jdGlvbi4KICAgKgogICAqIEBwYXJhbSB7RWxlbWVudCB8IE9iamVjdH0gbW9kZWwgUHJvdG90eXBlIG9yIGluc3RhbmNlCiAgICogQHBhcmFtIHshTWV0aG9kU2lnbmF0dXJlfSBzaWcgTWV0aG9kIHNpZ25hdHVyZSBtZXRhZGF0YQogICAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIFR5cGUgb2YgcHJvcGVydHkgZWZmZWN0IHRvIGFkZAogICAqIEBwYXJhbSB7RnVuY3Rpb259IGVmZmVjdEZuIEZ1bmN0aW9uIHRvIHJ1biB3aGVuIGFyZ3VtZW50cyBjaGFuZ2UKICAgKiBAcGFyYW0geyo9fSBtZXRob2RJbmZvIEVmZmVjdC1zcGVjaWZpYyBpbmZvcm1hdGlvbiB0byBiZSBpbmNsdWRlZCBpbgogICAqICAgbWV0aG9kIGVmZmVjdCBtZXRhZGF0YQogICAqIEBwYXJhbSB7Ym9vbGVhbnxPYmplY3Q9fSBkeW5hbWljRm4gQm9vbGVhbiBvciBvYmplY3QgbWFwIGluZGljYXRpbmcgd2hldGhlcgogICAqICAgbWV0aG9kIG5hbWVzIHNob3VsZCBiZSBpbmNsdWRlZCBhcyBhIGRlcGVuZGVuY3kgdG8gdGhlIGVmZmVjdC4gTm90ZSwKICAgKiAgIGRlZmF1bHRzIHRvIHRydWUgaWYgdGhlIHNpZ25hdHVyZSBpcyBzdGF0aWMgKHNpZy5zdGF0aWMgaXMgdHJ1ZSkuCiAgICogQHJldHVybiB7dm9pZH0KICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIGNyZWF0ZU1ldGhvZEVmZmVjdChtb2RlbCwgc2lnLCB0eXBlLCBlZmZlY3RGbiwgbWV0aG9kSW5mbywgZHluYW1pY0ZuKSB7CiAgICBkeW5hbWljRm4gPSBzaWcuc3RhdGljIHx8IChkeW5hbWljRm4gJiYKICAgICAgKHR5cGVvZiBkeW5hbWljRm4gIT09ICdvYmplY3QnIHx8IGR5bmFtaWNGbltzaWcubWV0aG9kTmFtZV0pKTsKICAgIGxldCBpbmZvID0gewogICAgICBtZXRob2ROYW1lOiBzaWcubWV0aG9kTmFtZSwKICAgICAgYXJnczogc2lnLmFyZ3MsCiAgICAgIG1ldGhvZEluZm8sCiAgICAgIGR5bmFtaWNGbgogICAgfTsKICAgIGZvciAobGV0IGk9MCwgYXJnOyAoaTxzaWcuYXJncy5sZW5ndGgpICYmIChhcmc9c2lnLmFyZ3NbaV0pOyBpKyspIHsKICAgICAgaWYgKCFhcmcubGl0ZXJhbCkgewogICAgICAgIG1vZGVsLl9hZGRQcm9wZXJ0eUVmZmVjdChhcmcucm9vdFByb3BlcnR5LCB0eXBlLCB7CiAgICAgICAgICBmbjogZWZmZWN0Rm4sIGluZm86IGluZm8sIHRyaWdnZXI6IGFyZwogICAgICAgIH0pOwogICAgICB9CiAgICB9CiAgICBpZiAoZHluYW1pY0ZuKSB7CiAgICAgIG1vZGVsLl9hZGRQcm9wZXJ0eUVmZmVjdChzaWcubWV0aG9kTmFtZSwgdHlwZSwgewogICAgICAgIGZuOiBlZmZlY3RGbiwgaW5mbzogaW5mbwogICAgICB9KTsKICAgIH0KICB9CgogIC8qKgogICAqIENhbGxzIGEgbWV0aG9kIHdpdGggYXJndW1lbnRzIG1hcnNoYWxlZCBmcm9tIHByb3BlcnRpZXMgb24gdGhlIGluc3RhbmNlCiAgICogYmFzZWQgb24gdGhlIG1ldGhvZCBzaWduYXR1cmUgY29udGFpbmVkIGluIHRoZSBlZmZlY3QgbWV0YWRhdGEuCiAgICoKICAgKiBNdWx0aS1wcm9wZXJ0eSBvYnNlcnZlcnMsIGNvbXB1dGVkIHByb3BlcnRpZXMsIGFuZCBpbmxpbmUgY29tcHV0aW5nCiAgICogZnVuY3Rpb25zIGNhbGwgdGhpcyBmdW5jdGlvbiB0byBpbnZva2UgdGhlIG1ldGhvZCwgdGhlbiB1c2UgdGhlIHJldHVybgogICAqIHZhbHVlIGFjY29yZGluZ2x5LgogICAqCiAgICogQHBhcmFtIHshUHJvcGVydHlFZmZlY3RzVHlwZX0gaW5zdCBUaGUgaW5zdGFuY2UgdGhlIGVmZmVjdCB3aWxsIGJlIHJ1biBvbgogICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBOYW1lIG9mIHByb3BlcnR5CiAgICogQHBhcmFtIHtPYmplY3R9IHByb3BzIEJhZyBvZiBjdXJyZW50IHByb3BlcnR5IGNoYW5nZXMKICAgKiBAcGFyYW0ge09iamVjdH0gb2xkUHJvcHMgQmFnIG9mIHByZXZpb3VzIHZhbHVlcyBmb3IgY2hhbmdlZCBwcm9wZXJ0aWVzCiAgICogQHBhcmFtIHs/fSBpbmZvIEVmZmVjdCBtZXRhZGF0YQogICAqIEByZXR1cm4geyp9IFJldHVybnMgdGhlIHJldHVybiB2YWx1ZSBmcm9tIHRoZSBtZXRob2QgaW52b2NhdGlvbgogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gcnVuTWV0aG9kRWZmZWN0KGluc3QsIHByb3BlcnR5LCBwcm9wcywgb2xkUHJvcHMsIGluZm8pIHsKICAgIC8vIEluc3RhbmNlcyBjYW4gb3B0aW9uYWxseSBoYXZlIGEgX21ldGhvZEhvc3Qgd2hpY2ggYWxsb3dzIHJlZGlyZWN0aW5nIHdoZXJlCiAgICAvLyB0byBmaW5kIG1ldGhvZHMuIEN1cnJlbnRseSB1c2VkIGJ5IGB0ZW1wbGF0aXplYC4KICAgIGxldCBjb250ZXh0ID0gaW5zdC5fbWV0aG9kSG9zdCB8fCBpbnN0OwogICAgbGV0IGZuID0gY29udGV4dFtpbmZvLm1ldGhvZE5hbWVdOwogICAgaWYgKGZuKSB7CiAgICAgIGxldCBhcmdzID0gaW5zdC5fbWFyc2hhbEFyZ3MoaW5mby5hcmdzLCBwcm9wZXJ0eSwgcHJvcHMpOwogICAgICByZXR1cm4gZm4uYXBwbHkoY29udGV4dCwgYXJncyk7CiAgICB9IGVsc2UgaWYgKCFpbmZvLmR5bmFtaWNGbikgewogICAgICBjb25zb2xlLndhcm4oJ21ldGhvZCBgJyArIGluZm8ubWV0aG9kTmFtZSArICdgIG5vdCBkZWZpbmVkJyk7CiAgICB9CiAgfQoKICBjb25zdCBlbXB0eUFycmF5ID0gW107CgogIC8vIFJlZ3VsYXIgZXhwcmVzc2lvbnMgdXNlZCBmb3IgYmluZGluZwogIGNvbnN0IElERU5UICA9ICcoPzonICsgJ1thLXpBLVpfJF1bXFx3LjokXFwtKl0qJyArICcpJzsKICBjb25zdCBOVU1CRVIgPSAnKD86JyArICdbLStdP1swLTldKlxcLj9bMC05XSsoPzpbZUVdWy0rXT9bMC05XSspPycgKyAnKSc7CiAgY29uc3QgU1FVT1RFX1NUUklORyA9ICcoPzonICsgJ1wnKD86W15cJ1xcXFxdfFxcXFwuKSpcJycgKyAnKSc7CiAgY29uc3QgRFFVT1RFX1NUUklORyA9ICcoPzonICsgJyIoPzpbXiJcXFxcXXxcXFxcLikqIicgKyAnKSc7CiAgY29uc3QgU1RSSU5HID0gJyg/OicgKyBTUVVPVEVfU1RSSU5HICsgJ3wnICsgRFFVT1RFX1NUUklORyArICcpJzsKICBjb25zdCBBUkdVTUVOVCA9ICcoPzooJyArIElERU5UICsgJ3wnICsgTlVNQkVSICsgJ3wnICsgIFNUUklORyArICcpXFxzKicgKyAnKSc7CiAgY29uc3QgQVJHVU1FTlRTID0gJyg/OicgKyBBUkdVTUVOVCArICcoPzosXFxzKicgKyBBUkdVTUVOVCArICcpKicgKyAnKSc7CiAgY29uc3QgQVJHVU1FTlRfTElTVCA9ICcoPzonICsgJ1xcKFxccyonICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnKD86JyArIEFSR1VNRU5UUyArICc/JyArICcpJyArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdcXClcXHMqJyArICcpJzsKICBjb25zdCBCSU5ESU5HID0gJygnICsgSURFTlQgKyAnXFxzKicgKyBBUkdVTUVOVF9MSVNUICsgJz8nICsgJyknOyAvLyBHcm91cCAzCiAgY29uc3QgT1BFTl9CUkFDS0VUID0gJyhcXFtcXFt8e3spJyArICdcXHMqJzsKICBjb25zdCBDTE9TRV9CUkFDS0VUID0gJyg/Ol1dfH19KSc7CiAgY29uc3QgTkVHQVRFID0gJyg/OighKVxccyopPyc7IC8vIEdyb3VwIDIKICBjb25zdCBFWFBSRVNTSU9OID0gT1BFTl9CUkFDS0VUICsgTkVHQVRFICsgQklORElORyArIENMT1NFX0JSQUNLRVQ7CiAgY29uc3QgYmluZGluZ1JlZ2V4ID0gbmV3IFJlZ0V4cChFWFBSRVNTSU9OLCAiZyIpOwoKICAvKioKICAgKiBDcmVhdGUgYSBzdHJpbmcgZnJvbSBiaW5kaW5nIHBhcnRzIG9mIGFsbCB0aGUgbGl0ZXJhbCBwYXJ0cwogICAqCiAgICogQHBhcmFtIHshQXJyYXk8QmluZGluZ1BhcnQ+fSBwYXJ0cyBBbGwgcGFydHMgdG8gc3RyaW5naWZ5CiAgICogQHJldHVybiB7c3RyaW5nfSBTdHJpbmcgbWFkZSBmcm9tIHRoZSBsaXRlcmFsIHBhcnRzCiAgICovCiAgZnVuY3Rpb24gbGl0ZXJhbEZyb21QYXJ0cyhwYXJ0cykgewogICAgbGV0IHMgPSAnJzsKICAgIGZvciAobGV0IGk9MDsgaTxwYXJ0cy5sZW5ndGg7IGkrKykgewogICAgICBsZXQgbGl0ZXJhbCA9IHBhcnRzW2ldLmxpdGVyYWw7CiAgICAgIHMgKz0gbGl0ZXJhbCB8fCAnJzsKICAgIH0KICAgIHJldHVybiBzOwogIH0KCiAgLyoqCiAgICogUGFyc2VzIGFuIGV4cHJlc3Npb24gc3RyaW5nIGZvciBhIG1ldGhvZCBzaWduYXR1cmUsIGFuZCByZXR1cm5zIGEgbWV0YWRhdGEKICAgKiBkZXNjcmliaW5nIHRoZSBtZXRob2QgaW4gdGVybXMgb2YgYG1ldGhvZE5hbWVgLCBgc3RhdGljYCAod2hldGhlciBhbGwgdGhlCiAgICogYXJndW1lbnRzIGFyZSBsaXRlcmFscyksIGFuZCBhbiBhcnJheSBvZiBgYXJnc2AKICAgKgogICAqIEBwYXJhbSB7c3RyaW5nfSBleHByZXNzaW9uIFRoZSBleHByZXNzaW9uIHRvIHBhcnNlCiAgICogQHJldHVybiB7P01ldGhvZFNpZ25hdHVyZX0gVGhlIG1ldGhvZCBtZXRhZGF0YSBvYmplY3QgaWYgYSBtZXRob2QgZXhwcmVzc2lvbiB3YXMKICAgKiAgIGZvdW5kLCBvdGhlcndpc2UgYHVuZGVmaW5lZGAKICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIHBhcnNlTWV0aG9kKGV4cHJlc3Npb24pIHsKICAgIC8vIHRyaWVzIHRvIG1hdGNoIHZhbGlkIGphdmFzY3JpcHQgcHJvcGVydHkgbmFtZXMKICAgIGxldCBtID0gZXhwcmVzc2lvbi5tYXRjaCgvKFteXHNdKz8pXCgoW1xzXFNdKilcKS8pOwogICAgaWYgKG0pIHsKICAgICAgbGV0IG1ldGhvZE5hbWUgPSBtWzFdOwogICAgICBsZXQgc2lnID0geyBtZXRob2ROYW1lLCBzdGF0aWM6IHRydWUsIGFyZ3M6IGVtcHR5QXJyYXkgfTsKICAgICAgaWYgKG1bMl0udHJpbSgpKSB7CiAgICAgICAgLy8gcmVwbGFjZSBlc2NhcGVkIGNvbW1hcyB3aXRoIGNvbW1hIGVudGl0eSwgc3BsaXQgb24gdW4tZXNjYXBlZCBjb21tYXMKICAgICAgICBsZXQgYXJncyA9IG1bMl0ucmVwbGFjZSgvXFwsL2csICcmY29tbWE7Jykuc3BsaXQoJywnKTsKICAgICAgICByZXR1cm4gcGFyc2VBcmdzKGFyZ3MsIHNpZyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHNpZzsKICAgICAgfQogICAgfQogICAgcmV0dXJuIG51bGw7CiAgfQoKICAvKioKICAgKiBQYXJzZXMgYW4gYXJyYXkgb2YgYXJndW1lbnRzIGFuZCBzZXRzIHRoZSBgYXJnc2AgcHJvcGVydHkgb2YgdGhlIHN1cHBsaWVkCiAgICogc2lnbmF0dXJlIG1ldGFkYXRhIG9iamVjdC4gU2V0cyB0aGUgYHN0YXRpY2AgcHJvcGVydHkgdG8gZmFsc2UgaWYgYW55CiAgICogYXJndW1lbnQgaXMgYSBub24tbGl0ZXJhbC4KICAgKgogICAqIEBwYXJhbSB7IUFycmF5PHN0cmluZz59IGFyZ0xpc3QgQXJyYXkgb2YgYXJndW1lbnQgbmFtZXMKICAgKiBAcGFyYW0geyFNZXRob2RTaWduYXR1cmV9IHNpZyBNZXRob2Qgc2lnbmF0dXJlIG1ldGFkYXRhIG9iamVjdAogICAqIEByZXR1cm4geyFNZXRob2RTaWduYXR1cmV9IFRoZSB1cGRhdGVkIHNpZ25hdHVyZSBtZXRhZGF0YSBvYmplY3QKICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIHBhcnNlQXJncyhhcmdMaXN0LCBzaWcpIHsKICAgIHNpZy5hcmdzID0gYXJnTGlzdC5tYXAoZnVuY3Rpb24ocmF3QXJnKSB7CiAgICAgIGxldCBhcmcgPSBwYXJzZUFyZyhyYXdBcmcpOwogICAgICBpZiAoIWFyZy5saXRlcmFsKSB7CiAgICAgICAgc2lnLnN0YXRpYyA9IGZhbHNlOwogICAgICB9CiAgICAgIHJldHVybiBhcmc7CiAgICB9LCB0aGlzKTsKICAgIHJldHVybiBzaWc7CiAgfQoKICAvKioKICAgKiBQYXJzZXMgYW4gaW5kaXZpZHVhbCBhcmd1bWVudCwgYW5kIHJldHVybnMgYW4gYXJndW1lbnQgbWV0YWRhdGEgb2JqZWN0CiAgICogd2l0aCB0aGUgZm9sbG93aW5nIGZpZWxkczoKICAgKgogICAqICAgewogICAqICAgICB2YWx1ZTogJ3Byb3AnLCAgICAgICAgLy8gcHJvcGVydHkvcGF0aCBvciBsaXRlcmFsIHZhbHVlCiAgICogICAgIGxpdGVyYWw6IGZhbHNlLCAgICAgICAvLyB3aGV0aGVyIGFyZ3VtZW50IGlzIGEgbGl0ZXJhbAogICAqICAgICBzdHJ1Y3R1cmVkOiBmYWxzZSwgICAgLy8gd2hldGhlciB0aGUgcHJvcGVydHkgaXMgYSBwYXRoCiAgICogICAgIHJvb3RQcm9wZXJ0eTogJ3Byb3AnLCAvLyB0aGUgcm9vdCBwcm9wZXJ0eSBvZiB0aGUgcGF0aAogICAqICAgICB3aWxkY2FyZDogZmFsc2UgICAgICAgLy8gd2hldGhlciB0aGUgYXJndW1lbnQgd2FzIGEgd2lsZGNhcmQgJy4qJyBwYXRoCiAgICogICB9CiAgICoKICAgKiBAcGFyYW0ge3N0cmluZ30gcmF3QXJnIFRoZSBzdHJpbmcgdmFsdWUgb2YgdGhlIGFyZ3VtZW50CiAgICogQHJldHVybiB7IU1ldGhvZEFyZ30gQXJndW1lbnQgbWV0YWRhdGEgb2JqZWN0CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBwYXJzZUFyZyhyYXdBcmcpIHsKICAgIC8vIGNsZWFuIHVwIHdoaXRlc3BhY2UKICAgIGxldCBhcmcgPSByYXdBcmcudHJpbSgpCiAgICAgIC8vIHJlcGxhY2UgY29tbWEgZW50aXR5IHdpdGggY29tbWEKICAgICAgLnJlcGxhY2UoLyZjb21tYTsvZywgJywnKQogICAgICAvLyByZXBhaXIgZXh0cmEgZXNjYXBlIHNlcXVlbmNlczsgbm90ZSBvbmx5IGNvbW1hcyBzdHJpY3RseSBuZWVkCiAgICAgIC8vIGVzY2FwaW5nLCBidXQgd2UgYWxsb3cgYW55IG90aGVyIGNoYXIgdG8gYmUgZXNjYXBlZCBzaW5jZSBpdHMKICAgICAgLy8gbGlrZWx5IHVzZXJzIHdpbGwgZG8gdGhpcwogICAgICAucmVwbGFjZSgvXFwoLikvZywgJ1wkMScpCiAgICAgIDsKICAgIC8vIGJhc2ljIGFyZ3VtZW50IGRlc2NyaXB0b3IKICAgIGxldCBhID0gewogICAgICBuYW1lOiBhcmcsCiAgICAgIHZhbHVlOiAnJywKICAgICAgbGl0ZXJhbDogZmFsc2UKICAgIH07CiAgICAvLyBkZXRlY3QgbGl0ZXJhbCB2YWx1ZSAobXVzdCBiZSBTdHJpbmcgb3IgTnVtYmVyKQogICAgbGV0IGZjID0gYXJnWzBdOwogICAgaWYgKGZjID09PSAnLScpIHsKICAgICAgZmMgPSBhcmdbMV07CiAgICB9CiAgICBpZiAoZmMgPj0gJzAnICYmIGZjIDw9ICc5JykgewogICAgICBmYyA9ICcjJzsKICAgIH0KICAgIHN3aXRjaChmYykgewogICAgICBjYXNlICInIjoKICAgICAgY2FzZSAnIic6CiAgICAgICAgYS52YWx1ZSA9IGFyZy5zbGljZSgxLCAtMSk7CiAgICAgICAgYS5saXRlcmFsID0gdHJ1ZTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSAnIyc6CiAgICAgICAgYS52YWx1ZSA9IE51bWJlcihhcmcpOwogICAgICAgIGEubGl0ZXJhbCA9IHRydWU7CiAgICAgICAgYnJlYWs7CiAgICB9CiAgICAvLyBpZiBub3QgbGl0ZXJhbCwgbG9vayBmb3Igc3RydWN0dXJlZCBwYXRoCiAgICBpZiAoIWEubGl0ZXJhbCkgewogICAgICBhLnJvb3RQcm9wZXJ0eSA9IFBvbHltZXIuUGF0aC5yb290KGFyZyk7CiAgICAgIC8vIGRldGVjdCBzdHJ1Y3R1cmVkIHBhdGggKGhhcyBkb3RzKQogICAgICBhLnN0cnVjdHVyZWQgPSBQb2x5bWVyLlBhdGguaXNQYXRoKGFyZyk7CiAgICAgIGlmIChhLnN0cnVjdHVyZWQpIHsKICAgICAgICBhLndpbGRjYXJkID0gKGFyZy5zbGljZSgtMikgPT0gJy4qJyk7CiAgICAgICAgaWYgKGEud2lsZGNhcmQpIHsKICAgICAgICAgIGEubmFtZSA9IGFyZy5zbGljZSgwLCAtMik7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4gYTsKICB9CgogIC8vIGRhdGEgYXBpCgogIC8qKgogICAqIFNlbmRzIGFycmF5IHNwbGljZSBub3RpZmljYXRpb25zIChgLnNwbGljZXNgIGFuZCBgLmxlbmd0aGApCiAgICoKICAgKiBOb3RlOiB0aGlzIGltcGxlbWVudGF0aW9uIG9ubHkgYWNjZXB0cyBub3JtYWxpemVkIHBhdGhzCiAgICoKICAgKiBAcGFyYW0geyFQcm9wZXJ0eUVmZmVjdHNUeXBlfSBpbnN0IEluc3RhbmNlIHRvIHNlbmQgbm90aWZpY2F0aW9ucyB0bwogICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0aGUgbXV0YXRpb25zIG9jY3VycmVkIG9uCiAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggVGhlIHBhdGggdG8gdGhlIGFycmF5IHRoYXQgd2FzIG11dGF0ZWQKICAgKiBAcGFyYW0ge0FycmF5fSBzcGxpY2VzIEFycmF5IG9mIHNwbGljZSByZWNvcmRzCiAgICogQHJldHVybiB7dm9pZH0KICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIG5vdGlmeVNwbGljZXMoaW5zdCwgYXJyYXksIHBhdGgsIHNwbGljZXMpIHsKICAgIGxldCBzcGxpY2VzUGF0aCA9IHBhdGggKyAnLnNwbGljZXMnOwogICAgaW5zdC5ub3RpZnlQYXRoKHNwbGljZXNQYXRoLCB7IGluZGV4U3BsaWNlczogc3BsaWNlcyB9KTsKICAgIGluc3Qubm90aWZ5UGF0aChwYXRoICsgJy5sZW5ndGgnLCBhcnJheS5sZW5ndGgpOwogICAgLy8gTnVsbCBoZXJlIHRvIGFsbG93IHBvdGVudGlhbGx5IGxhcmdlIHNwbGljZSByZWNvcmRzIHRvIGJlIEdDJ2VkLgogICAgaW5zdC5fX2RhdGFbc3BsaWNlc1BhdGhdID0ge2luZGV4U3BsaWNlczogbnVsbH07CiAgfQoKICAvKioKICAgKiBDcmVhdGVzIGEgc3BsaWNlIHJlY29yZCBhbmQgc2VuZHMgYW4gYXJyYXkgc3BsaWNlIG5vdGlmaWNhdGlvbiBmb3IKICAgKiB0aGUgZGVzY3JpYmVkIG11dGF0aW9uCiAgICoKICAgKiBOb3RlOiB0aGlzIGltcGxlbWVudGF0aW9uIG9ubHkgYWNjZXB0cyBub3JtYWxpemVkIHBhdGhzCiAgICoKICAgKiBAcGFyYW0geyFQcm9wZXJ0eUVmZmVjdHNUeXBlfSBpbnN0IEluc3RhbmNlIHRvIHNlbmQgbm90aWZpY2F0aW9ucyB0bwogICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0aGUgbXV0YXRpb25zIG9jY3VycmVkIG9uCiAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggVGhlIHBhdGggdG8gdGhlIGFycmF5IHRoYXQgd2FzIG11dGF0ZWQKICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggSW5kZXggYXQgd2hpY2ggdGhlIGFycmF5IG11dGF0aW9uIG9jY3VycmVkCiAgICogQHBhcmFtIHtudW1iZXJ9IGFkZGVkQ291bnQgTnVtYmVyIG9mIGFkZGVkIGl0ZW1zCiAgICogQHBhcmFtIHtBcnJheX0gcmVtb3ZlZCBBcnJheSBvZiByZW1vdmVkIGl0ZW1zCiAgICogQHJldHVybiB7dm9pZH0KICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIG5vdGlmeVNwbGljZShpbnN0LCBhcnJheSwgcGF0aCwgaW5kZXgsIGFkZGVkQ291bnQsIHJlbW92ZWQpIHsKICAgIG5vdGlmeVNwbGljZXMoaW5zdCwgYXJyYXksIHBhdGgsIFt7CiAgICAgIGluZGV4OiBpbmRleCwKICAgICAgYWRkZWRDb3VudDogYWRkZWRDb3VudCwKICAgICAgcmVtb3ZlZDogcmVtb3ZlZCwKICAgICAgb2JqZWN0OiBhcnJheSwKICAgICAgdHlwZTogJ3NwbGljZScKICAgIH1dKTsKICB9CgogIC8qKgogICAqIFJldHVybnMgYW4gdXBwZXItY2FzZWQgdmVyc2lvbiBvZiB0aGUgc3RyaW5nLgogICAqCiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgU3RyaW5nIHRvIHVwcGVyY2FzZQogICAqIEByZXR1cm4ge3N0cmluZ30gVXBwZXJjYXNlZCBzdHJpbmcKICAgKiBAcHJpdmF0ZQogICAqLwogIGZ1bmN0aW9uIHVwcGVyKG5hbWUpIHsKICAgIHJldHVybiBuYW1lWzBdLnRvVXBwZXJDYXNlKCkgKyBuYW1lLnN1YnN0cmluZygxKTsKICB9CgogIC8qKgogICAqIEVsZW1lbnQgY2xhc3MgbWl4aW4gdGhhdCBwcm92aWRlcyBtZXRhLXByb2dyYW1taW5nIGZvciBQb2x5bWVyJ3MgdGVtcGxhdGUKICAgKiBiaW5kaW5nIGFuZCBkYXRhIG9ic2VydmF0aW9uIChjb2xsZWN0aXZlbHksICJwcm9wZXJ0eSBlZmZlY3RzIikgc3lzdGVtLgogICAqCiAgICogVGhpcyBtaXhpbiB1c2VzIHByb3ZpZGVzIHRoZSBmb2xsb3dpbmcga2V5IHN0YXRpYyBtZXRob2RzIGZvciBhZGRpbmcKICAgKiBwcm9wZXJ0eSBlZmZlY3RzIHRvIGFuIGVsZW1lbnQgY2xhc3M6CiAgICogLSBgYWRkUHJvcGVydHlFZmZlY3RgCiAgICogLSBgY3JlYXRlUHJvcGVydHlPYnNlcnZlcmAKICAgKiAtIGBjcmVhdGVNZXRob2RPYnNlcnZlcmAKICAgKiAtIGBjcmVhdGVOb3RpZnlpbmdQcm9wZXJ0eWAKICAgKiAtIGBjcmVhdGVSZWFkT25seVByb3BlcnR5YAogICAqIC0gYGNyZWF0ZVJlZmxlY3RlZFByb3BlcnR5YAogICAqIC0gYGNyZWF0ZUNvbXB1dGVkUHJvcGVydHlgCiAgICogLSBgYmluZFRlbXBsYXRlYAogICAqCiAgICogRWFjaCBtZXRob2QgY3JlYXRlcyBvbmUgb3IgbW9yZSBwcm9wZXJ0eSBhY2Nlc3NvcnMsIGFsb25nIHdpdGggbWV0YWRhdGEKICAgKiB1c2VkIGJ5IHRoaXMgbWl4aW4ncyBpbXBsZW1lbnRhdGlvbiBvZiBgX3Byb3BlcnRpZXNDaGFuZ2VkYCB0byBwZXJmb3JtCiAgICogdGhlIHByb3BlcnR5IGVmZmVjdHMuCiAgICoKICAgKiBVbmRlcnNjb3JlZCB2ZXJzaW9ucyBvZiB0aGUgYWJvdmUgbWV0aG9kcyBhbHNvIGV4aXN0IG9uIHRoZSBlbGVtZW50CiAgICogcHJvdG90eXBlIGZvciBhZGRpbmcgcHJvcGVydHkgZWZmZWN0cyBvbiBpbnN0YW5jZXMgYXQgcnVudGltZS4KICAgKgogICAqIE5vdGUgdGhhdCB0aGlzIG1peGluIG92ZXJyaWRlcyBzZXZlcmFsIGBQcm9wZXJ0eUFjY2Vzc29yc2AgbWV0aG9kcywgaW4KICAgKiBtYW55IGNhc2VzIHRvIG1haW50YWluIGd1YXJhbnRlZXMgcHJvdmlkZWQgYnkgdGhlIFBvbHltZXIgMS54IGZlYXR1cmVzOwogICAqIG5vdGFibHkgaXQgY2hhbmdlcyBwcm9wZXJ0eSBhY2Nlc3NvcnMgdG8gYmUgc3luY2hyb25vdXMgYnkgZGVmYXVsdAogICAqIHdoZXJlYXMgdGhlIGRlZmF1bHQgd2hlbiB1c2luZyBgUHJvcGVydHlBY2Nlc3NvcnNgIHN0YW5kYWxvbmUgaXMgdG8gYmUKICAgKiBhc3luYyBieSBkZWZhdWx0LgogICAqCiAgICogQG1peGluRnVuY3Rpb24KICAgKiBAcG9seW1lcgogICAqIEBhcHBsaWVzTWl4aW4gUG9seW1lci5UZW1wbGF0ZVN0YW1wCiAgICogQGFwcGxpZXNNaXhpbiBQb2x5bWVyLlByb3BlcnR5QWNjZXNzb3JzCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBFbGVtZW50IGNsYXNzIG1peGluIHRoYXQgcHJvdmlkZXMgbWV0YS1wcm9ncmFtbWluZyBmb3IgUG9seW1lcidzCiAgICogdGVtcGxhdGUgYmluZGluZyBhbmQgZGF0YSBvYnNlcnZhdGlvbiBzeXN0ZW0uCiAgICovCiAgUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHMgPSBQb2x5bWVyLmRlZHVwaW5nTWl4aW4oc3VwZXJDbGFzcyA9PiB7CgogICAgLyoqCiAgICAgKiBAY29uc3RydWN0b3IKICAgICAqIEBleHRlbmRzIHtzdXBlckNsYXNzfQogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfUHJvcGVydHlBY2Nlc3NvcnN9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9UZW1wbGF0ZVN0YW1wfQogICAgICogQHVucmVzdHJpY3RlZAogICAgICogQHByaXZhdGUKICAgICAqLwogICAgY29uc3QgcHJvcGVydHlFZmZlY3RzQmFzZSA9IFBvbHltZXIuVGVtcGxhdGVTdGFtcChQb2x5bWVyLlByb3BlcnR5QWNjZXNzb3JzKHN1cGVyQ2xhc3MpKTsKCiAgICAvKioKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAbWl4aW5DbGFzcwogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfUHJvcGVydHlFZmZlY3RzfQogICAgICogQGV4dGVuZHMge3Byb3BlcnR5RWZmZWN0c0Jhc2V9CiAgICAgKiBAdW5yZXN0cmljdGVkCiAgICAgKi8KICAgIGNsYXNzIFByb3BlcnR5RWZmZWN0cyBleHRlbmRzIHByb3BlcnR5RWZmZWN0c0Jhc2UgewoKICAgICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgc3VwZXIoKTsKICAgICAgICAvKiogQHR5cGUge2Jvb2xlYW59ICovCiAgICAgICAgLy8gVXNlZCB0byBpZGVudGlmeSB1c2VycyBvZiB0aGlzIG1peGluLCBhbGEgaW5zdGFuY2VvZgogICAgICAgIHRoaXMuX19pc1Byb3BlcnR5RWZmZWN0c0NsaWVudCA9IHRydWU7CiAgICAgICAgLyoqIEB0eXBlIHtudW1iZXJ9ICovCiAgICAgICAgLy8gTk9URTogdXNlZCB0byB0cmFjayByZS1lbnRyYW50IGNhbGxzIHRvIGBfZmx1c2hQcm9wZXJ0aWVzYAogICAgICAgIC8vIHBhdGggY2hhbmdlcyBkaXJ0eSBjaGVjayBhZ2FpbnN0IGBfX2RhdGFUZW1wYCBvbmx5IGR1cmluZyBvbmUgInR1cm4iCiAgICAgICAgLy8gYW5kIGFyZSBjbGVhcmVkIHdoZW4gYF9fZGF0YUNvdW50ZXJgIHJldHVybnMgdG8gMC4KICAgICAgICB0aGlzLl9fZGF0YUNvdW50ZXIgPSAwOwogICAgICAgIC8qKiBAdHlwZSB7Ym9vbGVhbn0gKi8KICAgICAgICB0aGlzLl9fZGF0YUNsaWVudHNSZWFkeTsKICAgICAgICAvKiogQHR5cGUge0FycmF5fSAqLwogICAgICAgIHRoaXMuX19kYXRhUGVuZGluZ0NsaWVudHM7CiAgICAgICAgLyoqIEB0eXBlIHtPYmplY3R9ICovCiAgICAgICAgdGhpcy5fX2RhdGFUb05vdGlmeTsKICAgICAgICAvKiogQHR5cGUge09iamVjdH0gKi8KICAgICAgICB0aGlzLl9fZGF0YUxpbmtlZFBhdGhzOwogICAgICAgIC8qKiBAdHlwZSB7Ym9vbGVhbn0gKi8KICAgICAgICB0aGlzLl9fZGF0YUhhc1BhdGhzOwogICAgICAgIC8qKiBAdHlwZSB7T2JqZWN0fSAqLwogICAgICAgIHRoaXMuX19kYXRhQ29tcG91bmRTdG9yYWdlOwogICAgICAgIC8qKiBAdHlwZSB7UG9seW1lcl9Qcm9wZXJ0eUVmZmVjdHN9ICovCiAgICAgICAgdGhpcy5fX2RhdGFIb3N0OwogICAgICAgIC8qKiBAdHlwZSB7IU9iamVjdH0gKi8KICAgICAgICB0aGlzLl9fZGF0YVRlbXA7CiAgICAgICAgLyoqIEB0eXBlIHtib29sZWFufSAqLwogICAgICAgIHRoaXMuX19kYXRhQ2xpZW50c0luaXRpYWxpemVkOwogICAgICAgIC8qKiBAdHlwZSB7IU9iamVjdH0gKi8KICAgICAgICB0aGlzLl9fZGF0YTsKICAgICAgICAvKiogQHR5cGUgeyFPYmplY3R9ICovCiAgICAgICAgdGhpcy5fX2RhdGFQZW5kaW5nOwogICAgICAgIC8qKiBAdHlwZSB7IU9iamVjdH0gKi8KICAgICAgICB0aGlzLl9fZGF0YU9sZDsKICAgICAgICAvKiogQHR5cGUge09iamVjdH0gKi8KICAgICAgICB0aGlzLl9fY29tcHV0ZUVmZmVjdHM7CiAgICAgICAgLyoqIEB0eXBlIHtPYmplY3R9ICovCiAgICAgICAgdGhpcy5fX3JlZmxlY3RFZmZlY3RzOwogICAgICAgIC8qKiBAdHlwZSB7T2JqZWN0fSAqLwogICAgICAgIHRoaXMuX19ub3RpZnlFZmZlY3RzOwogICAgICAgIC8qKiBAdHlwZSB7T2JqZWN0fSAqLwogICAgICAgIHRoaXMuX19wcm9wYWdhdGVFZmZlY3RzOwogICAgICAgIC8qKiBAdHlwZSB7T2JqZWN0fSAqLwogICAgICAgIHRoaXMuX19vYnNlcnZlRWZmZWN0czsKICAgICAgICAvKiogQHR5cGUge09iamVjdH0gKi8KICAgICAgICB0aGlzLl9fcmVhZE9ubHk7CiAgICAgICAgLyoqIEB0eXBlIHshVGVtcGxhdGVJbmZvfSAqLwogICAgICAgIHRoaXMuX190ZW1wbGF0ZUluZm87CiAgICAgIH0KCiAgICAgIGdldCBQUk9QRVJUWV9FRkZFQ1RfVFlQRVMoKSB7CiAgICAgICAgcmV0dXJuIFRZUEVTOwogICAgICB9CgogICAgICAvKioKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9pbml0aWFsaXplUHJvcGVydGllcygpIHsKICAgICAgICBzdXBlci5faW5pdGlhbGl6ZVByb3BlcnRpZXMoKTsKICAgICAgICBob3N0U3RhY2sucmVnaXN0ZXJIb3N0KHRoaXMpOwogICAgICAgIHRoaXMuX19kYXRhQ2xpZW50c1JlYWR5ID0gZmFsc2U7CiAgICAgICAgdGhpcy5fX2RhdGFQZW5kaW5nQ2xpZW50cyA9IG51bGw7CiAgICAgICAgdGhpcy5fX2RhdGFUb05vdGlmeSA9IG51bGw7CiAgICAgICAgdGhpcy5fX2RhdGFMaW5rZWRQYXRocyA9IG51bGw7CiAgICAgICAgdGhpcy5fX2RhdGFIYXNQYXRocyA9IGZhbHNlOwogICAgICAgIC8vIE1heSBiZSBzZXQgb24gaW5zdGFuY2UgcHJpb3IgdG8gdXBncmFkZQogICAgICAgIHRoaXMuX19kYXRhQ29tcG91bmRTdG9yYWdlID0gdGhpcy5fX2RhdGFDb21wb3VuZFN0b3JhZ2UgfHwgbnVsbDsKICAgICAgICB0aGlzLl9fZGF0YUhvc3QgPSB0aGlzLl9fZGF0YUhvc3QgfHwgbnVsbDsKICAgICAgICB0aGlzLl9fZGF0YVRlbXAgPSB7fTsKICAgICAgICB0aGlzLl9fZGF0YUNsaWVudHNJbml0aWFsaXplZCA9IGZhbHNlOwogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGVzIGBQb2x5bWVyLlByb3BlcnR5QWNjZXNzb3JzYCBpbXBsZW1lbnRhdGlvbiB0byBwcm92aWRlIGEKICAgICAgICogbW9yZSBlZmZpY2llbnQgaW1wbGVtZW50YXRpb24gb2YgaW5pdGlhbGl6aW5nIHByb3BlcnRpZXMgZnJvbQogICAgICAgKiB0aGUgcHJvdG90eXBlIG9uIHRoZSBpbnN0YW5jZS4KICAgICAgICoKICAgICAgICogQG92ZXJyaWRlCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwcm9wcyBQcm9wZXJ0aWVzIHRvIGluaXRpYWxpemUgb24gdGhlIHByb3RvdHlwZQogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX2luaXRpYWxpemVQcm90b1Byb3BlcnRpZXMocHJvcHMpIHsKICAgICAgICB0aGlzLl9fZGF0YSA9IE9iamVjdC5jcmVhdGUocHJvcHMpOwogICAgICAgIHRoaXMuX19kYXRhUGVuZGluZyA9IE9iamVjdC5jcmVhdGUocHJvcHMpOwogICAgICAgIHRoaXMuX19kYXRhT2xkID0ge307CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZXMgYFBvbHltZXIuUHJvcGVydHlBY2Nlc3NvcnNgIGltcGxlbWVudGF0aW9uIHRvIGF2b2lkIHNldHRpbmcKICAgICAgICogYF9zZXRQcm9wZXJ0eWAncyBgc2hvdWxkTm90aWZ5OiB0cnVlYC4KICAgICAgICoKICAgICAgICogQG92ZXJyaWRlCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwcm9wcyBQcm9wZXJ0aWVzIHRvIGluaXRpYWxpemUgb24gdGhlIGluc3RhbmNlCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBfaW5pdGlhbGl6ZUluc3RhbmNlUHJvcGVydGllcyhwcm9wcykgewogICAgICAgIGxldCByZWFkT25seSA9IHRoaXNbVFlQRVMuUkVBRF9PTkxZXTsKICAgICAgICBmb3IgKGxldCBwcm9wIGluIHByb3BzKSB7CiAgICAgICAgICBpZiAoIXJlYWRPbmx5IHx8ICFyZWFkT25seVtwcm9wXSkgewogICAgICAgICAgICB0aGlzLl9fZGF0YVBlbmRpbmcgPSB0aGlzLl9fZGF0YVBlbmRpbmcgfHwge307CiAgICAgICAgICAgIHRoaXMuX19kYXRhT2xkID0gdGhpcy5fX2RhdGFPbGQgfHwge307CiAgICAgICAgICAgIHRoaXMuX19kYXRhW3Byb3BdID0gdGhpcy5fX2RhdGFQZW5kaW5nW3Byb3BdID0gcHJvcHNbcHJvcF07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CgogICAgICAvLyBQcm90b3R5cGUgc2V0dXAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKICAgICAgLyoqCiAgICAgICAqIEVxdWl2YWxlbnQgdG8gc3RhdGljIGBhZGRQcm9wZXJ0eUVmZmVjdGAgQVBJIGJ1dCBjYW4gYmUgY2FsbGVkIG9uCiAgICAgICAqIGFuIGluc3RhbmNlIHRvIGFkZCBlZmZlY3RzIGF0IHJ1bnRpbWUuICBTZWUgdGhhdCBtZXRob2QgZm9yCiAgICAgICAqIGZ1bGwgQVBJIGRvY3MuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSB0aGF0IHNob3VsZCB0cmlnZ2VyIHRoZSBlZmZlY3QKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgRWZmZWN0IHR5cGUsIGZyb20gdGhpcy5QUk9QRVJUWV9FRkZFQ1RfVFlQRVMKICAgICAgICogQHBhcmFtIHtPYmplY3Q9fSBlZmZlY3QgRWZmZWN0IG1ldGFkYXRhIG9iamVjdAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBfYWRkUHJvcGVydHlFZmZlY3QocHJvcGVydHksIHR5cGUsIGVmZmVjdCkgewogICAgICAgIHRoaXMuX2NyZWF0ZVByb3BlcnR5QWNjZXNzb3IocHJvcGVydHksIHR5cGUgPT0gVFlQRVMuUkVBRF9PTkxZKTsKICAgICAgICAvLyBlZmZlY3RzIGFyZSBhY2N1bXVsYXRlZCBpbnRvIGFycmF5cyBwZXIgcHJvcGVydHkgYmFzZWQgb24gdHlwZQogICAgICAgIGxldCBlZmZlY3RzID0gZW5zdXJlT3duRWZmZWN0TWFwKHRoaXMsIHR5cGUpW3Byb3BlcnR5XTsKICAgICAgICBpZiAoIWVmZmVjdHMpIHsKICAgICAgICAgIGVmZmVjdHMgPSB0aGlzW3R5cGVdW3Byb3BlcnR5XSA9IFtdOwogICAgICAgIH0KICAgICAgICBlZmZlY3RzLnB1c2goZWZmZWN0KTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJlbW92ZXMgdGhlIGdpdmVuIHByb3BlcnR5IGVmZmVjdC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IHRoZSBlZmZlY3Qgd2FzIGFzc29jaWF0ZWQgd2l0aAogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdHlwZSBFZmZlY3QgdHlwZSwgZnJvbSB0aGlzLlBST1BFUlRZX0VGRkVDVF9UWVBFUwogICAgICAgKiBAcGFyYW0ge09iamVjdD19IGVmZmVjdCBFZmZlY3QgbWV0YWRhdGEgb2JqZWN0IHRvIHJlbW92ZQogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX3JlbW92ZVByb3BlcnR5RWZmZWN0KHByb3BlcnR5LCB0eXBlLCBlZmZlY3QpIHsKICAgICAgICBsZXQgZWZmZWN0cyA9IGVuc3VyZU93bkVmZmVjdE1hcCh0aGlzLCB0eXBlKVtwcm9wZXJ0eV07CiAgICAgICAgbGV0IGlkeCA9IGVmZmVjdHMuaW5kZXhPZihlZmZlY3QpOwogICAgICAgIGlmIChpZHggPj0gMCkgewogICAgICAgICAgZWZmZWN0cy5zcGxpY2UoaWR4LCAxKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhlIGN1cnJlbnQgcHJvdG90eXBlL2luc3RhbmNlIGhhcyBhIHByb3BlcnR5IGVmZmVjdAogICAgICAgKiBvZiBhIGNlcnRhaW4gdHlwZS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSB0eXBlIEVmZmVjdCB0eXBlLCBmcm9tIHRoaXMuUFJPUEVSVFlfRUZGRUNUX1RZUEVTCiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIHByb3RvdHlwZS9pbnN0YW5jZSBoYXMgYW4gZWZmZWN0IG9mIHRoaXMgdHlwZQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBfaGFzUHJvcGVydHlFZmZlY3QocHJvcGVydHksIHR5cGUpIHsKICAgICAgICBsZXQgZWZmZWN0cyA9IHRoaXNbdHlwZV07CiAgICAgICAgcmV0dXJuIEJvb2xlYW4oZWZmZWN0cyAmJiBlZmZlY3RzW3Byb3BlcnR5XSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhlIGN1cnJlbnQgcHJvdG90eXBlL2luc3RhbmNlIGhhcyBhICJyZWFkIG9ubHkiCiAgICAgICAqIGFjY2Vzc29yIGZvciB0aGUgZ2l2ZW4gcHJvcGVydHkuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSBuYW1lCiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIHByb3RvdHlwZS9pbnN0YW5jZSBoYXMgYW4gZWZmZWN0IG9mIHRoaXMgdHlwZQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBfaGFzUmVhZE9ubHlFZmZlY3QocHJvcGVydHkpIHsKICAgICAgICByZXR1cm4gdGhpcy5faGFzUHJvcGVydHlFZmZlY3QocHJvcGVydHksIFRZUEVTLlJFQURfT05MWSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHdoZXRoZXIgdGhlIGN1cnJlbnQgcHJvdG90eXBlL2luc3RhbmNlIGhhcyBhICJub3RpZnkiCiAgICAgICAqIHByb3BlcnR5IGVmZmVjdCBmb3IgdGhlIGdpdmVuIHByb3BlcnR5LgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgUHJvcGVydHkgbmFtZQogICAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBwcm90b3R5cGUvaW5zdGFuY2UgaGFzIGFuIGVmZmVjdCBvZiB0aGlzIHR5cGUKICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX2hhc05vdGlmeUVmZmVjdChwcm9wZXJ0eSkgewogICAgICAgIHJldHVybiB0aGlzLl9oYXNQcm9wZXJ0eUVmZmVjdChwcm9wZXJ0eSwgVFlQRVMuTk9USUZZKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgd2hldGhlciB0aGUgY3VycmVudCBwcm90b3R5cGUvaW5zdGFuY2UgaGFzIGEgInJlZmxlY3QgdG8gYXR0cmlidXRlIgogICAgICAgKiBwcm9wZXJ0eSBlZmZlY3QgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgcHJvdG90eXBlL2luc3RhbmNlIGhhcyBhbiBlZmZlY3Qgb2YgdGhpcyB0eXBlCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9oYXNSZWZsZWN0RWZmZWN0KHByb3BlcnR5KSB7CiAgICAgICAgcmV0dXJuIHRoaXMuX2hhc1Byb3BlcnR5RWZmZWN0KHByb3BlcnR5LCBUWVBFUy5SRUZMRUNUKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgd2hldGhlciB0aGUgY3VycmVudCBwcm90b3R5cGUvaW5zdGFuY2UgaGFzIGEgImNvbXB1dGVkIgogICAgICAgKiBwcm9wZXJ0eSBlZmZlY3QgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgcHJvdG90eXBlL2luc3RhbmNlIGhhcyBhbiBlZmZlY3Qgb2YgdGhpcyB0eXBlCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9oYXNDb21wdXRlZEVmZmVjdChwcm9wZXJ0eSkgewogICAgICAgIHJldHVybiB0aGlzLl9oYXNQcm9wZXJ0eUVmZmVjdChwcm9wZXJ0eSwgVFlQRVMuQ09NUFVURSk7CiAgICAgIH0KCiAgICAgIC8vIFJ1bnRpbWUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKICAgICAgLyoqCiAgICAgICAqIFNldHMgYSBwZW5kaW5nIHByb3BlcnR5IG9yIHBhdGguICBJZiB0aGUgcm9vdCBwcm9wZXJ0eSBvZiB0aGUgcGF0aCBpbgogICAgICAgKiBxdWVzdGlvbiBoYWQgbm8gYWNjZXNzb3IsIHRoZSBwYXRoIGlzIHNldCwgb3RoZXJ3aXNlIGl0IGlzIGVucXVldWVkCiAgICAgICAqIHZpYSBgX3NldFBlbmRpbmdQcm9wZXJ0eWAuCiAgICAgICAqCiAgICAgICAqIFRoaXMgZnVuY3Rpb24gaXNvbGF0ZXMgcmVsYXRpdmVseSBleHBlbnNpdmUgZnVuY3Rpb25hbGl0eSBuZWNlc3NhcnkKICAgICAgICogZm9yIHRoZSBwdWJsaWMgQVBJIChgc2V0YCwgYHNldFByb3BlcnRpZXNgLCBgbm90aWZ5UGF0aGAsIGFuZCBwcm9wZXJ0eQogICAgICAgKiBjaGFuZ2UgbGlzdGVuZXJzIHZpYSB7ey4uLn19IGJpbmRpbmdzKSwgc3VjaCB0aGF0IGl0IGlzIG9ubHkgZG9uZQogICAgICAgKiB3aGVuIHBhdGhzIGVudGVyIHRoZSBzeXN0ZW0sIGFuZCBub3QgYXQgZXZlcnkgcHJvcGFnYXRpb24gc3RlcC4gIEl0CiAgICAgICAqIGFsc28gc2V0cyBhIGBfX2RhdGFIYXNQYXRoc2AgZmxhZyBvbiB0aGUgaW5zdGFuY2Ugd2hpY2ggaXMgdXNlZCB0bwogICAgICAgKiBmYXN0LXBhdGggc2xvd2VyIHBhdGgtbWF0Y2hpbmcgY29kZSBpbiB0aGUgcHJvcGVydHkgZWZmZWN0cyBob3N0IHBhdGhzLgogICAgICAgKgogICAgICAgKiBgcGF0aGAgY2FuIGJlIGEgcGF0aCBzdHJpbmcgb3IgYXJyYXkgb2YgcGF0aCBwYXJ0cyBhcyBhY2NlcHRlZCBieSB0aGUKICAgICAgICogcHVibGljIEFQSS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmcgfCAhQXJyYXk8bnVtYmVyfHN0cmluZz59IHBhdGggUGF0aCB0byBzZXQKICAgICAgICogQHBhcmFtIHsqfSB2YWx1ZSBWYWx1ZSB0byBzZXQKICAgICAgICogQHBhcmFtIHtib29sZWFuPX0gc2hvdWxkTm90aWZ5IFNldCB0byB0cnVlIGlmIHRoaXMgY2hhbmdlIHNob3VsZAogICAgICAgKiAgY2F1c2UgYSBwcm9wZXJ0eSBub3RpZmljYXRpb24gZXZlbnQgZGlzcGF0Y2gKICAgICAgICogQHBhcmFtIHtib29sZWFuPX0gaXNQYXRoTm90aWZpY2F0aW9uIElmIHRoZSBwYXRoIGJlaW5nIHNldCBpcyBhIHBhdGgKICAgICAgICogICBub3RpZmljYXRpb24gb2YgYW4gYWxyZWFkeSBjaGFuZ2VkIHZhbHVlLCBhcyBvcHBvc2VkIHRvIGEgcmVxdWVzdAogICAgICAgKiAgIHRvIHNldCBhbmQgbm90aWZ5IHRoZSBjaGFuZ2UuICBJbiB0aGUgbGF0dGVyIGBmYWxzZWAgY2FzZSwgYSBkaXJ0eQogICAgICAgKiAgIGNoZWNrIGlzIHBlcmZvcm1lZCBhbmQgdGhlbiB0aGUgdmFsdWUgaXMgc2V0IHRvIHRoZSBwYXRoIGJlZm9yZQogICAgICAgKiAgIGVucXVldWluZyB0aGUgcGVuZGluZyBwcm9wZXJ0eSBjaGFuZ2UuCiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFJldHVybnMgdHJ1ZSBpZiB0aGUgcHJvcGVydHkvcGF0aCB3YXMgZW5xdWV1ZWQgaW4KICAgICAgICogICB0aGUgcGVuZGluZyBjaGFuZ2VzIGJhZy4KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX3NldFBlbmRpbmdQcm9wZXJ0eU9yUGF0aChwYXRoLCB2YWx1ZSwgc2hvdWxkTm90aWZ5LCBpc1BhdGhOb3RpZmljYXRpb24pIHsKICAgICAgICBpZiAoaXNQYXRoTm90aWZpY2F0aW9uIHx8CiAgICAgICAgICAgIFBvbHltZXIuUGF0aC5yb290KEFycmF5LmlzQXJyYXkocGF0aCkgPyBwYXRoWzBdIDogcGF0aCkgIT09IHBhdGgpIHsKICAgICAgICAgIC8vIERpcnR5IGNoZWNrIGNoYW5nZXMgYmVpbmcgc2V0IHRvIGEgcGF0aCBhZ2FpbnN0IHRoZSBhY3R1YWwgb2JqZWN0LAogICAgICAgICAgLy8gc2luY2UgdGhpcyBpcyB0aGUgZW50cnkgcG9pbnQgZm9yIHBhdGhzIGludG8gdGhlIHN5c3RlbTsgZnJvbSBoZXJlCiAgICAgICAgICAvLyB0aGUgb25seSBkaXJ0eSBjaGVja3MgYXJlIGFnYWluc3QgdGhlIGBfX2RhdGFUZW1wYCBjYWNoZSB0byBwcmV2ZW50CiAgICAgICAgICAvLyBkdXBsaWNhdGUgd29yayBpbiB0aGUgc2FtZSB0dXJuIG9ubHkuIE5vdGUsIGlmIHRoaXMgd2FzIGEgbm90aWZpY2F0aW9uCiAgICAgICAgICAvLyBvZiBhIGNoYW5nZSBhbHJlYWR5IHNldCB0byBhIHBhdGggKGlzUGF0aE5vdGlmaWNhdGlvbjogdHJ1ZSksCiAgICAgICAgICAvLyB3ZSBhbHdheXMgbGV0IHRoZSBjaGFuZ2UgdGhyb3VnaCBhbmQgc2tpcCB0aGUgYHNldGAgc2luY2UgaXQgd2FzCiAgICAgICAgICAvLyBhbHJlYWR5IGRpcnR5IGNoZWNrZWQgYXQgdGhlIHBvaW50IG9mIGVudHJ5IGFuZCB0aGUgdW5kZXJseWluZwogICAgICAgICAgLy8gb2JqZWN0IGhhcyBhbHJlYWR5IGJlZW4gdXBkYXRlZAogICAgICAgICAgaWYgKCFpc1BhdGhOb3RpZmljYXRpb24pIHsKICAgICAgICAgICAgbGV0IG9sZCA9IFBvbHltZXIuUGF0aC5nZXQodGhpcywgcGF0aCk7CiAgICAgICAgICAgIHBhdGggPSAvKiogQHR5cGUge3N0cmluZ30gKi8gKFBvbHltZXIuUGF0aC5zZXQodGhpcywgcGF0aCwgdmFsdWUpKTsKICAgICAgICAgICAgLy8gVXNlIHByb3BlcnR5LWFjY2Vzc29yJ3Mgc2ltcGxlciBkaXJ0eSBjaGVjawogICAgICAgICAgICBpZiAoIXBhdGggfHwgIXN1cGVyLl9zaG91bGRQcm9wZXJ0eUNoYW5nZShwYXRoLCB2YWx1ZSwgb2xkKSkgewogICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgdGhpcy5fX2RhdGFIYXNQYXRocyA9IHRydWU7CiAgICAgICAgICBpZiAodGhpcy5fc2V0UGVuZGluZ1Byb3BlcnR5KC8qKkB0eXBle3N0cmluZ30qLyhwYXRoKSwgdmFsdWUsIHNob3VsZE5vdGlmeSkpIHsKICAgICAgICAgICAgY29tcHV0ZUxpbmtlZFBhdGhzKHRoaXMsIHBhdGgsIHZhbHVlKTsKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGlmICh0aGlzLl9fZGF0YUhhc0FjY2Vzc29yICYmIHRoaXMuX19kYXRhSGFzQWNjZXNzb3JbcGF0aF0pIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3NldFBlbmRpbmdQcm9wZXJ0eSgvKipAdHlwZXtzdHJpbmd9Ki8ocGF0aCksIHZhbHVlLCBzaG91bGROb3RpZnkpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdGhpc1twYXRoXSA9IHZhbHVlOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBBcHBsaWVzIGEgdmFsdWUgdG8gYSBub24tUG9seW1lciBlbGVtZW50L25vZGUncyBwcm9wZXJ0eS4KICAgICAgICoKICAgICAgICogVGhlIGltcGxlbWVudGF0aW9uIG1ha2VzIGEgYmVzdC1lZmZvcnQgYXQgYmluZGluZyBpbnRlcm9wOgogICAgICAgKiBTb21lIG5hdGl2ZSBlbGVtZW50IHByb3BlcnRpZXMgaGF2ZSBzaWRlLWVmZmVjdHMgd2hlbgogICAgICAgKiByZS1zZXR0aW5nIHRoZSBzYW1lIHZhbHVlIChlLmcuIHNldHRpbmcgYDxpbnB1dD4udmFsdWVgIHJlc2V0cyB0aGUKICAgICAgICogY3Vyc29yIHBvc2l0aW9uKSwgc28gd2UgZG8gYSBkaXJ0eS1jaGVjayBiZWZvcmUgc2V0dGluZyB0aGUgdmFsdWUuCiAgICAgICAqIEhvd2V2ZXIsIGZvciBiZXR0ZXIgaW50ZXJvcCB3aXRoIG5vbi1Qb2x5bWVyIGN1c3RvbSBlbGVtZW50cyB0aGF0CiAgICAgICAqIGFjY2VwdCBvYmplY3RzLCB3ZSBleHBsaWNpdGx5IHJlLXNldCBvYmplY3QgY2hhbmdlcyBjb21pbmcgZnJvbSB0aGUKICAgICAgICogUG9seW1lciB3b3JsZCAod2hpY2ggbWF5IGluY2x1ZGUgZGVlcCBvYmplY3QgY2hhbmdlcyB3aXRob3V0IHRoZQogICAgICAgKiB0b3AgcmVmZXJlbmNlIGNoYW5naW5nKSwgZXJyaW5nIG9uIHRoZSBzaWRlIG9mIHByb3ZpZGluZyBtb3JlCiAgICAgICAqIGluZm9ybWF0aW9uLgogICAgICAgKgogICAgICAgKiBVc2VycyBtYXkgb3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gcHJvdmlkZSBhbHRlcm5hdGUgYXBwcm9hY2hlcy4KICAgICAgICoKICAgICAgICogQHBhcmFtIHshTm9kZX0gbm9kZSBUaGUgbm9kZSB0byBzZXQgYSBwcm9wZXJ0eSBvbgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcCBUaGUgcHJvcGVydHkgdG8gc2V0CiAgICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIHNldAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBfc2V0VW5tYW5hZ2VkUHJvcGVydHlUb05vZGUobm9kZSwgcHJvcCwgdmFsdWUpIHsKICAgICAgICAvLyBJdCBpcyBhIGp1ZGdtZW50IGNhbGwgdGhhdCByZXNldHRpbmcgcHJpbWl0aXZlcyBpcwogICAgICAgIC8vICJiYWQiIGFuZCByZXNldHRpbmdzIG9iamVjdHMgaXMgYWxzbyAiZ29vZCI7IGFsdGVybmF0aXZlbHkgd2UgY291bGQKICAgICAgICAvLyBpbXBsZW1lbnQgYSB3aGl0ZWxpc3Qgb2YgdGFnICYgcHJvcGVydHkgdmFsdWVzIHRoYXQgc2hvdWxkIG5ldmVyCiAgICAgICAgLy8gYmUgcmVzZXQgKGUuZy4gPGlucHV0Pi52YWx1ZSAmJiA8c2VsZWN0Pi52YWx1ZSkKICAgICAgICBpZiAodmFsdWUgIT09IG5vZGVbcHJvcF0gfHwgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnKSB7CiAgICAgICAgICBub2RlW3Byb3BdID0gdmFsdWU7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGVzIHRoZSBgUHJvcGVydGllc0NoYW5nZWRgIGltcGxlbWVudGF0aW9uIHRvIGludHJvZHVjZSBzcGVjaWFsCiAgICAgICAqIGRpcnR5IGNoZWNrIGxvZ2ljIGRlcGVuZGluZyBvbiB0aGUgcHJvcGVydHkgJiB2YWx1ZSBiZWluZyBzZXQ6CiAgICAgICAqCiAgICAgICAqIDEuIEFueSB2YWx1ZSBzZXQgdG8gYSBwYXRoIChlLmcuICdvYmoucHJvcCc6IDQyIG9yICdvYmoucHJvcCc6IHsuLi59KQogICAgICAgKiAgICBTdG9yZWQgaW4gYF9fZGF0YVRlbXBgLCBkaXJ0eSBjaGVja2VkIGFnYWluc3QgYF9fZGF0YVRlbXBgCiAgICAgICAqIDIuIE9iamVjdCBzZXQgdG8gc2ltcGxlIHByb3BlcnR5IChlLmcuICdwcm9wJzogey4uLn0pCiAgICAgICAqICAgIFN0b3JlZCBpbiBgX19kYXRhVGVtcGAgYW5kIGBfX2RhdGFgLCBkaXJ0eSBjaGVja2VkIGFnYWluc3QKICAgICAgICogICAgYF9fZGF0YVRlbXBgIGJ5IGRlZmF1bHQgaW1wbGVtZW50YXRpb24gb2YgYF9zaG91bGRQcm9wZXJ0eUNoYW5nZWAKICAgICAgICogMy4gUHJpbWl0aXZlIHZhbHVlIHNldCB0byBzaW1wbGUgcHJvcGVydHkgKGUuZy4gJ3Byb3AnOiA0MikKICAgICAgICogICAgU3RvcmVkIGluIGBfX2RhdGFgLCBkaXJ0eSBjaGVja2VkIGFnYWluc3QgYF9fZGF0YWAKICAgICAgICoKICAgICAgICogVGhlIGRpcnR5LWNoZWNrIGlzIGltcG9ydGFudCB0byBwcmV2ZW50IGN5Y2xlcyBkdWUgdG8gdHdvLXdheQogICAgICAgKiBub3RpZmljYXRpb24sIGJ1dCBwYXRocyBhbmQgb2JqZWN0cyBhcmUgb25seSBkaXJ0eSBjaGVja2VkIGFnYWluc3QgYW55CiAgICAgICAqIHByZXZpb3VzIHZhbHVlIHNldCBkdXJpbmcgdGhpcyB0dXJuIHZpYSBhICJ0ZW1wb3JhcnkgY2FjaGUiIHRoYXQgaXMKICAgICAgICogY2xlYXJlZCB3aGVuIHRoZSBsYXN0IGBfcHJvcGVydGllc0NoYW5nZWRgIGV4aXRzLiBUaGlzIGlzIHNvOgogICAgICAgKiBhLiBhbnkgY2FjaGVkIGFycmF5IHBhdGhzIChlLmcuICdhcnJheS4zLnByb3AnKSBtYXkgYmUgaW52YWxpZGF0ZWQKICAgICAgICogICAgZHVlIHRvIGFycmF5IG11dGF0aW9ucyBsaWtlIHNoaWZ0L3Vuc2hpZnQvc3BsaWNlOyB0aGlzIGlzIGZpbmUKICAgICAgICogICAgc2luY2UgcGF0aCBjaGFuZ2VzIGFyZSBkaXJ0eS1jaGVja2VkIGF0IHVzZXIgZW50cnkgcG9pbnRzIGxpa2UgYHNldGAKICAgICAgICogYi4gZGlydHktY2hlY2tpbmcgZm9yIG9iamVjdHMgb25seSBsYXN0cyBvbmUgdHVybiB0byBhbGxvdyB0aGUgdXNlcgogICAgICAgKiAgICB0byBtdXRhdGUgdGhlIG9iamVjdCBpbi1wbGFjZSBhbmQgcmUtc2V0IGl0IHdpdGggdGhlIHNhbWUgaWRlbnRpdHkKICAgICAgICogICAgYW5kIGhhdmUgYWxsIHN1Yi1wcm9wZXJ0aWVzIHJlLXByb3BhZ2F0ZWQgaW4gYSBzdWJzZXF1ZW50IHR1cm4uCiAgICAgICAqCiAgICAgICAqIFRoZSB0ZW1wIGNhY2hlIGlzIG5vdCBuZWNlc3NhcmlseSBzdWZmaWNpZW50IHRvIHByZXZlbnQgaW52YWxpZCBhcnJheQogICAgICAgKiBwYXRocywgc2luY2UgYSBzcGxpY2UgY2FuIGhhcHBlbiBkdXJpbmcgdGhlIHNhbWUgdHVybiAod2l0aCBwYXRob2xvZ2ljYWwKICAgICAgICogdXNlciBjb2RlKTsgd2UgY291bGQgaW50cm9kdWNlIGEgImZpeHVwIiBmb3IgdGVtcG9yYXJpbHkgY2FjaGVkIGFycmF5CiAgICAgICAqIHBhdGhzIGlmIG5lZWRlZDogaHR0cHM6Ly9naXRodWIuY29tL1BvbHltZXIvcG9seW1lci9pc3N1ZXMvNDIyNwogICAgICAgKgogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgdGhlIHByb3BlcnR5CiAgICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVmFsdWUgdG8gc2V0CiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbj19IHNob3VsZE5vdGlmeSBUcnVlIGlmIHByb3BlcnR5IHNob3VsZCBmaXJlIG5vdGlmaWNhdGlvbgogICAgICAgKiAgIGV2ZW50IChhcHBsaWVzIG9ubHkgZm9yIGBub3RpZnk6IHRydWVgIHByb3BlcnRpZXMpCiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFJldHVybnMgdHJ1ZSBpZiB0aGUgcHJvcGVydHkgY2hhbmdlZAogICAgICAgKi8KICAgICAgX3NldFBlbmRpbmdQcm9wZXJ0eShwcm9wZXJ0eSwgdmFsdWUsIHNob3VsZE5vdGlmeSkgewogICAgICAgIGxldCBpc1BhdGggPSB0aGlzLl9fZGF0YUhhc1BhdGhzICYmIFBvbHltZXIuUGF0aC5pc1BhdGgocHJvcGVydHkpOwogICAgICAgIGxldCBwcmV2UHJvcHMgPSBpc1BhdGggPyB0aGlzLl9fZGF0YVRlbXAgOiB0aGlzLl9fZGF0YTsKICAgICAgICBpZiAodGhpcy5fc2hvdWxkUHJvcGVydHlDaGFuZ2UocHJvcGVydHksIHZhbHVlLCBwcmV2UHJvcHNbcHJvcGVydHldKSkgewogICAgICAgICAgaWYgKCF0aGlzLl9fZGF0YVBlbmRpbmcpIHsKICAgICAgICAgICAgdGhpcy5fX2RhdGFQZW5kaW5nID0ge307CiAgICAgICAgICAgIHRoaXMuX19kYXRhT2xkID0ge307CiAgICAgICAgICB9CiAgICAgICAgICAvLyBFbnN1cmUgb2xkIGlzIGNhcHR1cmVkIGZyb20gdGhlIGxhc3QgdHVybgogICAgICAgICAgaWYgKCEocHJvcGVydHkgaW4gdGhpcy5fX2RhdGFPbGQpKSB7CiAgICAgICAgICAgIHRoaXMuX19kYXRhT2xkW3Byb3BlcnR5XSA9IHRoaXMuX19kYXRhW3Byb3BlcnR5XTsKICAgICAgICAgIH0KICAgICAgICAgIC8vIFBhdGhzIGFyZSBzdG9yZWQgaW4gdGVtcG9yYXJ5IGNhY2hlIChjbGVhcmVkIGF0IGVuZCBvZiB0dXJuKSwKICAgICAgICAgIC8vIHdoaWNoIGlzIHVzZWQgZm9yIGRpcnR5LWNoZWNraW5nLCBhbGwgb3RoZXJzIHN0b3JlZCBpbiBfX2RhdGEKICAgICAgICAgIGlmIChpc1BhdGgpIHsKICAgICAgICAgICAgdGhpcy5fX2RhdGFUZW1wW3Byb3BlcnR5XSA9IHZhbHVlOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdGhpcy5fX2RhdGFbcHJvcGVydHldID0gdmFsdWU7CiAgICAgICAgICB9CiAgICAgICAgICAvLyBBbGwgY2hhbmdlcyBnbyBpbnRvIHBlbmRpbmcgcHJvcGVydHkgYmFnLCBwYXNzZWQgdG8gX3Byb3BlcnRpZXNDaGFuZ2VkCiAgICAgICAgICB0aGlzLl9fZGF0YVBlbmRpbmdbcHJvcGVydHldID0gdmFsdWU7CiAgICAgICAgICAvLyBUcmFjayBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkIG5vdGlmeSBzZXBhcmF0ZWx5CiAgICAgICAgICBpZiAoaXNQYXRoIHx8ICh0aGlzW1RZUEVTLk5PVElGWV0gJiYgdGhpc1tUWVBFUy5OT1RJRlldW3Byb3BlcnR5XSkpIHsKICAgICAgICAgICAgdGhpcy5fX2RhdGFUb05vdGlmeSA9IHRoaXMuX19kYXRhVG9Ob3RpZnkgfHwge307CiAgICAgICAgICAgIHRoaXMuX19kYXRhVG9Ob3RpZnlbcHJvcGVydHldID0gc2hvdWxkTm90aWZ5OwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQogICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIE92ZXJyaWRlcyBiYXNlIGltcGxlbWVudGF0aW9uIHRvIGVuc3VyZSBhbGwgYWNjZXNzb3JzIHNldCBgc2hvdWxkTm90aWZ5YAogICAgICAgKiB0byB0cnVlLCBmb3IgcGVyLXByb3BlcnR5IG5vdGlmaWNhdGlvbiB0cmFja2luZy4KICAgICAgICoKICAgICAgICogQG92ZXJyaWRlCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBOYW1lIG9mIHRoZSBwcm9wZXJ0eQogICAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFZhbHVlIHRvIHNldAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX3NldFByb3BlcnR5KHByb3BlcnR5LCB2YWx1ZSkgewogICAgICAgIGlmICh0aGlzLl9zZXRQZW5kaW5nUHJvcGVydHkocHJvcGVydHksIHZhbHVlLCB0cnVlKSkgewogICAgICAgICAgdGhpcy5faW52YWxpZGF0ZVByb3BlcnRpZXMoKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZXMgYFByb3BlcnR5QWNjZXNzb3JgJ3MgZGVmYXVsdCBhc3luYyBxdWV1aW5nIG9mCiAgICAgICAqIGBfcHJvcGVydGllc0NoYW5nZWRgOiBpZiBgX19kYXRhUmVhZHlgIGlzIGZhbHNlIChoYXMgbm90IHlldCBiZWVuCiAgICAgICAqIG1hbnVhbGx5IGZsdXNoZWQpLCB0aGUgZnVuY3Rpb24gbm8tb3BzOyBvdGhlcndpc2UgZmx1c2hlcwogICAgICAgKiBgX3Byb3BlcnRpZXNDaGFuZ2VkYCBzeW5jaHJvbm91c2x5LgogICAgICAgKgogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9pbnZhbGlkYXRlUHJvcGVydGllcygpIHsKICAgICAgICBpZiAodGhpcy5fX2RhdGFSZWFkeSkgewogICAgICAgICAgdGhpcy5fZmx1c2hQcm9wZXJ0aWVzKCk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogRW5xdWV1ZXMgdGhlIGdpdmVuIGNsaWVudCBvbiBhIGxpc3Qgb2YgcGVuZGluZyBjbGllbnRzLCB3aG9zZQogICAgICAgKiBwZW5kaW5nIHByb3BlcnR5IGNoYW5nZXMgY2FuIGxhdGVyIGJlIGZsdXNoZWQgdmlhIGEgY2FsbCB0bwogICAgICAgKiBgX2ZsdXNoQ2xpZW50c2AuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjbGllbnQgUHJvcGVydHlFZmZlY3RzIGNsaWVudCB0byBlbnF1ZXVlCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9lbnF1ZXVlQ2xpZW50KGNsaWVudCkgewogICAgICAgIHRoaXMuX19kYXRhUGVuZGluZ0NsaWVudHMgPSB0aGlzLl9fZGF0YVBlbmRpbmdDbGllbnRzIHx8IFtdOwogICAgICAgIGlmIChjbGllbnQgIT09IHRoaXMpIHsKICAgICAgICAgIHRoaXMuX19kYXRhUGVuZGluZ0NsaWVudHMucHVzaChjbGllbnQpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIE92ZXJyaWRlcyBzdXBlcmNsYXNzIGltcGxlbWVudGF0aW9uLgogICAgICAgKgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBfZmx1c2hQcm9wZXJ0aWVzKCkgewogICAgICAgIHRoaXMuX19kYXRhQ291bnRlcisrOwogICAgICAgIHN1cGVyLl9mbHVzaFByb3BlcnRpZXMoKTsKICAgICAgICB0aGlzLl9fZGF0YUNvdW50ZXItLTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEZsdXNoZXMgYW55IGNsaWVudHMgcHJldmlvdXNseSBlbnF1ZXVlZCB2aWEgYF9lbnF1ZXVlQ2xpZW50YCwgY2F1c2luZwogICAgICAgKiB0aGVpciBgX2ZsdXNoUHJvcGVydGllc2AgbWV0aG9kIHRvIHJ1bi4KICAgICAgICoKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX2ZsdXNoQ2xpZW50cygpIHsKICAgICAgICBpZiAoIXRoaXMuX19kYXRhQ2xpZW50c1JlYWR5KSB7CiAgICAgICAgICB0aGlzLl9fZGF0YUNsaWVudHNSZWFkeSA9IHRydWU7CiAgICAgICAgICB0aGlzLl9yZWFkeUNsaWVudHMoKTsKICAgICAgICAgIC8vIE92ZXJyaWRlIHBvaW50IHdoZXJlIGFjY2Vzc29ycyBhcmUgdHVybmVkIG9uOyBpbXBvcnRhbnRseSwKICAgICAgICAgIC8vIHRoaXMgaXMgYWZ0ZXIgY2xpZW50cyBoYXZlIGZ1bGx5IHJlYWRpZWQsIHByb3ZpZGluZyBhIGd1YXJhbnRlZQogICAgICAgICAgLy8gdGhhdCBhbnkgcHJvcGVydHkgZWZmZWN0cyBvY2N1ciBvbmx5IGFmdGVyIGFsbCBjbGllbnRzIGFyZSByZWFkeS4KICAgICAgICAgIHRoaXMuX19kYXRhUmVhZHkgPSB0cnVlOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB0aGlzLl9fZW5hYmxlT3JGbHVzaENsaWVudHMoKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8vIE5PVEU6IFdlIGVuc3VyZSBjbGllbnRzIGVpdGhlciBlbmFibGUgb3IgZmx1c2ggYXMgYXBwcm9wcmlhdGUuIFRoaXMKICAgICAgLy8gaGFuZGxlcyB0d28gY29ybmVyIGNhc2VzOgogICAgICAvLyAoMSkgY2xpZW50cyBmbHVzaCBwcm9wZXJseSB3aGVuIGNvbm5lY3RlZC9lbmFibGVkIGJlZm9yZSB0aGUgaG9zdAogICAgICAvLyBlbmFibGVzOyBlLmcuCiAgICAgIC8vICAgKGEpIFRlbXBsYXRpemUgc3RhbXBzIHdpdGggbm8gcHJvcGVydGllcyBhbmQgZG9lcyBub3QgZmx1c2ggYW5kCiAgICAgIC8vICAgKGIpIHRoZSBpbnN0YW5jZSBpcyBpbnNlcnRlZCBpbnRvIGRvbSBhbmQKICAgICAgLy8gICAoYykgdGhlbiB0aGUgaW5zdGFuY2UgZmx1c2hlcy4KICAgICAgLy8gKDIpIGNsaWVudHMgZW5hYmxlIHByb3Blcmx5IHdoZW4gbm90IGNvbm5lY3RlZC9lbmFibGVkIHdoZW4gdGhlIGhvc3QKICAgICAgLy8gZmx1c2hlczsgZS5nLgogICAgICAvLyAgIChhKSBhIHRlbXBsYXRlIGlzIHJ1bnRpbWUgc3RhbXBlZCBhbmQgbm90IHlldCBjb25uZWN0ZWQvZW5hYmxlZAogICAgICAvLyAgIChiKSBhIGhvc3Qgc2V0cyBhIHByb3BlcnR5LCBjYXVzaW5nIHN0YW1wZWQgZG9tIHRvIGZsdXNoCiAgICAgIC8vICAgKGMpIHRoZSBzdGFtcGVkIGRvbSBlbmFibGVzLgogICAgICBfX2VuYWJsZU9yRmx1c2hDbGllbnRzKCkgewogICAgICAgIGxldCBjbGllbnRzID0gdGhpcy5fX2RhdGFQZW5kaW5nQ2xpZW50czsKICAgICAgICBpZiAoY2xpZW50cykgewogICAgICAgICAgdGhpcy5fX2RhdGFQZW5kaW5nQ2xpZW50cyA9IG51bGw7CiAgICAgICAgICBmb3IgKGxldCBpPTA7IGkgPCBjbGllbnRzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIGxldCBjbGllbnQgPSBjbGllbnRzW2ldOwogICAgICAgICAgICBpZiAoIWNsaWVudC5fX2RhdGFFbmFibGVkKSB7CiAgICAgICAgICAgICAgY2xpZW50Ll9lbmFibGVQcm9wZXJ0aWVzKCk7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoY2xpZW50Ll9fZGF0YVBlbmRpbmcpIHsKICAgICAgICAgICAgICBjbGllbnQuX2ZsdXNoUHJvcGVydGllcygpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogUGVyZm9ybSBhbnkgaW5pdGlhbCBzZXR1cCBvbiBjbGllbnQgZG9tLiBDYWxsZWQgYmVmb3JlIHRoZSBmaXJzdAogICAgICAgKiBgX2ZsdXNoUHJvcGVydGllc2AgY2FsbCBvbiBjbGllbnQgZG9tIGFuZCBiZWZvcmUgYW55IGVsZW1lbnQKICAgICAgICogb2JzZXJ2ZXJzIGFyZSBjYWxsZWQuCiAgICAgICAqCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9yZWFkeUNsaWVudHMoKSB7CiAgICAgICAgdGhpcy5fX2VuYWJsZU9yRmx1c2hDbGllbnRzKCk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBTZXRzIGEgYmFnIG9mIHByb3BlcnR5IGNoYW5nZXMgdG8gdGhpcyBpbnN0YW5jZSwgYW5kCiAgICAgICAqIHN5bmNocm9ub3VzbHkgcHJvY2Vzc2VzIGFsbCBlZmZlY3RzIG9mIHRoZSBwcm9wZXJ0aWVzIGFzIGEgYmF0Y2guCiAgICAgICAqCiAgICAgICAqIFByb3BlcnR5IG5hbWVzIG11c3QgYmUgc2ltcGxlIHByb3BlcnRpZXMsIG5vdCBwYXRocy4gIEJhdGNoZWQKICAgICAgICogcGF0aCBwcm9wYWdhdGlvbiBpcyBub3Qgc3VwcG9ydGVkLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcHMgQmFnIG9mIG9uZSBvciBtb3JlIGtleS12YWx1ZSBwYWlycyB3aG9zZSBrZXkgaXMKICAgICAgICogICBhIHByb3BlcnR5IGFuZCB2YWx1ZSBpcyB0aGUgbmV3IHZhbHVlIHRvIHNldCBmb3IgdGhhdCBwcm9wZXJ0eS4KICAgICAgICogQHBhcmFtIHtib29sZWFuPX0gc2V0UmVhZE9ubHkgV2hlbiB0cnVlLCBhbnkgcHJpdmF0ZSB2YWx1ZXMgc2V0IGluCiAgICAgICAqICAgYHByb3BzYCB3aWxsIGJlIHNldC4gQnkgZGVmYXVsdCwgYHNldFByb3BlcnRpZXNgIHdpbGwgbm90IHNldAogICAgICAgKiAgIGByZWFkT25seTogdHJ1ZWAgcm9vdCBwcm9wZXJ0aWVzLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHVibGljCiAgICAgICAqLwogICAgICBzZXRQcm9wZXJ0aWVzKHByb3BzLCBzZXRSZWFkT25seSkgewogICAgICAgIGZvciAobGV0IHBhdGggaW4gcHJvcHMpIHsKICAgICAgICAgIGlmIChzZXRSZWFkT25seSB8fCAhdGhpc1tUWVBFUy5SRUFEX09OTFldIHx8ICF0aGlzW1RZUEVTLlJFQURfT05MWV1bcGF0aF0pIHsKICAgICAgICAgICAgLy9UT0RPKGtzY2hhYWYpOiBleHBsaWNpdGx5IGRpc2FsbG93IHBhdGhzIGluIHNldFByb3BlcnR5PwogICAgICAgICAgICAvLyB3aWxkY2FyZCBvYnNlcnZlcnMgY3VycmVudGx5IG9ubHkgcGFzcyB0aGUgZmlyc3QgY2hhbmdlZCBwYXRoCiAgICAgICAgICAgIC8vIGluIHRoZSBgaW5mb2Agb2JqZWN0LCBhbmQgeW91IGNvdWxkIGRvIHNvbWUgb2RkIHRoaW5ncyBiYXRjaGluZwogICAgICAgICAgICAvLyBwYXRocywgZS5nLiB7J2Zvby5iYXInOiB7Li4ufSwgJ2Zvbyc6IG51bGx9CiAgICAgICAgICAgIHRoaXMuX3NldFBlbmRpbmdQcm9wZXJ0eU9yUGF0aChwYXRoLCBwcm9wc1twYXRoXSwgdHJ1ZSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHRoaXMuX2ludmFsaWRhdGVQcm9wZXJ0aWVzKCk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZXMgYFByb3BlcnR5QWNjZXNzb3JzYCBzbyB0aGF0IHByb3BlcnR5IGFjY2Vzc29yCiAgICAgICAqIHNpZGUgZWZmZWN0cyBhcmUgbm90IGVuYWJsZWQgdW50aWwgYWZ0ZXIgY2xpZW50IGRvbSBpcyBmdWxseSByZWFkeS4KICAgICAgICogQWxzbyBjYWxscyBgX2ZsdXNoQ2xpZW50c2AgY2FsbGJhY2sgdG8gZW5zdXJlIGNsaWVudCBkb20gaXMgZW5hYmxlZAogICAgICAgKiB0aGF0IHdhcyBub3QgZW5hYmxlZCBhcyBhIHJlc3VsdCBvZiBmbHVzaGluZyBwcm9wZXJ0aWVzLgogICAgICAgKgogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIHJlYWR5KCkgewogICAgICAgIC8vIEl0IGlzIGltcG9ydGFudCB0aGF0IGBzdXBlci5yZWFkeSgpYCBpcyBub3QgY2FsbGVkIGhlcmUgYXMgaXQKICAgICAgICAvLyBpbW1lZGlhdGVseSB0dXJucyBvbiBhY2Nlc3NvcnMuIEluc3RlYWQsIHdlIHdhaXQgdW50aWwgYHJlYWR5Q2xpZW50c2AKICAgICAgICAvLyB0byBlbmFibGUgYWNjZXNzb3JzIHRvIHByb3ZpZGUgYSBndWFyYW50ZWUgdGhhdCBjbGllbnRzIGFyZSByZWFkeQogICAgICAgIC8vIGJlZm9yZSBwcm9jZXNzaW5nIGFueSBhY2Nlc3NvcnMgc2lkZSBlZmZlY3RzLgogICAgICAgIHRoaXMuX2ZsdXNoUHJvcGVydGllcygpOwogICAgICAgIC8vIElmIG5vIGRhdGEgd2FzIHBlbmRpbmcsIGBfZmx1c2hQcm9wZXJ0aWVzYCB3aWxsIG5vdCBgZmx1c2hDbGllbnRzYAogICAgICAgIC8vIHNvIGVuc3VyZSB0aGlzIGlzIGRvbmUuCiAgICAgICAgaWYgKCF0aGlzLl9fZGF0YUNsaWVudHNSZWFkeSkgewogICAgICAgICAgdGhpcy5fZmx1c2hDbGllbnRzKCk7CiAgICAgICAgfQogICAgICAgIC8vIEJlZm9yZSByZWFkeSwgY2xpZW50IG5vdGlmaWNhdGlvbnMgZG8gbm90IHRyaWdnZXIgX2ZsdXNoUHJvcGVydGllcy4KICAgICAgICAvLyBUaGVyZWZvcmUgYSBmbHVzaCBpcyBuZWNlc3NhcnkgaGVyZSBpZiBkYXRhIGhhcyBiZWVuIHNldC4KICAgICAgICBpZiAodGhpcy5fX2RhdGFQZW5kaW5nKSB7CiAgICAgICAgICB0aGlzLl9mbHVzaFByb3BlcnRpZXMoKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBJbXBsZW1lbnRzIGBQcm9wZXJ0eUFjY2Vzc29yc2AncyBwcm9wZXJ0aWVzIGNoYW5nZWQgY2FsbGJhY2suCiAgICAgICAqCiAgICAgICAqIFJ1bnMgZWFjaCBjbGFzcyBvZiBlZmZlY3RzIGZvciB0aGUgYmF0Y2ggb2YgY2hhbmdlZCBwcm9wZXJ0aWVzIGluCiAgICAgICAqIGEgc3BlY2lmaWMgb3JkZXIgKGNvbXB1dGUsIHByb3BhZ2F0ZSwgcmVmbGVjdCwgb2JzZXJ2ZSwgbm90aWZ5KS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHshT2JqZWN0fSBjdXJyZW50UHJvcHMgQmFnIG9mIGFsbCBjdXJyZW50IGFjY2Vzc29yIHZhbHVlcwogICAgICAgKiBAcGFyYW0geyFPYmplY3R9IGNoYW5nZWRQcm9wcyBCYWcgb2YgcHJvcGVydGllcyBjaGFuZ2VkIHNpbmNlIHRoZSBsYXN0CiAgICAgICAqICAgY2FsbCB0byBgX3Byb3BlcnRpZXNDaGFuZ2VkYAogICAgICAgKiBAcGFyYW0geyFPYmplY3R9IG9sZFByb3BzIEJhZyBvZiBwcmV2aW91cyB2YWx1ZXMgZm9yIGVhY2ggcHJvcGVydHkKICAgICAgICogICBpbiBgY2hhbmdlZFByb3BzYAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX3Byb3BlcnRpZXNDaGFuZ2VkKGN1cnJlbnRQcm9wcywgY2hhbmdlZFByb3BzLCBvbGRQcm9wcykgewogICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgICAgICAvLyBsZXQgYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGNoYW5nZWRQcm9wcyB8fCB7fSk7CiAgICAgICAgLy8gd2luZG93LmRlYnVnICYmIGNvbnNvbGUuZ3JvdXAodGhpcy5sb2NhbE5hbWUgKyAnIycgKyB0aGlzLmlkICsgJzogJyArIGMpOwogICAgICAgIC8vIGlmICh3aW5kb3cuZGVidWcpIHsgZGVidWdnZXI7IH0KICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAgICAgbGV0IGhhc1BhdGhzID0gdGhpcy5fX2RhdGFIYXNQYXRoczsKICAgICAgICB0aGlzLl9fZGF0YUhhc1BhdGhzID0gZmFsc2U7CiAgICAgICAgLy8gQ29tcHV0ZSBwcm9wZXJ0aWVzCiAgICAgICAgcnVuQ29tcHV0ZWRFZmZlY3RzKHRoaXMsIGNoYW5nZWRQcm9wcywgb2xkUHJvcHMsIGhhc1BhdGhzKTsKICAgICAgICAvLyBDbGVhciBub3RpZnkgcHJvcGVydGllcyBwcmlvciB0byBwb3NzaWJsZSByZWVudHJ5IChwcm9wYWdhdGUsIG9ic2VydmUpLAogICAgICAgIC8vIGJ1dCBhZnRlciBjb21wdXRpbmcgZWZmZWN0cyBoYXZlIGEgY2hhbmNlIHRvIGFkZCB0byB0aGVtCiAgICAgICAgbGV0IG5vdGlmeVByb3BzID0gdGhpcy5fX2RhdGFUb05vdGlmeTsKICAgICAgICB0aGlzLl9fZGF0YVRvTm90aWZ5ID0gbnVsbDsKICAgICAgICAvLyBQcm9wYWdhdGUgcHJvcGVydGllcyB0byBjbGllbnRzCiAgICAgICAgdGhpcy5fcHJvcGFnYXRlUHJvcGVydHlDaGFuZ2VzKGNoYW5nZWRQcm9wcywgb2xkUHJvcHMsIGhhc1BhdGhzKTsKICAgICAgICAvLyBGbHVzaCBjbGllbnRzCiAgICAgICAgdGhpcy5fZmx1c2hDbGllbnRzKCk7CiAgICAgICAgLy8gUmVmbGVjdCBwcm9wZXJ0aWVzCiAgICAgICAgcnVuRWZmZWN0cyh0aGlzLCB0aGlzW1RZUEVTLlJFRkxFQ1RdLCBjaGFuZ2VkUHJvcHMsIG9sZFByb3BzLCBoYXNQYXRocyk7CiAgICAgICAgLy8gT2JzZXJ2ZSBwcm9wZXJ0aWVzCiAgICAgICAgcnVuRWZmZWN0cyh0aGlzLCB0aGlzW1RZUEVTLk9CU0VSVkVdLCBjaGFuZ2VkUHJvcHMsIG9sZFByb3BzLCBoYXNQYXRocyk7CiAgICAgICAgLy8gTm90aWZ5IHByb3BlcnRpZXMgdG8gaG9zdAogICAgICAgIGlmIChub3RpZnlQcm9wcykgewogICAgICAgICAgcnVuTm90aWZ5RWZmZWN0cyh0aGlzLCBub3RpZnlQcm9wcywgY2hhbmdlZFByb3BzLCBvbGRQcm9wcywgaGFzUGF0aHMpOwogICAgICAgIH0KICAgICAgICAvLyBDbGVhciB0ZW1wb3JhcnkgY2FjaGUgYXQgZW5kIG9mIHR1cm4KICAgICAgICBpZiAodGhpcy5fX2RhdGFDb3VudGVyID09IDEpIHsKICAgICAgICAgIHRoaXMuX19kYXRhVGVtcCA9IHt9OwogICAgICAgIH0KICAgICAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAgICAgLy8gd2luZG93LmRlYnVnICYmIGNvbnNvbGUuZ3JvdXBFbmQodGhpcy5sb2NhbE5hbWUgKyAnIycgKyB0aGlzLmlkICsgJzogJyArIGMpOwogICAgICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENhbGxlZCB0byBwcm9wYWdhdGUgYW55IHByb3BlcnR5IGNoYW5nZXMgdG8gc3RhbXBlZCB0ZW1wbGF0ZSBub2RlcwogICAgICAgKiBtYW5hZ2VkIGJ5IHRoaXMgZWxlbWVudC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtPYmplY3R9IGNoYW5nZWRQcm9wcyBCYWcgb2YgY2hhbmdlZCBwcm9wZXJ0aWVzCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvbGRQcm9wcyBCYWcgb2YgcHJldmlvdXMgdmFsdWVzIGZvciBjaGFuZ2VkIHByb3BlcnRpZXMKICAgICAgICogQHBhcmFtIHtib29sZWFufSBoYXNQYXRocyBUcnVlIHdpdGggYHByb3BzYCBjb250YWlucyBvbmUgb3IgbW9yZSBwYXRocwogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBfcHJvcGFnYXRlUHJvcGVydHlDaGFuZ2VzKGNoYW5nZWRQcm9wcywgb2xkUHJvcHMsIGhhc1BhdGhzKSB7CiAgICAgICAgaWYgKHRoaXNbVFlQRVMuUFJPUEFHQVRFXSkgewogICAgICAgICAgcnVuRWZmZWN0cyh0aGlzLCB0aGlzW1RZUEVTLlBST1BBR0FURV0sIGNoYW5nZWRQcm9wcywgb2xkUHJvcHMsIGhhc1BhdGhzKTsKICAgICAgICB9CiAgICAgICAgbGV0IHRlbXBsYXRlSW5mbyA9IHRoaXMuX190ZW1wbGF0ZUluZm87CiAgICAgICAgd2hpbGUgKHRlbXBsYXRlSW5mbykgewogICAgICAgICAgcnVuRWZmZWN0cyh0aGlzLCB0ZW1wbGF0ZUluZm8ucHJvcGVydHlFZmZlY3RzLCBjaGFuZ2VkUHJvcHMsIG9sZFByb3BzLAogICAgICAgICAgICBoYXNQYXRocywgdGVtcGxhdGVJbmZvLm5vZGVMaXN0KTsKICAgICAgICAgIHRlbXBsYXRlSW5mbyA9IHRlbXBsYXRlSW5mby5uZXh0VGVtcGxhdGVJbmZvOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEFsaWFzZXMgb25lIGRhdGEgcGF0aCBhcyBhbm90aGVyLCBzdWNoIHRoYXQgcGF0aCBub3RpZmljYXRpb25zIGZyb20gb25lCiAgICAgICAqIGFyZSByb3V0ZWQgdG8gdGhlIG90aGVyLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZyB8ICFBcnJheTxzdHJpbmd8bnVtYmVyPn0gdG8gVGFyZ2V0IHBhdGggdG8gbGluay4KICAgICAgICogQHBhcmFtIHtzdHJpbmcgfCAhQXJyYXk8c3RyaW5nfG51bWJlcj59IGZyb20gU291cmNlIHBhdGggdG8gbGluay4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHB1YmxpYwogICAgICAgKi8KICAgICAgbGlua1BhdGhzKHRvLCBmcm9tKSB7CiAgICAgICAgdG8gPSBQb2x5bWVyLlBhdGgubm9ybWFsaXplKHRvKTsKICAgICAgICBmcm9tID0gUG9seW1lci5QYXRoLm5vcm1hbGl6ZShmcm9tKTsKICAgICAgICB0aGlzLl9fZGF0YUxpbmtlZFBhdGhzID0gdGhpcy5fX2RhdGFMaW5rZWRQYXRocyB8fCB7fTsKICAgICAgICB0aGlzLl9fZGF0YUxpbmtlZFBhdGhzW3RvXSA9IGZyb207CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZW1vdmVzIGEgZGF0YSBwYXRoIGFsaWFzIHByZXZpb3VzbHkgZXN0YWJsaXNoZWQgd2l0aCBgX2xpbmtQYXRoc2AuCiAgICAgICAqCiAgICAgICAqIE5vdGUsIHRoZSBwYXRoIHRvIHVubGluayBzaG91bGQgYmUgdGhlIHRhcmdldCAoYHRvYCkgdXNlZCB3aGVuCiAgICAgICAqIGxpbmtpbmcgdGhlIHBhdGhzLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZyB8ICFBcnJheTxzdHJpbmd8bnVtYmVyPn0gcGF0aCBUYXJnZXQgcGF0aCB0byB1bmxpbmsuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwdWJsaWMKICAgICAgICovCiAgICAgIHVubGlua1BhdGhzKHBhdGgpIHsKICAgICAgICBwYXRoID0gUG9seW1lci5QYXRoLm5vcm1hbGl6ZShwYXRoKTsKICAgICAgICBpZiAodGhpcy5fX2RhdGFMaW5rZWRQYXRocykgewogICAgICAgICAgZGVsZXRlIHRoaXMuX19kYXRhTGlua2VkUGF0aHNbcGF0aF07CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogTm90aWZ5IHRoYXQgYW4gYXJyYXkgaGFzIGNoYW5nZWQuCiAgICAgICAqCiAgICAgICAqIEV4YW1wbGU6CiAgICAgICAqCiAgICAgICAqICAgICB0aGlzLml0ZW1zID0gWyB7bmFtZTogJ0ppbSd9LCB7bmFtZTogJ1RvZGQnfSwge25hbWU6ICdCaWxsJ30gXTsKICAgICAgICogICAgIC4uLgogICAgICAgKiAgICAgdGhpcy5pdGVtcy5zcGxpY2UoMSwgMSwge25hbWU6ICdTYW0nfSk7CiAgICAgICAqICAgICB0aGlzLml0ZW1zLnB1c2goe25hbWU6ICdCb2InfSk7CiAgICAgICAqICAgICB0aGlzLm5vdGlmeVNwbGljZXMoJ2l0ZW1zJywgWwogICAgICAgKiAgICAgICB7IGluZGV4OiAxLCByZW1vdmVkOiBbe25hbWU6ICdUb2RkJ31dLCBhZGRlZENvdW50OiAxLCBvYmplY3Q6IHRoaXMuaXRlbXMsIHR5cGU6ICdzcGxpY2UnIH0sCiAgICAgICAqICAgICAgIHsgaW5kZXg6IDMsIHJlbW92ZWQ6IFtdLCBhZGRlZENvdW50OiAxLCBvYmplY3Q6IHRoaXMuaXRlbXMsIHR5cGU6ICdzcGxpY2UnfQogICAgICAgKiAgICAgXSk7CiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFBhdGggdGhhdCBzaG91bGQgYmUgbm90aWZpZWQuCiAgICAgICAqIEBwYXJhbSB7QXJyYXl9IHNwbGljZXMgQXJyYXkgb2Ygc3BsaWNlIHJlY29yZHMgaW5kaWNhdGluZyBvcmRlcmVkCiAgICAgICAqICAgY2hhbmdlcyB0aGF0IG9jY3VycmVkIHRvIHRoZSBhcnJheS4gRWFjaCByZWNvcmQgc2hvdWxkIGhhdmUgdGhlCiAgICAgICAqICAgZm9sbG93aW5nIGZpZWxkczoKICAgICAgICogICAgKiBpbmRleDogaW5kZXggYXQgd2hpY2ggdGhlIGNoYW5nZSBvY2N1cnJlZAogICAgICAgKiAgICAqIHJlbW92ZWQ6IGFycmF5IG9mIGl0ZW1zIHRoYXQgd2VyZSByZW1vdmVkIGZyb20gdGhpcyBpbmRleAogICAgICAgKiAgICAqIGFkZGVkQ291bnQ6IG51bWJlciBvZiBuZXcgaXRlbXMgYWRkZWQgYXQgdGhpcyBpbmRleAogICAgICAgKiAgICAqIG9iamVjdDogYSByZWZlcmVuY2UgdG8gdGhlIGFycmF5IGluIHF1ZXN0aW9uCiAgICAgICAqICAgICogdHlwZTogdGhlIHN0cmluZyBsaXRlcmFsICdzcGxpY2UnCiAgICAgICAqCiAgICAgICAqICAgTm90ZSB0aGF0IHNwbGljZSByZWNvcmRzIF9tdXN0XyBiZSBub3JtYWxpemVkIHN1Y2ggdGhhdCB0aGV5IGFyZQogICAgICAgKiAgIHJlcG9ydGVkIGluIGluZGV4IG9yZGVyIChyYXcgcmVzdWx0cyBmcm9tIGBPYmplY3Qub2JzZXJ2ZWAgYXJlIG5vdAogICAgICAgKiAgIG9yZGVyZWQgYW5kIG11c3QgYmUgbm9ybWFsaXplZC9tZXJnZWQgYmVmb3JlIG5vdGlmeWluZykuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwdWJsaWMKICAgICAgKi8KICAgICAgbm90aWZ5U3BsaWNlcyhwYXRoLCBzcGxpY2VzKSB7CiAgICAgICAgbGV0IGluZm8gPSB7cGF0aDogJyd9OwogICAgICAgIGxldCBhcnJheSA9IC8qKiBAdHlwZSB7QXJyYXl9ICovKFBvbHltZXIuUGF0aC5nZXQodGhpcywgcGF0aCwgaW5mbykpOwogICAgICAgIG5vdGlmeVNwbGljZXModGhpcywgYXJyYXksIGluZm8ucGF0aCwgc3BsaWNlcyk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBDb252ZW5pZW5jZSBtZXRob2QgZm9yIHJlYWRpbmcgYSB2YWx1ZSBmcm9tIGEgcGF0aC4KICAgICAgICoKICAgICAgICogTm90ZSwgaWYgYW55IHBhcnQgaW4gdGhlIHBhdGggaXMgdW5kZWZpbmVkLCB0aGlzIG1ldGhvZCByZXR1cm5zCiAgICAgICAqIGB1bmRlZmluZWRgICh0aGlzIG1ldGhvZCBkb2VzIG5vdCB0aHJvdyB3aGVuIGRlcmVmZXJlbmNpbmcgdW5kZWZpbmVkCiAgICAgICAqIHBhdGhzKS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHsoc3RyaW5nfCFBcnJheTwoc3RyaW5nfG51bWJlcik+KX0gcGF0aCBQYXRoIHRvIHRoZSB2YWx1ZQogICAgICAgKiAgIHRvIHJlYWQuICBUaGUgcGF0aCBtYXkgYmUgc3BlY2lmaWVkIGFzIGEgc3RyaW5nIChlLmcuIGBmb28uYmFyLmJhemApCiAgICAgICAqICAgb3IgYW4gYXJyYXkgb2YgcGF0aCBwYXJ0cyAoZS5nLiBgWydmb28uYmFyJywgJ2JheiddYCkuICBOb3RlIHRoYXQKICAgICAgICogICBicmFja2V0ZWQgZXhwcmVzc2lvbnMgYXJlIG5vdCBzdXBwb3J0ZWQ7IHN0cmluZy1iYXNlZCBwYXRoIHBhcnRzCiAgICAgICAqICAgKm11c3QqIGJlIHNlcGFyYXRlZCBieSBkb3RzLiAgTm90ZSB0aGF0IHdoZW4gZGVyZWZlcmVuY2luZyBhcnJheQogICAgICAgKiAgIGluZGljZXMsIHRoZSBpbmRleCBtYXkgYmUgdXNlZCBhcyBhIGRvdHRlZCBwYXJ0IGRpcmVjdGx5CiAgICAgICAqICAgKGUuZy4gYHVzZXJzLjEyLm5hbWVgIG9yIGBbJ3VzZXJzJywgMTIsICduYW1lJ11gKS4KICAgICAgICogQHBhcmFtIHtPYmplY3Q9fSByb290IFJvb3Qgb2JqZWN0IGZyb20gd2hpY2ggdGhlIHBhdGggaXMgZXZhbHVhdGVkLgogICAgICAgKiBAcmV0dXJuIHsqfSBWYWx1ZSBhdCB0aGUgcGF0aCwgb3IgYHVuZGVmaW5lZGAgaWYgYW55IHBhcnQgb2YgdGhlIHBhdGgKICAgICAgICogICBpcyB1bmRlZmluZWQuCiAgICAgICAqIEBwdWJsaWMKICAgICAgICovCiAgICAgIGdldChwYXRoLCByb290KSB7CiAgICAgICAgcmV0dXJuIFBvbHltZXIuUGF0aC5nZXQocm9vdCB8fCB0aGlzLCBwYXRoKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENvbnZlbmllbmNlIG1ldGhvZCBmb3Igc2V0dGluZyBhIHZhbHVlIHRvIGEgcGF0aCBhbmQgbm90aWZ5aW5nIGFueQogICAgICAgKiBlbGVtZW50cyBib3VuZCB0byB0aGUgc2FtZSBwYXRoLgogICAgICAgKgogICAgICAgKiBOb3RlLCBpZiBhbnkgcGFydCBpbiB0aGUgcGF0aCBleGNlcHQgZm9yIHRoZSBsYXN0IGlzIHVuZGVmaW5lZCwKICAgICAgICogdGhpcyBtZXRob2QgZG9lcyBub3RoaW5nICh0aGlzIG1ldGhvZCBkb2VzIG5vdCB0aHJvdyB3aGVuCiAgICAgICAqIGRlcmVmZXJlbmNpbmcgdW5kZWZpbmVkIHBhdGhzKS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHsoc3RyaW5nfCFBcnJheTwoc3RyaW5nfG51bWJlcik+KX0gcGF0aCBQYXRoIHRvIHRoZSB2YWx1ZQogICAgICAgKiAgIHRvIHdyaXRlLiAgVGhlIHBhdGggbWF5IGJlIHNwZWNpZmllZCBhcyBhIHN0cmluZyAoZS5nLiBgJ2Zvby5iYXIuYmF6J2ApCiAgICAgICAqICAgb3IgYW4gYXJyYXkgb2YgcGF0aCBwYXJ0cyAoZS5nLiBgWydmb28uYmFyJywgJ2JheiddYCkuICBOb3RlIHRoYXQKICAgICAgICogICBicmFja2V0ZWQgZXhwcmVzc2lvbnMgYXJlIG5vdCBzdXBwb3J0ZWQ7IHN0cmluZy1iYXNlZCBwYXRoIHBhcnRzCiAgICAgICAqICAgKm11c3QqIGJlIHNlcGFyYXRlZCBieSBkb3RzLiAgTm90ZSB0aGF0IHdoZW4gZGVyZWZlcmVuY2luZyBhcnJheQogICAgICAgKiAgIGluZGljZXMsIHRoZSBpbmRleCBtYXkgYmUgdXNlZCBhcyBhIGRvdHRlZCBwYXJ0IGRpcmVjdGx5CiAgICAgICAqICAgKGUuZy4gYCd1c2Vycy4xMi5uYW1lJ2Agb3IgYFsndXNlcnMnLCAxMiwgJ25hbWUnXWApLgogICAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFZhbHVlIHRvIHNldCBhdCB0aGUgc3BlY2lmaWVkIHBhdGguCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0PX0gcm9vdCBSb290IG9iamVjdCBmcm9tIHdoaWNoIHRoZSBwYXRoIGlzIGV2YWx1YXRlZC4KICAgICAgICogICBXaGVuIHNwZWNpZmllZCwgbm8gbm90aWZpY2F0aW9uIHdpbGwgb2NjdXIuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwdWJsaWMKICAgICAgKi8KICAgICAgc2V0KHBhdGgsIHZhbHVlLCByb290KSB7CiAgICAgICAgaWYgKHJvb3QpIHsKICAgICAgICAgIFBvbHltZXIuUGF0aC5zZXQocm9vdCwgcGF0aCwgdmFsdWUpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBpZiAoIXRoaXNbVFlQRVMuUkVBRF9PTkxZXSB8fCAhdGhpc1tUWVBFUy5SRUFEX09OTFldWy8qKiBAdHlwZSB7c3RyaW5nfSAqLyhwYXRoKV0pIHsKICAgICAgICAgICAgaWYgKHRoaXMuX3NldFBlbmRpbmdQcm9wZXJ0eU9yUGF0aChwYXRoLCB2YWx1ZSwgdHJ1ZSkpIHsKICAgICAgICAgICAgICB0aGlzLl9pbnZhbGlkYXRlUHJvcGVydGllcygpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogQWRkcyBpdGVtcyBvbnRvIHRoZSBlbmQgb2YgdGhlIGFycmF5IGF0IHRoZSBwYXRoIHNwZWNpZmllZC4KICAgICAgICoKICAgICAgICogVGhlIGFyZ3VtZW50cyBhZnRlciBgcGF0aGAgYW5kIHJldHVybiB2YWx1ZSBtYXRjaCB0aGF0IG9mCiAgICAgICAqIGBBcnJheS5wcm90b3R5cGUucHVzaGAuCiAgICAgICAqCiAgICAgICAqIFRoaXMgbWV0aG9kIG5vdGlmaWVzIG90aGVyIHBhdGhzIHRvIHRoZSBzYW1lIGFycmF5IHRoYXQgYQogICAgICAgKiBzcGxpY2Ugb2NjdXJyZWQgdG8gdGhlIGFycmF5LgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZyB8ICFBcnJheTxzdHJpbmd8bnVtYmVyPn0gcGF0aCBQYXRoIHRvIGFycmF5LgogICAgICAgKiBAcGFyYW0gey4uLip9IGl0ZW1zIEl0ZW1zIHRvIHB1c2ggb250byBhcnJheQogICAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IE5ldyBsZW5ndGggb2YgdGhlIGFycmF5LgogICAgICAgKiBAcHVibGljCiAgICAgICAqLwogICAgICBwdXNoKHBhdGgsIC4uLml0ZW1zKSB7CiAgICAgICAgbGV0IGluZm8gPSB7cGF0aDogJyd9OwogICAgICAgIGxldCBhcnJheSA9IC8qKiBAdHlwZSB7QXJyYXl9Ki8oUG9seW1lci5QYXRoLmdldCh0aGlzLCBwYXRoLCBpbmZvKSk7CiAgICAgICAgbGV0IGxlbiA9IGFycmF5Lmxlbmd0aDsKICAgICAgICBsZXQgcmV0ID0gYXJyYXkucHVzaCguLi5pdGVtcyk7CiAgICAgICAgaWYgKGl0ZW1zLmxlbmd0aCkgewogICAgICAgICAgbm90aWZ5U3BsaWNlKHRoaXMsIGFycmF5LCBpbmZvLnBhdGgsIGxlbiwgaXRlbXMubGVuZ3RoLCBbXSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZW1vdmVzIGFuIGl0ZW0gZnJvbSB0aGUgZW5kIG9mIGFycmF5IGF0IHRoZSBwYXRoIHNwZWNpZmllZC4KICAgICAgICoKICAgICAgICogVGhlIGFyZ3VtZW50cyBhZnRlciBgcGF0aGAgYW5kIHJldHVybiB2YWx1ZSBtYXRjaCB0aGF0IG9mCiAgICAgICAqIGBBcnJheS5wcm90b3R5cGUucG9wYC4KICAgICAgICoKICAgICAgICogVGhpcyBtZXRob2Qgbm90aWZpZXMgb3RoZXIgcGF0aHMgdG8gdGhlIHNhbWUgYXJyYXkgdGhhdCBhCiAgICAgICAqIHNwbGljZSBvY2N1cnJlZCB0byB0aGUgYXJyYXkuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nIHwgIUFycmF5PHN0cmluZ3xudW1iZXI+fSBwYXRoIFBhdGggdG8gYXJyYXkuCiAgICAgICAqIEByZXR1cm4geyp9IEl0ZW0gdGhhdCB3YXMgcmVtb3ZlZC4KICAgICAgICogQHB1YmxpYwogICAgICAgKi8KICAgICAgcG9wKHBhdGgpIHsKICAgICAgICBsZXQgaW5mbyA9IHtwYXRoOiAnJ307CiAgICAgICAgbGV0IGFycmF5ID0gLyoqIEB0eXBlIHtBcnJheX0gKi8oUG9seW1lci5QYXRoLmdldCh0aGlzLCBwYXRoLCBpbmZvKSk7CiAgICAgICAgbGV0IGhhZExlbmd0aCA9IEJvb2xlYW4oYXJyYXkubGVuZ3RoKTsKICAgICAgICBsZXQgcmV0ID0gYXJyYXkucG9wKCk7CiAgICAgICAgaWYgKGhhZExlbmd0aCkgewogICAgICAgICAgbm90aWZ5U3BsaWNlKHRoaXMsIGFycmF5LCBpbmZvLnBhdGgsIGFycmF5Lmxlbmd0aCwgMCwgW3JldF0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9CgogICAgICAvKioKICAgICAgICogU3RhcnRpbmcgZnJvbSB0aGUgc3RhcnQgaW5kZXggc3BlY2lmaWVkLCByZW1vdmVzIDAgb3IgbW9yZSBpdGVtcwogICAgICAgKiBmcm9tIHRoZSBhcnJheSBhbmQgaW5zZXJ0cyAwIG9yIG1vcmUgbmV3IGl0ZW1zIGluIHRoZWlyIHBsYWNlLgogICAgICAgKgogICAgICAgKiBUaGUgYXJndW1lbnRzIGFmdGVyIGBwYXRoYCBhbmQgcmV0dXJuIHZhbHVlIG1hdGNoIHRoYXQgb2YKICAgICAgICogYEFycmF5LnByb3RvdHlwZS5zcGxpY2VgLgogICAgICAgKgogICAgICAgKiBUaGlzIG1ldGhvZCBub3RpZmllcyBvdGhlciBwYXRocyB0byB0aGUgc2FtZSBhcnJheSB0aGF0IGEKICAgICAgICogc3BsaWNlIG9jY3VycmVkIHRvIHRoZSBhcnJheS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmcgfCAhQXJyYXk8c3RyaW5nfG51bWJlcj59IHBhdGggUGF0aCB0byBhcnJheS4KICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0IEluZGV4IGZyb20gd2hpY2ggdG8gc3RhcnQgcmVtb3ZpbmcvaW5zZXJ0aW5nLgogICAgICAgKiBAcGFyYW0ge251bWJlcn0gZGVsZXRlQ291bnQgTnVtYmVyIG9mIGl0ZW1zIHRvIHJlbW92ZS4KICAgICAgICogQHBhcmFtIHsuLi4qfSBpdGVtcyBJdGVtcyB0byBpbnNlcnQgaW50byBhcnJheS4KICAgICAgICogQHJldHVybiB7QXJyYXl9IEFycmF5IG9mIHJlbW92ZWQgaXRlbXMuCiAgICAgICAqIEBwdWJsaWMKICAgICAgICovCiAgICAgIHNwbGljZShwYXRoLCBzdGFydCwgZGVsZXRlQ291bnQsIC4uLml0ZW1zKSB7CiAgICAgICAgbGV0IGluZm8gPSB7cGF0aCA6ICcnfTsKICAgICAgICBsZXQgYXJyYXkgPSAvKiogQHR5cGUge0FycmF5fSAqLyhQb2x5bWVyLlBhdGguZ2V0KHRoaXMsIHBhdGgsIGluZm8pKTsKICAgICAgICAvLyBOb3JtYWxpemUgZmFuY3kgbmF0aXZlIHNwbGljZSBoYW5kbGluZyBvZiBjcmF6eSBzdGFydCB2YWx1ZXMKICAgICAgICBpZiAoc3RhcnQgPCAwKSB7CiAgICAgICAgICBzdGFydCA9IGFycmF5Lmxlbmd0aCAtIE1hdGguZmxvb3IoLXN0YXJ0KTsKICAgICAgICB9IGVsc2UgaWYgKHN0YXJ0KSB7CiAgICAgICAgICBzdGFydCA9IE1hdGguZmxvb3Ioc3RhcnQpOwogICAgICAgIH0KICAgICAgICAvLyBhcnJheS5zcGxpY2UgZG9lcyBkaWZmZXJlbnQgdGhpbmdzIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgYXJndW1lbnRzCiAgICAgICAgLy8geW91IHBhc3MgaW4uIFRoZXJlZm9yZSwgYXJyYXkuc3BsaWNlKDApIGFuZCBhcnJheS5zcGxpY2UoMCwgdW5kZWZpbmVkKQogICAgICAgIC8vIGRvIGRpZmZlcmVudCB0aGluZ3MuIEluIHRoZSBmb3JtZXIsIHRoZSB3aG9sZSBhcnJheSBpcyBjbGVhcmVkLiBJbiB0aGUKICAgICAgICAvLyBsYXR0ZXIsIG5vIGl0ZW1zIGFyZSByZW1vdmVkLgogICAgICAgIC8vIFRoaXMgbWVhbnMgdGhhdCB3ZSBuZWVkIHRvIGRldGVjdCB3aGV0aGVyIDEuIG9uZSBvZiB0aGUgYXJndW1lbnRzCiAgICAgICAgLy8gaXMgYWN0dWFsbHkgcGFzc2VkIGluIGFuZCB0aGVuIDIuIGRldGVybWluZSBob3cgbWFueSBhcmd1bWVudHMKICAgICAgICAvLyB3ZSBzaG91bGQgcGFzcyBvbiB0byB0aGUgbmF0aXZlIGFycmF5LnNwbGljZQogICAgICAgIC8vCiAgICAgICAgbGV0IHJldDsKICAgICAgICAvLyBPbWl0IGFueSBhZGRpdGlvbmFsIGFyZ3VtZW50cyBpZiB0aGV5IHdlcmUgbm90IHBhc3NlZCBpbgogICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAyKSB7CiAgICAgICAgICByZXQgPSBhcnJheS5zcGxpY2Uoc3RhcnQpOwogICAgICAgIC8vIEVpdGhlciBzdGFydCB3YXMgdW5kZWZpbmVkIGFuZCB0aGUgb3RoZXJzIHdlcmUgZGVmaW5lZCwgYnV0IGluIHRoaXMKICAgICAgICAvLyBjYXNlIHdlIGNhbiBzYWZlbHkgcGFzcyBvbiBhbGwgYXJndW1lbnRzCiAgICAgICAgLy8KICAgICAgICAvLyBOb3RlOiB0aGlzIGluY2x1ZGVzIHRoZSBjYXNlIHdoZXJlIG5vbmUgb2YgdGhlIGFyZ3VtZW50cyB3ZXJlIHBhc3NlZCBpbiwKICAgICAgICAvLyBlLmcuIHRoaXMuc3BsaWNlKCdhcnJheScpLiBIb3dldmVyLCBpZiBib3RoIHN0YXJ0IGFuZCBkZWxldGVDb3VudAogICAgICAgIC8vIGFyZSB1bmRlZmluZWQsIGFycmF5LnNwbGljZSB3aWxsIG5vdCBtb2RpZnkgdGhlIGFycmF5IChhcyBleHBlY3RlZCkKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmV0ID0gYXJyYXkuc3BsaWNlKHN0YXJ0LCBkZWxldGVDb3VudCwgLi4uaXRlbXMpOwogICAgICAgIH0KICAgICAgICAvLyBBdCB0aGUgZW5kLCBjaGVjayB3aGV0aGVyIGFueSBpdGVtcyB3ZXJlIHBhc3NlZCBpbiAoZS5nLiBpbnNlcnRpb25zKQogICAgICAgIC8vIG9yIGlmIHRoZSByZXR1cm4gYXJyYXkgY29udGFpbnMgaXRlbXMgKGUuZy4gZGVsZXRpb25zKS4KICAgICAgICAvLyBPbmx5IG5vdGlmeSBpZiBpdGVtcyB3ZXJlIGFkZGVkIG9yIGRlbGV0ZWQuCiAgICAgICAgaWYgKGl0ZW1zLmxlbmd0aCB8fCByZXQubGVuZ3RoKSB7CiAgICAgICAgICBub3RpZnlTcGxpY2UodGhpcywgYXJyYXksIGluZm8ucGF0aCwgc3RhcnQsIGl0ZW1zLmxlbmd0aCwgcmV0KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJlbW92ZXMgYW4gaXRlbSBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgYXJyYXkgYXQgdGhlIHBhdGggc3BlY2lmaWVkLgogICAgICAgKgogICAgICAgKiBUaGUgYXJndW1lbnRzIGFmdGVyIGBwYXRoYCBhbmQgcmV0dXJuIHZhbHVlIG1hdGNoIHRoYXQgb2YKICAgICAgICogYEFycmF5LnByb3RvdHlwZS5wb3BgLgogICAgICAgKgogICAgICAgKiBUaGlzIG1ldGhvZCBub3RpZmllcyBvdGhlciBwYXRocyB0byB0aGUgc2FtZSBhcnJheSB0aGF0IGEKICAgICAgICogc3BsaWNlIG9jY3VycmVkIHRvIHRoZSBhcnJheS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmcgfCAhQXJyYXk8c3RyaW5nfG51bWJlcj59IHBhdGggUGF0aCB0byBhcnJheS4KICAgICAgICogQHJldHVybiB7Kn0gSXRlbSB0aGF0IHdhcyByZW1vdmVkLgogICAgICAgKiBAcHVibGljCiAgICAgICAqLwogICAgICBzaGlmdChwYXRoKSB7CiAgICAgICAgbGV0IGluZm8gPSB7cGF0aDogJyd9OwogICAgICAgIGxldCBhcnJheSA9IC8qKiBAdHlwZSB7QXJyYXl9ICovKFBvbHltZXIuUGF0aC5nZXQodGhpcywgcGF0aCwgaW5mbykpOwogICAgICAgIGxldCBoYWRMZW5ndGggPSBCb29sZWFuKGFycmF5Lmxlbmd0aCk7CiAgICAgICAgbGV0IHJldCA9IGFycmF5LnNoaWZ0KCk7CiAgICAgICAgaWYgKGhhZExlbmd0aCkgewogICAgICAgICAgbm90aWZ5U3BsaWNlKHRoaXMsIGFycmF5LCBpbmZvLnBhdGgsIDAsIDAsIFtyZXRdKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEFkZHMgaXRlbXMgb250byB0aGUgYmVnaW5uaW5nIG9mIHRoZSBhcnJheSBhdCB0aGUgcGF0aCBzcGVjaWZpZWQuCiAgICAgICAqCiAgICAgICAqIFRoZSBhcmd1bWVudHMgYWZ0ZXIgYHBhdGhgIGFuZCByZXR1cm4gdmFsdWUgbWF0Y2ggdGhhdCBvZgogICAgICAgKiBgQXJyYXkucHJvdG90eXBlLnB1c2hgLgogICAgICAgKgogICAgICAgKiBUaGlzIG1ldGhvZCBub3RpZmllcyBvdGhlciBwYXRocyB0byB0aGUgc2FtZSBhcnJheSB0aGF0IGEKICAgICAgICogc3BsaWNlIG9jY3VycmVkIHRvIHRoZSBhcnJheS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmcgfCAhQXJyYXk8c3RyaW5nfG51bWJlcj59IHBhdGggUGF0aCB0byBhcnJheS4KICAgICAgICogQHBhcmFtIHsuLi4qfSBpdGVtcyBJdGVtcyB0byBpbnNlcnQgaW5mbyBhcnJheQogICAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IE5ldyBsZW5ndGggb2YgdGhlIGFycmF5LgogICAgICAgKiBAcHVibGljCiAgICAgICAqLwogICAgICB1bnNoaWZ0KHBhdGgsIC4uLml0ZW1zKSB7CiAgICAgICAgbGV0IGluZm8gPSB7cGF0aDogJyd9OwogICAgICAgIGxldCBhcnJheSA9IC8qKiBAdHlwZSB7QXJyYXl9ICovKFBvbHltZXIuUGF0aC5nZXQodGhpcywgcGF0aCwgaW5mbykpOwogICAgICAgIGxldCByZXQgPSBhcnJheS51bnNoaWZ0KC4uLml0ZW1zKTsKICAgICAgICBpZiAoaXRlbXMubGVuZ3RoKSB7CiAgICAgICAgICBub3RpZnlTcGxpY2UodGhpcywgYXJyYXksIGluZm8ucGF0aCwgMCwgaXRlbXMubGVuZ3RoLCBbXSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBOb3RpZnkgdGhhdCBhIHBhdGggaGFzIGNoYW5nZWQuCiAgICAgICAqCiAgICAgICAqIEV4YW1wbGU6CiAgICAgICAqCiAgICAgICAqICAgICB0aGlzLml0ZW0udXNlci5uYW1lID0gJ0JvYic7CiAgICAgICAqICAgICB0aGlzLm5vdGlmeVBhdGgoJ2l0ZW0udXNlci5uYW1lJyk7CiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFBhdGggdGhhdCBzaG91bGQgYmUgbm90aWZpZWQuCiAgICAgICAqIEBwYXJhbSB7Kj19IHZhbHVlIFZhbHVlIGF0IHRoZSBwYXRoIChvcHRpb25hbCkuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwdWJsaWMKICAgICAgKi8KICAgICAgbm90aWZ5UGF0aChwYXRoLCB2YWx1ZSkgewogICAgICAgIC8qKiBAdHlwZSB7c3RyaW5nfSAqLwogICAgICAgIGxldCBwcm9wUGF0aDsKICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PSAxKSB7CiAgICAgICAgICAvLyBHZXQgdmFsdWUgaWYgbm90IHN1cHBsaWVkCiAgICAgICAgICBsZXQgaW5mbyA9IHtwYXRoOiAnJ307CiAgICAgICAgICB2YWx1ZSA9IFBvbHltZXIuUGF0aC5nZXQodGhpcywgcGF0aCwgaW5mbyk7CiAgICAgICAgICBwcm9wUGF0aCA9IGluZm8ucGF0aDsKICAgICAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkocGF0aCkpIHsKICAgICAgICAgIC8vIE5vcm1hbGl6ZSBwYXRoIGlmIG5lZWRlZAogICAgICAgICAgcHJvcFBhdGggPSBQb2x5bWVyLlBhdGgubm9ybWFsaXplKHBhdGgpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBwcm9wUGF0aCA9IC8qKiBAdHlwZXtzdHJpbmd9ICovKHBhdGgpOwogICAgICAgIH0KICAgICAgICBpZiAodGhpcy5fc2V0UGVuZGluZ1Byb3BlcnR5T3JQYXRoKHByb3BQYXRoLCB2YWx1ZSwgdHJ1ZSwgdHJ1ZSkpIHsKICAgICAgICAgIHRoaXMuX2ludmFsaWRhdGVQcm9wZXJ0aWVzKCk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogRXF1aXZhbGVudCB0byBzdGF0aWMgYGNyZWF0ZVJlYWRPbmx5UHJvcGVydHlgIEFQSSBidXQgY2FuIGJlIGNhbGxlZCBvbgogICAgICAgKiBhbiBpbnN0YW5jZSB0byBhZGQgZWZmZWN0cyBhdCBydW50aW1lLiAgU2VlIHRoYXQgbWV0aG9kIGZvcgogICAgICAgKiBmdWxsIEFQSSBkb2NzLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgUHJvcGVydHkgbmFtZQogICAgICAgKiBAcGFyYW0ge2Jvb2xlYW49fSBwcm90ZWN0ZWRTZXR0ZXIgQ3JlYXRlcyBhIGN1c3RvbSBwcm90ZWN0ZWQgc2V0dGVyCiAgICAgICAqICAgd2hlbiBgdHJ1ZWAuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9jcmVhdGVSZWFkT25seVByb3BlcnR5KHByb3BlcnR5LCBwcm90ZWN0ZWRTZXR0ZXIpIHsKICAgICAgICB0aGlzLl9hZGRQcm9wZXJ0eUVmZmVjdChwcm9wZXJ0eSwgVFlQRVMuUkVBRF9PTkxZKTsKICAgICAgICBpZiAocHJvdGVjdGVkU2V0dGVyKSB7CiAgICAgICAgICB0aGlzWydfc2V0JyArIHVwcGVyKHByb3BlcnR5KV0gPSAvKiogQHRoaXMge1Byb3BlcnR5RWZmZWN0c30gKi9mdW5jdGlvbih2YWx1ZSkgewogICAgICAgICAgICB0aGlzLl9zZXRQcm9wZXJ0eShwcm9wZXJ0eSwgdmFsdWUpOwogICAgICAgICAgfTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBFcXVpdmFsZW50IHRvIHN0YXRpYyBgY3JlYXRlUHJvcGVydHlPYnNlcnZlcmAgQVBJIGJ1dCBjYW4gYmUgY2FsbGVkIG9uCiAgICAgICAqIGFuIGluc3RhbmNlIHRvIGFkZCBlZmZlY3RzIGF0IHJ1bnRpbWUuICBTZWUgdGhhdCBtZXRob2QgZm9yCiAgICAgICAqIGZ1bGwgQVBJIGRvY3MuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSBuYW1lCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfGZ1bmN0aW9uKCosKil9IG1ldGhvZCBGdW5jdGlvbiBvciBuYW1lIG9mIG9ic2VydmVyIG1ldGhvZCB0byBjYWxsCiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbj19IGR5bmFtaWNGbiBXaGV0aGVyIHRoZSBtZXRob2QgbmFtZSBzaG91bGQgYmUgaW5jbHVkZWQgYXMKICAgICAgICogICBhIGRlcGVuZGVuY3kgdG8gdGhlIGVmZmVjdC4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX2NyZWF0ZVByb3BlcnR5T2JzZXJ2ZXIocHJvcGVydHksIG1ldGhvZCwgZHluYW1pY0ZuKSB7CiAgICAgICAgbGV0IGluZm8gPSB7IHByb3BlcnR5LCBtZXRob2QsIGR5bmFtaWNGbjogQm9vbGVhbihkeW5hbWljRm4pIH07CiAgICAgICAgdGhpcy5fYWRkUHJvcGVydHlFZmZlY3QocHJvcGVydHksIFRZUEVTLk9CU0VSVkUsIHsKICAgICAgICAgIGZuOiBydW5PYnNlcnZlckVmZmVjdCwgaW5mbywgdHJpZ2dlcjoge25hbWU6IHByb3BlcnR5fQogICAgICAgIH0pOwogICAgICAgIGlmIChkeW5hbWljRm4pIHsKICAgICAgICAgIHRoaXMuX2FkZFByb3BlcnR5RWZmZWN0KC8qKiBAdHlwZSB7c3RyaW5nfSAqLyhtZXRob2QpLCBUWVBFUy5PQlNFUlZFLCB7CiAgICAgICAgICAgIGZuOiBydW5PYnNlcnZlckVmZmVjdCwgaW5mbywgdHJpZ2dlcjoge25hbWU6IG1ldGhvZH0KICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEVxdWl2YWxlbnQgdG8gc3RhdGljIGBjcmVhdGVNZXRob2RPYnNlcnZlcmAgQVBJIGJ1dCBjYW4gYmUgY2FsbGVkIG9uCiAgICAgICAqIGFuIGluc3RhbmNlIHRvIGFkZCBlZmZlY3RzIGF0IHJ1bnRpbWUuICBTZWUgdGhhdCBtZXRob2QgZm9yCiAgICAgICAqIGZ1bGwgQVBJIGRvY3MuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBleHByZXNzaW9uIE1ldGhvZCBleHByZXNzaW9uCiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbnxPYmplY3Q9fSBkeW5hbWljRm4gQm9vbGVhbiBvciBvYmplY3QgbWFwIGluZGljYXRpbmcKICAgICAgICogICB3aGV0aGVyIG1ldGhvZCBuYW1lcyBzaG91bGQgYmUgaW5jbHVkZWQgYXMgYSBkZXBlbmRlbmN5IHRvIHRoZSBlZmZlY3QuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9jcmVhdGVNZXRob2RPYnNlcnZlcihleHByZXNzaW9uLCBkeW5hbWljRm4pIHsKICAgICAgICBsZXQgc2lnID0gcGFyc2VNZXRob2QoZXhwcmVzc2lvbik7CiAgICAgICAgaWYgKCFzaWcpIHsKICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiTWFsZm9ybWVkIG9ic2VydmVyIGV4cHJlc3Npb24gJyIgKyBleHByZXNzaW9uICsgIiciKTsKICAgICAgICB9CiAgICAgICAgY3JlYXRlTWV0aG9kRWZmZWN0KHRoaXMsIHNpZywgVFlQRVMuT0JTRVJWRSwgcnVuTWV0aG9kRWZmZWN0LCBudWxsLCBkeW5hbWljRm4pOwogICAgICB9CgogICAgICAvKioKICAgICAgICogRXF1aXZhbGVudCB0byBzdGF0aWMgYGNyZWF0ZU5vdGlmeWluZ1Byb3BlcnR5YCBBUEkgYnV0IGNhbiBiZSBjYWxsZWQgb24KICAgICAgICogYW4gaW5zdGFuY2UgdG8gYWRkIGVmZmVjdHMgYXQgcnVudGltZS4gIFNlZSB0aGF0IG1ldGhvZCBmb3IKICAgICAgICogZnVsbCBBUEkgZG9jcy4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX2NyZWF0ZU5vdGlmeWluZ1Byb3BlcnR5KHByb3BlcnR5KSB7CiAgICAgICAgdGhpcy5fYWRkUHJvcGVydHlFZmZlY3QocHJvcGVydHksIFRZUEVTLk5PVElGWSwgewogICAgICAgICAgZm46IHJ1bk5vdGlmeUVmZmVjdCwKICAgICAgICAgIGluZm86IHsKICAgICAgICAgICAgZXZlbnROYW1lOiBDYXNlTWFwLmNhbWVsVG9EYXNoQ2FzZShwcm9wZXJ0eSkgKyAnLWNoYW5nZWQnLAogICAgICAgICAgICBwcm9wZXJ0eTogcHJvcGVydHkKICAgICAgICAgIH0KICAgICAgICB9KTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEVxdWl2YWxlbnQgdG8gc3RhdGljIGBjcmVhdGVSZWZsZWN0ZWRQcm9wZXJ0eWAgQVBJIGJ1dCBjYW4gYmUgY2FsbGVkIG9uCiAgICAgICAqIGFuIGluc3RhbmNlIHRvIGFkZCBlZmZlY3RzIGF0IHJ1bnRpbWUuICBTZWUgdGhhdCBtZXRob2QgZm9yCiAgICAgICAqIGZ1bGwgQVBJIGRvY3MuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSBuYW1lCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9jcmVhdGVSZWZsZWN0ZWRQcm9wZXJ0eShwcm9wZXJ0eSkgewogICAgICAgIGxldCBhdHRyID0gdGhpcy5jb25zdHJ1Y3Rvci5hdHRyaWJ1dGVOYW1lRm9yUHJvcGVydHkocHJvcGVydHkpOwogICAgICAgIGlmIChhdHRyWzBdID09PSAnLScpIHsKICAgICAgICAgIGNvbnNvbGUud2FybignUHJvcGVydHkgJyArIHByb3BlcnR5ICsgJyBjYW5ub3QgYmUgcmVmbGVjdGVkIHRvIGF0dHJpYnV0ZSAnICsKICAgICAgICAgICAgYXR0ciArICcgYmVjYXVzZSAiLSIgaXMgbm90IGEgdmFsaWQgc3RhcnRpbmcgYXR0cmlidXRlIG5hbWUuIFVzZSBhIGxvd2VyY2FzZSBmaXJzdCBsZXR0ZXIgZm9yIHRoZSBwcm9wZXJ0eSBpbnN0ZWFkLicpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB0aGlzLl9hZGRQcm9wZXJ0eUVmZmVjdChwcm9wZXJ0eSwgVFlQRVMuUkVGTEVDVCwgewogICAgICAgICAgICBmbjogcnVuUmVmbGVjdEVmZmVjdCwKICAgICAgICAgICAgaW5mbzogewogICAgICAgICAgICAgIGF0dHJOYW1lOiBhdHRyCiAgICAgICAgICAgIH0KICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEVxdWl2YWxlbnQgdG8gc3RhdGljIGBjcmVhdGVDb21wdXRlZFByb3BlcnR5YCBBUEkgYnV0IGNhbiBiZSBjYWxsZWQgb24KICAgICAgICogYW4gaW5zdGFuY2UgdG8gYWRkIGVmZmVjdHMgYXQgcnVudGltZS4gIFNlZSB0aGF0IG1ldGhvZCBmb3IKICAgICAgICogZnVsbCBBUEkgZG9jcy4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgY29tcHV0ZWQgcHJvcGVydHkgdG8gc2V0CiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBleHByZXNzaW9uIE1ldGhvZCBleHByZXNzaW9uCiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbnxPYmplY3Q9fSBkeW5hbWljRm4gQm9vbGVhbiBvciBvYmplY3QgbWFwIGluZGljYXRpbmcKICAgICAgICogICB3aGV0aGVyIG1ldGhvZCBuYW1lcyBzaG91bGQgYmUgaW5jbHVkZWQgYXMgYSBkZXBlbmRlbmN5IHRvIHRoZSBlZmZlY3QuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9jcmVhdGVDb21wdXRlZFByb3BlcnR5KHByb3BlcnR5LCBleHByZXNzaW9uLCBkeW5hbWljRm4pIHsKICAgICAgICBsZXQgc2lnID0gcGFyc2VNZXRob2QoZXhwcmVzc2lvbik7CiAgICAgICAgaWYgKCFzaWcpIHsKICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiTWFsZm9ybWVkIGNvbXB1dGVkIGV4cHJlc3Npb24gJyIgKyBleHByZXNzaW9uICsgIiciKTsKICAgICAgICB9CiAgICAgICAgY3JlYXRlTWV0aG9kRWZmZWN0KHRoaXMsIHNpZywgVFlQRVMuQ09NUFVURSwgcnVuQ29tcHV0ZWRFZmZlY3QsIHByb3BlcnR5LCBkeW5hbWljRm4pOwogICAgICB9CgogICAgICAvKioKICAgICAgICogR2F0aGVyIHRoZSBhcmd1bWVudCB2YWx1ZXMgZm9yIGEgbWV0aG9kIHNwZWNpZmllZCBpbiB0aGUgcHJvdmlkZWQgYXJyYXkKICAgICAgICogb2YgYXJndW1lbnQgbWV0YWRhdGEuCiAgICAgICAqCiAgICAgICAqIFRoZSBgcGF0aGAgYW5kIGB2YWx1ZWAgYXJndW1lbnRzIGFyZSB1c2VkIHRvIGZpbGwgaW4gd2lsZGNhcmQgZGVzY3JpcHRvcgogICAgICAgKiB3aGVuIHRoZSBtZXRob2QgaXMgYmVpbmcgY2FsbGVkIGFzIGEgcmVzdWx0IG9mIGEgcGF0aCBub3RpZmljYXRpb24uCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7IUFycmF5PCFNZXRob2RBcmc+fSBhcmdzIEFycmF5IG9mIGFyZ3VtZW50IG1ldGFkYXRhCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFByb3BlcnR5L3BhdGggbmFtZSB0aGF0IHRyaWdnZXJlZCB0aGUgbWV0aG9kIGVmZmVjdAogICAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcHMgQmFnIG9mIGN1cnJlbnQgcHJvcGVydHkgY2hhbmdlcwogICAgICAgKiBAcmV0dXJuIHtBcnJheTwqPn0gQXJyYXkgb2YgYXJndW1lbnQgdmFsdWVzCiAgICAgICAqIEBwcml2YXRlCiAgICAgICAqLwogICAgICBfbWFyc2hhbEFyZ3MoYXJncywgcGF0aCwgcHJvcHMpIHsKICAgICAgICBjb25zdCBkYXRhID0gdGhpcy5fX2RhdGE7CiAgICAgICAgbGV0IHZhbHVlcyA9IFtdOwogICAgICAgIGZvciAobGV0IGk9MCwgbD1hcmdzLmxlbmd0aDsgaTxsOyBpKyspIHsKICAgICAgICAgIGxldCBhcmcgPSBhcmdzW2ldOwogICAgICAgICAgbGV0IG5hbWUgPSBhcmcubmFtZTsKICAgICAgICAgIGxldCB2OwogICAgICAgICAgaWYgKGFyZy5saXRlcmFsKSB7CiAgICAgICAgICAgIHYgPSBhcmcudmFsdWU7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBpZiAoYXJnLnN0cnVjdHVyZWQpIHsKICAgICAgICAgICAgICB2ID0gUG9seW1lci5QYXRoLmdldChkYXRhLCBuYW1lKTsKICAgICAgICAgICAgICAvLyB3aGVuIGRhdGEgaXMgbm90IHN0b3JlZCBlLmcuIGBzcGxpY2VzYAogICAgICAgICAgICAgIGlmICh2ID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgIHYgPSBwcm9wc1tuYW1lXTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdiA9IGRhdGFbbmFtZV07CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChhcmcud2lsZGNhcmQpIHsKICAgICAgICAgICAgLy8gT25seSBzZW5kIHRoZSBhY3R1YWwgcGF0aCBjaGFuZ2VkIGluZm8gaWYgdGhlIGNoYW5nZSB0aGF0CiAgICAgICAgICAgIC8vIGNhdXNlZCB0aGUgb2JzZXJ2ZXIgdG8gcnVuIG1hdGNoZWQgdGhlIHdpbGRjYXJkCiAgICAgICAgICAgIGxldCBiYXNlQ2hhbmdlZCA9IChuYW1lLmluZGV4T2YocGF0aCArICcuJykgPT09IDApOwogICAgICAgICAgICBsZXQgbWF0Y2hlcyA9IChwYXRoLmluZGV4T2YobmFtZSkgPT09IDAgJiYgIWJhc2VDaGFuZ2VkKTsKICAgICAgICAgICAgdmFsdWVzW2ldID0gewogICAgICAgICAgICAgIHBhdGg6IG1hdGNoZXMgPyBwYXRoIDogbmFtZSwKICAgICAgICAgICAgICB2YWx1ZTogbWF0Y2hlcyA/IHByb3BzW3BhdGhdIDogdiwKICAgICAgICAgICAgICBiYXNlOiB2CiAgICAgICAgICAgIH07CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB2YWx1ZXNbaV0gPSB2OwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gdmFsdWVzOwogICAgICB9CgogICAgICAvLyAtLSBzdGF0aWMgY2xhc3MgbWV0aG9kcyAtLS0tLS0tLS0tLS0KCiAgICAgIC8qKgogICAgICAgKiBFbnN1cmVzIGFuIGFjY2Vzc29yIGV4aXN0cyBmb3IgdGhlIHNwZWNpZmllZCBwcm9wZXJ0eSwgYW5kIGFkZHMKICAgICAgICogdG8gYSBsaXN0IG9mICJwcm9wZXJ0eSBlZmZlY3RzIiB0aGF0IHdpbGwgcnVuIHdoZW4gdGhlIGFjY2Vzc29yIGZvcgogICAgICAgKiB0aGUgc3BlY2lmaWVkIHByb3BlcnR5IGlzIHNldC4gIEVmZmVjdHMgYXJlIGdyb3VwZWQgYnkgInR5cGUiLCB3aGljaAogICAgICAgKiByb3VnaGx5IGNvcnJlc3BvbmRzIHRvIGEgcGhhc2UgaW4gZWZmZWN0IHByb2Nlc3NpbmcuICBUaGUgZWZmZWN0CiAgICAgICAqIG1ldGFkYXRhIHNob3VsZCBiZSBpbiB0aGUgZm9sbG93aW5nIGZvcm06CiAgICAgICAqCiAgICAgICAqICAgICB7CiAgICAgICAqICAgICAgIGZuOiBlZmZlY3RGdW5jdGlvbiwgLy8gUmVmZXJlbmNlIHRvIGZ1bmN0aW9uIHRvIGNhbGwgdG8gcGVyZm9ybSBlZmZlY3QKICAgICAgICogICAgICAgaW5mbzogeyAuLi4gfSAgICAgICAvLyBFZmZlY3QgbWV0YWRhdGEgcGFzc2VkIHRvIGZ1bmN0aW9uCiAgICAgICAqICAgICAgIHRyaWdnZXI6IHsgICAgICAgICAgLy8gT3B0aW9uYWwgdHJpZ2dlcmluZyBtZXRhZGF0YTsgaWYgbm90IHByb3ZpZGVkCiAgICAgICAqICAgICAgICAgbmFtZTogc3RyaW5nICAgICAgLy8gdGhlIHByb3BlcnR5IGlzIHRyZWF0ZWQgYXMgYSB3aWxkY2FyZAogICAgICAgKiAgICAgICAgIHN0cnVjdHVyZWQ6IGJvb2xlYW4KICAgICAgICogICAgICAgICB3aWxkY2FyZDogYm9vbGVhbgogICAgICAgKiAgICAgICB9CiAgICAgICAqICAgICB9CiAgICAgICAqCiAgICAgICAqIEVmZmVjdHMgYXJlIGNhbGxlZCBmcm9tIGBfcHJvcGVydGllc0NoYW5nZWRgIGluIHRoZSBmb2xsb3dpbmcgb3JkZXIgYnkKICAgICAgICogdHlwZToKICAgICAgICoKICAgICAgICogMS4gQ09NUFVURQogICAgICAgKiAyLiBQUk9QQUdBVEUKICAgICAgICogMy4gUkVGTEVDVAogICAgICAgKiA0LiBPQlNFUlZFCiAgICAgICAqIDUuIE5PVElGWQogICAgICAgKgogICAgICAgKiBFZmZlY3QgZnVuY3Rpb25zIGFyZSBjYWxsZWQgd2l0aCB0aGUgZm9sbG93aW5nIHNpZ25hdHVyZToKICAgICAgICoKICAgICAgICogICAgIGVmZmVjdEZ1bmN0aW9uKGluc3QsIHBhdGgsIHByb3BzLCBvbGRQcm9wcywgaW5mbywgaGFzUGF0aHMpCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSB0aGF0IHNob3VsZCB0cmlnZ2VyIHRoZSBlZmZlY3QKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgRWZmZWN0IHR5cGUsIGZyb20gdGhpcy5QUk9QRVJUWV9FRkZFQ1RfVFlQRVMKICAgICAgICogQHBhcmFtIHtPYmplY3Q9fSBlZmZlY3QgRWZmZWN0IG1ldGFkYXRhIG9iamVjdAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBzdGF0aWMgYWRkUHJvcGVydHlFZmZlY3QocHJvcGVydHksIHR5cGUsIGVmZmVjdCkgewogICAgICAgIHRoaXMucHJvdG90eXBlLl9hZGRQcm9wZXJ0eUVmZmVjdChwcm9wZXJ0eSwgdHlwZSwgZWZmZWN0KTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENyZWF0ZXMgYSBzaW5nbGUtcHJvcGVydHkgb2JzZXJ2ZXIgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICogQHBhcmFtIHtzdHJpbmd8ZnVuY3Rpb24oKiwqKX0gbWV0aG9kIEZ1bmN0aW9uIG9yIG5hbWUgb2Ygb2JzZXJ2ZXIgbWV0aG9kIHRvIGNhbGwKICAgICAgICogQHBhcmFtIHtib29sZWFuPX0gZHluYW1pY0ZuIFdoZXRoZXIgdGhlIG1ldGhvZCBuYW1lIHNob3VsZCBiZSBpbmNsdWRlZCBhcwogICAgICAgKiAgIGEgZGVwZW5kZW5jeSB0byB0aGUgZWZmZWN0LgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBzdGF0aWMgY3JlYXRlUHJvcGVydHlPYnNlcnZlcihwcm9wZXJ0eSwgbWV0aG9kLCBkeW5hbWljRm4pIHsKICAgICAgICB0aGlzLnByb3RvdHlwZS5fY3JlYXRlUHJvcGVydHlPYnNlcnZlcihwcm9wZXJ0eSwgbWV0aG9kLCBkeW5hbWljRm4pOwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ3JlYXRlcyBhIG11bHRpLXByb3BlcnR5ICJtZXRob2Qgb2JzZXJ2ZXIiIGJhc2VkIG9uIHRoZSBwcm92aWRlZAogICAgICAgKiBleHByZXNzaW9uLCB3aGljaCBzaG91bGQgYmUgYSBzdHJpbmcgaW4gdGhlIGZvcm0gb2YgYSBub3JtYWwgSmF2YVNjcmlwdAogICAgICAgKiBmdW5jdGlvbiBzaWduYXR1cmU6IGAnbWV0aG9kTmFtZShhcmcxLCBbLi4uLCBhcmduXSknYC4gIEVhY2ggYXJndW1lbnQKICAgICAgICogc2hvdWxkIGNvcnJlc3BvbmQgdG8gYSBwcm9wZXJ0eSBvciBwYXRoIGluIHRoZSBjb250ZXh0IG9mIHRoaXMKICAgICAgICogcHJvdG90eXBlIChvciBpbnN0YW5jZSksIG9yIG1heSBiZSBhIGxpdGVyYWwgc3RyaW5nIG9yIG51bWJlci4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGV4cHJlc3Npb24gTWV0aG9kIGV4cHJlc3Npb24KICAgICAgICogQHBhcmFtIHtib29sZWFufE9iamVjdD19IGR5bmFtaWNGbiBCb29sZWFuIG9yIG9iamVjdCBtYXAgaW5kaWNhdGluZwogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiAgIHdoZXRoZXIgbWV0aG9kIG5hbWVzIHNob3VsZCBiZSBpbmNsdWRlZCBhcyBhIGRlcGVuZGVuY3kgdG8gdGhlIGVmZmVjdC4KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgc3RhdGljIGNyZWF0ZU1ldGhvZE9ic2VydmVyKGV4cHJlc3Npb24sIGR5bmFtaWNGbikgewogICAgICAgIHRoaXMucHJvdG90eXBlLl9jcmVhdGVNZXRob2RPYnNlcnZlcihleHByZXNzaW9uLCBkeW5hbWljRm4pOwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ2F1c2VzIHRoZSBzZXR0ZXIgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eSB0byBkaXNwYXRjaCBgPHByb3BlcnR5Pi1jaGFuZ2VkYAogICAgICAgKiBldmVudHMgdG8gbm90aWZ5IG9mIGNoYW5nZXMgdG8gdGhlIHByb3BlcnR5LgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgUHJvcGVydHkgbmFtZQogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBzdGF0aWMgY3JlYXRlTm90aWZ5aW5nUHJvcGVydHkocHJvcGVydHkpIHsKICAgICAgICB0aGlzLnByb3RvdHlwZS5fY3JlYXRlTm90aWZ5aW5nUHJvcGVydHkocHJvcGVydHkpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ3JlYXRlcyBhIHJlYWQtb25seSBhY2Nlc3NvciBmb3IgdGhlIGdpdmVuIHByb3BlcnR5LgogICAgICAgKgogICAgICAgKiBUbyBzZXQgdGhlIHByb3BlcnR5LCB1c2UgdGhlIHByb3RlY3RlZCBgX3NldFByb3BlcnR5YCBBUEkuCiAgICAgICAqIFRvIGNyZWF0ZSBhIGN1c3RvbSBwcm90ZWN0ZWQgc2V0dGVyIChlLmcuIGBfc2V0TXlQcm9wKClgIGZvcgogICAgICAgKiBwcm9wZXJ0eSBgbXlQcm9wYCksIHBhc3MgYHRydWVgIGZvciBgcHJvdGVjdGVkU2V0dGVyYC4KICAgICAgICoKICAgICAgICogTm90ZSwgaWYgdGhlIHByb3BlcnR5IHdpbGwgaGF2ZSBvdGhlciBwcm9wZXJ0eSBlZmZlY3RzLCB0aGlzIG1ldGhvZAogICAgICAgKiBzaG91bGQgYmUgY2FsbGVkIGZpcnN0LCBiZWZvcmUgYWRkaW5nIG90aGVyIGVmZmVjdHMuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wZXJ0eSBQcm9wZXJ0eSBuYW1lCiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbj19IHByb3RlY3RlZFNldHRlciBDcmVhdGVzIGEgY3VzdG9tIHByb3RlY3RlZCBzZXR0ZXIKICAgICAgICogICB3aGVuIGB0cnVlYC4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgc3RhdGljIGNyZWF0ZVJlYWRPbmx5UHJvcGVydHkocHJvcGVydHksIHByb3RlY3RlZFNldHRlcikgewogICAgICAgIHRoaXMucHJvdG90eXBlLl9jcmVhdGVSZWFkT25seVByb3BlcnR5KHByb3BlcnR5LCBwcm90ZWN0ZWRTZXR0ZXIpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ2F1c2VzIHRoZSBzZXR0ZXIgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eSB0byByZWZsZWN0IHRoZSBwcm9wZXJ0eSB2YWx1ZQogICAgICAgKiB0byBhIChkYXNoLWNhc2VkKSBhdHRyaWJ1dGUgb2YgdGhlIHNhbWUgbmFtZS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgc3RhdGljIGNyZWF0ZVJlZmxlY3RlZFByb3BlcnR5KHByb3BlcnR5KSB7CiAgICAgICAgdGhpcy5wcm90b3R5cGUuX2NyZWF0ZVJlZmxlY3RlZFByb3BlcnR5KHByb3BlcnR5KTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENyZWF0ZXMgYSBjb21wdXRlZCBwcm9wZXJ0eSB3aG9zZSB2YWx1ZSBpcyBzZXQgdG8gdGhlIHJlc3VsdCBvZiB0aGUKICAgICAgICogbWV0aG9kIGRlc2NyaWJlZCBieSB0aGUgZ2l2ZW4gYGV4cHJlc3Npb25gIGVhY2ggdGltZSBvbmUgb3IgbW9yZQogICAgICAgKiBhcmd1bWVudHMgdG8gdGhlIG1ldGhvZCBjaGFuZ2VzLiAgVGhlIGV4cHJlc3Npb24gc2hvdWxkIGJlIGEgc3RyaW5nCiAgICAgICAqIGluIHRoZSBmb3JtIG9mIGEgbm9ybWFsIEphdmFTY3JpcHQgZnVuY3Rpb24gc2lnbmF0dXJlOgogICAgICAgKiBgJ21ldGhvZE5hbWUoYXJnMSwgWy4uLiwgYXJnbl0pJ2AKICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IE5hbWUgb2YgY29tcHV0ZWQgcHJvcGVydHkgdG8gc2V0CiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBleHByZXNzaW9uIE1ldGhvZCBleHByZXNzaW9uCiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbnxPYmplY3Q9fSBkeW5hbWljRm4gQm9vbGVhbiBvciBvYmplY3QgbWFwIGluZGljYXRpbmcgd2hldGhlcgogICAgICAgKiAgIG1ldGhvZCBuYW1lcyBzaG91bGQgYmUgaW5jbHVkZWQgYXMgYSBkZXBlbmRlbmN5IHRvIHRoZSBlZmZlY3QuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIHN0YXRpYyBjcmVhdGVDb21wdXRlZFByb3BlcnR5KHByb3BlcnR5LCBleHByZXNzaW9uLCBkeW5hbWljRm4pIHsKICAgICAgICB0aGlzLnByb3RvdHlwZS5fY3JlYXRlQ29tcHV0ZWRQcm9wZXJ0eShwcm9wZXJ0eSwgZXhwcmVzc2lvbiwgZHluYW1pY0ZuKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFBhcnNlcyB0aGUgcHJvdmlkZWQgdGVtcGxhdGUgdG8gZW5zdXJlIGJpbmRpbmcgZWZmZWN0cyBhcmUgY3JlYXRlZAogICAgICAgKiBmb3IgdGhlbSwgYW5kIHRoZW4gZW5zdXJlcyBwcm9wZXJ0eSBhY2Nlc3NvcnMgYXJlIGNyZWF0ZWQgZm9yIGFueQogICAgICAgKiBkZXBlbmRlbnQgcHJvcGVydGllcyBpbiB0aGUgdGVtcGxhdGUuICBCaW5kaW5nIGVmZmVjdHMgZm9yIGJvdW5kCiAgICAgICAqIHRlbXBsYXRlcyBhcmUgc3RvcmVkIGluIGEgbGlua2VkIGxpc3Qgb24gdGhlIGluc3RhbmNlIHNvIHRoYXQKICAgICAgICogdGVtcGxhdGVzIGNhbiBiZSBlZmZpY2llbnRseSBzdGFtcGVkIGFuZCB1bnN0YW1wZWQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7IUhUTUxUZW1wbGF0ZUVsZW1lbnR9IHRlbXBsYXRlIFRlbXBsYXRlIGNvbnRhaW5pbmcgYmluZGluZwogICAgICAgKiAgIGJpbmRpbmdzCiAgICAgICAqIEByZXR1cm4geyFUZW1wbGF0ZUluZm99IFRlbXBsYXRlIG1ldGFkYXRhIG9iamVjdAogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBzdGF0aWMgYmluZFRlbXBsYXRlKHRlbXBsYXRlKSB7CiAgICAgICAgcmV0dXJuIHRoaXMucHJvdG90eXBlLl9iaW5kVGVtcGxhdGUodGVtcGxhdGUpOwogICAgICB9CgogICAgICAvLyAtLSBiaW5kaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiAgICAgIC8qKgogICAgICAgKiBFcXVpdmFsZW50IHRvIHN0YXRpYyBgYmluZFRlbXBsYXRlYCBBUEkgYnV0IGNhbiBiZSBjYWxsZWQgb24KICAgICAgICogYW4gaW5zdGFuY2UgdG8gYWRkIGVmZmVjdHMgYXQgcnVudGltZS4gIFNlZSB0aGF0IG1ldGhvZCBmb3IKICAgICAgICogZnVsbCBBUEkgZG9jcy4KICAgICAgICoKICAgICAgICogVGhpcyBtZXRob2QgbWF5IGJlIGNhbGxlZCBvbiB0aGUgcHJvdG90eXBlIChmb3IgcHJvdG90eXBpY2FsIHRlbXBsYXRlCiAgICAgICAqIGJpbmRpbmcsIHRvIGF2b2lkIGNyZWF0aW5nIGFjY2Vzc29ycyBldmVyeSBpbnN0YW5jZSkgb25jZSBwZXIgcHJvdG90eXBlLAogICAgICAgKiBhbmQgd2lsbCBiZSBjYWxsZWQgd2l0aCBgcnVudGltZUJpbmRpbmc6IHRydWVgIGJ5IGBfc3RhbXBUZW1wbGF0ZWAgdG8KICAgICAgICogY3JlYXRlIGFuZCBsaW5rIGFuIGluc3RhbmNlIG9mIHRoZSB0ZW1wbGF0ZSBtZXRhZGF0YSBhc3NvY2lhdGVkIHdpdGggYQogICAgICAgKiBwYXJ0aWN1bGFyIHN0YW1waW5nLgogICAgICAgKgogICAgICAgKiBAcGFyYW0geyFIVE1MVGVtcGxhdGVFbGVtZW50fSB0ZW1wbGF0ZSBUZW1wbGF0ZSBjb250YWluaW5nIGJpbmRpbmcKICAgICAgICogICBiaW5kaW5ncwogICAgICAgKiBAcGFyYW0ge2Jvb2xlYW49fSBpbnN0YW5jZUJpbmRpbmcgV2hlbiBmYWxzZSAoZGVmYXVsdCksIHBlcmZvcm1zCiAgICAgICAqICAgInByb3RvdHlwaWNhbCIgYmluZGluZyBvZiB0aGUgdGVtcGxhdGUgYW5kIG92ZXJ3cml0ZXMgYW55IHByZXZpb3VzbHkKICAgICAgICogICBib3VuZCB0ZW1wbGF0ZSBmb3IgdGhlIGNsYXNzLiBXaGVuIHRydWUgKGFzIHBhc3NlZCBmcm9tCiAgICAgICAqICAgYF9zdGFtcFRlbXBsYXRlYCksIHRoZSB0ZW1wbGF0ZSBpbmZvIGlzIGluc3RhbmNlZCBhbmQgbGlua2VkIGludG8KICAgICAgICogICB0aGUgbGlzdCBvZiBib3VuZCB0ZW1wbGF0ZXMuCiAgICAgICAqIEByZXR1cm4geyFUZW1wbGF0ZUluZm99IFRlbXBsYXRlIG1ldGFkYXRhIG9iamVjdDsgZm9yIGBydW50aW1lQmluZGluZ2AsCiAgICAgICAqICAgdGhpcyBpcyBhbiBpbnN0YW5jZSBvZiB0aGUgcHJvdG90eXBpY2FsIHRlbXBsYXRlIGluZm8KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX2JpbmRUZW1wbGF0ZSh0ZW1wbGF0ZSwgaW5zdGFuY2VCaW5kaW5nKSB7CiAgICAgICAgbGV0IHRlbXBsYXRlSW5mbyA9IHRoaXMuY29uc3RydWN0b3IuX3BhcnNlVGVtcGxhdGUodGVtcGxhdGUpOwogICAgICAgIGxldCB3YXNQcmVCb3VuZCA9IHRoaXMuX190ZW1wbGF0ZUluZm8gPT0gdGVtcGxhdGVJbmZvOwogICAgICAgIC8vIE9wdGltaXphdGlvbjogc2luY2UgdGhpcyBpcyBjYWxsZWQgdHdpY2UgZm9yIHByb3RvLWJvdW5kIHRlbXBsYXRlcywKICAgICAgICAvLyBkb24ndCBhdHRlbXB0IHRvIHJlY3JlYXRlIGFjY2Vzc29ycyBpZiB0aGlzIHRlbXBsYXRlIHdhcyBwcmUtYm91bmQKICAgICAgICBpZiAoIXdhc1ByZUJvdW5kKSB7CiAgICAgICAgICBmb3IgKGxldCBwcm9wIGluIHRlbXBsYXRlSW5mby5wcm9wZXJ0eUVmZmVjdHMpIHsKICAgICAgICAgICAgdGhpcy5fY3JlYXRlUHJvcGVydHlBY2Nlc3Nvcihwcm9wKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKGluc3RhbmNlQmluZGluZykgewogICAgICAgICAgLy8gRm9yIGluc3RhbmNlLXRpbWUgYmluZGluZywgY3JlYXRlIGluc3RhbmNlIG9mIHRlbXBsYXRlIG1ldGFkYXRhCiAgICAgICAgICAvLyBhbmQgbGluayBpbnRvIGxpc3Qgb2YgdGVtcGxhdGVzIGlmIG5lY2Vzc2FyeQogICAgICAgICAgdGVtcGxhdGVJbmZvID0gLyoqIEB0eXBlIHshVGVtcGxhdGVJbmZvfSAqLyhPYmplY3QuY3JlYXRlKHRlbXBsYXRlSW5mbykpOwogICAgICAgICAgdGVtcGxhdGVJbmZvLndhc1ByZUJvdW5kID0gd2FzUHJlQm91bmQ7CiAgICAgICAgICBpZiAoIXdhc1ByZUJvdW5kICYmIHRoaXMuX190ZW1wbGF0ZUluZm8pIHsKICAgICAgICAgICAgbGV0IGxhc3QgPSB0aGlzLl9fdGVtcGxhdGVJbmZvTGFzdCB8fCB0aGlzLl9fdGVtcGxhdGVJbmZvOwogICAgICAgICAgICB0aGlzLl9fdGVtcGxhdGVJbmZvTGFzdCA9IGxhc3QubmV4dFRlbXBsYXRlSW5mbyA9IHRlbXBsYXRlSW5mbzsKICAgICAgICAgICAgdGVtcGxhdGVJbmZvLnByZXZpb3VzVGVtcGxhdGVJbmZvID0gbGFzdDsKICAgICAgICAgICAgcmV0dXJuIHRlbXBsYXRlSW5mbzsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRoaXMuX190ZW1wbGF0ZUluZm8gPSB0ZW1wbGF0ZUluZm87CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBBZGRzIGEgcHJvcGVydHkgZWZmZWN0IHRvIHRoZSBnaXZlbiB0ZW1wbGF0ZSBtZXRhZGF0YSwgd2hpY2ggaXMgcnVuCiAgICAgICAqIGF0IHRoZSAicHJvcGFnYXRlIiBzdGFnZSBvZiBgX3Byb3BlcnRpZXNDaGFuZ2VkYCB3aGVuIHRoZSB0ZW1wbGF0ZQogICAgICAgKiBoYXMgYmVlbiBib3VuZCB0byB0aGUgZWxlbWVudCB2aWEgYF9iaW5kVGVtcGxhdGVgLgogICAgICAgKgogICAgICAgKiBUaGUgYGVmZmVjdGAgb2JqZWN0IHNob3VsZCBtYXRjaCB0aGUgZm9ybWF0IGluIGBfYWRkUHJvcGVydHlFZmZlY3RgLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge09iamVjdH0gdGVtcGxhdGVJbmZvIFRlbXBsYXRlIG1ldGFkYXRhIHRvIGFkZCBlZmZlY3QgdG8KICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3AgUHJvcGVydHkgdGhhdCBzaG91bGQgdHJpZ2dlciB0aGUgZWZmZWN0CiAgICAgICAqIEBwYXJhbSB7T2JqZWN0PX0gZWZmZWN0IEVmZmVjdCBtZXRhZGF0YSBvYmplY3QKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgc3RhdGljIF9hZGRUZW1wbGF0ZVByb3BlcnR5RWZmZWN0KHRlbXBsYXRlSW5mbywgcHJvcCwgZWZmZWN0KSB7CiAgICAgICAgbGV0IGhvc3RQcm9wcyA9IHRlbXBsYXRlSW5mby5ob3N0UHJvcHMgPSB0ZW1wbGF0ZUluZm8uaG9zdFByb3BzIHx8IHt9OwogICAgICAgIGhvc3RQcm9wc1twcm9wXSA9IHRydWU7CiAgICAgICAgbGV0IGVmZmVjdHMgPSB0ZW1wbGF0ZUluZm8ucHJvcGVydHlFZmZlY3RzID0gdGVtcGxhdGVJbmZvLnByb3BlcnR5RWZmZWN0cyB8fCB7fTsKICAgICAgICBsZXQgcHJvcEVmZmVjdHMgPSBlZmZlY3RzW3Byb3BdID0gZWZmZWN0c1twcm9wXSB8fCBbXTsKICAgICAgICBwcm9wRWZmZWN0cy5wdXNoKGVmZmVjdCk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBTdGFtcHMgdGhlIHByb3ZpZGVkIHRlbXBsYXRlIGFuZCBwZXJmb3JtcyBpbnN0YW5jZS10aW1lIHNldHVwIGZvcgogICAgICAgKiBQb2x5bWVyIHRlbXBsYXRlIGZlYXR1cmVzLCBpbmNsdWRpbmcgZGF0YSBiaW5kaW5ncywgZGVjbGFyYXRpdmUgZXZlbnQKICAgICAgICogbGlzdGVuZXJzLCBhbmQgdGhlIGB0aGlzLiRgIG1hcCBvZiBgaWRgJ3MgdG8gbm9kZXMuICBBIGRvY3VtZW50IGZyYWdtZW50CiAgICAgICAqIGlzIHJldHVybmVkIGNvbnRhaW5pbmcgdGhlIHN0YW1wZWQgRE9NLCByZWFkeSBmb3IgaW5zZXJ0aW9uIGludG8gdGhlCiAgICAgICAqIERPTS4KICAgICAgICoKICAgICAgICogVGhpcyBtZXRob2QgbWF5IGJlIGNhbGxlZCBtb3JlIHRoYW4gb25jZTsgaG93ZXZlciBub3RlIHRoYXQgZHVlIHRvCiAgICAgICAqIGBzaGFkeWNzc2AgcG9seWZpbGwgbGltaXRhdGlvbnMsIG9ubHkgc3R5bGVzIGZyb20gdGVtcGxhdGVzIHByZXBhcmVkCiAgICAgICAqIHVzaW5nIGBTaGFkeUNTUy5wcmVwYXJlVGVtcGxhdGVgIHdpbGwgYmUgY29ycmVjdGx5IHBvbHlmaWxsZWQgKHNjb3BlZAogICAgICAgKiB0byB0aGUgc2hhZG93IHJvb3QgYW5kIHN1cHBvcnQgQ1NTIGN1c3RvbSBwcm9wZXJ0aWVzKSwgYW5kIG5vdGUgdGhhdAogICAgICAgKiBgU2hhZHlDU1MucHJlcGFyZVRlbXBsYXRlYCBtYXkgb25seSBiZSBjYWxsZWQgb25jZSBwZXIgZWxlbWVudC4gQXMgc3VjaCwKICAgICAgICogYW55IHN0eWxlcyByZXF1aXJlZCBieSBpbiBydW50aW1lLXN0YW1wZWQgdGVtcGxhdGVzIG11c3QgYmUgaW5jbHVkZWQKICAgICAgICogaW4gdGhlIG1haW4gZWxlbWVudCB0ZW1wbGF0ZS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHshSFRNTFRlbXBsYXRlRWxlbWVudH0gdGVtcGxhdGUgVGVtcGxhdGUgdG8gc3RhbXAKICAgICAgICogQHJldHVybiB7IVN0YW1wZWRUZW1wbGF0ZX0gQ2xvbmVkIHRlbXBsYXRlIGNvbnRlbnQKICAgICAgICogQG92ZXJyaWRlCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9zdGFtcFRlbXBsYXRlKHRlbXBsYXRlKSB7CiAgICAgICAgLy8gRW5zdXJlcyB0aGF0IGNyZWF0ZWQgZG9tIGlzIGBfZW5xdWV1ZUNsaWVudGAnZCB0byB0aGlzIGVsZW1lbnQgc28KICAgICAgICAvLyB0aGF0IGl0IGNhbiBiZSBmbHVzaGVkIG9uIG5leHQgY2FsbCB0byBgX2ZsdXNoUHJvcGVydGllc2AKICAgICAgICBob3N0U3RhY2suYmVnaW5Ib3N0aW5nKHRoaXMpOwogICAgICAgIGxldCBkb20gPSBzdXBlci5fc3RhbXBUZW1wbGF0ZSh0ZW1wbGF0ZSk7CiAgICAgICAgaG9zdFN0YWNrLmVuZEhvc3RpbmcodGhpcyk7CiAgICAgICAgbGV0IHRlbXBsYXRlSW5mbyA9IC8qKiBAdHlwZSB7IVRlbXBsYXRlSW5mb30gKi8odGhpcy5fYmluZFRlbXBsYXRlKHRlbXBsYXRlLCB0cnVlKSk7CiAgICAgICAgLy8gQWRkIHRlbXBsYXRlLWluc3RhbmNlLXNwZWNpZmljIGRhdGEgdG8gaW5zdGFuY2VkIHRlbXBsYXRlSW5mbwogICAgICAgIHRlbXBsYXRlSW5mby5ub2RlTGlzdCA9IGRvbS5ub2RlTGlzdDsKICAgICAgICAvLyBDYXB0dXJlIGNoaWxkIG5vZGVzIHRvIGFsbG93IHVuc3RhbXBpbmcgb2Ygbm9uLXByb3RvdHlwaWNhbCB0ZW1wbGF0ZXMKICAgICAgICBpZiAoIXRlbXBsYXRlSW5mby53YXNQcmVCb3VuZCkgewogICAgICAgICAgbGV0IG5vZGVzID0gdGVtcGxhdGVJbmZvLmNoaWxkTm9kZXMgPSBbXTsKICAgICAgICAgIGZvciAobGV0IG49ZG9tLmZpcnN0Q2hpbGQ7IG47IG49bi5uZXh0U2libGluZykgewogICAgICAgICAgICBub2Rlcy5wdXNoKG4pOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBkb20udGVtcGxhdGVJbmZvID0gdGVtcGxhdGVJbmZvOwogICAgICAgIC8vIFNldHVwIGNvbXBvdW5kIHN0b3JhZ2UsIDItd2F5IGxpc3RlbmVycywgYW5kIGRhdGFIb3N0IGZvciBiaW5kaW5ncwogICAgICAgIHNldHVwQmluZGluZ3ModGhpcywgdGVtcGxhdGVJbmZvKTsKICAgICAgICAvLyBGbHVzaCBwcm9wZXJ0aWVzIGludG8gdGVtcGxhdGUgbm9kZXMgaWYgYWxyZWFkeSBib290ZWQKICAgICAgICBpZiAodGhpcy5fX2RhdGFSZWFkeSkgewogICAgICAgICAgcnVuRWZmZWN0cyh0aGlzLCB0ZW1wbGF0ZUluZm8ucHJvcGVydHlFZmZlY3RzLCB0aGlzLl9fZGF0YSwgbnVsbCwKICAgICAgICAgICAgZmFsc2UsIHRlbXBsYXRlSW5mby5ub2RlTGlzdCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBkb207CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZW1vdmVzIGFuZCB1bmJpbmRzIHRoZSBub2RlcyBwcmV2aW91c2x5IGNvbnRhaW5lZCBpbiB0aGUgcHJvdmlkZWQKICAgICAgICogRG9jdW1lbnRGcmFnbWVudCByZXR1cm5lZCBmcm9tIGBfc3RhbXBUZW1wbGF0ZWAuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7IVN0YW1wZWRUZW1wbGF0ZX0gZG9tIERvY3VtZW50RnJhZ21lbnQgcHJldmlvdXNseSByZXR1cm5lZAogICAgICAgKiAgIGZyb20gYF9zdGFtcFRlbXBsYXRlYCBhc3NvY2lhdGVkIHdpdGggdGhlIG5vZGVzIHRvIGJlIHJlbW92ZWQKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX3JlbW92ZUJvdW5kRG9tKGRvbSkgewogICAgICAgIC8vIFVubGluayB0ZW1wbGF0ZSBpbmZvCiAgICAgICAgbGV0IHRlbXBsYXRlSW5mbyA9IGRvbS50ZW1wbGF0ZUluZm87CiAgICAgICAgaWYgKHRlbXBsYXRlSW5mby5wcmV2aW91c1RlbXBsYXRlSW5mbykgewogICAgICAgICAgdGVtcGxhdGVJbmZvLnByZXZpb3VzVGVtcGxhdGVJbmZvLm5leHRUZW1wbGF0ZUluZm8gPQogICAgICAgICAgICB0ZW1wbGF0ZUluZm8ubmV4dFRlbXBsYXRlSW5mbzsKICAgICAgICB9CiAgICAgICAgaWYgKHRlbXBsYXRlSW5mby5uZXh0VGVtcGxhdGVJbmZvKSB7CiAgICAgICAgICB0ZW1wbGF0ZUluZm8ubmV4dFRlbXBsYXRlSW5mby5wcmV2aW91c1RlbXBsYXRlSW5mbyA9CiAgICAgICAgICAgIHRlbXBsYXRlSW5mby5wcmV2aW91c1RlbXBsYXRlSW5mbzsKICAgICAgICB9CiAgICAgICAgaWYgKHRoaXMuX190ZW1wbGF0ZUluZm9MYXN0ID09IHRlbXBsYXRlSW5mbykgewogICAgICAgICAgdGhpcy5fX3RlbXBsYXRlSW5mb0xhc3QgPSB0ZW1wbGF0ZUluZm8ucHJldmlvdXNUZW1wbGF0ZUluZm87CiAgICAgICAgfQogICAgICAgIHRlbXBsYXRlSW5mby5wcmV2aW91c1RlbXBsYXRlSW5mbyA9IHRlbXBsYXRlSW5mby5uZXh0VGVtcGxhdGVJbmZvID0gbnVsbDsKICAgICAgICAvLyBSZW1vdmUgc3RhbXBlZCBub2RlcwogICAgICAgIGxldCBub2RlcyA9IHRlbXBsYXRlSW5mby5jaGlsZE5vZGVzOwogICAgICAgIGZvciAobGV0IGk9MDsgaTxub2Rlcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgbGV0IG5vZGUgPSBub2Rlc1tpXTsKICAgICAgICAgIG5vZGUucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChub2RlKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZXMgZGVmYXVsdCBgVGVtcGxhdGVTdGFtcGAgaW1wbGVtZW50YXRpb24gdG8gYWRkIHN1cHBvcnQgZm9yCiAgICAgICAqIHBhcnNpbmcgYmluZGluZ3MgZnJvbSBgVGV4dE5vZGVgJ3MnIGB0ZXh0Q29udGVudGAuICBBIGBiaW5kaW5nc2AKICAgICAgICogYXJyYXkgaXMgYWRkZWQgdG8gYG5vZGVJbmZvYCBhbmQgcG9wdWxhdGVkIHdpdGggYmluZGluZyBtZXRhZGF0YQogICAgICAgKiB3aXRoIGluZm9ybWF0aW9uIGNhcHR1cmluZyB0aGUgYmluZGluZyB0YXJnZXQsIGFuZCBhIGBwYXJ0c2AgYXJyYXkKICAgICAgICogd2l0aCBvbmUgb3IgbW9yZSBtZXRhZGF0YSBvYmplY3RzIGNhcHR1cmluZyB0aGUgc291cmNlKHMpIG9mIHRoZQogICAgICAgKiBiaW5kaW5nLgogICAgICAgKgogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICogQHBhcmFtIHtOb2RlfSBub2RlIE5vZGUgdG8gcGFyc2UKICAgICAgICogQHBhcmFtIHtUZW1wbGF0ZUluZm99IHRlbXBsYXRlSW5mbyBUZW1wbGF0ZSBtZXRhZGF0YSBmb3IgY3VycmVudCB0ZW1wbGF0ZQogICAgICAgKiBAcGFyYW0ge05vZGVJbmZvfSBub2RlSW5mbyBOb2RlIG1ldGFkYXRhIGZvciBjdXJyZW50IHRlbXBsYXRlIG5vZGUKICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gYHRydWVgIGlmIHRoZSB2aXNpdGVkIG5vZGUgYWRkZWQgbm9kZS1zcGVjaWZpYwogICAgICAgKiAgIG1ldGFkYXRhIHRvIGBub2RlSW5mb2AKICAgICAgICogQHByb3RlY3RlZAogICAgICAgKiBAc3VwcHJlc3Mge21pc3NpbmdQcm9wZXJ0aWVzfSBJbnRlcmZhY2VzIGluIGNsb3N1cmUgZG8gbm90IGluaGVyaXQgc3RhdGljcywgYnV0IGNsYXNzZXMgZG8KICAgICAgICovCiAgICAgIHN0YXRpYyBfcGFyc2VUZW1wbGF0ZU5vZGUobm9kZSwgdGVtcGxhdGVJbmZvLCBub2RlSW5mbykgewogICAgICAgIGxldCBub3RlZCA9IHN1cGVyLl9wYXJzZVRlbXBsYXRlTm9kZShub2RlLCB0ZW1wbGF0ZUluZm8sIG5vZGVJbmZvKTsKICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PT0gTm9kZS5URVhUX05PREUpIHsKICAgICAgICAgIGxldCBwYXJ0cyA9IHRoaXMuX3BhcnNlQmluZGluZ3Mobm9kZS50ZXh0Q29udGVudCwgdGVtcGxhdGVJbmZvKTsKICAgICAgICAgIGlmIChwYXJ0cykgewogICAgICAgICAgICAvLyBJbml0aWFsaXplIHRoZSB0ZXh0Q29udGVudCB3aXRoIGFueSBsaXRlcmFsIHBhcnRzCiAgICAgICAgICAgIC8vIE5PVEU6IGRlZmF1bHQgdG8gYSBzcGFjZSBoZXJlIHNvIHRoZSB0ZXh0Tm9kZSByZW1haW5zOyBzb21lIGJyb3dzZXJzCiAgICAgICAgICAgIC8vIChJRSkgb21pdCBhbiBlbXB0eSB0ZXh0Tm9kZSBmb2xsb3dpbmcgY2xvbmVOb2RlL2ltcG9ydE5vZGUuCiAgICAgICAgICAgIG5vZGUudGV4dENvbnRlbnQgPSBsaXRlcmFsRnJvbVBhcnRzKHBhcnRzKSB8fCAnICc7CiAgICAgICAgICAgIGFkZEJpbmRpbmcodGhpcywgdGVtcGxhdGVJbmZvLCBub2RlSW5mbywgJ3RleHQnLCAndGV4dENvbnRlbnQnLCBwYXJ0cyk7CiAgICAgICAgICAgIG5vdGVkID0gdHJ1ZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5vdGVkOwogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGVzIGRlZmF1bHQgYFRlbXBsYXRlU3RhbXBgIGltcGxlbWVudGF0aW9uIHRvIGFkZCBzdXBwb3J0IGZvcgogICAgICAgKiBwYXJzaW5nIGJpbmRpbmdzIGZyb20gYXR0cmlidXRlcy4gIEEgYGJpbmRpbmdzYAogICAgICAgKiBhcnJheSBpcyBhZGRlZCB0byBgbm9kZUluZm9gIGFuZCBwb3B1bGF0ZWQgd2l0aCBiaW5kaW5nIG1ldGFkYXRhCiAgICAgICAqIHdpdGggaW5mb3JtYXRpb24gY2FwdHVyaW5nIHRoZSBiaW5kaW5nIHRhcmdldCwgYW5kIGEgYHBhcnRzYCBhcnJheQogICAgICAgKiB3aXRoIG9uZSBvciBtb3JlIG1ldGFkYXRhIG9iamVjdHMgY2FwdHVyaW5nIHRoZSBzb3VyY2Uocykgb2YgdGhlCiAgICAgICAqIGJpbmRpbmcuCiAgICAgICAqCiAgICAgICAqIEBvdmVycmlkZQogICAgICAgKiBAcGFyYW0ge0VsZW1lbnR9IG5vZGUgTm9kZSB0byBwYXJzZQogICAgICAgKiBAcGFyYW0ge1RlbXBsYXRlSW5mb30gdGVtcGxhdGVJbmZvIFRlbXBsYXRlIG1ldGFkYXRhIGZvciBjdXJyZW50IHRlbXBsYXRlCiAgICAgICAqIEBwYXJhbSB7Tm9kZUluZm99IG5vZGVJbmZvIE5vZGUgbWV0YWRhdGEgZm9yIGN1cnJlbnQgdGVtcGxhdGUgbm9kZQogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBBdHRyaWJ1dGUgbmFtZQogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgQXR0cmlidXRlIHZhbHVlCiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IGB0cnVlYCBpZiB0aGUgdmlzaXRlZCBub2RlIGFkZGVkIG5vZGUtc3BlY2lmaWMKICAgICAgICogICBtZXRhZGF0YSB0byBgbm9kZUluZm9gCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICogQHN1cHByZXNzIHttaXNzaW5nUHJvcGVydGllc30gSW50ZXJmYWNlcyBpbiBjbG9zdXJlIGRvIG5vdCBpbmhlcml0IHN0YXRpY3MsIGJ1dCBjbGFzc2VzIGRvCiAgICAgICAqLwogICAgICBzdGF0aWMgX3BhcnNlVGVtcGxhdGVOb2RlQXR0cmlidXRlKG5vZGUsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8sIG5hbWUsIHZhbHVlKSB7CiAgICAgICAgbGV0IHBhcnRzID0gdGhpcy5fcGFyc2VCaW5kaW5ncyh2YWx1ZSwgdGVtcGxhdGVJbmZvKTsKICAgICAgICBpZiAocGFydHMpIHsKICAgICAgICAgIC8vIEF0dHJpYnV0ZSBvciBwcm9wZXJ0eQogICAgICAgICAgbGV0IG9yaWdOYW1lID0gbmFtZTsKICAgICAgICAgIGxldCBraW5kID0gJ3Byb3BlcnR5JzsKICAgICAgICAgIC8vIFRoZSBvbmx5IHdheSB3ZSBzZWUgYSBjYXBpdGFsIGxldHRlciBoZXJlIGlzIGlmIHRoZSBhdHRyIGhhcwogICAgICAgICAgLy8gYSBjYXBpdGFsIGxldHRlciBpbiBpdCBwZXIgc3BlYy4gSW4gdGhpcyBjYXNlLCB0byBtYWtlIHN1cmUKICAgICAgICAgIC8vIHRoaXMgYmluZGluZyB3b3Jrcywgd2UgZ28gYWhlYWQgYW5kIG1ha2UgdGhlIGJpbmRpbmcgdG8gdGhlIGF0dHJpYnV0ZS4KICAgICAgICAgIGlmIChjYXBpdGFsQXR0cmlidXRlUmVnZXgudGVzdChuYW1lKSkgewogICAgICAgICAgICBraW5kID0gJ2F0dHJpYnV0ZSc7CiAgICAgICAgICB9IGVsc2UgaWYgKG5hbWVbbmFtZS5sZW5ndGgtMV0gPT0gJyQnKSB7CiAgICAgICAgICAgIG5hbWUgPSBuYW1lLnNsaWNlKDAsIC0xKTsKICAgICAgICAgICAga2luZCA9ICdhdHRyaWJ1dGUnOwogICAgICAgICAgfQogICAgICAgICAgLy8gSW5pdGlhbGl6ZSBhdHRyaWJ1dGUgYmluZGluZ3Mgd2l0aCBhbnkgbGl0ZXJhbCBwYXJ0cwogICAgICAgICAgbGV0IGxpdGVyYWwgPSBsaXRlcmFsRnJvbVBhcnRzKHBhcnRzKTsKICAgICAgICAgIGlmIChsaXRlcmFsICYmIGtpbmQgPT0gJ2F0dHJpYnV0ZScpIHsKICAgICAgICAgICAgLy8gRW5zdXJlIGEgU2hhZHlDU1MgdGVtcGxhdGUgc2NvcGVkIHN0eWxlIGlzIG5vdCByZW1vdmVkCiAgICAgICAgICAgIC8vIHdoZW4gYSBjbGFzcyQgYmluZGluZydzIGluaXRpYWwgbGl0ZXJhbCB2YWx1ZSBpcyBzZXQuCiAgICAgICAgICAgIGlmIChuYW1lID09ICdjbGFzcycgJiYgbm9kZS5oYXNBdHRyaWJ1dGUoJ2NsYXNzJykpIHsKICAgICAgICAgICAgICBsaXRlcmFsICs9ICcgJyArIG5vZGUuZ2V0QXR0cmlidXRlKG5hbWUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG5vZGUuc2V0QXR0cmlidXRlKG5hbWUsIGxpdGVyYWwpOwogICAgICAgICAgfQogICAgICAgICAgLy8gQ2xlYXIgYXR0cmlidXRlIGJlZm9yZSByZW1vdmluZywgc2luY2UgSUUgd29uJ3QgYWxsb3cgcmVtb3ZpbmcKICAgICAgICAgIC8vIGB2YWx1ZWAgYXR0cmlidXRlIGlmIGl0IHByZXZpb3VzbHkgaGFkIGEgdmFsdWUgKGNhbid0CiAgICAgICAgICAvLyB1bmNvbmRpdGlvbmFsbHkgc2V0ICcnIGJlZm9yZSByZW1vdmluZyBzaW5jZSBhdHRyaWJ1dGVzIHdpdGggYCRgCiAgICAgICAgICAvLyBjYW4ndCBiZSBzZXQgdXNpbmcgc2V0QXR0cmlidXRlKQogICAgICAgICAgaWYgKG5vZGUubG9jYWxOYW1lID09PSAnaW5wdXQnICYmIG9yaWdOYW1lID09PSAndmFsdWUnKSB7CiAgICAgICAgICAgIG5vZGUuc2V0QXR0cmlidXRlKG9yaWdOYW1lLCAnJyk7CiAgICAgICAgICB9CiAgICAgICAgICAvLyBSZW1vdmUgYW5ub3RhdGlvbgogICAgICAgICAgbm9kZS5yZW1vdmVBdHRyaWJ1dGUob3JpZ05hbWUpOwogICAgICAgICAgLy8gQ2FzZSBoYWNrZXJ5OiBhdHRyaWJ1dGVzIGFyZSBsb3dlci1jYXNlLCBidXQgYmluZCB0YXJnZXRzCiAgICAgICAgICAvLyAocHJvcGVydGllcykgYXJlIGNhc2Ugc2Vuc2l0aXZlLiBHYW1iaXQgaXMgdG8gbWFwIGRhc2gtY2FzZSB0bwogICAgICAgICAgLy8gY2FtZWwtY2FzZTogYGZvby1iYXJgIGJlY29tZXMgYGZvb0JhcmAuCiAgICAgICAgICAvLyBBdHRyaWJ1dGUgYmluZGluZ3MgYXJlIGV4Y2VwdGVkLgogICAgICAgICAgaWYgKGtpbmQgPT09ICdwcm9wZXJ0eScpIHsKICAgICAgICAgICAgbmFtZSA9IFBvbHltZXIuQ2FzZU1hcC5kYXNoVG9DYW1lbENhc2UobmFtZSk7CiAgICAgICAgICB9CiAgICAgICAgICBhZGRCaW5kaW5nKHRoaXMsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8sIGtpbmQsIG5hbWUsIHBhcnRzLCBsaXRlcmFsKTsKICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXR1cm4gc3VwZXIuX3BhcnNlVGVtcGxhdGVOb2RlQXR0cmlidXRlKG5vZGUsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8sIG5hbWUsIHZhbHVlKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZXMgZGVmYXVsdCBgVGVtcGxhdGVTdGFtcGAgaW1wbGVtZW50YXRpb24gdG8gYWRkIHN1cHBvcnQgZm9yCiAgICAgICAqIGJpbmRpbmcgdGhlIHByb3BlcnRpZXMgdGhhdCBhIG5lc3RlZCB0ZW1wbGF0ZSBkZXBlbmRzIG9uIHRvIHRoZSB0ZW1wbGF0ZQogICAgICAgKiBhcyBgX2hvc3RfPHByb3BlcnR5PmAuCiAgICAgICAqCiAgICAgICAqIEBvdmVycmlkZQogICAgICAgKiBAcGFyYW0ge05vZGV9IG5vZGUgTm9kZSB0byBwYXJzZQogICAgICAgKiBAcGFyYW0ge1RlbXBsYXRlSW5mb30gdGVtcGxhdGVJbmZvIFRlbXBsYXRlIG1ldGFkYXRhIGZvciBjdXJyZW50IHRlbXBsYXRlCiAgICAgICAqIEBwYXJhbSB7Tm9kZUluZm99IG5vZGVJbmZvIE5vZGUgbWV0YWRhdGEgZm9yIGN1cnJlbnQgdGVtcGxhdGUgbm9kZQogICAgICAgKiBAcmV0dXJuIHtib29sZWFufSBgdHJ1ZWAgaWYgdGhlIHZpc2l0ZWQgbm9kZSBhZGRlZCBub2RlLXNwZWNpZmljCiAgICAgICAqICAgbWV0YWRhdGEgdG8gYG5vZGVJbmZvYAogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqIEBzdXBwcmVzcyB7bWlzc2luZ1Byb3BlcnRpZXN9IEludGVyZmFjZXMgaW4gY2xvc3VyZSBkbyBub3QgaW5oZXJpdCBzdGF0aWNzLCBidXQgY2xhc3NlcyBkbwogICAgICAgKi8KICAgICAgc3RhdGljIF9wYXJzZVRlbXBsYXRlTmVzdGVkVGVtcGxhdGUobm9kZSwgdGVtcGxhdGVJbmZvLCBub2RlSW5mbykgewogICAgICAgIGxldCBub3RlZCA9IHN1cGVyLl9wYXJzZVRlbXBsYXRlTmVzdGVkVGVtcGxhdGUobm9kZSwgdGVtcGxhdGVJbmZvLCBub2RlSW5mbyk7CiAgICAgICAgLy8gTWVyZ2UgaG9zdCBwcm9wcyBpbnRvIG91dGVyIHRlbXBsYXRlIGFuZCBhZGQgYmluZGluZ3MKICAgICAgICBsZXQgaG9zdFByb3BzID0gbm9kZUluZm8udGVtcGxhdGVJbmZvLmhvc3RQcm9wczsKICAgICAgICBsZXQgbW9kZSA9ICd7JzsKICAgICAgICBmb3IgKGxldCBzb3VyY2UgaW4gaG9zdFByb3BzKSB7CiAgICAgICAgICBsZXQgcGFydHMgPSBbeyBtb2RlLCBzb3VyY2UsIGRlcGVuZGVuY2llczogW3NvdXJjZV0gfV07CiAgICAgICAgICBhZGRCaW5kaW5nKHRoaXMsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8sICdwcm9wZXJ0eScsICdfaG9zdF8nICsgc291cmNlLCBwYXJ0cyk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBub3RlZDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENhbGxlZCB0byBwYXJzZSB0ZXh0IGluIGEgdGVtcGxhdGUgKGVpdGhlciBhdHRyaWJ1dGUgdmFsdWVzIG9yCiAgICAgICAqIHRleHRDb250ZW50KSBpbnRvIGJpbmRpbmcgbWV0YWRhdGEuCiAgICAgICAqCiAgICAgICAqIEFueSBvdmVycmlkZXMgb2YgdGhpcyBtZXRob2Qgc2hvdWxkIHJldHVybiBhbiBhcnJheSBvZiBiaW5kaW5nIHBhcnQKICAgICAgICogbWV0YWRhdGEgIHJlcHJlc2VudGluZyBvbmUgb3IgbW9yZSBiaW5kaW5ncyBmb3VuZCBpbiB0aGUgcHJvdmlkZWQgdGV4dAogICAgICAgKiBhbmQgYW55ICJsaXRlcmFsIiB0ZXh0IGluIGJldHdlZW4uICBBbnkgbm9uLWxpdGVyYWwgcGFydHMgd2lsbCBiZSBwYXNzZWQKICAgICAgICogdG8gYF9ldmFsdWF0ZUJpbmRpbmdgIHdoZW4gYW55IGRlcGVuZGVuY2llcyBjaGFuZ2UuICBUaGUgb25seSByZXF1aXJlZAogICAgICAgKiBmaWVsZHMgb2YgZWFjaCAicGFydCIgaW4gdGhlIHJldHVybmVkIGFycmF5IGFyZSBhcyBmb2xsb3dzOgogICAgICAgKgogICAgICAgKiAtIGBkZXBlbmRlbmNpZXNgIC0gQXJyYXkgY29udGFpbmluZyB0cmlnZ2VyIG1ldGFkYXRhIGZvciBlYWNoIHByb3BlcnR5CiAgICAgICAqICAgdGhhdCBzaG91bGQgdHJpZ2dlciB0aGUgYmluZGluZyB0byB1cGRhdGUKICAgICAgICogLSBgbGl0ZXJhbGAgLSBTdHJpbmcgY29udGFpbmluZyB0ZXh0IGlmIHRoZSBwYXJ0IHJlcHJlc2VudHMgYSBsaXRlcmFsOwogICAgICAgKiAgIGluIHRoaXMgY2FzZSBubyBgZGVwZW5kZW5jaWVzYCBhcmUgbmVlZGVkCiAgICAgICAqCiAgICAgICAqIEFkZGl0aW9uYWwgbWV0YWRhdGEgZm9yIHVzZSBieSBgX2V2YWx1YXRlQmluZGluZ2AgbWF5IGJlIHByb3ZpZGVkIGluCiAgICAgICAqIGVhY2ggcGFydCBvYmplY3QgYXMgbmVlZGVkLgogICAgICAgKgogICAgICAgKiBUaGUgZGVmYXVsdCBpbXBsZW1lbnRhdGlvbiBoYW5kbGVzIHRoZSBmb2xsb3dpbmcgdHlwZXMgb2YgYmluZGluZ3MKICAgICAgICogKG9uZSBvciBtb3JlIG1heSBiZSBpbnRlcm1peGVkIHdpdGggbGl0ZXJhbCBzdHJpbmdzKToKICAgICAgICogLSBQcm9wZXJ0eSBiaW5kaW5nOiBgW1twcm9wXV1gCiAgICAgICAqIC0gUGF0aCBiaW5kaW5nOiBgW1tvYmplY3QucHJvcF1dYAogICAgICAgKiAtIE5lZ2F0ZWQgcHJvcGVydHkgb3IgcGF0aCBiaW5kaW5nczogYFtbIXByb3BdXWAgb3IgYFtbIW9iamVjdC5wcm9wXV1gCiAgICAgICAqIC0gVHdvLXdheSBwcm9wZXJ0eSBvciBwYXRoIGJpbmRpbmdzIChzdXBwb3J0cyBuZWdhdGlvbik6CiAgICAgICAqICAgYHt7cHJvcH19YCwgYHt7b2JqZWN0LnByb3B9fWAsIGB7eyFwcm9wfX1gIG9yIGB7eyFvYmplY3QucHJvcH19YAogICAgICAgKiAtIElubGluZSBjb21wdXRlZCBtZXRob2QgKHN1cHBvcnRzIG5lZ2F0aW9uKToKICAgICAgICogICBgW1tjb21wdXRlKGEsICdsaXRlcmFsJywgYildXWAsIGBbWyFjb21wdXRlKGEsICdsaXRlcmFsJywgYildXWAKICAgICAgICoKICAgICAgICogVGhlIGRlZmF1bHQgaW1wbGVtZW50YXRpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiBmb3IgYmVzdAogICAgICAgKiBwZXJmb3JtYW5jZS4gSG93ZXZlciwgdGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiB1c2VzIGEgd2hpdGUtbGlzdCBvZgogICAgICAgKiBhbGxvd2VkIGNoYXJhY3RlcnMgaW4gYSBkYXRhLWJpbmRpbmcsIHdoaWNoIGNhdXNlcyBwcm9ibGVtcyBmb3IKICAgICAgICogZGF0YS1iaW5kaW5ncyB0aGF0IGRvIHVzZSBjaGFyYWN0ZXJzIG5vdCBpbiB0aGlzIHdoaXRlLWxpc3QuCiAgICAgICAqCiAgICAgICAqIEluc3RlYWQgb2YgdXBkYXRpbmcgdGhlIHdoaXRlLWxpc3Qgd2l0aCBhbGwgYWxsb3dlZCBjaGFyYWN0ZXJzLAogICAgICAgKiB0aGVyZSBpcyBhIFN0cmljdEJpbmRpbmdQYXJzZXIgKHNlZSBsaWIvbWl4aW5zL3N0cmljdC1iaW5kaW5nLXBhcnNlcikKICAgICAgICogdGhhdCB1c2VzIGEgc3RhdGUgbWFjaGluZSBpbnN0ZWFkLiBUaGlzIHN0YXRlIG1hY2hpbmUgaXMgYWJsZSB0byBoYW5kbGUKICAgICAgICogYWxsIGNoYXJhY3RlcnMuIEhvd2V2ZXIsIGl0IGlzIHNsaWdodGx5IGxlc3MgcGVyZm9ybWFudCwgdGhlcmVmb3JlIHdlCiAgICAgICAqIGV4dHJhY3RlZCBpdCBpbnRvIGEgc2VwYXJhdGUgb3B0aW9uYWwgbWl4aW4uCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IFRleHQgdG8gcGFyc2UgZnJvbSBhdHRyaWJ1dGUgb3IgdGV4dENvbnRlbnQKICAgICAgICogQHBhcmFtIHtPYmplY3R9IHRlbXBsYXRlSW5mbyBDdXJyZW50IHRlbXBsYXRlIG1ldGFkYXRhCiAgICAgICAqIEByZXR1cm4ge0FycmF5PCFCaW5kaW5nUGFydD59IEFycmF5IG9mIGJpbmRpbmcgcGFydCBtZXRhZGF0YQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBzdGF0aWMgX3BhcnNlQmluZGluZ3ModGV4dCwgdGVtcGxhdGVJbmZvKSB7CiAgICAgICAgbGV0IHBhcnRzID0gW107CiAgICAgICAgbGV0IGxhc3RJbmRleCA9IDA7CiAgICAgICAgbGV0IG07CiAgICAgICAgLy8gRXhhbXBsZTogImxpdGVyYWwxe3twcm9wfX1saXRlcmFsMltbIWNvbXB1dGUoZm9vLGJhcildXWZpbmFsIgogICAgICAgIC8vIFJlZ2V4IG1hdGNoZXM6CiAgICAgICAgLy8gICAgICAgIEl0ZXJhdGlvbiAxOiAgSXRlcmF0aW9uIDI6CiAgICAgICAgLy8gbVsxXTogJ3t7JyAgICAgICAgICAnW1snCiAgICAgICAgLy8gbVsyXTogJycgICAgICAgICAgICAnIScKICAgICAgICAvLyBtWzNdOiAncHJvcCcgICAgICAgICdjb21wdXRlKGZvbyxiYXIpJwogICAgICAgIHdoaWxlICgobSA9IGJpbmRpbmdSZWdleC5leGVjKHRleHQpKSAhPT0gbnVsbCkgewogICAgICAgICAgLy8gQWRkIGxpdGVyYWwgcGFydAogICAgICAgICAgaWYgKG0uaW5kZXggPiBsYXN0SW5kZXgpIHsKICAgICAgICAgICAgcGFydHMucHVzaCh7bGl0ZXJhbDogdGV4dC5zbGljZShsYXN0SW5kZXgsIG0uaW5kZXgpfSk7CiAgICAgICAgICB9CiAgICAgICAgICAvLyBBZGQgYmluZGluZyBwYXJ0CiAgICAgICAgICBsZXQgbW9kZSA9IG1bMV1bMF07CiAgICAgICAgICBsZXQgbmVnYXRlID0gQm9vbGVhbihtWzJdKTsKICAgICAgICAgIGxldCBzb3VyY2UgPSBtWzNdLnRyaW0oKTsKICAgICAgICAgIGxldCBjdXN0b21FdmVudCA9IGZhbHNlLCBub3RpZnlFdmVudCA9ICcnLCBjb2xvbiA9IC0xOwogICAgICAgICAgaWYgKG1vZGUgPT0gJ3snICYmIChjb2xvbiA9IHNvdXJjZS5pbmRleE9mKCc6OicpKSA+IDApIHsKICAgICAgICAgICAgbm90aWZ5RXZlbnQgPSBzb3VyY2Uuc3Vic3RyaW5nKGNvbG9uICsgMik7CiAgICAgICAgICAgIHNvdXJjZSA9IHNvdXJjZS5zdWJzdHJpbmcoMCwgY29sb24pOwogICAgICAgICAgICBjdXN0b21FdmVudCA9IHRydWU7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgc2lnbmF0dXJlID0gcGFyc2VNZXRob2Qoc291cmNlKTsKICAgICAgICAgIGxldCBkZXBlbmRlbmNpZXMgPSBbXTsKICAgICAgICAgIGlmIChzaWduYXR1cmUpIHsKICAgICAgICAgICAgLy8gSW5saW5lIGNvbXB1dGVkIGZ1bmN0aW9uCiAgICAgICAgICAgIGxldCB7YXJncywgbWV0aG9kTmFtZX0gPSBzaWduYXR1cmU7CiAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaTxhcmdzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgbGV0IGFyZyA9IGFyZ3NbaV07CiAgICAgICAgICAgICAgaWYgKCFhcmcubGl0ZXJhbCkgewogICAgICAgICAgICAgICAgZGVwZW5kZW5jaWVzLnB1c2goYXJnKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbGV0IGR5bmFtaWNGbnMgPSB0ZW1wbGF0ZUluZm8uZHluYW1pY0ZuczsKICAgICAgICAgICAgaWYgKGR5bmFtaWNGbnMgJiYgZHluYW1pY0Zuc1ttZXRob2ROYW1lXSB8fCBzaWduYXR1cmUuc3RhdGljKSB7CiAgICAgICAgICAgICAgZGVwZW5kZW5jaWVzLnB1c2gobWV0aG9kTmFtZSk7CiAgICAgICAgICAgICAgc2lnbmF0dXJlLmR5bmFtaWNGbiA9IHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIC8vIFByb3BlcnR5IG9yIHBhdGgKICAgICAgICAgICAgZGVwZW5kZW5jaWVzLnB1c2goc291cmNlKTsKICAgICAgICAgIH0KICAgICAgICAgIHBhcnRzLnB1c2goewogICAgICAgICAgICBzb3VyY2UsIG1vZGUsIG5lZ2F0ZSwgY3VzdG9tRXZlbnQsIHNpZ25hdHVyZSwgZGVwZW5kZW5jaWVzLAogICAgICAgICAgICBldmVudDogbm90aWZ5RXZlbnQKICAgICAgICAgIH0pOwogICAgICAgICAgbGFzdEluZGV4ID0gYmluZGluZ1JlZ2V4Lmxhc3RJbmRleDsKICAgICAgICB9CiAgICAgICAgLy8gQWRkIGEgZmluYWwgbGl0ZXJhbCBwYXJ0CiAgICAgICAgaWYgKGxhc3RJbmRleCAmJiBsYXN0SW5kZXggPCB0ZXh0Lmxlbmd0aCkgewogICAgICAgICAgbGV0IGxpdGVyYWwgPSB0ZXh0LnN1YnN0cmluZyhsYXN0SW5kZXgpOwogICAgICAgICAgaWYgKGxpdGVyYWwpIHsKICAgICAgICAgICAgcGFydHMucHVzaCh7CiAgICAgICAgICAgICAgbGl0ZXJhbDogbGl0ZXJhbAogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKHBhcnRzLmxlbmd0aCkgewogICAgICAgICAgcmV0dXJuIHBhcnRzOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBDYWxsZWQgdG8gZXZhbHVhdGUgYSBwcmV2aW91c2x5IHBhcnNlZCBiaW5kaW5nIHBhcnQgYmFzZWQgb24gYSBzZXQgb2YKICAgICAgICogb25lIG9yIG1vcmUgY2hhbmdlZCBkZXBlbmRlbmNpZXMuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7dGhpc30gaW5zdCBFbGVtZW50IHRoYXQgc2hvdWxkIGJlIHVzZWQgYXMgc2NvcGUgZm9yCiAgICAgICAqICAgYmluZGluZyBkZXBlbmRlbmNpZXMKICAgICAgICogQHBhcmFtIHtCaW5kaW5nUGFydH0gcGFydCBCaW5kaW5nIHBhcnQgbWV0YWRhdGEKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggUHJvcGVydHkvcGF0aCB0aGF0IHRyaWdnZXJlZCB0aGlzIGVmZmVjdAogICAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcHMgQmFnIG9mIGN1cnJlbnQgcHJvcGVydHkgY2hhbmdlcwogICAgICAgKiBAcGFyYW0ge09iamVjdH0gb2xkUHJvcHMgQmFnIG9mIHByZXZpb3VzIHZhbHVlcyBmb3IgY2hhbmdlZCBwcm9wZXJ0aWVzCiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFzUGF0aHMgVHJ1ZSB3aXRoIGBwcm9wc2AgY29udGFpbnMgb25lIG9yIG1vcmUgcGF0aHMKICAgICAgICogQHJldHVybiB7Kn0gVmFsdWUgdGhlIGJpbmRpbmcgcGFydCBldmFsdWF0ZWQgdG8KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgc3RhdGljIF9ldmFsdWF0ZUJpbmRpbmcoaW5zdCwgcGFydCwgcGF0aCwgcHJvcHMsIG9sZFByb3BzLCBoYXNQYXRocykgewogICAgICAgIGxldCB2YWx1ZTsKICAgICAgICBpZiAocGFydC5zaWduYXR1cmUpIHsKICAgICAgICAgIHZhbHVlID0gcnVuTWV0aG9kRWZmZWN0KGluc3QsIHBhdGgsIHByb3BzLCBvbGRQcm9wcywgcGFydC5zaWduYXR1cmUpOwogICAgICAgIH0gZWxzZSBpZiAocGF0aCAhPSBwYXJ0LnNvdXJjZSkgewogICAgICAgICAgdmFsdWUgPSBQb2x5bWVyLlBhdGguZ2V0KGluc3QsIHBhcnQuc291cmNlKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgaWYgKGhhc1BhdGhzICYmIFBvbHltZXIuUGF0aC5pc1BhdGgocGF0aCkpIHsKICAgICAgICAgICAgdmFsdWUgPSBQb2x5bWVyLlBhdGguZ2V0KGluc3QsIHBhdGgpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdmFsdWUgPSBpbnN0Ll9fZGF0YVtwYXRoXTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKHBhcnQubmVnYXRlKSB7CiAgICAgICAgICB2YWx1ZSA9ICF2YWx1ZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICB9CgogICAgfQoKICAgIC8vIG1ha2UgYSB0eXBpbmcgZm9yIGNsb3N1cmUgOlAKICAgIFByb3BlcnR5RWZmZWN0c1R5cGUgPSBQcm9wZXJ0eUVmZmVjdHM7CgogICAgcmV0dXJuIFByb3BlcnR5RWZmZWN0czsKICB9KTsKCiAgLyoqCiAgICogSGVscGVyIGFwaSBmb3IgZW5xdWV1aW5nIGNsaWVudCBkb20gY3JlYXRlZCBieSBhIGhvc3QgZWxlbWVudC4KICAgKgogICAqIEJ5IGRlZmF1bHQgZWxlbWVudHMgYXJlIGZsdXNoZWQgdmlhIGBfZmx1c2hQcm9wZXJ0aWVzYCB3aGVuCiAgICogYGNvbm5lY3RlZENhbGxiYWNrYCBpcyBjYWxsZWQuIEVsZW1lbnRzIGF0dGFjaCB0aGVpciBjbGllbnQgZG9tIHRvCiAgICogdGhlbXNlbHZlcyBhdCBgcmVhZHlgIHRpbWUgd2hpY2ggcmVzdWx0cyBmcm9tIHRoaXMgZmlyc3QgZmx1c2guCiAgICogVGhpcyBwcm92aWRlcyBhbiBvcmRlcmluZyBndWFyYW50ZWUgdGhhdCB0aGUgY2xpZW50IGRvbSBhbiBlbGVtZW50CiAgICogY3JlYXRlcyBpcyBmbHVzaGVkIGJlZm9yZSB0aGUgZWxlbWVudCBpdHNlbGYgKGkuZS4gY2xpZW50IGByZWFkeWAKICAgKiBmaXJlcyBiZWZvcmUgaG9zdCBgcmVhZHlgKS4KICAgKgogICAqIEhvd2V2ZXIsIGlmIGBfZmx1c2hQcm9wZXJ0aWVzYCBpcyBjYWxsZWQgKmJlZm9yZSogYW4gZWxlbWVudCBpcyBjb25uZWN0ZWQsCiAgICogYXMgZm9yIGV4YW1wbGUgYFRlbXBsYXRpemVgIGRvZXMsIHRoaXMgb3JkZXJpbmcgZ3VhcmFudGVlIGNhbm5vdCBiZQogICAqIHNhdGlzZmllZCBiZWNhdXNlIG5vIGVsZW1lbnRzIGFyZSBjb25uZWN0ZWQuIChOb3RlOiBCb3VuZCBlbGVtZW50cyB0aGF0CiAgICogcmVjZWl2ZSBkYXRhIGRvIGJlY29tZSBlbnF1ZXVlZCBjbGllbnRzIGFuZCBhcmUgcHJvcGVybHkgb3JkZXJlZCBidXQKICAgKiB1bmJvdW5kIGVsZW1lbnRzIGFyZSBub3QuKQogICAqCiAgICogVG8gbWFpbnRhaW4gdGhlIGRlc2lyZWQgImNsaWVudCBiZWZvcmUgaG9zdCIgb3JkZXJpbmcgZ3VhcmFudGVlIGZvciB0aGlzCiAgICogY2FzZSB3ZSByZWx5IG9uIHRoZSAiaG9zdCBzdGFjay4gQ2xpZW50IG5vZGVzIHJlZ2lzdGVycyB0aGVtc2VsdmVzIHdpdGgKICAgKiB0aGUgY3JlYXRpbmcgaG9zdCBlbGVtZW50IHdoZW4gY3JlYXRlZC4gVGhpcyBlbnN1cmVzIHRoYXQgYWxsIGNsaWVudCBkb20KICAgKiBpcyByZWFkaWVkIGluIHRoZSBwcm9wZXIgb3JkZXIsIG1haW50YWluaW5nIHRoZSBkZXNpcmVkIGd1YXJhbnRlZS4KICAgKgogICAqIEBwcml2YXRlCiAgICovCiAgbGV0IGhvc3RTdGFjayA9IHsKCiAgICBzdGFjazogW10sCgogICAgLyoqCiAgICAgKiBAcGFyYW0geyp9IGluc3QgSW5zdGFuY2UgdG8gYWRkIHRvIGhvc3RTdGFjawogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqIEB0aGlzIHtob3N0U3RhY2t9CiAgICAgKi8KICAgIHJlZ2lzdGVySG9zdChpbnN0KSB7CiAgICAgIGlmICh0aGlzLnN0YWNrLmxlbmd0aCkgewogICAgICAgIGxldCBob3N0ID0gdGhpcy5zdGFja1t0aGlzLnN0YWNrLmxlbmd0aC0xXTsKICAgICAgICBob3N0Ll9lbnF1ZXVlQ2xpZW50KGluc3QpOwogICAgICB9CiAgICB9LAoKICAgIC8qKgogICAgICogQHBhcmFtIHsqfSBpbnN0IEluc3RhbmNlIHRvIGJlZ2luIGhvc3RpbmcKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKiBAdGhpcyB7aG9zdFN0YWNrfQogICAgICovCiAgICBiZWdpbkhvc3RpbmcoaW5zdCkgewogICAgICB0aGlzLnN0YWNrLnB1c2goaW5zdCk7CiAgICB9LAoKICAgIC8qKgogICAgICogQHBhcmFtIHsqfSBpbnN0IEluc3RhbmNlIHRvIGVuZCBob3N0aW5nCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICogQHRoaXMge2hvc3RTdGFja30KICAgICAqLwogICAgZW5kSG9zdGluZyhpbnN0KSB7CiAgICAgIGxldCBzdGFja0xlbiA9IHRoaXMuc3RhY2subGVuZ3RoOwogICAgICBpZiAoc3RhY2tMZW4gJiYgdGhpcy5zdGFja1tzdGFja0xlbi0xXSA9PSBpbnN0KSB7CiAgICAgICAgdGhpcy5zdGFjay5wb3AoKTsKICAgICAgfQogICAgfQoKICB9OwoKfSkoKTsKPC9zY3JpcHQ+PHNjcmlwdD4KKGZ1bmN0aW9uKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgLyoqCiAgICogUHJvdmlkZXMgYmFzaWMgdHJhY2tpbmcgb2YgZWxlbWVudCBkZWZpbml0aW9ucyAocmVnaXN0cmF0aW9ucykgYW5kCiAgICogaW5zdGFuY2UgY291bnRzLgogICAqCiAgICogQG5hbWVzcGFjZQogICAqIEBzdW1tYXJ5IFByb3ZpZGVzIGJhc2ljIHRyYWNraW5nIG9mIGVsZW1lbnQgZGVmaW5pdGlvbnMgKHJlZ2lzdHJhdGlvbnMpIGFuZAogICAqIGluc3RhbmNlIGNvdW50cy4KICAgKi8KICBQb2x5bWVyLnRlbGVtZXRyeSA9IHsKICAgIC8qKgogICAgICogVG90YWwgbnVtYmVyIG9mIFBvbHltZXIgZWxlbWVudCBpbnN0YW5jZXMgY3JlYXRlZC4KICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgKi8KICAgIGluc3RhbmNlQ291bnQ6IDAsCiAgICAvKioKICAgICAqIEFycmF5IG9mIFBvbHltZXIgZWxlbWVudCBjbGFzc2VzIHRoYXQgaGF2ZSBiZWVuIGZpbmFsaXplZC4KICAgICAqIEB0eXBlIHtBcnJheTxQb2x5bWVyLkVsZW1lbnQ+fQogICAgICovCiAgICByZWdpc3RyYXRpb25zOiBbXSwKICAgIC8qKgogICAgICogQHBhcmFtIHshUG9seW1lckVsZW1lbnRDb25zdHJ1Y3Rvcn0gcHJvdG90eXBlIEVsZW1lbnQgcHJvdG90eXBlIHRvIGxvZwogICAgICogQHRoaXMge3RoaXN9CiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBfcmVnTG9nOiBmdW5jdGlvbihwcm90b3R5cGUpIHsKICAgICAgY29uc29sZS5sb2coJ1snICsgcHJvdG90eXBlLmlzICsgJ106IHJlZ2lzdGVyZWQnKTsKICAgIH0sCiAgICAvKioKICAgICAqIFJlZ2lzdGVycyBhIGNsYXNzIHByb3RvdHlwZSBmb3IgdGVsZW1ldHJ5IHB1cnBvc2VzLgogICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gcHJvdG90eXBlIEVsZW1lbnQgcHJvdG90eXBlIHRvIHJlZ2lzdGVyCiAgICAgKiBAdGhpcyB7dGhpc30KICAgICAqIEBwcm90ZWN0ZWQKICAgICAqLwogICAgcmVnaXN0ZXI6IGZ1bmN0aW9uKHByb3RvdHlwZSkgewogICAgICB0aGlzLnJlZ2lzdHJhdGlvbnMucHVzaChwcm90b3R5cGUpOwogICAgICBQb2x5bWVyLmxvZyAmJiB0aGlzLl9yZWdMb2cocHJvdG90eXBlKTsKICAgIH0sCiAgICAvKioKICAgICAqIExvZ3MgYWxsIGVsZW1lbnRzIHJlZ2lzdGVyZWQgd2l0aCBhbiBgaXNgIHRvIHRoZSBjb25zb2xlLgogICAgICogQHB1YmxpYwogICAgICogQHRoaXMge3RoaXN9CiAgICAgKi8KICAgIGR1bXBSZWdpc3RyYXRpb25zOiBmdW5jdGlvbigpIHsKICAgICAgdGhpcy5yZWdpc3RyYXRpb25zLmZvckVhY2godGhpcy5fcmVnTG9nKTsKICAgIH0KICB9OwoKfSkoKTsKPC9zY3JpcHQ+PHNjcmlwdD4KKGZ1bmN0aW9uKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgLyoqCiAgICogQ3JlYXRlcyBhIGNvcHkgb2YgYHByb3BzYCB3aXRoIGVhY2ggcHJvcGVydHkgbm9ybWFsaXplZCBzdWNoIHRoYXQKICAgKiB1cGdyYWRlZCBpdCBpcyBhbiBvYmplY3Qgd2l0aCBhdCBsZWFzdCBhIHR5cGUgcHJvcGVydHkgeyB0eXBlOiBUeXBlfS4KICAgKgogICAqIEBwYXJhbSB7T2JqZWN0fSBwcm9wcyBQcm9wZXJ0aWVzIHRvIG5vcm1hbGl6ZQogICAqIEByZXR1cm4ge09iamVjdH0gQ29weSBvZiBpbnB1dCBgcHJvcHNgIHdpdGggbm9ybWFsaXplZCBwcm9wZXJ0aWVzIHRoYXQKICAgKiBhcmUgaW4gdGhlIGZvcm0ge3R5cGU6IFR5cGV9CiAgICogQHByaXZhdGUKICAgKi8KICBmdW5jdGlvbiBub3JtYWxpemVQcm9wZXJ0aWVzKHByb3BzKSB7CiAgICBjb25zdCBvdXRwdXQgPSB7fTsKICAgIGZvciAobGV0IHAgaW4gcHJvcHMpIHsKICAgICAgY29uc3QgbyA9IHByb3BzW3BdOwogICAgICBvdXRwdXRbcF0gPSAodHlwZW9mIG8gPT09ICdmdW5jdGlvbicpID8ge3R5cGU6IG99IDogbzsKICAgIH0KICAgIHJldHVybiBvdXRwdXQ7CiAgfQoKICAvKioKICAgKiBNaXhpbiB0aGF0IHByb3ZpZGVzIGEgbWluaW1hbCBzdGFydGluZyBwb2ludCB0byB1c2luZyB0aGUgUHJvcGVydGllc0NoYW5nZWQKICAgKiBtaXhpbiBieSBwcm92aWRpbmcgYSBtZWNoYW5pc20gdG8gZGVjbGFyZSBwcm9wZXJ0aWVzIGluIGEgc3RhdGljCiAgICogZ2V0dGVyIChlLmcuIHN0YXRpYyBnZXQgcHJvcGVydGllcygpIHsgcmV0dXJuIHsgZm9vOiBTdHJpbmcgfSB9KS4gQ2hhbmdlcwogICAqIGFyZSByZXBvcnRlZCB2aWEgdGhlIGBfcHJvcGVydGllc0NoYW5nZWRgIG1ldGhvZC4KICAgKgogICAqIFRoaXMgbWl4aW4gcHJvdmlkZXMgbm8gc3BlY2lmaWMgc3VwcG9ydCBmb3IgcmVuZGVyaW5nLiBVc2VycyBhcmUgZXhwZWN0ZWQKICAgKiB0byBjcmVhdGUgYSBTaGFkb3dSb290IGFuZCBwdXQgY29udGVudCBpbnRvIGl0IGFuZCB1cGRhdGUgaXQgaW4gd2hhdGV2ZXIKICAgKiB3YXkgbWFrZXMgc2Vuc2UuIFRoaXMgY2FuIGJlIGRvbmUgaW4gcmVhY3Rpb24gdG8gcHJvcGVydGllcyBjaGFuZ2luZyBieQogICAqIGltcGxlbWVudGluZyBgX3Byb3BlcnRpZXNDaGFuZ2VkYC4KICAgKgogICAqIEBtaXhpbkZ1bmN0aW9uCiAgICogQHBvbHltZXIKICAgKiBAYXBwbGllc01peGluIFBvbHltZXIuUHJvcGVydGllc0NoYW5nZWQKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBzdW1tYXJ5IE1peGluIHRoYXQgcHJvdmlkZXMgYSBtaW5pbWFsIHN0YXJ0aW5nIHBvaW50IGZvciB1c2luZwogICAqIHRoZSBQcm9wZXJ0aWVzQ2hhbmdlZCBtaXhpbiBieSBwcm92aWRpbmcgYSBkZWNsYXJhdGl2ZSBgcHJvcGVydGllc2Agb2JqZWN0LgogICAqLwogICBQb2x5bWVyLlByb3BlcnRpZXNNaXhpbiA9IFBvbHltZXIuZGVkdXBpbmdNaXhpbihzdXBlckNsYXNzID0+IHsKCiAgICAvKioKICAgICAqIEBjb25zdHJ1Y3RvcgogICAgICogQGV4dGVuZHMge3N1cGVyQ2xhc3N9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9Qcm9wZXJ0aWVzQ2hhbmdlZH0KICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIGNvbnN0IGJhc2UgPSBQb2x5bWVyLlByb3BlcnRpZXNDaGFuZ2VkKHN1cGVyQ2xhc3MpOwoKICAgIC8qKgogICAgICogUmV0dXJucyB0aGUgc3VwZXIgY2xhc3MgY29uc3RydWN0b3IgZm9yIHRoZSBnaXZlbiBjbGFzcywgaWYgaXQgaXMgYW4KICAgICAqIGluc3RhbmNlIG9mIHRoZSBQcm9wZXJ0aWVzTWl4aW4uCiAgICAgKgogICAgICogQHBhcmFtIHshUHJvcGVydGllc01peGluQ29uc3RydWN0b3J9IGNvbnN0cnVjdG9yIFByb3BlcnRpZXNNaXhpbiBjb25zdHJ1Y3RvcgogICAgICogQHJldHVybiB7UHJvcGVydGllc01peGluQ29uc3RydWN0b3J9IFN1cGVyIGNsYXNzIGNvbnN0cnVjdG9yCiAgICAgKi8KICAgIGZ1bmN0aW9uIHN1cGVyUHJvcGVydGllc0NsYXNzKGNvbnN0cnVjdG9yKSB7CiAgICAgIGNvbnN0IHN1cGVyQ3RvciA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihjb25zdHJ1Y3Rvcik7CgogICAgICAvLyBOb3RlLCB0aGUgYFByb3BlcnRpZXNNaXhpbmAgY2xhc3MgYmVsb3cgb25seSByZWZlcnMgdG8gdGhlIGNsYXNzCiAgICAgIC8vIGdlbmVyYXRlZCBieSB0aGlzIGNhbGwgdG8gdGhlIG1peGluOyB0aGUgaW5zdGFuY2VvZiB0ZXN0IG9ubHkgd29ya3MKICAgICAgLy8gYmVjYXVzZSB0aGUgbWl4aW4gaXMgZGVkdXBlZCBhbmQgZ3VhcmFudGVlZCBvbmx5IHRvIGFwcGx5IG9uY2UsIGhlbmNlCiAgICAgIC8vIGFsbCBjb25zdHJ1Y3RvcnMgaW4gYSBwcm90byBjaGFpbiB3aWxsIHNlZSB0aGUgc2FtZSBgUHJvcGVydGllc01peGluYAogICAgICByZXR1cm4gKHN1cGVyQ3Rvci5wcm90b3R5cGUgaW5zdGFuY2VvZiBQcm9wZXJ0aWVzTWl4aW4pID8KICAgICAgICAvKiogQHR5cGUge1Byb3BlcnRpZXNNaXhpbkNvbnN0cnVjdG9yfSAqLyAoc3VwZXJDdG9yKSA6IG51bGw7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgbWVtb2l6ZWQgdmVyc2lvbiBvZiB0aGUgYHByb3BlcnRpZXNgIG9iamVjdCBmb3IgdGhlCiAgICAgKiBnaXZlbiBjbGFzcy4gUHJvcGVydGllcyBub3QgaW4gb2JqZWN0IGZvcm1hdCBhcmUgY29udmVydGVkIHRvIGF0CiAgICAgKiBsZWFzdCB7dHlwZX0uCiAgICAgKgogICAgICogQHBhcmFtIHtQcm9wZXJ0aWVzTWl4aW5Db25zdHJ1Y3Rvcn0gY29uc3RydWN0b3IgUHJvcGVydGllc01peGluIGNvbnN0cnVjdG9yCiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IE1lbW9pemVkIHByb3BlcnRpZXMgb2JqZWN0CiAgICAgKi8KICAgIGZ1bmN0aW9uIG93blByb3BlcnRpZXMoY29uc3RydWN0b3IpIHsKICAgICAgaWYgKCFjb25zdHJ1Y3Rvci5oYXNPd25Qcm9wZXJ0eShKU0NvbXBpbGVyX3JlbmFtZVByb3BlcnR5KCdfX293blByb3BlcnRpZXMnLCBjb25zdHJ1Y3RvcikpKSB7CiAgICAgICAgbGV0IHByb3BzID0gbnVsbDsKCiAgICAgICAgaWYgKGNvbnN0cnVjdG9yLmhhc093blByb3BlcnR5KEpTQ29tcGlsZXJfcmVuYW1lUHJvcGVydHkoJ3Byb3BlcnRpZXMnLCBjb25zdHJ1Y3RvcikpKSB7CiAgICAgICAgICBjb25zdCBwcm9wZXJ0aWVzID0gY29uc3RydWN0b3IucHJvcGVydGllczsKICAgICAgICAgIAogICAgICAgICAgaWYgKHByb3BlcnRpZXMpIHsKICAgICAgICAgICAgcHJvcHMgPSBub3JtYWxpemVQcm9wZXJ0aWVzKHByb3BlcnRpZXMpOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgY29uc3RydWN0b3IuX19vd25Qcm9wZXJ0aWVzID0gcHJvcHM7CiAgICAgIH0KICAgICAgcmV0dXJuIGNvbnN0cnVjdG9yLl9fb3duUHJvcGVydGllczsKICAgIH0KCiAgICAvKioKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAbWl4aW5DbGFzcwogICAgICogQGV4dGVuZHMge2Jhc2V9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9Qcm9wZXJ0aWVzTWl4aW59CiAgICAgKiBAdW5yZXN0cmljdGVkCiAgICAgKi8KICAgIGNsYXNzIFByb3BlcnRpZXNNaXhpbiBleHRlbmRzIGJhc2UgewoKICAgICAgLyoqCiAgICAgICAqIEltcGxlbWVudHMgc3RhbmRhcmQgY3VzdG9tIGVsZW1lbnRzIGdldHRlciB0byBvYnNlcnZlcyB0aGUgYXR0cmlidXRlcwogICAgICAgKiBsaXN0ZWQgaW4gYHByb3BlcnRpZXNgLgogICAgICAgKiBAc3VwcHJlc3Mge21pc3NpbmdQcm9wZXJ0aWVzfSBJbnRlcmZhY2VzIGluIGNsb3N1cmUgZG8gbm90IGluaGVyaXQgc3RhdGljcywgYnV0IGNsYXNzZXMgZG8KICAgICAgICovCiAgICAgIHN0YXRpYyBnZXQgb2JzZXJ2ZWRBdHRyaWJ1dGVzKCkgewogICAgICAgIGlmICghdGhpcy5oYXNPd25Qcm9wZXJ0eSgnX19vYnNlcnZlZEF0dHJpYnV0ZXMnKSkgewogICAgICAgICAgUG9seW1lci50ZWxlbWV0cnkucmVnaXN0ZXIodGhpcy5wcm90b3R5cGUpOwogICAgICAgICAgY29uc3QgcHJvcHMgPSB0aGlzLl9wcm9wZXJ0aWVzOwogICAgICAgICAgdGhpcy5fX29ic2VydmVkQXR0cmlidXRlcyA9IHByb3BzID8gT2JqZWN0LmtleXMocHJvcHMpLm1hcChwID0+IHRoaXMuYXR0cmlidXRlTmFtZUZvclByb3BlcnR5KHApKSA6IFtdOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdGhpcy5fX29ic2VydmVkQXR0cmlidXRlczsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEZpbmFsaXplcyBhbiBlbGVtZW50IGRlZmluaXRpb24sIGluY2x1ZGluZyBlbnN1cmluZyBhbnkgc3VwZXIgY2xhc3NlcwogICAgICAgKiBhcmUgYWxzbyBmaW5hbGl6ZWQuIFRoaXMgaW5jbHVkZXMgZW5zdXJpbmcgcHJvcGVydHkKICAgICAgICogYWNjZXNzb3JzIGV4aXN0IG9uIHRoZSBlbGVtZW50IHByb3RvdHlwZS4gVGhpcyBtZXRob2QgY2FsbHMKICAgICAgICogYF9maW5hbGl6ZUNsYXNzYCB0byBmaW5hbGl6ZSBlYWNoIGNvbnN0cnVjdG9yIGluIHRoZSBwcm90b3R5cGUgY2hhaW4uCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBzdGF0aWMgZmluYWxpemUoKSB7CiAgICAgICAgaWYgKCF0aGlzLmhhc093blByb3BlcnR5KEpTQ29tcGlsZXJfcmVuYW1lUHJvcGVydHkoJ19fZmluYWxpemVkJywgdGhpcykpKSB7CiAgICAgICAgICBjb25zdCBzdXBlckN0b3IgPSBzdXBlclByb3BlcnRpZXNDbGFzcygvKiogQHR5cGUge1Byb3BlcnRpZXNNaXhpbkNvbnN0cnVjdG9yfSAqLyh0aGlzKSk7CiAgICAgICAgICBpZiAoc3VwZXJDdG9yKSB7CiAgICAgICAgICAgIHN1cGVyQ3Rvci5maW5hbGl6ZSgpOwogICAgICAgICAgfQogICAgICAgICAgdGhpcy5fX2ZpbmFsaXplZCA9IHRydWU7CiAgICAgICAgICB0aGlzLl9maW5hbGl6ZUNsYXNzKCk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogRmluYWxpemUgYW4gZWxlbWVudCBjbGFzcy4gVGhpcyBpbmNsdWRlcyBlbnN1cmluZyBwcm9wZXJ0eQogICAgICAgKiBhY2Nlc3NvcnMgZXhpc3Qgb24gdGhlIGVsZW1lbnQgcHJvdG90eXBlLiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgYnkKICAgICAgICogYGZpbmFsaXplYCBhbmQgZmluYWxpemVzIHRoZSBjbGFzcyBjb25zdHJ1Y3Rvci4KICAgICAgICoKICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgc3RhdGljIF9maW5hbGl6ZUNsYXNzKCkgewogICAgICAgIGNvbnN0IHByb3BzID0gb3duUHJvcGVydGllcygvKiogQHR5cGUge1Byb3BlcnRpZXNNaXhpbkNvbnN0cnVjdG9yfSAqLyh0aGlzKSk7CiAgICAgICAgaWYgKHByb3BzKSB7CiAgICAgICAgICB0aGlzLmNyZWF0ZVByb3BlcnRpZXMocHJvcHMpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgYSBtZW1vaXplZCB2ZXJzaW9uIG9mIGFsbCBwcm9wZXJ0aWVzLCBpbmNsdWRpbmcgdGhvc2UgaW5oZXJpdGVkCiAgICAgICAqIGZyb20gc3VwZXIgY2xhc3Nlcy4gUHJvcGVydGllcyBub3QgaW4gb2JqZWN0IGZvcm1hdCBhcmUgY29udmVydGVkIHRvCiAgICAgICAqIGF0IGxlYXN0IHt0eXBlfS4KICAgICAgICoKICAgICAgICogQHJldHVybiB7T2JqZWN0fSBPYmplY3QgY29udGFpbmluZyBwcm9wZXJ0aWVzIGZvciB0aGlzIGNsYXNzCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIHN0YXRpYyBnZXQgX3Byb3BlcnRpZXMoKSB7CiAgICAgICAgaWYgKCF0aGlzLmhhc093blByb3BlcnR5KAogICAgICAgICAgSlNDb21waWxlcl9yZW5hbWVQcm9wZXJ0eSgnX19wcm9wZXJ0aWVzJywgdGhpcykpKSB7CiAgICAgICAgICBjb25zdCBzdXBlckN0b3IgPSBzdXBlclByb3BlcnRpZXNDbGFzcygvKiogQHR5cGUge1Byb3BlcnRpZXNNaXhpbkNvbnN0cnVjdG9yfSAqLyh0aGlzKSk7CiAgICAgICAgICB0aGlzLl9fcHJvcGVydGllcyA9IE9iamVjdC5hc3NpZ24oe30sCiAgICAgICAgICAgIHN1cGVyQ3RvciAmJiBzdXBlckN0b3IuX3Byb3BlcnRpZXMsCiAgICAgICAgICAgIG93blByb3BlcnRpZXMoLyoqIEB0eXBlIHtQcm9wZXJ0aWVzTWl4aW5Db25zdHJ1Y3Rvcn0gKi8odGhpcykpKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRoaXMuX19wcm9wZXJ0aWVzOwogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGVzIGBQcm9wZXJ0aWVzQ2hhbmdlZGAgbWV0aG9kIHRvIHJldHVybiB0eXBlIHNwZWNpZmllZCBpbiB0aGUKICAgICAgICogc3RhdGljIGBwcm9wZXJ0aWVzYCBvYmplY3QgZm9yIHRoZSBnaXZlbiBwcm9wZXJ0eS4KICAgICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgTmFtZSBvZiBwcm9wZXJ0eQogICAgICAgKiBAcmV0dXJuIHsqfSBUeXBlIHRvIHdoaWNoIHRvIGRlc2VyaWFsaXplIGF0dHJpYnV0ZQogICAgICAgKgogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBzdGF0aWMgdHlwZUZvclByb3BlcnR5KG5hbWUpIHsKICAgICAgICBjb25zdCBpbmZvID0gdGhpcy5fcHJvcGVydGllc1tuYW1lXTsKICAgICAgICByZXR1cm4gaW5mbyAmJiBpbmZvLnR5cGU7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZXMgYFByb3BlcnRpZXNDaGFuZ2VkYCBtZXRob2QgYW5kIGFkZHMgYSBjYWxsIHRvCiAgICAgICAqIGBmaW5hbGl6ZWAgd2hpY2ggbGF6aWx5IGNvbmZpZ3VyZXMgdGhlIGVsZW1lbnQncyBwcm9wZXJ0eSBhY2Nlc3NvcnMuCiAgICAgICAqIEBvdmVycmlkZQogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX2luaXRpYWxpemVQcm9wZXJ0aWVzKCkgewogICAgICAgIFBvbHltZXIudGVsZW1ldHJ5Lmluc3RhbmNlQ291bnQrKzsKICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLmZpbmFsaXplKCk7CiAgICAgICAgc3VwZXIuX2luaXRpYWxpemVQcm9wZXJ0aWVzKCk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCBpcyBhZGRlZCB0byBhIGRvY3VtZW50LgogICAgICAgKiBDYWxscyBgX2VuYWJsZVByb3BlcnRpZXNgIHRvIHR1cm4gb24gcHJvcGVydHkgc3lzdGVtIGZyb20KICAgICAgICogYFByb3BlcnRpZXNDaGFuZ2VkYC4KICAgICAgICogQHN1cHByZXNzIHttaXNzaW5nUHJvcGVydGllc30gU3VwZXIgbWF5IG9yIG1heSBub3QgaW1wbGVtZW50IHRoZSBjYWxsYmFjawogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgY29ubmVjdGVkQ2FsbGJhY2soKSB7CiAgICAgICAgaWYgKHN1cGVyLmNvbm5lY3RlZENhbGxiYWNrKSB7CiAgICAgICAgICBzdXBlci5jb25uZWN0ZWRDYWxsYmFjaygpOwogICAgICAgIH0KICAgICAgICB0aGlzLl9lbmFibGVQcm9wZXJ0aWVzKCk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudCBpcyByZW1vdmVkIGZyb20gYSBkb2N1bWVudAogICAgICAgKiBAc3VwcHJlc3Mge21pc3NpbmdQcm9wZXJ0aWVzfSBTdXBlciBtYXkgb3IgbWF5IG5vdCBpbXBsZW1lbnQgdGhlIGNhbGxiYWNrCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBkaXNjb25uZWN0ZWRDYWxsYmFjaygpIHsKICAgICAgICBpZiAoc3VwZXIuZGlzY29ubmVjdGVkQ2FsbGJhY2spIHsKICAgICAgICAgIHN1cGVyLmRpc2Nvbm5lY3RlZENhbGxiYWNrKCk7CiAgICAgICAgfQogICAgICB9CgogICAgfQoKICAgIHJldHVybiBQcm9wZXJ0aWVzTWl4aW47CgogIH0pOwoKfSkoKTsKCjwvc2NyaXB0PjxzY3JpcHQ+CihmdW5jdGlvbigpIHsKICAndXNlIHN0cmljdCc7CgogIGNvbnN0IGJ1aWx0Q1NTID0gd2luZG93LlNoYWR5Q1NTICYmIHdpbmRvdy5TaGFkeUNTU1snY3NzQnVpbGQnXTsKCiAgLyoqCiAgICogRWxlbWVudCBjbGFzcyBtaXhpbiB0aGF0IHByb3ZpZGVzIHRoZSBjb3JlIEFQSSBmb3IgUG9seW1lcidzIG1ldGEtcHJvZ3JhbW1pbmcKICAgKiBmZWF0dXJlcyBpbmNsdWRpbmcgdGVtcGxhdGUgc3RhbXBpbmcsIGRhdGEtYmluZGluZywgYXR0cmlidXRlIGRlc2VyaWFsaXphdGlvbiwKICAgKiBhbmQgcHJvcGVydHkgY2hhbmdlIG9ic2VydmF0aW9uLgogICAqCiAgICogU3ViY2xhc3NlcnMgbWF5IHByb3ZpZGUgdGhlIGZvbGxvd2luZyBzdGF0aWMgZ2V0dGVycyB0byByZXR1cm4gbWV0YWRhdGEKICAgKiB1c2VkIHRvIGNvbmZpZ3VyZSBQb2x5bWVyJ3MgZmVhdHVyZXMgZm9yIHRoZSBjbGFzczoKICAgKgogICAqIC0gYHN0YXRpYyBnZXQgaXMoKWA6IFdoZW4gdGhlIHRlbXBsYXRlIGlzIHByb3ZpZGVkIHZpYSBhIGBkb20tbW9kdWxlYCwKICAgKiAgIHVzZXJzIHNob3VsZCByZXR1cm4gdGhlIGBkb20tbW9kdWxlYCBpZCBmcm9tIGEgc3RhdGljIGBpc2AgZ2V0dGVyLiAgSWYKICAgKiAgIG5vIHRlbXBsYXRlIGlzIG5lZWRlZCBvciB0aGUgdGVtcGxhdGUgaXMgcHJvdmlkZWQgZGlyZWN0bHkgdmlhIHRoZQogICAqICAgYHRlbXBsYXRlYCBnZXR0ZXIsIHRoZXJlIGlzIG5vIG5lZWQgdG8gZGVmaW5lIGBpc2AgZm9yIHRoZSBlbGVtZW50LgogICAqCiAgICogLSBgc3RhdGljIGdldCB0ZW1wbGF0ZSgpYDogVXNlcnMgbWF5IHByb3ZpZGUgdGhlIHRlbXBsYXRlIGRpcmVjdGx5IChhcwogICAqICAgb3Bwb3NlZCB0byB2aWEgYGRvbS1tb2R1bGVgKSBieSBpbXBsZW1lbnRpbmcgYSBzdGF0aWMgYHRlbXBsYXRlYCBnZXR0ZXIuCiAgICogICBUaGUgZ2V0dGVyIG1heSByZXR1cm4gYW4gYEhUTUxUZW1wbGF0ZUVsZW1lbnRgIG9yIGEgc3RyaW5nLCB3aGljaCB3aWxsCiAgICogICBhdXRvbWF0aWNhbGx5IGJlIHBhcnNlZCBpbnRvIGEgdGVtcGxhdGUuCiAgICoKICAgKiAtIGBzdGF0aWMgZ2V0IHByb3BlcnRpZXMoKWA6IFNob3VsZCByZXR1cm4gYW4gb2JqZWN0IGRlc2NyaWJpbmcKICAgKiAgIHByb3BlcnR5LXJlbGF0ZWQgbWV0YWRhdGEgdXNlZCBieSBQb2x5bWVyIGZlYXR1cmVzIChrZXk6IHByb3BlcnR5IG5hbWUKICAgKiAgIHZhbHVlOiBvYmplY3QgY29udGFpbmluZyBwcm9wZXJ0eSBtZXRhZGF0YSkuIFZhbGlkIGtleXMgaW4gcGVyLXByb3BlcnR5CiAgICogICBtZXRhZGF0YSBpbmNsdWRlOgogICAqICAgLSBgdHlwZWAgKFN0cmluZ3xOdW1iZXJ8T2JqZWN0fEFycmF5fC4uLik6IFVzZWQgYnkKICAgKiAgICAgYGF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFja2AgdG8gZGV0ZXJtaW5lIGhvdyBzdHJpbmctYmFzZWQgYXR0cmlidXRlcwogICAqICAgICBhcmUgZGVzZXJpYWxpemVkIHRvIEphdmFTY3JpcHQgcHJvcGVydHkgdmFsdWVzLgogICAqICAgLSBgbm90aWZ5YCAoYm9vbGVhbik6IENhdXNlcyBhIGNoYW5nZSBpbiB0aGUgcHJvcGVydHkgdG8gZmlyZSBhCiAgICogICAgIG5vbi1idWJibGluZyBldmVudCBjYWxsZWQgYDxwcm9wZXJ0eT4tY2hhbmdlZGAuIEVsZW1lbnRzIHRoYXQgaGF2ZQogICAqICAgICBlbmFibGVkIHR3by13YXkgYmluZGluZyB0byB0aGUgcHJvcGVydHkgdXNlIHRoaXMgZXZlbnQgdG8gb2JzZXJ2ZSBjaGFuZ2VzLgogICAqICAgLSBgcmVhZE9ubHlgIChib29sZWFuKTogQ3JlYXRlcyBhIGdldHRlciBmb3IgdGhlIHByb3BlcnR5LCBidXQgbm8gc2V0dGVyLgogICAqICAgICBUbyBzZXQgYSByZWFkLW9ubHkgcHJvcGVydHksIHVzZSB0aGUgcHJpdmF0ZSBzZXR0ZXIgbWV0aG9kCiAgICogICAgIGBfc2V0UHJvcGVydHkocHJvcGVydHksIHZhbHVlKWAuCiAgICogICAtIGBvYnNlcnZlcmAgKHN0cmluZyk6IE9ic2VydmVyIG1ldGhvZCBuYW1lIHRoYXQgd2lsbCBiZSBjYWxsZWQgd2hlbgogICAqICAgICB0aGUgcHJvcGVydHkgY2hhbmdlcy4gVGhlIGFyZ3VtZW50cyBvZiB0aGUgbWV0aG9kIGFyZQogICAqICAgICBgKHZhbHVlLCBwcmV2aW91c1ZhbHVlKWAuCiAgICogICAtIGBjb21wdXRlZGAgKHN0cmluZyk6IFN0cmluZyBkZXNjcmliaW5nIG1ldGhvZCBhbmQgZGVwZW5kZW50IHByb3BlcnRpZXMKICAgKiAgICAgZm9yIGNvbXB1dGluZyB0aGUgdmFsdWUgb2YgdGhpcyBwcm9wZXJ0eSAoZS5nLiBgJ2NvbXB1dGVGb28oYmFyLCB6b3QpJ2ApLgogICAqICAgICBDb21wdXRlZCBwcm9wZXJ0aWVzIGFyZSByZWFkLW9ubHkgYnkgZGVmYXVsdCBhbmQgY2FuIG9ubHkgYmUgY2hhbmdlZAogICAqICAgICB2aWEgdGhlIHJldHVybiB2YWx1ZSBvZiB0aGUgY29tcHV0aW5nIG1ldGhvZC4KICAgKgogICAqIC0gYHN0YXRpYyBnZXQgb2JzZXJ2ZXJzKClgOiBBcnJheSBvZiBzdHJpbmdzIGRlc2NyaWJpbmcgbXVsdGktcHJvcGVydHkKICAgKiAgIG9ic2VydmVyIG1ldGhvZHMgYW5kIHRoZWlyIGRlcGVuZGVudCBwcm9wZXJ0aWVzIChlLmcuCiAgICogICBgJ29ic2VydmVBQkMoYSwgYiwgYyknYCkuCiAgICoKICAgKiBUaGUgYmFzZSBjbGFzcyBwcm92aWRlcyBkZWZhdWx0IGltcGxlbWVudGF0aW9ucyBmb3IgdGhlIGZvbGxvd2luZyBzdGFuZGFyZAogICAqIGN1c3RvbSBlbGVtZW50IGxpZmVjeWNsZSBjYWxsYmFja3M7IHVzZXJzIG1heSBvdmVycmlkZSB0aGVzZSwgYnV0IHNob3VsZAogICAqIGNhbGwgdGhlIHN1cGVyIG1ldGhvZCB0byBlbnN1cmUKICAgKiAtIGBjb25zdHJ1Y3RvcmA6IFJ1biB3aGVuIHRoZSBlbGVtZW50IGlzIGNyZWF0ZWQgb3IgdXBncmFkZWQKICAgKiAtIGBjb25uZWN0ZWRDYWxsYmFja2A6IFJ1biBlYWNoIHRpbWUgdGhlIGVsZW1lbnQgaXMgY29ubmVjdGVkIHRvIHRoZQogICAqICAgZG9jdW1lbnQKICAgKiAtIGBkaXNjb25uZWN0ZWRDYWxsYmFja2A6IFJ1biBlYWNoIHRpbWUgdGhlIGVsZW1lbnQgaXMgZGlzY29ubmVjdGVkIGZyb20KICAgKiAgIHRoZSBkb2N1bWVudAogICAqIC0gYGF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFja2A6IFJ1biBlYWNoIHRpbWUgYW4gYXR0cmlidXRlIGluCiAgICogICBgb2JzZXJ2ZWRBdHRyaWJ1dGVzYCBpcyBzZXQgb3IgcmVtb3ZlZCAobm90ZTogdGhpcyBlbGVtZW50J3MgZGVmYXVsdAogICAqICAgYG9ic2VydmVkQXR0cmlidXRlc2AgaW1wbGVtZW50YXRpb24gd2lsbCBhdXRvbWF0aWNhbGx5IHJldHVybiBhbiBhcnJheQogICAqICAgb2YgZGFzaC1jYXNlZCBhdHRyaWJ1dGVzIGJhc2VkIG9uIGBwcm9wZXJ0aWVzYCkKICAgKgogICAqIEBtaXhpbkZ1bmN0aW9uCiAgICogQHBvbHltZXIKICAgKiBAYXBwbGllc01peGluIFBvbHltZXIuUHJvcGVydHlFZmZlY3RzCiAgICogQGFwcGxpZXNNaXhpbiBQb2x5bWVyLlByb3BlcnRpZXNNaXhpbgogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICogQHByb3BlcnR5IHJvb3RQYXRoIHtzdHJpbmd9IFNldCB0byB0aGUgdmFsdWUgb2YgYFBvbHltZXIucm9vdFBhdGhgLAogICAqICAgd2hpY2ggZGVmYXVsdHMgdG8gdGhlIG1haW4gZG9jdW1lbnQgcGF0aAogICAqIEBwcm9wZXJ0eSBpbXBvcnRQYXRoIHtzdHJpbmd9IFNldCB0byB0aGUgdmFsdWUgb2YgdGhlIGNsYXNzJ3Mgc3RhdGljCiAgICogICBgaW1wb3J0UGF0aGAgcHJvcGVydHksIHdoaWNoIGRlZmF1bHRzIHRvIHRoZSBwYXRoIG9mIHRoaXMgZWxlbWVudCdzCiAgICogICBgZG9tLW1vZHVsZWAgKHdoZW4gYGlzYCBpcyB1c2VkKSwgYnV0IGNhbiBiZSBvdmVycmlkZGVuIGZvciBvdGhlcgogICAqICAgaW1wb3J0IHN0cmF0ZWdpZXMuCiAgICogQHN1bW1hcnkgRWxlbWVudCBjbGFzcyBtaXhpbiB0aGF0IHByb3ZpZGVzIHRoZSBjb3JlIEFQSSBmb3IgUG9seW1lcidzCiAgICogbWV0YS1wcm9ncmFtbWluZyBmZWF0dXJlcy4KICAgKi8KICBQb2x5bWVyLkVsZW1lbnRNaXhpbiA9IFBvbHltZXIuZGVkdXBpbmdNaXhpbihiYXNlID0+IHsKCiAgICAvKioKICAgICAqIEBjb25zdHJ1Y3RvcgogICAgICogQGV4dGVuZHMge2Jhc2V9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9Qcm9wZXJ0eUVmZmVjdHN9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9Qcm9wZXJ0aWVzTWl4aW59CiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBjb25zdCBwb2x5bWVyRWxlbWVudEJhc2UgPSBQb2x5bWVyLlByb3BlcnRpZXNNaXhpbihQb2x5bWVyLlByb3BlcnR5RWZmZWN0cyhiYXNlKSk7CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgbGlzdCBvZiBwcm9wZXJ0aWVzIHdpdGggZGVmYXVsdCB2YWx1ZXMuCiAgICAgKiBUaGlzIGxpc3QgaXMgY3JlYXRlZCBhcyBhbiBvcHRpbWl6YXRpb24gc2luY2UgaXQgaXMgYSBzdWJzZXQgb2YKICAgICAqIHRoZSBsaXN0IHJldHVybmVkIGZyb20gYF9wcm9wZXJ0aWVzYC4KICAgICAqIFRoaXMgbGlzdCBpcyB1c2VkIGluIGBfaW5pdGlhbGl6ZVByb3BlcnRpZXNgIHRvIHNldCBwcm9wZXJ0eSBkZWZhdWx0cy4KICAgICAqCiAgICAgKiBAcGFyYW0ge1BvbHltZXJFbGVtZW50Q29uc3RydWN0b3J9IGNvbnN0cnVjdG9yIEVsZW1lbnQgY2xhc3MKICAgICAqIEByZXR1cm4ge1BvbHltZXJFbGVtZW50UHJvcGVydGllc30gRmxhdHRlbmVkIHByb3BlcnRpZXMgZm9yIHRoaXMgY2xhc3MKICAgICAqICAgdGhhdCBoYXZlIGRlZmF1bHQgdmFsdWVzCiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBmdW5jdGlvbiBwcm9wZXJ0eURlZmF1bHRzKGNvbnN0cnVjdG9yKSB7CiAgICAgIGlmICghY29uc3RydWN0b3IuaGFzT3duUHJvcGVydHkoCiAgICAgICAgSlNDb21waWxlcl9yZW5hbWVQcm9wZXJ0eSgnX19wcm9wZXJ0eURlZmF1bHRzJywgY29uc3RydWN0b3IpKSkgewogICAgICAgIGNvbnN0cnVjdG9yLl9fcHJvcGVydHlEZWZhdWx0cyA9IG51bGw7CiAgICAgICAgbGV0IHByb3BzID0gY29uc3RydWN0b3IuX3Byb3BlcnRpZXM7CiAgICAgICAgZm9yIChsZXQgcCBpbiBwcm9wcykgewogICAgICAgICAgbGV0IGluZm8gPSBwcm9wc1twXTsKICAgICAgICAgIGlmICgndmFsdWUnIGluIGluZm8pIHsKICAgICAgICAgICAgY29uc3RydWN0b3IuX19wcm9wZXJ0eURlZmF1bHRzID0gY29uc3RydWN0b3IuX19wcm9wZXJ0eURlZmF1bHRzIHx8IHt9OwogICAgICAgICAgICBjb25zdHJ1Y3Rvci5fX3Byb3BlcnR5RGVmYXVsdHNbcF0gPSBpbmZvOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gY29uc3RydWN0b3IuX19wcm9wZXJ0eURlZmF1bHRzOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyBhIG1lbW9pemVkIHZlcnNpb24gb2YgdGhlIGBvYnNlcnZlcnNgIGFycmF5LgogICAgICogQHBhcmFtIHtQb2x5bWVyRWxlbWVudENvbnN0cnVjdG9yfSBjb25zdHJ1Y3RvciBFbGVtZW50IGNsYXNzCiAgICAgKiBAcmV0dXJuIHtBcnJheX0gQXJyYXkgY29udGFpbmluZyBvd24gb2JzZXJ2ZXJzIGZvciB0aGUgZ2l2ZW4gY2xhc3MKICAgICAqIEBwcm90ZWN0ZWQKICAgICAqLwogICAgZnVuY3Rpb24gb3duT2JzZXJ2ZXJzKGNvbnN0cnVjdG9yKSB7CiAgICAgIGlmICghY29uc3RydWN0b3IuaGFzT3duUHJvcGVydHkoCiAgICAgICAgSlNDb21waWxlcl9yZW5hbWVQcm9wZXJ0eSgnX19vd25PYnNlcnZlcnMnLCBjb25zdHJ1Y3RvcikpKSB7CiAgICAgICAgICBjb25zdHJ1Y3Rvci5fX293bk9ic2VydmVycyA9CiAgICAgICAgICBjb25zdHJ1Y3Rvci5oYXNPd25Qcm9wZXJ0eShKU0NvbXBpbGVyX3JlbmFtZVByb3BlcnR5KCdvYnNlcnZlcnMnLCBjb25zdHJ1Y3RvcikpID8KICAgICAgICAgIC8qKiBAdHlwZSB7UG9seW1lckVsZW1lbnRDb25zdHJ1Y3Rvcn0gKi8gKGNvbnN0cnVjdG9yKS5vYnNlcnZlcnMgOiBudWxsOwogICAgICB9CiAgICAgIHJldHVybiBjb25zdHJ1Y3Rvci5fX293bk9ic2VydmVyczsKICAgIH0KCiAgICAvKioKICAgICAqIENyZWF0ZXMgZWZmZWN0cyBmb3IgYSBwcm9wZXJ0eS4KICAgICAqCiAgICAgKiBOb3RlLCBvbmNlIGEgcHJvcGVydHkgaGFzIGJlZW4gc2V0IHRvCiAgICAgKiBgcmVhZE9ubHlgLCBgY29tcHV0ZWRgLCBgcmVmbGVjdFRvQXR0cmlidXRlYCwgb3IgYG5vdGlmeWAKICAgICAqIHRoZXNlIHZhbHVlcyBtYXkgbm90IGJlIGNoYW5nZWQuIEZvciBleGFtcGxlLCBhIHN1YmNsYXNzIGNhbm5vdAogICAgICogYWx0ZXIgdGhlc2Ugc2V0dGluZ3MuIEhvd2V2ZXIsIGFkZGl0aW9uYWwgYG9ic2VydmVyc2AgbWF5IGJlIGFkZGVkCiAgICAgKiBieSBzdWJjbGFzc2VzLgogICAgICoKICAgICAqIFRoZSBpbmZvIG9iamVjdCBzaG91bGQgY29udGFpbiBwcm9wZXJ0eSBtZXRhZGF0YSBhcyBmb2xsb3dzOgogICAgICoKICAgICAqICogYHR5cGVgOiB7ZnVuY3Rpb259IHR5cGUgdG8gd2hpY2ggYW4gYXR0cmlidXRlIG1hdGNoaW5nIHRoZSBwcm9wZXJ0eQogICAgICogaXMgZGVzZXJpYWxpemVkLiBOb3RlIHRoZSBwcm9wZXJ0eSBpcyBjYW1lbC1jYXNlZCBmcm9tIGEgZGFzaC1jYXNlZAogICAgICogYXR0cmlidXRlLiBGb3IgZXhhbXBsZSwgJ2Zvby1iYXInIGF0dHJpYnV0ZSBpcyBkZXNlcmlhbGl6ZWQgdG8gYQogICAgICogcHJvcGVydHkgbmFtZWQgJ2Zvb0JhcicuCiAgICAgKgogICAgICogKiBgcmVhZE9ubHlgOiB7Ym9vbGVhbn0gY3JlYXRlcyBhIHJlYWRPbmx5IHByb3BlcnR5IGFuZAogICAgICogbWFrZXMgYSBwcml2YXRlIHNldHRlciBmb3IgdGhlIHByaXZhdGUgb2YgdGhlIGZvcm0gJ19zZXRGb28nIGZvciBhCiAgICAgKiBwcm9wZXJ0eSAnZm9vJywKICAgICAqCiAgICAgKiAqIGBjb21wdXRlZGA6IHtzdHJpbmd9IGNyZWF0ZXMgYSBjb21wdXRlZCBwcm9wZXJ0eS4gQSBjb21wdXRlZCBwcm9wZXJ0eQogICAgICogaXMgYWxzbyBhdXRvbWF0aWNhbGx5IHNldCB0byBgcmVhZE9ubHk6IHRydWVgLiBUaGUgdmFsdWUgaXMgY2FsY3VsYXRlZAogICAgICogYnkgcnVubmluZyBhIG1ldGhvZCBhbmQgYXJndW1lbnRzIHBhcnNlZCBmcm9tIHRoZSBnaXZlbiBzdHJpbmcuIEZvcgogICAgICogZXhhbXBsZSAnY29tcHV0ZShmb28pJyB3aWxsIGNvbXB1dGUgYSBnaXZlbiBwcm9wZXJ0eSB3aGVuIHRoZQogICAgICogJ2ZvbycgcHJvcGVydHkgY2hhbmdlcyBieSBleGVjdXRpbmcgdGhlICdjb21wdXRlJyBtZXRob2QuIFRoaXMgbWV0aG9kCiAgICAgKiBtdXN0IHJldHVybiB0aGUgY29tcHV0ZWQgdmFsdWUuCiAgICAgKgogICAgICogKiBgcmVmbGVjdFRvQXR0cmlidXRlYDoge2Jvb2xlYW59IElmIHRydWUsIHRoZSBwcm9wZXJ0eSB2YWx1ZSBpcyByZWZsZWN0ZWQKICAgICAqIHRvIGFuIGF0dHJpYnV0ZSBvZiB0aGUgc2FtZSBuYW1lLiBOb3RlLCB0aGUgYXR0cmlidXRlIGlzIGRhc2gtY2FzZWQKICAgICAqIHNvIGEgcHJvcGVydHkgbmFtZWQgJ2Zvb0JhcicgaXMgcmVmbGVjdGVkIGFzICdmb28tYmFyJy4KICAgICAqCiAgICAgKiAqIGBub3RpZnlgOiB7Ym9vbGVhbn0gc2VuZHMgYSBub24tYnViYmxpbmcgbm90aWZpY2F0aW9uIGV2ZW50IHdoZW4KICAgICAqIHRoZSBwcm9wZXJ0eSBjaGFuZ2VzLiBGb3IgZXhhbXBsZSwgYSBwcm9wZXJ0eSBuYW1lZCAnZm9vJyBzZW5kcyBhbgogICAgICogZXZlbnQgbmFtZWQgJ2Zvby1jaGFuZ2VkJyB3aXRoIGBldmVudC5kZXRhaWxgIHNldCB0byB0aGUgdmFsdWUgb2YKICAgICAqIHRoZSBwcm9wZXJ0eS4KICAgICAqCiAgICAgKiAqIG9ic2VydmVyOiB7c3RyaW5nfSBuYW1lIG9mIGEgbWV0aG9kIHRoYXQgcnVucyB3aGVuIHRoZSBwcm9wZXJ0eQogICAgICogY2hhbmdlcy4gVGhlIGFyZ3VtZW50cyBvZiB0aGUgbWV0aG9kIGFyZSAodmFsdWUsIHByZXZpb3VzVmFsdWUpLgogICAgICoKICAgICAqIE5vdGU6IFVzZXJzIG1heSB3YW50IGNvbnRyb2wgb3ZlciBtb2RpZnlpbmcgcHJvcGVydHkKICAgICAqIGVmZmVjdHMgdmlhIHN1YmNsYXNzaW5nLiBGb3IgZXhhbXBsZSwgYSB1c2VyIG1pZ2h0IHdhbnQgdG8gbWFrZSBhCiAgICAgKiByZWZsZWN0VG9BdHRyaWJ1dGUgcHJvcGVydHkgbm90IGRvIHNvIGluIGEgc3ViY2xhc3MuIFdlJ3ZlIGNob3NlbiB0bwogICAgICogZGlzYWJsZSB0aGlzIGJlY2F1c2UgaXQgbGVhZHMgdG8gYWRkaXRpb25hbCBjb21wbGljYXRpb24uCiAgICAgKiBGb3IgZXhhbXBsZSwgYSByZWFkT25seSBlZmZlY3QgZ2VuZXJhdGVzIGEgc3BlY2lhbCBzZXR0ZXIuIElmIGEgc3ViY2xhc3MKICAgICAqIGRpc2FibGVzIHRoZSBlZmZlY3QsIHRoZSBzZXR0ZXIgd291bGQgZmFpbCB1bmV4cGVjdGVkbHkuCiAgICAgKiBCYXNlZCBvbiBmZWVkYmFjaywgd2UgbWF5IHdhbnQgdG8gdHJ5IHRvIG1ha2UgZWZmZWN0cyBtb3JlIG1hbGxlYWJsZQogICAgICogYW5kL29yIHByb3ZpZGUgYW4gYWR2YW5jZWQgYXBpIGZvciBtYW5pcHVsYXRpbmcgdGhlbS4KICAgICAqIEFsc28gY29uc2lkZXIgYWRkaW5nIHdhcm5pbmdzIHdoZW4gYW4gZWZmZWN0IGNhbm5vdCBiZSBjaGFuZ2VkLgogICAgICoKICAgICAqIEBwYXJhbSB7IVBvbHltZXJFbGVtZW50fSBwcm90byBFbGVtZW50IGNsYXNzIHByb3RvdHlwZSB0byBhZGQgYWNjZXNzb3JzCiAgICAgKiAgIGFuZCBlZmZlY3RzIHRvCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBOYW1lIG9mIHRoZSBwcm9wZXJ0eS4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSBpbmZvIEluZm8gb2JqZWN0IGZyb20gd2hpY2ggdG8gY3JlYXRlIHByb3BlcnR5IGVmZmVjdHMuCiAgICAgKiBTdXBwb3J0ZWQga2V5czoKICAgICAqIEBwYXJhbSB7T2JqZWN0fSBhbGxQcm9wcyBGbGF0dGVuZWQgbWFwIG9mIGFsbCBwcm9wZXJ0aWVzIGRlZmluZWQgaW4gdGhpcwogICAgICogICBlbGVtZW50IChpbmNsdWRpbmcgaW5oZXJpdGVkIHByb3BlcnRpZXMpCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICogQHByaXZhdGUKICAgICAqLwogICAgZnVuY3Rpb24gY3JlYXRlUHJvcGVydHlGcm9tQ29uZmlnKHByb3RvLCBuYW1lLCBpbmZvLCBhbGxQcm9wcykgewogICAgICAvLyBjb21wdXRlZCBmb3JjZXMgcmVhZE9ubHkuLi4KICAgICAgaWYgKGluZm8uY29tcHV0ZWQpIHsKICAgICAgICBpbmZvLnJlYWRPbmx5ID0gdHJ1ZTsKICAgICAgfQogICAgICAvLyBOb3RlLCBzaW5jZSBhbGwgY29tcHV0ZWQgcHJvcGVydGllcyBhcmUgcmVhZE9ubHksIHRoaXMgcHJldmVudHMKICAgICAgLy8gYWRkaW5nIGFkZGl0aW9uYWwgY29tcHV0ZWQgcHJvcGVydHkgZWZmZWN0cyAod2hpY2ggbGVhZHMgdG8gYSBjb25mdXNpbmcKICAgICAgLy8gc2V0dXAgd2hlcmUgbXVsdGlwbGUgdHJpZ2dlcnMgZm9yIHNldHRpbmcgYSBwcm9wZXJ0eSkKICAgICAgLy8gV2hpbGUgd2UgZG8gaGF2ZSBgaGFzQ29tcHV0ZWRFZmZlY3RgIHRoaXMgaXMgc2V0IG9uIHRoZSBwcm9wZXJ0eSdzCiAgICAgIC8vIGRlcGVuZGVuY2llcyByYXRoZXIgdGhhbiBpdHNlbGYuCiAgICAgIGlmIChpbmZvLmNvbXB1dGVkICYmICFwcm90by5faGFzUmVhZE9ubHlFZmZlY3QobmFtZSkpIHsKICAgICAgICBwcm90by5fY3JlYXRlQ29tcHV0ZWRQcm9wZXJ0eShuYW1lLCBpbmZvLmNvbXB1dGVkLCBhbGxQcm9wcyk7CiAgICAgIH0KICAgICAgaWYgKGluZm8ucmVhZE9ubHkgJiYgIXByb3RvLl9oYXNSZWFkT25seUVmZmVjdChuYW1lKSkgewogICAgICAgIHByb3RvLl9jcmVhdGVSZWFkT25seVByb3BlcnR5KG5hbWUsICFpbmZvLmNvbXB1dGVkKTsKICAgICAgfQogICAgICBpZiAoaW5mby5yZWZsZWN0VG9BdHRyaWJ1dGUgJiYgIXByb3RvLl9oYXNSZWZsZWN0RWZmZWN0KG5hbWUpKSB7CiAgICAgICAgcHJvdG8uX2NyZWF0ZVJlZmxlY3RlZFByb3BlcnR5KG5hbWUpOwogICAgICB9CiAgICAgIGlmIChpbmZvLm5vdGlmeSAmJiAhcHJvdG8uX2hhc05vdGlmeUVmZmVjdChuYW1lKSkgewogICAgICAgIHByb3RvLl9jcmVhdGVOb3RpZnlpbmdQcm9wZXJ0eShuYW1lKTsKICAgICAgfQogICAgICAvLyBhbHdheXMgYWRkIG9ic2VydmVyCiAgICAgIGlmIChpbmZvLm9ic2VydmVyKSB7CiAgICAgICAgcHJvdG8uX2NyZWF0ZVByb3BlcnR5T2JzZXJ2ZXIobmFtZSwgaW5mby5vYnNlcnZlciwgYWxsUHJvcHNbaW5mby5vYnNlcnZlcl0pOwogICAgICB9CiAgICAgIC8vIGFsd2F5cyBjcmVhdGUgdGhlIG1hcHBpbmcgZnJvbSBhdHRyaWJ1dGUgYmFjayB0byBwcm9wZXJ0eSBmb3IgZGVzZXJpYWxpemF0aW9uLgogICAgICBwcm90by5fYWRkUHJvcGVydHlUb0F0dHJpYnV0ZU1hcChuYW1lKTsKICAgIH0KCiAgICAvKioKICAgICAqIFByb2Nlc3MgYWxsIHN0eWxlIGVsZW1lbnRzIGluIHRoZSBlbGVtZW50IHRlbXBsYXRlLiBTdHlsZXMgd2l0aCB0aGUKICAgICAqIGBpbmNsdWRlYCBhdHRyaWJ1dGUgYXJlIHByb2Nlc3NlZCBzdWNoIHRoYXQgYW55IHN0eWxlcyBpbgogICAgICogdGhlIGFzc29jaWF0ZWQgInN0eWxlIG1vZHVsZXMiIGFyZSBpbmNsdWRlZCBpbiB0aGUgZWxlbWVudCB0ZW1wbGF0ZS4KICAgICAqIEBwYXJhbSB7UG9seW1lckVsZW1lbnRDb25zdHJ1Y3Rvcn0ga2xhc3MgRWxlbWVudCBjbGFzcwogICAgICogQHBhcmFtIHshSFRNTFRlbXBsYXRlRWxlbWVudH0gdGVtcGxhdGUgVGVtcGxhdGUgdG8gcHJvY2VzcwogICAgICogQHBhcmFtIHtzdHJpbmd9IGlzIE5hbWUgb2YgZWxlbWVudAogICAgICogQHBhcmFtIHtzdHJpbmd9IGJhc2VVUkkgQmFzZSBVUkkgZm9yIGVsZW1lbnQKICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIGZ1bmN0aW9uIHByb2Nlc3NFbGVtZW50U3R5bGVzKGtsYXNzLCB0ZW1wbGF0ZSwgaXMsIGJhc2VVUkkpIHsKICAgICAgaWYgKCFidWlsdENTUykgewogICAgICAgIGNvbnN0IHRlbXBsYXRlU3R5bGVzID0gdGVtcGxhdGUuY29udGVudC5xdWVyeVNlbGVjdG9yQWxsKCdzdHlsZScpOwogICAgICAgIGNvbnN0IHN0eWxlc1dpdGhJbXBvcnRzID0gUG9seW1lci5TdHlsZUdhdGhlci5zdHlsZXNGcm9tVGVtcGxhdGUodGVtcGxhdGUpOwogICAgICAgIC8vIGluc2VydCBzdHlsZXMgZnJvbSA8bGluayByZWw9ImltcG9ydCIgdHlwZT0iY3NzIj4gYXQgdGhlIHRvcCBvZiB0aGUgdGVtcGxhdGUKICAgICAgICBjb25zdCBsaW5rZWRTdHlsZXMgPSBQb2x5bWVyLlN0eWxlR2F0aGVyLnN0eWxlc0Zyb21Nb2R1bGVJbXBvcnRzKGlzKTsKICAgICAgICBjb25zdCBmaXJzdFRlbXBsYXRlQ2hpbGQgPSB0ZW1wbGF0ZS5jb250ZW50LmZpcnN0RWxlbWVudENoaWxkOwogICAgICAgIGZvciAobGV0IGlkeCA9IDA7IGlkeCA8IGxpbmtlZFN0eWxlcy5sZW5ndGg7IGlkeCsrKSB7CiAgICAgICAgICBsZXQgcyA9IGxpbmtlZFN0eWxlc1tpZHhdOwogICAgICAgICAgcy50ZXh0Q29udGVudCA9IGtsYXNzLl9wcm9jZXNzU3R5bGVUZXh0KHMudGV4dENvbnRlbnQsIGJhc2VVUkkpOwogICAgICAgICAgdGVtcGxhdGUuY29udGVudC5pbnNlcnRCZWZvcmUocywgZmlyc3RUZW1wbGF0ZUNoaWxkKTsKICAgICAgICB9CiAgICAgICAgLy8ga2VlcCB0cmFjayBvZiB0aGUgbGFzdCAiY29uY3JldGUiIHN0eWxlIGluIHRoZSB0ZW1wbGF0ZSB3ZSBoYXZlIGVuY291bnRlcmVkCiAgICAgICAgbGV0IHRlbXBsYXRlU3R5bGVJbmRleCA9IDA7CiAgICAgICAgLy8gZW5zdXJlIGFsbCBnYXRoZXJlZCBzdHlsZXMgYXJlIGFjdHVhbGx5IGluIHRoaXMgdGVtcGxhdGUuCiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzdHlsZXNXaXRoSW1wb3J0cy5sZW5ndGg7IGkrKykgewogICAgICAgICAgbGV0IHMgPSBzdHlsZXNXaXRoSW1wb3J0c1tpXTsKICAgICAgICAgIGxldCB0ZW1wbGF0ZVN0eWxlID0gdGVtcGxhdGVTdHlsZXNbdGVtcGxhdGVTdHlsZUluZGV4XTsKICAgICAgICAgIC8vIGlmIHRoZSBzdHlsZSBpcyBub3QgaW4gdGhpcyB0ZW1wbGF0ZSwgaXQncyBiZWVuICJpbmNsdWRlZCIgYW5kCiAgICAgICAgICAvLyB3ZSBwdXQgYSBjbG9uZSBvZiBpdCBpbiB0aGUgdGVtcGxhdGUgYmVmb3JlIHRoZSBzdHlsZSB0aGF0IGluY2x1ZGVkIGl0CiAgICAgICAgICBpZiAodGVtcGxhdGVTdHlsZSAhPT0gcykgewogICAgICAgICAgICBzID0gcy5jbG9uZU5vZGUodHJ1ZSk7CiAgICAgICAgICAgIHRlbXBsYXRlU3R5bGUucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUocywgdGVtcGxhdGVTdHlsZSk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0ZW1wbGF0ZVN0eWxlSW5kZXgrKzsKICAgICAgICAgIH0KICAgICAgICAgIHMudGV4dENvbnRlbnQgPSBrbGFzcy5fcHJvY2Vzc1N0eWxlVGV4dChzLnRleHRDb250ZW50LCBiYXNlVVJJKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKHdpbmRvdy5TaGFkeUNTUykgewogICAgICAgIHdpbmRvdy5TaGFkeUNTUy5wcmVwYXJlVGVtcGxhdGUodGVtcGxhdGUsIGlzKTsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogTG9vayB1cCB0ZW1wbGF0ZSBmcm9tIGRvbS1tb2R1bGUgZm9yIGVsZW1lbnQKICAgICAqCiAgICAgKiBAcGFyYW0geyFzdHJpbmd9IGlzIEVsZW1lbnQgbmFtZSB0byBsb29rIHVwCiAgICAgKiBAcmV0dXJuIHshSFRNTFRlbXBsYXRlRWxlbWVudH0gVGVtcGxhdGUgZm91bmQgaW4gZG9tIG1vZHVsZSwgb3IKICAgICAqICAgdW5kZWZpbmVkIGlmIG5vdCBmb3VuZAogICAgICogQHByb3RlY3RlZAogICAgICovCiAgICBmdW5jdGlvbiBnZXRUZW1wbGF0ZUZyb21Eb21Nb2R1bGUoaXMpIHsKICAgICAgbGV0IHRlbXBsYXRlID0gbnVsbDsKICAgICAgaWYgKGlzICYmIFBvbHltZXIuRG9tTW9kdWxlKSB7CiAgICAgICAgdGVtcGxhdGUgPSBQb2x5bWVyLkRvbU1vZHVsZS5pbXBvcnQoaXMsICd0ZW1wbGF0ZScpOwogICAgICAgIC8vIFVuZGVyIHN0cmljdFRlbXBsYXRlUG9saWN5LCByZXF1aXJlIGFueSBlbGVtZW50IHdpdGggYW4gYGlzYAogICAgICAgIC8vIHNwZWNpZmllZCB0byBoYXZlIGEgZG9tLW1vZHVsZQogICAgICAgIGlmIChQb2x5bWVyLnN0cmljdFRlbXBsYXRlUG9saWN5ICYmICF0ZW1wbGF0ZSkgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBzdHJpY3RUZW1wbGF0ZVBvbGljeTogZXhwZWN0aW5nIGRvbS1tb2R1bGUgb3IgbnVsbCB0ZW1wbGF0ZSBmb3IgJHtpc31gKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIHRlbXBsYXRlOwogICAgfQoKICAvKioKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAbWl4aW5DbGFzcwogICAgICogQHVucmVzdHJpY3RlZAogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfRWxlbWVudE1peGlufQogICAgICovCiAgICBjbGFzcyBQb2x5bWVyRWxlbWVudCBleHRlbmRzIHBvbHltZXJFbGVtZW50QmFzZSB7CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGUgb2YgUHJvcGVydGllc01peGluIF9maW5hbGl6ZUNsYXNzIHRvIGNyZWF0ZSBvYnNlcnZlcnMgYW5kCiAgICAgICAqIGZpbmQgdGhlIHRlbXBsYXRlLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqIEBvdmVycmlkZQogICAgICAgKiBAc3VwcHJlc3Mge21pc3NpbmdQcm9wZXJ0aWVzfSBJbnRlcmZhY2VzIGluIGNsb3N1cmUgZG8gbm90IGluaGVyaXQgc3RhdGljcywgYnV0IGNsYXNzZXMgZG8KICAgICAgICovCiAgICAgIHN0YXRpYyBfZmluYWxpemVDbGFzcygpIHsKICAgICAgICBzdXBlci5fZmluYWxpemVDbGFzcygpOwogICAgICAgIGNvbnN0IG9ic2VydmVycyA9IG93bk9ic2VydmVycyh0aGlzKTsKICAgICAgICBpZiAob2JzZXJ2ZXJzKSB7CiAgICAgICAgICB0aGlzLmNyZWF0ZU9ic2VydmVycyhvYnNlcnZlcnMsIHRoaXMuX3Byb3BlcnRpZXMpOwogICAgICAgIH0KICAgICAgICB0aGlzLl9wcmVwYXJlVGVtcGxhdGUoKTsKICAgICAgfQoKICAgICAgc3RhdGljIF9wcmVwYXJlVGVtcGxhdGUoKSB7CiAgICAgICAgLy8gbm90ZTogY3JlYXRlICJ3b3JraW5nIiB0ZW1wbGF0ZSB0aGF0IGlzIGZpbmFsaXplZCBhdCBpbnN0YW5jZSB0aW1lCiAgICAgICAgbGV0IHRlbXBsYXRlID0gLyoqIEB0eXBlIHtQb2x5bWVyRWxlbWVudENvbnN0cnVjdG9yfSAqLyAodGhpcykudGVtcGxhdGU7CiAgICAgICAgaWYgKHRlbXBsYXRlKSB7CiAgICAgICAgICBpZiAodHlwZW9mIHRlbXBsYXRlID09PSAnc3RyaW5nJykgewogICAgICAgICAgICBsZXQgdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RlbXBsYXRlJyk7CiAgICAgICAgICAgIHQuaW5uZXJIVE1MID0gdGVtcGxhdGU7CiAgICAgICAgICAgIHRlbXBsYXRlID0gdDsKICAgICAgICAgIH0gZWxzZSBpZiAoIVBvbHltZXIubGVnYWN5T3B0aW1pemF0aW9ucykgewogICAgICAgICAgICAgdGVtcGxhdGUgPSB0ZW1wbGF0ZS5jbG9uZU5vZGUodHJ1ZSk7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICB0aGlzLnByb3RvdHlwZS5fdGVtcGxhdGUgPSB0ZW1wbGF0ZTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIE92ZXJyaWRlIG9mIFByb3BlcnRpZXNDaGFuZ2VkIGNyZWF0ZVByb3BlcnRpZXMgdG8gY3JlYXRlIGFjY2Vzc29ycwogICAgICAgKiBhbmQgcHJvcGVydHkgZWZmZWN0cyBmb3IgYWxsIG9mIHRoZSBwcm9wZXJ0aWVzLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqIEBvdmVycmlkZQogICAgICAgKi8KICAgICAgc3RhdGljIGNyZWF0ZVByb3BlcnRpZXMocHJvcHMpIHsKICAgICAgICBmb3IgKGxldCBwIGluIHByb3BzKSB7CiAgICAgICAgICBjcmVhdGVQcm9wZXJ0eUZyb21Db25maWcodGhpcy5wcm90b3R5cGUsIHAsIHByb3BzW3BdLCBwcm9wcyk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogQ3JlYXRlcyBvYnNlcnZlcnMgZm9yIHRoZSBnaXZlbiBgb2JzZXJ2ZXJzYCBhcnJheS4KICAgICAgICogTGV2ZXJhZ2VzIGBQcm9wZXJ0eUVmZmVjdHNgIHRvIGNyZWF0ZSBvYnNlcnZlcnMuCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYnNlcnZlcnMgQXJyYXkgb2Ygb2JzZXJ2ZXIgZGVzY3JpcHRvcnMgZm9yCiAgICAgICAqICAgdGhpcyBjbGFzcwogICAgICAgKiBAcGFyYW0ge09iamVjdH0gZHluYW1pY0ZucyBPYmplY3QgY29udGFpbmluZyBrZXlzIGZvciBhbnkgcHJvcGVydGllcwogICAgICAgKiAgIHRoYXQgYXJlIGZ1bmN0aW9ucyBhbmQgc2hvdWxkIHRyaWdnZXIgdGhlIGVmZmVjdCB3aGVuIHRoZSBmdW5jdGlvbgogICAgICAgKiAgIHJlZmVyZW5jZSBpcyBjaGFuZ2VkCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIHN0YXRpYyBjcmVhdGVPYnNlcnZlcnMob2JzZXJ2ZXJzLCBkeW5hbWljRm5zKSB7CiAgICAgICAgY29uc3QgcHJvdG8gPSB0aGlzLnByb3RvdHlwZTsKICAgICAgICBmb3IgKGxldCBpPTA7IGkgPCBvYnNlcnZlcnMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgIHByb3RvLl9jcmVhdGVNZXRob2RPYnNlcnZlcihvYnNlcnZlcnNbaV0sIGR5bmFtaWNGbnMpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgdGhlIHRlbXBsYXRlIHRoYXQgd2lsbCBiZSBzdGFtcGVkIGludG8gdGhpcyBlbGVtZW50J3Mgc2hhZG93IHJvb3QuCiAgICAgICAqCiAgICAgICAqIElmIGEgYHN0YXRpYyBnZXQgaXMoKWAgZ2V0dGVyIGlzIGRlZmluZWQsIHRoZSBkZWZhdWx0IGltcGxlbWVudGF0aW9uCiAgICAgICAqIHdpbGwgcmV0dXJuIHRoZSBmaXJzdCBgPHRlbXBsYXRlPmAgaW4gYSBgZG9tLW1vZHVsZWAgd2hvc2UgYGlkYAogICAgICAgKiBtYXRjaGVzIHRoaXMgZWxlbWVudCdzIGBpc2AuCiAgICAgICAqCiAgICAgICAqIFVzZXJzIG1heSBvdmVycmlkZSB0aGlzIGdldHRlciB0byByZXR1cm4gYW4gYXJiaXRyYXJ5IHRlbXBsYXRlCiAgICAgICAqIChpbiB3aGljaCBjYXNlIHRoZSBgaXNgIGdldHRlciBpcyB1bm5lY2Vzc2FyeSkuIFRoZSB0ZW1wbGF0ZSByZXR1cm5lZAogICAgICAgKiBtYXkgYmUgZWl0aGVyIGFuIGBIVE1MVGVtcGxhdGVFbGVtZW50YCBvciBhIHN0cmluZyB0aGF0IHdpbGwgYmUKICAgICAgICogYXV0b21hdGljYWxseSBwYXJzZWQgaW50byBhIHRlbXBsYXRlLgogICAgICAgKgogICAgICAgKiBOb3RlIHRoYXQgd2hlbiBzdWJjbGFzc2luZywgaWYgdGhlIHN1cGVyIGNsYXNzIG92ZXJyb2RlIHRoZSBkZWZhdWx0CiAgICAgICAqIGltcGxlbWVudGF0aW9uIGFuZCB0aGUgc3ViY2xhc3Mgd291bGQgbGlrZSB0byBwcm92aWRlIGFuIGFsdGVybmF0ZQogICAgICAgKiB0ZW1wbGF0ZSB2aWEgYSBgZG9tLW1vZHVsZWAsIGl0IHNob3VsZCBvdmVycmlkZSB0aGlzIGdldHRlciBhbmQKICAgICAgICogcmV0dXJuIGBQb2x5bWVyLkRvbU1vZHVsZS5pbXBvcnQodGhpcy5pcywgJ3RlbXBsYXRlJylgLgogICAgICAgKgogICAgICAgKiBJZiBhIHN1YmNsYXNzIHdvdWxkIGxpa2UgdG8gbW9kaWZ5IHRoZSBzdXBlciBjbGFzcyB0ZW1wbGF0ZSwgaXQgc2hvdWxkCiAgICAgICAqIGNsb25lIGl0IHJhdGhlciB0aGFuIG1vZGlmeSBpdCBpbiBwbGFjZS4gIElmIHRoZSBnZXR0ZXIgZG9lcyBleHBlbnNpdmUKICAgICAgICogd29yayBzdWNoIGFzIGNsb25pbmcvbW9kaWZ5aW5nIGEgdGVtcGxhdGUsIGl0IHNob3VsZCBtZW1vaXplIHRoZQogICAgICAgKiB0ZW1wbGF0ZSBmb3IgbWF4aW11bSBwZXJmb3JtYW5jZToKICAgICAgICoKICAgICAgICogICBsZXQgbWVtb2l6ZWRUZW1wbGF0ZTsKICAgICAgICogICBjbGFzcyBNeVN1YkNsYXNzIGV4dGVuZHMgTXlTdXBlckNsYXNzIHsKICAgICAgICogICAgIHN0YXRpYyBnZXQgdGVtcGxhdGUoKSB7CiAgICAgICAqICAgICAgIGlmICghbWVtb2l6ZWRUZW1wbGF0ZSkgewogICAgICAgKiAgICAgICAgIG1lbW9pemVkVGVtcGxhdGUgPSBNeVN1cGVyQ2xhc3MudGVtcGxhdGUuY2xvbmVOb2RlKHRydWUpOwogICAgICAgKiAgICAgICAgIGxldCBzdWJDb250ZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7CiAgICAgICAqICAgICAgICAgc3ViQ29udGVudC50ZXh0Q29udGVudCA9ICdUaGlzIGNhbWUgZnJvbSBNeVN1YkNsYXNzJzsKICAgICAgICogICAgICAgICBtZW1vaXplZFRlbXBsYXRlLmNvbnRlbnQuYXBwZW5kQ2hpbGQoc3ViQ29udGVudCk7CiAgICAgICAqICAgICAgIH0KICAgICAgICogICAgICAgcmV0dXJuIG1lbW9pemVkVGVtcGxhdGU7CiAgICAgICAqICAgICB9CiAgICAgICAqICAgfQogICAgICAgKgogICAgICAgKiBAcmV0dXJuIHtIVE1MVGVtcGxhdGVFbGVtZW50fHN0cmluZ30gVGVtcGxhdGUgdG8gYmUgc3RhbXBlZAogICAgICAgKi8KICAgICAgc3RhdGljIGdldCB0ZW1wbGF0ZSgpIHsKICAgICAgICAvLyBFeHBsYW5hdGlvbiBvZiB0ZW1wbGF0ZS1yZWxhdGVkIHByb3BlcnRpZXM6CiAgICAgICAgLy8gLSBjb25zdHJ1Y3Rvci50ZW1wbGF0ZSAodGhpcyBnZXR0ZXIpOiB0aGUgdGVtcGxhdGUgZm9yIHRoZSBjbGFzcy4KICAgICAgICAvLyAgICAgVGhpcyBjYW4gY29tZSBmcm9tIHRoZSBwcm90b3R5cGUgKGZvciBsZWdhY3kgZWxlbWVudHMpLCBmcm9tIGEKICAgICAgICAvLyAgICAgZG9tLW1vZHVsZSwgb3IgZnJvbSB0aGUgc3VwZXIgY2xhc3MncyB0ZW1wbGF0ZSAob3IgY2FuIGJlIG92ZXJyaWRkZW4KICAgICAgICAvLyAgICAgYWx0b2dldGhlciBieSB0aGUgdXNlcikKICAgICAgICAvLyAtIGNvbnN0cnVjdG9yLl90ZW1wbGF0ZTogbWVtb2l6ZWQgdmVyc2lvbiBvZiBjb25zdHJ1Y3Rvci50ZW1wbGF0ZQogICAgICAgIC8vIC0gcHJvdG90eXBlLl90ZW1wbGF0ZTogd29ya2luZyB0ZW1wbGF0ZSBmb3IgdGhlIGVsZW1lbnQsIHdoaWNoIHdpbGwgYmUKICAgICAgICAvLyAgICAgcGFyc2VkIGFuZCBtb2RpZmllZCBpbiBwbGFjZS4gSXQgaXMgYSBjbG9uZWQgdmVyc2lvbiBvZgogICAgICAgIC8vICAgICBjb25zdHJ1Y3Rvci50ZW1wbGF0ZSwgc2F2ZWQgaW4gX2ZpbmFsaXplQ2xhc3MoKS4gTm90ZSB0aGF0IGJlZm9yZQogICAgICAgIC8vICAgICB0aGlzIGdldHRlciBpcyBjYWxsZWQsIGZvciBsZWdhY3kgZWxlbWVudHMgdGhpcyBjb3VsZCBiZSBmcm9tIGEKICAgICAgICAvLyAgICAgX3RlbXBsYXRlIGZpZWxkIG9uIHRoZSBpbmZvIG9iamVjdCBwYXNzZWQgdG8gUG9seW1lcigpLCBhIGJlaGF2aW9yLAogICAgICAgIC8vICAgICBvciBzZXQgaW4gcmVnaXN0ZXJlZCgpOyBvbmNlIHRoZSBzdGF0aWMgZ2V0dGVyIHJ1bnMsIGEgY2xvbmUgb2YgaXQKICAgICAgICAvLyAgICAgd2lsbCBvdmVyd3JpdGUgaXQgb24gdGhlIHByb3RvdHlwZSBhcyB0aGUgd29ya2luZyB0ZW1wbGF0ZS4KICAgICAgICBpZiAoIXRoaXMuaGFzT3duUHJvcGVydHkoSlNDb21waWxlcl9yZW5hbWVQcm9wZXJ0eSgnX3RlbXBsYXRlJywgdGhpcykpKSB7CiAgICAgICAgICB0aGlzLl90ZW1wbGF0ZSA9CiAgICAgICAgICAgIC8vIElmIHVzZXIgaGFzIHB1dCB0ZW1wbGF0ZSBvbiBwcm90b3R5cGUgKGUuZy4gaW4gbGVnYWN5IHZpYSByZWdpc3RlcmVkCiAgICAgICAgICAgIC8vIGNhbGxiYWNrIG9yIGluZm8gb2JqZWN0KSwgcHJlZmVyIHRoYXQgZmlyc3QKICAgICAgICAgICAgdGhpcy5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkoSlNDb21waWxlcl9yZW5hbWVQcm9wZXJ0eSgnX3RlbXBsYXRlJywgdGhpcy5wcm90b3R5cGUpKSA/CiAgICAgICAgICAgIHRoaXMucHJvdG90eXBlLl90ZW1wbGF0ZSA6CiAgICAgICAgICAgIC8vIExvb2sgaW4gZG9tLW1vZHVsZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBlbGVtZW50J3MgaXMKICAgICAgICAgICAgKGdldFRlbXBsYXRlRnJvbURvbU1vZHVsZSgvKiogQHR5cGUge1BvbHltZXJFbGVtZW50Q29uc3RydWN0b3J9Ki8gKHRoaXMpLmlzKSB8fAogICAgICAgICAgICAvLyBOZXh0IGxvb2sgZm9yIHN1cGVyY2xhc3MgdGVtcGxhdGUgKGNhbGwgdGhlIHN1cGVyIGltcGwgdGhpcwogICAgICAgICAgICAvLyB3YXkgc28gdGhhdCBgdGhpc2AgcG9pbnRzIHRvIHRoZSBzdXBlcmNsYXNzKQogICAgICAgICAgICBPYmplY3QuZ2V0UHJvdG90eXBlT2YoLyoqIEB0eXBlIHtQb2x5bWVyRWxlbWVudENvbnN0cnVjdG9yfSovICh0aGlzKS5wcm90b3R5cGUpLmNvbnN0cnVjdG9yLnRlbXBsYXRlKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRoaXMuX3RlbXBsYXRlOwogICAgICB9CgogICAgICAvKioKICAgICAgICogU2V0IHRoZSB0ZW1wbGF0ZS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHshSFRNTFRlbXBsYXRlRWxlbWVudHxzdHJpbmd9IHZhbHVlIFRlbXBsYXRlIHRvIHNldC4KICAgICAgICovCiAgICAgIHN0YXRpYyBzZXQgdGVtcGxhdGUodmFsdWUpIHsKICAgICAgICB0aGlzLl90ZW1wbGF0ZSA9IHZhbHVlOwogICAgICB9CgogICAgICAvKioKICAgICAgICogUGF0aCBtYXRjaGluZyB0aGUgdXJsIGZyb20gd2hpY2ggdGhlIGVsZW1lbnQgd2FzIGltcG9ydGVkLgogICAgICAgKgogICAgICAgKiBUaGlzIHBhdGggaXMgdXNlZCB0byByZXNvbHZlIHVybCdzIGluIHRlbXBsYXRlIHN0eWxlIGNzc1RleHQuCiAgICAgICAqIFRoZSBgaW1wb3J0UGF0aGAgcHJvcGVydHkgaXMgYWxzbyBzZXQgb24gZWxlbWVudCBpbnN0YW5jZXMgYW5kIGNhbiBiZQogICAgICAgKiB1c2VkIHRvIGNyZWF0ZSBiaW5kaW5ncyByZWxhdGl2ZSB0byB0aGUgaW1wb3J0IHBhdGguCiAgICAgICAqCiAgICAgICAqIEZvciBlbGVtZW50cyBkZWZpbmVkIGluIEVTIG1vZHVsZXMsIHVzZXJzIHNob3VsZCBpbXBsZW1lbnQKICAgICAgICogYHN0YXRpYyBnZXQgaW1wb3J0TWV0YSgpIHsgcmV0dXJuIGltcG9ydC5tZXRhOyB9YCwgYW5kIHRoZSBkZWZhdWx0CiAgICAgICAqIGltcGxlbWVudGF0aW9uIG9mIGBpbXBvcnRQYXRoYCB3aWxsICByZXR1cm4gYGltcG9ydC5tZXRhLnVybGAncyBwYXRoLgogICAgICAgKiBGb3IgZWxlbWVudHMgZGVmaW5lZCBpbiBIVE1MIGltcG9ydHMsIHRoaXMgZ2V0dGVyIHdpbGwgcmV0dXJuIHRoZSBwYXRoCiAgICAgICAqIHRvIHRoZSBkb2N1bWVudCBjb250YWluaW5nIGEgYGRvbS1tb2R1bGVgIGVsZW1lbnQgbWF0Y2hpbmcgdGhpcwogICAgICAgKiBlbGVtZW50J3Mgc3RhdGljIGBpc2AgcHJvcGVydHkuCiAgICAgICAqCiAgICAgICAqIE5vdGUsIHRoaXMgcGF0aCBzaG91bGQgY29udGFpbiBhIHRyYWlsaW5nIGAvYC4KICAgICAgICoKICAgICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgaW1wb3J0IHBhdGggZm9yIHRoaXMgZWxlbWVudCBjbGFzcwogICAgICAgKiBAc3VwcHJlc3Mge21pc3NpbmdQcm9wZXJ0aWVzfQogICAgICAgKi8KICAgICAgc3RhdGljIGdldCBpbXBvcnRQYXRoKCkgewogICAgICAgIGlmICghdGhpcy5oYXNPd25Qcm9wZXJ0eShKU0NvbXBpbGVyX3JlbmFtZVByb3BlcnR5KCdfaW1wb3J0UGF0aCcsIHRoaXMpKSkgewogICAgICAgICAgY29uc3QgbWV0YSA9IHRoaXMuaW1wb3J0TWV0YTsKICAgICAgICAgIGlmIChtZXRhKSB7CiAgICAgICAgICAgIHRoaXMuX2ltcG9ydFBhdGggPSBQb2x5bWVyLlJlc29sdmVVcmwucGF0aEZyb21VcmwobWV0YS51cmwpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgY29uc3QgbW9kdWxlID0gUG9seW1lci5Eb21Nb2R1bGUgJiYgUG9seW1lci5Eb21Nb2R1bGUuaW1wb3J0KC8qKiBAdHlwZSB7UG9seW1lckVsZW1lbnRDb25zdHJ1Y3Rvcn0gKi8gKHRoaXMpLmlzKTsKICAgICAgICAgICAgdGhpcy5faW1wb3J0UGF0aCA9IChtb2R1bGUgJiYgbW9kdWxlLmFzc2V0cGF0aCkgfHwKICAgICAgICAgICAgICBPYmplY3QuZ2V0UHJvdG90eXBlT2YoLyoqIEB0eXBlIHtQb2x5bWVyRWxlbWVudENvbnN0cnVjdG9yfSovICh0aGlzKS5wcm90b3R5cGUpLmNvbnN0cnVjdG9yLmltcG9ydFBhdGg7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiB0aGlzLl9pbXBvcnRQYXRoOwogICAgICB9CgogICAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICBzdXBlcigpOwogICAgICAgIC8qKiBAdHlwZSB7SFRNTFRlbXBsYXRlRWxlbWVudH0gKi8KICAgICAgICB0aGlzLl90ZW1wbGF0ZTsKICAgICAgICAvKiogQHR5cGUge3N0cmluZ30gKi8KICAgICAgICB0aGlzLl9pbXBvcnRQYXRoOwogICAgICAgIC8qKiBAdHlwZSB7c3RyaW5nfSAqLwogICAgICAgIHRoaXMucm9vdFBhdGg7CiAgICAgICAgLyoqIEB0eXBlIHtzdHJpbmd9ICovCiAgICAgICAgdGhpcy5pbXBvcnRQYXRoOwogICAgICAgIC8qKiBAdHlwZSB7U3RhbXBlZFRlbXBsYXRlIHwgSFRNTEVsZW1lbnQgfCBTaGFkb3dSb290fSAqLwogICAgICAgIHRoaXMucm9vdDsKICAgICAgICAvKiogQHR5cGUgeyFPYmplY3Q8c3RyaW5nLCAhRWxlbWVudD59ICovCiAgICAgICAgdGhpcy4kOwogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGVzIHRoZSBkZWZhdWx0IGBQb2x5bWVyLlByb3BlcnR5QWNjZXNzb3JzYCB0byBlbnN1cmUgY2xhc3MKICAgICAgICogbWV0YXByb2dyYW1taW5nIHJlbGF0ZWQgdG8gcHJvcGVydHkgYWNjZXNzb3JzIGFuZCBlZmZlY3RzIGhhcwogICAgICAgKiBjb21wbGV0ZWQgKGNhbGxzIGBmaW5hbGl6ZWApLgogICAgICAgKgogICAgICAgKiBJdCBhbHNvIGluaXRpYWxpemVzIGFueSBwcm9wZXJ0eSBkZWZhdWx0cyBwcm92aWRlZCB2aWEgYHZhbHVlYCBpbgogICAgICAgKiBgcHJvcGVydGllc2AgbWV0YWRhdGEuCiAgICAgICAqCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBvdmVycmlkZQogICAgICAgKiBAc3VwcHJlc3Mge2ludmFsaWRDYXN0c30KICAgICAgICovCiAgICAgIF9pbml0aWFsaXplUHJvcGVydGllcygpIHsKICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLmZpbmFsaXplKCk7CiAgICAgICAgLy8gbm90ZTogZmluYWxpemUgdGVtcGxhdGUgd2hlbiB3ZSBoYXZlIGFjY2VzcyB0byBgbG9jYWxOYW1lYCB0bwogICAgICAgIC8vIGF2b2lkIGRlcGVuZGVuY2Ugb24gYGlzYCBmb3IgcG9seWZpbGxpbmcgc3R5bGluZy4KICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLl9maW5hbGl6ZVRlbXBsYXRlKC8qKiBAdHlwZSB7IUhUTUxFbGVtZW50fSAqLyh0aGlzKS5sb2NhbE5hbWUpOwogICAgICAgIHN1cGVyLl9pbml0aWFsaXplUHJvcGVydGllcygpOwogICAgICAgIC8vIHNldCBwYXRoIGRlZmF1bHRzCiAgICAgICAgdGhpcy5yb290UGF0aCA9IFBvbHltZXIucm9vdFBhdGg7CiAgICAgICAgdGhpcy5pbXBvcnRQYXRoID0gdGhpcy5jb25zdHJ1Y3Rvci5pbXBvcnRQYXRoOwogICAgICAgIC8vIGFwcGx5IHByb3BlcnR5IGRlZmF1bHRzLi4uCiAgICAgICAgbGV0IHAkID0gcHJvcGVydHlEZWZhdWx0cyh0aGlzLmNvbnN0cnVjdG9yKTsKICAgICAgICBpZiAoIXAkKSB7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGZvciAobGV0IHAgaW4gcCQpIHsKICAgICAgICAgIGxldCBpbmZvID0gcCRbcF07CiAgICAgICAgICAvLyBEb24ndCBzZXQgZGVmYXVsdCB2YWx1ZSBpZiB0aGVyZSBpcyBhbHJlYWR5IGFuIG93biBwcm9wZXJ0eSwgd2hpY2gKICAgICAgICAgIC8vIGhhcHBlbnMgd2hlbiBhIGBwcm9wZXJ0aWVzYCBwcm9wZXJ0eSB3aXRoIGRlZmF1bHQgYnV0IG5vIGVmZmVjdHMgaGFkCiAgICAgICAgICAvLyBhIHByb3BlcnR5IHNldCAoZS5nLiBib3VuZCkgYnkgaXRzIGhvc3QgYmVmb3JlIHVwZ3JhZGUKICAgICAgICAgIGlmICghdGhpcy5oYXNPd25Qcm9wZXJ0eShwKSkgewogICAgICAgICAgICBsZXQgdmFsdWUgPSB0eXBlb2YgaW5mby52YWx1ZSA9PSAnZnVuY3Rpb24nID8KICAgICAgICAgICAgICBpbmZvLnZhbHVlLmNhbGwodGhpcykgOgogICAgICAgICAgICAgIGluZm8udmFsdWU7CiAgICAgICAgICAgIC8vIFNldCB2aWEgYF9zZXRQcm9wZXJ0eWAgaWYgdGhlcmUgaXMgYW4gYWNjZXNzb3IsIHRvIGVuYWJsZQogICAgICAgICAgICAvLyBpbml0aWFsaXppbmcgcmVhZE9ubHkgcHJvcGVydHkgZGVmYXVsdHMKICAgICAgICAgICAgaWYgKHRoaXMuX2hhc0FjY2Vzc29yKHApKSB7CiAgICAgICAgICAgICAgdGhpcy5fc2V0UGVuZGluZ1Byb3BlcnR5KHAsIHZhbHVlLCB0cnVlKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICB0aGlzW3BdID0gdmFsdWU7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBHYXRoZXIgc3R5bGUgdGV4dCBmb3IgYSBzdHlsZSBlbGVtZW50IGluIHRoZSB0ZW1wbGF0ZS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGNzc1RleHQgVGV4dCBjb250YWluaW5nIHN0eWxpbmcgdG8gcHJvY2VzcwogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYmFzZVVSSSBCYXNlIFVSSSB0byByZWJhc2UgQ1NTIHBhdGhzIGFnYWluc3QKICAgICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgcHJvY2Vzc2VkIENTUyB0ZXh0CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIHN0YXRpYyBfcHJvY2Vzc1N0eWxlVGV4dChjc3NUZXh0LCBiYXNlVVJJKSB7CiAgICAgICAgcmV0dXJuIFBvbHltZXIuUmVzb2x2ZVVybC5yZXNvbHZlQ3NzKGNzc1RleHQsIGJhc2VVUkkpOwogICAgICB9CgogICAgICAvKioKICAgICAgKiBDb25maWd1cmVzIGFuIGVsZW1lbnQgYHByb3RvYCB0byBmdW5jdGlvbiB3aXRoIGEgZ2l2ZW4gYHRlbXBsYXRlYC4KICAgICAgKiBUaGUgZWxlbWVudCBuYW1lIGBpc2AgYW5kIGV4dGVuZHMgYGV4dGAgbXVzdCBiZSBzcGVjaWZpZWQgZm9yIFNoYWR5Q1NTCiAgICAgICogc3R5bGUgc2NvcGluZy4KICAgICAgKgogICAgICAqIEBwYXJhbSB7c3RyaW5nfSBpcyBUYWcgbmFtZSAob3IgdHlwZSBleHRlbnNpb24gbmFtZSkgZm9yIHRoaXMgZWxlbWVudAogICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICogQHByb3RlY3RlZAogICAgICAqLwogICAgICBzdGF0aWMgX2ZpbmFsaXplVGVtcGxhdGUoaXMpIHsKICAgICAgICAvKiogQGNvbnN0IHtIVE1MVGVtcGxhdGVFbGVtZW50fSAqLwogICAgICAgIGNvbnN0IHRlbXBsYXRlID0gdGhpcy5wcm90b3R5cGUuX3RlbXBsYXRlOwogICAgICAgIGlmICh0ZW1wbGF0ZSAmJiAhdGVtcGxhdGUuX19wb2x5bWVyRmluYWxpemVkKSB7CiAgICAgICAgICB0ZW1wbGF0ZS5fX3BvbHltZXJGaW5hbGl6ZWQgPSB0cnVlOwogICAgICAgICAgY29uc3QgaW1wb3J0UGF0aCA9IHRoaXMuaW1wb3J0UGF0aDsKICAgICAgICAgIGNvbnN0IGJhc2VVUkkgPSBpbXBvcnRQYXRoID8gUG9seW1lci5SZXNvbHZlVXJsLnJlc29sdmVVcmwoaW1wb3J0UGF0aCkgOiAnJzsKICAgICAgICAgIC8vIGUuZy4gc3VwcG9ydCBgaW5jbHVkZT0ibW9kdWxlLW5hbWUiYCwgYW5kIFNoYWR5Q1NTCiAgICAgICAgICBwcm9jZXNzRWxlbWVudFN0eWxlcyh0aGlzLCB0ZW1wbGF0ZSwgaXMsIGJhc2VVUkkpOwogICAgICAgICAgdGhpcy5wcm90b3R5cGUuX2JpbmRUZW1wbGF0ZSh0ZW1wbGF0ZSk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogUHJvdmlkZXMgYSBkZWZhdWx0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBzdGFuZGFyZCBDdXN0b20gRWxlbWVudHMKICAgICAgICogYGNvbm5lY3RlZENhbGxiYWNrYC4KICAgICAgICoKICAgICAgICogVGhlIGRlZmF1bHQgaW1wbGVtZW50YXRpb24gZW5hYmxlcyB0aGUgcHJvcGVydHkgZWZmZWN0cyBzeXN0ZW0gYW5kCiAgICAgICAqIGZsdXNoZXMgYW55IHBlbmRpbmcgcHJvcGVydGllcywgYW5kIHVwZGF0ZXMgc2hpbW1lZCBDU1MgcHJvcGVydGllcwogICAgICAgKiB3aGVuIHVzaW5nIHRoZSBTaGFkeUNTUyBzY29waW5nL2N1c3RvbSBwcm9wZXJ0aWVzIHBvbHlmaWxsLgogICAgICAgKgogICAgICAgKiBAc3VwcHJlc3Mge21pc3NpbmdQcm9wZXJ0aWVzLCBpbnZhbGlkQ2FzdHN9IFN1cGVyIG1heSBvciBtYXkgbm90IGltcGxlbWVudCB0aGUgY2FsbGJhY2sKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIGNvbm5lY3RlZENhbGxiYWNrKCkgewogICAgICAgIGlmICh3aW5kb3cuU2hhZHlDU1MgJiYgdGhpcy5fdGVtcGxhdGUpIHsKICAgICAgICAgIHdpbmRvdy5TaGFkeUNTUy5zdHlsZUVsZW1lbnQoLyoqIEB0eXBlIHshSFRNTEVsZW1lbnR9ICovKHRoaXMpKTsKICAgICAgICB9CiAgICAgICAgc3VwZXIuY29ubmVjdGVkQ2FsbGJhY2soKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFN0YW1wcyB0aGUgZWxlbWVudCB0ZW1wbGF0ZS4KICAgICAgICoKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQG92ZXJyaWRlCiAgICAgICAqLwogICAgICByZWFkeSgpIHsKICAgICAgICBpZiAodGhpcy5fdGVtcGxhdGUpIHsKICAgICAgICAgIHRoaXMucm9vdCA9IHRoaXMuX3N0YW1wVGVtcGxhdGUodGhpcy5fdGVtcGxhdGUpOwogICAgICAgICAgdGhpcy4kID0gdGhpcy5yb290LiQ7CiAgICAgICAgfQogICAgICAgIHN1cGVyLnJlYWR5KCk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBJbXBsZW1lbnRzIGBQcm9wZXJ0eUVmZmVjdHNgJ3MgYF9yZWFkeUNsaWVudHNgIGNhbGwuIEF0dGFjaGVzCiAgICAgICAqIGVsZW1lbnQgZG9tIGJ5IGNhbGxpbmcgYF9hdHRhY2hEb21gIHdpdGggdGhlIGRvbSBzdGFtcGVkIGZyb20gdGhlCiAgICAgICAqIGVsZW1lbnQncyB0ZW1wbGF0ZSB2aWEgYF9zdGFtcFRlbXBsYXRlYC4gTm90ZSB0aGF0IHRoaXMgYWxsb3dzCiAgICAgICAqIGNsaWVudCBkb20gdG8gYmUgYXR0YWNoZWQgdG8gdGhlIGVsZW1lbnQgcHJpb3IgdG8gYW55IG9ic2VydmVycwogICAgICAgKiBydW5uaW5nLgogICAgICAgKgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICovCiAgICAgIF9yZWFkeUNsaWVudHMoKSB7CiAgICAgICAgaWYgKHRoaXMuX3RlbXBsYXRlKSB7CiAgICAgICAgICB0aGlzLnJvb3QgPSB0aGlzLl9hdHRhY2hEb20oLyoqIEB0eXBlIHtTdGFtcGVkVGVtcGxhdGV9ICovKHRoaXMucm9vdCkpOwogICAgICAgIH0KICAgICAgICAvLyBUaGUgc3VwZXIuX3JlYWR5Q2xpZW50cyBoZXJlIHNldHMgdGhlIGNsaWVudHMgaW5pdGlhbGl6ZWQgZmxhZy4KICAgICAgICAvLyBXZSBtdXN0IHdhaXQgdG8gZG8gdGhpcyB1bnRpbCBhZnRlciBjbGllbnQgZG9tIGlzIGNyZWF0ZWQvYXR0YWNoZWQKICAgICAgICAvLyBzbyB0aGF0IHRoaXMgZmxhZyBjYW4gYmUgY2hlY2tlZCB0byBwcmV2ZW50IG5vdGlmaWNhdGlvbnMgZmlyZWQKICAgICAgICAvLyBkdXJpbmcgdGhpcyBwcm9jZXNzIGZyb20gYmVpbmcgaGFuZGxlZCBiZWZvcmUgY2xpZW50cyBhcmUgcmVhZHkuCiAgICAgICAgc3VwZXIuX3JlYWR5Q2xpZW50cygpOwogICAgICB9CgoKICAgICAgLyoqCiAgICAgICAqIEF0dGFjaGVzIGFuIGVsZW1lbnQncyBzdGFtcGVkIGRvbSB0byBpdHNlbGYuIEJ5IGRlZmF1bHQsCiAgICAgICAqIHRoaXMgbWV0aG9kIGNyZWF0ZXMgYSBgc2hhZG93Um9vdGAgYW5kIGFkZHMgdGhlIGRvbSB0byBpdC4KICAgICAgICogSG93ZXZlciwgdGhpcyBtZXRob2QgbWF5IGJlIG92ZXJyaWRkZW4gdG8gYWxsb3cgYW4gZWxlbWVudAogICAgICAgKiB0byBwdXQgaXRzIGRvbSBpbiBhbm90aGVyIGxvY2F0aW9uLgogICAgICAgKgogICAgICAgKiBAdGhyb3dzIHtFcnJvcn0KICAgICAgICogQHN1cHByZXNzIHttaXNzaW5nUmV0dXJufQogICAgICAgKiBAcGFyYW0ge1N0YW1wZWRUZW1wbGF0ZX0gZG9tIHRvIGF0dGFjaCB0byB0aGUgZWxlbWVudC4KICAgICAgICogQHJldHVybiB7U2hhZG93Um9vdH0gbm9kZSB0byB3aGljaCB0aGUgZG9tIGhhcyBiZWVuIGF0dGFjaGVkLgogICAgICAgKi8KICAgICAgX2F0dGFjaERvbShkb20pIHsKICAgICAgICBpZiAodGhpcy5hdHRhY2hTaGFkb3cpIHsKICAgICAgICAgIGlmIChkb20pIHsKICAgICAgICAgICAgaWYgKCF0aGlzLnNoYWRvd1Jvb3QpIHsKICAgICAgICAgICAgICB0aGlzLmF0dGFjaFNoYWRvdyh7bW9kZTogJ29wZW4nfSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5zaGFkb3dSb290LmFwcGVuZENoaWxkKGRvbSk7CiAgICAgICAgICAgIHJldHVybiB0aGlzLnNoYWRvd1Jvb3Q7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTaGFkb3dET00gbm90IGF2YWlsYWJsZS4gJyArCiAgICAgICAgICAgIC8vIFRPRE8oc29ydmVsbCk6IG1vdmUgdG8gY29tcGlsZS10aW1lIGNvbmRpdGlvbmFsIHdoZW4gc3VwcG9ydGVkCiAgICAgICAgICAnUG9seW1lci5FbGVtZW50IGNhbiBjcmVhdGUgZG9tIGFzIGNoaWxkcmVuIGluc3RlYWQgb2YgaW4gJyArCiAgICAgICAgICAnU2hhZG93RE9NIGJ5IHNldHRpbmcgYHRoaXMucm9vdCA9IHRoaXM7XGAgYmVmb3JlIFxgcmVhZHlcYC4nKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBXaGVuIHVzaW5nIHRoZSBTaGFkeUNTUyBzY29waW5nIGFuZCBjdXN0b20gcHJvcGVydHkgc2hpbSwgY2F1c2VzIGFsbAogICAgICAgKiBzaGltbWVkIHN0eWxlcyBpbiB0aGlzIGVsZW1lbnQgKGFuZCBpdHMgc3VidHJlZSkgdG8gYmUgdXBkYXRlZAogICAgICAgKiBiYXNlZCBvbiBjdXJyZW50IGN1c3RvbSBwcm9wZXJ0eSB2YWx1ZXMuCiAgICAgICAqCiAgICAgICAqIFRoZSBvcHRpb25hbCBwYXJhbWV0ZXIgb3ZlcnJpZGVzIGlubGluZSBjdXN0b20gcHJvcGVydHkgc3R5bGVzIHdpdGggYW4KICAgICAgICogb2JqZWN0IG9mIHByb3BlcnRpZXMgd2hlcmUgdGhlIGtleXMgYXJlIENTUyBwcm9wZXJ0aWVzLCBhbmQgdGhlIHZhbHVlcwogICAgICAgKiBhcmUgc3RyaW5ncy4KICAgICAgICoKICAgICAgICogRXhhbXBsZTogYHRoaXMudXBkYXRlU3R5bGVzKHsnLS1jb2xvcic6ICdibHVlJ30pYAogICAgICAgKgogICAgICAgKiBUaGVzZSBwcm9wZXJ0aWVzIGFyZSByZXRhaW5lZCB1bmxlc3MgYSB2YWx1ZSBvZiBgbnVsbGAgaXMgc2V0LgogICAgICAgKgogICAgICAgKiBOb3RlOiBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHN1cHBvcnQgdXBkYXRpbmcgQ1NTIG1peGlucy4KICAgICAgICogWW91IGNhbiBub3QgZHluYW1pY2FsbHkgY2hhbmdlIHRoZSB2YWx1ZSBvZiBhbiBgQGFwcGx5YC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtPYmplY3Q9fSBwcm9wZXJ0aWVzIEJhZyBvZiBjdXN0b20gcHJvcGVydHkga2V5L3ZhbHVlcyB0bwogICAgICAgKiAgIGFwcGx5IHRvIHRoaXMgZWxlbWVudC4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQHN1cHByZXNzIHtpbnZhbGlkQ2FzdHN9CiAgICAgICAqLwogICAgICB1cGRhdGVTdHlsZXMocHJvcGVydGllcykgewogICAgICAgIGlmICh3aW5kb3cuU2hhZHlDU1MpIHsKICAgICAgICAgIHdpbmRvdy5TaGFkeUNTUy5zdHlsZVN1YnRyZWUoLyoqIEB0eXBlIHshSFRNTEVsZW1lbnR9ICovKHRoaXMpLCBwcm9wZXJ0aWVzKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXdyaXRlcyBhIGdpdmVuIFVSTCByZWxhdGl2ZSB0byBhIGJhc2UgVVJMLiBUaGUgYmFzZSBVUkwgZGVmYXVsdHMgdG8KICAgICAgICogdGhlIG9yaWdpbmFsIGxvY2F0aW9uIG9mIHRoZSBkb2N1bWVudCBjb250YWluaW5nIHRoZSBgZG9tLW1vZHVsZWAgZm9yCiAgICAgICAqIHRoaXMgZWxlbWVudC4gVGhpcyBtZXRob2Qgd2lsbCByZXR1cm4gdGhlIHNhbWUgVVJMIGJlZm9yZSBhbmQgYWZ0ZXIKICAgICAgICogYnVuZGxpbmcuCiAgICAgICAqCiAgICAgICAqIE5vdGUgdGhhdCB0aGlzIGZ1bmN0aW9uIHBlcmZvcm1zIG5vIHJlc29sdXRpb24gZm9yIFVSTHMgdGhhdCBzdGFydAogICAgICAgKiB3aXRoIGAvYCAoYWJzb2x1dGUgVVJMcykgb3IgYCNgIChoYXNoIGlkZW50aWZpZXJzKS4gIEZvciBnZW5lcmFsIHB1cnBvc2UKICAgICAgICogVVJMIHJlc29sdXRpb24sIHVzZSBgd2luZG93LlVSTGAuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHRvIHJlc29sdmUuCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nPX0gYmFzZSBPcHRpb25hbCBiYXNlIFVSTCB0byByZXNvbHZlIGFnYWluc3QsIGRlZmF1bHRzCiAgICAgICAqIHRvIHRoZSBlbGVtZW50J3MgYGltcG9ydFBhdGhgCiAgICAgICAqIEByZXR1cm4ge3N0cmluZ30gUmV3cml0dGVuIFVSTCByZWxhdGl2ZSB0byBiYXNlCiAgICAgICAqLwogICAgICByZXNvbHZlVXJsKHVybCwgYmFzZSkgewogICAgICAgIGlmICghYmFzZSAmJiB0aGlzLmltcG9ydFBhdGgpIHsKICAgICAgICAgIGJhc2UgPSBQb2x5bWVyLlJlc29sdmVVcmwucmVzb2x2ZVVybCh0aGlzLmltcG9ydFBhdGgpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gUG9seW1lci5SZXNvbHZlVXJsLnJlc29sdmVVcmwodXJsLCBiYXNlKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIE92ZXJyaWRlcyBgUHJvcGVydHlBY2Nlc3NvcnNgIHRvIGFkZCBtYXAgb2YgZHluYW1pYyBmdW5jdGlvbnMgb24KICAgICAgICogdGVtcGxhdGUgaW5mbywgZm9yIGNvbnN1bXB0aW9uIGJ5IGBQcm9wZXJ0eUVmZmVjdHNgIHRlbXBsYXRlIGJpbmRpbmcKICAgICAgICogY29kZS4gVGhpcyBtYXAgZGV0ZXJtaW5lcyB3aGljaCBtZXRob2QgdGVtcGxhdGVzIHNob3VsZCBoYXZlIGFjY2Vzc29ycwogICAgICAgKiBjcmVhdGVkIGZvciB0aGVtLgogICAgICAgKgogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICogQHN1cHByZXNzIHttaXNzaW5nUHJvcGVydGllc30gSW50ZXJmYWNlcyBpbiBjbG9zdXJlIGRvIG5vdCBpbmhlcml0IHN0YXRpY3MsIGJ1dCBjbGFzc2VzIGRvCiAgICAgICAqLwogICAgICBzdGF0aWMgX3BhcnNlVGVtcGxhdGVDb250ZW50KHRlbXBsYXRlLCB0ZW1wbGF0ZUluZm8sIG5vZGVJbmZvKSB7CiAgICAgICAgdGVtcGxhdGVJbmZvLmR5bmFtaWNGbnMgPSB0ZW1wbGF0ZUluZm8uZHluYW1pY0ZucyB8fCB0aGlzLl9wcm9wZXJ0aWVzOwogICAgICAgIHJldHVybiBzdXBlci5fcGFyc2VUZW1wbGF0ZUNvbnRlbnQodGVtcGxhdGUsIHRlbXBsYXRlSW5mbywgbm9kZUluZm8pOwogICAgICB9CgogICAgfQoKICAgIHJldHVybiBQb2x5bWVyRWxlbWVudDsKICB9KTsKCiAgLyoqCiAgICogV2hlbiB1c2luZyB0aGUgU2hhZHlDU1Mgc2NvcGluZyBhbmQgY3VzdG9tIHByb3BlcnR5IHNoaW0sIGNhdXNlcyBhbGwKICAgKiBzaGltbWVkIGBzdHlsZXNgICh2aWEgYGN1c3RvbS1zdHlsZWApIGluIHRoZSBkb2N1bWVudCAoYW5kIGl0cyBzdWJ0cmVlKQogICAqIHRvIGJlIHVwZGF0ZWQgYmFzZWQgb24gY3VycmVudCBjdXN0b20gcHJvcGVydHkgdmFsdWVzLgogICAqCiAgICogVGhlIG9wdGlvbmFsIHBhcmFtZXRlciBvdmVycmlkZXMgaW5saW5lIGN1c3RvbSBwcm9wZXJ0eSBzdHlsZXMgd2l0aCBhbgogICAqIG9iamVjdCBvZiBwcm9wZXJ0aWVzIHdoZXJlIHRoZSBrZXlzIGFyZSBDU1MgcHJvcGVydGllcywgYW5kIHRoZSB2YWx1ZXMKICAgKiBhcmUgc3RyaW5ncy4KICAgKgogICAqIEV4YW1wbGU6IGBQb2x5bWVyLnVwZGF0ZVN0eWxlcyh7Jy0tY29sb3InOiAnYmx1ZSd9KWAKICAgKgogICAqIFRoZXNlIHByb3BlcnRpZXMgYXJlIHJldGFpbmVkIHVubGVzcyBhIHZhbHVlIG9mIGBudWxsYCBpcyBzZXQuCiAgICoKICAgKiBAcGFyYW0ge09iamVjdD19IHByb3BzIEJhZyBvZiBjdXN0b20gcHJvcGVydHkga2V5L3ZhbHVlcyB0bwogICAqICAgYXBwbHkgdG8gdGhlIGRvY3VtZW50LgogICAqIEByZXR1cm4ge3ZvaWR9CiAgICovCiAgUG9seW1lci51cGRhdGVTdHlsZXMgPSBmdW5jdGlvbihwcm9wcykgewogICAgaWYgKHdpbmRvdy5TaGFkeUNTUykgewogICAgICB3aW5kb3cuU2hhZHlDU1Muc3R5bGVEb2N1bWVudChwcm9wcyk7CiAgICB9CiAgfTsKCn0pKCk7Cjwvc2NyaXB0PjxzY3JpcHQ+CihmdW5jdGlvbigpIHsKICAndXNlIHN0cmljdCc7CgogIC8qKgogICAqIEBzdW1tYXJ5IENvbGxhcHNlIG11bHRpcGxlIGNhbGxiYWNrcyBpbnRvIG9uZSBpbnZvY2F0aW9uIGFmdGVyIGEgdGltZXIuCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKi8KICBjbGFzcyBEZWJvdW5jZXIgewogICAgY29uc3RydWN0b3IoKSB7CiAgICAgIHRoaXMuX2FzeW5jTW9kdWxlID0gbnVsbDsKICAgICAgdGhpcy5fY2FsbGJhY2sgPSBudWxsOwogICAgICB0aGlzLl90aW1lciA9IG51bGw7CiAgICB9CiAgICAvKioKICAgICAqIFNldHMgdGhlIHNjaGVkdWxlcjsgdGhhdCBpcywgYSBtb2R1bGUgd2l0aCB0aGUgQXN5bmMgaW50ZXJmYWNlLAogICAgICogYSBjYWxsYmFjayBhbmQgb3B0aW9uYWwgYXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgcnVuIGZ1bmN0aW9uCiAgICAgKiBmcm9tIHRoZSBhc3luYyBtb2R1bGUuCiAgICAgKgogICAgICogQHBhcmFtIHshQXN5bmNJbnRlcmZhY2V9IGFzeW5jTW9kdWxlIE9iamVjdCB3aXRoIEFzeW5jIGludGVyZmFjZS4KICAgICAqIEBwYXJhbSB7ZnVuY3Rpb24oKX0gY2FsbGJhY2sgQ2FsbGJhY2sgdG8gcnVuLgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgc2V0Q29uZmlnKGFzeW5jTW9kdWxlLCBjYWxsYmFjaykgewogICAgICB0aGlzLl9hc3luY01vZHVsZSA9IGFzeW5jTW9kdWxlOwogICAgICB0aGlzLl9jYWxsYmFjayA9IGNhbGxiYWNrOwogICAgICB0aGlzLl90aW1lciA9IHRoaXMuX2FzeW5jTW9kdWxlLnJ1bigoKSA9PiB7CiAgICAgICAgdGhpcy5fdGltZXIgPSBudWxsOwogICAgICAgIHRoaXMuX2NhbGxiYWNrKCk7CiAgICAgIH0pOwogICAgfQogICAgLyoqCiAgICAgKiBDYW5jZWxzIGFuIGFjdGl2ZSBkZWJvdW5jZXIgYW5kIHJldHVybnMgYSByZWZlcmVuY2UgdG8gaXRzZWxmLgogICAgICoKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIGNhbmNlbCgpIHsKICAgICAgaWYgKHRoaXMuaXNBY3RpdmUoKSkgewogICAgICAgIHRoaXMuX2FzeW5jTW9kdWxlLmNhbmNlbCh0aGlzLl90aW1lcik7CiAgICAgICAgdGhpcy5fdGltZXIgPSBudWxsOwogICAgICB9CiAgICB9CiAgICAvKioKICAgICAqIEZsdXNoZXMgYW4gYWN0aXZlIGRlYm91bmNlciBhbmQgcmV0dXJucyBhIHJlZmVyZW5jZSB0byBpdHNlbGYuCiAgICAgKgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgZmx1c2goKSB7CiAgICAgIGlmICh0aGlzLmlzQWN0aXZlKCkpIHsKICAgICAgICB0aGlzLmNhbmNlbCgpOwogICAgICAgIHRoaXMuX2NhbGxiYWNrKCk7CiAgICAgIH0KICAgIH0KICAgIC8qKgogICAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBkZWJvdW5jZXIgaXMgYWN0aXZlLgogICAgICoKICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgYWN0aXZlLgogICAgICovCiAgICBpc0FjdGl2ZSgpIHsKICAgICAgcmV0dXJuIHRoaXMuX3RpbWVyICE9IG51bGw7CiAgICB9CiAgICAvKioKICAgICAqIENyZWF0ZXMgYSBkZWJvdW5jZXIgaWYgbm8gZGVib3VuY2VyIGlzIHBhc3NlZCBhcyBhIHBhcmFtZXRlcgogICAgICogb3IgaXQgY2FuY2VscyBhbiBhY3RpdmUgZGVib3VuY2VyIG90aGVyd2lzZS4gVGhlIGZvbGxvd2luZwogICAgICogZXhhbXBsZSBzaG93cyBob3cgYSBkZWJvdW5jZXIgY2FuIGJlIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyB3aXRoaW4gYQogICAgICogbWljcm90YXNrIGFuZCAiZGVib3VuY2VkIiBzdWNoIHRoYXQgdGhlIHByb3ZpZGVkIGNhbGxiYWNrIGZ1bmN0aW9uIGlzCiAgICAgKiBjYWxsZWQgb25jZS4gQWRkIHRoaXMgbWV0aG9kIHRvIGEgY3VzdG9tIGVsZW1lbnQ6CiAgICAgKgogICAgICogX2RlYm91bmNlV29yaygpIHsKICAgICAqICAgdGhpcy5fZGVib3VuY2VKb2IgPSBQb2x5bWVyLkRlYm91bmNlci5kZWJvdW5jZSh0aGlzLl9kZWJvdW5jZUpvYiwKICAgICAqICAgICAgIFBvbHltZXIuQXN5bmMubWljcm9UYXNrLCAoKSA9PiB7CiAgICAgKiAgICAgdGhpcy5fZG9Xb3JrKCk7CiAgICAgKiAgIH0pOwogICAgICogfQogICAgICoKICAgICAqIElmIHRoZSBgX2RlYm91bmNlV29ya2AgbWV0aG9kIGlzIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyB3aXRoaW4gdGhlIHNhbWUKICAgICAqIG1pY3JvdGFzaywgdGhlIGBfZG9Xb3JrYCBmdW5jdGlvbiB3aWxsIGJlIGNhbGxlZCBvbmx5IG9uY2UgYXQgdGhlIG5leHQKICAgICAqIG1pY3JvdGFzayBjaGVja3BvaW50LgogICAgICoKICAgICAqIE5vdGU6IEluIHRlc3RpbmcgaXQgaXMgb2Z0ZW4gY29udmVuaWVudCB0byBhdm9pZCBhc3luY2hyb255LiBUbyBhY2NvbXBsaXNoCiAgICAgKiB0aGlzIHdpdGggYSBkZWJvdW5jZXIsIHlvdSBjYW4gdXNlIGBQb2x5bWVyLmVucXVldWVEZWJvdW5jZXJgIGFuZAogICAgICogYFBvbHltZXIuZmx1c2hgLiBGb3IgZXhhbXBsZSwgZXh0ZW5kIHRoZSBhYm92ZSBleGFtcGxlIGJ5IGFkZGluZwogICAgICogYFBvbHltZXIuZW5xdWV1ZURlYm91bmNlcih0aGlzLl9kZWJvdW5jZUpvYilgIGF0IHRoZSBlbmQgb2YgdGhlCiAgICAgKiBgX2RlYm91bmNlV29ya2AgbWV0aG9kLiBUaGVuIGluIGEgdGVzdCwgY2FsbCBgUG9seW1lci5mbHVzaGAgdG8gZW5zdXJlCiAgICAgKiB0aGUgZGVib3VuY2VyIGhhcyBjb21wbGV0ZWQuCiAgICAgKgogICAgICogQHBhcmFtIHtEZWJvdW5jZXI/fSBkZWJvdW5jZXIgRGVib3VuY2VyIG9iamVjdC4KICAgICAqIEBwYXJhbSB7IUFzeW5jSW50ZXJmYWNlfSBhc3luY01vZHVsZSBPYmplY3Qgd2l0aCBBc3luYyBpbnRlcmZhY2UKICAgICAqIEBwYXJhbSB7ZnVuY3Rpb24oKX0gY2FsbGJhY2sgQ2FsbGJhY2sgdG8gcnVuLgogICAgICogQHJldHVybiB7IURlYm91bmNlcn0gUmV0dXJucyBhIGRlYm91bmNlciBvYmplY3QuCiAgICAgKi8KICAgIHN0YXRpYyBkZWJvdW5jZShkZWJvdW5jZXIsIGFzeW5jTW9kdWxlLCBjYWxsYmFjaykgewogICAgICBpZiAoZGVib3VuY2VyIGluc3RhbmNlb2YgRGVib3VuY2VyKSB7CiAgICAgICAgZGVib3VuY2VyLmNhbmNlbCgpOwogICAgICB9IGVsc2UgewogICAgICAgIGRlYm91bmNlciA9IG5ldyBEZWJvdW5jZXIoKTsKICAgICAgfQogICAgICBkZWJvdW5jZXIuc2V0Q29uZmlnKGFzeW5jTW9kdWxlLCBjYWxsYmFjayk7CiAgICAgIHJldHVybiBkZWJvdW5jZXI7CiAgICB9CiAgfQoKICAvKiogQGNvbnN0ICovCiAgUG9seW1lci5EZWJvdW5jZXIgPSBEZWJvdW5jZXI7Cn0pKCk7Cjwvc2NyaXB0PjxzY3JpcHQ+CihmdW5jdGlvbigpIHsKCiAgJ3VzZSBzdHJpY3QnOwoKICAvLyBkZXRlY3QgbmF0aXZlIHRvdWNoIGFjdGlvbiBzdXBwb3J0CiAgbGV0IEhBU19OQVRJVkVfVEEgPSB0eXBlb2YgZG9jdW1lbnQuaGVhZC5zdHlsZS50b3VjaEFjdGlvbiA9PT0gJ3N0cmluZyc7CiAgbGV0IEdFU1RVUkVfS0VZID0gJ19fcG9seW1lckdlc3R1cmVzJzsKICBsZXQgSEFORExFRF9PQkogPSAnX19wb2x5bWVyR2VzdHVyZXNIYW5kbGVkJzsKICBsZXQgVE9VQ0hfQUNUSU9OID0gJ19fcG9seW1lckdlc3R1cmVzVG91Y2hBY3Rpb24nOwogIC8vIHJhZGl1cyBmb3IgdGFwIGFuZCB0cmFjawogIGxldCBUQVBfRElTVEFOQ0UgPSAyNTsKICBsZXQgVFJBQ0tfRElTVEFOQ0UgPSA1OwogIC8vIG51bWJlciBvZiBsYXN0IE4gdHJhY2sgcG9zaXRpb25zIHRvIGtlZXAKICBsZXQgVFJBQ0tfTEVOR1RIID0gMjsKCiAgLy8gRGlzYWJsaW5nICJtb3VzZSIgaGFuZGxlcnMgZm9yIDI1MDBtcyBpcyBlbm91Z2gKICBsZXQgTU9VU0VfVElNRU9VVCA9IDI1MDA7CiAgbGV0IE1PVVNFX0VWRU5UUyA9IFsnbW91c2Vkb3duJywgJ21vdXNlbW92ZScsICdtb3VzZXVwJywgJ2NsaWNrJ107CiAgLy8gYW4gYXJyYXkgb2YgYml0bWFzayB2YWx1ZXMgZm9yIG1hcHBpbmcgTW91c2VFdmVudC53aGljaCB0byBNb3VzZUV2ZW50LmJ1dHRvbnMKICBsZXQgTU9VU0VfV0hJQ0hfVE9fQlVUVE9OUyA9IFswLCAxLCA0LCAyXTsKICBsZXQgTU9VU0VfSEFTX0JVVFRPTlMgPSAoZnVuY3Rpb24oKSB7CiAgICB0cnkgewogICAgICByZXR1cm4gbmV3IE1vdXNlRXZlbnQoJ3Rlc3QnLCB7YnV0dG9uczogMX0pLmJ1dHRvbnMgPT09IDE7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICB9KSgpOwoKICAvKioKICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBQb3NzaWJsZSBtb3VzZSBldmVudCBuYW1lCiAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiBtb3VzZSBldmVudCwgZmFsc2UgaWYgbm90CiAgICovCiAgZnVuY3Rpb24gaXNNb3VzZUV2ZW50KG5hbWUpIHsKICAgIHJldHVybiBNT1VTRV9FVkVOVFMuaW5kZXhPZihuYW1lKSA+IC0xOwogIH0KCiAgLyogZXNsaW50IG5vLWVtcHR5OiBbImVycm9yIiwgeyAiYWxsb3dFbXB0eUNhdGNoIjogdHJ1ZSB9XSAqLwogIC8vIGNoZWNrIGZvciBwYXNzaXZlIGV2ZW50IGxpc3RlbmVycwogIGxldCBTVVBQT1JUU19QQVNTSVZFID0gZmFsc2U7CiAgKGZ1bmN0aW9uKCkgewogICAgdHJ5IHsKICAgICAgbGV0IG9wdHMgPSBPYmplY3QuZGVmaW5lUHJvcGVydHkoe30sICdwYXNzaXZlJywge2dldCgpIHtTVVBQT1JUU19QQVNTSVZFID0gdHJ1ZTt9fSk7CiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCd0ZXN0JywgbnVsbCwgb3B0cyk7CiAgICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCd0ZXN0JywgbnVsbCwgb3B0cyk7CiAgICB9IGNhdGNoKGUpIHt9CiAgfSkoKTsKCiAgLyoqCiAgICogR2VuZXJhdGUgc2V0dGluZ3MgZm9yIGV2ZW50IGxpc3RlbmVycywgZGVwZW5kYW50IG9uIGBQb2x5bWVyLnBhc3NpdmVUb3VjaEdlc3R1cmVzYAogICAqCiAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZSBFdmVudCBuYW1lIHRvIGRldGVybWluZSBpZiBge3Bhc3NpdmV9YCBvcHRpb24gaXMgbmVlZGVkCiAgICogQHJldHVybiB7e3Bhc3NpdmU6IGJvb2xlYW59IHwgdW5kZWZpbmVkfSBPcHRpb25zIHRvIHVzZSBmb3IgYWRkRXZlbnRMaXN0ZW5lciBhbmQgcmVtb3ZlRXZlbnRMaXN0ZW5lcgogICAqLwogIGZ1bmN0aW9uIFBBU1NJVkVfVE9VQ0goZXZlbnROYW1lKSB7CiAgICBpZiAoaXNNb3VzZUV2ZW50KGV2ZW50TmFtZSkgfHwgZXZlbnROYW1lID09PSAndG91Y2hlbmQnKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGlmIChIQVNfTkFUSVZFX1RBICYmIFNVUFBPUlRTX1BBU1NJVkUgJiYgUG9seW1lci5wYXNzaXZlVG91Y2hHZXN0dXJlcykgewogICAgICByZXR1cm4ge3Bhc3NpdmU6IHRydWV9OwogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuOwogICAgfQogIH0KCiAgLy8gQ2hlY2sgZm9yIHRvdWNoLW9ubHkgZGV2aWNlcwogIGxldCBJU19UT1VDSF9PTkxZID0gbmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvaVAoPzpbb2FdZHxob25lKXxBbmRyb2lkLyk7CgogIGxldCBHZXN0dXJlUmVjb2duaXplciA9IGZ1bmN0aW9uKCl7fTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFycwogIC8qKiBAdHlwZSB7ZnVuY3Rpb24oKTogdm9pZH0gKi8KICBHZXN0dXJlUmVjb2duaXplci5wcm90b3R5cGUucmVzZXQ7CiAgLyoqIEB0eXBlIHtmdW5jdGlvbihNb3VzZUV2ZW50KTogdm9pZCB8IHVuZGVmaW5lZH0gKi8KICBHZXN0dXJlUmVjb2duaXplci5wcm90b3R5cGUubW91c2Vkb3duOwogIC8qKiBAdHlwZSB7KGZ1bmN0aW9uKE1vdXNlRXZlbnQpOiB2b2lkIHwgdW5kZWZpbmVkKX0gKi8KICBHZXN0dXJlUmVjb2duaXplci5wcm90b3R5cGUubW91c2Vtb3ZlOwogIC8qKiBAdHlwZSB7KGZ1bmN0aW9uKE1vdXNlRXZlbnQpOiB2b2lkIHwgdW5kZWZpbmVkKX0gKi8KICBHZXN0dXJlUmVjb2duaXplci5wcm90b3R5cGUubW91c2V1cDsKICAvKiogQHR5cGUgeyhmdW5jdGlvbihUb3VjaEV2ZW50KTogdm9pZCB8IHVuZGVmaW5lZCl9ICovCiAgR2VzdHVyZVJlY29nbml6ZXIucHJvdG90eXBlLnRvdWNoc3RhcnQ7CiAgLyoqIEB0eXBlIHsoZnVuY3Rpb24oVG91Y2hFdmVudCk6IHZvaWQgfCB1bmRlZmluZWQpfSAqLwogIEdlc3R1cmVSZWNvZ25pemVyLnByb3RvdHlwZS50b3VjaG1vdmU7CiAgLyoqIEB0eXBlIHsoZnVuY3Rpb24oVG91Y2hFdmVudCk6IHZvaWQgfCB1bmRlZmluZWQpfSAqLwogIEdlc3R1cmVSZWNvZ25pemVyLnByb3RvdHlwZS50b3VjaGVuZDsKICAvKiogQHR5cGUgeyhmdW5jdGlvbihNb3VzZUV2ZW50KTogdm9pZCB8IHVuZGVmaW5lZCl9ICovCiAgR2VzdHVyZVJlY29nbml6ZXIucHJvdG90eXBlLmNsaWNrOwoKICAvLyBrZWVwIHRyYWNrIG9mIGFueSBsYWJlbHMgaGl0IGJ5IHRoZSBtb3VzZUNhbmNlbGxlcgogIC8qKiBAdHlwZSB7IUFycmF5PCFIVE1MTGFiZWxFbGVtZW50Pn0gKi8KICBjb25zdCBjbGlja2VkTGFiZWxzID0gW107CgogIC8qKiBAdHlwZSB7IU9iamVjdDxib29sZWFuPn0gKi8KICBjb25zdCBsYWJlbGxhYmxlID0gewogICAgJ2J1dHRvbic6IHRydWUsCiAgICAnaW5wdXQnOiB0cnVlLAogICAgJ2tleWdlbic6IHRydWUsCiAgICAnbWV0ZXInOiB0cnVlLAogICAgJ291dHB1dCc6IHRydWUsCiAgICAndGV4dGFyZWEnOiB0cnVlLAogICAgJ3Byb2dyZXNzJzogdHJ1ZSwKICAgICdzZWxlY3QnOiB0cnVlCiAgfTsKCiAgLy8gRGVmaW5lZCBhdCBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9mb3JtLWNvbnRyb2wtaW5mcmFzdHJ1Y3R1cmUuaHRtbCNlbmFibGluZy1hbmQtZGlzYWJsaW5nLWZvcm0tY29udHJvbHM6LXRoZS1kaXNhYmxlZC1hdHRyaWJ1dGUKICAvKiogQHR5cGUgeyFPYmplY3Q8Ym9vbGVhbj59ICovCiAgY29uc3QgY2FuQmVEaXNhYmxlZCA9IHsKICAgICdidXR0b24nOiB0cnVlLAogICAgJ2NvbW1hbmQnOiB0cnVlLAogICAgJ2ZpZWxkc2V0JzogdHJ1ZSwKICAgICdpbnB1dCc6IHRydWUsCiAgICAna2V5Z2VuJzogdHJ1ZSwKICAgICdvcHRncm91cCc6IHRydWUsCiAgICAnb3B0aW9uJzogdHJ1ZSwKICAgICdzZWxlY3QnOiB0cnVlLAogICAgJ3RleHRhcmVhJzogdHJ1ZQogIH07CgogIC8qKgogICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsIEVsZW1lbnQgdG8gY2hlY2sgbGFiZWxsaW5nIHN0YXR1cwogICAqIEByZXR1cm4ge2Jvb2xlYW59IGVsZW1lbnQgY2FuIGhhdmUgbGFiZWxzCiAgICovCiAgZnVuY3Rpb24gY2FuQmVMYWJlbGxlZChlbCkgewogICAgcmV0dXJuIGxhYmVsbGFibGVbZWwubG9jYWxOYW1lXSB8fCBmYWxzZTsKICB9CgogIC8qKgogICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsIEVsZW1lbnQgdGhhdCBtYXkgYmUgbGFiZWxsZWQuCiAgICogQHJldHVybiB7IUFycmF5PCFIVE1MTGFiZWxFbGVtZW50Pn0gUmVsZXZhbnQgbGFiZWwgZm9yIGBlbGAKICAgKi8KICBmdW5jdGlvbiBtYXRjaGluZ0xhYmVscyhlbCkgewogICAgbGV0IGxhYmVscyA9IEFycmF5LmZyb20oLyoqIEB0eXBlIHtIVE1MSW5wdXRFbGVtZW50fSAqLyhlbCkubGFiZWxzIHx8IFtdKTsKICAgIC8vIElFIGRvZXNuJ3QgaGF2ZSBgbGFiZWxzYCBhbmQgU2FmYXJpIGRvZXNuJ3QgcG9wdWxhdGUgYGxhYmVsc2AKICAgIC8vIGlmIGVsZW1lbnQgaXMgaW4gYSBzaGFkb3dyb290LgogICAgLy8gSW4gdGhpcyBpbnN0YW5jZSwgZmluZGluZyB0aGUgbm9uLWFuY2VzdG9yIGxhYmVscyBpcyBlbm91Z2gsCiAgICAvLyBhcyB0aGUgbW91c2VDYW5jZWxsb3IgY29kZSB3aWxsIGhhbmRsZSBhbmNzdG9yIGxhYmVscwogICAgaWYgKCFsYWJlbHMubGVuZ3RoKSB7CiAgICAgIGxhYmVscyA9IFtdOwogICAgICBsZXQgcm9vdCA9IGVsLmdldFJvb3ROb2RlKCk7CiAgICAgIC8vIGlmIHRoZXJlIGlzIGFuIGlkIG9uIGBlbGAsIGNoZWNrIGZvciBhbGwgbGFiZWxzIHdpdGggYSBtYXRjaGluZyBgZm9yYCBhdHRyaWJ1dGUKICAgICAgaWYgKGVsLmlkKSB7CiAgICAgICAgbGV0IG1hdGNoaW5nID0gcm9vdC5xdWVyeVNlbGVjdG9yQWxsKGBsYWJlbFtmb3IgPSAke2VsLmlkfV1gKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1hdGNoaW5nLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICBsYWJlbHMucHVzaCgvKiogQHR5cGUgeyFIVE1MTGFiZWxFbGVtZW50fSAqLyhtYXRjaGluZ1tpXSkpOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIGxhYmVsczsKICB9CgogIC8vIHRvdWNoIHdpbGwgbWFrZSBzeW50aGV0aWMgbW91c2UgZXZlbnRzCiAgLy8gYHByZXZlbnREZWZhdWx0YCBvbiB0b3VjaGVuZCB3aWxsIGNhbmNlbCB0aGVtLAogIC8vIGJ1dCB0aGlzIGJyZWFrcyBgPGlucHV0PmAgZm9jdXMgYW5kIGxpbmsgY2xpY2tzCiAgLy8gZGlzYWJsZSBtb3VzZSBoYW5kbGVycyBmb3IgTU9VU0VfVElNRU9VVCBtcyBhZnRlcgogIC8vIGEgdG91Y2hlbmQgdG8gaWdub3JlIHN5bnRoZXRpYyBtb3VzZSBldmVudHMKICBsZXQgbW91c2VDYW5jZWxsZXIgPSBmdW5jdGlvbihtb3VzZUV2ZW50KSB7CiAgICAvLyBDaGVjayBmb3Igc291cmNlQ2FwYWJpbGl0aWVzLCB1c2VkIHRvIGRpc3Rpbmd1aXNoIHN5bnRoZXRpYyBldmVudHMKICAgIC8vIGlmIG1vdXNlRXZlbnQgZGlkIG5vdCBjb21lIGZyb20gYSBkZXZpY2UgdGhhdCBmaXJlcyB0b3VjaCBldmVudHMsCiAgICAvLyBpdCB3YXMgbWFkZSBieSBhIHJlYWwgbW91c2UgYW5kIHNob3VsZCBiZSBjb3VudGVkCiAgICAvLyBodHRwOi8vd2ljZy5naXRodWIuaW8vSW5wdXREZXZpY2VDYXBhYmlsaXRpZXMvI2RvbS1pbnB1dGRldmljZWNhcGFiaWxpdGllcy1maXJlc3RvdWNoZXZlbnRzCiAgICBsZXQgc2MgPSBtb3VzZUV2ZW50LnNvdXJjZUNhcGFiaWxpdGllczsKICAgIGlmIChzYyAmJiAhc2MuZmlyZXNUb3VjaEV2ZW50cykgewogICAgICByZXR1cm47CiAgICB9CiAgICAvLyBza2lwIHN5bnRoZXRpYyBtb3VzZSBldmVudHMKICAgIG1vdXNlRXZlbnRbSEFORExFRF9PQkpdID0ge3NraXA6IHRydWV9OwogICAgLy8gZGlzYWJsZSAiZ2hvc3QgY2xpY2tzIgogICAgaWYgKG1vdXNlRXZlbnQudHlwZSA9PT0gJ2NsaWNrJykgewogICAgICBsZXQgY2xpY2tGcm9tTGFiZWwgPSBmYWxzZTsKICAgICAgbGV0IHBhdGggPSBtb3VzZUV2ZW50LmNvbXBvc2VkUGF0aCAmJiBtb3VzZUV2ZW50LmNvbXBvc2VkUGF0aCgpOwogICAgICBpZiAocGF0aCkgewogICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGF0aC5sZW5ndGg7IGkrKykgewogICAgICAgICAgaWYgKHBhdGhbaV0ubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFKSB7CiAgICAgICAgICAgIGlmIChwYXRoW2ldLmxvY2FsTmFtZSA9PT0gJ2xhYmVsJykgewogICAgICAgICAgICAgIGNsaWNrZWRMYWJlbHMucHVzaChwYXRoW2ldKTsKICAgICAgICAgICAgfSBlbHNlIGlmIChjYW5CZUxhYmVsbGVkKHBhdGhbaV0pKSB7CiAgICAgICAgICAgICAgbGV0IG93bmVyTGFiZWxzID0gbWF0Y2hpbmdMYWJlbHMocGF0aFtpXSk7CiAgICAgICAgICAgICAgLy8gY2hlY2sgaWYgb25lIG9mIHRoZSBjbGlja2VkIGxhYmVscyBpcyBsYWJlbGxpbmcgdGhpcyBlbGVtZW50CiAgICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBvd25lckxhYmVscy5sZW5ndGg7IGorKykgewogICAgICAgICAgICAgICAgY2xpY2tGcm9tTGFiZWwgPSBjbGlja0Zyb21MYWJlbCB8fCBjbGlja2VkTGFiZWxzLmluZGV4T2Yob3duZXJMYWJlbHNbal0pID4gLTE7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocGF0aFtpXSA9PT0gUE9JTlRFUlNUQVRFLm1vdXNlLnRhcmdldCkgewogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICAgIC8vIGlmIG9uZSBvZiB0aGUgY2xpY2tlZCBsYWJlbHMgd2FzIGxhYmVsbGluZyB0aGUgdGFyZ2V0IGVsZW1lbnQsCiAgICAgIC8vIHRoaXMgaXMgbm90IGEgZ2hvc3QgY2xpY2sKICAgICAgaWYgKGNsaWNrRnJvbUxhYmVsKSB7CiAgICAgICAgcmV0dXJuOwogICAgICB9CiAgICAgIG1vdXNlRXZlbnQucHJldmVudERlZmF1bHQoKTsKICAgICAgbW91c2VFdmVudC5zdG9wUHJvcGFnYXRpb24oKTsKICAgIH0KICB9OwoKICAvKioKICAgKiBAcGFyYW0ge2Jvb2xlYW49fSBzZXR1cCBUcnVlIHRvIGFkZCwgZmFsc2UgdG8gcmVtb3ZlLgogICAqIEByZXR1cm4ge3ZvaWR9CiAgICovCiAgZnVuY3Rpb24gc2V0dXBUZWFyZG93bk1vdXNlQ2FuY2VsbGVyKHNldHVwKSB7CiAgICBsZXQgZXZlbnRzID0gSVNfVE9VQ0hfT05MWSA/IFsnY2xpY2snXSA6IE1PVVNFX0VWRU5UUzsKICAgIGZvciAobGV0IGkgPSAwLCBlbjsgaSA8IGV2ZW50cy5sZW5ndGg7IGkrKykgewogICAgICBlbiA9IGV2ZW50c1tpXTsKICAgICAgaWYgKHNldHVwKSB7CiAgICAgICAgLy8gcmVzZXQgY2xpY2tMYWJlbHMgYXJyYXkKICAgICAgICBjbGlja2VkTGFiZWxzLmxlbmd0aCA9IDA7CiAgICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihlbiwgbW91c2VDYW5jZWxsZXIsIHRydWUpOwogICAgICB9IGVsc2UgewogICAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoZW4sIG1vdXNlQ2FuY2VsbGVyLCB0cnVlKTsKICAgICAgfQogICAgfQogIH0KCiAgZnVuY3Rpb24gaWdub3JlTW91c2UoZSkgewogICAgaWYgKCFQT0lOVEVSU1RBVEUubW91c2UubW91c2VJZ25vcmVKb2IpIHsKICAgICAgc2V0dXBUZWFyZG93bk1vdXNlQ2FuY2VsbGVyKHRydWUpOwogICAgfQogICAgbGV0IHVuc2V0ID0gZnVuY3Rpb24oKSB7CiAgICAgIHNldHVwVGVhcmRvd25Nb3VzZUNhbmNlbGxlcigpOwogICAgICBQT0lOVEVSU1RBVEUubW91c2UudGFyZ2V0ID0gbnVsbDsKICAgICAgUE9JTlRFUlNUQVRFLm1vdXNlLm1vdXNlSWdub3JlSm9iID0gbnVsbDsKICAgIH07CiAgICBQT0lOVEVSU1RBVEUubW91c2UudGFyZ2V0ID0gZS5jb21wb3NlZFBhdGgoKVswXTsKICAgIFBPSU5URVJTVEFURS5tb3VzZS5tb3VzZUlnbm9yZUpvYiA9IFBvbHltZXIuRGVib3VuY2VyLmRlYm91bmNlKAogICAgICAgICAgUE9JTlRFUlNUQVRFLm1vdXNlLm1vdXNlSWdub3JlSm9iCiAgICAgICAgLCBQb2x5bWVyLkFzeW5jLnRpbWVPdXQuYWZ0ZXIoTU9VU0VfVElNRU9VVCkKICAgICAgICAsIHVuc2V0KTsKICB9CgogIC8qKgogICAqIEBwYXJhbSB7TW91c2VFdmVudH0gZXYgZXZlbnQgdG8gdGVzdCBmb3IgbGVmdCBtb3VzZSBidXR0b24gZG93bgogICAqIEByZXR1cm4ge2Jvb2xlYW59IGhhcyBsZWZ0IG1vdXNlIGJ1dHRvbiBkb3duCiAgICovCiAgZnVuY3Rpb24gaGFzTGVmdE1vdXNlQnV0dG9uKGV2KSB7CiAgICBsZXQgdHlwZSA9IGV2LnR5cGU7CiAgICAvLyBleGl0IGVhcmx5IGlmIHRoZSBldmVudCBpcyBub3QgYSBtb3VzZSBldmVudAogICAgaWYgKCFpc01vdXNlRXZlbnQodHlwZSkpIHsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgLy8gZXYuYnV0dG9uIGlzIG5vdCByZWxpYWJsZSBmb3IgbW91c2Vtb3ZlICgwIGlzIG92ZXJsb2FkZWQgYXMgYm90aCBsZWZ0IGJ1dHRvbiBhbmQgbm8gYnV0dG9ucykKICAgIC8vIGluc3RlYWQgd2UgdXNlIGV2LmJ1dHRvbnMgKGJpdG1hc2sgb2YgYnV0dG9ucykgb3IgZmFsbCBiYWNrIHRvIGV2LndoaWNoIChkZXByZWNhdGVkLCAwIGZvciBubyBidXR0b25zLCAxIGZvciBsZWZ0IGJ1dHRvbikKICAgIGlmICh0eXBlID09PSAnbW91c2Vtb3ZlJykgewogICAgICAvLyBhbGxvdyB1bmRlZmluZWQgZm9yIHRlc3RpbmcgZXZlbnRzCiAgICAgIGxldCBidXR0b25zID0gZXYuYnV0dG9ucyA9PT0gdW5kZWZpbmVkID8gMSA6IGV2LmJ1dHRvbnM7CiAgICAgIGlmICgoZXYgaW5zdGFuY2VvZiB3aW5kb3cuTW91c2VFdmVudCkgJiYgIU1PVVNFX0hBU19CVVRUT05TKSB7CiAgICAgICAgYnV0dG9ucyA9IE1PVVNFX1dISUNIX1RPX0JVVFRPTlNbZXYud2hpY2hdIHx8IDA7CiAgICAgIH0KICAgICAgLy8gYnV0dG9ucyBpcyBhIGJpdG1hc2ssIGNoZWNrIHRoYXQgdGhlIGxlZnQgYnV0dG9uIGJpdCBpcyBzZXQgKDEpCiAgICAgIHJldHVybiBCb29sZWFuKGJ1dHRvbnMgJiAxKTsKICAgIH0gZWxzZSB7CiAgICAgIC8vIGFsbG93IHVuZGVmaW5lZCBmb3IgdGVzdGluZyBldmVudHMKICAgICAgbGV0IGJ1dHRvbiA9IGV2LmJ1dHRvbiA9PT0gdW5kZWZpbmVkID8gMCA6IGV2LmJ1dHRvbjsKICAgICAgLy8gZXYuYnV0dG9uIGlzIDAgaW4gbW91c2Vkb3duL21vdXNldXAvY2xpY2sgZm9yIGxlZnQgYnV0dG9uIGFjdGl2YXRpb24KICAgICAgcmV0dXJuIGJ1dHRvbiA9PT0gMDsKICAgIH0KICB9CgogIGZ1bmN0aW9uIGlzU3ludGhldGljQ2xpY2soZXYpIHsKICAgIGlmIChldi50eXBlID09PSAnY2xpY2snKSB7CiAgICAgIC8vIGV2LmRldGFpbCBpcyAwIGZvciBIVE1MRWxlbWVudC5jbGljayBpbiBtb3N0IGJyb3dzZXJzCiAgICAgIGlmIChldi5kZXRhaWwgPT09IDApIHsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfQogICAgICAvLyBpbiB0aGUgd29yc3QgY2FzZSwgY2hlY2sgdGhhdCB0aGUgeC95IHBvc2l0aW9uIG9mIHRoZSBjbGljayBpcyB3aXRoaW4KICAgICAgLy8gdGhlIGJvdW5kaW5nIGJveCBvZiB0aGUgdGFyZ2V0IG9mIHRoZSBldmVudAogICAgICAvLyBUaGFua3MgSUUgMTAgPjooCiAgICAgIGxldCB0ID0gR2VzdHVyZXMuX2ZpbmRPcmlnaW5hbFRhcmdldChldik7CiAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgdGFyZ2V0IG9mIHRoZSBldmVudCBpcyBhbiBlbGVtZW50IHNvIHdlIGNhbiB1c2UgZ2V0Qm91bmRpbmdDbGllbnRSZWN0LAogICAgICAvLyBpZiBub3QsIGp1c3QgYXNzdW1lIGl0IGlzIGEgc3ludGhldGljIGNsaWNrCiAgICAgIGlmICghdC5ub2RlVHlwZSB8fCAvKiogQHR5cGUge0VsZW1lbnR9ICovKHQpLm5vZGVUeXBlICE9PSBOb2RlLkVMRU1FTlRfTk9ERSkgewogICAgICAgIHJldHVybiB0cnVlOwogICAgICB9CiAgICAgIGxldCBiY3IgPSAvKiogQHR5cGUge0VsZW1lbnR9ICovKHQpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOwogICAgICAvLyB1c2UgcGFnZSB4L3kgdG8gYWNjb3VudCBmb3Igc2Nyb2xsaW5nCiAgICAgIGxldCB4ID0gZXYucGFnZVgsIHkgPSBldi5wYWdlWTsKICAgICAgLy8gZXYgaXMgYSBzeW50aGV0aWMgY2xpY2sgaWYgdGhlIHBvc2l0aW9uIGlzIG91dHNpZGUgdGhlIGJvdW5kaW5nIGJveCBvZiB0aGUgdGFyZ2V0CiAgICAgIHJldHVybiAhKCh4ID49IGJjci5sZWZ0ICYmIHggPD0gYmNyLnJpZ2h0KSAmJiAoeSA+PSBiY3IudG9wICYmIHkgPD0gYmNyLmJvdHRvbSkpOwogICAgfQogICAgcmV0dXJuIGZhbHNlOwogIH0KCiAgbGV0IFBPSU5URVJTVEFURSA9IHsKICAgIG1vdXNlOiB7CiAgICAgIHRhcmdldDogbnVsbCwKICAgICAgbW91c2VJZ25vcmVKb2I6IG51bGwKICAgIH0sCiAgICB0b3VjaDogewogICAgICB4OiAwLAogICAgICB5OiAwLAogICAgICBpZDogLTEsCiAgICAgIHNjcm9sbERlY2lkZWQ6IGZhbHNlCiAgICB9CiAgfTsKCiAgZnVuY3Rpb24gZmlyc3RUb3VjaEFjdGlvbihldikgewogICAgbGV0IHRhID0gJ2F1dG8nOwogICAgbGV0IHBhdGggPSBldi5jb21wb3NlZFBhdGggJiYgZXYuY29tcG9zZWRQYXRoKCk7CiAgICBpZiAocGF0aCkgewogICAgICBmb3IgKGxldCBpID0gMCwgbjsgaSA8IHBhdGgubGVuZ3RoOyBpKyspIHsKICAgICAgICBuID0gcGF0aFtpXTsKICAgICAgICBpZiAobltUT1VDSF9BQ1RJT05dKSB7CiAgICAgICAgICB0YSA9IG5bVE9VQ0hfQUNUSU9OXTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIHRhOwogIH0KCiAgZnVuY3Rpb24gdHJhY2tEb2N1bWVudChzdGF0ZU9iaiwgbW92ZWZuLCB1cGZuKSB7CiAgICBzdGF0ZU9iai5tb3ZlZm4gPSBtb3ZlZm47CiAgICBzdGF0ZU9iai51cGZuID0gdXBmbjsKICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIG1vdmVmbik7CiAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgdXBmbik7CiAgfQoKICBmdW5jdGlvbiB1bnRyYWNrRG9jdW1lbnQoc3RhdGVPYmopIHsKICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIHN0YXRlT2JqLm1vdmVmbik7CiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgc3RhdGVPYmoudXBmbik7CiAgICBzdGF0ZU9iai5tb3ZlZm4gPSBudWxsOwogICAgc3RhdGVPYmoudXBmbiA9IG51bGw7CiAgfQoKICAvLyB1c2UgYSBkb2N1bWVudC13aWRlIHRvdWNoZW5kIGxpc3RlbmVyIHRvIHN0YXJ0IHRoZSBnaG9zdC1jbGljayBwcmV2ZW50aW9uIG1lY2hhbmlzbQogIC8vIFVzZSBwYXNzaXZlIGV2ZW50IGxpc3RlbmVycywgaWYgc3VwcG9ydGVkLCB0byBub3QgYWZmZWN0IHNjcm9sbGluZyBwZXJmb3JtYW5jZQogIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoZW5kJywgaWdub3JlTW91c2UsIFNVUFBPUlRTX1BBU1NJVkUgPyB7cGFzc2l2ZTogdHJ1ZX0gOiBmYWxzZSk7CgogIC8qKgogICAqIE1vZHVsZSBmb3IgYWRkaW5nIGxpc3RlbmVycyB0byBhIG5vZGUgZm9yIHRoZSBmb2xsb3dpbmcgbm9ybWFsaXplZAogICAqIGNyb3NzLXBsYXRmb3JtICJnZXN0dXJlIiBldmVudHM6CiAgICogLSBgZG93bmAgLSBtb3VzZSBvciB0b3VjaCB3ZW50IGRvd24KICAgKiAtIGB1cGAgLSBtb3VzZSBvciB0b3VjaCB3ZW50IHVwCiAgICogLSBgdGFwYCAtIG1vdXNlIGNsaWNrIG9yIGZpbmdlciB0YXAKICAgKiAtIGB0cmFja2AgLSBtb3VzZSBkcmFnIG9yIHRvdWNoIG1vdmUKICAgKgogICAqIEBuYW1lc3BhY2UKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBzdW1tYXJ5IE1vZHVsZSBmb3IgYWRkaW5nIGNyb3NzLXBsYXRmb3JtIGdlc3R1cmUgZXZlbnQgbGlzdGVuZXJzLgogICAqLwogIGNvbnN0IEdlc3R1cmVzID0gewogICAgZ2VzdHVyZXM6IHt9LAogICAgcmVjb2duaXplcnM6IFtdLAoKICAgIC8qKgogICAgICogRmluZHMgdGhlIGVsZW1lbnQgcmVuZGVyZWQgb24gdGhlIHNjcmVlbiBhdCB0aGUgcHJvdmlkZWQgY29vcmRpbmF0ZXMuCiAgICAgKgogICAgICogU2ltaWxhciB0byBgZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludGAsIGJ1dCBwaWVyY2VzIHRocm91Z2gKICAgICAqIHNoYWRvdyByb290cy4KICAgICAqCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5HZXN0dXJlcwogICAgICogQHBhcmFtIHtudW1iZXJ9IHggSG9yaXpvbnRhbCBwaXhlbCBjb29yZGluYXRlCiAgICAgKiBAcGFyYW0ge251bWJlcn0geSBWZXJ0aWNhbCBwaXhlbCBjb29yZGluYXRlCiAgICAgKiBAcmV0dXJuIHtFbGVtZW50fSBSZXR1cm5zIHRoZSBkZWVwZXN0IHNoYWRvd1Jvb3QgaW5jbHVzaXZlIGVsZW1lbnQKICAgICAqIGZvdW5kIGF0IHRoZSBzY3JlZW4gcG9zaXRpb24gZ2l2ZW4uCiAgICAgKi8KICAgIGRlZXBUYXJnZXRGaW5kOiBmdW5jdGlvbih4LCB5KSB7CiAgICAgIGxldCBub2RlID0gZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludCh4LCB5KTsKICAgICAgbGV0IG5leHQgPSBub2RlOwogICAgICAvLyB0aGlzIGNvZGUgcGF0aCBpcyBvbmx5IHRha2VuIHdoZW4gbmF0aXZlIFNoYWRvd0RPTSBpcyB1c2VkCiAgICAgIC8vIGlmIHRoZXJlIGlzIGEgc2hhZG93cm9vdCwgaXQgbWF5IGhhdmUgYSBub2RlIGF0IHgveQogICAgICAvLyBpZiB0aGVyZSBpcyBub3QgYSBzaGFkb3dyb290LCBleGl0IHRoZSBsb29wCiAgICAgIHdoaWxlIChuZXh0ICYmIG5leHQuc2hhZG93Um9vdCAmJiAhd2luZG93LlNoYWR5RE9NKSB7CiAgICAgICAgLy8gaWYgdGhlcmUgaXMgYSBub2RlIGF0IHgveSBpbiB0aGUgc2hhZG93cm9vdCwgbG9vayBkZWVwZXIKICAgICAgICBsZXQgb2xkTmV4dCA9IG5leHQ7CiAgICAgICAgbmV4dCA9IG5leHQuc2hhZG93Um9vdC5lbGVtZW50RnJvbVBvaW50KHgsIHkpOwogICAgICAgIC8vIG9uIFNhZmFyaSwgZWxlbWVudEZyb21Qb2ludCBtYXkgcmV0dXJuIHRoZSBzaGFkb3dSb290IGhvc3QKICAgICAgICBpZiAob2xkTmV4dCA9PT0gbmV4dCkgewogICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIGlmIChuZXh0KSB7CiAgICAgICAgICBub2RlID0gbmV4dDsKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIG5vZGU7CiAgICB9LAogICAgLyoqCiAgICAgKiBhIGNoZWFwZXIgY2hlY2sgdGhhbiBldi5jb21wb3NlZFBhdGgoKVswXTsKICAgICAqCiAgICAgKiBAcHJpdmF0ZQogICAgICogQHBhcmFtIHtFdmVudH0gZXYgRXZlbnQuCiAgICAgKiBAcmV0dXJuIHtFdmVudFRhcmdldH0gUmV0dXJucyB0aGUgZXZlbnQgdGFyZ2V0LgogICAgICovCiAgICBfZmluZE9yaWdpbmFsVGFyZ2V0OiBmdW5jdGlvbihldikgewogICAgICAvLyBzaGFkb3dkb20KICAgICAgaWYgKGV2LmNvbXBvc2VkUGF0aCkgewogICAgICAgIGNvbnN0IHRhcmdldHMgPSAvKiogQHR5cGUgeyFBcnJheTwhRXZlbnRUYXJnZXQ+fSAqLyhldi5jb21wb3NlZFBhdGgoKSk7CiAgICAgICAgLy8gSXQgc2hvdWxkbid0IGJlLCBidXQgc29tZXRpbWVzIHRhcmdldHMgaXMgZW1wdHkgKHdpbmRvdyBvbiBTYWZhcmkpLgogICAgICAgIHJldHVybiB0YXJnZXRzLmxlbmd0aCA+IDAgPyB0YXJnZXRzWzBdIDogZXYudGFyZ2V0OwogICAgICB9CiAgICAgIC8vIHNoYWR5ZG9tCiAgICAgIHJldHVybiBldi50YXJnZXQ7CiAgICB9LAoKICAgIC8qKgogICAgICogQHByaXZhdGUKICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2IEV2ZW50LgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgX2hhbmRsZU5hdGl2ZTogZnVuY3Rpb24oZXYpIHsKICAgICAgbGV0IGhhbmRsZWQ7CiAgICAgIGxldCB0eXBlID0gZXYudHlwZTsKICAgICAgbGV0IG5vZGUgPSBldi5jdXJyZW50VGFyZ2V0OwogICAgICBsZXQgZ29iaiA9IG5vZGVbR0VTVFVSRV9LRVldOwogICAgICBpZiAoIWdvYmopIHsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgbGV0IGdzID0gZ29ialt0eXBlXTsKICAgICAgaWYgKCFncykgewogICAgICAgIHJldHVybjsKICAgICAgfQogICAgICBpZiAoIWV2W0hBTkRMRURfT0JKXSkgewogICAgICAgIGV2W0hBTkRMRURfT0JKXSA9IHt9OwogICAgICAgIGlmICh0eXBlLnNsaWNlKDAsIDUpID09PSAndG91Y2gnKSB7CiAgICAgICAgICBldiA9IC8qKiBAdHlwZSB7VG91Y2hFdmVudH0gKi8oZXYpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXNlbGYtYXNzaWduCiAgICAgICAgICBsZXQgdCA9IGV2LmNoYW5nZWRUb3VjaGVzWzBdOwogICAgICAgICAgaWYgKHR5cGUgPT09ICd0b3VjaHN0YXJ0JykgewogICAgICAgICAgICAvLyBvbmx5IGhhbmRsZSB0aGUgZmlyc3QgZmluZ2VyCiAgICAgICAgICAgIGlmIChldi50b3VjaGVzLmxlbmd0aCA9PT0gMSkgewogICAgICAgICAgICAgIFBPSU5URVJTVEFURS50b3VjaC5pZCA9IHQuaWRlbnRpZmllcjsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKFBPSU5URVJTVEFURS50b3VjaC5pZCAhPT0gdC5pZGVudGlmaWVyKSB7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghSEFTX05BVElWRV9UQSkgewogICAgICAgICAgICBpZiAodHlwZSA9PT0gJ3RvdWNoc3RhcnQnIHx8IHR5cGUgPT09ICd0b3VjaG1vdmUnKSB7CiAgICAgICAgICAgICAgR2VzdHVyZXMuX2hhbmRsZVRvdWNoQWN0aW9uKGV2KTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICBoYW5kbGVkID0gZXZbSEFORExFRF9PQkpdOwogICAgICAvLyB1c2VkIHRvIGlnbm9yZSBzeW50aGV0aWMgbW91c2UgZXZlbnRzCiAgICAgIGlmIChoYW5kbGVkLnNraXApIHsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgLy8gcmVzZXQgcmVjb2duaXplciBzdGF0ZQogICAgICBmb3IgKGxldCBpID0gMCwgcjsgaSA8IEdlc3R1cmVzLnJlY29nbml6ZXJzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgciA9IEdlc3R1cmVzLnJlY29nbml6ZXJzW2ldOwogICAgICAgIGlmIChnc1tyLm5hbWVdICYmICFoYW5kbGVkW3IubmFtZV0pIHsKICAgICAgICAgIGlmIChyLmZsb3cgJiYgci5mbG93LnN0YXJ0LmluZGV4T2YoZXYudHlwZSkgPiAtMSAmJiByLnJlc2V0KSB7CiAgICAgICAgICAgIHIucmVzZXQoKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgICAgLy8gZW5mb3JjZSBnZXN0dXJlIHJlY29nbml6ZXIgb3JkZXIKICAgICAgZm9yIChsZXQgaSA9IDAsIHI7IGkgPCBHZXN0dXJlcy5yZWNvZ25pemVycy5sZW5ndGg7IGkrKykgewogICAgICAgIHIgPSBHZXN0dXJlcy5yZWNvZ25pemVyc1tpXTsKICAgICAgICBpZiAoZ3Nbci5uYW1lXSAmJiAhaGFuZGxlZFtyLm5hbWVdKSB7CiAgICAgICAgICBoYW5kbGVkW3IubmFtZV0gPSB0cnVlOwogICAgICAgICAgclt0eXBlXShldik7CiAgICAgICAgfQogICAgICB9CiAgICB9LAoKICAgIC8qKgogICAgICogQHByaXZhdGUKICAgICAqIEBwYXJhbSB7VG91Y2hFdmVudH0gZXYgRXZlbnQuCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBfaGFuZGxlVG91Y2hBY3Rpb246IGZ1bmN0aW9uKGV2KSB7CiAgICAgIGxldCB0ID0gZXYuY2hhbmdlZFRvdWNoZXNbMF07CiAgICAgIGxldCB0eXBlID0gZXYudHlwZTsKICAgICAgaWYgKHR5cGUgPT09ICd0b3VjaHN0YXJ0JykgewogICAgICAgIFBPSU5URVJTVEFURS50b3VjaC54ID0gdC5jbGllbnRYOwogICAgICAgIFBPSU5URVJTVEFURS50b3VjaC55ID0gdC5jbGllbnRZOwogICAgICAgIFBPSU5URVJTVEFURS50b3VjaC5zY3JvbGxEZWNpZGVkID0gZmFsc2U7CiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gJ3RvdWNobW92ZScpIHsKICAgICAgICBpZiAoUE9JTlRFUlNUQVRFLnRvdWNoLnNjcm9sbERlY2lkZWQpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgUE9JTlRFUlNUQVRFLnRvdWNoLnNjcm9sbERlY2lkZWQgPSB0cnVlOwogICAgICAgIGxldCB0YSA9IGZpcnN0VG91Y2hBY3Rpb24oZXYpOwogICAgICAgIGxldCBwcmV2ZW50ID0gZmFsc2U7CiAgICAgICAgbGV0IGR4ID0gTWF0aC5hYnMoUE9JTlRFUlNUQVRFLnRvdWNoLnggLSB0LmNsaWVudFgpOwogICAgICAgIGxldCBkeSA9IE1hdGguYWJzKFBPSU5URVJTVEFURS50b3VjaC55IC0gdC5jbGllbnRZKTsKICAgICAgICBpZiAoIWV2LmNhbmNlbGFibGUpIHsKICAgICAgICAgIC8vIHNjcm9sbGluZyBpcyBoYXBwZW5pbmcKICAgICAgICB9IGVsc2UgaWYgKHRhID09PSAnbm9uZScpIHsKICAgICAgICAgIHByZXZlbnQgPSB0cnVlOwogICAgICAgIH0gZWxzZSBpZiAodGEgPT09ICdwYW4teCcpIHsKICAgICAgICAgIHByZXZlbnQgPSBkeSA+IGR4OwogICAgICAgIH0gZWxzZSBpZiAodGEgPT09ICdwYW4teScpIHsKICAgICAgICAgIHByZXZlbnQgPSBkeCA+IGR5OwogICAgICAgIH0KICAgICAgICBpZiAocHJldmVudCkgewogICAgICAgICAgZXYucHJldmVudERlZmF1bHQoKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgR2VzdHVyZXMucHJldmVudCgndHJhY2snKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0sCgogICAgLyoqCiAgICAgKiBBZGRzIGFuIGV2ZW50IGxpc3RlbmVyIHRvIGEgbm9kZSBmb3IgdGhlIGdpdmVuIGdlc3R1cmUgdHlwZS4KICAgICAqCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5HZXN0dXJlcwogICAgICogQHBhcmFtIHshTm9kZX0gbm9kZSBOb2RlIHRvIGFkZCBsaXN0ZW5lciBvbgogICAgICogQHBhcmFtIHtzdHJpbmd9IGV2VHlwZSBHZXN0dXJlIHR5cGU6IGBkb3duYCwgYHVwYCwgYHRyYWNrYCwgb3IgYHRhcGAKICAgICAqIEBwYXJhbSB7IWZ1bmN0aW9uKCFFdmVudCk6dm9pZH0gaGFuZGxlciBFdmVudCBsaXN0ZW5lciBmdW5jdGlvbiB0byBjYWxsCiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBSZXR1cm5zIHRydWUgaWYgYSBnZXN0dXJlIGV2ZW50IGxpc3RlbmVyIHdhcyBhZGRlZC4KICAgICAqIEB0aGlzIHtHZXN0dXJlc30KICAgICAqLwogICAgYWRkTGlzdGVuZXI6IGZ1bmN0aW9uKG5vZGUsIGV2VHlwZSwgaGFuZGxlcikgewogICAgICBpZiAodGhpcy5nZXN0dXJlc1tldlR5cGVdKSB7CiAgICAgICAgdGhpcy5fYWRkKG5vZGUsIGV2VHlwZSwgaGFuZGxlcik7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgIH0KICAgICAgcmV0dXJuIGZhbHNlOwogICAgfSwKCiAgICAvKioKICAgICAqIFJlbW92ZXMgYW4gZXZlbnQgbGlzdGVuZXIgZnJvbSBhIG5vZGUgZm9yIHRoZSBnaXZlbiBnZXN0dXJlIHR5cGUuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuR2VzdHVyZXMKICAgICAqIEBwYXJhbSB7IU5vZGV9IG5vZGUgTm9kZSB0byByZW1vdmUgbGlzdGVuZXIgZnJvbQogICAgICogQHBhcmFtIHtzdHJpbmd9IGV2VHlwZSBHZXN0dXJlIHR5cGU6IGBkb3duYCwgYHVwYCwgYHRyYWNrYCwgb3IgYHRhcGAKICAgICAqIEBwYXJhbSB7IWZ1bmN0aW9uKCFFdmVudCk6dm9pZH0gaGFuZGxlciBFdmVudCBsaXN0ZW5lciBmdW5jdGlvbiBwcmV2aW91c2x5IHBhc3NlZCB0bwogICAgICogIGBhZGRMaXN0ZW5lcmAuCiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBSZXR1cm5zIHRydWUgaWYgYSBnZXN0dXJlIGV2ZW50IGxpc3RlbmVyIHdhcyByZW1vdmVkLgogICAgICogQHRoaXMge0dlc3R1cmVzfQogICAgICovCiAgICByZW1vdmVMaXN0ZW5lcjogZnVuY3Rpb24obm9kZSwgZXZUeXBlLCBoYW5kbGVyKSB7CiAgICAgIGlmICh0aGlzLmdlc3R1cmVzW2V2VHlwZV0pIHsKICAgICAgICB0aGlzLl9yZW1vdmUobm9kZSwgZXZUeXBlLCBoYW5kbGVyKTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfQogICAgICByZXR1cm4gZmFsc2U7CiAgICB9LAoKICAgIC8qKgogICAgICogYXV0b21hdGUgdGhlIGV2ZW50IGxpc3RlbmVycyBmb3IgdGhlIG5hdGl2ZSBldmVudHMKICAgICAqCiAgICAgKiBAcHJpdmF0ZQogICAgICogQHBhcmFtIHshSFRNTEVsZW1lbnR9IG5vZGUgTm9kZSBvbiB3aGljaCB0byBhZGQgdGhlIGV2ZW50LgogICAgICogQHBhcmFtIHtzdHJpbmd9IGV2VHlwZSBFdmVudCB0eXBlIHRvIGFkZC4KICAgICAqIEBwYXJhbSB7ZnVuY3Rpb24oIUV2ZW50KX0gaGFuZGxlciBFdmVudCBoYW5kbGVyIGZ1bmN0aW9uLgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqIEB0aGlzIHtHZXN0dXJlc30KICAgICAqLwogICAgX2FkZDogZnVuY3Rpb24obm9kZSwgZXZUeXBlLCBoYW5kbGVyKSB7CiAgICAgIGxldCByZWNvZ25pemVyID0gdGhpcy5nZXN0dXJlc1tldlR5cGVdOwogICAgICBsZXQgZGVwcyA9IHJlY29nbml6ZXIuZGVwczsKICAgICAgbGV0IG5hbWUgPSByZWNvZ25pemVyLm5hbWU7CiAgICAgIGxldCBnb2JqID0gbm9kZVtHRVNUVVJFX0tFWV07CiAgICAgIGlmICghZ29iaikgewogICAgICAgIG5vZGVbR0VTVFVSRV9LRVldID0gZ29iaiA9IHt9OwogICAgICB9CiAgICAgIGZvciAobGV0IGkgPSAwLCBkZXAsIGdkOyBpIDwgZGVwcy5sZW5ndGg7IGkrKykgewogICAgICAgIGRlcCA9IGRlcHNbaV07CiAgICAgICAgLy8gZG9uJ3QgYWRkIG1vdXNlIGhhbmRsZXJzIG9uIGlPUyBiZWNhdXNlIHRoZXkgY2F1c2UgZ3JheSBzZWxlY3Rpb24gb3ZlcmxheXMKICAgICAgICBpZiAoSVNfVE9VQ0hfT05MWSAmJiBpc01vdXNlRXZlbnQoZGVwKSAmJiBkZXAgIT09ICdjbGljaycpIHsKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICBnZCA9IGdvYmpbZGVwXTsKICAgICAgICBpZiAoIWdkKSB7CiAgICAgICAgICBnb2JqW2RlcF0gPSBnZCA9IHtfY291bnQ6IDB9OwogICAgICAgIH0KICAgICAgICBpZiAoZ2QuX2NvdW50ID09PSAwKSB7CiAgICAgICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoZGVwLCB0aGlzLl9oYW5kbGVOYXRpdmUsIFBBU1NJVkVfVE9VQ0goZGVwKSk7CiAgICAgICAgfQogICAgICAgIGdkW25hbWVdID0gKGdkW25hbWVdIHx8IDApICsgMTsKICAgICAgICBnZC5fY291bnQgPSAoZ2QuX2NvdW50IHx8IDApICsgMTsKICAgICAgfQogICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoZXZUeXBlLCBoYW5kbGVyKTsKICAgICAgaWYgKHJlY29nbml6ZXIudG91Y2hBY3Rpb24pIHsKICAgICAgICB0aGlzLnNldFRvdWNoQWN0aW9uKG5vZGUsIHJlY29nbml6ZXIudG91Y2hBY3Rpb24pOwogICAgICB9CiAgICB9LAoKICAgIC8qKgogICAgICogYXV0b21hdGUgZXZlbnQgbGlzdGVuZXIgcmVtb3ZhbCBmb3IgbmF0aXZlIGV2ZW50cwogICAgICoKICAgICAqIEBwcml2YXRlCiAgICAgKiBAcGFyYW0geyFIVE1MRWxlbWVudH0gbm9kZSBOb2RlIG9uIHdoaWNoIHRvIHJlbW92ZSB0aGUgZXZlbnQuCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gZXZUeXBlIEV2ZW50IHR5cGUgdG8gcmVtb3ZlLgogICAgICogQHBhcmFtIHtmdW5jdGlvbihFdmVudD8pfSBoYW5kbGVyIEV2ZW50IGhhbmRsZXIgZnVuY3Rpb24uCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICogQHRoaXMge0dlc3R1cmVzfQogICAgICovCiAgICBfcmVtb3ZlOiBmdW5jdGlvbihub2RlLCBldlR5cGUsIGhhbmRsZXIpIHsKICAgICAgbGV0IHJlY29nbml6ZXIgPSB0aGlzLmdlc3R1cmVzW2V2VHlwZV07CiAgICAgIGxldCBkZXBzID0gcmVjb2duaXplci5kZXBzOwogICAgICBsZXQgbmFtZSA9IHJlY29nbml6ZXIubmFtZTsKICAgICAgbGV0IGdvYmogPSBub2RlW0dFU1RVUkVfS0VZXTsKICAgICAgaWYgKGdvYmopIHsKICAgICAgICBmb3IgKGxldCBpID0gMCwgZGVwLCBnZDsgaSA8IGRlcHMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgIGRlcCA9IGRlcHNbaV07CiAgICAgICAgICBnZCA9IGdvYmpbZGVwXTsKICAgICAgICAgIGlmIChnZCAmJiBnZFtuYW1lXSkgewogICAgICAgICAgICBnZFtuYW1lXSA9IChnZFtuYW1lXSB8fCAxKSAtIDE7CiAgICAgICAgICAgIGdkLl9jb3VudCA9IChnZC5fY291bnQgfHwgMSkgLSAxOwogICAgICAgICAgICBpZiAoZ2QuX2NvdW50ID09PSAwKSB7CiAgICAgICAgICAgICAgbm9kZS5yZW1vdmVFdmVudExpc3RlbmVyKGRlcCwgdGhpcy5faGFuZGxlTmF0aXZlLCBQQVNTSVZFX1RPVUNIKGRlcCkpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICAgIG5vZGUucmVtb3ZlRXZlbnRMaXN0ZW5lcihldlR5cGUsIGhhbmRsZXIpOwogICAgfSwKCiAgICAvKioKICAgICAqIFJlZ2lzdGVycyBhIG5ldyBnZXN0dXJlIGV2ZW50IHJlY29nbml6ZXIgZm9yIGFkZGluZyBuZXcgY3VzdG9tCiAgICAgKiBnZXN0dXJlIGV2ZW50IHR5cGVzLgogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLkdlc3R1cmVzCiAgICAgKiBAcGFyYW0geyFHZXN0dXJlUmVjb2duaXplcn0gcmVjb2cgR2VzdHVyZSByZWNvZ25pemVyIGRlc2NyaXB0b3IKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKiBAdGhpcyB7R2VzdHVyZXN9CiAgICAgKi8KICAgIHJlZ2lzdGVyOiBmdW5jdGlvbihyZWNvZykgewogICAgICB0aGlzLnJlY29nbml6ZXJzLnB1c2gocmVjb2cpOwogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJlY29nLmVtaXRzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgdGhpcy5nZXN0dXJlc1tyZWNvZy5lbWl0c1tpXV0gPSByZWNvZzsKICAgICAgfQogICAgfSwKCiAgICAvKioKICAgICAqIEBwcml2YXRlCiAgICAgKiBAcGFyYW0ge3N0cmluZ30gZXZOYW1lIEV2ZW50IG5hbWUuCiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IFJldHVybnMgdGhlIGdlc3R1cmUgZm9yIHRoZSBnaXZlbiBldmVudCBuYW1lLgogICAgICogQHRoaXMge0dlc3R1cmVzfQogICAgICovCiAgICBfZmluZFJlY29nbml6ZXJCeUV2ZW50OiBmdW5jdGlvbihldk5hbWUpIHsKICAgICAgZm9yIChsZXQgaSA9IDAsIHI7IGkgPCB0aGlzLnJlY29nbml6ZXJzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgciA9IHRoaXMucmVjb2duaXplcnNbaV07CiAgICAgICAgZm9yIChsZXQgaiA9IDAsIG47IGogPCByLmVtaXRzLmxlbmd0aDsgaisrKSB7CiAgICAgICAgICBuID0gci5lbWl0c1tqXTsKICAgICAgICAgIGlmIChuID09PSBldk5hbWUpIHsKICAgICAgICAgICAgcmV0dXJuIHI7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICAgIHJldHVybiBudWxsOwogICAgfSwKCiAgICAvKioKICAgICAqIFNldHMgc2Nyb2xsaW5nIGRpcmVjdGlvbiBvbiBub2RlLgogICAgICoKICAgICAqIFRoaXMgdmFsdWUgaXMgY2hlY2tlZCBvbiBmaXJzdCBtb3ZlLCB0aHVzIGl0IHNob3VsZCBiZSBjYWxsZWQgcHJpb3IgdG8KICAgICAqIGFkZGluZyBldmVudCBsaXN0ZW5lcnMuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuR2VzdHVyZXMKICAgICAqIEBwYXJhbSB7IUVsZW1lbnR9IG5vZGUgTm9kZSB0byBzZXQgdG91Y2ggYWN0aW9uIHNldHRpbmcgb24KICAgICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSBUb3VjaCBhY3Rpb24gdmFsdWUKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIHNldFRvdWNoQWN0aW9uOiBmdW5jdGlvbihub2RlLCB2YWx1ZSkgewogICAgICBpZiAoSEFTX05BVElWRV9UQSkgewogICAgICAgIC8vIE5PVEU6IGFkZCB0b3VjaEFjdGlvbiBhc3luYyBzbyB0aGF0IGV2ZW50cyBjYW4gYmUgYWRkZWQgaW4KICAgICAgICAvLyBjdXN0b20gZWxlbWVudCBjb25zdHJ1Y3RvcnMuIE90aGVyd2lzZSB3ZSBydW4gYWZvdWwgb2YgY3VzdG9tCiAgICAgICAgLy8gZWxlbWVudHMgcmVzdHJpY3Rpb24gYWdhaW5zdCBzZXR0aW5ncyBhdHRyaWJ1dGVzIChzdHlsZSkgaW4gdGhlCiAgICAgICAgLy8gY29uc3RydWN0b3IuCiAgICAgICAgUG9seW1lci5Bc3luYy5taWNyb1Rhc2sucnVuKCgpID0+IHsKICAgICAgICAgIG5vZGUuc3R5bGUudG91Y2hBY3Rpb24gPSB2YWx1ZTsKICAgICAgICB9KTsKICAgICAgfQogICAgICBub2RlW1RPVUNIX0FDVElPTl0gPSB2YWx1ZTsKICAgIH0sCgogICAgLyoqCiAgICAgKiBEaXNwYXRjaGVzIGFuIGV2ZW50IG9uIHRoZSBgdGFyZ2V0YCBlbGVtZW50IG9mIGB0eXBlYCB3aXRoIHRoZSBnaXZlbgogICAgICogYGRldGFpbGAuCiAgICAgKiBAcHJpdmF0ZQogICAgICogQHBhcmFtIHshRXZlbnRUYXJnZXR9IHRhcmdldCBUaGUgZWxlbWVudCBvbiB3aGljaCB0byBmaXJlIGFuIGV2ZW50LgogICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgVGhlIHR5cGUgb2YgZXZlbnQgdG8gZmlyZS4KICAgICAqIEBwYXJhbSB7IU9iamVjdD19IGRldGFpbCBUaGUgZGV0YWlsIG9iamVjdCB0byBwb3B1bGF0ZSBvbiB0aGUgZXZlbnQuCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBfZmlyZTogZnVuY3Rpb24odGFyZ2V0LCB0eXBlLCBkZXRhaWwpIHsKICAgICAgbGV0IGV2ID0gbmV3IEV2ZW50KHR5cGUsIHsgYnViYmxlczogdHJ1ZSwgY2FuY2VsYWJsZTogdHJ1ZSwgY29tcG9zZWQ6IHRydWUgfSk7CiAgICAgIGV2LmRldGFpbCA9IGRldGFpbDsKICAgICAgdGFyZ2V0LmRpc3BhdGNoRXZlbnQoZXYpOwogICAgICAvLyBmb3J3YXJkIGBwcmV2ZW50RGVmYXVsdGAgaW4gYSBjbGVhbiB3YXkKICAgICAgaWYgKGV2LmRlZmF1bHRQcmV2ZW50ZWQpIHsKICAgICAgICBsZXQgcHJldmVudGVyID0gZGV0YWlsLnByZXZlbnRlciB8fCBkZXRhaWwuc291cmNlRXZlbnQ7CiAgICAgICAgaWYgKHByZXZlbnRlciAmJiBwcmV2ZW50ZXIucHJldmVudERlZmF1bHQpIHsKICAgICAgICAgIHByZXZlbnRlci5wcmV2ZW50RGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgfQogICAgfSwKCiAgICAvKioKICAgICAqIFByZXZlbnRzIHRoZSBkaXNwYXRjaCBhbmQgZGVmYXVsdCBhY3Rpb24gb2YgdGhlIGdpdmVuIGV2ZW50IG5hbWUuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuR2VzdHVyZXMKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldk5hbWUgRXZlbnQgbmFtZS4KICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKiBAdGhpcyB7R2VzdHVyZXN9CiAgICAgKi8KICAgIHByZXZlbnQ6IGZ1bmN0aW9uKGV2TmFtZSkgewogICAgICBsZXQgcmVjb2duaXplciA9IHRoaXMuX2ZpbmRSZWNvZ25pemVyQnlFdmVudChldk5hbWUpOwogICAgICBpZiAocmVjb2duaXplci5pbmZvKSB7CiAgICAgICAgcmVjb2duaXplci5pbmZvLnByZXZlbnQgPSB0cnVlOwogICAgICB9CiAgICB9LAoKICAgIC8qKgogICAgICogUmVzZXQgdGhlIDI1MDBtcyB0aW1lb3V0IG9uIHByb2Nlc3NpbmcgbW91c2UgaW5wdXQgYWZ0ZXIgZGV0ZWN0aW5nIHRvdWNoIGlucHV0LgogICAgICoKICAgICAqIFRvdWNoIGlucHV0cyBjcmVhdGUgc3ludGhlc2l6ZWQgbW91c2UgaW5wdXRzIGFueXdoZXJlIGZyb20gMCB0byAyMDAwbXMgYWZ0ZXIgdGhlIHRvdWNoLgogICAgICogVGhpcyBtZXRob2Qgc2hvdWxkIG9ubHkgYmUgY2FsbGVkIGR1cmluZyB0ZXN0aW5nIHdpdGggc2ltdWxhdGVkIHRvdWNoIGlucHV0cy4KICAgICAqIENhbGxpbmcgdGhpcyBtZXRob2QgaW4gcHJvZHVjdGlvbiBtYXkgY2F1c2UgZHVwbGljYXRlIHRhcHMgb3Igb3RoZXIgR2VzdHVyZXMuCiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIuR2VzdHVyZXMKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIHJlc2V0TW91c2VDYW5jZWxsZXI6IGZ1bmN0aW9uKCkgewogICAgICBpZiAoUE9JTlRFUlNUQVRFLm1vdXNlLm1vdXNlSWdub3JlSm9iKSB7CiAgICAgICAgUE9JTlRFUlNUQVRFLm1vdXNlLm1vdXNlSWdub3JlSm9iLmZsdXNoKCk7CiAgICAgIH0KICAgIH0KICB9OwoKICAvKiBlc2xpbnQtZGlzYWJsZSB2YWxpZC1qc2RvYyAqLwoKICBHZXN0dXJlcy5yZWdpc3Rlcih7CiAgICBuYW1lOiAnZG93bnVwJywKICAgIGRlcHM6IFsnbW91c2Vkb3duJywgJ3RvdWNoc3RhcnQnLCAndG91Y2hlbmQnXSwKICAgIGZsb3c6IHsKICAgICAgc3RhcnQ6IFsnbW91c2Vkb3duJywgJ3RvdWNoc3RhcnQnXSwKICAgICAgZW5kOiBbJ21vdXNldXAnLCAndG91Y2hlbmQnXQogICAgfSwKICAgIGVtaXRzOiBbJ2Rvd24nLCAndXAnXSwKCiAgICBpbmZvOiB7CiAgICAgIG1vdmVmbjogbnVsbCwKICAgICAgdXBmbjogbnVsbAogICAgfSwKCiAgICAvKioKICAgICAqIEB0aGlzIHtHZXN0dXJlUmVjb2duaXplcn0KICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIHJlc2V0OiBmdW5jdGlvbigpIHsKICAgICAgdW50cmFja0RvY3VtZW50KHRoaXMuaW5mbyk7CiAgICB9LAoKICAgIC8qKgogICAgICogQHRoaXMge0dlc3R1cmVSZWNvZ25pemVyfQogICAgICogQHBhcmFtIHtNb3VzZUV2ZW50fSBlCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBtb3VzZWRvd246IGZ1bmN0aW9uKGUpIHsKICAgICAgaWYgKCFoYXNMZWZ0TW91c2VCdXR0b24oZSkpIHsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgbGV0IHQgPSBHZXN0dXJlcy5fZmluZE9yaWdpbmFsVGFyZ2V0KGUpOwogICAgICBsZXQgc2VsZiA9IHRoaXM7CiAgICAgIGxldCBtb3ZlZm4gPSBmdW5jdGlvbiBtb3ZlZm4oZSkgewogICAgICAgIGlmICghaGFzTGVmdE1vdXNlQnV0dG9uKGUpKSB7CiAgICAgICAgICBzZWxmLl9maXJlKCd1cCcsIHQsIGUpOwogICAgICAgICAgdW50cmFja0RvY3VtZW50KHNlbGYuaW5mbyk7CiAgICAgICAgfQogICAgICB9OwogICAgICBsZXQgdXBmbiA9IGZ1bmN0aW9uIHVwZm4oZSkgewogICAgICAgIGlmIChoYXNMZWZ0TW91c2VCdXR0b24oZSkpIHsKICAgICAgICAgIHNlbGYuX2ZpcmUoJ3VwJywgdCwgZSk7CiAgICAgICAgfQogICAgICAgIHVudHJhY2tEb2N1bWVudChzZWxmLmluZm8pOwogICAgICB9OwogICAgICB0cmFja0RvY3VtZW50KHRoaXMuaW5mbywgbW92ZWZuLCB1cGZuKTsKICAgICAgdGhpcy5fZmlyZSgnZG93bicsIHQsIGUpOwogICAgfSwKICAgIC8qKgogICAgICogQHRoaXMge0dlc3R1cmVSZWNvZ25pemVyfQogICAgICogQHBhcmFtIHtUb3VjaEV2ZW50fSBlCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICB0b3VjaHN0YXJ0OiBmdW5jdGlvbihlKSB7CiAgICAgIHRoaXMuX2ZpcmUoJ2Rvd24nLCBHZXN0dXJlcy5fZmluZE9yaWdpbmFsVGFyZ2V0KGUpLCBlLmNoYW5nZWRUb3VjaGVzWzBdLCBlKTsKICAgIH0sCiAgICAvKioKICAgICAqIEB0aGlzIHtHZXN0dXJlUmVjb2duaXplcn0KICAgICAqIEBwYXJhbSB7VG91Y2hFdmVudH0gZQogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgdG91Y2hlbmQ6IGZ1bmN0aW9uKGUpIHsKICAgICAgdGhpcy5fZmlyZSgndXAnLCBHZXN0dXJlcy5fZmluZE9yaWdpbmFsVGFyZ2V0KGUpLCBlLmNoYW5nZWRUb3VjaGVzWzBdLCBlKTsKICAgIH0sCiAgICAvKioKICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlCiAgICAgKiBAcGFyYW0geyFFdmVudFRhcmdldH0gdGFyZ2V0CiAgICAgKiBAcGFyYW0ge0V2ZW50fSBldmVudAogICAgICogQHBhcmFtIHtGdW5jdGlvbn0gcHJldmVudGVyCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBfZmlyZTogZnVuY3Rpb24odHlwZSwgdGFyZ2V0LCBldmVudCwgcHJldmVudGVyKSB7CiAgICAgIEdlc3R1cmVzLl9maXJlKHRhcmdldCwgdHlwZSwgewogICAgICAgIHg6IGV2ZW50LmNsaWVudFgsCiAgICAgICAgeTogZXZlbnQuY2xpZW50WSwKICAgICAgICBzb3VyY2VFdmVudDogZXZlbnQsCiAgICAgICAgcHJldmVudGVyOiBwcmV2ZW50ZXIsCiAgICAgICAgcHJldmVudDogZnVuY3Rpb24oZSkgewogICAgICAgICAgcmV0dXJuIEdlc3R1cmVzLnByZXZlbnQoZSk7CiAgICAgICAgfQogICAgICB9KTsKICAgIH0KICB9KTsKCiAgR2VzdHVyZXMucmVnaXN0ZXIoewogICAgbmFtZTogJ3RyYWNrJywKICAgIHRvdWNoQWN0aW9uOiAnbm9uZScsCiAgICBkZXBzOiBbJ21vdXNlZG93bicsICd0b3VjaHN0YXJ0JywgJ3RvdWNobW92ZScsICd0b3VjaGVuZCddLAogICAgZmxvdzogewogICAgICBzdGFydDogWydtb3VzZWRvd24nLCAndG91Y2hzdGFydCddLAogICAgICBlbmQ6IFsnbW91c2V1cCcsICd0b3VjaGVuZCddCiAgICB9LAogICAgZW1pdHM6IFsndHJhY2snXSwKCiAgICBpbmZvOiB7CiAgICAgIHg6IDAsCiAgICAgIHk6IDAsCiAgICAgIHN0YXRlOiAnc3RhcnQnLAogICAgICBzdGFydGVkOiBmYWxzZSwKICAgICAgbW92ZXM6IFtdLAogICAgICAvKiogQHRoaXMge0dlc3R1cmVSZWNvZ25pemVyfSAqLwogICAgICBhZGRNb3ZlOiBmdW5jdGlvbihtb3ZlKSB7CiAgICAgICAgaWYgKHRoaXMubW92ZXMubGVuZ3RoID4gVFJBQ0tfTEVOR1RIKSB7CiAgICAgICAgICB0aGlzLm1vdmVzLnNoaWZ0KCk7CiAgICAgICAgfQogICAgICAgIHRoaXMubW92ZXMucHVzaChtb3ZlKTsKICAgICAgfSwKICAgICAgbW92ZWZuOiBudWxsLAogICAgICB1cGZuOiBudWxsLAogICAgICBwcmV2ZW50OiBmYWxzZQogICAgfSwKCiAgICAvKioKICAgICAqIEB0aGlzIHtHZXN0dXJlUmVjb2duaXplcn0KICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIHJlc2V0OiBmdW5jdGlvbigpIHsKICAgICAgdGhpcy5pbmZvLnN0YXRlID0gJ3N0YXJ0JzsKICAgICAgdGhpcy5pbmZvLnN0YXJ0ZWQgPSBmYWxzZTsKICAgICAgdGhpcy5pbmZvLm1vdmVzID0gW107CiAgICAgIHRoaXMuaW5mby54ID0gMDsKICAgICAgdGhpcy5pbmZvLnkgPSAwOwogICAgICB0aGlzLmluZm8ucHJldmVudCA9IGZhbHNlOwogICAgICB1bnRyYWNrRG9jdW1lbnQodGhpcy5pbmZvKTsKICAgIH0sCgogICAgLyoqCiAgICAgKiBAdGhpcyB7R2VzdHVyZVJlY29nbml6ZXJ9CiAgICAgKiBAcGFyYW0ge251bWJlcn0geAogICAgICogQHBhcmFtIHtudW1iZXJ9IHkKICAgICAqIEByZXR1cm4ge2Jvb2xlYW59CiAgICAgKi8KICAgIGhhc01vdmVkRW5vdWdoOiBmdW5jdGlvbih4LCB5KSB7CiAgICAgIGlmICh0aGlzLmluZm8ucHJldmVudCkgewogICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgfQogICAgICBpZiAodGhpcy5pbmZvLnN0YXJ0ZWQpIHsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfQogICAgICBsZXQgZHggPSBNYXRoLmFicyh0aGlzLmluZm8ueCAtIHgpOwogICAgICBsZXQgZHkgPSBNYXRoLmFicyh0aGlzLmluZm8ueSAtIHkpOwogICAgICByZXR1cm4gKGR4ID49IFRSQUNLX0RJU1RBTkNFIHx8IGR5ID49IFRSQUNLX0RJU1RBTkNFKTsKICAgIH0sCiAgICAvKioKICAgICAqIEB0aGlzIHtHZXN0dXJlUmVjb2duaXplcn0KICAgICAqIEBwYXJhbSB7TW91c2VFdmVudH0gZQogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgbW91c2Vkb3duOiBmdW5jdGlvbihlKSB7CiAgICAgIGlmICghaGFzTGVmdE1vdXNlQnV0dG9uKGUpKSB7CiAgICAgICAgcmV0dXJuOwogICAgICB9CiAgICAgIGxldCB0ID0gR2VzdHVyZXMuX2ZpbmRPcmlnaW5hbFRhcmdldChlKTsKICAgICAgbGV0IHNlbGYgPSB0aGlzOwogICAgICBsZXQgbW92ZWZuID0gZnVuY3Rpb24gbW92ZWZuKGUpIHsKICAgICAgICBsZXQgeCA9IGUuY2xpZW50WCwgeSA9IGUuY2xpZW50WTsKICAgICAgICBpZiAoc2VsZi5oYXNNb3ZlZEVub3VnaCh4LCB5KSkgewogICAgICAgICAgLy8gZmlyc3QgbW92ZSBpcyAnc3RhcnQnLCBzdWJzZXF1ZW50IG1vdmVzIGFyZSAnbW92ZScsIG1vdXNldXAgaXMgJ2VuZCcKICAgICAgICAgIHNlbGYuaW5mby5zdGF0ZSA9IHNlbGYuaW5mby5zdGFydGVkID8gKGUudHlwZSA9PT0gJ21vdXNldXAnID8gJ2VuZCcgOiAndHJhY2snKSA6ICdzdGFydCc7CiAgICAgICAgICBpZiAoc2VsZi5pbmZvLnN0YXRlID09PSAnc3RhcnQnKSB7CiAgICAgICAgICAgIC8vIGlmIGFuZCBvbmx5IGlmIHRyYWNraW5nLCBhbHdheXMgcHJldmVudCB0YXAKICAgICAgICAgICAgR2VzdHVyZXMucHJldmVudCgndGFwJyk7CiAgICAgICAgICB9CiAgICAgICAgICBzZWxmLmluZm8uYWRkTW92ZSh7eDogeCwgeTogeX0pOwogICAgICAgICAgaWYgKCFoYXNMZWZ0TW91c2VCdXR0b24oZSkpIHsKICAgICAgICAgICAgLy8gYWx3YXlzIF9maXJlICJlbmQiCiAgICAgICAgICAgIHNlbGYuaW5mby5zdGF0ZSA9ICdlbmQnOwogICAgICAgICAgICB1bnRyYWNrRG9jdW1lbnQoc2VsZi5pbmZvKTsKICAgICAgICAgIH0KICAgICAgICAgIHNlbGYuX2ZpcmUodCwgZSk7CiAgICAgICAgICBzZWxmLmluZm8uc3RhcnRlZCA9IHRydWU7CiAgICAgICAgfQogICAgICB9OwogICAgICBsZXQgdXBmbiA9IGZ1bmN0aW9uIHVwZm4oZSkgewogICAgICAgIGlmIChzZWxmLmluZm8uc3RhcnRlZCkgewogICAgICAgICAgbW92ZWZuKGUpOwogICAgICAgIH0KCiAgICAgICAgLy8gcmVtb3ZlIHRoZSB0ZW1wb3JhcnkgbGlzdGVuZXJzCiAgICAgICAgdW50cmFja0RvY3VtZW50KHNlbGYuaW5mbyk7CiAgICAgIH07CiAgICAgIC8vIGFkZCB0ZW1wb3JhcnkgZG9jdW1lbnQgbGlzdGVuZXJzIGFzIG1vdXNlIHJldGFyZ2V0cwogICAgICB0cmFja0RvY3VtZW50KHRoaXMuaW5mbywgbW92ZWZuLCB1cGZuKTsKICAgICAgdGhpcy5pbmZvLnggPSBlLmNsaWVudFg7CiAgICAgIHRoaXMuaW5mby55ID0gZS5jbGllbnRZOwogICAgfSwKICAgIC8qKgogICAgICogQHRoaXMge0dlc3R1cmVSZWNvZ25pemVyfQogICAgICogQHBhcmFtIHtUb3VjaEV2ZW50fSBlCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICB0b3VjaHN0YXJ0OiBmdW5jdGlvbihlKSB7CiAgICAgIGxldCBjdCA9IGUuY2hhbmdlZFRvdWNoZXNbMF07CiAgICAgIHRoaXMuaW5mby54ID0gY3QuY2xpZW50WDsKICAgICAgdGhpcy5pbmZvLnkgPSBjdC5jbGllbnRZOwogICAgfSwKICAgIC8qKgogICAgICogQHRoaXMge0dlc3R1cmVSZWNvZ25pemVyfQogICAgICogQHBhcmFtIHtUb3VjaEV2ZW50fSBlCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICB0b3VjaG1vdmU6IGZ1bmN0aW9uKGUpIHsKICAgICAgbGV0IHQgPSBHZXN0dXJlcy5fZmluZE9yaWdpbmFsVGFyZ2V0KGUpOwogICAgICBsZXQgY3QgPSBlLmNoYW5nZWRUb3VjaGVzWzBdOwogICAgICBsZXQgeCA9IGN0LmNsaWVudFgsIHkgPSBjdC5jbGllbnRZOwogICAgICBpZiAodGhpcy5oYXNNb3ZlZEVub3VnaCh4LCB5KSkgewogICAgICAgIGlmICh0aGlzLmluZm8uc3RhdGUgPT09ICdzdGFydCcpIHsKICAgICAgICAgIC8vIGlmIGFuZCBvbmx5IGlmIHRyYWNraW5nLCBhbHdheXMgcHJldmVudCB0YXAKICAgICAgICAgIEdlc3R1cmVzLnByZXZlbnQoJ3RhcCcpOwogICAgICAgIH0KICAgICAgICB0aGlzLmluZm8uYWRkTW92ZSh7eDogeCwgeTogeX0pOwogICAgICAgIHRoaXMuX2ZpcmUodCwgY3QpOwogICAgICAgIHRoaXMuaW5mby5zdGF0ZSA9ICd0cmFjayc7CiAgICAgICAgdGhpcy5pbmZvLnN0YXJ0ZWQgPSB0cnVlOwogICAgICB9CiAgICB9LAogICAgLyoqCiAgICAgKiBAdGhpcyB7R2VzdHVyZVJlY29nbml6ZXJ9CiAgICAgKiBAcGFyYW0ge1RvdWNoRXZlbnR9IGUKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIHRvdWNoZW5kOiBmdW5jdGlvbihlKSB7CiAgICAgIGxldCB0ID0gR2VzdHVyZXMuX2ZpbmRPcmlnaW5hbFRhcmdldChlKTsKICAgICAgbGV0IGN0ID0gZS5jaGFuZ2VkVG91Y2hlc1swXTsKICAgICAgLy8gb25seSB0cmFja2VuZCBpZiB0cmFjayB3YXMgc3RhcnRlZCBhbmQgbm90IGFib3J0ZWQKICAgICAgaWYgKHRoaXMuaW5mby5zdGFydGVkKSB7CiAgICAgICAgLy8gcmVzZXQgc3RhcnRlZCBzdGF0ZSBvbiB1cAogICAgICAgIHRoaXMuaW5mby5zdGF0ZSA9ICdlbmQnOwogICAgICAgIHRoaXMuaW5mby5hZGRNb3ZlKHt4OiBjdC5jbGllbnRYLCB5OiBjdC5jbGllbnRZfSk7CiAgICAgICAgdGhpcy5fZmlyZSh0LCBjdCwgZSk7CiAgICAgIH0KICAgIH0sCgogICAgLyoqCiAgICAgKiBAdGhpcyB7R2VzdHVyZVJlY29nbml6ZXJ9CiAgICAgKiBAcGFyYW0geyFFdmVudFRhcmdldH0gdGFyZ2V0CiAgICAgKiBAcGFyYW0ge1RvdWNofSB0b3VjaAogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgX2ZpcmU6IGZ1bmN0aW9uKHRhcmdldCwgdG91Y2gpIHsKICAgICAgbGV0IHNlY29uZGxhc3QgPSB0aGlzLmluZm8ubW92ZXNbdGhpcy5pbmZvLm1vdmVzLmxlbmd0aCAtIDJdOwogICAgICBsZXQgbGFzdG1vdmUgPSB0aGlzLmluZm8ubW92ZXNbdGhpcy5pbmZvLm1vdmVzLmxlbmd0aCAtIDFdOwogICAgICBsZXQgZHggPSBsYXN0bW92ZS54IC0gdGhpcy5pbmZvLng7CiAgICAgIGxldCBkeSA9IGxhc3Rtb3ZlLnkgLSB0aGlzLmluZm8ueTsKICAgICAgbGV0IGRkeCwgZGR5ID0gMDsKICAgICAgaWYgKHNlY29uZGxhc3QpIHsKICAgICAgICBkZHggPSBsYXN0bW92ZS54IC0gc2Vjb25kbGFzdC54OwogICAgICAgIGRkeSA9IGxhc3Rtb3ZlLnkgLSBzZWNvbmRsYXN0Lnk7CiAgICAgIH0KICAgICAgR2VzdHVyZXMuX2ZpcmUodGFyZ2V0LCAndHJhY2snLCB7CiAgICAgICAgc3RhdGU6IHRoaXMuaW5mby5zdGF0ZSwKICAgICAgICB4OiB0b3VjaC5jbGllbnRYLAogICAgICAgIHk6IHRvdWNoLmNsaWVudFksCiAgICAgICAgZHg6IGR4LAogICAgICAgIGR5OiBkeSwKICAgICAgICBkZHg6IGRkeCwKICAgICAgICBkZHk6IGRkeSwKICAgICAgICBzb3VyY2VFdmVudDogdG91Y2gsCiAgICAgICAgaG92ZXI6IGZ1bmN0aW9uKCkgewogICAgICAgICAgcmV0dXJuIEdlc3R1cmVzLmRlZXBUYXJnZXRGaW5kKHRvdWNoLmNsaWVudFgsIHRvdWNoLmNsaWVudFkpOwogICAgICAgIH0KICAgICAgfSk7CiAgICB9CgogIH0pOwoKICBHZXN0dXJlcy5yZWdpc3Rlcih7CiAgICBuYW1lOiAndGFwJywKICAgIGRlcHM6IFsnbW91c2Vkb3duJywgJ2NsaWNrJywgJ3RvdWNoc3RhcnQnLCAndG91Y2hlbmQnXSwKICAgIGZsb3c6IHsKICAgICAgc3RhcnQ6IFsnbW91c2Vkb3duJywgJ3RvdWNoc3RhcnQnXSwKICAgICAgZW5kOiBbJ2NsaWNrJywgJ3RvdWNoZW5kJ10KICAgIH0sCiAgICBlbWl0czogWyd0YXAnXSwKICAgIGluZm86IHsKICAgICAgeDogTmFOLAogICAgICB5OiBOYU4sCiAgICAgIHByZXZlbnQ6IGZhbHNlCiAgICB9LAogICAgLyoqCiAgICAgKiBAdGhpcyB7R2VzdHVyZVJlY29nbml6ZXJ9CiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICByZXNldDogZnVuY3Rpb24oKSB7CiAgICAgIHRoaXMuaW5mby54ID0gTmFOOwogICAgICB0aGlzLmluZm8ueSA9IE5hTjsKICAgICAgdGhpcy5pbmZvLnByZXZlbnQgPSBmYWxzZTsKICAgIH0sCiAgICAvKioKICAgICAqIEB0aGlzIHtHZXN0dXJlUmVjb2duaXplcn0KICAgICAqIEBwYXJhbSB7TW91c2VFdmVudH0gZQogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgc2F2ZTogZnVuY3Rpb24oZSkgewogICAgICB0aGlzLmluZm8ueCA9IGUuY2xpZW50WDsKICAgICAgdGhpcy5pbmZvLnkgPSBlLmNsaWVudFk7CiAgICB9LAogICAgLyoqCiAgICAgKiBAdGhpcyB7R2VzdHVyZVJlY29nbml6ZXJ9CiAgICAgKiBAcGFyYW0ge01vdXNlRXZlbnR9IGUKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIG1vdXNlZG93bjogZnVuY3Rpb24oZSkgewogICAgICBpZiAoaGFzTGVmdE1vdXNlQnV0dG9uKGUpKSB7CiAgICAgICAgdGhpcy5zYXZlKGUpOwogICAgICB9CiAgICB9LAogICAgLyoqCiAgICAgKiBAdGhpcyB7R2VzdHVyZVJlY29nbml6ZXJ9CiAgICAgKiBAcGFyYW0ge01vdXNlRXZlbnR9IGUKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIGNsaWNrOiBmdW5jdGlvbihlKSB7CiAgICAgIGlmIChoYXNMZWZ0TW91c2VCdXR0b24oZSkpIHsKICAgICAgICB0aGlzLmZvcndhcmQoZSk7CiAgICAgIH0KICAgIH0sCiAgICAvKioKICAgICAqIEB0aGlzIHtHZXN0dXJlUmVjb2duaXplcn0KICAgICAqIEBwYXJhbSB7VG91Y2hFdmVudH0gZQogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgdG91Y2hzdGFydDogZnVuY3Rpb24oZSkgewogICAgICB0aGlzLnNhdmUoZS5jaGFuZ2VkVG91Y2hlc1swXSwgZSk7CiAgICB9LAogICAgLyoqCiAgICAgKiBAdGhpcyB7R2VzdHVyZVJlY29nbml6ZXJ9CiAgICAgKiBAcGFyYW0ge1RvdWNoRXZlbnR9IGUKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIHRvdWNoZW5kOiBmdW5jdGlvbihlKSB7CiAgICAgIHRoaXMuZm9yd2FyZChlLmNoYW5nZWRUb3VjaGVzWzBdLCBlKTsKICAgIH0sCiAgICAvKioKICAgICAqIEB0aGlzIHtHZXN0dXJlUmVjb2duaXplcn0KICAgICAqIEBwYXJhbSB7RXZlbnQgfCBUb3VjaH0gZQogICAgICogQHBhcmFtIHtFdmVudD19IHByZXZlbnRlcgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgZm9yd2FyZDogZnVuY3Rpb24oZSwgcHJldmVudGVyKSB7CiAgICAgIGxldCBkeCA9IE1hdGguYWJzKGUuY2xpZW50WCAtIHRoaXMuaW5mby54KTsKICAgICAgbGV0IGR5ID0gTWF0aC5hYnMoZS5jbGllbnRZIC0gdGhpcy5pbmZvLnkpOwogICAgICAvLyBmaW5kIG9yaWdpbmFsIHRhcmdldCBmcm9tIGBwcmV2ZW50ZXJgIGZvciBUb3VjaEV2ZW50cywgb3IgYGVgIGZvciBNb3VzZUV2ZW50cwogICAgICBsZXQgdCA9IEdlc3R1cmVzLl9maW5kT3JpZ2luYWxUYXJnZXQoLyoqIEB0eXBlIHtFdmVudH0gKi8ocHJldmVudGVyIHx8IGUpKTsKICAgICAgaWYgKCF0IHx8IChjYW5CZURpc2FibGVkWy8qKiBAdHlwZSB7IUhUTUxFbGVtZW50fSAqLyh0KS5sb2NhbE5hbWVdICYmIHQuaGFzQXR0cmlidXRlKCdkaXNhYmxlZCcpKSkgewogICAgICAgIHJldHVybjsKICAgICAgfQogICAgICAvLyBkeCxkeSBjYW4gYmUgTmFOIGlmIGBjbGlja2AgaGFzIGJlZW4gc2ltdWxhdGVkIGFuZCB0aGVyZSB3YXMgbm8gYGRvd25gIGZvciBgc3RhcnRgCiAgICAgIGlmIChpc05hTihkeCkgfHwgaXNOYU4oZHkpIHx8IChkeCA8PSBUQVBfRElTVEFOQ0UgJiYgZHkgPD0gVEFQX0RJU1RBTkNFKSB8fCBpc1N5bnRoZXRpY0NsaWNrKGUpKSB7CiAgICAgICAgLy8gcHJldmVudCB0YXBzIGZyb20gYmVpbmcgZ2VuZXJhdGVkIGlmIGFuIGV2ZW50IGhhcyBjYW5jZWxlZCB0aGVtCiAgICAgICAgaWYgKCF0aGlzLmluZm8ucHJldmVudCkgewogICAgICAgICAgR2VzdHVyZXMuX2ZpcmUodCwgJ3RhcCcsIHsKICAgICAgICAgICAgeDogZS5jbGllbnRYLAogICAgICAgICAgICB5OiBlLmNsaWVudFksCiAgICAgICAgICAgIHNvdXJjZUV2ZW50OiBlLAogICAgICAgICAgICBwcmV2ZW50ZXI6IHByZXZlbnRlcgogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfSk7CgogIC8qIGVzbGludC1lbmFibGUgdmFsaWQtanNkb2MgKi8KCiAgLyoqIEBkZXByZWNhdGVkICovCiAgR2VzdHVyZXMuZmluZE9yaWdpbmFsVGFyZ2V0ID0gR2VzdHVyZXMuX2ZpbmRPcmlnaW5hbFRhcmdldDsKCiAgLyoqIEBkZXByZWNhdGVkICovCiAgR2VzdHVyZXMuYWRkID0gR2VzdHVyZXMuYWRkTGlzdGVuZXI7CgogIC8qKiBAZGVwcmVjYXRlZCAqLwogIEdlc3R1cmVzLnJlbW92ZSA9IEdlc3R1cmVzLnJlbW92ZUxpc3RlbmVyOwoKICBQb2x5bWVyLkdlc3R1cmVzID0gR2VzdHVyZXM7Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CgogICd1c2Ugc3RyaWN0JzsKCiAgLyoqCiAgICogQGNvbnN0IHtQb2x5bWVyLkdlc3R1cmVzfQogICAqLwogIGNvbnN0IGdlc3R1cmVzID0gUG9seW1lci5HZXN0dXJlczsKCiAgLyoqCiAgICogRWxlbWVudCBjbGFzcyBtaXhpbiB0aGF0IHByb3ZpZGVzIEFQSSBmb3IgYWRkaW5nIFBvbHltZXIncyBjcm9zcy1wbGF0Zm9ybQogICAqIGdlc3R1cmUgZXZlbnRzIHRvIG5vZGVzLgogICAqCiAgICogVGhlIEFQSSBpcyBkZXNpZ25lZCB0byBiZSBjb21wYXRpYmxlIHdpdGggb3ZlcnJpZGUgcG9pbnRzIGltcGxlbWVudGVkCiAgICogaW4gYFBvbHltZXIuVGVtcGxhdGVTdGFtcGAgc3VjaCB0aGF0IGRlY2xhcmF0aXZlIGV2ZW50IGxpc3RlbmVycyBpbgogICAqIHRlbXBsYXRlcyB3aWxsIHN1cHBvcnQgZ2VzdHVyZSBldmVudHMgd2hlbiB0aGlzIG1peGluIGlzIGFwcGxpZWQgYWxvbmcgd2l0aAogICAqIGBQb2x5bWVyLlRlbXBsYXRlU3RhbXBgLgogICAqCiAgICogQG1peGluRnVuY3Rpb24KICAgKiBAcG9seW1lcgogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICogQHN1bW1hcnkgRWxlbWVudCBjbGFzcyBtaXhpbiB0aGF0IHByb3ZpZGVzIEFQSSBmb3IgYWRkaW5nIFBvbHltZXIncyBjcm9zcy1wbGF0Zm9ybQogICAqIGdlc3R1cmUgZXZlbnRzIHRvIG5vZGVzCiAgICovCiAgUG9seW1lci5HZXN0dXJlRXZlbnRMaXN0ZW5lcnMgPSBQb2x5bWVyLmRlZHVwaW5nTWl4aW4oc3VwZXJDbGFzcyA9PiB7CgogICAgLyoqCiAgICAgKiBAcG9seW1lcgogICAgICogQG1peGluQ2xhc3MKICAgICAqIEBpbXBsZW1lbnRzIHtQb2x5bWVyX0dlc3R1cmVFdmVudExpc3RlbmVyc30KICAgICAqLwogICAgY2xhc3MgR2VzdHVyZUV2ZW50TGlzdGVuZXJzIGV4dGVuZHMgc3VwZXJDbGFzcyB7CgogICAgICAvKioKICAgICAgICogQWRkIHRoZSBldmVudCBsaXN0ZW5lciB0byB0aGUgbm9kZSBpZiBpdCBpcyBhIGdlc3R1cmVzIGV2ZW50LgogICAgICAgKgogICAgICAgKiBAcGFyYW0geyFOb2RlfSBub2RlIE5vZGUgdG8gYWRkIGV2ZW50IGxpc3RlbmVyIHRvCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWUgTmFtZSBvZiBldmVudAogICAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKCFFdmVudCk6dm9pZH0gaGFuZGxlciBMaXN0ZW5lciBmdW5jdGlvbiB0byBhZGQKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9hZGRFdmVudExpc3RlbmVyVG9Ob2RlKG5vZGUsIGV2ZW50TmFtZSwgaGFuZGxlcikgewogICAgICAgIGlmICghZ2VzdHVyZXMuYWRkTGlzdGVuZXIobm9kZSwgZXZlbnROYW1lLCBoYW5kbGVyKSkgewogICAgICAgICAgc3VwZXIuX2FkZEV2ZW50TGlzdGVuZXJUb05vZGUobm9kZSwgZXZlbnROYW1lLCBoYW5kbGVyKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZW1vdmUgdGhlIGV2ZW50IGxpc3RlbmVyIHRvIHRoZSBub2RlIGlmIGl0IGlzIGEgZ2VzdHVyZXMgZXZlbnQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7IU5vZGV9IG5vZGUgTm9kZSB0byByZW1vdmUgZXZlbnQgbGlzdGVuZXIgZnJvbQogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lIE5hbWUgb2YgZXZlbnQKICAgICAgICogQHBhcmFtIHtmdW5jdGlvbighRXZlbnQpOnZvaWR9IGhhbmRsZXIgTGlzdGVuZXIgZnVuY3Rpb24gdG8gcmVtb3ZlCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBfcmVtb3ZlRXZlbnRMaXN0ZW5lckZyb21Ob2RlKG5vZGUsIGV2ZW50TmFtZSwgaGFuZGxlcikgewogICAgICAgIGlmICghZ2VzdHVyZXMucmVtb3ZlTGlzdGVuZXIobm9kZSwgZXZlbnROYW1lLCBoYW5kbGVyKSkgewogICAgICAgICAgc3VwZXIuX3JlbW92ZUV2ZW50TGlzdGVuZXJGcm9tTm9kZShub2RlLCBldmVudE5hbWUsIGhhbmRsZXIpOwogICAgICAgIH0KICAgICAgfQoKICAgIH0KCiAgICByZXR1cm4gR2VzdHVyZUV2ZW50TGlzdGVuZXJzOwoKICB9KTsKCn0pKCk7Cjwvc2NyaXB0PjxzY3JpcHQ+CiAgKGZ1bmN0aW9uKCkgewogICAgJ3VzZSBzdHJpY3QnOwoKICAgIGNvbnN0IEhPU1RfRElSID0gLzpob3N0XCg6ZGlyXCgobHRyfHJ0bClcKVwpL2c7CiAgICBjb25zdCBIT1NUX0RJUl9SRVBMQUNNRU5UID0gJzpob3N0KFtkaXI9IiQxIl0pJzsKCiAgICBjb25zdCBFTF9ESVIgPSAvKFtcc1x3LSNcLlxbXF1cKl0qKTpkaXJcKChsdHJ8cnRsKVwpL2c7CiAgICBjb25zdCBFTF9ESVJfUkVQTEFDTUVOVCA9ICc6aG9zdChbZGlyPSIkMiJdKSAkMSc7CgogICAgY29uc3QgRElSX0NIRUNLID0gLzpkaXJcKCg/Omx0cnxydGwpXCkvOwogICAgCiAgICBjb25zdCBTSElNX1NIQURPVyA9IEJvb2xlYW4od2luZG93WydTaGFkeURPTSddICYmIHdpbmRvd1snU2hhZHlET00nXVsnaW5Vc2UnXSk7CgogICAgLyoqCiAgICAgKiBAdHlwZSB7IUFycmF5PCFQb2x5bWVyX0Rpck1peGluPn0KICAgICAqLwogICAgY29uc3QgRElSX0lOU1RBTkNFUyA9IFtdOwoKICAgIC8qKiBAdHlwZSB7TXV0YXRpb25PYnNlcnZlcn0gKi8KICAgIGxldCBvYnNlcnZlciA9IG51bGw7CgogICAgbGV0IERPQ1VNRU5UX0RJUiA9ICcnOwoKICAgIGZ1bmN0aW9uIGdldFJUTCgpIHsKICAgICAgRE9DVU1FTlRfRElSID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmdldEF0dHJpYnV0ZSgnZGlyJyk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAcGFyYW0geyFQb2x5bWVyX0Rpck1peGlufSBpbnN0YW5jZSBJbnN0YW5jZSB0byBzZXQgUlRMIHN0YXR1cyBvbgogICAgICovCiAgICBmdW5jdGlvbiBzZXRSVEwoaW5zdGFuY2UpIHsKICAgICAgaWYgKCFpbnN0YW5jZS5fX2F1dG9EaXJPcHRPdXQpIHsKICAgICAgICBjb25zdCBlbCA9IC8qKiBAdHlwZSB7IUhUTUxFbGVtZW50fSAqLyhpbnN0YW5jZSk7CiAgICAgICAgZWwuc2V0QXR0cmlidXRlKCdkaXInLCBET0NVTUVOVF9ESVIpOwogICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gdXBkYXRlRGlyZWN0aW9uKCkgewogICAgICBnZXRSVEwoKTsKICAgICAgRE9DVU1FTlRfRElSID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmdldEF0dHJpYnV0ZSgnZGlyJyk7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgRElSX0lOU1RBTkNFUy5sZW5ndGg7IGkrKykgewogICAgICAgIHNldFJUTChESVJfSU5TVEFOQ0VTW2ldKTsKICAgICAgfQogICAgfQoKICAgIGZ1bmN0aW9uIHRha2VSZWNvcmRzKCkgewogICAgICBpZiAob2JzZXJ2ZXIgJiYgb2JzZXJ2ZXIudGFrZVJlY29yZHMoKS5sZW5ndGgpIHsKICAgICAgICB1cGRhdGVEaXJlY3Rpb24oKTsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogRWxlbWVudCBjbGFzcyBtaXhpbiB0aGF0IGFsbG93cyBlbGVtZW50cyB0byB1c2UgdGhlIGA6ZGlyYCBDU1MgU2VsZWN0b3IgdG8gaGF2ZQogICAgICogdGV4dCBkaXJlY3Rpb24gc3BlY2lmaWMgc3R5bGluZy4KICAgICAqCiAgICAgKiBXaXRoIHRoaXMgbWl4aW4sIGFueSBzdHlsZXNoZWV0IHByb3ZpZGVkIGluIHRoZSB0ZW1wbGF0ZSB3aWxsIHRyYW5zZm9ybSBgOmRpcmAgaW50bwogICAgICogYDpob3N0KFtkaXJdKWAgYW5kIHN5bmMgZGlyZWN0aW9uIHdpdGggdGhlIHBhZ2UgdmlhIHRoZSBlbGVtZW50J3MgYGRpcmAgYXR0cmlidXRlLgogICAgICoKICAgICAqIEVsZW1lbnRzIGNhbiBvcHQgb3V0IG9mIHRoZSBnbG9iYWwgcGFnZSB0ZXh0IGRpcmVjdGlvbiBieSBzZXR0aW5nIHRoZSBgZGlyYCBhdHRyaWJ1dGUKICAgICAqIGRpcmVjdGx5IGluIGByZWFkeSgpYCBvciBpbiBIVE1MLgogICAgICoKICAgICAqIENhdmVhdHM6CiAgICAgKiAtIEFwcGxpY2F0aW9ucyBtdXN0IHNldCBgPGh0bWwgZGlyPSJsdHIiPmAgb3IgYDxodG1sIGRpcj0icnRsIj5gIHRvIHN5bmMgZGlyZWN0aW9uCiAgICAgKiAtIEF1dG9tYXRpYyBsZWZ0LXRvLXJpZ2h0IG9yIHJpZ2h0LXRvLWxlZnQgc3R5bGluZyBpcyBzeW5jJ2Qgd2l0aCB0aGUgYDxodG1sPmAgZWxlbWVudCBvbmx5LgogICAgICogLSBDaGFuZ2luZyBgZGlyYCBhdCBydW50aW1lIGlzIHN1cHBvcnRlZC4KICAgICAqIC0gT3B0aW5nIG91dCBvZiB0aGUgZ2xvYmFsIGRpcmVjdGlvbiBzdHlsaW5nIGlzIHBlcm1hbmVudAogICAgICoKICAgICAqIEBtaXhpbkZ1bmN0aW9uCiAgICAgKiBAcG9seW1lcgogICAgICogQGFwcGxpZXNNaXhpbiBQb2x5bWVyLlByb3BlcnR5QWNjZXNzb3JzCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAgICovCiAgICBQb2x5bWVyLkRpck1peGluID0gUG9seW1lci5kZWR1cGluZ01peGluKChiYXNlKSA9PiB7CgogICAgICBpZiAoIVNISU1fU0hBRE9XKSB7CiAgICAgICAgaWYgKCFvYnNlcnZlcikgewogICAgICAgICAgZ2V0UlRMKCk7CiAgICAgICAgICBvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKHVwZGF0ZURpcmVjdGlvbik7CiAgICAgICAgICBvYnNlcnZlci5vYnNlcnZlKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCwge2F0dHJpYnV0ZXM6IHRydWUsIGF0dHJpYnV0ZUZpbHRlcjogWydkaXInXX0pOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEBjb25zdHJ1Y3RvcgogICAgICAgKiBAZXh0ZW5kcyB7YmFzZX0KICAgICAgICogQGltcGxlbWVudHMge1BvbHltZXJfUHJvcGVydHlBY2Nlc3NvcnN9CiAgICAgICAqIEBwcml2YXRlCiAgICAgICAqLwogICAgICBjb25zdCBlbGVtZW50QmFzZSA9IFBvbHltZXIuUHJvcGVydHlBY2Nlc3NvcnMoYmFzZSk7CgogICAgICAvKioKICAgICAgICogQHBvbHltZXIKICAgICAgICogQG1peGluQ2xhc3MKICAgICAgICogQGltcGxlbWVudHMge1BvbHltZXJfRGlyTWl4aW59CiAgICAgICAqLwogICAgICBjbGFzcyBEaXIgZXh0ZW5kcyBlbGVtZW50QmFzZSB7CgogICAgICAgIC8qKgogICAgICAgICAqIEBvdmVycmlkZQogICAgICAgICAqIEBzdXBwcmVzcyB7bWlzc2luZ1Byb3BlcnRpZXN9IEludGVyZmFjZXMgaW4gY2xvc3VyZSBkbyBub3QgaW5oZXJpdCBzdGF0aWNzLCBidXQgY2xhc3NlcyBkbwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBfcHJvY2Vzc1N0eWxlVGV4dChjc3NUZXh0LCBiYXNlVVJJKSB7CiAgICAgICAgICBjc3NUZXh0ID0gc3VwZXIuX3Byb2Nlc3NTdHlsZVRleHQoY3NzVGV4dCwgYmFzZVVSSSk7CiAgICAgICAgICBpZiAoIVNISU1fU0hBRE9XICYmIERJUl9DSEVDSy50ZXN0KGNzc1RleHQpKSB7CiAgICAgICAgICAgIGNzc1RleHQgPSB0aGlzLl9yZXBsYWNlRGlySW5Dc3NUZXh0KGNzc1RleHQpOwogICAgICAgICAgICB0aGlzLl9fYWN0aXZhdGVEaXIgPSB0cnVlOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGNzc1RleHQ7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBSZXBsYWNlIGA6ZGlyYCBpbiB0aGUgZ2l2ZW4gQ1NTIHRleHQKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IENTUyB0ZXh0IHRvIHJlcGxhY2UgRElSCiAgICAgICAgICogQHJldHVybiB7c3RyaW5nfSBNb2RpZmllZCBDU1MKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgX3JlcGxhY2VEaXJJbkNzc1RleHQodGV4dCkgewogICAgICAgICAgbGV0IHJlcGxhY2VkVGV4dCA9IHRleHQ7CiAgICAgICAgICByZXBsYWNlZFRleHQgPSByZXBsYWNlZFRleHQucmVwbGFjZShIT1NUX0RJUiwgSE9TVF9ESVJfUkVQTEFDTUVOVCk7CiAgICAgICAgICByZXBsYWNlZFRleHQgPSByZXBsYWNlZFRleHQucmVwbGFjZShFTF9ESVIsIEVMX0RJUl9SRVBMQUNNRU5UKTsKICAgICAgICAgIHJldHVybiByZXBsYWNlZFRleHQ7CiAgICAgICAgfQoKICAgICAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICAgIHN1cGVyKCk7CiAgICAgICAgICAvKiogQHR5cGUge2Jvb2xlYW59ICovCiAgICAgICAgICB0aGlzLl9fYXV0b0Rpck9wdE91dCA9IGZhbHNlOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQHN1cHByZXNzIHtpbnZhbGlkQ2FzdHN9IENsb3N1cmUgZG9lc24ndCB1bmRlcnN0YW5kIHRoYXQgYHRoaXNgIGlzIGFuIEhUTUxFbGVtZW50CiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKi8KICAgICAgICByZWFkeSgpIHsKICAgICAgICAgIHN1cGVyLnJlYWR5KCk7CiAgICAgICAgICB0aGlzLl9fYXV0b0Rpck9wdE91dCA9IC8qKiBAdHlwZSB7IUhUTUxFbGVtZW50fSAqLyh0aGlzKS5oYXNBdHRyaWJ1dGUoJ2RpcicpOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQHN1cHByZXNzIHttaXNzaW5nUHJvcGVydGllc30gSWYgaXQgZXhpc3RzIG9uIGVsZW1lbnRCYXNlLCBpdCBjYW4gYmUgc3VwZXInZAogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICovCiAgICAgICAgY29ubmVjdGVkQ2FsbGJhY2soKSB7CiAgICAgICAgICBpZiAoZWxlbWVudEJhc2UucHJvdG90eXBlLmNvbm5lY3RlZENhbGxiYWNrKSB7CiAgICAgICAgICAgIHN1cGVyLmNvbm5lY3RlZENhbGxiYWNrKCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodGhpcy5jb25zdHJ1Y3Rvci5fX2FjdGl2YXRlRGlyKSB7CiAgICAgICAgICAgIHRha2VSZWNvcmRzKCk7CiAgICAgICAgICAgIERJUl9JTlNUQU5DRVMucHVzaCh0aGlzKTsKICAgICAgICAgICAgc2V0UlRMKHRoaXMpOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQHN1cHByZXNzIHttaXNzaW5nUHJvcGVydGllc30gSWYgaXQgZXhpc3RzIG9uIGVsZW1lbnRCYXNlLCBpdCBjYW4gYmUgc3VwZXInZAogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICovCiAgICAgICAgZGlzY29ubmVjdGVkQ2FsbGJhY2soKSB7CiAgICAgICAgICBpZiAoZWxlbWVudEJhc2UucHJvdG90eXBlLmRpc2Nvbm5lY3RlZENhbGxiYWNrKSB7CiAgICAgICAgICAgIHN1cGVyLmRpc2Nvbm5lY3RlZENhbGxiYWNrKCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodGhpcy5jb25zdHJ1Y3Rvci5fX2FjdGl2YXRlRGlyKSB7CiAgICAgICAgICAgIGNvbnN0IGlkeCA9IERJUl9JTlNUQU5DRVMuaW5kZXhPZih0aGlzKTsKICAgICAgICAgICAgaWYgKGlkeCA+IC0xKSB7CiAgICAgICAgICAgICAgRElSX0lOU1RBTkNFUy5zcGxpY2UoaWR4LCAxKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQoKICAgICAgRGlyLl9fYWN0aXZhdGVEaXIgPSBmYWxzZTsKCiAgICAgIHJldHVybiBEaXI7CiAgICB9KTsKICB9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgoKKGZ1bmN0aW9uKCkgewoKICAndXNlIHN0cmljdCc7CgogIC8vIHJ1biBhIGNhbGxiYWNrIHdoZW4gSFRNTEltcG9ydHMgYXJlIHJlYWR5IG9yIGltbWVkaWF0ZWx5IGlmCiAgLy8gdGhpcyBhcGkgaXMgbm90IGF2YWlsYWJsZS4KICBmdW5jdGlvbiB3aGVuSW1wb3J0c1JlYWR5KGNiKSB7CiAgICBpZiAod2luZG93LkhUTUxJbXBvcnRzKSB7CiAgICAgIEhUTUxJbXBvcnRzLndoZW5SZWFkeShjYik7CiAgICB9IGVsc2UgewogICAgICBjYigpOwogICAgfQogIH0KCiAgLyoqCiAgICogQ29udmVuaWVuY2UgbWV0aG9kIGZvciBpbXBvcnRpbmcgYW4gSFRNTCBkb2N1bWVudCBpbXBlcmF0aXZlbHkuCiAgICoKICAgKiBUaGlzIG1ldGhvZCBjcmVhdGVzIGEgbmV3IGA8bGluayByZWw9ImltcG9ydCI+YCBlbGVtZW50IHdpdGgKICAgKiB0aGUgcHJvdmlkZWQgVVJMIGFuZCBhcHBlbmRzIGl0IHRvIHRoZSBkb2N1bWVudCB0byBzdGFydCBsb2FkaW5nLgogICAqIEluIHRoZSBgb25sb2FkYCBjYWxsYmFjaywgdGhlIGBpbXBvcnRgIHByb3BlcnR5IG9mIHRoZSBgbGlua2AKICAgKiBlbGVtZW50IHdpbGwgY29udGFpbiB0aGUgaW1wb3J0ZWQgZG9jdW1lbnQgY29udGVudHMuCiAgICoKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBwYXJhbSB7c3RyaW5nfSBocmVmIFVSTCB0byBkb2N1bWVudCB0byBsb2FkLgogICAqIEBwYXJhbSB7P2Z1bmN0aW9uKCFFdmVudCk6dm9pZD19IG9ubG9hZCBDYWxsYmFjayB0byBub3RpZnkgd2hlbiBhbiBpbXBvcnQgc3VjY2Vzc2Z1bGx5CiAgICogICBsb2FkZWQuCiAgICogQHBhcmFtIHs/ZnVuY3Rpb24oIUVycm9yRXZlbnQpOnZvaWQ9fSBvbmVycm9yIENhbGxiYWNrIHRvIG5vdGlmeSB3aGVuIGFuIGltcG9ydAogICAqICAgdW5zdWNjZXNzZnVsbHkgbG9hZGVkLgogICAqIEBwYXJhbSB7Ym9vbGVhbj19IG9wdEFzeW5jIFRydWUgaWYgdGhlIGltcG9ydCBzaG91bGQgYmUgbG9hZGVkIGBhc3luY2AuCiAgICogICBEZWZhdWx0cyB0byBgZmFsc2VgLgogICAqIEByZXR1cm4geyFIVE1MTGlua0VsZW1lbnR9IFRoZSBsaW5rIGVsZW1lbnQgZm9yIHRoZSBVUkwgdG8gYmUgbG9hZGVkLgogICAqLwogIFBvbHltZXIuaW1wb3J0SHJlZiA9IGZ1bmN0aW9uKGhyZWYsIG9ubG9hZCwgb25lcnJvciwgb3B0QXN5bmMpIHsKICAgIGxldCBsaW5rID0gLyoqIEB0eXBlIHtIVE1MTGlua0VsZW1lbnR9ICovCiAgICAgIChkb2N1bWVudC5oZWFkLnF1ZXJ5U2VsZWN0b3IoJ2xpbmtbaHJlZj0iJyArIGhyZWYgKyAnIl1baW1wb3J0LWhyZWZdJykpOwogICAgaWYgKCFsaW5rKSB7CiAgICAgIGxpbmsgPSAvKiogQHR5cGUge0hUTUxMaW5rRWxlbWVudH0gKi8gKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpbmsnKSk7CiAgICAgIGxpbmsucmVsID0gJ2ltcG9ydCc7CiAgICAgIGxpbmsuaHJlZiA9IGhyZWY7CiAgICAgIGxpbmsuc2V0QXR0cmlidXRlKCdpbXBvcnQtaHJlZicsICcnKTsKICAgIH0KICAgIC8vIGFsd2F5cyBlbnN1cmUgbGluayBoYXMgYGFzeW5jYCBhdHRyaWJ1dGUgaWYgdXNlciBzcGVjaWZpZWQgb25lLAogICAgLy8gZXZlbiBpZiBpdCB3YXMgcHJldmlvdXNseSBub3QgYXN5bmMuIFRoaXMgaXMgY29uc2lkZXJlZCBsZXNzIGNvbmZ1c2luZy4KICAgIGlmIChvcHRBc3luYykgewogICAgICBsaW5rLnNldEF0dHJpYnV0ZSgnYXN5bmMnLCAnJyk7CiAgICB9CiAgICAvLyBOT1RFOiB0aGUgbGluayBtYXkgbm93IGJlIGluIDMgc3RhdGVzOiAoMSkgcGVuZGluZyBpbnNlcnRpb24sCiAgICAvLyAoMikgaW5mbGlnaHQsICgzKSBhbHJlYWR5IGxvYWRlZC4gSW4gZWFjaCBjYXNlLCB3ZSBuZWVkIHRvIGFkZAogICAgLy8gZXZlbnQgbGlzdGVuZXJzIHRvIHByb2Nlc3MgY2FsbGJhY2tzLgogICAgbGV0IGNsZWFudXAgPSBmdW5jdGlvbigpIHsKICAgICAgbGluay5yZW1vdmVFdmVudExpc3RlbmVyKCdsb2FkJywgbG9hZExpc3RlbmVyKTsKICAgICAgbGluay5yZW1vdmVFdmVudExpc3RlbmVyKCdlcnJvcicsIGVycm9yTGlzdGVuZXIpOwogICAgfTsKICAgIGxldCBsb2FkTGlzdGVuZXIgPSBmdW5jdGlvbihldmVudCkgewogICAgICBjbGVhbnVwKCk7CiAgICAgIC8vIEluIGNhc2Ugb2YgYSBzdWNjZXNzZnVsIGxvYWQsIGNhY2hlIHRoZSBsb2FkIGV2ZW50IG9uIHRoZSBsaW5rIHNvCiAgICAgIC8vIHRoYXQgaXQgY2FuIGJlIHVzZWQgdG8gc2hvcnQtY2lyY3VpdCB0aGlzIG1ldGhvZCBpbiB0aGUgZnV0dXJlIHdoZW4KICAgICAgLy8gaXQgaXMgY2FsbGVkIHdpdGggdGhlIHNhbWUgaHJlZiBwYXJhbS4KICAgICAgbGluay5fX2R5bmFtaWNJbXBvcnRMb2FkZWQgPSB0cnVlOwogICAgICBpZiAob25sb2FkKSB7CiAgICAgICAgd2hlbkltcG9ydHNSZWFkeSgoKSA9PiB7CiAgICAgICAgICBvbmxvYWQoZXZlbnQpOwogICAgICAgIH0pOwogICAgICB9CiAgICB9OwogICAgbGV0IGVycm9yTGlzdGVuZXIgPSBmdW5jdGlvbihldmVudCkgewogICAgICBjbGVhbnVwKCk7CiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHJlbW92ZSB0aGUgbGluayBmcm9tIHRoZSBkb2N1bWVudCBzbyB0aGF0IGl0CiAgICAgIC8vIHdpbGwgYmUgYXV0b21hdGljYWxseSBjcmVhdGVkIGFnYWluIHRoZSBuZXh0IHRpbWUgYGltcG9ydEhyZWZgIGlzCiAgICAgIC8vIGNhbGxlZC4KICAgICAgaWYgKGxpbmsucGFyZW50Tm9kZSkgewogICAgICAgIGxpbmsucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChsaW5rKTsKICAgICAgfQogICAgICBpZiAob25lcnJvcikgewogICAgICAgIHdoZW5JbXBvcnRzUmVhZHkoKCkgPT4gewogICAgICAgICAgb25lcnJvcihldmVudCk7CiAgICAgICAgfSk7CiAgICAgIH0KICAgIH07CiAgICBsaW5rLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCBsb2FkTGlzdGVuZXIpOwogICAgbGluay5hZGRFdmVudExpc3RlbmVyKCdlcnJvcicsIGVycm9yTGlzdGVuZXIpOwogICAgaWYgKGxpbmsucGFyZW50Tm9kZSA9PSBudWxsKSB7CiAgICAgIGRvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQobGluayk7CiAgICAvLyBpZiB0aGUgbGluayBhbHJlYWR5IGxvYWRlZCwgZGlzcGF0Y2ggYSBmYWtlIGxvYWQgZXZlbnQKICAgIC8vIHNvIHRoYXQgbGlzdGVuZXJzIGFyZSBjYWxsZWQgYW5kIGdldCBhIHByb3BlciBldmVudCBhcmd1bWVudC4KICAgIH0gZWxzZSBpZiAobGluay5fX2R5bmFtaWNJbXBvcnRMb2FkZWQpIHsKICAgICAgbGluay5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnbG9hZCcpKTsKICAgIH0KICAgIHJldHVybiBsaW5rOwogIH07Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CgogICd1c2Ugc3RyaWN0JzsKCiAgbGV0IHNjaGVkdWxlZCA9IGZhbHNlOwogIGxldCBiZWZvcmVSZW5kZXJRdWV1ZSA9IFtdOwogIGxldCBhZnRlclJlbmRlclF1ZXVlID0gW107CgogIGZ1bmN0aW9uIHNjaGVkdWxlKCkgewogICAgc2NoZWR1bGVkID0gdHJ1ZTsKICAgIC8vIGJlZm9yZSBuZXh0IHJlbmRlcgogICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uKCkgewogICAgICBzY2hlZHVsZWQgPSBmYWxzZTsKICAgICAgZmx1c2hRdWV1ZShiZWZvcmVSZW5kZXJRdWV1ZSk7CiAgICAgIC8vIGFmdGVyIHRoZSByZW5kZXIKICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHsKICAgICAgICBydW5RdWV1ZShhZnRlclJlbmRlclF1ZXVlKTsKICAgICAgfSk7CiAgICB9KTsKICB9CgogIGZ1bmN0aW9uIGZsdXNoUXVldWUocXVldWUpIHsKICAgIHdoaWxlIChxdWV1ZS5sZW5ndGgpIHsKICAgICAgY2FsbE1ldGhvZChxdWV1ZS5zaGlmdCgpKTsKICAgIH0KICB9CgogIGZ1bmN0aW9uIHJ1blF1ZXVlKHF1ZXVlKSB7CiAgICBmb3IgKGxldCBpPTAsIGw9cXVldWUubGVuZ3RoOyBpIDwgbDsgaSsrKSB7CiAgICAgIGNhbGxNZXRob2QocXVldWUuc2hpZnQoKSk7CiAgICB9CiAgfQoKICBmdW5jdGlvbiBjYWxsTWV0aG9kKGluZm8pIHsKICAgIGNvbnN0IGNvbnRleHQgPSBpbmZvWzBdOwogICAgY29uc3QgY2FsbGJhY2sgPSBpbmZvWzFdOwogICAgY29uc3QgYXJncyA9IGluZm9bMl07CiAgICB0cnkgewogICAgICBjYWxsYmFjay5hcHBseShjb250ZXh0LCBhcmdzKTsKICAgIH0gY2F0Y2goZSkgewogICAgICBzZXRUaW1lb3V0KCgpID0+IHsKICAgICAgICB0aHJvdyBlOwogICAgICB9KTsKICAgIH0KICB9CgogIGZ1bmN0aW9uIGZsdXNoKCkgewogICAgd2hpbGUgKGJlZm9yZVJlbmRlclF1ZXVlLmxlbmd0aCB8fCBhZnRlclJlbmRlclF1ZXVlLmxlbmd0aCkgewogICAgICBmbHVzaFF1ZXVlKGJlZm9yZVJlbmRlclF1ZXVlKTsKICAgICAgZmx1c2hRdWV1ZShhZnRlclJlbmRlclF1ZXVlKTsKICAgIH0KICAgIHNjaGVkdWxlZCA9IGZhbHNlOwogIH0KCiAgLyoqCiAgICogTW9kdWxlIGZvciBzY2hlZHVsaW5nIGZsdXNoYWJsZSBwcmUtcmVuZGVyIGFuZCBwb3N0LXJlbmRlciB0YXNrcy4KICAgKgogICAqIEBuYW1lc3BhY2UKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBzdW1tYXJ5IE1vZHVsZSBmb3Igc2NoZWR1bGluZyBmbHVzaGFibGUgcHJlLXJlbmRlciBhbmQgcG9zdC1yZW5kZXIgdGFza3MuCiAgICovCiAgUG9seW1lci5SZW5kZXJTdGF0dXMgPSB7CgogICAgLyoqCiAgICAgKiBFbnF1ZXVlcyBhIGNhbGxiYWNrIHdoaWNoIHdpbGwgYmUgcnVuIGJlZm9yZSB0aGUgbmV4dCByZW5kZXIsIGF0CiAgICAgKiBgcmVxdWVzdEFuaW1hdGlvbkZyYW1lYCB0aW1pbmcuCiAgICAgKgogICAgICogVGhpcyBtZXRob2QgaXMgdXNlZnVsIGZvciBlbnF1ZXVpbmcgd29yayB0aGF0IHJlcXVpcmVzIERPTSBtZWFzdXJlbWVudCwKICAgICAqIHNpbmNlIG1lYXN1cmVtZW50IG1heSBub3QgYmUgcmVsaWFibGUgaW4gY3VzdG9tIGVsZW1lbnQgY2FsbGJhY2tzIGJlZm9yZQogICAgICogdGhlIGZpcnN0IHJlbmRlciwgYXMgd2VsbCBhcyBmb3IgYmF0Y2hpbmcgbWVhc3VyZW1lbnQgdGFza3MgaW4gZ2VuZXJhbC4KICAgICAqCiAgICAgKiBUYXNrcyBpbiB0aGlzIHF1ZXVlIG1heSBiZSBmbHVzaGVkIGJ5IGNhbGxpbmcgYFBvbHltZXIuUmVuZGVyU3RhdHVzLmZsdXNoKClgLgogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlJlbmRlclN0YXR1cwogICAgICogQHBhcmFtIHsqfSBjb250ZXh0IENvbnRleHQgb2JqZWN0IHRoZSBjYWxsYmFjayBmdW5jdGlvbiB3aWxsIGJlIGJvdW5kIHRvCiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKC4uLiopOnZvaWR9IGNhbGxiYWNrIENhbGxiYWNrIGZ1bmN0aW9uCiAgICAgKiBAcGFyYW0geyFBcnJheT19IGFyZ3MgQW4gYXJyYXkgb2YgYXJndW1lbnRzIHRvIGNhbGwgdGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHdpdGgKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIGJlZm9yZU5leHRSZW5kZXI6IGZ1bmN0aW9uKGNvbnRleHQsIGNhbGxiYWNrLCBhcmdzKSB7CiAgICAgIGlmICghc2NoZWR1bGVkKSB7CiAgICAgICAgc2NoZWR1bGUoKTsKICAgICAgfQogICAgICBiZWZvcmVSZW5kZXJRdWV1ZS5wdXNoKFtjb250ZXh0LCBjYWxsYmFjaywgYXJnc10pOwogICAgfSwKCiAgICAvKioKICAgICAqIEVucXVldWVzIGEgY2FsbGJhY2sgd2hpY2ggd2lsbCBiZSBydW4gYWZ0ZXIgdGhlIG5leHQgcmVuZGVyLCBlcXVpdmFsZW50CiAgICAgKiB0byBvbmUgdGFzayAoYHNldFRpbWVvdXRgKSBhZnRlciB0aGUgbmV4dCBgcmVxdWVzdEFuaW1hdGlvbkZyYW1lYC4KICAgICAqCiAgICAgKiBUaGlzIG1ldGhvZCBpcyB1c2VmdWwgZm9yIHR1bmluZyB0aGUgZmlyc3QtcmVuZGVyIHBlcmZvcm1hbmNlIG9mIGFuCiAgICAgKiBlbGVtZW50IG9yIGFwcGxpY2F0aW9uIGJ5IGRlZmVycmluZyBub24tY3JpdGljYWwgd29yayB1bnRpbCBhZnRlciB0aGUKICAgICAqIGZpcnN0IHBhaW50LiAgVHlwaWNhbCBub24tcmVuZGVyLWNyaXRpY2FsIHdvcmsgbWF5IGluY2x1ZGUgYWRkaW5nIFVJCiAgICAgKiBldmVudCBsaXN0ZW5lcnMgYW5kIGFyaWEgYXR0cmlidXRlcy4KICAgICAqCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5SZW5kZXJTdGF0dXMKICAgICAqIEBwYXJhbSB7Kn0gY29udGV4dCBDb250ZXh0IG9iamVjdCB0aGUgY2FsbGJhY2sgZnVuY3Rpb24gd2lsbCBiZSBib3VuZCB0bwogICAgICogQHBhcmFtIHtmdW5jdGlvbiguLi4qKTp2b2lkfSBjYWxsYmFjayBDYWxsYmFjayBmdW5jdGlvbgogICAgICogQHBhcmFtIHshQXJyYXk9fSBhcmdzIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byBjYWxsIHRoZSBjYWxsYmFjayBmdW5jdGlvbiB3aXRoCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBhZnRlck5leHRSZW5kZXI6IGZ1bmN0aW9uKGNvbnRleHQsIGNhbGxiYWNrLCBhcmdzKSB7CiAgICAgIGlmICghc2NoZWR1bGVkKSB7CiAgICAgICAgc2NoZWR1bGUoKTsKICAgICAgfQogICAgICBhZnRlclJlbmRlclF1ZXVlLnB1c2goW2NvbnRleHQsIGNhbGxiYWNrLCBhcmdzXSk7CiAgICB9LAoKICAgIC8qKgogICAgICogRmx1c2hlcyBhbGwgYGJlZm9yZU5leHRSZW5kZXJgIHRhc2tzLCBmb2xsb3dlZCBieSBhbGwgYGFmdGVyTmV4dFJlbmRlcmAKICAgICAqIHRhc2tzLgogICAgICoKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyLlJlbmRlclN0YXR1cwogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgZmx1c2g6IGZsdXNoCgogIH07Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CiAgJ3VzZSBzdHJpY3QnOwoKICAvLyB1bnJlc29sdmVkCgogIGZ1bmN0aW9uIHJlc29sdmUoKSB7CiAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUF0dHJpYnV0ZSgndW5yZXNvbHZlZCcpOwogIH0KCiAgaWYgKHdpbmRvdy5XZWJDb21wb25lbnRzKSB7CiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignV2ViQ29tcG9uZW50c1JlYWR5JywgcmVzb2x2ZSk7CiAgfSBlbHNlIHsKICAgIGlmIChkb2N1bWVudC5yZWFkeVN0YXRlID09PSAnaW50ZXJhY3RpdmUnIHx8IGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICdjb21wbGV0ZScpIHsKICAgICAgcmVzb2x2ZSgpOwogICAgfSBlbHNlIHsKICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCByZXNvbHZlKTsKICAgIH0KICB9Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CgogICd1c2Ugc3RyaWN0JzsKCiAgZnVuY3Rpb24gbmV3U3BsaWNlKGluZGV4LCByZW1vdmVkLCBhZGRlZENvdW50KSB7CiAgICByZXR1cm4gewogICAgICBpbmRleDogaW5kZXgsCiAgICAgIHJlbW92ZWQ6IHJlbW92ZWQsCiAgICAgIGFkZGVkQ291bnQ6IGFkZGVkQ291bnQKICAgIH07CiAgfQoKICBjb25zdCBFRElUX0xFQVZFID0gMDsKICBjb25zdCBFRElUX1VQREFURSA9IDE7CiAgY29uc3QgRURJVF9BREQgPSAyOwogIGNvbnN0IEVESVRfREVMRVRFID0gMzsKCiAgLy8gTm90ZTogVGhpcyBmdW5jdGlvbiBpcyAqYmFzZWQqIG9uIHRoZSBjb21wdXRhdGlvbiBvZiB0aGUgTGV2ZW5zaHRlaW4KICAvLyAiZWRpdCIgZGlzdGFuY2UuIFRoZSBvbmUgY2hhbmdlIGlzIHRoYXQgInVwZGF0ZXMiIGFyZSB0cmVhdGVkIGFzIHR3bwogIC8vIGVkaXRzIC0gbm90IG9uZS4gV2l0aCBBcnJheSBzcGxpY2VzLCBhbiB1cGRhdGUgaXMgcmVhbGx5IGEgZGVsZXRlCiAgLy8gZm9sbG93ZWQgYnkgYW4gYWRkLiBCeSByZXRhaW5pbmcgdGhpcywgd2Ugb3B0aW1pemUgZm9yICJrZWVwaW5nIiB0aGUKICAvLyBtYXhpbXVtIGFycmF5IGl0ZW1zIGluIHRoZSBvcmlnaW5hbCBhcnJheS4gRm9yIGV4YW1wbGU6CiAgLy8KICAvLyAgICd4eHh4MTIzJyAtPiAnMTIzeXl5eScKICAvLwogIC8vIFdpdGggMS1lZGl0IHVwZGF0ZXMsIHRoZSBzaG9ydGVzdCBwYXRoIHdvdWxkIGJlIGp1c3QgdG8gdXBkYXRlIGFsbCBzZXZlbgogIC8vIGNoYXJhY3RlcnMuIFdpdGggMi1lZGl0IHVwZGF0ZXMsIHdlIGRlbGV0ZSA0LCBsZWF2ZSAzLCBhbmQgYWRkIDQuIFRoaXMKICAvLyBsZWF2ZXMgdGhlIHN1YnN0cmluZyAnMTIzJyBpbnRhY3QuCiAgZnVuY3Rpb24gY2FsY0VkaXREaXN0YW5jZXMoY3VycmVudCwgY3VycmVudFN0YXJ0LCBjdXJyZW50RW5kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGQsIG9sZFN0YXJ0LCBvbGRFbmQpIHsKICAgIC8vICJEZWxldGlvbiIgY29sdW1ucwogICAgbGV0IHJvd0NvdW50ID0gb2xkRW5kIC0gb2xkU3RhcnQgKyAxOwogICAgbGV0IGNvbHVtbkNvdW50ID0gY3VycmVudEVuZCAtIGN1cnJlbnRTdGFydCArIDE7CiAgICBsZXQgZGlzdGFuY2VzID0gbmV3IEFycmF5KHJvd0NvdW50KTsKCiAgICAvLyAiQWRkaXRpb24iIHJvd3MuIEluaXRpYWxpemUgbnVsbCBjb2x1bW4uCiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJvd0NvdW50OyBpKyspIHsKICAgICAgZGlzdGFuY2VzW2ldID0gbmV3IEFycmF5KGNvbHVtbkNvdW50KTsKICAgICAgZGlzdGFuY2VzW2ldWzBdID0gaTsKICAgIH0KCiAgICAvLyBJbml0aWFsaXplIG51bGwgcm93CiAgICBmb3IgKGxldCBqID0gMDsgaiA8IGNvbHVtbkNvdW50OyBqKyspCiAgICAgIGRpc3RhbmNlc1swXVtqXSA9IGo7CgogICAgZm9yIChsZXQgaSA9IDE7IGkgPCByb3dDb3VudDsgaSsrKSB7CiAgICAgIGZvciAobGV0IGogPSAxOyBqIDwgY29sdW1uQ291bnQ7IGorKykgewogICAgICAgIGlmIChlcXVhbHMoY3VycmVudFtjdXJyZW50U3RhcnQgKyBqIC0gMV0sIG9sZFtvbGRTdGFydCArIGkgLSAxXSkpCiAgICAgICAgICBkaXN0YW5jZXNbaV1bal0gPSBkaXN0YW5jZXNbaSAtIDFdW2ogLSAxXTsKICAgICAgICBlbHNlIHsKICAgICAgICAgIGxldCBub3J0aCA9IGRpc3RhbmNlc1tpIC0gMV1bal0gKyAxOwogICAgICAgICAgbGV0IHdlc3QgPSBkaXN0YW5jZXNbaV1baiAtIDFdICsgMTsKICAgICAgICAgIGRpc3RhbmNlc1tpXVtqXSA9IG5vcnRoIDwgd2VzdCA/IG5vcnRoIDogd2VzdDsKICAgICAgICB9CiAgICAgIH0KICAgIH0KCiAgICByZXR1cm4gZGlzdGFuY2VzOwogIH0KCiAgLy8gVGhpcyBzdGFydHMgYXQgdGhlIGZpbmFsIHdlaWdodCwgYW5kIHdhbGtzICJiYWNrd2FyZCIgYnkgZmluZGluZwogIC8vIHRoZSBtaW5pbXVtIHByZXZpb3VzIHdlaWdodCByZWN1cnNpdmVseSB1bnRpbCB0aGUgb3JpZ2luIG9mIHRoZSB3ZWlnaHQKICAvLyBtYXRyaXguCiAgZnVuY3Rpb24gc3BsaWNlT3BlcmF0aW9uc0Zyb21FZGl0RGlzdGFuY2VzKGRpc3RhbmNlcykgewogICAgbGV0IGkgPSBkaXN0YW5jZXMubGVuZ3RoIC0gMTsKICAgIGxldCBqID0gZGlzdGFuY2VzWzBdLmxlbmd0aCAtIDE7CiAgICBsZXQgY3VycmVudCA9IGRpc3RhbmNlc1tpXVtqXTsKICAgIGxldCBlZGl0cyA9IFtdOwogICAgd2hpbGUgKGkgPiAwIHx8IGogPiAwKSB7CiAgICAgIGlmIChpID09IDApIHsKICAgICAgICBlZGl0cy5wdXNoKEVESVRfQUREKTsKICAgICAgICBqLS07CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgaWYgKGogPT0gMCkgewogICAgICAgIGVkaXRzLnB1c2goRURJVF9ERUxFVEUpOwogICAgICAgIGktLTsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBsZXQgbm9ydGhXZXN0ID0gZGlzdGFuY2VzW2kgLSAxXVtqIC0gMV07CiAgICAgIGxldCB3ZXN0ID0gZGlzdGFuY2VzW2kgLSAxXVtqXTsKICAgICAgbGV0IG5vcnRoID0gZGlzdGFuY2VzW2ldW2ogLSAxXTsKCiAgICAgIGxldCBtaW47CiAgICAgIGlmICh3ZXN0IDwgbm9ydGgpCiAgICAgICAgbWluID0gd2VzdCA8IG5vcnRoV2VzdCA/IHdlc3QgOiBub3J0aFdlc3Q7CiAgICAgIGVsc2UKICAgICAgICBtaW4gPSBub3J0aCA8IG5vcnRoV2VzdCA/IG5vcnRoIDogbm9ydGhXZXN0OwoKICAgICAgaWYgKG1pbiA9PSBub3J0aFdlc3QpIHsKICAgICAgICBpZiAobm9ydGhXZXN0ID09IGN1cnJlbnQpIHsKICAgICAgICAgIGVkaXRzLnB1c2goRURJVF9MRUFWRSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGVkaXRzLnB1c2goRURJVF9VUERBVEUpOwogICAgICAgICAgY3VycmVudCA9IG5vcnRoV2VzdDsKICAgICAgICB9CiAgICAgICAgaS0tOwogICAgICAgIGotLTsKICAgICAgfSBlbHNlIGlmIChtaW4gPT0gd2VzdCkgewogICAgICAgIGVkaXRzLnB1c2goRURJVF9ERUxFVEUpOwogICAgICAgIGktLTsKICAgICAgICBjdXJyZW50ID0gd2VzdDsKICAgICAgfSBlbHNlIHsKICAgICAgICBlZGl0cy5wdXNoKEVESVRfQUREKTsKICAgICAgICBqLS07CiAgICAgICAgY3VycmVudCA9IG5vcnRoOwogICAgICB9CiAgICB9CgogICAgZWRpdHMucmV2ZXJzZSgpOwogICAgcmV0dXJuIGVkaXRzOwogIH0KCiAgLyoqCiAgICogU3BsaWNlIFByb2plY3Rpb24gZnVuY3Rpb25zOgogICAqCiAgICogQSBzcGxpY2UgbWFwIGlzIGEgcmVwcmVzZW50YXRpb24gb2YgaG93IGEgcHJldmlvdXMgYXJyYXkgb2YgaXRlbXMKICAgKiB3YXMgdHJhbnNmb3JtZWQgaW50byBhIG5ldyBhcnJheSBvZiBpdGVtcy4gQ29uY2VwdHVhbGx5IGl0IGlzIGEgbGlzdCBvZgogICAqIHR1cGxlcyBvZgogICAqCiAgICogICA8aW5kZXgsIHJlbW92ZWQsIGFkZGVkQ291bnQ+CiAgICoKICAgKiB3aGljaCBhcmUga2VwdCBpbiBhc2NlbmRpbmcgaW5kZXggb3JkZXIgb2YuIFRoZSB0dXBsZSByZXByZXNlbnRzIHRoYXQgYXQKICAgKiB0aGUgfGluZGV4fCwgfHJlbW92ZWR8IHNlcXVlbmNlIG9mIGl0ZW1zIHdlcmUgcmVtb3ZlZCwgYW5kIGNvdW50aW5nIGZvcndhcmQKICAgKiBmcm9tIHxpbmRleHwsIHxhZGRlZENvdW50fCBpdGVtcyB3ZXJlIGFkZGVkLgogICAqLwoKICAvKioKICAgKiBMYWNraW5nIGluZGl2aWR1YWwgc3BsaWNlIG11dGF0aW9uIGluZm9ybWF0aW9uLCB0aGUgbWluaW1hbCBzZXQgb2YKICAgKiBzcGxpY2VzIGNhbiBiZSBzeW50aGVzaXplZCBnaXZlbiB0aGUgcHJldmlvdXMgc3RhdGUgYW5kIGZpbmFsIHN0YXRlIG9mIGFuCiAgICogYXJyYXkuIFRoZSBiYXNpYyBhcHByb2FjaCBpcyB0byBjYWxjdWxhdGUgdGhlIGVkaXQgZGlzdGFuY2UgbWF0cml4IGFuZAogICAqIGNob29zZSB0aGUgc2hvcnRlc3QgcGF0aCB0aHJvdWdoIGl0LgogICAqCiAgICogQ29tcGxleGl0eTogTyhsICogcCkKICAgKiAgIGw6IFRoZSBsZW5ndGggb2YgdGhlIGN1cnJlbnQgYXJyYXkKICAgKiAgIHA6IFRoZSBsZW5ndGggb2YgdGhlIG9sZCBhcnJheQogICAqCiAgICogQHBhcmFtIHshQXJyYXl9IGN1cnJlbnQgVGhlIGN1cnJlbnQgImNoYW5nZWQiIGFycmF5IGZvciB3aGljaCB0bwogICAqIGNhbGN1bGF0ZSBzcGxpY2VzLgogICAqIEBwYXJhbSB7bnVtYmVyfSBjdXJyZW50U3RhcnQgU3RhcnRpbmcgaW5kZXggaW4gdGhlIGBjdXJyZW50YCBhcnJheSBmb3IKICAgKiB3aGljaCBzcGxpY2VzIGFyZSBjYWxjdWxhdGVkLgogICAqIEBwYXJhbSB7bnVtYmVyfSBjdXJyZW50RW5kIEVuZGluZyBpbmRleCBpbiB0aGUgYGN1cnJlbnRgIGFycmF5IGZvcgogICAqIHdoaWNoIHNwbGljZXMgYXJlIGNhbGN1bGF0ZWQuCiAgICogQHBhcmFtIHshQXJyYXl9IG9sZCBUaGUgb3JpZ2luYWwgInVuY2hhbmdlZCIgYXJyYXkgdG8gY29tcGFyZSBgY3VycmVudGAKICAgKiBhZ2FpbnN0IHRvIGRldGVybWluZSBzcGxpY2VzLgogICAqIEBwYXJhbSB7bnVtYmVyfSBvbGRTdGFydCBTdGFydGluZyBpbmRleCBpbiB0aGUgYG9sZGAgYXJyYXkgZm9yCiAgICogd2hpY2ggc3BsaWNlcyBhcmUgY2FsY3VsYXRlZC4KICAgKiBAcGFyYW0ge251bWJlcn0gb2xkRW5kIEVuZGluZyBpbmRleCBpbiB0aGUgYG9sZGAgYXJyYXkgZm9yCiAgICogd2hpY2ggc3BsaWNlcyBhcmUgY2FsY3VsYXRlZC4KICAgKiBAcmV0dXJuIHshQXJyYXl9IFJldHVybnMgYW4gYXJyYXkgb2Ygc3BsaWNlIHJlY29yZCBvYmplY3RzLiBFYWNoIG9mIHRoZXNlCiAgICogY29udGFpbnM6IGBpbmRleGAgdGhlIGxvY2F0aW9uIHdoZXJlIHRoZSBzcGxpY2Ugb2NjdXJyZWQ7IGByZW1vdmVkYAogICAqIHRoZSBhcnJheSBvZiByZW1vdmVkIGl0ZW1zIGZyb20gdGhpcyBsb2NhdGlvbjsgYGFkZGVkQ291bnRgIHRoZSBudW1iZXIKICAgKiBvZiBpdGVtcyBhZGRlZCBhdCB0aGlzIGxvY2F0aW9uLgogICAqLwogIGZ1bmN0aW9uIGNhbGNTcGxpY2VzKGN1cnJlbnQsIGN1cnJlbnRTdGFydCwgY3VycmVudEVuZCwKICAgICAgICAgICAgICAgICAgICAgICAgb2xkLCBvbGRTdGFydCwgb2xkRW5kKSB7CiAgICBsZXQgcHJlZml4Q291bnQgPSAwOwogICAgbGV0IHN1ZmZpeENvdW50ID0gMDsKICAgIGxldCBzcGxpY2U7CgogICAgbGV0IG1pbkxlbmd0aCA9IE1hdGgubWluKGN1cnJlbnRFbmQgLSBjdXJyZW50U3RhcnQsIG9sZEVuZCAtIG9sZFN0YXJ0KTsKICAgIGlmIChjdXJyZW50U3RhcnQgPT0gMCAmJiBvbGRTdGFydCA9PSAwKQogICAgICBwcmVmaXhDb3VudCA9IHNoYXJlZFByZWZpeChjdXJyZW50LCBvbGQsIG1pbkxlbmd0aCk7CgogICAgaWYgKGN1cnJlbnRFbmQgPT0gY3VycmVudC5sZW5ndGggJiYgb2xkRW5kID09IG9sZC5sZW5ndGgpCiAgICAgIHN1ZmZpeENvdW50ID0gc2hhcmVkU3VmZml4KGN1cnJlbnQsIG9sZCwgbWluTGVuZ3RoIC0gcHJlZml4Q291bnQpOwoKICAgIGN1cnJlbnRTdGFydCArPSBwcmVmaXhDb3VudDsKICAgIG9sZFN0YXJ0ICs9IHByZWZpeENvdW50OwogICAgY3VycmVudEVuZCAtPSBzdWZmaXhDb3VudDsKICAgIG9sZEVuZCAtPSBzdWZmaXhDb3VudDsKCiAgICBpZiAoY3VycmVudEVuZCAtIGN1cnJlbnRTdGFydCA9PSAwICYmIG9sZEVuZCAtIG9sZFN0YXJ0ID09IDApCiAgICAgIHJldHVybiBbXTsKCiAgICBpZiAoY3VycmVudFN0YXJ0ID09IGN1cnJlbnRFbmQpIHsKICAgICAgc3BsaWNlID0gbmV3U3BsaWNlKGN1cnJlbnRTdGFydCwgW10sIDApOwogICAgICB3aGlsZSAob2xkU3RhcnQgPCBvbGRFbmQpCiAgICAgICAgc3BsaWNlLnJlbW92ZWQucHVzaChvbGRbb2xkU3RhcnQrK10pOwoKICAgICAgcmV0dXJuIFsgc3BsaWNlIF07CiAgICB9IGVsc2UgaWYgKG9sZFN0YXJ0ID09IG9sZEVuZCkKICAgICAgcmV0dXJuIFsgbmV3U3BsaWNlKGN1cnJlbnRTdGFydCwgW10sIGN1cnJlbnRFbmQgLSBjdXJyZW50U3RhcnQpIF07CgogICAgbGV0IG9wcyA9IHNwbGljZU9wZXJhdGlvbnNGcm9tRWRpdERpc3RhbmNlcygKICAgICAgICBjYWxjRWRpdERpc3RhbmNlcyhjdXJyZW50LCBjdXJyZW50U3RhcnQsIGN1cnJlbnRFbmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGQsIG9sZFN0YXJ0LCBvbGRFbmQpKTsKCiAgICBzcGxpY2UgPSB1bmRlZmluZWQ7CiAgICBsZXQgc3BsaWNlcyA9IFtdOwogICAgbGV0IGluZGV4ID0gY3VycmVudFN0YXJ0OwogICAgbGV0IG9sZEluZGV4ID0gb2xkU3RhcnQ7CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG9wcy5sZW5ndGg7IGkrKykgewogICAgICBzd2l0Y2gob3BzW2ldKSB7CiAgICAgICAgY2FzZSBFRElUX0xFQVZFOgogICAgICAgICAgaWYgKHNwbGljZSkgewogICAgICAgICAgICBzcGxpY2VzLnB1c2goc3BsaWNlKTsKICAgICAgICAgICAgc3BsaWNlID0gdW5kZWZpbmVkOwogICAgICAgICAgfQoKICAgICAgICAgIGluZGV4Kys7CiAgICAgICAgICBvbGRJbmRleCsrOwogICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSBFRElUX1VQREFURToKICAgICAgICAgIGlmICghc3BsaWNlKQogICAgICAgICAgICBzcGxpY2UgPSBuZXdTcGxpY2UoaW5kZXgsIFtdLCAwKTsKCiAgICAgICAgICBzcGxpY2UuYWRkZWRDb3VudCsrOwogICAgICAgICAgaW5kZXgrKzsKCiAgICAgICAgICBzcGxpY2UucmVtb3ZlZC5wdXNoKG9sZFtvbGRJbmRleF0pOwogICAgICAgICAgb2xkSW5kZXgrKzsKICAgICAgICAgIGJyZWFrOwogICAgICAgIGNhc2UgRURJVF9BREQ6CiAgICAgICAgICBpZiAoIXNwbGljZSkKICAgICAgICAgICAgc3BsaWNlID0gbmV3U3BsaWNlKGluZGV4LCBbXSwgMCk7CgogICAgICAgICAgc3BsaWNlLmFkZGVkQ291bnQrKzsKICAgICAgICAgIGluZGV4Kys7CiAgICAgICAgICBicmVhazsKICAgICAgICBjYXNlIEVESVRfREVMRVRFOgogICAgICAgICAgaWYgKCFzcGxpY2UpCiAgICAgICAgICAgIHNwbGljZSA9IG5ld1NwbGljZShpbmRleCwgW10sIDApOwoKICAgICAgICAgIHNwbGljZS5yZW1vdmVkLnB1c2gob2xkW29sZEluZGV4XSk7CiAgICAgICAgICBvbGRJbmRleCsrOwogICAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgIH0KCiAgICBpZiAoc3BsaWNlKSB7CiAgICAgIHNwbGljZXMucHVzaChzcGxpY2UpOwogICAgfQogICAgcmV0dXJuIHNwbGljZXM7CiAgfQoKICBmdW5jdGlvbiBzaGFyZWRQcmVmaXgoY3VycmVudCwgb2xkLCBzZWFyY2hMZW5ndGgpIHsKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2VhcmNoTGVuZ3RoOyBpKyspCiAgICAgIGlmICghZXF1YWxzKGN1cnJlbnRbaV0sIG9sZFtpXSkpCiAgICAgICAgcmV0dXJuIGk7CiAgICByZXR1cm4gc2VhcmNoTGVuZ3RoOwogIH0KCiAgZnVuY3Rpb24gc2hhcmVkU3VmZml4KGN1cnJlbnQsIG9sZCwgc2VhcmNoTGVuZ3RoKSB7CiAgICBsZXQgaW5kZXgxID0gY3VycmVudC5sZW5ndGg7CiAgICBsZXQgaW5kZXgyID0gb2xkLmxlbmd0aDsKICAgIGxldCBjb3VudCA9IDA7CiAgICB3aGlsZSAoY291bnQgPCBzZWFyY2hMZW5ndGggJiYgZXF1YWxzKGN1cnJlbnRbLS1pbmRleDFdLCBvbGRbLS1pbmRleDJdKSkKICAgICAgY291bnQrKzsKCiAgICByZXR1cm4gY291bnQ7CiAgfQoKICBmdW5jdGlvbiBjYWxjdWxhdGVTcGxpY2VzKGN1cnJlbnQsIHByZXZpb3VzKSB7CiAgICByZXR1cm4gY2FsY1NwbGljZXMoY3VycmVudCwgMCwgY3VycmVudC5sZW5ndGgsIHByZXZpb3VzLCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXMubGVuZ3RoKTsKICB9CgogIGZ1bmN0aW9uIGVxdWFscyhjdXJyZW50VmFsdWUsIHByZXZpb3VzVmFsdWUpIHsKICAgIHJldHVybiBjdXJyZW50VmFsdWUgPT09IHByZXZpb3VzVmFsdWU7CiAgfQoKICAvKioKICAgKiBAbmFtZXNwYWNlCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBNb2R1bGUgdGhhdCBwcm92aWRlcyB1dGlsaXRpZXMgZm9yIGRpZmZpbmcgYXJyYXlzLgogICAqLwogIFBvbHltZXIuQXJyYXlTcGxpY2UgPSB7CiAgICAvKioKICAgICAqIFJldHVybnMgYW4gYXJyYXkgb2Ygc3BsaWNlIHJlY29yZHMgaW5kaWNhdGluZyB0aGUgbWluaW11bSBlZGl0cyByZXF1aXJlZAogICAgICogdG8gdHJhbnNmb3JtIHRoZSBgcHJldmlvdXNgIGFycmF5IGludG8gdGhlIGBjdXJyZW50YCBhcnJheS4KICAgICAqCiAgICAgKiBTcGxpY2UgcmVjb3JkcyBhcmUgb3JkZXJlZCBieSBpbmRleCBhbmQgY29udGFpbiB0aGUgZm9sbG93aW5nIGZpZWxkczoKICAgICAqIC0gYGluZGV4YDogaW5kZXggd2hlcmUgZWRpdCBzdGFydGVkCiAgICAgKiAtIGByZW1vdmVkYDogYXJyYXkgb2YgcmVtb3ZlZCBpdGVtcyBmcm9tIHRoaXMgaW5kZXgKICAgICAqIC0gYGFkZGVkQ291bnRgOiBudW1iZXIgb2YgaXRlbXMgYWRkZWQgYXQgdGhpcyBpbmRleAogICAgICoKICAgICAqIFRoaXMgZnVuY3Rpb24gaXMgYmFzZWQgb24gdGhlIExldmVuc2h0ZWluICJtaW5pbXVtIGVkaXQgZGlzdGFuY2UiCiAgICAgKiBhbGdvcml0aG0uIE5vdGUgdGhhdCB1cGRhdGVzIGFyZSB0cmVhdGVkIGFzIHJlbW92YWwgZm9sbG93ZWQgYnkgYWRkaXRpb24uCiAgICAgKgogICAgICogVGhlIHdvcnN0LWNhc2UgdGltZSBjb21wbGV4aXR5IG9mIHRoaXMgYWxnb3JpdGhtIGlzIGBPKGwgKiBwKWAKICAgICAqICAgbDogVGhlIGxlbmd0aCBvZiB0aGUgY3VycmVudCBhcnJheQogICAgICogICBwOiBUaGUgbGVuZ3RoIG9mIHRoZSBwcmV2aW91cyBhcnJheQogICAgICoKICAgICAqIEhvd2V2ZXIsIHRoZSB3b3JzdC1jYXNlIGNvbXBsZXhpdHkgaXMgcmVkdWNlZCBieSBhbiBgTyhuKWAgb3B0aW1pemF0aW9uCiAgICAgKiB0byBkZXRlY3QgYW55IHNoYXJlZCBwcmVmaXggJiBzdWZmaXggYmV0d2VlbiB0aGUgdHdvIGFycmF5cyBhbmQgb25seQogICAgICogcGVyZm9ybSB0aGUgbW9yZSBleHBlbnNpdmUgbWluaW11bSBlZGl0IGRpc3RhbmNlIGNhbGN1bGF0aW9uIG92ZXIgdGhlCiAgICAgKiBub24tc2hhcmVkIHBvcnRpb25zIG9mIHRoZSBhcnJheXMuCiAgICAgKgogICAgICogQGZ1bmN0aW9uCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5BcnJheVNwbGljZQogICAgICogQHBhcmFtIHshQXJyYXl9IGN1cnJlbnQgVGhlICJjaGFuZ2VkIiBhcnJheSBmb3Igd2hpY2ggc3BsaWNlcyB3aWxsIGJlCiAgICAgKiBjYWxjdWxhdGVkLgogICAgICogQHBhcmFtIHshQXJyYXl9IHByZXZpb3VzIFRoZSAidW5jaGFuZ2VkIiBvcmlnaW5hbCBhcnJheSB0byBjb21wYXJlCiAgICAgKiBgY3VycmVudGAgYWdhaW5zdCB0byBkZXRlcm1pbmUgdGhlIHNwbGljZXMuCiAgICAgKiBAcmV0dXJuIHshQXJyYXl9IFJldHVybnMgYW4gYXJyYXkgb2Ygc3BsaWNlIHJlY29yZCBvYmplY3RzLiBFYWNoIG9mIHRoZXNlCiAgICAgKiBjb250YWluczogYGluZGV4YCB0aGUgbG9jYXRpb24gd2hlcmUgdGhlIHNwbGljZSBvY2N1cnJlZDsgYHJlbW92ZWRgCiAgICAgKiB0aGUgYXJyYXkgb2YgcmVtb3ZlZCBpdGVtcyBmcm9tIHRoaXMgbG9jYXRpb247IGBhZGRlZENvdW50YCB0aGUgbnVtYmVyCiAgICAgKiBvZiBpdGVtcyBhZGRlZCBhdCB0aGlzIGxvY2F0aW9uLgogICAgICovCiAgICBjYWxjdWxhdGVTcGxpY2VzCiAgfTsKCn0pKCk7Cjwvc2NyaXB0PjxzY3JpcHQ+CihmdW5jdGlvbigpIHsKICAndXNlIHN0cmljdCc7CgogIC8qKgogICAqIFJldHVybnMgdHJ1ZSBpZiBgbm9kZWAgaXMgYSBzbG90IGVsZW1lbnQKICAgKiBAcGFyYW0ge05vZGV9IG5vZGUgTm9kZSB0byB0ZXN0LgogICAqIEByZXR1cm4ge2Jvb2xlYW59IFJldHVybnMgdHJ1ZSBpZiB0aGUgZ2l2ZW4gYG5vZGVgIGlzIGEgc2xvdAogICAqIEBwcml2YXRlCiAgICovCiAgZnVuY3Rpb24gaXNTbG90KG5vZGUpIHsKICAgIHJldHVybiAobm9kZS5sb2NhbE5hbWUgPT09ICdzbG90Jyk7CiAgfQoKICAvKioKICAgKiBDbGFzcyB0aGF0IGxpc3RlbnMgZm9yIGNoYW5nZXMgKGFkZGl0aW9ucyBvciByZW1vdmFscykgdG8KICAgKiAiZmxhdHRlbmVkIG5vZGVzIiBvbiBhIGdpdmVuIGBub2RlYC4gVGhlIGxpc3Qgb2YgZmxhdHRlbmVkIG5vZGVzIGNvbnNpc3RzCiAgICogb2YgYSBub2RlJ3MgY2hpbGRyZW4gYW5kLCBmb3IgYW55IGNoaWxkcmVuIHRoYXQgYXJlIGA8c2xvdD5gIGVsZW1lbnRzLAogICAqIHRoZSBleHBhbmRlZCBmbGF0dGVuZWQgbGlzdCBvZiBgYXNzaWduZWROb2Rlc2AuCiAgICogRm9yIGV4YW1wbGUsIGlmIHRoZSBvYnNlcnZlZCBub2RlIGhhcyBjaGlsZHJlbiBgPGE+PC9hPjxzbG90Pjwvc2xvdD48Yj48L2I+YAogICAqIGFuZCB0aGUgYDxzbG90PmAgaGFzIG9uZSBgPGRpdj5gIGFzc2lnbmVkIHRvIGl0LCB0aGVuIHRoZSBmbGF0dGVuZWQKICAgKiBub2RlcyBsaXN0IGlzIGA8YT48L2E+PGRpdj48L2Rpdj48Yj48L2I+YC4gSWYgdGhlIGA8c2xvdD5gIGhhcyBvdGhlcgogICAqIGA8c2xvdD5gIGVsZW1lbnRzIGFzc2lnbmVkIHRvIGl0LCB0aGVzZSBhcmUgZmxhdHRlbmVkIGFzIHdlbGwuCiAgICoKICAgKiBUaGUgcHJvdmlkZWQgYGNhbGxiYWNrYCBpcyBjYWxsZWQgd2hlbmV2ZXIgYW55IGNoYW5nZSB0byB0aGlzIGxpc3QKICAgKiBvZiBmbGF0dGVuZWQgbm9kZXMgb2NjdXJzLCB3aGVyZSBhbiBhZGRpdGlvbiBvciByZW1vdmFsIG9mIGEgbm9kZSBpcwogICAqIGNvbnNpZGVyZWQgYSBjaGFuZ2UuIFRoZSBgY2FsbGJhY2tgIGlzIGNhbGxlZCB3aXRoIG9uZSBhcmd1bWVudCwgYW4gb2JqZWN0CiAgICogY29udGFpbmluZyBhbiBhcnJheSBvZiBhbnkgYGFkZGVkTm9kZXNgIGFuZCBgcmVtb3ZlZE5vZGVzYC4KICAgKgogICAqIE5vdGU6IHRoZSBjYWxsYmFjayBpcyBjYWxsZWQgYXN5bmNocm9ub3VzIHRvIGFueSBjaGFuZ2VzCiAgICogYXQgYSBtaWNyb3Rhc2sgY2hlY2twb2ludC4gVGhpcyBpcyBiZWNhdXNlIG9ic2VydmF0aW9uIGlzIHBlcmZvcm1lZCB1c2luZwogICAqIGBNdXRhdGlvbk9ic2VydmVyYCBhbmQgdGhlIGA8c2xvdD5gIGVsZW1lbnQncyBgc2xvdGNoYW5nZWAgZXZlbnQgd2hpY2gKICAgKiBhcmUgYXN5bmNocm9ub3VzLgogICAqCiAgICogQW4gZXhhbXBsZToKICAgKiBgYGBqcwogICAqIGNsYXNzIFRlc3RTZWxmT2JzZXJ2ZSBleHRlbmRzIFBvbHltZXIuRWxlbWVudCB7CiAgICogICBzdGF0aWMgZ2V0IGlzKCkgeyByZXR1cm4gJ3Rlc3Qtc2VsZi1vYnNlcnZlJzt9CiAgICogICBjb25uZWN0ZWRDYWxsYmFjaygpIHsKICAgKiAgICAgc3VwZXIuY29ubmVjdGVkQ2FsbGJhY2soKTsKICAgKiAgICAgdGhpcy5fb2JzZXJ2ZXIgPSBuZXcgUG9seW1lci5GbGF0dGVuZWROb2Rlc09ic2VydmVyKHRoaXMsIChpbmZvKSA9PiB7CiAgICogICAgICAgdGhpcy5pbmZvID0gaW5mbzsKICAgKiAgICAgfSk7CiAgICogICB9CiAgICogICBkaXNjb25uZWN0ZWRDYWxsYmFjaygpIHsKICAgKiAgICAgc3VwZXIuZGlzY29ubmVjdGVkQ2FsbGJhY2soKTsKICAgKiAgICAgdGhpcy5fb2JzZXJ2ZXIuZGlzY29ubmVjdCgpOwogICAqICAgfQogICAqIH0KICAgKiBjdXN0b21FbGVtZW50cy5kZWZpbmUoVGVzdFNlbGZPYnNlcnZlLmlzLCBUZXN0U2VsZk9ic2VydmUpOwogICAqIGBgYAogICAqCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBDbGFzcyB0aGF0IGxpc3RlbnMgZm9yIGNoYW5nZXMgKGFkZGl0aW9ucyBvciByZW1vdmFscykgdG8KICAgKiAiZmxhdHRlbmVkIG5vZGVzIiBvbiBhIGdpdmVuIGBub2RlYC4KICAgKi8KICBjbGFzcyBGbGF0dGVuZWROb2Rlc09ic2VydmVyIHsKCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIGxpc3Qgb2YgZmxhdHRlbmVkIG5vZGVzIGZvciB0aGUgZ2l2ZW4gYG5vZGVgLgogICAgICogVGhpcyBsaXN0IGNvbnNpc3RzIG9mIGEgbm9kZSdzIGNoaWxkcmVuIGFuZCwgZm9yIGFueSBjaGlsZHJlbgogICAgICogdGhhdCBhcmUgYDxzbG90PmAgZWxlbWVudHMsIHRoZSBleHBhbmRlZCBmbGF0dGVuZWQgbGlzdCBvZiBgYXNzaWduZWROb2Rlc2AuCiAgICAgKiBGb3IgZXhhbXBsZSwgaWYgdGhlIG9ic2VydmVkIG5vZGUgaGFzIGNoaWxkcmVuIGA8YT48L2E+PHNsb3Q+PC9zbG90PjxiPjwvYj5gCiAgICAgKiBhbmQgdGhlIGA8c2xvdD5gIGhhcyBvbmUgYDxkaXY+YCBhc3NpZ25lZCB0byBpdCwgdGhlbiB0aGUgZmxhdHRlbmVkCiAgICAgKiBub2RlcyBsaXN0IGlzIGA8YT48L2E+PGRpdj48L2Rpdj48Yj48L2I+YC4gSWYgdGhlIGA8c2xvdD5gIGhhcyBvdGhlcgogICAgICogYDxzbG90PmAgZWxlbWVudHMgYXNzaWduZWQgdG8gaXQsIHRoZXNlIGFyZSBmbGF0dGVuZWQgYXMgd2VsbC4KICAgICAqCiAgICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fEhUTUxTbG90RWxlbWVudH0gbm9kZSBUaGUgbm9kZSBmb3Igd2hpY2ggdG8gcmV0dXJuIHRoZSBsaXN0IG9mIGZsYXR0ZW5lZCBub2Rlcy4KICAgICAqIEByZXR1cm4ge0FycmF5fSBUaGUgbGlzdCBvZiBmbGF0dGVuZWQgbm9kZXMgZm9yIHRoZSBnaXZlbiBgbm9kZWAuCiAgICAqLwogICAgc3RhdGljIGdldEZsYXR0ZW5lZE5vZGVzKG5vZGUpIHsKICAgICAgaWYgKGlzU2xvdChub2RlKSkgewogICAgICAgIG5vZGUgPSAvKiogQHR5cGUge0hUTUxTbG90RWxlbWVudH0gKi8obm9kZSk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tc2VsZi1hc3NpZ24KICAgICAgICByZXR1cm4gbm9kZS5hc3NpZ25lZE5vZGVzKHtmbGF0dGVuOiB0cnVlfSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEFycmF5LmZyb20obm9kZS5jaGlsZE5vZGVzKS5tYXAoKG5vZGUpID0+IHsKICAgICAgICAgIGlmIChpc1Nsb3Qobm9kZSkpIHsKICAgICAgICAgICAgbm9kZSA9IC8qKiBAdHlwZSB7SFRNTFNsb3RFbGVtZW50fSAqLyhub2RlKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1zZWxmLWFzc2lnbgogICAgICAgICAgICByZXR1cm4gbm9kZS5hc3NpZ25lZE5vZGVzKHtmbGF0dGVuOiB0cnVlfSk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gW25vZGVdOwogICAgICAgICAgfQogICAgICAgIH0pLnJlZHVjZSgoYSwgYikgPT4gYS5jb25jYXQoYiksIFtdKTsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQHBhcmFtIHtFbGVtZW50fSB0YXJnZXQgTm9kZSBvbiB3aGljaCB0byBsaXN0ZW4gZm9yIGNoYW5nZXMuCiAgICAgKiBAcGFyYW0gez9mdW5jdGlvbighRWxlbWVudCwgeyB0YXJnZXQ6ICFFbGVtZW50LCBhZGRlZE5vZGVzOiAhQXJyYXk8IUVsZW1lbnQ+LCByZW1vdmVkTm9kZXM6ICFBcnJheTwhRWxlbWVudD4gfSk6dm9pZH0gY2FsbGJhY2sgRnVuY3Rpb24gY2FsbGVkIHdoZW4gdGhlcmUgYXJlIGFkZGl0aW9ucwogICAgICogb3IgcmVtb3ZhbHMgZnJvbSB0aGUgdGFyZ2V0J3MgbGlzdCBvZiBmbGF0dGVuZWQgbm9kZXMuCiAgICAqLwogICAgY29uc3RydWN0b3IodGFyZ2V0LCBjYWxsYmFjaykgewogICAgICAvKioKICAgICAgICogQHR5cGUge011dGF0aW9uT2JzZXJ2ZXJ9CiAgICAgICAqIEBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLl9zaGFkeUNoaWxkcmVuT2JzZXJ2ZXIgPSBudWxsOwogICAgICAvKioKICAgICAgICogQHR5cGUge011dGF0aW9uT2JzZXJ2ZXJ9CiAgICAgICAqIEBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLl9uYXRpdmVDaGlsZHJlbk9ic2VydmVyID0gbnVsbDsKICAgICAgdGhpcy5fY29ubmVjdGVkID0gZmFsc2U7CiAgICAgIC8qKgogICAgICAgKiBAdHlwZSB7RWxlbWVudH0KICAgICAgICogQHByaXZhdGUKICAgICAgICovCiAgICAgIHRoaXMuX3RhcmdldCA9IHRhcmdldDsKICAgICAgdGhpcy5jYWxsYmFjayA9IGNhbGxiYWNrOwogICAgICB0aGlzLl9lZmZlY3RpdmVOb2RlcyA9IFtdOwogICAgICB0aGlzLl9vYnNlcnZlciA9IG51bGw7CiAgICAgIHRoaXMuX3NjaGVkdWxlZCA9IGZhbHNlOwogICAgICAvKioKICAgICAgICogQHR5cGUge2Z1bmN0aW9uKCl9CiAgICAgICAqIEBwcml2YXRlCiAgICAgICAqLwogICAgICB0aGlzLl9ib3VuZFNjaGVkdWxlID0gKCkgPT4gewogICAgICAgIHRoaXMuX3NjaGVkdWxlKCk7CiAgICAgIH07CiAgICAgIHRoaXMuY29ubmVjdCgpOwogICAgICB0aGlzLl9zY2hlZHVsZSgpOwogICAgfQoKICAgIC8qKgogICAgICogQWN0aXZhdGVzIGFuIG9ic2VydmVyLiBUaGlzIG1ldGhvZCBpcyBhdXRvbWF0aWNhbGx5IGNhbGxlZCB3aGVuCiAgICAgKiBhIGBGbGF0dGVuZWROb2Rlc09ic2VydmVyYCBpcyBjcmVhdGVkLiBJdCBzaG91bGQgb25seSBiZSBjYWxsZWQgdG8KICAgICAqIHJlLWFjdGl2YXRlIGFuIG9ic2VydmVyIHRoYXQgaGFzIGJlZW4gZGVhY3RpdmF0ZWQgdmlhIHRoZSBgZGlzY29ubmVjdGAgbWV0aG9kLgogICAgICoKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIGNvbm5lY3QoKSB7CiAgICAgIGlmIChpc1Nsb3QodGhpcy5fdGFyZ2V0KSkgewogICAgICAgIHRoaXMuX2xpc3RlblNsb3RzKFt0aGlzLl90YXJnZXRdKTsKICAgICAgfSBlbHNlIGlmICh0aGlzLl90YXJnZXQuY2hpbGRyZW4pIHsKICAgICAgICB0aGlzLl9saXN0ZW5TbG90cyh0aGlzLl90YXJnZXQuY2hpbGRyZW4pOwogICAgICAgIGlmICh3aW5kb3cuU2hhZHlET00pIHsKICAgICAgICAgIHRoaXMuX3NoYWR5Q2hpbGRyZW5PYnNlcnZlciA9CiAgICAgICAgICAgIFNoYWR5RE9NLm9ic2VydmVDaGlsZHJlbih0aGlzLl90YXJnZXQsIChtdXRhdGlvbnMpID0+IHsKICAgICAgICAgICAgICB0aGlzLl9wcm9jZXNzTXV0YXRpb25zKG11dGF0aW9ucyk7CiAgICAgICAgICAgIH0pOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB0aGlzLl9uYXRpdmVDaGlsZHJlbk9ic2VydmVyID0KICAgICAgICAgICAgbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKG11dGF0aW9ucykgPT4gewogICAgICAgICAgICAgIHRoaXMuX3Byb2Nlc3NNdXRhdGlvbnMobXV0YXRpb25zKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICB0aGlzLl9uYXRpdmVDaGlsZHJlbk9ic2VydmVyLm9ic2VydmUodGhpcy5fdGFyZ2V0LCB7Y2hpbGRMaXN0OiB0cnVlfSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIHRoaXMuX2Nvbm5lY3RlZCA9IHRydWU7CiAgICB9CgogICAgLyoqCiAgICAgKiBEZWFjdGl2YXRlcyB0aGUgZmxhdHRlbmVkIG5vZGVzIG9ic2VydmVyLiBBZnRlciBjYWxsaW5nIHRoaXMgbWV0aG9kCiAgICAgKiB0aGUgb2JzZXJ2ZXIgY2FsbGJhY2sgd2lsbCBub3QgYmUgY2FsbGVkIHdoZW4gY2hhbmdlcyB0byBmbGF0dGVuZWQgbm9kZXMKICAgICAqIG9jY3VyLiBUaGUgYGNvbm5lY3RgIG1ldGhvZCBtYXkgYmUgc3Vic2VxdWVudGx5IGNhbGxlZCB0byByZWFjdGl2YXRlCiAgICAgKiB0aGUgb2JzZXJ2ZXIuCiAgICAgKgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgZGlzY29ubmVjdCgpIHsKICAgICAgaWYgKGlzU2xvdCh0aGlzLl90YXJnZXQpKSB7CiAgICAgICAgdGhpcy5fdW5saXN0ZW5TbG90cyhbdGhpcy5fdGFyZ2V0XSk7CiAgICAgIH0gZWxzZSBpZiAodGhpcy5fdGFyZ2V0LmNoaWxkcmVuKSB7CiAgICAgICAgdGhpcy5fdW5saXN0ZW5TbG90cyh0aGlzLl90YXJnZXQuY2hpbGRyZW4pOwogICAgICAgIGlmICh3aW5kb3cuU2hhZHlET00gJiYgdGhpcy5fc2hhZHlDaGlsZHJlbk9ic2VydmVyKSB7CiAgICAgICAgICBTaGFkeURPTS51bm9ic2VydmVDaGlsZHJlbih0aGlzLl9zaGFkeUNoaWxkcmVuT2JzZXJ2ZXIpOwogICAgICAgICAgdGhpcy5fc2hhZHlDaGlsZHJlbk9ic2VydmVyID0gbnVsbDsKICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX25hdGl2ZUNoaWxkcmVuT2JzZXJ2ZXIpIHsKICAgICAgICAgIHRoaXMuX25hdGl2ZUNoaWxkcmVuT2JzZXJ2ZXIuZGlzY29ubmVjdCgpOwogICAgICAgICAgdGhpcy5fbmF0aXZlQ2hpbGRyZW5PYnNlcnZlciA9IG51bGw7CiAgICAgICAgfQogICAgICB9CiAgICAgIHRoaXMuX2Nvbm5lY3RlZCA9IGZhbHNlOwogICAgfQoKICAgIC8qKgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIF9zY2hlZHVsZSgpIHsKICAgICAgaWYgKCF0aGlzLl9zY2hlZHVsZWQpIHsKICAgICAgICB0aGlzLl9zY2hlZHVsZWQgPSB0cnVlOwogICAgICAgIFBvbHltZXIuQXN5bmMubWljcm9UYXNrLnJ1bigoKSA9PiB0aGlzLmZsdXNoKCkpOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBAcGFyYW0ge0FycmF5PE11dGF0aW9uUmVjb3JkPn0gbXV0YXRpb25zIE11dGF0aW9ucyBzaWduYWxlZCBieSB0aGUgbXV0YXRpb24gb2JzZXJ2ZXIKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBfcHJvY2Vzc011dGF0aW9ucyhtdXRhdGlvbnMpIHsKICAgICAgdGhpcy5fcHJvY2Vzc1Nsb3RNdXRhdGlvbnMobXV0YXRpb25zKTsKICAgICAgdGhpcy5mbHVzaCgpOwogICAgfQoKICAgIC8qKgogICAgICogQHBhcmFtIHtBcnJheTxNdXRhdGlvblJlY29yZD59IG11dGF0aW9ucyBNdXRhdGlvbnMgc2lnbmFsZWQgYnkgdGhlIG11dGF0aW9uIG9ic2VydmVyCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICogQHByaXZhdGUKICAgICAqLwogICAgX3Byb2Nlc3NTbG90TXV0YXRpb25zKG11dGF0aW9ucykgewogICAgICBpZiAobXV0YXRpb25zKSB7CiAgICAgICAgZm9yIChsZXQgaT0wOyBpIDwgbXV0YXRpb25zLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICBsZXQgbXV0YXRpb24gPSBtdXRhdGlvbnNbaV07CiAgICAgICAgICBpZiAobXV0YXRpb24uYWRkZWROb2RlcykgewogICAgICAgICAgICB0aGlzLl9saXN0ZW5TbG90cyhtdXRhdGlvbi5hZGRlZE5vZGVzKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChtdXRhdGlvbi5yZW1vdmVkTm9kZXMpIHsKICAgICAgICAgICAgdGhpcy5fdW5saXN0ZW5TbG90cyhtdXRhdGlvbi5yZW1vdmVkTm9kZXMpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogRmx1c2hlcyB0aGUgb2JzZXJ2ZXIgY2F1c2luZyBhbnkgcGVuZGluZyBjaGFuZ2VzIHRvIGJlIGltbWVkaWF0ZWx5CiAgICAgKiBkZWxpdmVyZWQgdGhlIG9ic2VydmVyIGNhbGxiYWNrLiBCeSBkZWZhdWx0IHRoZXNlIGNoYW5nZXMgYXJlIGRlbGl2ZXJlZAogICAgICogYXN5bmNocm9ub3VzbHkgYXQgdGhlIG5leHQgbWljcm90YXNrIGNoZWNrcG9pbnQuCiAgICAgKgogICAgICogQHJldHVybiB7Ym9vbGVhbn0gUmV0dXJucyB0cnVlIGlmIGFueSBwZW5kaW5nIGNoYW5nZXMgY2F1c2VkIHRoZSBvYnNlcnZlcgogICAgICogY2FsbGJhY2sgdG8gcnVuLgogICAgICovCiAgICBmbHVzaCgpIHsKICAgICAgaWYgKCF0aGlzLl9jb25uZWN0ZWQpIHsKICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgIH0KICAgICAgaWYgKHdpbmRvdy5TaGFkeURPTSkgewogICAgICAgIFNoYWR5RE9NLmZsdXNoKCk7CiAgICAgIH0KICAgICAgaWYgKHRoaXMuX25hdGl2ZUNoaWxkcmVuT2JzZXJ2ZXIpIHsKICAgICAgICB0aGlzLl9wcm9jZXNzU2xvdE11dGF0aW9ucyh0aGlzLl9uYXRpdmVDaGlsZHJlbk9ic2VydmVyLnRha2VSZWNvcmRzKCkpOwogICAgICB9IGVsc2UgaWYgKHRoaXMuX3NoYWR5Q2hpbGRyZW5PYnNlcnZlcikgewogICAgICAgIHRoaXMuX3Byb2Nlc3NTbG90TXV0YXRpb25zKHRoaXMuX3NoYWR5Q2hpbGRyZW5PYnNlcnZlci50YWtlUmVjb3JkcygpKTsKICAgICAgfQogICAgICB0aGlzLl9zY2hlZHVsZWQgPSBmYWxzZTsKICAgICAgbGV0IGluZm8gPSB7CiAgICAgICAgdGFyZ2V0OiB0aGlzLl90YXJnZXQsCiAgICAgICAgYWRkZWROb2RlczogW10sCiAgICAgICAgcmVtb3ZlZE5vZGVzOiBbXQogICAgICB9OwogICAgICBsZXQgbmV3Tm9kZXMgPSB0aGlzLmNvbnN0cnVjdG9yLmdldEZsYXR0ZW5lZE5vZGVzKHRoaXMuX3RhcmdldCk7CiAgICAgIGxldCBzcGxpY2VzID0gUG9seW1lci5BcnJheVNwbGljZS5jYWxjdWxhdGVTcGxpY2VzKG5ld05vZGVzLAogICAgICAgIHRoaXMuX2VmZmVjdGl2ZU5vZGVzKTsKICAgICAgLy8gcHJvY2VzcyByZW1vdmFscwogICAgICBmb3IgKGxldCBpPTAsIHM7IChpPHNwbGljZXMubGVuZ3RoKSAmJiAocz1zcGxpY2VzW2ldKTsgaSsrKSB7CiAgICAgICAgZm9yIChsZXQgaj0wLCBuOyAoaiA8IHMucmVtb3ZlZC5sZW5ndGgpICYmIChuPXMucmVtb3ZlZFtqXSk7IGorKykgewogICAgICAgICAgaW5mby5yZW1vdmVkTm9kZXMucHVzaChuKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgLy8gcHJvY2VzcyBhZGRzCiAgICAgIGZvciAobGV0IGk9MCwgczsgKGk8c3BsaWNlcy5sZW5ndGgpICYmIChzPXNwbGljZXNbaV0pOyBpKyspIHsKICAgICAgICBmb3IgKGxldCBqPXMuaW5kZXg7IGogPCBzLmluZGV4ICsgcy5hZGRlZENvdW50OyBqKyspIHsKICAgICAgICAgIGluZm8uYWRkZWROb2Rlcy5wdXNoKG5ld05vZGVzW2pdKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgLy8gdXBkYXRlIGNhY2hlCiAgICAgIHRoaXMuX2VmZmVjdGl2ZU5vZGVzID0gbmV3Tm9kZXM7CiAgICAgIGxldCBkaWRGbHVzaCA9IGZhbHNlOwogICAgICBpZiAoaW5mby5hZGRlZE5vZGVzLmxlbmd0aCB8fCBpbmZvLnJlbW92ZWROb2Rlcy5sZW5ndGgpIHsKICAgICAgICBkaWRGbHVzaCA9IHRydWU7CiAgICAgICAgdGhpcy5jYWxsYmFjay5jYWxsKHRoaXMuX3RhcmdldCwgaW5mbyk7CiAgICAgIH0KICAgICAgcmV0dXJuIGRpZEZsdXNoOwogICAgfQoKICAgIC8qKgogICAgICogQHBhcmFtIHshQXJyYXk8RWxlbWVudHxOb2RlPnwhTm9kZUxpc3Q8Tm9kZT59IG5vZGVMaXN0IE5vZGVzIHRoYXQgY291bGQgY2hhbmdlCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICogQHByaXZhdGUKICAgICAqLwogICAgX2xpc3RlblNsb3RzKG5vZGVMaXN0KSB7CiAgICAgIGZvciAobGV0IGk9MDsgaSA8IG5vZGVMaXN0Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgbGV0IG4gPSBub2RlTGlzdFtpXTsKICAgICAgICBpZiAoaXNTbG90KG4pKSB7CiAgICAgICAgICBuLmFkZEV2ZW50TGlzdGVuZXIoJ3Nsb3RjaGFuZ2UnLCB0aGlzLl9ib3VuZFNjaGVkdWxlKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEBwYXJhbSB7IUFycmF5PEVsZW1lbnR8Tm9kZT58IU5vZGVMaXN0PE5vZGU+fSBub2RlTGlzdCBOb2RlcyB0aGF0IGNvdWxkIGNoYW5nZQogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIF91bmxpc3RlblNsb3RzKG5vZGVMaXN0KSB7CiAgICAgIGZvciAobGV0IGk9MDsgaSA8IG5vZGVMaXN0Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgbGV0IG4gPSBub2RlTGlzdFtpXTsKICAgICAgICBpZiAoaXNTbG90KG4pKSB7CiAgICAgICAgICBuLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Nsb3RjaGFuZ2UnLCB0aGlzLl9ib3VuZFNjaGVkdWxlKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KCiAgfQoKICBQb2x5bWVyLkZsYXR0ZW5lZE5vZGVzT2JzZXJ2ZXIgPSBGbGF0dGVuZWROb2Rlc09ic2VydmVyOwoKfSkoKTsKPC9zY3JpcHQ+PHNjcmlwdD4KKGZ1bmN0aW9uKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgbGV0IGRlYm91bmNlclF1ZXVlID0gW107CgogIC8qKgogICAqIEFkZHMgYSBgUG9seW1lci5EZWJvdW5jZXJgIHRvIGEgbGlzdCBvZiBnbG9iYWxseSBmbHVzaGFibGUgdGFza3MuCiAgICoKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBwYXJhbSB7IVBvbHltZXIuRGVib3VuY2VyfSBkZWJvdW5jZXIgRGVib3VuY2VyIHRvIGVucXVldWUKICAgKiBAcmV0dXJuIHt2b2lkfQogICAqLwogIFBvbHltZXIuZW5xdWV1ZURlYm91bmNlciA9IGZ1bmN0aW9uKGRlYm91bmNlcikgewogICAgZGVib3VuY2VyUXVldWUucHVzaChkZWJvdW5jZXIpOwogIH07CgogIGZ1bmN0aW9uIGZsdXNoRGVib3VuY2VycygpIHsKICAgIGNvbnN0IGRpZEZsdXNoID0gQm9vbGVhbihkZWJvdW5jZXJRdWV1ZS5sZW5ndGgpOwogICAgd2hpbGUgKGRlYm91bmNlclF1ZXVlLmxlbmd0aCkgewogICAgICB0cnkgewogICAgICAgIGRlYm91bmNlclF1ZXVlLnNoaWZ0KCkuZmx1c2goKTsKICAgICAgfSBjYXRjaChlKSB7CiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7CiAgICAgICAgICB0aHJvdyBlOwogICAgICAgIH0pOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gZGlkRmx1c2g7CiAgfQoKICAvKioKICAgKiBGb3JjZXMgc2V2ZXJhbCBjbGFzc2VzIG9mIGFzeW5jaHJvbm91c2x5IHF1ZXVlZCB0YXNrcyB0byBmbHVzaDoKICAgKiAtIERlYm91bmNlcnMgYWRkZWQgdmlhIGBlbnF1ZXVlRGVib3VuY2VyYAogICAqIC0gU2hhZHlET00gZGlzdHJpYnV0aW9uCiAgICoKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEByZXR1cm4ge3ZvaWR9CiAgICovCiAgUG9seW1lci5mbHVzaCA9IGZ1bmN0aW9uKCkgewogICAgbGV0IHNoYWR5RE9NLCBkZWJvdW5jZXJzOwogICAgZG8gewogICAgICBzaGFkeURPTSA9IHdpbmRvdy5TaGFkeURPTSAmJiBTaGFkeURPTS5mbHVzaCgpOwogICAgICBpZiAod2luZG93LlNoYWR5Q1NTICYmIHdpbmRvdy5TaGFkeUNTUy5TY29waW5nU2hpbSkgewogICAgICAgIHdpbmRvdy5TaGFkeUNTUy5TY29waW5nU2hpbS5mbHVzaCgpOwogICAgICB9CiAgICAgIGRlYm91bmNlcnMgPSBmbHVzaERlYm91bmNlcnMoKTsKICAgIH0gd2hpbGUgKHNoYWR5RE9NIHx8IGRlYm91bmNlcnMpOwogIH07Cgp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CiAgJ3VzZSBzdHJpY3QnOwoKICBjb25zdCBwID0gRWxlbWVudC5wcm90b3R5cGU7CiAgLyoqCiAgICogQGNvbnN0IHtmdW5jdGlvbih0aGlzOk5vZGUsIHN0cmluZyk6IGJvb2xlYW59CiAgICovCiAgY29uc3Qgbm9ybWFsaXplZE1hdGNoZXNTZWxlY3RvciA9IHAubWF0Y2hlcyB8fCBwLm1hdGNoZXNTZWxlY3RvciB8fAogICAgcC5tb3pNYXRjaGVzU2VsZWN0b3IgfHwgcC5tc01hdGNoZXNTZWxlY3RvciB8fAogICAgcC5vTWF0Y2hlc1NlbGVjdG9yIHx8IHAud2Via2l0TWF0Y2hlc1NlbGVjdG9yOwoKICAvKioKICAgKiBDcm9zcy1wbGF0Zm9ybSBgZWxlbWVudC5tYXRjaGVzYCBzaGltLgogICAqCiAgICogQGZ1bmN0aW9uIG1hdGNoZXNTZWxlY3RvcgogICAqIEBtZW1iZXJvZiBQb2x5bWVyLmRvbQogICAqIEBwYXJhbSB7IU5vZGV9IG5vZGUgTm9kZSB0byBjaGVjayBzZWxlY3RvciBhZ2FpbnN0CiAgICogQHBhcmFtIHtzdHJpbmd9IHNlbGVjdG9yIFNlbGVjdG9yIHRvIG1hdGNoCiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBub2RlIG1hdGNoZWQgc2VsZWN0b3IKICAgKi8KICBjb25zdCBtYXRjaGVzU2VsZWN0b3IgPSBmdW5jdGlvbihub2RlLCBzZWxlY3RvcikgewogICAgcmV0dXJuIG5vcm1hbGl6ZWRNYXRjaGVzU2VsZWN0b3IuY2FsbChub2RlLCBzZWxlY3Rvcik7CiAgfTsKCiAgLyoqCiAgICogTm9kZSBBUEkgd3JhcHBlciBjbGFzcyByZXR1cm5lZCBmcm9tIGBQb2x5bWVyLmRvbS4odGFyZ2V0KWAgd2hlbgogICAqIGB0YXJnZXRgIGlzIGEgYE5vZGVgLgogICAqCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKi8KICBjbGFzcyBEb21BcGkgewoKICAgIC8qKgogICAgICogQHBhcmFtIHtOb2RlfSBub2RlIE5vZGUgZm9yIHdoaWNoIHRvIGNyZWF0ZSBhIFBvbHltZXIuZG9tIGhlbHBlciBvYmplY3QuCiAgICAgKi8KICAgIGNvbnN0cnVjdG9yKG5vZGUpIHsKICAgICAgdGhpcy5ub2RlID0gbm9kZTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYW4gaW5zdGFuY2Ugb2YgYFBvbHltZXIuRmxhdHRlbmVkTm9kZXNPYnNlcnZlcmAgdGhhdAogICAgICogbGlzdGVucyBmb3Igbm9kZSBjaGFuZ2VzIG9uIHRoaXMgZWxlbWVudC4KICAgICAqCiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKCFFbGVtZW50LCB7IHRhcmdldDogIUVsZW1lbnQsIGFkZGVkTm9kZXM6ICFBcnJheTwhRWxlbWVudD4sIHJlbW92ZWROb2RlczogIUFycmF5PCFFbGVtZW50PiB9KTp2b2lkfSBjYWxsYmFjayBDYWxsZWQgd2hlbiBkaXJlY3Qgb3IgZGlzdHJpYnV0ZWQgY2hpbGRyZW4KICAgICAqICAgb2YgdGhpcyBlbGVtZW50IGNoYW5nZXMKICAgICAqIEByZXR1cm4geyFQb2x5bWVyLkZsYXR0ZW5lZE5vZGVzT2JzZXJ2ZXJ9IE9ic2VydmVyIGluc3RhbmNlCiAgICAgKi8KICAgIG9ic2VydmVOb2RlcyhjYWxsYmFjaykgewogICAgICByZXR1cm4gbmV3IFBvbHltZXIuRmxhdHRlbmVkTm9kZXNPYnNlcnZlcih0aGlzLm5vZGUsIGNhbGxiYWNrKTsKICAgIH0KCiAgICAvKioKICAgICAqIERpc2Nvbm5lY3RzIGFuIG9ic2VydmVyIHByZXZpb3VzbHkgY3JlYXRlZCB2aWEgYG9ic2VydmVOb2Rlc2AKICAgICAqCiAgICAgKiBAcGFyYW0geyFQb2x5bWVyLkZsYXR0ZW5lZE5vZGVzT2JzZXJ2ZXJ9IG9ic2VydmVySGFuZGxlIE9ic2VydmVyIGluc3RhbmNlCiAgICAgKiAgIHRvIGRpc2Nvbm5lY3QuCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICB1bm9ic2VydmVOb2RlcyhvYnNlcnZlckhhbmRsZSkgewogICAgICBvYnNlcnZlckhhbmRsZS5kaXNjb25uZWN0KCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBQcm92aWRlZCBhcyBhIGJhY2t3YXJkcy1jb21wYXRpYmxlIEFQSSBvbmx5LiAgVGhpcyBtZXRob2QgZG9lcyBub3RoaW5nLgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgbm90aWZ5T2JzZXJ2ZXIoKSB7fQoKICAgIC8qKgogICAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBwcm92aWRlZCBub2RlIGlzIGNvbnRhaW5lZCB3aXRoIHRoaXMgZWxlbWVudCdzCiAgICAgKiBsaWdodC1ET00gY2hpbGRyZW4gb3Igc2hhZG93IHJvb3QsIGluY2x1ZGluZyBhbnkgbmVzdGVkIHNoYWRvdyByb290cwogICAgICogb2YgY2hpbGRyZW4gdGhlcmVpbi4KICAgICAqCiAgICAgKiBAcGFyYW0ge05vZGV9IG5vZGUgTm9kZSB0byB0ZXN0CiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBSZXR1cm5zIHRydWUgaWYgdGhlIGdpdmVuIGBub2RlYCBpcyBjb250YWluZWQgd2l0aGluCiAgICAgKiAgIHRoaXMgZWxlbWVudCdzIGxpZ2h0IG9yIHNoYWRvdyBET00uCiAgICAgKi8KICAgIGRlZXBDb250YWlucyhub2RlKSB7CiAgICAgIGlmICh0aGlzLm5vZGUuY29udGFpbnMobm9kZSkpIHsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfQogICAgICBsZXQgbiA9IG5vZGU7CiAgICAgIGxldCBkb2MgPSBub2RlLm93bmVyRG9jdW1lbnQ7CiAgICAgIC8vIHdhbGsgZnJvbSBub2RlIHRvIGB0aGlzYCBvciBgZG9jdW1lbnRgCiAgICAgIHdoaWxlIChuICYmIG4gIT09IGRvYyAmJiBuICE9PSB0aGlzLm5vZGUpIHsKICAgICAgICAvLyB1c2UgbG9naWNhbCBwYXJlbnRub2RlLCBvciBuYXRpdmUgU2hhZG93Um9vdCBob3N0CiAgICAgICAgbiA9IG4ucGFyZW50Tm9kZSB8fCBuLmhvc3Q7CiAgICAgIH0KICAgICAgcmV0dXJuIG4gPT09IHRoaXMubm9kZTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIHJvb3Qgbm9kZSBvZiB0aGlzIG5vZGUuICBFcXVpdmFsZW50IHRvIGBnZXRSb29kTm9kZSgpYC4KICAgICAqCiAgICAgKiBAcmV0dXJuIHtOb2RlfSBUb3AgbW9zdCBlbGVtZW50IGluIHRoZSBkb20gdHJlZSBpbiB3aGljaCB0aGUgbm9kZQogICAgICogZXhpc3RzLiBJZiB0aGUgbm9kZSBpcyBjb25uZWN0ZWQgdG8gYSBkb2N1bWVudCB0aGlzIGlzIGVpdGhlciBhCiAgICAgKiBzaGFkb3dSb290IG9yIHRoZSBkb2N1bWVudDsgb3RoZXJ3aXNlLCBpdCBtYXkgYmUgdGhlIG5vZGUKICAgICAqIGl0c2VsZiBvciBhIG5vZGUgb3IgZG9jdW1lbnQgZnJhZ21lbnQgY29udGFpbmluZyBpdC4KICAgICAqLwogICAgZ2V0T3duZXJSb290KCkgewogICAgICByZXR1cm4gdGhpcy5ub2RlLmdldFJvb3ROb2RlKCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBGb3Igc2xvdCBlbGVtZW50cywgcmV0dXJucyB0aGUgbm9kZXMgYXNzaWduZWQgdG8gdGhlIHNsb3Q7IG90aGVyd2lzZQogICAgICogYW4gZW1wdHkgYXJyYXkuIEl0IGlzIGVxdWl2YWxlbnQgdG8gYDxzbG90Pi5hZGRpZ25lZE5vZGVzKHtmbGF0dGVuOnRydWV9KWAuCiAgICAgKgogICAgICogQHJldHVybiB7IUFycmF5PCFOb2RlPn0gQXJyYXkgb2YgYXNzaWduZWQgbm9kZXMKICAgICAqLwogICAgZ2V0RGlzdHJpYnV0ZWROb2RlcygpIHsKICAgICAgcmV0dXJuICh0aGlzLm5vZGUubG9jYWxOYW1lID09PSAnc2xvdCcpID8KICAgICAgICB0aGlzLm5vZGUuYXNzaWduZWROb2Rlcyh7ZmxhdHRlbjogdHJ1ZX0pIDoKICAgICAgICBbXTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgYW4gYXJyYXkgb2YgYWxsIHNsb3RzIHRoaXMgZWxlbWVudCB3YXMgZGlzdHJpYnV0ZWQgdG8uCiAgICAgKgogICAgICogQHJldHVybiB7IUFycmF5PCFIVE1MU2xvdEVsZW1lbnQ+fSBEZXNjcmlwdGlvbgogICAgICovCiAgICBnZXREZXN0aW5hdGlvbkluc2VydGlvblBvaW50cygpIHsKICAgICAgbGV0IGlwJCA9IFtdOwogICAgICBsZXQgbiA9IHRoaXMubm9kZS5hc3NpZ25lZFNsb3Q7CiAgICAgIHdoaWxlIChuKSB7CiAgICAgICAgaXAkLnB1c2gobik7CiAgICAgICAgbiA9IG4uYXNzaWduZWRTbG90OwogICAgICB9CiAgICAgIHJldHVybiBpcCQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBDYWxscyBgaW1wb3J0Tm9kZWAgb24gdGhlIGBvd25lckRvY3VtZW50YCBmb3IgdGhpcyBub2RlLgogICAgICoKICAgICAqIEBwYXJhbSB7IU5vZGV9IG5vZGUgTm9kZSB0byBpbXBvcnQKICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gZGVlcCBUcnVlIGlmIHRoZSBub2RlIHNob3VsZCBiZSBjbG9uZWQgZGVlcGx5IGR1cmluZwogICAgICogICBpbXBvcnQKICAgICAqIEByZXR1cm4ge05vZGV9IENsb25lIG9mIGdpdmVuIG5vZGUgaW1wb3J0ZWQgdG8gdGhpcyBvd25lciBkb2N1bWVudAogICAgICovCiAgICBpbXBvcnROb2RlKG5vZGUsIGRlZXApIHsKICAgICAgbGV0IGRvYyA9IHRoaXMubm9kZSBpbnN0YW5jZW9mIERvY3VtZW50ID8gdGhpcy5ub2RlIDoKICAgICAgICB0aGlzLm5vZGUub3duZXJEb2N1bWVudDsKICAgICAgcmV0dXJuIGRvYy5pbXBvcnROb2RlKG5vZGUsIGRlZXApOwogICAgfQoKICAgIC8qKgogICAgICogQHJldHVybiB7IUFycmF5PCFOb2RlPn0gUmV0dXJucyBhIGZsYXR0ZW5lZCBsaXN0IG9mIGFsbCBjaGlsZCBub2RlcyBhbmQKICAgICAqIG5vZGVzIGFzc2lnbmVkIHRvIGNoaWxkIHNsb3RzLgogICAgICovCiAgICBnZXRFZmZlY3RpdmVDaGlsZE5vZGVzKCkgewogICAgICByZXR1cm4gUG9seW1lci5GbGF0dGVuZWROb2Rlc09ic2VydmVyLmdldEZsYXR0ZW5lZE5vZGVzKHRoaXMubm9kZSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIGEgZmlsdGVyZWQgbGlzdCBvZiBmbGF0dGVuZWQgY2hpbGQgZWxlbWVudHMgZm9yIHRoaXMgZWxlbWVudCBiYXNlZAogICAgICogb24gdGhlIGdpdmVuIHNlbGVjdG9yLgogICAgICoKICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzZWxlY3RvciBTZWxlY3RvciB0byBmaWx0ZXIgbm9kZXMgYWdhaW5zdAogICAgICogQHJldHVybiB7IUFycmF5PCFIVE1MRWxlbWVudD59IExpc3Qgb2YgZmxhdHRlbmVkIGNoaWxkIGVsZW1lbnRzCiAgICAgKi8KICAgIHF1ZXJ5RGlzdHJpYnV0ZWRFbGVtZW50cyhzZWxlY3RvcikgewogICAgICBsZXQgYyQgPSB0aGlzLmdldEVmZmVjdGl2ZUNoaWxkTm9kZXMoKTsKICAgICAgbGV0IGxpc3QgPSBbXTsKICAgICAgZm9yIChsZXQgaT0wLCBsPWMkLmxlbmd0aCwgYzsgKGk8bCkgJiYgKGM9YyRbaV0pOyBpKyspIHsKICAgICAgICBpZiAoKGMubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFKSAmJgogICAgICAgICAgICBtYXRjaGVzU2VsZWN0b3IoYywgc2VsZWN0b3IpKSB7CiAgICAgICAgICBsaXN0LnB1c2goYyk7CiAgICAgICAgfQogICAgICB9CiAgICAgIHJldHVybiBsaXN0OwogICAgfQoKICAgIC8qKgogICAgICogRm9yIHNoYWRvdyByb290cywgcmV0dXJucyB0aGUgY3VycmVudGx5IGZvY3VzZWQgZWxlbWVudCB3aXRoaW4gdGhpcwogICAgICogc2hhZG93IHJvb3QuCiAgICAgKgogICAgICogQHJldHVybiB7Tm9kZXx1bmRlZmluZWR9IEN1cnJlbnRseSBmb2N1c2VkIGVsZW1lbnQKICAgICAqLwogICAgZ2V0IGFjdGl2ZUVsZW1lbnQoKSB7CiAgICAgIGxldCBub2RlID0gdGhpcy5ub2RlOwogICAgICByZXR1cm4gbm9kZS5fYWN0aXZlRWxlbWVudCAhPT0gdW5kZWZpbmVkID8gbm9kZS5fYWN0aXZlRWxlbWVudCA6IG5vZGUuYWN0aXZlRWxlbWVudDsKICAgIH0KICB9CgogIGZ1bmN0aW9uIGZvcndhcmRNZXRob2RzKHByb3RvLCBtZXRob2RzKSB7CiAgICBmb3IgKGxldCBpPTA7IGkgPCBtZXRob2RzLmxlbmd0aDsgaSsrKSB7CiAgICAgIGxldCBtZXRob2QgPSBtZXRob2RzW2ldOwogICAgICAvKiBlc2xpbnQtZGlzYWJsZSB2YWxpZC1qc2RvYyAqLwogICAgICBwcm90b1ttZXRob2RdID0gLyoqIEB0aGlzIHtEb21BcGl9ICovIGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0aGlzLm5vZGVbbWV0aG9kXS5hcHBseSh0aGlzLm5vZGUsIGFyZ3VtZW50cyk7CiAgICAgIH07CiAgICAgIC8qIGVzbGludC1lbmFibGUgKi8KICAgIH0KICB9CgogIGZ1bmN0aW9uIGZvcndhcmRSZWFkT25seVByb3BlcnRpZXMocHJvdG8sIHByb3BlcnRpZXMpIHsKICAgIGZvciAobGV0IGk9MDsgaSA8IHByb3BlcnRpZXMubGVuZ3RoOyBpKyspIHsKICAgICAgbGV0IG5hbWUgPSBwcm9wZXJ0aWVzW2ldOwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkocHJvdG8sIG5hbWUsIHsKICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgY29uc3QgZG9tQXBpID0gLyoqIEB0eXBlIHtEb21BcGl9ICovKHRoaXMpOwogICAgICAgICAgcmV0dXJuIGRvbUFwaS5ub2RlW25hbWVdOwogICAgICAgIH0sCiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlCiAgICAgIH0pOwogICAgfQogIH0KCiAgZnVuY3Rpb24gZm9yd2FyZFByb3BlcnRpZXMocHJvdG8sIHByb3BlcnRpZXMpIHsKICAgIGZvciAobGV0IGk9MDsgaSA8IHByb3BlcnRpZXMubGVuZ3RoOyBpKyspIHsKICAgICAgbGV0IG5hbWUgPSBwcm9wZXJ0aWVzW2ldOwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkocHJvdG8sIG5hbWUsIHsKICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgY29uc3QgZG9tQXBpID0gLyoqIEB0eXBlIHtEb21BcGl9ICovKHRoaXMpOwogICAgICAgICAgcmV0dXJuIGRvbUFwaS5ub2RlW25hbWVdOwogICAgICAgIH0sCiAgICAgICAgc2V0OiBmdW5jdGlvbih2YWx1ZSkgewogICAgICAgICAgLyoqIEB0eXBlIHtEb21BcGl9ICovICh0aGlzKS5ub2RlW25hbWVdID0gdmFsdWU7CiAgICAgICAgfSwKICAgICAgICBjb25maWd1cmFibGU6IHRydWUKICAgICAgfSk7CiAgICB9CiAgfQoKICBmb3J3YXJkTWV0aG9kcyhEb21BcGkucHJvdG90eXBlLCBbCiAgICAnY2xvbmVOb2RlJywgJ2FwcGVuZENoaWxkJywgJ2luc2VydEJlZm9yZScsICdyZW1vdmVDaGlsZCcsCiAgICAncmVwbGFjZUNoaWxkJywgJ3NldEF0dHJpYnV0ZScsICdyZW1vdmVBdHRyaWJ1dGUnLAogICAgJ3F1ZXJ5U2VsZWN0b3InLCAncXVlcnlTZWxlY3RvckFsbCcKICBdKTsKCiAgZm9yd2FyZFJlYWRPbmx5UHJvcGVydGllcyhEb21BcGkucHJvdG90eXBlLCBbCiAgICAncGFyZW50Tm9kZScsICdmaXJzdENoaWxkJywgJ2xhc3RDaGlsZCcsCiAgICAnbmV4dFNpYmxpbmcnLCAncHJldmlvdXNTaWJsaW5nJywgJ2ZpcnN0RWxlbWVudENoaWxkJywKICAgICdsYXN0RWxlbWVudENoaWxkJywgJ25leHRFbGVtZW50U2libGluZycsICdwcmV2aW91c0VsZW1lbnRTaWJsaW5nJywKICAgICdjaGlsZE5vZGVzJywgJ2NoaWxkcmVuJywgJ2NsYXNzTGlzdCcKICBdKTsKCiAgZm9yd2FyZFByb3BlcnRpZXMoRG9tQXBpLnByb3RvdHlwZSwgWwogICAgJ3RleHRDb250ZW50JywgJ2lubmVySFRNTCcKICBdKTsKCgogIC8qKgogICAqIEV2ZW50IEFQSSB3cmFwcGVyIGNsYXNzIHJldHVybmVkIGZyb20gYFBvbHltZXIuZG9tLih0YXJnZXQpYCB3aGVuCiAgICogYHRhcmdldGAgaXMgYW4gYEV2ZW50YC4KICAgKi8KICBjbGFzcyBFdmVudEFwaSB7CiAgICBjb25zdHJ1Y3RvcihldmVudCkgewogICAgICB0aGlzLmV2ZW50ID0gZXZlbnQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBmaXJzdCBub2RlIG9uIHRoZSBgY29tcG9zZWRQYXRoYCBvZiB0aGlzIGV2ZW50LgogICAgICoKICAgICAqIEByZXR1cm4geyFFdmVudFRhcmdldH0gVGhlIG5vZGUgdGhpcyBldmVudCB3YXMgZGlzcGF0Y2hlZCB0bwogICAgICovCiAgICBnZXQgcm9vdFRhcmdldCgpIHsKICAgICAgcmV0dXJuIHRoaXMuZXZlbnQuY29tcG9zZWRQYXRoKClbMF07CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBsb2NhbCAocmUtdGFyZ2V0ZWQpIHRhcmdldCBmb3IgdGhpcyBldmVudC4KICAgICAqCiAgICAgKiBAcmV0dXJuIHshRXZlbnRUYXJnZXR9IFRoZSBsb2NhbCAocmUtdGFyZ2V0ZWQpIHRhcmdldCBmb3IgdGhpcyBldmVudC4KICAgICAqLwogICAgZ2V0IGxvY2FsVGFyZ2V0KCkgewogICAgICByZXR1cm4gdGhpcy5ldmVudC50YXJnZXQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBgY29tcG9zZWRQYXRoYCBmb3IgdGhpcyBldmVudC4KICAgICAqIEByZXR1cm4geyFBcnJheTwhRXZlbnRUYXJnZXQ+fSBUaGUgbm9kZXMgdGhpcyBldmVudCBwcm9wYWdhdGVkIHRocm91Z2gKICAgICAqLwogICAgZ2V0IHBhdGgoKSB7CiAgICAgIHJldHVybiB0aGlzLmV2ZW50LmNvbXBvc2VkUGF0aCgpOwogICAgfQogIH0KCiAgUG9seW1lci5Eb21BcGkgPSBEb21BcGk7CgogIC8qKgogICAqIEBmdW5jdGlvbgogICAqIEBwYXJhbSB7Ym9vbGVhbj19IGRlZXAKICAgKiBAcmV0dXJuIHshTm9kZX0KICAgKi8KICBQb2x5bWVyLkRvbUFwaS5wcm90b3R5cGUuY2xvbmVOb2RlOwogIC8qKgogICAqIEBmdW5jdGlvbgogICAqIEBwYXJhbSB7IU5vZGV9IG5vZGUKICAgKiBAcmV0dXJuIHshTm9kZX0KICAgKi8KICBQb2x5bWVyLkRvbUFwaS5wcm90b3R5cGUuYXBwZW5kQ2hpbGQ7CiAgLyoqCiAgICogQGZ1bmN0aW9uCiAgICogQHBhcmFtIHshTm9kZX0gbmV3Q2hpbGQKICAgKiBAcGFyYW0ge05vZGV9IHJlZkNoaWxkCiAgICogQHJldHVybiB7IU5vZGV9CiAgICovCiAgUG9seW1lci5Eb21BcGkucHJvdG90eXBlLmluc2VydEJlZm9yZTsKICAvKioKICAgKiBAZnVuY3Rpb24KICAgKiBAcGFyYW0geyFOb2RlfSBub2RlCiAgICogQHJldHVybiB7IU5vZGV9CiAgICovCiAgUG9seW1lci5Eb21BcGkucHJvdG90eXBlLnJlbW92ZUNoaWxkOwogIC8qKgogICAqIEBmdW5jdGlvbgogICAqIEBwYXJhbSB7IU5vZGV9IG9sZENoaWxkCiAgICogQHBhcmFtIHshTm9kZX0gbmV3Q2hpbGQKICAgKiBAcmV0dXJuIHshTm9kZX0KICAgKi8KICBQb2x5bWVyLkRvbUFwaS5wcm90b3R5cGUucmVwbGFjZUNoaWxkOwogIC8qKgogICAqIEBmdW5jdGlvbgogICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lCiAgICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlCiAgICogQHJldHVybiB7dm9pZH0KICAgKi8KICBQb2x5bWVyLkRvbUFwaS5wcm90b3R5cGUuc2V0QXR0cmlidXRlOwogIC8qKgogICAqIEBmdW5jdGlvbgogICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lCiAgICogQHJldHVybiB7dm9pZH0KICAgKi8KICBQb2x5bWVyLkRvbUFwaS5wcm90b3R5cGUucmVtb3ZlQXR0cmlidXRlOwogIC8qKgogICAqIEBmdW5jdGlvbgogICAqIEBwYXJhbSB7c3RyaW5nfSBzZWxlY3RvcgogICAqIEByZXR1cm4gez9FbGVtZW50fQogICAqLwogIFBvbHltZXIuRG9tQXBpLnByb3RvdHlwZS5xdWVyeVNlbGVjdG9yOwogIC8qKgogICAqIEBmdW5jdGlvbgogICAqIEBwYXJhbSB7c3RyaW5nfSBzZWxlY3RvcgogICAqIEByZXR1cm4geyFOb2RlTGlzdDwhRWxlbWVudD59CiAgICovCiAgUG9seW1lci5Eb21BcGkucHJvdG90eXBlLnF1ZXJ5U2VsZWN0b3JBbGw7CgogIC8qKgogICAqIExlZ2FjeSBET00gYW5kIEV2ZW50IG1hbmlwdWxhdGlvbiBBUEkgd3JhcHBlciBmYWN0b3J5IHVzZWQgdG8gYWJzdHJhY3QKICAgKiBkaWZmZXJlbmNlcyBiZXR3ZWVuIG5hdGl2ZSBTaGFkb3cgRE9NIGFuZCAiU2hhZHkgRE9NIiB3aGVuIHBvbHlmaWxsaW5nIG9uCiAgICogb2xkZXIgYnJvd3NlcnMuCiAgICoKICAgKiBOb3RlIHRoYXQgaW4gUG9seW1lciAyLnggdXNlIG9mIGBQb2x5bWVyLmRvbWAgaXMgbm8gbG9uZ2VyIHJlcXVpcmVkIGFuZAogICAqIGluIHRoZSBtYWpvcml0eSBvZiBjYXNlcyBzaW1wbHkgZmFjYWRlcyBkaXJlY3RseSB0byB0aGUgc3RhbmRhcmQgbmF0aXZlCiAgICogQVBJLgogICAqCiAgICogQG5hbWVzcGFjZQogICAqIEBzdW1tYXJ5IExlZ2FjeSBET00gYW5kIEV2ZW50IG1hbmlwdWxhdGlvbiBBUEkgd3JhcHBlciBmYWN0b3J5IHVzZWQgdG8KICAgKiBhYnN0cmFjdCBkaWZmZXJlbmNlcyBiZXR3ZWVuIG5hdGl2ZSBTaGFkb3cgRE9NIGFuZCAiU2hhZHkgRE9NLiIKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBwYXJhbSB7KE5vZGV8RXZlbnQpPX0gb2JqIE5vZGUgb3IgZXZlbnQgdG8gb3BlcmF0ZSBvbgogICAqIEByZXR1cm4geyFEb21BcGl8IUV2ZW50QXBpfSBXcmFwcGVyIHByb3ZpZGluZyBlaXRoZXIgbm9kZSBBUEkgb3IgZXZlbnQgQVBJCiAgICovCiAgUG9seW1lci5kb20gPSBmdW5jdGlvbihvYmopIHsKICAgIG9iaiA9IG9iaiB8fCBkb2N1bWVudDsKICAgIGlmICghb2JqLl9fZG9tQXBpKSB7CiAgICAgIGxldCBoZWxwZXI7CiAgICAgIGlmIChvYmogaW5zdGFuY2VvZiBFdmVudCkgewogICAgICAgIGhlbHBlciA9IG5ldyBFdmVudEFwaShvYmopOwogICAgICB9IGVsc2UgewogICAgICAgIGhlbHBlciA9IG5ldyBEb21BcGkob2JqKTsKICAgICAgfQogICAgICBvYmouX19kb21BcGkgPSBoZWxwZXI7CiAgICB9CiAgICByZXR1cm4gb2JqLl9fZG9tQXBpOwogIH07CgogIFBvbHltZXIuZG9tLm1hdGNoZXNTZWxlY3RvciA9IG1hdGNoZXNTZWxlY3RvcjsKCiAgLyoqCiAgICogRm9yY2VzIHNldmVyYWwgY2xhc3NlcyBvZiBhc3luY2hyb25vdXNseSBxdWV1ZWQgdGFza3MgdG8gZmx1c2g6CiAgICogLSBEZWJvdW5jZXJzIGFkZGVkIHZpYSBgUG9seW1lci5lbnF1ZXVlRGVib3VuY2VyYAogICAqIC0gU2hhZHlET00gZGlzdHJpYnV0aW9uCiAgICoKICAgKiBUaGlzIG1ldGhvZCBmYWNhZGVzIHRvIGBQb2x5bWVyLmZsdXNoYC4KICAgKgogICAqIEBtZW1iZXJvZiBQb2x5bWVyLmRvbQogICAqLwogIFBvbHltZXIuZG9tLmZsdXNoID0gUG9seW1lci5mbHVzaDsKCiAgLyoqCiAgICogQWRkcyBhIGBQb2x5bWVyLkRlYm91bmNlcmAgdG8gYSBsaXN0IG9mIGdsb2JhbGx5IGZsdXNoYWJsZSB0YXNrcy4KICAgKgogICAqIFRoaXMgbWV0aG9kIGZhY2FkZXMgdG8gYFBvbHltZXIuZW5xdWV1ZURlYm91bmNlcmAuCiAgICoKICAgKiBAbWVtYmVyb2YgUG9seW1lci5kb20KICAgKiBAcGFyYW0geyFQb2x5bWVyLkRlYm91bmNlcn0gZGVib3VuY2VyIERlYm91bmNlciB0byBlbnF1ZXVlCiAgICovCiAgUG9seW1lci5kb20uYWRkRGVib3VuY2VyID0gUG9seW1lci5lbnF1ZXVlRGVib3VuY2VyOwp9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CgogICd1c2Ugc3RyaWN0JzsKCiAgbGV0IHN0eWxlSW50ZXJmYWNlID0gd2luZG93LlNoYWR5Q1NTOwoKICAvKioKICAgKiBFbGVtZW50IGNsYXNzIG1peGluIHRoYXQgcHJvdmlkZXMgUG9seW1lcidzICJsZWdhY3kiIEFQSSBpbnRlbmRlZCB0byBiZQogICAqIGJhY2t3YXJkLWNvbXBhdGlibGUgdG8gdGhlIGdyZWF0ZXN0IGV4dGVudCBwb3NzaWJsZSB3aXRoIHRoZSBBUEkKICAgKiBmb3VuZCBvbiB0aGUgUG9seW1lciAxLnggYFBvbHltZXIuQmFzZWAgcHJvdG90eXBlIGFwcGxpZWQgdG8gYWxsIGVsZW1lbnRzCiAgICogZGVmaW5lZCB1c2luZyB0aGUgYFBvbHltZXIoey4uLn0pYCBmdW5jdGlvbi4KICAgKgogICAqIEBtaXhpbkZ1bmN0aW9uCiAgICogQHBvbHltZXIKICAgKiBAYXBwbGllc01peGluIFBvbHltZXIuRWxlbWVudE1peGluCiAgICogQGFwcGxpZXNNaXhpbiBQb2x5bWVyLkdlc3R1cmVFdmVudExpc3RlbmVycwogICAqIEBwcm9wZXJ0eSBpc0F0dGFjaGVkIHtib29sZWFufSBTZXQgdG8gYHRydWVgIGluIHRoaXMgZWxlbWVudCdzCiAgICogICBgY29ubmVjdGVkQ2FsbGJhY2tgIGFuZCBgZmFsc2VgIGluIGBkaXNjb25uZWN0ZWRDYWxsYmFja2AKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBzdW1tYXJ5IEVsZW1lbnQgY2xhc3MgbWl4aW4gdGhhdCBwcm92aWRlcyBQb2x5bWVyJ3MgImxlZ2FjeSIgQVBJCiAgICovCiAgUG9seW1lci5MZWdhY3lFbGVtZW50TWl4aW4gPSBQb2x5bWVyLmRlZHVwaW5nTWl4aW4oKGJhc2UpID0+IHsKCiAgICAvKioKICAgICAqIEBjb25zdHJ1Y3RvcgogICAgICogQGV4dGVuZHMge2Jhc2V9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9FbGVtZW50TWl4aW59CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9HZXN0dXJlRXZlbnRMaXN0ZW5lcnN9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9EaXJNaXhpbn0KICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIGNvbnN0IGxlZ2FjeUVsZW1lbnRCYXNlID0gUG9seW1lci5EaXJNaXhpbihQb2x5bWVyLkdlc3R1cmVFdmVudExpc3RlbmVycyhQb2x5bWVyLkVsZW1lbnRNaXhpbihiYXNlKSkpOwoKICAgIC8qKgogICAgICogTWFwIG9mIHNpbXBsZSBuYW1lcyB0byB0b3VjaCBhY3Rpb24gbmFtZXMKICAgICAqIEBkaWN0CiAgICAgKi8KICAgIGNvbnN0IERJUkVDVElPTl9NQVAgPSB7CiAgICAgICd4JzogJ3Bhbi14JywKICAgICAgJ3knOiAncGFuLXknLAogICAgICAnbm9uZSc6ICdub25lJywKICAgICAgJ2FsbCc6ICdhdXRvJwogICAgfTsKCiAgICAvKioKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAbWl4aW5DbGFzcwogICAgICogQGV4dGVuZHMge2xlZ2FjeUVsZW1lbnRCYXNlfQogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfTGVnYWN5RWxlbWVudE1peGlufQogICAgICogQHVucmVzdHJpY3RlZAogICAgICovCiAgICBjbGFzcyBMZWdhY3lFbGVtZW50IGV4dGVuZHMgbGVnYWN5RWxlbWVudEJhc2UgewoKICAgICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgc3VwZXIoKTsKICAgICAgICAvKiogQHR5cGUge2Jvb2xlYW59ICovCiAgICAgICAgdGhpcy5pc0F0dGFjaGVkOwogICAgICAgIC8qKiBAdHlwZSB7V2Vha01hcDwhRWxlbWVudCwgIU9iamVjdDxzdHJpbmcsICFGdW5jdGlvbj4+fSAqLwogICAgICAgIHRoaXMuX19ib3VuZExpc3RlbmVyczsKICAgICAgICAvKiogQHR5cGUge09iamVjdDxzdHJpbmcsIEZ1bmN0aW9uPn0gKi8KICAgICAgICB0aGlzLl9kZWJvdW5jZXJzOwogICAgICB9CgogICAgICAvKioKICAgICAgICogRm9yd2FyZHMgYGltcG9ydE1ldGFgIGZyb20gdGhlIHByb3RvdHlwZSAoaS5lLiBmcm9tIHRoZSBpbmZvIG9iamVjdAogICAgICAgKiBwYXNzZWQgdG8gYFBvbHltZXIoey4uLn0pYCkgdG8gdGhlIHN0YXRpYyBBUEkuCiAgICAgICAqCiAgICAgICAqIEByZXR1cm4geyFPYmplY3R9IFRoZSBgaW1wb3J0Lm1ldGFgIG9iamVjdCBzZXQgb24gdGhlIHByb3RvdHlwZQogICAgICAgKiBAc3VwcHJlc3Mge21pc3NpbmdQcm9wZXJ0aWVzfSBgdGhpc2AgaXMgYWx3YXlzIGluIHRoZSBpbnN0YW5jZSBpbgogICAgICAgKiAgY2xvc3VyZSBmb3Igc29tZSByZWFzb24gZXZlbiBpbiBhIHN0YXRpYyBtZXRob2QsIHJhdGhlciB0aGFuIHRoZSBjbGFzcwogICAgICAgKi8KICAgICAgc3RhdGljIGdldCBpbXBvcnRNZXRhKCkgewogICAgICAgIHJldHVybiB0aGlzLnByb3RvdHlwZS5pbXBvcnRNZXRhOwogICAgICB9CgogICAgICAvKioKICAgICAgICogTGVnYWN5IGNhbGxiYWNrIGNhbGxlZCBkdXJpbmcgdGhlIGBjb25zdHJ1Y3RvcmAsIGZvciBvdmVycmlkaW5nCiAgICAgICAqIGJ5IHRoZSB1c2VyLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgY3JlYXRlZCgpIHt9CgogICAgICAvKioKICAgICAgICogUHJvdmlkZXMgYW4gaW1wbGVtZW50YXRpb24gb2YgYGNvbm5lY3RlZENhbGxiYWNrYAogICAgICAgKiB3aGljaCBhZGRzIFBvbHltZXIgbGVnYWN5IEFQSSdzIGBhdHRhY2hlZGAgbWV0aG9kLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICovCiAgICAgIGNvbm5lY3RlZENhbGxiYWNrKCkgewogICAgICAgIHN1cGVyLmNvbm5lY3RlZENhbGxiYWNrKCk7CiAgICAgICAgdGhpcy5pc0F0dGFjaGVkID0gdHJ1ZTsKICAgICAgICB0aGlzLmF0dGFjaGVkKCk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBMZWdhY3kgY2FsbGJhY2sgY2FsbGVkIGR1cmluZyBgY29ubmVjdGVkQ2FsbGJhY2tgLCBmb3Igb3ZlcnJpZGluZwogICAgICAgKiBieSB0aGUgdXNlci4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIGF0dGFjaGVkKCkge30KCiAgICAgIC8qKgogICAgICAgKiBQcm92aWRlcyBhbiBpbXBsZW1lbnRhdGlvbiBvZiBgZGlzY29ubmVjdGVkQ2FsbGJhY2tgCiAgICAgICAqIHdoaWNoIGFkZHMgUG9seW1lciBsZWdhY3kgQVBJJ3MgYGRldGFjaGVkYCBtZXRob2QuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBvdmVycmlkZQogICAgICAgKi8KICAgICAgZGlzY29ubmVjdGVkQ2FsbGJhY2soKSB7CiAgICAgICAgc3VwZXIuZGlzY29ubmVjdGVkQ2FsbGJhY2soKTsKICAgICAgICB0aGlzLmlzQXR0YWNoZWQgPSBmYWxzZTsKICAgICAgICB0aGlzLmRldGFjaGVkKCk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBMZWdhY3kgY2FsbGJhY2sgY2FsbGVkIGR1cmluZyBgZGlzY29ubmVjdGVkQ2FsbGJhY2tgLCBmb3Igb3ZlcnJpZGluZwogICAgICAgKiBieSB0aGUgdXNlci4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIGRldGFjaGVkKCkge30KCiAgICAgIC8qKgogICAgICAgKiBQcm92aWRlcyBhbiBvdmVycmlkZSBpbXBsZW1lbnRhdGlvbiBvZiBgYXR0cmlidXRlQ2hhbmdlZENhbGxiYWNrYAogICAgICAgKiB3aGljaCBhZGRzIHRoZSBQb2x5bWVyIGxlZ2FjeSBBUEkncyBgYXR0cmlidXRlQ2hhbmdlZGAgbWV0aG9kLgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBOYW1lIG9mIGF0dHJpYnV0ZS4KICAgICAgICogQHBhcmFtIHs/c3RyaW5nfSBvbGQgT2xkIHZhbHVlIG9mIGF0dHJpYnV0ZS4KICAgICAgICogQHBhcmFtIHs/c3RyaW5nfSB2YWx1ZSBDdXJyZW50IHZhbHVlIG9mIGF0dHJpYnV0ZS4KICAgICAgICogQHBhcmFtIHs/c3RyaW5nfSBuYW1lc3BhY2UgQXR0cmlidXRlIG5hbWVzcGFjZS4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICogQG92ZXJyaWRlCiAgICAgICAqLwogICAgICBhdHRyaWJ1dGVDaGFuZ2VkQ2FsbGJhY2sobmFtZSwgb2xkLCB2YWx1ZSwgbmFtZXNwYWNlKSB7CiAgICAgICAgaWYgKG9sZCAhPT0gdmFsdWUpIHsKICAgICAgICAgIHN1cGVyLmF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFjayhuYW1lLCBvbGQsIHZhbHVlLCBuYW1lc3BhY2UpOwogICAgICAgICAgdGhpcy5hdHRyaWJ1dGVDaGFuZ2VkKG5hbWUsIG9sZCwgdmFsdWUpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIExlZ2FjeSBjYWxsYmFjayBjYWxsZWQgZHVyaW5nIGBhdHRyaWJ1dGVDaGFuZ2VkQ2hhbGxiYWNrYCwgZm9yIG92ZXJyaWRpbmcKICAgICAgICogYnkgdGhlIHVzZXIuCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIE5hbWUgb2YgYXR0cmlidXRlLgogICAgICAgKiBAcGFyYW0gez9zdHJpbmd9IG9sZCBPbGQgdmFsdWUgb2YgYXR0cmlidXRlLgogICAgICAgKiBAcGFyYW0gez9zdHJpbmd9IHZhbHVlIEN1cnJlbnQgdmFsdWUgb2YgYXR0cmlidXRlLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgYXR0cmlidXRlQ2hhbmdlZChuYW1lLCBvbGQsIHZhbHVlKSB7fSAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzCgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGVzIHRoZSBkZWZhdWx0IGBQb2x5bWVyLlByb3BlcnR5RWZmZWN0c2AgaW1wbGVtZW50YXRpb24gdG8KICAgICAgICogYWRkIHN1cHBvcnQgZm9yIGNsYXNzIGluaXRpYWxpemF0aW9uIHZpYSB0aGUgYF9yZWdpc3RlcmVkYCBjYWxsYmFjay4KICAgICAgICogVGhpcyBpcyBjYWxsZWQgb25seSB3aGVuIHRoZSBmaXJzdCBpbnN0YW5jZSBvZiB0aGUgZWxlbWVudCBpcyBjcmVhdGVkLgogICAgICAgKgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICogQHN1cHByZXNzIHtpbnZhbGlkQ2FzdHN9CiAgICAgICAqLwogICAgICBfaW5pdGlhbGl6ZVByb3BlcnRpZXMoKSB7CiAgICAgICAgbGV0IHByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKHRoaXMpOwogICAgICAgIGlmICghcHJvdG8uaGFzT3duUHJvcGVydHkoJ19faGFzUmVnaXN0ZXJGaW5pc2hlZCcpKSB7CiAgICAgICAgICB0aGlzLl9yZWdpc3RlcmVkKCk7CiAgICAgICAgICAvLyBiYWNrc3RvcCBpbiBjYXNlIHRoZSBgX3JlZ2lzdGVyZWRgIGltcGxlbWVudGF0aW9uIGRvZXMgbm90IHNldCB0aGlzCiAgICAgICAgICBwcm90by5fX2hhc1JlZ2lzdGVyRmluaXNoZWQgPSB0cnVlOwogICAgICAgIH0KICAgICAgICBzdXBlci5faW5pdGlhbGl6ZVByb3BlcnRpZXMoKTsKICAgICAgICB0aGlzLnJvb3QgPSAvKiogQHR5cGUge0hUTUxFbGVtZW50fSAqLyh0aGlzKTsKICAgICAgICB0aGlzLmNyZWF0ZWQoKTsKICAgICAgICAvLyBFbnN1cmUgbGlzdGVuZXJzIGFyZSBhcHBsaWVkIGltbWVkaWF0ZWx5IHNvIHRoYXQgdGhleSBhcmUKICAgICAgICAvLyBhZGRlZCBiZWZvcmUgZGVjbGFyYXRpdmUgZXZlbnQgbGlzdGVuZXJzLiBUaGlzIGFsbG93cyBhbiBlbGVtZW50IHRvCiAgICAgICAgLy8gZGVjb3JhdGUgaXRzZWxmIHZpYSBhbiBldmVudCBwcmlvciB0byBhbnkgZGVjbGFyYXRpdmUgbGlzdGVuZXJzCiAgICAgICAgLy8gc2VlaW5nIHRoZSBldmVudC4gTm90ZSwgdGhpcyBlbnN1cmVzIGNvbXBhdGliaWxpdHkgd2l0aCAxLnggb3JkZXJpbmcuCiAgICAgICAgdGhpcy5fYXBwbHlMaXN0ZW5lcnMoKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENhbGxlZCBhdXRvbWF0aWNhbGx5IHdoZW4gYW4gZWxlbWVudCBpcyBpbml0aWFsaXppbmcuCiAgICAgICAqIFVzZXJzIG1heSBvdmVycmlkZSB0aGlzIG1ldGhvZCB0byBwZXJmb3JtIGNsYXNzIHJlZ2lzdHJhdGlvbiB0aW1lCiAgICAgICAqIHdvcmsuIFRoZSBpbXBsZW1lbnRhdGlvbiBzaG91bGQgZW5zdXJlIHRoZSB3b3JrIGlzIHBlcmZvcm1lZAogICAgICAgKiBvbmx5IG9uY2UgZm9yIHRoZSBjbGFzcy4KICAgICAgICogQHByb3RlY3RlZAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX3JlZ2lzdGVyZWQoKSB7fQoKICAgICAgLyoqCiAgICAgICAqIE92ZXJyaWRlcyB0aGUgZGVmYXVsdCBgUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHNgIGltcGxlbWVudGF0aW9uIHRvCiAgICAgICAqIGFkZCBzdXBwb3J0IGZvciBpbnN0YWxsaW5nIGBob3N0QXR0cmlidXRlc2AgYW5kIGBsaXN0ZW5lcnNgLgogICAgICAgKgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAb3ZlcnJpZGUKICAgICAgICovCiAgICAgIHJlYWR5KCkgewogICAgICAgIHRoaXMuX2Vuc3VyZUF0dHJpYnV0ZXMoKTsKICAgICAgICBzdXBlci5yZWFkeSgpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogRW5zdXJlcyBhbiBlbGVtZW50IGhhcyByZXF1aXJlZCBhdHRyaWJ1dGVzLiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudAogICAgICAgKiBpcyBiZWluZyByZWFkaWVkIHZpYSBgcmVhZHlgLiBVc2VycyBzaG91bGQgb3ZlcnJpZGUgdG8gc2V0IHRoZQogICAgICAgKiBlbGVtZW50J3MgcmVxdWlyZWQgYXR0cmlidXRlcy4gVGhlIGltcGxlbWVudGF0aW9uIHNob3VsZCBiZSBzdXJlCiAgICAgICAqIHRvIGNoZWNrIGFuZCBub3Qgb3ZlcnJpZGUgZXhpc3RpbmcgYXR0cmlidXRlcyBhZGRlZCBieQogICAgICAgKiB0aGUgdXNlciBvZiB0aGUgZWxlbWVudC4gVHlwaWNhbGx5LCBzZXR0aW5nIGF0dHJpYnV0ZXMgc2hvdWxkIGJlIGxlZnQKICAgICAgICogdG8gdGhlIGVsZW1lbnQgdXNlciBhbmQgbm90IGRvbmUgaGVyZTsgcmVhc29uYWJsZSBleGNlcHRpb25zIGluY2x1ZGUKICAgICAgICogc2V0dGluZyBhcmlhIHJvbGVzIGFuZCBmb2N1c2FiaWxpdHkuCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9lbnN1cmVBdHRyaWJ1dGVzKCkge30KCiAgICAgIC8qKgogICAgICAgKiBBZGRzIGVsZW1lbnQgZXZlbnQgbGlzdGVuZXJzLiBDYWxsZWQgd2hlbiB0aGUgZWxlbWVudAogICAgICAgKiBpcyBiZWluZyByZWFkaWVkIHZpYSBgcmVhZHlgLiBVc2VycyBzaG91bGQgb3ZlcnJpZGUgdG8KICAgICAgICogYWRkIGFueSByZXF1aXJlZCBlbGVtZW50IGV2ZW50IGxpc3RlbmVycy4KICAgICAgICogSW4gcGVyZm9ybWFuY2UgY3JpdGljYWwgZWxlbWVudHMsIHRoZSB3b3JrIGRvbmUgaGVyZSBzaG91bGQgYmUga2VwdAogICAgICAgKiB0byBhIG1pbmltdW0gc2luY2UgaXQgaXMgZG9uZSBiZWZvcmUgdGhlIGVsZW1lbnQgaXMgcmVuZGVyZWQuIEluCiAgICAgICAqIHRoZXNlIGVsZW1lbnRzLCBjb25zaWRlciBhZGRpbmcgbGlzdGVuZXJzIGFzeW5jaHJvbm91c2x5IHNvIGFzIG5vdCB0bwogICAgICAgKiBibG9jayByZW5kZXIuCiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9hcHBseUxpc3RlbmVycygpIHt9CgogICAgICAvKioKICAgICAgICogQ29udmVydHMgYSB0eXBlZCBKYXZhU2NyaXB0IHZhbHVlIHRvIGEgc3RyaW5nLgogICAgICAgKgogICAgICAgKiBOb3RlIHRoaXMgbWV0aG9kIGlzIHByb3ZpZGVkIGFzIGJhY2t3YXJkLWNvbXBhdGlibGUgbGVnYWN5IEFQSQogICAgICAgKiBvbmx5LiAgSXQgaXMgbm90IGRpcmVjdGx5IGNhbGxlZCBieSBhbnkgUG9seW1lciBmZWF0dXJlcy4gVG8gY3VzdG9taXplCiAgICAgICAqIGhvdyBwcm9wZXJ0aWVzIGFyZSBzZXJpYWxpemVkIHRvIGF0dHJpYnV0ZXMgZm9yIGF0dHJpYnV0ZSBiaW5kaW5ncyBhbmQKICAgICAgICogYHJlZmxlY3RUb0F0dHJpYnV0ZTogdHJ1ZWAgcHJvcGVydGllcyBhcyB3ZWxsIGFzIHRoaXMgbWV0aG9kLCBvdmVycmlkZQogICAgICAgKiB0aGUgYF9zZXJpYWxpemVWYWx1ZWAgbWV0aG9kIHByb3ZpZGVkIGJ5IGBQb2x5bWVyLlByb3BlcnR5QWNjZXNzb3JzYC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHsqfSB2YWx1ZSBWYWx1ZSB0byBkZXNlcmlhbGl6ZQogICAgICAgKiBAcmV0dXJuIHtzdHJpbmcgfCB1bmRlZmluZWR9IFNlcmlhbGl6ZWQgdmFsdWUKICAgICAgICovCiAgICAgIHNlcmlhbGl6ZSh2YWx1ZSkgewogICAgICAgIHJldHVybiB0aGlzLl9zZXJpYWxpemVWYWx1ZSh2YWx1ZSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBDb252ZXJ0cyBhIHN0cmluZyB0byBhIHR5cGVkIEphdmFTY3JpcHQgdmFsdWUuCiAgICAgICAqCiAgICAgICAqIE5vdGUgdGhpcyBtZXRob2QgaXMgcHJvdmlkZWQgYXMgYmFja3dhcmQtY29tcGF0aWJsZSBsZWdhY3kgQVBJCiAgICAgICAqIG9ubHkuICBJdCBpcyBub3QgZGlyZWN0bHkgY2FsbGVkIGJ5IGFueSBQb2x5bWVyIGZlYXR1cmVzLiAgVG8gY3VzdG9taXplCiAgICAgICAqIGhvdyBhdHRyaWJ1dGVzIGFyZSBkZXNlcmlhbGl6ZWQgdG8gcHJvcGVydGllcyBmb3IgaW4KICAgICAgICogYGF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFja2AsIG92ZXJyaWRlIGBfZGVzZXJpYWxpemVWYWx1ZWAgbWV0aG9kCiAgICAgICAqIHByb3ZpZGVkIGJ5IGBQb2x5bWVyLlByb3BlcnR5QWNjZXNzb3JzYC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIFN0cmluZyB0byBkZXNlcmlhbGl6ZQogICAgICAgKiBAcGFyYW0geyp9IHR5cGUgVHlwZSB0byBkZXNlcmlhbGl6ZSB0aGUgc3RyaW5nIHRvCiAgICAgICAqIEByZXR1cm4geyp9IFJldHVybnMgdGhlIGRlc2VyaWFsaXplZCB2YWx1ZSBpbiB0aGUgYHR5cGVgIGdpdmVuLgogICAgICAgKi8KICAgICAgZGVzZXJpYWxpemUodmFsdWUsIHR5cGUpIHsKICAgICAgICByZXR1cm4gdGhpcy5fZGVzZXJpYWxpemVWYWx1ZSh2YWx1ZSwgdHlwZSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBTZXJpYWxpemVzIGEgcHJvcGVydHkgdG8gaXRzIGFzc29jaWF0ZWQgYXR0cmlidXRlLgogICAgICAgKgogICAgICAgKiBOb3RlIHRoaXMgbWV0aG9kIGlzIHByb3ZpZGVkIGFzIGJhY2t3YXJkLWNvbXBhdGlibGUgbGVnYWN5IEFQSQogICAgICAgKiBvbmx5LiAgSXQgaXMgbm90IGRpcmVjdGx5IGNhbGxlZCBieSBhbnkgUG9seW1lciBmZWF0dXJlcy4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUgdG8gcmVmbGVjdC4KICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSBhdHRyaWJ1dGUgQXR0cmlidXRlIG5hbWUgdG8gcmVmbGVjdC4KICAgICAgICogQHBhcmFtIHsqPX0gdmFsdWUgUHJvcGVydHkgdmFsdWUgdG8gcmVmbGVjdC4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIHJlZmxlY3RQcm9wZXJ0eVRvQXR0cmlidXRlKHByb3BlcnR5LCBhdHRyaWJ1dGUsIHZhbHVlKSB7CiAgICAgICAgdGhpcy5fcHJvcGVydHlUb0F0dHJpYnV0ZShwcm9wZXJ0eSwgYXR0cmlidXRlLCB2YWx1ZSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBTZXRzIGEgdHlwZWQgdmFsdWUgdG8gYW4gSFRNTCBhdHRyaWJ1dGUgb24gYSBub2RlLgogICAgICAgKgogICAgICAgKiBOb3RlIHRoaXMgbWV0aG9kIGlzIHByb3ZpZGVkIGFzIGJhY2t3YXJkLWNvbXBhdGlibGUgbGVnYWN5IEFQSQogICAgICAgKiBvbmx5LiAgSXQgaXMgbm90IGRpcmVjdGx5IGNhbGxlZCBieSBhbnkgUG9seW1lciBmZWF0dXJlcy4KICAgICAgICoKICAgICAgICogQHBhcmFtIHsqfSB2YWx1ZSBWYWx1ZSB0byBzZXJpYWxpemUuCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBhdHRyaWJ1dGUgQXR0cmlidXRlIG5hbWUgdG8gc2VyaWFsaXplIHRvLgogICAgICAgKiBAcGFyYW0ge0VsZW1lbnR9IG5vZGUgRWxlbWVudCB0byBzZXQgYXR0cmlidXRlIHRvLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgc2VyaWFsaXplVmFsdWVUb0F0dHJpYnV0ZSh2YWx1ZSwgYXR0cmlidXRlLCBub2RlKSB7CiAgICAgICAgdGhpcy5fdmFsdWVUb05vZGVBdHRyaWJ1dGUoLyoqIEB0eXBlIHtFbGVtZW50fSAqLyAobm9kZSB8fCB0aGlzKSwgdmFsdWUsIGF0dHJpYnV0ZSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBDb3BpZXMgb3duIHByb3BlcnRpZXMgKGluY2x1ZGluZyBhY2Nlc3NvciBkZXNjcmlwdG9ycykgZnJvbSBhIHNvdXJjZQogICAgICAgKiBvYmplY3QgdG8gYSB0YXJnZXQgb2JqZWN0LgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvdG90eXBlIFRhcmdldCBvYmplY3QgdG8gY29weSBwcm9wZXJ0aWVzIHRvLgogICAgICAgKiBAcGFyYW0ge09iamVjdH0gYXBpIFNvdXJjZSBvYmplY3QgdG8gY29weSBwcm9wZXJ0aWVzIGZyb20uCiAgICAgICAqIEByZXR1cm4ge09iamVjdH0gcHJvdG90eXBlIG9iamVjdCB0aGF0IHdhcyBwYXNzZWQgYXMgZmlyc3QgYXJndW1lbnQuCiAgICAgICAqLwogICAgICBleHRlbmQocHJvdG90eXBlLCBhcGkpIHsKICAgICAgICBpZiAoIShwcm90b3R5cGUgJiYgYXBpKSkgewogICAgICAgICAgcmV0dXJuIHByb3RvdHlwZSB8fCBhcGk7CiAgICAgICAgfQogICAgICAgIGxldCBuJCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGFwaSk7CiAgICAgICAgZm9yIChsZXQgaT0wLCBuOyAoaTxuJC5sZW5ndGgpICYmIChuPW4kW2ldKTsgaSsrKSB7CiAgICAgICAgICBsZXQgcGQgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGFwaSwgbik7CiAgICAgICAgICBpZiAocGQpIHsKICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHByb3RvdHlwZSwgbiwgcGQpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gcHJvdG90eXBlOwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ29waWVzIHByb3BzIGZyb20gYSBzb3VyY2Ugb2JqZWN0IHRvIGEgdGFyZ2V0IG9iamVjdC4KICAgICAgICoKICAgICAgICogTm90ZSwgdGhpcyBtZXRob2QgdXNlcyBhIHNpbXBsZSBgZm9yLi4uaW5gIHN0cmF0ZWd5IGZvciBlbnVtZXJhdGluZwogICAgICAgKiBwcm9wZXJ0aWVzLiAgVG8gZW5zdXJlIG9ubHkgYG93blByb3BlcnRpZXNgIGFyZSBjb3BpZWQgZnJvbSBzb3VyY2UKICAgICAgICogdG8gdGFyZ2V0IGFuZCB0aGF0IGFjY2Vzc29yIGltcGxlbWVudGF0aW9ucyBhcmUgY29waWVkLCB1c2UgYGV4dGVuZGAuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7IU9iamVjdH0gdGFyZ2V0IFRhcmdldCBvYmplY3QgdG8gY29weSBwcm9wZXJ0aWVzIHRvLgogICAgICAgKiBAcGFyYW0geyFPYmplY3R9IHNvdXJjZSBTb3VyY2Ugb2JqZWN0IHRvIGNvcHkgcHJvcGVydGllcyBmcm9tLgogICAgICAgKiBAcmV0dXJuIHshT2JqZWN0fSBUYXJnZXQgb2JqZWN0IHRoYXQgd2FzIHBhc3NlZCBhcyBmaXJzdCBhcmd1bWVudC4KICAgICAgICovCiAgICAgIG1peGluKHRhcmdldCwgc291cmNlKSB7CiAgICAgICAgZm9yIChsZXQgaSBpbiBzb3VyY2UpIHsKICAgICAgICAgIHRhcmdldFtpXSA9IHNvdXJjZVtpXTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRhcmdldDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFNldHMgdGhlIHByb3RvdHlwZSBvZiBhbiBvYmplY3QuCiAgICAgICAqCiAgICAgICAqIE5vdGUgdGhpcyBtZXRob2QgaXMgcHJvdmlkZWQgYXMgYmFja3dhcmQtY29tcGF0aWJsZSBsZWdhY3kgQVBJCiAgICAgICAqIG9ubHkuICBJdCBpcyBub3QgZGlyZWN0bHkgY2FsbGVkIGJ5IGFueSBQb2x5bWVyIGZlYXR1cmVzLgogICAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3Qgb24gd2hpY2ggdG8gc2V0IHRoZSBwcm90b3R5cGUuCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwcm90b3R5cGUgVGhlIHByb3RvdHlwZSB0aGF0IHdpbGwgYmUgc2V0IG9uIHRoZSBnaXZlbgogICAgICAgKiBgb2JqZWN0YC4KICAgICAgICogQHJldHVybiB7T2JqZWN0fSBSZXR1cm5zIHRoZSBnaXZlbiBgb2JqZWN0YCB3aXRoIGl0cyBwcm90b3R5cGUgc2V0CiAgICAgICAqIHRvIHRoZSBnaXZlbiBgcHJvdG90eXBlYCBvYmplY3QuCiAgICAgICAqLwogICAgICBjaGFpbk9iamVjdChvYmplY3QsIHByb3RvdHlwZSkgewogICAgICAgIGlmIChvYmplY3QgJiYgcHJvdG90eXBlICYmIG9iamVjdCAhPT0gcHJvdG90eXBlKSB7CiAgICAgICAgICBvYmplY3QuX19wcm90b19fID0gcHJvdG90eXBlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gb2JqZWN0OwogICAgICB9CgogICAgICAvKiAqKioqIEJlZ2luIFRlbXBsYXRlICoqKiogKi8KCiAgICAgIC8qKgogICAgICAgKiBDYWxscyBgaW1wb3J0Tm9kZWAgb24gdGhlIGBjb250ZW50YCBvZiB0aGUgYHRlbXBsYXRlYCBzcGVjaWZpZWQgYW5kCiAgICAgICAqIHJldHVybnMgYSBkb2N1bWVudCBmcmFnbWVudCBjb250YWluaW5nIHRoZSBpbXBvcnRlZCBjb250ZW50LgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge0hUTUxUZW1wbGF0ZUVsZW1lbnR9IHRlbXBsYXRlIEhUTUwgdGVtcGxhdGUgZWxlbWVudCB0byBpbnN0YW5jZS4KICAgICAgICogQHJldHVybiB7IURvY3VtZW50RnJhZ21lbnR9IERvY3VtZW50IGZyYWdtZW50IGNvbnRhaW5pbmcgdGhlIGltcG9ydGVkCiAgICAgICAqICAgdGVtcGxhdGUgY29udGVudC4KICAgICAgKi8KICAgICAgaW5zdGFuY2VUZW1wbGF0ZSh0ZW1wbGF0ZSkgewogICAgICAgIGxldCBjb250ZW50ID0gdGhpcy5jb25zdHJ1Y3Rvci5fY29udGVudEZvclRlbXBsYXRlKHRlbXBsYXRlKTsKICAgICAgICBsZXQgZG9tID0gLyoqIEB0eXBlIHshRG9jdW1lbnRGcmFnbWVudH0gKi8KICAgICAgICAgIChkb2N1bWVudC5pbXBvcnROb2RlKGNvbnRlbnQsIHRydWUpKTsKICAgICAgICByZXR1cm4gZG9tOwogICAgICB9CgogICAgICAvKiAqKioqIEJlZ2luIEV2ZW50cyAqKioqICovCgoKCiAgICAgIC8qKgogICAgICAgKiBEaXNwYXRjaGVzIGEgY3VzdG9tIGV2ZW50IHdpdGggYW4gb3B0aW9uYWwgZGV0YWlsIHZhbHVlLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdHlwZSBOYW1lIG9mIGV2ZW50IHR5cGUuCiAgICAgICAqIEBwYXJhbSB7Kj19IGRldGFpbCBEZXRhaWwgdmFsdWUgY29udGFpbmluZyBldmVudC1zcGVjaWZpYwogICAgICAgKiAgIHBheWxvYWQuCiAgICAgICAqIEBwYXJhbSB7eyBidWJibGVzOiAoYm9vbGVhbnx1bmRlZmluZWQpLCBjYW5jZWxhYmxlOiAoYm9vbGVhbnx1bmRlZmluZWQpLCBjb21wb3NlZDogKGJvb2xlYW58dW5kZWZpbmVkKSB9PX0KICAgICAgICogIG9wdGlvbnMgT2JqZWN0IHNwZWNpZnlpbmcgb3B0aW9ucy4gIFRoZXNlIG1heSBpbmNsdWRlOgogICAgICAgKiAgYGJ1YmJsZXNgIChib29sZWFuLCBkZWZhdWx0cyB0byBgdHJ1ZWApLAogICAgICAgKiAgYGNhbmNlbGFibGVgIChib29sZWFuLCBkZWZhdWx0cyB0byBmYWxzZSksIGFuZAogICAgICAgKiAgYG5vZGVgIG9uIHdoaWNoIHRvIGZpcmUgdGhlIGV2ZW50IChIVE1MRWxlbWVudCwgZGVmYXVsdHMgdG8gYHRoaXNgKS4KICAgICAgICogQHJldHVybiB7IUV2ZW50fSBUaGUgbmV3IGV2ZW50IHRoYXQgd2FzIGZpcmVkLgogICAgICAgKi8KICAgICAgZmlyZSh0eXBlLCBkZXRhaWwsIG9wdGlvbnMpIHsKICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKICAgICAgICBkZXRhaWwgPSAoZGV0YWlsID09PSBudWxsIHx8IGRldGFpbCA9PT0gdW5kZWZpbmVkKSA/IHt9IDogZGV0YWlsOwogICAgICAgIGxldCBldmVudCA9IG5ldyBFdmVudCh0eXBlLCB7CiAgICAgICAgICBidWJibGVzOiBvcHRpb25zLmJ1YmJsZXMgPT09IHVuZGVmaW5lZCA/IHRydWUgOiBvcHRpb25zLmJ1YmJsZXMsCiAgICAgICAgICBjYW5jZWxhYmxlOiBCb29sZWFuKG9wdGlvbnMuY2FuY2VsYWJsZSksCiAgICAgICAgICBjb21wb3NlZDogb3B0aW9ucy5jb21wb3NlZCA9PT0gdW5kZWZpbmVkID8gdHJ1ZTogb3B0aW9ucy5jb21wb3NlZAogICAgICAgIH0pOwogICAgICAgIGV2ZW50LmRldGFpbCA9IGRldGFpbDsKICAgICAgICBsZXQgbm9kZSA9IG9wdGlvbnMubm9kZSB8fCB0aGlzOwogICAgICAgIG5vZGUuZGlzcGF0Y2hFdmVudChldmVudCk7CiAgICAgICAgcmV0dXJuIGV2ZW50OwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ29udmVuaWVuY2UgbWV0aG9kIHRvIGFkZCBhbiBldmVudCBsaXN0ZW5lciBvbiBhIGdpdmVuIGVsZW1lbnQsCiAgICAgICAqIGxhdGUgYm91bmQgdG8gYSBuYW1lZCBtZXRob2Qgb24gdGhpcyBlbGVtZW50LgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge0VsZW1lbnR9IG5vZGUgRWxlbWVudCB0byBhZGQgZXZlbnQgbGlzdGVuZXIgdG8uCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWUgTmFtZSBvZiBldmVudCB0byBsaXN0ZW4gZm9yLgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbWV0aG9kTmFtZSBOYW1lIG9mIGhhbmRsZXIgbWV0aG9kIG9uIGB0aGlzYCB0byBjYWxsLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgbGlzdGVuKG5vZGUsIGV2ZW50TmFtZSwgbWV0aG9kTmFtZSkgewogICAgICAgIG5vZGUgPSAvKiogQHR5cGUgeyFFbGVtZW50fSAqLyAobm9kZSB8fCB0aGlzKTsKICAgICAgICBsZXQgaGJsID0gdGhpcy5fX2JvdW5kTGlzdGVuZXJzIHx8CiAgICAgICAgICAodGhpcy5fX2JvdW5kTGlzdGVuZXJzID0gbmV3IFdlYWtNYXAoKSk7CiAgICAgICAgbGV0IGJsID0gaGJsLmdldChub2RlKTsKICAgICAgICBpZiAoIWJsKSB7CiAgICAgICAgICBibCA9IHt9OwogICAgICAgICAgaGJsLnNldChub2RlLCBibCk7CiAgICAgICAgfQogICAgICAgIGxldCBrZXkgPSBldmVudE5hbWUgKyBtZXRob2ROYW1lOwogICAgICAgIGlmICghYmxba2V5XSkgewogICAgICAgICAgYmxba2V5XSA9IHRoaXMuX2FkZE1ldGhvZEV2ZW50TGlzdGVuZXJUb05vZGUoCiAgICAgICAgICAgIG5vZGUsIGV2ZW50TmFtZSwgbWV0aG9kTmFtZSwgdGhpcyk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogQ29udmVuaWVuY2UgbWV0aG9kIHRvIHJlbW92ZSBhbiBldmVudCBsaXN0ZW5lciBmcm9tIGEgZ2l2ZW4gZWxlbWVudCwKICAgICAgICogbGF0ZSBib3VuZCB0byBhIG5hbWVkIG1ldGhvZCBvbiB0aGlzIGVsZW1lbnQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7RWxlbWVudH0gbm9kZSBFbGVtZW50IHRvIHJlbW92ZSBldmVudCBsaXN0ZW5lciBmcm9tLgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lIE5hbWUgb2YgZXZlbnQgdG8gc3RvcCBsaXN0ZW5pbmcgdG8uCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtZXRob2ROYW1lIE5hbWUgb2YgaGFuZGxlciBtZXRob2Qgb24gYHRoaXNgIHRvIG5vdCBjYWxsCiAgICAgICBhbnltb3JlLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgdW5saXN0ZW4obm9kZSwgZXZlbnROYW1lLCBtZXRob2ROYW1lKSB7CiAgICAgICAgbm9kZSA9IC8qKiBAdHlwZSB7IUVsZW1lbnR9ICovIChub2RlIHx8IHRoaXMpOwogICAgICAgIGxldCBibCA9IHRoaXMuX19ib3VuZExpc3RlbmVycyAmJiB0aGlzLl9fYm91bmRMaXN0ZW5lcnMuZ2V0KG5vZGUpOwogICAgICAgIGxldCBrZXkgPSBldmVudE5hbWUgKyBtZXRob2ROYW1lOwogICAgICAgIGxldCBoYW5kbGVyID0gYmwgJiYgYmxba2V5XTsKICAgICAgICBpZiAoaGFuZGxlcikgewogICAgICAgICAgdGhpcy5fcmVtb3ZlRXZlbnRMaXN0ZW5lckZyb21Ob2RlKG5vZGUsIGV2ZW50TmFtZSwgaGFuZGxlcik7CiAgICAgICAgICBibFtrZXldID0gbnVsbDsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZSBzY3JvbGxpbmcgYmVoYXZpb3IgdG8gYWxsIGRpcmVjdGlvbiwgb25lIGRpcmVjdGlvbiwgb3Igbm9uZS4KICAgICAgICoKICAgICAgICogVmFsaWQgc2Nyb2xsIGRpcmVjdGlvbnM6CiAgICAgICAqICAgLSAnYWxsJzogc2Nyb2xsIGluIGFueSBkaXJlY3Rpb24KICAgICAgICogICAtICd4Jzogc2Nyb2xsIG9ubHkgaW4gdGhlICd4JyBkaXJlY3Rpb24KICAgICAgICogICAtICd5Jzogc2Nyb2xsIG9ubHkgaW4gdGhlICd5JyBkaXJlY3Rpb24KICAgICAgICogICAtICdub25lJzogZGlzYWJsZSBzY3JvbGxpbmcgZm9yIHRoaXMgbm9kZQogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZz19IGRpcmVjdGlvbiBEaXJlY3Rpb24gdG8gYWxsb3cgc2Nyb2xsaW5nCiAgICAgICAqIERlZmF1bHRzIHRvIGBhbGxgLgogICAgICAgKiBAcGFyYW0ge0VsZW1lbnQ9fSBub2RlIEVsZW1lbnQgdG8gYXBwbHkgc2Nyb2xsIGRpcmVjdGlvbiBzZXR0aW5nLgogICAgICAgKiBEZWZhdWx0cyB0byBgdGhpc2AuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBzZXRTY3JvbGxEaXJlY3Rpb24oZGlyZWN0aW9uLCBub2RlKSB7CiAgICAgICAgUG9seW1lci5HZXN0dXJlcy5zZXRUb3VjaEFjdGlvbigvKiogQHR5cGUge0VsZW1lbnR9ICovIChub2RlIHx8IHRoaXMpLCBESVJFQ1RJT05fTUFQW2RpcmVjdGlvbl0gfHwgJ2F1dG8nKTsKICAgICAgfQogICAgICAvKiAqKioqIEVuZCBFdmVudHMgKioqKiAqLwoKICAgICAgLyoqCiAgICAgICAqIENvbnZlbmllbmNlIG1ldGhvZCB0byBydW4gYHF1ZXJ5U2VsZWN0b3JgIG9uIHRoaXMgbG9jYWwgRE9NIHNjb3BlLgogICAgICAgKgogICAgICAgKiBUaGlzIGZ1bmN0aW9uIGNhbGxzIGBQb2x5bWVyLmRvbSh0aGlzLnJvb3QpLnF1ZXJ5U2VsZWN0b3Ioc2xjdHIpYC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHNsY3RyIFNlbGVjdG9yIHRvIHJ1biBvbiB0aGlzIGxvY2FsIERPTSBzY29wZQogICAgICAgKiBAcmV0dXJuIHtFbGVtZW50fSBFbGVtZW50IGZvdW5kIGJ5IHRoZSBzZWxlY3Rvciwgb3IgbnVsbCBpZiBub3QgZm91bmQuCiAgICAgICAqLwogICAgICAkJChzbGN0cikgewogICAgICAgIHJldHVybiB0aGlzLnJvb3QucXVlcnlTZWxlY3RvcihzbGN0cik7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm4gdGhlIGVsZW1lbnQgd2hvc2UgbG9jYWwgZG9tIHdpdGhpbiB3aGljaCB0aGlzIGVsZW1lbnQKICAgICAgICogaXMgY29udGFpbmVkLiBUaGlzIGlzIGEgc2hvcnRoYW5kIGZvcgogICAgICAgKiBgdGhpcy5nZXRSb290Tm9kZSgpLmhvc3RgLgogICAgICAgKiBAdGhpcyB7RWxlbWVudH0KICAgICAgICovCiAgICAgIGdldCBkb21Ib3N0KCkgewogICAgICAgIGxldCByb290ID0gdGhpcy5nZXRSb290Tm9kZSgpOwogICAgICAgIHJldHVybiAocm9vdCBpbnN0YW5jZW9mIERvY3VtZW50RnJhZ21lbnQpID8gLyoqIEB0eXBlIHtTaGFkb3dSb290fSAqLyAocm9vdCkuaG9zdCA6IHJvb3Q7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBGb3JjZSB0aGlzIGVsZW1lbnQgdG8gZGlzdHJpYnV0ZSBpdHMgY2hpbGRyZW4gdG8gaXRzIGxvY2FsIGRvbS4KICAgICAgICogVGhpcyBzaG91bGQgbm90IGJlIG5lY2Vzc2FyeSBhcyBvZiBQb2x5bWVyIDIuMC4yIGFuZCBpcyBwcm92aWRlZCBvbmx5CiAgICAgICAqIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIGRpc3RyaWJ1dGVDb250ZW50KCkgewogICAgICAgIGlmICh3aW5kb3cuU2hhZHlET00gJiYgdGhpcy5zaGFkb3dSb290KSB7CiAgICAgICAgICBTaGFkeURPTS5mbHVzaCgpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgYSBsaXN0IG9mIG5vZGVzIHRoYXQgYXJlIHRoZSBlZmZlY3RpdmUgY2hpbGROb2Rlcy4gVGhlIGVmZmVjdGl2ZQogICAgICAgKiBjaGlsZE5vZGVzIGxpc3QgaXMgdGhlIHNhbWUgYXMgdGhlIGVsZW1lbnQncyBjaGlsZE5vZGVzIGV4Y2VwdCB0aGF0CiAgICAgICAqIGFueSBgPGNvbnRlbnQ+YCBlbGVtZW50cyBhcmUgcmVwbGFjZWQgd2l0aCB0aGUgbGlzdCBvZiBub2RlcyBkaXN0cmlidXRlZAogICAgICAgKiB0byB0aGUgYDxjb250ZW50PmAsIHRoZSByZXN1bHQgb2YgaXRzIGBnZXREaXN0cmlidXRlZE5vZGVzYCBtZXRob2QuCiAgICAgICAqIEByZXR1cm4geyFBcnJheTwhTm9kZT59IExpc3Qgb2YgZWZmZWN0aXZlIGNoaWxkIG5vZGVzLgogICAgICAgKiBAc3VwcHJlc3Mge2ludmFsaWRDYXN0c30gTGVnYWN5RWxlbWVudE1peGluIG11c3QgYmUgYXBwbGllZCB0byBhbiBIVE1MRWxlbWVudAogICAgICAgKi8KICAgICAgZ2V0RWZmZWN0aXZlQ2hpbGROb2RlcygpIHsKICAgICAgICBjb25zdCB0aGlzRWwgPSAvKiogQHR5cGUge0VsZW1lbnR9ICovICh0aGlzKTsKICAgICAgICBjb25zdCBkb21BcGkgPSAvKiogQHR5cGUge1BvbHltZXIuRG9tQXBpfSAqLyhQb2x5bWVyLmRvbSh0aGlzRWwpKTsKICAgICAgICByZXR1cm4gZG9tQXBpLmdldEVmZmVjdGl2ZUNoaWxkTm9kZXMoKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgYSBsaXN0IG9mIG5vZGVzIGRpc3RyaWJ1dGVkIHdpdGhpbiB0aGlzIGVsZW1lbnQgdGhhdCBtYXRjaAogICAgICAgKiBgc2VsZWN0b3JgLiBUaGVzZSBjYW4gYmUgZG9tIGNoaWxkcmVuIG9yIGVsZW1lbnRzIGRpc3RyaWJ1dGVkIHRvCiAgICAgICAqIGNoaWxkcmVuIHRoYXQgYXJlIGluc2VydGlvbiBwb2ludHMuCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzZWxlY3RvciBTZWxlY3RvciB0byBydW4uCiAgICAgICAqIEByZXR1cm4geyFBcnJheTwhTm9kZT59IExpc3Qgb2YgZGlzdHJpYnV0ZWQgZWxlbWVudHMgdGhhdCBtYXRjaCBzZWxlY3Rvci4KICAgICAgICogQHN1cHByZXNzIHtpbnZhbGlkQ2FzdHN9IExlZ2FjeUVsZW1lbnRNaXhpbiBtdXN0IGJlIGFwcGxpZWQgdG8gYW4gSFRNTEVsZW1lbnQKICAgICAgICovCiAgICAgIHF1ZXJ5RGlzdHJpYnV0ZWRFbGVtZW50cyhzZWxlY3RvcikgewogICAgICAgIGNvbnN0IHRoaXNFbCA9IC8qKiBAdHlwZSB7RWxlbWVudH0gKi8gKHRoaXMpOwogICAgICAgIGNvbnN0IGRvbUFwaSA9IC8qKiBAdHlwZSB7UG9seW1lci5Eb21BcGl9ICovKFBvbHltZXIuZG9tKHRoaXNFbCkpOwogICAgICAgIHJldHVybiBkb21BcGkucXVlcnlEaXN0cmlidXRlZEVsZW1lbnRzKHNlbGVjdG9yKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgYSBsaXN0IG9mIGVsZW1lbnRzIHRoYXQgYXJlIHRoZSBlZmZlY3RpdmUgY2hpbGRyZW4uIFRoZSBlZmZlY3RpdmUKICAgICAgICogY2hpbGRyZW4gbGlzdCBpcyB0aGUgc2FtZSBhcyB0aGUgZWxlbWVudCdzIGNoaWxkcmVuIGV4Y2VwdCB0aGF0CiAgICAgICAqIGFueSBgPGNvbnRlbnQ+YCBlbGVtZW50cyBhcmUgcmVwbGFjZWQgd2l0aCB0aGUgbGlzdCBvZiBlbGVtZW50cwogICAgICAgKiBkaXN0cmlidXRlZCB0byB0aGUgYDxjb250ZW50PmAuCiAgICAgICAqCiAgICAgICAqIEByZXR1cm4geyFBcnJheTwhTm9kZT59IExpc3Qgb2YgZWZmZWN0aXZlIGNoaWxkcmVuLgogICAgICAgKi8KICAgICAgZ2V0RWZmZWN0aXZlQ2hpbGRyZW4oKSB7CiAgICAgICAgbGV0IGxpc3QgPSB0aGlzLmdldEVmZmVjdGl2ZUNoaWxkTm9kZXMoKTsKICAgICAgICByZXR1cm4gbGlzdC5maWx0ZXIoZnVuY3Rpb24oLyoqIEB0eXBlIHshTm9kZX0gKi8gbikgewogICAgICAgICAgcmV0dXJuIChuLm5vZGVUeXBlID09PSBOb2RlLkVMRU1FTlRfTk9ERSk7CiAgICAgICAgfSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIGEgc3RyaW5nIG9mIHRleHQgY29udGVudCB0aGF0IGlzIHRoZSBjb25jYXRlbmF0aW9uIG9mIHRoZQogICAgICAgKiB0ZXh0IGNvbnRlbnQncyBvZiB0aGUgZWxlbWVudCdzIGVmZmVjdGl2ZSBjaGlsZE5vZGVzICh0aGUgZWxlbWVudHMKICAgICAgICogcmV0dXJuZWQgYnkgPGEgaHJlZj0iI2dldEVmZmVjdGl2ZUNoaWxkTm9kZXM+Z2V0RWZmZWN0aXZlQ2hpbGROb2RlczwvYT4uCiAgICAgICAqCiAgICAgICAqIEByZXR1cm4ge3N0cmluZ30gTGlzdCBvZiBlZmZlY3RpdmUgY2hpbGRyZW4uCiAgICAgICAqLwogICAgICBnZXRFZmZlY3RpdmVUZXh0Q29udGVudCgpIHsKICAgICAgICBsZXQgY24gPSB0aGlzLmdldEVmZmVjdGl2ZUNoaWxkTm9kZXMoKTsKICAgICAgICBsZXQgdGMgPSBbXTsKICAgICAgICBmb3IgKGxldCBpPTAsIGM7IChjID0gY25baV0pOyBpKyspIHsKICAgICAgICAgIGlmIChjLm5vZGVUeXBlICE9PSBOb2RlLkNPTU1FTlRfTk9ERSkgewogICAgICAgICAgICB0Yy5wdXNoKGMudGV4dENvbnRlbnQpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gdGMuam9pbignJyk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHRoZSBmaXJzdCBlZmZlY3RpdmUgY2hpbGROb2RlIHdpdGhpbiB0aGlzIGVsZW1lbnQgdGhhdAogICAgICAgKiBtYXRjaCBgc2VsZWN0b3JgLiBUaGVzZSBjYW4gYmUgZG9tIGNoaWxkIG5vZGVzIG9yIGVsZW1lbnRzIGRpc3RyaWJ1dGVkCiAgICAgICAqIHRvIGNoaWxkcmVuIHRoYXQgYXJlIGluc2VydGlvbiBwb2ludHMuCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzZWxlY3RvciBTZWxlY3RvciB0byBydW4uCiAgICAgICAqIEByZXR1cm4ge05vZGV9IEZpcnN0IGVmZmVjdGl2ZSBjaGlsZCBub2RlIHRoYXQgbWF0Y2hlcyBzZWxlY3Rvci4KICAgICAgICovCiAgICAgIHF1ZXJ5RWZmZWN0aXZlQ2hpbGRyZW4oc2VsZWN0b3IpIHsKICAgICAgICBsZXQgZSQgPSB0aGlzLnF1ZXJ5RGlzdHJpYnV0ZWRFbGVtZW50cyhzZWxlY3Rvcik7CiAgICAgICAgcmV0dXJuIGUkICYmIGUkWzBdOwogICAgICB9CgogICAgICAvKioKICAgICAgICogUmV0dXJucyBhIGxpc3Qgb2YgZWZmZWN0aXZlIGNoaWxkTm9kZXMgd2l0aGluIHRoaXMgZWxlbWVudCB0aGF0CiAgICAgICAqIG1hdGNoIGBzZWxlY3RvcmAuIFRoZXNlIGNhbiBiZSBkb20gY2hpbGQgbm9kZXMgb3IgZWxlbWVudHMgZGlzdHJpYnV0ZWQKICAgICAgICogdG8gY2hpbGRyZW4gdGhhdCBhcmUgaW5zZXJ0aW9uIHBvaW50cy4KICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHNlbGVjdG9yIFNlbGVjdG9yIHRvIHJ1bi4KICAgICAgICogQHJldHVybiB7IUFycmF5PCFOb2RlPn0gTGlzdCBvZiBlZmZlY3RpdmUgY2hpbGQgbm9kZXMgdGhhdCBtYXRjaCBzZWxlY3Rvci4KICAgICAgICovCiAgICAgIHF1ZXJ5QWxsRWZmZWN0aXZlQ2hpbGRyZW4oc2VsZWN0b3IpIHsKICAgICAgICByZXR1cm4gdGhpcy5xdWVyeURpc3RyaWJ1dGVkRWxlbWVudHMoc2VsZWN0b3IpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogUmV0dXJucyBhIGxpc3Qgb2Ygbm9kZXMgZGlzdHJpYnV0ZWQgdG8gdGhpcyBlbGVtZW50J3MgYDxzbG90PmAuCiAgICAgICAqCiAgICAgICAqIElmIHRoaXMgZWxlbWVudCBjb250YWlucyBtb3JlIHRoYW4gb25lIGA8c2xvdD5gIGluIGl0cyBsb2NhbCBET00sCiAgICAgICAqIGFuIG9wdGlvbmFsIHNlbGVjdG9yIG1heSBiZSBwYXNzZWQgdG8gY2hvb3NlIHRoZSBkZXNpcmVkIGNvbnRlbnQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nPX0gc2xjdHIgQ1NTIHNlbGVjdG9yIHRvIGNob29zZSB0aGUgZGVzaXJlZAogICAgICAgKiAgIGA8c2xvdD5gLiAgRGVmYXVsdHMgdG8gYGNvbnRlbnRgLgogICAgICAgKiBAcmV0dXJuIHshQXJyYXk8IU5vZGU+fSBMaXN0IG9mIGRpc3RyaWJ1dGVkIG5vZGVzIGZvciB0aGUgYDxzbG90PmAuCiAgICAgICAqLwogICAgICBnZXRDb250ZW50Q2hpbGROb2RlcyhzbGN0cikgewogICAgICAgIGxldCBjb250ZW50ID0gdGhpcy5yb290LnF1ZXJ5U2VsZWN0b3Ioc2xjdHIgfHwgJ3Nsb3QnKTsKICAgICAgICByZXR1cm4gY29udGVudCA/IC8qKiBAdHlwZSB7UG9seW1lci5Eb21BcGl9ICovKFBvbHltZXIuZG9tKGNvbnRlbnQpKS5nZXREaXN0cmlidXRlZE5vZGVzKCkgOiBbXTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgYSBsaXN0IG9mIGVsZW1lbnQgY2hpbGRyZW4gZGlzdHJpYnV0ZWQgdG8gdGhpcyBlbGVtZW50J3MKICAgICAgICogYDxzbG90PmAuCiAgICAgICAqCiAgICAgICAqIElmIHRoaXMgZWxlbWVudCBjb250YWlucyBtb3JlIHRoYW4gb25lIGA8c2xvdD5gIGluIGl0cwogICAgICAgKiBsb2NhbCBET00sIGFuIG9wdGlvbmFsIHNlbGVjdG9yIG1heSBiZSBwYXNzZWQgdG8gY2hvb3NlIHRoZSBkZXNpcmVkCiAgICAgICAqIGNvbnRlbnQuICBUaGlzIG1ldGhvZCBkaWZmZXJzIGZyb20gYGdldENvbnRlbnRDaGlsZE5vZGVzYCBpbiB0aGF0IG9ubHkKICAgICAgICogZWxlbWVudHMgYXJlIHJldHVybmVkLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZz19IHNsY3RyIENTUyBzZWxlY3RvciB0byBjaG9vc2UgdGhlIGRlc2lyZWQKICAgICAgICogICBgPGNvbnRlbnQ+YC4gIERlZmF1bHRzIHRvIGBjb250ZW50YC4KICAgICAgICogQHJldHVybiB7IUFycmF5PCFIVE1MRWxlbWVudD59IExpc3Qgb2YgZGlzdHJpYnV0ZWQgbm9kZXMgZm9yIHRoZQogICAgICAgKiAgIGA8c2xvdD5gLgogICAgICAgKiBAc3VwcHJlc3Mge2ludmFsaWRDYXN0c30KICAgICAgICovCiAgICAgIGdldENvbnRlbnRDaGlsZHJlbihzbGN0cikgewogICAgICAgIGxldCBjaGlsZHJlbiA9IC8qKiBAdHlwZSB7IUFycmF5PCFIVE1MRWxlbWVudD59ICovKHRoaXMuZ2V0Q29udGVudENoaWxkTm9kZXMoc2xjdHIpLmZpbHRlcihmdW5jdGlvbihuKSB7CiAgICAgICAgICByZXR1cm4gKG4ubm9kZVR5cGUgPT09IE5vZGUuRUxFTUVOVF9OT0RFKTsKICAgICAgICB9KSk7CiAgICAgICAgcmV0dXJuIGNoaWxkcmVuOwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ2hlY2tzIHdoZXRoZXIgYW4gZWxlbWVudCBpcyBpbiB0aGlzIGVsZW1lbnQncyBsaWdodCBET00gdHJlZS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHs/Tm9kZX0gbm9kZSBUaGUgZWxlbWVudCB0byBiZSBjaGVja2VkLgogICAgICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIG5vZGUgaXMgaW4gdGhpcyBlbGVtZW50J3MgbGlnaHQgRE9NIHRyZWUuCiAgICAgICAqIEBzdXBwcmVzcyB7aW52YWxpZENhc3RzfSBMZWdhY3lFbGVtZW50TWl4aW4gbXVzdCBiZSBhcHBsaWVkIHRvIGFuIEhUTUxFbGVtZW50CiAgICAgICAqLwogICAgICBpc0xpZ2h0RGVzY2VuZGFudChub2RlKSB7CiAgICAgICAgY29uc3QgdGhpc05vZGUgPSAvKiogQHR5cGUge05vZGV9ICovICh0aGlzKTsKICAgICAgICByZXR1cm4gdGhpc05vZGUgIT09IG5vZGUgJiYgdGhpc05vZGUuY29udGFpbnMobm9kZSkgJiYKICAgICAgICAgIHRoaXNOb2RlLmdldFJvb3ROb2RlKCkgPT09IG5vZGUuZ2V0Um9vdE5vZGUoKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENoZWNrcyB3aGV0aGVyIGFuIGVsZW1lbnQgaXMgaW4gdGhpcyBlbGVtZW50J3MgbG9jYWwgRE9NIHRyZWUuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7IUVsZW1lbnR9IG5vZGUgVGhlIGVsZW1lbnQgdG8gYmUgY2hlY2tlZC4KICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiBub2RlIGlzIGluIHRoaXMgZWxlbWVudCdzIGxvY2FsIERPTSB0cmVlLgogICAgICAgKi8KICAgICAgaXNMb2NhbERlc2NlbmRhbnQobm9kZSkgewogICAgICAgIHJldHVybiB0aGlzLnJvb3QgPT09IG5vZGUuZ2V0Um9vdE5vZGUoKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIE5vLW9wIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS4gVGhpcyBzaG91bGQgbm93IGJlIGhhbmRsZWQgYnkKICAgICAgICogU2hhZHlDc3MgbGlicmFyeS4KICAgICAgICogQHBhcmFtICB7Kn0gY29udGFpbmVyIFVudXNlZAogICAgICAgKiBAcGFyYW0gIHsqfSBzaG91bGRPYnNlcnZlIFVudXNlZAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgc2NvcGVTdWJ0cmVlKGNvbnRhaW5lciwgc2hvdWxkT2JzZXJ2ZSkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzCiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHRoZSBjb21wdXRlZCBzdHlsZSB2YWx1ZSBmb3IgdGhlIGdpdmVuIHByb3BlcnR5LgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgVGhlIGNzcyBwcm9wZXJ0eSBuYW1lLgogICAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFJldHVybnMgdGhlIGNvbXB1dGVkIGNzcyBwcm9wZXJ0eSB2YWx1ZSBmb3IgdGhlIGdpdmVuCiAgICAgICAqIGBwcm9wZXJ0eWAuCiAgICAgICAqIEBzdXBwcmVzcyB7aW52YWxpZENhc3RzfSBMZWdhY3lFbGVtZW50TWl4aW4gbXVzdCBiZSBhcHBsaWVkIHRvIGFuIEhUTUxFbGVtZW50CiAgICAgICAqLwogICAgICBnZXRDb21wdXRlZFN0eWxlVmFsdWUocHJvcGVydHkpIHsKICAgICAgICByZXR1cm4gc3R5bGVJbnRlcmZhY2UuZ2V0Q29tcHV0ZWRTdHlsZVZhbHVlKC8qKiBAdHlwZSB7IUVsZW1lbnR9ICovKHRoaXMpLCBwcm9wZXJ0eSk7CiAgICAgIH0KCiAgICAgIC8vIGRlYm91bmNlCgogICAgICAvKioKICAgICAgICogQ2FsbCBgZGVib3VuY2VgIHRvIGNvbGxhcHNlIG11bHRpcGxlIHJlcXVlc3RzIGZvciBhIG5hbWVkIHRhc2sgaW50bwogICAgICAgKiBvbmUgaW52b2NhdGlvbiB3aGljaCBpcyBtYWRlIGFmdGVyIHRoZSB3YWl0IHRpbWUgaGFzIGVsYXBzZWQgd2l0aAogICAgICAgKiBubyBuZXcgcmVxdWVzdC4gIElmIG5vIHdhaXQgdGltZSBpcyBnaXZlbiwgdGhlIGNhbGxiYWNrIHdpbGwgYmUgY2FsbGVkCiAgICAgICAqIGF0IG1pY3JvdGFzayB0aW1pbmcgKGd1YXJhbnRlZWQgYmVmb3JlIHBhaW50KS4KICAgICAgICoKICAgICAgICogICAgIGRlYm91bmNlZENsaWNrQWN0aW9uKGUpIHsKICAgICAgICogICAgICAgLy8gd2lsbCBub3QgY2FsbCBgcHJvY2Vzc0NsaWNrYCBtb3JlIHRoYW4gb25jZSBwZXIgMTAwbXMKICAgICAgICogICAgICAgdGhpcy5kZWJvdW5jZSgnY2xpY2snLCBmdW5jdGlvbigpIHsKICAgICAgICogICAgICAgIHRoaXMucHJvY2Vzc0NsaWNrKCk7CiAgICAgICAqICAgICAgIH0gMTAwKTsKICAgICAgICogICAgIH0KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGpvYk5hbWUgU3RyaW5nIHRvIGlkZW50aWZ5IHRoZSBkZWJvdW5jZSBqb2IuCiAgICAgICAqIEBwYXJhbSB7ZnVuY3Rpb24oKTp2b2lkfSBjYWxsYmFjayBGdW5jdGlvbiB0aGF0IGlzIGNhbGxlZCAod2l0aCBgdGhpc2AKICAgICAgICogICBjb250ZXh0KSB3aGVuIHRoZSB3YWl0IHRpbWUgZWxhcHNlcy4KICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHdhaXQgT3B0aW9uYWwgd2FpdCB0aW1lIGluIG1pbGxpc2Vjb25kcyAobXMpIGFmdGVyIHRoZQogICAgICAgKiAgIGxhc3Qgc2lnbmFsIHRoYXQgbXVzdCBlbGFwc2UgYmVmb3JlIGludm9raW5nIGBjYWxsYmFja2AKICAgICAgICogQHJldHVybiB7IU9iamVjdH0gUmV0dXJucyBhIGRlYm91bmNlciBvYmplY3Qgb24gd2hpY2ggZXhpc3RzIHRoZQogICAgICAgKiBmb2xsb3dpbmcgbWV0aG9kczogYGlzQWN0aXZlKClgIHJldHVybnMgdHJ1ZSBpZiB0aGUgZGVib3VuY2VyIGlzCiAgICAgICAqIGFjdGl2ZTsgYGNhbmNlbCgpYCBjYW5jZWxzIHRoZSBkZWJvdW5jZXIgaWYgaXQgaXMgYWN0aXZlOwogICAgICAgKiBgZmx1c2goKWAgaW1tZWRpYXRlbHkgaW52b2tlcyB0aGUgZGVib3VuY2VkIGNhbGxiYWNrIGlmIHRoZSBkZWJvdW5jZXIKICAgICAgICogaXMgYWN0aXZlLgogICAgICAgKi8KICAgICAgZGVib3VuY2Uoam9iTmFtZSwgY2FsbGJhY2ssIHdhaXQpIHsKICAgICAgICB0aGlzLl9kZWJvdW5jZXJzID0gdGhpcy5fZGVib3VuY2VycyB8fCB7fTsKICAgICAgICByZXR1cm4gdGhpcy5fZGVib3VuY2Vyc1tqb2JOYW1lXSA9IFBvbHltZXIuRGVib3VuY2VyLmRlYm91bmNlKAogICAgICAgICAgICAgIHRoaXMuX2RlYm91bmNlcnNbam9iTmFtZV0KICAgICAgICAgICAgLCB3YWl0ID4gMCA/IFBvbHltZXIuQXN5bmMudGltZU91dC5hZnRlcih3YWl0KSA6IFBvbHltZXIuQXN5bmMubWljcm9UYXNrCiAgICAgICAgICAgICwgY2FsbGJhY2suYmluZCh0aGlzKSk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHdoZXRoZXIgYSBuYW1lZCBkZWJvdW5jZXIgaXMgYWN0aXZlLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gam9iTmFtZSBUaGUgbmFtZSBvZiB0aGUgZGVib3VuY2VyIHN0YXJ0ZWQgd2l0aCBgZGVib3VuY2VgCiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgdGhlIGRlYm91bmNlciBpcyBhY3RpdmUgKGhhcyBub3QgeWV0IGZpcmVkKS4KICAgICAgICovCiAgICAgIGlzRGVib3VuY2VyQWN0aXZlKGpvYk5hbWUpIHsKICAgICAgICB0aGlzLl9kZWJvdW5jZXJzID0gdGhpcy5fZGVib3VuY2VycyB8fCB7fTsKICAgICAgICBsZXQgZGVib3VuY2VyID0gdGhpcy5fZGVib3VuY2Vyc1tqb2JOYW1lXTsKICAgICAgICByZXR1cm4gISEoZGVib3VuY2VyICYmIGRlYm91bmNlci5pc0FjdGl2ZSgpKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEltbWVkaWF0ZWx5IGNhbGxzIHRoZSBkZWJvdW5jZXIgYGNhbGxiYWNrYCBhbmQgaW5hY3RpdmF0ZXMgaXQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBqb2JOYW1lIFRoZSBuYW1lIG9mIHRoZSBkZWJvdW5jZXIgc3RhcnRlZCB3aXRoIGBkZWJvdW5jZWAKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIGZsdXNoRGVib3VuY2VyKGpvYk5hbWUpIHsKICAgICAgICB0aGlzLl9kZWJvdW5jZXJzID0gdGhpcy5fZGVib3VuY2VycyB8fCB7fTsKICAgICAgICBsZXQgZGVib3VuY2VyID0gdGhpcy5fZGVib3VuY2Vyc1tqb2JOYW1lXTsKICAgICAgICBpZiAoZGVib3VuY2VyKSB7CiAgICAgICAgICBkZWJvdW5jZXIuZmx1c2goKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBDYW5jZWxzIGFuIGFjdGl2ZSBkZWJvdW5jZXIuICBUaGUgYGNhbGxiYWNrYCB3aWxsIG5vdCBiZSBjYWxsZWQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBqb2JOYW1lIFRoZSBuYW1lIG9mIHRoZSBkZWJvdW5jZXIgc3RhcnRlZCB3aXRoIGBkZWJvdW5jZWAKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIGNhbmNlbERlYm91bmNlcihqb2JOYW1lKSB7CiAgICAgICAgdGhpcy5fZGVib3VuY2VycyA9IHRoaXMuX2RlYm91bmNlcnMgfHwge307CiAgICAgICAgbGV0IGRlYm91bmNlciA9IHRoaXMuX2RlYm91bmNlcnNbam9iTmFtZV07CiAgICAgICAgaWYgKGRlYm91bmNlcikgewogICAgICAgICAgZGVib3VuY2VyLmNhbmNlbCgpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJ1bnMgYSBjYWxsYmFjayBmdW5jdGlvbiBhc3luY2hyb25vdXNseS4KICAgICAgICoKICAgICAgICogQnkgZGVmYXVsdCAoaWYgbm8gd2FpdFRpbWUgaXMgc3BlY2lmaWVkKSwgYXN5bmMgY2FsbGJhY2tzIGFyZSBydW4gYXQKICAgICAgICogbWljcm90YXNrIHRpbWluZywgd2hpY2ggd2lsbCBvY2N1ciBiZWZvcmUgcGFpbnQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7IUZ1bmN0aW9ufSBjYWxsYmFjayBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gcnVuLCBib3VuZCB0byBgdGhpc2AuCiAgICAgICAqIEBwYXJhbSB7bnVtYmVyPX0gd2FpdFRpbWUgVGltZSB0byB3YWl0IGJlZm9yZSBjYWxsaW5nIHRoZQogICAgICAgKiAgIGBjYWxsYmFja2AuICBJZiB1bnNwZWNpZmllZCBvciAwLCB0aGUgY2FsbGJhY2sgd2lsbCBiZSBydW4gYXQgbWljcm90YXNrCiAgICAgICAqICAgdGltaW5nIChiZWZvcmUgcGFpbnQpLgogICAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IEhhbmRsZSB0aGF0IG1heSBiZSB1c2VkIHRvIGNhbmNlbCB0aGUgYXN5bmMgam9iLgogICAgICAgKi8KICAgICAgYXN5bmMoY2FsbGJhY2ssIHdhaXRUaW1lKSB7CiAgICAgICAgcmV0dXJuIHdhaXRUaW1lID4gMCA/IFBvbHltZXIuQXN5bmMudGltZU91dC5ydW4oY2FsbGJhY2suYmluZCh0aGlzKSwgd2FpdFRpbWUpIDoKICAgICAgICAgICAgflBvbHltZXIuQXN5bmMubWljcm9UYXNrLnJ1bihjYWxsYmFjay5iaW5kKHRoaXMpKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENhbmNlbHMgYW4gYXN5bmMgb3BlcmF0aW9uIHN0YXJ0ZWQgd2l0aCBgYXN5bmNgLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGFuZGxlIEhhbmRsZSByZXR1cm5lZCBmcm9tIG9yaWdpbmFsIGBhc3luY2AgY2FsbCB0bwogICAgICAgKiAgIGNhbmNlbC4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIGNhbmNlbEFzeW5jKGhhbmRsZSkgewogICAgICAgIGhhbmRsZSA8IDAgPyBQb2x5bWVyLkFzeW5jLm1pY3JvVGFzay5jYW5jZWwofmhhbmRsZSkgOgogICAgICAgICAgICBQb2x5bWVyLkFzeW5jLnRpbWVPdXQuY2FuY2VsKGhhbmRsZSk7CiAgICAgIH0KCiAgICAgIC8vIG90aGVyCgogICAgICAvKioKICAgICAgICogQ29udmVuaWVuY2UgbWV0aG9kIGZvciBjcmVhdGluZyBhbiBlbGVtZW50IGFuZCBjb25maWd1cmluZyBpdC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHRhZyBIVE1MIGVsZW1lbnQgdGFnIHRvIGNyZWF0ZS4KICAgICAgICogQHBhcmFtIHtPYmplY3Q9fSBwcm9wcyBPYmplY3Qgb2YgcHJvcGVydGllcyB0byBjb25maWd1cmUgb24gdGhlCiAgICAgICAqICAgIGluc3RhbmNlLgogICAgICAgKiBAcmV0dXJuIHshRWxlbWVudH0gTmV3bHkgY3JlYXRlZCBhbmQgY29uZmlndXJlZCBlbGVtZW50LgogICAgICAgKi8KICAgICAgY3JlYXRlKHRhZywgcHJvcHMpIHsKICAgICAgICBsZXQgZWx0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCh0YWcpOwogICAgICAgIGlmIChwcm9wcykgewogICAgICAgICAgaWYgKGVsdC5zZXRQcm9wZXJ0aWVzKSB7CiAgICAgICAgICAgIGVsdC5zZXRQcm9wZXJ0aWVzKHByb3BzKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGZvciAobGV0IG4gaW4gcHJvcHMpIHsKICAgICAgICAgICAgICBlbHRbbl0gPSBwcm9wc1tuXTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gZWx0OwogICAgICB9CgogICAgICAvKioKICAgICAgICogQ29udmVuaWVuY2UgbWV0aG9kIGZvciBpbXBvcnRpbmcgYW4gSFRNTCBkb2N1bWVudCBpbXBlcmF0aXZlbHkuCiAgICAgICAqCiAgICAgICAqIFRoaXMgbWV0aG9kIGNyZWF0ZXMgYSBuZXcgYDxsaW5rIHJlbD0iaW1wb3J0Ij5gIGVsZW1lbnQgd2l0aAogICAgICAgKiB0aGUgcHJvdmlkZWQgVVJMIGFuZCBhcHBlbmRzIGl0IHRvIHRoZSBkb2N1bWVudCB0byBzdGFydCBsb2FkaW5nLgogICAgICAgKiBJbiB0aGUgYG9ubG9hZGAgY2FsbGJhY2ssIHRoZSBgaW1wb3J0YCBwcm9wZXJ0eSBvZiB0aGUgYGxpbmtgCiAgICAgICAqIGVsZW1lbnQgd2lsbCBjb250YWluIHRoZSBpbXBvcnRlZCBkb2N1bWVudCBjb250ZW50cy4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGhyZWYgVVJMIHRvIGRvY3VtZW50IHRvIGxvYWQuCiAgICAgICAqIEBwYXJhbSB7P2Z1bmN0aW9uKCFFdmVudCk6dm9pZD19IG9ubG9hZCBDYWxsYmFjayB0byBub3RpZnkgd2hlbiBhbiBpbXBvcnQgc3VjY2Vzc2Z1bGx5CiAgICAgICAqICAgbG9hZGVkLgogICAgICAgKiBAcGFyYW0gez9mdW5jdGlvbighRXJyb3JFdmVudCk6dm9pZD19IG9uZXJyb3IgQ2FsbGJhY2sgdG8gbm90aWZ5IHdoZW4gYW4gaW1wb3J0CiAgICAgICAqICAgdW5zdWNjZXNzZnVsbHkgbG9hZGVkLgogICAgICAgKiBAcGFyYW0ge2Jvb2xlYW49fSBvcHRBc3luYyBUcnVlIGlmIHRoZSBpbXBvcnQgc2hvdWxkIGJlIGxvYWRlZCBgYXN5bmNgLgogICAgICAgKiAgIERlZmF1bHRzIHRvIGBmYWxzZWAuCiAgICAgICAqIEByZXR1cm4geyFIVE1MTGlua0VsZW1lbnR9IFRoZSBsaW5rIGVsZW1lbnQgZm9yIHRoZSBVUkwgdG8gYmUgbG9hZGVkLgogICAgICAgKi8KICAgICAgaW1wb3J0SHJlZihocmVmLCBvbmxvYWQsIG9uZXJyb3IsIG9wdEFzeW5jKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnMKICAgICAgICBsZXQgbG9hZEZuID0gb25sb2FkID8gb25sb2FkLmJpbmQodGhpcykgOiBudWxsOwogICAgICAgIGxldCBlcnJvckZuID0gb25lcnJvciA/IG9uZXJyb3IuYmluZCh0aGlzKSA6IG51bGw7CiAgICAgICAgcmV0dXJuIFBvbHltZXIuaW1wb3J0SHJlZihocmVmLCBsb2FkRm4sIGVycm9yRm4sIG9wdEFzeW5jKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFBvbHlmaWxsIGZvciBFbGVtZW50LnByb3RvdHlwZS5tYXRjaGVzLCB3aGljaCBpcyBzb21ldGltZXMgc3RpbGwKICAgICAgICogcHJlZml4ZWQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzZWxlY3RvciBTZWxlY3RvciB0byB0ZXN0LgogICAgICAgKiBAcGFyYW0geyFFbGVtZW50PX0gbm9kZSBFbGVtZW50IHRvIHRlc3QgdGhlIHNlbGVjdG9yIGFnYWluc3QuCiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgdGhlIGVsZW1lbnQgbWF0Y2hlcyB0aGUgc2VsZWN0b3IuCiAgICAgICAqLwogICAgICBlbGVtZW50TWF0Y2hlcyhzZWxlY3Rvciwgbm9kZSkgewogICAgICAgIHJldHVybiBQb2x5bWVyLmRvbS5tYXRjaGVzU2VsZWN0b3IoLyoqIEB0eXBlIHshRWxlbWVudH0gKi8gKG5vZGUgfHwgdGhpcyksIHNlbGVjdG9yKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFRvZ2dsZXMgYW4gSFRNTCBhdHRyaWJ1dGUgb24gb3Igb2ZmLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBIVE1MIGF0dHJpYnV0ZSBuYW1lCiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbj19IGJvb2wgQm9vbGVhbiB0byBmb3JjZSB0aGUgYXR0cmlidXRlIG9uIG9yIG9mZi4KICAgICAgICogICAgV2hlbiB1bnNwZWNpZmllZCwgdGhlIHN0YXRlIG9mIHRoZSBhdHRyaWJ1dGUgd2lsbCBiZSByZXZlcnNlZC4KICAgICAgICogQHBhcmFtIHtFbGVtZW50PX0gbm9kZSBOb2RlIHRvIHRhcmdldC4gIERlZmF1bHRzIHRvIGB0aGlzYC4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIHRvZ2dsZUF0dHJpYnV0ZShuYW1lLCBib29sLCBub2RlKSB7CiAgICAgICAgbm9kZSA9IC8qKiBAdHlwZSB7RWxlbWVudH0gKi8gKG5vZGUgfHwgdGhpcyk7CiAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT0gMSkgewogICAgICAgICAgYm9vbCA9ICFub2RlLmhhc0F0dHJpYnV0ZShuYW1lKTsKICAgICAgICB9CiAgICAgICAgaWYgKGJvb2wpIHsKICAgICAgICAgIG5vZGUuc2V0QXR0cmlidXRlKG5hbWUsICcnKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgbm9kZS5yZW1vdmVBdHRyaWJ1dGUobmFtZSk7CiAgICAgICAgfQogICAgICB9CgoKICAgICAgLyoqCiAgICAgICAqIFRvZ2dsZXMgYSBDU1MgY2xhc3Mgb24gb3Igb2ZmLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBDU1MgY2xhc3MgbmFtZQogICAgICAgKiBAcGFyYW0ge2Jvb2xlYW49fSBib29sIEJvb2xlYW4gdG8gZm9yY2UgdGhlIGNsYXNzIG9uIG9yIG9mZi4KICAgICAgICogICAgV2hlbiB1bnNwZWNpZmllZCwgdGhlIHN0YXRlIG9mIHRoZSBjbGFzcyB3aWxsIGJlIHJldmVyc2VkLgogICAgICAgKiBAcGFyYW0ge0VsZW1lbnQ9fSBub2RlIE5vZGUgdG8gdGFyZ2V0LiAgRGVmYXVsdHMgdG8gYHRoaXNgLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgdG9nZ2xlQ2xhc3MobmFtZSwgYm9vbCwgbm9kZSkgewogICAgICAgIG5vZGUgPSAvKiogQHR5cGUge0VsZW1lbnR9ICovIChub2RlIHx8IHRoaXMpOwogICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09IDEpIHsKICAgICAgICAgIGJvb2wgPSAhbm9kZS5jbGFzc0xpc3QuY29udGFpbnMobmFtZSk7CiAgICAgICAgfQogICAgICAgIGlmIChib29sKSB7CiAgICAgICAgICBub2RlLmNsYXNzTGlzdC5hZGQobmFtZSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIG5vZGUuY2xhc3NMaXN0LnJlbW92ZShuYW1lKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBDcm9zcy1wbGF0Zm9ybSBoZWxwZXIgZm9yIHNldHRpbmcgYW4gZWxlbWVudCdzIENTUyBgdHJhbnNmb3JtYCBwcm9wZXJ0eS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHRyYW5zZm9ybVRleHQgVHJhbnNmb3JtIHNldHRpbmcuCiAgICAgICAqIEBwYXJhbSB7RWxlbWVudD19IG5vZGUgRWxlbWVudCB0byBhcHBseSB0aGUgdHJhbnNmb3JtIHRvLgogICAgICAgKiBEZWZhdWx0cyB0byBgdGhpc2AKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIHRyYW5zZm9ybSh0cmFuc2Zvcm1UZXh0LCBub2RlKSB7CiAgICAgICAgbm9kZSA9IC8qKiBAdHlwZSB7RWxlbWVudH0gKi8gKG5vZGUgfHwgdGhpcyk7CiAgICAgICAgbm9kZS5zdHlsZS53ZWJraXRUcmFuc2Zvcm0gPSB0cmFuc2Zvcm1UZXh0OwogICAgICAgIG5vZGUuc3R5bGUudHJhbnNmb3JtID0gdHJhbnNmb3JtVGV4dDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENyb3NzLXBsYXRmb3JtIGhlbHBlciBmb3Igc2V0dGluZyBhbiBlbGVtZW50J3MgQ1NTIGB0cmFuc2xhdGUzZGAKICAgICAgICogcHJvcGVydHkuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4IFggb2Zmc2V0LgogICAgICAgKiBAcGFyYW0ge251bWJlcn0geSBZIG9mZnNldC4KICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHogWiBvZmZzZXQuCiAgICAgICAqIEBwYXJhbSB7RWxlbWVudD19IG5vZGUgRWxlbWVudCB0byBhcHBseSB0aGUgdHJhbnNmb3JtIHRvLgogICAgICAgKiBEZWZhdWx0cyB0byBgdGhpc2AuCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICB0cmFuc2xhdGUzZCh4LCB5LCB6LCBub2RlKSB7CiAgICAgICAgbm9kZSA9IC8qKiBAdHlwZSB7RWxlbWVudH0gKi8gKG5vZGUgfHwgdGhpcyk7CiAgICAgICAgdGhpcy50cmFuc2Zvcm0oJ3RyYW5zbGF0ZTNkKCcgKyB4ICsgJywnICsgeSArICcsJyArIHogKyAnKScsIG5vZGUpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogUmVtb3ZlcyBhbiBpdGVtIGZyb20gYW4gYXJyYXksIGlmIGl0IGV4aXN0cy4KICAgICAgICoKICAgICAgICogSWYgdGhlIGFycmF5IGlzIHNwZWNpZmllZCBieSBwYXRoLCBhIGNoYW5nZSBub3RpZmljYXRpb24gaXMKICAgICAgICogZ2VuZXJhdGVkLCBzbyB0aGF0IG9ic2VydmVycywgZGF0YSBiaW5kaW5ncyBhbmQgY29tcHV0ZWQKICAgICAgICogcHJvcGVydGllcyB3YXRjaGluZyB0aGF0IHBhdGggY2FuIHVwZGF0ZS4KICAgICAgICoKICAgICAgICogSWYgdGhlIGFycmF5IGlzIHBhc3NlZCBkaXJlY3RseSwgKipubyBjaGFuZ2UKICAgICAgICogbm90aWZpY2F0aW9uIGlzIGdlbmVyYXRlZCoqLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZyB8ICFBcnJheTxudW1iZXJ8c3RyaW5nPn0gYXJyYXlPclBhdGggUGF0aCB0byBhcnJheSBmcm9tIHdoaWNoIHRvIHJlbW92ZSB0aGUgaXRlbQogICAgICAgKiAgIChvciB0aGUgYXJyYXkgaXRzZWxmKS4KICAgICAgICogQHBhcmFtIHsqfSBpdGVtIEl0ZW0gdG8gcmVtb3ZlLgogICAgICAgKiBAcmV0dXJuIHtBcnJheX0gQXJyYXkgY29udGFpbmluZyBpdGVtIHJlbW92ZWQuCiAgICAgICAqLwogICAgICBhcnJheURlbGV0ZShhcnJheU9yUGF0aCwgaXRlbSkgewogICAgICAgIGxldCBpbmRleDsKICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShhcnJheU9yUGF0aCkpIHsKICAgICAgICAgIGluZGV4ID0gYXJyYXlPclBhdGguaW5kZXhPZihpdGVtKTsKICAgICAgICAgIGlmIChpbmRleCA+PSAwKSB7CiAgICAgICAgICAgIHJldHVybiBhcnJheU9yUGF0aC5zcGxpY2UoaW5kZXgsIDEpOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBsZXQgYXJyID0gUG9seW1lci5QYXRoLmdldCh0aGlzLCBhcnJheU9yUGF0aCk7CiAgICAgICAgICBpbmRleCA9IGFyci5pbmRleE9mKGl0ZW0pOwogICAgICAgICAgaWYgKGluZGV4ID49IDApIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3BsaWNlKGFycmF5T3JQYXRoLCBpbmRleCwgMSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBudWxsOwogICAgICB9CgogICAgICAvLyBsb2dnaW5nCgogICAgICAvKioKICAgICAgICogRmFjYWRlcyBgY29uc29sZS5sb2dgL2B3YXJuYC9gZXJyb3JgIGFzIG92ZXJyaWRlIHBvaW50LgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbGV2ZWwgT25lIG9mICdsb2cnLCAnd2FybicsICdlcnJvcicKICAgICAgICogQHBhcmFtIHtBcnJheX0gYXJncyBBcnJheSBvZiBzdHJpbmdzIG9yIG9iamVjdHMgdG8gbG9nCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBfbG9nZ2VyKGxldmVsLCBhcmdzKSB7CiAgICAgICAgLy8gYWNjZXB0IFsnZm9vJywgJ2JhciddIGFuZCBbWydmb28nLCAnYmFyJ11dCiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoYXJncykgJiYgYXJncy5sZW5ndGggPT09IDEgJiYgQXJyYXkuaXNBcnJheShhcmdzWzBdKSkgewogICAgICAgICAgYXJncyA9IGFyZ3NbMF07CiAgICAgICAgfQogICAgICAgIHN3aXRjaChsZXZlbCkgewogICAgICAgICAgY2FzZSAnbG9nJzoKICAgICAgICAgIGNhc2UgJ3dhcm4nOgogICAgICAgICAgY2FzZSAnZXJyb3InOgogICAgICAgICAgICBjb25zb2xlW2xldmVsXSguLi5hcmdzKTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBGYWNhZGVzIGBjb25zb2xlLmxvZ2AgYXMgYW4gb3ZlcnJpZGUgcG9pbnQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7Li4uKn0gYXJncyBBcnJheSBvZiBzdHJpbmdzIG9yIG9iamVjdHMgdG8gbG9nCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBfbG9nKC4uLmFyZ3MpIHsKICAgICAgICB0aGlzLl9sb2dnZXIoJ2xvZycsIGFyZ3MpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogRmFjYWRlcyBgY29uc29sZS53YXJuYCBhcyBhbiBvdmVycmlkZSBwb2ludC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHsuLi4qfSBhcmdzIEFycmF5IG9mIHN0cmluZ3Mgb3Igb2JqZWN0cyB0byBsb2cKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF93YXJuKC4uLmFyZ3MpIHsKICAgICAgICB0aGlzLl9sb2dnZXIoJ3dhcm4nLCBhcmdzKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEZhY2FkZXMgYGNvbnNvbGUuZXJyb3JgIGFzIGFuIG92ZXJyaWRlIHBvaW50LgogICAgICAgKgogICAgICAgKiBAcGFyYW0gey4uLip9IGFyZ3MgQXJyYXkgb2Ygc3RyaW5ncyBvciBvYmplY3RzIHRvIGxvZwogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgX2Vycm9yKC4uLmFyZ3MpIHsKICAgICAgICB0aGlzLl9sb2dnZXIoJ2Vycm9yJywgYXJncyk7CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBGb3JtYXRzIGEgbWVzc2FnZSB1c2luZyB0aGUgZWxlbWVudCB0eXBlIGFuIGEgbWV0aG9kIG5hbWUuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtZXRob2ROYW1lIE1ldGhvZCBuYW1lIHRvIGFzc29jaWF0ZSB3aXRoIG1lc3NhZ2UKICAgICAgICogQHBhcmFtIHsuLi4qfSBhcmdzIEFycmF5IG9mIHN0cmluZ3Mgb3Igb2JqZWN0cyB0byBsb2cKICAgICAgICogQHJldHVybiB7QXJyYXl9IEFycmF5IHdpdGggZm9ybWF0dGluZyBpbmZvcm1hdGlvbiBmb3IgYGNvbnNvbGVgCiAgICAgICAqICAgbG9nZ2luZy4KICAgICAgICovCiAgICAgIF9sb2dmKG1ldGhvZE5hbWUsIC4uLmFyZ3MpIHsKICAgICAgICByZXR1cm4gWydbJXM6OiVzXScsIHRoaXMuaXMsIG1ldGhvZE5hbWUsIC4uLmFyZ3NdOwogICAgICB9CgogICAgfQoKICAgIExlZ2FjeUVsZW1lbnQucHJvdG90eXBlLmlzID0gJyc7CgogICAgcmV0dXJuIExlZ2FjeUVsZW1lbnQ7CgogIH0pOwoKfSkoKTsKPC9zY3JpcHQ+PHNjcmlwdD4KCiAgKGZ1bmN0aW9uKCkgewoKICAgICd1c2Ugc3RyaWN0JzsKCiAgICBjb25zdCBsaWZlY3ljbGVQcm9wcyA9IHsKICAgICAgYXR0YWNoZWQ6IHRydWUsCiAgICAgIGRldGFjaGVkOiB0cnVlLAogICAgICByZWFkeTogdHJ1ZSwKICAgICAgY3JlYXRlZDogdHJ1ZSwKICAgICAgYmVmb3JlUmVnaXN0ZXI6IHRydWUsCiAgICAgIHJlZ2lzdGVyZWQ6IHRydWUsCiAgICAgIGF0dHJpYnV0ZUNoYW5nZWQ6IHRydWUsCiAgICAgIGxpc3RlbmVyczogdHJ1ZSwKICAgICAgaG9zdEF0dHJpYnV0ZXM6IHRydWUKICAgIH07CgogICAgY29uc3QgZXhjbHVkZU9uSW5mbyA9IHsKICAgICAgYXR0YWNoZWQ6IHRydWUsCiAgICAgIGRldGFjaGVkOiB0cnVlLAogICAgICByZWFkeTogdHJ1ZSwKICAgICAgY3JlYXRlZDogdHJ1ZSwKICAgICAgYmVmb3JlUmVnaXN0ZXI6IHRydWUsCiAgICAgIHJlZ2lzdGVyZWQ6IHRydWUsCiAgICAgIGF0dHJpYnV0ZUNoYW5nZWQ6IHRydWUsCiAgICAgIGJlaGF2aW9yczogdHJ1ZSwKICAgICAgX25vQWNjZXNzb3JzOiB0cnVlCiAgICB9OwoKICAgIGNvbnN0IGV4Y2x1ZGVPbkJlaGF2aW9ycyA9IE9iamVjdC5hc3NpZ24oewogICAgICBsaXN0ZW5lcnM6IHRydWUsCiAgICAgIGhvc3RBdHRyaWJ1dGVzOiB0cnVlLAogICAgICBwcm9wZXJ0aWVzOiB0cnVlLAogICAgICBvYnNlcnZlcnM6IHRydWUsCiAgICB9LCBleGNsdWRlT25JbmZvKTsKCiAgICBmdW5jdGlvbiBjb3B5UHJvcGVydGllcyhzb3VyY2UsIHRhcmdldCwgZXhjbHVkZVByb3BzKSB7CiAgICAgIGNvbnN0IG5vQWNjZXNzb3JzID0gc291cmNlLl9ub0FjY2Vzc29yczsKICAgICAgZm9yIChsZXQgcCBpbiBzb3VyY2UpIHsKICAgICAgICBpZiAoIShwIGluIGV4Y2x1ZGVQcm9wcykpIHsKICAgICAgICAgIGlmIChub0FjY2Vzc29ycykgewogICAgICAgICAgICB0YXJnZXRbcF0gPSBzb3VyY2VbcF07CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBsZXQgcGQgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHNvdXJjZSwgcCk7CiAgICAgICAgICAgIGlmIChwZCkgewogICAgICAgICAgICAgIC8vIGVuc3VyZSBwcm9wZXJ0eSBpcyBjb25maWd1cmFibGUgc28gdGhhdCBhIGxhdGVyIGJlaGF2aW9yIGNhbgogICAgICAgICAgICAgIC8vIHJlLWNvbmZpZ3VyZSBpdC4KICAgICAgICAgICAgICBwZC5jb25maWd1cmFibGUgPSB0cnVlOwogICAgICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHAsIHBkKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQXBwbGllcyBhICJsZWdhY3kiIGJlaGF2aW9yIG9yIGFycmF5IG9mIGJlaGF2aW9ycyB0byB0aGUgcHJvdmlkZWQgY2xhc3MuCiAgICAgKgogICAgICogTm90ZTogdGhpcyBtZXRob2Qgd2lsbCBhdXRvbWF0aWNhbGx5IGFsc28gYXBwbHkgdGhlIGBQb2x5bWVyLkxlZ2FjeUVsZW1lbnRNaXhpbmAKICAgICAqIHRvIGVuc3VyZSB0aGF0IGFueSBsZWdhY3kgYmVoYXZpb3JzIGNhbiByZWx5IG9uIGxlZ2FjeSBQb2x5bWVyIEFQSSBvbgogICAgICogdGhlIHVuZGVybHlpbmcgZWxlbWVudC4KICAgICAqCiAgICAgKiBAdGVtcGxhdGUgVAogICAgICogQHBhcmFtIHshT2JqZWN0fCFBcnJheTwhT2JqZWN0Pn0gYmVoYXZpb3JzIEJlaGF2aW9yIG9iamVjdCBvciBhcnJheSBvZiBiZWhhdmlvcnMuCiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKG5ldzpUKX0ga2xhc3MgRWxlbWVudCBjbGFzcy4KICAgICAqIEByZXR1cm4ge2Z1bmN0aW9uKG5ldzpUKX0gUmV0dXJucyBhIG5ldyBFbGVtZW50IGNsYXNzIGV4dGVuZGVkIGJ5IHRoZQogICAgICogcGFzc2VkIGluIGBiZWhhdmlvcnNgIGFuZCBhbHNvIGJ5IGBQb2x5bWVyLkxlZ2FjeUVsZW1lbnRNaXhpbmAuCiAgICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAgICogQHN1cHByZXNzIHtpbnZhbGlkQ2FzdHMsIGNoZWNrVHlwZXN9CiAgICAgKi8KICAgIGZ1bmN0aW9uIG1peGluQmVoYXZpb3JzKGJlaGF2aW9ycywga2xhc3MpIHsKICAgICAgcmV0dXJuIEdlbmVyYXRlQ2xhc3NGcm9tSW5mbyh7fSwgUG9seW1lci5MZWdhY3lFbGVtZW50TWl4aW4oa2xhc3MpLCBiZWhhdmlvcnMpOwogICAgfQoKICAgIC8vIE5PVEU6CiAgICAvLyAxLngKICAgIC8vIEJlaGF2aW9ycyB3ZXJlIG1peGVkIGluICppbiByZXZlcnNlIG9yZGVyKiBhbmQgZGUtZHVwZWQgb24gdGhlIGZseS4KICAgIC8vIFRoZSBydWxlIHdhcyB0aGF0IGJlaGF2aW9yIHByb3BlcnRpZXMgd2VyZSBjb3BpZWQgb250byB0aGUgZWxlbWVudAogICAgLy8gcHJvdG90eXBlIGlmIGFuZCBvbmx5IGlmIHRoZSBwcm9wZXJ0eSBkaWQgbm90IGFscmVhZHkgZXhpc3QuCiAgICAvLyBHaXZlbjogUG9seW1lcnsgYmVoYXZpb3JzOiBbQSwgQiwgQywgQSwgQl19LCBwcm9wZXJ0eSBjb3B5IG9yZGVyIHdhczoKICAgIC8vICgxKSwgQiwgKDIpLCBBLCAoMykgQy4gVGhpcyBtZWFucyBwcm90b3R5cGUgcHJvcGVydGllcyB3aW4gb3ZlcgogICAgLy8gQiBwcm9wZXJ0aWVzIHdpbiBvdmVyIEEgd2luIG92ZXIgQy4gVGhpcyBtaXJyb3JzIHdoYXQgd291bGQgaGFwcGVuCiAgICAvLyB3aXRoIGluaGVyaXRhbmNlIGlmIGVsZW1lbnQgZXh0ZW5kZWQgQiBleHRlbmRlZCBBIGV4dGVuZGVkIEMuCiAgICAvLwogICAgLy8gQWdhaW4gZ2l2ZW4sIFBvbHltZXJ7IGJlaGF2aW9yczogW0EsIEIsIEMsIEEsIEJdfSwgdGhlIHJlc3VsdGluZwogICAgLy8gYGJlaGF2aW9yc2AgYXJyYXkgd2FzIFtDLCBBLCBCXS4KICAgIC8vIEJlaGF2aW9yIGxpZmVjeWNsZSBtZXRob2RzIHdlcmUgY2FsbGVkIGluIGJlaGF2aW9yIGFycmF5IG9yZGVyCiAgICAvLyBmb2xsb3dlZCBieSB0aGUgZWxlbWVudCwgZS5nLiAoMSkgQy5jcmVhdGVkLCAoMikgQS5jcmVhdGVkLAogICAgLy8gKDMpIEIuY3JlYXRlZCwgKDQpIGVsZW1lbnQuY3JlYXRlZC4gVGhlcmUgd2FzIG5vIHN1cHBvcnQgZm9yCiAgICAvLyBzdXBlciwgYW5kICJzdXBlci1iZWhhdmlvciIgbWV0aG9kcyB3ZXJlIGNhbGxhYmxlIG9ubHkgYnkgbmFtZSkuCiAgICAvLwogICAgLy8gMi54CiAgICAvLyBCZWhhdmlvcnMgYXJlIG1hZGUgaW50byBwcm9wZXIgbWl4aW5zIHdoaWNoIGxpdmUgaW4gdGhlCiAgICAvLyBlbGVtZW50J3MgcHJvdG90eXBlIGNoYWluLiBCZWhhdmlvcnMgYXJlIHBsYWNlZCBpbiB0aGUgZWxlbWVudCBwcm90b3R5cGUKICAgIC8vIGVsZGVzdCB0byB5b3VuZ2VzdCBhbmQgZGUtZHVwZWQgeW91bmdlc3QgdG8gb2xkZXN0OgogICAgLy8gU28sIGZpcnN0IFtBLCBCLCBDLCBBLCBCXSBiZWNvbWVzIFtDLCBBLCBCXSB0aGVuLAogICAgLy8gdGhlIGVsZW1lbnQgcHJvdG90eXBlIGJlY29tZXMgKG9sZGVzdCkgKDEpIFBvbHltZXIuRWxlbWVudCwgKDIpIGNsYXNzKEMpLAogICAgLy8gKDMpIGNsYXNzKEEpLCAoNCkgY2xhc3MoQiksICg1KSBjbGFzcyhQb2x5bWVyKHsuLi59KSkuCiAgICAvLyBSZXN1bHQ6CiAgICAvLyBUaGlzIG1lYW5zIGVsZW1lbnQgcHJvcGVydGllcyB3aW4gb3ZlciBCIHByb3BlcnRpZXMgd2luIG92ZXIgQSB3aW4KICAgIC8vIG92ZXIgQy4gKHNhbWUgYXMgMS54KQogICAgLy8gSWYgbGlmZWN5Y2xlIGlzIGNhbGxlZCAoc3VwZXIgdGhlbiBtZSksIG9yZGVyIGlzCiAgICAvLyAoMSkgQy5jcmVhdGVkLCAoMikgQS5jcmVhdGVkLCAoMykgQi5jcmVhdGVkLCAoNCkgZWxlbWVudC5jcmVhdGVkCiAgICAvLyAoYWdhaW4gc2FtZSBhcyAxLngpCiAgICBmdW5jdGlvbiBhcHBseUJlaGF2aW9ycyhwcm90bywgYmVoYXZpb3JzLCBsaWZlY3ljbGUpIHsKICAgICAgZm9yIChsZXQgaT0wOyBpPGJlaGF2aW9ycy5sZW5ndGg7IGkrKykgewogICAgICAgIGFwcGx5SW5mbyhwcm90bywgYmVoYXZpb3JzW2ldLCBsaWZlY3ljbGUsIGV4Y2x1ZGVPbkJlaGF2aW9ycyk7CiAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBhcHBseUluZm8ocHJvdG8sIGluZm8sIGxpZmVjeWNsZSwgZXhjbHVkZVByb3BzKSB7CiAgICAgIGNvcHlQcm9wZXJ0aWVzKGluZm8sIHByb3RvLCBleGNsdWRlUHJvcHMpOwogICAgICBmb3IgKGxldCBwIGluIGxpZmVjeWNsZVByb3BzKSB7CiAgICAgICAgaWYgKGluZm9bcF0pIHsKICAgICAgICAgIGxpZmVjeWNsZVtwXSA9IGxpZmVjeWNsZVtwXSB8fCBbXTsKICAgICAgICAgIGxpZmVjeWNsZVtwXS5wdXNoKGluZm9bcF0pOwogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQHBhcmFtIHtBcnJheX0gYmVoYXZpb3JzIExpc3Qgb2YgYmVoYXZpb3JzIHRvIGZsYXR0ZW4uCiAgICAgKiBAcGFyYW0ge0FycmF5PX0gbGlzdCBUYXJnZXQgbGlzdCB0byBmbGF0dGVuIGJlaGF2aW9ycyBpbnRvLgogICAgICogQHBhcmFtIHtBcnJheT19IGV4Y2x1ZGUgTGlzdCBvZiBiZWhhdmlvcnMgdG8gZXhjbHVkZSBmcm9tIHRoZSBsaXN0LgogICAgICogQHJldHVybiB7IUFycmF5fSBSZXR1cm5zIHRoZSBsaXN0IG9mIGZsYXR0ZW5lZCBiZWhhdmlvcnMuCiAgICAgKi8KICAgIGZ1bmN0aW9uIGZsYXR0ZW5CZWhhdmlvcnMoYmVoYXZpb3JzLCBsaXN0LCBleGNsdWRlKSB7CiAgICAgIGxpc3QgPSBsaXN0IHx8IFtdOwogICAgICBmb3IgKGxldCBpPWJlaGF2aW9ycy5sZW5ndGgtMTsgaSA+PSAwOyBpLS0pIHsKICAgICAgICBsZXQgYiA9IGJlaGF2aW9yc1tpXTsKICAgICAgICBpZiAoYikgewogICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoYikpIHsKICAgICAgICAgICAgZmxhdHRlbkJlaGF2aW9ycyhiLCBsaXN0KTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIC8vIGRlZHVwCiAgICAgICAgICAgIGlmIChsaXN0LmluZGV4T2YoYikgPCAwICYmICghZXhjbHVkZSB8fCBleGNsdWRlLmluZGV4T2YoYikgPCAwKSkgewogICAgICAgICAgICAgIGxpc3QudW5zaGlmdChiKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBjb25zb2xlLndhcm4oJ2JlaGF2aW9yIGlzIG51bGwsIGNoZWNrIGZvciBtaXNzaW5nIG9yIDQwNCBpbXBvcnQnKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIGxpc3Q7CiAgICB9CgogICAgLyogTm90ZSBhYm91dCBjb25zdHJ1Y3Rpb24gYW5kIGV4dGVuc2lvbiBvZiBsZWdhY3kgY2xhc3Nlcy4KICAgICAgW0NoYW5nZWQgaW4gUTQgMjAxOCB0byBvcHRpbWl6ZSBwZXJmb3JtYW5jZS5dCgogICAgICBXaGVuIGNhbGxpbmcgYFBvbHltZXJgIG9yIGBtaXhpbkJlaGF2aW9yc2AsIHRoZSBnZW5lcmF0ZWQgY2xhc3MgYmVsb3cgaXMKICAgICAgbWFkZS4gVGhlIGxpc3Qgb2YgYmVoYXZpb3JzIHdhcyBwcmV2aW91c2x5IG1hZGUgaW50byBvbmUgZ2VuZXJhdGVkIGNsYXNzIHBlcgogICAgICBiZWhhdmlvciwgYnV0IHRoaXMgaXMgbm8gbG9uZ2VyIHRoZSBjYXNlIGFzIGJlaGF2aW9ycyBhcmUgbm93IGNhbGxlZAogICAgICBtYW51YWxseS4gTm90ZSwgdGhlcmUgbWF5ICpzdGlsbCogYmUgbXVsdGlwbGUgZ2VuZXJhdGVkIGNsYXNzZXMgaW4gdGhlCiAgICAgIGVsZW1lbnQncyBwcm90b3R5cGUgY2hhaW4gaWYgZXh0ZW5zaW9uIGlzIHVzZWQgd2l0aCBgbWl4aW5CZWhhdmlvcnNgLgoKICAgICAgVGhlIGdlbmVyYXRlZCBjbGFzcyBpcyBkaXJlY3RseSB0aWVkIHRvIHRoZSBpbmZvIG9iamVjdCBhbmQgYmVoYXZpb3JzCiAgICAgIHVzZWQgdG8gY3JlYXRlIGl0LiBUaGF0IGxpc3Qgb2YgYmVoYXZpb3JzIGlzIGZpbHRlcmVkIHNvIGl0J3Mgb25seSB0aGUKICAgICAgYmVoYXZpb3JzIG5vdCBhY3RpdmUgb24gdGhlIHN1cGVyY2xhc3MuIEluIG9yZGVyIHRvIGNhbGwgdGhyb3VnaCB0byB0aGUKICAgICAgZW50aXJlIGxpc3Qgb2YgbGlmZWN5Y2xlIG1ldGhvZHMsIGl0J3MgaW1wb3J0YW50IHRvIGNhbGwgYHN1cGVyYC4KCiAgICAgIFRoZSBlbGVtZW50J3MgYHByb3BlcnRpZXNgIGFuZCBgb2JzZXJ2ZXJzYCBhcmUgY29udHJvbGxlZCB2aWEgdGhlIGZpbmFsaXphdGlvbgogICAgICBtZWNoYW5pc20gcHJvdmlkZWQgYnkgYFByb3BlcnRpZXNNaXhpbmAuIGBQcm9wZXJ0aWVzYCBhbmQgYG9ic2VydmVyc2AgYXJlCiAgICAgIGNvbGxlY3RlZCBieSBtYW51YWxseSB0cmF2ZXJzaW5nIHRoZSBwcm90b3R5cGUgY2hhaW4gYW5kIG1lcmdpbmcuCgogICAgICBUbyBsaW1pdCBjaGFuZ2VzLCB0aGUgYF9yZWdpc3RlcmVkYCBtZXRob2QgaXMgY2FsbGVkIHZpYSBgX2luaXRpYWxpemVQcm9wZXJ0aWVzYAogICAgICBhbmQgbm90IGBfZmluYWxpemVDbGFzc2AuCiAgICAqLwogICAgLyoqCiAgICAgKiBAcGFyYW0geyFQb2x5bWVySW5pdH0gaW5mbyBQb2x5bWVyIGluZm8gb2JqZWN0CiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKG5ldzpIVE1MRWxlbWVudCl9IEJhc2UgYmFzZSBjbGFzcyB0byBleHRlbmQgd2l0aCBpbmZvIG9iamVjdAogICAgICogQHBhcmFtIHtPYmplY3R9IGJlaGF2aW9ycyBiZWhhdmlvcnMgdG8gY29weSBpbnRvIHRoZSBlbGVtZW50CiAgICAgKiBAcmV0dXJuIHtmdW5jdGlvbihuZXc6SFRNTEVsZW1lbnQpfSBHZW5lcmF0ZWQgY2xhc3MKICAgICAqIEBzdXBwcmVzcyB7Y2hlY2tUeXBlc30KICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIGZ1bmN0aW9uIEdlbmVyYXRlQ2xhc3NGcm9tSW5mbyhpbmZvLCBCYXNlLCBiZWhhdmlvcnMpIHsKCiAgICAgIC8vIG1hbmFnZXMgYmVoYXZpb3IgYW5kIGxpZmVjeWNsZSBwcm9jZXNzaW5nIChmaWxsZWQgaW4gYWZ0ZXIgY2xhc3MgZGVmaW5pdGlvbikKICAgICAgbGV0IGJlaGF2aW9yTGlzdDsKICAgICAgY29uc3QgbGlmZWN5Y2xlID0ge307CgogICAgICAvKiogQHByaXZhdGUgKi8KICAgICAgY2xhc3MgUG9seW1lckdlbmVyYXRlZCBleHRlbmRzIEJhc2UgewoKICAgICAgICAvLyBleHBsaWNpdGx5IG5vdCBjYWxsaW5nIHN1cGVyLl9maW5hbGl6ZUNsYXNzCiAgICAgICAgc3RhdGljIF9maW5hbGl6ZUNsYXNzKCkgewogICAgICAgICAgLy8gaWYgY2FsbGluZyB2aWEgYSBzdWJjbGFzcyB0aGF0IGhhc24ndCBiZWVuIGdlbmVyYXRlZCwgcGFzcyB0aHJvdWdoIHRvIHN1cGVyCiAgICAgICAgICBpZiAoIXRoaXMuaGFzT3duUHJvcGVydHkod2luZG93LkpTQ29tcGlsZXJfcmVuYW1lUHJvcGVydHkoJ2dlbmVyYXRlZEZyb20nLCB0aGlzKSkpIHsKICAgICAgICAgICAgc3VwZXIuX2ZpbmFsaXplQ2xhc3MoKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIC8vIGludGVybGVhdmUgcHJvcGVydGllcyBhbmQgb2JzZXJ2ZXJzIHBlciBiZWhhdmlvciBhbmQgYGluZm9gCiAgICAgICAgICAgIGlmIChiZWhhdmlvckxpc3QpIHsKICAgICAgICAgICAgICBmb3IgKGxldCBpPTAsIGI7IGkgPCBiZWhhdmlvckxpc3QubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIGIgPSBiZWhhdmlvckxpc3RbaV07CiAgICAgICAgICAgICAgICBpZiAoYi5wcm9wZXJ0aWVzKSB7CiAgICAgICAgICAgICAgICAgIHRoaXMuY3JlYXRlUHJvcGVydGllcyhiLnByb3BlcnRpZXMpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKGIub2JzZXJ2ZXJzKSB7CiAgICAgICAgICAgICAgICAgIHRoaXMuY3JlYXRlT2JzZXJ2ZXJzKGIub2JzZXJ2ZXJzLCBiLnByb3BlcnRpZXMpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoaW5mby5wcm9wZXJ0aWVzKSB7CiAgICAgICAgICAgICAgdGhpcy5jcmVhdGVQcm9wZXJ0aWVzKGluZm8ucHJvcGVydGllcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGluZm8ub2JzZXJ2ZXJzKSB7CiAgICAgICAgICAgICAgdGhpcy5jcmVhdGVPYnNlcnZlcnMoaW5mby5vYnNlcnZlcnMsIGluZm8ucHJvcGVydGllcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHRvIHByZXBhcmUgdGhlIGVsZW1lbnQgdGVtcGxhdGUKICAgICAgICAgICAgdGhpcy5fcHJlcGFyZVRlbXBsYXRlKCk7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBzdGF0aWMgZ2V0IHByb3BlcnRpZXMoKSB7CiAgICAgICAgICBjb25zdCBwcm9wZXJ0aWVzID0ge307CiAgICAgICAgICBpZiAoYmVoYXZpb3JMaXN0KSB7CiAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaSA8IGJlaGF2aW9yTGlzdC5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgIE9iamVjdC5hc3NpZ24ocHJvcGVydGllcywgYmVoYXZpb3JMaXN0W2ldLnByb3BlcnRpZXMpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBPYmplY3QuYXNzaWduKHByb3BlcnRpZXMsIGluZm8ucHJvcGVydGllcyk7CiAgICAgICAgICByZXR1cm4gcHJvcGVydGllczsKICAgICAgICB9CgogICAgICAgIHN0YXRpYyBnZXQgb2JzZXJ2ZXJzKCkgewogICAgICAgICAgbGV0IG9ic2VydmVycyA9IFtdOwogICAgICAgICAgaWYgKGJlaGF2aW9yTGlzdCkgewogICAgICAgICAgICBmb3IgKGxldCBpPTAsIGI7IGkgPCBiZWhhdmlvckxpc3QubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICBiID0gYmVoYXZpb3JMaXN0W2ldOwogICAgICAgICAgICAgIGlmIChiLm9ic2VydmVycykgewogICAgICAgICAgICAgICAgb2JzZXJ2ZXJzID0gb2JzZXJ2ZXJzLmNvbmNhdChiLm9ic2VydmVycyk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoaW5mby5vYnNlcnZlcnMpIHsKICAgICAgICAgICAgb2JzZXJ2ZXJzID0gb2JzZXJ2ZXJzLmNvbmNhdChpbmZvLm9ic2VydmVycyk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gb2JzZXJ2ZXJzOwogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKi8KICAgICAgICBjcmVhdGVkKCkgewogICAgICAgICAgc3VwZXIuY3JlYXRlZCgpOwogICAgICAgICAgY29uc3QgbGlzdCA9IGxpZmVjeWNsZS5jcmVhdGVkOwogICAgICAgICAgaWYgKGxpc3QpIHsKICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgIGxpc3RbaV0uY2FsbCh0aGlzKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKi8KICAgICAgICBfcmVnaXN0ZXJlZCgpIHsKICAgICAgICAgIC8qIE5PVEU6IGBiZWZvcmVSZWdpc3RlcmAgaXMgY2FsbGVkIGhlcmUgZm9yIGJjLCBidXQgdGhlIGJlaGF2aW9yCiAgICAgICAgICAgIGlzIGRpZmZlcmVudCB0aGFuIGluIDEueC4gSW4gMS4wLCB0aGUgbWV0aG9kIHdhcyBjYWxsZWQgKmFmdGVyKgogICAgICAgICAgICBtaXhpbmcgcHJvdG90eXBlcyB0b2dldGhlciBidXQgKmJlZm9yZSogcHJvY2Vzc2luZyBvZiBtZXRhLW9iamVjdHMuCiAgICAgICAgICAgIEhvd2V2ZXIsIGR5bmFtaWMgZWZmZWN0cyBjYW4gc3RpbGwgYmUgc2V0IGhlcmUgYW5kIGNhbiBiZSBkb25lIGVpdGhlcgogICAgICAgICAgICBpbiBgYmVmb3JlUmVnaXN0ZXJgIG9yIGByZWdpc3RlcmVkYC4gSXQgaXMgbm8gbG9uZ2VyIHBvc3NpYmxlIHRvIHNldAogICAgICAgICAgICBgaXNgIGluIGBiZWZvcmVSZWdpc3RlcmAgYXMgeW91IGNvdWxkIGluIDEueC4KICAgICAgICAgICovCiAgICAgICAgICAvLyBvbmx5IHByb2NlZWQgaWYgdGhlIGdlbmVyYXRlZCBjbGFzcycgcHJvdG90eXBlIGhhcyBub3QgYmVlbiByZWdpc3RlcmVkLgogICAgICAgICAgY29uc3QgZ2VuZXJhdGVkUHJvdG8gPSBQb2x5bWVyR2VuZXJhdGVkLnByb3RvdHlwZTsKICAgICAgICAgIGlmICghZ2VuZXJhdGVkUHJvdG8uaGFzT3duUHJvcGVydHkoJ19faGFzUmVnaXN0ZXJGaW5pc2hlZCcpKSB7CiAgICAgICAgICAgIGdlbmVyYXRlZFByb3RvLl9faGFzUmVnaXN0ZXJGaW5pc2hlZCA9IHRydWU7CiAgICAgICAgICAgIC8vIGVuc3VyZSBzdXBlcmNsYXNzIGlzIHJlZ2lzdGVyZWQgZmlyc3QuCiAgICAgICAgICAgIHN1cGVyLl9yZWdpc3RlcmVkKCk7CiAgICAgICAgICAgIC8vIGNvcHkgcHJvcGVydGllcyBvbnRvIHRoZSBnZW5lcmF0ZWQgY2xhc3MgbGF6aWx5IGlmIHdlJ3JlIG9wdGltaXppbmcsCiAgICAgICAgICAgIGlmIChQb2x5bWVyLmxlZ2FjeU9wdGltaXphdGlvbnMpIHsKICAgICAgICAgICAgICBjb3B5UHJvcGVydGllc1RvUHJvdG8oZ2VuZXJhdGVkUHJvdG8pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIG1ha2Ugc3VyZSBsZWdhY3kgbGlmZWN5Y2xlIGlzIGNhbGxlZCBvbiB0aGUgKmVsZW1lbnQqJ3MgcHJvdG90eXBlCiAgICAgICAgICAgIC8vIGFuZCBub3QgdGhlIGdlbmVyYXRlZCBjbGFzcyBwcm90b3R5cGU7IGlmIHRoZSBlbGVtZW50IGhhcyBiZWVuCiAgICAgICAgICAgIC8vIGV4dGVuZGVkLCB0aGVzZSBhcmUgKm5vdCogdGhlIHNhbWUuCiAgICAgICAgICAgIGNvbnN0IHByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKHRoaXMpOwogICAgICAgICAgICBsZXQgbGlzdCA9IGxpZmVjeWNsZS5iZWZvcmVSZWdpc3RlcjsKICAgICAgICAgICAgaWYgKGxpc3QpIHsKICAgICAgICAgICAgICBmb3IgKGxldCBpPTA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBsaXN0W2ldLmNhbGwocHJvdG8pOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBsaXN0ID0gbGlmZWN5Y2xlLnJlZ2lzdGVyZWQ7CiAgICAgICAgICAgIGlmIChsaXN0KSB7CiAgICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgICAgbGlzdFtpXS5jYWxsKHByb3RvKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICovCiAgICAgICAgX2FwcGx5TGlzdGVuZXJzKCkgewogICAgICAgICAgc3VwZXIuX2FwcGx5TGlzdGVuZXJzKCk7CiAgICAgICAgICBjb25zdCBsaXN0ID0gbGlmZWN5Y2xlLmxpc3RlbmVyczsKICAgICAgICAgIGlmIChsaXN0KSB7CiAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaSA8IGxpc3QubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICBjb25zdCBsaXN0ZW5lcnMgPSBsaXN0W2ldOwogICAgICAgICAgICAgIGlmIChsaXN0ZW5lcnMpIHsKICAgICAgICAgICAgICAgIGZvciAobGV0IGwgaW4gbGlzdGVuZXJzKSB7CiAgICAgICAgICAgICAgICAgIHRoaXMuX2FkZE1ldGhvZEV2ZW50TGlzdGVuZXJUb05vZGUodGhpcywgbCwgbGlzdGVuZXJzW2xdKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8vIG5vdGU6IGV4Y2VwdGlvbiB0byAic3VwZXIgdGhlbiBtZSIgcnVsZTsKICAgICAgICAvLyBkbyB3b3JrIGJlZm9yZSBjYWxsaW5nIHN1cGVyIHNvIHRoYXQgc3VwZXIgYXR0cmlidXRlcwogICAgICAgIC8vIG9ubHkgYXBwbHkgaWYgbm90IGFscmVhZHkgc2V0LgogICAgICAgIC8qKgogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICovCiAgICAgICAgX2Vuc3VyZUF0dHJpYnV0ZXMoKSB7CiAgICAgICAgICBjb25zdCBsaXN0ID0gbGlmZWN5Y2xlLmhvc3RBdHRyaWJ1dGVzOwogICAgICAgICAgaWYgKGxpc3QpIHsKICAgICAgICAgICAgZm9yIChsZXQgaT1saXN0Lmxlbmd0aC0xOyBpID49IDA7IGktLSkgewogICAgICAgICAgICAgIGNvbnN0IGhvc3RBdHRyaWJ1dGVzID0gbGlzdFtpXTsKICAgICAgICAgICAgICBmb3IgKGxldCBhIGluIGhvc3RBdHRyaWJ1dGVzKSB7CiAgICAgICAgICAgICAgICAgIHRoaXMuX2Vuc3VyZUF0dHJpYnV0ZShhLCBob3N0QXR0cmlidXRlc1thXSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIHN1cGVyLl9lbnN1cmVBdHRyaWJ1dGVzKCk7CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgICAqLwogICAgICAgIHJlYWR5KCkgewogICAgICAgICAgc3VwZXIucmVhZHkoKTsKICAgICAgICAgIGxldCBsaXN0ID0gbGlmZWN5Y2xlLnJlYWR5OwogICAgICAgICAgaWYgKGxpc3QpIHsKICAgICAgICAgICAgZm9yIChsZXQgaT0wOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAgIGxpc3RbaV0uY2FsbCh0aGlzKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLyoqCiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKi8KICAgICAgICBhdHRhY2hlZCgpIHsKICAgICAgICAgIHN1cGVyLmF0dGFjaGVkKCk7CiAgICAgICAgICBsZXQgbGlzdCA9IGxpZmVjeWNsZS5hdHRhY2hlZDsKICAgICAgICAgIGlmIChsaXN0KSB7CiAgICAgICAgICAgIGZvciAobGV0IGk9MDsgaSA8IGxpc3QubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICBsaXN0W2ldLmNhbGwodGhpcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAgICovCiAgICAgICAgZGV0YWNoZWQoKSB7CiAgICAgICAgICBzdXBlci5kZXRhY2hlZCgpOwogICAgICAgICAgbGV0IGxpc3QgPSBsaWZlY3ljbGUuZGV0YWNoZWQ7CiAgICAgICAgICBpZiAobGlzdCkgewogICAgICAgICAgICBmb3IgKGxldCBpPTA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgbGlzdFtpXS5jYWxsKHRoaXMpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBJbXBsZW1lbnRzIG5hdGl2ZSBDdXN0b20gRWxlbWVudHMgYGF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFja2AgdG8KICAgICAgICAgKiBzZXQgYW4gYXR0cmlidXRlIHZhbHVlIHRvIGEgcHJvcGVydHkgdmlhIGBfYXR0cmlidXRlVG9Qcm9wZXJ0eWAuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBOYW1lIG9mIGF0dHJpYnV0ZSB0aGF0IGNoYW5nZWQKICAgICAgICAgKiBAcGFyYW0gez9zdHJpbmd9IG9sZCBPbGQgYXR0cmlidXRlIHZhbHVlCiAgICAgICAgICogQHBhcmFtIHs/c3RyaW5nfSB2YWx1ZSBOZXcgYXR0cmlidXRlIHZhbHVlCiAgICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICAgKi8KICAgICAgICBhdHRyaWJ1dGVDaGFuZ2VkKG5hbWUsIG9sZCwgdmFsdWUpIHsKICAgICAgICAgIHN1cGVyLmF0dHJpYnV0ZUNoYW5nZWQoKTsKICAgICAgICAgIGxldCBsaXN0ID0gbGlmZWN5Y2xlLmF0dHJpYnV0ZUNoYW5nZWQ7CiAgICAgICAgICBpZiAobGlzdCkgewogICAgICAgICAgICBmb3IgKGxldCBpPTA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgbGlzdFtpXS5jYWxsKHRoaXMsIG5hbWUsIG9sZCwgdmFsdWUpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CgogICAgICAvLyBhcHBseSBiZWhhdmlvcnMsIG5vdGUgYWN0dWFsIGNvcHlpbmcgaXMgZG9uZSBsYXppbHkgYXQgZmlyc3QgaW5zdGFuY2UgY3JlYXRpb24KICAgICAgaWYgKGJlaGF2aW9ycykgewogICAgICAgIC8vIE5PVEU6IGVuc3VyZSB0aGUgYmVoYXZpb3IgaXMgZXh0ZW5kaW5nIGEgY2xhc3Mgd2l0aAogICAgICAgIC8vIGxlZ2FjeSBlbGVtZW50IGFwaS4gVGhpcyBpcyBuZWNlc3Nhcnkgc2luY2UgYmVoYXZpb3JzIGV4cGVjdCB0byBiZSBhYmxlCiAgICAgICAgLy8gdG8gYWNjZXNzIDEueCBsZWdhY3kgYXBpLgogICAgICAgIGlmICghQXJyYXkuaXNBcnJheShiZWhhdmlvcnMpKSB7CiAgICAgICAgICBiZWhhdmlvcnMgPSBbYmVoYXZpb3JzXTsKICAgICAgICB9CiAgICAgICAgbGV0IHN1cGVyQmVoYXZpb3JzID0gQmFzZS5wcm90b3R5cGUuYmVoYXZpb3JzOwogICAgICAgIC8vIGdldCBmbGF0dGVuZWQsIGRlZHVwZWQgbGlzdCBvZiBiZWhhdmlvcnMgKm5vdCogYWxyZWFkeSBvbiBzdXBlciBjbGFzcwogICAgICAgIGJlaGF2aW9yTGlzdCA9IGZsYXR0ZW5CZWhhdmlvcnMoYmVoYXZpb3JzLCBudWxsLCBzdXBlckJlaGF2aW9ycyk7CiAgICAgICAgUG9seW1lckdlbmVyYXRlZC5wcm90b3R5cGUuYmVoYXZpb3JzID0gc3VwZXJCZWhhdmlvcnMgPwogICAgICAgICAgc3VwZXJCZWhhdmlvcnMuY29uY2F0KGJlaGF2aW9ycykgOiBiZWhhdmlvckxpc3Q7CiAgICAgIH0KCiAgICAgIGNvbnN0IGNvcHlQcm9wZXJ0aWVzVG9Qcm90byA9IChwcm90bykgPT4gewogICAgICAgIGlmIChiZWhhdmlvckxpc3QpIHsKICAgICAgICAgIGFwcGx5QmVoYXZpb3JzKHByb3RvLCBiZWhhdmlvckxpc3QsIGxpZmVjeWNsZSk7CiAgICAgICAgfQogICAgICAgIGFwcGx5SW5mbyhwcm90bywgaW5mbywgbGlmZWN5Y2xlLCBleGNsdWRlT25JbmZvKTsKICAgICAgfTsKCiAgICAgIC8vIGNvcHkgcHJvcGVydGllcyBpZiB3ZSdyZSBub3Qgb3B0aW1pemluZwogICAgICBpZiAoIVBvbHltZXIubGVnYWN5T3B0aW1pemF0aW9ucykgewogICAgICAgIGNvcHlQcm9wZXJ0aWVzVG9Qcm90byhQb2x5bWVyR2VuZXJhdGVkLnByb3RvdHlwZSk7CiAgICAgIH0KCiAgICAgIFBvbHltZXJHZW5lcmF0ZWQuZ2VuZXJhdGVkRnJvbSA9IGluZm87CgogICAgICByZXR1cm4gUG9seW1lckdlbmVyYXRlZDsKICAgIH0KCiAgICAvKioKICAgICAqIEdlbmVyYXRlcyBhIGNsYXNzIHRoYXQgZXh0ZW5kcyBgUG9seW1lci5MZWdhY3lFbGVtZW50YCBiYXNlZCBvbiB0aGUKICAgICAqIHByb3ZpZGVkIGluZm8gb2JqZWN0LiAgTWV0YWRhdGEgb2JqZWN0cyBvbiB0aGUgYGluZm9gIG9iamVjdAogICAgICogKGBwcm9wZXJ0aWVzYCwgYG9ic2VydmVyc2AsIGBsaXN0ZW5lcnNgLCBgYmVoYXZpb3JzYCwgYGlzYCkgYXJlIHVzZWQKICAgICAqIGZvciBQb2x5bWVyJ3MgbWV0YS1wcm9ncmFtbWluZyBzeXN0ZW1zLCBhbmQgYW55IGZ1bmN0aW9ucyBhcmUgY29waWVkCiAgICAgKiB0byB0aGUgZ2VuZXJhdGVkIGNsYXNzLgogICAgICoKICAgICAqIFZhbGlkICJtZXRhZGF0YSIgdmFsdWVzIGFyZSBhcyBmb2xsb3dzOgogICAgICoKICAgICAqIGBpc2A6IFN0cmluZyBwcm92aWRpbmcgdGhlIHRhZyBuYW1lIHRvIHJlZ2lzdGVyIHRoZSBlbGVtZW50IHVuZGVyLiBJbgogICAgICogYWRkaXRpb24sIGlmIGEgYGRvbS1tb2R1bGVgIHdpdGggdGhlIHNhbWUgaWQgZXhpc3RzLCB0aGUgZmlyc3QgdGVtcGxhdGUKICAgICAqIGluIHRoYXQgYGRvbS1tb2R1bGVgIHdpbGwgYmUgc3RhbXBlZCBpbnRvIHRoZSBzaGFkb3cgcm9vdCBvZiB0aGlzIGVsZW1lbnQsCiAgICAgKiB3aXRoIHN1cHBvcnQgZm9yIGRlY2xhcmF0aXZlIGV2ZW50IGxpc3RlbmVycyAoYG9uLS4uLmApLCBQb2x5bWVyIGRhdGEKICAgICAqIGJpbmRpbmdzIChgW1suLi5dXWAgYW5kIGB7ey4uLn19YCksIGFuZCBpZC1iYXNlZCBub2RlIGZpbmRpbmcgaW50bwogICAgICogYHRoaXMuJGAuCiAgICAgKgogICAgICogYHByb3BlcnRpZXNgOiBPYmplY3QgZGVzY3JpYmluZyBwcm9wZXJ0eS1yZWxhdGVkIG1ldGFkYXRhIHVzZWQgYnkgUG9seW1lcgogICAgICogZmVhdHVyZXMgKGtleTogcHJvcGVydHkgbmFtZXMsIHZhbHVlOiBvYmplY3QgY29udGFpbmluZyBwcm9wZXJ0eSBtZXRhZGF0YSkuCiAgICAgKiBWYWxpZCBrZXlzIGluIHBlci1wcm9wZXJ0eSBtZXRhZGF0YSBpbmNsdWRlOgogICAgICogLSBgdHlwZWAgKFN0cmluZ3xOdW1iZXJ8T2JqZWN0fEFycmF5fC4uLik6IFVzZWQgYnkKICAgICAqICAgYGF0dHJpYnV0ZUNoYW5nZWRDYWxsYmFja2AgdG8gZGV0ZXJtaW5lIGhvdyBzdHJpbmctYmFzZWQgYXR0cmlidXRlcwogICAgICogICBhcmUgZGVzZXJpYWxpemVkIHRvIEphdmFTY3JpcHQgcHJvcGVydHkgdmFsdWVzLgogICAgICogLSBgbm90aWZ5YCAoYm9vbGVhbik6IENhdXNlcyBhIGNoYW5nZSBpbiB0aGUgcHJvcGVydHkgdG8gZmlyZSBhCiAgICAgKiAgIG5vbi1idWJibGluZyBldmVudCBjYWxsZWQgYDxwcm9wZXJ0eT4tY2hhbmdlZGAuIEVsZW1lbnRzIHRoYXQgaGF2ZQogICAgICogICBlbmFibGVkIHR3by13YXkgYmluZGluZyB0byB0aGUgcHJvcGVydHkgdXNlIHRoaXMgZXZlbnQgdG8gb2JzZXJ2ZSBjaGFuZ2VzLgogICAgICogLSBgcmVhZE9ubHlgIChib29sZWFuKTogQ3JlYXRlcyBhIGdldHRlciBmb3IgdGhlIHByb3BlcnR5LCBidXQgbm8gc2V0dGVyLgogICAgICogICBUbyBzZXQgYSByZWFkLW9ubHkgcHJvcGVydHksIHVzZSB0aGUgcHJpdmF0ZSBzZXR0ZXIgbWV0aG9kCiAgICAgKiAgIGBfc2V0UHJvcGVydHkocHJvcGVydHksIHZhbHVlKWAuCiAgICAgKiAtIGBvYnNlcnZlcmAgKHN0cmluZyk6IE9ic2VydmVyIG1ldGhvZCBuYW1lIHRoYXQgd2lsbCBiZSBjYWxsZWQgd2hlbgogICAgICogICB0aGUgcHJvcGVydHkgY2hhbmdlcy4gVGhlIGFyZ3VtZW50cyBvZiB0aGUgbWV0aG9kIGFyZQogICAgICogICBgKHZhbHVlLCBwcmV2aW91c1ZhbHVlKWAuCiAgICAgKiAtIGBjb21wdXRlZGAgKHN0cmluZyk6IFN0cmluZyBkZXNjcmliaW5nIG1ldGhvZCBhbmQgZGVwZW5kZW50IHByb3BlcnRpZXMKICAgICAqICAgZm9yIGNvbXB1dGluZyB0aGUgdmFsdWUgb2YgdGhpcyBwcm9wZXJ0eSAoZS5nLiBgJ2NvbXB1dGVGb28oYmFyLCB6b3QpJ2ApLgogICAgICogICBDb21wdXRlZCBwcm9wZXJ0aWVzIGFyZSByZWFkLW9ubHkgYnkgZGVmYXVsdCBhbmQgY2FuIG9ubHkgYmUgY2hhbmdlZAogICAgICogICB2aWEgdGhlIHJldHVybiB2YWx1ZSBvZiB0aGUgY29tcHV0aW5nIG1ldGhvZC4KICAgICAqCiAgICAgKiBgb2JzZXJ2ZXJzYDogQXJyYXkgb2Ygc3RyaW5ncyBkZXNjcmliaW5nIG11bHRpLXByb3BlcnR5IG9ic2VydmVyIG1ldGhvZHMKICAgICAqICBhbmQgdGhlaXIgZGVwZW5kZW50IHByb3BlcnRpZXMgKGUuZy4gYCdvYnNlcnZlQUJDKGEsIGIsIGMpJ2ApLgogICAgICoKICAgICAqIGBsaXN0ZW5lcnNgOiBPYmplY3QgZGVzY3JpYmluZyBldmVudCBsaXN0ZW5lcnMgdG8gYmUgYWRkZWQgdG8gZWFjaAogICAgICogIGluc3RhbmNlIG9mIHRoaXMgZWxlbWVudCAoa2V5OiBldmVudCBuYW1lLCB2YWx1ZTogbWV0aG9kIG5hbWUpLgogICAgICoKICAgICAqIGBiZWhhdmlvcnNgOiBBcnJheSBvZiBhZGRpdGlvbmFsIGBpbmZvYCBvYmplY3RzIGNvbnRhaW5pbmcgbWV0YWRhdGEKICAgICAqIGFuZCBjYWxsYmFja3MgaW4gdGhlIHNhbWUgZm9ybWF0IGFzIHRoZSBgaW5mb2Agb2JqZWN0IGhlcmUgd2hpY2ggYXJlCiAgICAgKiBtZXJnZWQgaW50byB0aGlzIGVsZW1lbnQuCiAgICAgKgogICAgICogYGhvc3RBdHRyaWJ1dGVzYDogT2JqZWN0IGxpc3RpbmcgYXR0cmlidXRlcyB0byBiZSBhcHBsaWVkIHRvIHRoZSBob3N0CiAgICAgKiAgb25jZSBjcmVhdGVkIChrZXk6IGF0dHJpYnV0ZSBuYW1lLCB2YWx1ZTogYXR0cmlidXRlIHZhbHVlKS4gIFZhbHVlcwogICAgICogIGFyZSBzZXJpYWxpemVkIGJhc2VkIG9uIHRoZSB0eXBlIG9mIHRoZSB2YWx1ZS4gIEhvc3QgYXR0cmlidXRlcyBzaG91bGQKICAgICAqICBnZW5lcmFsbHkgYmUgbGltaXRlZCB0byBhdHRyaWJ1dGVzIHN1Y2ggYXMgYHRhYkluZGV4YCBhbmQgYGFyaWEtLi4uYC4KICAgICAqICBBdHRyaWJ1dGVzIGluIGBob3N0QXR0cmlidXRlc2AgYXJlIG9ubHkgYXBwbGllZCBpZiBhIHVzZXItc3VwcGxpZWQKICAgICAqICBhdHRyaWJ1dGUgaXMgbm90IGFscmVhZHkgcHJlc2VudCAoYXR0cmlidXRlcyBpbiBtYXJrdXAgb3ZlcnJpZGUKICAgICAqICBgaG9zdEF0dHJpYnV0ZXNgKS4KICAgICAqCiAgICAgKiBJbiBhZGRpdGlvbiwgdGhlIGZvbGxvd2luZyBQb2x5bWVyLXNwZWNpZmljIGNhbGxiYWNrcyBtYXkgYmUgcHJvdmlkZWQ6CiAgICAgKiAtIGByZWdpc3RlcmVkYDogY2FsbGVkIGFmdGVyIGZpcnN0IGluc3RhbmNlIG9mIHRoaXMgZWxlbWVudCwKICAgICAqIC0gYGNyZWF0ZWRgOiBjYWxsZWQgZHVyaW5nIGBjb25zdHJ1Y3RvcmAKICAgICAqIC0gYGF0dGFjaGVkYDogY2FsbGVkIGR1cmluZyBgY29ubmVjdGVkQ2FsbGJhY2tgCiAgICAgKiAtIGBkZXRhY2hlZGA6IGNhbGxlZCBkdXJpbmcgYGRpc2Nvbm5lY3RlZENhbGxiYWNrYAogICAgICogLSBgcmVhZHlgOiBjYWxsZWQgYmVmb3JlIGZpcnN0IGBhdHRhY2hlZGAsIGFmdGVyIGFsbCBwcm9wZXJ0aWVzIG9mCiAgICAgKiAgIHRoaXMgZWxlbWVudCBoYXZlIGJlZW4gcHJvcGFnYXRlZCB0byBpdHMgdGVtcGxhdGUgYW5kIGFsbCBvYnNlcnZlcnMKICAgICAqICAgaGF2ZSBydW4KICAgICAqCiAgICAgKiBAcGFyYW0geyFQb2x5bWVySW5pdH0gaW5mbyBPYmplY3QgY29udGFpbmluZyBQb2x5bWVyIG1ldGFkYXRhIGFuZCBmdW5jdGlvbnMKICAgICAqICAgdG8gYmVjb21lIGNsYXNzIG1ldGhvZHMuCiAgICAgKiBAdGVtcGxhdGUgVAogICAgICogQHBhcmFtIHtmdW5jdGlvbihUKTpUfSBtaXhpbiBPcHRpb25hbCBtaXhpbiB0byBhcHBseSB0byBsZWdhY3kgYmFzZSBjbGFzcwogICAgICogICBiZWZvcmUgZXh0ZW5kaW5nIHdpdGggUG9seW1lciBtZXRhcHJvZ3JhbW1pbmcuCiAgICAgKiBAcmV0dXJuIHtmdW5jdGlvbihuZXc6SFRNTEVsZW1lbnQpfSBHZW5lcmF0ZWQgY2xhc3MKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICAgKi8KICAgIFBvbHltZXIuQ2xhc3MgPSBmdW5jdGlvbihpbmZvLCBtaXhpbikgewogICAgICBpZiAoIWluZm8pIHsKICAgICAgICBjb25zb2xlLndhcm4oJ1BvbHltZXIuQ2xhc3MgcmVxdWlyZXMgYGluZm9gIGFyZ3VtZW50Jyk7CiAgICAgIH0KICAgICAgbGV0IGtsYXNzID0gbWl4aW4gPyBtaXhpbihQb2x5bWVyLkxlZ2FjeUVsZW1lbnRNaXhpbihIVE1MRWxlbWVudCkpIDoKICAgICAgICAgIFBvbHltZXIuTGVnYWN5RWxlbWVudE1peGluKEhUTUxFbGVtZW50KTsKICAgICAga2xhc3MgPSBHZW5lcmF0ZUNsYXNzRnJvbUluZm8oaW5mbywga2xhc3MsIGluZm8uYmVoYXZpb3JzKTsKICAgICAgaWYgKGluZm8uX2VuYWJsZURpc2FibGVVcGdyYWRlKSB7CiAgICAgICAga2xhc3MgPSBQb2x5bWVyLkRpc2FibGVVcGdyYWRlTWl4aW4oa2xhc3MpOwogICAgICB9CiAgICAgIC8vIGRlY29yYXRlIGtsYXNzIHdpdGggcmVnaXN0cmF0aW9uIGluZm8KICAgICAga2xhc3MuaXMgPSBrbGFzcy5wcm90b3R5cGUuaXMgPSBpbmZvLmlzOwogICAgICByZXR1cm4ga2xhc3M7CiAgICB9OwoKICAgIFBvbHltZXIubWl4aW5CZWhhdmlvcnMgPSBtaXhpbkJlaGF2aW9yczsKCiAgfSkoKTsKCjwvc2NyaXB0PjxzY3JpcHQ+CgogIChmdW5jdGlvbigpIHsKICAgICd1c2Ugc3RyaWN0JzsKCiAgICAvKioKICAgICAqIExlZ2FjeSBjbGFzcyBmYWN0b3J5IGFuZCByZWdpc3RyYXRpb24gaGVscGVyIGZvciBkZWZpbmluZyBQb2x5bWVyCiAgICAgKiBlbGVtZW50cy4KICAgICAqCiAgICAgKiBUaGlzIG1ldGhvZCBpcyBlcXVpdmFsZW50IHRvCiAgICAgKiBgY3VzdG9tRWxlbWVudHMuZGVmaW5lKGluZm8uaXMsIFBvbHltZXIuQ2xhc3MoaW5mbykpO2AKICAgICAqCiAgICAgKiBTZWUgYFBvbHltZXIuQ2xhc3NgIGZvciBkZXRhaWxzIG9uIHZhbGlkIGxlZ2FjeSBtZXRhZGF0YSBmb3JtYXQgZm9yIGBpbmZvYC4KICAgICAqCiAgICAgKiBAZ2xvYmFsCiAgICAgKiBAb3ZlcnJpZGUKICAgICAqIEBmdW5jdGlvbiBQb2x5bWVyCiAgICAgKiBAcGFyYW0geyFQb2x5bWVySW5pdH0gaW5mbyBPYmplY3QgY29udGFpbmluZyBQb2x5bWVyIG1ldGFkYXRhIGFuZCBmdW5jdGlvbnMKICAgICAqICAgdG8gYmVjb21lIGNsYXNzIG1ldGhvZHMuCiAgICAgKiBAcmV0dXJuIHtmdW5jdGlvbihuZXc6IEhUTUxFbGVtZW50KX0gR2VuZXJhdGVkIGNsYXNzCiAgICAgKiBAc3VwcHJlc3Mge2R1cGxpY2F0ZSwgaW52YWxpZENhc3RzLCBjaGVja1R5cGVzfQogICAgICovCiAgICB3aW5kb3cuUG9seW1lci5fcG9seW1lckZuID0gZnVuY3Rpb24oaW5mbykgewogICAgICAvLyBpZiBpbnB1dCBpcyBhIGBjbGFzc2AgKGFrYSBhIGZ1bmN0aW9uIHdpdGggYSBwcm90b3R5cGUpLCB1c2UgdGhlIHByb3RvdHlwZQogICAgICAvLyByZW1lbWJlciB0aGF0IHRoZSBgY29uc3RydWN0b3JgIHdpbGwgbmV2ZXIgYmUgY2FsbGVkCiAgICAgIGxldCBrbGFzczsKICAgICAgaWYgKHR5cGVvZiBpbmZvID09PSAnZnVuY3Rpb24nKSB7CiAgICAgICAga2xhc3MgPSBpbmZvOwogICAgICB9IGVsc2UgewogICAgICAgIGtsYXNzID0gUG9seW1lci5DbGFzcyhpbmZvKTsKICAgICAgfQogICAgICBjdXN0b21FbGVtZW50cy5kZWZpbmUoa2xhc3MuaXMsIC8qKiBAdHlwZSB7IUhUTUxFbGVtZW50fSAqLyhrbGFzcykpOwogICAgICByZXR1cm4ga2xhc3M7CiAgICB9OwoKICB9KSgpOwoKPC9zY3JpcHQ+PHNjcmlwdD4KKGZ1bmN0aW9uKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgLy8gQ29tbW9uIGltcGxlbWVudGF0aW9uIGZvciBtaXhpbiAmIGJlaGF2aW9yCiAgZnVuY3Rpb24gbXV0YWJsZVByb3BlcnR5Q2hhbmdlKGluc3QsIHByb3BlcnR5LCB2YWx1ZSwgb2xkLCBtdXRhYmxlRGF0YSkgewogICAgbGV0IGlzT2JqZWN0OwogICAgaWYgKG11dGFibGVEYXRhKSB7CiAgICAgIGlzT2JqZWN0ID0gKHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgIT09IG51bGwpOwogICAgICAvLyBQdWxsIGBvbGRgIGZvciBPYmplY3RzIGZyb20gdGVtcCBjYWNoZSwgYnV0IHRyZWF0IGBudWxsYCBhcyBhIHByaW1pdGl2ZQogICAgICBpZiAoaXNPYmplY3QpIHsKICAgICAgICBvbGQgPSBpbnN0Ll9fZGF0YVRlbXBbcHJvcGVydHldOwogICAgICB9CiAgICB9CiAgICAvLyBTdHJpY3QgZXF1YWxpdHkgY2hlY2ssIGJ1dCByZXR1cm4gZmFsc2UgZm9yIE5hTj09PU5hTgogICAgbGV0IHNob3VsZENoYW5nZSA9IChvbGQgIT09IHZhbHVlICYmIChvbGQgPT09IG9sZCB8fCB2YWx1ZSA9PT0gdmFsdWUpKTsKICAgIC8vIE9iamVjdHMgYXJlIHN0b3JlZCBpbiB0ZW1wb3JhcnkgY2FjaGUgKGNsZWFyZWQgYXQgZW5kIG9mCiAgICAvLyB0dXJuKSwgd2hpY2ggaXMgdXNlZCBmb3IgZGlydHktY2hlY2tpbmcKICAgIGlmIChpc09iamVjdCAmJiBzaG91bGRDaGFuZ2UpIHsKICAgICAgaW5zdC5fX2RhdGFUZW1wW3Byb3BlcnR5XSA9IHZhbHVlOwogICAgfQogICAgcmV0dXJuIHNob3VsZENoYW5nZTsKICB9CgogIC8qKgogICAqIEVsZW1lbnQgY2xhc3MgbWl4aW4gdG8gc2tpcCBzdHJpY3QgZGlydHktY2hlY2tpbmcgZm9yIG9iamVjdHMgYW5kIGFycmF5cwogICAqIChhbHdheXMgY29uc2lkZXIgdGhlbSB0byBiZSAiZGlydHkiKSwgZm9yIHVzZSBvbiBlbGVtZW50cyB1dGlsaXppbmcKICAgKiBgUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHNgCiAgICoKICAgKiBCeSBkZWZhdWx0LCBgUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHNgIHBlcmZvcm1zIHN0cmljdCBkaXJ0eSBjaGVja2luZyBvbgogICAqIG9iamVjdHMsIHdoaWNoIG1lYW5zIHRoYXQgYW55IGRlZXAgbW9kaWZpY2F0aW9ucyB0byBhbiBvYmplY3Qgb3IgYXJyYXkgd2lsbAogICAqIG5vdCBiZSBwcm9wYWdhdGVkIHVubGVzcyAiaW1tdXRhYmxlIiBkYXRhIHBhdHRlcm5zIGFyZSB1c2VkIChpLmUuIGFsbCBvYmplY3QKICAgKiByZWZlcmVuY2VzIGZyb20gdGhlIHJvb3QgdG8gdGhlIG11dGF0aW9uIHdlcmUgY2hhbmdlZCkuCiAgICoKICAgKiBQb2x5bWVyIGFsc28gcHJvdmlkZXMgYSBwcm9wcmlldGFyeSBkYXRhIG11dGF0aW9uIGFuZCBwYXRoIG5vdGlmaWNhdGlvbiBBUEkKICAgKiAoZS5nLiBgbm90aWZ5UGF0aGAsIGBzZXRgLCBhbmQgYXJyYXkgbXV0YXRpb24gQVBJJ3MpIHRoYXQgYWxsb3cgZWZmaWNpZW50CiAgICogbXV0YXRpb24gYW5kIG5vdGlmaWNhdGlvbiBvZiBkZWVwIGNoYW5nZXMgaW4gYW4gb2JqZWN0IGdyYXBoIHRvIGFsbCBlbGVtZW50cwogICAqIGJvdW5kIHRvIHRoZSBzYW1lIG9iamVjdCBncmFwaC4KICAgKgogICAqIEluIGNhc2VzIHdoZXJlIG5laXRoZXIgaW1tdXRhYmxlIHBhdHRlcm5zIG5vciB0aGUgZGF0YSBtdXRhdGlvbiBBUEkgY2FuIGJlCiAgICogdXNlZCwgYXBwbHlpbmcgdGhpcyBtaXhpbiB3aWxsIGNhdXNlIFBvbHltZXIgdG8gc2tpcCBkaXJ0eSBjaGVja2luZyBmb3IKICAgKiBvYmplY3RzIGFuZCBhcnJheXMgKGFsd2F5cyBjb25zaWRlciB0aGVtIHRvIGJlICJkaXJ0eSIpLiAgVGhpcyBhbGxvd3MgYQogICAqIHVzZXIgdG8gbWFrZSBhIGRlZXAgbW9kaWZpY2F0aW9uIHRvIGEgYm91bmQgb2JqZWN0IGdyYXBoLCBhbmQgdGhlbiBlaXRoZXIKICAgKiBzaW1wbHkgcmUtc2V0IHRoZSBvYmplY3QgKGUuZy4gYHRoaXMuaXRlbXMgPSB0aGlzLml0ZW1zYCkgb3IgY2FsbCBgbm90aWZ5UGF0aGAKICAgKiAoZS5nLiBgdGhpcy5ub3RpZnlQYXRoKCdpdGVtcycpYCkgdG8gdXBkYXRlIHRoZSB0cmVlLiAgTm90ZSB0aGF0IGFsbAogICAqIGVsZW1lbnRzIHRoYXQgd2lzaCB0byBiZSB1cGRhdGVkIGJhc2VkIG9uIGRlZXAgbXV0YXRpb25zIG11c3QgYXBwbHkgdGhpcwogICAqIG1peGluIG9yIG90aGVyd2lzZSBza2lwIHN0cmljdCBkaXJ0eSBjaGVja2luZyBmb3Igb2JqZWN0cy9hcnJheXMuCiAgICogU3BlY2lmaWNhbGx5LCBhbnkgZWxlbWVudHMgaW4gdGhlIGJpbmRpbmcgdHJlZSBiZXR3ZWVuIHRoZSBzb3VyY2Ugb2YgYQogICAqIG11dGF0aW9uIGFuZCB0aGUgY29uc3VtcHRpb24gb2YgaXQgbXVzdCBhcHBseSB0aGlzIG1peGluIG9yIGVuYWJsZSB0aGUKICAgKiBgUG9seW1lci5PcHRpb25hbE11dGFibGVEYXRhYCBtaXhpbi4KICAgKgogICAqIEluIG9yZGVyIHRvIG1ha2UgdGhlIGRpcnR5IGNoZWNrIHN0cmF0ZWd5IGNvbmZpZ3VyYWJsZSwgc2VlCiAgICogYFBvbHltZXIuT3B0aW9uYWxNdXRhYmxlRGF0YWAuCiAgICoKICAgKiBOb3RlLCB0aGUgcGVyZm9ybWFuY2UgY2hhcmFjdGVyaXN0aWNzIG9mIHByb3BhZ2F0aW5nIGxhcmdlIG9iamVjdCBncmFwaHMKICAgKiB3aWxsIGJlIHdvcnNlIGFzIG9wcG9zZWQgdG8gdXNpbmcgc3RyaWN0IGRpcnR5IGNoZWNraW5nIHdpdGggaW1tdXRhYmxlCiAgICogcGF0dGVybnMgb3IgUG9seW1lcidzIHBhdGggbm90aWZpY2F0aW9uIEFQSS4KICAgKgogICAqIEBtaXhpbkZ1bmN0aW9uCiAgICogQHBvbHltZXIKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBzdW1tYXJ5IEVsZW1lbnQgY2xhc3MgbWl4aW4gdG8gc2tpcCBzdHJpY3QgZGlydHktY2hlY2tpbmcgZm9yIG9iamVjdHMKICAgKiAgIGFuZCBhcnJheXMKICAgKi8KICBQb2x5bWVyLk11dGFibGVEYXRhID0gUG9seW1lci5kZWR1cGluZ01peGluKHN1cGVyQ2xhc3MgPT4gewoKICAgIC8qKgogICAgICogQHBvbHltZXIKICAgICAqIEBtaXhpbkNsYXNzCiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9NdXRhYmxlRGF0YX0KICAgICAqLwogICAgY2xhc3MgTXV0YWJsZURhdGEgZXh0ZW5kcyBzdXBlckNsYXNzIHsKICAgICAgLyoqCiAgICAgICAqIE92ZXJyaWRlcyBgUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHNgIHRvIHByb3ZpZGUgb3B0aW9uIGZvciBza2lwcGluZwogICAgICAgKiBzdHJpY3QgZXF1YWxpdHkgY2hlY2tpbmcgZm9yIE9iamVjdHMgYW5kIEFycmF5cy4KICAgICAgICoKICAgICAgICogVGhpcyBtZXRob2QgcHVsbHMgdGhlIHZhbHVlIHRvIGRpcnR5IGNoZWNrIGFnYWluc3QgZnJvbSB0aGUgYF9fZGF0YVRlbXBgCiAgICAgICAqIGNhY2hlIChyYXRoZXIgdGhhbiB0aGUgbm9ybWFsIGBfX2RhdGFgIGNhY2hlKSBmb3IgT2JqZWN0cy4gIFNpbmNlIHRoZSB0ZW1wCiAgICAgICAqIGNhY2hlIGlzIGNsZWFyZWQgYXQgdGhlIGVuZCBvZiBhIHR1cm4sIHRoaXMgaW1wbGVtZW50YXRpb24gYWxsb3dzCiAgICAgICAqIHNpZGUtZWZmZWN0cyBvZiBkZWVwIG9iamVjdCBjaGFuZ2VzIHRvIGJlIHByb2Nlc3NlZCBieSByZS1zZXR0aW5nIHRoZQogICAgICAgKiBzYW1lIG9iamVjdCAodXNpbmcgdGhlIHRlbXAgY2FjaGUgYXMgYW4gaW4tdHVybiBiYWNrc3RvcCB0byBwcmV2ZW50CiAgICAgICAqIGN5Y2xlcyBkdWUgdG8gMi13YXkgbm90aWZpY2F0aW9uKS4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHByb3BlcnR5IFByb3BlcnR5IG5hbWUKICAgICAgICogQHBhcmFtIHsqfSB2YWx1ZSBOZXcgcHJvcGVydHkgdmFsdWUKICAgICAgICogQHBhcmFtIHsqfSBvbGQgUHJldmlvdXMgcHJvcGVydHkgdmFsdWUKICAgICAgICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgcHJvcGVydHkgc2hvdWxkIGJlIGNvbnNpZGVyZWQgYSBjaGFuZ2UKICAgICAgICogQHByb3RlY3RlZAogICAgICAgKi8KICAgICAgX3Nob3VsZFByb3BlcnR5Q2hhbmdlKHByb3BlcnR5LCB2YWx1ZSwgb2xkKSB7CiAgICAgICAgcmV0dXJuIG11dGFibGVQcm9wZXJ0eUNoYW5nZSh0aGlzLCBwcm9wZXJ0eSwgdmFsdWUsIG9sZCwgdHJ1ZSk7CiAgICAgIH0KCiAgICB9CgogICAgcmV0dXJuIE11dGFibGVEYXRhOwoKICB9KTsKCgogIC8qKgogICAqIEVsZW1lbnQgY2xhc3MgbWl4aW4gdG8gYWRkIHRoZSBvcHRpb25hbCBhYmlsaXR5IHRvIHNraXAgc3RyaWN0CiAgICogZGlydHktY2hlY2tpbmcgZm9yIG9iamVjdHMgYW5kIGFycmF5cyAoYWx3YXlzIGNvbnNpZGVyIHRoZW0gdG8gYmUKICAgKiAiZGlydHkiKSBieSBzZXR0aW5nIGEgYG11dGFibGUtZGF0YWAgYXR0cmlidXRlIG9uIGFuIGVsZW1lbnQgaW5zdGFuY2UuCiAgICoKICAgKiBCeSBkZWZhdWx0LCBgUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHNgIHBlcmZvcm1zIHN0cmljdCBkaXJ0eSBjaGVja2luZyBvbgogICAqIG9iamVjdHMsIHdoaWNoIG1lYW5zIHRoYXQgYW55IGRlZXAgbW9kaWZpY2F0aW9ucyB0byBhbiBvYmplY3Qgb3IgYXJyYXkgd2lsbAogICAqIG5vdCBiZSBwcm9wYWdhdGVkIHVubGVzcyAiaW1tdXRhYmxlIiBkYXRhIHBhdHRlcm5zIGFyZSB1c2VkIChpLmUuIGFsbCBvYmplY3QKICAgKiByZWZlcmVuY2VzIGZyb20gdGhlIHJvb3QgdG8gdGhlIG11dGF0aW9uIHdlcmUgY2hhbmdlZCkuCiAgICoKICAgKiBQb2x5bWVyIGFsc28gcHJvdmlkZXMgYSBwcm9wcmlldGFyeSBkYXRhIG11dGF0aW9uIGFuZCBwYXRoIG5vdGlmaWNhdGlvbiBBUEkKICAgKiAoZS5nLiBgbm90aWZ5UGF0aGAsIGBzZXRgLCBhbmQgYXJyYXkgbXV0YXRpb24gQVBJJ3MpIHRoYXQgYWxsb3cgZWZmaWNpZW50CiAgICogbXV0YXRpb24gYW5kIG5vdGlmaWNhdGlvbiBvZiBkZWVwIGNoYW5nZXMgaW4gYW4gb2JqZWN0IGdyYXBoIHRvIGFsbCBlbGVtZW50cwogICAqIGJvdW5kIHRvIHRoZSBzYW1lIG9iamVjdCBncmFwaC4KICAgKgogICAqIEluIGNhc2VzIHdoZXJlIG5laXRoZXIgaW1tdXRhYmxlIHBhdHRlcm5zIG5vciB0aGUgZGF0YSBtdXRhdGlvbiBBUEkgY2FuIGJlCiAgICogdXNlZCwgYXBwbHlpbmcgdGhpcyBtaXhpbiB3aWxsIGFsbG93IFBvbHltZXIgdG8gc2tpcCBkaXJ0eSBjaGVja2luZyBmb3IKICAgKiBvYmplY3RzIGFuZCBhcnJheXMgKGFsd2F5cyBjb25zaWRlciB0aGVtIHRvIGJlICJkaXJ0eSIpLiAgVGhpcyBhbGxvd3MgYQogICAqIHVzZXIgdG8gbWFrZSBhIGRlZXAgbW9kaWZpY2F0aW9uIHRvIGEgYm91bmQgb2JqZWN0IGdyYXBoLCBhbmQgdGhlbiBlaXRoZXIKICAgKiBzaW1wbHkgcmUtc2V0IHRoZSBvYmplY3QgKGUuZy4gYHRoaXMuaXRlbXMgPSB0aGlzLml0ZW1zYCkgb3IgY2FsbCBgbm90aWZ5UGF0aGAKICAgKiAoZS5nLiBgdGhpcy5ub3RpZnlQYXRoKCdpdGVtcycpYCkgdG8gdXBkYXRlIHRoZSB0cmVlLiAgTm90ZSB0aGF0IGFsbAogICAqIGVsZW1lbnRzIHRoYXQgd2lzaCB0byBiZSB1cGRhdGVkIGJhc2VkIG9uIGRlZXAgbXV0YXRpb25zIG11c3QgYXBwbHkgdGhpcwogICAqIG1peGluIG9yIG90aGVyd2lzZSBza2lwIHN0cmljdCBkaXJ0eSBjaGVja2luZyBmb3Igb2JqZWN0cy9hcnJheXMuCiAgICogU3BlY2lmaWNhbGx5LCBhbnkgZWxlbWVudHMgaW4gdGhlIGJpbmRpbmcgdHJlZSBiZXR3ZWVuIHRoZSBzb3VyY2Ugb2YgYQogICAqIG11dGF0aW9uIGFuZCB0aGUgY29uc3VtcHRpb24gb2YgaXQgbXVzdCBlbmFibGUgdGhpcyBtaXhpbiBvciBhcHBseSB0aGUKICAgKiBgUG9seW1lci5NdXRhYmxlRGF0YWAgbWl4aW4uCiAgICoKICAgKiBXaGlsZSB0aGlzIG1peGluIGFkZHMgdGhlIGFiaWxpdHkgdG8gZm9yZ28gT2JqZWN0L0FycmF5IGRpcnR5IGNoZWNraW5nLAogICAqIHRoZSBgbXV0YWJsZURhdGFgIGZsYWcgZGVmYXVsdHMgdG8gZmFsc2UgYW5kIG11c3QgYmUgc2V0IG9uIHRoZSBpbnN0YW5jZS4KICAgKgogICAqIE5vdGUsIHRoZSBwZXJmb3JtYW5jZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgcHJvcGFnYXRpbmcgbGFyZ2Ugb2JqZWN0IGdyYXBocwogICAqIHdpbGwgYmUgd29yc2UgYnkgcmVseWluZyBvbiBgbXV0YWJsZURhdGE6IHRydWVgIGFzIG9wcG9zZWQgdG8gdXNpbmcKICAgKiBzdHJpY3QgZGlydHkgY2hlY2tpbmcgd2l0aCBpbW11dGFibGUgcGF0dGVybnMgb3IgUG9seW1lcidzIHBhdGggbm90aWZpY2F0aW9uCiAgICogQVBJLgogICAqCiAgICogQG1peGluRnVuY3Rpb24KICAgKiBAcG9seW1lcgogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICogQHN1bW1hcnkgRWxlbWVudCBjbGFzcyBtaXhpbiB0byBvcHRpb25hbGx5IHNraXAgc3RyaWN0IGRpcnR5LWNoZWNraW5nCiAgICogICBmb3Igb2JqZWN0cyBhbmQgYXJyYXlzCiAgICovCiAgUG9seW1lci5PcHRpb25hbE11dGFibGVEYXRhID0gUG9seW1lci5kZWR1cGluZ01peGluKHN1cGVyQ2xhc3MgPT4gewoKICAgIC8qKgogICAgICogQG1peGluQ2xhc3MKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9PcHRpb25hbE11dGFibGVEYXRhfQogICAgICovCiAgICBjbGFzcyBPcHRpb25hbE11dGFibGVEYXRhIGV4dGVuZHMgc3VwZXJDbGFzcyB7CgogICAgICBzdGF0aWMgZ2V0IHByb3BlcnRpZXMoKSB7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIC8qKgogICAgICAgICAgICogSW5zdGFuY2UtbGV2ZWwgZmxhZyBmb3IgY29uZmlndXJpbmcgdGhlIGRpcnR5LWNoZWNraW5nIHN0cmF0ZWd5CiAgICAgICAgICAgKiBmb3IgdGhpcyBlbGVtZW50LiAgV2hlbiB0cnVlLCBPYmplY3RzIGFuZCBBcnJheXMgd2lsbCBza2lwIGRpcnR5CiAgICAgICAgICAgKiBjaGVja2luZywgb3RoZXJ3aXNlIHN0cmljdCBlcXVhbGl0eSBjaGVja2luZyB3aWxsIGJlIHVzZWQuCiAgICAgICAgICAgKi8KICAgICAgICAgIG11dGFibGVEYXRhOiBCb29sZWFuCiAgICAgICAgfTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIE92ZXJyaWRlcyBgUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHNgIHRvIHByb3ZpZGUgb3B0aW9uIGZvciBza2lwcGluZwogICAgICAgKiBzdHJpY3QgZXF1YWxpdHkgY2hlY2tpbmcgZm9yIE9iamVjdHMgYW5kIEFycmF5cy4KICAgICAgICoKICAgICAgICogV2hlbiBgdGhpcy5tdXRhYmxlRGF0YWAgaXMgdHJ1ZSBvbiB0aGlzIGluc3RhbmNlLCB0aGlzIG1ldGhvZAogICAgICAgKiBwdWxscyB0aGUgdmFsdWUgdG8gZGlydHkgY2hlY2sgYWdhaW5zdCBmcm9tIHRoZSBgX19kYXRhVGVtcGAgY2FjaGUKICAgICAgICogKHJhdGhlciB0aGFuIHRoZSBub3JtYWwgYF9fZGF0YWAgY2FjaGUpIGZvciBPYmplY3RzLiAgU2luY2UgdGhlIHRlbXAKICAgICAgICogY2FjaGUgaXMgY2xlYXJlZCBhdCB0aGUgZW5kIG9mIGEgdHVybiwgdGhpcyBpbXBsZW1lbnRhdGlvbiBhbGxvd3MKICAgICAgICogc2lkZS1lZmZlY3RzIG9mIGRlZXAgb2JqZWN0IGNoYW5nZXMgdG8gYmUgcHJvY2Vzc2VkIGJ5IHJlLXNldHRpbmcgdGhlCiAgICAgICAqIHNhbWUgb2JqZWN0ICh1c2luZyB0aGUgdGVtcCBjYWNoZSBhcyBhbiBpbi10dXJuIGJhY2tzdG9wIHRvIHByZXZlbnQKICAgICAgICogY3ljbGVzIGR1ZSB0byAyLXdheSBub3RpZmljYXRpb24pLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgUHJvcGVydHkgbmFtZQogICAgICAgKiBAcGFyYW0geyp9IHZhbHVlIE5ldyBwcm9wZXJ0eSB2YWx1ZQogICAgICAgKiBAcGFyYW0geyp9IG9sZCBQcmV2aW91cyBwcm9wZXJ0eSB2YWx1ZQogICAgICAgKiBAcmV0dXJuIHtib29sZWFufSBXaGV0aGVyIHRoZSBwcm9wZXJ0eSBzaG91bGQgYmUgY29uc2lkZXJlZCBhIGNoYW5nZQogICAgICAgKiBAcHJvdGVjdGVkCiAgICAgICAqLwogICAgICBfc2hvdWxkUHJvcGVydHlDaGFuZ2UocHJvcGVydHksIHZhbHVlLCBvbGQpIHsKICAgICAgICByZXR1cm4gbXV0YWJsZVByb3BlcnR5Q2hhbmdlKHRoaXMsIHByb3BlcnR5LCB2YWx1ZSwgb2xkLCB0aGlzLm11dGFibGVEYXRhKTsKICAgICAgfQogICAgfQoKICAgIHJldHVybiBPcHRpb25hbE11dGFibGVEYXRhOwoKICB9KTsKCiAgLy8gRXhwb3J0IGZvciB1c2UgYnkgbGVnYWN5IGJlaGF2aW9yCiAgUG9seW1lci5NdXRhYmxlRGF0YS5fbXV0YWJsZVByb3BlcnR5Q2hhbmdlID0gbXV0YWJsZVByb3BlcnR5Q2hhbmdlOwoKfSkoKTsKPC9zY3JpcHQ+PHNjcmlwdD4KICAoZnVuY3Rpb24oKSB7CiAgICAndXNlIHN0cmljdCc7CgogICAgLy8gQmFzZSBjbGFzcyBmb3IgSFRNTFRlbXBsYXRlRWxlbWVudCBleHRlbnNpb24gdGhhdCBoYXMgcHJvcGVydHkgZWZmZWN0cwogICAgLy8gbWFjaGluZXJ5IGZvciBwcm9wYWdhdGluZyBob3N0IHByb3BlcnRpZXMgdG8gY2hpbGRyZW4uIFRoaXMgaXMgYW4gRVM1CiAgICAvLyBjbGFzcyBvbmx5IGJlY2F1c2UgQmFiZWwgKGluY29ycmVjdGx5KSByZXF1aXJlcyBzdXBlcigpIGluIHRoZSBjbGFzcwogICAgLy8gY29uc3RydWN0b3IgZXZlbiB0aG91Z2ggbm8gYHRoaXNgIGlzIHVzZWQgYW5kIGl0IHJldHVybnMgYW4gaW5zdGFuY2UuCiAgICBsZXQgbmV3SW5zdGFuY2UgPSBudWxsOwoKICAgIC8qKgogICAgICogQGNvbnN0cnVjdG9yCiAgICAgKiBAZXh0ZW5kcyB7SFRNTFRlbXBsYXRlRWxlbWVudH0KICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIGZ1bmN0aW9uIEhUTUxUZW1wbGF0ZUVsZW1lbnRFeHRlbnNpb24oKSB7IHJldHVybiBuZXdJbnN0YW5jZTsgfQogICAgSFRNTFRlbXBsYXRlRWxlbWVudEV4dGVuc2lvbi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEhUTUxUZW1wbGF0ZUVsZW1lbnQucHJvdG90eXBlLCB7CiAgICAgIGNvbnN0cnVjdG9yOiB7CiAgICAgICAgdmFsdWU6IEhUTUxUZW1wbGF0ZUVsZW1lbnRFeHRlbnNpb24sCiAgICAgICAgd3JpdGFibGU6IHRydWUKICAgICAgfQogICAgfSk7CgogICAgLyoqCiAgICAgKiBAY29uc3RydWN0b3IKICAgICAqIEBpbXBsZW1lbnRzIHtQb2x5bWVyX1Byb3BlcnR5RWZmZWN0c30KICAgICAqIEBleHRlbmRzIHtIVE1MVGVtcGxhdGVFbGVtZW50RXh0ZW5zaW9ufQogICAgICogQHByaXZhdGUKICAgICAqLwogICAgY29uc3QgRGF0YVRlbXBsYXRlID0gUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHMoSFRNTFRlbXBsYXRlRWxlbWVudEV4dGVuc2lvbik7CgogICAgLyoqCiAgICAgKiBAY29uc3RydWN0b3IKICAgICAqIEBpbXBsZW1lbnRzIHtQb2x5bWVyX011dGFibGVEYXRhfQogICAgICogQGV4dGVuZHMge0RhdGFUZW1wbGF0ZX0KICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIGNvbnN0IE11dGFibGVEYXRhVGVtcGxhdGUgPSBQb2x5bWVyLk11dGFibGVEYXRhKERhdGFUZW1wbGF0ZSk7CgogICAgLy8gQXBwbGllcyBhIERhdGFUZW1wbGF0ZSBzdWJjbGFzcyB0byBhIDx0ZW1wbGF0ZT4gaW5zdGFuY2UKICAgIGZ1bmN0aW9uIHVwZ3JhZGVUZW1wbGF0ZSh0ZW1wbGF0ZSwgY29uc3RydWN0b3IpIHsKICAgICAgbmV3SW5zdGFuY2UgPSB0ZW1wbGF0ZTsKICAgICAgT2JqZWN0LnNldFByb3RvdHlwZU9mKHRlbXBsYXRlLCBjb25zdHJ1Y3Rvci5wcm90b3R5cGUpOwogICAgICBuZXcgY29uc3RydWN0b3IoKTsKICAgICAgbmV3SW5zdGFuY2UgPSBudWxsOwogICAgfQoKICAgIC8qKgogICAgICogQmFzZSBjbGFzcyBmb3IgVGVtcGxhdGVJbnN0YW5jZS4KICAgICAqIEBjb25zdHJ1Y3RvcgogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfUHJvcGVydHlFZmZlY3RzfQogICAgICogQHByaXZhdGUKICAgICAqLwogICAgY29uc3QgYmFzZSA9IFBvbHltZXIuUHJvcGVydHlFZmZlY3RzKGNsYXNzIHt9KTsKCiAgICAvKioKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAY3VzdG9tRWxlbWVudAogICAgICogQGFwcGxpZXNNaXhpbiBQb2x5bWVyLlByb3BlcnR5RWZmZWN0cwogICAgICogQHVucmVzdHJpY3RlZAogICAgICovCiAgICBjbGFzcyBUZW1wbGF0ZUluc3RhbmNlQmFzZSBleHRlbmRzIGJhc2UgewogICAgICBjb25zdHJ1Y3Rvcihwcm9wcykgewogICAgICAgIHN1cGVyKCk7CiAgICAgICAgdGhpcy5fY29uZmlndXJlUHJvcGVydGllcyhwcm9wcyk7CiAgICAgICAgdGhpcy5yb290ID0gdGhpcy5fc3RhbXBUZW1wbGF0ZSh0aGlzLl9fZGF0YUhvc3QpOwogICAgICAgIC8vIFNhdmUgbGlzdCBvZiBzdGFtcGVkIGNoaWxkcmVuCiAgICAgICAgbGV0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbiA9IFtdOwogICAgICAgIGZvciAobGV0IG4gPSB0aGlzLnJvb3QuZmlyc3RDaGlsZDsgbjsgbj1uLm5leHRTaWJsaW5nKSB7CiAgICAgICAgICBjaGlsZHJlbi5wdXNoKG4pOwogICAgICAgICAgbi5fX3RlbXBsYXRpemVJbnN0YW5jZSA9IHRoaXM7CiAgICAgICAgfQogICAgICAgIGlmICh0aGlzLl9fdGVtcGxhdGl6ZU93bmVyICYmCiAgICAgICAgICB0aGlzLl9fdGVtcGxhdGl6ZU93bmVyLl9faGlkZVRlbXBsYXRlQ2hpbGRyZW5fXykgewogICAgICAgICAgdGhpcy5fc2hvd0hpZGVDaGlsZHJlbih0cnVlKTsKICAgICAgICB9CiAgICAgICAgLy8gRmx1c2ggcHJvcHMgb25seSB3aGVuIHByb3BzIGFyZSBwYXNzZWQgaWYgaW5zdGFuY2UgcHJvcHMgZXhpc3QKICAgICAgICAvLyBvciB3aGVuIHRoZXJlIGlzbid0IGluc3RhbmNlIHByb3BzLgogICAgICAgIGxldCBvcHRpb25zID0gdGhpcy5fX3RlbXBsYXRpemVPcHRpb25zOwogICAgICAgIGlmICgocHJvcHMgJiYgb3B0aW9ucy5pbnN0YW5jZVByb3BzKSB8fCAhb3B0aW9ucy5pbnN0YW5jZVByb3BzKSB7CiAgICAgICAgICB0aGlzLl9lbmFibGVQcm9wZXJ0aWVzKCk7CiAgICAgICAgfQogICAgICB9CiAgICAgIC8qKgogICAgICAgKiBDb25maWd1cmUgdGhlIGdpdmVuIGBwcm9wc2AgYnkgY2FsbGluZyBgX3NldFBlbmRpbmdQcm9wZXJ0eWAuIEFsc28KICAgICAgICogc2V0cyBhbnkgcHJvcGVydGllcyBzdG9yZWQgaW4gYF9faG9zdFByb3BzYC4KICAgICAgICogQHByaXZhdGUKICAgICAgICogQHBhcmFtIHtPYmplY3R9IHByb3BzIE9iamVjdCBvZiBwcm9wZXJ0eSBuYW1lLXZhbHVlIHBhaXJzIHRvIHNldC4KICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9jb25maWd1cmVQcm9wZXJ0aWVzKHByb3BzKSB7CiAgICAgICAgbGV0IG9wdGlvbnMgPSB0aGlzLl9fdGVtcGxhdGl6ZU9wdGlvbnM7CiAgICAgICAgaWYgKG9wdGlvbnMuZm9yd2FyZEhvc3RQcm9wKSB7CiAgICAgICAgICBmb3IgKGxldCBocHJvcCBpbiB0aGlzLl9faG9zdFByb3BzKSB7CiAgICAgICAgICAgIHRoaXMuX3NldFBlbmRpbmdQcm9wZXJ0eShocHJvcCwgdGhpcy5fX2RhdGFIb3N0WydfaG9zdF8nICsgaHByb3BdKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8gQW55IGluc3RhbmNlIHByb3BzIHBhc3NlZCBpbiB0aGUgY29uc3RydWN0b3Igd2lsbCBvdmVyd3JpdGUgaG9zdCBwcm9wczsKICAgICAgICAvLyBub3JtYWxseSB0aGlzIHdvdWxkIGJlIGEgdXNlciBlcnJvciBidXQgd2UgZG9uJ3Qgc3BlY2lmaWNhbGx5IGZpbHRlciB0aGVtCiAgICAgICAgZm9yIChsZXQgaXByb3AgaW4gcHJvcHMpIHsKICAgICAgICAgIHRoaXMuX3NldFBlbmRpbmdQcm9wZXJ0eShpcHJvcCwgcHJvcHNbaXByb3BdKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgLyoqCiAgICAgICAqIEZvcndhcmRzIGEgaG9zdCBwcm9wZXJ0eSB0byB0aGlzIGluc3RhbmNlLiAgVGhpcyBtZXRob2Qgc2hvdWxkIGJlCiAgICAgICAqIGNhbGxlZCBvbiBpbnN0YW5jZXMgZnJvbSB0aGUgYG9wdGlvbnMuZm9yd2FyZEhvc3RQcm9wYCBjYWxsYmFjawogICAgICAgKiB0byBwcm9wYWdhdGUgY2hhbmdlcyBvZiBob3N0IHByb3BlcnRpZXMgdG8gZWFjaCBpbnN0YW5jZS4KICAgICAgICoKICAgICAgICogTm90ZSB0aGlzIG1ldGhvZCBlbnF1ZXVlcyB0aGUgY2hhbmdlLCB3aGljaCBhcmUgZmx1c2hlZCBhcyBhIGJhdGNoLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcCBQcm9wZXJ0eSBvciBwYXRoIG5hbWUKICAgICAgICogQHBhcmFtIHsqfSB2YWx1ZSBWYWx1ZSBvZiB0aGUgcHJvcGVydHkgdG8gZm9yd2FyZAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgZm9yd2FyZEhvc3RQcm9wKHByb3AsIHZhbHVlKSB7CiAgICAgICAgaWYgKHRoaXMuX3NldFBlbmRpbmdQcm9wZXJ0eU9yUGF0aChwcm9wLCB2YWx1ZSwgZmFsc2UsIHRydWUpKSB7CiAgICAgICAgICB0aGlzLl9fZGF0YUhvc3QuX2VucXVldWVDbGllbnQodGhpcyk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogT3ZlcnJpZGUgcG9pbnQgZm9yIGFkZGluZyBjdXN0b20gb3Igc2ltdWxhdGVkIGV2ZW50IGhhbmRsaW5nLgogICAgICAgKgogICAgICAgKiBAcGFyYW0geyFOb2RlfSBub2RlIE5vZGUgdG8gYWRkIGV2ZW50IGxpc3RlbmVyIHRvCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWUgTmFtZSBvZiBldmVudAogICAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKCFFdmVudCk6dm9pZH0gaGFuZGxlciBMaXN0ZW5lciBmdW5jdGlvbiB0byBhZGQKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIF9hZGRFdmVudExpc3RlbmVyVG9Ob2RlKG5vZGUsIGV2ZW50TmFtZSwgaGFuZGxlcikgewogICAgICAgIGlmICh0aGlzLl9tZXRob2RIb3N0ICYmIHRoaXMuX190ZW1wbGF0aXplT3B0aW9ucy5wYXJlbnRNb2RlbCkgewogICAgICAgICAgLy8gSWYgdGhpcyBpbnN0YW5jZSBzaG91bGQgYmUgY29uc2lkZXJlZCBhIHBhcmVudCBtb2RlbCwgZGVjb3JhdGUKICAgICAgICAgIC8vIGV2ZW50cyB0aGlzIHRlbXBsYXRlIGluc3RhbmNlIGFzIGBtb2RlbGAKICAgICAgICAgIHRoaXMuX21ldGhvZEhvc3QuX2FkZEV2ZW50TGlzdGVuZXJUb05vZGUobm9kZSwgZXZlbnROYW1lLCAoZSkgPT4gewogICAgICAgICAgICBlLm1vZGVsID0gdGhpczsKICAgICAgICAgICAgaGFuZGxlcihlKTsKICAgICAgICAgIH0pOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAvLyBPdGhlcndpc2UgZGVsZWdhdGUgdG8gdGhlIHRlbXBsYXRlJ3MgaG9zdCAod2hpY2ggY291bGQgYmUpCiAgICAgICAgICAvLyBhbm90aGVyIHRlbXBsYXRlIGluc3RhbmNlCiAgICAgICAgICBsZXQgdGVtcGxhdGVIb3N0ID0gdGhpcy5fX2RhdGFIb3N0Ll9fZGF0YUhvc3Q7CiAgICAgICAgICBpZiAodGVtcGxhdGVIb3N0KSB7CiAgICAgICAgICAgIHRlbXBsYXRlSG9zdC5fYWRkRXZlbnRMaXN0ZW5lclRvTm9kZShub2RlLCBldmVudE5hbWUsIGhhbmRsZXIpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICAvKioKICAgICAgICogU2hvd3Mgb3IgaGlkZXMgdGhlIHRlbXBsYXRlIGluc3RhbmNlIHRvcCBsZXZlbCBjaGlsZCBlbGVtZW50cy4gRm9yCiAgICAgICAqIHRleHQgbm9kZXMsIGB0ZXh0Q29udGVudGAgaXMgcmVtb3ZlZCB3aGlsZSAiaGlkZGVuIiBhbmQgcmVwbGFjZWQgd2hlbgogICAgICAgKiAic2hvd24uIgogICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGhpZGUgU2V0IHRvIHRydWUgdG8gaGlkZSB0aGUgY2hpbGRyZW47CiAgICAgICAqIHNldCB0byBmYWxzZSB0byBzaG93IHRoZW0uCiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9zaG93SGlkZUNoaWxkcmVuKGhpZGUpIHsKICAgICAgICBsZXQgYyA9IHRoaXMuY2hpbGRyZW47CiAgICAgICAgZm9yIChsZXQgaT0wOyBpPGMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgIGxldCBuID0gY1tpXTsKICAgICAgICAgIC8vIElnbm9yZSBub24tY2hhbmdlcwogICAgICAgICAgaWYgKEJvb2xlYW4oaGlkZSkgIT0gQm9vbGVhbihuLl9faGlkZVRlbXBsYXRlQ2hpbGRyZW5fXykpIHsKICAgICAgICAgICAgaWYgKG4ubm9kZVR5cGUgPT09IE5vZGUuVEVYVF9OT0RFKSB7CiAgICAgICAgICAgICAgaWYgKGhpZGUpIHsKICAgICAgICAgICAgICAgIG4uX19wb2x5bWVyVGV4dENvbnRlbnRfXyA9IG4udGV4dENvbnRlbnQ7CiAgICAgICAgICAgICAgICBuLnRleHRDb250ZW50ID0gJyc7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG4udGV4dENvbnRlbnQgPSBuLl9fcG9seW1lclRleHRDb250ZW50X187CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAvLyByZW1vdmUgYW5kIHJlcGxhY2Ugc2xvdAogICAgICAgICAgICB9IGVsc2UgaWYgKG4ubG9jYWxOYW1lID09PSAnc2xvdCcpIHsKICAgICAgICAgICAgICBpZiAoaGlkZSkgewogICAgICAgICAgICAgICAgbi5fX3BvbHltZXJSZXBsYWNlZF9fID0gZG9jdW1lbnQuY3JlYXRlQ29tbWVudCgnaGlkZGVuLXNsb3QnKTsKICAgICAgICAgICAgICAgIG4ucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobi5fX3BvbHltZXJSZXBsYWNlZF9fLCBuKTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgY29uc3QgcmVwbGFjZSA9IG4uX19wb2x5bWVyUmVwbGFjZWRfXzsKICAgICAgICAgICAgICAgIGlmIChyZXBsYWNlKSB7CiAgICAgICAgICAgICAgICAgIHJlcGxhY2UucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobiwgcmVwbGFjZSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBlbHNlIGlmIChuLnN0eWxlKSB7CiAgICAgICAgICAgICAgaWYgKGhpZGUpIHsKICAgICAgICAgICAgICAgIG4uX19wb2x5bWVyRGlzcGxheV9fID0gbi5zdHlsZS5kaXNwbGF5OwogICAgICAgICAgICAgICAgbi5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBuLnN0eWxlLmRpc3BsYXkgPSBuLl9fcG9seW1lckRpc3BsYXlfXzsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIG4uX19oaWRlVGVtcGxhdGVDaGlsZHJlbl9fID0gaGlkZTsKICAgICAgICAgIGlmIChuLl9zaG93SGlkZUNoaWxkcmVuKSB7CiAgICAgICAgICAgIG4uX3Nob3dIaWRlQ2hpbGRyZW4oaGlkZSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICAgIC8qKgogICAgICAgKiBPdmVycmlkZXMgZGVmYXVsdCBwcm9wZXJ0eS1lZmZlY3RzIGltcGxlbWVudGF0aW9uIHRvIGludGVyY2VwdAogICAgICAgKiB0ZXh0Q29udGVudCBiaW5kaW5ncyB3aGlsZSBjaGlsZHJlbiBhcmUgImhpZGRlbiIgYW5kIGNhY2hlIGluCiAgICAgICAqIHByaXZhdGUgc3RvcmFnZSBmb3IgbGF0ZXIgcmV0cmlldmFsLgogICAgICAgKgogICAgICAgKiBAcGFyYW0geyFOb2RlfSBub2RlIFRoZSBub2RlIHRvIHNldCBhIHByb3BlcnR5IG9uCiAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wIFRoZSBwcm9wZXJ0eSB0byBzZXQKICAgICAgICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gc2V0CiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqIEBwcm90ZWN0ZWQKICAgICAgICovCiAgICAgIF9zZXRVbm1hbmFnZWRQcm9wZXJ0eVRvTm9kZShub2RlLCBwcm9wLCB2YWx1ZSkgewogICAgICAgIGlmIChub2RlLl9faGlkZVRlbXBsYXRlQ2hpbGRyZW5fXyAmJgogICAgICAgICAgICBub2RlLm5vZGVUeXBlID09IE5vZGUuVEVYVF9OT0RFICYmIHByb3AgPT0gJ3RleHRDb250ZW50JykgewogICAgICAgICAgbm9kZS5fX3BvbHltZXJUZXh0Q29udGVudF9fID0gdmFsdWU7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHN1cGVyLl9zZXRVbm1hbmFnZWRQcm9wZXJ0eVRvTm9kZShub2RlLCBwcm9wLCB2YWx1ZSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIC8qKgogICAgICAgKiBGaW5kIHRoZSBwYXJlbnQgbW9kZWwgb2YgdGhpcyB0ZW1wbGF0ZSBpbnN0YW5jZS4gIFRoZSBwYXJlbnQgbW9kZWwKICAgICAgICogaXMgZWl0aGVyIGFub3RoZXIgdGVtcGxhdGl6ZSBpbnN0YW5jZSB0aGF0IGhhZCBvcHRpb24gYHBhcmVudE1vZGVsOiB0cnVlYCwKICAgICAgICogb3IgZWxzZSB0aGUgaG9zdCBlbGVtZW50LgogICAgICAgKgogICAgICAgKiBAcmV0dXJuIHshUG9seW1lcl9Qcm9wZXJ0eUVmZmVjdHN9IFRoZSBwYXJlbnQgbW9kZWwgb2YgdGhpcyBpbnN0YW5jZQogICAgICAgKi8KICAgICAgZ2V0IHBhcmVudE1vZGVsKCkgewogICAgICAgIGxldCBtb2RlbCA9IHRoaXMuX19wYXJlbnRNb2RlbDsKICAgICAgICBpZiAoIW1vZGVsKSB7CiAgICAgICAgICBsZXQgb3B0aW9uczsKICAgICAgICAgIG1vZGVsID0gdGhpczsKICAgICAgICAgIGRvIHsKICAgICAgICAgICAgLy8gQSB0ZW1wbGF0ZSBpbnN0YW5jZSdzIGBfX2RhdGFIb3N0YCBpcyBhIDx0ZW1wbGF0ZT4KICAgICAgICAgICAgLy8gYG1vZGVsLl9fZGF0YUhvc3QuX19kYXRhSG9zdGAgaXMgdGhlIHRlbXBsYXRlJ3MgaG9zdAogICAgICAgICAgICBtb2RlbCA9IG1vZGVsLl9fZGF0YUhvc3QuX19kYXRhSG9zdDsKICAgICAgICAgIH0gd2hpbGUgKChvcHRpb25zID0gbW9kZWwuX190ZW1wbGF0aXplT3B0aW9ucykgJiYgIW9wdGlvbnMucGFyZW50TW9kZWwpOwogICAgICAgICAgdGhpcy5fX3BhcmVudE1vZGVsID0gbW9kZWw7CiAgICAgICAgfQogICAgICAgIHJldHVybiBtb2RlbDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFN0dWIgb2YgSFRNTEVsZW1lbnQncyBgZGlzcGF0Y2hFdmVudGAsIHNvIHRoYXQgZWZmZWN0cyB0aGF0IG1heQogICAgICAgKiBkaXNwYXRjaCBldmVudHMgc2FmZWx5IG5vLW9wLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge0V2ZW50fSBldmVudCBFdmVudCB0byBkaXNwYXRjaAogICAgICAgKiBAcmV0dXJuIHtib29sZWFufSBBbHdheXMgdHJ1ZS4KICAgICAgICovCiAgICAgICBkaXNwYXRjaEV2ZW50KGV2ZW50KSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnMKICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgIH0KICAgIH0KCiAgICAvKiogQHR5cGUgeyFEYXRhVGVtcGxhdGV9ICovCiAgICBUZW1wbGF0ZUluc3RhbmNlQmFzZS5wcm90b3R5cGUuX19kYXRhSG9zdDsKICAgIC8qKiBAdHlwZSB7IVRlbXBsYXRpemVPcHRpb25zfSAqLwogICAgVGVtcGxhdGVJbnN0YW5jZUJhc2UucHJvdG90eXBlLl9fdGVtcGxhdGl6ZU9wdGlvbnM7CiAgICAvKiogQHR5cGUgeyFQb2x5bWVyX1Byb3BlcnR5RWZmZWN0c30gKi8KICAgIFRlbXBsYXRlSW5zdGFuY2VCYXNlLnByb3RvdHlwZS5fbWV0aG9kSG9zdDsKICAgIC8qKiBAdHlwZSB7IU9iamVjdH0gKi8KICAgIFRlbXBsYXRlSW5zdGFuY2VCYXNlLnByb3RvdHlwZS5fX3RlbXBsYXRpemVPd25lcjsKICAgIC8qKiBAdHlwZSB7IU9iamVjdH0gKi8KICAgIFRlbXBsYXRlSW5zdGFuY2VCYXNlLnByb3RvdHlwZS5fX2hvc3RQcm9wczsKCiAgICAvKioKICAgICAqIEBjb25zdHJ1Y3RvcgogICAgICogQGV4dGVuZHMge1RlbXBsYXRlSW5zdGFuY2VCYXNlfQogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfTXV0YWJsZURhdGF9CiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBjb25zdCBNdXRhYmxlVGVtcGxhdGVJbnN0YW5jZUJhc2UgPSBQb2x5bWVyLk11dGFibGVEYXRhKFRlbXBsYXRlSW5zdGFuY2VCYXNlKTsKCiAgICBmdW5jdGlvbiBmaW5kTWV0aG9kSG9zdCh0ZW1wbGF0ZSkgewogICAgICAvLyBUZWNobmljYWxseSB0aGlzIHNob3VsZCBiZSB0aGUgb3duZXIgb2YgdGhlIG91dGVybW9zdCB0ZW1wbGF0ZS4KICAgICAgLy8gSW4gc2hhZG93IGRvbSwgdGhpcyBpcyBhbHdheXMgZ2V0Um9vdE5vZGUoKS5ob3N0LCBidXQgd2UgY2FuCiAgICAgIC8vIGFwcHJveGltYXRlIHRoaXMgdmlhIGNvb3BlcmF0aW9uIHdpdGggb3VyIGRhdGFIb3N0IGFsd2F5cyBzZXR0aW5nCiAgICAgIC8vIGBfbWV0aG9kSG9zdGAgYXMgbG9uZyBhcyB0aGVyZSB3ZXJlIGJpbmRpbmdzIChvciBpZCdzKSBvbiB0aGlzCiAgICAgIC8vIGluc3RhbmNlIGNhdXNpbmcgaXQgdG8gZ2V0IGEgZGF0YUhvc3QuCiAgICAgIGxldCB0ZW1wbGF0ZUhvc3QgPSB0ZW1wbGF0ZS5fX2RhdGFIb3N0OwogICAgICByZXR1cm4gdGVtcGxhdGVIb3N0ICYmIHRlbXBsYXRlSG9zdC5fbWV0aG9kSG9zdCB8fCB0ZW1wbGF0ZUhvc3Q7CiAgICB9CgogICAgLyogZXNsaW50LWRpc2FibGUgdmFsaWQtanNkb2MgKi8KICAgIC8qKgogICAgICogQHN1cHByZXNzIHttaXNzaW5nUHJvcGVydGllc30gY2xhc3MucHJvdG90eXBlIGlzIG5vdCBkZWZpbmVkIGZvciBzb21lIHJlYXNvbgogICAgICovCiAgICBmdW5jdGlvbiBjcmVhdGVUZW1wbGF0aXplckNsYXNzKHRlbXBsYXRlLCB0ZW1wbGF0ZUluZm8sIG9wdGlvbnMpIHsKICAgICAgLy8gQW5vbnltb3VzIGNsYXNzIGNyZWF0ZWQgYnkgdGhlIHRlbXBsYXRpemUKICAgICAgbGV0IGJhc2UgPSBvcHRpb25zLm11dGFibGVEYXRhID8KICAgICAgICBNdXRhYmxlVGVtcGxhdGVJbnN0YW5jZUJhc2UgOiBUZW1wbGF0ZUluc3RhbmNlQmFzZTsKICAgICAgLy8gQWZmb3JkYW5jZSBmb3IgZ2xvYmFsIG1peGlucyBvbnRvIFRlbXBsYXRpemVJbnN0YW5jZQogICAgICBpZiAoUG9seW1lci5UZW1wbGF0aXplLm1peGluKSB7CiAgICAgICAgYmFzZSA9IFBvbHltZXIuVGVtcGxhdGl6ZS5taXhpbihiYXNlKTsKICAgICAgfQogICAgICAvKioKICAgICAgICogQGNvbnN0cnVjdG9yCiAgICAgICAqIEBleHRlbmRzIHtiYXNlfQogICAgICAgKiBAcHJpdmF0ZQogICAgICAgKi8KICAgICAgbGV0IGtsYXNzID0gY2xhc3MgZXh0ZW5kcyBiYXNlIHsgfTsKICAgICAga2xhc3MucHJvdG90eXBlLl9fdGVtcGxhdGl6ZU9wdGlvbnMgPSBvcHRpb25zOwogICAgICBrbGFzcy5wcm90b3R5cGUuX2JpbmRUZW1wbGF0ZSh0ZW1wbGF0ZSk7CiAgICAgIGFkZE5vdGlmeUVmZmVjdHMoa2xhc3MsIHRlbXBsYXRlLCB0ZW1wbGF0ZUluZm8sIG9wdGlvbnMpOwogICAgICByZXR1cm4ga2xhc3M7CiAgICB9CgogICAgLyoqCiAgICAgKiBAc3VwcHJlc3Mge21pc3NpbmdQcm9wZXJ0aWVzfSBjbGFzcy5wcm90b3R5cGUgaXMgbm90IGRlZmluZWQgZm9yIHNvbWUgcmVhc29uCiAgICAgKi8KICAgIGZ1bmN0aW9uIGFkZFByb3BhZ2F0ZUVmZmVjdHModGVtcGxhdGUsIHRlbXBsYXRlSW5mbywgb3B0aW9ucykgewogICAgICBsZXQgdXNlckZvcndhcmRIb3N0UHJvcCA9IG9wdGlvbnMuZm9yd2FyZEhvc3RQcm9wOwogICAgICBpZiAodXNlckZvcndhcmRIb3N0UHJvcCkgewogICAgICAgIC8vIFByb3ZpZGUgZGF0YSBBUEkgYW5kIHByb3BlcnR5IGVmZmVjdHMgb24gbWVtb2l6ZWQgdGVtcGxhdGUgY2xhc3MKICAgICAgICBsZXQga2xhc3MgPSB0ZW1wbGF0ZUluZm8udGVtcGxhdGl6ZVRlbXBsYXRlQ2xhc3M7CiAgICAgICAgaWYgKCFrbGFzcykgewogICAgICAgICAgbGV0IGJhc2UgPSBvcHRpb25zLm11dGFibGVEYXRhID8gTXV0YWJsZURhdGFUZW1wbGF0ZSA6IERhdGFUZW1wbGF0ZTsKICAgICAgICAgIC8qKiBAcHJpdmF0ZSAqLwogICAgICAgICAga2xhc3MgPSB0ZW1wbGF0ZUluZm8udGVtcGxhdGl6ZVRlbXBsYXRlQ2xhc3MgPQogICAgICAgICAgICBjbGFzcyBUZW1wbGF0aXplZFRlbXBsYXRlIGV4dGVuZHMgYmFzZSB7fTsKICAgICAgICAgIC8vIEFkZCB0ZW1wbGF0ZSAtID5pbnN0YW5jZXMgZWZmZWN0cwogICAgICAgICAgLy8gYW5kIGhvc3QgPC0gdGVtcGxhdGUgZWZmZWN0cwogICAgICAgICAgbGV0IGhvc3RQcm9wcyA9IHRlbXBsYXRlSW5mby5ob3N0UHJvcHM7CiAgICAgICAgICBmb3IgKGxldCBwcm9wIGluIGhvc3RQcm9wcykgewogICAgICAgICAgICBrbGFzcy5wcm90b3R5cGUuX2FkZFByb3BlcnR5RWZmZWN0KCdfaG9zdF8nICsgcHJvcCwKICAgICAgICAgICAgICBrbGFzcy5wcm90b3R5cGUuUFJPUEVSVFlfRUZGRUNUX1RZUEVTLlBST1BBR0FURSwKICAgICAgICAgICAgICB7Zm46IGNyZWF0ZUZvcndhcmRIb3N0UHJvcEVmZmVjdChwcm9wLCB1c2VyRm9yd2FyZEhvc3RQcm9wKX0pOwogICAgICAgICAgICBrbGFzcy5wcm90b3R5cGUuX2NyZWF0ZU5vdGlmeWluZ1Byb3BlcnR5KCdfaG9zdF8nICsgcHJvcCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHVwZ3JhZGVUZW1wbGF0ZSh0ZW1wbGF0ZSwga2xhc3MpOwogICAgICAgIC8vIE1peCBhbnkgcHJlLWJvdW5kIGRhdGEgaW50byBfX2RhdGE7IG5vIG5lZWQgdG8gZmx1c2ggdGhpcyB0bwogICAgICAgIC8vIGluc3RhbmNlcyBzaW5jZSB0aGV5IHB1bGwgZnJvbSB0aGUgdGVtcGxhdGUgYXQgaW5zdGFuY2UtdGltZQogICAgICAgIGlmICh0ZW1wbGF0ZS5fX2RhdGFQcm90bykgewogICAgICAgICAgLy8gTm90ZSwgZ2VuZXJhbGx5IGBfX2RhdGFQcm90b2AgY291bGQgYmUgY2hhaW5lZCwgYnV0IGl0J3MgZ3VhcmFudGVlZAogICAgICAgICAgLy8gdG8gbm90IGJlIHNpbmNlIHRoaXMgaXMgYSB2YW5pbGxhIHRlbXBsYXRlIHdlIGp1c3QgYWRkZWQgZWZmZWN0cyB0bwogICAgICAgICAgT2JqZWN0LmFzc2lnbih0ZW1wbGF0ZS5fX2RhdGEsIHRlbXBsYXRlLl9fZGF0YVByb3RvKTsKICAgICAgICB9CiAgICAgICAgLy8gQ2xlYXIgYW55IHBlbmRpbmcgZGF0YSBmb3IgcGVyZm9ybWFuY2UKICAgICAgICB0ZW1wbGF0ZS5fX2RhdGFUZW1wID0ge307CiAgICAgICAgdGVtcGxhdGUuX19kYXRhUGVuZGluZyA9IG51bGw7CiAgICAgICAgdGVtcGxhdGUuX19kYXRhT2xkID0gbnVsbDsKICAgICAgICB0ZW1wbGF0ZS5fZW5hYmxlUHJvcGVydGllcygpOwogICAgICB9CiAgICB9CiAgICAvKiBlc2xpbnQtZW5hYmxlIHZhbGlkLWpzZG9jICovCgogICAgZnVuY3Rpb24gY3JlYXRlRm9yd2FyZEhvc3RQcm9wRWZmZWN0KGhvc3RQcm9wLCB1c2VyRm9yd2FyZEhvc3RQcm9wKSB7CiAgICAgIHJldHVybiBmdW5jdGlvbiBmb3J3YXJkSG9zdFByb3AodGVtcGxhdGUsIHByb3AsIHByb3BzKSB7CiAgICAgICAgdXNlckZvcndhcmRIb3N0UHJvcC5jYWxsKHRlbXBsYXRlLl9fdGVtcGxhdGl6ZU93bmVyLAogICAgICAgICAgcHJvcC5zdWJzdHJpbmcoJ19ob3N0XycubGVuZ3RoKSwgcHJvcHNbcHJvcF0pOwogICAgICB9OwogICAgfQoKICAgIGZ1bmN0aW9uIGFkZE5vdGlmeUVmZmVjdHMoa2xhc3MsIHRlbXBsYXRlLCB0ZW1wbGF0ZUluZm8sIG9wdGlvbnMpIHsKICAgICAgbGV0IGhvc3RQcm9wcyA9IHRlbXBsYXRlSW5mby5ob3N0UHJvcHMgfHwge307CiAgICAgIGZvciAobGV0IGlwcm9wIGluIG9wdGlvbnMuaW5zdGFuY2VQcm9wcykgewogICAgICAgIGRlbGV0ZSBob3N0UHJvcHNbaXByb3BdOwogICAgICAgIGxldCB1c2VyTm90aWZ5SW5zdGFuY2VQcm9wID0gb3B0aW9ucy5ub3RpZnlJbnN0YW5jZVByb3A7CiAgICAgICAgaWYgKHVzZXJOb3RpZnlJbnN0YW5jZVByb3ApIHsKICAgICAgICAgIGtsYXNzLnByb3RvdHlwZS5fYWRkUHJvcGVydHlFZmZlY3QoaXByb3AsCiAgICAgICAgICAgIGtsYXNzLnByb3RvdHlwZS5QUk9QRVJUWV9FRkZFQ1RfVFlQRVMuTk9USUZZLAogICAgICAgICAgICB7Zm46IGNyZWF0ZU5vdGlmeUluc3RhbmNlUHJvcEVmZmVjdChpcHJvcCwgdXNlck5vdGlmeUluc3RhbmNlUHJvcCl9KTsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKG9wdGlvbnMuZm9yd2FyZEhvc3RQcm9wICYmIHRlbXBsYXRlLl9fZGF0YUhvc3QpIHsKICAgICAgICBmb3IgKGxldCBocHJvcCBpbiBob3N0UHJvcHMpIHsKICAgICAgICAgIGtsYXNzLnByb3RvdHlwZS5fYWRkUHJvcGVydHlFZmZlY3QoaHByb3AsCiAgICAgICAgICAgIGtsYXNzLnByb3RvdHlwZS5QUk9QRVJUWV9FRkZFQ1RfVFlQRVMuTk9USUZZLAogICAgICAgICAgICB7Zm46IGNyZWF0ZU5vdGlmeUhvc3RQcm9wRWZmZWN0KCl9KTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBjcmVhdGVOb3RpZnlJbnN0YW5jZVByb3BFZmZlY3QoaW5zdFByb3AsIHVzZXJOb3RpZnlJbnN0YW5jZVByb3ApIHsKICAgICAgcmV0dXJuIGZ1bmN0aW9uIG5vdGlmeUluc3RhbmNlUHJvcChpbnN0LCBwcm9wLCBwcm9wcykgewogICAgICAgIHVzZXJOb3RpZnlJbnN0YW5jZVByb3AuY2FsbChpbnN0Ll9fdGVtcGxhdGl6ZU93bmVyLAogICAgICAgICAgaW5zdCwgcHJvcCwgcHJvcHNbcHJvcF0pOwogICAgICB9OwogICAgfQoKICAgIGZ1bmN0aW9uIGNyZWF0ZU5vdGlmeUhvc3RQcm9wRWZmZWN0KCkgewogICAgICByZXR1cm4gZnVuY3Rpb24gbm90aWZ5SG9zdFByb3AoaW5zdCwgcHJvcCwgcHJvcHMpIHsKICAgICAgICBpbnN0Ll9fZGF0YUhvc3QuX3NldFBlbmRpbmdQcm9wZXJ0eU9yUGF0aCgnX2hvc3RfJyArIHByb3AsIHByb3BzW3Byb3BdLCB0cnVlLCB0cnVlKTsKICAgICAgfTsKICAgIH0KCiAgICAvKioKICAgICAqIE1vZHVsZSBmb3IgcHJlcGFyaW5nIGFuZCBzdGFtcGluZyBpbnN0YW5jZXMgb2YgdGVtcGxhdGVzIHRoYXQgdXRpbGl6ZQogICAgICogUG9seW1lcidzIGRhdGEtYmluZGluZyBhbmQgZGVjbGFyYXRpdmUgZXZlbnQgbGlzdGVuZXIgZmVhdHVyZXMuCiAgICAgKgogICAgICogRXhhbXBsZToKICAgICAqCiAgICAgKiAgICAgLy8gR2V0IGEgdGVtcGxhdGUgZnJvbSBzb21ld2hlcmUsIGUuZy4gbGlnaHQgRE9NCiAgICAgKiAgICAgbGV0IHRlbXBsYXRlID0gdGhpcy5xdWVyeVNlbGVjdG9yKCd0ZW1wbGF0ZScpOwogICAgICogICAgIC8vIFByZXBhcmUgdGhlIHRlbXBsYXRlCiAgICAgKiAgICAgbGV0IFRlbXBsYXRlQ2xhc3MgPSBQb2x5bWVyLlRlbXBsYXRpemUudGVtcGxhdGl6ZSh0ZW1wbGF0ZSk7CiAgICAgKiAgICAgLy8gSW5zdGFuY2UgdGhlIHRlbXBsYXRlIHdpdGggYW4gaW5pdGlhbCBkYXRhIG1vZGVsCiAgICAgKiAgICAgbGV0IGluc3RhbmNlID0gbmV3IFRlbXBsYXRlQ2xhc3Moe215UHJvcDogJ2luaXRpYWwnfSk7CiAgICAgKiAgICAgLy8gSW5zZXJ0IHRoZSBpbnN0YW5jZSdzIERPTSBzb21ld2hlcmUsIGUuZy4gZWxlbWVudCdzIHNoYWRvdyBET00KICAgICAqICAgICB0aGlzLnNoYWRvd1Jvb3QuYXBwZW5kQ2hpbGQoaW5zdGFuY2Uucm9vdCk7CiAgICAgKiAgICAgLy8gQ2hhbmdpbmcgYSBwcm9wZXJ0eSBvbiB0aGUgaW5zdGFuY2Ugd2lsbCBwcm9wYWdhdGUgdG8gYmluZGluZ3MKICAgICAqICAgICAvLyBpbiB0aGUgdGVtcGxhdGUKICAgICAqICAgICBpbnN0YW5jZS5teVByb3AgPSAnbmV3IHZhbHVlJzsKICAgICAqCiAgICAgKiBUaGUgYG9wdGlvbnNgIGRpY3Rpb25hcnkgcGFzc2VkIHRvIGB0ZW1wbGF0aXplYCBhbGxvd3MgZm9yIGN1c3RvbWl6aW5nCiAgICAgKiBmZWF0dXJlcyBvZiB0aGUgZ2VuZXJhdGVkIHRlbXBsYXRlIGNsYXNzLCBpbmNsdWRpbmcgaG93IG91dGVyLXNjb3BlIGhvc3QKICAgICAqIHByb3BlcnRpZXMgc2hvdWxkIGJlIGZvcndhcmRlZCBpbnRvIHRlbXBsYXRlIGluc3RhbmNlcywgaG93IGFueSBpbnN0YW5jZQogICAgICogcHJvcGVydGllcyBhZGRlZCBpbnRvIHRoZSB0ZW1wbGF0ZSdzIHNjb3BlIHNob3VsZCBiZSBub3RpZmllZCBvdXQgdG8KICAgICAqIHRoZSBob3N0LCBhbmQgd2hldGhlciB0aGUgaW5zdGFuY2Ugc2hvdWxkIGJlIGRlY29yYXRlZCBhcyBhICJwYXJlbnQgbW9kZWwiCiAgICAgKiBvZiBhbnkgZXZlbnQgaGFuZGxlcnMuCiAgICAgKgogICAgICogICAgIC8vIEN1c3RvbWl6ZSBwcm9wZXJ0eSBmb3J3YXJkaW5nIGFuZCBldmVudCBtb2RlbCBkZWNvcmF0aW9uCiAgICAgKiAgICAgbGV0IFRlbXBsYXRlQ2xhc3MgPSBQb2x5bWVyLlRlbXBsYXRpemUudGVtcGxhdGl6ZSh0ZW1wbGF0ZSwgdGhpcywgewogICAgICogICAgICAgcGFyZW50TW9kZWw6IHRydWUsCiAgICAgKiAgICAgICBmb3J3YXJkSG9zdFByb3AocHJvcGVydHksIHZhbHVlKSB7Li4ufSwKICAgICAqICAgICAgIGluc3RhbmNlUHJvcHM6IHsuLi59LAogICAgICogICAgICAgbm90aWZ5SW5zdGFuY2VQcm9wKGluc3RhbmNlLCBwcm9wZXJ0eSwgdmFsdWUpIHsuLi59LAogICAgICogICAgIH0pOwogICAgICoKICAgICAqIEBuYW1lc3BhY2UKICAgICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICAgKiBAc3VtbWFyeSBNb2R1bGUgZm9yIHByZXBhcmluZyBhbmQgc3RhbXBpbmcgaW5zdGFuY2VzIG9mIHRlbXBsYXRlcwogICAgICogICB1dGlsaXppbmcgUG9seW1lciB0ZW1wbGF0aW5nIGZlYXR1cmVzLgogICAgICovCiAgICBQb2x5bWVyLlRlbXBsYXRpemUgPSB7CgogICAgICAvKioKICAgICAgICogUmV0dXJucyBhbiBhbm9ueW1vdXMgYFBvbHltZXIuUHJvcGVydHlFZmZlY3RzYCBjbGFzcyBib3VuZCB0byB0aGUKICAgICAgICogYDx0ZW1wbGF0ZT5gIHByb3ZpZGVkLiAgSW5zdGFuY2luZyB0aGUgY2xhc3Mgd2lsbCByZXN1bHQgaW4gdGhlCiAgICAgICAqIHRlbXBsYXRlIGJlaW5nIHN0YW1wZWQgaW50byBhIGRvY3VtZW50IGZyYWdtZW50IHN0b3JlZCBhcyB0aGUgaW5zdGFuY2UncwogICAgICAgKiBgcm9vdGAgcHJvcGVydHksIGFmdGVyIHdoaWNoIGl0IGNhbiBiZSBhcHBlbmRlZCB0byB0aGUgRE9NLgogICAgICAgKgogICAgICAgKiBUZW1wbGF0ZXMgbWF5IHV0aWxpemUgYWxsIFBvbHltZXIgZGF0YS1iaW5kaW5nIGZlYXR1cmVzIGFzIHdlbGwgYXMKICAgICAgICogZGVjbGFyYXRpdmUgZXZlbnQgbGlzdGVuZXJzLiAgRXZlbnQgbGlzdGVuZXJzIGFuZCBpbmxpbmUgY29tcHV0aW5nCiAgICAgICAqIGZ1bmN0aW9ucyBpbiB0aGUgdGVtcGxhdGUgd2lsbCBiZSBjYWxsZWQgb24gdGhlIGhvc3Qgb2YgdGhlIHRlbXBsYXRlLgogICAgICAgKgogICAgICAgKiBUaGUgY29uc3RydWN0b3IgcmV0dXJuZWQgdGFrZXMgYSBzaW5nbGUgYXJndW1lbnQgZGljdGlvbmFyeSBvZiBpbml0aWFsCiAgICAgICAqIHByb3BlcnR5IHZhbHVlcyB0byBwcm9wYWdhdGUgaW50byB0ZW1wbGF0ZSBiaW5kaW5ncy4gIEFkZGl0aW9uYWxseQogICAgICAgKiBob3N0IHByb3BlcnRpZXMgY2FuIGJlIGZvcndhcmRlZCBpbiwgYW5kIGluc3RhbmNlIHByb3BlcnRpZXMgY2FuIGJlCiAgICAgICAqIG5vdGlmaWVkIG91dCBieSBwcm92aWRpbmcgb3B0aW9uYWwgY2FsbGJhY2tzIGluIHRoZSBgb3B0aW9uc2AgZGljdGlvbmFyeS4KICAgICAgICoKICAgICAgICogVmFsaWQgY29uZmlndXJhdGlvbiBpbiBgb3B0aW9uc2AgYXJlIGFzIGZvbGxvd3M6CiAgICAgICAqCiAgICAgICAqIC0gYGZvcndhcmRIb3N0UHJvcChwcm9wZXJ0eSwgdmFsdWUpYDogQ2FsbGVkIHdoZW4gYSBwcm9wZXJ0eSByZWZlcmVuY2VkCiAgICAgICAqICAgaW4gdGhlIHRlbXBsYXRlIGNoYW5nZWQgb24gdGhlIHRlbXBsYXRlJ3MgaG9zdC4gQXMgdGhpcyBsaWJyYXJ5IGRvZXMKICAgICAgICogICBub3QgcmV0YWluIHJlZmVyZW5jZXMgdG8gdGVtcGxhdGVzIGluc3RhbmNlZCBieSB0aGUgdXNlciwgaXQgaXMgdGhlCiAgICAgICAqICAgdGVtcGxhdGl6ZSBvd25lcidzIHJlc3BvbnNpYmlsaXR5IHRvIGZvcndhcmQgaG9zdCBwcm9wZXJ0eSBjaGFuZ2VzIGludG8KICAgICAgICogICB1c2VyLXN0YW1wZWQgaW5zdGFuY2VzLiAgVGhlIGBpbnN0YW5jZS5mb3J3YXJkSG9zdFByb3AocHJvcGVydHksIHZhbHVlKWAKICAgICAgICogICAgbWV0aG9kIG9uIHRoZSBnZW5lcmF0ZWQgY2xhc3Mgc2hvdWxkIGJlIGNhbGxlZCB0byBmb3J3YXJkIGhvc3QKICAgICAgICogICBwcm9wZXJ0aWVzIGludG8gdGhlIHRlbXBsYXRlIHRvIHByZXZlbnQgdW5uZWNlc3NhcnkgcHJvcGVydHktY2hhbmdlZAogICAgICAgKiAgIG5vdGlmaWNhdGlvbnMuIEFueSBwcm9wZXJ0aWVzIHJlZmVyZW5jZWQgaW4gdGhlIHRlbXBsYXRlIHRoYXQgYXJlIG5vdAogICAgICAgKiAgIGRlZmluZWQgaW4gYGluc3RhbmNlUHJvcHNgIHdpbGwgYmUgbm90aWZpZWQgdXAgdG8gdGhlIHRlbXBsYXRlJ3MgaG9zdAogICAgICAgKiAgIGF1dG9tYXRpY2FsbHkuCiAgICAgICAqIC0gYGluc3RhbmNlUHJvcHNgOiBEaWN0aW9uYXJ5IG9mIHByb3BlcnR5IG5hbWVzIHRoYXQgd2lsbCBiZSBhZGRlZAogICAgICAgKiAgIHRvIHRoZSBpbnN0YW5jZSBieSB0aGUgdGVtcGxhdGl6ZSBvd25lci4gIFRoZXNlIHByb3BlcnRpZXMgc2hhZG93IGFueQogICAgICAgKiAgIGhvc3QgcHJvcGVydGllcywgYW5kIGNoYW5nZXMgd2l0aGluIHRoZSB0ZW1wbGF0ZSB0byB0aGVzZSBwcm9wZXJ0aWVzCiAgICAgICAqICAgd2lsbCByZXN1bHQgaW4gYG5vdGlmeUluc3RhbmNlUHJvcGAgYmVpbmcgY2FsbGVkLgogICAgICAgKiAtIGBtdXRhYmxlRGF0YWA6IFdoZW4gYHRydWVgLCB0aGUgZ2VuZXJhdGVkIGNsYXNzIHdpbGwgc2tpcCBzdHJpY3QKICAgICAgICogICBkaXJ0eS1jaGVja2luZyBmb3Igb2JqZWN0cyBhbmQgYXJyYXlzIChhbHdheXMgY29uc2lkZXIgdGhlbSB0byBiZQogICAgICAgKiAgICJkaXJ0eSIpLgogICAgICAgKiAtIGBub3RpZnlJbnN0YW5jZVByb3AoaW5zdGFuY2UsIHByb3BlcnR5LCB2YWx1ZSlgOiBDYWxsZWQgd2hlbgogICAgICAgKiAgIGFuIGluc3RhbmNlIHByb3BlcnR5IGNoYW5nZXMuICBVc2VycyBtYXkgY2hvb3NlIHRvIGNhbGwgYG5vdGlmeVBhdGhgCiAgICAgICAqICAgb24gZS5nLiB0aGUgb3duZXIgdG8gbm90aWZ5IHRoZSBjaGFuZ2UuCiAgICAgICAqIC0gYHBhcmVudE1vZGVsYDogV2hlbiBgdHJ1ZWAsIGV2ZW50cyBoYW5kbGVkIGJ5IGRlY2xhcmF0aXZlIGV2ZW50IGxpc3RlbmVycwogICAgICAgKiAgIChgb24tZXZlbnQ9ImhhbmRsZXIiYCkgd2lsbCBiZSBkZWNvcmF0ZWQgd2l0aCBhIGBtb2RlbGAgcHJvcGVydHkgcG9pbnRpbmcKICAgICAgICogICB0byB0aGUgdGVtcGxhdGUgaW5zdGFuY2UgdGhhdCBzdGFtcGVkIGl0LiAgSXQgd2lsbCBhbHNvIGJlIHJldHVybmVkCiAgICAgICAqICAgZnJvbSBgaW5zdGFuY2UucGFyZW50TW9kZWxgIGluIGNhc2VzIHdoZXJlIHRlbXBsYXRlIGluc3RhbmNlIG5lc3RpbmcKICAgICAgICogICBjYXVzZXMgYW4gaW5uZXIgbW9kZWwgdG8gc2hhZG93IGFuIG91dGVyIG1vZGVsLgogICAgICAgKgogICAgICAgKiBBbGwgY2FsbGJhY2tzIGFyZSBjYWxsZWQgYm91bmQgdG8gdGhlIGBvd25lcmAuIEFueSBjb250ZXh0CiAgICAgICAqIG5lZWRlZCBmb3IgdGhlIGNhbGxiYWNrcyAoc3VjaCBhcyByZWZlcmVuY2VzIHRvIGBpbnN0YW5jZXNgIHN0YW1wZWQpCiAgICAgICAqIHNob3VsZCBiZSBzdG9yZWQgb24gdGhlIGBvd25lcmAgc3VjaCB0aGF0IHRoZXkgY2FuIGJlIHJldHJpZXZlZCB2aWEKICAgICAgICogYHRoaXNgLgogICAgICAgKgogICAgICAgKiBXaGVuIGBvcHRpb25zLmZvcndhcmRIb3N0UHJvcGAgaXMgZGVjbGFyZWQgYXMgYW4gb3B0aW9uLCBhbnkgcHJvcGVydGllcwogICAgICAgKiByZWZlcmVuY2VkIGluIHRoZSB0ZW1wbGF0ZSB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZm9yd2FyZGVkIGZyb20gdGhlIGhvc3Qgb2YKICAgICAgICogdGhlIGA8dGVtcGxhdGU+YCB0byBpbnN0YW5jZXMsIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiBhbnkgcHJvcGVydGllcyBsaXN0ZWQgaW4KICAgICAgICogdGhlIGBvcHRpb25zLmluc3RhbmNlUHJvcHNgIG9iamVjdC4gIGBpbnN0YW5jZVByb3BzYCBhcmUgYXNzdW1lZCB0byBiZQogICAgICAgKiBtYW5hZ2VkIGJ5IHRoZSBvd25lciBvZiB0aGUgaW5zdGFuY2VzLCBlaXRoZXIgcGFzc2VkIGludG8gdGhlIGNvbnN0cnVjdG9yCiAgICAgICAqIG9yIHNldCBhZnRlciB0aGUgZmFjdC4gIE5vdGUsIGFueSBwcm9wZXJ0aWVzIHBhc3NlZCBpbnRvIHRoZSBjb25zdHJ1Y3RvciB3aWxsCiAgICAgICAqIGFsd2F5cyBiZSBzZXQgdG8gdGhlIGluc3RhbmNlIChyZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhleSB3b3VsZCBub3JtYWxseQogICAgICAgKiBiZSBmb3J3YXJkZWQgZnJvbSB0aGUgaG9zdCkuCiAgICAgICAqCiAgICAgICAqIE5vdGUgdGhhdCBgdGVtcGxhdGl6ZSgpYCBjYW4gYmUgcnVuIG9ubHkgb25jZSBmb3IgYSBnaXZlbiBgPHRlbXBsYXRlPmAuCiAgICAgICAqIEZ1cnRoZXIgY2FsbHMgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3IuIEFsc28sIHRoZXJlIGlzIGEgc3BlY2lhbAogICAgICAgKiBiZWhhdmlvciBpZiB0aGUgdGVtcGxhdGUgd2FzIGR1cGxpY2F0ZWQgdGhyb3VnaCBhIG1lY2hhbmlzbSBzdWNoIGFzCiAgICAgICAqIGA8ZG9tLXJlcGVhdD5gIG9yIGA8dGVzdC1maXh0dXJlPmAuIEluIHRoaXMgY2FzZSwgYWxsIGNhbGxzIHRvCiAgICAgICAqIGB0ZW1wbGF0aXplKClgIHJldHVybiB0aGUgc2FtZSBjbGFzcyBmb3IgYWxsIGR1cGxpY2F0ZXMgb2YgYSB0ZW1wbGF0ZS4KICAgICAgICogVGhlIGNsYXNzIHJldHVybmVkIGZyb20gYHRlbXBsYXRpemUoKWAgaXMgZ2VuZXJhdGVkIG9ubHkgb25jZSB1c2luZwogICAgICAgKiB0aGUgYG9wdGlvbnNgIGZyb20gdGhlIGZpcnN0IGNhbGwuIFRoaXMgbWVhbnMgdGhhdCBhbnkgYG9wdGlvbnNgCiAgICAgICAqIHByb3ZpZGVkIHRvIHN1YnNlcXVlbnQgY2FsbHMgd2lsbCBiZSBpZ25vcmVkLiBUaGVyZWZvcmUsIGl0IGlzIHZlcnkKICAgICAgICogaW1wb3J0YW50IG5vdCB0byBjbG9zZSBvdmVyIGFueSB2YXJpYWJsZXMgaW5zaWRlIHRoZSBjYWxsYmFja3MuIEFsc28sCiAgICAgICAqIGFycm93IGZ1bmN0aW9ucyBtdXN0IGJlIGF2b2lkZWQgYmVjYXVzZSB0aGV5IGJpbmQgdGhlIG91dGVyIGB0aGlzYC4KICAgICAgICogSW5zaWRlIHRoZSBjYWxsYmFja3MsIGFueSBjb250ZXh0dWFsIGluZm9ybWF0aW9uIGNhbiBiZSBhY2Nlc3NlZAogICAgICAgKiB0aHJvdWdoIGB0aGlzYCwgd2hpY2ggcG9pbnRzIHRvIHRoZSBgb3duZXJgLgogICAgICAgKgogICAgICAgKiBAbWVtYmVyb2YgUG9seW1lci5UZW1wbGF0aXplCiAgICAgICAqIEBwYXJhbSB7IUhUTUxUZW1wbGF0ZUVsZW1lbnR9IHRlbXBsYXRlIFRlbXBsYXRlIHRvIHRlbXBsYXRpemUKICAgICAgICogQHBhcmFtIHtQb2x5bWVyX1Byb3BlcnR5RWZmZWN0cz19IG93bmVyIE93bmVyIG9mIHRoZSB0ZW1wbGF0ZSBpbnN0YW5jZXM7CiAgICAgICAqICAgYW55IG9wdGlvbmFsIGNhbGxiYWNrcyB3aWxsIGJlIGJvdW5kIHRvIHRoaXMgb3duZXIuCiAgICAgICAqIEBwYXJhbSB7T2JqZWN0PX0gb3B0aW9ucyBPcHRpb25zIGRpY3Rpb25hcnkgKHNlZSBzdW1tYXJ5IGZvciBkZXRhaWxzKQogICAgICAgKiBAcmV0dXJuIHtmdW5jdGlvbihuZXc6VGVtcGxhdGVJbnN0YW5jZUJhc2UpfSBHZW5lcmF0ZWQgY2xhc3MgYm91bmQgdG8gdGhlIHRlbXBsYXRlCiAgICAgICAqICAgcHJvdmlkZWQKICAgICAgICogQHN1cHByZXNzIHtpbnZhbGlkQ2FzdHN9CiAgICAgICAqLwogICAgICB0ZW1wbGF0aXplKHRlbXBsYXRlLCBvd25lciwgb3B0aW9ucykgewogICAgICAgIC8vIFVuZGVyIHN0cmljdFRlbXBsYXRlUG9saWN5LCB0aGUgdGVtcGxhdGl6ZWQgZWxlbWVudCBtdXN0IGJlIG93bmVkCiAgICAgICAgLy8gYnkgYSAodHJ1c3RlZCkgUG9seW1lciBlbGVtZW50LCBpbmRpY2F0ZWQgYnkgZXhpc3RlbmNlIG9mIF9tZXRob2RIb3N0OwogICAgICAgIC8vIGUuZy4gZm9yIGRvbS1pZiAmIGRvbS1yZXBlYXQgaW4gbWFpbiBkb2N1bWVudCwgX21ldGhvZEhvc3QgaXMgbnVsbAogICAgICAgIGlmIChQb2x5bWVyLnN0cmljdFRlbXBsYXRlUG9saWN5ICYmICFmaW5kTWV0aG9kSG9zdCh0ZW1wbGF0ZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBFcnJvcignc3RyaWN0VGVtcGxhdGVQb2xpY3k6IHRlbXBsYXRlIG93bmVyIG5vdCB0cnVzdGVkJyk7CiAgICAgICAgfQogICAgICAgIG9wdGlvbnMgPSAvKiogQHR5cGUgeyFUZW1wbGF0aXplT3B0aW9uc30gKi8ob3B0aW9ucyB8fCB7fSk7CiAgICAgICAgaWYgKHRlbXBsYXRlLl9fdGVtcGxhdGl6ZU93bmVyKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0EgPHRlbXBsYXRlPiBjYW4gb25seSBiZSB0ZW1wbGF0aXplZCBvbmNlJyk7CiAgICAgICAgfQogICAgICAgIHRlbXBsYXRlLl9fdGVtcGxhdGl6ZU93bmVyID0gb3duZXI7CiAgICAgICAgY29uc3QgY3RvciA9IG93bmVyID8gb3duZXIuY29uc3RydWN0b3IgOiBUZW1wbGF0ZUluc3RhbmNlQmFzZTsKICAgICAgICBsZXQgdGVtcGxhdGVJbmZvID0gY3Rvci5fcGFyc2VUZW1wbGF0ZSh0ZW1wbGF0ZSk7CiAgICAgICAgLy8gR2V0IG1lbW9pemVkIGJhc2UgY2xhc3MgZm9yIHRoZSBwcm90b3R5cGljYWwgdGVtcGxhdGUsIHdoaWNoCiAgICAgICAgLy8gaW5jbHVkZXMgcHJvcGVydHkgZWZmZWN0cyBmb3IgYmluZGluZyB0ZW1wbGF0ZSAmIGZvcndhcmRpbmcKICAgICAgICBsZXQgYmFzZUNsYXNzID0gdGVtcGxhdGVJbmZvLnRlbXBsYXRpemVJbnN0YW5jZUNsYXNzOwogICAgICAgIGlmICghYmFzZUNsYXNzKSB7CiAgICAgICAgICBiYXNlQ2xhc3MgPSBjcmVhdGVUZW1wbGF0aXplckNsYXNzKHRlbXBsYXRlLCB0ZW1wbGF0ZUluZm8sIG9wdGlvbnMpOwogICAgICAgICAgdGVtcGxhdGVJbmZvLnRlbXBsYXRpemVJbnN0YW5jZUNsYXNzID0gYmFzZUNsYXNzOwogICAgICAgIH0KICAgICAgICAvLyBIb3N0IHByb3BlcnR5IGZvcndhcmRpbmcgbXVzdCBiZSBpbnN0YWxsZWQgb250byB0ZW1wbGF0ZSBpbnN0YW5jZQogICAgICAgIGFkZFByb3BhZ2F0ZUVmZmVjdHModGVtcGxhdGUsIHRlbXBsYXRlSW5mbywgb3B0aW9ucyk7CiAgICAgICAgLy8gU3ViY2xhc3MgYmFzZSBjbGFzcyBhbmQgYWRkIHJlZmVyZW5jZSBmb3IgdGhpcyBzcGVjaWZpYyB0ZW1wbGF0ZQogICAgICAgIC8qKiBAcHJpdmF0ZSAqLwogICAgICAgIGxldCBrbGFzcyA9IGNsYXNzIFRlbXBsYXRlSW5zdGFuY2UgZXh0ZW5kcyBiYXNlQ2xhc3Mge307CiAgICAgICAga2xhc3MucHJvdG90eXBlLl9tZXRob2RIb3N0ID0gZmluZE1ldGhvZEhvc3QodGVtcGxhdGUpOwogICAgICAgIGtsYXNzLnByb3RvdHlwZS5fX2RhdGFIb3N0ID0gdGVtcGxhdGU7CiAgICAgICAga2xhc3MucHJvdG90eXBlLl9fdGVtcGxhdGl6ZU93bmVyID0gb3duZXI7CiAgICAgICAga2xhc3MucHJvdG90eXBlLl9faG9zdFByb3BzID0gdGVtcGxhdGVJbmZvLmhvc3RQcm9wczsKICAgICAgICBrbGFzcyA9IC8qKiBAdHlwZSB7ZnVuY3Rpb24obmV3OlRlbXBsYXRlSW5zdGFuY2VCYXNlKX0gKi8oa2xhc3MpOyAvL2VzbGludC1kaXNhYmxlLWxpbmUgbm8tc2VsZi1hc3NpZ24KICAgICAgICByZXR1cm4ga2xhc3M7CiAgICAgIH0sCgogICAgICAvKioKICAgICAgICogUmV0dXJucyB0aGUgdGVtcGxhdGUgIm1vZGVsIiBhc3NvY2lhdGVkIHdpdGggYSBnaXZlbiBlbGVtZW50LCB3aGljaAogICAgICAgKiBzZXJ2ZXMgYXMgdGhlIGJpbmRpbmcgc2NvcGUgZm9yIHRoZSB0ZW1wbGF0ZSBpbnN0YW5jZSB0aGUgZWxlbWVudCBpcwogICAgICAgKiBjb250YWluZWQgaW4uIEEgdGVtcGxhdGUgbW9kZWwgaXMgYW4gaW5zdGFuY2Ugb2YKICAgICAgICogYFRlbXBsYXRlSW5zdGFuY2VCYXNlYCwgYW5kIHNob3VsZCBiZSB1c2VkIHRvIG1hbmlwdWxhdGUgZGF0YQogICAgICAgKiBhc3NvY2lhdGVkIHdpdGggdGhpcyB0ZW1wbGF0ZSBpbnN0YW5jZS4KICAgICAgICoKICAgICAgICogRXhhbXBsZToKICAgICAgICoKICAgICAgICogICBsZXQgbW9kZWwgPSBtb2RlbEZvckVsZW1lbnQoZWwpOwogICAgICAgKiAgIGlmIChtb2RlbC5pbmRleCA8IDEwKSB7CiAgICAgICAqICAgICBtb2RlbC5zZXQoJ2l0ZW0uY2hlY2tlZCcsIHRydWUpOwogICAgICAgKiAgIH0KICAgICAgICoKICAgICAgICogQG1lbWJlcm9mIFBvbHltZXIuVGVtcGxhdGl6ZQogICAgICAgKiBAcGFyYW0ge0hUTUxUZW1wbGF0ZUVsZW1lbnR9IHRlbXBsYXRlIFRoZSBtb2RlbCB3aWxsIGJlIHJldHVybmVkIGZvcgogICAgICAgKiAgIGVsZW1lbnRzIHN0YW1wZWQgZnJvbSB0aGlzIHRlbXBsYXRlCiAgICAgICAqIEBwYXJhbSB7Tm9kZT19IG5vZGUgTm9kZSBmb3Igd2hpY2ggdG8gcmV0dXJuIGEgdGVtcGxhdGUgbW9kZWwuCiAgICAgICAqIEByZXR1cm4ge1RlbXBsYXRlSW5zdGFuY2VCYXNlfSBUZW1wbGF0ZSBpbnN0YW5jZSByZXByZXNlbnRpbmcgdGhlCiAgICAgICAqICAgYmluZGluZyBzY29wZSBmb3IgdGhlIGVsZW1lbnQKICAgICAgICovCiAgICAgIG1vZGVsRm9yRWxlbWVudCh0ZW1wbGF0ZSwgbm9kZSkgewogICAgICAgIGxldCBtb2RlbDsKICAgICAgICB3aGlsZSAobm9kZSkgewogICAgICAgICAgLy8gQW4gZWxlbWVudCB3aXRoIGEgX190ZW1wbGF0aXplSW5zdGFuY2UgbWFya3MgdGhlIHRvcCBib3VuZGFyeQogICAgICAgICAgLy8gb2YgYSBzY29wZTsgd2FsayB1cCB1bnRpbCB3ZSBmaW5kIG9uZSwgYW5kIHRoZW4gZW5zdXJlIHRoYXQKICAgICAgICAgIC8vIGl0cyBfX2RhdGFIb3N0IG1hdGNoZXMgYHRoaXNgLCBtZWFuaW5nIHRoaXMgZG9tLXJlcGVhdCBzdGFtcGVkIGl0CiAgICAgICAgICBpZiAoKG1vZGVsID0gbm9kZS5fX3RlbXBsYXRpemVJbnN0YW5jZSkpIHsKICAgICAgICAgICAgLy8gRm91bmQgYW4gZWxlbWVudCBzdGFtcGVkIGJ5IGFub3RoZXIgdGVtcGxhdGU7IGtlZXAgd2Fsa2luZyB1cAogICAgICAgICAgICAvLyBmcm9tIGl0cyBfX2RhdGFIb3N0CiAgICAgICAgICAgIGlmIChtb2RlbC5fX2RhdGFIb3N0ICE9IHRlbXBsYXRlKSB7CiAgICAgICAgICAgICAgbm9kZSA9IG1vZGVsLl9fZGF0YUhvc3Q7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgcmV0dXJuIG1vZGVsOwogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAvLyBTdGlsbCBpbiBhIHRlbXBsYXRlIHNjb3BlLCBrZWVwIGdvaW5nIHVwIHVudGlsCiAgICAgICAgICAgIC8vIGEgX190ZW1wbGF0aXplSW5zdGFuY2UgaXMgZm91bmQKICAgICAgICAgICAgbm9kZSA9IG5vZGUucGFyZW50Tm9kZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgIH0KICAgIH07CgogICAgUG9seW1lci5UZW1wbGF0ZUluc3RhbmNlQmFzZSA9IFRlbXBsYXRlSW5zdGFuY2VCYXNlOwoKICB9KSgpOwoKPC9zY3JpcHQ+PHNjcmlwdD4KICAoZnVuY3Rpb24oKSB7CiAgICAndXNlIHN0cmljdCc7CgogICAgbGV0IFRlbXBsYXRlSW5zdGFuY2VCYXNlID0gUG9seW1lci5UZW1wbGF0ZUluc3RhbmNlQmFzZTsgLy8gZXNsaW50LWRpc2FibGUtbGluZQoKICAgIC8qKgogICAgICogQHR5cGVkZWYge3sKICAgICAqICAgX3RlbXBsYXRpemVyVGVtcGxhdGU6IEhUTUxUZW1wbGF0ZUVsZW1lbnQsCiAgICAgKiAgIF9wYXJlbnRNb2RlbDogYm9vbGVhbiwKICAgICAqICAgX2luc3RhbmNlUHJvcHM6IE9iamVjdCwKICAgICAqICAgX2ZvcndhcmRIb3N0UHJvcFYyOiBGdW5jdGlvbiwKICAgICAqICAgX25vdGlmeUluc3RhbmNlUHJvcFYyOiBGdW5jdGlvbiwKICAgICAqICAgY3RvcjogVGVtcGxhdGVJbnN0YW5jZUJhc2UKICAgICAqIH19CiAgICAgKi8KICAgIGxldCBUZW1wbGF0aXplclVzZXI7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUKCiAgICAvKioKICAgICAqIFRoZSBgUG9seW1lci5UZW1wbGF0aXplcmAgYmVoYXZpb3IgYWRkcyBtZXRob2RzIHRvIGdlbmVyYXRlIGluc3RhbmNlcyBvZgogICAgICogdGVtcGxhdGVzIHRoYXQgYXJlIGVhY2ggbWFuYWdlZCBieSBhbiBhbm9ueW1vdXMgYFBvbHltZXIuUHJvcGVydHlFZmZlY3RzYAogICAgICogaW5zdGFuY2Ugd2hlcmUgZGF0YS1iaW5kaW5ncyBpbiB0aGUgc3RhbXBlZCB0ZW1wbGF0ZSBjb250ZW50IGFyZSBib3VuZCB0bwogICAgICogYWNjZXNzb3JzIG9uIGl0c2VsZi4KICAgICAqCiAgICAgKiBUaGlzIGJlaGF2aW9yIGlzIHByb3ZpZGVkIGluIFBvbHltZXIgMi54IGFzIGEgaHlicmlkLWVsZW1lbnQgY29udmVuaWVuY2UKICAgICAqIG9ubHkuICBGb3Igbm9uLWh5YnJpZCB1c2FnZSwgdGhlIGBQb2x5bWVyLlRlbXBsYXRpemVgIGxpYnJhcnkKICAgICAqIHNob3VsZCBiZSB1c2VkIGluc3RlYWQuCiAgICAgKgogICAgICogRXhhbXBsZToKICAgICAqCiAgICAgKiAgICAgLy8gR2V0IGEgdGVtcGxhdGUgZnJvbSBzb21ld2hlcmUsIGUuZy4gbGlnaHQgRE9NCiAgICAgKiAgICAgbGV0IHRlbXBsYXRlID0gdGhpcy5xdWVyeVNlbGVjdG9yKCd0ZW1wbGF0ZScpOwogICAgICogICAgIC8vIFByZXBhcmUgdGhlIHRlbXBsYXRlCiAgICAgKiAgICAgdGhpcy50ZW1wbGF0aXplKHRlbXBsYXRlKTsKICAgICAqICAgICAvLyBJbnN0YW5jZSB0aGUgdGVtcGxhdGUgd2l0aCBhbiBpbml0aWFsIGRhdGEgbW9kZWwKICAgICAqICAgICBsZXQgaW5zdGFuY2UgPSB0aGlzLnN0YW1wKHtteVByb3A6ICdpbml0aWFsJ30pOwogICAgICogICAgIC8vIEluc2VydCB0aGUgaW5zdGFuY2UncyBET00gc29tZXdoZXJlLCBlLmcuIGxpZ2h0IERPTQogICAgICogICAgIFBvbHltZXIuZG9tKHRoaXMpLmFwcGVuZENoaWxkKGluc3RhbmNlLnJvb3QpOwogICAgICogICAgIC8vIENoYW5naW5nIGEgcHJvcGVydHkgb24gdGhlIGluc3RhbmNlIHdpbGwgcHJvcGFnYXRlIHRvIGJpbmRpbmdzCiAgICAgKiAgICAgLy8gaW4gdGhlIHRlbXBsYXRlCiAgICAgKiAgICAgaW5zdGFuY2UubXlQcm9wID0gJ25ldyB2YWx1ZSc7CiAgICAgKgogICAgICogVXNlcnMgb2YgYFRlbXBsYXRpemVyYCBtYXkgbmVlZCB0byBpbXBsZW1lbnQgdGhlIGZvbGxvd2luZyBhYnN0cmFjdAogICAgICogQVBJJ3MgdG8gZGV0ZXJtaW5lIGhvdyBwcm9wZXJ0aWVzIGFuZCBwYXRocyBmcm9tIHRoZSBob3N0IHNob3VsZCBiZQogICAgICogZm9yd2FyZGVkIGludG8gdG8gaW5zdGFuY2VzOgogICAgICoKICAgICAqICAgICBfZm9yd2FyZEhvc3RQcm9wVjI6IGZ1bmN0aW9uKHByb3AsIHZhbHVlKQogICAgICoKICAgICAqIExpa2V3aXNlLCB1c2VycyBtYXkgaW1wbGVtZW50IHRoZXNlIGFkZGl0aW9uYWwgYWJzdHJhY3QgQVBJJ3MgdG8gZGV0ZXJtaW5lCiAgICAgKiBob3cgaW5zdGFuY2Utc3BlY2lmaWMgcHJvcGVydGllcyB0aGF0IGNoYW5nZSBvbiB0aGUgaW5zdGFuY2Ugc2hvdWxkIGJlCiAgICAgKiBmb3J3YXJkZWQgb3V0IHRvIHRoZSBob3N0LCBpZiBuZWNlc3NhcnkuCiAgICAgKgogICAgICogICAgIF9ub3RpZnlJbnN0YW5jZVByb3BWMjogZnVuY3Rpb24oaW5zdCwgcHJvcCwgdmFsdWUpCiAgICAgKgogICAgICogSW4gb3JkZXIgdG8gZGV0ZXJtaW5lIHdoaWNoIHByb3BlcnRpZXMgYXJlIGluc3RhbmNlLXNwZWNpZmljIGFuZCByZXF1aXJlCiAgICAgKiBjdXN0b20gbm90aWZpY2F0aW9uIHZpYSBgX25vdGlmeUluc3RhbmNlUHJvcGAsIGRlZmluZSBhbiBgX2luc3RhbmNlUHJvcHNgCiAgICAgKiBvYmplY3QgY29udGFpbmluZyBrZXlzIGZvciBlYWNoIGluc3RhbmNlIHByb3AsIGZvciBleGFtcGxlOgogICAgICoKICAgICAqICAgICBfaW5zdGFuY2VQcm9wczogewogICAgICogICAgICAgaXRlbTogdHJ1ZSwKICAgICAqICAgICAgIGluZGV4OiB0cnVlCiAgICAgKiAgICAgfQogICAgICoKICAgICAqIEFueSBwcm9wZXJ0aWVzIHVzZWQgaW4gdGhlIHRlbXBsYXRlIHRoYXQgYXJlIG5vdCBkZWZpbmVkIGluIF9pbnN0YW5jZVByb3AKICAgICAqIHdpbGwgYmUgZm9yd2FyZGVkIG91dCB0byB0aGUgVGVtcGxhdGl6ZSBgb3duZXJgIGF1dG9tYXRpY2FsbHkuCiAgICAgKgogICAgICogVXNlcnMgbWF5IGFsc28gaW1wbGVtZW50IHRoZSBmb2xsb3dpbmcgYWJzdHJhY3QgZnVuY3Rpb24gdG8gc2hvdyBvcgogICAgICogaGlkZSBhbnkgRE9NIGdlbmVyYXRlZCB1c2luZyBgc3RhbXBgOgogICAgICoKICAgICAqICAgICBfc2hvd0hpZGVDaGlsZHJlbjogZnVuY3Rpb24oc2hvdWxkSGlkZSkKICAgICAqCiAgICAgKiBOb3RlIHRoYXQgc29tZSBjYWxsYmFja3MgYXJlIHN1ZmZpeGVkIHdpdGggYFYyYCBpbiB0aGUgUG9seW1lciAyLnggYmVoYXZpb3IKICAgICAqIGFzIHRoZSBpbXBsZW1lbnRhdGlvbnMgd2lsbCBuZWVkIHRvIGRpZmZlciBmcm9tIHRoZSBjYWxsYmFja3MgcmVxdWlyZWQKICAgICAqIGJ5IHRoZSAxLnggVGVtcGxhdGl6ZXIgQVBJIGR1ZSB0byBjaGFuZ2VzIGluIHRoZSBgVGVtcGxhdGVJbnN0YW5jZWAgQVBJCiAgICAgKiBiZXR3ZWVuIHZlcnNpb25zIDEueCBhbmQgMi54LgogICAgICoKICAgICAqIEBwb2x5bWVyQmVoYXZpb3IKICAgICAqLwogICAgUG9seW1lci5UZW1wbGF0aXplciA9IHsKCiAgICAgIC8qKgogICAgICAgKiBHZW5lcmF0ZXMgYW4gYW5vbnltb3VzIGBUZW1wbGF0ZUluc3RhbmNlYCBjbGFzcyAoc3RvcmVkIGFzIGB0aGlzLmN0b3JgKQogICAgICAgKiBmb3IgdGhlIHByb3ZpZGVkIHRlbXBsYXRlLiAgVGhpcyBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCBvbmNlIHBlcgogICAgICAgKiB0ZW1wbGF0ZSB0byBwcmVwYXJlIGFuIGVsZW1lbnQgZm9yIHN0YW1waW5nIHRoZSB0ZW1wbGF0ZSwgZm9sbG93ZWQKICAgICAgICogYnkgYHN0YW1wYCB0byBjcmVhdGUgbmV3IGluc3RhbmNlcyBvZiB0aGUgdGVtcGxhdGUuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7IUhUTUxUZW1wbGF0ZUVsZW1lbnR9IHRlbXBsYXRlIFRlbXBsYXRlIHRvIHByZXBhcmUKICAgICAgICogQHBhcmFtIHtib29sZWFuPX0gbXV0YWJsZURhdGEgV2hlbiBgdHJ1ZWAsIHRoZSBnZW5lcmF0ZWQgY2xhc3Mgd2lsbCBza2lwCiAgICAgICAqICAgc3RyaWN0IGRpcnR5LWNoZWNraW5nIGZvciBvYmplY3RzIGFuZCBhcnJheXMgKGFsd2F5cyBjb25zaWRlciB0aGVtIHRvCiAgICAgICAqICAgYmUgImRpcnR5IikuIERlZmF1bHRzIHRvIGZhbHNlLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKiBAdGhpcyB7VGVtcGxhdGl6ZXJVc2VyfQogICAgICAgKi8KICAgICAgdGVtcGxhdGl6ZSh0ZW1wbGF0ZSwgbXV0YWJsZURhdGEpIHsKICAgICAgICB0aGlzLl90ZW1wbGF0aXplclRlbXBsYXRlID0gdGVtcGxhdGU7CiAgICAgICAgdGhpcy5jdG9yID0gUG9seW1lci5UZW1wbGF0aXplLnRlbXBsYXRpemUodGVtcGxhdGUsIHRoaXMsIHsKICAgICAgICAgIG11dGFibGVEYXRhOiBCb29sZWFuKG11dGFibGVEYXRhKSwKICAgICAgICAgIHBhcmVudE1vZGVsOiB0aGlzLl9wYXJlbnRNb2RlbCwKICAgICAgICAgIGluc3RhbmNlUHJvcHM6IHRoaXMuX2luc3RhbmNlUHJvcHMsCiAgICAgICAgICBmb3J3YXJkSG9zdFByb3A6IHRoaXMuX2ZvcndhcmRIb3N0UHJvcFYyLAogICAgICAgICAgbm90aWZ5SW5zdGFuY2VQcm9wOiB0aGlzLl9ub3RpZnlJbnN0YW5jZVByb3BWMgogICAgICAgIH0pOwogICAgICB9LAoKICAgICAgLyoqCiAgICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgdGhlIHRlbXBsYXRlIHByZXBhcmVkIGJ5IGB0ZW1wbGF0aXplYC4gIFRoZSBvYmplY3QKICAgICAgICogcmV0dXJuZWQgaXMgYW4gaW5zdGFuY2Ugb2YgdGhlIGFub255bW91cyBjbGFzcyBnZW5lcmF0ZWQgYnkgYHRlbXBsYXRpemVgCiAgICAgICAqIHdob3NlIGByb290YCBwcm9wZXJ0eSBpcyBhIGRvY3VtZW50IGZyYWdtZW50IGNvbnRhaW5pbmcgbmV3bHkgY2xvbmVkCiAgICAgICAqIHRlbXBsYXRlIGNvbnRlbnQsIGFuZCB3aGljaCBoYXMgcHJvcGVydHkgYWNjZXNzb3JzIGNvcnJlc3BvbmRpbmcgdG8KICAgICAgICogcHJvcGVydGllcyByZWZlcmVuY2VkIGluIHRlbXBsYXRlIGJpbmRpbmdzLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge09iamVjdD19IG1vZGVsIE9iamVjdCBjb250YWluaW5nIGluaXRpYWwgcHJvcGVydHkgdmFsdWVzIHRvCiAgICAgICAqICAgcG9wdWxhdGUgaW50byB0aGUgdGVtcGxhdGUgYmluZGluZ3MuCiAgICAgICAqIEByZXR1cm4ge1RlbXBsYXRlSW5zdGFuY2VCYXNlfSBSZXR1cm5zIHRoZSBjcmVhdGVkIGluc3RhbmNlIG9mCiAgICAgICAqIHRoZSB0ZW1wbGF0ZSBwcmVwYXJlZCBieSBgdGVtcGxhdGl6ZWAuCiAgICAgICAqIEB0aGlzIHtUZW1wbGF0aXplclVzZXJ9CiAgICAgICAqLwogICAgICBzdGFtcChtb2RlbCkgewogICAgICAgIHJldHVybiBuZXcgdGhpcy5jdG9yKG1vZGVsKTsKICAgICAgfSwKCiAgICAgIC8qKgogICAgICAgKiBSZXR1cm5zIHRoZSB0ZW1wbGF0ZSAibW9kZWwiIChgVGVtcGxhdGVJbnN0YW5jZWApIGFzc29jaWF0ZWQgd2l0aAogICAgICAgKiBhIGdpdmVuIGVsZW1lbnQsIHdoaWNoIHNlcnZlcyBhcyB0aGUgYmluZGluZyBzY29wZSBmb3IgdGhlIHRlbXBsYXRlCiAgICAgICAqIGluc3RhbmNlIHRoZSBlbGVtZW50IGlzIGNvbnRhaW5lZCBpbi4gIEEgdGVtcGxhdGUgbW9kZWwgc2hvdWxkIGJlIHVzZWQKICAgICAgICogdG8gbWFuaXB1bGF0ZSBkYXRhIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHRlbXBsYXRlIGluc3RhbmNlLgogICAgICAgKgogICAgICAgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbCBFbGVtZW50IGZvciB3aGljaCB0byByZXR1cm4gYSB0ZW1wbGF0ZSBtb2RlbC4KICAgICAgICogQHJldHVybiB7VGVtcGxhdGVJbnN0YW5jZUJhc2V9IE1vZGVsIHJlcHJlc2VudGluZyB0aGUgYmluZGluZyBzY29wZSBmb3IKICAgICAgICogICB0aGUgZWxlbWVudC4KICAgICAgICogQHRoaXMge1RlbXBsYXRpemVyVXNlcn0KICAgICAgICovCiAgICAgIG1vZGVsRm9yRWxlbWVudChlbCkgewogICAgICAgIHJldHVybiBQb2x5bWVyLlRlbXBsYXRpemUubW9kZWxGb3JFbGVtZW50KHRoaXMuX3RlbXBsYXRpemVyVGVtcGxhdGUsIGVsKTsKICAgICAgfQogICAgfTsKCiAgfSkoKTsKPC9zY3JpcHQ+PHNjcmlwdD4KCiAgKGZ1bmN0aW9uKCkgewogICAgJ3VzZSBzdHJpY3QnOwoKICAgIC8qKgogICAgICogQGNvbnN0cnVjdG9yCiAgICAgKiBAZXh0ZW5kcyB7SFRNTEVsZW1lbnR9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9Qcm9wZXJ0eUVmZmVjdHN9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9PcHRpb25hbE11dGFibGVEYXRhfQogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfR2VzdHVyZUV2ZW50TGlzdGVuZXJzfQogICAgICogQHByaXZhdGUKICAgICAqLwogICAgY29uc3QgZG9tQmluZEJhc2UgPQogICAgICBQb2x5bWVyLkdlc3R1cmVFdmVudExpc3RlbmVycygKICAgICAgICBQb2x5bWVyLk9wdGlvbmFsTXV0YWJsZURhdGEoCiAgICAgICAgICBQb2x5bWVyLlByb3BlcnR5RWZmZWN0cyhIVE1MRWxlbWVudCkpKTsKCiAgICAvKioKICAgICAqIEN1c3RvbSBlbGVtZW50IHRvIGFsbG93IHVzaW5nIFBvbHltZXIncyB0ZW1wbGF0ZSBmZWF0dXJlcyAoZGF0YSBiaW5kaW5nLAogICAgICogZGVjbGFyYXRpdmUgZXZlbnQgbGlzdGVuZXJzLCBldGMuKSBpbiB0aGUgbWFpbiBkb2N1bWVudCB3aXRob3V0IGRlZmluaW5nCiAgICAgKiBhIG5ldyBjdXN0b20gZWxlbWVudC4KICAgICAqCiAgICAgKiBgPHRlbXBsYXRlPmAgdGFncyB1dGlsaXppbmcgYmluZGluZ3MgbWF5IGJlIHdyYXBwZWQgd2l0aCB0aGUgYDxkb20tYmluZD5gCiAgICAgKiBlbGVtZW50LCB3aGljaCB3aWxsIGltbWVkaWF0ZWx5IHN0YW1wIHRoZSB3cmFwcGVkIHRlbXBsYXRlIGludG8gdGhlIG1haW4KICAgICAqIGRvY3VtZW50IGFuZCBiaW5kIGVsZW1lbnRzIHRvIHRoZSBgZG9tLWJpbmRgIGVsZW1lbnQgaXRzZWxmIGFzIHRoZQogICAgICogYmluZGluZyBzY29wZS4KICAgICAqCiAgICAgKiBAcG9seW1lcgogICAgICogQGN1c3RvbUVsZW1lbnQKICAgICAqIEBhcHBsaWVzTWl4aW4gUG9seW1lci5Qcm9wZXJ0eUVmZmVjdHMKICAgICAqIEBhcHBsaWVzTWl4aW4gUG9seW1lci5PcHRpb25hbE11dGFibGVEYXRhCiAgICAgKiBAYXBwbGllc01peGluIFBvbHltZXIuR2VzdHVyZUV2ZW50TGlzdGVuZXJzCiAgICAgKiBAZXh0ZW5kcyB7ZG9tQmluZEJhc2V9CiAgICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAgICogQHN1bW1hcnkgQ3VzdG9tIGVsZW1lbnQgdG8gYWxsb3cgdXNpbmcgUG9seW1lcidzIHRlbXBsYXRlIGZlYXR1cmVzIChkYXRhCiAgICAgKiAgIGJpbmRpbmcsIGRlY2xhcmF0aXZlIGV2ZW50IGxpc3RlbmVycywgZXRjLikgaW4gdGhlIG1haW4gZG9jdW1lbnQuCiAgICAgKi8KICAgIGNsYXNzIERvbUJpbmQgZXh0ZW5kcyBkb21CaW5kQmFzZSB7CgogICAgICBzdGF0aWMgZ2V0IG9ic2VydmVkQXR0cmlidXRlcygpIHsgcmV0dXJuIFsnbXV0YWJsZS1kYXRhJ107IH0KCiAgICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgIHN1cGVyKCk7CiAgICAgICAgaWYgKFBvbHltZXIuc3RyaWN0VGVtcGxhdGVQb2xpY3kpIHsKICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgc3RyaWN0VGVtcGxhdGVQb2xpY3k6IGRvbS1iaW5kIG5vdCBhbGxvd2VkYCk7CiAgICAgICAgfQogICAgICAgIHRoaXMucm9vdCA9IG51bGw7CiAgICAgICAgdGhpcy4kID0gbnVsbDsKICAgICAgICB0aGlzLl9fY2hpbGRyZW4gPSBudWxsOwogICAgICB9CgogICAgICAvKiogQHJldHVybiB7dm9pZH0gKi8KICAgICAgYXR0cmlidXRlQ2hhbmdlZENhbGxiYWNrKCkgewogICAgICAgIC8vIGFzc3VtZXMgb25seSBvbmUgb2JzZXJ2ZWQgYXR0cmlidXRlCiAgICAgICAgdGhpcy5tdXRhYmxlRGF0YSA9IHRydWU7CiAgICAgIH0KCiAgICAgIC8qKiBAcmV0dXJuIHt2b2lkfSAqLwogICAgICBjb25uZWN0ZWRDYWxsYmFjaygpIHsKICAgICAgICB0aGlzLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7CiAgICAgICAgdGhpcy5yZW5kZXIoKTsKICAgICAgfQoKICAgICAgLyoqIEByZXR1cm4ge3ZvaWR9ICovCiAgICAgIGRpc2Nvbm5lY3RlZENhbGxiYWNrKCkgewogICAgICAgIHRoaXMuX19yZW1vdmVDaGlsZHJlbigpOwogICAgICB9CgogICAgICBfX2luc2VydENoaWxkcmVuKCkgewogICAgICAgIHRoaXMucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUodGhpcy5yb290LCB0aGlzKTsKICAgICAgfQoKICAgICAgX19yZW1vdmVDaGlsZHJlbigpIHsKICAgICAgICBpZiAodGhpcy5fX2NoaWxkcmVuKSB7CiAgICAgICAgICBmb3IgKGxldCBpPTA7IGk8dGhpcy5fX2NoaWxkcmVuLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIHRoaXMucm9vdC5hcHBlbmRDaGlsZCh0aGlzLl9fY2hpbGRyZW5baV0pOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIEZvcmNlcyB0aGUgZWxlbWVudCB0byByZW5kZXIgaXRzIGNvbnRlbnQuIFRoaXMgaXMgdHlwaWNhbGx5IG9ubHkKICAgICAgICogbmVjZXNzYXJ5IHRvIGNhbGwgaWYgSFRNTEltcG9ydHMgd2l0aCB0aGUgYXN5bmMgYXR0cmlidXRlIGFyZSB1c2VkLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgcmVuZGVyKCkgewogICAgICAgIGxldCB0ZW1wbGF0ZTsKICAgICAgICBpZiAoIXRoaXMuX19jaGlsZHJlbikgewogICAgICAgICAgdGVtcGxhdGUgPSAvKiogQHR5cGUge0hUTUxUZW1wbGF0ZUVsZW1lbnR9ICovKHRlbXBsYXRlIHx8IHRoaXMucXVlcnlTZWxlY3RvcigndGVtcGxhdGUnKSk7CiAgICAgICAgICBpZiAoIXRlbXBsYXRlKSB7CiAgICAgICAgICAgIC8vIFdhaXQgdW50aWwgY2hpbGRMaXN0IGNoYW5nZXMgYW5kIHRlbXBsYXRlIHNob3VsZCBiZSB0aGVyZSBieSB0aGVuCiAgICAgICAgICAgIGxldCBvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKCgpID0+IHsKICAgICAgICAgICAgICB0ZW1wbGF0ZSA9IC8qKiBAdHlwZSB7SFRNTFRlbXBsYXRlRWxlbWVudH0gKi8odGhpcy5xdWVyeVNlbGVjdG9yKCd0ZW1wbGF0ZScpKTsKICAgICAgICAgICAgICBpZiAodGVtcGxhdGUpIHsKICAgICAgICAgICAgICAgIG9ic2VydmVyLmRpc2Nvbm5lY3QoKTsKICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyKCk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZG9tLWJpbmQgcmVxdWlyZXMgYSA8dGVtcGxhdGU+IGNoaWxkJyk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgb2JzZXJ2ZXIub2JzZXJ2ZSh0aGlzLCB7Y2hpbGRMaXN0OiB0cnVlfSk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgIH0KICAgICAgICAgIHRoaXMucm9vdCA9IHRoaXMuX3N0YW1wVGVtcGxhdGUodGVtcGxhdGUpOwogICAgICAgICAgdGhpcy4kID0gdGhpcy5yb290LiQ7CiAgICAgICAgICB0aGlzLl9fY2hpbGRyZW4gPSBbXTsKICAgICAgICAgIGZvciAobGV0IG49dGhpcy5yb290LmZpcnN0Q2hpbGQ7IG47IG49bi5uZXh0U2libGluZykgewogICAgICAgICAgICB0aGlzLl9fY2hpbGRyZW5bdGhpcy5fX2NoaWxkcmVuLmxlbmd0aF0gPSBuOwogICAgICAgICAgfQogICAgICAgICAgdGhpcy5fZW5hYmxlUHJvcGVydGllcygpOwogICAgICAgIH0KICAgICAgICB0aGlzLl9faW5zZXJ0Q2hpbGRyZW4oKTsKICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KCdkb20tY2hhbmdlJywgewogICAgICAgICAgYnViYmxlczogdHJ1ZSwKICAgICAgICAgIGNvbXBvc2VkOiB0cnVlCiAgICAgICAgfSkpOwogICAgICB9CgogICAgfQoKICAgIGN1c3RvbUVsZW1lbnRzLmRlZmluZSgnZG9tLWJpbmQnLCBEb21CaW5kKTsKCiAgICAvKiogQGNvbnN0ICovCiAgICBQb2x5bWVyLkRvbUJpbmQgPSBEb21CaW5kOwoKICB9KSgpOwoKPC9zY3JpcHQ+PHNjcmlwdD4KICAoZnVuY3Rpb24oKSB7CiAgICAndXNlIHN0cmljdCc7CgogICAgLyoqCiAgICAgKiBDbGFzcyByZXByZXNlbnRpbmcgYSBzdGF0aWMgc3RyaW5nIHZhbHVlIHdoaWNoIGNhbiBiZSB1c2VkIHRvIGZpbHRlcgogICAgICogc3RyaW5ncyBieSBhc3NldGluZyB0aGF0IHRoZXkgaGF2ZSBiZWVuIGNyZWF0ZWQgdmlhIHRoaXMgY2xhc3MuIFRoZQogICAgICogYHZhbHVlYCBwcm9wZXJ0eSByZXR1cm5zIHRoZSBzdHJpbmcgcGFzc2VkIHRvIHRoZSBjb25zdHJ1Y3Rvci4KICAgICAqLwogICAgY2xhc3MgTGl0ZXJhbFN0cmluZyB7CiAgICAgIGNvbnN0cnVjdG9yKHN0cmluZykgewogICAgICAgIC8qKiBAdHlwZSB7c3RyaW5nfSAqLwogICAgICAgIHRoaXMudmFsdWUgPSBzdHJpbmcudG9TdHJpbmcoKTsKICAgICAgfQogICAgICAvKioKICAgICAgICogQHJldHVybiB7c3RyaW5nfSBMaXRlcmFsU3RyaW5nIHN0cmluZyB2YWx1ZQogICAgICAgKi8KICAgICAgdG9TdHJpbmcoKSB7CiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWU7CiAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgT2JqZWN0IHRvIHN0cmluZ2lmeSBpbnRvIEhUTUwKICAgICAqIEByZXR1cm4ge3N0cmluZ30gSFRNTCBzdHJpbmdpZmllZCBmb3JtIG9mIGBvYmpgCiAgICAgKi8KICAgIGZ1bmN0aW9uIGxpdGVyYWxWYWx1ZSh2YWx1ZSkgewogICAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBMaXRlcmFsU3RyaW5nKSB7CiAgICAgICAgcmV0dXJuIC8qKiBAdHlwZSB7IUxpdGVyYWxTdHJpbmd9ICovKHZhbHVlKS52YWx1ZTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYG5vbi1saXRlcmFsIHZhbHVlIHBhc3NlZCB0byBQb2x5bWVyLmh0bWxMaXRlcmFsOiAke3ZhbHVlfWApOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIE9iamVjdCB0byBzdHJpbmdpZnkgaW50byBIVE1MCiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IEhUTUwgc3RyaW5naWZpZWQgZm9ybSBvZiBgb2JqYAogICAgICovCiAgICBmdW5jdGlvbiBodG1sVmFsdWUodmFsdWUpIHsKICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgSFRNTFRlbXBsYXRlRWxlbWVudCkgewogICAgICAgIHJldHVybiAvKiogQHR5cGUgeyFIVE1MVGVtcGxhdGVFbGVtZW50IH0gKi8odmFsdWUpLmlubmVySFRNTDsKICAgICAgfSBlbHNlIGlmICh2YWx1ZSBpbnN0YW5jZW9mIExpdGVyYWxTdHJpbmcpIHsKICAgICAgICByZXR1cm4gbGl0ZXJhbFZhbHVlKHZhbHVlKTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYG5vbi10ZW1wbGF0ZSB2YWx1ZSBwYXNzZWQgdG8gUG9seW1lci5odG1sOiAke3ZhbHVlfWApOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBBIHRlbXBsYXRlIGxpdGVyYWwgdGFnIHRoYXQgY3JlYXRlcyBhbiBIVE1MIDx0ZW1wbGF0ZT4gZWxlbWVudCBmcm9tIHRoZQogICAgICogY29udGVudHMgb2YgdGhlIHN0cmluZy4KICAgICAqCiAgICAgKiBUaGlzIGFsbG93cyB5b3UgdG8gd3JpdGUgYSBQb2x5bWVyIFRlbXBsYXRlIGluIEphdmFTY3JpcHQuCiAgICAgKgogICAgICogVGVtcGxhdGVzIGNhbiBiZSBjb21wb3NlZCBieSBpbnRlcnBvbGF0aW5nIGBIVE1MVGVtcGxhdGVFbGVtZW50YHMgaW4KICAgICAqIGV4cHJlc3Npb25zIGluIHRoZSBKYXZhU2NyaXB0IHRlbXBsYXRlIGxpdGVyYWwuIFRoZSBuZXN0ZWQgdGVtcGxhdGUncwogICAgICogYGlubmVySFRNTGAgaXMgaW5jbHVkZWQgaW4gdGhlIGNvbnRhaW5pbmcgdGVtcGxhdGUuICBUaGUgb25seSBvdGhlcgogICAgICogdmFsdWVzIGFsbG93ZWQgaW4gZXhwcmVzc2lvbnMgYXJlIHRob3NlIHJldHVybmVkIGZyb20gYFBvbHltZXIuaHRtbExpdGVyYWxgCiAgICAgKiB3aGljaCBlbnN1cmVzIG9ubHkgbGl0ZXJhbCB2YWx1ZXMgZnJvbSBKUyBzb3VyY2UgZXZlciByZWFjaCB0aGUgSFRNTCwgdG8KICAgICAqIGd1YXJkIGFnYWluc3QgWFNTIHJpc2tzLgogICAgICoKICAgICAqIEFsbCBvdGhlciB2YWx1ZXMgYXJlIGRpc2FsbG93ZWQgaW4gZXhwcmVzc2lvbnMgdG8gaGVscCBwcmV2ZW50IFhTUwogICAgICogYXR0YWNrczsgaG93ZXZlciwgYFBvbHltZXIuaHRtbExpdGVyYWxgIGNhbiBiZSB1c2VkIHRvIGNvbXBvc2Ugc3RhdGljCiAgICAgKiBzdHJpbmcgdmFsdWVzIGludG8gdGVtcGxhdGVzLiBUaGlzIGlzIHVzZWZ1bCB0byBjb21wb3NlIHN0cmluZ3MgaW50bwogICAgICogcGxhY2VzIHRoYXQgZG8gbm90IGFjY2VwdCBodG1sLCBsaWtlIHRoZSBjc3MgdGV4dCBvZiBhIGBzdHlsZWAKICAgICAqIGVsZW1lbnQuCiAgICAgKgogICAgICogRXhhbXBsZToKICAgICAqCiAgICAgKiAgICAgc3RhdGljIGdldCB0ZW1wbGF0ZSgpIHsKICAgICAqICAgICAgIHJldHVybiBQb2x5bWVyLmh0bWxgCiAgICAgKiAgICAgICAgIDxzdHlsZT46aG9zdHsgY29udGVudDoiLi4uIiB9PC9zdHlsZT4KICAgICAqICAgICAgICAgPGRpdiBjbGFzcz0ic2hhZG93ZWQiPiR7dGhpcy5wYXJ0aWFsVGVtcGxhdGV9PC9kaXY+CiAgICAgKiAgICAgICAgICR7c3VwZXIudGVtcGxhdGV9CiAgICAgKiAgICAgICBgOwogICAgICogICAgIH0KICAgICAqICAgICBzdGF0aWMgZ2V0IHBhcnRpYWxUZW1wbGF0ZSgpIHsgcmV0dXJuIFBvbHltZXIuaHRtbGA8c3Bhbj5QYXJ0aWFsITwvc3Bhbj5gOyB9CiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgICAqIEBwYXJhbSB7IUlUZW1wbGF0ZUFycmF5fSBzdHJpbmdzIENvbnN0YW50IHBhcnRzIG9mIHRhZ2dlZCB0ZW1wbGF0ZSBsaXRlcmFsCiAgICAgKiBAcGFyYW0gey4uLip9IHZhbHVlcyBWYXJpYWJsZSBwYXJ0cyBvZiB0YWdnZWQgdGVtcGxhdGUgbGl0ZXJhbAogICAgICogQHJldHVybiB7IUhUTUxUZW1wbGF0ZUVsZW1lbnR9IENvbnN0cnVjdGVkIEhUTUxUZW1wbGF0ZUVsZW1lbnQKICAgICAqLwogICAgUG9seW1lci5odG1sID0gZnVuY3Rpb24gaHRtbChzdHJpbmdzLCAuLi52YWx1ZXMpIHsKICAgICAgY29uc3QgdGVtcGxhdGUgPSAvKiogQHR5cGUgeyFIVE1MVGVtcGxhdGVFbGVtZW50fSAqLyhkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0ZW1wbGF0ZScpKTsKICAgICAgdGVtcGxhdGUuaW5uZXJIVE1MID0gdmFsdWVzLnJlZHVjZSgoYWNjLCB2LCBpZHgpID0+CiAgICAgICAgICBhY2MgKyBodG1sVmFsdWUodikgKyBzdHJpbmdzW2lkeCArIDFdLCBzdHJpbmdzWzBdKTsKICAgICAgcmV0dXJuIHRlbXBsYXRlOwogICAgfTsKCiAgICAvKioKICAgICAqIEFuIGh0bWwgbGl0ZXJhbCB0YWcgdGhhdCBjYW4gYmUgdXNlZCB3aXRoIGBQb2x5bWVyLmh0bWxgIHRvIGNvbXBvc2UuCiAgICAgKiBhIGxpdGVyYWwgc3RyaW5nLgogICAgICoKICAgICAqIEV4YW1wbGU6CiAgICAgKgogICAgICogICAgIHN0YXRpYyBnZXQgdGVtcGxhdGUoKSB7CiAgICAgKiAgICAgICByZXR1cm4gUG9seW1lci5odG1sYAogICAgICogICAgICAgICA8c3R5bGU+CiAgICAgKiAgICAgICAgICAgOmhvc3QgeyBkaXNwbGF5OiBibG9jazsgfQogICAgICogICAgICAgICAgICR7c3R5bGVUZW1wbGF0ZX0KICAgICAqICAgICAgICAgPC9zdHlsZT4KICAgICAqICAgICAgICAgPGRpdiBjbGFzcz0ic2hhZG93ZWQiPiR7c3RhdGljVmFsdWV9PC9kaXY+CiAgICAgKiAgICAgICAgICR7c3VwZXIudGVtcGxhdGV9CiAgICAgKiAgICAgICBgOwogICAgICogICAgIH0KICAgICAqICAgICBzdGF0aWMgZ2V0IHN0eWxlVGVtcGxhdGUoKSB7IHJldHVybiBQb2x5bWVyLmh0bWxMaXRlcmFsYC5zaGFkb3dlZCB7IGJhY2tncm91bmQ6IGdyYXk7IH1gOyB9CiAgICAgKgogICAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgICAqIEBwYXJhbSB7IUlUZW1wbGF0ZUFycmF5fSBzdHJpbmdzIENvbnN0YW50IHBhcnRzIG9mIHRhZ2dlZCB0ZW1wbGF0ZSBsaXRlcmFsCiAgICAgKiBAcGFyYW0gey4uLip9IHZhbHVlcyBWYXJpYWJsZSBwYXJ0cyBvZiB0YWdnZWQgdGVtcGxhdGUgbGl0ZXJhbAogICAgICogQHJldHVybiB7IUxpdGVyYWxTdHJpbmd9IENvbnN0cnVjdGVkIGxpdGVyYWwgc3RyaW5nCiAgICAgKi8KICAgIFBvbHltZXIuaHRtbExpdGVyYWwgPSBmdW5jdGlvbihzdHJpbmdzLCAuLi52YWx1ZXMpIHsKICAgICAgcmV0dXJuIG5ldyBMaXRlcmFsU3RyaW5nKHZhbHVlcy5yZWR1Y2UoKGFjYywgdiwgaWR4KSA9PgogICAgICAgICAgYWNjICsgbGl0ZXJhbFZhbHVlKHYpICsgc3RyaW5nc1tpZHggKyAxXSwgc3RyaW5nc1swXSkpOwogICAgfTsKICB9KSgpOwo8L3NjcmlwdD48c2NyaXB0PgooZnVuY3Rpb24oKSB7CiAgJ3VzZSBzdHJpY3QnOwoKICAvKioKICAgKiBCYXNlIGNsYXNzIHRoYXQgcHJvdmlkZXMgdGhlIGNvcmUgQVBJIGZvciBQb2x5bWVyJ3MgbWV0YS1wcm9ncmFtbWluZwogICAqIGZlYXR1cmVzIGluY2x1ZGluZyB0ZW1wbGF0ZSBzdGFtcGluZywgZGF0YS1iaW5kaW5nLCBhdHRyaWJ1dGUgZGVzZXJpYWxpemF0aW9uLAogICAqIGFuZCBwcm9wZXJ0eSBjaGFuZ2Ugb2JzZXJ2YXRpb24uCiAgICoKICAgKiBAY3VzdG9tRWxlbWVudAogICAqIEBtZW1iZXJvZiBQb2x5bWVyCiAgICogQGNvbnN0cnVjdG9yCiAgICogQGltcGxlbWVudHMge1BvbHltZXJfRWxlbWVudE1peGlufQogICAqIEBleHRlbmRzIHtIVE1MRWxlbWVudH0KICAgKiBAYXBwbGllc01peGluIFBvbHltZXIuRWxlbWVudE1peGluCiAgICogQHN1bW1hcnkgQ3VzdG9tIGVsZW1lbnQgYmFzZSBjbGFzcyB0aGF0IHByb3ZpZGVzIHRoZSBjb3JlIEFQSSBmb3IgUG9seW1lcidzCiAgICogICBrZXkgbWV0YS1wcm9ncmFtbWluZyBmZWF0dXJlcyBpbmNsdWRpbmcgdGVtcGxhdGUgc3RhbXBpbmcsIGRhdGEtYmluZGluZywKICAgKiAgIGF0dHJpYnV0ZSBkZXNlcmlhbGl6YXRpb24sIGFuZCBwcm9wZXJ0eSBjaGFuZ2Ugb2JzZXJ2YXRpb24KICAgKi8KICBQb2x5bWVyLkVsZW1lbnQgPSBQb2x5bWVyLkVsZW1lbnRNaXhpbihIVE1MRWxlbWVudCk7CgogIC8vIE5PVEU6IHRoaXMgaXMgaGVyZSBmb3IgbW9kdWxpemVyIHRvIGV4cG9ydCBgaHRtbGAgZm9yIHRoZSBtb2R1bGUgdmVyc2lvbiBvZiB0aGlzIGZpbGUKICBQb2x5bWVyLmh0bWwgPSBQb2x5bWVyLmh0bWw7Cn0pKCk7Cjwvc2NyaXB0PjxzY3JpcHQ+CihmdW5jdGlvbigpIHsKICAndXNlIHN0cmljdCc7CgogIGxldCBUZW1wbGF0ZUluc3RhbmNlQmFzZSA9IFBvbHltZXIuVGVtcGxhdGVJbnN0YW5jZUJhc2U7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUKCiAgLyoqCiAgICogQGNvbnN0cnVjdG9yCiAgICogQGltcGxlbWVudHMge1BvbHltZXJfT3B0aW9uYWxNdXRhYmxlRGF0YX0KICAgKiBAZXh0ZW5kcyB7UG9seW1lci5FbGVtZW50fQogICAqIEBwcml2YXRlCiAgICovCiAgY29uc3QgZG9tUmVwZWF0QmFzZSA9IFBvbHltZXIuT3B0aW9uYWxNdXRhYmxlRGF0YShQb2x5bWVyLkVsZW1lbnQpOwoKICAvKioKICAgKiBUaGUgYDxkb20tcmVwZWF0PmAgZWxlbWVudCB3aWxsIGF1dG9tYXRpY2FsbHkgc3RhbXAgYW5kIGJpbmRzIG9uZSBpbnN0YW5jZQogICAqIG9mIHRlbXBsYXRlIGNvbnRlbnQgdG8gZWFjaCBvYmplY3QgaW4gYSB1c2VyLXByb3ZpZGVkIGFycmF5LgogICAqIGBkb20tcmVwZWF0YCBhY2NlcHRzIGFuIGBpdGVtc2AgcHJvcGVydHksIGFuZCBvbmUgaW5zdGFuY2Ugb2YgdGhlIHRlbXBsYXRlCiAgICogaXMgc3RhbXBlZCBmb3IgZWFjaCBpdGVtIGludG8gdGhlIERPTSBhdCB0aGUgbG9jYXRpb24gb2YgdGhlIGBkb20tcmVwZWF0YAogICAqIGVsZW1lbnQuICBUaGUgYGl0ZW1gIHByb3BlcnR5IHdpbGwgYmUgc2V0IG9uIGVhY2ggaW5zdGFuY2UncyBiaW5kaW5nCiAgICogc2NvcGUsIHRodXMgdGVtcGxhdGVzIHNob3VsZCBiaW5kIHRvIHN1Yi1wcm9wZXJ0aWVzIG9mIGBpdGVtYC4KICAgKgogICAqIEV4YW1wbGU6CiAgICoKICAgKiBgYGBodG1sCiAgICogPGRvbS1tb2R1bGUgaWQ9ImVtcGxveWVlLWxpc3QiPgogICAqCiAgICogICA8dGVtcGxhdGU+CiAgICoKICAgKiAgICAgPGRpdj4gRW1wbG95ZWUgbGlzdDogPC9kaXY+CiAgICogICAgIDxkb20tcmVwZWF0IGl0ZW1zPSJ7e2VtcGxveWVlc319Ij4KICAgKiAgICAgICA8dGVtcGxhdGU+CiAgICogICAgICAgICA8ZGl2PkZpcnN0IG5hbWU6IDxzcGFuPnt7aXRlbS5maXJzdH19PC9zcGFuPjwvZGl2PgogICAqICAgICAgICAgPGRpdj5MYXN0IG5hbWU6IDxzcGFuPnt7aXRlbS5sYXN0fX08L3NwYW4+PC9kaXY+CiAgICogICAgICAgPC90ZW1wbGF0ZT4KICAgKiAgICAgPC9kb20tcmVwZWF0PgogICAqCiAgICogICA8L3RlbXBsYXRlPgogICAqCiAgICogPC9kb20tbW9kdWxlPgogICAqIGBgYAogICAqCiAgICogV2l0aCB0aGUgZm9sbG93aW5nIGN1c3RvbSBlbGVtZW50IGRlZmluaXRpb246CiAgICoKICAgKiBgYGBqcwogICAqIGNsYXNzIEVtcGxveWVlTGlzdCBleHRlbmRzIFBvbHltZXIuRWxlbWVudCB7CiAgICogICBzdGF0aWMgZ2V0IGlzKCkgeyByZXR1cm4gJ2VtcGxveWVlLWxpc3QnOyB9CiAgICogICBzdGF0aWMgZ2V0IHByb3BlcnRpZXMoKSB7CiAgICogICAgIHJldHVybiB7CiAgICogICAgICAgZW1wbG95ZWVzOiB7CiAgICogICAgICAgICB2YWx1ZSgpIHsKICAgKiAgICAgICAgICAgcmV0dXJuIFsKICAgKiAgICAgICAgICAgICB7Zmlyc3Q6ICdCb2InLCBsYXN0OiAnU21pdGgnfSwKICAgKiAgICAgICAgICAgICB7Zmlyc3Q6ICdTYWxseScsIGxhc3Q6ICdKb2huc29uJ30sCiAgICogICAgICAgICAgICAgLi4uCiAgICogICAgICAgICAgIF07CiAgICogICAgICAgICB9CiAgICogICAgICAgfQogICAqICAgICB9OwogICAqICAgfQogICAqIH0KICAgKiBgYGAKICAgKgogICAqIE5vdGlmaWNhdGlvbnMgZm9yIGNoYW5nZXMgdG8gaXRlbXMgc3ViLXByb3BlcnRpZXMgd2lsbCBiZSBmb3J3YXJkZWQgdG8gdGVtcGxhdGUKICAgKiBpbnN0YW5jZXMsIHdoaWNoIHdpbGwgdXBkYXRlIHZpYSB0aGUgbm9ybWFsIHN0cnVjdHVyZWQgZGF0YSBub3RpZmljYXRpb24gc3lzdGVtLgogICAqCiAgICogTXV0YXRpb25zIHRvIHRoZSBgaXRlbXNgIGFycmF5IGl0c2VsZiBzaG91bGQgYmUgbWFkZSB1c2luZyB0aGUgQXJyYXkKICAgKiBtdXRhdGlvbiBBUEkncyBvbiBgUG9seW1lci5CYXNlYCAoYHB1c2hgLCBgcG9wYCwgYHNwbGljZWAsIGBzaGlmdGAsCiAgICogYHVuc2hpZnRgKSwgYW5kIHRlbXBsYXRlIGluc3RhbmNlcyB3aWxsIGJlIGtlcHQgaW4gc3luYyB3aXRoIHRoZSBkYXRhIGluIHRoZQogICAqIGFycmF5LgogICAqCiAgICogRXZlbnRzIGNhdWdodCBieSBldmVudCBoYW5kbGVycyB3aXRoaW4gdGhlIGBkb20tcmVwZWF0YCB0ZW1wbGF0ZSB3aWxsIGJlCiAgICogZGVjb3JhdGVkIHdpdGggYSBgbW9kZWxgIHByb3BlcnR5LCB3aGljaCByZXByZXNlbnRzIHRoZSBiaW5kaW5nIHNjb3BlIGZvcgogICAqIGVhY2ggdGVtcGxhdGUgaW5zdGFuY2UuICBUaGUgbW9kZWwgaXMgYW4gaW5zdGFuY2Ugb2YgUG9seW1lci5CYXNlLCBhbmQgc2hvdWxkCiAgICogYmUgdXNlZCB0byBtYW5pcHVsYXRlIGRhdGEgb24gdGhlIGluc3RhbmNlLCBmb3IgZXhhbXBsZQogICAqIGBldmVudC5tb2RlbC5zZXQoJ2l0ZW0uY2hlY2tlZCcsIHRydWUpO2AuCiAgICoKICAgKiBBbHRlcm5hdGl2ZWx5LCB0aGUgbW9kZWwgZm9yIGEgdGVtcGxhdGUgaW5zdGFuY2UgZm9yIGFuIGVsZW1lbnQgc3RhbXBlZCBieQogICAqIGEgYGRvbS1yZXBlYXRgIGNhbiBiZSBvYnRhaW5lZCB1c2luZyB0aGUgYG1vZGVsRm9yRWxlbWVudGAgQVBJIG9uIHRoZQogICAqIGBkb20tcmVwZWF0YCB0aGF0IHN0YW1wZWQgaXQsIGZvciBleGFtcGxlCiAgICogYHRoaXMuJC5kb21SZXBlYXQubW9kZWxGb3JFbGVtZW50KGV2ZW50LnRhcmdldCkuc2V0KCdpdGVtLmNoZWNrZWQnLCB0cnVlKTtgLgogICAqIFRoaXMgbWF5IGJlIHVzZWZ1bCBmb3IgbWFuaXB1bGF0aW5nIGluc3RhbmNlIGRhdGEgb2YgZXZlbnQgdGFyZ2V0cyBvYnRhaW5lZAogICAqIGJ5IGV2ZW50IGhhbmRsZXJzIG9uIHBhcmVudHMgb2YgdGhlIGBkb20tcmVwZWF0YCAoZXZlbnQgZGVsZWdhdGlvbikuCiAgICoKICAgKiBBIHZpZXctc3BlY2lmaWMgZmlsdGVyL3NvcnQgbWF5IGJlIGFwcGxpZWQgdG8gZWFjaCBgZG9tLXJlcGVhdGAgYnkgc3VwcGx5aW5nIGEKICAgKiBgZmlsdGVyYCBhbmQvb3IgYHNvcnRgIHByb3BlcnR5LiAgVGhpcyBtYXkgYmUgYSBzdHJpbmcgdGhhdCBuYW1lcyBhIGZ1bmN0aW9uIG9uCiAgICogdGhlIGhvc3QsIG9yIGEgZnVuY3Rpb24gbWF5IGJlIGFzc2lnbmVkIHRvIHRoZSBwcm9wZXJ0eSBkaXJlY3RseS4gIFRoZSBmdW5jdGlvbnMKICAgKiBzaG91bGQgaW1wbGVtZW50ZWQgZm9sbG93aW5nIHRoZSBzdGFuZGFyZCBgQXJyYXlgIGZpbHRlci9zb3J0IEFQSS4KICAgKgogICAqIEluIG9yZGVyIHRvIHJlLXJ1biB0aGUgZmlsdGVyIG9yIHNvcnQgZnVuY3Rpb25zIGJhc2VkIG9uIGNoYW5nZXMgdG8gc3ViLWZpZWxkcwogICAqIG9mIGBpdGVtc2AsIHRoZSBgb2JzZXJ2ZWAgcHJvcGVydHkgbWF5IGJlIHNldCBhcyBhIHNwYWNlLXNlcGFyYXRlZCBsaXN0IG9mCiAgICogYGl0ZW1gIHN1Yi1maWVsZHMgdGhhdCBzaG91bGQgY2F1c2UgYSByZS1maWx0ZXIvc29ydCB3aGVuIG1vZGlmaWVkLiAgSWYKICAgKiB0aGUgZmlsdGVyIG9yIHNvcnQgZnVuY3Rpb24gZGVwZW5kcyBvbiBwcm9wZXJ0aWVzIG5vdCBjb250YWluZWQgaW4gYGl0ZW1zYCwKICAgKiB0aGUgdXNlciBzaG91bGQgb2JzZXJ2ZSBjaGFuZ2VzIHRvIHRob3NlIHByb3BlcnRpZXMgYW5kIGNhbGwgYHJlbmRlcmAgdG8gdXBkYXRlCiAgICogdGhlIHZpZXcgYmFzZWQgb24gdGhlIGRlcGVuZGVuY3kgY2hhbmdlLgogICAqCiAgICogRm9yIGV4YW1wbGUsIGZvciBhbiBgZG9tLXJlcGVhdGAgd2l0aCBhIGZpbHRlciBvZiB0aGUgZm9sbG93aW5nOgogICAqCiAgICogYGBganMKICAgKiBpc0VuZ2luZWVyKGl0ZW0pIHsKICAgKiAgIHJldHVybiBpdGVtLnR5cGUgPT0gJ2VuZ2luZWVyJyB8fCBpdGVtLm1hbmFnZXIudHlwZSA9PSAnZW5naW5lZXInOwogICAqIH0KICAgKiBgYGAKICAgKgogICAqIFRoZW4gdGhlIGBvYnNlcnZlYCBwcm9wZXJ0eSBzaG91bGQgYmUgY29uZmlndXJlZCBhcyBmb2xsb3dzOgogICAqCiAgICogYGBgaHRtbAogICAqIDxkb20tcmVwZWF0IGl0ZW1zPSJ7e2VtcGxveWVlc319IiBmaWx0ZXI9ImlzRW5naW5lZXIiIG9ic2VydmU9InR5cGUgbWFuYWdlci50eXBlIj4KICAgKiBgYGAKICAgKgogICAqIEBjdXN0b21FbGVtZW50CiAgICogQHBvbHltZXIKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBleHRlbmRzIHtkb21SZXBlYXRCYXNlfQogICAqIEBhcHBsaWVzTWl4aW4gUG9seW1lci5PcHRpb25hbE11dGFibGVEYXRhCiAgICogQHN1bW1hcnkgQ3VzdG9tIGVsZW1lbnQgZm9yIHN0YW1waW5nIGluc3RhbmNlIG9mIGEgdGVtcGxhdGUgYm91bmQgdG8KICAgKiAgIGl0ZW1zIGluIGFuIGFycmF5LgogICAqLwogIGNsYXNzIERvbVJlcGVhdCBleHRlbmRzIGRvbVJlcGVhdEJhc2UgewoKICAgIC8vIE5vdCBuZWVkZWQgdG8gZmluZCB0ZW1wbGF0ZTsgY2FuIGJlIHJlbW92ZWQgb25jZSB0aGUgYW5hbHl6ZXIKICAgIC8vIGNhbiBmaW5kIHRoZSB0YWcgbmFtZSBmcm9tIGN1c3RvbUVsZW1lbnRzLmRlZmluZSBjYWxsCiAgICBzdGF0aWMgZ2V0IGlzKCkgeyByZXR1cm4gJ2RvbS1yZXBlYXQnOyB9CgogICAgc3RhdGljIGdldCB0ZW1wbGF0ZSgpIHsgcmV0dXJuIG51bGw7IH0KCiAgICBzdGF0aWMgZ2V0IHByb3BlcnRpZXMoKSB7CgogICAgICAvKioKICAgICAgICogRmlyZWQgd2hlbmV2ZXIgRE9NIGlzIGFkZGVkIG9yIHJlbW92ZWQgYnkgdGhpcyB0ZW1wbGF0ZSAoYnkKICAgICAgICogZGVmYXVsdCwgcmVuZGVyaW5nIG9jY3VycyBsYXppbHkpLiAgVG8gZm9yY2UgaW1tZWRpYXRlIHJlbmRlcmluZywgY2FsbAogICAgICAgKiBgcmVuZGVyYC4KICAgICAgICoKICAgICAgICogQGV2ZW50IGRvbS1jaGFuZ2UKICAgICAgICovCiAgICAgIHJldHVybiB7CgogICAgICAgIC8qKgogICAgICAgICAqIEFuIGFycmF5IGNvbnRhaW5pbmcgaXRlbXMgZGV0ZXJtaW5pbmcgaG93IG1hbnkgaW5zdGFuY2VzIG9mIHRoZSB0ZW1wbGF0ZQogICAgICAgICAqIHRvIHN0YW1wIGFuZCB0aGF0IHRoYXQgZWFjaCB0ZW1wbGF0ZSBpbnN0YW5jZSBzaG91bGQgYmluZCB0by4KICAgICAgICAgKi8KICAgICAgICBpdGVtczogewogICAgICAgICAgdHlwZTogQXJyYXkKICAgICAgICB9LAoKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgbmFtZSBvZiB0aGUgdmFyaWFibGUgdG8gYWRkIHRvIHRoZSBiaW5kaW5nIHNjb3BlIGZvciB0aGUgYXJyYXkKICAgICAgICAgKiBlbGVtZW50IGFzc29jaWF0ZWQgd2l0aCBhIGdpdmVuIHRlbXBsYXRlIGluc3RhbmNlLgogICAgICAgICAqLwogICAgICAgIGFzOiB7CiAgICAgICAgICB0eXBlOiBTdHJpbmcsCiAgICAgICAgICB2YWx1ZTogJ2l0ZW0nCiAgICAgICAgfSwKCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlIHRvIGFkZCB0byB0aGUgYmluZGluZyBzY29wZSB3aXRoIHRoZSBpbmRleAogICAgICAgICAqIG9mIHRoZSBpbnN0YW5jZSBpbiB0aGUgc29ydGVkIGFuZCBmaWx0ZXJlZCBsaXN0IG9mIHJlbmRlcmVkIGl0ZW1zLgogICAgICAgICAqIE5vdGUsIGZvciB0aGUgaW5kZXggaW4gdGhlIGB0aGlzLml0ZW1zYCBhcnJheSwgdXNlIHRoZSB2YWx1ZSBvZiB0aGUKICAgICAgICAgKiBgaXRlbXNJbmRleEFzYCBwcm9wZXJ0eS4KICAgICAgICAgKi8KICAgICAgICBpbmRleEFzOiB7CiAgICAgICAgICB0eXBlOiBTdHJpbmcsCiAgICAgICAgICB2YWx1ZTogJ2luZGV4JwogICAgICAgIH0sCgogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSB0byBhZGQgdG8gdGhlIGJpbmRpbmcgc2NvcGUgd2l0aCB0aGUgaW5kZXgKICAgICAgICAgKiBvZiB0aGUgaW5zdGFuY2UgaW4gdGhlIGB0aGlzLml0ZW1zYCBhcnJheS4gTm90ZSwgZm9yIHRoZSBpbmRleCBvZgogICAgICAgICAqIHRoaXMgaW5zdGFuY2UgaW4gdGhlIHNvcnRlZCBhbmQgZmlsdGVyZWQgbGlzdCBvZiByZW5kZXJlZCBpdGVtcywKICAgICAgICAgKiB1c2UgdGhlIHZhbHVlIG9mIHRoZSBgaW5kZXhBc2AgcHJvcGVydHkuCiAgICAgICAgICovCiAgICAgICAgaXRlbXNJbmRleEFzOiB7CiAgICAgICAgICB0eXBlOiBTdHJpbmcsCiAgICAgICAgICB2YWx1ZTogJ2l0ZW1zSW5kZXgnCiAgICAgICAgfSwKCiAgICAgICAgLyoqCiAgICAgICAgICogQSBmdW5jdGlvbiB0aGF0IHNob3VsZCBkZXRlcm1pbmUgdGhlIHNvcnQgb3JkZXIgb2YgdGhlIGl0ZW1zLiAgVGhpcwogICAgICAgICAqIHByb3BlcnR5IHNob3VsZCBlaXRoZXIgYmUgcHJvdmlkZWQgYXMgYSBzdHJpbmcsIGluZGljYXRpbmcgYSBtZXRob2QKICAgICAgICAgKiBuYW1lIG9uIHRoZSBlbGVtZW50J3MgaG9zdCwgb3IgZWxzZSBiZSBhbiBhY3R1YWwgZnVuY3Rpb24uICBUaGUKICAgICAgICAgKiBmdW5jdGlvbiBzaG91bGQgbWF0Y2ggdGhlIHNvcnQgZnVuY3Rpb24gcGFzc2VkIHRvIGBBcnJheS5zb3J0YC4KICAgICAgICAgKiBVc2luZyBhIHNvcnQgZnVuY3Rpb24gaGFzIG5vIGVmZmVjdCBvbiB0aGUgdW5kZXJseWluZyBgaXRlbXNgIGFycmF5LgogICAgICAgICAqLwogICAgICAgIHNvcnQ6IHsKICAgICAgICAgIHR5cGU6IEZ1bmN0aW9uLAogICAgICAgICAgb2JzZXJ2ZXI6ICdfX3NvcnRDaGFuZ2VkJwogICAgICAgIH0sCgogICAgICAgIC8qKgogICAgICAgICAqIEEgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCB0byBmaWx0ZXIgaXRlbXMgb3V0IG9mIHRoZSB2aWV3LiAgVGhpcwogICAgICAgICAqIHByb3BlcnR5IHNob3VsZCBlaXRoZXIgYmUgcHJvdmlkZWQgYXMgYSBzdHJpbmcsIGluZGljYXRpbmcgYSBtZXRob2QKICAgICAgICAgKiBuYW1lIG9uIHRoZSBlbGVtZW50J3MgaG9zdCwgb3IgZWxzZSBiZSBhbiBhY3R1YWwgZnVuY3Rpb24uICBUaGUKICAgICAgICAgKiBmdW5jdGlvbiBzaG91bGQgbWF0Y2ggdGhlIHNvcnQgZnVuY3Rpb24gcGFzc2VkIHRvIGBBcnJheS5maWx0ZXJgLgogICAgICAgICAqIFVzaW5nIGEgZmlsdGVyIGZ1bmN0aW9uIGhhcyBubyBlZmZlY3Qgb24gdGhlIHVuZGVybHlpbmcgYGl0ZW1zYCBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBmaWx0ZXI6IHsKICAgICAgICAgIHR5cGU6IEZ1bmN0aW9uLAogICAgICAgICAgb2JzZXJ2ZXI6ICdfX2ZpbHRlckNoYW5nZWQnCiAgICAgICAgfSwKCiAgICAgICAgLyoqCiAgICAgICAgICogV2hlbiB1c2luZyBhIGBmaWx0ZXJgIG9yIGBzb3J0YCBmdW5jdGlvbiwgdGhlIGBvYnNlcnZlYCBwcm9wZXJ0eQogICAgICAgICAqIHNob3VsZCBiZSBzZXQgdG8gYSBzcGFjZS1zZXBhcmF0ZWQgbGlzdCBvZiB0aGUgbmFtZXMgb2YgaXRlbQogICAgICAgICAqIHN1Yi1maWVsZHMgdGhhdCBzaG91bGQgdHJpZ2dlciBhIHJlLXNvcnQgb3IgcmUtZmlsdGVyIHdoZW4gY2hhbmdlZC4KICAgICAgICAgKiBUaGVzZSBzaG91bGQgZ2VuZXJhbGx5IGJlIGZpZWxkcyBvZiBgaXRlbWAgdGhhdCB0aGUgc29ydCBvciBmaWx0ZXIKICAgICAgICAgKiBmdW5jdGlvbiBkZXBlbmRzIG9uLgogICAgICAgICAqLwogICAgICAgIG9ic2VydmU6IHsKICAgICAgICAgIHR5cGU6IFN0cmluZywKICAgICAgICAgIG9ic2VydmVyOiAnX19vYnNlcnZlQ2hhbmdlZCcKICAgICAgICB9LAoKICAgICAgICAvKioKICAgICAgICAgKiBXaGVuIHVzaW5nIGEgYGZpbHRlcmAgb3IgYHNvcnRgIGZ1bmN0aW9uLCB0aGUgYGRlbGF5YCBwcm9wZXJ0eQogICAgICAgICAqIGRldGVybWluZXMgYSBkZWJvdW5jZSB0aW1lIGluIG1zIGFmdGVyIGEgY2hhbmdlIHRvIG9ic2VydmVkIGl0ZW0KICAgICAgICAgKiBwcm9wZXJ0aWVzIHRoYXQgbXVzdCBwYXNzIGJlZm9yZSB0aGUgZmlsdGVyIG9yIHNvcnQgaXMgcmUtcnVuLgogICAgICAgICAqIFRoaXMgaXMgdXNlZnVsIGluIHJhdGUtbGltaXRpbmcgc2h1ZmZsaW5nIG9mIHRoZSB2aWV3IHdoZW4KICAgICAgICAgKiBpdGVtIGNoYW5nZXMgbWF5IGJlIGZyZXF1ZW50LgogICAgICAgICAqLwogICAgICAgIGRlbGF5OiBOdW1iZXIsCgogICAgICAgIC8qKgogICAgICAgICAqIENvdW50IG9mIGN1cnJlbnRseSByZW5kZXJlZCBpdGVtcyBhZnRlciBgZmlsdGVyYCAoaWYgYW55KSBoYXMgYmVlbiBhcHBsaWVkLgogICAgICAgICAqIElmICJjaHVua2luZyBtb2RlIiBpcyBlbmFibGVkLCBgcmVuZGVyZWRJdGVtQ291bnRgIGlzIHVwZGF0ZWQgZWFjaCB0aW1lIGEKICAgICAgICAgKiBzZXQgb2YgdGVtcGxhdGUgaW5zdGFuY2VzIGlzIHJlbmRlcmVkLgogICAgICAgICAqCiAgICAgICAgICovCiAgICAgICAgcmVuZGVyZWRJdGVtQ291bnQ6IHsKICAgICAgICAgIHR5cGU6IE51bWJlciwKICAgICAgICAgIG5vdGlmeTogdHJ1ZSwKICAgICAgICAgIHJlYWRPbmx5OiB0cnVlCiAgICAgICAgfSwKCiAgICAgICAgLyoqCiAgICAgICAgICogRGVmaW5lcyBhbiBpbml0aWFsIGNvdW50IG9mIHRlbXBsYXRlIGluc3RhbmNlcyB0byByZW5kZXIgYWZ0ZXIgc2V0dGluZwogICAgICAgICAqIHRoZSBgaXRlbXNgIGFycmF5LCBiZWZvcmUgdGhlIG5leHQgcGFpbnQsIGFuZCBwdXRzIHRoZSBgZG9tLXJlcGVhdGAKICAgICAgICAgKiBpbnRvICJjaHVua2luZyBtb2RlIi4gIFRoZSByZW1haW5pbmcgaXRlbXMgd2lsbCBiZSBjcmVhdGVkIGFuZCByZW5kZXJlZAogICAgICAgICAqIGluY3JlbWVudGFsbHkgYXQgZWFjaCBhbmltYXRpb24gZnJhbWUgdGhlcm9mIHVudGlsIGFsbCBpbnN0YW5jZXMgaGF2ZQogICAgICAgICAqIGJlZW4gcmVuZGVyZWQuCiAgICAgICAgICovCiAgICAgICAgaW5pdGlhbENvdW50OiB7CiAgICAgICAgICB0eXBlOiBOdW1iZXIsCiAgICAgICAgICBvYnNlcnZlcjogJ19faW5pdGlhbGl6ZUNodW5raW5nJwogICAgICAgIH0sCgogICAgICAgIC8qKgogICAgICAgICAqIFdoZW4gYGluaXRpYWxDb3VudGAgaXMgdXNlZCwgdGhpcyBwcm9wZXJ0eSBkZWZpbmVzIGEgZnJhbWUgcmF0ZSAoaW4KICAgICAgICAgKiBmcHMpIHRvIHRhcmdldCBieSB0aHJvdHRsaW5nIHRoZSBudW1iZXIgb2YgaW5zdGFuY2VzIHJlbmRlcmVkIGVhY2gKICAgICAgICAgKiBmcmFtZSB0byBub3QgZXhjZWVkIHRoZSBidWRnZXQgZm9yIHRoZSB0YXJnZXQgZnJhbWUgcmF0ZS4gIFRoZQogICAgICAgICAqIGZyYW1lcmF0ZSBpcyBlZmZlY3RpdmVseSB0aGUgbnVtYmVyIG9mIGByZXF1ZXN0QW5pbWF0aW9uRnJhbWVgcyB0aGF0CiAgICAgICAgICogaXQgdHJpZXMgdG8gYWxsb3cgdG8gYWN0dWFsbHkgZmlyZSBpbiBhIGdpdmVuIHNlY29uZC4gSXQgZG9lcyB0aGlzCiAgICAgICAgICogYnkgbWVhc3VyaW5nIHRoZSB0aW1lIGJldHdlZW4gYHJBRmBzIGFuZCBjb250aW51b3VzbHkgYWRqdXN0aW5nIHRoZQogICAgICAgICAqIG51bWJlciBvZiBpdGVtcyBjcmVhdGVkIGVhY2ggYHJBRmAgdG8gbWFpbnRhaW4gdGhlIHRhcmdldCBmcmFtZXJhdGUuCiAgICAgICAgICogU2V0dGluZyB0aGlzIHRvIGEgaGlnaGVyIG51bWJlciBhbGxvd3MgbG93ZXIgbGF0ZW5jeSBhbmQgaGlnaGVyCiAgICAgICAgICogdGhyb3VnaHB1dCBmb3IgZXZlbnQgaGFuZGxlcnMgYW5kIG90aGVyIHRhc2tzLCBidXQgcmVzdWx0cyBpbiBhCiAgICAgICAgICogbG9uZ2VyIHRpbWUgZm9yIHRoZSByZW1haW5pbmcgaXRlbXMgdG8gY29tcGxldGUgcmVuZGVyaW5nLgogICAgICAgICAqLwogICAgICAgIHRhcmdldEZyYW1lcmF0ZTogewogICAgICAgICAgdHlwZTogTnVtYmVyLAogICAgICAgICAgdmFsdWU6IDIwCiAgICAgICAgfSwKCiAgICAgICAgX3RhcmdldEZyYW1lVGltZTogewogICAgICAgICAgdHlwZTogTnVtYmVyLAogICAgICAgICAgY29tcHV0ZWQ6ICdfX2NvbXB1dGVGcmFtZVRpbWUodGFyZ2V0RnJhbWVyYXRlKScKICAgICAgICB9CgogICAgICB9OwoKICAgIH0KCiAgICBzdGF0aWMgZ2V0IG9ic2VydmVycygpIHsKICAgICAgcmV0dXJuIFsgJ19faXRlbXNDaGFuZ2VkKGl0ZW1zLiopJyBdOwogICAgfQoKICAgIGNvbnN0cnVjdG9yKCkgewogICAgICBzdXBlcigpOwogICAgICB0aGlzLl9faW5zdGFuY2VzID0gW107CiAgICAgIHRoaXMuX19saW1pdCA9IEluZmluaXR5OwogICAgICB0aGlzLl9fcG9vbCA9IFtdOwogICAgICB0aGlzLl9fcmVuZGVyRGVib3VuY2VyID0gbnVsbDsKICAgICAgdGhpcy5fX2l0ZW1zSWR4VG9JbnN0SWR4ID0ge307CiAgICAgIHRoaXMuX19jaHVua0NvdW50ID0gbnVsbDsKICAgICAgdGhpcy5fX2xhc3RDaHVua1RpbWUgPSBudWxsOwogICAgICB0aGlzLl9fc29ydEZuID0gbnVsbDsKICAgICAgdGhpcy5fX2ZpbHRlckZuID0gbnVsbDsKICAgICAgdGhpcy5fX29ic2VydmVQYXRocyA9IG51bGw7CiAgICAgIHRoaXMuX19jdG9yID0gbnVsbDsKICAgICAgdGhpcy5fX2lzRGV0YWNoZWQgPSB0cnVlOwogICAgICB0aGlzLnRlbXBsYXRlID0gbnVsbDsKICAgIH0KCiAgICAvKioKICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIGRpc2Nvbm5lY3RlZENhbGxiYWNrKCkgewogICAgICBzdXBlci5kaXNjb25uZWN0ZWRDYWxsYmFjaygpOwogICAgICB0aGlzLl9faXNEZXRhY2hlZCA9IHRydWU7CiAgICAgIGZvciAobGV0IGk9MDsgaTx0aGlzLl9faW5zdGFuY2VzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgdGhpcy5fX2RldGFjaEluc3RhbmNlKGkpOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBjb25uZWN0ZWRDYWxsYmFjaygpIHsKICAgICAgc3VwZXIuY29ubmVjdGVkQ2FsbGJhY2soKTsKICAgICAgdGhpcy5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnOwogICAgICAvLyBvbmx5IHBlcmZvcm0gYXR0YWNobWVudCBpZiB0aGUgZWxlbWVudCB3YXMgcHJldmlvdXNseSBkZXRhY2hlZC4KICAgICAgaWYgKHRoaXMuX19pc0RldGFjaGVkKSB7CiAgICAgICAgdGhpcy5fX2lzRGV0YWNoZWQgPSBmYWxzZTsKICAgICAgICBsZXQgcGFyZW50ID0gdGhpcy5wYXJlbnROb2RlOwogICAgICAgIGZvciAobGV0IGk9MDsgaTx0aGlzLl9faW5zdGFuY2VzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICB0aGlzLl9fYXR0YWNoSW5zdGFuY2UoaSwgcGFyZW50KTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KCiAgICBfX2Vuc3VyZVRlbXBsYXRpemVkKCkgewogICAgICAvLyBUZW1wbGF0aXppbmcgKGdlbmVyYXRpbmcgdGhlIGluc3RhbmNlIGNvbnN0cnVjdG9yKSBuZWVkcyB0byB3YWl0CiAgICAgIC8vIHVudGlsIHJlYWR5LCBzaW5jZSB3b24ndCBoYXZlIGl0cyB0ZW1wbGF0ZSBjb250ZW50IGhhbmRlZCBiYWNrIHRvCiAgICAgIC8vIGl0IHVudGlsIHRoZW4KICAgICAgaWYgKCF0aGlzLl9fY3RvcikgewogICAgICAgIGxldCB0ZW1wbGF0ZSA9IHRoaXMudGVtcGxhdGUgPSAvKiogQHR5cGUge0hUTUxUZW1wbGF0ZUVsZW1lbnR9ICovKHRoaXMucXVlcnlTZWxlY3RvcigndGVtcGxhdGUnKSk7CiAgICAgICAgaWYgKCF0ZW1wbGF0ZSkgewogICAgICAgICAgLy8gLy8gV2FpdCB1bnRpbCBjaGlsZExpc3QgY2hhbmdlcyBhbmQgdGVtcGxhdGUgc2hvdWxkIGJlIHRoZXJlIGJ5IHRoZW4KICAgICAgICAgIGxldCBvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKCgpID0+IHsKICAgICAgICAgICAgaWYgKHRoaXMucXVlcnlTZWxlY3RvcigndGVtcGxhdGUnKSkgewogICAgICAgICAgICAgIG9ic2VydmVyLmRpc2Nvbm5lY3QoKTsKICAgICAgICAgICAgICB0aGlzLl9fcmVuZGVyKCk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdkb20tcmVwZWF0IHJlcXVpcmVzIGEgPHRlbXBsYXRlPiBjaGlsZCcpOwogICAgICAgICAgICB9CiAgICAgICAgICB9KTsKICAgICAgICAgIG9ic2VydmVyLm9ic2VydmUodGhpcywge2NoaWxkTGlzdDogdHJ1ZX0pOwogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICAvLyBUZW1wbGF0ZSBpbnN0YW5jZSBwcm9wcyB0aGF0IHNob3VsZCBiZSBleGNsdWRlZCBmcm9tIGZvcndhcmRpbmcKICAgICAgICBsZXQgaW5zdGFuY2VQcm9wcyA9IHt9OwogICAgICAgIGluc3RhbmNlUHJvcHNbdGhpcy5hc10gPSB0cnVlOwogICAgICAgIGluc3RhbmNlUHJvcHNbdGhpcy5pbmRleEFzXSA9IHRydWU7CiAgICAgICAgaW5zdGFuY2VQcm9wc1t0aGlzLml0ZW1zSW5kZXhBc10gPSB0cnVlOwogICAgICAgIHRoaXMuX19jdG9yID0gUG9seW1lci5UZW1wbGF0aXplLnRlbXBsYXRpemUodGVtcGxhdGUsIHRoaXMsIHsKICAgICAgICAgIG11dGFibGVEYXRhOiB0aGlzLm11dGFibGVEYXRhLAogICAgICAgICAgcGFyZW50TW9kZWw6IHRydWUsCiAgICAgICAgICBpbnN0YW5jZVByb3BzOiBpbnN0YW5jZVByb3BzLAogICAgICAgICAgLyoqCiAgICAgICAgICAgKiBAdGhpcyB7dGhpc30KICAgICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wIFByb3BlcnR5IHRvIHNldAogICAgICAgICAgICogQHBhcmFtIHsqfSB2YWx1ZSBWYWx1ZSB0byBzZXQgcHJvcGVydHkgdG8KICAgICAgICAgICAqLwogICAgICAgICAgZm9yd2FyZEhvc3RQcm9wOiBmdW5jdGlvbihwcm9wLCB2YWx1ZSkgewogICAgICAgICAgICBsZXQgaSQgPSB0aGlzLl9faW5zdGFuY2VzOwogICAgICAgICAgICBmb3IgKGxldCBpPTAsIGluc3Q7IChpPGkkLmxlbmd0aCkgJiYgKGluc3Q9aSRbaV0pOyBpKyspIHsKICAgICAgICAgICAgICBpbnN0LmZvcndhcmRIb3N0UHJvcChwcm9wLCB2YWx1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0sCiAgICAgICAgICAvKioKICAgICAgICAgICAqIEB0aGlzIHt0aGlzfQogICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGluc3QgSW5zdGFuY2UgdG8gbm90aWZ5CiAgICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcCBQcm9wZXJ0eSB0byBub3RpZnkKICAgICAgICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVmFsdWUgdG8gbm90aWZ5CiAgICAgICAgICAgKi8KICAgICAgICAgIG5vdGlmeUluc3RhbmNlUHJvcDogZnVuY3Rpb24oaW5zdCwgcHJvcCwgdmFsdWUpIHsKICAgICAgICAgICAgaWYgKFBvbHltZXIuUGF0aC5tYXRjaGVzKHRoaXMuYXMsIHByb3ApKSB7CiAgICAgICAgICAgICAgbGV0IGlkeCA9IGluc3RbdGhpcy5pdGVtc0luZGV4QXNdOwogICAgICAgICAgICAgIGlmIChwcm9wID09IHRoaXMuYXMpIHsKICAgICAgICAgICAgICAgIHRoaXMuaXRlbXNbaWR4XSA9IHZhbHVlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBsZXQgcGF0aCA9IFBvbHltZXIuUGF0aC50cmFuc2xhdGUodGhpcy5hcywgJ2l0ZW1zLicgKyBpZHgsIHByb3ApOwogICAgICAgICAgICAgIHRoaXMubm90aWZ5UGF0aChwYXRoLCB2YWx1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9KTsKICAgICAgfQogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBfX2dldE1ldGhvZEhvc3QoKSB7CiAgICAgIC8vIFRlY2huaWNhbGx5IHRoaXMgc2hvdWxkIGJlIHRoZSBvd25lciBvZiB0aGUgb3V0ZXJtb3N0IHRlbXBsYXRlLgogICAgICAvLyBJbiBzaGFkb3cgZG9tLCB0aGlzIGlzIGFsd2F5cyBnZXRSb290Tm9kZSgpLmhvc3QsIGJ1dCB3ZSBjYW4KICAgICAgLy8gYXBwcm94aW1hdGUgdGhpcyB2aWEgY29vcGVyYXRpb24gd2l0aCBvdXIgZGF0YUhvc3QgYWx3YXlzIHNldHRpbmcKICAgICAgLy8gYF9tZXRob2RIb3N0YCBhcyBsb25nIGFzIHRoZXJlIHdlcmUgYmluZGluZ3MgKG9yIGlkJ3MpIG9uIHRoaXMKICAgICAgLy8gaW5zdGFuY2UgY2F1c2luZyBpdCB0byBnZXQgYSBkYXRhSG9zdC4KICAgICAgcmV0dXJuIHRoaXMuX19kYXRhSG9zdC5fbWV0aG9kSG9zdCB8fCB0aGlzLl9fZGF0YUhvc3Q7CiAgICB9CgogICAgX19mdW5jdGlvbkZyb21Qcm9wZXJ0eVZhbHVlKGZ1bmN0aW9uT3JNZXRob2ROYW1lKSB7CiAgICAgIGlmICh0eXBlb2YgZnVuY3Rpb25Pck1ldGhvZE5hbWUgPT09ICdzdHJpbmcnKSB7CiAgICAgICAgbGV0IG1ldGhvZE5hbWUgPSBmdW5jdGlvbk9yTWV0aG9kTmFtZTsKICAgICAgICBsZXQgb2JqID0gdGhpcy5fX2dldE1ldGhvZEhvc3QoKTsKICAgICAgICByZXR1cm4gZnVuY3Rpb24oKSB7IHJldHVybiBvYmpbbWV0aG9kTmFtZV0uYXBwbHkob2JqLCBhcmd1bWVudHMpOyB9OwogICAgICB9CgogICAgICByZXR1cm4gZnVuY3Rpb25Pck1ldGhvZE5hbWU7CiAgICB9CgogICAgX19zb3J0Q2hhbmdlZChzb3J0KSB7CiAgICAgIHRoaXMuX19zb3J0Rm4gPSB0aGlzLl9fZnVuY3Rpb25Gcm9tUHJvcGVydHlWYWx1ZShzb3J0KTsKICAgICAgaWYgKHRoaXMuaXRlbXMpIHsgdGhpcy5fX2RlYm91bmNlUmVuZGVyKHRoaXMuX19yZW5kZXIpOyB9CiAgICB9CgogICAgX19maWx0ZXJDaGFuZ2VkKGZpbHRlcikgewogICAgICB0aGlzLl9fZmlsdGVyRm4gPSB0aGlzLl9fZnVuY3Rpb25Gcm9tUHJvcGVydHlWYWx1ZShmaWx0ZXIpOwogICAgICBpZiAodGhpcy5pdGVtcykgeyB0aGlzLl9fZGVib3VuY2VSZW5kZXIodGhpcy5fX3JlbmRlcik7IH0KICAgIH0KCiAgICBfX2NvbXB1dGVGcmFtZVRpbWUocmF0ZSkgewogICAgICByZXR1cm4gTWF0aC5jZWlsKDEwMDAvcmF0ZSk7CiAgICB9CgogICAgX19pbml0aWFsaXplQ2h1bmtpbmcoKSB7CiAgICAgIGlmICh0aGlzLmluaXRpYWxDb3VudCkgewogICAgICAgIHRoaXMuX19saW1pdCA9IHRoaXMuaW5pdGlhbENvdW50OwogICAgICAgIHRoaXMuX19jaHVua0NvdW50ID0gdGhpcy5pbml0aWFsQ291bnQ7CiAgICAgICAgdGhpcy5fX2xhc3RDaHVua1RpbWUgPSBwZXJmb3JtYW5jZS5ub3coKTsKICAgICAgfQogICAgfQoKICAgIF9fdHJ5UmVuZGVyQ2h1bmsoKSB7CiAgICAgIC8vIERlYm91bmNlZCBzbyB0aGF0IG11bHRpcGxlIGNhbGxzIHRocm91Z2ggYF9yZW5kZXJgIGJldHdlZW4gYW5pbWF0aW9uCiAgICAgIC8vIGZyYW1lcyBvbmx5IHF1ZXVlIG9uZSBuZXcgckFGIChlLmcuIGFycmF5IG11dGF0aW9uICYgY2h1bmtlZCByZW5kZXIpCiAgICAgIGlmICh0aGlzLml0ZW1zICYmIHRoaXMuX19saW1pdCA8IHRoaXMuaXRlbXMubGVuZ3RoKSB7CiAgICAgICAgdGhpcy5fX2RlYm91bmNlUmVuZGVyKHRoaXMuX19yZXF1ZXN0UmVuZGVyQ2h1bmspOwogICAgICB9CiAgICB9CgogICAgX19yZXF1ZXN0UmVuZGVyQ2h1bmsoKSB7CiAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKT0+dGhpcy5fX3JlbmRlckNodW5rKCkpOwogICAgfQoKICAgIF9fcmVuZGVyQ2h1bmsoKSB7CiAgICAgIC8vIFNpbXBsZSBhdXRvIGNodW5rU2l6ZSB0aHJvdHRsaW5nIGFsZ29yaXRobSBiYXNlZCBvbiBmZWVkYmFjayBsb29wOgogICAgICAvLyBtZWFzdXJlIGFjdHVhbCB0aW1lIGJldHdlZW4gZnJhbWVzIGFuZCBzY2FsZSBjaHVuayBjb3VudCBieSByYXRpbwogICAgICAvLyBvZiB0YXJnZXQvYWN0dWFsIGZyYW1lIHRpbWUKICAgICAgbGV0IGN1cnJDaHVua1RpbWUgPSBwZXJmb3JtYW5jZS5ub3coKTsKICAgICAgbGV0IHJhdGlvID0gdGhpcy5fdGFyZ2V0RnJhbWVUaW1lIC8gKGN1cnJDaHVua1RpbWUgLSB0aGlzLl9fbGFzdENodW5rVGltZSk7CiAgICAgIHRoaXMuX19jaHVua0NvdW50ID0gTWF0aC5yb3VuZCh0aGlzLl9fY2h1bmtDb3VudCAqIHJhdGlvKSB8fCAxOwogICAgICB0aGlzLl9fbGltaXQgKz0gdGhpcy5fX2NodW5rQ291bnQ7CiAgICAgIHRoaXMuX19sYXN0Q2h1bmtUaW1lID0gY3VyckNodW5rVGltZTsKICAgICAgdGhpcy5fX2RlYm91bmNlUmVuZGVyKHRoaXMuX19yZW5kZXIpOwogICAgfQoKICAgIF9fb2JzZXJ2ZUNoYW5nZWQoKSB7CiAgICAgIHRoaXMuX19vYnNlcnZlUGF0aHMgPSB0aGlzLm9ic2VydmUgJiYKICAgICAgICB0aGlzLm9ic2VydmUucmVwbGFjZSgnLionLCAnLicpLnNwbGl0KCcgJyk7CiAgICB9CgogICAgX19pdGVtc0NoYW5nZWQoY2hhbmdlKSB7CiAgICAgIGlmICh0aGlzLml0ZW1zICYmICFBcnJheS5pc0FycmF5KHRoaXMuaXRlbXMpKSB7CiAgICAgICAgY29uc29sZS53YXJuKCdkb20tcmVwZWF0IGV4cGVjdGVkIGFycmF5IGZvciBgaXRlbXNgLCBmb3VuZCcsIHRoaXMuaXRlbXMpOwogICAgICB9CiAgICAgIC8vIElmIHBhdGggd2FzIHRvIGFuIGl0ZW0gKGUuZy4gJ2l0ZW1zLjMnIG9yICdpdGVtcy4zLmZvbycpLCBmb3J3YXJkIHRoZQogICAgICAvLyBwYXRoIHRvIHRoYXQgaW5zdGFuY2Ugc3luY2hyb25vdXNseSAocmV0dXJucyBmYWxzZSBmb3Igbm9uLWl0ZW0gcGF0aHMpCiAgICAgIGlmICghdGhpcy5fX2hhbmRsZUl0ZW1QYXRoKGNoYW5nZS5wYXRoLCBjaGFuZ2UudmFsdWUpKSB7CiAgICAgICAgLy8gT3RoZXJ3aXNlLCB0aGUgYXJyYXkgd2FzIHJlc2V0ICgnaXRlbXMnKSBvciBzcGxpY2VkICgnaXRlbXMuc3BsaWNlcycpLAogICAgICAgIC8vIHNvIHF1ZXVlIGEgZnVsbCByZWZyZXNoCiAgICAgICAgdGhpcy5fX2luaXRpYWxpemVDaHVua2luZygpOwogICAgICAgIHRoaXMuX19kZWJvdW5jZVJlbmRlcih0aGlzLl9fcmVuZGVyKTsKICAgICAgfQogICAgfQoKICAgIF9faGFuZGxlT2JzZXJ2ZWRQYXRocyhwYXRoKSB7CiAgICAgIC8vIEhhbmRsZSBjYXNlcyB3aGVyZSBwYXRoIGNoYW5nZXMgc2hvdWxkIGNhdXNlIGEgcmUtc29ydC9maWx0ZXIKICAgICAgaWYgKHRoaXMuX19zb3J0Rm4gfHwgdGhpcy5fX2ZpbHRlckZuKSB7CiAgICAgICAgaWYgKCFwYXRoKSB7CiAgICAgICAgICAvLyBBbHdheXMgcmUtcmVuZGVyIGlmIHRoZSBpdGVtIGl0c2VsZiBjaGFuZ2VkCiAgICAgICAgICB0aGlzLl9fZGVib3VuY2VSZW5kZXIodGhpcy5fX3JlbmRlciwgdGhpcy5kZWxheSk7CiAgICAgICAgfSBlbHNlIGlmICh0aGlzLl9fb2JzZXJ2ZVBhdGhzKSB7CiAgICAgICAgICAvLyBPdGhlcndpc2UsIHJlLXJlbmRlciBpZiB0aGUgcGF0aCBjaGFuZ2VkIG1hdGNoZXMgYW4gb2JzZXJ2ZWQgcGF0aAogICAgICAgICAgbGV0IHBhdGhzID0gdGhpcy5fX29ic2VydmVQYXRoczsKICAgICAgICAgIGZvciAobGV0IGk9MDsgaTxwYXRocy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICBpZiAocGF0aC5pbmRleE9mKHBhdGhzW2ldKSA9PT0gMCkgewogICAgICAgICAgICAgIHRoaXMuX19kZWJvdW5jZVJlbmRlcih0aGlzLl9fcmVuZGVyLCB0aGlzLmRlbGF5KTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogQHBhcmFtIHtmdW5jdGlvbih0aGlzOkRvbVJlcGVhdCl9IGZuIEZ1bmN0aW9uIHRvIGRlYm91bmNlLgogICAgICogQHBhcmFtIHtudW1iZXI9fSBkZWxheSBEZWxheSBpbiBtcyB0byBkZWJvdW5jZSBieS4KICAgICAqLwogICAgX19kZWJvdW5jZVJlbmRlcihmbiwgZGVsYXkgPSAwKSB7CiAgICAgIHRoaXMuX19yZW5kZXJEZWJvdW5jZXIgPSBQb2x5bWVyLkRlYm91bmNlci5kZWJvdW5jZSgKICAgICAgICAgICAgdGhpcy5fX3JlbmRlckRlYm91bmNlcgogICAgICAgICAgLCBkZWxheSA+IDAgPyBQb2x5bWVyLkFzeW5jLnRpbWVPdXQuYWZ0ZXIoZGVsYXkpIDogUG9seW1lci5Bc3luYy5taWNyb1Rhc2sKICAgICAgICAgICwgZm4uYmluZCh0aGlzKSk7CiAgICAgIFBvbHltZXIuZW5xdWV1ZURlYm91bmNlcih0aGlzLl9fcmVuZGVyRGVib3VuY2VyKTsKICAgIH0KCiAgICAvKioKICAgICAqIEZvcmNlcyB0aGUgZWxlbWVudCB0byByZW5kZXIgaXRzIGNvbnRlbnQuIE5vcm1hbGx5IHJlbmRlcmluZyBpcwogICAgICogYXN5bmNocm9ub3VzIHRvIGEgcHJvdm9raW5nIGNoYW5nZS4gVGhpcyBpcyBkb25lIGZvciBlZmZpY2llbmN5IHNvCiAgICAgKiB0aGF0IG11bHRpcGxlIGNoYW5nZXMgdHJpZ2dlciBvbmx5IGEgc2luZ2xlIHJlbmRlci4gVGhlIHJlbmRlciBtZXRob2QKICAgICAqIHNob3VsZCBiZSBjYWxsZWQgaWYsIGZvciBleGFtcGxlLCB0ZW1wbGF0ZSByZW5kZXJpbmcgaXMgcmVxdWlyZWQgdG8KICAgICAqIHZhbGlkYXRlIGFwcGxpY2F0aW9uIHN0YXRlLgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgcmVuZGVyKCkgewogICAgICAvLyBRdWV1ZSB0aGlzIHJlcGVhdGVyLCB0aGVuIGZsdXNoIGFsbCBpbiBvcmRlcgogICAgICB0aGlzLl9fZGVib3VuY2VSZW5kZXIodGhpcy5fX3JlbmRlcik7CiAgICAgIFBvbHltZXIuZmx1c2goKTsKICAgIH0KCiAgICBfX3JlbmRlcigpIHsKICAgICAgaWYgKCF0aGlzLl9fZW5zdXJlVGVtcGxhdGl6ZWQoKSkgewogICAgICAgIC8vIE5vIHRlbXBsYXRlIGZvdW5kIHlldAogICAgICAgIHJldHVybjsKICAgICAgfQogICAgICB0aGlzLl9fYXBwbHlGdWxsUmVmcmVzaCgpOwogICAgICAvLyBSZXNldCB0aGUgcG9vbAogICAgICAvLyBUT0RPKGtzY2hhYWYpOiBSZXVzZSBwb29sIGFjcm9zcyB0dXJucyBhbmQgbmVzdGVkIHRlbXBsYXRlcwogICAgICAvLyBOb3cgdGhhdCBvYmplY3RzL2FycmF5cyBhcmUgcmUtZXZhbHVhdGVkIHdoZW4gc2V0LCB3ZSBjYW4gc2FmZWx5CiAgICAgIC8vIHJldXNlIHBvb2xlZCBpbnN0YW5jZXMgYWNyb3NzIHR1cm5zLCBob3dldmVyIHdlIHN0aWxsIG5lZWQgdG8gZGVjaWRlCiAgICAgIC8vIHNlbWFudGljcyByZWdhcmRpbmcgaG93IGxvbmcgdG8gaG9sZCwgaG93IG1hbnkgdG8gaG9sZCwgZXRjLgogICAgICB0aGlzLl9fcG9vbC5sZW5ndGggPSAwOwogICAgICAvLyBTZXQgcmVuZGVyZWQgaXRlbSBjb3VudAogICAgICB0aGlzLl9zZXRSZW5kZXJlZEl0ZW1Db3VudCh0aGlzLl9faW5zdGFuY2VzLmxlbmd0aCk7CiAgICAgIC8vIE5vdGlmeSB1c2VycwogICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KCdkb20tY2hhbmdlJywgewogICAgICAgIGJ1YmJsZXM6IHRydWUsCiAgICAgICAgY29tcG9zZWQ6IHRydWUKICAgICAgfSkpOwogICAgICAvLyBDaGVjayB0byBzZWUgaWYgd2UgbmVlZCB0byByZW5kZXIgbW9yZSBpdGVtcwogICAgICB0aGlzLl9fdHJ5UmVuZGVyQ2h1bmsoKTsKICAgIH0KCiAgICBfX2FwcGx5RnVsbFJlZnJlc2goKSB7CiAgICAgIGxldCBpdGVtcyA9IHRoaXMuaXRlbXMgfHwgW107CiAgICAgIGxldCBpc250SWR4VG9JdGVtc0lkeCA9IG5ldyBBcnJheShpdGVtcy5sZW5ndGgpOwogICAgICBmb3IgKGxldCBpPTA7IGk8aXRlbXMubGVuZ3RoOyBpKyspIHsKICAgICAgICBpc250SWR4VG9JdGVtc0lkeFtpXSA9IGk7CiAgICAgIH0KICAgICAgLy8gQXBwbHkgdXNlciBmaWx0ZXIKICAgICAgaWYgKHRoaXMuX19maWx0ZXJGbikgewogICAgICAgIGlzbnRJZHhUb0l0ZW1zSWR4ID0gaXNudElkeFRvSXRlbXNJZHguZmlsdGVyKChpLCBpZHgsIGFycmF5KSA9PgogICAgICAgICAgdGhpcy5fX2ZpbHRlckZuKGl0ZW1zW2ldLCBpZHgsIGFycmF5KSk7CiAgICAgIH0KICAgICAgLy8gQXBwbHkgdXNlciBzb3J0CiAgICAgIGlmICh0aGlzLl9fc29ydEZuKSB7CiAgICAgICAgaXNudElkeFRvSXRlbXNJZHguc29ydCgoYSwgYikgPT4gdGhpcy5fX3NvcnRGbihpdGVtc1thXSwgaXRlbXNbYl0pKTsKICAgICAgfQogICAgICAvLyBpdGVtcy0+aW5zdCBtYXAga2VwdCBmb3IgaXRlbSBwYXRoIGZvcndhcmRpbmcKICAgICAgY29uc3QgaXRlbXNJZHhUb0luc3RJZHggPSB0aGlzLl9faXRlbXNJZHhUb0luc3RJZHggPSB7fTsKICAgICAgbGV0IGluc3RJZHggPSAwOwogICAgICAvLyBHZW5lcmF0ZSBpbnN0YW5jZXMgYW5kIGFzc2lnbiBpdGVtcwogICAgICBjb25zdCBsaW1pdCA9IE1hdGgubWluKGlzbnRJZHhUb0l0ZW1zSWR4Lmxlbmd0aCwgdGhpcy5fX2xpbWl0KTsKICAgICAgZm9yICg7IGluc3RJZHg8bGltaXQ7IGluc3RJZHgrKykgewogICAgICAgIGxldCBpbnN0ID0gdGhpcy5fX2luc3RhbmNlc1tpbnN0SWR4XTsKICAgICAgICBsZXQgaXRlbUlkeCA9IGlzbnRJZHhUb0l0ZW1zSWR4W2luc3RJZHhdOwogICAgICAgIGxldCBpdGVtID0gaXRlbXNbaXRlbUlkeF07CiAgICAgICAgaXRlbXNJZHhUb0luc3RJZHhbaXRlbUlkeF0gPSBpbnN0SWR4OwogICAgICAgIGlmIChpbnN0KSB7CiAgICAgICAgICBpbnN0Ll9zZXRQZW5kaW5nUHJvcGVydHkodGhpcy5hcywgaXRlbSk7CiAgICAgICAgICBpbnN0Ll9zZXRQZW5kaW5nUHJvcGVydHkodGhpcy5pbmRleEFzLCBpbnN0SWR4KTsKICAgICAgICAgIGluc3QuX3NldFBlbmRpbmdQcm9wZXJ0eSh0aGlzLml0ZW1zSW5kZXhBcywgaXRlbUlkeCk7CiAgICAgICAgICBpbnN0Ll9mbHVzaFByb3BlcnRpZXMoKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdGhpcy5fX2luc2VydEluc3RhbmNlKGl0ZW0sIGluc3RJZHgsIGl0ZW1JZHgpOwogICAgICAgIH0KICAgICAgfQogICAgICAvLyBSZW1vdmUgYW55IGV4dHJhIGluc3RhbmNlcyBmcm9tIHByZXZpb3VzIHN0YXRlCiAgICAgIGZvciAobGV0IGk9dGhpcy5fX2luc3RhbmNlcy5sZW5ndGgtMTsgaT49aW5zdElkeDsgaS0tKSB7CiAgICAgICAgdGhpcy5fX2RldGFjaEFuZFJlbW92ZUluc3RhbmNlKGkpOwogICAgICB9CiAgICB9CgogICAgX19kZXRhY2hJbnN0YW5jZShpZHgpIHsKICAgICAgbGV0IGluc3QgPSB0aGlzLl9faW5zdGFuY2VzW2lkeF07CiAgICAgIGZvciAobGV0IGk9MDsgaTxpbnN0LmNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgbGV0IGVsID0gaW5zdC5jaGlsZHJlbltpXTsKICAgICAgICBpbnN0LnJvb3QuYXBwZW5kQ2hpbGQoZWwpOwogICAgICB9CiAgICAgIHJldHVybiBpbnN0OwogICAgfQoKICAgIF9fYXR0YWNoSW5zdGFuY2UoaWR4LCBwYXJlbnQpIHsKICAgICAgbGV0IGluc3QgPSB0aGlzLl9faW5zdGFuY2VzW2lkeF07CiAgICAgIHBhcmVudC5pbnNlcnRCZWZvcmUoaW5zdC5yb290LCB0aGlzKTsKICAgIH0KCiAgICBfX2RldGFjaEFuZFJlbW92ZUluc3RhbmNlKGlkeCkgewogICAgICBsZXQgaW5zdCA9IHRoaXMuX19kZXRhY2hJbnN0YW5jZShpZHgpOwogICAgICBpZiAoaW5zdCkgewogICAgICAgIHRoaXMuX19wb29sLnB1c2goaW5zdCk7CiAgICAgIH0KICAgICAgdGhpcy5fX2luc3RhbmNlcy5zcGxpY2UoaWR4LCAxKTsKICAgIH0KCiAgICBfX3N0YW1wSW5zdGFuY2UoaXRlbSwgaW5zdElkeCwgaXRlbUlkeCkgewogICAgICBsZXQgbW9kZWwgPSB7fTsKICAgICAgbW9kZWxbdGhpcy5hc10gPSBpdGVtOwogICAgICBtb2RlbFt0aGlzLmluZGV4QXNdID0gaW5zdElkeDsKICAgICAgbW9kZWxbdGhpcy5pdGVtc0luZGV4QXNdID0gaXRlbUlkeDsKICAgICAgcmV0dXJuIG5ldyB0aGlzLl9fY3Rvcihtb2RlbCk7CiAgICB9CgogICAgX19pbnNlcnRJbnN0YW5jZShpdGVtLCBpbnN0SWR4LCBpdGVtSWR4KSB7CiAgICAgIGxldCBpbnN0ID0gdGhpcy5fX3Bvb2wucG9wKCk7CiAgICAgIGlmIChpbnN0KSB7CiAgICAgICAgLy8gVE9ETyhrc2NoYWFmKTogSWYgdGhlIHBvb2wgaXMgc2hhcmVkIGFjcm9zcyB0dXJucywgaG9zdFByb3BzCiAgICAgICAgLy8gbmVlZCB0byBiZSByZS1zZXQgdG8gcmV1c2VkIGluc3RhbmNlcyBpbiBhZGRpdGlvbiB0byBpdGVtCiAgICAgICAgaW5zdC5fc2V0UGVuZGluZ1Byb3BlcnR5KHRoaXMuYXMsIGl0ZW0pOwogICAgICAgIGluc3QuX3NldFBlbmRpbmdQcm9wZXJ0eSh0aGlzLmluZGV4QXMsIGluc3RJZHgpOwogICAgICAgIGluc3QuX3NldFBlbmRpbmdQcm9wZXJ0eSh0aGlzLml0ZW1zSW5kZXhBcywgaXRlbUlkeCk7CiAgICAgICAgaW5zdC5fZmx1c2hQcm9wZXJ0aWVzKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgaW5zdCA9IHRoaXMuX19zdGFtcEluc3RhbmNlKGl0ZW0sIGluc3RJZHgsIGl0ZW1JZHgpOwogICAgICB9CiAgICAgIGxldCBiZWZvcmVSb3cgPSB0aGlzLl9faW5zdGFuY2VzW2luc3RJZHggKyAxXTsKICAgICAgbGV0IGJlZm9yZU5vZGUgPSBiZWZvcmVSb3cgPyBiZWZvcmVSb3cuY2hpbGRyZW5bMF0gOiB0aGlzOwogICAgICB0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGluc3Qucm9vdCwgYmVmb3JlTm9kZSk7CiAgICAgIHRoaXMuX19pbnN0YW5jZXNbaW5zdElkeF0gPSBpbnN0OwogICAgICByZXR1cm4gaW5zdDsKICAgIH0KCiAgICAvLyBJbXBsZW1lbnRzIGV4dGVuc2lvbiBwb2ludCBmcm9tIFRlbXBsYXRpemUgbWl4aW4KICAgIC8qKgogICAgICogU2hvd3Mgb3IgaGlkZXMgdGhlIHRlbXBsYXRlIGluc3RhbmNlIHRvcCBsZXZlbCBjaGlsZCBlbGVtZW50cy4gRm9yCiAgICAgKiB0ZXh0IG5vZGVzLCBgdGV4dENvbnRlbnRgIGlzIHJlbW92ZWQgd2hpbGUgImhpZGRlbiIgYW5kIHJlcGxhY2VkIHdoZW4KICAgICAqICJzaG93bi4iCiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGhpZGRlbiBTZXQgdG8gdHJ1ZSB0byBoaWRlIHRoZSBjaGlsZHJlbjsKICAgICAqIHNldCB0byBmYWxzZSB0byBzaG93IHRoZW0uCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICogQHByb3RlY3RlZAogICAgICovCiAgICBfc2hvd0hpZGVDaGlsZHJlbihoaWRkZW4pIHsKICAgICAgZm9yIChsZXQgaT0wOyBpPHRoaXMuX19pbnN0YW5jZXMubGVuZ3RoOyBpKyspIHsKICAgICAgICB0aGlzLl9faW5zdGFuY2VzW2ldLl9zaG93SGlkZUNoaWxkcmVuKGhpZGRlbik7CiAgICAgIH0KICAgIH0KCiAgICAvLyBDYWxsZWQgYXMgYSBzaWRlIGVmZmVjdCBvZiBhIGhvc3QgaXRlbXMuPGtleT4uPHBhdGg+IHBhdGggY2hhbmdlLAogICAgLy8gcmVzcG9uc2libGUgZm9yIG5vdGlmeWluZyBpdGVtLjxwYXRoPiBjaGFuZ2VzIHRvIGluc3QgZm9yIGtleQogICAgX19oYW5kbGVJdGVtUGF0aChwYXRoLCB2YWx1ZSkgewogICAgICBsZXQgaXRlbXNQYXRoID0gcGF0aC5zbGljZSg2KTsgLy8gJ2l0ZW1zLicubGVuZ3RoID09IDYKICAgICAgbGV0IGRvdCA9IGl0ZW1zUGF0aC5pbmRleE9mKCcuJyk7CiAgICAgIGxldCBpdGVtc0lkeCA9IGRvdCA8IDAgPyBpdGVtc1BhdGggOiBpdGVtc1BhdGguc3Vic3RyaW5nKDAsIGRvdCk7CiAgICAgIC8vIElmIHBhdGggd2FzIGluZGV4IGludG8gYXJyYXkuLi4KICAgICAgaWYgKGl0ZW1zSWR4ID09IHBhcnNlSW50KGl0ZW1zSWR4LCAxMCkpIHsKICAgICAgICBsZXQgaXRlbVN1YlBhdGggPSBkb3QgPCAwID8gJycgOiBpdGVtc1BhdGguc3Vic3RyaW5nKGRvdCsxKTsKICAgICAgICAvLyBJZiB0aGUgcGF0aCBpcyBvYnNlcnZlZCwgaXQgd2lsbCB0cmlnZ2VyIGEgZnVsbCByZWZyZXNoCiAgICAgICAgdGhpcy5fX2hhbmRsZU9ic2VydmVkUGF0aHMoaXRlbVN1YlBhdGgpOwogICAgICAgIC8vIE5vdGUsIGV2ZW4gaWYgYSBydWxsIHJlZnJlc2ggaXMgdHJpZ2dlcmVkLCBhbHdheXMgZG8gdGhlIHBhdGgKICAgICAgICAvLyBub3RpZmljYXRpb24gYmVjYXVzZSB1bmxlc3MgbXV0YWJsZURhdGEgaXMgdXNlZCBmb3IgZG9tLXJlcGVhdAogICAgICAgIC8vIGFuZCBhbGwgZWxlbWVudHMgaW4gdGhlIGluc3RhbmNlIHN1YnRyZWUsIGEgZnVsbCByZWZyZXNoIG1heQogICAgICAgIC8vIG5vdCB0cmlnZ2VyIHRoZSBwcm9wZXIgdXBkYXRlLgogICAgICAgIGxldCBpbnN0SWR4ID0gdGhpcy5fX2l0ZW1zSWR4VG9JbnN0SWR4W2l0ZW1zSWR4XTsKICAgICAgICBsZXQgaW5zdCA9IHRoaXMuX19pbnN0YW5jZXNbaW5zdElkeF07CiAgICAgICAgaWYgKGluc3QpIHsKICAgICAgICAgIGxldCBpdGVtUGF0aCA9IHRoaXMuYXMgKyAoaXRlbVN1YlBhdGggPyAnLicgKyBpdGVtU3ViUGF0aCA6ICcnKTsKICAgICAgICAgIC8vIFRoaXMgaXMgZWZmZWN0aXZlbHkgYG5vdGlmeVBhdGhgLCBidXQgYXZvaWRzIHNvbWUgb2YgdGhlIG92ZXJoZWFkCiAgICAgICAgICAvLyBvZiB0aGUgcHVibGljIEFQSQogICAgICAgICAgaW5zdC5fc2V0UGVuZGluZ1Byb3BlcnR5T3JQYXRoKGl0ZW1QYXRoLCB2YWx1ZSwgZmFsc2UsIHRydWUpOwogICAgICAgICAgaW5zdC5fZmx1c2hQcm9wZXJ0aWVzKCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB0cnVlOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBpdGVtIGFzc29jaWF0ZWQgd2l0aCBhIGdpdmVuIGVsZW1lbnQgc3RhbXBlZCBieQogICAgICogdGhpcyBgZG9tLXJlcGVhdGAuCiAgICAgKgogICAgICogTm90ZSwgdG8gbW9kaWZ5IHN1Yi1wcm9wZXJ0aWVzIG9mIHRoZSBpdGVtLAogICAgICogYG1vZGVsRm9yRWxlbWVudChlbCkuc2V0KCdpdGVtLjxzdWItcHJvcD4nLCB2YWx1ZSlgCiAgICAgKiBzaG91bGQgYmUgdXNlZC4KICAgICAqCiAgICAgKiBAcGFyYW0geyFIVE1MRWxlbWVudH0gZWwgRWxlbWVudCBmb3Igd2hpY2ggdG8gcmV0dXJuIHRoZSBpdGVtLgogICAgICogQHJldHVybiB7Kn0gSXRlbSBhc3NvY2lhdGVkIHdpdGggdGhlIGVsZW1lbnQuCiAgICAgKi8KICAgIGl0ZW1Gb3JFbGVtZW50KGVsKSB7CiAgICAgIGxldCBpbnN0YW5jZSA9IHRoaXMubW9kZWxGb3JFbGVtZW50KGVsKTsKICAgICAgcmV0dXJuIGluc3RhbmNlICYmIGluc3RhbmNlW3RoaXMuYXNdOwogICAgfQoKICAgIC8qKgogICAgICogUmV0dXJucyB0aGUgaW5zdCBpbmRleCBmb3IgYSBnaXZlbiBlbGVtZW50IHN0YW1wZWQgYnkgdGhpcyBgZG9tLXJlcGVhdGAuCiAgICAgKiBJZiBgc29ydGAgaXMgcHJvdmlkZWQsIHRoZSBpbmRleCB3aWxsIHJlZmxlY3QgdGhlIHNvcnRlZCBvcmRlciAocmF0aGVyCiAgICAgKiB0aGFuIHRoZSBvcmlnaW5hbCBhcnJheSBvcmRlcikuCiAgICAgKgogICAgICogQHBhcmFtIHshSFRNTEVsZW1lbnR9IGVsIEVsZW1lbnQgZm9yIHdoaWNoIHRvIHJldHVybiB0aGUgaW5kZXguCiAgICAgKiBAcmV0dXJuIHs/bnVtYmVyfSBSb3cgaW5kZXggYXNzb2NpYXRlZCB3aXRoIHRoZSBlbGVtZW50IChub3RlIHRoaXMgbWF5CiAgICAgKiAgIG5vdCBjb3JyZXNwb25kIHRvIHRoZSBhcnJheSBpbmRleCBpZiBhIHVzZXIgYHNvcnRgIGlzIGFwcGxpZWQpLgogICAgICovCiAgICBpbmRleEZvckVsZW1lbnQoZWwpIHsKICAgICAgbGV0IGluc3RhbmNlID0gdGhpcy5tb2RlbEZvckVsZW1lbnQoZWwpOwogICAgICByZXR1cm4gaW5zdGFuY2UgJiYgaW5zdGFuY2VbdGhpcy5pbmRleEFzXTsKICAgIH0KCiAgICAvKioKICAgICAqIFJldHVybnMgdGhlIHRlbXBsYXRlICJtb2RlbCIgYXNzb2NpYXRlZCB3aXRoIGEgZ2l2ZW4gZWxlbWVudCwgd2hpY2gKICAgICAqIHNlcnZlcyBhcyB0aGUgYmluZGluZyBzY29wZSBmb3IgdGhlIHRlbXBsYXRlIGluc3RhbmNlIHRoZSBlbGVtZW50IGlzCiAgICAgKiBjb250YWluZWQgaW4uIEEgdGVtcGxhdGUgbW9kZWwgaXMgYW4gaW5zdGFuY2Ugb2YgYFBvbHltZXIuQmFzZWAsIGFuZAogICAgICogc2hvdWxkIGJlIHVzZWQgdG8gbWFuaXB1bGF0ZSBkYXRhIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHRlbXBsYXRlIGluc3RhbmNlLgogICAgICoKICAgICAqIEV4YW1wbGU6CiAgICAgKgogICAgICogICBsZXQgbW9kZWwgPSBtb2RlbEZvckVsZW1lbnQoZWwpOwogICAgICogICBpZiAobW9kZWwuaW5kZXggPCAxMCkgewogICAgICogICAgIG1vZGVsLnNldCgnaXRlbS5jaGVja2VkJywgdHJ1ZSk7CiAgICAgKiAgIH0KICAgICAqCiAgICAgKiBAcGFyYW0geyFIVE1MRWxlbWVudH0gZWwgRWxlbWVudCBmb3Igd2hpY2ggdG8gcmV0dXJuIGEgdGVtcGxhdGUgbW9kZWwuCiAgICAgKiBAcmV0dXJuIHtUZW1wbGF0ZUluc3RhbmNlQmFzZX0gTW9kZWwgcmVwcmVzZW50aW5nIHRoZSBiaW5kaW5nIHNjb3BlIGZvcgogICAgICogICB0aGUgZWxlbWVudC4KICAgICAqLwogICAgbW9kZWxGb3JFbGVtZW50KGVsKSB7CiAgICAgIHJldHVybiBQb2x5bWVyLlRlbXBsYXRpemUubW9kZWxGb3JFbGVtZW50KHRoaXMudGVtcGxhdGUsIGVsKTsKICAgIH0KCiAgfQoKICBjdXN0b21FbGVtZW50cy5kZWZpbmUoRG9tUmVwZWF0LmlzLCBEb21SZXBlYXQpOwoKICAvKiogQGNvbnN0ICovCiAgUG9seW1lci5Eb21SZXBlYXQgPSBEb21SZXBlYXQ7Cgp9KSgpOwoKPC9zY3JpcHQ+PHNjcmlwdD4KCihmdW5jdGlvbigpIHsKICAndXNlIHN0cmljdCc7CgogIC8qKgogICAqIFRoZSBgPGRvbS1pZj5gIGVsZW1lbnQgd2lsbCBzdGFtcCBhIGxpZ2h0LWRvbSBgPHRlbXBsYXRlPmAgY2hpbGQgd2hlbgogICAqIHRoZSBgaWZgIHByb3BlcnR5IGJlY29tZXMgdHJ1dGh5LCBhbmQgdGhlIHRlbXBsYXRlIGNhbiB1c2UgUG9seW1lcgogICAqIGRhdGEtYmluZGluZyBhbmQgZGVjbGFyYXRpdmUgZXZlbnQgZmVhdHVyZXMgd2hlbiB1c2VkIGluIHRoZSBjb250ZXh0IG9mCiAgICogYSBQb2x5bWVyIGVsZW1lbnQncyB0ZW1wbGF0ZS4KICAgKgogICAqIFdoZW4gYGlmYCBiZWNvbWVzIGZhbHN5LCB0aGUgc3RhbXBlZCBjb250ZW50IGlzIGhpZGRlbiBidXQgbm90CiAgICogcmVtb3ZlZCBmcm9tIGRvbS4gV2hlbiBgaWZgIHN1YnNlcXVlbnRseSBiZWNvbWVzIHRydXRoeSBhZ2FpbiwgdGhlIGNvbnRlbnQKICAgKiBpcyBzaW1wbHkgcmUtc2hvd24uIFRoaXMgYXBwcm9hY2ggaXMgdXNlZCBkdWUgdG8gaXRzIGZhdm9yYWJsZSBwZXJmb3JtYW5jZQogICAqIGNoYXJhY3RlcmlzdGljczogdGhlIGV4cGVuc2Ugb2YgY3JlYXRpbmcgdGVtcGxhdGUgY29udGVudCBpcyBwYWlkIG9ubHkKICAgKiBvbmNlIGFuZCBsYXppbHkuCiAgICoKICAgKiBTZXQgdGhlIGByZXN0YW1wYCBwcm9wZXJ0eSB0byB0cnVlIHRvIGZvcmNlIHRoZSBzdGFtcGVkIGNvbnRlbnQgdG8gYmUKICAgKiBjcmVhdGVkIC8gZGVzdHJveWVkIHdoZW4gdGhlIGBpZmAgY29uZGl0aW9uIGNoYW5nZXMuCiAgICoKICAgKiBAY3VzdG9tRWxlbWVudAogICAqIEBwb2x5bWVyCiAgICogQGV4dGVuZHMgUG9seW1lci5FbGVtZW50CiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBDdXN0b20gZWxlbWVudCB0aGF0IGNvbmRpdGlvbmFsbHkgc3RhbXBzIGFuZCBoaWRlcyBvciByZW1vdmVzCiAgICogICB0ZW1wbGF0ZSBjb250ZW50IGJhc2VkIG9uIGEgYm9vbGVhbiBmbGFnLgogICAqLwogIGNsYXNzIERvbUlmIGV4dGVuZHMgUG9seW1lci5FbGVtZW50IHsKCiAgICAvLyBOb3QgbmVlZGVkIHRvIGZpbmQgdGVtcGxhdGU7IGNhbiBiZSByZW1vdmVkIG9uY2UgdGhlIGFuYWx5emVyCiAgICAvLyBjYW4gZmluZCB0aGUgdGFnIG5hbWUgZnJvbSBjdXN0b21FbGVtZW50cy5kZWZpbmUgY2FsbAogICAgc3RhdGljIGdldCBpcygpIHsgcmV0dXJuICdkb20taWYnOyB9CgogICAgc3RhdGljIGdldCB0ZW1wbGF0ZSgpIHsgcmV0dXJuIG51bGw7IH0KCiAgICBzdGF0aWMgZ2V0IHByb3BlcnRpZXMoKSB7CgogICAgICByZXR1cm4gewoKICAgICAgICAvKioKICAgICAgICAgKiBGaXJlZCB3aGVuZXZlciBET00gaXMgYWRkZWQgb3IgcmVtb3ZlZC9oaWRkZW4gYnkgdGhpcyB0ZW1wbGF0ZSAoYnkKICAgICAgICAgKiBkZWZhdWx0LCByZW5kZXJpbmcgb2NjdXJzIGxhemlseSkuICBUbyBmb3JjZSBpbW1lZGlhdGUgcmVuZGVyaW5nLCBjYWxsCiAgICAgICAgICogYHJlbmRlcmAuCiAgICAgICAgICoKICAgICAgICAgKiBAZXZlbnQgZG9tLWNoYW5nZQogICAgICAgICAqLwoKICAgICAgICAvKioKICAgICAgICAgKiBBIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIHRoaXMgdGVtcGxhdGUgc2hvdWxkIHN0YW1wLgogICAgICAgICAqLwogICAgICAgIGlmOiB7CiAgICAgICAgICB0eXBlOiBCb29sZWFuLAogICAgICAgICAgb2JzZXJ2ZXI6ICdfX2RlYm91bmNlUmVuZGVyJwogICAgICAgIH0sCgogICAgICAgIC8qKgogICAgICAgICAqIFdoZW4gdHJ1ZSwgZWxlbWVudHMgd2lsbCBiZSByZW1vdmVkIGZyb20gRE9NIGFuZCBkaXNjYXJkZWQgd2hlbiBgaWZgCiAgICAgICAgICogYmVjb21lcyBmYWxzZSBhbmQgcmUtY3JlYXRlZCBhbmQgYWRkZWQgYmFjayB0byB0aGUgRE9NIHdoZW4gYGlmYAogICAgICAgICAqIGJlY29tZXMgdHJ1ZS4gIEJ5IGRlZmF1bHQsIHN0YW1wZWQgZWxlbWVudHMgd2lsbCBiZSBoaWRkZW4gYnV0IGxlZnQKICAgICAgICAgKiBpbiB0aGUgRE9NIHdoZW4gYGlmYCBiZWNvbWVzIGZhbHNlLCB3aGljaCBpcyBnZW5lcmFsbHkgcmVzdWx0cwogICAgICAgICAqIGluIGJldHRlciBwZXJmb3JtYW5jZS4KICAgICAgICAgKi8KICAgICAgICByZXN0YW1wOiB7CiAgICAgICAgICB0eXBlOiBCb29sZWFuLAogICAgICAgICAgb2JzZXJ2ZXI6ICdfX2RlYm91bmNlUmVuZGVyJwogICAgICAgIH0KCiAgICAgIH07CgogICAgfQoKICAgIGNvbnN0cnVjdG9yKCkgewogICAgICBzdXBlcigpOwogICAgICB0aGlzLl9fcmVuZGVyRGVib3VuY2VyID0gbnVsbDsKICAgICAgdGhpcy5fX2ludmFsaWRQcm9wcyA9IG51bGw7CiAgICAgIHRoaXMuX19pbnN0YW5jZSA9IG51bGw7CiAgICAgIHRoaXMuX2xhc3RJZiA9IGZhbHNlOwogICAgICB0aGlzLl9fY3RvciA9IG51bGw7CiAgICB9CgogICAgX19kZWJvdW5jZVJlbmRlcigpIHsKICAgICAgLy8gUmVuZGVyIGlzIGFzeW5jIGZvciAyIHJlYXNvbnM6CiAgICAgIC8vIDEuIFRvIGVsaW1pbmF0ZSBkb20gY3JlYXRpb24gdHJhc2hpbmcgaWYgdXNlciBjb2RlIHRocmFzaGVzIGBpZmAgaW4gdGhlCiAgICAgIC8vICAgIHNhbWUgdHVybi4gVGhpcyB3YXMgbW9yZSBjb21tb24gaW4gMS54IHdoZXJlIGEgY29tcG91bmQgY29tcHV0ZWQKICAgICAgLy8gICAgcHJvcGVydHkgY291bGQgcmVzdWx0IGluIHRoZSByZXN1bHQgY2hhbmdpbmcgbXVsdGlwbGUgdGltZXMsIGJ1dCBpcwogICAgICAvLyAgICBtaXRpZ2F0ZWQgdG8gYSBsYXJnZSBleHRlbnQgYnkgYmF0Y2hlZCBwcm9wZXJ0eSBwcm9jZXNzaW5nIGluIDIueC4KICAgICAgLy8gMi4gVG8gYXZvaWQgZG91YmxlIG9iamVjdCBwcm9wYWdhdGlvbiB3aGVuIGEgYmFnIGluY2x1ZGluZyB2YWx1ZXMgYm91bmQKICAgICAgLy8gICAgdG8gdGhlIGBpZmAgcHJvcGVydHkgYXMgd2VsbCBhcyBvbmUgb3IgbW9yZSBob3N0UHJvcHMgY291bGQgZW5xdWV1ZQogICAgICAvLyAgICB0aGUgPGRvbS1pZj4gdG8gZmx1c2ggYmVmb3JlIHRoZSA8dGVtcGxhdGU+J3MgaG9zdCBwcm9wZXJ0eQogICAgICAvLyAgICBmb3J3YXJkaW5nLiBJbiB0aGF0IHNjZW5hcmlvIGNyZWF0aW5nIGFuIGluc3RhbmNlIHdvdWxkIHJlc3VsdCBpbgogICAgICAvLyAgICB0aGUgaG9zdCBwcm9wcyBiZWluZyBzZXQgb25jZSwgYW5kIHRoZW4gdGhlIGVucXVldWVkIGNoYW5nZXMgb24gdGhlCiAgICAgIC8vICAgIHRlbXBsYXRlIHdvdWxkIHNldCBwcm9wZXJ0aWVzIGEgc2Vjb25kIHRpbWUsIHBvdGVudGlhbGx5IGNhdXNpbmcgYW4KICAgICAgLy8gICAgb2JqZWN0IHRvIGJlIHNldCB0byBhbiBpbnN0YW5jZSBtb3JlIHRoYW4gb25jZS4gIENyZWF0aW5nIHRoZQogICAgICAvLyAgICBpbnN0YW5jZSBhc3luYyBmcm9tIGZsdXNoaW5nIGRhdGEgZW5zdXJlcyB0aGlzIGRvZXNuJ3QgaGFwcGVuLiBJZgogICAgICAvLyAgICB3ZSB3YW50ZWQgYSBzeW5jIG9wdGlvbiBpbiB0aGUgZnV0dXJlLCBzaW1wbHkgaGF2aW5nIDxkb20taWY+IGZsdXNoCiAgICAgIC8vICAgIChvciBjbGVhcikgaXRzIHRlbXBsYXRlJ3MgcGVuZGluZyBob3N0IHByb3BlcnRpZXMgYmVmb3JlIGNyZWF0aW5nCiAgICAgIC8vICAgIHRoZSBpbnN0YW5jZSB3b3VsZCBhbHNvIGF2b2lkIHRoZSBwcm9ibGVtLgogICAgICB0aGlzLl9fcmVuZGVyRGVib3VuY2VyID0gUG9seW1lci5EZWJvdW5jZXIuZGVib3VuY2UoCiAgICAgICAgICAgIHRoaXMuX19yZW5kZXJEZWJvdW5jZXIKICAgICAgICAgICwgUG9seW1lci5Bc3luYy5taWNyb1Rhc2sKICAgICAgICAgICwgKCkgPT4gdGhpcy5fX3JlbmRlcigpKTsKICAgICAgUG9seW1lci5lbnF1ZXVlRGVib3VuY2VyKHRoaXMuX19yZW5kZXJEZWJvdW5jZXIpOwogICAgfQoKICAgIC8qKgogICAgICogQHJldHVybiB7dm9pZH0KICAgICAqLwogICAgZGlzY29ubmVjdGVkQ2FsbGJhY2soKSB7CiAgICAgIHN1cGVyLmRpc2Nvbm5lY3RlZENhbGxiYWNrKCk7CiAgICAgIGlmICghdGhpcy5wYXJlbnROb2RlIHx8CiAgICAgICAgICAodGhpcy5wYXJlbnROb2RlLm5vZGVUeXBlID09IE5vZGUuRE9DVU1FTlRfRlJBR01FTlRfTk9ERSAmJgogICAgICAgICAgICF0aGlzLnBhcmVudE5vZGUuaG9zdCkpIHsKICAgICAgICB0aGlzLl9fdGVhcmRvd25JbnN0YW5jZSgpOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICovCiAgICBjb25uZWN0ZWRDYWxsYmFjaygpIHsKICAgICAgc3VwZXIuY29ubmVjdGVkQ2FsbGJhY2soKTsKICAgICAgdGhpcy5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnOwogICAgICBpZiAodGhpcy5pZikgewogICAgICAgIHRoaXMuX19kZWJvdW5jZVJlbmRlcigpOwogICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBGb3JjZXMgdGhlIGVsZW1lbnQgdG8gcmVuZGVyIGl0cyBjb250ZW50LiBOb3JtYWxseSByZW5kZXJpbmcgaXMKICAgICAqIGFzeW5jaHJvbm91cyB0byBhIHByb3Zva2luZyBjaGFuZ2UuIFRoaXMgaXMgZG9uZSBmb3IgZWZmaWNpZW5jeSBzbwogICAgICogdGhhdCBtdWx0aXBsZSBjaGFuZ2VzIHRyaWdnZXIgb25seSBhIHNpbmdsZSByZW5kZXIuIFRoZSByZW5kZXIgbWV0aG9kCiAgICAgKiBzaG91bGQgYmUgY2FsbGVkIGlmLCBmb3IgZXhhbXBsZSwgdGVtcGxhdGUgcmVuZGVyaW5nIGlzIHJlcXVpcmVkIHRvCiAgICAgKiB2YWxpZGF0ZSBhcHBsaWNhdGlvbiBzdGF0ZS4KICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgKi8KICAgIHJlbmRlcigpIHsKICAgICAgUG9seW1lci5mbHVzaCgpOwogICAgfQoKICAgIF9fcmVuZGVyKCkgewogICAgICBpZiAodGhpcy5pZikgewogICAgICAgIGlmICghdGhpcy5fX2Vuc3VyZUluc3RhbmNlKCkpIHsKICAgICAgICAgIC8vIE5vIHRlbXBsYXRlIGZvdW5kIHlldAogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICB0aGlzLl9zaG93SGlkZUNoaWxkcmVuKCk7CiAgICAgIH0gZWxzZSBpZiAodGhpcy5yZXN0YW1wKSB7CiAgICAgICAgdGhpcy5fX3RlYXJkb3duSW5zdGFuY2UoKTsKICAgICAgfQogICAgICBpZiAoIXRoaXMucmVzdGFtcCAmJiB0aGlzLl9faW5zdGFuY2UpIHsKICAgICAgICB0aGlzLl9zaG93SGlkZUNoaWxkcmVuKCk7CiAgICAgIH0KICAgICAgaWYgKHRoaXMuaWYgIT0gdGhpcy5fbGFzdElmKSB7CiAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudCgnZG9tLWNoYW5nZScsIHsKICAgICAgICAgIGJ1YmJsZXM6IHRydWUsCiAgICAgICAgICBjb21wb3NlZDogdHJ1ZQogICAgICAgIH0pKTsKICAgICAgICB0aGlzLl9sYXN0SWYgPSB0aGlzLmlmOwogICAgICB9CiAgICB9CgogICAgX19lbnN1cmVJbnN0YW5jZSgpIHsKICAgICAgbGV0IHBhcmVudE5vZGUgPSB0aGlzLnBhcmVudE5vZGU7CiAgICAgIC8vIEd1YXJkIGFnYWluc3QgZWxlbWVudCBiZWluZyBkZXRhY2hlZCB3aGlsZSByZW5kZXIgd2FzIHF1ZXVlZAogICAgICBpZiAocGFyZW50Tm9kZSkgewogICAgICAgIGlmICghdGhpcy5fX2N0b3IpIHsKICAgICAgICAgIGxldCB0ZW1wbGF0ZSA9IC8qKiBAdHlwZSB7SFRNTFRlbXBsYXRlRWxlbWVudH0gKi8odGhpcy5xdWVyeVNlbGVjdG9yKCd0ZW1wbGF0ZScpKTsKICAgICAgICAgIGlmICghdGVtcGxhdGUpIHsKICAgICAgICAgICAgLy8gV2FpdCB1bnRpbCBjaGlsZExpc3QgY2hhbmdlcyBhbmQgdGVtcGxhdGUgc2hvdWxkIGJlIHRoZXJlIGJ5IHRoZW4KICAgICAgICAgICAgbGV0IG9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKCkgPT4gewogICAgICAgICAgICAgIGlmICh0aGlzLnF1ZXJ5U2VsZWN0b3IoJ3RlbXBsYXRlJykpIHsKICAgICAgICAgICAgICAgIG9ic2VydmVyLmRpc2Nvbm5lY3QoKTsKICAgICAgICAgICAgICAgIHRoaXMuX19yZW5kZXIoKTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdkb20taWYgcmVxdWlyZXMgYSA8dGVtcGxhdGU+IGNoaWxkJyk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgb2JzZXJ2ZXIub2JzZXJ2ZSh0aGlzLCB7Y2hpbGRMaXN0OiB0cnVlfSk7CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgIH0KICAgICAgICAgIHRoaXMuX19jdG9yID0gUG9seW1lci5UZW1wbGF0aXplLnRlbXBsYXRpemUodGVtcGxhdGUsIHRoaXMsIHsKICAgICAgICAgICAgLy8gZG9tLWlmIHRlbXBsYXRpemVyIGluc3RhbmNlcyByZXF1aXJlIGBtdXRhYmxlOiB0cnVlYCwgYXMKICAgICAgICAgICAgLy8gYF9fc3luY0hvc3RQcm9wZXJ0aWVzYCByZWxpZXMgb24gdGhhdCBiZWhhdmlvciB0byBzeW5jIG9iamVjdHMKICAgICAgICAgICAgbXV0YWJsZURhdGE6IHRydWUsCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcCBQcm9wZXJ0eSB0byBmb3J3YXJkCiAgICAgICAgICAgICAqIEBwYXJhbSB7Kn0gdmFsdWUgVmFsdWUgb2YgcHJvcGVydHkKICAgICAgICAgICAgICogQHRoaXMge3RoaXN9CiAgICAgICAgICAgICAqLwogICAgICAgICAgICBmb3J3YXJkSG9zdFByb3A6IGZ1bmN0aW9uKHByb3AsIHZhbHVlKSB7CiAgICAgICAgICAgICAgaWYgKHRoaXMuX19pbnN0YW5jZSkgewogICAgICAgICAgICAgICAgaWYgKHRoaXMuaWYpIHsKICAgICAgICAgICAgICAgICAgdGhpcy5fX2luc3RhbmNlLmZvcndhcmRIb3N0UHJvcChwcm9wLCB2YWx1ZSk7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAvLyBJZiB3ZSBoYXZlIGFuIGluc3RhbmNlIGJ1dCBhcmUgc3F1ZWxjaGluZyBob3N0IHByb3BlcnR5CiAgICAgICAgICAgICAgICAgIC8vIGZvcndhcmRpbmcgZHVlIHRvIGlmIGJlaW5nIGZhbHNlLCBub3RlIHRoZSBpbnZhbGlkYXRlZAogICAgICAgICAgICAgICAgICAvLyBwcm9wZXJ0aWVzIHNvIGBfX3N5bmNIb3N0UHJvcGVydGllc2AgY2FuIHN5bmMgdGhlbSB0aGUgbmV4dAogICAgICAgICAgICAgICAgICAvLyB0aW1lIGBpZmAgYmVjb21lcyB0cnVlCiAgICAgICAgICAgICAgICAgIHRoaXMuX19pbnZhbGlkUHJvcHMgPSB0aGlzLl9faW52YWxpZFByb3BzIHx8IE9iamVjdC5jcmVhdGUobnVsbCk7CiAgICAgICAgICAgICAgICAgIHRoaXMuX19pbnZhbGlkUHJvcHNbUG9seW1lci5QYXRoLnJvb3QocHJvcCldID0gdHJ1ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICBpZiAoIXRoaXMuX19pbnN0YW5jZSkgewogICAgICAgICAgdGhpcy5fX2luc3RhbmNlID0gbmV3IHRoaXMuX19jdG9yKCk7CiAgICAgICAgICBwYXJlbnROb2RlLmluc2VydEJlZm9yZSh0aGlzLl9faW5zdGFuY2Uucm9vdCwgdGhpcyk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRoaXMuX19zeW5jSG9zdFByb3BlcnRpZXMoKTsKICAgICAgICAgIGxldCBjJCA9IHRoaXMuX19pbnN0YW5jZS5jaGlsZHJlbjsKICAgICAgICAgIGlmIChjJCAmJiBjJC5sZW5ndGgpIHsKICAgICAgICAgICAgLy8gRGV0ZWN0IGNhc2Ugd2hlcmUgZG9tLWlmIHdhcyByZS1hdHRhY2hlZCBpbiBuZXcgcG9zaXRpb24KICAgICAgICAgICAgbGV0IGxhc3RDaGlsZCA9IHRoaXMucHJldmlvdXNTaWJsaW5nOwogICAgICAgICAgICBpZiAobGFzdENoaWxkICE9PSBjJFtjJC5sZW5ndGgtMV0pIHsKICAgICAgICAgICAgICBmb3IgKGxldCBpPTAsIG47IChpPGMkLmxlbmd0aCkgJiYgKG49YyRbaV0pOyBpKyspIHsKICAgICAgICAgICAgICAgIHBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKG4sIHRoaXMpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBfX3N5bmNIb3N0UHJvcGVydGllcygpIHsKICAgICAgbGV0IHByb3BzID0gdGhpcy5fX2ludmFsaWRQcm9wczsKICAgICAgaWYgKHByb3BzKSB7CiAgICAgICAgZm9yIChsZXQgcHJvcCBpbiBwcm9wcykgewogICAgICAgICAgdGhpcy5fX2luc3RhbmNlLl9zZXRQZW5kaW5nUHJvcGVydHkocHJvcCwgdGhpcy5fX2RhdGFIb3N0W3Byb3BdKTsKICAgICAgICB9CiAgICAgICAgdGhpcy5fX2ludmFsaWRQcm9wcyA9IG51bGw7CiAgICAgICAgdGhpcy5fX2luc3RhbmNlLl9mbHVzaFByb3BlcnRpZXMoKTsKICAgICAgfQogICAgfQoKICAgIF9fdGVhcmRvd25JbnN0YW5jZSgpIHsKICAgICAgaWYgKHRoaXMuX19pbnN0YW5jZSkgewogICAgICAgIGxldCBjJCA9IHRoaXMuX19pbnN0YW5jZS5jaGlsZHJlbjsKICAgICAgICBpZiAoYyQgJiYgYyQubGVuZ3RoKSB7CiAgICAgICAgICAvLyB1c2UgZmlyc3QgY2hpbGQgcGFyZW50LCBmb3IgY2FzZSB3aGVuIGRvbS1pZiBtYXkgaGF2ZSBiZWVuIGRldGFjaGVkCiAgICAgICAgICBsZXQgcGFyZW50ID0gYyRbMF0ucGFyZW50Tm9kZTsKICAgICAgICAgIC8vIEluc3RhbmNlIGNoaWxkcmVuIG1heSBiZSBkaXNjb25uZWN0ZWQgZnJvbSBwYXJlbnRzIHdoZW4gZG9tLWlmCiAgICAgICAgICAvLyBkZXRhY2hlcyBpZiBhIHRyZWUgd2FzIGlubmVySFRNTCdlZAogICAgICAgICAgaWYgKHBhcmVudCkgewogICAgICAgICAgICBmb3IgKGxldCBpPTAsIG47IChpPGMkLmxlbmd0aCkgJiYgKG49YyRbaV0pOyBpKyspIHsKICAgICAgICAgICAgICBwYXJlbnQucmVtb3ZlQ2hpbGQobik7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgdGhpcy5fX2luc3RhbmNlID0gbnVsbDsKICAgICAgICB0aGlzLl9faW52YWxpZFByb3BzID0gbnVsbDsKICAgICAgfQogICAgfQoKICAgIC8qKgogICAgICogU2hvd3Mgb3IgaGlkZXMgdGhlIHRlbXBsYXRlIGluc3RhbmNlIHRvcCBsZXZlbCBjaGlsZCBlbGVtZW50cy4gRm9yCiAgICAgKiB0ZXh0IG5vZGVzLCBgdGV4dENvbnRlbnRgIGlzIHJlbW92ZWQgd2hpbGUgImhpZGRlbiIgYW5kIHJlcGxhY2VkIHdoZW4KICAgICAqICJzaG93bi4iCiAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICogQHByb3RlY3RlZAogICAgICovCiAgICBfc2hvd0hpZGVDaGlsZHJlbigpIHsKICAgICAgbGV0IGhpZGRlbiA9IHRoaXMuX19oaWRlVGVtcGxhdGVDaGlsZHJlbl9fIHx8ICF0aGlzLmlmOwogICAgICBpZiAodGhpcy5fX2luc3RhbmNlKSB7CiAgICAgICAgdGhpcy5fX2luc3RhbmNlLl9zaG93SGlkZUNoaWxkcmVuKGhpZGRlbik7CiAgICAgIH0KICAgIH0KCiAgfQoKICBjdXN0b21FbGVtZW50cy5kZWZpbmUoRG9tSWYuaXMsIERvbUlmKTsKCiAgLyoqIEBjb25zdCAqLwogIFBvbHltZXIuRG9tSWYgPSBEb21JZjsKCn0pKCk7Cjwvc2NyaXB0PjxzY3JpcHQ+CihmdW5jdGlvbigpIHsKICAndXNlIHN0cmljdCc7CgogIC8qKgogICAqIEVsZW1lbnQgbWl4aW4gZm9yIHJlY29yZGluZyBkeW5hbWljIGFzc29jaWF0aW9ucyBiZXR3ZWVuIGl0ZW0gcGF0aHMgaW4gYQogICAqIG1hc3RlciBgaXRlbXNgIGFycmF5IGFuZCBhIGBzZWxlY3RlZGAgYXJyYXkgc3VjaCB0aGF0IHBhdGggY2hhbmdlcyB0byB0aGUKICAgKiBtYXN0ZXIgYXJyYXkgKGF0IHRoZSBob3N0KSBlbGVtZW50IG9yIGVsc2V3aGVyZSB2aWEgZGF0YS1iaW5kaW5nKSBhcmUKICAgKiBjb3JyZWN0bHkgcHJvcGFnYXRlZCB0byBpdGVtcyBpbiB0aGUgc2VsZWN0ZWQgYXJyYXkgYW5kIHZpY2UtdmVyc2EuCiAgICoKICAgKiBUaGUgYGl0ZW1zYCBwcm9wZXJ0eSBhY2NlcHRzIGFuIGFycmF5IG9mIHVzZXIgZGF0YSwgYW5kIHZpYSB0aGUKICAgKiBgc2VsZWN0KGl0ZW0pYCBhbmQgYGRlc2VsZWN0KGl0ZW0pYCBBUEksIHVwZGF0ZXMgdGhlIGBzZWxlY3RlZGAgcHJvcGVydHkKICAgKiB3aGljaCBtYXkgYmUgYm91bmQgdG8gb3RoZXIgcGFydHMgb2YgdGhlIGFwcGxpY2F0aW9uLCBhbmQgYW55IGNoYW5nZXMgdG8KICAgKiBzdWItZmllbGRzIG9mIGBzZWxlY3RlZGAgaXRlbShzKSB3aWxsIGJlIGtlcHQgaW4gc3luYyB3aXRoIGl0ZW1zIGluIHRoZQogICAqIGBpdGVtc2AgYXJyYXkuICBXaGVuIGBtdWx0aWAgaXMgZmFsc2UsIGBzZWxlY3RlZGAgaXMgYSBwcm9wZXJ0eQogICAqIHJlcHJlc2VudGluZyB0aGUgbGFzdCBzZWxlY3RlZCBpdGVtLiAgV2hlbiBgbXVsdGlgIGlzIHRydWUsIGBzZWxlY3RlZGAKICAgKiBpcyBhbiBhcnJheSBvZiBtdWx0aXBseSBzZWxlY3RlZCBpdGVtcy4KICAgKgogICAqIEBwb2x5bWVyCiAgICogQG1peGluRnVuY3Rpb24KICAgKiBAYXBwbGllc01peGluIFBvbHltZXIuRWxlbWVudE1peGluCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBFbGVtZW50IG1peGluIGZvciByZWNvcmRpbmcgZHluYW1pYyBhc3NvY2lhdGlvbnMgYmV0d2VlbiBpdGVtIHBhdGhzIGluIGEKICAgKiBtYXN0ZXIgYGl0ZW1zYCBhcnJheSBhbmQgYSBgc2VsZWN0ZWRgIGFycmF5CiAgICovCiAgbGV0IEFycmF5U2VsZWN0b3JNaXhpbiA9IFBvbHltZXIuZGVkdXBpbmdNaXhpbihzdXBlckNsYXNzID0+IHsKCiAgICAvKioKICAgICAqIEBjb25zdHJ1Y3RvcgogICAgICogQGV4dGVuZHMge3N1cGVyQ2xhc3N9CiAgICAgKiBAaW1wbGVtZW50cyB7UG9seW1lcl9FbGVtZW50TWl4aW59CiAgICAgKiBAcHJpdmF0ZQogICAgICovCiAgICBsZXQgZWxlbWVudEJhc2UgPSBQb2x5bWVyLkVsZW1lbnRNaXhpbihzdXBlckNsYXNzKTsKCiAgICAvKioKICAgICAqIEBwb2x5bWVyCiAgICAgKiBAbWl4aW5DbGFzcwogICAgICogQGltcGxlbWVudHMge1BvbHltZXJfQXJyYXlTZWxlY3Rvck1peGlufQogICAgICogQHVucmVzdHJpY3RlZAogICAgICovCiAgICBjbGFzcyBBcnJheVNlbGVjdG9yTWl4aW4gZXh0ZW5kcyBlbGVtZW50QmFzZSB7CgogICAgICBzdGF0aWMgZ2V0IHByb3BlcnRpZXMoKSB7CgogICAgICAgIHJldHVybiB7CgogICAgICAgICAgLyoqCiAgICAgICAgICAgKiBBbiBhcnJheSBjb250YWluaW5nIGl0ZW1zIGZyb20gd2hpY2ggc2VsZWN0aW9uIHdpbGwgYmUgbWFkZS4KICAgICAgICAgICAqLwogICAgICAgICAgaXRlbXM6IHsKICAgICAgICAgICAgdHlwZTogQXJyYXksCiAgICAgICAgICB9LAoKICAgICAgICAgIC8qKgogICAgICAgICAgICogV2hlbiBgdHJ1ZWAsIG11bHRpcGxlIGl0ZW1zIG1heSBiZSBzZWxlY3RlZCBhdCBvbmNlIChpbiB0aGlzIGNhc2UsCiAgICAgICAgICAgKiBgc2VsZWN0ZWRgIGlzIGFuIGFycmF5IG9mIGN1cnJlbnRseSBzZWxlY3RlZCBpdGVtcykuICBXaGVuIGBmYWxzZWAsCiAgICAgICAgICAgKiBvbmx5IG9uZSBpdGVtIG1heSBiZSBzZWxlY3RlZCBhdCBhIHRpbWUuCiAgICAgICAgICAgKi8KICAgICAgICAgIG11bHRpOiB7CiAgICAgICAgICAgIHR5cGU6IEJvb2xlYW4sCiAgICAgICAgICAgIHZhbHVlOiBmYWxzZSwKICAgICAgICAgIH0sCgogICAgICAgICAgLyoqCiAgICAgICAgICAgKiBXaGVuIGBtdWx0aWAgaXMgdHJ1ZSwgdGhpcyBpcyBhbiBhcnJheSB0aGF0IGNvbnRhaW5zIGFueSBzZWxlY3RlZC4KICAgICAgICAgICAqIFdoZW4gYG11bHRpYCBpcyBmYWxzZSwgdGhpcyBpcyB0aGUgY3VycmVudGx5IHNlbGVjdGVkIGl0ZW0sIG9yIGBudWxsYAogICAgICAgICAgICogaWYgbm8gaXRlbSBpcyBzZWxlY3RlZC4KICAgICAgICAgICAqIEB0eXBlIHs/KE9iamVjdHxBcnJheTwhT2JqZWN0Pil9CiAgICAgICAgICAgKi8KICAgICAgICAgIHNlbGVjdGVkOiB7CiAgICAgICAgICAgIHR5cGU6IE9iamVjdCwKICAgICAgICAgICAgbm90aWZ5OiB0cnVlCiAgICAgICAgICB9LAoKICAgICAgICAgIC8qKgogICAgICAgICAgICogV2hlbiBgbXVsdGlgIGlzIGZhbHNlLCB0aGlzIGlzIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgaXRlbSwgb3IgYG51bGxgCiAgICAgICAgICAgKiBpZiBubyBpdGVtIGlzIHNlbGVjdGVkLgogICAgICAgICAgICogQHR5cGUgez9PYmplY3R9CiAgICAgICAgICAgKi8KICAgICAgICAgIHNlbGVjdGVkSXRlbTogewogICAgICAgICAgICB0eXBlOiBPYmplY3QsCiAgICAgICAgICAgIG5vdGlmeTogdHJ1ZQogICAgICAgICAgfSwKCiAgICAgICAgICAvKioKICAgICAgICAgICAqIFdoZW4gYHRydWVgLCBjYWxsaW5nIGBzZWxlY3RgIG9uIGFuIGl0ZW0gdGhhdCBpcyBhbHJlYWR5IHNlbGVjdGVkCiAgICAgICAgICAgKiB3aWxsIGRlc2VsZWN0IHRoZSBpdGVtLgogICAgICAgICAgICovCiAgICAgICAgICB0b2dnbGU6IHsKICAgICAgICAgICAgdHlwZTogQm9vbGVhbiwKICAgICAgICAgICAgdmFsdWU6IGZhbHNlCiAgICAgICAgICB9CgogICAgICAgIH07CiAgICAgIH0KCiAgICAgIHN0YXRpYyBnZXQgb2JzZXJ2ZXJzKCkgewogICAgICAgIHJldHVybiBbJ19fdXBkYXRlU2VsZWN0aW9uKG11bHRpLCBpdGVtcy4qKSddOwogICAgICB9CgogICAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICBzdXBlcigpOwogICAgICAgIHRoaXMuX19sYXN0SXRlbXMgPSBudWxsOwogICAgICAgIHRoaXMuX19sYXN0TXVsdGkgPSBudWxsOwogICAgICAgIHRoaXMuX19zZWxlY3RlZE1hcCA9IG51bGw7CiAgICAgIH0KCiAgICAgIF9fdXBkYXRlU2VsZWN0aW9uKG11bHRpLCBpdGVtc0luZm8pIHsKICAgICAgICBsZXQgcGF0aCA9IGl0ZW1zSW5mby5wYXRoOwogICAgICAgIGlmIChwYXRoID09ICdpdGVtcycpIHsKICAgICAgICAgIC8vIENhc2UgMSAtIGl0ZW1zIGFycmF5IGNoYW5nZWQsIHNvIGRpZmYgYWdhaW5zdCBwcmV2aW91cyBhcnJheSBhbmQKICAgICAgICAgIC8vIGRlc2VsZWN0IGFueSByZW1vdmVkIGl0ZW1zIGFuZCBhZGp1c3Qgc2VsZWN0ZWQgaW5kaWNlcwogICAgICAgICAgbGV0IG5ld0l0ZW1zID0gaXRlbXNJbmZvLmJhc2UgfHwgW107CiAgICAgICAgICBsZXQgbGFzdEl0ZW1zID0gdGhpcy5fX2xhc3RJdGVtczsKICAgICAgICAgIGxldCBsYXN0TXVsdGkgPSB0aGlzLl9fbGFzdE11bHRpOwogICAgICAgICAgaWYgKG11bHRpICE9PSBsYXN0TXVsdGkpIHsKICAgICAgICAgICAgdGhpcy5jbGVhclNlbGVjdGlvbigpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGxhc3RJdGVtcykgewogICAgICAgICAgICBsZXQgc3BsaWNlcyA9IFBvbHltZXIuQXJyYXlTcGxpY2UuY2FsY3VsYXRlU3BsaWNlcyhuZXdJdGVtcywgbGFzdEl0ZW1zKTsKICAgICAgICAgICAgdGhpcy5fX2FwcGx5U3BsaWNlcyhzcGxpY2VzKTsKICAgICAgICAgIH0KICAgICAgICAgIHRoaXMuX19sYXN0SXRlbXMgPSBuZXdJdGVtczsKICAgICAgICAgIHRoaXMuX19sYXN0TXVsdGkgPSBtdWx0aTsKICAgICAgICB9IGVsc2UgaWYgKGl0ZW1zSW5mby5wYXRoID09ICdpdGVtcy5zcGxpY2VzJykgewogICAgICAgICAgLy8gQ2FzZSAyIC0gZ290IHNwZWNpZmljIHNwbGljZSBpbmZvcm1hdGlvbiBkZXNjcmliaW5nIHRoZSBhcnJheSBtdXRhdGlvbjoKICAgICAgICAgIC8vIGRlc2VsZWN0IGFueSByZW1vdmVkIGl0ZW1zIGFuZCBhZGp1c3Qgc2VsZWN0ZWQgaW5kaWNlcwogICAgICAgICAgdGhpcy5fX2FwcGx5U3BsaWNlcyhpdGVtc0luZm8udmFsdWUuaW5kZXhTcGxpY2VzKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgLy8gQ2FzZSAzIC0gYW4gYXJyYXkgZWxlbWVudCB3YXMgY2hhbmdlZCwgc28gZGVzZWxlY3QgdGhlIHByZXZpb3VzCiAgICAgICAgICAvLyBpdGVtIGZvciB0aGF0IGluZGV4IGlmIGl0IHdhcyBwcmV2aW91c2x5IHNlbGVjdGVkCiAgICAgICAgICBsZXQgcGFydCA9IHBhdGguc2xpY2UoJ2l0ZW1zLicubGVuZ3RoKTsKICAgICAgICAgIGxldCBpZHggPSBwYXJzZUludChwYXJ0LCAxMCk7CiAgICAgICAgICBpZiAoKHBhcnQuaW5kZXhPZignLicpIDwgMCkgJiYgcGFydCA9PSBpZHgpIHsKICAgICAgICAgICAgdGhpcy5fX2Rlc2VsZWN0Q2hhbmdlZElkeChpZHgpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQoKICAgICAgX19hcHBseVNwbGljZXMoc3BsaWNlcykgewogICAgICAgIGxldCBzZWxlY3RlZCA9IHRoaXMuX19zZWxlY3RlZE1hcDsKICAgICAgICAvLyBBZGp1c3Qgc2VsZWN0ZWQgaW5kaWNlcyBhbmQgbWFyayByZW1vdmFscwogICAgICAgIGZvciAobGV0IGk9MDsgaTxzcGxpY2VzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICBsZXQgcyA9IHNwbGljZXNbaV07CiAgICAgICAgICBzZWxlY3RlZC5mb3JFYWNoKChpZHgsIGl0ZW0pID0+IHsKICAgICAgICAgICAgaWYgKGlkeCA8IHMuaW5kZXgpIHsKICAgICAgICAgICAgICAvLyBubyBjaGFuZ2UKICAgICAgICAgICAgfSBlbHNlIGlmIChpZHggPj0gcy5pbmRleCArIHMucmVtb3ZlZC5sZW5ndGgpIHsKICAgICAgICAgICAgICAvLyBhZGp1c3QgaW5kZXgKICAgICAgICAgICAgICBzZWxlY3RlZC5zZXQoaXRlbSwgaWR4ICsgcy5hZGRlZENvdW50IC0gcy5yZW1vdmVkLmxlbmd0aCk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgLy8gcmVtb3ZlIGluZGV4CiAgICAgICAgICAgICAgc2VsZWN0ZWQuc2V0KGl0ZW0sIC0xKTsKICAgICAgICAgICAgfQogICAgICAgICAgfSk7CiAgICAgICAgICBmb3IgKGxldCBqPTA7IGo8cy5hZGRlZENvdW50OyBqKyspIHsKICAgICAgICAgICAgbGV0IGlkeCA9IHMuaW5kZXggKyBqOwogICAgICAgICAgICBpZiAoc2VsZWN0ZWQuaGFzKHRoaXMuaXRlbXNbaWR4XSkpIHsKICAgICAgICAgICAgICBzZWxlY3RlZC5zZXQodGhpcy5pdGVtc1tpZHhdLCBpZHgpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8vIFVwZGF0ZSBsaW5rZWQgcGF0aHMKICAgICAgICB0aGlzLl9fdXBkYXRlTGlua3MoKTsKICAgICAgICAvLyBSZW1vdmUgc2VsZWN0ZWQgaXRlbXMgdGhhdCB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgaXRlbXMgYXJyYXkKICAgICAgICBsZXQgc2lkeCA9IDA7CiAgICAgICAgc2VsZWN0ZWQuZm9yRWFjaCgoaWR4LCBpdGVtKSA9PiB7CiAgICAgICAgICBpZiAoaWR4IDwgMCkgewogICAgICAgICAgICBpZiAodGhpcy5tdWx0aSkgewogICAgICAgICAgICAgIHRoaXMuc3BsaWNlKCdzZWxlY3RlZCcsIHNpZHgsIDEpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWQgPSB0aGlzLnNlbGVjdGVkSXRlbSA9IG51bGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc2VsZWN0ZWQuZGVsZXRlKGl0ZW0pOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgc2lkeCsrOwogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICB9CgogICAgICBfX3VwZGF0ZUxpbmtzKCkgewogICAgICAgIHRoaXMuX19kYXRhTGlua2VkUGF0aHMgPSB7fTsKICAgICAgICBpZiAodGhpcy5tdWx0aSkgewogICAgICAgICAgbGV0IHNpZHggPSAwOwogICAgICAgICAgdGhpcy5fX3NlbGVjdGVkTWFwLmZvckVhY2goaWR4ID0+IHsKICAgICAgICAgICAgaWYgKGlkeCA+PSAwKSB7CiAgICAgICAgICAgICAgdGhpcy5saW5rUGF0aHMoJ2l0ZW1zLicgKyBpZHgsICdzZWxlY3RlZC4nICsgc2lkeCsrKTsKICAgICAgICAgICAgfQogICAgICAgICAgfSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRoaXMuX19zZWxlY3RlZE1hcC5mb3JFYWNoKGlkeCA9PiB7CiAgICAgICAgICAgIHRoaXMubGlua1BhdGhzKCdzZWxlY3RlZCcsICdpdGVtcy4nICsgaWR4KTsKICAgICAgICAgICAgdGhpcy5saW5rUGF0aHMoJ3NlbGVjdGVkSXRlbScsICdpdGVtcy4nICsgaWR4KTsKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIENsZWFycyB0aGUgc2VsZWN0aW9uIHN0YXRlLgogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgY2xlYXJTZWxlY3Rpb24oKSB7CiAgICAgICAgLy8gVW5iaW5kIHByZXZpb3VzIHNlbGVjdGlvbgogICAgICAgIHRoaXMuX19kYXRhTGlua2VkUGF0aHMgPSB7fTsKICAgICAgICAvLyBUaGUgc2VsZWN0ZWQgbWFwIHN0b3JlcyAzIHBpZWNlcyBvZiBpbmZvcm1hdGlvbjoKICAgICAgICAvLyBrZXk6IGl0ZW1zIGFycmF5IG9iamVjdAogICAgICAgIC8vIHZhbHVlOiBpdGVtcyBhcnJheSBpbmRleAogICAgICAgIC8vIG9yZGVyOiBzZWxlY3RlZCBhcnJheSBpbmRleAogICAgICAgIHRoaXMuX19zZWxlY3RlZE1hcCA9IG5ldyBNYXAoKTsKICAgICAgICAvLyBJbml0aWFsaXplIHNlbGVjdGlvbgogICAgICAgIHRoaXMuc2VsZWN0ZWQgPSB0aGlzLm11bHRpID8gW10gOiBudWxsOwogICAgICAgIHRoaXMuc2VsZWN0ZWRJdGVtID0gbnVsbDsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFJldHVybnMgd2hldGhlciB0aGUgaXRlbSBpcyBjdXJyZW50bHkgc2VsZWN0ZWQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7Kn0gaXRlbSBJdGVtIGZyb20gYGl0ZW1zYCBhcnJheSB0byB0ZXN0CiAgICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgdGhlIGl0ZW0gaXMgc2VsZWN0ZWQKICAgICAgICovCiAgICAgIGlzU2VsZWN0ZWQoaXRlbSkgewogICAgICAgIHJldHVybiB0aGlzLl9fc2VsZWN0ZWRNYXAuaGFzKGl0ZW0pOwogICAgICB9CgogICAgICAvKioKICAgICAgICogUmV0dXJucyB3aGV0aGVyIHRoZSBpdGVtIGlzIGN1cnJlbnRseSBzZWxlY3RlZC4KICAgICAgICoKICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGlkeCBJbmRleCBmcm9tIGBpdGVtc2AgYXJyYXkgdG8gdGVzdAogICAgICAgKiBAcmV0dXJuIHtib29sZWFufSBXaGV0aGVyIHRoZSBpdGVtIGlzIHNlbGVjdGVkCiAgICAgICAqLwogICAgICBpc0luZGV4U2VsZWN0ZWQoaWR4KSB7CiAgICAgICAgcmV0dXJuIHRoaXMuaXNTZWxlY3RlZCh0aGlzLml0ZW1zW2lkeF0pOwogICAgICB9CgogICAgICBfX2Rlc2VsZWN0Q2hhbmdlZElkeChpZHgpIHsKICAgICAgICBsZXQgc2lkeCA9IHRoaXMuX19zZWxlY3RlZEluZGV4Rm9ySXRlbUluZGV4KGlkeCk7CiAgICAgICAgaWYgKHNpZHggPj0gMCkgewogICAgICAgICAgbGV0IGkgPSAwOwogICAgICAgICAgdGhpcy5fX3NlbGVjdGVkTWFwLmZvckVhY2goKGlkeCwgaXRlbSkgPT4gewogICAgICAgICAgICBpZiAoc2lkeCA9PSBpKyspIHsKICAgICAgICAgICAgICB0aGlzLmRlc2VsZWN0KGl0ZW0pOwogICAgICAgICAgICB9CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIF9fc2VsZWN0ZWRJbmRleEZvckl0ZW1JbmRleChpZHgpIHsKICAgICAgICBsZXQgc2VsZWN0ZWQgPSB0aGlzLl9fZGF0YUxpbmtlZFBhdGhzWydpdGVtcy4nICsgaWR4XTsKICAgICAgICBpZiAoc2VsZWN0ZWQpIHsKICAgICAgICAgIHJldHVybiBwYXJzZUludChzZWxlY3RlZC5zbGljZSgnc2VsZWN0ZWQuJy5sZW5ndGgpLCAxMCk7CiAgICAgICAgfQogICAgICB9CgogICAgICAvKioKICAgICAgICogRGVzZWxlY3RzIHRoZSBnaXZlbiBpdGVtIGlmIGl0IGlzIGFscmVhZHkgc2VsZWN0ZWQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7Kn0gaXRlbSBJdGVtIGZyb20gYGl0ZW1zYCBhcnJheSB0byBkZXNlbGVjdAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgZGVzZWxlY3QoaXRlbSkgewogICAgICAgIGxldCBpZHggPSB0aGlzLl9fc2VsZWN0ZWRNYXAuZ2V0KGl0ZW0pOwogICAgICAgIGlmIChpZHggPj0gMCkgewogICAgICAgICAgdGhpcy5fX3NlbGVjdGVkTWFwLmRlbGV0ZShpdGVtKTsKICAgICAgICAgIGxldCBzaWR4OwogICAgICAgICAgaWYgKHRoaXMubXVsdGkpIHsKICAgICAgICAgICAgc2lkeCA9IHRoaXMuX19zZWxlY3RlZEluZGV4Rm9ySXRlbUluZGV4KGlkeCk7CiAgICAgICAgICB9CiAgICAgICAgICB0aGlzLl9fdXBkYXRlTGlua3MoKTsKICAgICAgICAgIGlmICh0aGlzLm11bHRpKSB7CiAgICAgICAgICAgIHRoaXMuc3BsaWNlKCdzZWxlY3RlZCcsIHNpZHgsIDEpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdGhpcy5zZWxlY3RlZCA9IHRoaXMuc2VsZWN0ZWRJdGVtID0gbnVsbDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KCiAgICAgIC8qKgogICAgICAgKiBEZXNlbGVjdHMgdGhlIGdpdmVuIGluZGV4IGlmIGl0IGlzIGFscmVhZHkgc2VsZWN0ZWQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpZHggSW5kZXggZnJvbSBgaXRlbXNgIGFycmF5IHRvIGRlc2VsZWN0CiAgICAgICAqIEByZXR1cm4ge3ZvaWR9CiAgICAgICAqLwogICAgICBkZXNlbGVjdEluZGV4KGlkeCkgewogICAgICAgIHRoaXMuZGVzZWxlY3QodGhpcy5pdGVtc1tpZHhdKTsKICAgICAgfQoKICAgICAgLyoqCiAgICAgICAqIFNlbGVjdHMgdGhlIGdpdmVuIGl0ZW0uICBXaGVuIGB0b2dnbGVgIGlzIHRydWUsIHRoaXMgd2lsbCBhdXRvbWF0aWNhbGx5CiAgICAgICAqIGRlc2VsZWN0IHRoZSBpdGVtIGlmIGFscmVhZHkgc2VsZWN0ZWQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7Kn0gaXRlbSBJdGVtIGZyb20gYGl0ZW1zYCBhcnJheSB0byBzZWxlY3QKICAgICAgICogQHJldHVybiB7dm9pZH0KICAgICAgICovCiAgICAgIHNlbGVjdChpdGVtKSB7CiAgICAgICAgdGhpcy5zZWxlY3RJbmRleCh0aGlzLml0ZW1zLmluZGV4T2YoaXRlbSkpOwogICAgICB9CgogICAgICAvKioKICAgICAgICogU2VsZWN0cyB0aGUgZ2l2ZW4gaW5kZXguICBXaGVuIGB0b2dnbGVgIGlzIHRydWUsIHRoaXMgd2lsbCBhdXRvbWF0aWNhbGx5CiAgICAgICAqIGRlc2VsZWN0IHRoZSBpdGVtIGlmIGFscmVhZHkgc2VsZWN0ZWQuCiAgICAgICAqCiAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpZHggSW5kZXggZnJvbSBgaXRlbXNgIGFycmF5IHRvIHNlbGVjdAogICAgICAgKiBAcmV0dXJuIHt2b2lkfQogICAgICAgKi8KICAgICAgc2VsZWN0SW5kZXgoaWR4KSB7CiAgICAgICAgbGV0IGl0ZW0gPSB0aGlzLml0ZW1zW2lkeF07CiAgICAgICAgaWYgKCF0aGlzLmlzU2VsZWN0ZWQoaXRlbSkpIHsKICAgICAgICAgIGlmICghdGhpcy5tdWx0aSkgewogICAgICAgICAgICB0aGlzLl9fc2VsZWN0ZWRNYXAuY2xlYXIoKTsKICAgICAgICAgIH0KICAgICAgICAgIHRoaXMuX19zZWxlY3RlZE1hcC5zZXQoaXRlbSwgaWR4KTsKICAgICAgICAgIHRoaXMuX191cGRhdGVMaW5rcygpOwogICAgICAgICAgaWYgKHRoaXMubXVsdGkpIHsKICAgICAgICAgICAgdGhpcy5wdXNoKCdzZWxlY3RlZCcsIGl0ZW0pOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdGhpcy5zZWxlY3RlZCA9IHRoaXMuc2VsZWN0ZWRJdGVtID0gaXRlbTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgaWYgKHRoaXMudG9nZ2xlKSB7CiAgICAgICAgICB0aGlzLmRlc2VsZWN0SW5kZXgoaWR4KTsKICAgICAgICB9CiAgICAgIH0KCiAgICB9CgogICAgcmV0dXJuIEFycmF5U2VsZWN0b3JNaXhpbjsKCiAgfSk7CgogIC8vIGV4cG9ydCBtaXhpbgogIFBvbHltZXIuQXJyYXlTZWxlY3Rvck1peGluID0gQXJyYXlTZWxlY3Rvck1peGluOwoKICAvKioKICAgKiBAY29uc3RydWN0b3IKICAgKiBAZXh0ZW5kcyB7UG9seW1lci5FbGVtZW50fQogICAqIEBpbXBsZW1lbnRzIHtQb2x5bWVyX0FycmF5U2VsZWN0b3JNaXhpbn0KICAgKiBAcHJpdmF0ZQogICAqLwogIGxldCBiYXNlQXJyYXlTZWxlY3RvciA9IEFycmF5U2VsZWN0b3JNaXhpbihQb2x5bWVyLkVsZW1lbnQpOwoKICAvKioKICAgKiBFbGVtZW50IGltcGxlbWVudGluZyB0aGUgYFBvbHltZXIuQXJyYXlTZWxlY3RvcmAgbWl4aW4sIHdoaWNoIHJlY29yZHMKICAgKiBkeW5hbWljIGFzc29jaWF0aW9ucyBiZXR3ZWVuIGl0ZW0gcGF0aHMgaW4gYSBtYXN0ZXIgYGl0ZW1zYCBhcnJheSBhbmQgYQogICAqIGBzZWxlY3RlZGAgYXJyYXkgc3VjaCB0aGF0IHBhdGggY2hhbmdlcyB0byB0aGUgbWFzdGVyIGFycmF5IChhdCB0aGUgaG9zdCkKICAgKiBlbGVtZW50IG9yIGVsc2V3aGVyZSB2aWEgZGF0YS1iaW5kaW5nKSBhcmUgY29ycmVjdGx5IHByb3BhZ2F0ZWQgdG8gaXRlbXMKICAgKiBpbiB0aGUgc2VsZWN0ZWQgYXJyYXkgYW5kIHZpY2UtdmVyc2EuCiAgICoKICAgKiBUaGUgYGl0ZW1zYCBwcm9wZXJ0eSBhY2NlcHRzIGFuIGFycmF5IG9mIHVzZXIgZGF0YSwgYW5kIHZpYSB0aGUKICAgKiBgc2VsZWN0KGl0ZW0pYCBhbmQgYGRlc2VsZWN0KGl0ZW0pYCBBUEksIHVwZGF0ZXMgdGhlIGBzZWxlY3RlZGAgcHJvcGVydHkKICAgKiB3aGljaCBtYXkgYmUgYm91bmQgdG8gb3RoZXIgcGFydHMgb2YgdGhlIGFwcGxpY2F0aW9uLCBhbmQgYW55IGNoYW5nZXMgdG8KICAgKiBzdWItZmllbGRzIG9mIGBzZWxlY3RlZGAgaXRlbShzKSB3aWxsIGJlIGtlcHQgaW4gc3luYyB3aXRoIGl0ZW1zIGluIHRoZQogICAqIGBpdGVtc2AgYXJyYXkuICBXaGVuIGBtdWx0aWAgaXMgZmFsc2UsIGBzZWxlY3RlZGAgaXMgYSBwcm9wZXJ0eQogICAqIHJlcHJlc2VudGluZyB0aGUgbGFzdCBzZWxlY3RlZCBpdGVtLiAgV2hlbiBgbXVsdGlgIGlzIHRydWUsIGBzZWxlY3RlZGAKICAgKiBpcyBhbiBhcnJheSBvZiBtdWx0aXBseSBzZWxlY3RlZCBpdGVtcy4KICAgKgogICAqIEV4YW1wbGU6CiAgICoKICAgKiBgYGBodG1sCiAgICogPGRvbS1tb2R1bGUgaWQ9ImVtcGxveWVlLWxpc3QiPgogICAqCiAgICogICA8dGVtcGxhdGU+CiAgICoKICAgKiAgICAgPGRpdj4gRW1wbG95ZWUgbGlzdDogPC9kaXY+CiAgICogICAgIDxkb20tcmVwZWF0IGlkPSJlbXBsb3llZUxpc3QiIGl0ZW1zPSJ7e2VtcGxveWVlc319Ij4KICAgKiAgICAgICA8dGVtcGxhdGU+CiAgICogICAgICAgICA8ZGl2PkZpcnN0IG5hbWU6IDxzcGFuPnt7aXRlbS5maXJzdH19PC9zcGFuPjwvZGl2PgogICAqICAgICAgICAgICA8ZGl2Pkxhc3QgbmFtZTogPHNwYW4+e3tpdGVtLmxhc3R9fTwvc3Bhbj48L2Rpdj4KICAgKiAgICAgICAgICAgPGJ1dHRvbiBvbi1jbGljaz0idG9nZ2xlU2VsZWN0aW9uIj5TZWxlY3Q8L2J1dHRvbj4KICAgKiAgICAgICA8L3RlbXBsYXRlPgogICAqICAgICA8L2RvbS1yZXBlYXQ+CiAgICoKICAgKiAgICAgPGFycmF5LXNlbGVjdG9yIGlkPSJzZWxlY3RvciIgaXRlbXM9Int7ZW1wbG95ZWVzfX0iIHNlbGVjdGVkPSJ7e3NlbGVjdGVkfX0iIG11bHRpIHRvZ2dsZT48L2FycmF5LXNlbGVjdG9yPgogICAqCiAgICogICAgIDxkaXY+IFNlbGVjdGVkIGVtcGxveWVlczogPC9kaXY+CiAgICogICAgIDxkb20tcmVwZWF0IGl0ZW1zPSJ7e3NlbGVjdGVkfX0iPgogICAqICAgICAgIDx0ZW1wbGF0ZT4KICAgKiAgICAgICAgIDxkaXY+Rmlyc3QgbmFtZTogPHNwYW4+e3tpdGVtLmZpcnN0fX08L3NwYW4+PC9kaXY+CiAgICogICAgICAgICA8ZGl2Pkxhc3QgbmFtZTogPHNwYW4+e3tpdGVtLmxhc3R9fTwvc3Bhbj48L2Rpdj4KICAgKiAgICAgICA8L3RlbXBsYXRlPgogICAqICAgICA8L2RvbS1yZXBlYXQ+CiAgICoKICAgKiAgIDwvdGVtcGxhdGU+CiAgICoKICAgKiA8L2RvbS1tb2R1bGU+CiAgICogYGBgCiAgICoKICAgKiBgYGBqcwogICAqY2xhc3MgRW1wbG95ZWVMaXN0IGV4dGVuZHMgUG9seW1lci5FbGVtZW50IHsKICAgKiAgc3RhdGljIGdldCBpcygpIHsgcmV0dXJuICdlbXBsb3llZS1saXN0JzsgfQogICAqICBzdGF0aWMgZ2V0IHByb3BlcnRpZXMoKSB7CiAgICogICAgcmV0dXJuIHsKICAgKiAgICAgIGVtcGxveWVlczogewogICAqICAgICAgICB2YWx1ZSgpIHsKICAgKiAgICAgICAgICByZXR1cm4gWwogICAqICAgICAgICAgICAge2ZpcnN0OiAnQm9iJywgbGFzdDogJ1NtaXRoJ30sCiAgICogICAgICAgICAgICB7Zmlyc3Q6ICdTYWxseScsIGxhc3Q6ICdKb2huc29uJ30sCiAgICogICAgICAgICAgICAuLi4KICAgKiAgICAgICAgICBdOwogICAqICAgICAgICB9CiAgICogICAgICB9CiAgICogICAgfTsKICAgKiAgfQogICAqICB0b2dnbGVTZWxlY3Rpb24oZSkgewogICAqICAgIGxldCBpdGVtID0gdGhpcy4kLmVtcGxveWVlTGlzdC5pdGVtRm9yRWxlbWVudChlLnRhcmdldCk7CiAgICogICAgdGhpcy4kLnNlbGVjdG9yLnNlbGVjdChpdGVtKTsKICAgKiAgfQogICAqfQogICAqIGBgYAogICAqCiAgICogQHBvbHltZXIKICAgKiBAY3VzdG9tRWxlbWVudAogICAqIEBleHRlbmRzIHtiYXNlQXJyYXlTZWxlY3Rvcn0KICAgKiBAYXBwbGllc01peGluIFBvbHltZXIuQXJyYXlTZWxlY3Rvck1peGluCiAgICogQG1lbWJlcm9mIFBvbHltZXIKICAgKiBAc3VtbWFyeSBDdXN0b20gZWxlbWVudCB0aGF0IGxpbmtzIHBhdGhzIGJldHdlZW4gYW4gaW5wdXQgYGl0ZW1zYCBhcnJheSBhbmQKICAgKiAgIGFuIG91dHB1dCBgc2VsZWN0ZWRgIGl0ZW0gb3IgYXJyYXkgYmFzZWQgb24gY2FsbHMgdG8gaXRzIHNlbGVjdGlvbiBBUEkuCiAgICovCiAgY2xhc3MgQXJyYXlTZWxlY3RvciBleHRlbmRzIGJhc2VBcnJheVNlbGVjdG9yIHsKICAgIC8vIE5vdCBuZWVkZWQgdG8gZmluZCB0ZW1wbGF0ZTsgY2FuIGJlIHJlbW92ZWQgb25jZSB0aGUgYW5hbHl6ZXIKICAgIC8vIGNhbiBmaW5kIHRoZSB0YWcgbmFtZSBmcm9tIGN1c3RvbUVsZW1lbnRzLmRlZmluZSBjYWxsCiAgICBzdGF0aWMgZ2V0IGlzKCkgeyByZXR1cm4gJ2FycmF5LXNlbGVjdG9yJzsgfQogIH0KICBjdXN0b21FbGVtZW50cy5kZWZpbmUoQXJyYXlTZWxlY3Rvci5pcywgQXJyYXlTZWxlY3Rvcik7CgogIC8qKiBAY29uc3QgKi8KICBQb2x5bWVyLkFycmF5U2VsZWN0b3IgPSBBcnJheVNlbGVjdG9yOwoKfSkoKTsKCjwvc2NyaXB0PjxzY3JpcHQ+KGZ1bmN0aW9uKCl7LyoKCkNvcHlyaWdodCAoYykgMjAxNyBUaGUgUG9seW1lciBQcm9qZWN0IEF1dGhvcnMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuClRoaXMgY29kZSBtYXkgb25seSBiZSB1c2VkIHVuZGVyIHRoZSBCU0Qgc3R5bGUgbGljZW5zZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vTElDRU5TRS50eHQKVGhlIGNvbXBsZXRlIHNldCBvZiBhdXRob3JzIG1heSBiZSBmb3VuZCBhdCBodHRwOi8vcG9seW1lci5naXRodWIuaW8vQVVUSE9SUy50eHQKVGhlIGNvbXBsZXRlIHNldCBvZiBjb250cmlidXRvcnMgbWF5IGJlIGZvdW5kIGF0IGh0dHA6Ly9wb2x5bWVyLmdpdGh1Yi5pby9DT05UUklCVVRPUlMudHh0CkNvZGUgZGlzdHJpYnV0ZWQgYnkgR29vZ2xlIGFzIHBhcnQgb2YgdGhlIHBvbHltZXIgcHJvamVjdCBpcyBhbHNvCnN1YmplY3QgdG8gYW4gYWRkaXRpb25hbCBJUCByaWdodHMgZ3JhbnQgZm91bmQgYXQgaHR0cDovL3BvbHltZXIuZ2l0aHViLmlvL1BBVEVOVFMudHh0CiovCid1c2Ugc3RyaWN0Jzt2YXIgYz1udWxsLGY9d2luZG93LkhUTUxJbXBvcnRzJiZ3aW5kb3cuSFRNTEltcG9ydHMud2hlblJlYWR5fHxudWxsLGc7ZnVuY3Rpb24gaChhKXtyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24oKXtmP2YoYSk6KGN8fChjPW5ldyBQcm9taXNlKGZ1bmN0aW9uKGEpe2c9YX0pLCJjb21wbGV0ZSI9PT1kb2N1bWVudC5yZWFkeVN0YXRlP2coKTpkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJyZWFkeXN0YXRlY2hhbmdlIixmdW5jdGlvbigpeyJjb21wbGV0ZSI9PT1kb2N1bWVudC5yZWFkeVN0YXRlJiZnKCl9KSksYy50aGVuKGZ1bmN0aW9uKCl7YSYmYSgpfSkpfSl9O3ZhciBrPW51bGwsbD1udWxsO2Z1bmN0aW9uIG0oKXt0aGlzLmN1c3RvbVN0eWxlcz1bXTt0aGlzLmVucXVldWVkPSExO2goZnVuY3Rpb24oKXt3aW5kb3cuU2hhZHlDU1MuZmx1c2hDdXN0b21TdHlsZXMmJndpbmRvdy5TaGFkeUNTUy5mbHVzaEN1c3RvbVN0eWxlcygpfSl9ZnVuY3Rpb24gbihhKXshYS5lbnF1ZXVlZCYmbCYmKGEuZW5xdWV1ZWQ9ITAsaChsKSl9bS5wcm90b3R5cGUuYz1mdW5jdGlvbihhKXthLl9fc2VlbkJ5U2hhZHlDU1N8fChhLl9fc2VlbkJ5U2hhZHlDU1M9ITAsdGhpcy5jdXN0b21TdHlsZXMucHVzaChhKSxuKHRoaXMpKX07bS5wcm90b3R5cGUuYj1mdW5jdGlvbihhKXtpZihhLl9fc2hhZHlDU1NDYWNoZWRTdHlsZSlyZXR1cm4gYS5fX3NoYWR5Q1NTQ2FjaGVkU3R5bGU7dmFyIGI7YS5nZXRTdHlsZT9iPWEuZ2V0U3R5bGUoKTpiPWE7cmV0dXJuIGJ9OwptLnByb3RvdHlwZS5hPWZ1bmN0aW9uKCl7Zm9yKHZhciBhPXRoaXMuY3VzdG9tU3R5bGVzLGI9MDtiPGEubGVuZ3RoO2IrKyl7dmFyIGQ9YVtiXTtpZighZC5fX3NoYWR5Q1NTQ2FjaGVkU3R5bGUpe3ZhciBlPXRoaXMuYihkKTtlJiYoZT1lLl9fYXBwbGllZEVsZW1lbnR8fGUsayYmayhlKSxkLl9fc2hhZHlDU1NDYWNoZWRTdHlsZT1lKX19cmV0dXJuIGF9O20ucHJvdG90eXBlLmFkZEN1c3RvbVN0eWxlPW0ucHJvdG90eXBlLmM7bS5wcm90b3R5cGUuZ2V0U3R5bGVGb3JDdXN0b21TdHlsZT1tLnByb3RvdHlwZS5iO20ucHJvdG90eXBlLnByb2Nlc3NTdHlsZXM9bS5wcm90b3R5cGUuYTsKT2JqZWN0LmRlZmluZVByb3BlcnRpZXMobS5wcm90b3R5cGUse3RyYW5zZm9ybUNhbGxiYWNrOntnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4ga30sc2V0OmZ1bmN0aW9uKGEpe2s9YX19LHZhbGlkYXRlQ2FsbGJhY2s6e2dldDpmdW5jdGlvbigpe3JldHVybiBsfSxzZXQ6ZnVuY3Rpb24oYSl7dmFyIGI9ITE7bHx8KGI9ITApO2w9YTtiJiZuKHRoaXMpfX19KTtmdW5jdGlvbiBwKGEsYil7Zm9yKHZhciBkIGluIGIpbnVsbD09PWQ/YS5zdHlsZS5yZW1vdmVQcm9wZXJ0eShkKTphLnN0eWxlLnNldFByb3BlcnR5KGQsYltkXSl9O3ZhciBxPSEod2luZG93LlNoYWR5RE9NJiZ3aW5kb3cuU2hhZHlET00uaW5Vc2UpLHI7ZnVuY3Rpb24gdChhKXtyPWEmJmEuc2hpbWNzc3Byb3BlcnRpZXM/ITE6cXx8IShuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9BcHBsZVdlYktpdFwvNjAxfEVkZ2VcLzE1Lyl8fCF3aW5kb3cuQ1NTfHwhQ1NTLnN1cHBvcnRzfHwhQ1NTLnN1cHBvcnRzKCJib3gtc2hhZG93IiwiMCAwIDAgdmFyKC0tZm9vKSIpKX12YXIgdTt3aW5kb3cuU2hhZHlDU1MmJnZvaWQgMCE9PXdpbmRvdy5TaGFkeUNTUy5jc3NCdWlsZCYmKHU9d2luZG93LlNoYWR5Q1NTLmNzc0J1aWxkKTt2YXIgdj0hKCF3aW5kb3cuU2hhZHlDU1N8fCF3aW5kb3cuU2hhZHlDU1MuZGlzYWJsZVJ1bnRpbWUpOwp3aW5kb3cuU2hhZHlDU1MmJnZvaWQgMCE9PXdpbmRvdy5TaGFkeUNTUy5uYXRpdmVDc3M/cj13aW5kb3cuU2hhZHlDU1MubmF0aXZlQ3NzOndpbmRvdy5TaGFkeUNTUz8odCh3aW5kb3cuU2hhZHlDU1MpLHdpbmRvdy5TaGFkeUNTUz12b2lkIDApOnQod2luZG93LldlYkNvbXBvbmVudHMmJndpbmRvdy5XZWJDb21wb25lbnRzLmZsYWdzKTt2YXIgdz1yLHg9dTt2YXIgeT1uZXcgbTt3aW5kb3cuU2hhZHlDU1N8fCh3aW5kb3cuU2hhZHlDU1M9e3ByZXBhcmVUZW1wbGF0ZTpmdW5jdGlvbigpe30scHJlcGFyZVRlbXBsYXRlRG9tOmZ1bmN0aW9uKCl7fSxwcmVwYXJlVGVtcGxhdGVTdHlsZXM6ZnVuY3Rpb24oKXt9LHN0eWxlU3VidHJlZTpmdW5jdGlvbihhLGIpe3kuYSgpO3AoYSxiKX0sc3R5bGVFbGVtZW50OmZ1bmN0aW9uKCl7eS5hKCl9LHN0eWxlRG9jdW1lbnQ6ZnVuY3Rpb24oYSl7eS5hKCk7cChkb2N1bWVudC5ib2R5LGEpfSxnZXRDb21wdXRlZFN0eWxlVmFsdWU6ZnVuY3Rpb24oYSxiKXtyZXR1cm4oYT13aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShhKS5nZXRQcm9wZXJ0eVZhbHVlKGIpKT9hLnRyaW0oKToiIn0sZmx1c2hDdXN0b21TdHlsZXM6ZnVuY3Rpb24oKXt9LG5hdGl2ZUNzczp3LG5hdGl2ZVNoYWRvdzpxLGNzc0J1aWxkOngsZGlzYWJsZVJ1bnRpbWU6dn0pO3dpbmRvdy5TaGFkeUNTUy5DdXN0b21TdHlsZUludGVyZmFjZT15O30pLmNhbGwodGhpcyk7CgoKPC9zY3JpcHQ+PHNjcmlwdD4KKGZ1bmN0aW9uKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgY29uc3QgYXR0ciA9ICdpbmNsdWRlJzsKCiAgY29uc3QgQ3VzdG9tU3R5bGVJbnRlcmZhY2UgPSB3aW5kb3cuU2hhZHlDU1MuQ3VzdG9tU3R5bGVJbnRlcmZhY2U7CgogIC8qKgogICAqIEN1c3RvbSBlbGVtZW50IGZvciBkZWZpbmluZyBzdHlsZXMgaW4gdGhlIG1haW4gZG9jdW1lbnQgdGhhdCBjYW4gdGFrZQogICAqIGFkdmFudGFnZSBvZiBbc2hhZHkgRE9NXShodHRwczovL2dpdGh1Yi5jb20vd2ViY29tcG9uZW50cy9zaGFkeWNzcykgc2hpbXMKICAgKiBmb3Igc3R5bGUgZW5jYXBzdWxhdGlvbiwgY3VzdG9tIHByb3BlcnRpZXMsIGFuZCBjdXN0b20gbWl4aW5zLgogICAqCiAgICogLSBEb2N1bWVudCBzdHlsZXMgZGVmaW5lZCBpbiBhIGA8Y3VzdG9tLXN0eWxlPmAgYXJlIHNoaW1tZWQgdG8gZW5zdXJlIHRoZXkKICAgKiAgIGRvIG5vdCBsZWFrIGludG8gbG9jYWwgRE9NIHdoZW4gcnVubmluZyBvbiBicm93c2VycyB3aXRob3V0IG5hdGl2ZQogICAqICAgU2hhZG93IERPTS4KICAgKiAtIEN1c3RvbSBwcm9wZXJ0aWVzIGNhbiBiZSBkZWZpbmVkIGluIGEgYDxjdXN0b20tc3R5bGU+YC4gVXNlIHRoZSBgaHRtbGAgc2VsZWN0b3IKICAgKiAgIHRvIGRlZmluZSBjdXN0b20gcHJvcGVydGllcyB0aGF0IGFwcGx5IHRvIGFsbCBjdXN0b20gZWxlbWVudHMuCiAgICogLSBDdXN0b20gbWl4aW5zIGNhbiBiZSBkZWZpbmVkIGluIGEgYDxjdXN0b20tc3R5bGU+YCwgaWYgeW91IGltcG9ydCB0aGUgb3B0aW9uYWwKICAgKiAgIFthcHBseSBzaGltXShodHRwczovL2dpdGh1Yi5jb20vd2ViY29tcG9uZW50cy9zaGFkeWNzcyNhYm91dC1hcHBseXNoaW0pCiAgICogICAoYHNoYWR5Y3NzL2FwcGx5LXNoaW0uaHRtbGApLgogICAqCiAgICogVG8gdXNlOgogICAqCiAgICogLSBJbXBvcnQgYGN1c3RvbS1zdHlsZS5odG1sYC4KICAgKiAtIFBsYWNlIGEgYDxjdXN0b20tc3R5bGU+YCBlbGVtZW50IGluIHRoZSBtYWluIGRvY3VtZW50LCB3cmFwcGluZyBhbiBpbmxpbmUgYDxzdHlsZT5gIHRhZyB0aGF0CiAgICogICBjb250YWlucyB0aGUgQ1NTIHJ1bGVzIHlvdSB3YW50IHRvIHNoaW0uCiAgICoKICAgKiBGb3IgZXhhbXBsZToKICAgKgogICAqIGBgYGh0bWwKICAgKiA8IS0tIGltcG9ydCBhcHBseSBzaGltLS1vbmx5IHJlcXVpcmVkIGlmIHVzaW5nIG1peGlucyAtLT4KICAgKiA8bGluayByZWw9ImltcG9ydCIgaHJlZj0iYm93ZXJfY29tcG9uZW50cy9zaGFkeWNzcy9hcHBseS1zaGltLmh0bWwiPgogICAqIDwhLS0gaW1wb3J0IGN1c3RvbS1zdHlsZSBlbGVtZW50IC0tPgogICAqIDxsaW5rIHJlbD0iaW1wb3J0IiBocmVmPSJib3dlcl9jb21wb25lbnRzL3BvbHltZXIvbGliL2VsZW1lbnRzL2N1c3RvbS1zdHlsZS5odG1sIj4KICAgKgogICAqIDxjdXN0b20tc3R5bGU+CiAgICogICA8c3R5bGU+CiAgICogICAgIGh0bWwgewogICAqICAgICAgIC0tY3VzdG9tLWNvbG9yOiBibHVlOwogICAqICAgICAgIC0tY3VzdG9tLW1peGluOiB7CiAgICogICAgICAgICBmb250LXdlaWdodDogYm9sZDsKICAgKiAgICAgICAgIGNvbG9yOiByZWQ7CiAgICogICAgICAgfTsKICAgKiAgICAgfQogICAqICAgPC9zdHlsZT4KICAgKiA8L2N1c3RvbS1zdHlsZT4KICAgKiBgYGAKICAgKgogICAqIEBjdXN0b21FbGVtZW50CiAgICogQGV4dGVuZHMgSFRNTEVsZW1lbnQKICAgKiBAbWVtYmVyb2YgUG9seW1lcgogICAqIEBzdW1tYXJ5IEN1c3RvbSBlbGVtZW50IGZvciBkZWZpbmluZyBzdHlsZXMgaW4gdGhlIG1haW4gZG9jdW1lbnQgdGhhdCBjYW4KICAgKiAgIHRha2UgYWR2YW50YWdlIG9mIFBvbHltZXIncyBzdHlsZSBzY29waW5nIGFuZCBjdXN0b20gcHJvcGVydGllcyBzaGltcy4KICAgKi8KICBjbGFzcyBDdXN0b21TdHlsZSBleHRlbmRzIEhUTUxFbGVtZW50IHsKICAgIGNvbnN0cnVjdG9yKCkgewogICAgICBzdXBlcigpOwogICAgICB0aGlzLl9zdHlsZSA9IG51bGw7CiAgICAgIEN1c3RvbVN0eWxlSW50ZXJmYWNlLmFkZEN1c3RvbVN0eWxlKHRoaXMpOwogICAgfQogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBsaWdodC1ET00gYDxzdHlsZT5gIGNoaWxkIHRoaXMgZWxlbWVudCB3cmFwcy4gIFVwb24gZmlyc3QKICAgICAqIGNhbGwgYW55IHN0eWxlIG1vZHVsZXMgcmVmZXJlbmNlZCB2aWEgdGhlIGBpbmNsdWRlYCBhdHRyaWJ1dGUgd2lsbCBiZQogICAgICogY29uY2F0ZW5hdGVkIHRvIHRoaXMgZWxlbWVudCdzIGA8c3R5bGU+YC4KICAgICAqCiAgICAgKiBAcmV0dXJuIHtIVE1MU3R5bGVFbGVtZW50fSBUaGlzIGVsZW1lbnQncyBsaWdodC1ET00gYDxzdHlsZT5gCiAgICAgKi8KICAgIGdldFN0eWxlKCkgewogICAgICBpZiAodGhpcy5fc3R5bGUpIHsKICAgICAgICByZXR1cm4gdGhpcy5fc3R5bGU7CiAgICAgIH0KICAgICAgY29uc3Qgc3R5bGUgPSAvKiogQHR5cGUge0hUTUxTdHlsZUVsZW1lbnR9ICovKHRoaXMucXVlcnlTZWxlY3Rvcignc3R5bGUnKSk7CiAgICAgIGlmICghc3R5bGUpIHsKICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgfQogICAgICB0aGlzLl9zdHlsZSA9IHN0eWxlOwogICAgICBjb25zdCBpbmNsdWRlID0gc3R5bGUuZ2V0QXR0cmlidXRlKGF0dHIpOwogICAgICBpZiAoaW5jbHVkZSkgewogICAgICAgIHN0eWxlLnJlbW92ZUF0dHJpYnV0ZShhdHRyKTsKICAgICAgICBzdHlsZS50ZXh0Q29udGVudCA9IFBvbHltZXIuU3R5bGVHYXRoZXIuY3NzRnJvbU1vZHVsZXMoaW5jbHVkZSkgKyBzdHlsZS50ZXh0Q29udGVudDsKICAgICAgfQogICAgICAvKgogICAgICBIVE1MIEltcG9ydHMgc3R5bGluZyB0aGUgbWFpbiBkb2N1bWVudCBhcmUgZGVwcmVjYXRlZCBpbiBDaHJvbWUKICAgICAgaHR0cHM6Ly9jcmJ1Zy5jb20vNTIzOTUyCgogICAgICBJZiB0aGlzIGVsZW1lbnQgaXMgbm90IGluIHRoZSBtYWluIGRvY3VtZW50LCB0aGVuIGl0IG11c3QgYmUgaW4gYW4gSFRNTCBJbXBvcnQgZG9jdW1lbnQuCiAgICAgIEluIHRoYXQgY2FzZSwgbW92ZSB0aGUgY3VzdG9tIHN0eWxlIHRvIHRoZSBtYWluIGRvY3VtZW50LgoKICAgICAgVGhlIG9yZGVyaW5nIG9mIGA8Y3VzdG9tLXN0eWxlPmAgc2hvdWxkIHN0YXkgdGhlIHNhbWUgYXMgd2hlbiBsb2FkZWQgYnkgSFRNTCBJbXBvcnRzLCBidXQgdGhlcmUgbWF5IGJlIG9kZAogICAgICBjYXNlcyBvZiBvcmRlcmluZyB3LnIudCB0aGUgbWFpbiBkb2N1bWVudCBzdHlsZXMuCiAgICAgICovCiAgICAgIGlmICh0aGlzLm93bmVyRG9jdW1lbnQgIT09IHdpbmRvdy5kb2N1bWVudCkgewogICAgICAgIHdpbmRvdy5kb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHRoaXMpOwogICAgICB9CiAgICAgIHJldHVybiB0aGlzLl9zdHlsZTsKICAgIH0KICB9CgogIHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2N1c3RvbS1zdHlsZScsIEN1c3RvbVN0eWxlKTsKCiAgLyoqIEBjb25zdCAqLwogIFBvbHltZXIuQ3VzdG9tU3R5bGUgPSBDdXN0b21TdHlsZTsKfSkoKTsKPC9zY3JpcHQ+PHNjcmlwdD4KKGZ1bmN0aW9uKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgbGV0IG11dGFibGVQcm9wZXJ0eUNoYW5nZTsKICAvKiogQHN1cHByZXNzIHttaXNzaW5nUHJvcGVydGllc30gKi8KICAoKCkgPT4gewogICAgbXV0YWJsZVByb3BlcnR5Q2hhbmdlID0gUG9seW1lci5NdXRhYmxlRGF0YS5fbXV0YWJsZVByb3BlcnR5Q2hhbmdlOwogIH0pKCk7CgogIC8qKgogICAqIExlZ2FjeSBlbGVtZW50IGJlaGF2aW9yIHRvIHNraXAgc3RyaWN0IGRpcnR5LWNoZWNraW5nIGZvciBvYmplY3RzIGFuZCBhcnJheXMsCiAgICogKGFsd2F5cyBjb25zaWRlciB0aGVtIHRvIGJlICJkaXJ0eSIpIGZvciB1c2Ugb24gbGVnYWN5IEFQSSBQb2x5bWVyIGVsZW1lbnRzLgogICAqCiAgICogQnkgZGVmYXVsdCwgYFBvbHltZXIuUHJvcGVydHlFZmZlY3RzYCBwZXJmb3JtcyBzdHJpY3QgZGlydHkgY2hlY2tpbmcgb24KICAgKiBvYmplY3RzLCB3aGljaCBtZWFucyB0aGF0IGFueSBkZWVwIG1vZGlmaWNhdGlvbnMgdG8gYW4gb2JqZWN0IG9yIGFycmF5IHdpbGwKICAgKiBub3QgYmUgcHJvcGFnYXRlZCB1bmxlc3MgImltbXV0YWJsZSIgZGF0YSBwYXR0ZXJucyBhcmUgdXNlZCAoaS5lLiBhbGwgb2JqZWN0CiAgICogcmVmZXJlbmNlcyBmcm9tIHRoZSByb290IHRvIHRoZSBtdXRhdGlvbiB3ZXJlIGNoYW5nZWQpLgogICAqCiAgICogUG9seW1lciBhbHNvIHByb3ZpZGVzIGEgcHJvcHJpZXRhcnkgZGF0YSBtdXRhdGlvbiBhbmQgcGF0aCBub3RpZmljYXRpb24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment