{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "Lesson3-AWSML-Exploratory-Data-Analysis.ipynb", "version": "0.3.2", "provenance": [], "collapsed_sections": [ "bq4VmHjPpMOR", "hYtm6PMXsrQd", "m3vq6mPGt0_L", "DKHT-auXt8j5", "-DvJ7AqwuDSl", "0j1oxFY9d6hZ", "52KaE0sFbyWf" ], "include_colab_link": true }, "kernelspec": { "name": "python3", "display_name": "Python 3" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "view-in-github", "colab_type": "text" }, "source": [ "\"Open" ] }, { "metadata": { "id": "iwV-bBLUtTQu", "colab_type": "text" }, "cell_type": "markdown", "source": [ "# Lesson 3 Exploratory Data Analysis\n", "\n", "[Watch Lesson 3: Exploratory Data Analysis on AWS Video](https://learning.oreilly.com/videos/aws-certified-machine/9780135556597/9780135556597-ACML_01_03_00)" ] }, { "metadata": { "id": "c_Id55m6Jsbu", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Pragmatic AI Labs\n", "\n" ] }, { "metadata": { "id": "e5p96AqpSDZa", "colab_type": "text" }, "cell_type": "markdown", "source": [ "![alt text](https://paiml.com/images/logo_with_slogan_white_background.png)\n", "\n", "This notebook was produced by [Pragmatic AI Labs](https://paiml.com/). You can continue learning about these topics by:\n", "\n", "* Buying a copy of [Pragmatic AI: An Introduction to Cloud-Based Machine Learning](http://www.informit.com/store/pragmatic-ai-an-introduction-to-cloud-based-machine-9780134863863) from Informit.\n", "* Buying a copy of [Pragmatic AI: An Introduction to Cloud-Based Machine Learning](https://www.amazon.com/Pragmatic-AI-Introduction-Cloud-Based-Learning/dp/0134863860) from Amazon\n", "* Reading an online copy of [Pragmatic AI:Pragmatic AI: An Introduction to Cloud-Based Machine Learning](https://www.safaribooksonline.com/library/view/pragmatic-ai-an/9780134863924/)\n", "* Watching video [Essential Machine Learning and AI with Python and Jupyter Notebook-Video-SafariOnline](https://www.safaribooksonline.com/videos/essential-machine-learning/9780135261118) on Safari Books Online.\n", "* Watching video [AWS Certified Machine Learning-Speciality](https://learning.oreilly.com/videos/aws-certified-machine/9780135556597)\n", "* Purchasing video [Essential Machine Learning and AI with Python and Jupyter Notebook- Purchase Video](http://www.informit.com/store/essential-machine-learning-and-ai-with-python-and-jupyter-9780135261095)\n", "* Viewing more content at [noahgift.com](https://noahgift.com/)\n" ] }, { "metadata": { "id": "bq4VmHjPpMOR", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Load AWS API Keys" ] }, { "metadata": { "id": "aWrzIk7WpRoh", "colab_type": "text" }, "cell_type": "markdown", "source": [ "Put keys in local or remote GDrive: \n", "\n", "`cp ~/.aws/credentials /Users/myname/Google\\ Drive/awsml/`" ] }, { "metadata": { "id": "hPWO_zyRopXN", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Mount GDrive\n" ] }, { "metadata": { "id": "XI73HZNLobp4", "colab_type": "code", "outputId": "66f597a9-6c94-4ffd-b323-21869a4eb988", "colab": { "base_uri": "https://localhost:8080/", "height": 34 } }, "cell_type": "code", "source": [ "from google.colab import drive\n", "drive.mount('/content/gdrive', force_remount=True)" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Mounted at /content/gdrive\n" ], "name": "stdout" } ] }, { "metadata": { "id": "UNyzZwgmoxwm", "colab_type": "code", "outputId": "80a98691-3926-4666-82c7-f27f606fbfaf", "colab": { "base_uri": "https://localhost:8080/", "height": 34 } }, "cell_type": "code", "source": [ "import os;os.listdir(\"/content/gdrive/My Drive/awsml\")" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "['kaggle.json', 'credentials', 'config']" ] }, "metadata": { "tags": [] }, "execution_count": 27 } ] }, { "metadata": { "id": "fYu0ekUlqPk6", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Install Boto" ] }, { "metadata": { "id": "dJDDrUkWrYRY", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "!pip -q install boto3\n" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "FpJhrpSQsK5E", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Create API Config" ] }, { "metadata": { "id": "QxRwGOZtsN0-", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "!mkdir -p ~/.aws &&\\\n", " cp /content/gdrive/My\\ Drive/awsml/credentials ~/.aws/credentials " ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "Kj977UW3rph_", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Test Comprehend API Call" ] }, { "metadata": { "id": "P-A8Cia-raT0", "colab_type": "code", "outputId": "4290a9a8-667f-4b06-edf3-aa4c2ae121f2", "colab": { "base_uri": "https://localhost:8080/", "height": 238 } }, "cell_type": "code", "source": [ "import boto3\n", "comprehend = boto3.client(service_name='comprehend', region_name=\"us-east-1\")\n", "text = \"There is smoke in San Francisco\"\n", "comprehend.detect_sentiment(Text=text, LanguageCode='en')" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "{'ResponseMetadata': {'HTTPHeaders': {'connection': 'keep-alive',\n", " 'content-length': '160',\n", " 'content-type': 'application/x-amz-json-1.1',\n", " 'date': 'Thu, 22 Nov 2018 00:21:54 GMT',\n", " 'x-amzn-requestid': '9d69a0a9-edec-11e8-8560-532dc7aa62ea'},\n", " 'HTTPStatusCode': 200,\n", " 'RequestId': '9d69a0a9-edec-11e8-8560-532dc7aa62ea',\n", " 'RetryAttempts': 0},\n", " 'Sentiment': 'NEUTRAL',\n", " 'SentimentScore': {'Mixed': 0.008628507144749165,\n", " 'Negative': 0.1037612184882164,\n", " 'Neutral': 0.8582549691200256,\n", " 'Positive': 0.0293553676456213}}" ] }, "metadata": { "tags": [] }, "execution_count": 50 } ] }, { "metadata": { "id": "hYtm6PMXsrQd", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## 3.1 Data Visualization" ] }, { "metadata": { "id": "q5nioy1LuCTQ", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### AWS Quicksite" ] }, { "metadata": { "id": "9TIbWnzcYJ9w", "colab_type": "text" }, "cell_type": "markdown", "source": [ "\n", "\n", "* Business Intelligence Service\n", "* Creates Automated Visualizations\n", "\n", "\n", "\n", "![Quicksite](https://user-images.githubusercontent.com/58792/49444530-4890e800-f784-11e8-900f-417edd143eb2.png)" ] }, { "metadata": { "id": "g7hVS3d-nh0T", "colab_type": "text" }, "cell_type": "markdown", "source": [ "#### [Demo] Quicksite" ] }, { "metadata": { "id": "9NbCNan3ZLTF", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Part of EDA Cycle\n", "\n", "* used to detect outliers\n", "* See data Distribution" ] }, { "metadata": { "id": "Hk3QVRT5oFHT", "colab_type": "text" }, "cell_type": "markdown", "source": [ "[Demo] Plotly" ] }, { "metadata": { "id": "WirfPfS8zQ1G", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "df = pd.read_csv(\"https://raw.githubusercontent.com/noahgift/real_estate_ml/master/data/Zip_Zhvi_SingleFamilyResidence.csv\")\n" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "PQan_MCrP7eF", "colab_type": "text" }, "cell_type": "markdown", "source": [ "**Clean Up DataFrame**\n", "Rename RegionName to ZipCode and Change Zip Code to String\n", "\n" ] }, { "metadata": { "id": "93nEMwVWP5ic", "colab_type": "code", "outputId": "de69504c-1d73-4e12-9ec2-5c7a6ae9ea75", "colab": { "base_uri": "https://localhost:8080/", "height": 270 } }, "cell_type": "code", "source": [ "df.rename(columns={\"RegionName\":\"ZipCode\"}, inplace=True)\n", "df[\"ZipCode\"]=df[\"ZipCode\"].map(lambda x: \"{:.0f}\".format(x))\n", "df[\"RegionID\"]=df[\"RegionID\"].map(lambda x: \"{:.0f}\".format(x))\n", "df.head()" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
RegionIDZipCodeCityStateMetroCountyNameSizeRank1996-041996-051996-06...2016-122017-012017-022017-032017-042017-052017-062017-072017-082017-09
08465460657ChicagoILChicagoCook1.0420800.0423500.0426200.0...1097900.01098300.01094700.01088500.01081200.01073900.01064300.01054300.01048500.01044400.0
18461660614ChicagoILChicagoCook2.0542400.0546700.0551700.0...1522800.01525900.01525000.01526100.01528700.01526700.01518900.01515800.01519900.01525300.0
29314479936El PasoTXEl PasoEl Paso3.070900.071200.071100.0...114200.0114300.0114200.0114000.0113800.0114000.0114000.0113800.0113500.0113300.0
38464060640ChicagoILChicagoCook4.0298200.0297400.0295300.0...739400.0743100.0741500.0736300.0729500.0727700.0726000.0718800.0713400.0710900.0
46180710467New YorkNYNew YorkBronx5.0NaNNaNNaN...391600.0388900.0388800.0391100.0394400.0396900.0398600.0400500.0402600.0403700.0
\n", "

5 rows × 265 columns

\n", "
" ], "text/plain": [ " RegionID ZipCode City State Metro CountyName SizeRank 1996-04 \\\n", "0 84654 60657 Chicago IL Chicago Cook 1.0 420800.0 \n", "1 84616 60614 Chicago IL Chicago Cook 2.0 542400.0 \n", "2 93144 79936 El Paso TX El Paso El Paso 3.0 70900.0 \n", "3 84640 60640 Chicago IL Chicago Cook 4.0 298200.0 \n", "4 61807 10467 New York NY New York Bronx 5.0 NaN \n", "\n", " 1996-05 1996-06 ... 2016-12 2017-01 2017-02 2017-03 \\\n", "0 423500.0 426200.0 ... 1097900.0 1098300.0 1094700.0 1088500.0 \n", "1 546700.0 551700.0 ... 1522800.0 1525900.0 1525000.0 1526100.0 \n", "2 71200.0 71100.0 ... 114200.0 114300.0 114200.0 114000.0 \n", "3 297400.0 295300.0 ... 739400.0 743100.0 741500.0 736300.0 \n", "4 NaN NaN ... 391600.0 388900.0 388800.0 391100.0 \n", "\n", " 2017-04 2017-05 2017-06 2017-07 2017-08 2017-09 \n", "0 1081200.0 1073900.0 1064300.0 1054300.0 1048500.0 1044400.0 \n", "1 1528700.0 1526700.0 1518900.0 1515800.0 1519900.0 1525300.0 \n", "2 113800.0 114000.0 114000.0 113800.0 113500.0 113300.0 \n", "3 729500.0 727700.0 726000.0 718800.0 713400.0 710900.0 \n", "4 394400.0 396900.0 398600.0 400500.0 402600.0 403700.0 \n", "\n", "[5 rows x 265 columns]" ] }, "metadata": { "tags": [] }, "execution_count": 28 } ] }, { "metadata": { "id": "1HLi8XudQGW9", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "median_prices = df.median()\n", "marin_df = df[df[\"CountyName\"] == \"Marin\"].median()\n", "sf_df = df[df[\"City\"] == \"San Francisco\"].median()\n", "palo_alto = df[df[\"City\"] == \"Palo Alto\"].median()\n", "df_comparison = pd.concat([marin_df, sf_df, palo_alto, median_prices], axis=1)\n", "df_comparison.columns = [\"Marin County\", \"San Francisco\", \"Palo Alto\", \"Median USA\"]" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "tRARDb7tQOUm", "colab_type": "text" }, "cell_type": "markdown", "source": [ "Install **Cufflinks**" ] }, { "metadata": { "id": "V3lJoE5YGt9f", "colab_type": "text" }, "cell_type": "markdown", "source": [ "Cell configuration to setup Plotly\n", "Further documentation available from [Google on Plotly Colab Integration](https://colab.research.google.com/notebooks/charts.ipynb#scrollTo=YVhMPxwa-wmS)\n", "\n" ] }, { "metadata": { "id": "bExwVgaAlGOi", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "def configure_plotly_browser_state():\n", " import IPython\n", " display(IPython.core.display.HTML('''\n", " \n", " \n", " '''))\n" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "eti_zBsLQNhw", "colab_type": "code", "outputId": "05939ba9-7a02-450a-d8b0-5d9cf06fe493", "colab": { "base_uri": "https://localhost:8080/", "height": 34 } }, "cell_type": "code", "source": [ "!pip -q uninstall -y plotly\n", "!pip -q install plotly==2.7.0\n", "!pip -q install --upgrade cufflinks" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "\u001b[31mcufflinks 0.14.6 has requirement plotly>=3.0.0, but you'll have plotly 2.7.0 which is incompatible.\u001b[0m\n" ], "name": "stdout" } ] }, { "metadata": { "id": "er6GHFbuSmh3", "colab_type": "text" }, "cell_type": "markdown", "source": [ "**Plotly visualization**\n", "\n", "[Shortcut view of plot if slow to load](http://nbviewer.jupyter.org/github/noahgift/real_estate_ml/blob/648361ce7392a0af29ce79780e6e5159c1a378e9/notebooks/explore_zillow_data_sets.ipynb)" ] }, { "metadata": { "id": "irsjeE3NQI0l", "colab_type": "code", "outputId": "35a2b8c0-a9b3-4f93-dd1d-0974e4efae66", "colab": { "resources": { "http://localhost:8080/static/components/requirejs/require.js": { "data": "LyoqIHZpbTogZXQ6dHM9NDpzdz00OnN0cz00CiAqIEBsaWNlbnNlIFJlcXVpcmVKUyAyLjEuMjIgQ29weXJpZ2h0IChjKSAyMDEwLTIwMTUsIFRoZSBEb2pvIEZvdW5kYXRpb24gQWxsIFJpZ2h0cyBSZXNlcnZlZC4KICogQXZhaWxhYmxlIHZpYSB0aGUgTUlUIG9yIG5ldyBCU0QgbGljZW5zZS4KICogc2VlOiBodHRwOi8vZ2l0aHViLmNvbS9qcmJ1cmtlL3JlcXVpcmVqcyBmb3IgZGV0YWlscwogKi8KLy9Ob3QgdXNpbmcgc3RyaWN0OiB1bmV2ZW4gc3RyaWN0IHN1cHBvcnQgaW4gYnJvd3NlcnMsICMzOTIsIGFuZCBjYXVzZXMKLy9wcm9ibGVtcyB3aXRoIHJlcXVpcmVqcy5leGVjKCkvdHJhbnNwaWxlciBwbHVnaW5zIHRoYXQgbWF5IG5vdCBiZSBzdHJpY3QuCi8qanNsaW50IHJlZ2V4cDogdHJ1ZSwgbm9tZW46IHRydWUsIHNsb3BweTogdHJ1ZSAqLwovKmdsb2JhbCB3aW5kb3csIG5hdmlnYXRvciwgZG9jdW1lbnQsIGltcG9ydFNjcmlwdHMsIHNldFRpbWVvdXQsIG9wZXJhICovCgp2YXIgcmVxdWlyZWpzLCByZXF1aXJlLCBkZWZpbmU7CihmdW5jdGlvbiAoZ2xvYmFsKSB7CiAgICB2YXIgcmVxLCBzLCBoZWFkLCBiYXNlRWxlbWVudCwgZGF0YU1haW4sIHNyYywKICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCwgY3VycmVudGx5QWRkaW5nU2NyaXB0LCBtYWluU2NyaXB0LCBzdWJQYXRoLAogICAgICAgIHZlcnNpb24gPSAnMi4xLjIyJywKICAgICAgICBjb21tZW50UmVnRXhwID0gLyhcL1wqKFtcc1xTXSo/KVwqXC98KFteOl18XilcL1wvKC4qKSQpL21nLAogICAgICAgIGNqc1JlcXVpcmVSZWdFeHAgPSAvW14uXVxzKnJlcXVpcmVccypcKFxzKlsiJ10oW14nIlxzXSspWyInXVxzKlwpL2csCiAgICAgICAganNTdWZmaXhSZWdFeHAgPSAvXC5qcyQvLAogICAgICAgIGN1cnJEaXJSZWdFeHAgPSAvXlwuXC8vLAogICAgICAgIG9wID0gT2JqZWN0LnByb3RvdHlwZSwKICAgICAgICBvc3RyaW5nID0gb3AudG9TdHJpbmcsCiAgICAgICAgaGFzT3duID0gb3AuaGFzT3duUHJvcGVydHksCiAgICAgICAgYXAgPSBBcnJheS5wcm90b3R5cGUsCiAgICAgICAgaXNCcm93c2VyID0gISEodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmRvY3VtZW50KSwKICAgICAgICBpc1dlYldvcmtlciA9ICFpc0Jyb3dzZXIgJiYgdHlwZW9mIGltcG9ydFNjcmlwdHMgIT09ICd1bmRlZmluZWQnLAogICAgICAgIC8vUFMzIGluZGljYXRlcyBsb2FkZWQgYW5kIGNvbXBsZXRlLCBidXQgbmVlZCB0byB3YWl0IGZvciBjb21wbGV0ZQogICAgICAgIC8vc3BlY2lmaWNhbGx5LiBTZXF1ZW5jZSBpcyAnbG9hZGluZycsICdsb2FkZWQnLCBleGVjdXRpb24sCiAgICAgICAgLy8gdGhlbiAnY29tcGxldGUnLiBUaGUgVUEgY2hlY2sgaXMgdW5mb3J0dW5hdGUsIGJ1dCBub3Qgc3VyZSBob3cKICAgICAgICAvL3RvIGZlYXR1cmUgdGVzdCB3L28gY2F1c2luZyBwZXJmIGlzc3Vlcy4KICAgICAgICByZWFkeVJlZ0V4cCA9IGlzQnJvd3NlciAmJiBuYXZpZ2F0b3IucGxhdGZvcm0gPT09ICdQTEFZU1RBVElPTiAzJyA/CiAgICAgICAgICAgICAgICAgICAgICAvXmNvbXBsZXRlJC8gOiAvXihjb21wbGV0ZXxsb2FkZWQpJC8sCiAgICAgICAgZGVmQ29udGV4dE5hbWUgPSAnXycsCiAgICAgICAgLy9PaCB0aGUgdHJhZ2VkeSwgZGV0ZWN0aW5nIG9wZXJhLiBTZWUgdGhlIHVzYWdlIG9mIGlzT3BlcmEgZm9yIHJlYXNvbi4KICAgICAgICBpc09wZXJhID0gdHlwZW9mIG9wZXJhICE9PSAndW5kZWZpbmVkJyAmJiBvcGVyYS50b1N0cmluZygpID09PSAnW29iamVjdCBPcGVyYV0nLAogICAgICAgIGNvbnRleHRzID0ge30sCiAgICAgICAgY2ZnID0ge30sCiAgICAgICAgZ2xvYmFsRGVmUXVldWUgPSBbXSwKICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwoKICAgIGZ1bmN0aW9uIGlzRnVuY3Rpb24oaXQpIHsKICAgICAgICByZXR1cm4gb3N0cmluZy5jYWxsKGl0KSA9PT0gJ1tvYmplY3QgRnVuY3Rpb25dJzsKICAgIH0KCiAgICBmdW5jdGlvbiBpc0FycmF5KGl0KSB7CiAgICAgICAgcmV0dXJuIG9zdHJpbmcuY2FsbChpdCkgPT09ICdbb2JqZWN0IEFycmF5XSc7CiAgICB9CgogICAgLyoqCiAgICAgKiBIZWxwZXIgZnVuY3Rpb24gZm9yIGl0ZXJhdGluZyBvdmVyIGFuIGFycmF5LiBJZiB0aGUgZnVuYyByZXR1cm5zCiAgICAgKiBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoKGFyeSwgZnVuYykgewogICAgICAgIGlmIChhcnkpIHsKICAgICAgICAgICAgdmFyIGk7CiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBhcnkubGVuZ3RoOyBpICs9IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEhlbHBlciBmdW5jdGlvbiBmb3IgaXRlcmF0aW5nIG92ZXIgYW4gYXJyYXkgYmFja3dhcmRzLiBJZiB0aGUgZnVuYwogICAgICogcmV0dXJucyBhIHRydWUgdmFsdWUsIGl0IHdpbGwgYnJlYWsgb3V0IG9mIHRoZSBsb29wLgogICAgICovCiAgICBmdW5jdGlvbiBlYWNoUmV2ZXJzZShhcnksIGZ1bmMpIHsKICAgICAgICBpZiAoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpOwogICAgICAgICAgICBmb3IgKGkgPSBhcnkubGVuZ3RoIC0gMTsgaSA+IC0xOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgIGlmIChhcnlbaV0gJiYgZnVuYyhhcnlbaV0sIGksIGFyeSkpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBoYXNQcm9wKG9iaiwgcHJvcCkgewogICAgICAgIHJldHVybiBoYXNPd24uY2FsbChvYmosIHByb3ApOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldE93bihvYmosIHByb3ApIHsKICAgICAgICByZXR1cm4gaGFzUHJvcChvYmosIHByb3ApICYmIG9ialtwcm9wXTsKICAgIH0KCiAgICAvKioKICAgICAqIEN5Y2xlcyBvdmVyIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGFuZCBjYWxscyBhIGZ1bmN0aW9uIGZvciBlYWNoCiAgICAgKiBwcm9wZXJ0eSB2YWx1ZS4gSWYgdGhlIGZ1bmN0aW9uIHJldHVybnMgYSB0cnV0aHkgdmFsdWUsIHRoZW4gdGhlCiAgICAgKiBpdGVyYXRpb24gaXMgc3RvcHBlZC4KICAgICAqLwogICAgZnVuY3Rpb24gZWFjaFByb3Aob2JqLCBmdW5jKSB7CiAgICAgICAgdmFyIHByb3A7CiAgICAgICAgZm9yIChwcm9wIGluIG9iaikgewogICAgICAgICAgICBpZiAoaGFzUHJvcChvYmosIHByb3ApKSB7CiAgICAgICAgICAgICAgICBpZiAoZnVuYyhvYmpbcHJvcF0sIHByb3ApKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBTaW1wbGUgZnVuY3Rpb24gdG8gbWl4IGluIHByb3BlcnRpZXMgZnJvbSBzb3VyY2UgaW50byB0YXJnZXQsCiAgICAgKiBidXQgb25seSBpZiB0YXJnZXQgZG9lcyBub3QgYWxyZWFkeSBoYXZlIGEgcHJvcGVydHkgb2YgdGhlIHNhbWUgbmFtZS4KICAgICAqLwogICAgZnVuY3Rpb24gbWl4aW4odGFyZ2V0LCBzb3VyY2UsIGZvcmNlLCBkZWVwU3RyaW5nTWl4aW4pIHsKICAgICAgICBpZiAoc291cmNlKSB7CiAgICAgICAgICAgIGVhY2hQcm9wKHNvdXJjZSwgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICBpZiAoZm9yY2UgfHwgIWhhc1Byb3AodGFyZ2V0LCBwcm9wKSkgewogICAgICAgICAgICAgICAgICAgIGlmIChkZWVwU3RyaW5nTWl4aW4gJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAhaXNBcnJheSh2YWx1ZSkgJiYgIWlzRnVuY3Rpb24odmFsdWUpICYmCiAgICAgICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBSZWdFeHApKSB7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRhcmdldFtwcm9wXSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0ge307CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgbWl4aW4odGFyZ2V0W3Byb3BdLCB2YWx1ZSwgZm9yY2UsIGRlZXBTdHJpbmdNaXhpbik7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0gdmFsdWU7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRhcmdldDsKICAgIH0KCiAgICAvL1NpbWlsYXIgdG8gRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQsIGJ1dCB0aGUgJ3RoaXMnIG9iamVjdCBpcyBzcGVjaWZpZWQKICAgIC8vZmlyc3QsIHNpbmNlIGl0IGlzIGVhc2llciB0byByZWFkL2ZpZ3VyZSBvdXQgd2hhdCAndGhpcycgd2lsbCBiZS4KICAgIGZ1bmN0aW9uIGJpbmQob2JqLCBmbikgewogICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHJldHVybiBmbi5hcHBseShvYmosIGFyZ3VtZW50cyk7CiAgICAgICAgfTsKICAgIH0KCiAgICBmdW5jdGlvbiBzY3JpcHRzKCkgewogICAgICAgIHJldHVybiBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7CiAgICB9CgogICAgZnVuY3Rpb24gZGVmYXVsdE9uRXJyb3IoZXJyKSB7CiAgICAgICAgdGhyb3cgZXJyOwogICAgfQoKICAgIC8vQWxsb3cgZ2V0dGluZyBhIGdsb2JhbCB0aGF0IGlzIGV4cHJlc3NlZCBpbgogICAgLy9kb3Qgbm90YXRpb24sIGxpa2UgJ2EuYi5jJy4KICAgIGZ1bmN0aW9uIGdldEdsb2JhbCh2YWx1ZSkgewogICAgICAgIGlmICghdmFsdWUpIHsKICAgICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgIH0KICAgICAgICB2YXIgZyA9IGdsb2JhbDsKICAgICAgICBlYWNoKHZhbHVlLnNwbGl0KCcuJyksIGZ1bmN0aW9uIChwYXJ0KSB7CiAgICAgICAgICAgIGcgPSBnW3BhcnRdOwogICAgICAgIH0pOwogICAgICAgIHJldHVybiBnOwogICAgfQoKICAgIC8qKgogICAgICogQ29uc3RydWN0cyBhbiBlcnJvciB3aXRoIGEgcG9pbnRlciB0byBhbiBVUkwgd2l0aCBtb3JlIGluZm9ybWF0aW9uLgogICAgICogQHBhcmFtIHtTdHJpbmd9IGlkIHRoZSBlcnJvciBJRCB0aGF0IG1hcHMgdG8gYW4gSUQgb24gYSB3ZWIgcGFnZS4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIGh1bWFuIHJlYWRhYmxlIGVycm9yLgogICAgICogQHBhcmFtIHtFcnJvcn0gW2Vycl0gdGhlIG9yaWdpbmFsIGVycm9yLCBpZiB0aGVyZSBpcyBvbmUuCiAgICAgKgogICAgICogQHJldHVybnMge0Vycm9yfQogICAgICovCiAgICBmdW5jdGlvbiBtYWtlRXJyb3IoaWQsIG1zZywgZXJyLCByZXF1aXJlTW9kdWxlcykgewogICAgICAgIHZhciBlID0gbmV3IEVycm9yKG1zZyArICdcbmh0dHA6Ly9yZXF1aXJlanMub3JnL2RvY3MvZXJyb3JzLmh0bWwjJyArIGlkKTsKICAgICAgICBlLnJlcXVpcmVUeXBlID0gaWQ7CiAgICAgICAgZS5yZXF1aXJlTW9kdWxlcyA9IHJlcXVpcmVNb2R1bGVzOwogICAgICAgIGlmIChlcnIpIHsKICAgICAgICAgICAgZS5vcmlnaW5hbEVycm9yID0gZXJyOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZTsKICAgIH0KCiAgICBpZiAodHlwZW9mIGRlZmluZSAhPT0gJ3VuZGVmaW5lZCcpIHsKICAgICAgICAvL0lmIGEgZGVmaW5lIGlzIGFscmVhZHkgaW4gcGxheSB2aWEgYW5vdGhlciBBTUQgbG9hZGVyLAogICAgICAgIC8vZG8gbm90IG92ZXJ3cml0ZS4KICAgICAgICByZXR1cm47CiAgICB9CgogICAgaWYgKHR5cGVvZiByZXF1aXJlanMgIT09ICd1bmRlZmluZWQnKSB7CiAgICAgICAgaWYgKGlzRnVuY3Rpb24ocmVxdWlyZWpzKSkgewogICAgICAgICAgICAvL0RvIG5vdCBvdmVyd3JpdGUgYW4gZXhpc3RpbmcgcmVxdWlyZWpzIGluc3RhbmNlLgogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNmZyA9IHJlcXVpcmVqczsKICAgICAgICByZXF1aXJlanMgPSB1bmRlZmluZWQ7CiAgICB9CgogICAgLy9BbGxvdyBmb3IgYSByZXF1aXJlIGNvbmZpZyBvYmplY3QKICAgIGlmICh0eXBlb2YgcmVxdWlyZSAhPT0gJ3VuZGVmaW5lZCcgJiYgIWlzRnVuY3Rpb24ocmVxdWlyZSkpIHsKICAgICAgICAvL2Fzc3VtZSBpdCBpcyBhIGNvbmZpZyBvYmplY3QuCiAgICAgICAgY2ZnID0gcmVxdWlyZTsKICAgICAgICByZXF1aXJlID0gdW5kZWZpbmVkOwogICAgfQoKICAgIGZ1bmN0aW9uIG5ld0NvbnRleHQoY29udGV4dE5hbWUpIHsKICAgICAgICB2YXIgaW5DaGVja0xvYWRlZCwgTW9kdWxlLCBjb250ZXh0LCBoYW5kbGVycywKICAgICAgICAgICAgY2hlY2tMb2FkZWRUaW1lb3V0SWQsCiAgICAgICAgICAgIGNvbmZpZyA9IHsKICAgICAgICAgICAgICAgIC8vRGVmYXVsdHMuIERvIG5vdCBzZXQgYSBkZWZhdWx0IGZvciBtYXAKICAgICAgICAgICAgICAgIC8vY29uZmlnIHRvIHNwZWVkIHVwIG5vcm1hbGl6ZSgpLCB3aGljaAogICAgICAgICAgICAgICAgLy93aWxsIHJ1biBmYXN0ZXIgaWYgdGhlcmUgaXMgbm8gZGVmYXVsdC4KICAgICAgICAgICAgICAgIHdhaXRTZWNvbmRzOiA3LAogICAgICAgICAgICAgICAgYmFzZVVybDogJy4vJywKICAgICAgICAgICAgICAgIHBhdGhzOiB7fSwKICAgICAgICAgICAgICAgIGJ1bmRsZXM6IHt9LAogICAgICAgICAgICAgICAgcGtnczoge30sCiAgICAgICAgICAgICAgICBzaGltOiB7fSwKICAgICAgICAgICAgICAgIGNvbmZpZzoge30KICAgICAgICAgICAgfSwKICAgICAgICAgICAgcmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgLy9yZWdpc3RyeSBvZiBqdXN0IGVuYWJsZWQgbW9kdWxlcywgdG8gc3BlZWQKICAgICAgICAgICAgLy9jeWNsZSBicmVha2luZyBjb2RlIHdoZW4gbG90cyBvZiBtb2R1bGVzCiAgICAgICAgICAgIC8vYXJlIHJlZ2lzdGVyZWQsIGJ1dCBub3QgYWN0aXZhdGVkLgogICAgICAgICAgICBlbmFibGVkUmVnaXN0cnkgPSB7fSwKICAgICAgICAgICAgdW5kZWZFdmVudHMgPSB7fSwKICAgICAgICAgICAgZGVmUXVldWUgPSBbXSwKICAgICAgICAgICAgZGVmaW5lZCA9IHt9LAogICAgICAgICAgICB1cmxGZXRjaGVkID0ge30sCiAgICAgICAgICAgIGJ1bmRsZXNNYXAgPSB7fSwKICAgICAgICAgICAgcmVxdWlyZUNvdW50ZXIgPSAxLAogICAgICAgICAgICB1bm5vcm1hbGl6ZWRDb3VudGVyID0gMTsKCiAgICAgICAgLyoqCiAgICAgICAgICogVHJpbXMgdGhlIC4gYW5kIC4uIGZyb20gYW4gYXJyYXkgb2YgcGF0aCBzZWdtZW50cy4KICAgICAgICAgKiBJdCB3aWxsIGtlZXAgYSBsZWFkaW5nIHBhdGggc2VnbWVudCBpZiBhIC4uIHdpbGwgYmVjb21lCiAgICAgICAgICogdGhlIGZpcnN0IHBhdGggc2VnbWVudCwgdG8gaGVscCB3aXRoIG1vZHVsZSBuYW1lIGxvb2t1cHMsCiAgICAgICAgICogd2hpY2ggYWN0IGxpa2UgcGF0aHMsIGJ1dCBjYW4gYmUgcmVtYXBwZWQuIEJ1dCB0aGUgZW5kIHJlc3VsdCwKICAgICAgICAgKiBhbGwgcGF0aHMgdGhhdCB1c2UgdGhpcyBmdW5jdGlvbiBzaG91bGQgbG9vayBub3JtYWxpemVkLgogICAgICAgICAqIE5PVEU6IHRoaXMgbWV0aG9kIE1PRElGSUVTIHRoZSBpbnB1dCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnkgdGhlIGFycmF5IG9mIHBhdGggc2VnbWVudHMuCiAgICAgICAgICovCiAgICAgICAgZnVuY3Rpb24gdHJpbURvdHMoYXJ5KSB7CiAgICAgICAgICAgIHZhciBpLCBwYXJ0OwogICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYXJ5Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgICAgICBwYXJ0ID0gYXJ5W2ldOwogICAgICAgICAgICAgICAgaWYgKHBhcnQgPT09ICcuJykgewogICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSwgMSk7CiAgICAgICAgICAgICAgICAgICAgaSAtPSAxOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChwYXJ0ID09PSAnLi4nKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gSWYgYXQgdGhlIHN0YXJ0LCBvciBwcmV2aW91cyB2YWx1ZSBpcyBzdGlsbCAuLiwKICAgICAgICAgICAgICAgICAgICAvLyBrZWVwIHRoZW0gc28gdGhhdCB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGggaXQgbWF5CiAgICAgICAgICAgICAgICAgICAgLy8gc3RpbGwgd29yayB3aGVuIGNvbnZlcnRlZCB0byBhIHBhdGgsIGV2ZW4gdGhvdWdoCiAgICAgICAgICAgICAgICAgICAgLy8gYXMgYW4gSUQgaXQgaXMgbGVzcyB0aGFuIGlkZWFsLiBJbiBsYXJnZXIgcG9pbnQKICAgICAgICAgICAgICAgICAgICAvLyByZWxlYXNlcywgbWF5IGJlIGJldHRlciB0byBqdXN0IGtpY2sgb3V0IGFuIGVycm9yLgogICAgICAgICAgICAgICAgICAgIGlmIChpID09PSAwIHx8IChpID09PSAxICYmIGFyeVsyXSA9PT0gJy4uJykgfHwgYXJ5W2kgLSAxXSA9PT0gJy4uJykgewogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGkgPiAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGFyeS5zcGxpY2UoaSAtIDEsIDIpOwogICAgICAgICAgICAgICAgICAgICAgICBpIC09IDI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBHaXZlbiBhIHJlbGF0aXZlIG1vZHVsZSBuYW1lLCBsaWtlIC4vc29tZXRoaW5nLCBub3JtYWxpemUgaXQgdG8KICAgICAgICAgKiBhIHJlYWwgbmFtZSB0aGF0IGNhbiBiZSBtYXBwZWQgdG8gYSBwYXRoLgogICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIHRoZSByZWxhdGl2ZSBuYW1lCiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGJhc2VOYW1lIGEgcmVhbCBuYW1lIHRoYXQgdGhlIG5hbWUgYXJnIGlzIHJlbGF0aXZlCiAgICAgICAgICogdG8uCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBhcHBseU1hcCBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgdmFsdWUuIFNob3VsZAogICAgICAgICAqIG9ubHkgYmUgZG9uZSBpZiB0aGlzIG5vcm1hbGl6YXRpb24gaXMgZm9yIGEgZGVwZW5kZW5jeSBJRC4KICAgICAgICAgKiBAcmV0dXJucyB7U3RyaW5nfSBub3JtYWxpemVkIG5hbWUKICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBub3JtYWxpemUobmFtZSwgYmFzZU5hbWUsIGFwcGx5TWFwKSB7CiAgICAgICAgICAgIHZhciBwa2dNYWluLCBtYXBWYWx1ZSwgbmFtZVBhcnRzLCBpLCBqLCBuYW1lU2VnbWVudCwgbGFzdEluZGV4LAogICAgICAgICAgICAgICAgZm91bmRNYXAsIGZvdW5kSSwgZm91bmRTdGFyTWFwLCBzdGFySSwgbm9ybWFsaXplZEJhc2VQYXJ0cywKICAgICAgICAgICAgICAgIGJhc2VQYXJ0cyA9IChiYXNlTmFtZSAmJiBiYXNlTmFtZS5zcGxpdCgnLycpKSwKICAgICAgICAgICAgICAgIG1hcCA9IGNvbmZpZy5tYXAsCiAgICAgICAgICAgICAgICBzdGFyTWFwID0gbWFwICYmIG1hcFsnKiddOwoKICAgICAgICAgICAgLy9BZGp1c3QgYW55IHJlbGF0aXZlIHBhdGhzLgogICAgICAgICAgICBpZiAobmFtZSkgewogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3BsaXQoJy8nKTsKICAgICAgICAgICAgICAgIGxhc3RJbmRleCA9IG5hbWUubGVuZ3RoIC0gMTsKCiAgICAgICAgICAgICAgICAvLyBJZiB3YW50aW5nIG5vZGUgSUQgY29tcGF0aWJpbGl0eSwgc3RyaXAgLmpzIGZyb20gZW5kCiAgICAgICAgICAgICAgICAvLyBvZiBJRHMuIEhhdmUgdG8gZG8gdGhpcyBoZXJlLCBhbmQgbm90IGluIG5hbWVUb1VybAogICAgICAgICAgICAgICAgLy8gYmVjYXVzZSBub2RlIGFsbG93cyBlaXRoZXIgLmpzIG9yIG5vbiAuanMgdG8gbWFwCiAgICAgICAgICAgICAgICAvLyB0byBzYW1lIGZpbGUuCiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLm5vZGVJZENvbXBhdCAmJiBqc1N1ZmZpeFJlZ0V4cC50ZXN0KG5hbWVbbGFzdEluZGV4XSkpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lW2xhc3RJbmRleF0gPSBuYW1lW2xhc3RJbmRleF0ucmVwbGFjZShqc1N1ZmZpeFJlZ0V4cCwgJycpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vIFN0YXJ0cyB3aXRoIGEgJy4nIHNvIG5lZWQgdGhlIGJhc2VOYW1lCiAgICAgICAgICAgICAgICBpZiAobmFtZVswXS5jaGFyQXQoMCkgPT09ICcuJyAmJiBiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAvL0NvbnZlcnQgYmFzZU5hbWUgdG8gYXJyYXksIGFuZCBsb3Agb2ZmIHRoZSBsYXN0IHBhcnQsCiAgICAgICAgICAgICAgICAgICAgLy9zbyB0aGF0IC4gbWF0Y2hlcyB0aGF0ICdkaXJlY3RvcnknIGFuZCBub3QgbmFtZSBvZiB0aGUgYmFzZU5hbWUncwogICAgICAgICAgICAgICAgICAgIC8vbW9kdWxlLiBGb3IgaW5zdGFuY2UsIGJhc2VOYW1lIG9mICdvbmUvdHdvL3RocmVlJywgbWFwcyB0bwogICAgICAgICAgICAgICAgICAgIC8vJ29uZS90d28vdGhyZWUuanMnLCBidXQgd2Ugd2FudCB0aGUgZGlyZWN0b3J5LCAnb25lL3R3bycgZm9yCiAgICAgICAgICAgICAgICAgICAgLy90aGlzIG5vcm1hbGl6YXRpb24uCiAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZEJhc2VQYXJ0cyA9IGJhc2VQYXJ0cy5zbGljZSgwLCBiYXNlUGFydHMubGVuZ3RoIC0gMSk7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vcm1hbGl6ZWRCYXNlUGFydHMuY29uY2F0KG5hbWUpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHRyaW1Eb3RzKG5hbWUpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuam9pbignLycpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL0FwcGx5IG1hcCBjb25maWcgaWYgYXZhaWxhYmxlLgogICAgICAgICAgICBpZiAoYXBwbHlNYXAgJiYgbWFwICYmIChiYXNlUGFydHMgfHwgc3Rhck1hcCkpIHsKICAgICAgICAgICAgICAgIG5hbWVQYXJ0cyA9IG5hbWUuc3BsaXQoJy8nKTsKCiAgICAgICAgICAgICAgICBvdXRlckxvb3A6IGZvciAoaSA9IG5hbWVQYXJ0cy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICBuYW1lU2VnbWVudCA9IG5hbWVQYXJ0cy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgIGlmIChiYXNlUGFydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9GaW5kIHRoZSBsb25nZXN0IGJhc2VOYW1lIHNlZ21lbnQgbWF0Y2ggaW4gdGhlIGNvbmZpZy4KICAgICAgICAgICAgICAgICAgICAgICAgLy9TbywgZG8gam9pbnMgb24gdGhlIGJpZ2dlc3QgdG8gc21hbGxlc3QgbGVuZ3RocyBvZiBiYXNlUGFydHMuCiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaiA9IGJhc2VQYXJ0cy5sZW5ndGg7IGogPiAwOyBqIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcFZhbHVlID0gZ2V0T3duKG1hcCwgYmFzZVBhcnRzLnNsaWNlKDAsIGopLmpvaW4oJy8nKSk7CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iYXNlTmFtZSBzZWdtZW50IGhhcyBjb25maWcsIGZpbmQgaWYgaXQgaGFzIG9uZSBmb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hcFZhbHVlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwVmFsdWUgPSBnZXRPd24obWFwVmFsdWUsIG5hbWVTZWdtZW50KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobWFwVmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXRjaCwgdXBkYXRlIG5hbWUgdG8gdGhlIG5ldyB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRNYXAgPSBtYXBWYWx1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm91bmRJID0gaTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsgb3V0ZXJMb29wOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9DaGVjayBmb3IgYSBzdGFyIG1hcCBtYXRjaCwgYnV0IGp1c3QgaG9sZCBvbiB0byBpdCwKICAgICAgICAgICAgICAgICAgICAvL2lmIHRoZXJlIGlzIGEgc2hvcnRlciBzZWdtZW50IG1hdGNoIGxhdGVyIGluIGEgbWF0Y2hpbmcKICAgICAgICAgICAgICAgICAgICAvL2NvbmZpZywgdGhlbiBmYXZvciBvdmVyIHRoaXMgc3RhciBtYXAuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFmb3VuZFN0YXJNYXAgJiYgc3Rhck1hcCAmJiBnZXRPd24oc3Rhck1hcCwgbmFtZVNlZ21lbnQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGZvdW5kU3Rhck1hcCA9IGdldE93bihzdGFyTWFwLCBuYW1lU2VnbWVudCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJJID0gaTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFmb3VuZE1hcCAmJiBmb3VuZFN0YXJNYXApIHsKICAgICAgICAgICAgICAgICAgICBmb3VuZE1hcCA9IGZvdW5kU3Rhck1hcDsKICAgICAgICAgICAgICAgICAgICBmb3VuZEkgPSBzdGFySTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBpZiAoZm91bmRNYXApIHsKICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMuc3BsaWNlKDAsIGZvdW5kSSwgZm91bmRNYXApOwogICAgICAgICAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHMuam9pbignLycpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBJZiB0aGUgbmFtZSBwb2ludHMgdG8gYSBwYWNrYWdlJ3MgbmFtZSwgdXNlCiAgICAgICAgICAgIC8vIHRoZSBwYWNrYWdlIG1haW4gaW5zdGVhZC4KICAgICAgICAgICAgcGtnTWFpbiA9IGdldE93bihjb25maWcucGtncywgbmFtZSk7CgogICAgICAgICAgICByZXR1cm4gcGtnTWFpbiA/IHBrZ01haW4gOiBuYW1lOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gcmVtb3ZlU2NyaXB0KG5hbWUpIHsKICAgICAgICAgICAgaWYgKGlzQnJvd3NlcikgewogICAgICAgICAgICAgICAgZWFjaChzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHROb2RlKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKHNjcmlwdE5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKSA9PT0gbmFtZSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NyaXB0Tm9kZS5nZXRBdHRyaWJ1dGUoJ2RhdGEtcmVxdWlyZWNvbnRleHQnKSA9PT0gY29udGV4dC5jb250ZXh0TmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzY3JpcHROb2RlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoc2NyaXB0Tm9kZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBoYXNQYXRoRmFsbGJhY2soaWQpIHsKICAgICAgICAgICAgdmFyIHBhdGhDb25maWcgPSBnZXRPd24oY29uZmlnLnBhdGhzLCBpZCk7CiAgICAgICAgICAgIGlmIChwYXRoQ29uZmlnICYmIGlzQXJyYXkocGF0aENvbmZpZykgJiYgcGF0aENvbmZpZy5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgICAvL1BvcCBvZmYgdGhlIGZpcnN0IGFycmF5IHZhbHVlLCBzaW5jZSBpdCBmYWlsZWQsIGFuZAogICAgICAgICAgICAgICAgLy9yZXRyeQogICAgICAgICAgICAgICAgcGF0aENvbmZpZy5zaGlmdCgpOwogICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlLnVuZGVmKGlkKTsKCiAgICAgICAgICAgICAgICAvL0N1c3RvbSByZXF1aXJlIHRoYXQgZG9lcyBub3QgZG8gbWFwIHRyYW5zbGF0aW9uLCBzaW5jZQogICAgICAgICAgICAgICAgLy9JRCBpcyAiYWJzb2x1dGUiLCBhbHJlYWR5IG1hcHBlZC9yZXNvbHZlZC4KICAgICAgICAgICAgICAgIGNvbnRleHQubWFrZVJlcXVpcmUobnVsbCwgewogICAgICAgICAgICAgICAgICAgIHNraXBNYXA6IHRydWUKICAgICAgICAgICAgICAgIH0pKFtpZF0pOwoKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvL1R1cm5zIGEgcGx1Z2luIXJlc291cmNlIHRvIFtwbHVnaW4sIHJlc291cmNlXQogICAgICAgIC8vd2l0aCB0aGUgcGx1Z2luIGJlaW5nIHVuZGVmaW5lZCBpZiB0aGUgbmFtZQogICAgICAgIC8vZGlkIG5vdCBoYXZlIGEgcGx1Z2luIHByZWZpeC4KICAgICAgICBmdW5jdGlvbiBzcGxpdFByZWZpeChuYW1lKSB7CiAgICAgICAgICAgIHZhciBwcmVmaXgsCiAgICAgICAgICAgICAgICBpbmRleCA9IG5hbWUgPyBuYW1lLmluZGV4T2YoJyEnKSA6IC0xOwogICAgICAgICAgICBpZiAoaW5kZXggPiAtMSkgewogICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZS5zdWJzdHJpbmcoMCwgaW5kZXgpOwogICAgICAgICAgICAgICAgbmFtZSA9IG5hbWUuc3Vic3RyaW5nKGluZGV4ICsgMSwgbmFtZS5sZW5ndGgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBbcHJlZml4LCBuYW1lXTsKICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBtb2R1bGUgbWFwcGluZyB0aGF0IGluY2x1ZGVzIHBsdWdpbiBwcmVmaXgsIG1vZHVsZQogICAgICAgICAqIG5hbWUsIGFuZCBwYXRoLiBJZiBwYXJlbnRNb2R1bGVNYXAgaXMgcHJvdmlkZWQgaXQgd2lsbAogICAgICAgICAqIGFsc28gbm9ybWFsaXplIHRoZSBuYW1lIHZpYSByZXF1aXJlLm5vcm1hbGl6ZSgpCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSB0aGUgbW9kdWxlIG5hbWUKICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gW3BhcmVudE1vZHVsZU1hcF0gcGFyZW50IG1vZHVsZSBtYXAKICAgICAgICAgKiBmb3IgdGhlIG1vZHVsZSBuYW1lLCB1c2VkIHRvIHJlc29sdmUgcmVsYXRpdmUgbmFtZXMuCiAgICAgICAgICogQHBhcmFtIHtCb29sZWFufSBpc05vcm1hbGl6ZWQ6IGlzIHRoZSBJRCBhbHJlYWR5IG5vcm1hbGl6ZWQuCiAgICAgICAgICogVGhpcyBpcyB0cnVlIGlmIHRoaXMgY2FsbCBpcyBkb25lIGZvciBhIGRlZmluZSgpIG1vZHVsZSBJRC4KICAgICAgICAgKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGx5TWFwOiBhcHBseSB0aGUgbWFwIGNvbmZpZyB0byB0aGUgSUQuCiAgICAgICAgICogU2hvdWxkIG9ubHkgYmUgdHJ1ZSBpZiB0aGlzIG1hcCBpcyBmb3IgYSBkZXBlbmRlbmN5LgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge09iamVjdH0KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiBtYWtlTW9kdWxlTWFwKG5hbWUsIHBhcmVudE1vZHVsZU1hcCwgaXNOb3JtYWxpemVkLCBhcHBseU1hcCkgewogICAgICAgICAgICB2YXIgdXJsLCBwbHVnaW5Nb2R1bGUsIHN1ZmZpeCwgbmFtZVBhcnRzLAogICAgICAgICAgICAgICAgcHJlZml4ID0gbnVsbCwKICAgICAgICAgICAgICAgIHBhcmVudE5hbWUgPSBwYXJlbnRNb2R1bGVNYXAgPyBwYXJlbnRNb2R1bGVNYXAubmFtZSA6IG51bGwsCiAgICAgICAgICAgICAgICBvcmlnaW5hbE5hbWUgPSBuYW1lLAogICAgICAgICAgICAgICAgaXNEZWZpbmUgPSB0cnVlLAogICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUgPSAnJzsKCiAgICAgICAgICAgIC8vSWYgbm8gbmFtZSwgdGhlbiBpdCBtZWFucyBpdCBpcyBhIHJlcXVpcmUgY2FsbCwgZ2VuZXJhdGUgYW4KICAgICAgICAgICAgLy9pbnRlcm5hbCBuYW1lLgogICAgICAgICAgICBpZiAoIW5hbWUpIHsKICAgICAgICAgICAgICAgIGlzRGVmaW5lID0gZmFsc2U7CiAgICAgICAgICAgICAgICBuYW1lID0gJ19AcicgKyAocmVxdWlyZUNvdW50ZXIgKz0gMSk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIG5hbWVQYXJ0cyA9IHNwbGl0UHJlZml4KG5hbWUpOwogICAgICAgICAgICBwcmVmaXggPSBuYW1lUGFydHNbMF07CiAgICAgICAgICAgIG5hbWUgPSBuYW1lUGFydHNbMV07CgogICAgICAgICAgICBpZiAocHJlZml4KSB7CiAgICAgICAgICAgICAgICBwcmVmaXggPSBub3JtYWxpemUocHJlZml4LCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICBwbHVnaW5Nb2R1bGUgPSBnZXRPd24oZGVmaW5lZCwgcHJlZml4KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9BY2NvdW50IGZvciByZWxhdGl2ZSBwYXRocyBpZiB0aGVyZSBpcyBhIGJhc2UgbmFtZS4KICAgICAgICAgICAgaWYgKG5hbWUpIHsKICAgICAgICAgICAgICAgIGlmIChwcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICBpZiAocGx1Z2luTW9kdWxlICYmIHBsdWdpbk1vZHVsZS5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9QbHVnaW4gaXMgbG9hZGVkLCB1c2UgaXRzIG5vcm1hbGl6ZSBtZXRob2QuCiAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gcGx1Z2luTW9kdWxlLm5vcm1hbGl6ZShuYW1lLCBmdW5jdGlvbiAobmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIG5lc3RlZCBwbHVnaW4gcmVmZXJlbmNlcywgdGhlbiBkbyBub3QgdHJ5IHRvCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSwgYXMgaXQgd2lsbCBub3Qgbm9ybWFsaXplIGNvcnJlY3RseS4gVGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvLyBwbGFjZXMgYSByZXN0cmljdGlvbiBvbiByZXNvdXJjZUlkcywgYW5kIHRoZSBsb25nZXIKICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGVybSBzb2x1dGlvbiBpcyBub3QgdG8gbm9ybWFsaXplIHVudGlsIHBsdWdpbnMgYXJlCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxvYWRlZCBhbmQgYWxsIG5vcm1hbGl6YXRpb25zIHRvIGFsbG93IGZvciBhc3luYwogICAgICAgICAgICAgICAgICAgICAgICAvLyBsb2FkaW5nIG9mIGEgbG9hZGVyIHBsdWdpbi4gQnV0IGZvciBub3csIGZpeGVzIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAvLyBjb21tb24gdXNlcy4gRGV0YWlscyBpbiAjMTEzMQogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5hbWUuaW5kZXhPZignIScpID09PSAtMSA/CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplKG5hbWUsIHBhcmVudE5hbWUsIGFwcGx5TWFwKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIC8vQSByZWd1bGFyIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSA9IG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCBhcHBseU1hcCk7CgogICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplZCBuYW1lIG1heSBiZSBhIHBsdWdpbiBJRCBkdWUgdG8gbWFwIGNvbmZpZwogICAgICAgICAgICAgICAgICAgIC8vYXBwbGljYXRpb24gaW4gbm9ybWFsaXplLiBUaGUgbWFwIGNvbmZpZyB2YWx1ZXMgbXVzdAogICAgICAgICAgICAgICAgICAgIC8vYWxyZWFkeSBiZSBub3JtYWxpemVkLCBzbyBkbyBub3QgbmVlZCB0byByZWRvIHRoYXQgcGFydC4KICAgICAgICAgICAgICAgICAgICBuYW1lUGFydHMgPSBzcGxpdFByZWZpeChub3JtYWxpemVkTmFtZSk7CiAgICAgICAgICAgICAgICAgICAgcHJlZml4ID0gbmFtZVBhcnRzWzBdOwogICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWROYW1lID0gbmFtZVBhcnRzWzFdOwogICAgICAgICAgICAgICAgICAgIGlzTm9ybWFsaXplZCA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIHVybCA9IGNvbnRleHQubmFtZVRvVXJsKG5vcm1hbGl6ZWROYW1lKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiB0aGUgaWQgaXMgYSBwbHVnaW4gaWQgdGhhdCBjYW5ub3QgYmUgZGV0ZXJtaW5lZCBpZiBpdCBuZWVkcwogICAgICAgICAgICAvL25vcm1hbGl6YXRpb24sIHN0YW1wIGl0IHdpdGggYSB1bmlxdWUgSUQgc28gdHdvIG1hdGNoaW5nIHJlbGF0aXZlCiAgICAgICAgICAgIC8vaWRzIHRoYXQgbWF5IGNvbmZsaWN0IGNhbiBiZSBzZXBhcmF0ZS4KICAgICAgICAgICAgc3VmZml4ID0gcHJlZml4ICYmICFwbHVnaW5Nb2R1bGUgJiYgIWlzTm9ybWFsaXplZCA/CiAgICAgICAgICAgICAgICAgICAgICdfdW5ub3JtYWxpemVkJyArICh1bm5vcm1hbGl6ZWRDb3VudGVyICs9IDEpIDoKICAgICAgICAgICAgICAgICAgICAgJyc7CgogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgcHJlZml4OiBwcmVmaXgsCiAgICAgICAgICAgICAgICBuYW1lOiBub3JtYWxpemVkTmFtZSwKICAgICAgICAgICAgICAgIHBhcmVudE1hcDogcGFyZW50TW9kdWxlTWFwLAogICAgICAgICAgICAgICAgdW5ub3JtYWxpemVkOiAhIXN1ZmZpeCwKICAgICAgICAgICAgICAgIHVybDogdXJsLAogICAgICAgICAgICAgICAgb3JpZ2luYWxOYW1lOiBvcmlnaW5hbE5hbWUsCiAgICAgICAgICAgICAgICBpc0RlZmluZTogaXNEZWZpbmUsCiAgICAgICAgICAgICAgICBpZDogKHByZWZpeCA/CiAgICAgICAgICAgICAgICAgICAgICAgIHByZWZpeCArICchJyArIG5vcm1hbGl6ZWROYW1lIDoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUpICsgc3VmZml4CiAgICAgICAgICAgIH07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBnZXRNb2R1bGUoZGVwTWFwKSB7CiAgICAgICAgICAgIHZhciBpZCA9IGRlcE1hcC5pZCwKICAgICAgICAgICAgICAgIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwoKICAgICAgICAgICAgaWYgKCFtb2QpIHsKICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXSA9IG5ldyBjb250ZXh0Lk1vZHVsZShkZXBNYXApOwogICAgICAgICAgICB9CgogICAgICAgICAgICByZXR1cm4gbW9kOwogICAgICAgIH0KCiAgICAgICAgZnVuY3Rpb24gb24oZGVwTWFwLCBuYW1lLCBmbikgewogICAgICAgICAgICB2YXIgaWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIGlkKTsKCiAgICAgICAgICAgIGlmIChoYXNQcm9wKGRlZmluZWQsIGlkKSAmJgogICAgICAgICAgICAgICAgICAgICghbW9kIHx8IG1vZC5kZWZpbmVFbWl0Q29tcGxldGUpKSB7CiAgICAgICAgICAgICAgICBpZiAobmFtZSA9PT0gJ2RlZmluZWQnKSB7CiAgICAgICAgICAgICAgICAgICAgZm4oZGVmaW5lZFtpZF0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgbW9kID0gZ2V0TW9kdWxlKGRlcE1hcCk7CiAgICAgICAgICAgICAgICBpZiAobW9kLmVycm9yICYmIG5hbWUgPT09ICdlcnJvcicpIHsKICAgICAgICAgICAgICAgICAgICBmbihtb2QuZXJyb3IpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBtb2Qub24obmFtZSwgZm4pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBvbkVycm9yKGVyciwgZXJyYmFjaykgewogICAgICAgICAgICB2YXIgaWRzID0gZXJyLnJlcXVpcmVNb2R1bGVzLAogICAgICAgICAgICAgICAgbm90aWZpZWQgPSBmYWxzZTsKCiAgICAgICAgICAgIGlmIChlcnJiYWNrKSB7CiAgICAgICAgICAgICAgICBlcnJiYWNrKGVycik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBlYWNoKGlkcywgZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgaWQpOwogICAgICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9TZXQgZXJyb3Igb24gbW9kdWxlLCBzbyBpdCBza2lwcyB0aW1lb3V0IGNoZWNrcy4KICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVycm9yID0gZXJyOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90aWZpZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIGlmICghbm90aWZpZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvKioKICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdG8gdHJhbnNmZXIgZ2xvYmFsUXVldWUgaXRlbXMgdG8gdGhpcyBjb250ZXh0J3MKICAgICAgICAgKiBkZWZRdWV1ZS4KICAgICAgICAgKi8KICAgICAgICBmdW5jdGlvbiB0YWtlR2xvYmFsUXVldWUoKSB7CiAgICAgICAgICAgIC8vUHVzaCBhbGwgdGhlIGdsb2JhbERlZlF1ZXVlIGl0ZW1zIGludG8gdGhlIGNvbnRleHQncyBkZWZRdWV1ZQogICAgICAgICAgICBpZiAoZ2xvYmFsRGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBlYWNoKGdsb2JhbERlZlF1ZXVlLCBmdW5jdGlvbihxdWV1ZUl0ZW0pIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQgPSBxdWV1ZUl0ZW1bMF07CiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpZCA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcFtpZF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBkZWZRdWV1ZS5wdXNoKHF1ZXVlSXRlbSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGdsb2JhbERlZlF1ZXVlID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGhhbmRsZXJzID0gewogICAgICAgICAgICAncmVxdWlyZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QucmVxdWlyZSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBtb2QucmVxdWlyZTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChtb2QucmVxdWlyZSA9IGNvbnRleHQubWFrZVJlcXVpcmUobW9kLm1hcCkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAnZXhwb3J0cyc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIG1vZC51c2luZ0V4cG9ydHMgPSB0cnVlOwogICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICBpZiAobW9kLmV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChkZWZpbmVkW21vZC5tYXAuaWRdID0gbW9kLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLmV4cG9ydHMgPSBkZWZpbmVkW21vZC5tYXAuaWRdID0ge30pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgJ21vZHVsZSc6IGZ1bmN0aW9uIChtb2QpIHsKICAgICAgICAgICAgICAgIGlmIChtb2QubW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vZC5tb2R1bGU7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiAobW9kLm1vZHVsZSA9IHsKICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IG1vZC5tYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIHVyaTogbW9kLm1hcC51cmwsCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZzogZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdldE93bihjb25maWcuY29uZmlnLCBtb2QubWFwLmlkKSB8fCB7fTsKICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0czogbW9kLmV4cG9ydHMgfHwgKG1vZC5leHBvcnRzID0ge30pCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjbGVhblJlZ2lzdHJ5KGlkKSB7CiAgICAgICAgICAgIC8vQ2xlYW4gdXAgbWFjaGluZXJ5IHVzZWQgZm9yIHdhaXRpbmcgbW9kdWxlcy4KICAgICAgICAgICAgZGVsZXRlIHJlZ2lzdHJ5W2lkXTsKICAgICAgICAgICAgZGVsZXRlIGVuYWJsZWRSZWdpc3RyeVtpZF07CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBicmVha0N5Y2xlKG1vZCwgdHJhY2VkLCBwcm9jZXNzZWQpIHsKICAgICAgICAgICAgdmFyIGlkID0gbW9kLm1hcC5pZDsKCiAgICAgICAgICAgIGlmIChtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgIG1vZC5lbWl0KCdlcnJvcicsIG1vZC5lcnJvcik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB0cmFjZWRbaWRdID0gdHJ1ZTsKICAgICAgICAgICAgICAgIGVhY2gobW9kLmRlcE1hcHMsIGZ1bmN0aW9uIChkZXBNYXAsIGkpIHsKICAgICAgICAgICAgICAgICAgICB2YXIgZGVwSWQgPSBkZXBNYXAuaWQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRlcCA9IGdldE93bihyZWdpc3RyeSwgZGVwSWQpOwoKICAgICAgICAgICAgICAgICAgICAvL09ubHkgZm9yY2UgdGhpbmdzIHRoYXQgaGF2ZSBub3QgY29tcGxldGVkCiAgICAgICAgICAgICAgICAgICAgLy9iZWluZyBkZWZpbmVkLCBzbyBzdGlsbCBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAgICAgLy9hbmQgb25seSBpZiBpdCBoYXMgbm90IGJlZW4gbWF0Y2hlZCB1cAogICAgICAgICAgICAgICAgICAgIC8vaW4gdGhlIG1vZHVsZSBhbHJlYWR5LgogICAgICAgICAgICAgICAgICAgIGlmIChkZXAgJiYgIW1vZC5kZXBNYXRjaGVkW2ldICYmICFwcm9jZXNzZWRbZGVwSWRdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChnZXRPd24odHJhY2VkLCBkZXBJZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZC5kZWZpbmVEZXAoaSwgZGVmaW5lZFtkZXBJZF0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kLmNoZWNrKCk7IC8vcGFzcyBmYWxzZT8KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrQ3ljbGUoZGVwLCB0cmFjZWQsIHByb2Nlc3NlZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIHByb2Nlc3NlZFtpZF0gPSB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiBjaGVja0xvYWRlZCgpIHsKICAgICAgICAgICAgdmFyIGVyciwgdXNpbmdQYXRoRmFsbGJhY2ssCiAgICAgICAgICAgICAgICB3YWl0SW50ZXJ2YWwgPSBjb25maWcud2FpdFNlY29uZHMgKiAxMDAwLAogICAgICAgICAgICAgICAgLy9JdCBpcyBwb3NzaWJsZSB0byBkaXNhYmxlIHRoZSB3YWl0IGludGVydmFsIGJ5IHVzaW5nIHdhaXRTZWNvbmRzIG9mIDAuCiAgICAgICAgICAgICAgICBleHBpcmVkID0gd2FpdEludGVydmFsICYmIChjb250ZXh0LnN0YXJ0VGltZSArIHdhaXRJbnRlcnZhbCkgPCBuZXcgRGF0ZSgpLmdldFRpbWUoKSwKICAgICAgICAgICAgICAgIG5vTG9hZHMgPSBbXSwKICAgICAgICAgICAgICAgIHJlcUNhbGxzID0gW10sCiAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSBmYWxzZSwKICAgICAgICAgICAgICAgIG5lZWRDeWNsZUNoZWNrID0gdHJ1ZTsKCiAgICAgICAgICAgIC8vRG8gbm90IGJvdGhlciBpZiB0aGlzIGNhbGwgd2FzIGEgcmVzdWx0IG9mIGEgY3ljbGUgYnJlYWsuCiAgICAgICAgICAgIGlmIChpbkNoZWNrTG9hZGVkKSB7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGluQ2hlY2tMb2FkZWQgPSB0cnVlOwoKICAgICAgICAgICAgLy9GaWd1cmUgb3V0IHRoZSBzdGF0ZSBvZiBhbGwgdGhlIG1vZHVsZXMuCiAgICAgICAgICAgIGVhY2hQcm9wKGVuYWJsZWRSZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgdmFyIG1hcCA9IG1vZC5tYXAsCiAgICAgICAgICAgICAgICAgICAgbW9kSWQgPSBtYXAuaWQ7CgogICAgICAgICAgICAgICAgLy9Ta2lwIHRoaW5ncyB0aGF0IGFyZSBub3QgZW5hYmxlZCBvciBpbiBlcnJvciBzdGF0ZS4KICAgICAgICAgICAgICAgIGlmICghbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtYXAuaXNEZWZpbmUpIHsKICAgICAgICAgICAgICAgICAgICByZXFDYWxscy5wdXNoKG1vZCk7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKCFtb2QuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIHRoZSBtb2R1bGUgc2hvdWxkIGJlIGV4ZWN1dGVkLCBhbmQgaXQgaGFzIG5vdAogICAgICAgICAgICAgICAgICAgIC8vYmVlbiBpbml0ZWQgYW5kIHRpbWUgaXMgdXAsIHJlbWVtYmVyIGl0LgogICAgICAgICAgICAgICAgICAgIGlmICghbW9kLmluaXRlZCAmJiBleHBpcmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoYXNQYXRoRmFsbGJhY2sobW9kSWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2luZ1BhdGhGYWxsYmFjayA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9Mb2Fkcy5wdXNoKG1vZElkKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChtb2RJZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCFtb2QuaW5pdGVkICYmIG1vZC5mZXRjaGVkICYmIG1hcC5pc0RlZmluZSkgewogICAgICAgICAgICAgICAgICAgICAgICBzdGlsbExvYWRpbmcgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW1hcC5wcmVmaXgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vTm8gcmVhc29uIHRvIGtlZXAgbG9va2luZyBmb3IgdW5maW5pc2hlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9sb2FkaW5nLiBJZiB0aGUgb25seSBzdGlsbExvYWRpbmcgaXMgYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9wbHVnaW4gcmVzb3VyY2UgdGhvdWdoLCBrZWVwIGdvaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9iZWNhdXNlIGl0IG1heSBiZSB0aGF0IGEgcGx1Z2luIHJlc291cmNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL2lzIHdhaXRpbmcgb24gYSBub24tcGx1Z2luIGN5Y2xlLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChuZWVkQ3ljbGVDaGVjayA9IGZhbHNlKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSk7CgogICAgICAgICAgICBpZiAoZXhwaXJlZCAmJiBub0xvYWRzLmxlbmd0aCkgewogICAgICAgICAgICAgICAgLy9JZiB3YWl0IHRpbWUgZXhwaXJlZCwgdGhyb3cgZXJyb3Igb2YgdW5sb2FkZWQgbW9kdWxlcy4KICAgICAgICAgICAgICAgIGVyciA9IG1ha2VFcnJvcigndGltZW91dCcsICdMb2FkIHRpbWVvdXQgZm9yIG1vZHVsZXM6ICcgKyBub0xvYWRzLCBudWxsLCBub0xvYWRzKTsKICAgICAgICAgICAgICAgIGVyci5jb250ZXh0TmFtZSA9IGNvbnRleHQuY29udGV4dE5hbWU7CiAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihlcnIpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvL05vdCBleHBpcmVkLCBjaGVjayBmb3IgYSBjeWNsZS4KICAgICAgICAgICAgaWYgKG5lZWRDeWNsZUNoZWNrKSB7CiAgICAgICAgICAgICAgICBlYWNoKHJlcUNhbGxzLCBmdW5jdGlvbiAobW9kKSB7CiAgICAgICAgICAgICAgICAgICAgYnJlYWtDeWNsZShtb2QsIHt9LCB7fSk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy9JZiBzdGlsbCB3YWl0aW5nIG9uIGxvYWRzLCBhbmQgdGhlIHdhaXRpbmcgbG9hZCBpcyBzb21ldGhpbmcKICAgICAgICAgICAgLy9vdGhlciB0aGFuIGEgcGx1Z2luIHJlc291cmNlLCBvciB0aGVyZSBhcmUgc3RpbGwgb3V0c3RhbmRpbmcKICAgICAgICAgICAgLy9zY3JpcHRzLCB0aGVuIGp1c3QgdHJ5IGJhY2sgbGF0ZXIuCiAgICAgICAgICAgIGlmICgoIWV4cGlyZWQgfHwgdXNpbmdQYXRoRmFsbGJhY2spICYmIHN0aWxsTG9hZGluZykgewogICAgICAgICAgICAgICAgLy9Tb21ldGhpbmcgaXMgc3RpbGwgd2FpdGluZyB0byBsb2FkLiBXYWl0IGZvciBpdCwgYnV0IG9ubHkKICAgICAgICAgICAgICAgIC8vaWYgYSB0aW1lb3V0IGlzIG5vdCBhbHJlYWR5IGluIGVmZmVjdC4KICAgICAgICAgICAgICAgIGlmICgoaXNCcm93c2VyIHx8IGlzV2ViV29ya2VyKSAmJiAhY2hlY2tMb2FkZWRUaW1lb3V0SWQpIHsKICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICBjaGVja0xvYWRlZFRpbWVvdXRJZCA9IDA7CiAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrTG9hZGVkKCk7CiAgICAgICAgICAgICAgICAgICAgfSwgNTApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBpbkNoZWNrTG9hZGVkID0gZmFsc2U7CiAgICAgICAgfQoKICAgICAgICBNb2R1bGUgPSBmdW5jdGlvbiAobWFwKSB7CiAgICAgICAgICAgIHRoaXMuZXZlbnRzID0gZ2V0T3duKHVuZGVmRXZlbnRzLCBtYXAuaWQpIHx8IHt9OwogICAgICAgICAgICB0aGlzLm1hcCA9IG1hcDsKICAgICAgICAgICAgdGhpcy5zaGltID0gZ2V0T3duKGNvbmZpZy5zaGltLCBtYXAuaWQpOwogICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHMgPSBbXTsKICAgICAgICAgICAgdGhpcy5kZXBNYXBzID0gW107CiAgICAgICAgICAgIHRoaXMuZGVwTWF0Y2hlZCA9IFtdOwogICAgICAgICAgICB0aGlzLnBsdWdpbk1hcHMgPSB7fTsKICAgICAgICAgICAgdGhpcy5kZXBDb3VudCA9IDA7CgogICAgICAgICAgICAvKiB0aGlzLmV4cG9ydHMgdGhpcy5mYWN0b3J5CiAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcyA9IFtdLAogICAgICAgICAgICAgICB0aGlzLmVuYWJsZWQsIHRoaXMuZmV0Y2hlZAogICAgICAgICAgICAqLwogICAgICAgIH07CgogICAgICAgIE1vZHVsZS5wcm90b3R5cGUgPSB7CiAgICAgICAgICAgIGluaXQ6IGZ1bmN0aW9uIChkZXBNYXBzLCBmYWN0b3J5LCBlcnJiYWNrLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIG5vdCBkbyBtb3JlIGluaXRzIGlmIGFscmVhZHkgZG9uZS4gQ2FuIGhhcHBlbiBpZiB0aGVyZQogICAgICAgICAgICAgICAgLy9hcmUgbXVsdGlwbGUgZGVmaW5lIGNhbGxzIGZvciB0aGUgc2FtZSBtb2R1bGUuIFRoYXQgaXMgbm90CiAgICAgICAgICAgICAgICAvL2Egbm9ybWFsLCBjb21tb24gY2FzZSwgYnV0IGl0IGlzIGFsc28gbm90IHVuZXhwZWN0ZWQuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgdGhpcy5mYWN0b3J5ID0gZmFjdG9yeTsKCiAgICAgICAgICAgICAgICBpZiAoZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgIC8vUmVnaXN0ZXIgZm9yIGVycm9ycyBvbiB0aGlzIG1vZHVsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLm9uKCdlcnJvcicsIGVycmJhY2spOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLmV2ZW50cy5lcnJvcikgewogICAgICAgICAgICAgICAgICAgIC8vSWYgbm8gZXJyYmFjayBhbHJlYWR5LCBidXQgdGhlcmUgYXJlIGVycm9yIGxpc3RlbmVycwogICAgICAgICAgICAgICAgICAgIC8vb24gdGhpcyBtb2R1bGUsIHNldCB1cCBhbiBlcnJiYWNrIHRvIHBhc3MgdG8gdGhlIGRlcHMuCiAgICAgICAgICAgICAgICAgICAgZXJyYmFjayA9IGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0RvIGEgY29weSBvZiB0aGUgZGVwZW5kZW5jeSBhcnJheSwgc28gdGhhdAogICAgICAgICAgICAgICAgLy9zb3VyY2UgaW5wdXRzIGFyZSBub3QgbW9kaWZpZWQuIEZvciBleGFtcGxlCiAgICAgICAgICAgICAgICAvLyJzaGltIiBkZXBzIGFyZSBwYXNzZWQgaW4gaGVyZSBkaXJlY3RseSwgYW5kCiAgICAgICAgICAgICAgICAvL2RvaW5nIGEgZGlyZWN0IG1vZGlmaWNhdGlvbiBvZiB0aGUgZGVwTWFwcyBhcnJheQogICAgICAgICAgICAgICAgLy93b3VsZCBhZmZlY3QgdGhhdCBjb25maWcuCiAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMgPSBkZXBNYXBzICYmIGRlcE1hcHMuc2xpY2UoMCk7CgogICAgICAgICAgICAgICAgdGhpcy5lcnJiYWNrID0gZXJyYmFjazsKCiAgICAgICAgICAgICAgICAvL0luZGljYXRlIHRoaXMgbW9kdWxlIGhhcyBiZSBpbml0aWFsaXplZAogICAgICAgICAgICAgICAgdGhpcy5pbml0ZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIHRoaXMuaWdub3JlID0gb3B0aW9ucy5pZ25vcmU7CgogICAgICAgICAgICAgICAgLy9Db3VsZCBoYXZlIG9wdGlvbiB0byBpbml0IHRoaXMgbW9kdWxlIGluIGVuYWJsZWQgbW9kZSwKICAgICAgICAgICAgICAgIC8vb3IgY291bGQgaGF2ZSBiZWVuIHByZXZpb3VzbHkgbWFya2VkIGFzIGVuYWJsZWQuIEhvd2V2ZXIsCiAgICAgICAgICAgICAgICAvL3RoZSBkZXBlbmRlbmNpZXMgYXJlIG5vdCBrbm93biB1bnRpbCBpbml0IGlzIGNhbGxlZC4gU28KICAgICAgICAgICAgICAgIC8vaWYgZW5hYmxlZCBwcmV2aW91c2x5LCBub3cgdHJpZ2dlciBkZXBlbmRlbmNpZXMgYXMgZW5hYmxlZC4KICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVuYWJsZWQgfHwgdGhpcy5lbmFibGVkKSB7CiAgICAgICAgICAgICAgICAgICAgLy9FbmFibGUgdGhpcyBtb2R1bGUgYW5kIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAvL1dpbGwgY2FsbCB0aGlzLmNoZWNrKCkKICAgICAgICAgICAgICAgICAgICB0aGlzLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmNoZWNrKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBkZWZpbmVEZXA6IGZ1bmN0aW9uIChpLCBkZXBFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAvL0JlY2F1c2Ugb2YgY3ljbGVzLCBkZWZpbmVkIGNhbGxiYWNrIGZvciBhIGdpdmVuCiAgICAgICAgICAgICAgICAvL2V4cG9ydCBjYW4gYmUgY2FsbGVkIG1vcmUgdGhhbiBvbmNlLgogICAgICAgICAgICAgICAgaWYgKCF0aGlzLmRlcE1hdGNoZWRbaV0pIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hdGNoZWRbaV0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwQ291bnQgLT0gMTsKICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcEV4cG9ydHNbaV0gPSBkZXBFeHBvcnRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZmV0Y2g6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIGlmICh0aGlzLmZldGNoZWQpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB0aGlzLmZldGNoZWQgPSB0cnVlOwoKICAgICAgICAgICAgICAgIGNvbnRleHQuc3RhcnRUaW1lID0gKG5ldyBEYXRlKCkpLmdldFRpbWUoKTsKCiAgICAgICAgICAgICAgICB2YXIgbWFwID0gdGhpcy5tYXA7CgogICAgICAgICAgICAgICAgLy9JZiB0aGUgbWFuYWdlciBpcyBmb3IgYSBwbHVnaW4gbWFuYWdlZCByZXNvdXJjZSwKICAgICAgICAgICAgICAgIC8vYXNrIHRoZSBwbHVnaW4gdG8gbG9hZCBpdCBub3cuCiAgICAgICAgICAgICAgICBpZiAodGhpcy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5tYWtlUmVxdWlyZSh0aGlzLm1hcCwgewogICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVCdWlsZENhbGxiYWNrOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgfSkodGhpcy5zaGltLmRlcHMgfHwgW10sIGJpbmQodGhpcywgZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgfSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL1JlZ3VsYXIgZGVwZW5kZW5jeS4KICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWFwLnByZWZpeCA/IHRoaXMuY2FsbFBsdWdpbigpIDogdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICBsb2FkOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICB2YXIgdXJsID0gdGhpcy5tYXAudXJsOwoKICAgICAgICAgICAgICAgIC8vUmVndWxhciBkZXBlbmRlbmN5LgogICAgICAgICAgICAgICAgaWYgKCF1cmxGZXRjaGVkW3VybF0pIHsKICAgICAgICAgICAgICAgICAgICB1cmxGZXRjaGVkW3VybF0gPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIGNvbnRleHQubG9hZCh0aGlzLm1hcC5pZCwgdXJsKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBDaGVja3MgaWYgdGhlIG1vZHVsZSBpcyByZWFkeSB0byBkZWZpbmUgaXRzZWxmLCBhbmQgaWYgc28sCiAgICAgICAgICAgICAqIGRlZmluZSBpdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNoZWNrOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuZW5hYmxlZCB8fCB0aGlzLmVuYWJsaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHZhciBlcnIsIGNqc01vZHVsZSwKICAgICAgICAgICAgICAgICAgICBpZCA9IHRoaXMubWFwLmlkLAogICAgICAgICAgICAgICAgICAgIGRlcEV4cG9ydHMgPSB0aGlzLmRlcEV4cG9ydHMsCiAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0cywKICAgICAgICAgICAgICAgICAgICBmYWN0b3J5ID0gdGhpcy5mYWN0b3J5OwoKICAgICAgICAgICAgICAgIGlmICghdGhpcy5pbml0ZWQpIHsKICAgICAgICAgICAgICAgICAgICAvLyBPbmx5IGZldGNoIGlmIG5vdCBhbHJlYWR5IGluIHRoZSBkZWZRdWV1ZS4KICAgICAgICAgICAgICAgICAgICBpZiAoIWhhc1Byb3AoY29udGV4dC5kZWZRdWV1ZU1hcCwgaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZmV0Y2goKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgdGhpcy5lcnJvcik7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLmRlZmluaW5nKSB7CiAgICAgICAgICAgICAgICAgICAgLy9UaGUgZmFjdG9yeSBjb3VsZCB0cmlnZ2VyIGFub3RoZXIgcmVxdWlyZSBjYWxsCiAgICAgICAgICAgICAgICAgICAgLy90aGF0IHdvdWxkIHJlc3VsdCBpbiBjaGVja2luZyB0aGlzIG1vZHVsZSB0bwogICAgICAgICAgICAgICAgICAgIC8vZGVmaW5lIGl0c2VsZiBhZ2Fpbi4gSWYgYWxyZWFkeSBpbiB0aGUgcHJvY2VzcwogICAgICAgICAgICAgICAgICAgIC8vb2YgZG9pbmcgdGhhdCwgc2tpcCB0aGlzIHdvcmsuCiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWZpbmluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlcENvdW50IDwgMSAmJiAhdGhpcy5kZWZpbmVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0Z1bmN0aW9uKGZhY3RvcnkpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjb250ZXh0LmV4ZWNDYihpZCwgZmFjdG9yeSwgZGVwRXhwb3J0cywgZXhwb3J0cyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyID0gZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGYXZvciByZXR1cm4gdmFsdWUgb3ZlciBleHBvcnRzLiBJZiBub2RlL2NqcyBpbiBwbGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlbiB3aWxsIG5vdCBoYXZlIGEgcmV0dXJuIHZhbHVlIGFueXdheS4gRmF2b3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1vZHVsZS5leHBvcnRzIGFzc2lnbm1lbnQgb3ZlciBleHBvcnRzIG9iamVjdC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm1hcC5pc0RlZmluZSAmJiBleHBvcnRzID09PSB1bmRlZmluZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjanNNb2R1bGUgPSB0aGlzLm1vZHVsZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2pzTW9kdWxlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBjanNNb2R1bGUuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMudXNpbmdFeHBvcnRzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vZXhwb3J0cyBhbHJlYWR5IHNldCB0aGUgZGVmaW5lZCB2YWx1ZS4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwb3J0cyA9IHRoaXMuZXhwb3J0czsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZXJlIGlzIGFuIGVycm9yIGxpc3RlbmVyLCBmYXZvciBwYXNzaW5nCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdG8gdGhhdCBpbnN0ZWFkIG9mIHRocm93aW5nIGFuIGVycm9yLiBIb3dldmVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9ubHkgZG8gaXQgZm9yIGRlZmluZSgpJ2QgIG1vZHVsZXMuIHJlcXVpcmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBlcnJiYWNrcyBzaG91bGQgbm90IGJlIGNhbGxlZCBmb3IgZmFpbHVyZXMgaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGVpciBjYWxsYmFja3MgKCM2OTkpLiBIb3dldmVyIGlmIGEgZ2xvYmFsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb25FcnJvciBpcyBzZXQsIHVzZSB0aGF0LgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodGhpcy5ldmVudHMuZXJyb3IgJiYgdGhpcy5tYXAuaXNEZWZpbmUpIHx8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5vbkVycm9yICE9PSBkZWZhdWx0T25FcnJvcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1hcCA9IHRoaXMubWFwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZU1vZHVsZXMgPSB0aGlzLm1hcC5pc0RlZmluZSA/IFt0aGlzLm1hcC5pZF0gOiBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIucmVxdWlyZVR5cGUgPSB0aGlzLm1hcC5pc0RlZmluZSA/ICdkZWZpbmUnIDogJ3JlcXVpcmUnOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcigodGhpcy5lcnJvciA9IGVycikpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvZyB0aGUgZXJyb3IgZm9yIGRlYnVnZ2luZy4gSWYgcHJvbWlzZXMgY291bGQgYmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdXNlZCwgdGhpcyB3b3VsZCBiZSBkaWZmZXJlbnQsIGJ1dCBtYWtpbmcgZG8uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBEbyBub3Qgd2FudCB0byBjb21wbGV0ZWx5IGxvc2UgdGhlIGVycm9yLiBXaGlsZSB0aGlzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpbGwgbWVzcyB1cCBwcm9jZXNzaW5nIGFuZCBsZWFkIHRvIHNpbWlsYXIgcmVzdWx0cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcyBidWcgMTQ0MCwgaXQgYXQgbGVhc3Qgc3VyZmFjZXMgdGhlIGVycm9yLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXEub25FcnJvcihlcnIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIGxpdGVyYWwgdmFsdWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9ydHMgPSBmYWN0b3J5OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmV4cG9ydHMgPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubWFwLmlzRGVmaW5lICYmICF0aGlzLmlnbm9yZSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmaW5lZFtpZF0gPSBleHBvcnRzOwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEub25SZXNvdXJjZUxvYWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzTG9hZE1hcHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNMb2FkTWFwcy5wdXNoKGRlcE1hcC5ub3JtYWxpemVkTWFwIHx8IGRlcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxLm9uUmVzb3VyY2VMb2FkKGNvbnRleHQsIHRoaXMubWFwLCByZXNMb2FkTWFwcyk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQ2xlYW4gdXAKICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgLy9GaW5pc2hlZCB0aGUgZGVmaW5lIHN0YWdlLiBBbGxvdyBjYWxsaW5nIGNoZWNrIGFnYWluCiAgICAgICAgICAgICAgICAgICAgLy90byBhbGxvdyBkZWZpbmUgbm90aWZpY2F0aW9ucyBiZWxvdyBpbiB0aGUgY2FzZSBvZiBhCiAgICAgICAgICAgICAgICAgICAgLy9jeWNsZS4KICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluaW5nID0gZmFsc2U7CgogICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRlZmluZWQgJiYgIXRoaXMuZGVmaW5lRW1pdHRlZCkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXR0ZWQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2RlZmluZWQnLCB0aGlzLmV4cG9ydHMpOwogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZUVtaXRDb21wbGV0ZSA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGNhbGxQbHVnaW46IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIHZhciBtYXAgPSB0aGlzLm1hcCwKICAgICAgICAgICAgICAgICAgICBpZCA9IG1hcC5pZCwKICAgICAgICAgICAgICAgICAgICAvL01hcCBhbHJlYWR5IG5vcm1hbGl6ZWQgdGhlIHByZWZpeC4KICAgICAgICAgICAgICAgICAgICBwbHVnaW5NYXAgPSBtYWtlTW9kdWxlTWFwKG1hcC5wcmVmaXgpOwoKICAgICAgICAgICAgICAgIC8vTWFyayB0aGlzIGFzIGEgZGVwZW5kZW5jeSBmb3IgdGhpcyBwbHVnaW4sIHNvIGl0CiAgICAgICAgICAgICAgICAvL2NhbiBiZSB0cmFjZWQgZm9yIGN5Y2xlcy4KICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwcy5wdXNoKHBsdWdpbk1hcCk7CgogICAgICAgICAgICAgICAgb24ocGx1Z2luTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbikgewogICAgICAgICAgICAgICAgICAgIHZhciBsb2FkLCBub3JtYWxpemVkTWFwLCBub3JtYWxpemVkTW9kLAogICAgICAgICAgICAgICAgICAgICAgICBidW5kbGVJZCA9IGdldE93bihidW5kbGVzTWFwLCB0aGlzLm1hcC5pZCksCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSB0aGlzLm1hcC5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnROYW1lID0gdGhpcy5tYXAucGFyZW50TWFwID8gdGhpcy5tYXAucGFyZW50TWFwLm5hbWUgOiBudWxsLAogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKG1hcC5wYXJlbnRNYXAsIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZUJ1aWxkQ2FsbGJhY2s6IHRydWUKICAgICAgICAgICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgICAgIC8vSWYgY3VycmVudCBtYXAgaXMgbm90IG5vcm1hbGl6ZWQsIHdhaXQgZm9yIHRoYXQKICAgICAgICAgICAgICAgICAgICAvL25vcm1hbGl6ZWQgbmFtZSB0byBsb2FkIGluc3RlYWQgb2YgY29udGludWluZy4KICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5tYXAudW5ub3JtYWxpemVkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIHRoZSBJRCBpZiB0aGUgcGx1Z2luIGFsbG93cyBpdC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBsdWdpbi5ub3JtYWxpemUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBwbHVnaW4ubm9ybWFsaXplKG5hbWUsIGZ1bmN0aW9uIChuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZShuYW1lLCBwYXJlbnROYW1lLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pIHx8ICcnOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL3ByZWZpeCBhbmQgbmFtZSBzaG91bGQgYWxyZWFkeSBiZSBub3JtYWxpemVkLCBubyBuZWVkCiAgICAgICAgICAgICAgICAgICAgICAgIC8vZm9yIGFwcGx5aW5nIG1hcCBjb25maWcgYWdhaW4gZWl0aGVyLgogICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTWFwID0gbWFrZU1vZHVsZU1hcChtYXAucHJlZml4ICsgJyEnICsgbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tYXAucGFyZW50TWFwKTsKICAgICAgICAgICAgICAgICAgICAgICAgb24obm9ybWFsaXplZE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICdkZWZpbmVkJywgYmluZCh0aGlzLCBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hcC5ub3JtYWxpemVkTWFwID0gbm9ybWFsaXplZE1hcDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZTogdHJ1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZE1vZCA9IGdldE93bihyZWdpc3RyeSwgbm9ybWFsaXplZE1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkTW9kKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL01hcmsgdGhpcyBhcyBhIGRlcGVuZGVuY3kgZm9yIHRoaXMgcGx1Z2luLCBzbyBpdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9jYW4gYmUgdHJhY2VkIGZvciBjeWNsZXMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlcE1hcHMucHVzaChub3JtYWxpemVkTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5ldmVudHMuZXJyb3IpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLm9uKCdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24gKGVycikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkTW9kLmVuYWJsZSgpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0lmIGEgcGF0aHMgY29uZmlnLCB0aGVuIGp1c3QgbG9hZCB0aGF0IGZpbGUgaW5zdGVhZCB0bwogICAgICAgICAgICAgICAgICAgIC8vcmVzb2x2ZSB0aGUgcGx1Z2luLCBhcyBpdCBpcyBidWlsdCBpbnRvIHRoYXQgcGF0aHMgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWFwLnVybCA9IGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkKTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2FkKCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGxvYWQgPSBiaW5kKHRoaXMsIGZ1bmN0aW9uICh2YWx1ZSkgewogICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmluaXQoW10sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHZhbHVlOyB9LCBudWxsLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICBsb2FkLmVycm9yID0gYmluZCh0aGlzLCBmdW5jdGlvbiAoZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdGVkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvciA9IGVycjsKICAgICAgICAgICAgICAgICAgICAgICAgZXJyLnJlcXVpcmVNb2R1bGVzID0gW2lkXTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vUmVtb3ZlIHRlbXAgdW5ub3JtYWxpemVkIG1vZHVsZXMgZm9yIHRoaXMgbW9kdWxlLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NpbmNlIHRoZXkgd2lsbCBuZXZlciBiZSByZXNvbHZlZCBvdGhlcndpc2Ugbm93LgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5tYXAuaWQuaW5kZXhPZihpZCArICdfdW5ub3JtYWxpemVkJykgPT09IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhblJlZ2lzdHJ5KG1vZC5tYXAuaWQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgICAgIG9uRXJyb3IoZXJyKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9BbGxvdyBwbHVnaW5zIHRvIGxvYWQgb3RoZXIgY29kZSB3aXRob3V0IGhhdmluZyB0byBrbm93IHRoZQogICAgICAgICAgICAgICAgICAgIC8vY29udGV4dCBvciBob3cgdG8gJ2NvbXBsZXRlJyB0aGUgbG9hZC4KICAgICAgICAgICAgICAgICAgICBsb2FkLmZyb21UZXh0ID0gYmluZCh0aGlzLCBmdW5jdGlvbiAodGV4dCwgdGV4dEFsdCkgewogICAgICAgICAgICAgICAgICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtb2R1bGVOYW1lID0gbWFwLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVNYXAgPSBtYWtlTW9kdWxlTWFwKG1vZHVsZU5hbWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzSW50ZXJhY3RpdmUgPSB1c2VJbnRlcmFjdGl2ZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vQXMgb2YgMi4xLjAsIHN1cHBvcnQganVzdCBwYXNzaW5nIHRoZSB0ZXh0LCB0byByZWluZm9yY2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9mcm9tVGV4dCBvbmx5IGJlaW5nIGNhbGxlZCBvbmNlIHBlciByZXNvdXJjZS4gU3RpbGwKICAgICAgICAgICAgICAgICAgICAgICAgLy9zdXBwb3J0IG9sZCBzdHlsZSBvZiBwYXNzaW5nIG1vZHVsZU5hbWUgYnV0IGRpc2NhcmQKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGF0IG1vZHVsZU5hbWUgaW4gZmF2b3Igb2YgdGhlIGludGVybmFsIHJlZi4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRleHRBbHQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHQgPSB0ZXh0QWx0OwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1R1cm4gb2ZmIGludGVyYWN0aXZlIHNjcmlwdCBtYXRjaGluZyBmb3IgSUUgZm9yIGFueSBkZWZpbmUKICAgICAgICAgICAgICAgICAgICAgICAgLy9jYWxscyBpbiB0aGUgdGV4dCwgdGhlbiB0dXJuIGl0IGJhY2sgb24gYXQgdGhlIGVuZC4KICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc0ludGVyYWN0aXZlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VJbnRlcmFjdGl2ZSA9IGZhbHNlOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvL1ByaW1lIHRoZSBzeXN0ZW0gYnkgY3JlYXRpbmcgYSBtb2R1bGUgaW5zdGFuY2UgZm9yCiAgICAgICAgICAgICAgICAgICAgICAgIC8vaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGdldE1vZHVsZShtb2R1bGVNYXApOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9UcmFuc2ZlciBhbnkgY29uZmlnIHRvIHRoaXMgb3RoZXIgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzUHJvcChjb25maWcuY29uZmlnLCBpZCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5jb25maWdbbW9kdWxlTmFtZV0gPSBjb25maWcuY29uZmlnW2lkXTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5leGVjKHRleHQpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ2Zyb210ZXh0ZXZhbCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdmcm9tVGV4dCBldmFsIGZvciAnICsgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcgZmFpbGVkOiAnICsgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2lkXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9NYXJrIHRoaXMgYXMgYSBkZXBlbmRlbmN5IGZvciB0aGUgcGx1Z2luCiAgICAgICAgICAgICAgICAgICAgICAgIC8vcmVzb3VyY2UKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBNYXBzLnB1c2gobW9kdWxlTWFwKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3VwcG9ydCBhbm9ueW1vdXMgbW9kdWxlcy4KICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQobW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgdGhlIHZhbHVlIG9mIHRoYXQgbW9kdWxlIHRvIHRoZSB2YWx1ZSBmb3IgdGhpcwogICAgICAgICAgICAgICAgICAgICAgICAvL3Jlc291cmNlIElELgogICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFJlcXVpcmUoW21vZHVsZU5hbWVdLCBsb2FkKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgLy9Vc2UgcGFyZW50TmFtZSBoZXJlIHNpbmNlIHRoZSBwbHVnaW4ncyBuYW1lIGlzIG5vdCByZWxpYWJsZSwKICAgICAgICAgICAgICAgICAgICAvL2NvdWxkIGJlIHNvbWUgd2VpcmQgc3RyaW5nIHdpdGggbm8gcGF0aCB0aGF0IGFjdHVhbGx5IHdhbnRzIHRvCiAgICAgICAgICAgICAgICAgICAgLy9yZWZlcmVuY2UgdGhlIHBhcmVudE5hbWUncyBwYXRoLgogICAgICAgICAgICAgICAgICAgIHBsdWdpbi5sb2FkKG1hcC5uYW1lLCBsb2NhbFJlcXVpcmUsIGxvYWQsIGNvbmZpZyk7CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luTWFwc1twbHVnaW5NYXAuaWRdID0gcGx1Z2luTWFwOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgZW5hYmxlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICBlbmFibGVkUmVnaXN0cnlbdGhpcy5tYXAuaWRdID0gdGhpczsKICAgICAgICAgICAgICAgIHRoaXMuZW5hYmxlZCA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9TZXQgZmxhZyBtZW50aW9uaW5nIHRoYXQgdGhlIG1vZHVsZSBpcyBlbmFibGluZywKICAgICAgICAgICAgICAgIC8vc28gdGhhdCBpbW1lZGlhdGUgY2FsbHMgdG8gdGhlIGRlZmluZWQgY2FsbGJhY2tzCiAgICAgICAgICAgICAgICAvL2ZvciBkZXBlbmRlbmNpZXMgZG8gbm90IHRyaWdnZXIgaW5hZHZlcnRlbnQgbG9hZAogICAgICAgICAgICAgICAgLy93aXRoIHRoZSBkZXBDb3VudCBzdGlsbCBiZWluZyB6ZXJvLgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IHRydWU7CgogICAgICAgICAgICAgICAgLy9FbmFibGUgZWFjaCBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoKHRoaXMuZGVwTWFwcywgYmluZCh0aGlzLCBmdW5jdGlvbiAoZGVwTWFwLCBpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIGlkLCBtb2QsIGhhbmRsZXI7CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwTWFwID09PSAnc3RyaW5nJykgewogICAgICAgICAgICAgICAgICAgICAgICAvL0RlcGVuZGVuY3kgbmVlZHMgdG8gYmUgY29udmVydGVkIHRvIGEgZGVwTWFwCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYW5kIHdpcmVkIHVwIHRvIHRoaXMgbW9kdWxlLgogICAgICAgICAgICAgICAgICAgICAgICBkZXBNYXAgPSBtYWtlTW9kdWxlTWFwKGRlcE1hcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5tYXAuaXNEZWZpbmUgPyB0aGlzLm1hcCA6IHRoaXMubWFwLnBhcmVudE1hcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIXRoaXMuc2tpcE1hcCk7CiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGVwTWFwc1tpXSA9IGRlcE1hcDsKCiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZXIgPSBnZXRPd24oaGFuZGxlcnMsIGRlcE1hcC5pZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFuZGxlcikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBFeHBvcnRzW2ldID0gaGFuZGxlcih0aGlzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXBDb3VudCArPSAxOwoKICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZGVmaW5lZCcsIGJpbmQodGhpcywgZnVuY3Rpb24gKGRlcEV4cG9ydHMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnVuZGVmZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmluZURlcChpLCBkZXBFeHBvcnRzKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgICAgICAgICAgICAgfSkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZXJyYmFjaykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgb24oZGVwTWFwLCAnZXJyb3InLCBiaW5kKHRoaXMsIHRoaXMuZXJyYmFjaykpOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZXZlbnRzLmVycm9yKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBObyBkaXJlY3QgZXJyYmFjayBvbiB0aGlzIG1vZHVsZSwgYnV0IHNvbWV0aGluZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWxzZSBpcyBsaXN0ZW5pbmcgZm9yIGVycm9ycywgc28gYmUgc3VyZSB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJvcGFnYXRlIHRoZSBlcnJvciBjb3JyZWN0bHkuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbihkZXBNYXAsICdlcnJvcicsIGJpbmQodGhpcywgZnVuY3Rpb24oZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIGVycik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlkID0gZGVwTWFwLmlkOwogICAgICAgICAgICAgICAgICAgIG1vZCA9IHJlZ2lzdHJ5W2lkXTsKCiAgICAgICAgICAgICAgICAgICAgLy9Ta2lwIHNwZWNpYWwgbW9kdWxlcyBsaWtlICdyZXF1aXJlJywgJ2V4cG9ydHMnLCAnbW9kdWxlJwogICAgICAgICAgICAgICAgICAgIC8vQWxzbywgZG9uJ3QgY2FsbCBlbmFibGUgaWYgaXQgaXMgYWxyZWFkeSBlbmFibGVkLAogICAgICAgICAgICAgICAgICAgIC8vaW1wb3J0YW50IGluIGNpcmN1bGFyIGRlcGVuZGVuY3kgY2FzZXMuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGhhbmRsZXJzLCBpZCkgJiYgbW9kICYmICFtb2QuZW5hYmxlZCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LmVuYWJsZShkZXBNYXAsIHRoaXMpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pKTsKCiAgICAgICAgICAgICAgICAvL0VuYWJsZSBlYWNoIHBsdWdpbiB0aGF0IGlzIHVzZWQgaW4KICAgICAgICAgICAgICAgIC8vYSBkZXBlbmRlbmN5CiAgICAgICAgICAgICAgICBlYWNoUHJvcCh0aGlzLnBsdWdpbk1hcHMsIGJpbmQodGhpcywgZnVuY3Rpb24gKHBsdWdpbk1hcCkgewogICAgICAgICAgICAgICAgICAgIHZhciBtb2QgPSBnZXRPd24ocmVnaXN0cnksIHBsdWdpbk1hcC5pZCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCAmJiAhbW9kLmVuYWJsZWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dC5lbmFibGUocGx1Z2luTWFwLCB0aGlzKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9KSk7CgogICAgICAgICAgICAgICAgdGhpcy5lbmFibGluZyA9IGZhbHNlOwoKICAgICAgICAgICAgICAgIHRoaXMuY2hlY2soKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG9uOiBmdW5jdGlvbiAobmFtZSwgY2IpIHsKICAgICAgICAgICAgICAgIHZhciBjYnMgPSB0aGlzLmV2ZW50c1tuYW1lXTsKICAgICAgICAgICAgICAgIGlmICghY2JzKSB7CiAgICAgICAgICAgICAgICAgICAgY2JzID0gdGhpcy5ldmVudHNbbmFtZV0gPSBbXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNicy5wdXNoKGNiKTsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIGVtaXQ6IGZ1bmN0aW9uIChuYW1lLCBldnQpIHsKICAgICAgICAgICAgICAgIGVhY2godGhpcy5ldmVudHNbbmFtZV0sIGZ1bmN0aW9uIChjYikgewogICAgICAgICAgICAgICAgICAgIGNiKGV2dCk7CiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIGlmIChuYW1lID09PSAnZXJyb3InKSB7CiAgICAgICAgICAgICAgICAgICAgLy9Ob3cgdGhhdCB0aGUgZXJyb3IgaGFuZGxlciB3YXMgdHJpZ2dlcmVkLCByZW1vdmUKICAgICAgICAgICAgICAgICAgICAvL3RoZSBsaXN0ZW5lcnMsIHNpbmNlIHRoaXMgYnJva2VuIE1vZHVsZSBpbnN0YW5jZQogICAgICAgICAgICAgICAgICAgIC8vY2FuIHN0YXkgYXJvdW5kIGZvciBhIHdoaWxlIGluIHRoZSByZWdpc3RyeS4KICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5ldmVudHNbbmFtZV07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBmdW5jdGlvbiBjYWxsR2V0TW9kdWxlKGFyZ3MpIHsKICAgICAgICAgICAgLy9Ta2lwIG1vZHVsZXMgYWxyZWFkeSBkZWZpbmVkLgogICAgICAgICAgICBpZiAoIWhhc1Byb3AoZGVmaW5lZCwgYXJnc1swXSkpIHsKICAgICAgICAgICAgICAgIGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKGFyZ3NbMF0sIG51bGwsIHRydWUpKS5pbml0KGFyZ3NbMV0sIGFyZ3NbMl0pOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihub2RlLCBmdW5jLCBuYW1lLCBpZU5hbWUpIHsKICAgICAgICAgICAgLy9GYXZvciBkZXRhY2hFdmVudCBiZWNhdXNlIG9mIElFOQogICAgICAgICAgICAvL2lzc3VlLCBzZWUgYXR0YWNoRXZlbnQvYWRkRXZlbnRMaXN0ZW5lciBjb21tZW50IGVsc2V3aGVyZQogICAgICAgICAgICAvL2luIHRoaXMgZmlsZS4KICAgICAgICAgICAgaWYgKG5vZGUuZGV0YWNoRXZlbnQgJiYgIWlzT3BlcmEpIHsKICAgICAgICAgICAgICAgIC8vUHJvYmFibHkgSUUuIElmIG5vdCBpdCB3aWxsIHRocm93IGFuIGVycm9yLCB3aGljaCB3aWxsIGJlCiAgICAgICAgICAgICAgICAvL3VzZWZ1bCB0byBrbm93LgogICAgICAgICAgICAgICAgaWYgKGllTmFtZSkgewogICAgICAgICAgICAgICAgICAgIG5vZGUuZGV0YWNoRXZlbnQoaWVOYW1lLCBmdW5jKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUucmVtb3ZlRXZlbnRMaXN0ZW5lcihuYW1lLCBmdW5jLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8qKgogICAgICAgICAqIEdpdmVuIGFuIGV2ZW50IGZyb20gYSBzY3JpcHQgbm9kZSwgZ2V0IHRoZSByZXF1aXJlanMgaW5mbyBmcm9tIGl0LAogICAgICAgICAqIGFuZCB0aGVuIHJlbW92ZXMgdGhlIGV2ZW50IGxpc3RlbmVycyBvbiB0aGUgbm9kZS4KICAgICAgICAgKiBAcGFyYW0ge0V2ZW50fSBldnQKICAgICAgICAgKiBAcmV0dXJucyB7T2JqZWN0fQogICAgICAgICAqLwogICAgICAgIGZ1bmN0aW9uIGdldFNjcmlwdERhdGEoZXZ0KSB7CiAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgLy9hbGwgb2xkIGJyb3dzZXJzIHdpbGwgYmUgc3VwcG9ydGVkLCBidXQgdGhpcyBvbmUgd2FzIGVhc3kgZW5vdWdoCiAgICAgICAgICAgIC8vdG8gc3VwcG9ydCBhbmQgc3RpbGwgbWFrZXMgc2Vuc2UuCiAgICAgICAgICAgIHZhciBub2RlID0gZXZ0LmN1cnJlbnRUYXJnZXQgfHwgZXZ0LnNyY0VsZW1lbnQ7CgogICAgICAgICAgICAvL1JlbW92ZSB0aGUgbGlzdGVuZXJzIG9uY2UgaGVyZS4KICAgICAgICAgICAgcmVtb3ZlTGlzdGVuZXIobm9kZSwgY29udGV4dC5vblNjcmlwdExvYWQsICdsb2FkJywgJ29ucmVhZHlzdGF0ZWNoYW5nZScpOwogICAgICAgICAgICByZW1vdmVMaXN0ZW5lcihub2RlLCBjb250ZXh0Lm9uU2NyaXB0RXJyb3IsICdlcnJvcicpOwoKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIG5vZGU6IG5vZGUsCiAgICAgICAgICAgICAgICBpZDogbm9kZSAmJiBub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJykKICAgICAgICAgICAgfTsKICAgICAgICB9CgogICAgICAgIGZ1bmN0aW9uIGludGFrZURlZmluZXMoKSB7CiAgICAgICAgICAgIHZhciBhcmdzOwoKICAgICAgICAgICAgLy9BbnkgZGVmaW5lZCBtb2R1bGVzIGluIHRoZSBnbG9iYWwgcXVldWUsIGludGFrZSB0aGVtIG5vdy4KICAgICAgICAgICAgdGFrZUdsb2JhbFF1ZXVlKCk7CgogICAgICAgICAgICAvL01ha2Ugc3VyZSBhbnkgcmVtYWluaW5nIGRlZlF1ZXVlIGl0ZW1zIGdldCBwcm9wZXJseSBwcm9jZXNzZWQuCiAgICAgICAgICAgIHdoaWxlIChkZWZRdWV1ZS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGFyZ3MgPSBkZWZRdWV1ZS5zaGlmdCgpOwogICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ21pc21hdGNoJywgJ01pc21hdGNoZWQgYW5vbnltb3VzIGRlZmluZSgpIG1vZHVsZTogJyArCiAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3NbYXJncy5sZW5ndGggLSAxXSkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAvL2FyZ3MgYXJlIGlkLCBkZXBzLCBmYWN0b3J5LiBTaG91bGQgYmUgbm9ybWFsaXplZCBieSB0aGUKICAgICAgICAgICAgICAgICAgICAvL2RlZmluZSgpIGZ1bmN0aW9uLgogICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoYXJncyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZU1hcCA9IHt9OwogICAgICAgIH0KCiAgICAgICAgY29udGV4dCA9IHsKICAgICAgICAgICAgY29uZmlnOiBjb25maWcsCiAgICAgICAgICAgIGNvbnRleHROYW1lOiBjb250ZXh0TmFtZSwKICAgICAgICAgICAgcmVnaXN0cnk6IHJlZ2lzdHJ5LAogICAgICAgICAgICBkZWZpbmVkOiBkZWZpbmVkLAogICAgICAgICAgICB1cmxGZXRjaGVkOiB1cmxGZXRjaGVkLAogICAgICAgICAgICBkZWZRdWV1ZTogZGVmUXVldWUsCiAgICAgICAgICAgIGRlZlF1ZXVlTWFwOiB7fSwKICAgICAgICAgICAgTW9kdWxlOiBNb2R1bGUsCiAgICAgICAgICAgIG1ha2VNb2R1bGVNYXA6IG1ha2VNb2R1bGVNYXAsCiAgICAgICAgICAgIG5leHRUaWNrOiByZXEubmV4dFRpY2ssCiAgICAgICAgICAgIG9uRXJyb3I6IG9uRXJyb3IsCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogU2V0IGEgY29uZmlndXJhdGlvbiBmb3IgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgY29uZmlnIG9iamVjdCB0byBpbnRlZ3JhdGUuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBjb25maWd1cmU6IGZ1bmN0aW9uIChjZmcpIHsKICAgICAgICAgICAgICAgIC8vTWFrZSBzdXJlIHRoZSBiYXNlVXJsIGVuZHMgaW4gYSBzbGFzaC4KICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIGlmIChjZmcuYmFzZVVybC5jaGFyQXQoY2ZnLmJhc2VVcmwubGVuZ3RoIC0gMSkgIT09ICcvJykgewogICAgICAgICAgICAgICAgICAgICAgICBjZmcuYmFzZVVybCArPSAnLyc7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vU2F2ZSBvZmYgdGhlIHBhdGhzIHNpbmNlIHRoZXkgcmVxdWlyZSBzcGVjaWFsIHByb2Nlc3NpbmcsCiAgICAgICAgICAgICAgICAvL3RoZXkgYXJlIGFkZGl0aXZlLgogICAgICAgICAgICAgICAgdmFyIHNoaW0gPSBjb25maWcuc2hpbSwKICAgICAgICAgICAgICAgICAgICBvYmpzID0gewogICAgICAgICAgICAgICAgICAgICAgICBwYXRoczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlczogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnOiB0cnVlLAogICAgICAgICAgICAgICAgICAgICAgICBtYXA6IHRydWUKICAgICAgICAgICAgICAgICAgICB9OwoKICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZywgZnVuY3Rpb24gKHZhbHVlLCBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKG9ianNbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjb25maWdbcHJvcF0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHt9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIG1peGluKGNvbmZpZ1twcm9wXSwgdmFsdWUsIHRydWUsIHRydWUpOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZ1twcm9wXSA9IHZhbHVlOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgIC8vUmV2ZXJzZSBtYXAgdGhlIGJ1bmRsZXMKICAgICAgICAgICAgICAgIGlmIChjZmcuYnVuZGxlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2hQcm9wKGNmZy5idW5kbGVzLCBmdW5jdGlvbiAodmFsdWUsIHByb3ApIHsKICAgICAgICAgICAgICAgICAgICAgICAgZWFjaCh2YWx1ZSwgZnVuY3Rpb24gKHYpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2ICE9PSBwcm9wKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVuZGxlc01hcFt2XSA9IHByb3A7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vTWVyZ2Ugc2hpbQogICAgICAgICAgICAgICAgaWYgKGNmZy5zaGltKSB7CiAgICAgICAgICAgICAgICAgICAgZWFjaFByb3AoY2ZnLnNoaW0sIGZ1bmN0aW9uICh2YWx1ZSwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9Ob3JtYWxpemUgdGhlIHN0cnVjdHVyZQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlcHM6IHZhbHVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodmFsdWUuZXhwb3J0cyB8fCB2YWx1ZS5pbml0KSAmJiAhdmFsdWUuZXhwb3J0c0ZuKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5leHBvcnRzRm4gPSBjb250ZXh0Lm1ha2VTaGltRXhwb3J0cyh2YWx1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgc2hpbVtpZF0gPSB2YWx1ZTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICBjb25maWcuc2hpbSA9IHNoaW07CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgLy9BZGp1c3QgcGFja2FnZXMgaWYgbmVjZXNzYXJ5LgogICAgICAgICAgICAgICAgaWYgKGNmZy5wYWNrYWdlcykgewogICAgICAgICAgICAgICAgICAgIGVhY2goY2ZnLnBhY2thZ2VzLCBmdW5jdGlvbiAocGtnT2JqKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsb2NhdGlvbiwgbmFtZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHBrZ09iaiA9IHR5cGVvZiBwa2dPYmogPT09ICdzdHJpbmcnID8ge25hbWU6IHBrZ09ian0gOiBwa2dPYmo7CgogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gcGtnT2JqLm5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uID0gcGtnT2JqLmxvY2F0aW9uOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9jYXRpb24pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5wYXRoc1tuYW1lXSA9IHBrZ09iai5sb2NhdGlvbjsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TYXZlIHBvaW50ZXIgdG8gbWFpbiBtb2R1bGUgSUQgZm9yIHBrZyBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICAvL1JlbW92ZSBsZWFkaW5nIGRvdCBpbiBtYWluLCBzbyBtYWluIHBhdGhzIGFyZSBub3JtYWxpemVkLAogICAgICAgICAgICAgICAgICAgICAgICAvL2FuZCByZW1vdmUgYW55IHRyYWlsaW5nIC5qcywgc2luY2UgZGlmZmVyZW50IHBhY2thZ2UKICAgICAgICAgICAgICAgICAgICAgICAgLy9lbnZzIGhhdmUgZGlmZmVyZW50IGNvbnZlbnRpb25zOiBzb21lIHVzZSBhIG1vZHVsZSBuYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAvL3NvbWUgdXNlIGEgZmlsZSBuYW1lLgogICAgICAgICAgICAgICAgICAgICAgICBjb25maWcucGtnc1tuYW1lXSA9IHBrZ09iai5uYW1lICsgJy8nICsgKHBrZ09iai5tYWluIHx8ICdtYWluJykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKGN1cnJEaXJSZWdFeHAsICcnKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL0lmIHRoZXJlIGFyZSBhbnkgIndhaXRpbmcgdG8gZXhlY3V0ZSIgbW9kdWxlcyBpbiB0aGUgcmVnaXN0cnksCiAgICAgICAgICAgICAgICAvL3VwZGF0ZSB0aGUgbWFwcyBmb3IgdGhlbSwgc2luY2UgdGhlaXIgaW5mbywgbGlrZSBVUkxzIHRvIGxvYWQsCiAgICAgICAgICAgICAgICAvL21heSBoYXZlIGNoYW5nZWQuCiAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24gKG1vZCwgaWQpIHsKICAgICAgICAgICAgICAgICAgICAvL0lmIG1vZHVsZSBhbHJlYWR5IGhhcyBpbml0IGNhbGxlZCwgc2luY2UgaXQgaXMgdG9vCiAgICAgICAgICAgICAgICAgICAgLy9sYXRlIHRvIG1vZGlmeSB0aGVtLCBhbmQgaWdub3JlIHVubm9ybWFsaXplZCBvbmVzCiAgICAgICAgICAgICAgICAgICAgLy9zaW5jZSB0aGV5IGFyZSB0cmFuc2llbnQuCiAgICAgICAgICAgICAgICAgICAgaWYgKCFtb2QuaW5pdGVkICYmICFtb2QubWFwLnVubm9ybWFsaXplZCkgewogICAgICAgICAgICAgICAgICAgICAgICBtb2QubWFwID0gbWFrZU1vZHVsZU1hcChpZCwgbnVsbCwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9JZiBhIGRlcHMgYXJyYXkgb3IgYSBjb25maWcgY2FsbGJhY2sgaXMgc3BlY2lmaWVkLCB0aGVuIGNhbGwKICAgICAgICAgICAgICAgIC8vcmVxdWlyZSB3aXRoIHRob3NlIGFyZ3MuIFRoaXMgaXMgdXNlZnVsIHdoZW4gcmVxdWlyZSBpcyBkZWZpbmVkIGFzIGEKICAgICAgICAgICAgICAgIC8vY29uZmlnIG9iamVjdCBiZWZvcmUgcmVxdWlyZS5qcyBpcyBsb2FkZWQuCiAgICAgICAgICAgICAgICBpZiAoY2ZnLmRlcHMgfHwgY2ZnLmNhbGxiYWNrKSB7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5yZXF1aXJlKGNmZy5kZXBzIHx8IFtdLCBjZmcuY2FsbGJhY2spOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAoKICAgICAgICAgICAgbWFrZVNoaW1FeHBvcnRzOiBmdW5jdGlvbiAodmFsdWUpIHsKICAgICAgICAgICAgICAgIGZ1bmN0aW9uIGZuKCkgewogICAgICAgICAgICAgICAgICAgIHZhciByZXQ7CiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlLmluaXQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0ID0gdmFsdWUuaW5pdC5hcHBseShnbG9iYWwsIGFyZ3VtZW50cyk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIHJldHVybiByZXQgfHwgKHZhbHVlLmV4cG9ydHMgJiYgZ2V0R2xvYmFsKHZhbHVlLmV4cG9ydHMpKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBmbjsKICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIG1ha2VSZXF1aXJlOiBmdW5jdGlvbiAocmVsTWFwLCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKCiAgICAgICAgICAgICAgICBmdW5jdGlvbiBsb2NhbFJlcXVpcmUoZGVwcywgY2FsbGJhY2ssIGVycmJhY2spIHsKICAgICAgICAgICAgICAgICAgICB2YXIgaWQsIG1hcCwgcmVxdWlyZU1vZDsKCiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZW5hYmxlQnVpbGRDYWxsYmFjayAmJiBjYWxsYmFjayAmJiBpc0Z1bmN0aW9uKGNhbGxiYWNrKSkgewogICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjay5fX3JlcXVpcmVKc0J1aWxkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGVwcyA9PT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzRnVuY3Rpb24oY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0ludmFsaWQgY2FsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdyZXF1aXJlYXJncycsICdJbnZhbGlkIHJlcXVpcmUgY2FsbCcpLCBlcnJiYWNrKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiByZXF1aXJlfGV4cG9ydHN8bW9kdWxlIGFyZSByZXF1ZXN0ZWQsIGdldCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy92YWx1ZSBmb3IgdGhlbSBmcm9tIHRoZSBzcGVjaWFsIGhhbmRsZXJzLiBDYXZlYXQ6CiAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcyBvbmx5IHdvcmtzIHdoaWxlIG1vZHVsZSBpcyBiZWluZyBkZWZpbmVkLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVsTWFwICYmIGhhc1Byb3AoaGFuZGxlcnMsIGRlcHMpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlcnNbZGVwc10ocmVnaXN0cnlbcmVsTWFwLmlkXSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vU3luY2hyb25vdXMgYWNjZXNzIHRvIG9uZSBtb2R1bGUuIElmIHJlcXVpcmUuZ2V0IGlzCiAgICAgICAgICAgICAgICAgICAgICAgIC8vYXZhaWxhYmxlIChhcyBpbiB0aGUgTm9kZSBhZGFwdGVyKSwgcHJlZmVyIHRoYXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXEuZ2V0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVxLmdldChjb250ZXh0LCBkZXBzLCByZWxNYXAsIGxvY2FsUmVxdWlyZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vTm9ybWFsaXplIG1vZHVsZSBuYW1lLCBpZiBpdCBjb250YWlucyAuIG9yIC4uCiAgICAgICAgICAgICAgICAgICAgICAgIG1hcCA9IG1ha2VNb2R1bGVNYXAoZGVwcywgcmVsTWFwLCBmYWxzZSwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFwLmlkOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFoYXNQcm9wKGRlZmluZWQsIGlkKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub3Rsb2FkZWQnLCAnTW9kdWxlIG5hbWUgIicgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIgaGFzIG5vdCBiZWVuIGxvYWRlZCB5ZXQgZm9yIGNvbnRleHQ6ICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGV4dE5hbWUgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlbE1hcCA/ICcnIDogJy4gVXNlIHJlcXVpcmUoW10pJykpKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvL0dyYWIgZGVmaW5lcyB3YWl0aW5nIGluIHRoZSBnbG9iYWwgcXVldWUuCiAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAvL01hcmsgYWxsIHRoZSBkZXBlbmRlbmNpZXMgYXMgbmVlZGluZyB0byBiZSBsb2FkZWQuCiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5uZXh0VGljayhmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vU29tZSBkZWZpbmVzIGNvdWxkIGhhdmUgYmVlbiBhZGRlZCBzaW5jZSB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9yZXF1aXJlIGNhbGwsIGNvbGxlY3QgdGhlbS4KICAgICAgICAgICAgICAgICAgICAgICAgaW50YWtlRGVmaW5lcygpOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZCA9IGdldE1vZHVsZShtYWtlTW9kdWxlTWFwKG51bGwsIHJlbE1hcCkpOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9TdG9yZSBpZiBtYXAgY29uZmlnIHNob3VsZCBiZSBhcHBsaWVkIHRvIHRoaXMgcmVxdWlyZQogICAgICAgICAgICAgICAgICAgICAgICAvL2NhbGwgZm9yIGRlcGVuZGVuY2llcy4KICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5za2lwTWFwID0gb3B0aW9ucy5za2lwTWFwOwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZU1vZC5pbml0KGRlcHMsIGNhbGxiYWNrLCBlcnJiYWNrLCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkOiB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgIH0pOwoKICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tMb2FkZWQoKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGxvY2FsUmVxdWlyZTsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBtaXhpbihsb2NhbFJlcXVpcmUsIHsKICAgICAgICAgICAgICAgICAgICBpc0Jyb3dzZXI6IGlzQnJvd3NlciwKCiAgICAgICAgICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAgICAgICAgICogQ29udmVydHMgYSBtb2R1bGUgbmFtZSArIC5leHRlbnNpb24gaW50byBhbiBVUkwgcGF0aC4KICAgICAgICAgICAgICAgICAgICAgKiAqUmVxdWlyZXMqIHRoZSB1c2Ugb2YgYSBtb2R1bGUgbmFtZS4gSXQgZG9lcyBub3Qgc3VwcG9ydCB1c2luZwogICAgICAgICAgICAgICAgICAgICAqIHBsYWluIFVSTHMgbGlrZSBuYW1lVG9VcmwuCiAgICAgICAgICAgICAgICAgICAgICovCiAgICAgICAgICAgICAgICAgICAgdG9Vcmw6IGZ1bmN0aW9uIChtb2R1bGVOYW1lUGx1c0V4dCkgewogICAgICAgICAgICAgICAgICAgICAgICB2YXIgZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSBtb2R1bGVOYW1lUGx1c0V4dC5sYXN0SW5kZXhPZignLicpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VnbWVudCA9IG1vZHVsZU5hbWVQbHVzRXh0LnNwbGl0KCcvJylbMF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc1JlbGF0aXZlID0gc2VnbWVudCA9PT0gJy4nIHx8IHNlZ21lbnQgPT09ICcuLic7CgogICAgICAgICAgICAgICAgICAgICAgICAvL0hhdmUgYSBmaWxlIGV4dGVuc2lvbiBhbGlhcywgYW5kIGl0IGlzIG5vdCB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgLy9kb3RzIGZyb20gYSByZWxhdGl2ZSBwYXRoLgogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW5kZXggIT09IC0xICYmICghaXNSZWxhdGl2ZSB8fCBpbmRleCA+IDEpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHQgPSBtb2R1bGVOYW1lUGx1c0V4dC5zdWJzdHJpbmcoaW5kZXgsIG1vZHVsZU5hbWVQbHVzRXh0Lmxlbmd0aCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lUGx1c0V4dCA9IG1vZHVsZU5hbWVQbHVzRXh0LnN1YnN0cmluZygwLCBpbmRleCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjb250ZXh0Lm5hbWVUb1VybChub3JtYWxpemUobW9kdWxlTmFtZVBsdXNFeHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbE1hcCAmJiByZWxNYXAuaWQsIHRydWUpLCBleHQsICB0cnVlKTsKICAgICAgICAgICAgICAgICAgICB9LAoKICAgICAgICAgICAgICAgICAgICBkZWZpbmVkOiBmdW5jdGlvbiAoaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGhhc1Byb3AoZGVmaW5lZCwgbWFrZU1vZHVsZU1hcChpZCwgcmVsTWFwLCBmYWxzZSwgdHJ1ZSkuaWQpOwogICAgICAgICAgICAgICAgICAgIH0sCgogICAgICAgICAgICAgICAgICAgIHNwZWNpZmllZDogZnVuY3Rpb24gKGlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlkID0gbWFrZU1vZHVsZU1hcChpZCwgcmVsTWFwLCBmYWxzZSwgdHJ1ZSkuaWQ7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBoYXNQcm9wKGRlZmluZWQsIGlkKSB8fCBoYXNQcm9wKHJlZ2lzdHJ5LCBpZCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CgogICAgICAgICAgICAgICAgLy9Pbmx5IGFsbG93IHVuZGVmIG9uIHRvcCBsZXZlbCByZXF1aXJlIGNhbGxzCiAgICAgICAgICAgICAgICBpZiAoIXJlbE1hcCkgewogICAgICAgICAgICAgICAgICAgIGxvY2FsUmVxdWlyZS51bmRlZiA9IGZ1bmN0aW9uIChpZCkgewogICAgICAgICAgICAgICAgICAgICAgICAvL0JpbmQgYW55IHdhaXRpbmcgZGVmaW5lKCkgY2FsbHMgdG8gdGhpcyBjb250ZXh0LAogICAgICAgICAgICAgICAgICAgICAgICAvL2ZpeCBmb3IgIzQwOAogICAgICAgICAgICAgICAgICAgICAgICB0YWtlR2xvYmFsUXVldWUoKTsKCiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtYXAgPSBtYWtlTW9kdWxlTWFwKGlkLCByZWxNYXAsIHRydWUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kID0gZ2V0T3duKHJlZ2lzdHJ5LCBpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBtb2QudW5kZWZlZCA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZVNjcmlwdChpZCk7CgogICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgZGVmaW5lZFtpZF07CiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB1cmxGZXRjaGVkW21hcC51cmxdOwogICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgdW5kZWZFdmVudHNbaWRdOwoKICAgICAgICAgICAgICAgICAgICAgICAgLy9DbGVhbiBxdWV1ZWQgZGVmaW5lcyB0b28uIEdvIGJhY2t3YXJkcwogICAgICAgICAgICAgICAgICAgICAgICAvL2luIGFycmF5IHNvIHRoYXQgdGhlIHNwbGljZXMgZG8gbm90CiAgICAgICAgICAgICAgICAgICAgICAgIC8vbWVzcyB1cCB0aGUgaXRlcmF0aW9uLgogICAgICAgICAgICAgICAgICAgICAgICBlYWNoUmV2ZXJzZShkZWZRdWV1ZSwgZnVuY3Rpb24oYXJncywgaSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IGlkKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmUXVldWUuc3BsaWNlKGksIDEpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIGNvbnRleHQuZGVmUXVldWVNYXBbaWRdOwoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9Ib2xkIG9uIHRvIGxpc3RlbmVycyBpbiBjYXNlIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9tb2R1bGUgd2lsbCBiZSBhdHRlbXB0ZWQgdG8gYmUgcmVsb2FkZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdXNpbmcgYSBkaWZmZXJlbnQgY29uZmlnLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1vZC5ldmVudHMuZGVmaW5lZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVmRXZlbnRzW2lkXSA9IG1vZC5ldmVudHM7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5SZWdpc3RyeShpZCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHJldHVybiBsb2NhbFJlcXVpcmU7CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogQ2FsbGVkIHRvIGVuYWJsZSBhIG1vZHVsZSBpZiBpdCBpcyBzdGlsbCBpbiB0aGUgcmVnaXN0cnkKICAgICAgICAgICAgICogYXdhaXRpbmcgZW5hYmxlbWVudC4gQSBzZWNvbmQgYXJnLCBwYXJlbnQsIHRoZSBwYXJlbnQgbW9kdWxlLAogICAgICAgICAgICAgKiBpcyBwYXNzZWQgaW4gZm9yIGNvbnRleHQsIHdoZW4gdGhpcyBtZXRob2QgaXMgb3ZlcnJpZGRlbiBieQogICAgICAgICAgICAgKiB0aGUgb3B0aW1pemVyLiBOb3Qgc2hvd24gaGVyZSB0byBrZWVwIGNvZGUgY29tcGFjdC4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGVuYWJsZTogZnVuY3Rpb24gKGRlcE1hcCkgewogICAgICAgICAgICAgICAgdmFyIG1vZCA9IGdldE93bihyZWdpc3RyeSwgZGVwTWFwLmlkKTsKICAgICAgICAgICAgICAgIGlmIChtb2QpIHsKICAgICAgICAgICAgICAgICAgICBnZXRNb2R1bGUoZGVwTWFwKS5lbmFibGUoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBJbnRlcm5hbCBtZXRob2QgdXNlZCBieSBlbnZpcm9ubWVudCBhZGFwdGVycyB0byBjb21wbGV0ZSBhIGxvYWQgZXZlbnQuCiAgICAgICAgICAgICAqIEEgbG9hZCBldmVudCBjb3VsZCBiZSBhIHNjcmlwdCBsb2FkIG9yIGp1c3QgYSBsb2FkIHBhc3MgZnJvbSBhIHN5bmNocm9ub3VzCiAgICAgICAgICAgICAqIGxvYWQgY2FsbC4KICAgICAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IG1vZHVsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZSB0byBwb3RlbnRpYWxseSBjb21wbGV0ZS4KICAgICAgICAgICAgICovCiAgICAgICAgICAgIGNvbXBsZXRlTG9hZDogZnVuY3Rpb24gKG1vZHVsZU5hbWUpIHsKICAgICAgICAgICAgICAgIHZhciBmb3VuZCwgYXJncywgbW9kLAogICAgICAgICAgICAgICAgICAgIHNoaW0gPSBnZXRPd24oY29uZmlnLnNoaW0sIG1vZHVsZU5hbWUpIHx8IHt9LAogICAgICAgICAgICAgICAgICAgIHNoRXhwb3J0cyA9IHNoaW0uZXhwb3J0czsKCiAgICAgICAgICAgICAgICB0YWtlR2xvYmFsUXVldWUoKTsKCiAgICAgICAgICAgICAgICB3aGlsZSAoZGVmUXVldWUubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgICAgYXJncyA9IGRlZlF1ZXVlLnNoaWZ0KCk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGFyZ3NbMF0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICAgICAgYXJnc1swXSA9IG1vZHVsZU5hbWU7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vSWYgYWxyZWFkeSBmb3VuZCBhbiBhbm9ueW1vdXMgbW9kdWxlIGFuZCBib3VuZCBpdAogICAgICAgICAgICAgICAgICAgICAgICAvL3RvIHRoaXMgbmFtZSwgdGhlbiB0aGlzIGlzIHNvbWUgb3RoZXIgYW5vbiBtb2R1bGUKICAgICAgICAgICAgICAgICAgICAgICAgLy93YWl0aW5nIGZvciBpdHMgY29tcGxldGVMb2FkIHRvIGZpcmUuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChmb3VuZCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJnc1swXSA9PT0gbW9kdWxlTmFtZSkgewogICAgICAgICAgICAgICAgICAgICAgICAvL0ZvdW5kIG1hdGNoaW5nIGRlZmluZSBjYWxsIGZvciB0aGlzIHNjcmlwdCEKICAgICAgICAgICAgICAgICAgICAgICAgZm91bmQgPSB0cnVlOwogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgY2FsbEdldE1vZHVsZShhcmdzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnRleHQuZGVmUXVldWVNYXAgPSB7fTsKCiAgICAgICAgICAgICAgICAvL0RvIHRoaXMgYWZ0ZXIgdGhlIGN5Y2xlIG9mIGNhbGxHZXRNb2R1bGUgaW4gY2FzZSB0aGUgcmVzdWx0CiAgICAgICAgICAgICAgICAvL29mIHRob3NlIGNhbGxzL2luaXQgY2FsbHMgY2hhbmdlcyB0aGUgcmVnaXN0cnkuCiAgICAgICAgICAgICAgICBtb2QgPSBnZXRPd24ocmVnaXN0cnksIG1vZHVsZU5hbWUpOwoKICAgICAgICAgICAgICAgIGlmICghZm91bmQgJiYgIWhhc1Byb3AoZGVmaW5lZCwgbW9kdWxlTmFtZSkgJiYgbW9kICYmICFtb2QuaW5pdGVkKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbmZpZy5lbmZvcmNlRGVmaW5lICYmICghc2hFeHBvcnRzIHx8ICFnZXRHbG9iYWwoc2hFeHBvcnRzKSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc1BhdGhGYWxsYmFjayhtb2R1bGVOYW1lKSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uRXJyb3IobWFrZUVycm9yKCdub2RlZmluZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdObyBkZWZpbmUgY2FsbCBmb3IgJyArIG1vZHVsZU5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFttb2R1bGVOYW1lXSkpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgLy9BIHNjcmlwdCB0aGF0IGRvZXMgbm90IGNhbGwgZGVmaW5lKCksIHNvIGp1c3Qgc2ltdWxhdGUKICAgICAgICAgICAgICAgICAgICAgICAgLy90aGUgY2FsbCBmb3IgaXQuCiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxHZXRNb2R1bGUoW21vZHVsZU5hbWUsIChzaGltLmRlcHMgfHwgW10pLCBzaGltLmV4cG9ydHNGbl0pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICBjaGVja0xvYWRlZCgpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIENvbnZlcnRzIGEgbW9kdWxlIG5hbWUgdG8gYSBmaWxlIHBhdGguIFN1cHBvcnRzIGNhc2VzIHdoZXJlCiAgICAgICAgICAgICAqIG1vZHVsZU5hbWUgbWF5IGFjdHVhbGx5IGJlIGp1c3QgYW4gVVJMLgogICAgICAgICAgICAgKiBOb3RlIHRoYXQgaXQgKipkb2VzIG5vdCoqIGNhbGwgbm9ybWFsaXplIG9uIHRoZSBtb2R1bGVOYW1lLAogICAgICAgICAgICAgKiBpdCBpcyBhc3N1bWVkIHRvIGhhdmUgYWxyZWFkeSBiZWVuIG5vcm1hbGl6ZWQuIFRoaXMgaXMgYW4KICAgICAgICAgICAgICogaW50ZXJuYWwgQVBJLCBub3QgYSBwdWJsaWMgb25lLiBVc2UgdG9VcmwgZm9yIHRoZSBwdWJsaWMgQVBJLgogICAgICAgICAgICAgKi8KICAgICAgICAgICAgbmFtZVRvVXJsOiBmdW5jdGlvbiAobW9kdWxlTmFtZSwgZXh0LCBza2lwRXh0KSB7CiAgICAgICAgICAgICAgICB2YXIgcGF0aHMsIHN5bXMsIGksIHBhcmVudE1vZHVsZSwgdXJsLAogICAgICAgICAgICAgICAgICAgIHBhcmVudFBhdGgsIGJ1bmRsZUlkLAogICAgICAgICAgICAgICAgICAgIHBrZ01haW4gPSBnZXRPd24oY29uZmlnLnBrZ3MsIG1vZHVsZU5hbWUpOwoKICAgICAgICAgICAgICAgIGlmIChwa2dNYWluKSB7CiAgICAgICAgICAgICAgICAgICAgbW9kdWxlTmFtZSA9IHBrZ01haW47CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgYnVuZGxlSWQgPSBnZXRPd24oYnVuZGxlc01hcCwgbW9kdWxlTmFtZSk7CgogICAgICAgICAgICAgICAgaWYgKGJ1bmRsZUlkKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQubmFtZVRvVXJsKGJ1bmRsZUlkLCBleHQsIHNraXBFeHQpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vSWYgYSBjb2xvbiBpcyBpbiB0aGUgVVJMLCBpdCBpbmRpY2F0ZXMgYSBwcm90b2NvbCBpcyB1c2VkIGFuZCBpdCBpcyBqdXN0CiAgICAgICAgICAgICAgICAvL2FuIFVSTCB0byBhIGZpbGUsIG9yIGlmIGl0IHN0YXJ0cyB3aXRoIGEgc2xhc2gsIGNvbnRhaW5zIGEgcXVlcnkgYXJnIChpLmUuID8pCiAgICAgICAgICAgICAgICAvL29yIGVuZHMgd2l0aCAuanMsIHRoZW4gYXNzdW1lIHRoZSB1c2VyIG1lYW50IHRvIHVzZSBhbiB1cmwgYW5kIG5vdCBhIG1vZHVsZSBpZC4KICAgICAgICAgICAgICAgIC8vVGhlIHNsYXNoIGlzIGltcG9ydGFudCBmb3IgcHJvdG9jb2wtbGVzcyBVUkxzIGFzIHdlbGwgYXMgZnVsbCBwYXRocy4KICAgICAgICAgICAgICAgIGlmIChyZXEuanNFeHRSZWdFeHAudGVzdChtb2R1bGVOYW1lKSkgewogICAgICAgICAgICAgICAgICAgIC8vSnVzdCBhIHBsYWluIHBhdGgsIG5vdCBtb2R1bGUgbmFtZSBsb29rdXAsIHNvIGp1c3QgcmV0dXJuIGl0LgogICAgICAgICAgICAgICAgICAgIC8vQWRkIGV4dGVuc2lvbiBpZiBpdCBpcyBpbmNsdWRlZC4gVGhpcyBpcyBhIGJpdCB3b25reSwgb25seSBub24tLmpzIHRoaW5ncyBwYXNzCiAgICAgICAgICAgICAgICAgICAgLy9hbiBleHRlbnNpb24sIHRoaXMgbWV0aG9kIHByb2JhYmx5IG5lZWRzIHRvIGJlIHJld29ya2VkLgogICAgICAgICAgICAgICAgICAgIHVybCA9IG1vZHVsZU5hbWUgKyAoZXh0IHx8ICcnKTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgLy9BIG1vZHVsZSB0aGF0IG5lZWRzIHRvIGJlIGNvbnZlcnRlZCB0byBhIHBhdGguCiAgICAgICAgICAgICAgICAgICAgcGF0aHMgPSBjb25maWcucGF0aHM7CgogICAgICAgICAgICAgICAgICAgIHN5bXMgPSBtb2R1bGVOYW1lLnNwbGl0KCcvJyk7CiAgICAgICAgICAgICAgICAgICAgLy9Gb3IgZWFjaCBtb2R1bGUgbmFtZSBzZWdtZW50LCBzZWUgaWYgdGhlcmUgaXMgYSBwYXRoCiAgICAgICAgICAgICAgICAgICAgLy9yZWdpc3RlcmVkIGZvciBpdC4gU3RhcnQgd2l0aCBtb3N0IHNwZWNpZmljIG5hbWUKICAgICAgICAgICAgICAgICAgICAvL2FuZCB3b3JrIHVwIGZyb20gaXQuCiAgICAgICAgICAgICAgICAgICAgZm9yIChpID0gc3ltcy5sZW5ndGg7IGkgPiAwOyBpIC09IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50TW9kdWxlID0gc3ltcy5zbGljZSgwLCBpKS5qb2luKCcvJyk7CgogICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRQYXRoID0gZ2V0T3duKHBhdGhzLCBwYXJlbnRNb2R1bGUpOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAocGFyZW50UGF0aCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9JZiBhbiBhcnJheSwgaXQgbWVhbnMgdGhlcmUgYXJlIGEgZmV3IGNob2ljZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL0Nob29zZSB0aGUgb25lIHRoYXQgaXMgZGVzaXJlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzQXJyYXkocGFyZW50UGF0aCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRQYXRoID0gcGFyZW50UGF0aFswXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXMuc3BsaWNlKDAsIGksIHBhcmVudFBhdGgpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgIC8vSm9pbiB0aGUgcGF0aCBwYXJ0cyB0b2dldGhlciwgdGhlbiBmaWd1cmUgb3V0IGlmIGJhc2VVcmwgaXMgbmVlZGVkLgogICAgICAgICAgICAgICAgICAgIHVybCA9IHN5bXMuam9pbignLycpOwogICAgICAgICAgICAgICAgICAgIHVybCArPSAoZXh0IHx8ICgvXmRhdGFcOnxcPy8udGVzdCh1cmwpIHx8IHNraXBFeHQgPyAnJyA6ICcuanMnKSk7CiAgICAgICAgICAgICAgICAgICAgdXJsID0gKHVybC5jaGFyQXQoMCkgPT09ICcvJyB8fCB1cmwubWF0Y2goL15bXHdcK1wuXC1dKzovKSA/ICcnIDogY29uZmlnLmJhc2VVcmwpICsgdXJsOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHJldHVybiBjb25maWcudXJsQXJncyA/IHVybCArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKHVybC5pbmRleE9mKCc/JykgPT09IC0xID8gJz8nIDogJyYnKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnLnVybEFyZ3MpIDogdXJsOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLy9EZWxlZ2F0ZXMgdG8gcmVxLmxvYWQuIEJyb2tlbiBvdXQgYXMgYSBzZXBhcmF0ZSBmdW5jdGlvbiB0bwogICAgICAgICAgICAvL2FsbG93IG92ZXJyaWRpbmcgaW4gdGhlIG9wdGltaXplci4KICAgICAgICAgICAgbG9hZDogZnVuY3Rpb24gKGlkLCB1cmwpIHsKICAgICAgICAgICAgICAgIHJlcS5sb2FkKGNvbnRleHQsIGlkLCB1cmwpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIEV4ZWN1dGVzIGEgbW9kdWxlIGNhbGxiYWNrIGZ1bmN0aW9uLiBCcm9rZW4gb3V0IGFzIGEgc2VwYXJhdGUgZnVuY3Rpb24KICAgICAgICAgICAgICogc29sZWx5IHRvIGFsbG93IHRoZSBidWlsZCBzeXN0ZW0gdG8gc2VxdWVuY2UgdGhlIGZpbGVzIGluIHRoZSBidWlsdAogICAgICAgICAgICAgKiBsYXllciBpbiB0aGUgcmlnaHQgc2VxdWVuY2UuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBleGVjQ2I6IGZ1bmN0aW9uIChuYW1lLCBjYWxsYmFjaywgYXJncywgZXhwb3J0cykgewogICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrLmFwcGx5KGV4cG9ydHMsIGFyZ3MpOwogICAgICAgICAgICB9LAoKICAgICAgICAgICAgLyoqCiAgICAgICAgICAgICAqIGNhbGxiYWNrIGZvciBzY3JpcHQgbG9hZHMsIHVzZWQgdG8gY2hlY2sgc3RhdHVzIG9mIGxvYWRpbmcuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2dCB0aGUgZXZlbnQgZnJvbSB0aGUgYnJvd3NlciBmb3IgdGhlIHNjcmlwdAogICAgICAgICAgICAgKiB0aGF0IHdhcyBsb2FkZWQuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBvblNjcmlwdExvYWQ6IGZ1bmN0aW9uIChldnQpIHsKICAgICAgICAgICAgICAgIC8vVXNpbmcgY3VycmVudFRhcmdldCBpbnN0ZWFkIG9mIHRhcmdldCBmb3IgRmlyZWZveCAyLjAncyBzYWtlLiBOb3QKICAgICAgICAgICAgICAgIC8vYWxsIG9sZCBicm93c2VycyB3aWxsIGJlIHN1cHBvcnRlZCwgYnV0IHRoaXMgb25lIHdhcyBlYXN5IGVub3VnaAogICAgICAgICAgICAgICAgLy90byBzdXBwb3J0IGFuZCBzdGlsbCBtYWtlcyBzZW5zZS4KICAgICAgICAgICAgICAgIGlmIChldnQudHlwZSA9PT0gJ2xvYWQnIHx8CiAgICAgICAgICAgICAgICAgICAgICAgIChyZWFkeVJlZ0V4cC50ZXN0KChldnQuY3VycmVudFRhcmdldCB8fCBldnQuc3JjRWxlbWVudCkucmVhZHlTdGF0ZSkpKSB7CiAgICAgICAgICAgICAgICAgICAgLy9SZXNldCBpbnRlcmFjdGl2ZSBzY3JpcHQgc28gYSBzY3JpcHQgbm9kZSBpcyBub3QgaGVsZCBvbnRvIGZvcgogICAgICAgICAgICAgICAgICAgIC8vdG8gbG9uZy4KICAgICAgICAgICAgICAgICAgICBpbnRlcmFjdGl2ZVNjcmlwdCA9IG51bGw7CgogICAgICAgICAgICAgICAgICAgIC8vUHVsbCBvdXQgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZSBhbmQgdGhlIGNvbnRleHQuCiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBnZXRTY3JpcHREYXRhKGV2dCk7CiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5jb21wbGV0ZUxvYWQoZGF0YS5pZCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCgogICAgICAgICAgICAvKioKICAgICAgICAgICAgICogQ2FsbGJhY2sgZm9yIHNjcmlwdCBlcnJvcnMuCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBvblNjcmlwdEVycm9yOiBmdW5jdGlvbiAoZXZ0KSB7CiAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IGdldFNjcmlwdERhdGEoZXZ0KTsKICAgICAgICAgICAgICAgIGlmICghaGFzUGF0aEZhbGxiYWNrKGRhdGEuaWQpKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmVudHMgPSBbXTsKICAgICAgICAgICAgICAgICAgICBlYWNoUHJvcChyZWdpc3RyeSwgZnVuY3Rpb24odmFsdWUsIGtleSkgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoa2V5LmluZGV4T2YoJ19AcicpICE9PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoKHZhbHVlLmRlcE1hcHMsIGZ1bmN0aW9uKGRlcE1hcCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkZXBNYXAuaWQgPT09IGRhdGEuaWQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50cy5wdXNoKGtleSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gb25FcnJvcihtYWtlRXJyb3IoJ3NjcmlwdGVycm9yJywgJ1NjcmlwdCBlcnJvciBmb3IgIicgKyBkYXRhLmlkICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhcmVudHMubGVuZ3RoID8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIsIG5lZWRlZCBieTogJyArIHBhcmVudHMuam9pbignLCAnKSA6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICciJyksIGV2dCwgW2RhdGEuaWRdKSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICBjb250ZXh0LnJlcXVpcmUgPSBjb250ZXh0Lm1ha2VSZXF1aXJlKCk7CiAgICAgICAgcmV0dXJuIGNvbnRleHQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBNYWluIGVudHJ5IHBvaW50LgogICAgICoKICAgICAqIElmIHRoZSBvbmx5IGFyZ3VtZW50IHRvIHJlcXVpcmUgaXMgYSBzdHJpbmcsIHRoZW4gdGhlIG1vZHVsZSB0aGF0CiAgICAgKiBpcyByZXByZXNlbnRlZCBieSB0aGF0IHN0cmluZyBpcyBmZXRjaGVkIGZvciB0aGUgYXBwcm9wcmlhdGUgY29udGV4dC4KICAgICAqCiAgICAgKiBJZiB0aGUgZmlyc3QgYXJndW1lbnQgaXMgYW4gYXJyYXksIHRoZW4gaXQgd2lsbCBiZSB0cmVhdGVkIGFzIGFuIGFycmF5CiAgICAgKiBvZiBkZXBlbmRlbmN5IHN0cmluZyBuYW1lcyB0byBmZXRjaC4gQW4gb3B0aW9uYWwgZnVuY3Rpb24gY2FsbGJhY2sgY2FuCiAgICAgKiBiZSBzcGVjaWZpZWQgdG8gZXhlY3V0ZSB3aGVuIGFsbCBvZiB0aG9zZSBkZXBlbmRlbmNpZXMgYXJlIGF2YWlsYWJsZS4KICAgICAqCiAgICAgKiBNYWtlIGEgbG9jYWwgcmVxIHZhcmlhYmxlIHRvIGhlbHAgQ2FqYSBjb21wbGlhbmNlIChpdCBhc3N1bWVzIHRoaW5ncwogICAgICogb24gYSByZXF1aXJlIHRoYXQgYXJlIG5vdCBzdGFuZGFyZGl6ZWQpLCBhbmQgdG8gZ2l2ZSBhIHNob3J0CiAgICAgKiBuYW1lIGZvciBtaW5pZmljYXRpb24vbG9jYWwgc2NvcGUgdXNlLgogICAgICovCiAgICByZXEgPSByZXF1aXJlanMgPSBmdW5jdGlvbiAoZGVwcywgY2FsbGJhY2ssIGVycmJhY2ssIG9wdGlvbmFsKSB7CgogICAgICAgIC8vRmluZCB0aGUgcmlnaHQgY29udGV4dCwgdXNlIGRlZmF1bHQKICAgICAgICB2YXIgY29udGV4dCwgY29uZmlnLAogICAgICAgICAgICBjb250ZXh0TmFtZSA9IGRlZkNvbnRleHROYW1lOwoKICAgICAgICAvLyBEZXRlcm1pbmUgaWYgaGF2ZSBjb25maWcgb2JqZWN0IGluIHRoZSBjYWxsLgogICAgICAgIGlmICghaXNBcnJheShkZXBzKSAmJiB0eXBlb2YgZGVwcyAhPT0gJ3N0cmluZycpIHsKICAgICAgICAgICAgLy8gZGVwcyBpcyBhIGNvbmZpZyBvYmplY3QKICAgICAgICAgICAgY29uZmlnID0gZGVwczsKICAgICAgICAgICAgaWYgKGlzQXJyYXkoY2FsbGJhY2spKSB7CiAgICAgICAgICAgICAgICAvLyBBZGp1c3QgYXJncyBpZiB0aGVyZSBhcmUgZGVwZW5kZW5jaWVzCiAgICAgICAgICAgICAgICBkZXBzID0gY2FsbGJhY2s7CiAgICAgICAgICAgICAgICBjYWxsYmFjayA9IGVycmJhY2s7CiAgICAgICAgICAgICAgICBlcnJiYWNrID0gb3B0aW9uYWw7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBkZXBzID0gW107CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmIChjb25maWcgJiYgY29uZmlnLmNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dE5hbWUgPSBjb25maWcuY29udGV4dDsKICAgICAgICB9CgogICAgICAgIGNvbnRleHQgPSBnZXRPd24oY29udGV4dHMsIGNvbnRleHROYW1lKTsKICAgICAgICBpZiAoIWNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dCA9IGNvbnRleHRzW2NvbnRleHROYW1lXSA9IHJlcS5zLm5ld0NvbnRleHQoY29udGV4dE5hbWUpOwogICAgICAgIH0KCiAgICAgICAgaWYgKGNvbmZpZykgewogICAgICAgICAgICBjb250ZXh0LmNvbmZpZ3VyZShjb25maWcpOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIGNvbnRleHQucmVxdWlyZShkZXBzLCBjYWxsYmFjaywgZXJyYmFjayk7CiAgICB9OwoKICAgIC8qKgogICAgICogU3VwcG9ydCByZXF1aXJlLmNvbmZpZygpIHRvIG1ha2UgaXQgZWFzaWVyIHRvIGNvb3BlcmF0ZSB3aXRoIG90aGVyCiAgICAgKiBBTUQgbG9hZGVycyBvbiBnbG9iYWxseSBhZ3JlZWQgbmFtZXMuCiAgICAgKi8KICAgIHJlcS5jb25maWcgPSBmdW5jdGlvbiAoY29uZmlnKSB7CiAgICAgICAgcmV0dXJuIHJlcShjb25maWcpOwogICAgfTsKCiAgICAvKioKICAgICAqIEV4ZWN1dGUgc29tZXRoaW5nIGFmdGVyIHRoZSBjdXJyZW50IHRpY2sKICAgICAqIG9mIHRoZSBldmVudCBsb29wLiBPdmVycmlkZSBmb3Igb3RoZXIgZW52cwogICAgICogdGhhdCBoYXZlIGEgYmV0dGVyIHNvbHV0aW9uIHRoYW4gc2V0VGltZW91dC4KICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBmbiBmdW5jdGlvbiB0byBleGVjdXRlIGxhdGVyLgogICAgICovCiAgICByZXEubmV4dFRpY2sgPSB0eXBlb2Ygc2V0VGltZW91dCAhPT0gJ3VuZGVmaW5lZCcgPyBmdW5jdGlvbiAoZm4pIHsKICAgICAgICBzZXRUaW1lb3V0KGZuLCA0KTsKICAgIH0gOiBmdW5jdGlvbiAoZm4pIHsgZm4oKTsgfTsKCiAgICAvKioKICAgICAqIEV4cG9ydCByZXF1aXJlIGFzIGEgZ2xvYmFsLCBidXQgb25seSBpZiBpdCBkb2VzIG5vdCBhbHJlYWR5IGV4aXN0LgogICAgICovCiAgICBpZiAoIXJlcXVpcmUpIHsKICAgICAgICByZXF1aXJlID0gcmVxOwogICAgfQoKICAgIHJlcS52ZXJzaW9uID0gdmVyc2lvbjsKCiAgICAvL1VzZWQgdG8gZmlsdGVyIG91dCBkZXBlbmRlbmNpZXMgdGhhdCBhcmUgYWxyZWFkeSBwYXRocy4KICAgIHJlcS5qc0V4dFJlZ0V4cCA9IC9eXC98OnxcP3xcLmpzJC87CiAgICByZXEuaXNCcm93c2VyID0gaXNCcm93c2VyOwogICAgcyA9IHJlcS5zID0gewogICAgICAgIGNvbnRleHRzOiBjb250ZXh0cywKICAgICAgICBuZXdDb250ZXh0OiBuZXdDb250ZXh0CiAgICB9OwoKICAgIC8vQ3JlYXRlIGRlZmF1bHQgY29udGV4dC4KICAgIHJlcSh7fSk7CgogICAgLy9FeHBvcnRzIHNvbWUgY29udGV4dC1zZW5zaXRpdmUgbWV0aG9kcyBvbiBnbG9iYWwgcmVxdWlyZS4KICAgIGVhY2goWwogICAgICAgICd0b1VybCcsCiAgICAgICAgJ3VuZGVmJywKICAgICAgICAnZGVmaW5lZCcsCiAgICAgICAgJ3NwZWNpZmllZCcKICAgIF0sIGZ1bmN0aW9uIChwcm9wKSB7CiAgICAgICAgLy9SZWZlcmVuY2UgZnJvbSBjb250ZXh0cyBpbnN0ZWFkIG9mIGVhcmx5IGJpbmRpbmcgdG8gZGVmYXVsdCBjb250ZXh0LAogICAgICAgIC8vc28gdGhhdCBkdXJpbmcgYnVpbGRzLCB0aGUgbGF0ZXN0IGluc3RhbmNlIG9mIHRoZSBkZWZhdWx0IGNvbnRleHQKICAgICAgICAvL3dpdGggaXRzIGNvbmZpZyBnZXRzIHVzZWQuCiAgICAgICAgcmVxW3Byb3BdID0gZnVuY3Rpb24gKCkgewogICAgICAgICAgICB2YXIgY3R4ID0gY29udGV4dHNbZGVmQ29udGV4dE5hbWVdOwogICAgICAgICAgICByZXR1cm4gY3R4LnJlcXVpcmVbcHJvcF0uYXBwbHkoY3R4LCBhcmd1bWVudHMpOwogICAgICAgIH07CiAgICB9KTsKCiAgICBpZiAoaXNCcm93c2VyKSB7CiAgICAgICAgaGVhZCA9IHMuaGVhZCA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdoZWFkJylbMF07CiAgICAgICAgLy9JZiBCQVNFIHRhZyBpcyBpbiBwbGF5LCB1c2luZyBhcHBlbmRDaGlsZCBpcyBhIHByb2JsZW0gZm9yIElFNi4KICAgICAgICAvL1doZW4gdGhhdCBicm93c2VyIGRpZXMsIHRoaXMgY2FuIGJlIHJlbW92ZWQuIERldGFpbHMgaW4gdGhpcyBqUXVlcnkgYnVnOgogICAgICAgIC8vaHR0cDovL2Rldi5qcXVlcnkuY29tL3RpY2tldC8yNzA5CiAgICAgICAgYmFzZUVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnYmFzZScpWzBdOwogICAgICAgIGlmIChiYXNlRWxlbWVudCkgewogICAgICAgICAgICBoZWFkID0gcy5oZWFkID0gYmFzZUVsZW1lbnQucGFyZW50Tm9kZTsKICAgICAgICB9CiAgICB9CgogICAgLyoqCiAgICAgKiBBbnkgZXJyb3JzIHRoYXQgcmVxdWlyZSBleHBsaWNpdGx5IGdlbmVyYXRlcyB3aWxsIGJlIHBhc3NlZCB0byB0aGlzCiAgICAgKiBmdW5jdGlvbi4gSW50ZXJjZXB0L292ZXJyaWRlIGl0IGlmIHlvdSB3YW50IGN1c3RvbSBlcnJvciBoYW5kbGluZy4KICAgICAqIEBwYXJhbSB7RXJyb3J9IGVyciB0aGUgZXJyb3Igb2JqZWN0LgogICAgICovCiAgICByZXEub25FcnJvciA9IGRlZmF1bHRPbkVycm9yOwoKICAgIC8qKgogICAgICogQ3JlYXRlcyB0aGUgbm9kZSBmb3IgdGhlIGxvYWQgY29tbWFuZC4gT25seSB1c2VkIGluIGJyb3dzZXIgZW52cy4KICAgICAqLwogICAgcmVxLmNyZWF0ZU5vZGUgPSBmdW5jdGlvbiAoY29uZmlnLCBtb2R1bGVOYW1lLCB1cmwpIHsKICAgICAgICB2YXIgbm9kZSA9IGNvbmZpZy54aHRtbCA/CiAgICAgICAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnLCAnaHRtbDpzY3JpcHQnKSA6CiAgICAgICAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsKICAgICAgICBub2RlLnR5cGUgPSBjb25maWcuc2NyaXB0VHlwZSB8fCAndGV4dC9qYXZhc2NyaXB0JzsKICAgICAgICBub2RlLmNoYXJzZXQgPSAndXRmLTgnOwogICAgICAgIG5vZGUuYXN5bmMgPSB0cnVlOwogICAgICAgIHJldHVybiBub2RlOwogICAgfTsKCiAgICAvKioKICAgICAqIERvZXMgdGhlIHJlcXVlc3QgdG8gbG9hZCBhIG1vZHVsZSBmb3IgdGhlIGJyb3dzZXIgY2FzZS4KICAgICAqIE1ha2UgdGhpcyBhIHNlcGFyYXRlIGZ1bmN0aW9uIHRvIGFsbG93IG90aGVyIGVudmlyb25tZW50cwogICAgICogdG8gb3ZlcnJpZGUgaXQuCiAgICAgKgogICAgICogQHBhcmFtIHtPYmplY3R9IGNvbnRleHQgdGhlIHJlcXVpcmUgY29udGV4dCB0byBmaW5kIHN0YXRlLgogICAgICogQHBhcmFtIHtTdHJpbmd9IG1vZHVsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIG1vZHVsZS4KICAgICAqIEBwYXJhbSB7T2JqZWN0fSB1cmwgdGhlIFVSTCB0byB0aGUgbW9kdWxlLgogICAgICovCiAgICByZXEubG9hZCA9IGZ1bmN0aW9uIChjb250ZXh0LCBtb2R1bGVOYW1lLCB1cmwpIHsKICAgICAgICB2YXIgY29uZmlnID0gKGNvbnRleHQgJiYgY29udGV4dC5jb25maWcpIHx8IHt9LAogICAgICAgICAgICBub2RlOwogICAgICAgIGlmIChpc0Jyb3dzZXIpIHsKICAgICAgICAgICAgLy9JbiB0aGUgYnJvd3NlciBzbyB1c2UgYSBzY3JpcHQgdGFnCiAgICAgICAgICAgIG5vZGUgPSByZXEuY3JlYXRlTm9kZShjb25maWcsIG1vZHVsZU5hbWUsIHVybCk7CiAgICAgICAgICAgIGlmIChjb25maWcub25Ob2RlQ3JlYXRlZCkgewogICAgICAgICAgICAgICAgY29uZmlnLm9uTm9kZUNyZWF0ZWQobm9kZSwgY29uZmlnLCBtb2R1bGVOYW1lLCB1cmwpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlY29udGV4dCcsIGNvbnRleHQuY29udGV4dE5hbWUpOwogICAgICAgICAgICBub2RlLnNldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlbW9kdWxlJywgbW9kdWxlTmFtZSk7CgogICAgICAgICAgICAvL1NldCB1cCBsb2FkIGxpc3RlbmVyLiBUZXN0IGF0dGFjaEV2ZW50IGZpcnN0IGJlY2F1c2UgSUU5IGhhcwogICAgICAgICAgICAvL2Egc3VidGxlIGlzc3VlIGluIGl0cyBhZGRFdmVudExpc3RlbmVyIGFuZCBzY3JpcHQgb25sb2FkIGZpcmluZ3MKICAgICAgICAgICAgLy90aGF0IGRvIG5vdCBtYXRjaCB0aGUgYmVoYXZpb3Igb2YgYWxsIG90aGVyIGJyb3dzZXJzIHdpdGgKICAgICAgICAgICAgLy9hZGRFdmVudExpc3RlbmVyIHN1cHBvcnQsIHdoaWNoIGZpcmUgdGhlIG9ubG9hZCBldmVudCBmb3IgYQogICAgICAgICAgICAvL3NjcmlwdCByaWdodCBhZnRlciB0aGUgc2NyaXB0IGV4ZWN1dGlvbi4gU2VlOgogICAgICAgICAgICAvL2h0dHBzOi8vY29ubmVjdC5taWNyb3NvZnQuY29tL0lFL2ZlZWRiYWNrL2RldGFpbHMvNjQ4MDU3L3NjcmlwdC1vbmxvYWQtZXZlbnQtaXMtbm90LWZpcmVkLWltbWVkaWF0ZWx5LWFmdGVyLXNjcmlwdC1leGVjdXRpb24KICAgICAgICAgICAgLy9VTkZPUlRVTkFURUxZIE9wZXJhIGltcGxlbWVudHMgYXR0YWNoRXZlbnQgYnV0IGRvZXMgbm90IGZvbGxvdyB0aGUgc2NyaXB0CiAgICAgICAgICAgIC8vc2NyaXB0IGV4ZWN1dGlvbiBtb2RlLgogICAgICAgICAgICBpZiAobm9kZS5hdHRhY2hFdmVudCAmJgogICAgICAgICAgICAgICAgICAgIC8vQ2hlY2sgaWYgbm9kZS5hdHRhY2hFdmVudCBpcyBhcnRpZmljaWFsbHkgYWRkZWQgYnkgY3VzdG9tIHNjcmlwdCBvcgogICAgICAgICAgICAgICAgICAgIC8vbmF0aXZlbHkgc3VwcG9ydGVkIGJ5IGJyb3dzZXIKICAgICAgICAgICAgICAgICAgICAvL3JlYWQgaHR0cHM6Ly9naXRodWIuY29tL2pyYnVya2UvcmVxdWlyZWpzL2lzc3Vlcy8xODcKICAgICAgICAgICAgICAgICAgICAvL2lmIHdlIGNhbiBOT1QgZmluZCBbbmF0aXZlIGNvZGVdIHRoZW4gaXQgbXVzdCBOT1QgbmF0aXZlbHkgc3VwcG9ydGVkLgogICAgICAgICAgICAgICAgICAgIC8vaW4gSUU4LCBub2RlLmF0dGFjaEV2ZW50IGRvZXMgbm90IGhhdmUgdG9TdHJpbmcoKQogICAgICAgICAgICAgICAgICAgIC8vTm90ZSB0aGUgdGVzdCBmb3IgIltuYXRpdmUgY29kZSIgd2l0aCBubyBjbG9zaW5nIGJyYWNlLCBzZWU6CiAgICAgICAgICAgICAgICAgICAgLy9odHRwczovL2dpdGh1Yi5jb20vanJidXJrZS9yZXF1aXJlanMvaXNzdWVzLzI3MwogICAgICAgICAgICAgICAgICAgICEobm9kZS5hdHRhY2hFdmVudC50b1N0cmluZyAmJiBub2RlLmF0dGFjaEV2ZW50LnRvU3RyaW5nKCkuaW5kZXhPZignW25hdGl2ZSBjb2RlJykgPCAwKSAmJgogICAgICAgICAgICAgICAgICAgICFpc09wZXJhKSB7CiAgICAgICAgICAgICAgICAvL1Byb2JhYmx5IElFLiBJRSAoYXQgbGVhc3QgNi04KSBkbyBub3QgZmlyZQogICAgICAgICAgICAgICAgLy9zY3JpcHQgb25sb2FkIHJpZ2h0IGFmdGVyIGV4ZWN1dGluZyB0aGUgc2NyaXB0LCBzbwogICAgICAgICAgICAgICAgLy93ZSBjYW5ub3QgdGllIHRoZSBhbm9ueW1vdXMgZGVmaW5lIGNhbGwgdG8gYSBuYW1lLgogICAgICAgICAgICAgICAgLy9Ib3dldmVyLCBJRSByZXBvcnRzIHRoZSBzY3JpcHQgYXMgYmVpbmcgaW4gJ2ludGVyYWN0aXZlJwogICAgICAgICAgICAgICAgLy9yZWFkeVN0YXRlIGF0IHRoZSB0aW1lIG9mIHRoZSBkZWZpbmUgY2FsbC4KICAgICAgICAgICAgICAgIHVzZUludGVyYWN0aXZlID0gdHJ1ZTsKCiAgICAgICAgICAgICAgICBub2RlLmF0dGFjaEV2ZW50KCdvbnJlYWR5c3RhdGVjaGFuZ2UnLCBjb250ZXh0Lm9uU2NyaXB0TG9hZCk7CiAgICAgICAgICAgICAgICAvL0l0IHdvdWxkIGJlIGdyZWF0IHRvIGFkZCBhbiBlcnJvciBoYW5kbGVyIGhlcmUgdG8gY2F0Y2gKICAgICAgICAgICAgICAgIC8vNDA0cyBpbiBJRTkrLiBIb3dldmVyLCBvbnJlYWR5c3RhdGVjaGFuZ2Ugd2lsbCBmaXJlIGJlZm9yZQogICAgICAgICAgICAgICAgLy90aGUgZXJyb3IgaGFuZGxlciwgc28gdGhhdCBkb2VzIG5vdCBoZWxwLiBJZiBhZGRFdmVudExpc3RlbmVyCiAgICAgICAgICAgICAgICAvL2lzIHVzZWQsIHRoZW4gSUUgd2lsbCBmaXJlIGVycm9yIGJlZm9yZSBsb2FkLCBidXQgd2UgY2Fubm90CiAgICAgICAgICAgICAgICAvL3VzZSB0aGF0IHBhdGh3YXkgZ2l2ZW4gdGhlIGNvbm5lY3QubWljcm9zb2Z0LmNvbSBpc3N1ZQogICAgICAgICAgICAgICAgLy9tZW50aW9uZWQgYWJvdmUgYWJvdXQgbm90IGRvaW5nIHRoZSAnc2NyaXB0IGV4ZWN1dGUsCiAgICAgICAgICAgICAgICAvL3RoZW4gZmlyZSB0aGUgc2NyaXB0IGxvYWQgZXZlbnQgbGlzdGVuZXIgYmVmb3JlIGV4ZWN1dGUKICAgICAgICAgICAgICAgIC8vbmV4dCBzY3JpcHQnIHRoYXQgb3RoZXIgYnJvd3NlcnMgZG8uCiAgICAgICAgICAgICAgICAvL0Jlc3QgaG9wZTogSUUxMCBmaXhlcyB0aGUgaXNzdWVzLAogICAgICAgICAgICAgICAgLy9hbmQgdGhlbiBkZXN0cm95cyBhbGwgaW5zdGFsbHMgb2YgSUUgNi05LgogICAgICAgICAgICAgICAgLy9ub2RlLmF0dGFjaEV2ZW50KCdvbmVycm9yJywgY29udGV4dC5vblNjcmlwdEVycm9yKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG5vZGUuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIGNvbnRleHQub25TY3JpcHRMb2FkLCBmYWxzZSk7CiAgICAgICAgICAgICAgICBub2RlLmFkZEV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgY29udGV4dC5vblNjcmlwdEVycm9yLCBmYWxzZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbm9kZS5zcmMgPSB1cmw7CgogICAgICAgICAgICAvL0ZvciBzb21lIGNhY2hlIGNhc2VzIGluIElFIDYtOCwgdGhlIHNjcmlwdCBleGVjdXRlcyBiZWZvcmUgdGhlIGVuZAogICAgICAgICAgICAvL29mIHRoZSBhcHBlbmRDaGlsZCBleGVjdXRpb24sIHNvIHRvIHRpZSBhbiBhbm9ueW1vdXMgZGVmaW5lCiAgICAgICAgICAgIC8vY2FsbCB0byB0aGUgbW9kdWxlIG5hbWUgKHdoaWNoIGlzIHN0b3JlZCBvbiB0aGUgbm9kZSksIGhvbGQgb24KICAgICAgICAgICAgLy90byBhIHJlZmVyZW5jZSB0byB0aGlzIG5vZGUsIGJ1dCBjbGVhciBhZnRlciB0aGUgRE9NIGluc2VydGlvbi4KICAgICAgICAgICAgY3VycmVudGx5QWRkaW5nU2NyaXB0ID0gbm9kZTsKICAgICAgICAgICAgaWYgKGJhc2VFbGVtZW50KSB7CiAgICAgICAgICAgICAgICBoZWFkLmluc2VydEJlZm9yZShub2RlLCBiYXNlRWxlbWVudCk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBoZWFkLmFwcGVuZENoaWxkKG5vZGUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGN1cnJlbnRseUFkZGluZ1NjcmlwdCA9IG51bGw7CgogICAgICAgICAgICByZXR1cm4gbm9kZTsKICAgICAgICB9IGVsc2UgaWYgKGlzV2ViV29ya2VyKSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAvL0luIGEgd2ViIHdvcmtlciwgdXNlIGltcG9ydFNjcmlwdHMuIFRoaXMgaXMgbm90IGEgdmVyeQogICAgICAgICAgICAgICAgLy9lZmZpY2llbnQgdXNlIG9mIGltcG9ydFNjcmlwdHMsIGltcG9ydFNjcmlwdHMgd2lsbCBibG9jayB1bnRpbAogICAgICAgICAgICAgICAgLy9pdHMgc2NyaXB0IGlzIGRvd25sb2FkZWQgYW5kIGV2YWx1YXRlZC4gSG93ZXZlciwgaWYgd2ViIHdvcmtlcnMKICAgICAgICAgICAgICAgIC8vYXJlIGluIHBsYXksIHRoZSBleHBlY3RhdGlvbiBpcyB0aGF0IGEgYnVpbGQgaGFzIGJlZW4gZG9uZSBzbwogICAgICAgICAgICAgICAgLy90aGF0IG9ubHkgb25lIHNjcmlwdCBuZWVkcyB0byBiZSBsb2FkZWQgYW55d2F5LiBUaGlzIG1heSBuZWVkCiAgICAgICAgICAgICAgICAvL3RvIGJlIHJlZXZhbHVhdGVkIGlmIG90aGVyIHVzZSBjYXNlcyBiZWNvbWUgY29tbW9uLgogICAgICAgICAgICAgICAgaW1wb3J0U2NyaXB0cyh1cmwpOwoKICAgICAgICAgICAgICAgIC8vQWNjb3VudCBmb3IgYW5vbnltb3VzIG1vZHVsZXMKICAgICAgICAgICAgICAgIGNvbnRleHQuY29tcGxldGVMb2FkKG1vZHVsZU5hbWUpOwogICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICBjb250ZXh0Lm9uRXJyb3IobWFrZUVycm9yKCdpbXBvcnRzY3JpcHRzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnaW1wb3J0U2NyaXB0cyBmYWlsZWQgZm9yICcgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGVOYW1lICsgJyBhdCAnICsgdXJsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW21vZHVsZU5hbWVdKSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9OwoKICAgIGZ1bmN0aW9uIGdldEludGVyYWN0aXZlU2NyaXB0KCkgewogICAgICAgIGlmIChpbnRlcmFjdGl2ZVNjcmlwdCAmJiBpbnRlcmFjdGl2ZVNjcmlwdC5yZWFkeVN0YXRlID09PSAnaW50ZXJhY3RpdmUnKSB7CiAgICAgICAgICAgIHJldHVybiBpbnRlcmFjdGl2ZVNjcmlwdDsKICAgICAgICB9CgogICAgICAgIGVhY2hSZXZlcnNlKHNjcmlwdHMoKSwgZnVuY3Rpb24gKHNjcmlwdCkgewogICAgICAgICAgICBpZiAoc2NyaXB0LnJlYWR5U3RhdGUgPT09ICdpbnRlcmFjdGl2ZScpIHsKICAgICAgICAgICAgICAgIHJldHVybiAoaW50ZXJhY3RpdmVTY3JpcHQgPSBzY3JpcHQpOwogICAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgcmV0dXJuIGludGVyYWN0aXZlU2NyaXB0OwogICAgfQoKICAgIC8vTG9vayBmb3IgYSBkYXRhLW1haW4gc2NyaXB0IGF0dHJpYnV0ZSwgd2hpY2ggY291bGQgYWxzbyBhZGp1c3QgdGhlIGJhc2VVcmwuCiAgICBpZiAoaXNCcm93c2VyICYmICFjZmcuc2tpcERhdGFNYWluKSB7CiAgICAgICAgLy9GaWd1cmUgb3V0IGJhc2VVcmwuIEdldCBpdCBmcm9tIHRoZSBzY3JpcHQgdGFnIHdpdGggcmVxdWlyZS5qcyBpbiBpdC4KICAgICAgICBlYWNoUmV2ZXJzZShzY3JpcHRzKCksIGZ1bmN0aW9uIChzY3JpcHQpIHsKICAgICAgICAgICAgLy9TZXQgdGhlICdoZWFkJyB3aGVyZSB3ZSBjYW4gYXBwZW5kIGNoaWxkcmVuIGJ5CiAgICAgICAgICAgIC8vdXNpbmcgdGhlIHNjcmlwdCdzIHBhcmVudC4KICAgICAgICAgICAgaWYgKCFoZWFkKSB7CiAgICAgICAgICAgICAgICBoZWFkID0gc2NyaXB0LnBhcmVudE5vZGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8vTG9vayBmb3IgYSBkYXRhLW1haW4gYXR0cmlidXRlIHRvIHNldCBtYWluIHNjcmlwdCBmb3IgdGhlIHBhZ2UKICAgICAgICAgICAgLy90byBsb2FkLiBJZiBpdCBpcyB0aGVyZSwgdGhlIHBhdGggdG8gZGF0YSBtYWluIGJlY29tZXMgdGhlCiAgICAgICAgICAgIC8vYmFzZVVybCwgaWYgaXQgaXMgbm90IGFscmVhZHkgc2V0LgogICAgICAgICAgICBkYXRhTWFpbiA9IHNjcmlwdC5nZXRBdHRyaWJ1dGUoJ2RhdGEtbWFpbicpOwogICAgICAgICAgICBpZiAoZGF0YU1haW4pIHsKICAgICAgICAgICAgICAgIC8vUHJlc2VydmUgZGF0YU1haW4gaW4gY2FzZSBpdCBpcyBhIHBhdGggKGkuZS4gY29udGFpbnMgJz8nKQogICAgICAgICAgICAgICAgbWFpblNjcmlwdCA9IGRhdGFNYWluOwoKICAgICAgICAgICAgICAgIC8vU2V0IGZpbmFsIGJhc2VVcmwgaWYgdGhlcmUgaXMgbm90IGFscmVhZHkgYW4gZXhwbGljaXQgb25lLgogICAgICAgICAgICAgICAgaWYgKCFjZmcuYmFzZVVybCkgewogICAgICAgICAgICAgICAgICAgIC8vUHVsbCBvZmYgdGhlIGRpcmVjdG9yeSBvZiBkYXRhLW1haW4gZm9yIHVzZSBhcyB0aGUKICAgICAgICAgICAgICAgICAgICAvL2Jhc2VVcmwuCiAgICAgICAgICAgICAgICAgICAgc3JjID0gbWFpblNjcmlwdC5zcGxpdCgnLycpOwogICAgICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBzcmMucG9wKCk7CiAgICAgICAgICAgICAgICAgICAgc3ViUGF0aCA9IHNyYy5sZW5ndGggPyBzcmMuam9pbignLycpICArICcvJyA6ICcuLyc7CgogICAgICAgICAgICAgICAgICAgIGNmZy5iYXNlVXJsID0gc3ViUGF0aDsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL1N0cmlwIG9mZiBhbnkgdHJhaWxpbmcgLmpzIHNpbmNlIG1haW5TY3JpcHQgaXMgbm93CiAgICAgICAgICAgICAgICAvL2xpa2UgYSBtb2R1bGUgbmFtZS4KICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBtYWluU2NyaXB0LnJlcGxhY2UoanNTdWZmaXhSZWdFeHAsICcnKTsKCiAgICAgICAgICAgICAgICAvL0lmIG1haW5TY3JpcHQgaXMgc3RpbGwgYSBwYXRoLCBmYWxsIGJhY2sgdG8gZGF0YU1haW4KICAgICAgICAgICAgICAgIGlmIChyZXEuanNFeHRSZWdFeHAudGVzdChtYWluU2NyaXB0KSkgewogICAgICAgICAgICAgICAgICAgIG1haW5TY3JpcHQgPSBkYXRhTWFpbjsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAvL1B1dCB0aGUgZGF0YS1tYWluIHNjcmlwdCBpbiB0aGUgZmlsZXMgdG8gbG9hZC4KICAgICAgICAgICAgICAgIGNmZy5kZXBzID0gY2ZnLmRlcHMgPyBjZmcuZGVwcy5jb25jYXQobWFpblNjcmlwdCkgOiBbbWFpblNjcmlwdF07CgogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICB9KTsKICAgIH0KCiAgICAvKioKICAgICAqIFRoZSBmdW5jdGlvbiB0aGF0IGhhbmRsZXMgZGVmaW5pdGlvbnMgb2YgbW9kdWxlcy4gRGlmZmVycyBmcm9tCiAgICAgKiByZXF1aXJlKCkgaW4gdGhhdCBhIHN0cmluZyBmb3IgdGhlIG1vZHVsZSBzaG91bGQgYmUgdGhlIGZpcnN0IGFyZ3VtZW50LAogICAgICogYW5kIHRoZSBmdW5jdGlvbiB0byBleGVjdXRlIGFmdGVyIGRlcGVuZGVuY2llcyBhcmUgbG9hZGVkIHNob3VsZAogICAgICogcmV0dXJuIGEgdmFsdWUgdG8gZGVmaW5lIHRoZSBtb2R1bGUgY29ycmVzcG9uZGluZyB0byB0aGUgZmlyc3QgYXJndW1lbnQncwogICAgICogbmFtZS4KICAgICAqLwogICAgZGVmaW5lID0gZnVuY3Rpb24gKG5hbWUsIGRlcHMsIGNhbGxiYWNrKSB7CiAgICAgICAgdmFyIG5vZGUsIGNvbnRleHQ7CgogICAgICAgIC8vQWxsb3cgZm9yIGFub255bW91cyBtb2R1bGVzCiAgICAgICAgaWYgKHR5cGVvZiBuYW1lICE9PSAnc3RyaW5nJykgewogICAgICAgICAgICAvL0FkanVzdCBhcmdzIGFwcHJvcHJpYXRlbHkKICAgICAgICAgICAgY2FsbGJhY2sgPSBkZXBzOwogICAgICAgICAgICBkZXBzID0gbmFtZTsKICAgICAgICAgICAgbmFtZSA9IG51bGw7CiAgICAgICAgfQoKICAgICAgICAvL1RoaXMgbW9kdWxlIG1heSBub3QgaGF2ZSBkZXBlbmRlbmNpZXMKICAgICAgICBpZiAoIWlzQXJyYXkoZGVwcykpIHsKICAgICAgICAgICAgY2FsbGJhY2sgPSBkZXBzOwogICAgICAgICAgICBkZXBzID0gbnVsbDsKICAgICAgICB9CgogICAgICAgIC8vSWYgbm8gbmFtZSwgYW5kIGNhbGxiYWNrIGlzIGEgZnVuY3Rpb24sIHRoZW4gZmlndXJlIG91dCBpZiBpdCBhCiAgICAgICAgLy9Db21tb25KUyB0aGluZyB3aXRoIGRlcGVuZGVuY2llcy4KICAgICAgICBpZiAoIWRlcHMgJiYgaXNGdW5jdGlvbihjYWxsYmFjaykpIHsKICAgICAgICAgICAgZGVwcyA9IFtdOwogICAgICAgICAgICAvL1JlbW92ZSBjb21tZW50cyBmcm9tIHRoZSBjYWxsYmFjayBzdHJpbmcsCiAgICAgICAgICAgIC8vbG9vayBmb3IgcmVxdWlyZSBjYWxscywgYW5kIHB1bGwgdGhlbSBpbnRvIHRoZSBkZXBlbmRlbmNpZXMsCiAgICAgICAgICAgIC8vYnV0IG9ubHkgaWYgdGhlcmUgYXJlIGZ1bmN0aW9uIGFyZ3MuCiAgICAgICAgICAgIGlmIChjYWxsYmFjay5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGNhbGxiYWNrCiAgICAgICAgICAgICAgICAgICAgLnRvU3RyaW5nKCkKICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShjb21tZW50UmVnRXhwLCAnJykKICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShjanNSZXF1aXJlUmVnRXhwLCBmdW5jdGlvbiAobWF0Y2gsIGRlcCkgewogICAgICAgICAgICAgICAgICAgICAgICBkZXBzLnB1c2goZGVwKTsKICAgICAgICAgICAgICAgICAgICB9KTsKCiAgICAgICAgICAgICAgICAvL01heSBiZSBhIENvbW1vbkpTIHRoaW5nIGV2ZW4gd2l0aG91dCByZXF1aXJlIGNhbGxzLCBidXQgc3RpbGwKICAgICAgICAgICAgICAgIC8vY291bGQgdXNlIGV4cG9ydHMsIGFuZCBtb2R1bGUuIEF2b2lkIGRvaW5nIGV4cG9ydHMgYW5kIG1vZHVsZQogICAgICAgICAgICAgICAgLy93b3JrIHRob3VnaCBpZiBpdCBqdXN0IG5lZWRzIHJlcXVpcmUuCiAgICAgICAgICAgICAgICAvL1JFUVVJUkVTIHRoZSBmdW5jdGlvbiB0byBleHBlY3QgdGhlIENvbW1vbkpTIHZhcmlhYmxlcyBpbiB0aGUKICAgICAgICAgICAgICAgIC8vb3JkZXIgbGlzdGVkIGJlbG93LgogICAgICAgICAgICAgICAgZGVwcyA9IChjYWxsYmFjay5sZW5ndGggPT09IDEgPyBbJ3JlcXVpcmUnXSA6IFsncmVxdWlyZScsICdleHBvcnRzJywgJ21vZHVsZSddKS5jb25jYXQoZGVwcyk7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8vSWYgaW4gSUUgNi04IGFuZCBoaXQgYW4gYW5vbnltb3VzIGRlZmluZSgpIGNhbGwsIGRvIHRoZSBpbnRlcmFjdGl2ZQogICAgICAgIC8vd29yay4KICAgICAgICBpZiAodXNlSW50ZXJhY3RpdmUpIHsKICAgICAgICAgICAgbm9kZSA9IGN1cnJlbnRseUFkZGluZ1NjcmlwdCB8fCBnZXRJbnRlcmFjdGl2ZVNjcmlwdCgpOwogICAgICAgICAgICBpZiAobm9kZSkgewogICAgICAgICAgICAgICAgaWYgKCFuYW1lKSB7CiAgICAgICAgICAgICAgICAgICAgbmFtZSA9IG5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLXJlcXVpcmVtb2R1bGUnKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNvbnRleHQgPSBjb250ZXh0c1tub2RlLmdldEF0dHJpYnV0ZSgnZGF0YS1yZXF1aXJlY29udGV4dCcpXTsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy9BbHdheXMgc2F2ZSBvZmYgZXZhbHVhdGluZyB0aGUgZGVmIGNhbGwgdW50aWwgdGhlIHNjcmlwdCBvbmxvYWQgaGFuZGxlci4KICAgICAgICAvL1RoaXMgYWxsb3dzIG11bHRpcGxlIG1vZHVsZXMgdG8gYmUgaW4gYSBmaWxlIHdpdGhvdXQgcHJlbWF0dXJlbHkKICAgICAgICAvL3RyYWNpbmcgZGVwZW5kZW5jaWVzLCBhbmQgYWxsb3dzIGZvciBhbm9ueW1vdXMgbW9kdWxlIHN1cHBvcnQsCiAgICAgICAgLy93aGVyZSB0aGUgbW9kdWxlIG5hbWUgaXMgbm90IGtub3duIHVudGlsIHRoZSBzY3JpcHQgb25sb2FkIGV2ZW50CiAgICAgICAgLy9vY2N1cnMuIElmIG5vIGNvbnRleHQsIHVzZSB0aGUgZ2xvYmFsIHF1ZXVlLCBhbmQgZ2V0IGl0IHByb2Nlc3NlZAogICAgICAgIC8vaW4gdGhlIG9uc2NyaXB0IGxvYWQgY2FsbGJhY2suCiAgICAgICAgaWYgKGNvbnRleHQpIHsKICAgICAgICAgICAgY29udGV4dC5kZWZRdWV1ZS5wdXNoKFtuYW1lLCBkZXBzLCBjYWxsYmFja10pOwogICAgICAgICAgICBjb250ZXh0LmRlZlF1ZXVlTWFwW25hbWVdID0gdHJ1ZTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBnbG9iYWxEZWZRdWV1ZS5wdXNoKFtuYW1lLCBkZXBzLCBjYWxsYmFja10pOwogICAgICAgIH0KICAgIH07CgogICAgZGVmaW5lLmFtZCA9IHsKICAgICAgICBqUXVlcnk6IHRydWUKICAgIH07CgogICAgLyoqCiAgICAgKiBFeGVjdXRlcyB0aGUgdGV4dC4gTm9ybWFsbHkganVzdCB1c2VzIGV2YWwsIGJ1dCBjYW4gYmUgbW9kaWZpZWQKICAgICAqIHRvIHVzZSBhIGJldHRlciwgZW52aXJvbm1lbnQtc3BlY2lmaWMgY2FsbC4gT25seSB1c2VkIGZvciB0cmFuc3BpbGluZwogICAgICogbG9hZGVyIHBsdWdpbnMsIG5vdCBmb3IgcGxhaW4gSlMgbW9kdWxlcy4KICAgICAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0IHRoZSB0ZXh0IHRvIGV4ZWN1dGUvZXZhbHVhdGUuCiAgICAgKi8KICAgIHJlcS5leGVjID0gZnVuY3Rpb24gKHRleHQpIHsKICAgICAgICAvKmpzbGludCBldmlsOiB0cnVlICovCiAgICAgICAgcmV0dXJuIGV2YWwodGV4dCk7CiAgICB9OwoKICAgIC8vU2V0IHVwIHdpdGggY29uZmlnIGluZm8uCiAgICByZXEoY2ZnKTsKfSh0aGlzKSk7Cg==", "ok": true, "headers": [ [ "content-type", "application/javascript" ] ], "status": 200, "status_text": "" } }, "base_uri": "https://localhost:8080/", "height": 542 } }, "cell_type": "code", "source": [ "import cufflinks as cf\n", "cf.go_offline()\n", "\n", "from plotly.offline import init_notebook_mode\n", "configure_plotly_browser_state()\n", "init_notebook_mode(connected=False)\n", "\n", "\n", "df_comparison.iplot(title=\"Bay Area Median Single Family Home Prices 1996-2017\",\n", " xTitle=\"Year\",\n", " yTitle=\"Sales Price\",\n", " #bestfit=True, bestfit_colors=[\"pink\"],\n", " #subplots=True,\n", " shape=(4,1),\n", " #subplot_titles=True,\n", " fill=True,)" ], "execution_count": 0, "outputs": [ { "output_type": "display_data", "data": { "text/vnd.plotly.v1+html": "", "text/html": [ "" ] }, "metadata": { "tags": [] } }, { "output_type": "display_data", "data": { "text/html": [ "\n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": { "tags": [] } }, { "output_type": "display_data", "data": { "text/vnd.plotly.v1+html": "", "text/html": [ "" ] }, "metadata": { "tags": [] } }, { "output_type": "display_data", "data": { "text/vnd.plotly.v1+html": "
", "text/html": [ "
" ], "application/vnd.plotly.v1+json": { "layout": { "title": "Bay Area Median Single Family Home Prices 1996-2017", "paper_bgcolor": "#F5F6F9", "plot_bgcolor": "#F5F6F9", "yaxis": { "tickfont": { "color": "#4D5663" }, "title": "Sales Price", "showgrid": true, "zerolinecolor": "#E1E5ED", "titlefont": { "color": "#4D5663" }, "gridcolor": "#E1E5ED" }, "titlefont": { "color": "#4D5663" }, "xaxis": { "tickfont": { "color": "#4D5663" }, "title": "Year", "showgrid": true, "zerolinecolor": "#E1E5ED", "titlefont": { "color": "#4D5663" }, "gridcolor": "#E1E5ED" }, "legend": { "bgcolor": "#F5F6F9", "font": { "color": "#4D5663" } } }, "config": { "plotlyServerURL": "https://plot.ly", "linkText": "Export to plot.ly", "showLink": true }, "data": [ { "name": "Marin County", "uid": "a095e749-7aea-41ca-852d-b3c513eca337", "text": "", "mode": "lines", "y": [ 97881, 94941, 6884, 337700, 335000, 334400, 336300, 336900, 335500, 335800, 337400, 338600, 339900, 342900, 345100, 346800, 349300, 353000, 357200, 368000, 369500, 371000, 375000, 380550, 385000, 388200, 398150, 402650, "", "", 410650, 417450, 418800, 428250, 430850, 435750, 442350, 449400, 456250, 462550, 469100, 476250, 483950, 491200, 497400, 506700, 520850, 535100, 545450, 552750, 560600, 568800, 576500, 584600, 593400, 602850, 609700, 614850, 622150, 630700, 637850, 642850, 647850, 653250, 658850, 659600, 659750, 658250, 657500, 658750, 661400, 662300, 663300, 663450, 663800, 665150, 667700, 666900, 667500, 670050, 677050, 683200, 686600, 686150, 686550, 690350, 697250, 704650, 710750, 715800, 720400, 725300, 729950, 734300, 738550, 744750, 752700, 760800, 771300, 785300, 801100, 816500, 830450, 839500, 845900, 852500, 858700, 864750, 873600, 883600, 892400, 899200, 903150, 904600, 907150, 911850, 917000, 922500, 929350, 937850, 945250, 948500, 947650, 948150, 949800, 949850, 947100, 943850, 941450, 939950, 935950, 931750, 928950, 927850, 924950, 919600, 911950, 905000, 903200, 907200, 912500, 910350, 904100, 901550, 906150, 911000, 912450, 907650, 897800, 890200, 888600, 888650, 882300, 875400, 867550, 857150, 847000, 840800, 831200, 818000, 803800, 790800, 783950, 782200, 780300, 779050, 783600, 777500, 759250, 753200, 766850, 780500, 787750, 791800, 787000, 778850, 771200, 759750, 750700, 756650, 755000, 727800, 696900, 685850, 696250, 714850, 722350, 718100, 722550, 747800, 755100, 753000, 758700, 772300, 780600, 781700, 781800, 781100, 774700, 764200, 755200, 750000, 752600, 768100, 789200, 805800, 818600, 836900, 861800, 888800, 919900, 947600, 957200, 947400, 934300, 925000, 916300, 908000, 901200, 894900, 888600, 888800, 897900, 911400, 924800, 943700, 960400, 960900, 964500, 985200, 1007500, 1016000, 1011500, 1003300, 1002100, 1006000, 1007600, 1015400, 1027800, 1044900, 1067800, 1085900, 1105800, 1124800, 1133400, 1133900, 1134900, 1142300, 1156000, 1166800, 1162200, 1160100, 1165000, 1173300, 1176600, 1177700, 1168200, 1156600, 1151400, 1149900, 1168300 ], "x": [ "RegionID", "ZipCode", "SizeRank", "1996-04", "1996-05", "1996-06", "1996-07", "1996-08", "1996-09", "1996-10", "1996-11", "1996-12", "1997-01", "1997-02", "1997-03", "1997-04", "1997-05", "1997-06", "1997-07", "1997-08", "1997-09", "1997-10", "1997-11", "1997-12", "1998-01", "1998-02", "1998-03", "1998-04", "1998-05", "1998-06", "1998-07", "1998-08", "1998-09", "1998-10", "1998-11", "1998-12", "1999-01", "1999-02", "1999-03", "1999-04", "1999-05", "1999-06", "1999-07", "1999-08", "1999-09", "1999-10", "1999-11", "1999-12", "2000-01", "2000-02", "2000-03", "2000-04", "2000-05", "2000-06", "2000-07", "2000-08", "2000-09", "2000-10", "2000-11", "2000-12", "2001-01", "2001-02", "2001-03", "2001-04", "2001-05", "2001-06", "2001-07", "2001-08", "2001-09", "2001-10", "2001-11", "2001-12", "2002-01", "2002-02", "2002-03", "2002-04", "2002-05", "2002-06", "2002-07", "2002-08", "2002-09", "2002-10", "2002-11", "2002-12", "2003-01", "2003-02", "2003-03", "2003-04", "2003-05", "2003-06", "2003-07", "2003-08", "2003-09", "2003-10", "2003-11", "2003-12", "2004-01", "2004-02", "2004-03", "2004-04", "2004-05", "2004-06", "2004-07", "2004-08", "2004-09", "2004-10", "2004-11", "2004-12", "2005-01", "2005-02", "2005-03", "2005-04", "2005-05", "2005-06", "2005-07", "2005-08", "2005-09", "2005-10", "2005-11", "2005-12", "2006-01", "2006-02", "2006-03", "2006-04", "2006-05", "2006-06", "2006-07", "2006-08", "2006-09", "2006-10", "2006-11", "2006-12", "2007-01", "2007-02", "2007-03", "2007-04", "2007-05", "2007-06", "2007-07", "2007-08", "2007-09", "2007-10", "2007-11", "2007-12", "2008-01", "2008-02", "2008-03", "2008-04", "2008-05", "2008-06", "2008-07", "2008-08", "2008-09", "2008-10", "2008-11", "2008-12", "2009-01", "2009-02", "2009-03", "2009-04", "2009-05", "2009-06", "2009-07", "2009-08", "2009-09", "2009-10", "2009-11", "2009-12", "2010-01", "2010-02", "2010-03", "2010-04", "2010-05", "2010-06", "2010-07", "2010-08", "2010-09", "2010-10", "2010-11", "2010-12", "2011-01", "2011-02", "2011-03", "2011-04", "2011-05", "2011-06", "2011-07", "2011-08", "2011-09", "2011-10", "2011-11", "2011-12", "2012-01", "2012-02", "2012-03", "2012-04", "2012-05", "2012-06", "2012-07", "2012-08", "2012-09", "2012-10", "2012-11", "2012-12", "2013-01", "2013-02", "2013-03", "2013-04", "2013-05", "2013-06", "2013-07", "2013-08", "2013-09", "2013-10", "2013-11", "2013-12", "2014-01", "2014-02", "2014-03", "2014-04", "2014-05", "2014-06", "2014-07", "2014-08", "2014-09", "2014-10", "2014-11", "2014-12", "2015-01", "2015-02", "2015-03", "2015-04", "2015-05", "2015-06", "2015-07", "2015-08", "2015-09", "2015-10", "2015-11", "2015-12", "2016-01", "2016-02", "2016-03", "2016-04", "2016-05", "2016-06", "2016-07", "2016-08", "2016-09", "2016-10", "2016-11", "2016-12", "2017-01", "2017-02", "2017-03", "2017-04", "2017-05", "2017-06", "2017-07", "2017-08", "2017-09" ], "line": { "color": "rgba(255, 153, 51, 1.0)", "dash": "solid", "shape": "linear", "width": 1.3 }, "fill": "tozeroy", "type": "scatter", "fillcolor": "rgba(255, 153, 51, 0.3)" }, { "name": "San Francisco", "uid": "b90f3b3c-d91b-4ab5-8c30-1eb4073693c2", "text": "", "mode": "lines", "y": [ 97572, 94118, 1553, 258100, 260850, 262750, 265000, 267100, 267950, 268350, 269900, 271800, 273550, 287400, 290500, 293100, 295500, 297600, 300600, 308550, 313250, 317850, 322650, 327800, 334450, 340850, 343900, 344150, 345300, 348250, 351700, 354700, 357300, 360800, 363700, 363600, 364550, 366450, 369400, 375300, 385200, 394150, 400150, 406450, 415150, 426100, 438750, 453350, 469700, 483950, 497750, 509200, 519450, 532700, 545950, 551700, 553000, 552200, 552700, 556250, 560200, 565150, 573450, 579200, 579350, 576400, 574600, 576850, 582750, 585300, 590100, 596300, 597600, 597150, 594150, 593450, 600800, 610900, 618550, 625650, 626300, 621050, 616150, 613950, 611800, 608650, 606250, 607200, 610850, 618500, 628600, 637150, 640600, 645350, 650800, 662200, 673250, 685050, 697700, 710600, 717600, 721550, 724150, 728750, 736750, 753050, 772400, 784400, 795450, 809350, 826300, 840900, 847750, 849500, 853850, 863050, 870650, 872850, 872500, 869900, 871400, 875100, 875200, 868800, 865400, 861950, 856600, 852150, 851150, 849450, 840400, 829550, 825850, 829550, 836250, 847850, 864400, 881350, 894500, 900100, 901250, 900450, 900750, 898950, 894050, 889450, 882800, 873500, 863550, 852700, 839850, 828750, 819000, 812300, 810450, 804550, 790300, 774850, 764450, 760300, 755850, 753050, 753800, 757000, 758950, 758600, 758300, 765100, 776850, 784650, 781550, 775800, 768800, 764650, 758650, 792300, 793000, 792200, 787600, 779500, 773200, 772100, 772300, 775300, 779200, 783800, 788800, 791400, 790900, 792300, 794200, 792300, 788800, 785700, 778700, 781900, 791700, 803100, 819600, 831300, 835700, 844100, 859900, 870100, 875200, 882900, 896600, 914800, 934800, 957400, 976100, 996300, 1024800, 1059900, 1083000, 1094500, 1105600, 1121800, 1140000, 1159300, 1182000, 1207500, 1224000, 1231700, 1243100, 1247400, 1239000, 1229900, 1233800, 1263700, 1309300, 1345200, 1369500, 1392500, 1426800, 1437400, 1440700, 1447500, 1455200, 1465200, 1478200, 1490800, 1502900, 1502500, 1492300, 1476100, 1448100, 1431800, 1431000, 1425700, 1424100, 1426500, 1427800, 1428500, 1435800, 1447500, 1453300, 1455300, 1460600, 1469400, 1475500 ], "x": [ "RegionID", "ZipCode", "SizeRank", "1996-04", "1996-05", "1996-06", "1996-07", "1996-08", "1996-09", "1996-10", "1996-11", "1996-12", "1997-01", "1997-02", "1997-03", "1997-04", "1997-05", "1997-06", "1997-07", "1997-08", "1997-09", "1997-10", "1997-11", "1997-12", "1998-01", "1998-02", "1998-03", "1998-04", "1998-05", "1998-06", "1998-07", "1998-08", "1998-09", "1998-10", "1998-11", "1998-12", "1999-01", "1999-02", "1999-03", "1999-04", "1999-05", "1999-06", "1999-07", "1999-08", "1999-09", "1999-10", "1999-11", "1999-12", "2000-01", "2000-02", "2000-03", "2000-04", "2000-05", "2000-06", "2000-07", "2000-08", "2000-09", "2000-10", "2000-11", "2000-12", "2001-01", "2001-02", "2001-03", "2001-04", "2001-05", "2001-06", "2001-07", "2001-08", "2001-09", "2001-10", "2001-11", "2001-12", "2002-01", "2002-02", "2002-03", "2002-04", "2002-05", "2002-06", "2002-07", "2002-08", "2002-09", "2002-10", "2002-11", "2002-12", "2003-01", "2003-02", "2003-03", "2003-04", "2003-05", "2003-06", "2003-07", "2003-08", "2003-09", "2003-10", "2003-11", "2003-12", "2004-01", "2004-02", "2004-03", "2004-04", "2004-05", "2004-06", "2004-07", "2004-08", "2004-09", "2004-10", "2004-11", "2004-12", "2005-01", "2005-02", "2005-03", "2005-04", "2005-05", "2005-06", "2005-07", "2005-08", "2005-09", "2005-10", "2005-11", "2005-12", "2006-01", "2006-02", "2006-03", "2006-04", "2006-05", "2006-06", "2006-07", "2006-08", "2006-09", "2006-10", "2006-11", "2006-12", "2007-01", "2007-02", "2007-03", "2007-04", "2007-05", "2007-06", "2007-07", "2007-08", "2007-09", "2007-10", "2007-11", "2007-12", "2008-01", "2008-02", "2008-03", "2008-04", "2008-05", "2008-06", "2008-07", "2008-08", "2008-09", "2008-10", "2008-11", "2008-12", "2009-01", "2009-02", "2009-03", "2009-04", "2009-05", "2009-06", "2009-07", "2009-08", "2009-09", "2009-10", "2009-11", "2009-12", "2010-01", "2010-02", "2010-03", "2010-04", "2010-05", "2010-06", "2010-07", "2010-08", "2010-09", "2010-10", "2010-11", "2010-12", "2011-01", "2011-02", "2011-03", "2011-04", "2011-05", "2011-06", "2011-07", "2011-08", "2011-09", "2011-10", "2011-11", "2011-12", "2012-01", "2012-02", "2012-03", "2012-04", "2012-05", "2012-06", "2012-07", "2012-08", "2012-09", "2012-10", "2012-11", "2012-12", "2013-01", "2013-02", "2013-03", "2013-04", "2013-05", "2013-06", "2013-07", "2013-08", "2013-09", "2013-10", "2013-11", "2013-12", "2014-01", "2014-02", "2014-03", "2014-04", "2014-05", "2014-06", "2014-07", "2014-08", "2014-09", "2014-10", "2014-11", "2014-12", "2015-01", "2015-02", "2015-03", "2015-04", "2015-05", "2015-06", "2015-07", "2015-08", "2015-09", "2015-10", "2015-11", "2015-12", "2016-01", "2016-02", "2016-03", "2016-04", "2016-05", "2016-06", "2016-07", "2016-08", "2016-09", "2016-10", "2016-11", "2016-12", "2017-01", "2017-02", "2017-03", "2017-04", "2017-05", "2017-06", "2017-07", "2017-08", "2017-09" ], "line": { "color": "rgba(55, 128, 191, 1.0)", "dash": "solid", "shape": "linear", "width": 1.3 }, "fill": "tozeroy", "type": "scatter", "fillcolor": "rgba(55, 128, 191, 0.3)" }, { "name": "Palo Alto", "uid": "633c01c4-ca4e-4493-8761-4988bfa70fe3", "text": "", "mode": "lines", "y": [ 97693, 94303, 3262, 431500, 434200, 436000, 439200, 444000, 448100, 452600, 458800, 466300, 474300, 480700, 485100, 488400, 491900, 496600, 502200, 509000, 518400, 528600, 537000, 544600, 550700, 555700, 561000, 566500, 570400, 572900, 575000, 578100, 580600, 583100, 585600, 586300, 584600, 585000, 588000, 592800, 599900, 610500, 626800, 645600, 663000, 680800, 700900, 720100, 740300, 763300, 785700, 810300, 838400, 865800, 886900, 900700, 913800, 931100, 946700, 956100, 961200, 960100, 950000, 932900, 912300, 889800, 864300, 839500, 819600, 802000, 783600, 769300, 762500, 765100, 778400, 798800, 820300, 839800, 854000, 863600, 871100, 875800, 879800, 884000, 884400, 879900, 874700, 868300, 859400, 851600, 850800, 856000, 861500, 867600, 877300, 891000, 905500, 917000, 924900, 931600, 938200, 947900, 962600, 980600, 997000, 1009300, 1020000, 1031800, 1046000, 1066000, 1092100, 1116800, 1142200, 1163100, 1178100, 1190300, 1201700, 1204400, 1199000, 1193200, 1193400, 1193600, 1187500, 1178400, 1172500, 1172000, 1174200, 1174400, 1174600, 1182700, 1202000, 1225300, 1242700, 1255200, 1268000, 1284800, 1296600, 1304800, 1310900, 1318800, 1325400, 1332300, 1339000, 1342400, 1340600, 1340800, 1342900, 1341200, 1338400, 1332400, 1322000, 1309900, 1299200, 1286700, 1272100, 1262000, 1259800, 1254500, 1245300, 1235400, 1225500, 1217500, 1214200, 1210600, 1204500, 1200700, 1201100, 1200000, 1199400, 1205900, 1209400, 1205800, 1203200, 1208000, 1210000, 1210200, 1215000, 1225800, 1233200, 1236700, 1231800, 1218700, 1209400, 1208500, 1211400, 1216500, 1225900, 1233400, 1238900, 1247100, 1256400, 1260700, 1264300, 1276400, 1296700, 1322200, 1353500, 1381900, 1409700, 1443000, 1479300, 1509800, 1534600, 1553100, 1566900, 1578300, 1589400, 1606100, 1630000, 1660400, 1697000, 1731100, 1761100, 1787600, 1816500, 1848200, 1887200, 1922700, 1953000, 1976100, 1992200, 2005200, 2021800, 2043400, 2080200, 2125700, 2165600, 2197700, 2228700, 2264700, 2312500, 2367500, 2417500, 2449400, 2465800, 2485300, 2507000, 2517400, 2516600, 2518100, 2530300, 2545700, 2558100, 2558000, 2536800, 2507200, 2480400, 2450100, 2430400, 2430400, 2439900, 2460800, 2496000, 2525900, 2544100, 2566800, 2594800, 2624400, 2643900, 2666300, 2690500 ], "x": [ "RegionID", "ZipCode", "SizeRank", "1996-04", "1996-05", "1996-06", "1996-07", "1996-08", "1996-09", "1996-10", "1996-11", "1996-12", "1997-01", "1997-02", "1997-03", "1997-04", "1997-05", "1997-06", "1997-07", "1997-08", "1997-09", "1997-10", "1997-11", "1997-12", "1998-01", "1998-02", "1998-03", "1998-04", "1998-05", "1998-06", "1998-07", "1998-08", "1998-09", "1998-10", "1998-11", "1998-12", "1999-01", "1999-02", "1999-03", "1999-04", "1999-05", "1999-06", "1999-07", "1999-08", "1999-09", "1999-10", "1999-11", "1999-12", "2000-01", "2000-02", "2000-03", "2000-04", "2000-05", "2000-06", "2000-07", "2000-08", "2000-09", "2000-10", "2000-11", "2000-12", "2001-01", "2001-02", "2001-03", "2001-04", "2001-05", "2001-06", "2001-07", "2001-08", "2001-09", "2001-10", "2001-11", "2001-12", "2002-01", "2002-02", "2002-03", "2002-04", "2002-05", "2002-06", "2002-07", "2002-08", "2002-09", "2002-10", "2002-11", "2002-12", "2003-01", "2003-02", "2003-03", "2003-04", "2003-05", "2003-06", "2003-07", "2003-08", "2003-09", "2003-10", "2003-11", "2003-12", "2004-01", "2004-02", "2004-03", "2004-04", "2004-05", "2004-06", "2004-07", "2004-08", "2004-09", "2004-10", "2004-11", "2004-12", "2005-01", "2005-02", "2005-03", "2005-04", "2005-05", "2005-06", "2005-07", "2005-08", "2005-09", "2005-10", "2005-11", "2005-12", "2006-01", "2006-02", "2006-03", "2006-04", "2006-05", "2006-06", "2006-07", "2006-08", "2006-09", "2006-10", "2006-11", "2006-12", "2007-01", "2007-02", "2007-03", "2007-04", "2007-05", "2007-06", "2007-07", "2007-08", "2007-09", "2007-10", "2007-11", "2007-12", "2008-01", "2008-02", "2008-03", "2008-04", "2008-05", "2008-06", "2008-07", "2008-08", "2008-09", "2008-10", "2008-11", "2008-12", "2009-01", "2009-02", "2009-03", "2009-04", "2009-05", "2009-06", "2009-07", "2009-08", "2009-09", "2009-10", "2009-11", "2009-12", "2010-01", "2010-02", "2010-03", "2010-04", "2010-05", "2010-06", "2010-07", "2010-08", "2010-09", "2010-10", "2010-11", "2010-12", "2011-01", "2011-02", "2011-03", "2011-04", "2011-05", "2011-06", "2011-07", "2011-08", "2011-09", "2011-10", "2011-11", "2011-12", "2012-01", "2012-02", "2012-03", "2012-04", "2012-05", "2012-06", "2012-07", "2012-08", "2012-09", "2012-10", "2012-11", "2012-12", "2013-01", "2013-02", "2013-03", "2013-04", "2013-05", "2013-06", "2013-07", "2013-08", "2013-09", "2013-10", "2013-11", "2013-12", "2014-01", "2014-02", "2014-03", "2014-04", "2014-05", "2014-06", "2014-07", "2014-08", "2014-09", "2014-10", "2014-11", "2014-12", "2015-01", "2015-02", "2015-03", "2015-04", "2015-05", "2015-06", "2015-07", "2015-08", "2015-09", "2015-10", "2015-11", "2015-12", "2016-01", "2016-02", "2016-03", "2016-04", "2016-05", "2016-06", "2016-07", "2016-08", "2016-09", "2016-10", "2016-11", "2016-12", "2017-01", "2017-02", "2017-03", "2017-04", "2017-05", "2017-06", "2017-07", "2017-08", "2017-09" ], "line": { "color": "rgba(50, 171, 96, 1.0)", "dash": "solid", "shape": "linear", "width": 1.3 }, "fill": "tozeroy", "type": "scatter", "fillcolor": "rgba(50, 171, 96, 0.3)" }, { "name": "Median USA", "uid": "1aa346e6-3a83-4daf-84ef-7368ade980d8", "text": "", "mode": "lines", "y": [ 77175, 44306.5, 7641.5, 104300, 104450, 104500, 104600, 104900, 105000, 105100, 105500, 105700, 106100, 105600, 106000, 106300, 106600, 107000, 107500, 107400, 107700, 108000, 108500, 108900, 109500, 109600, 110050, 110000, 110200, 110400, 111500, 111800, 112100, 112500, 113200, 113800, 114200, 114700, 115300, 115800, 116400, 117100, 117800, 118300, 118700, 119300, 120000, 120600, 121200, 121800, 122300, 122800, 123400, 124000, 124800, 125100, 125700, 126300, 126900, 127600, 128600, 128900, 129800, 130500, 131000, 131700, 132200, 132700, 133200, 133800, 134300, 134700, 135300, 135900, 136500, 137100, 137800, 138400, 139200, 140000, 140900, 141500, 142250, 143100, 143900, 144800, 145800, 146700, 147500, 148400, 149200, 150150, 151300, 152300, 153400, 154800, 155900, 156700, 157700, 158800, 159800, 161450, 162800, 164100, 165500, 167300, 168600, 170000, 171350, 172800, 174000, 175900, 177700, 179600, 181400, 182700, 184200, 185700, 187200, 188600, 190000, 190400, 191550, 192400, 193500, 194300, 194800, 195150, 196000, 196200, 196300, 196300, 196300, 196000, 196000, 196000, 195900, 195500, 194750, 194200, 194100, 193100, 192600, 191500, 190550, 189400, 188100, 186500, 185100, 183500, 182400, 180700, 179200, 177950, 176500, 175500, 175000, 174250, 173200, 171700, 170600, 168900, 167800, 165900, 165300, 164700, 164200, 163400, 162150, 161400, 159700, 159400, 158800, 158300, 157700, 154200, 153700, 153000, 152300, 151900, 151200, 150250, 149500, 148900, 148400, 148000, 147700, 147000, 146650, 146100, 145850, 145600, 145400, 145100, 145100, 145500, 145600, 145900, 146200, 146700, 147000, 147500, 147700, 148300, 148700, 148800, 149300, 149800, 150350, 150900, 151600, 152200, 152800, 153300, 154000, 154500, 154900, 155300, 155700, 156100, 156500, 157000, 157600, 158000, 158300, 158850, 159400, 159650, 159900, 160300, 161000, 161800, 162250, 162900, 163600, 164100, 164900, 165700, 166300, 167100, 167600, 168000, 168700, 169400, 170100, 171000, 171700, 172500, 173400, 174300, 175700, 176800, 177400, 178300, 179200, 179900, 180600, 181300, 182000, 182500, 183100 ], "x": [ "RegionID", "ZipCode", "SizeRank", "1996-04", "1996-05", "1996-06", "1996-07", "1996-08", "1996-09", "1996-10", "1996-11", "1996-12", "1997-01", "1997-02", "1997-03", "1997-04", "1997-05", "1997-06", "1997-07", "1997-08", "1997-09", "1997-10", "1997-11", "1997-12", "1998-01", "1998-02", "1998-03", "1998-04", "1998-05", "1998-06", "1998-07", "1998-08", "1998-09", "1998-10", "1998-11", "1998-12", "1999-01", "1999-02", "1999-03", "1999-04", "1999-05", "1999-06", "1999-07", "1999-08", "1999-09", "1999-10", "1999-11", "1999-12", "2000-01", "2000-02", "2000-03", "2000-04", "2000-05", "2000-06", "2000-07", "2000-08", "2000-09", "2000-10", "2000-11", "2000-12", "2001-01", "2001-02", "2001-03", "2001-04", "2001-05", "2001-06", "2001-07", "2001-08", "2001-09", "2001-10", "2001-11", "2001-12", "2002-01", "2002-02", "2002-03", "2002-04", "2002-05", "2002-06", "2002-07", "2002-08", "2002-09", "2002-10", "2002-11", "2002-12", "2003-01", "2003-02", "2003-03", "2003-04", "2003-05", "2003-06", "2003-07", "2003-08", "2003-09", "2003-10", "2003-11", "2003-12", "2004-01", "2004-02", "2004-03", "2004-04", "2004-05", "2004-06", "2004-07", "2004-08", "2004-09", "2004-10", "2004-11", "2004-12", "2005-01", "2005-02", "2005-03", "2005-04", "2005-05", "2005-06", "2005-07", "2005-08", "2005-09", "2005-10", "2005-11", "2005-12", "2006-01", "2006-02", "2006-03", "2006-04", "2006-05", "2006-06", "2006-07", "2006-08", "2006-09", "2006-10", "2006-11", "2006-12", "2007-01", "2007-02", "2007-03", "2007-04", "2007-05", "2007-06", "2007-07", "2007-08", "2007-09", "2007-10", "2007-11", "2007-12", "2008-01", "2008-02", "2008-03", "2008-04", "2008-05", "2008-06", "2008-07", "2008-08", "2008-09", "2008-10", "2008-11", "2008-12", "2009-01", "2009-02", "2009-03", "2009-04", "2009-05", "2009-06", "2009-07", "2009-08", "2009-09", "2009-10", "2009-11", "2009-12", "2010-01", "2010-02", "2010-03", "2010-04", "2010-05", "2010-06", "2010-07", "2010-08", "2010-09", "2010-10", "2010-11", "2010-12", "2011-01", "2011-02", "2011-03", "2011-04", "2011-05", "2011-06", "2011-07", "2011-08", "2011-09", "2011-10", "2011-11", "2011-12", "2012-01", "2012-02", "2012-03", "2012-04", "2012-05", "2012-06", "2012-07", "2012-08", "2012-09", "2012-10", "2012-11", "2012-12", "2013-01", "2013-02", "2013-03", "2013-04", "2013-05", "2013-06", "2013-07", "2013-08", "2013-09", "2013-10", "2013-11", "2013-12", "2014-01", "2014-02", "2014-03", "2014-04", "2014-05", "2014-06", "2014-07", "2014-08", "2014-09", "2014-10", "2014-11", "2014-12", "2015-01", "2015-02", "2015-03", "2015-04", "2015-05", "2015-06", "2015-07", "2015-08", "2015-09", "2015-10", "2015-11", "2015-12", "2016-01", "2016-02", "2016-03", "2016-04", "2016-05", "2016-06", "2016-07", "2016-08", "2016-09", "2016-10", "2016-11", "2016-12", "2017-01", "2017-02", "2017-03", "2017-04", "2017-05", "2017-06", "2017-07", "2017-08", "2017-09" ], "line": { "color": "rgba(128, 0, 128, 1.0)", "dash": "solid", "shape": "linear", "width": 1.3 }, "fill": "tozeroy", "type": "scatter", "fillcolor": "rgba(128, 0, 128, 0.3)" } ] } }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "m3vq6mPGt0_L", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## 3.2 Clustering" ] }, { "metadata": { "id": "WNJTB_vvgBQq", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "import pandas as pd\n", "pd.set_option('display.float_format', lambda x: '%.3f' % x)\n", "val_housing_win_df = pd.read_csv(\"https://raw.githubusercontent.com/noahgift/socialpowernba/master/data/nba_2017_att_val_elo_win_housing.csv\");val_housing_win_df.head()\n", "numerical_df = val_housing_win_df.loc[:,[\"TOTAL_ATTENDANCE_MILLIONS\", \"ELO\", \"VALUE_MILLIONS\", \"MEDIAN_HOME_PRICE_COUNTY_MILLIONS\"]]" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "D6YPY0DRgDbG", "colab_type": "code", "outputId": "afbe5ee9-2dcc-4ed4-d834-8fcde168cdbc", "colab": { "base_uri": "https://localhost:8080/", "height": 544 } }, "cell_type": "code", "source": [ "from sklearn.preprocessing import MinMaxScaler\n", "scaler = MinMaxScaler()\n", "print(scaler.fit(numerical_df))\n", "print(scaler.transform(numerical_df))" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "MinMaxScaler(copy=True, feature_range=(0, 1))\n", "[[1. 0.41898148 0.68627451 0.08776879]\n", " [0.72637903 0.18981481 0.2745098 0.11603661]\n", " [0.41067502 0.12731481 0.12745098 0.13419221]\n", " [0.70531986 0.53472222 0.23529412 0.16243496]\n", " [0.73232332 0.60648148 0.14705882 0.16306188]\n", " [0.62487072 0.68981481 0.49019608 0.31038806]\n", " [0.83819102 0.47916667 0.17647059 0.00476459]\n", " [0.6983872 1. 0.7254902 0.39188139]\n", " [0.49678606 0.47453704 0.10784314 0.04993825]\n", " [0.72417286 0.08333333 1. 1. ]\n", " [0.54749962 0.57638889 0.56862745 0.23139615]\n", " [0.60477873 0.06712963 0.88235294 0.31038806]\n", " [0.65812204 0.52083333 0.11764706 0.184816 ]\n", " [0.52863955 0.74768519 0.16666667 0.08156228]\n", " [0.70957335 0.64583333 0.0627451 0.13983449]\n", " [0.43166712 0.03240741 0.06666667 0.10657639]\n", " [0.20301662 0.33333333 0. 0.10350448]\n", " [0.31881029 0.61111111 0.35294118 0.09062441]\n", " [0.36376665 0.00462963 0.1372549 0.10350448]\n", " [0.27883458 0.43518519 0.05098039 0.00946649]\n", " [0.25319364 0.33333333 0.01568627 0.01573569]\n", " [0.3708405 0.28935185 0.01176471 0.10977023]\n", " [0.37053693 0. 0.01960784 0.03140869]\n", " [0.17197852 0.32638889 0.05294118 0.14738888]\n", " [0.09538753 0.0787037 0.41176471 0.40756065]\n", " [0.15307963 0.37962963 0.01372549 0. ]\n", " [0.32306025 0.57638889 0.09803922 0.27336844]\n", " [0. 0.49537037 0.05490196 0.21885775]\n", " [0.00571132 0.28935185 0.00784314 0.12758322]\n", " [0.17492596 0.23842593 0.05882353 0.10663281]]\n" ], "name": "stdout" } ] }, { "metadata": { "id": "BNnp4XnwuCyh", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Usupervized Learning Technique" ] }, { "metadata": { "id": "hfsMDiIxd07A", "colab_type": "text" }, "cell_type": "markdown", "source": [ "*NBA Season Faceted Cluster Plot *\n", "\n", "![Discovering Clusters in the NBA](https://user-images.githubusercontent.com/58792/40759110-6a93a2f8-6445-11e8-980b-ecbb1a2cc029.png)\n", "\n", "* Used to reveal hidden patterns\n", "* Can be used in Exploratory Data Analysis" ] }, { "metadata": { "id": "CjhaQfxjfo07", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Elbow Plot \n", "\n", "\n", "\n", "* Used to identify ideal cluster number\n", "* Diagnostic tool for Clustering\n", "\n", "\n" ] }, { "metadata": { "id": "L5OzYF01geMG", "colab_type": "code", "outputId": "18b36e9b-8e63-4fce-a14e-e0b3a0676b95", "colab": { "base_uri": "https://localhost:8080/", "height": 292 } }, "cell_type": "code", "source": [ "from sklearn.cluster import KMeans\n", "k_means = KMeans(n_clusters=3)\n", "kmeans = k_means.fit(scaler.transform(numerical_df))\n", "val_housing_win_df['cluster'] = kmeans.labels_\n", "val_housing_win_df.head()" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TEAMGMSPCT_ATTENDANCEWINNING_SEASONTOTAL_ATTENDANCE_MILLIONSVALUE_MILLIONSELOCONFCOUNTYMEDIAN_HOME_PRICE_COUNTY_MILLIONSCOUNTY_POPULATION_MILLIONScluster
0Chicago Bulls4110410.88888225001519EastCook269900.05.200
1Dallas Mavericks4110300.81136614501420WestDallas314990.02.570
2Sacramento Kings4110100.72192810751393WestSacremento343950.01.511
3Miami Heat4110010.80540013501569EastMiami-Dade389000.02.710
4Toronto Raptors4110010.81305011251600EastYork-County390000.01.100
\n", "
" ], "text/plain": [ " TEAM GMS PCT_ATTENDANCE WINNING_SEASON \\\n", "0 Chicago Bulls 41 104 1 \n", "1 Dallas Mavericks 41 103 0 \n", "2 Sacramento Kings 41 101 0 \n", "3 Miami Heat 41 100 1 \n", "4 Toronto Raptors 41 100 1 \n", "\n", " TOTAL_ATTENDANCE_MILLIONS VALUE_MILLIONS ELO CONF COUNTY \\\n", "0 0.888882 2500 1519 East Cook \n", "1 0.811366 1450 1420 West Dallas \n", "2 0.721928 1075 1393 West Sacremento \n", "3 0.805400 1350 1569 East Miami-Dade \n", "4 0.813050 1125 1600 East York-County \n", "\n", " MEDIAN_HOME_PRICE_COUNTY_MILLIONS COUNTY_POPULATION_MILLIONS cluster \n", "0 269900.0 5.20 0 \n", "1 314990.0 2.57 0 \n", "2 343950.0 1.51 1 \n", "3 389000.0 2.71 0 \n", "4 390000.0 1.10 0 " ] }, "metadata": { "tags": [] }, "execution_count": 34 } ] }, { "metadata": { "id": "ai4FT_VEgZ7o", "colab_type": "code", "outputId": "7d1d82cd-ec78-4eba-e7e9-ae868c32baaa", "colab": { "base_uri": "https://localhost:8080/", "height": 376 } }, "cell_type": "code", "source": [ "import matplotlib.pyplot as plt\n", "distortions = []\n", "for i in range(1, 11):\n", " km = KMeans(n_clusters=i,\n", " init='k-means++',\n", " n_init=10,\n", " max_iter=300,\n", " random_state=0)\n", " km.fit(scaler.transform(numerical_df))\n", " distortions.append(km.inertia_)\n", " \n", "plt.plot(range(1,11), distortions, marker='o')\n", "plt.xlabel('Number of clusters')\n", "plt.ylabel('Distortion')\n", "plt.title(\"Team Valuation Elbow Method Cluster Analysis\")\n", "plt.show()" ], "execution_count": 0, "outputs": [ { "output_type": "display_data", "data": { "image/png": "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\nb03CywvC4OxgJ3ZZRETUhloM52nTpiE8PBxPPPEEFi5caNoulUrRo0cPsxdHTeumdcO0EQHYHHcB\n63ecxcPT+kAikYhdFhERtZEbjtbWaDQYMWJEs13YN3J9qFPbmRLhj1PnC3E4KR8DeqgQ0YfrPxMR\n2YpWPeecmpqK9PR0c9dCN0HTtHKvAAAgAElEQVQmleL/pvaGvUKGr3aeRUFJldglERFRG2nVc85n\nz57F5MmT4eHhATs7OwiCAIlEgtjYWDOXRy3xVjph9vie+GJbMj7fkoQl9w2EVMrubSKi9q5V4bxq\n1Spz10G3aEQ/X5w8V4ijKTrEHL6EyUP9xS6JiIhuU6vC2cfHB7/88gsSExMBACEhIZg6dapZC6PW\nkUgkmBcVhHPZJfhp33n0CfCEvw+fdyQias9adc/5lVdewW+//YauXbsiICAA27dvN80eRuJzdVJg\nweReMNYJ+OyX07hcaxS7JCIiug2tunJOTU3FV199Zfp6zpw5mD17ttmKopvXt5sXxg/qjF+PZmLT\nnjT8bWLgjXciIiKr1Kor59raWtTVXZvL2Wg0wmjk1Zm1uWdMd2hVztidkImTaYVil0NERLeoVVfO\no0ePxj333IMhQ4YAAA4dOoTJkyebtTC6eQo7GR66szeWfRmPL7Yl4aUFYXBzUohdFhER3SSJIAhC\na9547NgxnDx5EhKJBCEhIejfv3+bFsJ5Ydtu3tbth9KxcU8aBvZU4d8z+nH2sD/hPMSWw7a2DLaz\nZVhybu1WdWsvXboUAwcOxP3334958+ahf//+WLBgQZsVSG0rcogfgv08cCy1AHEnc8Quh4iIbtIt\nLXxRW1vb4sIXJC6pVIIFU3rj+bWH8c2vqQjy84BG6SR2WURE1Epc+MJGebk7YG5kID6LPoPVv5zB\n03NCIZO2qqOEiIhEdsOf1hqNBmvWrIGfnx/CwsLg5uaGzMxM2NvbW6I+ug1De/tgaG8NzmeXYssf\nnBudiKi9aNWl1NNPP43jx48jLy8PCxcuREpKCpYuXWru2qgNzJkYCE83e/yy/yLSskrELoeIiFqh\nVeGcl5eHqKgobNu2DbNnz8aSJUtQUsIf9O2Bk4MdHpzSG4IgYPUvZ1BdYxC7JCIiuoFWhXNNTQ0E\nQcCuXbswZswYAEBlZaU566I2FOyvRFS4H/KLq/Dt7lSxyyEiohtoVTiHhYVh0KBBUKvV6Nq1K9at\n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\nAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "DKHT-auXt8j5", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## 3.3 Summary Statistics" ] }, { "metadata": { "id": "-DvJ7AqwuDSl", "colab_type": "text" }, "cell_type": "markdown", "source": [ "#### Used to Describe Data" ] }, { "metadata": { "id": "DHOCDUe67gBH", "colab_type": "code", "outputId": "01e04a16-368d-42ff-c3b1-711beb98b8e2", "colab": { "base_uri": "https://localhost:8080/", "height": 102 } }, "cell_type": "code", "source": [ "numerical_df.median()" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "TOTAL_ATTENDANCE_MILLIONS 0.724902\n", "ELO 1510.500000\n", "VALUE_MILLIONS 1062.500000\n", "MEDIAN_HOME_PRICE_COUNTY_MILLIONS 324199.000000\n", "dtype: float64" ] }, "metadata": { "tags": [] }, "execution_count": 36 } ] }, { "metadata": { "id": "OfAoBl-f7wXY", "colab_type": "code", "outputId": "efe31df1-d2be-415f-fe0c-55651c8d4a66", "colab": { "base_uri": "https://localhost:8080/", "height": 102 } }, "cell_type": "code", "source": [ "\n", "numerical_df.max()" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "TOTAL_ATTENDANCE_MILLIONS 0.889\n", "ELO 1770.000\n", "VALUE_MILLIONS 3300.000\n", "MEDIAN_HOME_PRICE_COUNTY_MILLIONS 1725000.000\n", "dtype: float64" ] }, "metadata": { "tags": [] }, "execution_count": 40 } ] }, { "metadata": { "id": "RGt4MVnln4Cf", "colab_type": "code", "outputId": "2abebd3e-890b-41d5-9e1a-4d6b866cea11", "colab": { "base_uri": "https://localhost:8080/", "height": 297 } }, "cell_type": "code", "source": [ "numerical_df.describe()" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TOTAL_ATTENDANCE_MILLIONSELOVALUE_MILLIONSMEDIAN_HOME_PRICE_COUNTY_MILLIONS
count30.00030.00030.00030.000
mean0.7331504.8331355.333407471.133
std0.073106.843709.614301904.127
min0.6061338.000750.000129900.000
25%0.6791425.250886.250271038.750
50%0.7251510.5001062.500324199.000
75%0.8011582.5001600.000465425.000
max0.8891770.0003300.0001725000.000
\n", "
" ], "text/plain": [ " TOTAL_ATTENDANCE_MILLIONS ELO VALUE_MILLIONS \\\n", "count 30.000 30.000 30.000 \n", "mean 0.733 1504.833 1355.333 \n", "std 0.073 106.843 709.614 \n", "min 0.606 1338.000 750.000 \n", "25% 0.679 1425.250 886.250 \n", "50% 0.725 1510.500 1062.500 \n", "75% 0.801 1582.500 1600.000 \n", "max 0.889 1770.000 3300.000 \n", "\n", " MEDIAN_HOME_PRICE_COUNTY_MILLIONS \n", "count 30.000 \n", "mean 407471.133 \n", "std 301904.127 \n", "min 129900.000 \n", "25% 271038.750 \n", "50% 324199.000 \n", "75% 465425.000 \n", "max 1725000.000 " ] }, "metadata": { "tags": [] }, "execution_count": 41 } ] }, { "metadata": { "id": "5bhFnJMkuBQm", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## 3.4 Implement Heatmap" ] }, { "metadata": { "id": "wmoYSPBiuBTi", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Used to compare Features" ] }, { "metadata": { "id": "1wWY2LgZmUbM", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "!pip -q install -U yellowbrick" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "weG-V888l02_", "colab_type": "code", "outputId": "0a98fea8-64f3-47ed-9f11-cab73b6d2ab8", "colab": { "base_uri": "https://localhost:8080/", "height": 564 } }, "cell_type": "code", "source": [ "from yellowbrick.features import Rank2D\n", "\n", "visualizer = Rank2D(algorithm=\"pearson\")\n", "visualizer.fit_transform(numerical_df)\n", "visualizer.poof()" ], "execution_count": 0, "outputs": [ { "output_type": "display_data", "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlkAAAIjCAYAAAAwQQ7gAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzs3XlYVeX6//H33hvRFCcMnD0O5RBm\naha/RNNwAE09TiSYaKWVHefUI/J1OmkOOXRKrVNGmZ5SM6EBcSjDyuGrmScNK80xh1QQFXGADezf\nHx7W1y0zsV26+7yui+tyPWs9a91ru4Cb+3n2sy0Oh8OBiIiIiJQoq9kBiIiIiLgjJVkiIiIiLqAk\nS0RERMQFlGSJiIiIuICSLBEREREXUJIlIiIi4gJKskTkttKoUSM6depEcHAwQUFB9OnTh+3bt5sd\nVqGFh4fTpk0bgoODCQ4OplOnTgwePJgjR478ofMGBgaya9euHO2DBg1i3759f+jchfHll1/Spk0b\npk6dmucxv/zyC35+fuzYsSPX/YGBgTz22GPGaxMcHEy3bt3+UFwfffTRH+ov4koeZgcgInKz5cuX\nU61aNQC+//57XnjhBdavX4+3t7fJkRXO+PHj+etf/2psL1myhIkTJ7Jy5coSv9b7779f4ufMzVdf\nfUXfvn0ZPXp0rvuzsrKYNm0ad999d77nmTt3Lq1atSqRmBITE3nnnXd44oknSuR8IiVNlSwRua09\n+OCD1KlTh//85z/A9YpK9+7d6dChA8888wzJyckAXL16ldGjRxMUFERgYCBz5swxzhEeHs6rr75K\nly5d2L17Nzt37qRXr1507dqVLl26sG7dOgAuXLjAqFGjCAoKomvXrrz99tvGORo1asQnn3xCz549\nadOmDUuXLi30PXTo0IFffvnF2F68eDFBQUF07NiR559/npSUFAAWLlzISy+9xLBhw+jQoQN9+/bl\n7NmzOc63evVqQkJCuHbtmlHhOnHiBG3atGHZsmV0796dtm3bEhcXB0BaWhqjRo2ibdu2PPPMM8yb\nN4+IiIgc583KyuLVV181qkwRERFcuXKF999/nw0bNrBy5UomTZqU6z2uWLGCxo0bU6dOnUK/LjdK\nSUlh/PjxBAUF0aFDB9asWWPs27RpE927dycoKIjevXvz888/AxAaGsqpU6cIDg4mPT2dRo0acfr0\naaNf9vaOHTsIDQ1l1KhRjB07Fsj7OTpw4AD9+vXj8ccfp3Pnzvz73/8u1v2IgJIsEbkDZGRk4Onp\nyfHjx/n73//O/Pnz2bRpE/7+/kybNg24/kv+8uXLrF+/npiYGKKjo52G1xISEli7di0tW7Zkzpw5\nTJw4kbi4ON58802+/PJLABYsWEDFihXZsGEDH374IStWrHA6x8GDB/nkk0944403WLBgAZmZmYWK\nfdWqVbRo0cKI44MPPmDNmjVs3LiR9PR0p1/k69evJzIyki+//JIqVao4JRsAu3btYsmSJbz55puU\nKVPGad/58+exWq18/vnnREZG8s9//hO4npSdPXuW+Ph4pk+fTnR0dK6xrlu3jm+++Ybo6GjWrl1L\nSkoKS5cuZdCgQXTq1ImBAwcyY8aMHP0SExNZtmwZL774YoGvR15mz56N1Wpl3bp1rF69moULF3Lg\nwAEyMjKIiIhg+vTpbNiwwSmBnjlzJtWrV2f9+vV4enrme/6ffvqJ0NBQ5s+fn+9ztGjRIkJDQ1m7\ndi0rV65k27ZtpKenF/u+5M9NSZaI3Na+/vprkpKSaNmyJd988w0PP/wwDRs2BK5XMr766isyMzN5\n5plneOONN7BYLFSsWJF7772XEydOGOdp164dVuv1H3lVqlThk08+4dChQ9StW5f58+cb1+rfvz8A\nlSpVolOnTmzdutU4R/YQoJ+fH2lpaZw7dy7XmOfOnWvMKWvevDkpKSnGNZo2bcrmzZvx8vLCarXS\nokULjh8/bvRt1aoVNWvWxGKx0KRJE37//Xdj3++//87EiRNZuHBhrsNyGRkZ9O7d24jx1KlTwPXE\nLCgoCA8PD2rWrEm7du1yjXvz5s307NmTsmXLYrPZ6N27t9P952XmzJkMGzaMChUqFHjs+PHjneZk\nPfvsswDEx8czcOBArFYr3t7edOrUiY0bN+Lh4cG2bdto3ry58frc+HoVVpkyZXjkkUcA8n2OqlSp\nwoYNG9i3bx+VK1fmjTfeKDCBE8mL5mSJyG0nPDwcm82Gw+GgZs2aLFmyhHLlynHp0iV27dpFcHCw\ncayXlxcXLlzg0qVLzJ49m8OHD2O1Wjl9+rSRcABUrFjR+PfMmTN58803efrppylTpgwvvvgiwcHB\nJCcnOyUKFSpUcBquK1++PAA2mw24PryWmxvnZIWGhtKyZUtjPtnVq1eZNWuWMTn84sWLtG/fPsc1\nsq9zY7Vs5syZWK1WqlSpkut1bTYbZcuWBcBqtRrxpaSkUKlSJeO4qlWrOg2rZUtOTnZ6nSpWrJhn\nIpnt22+/5cKFC/To0SPf47LlNSfr0qVLjB492nht09LSjP/n5cuXExMTQ3p6Ounp6VgslkJd60Y3\n3ld+z9G4ceN46623GD16NGlpaTz//PM8+eSTRb6eCCjJEpHb0I0T32/k6+tL69atef3113PsGz9+\nPH5+fixevBibzUZoaGie57/77ruZPHkykydPZsuWLYwYMYK2bdty9913c+HCBWrUqAFcn6NV0ETu\ngowZM4Zx48bRrVs37rrrLt5//32OHj1KdHQ05cqV49VXX+XMmTOFOtf48eM5cuQIU6ZM4Y033ih0\nDF5eXly+fNnYTkxMzPW47PvPVpj7/+KLL/jpp58ICAgArieNI0aMIDIykp49exY6Rl9fXxYvXmxU\nl7Lt3r2bJUuWsHr1amrVqsXWrVuZPHlyruewWq1GUnrx4sV8r5XXcwTw4osv8uKLL7J3716effZZ\nWrduTb169Qp9LyLZNFwoIneMNm3asGvXLmO4aO/evcYcoXPnztGkSRNsNhtbt27l2LFjXLlyJcc5\n7HY74eHhRoXKz88PDw8PrFYr7du3Z9WqVcD1qs4XX3zhVGUqDn9/f+69916ioqKMOOvXr0+5cuU4\nefIkX3/9da5x5qZOnTqMGDGC3377jZiYmELHcP/997Nx40aysrL4/fff+eabb3I9rn379nz22Wdc\nvXqVjIwMPv744zyHFrO99NJL7Nixg61bt7J161ZatGjBwoULi5RgwfXlHbLffZmRkcHMmTPZt28f\nycnJVKlShRo1anD16lViYmK4cuUKDocDDw8Prly5QkZGBgA+Pj7GGwzWrFljDA/fLL/naOjQofz6\n668ANGzYEC8vr2JVzkRAlSwRuYP4+voyffp0hg0bht1up1y5ckRGRgLwwgsvMGvWLN544w06dOjA\n8OHDef3112nSpInTOUqVKkXfvn156qmngOvVj0mTJnHXXXcxevRopk2bRnBwMFarleeee45mzZr9\n4bjHjBnDwIED6devH6GhoYwcOZKgoCAaNWpEREQEI0aMKPS7FT09PZk9ezZDhgwx5hgVJCwsjO++\n+46OHTvSsGFDHn/88VwrPcHBwezfv5/evXvjcDjw9/dn4MCBRbnVYhs9ejT/+Mc/CAoKAqBt27Y0\n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\nV5IlIpKP4k5gL66AgADWr19P27ZtiY+Px9/fP8cx//M//8O0adPw8/Mz2pYsWUL16tXp1q0bBw4c\nwNvbO88EC5RkST68vLxo1KgRb731ljFUuHbtWpYuXUqjRo0A+O6773j11VfzTLKaNWvG7NmzjWrX\n0aNHOXHiBPfee+8fii0oKIi+ffvSt2/fP3Se3ISFhTFo0CACAwOpU6cOdrud2bNnM2jQoBzHDh06\nlAEDBnDXXXcBEBkZib+/v/FX0+nTp0t0Ur6IiDvKusULvnft2pVt27YRFhaGp6cns2fPBuDtt9/m\noYceolKlSuzatYvXX3/d6PPUU0/RvXt3xo8fz8qVK8nIyODll1/O9zpKsiRf3bt35+9//zvz5s3j\nl19+wdPT00iwAFq1asW5c+f4/fffAXj22WeNrL5bt27069ePyZMnM3z4cGw2Gx4eHsydO9coy948\nXAjXH+QOHTrkG1ft2rWpVasWQUFB+R4XFxfntBRFVFQUABMnTqRs2bIA+Pv7G5U5uD7/at68eYwf\nPx6Hw0F6ejo9evRwOiZbxYoV+etf/2os8RAZGcmUKVOIjo7G09MTDw8Ppk2blm+MIiJ/dpm3OMvK\nXhvrZs8995zx7z179uTatyijLxZHXrO9ROSWSEtLIyEhAe+497FduWR2OLe1ahNyrnsmefOs5Gt2\nCOJGsn9WNW3alNKlS5foudf9cqbYfbs0rlqCkZQsVbLktrN3717mzp2bo71Lly7079/fhIhERMSV\nMt203KMkS247zZo1K9ZkeBERuTPd6sVIbxWtkyUiIiLiAqpkiYiIiKlu9cT3W0VJloiIiJjKXYcL\nlWSJiIiIqTTxXURERMQFVMkSERERcYEszckSERERKXnuOlyoJRxEREREXECVLBERETGV5mSJiIiI\nuECmkiwRERGRkqeJ7yIiIiIu4K4T35VkiYiIiKk0J0tERETEBdx1TpaWcBARERFxAVWyRERExFSZ\nmvguIiIiUvKUZImIiIi4gJIsERERERdQkiUiIiLiAkqyRERERFzAXZMsLeEgIiIi4gKqZImIiIip\n3LWSpSRLRERETKUkS0RERMQFlGSJiIiIuMCtTrLsdjsRERGcOnUKm83GrFmzqF27ttMxfn5+tGzZ\n0theunQpWVlZBfa7kZIsERERMVXGLU6yYmNjqVChAvPnz2fLli3Mnz+ff/7zn07HeHl5sXz5cqe2\n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\n5pVXXuHjjz926vNH5mTdLHtOVnx8PB999BG+vr5O+8uXL09GRgZJSUncfffdRvu+ffuMqldR5mTV\nr1/fmFeULT09naNHj1KrVi2OHDlCenq608P2yy+/0LFjR7y9vXP8vyQnJ9OoUSOnti5duvD+++8b\n1cHCqF27NpUrVy708Z07d2bIkCH89ttvhISE8NtvvxW6b0Hq16/PokWLcrT//PPP9O7dm4sXLxpt\nuT2X165do1atWoSFhREWFkZ4eDh79+79Q8+uiIiUnICAANavX0/btm2Jj4/P9U1ScP1dho0bNza2\nZ8yYQXBwMK1atWLnzp3ce++9+V6n0LO4PD09eeihh1izZg2BgYGF7Wa4fPkyL7/8Ms8//7xT+969\neylXrhzr16/n008/5fPPP6dLly5OlRm4Pnm6Zs2aTu9ILKqAgABOnDjB119/bbQtXbqUBx98kEqV\nKhltzZo14+TJk2RkZFC9evViX68oHnvsMdLT09m8eXOOfU8++SSzZs0yhlm///57IiIich0/LkhA\nQAAnT540hmSzsrKYO3cucXFxeHl58dhjjzklGLt37+ann36iffv21K1bl9OnTxvzxpKTk9mxY0eu\nc6iKOsRbVD4+PlSoUIGEhIQC53AVVf369fHx8WHlypVG24YNG7DZbE7fbJDzudy2bRvPPfccdrsd\ngLS0NFJSUqhRo0aJxigi4k5u9Zysrl27kpWVRVhYGB988AFjx44F4O233+Y///mPcVxKSorTG7lC\nQkKYN28eAwYM4J133uF//ud/8r1OkWZOBwcHk5ycTPny5Z3abx4ubNCgAdOmTQOuD63B9blFffr0\noUuXLk59Y2Nj6d27t1Nbnz59WLx4sdMEbIBRo0blqKIVhdVqJSoqiqlTp/Laa6/hcDho2rQpkyZN\nynFsmzZtqFKlSq7nuXm4sFu3bvTr16/YcWWbOHEiw4YNc5qYDzBkyBD+9a9/0atXLypWrEj58uV5\n8803KV26NJBzuLBixYq5VmLg/16DKVOmsGjRIjw9PWndujXDhw8HIDIykvnz59OjRw88PT3x9vbm\ntddew2azYbPZmDdvHpMnT8bhcOBwOJg0aZJThS2bv79/ru0lKTg4mIMHD+b7jo/U1FRjuBgw3pEY\nFxdHQkKC0X7zZP1XX32VGTNmsGrVKiwWC3Xq1MmzLHzjc9m6dWv27dtHWFgYd911F3a7nUGDBlGr\n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\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "ZHWg-dccuBWY", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## 3.5 PCA (Principle Component Analysis)" ] }, { "metadata": { "id": "SnwQx2ZVuBif", "colab_type": "text" }, "cell_type": "markdown", "source": [ "Reduce Dimensions\n", "\n", "* AWS Sagemaker has capabilities\n", "* Deep Learning AMIs can create custom Solution\n", "\n" ] }, { "metadata": { "id": "0j1oxFY9d6hZ", "colab_type": "text" }, "cell_type": "markdown", "source": [ "#### Use PCA with sklearn\n", "\n", "References:\n", "\n", "\n", "\n", "1. [ PCA sklearn](http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html)\n", "\n", "\n", "\n" ] }, { "metadata": { "id": "io-MtBQRd_qK", "colab_type": "code", "outputId": "4b8eb757-f518-4a2f-cdaa-2e46e066c3f2", "colab": { "base_uri": "https://localhost:8080/", "height": 51 } }, "cell_type": "code", "source": [ "import pandas as pd\n", "from sklearn.decomposition import PCA\n", "pca = PCA(n_components=2)\n", "pca.fit(numerical_df)\n", "X = pca.transform(numerical_df)\n", "print(f\"Before PCA Reduction{numerical_df.shape}\")\n", "print(f\"After PCA Reduction {X.shape}\")" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Before PCA Reduction(30, 4)\n", "After PCA Reduction (30, 2)\n" ], "name": "stdout" } ] }, { "metadata": { "id": "w5sxCSV3dGvO", "colab_type": "text" }, "cell_type": "markdown", "source": [ "##### Simple Scatter Plot of Reduced Dimensions" ] }, { "metadata": { "id": "YygzH0jzb1GX", "colab_type": "code", "outputId": "7f8e0f29-d4b8-40eb-8fc1-1e891ffb1e41", "colab": { "base_uri": "https://localhost:8080/", "height": 347 } }, "cell_type": "code", "source": [ "plt.scatter(X[:, 0], X[:, 1])\n", "plt.show()\n" ], "execution_count": 0, "outputs": [ { "output_type": "display_data", "data": { "image/png": "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\nrCeffNKyrJv7LgPthRdesB5++GHrd7/7XdjWcvHiReu+++6zLl26ZFVUVFjr168P21r27t1rbdu2\nzbIsy/ryyy+tWbNmhdW/dbfbbeXm5lrr16+39u7da1mWFfTv4nq/g0DUsmrVKuuPf/yjZVmWtW/f\nPmvz5s1hUUswdOuh76ysLK1du1aS5HQ6VVtbq6amJp07d8771+/06dNVVFSk4uJiZWZmyuFwyOl0\nasCAATp9+rSKioo0c+bMa95bXl6u733ve+rXr5+ioqI0bdo0FRUVqaioSPfee68kKT09XV999ZUu\nX74c9LpN6ce3jR8/Xi+99JIkKTk5WQ0NDSouLtY999wj6Zvf7fHjxzVixAglJSUpLi5OY8eOVWlp\n6TXfw+TJk1VaWnrT32Ugffrppzp9+rTuvvtuSQrbWoqKijRp0iQlJiYqNTVVzz77bNjW0rNnT9XW\n1kqS6urqlJKSElb/1h0Oh3bu3KnU1FRvW7C/C1+/g0DVsmHDBs2aNUvSN99VONQSDN06qGNiYhQb\nGytJ2rNnjx588EHV1NQoOTnZ+55evXqpqqpK1dXVcjqd3nan09mmvVevXqqsrFRVVdV139uzZ882\n7cFmSj++LTo6WgkJCZKkgoIC3XXXXWpoaJDD4ZB0c99DVFSUbDabqqurb+q7DKTNmzdrzZo13tfh\nWsvnn3+uK1eu6PHHH9eCBQtUVFQUtrU88MAD+uKLLzRz5kzl5uZq1apVYfVv3W63Ky4u7pq2YH8X\nvn4HgaolISFB0dHRamlp0Ztvvqm5c+eGRS3B0G2uUefn5ys/P/+atmXLlikzM1NvvPGGPv74Y+3Y\nsUMXL1685j3WdZ4H46v9eu+9npt9f1cxpR+S9Kc//UkFBQX6zW9+o/vuu8/bfjPfw/Xab/Yz/PWH\nP/xBo0eP1qBBg25qfybWIkm1tbV65ZVX9MUXX+ixxx67Zh/hVMvbb7+t/v37a/fu3Tp58qSWLFly\nzeMaw/3ferC/i66o6epcoYkTJ2rSpEk6ePBgwPsXrFoCqdsEdXZ2trKzs9u05+fn67333tOvf/1r\nxcTEeIfAr6qoqFBqaqpSU1P12Wef+WyvqqpSUlLSNW3V1dVt3hsTE3NNe2Vlpfr06dNFFV/fd/sX\nqn5817Fjx7Rjxw7t2rVLSUlJSkhI0JUrVxQXF3fd321lZaVGjx7t/R6GDx+u5uZmWZalPn363NR3\nGShHjx5VeXm5jh49qi+//FIOhyNsa+nVq5fGjBkju92utLQ09ejRQ9HR0WFZS2lpqaZOnSpJGj58\nuBobG+XxeDrcDxP/rQf7/1e+fgeBtHbtWt16661aunSpJN/HqnCpJZC69dB3eXm59u/fr1deecU7\nBB4TE6Pbb79dH330kSTp3XffVWZmpiZOnKijR4+qqalJFRUVqqys1ODBgzVlyhQdPnz4mvcOHDhQ\nly9f1ueffy6Px6P3339fU6ZM0ZQpU3TkyBFJ0scff6zU1FQlJiYGvW5T+vFtly5d0pYtW/Taa695\nZ15OnjzZ28+rv9tRo0bpxIkTqqurk9vtVmlpqcaNG3fN9/D+++9rwoQJN/1dBsqvfvUr/e53v9O/\n/du/KTs7W0888UTY1jJ16lT95S9/UWtrq2pqalRfXx+2tdx66606fvy4JOncuXPq0aOH0tPTw/rf\nerC/C1+/g0ApLCxUTEyMli9f7m0L11oCrVs/6/uFF17QH//4R/Xv39/btnv3bp09e1Y///nP1dra\nqlGjRnknnO3du1cHDx6UzWbTU089pUmTJsntdmvlypWqra1VcnKytm7dqqSkJP31r3/Vtm3bJEn3\n3XefFi9eLEnatm2bPvroI9lsNm3YsEHDhw8PfuEG9eOqAwcO6OWXX9Y//dM/eduee+45rV+/Xo2N\njerfv782bdqkmJgYHT58WLt375bNZlNubq6ysrLU0tKi9evX68yZM3I4HHruuefUr18/nT59usPf\nZVd4+eWXNWDAAE2dOlWrV68Oy1r279+vgoICSdJPf/pTjRgxIixrcbvdWrdunS5cuCCPx6Mnn3xS\nffr0CZt/62VlZdq8ebPOnTsnu92uvn37atu2bVqzZk3Qvovr/Q4CUcuFCxcUGxvr/YMmPT1deXl5\nxtcSDN06qAEAMF23HvoGAMB0BDUAAAYjqAEAMBhBDQCAwQhqAAAMRlADAGAwghoAAIMR1AAAGOz/\nAc/EnKgrmozYAAAAAElFTkSuQmCC\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "LZxHsQY8vYvR", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "orMnUf4-ufMe", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## 3.6 Data Distributions" ] }, { "metadata": { "id": "RAyzNcpoufPb", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Used to show shape and distribution" ] }, { "metadata": { "id": "hJqcMHtuo8-z", "colab_type": "text" }, "cell_type": "markdown", "source": [ "* What is the skew of the data?\n", "* What modeling should acccount for this?" ] }, { "metadata": { "id": "n10MIGGVoAez", "colab_type": "code", "outputId": "f2f35481-c2ba-4013-fb32-cc62f14a6c3a", "colab": { "base_uri": "https://localhost:8080/", "height": 446 } }, "cell_type": "code", "source": [ "import seaborn as sns\n", "sns.boxplot(numerical_df['MEDIAN_HOME_PRICE_COUNTY_MILLIONS'])" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "/usr/local/lib/python3.6/dist-packages/seaborn/categorical.py:454: FutureWarning:\n", "\n", "remove_na is deprecated and is a private function. Do not use.\n", "\n" ], "name": "stderr" }, { "output_type": "execute_result", "data": { "text/plain": [ "" ] }, "metadata": { "tags": [] }, "execution_count": 47 }, { "output_type": "display_data", "data": { "image/png": "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\nGKGXX37ZXseCBQs0YsQIhYWF6ZtvvqmTOWRmZiogIECJiYmSZPy5qO4xqKu5jBkzRuHh4RozZoxy\nc3Oddi7lduzYoc6dO9s/O+Ncysc3bNgwPfHEEzp9+rRTzOXieezatUsjR45URESExo8fb8+jvrb1\n6rbNS7IaQGpqqhUZGWlZlmWdPHnSeuCBB6zo6Gjrww8/tCzLsl566SXr7bfftgoKCqxBgwZZeXl5\n1tmzZ63Bgwdbv/zyi5WcnGzNnTvXsizL2rFjhzV58mTLsiwrPDzc2rt3r2VZlvXMM89Y27dvt376\n6ScrJCTEKioqsk6cOGEFBgZaJSUldT6npUuXWqGhodb69euddi4nT560Bg0aZOXn51vZ2dlWTEyM\n084lISHBio2NtSzLso4fP24FBgbWahzx8fHWqlWrLMuyrHfffddasmSJZVmWFRQUZB07dsw6f/68\nNXLkSOvAgQNWWlqaNW7cOMuyLCsrK8t6/PHHr3r8BQUFVnh4uBUTE2MlJCRYlmUZfy6qewzqYi7T\np0+3tmzZYlmWZSUmJlqLFy922rlYlmUVFhZa4eHhVt++fe3rOeNcEhMTrXnz5tnrTklJafRzqWoe\nISEh1sGDBy3LsqxXXnnFWrlyZb1u61Vtm5fTIO987777bi1fvlyS5OPjo7NnzyotLU0DBw6UJD34\n4INKTU3V3r171b17dzVt2lSenp7q2bOnMjIylJqaqocffliSdP/99ysjI0PFxcU6evSofve731VY\nR1pamvr37y93d3e1aNFC7du3V1ZWVp3O5+DBg8rKytLvf/97SXLauaSmpqpPnz668cYb5efnp3nz\n5jntXJo3b26/gs3Ly1OzZs1qNY4L51J+3cOHD8vX11ft2rVTkyZN9MADDyg1NVWpqakKCAiQJHXq\n1EmnT5/Wr7/+elXjd3d316pVq+Tn52cvM/1cVPUY1NVc5syZo8DAQEn//1w561wk6dVXX9WoUaPk\n7u4uSU47l08//VTBwcGSpBEjRmjgwIGNfi5VzePC7f/06dNq3rx5vW7rVW2bl9Mg8XVxcZGXl5ck\nKSkpSQMGDNDZs2ftX9yWLVsqNzdXP//8s1q0aGHfrkWLFpWWN2nSRA6HQz///LN8fHzs615uHXVp\n8eLFio6Otn921rkcOXJEhYWF+vOf/6xRo0YpNTXVaecyePBgHTt2TA8//LDCw8M1ffr0Wo3jwuUt\nW7ZUTk6OcnNzq71u8+bN63Qurq6u8vT0rLDM9HNR1WNQV3Px8vKSi4uLzp8/r7Vr12rIkCFOO5cf\nf/xR33//vYKCguxlzjqXo0eP6vPPP1dERISmTJmiU6dONfq5VDWPmTNnauLEiQoMDNTu3bsVEhJS\nr9t6Vdvm5TToB65SUlKUlJSk2bNnV1huVfO9H7VZXtt1XKmNGzeqR48e6tChQ63urzHORZJOnTql\nFStWaNGiRZoxY0aF+3CmuWzatEk33XSTPvnkE7311luaNm3aFY+jtmOrj+elpvdRX89Ffczp/Pnz\nmj59uu677z716dOnXsZnYi4LFy7UjBkzLnkdZ5mLZVm67bbblJCQoN/+9rdauXJlvYyvvucyb948\nrVixQtu2bVOvXr20du3aehnD1ayjweK7Y8cOvfrqq1q1apWaNm0qLy8vFRYWSpKys7Pl5+cnPz8/\n/fzzz/ZtcnJy7OXlryzOnTsny7LUunXrCgfrq1tH+fK6sn37dv3zn//U448/rvfff19/+9vfnHYu\nLVu21F133SVXV1fdcsst8vb2lre3t1POJSMjQ/369ZMkdenSRUVFRfrll19qPI4L51KT6178eLRu\n3brO5lLO9O9VVY9BXZoxY4Y6duyoSZMmSZJTziU7O1uHDh3S1KlT9fjjjysnJ0fh4eFOORdJatWq\nle6++25JUr9+/ZSVleWUc/nhhx/Uq1cvSWW7xPfv31+v23pV2+blNEh88/PztWTJEq1cuVLNmjWT\nVPYAbdu2TZL08ccfq3///rrzzju1b98+5eXlqaCgQBkZGerdu7f69u2rrVu3Sio7RnHvvffKzc1N\nt99+u9LT0yus47777tP27dtVXFys7Oxs5eTk6De/+U2dzWXZsmVav3691q1bp+HDh2vChAlOO5d+\n/frpyy+/VGlpqX755RedOXPGaefSsWNH7d27V1LZrjRvb2916tSpxuO4cC7l17355pv166+/6siR\nIyopKdGnn36qvn37qm/fvvZj9O2338rPz0833nhjnc2lnOnnoqrHoK5s3rxZbm5uevrpp+1lzjiX\nNm3aKCUlRevWrdO6devk5+enxMREp5yLJA0YMEA7duyQVPa7fNtttznlXFq1amV/hmTfvn3q2LFj\nvW7rVW2bl9Mg3+383nvvKT4+Xrfddpu9bNGiRYqJiVFRUZFuuukmLVy4UG5ubtq6datWr14th8Oh\n8PBwBQcH6/z584qJidF//vMfubu7a9GiRWrXrp2ysrI0e/ZslZaW6s4777R3BSUkJOiDDz6Qw+HQ\nX/7ylyp3cdWF+Ph4tW/fXv369dNzzz3nlHN59913lZSUJEmKiopS9+7dnXIuBQUFmjlzpk6cOKGS\nkhJNnjxZrVu3rvE4CgoKNG3aNJ06dUo+Pj568cUX1bRpU+3atUuxsbGSpEGDBmns2LGSpNjYWKWn\np8vhcGjOnDnq0qXLVY1///79Wrx4sY4ePSpXV1e1adNGsbGxio6ONvZcVPcY1MVcTpw4IQ8PD/tF\nSqdOnTR37lynnEt8fLz9JuKhhx7Sv/71L0lyyrnExsbqhRdeUG5urry8vLR48WK1atWqUc+lqnlM\nmTJFS5YskZubm3x9fbVgwQL5+PjU27aek5NT5d/JS+HECgAAGMY3XAEAYBjxBQDAMOILAIBhxBcA\nAMOILwAAhhFfAAAMc23oAaBuHTlyRAMHDtTcuXM1cuRIe3l6erpGjx6tv//97/rjH/+ou+++Ww6H\nw768W7duio6OVkREhE6fPi1fX1+VlpbK19dXTz/9tP3vViMiIhQVFaX777/fvu3gwYPVtm1brV69\n2l4WHx+vtWvXatu2bfZ3vaalpWnDhg1atGhRteOPj49XSUmJpkyZYi9LTk7Wzp077X9zt2XLFr35\n5ptyOBwqLCxU165dNX36dLVs2bJG87/33nvVuXPnah+D6kRHR2vPnj3y8/OTZVkqLi5WZGSkBg0a\npLS0NE2YMEFdu3aVVPYVcw6HQ88//7z8/f2VlpamZcuW6Z133pEkffPNN1q6dKny8vLk4uKiVq1a\naebMmerQoYPi4+OVnJysm2++ucL9x8TEVDhl3cVycnK0ZMkSZWZmytvbW5L01FNP2c/Vf//7X734\n4ov66aef5ObmJk9PT02cONG+vKrnNi4uTq6urnrqqacUEREhV1dXvfnmmxWer/bt28vNzU3r1q2T\nJH399dfq0qWLPD091a1bNzVv3lyZmZl66aWX7Ntt3LhR69evV0JCQrXziYiIUFFRkb3ecoMGDVLP\nnj21aNGiCr8v0dHR6tWrl4YPH17h+lX9Tkmq9Jzs379fcXFxOnnypKSy7+195pln1K1bN0ll/4b3\n/vvv1/z58+11REdHKyQkRPfee6+++eYbvfTSSyotLdW5c+fk7e2tefPm6aabbqp2jrh+Ed9r0K23\n3qrk5OQK8UlOTq7wpSZr1qyRq2vVT390dLT9B/iLL75QZGSk3nvvPbVv377Sdb/++msVFRVpz549\nOn78uNq2bWtf1rZtWy1fvlzPP/98XU2twteSlt/X6tWrNWnSJPuPaE3mL136MahOZGSk/cc9JydH\nQ4cOtb+Oz9/fv0JMPvvsM82aNcs+/2m53NxcTZo0ScuXL9ddd90lSfrggw8UGRmpLVu2SJKCg4Mr\nxeJSLMvSxIkTNXToUPtFyg8//KAnn3xS77zzjtq0aaPIyEhNmzZNgwYNsi8fP368Vq9erU6dOtXo\nfk6dOqVt27bZZyQqN2TIEA0ZMkRSWaRiY2PVsWNHSWVfPRgSEqKvvvpK99xzj/Lz87V8+fIKL9aq\nk5eXp6ysLPvbz9LT09WkSd3vsDtx4oQmTJigpUuXqnfv3pKkr776SlFRUdq4caP9Jfv//ve/tW/f\nPnXv3r3SOqZOnaply5bZL8ASEhK0Zs0azZw5s87HC+fHbudrkJ+fnxwOhw4cOCCp7Gw4u3fvtk/z\nVRv9+vXTY489prfffrvKy5OSkhQcHKwHH3xQGzdurHDZqFGjtGvXLn3//fe1n0Q1Xn75ZU2dOrVC\n5MeOHauioiLt3LlTUt3O/1L8/PzUtm1bHTlypMrLe/bsaY/hQomJiQoODrbDK5XFa926dbV+MVAu\nNTVVDodDo0ePtpd17txZH374oW655RZt3LhR3bp1s8NbfvmTTz6pV155pcb389xzzykuLs7+Htua\ncHNz09y5czVv3jyVlJRo+fLlCg0N1e23337Z2wYEBGj9+vX2z8nJyXrooYdqfN819dZbb2nIkCF2\neCXpnnvuUVBQkN566y172axZszR//vwqvzz/4lNJRkREEF5Ui/heox599FH7j9a2bds0YMCAK37H\n0KNHD2VmZlZafubMGX300UcKCQlRaGioNmzYUOFyFxcXzZgxQy+88MIV3W9Vvvvuuyojeuedd+rb\nb7+1f67L+VfnwIEDOnHiRLXvGjds2KAePXpUWp6VlVXlOydfX9+rGsul1lnd49ajRw999913Nb6f\nm2++WUFBQVWe7eZSevfure7du2v27NnauXOnxo8fX6PbBQUFaevWrSopKdHZs2f11Vdf2SfMqEs1\nfXx69uypjh07VnhBUG7GjBmKiopSWFiY4uLiKvw+Ahdjt/M1KigoSCEhIZo6dao2bNigqVOnVnj3\nOmbMmArHO8eMGWOfDPpi+fn5cnFxqbT8o48+Urdu3dShQwe1b99excXFSk9Pr/DuoU+fPnr33Xf1\nwQcf1PiMJZs3b1ZGRob9c25uru644w5J0g033FDtKbsujOvl5l8+55o+BuVef/11bd68WZZlycvL\nS/Hx8fa5qTMzMxURESGp7Byvd911l1588cVK6yg/j+2lXPwY+Pr6asWKFdVe/3Lr9PLyUmlpaZWX\nXe5FyYWPkSSNHz9eQ4cOVWho6CVvd7Fp06Zp4MCBiouLs899ejm+vr7q1q2bPvvsM+Xn52vAgAFV\n/i5erdo8PtOmTdPo0aMr7XofOnSoHn74YaWmpurLL79UZGSkhg0bpmeffbbOxwvnR3yvUS1atFDX\nrl2VlJSk3NzcSu+KanO8MyMjw/7QyYWSkpJ0/PhxPfroo5Kk4uJiJScnV4ivVHYMecyYMZf8MNOF\nLj7eWf6BK6lsV+mePXsqRXLfvn165JFH7J8vN3/p6o/5XuzCY75vvPGGvvvuuypPLejv76+MjIwK\n45WkvXv32u++anvM19/fv9KxZansuG6HDh3UuXNnpaSkVLr8wuOX3t7eFU4HJ5UdC734bFOenp6a\nMmWKFixYYB/frInmzZurWbNmuvXWW2t8G6lsL8amTZtUUFCgSZMmqbi4uFa3rwl/f399/fXXCgoK\nqrC8quO7rVu3VlhYmJYvX15h+dmzZ+Xt7a2AgAAFBAQoPDxcoaGhxBdVYrfzNezRRx9VXFycBg8e\nfMXr+Pzzz5WSkqKwsLAKyw8dOqRDhw5p69at2rRpkzZt2qSkpCR98sknOnPmTIXrtmvXTkOHDtWr\nr756xeMoFxUVpdjYWB07dsxelpiYKB8fH/uDT+XqYv5X6oknntChQ4fsM9xcaNSoUdq6dau+/PJL\ne9mHH36oWbNm6dy5c1d0f/fcc4+8vb312muv2csOHDigqKgoHT9+XI888ogOHDigf/zjH/blBw8e\n1Jo1azRhwgRJUmBgoDZs2GDH7ejRo9q5c2eVewMCAwNVWFioL7744orGWxsPPPCA9u/fr2PHjlU4\nTl6XRo8eXek5ycjI0CeffKInnnii0vUjIiKUlpZmH9M/ePCgAgMDlZOTY1/n8OHD9ofOgIvxzvca\n9tBDD2n27NkKDg6udNnFu1w9PDz0+uuvSyo7vaOvr6/y8/PVsmVLrV69utIu46SkJIWGhsrDw8Ne\n1q5dO/Xu3ds+r+WFxo4dW+UnjmurT58+iomJ0eTJk+VwOFRcXKyuXbsqLi6u0nUvNX/p0o/B1XJx\ncdH8+fM1ceLESnsCWrRoocTERM2bN0+LFy+Wp6en2rdvrzVr1ti7Yy/e7SxJI0eOrPRu+UKvvfaa\nFi5cqD/84Q9q1qyZPDw8tGzZMvuDTWvXrtX8+fO1atUqubm56YYbbtDChQvVoUMHSVJISIhOnjyp\niIgIexwXXn6xmJgYe69HfXJ3d1f//v3VsmXLy163/LBAuTlz5kiq/HhOmDChwu7k5s2bKyEhQfPn\nz9eSJUsklZ0TdsWKFVWe4s7NzU0zZszQn/70J0llp0SMjo7WU089JXd3dzkcDnl4eNifPAcuxikF\nAQAwjHe+MO6vf/2rdu3aVWl5ly5dNGvWrAYY0f+bPXu2fvzxx0rL+/fvr3HjxjXAiP7fnj17tHTp\n0iovW7p0aZXHlxu7qKioCv88p1z5J+iBaxXvfAEAMIwPXAEAYBjxBQDAMOILAIBhxBcAAMOILwAA\nhv0fxWhcj13apdkAAAAASUVORK5CYII=\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "0QhJF_9r_f35", "colab_type": "code", "outputId": "c5e81962-ab9f-4780-b8f4-76da935329b1", "colab": { "base_uri": "https://localhost:8080/", "height": 378 } }, "cell_type": "code", "source": [ "sns.distplot(numerical_df[\"MEDIAN_HOME_PRICE_COUNTY_MILLIONS\"])" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "" ] }, "metadata": { "tags": [] }, "execution_count": 48 }, { "output_type": "display_data", "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "hOHg-qnPuk0-", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## 3.7 Data Normalizations" ] }, { "metadata": { "id": "iTfmGaYluqnD", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Normalize Magnitude of data\n", "\n" ] }, { "metadata": { "id": "ViEg8L1YfaUP", "colab_type": "text" }, "cell_type": "markdown", "source": [ "\n", "\n", "* Used to prepare data for Clustering\n", "* Without it distorted results from magnitude of one variable or column\n", "\n" ] }, { "metadata": { "id": "yjNQuXlqAeyh", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "from sklearn.preprocessing import StandardScaler\n" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "G4jwa33hApxK", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "StandardScaler?" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "ei1Itkf_lgEU", "colab_type": "code", "outputId": "2dfffdca-d2d2-43f3-ee3c-e49edb040f92", "colab": { "base_uri": "https://localhost:8080/", "height": 544 } }, "cell_type": "code", "source": [ "from sklearn.preprocessing import MinMaxScaler\n", "scaler = StandardScaler()\n", "print(scaler.fit(numerical_df))\n", "print(scaler.transform(numerical_df))" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "StandardScaler(copy=True, with_mean=True, with_std=True)\n", "[[ 2.15710914 0.13485945 1.6406603 -0.46346815]\n", " [ 1.08262637 -0.80757014 0.13568652 -0.31156289]\n", " [-0.1571124 -1.0645964 -0.40180411 -0.21399854]\n", " [ 0.99992906 0.610834 -0.00764431 -0.06222804]\n", " [ 1.10596902 0.90593821 -0.33013869 -0.05885911]\n", " [ 0.68401316 1.24863989 0.92400612 0.73284052]\n", " [ 1.52170109 0.38236622 -0.22264057 -0.90951509]\n", " [ 0.97270521 2.52425166 1.78399114 1.17076833]\n", " [ 0.18103723 0.36332724 -0.47346953 -0.66676145]\n", " [ 1.07396297 -1.24546672 2.78730699 4.43866857]\n", " [ 0.38018443 0.78218483 1.2106678 0.30835476]\n", " [ 0.60511389 -1.31210316 2.35731448 0.73284052]\n", " [ 0.81458785 0.55371705 -0.43763682 0.05804292]\n", " [ 0.3061228 1.48662716 -0.25847327 -0.4968206 ]\n", " [ 1.01663209 1.06776956 -0.63829999 -0.18367813]\n", " [-0.07467847 -1.45489552 -0.62396691 -0.36240011]\n", " [-0.97256659 -0.21736171 -0.86762933 -0.37890789]\n", " [-0.51785617 0.9249772 0.4223482 -0.44812265]\n", " [-0.34131697 -1.56912941 -0.3659714 -0.37890789]\n", " [-0.67483689 0.20149589 -0.68129924 -0.88424808]\n", " [-0.77552634 -0.21736171 -0.81029699 -0.85055873]\n", " [-0.31353866 -0.39823203 -0.82463008 -0.34523707]\n", " [-0.31473075 -1.58816839 -0.79596391 -0.76633537]\n", " [-1.09445017 -0.24592018 -0.6741327 -0.14308247]\n", " [-1.39521552 -1.2645057 0.63734445 1.25502538]\n", " [-1.16866427 -0.02697189 -0.81746354 -0.93511899]\n", " [-0.50116701 0.78218483 -0.50930224 0.53390494]\n", " [-1.769793 0.44900265 -0.66696616 0.24097607]\n", " [-1.74736521 -0.39823203 -0.83896316 -0.24951385]\n", " [-1.08287587 -0.60766083 -0.65263307 -0.36209691]]\n" ], "name": "stdout" } ] }, { "metadata": { "id": "0XvFJuRYbtKq", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## 3.8 Data Preprocessing\n" ] }, { "metadata": { "id": "52KaE0sFbyWf", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### Encoding Categorical Variables" ] }, { "metadata": { "id": "s8GCyNTgb281", "colab_type": "text" }, "cell_type": "markdown", "source": [ "* **Categorical (Discreet) Variables**\n", " - finite set of values: `{green, red, blue}` or` {false, true}`\n", "* Categorical Types:\n", " - Ordinal (ordered): `{Large, Medium, Small}`\n", " - Nominal (unordered): `{green, red, blue}`\n", "* Represented as text \n", "\n", " " ] }, { "metadata": { "id": "53py7FaYoZMl", "colab_type": "text" }, "cell_type": "markdown", "source": [ "### [Demo] Pandas preprocessing w/ Apply Function\n" ] }, { "metadata": { "id": "tx6dJ3bCJPnt", "colab_type": "code", "outputId": "7e972758-d1e3-4184-91a6-78b99b88d6df", "colab": { "base_uri": "https://localhost:8080/", "height": 410 } }, "cell_type": "code", "source": [ "import pandas as pd\n", "import seaborn as sns\n", "import matplotlib.pyplot as plt\n", "\n", "df = pd.read_csv(\"https://raw.githubusercontent.com/noahgift/socialpowernba/master/data/nba_2017_players_with_salary_wiki_twitter.csv\")\n", "sns.distplot(df.AGE)\n", "plt.legend()\n", "plt.title(\"NBA Players Ages\")" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "No handles with labels found to put in legend.\n" ], "name": "stderr" }, { "output_type": "execute_result", "data": { "text/plain": [ "Text(0.5,1,'NBA Players Ages')" ] }, "metadata": { "tags": [] }, "execution_count": 54 }, { "output_type": "display_data", "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAecAAAFnCAYAAACcvYGMAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzs3Xl4lOWh/vHvzCSTPSEJmSQkLEkg\nBIJsAQXCvoNbtVZSi9rqqa1yaq3oOZb6q566nONSq6J1ae1qVSoiroCiQRGiQEQgbIFASAJk3/dk\nZn5/IMEokABJ3snM/bkuL5N5Z7nncZw77/a8JqfT6URERERchtnoACIiItKeyllERMTFqJxFRERc\njMpZRETExaicRUREXIzKWURExMWonEUu0NChQ1m2bFm727744guuv/76tp9HjBjB/PnzmT9/PnPn\nzuX//b//R3Nzc7vHVFZWMmnSJO69996zvt7MmTOZMWMG8+fPZ968eVx++eW89957ABQUFDB8+PAu\nfHddIzs7m3HjxvHcc88ZHUWkV1A5i3SBrVu3smfPnjMuj46OZu3ataxdu5Z33nmH3NxcXn755Xb3\neffdd7n++uvJyMigqanprK/32GOPsXbtWtatW8fTTz/N7373Ow4cONAl76U7vPnmm/zyl7/k3Xff\nNTqKSK+gchbpAnfeeScPP/xwp+7r4+PD2LFjyc/Pb3f76tWrueyyy0hNTeWjjz7q9GvHxcUxYcIE\nMjIy2t3ucDj4n//5H+bNm8fMmTO5++67aWlpYcOGDVx22WXt7nv11Vezfv16qqurufvuu5k3bx6z\nZs3ijTfeaLvP0KFDeeGFF5g3bx52u52XX36ZBQsWMH/+fK655poz/nFgt9tZv349V199NVFRUezY\nsaNtWWVlJTfccAPTp0/n9ttv5ze/+Q3Lly8H4ODBgyxevLht68CuXbsAqKurY8mSJSxYsIBZs2Zx\n77330tLS0unxEukNVM4iXWDBggU4nU7Wrl3b4X3LyspIT09nxowZbbcdOHAAb29v+vfvzxVXXMHq\n1avP6fVbW1uxWq3tbvvwww/Ztm0b7777LmvWrGH37t28//77pKamUlJSwr59+wA4duwYeXl5TJ06\nlf/7v//DbDazZs0aXn/9dZYvX052dnbbczqdTtatW0dDQwNPPfUUr7/+OmvXruXmm29mw4YNp822\nceNGRo0aRUBAAJdffnm79/bCCy8QFhbGhg0buOWWW9o2zzscDpYsWcKVV17JunXruP/++7ntttto\nbW1l9erVBAcHs2bNGtatW4fFYuHgwYPnNF4irk7lLNJFli1bxuOPP37aTdLHjx9v20c8ffp0+vfv\nz9ixY9uWv/nmm1xxxRUApKSkkJubS2lpaaded/fu3Wzbto1p06a1u33evHm88cYbeHt74+Pjw0UX\nXUR+fj7e3t7MmzevrQjXr1/PrFmzsFqtpKenc8MNN2A2mwkLC2POnDl88MEHbc85ffp04MTav8lk\nYuXKlZSWlrJgwQJ++tOfnjbfN9/bnDlzSE9Pb9vfvm3btra1+BEjRjBy5EgADh06RFlZGddcc03b\nmISFhbF9+/a2f3/22WdtWweGDRvWqbES6S28jA4g4i6Sk5MZP348f/3rXxkzZky7ZSf3OcOJzbz/\n/Oc/ufHGG3njjTew2+2888471NfX8/vf/x6ApqYm3nnnHX7yk5+c9rXuvvtufHx8cDqdhIeH8+ST\nTxIdHU1BQUHbfcrLy3nggQfYs2cPJpOJ0tJSbrzxRgAuvfRSfv3rX7N06VLWr1/PzTffDEBNTQ13\n3HEHFoulLcf8+fPbnrNPnz4AeHt787e//Y3nn3+e5cuXM3ToUO677z6GDh3aLmdVVRUbNmxg06ZN\nbbc1NjayYcMG5s6dS3V1NSEhIW3LIiMjAaiurqaxsZEFCxa0LautraWyspIFCxZQVVXFU089xaFD\nh7jiiiv49a9//Z0tByK9mcpZpAv96le/4uqrryY2NvaM97FYLKSlpfG///u/lJeXs2vXLhITE3np\npZfa7rNnzx5+/etfn7GcH3vsMcaNG3fWLH/4wx/w8vLinXfewWq1snTp0rZl48ePp7W1lfT0dA4c\nOMCkSZMAsNlsPPvssyQmJnb4XocPH87TTz9Nc3Mzf/7zn7nvvvt47bXX2t3nvffe48orr+R3v/td\n220ffvghb775JnPnziUgIID6+vq2ZSUlJQwYMACbzUZAQMAZdxOkpaWRlpZGUVERv/jFL1i9ejXX\nXntth5lFegtt1hbpQjabjR/96EdtBzWdyfr167HZbAQHB/Pmm28ye/bsdsuHDx9OTU0N+/fvP+8s\nZWVlJCYmYrVa2bdvH9u3b28rQrPZzMKFC3nggQeYOXMm3t7ewInTtE4WbGtrKw8//DC7d+/+znPv\n37+f22+/nebmZqxWKyNGjMBkMn3nfqd7b5MnT2bLli1UVFQwcuTItgLeu3cvO3fuBCAmJoaoqKi2\nZeXl5dx5553U19fz7LPPsnLlSuDEmnZsbOxpX1ukN1M5i3Sxm2666TtHD5/c53xyv/OKFSt48cUX\nqa+vJz09nVmzZn3neWbNmnXOB4Z9O8drr73GggUL+Ne//sV///d/8/rrr7NmzRrgxKbto0ePsnDh\nwrbH3HHHHdTU1DBv3jwuvfRSHA7HdzZVAyQmJhIbG8tll13GpZdeyjPPPMNvfvObdvfJycnh0KFD\nTJgwod3tfn5+XHzxxbz33nvceuutHD58mDlz5vCXv/yFWbNmYTKZMJlMPPHEE/zrX/9i/vz5LF68\nmIkTJ+Lv78+VV17JW2+9xbx585g/fz7e3t5ceeWV5z1OIq7IpOs5i3im0tJSrrrqKjZs2NC2j9kI\nTqezbc339ttvJyUlpW3fuIin0pqziId6+umn+eEPf2hoMb/88svceuutOBwOysrK2LJly3cOphPx\nRCpnEQ9TWlrKrFmzKC0t5aabbjI0y1VXXYXVamXu3Ln88Ic/5Kabbmo7nUrEk2mztoiIiIvRmrOI\niIiLcYnznB0OB3V1dXh7e+uUCBERcXtOp5OWlhYCAgIwm7+7nuwS5VxXV9du/l4RERFPkJiYSFBQ\n0Hdud4lyPjkBwskJE3pSVlYWI0aM6NHXdEUah1M0FqdoLE7QOJyisTjlQsaiubmZ7Ozstv77Npco\n55Obsq1WKz4+Pj3++ka8pivSOJyisThFY3GCxuEUjcUpFzoWZ9qVqwPCREREXIzKWURExMWonEVE\nRFyMyllERMTFqJxFRERcjMpZRETExaicRUREXIzKWURExMWonEVERFyMyllERMTFqJxFRERcjEvM\nrS1ipBcz2l8RLS+vgszmrr9K2i0TE7v8OUXEPWnNWURExMWonEVERFyMyllERMTFqJxFRERcjMpZ\nRETExaicRUREXIzKWURExMWonEVERFyMyllERMTFqJxFRERcjMpZRETExaicRUREXIzKWURExMWo\nnEVERFyMyllERMTFqJxFRERcjMpZRETExaicRUREXIzKWURExMWonEVERFyMyllERMTFqJxFRERc\njMpZRETExaicRUREXIzKWURExMWonEVERFyMyllERMTFeHXmTg8//DA7duzAZDKxbNkyRo4c2bZs\n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\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "ksI44lAFbxic", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "def age_brackets (age):\n", " if age >17 and age <25:\n", " return 'Rookie'\n", " if age >25 and age <30:\n", " return 'Prime'\n", " if age >30 and age <35:\n", " return 'Post Prime'\n", " if age >35 and age <45:\n", " return 'Pre-Retirement'\n", " " ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "Wq_axlRTLc11", "colab_type": "code", "outputId": "6f41b515-07de-4a09-e234-77e70bb475ee", "colab": { "base_uri": "https://localhost:8080/", "height": 136 } }, "cell_type": "code", "source": [ "df.columns" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "Index(['Unnamed: 0', 'Rk', 'PLAYER', 'POSITION', 'AGE', 'MP', 'FG', 'FGA',\n", " 'FG%', '3P', '3PA', '3P%', '2P', '2PA', '2P%', 'eFG%', 'FT', 'FTA',\n", " 'FT%', 'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'POINTS',\n", " 'TEAM', 'GP', 'MPG', 'ORPM', 'DRPM', 'RPM', 'WINS_RPM', 'PIE', 'PACE',\n", " 'W', 'SALARY_MILLIONS', 'PAGEVIEWS', 'TWITTER_FAVORITE_COUNT',\n", " 'TWITTER_RETWEET_COUNT'],\n", " dtype='object')" ] }, "metadata": { "tags": [] }, "execution_count": 56 } ] }, { "metadata": { "id": "MquJliZzJM2g", "colab_type": "code", "outputId": "c57e9d46-f4bd-4b62-ea2b-32b2a73cd00b", "colab": { "base_uri": "https://localhost:8080/", "height": 119 } }, "cell_type": "code", "source": [ "df[\"age_category\"] = df[\"AGE\"].apply(age_brackets)\n", "df.groupby(\"age_category\")[\"SALARY_MILLIONS\"].median()" ], "execution_count": 0, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "age_category\n", "Post Prime 8.550\n", "Pre-Retirement 5.500\n", "Prime 9.515\n", "Rookie 2.940\n", "Name: SALARY_MILLIONS, dtype: float64" ] }, "metadata": { "tags": [] }, "execution_count": 57 } ] }, { "metadata": { "id": "aXI-XtD9LLs8", "colab_type": "code", "colab": {} }, "cell_type": "code", "source": [ "" ], "execution_count": 0, "outputs": [] } ] }