Repository: sunnysavita10/Generative-AI-Indepth-Basic-to-Advance
Branch: main
Commit: 59e7a0a31b08
Files: 86
Total size: 3.0 MB
Directory structure:
gitextract_kzntgr93/
├── Access_APIs_Using_Langchain/
│ ├── LangChain_Complete_Course.ipynb
│ └── requirements.txt
├── Advance RAG Hybrid Search/
│ └── Hybrid_Search_in_RAG.ipynb
├── Advance RAG Reranking from Scratch/
│ └── Reranking_from_Scratch.ipynb
├── Advance RAG with Hybrid Search and Reranker/
│ └── Hybrid_Search_and_reranking_in_RAG.ipynb
├── Chat with Multiple Doc using Astradb and Langchain/
│ └── Chat_With_Multiple_Doc(pdfs,_docs,_txt,_pptx)_using_AstraDB_and_Langchain.ipynb
├── Child_to_Parent_Retrieval.ipynb
├── ConversationEntityMemory.ipynb
├── Conversational_Summary_Memory.ipynb
├── FlashRerankPractical.ipynb
├── Generative AI Dataset/
│ ├── llama3.txt
│ └── state_of_the_union.txt
├── Generative AI Interview Questions/
│ └── Generative_AI_Interview_Questions.docx
├── Google Gemini API with Python/
│ └── GeminiAPI_With_Python.ipynb
├── LCEL(Langchain_Expression_Language).ipynb
├── Langchain_memory_classes.ipynb
├── MergerRetriever_and_LongContextReorder.ipynb
├── MongoDB with Pinecone/
│ ├── Mongodb_with_Pinecone_Realtime_RAG_Pipeline_yt.ipynb
│ └── Mongodb_with_Pinecone_Realtime_RAG_Pipeline_yt_Part2.ipynb
├── MultiModal RAG/
│ ├── Extract_Image,Table,Text_from_Document_MultiModal_Summrizer_AAG_App_YT.ipynb
│ ├── Extract_Image,Table,Text_from_Document_MultiModal_Summrizer_RAG_App.ipynb
│ ├── MultiModal RAG using Vertex AI AstraDB(Cassandra) & Langchain.ipynb
│ ├── MultiModal_RAG_with_llamaIndex_and_LanceDB.ipynb
│ └── Multimodal_RAG_with_Gemini_Langchain_and_Google_AI_Studio_Yt.ipynb
├── MultiModal RAG with Vertex AI/
│ └── MultiModal RAG using Vertex AI AstraDB(Cassandra) & Langchain.ipynb
├── Multilingual AI based Voice Assistant/
│ ├── .gitignore
│ ├── README.md
│ ├── app.py
│ ├── genai_AI_Project.egg-info/
│ │ ├── PKG-INFO
│ │ ├── SOURCES.txt
│ │ ├── dependency_links.txt
│ │ └── top_level.txt
│ ├── multilingual_assistant.egg-info/
│ │ ├── PKG-INFO
│ │ ├── SOURCES.txt
│ │ ├── dependency_links.txt
│ │ ├── requires.txt
│ │ └── top_level.txt
│ ├── requirements.txt
│ ├── research/
│ │ └── trials.ipynb
│ ├── setup.py
│ ├── src/
│ │ ├── __init__.py
│ │ └── helper.py
│ └── template.py
├── QA_With_Doc_Using_LlamaIndex_Gemini/
│ ├── Data/
│ │ └── MLDOC.txt
│ ├── Exception.py
│ ├── Experiments/
│ │ ├── ChatWithDoc.ipynb
│ │ └── storage/
│ │ ├── default__vector_store.json
│ │ ├── docstore.json
│ │ ├── graph_store.json
│ │ ├── image__vector_store.json
│ │ └── index_store.json
│ ├── Logger.py
│ ├── QAWithPDF/
│ │ ├── __init__.py
│ │ ├── data_ingestion.py
│ │ ├── embeddings.py
│ │ └── model_api.py
│ ├── StreamlitApp.py
│ ├── Template.py
│ ├── logs/
│ │ ├── 02_15_2024_16_21_43.log
│ │ ├── 02_15_2024_16_22_49.log
│ │ ├── 02_15_2024_16_23_52.log
│ │ ├── 02_15_2024_16_26_42.log
│ │ ├── 02_15_2024_16_27_41.log
│ │ ├── 02_15_2024_16_45_53.log
│ │ └── 02_15_2024_16_58_10.log
│ ├── requirements.txt
│ ├── setup.py
│ └── storage/
│ ├── default__vector_store.json
│ ├── docstore.json
│ ├── graph_store.json
│ ├── image__vector_store.json
│ └── index_store.json
├── RAG App using Haystack & OpenAI/
│ └── RAG_Application_Using_Haystack_and_OpenAI.ipynb
├── RAG App using LLAMAINDEX & MistralAI/
│ └── RAG_Application_Using_LlamaIndex_and_Mistral_AI.ipynb
├── RAG App using Langchain Mistral Weaviate/
│ └── RAG_Application_Using_LangChain_Mistral_and_Weviate.ipynb
├── RAG App using Langchain OpenAI FAISS/
│ ├── RAG_Application_using_Langchain_OpenAI_API_and_FAISS.ipynb
│ └── state_of_the_union.txt
├── RAG App with Mongo Vector Search & Gemma/
│ └── rag_with_huggingface_and_mongodb.ipynb
├── RAG Pipeline from Scratch/
│ └── RAG_Implementation_from _Scartch.ipynb
├── RAG_Fusion.ipynb
├── RAG_With_Knowledge_graph(Neo4j).ipynb
├── RAG_with_LLAMA3_1.ipynb
├── README.md
├── Roadmap of Generative AI/
│ └── Generative_AI_Roadmap.pptx
├── basic_retrieval_and_contextual_compression_retrieval.ipynb
└── self_query_retrieval.ipynb
================================================
FILE CONTENTS
================================================
================================================
FILE: Access_APIs_Using_Langchain/LangChain_Complete_Course.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "0",
"metadata": {},
"outputs": [],
"source": [
"import langchain\n",
"print(\"ok!\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"from dotenv import load_dotenv\n",
"\n",
"load_dotenv() # take environment variables from .env."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"GOOGLE_API_KEY=os.getenv(\"GOOGLE_API_KEY\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3",
"metadata": {},
"outputs": [],
"source": [
"HUGGINGFACE_TOKEN=os.getenv(\"HUGGINGFACE_TOKEN\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {},
"outputs": [],
"source": [
"HUGGINGFACE_TOKEN\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5",
"metadata": {},
"outputs": [],
"source": [
"OPENAI_API_KEY=os.getenv(\"OPENAI_API_KEY\")"
]
},
{
"cell_type": "markdown",
"id": "6",
"metadata": {},
"source": [
"# Langchain with openapi api"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7",
"metadata": {},
"outputs": [],
"source": [
"import openai"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8",
"metadata": {},
"outputs": [],
"source": [
"from langchain.llms import OpenAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9",
"metadata": {},
"outputs": [],
"source": [
"llm=OpenAI()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10",
"metadata": {},
"outputs": [],
"source": [
"text=\"can you tell me about the chaina?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "11",
"metadata": {},
"outputs": [],
"source": [
"print(llm.predict(text))"
]
},
{
"cell_type": "markdown",
"id": "12",
"metadata": {},
"source": [
"# Langchain with Huggingface hub"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
"metadata": {},
"outputs": [],
"source": [
"from langchain import HuggingFaceHub"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "14",
"metadata": {},
"outputs": [],
"source": [
"llm2=HuggingFaceHub(repo_id=\"google/flan-t5-large\",huggingfacehub_api_token=HUGGINGFACE_TOKEN)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15",
"metadata": {},
"outputs": [],
"source": [
"print(llm2(\"'how old are you?'please translate it in hindi\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "16",
"metadata": {},
"outputs": [],
"source": [
"llm3=HuggingFaceHub(repo_id=\"mistralai/Mistral-7B-Instruct-v0.2\",huggingfacehub_api_token=HUGGINGFACE_TOKEN)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "17",
"metadata": {},
"outputs": [],
"source": [
"print(llm3(\"what is the capital city of India?\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18",
"metadata": {},
"outputs": [],
"source": [
"print(llm3.predict(\"can you give me 200 line of summary on the capital city of India\"))"
]
},
{
"cell_type": "markdown",
"id": "19",
"metadata": {},
"source": [
"# Lanchain with gemini api"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "20",
"metadata": {},
"outputs": [],
"source": [
"from langchain_google_genai import ChatGoogleGenerativeAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21",
"metadata": {},
"outputs": [],
"source": [
"llm4=ChatGoogleGenerativeAI(model=\"gemini-pro\",google_api_key=GOOGLE_API_KEY)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "22",
"metadata": {},
"outputs": [],
"source": [
"llm4.predict(\"what is capital of usa?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23",
"metadata": {},
"outputs": [],
"source": [
"llm4.invoke(\"what is capital of usa?\").content"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "24",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
================================================
FILE: Access_APIs_Using_Langchain/requirements.txt
================================================
langchain
openai
huggingface_hub
langchain_google_genai
================================================
FILE: Advance RAG Hybrid Search/Hybrid_Search_in_RAG.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ZHzAavdZ3VNX"
},
"outputs": [],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"from sklearn.metrics.pairwise import cosine_similarity\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nYRfi-RmDbp3"
},
"outputs": [],
"source": [
"# Sample documents\n",
"documents = [\n",
" \"This is a list which containig sample documents.\",\n",
" \"Keywords are important for keyword-based search.\",\n",
" \"Document analysis involves extracting keywords.\",\n",
" \"Keyword-based search relies on sparse embeddings.\"\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "H4MwrCZ_DmrA"
},
"outputs": [],
"source": [
"query=\"keyword-based search\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NhzyM3v3Du2R"
},
"outputs": [],
"source": [
"import re\n",
"def preprocess_text(text):\n",
" # Convert text to lowercase\n",
" text = text.lower()\n",
" # Remove punctuation\n",
" text = re.sub(r'[^\\w\\s]', '', text)\n",
" return text\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "y2ni_SqXD0Vd"
},
"outputs": [],
"source": [
"preprocess_documents=[preprocess_text(doc) for doc in documents]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "j8V1C_9tEBMQ",
"outputId": "7b32b1e6-9a86-46cc-ce34-69853884e2bf"
},
"outputs": [],
"source": [
"preprocess_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gIOe6cD3EEsR",
"outputId": "f8d7ed10-52fd-4017-d609-b2d23c5db662"
},
"outputs": [],
"source": [
"print(\"Preprocessed Documents:\")\n",
"for doc in preprocess_documents:\n",
" print(doc)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "YsE3-_29EQZ4",
"outputId": "928dc874-96c1-43df-ad6c-bc2012537f7f"
},
"outputs": [],
"source": [
"print(\"Preprocessed Query:\")\n",
"print(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SHeGaVJWESI-"
},
"outputs": [],
"source": [
"preprocessed_query = preprocess_text(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "M0KhXDLiEcCI",
"outputId": "d191b0de-17db-44e8-de9a-e32b1166e7ab"
},
"outputs": [],
"source": [
"preprocessed_query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "DxMRTcYiEdHG"
},
"outputs": [],
"source": [
"vector=TfidfVectorizer()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "08jzr0KsEmDX"
},
"outputs": [],
"source": [
"X=vector.fit_transform(preprocess_documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "J_dkpYYZErZv",
"outputId": "1cb63639-5057-4d47-b1db-d7772f021e75"
},
"outputs": [],
"source": [
"X.toarray()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Qzz9npHZE0oV",
"outputId": "02716dd3-9e0e-4d69-c48c-55b643cd6062"
},
"outputs": [],
"source": [
"X.toarray()[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LckZUiA4E4ft"
},
"outputs": [],
"source": [
"query_embedding=vector.transform([preprocessed_query])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "aiNDyXHJFEZu",
"outputId": "6021c89a-d268-47bb-c582-de2a3e0769bc"
},
"outputs": [],
"source": [
"query_embedding.toarray()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XXBAHj3nFGXh"
},
"outputs": [],
"source": [
"similarities = cosine_similarity(X, query_embedding)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "mrsvAIehHhIf",
"outputId": "95d2b3dd-f983-4f4c-b91e-6e7339ff5c83"
},
"outputs": [],
"source": [
"similarities"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Juj5TN8GHzpV",
"outputId": "9d081198-b336-4f24-cffc-3665d37c7529"
},
"outputs": [],
"source": [
"np.argsort(similarities,axis=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RHj8jNt2IPzU"
},
"outputs": [],
"source": [
"ranked_documents = [documents[i] for i in ranked_indices]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gRmz-mQVHh-u"
},
"outputs": [],
"source": [
"#Ranking\n",
"ranked_indices=np.argsort(similarities,axis=0)[::-1].flatten()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tqcS1JjmICiX",
"outputId": "5686d7b5-d395-4f1b-9115-dab500b4a561"
},
"outputs": [],
"source": [
"ranked_indices\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Wsr1s-vcIEGm",
"outputId": "8b98886b-0d39-4580-efcf-541a871ded6b"
},
"outputs": [],
"source": [
"# Output the ranked documents\n",
"for i, doc in enumerate(ranked_documents):\n",
" print(f\"Rank {i+1}: {doc}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "P4bJxZwAILue",
"outputId": "288b18fa-cf8f-4f4f-ef7c-fc3dc03fbe88"
},
"outputs": [],
"source": [
"query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JVa9FNvtJADx"
},
"outputs": [],
"source": [
"documents = [\n",
" \"This is a list which containig sample documents.\",\n",
" \"Keywords are important for keyword-based search.\",\n",
" \"Document analysis involves extracting keywords.\",\n",
" \"Keyword-based search relies on sparse embeddings.\"\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hU93ANjGJDLt"
},
"outputs": [],
"source": [
"#https://huggingface.co/sentence-transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "c2Eh8p_MIVAV"
},
"outputs": [],
"source": [
"document_embeddings = np.array([\n",
" [0.634, 0.234, 0.867, 0.042, 0.249],\n",
" [0.123, 0.456, 0.789, 0.321, 0.654],\n",
" [0.987, 0.654, 0.321, 0.123, 0.456]\n",
"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YHKoe1BBIw1j"
},
"outputs": [],
"source": [
"# Sample search query (represented as a dense vector)\n",
"query_embedding = np.array([[0.789, 0.321, 0.654, 0.987, 0.123]])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "-EYl_pwbIyvN"
},
"outputs": [],
"source": [
"# Calculate cosine similarity between query and documents\n",
"similarities = cosine_similarity(document_embeddings, query_embedding)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "IMNMKcChLjkE",
"outputId": "2e582a10-31bb-4c99-9966-35b21ac0f901"
},
"outputs": [],
"source": [
"similarities"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Vk1EdOJBI0S1"
},
"outputs": [],
"source": [
"ranked_indices = np.argsort(similarities, axis=0)[::-1].flatten()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "cA8La-wuI1rV",
"outputId": "f5e5ceb8-1533-4cee-b50c-d510a64acc8a"
},
"outputs": [],
"source": [
"ranked_indices"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "T_DQrmU9I2b2",
"outputId": "f8abc51c-7bbe-4a46-88f5-e7cb3e1fcddb"
},
"outputs": [],
"source": [
"# Output the ranked documents\n",
"for i, idx in enumerate(ranked_indices):\n",
" print(f\"Rank {i+1}: Document {idx+1}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bonW5T3DI343"
},
"outputs": [],
"source": [
"doc_path=\"/content/Retrieval-Augmented-Generation-for-NLP.pdf\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4i1BwkuaJdUG",
"outputId": "b56b6dca-172f-4e11-9204-369e45d0420b"
},
"outputs": [],
"source": [
"!pip install pypdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1IG4zizRJgWW",
"outputId": "898c9837-265b-409e-a684-eadef1844a97"
},
"outputs": [],
"source": [
"!pip install langchain_community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "uYdubydrJmUH"
},
"outputs": [],
"source": [
"from langchain_community.document_loaders import PyPDFLoader"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2f9DJUCzJprn"
},
"outputs": [],
"source": [
"loader=PyPDFLoader(doc_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "B98wvocsJvTN"
},
"outputs": [],
"source": [
"docs=loader.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "v7l4fCgvJxUW"
},
"outputs": [],
"source": [
"from langchain.text_splitter import RecursiveCharacterTextSplitter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "WepxAdEdJ_nW"
},
"outputs": [],
"source": [
"splitter = RecursiveCharacterTextSplitter(chunk_size=200,chunk_overlap=30)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lwvamrKDKCn_"
},
"outputs": [],
"source": [
"chunks = splitter.split_documents(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "jeYdtmSQKFII",
"outputId": "cf3c4288-aeea-4f6f-d29f-d37dd6220d55"
},
"outputs": [],
"source": [
"chunks"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9ELPWtoiKGj_"
},
"outputs": [],
"source": [
"from langchain.embeddings import HuggingFaceInferenceAPIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tie5VFKiKNLG"
},
"outputs": [],
"source": [
"HF_TOKEN=\"\" # Replace with your Hugging Face API token"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zUHbfW8kKOvP"
},
"outputs": [],
"source": [
"embeddings = HuggingFaceInferenceAPIEmbeddings(api_key=HF_TOKEN, model_name=\"BAAI/bge-base-en-v1.5\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ac6yOdC2KYRP",
"outputId": "f176c60f-ea0e-426e-ceb7-cc18cc6829ce"
},
"outputs": [],
"source": [
"!pip install chromadb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Y0quqPhKKc22"
},
"outputs": [],
"source": [
"from langchain.vectorstores import Chroma"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Zfzae2UlKh9O"
},
"outputs": [],
"source": [
"vectorstore=Chroma.from_documents(chunks,embeddings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0ALPQsPUKpau"
},
"outputs": [],
"source": [
"vectorstore_retreiver = vectorstore.as_retriever(search_kwargs={\"k\": 3})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "2FV-WXkyKx6P",
"outputId": "b6130974-ba6b-4296-9105-d750ab9c77d3"
},
"outputs": [],
"source": [
"vectorstore_retreiver"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "QT6vnCxHKyw9",
"outputId": "05a917ff-c00c-460c-bb49-a711f88e52d0"
},
"outputs": [],
"source": [
"!pip install rank_bm25"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IqeQYitAK4ct"
},
"outputs": [],
"source": [
"from langchain.retrievers import BM25Retriever, EnsembleRetriever"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "K0Ysb2j7K8q-"
},
"outputs": [],
"source": [
"keyword_retriever = BM25Retriever.from_documents(chunks)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ns_BlaSPK_7G"
},
"outputs": [],
"source": [
"keyword_retriever.k = 3"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mgWvoTb6LFTu"
},
"outputs": [],
"source": [
"ensemble_retriever = EnsembleRetriever(retrievers=[vectorstore_retreiver,keyword_retriever],weights=[0.3, 0.7])"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "UofjUpUzLYep"
},
"source": [
"# Mixing vector search and keyword search for Hybrid search\n",
"\n",
"## hybrid_score = (1 — alpha) * sparse_score + alpha * dense_score"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YcoWWuHCLRpI"
},
"outputs": [],
"source": [
"model_name = \"HuggingFaceH4/zephyr-7b-beta\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "npRU0vb2MID-",
"outputId": "9ed32b71-d556-4ce3-b173-4dde1adeffad"
},
"outputs": [],
"source": [
"!pip install bitsandbytes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1-5-EKRgMKIG",
"outputId": "92a5cc0e-a1d0-4632-feeb-c4fe330db197"
},
"outputs": [],
"source": [
"!pip install accelerate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "j1hZfTx7MMvF"
},
"outputs": [],
"source": [
"import torch\n",
"from transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, pipeline, )\n",
"from langchain import HuggingFacePipeline"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "wreWtbxiMjX2"
},
"outputs": [],
"source": [
"# function for loading 4-bit quantized model\n",
"def load_quantized_model(model_name: str):\n",
" \"\"\"\n",
" model_name: Name or path of the model to be loaded.\n",
" return: Loaded quantized model.\n",
" \"\"\"\n",
" bnb_config = BitsAndBytesConfig(\n",
" load_in_4bit=True,\n",
" bnb_4bit_use_double_quant=True,\n",
" bnb_4bit_quant_type=\"nf4\",\n",
" bnb_4bit_compute_dtype=torch.bfloat16,\n",
" )\n",
"\n",
" model = AutoModelForCausalLM.from_pretrained(\n",
" model_name,\n",
" torch_dtype=torch.bfloat16,\n",
" quantization_config=bnb_config,\n",
" )\n",
" return model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NwjY8MH2MlPy"
},
"outputs": [],
"source": [
"# initializing tokenizer\n",
"def initialize_tokenizer(model_name: str):\n",
" \"\"\"\n",
" model_name: Name or path of the model for tokenizer initialization.\n",
" return: Initialized tokenizer.\n",
" \"\"\"\n",
" tokenizer = AutoTokenizer.from_pretrained(model_name, return_token_type_ids=False)\n",
" tokenizer.bos_token_id = 1 # Set beginning of sentence token id\n",
" return tokenizer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 301,
"referenced_widgets": [
"80926a7d4df344508960da3bd0ca49f7",
"6c641853c1b74a41b184f51b87ae906f",
"8d2c6e157a924a26880515f7324b2c75",
"a0be9de9c0a74bf7a71990b7cf90fc81",
"af31aa045fc34aa988fd62c069526825",
"2a1bec229f7d47848a7b2295c6a268f4",
"26095125285d4e9ea83874f6ffe25942",
"08cf29966c294859bccd6c732c5f3d7f",
"9e1aa7119d43472d8aa59c7dab6c694a",
"16eb1f8b842d4826ba3ef2005ed31e6e",
"3c1d8fe6e80543a2882f85db87ea1ac0",
"0b1bcab0cf134f63a5e8266625a942bd",
"09826733b772426087d6637d792ba548",
"44e281bf0ce446c4b8498228561135de",
"59b548dd70b44891b3aa98de1791bfb5",
"384b571d3e39475b85ca761ab673ee73",
"447d6969157c43bcb0631a26b6c8cac0",
"071e4ae0b00c4f26be7211138a1181ae",
"f8be43f1c46c4faf8f051210a43f0bfb",
"a1a23db33c224752a1dc2196ba382ae6",
"a378202cc8d949f69d3d12d4fa73213e",
"f31d3074eae94590b898da18bac54d06",
"ad36707579d845b7a06f50cb63ed7b83",
"3a814f699a8343c3af2fad3f95de8de1",
"4ad0219054824fd0af5bbdb93442da57",
"71bc0d30d99a4e47a0404b1f6889eaf3",
"263d4bd8d0574212a6a321a1c7bdb196",
"fd6295669e164ce4a387bc2e62946a4f",
"ae1113c16973440d83b13200041c3951",
"21f3d9c1e06e4296926555bfdc1f06fa",
"458d94bad2094540a2f39a68ca453b69",
"3c67a6a263944cf6b4c5a16bb12f645c",
"582960e55cca46a2bb98c6262b4b8dac",
"cb616a7cdbe34801b06a02faa2e1bf63",
"840eaca5fb2946509606fbb200dc09f4",
"363406e6e0014ebc84b4dc59b02f02c5",
"85b93405ad3a4ba38e2556d6524d65fd",
"a742a5585675495a93f79f8637ca1280",
"de907241aa264c45934acfb7e9d24f57",
"615281b2b6784b98847b50f01192f1a2",
"9c4daf9db0034665a2594f47327b6788",
"88d9d8050d1e4969b098f6abf84c1fee",
"26b3044048b64a73b51d5898315d6dc5",
"538545500c344b779460fb35fe1518db",
"1d037ffc17d640548efc347135c3161c",
"092a08cdbb7642afbc7690fc24df984f",
"13625c7173694bf4aacdcc3d220d1987",
"21c9320ad08a483d8d157a54618b560b",
"fb5058f498e343109b9efc4e5b686abb",
"36acdc477dde484db4a62e3457d5e541",
"dc92e27c5fb54dfeba414b52de3e61ff",
"176dbed88ecc4ac48b8f5c8ee5f18954",
"11f30ee987e44ab3a314a8bfcb97ae65",
"c897c57b73b94813b98b404a09eb8c27",
"73a4375a86fc4d238183d1c5b8ec0947"
]
},
"id": "6jPsnRl1MnTT",
"outputId": "01daf0fc-3df3-4595-d25c-cbac7a854885"
},
"outputs": [],
"source": [
"tokenizer = initialize_tokenizer(model_name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 450,
"referenced_widgets": [
"07d8c85868c449449b6baa5e01a73b29",
"e471c5568cb64517b04d6928bf8fe489",
"57fe89b8228949a38be75ef7e4de7839",
"77e99c47ee4e454eb52737d88bbd251d",
"34f2a684450948a9b3282c6ed6a942f8",
"2df56bd6d013457394f095f7059eb749",
"cd260bcc399844f4a1e8ba5f6e9c7583",
"a0966045942d45f4971f9cafe09ca3d9",
"202f976699894040976c79e074f3f872",
"afadf115dc5b48dd96c6116f79c5d1e2",
"63de9883e84a4b5da61f47973c20d9ef",
"4881c9bf45b3451db46fee4c157f0f04",
"2442fa158c45499d8cd8180a8315c17c",
"5f117ff65397456db4831a76762e6fc7",
"f51636a5b18446ec8f796bed4cac5235",
"70aabcb99c8d440ebf7e62fa8bef67ca",
"43b7aa07093e4743a1840b537e45ec49",
"bd3b9e1eec7f4e15a6fbb5a5008b0ed7",
"cdb4ac97ae9c4f9ba4acd34c8ad754e1",
"005034b8094743e6a66ba5f3a92e2528",
"f361d834ed24402aa92d7e68a5643baa",
"040e68a26cba4ed59cbbb645b415849c",
"1cdbc02ee2254e4d8d9f74f03877982f",
"2750c773ab1f4aba83a4bc49810e0b2d",
"c621c7507656401996f18f6d8838c10f",
"49df4a8fb9324b38beb88827dc616397",
"f5aa99bc46bd402c8f87d66974ab5381",
"e9e8dcede4384b909a3d4075ee0e81ad",
"03f5ae15263d430ab78f9b411b3a791c",
"842c86b1c46b4e52940fccbe4189e99c",
"b5f2d4c72b4844b893aa321beb203024",
"d3b49dd99b7f4bdc99916a8489d5a2b9",
"2962ac0a38fd4520a5d1a8dbff0d0017",
"c62b209db3d84077955d5f8098ba8e7e",
"03fead08af6e4045bd486059db06778e",
"07d9e2dc13e6425aabab9742595319f9",
"f8dcdea2c21746e8bd31d3545bec063e",
"6b09ce81e3d14ba393667f1d2107d664",
"520c039fd1ff42888eb2ccedcae2206b",
"ed6bb088584346f29abc2dd96a165f25",
"0b93285e9d6648a18895bcc97f8fd047",
"cc1faa52bbb349da949ba8685a02a634",
"2117b98dcd9145788388d65cfc226276",
"5b7b92c68df94ad4aa7a57c24392b881",
"15668490074e4146924c76d30d58b36d",
"a295f559a84548b99dbf37b543be5a3e",
"58e921fa323a469d9a0605ddbed59a75",
"7e27e52524774fc18cbb1be105a95754",
"63847ee284194d009825351d96a5b02b",
"865e74c7b5f74079af763e2263bc2327",
"2113668d3b97456bb12ce916a676feaf",
"9c800bd92ce74075b918c4d466e84863",
"52fa72ead88142e98c414a13859d6eab",
"af20ec59965f42b18c2f96351b5fb0ba",
"7971e0b059c64a23a389b43ddf387122",
"6f7c608396e44029991536f150818d16",
"d15b0846c4314acdaa7b3a1dcb71f0bc",
"f758e0d677a547c3841b80497c674978",
"ab34a0c84c3e46c1b4f68d1283f5935d",
"b48a6bba01984146a10e72505b3759a7",
"38f8636944b44bb49d36566ced632076",
"f9420643986c4ed4b8d9c07e27acd48f",
"8d145b507e28468f9c856014199d4db5",
"e46fcdd2b72b4e30b0e12c0d624dd98e",
"cdcb1c54936141dcac96fddd96f271a5",
"8434d230785e4dee8d148f68c6a888fb",
"50454394fabb4f31a45cb58b96cc26d5",
"977c8cfbd6a44a5d86c594d26911d557",
"f468056e46044349b8ce3a41d550ee78",
"7bd32807c89848e1bbf33f3caf1f387e",
"bd90f8108f084b87a4d430ba0e515cf2",
"b0519b9d03394d5eab8484f2abe3a70c",
"e05120f1c0a4434ab707344d1e383ed9",
"b050ac0e6aea4d79bb1d2490dfc3ae98",
"94bf0da48d34429886d0e4cce5450fd3",
"c17d1f96f8594112b765de1dbc6f3b74",
"e2aeb272fb374ef592c822c90ed8778d",
"165a5174fbab472c9ef25bd99e6ac28c",
"c1acc369a31e4e79a938a6c0cb36e559",
"73b31d036d464c82a3a1ff920f6a3449",
"4972967026934ea5acaf5f6ff7e85959",
"3dcb0ed858364e949e263d5d4826ef2a",
"a6076c8c267b4eec8178d409074903c7",
"73cac54fe96f4a279e0c207709a86eaf",
"e4bd4490dcec4d7d87be03a9a4d4382d",
"57b4dcff412b4b468a6de20591de26ce",
"4693d715c66547ea8d39cd1a6ba0336f",
"2a01c5ef1de4456aad63cca3b2069593",
"677a79a0338d422ca3368dd57f178b85",
"d862657320ee4504a7265c5c97c31081",
"04cfd5ba6ecc40c1952558acfbb2f4ce",
"b52cb5cffa3141419db3efa89113e814",
"cc6887ac097e4289a6ce4b1b1bf173e7",
"4a7a6b7c7d784185b57d67d7f54b2691",
"44bc78242bf94d79ac70fc791e3af16a",
"6666fa1158c346e29cad1357589fcaa6",
"db8b5eeea5754a399ce04f1870623cb7",
"b28becf405c34086b763f02b63260aee",
"69352bdd872d47649698abb7de37d3ef",
"aaabc037d2f646788594f91d50da1997",
"a2433ece64f547f39705001c3e30a6d9",
"92c03fe2ae76461790874e0018815a28",
"584662741e874eefacf19320737c2b59",
"a6801fca131c4230987a70253e4ec6d7",
"4b2a88c686e3410cbb0dea89f563a36a",
"32ca4c3fc1814b42a14f37b6f6fd0882",
"909b322452804f2abc0d2b4b56f0dfc5",
"37d95d871dc8470ea003d21eae074fc8",
"9029d7f32c234fdca72c18b30dbd43d6",
"3fc32e8724b643b8b99ed542902ffb50",
"809e6a3712b74ba2bee89cdefbbb5a8a",
"b9e89f8490404229b28b9bfbc1f07ed3",
"d7dbac36a72a4bc792127f08576906fd",
"29323042926c40fe9d6bfdf90a1a8461",
"236c12bc38d740b9a40e77b0257f614b",
"07c3636d7be347f7a5c7ecdfe20e3b6f",
"99437495138f4cff8fa55107bfb2c6e2",
"2b2e6307d78645fe84349bd7f84bba2d",
"e75fbee35ed940dca1d5c2f8c648180f",
"fe2e1a2e23c7469382035a693633530a",
"2998a1d726c44d13870fb56d0382414a",
"a915809bec36492e82b2ffe103dbaa38",
"00d6d459dc3e419d882aa81ae4f28154",
"4a1269dcfb8f426a980f5e0154d72a69",
"2b10ac1bc5e645609c9e94c611ab5d9d",
"154279dc043b484ab636061c284b999e",
"00e126aa54674c7f94645fc575d337a3",
"68473a26b8fa4e53a0323b87cf64c85b",
"88e62c14da344b09924afb5f76fb82f2",
"dfc1ce03a4264afdbfcbdc3e49da55f7",
"7180d98479b04fc7ac68016993803fd1",
"d6b7a480f8c841b484a5dc7f25fd07e6",
"d6ae442401a549a183fe9ee6acde7d6c",
"c5730f6901a94164b6d011b1be334779",
"083df6dcb00e4c4d8067aebdb17739f3",
"84c4aaf7020a42fea9195c6721140956",
"774958b959c144ad96ad9ed6cd5a65b8",
"2bab900d4d464e38b02e8428a9167a20",
"6f940eecd7a24898aec4adeb1c2ea9d7",
"5a1d235b8ed447718d6c99999b27f663",
"12c23e90d37d444bb5a6a29d282b0a48",
"1ee7eb7cb9c94e89a82e7d01008d1030",
"f6458c06ee6e472d8f48ebe902d6e420"
]
},
"id": "SlPXp-MdMoud",
"outputId": "a10228f2-d79e-4e87-8802-a5d2c4923ffe"
},
"outputs": [],
"source": [
"model = load_quantized_model(model_name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "W92XMGCnMuuG"
},
"outputs": [],
"source": [
"pipeline = pipeline(\n",
" \"text-generation\",\n",
" model=model,\n",
" tokenizer=tokenizer,\n",
" use_cache=True,\n",
" device_map=\"auto\",\n",
" max_length=2048,\n",
" do_sample=True,\n",
" top_k=5,\n",
" num_return_sequences=1,\n",
" eos_token_id=tokenizer.eos_token_id,\n",
" pad_token_id=tokenizer.pad_token_id,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "c_9lkcQxMzRz"
},
"outputs": [],
"source": [
"llm = HuggingFacePipeline(pipeline=pipeline)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xifUF7rhM0zw"
},
"outputs": [],
"source": [
"from langchain.chains import RetrievalQA"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SusMb1LuM2I9"
},
"outputs": [],
"source": [
"normal_chain = RetrievalQA.from_chain_type(\n",
" llm=llm, chain_type=\"stuff\", retriever=vectorstore_retreiver\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EryZWwp0OK1b"
},
"outputs": [],
"source": [
"hybrid_chain = RetrievalQA.from_chain_type(\n",
" llm=llm, chain_type=\"stuff\", retriever=ensemble_retriever\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8LfE83mROQPS"
},
"outputs": [],
"source": [
"response1 = normal_chain.invoke(\"What is Abstractive Question Answering?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "V9AD5METOTne",
"outputId": "ee2d24ca-4e41-4a09-e061-01c4a7a2fe5c"
},
"outputs": [],
"source": [
"response1"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "3upJ2p95OSA2",
"outputId": "fab70c85-73b4-4aeb-b4af-de5a38f14bc0"
},
"outputs": [],
"source": [
"print(response1.get(\"result\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "05btkVByOVPA"
},
"outputs": [],
"source": [
"response2 = hybrid_chain.invoke(\"What is Abstractive Question Answering?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8iTPRsBqO_o9",
"outputId": "213c4356-657f-4cef-a814-3885ce7c88e7"
},
"outputs": [],
"source": [
"response2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "TH4DKQYYPDuA",
"outputId": "2dd0f6e8-fa4a-464b-8c12-5605c26a2141"
},
"outputs": [],
"source": [
"print(response2.get(\"result\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "r3k6SAjmPH5X"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"authorship_tag": "ABX9TyN9J8sAFAwcZchZQM3mPc4J",
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: Advance RAG Reranking from Scratch/Reranking_from_Scratch.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zkZpN87d4HJf"
},
"outputs": [],
"source": [
"documents = [\n",
" \"This is a list which containing sample documents.\",\n",
" \"Keywords are important for keyword-based search.\",\n",
" \"Document analysis involves extracting keywords.\",\n",
" \"Keyword-based search relies on sparse embeddings.\",\n",
" \"Understanding document structure aids in keyword extraction.\",\n",
" \"Efficient keyword extraction enhances search accuracy.\",\n",
" \"Semantic similarity improves document retrieval performance.\",\n",
" \"Machine learning algorithms can optimize keyword extraction methods.\"\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MLF_E-ZQCYq_",
"outputId": "d6663d67-6aaa-4d05-e6d6-f93a38bee6d0"
},
"outputs": [],
"source": [
"!pip install sentence_transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "A2TapY91Cde2",
"outputId": "59730e9c-973c-4e42-9e62-319b0c783df2"
},
"outputs": [],
"source": [
"from sentence_transformers import SentenceTransformer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YcMjOGquCkSu"
},
"outputs": [],
"source": [
"# Load pre-trained Sentence Transformer model\n",
"model_name = 'sentence-transformers/paraphrase-xlm-r-multilingual-v1'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 528,
"referenced_widgets": [
"a73efd61756445ee8f59a9d4c477a496",
"68ccd8382e3b4b67918c1185619569be",
"abdde99c2beb414a85ec34c5786d6bb4",
"268eb8843398482fafafc7872d0ecfe3",
"237e90ec67814d0dae44d87298d7832f",
"065e9d8dea90483e82a8b2245f4536ca",
"b79089b353334f93815eca389075e53e",
"4e4fceb1c2694de983367ffbc14cc6b1",
"78a1ec72ded34a38be5a53b826a3f47e",
"0e6e82e47c794f8c84635a9dbcfe2f41",
"9e2638ccb48848ecab369c3cfc3858d5",
"8a3090b91dda4a14a4ef1edcdcdcd169",
"c9108a02b3ca4b3fa1fd27498841f5fe",
"d61f57fb6cad482090fe874268bb7fb0",
"e994f58d6e7e4639b9feb59166e49ece",
"6116d2df9d8b4290981f7d45b0c1ece9",
"147152f3f8314d5f93c35194e96bf41f",
"1a0b0b6b1848413baea8804af947cf7f",
"d3603d3fdc314fca9132355c70948e28",
"d6258c5bfc474ef59d9c106245dfa5f6",
"918d839c76564c41ba9373b576de1cfd",
"47dad9a831044689b1926f2b9e608787",
"e767c41657d345a5ba8569b89d3347f7",
"ea8879768efa416d9a032ac56760039f",
"61ad01c8d10d41579300176be2388cb5",
"7a2e7317b9d64b07b032e42fd1a7f021",
"3a0feffa1d4b4f49bf875eeece9eda44",
"eaf1862044564eefb3ae75a3f1d9b5cb",
"8f337c9564e748d5825b0338cbfe61ed",
"83362efd58e543b3b37fef730a92e472",
"a766e351652e480ba9c2bbe9e4654277",
"f6c2e7b4ffd24a299f77966e6a01bfae",
"3722b793a3864a7ea37d17190502214f",
"4fafa1c7e2ba4226adcc96923366ad27",
"485bbf74d899477aa078deb9c041ed78",
"f99622285dd54f7ba2e53328281f4622",
"1cb793924d74484cab6ef3d25f03d6a1",
"085ef7cf00f34d17b0a408d30edf2fe4",
"783b47a891e54914b6c1c02282d60ab4",
"316319c51c8e4641bf6a54b0faa115da",
"cdfe2c8c9e85479d85e9f8807a8e0d80",
"eaaf65e04ae643e0b345e4c9fb66b395",
"a9655237479c4dda903e7cf2bce5ed47",
"6ed8f516577445a59b14d83cc70051b9",
"d0ad25f469704abc9f50593e7a700493",
"ab96ab19368e4e0a9b9db9651e82dcfb",
"d7e49001505f423a875b4a104f802791",
"e0430cc1c475449cb7d7e95996346386",
"310b3c09502d478cb4f6d5c368477d3d",
"da40ed22f73d45e38c18a0840447f9f4",
"3b691de532754ca896537b9545b98b3c",
"23d6300688ed48f4854d3b1b1d95f7b5",
"07e8d136197c42e4bf13e268fe4a7e18",
"adb7a266e6f544d69a431d639b7ec8ca",
"389621bc791d43009a1dc72f8b8c6255",
"d0d22e982bae4a22bc3096a20d5df450",
"5b15d268cb2f41f789fc64b69ecbfacd",
"e193101058a84d748d8d9d7de188206c",
"2260ad86c1fc4fd19a45c739a149a468",
"12eebf8fb4754a3fb437826534a59122",
"aed192be683a4457a203023a767d9657",
"07804e100ec94400be6112715766edd4",
"ca3c48a038ba41ad8cb8c63818efc56e",
"b7b6faa206d24c2aa170db8c1e4fdd5a",
"429081ab64d243658e23629aa5f5dd42",
"b48366eeb2764d538c7377dbd885e645",
"d7551d3c5c7b40feaf5e10980941be6a",
"fc7e4928ab3d41399a353a635458b839",
"92c726d5833442a2b2370e39f1f3beb6",
"b66f31b83a7a45c2802f82e71977a484",
"f23f5ac637634ce99d980ff914f5f2b5",
"7b8d20d4f0ea491eb0c572b35632b491",
"b0c146ab051e469c9a221f7a4aa2dcb0",
"7870aca389cd476f9f9fc3e18a3a7dc1",
"b0196615760e4f8090bcefeb6dc75ad0",
"2543d539ac1846bc9c8a60f5c9bf8b0f",
"0518c6d6fd6345a0bd4d8cd42624c9b0",
"a24d5de3191d4ab9b14042d1b74b2771",
"360e5501781641e28223c2ca04885712",
"61ba97ed908347bdb108414d00ae1da8",
"f532e2107a504f02b1c8aaf808fab285",
"bbbe88e4bcb8419eae1287f873030c32",
"6fe021d4c3354f928864812d36c6f505",
"b858cf901d114e0fb8c5d4b5e60a37fd",
"5f9cd04cd1ad45e797b5a19b59d12a53",
"ed88bb06e121466990f46709fe4cb04a",
"bb1918b54e5a49c7955615803d61d9fb",
"f2c7997c24034b339b32bc6c6e29caf1",
"6251884fe0ed43649766f7564e6ad115",
"c14ae62edc51484d963fa9160806d171",
"611c4d1847b34f17ae0e00dcd94154ce",
"29fd88b5e6e6476cbcce4f612905a8e6",
"90f11cadc2ca48f58e2d63351593710c",
"3d35a1d2cfc94dcebf9e972fb156d966",
"d33d91cab584458ca5c739c4bc90c303",
"f4e5d0f719a04dc0b67589274369a421",
"81202f4eeb1c41378a67ef9b5841c1c0",
"b6acd772cff24e5d96d0624ddf4ff44e",
"b1c612692bb1479b8dec5f467ad58832",
"7a96b13409884197a28ec4b78a86282d",
"71f6ffd6635b40608b37066f9b67e176",
"70af227d52094d18a829639dd84955b1",
"17317293304644c5a891955e3b387964",
"c74008e0e8e2429b89f1192f8bb0d4b7",
"e1cb3eb282a14850b48ab5a380a2acb5",
"7319aebddf3445b2b7e9a0306e0447e7",
"5d19b88244904aa88059b6c9e27a8599",
"fffd1f3b84b443828a2f8b49d41be906",
"5f5f4d08736d4f2e96c439820fc64713",
"ced7c15e2caa4e73a6feb289b66a3dfe",
"319c9d6c19af43a1bfdeea654417384f",
"b57386b666e74e1e98b2dd63ddee47f7",
"5a1215e03da746c1afdd509b76ab1004",
"8ccec9a9c0f74eb8be6955cff6e53705",
"ab8123ece1a240dfa5ca5745e6ab8292",
"edd08d1dc4ba4372a0d922d6d3082aed",
"638363a050bb40e3bd7c4486bae71ed5",
"4fbbae328003461a9ff3504ad3ea6ce1",
"4261373691d54f818090945cc72bae02",
"1a8126495ffe4bbc9a25ee1815db4cbb",
"9b3cad44fe2548c48336193e7c4643c9"
]
},
"id": "3HLEx9rKCxdn",
"outputId": "cf3da8e1-e2b6-4153-8d0e-384210001ba0"
},
"outputs": [],
"source": [
"model = SentenceTransformer(model_name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "oj8kcRVZDDYs",
"outputId": "814cd1b0-cacd-44c3-b3d1-65df0b6534cd"
},
"outputs": [],
"source": [
"documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "yaI-PRMwDGxf",
"outputId": "00c9abfc-2371-4006-d76a-681e7b9c619b"
},
"outputs": [],
"source": [
"len(documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PYxjbDxdC0T_"
},
"outputs": [],
"source": [
"document_embeddings = model.encode(documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "UUENS13LDJ5y",
"outputId": "08c30846-cab5-41ce-a7de-fc7daaabc4a0"
},
"outputs": [],
"source": [
"len(document_embeddings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "25ZYBnhcDMcj",
"outputId": "b9665b05-aea9-4d7b-fc4a-70e578f8eb79"
},
"outputs": [],
"source": [
"len(document_embeddings[0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "IcQ1Q9PtC9o-",
"outputId": "15b836c5-7519-4ce7-dde0-6f0a8ff833ea"
},
"outputs": [],
"source": [
"for i, embedding in enumerate(document_embeddings):\n",
" print(f\"Document {i+1} embedding: {embedding}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "z29WzyItDX8x",
"outputId": "7da471bd-609b-493b-d371-c23acc609bed"
},
"outputs": [],
"source": [
"documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1nQF36rhDA9_"
},
"outputs": [],
"source": [
"query = \"Natural language processing techniques enhance keyword extraction efficiency.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bJatNM_4Da5y"
},
"outputs": [],
"source": [
"query_embedding = model.encode(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ZxQf2v2TDc3I",
"outputId": "1269d99d-8489-44ab-9782-b8b4cbcf9f02"
},
"outputs": [],
"source": [
"print(\"Query embedding:\", query_embedding)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "161pAXWNE6Ch",
"outputId": "6e81b715-5a8c-4aed-daf1-8f366e6ac0c8"
},
"outputs": [],
"source": [
"len(query_embedding)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4dZjQsGDDj5m"
},
"outputs": [],
"source": [
"import numpy as np\n",
"from sklearn.metrics.pairwise import cosine_similarity"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Rcf5V3I7Dp-B"
},
"outputs": [],
"source": [
"similarities = cosine_similarity(np.array([query_embedding]), document_embeddings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "sfk1qPUeDt_l",
"outputId": "9795635a-1773-4f29-96dd-eab6c337cf5e"
},
"outputs": [],
"source": [
"similarities"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "L_vQO9WoDvLF"
},
"outputs": [],
"source": [
"most_similar_index = np.argmax(similarities)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "kstZiJpZFKLe",
"outputId": "63f259e1-4fa0-432b-eecb-b7575f064f77"
},
"outputs": [],
"source": [
"most_similar_index"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NQiqJlgNFLHn"
},
"outputs": [],
"source": [
"most_similar_document = documents[most_similar_index]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "ghiLFqGEFPxn",
"outputId": "13def6c9-0535-4b37-a51a-c58199e973ed"
},
"outputs": [],
"source": [
"most_similar_document"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "J0WDD1hvFQ62",
"outputId": "6decb463-f85d-4720-f866-2eabd198767d"
},
"outputs": [],
"source": [
"query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "l0FK7NeAFR2V"
},
"outputs": [],
"source": [
"similarity_score = similarities[0][most_similar_index]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "vVYM05pnFa6I",
"outputId": "bb851a47-2724-43c2-b079-2d7f822435ea"
},
"outputs": [],
"source": [
"similarity_score"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0MDWnmaWFbwm"
},
"outputs": [],
"source": [
"sorted_indices = np.argsort(similarities[0])[::-1]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "2ANc52lQFizG",
"outputId": "d98ed7fc-8c1c-4cef-8d73-64a3203a46b7"
},
"outputs": [],
"source": [
"sorted_indices"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "K3ydRBXWFj0N"
},
"outputs": [],
"source": [
"ranked_documents = [(documents[i], similarities[0][i]) for i in sorted_indices]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "SC6o7OhYFrC_",
"outputId": "204cc6d6-aa63-4296-cc92-003002dc80be"
},
"outputs": [],
"source": [
"ranked_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "XKIQNhJ2FsCd",
"outputId": "51c38f25-a8c8-4c06-cdf0-dc1cf7513634"
},
"outputs": [],
"source": [
"query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fyEQPRNaFwDn",
"outputId": "58ac9e6f-8ab1-4c61-baa9-84fab33a3d36"
},
"outputs": [],
"source": [
"print(\"Ranked Documents:\")\n",
"for rank, (document, similarity) in enumerate(ranked_documents, start=1):\n",
" print(f\"Rank {rank}: Document - '{document}', Similarity Score - {similarity}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "nIRnIQbbF6u4",
"outputId": "2cbfeb6e-ded3-4187-eaf7-3e20d4a6a870"
},
"outputs": [],
"source": [
"print(\"Top 4 Documents:\")\n",
"for rank, (document, similarity) in enumerate(ranked_documents[:4], start=1):\n",
" print(f\"Rank {rank}: Document - '{document}', Similarity Score - {similarity}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "_OrCV0bDGWeN",
"outputId": "7850bfa2-1446-4f82-fe3f-7f9b66fcac73"
},
"outputs": [],
"source": [
"query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RdUhRaPuGBdG",
"outputId": "07310c7d-e6f7-4448-f486-fc74e977c0b8"
},
"outputs": [],
"source": [
"!pip install rank_bm25"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "V2xHQLECGOPh"
},
"outputs": [],
"source": [
"from rank_bm25 import BM25Okapi"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IOWKXh97GTt9"
},
"outputs": [],
"source": [
"top_4_documents = [doc[0] for doc in ranked_documents[:4]]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "HL6C8FBkGkvR",
"outputId": "b6008275-ca9e-4f57-af0d-8022926eb976"
},
"outputs": [],
"source": [
"top_4_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JRxkOMP8GlmO"
},
"outputs": [],
"source": [
"tokenized_top_4_documents = [doc.split() for doc in top_4_documents]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JXfRdUURGqak",
"outputId": "284d7b52-f5c8-4b54-e65b-93b51ccac61d"
},
"outputs": [],
"source": [
"tokenized_top_4_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qI6FBUxVGrPG"
},
"outputs": [],
"source": [
"tokenized_query = query.split()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "pmLnmTKwHV3Q",
"outputId": "4e581b53-63c5-4cd7-bd5f-beba513e71a6"
},
"outputs": [],
"source": [
"tokenized_query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tFnVRMXgHXGf"
},
"outputs": [],
"source": [
"bm25=BM25Okapi(tokenized_top_4_documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "M1JsrrgQHft_",
"outputId": "9ce9731f-1a5f-4a6d-9a5a-c2de87d74441"
},
"outputs": [],
"source": [
"bm25"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_qSArmibHhIm"
},
"outputs": [],
"source": [
"bm25_scores = bm25.get_scores(tokenized_query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "uCwf4pd1HsKe",
"outputId": "701d823b-66ad-47ee-bc36-721482a5a30d"
},
"outputs": [],
"source": [
"bm25_scores"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NZ9O9jCqHuEV"
},
"outputs": [],
"source": [
"sorted_indices2 = np.argsort(bm25_scores)[::-1]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "r4E-x3nyIBoH",
"outputId": "54cf1b6d-0b7c-4530-9d6a-c064af50b876"
},
"outputs": [],
"source": [
"sorted_indices2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "b7CaBP5QICd2",
"outputId": "46e955c8-59ed-4754-9670-703431fb2939"
},
"outputs": [],
"source": [
"top_4_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "uRatS013IM0m",
"outputId": "121e1576-5234-41d0-f283-5e3ebc013549"
},
"outputs": [],
"source": [
"query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IDrlrwEZQwgz"
},
"outputs": [],
"source": [
"reranked_documents = [(top_4_documents[i], bm25_scores[i]) for i in sorted_indices2]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "mdlTwxcSQ7UD",
"outputId": "65dc55c0-7add-48c4-8edc-13df8fd6e683"
},
"outputs": [],
"source": [
"reranked_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Tp0KrhpHQYIC",
"outputId": "d8a30b20-6d03-434e-cda1-cd194d652be0"
},
"outputs": [],
"source": [
"print(\"Rerank of top 4 Documents:\")\n",
"for rank, (document, similarity) in enumerate(reranked_documents, start=1):\n",
" print(f\"Rank {rank}: Document - '{document}', Similarity Score - {similarity}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "EStAQfpCRS42",
"outputId": "95fb587a-c7d1-4306-8aec-1c1c5117ed59"
},
"outputs": [],
"source": [
"ranked_documents[:4]"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "G4J4__8URiHJ"
},
"source": [
"# Cross-Encoder"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1-5TWTMuLLP3"
},
"outputs": [],
"source": [
"from sentence_transformers import CrossEncoder"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 232,
"referenced_widgets": [
"333ba957c0164cc7b1367fb4e77c165f",
"60dffc29c59743719ccbe57607b306be",
"1c1b5ab6594246699420d15f40dcbf9a",
"9d17552a55fc44be878dd307775ac321",
"9e0dd06ae62747ffa2afd3603eece633",
"cbedaac8d74e4abca2d169ac86c1a637",
"255b200fe7844af5ae00e2db870baeca",
"8dd323012ba14f6eb099213e75490155",
"9234b774c856496a93449f43840cdf22",
"9945335709b245ca8ec2442cc91e3f17",
"f1ffd96a7aab475283cc4eeec7f51e79",
"35a8f13d044b46839c6929f4b3c051b5",
"47f9be3cc02742e8a4a0631e32ebef7c",
"334ee20108d542f0adc8f90a03639ce2",
"e90378ec97604ff7a9d210d9ab813770",
"51a10f9e1520468abe3aa8ab11b96fe4",
"8ab3c4817e1646e8997d3a7dbe2d8de0",
"c4d4e21690a8406db75c681fe5a982c3",
"d8a6c3f4dd5843808e9f892568528b2f",
"46cd6012a4764a61bc4d4afb901adfbf",
"e35dfa10dc3343498f7d99b99f8f9bbe",
"06f393835dcd46bd826335e62c32de9d",
"8e3c909019364932843a339d20f5b361",
"18dac171c82043688a6d2f181ff675db",
"49768866bcd04cd1a1d9a87bd52d8ece",
"01db3797f9bf4f538502c97de09c87d0",
"d31a76180c5049768d150c88cdb56a6d",
"876314d86ebf4879a3f831a982d6c9a0",
"5907a798063a4e5cb2c943a23eb82d70",
"acce923405544520ac3173e6d98e1c1c",
"754f2e87a56e410d961c8bb803258d22",
"f9c9e5dd77294f47b227fceea135c663",
"1145cfda26014c00a372cad81fd7292f",
"5e0aa6c336094cdcbff419ace9866327",
"bf81c8f43ac8436eaf7e4011c51a05be",
"38cef872a51f4ef499e0fd885144c593",
"b95e39b0d7304f6a8e8f3c1f539b5cfe",
"7a87c8bf911f403d92563ac4b0c8e708",
"0002e0e41c2246c8828d54ff07773cd7",
"ff569f3b6df641d48f6657e699c32c5a",
"e4f33c9295cf402e803f9f0ffa676894",
"1b167f862fa44b199524107af690eaea",
"be453dbcf0ab4bda8eb5b4586ea260df",
"f993ac5a08e948cebb08ce7b03cb1553",
"41feb9480c9d4766870aae759b13eb83",
"b331725039514bdd855459d96399b6b4",
"186c4b647c444c3a8883ad7356057d82",
"2eee9553552c424c9c2af6a203122659",
"00f97ae5e93b4b9c8a2875ad7261d920",
"bb61044a9b8d4a0b8046323b1362d5c0",
"f82665fb752e424fa74862157349de6f",
"893ed7f5802543a1a91ad502cb4604c4",
"7ed3ad5926fa416689ab21d83d3c4130",
"1d89db0e3d1e44acbf306d20b8bf38fb",
"09987e3201424e1f9958604ea336e601"
]
},
"id": "i0mlZrepRlY5",
"outputId": "1e56d95b-710a-4b33-ffee-4e4e3326e790"
},
"outputs": [],
"source": [
"cross_encoder = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "3qe0M86ERoHJ",
"outputId": "8d042ab6-4236-4adb-f0a8-4f8d3a7c65df"
},
"outputs": [],
"source": [
"top_4_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "aEpEpJGHRrQD",
"outputId": "4466a61f-3662-4d03-9068-40d5b7e8f58f"
},
"outputs": [],
"source": [
"query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pl0C674yRtFQ"
},
"outputs": [],
"source": [
"pairs = []\n",
"for doc in top_4_documents:\n",
" pairs.append([query, doc])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XTFyfLz5XXO8",
"outputId": "b47d87a7-b7b7-47f5-b535-34ee99a37f10"
},
"outputs": [],
"source": [
"pairs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "9Mo5_OHVRu0x",
"outputId": "1156480a-fecf-4491-ab6f-2ab02d7fdef6"
},
"outputs": [],
"source": [
"scores = cross_encoder.predict(pairs)\n",
"scores"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3RstDfogRwZi"
},
"outputs": [],
"source": [
"scored_docs = zip(scores, top_4_documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "M2feALlgXqnq",
"outputId": "cf780c2c-41a9-419a-e922-aab20209a2b7"
},
"outputs": [],
"source": [
"scored_docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mPmPy-XwRy6n"
},
"outputs": [],
"source": [
"reranked_document_cross_encoder = sorted(scored_docs, reverse=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "eXb2dOvwR0YR",
"outputId": "dc214e72-abaf-4f51-f9e7-e4ba0aad906a"
},
"outputs": [],
"source": [
"reranked_document_cross_encoder"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ZCb89yk6X600"
},
"source": [
"# BM_25"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "jkxrfvbSR2cz",
"outputId": "598a94dc-9cae-4d70-fac1-4553ccb64e66"
},
"outputs": [],
"source": [
"reranked_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "L9nMXBERSroy",
"outputId": "a7620b5f-c385-43a3-f6de-0efb5457dbf3"
},
"outputs": [],
"source": [
"!pip install cohere"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_a4J2-TfS2vC"
},
"outputs": [],
"source": [
"import cohere"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SdLeyOkES5OP"
},
"outputs": [],
"source": [
"co = cohere.Client(\"nbDqU1hTVxWmXGbLYI6OnYhp4Cx40MZ5hOmO5oKX\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "oG-b7zwjTJu6",
"outputId": "383724b7-6087-4623-a061-9590f515975f"
},
"outputs": [],
"source": [
"top_4_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "yb8ykLpRTMBk",
"outputId": "7b160b1a-9256-406f-ddee-6e4db54de349"
},
"outputs": [],
"source": [
"query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "FYPqN4zZS6wC"
},
"outputs": [],
"source": [
"response = co.rerank(\n",
" model=\"rerank-english-v3.0\",\n",
" query=\"Natural language processing techniques enhance keyword extraction efficiency.\",\n",
" documents=top_4_documents,\n",
" return_documents=True\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "i_PU-k1HTXbR",
"outputId": "3657e386-83be-4fa0-a2ac-e7800c11aa31"
},
"outputs": [],
"source": [
"print(response)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "j6rK9-qJTaLZ",
"outputId": "698a9024-284e-4314-c00b-13c7c5a8bfb2"
},
"outputs": [],
"source": [
"response.results[0].document.text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JhWpXlwsTcAr",
"outputId": "56c8afcf-a423-480c-917d-5b1056335b1c"
},
"outputs": [],
"source": [
"response.results[0].relevance_score"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XK91v711TdaV",
"outputId": "26a032c6-07c9-47a9-d0b1-221e5edf0c2a"
},
"outputs": [],
"source": [
"for i in range(4):\n",
" print(f'text: {response.results[i].document.text} score: {response.results[i].relevance_score}')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vHkJZ_ODTe5a"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"authorship_tag": "ABX9TyMiYSfyl0P/2phVKD60MU27",
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: Advance RAG with Hybrid Search and Reranker/Hybrid_Search_and_reranking_in_RAG.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ZHlE17nUjXnp"
},
"source": [
"https://s4ds.org/\n",
"\n",
"https://www.icdmai.org/\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "qmp_SaX69q18",
"outputId": "63596de4-d1d9-4d78-cf94-7586f314ec44"
},
"outputs": [],
"source": [
"!pip install weaviate-client"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "qQLSw3iJ_0RX",
"outputId": "d628e74a-a8de-42d2-ed1a-522acb9c3f51"
},
"outputs": [],
"source": [
"!pip install langchain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4lpn398P__vR",
"outputId": "2f217e89-f2ad-4b53-9968-dfa0d3c857ef"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RSik_tYq-JRN"
},
"outputs": [],
"source": [
"import weaviate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "M5rKS1Co-22r"
},
"outputs": [],
"source": [
"WEAVIATE_CLUSTER=\"https://hybridsearch-ewd5zpr1.weaviate.network\"\n",
"WEAVIATE_API_KEY=\"\" # Replace with your Weaviate API key"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ovLN44VY-6tU"
},
"outputs": [],
"source": [
"WEAVIATE_URL = WEAVIATE_CLUSTER\n",
"WEAVIATE_API_KEY = WEAVIATE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Z93YcxMF_iCN"
},
"outputs": [],
"source": [
"HF_TOKEN=\"\" # Replace with your Hugging Face API token"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JUDJ74Ut_N-M"
},
"outputs": [],
"source": [
"import os"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YFrBhzvM--rd"
},
"outputs": [],
"source": [
"client = weaviate.Client(\n",
" url=WEAVIATE_URL, auth_client_secret=weaviate.AuthApiKey(WEAVIATE_API_KEY),\n",
" additional_headers={\n",
" \"X-HuggingFace-Api-Key\": HF_TOKEN\n",
" },\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "LQJQDj68Cy4J",
"outputId": "ccf1aad1-8ca1-4079-b284-2f60397d0cd1"
},
"outputs": [],
"source": [
"client.is_ready()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6ouOrLG2B9wj",
"outputId": "3038912b-d5cb-4714-9803-6706392ca7cf"
},
"outputs": [],
"source": [
"client.schema.get()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9zR5jAGHC3bS"
},
"outputs": [],
"source": [
"client.schema.delete_all()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7l8nTgbRDCWt"
},
"outputs": [],
"source": [
"schema = {\n",
" \"classes\": [\n",
" {\n",
" \"class\": \"RAG\",\n",
" \"description\": \"Documents for RAG\",\n",
" \"vectorizer\": \"text2vec-huggingface\",\n",
" \"moduleConfig\": {\"text2vec-huggingface\": {\"model\": \"sentence-transformers/all-MiniLM-L6-v2\", \"type\": \"text\"}},\n",
" \"properties\": [\n",
" {\n",
" \"dataType\": [\"text\"],\n",
" \"description\": \"The content of the paragraph\",\n",
" \"moduleConfig\": {\n",
" \"text2vec-huggingface\": {\n",
" \"skip\": False,\n",
" \"vectorizePropertyName\": False,\n",
" }\n",
" },\n",
" \"name\": \"content\",\n",
" },\n",
" ],\n",
" },\n",
" ]\n",
"}\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XxlykBOsD4oW"
},
"outputs": [],
"source": [
"client.schema.create(schema)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "boKhfW7xD8je",
"outputId": "6dec38eb-ab67-428a-c5fa-79849de612f5"
},
"outputs": [],
"source": [
"client.schema.get()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9fYFxszF_lTL"
},
"outputs": [],
"source": [
"from langchain.retrievers.weaviate_hybrid_search import WeaviateHybridSearchRetriever"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xDD_FAKZ_sZK"
},
"outputs": [],
"source": [
"retriever = WeaviateHybridSearchRetriever(\n",
" alpha = 0.5, # defaults to 0.5, which is equal weighting between keyword and semantic search\n",
" client = client, # keyword arguments to pass to the Weaviate client\n",
" index_name = \"RAG\", # The name of the index to use\n",
" text_key = \"content\", # The name of the text key to use\n",
" attributes = [], # The attributes to return in the results\n",
" create_schema_if_missing=True,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RJLYAGHbE1Z5"
},
"outputs": [],
"source": [
"model_name = \"HuggingFaceH4/zephyr-7b-beta\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1w6ml1DsEv-q",
"outputId": "235602d0-14da-4ebb-fd21-fe314ed872c5"
},
"outputs": [],
"source": [
"!pip install bitsandbytes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "LtJsxhOmEzWX",
"outputId": "ceb6003d-d09d-4e19-90fe-beb540912dc7"
},
"outputs": [],
"source": [
"!pip install accelerate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7YcsnAveEiFy"
},
"outputs": [],
"source": [
"import torch\n",
"from transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, pipeline, )\n",
"from langchain import HuggingFacePipeline"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Yflg19-qEiJs"
},
"outputs": [],
"source": [
"# function for loading 4-bit quantized model\n",
"def load_quantized_model(model_name: str):\n",
" \"\"\"\n",
" model_name: Name or path of the model to be loaded.\n",
" return: Loaded quantized model.\n",
" \"\"\"\n",
" bnb_config = BitsAndBytesConfig(\n",
" load_in_4bit=True,\n",
" bnb_4bit_use_double_quant=True,\n",
" bnb_4bit_quant_type=\"nf4\",\n",
" bnb_4bit_compute_dtype=torch.bfloat16,\n",
" low_cpu_mem_usage=True\n",
" )\n",
"\n",
" model = AutoModelForCausalLM.from_pretrained(\n",
" model_name,\n",
" torch_dtype=torch.bfloat16,\n",
" quantization_config=bnb_config,\n",
" )\n",
" return model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Pfdzn1ukEiMd"
},
"outputs": [],
"source": [
"# initializing tokenizer\n",
"def initialize_tokenizer(model_name: str):\n",
" \"\"\"\n",
" model_name: Name or path of the model for tokenizer initialization.\n",
" return: Initialized tokenizer.\n",
" \"\"\"\n",
" tokenizer = AutoTokenizer.from_pretrained(model_name, return_token_type_ids=False)\n",
" tokenizer.bos_token_id = 1 # Set beginning of sentence token id\n",
" return tokenizer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "a8UgT93sEiQK"
},
"outputs": [],
"source": [
"tokenizer = initialize_tokenizer(model_name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 104,
"referenced_widgets": [
"1a3922c925d243fe825c2fdffc1ac440",
"848a9e20a5ff46329ac18f0f168a5d52",
"3c0f9911a51648cb8be3aaf49a806575",
"3f634bcca28549c8b922c73c7b475d91",
"25ddfbae30f74ca6b5baf5cc1d94bcb1",
"de412a1000a94bea8707e1cdc8d805b7",
"65283aca47324d5b917ba33f61e2f240",
"7a27e7b7ea6045a7a855237fd2a009e8",
"e85f3538253c482eb76e42e6341abb83",
"791e2040d86848d6be8fbc486e8ab8b5",
"201266a8824041118a32f623036eb633"
]
},
"id": "Csv9lG6cErbb",
"outputId": "1984deee-8c48-49af-bd66-9ee1d3018221"
},
"outputs": [],
"source": [
"model = load_quantized_model(model_name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 446
},
"id": "IplrZgxvEreX",
"outputId": "82543b1a-a0bf-4693-e975-98fce166013b"
},
"outputs": [],
"source": [
"pipeline = pipeline(\n",
" \"text-generation\",\n",
" model=model,\n",
" tokenizer=tokenizer,\n",
" use_cache=True,\n",
" device_map=\"auto\",\n",
" #max_length=2048,\n",
" do_sample=True,\n",
" top_k=5,\n",
" max_new_tokens=100,\n",
" num_return_sequences=1,\n",
" eos_token_id=tokenizer.eos_token_id,\n",
" pad_token_id=tokenizer.pad_token_id,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Uo348jKvErhO"
},
"outputs": [],
"source": [
"llm = HuggingFacePipeline(pipeline=pipeline)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "uva-5Nkqpr8w"
},
"outputs": [],
"source": [
"doc_path=\"/content/Retrieval-Augmented-Generation-for-NLP.pdf\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "BTNRvdSNp9jC",
"outputId": "68d151fe-ac47-4e64-9d56-7cabd3fb2c50"
},
"outputs": [],
"source": [
"!pip install pypdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ev8_SeQIp_4A",
"outputId": "f4dc1edd-7f8d-4d60-da77-96284597c657"
},
"outputs": [],
"source": [
"!pip install langchain_community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3n-7-QWyp_8x"
},
"outputs": [],
"source": [
"from langchain_community.document_loaders import PyPDFLoader"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nhBRpl8dsHw6"
},
"outputs": [],
"source": [
"loader = PyPDFLoader(doc_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xHegGUGssHzV"
},
"outputs": [],
"source": [
"docs = loader.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gpshkBhjvLlC",
"outputId": "6fa66ef9-f60c-4e6a-ad16-0d1464f27246"
},
"outputs": [],
"source": [
"docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6DNTiAvgvNYC",
"outputId": "3bc37592-d65b-473e-ae39-ec0dd2b79c40"
},
"outputs": [],
"source": [
"docs[6]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Ux831sq2pq3C",
"outputId": "3ee30aa3-f465-4d02-e4ea-4a2e07b6bc69"
},
"outputs": [],
"source": [
"retriever.add_documents(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "jRoDhLHjsy5f",
"outputId": "9e1b9921-2fe7-4549-dfa0-b64fef8da144"
},
"outputs": [],
"source": [
"print(retriever.invoke(\"what is RAG token?\")[0].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "WHdda33buBrS",
"outputId": "843cffb4-caad-4033-97ce-e43c4035e3b3"
},
"outputs": [],
"source": [
"retriever.invoke(\n",
" \"what is RAG token?\",\n",
" score=True\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Vt5vaVuLEdY9"
},
"outputs": [],
"source": [
"from langchain.chains import RetrievalQA"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "HkhbVjqiMJXJ"
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "heu-l-l176Pp"
},
"outputs": [],
"source": [
"from langchain_core.prompts import ChatPromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RrEl6Nm87_Vi"
},
"outputs": [],
"source": [
"system_prompt = (\n",
" \"Use the given context to answer the question. \"\n",
" \"If you don't know the answer, say you don't know. \"\n",
" \"Use three sentence maximum and keep the answer concise. \"\n",
" \"Context: {context}\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Gg0TRf_Q72P6"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_messages(\n",
" [\n",
" (\"system\", system_prompt),\n",
" (\"human\", \"{query}\"),\n",
" ]\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GNPZSFun-4Ka"
},
"outputs": [],
"source": [
"from langchain.prompts import PromptTemplate\n",
"template = \"\"\"\n",
"Use the following pieces of context to answer the question at the end.\n",
"If you don't know the answer, just say that you do not have the relevant information needed to provide a verified answer, don't try to make up an answer.\n",
"When providing an answer, aim for clarity and precision. Position yourself as a knowledgeable authority on the topic, but also be mindful to explain the information in a manner that is accessible and comprehensible to those without a technical background.\n",
"Always say \"Do you have any more questions pertaining to this instrument?\" at the end of the answer.\n",
"{context}\n",
"Question: {question}\n",
"Helpful Answer:\"\"\"\n",
"\n",
"prompt = PromptTemplate.from_template(template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Q3lt9jMW8hxK"
},
"outputs": [],
"source": [
"from langchain.chains.combine_documents import create_stuff_documents_chain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ppRiYOIa8b6y"
},
"outputs": [],
"source": [
"question_answer_chain = create_stuff_documents_chain(llm, prompt)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3t7fVtBaAOfq"
},
"outputs": [],
"source": [
"hybrid_chain = RetrievalQA.from_chain_type(llm=llm, chain_type=\"stuff\", retriever=retriever,)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "I0DfMLiJ6lbr",
"outputId": "29e93eae-37ce-48b4-8c49-dd04a7195edc"
},
"outputs": [],
"source": [
"result1 = hybrid_chain.invoke(\"what is natural language processing?\")\n",
"print(result1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Flsjn21WMypT",
"outputId": "3e4d6073-bfd3-4c31-b08c-d5fe399e8935"
},
"outputs": [],
"source": [
"print(result1['result'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "QhG3Krz99APy"
},
"outputs": [],
"source": [
"query=\"What is Abstractive Question Answering?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 304
},
"id": "hmmRp1O_ArC9",
"outputId": "e56e99d7-4ddf-460a-e5a7-330b968d5cf6"
},
"outputs": [],
"source": [
"response = hybrid_chain.invoke({\"query\":query})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LZ-Id5sW-LLR"
},
"outputs": [],
"source": [
"from langchain_core.runnables import RunnableParallel, RunnablePassthrough"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "b1DvxugA-DIC"
},
"outputs": [],
"source": [
"# Set up the RAG chain\n",
"rag_chain = (\n",
" {\"context\": retriever, \"question\": RunnablePassthrough()} |\n",
" prompt |\n",
" llm\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "OTU5Wycg-l9y"
},
"outputs": [],
"source": [
"query=\"what is RAG token?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ykAekNO_-bkZ",
"outputId": "140e6b43-ffac-43f3-c2bd-17959f6dea91"
},
"outputs": [],
"source": [
"response=rag_chain.invoke(\"what is RAG token?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "iqKKvHQ-_05x",
"outputId": "a07f9be8-c605-4902-e957-7a005e296185"
},
"outputs": [],
"source": [
"print(response)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "KWe11B_3H6Yc",
"outputId": "08ac50fc-d407-4647-d7ac-ce0b786e5dd1"
},
"outputs": [],
"source": [
"response"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "_Y6DcD3Z5lZp",
"outputId": "f792675c-237c-4e08-9f09-ed5229d4dad5"
},
"outputs": [],
"source": [
"print(response[\"result\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0A3hrUdwJ3pC"
},
"outputs": [],
"source": [
"from langchain.retrievers import ContextualCompressionRetriever\n",
"from langchain.retrievers.document_compressors import CohereRerank"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1VewE8gRKCla",
"outputId": "48c1abc0-eb81-4bec-ada4-00c316b18120"
},
"outputs": [],
"source": [
"!pip install cohere"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "OE0vUax4J-Ij"
},
"outputs": [],
"source": [
"compressor = CohereRerank(cohere_api_key=\"\") # Replace with your Cohere API key"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "b3Kmr4CIKG7n"
},
"outputs": [],
"source": [
"compression_retriever = ContextualCompressionRetriever(\n",
" base_compressor=compressor, base_retriever=retriever\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "f7m22qlCiUAb"
},
"outputs": [],
"source": [
"compressed_docs = compression_retriever.get_relevant_documents(user_query)\n",
"# Print the relevant documents from using the embeddings and reranker\n",
"print(compressed_docs)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0dKqM3XbKkE4"
},
"outputs": [],
"source": [
"hybrid_chain = RetrievalQA.from_chain_type(\n",
" llm=llm, chain_type=\"stuff\", retriever=compression_retriever\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "2N2k_RCmKAIL",
"outputId": "466dc508-4180-48d4-f167-fd267628dd92"
},
"outputs": [],
"source": [
"response = hybrid_chain.invoke(\"What is Abstractive Question Answering?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "DVJxJg-bK2pg",
"outputId": "9ee8590f-6350-4821-cb51-e497e4a020c0"
},
"outputs": [],
"source": [
"print(response.get(\"result\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8Wa3jBEgLwXB",
"outputId": "d5e1a29a-5969-4ff2-d147-cdd49d2f7ed0"
},
"outputs": [],
"source": [
"print(response.get(\"result\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tcdaBC5gMCzh"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: Chat with Multiple Doc using Astradb and Langchain/Chat_With_Multiple_Doc(pdfs,_docs,_txt,_pptx)_using_AstraDB_and_Langchain.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9RDOffvrZ3F4"
},
"outputs": [],
"source": [
"!pip install langchain\n",
"!pip install unstructured\n",
"!pip install openai\n",
"!pip install Cython\n",
"!pip install tiktoken"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "i929xxKLnRgr",
"outputId": "a3e71b8a-85a9-4dc0-c259-c19cb5039baf"
},
"outputs": [],
"source": [
"!pip install --upgrade langchain-astradb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "IWdY3uvRnZKn",
"outputId": "4fadc829-460e-410d-fc7d-f4013ee62966"
},
"outputs": [],
"source": [
"!pip install langchain langchain-openai datasets pypdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "B6oJrqqRauvY"
},
"outputs": [],
"source": [
"!pip install pdf2image"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Ox_1QUszavjV"
},
"outputs": [],
"source": [
"!pip install pdfminer.six"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fvp_dAEWayjg"
},
"outputs": [],
"source": [
"!pip install unstructured[pdf]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gPuH-fXlnaiX"
},
"outputs": [],
"source": [
"import os\n",
"from getpass import getpass\n",
"\n",
"from datasets import (\n",
" load_dataset,\n",
")\n",
"from langchain_community.document_loaders import PyPDFLoader\n",
"from langchain_core.documents import Document\n",
"from langchain_core.output_parsers import StrOutputParser\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_core.runnables import RunnablePassthrough\n",
"from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n",
"from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
"from langchain.document_loaders import UnstructuredPDFLoader\n",
"from langchain.indexes import VectorstoreIndexCreator"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Bost4y11ngS2"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n",
"\n",
"embedding = OpenAIEmbeddings()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gXD1e0iknq9m"
},
"outputs": [],
"source": [
"embedding = OpenAIEmbeddings()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "BhXC2nsaaao4"
},
"source": [
"# Using Unstructured for loading Multiple Pdfs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "obMEfgOUaYoI"
},
"outputs": [],
"source": [
"root_dir=\"/content/\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fHwmBphmaMrJ"
},
"outputs": [],
"source": [
"pdf_folder_path = f'{root_dir}/docs/'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EXg7WYjmaMx6"
},
"outputs": [],
"source": [
"os.listdir(pdf_folder_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gdyyz5uDbF65"
},
"outputs": [],
"source": [
"# location of the pdf file/files.\n",
"loaders = [UnstructuredPDFLoader(os.path.join(pdf_folder_path, fn)) for fn in os.listdir(pdf_folder_path)]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cIOOjInebHHR"
},
"outputs": [],
"source": [
"loaders"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "C6sNGjHsaM05"
},
"outputs": [],
"source": [
"index = VectorstoreIndexCreator().from_loaders(loaders)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TyONx7bRaM6q"
},
"outputs": [],
"source": [
"index.query('What is the tokenization in RAG?')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1kCaJmvhaM9o"
},
"outputs": [],
"source": [
"index.query_with_sources('What is the tokenization in RAG?')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2X3IRcpxbSKZ"
},
"source": [
"# Pypdf loader with Multiple Pdfs."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "btAgdVVknvyd"
},
"outputs": [],
"source": [
"from langchain_astradb import AstraDBVectorStore"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "DgLFd0Kd2nIO"
},
"outputs": [],
"source": [
"from langchain_astradb import AstraDBVectorStore\n",
"ASTRA_DB_API_ENDPOINT=\"https://d2357619-8f04-4cfd-bc3a-16e410893ba3-us-east-2.apps.astra.datastax.com\"\n",
"ASTRA_DB_APPLICATION_TOKEN=\"ASTRA_TOKEN_REMOVEDhTmlZSqmAOUHSWZaeNqzEDOR:1128826e960e49c2508b3014ae7fa40e6b5d0490d8565702a30b4ea338083a4a\"\n",
"ASTRA_DB_KEYSPACE=\"default_keyspace\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fLh8RfMwaNLM"
},
"outputs": [],
"source": [
"root_dir=\"/content/\"\n",
"pdf_folder_path = f'{root_dir}/data/'\n",
"pdfs=os.listdir(pdf_folder_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Quw8romYBEpV",
"outputId": "d3a645f6-8cce-4d4a-b0c5-3d35f2ae51ae"
},
"outputs": [],
"source": [
"pdfs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "iGWaBKx7BSiP"
},
"outputs": [],
"source": [
"data=PyPDFLoader(\"/content/data/MachineTranslationwithAttention.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Z4Y6bmItBhbB",
"outputId": "0ba46137-2b3e-42b7-90ae-b9afefcad5b4"
},
"outputs": [],
"source": [
"data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "u280YuAtCCzX"
},
"outputs": [],
"source": [
"splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "NRH8dsh5B-n9",
"outputId": "c092b97a-84e9-4605-bf8b-010ee09482c8"
},
"outputs": [],
"source": [
"data.load_and_split(text_splitter=splitter)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hK6CgClrbbS5"
},
"outputs": [],
"source": [
"docs=[]\n",
"for pdf in pdfs:\n",
" data=PyPDFLoader(f\"/content/data/{pdf}\")\n",
" docs.append(data)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 158
},
"id": "agk6IZLabd3p",
"outputId": "ffdbaa2b-58a4-406f-c781-a9a9fa2b20c7"
},
"outputs": [],
"source": [
"\n",
"docs_from_pdf = docs.load_and_split(text_splitter=splitter)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "oNllVkvIbgKM"
},
"outputs": [],
"source": [
"print(f\"Documents from PDF: {len(docs_from_pdf)}.\")\n",
"inserted_ids_from_pdf = vstore.add_documents(docs_from_pdf)\n",
"print(f\"Inserted {len(inserted_ids_from_pdf)} documents.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "n4G743wn3i9F"
},
"outputs": [],
"source": [
"vstore = AstraDBVectorStore(\n",
" embedding=embedding,\n",
" collection_name=\"astra_vector_demo\",\n",
" api_endpoint=ASTRA_DB_API_ENDPOINT,\n",
" token=ASTRA_DB_APPLICATION_TOKEN,\n",
" namespace=ASTRA_DB_KEYSPACE,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cfzD7a8naIEK"
},
"outputs": [],
"source": [
"retriever = vstore.as_retriever(search_kwargs={\"k\": 3})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9Y2EFU9_aINQ"
},
"outputs": [],
"source": [
"prompt_template = \"\"\"\n",
"You are a philosopher that draws inspiration from great thinkers of the past\n",
"to craft well-thought answers to user questions. Use the provided context as the basis\n",
"for your answers and do not make up new reasoning paths - just mix-and-match what you are given.\n",
"Your answers must be concise and to the point, and refrain from answering about other topics than philosophy.\n",
"\n",
"CONTEXT:\n",
"{context}\n",
"\n",
"QUESTION: {question}\n",
"\n",
"YOUR ANSWER:\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Nx0rM706aIPo"
},
"outputs": [],
"source": [
"prompt_template = ChatPromptTemplate.from_template(prompt_template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tRg2VFehaISq"
},
"outputs": [],
"source": [
"llm = ChatOpenAI()\n",
"\n",
"chain = (\n",
" {\"context\": retriever, \"question\": RunnablePassthrough()}\n",
" | philo_prompt\n",
" | llm\n",
" | StrOutputParser()\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "D9pg2syhbyHI"
},
"outputs": [],
"source": [
"chain.invoke(\"How does Russel elaborate on Peirce's idea of the security blanket?\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "v2b452jhb6mh"
},
"source": [
"# Directory loders(Chat With Multiple Doc)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tZS1rEQB7YOP"
},
"outputs": [],
"source": [
"!rm -rf \"/content/docs/.ipynb_checkpoints\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1yqDtZ1M3z8U",
"outputId": "1602047a-f75d-4544-e49d-d1ea5405e3f6"
},
"outputs": [],
"source": [
"%pip install langchain_community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1UuNkzrU5Q5q",
"outputId": "3f4e6178-064f-406e-cf4a-909229fb3da6"
},
"outputs": [],
"source": [
"!pip install unstructured"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "ksK7gi4p5d1l",
"outputId": "dc8ba9fb-b8fd-46cc-b38c-ebbafca693c7"
},
"outputs": [],
"source": [
"!pip install \"unstructured[pdf]\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "3uk7ezbu7OQp",
"outputId": "1bbf4d20-f90d-4247-b38f-bbab19599190"
},
"outputs": [],
"source": [
"!sudo apt-get update"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "nkesIO_m7P9P",
"outputId": "0c321129-5b04-4a63-fded-445eab6bb4a2"
},
"outputs": [],
"source": [
"!sudo apt-get install poppler-utils"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "o9OycnSq7Tt9",
"outputId": "689a781d-dfb9-4c9d-d386-9f17804a3006"
},
"outputs": [],
"source": [
"!sudo apt-get install libleptonica-dev tesseract-ocr libtesseract-dev python3-pil tesseract-ocr-eng tesseract-ocr-script-latn\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "TMP99Q_y7XWl",
"outputId": "38690471-e581-4be4-d99c-9e5f0d07f120"
},
"outputs": [],
"source": [
"!pip install unstructured-pytesseract\n",
"!pip install tesseract-ocr"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RruMFEmtMhVw",
"outputId": "12220b5c-ef1f-451d-997d-9283aa4cbb84"
},
"outputs": [],
"source": [
"!pip install \"unstructured[pptx]\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "DR8YmEFX_bXo",
"outputId": "6fbcfd3f-9d50-44b7-c210-7b2bc74abb06"
},
"outputs": [],
"source": [
"!pip install langchain_astradb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4rN3g_sxPLjN",
"outputId": "93096ee0-bcca-4233-a170-ee4a68ad727e"
},
"outputs": [],
"source": [
"!pip install langchain langchain-openai datasets pypdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AjAFSJYlDpkA"
},
"outputs": [],
"source": [
"from langchain_text_splitters import RecursiveCharacterTextSplitter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nBVPhAdPDNE3"
},
"outputs": [],
"source": [
"from langchain_community.document_loaders import DirectoryLoader\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GYA9S1oaU1g3"
},
"outputs": [],
"source": [
"loader = DirectoryLoader('/content/docs')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "icOls_EgDQy_"
},
"outputs": [],
"source": [
"splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 304,
"referenced_widgets": [
"8e035199e06b40eabbe34b3852c53034",
"75777df2725d4509adaddc144ee52baa",
"61c802dc2e7a486e91ed26b43a579a65",
"9123e7f5130a4f498130e117726e8430",
"2ed0f1ed939949518905dbcd850f9ee8",
"73d7a2d3325a469c89c275c0d6912551",
"7cf8bdbebd52448bb8444099cfb70886",
"0fb6312ab0b94e92a8989059794038ce",
"bcc6d619f2ce49b6bb2ad45099d229a2",
"80b344425b2e46868c6988d0b6bf0a60",
"f12e15d72d634c8ba643a468f4d76735",
"4e840cdb44a44a99b851cbe1673db6b5",
"4f02de36c68c4a12978129ce6856a104",
"c2f04856ddcb4fd1bbc1ead4274ce0aa",
"bc28ccf6311547daaa88e14861fc653d",
"8e12ba7b025e42b09bff0115dd840e49",
"b4207375ca9442d9b88cbaa5810f5041",
"51fb8e49361e48479028d3112a4bcd90",
"6216f9fd90b44c97bc251ad1b554047d",
"64e9f9d5e7504dbea334234d4788089d",
"0b912a2a673f4daea2da687bb94547c6",
"e4d2f8a121c54c49b681a767ac1fc3b1",
"8adde71b0962495c80261b2dd1d4abf3",
"9596bb6c2fa149b4945ab2d10e207e84",
"bcd1278264fa44518f09164105271b22",
"93edc57d3b134be88f4b5d0fdf12ebbc",
"88c95ef5ee33412c8141ffc7c11c702e",
"af1fea75b14f4b0a936513c4f3074fbc",
"3f9760917bcf4e249f16f34a2361b73c",
"037f7836ab6f465caf2b87dc5b7aef63",
"829923a46f24479ea648945c677d9e3a",
"db4ea8e3882c493cb980e9dfd8151a84",
"a67ed49aae1544e3b5a9b141d1c5dd3e",
"9d9f277060934802932d690307fc9685",
"1a3c537f212645fda454ffa103aac256",
"1646ce29bbb5425a9262a009f7fa2a13",
"3b8846ae905f4b7683e4f5e422e21f75",
"5b9853b590fe415fb559ae396a7bc3c7",
"f63494b47dbe412cb82f29a350cbbbc2",
"12d2ab6a477e4b94a83dae2651c6fb4b",
"d7e400593ed24394a24fb07c069b83c9",
"bc2a5e16203d4c83a976cd85e9622467",
"5b38a4d2ed5b4078b13b8397d6439ae8",
"c38f90a27964497db1c6f500510b4c03"
]
},
"id": "gXfYNkYx5Lx7",
"outputId": "7097f252-1c7e-45e2-bf13-044263056b27"
},
"outputs": [],
"source": [
"docs = loader.load_and_split(text_splitter=splitter)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "uaBLlukoN1in",
"outputId": "91fbb728-e2b2-4eb1-e6e1-25531fcb53a9"
},
"outputs": [],
"source": [
"len(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "irbe3D7R_J_n"
},
"outputs": [],
"source": [
"import os\n",
"from langchain_core.documents import Document\n",
"from langchain_community.document_loaders import PyPDFLoader\n",
"\n",
"from langchain_core.output_parsers import StrOutputParser\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_core.runnables import RunnablePassthrough\n",
"from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YoyE7fpl_pDB"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mVnI4Sc5_pxr"
},
"outputs": [],
"source": [
"embedding = OpenAIEmbeddings()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8TCV0FA2YwxY"
},
"outputs": [],
"source": [
"from langchain_astradb import AstraDBVectorStore\n",
"from langchain.indexes import VectorstoreIndexCreator"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "KLWvXEYS_WGA"
},
"outputs": [],
"source": [
"ASTRA_DB_API_ENDPOINT=\"https://79b63042-b3d1-4163-b10a-75c9979ebf59-us-east-2.apps.astra.datastax.com\"\n",
"ASTRA_DB_APPLICATION_TOKEN=\"ASTRA_TOKEN_REMOVEDRyuexWdwLrGymMZnubGtbuZq:b7e36eae7d7f021e542f9f8b541a4ccdd7a5705e077b18887579f56bb0955ad4\"\n",
"ASTRA_DB_KEYSPACE=\"default_keyspace\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qwf9jP-mFsho"
},
"outputs": [],
"source": [
"vstore = AstraDBVectorStore(\n",
" embedding=embedding,\n",
" collection_name=\"multidoc_vector\",\n",
" api_endpoint=ASTRA_DB_API_ENDPOINT,\n",
" token=ASTRA_DB_APPLICATION_TOKEN,\n",
" namespace=ASTRA_DB_KEYSPACE,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PB0OTyiPZYtj"
},
"outputs": [],
"source": [
"inserted_ids = vstore.add_documents(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MCZF7rhmOEBQ",
"outputId": "3f41cd26-3df0-4d85-859e-a1815abaf89e"
},
"outputs": [],
"source": [
"print(f\"\\nInserted {len(inserted_ids)} documents.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "U8IkQRVzF9pP"
},
"outputs": [],
"source": [
"prompt_template = \"\"\"\n",
"You are an AI philosopher drawing insights from the roadmap of \"rag,\" \"llama3,\" and \"genai.\"\n",
"Craft thoughtful answers based on this roadmap, mixing and matching existing paths.\n",
"Your responses should be concise and strictly related to the provided context.\n",
"\n",
"ROADMAP CONTEXT:\n",
"{context}\n",
"\n",
"QUESTION: {question}\n",
"\n",
"YOUR ANSWER:\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "DQp4n2tCG-F_"
},
"outputs": [],
"source": [
"prompt_template = ChatPromptTemplate.from_template(prompt_template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "HLTlpaHDGg6n"
},
"outputs": [],
"source": [
"retriever = vstore.as_retriever(search_kwargs={\"k\": 3})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "QdvsgC2UG2F4",
"outputId": "82af6575-982b-4b13-efe5-c35b6e23d109"
},
"outputs": [],
"source": [
"retriever"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "jp8EyMrWGxUx"
},
"outputs": [],
"source": [
"llm = ChatOpenAI()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7HITJ2t3GtNf"
},
"outputs": [],
"source": [
"chain = (\n",
" {\"context\": retriever, \"question\": RunnablePassthrough()}\n",
" | prompt_template\n",
" | llm\n",
" | StrOutputParser()\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 87
},
"id": "uYnIVzpTcauK",
"outputId": "fdf2ab30-f628-4b8b-d02e-5c8140c8d701"
},
"outputs": [],
"source": [
"chain.invoke(\"can you tell me the roadmap of generative ai?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 87
},
"id": "jVag171QaHi2",
"outputId": "b99cd96e-c72d-4d74-9f71-c1801cbd76ba"
},
"outputs": [],
"source": [
"chain.invoke(\"what is a llama can you tell me some important point on top of it.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "M0NfhTCIaRMF"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: Child_to_Parent_Retrieval.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "o7u2h6FLqlhE"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "wfE3n6CrrnvD"
},
"source": [
"# Parent Document Retriever\n",
"\n",
"which issue this parent-child retrieval will solve.\n",
"\n",
"You may want to have small documents, so that their embeddings can most accurately reflect their meaning. If too long, then the embeddings can lose meaning.\n",
"\n",
"You want to have long enough documents that the context of each chunk is retained.\n",
"\n",
"The ParentDocumentRetriever strikes that balance by splitting and storing small chunks of data. During retrieval, it first fetches the small chunks but then looks up the parent ids for those chunks and returns those larger documents.\n",
"\n",
"Note that \"parent document\" refers to the document that a small chunk originated from. This can either be the whole raw document OR a larger chunk."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "G4ayMTWunxMO",
"outputId": "cd1eee99-fdde-4282-87b5-ac6c08fb82f3"
},
"outputs": [],
"source": [
"!pip install langchain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ii1EIj8gD5tS",
"outputId": "8c5a3ec6-f553-451d-e970-9ecbe0e6e25a"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tfjfXJr1D5vs",
"outputId": "7c44ade3-687d-4f1b-d2e1-74155f4a8b3a"
},
"outputs": [],
"source": [
"!pip install sentence-transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "m3xnoTsMD5yQ",
"outputId": "47f1b53a-bdff-4057-d5cc-e9a4910ac681"
},
"outputs": [],
"source": [
"!pip install langchain_chroma"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "VskBgo9gGAlO"
},
"outputs": [],
"source": [
"####if you want to use gemini feel free to use this code.\n",
"\n",
"%pip install --upgrade --quiet google-generativeai langchain-google-genai"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2xJdEql4oqCc"
},
"source": [
"# Data Ingestion"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Eh9IIWPsowTD"
},
"outputs": [],
"source": [
"from langchain_community.document_loaders import TextLoader"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Z-zV6y-powVj"
},
"outputs": [],
"source": [
"loaders = [\n",
" TextLoader(\"/content/data/paul_graham_essay.txt\"),\n",
" TextLoader(\"/content/data/state_of_the_union.txt\"),\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "obRj2p23EwPv"
},
"outputs": [],
"source": [
"docs = []"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zT9DHChvowYL"
},
"outputs": [],
"source": [
"for loader in loaders:\n",
" docs.extend(loader.load())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "SYT5-y2wowaj",
"outputId": "c89b2637-2acd-4eb4-accd-f0257ee542f4"
},
"outputs": [],
"source": [
"docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "sLtZhaDnFUDL"
},
"outputs": [],
"source": [
"# This text splitter is used to create the child documents\n",
"from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
"child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "l_x04zdrowdD"
},
"outputs": [],
"source": [
"from langchain.storage import InMemoryStore\n",
"from langchain_chroma import Chroma"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "WtPMrD6nog-P"
},
"source": [
"**Dataset size:** Larger datasets generally benefit from more powerful models like MPNet.\n",
"\n",
"**Computational resources:** If you have limited resources, BGE Small En or MiniLM might be better options.\n",
"\n",
"**Task complexity:** For complex tasks like question answering or text summarization, MPNet is often preferred.\n",
"\n",
"**Embedding dimensionality:** Different models produce embeddings of varying dimensions.Choose based on downstream task requirements.\n",
"\n",
"**Performance vs. efficiency trade-off:** Decide if you prioritize high accuracy or faster processing\n",
"\n",
"#####Experimentation is key. Try different models and evaluate their performance on your specific task and dataset to find the best fit.\n",
"\n",
"MTEB: Massive Text Embedding Benchmark\n",
"\n",
"MPNET: Masked and Permuted Pre-training for Language Understanding.\n",
"\n",
"BGE(BAAI general embedding)\n",
"BAAI: https://huggingface.co/BAAI\n",
"\n",
"https://huggingface.co/sentence-transformers\n",
"\n",
"https://huggingface.co/spaces/mteb/leaderboard\n",
"\n",
"https://huggingface.co/blog/mteb\n",
"\n",
"#### The all-mpnet-base-v2 model provides the best quality, while all-MiniLM-L6-v2 is 5 times faster and still offers good quality."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "o1O5hxRCHevP"
},
"outputs": [],
"source": [
"'''# specify embedding model (using huggingface sentence transformer)\n",
"from langchain.embeddings import HuggingFaceEmbeddings\n",
"embedding_model_name = \"sentence-transformers/all-mpnet-base-v2\"\n",
"model_kwargs = {\"device\": \"cuda\"}\n",
"embeddings = HuggingFaceEmbeddings(\n",
" model_name=embedding_model_name,\n",
" model_kwargs=model_kwargs\n",
")'''"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "C5NFA0cMHF9u"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"\n",
"GOOGLE_API_KEY = userdata.get('GOOGLE_API_KEY')\n",
"os.environ[\"GOOGLE_API_KEY\"] = GOOGLE_API_KEY\n",
"\n",
"from langchain_google_genai import GoogleGenerativeAIEmbeddings\n",
"gemini_embeddings = GoogleGenerativeAIEmbeddings(model=\"models/embedding-001\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "wHnoDNOaE8nS"
},
"outputs": [],
"source": [
"vectorstore = Chroma(\n",
" collection_name=\"full_documents\", embedding_function=gemini_embeddings\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4YRLmyMmE8p-"
},
"outputs": [],
"source": [
"store = InMemoryStore()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "z0TRe_yxE8sg"
},
"outputs": [],
"source": [
"from langchain.retrievers import ParentDocumentRetriever\n",
"retriever = ParentDocumentRetriever(\n",
" vectorstore=vectorstore,\n",
" docstore=store,\n",
" child_splitter=child_splitter,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3yQp2lzZFOoP"
},
"outputs": [],
"source": [
"retriever.add_documents(docs, ids=None)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GXrbdq3vpyQs",
"outputId": "80ac07d5-e38f-4337-9c97-74ea085012a3"
},
"outputs": [],
"source": [
"list(store.yield_keys())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nOwg2zSnp6E7"
},
"outputs": [],
"source": [
"retrieved_docs= retriever.invoke(\"What did the president say about Ketanji Brown Jackson\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Xo0wX26Ap6Hc",
"outputId": "5171b01e-b1c6-4cef-cf24-3511cea9b60b"
},
"outputs": [],
"source": [
"print(retrieved_docs[0].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "qa5Uakyip6J7",
"outputId": "bf19c244-db05-4054-d69c-ddd3c508abca"
},
"outputs": [],
"source": [
"print(len(retrieved_docs[0].page_content))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UQREOCakp6O8"
},
"outputs": [],
"source": [
"# It should create documents smaller than the parent\n",
"child_splitter = RecursiveCharacterTextSplitter(chunk_size=500)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "G6L0oYSXp6Rz"
},
"outputs": [],
"source": [
"# This text splitter is used to create the parent documents\n",
"parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "-hKUDmJrJLes"
},
"outputs": [],
"source": [
"# The storage layer for the parent documents\n",
"store1 = InMemoryStore()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7mrkzvizJToH"
},
"outputs": [],
"source": [
"vectorstore1 = Chroma(\n",
" collection_name=\"full_documents\", embedding_function=gemini_embeddings\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3YFmtO5rp6U0"
},
"outputs": [],
"source": [
"retriever2 = ParentDocumentRetriever(\n",
" vectorstore=vectorstore1,\n",
" docstore=store1,\n",
" child_splitter=child_splitter,\n",
" parent_splitter=parent_splitter,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bayGpg5pp6XT"
},
"outputs": [],
"source": [
"retriever2.add_documents(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gIUPIp15p6Z7",
"outputId": "72e36fa6-9a92-4e53-c69c-b2badac6fb55"
},
"outputs": [],
"source": [
"len(list(store1.yield_keys()))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "D4UoqeZ-p6cL",
"outputId": "bea06635-b17b-49b1-b09e-af3e58440c91"
},
"outputs": [],
"source": [
"len(list(store.yield_keys()))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "t5gyMvXhp6ej"
},
"outputs": [],
"source": [
"retrieved_docs2= retriever2.invoke(\"What did the president say about Ketanji Brown Jackson\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "TEta4Oq4J63m",
"outputId": "8fc8834c-ca52-4e56-f41f-6e3d6ea6e54f"
},
"outputs": [],
"source": [
"retrieved_docs2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "45c3gP25JzpT",
"outputId": "f20a5cc1-be08-4c0f-8107-43e9d2520c3b"
},
"outputs": [],
"source": [
"len(retrieved_docs2[0].page_content)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Dh5TRjUup7iE"
},
"source": [
"# Data Generation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "aSj_UeLtp-KK",
"outputId": "3873f356-d05b-4b9b-e753-036bd0c27080"
},
"outputs": [],
"source": [
"from langchain_google_genai import ChatGoogleGenerativeAI\n",
"llm = ChatGoogleGenerativeAI(model=\"gemini-1.5-pro\")\n",
"\n",
"result = llm.invoke(\"Write a ballad about LangChain\")\n",
"print(result.content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Q_bsstEYKbn5"
},
"outputs": [],
"source": [
"from langchain.chains import RetrievalQA\n",
"from langchain.llms import OpenAI\n",
"\n",
"qa = RetrievalQA.from_chain_type(llm=llm,\n",
" chain_type=\"stuff\",\n",
" retriever=retriever2)\n",
"\n",
"query = \"What did the president say about Ketanji Brown Jackson\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 146
},
"id": "2exNRRDfKqzc",
"outputId": "5e234b59-ce5c-4ff9-d494-d54cde805f39"
},
"outputs": [],
"source": [
"qa.run(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YWshwI6IKtEp"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyMhxzSd/m4NaE57flW3r70r",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: ConversationEntityMemory.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "CyfXAUX9tt5C"
},
"source": [
"#### ConversationEntityMemory is a memory class provided by LangChain, designed to track and store information about entities that arise in a conversation. It allows the AI to \"remember\" key facts about people, places, or concepts mentioned during a conversation, so it can refer back to them later on, improving the conversational experience.\n",
"\n",
"## Key Features:\n",
"**Entity Tracking:** It identifies entities (e.g., names, places, concepts) and stores relevant information about them. For instance, if you mention \"Tanmay\" in one part of a conversation, it can remember details about \"Tanmay\" for later reference.\n",
"\n",
"**Context-Aware:** It helps the AI maintain context by remembering details about the entities mentioned during the chat, ensuring more natural, fluid conversations over time.\n",
"\n",
"**Customization:** You can customize what to store and how to retrieve it during future interactions."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "NyxQrf84k8N6",
"outputId": "ee8595b3-3d8e-43ad-d5a8-57e37dc22963"
},
"outputs": [],
"source": [
"!pip install langchain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JMDjmz5llRqJ",
"outputId": "3c2bd290-2187-4c94-db9e-ee011fd7a8a2"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "DVLzegcvlRFh",
"outputId": "507e99b3-7885-4b19-aa6c-c402336b24e1"
},
"outputs": [],
"source": [
"!pip install langchain_google_genai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "KJkL7-belXEJ"
},
"outputs": [],
"source": [
"import warnings\n",
"warnings.filterwarnings('ignore')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "yEZcG8GmlX7q"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')\n",
"os.environ[\"GOOGLE_API_KEY\"] = GOOGLE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JrcW8y-Lxcrz"
},
"outputs": [],
"source": [
"from langchain_google_genai import ChatGoogleGenerativeAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UHzW2v8qlUiB"
},
"outputs": [],
"source": [
"model = ChatGoogleGenerativeAI(model=\"gemini-1.0-pro\",convert_system_message_to_human=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hfmpxyFqld-k",
"outputId": "a45e0a86-a1ff-4d57-f984-253380cbf840"
},
"outputs": [],
"source": [
"print(model.invoke(\"hi\").content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "6oP8kSH7xZ00"
},
"outputs": [],
"source": [
"from langchain.memory import ConversationEntityMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "y_z9GNKik5Di"
},
"outputs": [],
"source": [
"memory = ConversationEntityMemory(llm=model)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "e9lOMUwIlMcJ",
"outputId": "1083435f-63f9-4165-dc91-844960a14f42"
},
"outputs": [],
"source": [
"_input= {\"input\": \"i am very hungry.\"}\n",
"memory.load_memory_variables(_input)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "l8qru5UcrgeC",
"outputId": "d49fbd15-086a-4a41-9821-7d3617b735d2"
},
"outputs": [],
"source": [
"_input= {\"input\": \"sunny & mayank are working on a hackathon project\"}\n",
"memory.load_memory_variables(_input)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hGPOpmFesoC7",
"outputId": "35a4434a-142f-4989-c4c7-1088f881fa18"
},
"outputs": [],
"source": [
"_input= {\"input\": \"My name is John, and I'm planning a trip to Paris.\"}\n",
"memory.load_memory_variables(_input)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "D6AwIuiDtBiy",
"outputId": "a26fe41c-3a43-4f54-c0e1-9c57f3c40ed6"
},
"outputs": [],
"source": [
"_input= {\"input\": \"Sunny is a great person who values gratitude.\"}\n",
"memory.load_memory_variables(_input)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "F8EExXXblzaL"
},
"outputs": [],
"source": [
"memory.save_context(\n",
" {\"Human\": \"Sunny and Mayank are working on a hackathon project\"},\n",
" {\"AI\": \"That's awesome! What's the hackathon project about?\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "OnwhQHgEuYeS",
"outputId": "d8228df2-e284-4767-eb97-f1035053aeb4"
},
"outputs": [],
"source": [
"memory.load_memory_variables({\"input\": \"who is Sunny?\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "wVGC3O-Vmofz"
},
"outputs": [],
"source": [
"memory.save_context(\n",
" {\"Human\": \"It's a machine learning project focused on healthcare.\"},\n",
" {\"AI\": \"Sounds exciting! Are they building a prediction model or something else?\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "g84umam_1MX6"
},
"outputs": [],
"source": [
"memory.save_context(\n",
" {\"Human\": \"Yes, they are building prediction model.\"},\n",
" {\"AI\": \"Wishing Sunny and Mayank all the best for their project!\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Fkaw4hMX1loT",
"outputId": "5530adea-9863-4633-ba96-d4c948296474"
},
"outputs": [],
"source": [
"memory.load_memory_variables({\"input\": \"who is Sunny?\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "k62uDbQc17Ba",
"outputId": "c473eb7c-644e-4071-f098-22ea9ca0ba2b"
},
"outputs": [],
"source": [
"print('You are an AI assistant helping a human keep track of facts about relevant people, places, and concepts in their life. Update the summary of the provided entity in the \"Entity\" section based on the last line of your conversation with the human. If you are writing the summary for the first time, return a single sentence.\\nThe update should only include facts that are relayed in the last line of conversation about the provided entity, and should only contain facts about the provided entity.\\n\\nIf there is no new information about the provided entity or the information is not worth noting (not an important or relevant fact to remember long-term), return the existing summary unchanged.\\n\\nFull conversation history (for context):\\n{history}\\n\\nEntity to summarize:\\n{entity}\\n\\nExisting summary of {entity}:\\n{summary}\\n\\nLast line of conversation:\\nHuman: {input}\\nUpdated summary:')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ck2xTr9H26O7",
"outputId": "18282a75-c119-46c8-a165-f2b1d899a93f"
},
"outputs": [],
"source": [
"print('You are an AI assistant reading the transcript of a conversation between an AI and a human. Extract all of the proper nouns from the last line of conversation. As a guideline, a proper noun is generally capitalized. You should definitely extract all names and places.\\n\\nThe conversation history is provided just in case of a coreference (e.g. \"What do you know about him\" where \"him\" is defined in a previous line) -- ignore items mentioned there that are not in the last line.\\n\\nReturn the output as a single comma-separated list, or NONE if there is nothing of note to return (e.g. the user is just issuing a greeting or having a simple conversation).\\n\\nEXAMPLE\\nConversation history:\\nPerson #1: how\\'s it going today?\\nAI: \"It\\'s going great! How about you?\"\\nPerson #1: good! busy working on Langchain. lots to do.\\nAI: \"That sounds like a lot of work! What kind of things are you doing to make Langchain better?\"\\nLast line:\\nPerson #1: i\\'m trying to improve Langchain\\'s interfaces, the UX, its integrations with various products the user might want ... a lot of stuff.\\nOutput: Langchain\\nEND OF EXAMPLE\\n\\nEXAMPLE\\nConversation history:\\nPerson #1: how\\'s it going today?\\nAI: \"It\\'s going great! How about you?\"\\nPerson #1: good! busy working on Langchain. lots to do.\\nAI: \"That sounds like a lot of work! What kind of things are you doing to make Langchain better?\"\\nLast line:\\nPerson #1: i\\'m trying to improve Langchain\\'s interfaces, the UX, its integrations with various products the user might want ... a lot of stuff. I\\'m working with Person #2.\\nOutput: Langchain, Person #2\\nEND OF EXAMPLE\\n\\nConversation history (for reference only):\\n{history}\\nLast line of conversation (for extraction):\\nHuman: {input}\\n\\nOutput:')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "P291dMnv3MlT"
},
"outputs": [],
"source": [
"from langchain.chains import ConversationChain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "20gCJ34f4F-i"
},
"outputs": [],
"source": [
"from langchain.memory import ConversationEntityMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5n-02nGT4HKy"
},
"outputs": [],
"source": [
"from langchain.memory.prompt import ENTITY_MEMORY_CONVERSATION_TEMPLATE"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_hUoV7Jt4Iry"
},
"outputs": [],
"source": [
"from pydantic import BaseModel"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tRO6ucqk4Lsi"
},
"outputs": [],
"source": [
"from typing import List, Dict, Any"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ooyiYhho4NVT",
"outputId": "c9041a75-2fba-465a-892a-977f236aa696"
},
"outputs": [],
"source": [
"conversation = ConversationChain(\n",
" llm=model,\n",
" verbose=True,\n",
" prompt=ENTITY_MEMORY_CONVERSATION_TEMPLATE,\n",
" memory=ConversationEntityMemory(llm=model)\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 453
},
"id": "lX97yNGp4cJz",
"outputId": "4112c2de-cc7d-4f61-c61f-39dbef869a37"
},
"outputs": [],
"source": [
"conversation.predict(input=\"Deven & Sam are working on a hackathon project\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xIQAi2Dh4qI0",
"outputId": "545a45c1-3d10-49aa-eeed-8bbb9f578b18"
},
"outputs": [],
"source": [
"conversation.memory.entity_store.store"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 489
},
"id": "Ik-bPxX34u4i",
"outputId": "e450b4a6-769c-4831-b777-6f2738d2efd3"
},
"outputs": [],
"source": [
"conversation.predict(input=\"They are trying to add more complex memory structures to Langchain\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 561
},
"id": "ACakaFY64y_q",
"outputId": "dad76347-c45d-43ca-9520-c29189c86ca8"
},
"outputs": [],
"source": [
"conversation.predict(input=\"They are adding in a key-value store for entities mentioned so far in the conversation.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 597
},
"id": "VUfQMU365GtL",
"outputId": "465becdd-d918-4dc7-f0d1-61b37e56f29a"
},
"outputs": [],
"source": [
"conversation.predict(input=\"What do you know about Deven & Sam?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "WIFsSUtn5KGa",
"outputId": "6849a1de-34f0-4743-b644-bf9912a1f7f3"
},
"outputs": [],
"source": [
"from pprint import pprint\n",
"pprint(conversation.memory.entity_store.store)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 561
},
"id": "OVgc65P25ZpC",
"outputId": "04e79e8d-1e04-430b-d020-3eb39fe564ec"
},
"outputs": [],
"source": [
"conversation.predict(input=\"Sam is the founder of a company called Daimon.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "I0MZLauH58Ra",
"outputId": "5a259648-7ece-42bd-c85c-b4aeccc991d5"
},
"outputs": [],
"source": [
"from pprint import pprint\n",
"pprint(conversation.memory.entity_store.store)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 597
},
"id": "lTsnRFsh6EG6",
"outputId": "c249efdf-1299-4e31-a8ba-73af3ef89dd0"
},
"outputs": [],
"source": [
"conversation.predict(input=\"What do you know about Sam?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fJQs1HKr6Npq"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyOplxTeNXfxmmaGgbaEUeNp",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: Conversational_Summary_Memory.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "AygnEOhZIjbO",
"outputId": "a6bce69e-b458-404c-f318-a06160e8fd4c"
},
"outputs": [],
"source": [
"!pip install langchain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "PvFZRklaIpbV",
"outputId": "b837f7fc-618d-47ef-a9d4-9a4befbc71b1"
},
"outputs": [],
"source": [
"!pip install langchain_community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xPchyz3U8lCl",
"outputId": "45596571-05df-475a-9ed8-c75833eabd77"
},
"outputs": [],
"source": [
"!pip install langchain-groq"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Fg-AKGTs_PQU"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2Cu_pYwIKAUs"
},
"outputs": [],
"source": [
"GROQ_API_KEY=userdata.get('GROQ_API_KEY')\n",
"os.environ[\"GROQ_API_KEY\"] = GROQ_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LW2FMfFP_OQM"
},
"outputs": [],
"source": [
"LANGCHAIN_KEY_REMOVED=userdata.get('LANGCHAIN_KEY_REMOVED')\n",
"os.environ[\"LANGCHAIN_KEY_REMOVED\"] = LANGCHAIN_KEY_REMOVED"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7ebHtdBt_NMl"
},
"outputs": [],
"source": [
"os.environ[\"LANGCHAIN_PROJECT\"]=\"memorylogs\"\n",
"os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
"os.environ[\"LANGCHAIN_ENDPOINT\"] = \"https://api.smith.langchain.com\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2qUMkyoc85cF"
},
"outputs": [],
"source": [
"from langchain_groq import ChatGroq\n",
"model=ChatGroq(model_name=\"Gemma2-9b-It\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "DrWr856dUYZ0",
"outputId": "2d29db2c-7557-43b1-fb1c-6995cef078fd"
},
"outputs": [],
"source": [
"model.invoke(\"Hi, what's up?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "41gGc9AyIOnz"
},
"outputs": [],
"source": [
"from langchain.memory import ConversationSummaryMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kVGDaPvPGESO"
},
"outputs": [],
"source": [
"from langchain.memory import ChatMessageHistory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "VLErHCqoLPCG"
},
"outputs": [],
"source": [
"memory = ConversationSummaryMemory(llm=model, return_messages=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mbl6oOr7LP21"
},
"outputs": [],
"source": [
"memory.save_context(\n",
" {\"input\": \"Sunny and Mayank are working on a hackathon project.\"},\n",
" {\"output\": \"That's awesome! What's the hackathon project about?\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "L8fTked0LUTd",
"outputId": "4056e3b8-9738-4668-9cb9-99d7664cdf1a"
},
"outputs": [],
"source": [
"memory.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "geXY_wMSHvLv"
},
"outputs": [],
"source": [
"summary=memory.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "kVx_ktZwH61P",
"outputId": "3e2eb48c-1756-4c2e-c4df-56d7a93bbae1"
},
"outputs": [],
"source": [
"summary"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "O4JEUOyUHzBz",
"outputId": "d0ed406a-c099-4b20-c525-7cea579e640b"
},
"outputs": [],
"source": [
"print(summary[\"history\"][0].content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "I_X4a1RMLsbO"
},
"outputs": [],
"source": [
"memory.save_context(\n",
" {\"input\": \"It's a machine learning project focused on healthcare.\"},\n",
" {\"output\": \"Sounds exciting! Are they building a prediction model or something else\"}\n",
")\n",
"memory.save_context(\n",
" {\"input\": \"Yes, they’re working on a model to predict patient outcomes.\"},\n",
" {\"output\": \"Impressive! How far along are they with the project?\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "nS6bvFa-L49_",
"outputId": "b8e01291-910c-4888-9777-df3d3484e302"
},
"outputs": [],
"source": [
"memory.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "HyJX047FInuH"
},
"outputs": [],
"source": [
"summary=memory.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "pv7Y51HkIs7n",
"outputId": "df18e64e-235c-49f1-ebdc-281faacfb808"
},
"outputs": [],
"source": [
"print(summary[\"history\"][0].content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "BxDFvMLXKf51",
"outputId": "7c9cf81e-9455-4cec-b285-70245995813e"
},
"outputs": [],
"source": [
"memory.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ax-wiHmpJUCB",
"outputId": "b406c6e0-23b1-49b7-fc9e-d8e2533ba3d6"
},
"outputs": [],
"source": [
"print('Progressively summarize the lines of conversation provided, adding onto the previous summary returning a new summary.\\n\\nEXAMPLE\\nCurrent summary:\\nThe human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good.\\n\\nNew lines of conversation:\\nHuman: Why do you think artificial intelligence is a force for good?\\nAI: Because artificial intelligence will help humans reach their full potential.\\n\\nNew summary:\\nThe human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good because it will help humans reach their full potential.\\nEND OF EXAMPLE\\n\\nCurrent summary:\\n{summary}\\n\\nNew lines of conversation:\\n{new_lines}\\n\\nNew summary:')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8YUuMPxGKxVF",
"outputId": "e7833d2b-68a0-431f-ed06-f59bf5b3c691"
},
"outputs": [],
"source": [
"memory.chat_memory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "0MKYIhNARIRW",
"outputId": "cf64bf27-9e69-4eb5-bd38-41397f7f8ad7"
},
"outputs": [],
"source": [
"memory.chat_memory.messages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "yuV4T9HmQh7k"
},
"outputs": [],
"source": [
"messages = memory.chat_memory.messages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "dUtkymzCWHLa",
"outputId": "93ba3130-6163-4e46-d211-7eebe6abdb61"
},
"outputs": [],
"source": [
"messages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cZ7Fn-ZwQkEs"
},
"outputs": [],
"source": [
"previous_summary=\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"id": "iQnpKenHQpaM",
"outputId": "d6a80bee-ec1b-4870-f4d4-3212d74db19e"
},
"outputs": [],
"source": [
"memory.predict_new_summary(messages, previous_summary)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "s5K5tGBEQ3A1"
},
"outputs": [],
"source": [
"history = ChatMessageHistory()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gK__XEGDSDXt"
},
"outputs": [],
"source": [
"history.add_user_message(\"Hi\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "npFZROIOSGsm"
},
"outputs": [],
"source": [
"history.add_ai_message(\"Hello, how can I assist you today?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "vJhxPTCPSJc1",
"outputId": "50764ff3-5daf-484d-cf90-855679bb75e6"
},
"outputs": [],
"source": [
"ConversationSummaryMemory.from_messages(\n",
" llm=model,\n",
" chat_memory=history,\n",
" memory_key=\"summary\",\n",
" human_prefix=\"User\",\n",
" ai_prefix=\"AI\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1GSJ1hDiSaHM"
},
"outputs": [],
"source": [
"memory = ConversationSummaryMemory.from_messages(\n",
" llm=model,\n",
" chat_memory=history,\n",
" memory_key=\"summary\",\n",
" human_prefix=\"User\",\n",
" ai_prefix=\"AI\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"id": "obdS8sIbSnus",
"outputId": "5ac9af99-ed5a-40ea-ec0e-5f4e11858eec"
},
"outputs": [],
"source": [
"memory.buffer"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "qRfFhS-3LfQu"
},
"source": [
"# From here the chaining starting"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "_TDHr7zGSpph",
"outputId": "c2a47e77-2b1c-430e-cdc5-ee990fe9d076"
},
"outputs": [],
"source": [
"from langchain.chains import ConversationChain\n",
"conversation_with_summary = ConversationChain(\n",
" llm=model,\n",
" memory=ConversationSummaryMemory(llm=model),\n",
" verbose=True\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 290
},
"id": "HMomUKKaYcis",
"outputId": "f6af1d1d-01f4-44a5-a008-ee3701fe752b"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"Hi, what's up?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 362
},
"id": "-rhWP-RuYfD8",
"outputId": "e9776166-0d7c-426d-a93f-73ba6b014222"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"Sunny and Mayank are working on a mlops production ready project.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 344
},
"id": "OCHN6jgpYuvW",
"outputId": "857d05d0-fb90-443d-84ec-4d18b8d32f80"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"It's project focused on healthcare.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 417
},
"id": "APVEcglEYux2",
"outputId": "0269a79b-3cb3-4cce-910d-003bb86f943a"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"so can you describe mlops pipeline to me with in six point.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ttahJHLcMKtH"
},
"source": [
"You got it! Describing an MLOps pipeline in six points is a great way to get a handle on the key concepts. Here's one way to do it:\n",
"\n",
"1. **Data Collection & Preparation:** This is where you gather the raw data needed for your model and clean, transform, and prepare it for training. Think of it like gathering ingredients and chopping them up before you start cooking.\n",
"2. **Model Development:** This is where the \"magic\" happens! You choose a suitable machine learning algorithm, train it on your prepared data, and fine-tune its parameters to achieve the best performance. \n",
"3. **Model Evaluation:** Before deploying your model, you rigorously test and evaluate its performance on unseen data. This helps you understand how well it will generalize to real-world scenarios.\n",
"4. **Model Deployment:** This involves making your trained model accessible for use. It could be deployed as a web service, integrated into an application, or run on edge devices.\n",
"5. **Monitoring & Maintenance:** Once deployed, you continuously monitor the model's performance in the real world. You might also need to retrain or update the model periodically to ensure it stays accurate and relevant.\n",
"6. **Versioning & Experiment Tracking:** Throughout the pipeline, it's crucial to track all changes to your code, data, and model parameters. This allows you to roll back to previous versions if needed and understand how different decisions impacted your model's performance.\n",
"\n",
"\n",
"\n",
"Let me know if you'd like me to elaborate on any of these points or if you have other questions about MLOps!\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 290
},
"id": "zG6fTjw5ZEaG",
"outputId": "3c07cca6-2eb1-4169-9504-6b0a16ca0cf3"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"How many total points are there?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 417
},
"id": "5fWaLReZZOMm",
"outputId": "156b4a3a-3415-431a-b17e-83e641dccd04"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"can you give me 5th point with explaination\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "FgNQ7TbdMcoA"
},
"source": [
"Absolutely! The fifth point in an MLOps pipeline is **Monitoring and Maintenance**.\n",
"\n",
"This stage is crucial because it ensures that the deployed model continues to perform well in the real world. \n",
"\n",
"Here's a breakdown:\n",
"\n",
"* **Performance Tracking:** We continuously monitor the model's performance metrics, like accuracy, precision, recall, and F1-score. This helps us detect any degradation in performance over time.\n",
"* **Data Drift Detection:** Real-world data can change, and if the input data distribution shifts significantly from what the model was trained on, its performance can suffer. We use techniques to detect these data drifts.\n",
"* **Error Analysis:** We analyze any errors or unexpected outputs from the model to understand the reasons behind them. This can help us identify areas for improvement in the model or the data.\n",
"* **Model Retraining:** Based on performance monitoring and data drift detection, we might need to retrain the model with updated data to maintain its effectiveness.\n",
"* **System Health Checks:** We also monitor the infrastructure and systems supporting the model deployment to ensure they are running smoothly and securely.\n",
"\n",
"\n",
"Think of monitoring and maintenance like keeping your car in top shape. You need regular checkups, oil changes, and repairs to keep it running efficiently and safely.\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 162
},
"id": "UnwvA7MqYxYw",
"outputId": "b20df4f5-9db5-47aa-9435-b26940d66cc7"
},
"outputs": [],
"source": [
"conversation_with_summary.memory.buffer"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "x0dDwGFZd5UH"
},
"source": [
"# Conversation Summary Buffer Memory"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fwRMCMa37OGA"
},
"source": [
"While summary is good, we know that recent conversation has high correlation to upcoming query and\n",
"\n",
"A summary of old conversation with a buffer memory of last few conversation would be a good combination. This class exactly does that.\n",
"\n",
"You can set the token limit which define how much historical conversation to be kept along with the summary. Higher the token size more the exact conversation history kept as-it-is."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pJWamX6dYu3_"
},
"outputs": [],
"source": [
"from langchain.memory import ConversationSummaryBufferMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JrmZ7BIceAPG"
},
"outputs": [],
"source": [
"memory2 = ConversationSummaryBufferMemory(llm=model,return_messages=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "J9Dgn3pafik7"
},
"outputs": [],
"source": [
"memory2.save_context(\n",
" {\"input\": \"It's a machine learning project focused on healthcare.\"},\n",
" {\"output\": \"Sounds exciting! Are they building a prediction model or something else\"}\n",
")\n",
"memory2.save_context(\n",
" {\"input\": \"Yes, they’re working on a model to predict patient outcomes.\"},\n",
" {\"output\": \"Impressive! How far along are they with the project?\"}\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "SGwrNY39gOqe",
"outputId": "884b2989-d181-4b41-a615-d88ba2cf095a"
},
"outputs": [],
"source": [
"memory2.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xOe2ohwSgSDG"
},
"outputs": [],
"source": [
"memory3 = ConversationSummaryBufferMemory(llm=model,return_messages=True,max_token_limit=50)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AAuBIP0FgmO3"
},
"outputs": [],
"source": [
"memory3.save_context(\n",
" {\"input\": \"Sunny and Mayank are working on a hackathon project.\"},\n",
" {\"output\": \"That's awesome! What's the hackathon project about?\"}\n",
")\n",
"memory3.save_context(\n",
" {\"input\": \"It's a machine learning project focused on healthcare.\"},\n",
" {\"output\": \"Sounds exciting! Are they building a prediction model or something else?\"}\n",
")\n",
"memory3.save_context(\n",
" {\"input\": \"Yes, they’re working on a model to predict patient outcomes.\"},\n",
" {\"output\": \"Impressive! Wishing Sunny and Mayank all the best for their project.\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ChgkyCaxbdAU"
},
"outputs": [],
"source": [
"#memory3.clear()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "IG4ihK2cbrql",
"outputId": "ccc260ce-9299-4a5b-c439-b8d0e03b3896"
},
"outputs": [],
"source": [
"memory3.load_memory_variables({})[\"history\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"id": "Zhsc_gU3b3TW",
"outputId": "6566bb2d-975e-4039-e6c2-f85f2a28e58a"
},
"outputs": [],
"source": [
"memory3.load_memory_variables({})[\"history\"][0].content"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "NqIz-Yg3cEHb"
},
"source": [
"AIMessage(content='Sounds exciting! Are they building a prediction model or something else?'),\n",
"\n",
"HumanMessage(content='Yes, they’re working on a model to predict patient outcomes.'),\n",
"\n",
"AIMessage(content='Impressive! Wishing Sunny and Mayank all the best for their project.')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "I48xWE5e06tL"
},
"outputs": [],
"source": [
"memory4 = ConversationSummaryBufferMemory(llm=model,return_messages=True,max_token_limit=20)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cEfsThiN3mlK"
},
"outputs": [],
"source": [
"memory4.save_context(\n",
" {\"input\": \"Sunny and Mayank are working on a hackathon project.\"},\n",
" {\"output\": \"That's awesome! What's the hackathon project about?\"}\n",
")\n",
"memory4.save_context(\n",
" {\"input\": \"It's a machine learning project focused on healthcare.\"},\n",
" {\"output\": \"Sounds exciting! Are they building a prediction model or something else?\"}\n",
")\n",
"memory4.save_context(\n",
" {\"input\": \"Yes, they’re working on a model to predict patient outcomes.\"},\n",
" {\"output\": \"Impressive! Wishing Sunny and Mayank all the best for their project.\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6s1X55XKccyJ",
"outputId": "64691a41-69a9-4c0a-9af4-8f7161d9ef9e"
},
"outputs": [],
"source": [
"memory4.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 290
},
"id": "UrE697y6grl8",
"outputId": "7c14e3c1-6b20-4772-ae52-dee3fad699d5"
},
"outputs": [],
"source": [
"from langchain.chains import ConversationChain\n",
"\n",
"conversation_with_summary = ConversationChain(\n",
" llm=model,\n",
" # We set a very low max_token_limit for the purposes of testing.\n",
" memory=ConversationSummaryBufferMemory(llm=model, max_token_limit=40),\n",
" verbose=True,\n",
")\n",
"conversation_with_summary.predict(input=\"Hi, what's up?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 362
},
"id": "opRAv9LgiAod",
"outputId": "c1af6e8b-6da8-4f17-9ab5-795856499950"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"Just working on writing some documentation on machine learning!\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 399
},
"id": "x3H2jeVEiHUN",
"outputId": "6ba6dafa-1989-447e-a1ff-f48b65fd185d"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"give me some points for writing about the document\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 471
},
"id": "qRUfbtM3iRdN",
"outputId": "43449926-483f-4e84-99db-9f78f9ff4169"
},
"outputs": [],
"source": [
"conversation_with_summary.predict(input=\"can you list out the resources from the previous message\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GxbjdvEHidtl"
},
"outputs": [],
"source": [
"Conversation Knowledge Graph Memory : Uses a knowledge graph to store information and relationships between entities\n",
"\n",
"VectorStore-Backed Memory: Uses vector embeddings to store and retrieve information based on semantic similarity.\n",
"\n",
"ConversationTokenBufferMemory: Instead of “k” conversations being remembered in ConversationBufferWindowMemory, in this case we want to remember last set of discussion based on “max token limit”.\n"
]
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyOSai68G4Hc4t9gpJ5+CkAy",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: FlashRerankPractical.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "4HTzTeXkt-Ny"
},
"source": [
"**Model Options:**\n",
"- **Nano**: ~4MB, blazing fast model with competitive performance (ranking precision).\n",
"- **Small**: ~34MB, slightly slower with the best performance (ranking precision).\n",
"- **Medium**: ~110MB, slower model with the best zero-shot performance (ranking precision).\n",
"- **Large**: ~150MB, slower model with competitive performance (ranking precision) for 100+ languages."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "GBpXU2_Mt_-T"
},
"source": [
" **Flash Rank**: Ultra-lite & Super-fast Python library for search & retrieval re-ranking.\n",
"\n",
"- **Ultra-lite**: No heavy dependencies. Runs on CPU with a tiny ~4MB reranking model.\n",
"- **Super-fast**: Speed depends on the number of tokens in passages and query, plus model depth.\n",
"- **Cost-efficient**: Ideal for serverless deployments with low memory and time requirements.\n",
"- **Based on State-of-the-Art Cross-encoders**: Includes models like ms-marco-TinyBERT-L-2-v2 (default), ms-marco-MiniLM-L-12-v2, rank-T5-flan, and ms-marco-MultiBERT-L-12.\n",
"- **Sleek Models for Efficiency**: Designed for minimal overhead in user-facing scenarios.\n",
"\n",
"_Flash Rank is tailored for scenarios requiring efficient and effective reranking, balancing performance with resource usage._"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "S5d9ptq9tOLg",
"outputId": "eac0f366-39d0-4de1-fc86-297fed840821"
},
"outputs": [],
"source": [
"!pip install flashrank"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zSjnmXLbuKhV"
},
"outputs": [],
"source": [
"# Helper function for printing docs\n",
"\n",
"\n",
"def pretty_print_docs(docs):\n",
" print(\n",
" f\"\\n{'-' * 100}\\n\".join(\n",
" [\n",
" f\"Document {i+1}:\\n\\n{d.page_content}\\nMetadata: {d.metadata}\"\n",
" for i, d in enumerate(docs)\n",
" ]\n",
" )\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4NgkbKGBunFn"
},
"outputs": [],
"source": [
"query = \"How to speedup LLMs?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PxFLnmwwunnG"
},
"outputs": [],
"source": [
"passages = [\n",
" {\n",
" \"id\":1,\n",
" \"text\":\"Introduce *lookahead decoding*: - a parallel decoding algo to accelerate LLM inference - w/o the need for a draft model or a data store - linearly decreases # decoding steps relative to log(FLOPs) used per decoding step.\",\n",
" \"meta\": {\"additional\": \"info1\"}\n",
" },\n",
" {\n",
" \"id\":2,\n",
" \"text\":\"LLM inference efficiency will be one of the most crucial topics for both industry and academia, simply because the more efficient you are, the more $$$ you will save. vllm project is a must-read for this direction, and now they have just released the paper\",\n",
" \"meta\": {\"additional\": \"info2\"}\n",
" },\n",
" {\n",
" \"id\":3,\n",
" \"text\":\"There are many ways to increase LLM inference throughput (tokens/second) and decrease memory footprint, sometimes at the same time. Here are a few methods I’ve found effective when working with Llama 2. These methods are all well-integrated with Hugging Face. This list is far from exhaustive; some of these techniques can be used in combination with each other and there are plenty of others to try. - Bettertransformer (Optimum Library): Simply call `model.to_bettertransformer()` on your Hugging Face model for a modest improvement in tokens per second. - Fp4 Mixed-Precision (Bitsandbytes): Requires minimal configuration and dramatically reduces the model's memory footprint. - AutoGPTQ: Time-consuming but leads to a much smaller model and faster inference. The quantization is a one-time cost that pays off in the long run.\",\n",
" \"meta\": {\"additional\": \"info3\"}\n",
"\n",
" },\n",
" {\n",
" \"id\":4,\n",
" \"text\":\"Ever want to make your LLM inference go brrrrr but got stuck at implementing speculative decoding and finding the suitable draft model? No more pain! Thrilled to unveil Medusa, a simple framework that removes the annoying draft model while getting 2x speedup.\",\n",
" \"meta\": {\"additional\": \"info4\"}\n",
" },\n",
" {\n",
" \"id\":5,\n",
" \"text\":\"vLLM is a fast and easy-to-use library for LLM inference and serving. vLLM is fast with: State-of-the-art serving throughput Efficient management of attention key and value memory with PagedAttention Continuous batching of incoming requests Optimized CUDA kernels\",\n",
" \"meta\": {\"additional\": \"info5\"}\n",
" }\n",
"]\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2Vp8evUat4Yf"
},
"outputs": [],
"source": [
"from flashrank.Ranker import Ranker, RerankRequest"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "DEKdOyY9uGQ8"
},
"outputs": [],
"source": [
"def get_result(query,passages,choice):\n",
" if choice == \"Nano\":\n",
" ranker = Ranker()\n",
" elif choice == \"Small\":\n",
" ranker = Ranker(model_name=\"ms-marco-MiniLM-L-12-v2\", cache_dir=\"/opt\")\n",
" elif choice == \"Medium\":\n",
" ranker = Ranker(model_name=\"rank-T5-flan\", cache_dir=\"/opt\")\n",
" elif choice == \"Large\":\n",
" ranker = Ranker(model_name=\"ms-marco-MultiBERT-L-12\", cache_dir=\"/opt\")\n",
" rerankrequest = RerankRequest(query=query, passages=passages)\n",
" results = ranker.rerank(rerankrequest)\n",
" print(results)\n",
"\n",
" return results"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7juQN4HX4y5p",
"outputId": "e5049c03-79af-4a68-f5c4-96f2f3677482"
},
"outputs": [],
"source": [
"%%time\n",
"print(\"sunny\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "90z7C8sTuU-y",
"outputId": "30ecc61b-9024-43db-9e3c-c9c50d5d239e"
},
"outputs": [],
"source": [
"%%time\n",
"get_result(query,passages,\"Nano\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GS5ndB7kusz2",
"outputId": "7631bffb-8f85-45dd-f845-f5eba41e2d4b"
},
"outputs": [],
"source": [
"%%time\n",
"get_result(query,passages,\"Small\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "_xaL3dXaxnd2",
"outputId": "91dfb259-cdc2-49fa-8ca3-0ae635419f38"
},
"outputs": [],
"source": [
"%%time\n",
"get_result(query,passages,\"Medium\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "c1-4gQdHuy8U",
"outputId": "05a1d225-f51f-439e-fe48-73bac2465796"
},
"outputs": [],
"source": [
"!pip install langchain_community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1PXvV0Itu0rh",
"outputId": "27e278fe-a8a9-497d-ea95-c503a919e2fd"
},
"outputs": [],
"source": [
"!pip install langchain_openai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "rzofq9Fou3RQ"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SlfpkIBdu4mf"
},
"outputs": [],
"source": [
"import os\n",
"os.environ[\"OPENAI_API_KEY\"]=OPENAI_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Mub11J8gu6mm"
},
"outputs": [],
"source": [
"from langchain_community.document_loaders import TextLoader\n",
"from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
"from langchain_community.embeddings import OpenAIEmbeddings\n",
"from langchain_community.vectorstores import FAISS"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "FXqPAq0QvHZH"
},
"outputs": [],
"source": [
"documents = TextLoader(\"/content/state_of_the_union.txt\").load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4aQEhuJsvmB2"
},
"outputs": [],
"source": [
"text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "R7eg9FN6voFb"
},
"outputs": [],
"source": [
"texts = text_splitter.split_documents(documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "i2aGoUMAvqZw"
},
"outputs": [],
"source": [
"for id, text in enumerate(texts):\n",
" text.metadata[\"id\"] = id"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "WZ8dATGS6TVn",
"outputId": "035cc344-6397-42a1-acf6-f0f44b8c1e98"
},
"outputs": [],
"source": [
"texts"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "G5T-mJxtvsNw",
"outputId": "628821ca-dd80-4374-c0a4-0ed1dc85fdf5"
},
"outputs": [],
"source": [
"embedding = OpenAIEmbeddings(model=\"text-embedding-ada-002\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "jVJ52yXjyWs_",
"outputId": "aa4cc7fd-9046-48b1-b350-8f183505a6cf"
},
"outputs": [],
"source": [
"!pip install faiss-cpu"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bRMhm3DjvtkX"
},
"outputs": [],
"source": [
"retriever = FAISS.from_documents(texts, embedding).as_retriever(search_kwargs={\"k\": 10})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "P_6NVzg-vvpV"
},
"outputs": [],
"source": [
"query = \"What did the president say about Ketanji Brown Jackson\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0O3Zt_4kvxWX"
},
"outputs": [],
"source": [
"docs = retriever.invoke(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "d65muVfQvyop",
"outputId": "23fa1ba2-0b55-4d1c-8632-ccd46a275ae5"
},
"outputs": [],
"source": [
"pretty_print_docs(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zvrnj0O0v0Pe"
},
"outputs": [],
"source": [
"from langchain.retrievers import ContextualCompressionRetriever\n",
"from langchain.retrievers.document_compressors import FlashrankRerank\n",
"from langchain_openai import ChatOpenAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LN6kmZ6Rv2VA"
},
"outputs": [],
"source": [
"llm = ChatOpenAI(temperature=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Hrg7KvbCv630",
"outputId": "0209aac4-08d4-490e-810c-d9459b6a804b"
},
"outputs": [],
"source": [
"compressor = FlashrankRerank()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cugusxEgv9E3"
},
"outputs": [],
"source": [
"compression_retriever = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2Pu1osglv_aY"
},
"outputs": [],
"source": [
"compressed_docs = compression_retriever.invoke(\"What did the president say about Ketanji Jackson Brown\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1YgfzFuB7TpM",
"outputId": "57977d13-2bf5-420f-8bfb-7742853cfcc2"
},
"outputs": [],
"source": [
"len(compressed_docs)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RVQiO2vY7nuT",
"outputId": "85bad12f-0e9e-446f-e686-ae3d2629076f"
},
"outputs": [],
"source": [
"compressed_docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "iC6mJMISwALJ",
"outputId": "d6e30499-492f-43cd-9ebe-6580ba292cc3"
},
"outputs": [],
"source": [
"print([doc.metadata[\"id\"] for doc in compressed_docs])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lmHurSMPwDgT",
"outputId": "e6d72721-d8cd-4e07-8987-6c67b6e5a963"
},
"outputs": [],
"source": [
"pretty_print_docs(compressed_docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AAgLxoK2wFCm"
},
"outputs": [],
"source": [
"from langchain.chains import RetrievalQA\n",
"\n",
"chain = RetrievalQA.from_chain_type(llm=llm, retriever=compression_retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "UHPoBgKqwFwl",
"outputId": "9d6c9d03-a052-4c0c-a9d2-825d407e0e27"
},
"outputs": [],
"source": [
"chain.invoke(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3x3PiL69yf0V"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyNBiDPCIpoyGNT1WYhF/3UL",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: Generative AI Dataset/llama3.txt
================================================
Llama (Large Language Model Meta AI) is a family of autoregressive large language models released by Meta AI starting in February 2023.[2][3] The latest version is Llama 3 released in April 2024.[4]
Model weights for the first version of Llama were released to the research community under a non-commercial license.[5][3] Subsequent versions of Llama were made accessible outside academia and released under licenses that permitted some commercial use.[6][7] Llama models are trained at different parameter sizes, typically ranging between 7B and 70B.[4] Originally, Llama was only available as a foundation model.[8] Starting with Llama 2, Meta AI started releasing instruction fine-tuned versions alongside foundation models.[7]
Llama models have been compared favorably against other large language models. Meta AI reported the original 13B parameter model's performance on most NLP benchmarks exceeded that of the much larger GPT-3 (with 175B parameters) and that the largest model was competitive with state of the art models such as PaLM and Chinchilla.[2]. Meta AI's testing shows that Llama 3 70B beats Gemini, and Claude in most benchmarks.[9][10] Wired describes the 8B parameter version of Llama 3 as being "surprisingly capable" given it's size.[11]
Alongside the release of Llama 3, Meta added virtual assistant features to Facebook and WhatsApp in select regions, and a standalone website. Both services use a Llama 3 model.[12] Reception was mixed, with some users confused after Meta AI told a parental group that it had a child.[13]
================================================
FILE: Generative AI Dataset/state_of_the_union.txt
================================================
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.
Last year COVID-19 kept us apart. This year we are finally together again.
Tonight, we meet as Democrats Republicans and Independents. But most importantly as Americans.
With a duty to one another to the American people to the Constitution.
And with an unwavering resolve that freedom will always triumph over tyranny.
Six days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways. But he badly miscalculated.
He thought he could roll into Ukraine and the world would roll over. Instead he met a wall of strength he never imagined.
He met the Ukrainian people.
From President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world.
Groups of citizens blocking tanks with their bodies. Everyone from students to retirees teachers turned soldiers defending their homeland.
In this struggle as President Zelenskyy said in his speech to the European Parliament “Light will win over darkness.” The Ukrainian Ambassador to the United States is here tonight.
Let each of us here tonight in this Chamber send an unmistakable signal to Ukraine and to the world.
Please rise if you are able and show that, Yes, we the United States of America stand with the Ukrainian people.
Throughout our history we’ve learned this lesson when dictators do not pay a price for their aggression they cause more chaos.
They keep moving.
And the costs and the threats to America and the world keep rising.
That’s why the NATO Alliance was created to secure peace and stability in Europe after World War 2.
The United States is a member along with 29 other nations.
It matters. American diplomacy matters. American resolve matters.
Putin’s latest attack on Ukraine was premeditated and unprovoked.
He rejected repeated efforts at diplomacy.
He thought the West and NATO wouldn’t respond. And he thought he could divide us at home. Putin was wrong. We were ready. Here is what we did.
We prepared extensively and carefully.
We spent months building a coalition of other freedom-loving nations from Europe and the Americas to Asia and Africa to confront Putin.
I spent countless hours unifying our European allies. We shared with the world in advance what we knew Putin was planning and precisely how he would try to falsely justify his aggression.
We countered Russia’s lies with truth.
And now that he has acted the free world is holding him accountable.
Along with twenty-seven members of the European Union including France, Germany, Italy, as well as countries like the United Kingdom, Canada, Japan, Korea, Australia, New Zealand, and many others, even Switzerland.
We are inflicting pain on Russia and supporting the people of Ukraine. Putin is now isolated from the world more than ever.
Together with our allies –we are right now enforcing powerful economic sanctions.
We are cutting off Russia’s largest banks from the international financial system.
Preventing Russia’s central bank from defending the Russian Ruble making Putin’s $630 Billion “war fund” worthless.
We are choking off Russia’s access to technology that will sap its economic strength and weaken its military for years to come.
Tonight I say to the Russian oligarchs and corrupt leaders who have bilked billions of dollars off this violent regime no more.
The U.S. Department of Justice is assembling a dedicated task force to go after the crimes of Russian oligarchs.
We are joining with our European allies to find and seize your yachts your luxury apartments your private jets. We are coming for your ill-begotten gains.
And tonight I am announcing that we will join our allies in closing off American air space to all Russian flights – further isolating Russia – and adding an additional squeeze –on their economy. The Ruble has lost 30% of its value.
The Russian stock market has lost 40% of its value and trading remains suspended. Russia’s economy is reeling and Putin alone is to blame.
Together with our allies we are providing support to the Ukrainians in their fight for freedom. Military assistance. Economic assistance. Humanitarian assistance.
We are giving more than $1 Billion in direct assistance to Ukraine.
And we will continue to aid the Ukrainian people as they defend their country and to help ease their suffering.
Let me be clear, our forces are not engaged and will not engage in conflict with Russian forces in Ukraine.
Our forces are not going to Europe to fight in Ukraine, but to defend our NATO Allies – in the event that Putin decides to keep moving west.
For that purpose we’ve mobilized American ground forces, air squadrons, and ship deployments to protect NATO countries including Poland, Romania, Latvia, Lithuania, and Estonia.
As I have made crystal clear the United States and our Allies will defend every inch of territory of NATO countries with the full force of our collective power.
And we remain clear-eyed. The Ukrainians are fighting back with pure courage. But the next few days weeks, months, will be hard on them.
Putin has unleashed violence and chaos. But while he may make gains on the battlefield – he will pay a continuing high price over the long run.
And a proud Ukrainian people, who have known 30 years of independence, have repeatedly shown that they will not tolerate anyone who tries to take their country backwards.
To all Americans, I will be honest with you, as I’ve always promised. A Russian dictator, invading a foreign country, has costs around the world.
And I’m taking robust action to make sure the pain of our sanctions is targeted at Russia’s economy. And I will use every tool at our disposal to protect American businesses and consumers.
Tonight, I can announce that the United States has worked with 30 other countries to release 60 Million barrels of oil from reserves around the world.
America will lead that effort, releasing 30 Million barrels from our own Strategic Petroleum Reserve. And we stand ready to do more if necessary, unified with our allies.
These steps will help blunt gas prices here at home. And I know the news about what’s happening can seem alarming.
But I want you to know that we are going to be okay.
When the history of this era is written Putin’s war on Ukraine will have left Russia weaker and the rest of the world stronger.
While it shouldn’t have taken something so terrible for people around the world to see what’s at stake now everyone sees it clearly.
We see the unity among leaders of nations and a more unified Europe a more unified West. And we see unity among the people who are gathering in cities in large crowds around the world even in Russia to demonstrate their support for Ukraine.
In the battle between democracy and autocracy, democracies are rising to the moment, and the world is clearly choosing the side of peace and security.
This is a real test. It’s going to take time. So let us continue to draw inspiration from the iron will of the Ukrainian people.
To our fellow Ukrainian Americans who forge a deep bond that connects our two nations we stand with you.
Putin may circle Kyiv with tanks, but he will never gain the hearts and souls of the Ukrainian people.
He will never extinguish their love of freedom. He will never weaken the resolve of the free world.
We meet tonight in an America that has lived through two of the hardest years this nation has ever faced.
The pandemic has been punishing.
And so many families are living paycheck to paycheck, struggling to keep up with the rising cost of food, gas, housing, and so much more.
I understand.
I remember when my Dad had to leave our home in Scranton, Pennsylvania to find work. I grew up in a family where if the price of food went up, you felt it.
That’s why one of the first things I did as President was fight to pass the American Rescue Plan.
Because people were hurting. We needed to act, and we did.
Few pieces of legislation have done more in a critical moment in our history to lift us out of crisis.
It fueled our efforts to vaccinate the nation and combat COVID-19. It delivered immediate economic relief for tens of millions of Americans.
Helped put food on their table, keep a roof over their heads, and cut the cost of health insurance.
And as my Dad used to say, it gave people a little breathing room.
And unlike the $2 Trillion tax cut passed in the previous administration that benefitted the top 1% of Americans, the American Rescue Plan helped working people—and left no one behind.
And it worked. It created jobs. Lots of jobs.
In fact—our economy created over 6.5 Million new jobs just last year, more jobs created in one year
than ever before in the history of America.
Our economy grew at a rate of 5.7% last year, the strongest growth in nearly 40 years, the first step in bringing fundamental change to an economy that hasn’t worked for the working people of this nation for too long.
For the past 40 years we were told that if we gave tax breaks to those at the very top, the benefits would trickle down to everyone else.
But that trickle-down theory led to weaker economic growth, lower wages, bigger deficits, and the widest gap between those at the top and everyone else in nearly a century.
Vice President Harris and I ran for office with a new economic vision for America.
Invest in America. Educate Americans. Grow the workforce. Build the economy from the bottom up
and the middle out, not from the top down.
Because we know that when the middle class grows, the poor have a ladder up and the wealthy do very well.
America used to have the best roads, bridges, and airports on Earth.
Now our infrastructure is ranked 13th in the world.
We won’t be able to compete for the jobs of the 21st Century if we don’t fix that.
That’s why it was so important to pass the Bipartisan Infrastructure Law—the most sweeping investment to rebuild America in history.
This was a bipartisan effort, and I want to thank the members of both parties who worked to make it happen.
We’re done talking about infrastructure weeks.
We’re going to have an infrastructure decade.
It is going to transform America and put us on a path to win the economic competition of the 21st Century that we face with the rest of the world—particularly with China.
As I’ve told Xi Jinping, it is never a good bet to bet against the American people.
We’ll create good jobs for millions of Americans, modernizing roads, airports, ports, and waterways all across America.
And we’ll do it all to withstand the devastating effects of the climate crisis and promote environmental justice.
We’ll build a national network of 500,000 electric vehicle charging stations, begin to replace poisonous lead pipes—so every child—and every American—has clean water to drink at home and at school, provide affordable high-speed internet for every American—urban, suburban, rural, and tribal communities.
4,000 projects have already been announced.
And tonight, I’m announcing that this year we will start fixing over 65,000 miles of highway and 1,500 bridges in disrepair.
When we use taxpayer dollars to rebuild America – we are going to Buy American: buy American products to support American jobs.
The federal government spends about $600 Billion a year to keep the country safe and secure.
There’s been a law on the books for almost a century
to make sure taxpayers’ dollars support American jobs and businesses.
Every Administration says they’ll do it, but we are actually doing it.
We will buy American to make sure everything from the deck of an aircraft carrier to the steel on highway guardrails are made in America.
But to compete for the best jobs of the future, we also need to level the playing field with China and other competitors.
That’s why it is so important to pass the Bipartisan Innovation Act sitting in Congress that will make record investments in emerging technologies and American manufacturing.
Let me give you one example of why it’s so important to pass it.
If you travel 20 miles east of Columbus, Ohio, you’ll find 1,000 empty acres of land.
It won’t look like much, but if you stop and look closely, you’ll see a “Field of dreams,” the ground on which America’s future will be built.
This is where Intel, the American company that helped build Silicon Valley, is going to build its $20 billion semiconductor “mega site”.
Up to eight state-of-the-art factories in one place. 10,000 new good-paying jobs.
Some of the most sophisticated manufacturing in the world to make computer chips the size of a fingertip that power the world and our everyday lives.
Smartphones. The Internet. Technology we have yet to invent.
But that’s just the beginning.
Intel’s CEO, Pat Gelsinger, who is here tonight, told me they are ready to increase their investment from
$20 billion to $100 billion.
That would be one of the biggest investments in manufacturing in American history.
And all they’re waiting for is for you to pass this bill.
So let’s not wait any longer. Send it to my desk. I’ll sign it.
And we will really take off.
And Intel is not alone.
There’s something happening in America.
Just look around and you’ll see an amazing story.
The rebirth of the pride that comes from stamping products “Made In America.” The revitalization of American manufacturing.
Companies are choosing to build new factories here, when just a few years ago, they would have built them overseas.
That’s what is happening. Ford is investing $11 billion to build electric vehicles, creating 11,000 jobs across the country.
GM is making the largest investment in its history—$7 billion to build electric vehicles, creating 4,000 jobs in Michigan.
All told, we created 369,000 new manufacturing jobs in America just last year.
Powered by people I’ve met like JoJo Burgess, from generations of union steelworkers from Pittsburgh, who’s here with us tonight.
As Ohio Senator Sherrod Brown says, “It’s time to bury the label “Rust Belt.”
It’s time.
But with all the bright spots in our economy, record job growth and higher wages, too many families are struggling to keep up with the bills.
Inflation is robbing them of the gains they might otherwise feel.
I get it. That’s why my top priority is getting prices under control.
Look, our economy roared back faster than most predicted, but the pandemic meant that businesses had a hard time hiring enough workers to keep up production in their factories.
The pandemic also disrupted global supply chains.
When factories close, it takes longer to make goods and get them from the warehouse to the store, and prices go up.
Look at cars.
Last year, there weren’t enough semiconductors to make all the cars that people wanted to buy.
And guess what, prices of automobiles went up.
So—we have a choice.
One way to fight inflation is to drive down wages and make Americans poorer.
I have a better plan to fight inflation.
Lower your costs, not your wages.
Make more cars and semiconductors in America.
More infrastructure and innovation in America.
More goods moving faster and cheaper in America.
More jobs where you can earn a good living in America.
And instead of relying on foreign supply chains, let’s make it in America.
Economists call it “increasing the productive capacity of our economy.”
I call it building a better America.
My plan to fight inflation will lower your costs and lower the deficit.
17 Nobel laureates in economics say my plan will ease long-term inflationary pressures. Top business leaders and most Americans support my plan. And here’s the plan:
First – cut the cost of prescription drugs. Just look at insulin. One in ten Americans has diabetes. In Virginia, I met a 13-year-old boy named Joshua Davis.
He and his Dad both have Type 1 diabetes, which means they need insulin every day. Insulin costs about $10 a vial to make.
But drug companies charge families like Joshua and his Dad up to 30 times more. I spoke with Joshua’s mom.
Imagine what it’s like to look at your child who needs insulin and have no idea how you’re going to pay for it.
What it does to your dignity, your ability to look your child in the eye, to be the parent you expect to be.
Joshua is here with us tonight. Yesterday was his birthday. Happy birthday, buddy.
For Joshua, and for the 200,000 other young people with Type 1 diabetes, let’s cap the cost of insulin at $35 a month so everyone can afford it.
Drug companies will still do very well. And while we’re at it let Medicare negotiate lower prices for prescription drugs, like the VA already does.
Look, the American Rescue Plan is helping millions of families on Affordable Care Act plans save $2,400 a year on their health care premiums. Let’s close the coverage gap and make those savings permanent.
Second – cut energy costs for families an average of $500 a year by combatting climate change.
Let’s provide investments and tax credits to weatherize your homes and businesses to be energy efficient and you get a tax credit; double America’s clean energy production in solar, wind, and so much more; lower the price of electric vehicles, saving you another $80 a month because you’ll never have to pay at the gas pump again.
Third – cut the cost of child care. Many families pay up to $14,000 a year for child care per child.
Middle-class and working families shouldn’t have to pay more than 7% of their income for care of young children.
My plan will cut the cost in half for most families and help parents, including millions of women, who left the workforce during the pandemic because they couldn’t afford child care, to be able to get back to work.
My plan doesn’t stop there. It also includes home and long-term care. More affordable housing. And Pre-K for every 3- and 4-year-old.
All of these will lower costs.
And under my plan, nobody earning less than $400,000 a year will pay an additional penny in new taxes. Nobody.
The one thing all Americans agree on is that the tax system is not fair. We have to fix it.
I’m not looking to punish anyone. But let’s make sure corporations and the wealthiest Americans start paying their fair share.
Just last year, 55 Fortune 500 corporations earned $40 billion in profits and paid zero dollars in federal income tax.
That’s simply not fair. That’s why I’ve proposed a 15% minimum tax rate for corporations.
We got more than 130 countries to agree on a global minimum tax rate so companies can’t get out of paying their taxes at home by shipping jobs and factories overseas.
That’s why I’ve proposed closing loopholes so the very wealthy don’t pay a lower tax rate than a teacher or a firefighter.
So that’s my plan. It will grow the economy and lower costs for families.
So what are we waiting for? Let’s get this done. And while you’re at it, confirm my nominees to the Federal Reserve, which plays a critical role in fighting inflation.
My plan will not only lower costs to give families a fair shot, it will lower the deficit.
The previous Administration not only ballooned the deficit with tax cuts for the very wealthy and corporations, it undermined the watchdogs whose job was to keep pandemic relief funds from being wasted.
But in my administration, the watchdogs have been welcomed back.
We’re going after the criminals who stole billions in relief money meant for small businesses and millions of Americans.
And tonight, I’m announcing that the Justice Department will name a chief prosecutor for pandemic fraud.
By the end of this year, the deficit will be down to less than half what it was before I took office.
The only president ever to cut the deficit by more than one trillion dollars in a single year.
Lowering your costs also means demanding more competition.
I’m a capitalist, but capitalism without competition isn’t capitalism.
It’s exploitation—and it drives up prices.
When corporations don’t have to compete, their profits go up, your prices go up, and small businesses and family farmers and ranchers go under.
We see it happening with ocean carriers moving goods in and out of America.
During the pandemic, these foreign-owned companies raised prices by as much as 1,000% and made record profits.
Tonight, I’m announcing a crackdown on these companies overcharging American businesses and consumers.
And as Wall Street firms take over more nursing homes, quality in those homes has gone down and costs have gone up.
That ends on my watch.
Medicare is going to set higher standards for nursing homes and make sure your loved ones get the care they deserve and expect.
We’ll also cut costs and keep the economy going strong by giving workers a fair shot, provide more training and apprenticeships, hire them based on their skills not degrees.
Let’s pass the Paycheck Fairness Act and paid leave.
Raise the minimum wage to $15 an hour and extend the Child Tax Credit, so no one has to raise a family in poverty.
Let’s increase Pell Grants and increase our historic support of HBCUs, and invest in what Jill—our First Lady who teaches full-time—calls America’s best-kept secret: community colleges.
And let’s pass the PRO Act when a majority of workers want to form a union—they shouldn’t be stopped.
When we invest in our workers, when we build the economy from the bottom up and the middle out together, we can do something we haven’t done in a long time: build a better America.
For more than two years, COVID-19 has impacted every decision in our lives and the life of the nation.
And I know you’re tired, frustrated, and exhausted.
But I also know this.
Because of the progress we’ve made, because of your resilience and the tools we have, tonight I can say
we are moving forward safely, back to more normal routines.
We’ve reached a new moment in the fight against COVID-19, with severe cases down to a level not seen since last July.
Just a few days ago, the Centers for Disease Control and Prevention—the CDC—issued new mask guidelines.
Under these new guidelines, most Americans in most of the country can now be mask free.
And based on the projections, more of the country will reach that point across the next couple of weeks.
Thanks to the progress we have made this past year, COVID-19 need no longer control our lives.
I know some are talking about “living with COVID-19”. Tonight – I say that we will never just accept living with COVID-19.
We will continue to combat the virus as we do other diseases. And because this is a virus that mutates and spreads, we will stay on guard.
Here are four common sense steps as we move forward safely.
First, stay protected with vaccines and treatments. We know how incredibly effective vaccines are. If you’re vaccinated and boosted you have the highest degree of protection.
We will never give up on vaccinating more Americans. Now, I know parents with kids under 5 are eager to see a vaccine authorized for their children.
The scientists are working hard to get that done and we’ll be ready with plenty of vaccines when they do.
We’re also ready with anti-viral treatments. If you get COVID-19, the Pfizer pill reduces your chances of ending up in the hospital by 90%.
We’ve ordered more of these pills than anyone in the world. And Pfizer is working overtime to get us 1 Million pills this month and more than double that next month.
And we’re launching the “Test to Treat” initiative so people can get tested at a pharmacy, and if they’re positive, receive antiviral pills on the spot at no cost.
If you’re immunocompromised or have some other vulnerability, we have treatments and free high-quality masks.
We’re leaving no one behind or ignoring anyone’s needs as we move forward.
And on testing, we have made hundreds of millions of tests available for you to order for free.
Even if you already ordered free tests tonight, I am announcing that you can order more from covidtests.gov starting next week.
Second – we must prepare for new variants. Over the past year, we’ve gotten much better at detecting new variants.
If necessary, we’ll be able to deploy new vaccines within 100 days instead of many more months or years.
And, if Congress provides the funds we need, we’ll have new stockpiles of tests, masks, and pills ready if needed.
I cannot promise a new variant won’t come. But I can promise you we’ll do everything within our power to be ready if it does.
Third – we can end the shutdown of schools and businesses. We have the tools we need.
It’s time for Americans to get back to work and fill our great downtowns again. People working from home can feel safe to begin to return to the office.
We’re doing that here in the federal government. The vast majority of federal workers will once again work in person.
Our schools are open. Let’s keep it that way. Our kids need to be in school.
And with 75% of adult Americans fully vaccinated and hospitalizations down by 77%, most Americans can remove their masks, return to work, stay in the classroom, and move forward safely.
We achieved this because we provided free vaccines, treatments, tests, and masks.
Of course, continuing this costs money.
I will soon send Congress a request.
The vast majority of Americans have used these tools and may want to again, so I expect Congress to pass it quickly.
Fourth, we will continue vaccinating the world.
We’ve sent 475 Million vaccine doses to 112 countries, more than any other nation.
And we won’t stop.
We have lost so much to COVID-19. Time with one another. And worst of all, so much loss of life.
Let’s use this moment to reset. Let’s stop looking at COVID-19 as a partisan dividing line and see it for what it is: A God-awful disease.
Let’s stop seeing each other as enemies, and start seeing each other for who we really are: Fellow Americans.
We can’t change how divided we’ve been. But we can change how we move forward—on COVID-19 and other issues we must face together.
I recently visited the New York City Police Department days after the funerals of Officer Wilbert Mora and his partner, Officer Jason Rivera.
They were responding to a 9-1-1 call when a man shot and killed them with a stolen gun.
Officer Mora was 27 years old.
Officer Rivera was 22.
Both Dominican Americans who’d grown up on the same streets they later chose to patrol as police officers.
I spoke with their families and told them that we are forever in debt for their sacrifice, and we will carry on their mission to restore the trust and safety every community deserves.
I’ve worked on these issues a long time.
I know what works: Investing in crime prevention and community police officers who’ll walk the beat, who’ll know the neighborhood, and who can restore trust and safety.
So let’s not abandon our streets. Or choose between safety and equal justice.
Let’s come together to protect our communities, restore trust, and hold law enforcement accountable.
That’s why the Justice Department required body cameras, banned chokeholds, and restricted no-knock warrants for its officers.
That’s why the American Rescue Plan provided $350 Billion that cities, states, and counties can use to hire more police and invest in proven strategies like community violence interruption—trusted messengers breaking the cycle of violence and trauma and giving young people hope.
We should all agree: The answer is not to Defund the police. The answer is to FUND the police with the resources and training they need to protect our communities.
I ask Democrats and Republicans alike: Pass my budget and keep our neighborhoods safe.
And I will keep doing everything in my power to crack down on gun trafficking and ghost guns you can buy online and make at home—they have no serial numbers and can’t be traced.
And I ask Congress to pass proven measures to reduce gun violence. Pass universal background checks. Why should anyone on a terrorist list be able to purchase a weapon?
Ban assault weapons and high-capacity magazines.
Repeal the liability shield that makes gun manufacturers the only industry in America that can’t be sued.
These laws don’t infringe on the Second Amendment. They save lives.
The most fundamental right in America is the right to vote – and to have it counted. And it’s under assault.
In state after state, new laws have been passed, not only to suppress the vote, but to subvert entire elections.
We cannot let this happen.
Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections.
Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service.
One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court.
And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.
A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans.
And if we are to advance liberty and justice, we need to secure the Border and fix the immigration system.
We can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling.
We’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers.
We’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster.
We’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders.
We can do all this while keeping lit the torch of liberty that has led generations of immigrants to this land—my forefathers and so many of yours.
Provide a pathway to citizenship for Dreamers, those on temporary status, farm workers, and essential workers.
Revise our laws so businesses have the workers they need and families don’t wait decades to reunite.
It’s not only the right thing to do—it’s the economically smart thing to do.
That’s why immigration reform is supported by everyone from labor unions to religious leaders to the U.S. Chamber of Commerce.
Let’s get it done once and for all.
Advancing liberty and justice also requires protecting the rights of women.
The constitutional right affirmed in Roe v. Wade—standing precedent for half a century—is under attack as never before.
If we want to go forward—not backward—we must protect access to health care. Preserve a woman’s right to choose. And let’s continue to advance maternal health care in America.
And for our LGBTQ+ Americans, let’s finally get the bipartisan Equality Act to my desk. The onslaught of state laws targeting transgender Americans and their families is wrong.
As I said last year, especially to our younger transgender Americans, I will always have your back as your President, so you can be yourself and reach your God-given potential.
While it often appears that we never agree, that isn’t true. I signed 80 bipartisan bills into law last year. From preventing government shutdowns to protecting Asian-Americans from still-too-common hate crimes to reforming military justice.
And soon, we’ll strengthen the Violence Against Women Act that I first wrote three decades ago. It is important for us to show the nation that we can come together and do big things.
So tonight I’m offering a Unity Agenda for the Nation. Four big things we can do together.
First, beat the opioid epidemic.
There is so much we can do. Increase funding for prevention, treatment, harm reduction, and recovery.
Get rid of outdated rules that stop doctors from prescribing treatments. And stop the flow of illicit drugs by working with state and local law enforcement to go after traffickers.
If you’re suffering from addiction, know you are not alone. I believe in recovery, and I celebrate the 23 million Americans in recovery.
Second, let’s take on mental health. Especially among our children, whose lives and education have been turned upside down.
The American Rescue Plan gave schools money to hire teachers and help students make up for lost learning.
I urge every parent to make sure your school does just that. And we can all play a part—sign up to be a tutor or a mentor.
Children were also struggling before the pandemic. Bullying, violence, trauma, and the harms of social media.
As Frances Haugen, who is here with us tonight, has shown, we must hold social media platforms accountable for the national experiment they’re conducting on our children for profit.
It’s time to strengthen privacy protections, ban targeted advertising to children, demand tech companies stop collecting personal data on our children.
And let’s get all Americans the mental health services they need. More people they can turn to for help, and full parity between physical and mental health care.
Third, support our veterans.
Veterans are the best of us.
I’ve always believed that we have a sacred obligation to equip all those we send to war and care for them and their families when they come home.
My administration is providing assistance with job training and housing, and now helping lower-income veterans get VA care debt-free.
Our troops in Iraq and Afghanistan faced many dangers.
One was stationed at bases and breathing in toxic smoke from “burn pits” that incinerated wastes of war—medical and hazard material, jet fuel, and more.
When they came home, many of the world’s fittest and best trained warriors were never the same.
Headaches. Numbness. Dizziness.
A cancer that would put them in a flag-draped coffin.
I know.
One of those soldiers was my son Major Beau Biden.
We don’t know for sure if a burn pit was the cause of his brain cancer, or the diseases of so many of our troops.
But I’m committed to finding out everything we can.
Committed to military families like Danielle Robinson from Ohio.
The widow of Sergeant First Class Heath Robinson.
He was born a soldier. Army National Guard. Combat medic in Kosovo and Iraq.
Stationed near Baghdad, just yards from burn pits the size of football fields.
Heath’s widow Danielle is here with us tonight. They loved going to Ohio State football games. He loved building Legos with their daughter.
But cancer from prolonged exposure to burn pits ravaged Heath’s lungs and body.
Danielle says Heath was a fighter to the very end.
He didn’t know how to stop fighting, and neither did she.
Through her pain she found purpose to demand we do better.
Tonight, Danielle—we are.
The VA is pioneering new ways of linking toxic exposures to diseases, already helping more veterans get benefits.
And tonight, I’m announcing we’re expanding eligibility to veterans suffering from nine respiratory cancers.
I’m also calling on Congress: pass a law to make sure veterans devastated by toxic exposures in Iraq and Afghanistan finally get the benefits and comprehensive health care they deserve.
And fourth, let’s end cancer as we know it.
This is personal to me and Jill, to Kamala, and to so many of you.
Cancer is the #2 cause of death in America–second only to heart disease.
Last month, I announced our plan to supercharge
the Cancer Moonshot that President Obama asked me to lead six years ago.
Our goal is to cut the cancer death rate by at least 50% over the next 25 years, turn more cancers from death sentences into treatable diseases.
More support for patients and families.
To get there, I call on Congress to fund ARPA-H, the Advanced Research Projects Agency for Health.
It’s based on DARPA—the Defense Department project that led to the Internet, GPS, and so much more.
ARPA-H will have a singular purpose—to drive breakthroughs in cancer, Alzheimer’s, diabetes, and more.
A unity agenda for the nation.
We can do this.
My fellow Americans—tonight , we have gathered in a sacred space—the citadel of our democracy.
In this Capitol, generation after generation, Americans have debated great questions amid great strife, and have done great things.
We have fought for freedom, expanded liberty, defeated totalitarianism and terror.
And built the strongest, freest, and most prosperous nation the world has ever known.
Now is the hour.
Our moment of responsibility.
Our test of resolve and conscience, of history itself.
It is in this moment that our character is formed. Our purpose is found. Our future is forged.
Well I know this nation.
We will meet the test.
To protect freedom and liberty, to expand fairness and opportunity.
We will save democracy.
As hard as these times have been, I am more optimistic about America today than I have been my whole life.
Because I see the future that is within our grasp.
Because I know there is simply nothing beyond our capacity.
We are the only nation on Earth that has always turned every crisis we have faced into an opportunity.
The only nation that can be defined by a single word: possibilities.
So on this night, in our 245th year as a nation, I have come to report on the State of the Union.
And my report is this: the State of the Union is strong—because you, the American people, are strong.
We are stronger today than we were a year ago.
And we will be stronger a year from now than we are today.
Now is our moment to meet and overcome the challenges of our time.
And we will, as one people.
One America.
The United States of America.
May God bless you all. May God protect our troops.
================================================
FILE: Google Gemini API with Python/GeminiAPI_With_Python.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "MAVEZiWFTGXH"
},
"source": [
"\n",
"## Setup"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "rp_U8LpuTMoI"
},
"source": [
"The Python SDK for the Gemini API, is contained in the [`google-generativeai`](https://pypi.org/project/google-generativeai/) package. Install the dependency using pip:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2Z68sZT_RFPl"
},
"outputs": [],
"source": [
"!pip install -q -U google-generativeai"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "HtoCxa2jTT-o"
},
"source": [
"### Import packages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 62
},
"id": "T6FLLtaCRe8R",
"outputId": "582dc142-910e-4c8e-fe11-a0eaa0d7431b"
},
"outputs": [],
"source": [
"import google.generativeai as genai\n",
"import pathlib\n",
"import textwrap\n",
"from IPython.display import display\n",
"from IPython.display import Markdown\n",
"\n",
"def to_markdown(text):\n",
" text = text.replace('•', ' *')\n",
" return Markdown(textwrap.indent(text, '> ', predicate=lambda _: True))\n",
"\n",
"\n",
"# Example usage:\n",
"input_text = \"This is a • sample text with bullet points.\"\n",
"result = to_markdown(input_text)\n",
"\n",
"display(result)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "YdRHFl1-TdrI"
},
"source": [
"### Setup your API key\n",
"\n",
"Before you can use the Gemini API, you must first obtain an API key. If you don't already have one, create a key with one click in Google AI Studio.\n",
"\n",
"Get an API key\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "mm2gARR9TlsI"
},
"source": [
"In Colab, add the key to the secrets manager under the \"🔑\" in the left panel. Give it the name `GOOGLE_API_KEY`.\n",
"\n",
"Once you have the API key, pass it to the SDK. You can do this in two ways:\n",
"\n",
"* Put the key in the `GOOGLE_API_KEY` environment variable (the SDK will automatically pick it up from there).\n",
"* Pass the key to `genai.configure(api_key=...)`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ZcbuuQQ9SOmo"
},
"outputs": [],
"source": [
"# Used to securely store your API key\n",
"from google.colab import userdata"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qWgCX3sJTCn2"
},
"outputs": [],
"source": [
"GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "djrw9PeOTDuf"
},
"outputs": [],
"source": [
"genai.configure(api_key=GOOGLE_API_KEY)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "rgmaAm3BTMaJ",
"outputId": "57bf1d07-bc46-4f50-b61c-c16c67434af9"
},
"outputs": [],
"source": [
"for m in genai.list_models():\n",
" print(m)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "T4IjmRmJTF-Q",
"outputId": "cfc439ce-5b55-4438-e167-8e7e5df11f26"
},
"outputs": [],
"source": [
"for m in genai.list_models():\n",
" if 'generateContent' in m.supported_generation_methods:\n",
" print(m.name)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "icUyuYi6UC-o"
},
"source": [
"The `genai` package also supports the PaLM family of models, but only the Gemini models support the generic, multimodal capabilities of the `generateContent` method."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "NCfPoXTDThip"
},
"source": [
"# Generate text from text inputs"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "q5iHVxwDbya3"
},
"source": [
"The available models only support text and images as input, and text as output."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vBXr8sWRTiR_"
},
"outputs": [],
"source": [
"model = genai.GenerativeModel('gemini-pro')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "PdNNLhomTk6g",
"outputId": "006d5bfc-896a-4c57-cde3-96a2e9acbc7a"
},
"outputs": [],
"source": [
"%%time\n",
"response = model.generate_content(\"What is the meaning of life?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "FbfpVehlTqG4",
"outputId": "39333ece-2435-4a31-ec3f-20800759b93a"
},
"outputs": [],
"source": [
"response"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 757
},
"id": "RajPP2kmTwQf",
"outputId": "1786a5b2-da84-4039-803c-4e52158cb80a"
},
"outputs": [],
"source": [
"to_markdown(response.text)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "dLjbFmdOcIv1"
},
"source": [
"If the API failed to return a result, use `GenerateContentRespose.prompt_feedback` to see if it was blocked due to safety concerns regarding the prompt."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "w5affs4sTyQ3",
"outputId": "6ea6448d-2f19-4223-a287-a26b36c0dea5"
},
"outputs": [],
"source": [
"response.prompt_feedback"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "kOP2RDWKcTel"
},
"source": [
"Gemini can generate multiple possible responses for a single prompt. These possible responses are called `candidates`, and you can review them to select the most suitable one as the response.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "eCUaPu1MT7h_",
"outputId": "6a16fc94-8c18-48a0-c47d-76afad08c877"
},
"outputs": [],
"source": [
"response.candidates"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "vKHqLNWJc0gN"
},
"source": [
"By default, the model returns a response after completing the entire generation process. You can also stream the response as it is being generated, and the model will return chunks of the response as soon as they are generated."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 679
},
"id": "4Hbfd4_wT96G",
"outputId": "e545d351-7dab-458d-d10c-8e1178ac0bed"
},
"outputs": [],
"source": [
"%%time\n",
"response = model.generate_content(\"What is the meaning of life?\", stream=True)\n",
"for chunk in response:\n",
" print(chunk.text)\n",
" print(\"_\"*80)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4RggW3P5UIke",
"outputId": "418ce66e-6e75-47ef-e0be-92601804f252"
},
"outputs": [],
"source": [
"response.prompt_feedback"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "b3iP6lJCUSC3"
},
"source": [
"# Generate text from image"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "bPGPYvAVUnTe"
},
"source": [
"## Generate text from image and text inputs\n",
"\n",
"Gemini provides a multimodal model (`gemini-pro-vision`) that accepts both text and images and inputs. The `GenerativeModel.generate_content` API is designed to handle multimodal prompts and returns a text output.\n",
"\n",
"Let's include an image:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gigaE3R9Uo_f",
"outputId": "6085fcf2-d42b-44b1-b477-a36fcd5dc767"
},
"outputs": [],
"source": [
"!curl -o image.jpg https://t0.gstatic.com/licensed-image?q=tbn:ANd9GcQ_Kevbk21QBRy-PgB4kQpS79brbmmEG7m3VOTShAn4PecDU5H5UxrJxE3Dw1JiaG17V88QIol19-3TM2wCHw"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "b4nG8QBseQGl",
"outputId": "f8c85ece-2e2d-45a2-f242-a5769cd7c277"
},
"outputs": [],
"source": [
"!curl -o image.jpg https://images.pexels.com/photos/414612/pexels-photo-414612.jpeg?cs=srgb&dl=pexels-james-wheeler-414612.jpg&fm=jpg"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"background_save": true
},
"id": "QntZInHvUrP8",
"outputId": "4622d88b-043d-42d1-974d-0db581677565"
},
"outputs": [],
"source": [
"import PIL.Image\n",
"\n",
"img = PIL.Image.open('image.jpg')\n",
"img"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"background_save": true
},
"id": "4t2w6nqqUvVG"
},
"outputs": [],
"source": [
"model = genai.GenerativeModel('gemini-pro-vision')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"background_save": true
},
"id": "k61ieAUNeB38",
"outputId": "edec6fb7-0727-4d13-e4f5-a385593c9576"
},
"outputs": [],
"source": [
"response = model.generate_content(img)\n",
"\n",
"to_markdown(response.text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"background_save": true
},
"id": "E15inz5OUy54"
},
"outputs": [],
"source": [
"response = model.generate_content([\"Write a short, engaging blog post based on this picture. It should include a description of the meal in the photo and talk about my journey meal prepping.\", img], stream=True)\n",
"response.resolve()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 243
},
"id": "M7MQutLrU1B5",
"outputId": "07807278-0a8a-41d3-c8d0-37e39b3c1d5b"
},
"outputs": [],
"source": [
"to_markdown(response.text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IYEXUtrcU2y-"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "nWDB9APrU6dV"
},
"source": [
"## Chat conversations\n",
"\n",
"Gemini enables you to have freeform conversations across multiple turns. The `ChatSession` class simplifies the process by managing the state of the conversation, so unlike with `generate_content`, you do not have to store the conversation history as a list.\n",
"\n",
"Initialize the chat:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7WNebflnU8FP",
"outputId": "af00f734-2470-41cf-dc73-55a054ccdba5"
},
"outputs": [],
"source": [
"model = genai.GenerativeModel('gemini-pro')\n",
"chat = model.start_chat(history=[])\n",
"chat"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 62
},
"id": "QH2ACfBsVF4m",
"outputId": "0be79288-1123-4eed-a5df-8e74c61d6433"
},
"outputs": [],
"source": [
"response = chat.send_message(\"In one sentence, explain how a computer works to a young child.\")\n",
"to_markdown(response.text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "oudynKhTVHli",
"outputId": "e0ad88fb-943f-4692-b8dd-a16f65a2fefd"
},
"outputs": [],
"source": [
"chat.history"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "uS0bdROFVPNN"
},
"source": [
"You can keep sending messages to continue the conversation. Use the `stream=True` argument to stream the chat:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 220
},
"id": "9IkJPKrbVQlA",
"outputId": "0f517637-ab73-44e9-a635-dc2259e7fdb6"
},
"outputs": [],
"source": [
"response = chat.send_message(\"Okay, how about a more detailed explanation to a high schooler?\", stream=True)\n",
"\n",
"for chunk in response:\n",
" print(chunk.text)\n",
" print(\"_\"*80)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 301
},
"id": "Cunuisn9VShg",
"outputId": "1749f5cb-58c8-4555-8f47-bc1af5f443db"
},
"outputs": [],
"source": [
"for message in chat.history:\n",
" display(to_markdown(f'**{message.role}**: {message.parts[0].text}'))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "mGKloAy7hjDv"
},
"source": [
"## Count tokens"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "U3IZy5anh1el",
"outputId": "f0505b38-c8ea-4ebf-a42d-e4e7c9235b8e"
},
"outputs": [],
"source": [
"model.count_tokens(\"What is the meaning of life?\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Z1Xs4Jv1iLNt"
},
"source": [
"## Use embeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "kX34sRbkh4hd",
"outputId": "6cf19685-53f6-478a-d6a0-172d33e73b87"
},
"outputs": [],
"source": [
"result = genai.embed_content(\n",
" model=\"models/embedding-001\",\n",
" content=\"What is the meaning of life?\",\n",
" task_type=\"retrieval_document\",\n",
" title=\"Embedding of single string\")\n",
"\n",
"# 1 input > 1 vector output\n",
"print(str(result['embedding'])[:50], '... TRIMMED]')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 72
},
"id": "zePmMj0OiSK0",
"outputId": "c61c4dbf-3883-49ba-8e41-2b1c8df0ef65"
},
"outputs": [],
"source": [
"result = genai.embed_content(\n",
" model=\"models/embedding-001\",\n",
" content=[\n",
" 'What is the meaning of life?',\n",
" 'How much wood would a woodchuck chuck?',\n",
" 'How does the brain work?'],\n",
" task_type=\"retrieval_document\",\n",
" title=\"Embedding of list of strings\")\n",
"\n",
"# A list of inputs > A list of vectors output\n",
"for v in result['embedding']:\n",
" print(str(v)[:50], '... TRIMMED ...')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Gg7JC4C4iVWF",
"outputId": "c42c2bfd-e2db-4b2b-c614-0ac940191115"
},
"outputs": [],
"source": [
"response.candidates[0].content"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "xXfS1ZrLiXo9",
"outputId": "45f3c35c-66d5-48d7-9243-6f54a2494d98"
},
"outputs": [],
"source": [
"result = genai.embed_content(\n",
" model = 'models/embedding-001',\n",
" content = response.candidates[0].content)\n",
"\n",
"# 1 input > 1 vector output\n",
"print(str(result['embedding'])[:50], '... TRIMMED ...')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "mLuIXjsxiat9",
"outputId": "8bac0bdd-ce28-4af4-d9be-6dc469346ced"
},
"outputs": [],
"source": [
"chat.history"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
},
"id": "EFWNKeIYica1",
"outputId": "f0cfaf2c-80a5-4c04-b4f1-715d1a79ead7"
},
"outputs": [],
"source": [
"result = genai.embed_content(\n",
" model = 'models/embedding-001',\n",
" content = chat.history)\n",
"\n",
"# 1 input > 1 vector output\n",
"for i,v in enumerate(result['embedding']):\n",
" print(str(v)[:50], '... TRIMMED...')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "A5Kgm8Jdi57G"
},
"source": [
"## Advanced use cases\n",
"\n",
"The following sections discuss advanced use cases and lower-level details of the Python SDK for the Gemini API."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0G5dzrOBi9pJ"
},
"source": [
"### Safety settings\n",
"\n",
"The `safety_settings` argument lets you configure what the model blocks and allows in both prompts and responses. By default, safety settings block content with medium and/or high probability of being unsafe content across all dimensions. Learn more about [Safety settings](https://ai.google.dev/docs/safety_setting).\n",
"\n",
"Enter a questionable prompt and run the model with the default safety settings, and it will not return any candidates:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "yp8O8tZOj3AP"
},
"outputs": [],
"source": [
"response = model.generate_content('how i can built time bomb?')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "LactHc_fj49o",
"outputId": "31adfdfd-c447-40d8-ad94-c8d165d7589e"
},
"outputs": [],
"source": [
"response"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JrVz4pSsjA5-",
"outputId": "f8316f5b-be2e-4cf4-c8a5-60091973aeee"
},
"outputs": [],
"source": [
"response.candidates"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "esrIvtaMjBXs",
"outputId": "64cfa1c4-461b-4ebb-8c8f-5c3afae17ba4"
},
"outputs": [],
"source": [
"response.prompt_feedback"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 36
},
"id": "9ZNGftn_jHvl",
"outputId": "ca98a274-b01e-4ac8-c909-2bd5c8c644e5"
},
"outputs": [],
"source": [
"response.text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "BejRyCWwjV-k"
},
"outputs": [],
"source": [
"response = model.generate_content('what is sex?',safety_settings={'HARASSMENT':'block_none'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "vv-SheqbkJMc",
"outputId": "ab881adf-43fd-4af2-f40e-d60fffec111f"
},
"outputs": [],
"source": [
"response"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 479
},
"id": "V6nrxHhkkNkF",
"outputId": "7c122341-4106-4530-d179-56927806acb9"
},
"outputs": [],
"source": [
"response.text"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "g6y4cMmVk3qu"
},
"source": [
"### Encode messages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "-l6QczJzkP9s"
},
"outputs": [],
"source": [
"import google.ai.generativelanguage as glm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2QYuyvSTkgzW"
},
"outputs": [],
"source": [
"model = genai.GenerativeModel('gemini-pro-vision')\n",
"response = model.generate_content(\n",
" glm.Content(\n",
" parts = [\n",
" glm.Part(text=\"Write a short, engaging blog post based on this picture.\"),\n",
" glm.Part(\n",
" inline_data=glm.Blob(\n",
" mime_type='image/jpeg',\n",
" data=pathlib.Path('image.jpg').read_bytes()\n",
" )\n",
" ),\n",
" ],\n",
" ),\n",
" stream=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 62
},
"id": "Mw8rnZx9ki9l",
"outputId": "6edb18de-b7b1-40c6-9ee2-6a6d52f75a65"
},
"outputs": [],
"source": [
"response.resolve()\n",
"\n",
"to_markdown(response.text[:100] + \"... [TRIMMED] ...\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 114
},
"id": "fmKSew8jkw6k",
"outputId": "57679295-dc87-4ea1-ae03-208e5323b322"
},
"outputs": [],
"source": [
"model = genai.GenerativeModel('gemini-pro')\n",
"\n",
"messages = [\n",
" {'role':'user',\n",
" 'parts': [\"Briefly explain how a computer works to a young child.\"]}\n",
"]\n",
"response = model.generate_content(messages)\n",
"\n",
"to_markdown(response.text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 630
},
"id": "LecQX3nSlHiE",
"outputId": "6d60d3bd-6624-4bbd-b045-170971fa3ad1"
},
"outputs": [],
"source": [
"messages.append({'role':'model',\n",
" 'parts':[response.text]})\n",
"\n",
"messages.append({'role':'user',\n",
" 'parts':[\"Okay, how about a more detailed explanation to a high school student?\"]})\n",
"\n",
"response = model.generate_content(messages)\n",
"\n",
"to_markdown(response.text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XtFB6BYxlMM1"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "eu-eAsa0lcKw"
},
"source": [
"### Generation configuration\n",
"\n",
"The `generation_config` argument allows you to modify the generation parameters. Every prompt you send to the model includes parameter values that control how the model generates responses."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bsgTm9XplcwU"
},
"outputs": [],
"source": [
"model = genai.GenerativeModel('gemini-pro')\n",
"response = model.generate_content(\n",
" 'Tell me a story about a magic backpack.',\n",
" generation_config=genai.types.GenerationConfig(\n",
" # Only one candidate for now.\n",
" candidate_count=1,\n",
" stop_sequences=['x'],\n",
" max_output_tokens=20,\n",
" temperature=1.0)\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 401
},
"id": "3yaYlcAWllSs",
"outputId": "3ba39153-e9c6-4480-d9a0-3d5345aee604"
},
"outputs": [],
"source": [
"text = response.text\n",
"\n",
"if response.candidates[0].finish_reason.name == \"MAX_TOKENS\":\n",
" text += '...'\n",
"\n",
"to_markdown(text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "28x-MV80lqxV"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: LCEL(Langchain_Expression_Language).ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "e9BSbrZq-Uqj"
},
"source": [
"## Transitioning from Old class to New Pipe Base Operator\n",
"\n",
"## 1. Understanding `Runnables`\n",
"- `Runnables` are self-contained units of work.\n",
"- Can be executed in isolation or combined for complex operations.\n",
"- Provides flexibility in execution (sync, async, parallel).\n",
"\n",
"## 2. `RunnableParallel`\n",
"- Executes tasks concurrently.\n",
"- Useful for performance enhancement in scenarios where tasks can run independently.\n",
"- Syntax example:\n",
" ```python\n",
" from some_module import RunnableParallel\n",
" ```\n",
"\n",
"## 3. `RunnablePassthrough`\n",
"- A simple `Runnable` that passes inputs directly to outputs without modification.\n",
"- Helpful for debugging or chaining in pipelines.\n",
"- Example use case:\n",
" ```python\n",
" from some_module import RunnablePassthrough\n",
" passthrough = RunnablePassthrough()\n",
" result = passthrough.run(input_data)\n",
" ```\n",
"\n",
"## 4. `RunnableLambda`\n",
"- Allows quick, inline definitions of small, custom functions.\n",
"- Example:\n",
" ```python\n",
" from some_module import RunnableLambda\n",
" lambda_op = RunnableLambda(lambda x: x * 2)\n",
" result = lambda_op.run(5) # Output: 10\n",
" ```\n",
"\n",
"## 5. Assign Functions\n",
"- Used to assign values or parameters during execution.\n",
"- Useful in data pipelines to update intermediate values.\n",
"\n",
"## 6. Performance Improvement (Inference Speed)\n",
"- Focus on optimizing the inference speed by leveraging parallel execution.\n",
"- Use `RunnableParallel` or batching techniques.\n",
"- Consider optimizing data pipelines by removing unnecessary steps.\n",
"\n",
"## 7. Async Invoke\n",
"- Executes operations asynchronously, improving the overall throughput of the system.\n",
"- Syntax example:\n",
" ```python\n",
" async def async_operation():\n",
" result = await some_async_function()\n",
" ```\n",
"\n",
"## 8. Batch Support\n",
"- Handles multiple inputs at once to improve performance.\n",
"- Can be combined with `RunnableParallel` for parallel batch execution.\n",
"\n",
"## 9. Async Batch Execution\n",
"- Combines asynchronous execution with batch processing for high-performance tasks.\n",
"- Reduces overall execution time for larger datasets.\n",
"\n",
"## 10. Using `Itemgetter` with `LCEL`\n",
"- `Itemgetter` is used to extract specific items from collections.\n",
"- When combined with `LCEL` (LangChain Execution Layer), it can streamline complex operations.\n",
"\n",
"## 11. Bind Tools\n",
"- `Bind` tools help to connect different steps in the pipeline.\n",
"- Ensures smooth data flow between various `Runnable` components.\n",
"\n",
"## 12. Stream Support\n",
"- Keep your pipelines more responsive by incorporating stream support for data.\n",
"- This allows continuous data processing and near real-time outputs.\n",
" \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "3einjXsX3RgD",
"outputId": "ed88ee6f-4081-492b-a10f-0cf8c79121d3"
},
"outputs": [],
"source": [
"!pip install langchain_google_genai\n",
"!pip install langchain_community\n",
"!pip install langchain\n",
"!pip install langchain_huggingface\n",
"!pip install langchain_groq"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "rxKWe5nxCpRj"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"GROQ_API_KEY=userdata.get('GROQ_API_KEY')\n",
"import os\n",
"os.environ[\"GROQ_API_KEY\"]=GROQ_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gigsz8A_Cswd"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')\n",
"import os\n",
"os.environ[\"GOOGLE_API_KEY\"]=GOOGLE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "-T6Y59BhC_05"
},
"outputs": [],
"source": [
"from langchain_google_genai import GoogleGenerativeAIEmbeddings\n",
"embeddings = GoogleGenerativeAIEmbeddings(model=\"models/embedding-001\")\n",
"from langchain_google_genai import ChatGoogleGenerativeAI\n",
"llm = ChatGoogleGenerativeAI(model=\"gemini-1.0-pro\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 424,
"referenced_widgets": [
"f227a0992bde4673af0fb062aa5b35e8",
"0f82ee1dd69942bb9c3b7768619237ca",
"6f535b58873248698e94c5bf9cff6a58",
"3fbcde1c16644a8083f5ad7141d584a9",
"5b3ea04a18f341cab660bb8750548975",
"5bbb9df62d394236885e2e2866846581",
"9ce089032c6b49f9bf40d637c0efef6e",
"37733f7c7f584057b9cf7faa0b0c3760",
"c02b648dd77d4ef0af423890c32f2f30",
"3c0573e4f8744ddea2654f31cc85ff2d",
"a77916c64d1d46b3afe624ad02ca4137",
"33b81cf377fb42a585f77e67399e082b",
"7fd723a318324a79bf33abfe56d3620d",
"918ef72969bb4815a8876164cc56d1fc",
"3483fb7f00f04cef9958e370fb9c8a8c",
"6da2c67cf3bf4814bcd64dfca244776e",
"24721c2aad2c4fa590e5bb486341402a",
"e7f09a2c0ff84825867ee6ec25bc10f7",
"45f9a0c73f004ef69a76e200309570f4",
"5566c6a8f8ff40818436490b9e07173e",
"e08b06fb92d8449db0b357558c25d620",
"628c5f16be4045ca99d9467fa07bd888",
"29b6b20ce1b847309bc9549f208bfe39",
"954fe98f3261408aa10491d96f19e272",
"0927025465b0492d81409fb71018bd60",
"e14d291267454ec7a181ddf6929c33bb",
"0b78598e186a4d1980d5196ffd44cde7",
"876c972040d24ca8a1e04816afa89866",
"8b537c3657de40999e86bfecafc583f9",
"9d71e1827f574c9eadc792509f4d17fb",
"9101047b368a47418b1af2852dca6309",
"248c31eb970f4f08aaab64374420adb4",
"7460ad56137c4789bd01ee3770ebb4d4",
"e14b79c1eb09499f925c5abc87f9e358",
"07c4f947bfe245f4adb3cf375f089939",
"d8f943cdce2a4e30a4a47dad04f05d28",
"a2114d55fda4451d902c0ef1aa12a428",
"2965df6c49044b35b3ba6d2cdc24d74d",
"d7c44beb266141d3875b800de14214aa",
"423c43f9333c464594d744a6c5d8be8a",
"ec1075c521644d3f953a16cbe1f2e030",
"2ce57d428da04626be6995389469ab28",
"48ca0355d5c740f59db88d4332353ee7",
"19789d9a79fd4742af4e1dafee03c1b1",
"6076bc5b88e640a39a45107139036090",
"7b9ed53198aa46fea9f0875fd07999c5",
"708cf9ffbd7c4dfd9bb35581026f12d9",
"bdde8937a9a0463388d84a721b95d31f",
"a28656b202ea4b75a3dc564616d209f8",
"09caf4b59d1a4b579a9a590b748c53b6",
"ba06a80754314d20836a87ded5becb99",
"f88d5e5fb2734091b1916b578cf4a8b9",
"381aa0cbbe4044999bca9df41dd00664",
"f9da47d45cbd423e9c74e48e82452b83",
"074a6471fdbe40ed9acfbe2f5e949c2f",
"e8d779e8ed5a4d659c74aa586c169c57",
"ff51e0815d29426d9304a0d781dafb12",
"72b6c4c385af44e1bba560296276db76",
"211627521efb4a829aebb5e64cdd2115",
"2bcfc3e35bd54e0f8eb411e2accaffd4",
"f71bb3b2677c43bd8b918346db36be48",
"b5526335d665446daf7e5837c8dea650",
"2ff329f286054bcaae5fc27cf67ed36f",
"fe4a5fec3f0f46eda3d9b1b44a20a4e2",
"b264cfc0a5c24aa193d246fbc3de15e5",
"110d0c5bef664638b7977f46f0735905",
"b3651292353c458099e7e96a8a002096",
"e220c44bbc18421d8d147ca77e6788bd",
"53cd5af714e6466cacc1dc92d478b775",
"d3606dc8cdb141ed8fca43bb6ce043c7",
"cdc13486cd4d4b35afa107c79675a19d",
"58d206a51602494abfbffab3f862015b",
"8fc3256efadb4fb3827e8a88e6acb998",
"2e525eb63279444fb86403a0ea77addb",
"1a32af7ea56843d982e2d4f794c6dfe8",
"85e14014592f492782b195a283ba74ad",
"131c46f2ecf6494b97829e9ba56d49ee",
"d12085da77d84d0ab0884a36c3b63a8c",
"972a61bd9c4d499b938c16a982410ca7",
"cad4498ad3f64a9c93065415c36adb29",
"4c7a2b0542674b7aaeccce12591528ed",
"830add38427f45568eb0700b8136a737",
"8eac6546a3af4e1597184bd879817cf7",
"b824f2ae1ac04cd78a093d6e196a7f97",
"cb1c6c4e740b4a91b4a0f12a5adbe9d7",
"12061393e24442a1ac19f59df7c8ed02",
"02b9bc0c2f2f4201b6ff2a2412c5e7a7",
"18009a48070c44c3a428ebfc174efe15",
"d1ae802dba1149ca9e4def59a72ec3ba",
"3b252b6cee3c4543bb8919f80eebe288",
"56efd36f6e5c4ab29702cf374d442039",
"290d595d8e58474faee18e36c503249f",
"aecd0585304f43e5aa8086877e41e679",
"f408d390719b4587bf89a2e6d4245f39",
"b4444854e39f4b3eb9c20553aa509790",
"7548118226e74462b1fb7ccf470707dc",
"fce994a8f0a742a39d7a009cbcd91db7",
"c666a1a873e74e1f87570d25e5839c3b",
"fb08084b416f40818b123916cac094de",
"0201bd357a964ef28e97bf63947147a0",
"9b326f532e5f46dd8c64a37ca7d23bfa",
"b95bc3eb580248ec8f31ef90419f9ce1",
"316acc82952243649ee78e5bf7357811",
"1cd8d4ce444d4bf185bf1ce8668486dc",
"487f9f61b45e4365b0ac0dfc7a64eca3",
"a5b48868639f494fb1dc7a52ad9a2ab5",
"53e3b30a041d4a31938adb1cf6d55c46",
"7c8dbffeb2294ad590974f644847a2c3",
"9c45a4095bc34f15b4415f58edbb17df",
"49125bd1de2b46899a52c69d54e6ace0",
"e8e8700a0b45490992fae82f6e04ccf0",
"ef43923528a84424bde4490feb99cf6e",
"dd26fb9910ba4bffaa5d4db648e951ef",
"715c8f7ed318476faf6dd2309530162f",
"b15aecf8ca824865934329dd8fb6b232",
"d132cbcf72a346c9974b776cd7d55d47",
"dc464f3338c2435b84b75db1f8e6e416",
"1f29ae9f38694368adc61335125598e0",
"367c6767a186473d83432d8f38aba8cb",
"c625fadf89a945a098c8cab8c79edaed",
"00ddbe52e41b48a890d99c146637f9fc"
]
},
"id": "PP7O_-5CDLs5",
"outputId": "621a1489-08f7-46bd-b1e0-93901ae9b04c"
},
"outputs": [],
"source": [
"'''from langchain_huggingface import HuggingFaceEmbeddings\n",
"embeddings=HuggingFaceEmbeddings(model_name=\"all-MiniLM-L6-v2\")\n",
"from langchain_groq import ChatGroq\n",
"import os\n",
"llm=ChatGroq(model_name=\"Gemma2-9b-It\")'''"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "imELHoVZMR53"
},
"source": [
"# this is my simple chain (old chaining concept)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pZOC6k1_DSpM"
},
"outputs": [],
"source": [
"template= 'Hi! I am learning {skill}. Can you suggest me top 5 things to learn?\\n'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "l6nUqQ7NDf0h"
},
"outputs": [],
"source": [
"from langchain import PromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cqgbDPABDhkL"
},
"outputs": [],
"source": [
"prompt = PromptTemplate(template=template,input_variables=[\"skill\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "iVMhFTXfDpmz",
"outputId": "9d269bdd-2fce-4ef4-aea7-83444fd39597"
},
"outputs": [],
"source": [
"print(prompt)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2n2FbzaUDsHx"
},
"outputs": [],
"source": [
"from langchain import LLMChain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bgv6v3kRD1wh"
},
"outputs": [],
"source": [
"llm_chain = LLMChain(prompt=prompt,llm=llm)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "y0vv9CH-EAuR",
"outputId": "e77a91e6-e5aa-4388-b500-754f41c4134d"
},
"outputs": [],
"source": [
"print(llm_chain.run('Data Science'))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "QSlUMR_BELrZ",
"outputId": "a5e201d1-f434-4193-a7ee-db7caed30369"
},
"outputs": [],
"source": [
"print(llm_chain.run({'skill':'Data Science'}))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Sw-ow6nHNIZQ"
},
"source": [
"# this is a implementation using LCEL"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "BkHP_36eEXNp",
"outputId": "989af42e-3465-4ea3-bf53-3a792bdd8557"
},
"outputs": [],
"source": [
"llm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "J-SyysJqMd5T",
"outputId": "a7c01f22-7c96-491d-ee4f-43cbfb7c312f"
},
"outputs": [],
"source": [
"prompt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0x3jF1zHMgrT"
},
"outputs": [],
"source": [
"chain = prompt | llm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "HlWhjIxJMlMz",
"outputId": "718b5767-42b4-45a1-d663-de5d1ec77080"
},
"outputs": [],
"source": [
"print(chain.invoke({'skill':'Big Data'}))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "D1g1TnedM08c"
},
"outputs": [],
"source": [
"from langchain_core.output_parsers import StrOutputParser"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7hLevRtnM4v1"
},
"outputs": [],
"source": [
"parser = StrOutputParser()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Y8m8mq1wM7wj"
},
"outputs": [],
"source": [
"chain = prompt | llm | parser"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rQ4mSKFgM_rM",
"outputId": "d1e81fcf-175e-4efc-d103-718a5a74401c"
},
"outputs": [],
"source": [
"print(chain.invoke({'skill':'Machine Learning'}))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "99PwfyAjNNpv"
},
"source": [
"# lets discuss about the runnables"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "6o2eHdFXNDhT"
},
"outputs": [],
"source": [
"from langchain_core.runnables import RunnableParallel, RunnablePassthrough , RunnableLambda"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "thIShr5mNhm_"
},
"outputs": [],
"source": [
"chain = RunnablePassthrough()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "AQRkFFeMNmLb",
"outputId": "8999112b-e24b-4d5a-b053-4229ec0f5ee0"
},
"outputs": [],
"source": [
"chain.invoke('Welcome to this youtube channel')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "uZ_-Vw1RNzls"
},
"outputs": [],
"source": [
"chain = RunnablePassthrough() | RunnablePassthrough() | RunnablePassthrough()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "G1TYVRLYN83A",
"outputId": "9784600c-fa77-4ff5-9745-3b762d6178ff"
},
"outputs": [],
"source": [
"chain.invoke('Welcome to my sunny\"s youtube channel')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fPpAEYVJORUf"
},
"outputs": [],
"source": [
"def string_upper(input):\n",
" return input.upper()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RkrgncYDN-ej"
},
"outputs": [],
"source": [
"chain = RunnablePassthrough() | RunnableLambda(string_upper)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "TfkJXhuKOYGj",
"outputId": "59974653-d974-4513-b418-837231482548"
},
"outputs": [],
"source": [
"chain.invoke('Welcome to my sunny\"s youtube channel')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 141
},
"id": "hbipHFRNOm3A",
"outputId": "f4655d86-4682-416e-cf2f-5e078e298f62"
},
"outputs": [],
"source": [
"string_upper.invoke('Welcome to my sunny\"s youtube channel')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dytKiiXVOm5O"
},
"outputs": [],
"source": [
"chain = RunnableLambda(string_upper)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "d9LJwI12PAi1",
"outputId": "263e35f7-4ab8-489f-8dfe-8183cdea32f3"
},
"outputs": [],
"source": [
"chain.invoke('Welcome to my sunny\"s youtube channel')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3ZGkNnXjPEWU"
},
"outputs": [],
"source": [
"chain = RunnableParallel({'x':RunnablePassthrough(),'y':RunnablePassthrough()})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "9aBTG_OsPPA8",
"outputId": "b1ea167d-e1b9-4c25-fe31-0858854cf4bc"
},
"outputs": [],
"source": [
"chain.invoke(\"Sunny\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "FSP5r-qxPSjU",
"outputId": "3f3431bb-1255-42e0-fb48-64c0079666eb"
},
"outputs": [],
"source": [
"chain.invoke({'Youtube': '@sunnysavita10','Blog': \"Sunny's blog\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "wmX6hCbPTJrI"
},
"outputs": [],
"source": [
"lambda x: x['Blog']"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xD3lHrcIQazJ"
},
"outputs": [],
"source": [
"chain = RunnableParallel({'x':RunnablePassthrough(),'Blog':lambda x: x['Blog']})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "3hM3gBqtQcCa",
"outputId": "665da4fd-07b5-4d97-d70d-1d630b4df5f9"
},
"outputs": [],
"source": [
"chain.invoke({'Youtube': '@sunnysavita10','Blog': \"Sunny's blog\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "U4SUTxQ0QdUW"
},
"outputs": [],
"source": [
"def fetch_website(input: dict):\n",
" output = input.get('Website','Not found')\n",
" return output"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "15vR9qJzTs5M"
},
"outputs": [],
"source": [
"mydict={'Youtube': '@sunnysavita10','Blog': \"Sunny's blog\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "DChnkIoFTwpn",
"outputId": "554609b8-8c43-4dcd-b11d-4508af64d145"
},
"outputs": [],
"source": [
"mydict.get(\"website\",\"Not found\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "r4ApiixHQe0n"
},
"outputs": [],
"source": [
"chain = RunnableParallel({'Website':RunnablePassthrough() | RunnableLambda(fetch_website),\n",
" 'Blog':lambda z: z['Blog']})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7tSnqZ9-QgCI",
"outputId": "172f2641-4016-4191-bcc2-a0ee696700fd"
},
"outputs": [],
"source": [
"chain.invoke({'Youtube': '@sunnysavita10','Blog': \"Sunny's blog\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "P9UWY3o2QhcI",
"outputId": "6536bcbc-28c3-4802-a672-264f50b3e13f"
},
"outputs": [],
"source": [
"chain.invoke({'Youtube': '@sunnysavita10','Blog': \"Sunny's blog\" , 'Website' : 'sunnysavita.com'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4xKCFIioQi8Y"
},
"outputs": [],
"source": [
"def extra_func(input):\n",
" return 'Happy Learning'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ymBvP7r9QkTv"
},
"outputs": [],
"source": [
"chain = RunnableParallel({'x' : RunnablePassthrough()}).assign(extra=RunnableLambda(extra_func))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "W6ZoETBaUf4f"
},
"outputs": [],
"source": [
"chain = RunnableParallel({'x' : RunnablePassthrough()}).assign(y=RunnableLambda(extra_func))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "cIYfRydBQliP",
"outputId": "1fa3bb6c-c429-4a48-e353-9674a2ab7c9d"
},
"outputs": [],
"source": [
"chain.invoke('Hello')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "NfjIKZsvUZR2",
"outputId": "61a639fc-65c7-4d83-bba8-5795271e99c5"
},
"outputs": [],
"source": [
"!pip install chromadb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "oxWNmfPJUrZs"
},
"outputs": [],
"source": [
"from langchain_community.document_loaders import TextLoader, DirectoryLoader\n",
"from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
"from langchain_community.vectorstores import Chroma\n",
"\n",
"### Reading the txt files from source directory\n",
"\n",
"loader = DirectoryLoader('./source', glob=\"./*.txt\", loader_cls=TextLoader)\n",
"docs = loader.load()\n",
"\n",
"### Creating Chunks using RecursiveCharacterTextSplitter\n",
"\n",
"text_splitter = RecursiveCharacterTextSplitter(\n",
" chunk_size=50,\n",
" chunk_overlap=10,\n",
" length_function=len\n",
")\n",
"new_docs = text_splitter.split_documents(documents=docs)\n",
"doc_strings = [doc.page_content for doc in new_docs]\n",
"\n",
"### BGE Embddings\n",
"\n",
"'''from langchain.embeddings import HuggingFaceBgeEmbeddings\n",
"\n",
"model_name = \"BAAI/bge-base-en-v1.5\"\n",
"model_kwargs = {'device': 'cpu'}\n",
"encode_kwargs = {'normalize_embeddings': True} # set True to compute cosine similarity\n",
"embeddings = HuggingFaceBgeEmbeddings(\n",
" model_name=model_name,\n",
" model_kwargs=model_kwargs,\n",
" encode_kwargs=encode_kwargs,\n",
")\n",
"'''\n",
"\n",
"### Creating Retriever using Vector DB\n",
"\n",
"db = Chroma.from_documents(new_docs, embeddings)\n",
"retriever = db.as_retriever(search_kwargs={\"k\": 4})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mRV0rT9bVRqo"
},
"outputs": [],
"source": [
"template = \"\"\"Answer the question based only on the following context:\n",
"{context}\n",
"\n",
"Question: {question}\n",
"\"\"\"\n",
"prompt = PromptTemplate.from_template(template)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gRn_Zn3fUusE"
},
"outputs": [],
"source": [
"retrieval_chain = (\n",
" RunnableParallel({\"context\": retriever, \"question\": RunnablePassthrough()})\n",
" | prompt\n",
" | llm\n",
" | StrOutputParser()\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xH0TxuFLU06x"
},
"outputs": [],
"source": [
"question =\"what is llama3? can you highlight 3 important points?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 53
},
"id": "lQbsuB43Vc-L",
"outputId": "0a35d312-2949-4368-856c-d89d4e729da3"
},
"outputs": [],
"source": [
"retrieval_chain.invoke(question)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "kHqEw55uVgVd",
"outputId": "37a7e6e7-2c1d-40f0-a352-59b14c01095b"
},
"outputs": [],
"source": [
"import time\n",
"\n",
"start_time = time.time()\n",
"\n",
"result = retrieval_chain.invoke(question)\n",
"\n",
"print('Time taken:',time.time() - start_time)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Tk71kT4ZVnrT",
"outputId": "6d2de3fd-57b3-4a66-9057-5be9fbabc25d"
},
"outputs": [],
"source": [
"start_time = time.time()\n",
"\n",
"result = retrieval_chain.ainvoke(question)\n",
"\n",
"print('Time taken:',time.time() - start_time)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "2bjWjZHKV4WS",
"outputId": "b92165ae-7cd2-4b15-eb39-8fc2d325a30f"
},
"outputs": [],
"source": [
"start_time = time.time()\n",
"\n",
"batch_output = retrieval_chain.batch([\n",
" \"what is llama3?\",\n",
" \"can you highlight 3 main properties?\"\n",
" ])\n",
"\n",
"print('Time taken:',time.time() - start_time)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "YlEAL3OPV55X",
"outputId": "5144a8bc-0a40-484d-d17b-a301c3d1bc0b"
},
"outputs": [],
"source": [
"batch_output"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "A0Odh6PiV7i4",
"outputId": "0d03839c-6f1c-4938-9936-5b0c99ebed2f"
},
"outputs": [],
"source": [
"start_time = time.time()\n",
"\n",
"batch_output = await retrieval_chain.abatch([\n",
" \"what is llama3?\",\n",
" \"can you highlight 3 main properties?\"\n",
" ])\n",
"\n",
"print('Time taken:',time.time() - start_time)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "uye5uA4SV83i"
},
"outputs": [],
"source": [
"batch_output"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "im5Guk7eWDwl",
"outputId": "86fb4bcc-e6cd-493f-dbdf-a0bcc10a449c"
},
"outputs": [],
"source": [
"my_dict = {'Youtube': '@sunnysavita10','Blog': \"sunny's blog\" , 'Website' : 'sunnysavita.com'}\n",
"my_dict"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tZ4vG0XaWFbB"
},
"outputs": [],
"source": [
"from operator import itemgetter\n",
"\n",
"website = itemgetter('Website')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "zEPPAK3yWGiw",
"outputId": "a3cabbb1-66d0-4b0e-b919-9a1006a6c434"
},
"outputs": [],
"source": [
"website(my_dict)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gvKpRIcHYQeh"
},
"outputs": [],
"source": [
"template = \"\"\"Answer the question based only on the following context:\n",
"{context}\n",
"\n",
"Question: {question}\n",
"\n",
"Answer in the following language: {language}\n",
"\"\"\"\n",
"prompt = PromptTemplate.from_template(template)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lhl9vll7WIEY"
},
"outputs": [],
"source": [
"retrieval_chain = (\n",
" RunnableParallel({\"context\": itemgetter('question') | retriever,\n",
" \"question\": itemgetter('question'),\n",
" \"language\": itemgetter('language')\n",
" })\n",
" | prompt\n",
" | llm\n",
" | StrOutputParser()\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "73Rl5KYZWJCh",
"outputId": "596b6ccf-bf12-45f4-c6a6-c628c87a5710"
},
"outputs": [],
"source": [
"### itemgetter only works with dictionaries , input has to be a dict\n",
"\n",
"response = retrieval_chain.invoke({'question': \"what is llama3?\",\n",
" 'language': \"Spnish\"})\n",
"\n",
"print(response)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EDevsLI3WL8w"
},
"outputs": [],
"source": [
"template = 'Hi! I am learning {skill}. Can you suggest me top 5 things to learn?\\n'\n",
"\n",
"prompt = PromptTemplate.from_template(template=template)\n",
"\n",
"chain = prompt | llm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "pJv0bVtUWNCG",
"outputId": "c2679e08-6dcc-43af-e29a-898a93c0cd4e"
},
"outputs": [],
"source": [
"for s in chain.stream({'skill':'Big Data'}):\n",
" print(s.content,end='')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bpmGR1mbWPdp"
},
"outputs": [],
"source": [
"import json\n",
"from langchain_core.messages import ToolMessage\n",
"from langchain_core.tools import tool\n",
"from langchain_core.utils.function_calling import convert_to_openai_tool\n",
"\n",
"@tool\n",
"def multiply(first_number: int, second_number: int):\n",
" \"\"\"Multiplies two numbers together.\"\"\"\n",
" return first_number * second_number\n",
"\n",
"model_with_tools = llm.bind(tools=[convert_to_openai_tool(multiply)])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mMG5ND6rWRDr"
},
"outputs": [],
"source": [
"response = model_with_tools.invoke('What is 35 * 46?')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PijeN4AUWSFN"
},
"outputs": [],
"source": [
"response"
]
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyNeJZ3T3sy685liBqGIgoGw",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: Langchain_memory_classes.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ObdXCxM7c9uG",
"outputId": "0ef24b8f-e978-4b26-81d5-eea1461629f3"
},
"outputs": [],
"source": [
"!pip install langchain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "aKUkmjG7obXp",
"outputId": "5bbcb0d6-1397-45a8-e3c9-a0b1cc35deeb"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hF9ONG-Xpiwy",
"outputId": "13099f6b-f643-46a3-f3fd-bee676630e3c"
},
"outputs": [],
"source": [
"!pip install langchain_google_genai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "sT-M-IbGO_fX"
},
"outputs": [],
"source": [
"import warnings\n",
"warnings.filterwarnings('ignore')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1qH4CJp-puOR"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')\n",
"os.environ[\"GOOGLE_API_KEY\"] = GOOGLE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Y82qy4YTpmGx"
},
"outputs": [],
"source": [
"from langchain_google_genai import ChatGoogleGenerativeAI\n",
"model = ChatGoogleGenerativeAI(model=\"gemini-1.0-pro\",convert_system_message_to_human=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "mUQPzgTMpnVg",
"outputId": "bfb0c6df-6a4c-49fd-fa49-6c8327b20e6a"
},
"outputs": [],
"source": [
"print(model.invoke(\"hi\").content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "AmitzKzGoo6e",
"outputId": "7c8307a1-70f1-450d-e61e-ca7e1be332f6"
},
"outputs": [],
"source": [
"print(model.invoke(\"hi, how are you please tell me?\").content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3zgleD2norLX"
},
"outputs": [],
"source": [
"from langchain.memory import ConversationBufferMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "iK0mnJnho1WH"
},
"outputs": [],
"source": [
"memory = ConversationBufferMemory()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "h2px3_AAo5wX"
},
"outputs": [],
"source": [
"memory.save_context({\"input\": \"Hi\"},\n",
" {\"output\": \"What's up\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "c_nviz7-o-Lg",
"outputId": "e9f3fa5c-f755-4f11-e78f-cd51b4a5774f"
},
"outputs": [],
"source": [
"memory.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qtz58I3fpIRv"
},
"outputs": [],
"source": [
"memory2 = ConversationBufferMemory(return_messages=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kIYkuLPspQx_"
},
"outputs": [],
"source": [
"memory2.save_context({\"input\": \"Hi\"},\n",
" {\"output\": \"What's up\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "BweTLFgYpUVR",
"outputId": "bbca8008-2435-4213-b274-80af5f360b7d"
},
"outputs": [],
"source": [
"memory2.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "MATKudmrQRdl"
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "D8mXubm9pZXp"
},
"outputs": [],
"source": [
"import os"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "22KrSvL-peAo"
},
"outputs": [],
"source": [
"from langchain.chains import ConversationChain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Ie3Onspvp6cP"
},
"outputs": [],
"source": [
"conversation = ConversationChain(llm=model,verbose=True,memory=ConversationBufferMemory())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 263
},
"id": "FtXYKCiQqJSX",
"outputId": "2546e8c6-aa8d-4444-8b58-b1e8789e85e1"
},
"outputs": [],
"source": [
"conversation.predict(input=\"Hi there!\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 385
},
"id": "T84Xm_07qLlQ",
"outputId": "a85b0f33-db4c-467b-c196-2a43aab04f30"
},
"outputs": [],
"source": [
"conversation.predict(input=\"Nothing much! Just tell me how do a conversation with an AI.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 524
},
"id": "0ckLlsGiqdSH",
"outputId": "35d77981-8eb9-40a4-fbbf-7c3bb3b42943"
},
"outputs": [],
"source": [
"conversation.predict(input=\"how many tips are there can you mention in the numbers\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "by5vIxH2CS3Z",
"outputId": "57a704bd-dcb1-44ca-87e7-b47329006f16"
},
"outputs": [],
"source": [
"conversation.memory.chat_memory.messages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 662
},
"id": "rmlGoT6IQsKV",
"outputId": "5f27894a-2875-4864-cab2-6b434bad8152"
},
"outputs": [],
"source": [
"conversation.predict(input=\"can you give me the 3rd tip?\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ayGsHEv9qqNa"
},
"source": [
"# ConversationBufferWindowMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "M5MfA3coql_o"
},
"outputs": [],
"source": [
"from langchain.memory import ConversationBufferWindowMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "WADVyAaIq12p"
},
"outputs": [],
"source": [
"window_memory = ConversationBufferWindowMemory(k=1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "afJtNTWrq9Z_"
},
"outputs": [],
"source": [
"window_memory.save_context(\n",
" {\"input\": \"Hi\"},\n",
" {\"output\": \"What's up\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ymZ7WpfYrR7_"
},
"outputs": [],
"source": [
"window_memory.save_context(\n",
" {\"input\": \"Not much, just hanging\"},\n",
" {\"output\": \"Cool\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "PUmMWst6rZdH",
"outputId": "50b89e06-ec98-494b-bddc-00272b452b22"
},
"outputs": [],
"source": [
"window_memory.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "92JAkps_rcHo"
},
"outputs": [],
"source": [
"window_memory = ConversationBufferWindowMemory( k=2, return_messages=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4I5696VUr4H6"
},
"outputs": [],
"source": [
"window_memory.save_context(\n",
" {\"input\": \"Hi\"},\n",
" {\"output\": \"What's up\"}\n",
")\n",
"window_memory.save_context(\n",
" {\"input\": \"Not much, just hanging\"},\n",
" {\"output\": \"Cool\"}\n",
")\n",
"window_memory.save_context(\n",
" {\"input\": \"ok thanks \"},\n",
" {\"output\": \"great thankyou\"}\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lTz6A1ZUr-3Q",
"outputId": "a21e9c92-a192-46bf-971f-1693bd33ba5f"
},
"outputs": [],
"source": [
"window_memory.load_memory_variables({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gSLZAyaCsBSw"
},
"outputs": [],
"source": [
"conversation_window = ConversationChain(\n",
" llm=model,\n",
" memory=window_memory,\n",
" verbose=True\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 263
},
"id": "c57Fr0kasY3g",
"outputId": "7071ffae-b81c-4e18-d73f-793d65068188"
},
"outputs": [],
"source": [
"conversation_window.predict(input=\"Hi, what's up?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 315
},
"id": "Cb_2zJAgshtv",
"outputId": "60b35011-526d-4dde-8aa1-243df0640938"
},
"outputs": [],
"source": [
"conversation_window.predict(input=\"how we can talk with AI give me 5 points\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 263
},
"id": "cqjuwol7soep",
"outputId": "d3bfead1-8854-4e21-b787-7b4e4ecfff14"
},
"outputs": [],
"source": [
"conversation_window.predict(input=\"what is a allows AI to 'see' and 'interpret' images?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 263
},
"id": "v5bzPXTys_mw",
"outputId": "a0ac905b-2e4f-4851-f425-18238ff600d2"
},
"outputs": [],
"source": [
"conversation_window.predict(input=\"can you tell me how many tips you genearte in the previous to previous message?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 263
},
"id": "Dq4X_PVYtJnx",
"outputId": "23ac5f3c-c779-464a-ad0a-4f0b248c446b"
},
"outputs": [],
"source": [
"conversation.predict(input=\"what was the fifth number tips?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "11Sj-AcdvN-S"
},
"outputs": [],
"source": [
"from langchain.memory import ConversationEntityMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gx7UfR2b55Wy"
},
"outputs": [],
"source": [
"memory = ConversationEntityMemory(llm=model)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "h7H3aQ5t6Esy"
},
"outputs": [],
"source": [
"_input = {\"input\": \"Deven & Sam are working on a hackathon project\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "prEkB6V16IHr",
"outputId": "a5b093a9-b51e-4469-e212-f873dd0650eb"
},
"outputs": [],
"source": [
"memory.load_memory_variables(_input)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "iEJTouF96LH7"
},
"outputs": [],
"source": [
"memory.save_context(\n",
" _input,\n",
" {\"output\": \" That sounds like a great project! What kind of project are they working on?\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "vaefDOzq6mmS",
"outputId": "395b1892-ca17-424a-9af4-c1dc1ca9ca6b"
},
"outputs": [],
"source": [
"memory.load_memory_variables({\"input\": 'who is Sam'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9eHY8f8A7E0K"
},
"outputs": [],
"source": [
"memory = ConversationEntityMemory(llm=model, return_messages=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fKCuHE6K8Dvy",
"outputId": "fb4bd10c-c3ea-4c5e-9406-2a9ceb9e02ec"
},
"outputs": [],
"source": [
"memory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PzBxI_6J8FCc"
},
"outputs": [],
"source": [
"_input = {\"input\": \"Deven & Sam are working on a hackathon project\"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "jZj9GaBH8Hej",
"outputId": "e877af0f-cee9-4304-8a49-bb4a47510480"
},
"outputs": [],
"source": [
"memory.load_memory_variables(_input)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "r0Sa4O9C8Otz"
},
"outputs": [],
"source": [
"memory.save_context(\n",
" _input,\n",
" {\"output\": \" That sounds like a great project! What kind of project are they working on?\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "yLBPaeWU8SUL",
"outputId": "9ac3bf92-ff52-48b1-d3ad-20c0c249a9d6"
},
"outputs": [],
"source": [
"memory.load_memory_variables({\"input\": 'who is Sam'})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "25sJTv-J8cRb"
},
"outputs": [],
"source": [
"from langchain.chains import ConversationChain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tcLlxQe4_MBI"
},
"outputs": [],
"source": [
"from langchain.memory import ConversationEntityMemory"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UybNNJCA_N2X"
},
"outputs": [],
"source": [
"from langchain.memory.prompt import ENTITY_MEMORY_CONVERSATION_TEMPLATE"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "g9-ALiFc_SQ8"
},
"outputs": [],
"source": [
"from pydantic import BaseModel"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7kQLI2Tk_U2C"
},
"outputs": [],
"source": [
"from typing import List, Dict, Any"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "KGqFtiST_Wf6"
},
"outputs": [],
"source": [
"conversation = ConversationChain(\n",
" llm=model,\n",
" verbose=True,\n",
" prompt=ENTITY_MEMORY_CONVERSATION_TEMPLATE,\n",
" memory=ConversationEntityMemory(llm=model)\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 437
},
"id": "I1i6FFEE_u_D",
"outputId": "79197e71-b89e-467f-b0d1-5be7e015bba6"
},
"outputs": [],
"source": [
"conversation.predict(input=\"Deven & Sam are working on a hackathon project\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "QDdJUJjd_4Ol",
"outputId": "1a1c9bd1-e334-45cb-d370-d6bd1d08f948"
},
"outputs": [],
"source": [
"conversation.memory.entity_store.store"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 472
},
"id": "7_3ELrYJAB57",
"outputId": "4c0b9050-b80e-4682-c4d0-063cda7cee79"
},
"outputs": [],
"source": [
"conversation.predict(input=\"They are trying to add more complex memory structures to Langchain\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 524
},
"id": "FAToSArZAGJy",
"outputId": "f458234e-cb17-4706-82d7-db05aee12afe"
},
"outputs": [],
"source": [
"conversation.predict(input=\"They are adding in a key-value store for entities mentioned so far in the conversation.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 576
},
"id": "JMqcPvC3AJEC",
"outputId": "b3991c52-de54-4436-abfe-1b9640203e9c"
},
"outputs": [],
"source": [
"conversation.predict(input=\"What do you know about Deven & Sam?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "dJkuNNOZAKri",
"outputId": "9c448519-a611-49e0-c50e-79ce374ce544"
},
"outputs": [],
"source": [
"from pprint import pprint\n",
"pprint(conversation.memory.entity_store.store)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 541
},
"id": "sI7tSPB7AN8b",
"outputId": "6a7660a5-c92a-4488-a25e-97bfe401086f"
},
"outputs": [],
"source": [
"conversation.predict(input=\"Sam is the founder of a company called Daimon.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6Mqxyr1mAQyk",
"outputId": "9878d6ab-8e25-4092-fe9b-a6c95c6def64"
},
"outputs": [],
"source": [
"from pprint import pprint\n",
"pprint(conversation.memory.entity_store.store)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 541
},
"id": "yKVKMXI_ATYk",
"outputId": "22bbbbd9-92bd-4ac6-e8a3-61d4b3cb2e3a"
},
"outputs": [],
"source": [
"conversation.predict(input=\"What do you know about Sam?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1XfVuH3CAWGj"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyMAIeL7BnRH5Lu0OSgsgW4c",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: MergerRetriever_and_LongContextReorder.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1P1Vj3uQHRDt"
},
"source": [
"# Install the Require Libraries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ei-8sHPAHFNZ",
"outputId": "ad1a16b5-6b62-427d-9793-3d97be6c1e8d"
},
"outputs": [],
"source": [
"!pip install -qU langchain chromadb huggingface_hub sentence-transformers pypdf openai tiktoken"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "I_V67Rx_HhWA",
"outputId": "905e45e6-94bb-4367-ef28-5e3eac611dab"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "TvshtPmCHgBm"
},
"source": [
"# Let's Load the Data Now..."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pNDOZg3VHfP0"
},
"outputs": [],
"source": [
"from langchain.document_loaders import PyPDFLoader"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5igjOcwZpWaZ",
"outputId": "e96c4a19-01f6-45a9-b768-9a53a429b258"
},
"outputs": [],
"source": [
"from google.colab import drive\n",
"drive.mount('/content/drive')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "217952OxHfg3"
},
"outputs": [],
"source": [
"loader_harrypotter = PyPDFLoader(\"/content/harry_potter_book.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "S7lo4198Hu75"
},
"outputs": [],
"source": [
"documnet_harrypotter = loader_harrypotter.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "wPqxvghoH3d9",
"outputId": "84dd1f8f-3173-4698-8467-01168fe82da5"
},
"outputs": [],
"source": [
"print(len(documnet_harrypotter))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "FNPa1j0yHxp6"
},
"outputs": [],
"source": [
"loader_got = PyPDFLoader(\"/content/got_book.pdf\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mxAC2A2TH1KT"
},
"outputs": [],
"source": [
"documnet_got = loader_got.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "qGTJQ0LvH2zh",
"outputId": "05838a5a-97a3-451c-aca9-7406ab605cf6"
},
"outputs": [],
"source": [
"print(len(documnet_got))\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "sfDKpYApH7zI"
},
"source": [
"# Let's create the text splitter for chunking"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_QXMD3tFH7Rj"
},
"outputs": [],
"source": [
"from langchain.text_splitter import RecursiveCharacterTextSplitter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "oenh8PnUID5j"
},
"outputs": [],
"source": [
"text_splitter = RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=100)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "u4ZCHzbTID77"
},
"outputs": [],
"source": [
"text_harrypotter = text_splitter.split_documents(documnet_harrypotter)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GatbtzNFID-n"
},
"outputs": [],
"source": [
"text_got = text_splitter.split_documents(documnet_got)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7Osyfco7IEBN",
"outputId": "9a785ba2-6f96-4685-8782-19e986dad963"
},
"outputs": [],
"source": [
"print(len(text_harrypotter))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5a8-6GJcIEDn",
"outputId": "5cb3f0d6-4c9a-4e87-8e3c-993fd2abac2e"
},
"outputs": [],
"source": [
"print(len(text_got))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "hDE7LsSUI2sW"
},
"source": [
"# Load the Embedding Model to Conver the Data into Vector"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "l6gA2KxKI16r"
},
"outputs": [],
"source": [
"from langchain.embeddings import HuggingFaceEmbeddings, OpenAIEmbeddings,HuggingFaceBgeEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 493,
"referenced_widgets": [
"ee215ef10f494d52a2a091d67e8432a4",
"9203eda301804e49bc56798612de010d",
"634e2835a5b74ffd82dd06b427c9e390",
"1a71ba039828422396259a6af43d7770",
"ce863827bb05437ea08a792a57f8b632",
"82b9f1a1d70241d4b94eecf52c3c3e4d",
"65b087dcd36c421b9add6668437294ea",
"b02cde4d14b0489d82827f30cf4c2d55",
"235284b36cda4f6fb44f935beaa560d6",
"8a3822a45f174c2da380514c870c708d",
"72ca8a796ff0471d8372ed24cd738730",
"09cb3928eb364f27a9e569ce904a3a5d",
"3ddd001a572e4310b618be4a5b7e64a0",
"99196d002c6c412f9aa3dba1f41d8107",
"745598ff4c19424dad01db020dca5cd4",
"6ee4b4edc99349d48fd813f8e7c08300",
"976aa10bbf34432c99af0ad710e5c8d1",
"1dd982f4941643ac8b5af9e8bfd807ed",
"eb075af716d04ba28c8fc99b22470c01",
"f2283ca6d0bf475e845d05cd8dac5fc2",
"79b0267062244c1ab97de13cfb6c5f9c",
"fa62f69e437245a4b329b31635bac286",
"aed492f54811497499af8d7b1bdd8fdf",
"b52248c79cd94ae0b81389cb9904f13f",
"16a23295539d47ac95236203511149b3",
"ca4b92636f7545b29342e416606b032a",
"2fb871db0757401e8a4b5c1925bce886",
"7ad3bd0c61794e4fbcfa46b47673d4a9",
"38b3a10f67e948e7840d282640d4a48f",
"701b0c32429b4898b65ae3b4f7896c0e",
"dd63b4aabc7443efb51e639a01d3178c",
"88a1357ead3e4b9d8819c7f02d6dd3ca",
"b42f5ffaf2f4473f86c52116e3dbbe95",
"941618650f524843a993beb1c5250e39",
"250abf2d322a4a8f8ffa9f8bafdf7bcd",
"ced1eb78339e4f59b24b9a9b29c0ee05",
"11ab517f1b504bad985b5cf264a4896c",
"858f8c7950cc4ab99602b77d50be5f3c",
"486da2d282f24097ae493d36f8c1398d",
"c172c7725fda4650bae40b79c36c9323",
"8054b4f9e8cc4aaaaccc8ee3d6dd887a",
"a9bbbc0223794e7ca52731898b78a324",
"5976ba33a95a42029579c7926738f013",
"fc4bffe2adbc49d4a06b1ff79ae97cdd",
"bc15438df591468980b5f26976c43ac1",
"60be866bde6e465996d4f889be82e175",
"751a1be15a834c3181cf0bea8799d1b0",
"d48461ef1c8443bfb6f44a233aa03835",
"0009dddefd1e461fbb60fe4a18ebadbb",
"aa6677d45cfc415392a16b33b2e31ba2",
"4c59ee8b3f834775a88b550280d3baff",
"a67f84dce54f4a4b9bd83675b511d58e",
"00c87791b53d405cba3480b5b592de69",
"13fde207aea948ac89af602361419507",
"9b7dbbd1e36444bab8dee0d5e88b9ecf",
"65bbee058ce848e99e264f64461d8f39",
"0b2d947cc0d047d89eac291e2121d32d",
"f5c4d45800c5468e96bd032fa5f74daa",
"be5d0a001dd44a86ac24d92d3ef40a8c",
"e408de6aa1a34d8f9883a4495012c88f",
"a8ebdc1ed2214472948152934918f5d6",
"079de9c2d547450584d61bcf18ac301d",
"c24b91c8065a4afd8d8e29175fed098c",
"29e22655d8b34dc88154326a0205e7f7",
"91728a2ad8df46f2abe76caff3f9d407",
"0419d1ca156b473483198463868d5ed2",
"fdd2e6a7ff254ba2ba97e435aeaa81f8",
"f7a6e981d2894acda2121c4cf986b2e5",
"1c0eb4d333684d6fad7937543f1510b6",
"64a4e97335be4b629daadfefeff08e87",
"47c5196120414bfca0cb381e7cd5d6c9",
"7fe3b3db87f24115862d0d55a6078a57",
"31f9ffa2cb0141dfb2ed1ada396e97aa",
"0421b2a711a140b389bb5a815107ae90",
"f2b34554d0f24735bd26e6dcdbc6233c",
"f4b3d56112ce48c8a017dd7ec6a32060",
"e6575ec199e24391a95c28363bf829af",
"6dc18b142b9b4763b5965d3d4bd932f5",
"6b00d5014f7649bfa6fd4ef9ccc9296e",
"8e035d07e1fa4574b840c22803255c71",
"e4d3ffeb165846dc971b8197e6809532",
"f6ca7a61ada64850b1c1a584f31de2b5",
"935f281da6d243bdb94062e8f1f8235e",
"bd7f60bf8cb540779aa5d8e90f15b103",
"6329888f91ba4c99b70034b85fea82df",
"3417e8d3677042ef9bcf339a4f6504f5",
"81c94e39514c46e0971e12bd2546b027",
"dd00885a653b4065a8ee35d872080a7a",
"2435cf6b4c0846f985260ecab6183360",
"a736af1b094b45dd898df15395c01f4e",
"b519805e6ecb4baa8f3ac3ec6605b895",
"5e702939450c429da9ae6bf5c904a50b",
"532f95591d4c4a7fba352d7a12c6a14e",
"34b23a173266471f90e2d48b90d0b561",
"f8a5e73ae59e49c1946c92ed6ff66e58",
"83f0889c098f4ae382896a4d85904a92",
"629f848bc34b4551877a65d497870c14",
"e64bac450126432bb4967544a6558a06",
"cf07782958874e0289d541ca2cc35ad8",
"f0543b4da83d4ebc80f8ac4f8ebbeebd",
"9a6ae2d492da4121b24ae04dbd296adb",
"c215d0e072fa4a19842675a679468f8a",
"9cb1389c8b464869b656514d027ff492",
"6c2136d36fb443daa2304bab38671dea",
"70f920ed918f456cac5c144e02d8c2c5",
"c67cda9e4c834319a657653e810f11de",
"650ddd91753b42f38c56e47bd732f80b",
"16de2e26229746b9958ac7f94af622ba",
"aba829261ba64dac91c60d1e440ab7dd",
"a3cff9e2093c4eef9f3c4e1a86780e1d",
"b9d72371c5034e5a82a086fc428e029e",
"6e9082f5b0904a2799c2fa04012042a7",
"44ebf724093847d682191b5a63079976",
"f1396779ae304306b2ff1d5466de628d",
"a0d7219a039e49dea69be411a53db908",
"a2bb4a4a755143f0bfbc1cbdb21a746a",
"2a5eda846a104efcab2f757c307973b2",
"4f6d3bb604ee4b0e81d0beb0213e25ae",
"254410c2340e4aedbcde9c21a3bfcdee",
"a09bbe200e9d4b10b3610a554e4b50ed",
"80d319999e5044e5b8ff008eb1a4ec4e"
]
},
"id": "aPRKRbjwI2Bq",
"outputId": "800e87d9-63b2-458c-e580-ab39616fb899"
},
"outputs": [],
"source": [
"HF_TOKEN_REMOVEDembeddings = HuggingFaceEmbeddings(model_name=\"sentence-transformers/all-MiniLM-L6-v2\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 369,
"referenced_widgets": [
"b110961aaea94d34b6c4b203eb384268",
"7ce9b8499cdb45a681b272112a75bdd0",
"d46b3db0765049ee9d271d36db7b8215",
"874bd41178b848e4a942fe49378cbc44",
"fa9c04e4c4ba49a99372d431b39efd7e",
"57a3c34da043474e88a52060ad1d8d3e",
"323cac6e4a054800a806d37e4fa42ded",
"1782057e66a148bfaf69e707b1d97b95",
"eb35d1540e454242bf7681e0fa6102ad",
"68ae5014b93b414f817a1e1af7c4ebb2",
"5195218ade4447eeb57ff5b002295e3b",
"340b177019c04a07bfbc86c515bad28b",
"391243030990451998c5fe9c94858f7a",
"f8257cad5c7543cebca9a53b9c7aad3a",
"6bed2a55be174789a16e475aebe96823",
"48ac3aced9734107ae37bdc6034cd386",
"ec1e598132ca4b37b829d84281dfaa10",
"59c8a25854024befbb615fcf601c8fda",
"8f8aeedfd9f249f3857f150327bfd995",
"6301ff8170e74e4abefc5646390bf3d7",
"5e914f10548b4134baea7ea925489858",
"5b081a61f2a44a4ba813a33c90d8f64f",
"5a731c6d6fd74caeba6fd607077d6d79",
"e920047bf38b4114a3bb68d2b593e466",
"ec89b5718ae241e19ad57f2fb047479c",
"fe1a27dbc4d84744bbcdae3f8471cc7e",
"68baa4e1528847f18867908fe97ab9c1",
"958b7cf7601a48a68a6e84827d06fe5b",
"e854acb31c70421d8fcf82f2ff353570",
"aaac7286538043dc9b6d38c575ba384e",
"87d09f693883487986aaeed3e27408fa",
"fb76146383d44f5ca4d862ea8bd6c07f",
"8f469fc9efb74619b4883a652caf2534",
"2919cc2dada04a949b0385c4b8f25d47",
"97e0fc2aa4534b91862b3daecd003ac2",
"fe1abfcb7e0c474eae5182970b2907f8",
"ff3bece7a72c4ad4abc63fccc3107c06",
"2c191068bc514dbdb2e29a35e5be3fd2",
"8f7fefd6cf1144e7a0021ca002ae5841",
"bb95abe18e784ae2a3b0baed5d074338",
"02d3083e54be47c8baaf59500690d79c",
"416026903cba4d7484ecaad84fd15596",
"4d29a785b7ef43b0a78488ef97d8dae8",
"448fd581ef7440b89c190f90855f4dc7",
"376e687ffd7142aab018e642cebfbb29",
"2bc25e13e0cf4f19a03eaec94aa8aca8",
"b67a1568da9b4be69cd446bb5f0f86e2",
"290b3bf804c044c48a5ef7a1eefd6b34",
"99b07143b72d44f0b154fa636d22e6b9",
"7b887e29fc53413a97273f66e7965cc9",
"e09c3f97c51f4f4a94f78fbaba742801",
"67e15d40dc1049ebb7f5267ca0c083aa",
"3188993f7aac4334bdfce7a6ce220ce1",
"8dbdc87297c84b71a839a42fa38bbb10",
"e775f31adaed4138b4a190912f611c20",
"e50e1396221543b180a3bdb382b160be",
"3a269b0861ca4a489c76737313346d93",
"c5d113b2221c45c9816a5c5ebd160440",
"12723b4e390a4fa3b5407d4026865338",
"590c03e7dca143e3978394ec9751bbcd",
"c1aed9556af64400b52fe46e6d0a177e",
"c84e73b21aa845f3b56ed3f01d45c503",
"7a117a71a77649b796fed1c21eaefc32",
"c01ab0f9b98b41b9bc8df5c621cdc8a0",
"c4f20f4e8b1343e6afaf251e21cbe40b",
"d0067035c9dd4d129ccb49c8d072b04f",
"88a47049a35b4f0db2a4a645aff7912e",
"32e9576863334e1a81ac51f120f4c0c6",
"972dac8d179d4db28a31987f40ffbbb8",
"aa334d37f0e7450187e5f6a86ec3e280",
"5d2c8b6bd9a54ecead24035c0d7ecdb0",
"b9b564a71bdd4e67956f90c28517387e",
"c9c18010dfa8493f82eaa03aa3981eaa",
"79f25fc3cf604caa84a20488a53a59d2",
"e59a741bc31d4a4cb000fac096e05626",
"5797212fa9c240ba844f950e6d82690d",
"1f92604e3045478d8c8e890ac0543db9",
"1ad868f457f345768c011063eb1d11f1",
"ea1ec1bab6184d04833baa87138fc454",
"cf3c814e22a3427cb685f0faddbd09bc",
"0c216bf37e364991944893db8845f326",
"63421be79b664d258ac8d01af0beb5dd",
"895c5cf715ff4065b719274b1d7a0583",
"4b8c82655d364014941093e98dc99082",
"66a10af59a2a4dacbcbdaff985c3363a",
"b8dabdddd5464d44adfdbc3a46b94da1",
"c7874624489b46b1849ae676d402efaf",
"785362769ac347c8a42c8123e7a8ba04",
"e6a972da6a1e43c8ac9d3d1ba68be16a",
"290eb6fe365e4ba2a04e6b4730f5d61a",
"ef49946e57d54c099d0eed0c69307192",
"ec1291be69134a47a0de5daf893dce8a",
"a12725c0e174452eb11744c9c76ce5c4",
"b1ff3f63af1649aabc963586f71fe8f4",
"7f8b97f2741d466d8aee5a3640c023a0",
"27686be245d64085a204c84d78b9376f",
"4c8f1b48d2ab4bb48e56a518cbd96941",
"671ec6da65b043a684d1d1879fb647a3",
"298da64f90034ffcaae0d4f4a155a6e9",
"b90fe413a1db4f9eaa1c9e5a45d2e031",
"d87171efcb8e40ac88adf6f020fed5a3",
"be3f00d0d0724af5a493b4592374ce1e",
"3f51122f53c84027ba806c3c43bb0c71",
"e066b582664c49a2aced312c15a340c5",
"3096602f5e2b478b8b904e481e8ca024",
"5198af7a69514d1bac63b4174a3b32b0",
"883f277278754c4f9cdf942ea65503d7",
"274d2d787a3a4571aa4c92b1dc65d260",
"d949f2cd71094ba6914ba2ff06d15404",
"836a1b7fb19245e6820a08d0b1140a7f",
"183a90baf9854fbc9810b0de23dc9276",
"c4448621044b48bab92fbdde9b623c73",
"26cf687795634427973a483aa5d8e191",
"934d837129de4c1f83bc50b1b9b4bb8e",
"06e9b62f18914f45b856bbf217a1766c",
"04670edc37ae47e9985dfe21c85eb8f6",
"f352721c678443e8b0cb2bf050484dec",
"5b7d001f4aee419faf66f808a0e468dc",
"2f333f7b7771484cad70c5b042330ade",
"c0067ebd960d445d9ed8e7681963cc54",
"c39e75ae20524406b75ca8f5d197b54b"
]
},
"id": "xZXAeGj6I2ET",
"outputId": "499ee301-1ab6-4111-d93e-0f91f8eb8aaa"
},
"outputs": [],
"source": [
"HF_TOKEN_REMOVEDbge_embeddings = HuggingFaceBgeEmbeddings(model_name=\"BAAI/bge-large-en\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IFUJsrCHI2Gp"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "oOavSXiA8TzW"
},
"outputs": [],
"source": [
"os.environ[\"OPENAI_API_KEY\"]=OPENAI_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1uf3FGgIJHrX"
},
"outputs": [],
"source": [
"openai_embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "09wnx-HmIrmL"
},
"source": [
"# Now ingest the Data into the Chroma Database"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "R5YZtmTzIEGG"
},
"outputs": [],
"source": [
"from langchain.vectorstores import Chroma\n",
"import chromadb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "j-9W8rfiIRxS",
"outputId": "e0d73af2-207f-404a-f73c-a6bd9439bf5f"
},
"outputs": [],
"source": [
"import os\n",
"os.getcwd()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "WA_V53CYIRzv"
},
"outputs": [],
"source": [
"CURRENT_DIR = os.path.dirname(os.path.abspath(\".\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "S2NElj3nIR2c",
"outputId": "6a7c770d-a7b5-4319-e62a-813f6f0fdc7b"
},
"outputs": [],
"source": [
"CURRENT_DIR"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PlBALwqgIR47"
},
"outputs": [],
"source": [
"DB_DIR = os.path.join(CURRENT_DIR, \"/content/db\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "ICo12gHbadYI",
"outputId": "079173d4-548e-4ac7-dbe2-991f65c50fde"
},
"outputs": [],
"source": [
"DB_DIR"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UwOOnUaNIR7U"
},
"outputs": [],
"source": [
"client_settings = chromadb.config.Settings(\n",
" is_persistent=True,\n",
" persist_directory=DB_DIR,\n",
" anonymized_telemetry=False,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YKS58oWHIgot"
},
"outputs": [],
"source": [
"harrypotter_vectorstore = Chroma.from_documents(text_harrypotter,\n",
" HF_TOKEN_REMOVEDbge_embeddings,\n",
" client_settings=client_settings,\n",
" collection_name=\"harrypotter\",\n",
" collection_metadata={\"hnsw\":\"cosine\"},\n",
" persist_directory=\"/store/harrypotter\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dk0OU3NvIgrN"
},
"outputs": [],
"source": [
"got_vectorstore = Chroma.from_documents(text_got,\n",
" HF_TOKEN_REMOVEDbge_embeddings,\n",
" client_settings=client_settings,\n",
" collection_name=\"got\",\n",
" collection_metadata={\"hnsw\":\"cosine\"},\n",
" persist_directory=\"/store/got\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "WRHJ4hfQJLVj"
},
"source": [
" # Now Crearte a Retriever"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hHQSNWOZIgte"
},
"outputs": [],
"source": [
"retriever_harrypotter = harrypotter_vectorstore.as_retriever(search_type=\"mmr\",search_kwargs={\"k\": 5, \"include_metadata\": True})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "VYCpv9s1Igvb"
},
"outputs": [],
"source": [
"retriever_got = got_vectorstore.as_retriever(search_type=\"mmr\",search_kwargs={\"k\": 5, \"include_metadata\": True})"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nTFvuWt-JTN_"
},
"source": [
"# Let's Merge both Retriever"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Eg0WIDadJdOc"
},
"source": [
"# It is also called lord of retriever(LOTR)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bf9qpiQ0bYc8"
},
"outputs": [],
"source": [
"from langchain.retrievers.merger_retriever import MergerRetriever"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pKVt1XkJJW2N"
},
"outputs": [],
"source": [
"lotr = MergerRetriever(retrievers=[retriever_harrypotter, retriever_got])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ev-OCloIJlAD",
"outputId": "fe5ee8ea-b6a8-4efb-ffa1-1cdaa1e50f76"
},
"outputs": [],
"source": [
"for chunks in lotr.get_relevant_documents(\"Who was the jon snow?\"):\n",
" print(chunks.page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tn4-5rs2JnH1",
"outputId": "cb76d81f-6112-4a47-dceb-89e167235f66"
},
"outputs": [],
"source": [
"for chunks in lotr.get_relevant_documents(\"Who is a harry potter?\"):\n",
" print(chunks.page_content)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "F837e_8WJot6"
},
"source": [
"## See this result is too much messy now lets refine it according to the question and overcome the situation of lost in middle"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "adVBzdP4Kjxe"
},
"source": [
"# Now After understanding step by step it create a pipeline for LLM"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TkgJD6hu9HYt"
},
"outputs": [],
"source": [
"from langchain.document_transformers import (\n",
" EmbeddingsClusteringFilter,\n",
" EmbeddingsRedundantFilter,\n",
")\n",
"from langchain.retrievers.document_compressors import DocumentCompressorPipeline\n",
"from langchain.retrievers import ContextualCompressionRetriever\n",
"from langchain.document_transformers import LongContextReorder"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "uiOCgKcWKqNt"
},
"outputs": [],
"source": [
"from re import search\n",
"filter = EmbeddingsRedundantFilter(embeddings=HF_TOKEN_REMOVEDbge_embeddings)\n",
"reordering = LongContextReorder()\n",
"pipeline = DocumentCompressorPipeline(transformers=[filter, reordering])\n",
"compression_retriever_reordered = ContextualCompressionRetriever(\n",
" base_compressor=pipeline, base_retriever=lotr,search_kwargs={\"k\": 3, \"include_metadata\": True}\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 53
},
"id": "E47YiiT6K2-k",
"outputId": "13a2b4e2-9e74-4561-8c1e-b37b047430d8"
},
"outputs": [],
"source": [
"\"\"\"docs = compression_retriever_reordered.get_relevant_documents(\"What is esops?\")\n",
"print(len(docs))\n",
"#\n",
"print(docs[0].page_content)\"\"\""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2M-BOy9mK7to"
},
"source": [
"# Load the model from huggingface"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "9z4Jur-dK5up",
"outputId": "362c7db4-3d8a-4f30-dcaa-08b512916503"
},
"outputs": [],
"source": [
"!pip install llama-cpp-python"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hNiO_irtLDpO",
"outputId": "99c869f4-d1eb-4b70-b74c-dcfb59d25f66"
},
"outputs": [],
"source": [
"from langchain.llms import LlamaCpp\n",
"llms = LlamaCpp(streaming=True,\n",
" model_path=\"/content/drive/MyDrive/zephyr-7b-beta.Q4_K_M.gguf\",\n",
" max_tokens = 1500,\n",
" temperature=0.75,\n",
" top_p=1,\n",
" gpu_layers=0,\n",
" stream=True,\n",
" verbose=True,n_threads = int(os.cpu_count()/2),\n",
" n_ctx=4096)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cQU3kYJ8LIPQ"
},
"outputs": [],
"source": [
"from langchain.chains import RetrievalQA"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qUbRD-MMLJnJ"
},
"outputs": [],
"source": [
"qa = RetrievalQA.from_chain_type(\n",
" llm=llms,\n",
" chain_type=\"stuff\",\n",
" retriever = compression_retriever_reordered,\n",
" return_source_documents = True\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "BVJoUUX7LLRV",
"outputId": "5ea7b55b-f02b-4b87-f166-f2145ff5695e"
},
"outputs": [],
"source": [
"query =\"who is jon snow?\"\n",
"results = qa(query)\n",
"print(results['result'])\n",
"#\n",
"print(results[\"source_documents\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NAaRNaAJ_lMB"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "vd4_hOZr_roP"
},
"source": [
"\n",
" Jon Snow is a character in George R.R. Martin's \"A Song of Ice and Fire\" series, which has been adapted into the popular HBO show \"Game of Thrones.\" In the context provided, he is described as Bran Stark's bastard brother and is mentioned as moving closer to Bran during a scene in which Bran witnesses his father, King Robert Baratheon, sentencing Ned Stark to death for treason. Jon Snow has been portrayed by actor Kit Harington on the TV show \"Game of Thrones.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Q-TSWYdRLNJA",
"outputId": "2fedc131-8a24-4222-ea02-64542e9bd41b"
},
"outputs": [],
"source": [
"results = qa(\"who is a harry potter?\")\n",
"print(results['result'])\n",
"#\n",
"print(results[\"source_documents\"])\n",
"#\n",
"for source in results[\"source_documents\"]:\n",
" print(source.metadata)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VMUTfRBG_0jN"
},
"source": [
"Harry Potter is the main character in J.K. Rowling's series of novels and films about magic and wizards. He is an orphan who discovers that he has magical powers and goes to attend Hogwarts School of Witchcraft and Wizardry, where he makes friends and battles evil forces like Lord Voldemort."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "P6OGT_GVLNvu",
"outputId": "13089a0f-0be5-4fec-c775-28bfda33dd95"
},
"outputs": [],
"source": [
"results = qa.invoke(\"How does Jon Snow's relationship with the Stark family influence his identity and decisions throughout A Game of Thrones?\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tmPpxH4lx7Tl",
"outputId": "22ae373d-d76d-41ad-fb63-8821de8ac6ea"
},
"outputs": [],
"source": [
"results"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "EJLoZ_50x6W6",
"outputId": "e23e8c42-7d27-4b06-feaa-ba778d8ce590"
},
"outputs": [],
"source": [
"print(results['result'])\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Vb3ZR3uXx-Fo",
"outputId": "9d4fc9c5-bdbd-45ba-b91e-5d8c529e2d22"
},
"outputs": [],
"source": [
"print(results[\"source_documents\"])\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "touA05JPx_EF",
"outputId": "f036f586-32db-4657-b0d0-070270b773dc"
},
"outputs": [],
"source": [
"for source in results[\"source_documents\"]:\n",
" print(source.metadata)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "U0h0uPaJ2Lic"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: MongoDB with Pinecone/Mongodb_with_Pinecone_Realtime_RAG_Pipeline_yt.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "sqR0IDn39a4C",
"outputId": "5bc9c606-7511-4be8-ca51-65c954d295cf"
},
"outputs": [],
"source": [
"!pip install pinecone-client"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "mNC5WFYMFmuH",
"outputId": "20353f96-9f89-497b-9cda-361559bb9ed4"
},
"outputs": [],
"source": [
"!pip install pymongo"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "YiUQebngFox5",
"outputId": "a6dd7e96-2167-4a45-b100-d9cd7476bfec"
},
"outputs": [],
"source": [
"!pip install transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "t7H-h8ffFxhN",
"outputId": "40405050-b7c5-4d94-e7c5-edcbe9384547"
},
"outputs": [],
"source": [
"\n",
"from pymongo.mongo_client import MongoClient\n",
"\n",
"uri = \"mongodb+srv://snshrivas:Snshrivas@cluster0.u141hkk.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0\"\n",
"\n",
"# Create a new client and connect to the server\n",
"client = MongoClient(uri)\n",
"\n",
"# Send a ping to confirm a successful connection\n",
"try:\n",
" client.admin.command('ping')\n",
" print(\"Pinged your deployment. You successfully connected to MongoDB!\")\n",
"except Exception as e:\n",
" print(e)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ZscjjyNlGRws"
},
"outputs": [],
"source": [
"PINECONE_API_KEY=\"your_api_key_here\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "11FSLgusGlBn"
},
"outputs": [],
"source": [
"from pinecone import Pinecone\n",
"\n",
"pc = Pinecone(api_key=PINECONE_API_KEY)\n",
"index = pc.Index(\"mongo\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5PBXYNP4G9NP",
"outputId": "b6995080-2112-4c33-efcb-2f2ae7af0cb4"
},
"outputs": [],
"source": [
"index"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RvocDAXmG-pl"
},
"outputs": [],
"source": [
"db=client[\"mytestdb\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8SnrOSLjHD3v"
},
"outputs": [],
"source": [
"collection=db[\"mytestcollection\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4-ceaak6HdoP",
"outputId": "0130d75e-ac54-42f1-bd7a-577508065c7b"
},
"outputs": [],
"source": [
"!pip install sentence_transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qBLYxnQZHZWL"
},
"outputs": [],
"source": [
"from sentence_transformers import SentenceTransformer, util"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 493,
"referenced_widgets": [
"69c37c291cbd4dd8bbe47d1cabc8c01b",
"3ce1e947546445f592abc405ad18db21",
"206a70fd981d456d8654fa2c3aef9b0d",
"914aaa86a5fc46e6a7a57e5423162c8b",
"599e1a29c1ca4efb859c914d0940fd3a",
"95574f96abba4db69a3f07f862ce0a47",
"1d0cd2dcf5fa4ece9ac5690e27c12e7f",
"a0db63d5ec3141eebee8cc2a89aacc14",
"d9d7d84d51174bdaa1438fb33da82868",
"d01ff037d45e4328aaec5ab3fa7a2422",
"375ada49ae514f499633f2d5a86535b5",
"22c5049602004b67a57589cd3bac1c3f",
"8eb9241f12b04ed8be73d11b9d07643d",
"ef9e2f14e34840e2986ea0610a1173f7",
"c881718e5c1d486699d1570d82a39e49",
"2bf190efa2654b84b5c929819be83ed3",
"01ef07c504a94bbfaa7ee285a1fcdde0",
"bf4bafa3b721495e927b6ddf172e5ab8",
"fd1a2b9f69a84b3a8902e2d75e7112be",
"9cfc96fb098d4c7bbf425e44262997ef",
"024643cb2f90435496893dc2efd4577c",
"1366700a7d064b1aaa85e90920b262f5",
"a38f2880d6dc48bab0a760480fe7cfb0",
"ada2598141234c0aa5147c47da602b0b",
"3e7e1e5bcdc243f3a5325115c054ad00",
"66aeeec68e4d4c87a2ae45b105616570",
"b9979469479a4400bac37e469787942b",
"580b038445c6479592fa94b0f511b874",
"9d17ceec5d7f422a845855ae7ac4a9f5",
"3bd97e602df94c8399001d830ca6c9f7",
"fb930f715ed643b08d94339a53ad214c",
"a60ad74805a347dfaf2202de695e7e41",
"639c1f3bc2a94553a255c27e282c9540",
"ff6426509bbc4bb0851ec33fc4485935",
"097b48587e82493098c3b74084ccb3fd",
"704c41345ac4458b866c470c079c9d98",
"af0c9c33cf594478a3883c9f5339ce80",
"ece08e4cb7c247a2aa17be6dbceacc7d",
"1ce5c0ce243d419498f69808521167be",
"79991d32fc9b4c99a31d1828f06136f2",
"6ccbcb0a415e4b5dbfc110f4e68037d3",
"47ca97c2e6ab4ea2a99d8da5fcc5ae28",
"97df3286cac84d3299e89a4fd97036ee",
"13e98a62b7454720a4078aa1923847e5",
"a0b0a60e94c341fbad866d69fa093d27",
"fe18cdd9639b4993aff226935ee6d999",
"15a3837ee60047949ebd3abd33fab5f2",
"38df1bc0ba5e4efebf247c8fb466f9d6",
"d68a881f4fa8449cab4ef90c47ce39ba",
"406a0f56a3204b32a85ede479847ec5f",
"b74554de594d45d0bd3f3214ee86670a",
"7c66e1a92b78409f905a1bec960b81eb",
"6f257f936e6a4f898fce5759ce3c89cf",
"bc5ab709916049be8020d43012665a16",
"a91f2281ca1d4c80ac2f65e8cba0f7b7",
"9d73ba75ef214bdea7fbe1a6873e6912",
"42a9be2094154b9893852cc26828804e",
"b76d5eb3156e4a8fb3251e1d58bafd47",
"a5c4376fdca747d28ef95824f371c9cd",
"b557625a707a4226b91ffa2bf247efd0",
"0d6e15314c924bdbbef2530cc86458ad",
"9193263cf8b946a3a4d940a60e208a3b",
"ca40f350179e49409d346febf74047c8",
"7d0c62b2046f4276af80ceef9b693c96",
"56ddc5bd3e544b30a741834664803cb4",
"5a21dc8149ed439d81daf629dd1babde",
"b9f0c3f88954429cb21e7753ddef4186",
"aa54392f0c314d8283df6094d3c03091",
"acea9e14aa054a4c93e3f0a64598f1ea",
"9f5aac5f4fb24bb0aab2f73c81ea17d9",
"b6d43544cdd44d47bc2174a849125d74",
"f5629763e82a4ddd9b92ba46e71059af",
"cad105eec19647e586d714154a3e4edb",
"a4f6d80fbf0a4aed93c7447e1f110783",
"eb28384b6b6843a0a633dd7485b9703f",
"5b674f158dd34ef8a0699afb04f278da",
"3bff4db71c604577b760fab6cf1ebf35",
"cc100c5224b2479483e4b0004e38c473",
"6282491fcebc405fb16cd4c239cd4dc4",
"5f721992a8c04b86babb97d012b6b879",
"404b775858e34717a46b272e9a323d9f",
"baf74023b48f4aa29d75a3b4472fb057",
"971b5b8879514fc18465f90d0d8a33ad",
"a42e7064d6ba412b88acb6b601e5e028",
"fd073e5374124b69b857ded6c6b9dc52",
"38eb5c73dcfa4fc5a7420d90fe974fe3",
"d0a6fd0d58854b4a96b49bac6b35cf01",
"9c94d44e68e54f77b058d3cdd11e4779",
"39036980c9de426b9d8307c59c9af675",
"1e64e5999cc64df0b2b9f1a55cfc1379",
"eb03d76d268e4b558701ee1d53e4469d",
"0b167fe1412c47118191ca423191631c",
"11525567a7604fde9c55432d44a10cdc",
"27c53224fde141228de1b1a0e88185ef",
"003744665d6d443aa3cbc772cef892d1",
"a55e2e3397114174a71f403ee76faa94",
"173d11cf1dac4d218b20aa1653cb4fbc",
"6c338590c2e1400495f9c4936515ec8f",
"276a1342eb39482db554c1bd1aceb99d",
"285903fde1ff4861ac539d5fb86a3874",
"95d054ac3f3f4fbdb86ea4c8fc803881",
"348b620d883f4a5cb40c2fa730e312a4",
"dbe23d3eee6448cd90a7435e793170c2",
"63281031198849478923a4b0ade89621",
"cb658eb8416a4c8a94587e33ec83587e",
"85687202fcc94b5786dcc296d327a325",
"b119459355d14534b8c8cc6cf51c1ebd",
"0a4a53a771c9421797002c0d7bbd147c",
"44f139fdf7cf4e2cbfeb4c243dd8eb7e",
"39fe53c702764c46bdebc19246cda479",
"cab7e0c2f0404c91b444641cd481b29f",
"7f4a4e067f3c412d87f3614e56818620",
"6b449e29476c45bea1276ad18fccf619",
"395fcc1f86b24ebfa8606d8a00fd8934",
"5e0f721a4d854a468eafee6682aa26b2",
"8336c171ac944bc4927af15dcddd08bd",
"d0fba6ab2f0f4ec8a4469a9122c387f4",
"c9aef3f6dde04123831e8045d3c34ee8",
"51efe16022be430687115db2fa4d8c00",
"caf24c6c00474caeafafeb397c7e3ae8",
"a9c59feafd25476c9b0714e6078b87b9"
]
},
"id": "G9IrXWkLHQZs",
"outputId": "c01bff0a-c200-4f00-f295-79dd41bc4db5"
},
"outputs": [],
"source": [
"embedding_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"background_save": true,
"base_uri": "https://localhost:8080/"
},
"id": "w_B97dyTHH5d",
"outputId": "7cf17015-0cbb-47e3-f0d2-f15d9fd64d8f"
},
"outputs": [],
"source": [
"# open up change stream cursor\n",
"cursor = collection.watch(full_document='updateLookup')\n",
"print(\"Change stream is now open.\")\n",
"while True:\n",
" change = next(cursor)\n",
" # If a new document is inserted into the collection, replicate its vector in Pinecone\n",
" if change['operationType'] == 'insert':\n",
" document = change['fullDocument']\n",
" # convert the document's name into an embedding\n",
" vector = embedding_model.encode(document['fullplot'])\n",
" # Ensure the vector is a flat list of floats (and possibly convert to float64)\n",
" vector = vector.tolist() # Convert from numpy array to list\n",
" vector = [float(x) for x in vector] # Convert elements to float (usually float64)\n",
" # Prepare the data for Pinecone upsert, which requires a tuple of (id, vector)\n",
" # Assuming 'document['_id']' is the unique ID for the upsert operation\n",
" upsert_data = (str(document['_id']), vector)\n",
" # Insert into Pinecone\n",
" index.upsert([upsert_data]) # Note that upsert_data is enclosed in a list\n",
"\n",
" elif change['operationType'] == 'update':\n",
" document = change['fullDocument']\n",
" document_id = document['_id']\n",
" updated_fields = change['updateDescription']['updatedFields']\n",
"\n",
" # if the change is in the name field, generate the embedding and insert\n",
" if updated_fields.get('fullplot'):\n",
" vector = embedding_model.encode(updated_fields['fullplot'])\n",
" upsert_data = (str(document_id), vector)\n",
" # Insert into Pinecone\n",
" index.upsert([upsert_data]) # Note that upsert_data is enclosed in a list\n",
"\n",
" #pinecone.upsert(index_name=\"myindex\", data=vector, ids=[str(document_id)])\n",
"\n",
" # If a document is deleted from the collection, remove its vector from Pinecone\n",
" elif change['operationType'] == 'delete':\n",
" index.delete(ids=[str(change['documentKey']['_id'])])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Exoi5mYKIqNC"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: MongoDB with Pinecone/Mongodb_with_Pinecone_Realtime_RAG_Pipeline_yt_Part2.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Agcs9cqVRzlx",
"outputId": "5b6bb263-6dfc-408e-808f-b56090d32263"
},
"outputs": [],
"source": [
"!pip install datasets"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "jmHr7IcRu1bg",
"outputId": "30380457-63b3-4909-95f9-211b91eff8fc"
},
"outputs": [],
"source": [
"!pip install pandas"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hywVUlFRu5Jw"
},
"outputs": [],
"source": [
"from datasets import load_dataset"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 113,
"referenced_widgets": [
"1029b02ea1974b3fbf6ae5fd4b672e60",
"c13b0e0a35994c50a4591ec48bbe9ec8",
"107eadc4300c44a7889f09672eca02fe",
"bc33b05ed006436d8aafa97a0c51abde",
"f2d76e677e004baa8a806e8a2b91a01c",
"c3fbfd22a5fb4d47a7c5e75dde2289f6",
"f962fe8da6d74af3a24334f3f3024c8a",
"86c68952a8934fd3a0c2d9e223ef4f77",
"e4e9cfe75b614823b6ee7aa5c3fa2d77",
"7b4249a9e72d4780867cf742417339f3",
"c774b74fe854463f89e54cbd3d73e7e9",
"25bd324303d14d0aa32494b014958e8e",
"295a7246575c455ca4ac15f6c331b676",
"7268522b6cce4bbbb991cb64742f08c2",
"d3567008d2da4c86a992c80c00eb8737",
"4f67676d6d86488cbaffd6254c3fe5db",
"1eb727fe9d5a4bd89b14c5f35a549f10",
"688788bbfa1f48d6829d2c60121379aa",
"de7f75132a8a4a458807209f8eec458d",
"6048948e3c044c94b7490cfd250f2ffd",
"c8f4ba3150e648518f2ae1706721c505",
"434997a3c6524cc1859c86e354dbb7ec",
"b781dfe891cc4676b0827a0e1d86fc9e",
"72306a6b64ef4a4e9b3a190cb9bbf971",
"84cc9e635d4046c0a0e3904f35d001fc",
"1b9a661e3fa446aa8be565552a853295",
"8b6dc26221144b24950c1da666d058eb",
"5da7b973ca35496da771a8c84971c9eb",
"7b83376fe1804ff9bd999b6ea579706a",
"d89b4f6b5b994ea5a157edecd85b7f3b",
"78e621d0575b4652ad550103796a9003",
"bc2e1d0bff6540b2a61768fbfe79cf59",
"a29102b7ed40424db2b00bcdbcc6bdb3"
]
},
"id": "Zyd2Vp8uu9Yv",
"outputId": "b0c4e38c-316c-4ac8-fa48-848b55d8c29d"
},
"outputs": [],
"source": [
"dataset=load_dataset(\"MongoDB/embedded_movies\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "uCQVhPi26MBr",
"outputId": "b3d13efe-51e6-4fde-871a-1c4f6e6f8d4c"
},
"outputs": [],
"source": [
"dataset"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "m92LGvLuvGsX"
},
"outputs": [],
"source": [
"import pandas as pd\n",
"data=pd.DataFrame(dataset[\"train\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "3MhwK2v4vDWv",
"outputId": "b18b4664-8768-40a2-8a96-40e58cfb2ab8"
},
"outputs": [],
"source": [
"data.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 746
},
"id": "tI_doa-L6PS6",
"outputId": "2e15b25b-8897-459d-fdde-3198d9ce48a3"
},
"outputs": [],
"source": [
"data.head()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lHGcmKGPvKhp"
},
"outputs": [],
"source": [
"data=data.sample(80)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Oby5bgI6vO5Q",
"outputId": "02aac810-8cf7-41c2-efdb-f0deb054effa"
},
"outputs": [],
"source": [
"data.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "R27ulcmfvP9w",
"outputId": "541ef14c-44fa-4a43-d8d3-b9138518ff17"
},
"outputs": [],
"source": [
"data.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Hthvn8BevSGQ",
"outputId": "67f1356e-c68b-4e9e-e87d-c102c92ecf02"
},
"outputs": [],
"source": [
"data.isnull().sum()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nqv7fLFsvXZv"
},
"outputs": [],
"source": [
"data=data.dropna(subset=[\"fullplot\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ssTczw8Xvccg"
},
"outputs": [],
"source": [
"data=data.drop(columns=[\"plot_embedding\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ujGYzQNDvfwa",
"outputId": "43700158-b703-46b8-e5f5-0a9d580d9404"
},
"outputs": [],
"source": [
"data.isnull().sum()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "n08Io4ytvipn",
"outputId": "fb229fc2-3524-444d-abd9-8fb336917e12"
},
"outputs": [],
"source": [
"!pip install sentence_transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 392,
"referenced_widgets": [
"c82b8a2349344c249a986dcc16927495",
"6eb99d299ae14a8fb14ccb3cd38d6bf9",
"98a18f3c217642caac971bc91cfa7c3f",
"2f1be0c2d06648bab350b8503c41d459",
"d76a6a94dcbf42648361ddf423d7f969",
"b1395879808b4142be236259e1c516e0",
"3a281b8d0f41493db24974880c4a7c6c",
"dacc696753d9475d886187f05e40ee7a",
"9191ea078c3746dba4bb3f4900285bb8",
"18176f258c004d7a98a25930a5b057cc",
"7b32eedf72004288a702e58ee4a2408c",
"36effe5381924399af196a6f24fd98e8",
"ff28f9fa73224896983586a960e11fd4",
"e00d2c61d5844d48802b16f02786723e",
"7f2df9a4be9a45fa96eb3c08df38f3e1",
"47dfcc76978f497fbb8f77449eba41f4",
"313d6c00af044940b2e1d8245fbf1837",
"8f7bd91baea24e66afe51a1380085c91",
"24e00d4b6656436abdebeb694ccd8980",
"8de3cdd3e7ac4ce4825f2d5754acaecd",
"1d0ab759a2404b8b88db0fe0d752b0ca",
"5595e14cbc8746caaaf08ced876455a5",
"a0e4ef164a394d2e990ebd1cb81ee41c",
"9459985f94e541dbafd69fa36fa5023f",
"3a3ad499ffc14f70929ffe79bb1eb7c0",
"c98f5dae052c46e0b38f2c4839268fc5",
"1166c0982782442ab5bfb36a117d324d",
"7f5914088bff434b9c1134ba21a7c961",
"fe1ca2c1e7ca4ba1953e14bef21a34af",
"9fb5fd20dbcb4e2bb8b41a1c021cebd1",
"e03556fd85e04833981746ea0c1a68bb",
"2654a7026b0d4df4a63638c1ce1eab71",
"8ed98dbfc5f449f1a4dc1753e4dc232a",
"989ff4be9d8e4026bcffa4e13bd95088",
"15db6632bf294345acda1b9c4879c6a5",
"2afffa82d42a4b90b76935a0b1683ca5",
"657ca126c115418e85de0c8f19c4adcb",
"d2a936181416420389f6678c4534fb72",
"b0a4942167b74246a37910154809f9e2",
"14c4e67e040e4e2dbb8f0b968670a481",
"51a4ebef5d37444ab9351cf55272b1ea",
"5cc49be8b7af4c8d853074f0d0bb7873",
"9bb202e839634afe87f5ce96d7a5118d",
"023bd7eea0164255aad63774e688f5c7",
"bf2a331d5b384543bc248167afe08300",
"bd8c7ceb1e0a4bbc8582b22d9442c9b2",
"85c7ed73dc544ca38f8e71a5f38bf0a1",
"39621c73b3cd430a81ba8dc5d46c8f9a",
"d2f67f6c5d5e427b8327f4f75c0f32c7",
"2f64d610e4cb494aa12b459b9e60f637",
"b0aa660e14714c95bcf9fd619a75e442",
"b51755c4988046d4b74ed4041cde2af6",
"e7ad44bffe0049d589a44ae4d043fc08",
"d3df39ef598b4e7689f2cd5470fbcfc8",
"5c4878eb5178492f93158b0aeff1415d",
"57f48528f7ab479a933a53b1eabd9793",
"e1f26d4b639345fa91078fc6915478a8",
"8bc6f8ff00f941558623c1e73111e9f4",
"09741a07a2d143a5a6e3104f6806f7b2",
"f095f95c046b45cbbc1f270b5638896f",
"550239efa14b4150869ccd7fa6fafa79",
"f8de658756b6435cbab5da7a08246e4b",
"c35ba91f4da541c0b952c5ad7a15b2b5",
"e9aef987924b4c5d9981ba53daebcc25",
"7baaf7fcfc404271b3dd21079f6c5e14",
"76314a63041e4fc0aec7c20b9c1c876c",
"0d5e34d133234fefbf36c9b1e532f11c",
"fbef9146d0eb4cdeb6d1ed1e970e32ac",
"b3f6a640374a45899cd7e65754c1b433",
"429e3964ab3143c4a651cee20d6b1dea",
"d5f9f7b3b372493aa241dee207ff5b37",
"70286cceefc04519ada7b063ae33c90d",
"aab96e47d0f54292be0204564ab6da13",
"bf40d9868e824e4188fc3185a8d2a6c2",
"facf4c49b7a744f4ba4d327e5b633381",
"51dcb1403d0f4dd0aa70838a7088aca4",
"a3ea452bb9dd4cf09d24682730230fc2",
"adb01ed209ff44c59394971bd6a16970",
"85ba60f7954b46b6bdb77138f8181c62",
"605f1c241c5c4f50bed9b57fdf040a91",
"2ebf049412ff42778edbfc98583d258c",
"906b2f45d1524449807c15dd1ce822e5",
"f0ffd82f413f4cd1a3c6e39d4f0c6543",
"84aa43b0396f485f80e7a2a8aef0a617",
"760a9421144b4f4b952f893ba57deeac",
"a3f16e0d255b41bcb4c73a59518bbdfe",
"b46b4a4a6ce74641995d722292cf446b",
"f24598749bf440738aa790b60845ba16",
"75f0a82140d2408b8cfc968e65376568",
"5be225e39c624163bdfc5e010d93026c",
"dd38b9e01bd94ce19294398200652271",
"bead11d2b0064cec8f9c8731b2316589",
"04ec6699d63a453cb7a124cc57e90d54",
"2b1c0e48ea7149e0aef6b4d498ed6e8d",
"ee1b06c5bd7048fb9e39c3c304ee2169",
"8605aa79cbc14a83a4c44a5a577de9c7",
"7ed3aa5d8f4547de978ef82a61210eb0",
"d743f231885b4564a25bd18082c31390",
"62314dddce2544bcb1437f40070c76b0",
"fa3b9a6f0d7143afa84ba909e024fadc",
"69acbc57fe4b4c3094c4558b2fc5fa28",
"a4f0602f2bc24b9887b3eede789752ea",
"5319df1153dd45cda829eedd5696c849",
"c66a18a94e524124a100cdef36427cdb",
"0908e1c914574250b5f91ea1adb08a29",
"a3c2bbfd68bd4ab898d00ccb034b9b99",
"394ef0bb5d5943b49e76de517f5db51a",
"140aa3439ea44396a7514c977985f86c",
"cb34ee935b064fa0ae3302c5a240c974",
"83c32fe5831e49aca35b5af6eb409046"
]
},
"id": "jmFFbkg-vxyw",
"outputId": "ab5aae5c-bb5b-44bb-c4fe-6a265dc54247"
},
"outputs": [],
"source": [
"from sentence_transformers import SentenceTransformer\n",
"embedding_model = SentenceTransformer(\"thenlper/gte-large\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "WORA6ITDwg8z",
"outputId": "cf0cbc6f-e952-44dc-c9ef-0a9c1ff152ae"
},
"outputs": [],
"source": [
"!pip install pymongo"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "kaivsjLSwSrs",
"outputId": "87efceda-b1b6-4ddc-ea3c-6a032a150093"
},
"outputs": [],
"source": [
"from pymongo.mongo_client import MongoClient\n",
"\n",
"uri = \"mongodb+srv://snshrivas:Snshrivas@cluster0.u141hkk.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0\"\n",
"\n",
"# Create a new client and connect to the server\n",
"client = MongoClient(uri)\n",
"\n",
"# Send a ping to confirm a successful connection\n",
"try:\n",
" client.admin.command('ping')\n",
" print(\"Pinged your deployment. You successfully connected to MongoDB!\")\n",
"except Exception as e:\n",
" print(e)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2VnSfFW-wetw"
},
"outputs": [],
"source": [
"db=client[\"moviemydb\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "y2eJXzmQwqfA"
},
"outputs": [],
"source": [
"collection=db[\"moviemycollection\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "jxSE-sQ4wvlQ"
},
"outputs": [],
"source": [
"document=data.to_dict(\"records\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "odoVfsVow4Q_",
"outputId": "7dcc4747-6f18-48a4-a087-2f2bfb6341dd"
},
"outputs": [],
"source": [
"collection.insert_many(document)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7Mq2fx_Ow-gQ",
"outputId": "135f336b-1727-4133-faab-10e5a8cc51c3"
},
"outputs": [],
"source": [
"!pip install pinecone-client"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "B_4B1quOxVU_"
},
"outputs": [],
"source": [
"from pinecone import Pinecone\n",
"PINECONE_API_KEY=\"\"\n",
"pc = Pinecone(api_key=PINECONE_API_KEY)\n",
"index = pc.Index(\"mongomovie\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "t2p6gqSWxcnP"
},
"outputs": [],
"source": [
"def get_result(query,similar_result=3):\n",
" embedding=embedding_model.encode(query)\n",
" embedding=embedding.tolist()\n",
"\n",
" result=index.query(\n",
" vector=embedding,\n",
" top_k=similar_result,\n",
" )\n",
" return result"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lBTDaPtrxj2P"
},
"outputs": [],
"source": [
"query=\"what is the best horror movie to watch and why?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tK8JoCw-xp93"
},
"outputs": [],
"source": [
"result=get_result(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "bcoKC0TryXkf",
"outputId": "219720f3-f1c4-4d36-b959-b9eaae30a5e2"
},
"outputs": [],
"source": [
"result"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5V2O5aApyCmq"
},
"outputs": [],
"source": [
"from bson.objectid import ObjectId"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "g2FJgqVGx1ST"
},
"outputs": [],
"source": [
"mylist=[]\n",
"for i in range(len(result[\"matches\"])):\n",
" value=result[\"matches\"][i]['id']\n",
" mylist.append(collection.find_one({\"_id\": ObjectId(value)}))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "v61CvjPty6-l",
"outputId": "0cf1dbbb-bb71-452b-8624-fc4fbd0ad424"
},
"outputs": [],
"source": [
"mylist"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GHqr8BXIx-uC"
},
"outputs": [],
"source": [
"combined_information = \"\"\n",
"for i in range(len(mylist)):\n",
" fullplot=mylist[i][\"fullplot\"]\n",
" title=mylist[i][\"title\"]\n",
" combined_information += f\"Title:{title}, fullplot: {fullplot}\\n\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XGWVmhWgzJzh",
"outputId": "9ac851e8-bd9c-4d07-c659-5a152f296e7c"
},
"outputs": [],
"source": [
"print(combined_information)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "94Ms5rAq8ysn",
"outputId": "058878d3-8636-40db-e022-0fd0ae086750"
},
"outputs": [],
"source": [
"query"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Z5b06yDLzFgw"
},
"outputs": [],
"source": [
"prompt = f\"Query: {query}\\nContinue to answer the query by using the fullplot only:\\n{combined_information}.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RYHYR7fFztvD",
"outputId": "6e3fa0aa-1a27-4e6c-ae08-be13473c06b3"
},
"outputs": [],
"source": [
"print(prompt)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XqJxF7Z-zP5X",
"outputId": "0adbaff1-8704-433a-c298-15a46bf1f6db"
},
"outputs": [],
"source": [
"%pip install --upgrade langchain-google-genai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "wth_GgHHzTO4"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')\n",
"os.environ[\"GOOGLE_API_KEY\"] = GOOGLE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GwiF03ixzayg"
},
"outputs": [],
"source": [
"from langchain_google_genai import ChatGoogleGenerativeAI\n",
"def load_model(model_name):\n",
" if model_name==\"gemini-pro\":\n",
" llm = ChatGoogleGenerativeAI(model=\"gemini-pro\")\n",
" else:\n",
" llm=ChatGoogleGenerativeAI(model=\"gemini-pro-vision\")\n",
"\n",
" return llm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "MKc50pW9zgdo"
},
"outputs": [],
"source": [
"model_text=load_model(\"gemini-pro\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 87
},
"id": "OWWfm8XRzlxY",
"outputId": "61b0bec5-0a7a-4b08-e4d3-d55297bd3f74"
},
"outputs": [],
"source": [
"model_text.invoke(prompt).content"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nf6dl_t_zo-n"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: MultiModal RAG/Extract_Image,Table,Text_from_Document_MultiModal_Summrizer_AAG_App_YT.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "AUeScs9rB6Nk"
},
"source": [
"# Realtime multimodal Usecase | Extract Image,Table,Text from Document | MultiModal Summrizer| RAG App"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "M7BsV2KiVRm2",
"outputId": "c5e60d31-aa52-4de2-bb12-ab97c1ea0ecc"
},
"outputs": [],
"source": [
"! pip install \"unstructured[all-docs]\" pillow pydantic lxml matplotlib"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "9ERiIOhfeWeJ",
"outputId": "252a51f6-1cca-45bb-e57b-eb9694182b04"
},
"outputs": [],
"source": [
"!sudo apt-get update"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Mu97I46AefNj",
"outputId": "50c79707-1615-4dea-f239-e63e12bedfb9"
},
"outputs": [],
"source": [
"!sudo apt-get install poppler-utils"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "BmntZhzTejwH",
"outputId": "9c0c5201-fb25-4fe7-9234-c78f4ceddeba"
},
"outputs": [],
"source": [
"!sudo apt-get install libleptonica-dev tesseract-ocr libtesseract-dev python3-pil tesseract-ocr-eng tesseract-ocr-script-latn"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "u7Rrt88Nex_u",
"outputId": "93b098d1-0045-4ca5-8a53-a6fd0d653491"
},
"outputs": [],
"source": [
"!pip install unstructured-pytesseract\n",
"!pip install tesseract-ocr"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GiVgnFmee7M7"
},
"outputs": [],
"source": [
"from unstructured.partition.pdf import partition_pdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 177,
"referenced_widgets": [
"29fef475a16a499b95bd7495e2388663",
"8e3eae6d05294e9e8a28d11b2e4b0ae2",
"035c1f9016ec4219a3d9c5b39e4066e7",
"07a7635319024098af3c7e313c0cd1d2",
"79991327fb3e4b25b963d317e85d43f8",
"910aa943220c43a697ca2156df61c4d0",
"9f34dbbd331e4dd7ae9a6d69334efa87",
"f81683846b9e4d4d9c0a2ca0fcf78386",
"63956298d47b4f81aaecbd73a38874ac",
"c266c91b3a6e4950aade4d8641db71d1",
"5fa906e23e804770ba4ca39b43db0e89"
]
},
"id": "j9uoVggzfWRI",
"outputId": "b11f8430-e6ee-44a4-93db-cb78193351dc"
},
"outputs": [],
"source": [
"raw_pdf_elements=partition_pdf(\n",
" filename=\"/content/data/cj.pdf\",\n",
" strategy=\"hi_res\",\n",
" extract_images_in_pdf=True,\n",
" extract_image_block_types=[\"Image\", \"Table\"],\n",
" extract_image_block_to_payload=False,\n",
" extract_image_block_output_dir=\"extracted_data\"\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "U4h0uSdEhIo6",
"outputId": "4c3e283a-22b5-4656-e87b-c6d6b97a8bb0"
},
"outputs": [],
"source": [
"raw_pdf_elements"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0udLgeRzkWzo"
},
"outputs": [],
"source": [
"Header=[]\n",
"Footer=[]\n",
"Title=[]\n",
"NarrativeText=[]\n",
"Text=[]\n",
"ListItem=[]\n",
"\n",
"\n",
"for element in raw_pdf_elements:\n",
" if \"unstructured.documents.elements.Header\" in str(type(element)):\n",
" Header.append(str(element))\n",
" elif \"unstructured.documents.elements.Footer\" in str(type(element)):\n",
" Footer.append(str(element))\n",
" elif \"unstructured.documents.elements.Title\" in str(type(element)):\n",
" Title.append(str(element))\n",
" elif \"unstructured.documents.elements.NarrativeText\" in str(type(element)):\n",
" NarrativeText.append(str(element))\n",
" elif \"unstructured.documents.elements.Text\" in str(type(element)):\n",
" Text.append(str(element))\n",
" elif \"unstructured.documents.elements.ListItem\" in str(type(element)):\n",
" ListItem.append(str(element))\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "U3Qjtbxfkslh",
"outputId": "5921899e-adfc-45a8-c798-3b30c4e3c580"
},
"outputs": [],
"source": [
"NarrativeText"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "eXxg4HwvkwtB",
"outputId": "c4d9a015-e841-47d7-bb84-267aad8fa743"
},
"outputs": [],
"source": [
"ListItem"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "QRsiXMKEkqjl"
},
"outputs": [],
"source": [
"img=[]\n",
"for element in raw_pdf_elements:\n",
" if \"unstructured.documents.elements.Image\" in str(type(element)):\n",
" img.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 144
},
"id": "-idYwDsQlCYy",
"outputId": "1bb9af7d-4f9d-4950-e7db-908b826b43f2"
},
"outputs": [],
"source": [
"img[2]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "wxEKH9xWk9SP",
"outputId": "68e30c33-ab8f-43f1-cf55-a62d5e577f82"
},
"outputs": [],
"source": [
"raw_pdf_elements2=partition_pdf(\n",
" filename=\"/content/data2/Retrieval-Augmented-Generation-for-NLP.pdf\",\n",
" strategy=\"hi_res\",\n",
" extract_images_in_pdf=True,\n",
" extract_image_block_types=[\"Image\", \"Table\"],\n",
" extract_image_block_to_payload=False,\n",
" extract_image_block_output_dir=\"extracted_data2\"\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fk8hSSbZlBhM",
"outputId": "54ba4415-dff1-448b-8afc-d55f101e6828"
},
"outputs": [],
"source": [
"raw_pdf_elements2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "K-NxyHd2mc_n"
},
"outputs": [],
"source": [
"img=[]\n",
"for element in raw_pdf_elements2:\n",
" if \"unstructured.documents.elements.Image\" in str(type(element)):\n",
" img.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ZyheLpbZnDnm",
"outputId": "562685ff-c5c5-4c5f-a719-d74050a6cb42"
},
"outputs": [],
"source": [
"img"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EJXbI-qnmiqh"
},
"outputs": [],
"source": [
"tab=[]\n",
"for element in raw_pdf_elements2:\n",
" if \"unstructured.documents.elements.Table\" in str(type(element)):\n",
" tab.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
},
"id": "ggmzHxN_nGbQ",
"outputId": "de7e1928-1052-4bf5-caf7-2c2db4b17bbb"
},
"outputs": [],
"source": [
"tab[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Q_HPBYJUmki8"
},
"outputs": [],
"source": [
"NarrativeText=[]\n",
"for element in raw_pdf_elements2:\n",
" if \"unstructured.documents.elements.NarrativeText\" in str(type(element)):\n",
" NarrativeText.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "BEQ3vkYjmnER"
},
"outputs": [],
"source": [
"ListItem=[]\n",
"for element in raw_pdf_elements2:\n",
" if \"unstructured.documents.elements.ListItem\" in str(type(element)):\n",
" ListItem.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "NqS75kwYnF84",
"outputId": "d2e26583-21b4-4f68-b2ed-cf5057e22574"
},
"outputs": [],
"source": [
"NarrativeText\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "AiKLLrmfv_D_",
"outputId": "ef57d10a-4839-49e0-fa19-4deb17e0ebeb"
},
"outputs": [],
"source": [
"ListItem"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "-_OkfkQH3Y2s",
"outputId": "f8669c3e-6aa9-4806-a74a-fa28c98ab7fc"
},
"outputs": [],
"source": [
"!pip install langchain_core"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rbRMkWGOefZm",
"outputId": "33bff2ab-55a8-4730-b7ac-0d5671f5c7f3"
},
"outputs": [],
"source": [
"!pip install langchain_openai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "V5f6LEkWeh_e",
"outputId": "48a085c8-aa6b-4cb1-e2c9-306d15e07c99"
},
"outputs": [],
"source": [
"len(tab)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
},
"id": "0xbJ4cytfpsN",
"outputId": "48daacff-62f6-4cc4-c16f-23b740384fb6"
},
"outputs": [],
"source": [
"tab[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "CXMVS1PWezj3",
"outputId": "86746ab0-cdc2-4b4e-c7a4-0cec5cd7d3dd"
},
"outputs": [],
"source": [
"len(img)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kpjw423Ye0ju"
},
"outputs": [],
"source": [
"from langchain_core.output_parsers import StrOutputParser\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_openai import ChatOpenAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_bbRvggrfFUG"
},
"outputs": [],
"source": [
"# Prompt\n",
"prompt_text = \"\"\"You are an assistant tasked with summarizing tables for retrieval. \\\n",
" These summaries will be embedded and used to retrieve the raw table elements. \\\n",
" Give a concise summary of the table that is well optimized for retrieval. Table {element} \"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JM-4CppSfJnd"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_template(prompt_text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kEAfJG7_fXDu"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"OPENAI_API_TOKEN=userdata.get('OPENAI_API_KEY')\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_TOKEN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1mHzuhFAfdUn"
},
"outputs": [],
"source": [
"# Text summary chain\n",
"model = ChatOpenAI(temperature=0, model=\"gpt-4\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Vi5h9tpPftEu"
},
"outputs": [],
"source": [
"summarize_chain = {\"element\": lambda x: x} | prompt | model | StrOutputParser()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2nqNsUzyf03Q"
},
"outputs": [],
"source": [
"table_summaries = []"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ybpy889Hf4GI"
},
"outputs": [],
"source": [
"table_summaries=summarize_chain.batch(tab,{\"max_concurrency\": 5})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
},
"id": "t114EKUfgLKF",
"outputId": "b18ed036-b1a8-4be3-893b-697091210e3d"
},
"outputs": [],
"source": [
"tab[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 108
},
"id": "aAslSPlZgOAu",
"outputId": "7b252d46-e209-4d92-c062-986c1bf3817a"
},
"outputs": [],
"source": [
"table_summaries[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 126
},
"id": "Xdif_KSTgQ9G",
"outputId": "a067dfff-f894-4f52-f280-a8b129b1eb43"
},
"outputs": [],
"source": [
"img[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "clS9oDdqgcqn"
},
"outputs": [],
"source": [
"import base64\n",
"import os\n",
"from langchain_core.messages import HumanMessage"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mKR7JUAEgixP"
},
"outputs": [],
"source": [
"def encode_image(image_path):\n",
" \"\"\"Getting the base64 string\"\"\"\n",
" with open(image_path, \"rb\") as image_file:\n",
" return base64.b64encode(image_file.read()).decode(\"utf-8\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nqWb87Hbgn8g"
},
"outputs": [],
"source": [
"def image_summarize(img_base64, prompt):\n",
" \"\"\"Make image summary\"\"\"\n",
"\n",
"\n",
" chat = ChatOpenAI(model=\"gpt-4-vision-preview\", max_tokens=1024)\n",
"\n",
" msg = chat.invoke(\n",
" [\n",
" HumanMessage(\n",
" content=[\n",
" {\"type\": \"text\", \"text\": prompt},\n",
"\n",
" {\n",
" \"type\": \"image_url\",\n",
" \"image_url\": {\"url\": f\"data:image/jpeg;base64,{img_base64}\"},\n",
" },\n",
" ]\n",
" )\n",
" ]\n",
" )\n",
" return msg.content"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "M2chds0kg16e"
},
"outputs": [],
"source": [
"def generate_img_summaries(path):\n",
" \"\"\"\n",
" Generate summaries and base64 encoded strings for images\n",
" path: Path to list of .jpg files extracted by Unstructured\n",
" \"\"\"\n",
"\n",
" # Store base64 encoded images\n",
" img_base64_list = []\n",
"\n",
" # Store image summaries\n",
" image_summaries = []\n",
"\n",
" # Prompt\n",
" prompt = \"\"\"You are an assistant tasked with summarizing images for retrieval. \\\n",
" These summaries will be embedded and used to retrieve the raw image. \\\n",
" Give a concise summary of the image that is well optimized for retrieval.\"\"\"\n",
"\n",
"\n",
" base64_image = encode_image(path)\n",
" img_base64_list.append(base64_image)\n",
" image_summaries.append(image_summarize(base64_image, prompt))\n",
"\n",
" return img_base64_list, image_summaries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ebVqRi8fhLM4"
},
"outputs": [],
"source": [
"fpath=\"/content/extracted_data2/figure-17-4.jpg\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zQbpbrRbhRhO"
},
"outputs": [],
"source": [
"img_base64_list,image_summaries=generate_img_summaries(fpath)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 126
},
"id": "GTtDwQ0chbf-",
"outputId": "9da9597f-47f6-4ed9-da69-1cf3c66df5b5"
},
"outputs": [],
"source": [
"image_summaries[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "HA5izJnzhgB3"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: MultiModal RAG/Extract_Image,Table,Text_from_Document_MultiModal_Summrizer_RAG_App.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "4rQa1vCdaDhv",
"outputId": "be0a955c-29f1-45a5-c31c-fabf42cfa145"
},
"outputs": [],
"source": [
"! pip install \"unstructured[all-docs]\" pillow pydantic lxml pillow matplotlib"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "a3W2ooY3OYfT",
"outputId": "3d2ef898-2209-4499-b191-62b036b1cd5a"
},
"outputs": [],
"source": [
"!sudo apt-get update"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MC7K2XQgOa-x",
"outputId": "55c55949-3ba3-4e01-8f9b-2de775e2acd2"
},
"outputs": [],
"source": [
"!sudo apt-get install poppler-utils"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "kMike74aFqrq",
"outputId": "02807e20-7a00-4747-a11a-eb0acbb20187"
},
"outputs": [],
"source": [
"!sudo apt-get install libleptonica-dev tesseract-ocr libtesseract-dev python3-pil tesseract-ocr-eng tesseract-ocr-script-latn"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hCq4oMVXO3DR",
"outputId": "470b8e87-9d0a-4ef1-8fd1-b2e78e186ea9"
},
"outputs": [],
"source": [
"!pip install unstructured-pytesseract\n",
"!pip install tesseract-ocr"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lsSUx1cPNNH_"
},
"outputs": [],
"source": [
"from unstructured.partition.pdf import partition_pdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "a_bls3tZMzCn",
"outputId": "17ad3c5a-6b5a-497f-b8f5-8ada1dadf97c"
},
"outputs": [],
"source": [
"\"/content/extracted_data\"\n",
"\"/content/data/cj.pdf\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 177,
"referenced_widgets": [
"8e8dcb04f382423d9c29d216bc074b1d",
"abf35c1d7451478eb155df336d25d17b",
"8da708152dd34924b8f95c578162f0ea",
"3339ce0efc82406da373cda19e2d81af",
"a2aafc5851e5485a9b16894e8fa2f820",
"9fba488c640b4bd3a2fd65f433500098",
"0e3e54c79043416c9cbd962492a349d3",
"c873ad85c4e643b0b89417f03be98a22",
"1d218f7e9bf141e38aad48f2a6c37b10",
"caa19e23c36545f6b2867ead37181810",
"aa6427d321a54a1b85422df0fb0ff324"
]
},
"id": "GzIeIXtEQOsh",
"outputId": "08caeb95-40c8-409e-c34b-2e8ef36786c7"
},
"outputs": [],
"source": [
"raw_pdf_elements=partition_pdf(\n",
" filename=\"/content/data/cj.pdf\", # mandatory\n",
" strategy=\"hi_res\", # mandatory to use ``hi_res`` strategy\n",
" extract_images_in_pdf=True, # mandatory to set as ``True``\n",
" extract_image_block_types=[\"Image\", \"Table\"], # optional\n",
" extract_image_block_to_payload=False, # optional\n",
" extract_image_block_output_dir=\"extracted_data\", # optional - only works when ``extract_image_block_to_payload=False``\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "wPJQmmXtTky5",
"outputId": "6e04fb3e-78e9-4182-806d-b7e9d09192ae"
},
"outputs": [],
"source": [
"raw_pdf_elements"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "a9C9hfJtQ27C"
},
"outputs": [],
"source": [
"Header=[]\n",
"Footer=[]\n",
"Title=[]\n",
"NarrativeText=[]\n",
"Text=[]\n",
"ListItem=[]\n",
"for element in raw_pdf_elements:\n",
" if \"unstructured.documents.elements.Header\" in str(type(element)):\n",
" Header.append(str(element))\n",
" elif \"unstructured.documents.elements.Footer\" in str(type(element)):\n",
" Footer.append(str(element))\n",
" elif \"unstructured.documents.elements.Title\" in str(type(element)):\n",
" Title.append(str(element))\n",
" elif \"unstructured.documents.elements.NarrativeText\" in str(type(element)):\n",
" NarrativeText.append(str(element))\n",
" elif \"unstructured.documents.elements.Text\" in str(type(element)):\n",
" Text.append(str(element))\n",
" elif \"unstructured.documents.elements.ListItem\" in str(type(element)):\n",
" ListItem.append(str(element))\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0CIyaT9Ir0-J"
},
"outputs": [],
"source": [
"img=[]\n",
"for element in raw_pdf_elements:\n",
" if \"unstructured.documents.elements.Image\" in str(type(element)):\n",
" img.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "rUal9rnMsyO8"
},
"outputs": [],
"source": [
"tab=[]\n",
"for element in raw_pdf_elements:\n",
" if \"unstructured.documents.elements.Table\" in str(type(element)):\n",
" tab.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "0rkKxzTws1kQ",
"outputId": "65b2e116-ff57-4558-f690-0c384e4d23ff"
},
"outputs": [],
"source": [
"tab"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ShGjDo0gsQLJ",
"outputId": "1823a4b0-6895-4c6d-9ac9-c875f1ea881f"
},
"outputs": [],
"source": [
"img"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 177,
"referenced_widgets": [
"58e0223794d34ffb977a1bd3d4a9e3a8",
"4ddca619a25e4cd6b674136fb209c9a4",
"2db722ea2d8043c2a7c151be4927fe01",
"078a851cd8424e088f9783f5355ad9a8",
"0d8693aedb1f4d34a53a2cc71de9a5bd",
"05a6983e0f464958b51a0a9b1618f93f",
"469b22cbe0cd4934ab985e247ab46fcc",
"0335637ed64141ec8c5472fc43fe2cd1",
"533e33b22a184e9592b267264c4024d0",
"d8e30e3e8ce747aabc45d843e0248036",
"f8717264f83f4b5289f5b817473be375"
]
},
"id": "SrIboN8gqva2",
"outputId": "e83fd2df-0d0f-46f7-d7bf-09cfd91a0d48"
},
"outputs": [],
"source": [
"raw_pdf_elements2=partition_pdf(\n",
" filename=\"/content/data2/Retrieval-Augmented-Generation-for-NLP.pdf\", # mandatory\n",
" strategy=\"hi_res\", # mandatory to use ``hi_res`` strategy\n",
" extract_images_in_pdf=True, # mandatory to set as ``True``\n",
" extract_image_block_types=[\"Image\",\"Table\"], # optional\n",
" extract_image_block_to_payload=False, # optional\n",
" extract_image_block_output_dir=\"extracted_data2\", # optional - only works when ``extract_image_block_to_payload=False``\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "-ugHzV-gzlRl",
"outputId": "f951f8ee-dc14-4c41-ee3d-b997af6b7c15"
},
"outputs": [],
"source": [
"raw_pdf_elements2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XaFRVm2A0qOH"
},
"outputs": [],
"source": [
"Table=[]\n",
"for element in raw_pdf_elements2:\n",
" if \"unstructured.documents.elements.Table\" in str(type(element)):\n",
" Table.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "EutEm_Se1CWs",
"outputId": "cd5a6f50-bc7b-448b-88a0-f37608606fb0"
},
"outputs": [],
"source": [
"Table"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "da60xGmUfBLY"
},
"outputs": [],
"source": [
"Text=[]\n",
"for element in raw_pdf_elements2:\n",
" if \"unstructured.documents.elements.NarrativeText\" in str(type(element)):\n",
" Text.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7TGpgQqdfdF1",
"outputId": "5698b09a-73cf-4625-bf7d-2d7f54a1a472"
},
"outputs": [],
"source": [
"Text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qk39xLU1fGX_"
},
"outputs": [],
"source": [
"Image=[]\n",
"for element in raw_pdf_elements2:\n",
" if \"unstructured.documents.elements.Image\" in str(type(element)):\n",
" Image.append(str(element))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "d-Ybd_fKfqE2",
"outputId": "9dc82bbb-d36b-46a8-cf93-5c8ba1d10ced"
},
"outputs": [],
"source": [
"Image"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "DRqY6KQ41yZx",
"outputId": "28be7db9-3b23-4c77-f41f-8e54f975bcfb"
},
"outputs": [],
"source": [
"!pip install langchain_core\n",
"!pip install langchain_openai\n",
"!pip install langchain\n",
"!pip install chromadb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mlZDRX9HgLBB"
},
"outputs": [],
"source": [
"from langchain_core.output_parsers import StrOutputParser\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_openai import ChatOpenAI"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PxiVeh1SjNFX"
},
"source": [
"# Table Summary"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "sCzuQvDJgXSH"
},
"outputs": [],
"source": [
"# Prompt\n",
"prompt_text = \"\"\"You are an assistant tasked with summarizing tables for retrieval. \\\n",
" These summaries will be embedded and used to retrieve the raw table elements. \\\n",
" Give a concise summary of the table that is well optimized for retrieval. Table:{element} \"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "KEO6eO5E1E1E"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_template(prompt_text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "f1ZYHfpt2VP5"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"OPENAI_API_TOKEN=userdata.get('OPENAI_API_KEY')\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_TOKEN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Wr11j3RU1ueV"
},
"outputs": [],
"source": [
"# Text summary chain\n",
"model = ChatOpenAI(temperature=0, model=\"gpt-4\")\n",
"summarize_chain = {\"element\": lambda x: x} | prompt | model | StrOutputParser()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "a2Uc1yiU2UH1"
},
"outputs": [],
"source": [
"table_summaries = []"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "DaiY0-6q2ty9"
},
"outputs": [],
"source": [
"table_summaries = summarize_chain.batch(Table, {\"max_concurrency\": 5})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lF7T14e525U0",
"outputId": "26f41999-335a-4492-b408-b521f6a5ebb9"
},
"outputs": [],
"source": [
"table_summaries"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "MS9B1A1cjIVp"
},
"source": [
"# Text Summary"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "asukHsbYiXGn"
},
"outputs": [],
"source": [
"# Prompt\n",
"prompt_text = \"\"\"You are an assistant tasked with summarizing text for retrieval. \\\n",
" These summaries will be embedded and used to retrieve the raw text elements. \\\n",
" Give a concise summary of the table or text that is well optimized for retrieval.text: {element} \"\"\"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UQto_85fidC3"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_template(prompt_text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SgMaMLpYiiC3"
},
"outputs": [],
"source": [
"# Text summary chain\n",
"model = ChatOpenAI(temperature=0, model=\"gpt-4\")\n",
"summarize_chain = {\"element\": lambda x: x} | prompt | model | StrOutputParser()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "d7F-TIw0itHn"
},
"outputs": [],
"source": [
"# Initialize empty summaries\n",
"\n",
"text_summaries = []\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2kM4EmaQUfJy"
},
"outputs": [],
"source": [
"text_summaries = summarize_chain.batch(Text, {\"max_concurrency\": 5})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "mF-rjDzrfXCW",
"outputId": "fcfa081f-2133-4628-b192-a6f2d8e6e330"
},
"outputs": [],
"source": [
"text_summaries"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "4z2ukjxCjRKn"
},
"source": [
"# Image Summary"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "DMd67jCQ-AQa"
},
"outputs": [],
"source": [
"import base64\n",
"import os\n",
"from langchain_core.messages import HumanMessage"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9Azy9eQZ-DvK"
},
"outputs": [],
"source": [
"def encode_image(image_path):\n",
" \"\"\"Getting the base64 string\"\"\"\n",
" with open(image_path, \"rb\") as image_file:\n",
" return base64.b64encode(image_file.read()).decode(\"utf-8\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RKM8O7QZ-HMK"
},
"outputs": [],
"source": [
"def image_summarize(img_base64, prompt):\n",
" \"\"\"Make image summary\"\"\"\n",
" chat = ChatOpenAI(model=\"gpt-4-vision-preview\", max_tokens=1024)\n",
"\n",
" msg = chat.invoke(\n",
" [\n",
" HumanMessage(\n",
" content=[\n",
" {\"type\": \"text\", \"text\": prompt},\n",
" {\n",
" \"type\": \"image_url\",\n",
" \"image_url\": {\"url\": f\"data:image/jpeg;base64,{img_base64}\"},\n",
" },\n",
" ]\n",
" )\n",
" ]\n",
" )\n",
" return msg.content"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "vR_u--yu231y"
},
"source": [
"https://github.com/langchain-ai/langchain/blob/master/cookbook/Multi_modal_RAG.ipynb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qytxMFVq-MUF"
},
"outputs": [],
"source": [
"def generate_img_summaries(path):\n",
" \"\"\"\n",
" Generate summaries and base64 encoded strings for images\n",
" path: Path to list of .jpg files extracted by Unstructured\n",
" \"\"\"\n",
"\n",
" # Store base64 encoded images\n",
" img_base64_list = []\n",
"\n",
" # Store image summaries\n",
" image_summaries = []\n",
"\n",
" # Prompt\n",
" prompt = \"\"\"You are an assistant tasked with summarizing images for retrieval. \\\n",
" These summaries will be embedded and used to retrieve the raw image. \\\n",
" Give a concise summary of the image that is well optimized for retrieval.\"\"\"\n",
"\n",
" # Apply to images\n",
" for img_file in sorted(os.listdir(path)):\n",
" if img_file.endswith(\".jpg\"):\n",
" img_path = os.path.join(path, img_file)\n",
" base64_image = encode_image(img_path)\n",
" img_base64_list.append(base64_image)\n",
" image_summaries.append(image_summarize(base64_image, prompt))\n",
"\n",
"\n",
" return img_base64_list, image_summaries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ZzyqftLY-Ofi"
},
"outputs": [],
"source": [
"fpath=\"/content/extracted_data2/\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gybx1HDu99Gu"
},
"outputs": [],
"source": [
"# Image summaries\n",
"img_base64_list, image_summaries = generate_img_summaries(fpath)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XQ2NVyJW-RZH",
"outputId": "42df109e-7cf0-4521-b78d-1b88170a2bd6"
},
"outputs": [],
"source": [
"image_summaries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JrqixR6qvUm_",
"outputId": "968114cc-bdd0-408b-91de-579eae4b00e2"
},
"outputs": [],
"source": [
"img_base64_list"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "AUWQu5hhLTXO"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "afOqMhtQkeS2"
},
"source": [
"# Creating a MultiVector Retriever"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XYKpk0EV-mPc"
},
"outputs": [],
"source": [
"import uuid\n",
"\n",
"from langchain.retrievers.multi_vector import MultiVectorRetriever\n",
"from langchain.storage import InMemoryStore\n",
"from langchain_community.vectorstores import Chroma\n",
"from langchain_core.documents import Document\n",
"from langchain_openai import OpenAIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kG-bGuWp4o_e"
},
"outputs": [],
"source": [
"def create_multi_vector_retriever(vectorstore, text_summaries, texts, table_summaries, tables, image_summaries, images):\n",
" \"\"\"\n",
" Create retriever that indexes summaries, but returns raw images or texts\n",
" \"\"\"\n",
"\n",
" # Initialize the storage layer\n",
" store = InMemoryStore()\n",
" id_key = \"doc_id\"\n",
"\n",
" # Create the multi-vector retriever\n",
" retriever = MultiVectorRetriever(\n",
" vectorstore=vectorstore,\n",
" docstore=store,\n",
" id_key=id_key,\n",
" )\n",
"\n",
"\n",
" # Helper function to add documents to the vectorstore and docstore\n",
" def add_documents(retriever, doc_summaries, doc_contents):\n",
"\n",
" doc_ids = [str(uuid.uuid4()) for _ in doc_contents]\n",
"\n",
" summary_docs = [\n",
" Document(page_content=s, metadata={id_key: doc_ids[i]})\n",
" for i, s in enumerate(doc_summaries)\n",
" ]\n",
"\n",
" retriever.vectorstore.add_documents(summary_docs)\n",
" retriever.docstore.mset(list(zip(doc_ids, doc_contents)))\n",
"\n",
" # Add texts, tables, and images\n",
" # Check that text_summaries is not empty before adding\n",
" if text_summaries:\n",
" add_documents(retriever, text_summaries, texts)\n",
" # Check that table_summaries is not empty before adding\n",
" if table_summaries:\n",
" add_documents(retriever, table_summaries, tab)\n",
" # Check that image_summaries is not empty before adding\n",
" if image_summaries:\n",
" add_documents(retriever, image_summaries, img)\n",
"\n",
" return retriever\n",
"\n",
"vectorstore = Chroma(\n",
" collection_name=\"mm_rag\", embedding_function=OpenAIEmbeddings()\n",
")\n",
"\n",
"# Create retriever\n",
"retriever_multi_vector_img = create_multi_vector_retriever(\n",
" vectorstore,\n",
" text_summaries,\n",
" Text,\n",
" table_summaries,\n",
" Table,\n",
" image_summaries,\n",
" img_base64_list,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GaYHuuAbbpUi",
"outputId": "571d23fb-9252-4fca-a7c6-6a6ec2f09c75"
},
"outputs": [],
"source": [
"retriever_multi_vector_img"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "E2fm4STH8MyY"
},
"outputs": [],
"source": [
"import io\n",
"import re\n",
"\n",
"from IPython.display import HTML, display\n",
"from PIL import Image"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JOts0DUa8NVd"
},
"outputs": [],
"source": [
"def plt_img_base64(img_base64):\n",
" \"\"\"Disply base64 encoded string as image\"\"\"\n",
" # Create an HTML img tag with the base64 string as the source\n",
" image_html = f'
'\n",
" # Display the image by rendering the HTML\n",
" display(HTML(image_html))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 338
},
"id": "Eb2_22-aoGSB",
"outputId": "231dc2a4-03bf-4893-8aef-e3ea508bcbb3"
},
"outputs": [],
"source": [
"plt_img_base64(img_base64_list[1])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 108
},
"id": "aYaHWDneBWF2",
"outputId": "48447e8b-6ac2-453a-a0fe-b27a786d451d"
},
"outputs": [],
"source": [
"image_summaries[1]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8xHdKk5U8u5B"
},
"outputs": [],
"source": [
"def looks_like_base64(sb):\n",
" \"\"\"Check if the string looks like base64\"\"\"\n",
" return re.match(\"^[A-Za-z0-9+/]+[=]{0,2}$\", sb) is not None\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1ozW0Yir8wux"
},
"outputs": [],
"source": [
"def is_image_data(b64data):\n",
" \"\"\"\n",
" Check if the base64 data is an image by looking at the start of the data\n",
" \"\"\"\n",
" image_signatures = {\n",
" b\"\\xFF\\xD8\\xFF\": \"jpg\",\n",
" b\"\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A\": \"png\",\n",
" b\"\\x47\\x49\\x46\\x38\": \"gif\",\n",
" b\"\\x52\\x49\\x46\\x46\": \"webp\",\n",
" }\n",
" try:\n",
" header = base64.b64decode(b64data)[:8] # Decode and get the first 8 bytes\n",
" for sig, format in image_signatures.items():\n",
" if header.startswith(sig):\n",
" return True\n",
" return False\n",
" except Exception:\n",
" return False"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "W_NbnR5B8zCa"
},
"outputs": [],
"source": [
"def resize_base64_image(base64_string, size=(128, 128)):\n",
" \"\"\"\n",
" Resize an image encoded as a Base64 string\n",
" \"\"\"\n",
" # Decode the Base64 string\n",
" img_data = base64.b64decode(base64_string)\n",
" img = Image.open(io.BytesIO(img_data))\n",
"\n",
" # Resize the image\n",
" resized_img = img.resize(size, Image.LANCZOS)\n",
"\n",
" # Save the resized image to a bytes buffer\n",
" buffered = io.BytesIO()\n",
" resized_img.save(buffered, format=img.format)\n",
"\n",
" # Encode the resized image to Base64\n",
" return base64.b64encode(buffered.getvalue()).decode(\"utf-8\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "sitteApG81AA"
},
"outputs": [],
"source": [
"def split_image_text_types(docs):\n",
" \"\"\"\n",
" Split base64-encoded images and texts\n",
" \"\"\"\n",
" b64_images = []\n",
" texts = []\n",
"\n",
" for doc in docs:\n",
" # Check if the document is of type Document and extract page_content if so\n",
" if isinstance(doc, Document):\n",
" doc = doc.page_content\n",
" if looks_like_base64(doc) and is_image_data(doc):\n",
" doc = resize_base64_image(doc, size=(1300, 600))\n",
" b64_images.append(doc)\n",
" else:\n",
" texts.append(doc)\n",
"\n",
" return {\"images\": b64_images, \"texts\": texts}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3q0i4U_n88IZ"
},
"outputs": [],
"source": [
"def img_prompt_func(data_dict):\n",
" \"\"\"\n",
" Join the context into a single string\n",
" \"\"\"\n",
" #print(data_dict)\n",
" formatted_texts = \"\\n\".join(data_dict[\"context\"][\"texts\"])\n",
" messages = []\n",
"\n",
" # Adding image(s) to the messages if present\n",
" if data_dict[\"context\"][\"images\"]:\n",
" for image in data_dict[\"context\"][\"images\"]:\n",
" image_message = {\n",
" \"type\": \"image_url\",\n",
" \"image_url\": {\"url\": f\"data:image/jpeg;base64,{image}\"},\n",
" }\n",
" messages.append(image_message)\n",
"\n",
" # Adding the text for analysis\n",
" text_message = {\n",
" \"type\": \"text\",\n",
" \"text\": (\n",
" \"You are a helpful assistant.\\n\"\n",
" \"You will be given a mixed info(s) .\\n\"\n",
" \"Use this information to provide relevant information to the user question. \\n\"\n",
" f\"User-provided question: {data_dict['question']}\\n\\n\"\n",
" \"Text and / or tables:\\n\"\n",
" f\"{formatted_texts}\"\n",
" ),\n",
" }\n",
" messages.append(text_message)\n",
" return [HumanMessage(content=messages)]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fK7NdBN9TXbN"
},
"outputs": [],
"source": [
"from langchain_core.runnables import RunnableLambda, RunnablePassthrough"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1Hg65Azq8-La"
},
"outputs": [],
"source": [
"def multi_modal_rag_chain(retriever):\n",
" \"\"\"\n",
" Multi-modal RAG chain\n",
" \"\"\"\n",
"\n",
" # Multi-modal LLM\n",
" model = ChatOpenAI(temperature=0, model=\"gpt-4-vision-preview\", max_tokens=1024)\n",
"\n",
"\n",
" # RAG pipeline\n",
" chain = (\n",
" {\n",
" \"context\": retriever | RunnableLambda(split_image_text_types),\n",
" \"question\": RunnablePassthrough(),\n",
" }\n",
" | RunnableLambda(img_prompt_func)\n",
" | model\n",
" | StrOutputParser()\n",
" )\n",
"\n",
" return chain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hvyZkjqa9AHZ"
},
"outputs": [],
"source": [
"# Create RAG chain\n",
"chain_multimodal_rag = multi_modal_rag_chain(retriever_multi_vector_img)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "y1N9ONMPCW-h",
"outputId": "e22a46e6-ff1b-4e71-8350-d372d7846871"
},
"outputs": [],
"source": [
"chain_multimodal_rag"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "9H1zhRDa7zpD"
},
"source": [
"# Check"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "FmStvDLddInz"
},
"outputs": [],
"source": [
"# Check retrieval\n",
"query = \"Why We combine a pre-trained retriever (Query Encoder + Document Index) with a pre-trained seq2seq model (Generator) and fine-tune end-to-end?\"\n",
"docs = retriever_multi_vector_img.invoke(query)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "QujmCVbHlyFg",
"outputId": "7974d7cc-b8c3-4724-96d7-cab726b69b44"
},
"outputs": [],
"source": [
"docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dOPXJDfUC3BI"
},
"outputs": [],
"source": [
"query=\"Open-Domain QA Test Scores. For TQA,\\\n",
"left column uses the standard test set for Open-\\\n",
"Domain QA, right column uses the TQA-Wiki\\\n",
"test set. See Appendix D for further details.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "H1YaG7QYTrFV"
},
"outputs": [],
"source": [
"docs = retriever_multi_vector_img.invoke(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "NXt_JE33TsyC",
"outputId": "579c777f-f985-4c99-f9ec-ca60d9e3bb2f"
},
"outputs": [],
"source": [
"docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "OtspMKwyDr5p"
},
"outputs": [],
"source": [
"query=\"Models are trained with either 5 or 10 retrieved latent\\\n",
"documents, and we do not observe significant differences in performance between them.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "J6RFUzOgC9Nn",
"outputId": "712d33e6-4644-4e9c-a427-c61af688e8c1"
},
"outputs": [],
"source": [
"retriever_multi_vector_img.invoke(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 37
},
"id": "2HkKxemH9GHg",
"outputId": "591e1738-f060-4f88-85a3-cb4cbe1f65ea"
},
"outputs": [],
"source": [
"# We get back relevant images\n",
"plt_img_base64(docs)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "p0F8kQmMBhdS"
},
"source": [
"# RAG"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PhhTb937EDJ5"
},
"outputs": [],
"source": [
"query=\"can you explain me this Left: NQ performance as more documents are retrieved. Center: Retrieval recall performance\\\n",
"in NQ. Right: MS-MARCO Bleu-1 and Rouge-L as more documents are retrieved.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RRTcmOhnHBiE"
},
"outputs": [],
"source": [
"query1=\"Explain any images / figures in the paper with Left: NQ performance as more documents are retrieved. Center: Retrieval recall performance\\\n",
"in NQ. Right: MS-MARCO Bleu-1 and Rouge-L as more documents are retrieved.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 162
},
"id": "mi4Se2uP9NCc",
"outputId": "3fe09275-23ea-4569-c656-9bb26731eaf1"
},
"outputs": [],
"source": [
"# Run RAG chain\n",
"chain_multimodal_rag.invoke(query1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "jz_S4m9vc6_5"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: MultiModal RAG/MultiModal RAG using Vertex AI AstraDB(Cassandra) & Langchain.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"id": "0",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"id": "1",
"metadata": {
"id": "Su9UaTllPPyT"
},
"source": [
"## Install Vertex AI SDK for Python"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 845
},
"id": "sp5rXuilbYyz1ue2BFuSmJle",
"outputId": "05bca8b5-a950-4817-fe9d-72c495126451",
"tags": []
},
"outputs": [],
"source": [
"!pip install --upgrade --user google-cloud-aiplatform"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "DCoTFxquXd3m",
"outputId": "97a836c7-7321-47f2-8850-57dd0709ad98"
},
"outputs": [],
"source": [
"!pip install ragstack-ai"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {
"id": "xh6SW67NmMaj"
},
"outputs": [],
"source": [
"PROJECT_ID = \"red-delight-346705\"\n",
"LOCATION = \"us-central1\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 70
},
"id": "QiyrYIBKnElp",
"outputId": "5f506fc5-2cb2-41df-cac4-7a7d8d260438"
},
"outputs": [],
"source": [
"ASTRA_DB_API_ENDPOINT=\"https://79b63042-b3d1-4163-b10a-75c9979ebf59-us-east-2.apps.astra.datastax.com\"\n",
"ASTRA_DB_APPLICATION_TOKEN=\"\"#keep your token here\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lKXWCbjHydhC",
"outputId": "1849aa94-63dd-4438-8fdc-82c1158234a6"
},
"outputs": [],
"source": [
"import getpass, os, requests\n",
"\n",
"if \"GCP_PROJECT_ID\" not in os.environ:\n",
" os.environ[\"GCP_PROJECT_ID\"] = getpass.getpass(\"Provide your GCP Project ID\")\n",
"\n",
"if \"LOCATION\" not in os.environ:\n",
" os.environ[\"LOCATION\"] = getpass.getpass(\"Provide your GCP Location\")\n",
"\n",
"if \"ASTRA_DB_ENDPOINT\" not in os.environ:\n",
" os.environ[\"ASTRA_DB_ENDPOINT\"] = getpass.getpass(\"Provide your Astra DB Endpoint\")\n",
"\n",
"if \"ASTRA_DB_TOKEN\" not in os.environ:\n",
" os.environ[\"ASTRA_DB_TOKEN\"] = getpass.getpass(\"Provide your Astra DB Token\")"
]
},
{
"cell_type": "markdown",
"id": "7",
"metadata": {
"id": "mO8cqwwwRIJv"
},
"source": [
"## Authenticate your notebook environment ( Colab only )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xCh2oo_LYFxf",
"outputId": "3d586ed2-30bd-40dd-ab77-d80cce5c15ec"
},
"outputs": [],
"source": [
"!gcloud config set project {os.getenv(\"GCP_PROJECT_ID\")}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9",
"metadata": {
"id": "BWflD-lzRFgC"
},
"outputs": [],
"source": [
"import sys\n",
"\n",
"# Additional authentication is required for Google Colab\n",
"if \"google.colab\" in sys.modules:\n",
" # Authenticate user to Google Cloud\n",
" from google.colab import auth\n",
"\n",
" auth.authenticate_user()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MpyaRy-JXqYx",
"outputId": "b59285fb-ef6f-4230-8c73-8f59adcc585a"
},
"outputs": [],
"source": [
"!gcloud auth list"
]
},
{
"cell_type": "markdown",
"id": "11",
"metadata": {
"id": "Ef3YjVSsRp9Q"
},
"source": [
"## Set Google Cloud project information and initialize Vertex AI SDK"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12",
"metadata": {
"id": "C8iMCMkeYgGT"
},
"outputs": [],
"source": [
"# Define project information\n",
"PROJECT_ID=os.getenv(\"GCP_PROJECT_ID\")\n",
"LOCATION=os.getenv(\"LOCATION\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
"metadata": {
"id": "G1MCN16ZRFR3"
},
"outputs": [],
"source": [
"# Initialize Vertex AI\n",
"import vertexai\n",
"\n",
"vertexai.init(project=PROJECT_ID, location=LOCATION)"
]
},
{
"cell_type": "markdown",
"id": "14",
"metadata": {
"id": "KOBAtIV3R8mY"
},
"source": [
"## Import libraries"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15",
"metadata": {
"id": "lXlozq1mQThR"
},
"outputs": [],
"source": [
"from vertexai.preview.generative_models import (\n",
" GenerationConfig,\n",
" GenerativeModel,\n",
" HarmCategory,\n",
" HarmBlockThreshold,\n",
" Image,\n",
" Part\n",
")"
]
},
{
"cell_type": "markdown",
"id": "16",
"metadata": {
"id": "Pyza6kJuSCg_"
},
"source": [
"## Use the Gemini 1.0 Pro model\n",
"\n",
"The Gemini 1.0 Pro (`gemini-1.0-pro`) model is designed to handle natural language tasks, multi-turn text and code chat, and code generation.\n"
]
},
{
"cell_type": "markdown",
"id": "17",
"metadata": {
"id": "teZPcNCISLkQ"
},
"source": [
"## Load the Gemini 1.0 Pro model"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18",
"metadata": {
"id": "kUB8nEGhQXMH"
},
"outputs": [],
"source": [
"model = GenerativeModel(\"gemini-1.0-pro\")"
]
},
{
"cell_type": "markdown",
"id": "19",
"metadata": {
"id": "soDP_1kmSTSn"
},
"source": [
"## Generate text from text prompts"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "20",
"metadata": {
"id": "cvWMgCTZntYK"
},
"outputs": [],
"source": [
"responses = model.generate_content(\"Why is the sky blue?\", stream=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xuwrxROoSESn",
"outputId": "f3ad777a-13dc-499e-cc23-e899e39456ec"
},
"outputs": [],
"source": [
"for response in responses:\n",
" print(response.text, end=\"\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "22",
"metadata": {
"id": "yYfeGQzMn0E4"
},
"outputs": [],
"source": [
"prompt = \"\"\"Create a numbered list of 10 items. Each item in the list should be a trend in the tech industry.\n",
"\n",
"Each trend should be less than 5 words.\"\"\" # try your own prompt\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23",
"metadata": {
"id": "F2FOUPIfn4jp"
},
"outputs": [],
"source": [
"responses = model.generate_content(prompt, stream=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "24",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "yhtHW2wySENe",
"outputId": "adf3ffdc-b7ca-4a73-c61d-6ce28279d22d"
},
"outputs": [],
"source": [
"for response in responses:\n",
" print(response.text, end=\"\")"
]
},
{
"cell_type": "markdown",
"id": "25",
"metadata": {
"id": "lmoUexYKTFmj"
},
"source": [
"## Model parameters\n",
"\n",
"Every prompt you send to the model includes parameter values that control how the model generates a response. The model can generate different results for different parameter values. You can experiment with different model parameters to see how the results change."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "26",
"metadata": {
"id": "-96LHeIVoDVw"
},
"outputs": [],
"source": [
"generation_config = GenerationConfig(\n",
" temperature=0.9,\n",
" top_p=1.0,\n",
" top_k=32,\n",
" candidate_count=1,\n",
" max_output_tokens=8192,\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "27",
"metadata": {
"id": "9CyRucFooHMH"
},
"outputs": [],
"source": [
"responses = model.generate_content(\n",
" \"Why is the sky blue?\",\n",
" generation_config=generation_config,\n",
" stream=True,\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "28",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "q4C71eAFSEK3",
"outputId": "a5e31697-a5f8-423b-e35e-3ddfafab0993"
},
"outputs": [],
"source": [
"for response in responses:\n",
" print(response.text, end=\"\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "29",
"metadata": {
"id": "UxflQ0mWoZcu"
},
"outputs": [],
"source": [
"source_img_data = requests.get('https://drive.google.com/uc?export=view&id=15ddcn-AIxpvRdWcFGvIr77XLWdo4Maof').content"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "30",
"metadata": {
"id": "G2SNnO7JYtlu"
},
"outputs": [],
"source": [
"with open('coffee_maker_part.png', 'wb') as handler:\n",
" handler.write(source_img_data)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "31",
"metadata": {
"id": "lYAFQWLFurTf"
},
"outputs": [],
"source": [
"from langchain_google_vertexai import ChatVertexAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "32",
"metadata": {
"id": "h4_Cd_QP13jh"
},
"outputs": [],
"source": [
"from langchain.schema.messages import HumanMessage\n",
"from PIL import Image, ImageFile\n",
"import os, sys\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "33",
"metadata": {
"id": "Q5-GXhql2amH"
},
"outputs": [],
"source": [
"chat = ChatVertexAI(model_name=\"gemini-1.0-pro-vision\",safety_settings={\n",
" HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE\n",
" },)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "34",
"metadata": {
"id": "-5a4W_Os2iUo"
},
"outputs": [],
"source": [
"image_message = {\n",
" \"type\": \"image_url\",\n",
" \"image_url\": {\"url\": \"coffee_maker_part.png\"},\n",
"}\n",
"text_message = {\n",
" \"type\": \"text\",\n",
" \"text\": \"What is this image? Share a link to purchase a replacement\",\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "35",
"metadata": {
"id": "d3_y9HUppFS3"
},
"outputs": [],
"source": [
"message = HumanMessage(content=[text_message, image_message])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RO10SiFzpLX5",
"outputId": "6ef1c5c2-33a6-4f28-c30d-1332d3379599"
},
"outputs": [],
"source": [
"output = chat([message])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "37",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8i96veBrYwim",
"outputId": "b90ee03e-51cf-4dac-d8e8-08971cbae5fd"
},
"outputs": [],
"source": [
"print(output.content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 780
},
"id": "s0kOfknRY20q",
"outputId": "98be1d6b-9791-4743-88c3-72193503d3a6"
},
"outputs": [],
"source": [
"import pandas as pd\n",
"\n",
"d = {'name': [\"Saucer\", \"Saucer Ceramic\", \"Milk Jug Assembly\", \"Handle Steam Wand Kit (New Version From 0735 PDC)\", \"Spout Juice Small (From 0637 to 1041 PDC)\", \"Cleaning Steam Wand\", \"Jug Frothing\", \"Spoon Tamping 50mm\", \"Collar Grouphead 50mm\", \"Filter 2 Cup Dual Wall 50mm\", \"Filter 1 Cup 50mm\", \"Water Tank Assembly\", \"Portafilter Assembly 50mm\", \"Milk Jug Assembly\", \"Filter 2 Cup 50mm\" ],\n",
" 'url': [\"https://www.breville.com/us/en/parts-accessories/parts/sp0014946.html?sku=SP0014946\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0014914.html?sku=SP0014914\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0011391.html?sku=SP0011391\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0010719.html?sku=SP0010719\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0010718.html?sku=SP0010718\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003247.html?sku=SP0003247\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003246.html?sku=SP0003246\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003243.html?sku=SP0003243\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003232.html?sku=SP0003232\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003231.html?sku=SP0003231\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003230.html?sku=SP0003230\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003225.html?sku=SP0003225\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003216.html?sku=SP0003216\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0001875.html?sku=SP0001875\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0000166.html?sku=SP0000166\"],\n",
" 'price': [\"10.95\", \"4.99\", \"14.95\", \"8.95\", \"10.95\", \"6.95\", \"24.95\", \"8.95\", \"6.95\", \"12.95\", \"12.95\", \"14.95\", \"10.95\", \"16.95\", \"11.95\"],\n",
" 'image': [\"https://www.breville.com/content/dam/breville/us/catalog/products/images/sp0/sp0014946/tile.jpg\", \"https://www.breville.com/content/dam/breville/us/catalog/products/images/sp0/sp0014914/tile.jpg\", \"https://www.breville.com/content/dam/breville/us/catalog/products/images/sp0/sp0011391/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0010719/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0010718/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0003247/tile.jpg\", \"https://assets.breville.com/cdn-cgi/image/width=400,format=auto/Spare+Parts+/Espresso+Machines/BES250/SP0003246/SP0003246_IMAGE1_400X400.jpg\", \"https://assets.breville.com/cdn-cgi/image/width=400,format=auto/Spare+Parts+/Espresso+Machines/ESP8/SP0003243/SP0003243_IMAGE1_400X400.jpg\", \"https://assets.breville.com/cdn-cgi/image/width=400,format=auto/Spare+Parts+/Espresso+Machines/ESP8/SP0003232/SP0003232_IMAGE1_400x400.jpg\", \"https://www.breville.com/content/dam/breville/au/catalog/products/images/sp0/sp0003231/tile.jpg\", \"https://www.breville.com/content/dam/breville/au/catalog/products/images/sp0/sp0003230/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0003225/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0003216/tile.jpg\", \"https://www.breville.com/content/dam/breville/au/catalog/products/images/sp0/sp0001875/tile.jpg\", \"https://www.breville.com/content/dam/breville/us/catalog/products/images/sp0/sp0000166/tile.jpg\"]}\n",
"df = pd.DataFrame(data=d)\n",
"df"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39",
"metadata": {
"id": "2fcMmT6x2_Fu"
},
"outputs": [],
"source": [
"import vertexai, json, requests\n",
"from vertexai.preview.vision_models import MultiModalEmbeddingModel, Image\n",
"from astrapy.db import AstraDB, AstraDBCollection\n",
"from google.colab import files"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "40",
"metadata": {
"id": "c5RNXJmb3BVw"
},
"outputs": [],
"source": [
"model = MultiModalEmbeddingModel.from_pretrained(\"multimodalembedding@001\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41",
"metadata": {
"id": "MmAw9Z8D3EYM"
},
"outputs": [],
"source": [
"# Initialize our vector db\n",
"astra_db = AstraDB(token=os.getenv(\"ASTRA_DB_TOKEN\"), api_endpoint=os.getenv(\"ASTRA_DB_ENDPOINT\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "42",
"metadata": {
"id": "rGf8tmF23Gxc"
},
"outputs": [],
"source": [
"collection = astra_db.create_collection(collection_name=\"coffee_shop_ecommerce\", dimension=1408)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "43",
"metadata": {
"id": "Qc2D1qqvY6Jy"
},
"outputs": [],
"source": [
"for i in range(len(df)):\n",
" name = df.loc[i, \"name\"]\n",
" image = df.loc[i, \"image\"]\n",
" price = df.loc[i, \"price\"]\n",
" url = df.loc[i, \"url\"]\n",
"\n",
" # Download this product's image and save it to the Colab filesystem.\n",
" # In a production system this binary data would be stored in Google Cloud Storage\n",
" img_data = requests.get(image).content\n",
" with open(f'{name}.png', 'wb') as handler:\n",
" handler.write(img_data)\n",
"\n",
" # load the image from filesystem and compute the embedding value\n",
" img = Image.load_from_file(f'{name}.png')\n",
" embeddings = model.get_embeddings(image=img, contextual_text=name)\n",
"\n",
" try:\n",
" # add to the AstraDB Vector Database\n",
" collection.insert_one({\n",
" \"_id\": i,\n",
" \"name\": name,\n",
" \"image\": image,\n",
" \"url\": url,\n",
" \"price\": price,\n",
" \"$vector\": embeddings.image_embedding,\n",
" })\n",
" except Exception as error:\n",
" # if you've already added this record, skip the error message\n",
" error_info = json.loads(str(error))\n",
" if error_info[0]['errorCode'] == \"DOCUMENT_ALREADY_EXISTS\":\n",
" print(\"Document already exists in the database. Skipping.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "44",
"metadata": {
"id": "A8OALWDt4alj"
},
"outputs": [],
"source": [
"import json\n",
"\n",
"# Embed the similar item\n",
"img = Image.load_from_file('coffee_maker_part.png')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "45",
"metadata": {
"id": "FYEBo0rO3uV9"
},
"outputs": [],
"source": [
"embeddings = model.get_embeddings(image=img, contextual_text=\"A espresso machine part\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "46",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GfTqY9MKouR_",
"outputId": "582f5bfb-86ea-4b5c-9c12-db60cdffe617"
},
"outputs": [],
"source": [
"embeddings.image_embedding"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "47",
"metadata": {
"id": "UE6SRN1t3wEv"
},
"outputs": [],
"source": [
"# Perform the vector search against AstraDB Vector\n",
"documents = collection.vector_find(\n",
" embeddings.image_embedding,\n",
" limit=3,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "48",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5rhq7QNQrM-f",
"outputId": "97790f82-3584-4cb1-f482-444f07f93609"
},
"outputs": [],
"source": [
"documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "49",
"metadata": {
"id": "4eTwAQKH3yD6"
},
"outputs": [],
"source": [
"related_products_csv = \"name, image, price, url\\n\"\n",
"for doc in documents:\n",
" related_products_csv += f\"{doc['name']}, {doc['image']}, {doc['price']}, {doc['url']},\\n\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "50",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "T-A4o7wIrmTj",
"outputId": "020b73b5-5520-4c00-92b0-af67b6d83f55"
},
"outputs": [],
"source": [
"print(related_products_csv)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "51",
"metadata": {
"id": "Li-fX8pz30kz"
},
"outputs": [],
"source": [
"image_message = {\n",
" \"type\": \"image_url\",\n",
" \"image_url\": {\"url\": \"/content/coffee_maker_part.png\"},\n",
"}\n",
"text_message = {\n",
" \"type\": \"text\",\n",
" \"text\": f\"What we have in this image? Share the URL and price to purchase a replacement. Here are related products {related_products_csv}\",\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "52",
"metadata": {
"id": "57KzUhbd4B2e"
},
"outputs": [],
"source": [
"message = HumanMessage(content=[text_message, image_message])\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "53",
"metadata": {
"id": "Q7_Ktwg7tBTR"
},
"outputs": [],
"source": [
"chat = ChatVertexAI(model_name=\"gemini-1.0-pro-vision\",safety_settings={\n",
" HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE\n",
" },)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "54",
"metadata": {
"id": "opNLdOPw4DTk"
},
"outputs": [],
"source": [
"output = chat([message])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "55",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rUDI6iZyY-yc",
"outputId": "41ffd1bf-68eb-4a74-c78d-a2367da381a1"
},
"outputs": [],
"source": [
"print(output.content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "56",
"metadata": {
"id": "SWqUjjMMWWfH"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
================================================
FILE: MultiModal RAG/MultiModal_RAG_with_llamaIndex_and_LanceDB.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "Yn8jv85EiZn_"
},
"source": [
"# **MultiModal RAG App for Video Processing With LlamaIndex and LanceDB**"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "5ZHVe_qkiYkg"
},
"source": [
"### 1. llamaindex framework\n",
"### 2. Lancedb Vector DataBase\n",
"### 3. LLM MultiModAl GPT-4V or Google-gemini-pro-vision\n",
"\n",
"\n",
"# **Steps Need to follow:**\n",
"#### 1. Download video from YouTube, process and store it.\n",
"\n",
"#### 2. Build Multi-Modal index and vector store for both texts and images.\n",
"\n",
"#### 3. Retrieve relevant images and context, use both to augment the prompt.\n",
"\n",
"#### 4. Using GPT4V for reasoning the correlations between the input query and augmented data and generating final response."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "sY9xSK0SihIG",
"outputId": "22e8e2d4-aa21-4706-8660-76cb79a39caa"
},
"outputs": [],
"source": [
"%pip install llama-index-vector-stores-lancedb\n",
"%pip install llama-index-multi-modal-llms-openai\n",
"%pip install llama-index-embeddings-clip\n",
"%pip install git+https://github.com/openai/CLIP.git\n",
"!pip install llama-index-readers-file"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "qNZ4yrIMpa9S",
"outputId": "cad849f2-6b95-4e56-b3c1-da66eb4a89bc"
},
"outputs": [],
"source": [
"%pip install llama_index\n",
"%pip install -U openai-whisper"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "Y6xmSWjkppBJ",
"outputId": "637cab2b-a090-47e5-b4e3-b88428ef65c2"
},
"outputs": [],
"source": [
"%pip install lancedb\n",
"%pip install moviepy\n",
"%pip install pytube\n",
"%pip install pydub\n",
"%pip install SpeechRecognition\n",
"%pip install ffmpeg-python\n",
"%pip install soundfile\n",
"%pip install torch torchvision\n",
"%pip install matplotlib scikit-image\n",
"%pip install ftfy regex tqdm"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "tMlqUqibp0ji"
},
"source": [
"ffmpeg-library enables you to use FFmpeg in Python to manipulate various media files for different purposes like building comprehensive multimedia applications, preprocessing media files.\n",
"\n",
"MoviePy is a Python library for video editing, enabling cutting, concatenations, title insertions, video compositing, and effects like animations or color grading.\n",
"\n",
"Pytube is a Python library used for downloading videos from YouTube. It supports downloading in various formats, resolutions, and also direct audio extraction.\n",
"\n",
"\n",
"Pydub is a Python library for audio manipulation, enabling easy loading,\n",
"editing, and exporting of audio files in various formats with minimal code.\n",
"\n",
"The SpeechRecognition library in Python allows you to convert spoken language into text using various engines and APIs, such as Google Speech Recognition, IBM Speech to Text, etc.\n",
"\n",
"\n",
"SoundFile is a Python library for reading from and writing to audio files, supporting many formats through the libsndfile library, ideal for high-quality audio processing.\n",
"\n",
"FTFY (Fix Text For You) is a Python library that fixes broken Unicode text and mojibake (garbled text due to encoding issues), making text legible again.\n",
"\n",
"OpenAI Whisper is a robust, multilingual speech recognition model developed by OpenAI. It converts speech into text and supports various languages with high accuracy.\n",
"\n",
"pprint is a Python module that provides a capability to \"pretty-print\" complex data structures in a well-formatted and more readable way than the basic print function."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "igmrjXU6pwhu"
},
"outputs": [],
"source": [
"from moviepy.editor import VideoFileClip\n",
"from pathlib import Path\n",
"import speech_recognition as sr\n",
"from pytube import YouTube\n",
"from pprint import pprint\n",
"from PIL import Image\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ukX3ASTKqNDw"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"OPENAI_API_TOKEN=userdata.get('OPENAI_API_KEY')\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_TOKEN"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "TjxaH7FwqRGQ",
"outputId": "ebaf140c-15b1-40db-e50f-69d441bb9aa1"
},
"outputs": [],
"source": [
"import os\n",
"print(os.getcwd())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0dA6Lv4Hqp26"
},
"outputs": [],
"source": [
"video_url=\"https://youtu.be/3dhcmeOTZ_Q\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0TzZx3dbqrwq"
},
"outputs": [],
"source": [
"output_video_path = \"/content/video_data/\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bTx05t7bqcFv"
},
"outputs": [],
"source": [
"# from the video i am going to collect images,audio,text\n",
"output_folder = \"/content/mixed_data/\"\n",
"output_audio_path = \"/content/mixed_data/output_audio.wav\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PTzo50Y6qtmA"
},
"outputs": [],
"source": [
"!mkdir mixed_data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "n9SkpcGgq--g",
"outputId": "4fc30558-b6f9-493b-8a5a-403d6f1e10ae"
},
"outputs": [],
"source": [
"filepath=output_video_path + \"input_vid.mp4\"\n",
"print(filepath)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dwfB_9uhrB2F"
},
"outputs": [],
"source": [
"from pytube import YouTube\n",
"def download_video(url,output_path):\n",
" yt = YouTube(url)\n",
" metadata = {\"Author\": yt.author, \"Title\": yt.title, \"Views\": yt.views}\n",
"\n",
" yt.streams.get_highest_resolution().download(\n",
" output_path=output_path, filename=\"input_vid.mp4\"\n",
" )\n",
" return metadata"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "-lOX4wuBr8N6"
},
"outputs": [],
"source": [
"from moviepy.editor import VideoFileClip\n",
"def video_to_images(video_path,output_folder):\n",
" clip=VideoFileClip(video_path)\n",
" clip.write_images_sequence(\n",
" os.path.join(output_folder,\"frame%04d.png\"),fps=0.2\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0HPUIQSFsMkh"
},
"outputs": [],
"source": [
"def video_to_audio(video_path,output_audio_path):\n",
" clip=VideoFileClip(video_path)\n",
" audio=clip.audio\n",
" audio.write_audiofile(output_audio_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_p39w53ZsRb5"
},
"outputs": [],
"source": [
"def audio_to_text(audio_path):\n",
" recognizer=sr.Recognizer()\n",
" audio=sr.AudioFile(audio_path)\n",
"\n",
" with audio as source:\n",
" audio_data=recognizer.record(source)\n",
"\n",
" try:\n",
"\n",
" #recognize the speech\n",
" text = recognizer.recognize_whisper(audio_data)\n",
"\n",
" except sr.UnknownValueError:\n",
" print(\"Speech recognition could not understand the audio.\")\n",
" return text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "RZnTqV_fslb2",
"outputId": "e043f6f5-f3d3-4031-dae2-e260004fcb02"
},
"outputs": [],
"source": [
"video_url"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "KU1B6rEGsnVt",
"outputId": "0bf343b3-b008-491f-c705-1d2d363476aa"
},
"outputs": [],
"source": [
"output_video_path"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RblUwfbJshSJ"
},
"outputs": [],
"source": [
"metadata_vid = download_video(video_url, output_video_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gwZJpGH8ssiM",
"outputId": "3051ee60-9337-43ec-8698-9c4ccf6d9e6b"
},
"outputs": [],
"source": [
"metadata_vid"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JbtVwXvgsqD8",
"outputId": "5e51c2e6-cbea-4ad8-e76e-c444eb027bfc"
},
"outputs": [],
"source": [
"video_to_images(filepath,output_folder)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "XeIiBcBXs9fu",
"outputId": "2dc35766-49b3-43e5-fc58-3128d316c97e"
},
"outputs": [],
"source": [
"filepath"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "hhf-ckBDtAAe",
"outputId": "4a97db0f-737a-440a-d555-e11f2135e538"
},
"outputs": [],
"source": [
"output_audio_path"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lhfIDRJLswtx",
"outputId": "4d3e1a7e-c431-4590-ceb3-bbd4d680db13"
},
"outputs": [],
"source": [
"video_to_audio(filepath,output_audio_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GGIEgadAtCaq",
"outputId": "49523efa-e6e1-4d56-9fcd-f25c4b377f10"
},
"outputs": [],
"source": [
"text_data=audio_to_text(output_audio_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 162
},
"id": "TCEnFoCPtHq8",
"outputId": "df721248-ec0e-4747-c6bc-34f254354d27"
},
"outputs": [],
"source": [
"text_data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "EgEEv89ptdHp",
"outputId": "d9ceef12-1119-4595-d077-925034701218"
},
"outputs": [],
"source": [
"with open(output_folder + \"output_text.txt\", \"w\") as file:\n",
" file.write(text_data)\n",
"print(\"Text data saved to file\")\n",
"file.close()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "zse424_3tl9a",
"outputId": "240eb1ac-2384-4ef4-e11b-3f31e8af11a5"
},
"outputs": [],
"source": [
"os.remove(output_audio_path)\n",
"print(\"Audio file removed\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7KB6YBHJuCLt"
},
"outputs": [],
"source": [
"#process the video\n",
"#image\n",
"#text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vj4OUtZluIGG"
},
"outputs": [],
"source": [
"from llama_index.core.indices import MultiModalVectorStoreIndex\n",
"from llama_index.core import SimpleDirectoryReader\n",
"from llama_index.core import StorageContext"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kBBDEuXUutl5"
},
"outputs": [],
"source": [
"from llama_index.vector_stores.lancedb import LanceDBVectorStore"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xUv_t8vMuxYK"
},
"outputs": [],
"source": [
"text_store=LanceDBVectorStore(uri=\"lancedb\",table_name=\"text_collection\")\n",
"image_store=LanceDBVectorStore(uri=\"lancedb\",table_name=\"image_collection\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Ua0JXObmvRYN"
},
"outputs": [],
"source": [
"storage_context=StorageContext.from_defaults(vector_store=text_store,image_store=image_store)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "KCicDH2WvZvQ",
"outputId": "8a22d126-c409-49fe-e68b-bde9f5edd5d0"
},
"outputs": [],
"source": [
"output_folder"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_B-UYzwtvXKq"
},
"outputs": [],
"source": [
"documents=SimpleDirectoryReader(output_folder).load_data()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "BbaU5Noqvdyk",
"outputId": "6ea2eefc-b4fb-4eb6-f93b-17044a47b3fc"
},
"outputs": [],
"source": [
"index = MultiModalVectorStoreIndex.from_documents(documents,storage_context=storage_context)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "v5vZLg_-vm2o"
},
"outputs": [],
"source": [
"retriever_engine=index.as_retriever(similarity_top_k=1, image_similarity_top_k=5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "BQ2viUQuvv8K"
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3hTtlvjav2fw"
},
"outputs": [],
"source": [
"from llama_index.core.response.notebook_utils import display_source_node\n",
"from llama_index.core.schema import ImageNode"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3c5AB1KWv3yv"
},
"outputs": [],
"source": [
"def retrieve(retriever_engine, query_str):\n",
" retrieval_results = retriever_engine.retrieve(query_str)\n",
"\n",
" retrieved_image = []\n",
" retrieved_text = []\n",
" for res_node in retrieval_results:\n",
" if isinstance(res_node.node, ImageNode):\n",
" retrieved_image.append(res_node.node.metadata[\"file_path\"])\n",
" else:\n",
" display_source_node(res_node, source_length=200)\n",
" retrieved_text.append(res_node.text)\n",
"\n",
" return retrieved_image, retrieved_text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LZHW-10jwEla"
},
"outputs": [],
"source": [
"query=\"can you tell me what is linear regression? explain equation of the multiple linear regression?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 98
},
"id": "byH2Aq95wK1B",
"outputId": "048af396-0548-4ae2-ccb6-cfc00751a975"
},
"outputs": [],
"source": [
"img,text=retrieve(retriever_engine,query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "HnCjdTmnwSVJ"
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"def plot_images(images_path):\n",
" images_shown = 0\n",
" plt.figure(figsize=(16, 9))\n",
" for img_path in images_path:\n",
" if os.path.isfile(img_path):\n",
" image = Image.open(img_path)\n",
"\n",
" plt.subplot(2, 3, images_shown + 1)\n",
" plt.imshow(image)\n",
" plt.xticks([])\n",
" plt.yticks([])\n",
"\n",
" images_shown += 1\n",
" if images_shown >= 5:\n",
" break"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 532
},
"id": "ovyDQLk-wkcS",
"outputId": "12fd36b6-c601-4f0b-e306-69d441fb3b31"
},
"outputs": [],
"source": [
"plot_images(img)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "97bGd7wcyKTZ"
},
"outputs": [],
"source": [
"qa_tmpl_str=(\n",
" \"Based on the provided information, including relevant images and retrieved context from the video, \\\n",
" accurately and precisely answer the query without any additional prior knowledge.\\n\"\n",
"\n",
" \"---------------------\\n\"\n",
" \"Context: {context_str}\\n\"\n",
" \"Metadata for video: {metadata_str} \\n\"\n",
"\n",
" \"---------------------\\n\"\n",
" \"Query: {query_str}\\n\"\n",
" \"Answer: \"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fYVgHILHy5-X",
"outputId": "81c6e61e-9acb-4942-87bb-06dea9d0f0aa"
},
"outputs": [],
"source": [
"img"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "P-oEG3Q2zC0F"
},
"outputs": [],
"source": [
"import json\n",
"metadata_str=json.dumps(metadata_vid)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "MrgFXHJIy_XU"
},
"outputs": [],
"source": [
"query_str=\"can you tell me what is linear regression and equation of linear regression?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "6VC4mg79yuMZ"
},
"outputs": [],
"source": [
"context_str = \"\".join(text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tNyOcu2fywnO"
},
"outputs": [],
"source": [
"image_documents = SimpleDirectoryReader( input_files=img).load_data()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IUGGglIMwtHB"
},
"outputs": [],
"source": [
"from llama_index.multi_modal_llms.openai import OpenAIMultiModal"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qRrclz5dxlaj"
},
"outputs": [],
"source": [
"openai_mm_llm = OpenAIMultiModal(model=\"gpt-4-vision-preview\", api_key=OPENAI_API_TOKEN, max_new_tokens=1500)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UdzMuacuyWMR"
},
"outputs": [],
"source": [
"result=openai_mm_llm.complete(\n",
" prompt=qa_tmpl_str.format(\n",
" query_str=query_str,metadata_str=metadata_str\n",
" ),\n",
" image_documents=image_documents,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "2PGjzok8zKDS",
"outputId": "039f8566-0095-4095-bd9c-1e261e2d359c"
},
"outputs": [],
"source": [
"pprint(result.text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "t8Y8VyRbzYuB"
},
"outputs": [],
"source": [
"qa_tmpl_str=(\n",
" \"Based on the provided information, including relevant images and retrieved context from the video, \\\n",
" accurately and precisely answer the query without any additional prior knowledge.\\n\"\n",
"\n",
" \"---------------------\\n\"\n",
" \"Metadata for video: {metadata_str} \\n\"\n",
"\n",
" \"---------------------\\n\"\n",
" \"Query: {query_str}\\n\"\n",
" \"Answer: \"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "X24-KE-UznCS"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: MultiModal RAG/Multimodal_RAG_with_Gemini_Langchain_and_Google_AI_Studio_Yt.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "oysa0lp3Ym1j",
"outputId": "1b53e723-22b5-49f6-e57a-8aa1488caeda"
},
"outputs": [],
"source": [
"%pip install --upgrade langchain langchain-google-genai \"langchain[docarray]\" faiss-cpu pypdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SuBM06ben3nZ"
},
"outputs": [],
"source": [
"import os\n",
"import requests\n",
"from PIL import Image"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5wkdBia9oMKh"
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import matplotlib.image as mpimg\n",
"from IPython.display import display, Markdown"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NYdyB53coS2E"
},
"outputs": [],
"source": [
"from langchain_google_genai import ChatGoogleGenerativeAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kRbG38lzoVyk"
},
"outputs": [],
"source": [
"from langchain_core.messages import HumanMessage, SystemMessage"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JN7UyGProXxS"
},
"outputs": [],
"source": [
"from langchain.vectorstores import DocArrayInMemorySearch"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Y65k-jUioZcD"
},
"outputs": [],
"source": [
"from langchain_google_genai import GoogleGenerativeAIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YAxMXEaloP5J"
},
"outputs": [],
"source": [
"from langchain_core.output_parsers import StrOutputParser\n",
"from langchain_core.prompts import ChatPromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cIwDydB5obpB"
},
"outputs": [],
"source": [
"from langchain.schema.document import Document\n",
"from langchain_community.document_loaders import TextLoader"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hp2OWo5Ooe9Y"
},
"outputs": [],
"source": [
"from langchain_text_splitters import CharacterTextSplitter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qLxSPRlMog3S"
},
"outputs": [],
"source": [
"from langchain_community.vectorstores import FAISS"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "DPMkR5BloiiB"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')\n",
"os.environ[\"GOOGLE_API_KEY\"] = GOOGLE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "v6dATsOFo0VJ"
},
"outputs": [],
"source": [
"def load_model(model_name):\n",
" if model_name==\"gemini-pro\":\n",
" llm = ChatGoogleGenerativeAI(model=\"gemini-pro\")\n",
" else:\n",
" llm=ChatGoogleGenerativeAI(model=\"gemini-pro-vision\")\n",
"\n",
" return llm\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "67oGZQvHo7tC"
},
"outputs": [],
"source": [
"model_text=load_model(\"gemini-pro\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "q1WmHYc4pB1Y",
"outputId": "832a2680-253d-46c4-b5a2-12c54578717c"
},
"outputs": [],
"source": [
"model_text.invoke(\"please come up with the best funny line.\").content"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 92
},
"id": "0b2Ycj8ypNGi",
"outputId": "11776336-3cd8-4966-fd0a-3df0d279a5ac"
},
"outputs": [],
"source": [
"model_text(\n",
" [\n",
" HumanMessage(content=\"Answer with Simple 'Yes' or 'No'. Question: Is apple a Fruit?\")\n",
" ]\n",
").content"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Xa1fVCCBplBR"
},
"outputs": [],
"source": [
"def get_image(url,filename,extension):\n",
" content = requests.get(url).content\n",
" with open(f'/content/{filename}.{extension}', 'wb') as f:\n",
" f.write(content)\n",
" image = Image.open(f\"/content/{filename}.{extension}\")\n",
" image.show()\n",
" return image\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RgHHEYjjp206"
},
"outputs": [],
"source": [
"image = get_image(\"https://static.nike.com/a/images/t_PDP_1728_v1/f_auto,q_auto:eco/1705ca64-fbc8-4b79-a451-4ab77760c219/dunk-low-older-shoes-C7T1cx.png\",\n",
" \"nike-shoes\",\n",
" \"png\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 435
},
"id": "0EhD9Lbjp7AS",
"outputId": "feca7266-a48c-465a-c052-2df87d7a65b5"
},
"outputs": [],
"source": [
"plt.imshow(image)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "g8GURmtIqAzJ"
},
"outputs": [],
"source": [
"vision_model=load_model(\"gemini-pro-vision\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "sZVlrxYLqsNI"
},
"outputs": [],
"source": [
"prompt=\"give me summary of this image in 5 words\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zJ116KMkqSfU"
},
"outputs": [],
"source": [
"message= HumanMessage(\n",
" content=[\n",
" {\n",
" \"type\": \"text\",\n",
" \"text\": prompt,\n",
" },\n",
" {\n",
"\n",
" \"type\": \"image_url\", \"image_url\": image\n",
" }\n",
" ]\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "UaIyYPpPqN8h",
"outputId": "92430ddc-b902-42b2-b41a-6813faa0fa7b"
},
"outputs": [],
"source": [
"print(vision_model.invoke([message]).content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Ttdz3y0pqcAy",
"outputId": "13c867fe-0fec-4894-c380-aa3be708503d"
},
"outputs": [],
"source": [
"loader = TextLoader(\"/content/nike_shoes.txt\")\n",
"print(loader.load()[0].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Pw2Ibaver5iu"
},
"outputs": [],
"source": [
"text=loader.load()[0].page_content"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fehnPFPGrnzJ"
},
"outputs": [],
"source": [
"def get_text_chunks_langchain(text):\n",
" text_splitter = CharacterTextSplitter(chunk_size=20, chunk_overlap=10)\n",
" docs = [Document(page_content=x) for x in text_splitter.split_text(text)]\n",
" return docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "-uu45AFvrwex",
"outputId": "465fd0e3-a652-4fe7-a1ec-505cb431accf"
},
"outputs": [],
"source": [
"docs = get_text_chunks_langchain(text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "rPmyFEBKr31r"
},
"outputs": [],
"source": [
"embeddings = GoogleGenerativeAIEmbeddings(model=\"models/embedding-001\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "yi3NMD0pr_yI"
},
"outputs": [],
"source": [
"vectorstore = FAISS.from_documents(docs,embedding=embeddings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "taarsyO-sBXB"
},
"outputs": [],
"source": [
"retriever=vectorstore.as_retriever()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fEW4gvOlsJAQ",
"outputId": "ad430ac0-560e-4d8a-eb41-94830784a781"
},
"outputs": [],
"source": [
"retriever.invoke(\"Nike slide/sandal.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lHaUxE20sM0x"
},
"outputs": [],
"source": [
"from langchain_core.runnables import RunnableLambda, RunnablePassthrough"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "984WtM2AsRnh"
},
"outputs": [],
"source": [
"llm_vision = load_model(\"gemini-pro-vision\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5uVuoC4qsq3M"
},
"outputs": [],
"source": [
"llm_text = load_model(\"gemini-pro\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "FovmYztwsVPh"
},
"outputs": [],
"source": [
"template = \"\"\"\n",
"```\n",
"{context}\n",
"```\n",
"\n",
"{query}\n",
"\n",
"\n",
"Provide brief information and store location.\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cF2y5fvUseFB"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_template(template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LummLlRtsf3p"
},
"outputs": [],
"source": [
"rag_chain = (\n",
" {\"context\": retriever, \"query\": RunnablePassthrough()}\n",
" | prompt\n",
" | llm_text\n",
" | StrOutputParser()\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IMSzYUOnsu0q"
},
"outputs": [],
"source": [
"result = rag_chain.invoke(\"can you give me a detail of nike sandal?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 186
},
"id": "_uOV4g31s03y",
"outputId": "703092ad-09fa-4cbd-8d93-d7ec793fc003"
},
"outputs": [],
"source": [
"display(Markdown(result))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "S0NCym1_tMMM",
"outputId": "1ed205c5-15be-47d2-e35a-e3ec5f007020"
},
"outputs": [],
"source": [
"rag_chain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "US0kn6zFs63Z"
},
"outputs": [],
"source": [
"full_chain = (\n",
" RunnablePassthrough() | llm_vision | StrOutputParser() | rag_chain\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qlIS7wlatPlo"
},
"outputs": [],
"source": [
"full_chain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lXZuKCq0tVOk"
},
"outputs": [],
"source": [
"url_1 = \"https://static.nike.com/a/images/t_PDP_1728_v1/f_auto,q_auto:eco/252f2db6-d426-4931-80a0-8b7f8f875536/calm-slides-K7mr3W.png\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_mERPfRjtWYZ"
},
"outputs": [],
"source": [
"image = get_image(url_1, \"nike3\", \"png\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 435
},
"id": "WBsa4tEjtYv5",
"outputId": "828138f0-8433-4310-9e8c-2a52b90cd99e"
},
"outputs": [],
"source": [
"plt.imshow(image)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3-kXDQdVtaMZ"
},
"outputs": [],
"source": [
"message = HumanMessage(\n",
" content=[\n",
" {\n",
" \"type\": \"text\",\n",
" \"text\": \"Provide information on given sandle image Brand and model.\",\n",
" }, # You can optionally provide text parts\n",
" {\"type\": \"image_url\", \"image_url\": image},\n",
" ]\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "exYSFX8Vtkym"
},
"outputs": [],
"source": [
"result = full_chain.invoke([message])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 139
},
"id": "JM5HWElVtlxV",
"outputId": "42d96e3b-5159-4388-8c70-8658a109b3c6"
},
"outputs": [],
"source": [
"display(Markdown(result))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4VdTbmHXtwuB"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: MultiModal RAG with Vertex AI/MultiModal RAG using Vertex AI AstraDB(Cassandra) & Langchain.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"id": "0",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"id": "1",
"metadata": {
"id": "Su9UaTllPPyT"
},
"source": [
"## Install Vertex AI SDK for Python"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 845
},
"id": "sp5rXuilbYyz1ue2BFuSmJle",
"outputId": "05bca8b5-a950-4817-fe9d-72c495126451",
"tags": []
},
"outputs": [],
"source": [
"!pip install --upgrade --user google-cloud-aiplatform"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "DCoTFxquXd3m",
"outputId": "97a836c7-7321-47f2-8850-57dd0709ad98"
},
"outputs": [],
"source": [
"!pip install ragstack-ai"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {
"id": "xh6SW67NmMaj"
},
"outputs": [],
"source": [
"PROJECT_ID = \"red-delight-346705\"\n",
"LOCATION = \"us-central1\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 70
},
"id": "QiyrYIBKnElp",
"outputId": "5f506fc5-2cb2-41df-cac4-7a7d8d260438"
},
"outputs": [],
"source": [
"ASTRA_DB_API_ENDPOINT=\"https://79b63042-b3d1-4163-b10a-75c9979ebf59-us-east-2.apps.astra.datastax.com\"\n",
"ASTRA_DB_APPLICATION_TOKEN=\"ASTRA_TOKEN_REMOVEDqtZxIFJmAWgJLKMBHsbvAzjb:66d4ef1337add84bdf44d90afac64a0f2d7d04899249d30e7038fe404c45687f\"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lKXWCbjHydhC",
"outputId": "1849aa94-63dd-4438-8fdc-82c1158234a6"
},
"outputs": [],
"source": [
"import getpass, os, requests\n",
"\n",
"if \"GCP_PROJECT_ID\" not in os.environ:\n",
" os.environ[\"GCP_PROJECT_ID\"] = getpass.getpass(\"Provide your GCP Project ID\")\n",
"\n",
"if \"LOCATION\" not in os.environ:\n",
" os.environ[\"LOCATION\"] = getpass.getpass(\"Provide your GCP Location\")\n",
"\n",
"if \"ASTRA_DB_ENDPOINT\" not in os.environ:\n",
" os.environ[\"ASTRA_DB_ENDPOINT\"] = getpass.getpass(\"Provide your Astra DB Endpoint\")\n",
"\n",
"if \"ASTRA_DB_TOKEN\" not in os.environ:\n",
" os.environ[\"ASTRA_DB_TOKEN\"] = getpass.getpass(\"Provide your Astra DB Token\")"
]
},
{
"cell_type": "markdown",
"id": "7",
"metadata": {
"id": "mO8cqwwwRIJv"
},
"source": [
"## Authenticate your notebook environment ( Colab only )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xCh2oo_LYFxf",
"outputId": "3d586ed2-30bd-40dd-ab77-d80cce5c15ec"
},
"outputs": [],
"source": [
"!gcloud config set project {os.getenv(\"GCP_PROJECT_ID\")}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9",
"metadata": {
"id": "BWflD-lzRFgC"
},
"outputs": [],
"source": [
"import sys\n",
"\n",
"# Additional authentication is required for Google Colab\n",
"if \"google.colab\" in sys.modules:\n",
" # Authenticate user to Google Cloud\n",
" from google.colab import auth\n",
"\n",
" auth.authenticate_user()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MpyaRy-JXqYx",
"outputId": "b59285fb-ef6f-4230-8c73-8f59adcc585a"
},
"outputs": [],
"source": [
"!gcloud auth list"
]
},
{
"cell_type": "markdown",
"id": "11",
"metadata": {
"id": "Ef3YjVSsRp9Q"
},
"source": [
"## Set Google Cloud project information and initialize Vertex AI SDK"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12",
"metadata": {
"id": "C8iMCMkeYgGT"
},
"outputs": [],
"source": [
"# Define project information\n",
"PROJECT_ID=os.getenv(\"GCP_PROJECT_ID\")\n",
"LOCATION=os.getenv(\"LOCATION\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
"metadata": {
"id": "G1MCN16ZRFR3"
},
"outputs": [],
"source": [
"# Initialize Vertex AI\n",
"import vertexai\n",
"\n",
"vertexai.init(project=PROJECT_ID, location=LOCATION)"
]
},
{
"cell_type": "markdown",
"id": "14",
"metadata": {
"id": "KOBAtIV3R8mY"
},
"source": [
"## Import libraries"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15",
"metadata": {
"id": "lXlozq1mQThR"
},
"outputs": [],
"source": [
"from vertexai.preview.generative_models import (\n",
" GenerationConfig,\n",
" GenerativeModel,\n",
" HarmCategory,\n",
" HarmBlockThreshold,\n",
" Image,\n",
" Part\n",
")"
]
},
{
"cell_type": "markdown",
"id": "16",
"metadata": {
"id": "Pyza6kJuSCg_"
},
"source": [
"## Use the Gemini 1.0 Pro model\n",
"\n",
"The Gemini 1.0 Pro (`gemini-1.0-pro`) model is designed to handle natural language tasks, multi-turn text and code chat, and code generation.\n"
]
},
{
"cell_type": "markdown",
"id": "17",
"metadata": {
"id": "teZPcNCISLkQ"
},
"source": [
"## Load the Gemini 1.0 Pro model"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18",
"metadata": {
"id": "kUB8nEGhQXMH"
},
"outputs": [],
"source": [
"model = GenerativeModel(\"gemini-1.0-pro\")"
]
},
{
"cell_type": "markdown",
"id": "19",
"metadata": {
"id": "soDP_1kmSTSn"
},
"source": [
"## Generate text from text prompts"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "20",
"metadata": {
"id": "cvWMgCTZntYK"
},
"outputs": [],
"source": [
"responses = model.generate_content(\"Why is the sky blue?\", stream=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xuwrxROoSESn",
"outputId": "f3ad777a-13dc-499e-cc23-e899e39456ec"
},
"outputs": [],
"source": [
"for response in responses:\n",
" print(response.text, end=\"\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "22",
"metadata": {
"id": "yYfeGQzMn0E4"
},
"outputs": [],
"source": [
"prompt = \"\"\"Create a numbered list of 10 items. Each item in the list should be a trend in the tech industry.\n",
"\n",
"Each trend should be less than 5 words.\"\"\" # try your own prompt\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23",
"metadata": {
"id": "F2FOUPIfn4jp"
},
"outputs": [],
"source": [
"responses = model.generate_content(prompt, stream=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "24",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "yhtHW2wySENe",
"outputId": "adf3ffdc-b7ca-4a73-c61d-6ce28279d22d"
},
"outputs": [],
"source": [
"for response in responses:\n",
" print(response.text, end=\"\")"
]
},
{
"cell_type": "markdown",
"id": "25",
"metadata": {
"id": "lmoUexYKTFmj"
},
"source": [
"## Model parameters\n",
"\n",
"Every prompt you send to the model includes parameter values that control how the model generates a response. The model can generate different results for different parameter values. You can experiment with different model parameters to see how the results change."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "26",
"metadata": {
"id": "-96LHeIVoDVw"
},
"outputs": [],
"source": [
"generation_config = GenerationConfig(\n",
" temperature=0.9,\n",
" top_p=1.0,\n",
" top_k=32,\n",
" candidate_count=1,\n",
" max_output_tokens=8192,\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "27",
"metadata": {
"id": "9CyRucFooHMH"
},
"outputs": [],
"source": [
"responses = model.generate_content(\n",
" \"Why is the sky blue?\",\n",
" generation_config=generation_config,\n",
" stream=True,\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "28",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "q4C71eAFSEK3",
"outputId": "a5e31697-a5f8-423b-e35e-3ddfafab0993"
},
"outputs": [],
"source": [
"for response in responses:\n",
" print(response.text, end=\"\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "29",
"metadata": {
"id": "UxflQ0mWoZcu"
},
"outputs": [],
"source": [
"source_img_data = requests.get('https://drive.google.com/uc?export=view&id=15ddcn-AIxpvRdWcFGvIr77XLWdo4Maof').content"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "30",
"metadata": {
"id": "G2SNnO7JYtlu"
},
"outputs": [],
"source": [
"with open('coffee_maker_part.png', 'wb') as handler:\n",
" handler.write(source_img_data)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "31",
"metadata": {
"id": "lYAFQWLFurTf"
},
"outputs": [],
"source": [
"from langchain_google_vertexai import ChatVertexAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "32",
"metadata": {
"id": "h4_Cd_QP13jh"
},
"outputs": [],
"source": [
"from langchain.schema.messages import HumanMessage\n",
"from PIL import Image, ImageFile\n",
"import os, sys\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "33",
"metadata": {
"id": "Q5-GXhql2amH"
},
"outputs": [],
"source": [
"chat = ChatVertexAI(model_name=\"gemini-1.0-pro-vision\",safety_settings={\n",
" HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE\n",
" },)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "34",
"metadata": {
"id": "-5a4W_Os2iUo"
},
"outputs": [],
"source": [
"image_message = {\n",
" \"type\": \"image_url\",\n",
" \"image_url\": {\"url\": \"coffee_maker_part.png\"},\n",
"}\n",
"text_message = {\n",
" \"type\": \"text\",\n",
" \"text\": \"What is this image? Share a link to purchase a replacement\",\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "35",
"metadata": {
"id": "d3_y9HUppFS3"
},
"outputs": [],
"source": [
"message = HumanMessage(content=[text_message, image_message])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RO10SiFzpLX5",
"outputId": "6ef1c5c2-33a6-4f28-c30d-1332d3379599"
},
"outputs": [],
"source": [
"output = chat([message])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "37",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8i96veBrYwim",
"outputId": "b90ee03e-51cf-4dac-d8e8-08971cbae5fd"
},
"outputs": [],
"source": [
"print(output.content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 780
},
"id": "s0kOfknRY20q",
"outputId": "98be1d6b-9791-4743-88c3-72193503d3a6"
},
"outputs": [],
"source": [
"import pandas as pd\n",
"\n",
"d = {'name': [\"Saucer\", \"Saucer Ceramic\", \"Milk Jug Assembly\", \"Handle Steam Wand Kit (New Version From 0735 PDC)\", \"Spout Juice Small (From 0637 to 1041 PDC)\", \"Cleaning Steam Wand\", \"Jug Frothing\", \"Spoon Tamping 50mm\", \"Collar Grouphead 50mm\", \"Filter 2 Cup Dual Wall 50mm\", \"Filter 1 Cup 50mm\", \"Water Tank Assembly\", \"Portafilter Assembly 50mm\", \"Milk Jug Assembly\", \"Filter 2 Cup 50mm\" ],\n",
" 'url': [\"https://www.breville.com/us/en/parts-accessories/parts/sp0014946.html?sku=SP0014946\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0014914.html?sku=SP0014914\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0011391.html?sku=SP0011391\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0010719.html?sku=SP0010719\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0010718.html?sku=SP0010718\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003247.html?sku=SP0003247\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003246.html?sku=SP0003246\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003243.html?sku=SP0003243\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003232.html?sku=SP0003232\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003231.html?sku=SP0003231\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003230.html?sku=SP0003230\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003225.html?sku=SP0003225\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0003216.html?sku=SP0003216\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0001875.html?sku=SP0001875\", \"https://www.breville.com/us/en/parts-accessories/parts/sp0000166.html?sku=SP0000166\"],\n",
" 'price': [\"10.95\", \"4.99\", \"14.95\", \"8.95\", \"10.95\", \"6.95\", \"24.95\", \"8.95\", \"6.95\", \"12.95\", \"12.95\", \"14.95\", \"10.95\", \"16.95\", \"11.95\"],\n",
" 'image': [\"https://www.breville.com/content/dam/breville/us/catalog/products/images/sp0/sp0014946/tile.jpg\", \"https://www.breville.com/content/dam/breville/us/catalog/products/images/sp0/sp0014914/tile.jpg\", \"https://www.breville.com/content/dam/breville/us/catalog/products/images/sp0/sp0011391/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0010719/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0010718/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0003247/tile.jpg\", \"https://assets.breville.com/cdn-cgi/image/width=400,format=auto/Spare+Parts+/Espresso+Machines/BES250/SP0003246/SP0003246_IMAGE1_400X400.jpg\", \"https://assets.breville.com/cdn-cgi/image/width=400,format=auto/Spare+Parts+/Espresso+Machines/ESP8/SP0003243/SP0003243_IMAGE1_400X400.jpg\", \"https://assets.breville.com/cdn-cgi/image/width=400,format=auto/Spare+Parts+/Espresso+Machines/ESP8/SP0003232/SP0003232_IMAGE1_400x400.jpg\", \"https://www.breville.com/content/dam/breville/au/catalog/products/images/sp0/sp0003231/tile.jpg\", \"https://www.breville.com/content/dam/breville/au/catalog/products/images/sp0/sp0003230/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0003225/tile.jpg\", \"https://www.breville.com/content/dam/breville/ca/catalog/products/images/sp0/sp0003216/tile.jpg\", \"https://www.breville.com/content/dam/breville/au/catalog/products/images/sp0/sp0001875/tile.jpg\", \"https://www.breville.com/content/dam/breville/us/catalog/products/images/sp0/sp0000166/tile.jpg\"]}\n",
"df = pd.DataFrame(data=d)\n",
"df"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39",
"metadata": {
"id": "2fcMmT6x2_Fu"
},
"outputs": [],
"source": [
"import vertexai, json, requests\n",
"from vertexai.preview.vision_models import MultiModalEmbeddingModel, Image\n",
"from astrapy.db import AstraDB, AstraDBCollection\n",
"from google.colab import files"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "40",
"metadata": {
"id": "c5RNXJmb3BVw"
},
"outputs": [],
"source": [
"model = MultiModalEmbeddingModel.from_pretrained(\"multimodalembedding@001\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41",
"metadata": {
"id": "MmAw9Z8D3EYM"
},
"outputs": [],
"source": [
"# Initialize our vector db\n",
"astra_db = AstraDB(token=os.getenv(\"ASTRA_DB_TOKEN\"), api_endpoint=os.getenv(\"ASTRA_DB_ENDPOINT\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "42",
"metadata": {
"id": "rGf8tmF23Gxc"
},
"outputs": [],
"source": [
"collection = astra_db.create_collection(collection_name=\"coffee_shop_ecommerce\", dimension=1408)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "43",
"metadata": {
"id": "Qc2D1qqvY6Jy"
},
"outputs": [],
"source": [
"for i in range(len(df)):\n",
" name = df.loc[i, \"name\"]\n",
" image = df.loc[i, \"image\"]\n",
" price = df.loc[i, \"price\"]\n",
" url = df.loc[i, \"url\"]\n",
"\n",
" # Download this product's image and save it to the Colab filesystem.\n",
" # In a production system this binary data would be stored in Google Cloud Storage\n",
" img_data = requests.get(image).content\n",
" with open(f'{name}.png', 'wb') as handler:\n",
" handler.write(img_data)\n",
"\n",
" # load the image from filesystem and compute the embedding value\n",
" img = Image.load_from_file(f'{name}.png')\n",
" embeddings = model.get_embeddings(image=img, contextual_text=name)\n",
"\n",
" try:\n",
" # add to the AstraDB Vector Database\n",
" collection.insert_one({\n",
" \"_id\": i,\n",
" \"name\": name,\n",
" \"image\": image,\n",
" \"url\": url,\n",
" \"price\": price,\n",
" \"$vector\": embeddings.image_embedding,\n",
" })\n",
" except Exception as error:\n",
" # if you've already added this record, skip the error message\n",
" error_info = json.loads(str(error))\n",
" if error_info[0]['errorCode'] == \"DOCUMENT_ALREADY_EXISTS\":\n",
" print(\"Document already exists in the database. Skipping.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "44",
"metadata": {
"id": "A8OALWDt4alj"
},
"outputs": [],
"source": [
"import json\n",
"\n",
"# Embed the similar item\n",
"img = Image.load_from_file('coffee_maker_part.png')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "45",
"metadata": {
"id": "FYEBo0rO3uV9"
},
"outputs": [],
"source": [
"embeddings = model.get_embeddings(image=img, contextual_text=\"A espresso machine part\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "46",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GfTqY9MKouR_",
"outputId": "582f5bfb-86ea-4b5c-9c12-db60cdffe617"
},
"outputs": [],
"source": [
"embeddings.image_embedding"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "47",
"metadata": {
"id": "UE6SRN1t3wEv"
},
"outputs": [],
"source": [
"# Perform the vector search against AstraDB Vector\n",
"documents = collection.vector_find(\n",
" embeddings.image_embedding,\n",
" limit=3,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "48",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5rhq7QNQrM-f",
"outputId": "97790f82-3584-4cb1-f482-444f07f93609"
},
"outputs": [],
"source": [
"documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "49",
"metadata": {
"id": "4eTwAQKH3yD6"
},
"outputs": [],
"source": [
"related_products_csv = \"name, image, price, url\\n\"\n",
"for doc in documents:\n",
" related_products_csv += f\"{doc['name']}, {doc['image']}, {doc['price']}, {doc['url']},\\n\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "50",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "T-A4o7wIrmTj",
"outputId": "020b73b5-5520-4c00-92b0-af67b6d83f55"
},
"outputs": [],
"source": [
"print(related_products_csv)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "51",
"metadata": {
"id": "Li-fX8pz30kz"
},
"outputs": [],
"source": [
"image_message = {\n",
" \"type\": \"image_url\",\n",
" \"image_url\": {\"url\": \"/content/coffee_maker_part.png\"},\n",
"}\n",
"text_message = {\n",
" \"type\": \"text\",\n",
" \"text\": f\"What we have in this image? Share the URL and price to purchase a replacement. Here are related products {related_products_csv}\",\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "52",
"metadata": {
"id": "57KzUhbd4B2e"
},
"outputs": [],
"source": [
"message = HumanMessage(content=[text_message, image_message])\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "53",
"metadata": {
"id": "Q7_Ktwg7tBTR"
},
"outputs": [],
"source": [
"chat = ChatVertexAI(model_name=\"gemini-1.0-pro-vision\",safety_settings={\n",
" HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE\n",
" },)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "54",
"metadata": {
"id": "opNLdOPw4DTk"
},
"outputs": [],
"source": [
"output = chat([message])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "55",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rUDI6iZyY-yc",
"outputId": "41ffd1bf-68eb-4a74-c78d-a2367da381a1"
},
"outputs": [],
"source": [
"print(output.content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "56",
"metadata": {
"id": "SWqUjjMMWWfH"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
================================================
FILE: Multilingual AI based Voice Assistant/.gitignore
================================================
multilingual
/.env
env
================================================
FILE: Multilingual AI based Voice Assistant/README.md
================================================
# Multilingual Assistant
# How to run?
### STEPS:
Clone the repository
```bash
Project repo: https://github.com/
```
### STEP 01- Create a conda environment after opening the repository
```bash
conda create -n llmapp python=3.8 -y
```
```bash
conda activate llmapp
```
### STEP 02- install the requirements
```bash
pip install -r requirements.txt
```
### Create a `.env` file in the root directory and add your GOOGLE_API_KEY credentials as follows:
```ini
GOOGLE_API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```
```bash
# Finally run the following command
streamlit run app.py
```
Now,
```bash
open up localhost:
```
### Techstack Used:
- Python
- Google API
- Streamlit
- PaLM2
- s2t
- t2s
================================================
FILE: Multilingual AI based Voice Assistant/app.py
================================================
import streamlit as st
from src.helper import voice_input, llm_model_object, text_to_speech
def main():
st.title("Multilingual AI Assistant 🤖")
if st.button("Ask me anything"):
with st.spinner("Listening..."):
text=voice_input()
response=llm_model_object(text)
text_to_speech(response)
audio_file=open("speech.mp3","rb")
audio_bytes=audio_file.read()
st.text_area(label="Response:",value=response,height=350)
st.audio(audio_bytes)
st.download_button(label="Download Speech",
data=audio_bytes,
file_name="speech.mp3",
mime="audio/mp3")
if __name__=='__main__':
main()
================================================
FILE: Multilingual AI based Voice Assistant/genai_AI_Project.egg-info/PKG-INFO
================================================
Metadata-Version: 2.1
Name: genai-AI-Project
Version: 0.0.0
Author: sunny savita
Author-email: sunnysavita@gmail.com
================================================
FILE: Multilingual AI based Voice Assistant/genai_AI_Project.egg-info/SOURCES.txt
================================================
setup.py
genai_AI_Project.egg-info/PKG-INFO
genai_AI_Project.egg-info/SOURCES.txt
genai_AI_Project.egg-info/dependency_links.txt
genai_AI_Project.egg-info/top_level.txt
src/__init__.py
src/helper.py
================================================
FILE: Multilingual AI based Voice Assistant/genai_AI_Project.egg-info/dependency_links.txt
================================================
================================================
FILE: Multilingual AI based Voice Assistant/genai_AI_Project.egg-info/top_level.txt
================================================
src
================================================
FILE: Multilingual AI based Voice Assistant/multilingual_assistant.egg-info/PKG-INFO
================================================
Metadata-Version: 2.1
Name: multilingual-assistant
Version: 0.0.1
Author: sunny
Author-email: sunny.savita@ineuron.ai
Requires-Dist: SpeechRecognition
Requires-Dist: pipwin
Requires-Dist: pyaudio
Requires-Dist: gTTS
Requires-Dist: google-generativeai
Requires-Dist: python-dotenv
Requires-Dist: streamlit
================================================
FILE: Multilingual AI based Voice Assistant/multilingual_assistant.egg-info/SOURCES.txt
================================================
README.md
setup.py
multilingual_assistant.egg-info/PKG-INFO
multilingual_assistant.egg-info/SOURCES.txt
multilingual_assistant.egg-info/dependency_links.txt
multilingual_assistant.egg-info/requires.txt
multilingual_assistant.egg-info/top_level.txt
src/__init__.py
src/helper.py
================================================
FILE: Multilingual AI based Voice Assistant/multilingual_assistant.egg-info/dependency_links.txt
================================================
================================================
FILE: Multilingual AI based Voice Assistant/multilingual_assistant.egg-info/requires.txt
================================================
SpeechRecognition
pipwin
pyaudio
gTTS
google-generativeai
python-dotenv
streamlit
================================================
FILE: Multilingual AI based Voice Assistant/multilingual_assistant.egg-info/top_level.txt
================================================
src
================================================
FILE: Multilingual AI based Voice Assistant/requirements.txt
================================================
SpeechRecognition
pipwin
pyaudio
gTTS
google-generativeai
python-dotenv
streamlit
-e .
================================================
FILE: Multilingual AI based Voice Assistant/research/trials.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"perfect!!\n",
"AIzaSyB5Nlw2teuugvkFSGzMyYEvTZDRFojtNF0\n"
]
}
],
"source": [
"from dotenv import load_dotenv\n",
"import os\n",
"\n",
"print(\"perfect!!\")\n",
"load_dotenv()\n",
"\n",
"GOOGLE_API_KEY=os.getenv(\"GOOGLE_API_KEY\")\n",
"print(GOOGLE_API_KEY)\n",
"os.environ[\"GOOGLE_API_KEY\"]=GOOGLE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"c:\\Users\\sunny\\Multiligual-AI-Assistant\\env\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
}
],
"source": [
"# Import the Python SDK\n",
"import google.generativeai as genai"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"genai.configure(api_key=GOOGLE_API_KEY)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"model = genai.GenerativeModel('gemini-pro')"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"In the quaint and bustling town of Willow Creek, amidst ivy-covered cottages and blooming gardens, there lived a young girl named Anya. One fateful morning, as she skipped towards the town square, her eyes widened at the sight of a peculiar display in the antique shop window. A magnificent backpack, crafted from shimmering midnight blue leather and adorned with intricate silver runes, seemed to whisper secrets to her from across the glass.\n",
"\n",
"Intrigued, Anya pushed open the door and stepped inside. The shop was a treasure trove of forgotten relics and curiosities, its shelves crammed with antique jewelry, vintage toys, and dusty tomes. As she approached the display, the backpack's runes glowed faintly, as if calling out to her.\n",
"\n",
"Hesitantly, Anya lifted the backpack from its pedestal. Instantly, a surge of warmth spread through her body, and she felt a strange connection to its enigmatic presence. She knew in that moment that this was no ordinary satchel but a vessel of ancient magic.\n",
"\n",
"As Anya made her way home, her footsteps were lighter and her spirit soared. She couldn't wait to explore the secrets hidden within her new companion. With trembling hands, she unzipped the main compartment and gasped at the sight that greeted her.\n",
"\n",
"A shimmering portal shimmered in the center of the backpack, its edges swirling with iridescent colors. Anya cautiously reached out and touched the portal, and in an instant, she was transported to a realm both familiar and utterly fantastical.\n",
"\n",
"Towering trees with emerald leaves and vines that danced in the wind surrounded her, while the air crackled with the scent of pine needles and wildflowers. A sparkling stream bubbled nearby, its waters reflecting the changing colors of the sky above.\n",
"\n",
"As Anya ventured deeper into this magical realm, she encountered creatures she had never imagined. A mischievous pixie fluttered overhead, leaving a trail of shimmering dust in its wake. A wise old owl perched on a gnarled root, its eyes twinkling with ancient wisdom.\n",
"\n",
"With each step she took, Anya discovered new wonders. A hidden waterfall cascaded into a shimmering pool, and a rainbow arced across the sky like a celestial bridge. She realized that her backpack was not merely a container but a gateway to a world of boundless possibility.\n",
"\n",
"As the sun began its descent, painting the sky in hues of gold and crimson, Anya knew it was time to return. She stepped back through the portal and found herself once more in the confines of her humble cottage.\n",
"\n",
"From that day forward, Anya's backpack became her constant companion. It held not only her school books and pencils but also the secrets of a magical realm. She carried it with her on every adventure, knowing that within its leather folds lay a treasure that would forever enrich her life.\n",
"\n",
"And so, the legend of Anya and her magic backpack passed down through generations, becoming a beloved tale whispered among the children of Willow Creek, reminding them that even in the ordinary, the extraordinary could be found.\n"
]
}
],
"source": [
"response = model.generate_content(\"Write a story about a magic backpack.\")\n",
"print(response.text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.19"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
================================================
FILE: Multilingual AI based Voice Assistant/setup.py
================================================
from setuptools import find_packages, setup
setup(
name="multilingual assistant",
version="0.0.1",
author="sunny",
author_email="sunny.savita@ineuron.ai",
packages=find_packages(),
install_requires=["SpeechRecognition","pipwin","pyaudio","gTTS","google-generativeai","python-dotenv","streamlit"]
)
================================================
FILE: Multilingual AI based Voice Assistant/src/__init__.py
================================================
================================================
FILE: Multilingual AI based Voice Assistant/src/helper.py
================================================
import speech_recognition as sr
import google.generativeai as genai
from dotenv import load_dotenv
import os
from gtts import gTTS
print("perfect!!")
load_dotenv()
GOOGLE_API_KEY=os.getenv("GOOGLE_API_KEY")
os.environ["GOOGLE_API_KEY"]=GOOGLE_API_KEY
def voice_input():
r=sr.Recognizer()
with sr.Microphone() as source:
print("listening...")
audio=r.listen(source)
try:
text=r.recognize_google(audio)
print("you said: ", text)
return text
except sr.UnknownValueError:
print("sorry, could not understand the audio")
except sr.RequestError as e:
print("could not request result from google speech recognition service: {0}".format(e))
def text_to_speech(text):
tts=gTTS(text=text, lang="en")
#save the speech from the given text in the mp3 format
tts.save("speech.mp3")
def llm_model_object(user_text):
#model = "models/gemini-pro"
genai.configure(api_key=GOOGLE_API_KEY)
model = genai.GenerativeModel('gemini-pro')
response=model.generate_content(user_text)
result=response.text
return result
================================================
FILE: Multilingual AI based Voice Assistant/template.py
================================================
import os
import logging
from pathlib import Path
logging.basicConfig(level=logging.INFO, format='[%(asctime)s]: %(message)s:')
list_of_files = [
"src/__init__.py",
"src/helper.py",
".env",
"requirements.txt",
"setup.py",
"app.py",
"research/trials.ipynb"
]
for filepath in list_of_files:
filepath = Path(filepath)
filedir, filename = os.path.split(filepath)
if filedir !="":
os.makedirs(filedir, exist_ok=True)
logging.info(f"Creating directory; {filedir} for the file: {filename}")
if (not os.path.exists(filepath)) or (os.path.getsize(filepath) == 0):
with open(filepath, "w") as f:
pass
logging.info(f"Creating empty file: {filepath}")
else:
logging.info(f"{filename} is already exists")
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Data/MLDOC.txt
================================================
What is machine learning?
Machine learning is a branch of artificial intelligence (AI) and computer science which
focuses on the use of data and algorithms to imitate the way that humans learn,
gradually improving its accuracy.
IBM has a rich history with machine learning. One of its own, Arthur Samuel, is credited
for coining the term, “machine learning” with his research (link resides outside ibm.com)
around the game of checkers. Robert Nealey, the self-proclaimed checkers master,
played the game on an IBM 7094 computer in 1962, and he lost to the computer.
Compared to what can be done today, this feat seems trivial, but it’s considered a major
milestone in the field of artificial intelligence.
Over the last couple of decades, the technological advances in storage and processing
power have enabled some innovative products based on machine learning, such as
Netflix’s recommendation engine and self-driving cars.
Machine learning is an important component of the growing field of data science.
Through the use of statistical methods, algorithms are trained to make classifications or
predictions, and to uncover key insights in data mining projects. These insights
subsequently drive decision making within applications and businesses, ideally
impacting key growth metrics. As big data continues to expand and grow, the market
demand for new data scientists will increase. They will be required to help identify the
most relevant business questions and the data to answer them.
Machine learning algorithms are typically created using frameworks such as Python that
accelerate solution development by using platforms like TensorFlow or PyTorch.
Now available: watsonx.ai
The all-new enterprise studio that brings together traditional machine learning along
with new generative AI capabilities powered by foundation models.
Try watsonx.ai
Begin your journey to AI
Learn how to scale AI
Explore the AI Academy
Machine Learning vs. Deep Learning vs. Neural Networks
Since deep learning and machine learning tend to be used interchangeably, it’s worth
noting the nuances between the two. Machine learning, deep learning, and neural
networks are all sub-fields of artificial intelligence. However, neural networks is actually
a sub-field of machine learning, and deep learning is a sub-field of neural networks.
The way in which deep learning and machine learning differ is in how each algorithm
learns. "Deep" machine learning can use labeled datasets, also known as supervised
learning, to inform its algorithm, but it doesn’t necessarily require a labeled dataset. The
deep learning process can ingest unstructured data in its raw form (e.g., text or images),
and it can automatically determine the set of features which distinguish different
categories of data from one another. This eliminates some of the human intervention
required and enables the use of large amounts of data. You can think of deep learning
as "scalable machine learning" as Lex Fridman notes in this MIT lecture (link resides
outside ibm.com).
Classical, or "non-deep," machine learning is more dependent on human intervention to
learn. Human experts determine the set of features to understand the differences
between data inputs, usually requiring more structured data to learn.
Neural networks, or artificial neural networks (ANNs), are comprised of node layers,
containing an input layer, one or more hidden layers, and an output layer. Each node, or
artificial neuron, connects to another and has an associated weight and threshold. If the
output of any individual node is above the specified threshold value, that node is
activated, sending data to the next layer of the network. Otherwise, no data is passed
along to the next layer of the network by that node. The “deep” in deep learning is just
referring to the number of layers in a neural network. A neural network that consists of
more than three layers—which would be inclusive of the input and the output—can be
considered a deep learning algorithm or a deep neural network. A neural network that
only has three layers is just a basic neural network.
Deep learning and neural networks are credited with accelerating progress in areas
such as computer vision, natural language processing, and speech recognition.
See the blog post “AI vs. Machine Learning vs. Deep Learning vs. Neural Networks:
What’s the Difference?” for a closer look at how the different concepts relate.
Related content
Explore the watsonx.ai interactive demo
Download “Machine learning for Dummies”
- This link downloads a pdf
Explore Gen AI for developers
How does machine learning work?
UC Berkeley (link resides outside ibm.com) breaks out the learning system of a
machine learning algorithm into three main parts.
A Decision Process: In general, machine learning algorithms are used to make a
prediction or classification. Based on some input data, which can be labeled or
unlabeled, your algorithm will produce an estimate about a pattern in the data.
An Error Function: An error function evaluates the prediction of the model. If
there are known examples, an error function can make a comparison to assess
the accuracy of the model.
A Model Optimization Process: If the model can fit better to the data points in the
training set, then weights are adjusted to reduce the discrepancy between the
known example and the model estimate. The algorithm will repeat this iterative
“evaluate and optimize” process, updating weights autonomously until a
threshold of accuracy has been met.
Machine learning methods
Machine learning models fall into three primary categories.
Supervised machine learning
Supervised learning, also known as supervised machine learning, is defined by its use
of labeled datasets to train algorithms to classify data or predict outcomes accurately.
As input data is fed into the model, the model adjusts its weights until it has been fitted
appropriately. This occurs as part of the cross validation process to ensure that the
model avoids overfitting or underfitting. Supervised learning helps organizations solve a
variety of real-world problems at scale, such as classifying spam in a separate folder
from your inbox. Some methods used in supervised learning include neural networks,
naïve bayes, linear regression, logistic regression, random forest, and support vector
machine (SVM).
Unsupervised machine learning
Unsupervised learning, also known as unsupervised machine learning, uses machine
learning algorithms to analyze and cluster unlabeled datasets (subsets called clusters).
These algorithms discover hidden patterns or data groupings without the need for
human intervention. This method’s ability to discover similarities and differences in
information make it ideal for exploratory data analysis, cross-selling strategies,
customer segmentation, and image and pattern recognition. It’s also used to reduce the
number of features in a model through the process of dimensionality reduction. Principal
component analysis (PCA) and singular value decomposition (SVD) are two common
approaches for this. Other algorithms used in unsupervised learning include neural
networks, k-means clustering, and probabilistic clustering methods.
Semi-supervised learning
Semi-supervised learning offers a happy medium between supervised and
unsupervised learning. During training, it uses a smaller labeled data set to guide
classification and feature extraction from a larger, unlabeled data set. Semi-supervised
learning can solve the problem of not having enough labeled data for a supervised
learning algorithm. It also helps if it’s too costly to label enough data.
For a deep dive into the differences between these approaches, check out "Supervised
vs. Unsupervised Learning: What's the Difference?"
Reinforcement machine learning
Reinforcement machine learning is a machine learning model that is similar to
supervised learning, but the algorithm isn’t trained using sample data. This model learns
as it goes by using trial and error. A sequence of successful outcomes will be reinforced
to develop the best recommendation or policy for a given problem.
The IBM Watson® system that won the Jeopardy! challenge in 2011 is a good example.
The system used reinforcement learning to learn when to attempt an answer (or
question, as it were), which square to select on the board, and how much to
wager—especially on daily doubles.
Learn more about reinforcement learning
Common machine learning algorithms
A number of machine learning algorithms are commonly used. These include:
Neural networks: Neural networks simulate the way the human brain works, with
a huge number of linked processing nodes. Neural networks are good at
recognizing patterns and play an important role in applications including natural
language translation, image recognition, speech recognition, and image creation.
Linear regression: This algorithm is used to predict numerical values, based on a
linear relationship between different values. For example, the technique could be
used to predict house prices based on historical data for the area.
Logistic regression: This supervised learning algorithm makes predictions for
categorical response variables, such as “yes/no” answers to questions. It can be
used for applications such as classifying spam and quality control on a
production line.
Clustering: Using unsupervised learning, clustering algorithms can identify
patterns in data so that it can be grouped. Computers can help data scientists by
identifying differences between data items that humans have overlooked.
Decision trees: Decision trees can be used for both predicting numerical values
(regression) and classifying data into categories. Decision trees use a branching
sequence of linked decisions that can be represented with a tree diagram. One of
the advantages of decision trees is that they are easy to validate and audit,
unlike the black box of the neural network.
Random forests: In a random forest, the machine learning algorithm predicts a
value or category by combining the results from a number of decision trees.
Advantages and disadvantages of machine learning algorithms
Depending on your budget, need for speed and precision required, each algorithm
type—supervised, unsupervised, semi-supervised, or reinforcement—has its own
advantages and disadvantages. For example, decision tree algorithms are used for both
predicting numerical values (regression problems) and classifying data into categories.
Decision trees use a branching sequence of linked decisions that may be represented
with a tree diagram. A prime advantage of decision trees is that they are easier to
validate and audit than a neural network. The bad news is that they can be more
unstable than other decision predictors.
Overall, there are many advantages to machine learning that businesses can leverage
for new efficiencies. These include machine learning identifying patterns and trends in
massive volumes of data that humans might not spot at all. And this analysis requires
little human intervention: just feed in the dataset of interest and let the machine learning
system assemble and refine its own algorithms—which will continually improve with
more data input over time. Customers and users can enjoy a more personalized
experience as the model learns more with every experience with that person.
On the downside, machine learning requires large training datasets that are accurate
and unbiased. GIGO is the operative factor: garbage in / garbage out. Gathering
sufficient data and having a system robust enough to run it might also be a drain on
resources. Machine learning can also be prone to error, depending on the input. With
too small a sample, the system could produce a perfectly logical algorithm that is
completely wrong or misleading. To avoid wasting budget or displeasing customers,
organizations should act on the answers only when there is high confidence in the
output.
Real-world machine learning use cases
Here are just a few examples of machine learning you might encounter every day:
Speech recognition: It is also known as automatic speech recognition (ASR), computer
speech recognition, or speech-to-text, and it is a capability which uses natural language
processing (NLP) to translate human speech into a written format. Many mobile devices
incorporate speech recognition into their systems to conduct voice search—e.g. Siri—or
improve accessibility for texting.
Customer service: Online chatbots are replacing human agents along the customer
journey, changing the way we think about customer engagement across websites and
social media platforms. Chatbots answer frequently asked questions (FAQs) about
topics such as shipping, or provide personalized advice, cross-selling products or
suggesting sizes for users. Examples include virtual agents on e-commerce sites;
messaging bots, using Slack and Facebook Messenger; and tasks usually done by
virtual assistants and voice assistants.
Computer vision: This AI technology enables computers to derive meaningful
information from digital images, videos, and other visual inputs, and then take the
appropriate action. Powered by convolutional neural networks, computer vision has
applications in photo tagging on social media, radiology imaging in healthcare, and
self-driving cars in the automotive industry.
Recommendation engines: Using past consumption behavior data, AI algorithms can
help to discover data trends that can be used to develop more effective cross-selling
strategies. Recommendation engines are used by online retailers to make relevant
product recommendations to customers during the checkout process.
Robotic process automation (RPA): Also known as software robotics, RPA uses
intelligent automation technologies to perform repetitive manual tasks.
Automated stock trading: Designed to optimize stock portfolios, AI-driven
high-frequency trading platforms make thousands or even millions of trades per day
without human intervention.
Fraud detection: Banks and other financial institutions can use machine learning to spot
suspicious transactions. Supervised learning can train a model using information about
known fraudulent transactions. Anomaly detection can identify transactions that look
atypical and deserve further investigation.
Challenges of machine learning
As machine learning technology has developed, it has certainly made our lives easier.
However, implementing machine learning in businesses has also raised a number of
ethical concerns about AI technologies. Some of these include:
Technological singularity
While this topic garners a lot of public attention, many researchers are not concerned
with the idea of AI surpassing human intelligence in the near future. Technological
singularity is also referred to as strong AI or superintelligence. Philosopher Nick
Bostrum defines superintelligence as “any intellect that vastly outperforms the best
human brains in practically every field, including scientific creativity, general wisdom,
and social skills.” Despite the fact that superintelligence is not imminent in society, the
idea of it raises some interesting questions as we consider the use of autonomous
systems, like self-driving cars. It’s unrealistic to think that a driverless car would never
have an accident, but who is responsible and liable under those circumstances? Should
we still develop autonomous vehicles, or do we limit this technology to
semi-autonomous vehicles which help people drive safely? The jury is still out on this,
but these are the types of ethical debates that are occurring as new, innovative AI
technology develops.
AI impact on jobs
While a lot of public perception of artificial intelligence centers around job losses, this
concern should probably be reframed. With every disruptive, new technology, we see
that the market demand for specific job roles shifts. For example, when we look at the
automotive industry, many manufacturers, like GM, are shifting to focus on electric
vehicle production to align with green initiatives. The energy industry isn’t going away,
but the source of energy is shifting from a fuel economy to an electric one.
In a similar way, artificial intelligence will shift the demand for jobs to other areas. There
will need to be individuals to help manage AI systems. There will still need to be people
to address more complex problems within the industries that are most likely to be
affected by job demand shifts, such as customer service. The biggest challenge with
artificial intelligence and its effect on the job market will be helping people to transition
to new roles that are in demand.
Privacy
Privacy tends to be discussed in the context of data privacy, data protection, and data
security. These concerns have allowed policymakers to make more strides in recent
years. For example, in 2016, GDPR legislation was created to protect the personal data
of people in the European Union and European Economic Area, giving individuals more
control of their data. In the United States, individual states are developing policies, such
as the California Consumer Privacy Act (CCPA), which was introduced in 2018 and
requires businesses to inform consumers about the collection of their data. Legislation
such as this has forced companies to rethink how they store and use personally
identifiable information (PII). As a result, investments in security have become an
increasing priority for businesses as they seek to eliminate any vulnerabilities and
opportunities for surveillance, hacking, and cyberattacks.
Bias and discrimination
Instances of bias and discrimination across a number of machine learning systems have
raised many ethical questions regarding the use of artificial intelligence. How can we
safeguard against bias and discrimination when the training data itself may be
generated by biased human processes? While companies typically have good
intentions for their automation efforts, Reuters (link resides outside ibm.com) highlights
some of the unforeseen consequences of incorporating AI into hiring practices. In their
effort to automate and simplify a process, Amazon unintentionally discriminated against
job candidates by gender for technical roles, and the company ultimately had to scrap
the project. Harvard Business Review (link resides outside ibm.com) has raised other
pointed questions about the use of AI in hiring practices, such as what data you should
be able to use when evaluating a candidate for a role.
Bias and discrimination aren’t limited to the human resources function either; they can
be found in a number of applications from facial recognition software to social media
algorithms.
As businesses become more aware of the risks with AI, they’ve also become more
active in this discussion around AI ethics and values. For example, IBM has sunset its
general purpose facial recognition and analysis products. IBM CEO Arvind Krishna
wrote: “IBM firmly opposes and will not condone uses of any technology, including facial
recognition technology offered by other vendors, for mass surveillance, racial profiling,
violations of basic human rights and freedoms, or any purpose which is not consistent
with our values and Principles of Trust and Transparency.”
Accountability
Since there isn’t significant legislation to regulate AI practices, there is no real
enforcement mechanism to ensure that ethical AI is practiced. The current incentives for
companies to be ethical are the negative repercussions of an unethical AI system on the
bottom line. To fill the gap, ethical frameworks have emerged as part of a collaboration
between ethicists and researchers to govern the construction and distribution of AI
models within society. However, at the moment, these only serve to guide. Some
research (link resides outside ibm.com) shows that the combination of distributed
responsibility and a lack of foresight into potential consequences aren’t conducive to
preventing harm to society.
Read more about IBM's position on AI Ethics
How to choose the right AI platform for machine learning
Selecting a platform can be a challenging process, as the wrong system can drive up
costs, or limit the use of other valuable tools or technologies. When reviewing multiple
vendors to select an AI platform, there is often a tendency to think that more features =
a better system. Maybe so, but reviewers should start by thinking through what the AI
platform will be doing for their organization. What machine learning capabilities need to
be delivered and what features are important to accomplish them? One missing feature
might doom the usefulness of an entire system. Here are some features to consider.
MLOps capabilities. Does the system have:
a unified interface for ease of management?
automated machine learning tools for faster model creation with low-code
and no-code functionality?
decision optimization to streamline the selection and deployment of
optimization models?
visual modeling to combine visual data science with open-source libraries
and notebook-based interfaces on a unified data and AI studio?
automated development for beginners to get started quickly and more
advanced data scientists to experiment?
synthetic data generator as an alternative or supplement to real-world data
when real-world data is not readily available?
Generative AI capabilities. Does the system have:
a content generator that can generate text, images and other content
based on the data it was trained on?
automated classification to read and classify written input, such as
evaluating and sorting customer complaints or reviewing customer
feedback sentiment?
a summary generator that can transform dense text into a high-quality
summary, capture key points from financial reports, and generate meeting
transcriptions?
a data extraction capability to sort through complex details and quickly pull
the necessary information from large documents?
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Exception.py
================================================
import sys
class customexception(Exception):
def __init__(self,error_message,error_details:sys):
self.error_message=error_message
_,_,exc_tb=error_details.exc_info()
print(exc_tb)
self.lineno=exc_tb.tb_lineno
self.file_name=exc_tb.tb_frame.f_code.co_filename
def __str__(self):
return "Error occured in python script name [{0}] line number [{1}] error message [{2}]".format(
self.file_name, self.lineno, str(self.error_message))
if __name__=="__main__":
try:
a=1/0
except Exception as e:
#print(e)
raise customexception(e,sys)
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Experiments/ChatWithDoc.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import os\n",
"from dotenv import load_dotenv\n",
"load_dotenv()\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"GOOGLE_API_KEY=os.getenv(\"GOOGLE_API_KEY\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'AIzaSyDnACKG8IVHV0NwTP3tiZJEI937ck6HH7w'"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"GOOGLE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"c:\\Users\\sunny\\chatwithdocllama\\venv\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
}
],
"source": [
"from llama_index.core import SimpleDirectoryReader\n",
"from llama_index.core import VectorStoreIndex\n",
"from llama_index.llms.gemini import Gemini\n",
"from IPython.display import Markdown, display\n",
"from llama_index.core import ServiceContext\n",
"from llama_index.core import StorageContext, load_index_from_storage\n",
"import google.generativeai as genai\n",
"from llama_index.embeddings.gemini import GeminiEmbedding\n",
"#from llama_index.core.settings import Settings\n",
"genai.configure(api_key=GOOGLE_API_KEY)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model(name='models/chat-bison-001',\n",
" base_model_id='',\n",
" version='001',\n",
" display_name='PaLM 2 Chat (Legacy)',\n",
" description='A legacy text-only model optimized for chat conversations',\n",
" input_token_limit=4096,\n",
" output_token_limit=1024,\n",
" supported_generation_methods=['generateMessage', 'countMessageTokens'],\n",
" temperature=0.25,\n",
" top_p=0.95,\n",
" top_k=40)\n",
"Model(name='models/text-bison-001',\n",
" base_model_id='',\n",
" version='001',\n",
" display_name='PaLM 2 (Legacy)',\n",
" description='A legacy model that understands text and generates text as an output',\n",
" input_token_limit=8196,\n",
" output_token_limit=1024,\n",
" supported_generation_methods=['generateText', 'countTextTokens', 'createTunedTextModel'],\n",
" temperature=0.7,\n",
" top_p=0.95,\n",
" top_k=40)\n",
"Model(name='models/embedding-gecko-001',\n",
" base_model_id='',\n",
" version='001',\n",
" display_name='Embedding Gecko',\n",
" description='Obtain a distributed representation of a text.',\n",
" input_token_limit=1024,\n",
" output_token_limit=1,\n",
" supported_generation_methods=['embedText', 'countTextTokens'],\n",
" temperature=None,\n",
" top_p=None,\n",
" top_k=None)\n",
"Model(name='models/gemini-pro',\n",
" base_model_id='',\n",
" version='001',\n",
" display_name='Gemini 1.0 Pro',\n",
" description='The best model for scaling across a wide range of tasks',\n",
" input_token_limit=30720,\n",
" output_token_limit=2048,\n",
" supported_generation_methods=['generateContent', 'countTokens'],\n",
" temperature=0.9,\n",
" top_p=1.0,\n",
" top_k=1)\n",
"Model(name='models/gemini-pro-vision',\n",
" base_model_id='',\n",
" version='001',\n",
" display_name='Gemini 1.0 Pro Vision',\n",
" description='The best image understanding model to handle a broad range of applications',\n",
" input_token_limit=12288,\n",
" output_token_limit=4096,\n",
" supported_generation_methods=['generateContent', 'countTokens'],\n",
" temperature=0.4,\n",
" top_p=1.0,\n",
" top_k=32)\n",
"Model(name='models/embedding-001',\n",
" base_model_id='',\n",
" version='001',\n",
" display_name='Embedding 001',\n",
" description='Obtain a distributed representation of a text.',\n",
" input_token_limit=2048,\n",
" output_token_limit=1,\n",
" supported_generation_methods=['embedContent', 'countTextTokens'],\n",
" temperature=None,\n",
" top_p=None,\n",
" top_k=None)\n",
"Model(name='models/aqa',\n",
" base_model_id='',\n",
" version='001',\n",
" display_name='Model that performs Attributed Question Answering.',\n",
" description=('Model trained to return answers to questions that are grounded in provided '\n",
" 'sources, along with estimating answerable probability.'),\n",
" input_token_limit=7168,\n",
" output_token_limit=1024,\n",
" supported_generation_methods=['generateAnswer'],\n",
" temperature=0.2,\n",
" top_p=1.0,\n",
" top_k=40)\n"
]
}
],
"source": [
"for models in genai.list_models():\n",
" print(models)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"models/gemini-pro\n",
"models/gemini-pro-vision\n"
]
}
],
"source": [
"for models in genai.list_models():\n",
" if 'generateContent' in models.supported_generation_methods:\n",
" print(models.name)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"documents = SimpleDirectoryReader(\"../Data\").load_data()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[Document(id_='e853545c-0ca1-4b7e-9681-02919ad26522', embedding=None, metadata={'file_path': '..\\\\Data\\\\MLDOC.txt', 'file_name': 'MLDOC.txt', 'file_type': 'text/plain', 'file_size': 22273, 'creation_date': '2024-02-15', 'last_modified_date': '2024-02-15', 'last_accessed_date': '2024-02-15'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={}, text='What is machine learning?\\nMachine learning is a branch of artificial intelligence (AI) and computer science which\\nfocuses on the use of data and algorithms to imitate the way that humans learn,\\ngradually improving its accuracy.\\nIBM has a rich history with machine learning. One of its own, Arthur Samuel, is credited\\nfor coining the term, “machine learning” with his research (link resides outside ibm.com)\\naround the game of checkers. Robert Nealey, the self-proclaimed checkers master,\\nplayed the game on an IBM 7094 computer in 1962, and he lost to the computer.\\nCompared to what can be done today, this feat seems trivial, but it’s considered a major\\nmilestone in the field of artificial intelligence.\\nOver the last couple of decades, the technological advances in storage and processing\\npower have enabled some innovative products based on machine learning, such as\\nNetflix’s recommendation engine and self-driving cars.\\nMachine learning is an important component of the growing field of data science.\\nThrough the use of statistical methods, algorithms are trained to make classifications or\\npredictions, and to uncover key insights in data mining projects. These insights\\nsubsequently drive decision making within applications and businesses, ideally\\nimpacting key growth metrics. As big data continues to expand and grow, the market\\ndemand for new data scientists will increase. They will be required to help identify the\\nmost relevant business questions and the data to answer them.\\nMachine learning algorithms are typically created using frameworks such as Python that\\naccelerate solution development by using platforms like TensorFlow or PyTorch.\\nNow available: watsonx.ai\\nThe all-new enterprise studio that brings together traditional machine learning along\\nwith new generative AI capabilities powered by foundation models.\\nTry watsonx.ai\\nBegin your journey to AI\\nLearn how to scale AI\\nExplore the AI Academy\\nMachine Learning vs. Deep Learning vs. Neural Networks\\nSince deep learning and machine learning tend to be used interchangeably, it’s worth\\nnoting the nuances between the two. Machine learning, deep learning, and neural\\nnetworks are all sub-fields of artificial intelligence. However, neural networks is actually\\na sub-field of machine learning, and deep learning is a sub-field of neural networks.\\nThe way in which deep learning and machine learning differ is in how each algorithm\\nlearns. \"Deep\" machine learning can use labeled datasets, also known as supervised\\nlearning, to inform its algorithm, but it doesn’t necessarily require a labeled dataset. The\\ndeep learning process can ingest unstructured data in its raw form (e.g., text or images),\\nand it can automatically determine the set of features which distinguish different\\ncategories of data from one another. This eliminates some of the human intervention\\nrequired and enables the use of large amounts of data. You can think of deep learning\\nas \"scalable machine learning\" as Lex Fridman notes in this MIT lecture (link resides\\noutside ibm.com).\\nClassical, or \"non-deep,\" machine learning is more dependent on human intervention to\\nlearn. Human experts determine the set of features to understand the differences\\nbetween data inputs, usually requiring more structured data to learn.\\nNeural networks, or artificial neural networks (ANNs), are comprised of node layers,\\ncontaining an input layer, one or more hidden layers, and an output layer. Each node, or\\nartificial neuron, connects to another and has an associated weight and threshold. If the\\noutput of any individual node is above the specified threshold value, that node is\\nactivated, sending data to the next layer of the network. Otherwise, no data is passed\\nalong to the next layer of the network by that node. The “deep” in deep learning is just\\nreferring to the number of layers in a neural network. A neural network that consists of\\nmore than three layers—which would be inclusive of the input and the output—can be\\nconsidered a deep learning algorithm or a deep neural network. A neural network that\\nonly has three layers is just a basic neural network.\\nDeep learning and neural networks are credited with accelerating progress in areas\\nsuch as computer vision, natural language processing, and speech recognition.\\nSee the blog post “AI vs. Machine Learning vs. Deep Learning vs. Neural Networks:\\nWhat’s the Difference?” for a closer look at how the different concepts relate.\\nRelated content\\nExplore the watsonx.ai interactive demo\\nDownload “Machine learning for Dummies”\\n- This link downloads a pdf\\nExplore Gen AI for developers\\nHow does machine learning work?\\nUC Berkeley (link resides outside ibm.com) breaks out the learning system of a\\nmachine learning algorithm into three main parts.\\nA Decision Process: In general, machine learning algorithms are used to make a\\nprediction or classification. Based on some input data, which can be labeled or\\nunlabeled, your algorithm will produce an estimate about a pattern in the data.\\nAn Error Function: An error function evaluates the prediction of the model. If\\nthere are known examples, an error function can make a comparison to assess\\nthe accuracy of the model.\\nA Model Optimization Process: If the model can fit better to the data points in the\\ntraining set, then weights are adjusted to reduce the discrepancy between the\\nknown example and the model estimate. The algorithm will repeat this iterative\\n“evaluate and optimize” process, updating weights autonomously until a\\nthreshold of accuracy has been met.\\nMachine learning methods\\nMachine learning models fall into three primary categories.\\nSupervised machine learning\\nSupervised learning, also known as supervised machine learning, is defined by its use\\nof labeled datasets to train algorithms to classify data or predict outcomes accurately.\\nAs input data is fed into the model, the model adjusts its weights until it has been fitted\\nappropriately. This occurs as part of the cross validation process to ensure that the\\nmodel avoids overfitting or underfitting. Supervised learning helps organizations solve a\\nvariety of real-world problems at scale, such as classifying spam in a separate folder\\nfrom your inbox. Some methods used in supervised learning include neural networks,\\nnaïve bayes, linear regression, logistic regression, random forest, and support vector\\nmachine (SVM).\\nUnsupervised machine learning\\nUnsupervised learning, also known as unsupervised machine learning, uses machine\\nlearning algorithms to analyze and cluster unlabeled datasets (subsets called clusters).\\nThese algorithms discover hidden patterns or data groupings without the need for\\nhuman intervention. This method’s ability to discover similarities and differences in\\ninformation make it ideal for exploratory data analysis, cross-selling strategies,\\ncustomer segmentation, and image and pattern recognition. It’s also used to reduce the\\nnumber of features in a model through the process of dimensionality reduction. Principal\\ncomponent analysis (PCA) and singular value decomposition (SVD) are two common\\napproaches for this. Other algorithms used in unsupervised learning include neural\\nnetworks, k-means clustering, and probabilistic clustering methods.\\nSemi-supervised learning\\nSemi-supervised learning offers a happy medium between supervised and\\nunsupervised learning. During training, it uses a smaller labeled data set to guide\\nclassification and feature extraction from a larger, unlabeled data set. Semi-supervised\\nlearning can solve the problem of not having enough labeled data for a supervised\\nlearning algorithm. It also helps if it’s too costly to label enough data.\\nFor a deep dive into the differences between these approaches, check out \"Supervised\\nvs. Unsupervised Learning: What\\'s the Difference?\"\\nReinforcement machine learning\\nReinforcement machine learning is a machine learning model that is similar to\\nsupervised learning, but the algorithm isn’t trained using sample data. This model learns\\nas it goes by using trial and error. A sequence of successful outcomes will be reinforced\\nto develop the best recommendation or policy for a given problem.\\nThe IBM Watson® system that won the Jeopardy! challenge in 2011 is a good example.\\nThe system used reinforcement learning to learn when to attempt an answer (or\\nquestion, as it were), which square to select on the board, and how much to\\nwager—especially on daily doubles.\\nLearn more about reinforcement learning\\nCommon machine learning algorithms\\nA number of machine learning algorithms are commonly used. These include:\\nNeural networks: Neural networks simulate the way the human brain works, with\\na huge number of linked processing nodes. Neural networks are good at\\nrecognizing patterns and play an important role in applications including natural\\nlanguage translation, image recognition, speech recognition, and image creation.\\nLinear regression: This algorithm is used to predict numerical values, based on a\\nlinear relationship between different values. For example, the technique could be\\nused to predict house prices based on historical data for the area.\\nLogistic regression: This supervised learning algorithm makes predictions for\\ncategorical response variables, such as “yes/no” answers to questions. It can be\\nused for applications such as classifying spam and quality control on a\\nproduction line.\\nClustering: Using unsupervised learning, clustering algorithms can identify\\npatterns in data so that it can be grouped. Computers can help data scientists by\\nidentifying differences between data items that humans have overlooked.\\nDecision trees: Decision trees can be used for both predicting numerical values\\n(regression) and classifying data into categories. Decision trees use a branching\\nsequence of linked decisions that can be represented with a tree diagram. One of\\nthe advantages of decision trees is that they are easy to validate and audit,\\nunlike the black box of the neural network.\\nRandom forests: In a random forest, the machine learning algorithm predicts a\\nvalue or category by combining the results from a number of decision trees.\\nAdvantages and disadvantages of machine learning algorithms\\nDepending on your budget, need for speed and precision required, each algorithm\\ntype—supervised, unsupervised, semi-supervised, or reinforcement—has its own\\nadvantages and disadvantages. For example, decision tree algorithms are used for both\\npredicting numerical values (regression problems) and classifying data into categories.\\nDecision trees use a branching sequence of linked decisions that may be represented\\nwith a tree diagram. A prime advantage of decision trees is that they are easier to\\nvalidate and audit than a neural network. The bad news is that they can be more\\nunstable than other decision predictors.\\nOverall, there are many advantages to machine learning that businesses can leverage\\nfor new efficiencies. These include machine learning identifying patterns and trends in\\nmassive volumes of data that humans might not spot at all. And this analysis requires\\nlittle human intervention: just feed in the dataset of interest and let the machine learning\\nsystem assemble and refine its own algorithms—which will continually improve with\\nmore data input over time. Customers and users can enjoy a more personalized\\nexperience as the model learns more with every experience with that person.\\nOn the downside, machine learning requires large training datasets that are accurate\\nand unbiased. GIGO is the operative factor: garbage in / garbage out. Gathering\\nsufficient data and having a system robust enough to run it might also be a drain on\\nresources. Machine learning can also be prone to error, depending on the input. With\\ntoo small a sample, the system could produce a perfectly logical algorithm that is\\ncompletely wrong or misleading. To avoid wasting budget or displeasing customers,\\norganizations should act on the answers only when there is high confidence in the\\noutput.\\nReal-world machine learning use cases\\nHere are just a few examples of machine learning you might encounter every day:\\nSpeech recognition: It is also known as automatic speech recognition (ASR), computer\\nspeech recognition, or speech-to-text, and it is a capability which uses natural language\\nprocessing (NLP) to translate human speech into a written format. Many mobile devices\\nincorporate speech recognition into their systems to conduct voice search—e.g. Siri—or\\nimprove accessibility for texting.\\nCustomer service: Online chatbots are replacing human agents along the customer\\njourney, changing the way we think about customer engagement across websites and\\nsocial media platforms. Chatbots answer frequently asked questions (FAQs) about\\ntopics such as shipping, or provide personalized advice, cross-selling products or\\nsuggesting sizes for users. Examples include virtual agents on e-commerce sites;\\nmessaging bots, using Slack and Facebook Messenger; and tasks usually done by\\nvirtual assistants and voice assistants.\\nComputer vision: This AI technology enables computers to derive meaningful\\ninformation from digital images, videos, and other visual inputs, and then take the\\nappropriate action. Powered by convolutional neural networks, computer vision has\\napplications in photo tagging on social media, radiology imaging in healthcare, and\\nself-driving cars in the automotive industry.\\nRecommendation engines: Using past consumption behavior data, AI algorithms can\\nhelp to discover data trends that can be used to develop more effective cross-selling\\nstrategies. Recommendation engines are used by online retailers to make relevant\\nproduct recommendations to customers during the checkout process.\\nRobotic process automation (RPA): Also known as software robotics, RPA uses\\nintelligent automation technologies to perform repetitive manual tasks.\\nAutomated stock trading: Designed to optimize stock portfolios, AI-driven\\nhigh-frequency trading platforms make thousands or even millions of trades per day\\nwithout human intervention.\\nFraud detection: Banks and other financial institutions can use machine learning to spot\\nsuspicious transactions. Supervised learning can train a model using information about\\nknown fraudulent transactions. Anomaly detection can identify transactions that look\\natypical and deserve further investigation.\\nChallenges of machine learning\\nAs machine learning technology has developed, it has certainly made our lives easier.\\nHowever, implementing machine learning in businesses has also raised a number of\\nethical concerns about AI technologies. Some of these include:\\nTechnological singularity\\nWhile this topic garners a lot of public attention, many researchers are not concerned\\nwith the idea of AI surpassing human intelligence in the near future. Technological\\nsingularity is also referred to as strong AI or superintelligence. Philosopher Nick\\nBostrum defines superintelligence as “any intellect that vastly outperforms the best\\nhuman brains in practically every field, including scientific creativity, general wisdom,\\nand social skills.” Despite the fact that superintelligence is not imminent in society, the\\nidea of it raises some interesting questions as we consider the use of autonomous\\nsystems, like self-driving cars. It’s unrealistic to think that a driverless car would never\\nhave an accident, but who is responsible and liable under those circumstances? Should\\nwe still develop autonomous vehicles, or do we limit this technology to\\nsemi-autonomous vehicles which help people drive safely? The jury is still out on this,\\nbut these are the types of ethical debates that are occurring as new, innovative AI\\ntechnology develops.\\nAI impact on jobs\\nWhile a lot of public perception of artificial intelligence centers around job losses, this\\nconcern should probably be reframed. With every disruptive, new technology, we see\\nthat the market demand for specific job roles shifts. For example, when we look at the\\nautomotive industry, many manufacturers, like GM, are shifting to focus on electric\\nvehicle production to align with green initiatives. The energy industry isn’t going away,\\nbut the source of energy is shifting from a fuel economy to an electric one.\\nIn a similar way, artificial intelligence will shift the demand for jobs to other areas. There\\nwill need to be individuals to help manage AI systems. There will still need to be people\\nto address more complex problems within the industries that are most likely to be\\naffected by job demand shifts, such as customer service. The biggest challenge with\\nartificial intelligence and its effect on the job market will be helping people to transition\\nto new roles that are in demand.\\nPrivacy\\nPrivacy tends to be discussed in the context of data privacy, data protection, and data\\nsecurity. These concerns have allowed policymakers to make more strides in recent\\nyears. For example, in 2016, GDPR legislation was created to protect the personal data\\nof people in the European Union and European Economic Area, giving individuals more\\ncontrol of their data. In the United States, individual states are developing policies, such\\nas the California Consumer Privacy Act (CCPA), which was introduced in 2018 and\\nrequires businesses to inform consumers about the collection of their data. Legislation\\nsuch as this has forced companies to rethink how they store and use personally\\nidentifiable information (PII). As a result, investments in security have become an\\nincreasing priority for businesses as they seek to eliminate any vulnerabilities and\\nopportunities for surveillance, hacking, and cyberattacks.\\nBias and discrimination\\nInstances of bias and discrimination across a number of machine learning systems have\\nraised many ethical questions regarding the use of artificial intelligence. How can we\\nsafeguard against bias and discrimination when the training data itself may be\\ngenerated by biased human processes? While companies typically have good\\nintentions for their automation efforts, Reuters (link resides outside ibm.com) highlights\\nsome of the unforeseen consequences of incorporating AI into hiring practices. In their\\neffort to automate and simplify a process, Amazon unintentionally discriminated against\\njob candidates by gender for technical roles, and the company ultimately had to scrap\\nthe project. Harvard Business Review (link resides outside ibm.com) has raised other\\npointed questions about the use of AI in hiring practices, such as what data you should\\nbe able to use when evaluating a candidate for a role.\\nBias and discrimination aren’t limited to the human resources function either; they can\\nbe found in a number of applications from facial recognition software to social media\\nalgorithms.\\nAs businesses become more aware of the risks with AI, they’ve also become more\\nactive in this discussion around AI ethics and values. For example, IBM has sunset its\\ngeneral purpose facial recognition and analysis products. IBM CEO Arvind Krishna\\nwrote: “IBM firmly opposes and will not condone uses of any technology, including facial\\nrecognition technology offered by other vendors, for mass surveillance, racial profiling,\\nviolations of basic human rights and freedoms, or any purpose which is not consistent\\nwith our values and Principles of Trust and Transparency.”\\nAccountability\\nSince there isn’t significant legislation to regulate AI practices, there is no real\\nenforcement mechanism to ensure that ethical AI is practiced. The current incentives for\\ncompanies to be ethical are the negative repercussions of an unethical AI system on the\\nbottom line. To fill the gap, ethical frameworks have emerged as part of a collaboration\\nbetween ethicists and researchers to govern the construction and distribution of AI\\nmodels within society. However, at the moment, these only serve to guide. Some\\nresearch (link resides outside ibm.com) shows that the combination of distributed\\nresponsibility and a lack of foresight into potential consequences aren’t conducive to\\npreventing harm to society.\\nRead more about IBM\\'s position on AI Ethics\\nHow to choose the right AI platform for machine learning\\nSelecting a platform can be a challenging process, as the wrong system can drive up\\ncosts, or limit the use of other valuable tools or technologies. When reviewing multiple\\nvendors to select an AI platform, there is often a tendency to think that more features =\\na better system. Maybe so, but reviewers should start by thinking through what the AI\\nplatform will be doing for their organization. What machine learning capabilities need to\\nbe delivered and what features are important to accomplish them? One missing feature\\nmight doom the usefulness of an entire system. Here are some features to consider.\\nMLOps capabilities. Does the system have:\\na unified interface for ease of management?\\nautomated machine learning tools for faster model creation with low-code\\nand no-code functionality?\\ndecision optimization to streamline the selection and deployment of\\noptimization models?\\nvisual modeling to combine visual data science with open-source libraries\\nand notebook-based interfaces on a unified data and AI studio?\\nautomated development for beginners to get started quickly and more\\nadvanced data scientists to experiment?\\nsynthetic data generator as an alternative or supplement to real-world data\\nwhen real-world data is not readily available?\\nGenerative AI capabilities. Does the system have:\\na content generator that can generate text, images and other content\\nbased on the data it was trained on?\\nautomated classification to read and classify written input, such as\\nevaluating and sorting customer complaints or reviewing customer\\nfeedback sentiment?\\na summary generator that can transform dense text into a high-quality\\nsummary, capture key points from financial reports, and generate meeting\\ntranscriptions?\\na data extraction capability to sort through complex details and quickly pull\\nthe necessary information from large documents?', start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\\n\\n{content}', metadata_template='{key}: {value}', metadata_seperator='\\n')]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"documents\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"What is machine learning?\n",
"Machine learning is a branch of artificial intelligence (AI) and computer science which\n",
"focuses on the use of data and algorithms to imitate the way that humans learn,\n",
"gradually improving its accuracy.\n",
"IBM has a rich history with machine learning. One of its own, Arthur Samuel, is credited\n",
"for coining the term, “machine learning” with his research (link resides outside ibm.com)\n",
"around the game of checkers. Robert Nealey, the self-proclaimed checkers master,\n",
"played the game on an IBM 7094 computer in 1962, and he lost to the computer.\n",
"Compared to what can be done today, this feat seems trivial, but it’s considered a major\n",
"milestone in the field of artificial intelligence.\n",
"Over the last couple of decades, the technological advances in storage and processing\n",
"power have enabled some innovative products based on machine learning, such as\n",
"Netflix’s recommendation engine and self-driving cars.\n",
"Machine learning is an important component of the growing field of data science.\n",
"Through the use of statistical methods, algorithms are trained to make classifications or\n",
"predictions, and to uncover key insights in data mining projects. These insights\n",
"subsequently drive decision making within applications and businesses, ideally\n",
"impacting key growth metrics. As big data continues to expand and grow, the market\n",
"demand for new data scientists will increase. They will be required to help identify the\n",
"most relevant business questions and the data to answer them.\n",
"Machine learning algorithms are typically created using frameworks such as Python that\n",
"accelerate solution development by using platforms like TensorFlow or PyTorch.\n",
"Now available: watsonx.ai\n",
"The all-new enterprise studio that brings together traditional machine learning along\n",
"with new generative AI capabilities powered by foundation models.\n",
"Try watsonx.ai\n",
"Begin your journey to AI\n",
"Learn how to scale AI\n",
"Explore the AI Academy\n",
"Machine Learning vs. Deep Learning vs. Neural Networks\n",
"Since deep learning and machine learning tend to be used interchangeably, it’s worth\n",
"noting the nuances between the two. Machine learning, deep learning, and neural\n",
"networks are all sub-fields of artificial intelligence. However, neural networks is actually\n",
"a sub-field of machine learning, and deep learning is a sub-field of neural networks.\n",
"The way in which deep learning and machine learning differ is in how each algorithm\n",
"learns. \"Deep\" machine learning can use labeled datasets, also known as supervised\n",
"learning, to inform its algorithm, but it doesn’t necessarily require a labeled dataset. The\n",
"deep learning process can ingest unstructured data in its raw form (e.g., text or images),\n",
"and it can automatically determine the set of features which distinguish different\n",
"categories of data from one another. This eliminates some of the human intervention\n",
"required and enables the use of large amounts of data. You can think of deep learning\n",
"as \"scalable machine learning\" as Lex Fridman notes in this MIT lecture (link resides\n",
"outside ibm.com).\n",
"Classical, or \"non-deep,\" machine learning is more dependent on human intervention to\n",
"learn. Human experts determine the set of features to understand the differences\n",
"between data inputs, usually requiring more structured data to learn.\n",
"Neural networks, or artificial neural networks (ANNs), are comprised of node layers,\n",
"containing an input layer, one or more hidden layers, and an output layer. Each node, or\n",
"artificial neuron, connects to another and has an associated weight and threshold. If the\n",
"output of any individual node is above the specified threshold value, that node is\n",
"activated, sending data to the next layer of the network. Otherwise, no data is passed\n",
"along to the next layer of the network by that node. The “deep” in deep learning is just\n",
"referring to the number of layers in a neural network. A neural network that consists of\n",
"more than three layers—which would be inclusive of the input and the output—can be\n",
"considered a deep learning algorithm or a deep neural network. A neural network that\n",
"only has three layers is just a basic neural network.\n",
"Deep learning and neural networks are credited with accelerating progress in areas\n",
"such as computer vision, natural language processing, and speech recognition.\n",
"See the blog post “AI vs. Machine Learning vs. Deep Learning vs. Neural Networks:\n",
"What’s the Difference?” for a closer look at how the different concepts relate.\n",
"Related content\n",
"Explore the watsonx.ai interactive demo\n",
"Download “Machine learning for Dummies”\n",
"- This link downloads a pdf\n",
"Explore Gen AI for developers\n",
"How does machine learning work?\n",
"UC Berkeley (link resides outside ibm.com) breaks out the learning system of a\n",
"machine learning algorithm into three main parts.\n",
"A Decision Process: In general, machine learning algorithms are used to make a\n",
"prediction or classification. Based on some input data, which can be labeled or\n",
"unlabeled, your algorithm will produce an estimate about a pattern in the data.\n",
"An Error Function: An error function evaluates the prediction of the model. If\n",
"there are known examples, an error function can make a comparison to assess\n",
"the accuracy of the model.\n",
"A Model Optimization Process: If the model can fit better to the data points in the\n",
"training set, then weights are adjusted to reduce the discrepancy between the\n",
"known example and the model estimate. The algorithm will repeat this iterative\n",
"“evaluate and optimize” process, updating weights autonomously until a\n",
"threshold of accuracy has been met.\n",
"Machine learning methods\n",
"Machine learning models fall into three primary categories.\n",
"Supervised machine learning\n",
"Supervised learning, also known as supervised machine learning, is defined by its use\n",
"of labeled datasets to train algorithms to classify data or predict outcomes accurately.\n",
"As input data is fed into the model, the model adjusts its weights until it has been fitted\n",
"appropriately. This occurs as part of the cross validation process to ensure that the\n",
"model avoids overfitting or underfitting. Supervised learning helps organizations solve a\n",
"variety of real-world problems at scale, such as classifying spam in a separate folder\n",
"from your inbox. Some methods used in supervised learning include neural networks,\n",
"naïve bayes, linear regression, logistic regression, random forest, and support vector\n",
"machine (SVM).\n",
"Unsupervised machine learning\n",
"Unsupervised learning, also known as unsupervised machine learning, uses machine\n",
"learning algorithms to analyze and cluster unlabeled datasets (subsets called clusters).\n",
"These algorithms discover hidden patterns or data groupings without the need for\n",
"human intervention. This method’s ability to discover similarities and differences in\n",
"information make it ideal for exploratory data analysis, cross-selling strategies,\n",
"customer segmentation, and image and pattern recognition. It’s also used to reduce the\n",
"number of features in a model through the process of dimensionality reduction. Principal\n",
"component analysis (PCA) and singular value decomposition (SVD) are two common\n",
"approaches for this. Other algorithms used in unsupervised learning include neural\n",
"networks, k-means clustering, and probabilistic clustering methods.\n",
"Semi-supervised learning\n",
"Semi-supervised learning offers a happy medium between supervised and\n",
"unsupervised learning. During training, it uses a smaller labeled data set to guide\n",
"classification and feature extraction from a larger, unlabeled data set. Semi-supervised\n",
"learning can solve the problem of not having enough labeled data for a supervised\n",
"learning algorithm. It also helps if it’s too costly to label enough data.\n",
"For a deep dive into the differences between these approaches, check out \"Supervised\n",
"vs. Unsupervised Learning: What's the Difference?\"\n",
"Reinforcement machine learning\n",
"Reinforcement machine learning is a machine learning model that is similar to\n",
"supervised learning, but the algorithm isn’t trained using sample data. This model learns\n",
"as it goes by using trial and error. A sequence of successful outcomes will be reinforced\n",
"to develop the best recommendation or policy for a given problem.\n",
"The IBM Watson® system that won the Jeopardy! challenge in 2011 is a good example.\n",
"The system used reinforcement learning to learn when to attempt an answer (or\n",
"question, as it were), which square to select on the board, and how much to\n",
"wager—especially on daily doubles.\n",
"Learn more about reinforcement learning\n",
"Common machine learning algorithms\n",
"A number of machine learning algorithms are commonly used. These include:\n",
"Neural networks: Neural networks simulate the way the human brain works, with\n",
"a huge number of linked processing nodes. Neural networks are good at\n",
"recognizing patterns and play an important role in applications including natural\n",
"language translation, image recognition, speech recognition, and image creation.\n",
"Linear regression: This algorithm is used to predict numerical values, based on a\n",
"linear relationship between different values. For example, the technique could be\n",
"used to predict house prices based on historical data for the area.\n",
"Logistic regression: This supervised learning algorithm makes predictions for\n",
"categorical response variables, such as “yes/no” answers to questions. It can be\n",
"used for applications such as classifying spam and quality control on a\n",
"production line.\n",
"Clustering: Using unsupervised learning, clustering algorithms can identify\n",
"patterns in data so that it can be grouped. Computers can help data scientists by\n",
"identifying differences between data items that humans have overlooked.\n",
"Decision trees: Decision trees can be used for both predicting numerical values\n",
"(regression) and classifying data into categories. Decision trees use a branching\n",
"sequence of linked decisions that can be represented with a tree diagram. One of\n",
"the advantages of decision trees is that they are easy to validate and audit,\n",
"unlike the black box of the neural network.\n",
"Random forests: In a random forest, the machine learning algorithm predicts a\n",
"value or category by combining the results from a number of decision trees.\n",
"Advantages and disadvantages of machine learning algorithms\n",
"Depending on your budget, need for speed and precision required, each algorithm\n",
"type—supervised, unsupervised, semi-supervised, or reinforcement—has its own\n",
"advantages and disadvantages. For example, decision tree algorithms are used for both\n",
"predicting numerical values (regression problems) and classifying data into categories.\n",
"Decision trees use a branching sequence of linked decisions that may be represented\n",
"with a tree diagram. A prime advantage of decision trees is that they are easier to\n",
"validate and audit than a neural network. The bad news is that they can be more\n",
"unstable than other decision predictors.\n",
"Overall, there are many advantages to machine learning that businesses can leverage\n",
"for new efficiencies. These include machine learning identifying patterns and trends in\n",
"massive volumes of data that humans might not spot at all. And this analysis requires\n",
"little human intervention: just feed in the dataset of interest and let the machine learning\n",
"system assemble and refine its own algorithms—which will continually improve with\n",
"more data input over time. Customers and users can enjoy a more personalized\n",
"experience as the model learns more with every experience with that person.\n",
"On the downside, machine learning requires large training datasets that are accurate\n",
"and unbiased. GIGO is the operative factor: garbage in / garbage out. Gathering\n",
"sufficient data and having a system robust enough to run it might also be a drain on\n",
"resources. Machine learning can also be prone to error, depending on the input. With\n",
"too small a sample, the system could produce a perfectly logical algorithm that is\n",
"completely wrong or misleading. To avoid wasting budget or displeasing customers,\n",
"organizations should act on the answers only when there is high confidence in the\n",
"output.\n",
"Real-world machine learning use cases\n",
"Here are just a few examples of machine learning you might encounter every day:\n",
"Speech recognition: It is also known as automatic speech recognition (ASR), computer\n",
"speech recognition, or speech-to-text, and it is a capability which uses natural language\n",
"processing (NLP) to translate human speech into a written format. Many mobile devices\n",
"incorporate speech recognition into their systems to conduct voice search—e.g. Siri—or\n",
"improve accessibility for texting.\n",
"Customer service: Online chatbots are replacing human agents along the customer\n",
"journey, changing the way we think about customer engagement across websites and\n",
"social media platforms. Chatbots answer frequently asked questions (FAQs) about\n",
"topics such as shipping, or provide personalized advice, cross-selling products or\n",
"suggesting sizes for users. Examples include virtual agents on e-commerce sites;\n",
"messaging bots, using Slack and Facebook Messenger; and tasks usually done by\n",
"virtual assistants and voice assistants.\n",
"Computer vision: This AI technology enables computers to derive meaningful\n",
"information from digital images, videos, and other visual inputs, and then take the\n",
"appropriate action. Powered by convolutional neural networks, computer vision has\n",
"applications in photo tagging on social media, radiology imaging in healthcare, and\n",
"self-driving cars in the automotive industry.\n",
"Recommendation engines: Using past consumption behavior data, AI algorithms can\n",
"help to discover data trends that can be used to develop more effective cross-selling\n",
"strategies. Recommendation engines are used by online retailers to make relevant\n",
"product recommendations to customers during the checkout process.\n",
"Robotic process automation (RPA): Also known as software robotics, RPA uses\n",
"intelligent automation technologies to perform repetitive manual tasks.\n",
"Automated stock trading: Designed to optimize stock portfolios, AI-driven\n",
"high-frequency trading platforms make thousands or even millions of trades per day\n",
"without human intervention.\n",
"Fraud detection: Banks and other financial institutions can use machine learning to spot\n",
"suspicious transactions. Supervised learning can train a model using information about\n",
"known fraudulent transactions. Anomaly detection can identify transactions that look\n",
"atypical and deserve further investigation.\n",
"Challenges of machine learning\n",
"As machine learning technology has developed, it has certainly made our lives easier.\n",
"However, implementing machine learning in businesses has also raised a number of\n",
"ethical concerns about AI technologies. Some of these include:\n",
"Technological singularity\n",
"While this topic garners a lot of public attention, many researchers are not concerned\n",
"with the idea of AI surpassing human intelligence in the near future. Technological\n",
"singularity is also referred to as strong AI or superintelligence. Philosopher Nick\n",
"Bostrum defines superintelligence as “any intellect that vastly outperforms the best\n",
"human brains in practically every field, including scientific creativity, general wisdom,\n",
"and social skills.” Despite the fact that superintelligence is not imminent in society, the\n",
"idea of it raises some interesting questions as we consider the use of autonomous\n",
"systems, like self-driving cars. It’s unrealistic to think that a driverless car would never\n",
"have an accident, but who is responsible and liable under those circumstances? Should\n",
"we still develop autonomous vehicles, or do we limit this technology to\n",
"semi-autonomous vehicles which help people drive safely? The jury is still out on this,\n",
"but these are the types of ethical debates that are occurring as new, innovative AI\n",
"technology develops.\n",
"AI impact on jobs\n",
"While a lot of public perception of artificial intelligence centers around job losses, this\n",
"concern should probably be reframed. With every disruptive, new technology, we see\n",
"that the market demand for specific job roles shifts. For example, when we look at the\n",
"automotive industry, many manufacturers, like GM, are shifting to focus on electric\n",
"vehicle production to align with green initiatives. The energy industry isn’t going away,\n",
"but the source of energy is shifting from a fuel economy to an electric one.\n",
"In a similar way, artificial intelligence will shift the demand for jobs to other areas. There\n",
"will need to be individuals to help manage AI systems. There will still need to be people\n",
"to address more complex problems within the industries that are most likely to be\n",
"affected by job demand shifts, such as customer service. The biggest challenge with\n",
"artificial intelligence and its effect on the job market will be helping people to transition\n",
"to new roles that are in demand.\n",
"Privacy\n",
"Privacy tends to be discussed in the context of data privacy, data protection, and data\n",
"security. These concerns have allowed policymakers to make more strides in recent\n",
"years. For example, in 2016, GDPR legislation was created to protect the personal data\n",
"of people in the European Union and European Economic Area, giving individuals more\n",
"control of their data. In the United States, individual states are developing policies, such\n",
"as the California Consumer Privacy Act (CCPA), which was introduced in 2018 and\n",
"requires businesses to inform consumers about the collection of their data. Legislation\n",
"such as this has forced companies to rethink how they store and use personally\n",
"identifiable information (PII). As a result, investments in security have become an\n",
"increasing priority for businesses as they seek to eliminate any vulnerabilities and\n",
"opportunities for surveillance, hacking, and cyberattacks.\n",
"Bias and discrimination\n",
"Instances of bias and discrimination across a number of machine learning systems have\n",
"raised many ethical questions regarding the use of artificial intelligence. How can we\n",
"safeguard against bias and discrimination when the training data itself may be\n",
"generated by biased human processes? While companies typically have good\n",
"intentions for their automation efforts, Reuters (link resides outside ibm.com) highlights\n",
"some of the unforeseen consequences of incorporating AI into hiring practices. In their\n",
"effort to automate and simplify a process, Amazon unintentionally discriminated against\n",
"job candidates by gender for technical roles, and the company ultimately had to scrap\n",
"the project. Harvard Business Review (link resides outside ibm.com) has raised other\n",
"pointed questions about the use of AI in hiring practices, such as what data you should\n",
"be able to use when evaluating a candidate for a role.\n",
"Bias and discrimination aren’t limited to the human resources function either; they can\n",
"be found in a number of applications from facial recognition software to social media\n",
"algorithms.\n",
"As businesses become more aware of the risks with AI, they’ve also become more\n",
"active in this discussion around AI ethics and values. For example, IBM has sunset its\n",
"general purpose facial recognition and analysis products. IBM CEO Arvind Krishna\n",
"wrote: “IBM firmly opposes and will not condone uses of any technology, including facial\n",
"recognition technology offered by other vendors, for mass surveillance, racial profiling,\n",
"violations of basic human rights and freedoms, or any purpose which is not consistent\n",
"with our values and Principles of Trust and Transparency.”\n",
"Accountability\n",
"Since there isn’t significant legislation to regulate AI practices, there is no real\n",
"enforcement mechanism to ensure that ethical AI is practiced. The current incentives for\n",
"companies to be ethical are the negative repercussions of an unethical AI system on the\n",
"bottom line. To fill the gap, ethical frameworks have emerged as part of a collaboration\n",
"between ethicists and researchers to govern the construction and distribution of AI\n",
"models within society. However, at the moment, these only serve to guide. Some\n",
"research (link resides outside ibm.com) shows that the combination of distributed\n",
"responsibility and a lack of foresight into potential consequences aren’t conducive to\n",
"preventing harm to society.\n",
"Read more about IBM's position on AI Ethics\n",
"How to choose the right AI platform for machine learning\n",
"Selecting a platform can be a challenging process, as the wrong system can drive up\n",
"costs, or limit the use of other valuable tools or technologies. When reviewing multiple\n",
"vendors to select an AI platform, there is often a tendency to think that more features =\n",
"a better system. Maybe so, but reviewers should start by thinking through what the AI\n",
"platform will be doing for their organization. What machine learning capabilities need to\n",
"be delivered and what features are important to accomplish them? One missing feature\n",
"might doom the usefulness of an entire system. Here are some features to consider.\n",
"MLOps capabilities. Does the system have:\n",
"a unified interface for ease of management?\n",
"automated machine learning tools for faster model creation with low-code\n",
"and no-code functionality?\n",
"decision optimization to streamline the selection and deployment of\n",
"optimization models?\n",
"visual modeling to combine visual data science with open-source libraries\n",
"and notebook-based interfaces on a unified data and AI studio?\n",
"automated development for beginners to get started quickly and more\n",
"advanced data scientists to experiment?\n",
"synthetic data generator as an alternative or supplement to real-world data\n",
"when real-world data is not readily available?\n",
"Generative AI capabilities. Does the system have:\n",
"a content generator that can generate text, images and other content\n",
"based on the data it was trained on?\n",
"automated classification to read and classify written input, such as\n",
"evaluating and sorting customer complaints or reviewing customer\n",
"feedback sentiment?\n",
"a summary generator that can transform dense text into a high-quality\n",
"summary, capture key points from financial reports, and generate meeting\n",
"transcriptions?\n",
"a data extraction capability to sort through complex details and quickly pull\n",
"the necessary information from large documents?\n"
]
}
],
"source": [
"print(documents[0].text)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"model=Gemini(models='gemini-pro',api_key=GOOGLE_API_KEY)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"# grab embeddings from gemini embeddings model\n",
"gemini_embed_model = GeminiEmbedding(model_name=\"models/embedding-001\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\sunny\\AppData\\Local\\Temp\\ipykernel_27624\\4136029042.py:2: DeprecationWarning: Call to deprecated class method from_defaults. (ServiceContext is deprecated, please use `llama_index.settings.Settings` instead.) -- Deprecated since version 0.10.0.\n",
" service_context = ServiceContext.from_defaults(llm=model,embed_model=gemini_embed_model, chunk_size=800, chunk_overlap=20)\n"
]
}
],
"source": [
"# Configure Service Context\n",
"service_context = ServiceContext.from_defaults(llm=model,embed_model=gemini_embed_model, chunk_size=800, chunk_overlap=20)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"index = VectorStoreIndex.from_documents(documents,service_context=service_context)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"index.storage_context.persist()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"query_engine = index.as_query_engine()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"\n",
"response = query_engine.query(\"what is machine learning?\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Machine learning is a branch of artificial intelligence (AI) and computer science which focuses on the use of data and algorithms to imitate the way that humans learn, gradually improving its accuracy.'"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"response.response"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"response = query_engine.query(\"what is attention mechnism\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"response.response"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.18"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Experiments/storage/default__vector_store.json
================================================
{"embedding_dict": {"35be54dc-30ad-446a-8ceb-55211de07da6": [-0.002203774, -0.060024295, -0.04713062, -0.0013296342, 0.061716102, 0.021549296, 0.0020747657, -0.014787987, 0.013873387, 0.018041978, -0.012738351, 0.03396815, 0.00733824, -0.02696071, -0.004742023, -0.06947529, 0.022794064, 0.046541367, 0.020981258, -0.02053794, -0.008536696, 0.003348506, 0.0037701814, -0.03353993, -0.0140477875, -0.035146646, -0.005439767, -0.086886436, -0.049203344, 0.05926542, -0.033465333, 0.017176015, -0.011814407, 0.0541833, 0.012854958, -0.014688459, 0.0073425905, 0.042993993, 0.0097140195, -0.02418341, 0.012351348, -0.046470195, -0.008410227, -0.00606635, -0.009812497, -0.027221842, 0.003883179, 0.009347943, 0.024387643, -0.075623356, 0.016171858, 0.01415275, 0.05649294, -0.0012945123, 0.04448769, -0.033215474, 0.0063176323, 0.018802645, 5.417889e-05, 0.00023273664, 0.010701638, 0.016135937, -0.019104414, 0.025648508, 0.044736963, -0.02506695, -0.07390778, 0.025962427, 0.004810607, 0.0047641112, 0.015145164, 0.0013873322, 0.07171806, -0.023748612, -0.027877348, -0.099459775, -0.03033671, 0.073696665, 0.030475855, 0.01704109, 0.012375895, -0.02954333, -0.019610418, -0.063602366, -0.06293407, -0.0043150717, -0.004228505, -0.036013756, -0.036788046, 0.05620212, -0.010898958, 0.014881095, 0.063317485, -0.060158927, -0.008142738, 0.06246911, 0.0015545533, -0.0327758, 0.023140343, -0.051800247, 0.038916364, -0.006682154, -0.021051304, 0.021457419, 0.033587493, -8.823798e-05, -0.06727047, 0.06973627, -0.004236397, 0.024015909, -0.01210447, -0.028315732, -0.032067746, -0.018788643, 0.04945082, 0.0036923587, 0.013326614, 0.018340075, 0.029659383, 0.050455347, 0.013976186, 0.03443311, 0.050304387, -0.03637113, -0.013800043, 0.04530979, -0.0006481351, 0.008239906, 0.034968525, -0.01830898, 0.0068063573, -0.053750128, -0.018379966, 0.00046745554, -0.018483771, 0.081361115, 0.036600232, -0.003180567, 0.034444883, 0.06588035, -0.028914321, -0.00027604614, 0.017895991, 0.022538988, 0.01598838, 0.021661768, -0.04410282, -0.01651428, -0.015548872, -0.017190143, -0.040157657, 0.019950246, -0.06346032, -0.031546526, 0.025508627, -0.0042748065, -0.033107173, 0.062295243, 0.026450194, 0.023206262, 0.06904276, 0.026051365, 0.019436365, 0.06924312, -0.04841407, -0.053751484, 0.007477714, -0.0027891323, 0.0013912241, 0.019118758, 0.025028706, 0.12817673, -0.052691855, -0.04182658, -0.00714179, -0.037332125, 0.02774489, 0.04408458, -0.009787175, -0.0137098795, -0.031770416, -0.044364825, -0.005324471, 0.032101486, 0.020991687, 0.029249066, 0.062433377, -0.014937614, -0.059674986, 0.03255669, -0.027782688, 0.0040898896, -0.067739435, -0.0013901081, -0.005530454, 0.07508662, 0.027928876, 0.015382251, 0.019889178, -0.025817856, 0.021522209, 0.036175754, -0.0068338844, -0.030122302, 0.034052696, -0.010969484, 0.06780693, -0.031338967, -0.0901692, 0.041862577, -0.05916816, 0.025243718, -0.01804889, 0.037353676, 0.029721867, 0.022611134, -0.00561162, -0.02343679, -0.018891793, -0.033388354, -0.025810434, 0.020129433, -0.044581458, 0.019044552, 0.013590064, 0.053859837, -0.011600017, 0.03819082, 0.023442408, -0.058505725, 0.016262183, 0.08187502, -0.0037637122, -0.0073997653, 0.06274878, -0.042927034, 0.038207997, 0.025071122, 0.048849456, 0.03476461, -0.017111573, 0.0065474734, 0.04561811, -0.009443265, -0.0715335, -0.04482328, -0.011604169, 0.04052291, 0.012108156, 0.030277241, -0.0020766037, -0.028903153, -0.029946111, 0.01897969, -0.04836673, 0.04674478, 0.002275566, 0.028353078, -0.021606384, -0.001990024, -0.024348633, 0.05410748, 0.0067285146, 0.009018802, 0.02120824, -0.026882783, -0.023273552, -0.06618962, -0.011052104, 0.051011972, -0.05195798, -0.068032645, 0.031294424, 0.0067782886, 0.016281288, 0.029986901, 0.0035789153, 0.03967168, -0.030021943, -0.021339854, 0.011290146, 0.016510949, 0.04616619, -0.026625305, -0.045626044, 0.03308425, -0.016166097, 0.003080545, -0.0025927073, -0.053743653, -0.023147997, 0.020883132, 0.0071945637, -0.07142522, -0.05498592, -0.0066575324, -0.008384548, 0.06561856, -0.03798415, -0.037033428, -0.0036052011, -0.07590886, 0.02061544, -0.06972096, 0.015086707, 0.027300602, -0.011845893, -0.06050376, 0.019287422, 0.044613253, 0.029209524, -0.05253632, -0.04778985, -0.0259414, 0.04880921, 0.061600517, 0.04378635, 0.021030057, -0.033455346, 0.020830134, 0.015467308, 0.06451422, -0.013394385, 0.00794779, -0.015200834, 0.038035847, -0.036819186, 0.04574901, -0.044204276, 0.028958773, 0.009407912, 0.01525936, -0.062978916, 0.05300022, -0.016457735, -0.020693444, -0.029401798, -0.020639801, -0.023301095, -0.03749184, -0.017695358, 0.020514863, -0.004300528, -0.0062540337, 0.039481174, -0.037857212, -0.047187306, 0.030509615, 0.0963482, 0.0017670164, 0.01214917, 0.057562664, -0.048511773, 0.0032931748, 0.045147505, -0.0063412474, 0.033765048, 0.0018233988, 0.06542811, -0.056105193, -0.030418295, 0.03664008, -0.035028465, -0.0021512513, -0.010438304, -0.009246807, -0.022026075, 0.034778506, -0.008033392, 0.014973402, 0.031786952, -0.015541432, 0.03013826, -0.038646515, -0.0071214642, -0.04690987, -0.05221237, -0.048153695, 0.017477494, -0.008764498, -0.039612606, -0.020558845, 0.057209387, 0.09089033, 0.009344879, 0.014453023, 0.0046271235, 0.047276407, -0.031111078, 0.014519955, -0.014393582, 0.032673206, 0.0754012, 0.003260783, 0.017340802, 0.0026388634, -0.03395302, -0.09052871, 0.01957076, 0.02313459, -0.017635383, -0.035773925, -0.066307746, -0.032888096, -0.021767173, 0.025388291, -0.021413492, -0.019211795, 0.0056617945, -0.00043064237, 0.0052286442, 0.033992514, 0.04140032, -0.029350653, -0.02011501, -0.012518799, 0.06552335, -0.010573514, 0.007041848, 0.07249444, -0.0025394948, -0.04431915, 0.02934329, 0.006880606, -0.07342058, -0.0064410097, 0.039809413, 0.008865643, 0.026518518, 0.022651661, 0.03865922, -0.036452554, 0.015143161, -0.0076236897, -0.022465542, -0.0299486, -0.001948201, 0.059736315, -0.017041476, -0.009741406, 0.013766012, 0.010593223, 0.008648345, -0.01904887, -0.058119904, -0.059165582, -0.029428244, -0.044569578, 0.03394445, -0.08456024, 0.052219853, 0.0018710365, -0.06826962, -0.025574267, 0.0015476929, -0.01859397, -0.00699206, 0.03403487, 0.004821799, -0.007860277, 0.040290926, -0.028861478, -0.020966131, -0.028188104, 0.046340007, -0.065610744, 0.0049762577, -0.056262072, 0.014727484, 0.042378865, -0.0015105443, -0.016009176, 0.03298992, -0.0309785, 0.0098930085, -0.0128868185, -0.06581745, 0.055518992, -0.07093144, -0.011295005, -0.018255048, 0.042263385, 0.04650912, -0.021479465, -0.040635284, 0.020445675, 0.04396692, 0.034479734, -0.04652897, 0.012911873, 0.00818871, 0.028080922, -0.053437654, -0.01278611, -0.03118865, 0.00084422954, -0.03095396, 0.097957194, 0.022326827, 0.055423204, -0.021962, 0.009884309, -0.01507914, 0.0022355353, 0.056271452, -0.09506677, 0.014385446, 0.011772169, -0.019363593, 0.018923447, 0.019027594, 0.0397291, -0.0057024346, 0.014354398, 0.058533356, -0.03771455, 0.0016542764, -0.023116902, 0.031977143, -0.0024227232, 0.05015547, -0.019928161, -0.08171058, 0.0063682613, 0.03979795, -0.058225155, 0.021815812, -0.0013611955, -0.025291279, 0.00074593467, -0.04067745, 0.03629181, -0.08005236, 0.018536981, 0.017565228, -0.0247323, -0.016964061, 0.013546188, 0.029501094, -0.04139717, 0.028966127, 0.010443858, 0.032063928, 0.01737508, -0.033715792, 0.005173619, -0.037534066, -0.0916218, 0.03578557, -0.036030255, -0.022038762, -0.013527934, 0.052591022, -0.030108724, 0.03878443, -0.009779705, -0.0041205566, -0.016188866, -0.0055203596, -0.0064403857, -0.054902557, 0.054920226, 0.015885923, 0.010718261, 0.055153657, -0.010324694, -0.009820035, -0.010448323, 0.06666592, -0.06767029, -0.01635904, -0.03185411, -0.0015366019, 0.0143762, 0.05778025, -0.05519335, 0.013229535, -0.006073038, -0.059700865, 0.036485776, 0.027370136, 0.0012069022, 0.0009872833, 0.027286474, 0.00019659728, -0.02920763, 0.03839712, 0.05115578, 0.027060319, -0.044736844, -0.026224691, 0.05110946, -0.029575067, -0.02745467, 0.00031391255, -0.007439323, 0.03823171, -0.022997072, -0.045585867, 0.02876602, -0.006106302, -0.035401046, 0.041062158, -0.016842516, 0.037892357, 0.04317294, 0.01804814, 0.029144851, 0.021018928, 0.015603451, -0.011999006, -0.030720627, -0.009711528, -0.052484434, -0.05552642, -0.031298906, 0.05083351, 0.05287082, -0.031856723, -0.06333419, 0.03458077, -0.014195608, 0.008421349, 0.013310852, 0.019847808, -0.01917335, -0.015233831, 0.010180664, 0.06434256, 0.057029128, 0.066450045, 0.017172951, 0.06426091, 0.009713494, -0.026966866, -0.022918513, -0.07316935, -0.015887445, 0.012158466, 0.009167215, -0.0749836, 0.01846572, -0.013664896, -0.037279043, 0.00076408434, 0.0114998445, -0.022741795, -0.06233905, -0.0106479, -0.0012268012, -0.047632836, -0.027751103, 0.029267572, -0.022706807, 0.057720724, 0.0030818353, 0.021241609, -0.015011915, 0.034052487, -0.036724526, -0.043025654, 0.02293272, 1.1932892e-05, -0.00096595497, -0.004044761, -0.054462556, 0.00919402, -0.06741997, -0.01006735, 0.019230593, -0.049240593, 0.008891811, 0.04615782, -0.0043172715, 0.050505605, 0.027413681, -0.04688586, 0.05668945, 0.012883582, 0.010813096, -0.032242477, 0.014298584, -0.009915224, -0.009893459, -0.030812487, 0.018036788, -0.0007038884, 0.0069540585, -0.03761857, -0.054132156, 0.0028590257, 0.019310834, -0.014690494, 0.039879426, 0.06570338, 0.01566235, -0.03020141, -0.026345247, 0.03707188, 0.07692084, -0.021125276, -0.035064135, -0.013396917, 0.029646033, 0.04357418, -0.0342317, 0.0076841908, 0.019414425, 0.003848162, 0.04626723, 0.022946337, -0.019249706, 0.033979155, -0.008311704, -0.0033839128, -0.06217221, 0.0046183732, -0.0065375776, -0.0177113, 0.003994493, 0.042487025, 0.014396898, 0.024168009, -0.04208569, -0.08723568, 0.04747193, -0.032119043, -0.034121774, -0.0053762463, 0.033899, 0.005765396, -0.042249765, -0.029593723, 0.031622533, -0.039944682, 0.07437871, 0.024578895, 0.033653848, 0.0036801752, -0.08450767, -0.020110808, -0.019222947, 0.008281644, 0.025453506, 0.05045007, -0.055548068, -0.036458623, -0.055234835, 0.016951289, -0.029446403, -0.031270936, -0.035392717, -0.01885009, 0.009011577, 0.066162616, -0.04763524, -0.01938243, -0.0047225277, -0.004209129, -0.010195206, -0.02350366, 0.0039373157, 0.005620795, -0.006771715, 0.040239833, 0.032540698, -0.02612464, 0.04612531], "eb04d635-c6d9-411d-8d43-fffdbf9963c8": [0.0019265021, -0.06162956, -0.040496815, 0.0051854947, 0.04611832, -0.0037965463, 0.02262821, -0.005813671, 0.009001214, 0.022603355, -0.044921063, 0.022526281, 0.009383474, -0.02551281, 0.00033160223, -0.07127107, 0.0040732175, 0.04368011, 0.020667192, -0.0031373352, 0.0013909311, -0.0060444707, 0.035355985, -0.043978807, -0.031136923, -0.05202195, -0.0027891307, -0.07746709, -0.04157943, 0.056200836, -0.027742313, 0.0352351, -0.029344274, 0.048990097, 0.013163509, -0.02651134, 0.016177932, 0.071970664, -0.004236448, -0.013303469, 0.020442782, -0.0454235, 0.0076065673, 0.011295916, -0.008771205, 0.013310138, -0.014755841, -0.0044590035, -0.0039058463, -0.06996649, 0.0051622977, -0.0043117222, 0.059127506, 0.010999171, 0.008329075, -0.022197116, -0.00570594, -0.0119659025, -0.0020324695, 0.009915387, -0.00729157, 0.025817452, -0.024019556, 0.017163573, 0.0072772433, -0.039584342, -0.047774356, 0.0068154214, 0.021026148, 0.0004192272, -0.015198496, -0.014316956, 0.08122834, -0.039490316, -0.009347933, -0.12211327, -0.010210872, 0.06373346, 0.028640555, 0.028711678, 0.029323315, -0.047656823, -0.028004302, -0.057859775, -0.06692304, 0.014046752, -0.022229517, -0.03211548, -0.035822976, 0.06890932, -0.008764494, -0.033546485, 0.060833093, -0.06009119, 0.0022933527, 0.063172504, -0.008396711, -0.03382579, 0.030410843, -0.046045184, 0.007908168, 0.007307499, -0.037933987, -0.033270244, 0.032018483, 0.008248995, -0.06528957, 0.06948999, -0.014969685, 0.0023724441, 0.0041459124, -0.011109987, -0.031439282, -0.03194384, 0.07977244, -0.011573395, 0.02568874, 0.04532163, 0.02590897, 0.04184341, 0.018111954, 0.031221684, 0.017537935, -0.05107229, -0.046149477, 0.034838796, 0.016883237, 0.022166288, 0.03712023, -0.018218363, -0.0027082765, -0.0309117, -0.019350534, -0.0049475497, 0.007371661, 0.09043514, 0.034879994, 0.01264823, 0.009296162, 0.06429091, -0.028744066, 0.010680139, 0.02503849, 0.031109735, 0.011530831, 0.02934321, -0.025907656, 0.013295312, 0.0097014075, -0.02590554, -0.039849017, 0.018503457, -0.059463132, -0.026043087, 0.036212325, 0.009747116, -0.043752838, 0.049637586, 0.026051717, 0.010040904, 0.057007313, 0.016997779, 0.014041555, 0.059766527, -0.028055554, -0.018001156, 0.026036933, 0.028142883, -0.0026527443, 0.022187455, 0.0023092204, 0.12208915, -0.046650738, -0.050308295, 0.008184802, -0.026671842, 0.03989906, 0.046320412, 0.0063755447, -0.029164143, -0.0060585584, -0.04805156, -0.0001259348, -0.00020717201, 0.02928345, -0.0074098897, 0.07006709, -0.016237978, -0.040026415, -0.0041522067, -0.02392177, -0.0008492301, -0.038403656, 0.011735122, -0.007441964, 0.045847338, 0.016651085, 0.008183982, 0.038124606, -0.034680687, 0.03004276, 0.017380811, -0.0024967461, -0.013919103, 0.049176816, 0.0016336072, 0.06432746, -0.038800925, -0.0790089, 0.020201584, -0.05176153, -0.0036301294, -0.014739262, 0.04396952, 0.012252265, 0.012520937, 0.00758529, -0.003108058, -0.024018444, -0.063263424, -0.0202963, 0.014690761, -0.029280454, 0.021398177, 0.022273079, 0.06671052, -0.019054843, 0.033678938, 0.031865396, -0.042937268, 0.013396499, 0.0645321, 0.0052070427, -0.00895646, 0.050370447, -0.033076327, 0.036005914, 0.025823759, 0.034034725, 0.0074797436, -0.035355266, 0.011454422, 0.056700453, 0.012424757, -0.07139529, -0.050087858, 0.004032849, 0.050183434, -0.011559295, 0.0015696541, -0.06291146, -0.04450657, -0.014772951, 0.018944666, -0.03097337, 0.069811426, 0.0020023251, 0.004842232, -0.039375845, 0.004544852, 0.008009263, 0.07186661, 0.014873769, 0.01553506, 0.025009282, -0.037081257, -0.014856784, -0.06424582, -0.030250315, 0.033577934, -0.06691736, -0.06337095, 0.02517666, 0.022006333, 0.0051877364, 0.024626095, -0.010127123, 0.034032546, 0.006254262, -0.009643867, 0.018670805, 0.022698864, 0.0400208, -0.021681909, -0.036158167, 0.009833666, -0.0094870785, -0.009740138, -0.017111033, -0.057598084, -0.018474126, -0.005250477, 0.010857224, -0.08018364, -0.03846106, 0.0017705532, 0.016258573, 0.05539077, -0.02469067, -0.05805475, -0.007591027, -0.07573125, 0.010726089, -0.06931168, 0.03560489, 0.006892549, -0.017249431, -0.061076697, 0.018598862, 0.057920877, 0.0478473, -0.041513287, -0.05975471, -0.012580596, 0.07372282, 0.065387085, 0.04462931, 0.006122164, -0.04372886, 0.020770472, -0.012872488, 0.061949763, 0.01354653, 0.0049280655, -0.02539824, 0.039923552, -0.04990915, 0.013111223, -0.040834505, 0.046368685, 0.017089944, 0.009931556, -0.02598961, 0.048322238, -0.022391817, -0.006931018, -0.05674551, -0.0135116335, -0.03669947, -0.02836563, -0.014420576, 0.022877771, -0.008714432, -0.02362363, 0.04989347, -0.016569795, -0.05405525, 0.019050548, 0.10903884, 0.0051971055, 0.0066536586, 0.045588292, -0.040447854, -0.0011031531, 0.040778972, -0.010537127, 0.0373783, -0.011023482, 0.0897676, -0.059725363, -0.040733874, 0.020355672, -0.033687983, -0.014451927, 0.011460626, -0.010176939, -0.016078556, 0.050533276, -0.019284166, 0.024441512, 0.004119248, -0.036250956, 0.012792928, -0.024201896, 0.0064069666, -0.008730039, -0.03507326, -0.04871947, 0.020138651, -0.008350007, -0.0685444, -0.010175372, 0.025412617, 0.0643952, 0.019902704, -0.015598517, 0.026019512, 0.0158846, -0.018350102, 0.026045557, -0.024960157, 0.046227142, 0.06699232, -0.0011590573, 0.036044493, -0.019144459, -0.031906206, -0.08070133, 0.04379033, 0.01976837, -0.012434917, -0.017843783, -0.07090187, -0.03623467, -0.021588024, 0.029324546, -0.016713725, -0.051953148, -0.0037593867, -0.004814164, 0.015193529, 0.029361201, 0.033859957, -0.01307031, -0.038665276, 0.01240371, 0.06674181, -0.033553366, 0.009824119, 0.028933877, -0.015896816, -0.03991109, 0.022597069, 0.01993429, -0.087010905, -0.04014994, 0.012862792, 0.02405555, 0.021875994, 0.024662515, 0.0494198, -0.021647483, 0.018870981, -0.005813663, -0.016511764, -0.026773954, 0.0013839671, 0.050139837, -0.009192879, -0.023147011, 0.018556364, -0.009898052, -0.016472422, -0.018668266, -0.04681387, -0.042342845, -0.009903007, -0.039697878, 0.036622826, -0.08836583, 0.025411146, -0.018038886, -0.066629216, -0.032768197, 0.017140247, -0.015628647, 0.0012111021, 0.031091643, -0.00022973679, -0.025270892, 0.058983892, -0.02793903, -0.03732593, -0.038017713, 0.066150375, -0.07809672, 0.0063955286, -0.06255056, 0.026180072, 0.037618756, 0.021667892, 0.00024342125, 0.03196584, -0.061699666, -0.01993321, -0.0025830024, -0.0636491, 0.06728848, -0.057091005, 0.0028581347, -0.023797967, 0.04389388, 0.031128991, -0.029869901, -0.050862383, 0.0051021394, 0.024997283, 0.025411086, -0.04876894, -0.0034795187, 0.002523676, 0.019682145, -0.05357617, -0.031057967, -0.003608901, -0.019133579, -0.017194387, 0.09996339, 0.016022379, 0.04802904, -0.010918832, 0.024431452, 0.014391417, -0.012405585, 0.028204711, -0.094599016, 0.030248517, 0.019774728, -0.029653765, 0.013577919, -0.0057110162, -0.0026602314, -0.026604252, 0.0008552477, 0.06214526, -0.049604338, 0.0035939503, -0.017118884, -0.0011908644, 0.0034190314, 0.009369845, -0.016473496, -0.06866124, -0.005302845, 0.05773276, -0.08695541, -0.018691465, 0.013481396, -0.045256913, 0.014351317, -0.021175541, 0.038167775, -0.0621248, 0.016783006, 0.027186764, -0.019461304, -0.006171492, -0.0045449533, 0.028939683, -0.043422993, 0.030476494, 0.02909117, 0.0421711, 0.02399143, -0.06892502, -0.0037526009, -0.035349485, -0.08361971, 0.03374962, -0.030316684, -0.05527424, 0.0076554073, 0.050907183, -0.019856121, 0.036795374, -0.03659147, 0.016370485, 0.00467345, 0.011575887, -0.016126642, -0.038561046, 0.041966535, -0.0030533036, -0.012039513, 0.04167514, -0.04321688, -0.011044564, -0.007324095, 0.053548615, -0.06577419, -0.032732584, -0.031613514, 0.012765521, 0.026093734, 0.061635375, -0.06987801, -0.011462272, -0.018407619, -0.065027215, 0.011345962, 0.023450483, -0.0061678714, -4.522249e-05, 0.04266315, -0.027644811, -0.022275671, 0.04081572, 0.03552086, 0.03510464, -0.038328815, -0.027798582, 0.057985075, -0.03347874, -0.06610127, 0.007585655, 0.0075244005, 0.04168486, -0.035794552, -0.033304106, 0.037795234, 0.0072093927, -0.021400495, 0.0645989, -0.02301357, 0.044117652, 0.05140804, 0.037277292, 0.025452225, 0.039978143, 0.004555923, -0.011392704, -0.017510874, -0.017772377, -0.04021153, -0.052332357, -0.020558495, 0.07614214, 0.045916274, -0.016327765, -0.053734884, 0.04094652, 0.013561288, 0.0092465095, 0.013256853, 0.030074751, -0.005489892, -0.024559798, -0.010399166, 0.08011043, 0.057433825, 0.056129593, 0.02109423, 0.038168043, -0.011221485, -0.04101278, -0.008320581, -0.062136527, 0.0059296037, 0.040416207, -0.005170856, -0.08981858, -0.008239033, -0.03770166, -0.02136936, 0.027952785, 0.008527726, -0.00020240384, -0.08945283, -0.02313903, -0.01671495, -0.056180574, -0.0049148174, 0.024279589, -0.052686848, 0.045700785, -0.0055583804, 0.035646662, -0.00412824, 0.032827158, -0.029142976, -0.047367703, 0.025921436, 0.019681305, 0.014468058, -0.02117584, -0.056284063, 0.0038069964, -0.052800484, -0.043032702, 0.015905948, -0.042259537, 0.0199606, 0.031759232, -0.0041592573, 0.041691713, 0.033215422, -0.007905442, 0.056798227, 0.019989638, 0.012111727, -0.028877508, 0.017575182, -0.008310268, -0.028277727, -0.009070107, 0.006045032, 0.0003434715, 0.028013175, -0.046392918, -0.05025718, 0.0017327471, 1.4205224e-05, 0.003719512, 0.011702853, 0.07480594, 0.012611621, -0.020702241, -0.037530065, 0.034226794, 0.059862237, -0.008531507, -0.065709196, -0.019232597, 0.020865062, 0.014866149, -0.043154243, -5.9566333e-05, 0.031582523, -0.00060471037, 0.023770427, 0.035791356, -0.029818466, 0.013375438, 0.022028672, -0.010924728, -0.058241107, -0.00055730814, -0.0048449337, -0.008878859, 0.005501292, 0.016025156, 0.0053201285, 0.005694332, -0.00625626, -0.07922892, 0.039160255, -0.035943832, -0.009378322, 0.005024824, 0.01969016, 0.023261836, -0.0455829, -0.009732185, 0.039519154, -0.025506733, 0.07368471, 0.019641133, 0.019190604, -0.000560127, -0.08624114, -0.019916382, -0.016403787, -0.012946459, 0.039387304, 0.048855525, -0.06504147, -0.014476084, -0.055207662, 0.027400035, -0.031095989, -0.034048215, -0.0026530996, -0.032550305, -0.0007686487, 0.03675454, -0.04292119, -0.017604265, 0.006658093, -0.009520675, 0.00530397, -0.015079296, 0.007739821, -0.0069623343, 0.016325256, 0.04409792, 0.021750357, -0.015682591, 0.061032176], "0f57e92b-7644-4f0d-a6bd-5e039a0228d1": [0.0034568335, -0.064391635, -0.036742635, 0.021978546, 0.027109167, -0.009057403, 0.007600247, -0.008002013, 0.00095309876, -0.0011005853, -0.002097404, 0.023244312, 0.011526132, -0.0043042055, -0.0035316227, -0.05588166, 0.0033919918, 0.018360494, 0.01693514, -0.043026805, -0.0046988316, -0.013592416, 0.00017037572, -0.042473465, -0.008143828, -0.021942642, -0.002878827, -0.07569881, -0.030294195, 0.06878331, -0.0066680466, 0.012956739, -0.032749698, 0.03770709, 0.0054613026, -0.039498992, 0.012623216, 0.046385974, 0.036304954, -0.0005640243, 0.007829161, -0.041084725, -0.027403405, 0.0075169634, -0.01990284, -0.015730208, 0.006549537, 0.008434691, 0.039508764, -0.07907036, 0.018304726, 0.024781177, 0.064035304, -0.014816098, 0.056647547, -0.023790294, 0.008436222, -0.042772885, -0.0055881315, -0.0131032895, 0.0021551533, -0.002920415, -0.032003827, 0.005539932, -0.0009898782, -0.010670334, -0.10962636, -0.0134414835, 0.010346971, 0.0113612395, 0.0033058047, 0.038943827, 0.06681381, 0.0155078685, -0.030331848, -0.096964374, -0.03865995, 0.07130417, 0.021851277, 0.0479883, 0.044506874, -0.04500858, -0.040183224, -0.06814732, -0.069528304, 0.017938877, -0.031241657, -0.046921663, -0.030669251, 0.045586135, -0.006100244, -0.010061776, 0.019701153, -0.0026448464, 0.011347481, 0.081346974, -0.0052010324, -0.06364459, 0.055480547, -0.06495193, 0.04631336, 0.03350861, 0.0108158095, 0.023496429, 0.02721918, 0.065487415, -0.055958442, 0.040796433, -0.008532669, -0.00904224, -0.036396686, -0.002817568, -0.006305701, -0.054284424, 0.070620835, -0.045853276, 0.022000486, 0.06082404, 0.013858771, 0.01351072, 0.032802008, 0.026543288, 0.023905227, -0.043165404, -0.036180206, 0.045556888, 0.025655318, 0.023247674, 0.062845655, -0.011773858, -0.0018834841, -0.017786803, 0.0049440763, -0.00012967394, 0.020003028, 0.05940901, 0.047106083, -0.0050097364, 0.0107948305, 0.018010542, -0.011536278, -0.009519133, 0.033251807, 0.035854414, -0.03542225, 0.037874777, -0.025141621, -0.007349836, -0.0071949437, -0.02608856, -0.049277753, 0.04353151, -0.06498158, -0.018294076, 0.024811283, -0.009759971, -0.01571817, 0.028964076, 0.027535673, -0.006747649, 0.0631313, 0.04332942, 0.015412052, 0.052435704, -0.03659593, -0.022573017, 0.030249974, 0.0008805879, 0.018523635, 0.019568698, 0.008073867, 0.12170016, -0.06883438, -0.059304915, 0.0011458978, -0.013914678, 0.03420946, 0.03374624, 0.0078292275, -0.011646573, -0.055642836, -0.046266817, -0.0258716, 0.040051837, 0.057370342, 0.025306275, 0.09251374, -0.030938195, -0.050210953, -0.012587995, -0.03615459, -0.001432479, -0.04577059, 0.03199769, -0.019951442, 0.055791456, 0.00574505, 0.04998229, 0.03271102, -0.03131346, 0.017710827, 0.06984691, 0.015542572, -0.0094904015, 0.046081014, -0.01832228, 0.06443147, -0.054801885, -0.057849765, 0.053757053, -0.045443796, 0.020583509, 0.0049979324, 0.04428657, 0.01599728, 0.013335532, -0.003179339, -0.0037943146, -0.003802914, -0.032092392, -0.0196419, 0.00688131, -0.025133446, 0.023491424, -0.028798977, 0.046875548, -0.0076128608, 0.014641362, 0.03651221, -0.047990397, 0.03585515, 0.06935772, 0.013978824, 0.0040564993, 0.048802104, -0.00044168028, 0.028222712, 0.028914103, 0.03864742, 0.056386024, -0.04186045, 0.024662135, 0.035144344, 0.00044316656, -0.09503441, -0.031696122, -0.0010793946, 0.059531547, 0.037219558, -0.00050247007, -0.04643367, -0.022742795, -0.038670216, 0.0012602339, -0.011416065, 0.04507972, -0.0032958589, -0.012959267, -0.0103007, -0.005649785, -0.00094296696, 0.031094633, 0.025260627, 0.005090741, 0.031894363, -0.032912053, 0.0027403717, -0.050499454, 0.027923776, 0.079101674, -0.03283373, -0.07631004, -0.008412405, 0.009678278, 0.027279457, 0.008496661, -0.0023588387, 0.019787917, -0.007431538, -0.018304631, 0.0049580582, 0.0045109554, 0.054172665, -0.021088213, -0.03426919, 0.02226661, -0.014928213, -0.0414242, -0.02565567, -0.06425739, 0.023606576, 0.0045990227, 0.006357003, -0.07867495, -0.065733254, 0.030070325, 0.0067470265, 0.028851198, -0.019476317, -0.0054288665, -0.019241791, -0.039040487, -0.0006915397, -0.050312467, 0.0076420535, 0.00712655, -0.038690098, -0.054427475, 0.026097871, 0.019226, 0.04155036, -0.025494691, -0.011772471, -0.0067975246, 0.070589334, 0.051307213, 0.043656584, 0.008299609, -0.046767678, 0.01516355, -0.019400688, 0.04693061, 0.0013824983, -0.004872768, -0.044383567, 0.06271946, -0.048243433, 0.0011643819, -0.037498947, 0.0100888, 0.02544928, 0.010388445, -0.035469383, 0.0353395, -0.0059035714, 0.0021829694, -0.037922848, -0.052057672, -0.021033451, -0.0330386, 0.016444711, -0.01603994, 0.0025154036, -0.007854959, 0.023713266, -0.019547865, -0.06887958, -0.0070601813, 0.120630994, -0.011109312, 0.008360318, 0.046502475, -0.04518779, 0.00021899623, 0.044843517, -0.0052271015, 0.010324065, 0.017106034, 0.09361394, -0.060507607, -0.03389716, 0.009707386, -0.03777302, 0.018412396, 0.018897278, -0.01764462, 0.011567334, 0.031895686, -0.023540074, 0.016806277, 0.015918665, -0.012093924, 0.020309623, -0.034212094, 0.010619278, -0.0054977695, -0.025029123, -0.05289087, 0.02405488, -0.006937712, -0.025574867, -0.019276164, 0.022655955, 0.042944957, -0.0009067763, 0.003954322, 0.025461081, 0.044434804, -0.020263074, 0.05775088, -0.0115069635, 0.028136263, 0.08041197, 0.00922804, 0.00056534645, -0.00069735415, 0.003289114, -0.08924045, 0.016892966, -0.002183652, -0.026986225, -0.055598777, -0.07009484, -0.037937142, -0.0073317178, 0.01426508, -0.039420035, -0.0875671, 0.0017613948, 0.03582048, -0.005627385, -0.008795992, 0.030623864, -0.04475591, -0.05940716, 0.01235298, 0.041333936, -0.015129726, 0.017964272, 0.03522283, -0.0077945446, -0.045821324, 0.0043893596, 0.015264262, -0.045578193, -0.0355238, 0.037690725, -0.008031361, 0.024557808, 0.030222466, 0.04605042, -0.045590762, 0.051329147, -0.011826469, 0.008998461, -0.013765889, -0.012127799, 0.050073262, -0.024368431, 0.0073590376, 0.04966553, -0.0028701397, -0.021989187, -0.016330337, -0.037445806, -0.053942006, 0.0012026336, -0.04969061, 0.022186331, -0.053456523, 0.029987771, -0.020404218, -0.06836803, -0.011822947, 0.013283399, -0.04131928, -0.009808341, 0.02258854, 0.008475982, 0.0105936285, 0.05525041, -0.04264641, -0.01954558, -0.04738329, 0.059491783, -0.05474736, 0.01763611, -0.054044116, 0.02783334, 0.03683039, 0.010439192, -0.044803604, 0.027198594, -0.068417765, -0.027910374, -0.018884907, -0.06171872, 0.04154555, -0.064364284, -0.008998637, 0.008197296, 0.041570876, 0.041176755, -0.055768102, -0.03504732, 0.035111133, 0.04311994, 0.00523051, -0.04121845, 0.055118773, 0.0004501275, -0.0042790975, -0.010033609, -0.06861437, -0.015596392, -0.020397814, -0.04868392, 0.08761122, 0.0151616195, 0.034444492, -0.03883628, 0.00990614, 0.0015640144, 0.00031797567, 0.063568674, -0.0664031, 0.016786782, 0.0037397654, -0.03094217, -0.015144834, 0.0034393014, 0.035001043, -0.032403894, 0.023583436, 0.05860912, -0.050153427, -0.017349223, -0.005854398, 0.028339894, 0.0013055513, 0.023762707, -0.011840725, -0.044474613, 0.00074322545, 0.045367535, -0.053094737, -0.023079297, 0.01960814, -0.03963502, -0.0021359364, -0.030477624, 0.020597681, -0.06586777, 0.034945995, 0.022419076, -0.012843678, -0.008043234, -0.0021510408, 0.018504232, -0.044420894, 0.029745584, 0.022982506, 0.021502802, 0.052170545, -0.030970637, -0.0057599046, -0.0065822876, -0.10357367, 0.00800004, -0.050983094, -0.025977364, 0.042639825, 0.027953587, -0.007023218, 0.049335115, -0.029614605, -0.000997428, 0.0067768143, 0.012565284, -0.051110744, -0.04716734, 0.04088393, 0.009501524, -0.020689322, 0.052893102, 0.0026625984, -0.009890033, -0.010147988, 0.06903787, -0.073242866, -0.006736887, -0.028902505, 0.029338049, -0.008371588, 0.06302587, -0.06875299, 0.014541894, -0.0016199122, -0.076651126, 0.035553627, 0.05987138, 0.0020002795, -0.0109954225, 0.049822185, -0.039989416, -0.017844733, 0.01530663, 0.045504797, 0.030460399, 0.00056606135, -0.042307436, 0.049094316, -0.018786948, -0.028372431, -0.029414799, 0.03753302, 0.007394001, -0.030290117, -0.03933099, 0.033539817, -0.02524337, -0.06360653, 0.041005455, 0.0010213756, 0.055742778, 0.010734028, 0.02293986, 0.034218784, 0.028302554, -0.0013581433, -0.013010892, -0.021309206, 0.008975078, -0.069695376, -0.031649455, -0.010749256, 0.07489479, 0.031624533, -0.017132437, -0.034417648, 0.05871006, 0.027447667, 0.034946293, -0.01685509, 0.025915077, 0.04378204, -0.048504174, 0.019509489, 0.063310996, 0.05662395, 0.061210062, -0.00804227, 0.0596641, 0.0073663676, -0.04950206, -0.018931821, -0.067386165, -0.005724462, 0.032374308, 0.014596216, -0.06392323, -0.008847786, -0.021982735, -0.012444769, -0.024311813, 0.004846107, 1.6815263e-06, -0.080354035, -0.06795929, 0.0030046874, -0.053798243, 0.02699662, 0.037752274, -0.029797718, 0.0566251, -0.011561497, 0.0049283057, -0.0124314865, 0.024697723, 0.008744769, -0.044387028, 0.045093756, 0.038822517, 0.024929961, -0.012212699, -0.042437732, -0.0003834518, -0.057053067, -0.04867633, 0.031434022, -0.060743563, -0.025635771, -0.00091880985, -0.045980293, 0.01998794, 0.004388716, -0.018683355, 0.042588625, -0.013521854, 0.016051501, -0.027636241, -0.033675674, 0.008997618, -0.022992548, -0.008849766, 0.020030702, -0.018015714, 0.020406624, -0.05658562, -0.017531602, -0.0029398678, 0.0034368832, 2.2176162e-05, -0.023362463, 0.04983894, 0.017375886, -0.019341128, -0.034602612, -0.0045956075, 0.07083599, 0.0028517158, -0.026241945, -0.04142211, 0.0029648638, 0.036815565, -0.0026497466, 0.02257979, 0.04849968, 0.0060983775, 0.00850028, 0.00046435418, -0.044240627, -0.005583121, 0.005036855, -0.0015294388, -0.05421279, 0.006066, -0.027871205, -0.058689658, -0.03413742, 0.04028169, 0.009361554, 0.021974279, -0.033130653, -0.0551864, 0.051876478, -0.03507066, -0.008676656, -0.006049319, -0.0020138014, -0.0014158728, -0.054633915, -0.008131088, 0.04178853, -0.047015775, 0.07559636, 0.021057824, 0.018239507, -0.0060652643, -0.07677354, -0.00026717398, -0.008669981, -0.034205347, 0.03657646, 0.06388102, -0.03383116, -0.026649535, -0.013987406, -0.025501283, -0.048348352, -0.054841217, -0.001914805, -0.02018778, 0.067666955, 0.04115917, -0.041106585, 0.008315216, -0.0051586544, -0.019085716, 0.026647788, -0.029670557, 0.003974396, 0.013034682, -0.0005868189, 0.03389384, -0.004451791, -0.0029730725, 0.010654164], "db26e25e-87d0-4733-a486-40d71ccd51c6": [0.012845981, -0.057604406, -0.028221885, 0.032970447, 0.072186485, 0.019846337, 0.01920181, -0.004789988, 0.006718927, 0.013862136, 0.047152434, 0.05939298, 0.015253058, -0.00646325, 0.019551972, -0.08356028, 0.008929146, 0.045940373, -0.008838006, -0.059750255, -0.02749521, -0.053820368, -0.01016943, -0.04383953, -0.042419173, 0.010228272, 0.014276472, -0.0601227, -0.03799981, 0.036395382, -0.025961066, 0.024264188, -0.021319335, 0.031493228, 0.021161122, -0.018226119, 0.018775867, 0.049134944, 0.041089296, 0.038170125, 0.01106842, -0.0049624383, -0.023311578, 0.0028061129, -0.022280052, -0.011831604, -0.012743657, 0.029007053, 0.017575206, -0.053126708, 0.013667293, 0.017417332, 0.088612095, -0.0070378603, 0.03246672, -0.023107462, 0.028268142, -0.022393633, 0.014636003, -0.016317373, -0.0021827451, -0.0024723972, -0.03222986, 0.015866557, -0.0054583047, -0.0094297575, -0.06849074, -0.021474782, 0.0021980477, -0.0067894664, 0.020771997, 0.016950052, 0.07706586, -0.0037923097, -0.0427046, -0.11152686, -0.047028027, 0.07043692, 0.03424414, 0.020393154, 0.040976115, -0.054095507, -0.05220523, -0.049804848, -0.06719277, 0.00046012565, -0.03413031, -0.026447475, -0.036468673, 0.009472045, 0.00021197884, -0.005257177, 0.035368517, -0.007636979, -0.012173497, 0.07807974, 0.0112114465, -0.06455636, 0.0415583, -0.07358311, 0.04109205, 0.004541289, 0.0028546439, 0.026921995, 0.02542755, 0.072798185, -0.054847136, 0.046939764, -0.027978797, -0.0025730983, -0.04459689, -0.041206036, -0.005690196, -0.07437364, 0.059737016, -0.036153927, 0.025719356, 0.05912736, 0.004381349, 0.0029634885, 0.031073919, 0.009027971, 0.04862313, -0.011412732, -0.019661129, 0.041611522, 0.027257143, 0.01592763, 0.07086047, -0.0035206215, 0.011587689, -0.00089852366, 0.0067393854, -0.014619048, 0.027374491, 0.07707751, 0.017559545, -0.0077262293, 0.022702955, 0.043560848, 0.011251308, 0.026914733, 0.010324353, 0.0125514865, -0.035567667, 0.022540106, -0.03249699, -0.00747628, 0.021766368, -0.033854336, -0.035290215, 0.0062608523, -0.060544595, -0.051083323, 0.04736152, 0.024685146, 0.007842425, 0.050661135, 0.011694589, 0.043302674, 0.021902923, 0.060736723, 0.017296214, 0.038128443, -0.042453483, 0.0070188646, 0.020233637, -0.006374245, 0.0077217463, 0.00394554, -0.013044998, 0.11897172, -0.06157524, -0.06939051, -0.007065191, -0.02292575, 0.06574376, 0.053355467, 0.008060585, -0.015817817, -0.07549031, -0.030296165, -0.0101670865, 0.037049424, 0.03943472, 0.02805188, 0.06767231, -0.009895604, -0.026789987, 0.0034250524, 0.007982938, -0.009996053, -0.033947267, 0.03985385, 0.010244757, 0.03943661, 0.038722735, 0.024273789, 0.038639203, -0.058327474, 0.02138745, 0.06269354, 0.012084191, -0.013346833, 0.053047158, 0.0029392946, 0.037316673, -0.026767936, -0.06799683, 0.05094095, -0.06090547, 0.016095594, -0.007628935, -0.0010867597, 0.03845498, 0.005852614, 0.004949525, 0.024956193, -0.007332627, -0.00535119, 0.0051799696, 0.002823022, -0.031364974, 0.017042387, -0.032286283, 0.034076862, -0.019678272, 0.0134626, 0.04091534, -0.048054576, 0.021249628, 0.036581397, -0.0043807277, -0.005111538, 0.053104382, 0.012393382, 0.0016773244, 0.057743575, 0.044001326, 0.06452371, -0.028373834, 0.011337809, 0.034973223, -0.0035106489, -0.08634554, -0.026304377, 0.0132336505, 0.0066072666, 0.012327945, 0.028105453, -0.03171111, -0.04380215, -0.03654843, -0.002633314, 0.019265113, 0.07493132, -0.027240027, -0.035195798, 0.010575034, -0.016596125, -0.0014456724, 0.034585238, 0.023478905, 0.012384388, 0.014352475, -0.038023762, -0.00012857483, -0.06381966, 0.021378558, 0.06669072, -0.01669086, -0.049011253, 0.004832926, 6.95388e-05, 0.018698124, -0.014841245, 0.03536946, 0.0060135038, 0.006102355, 0.003939737, 0.0022589872, -0.0008712941, 0.02308667, -0.010717796, -0.02520619, 0.004794887, -0.04140592, -0.036016583, 0.00366148, -0.0702102, 0.0114025865, 0.019977188, 0.005159337, -0.07955875, -0.062319193, 0.033885412, -0.014956216, 0.053306513, 0.01012134, 0.00029321108, -0.009932267, -0.028777633, -0.027722599, -0.039048072, 0.01351267, 0.020049855, -0.024516074, -0.049341574, 0.019005938, -0.010966759, 0.023320107, -0.058216516, -0.0014186797, -0.006549121, 0.03698208, 0.026519509, 0.04177107, 0.028079141, -0.027796475, 0.02111338, -0.020741487, 0.03200794, 0.017371941, 0.009678489, -0.03834044, 0.06165409, -0.048105534, 0.02852138, -0.0012688909, 0.011666378, 0.050789777, -0.008484167, -0.047024462, 0.020736584, -0.0042503965, 0.007458155, -0.07769759, -0.04081121, 0.011798939, -0.018671198, 4.6697813e-05, 0.006717298, 0.015497226, -0.027473653, 0.026609078, -0.009673631, -0.064741865, -0.00328442, 0.088270396, -0.01271868, 0.039136466, 0.052870113, -0.038240116, -0.0027824887, 0.07798527, 0.027322873, 0.030192634, 0.021309357, 0.121612415, -0.036553435, -0.06982358, 0.01509282, -0.02702056, 0.012244012, 0.04184566, -0.01197942, -0.0028127325, 0.01610073, -0.014254417, 0.04936927, 0.0002558412, 0.011857993, -0.00541939, -0.028052747, -0.000785594, -0.021008564, -0.046873946, -0.047165103, 0.048337985, -0.011918039, -0.028482387, -0.007860438, 0.040236626, 0.040002894, 0.008200728, -0.024421992, 0.0012427339, 0.038347587, 0.01151021, 0.050304856, -0.03526242, 0.008750083, 0.047468808, -0.016774569, 0.014144492, -0.00034561034, -0.022874579, -0.07837406, 0.024352953, 0.004662603, -0.04068691, -0.047935653, -0.053883705, -0.037897244, -0.019414205, -0.028407943, -0.021495255, -0.08467891, -0.0024367794, 0.032139312, 0.024641128, -0.018885432, 0.03709336, -0.03909566, -0.030033177, 0.034592792, 0.04200976, -0.019047964, 0.025475489, 0.015609821, -0.04219784, -0.029002767, -0.017936802, 0.011986159, -0.07268056, -0.06226878, 0.0229266, -0.01650241, 0.051461812, 0.012834943, 0.05350871, -0.034610838, 0.06516451, 0.006378775, -0.010357973, -0.03065876, -0.020577746, 0.024115197, -0.03779799, 0.017498314, 0.041530088, 0.024816617, -0.015373154, -0.020482732, -0.027996682, -0.027998481, -0.007963695, -0.036386505, 0.03087951, -0.07747096, 0.045279637, -0.014360455, -0.048994496, -0.024146754, -0.0054552187, -0.071398236, 0.00755941, 0.036810495, 0.0039560953, 0.034823176, 0.043289945, -0.04903012, -0.025445255, -0.028093288, 0.042712525, -0.03545136, 0.025283713, -0.0569664, 0.014741636, 0.03636201, 0.022823013, -0.044949967, 0.03510351, -0.029504698, -0.008626771, -0.026307184, -0.050283153, 0.052420326, -0.04268834, 0.006151863, 0.013044553, 0.019460276, 0.02713716, -0.029768465, -0.024021061, 0.039839048, 0.054542914, -0.0031713936, -0.0041491115, 0.04545338, -0.026344506, 0.0024459043, -0.02158708, -0.054814875, -0.0035977447, -0.010529539, -0.069686785, 0.074290566, 0.049073413, 0.048007876, -0.024829214, -0.02367342, -0.016540108, -0.00013843806, 0.10365091, -0.059478205, 0.01785602, -0.016754422, -0.017161163, 0.000723225, 0.006078587, 0.045717627, -0.002376022, 0.0074438727, 0.069973476, -0.04532901, -0.020506734, -0.01703772, 0.026114292, 0.024519276, 0.05076676, -0.041650254, -0.10292704, 0.0032967734, 0.056734383, -0.063071266, -0.007934963, -0.0019880089, -0.061757665, -0.005966627, -0.020863194, 0.030864397, -0.070201665, 0.07021696, 0.03882433, -0.0035922173, -0.010729366, 0.029439447, 0.011205671, -0.010085394, 0.035795197, -0.0033242519, 0.06383946, 0.05576995, -0.025763554, -0.005014215, 0.021385696, -0.1030201, 0.00855903, -0.035065264, -0.041319303, 0.037295472, 0.011135138, -0.002459543, 0.041918807, -0.0039754324, 0.007870122, 0.014273868, 0.01181064, -0.031335503, -0.035426285, 0.041684084, 0.04452486, -0.0009916327, 0.045704935, 0.012652687, -0.031460114, 0.0055532516, 0.040808495, -0.08020583, 0.0072122924, 0.0010513214, 0.055688586, -0.041688155, 0.05142305, -0.04708694, 0.004612378, -0.003759412, -0.078527816, 0.026952427, 0.05354959, -0.0014500757, -0.016007723, 0.049495477, -0.033664126, -0.031957846, 0.03996192, 0.062673695, -0.009056985, -0.009137559, -0.05071238, 0.04448932, -0.04604109, -0.007018998, -0.01745544, 0.031578608, -0.0020998837, -0.028049314, -0.046572063, 0.01586411, -0.00049299723, -0.03551096, 0.05216081, -0.0039969417, 0.036591157, 0.008170432, 0.021205429, -0.005531449, 0.034505814, 0.002719819, -0.014115543, -0.033127245, 0.0154575845, -0.04796433, -0.034668528, -0.04078928, 0.09199318, 0.031246109, -0.03901123, -0.026314009, 0.05380596, 0.0292102, 0.028672667, -0.0046241865, 0.0028096288, 0.0077341567, -0.031839725, 0.014713902, 0.076425284, 0.039047536, 0.08582377, -0.011597841, 0.020717232, -0.029963765, -0.059380475, -0.027137885, -0.036732107, 0.0024232615, 0.03573363, -0.008669, -0.0331871, -0.008252467, 0.0038758828, -0.016504407, -0.0284953, 0.05346273, -0.023278495, -0.10753093, -0.066228844, 0.0017262085, -0.048423577, 0.018373443, 0.034163915, -0.013583164, 0.023665775, -0.007869757, -0.030282864, -0.006105255, 0.014812477, 0.0109767765, -0.03452725, 0.042400476, 0.035720028, 0.0047796774, 0.00344309, -0.02763738, -0.012235506, -0.06116074, -0.05143534, 0.0463321, -0.060275685, -0.011752143, 0.01152667, -0.02381563, 0.02137542, 0.02962223, -0.029383175, 0.029385142, -0.000508776, 0.0313664, -0.03412263, -0.0073380554, 0.019250294, -0.032187864, -0.0042721853, 0.021946486, -0.01742853, -0.03321611, -0.04235328, -0.03214332, 0.00992595, 0.012492337, -0.00020227267, 0.009040729, 0.031084849, -0.011386254, -0.036536787, -0.05343854, -0.004083784, 0.041551262, 0.008121242, -0.009682486, -0.02298711, 0.023583077, 0.010244591, 0.017874036, 0.008305703, 0.035779558, 0.03172564, 0.009442261, 0.007703398, -0.034135815, 0.0235881, 0.040991824, 0.020225963, -0.035598002, 0.022706814, -0.011447516, -0.0053803404, 0.025798764, 0.020515688, 0.0020012811, 0.03763451, -0.025219584, -0.034180377, 0.059940953, 0.00016026806, -0.019244092, -0.007989041, -0.0015264193, 0.0052625253, -0.06792375, -0.013850968, 0.04576526, -0.035767075, 0.05095894, 0.010925518, 0.030118953, -0.0060324185, -0.06143651, -0.0038925074, -0.030250477, -0.03009429, 0.08681922, 0.045476247, -0.017264945, -0.01690634, -0.004458203, -0.028265376, -0.0024999422, -0.06687186, -0.015099792, -0.014197466, 0.100642554, 0.04639973, -0.04743784, -0.016173368, -0.004059485, -0.007962693, 0.003921108, -0.022593834, 0.0023274813, 0.0025442345, 0.015775867, 0.024660185, 0.010436949, -0.030896157, 0.016161544], "465ffc8b-5db9-4da0-a722-cfe37443f6b9": [-0.013942576, -0.05004572, -0.0024596145, -0.004988307, 0.033816706, 0.04160804, 0.0559897, 0.03865134, 0.0325686, 0.03571612, 0.02257427, 0.019416947, -0.0060722977, -0.00092252507, 0.0070096124, -0.101691514, 0.013839439, 0.063001856, -0.0074150767, -0.036019377, 0.032417387, -0.01675528, 0.015656779, -0.026464162, -0.016863497, -0.023013365, 0.00021340209, -0.07905518, -0.012595439, 0.024790484, 0.0061354754, 0.03503358, -0.006901227, 0.0058576097, -0.0021557047, -0.034930084, -0.01944597, 0.028006013, 0.036092594, 0.02390419, -0.008325563, -0.023818605, -0.02897559, -0.017931249, -0.0031968073, -0.030294323, -0.013055801, 0.018080711, 0.042078517, -0.061783437, -0.012196568, 0.043938994, 0.061092325, 0.0068091666, 0.015351793, -0.002790619, 0.026627544, 0.014306695, 0.046205748, 0.006187914, -0.015907815, 0.00750223, -0.009247156, -0.017149663, -0.002674156, -0.06978486, -0.032562487, 0.014909877, 0.0512232, 0.003581862, 0.023821447, 0.020594971, 0.096465856, -0.02106757, -0.049181167, -0.08413422, -0.060515936, 0.07722382, 0.07005975, -0.025156694, 0.010414111, -0.056616966, -0.062517375, -0.050671868, -0.105120406, -0.0028396414, 0.012043942, -0.02564401, -0.03650447, 0.0047695306, -0.032658335, -0.006039989, 0.029534796, -0.041803803, -0.015587443, 0.0718559, 0.0025380955, -0.038305957, 0.024009505, -0.051916994, 0.027038254, -0.083688006, -0.023876462, 0.034360267, 0.016052632, 0.03580638, -0.02369926, 0.051842872, -0.013707251, 0.03882432, -0.02072547, -0.008863828, -0.005643345, -0.06959853, 0.015641265, -0.06949581, 0.014532822, 0.033776037, 0.052815624, 0.037260395, -0.0040080897, 0.02787845, 0.07761898, -0.02813797, 0.029425994, 0.050672222, 0.055883978, -0.013738704, 0.064254, -0.017961308, 2.3516894e-05, -0.016244035, -0.022785924, 0.0067581628, 0.002548854, 0.06472949, 0.013539149, -0.009980852, 0.00745886, -0.013680364, -0.012576743, -0.0037348242, -0.006975991, 0.022205133, -0.03149932, 0.04297427, -0.06605839, 0.02031178, 0.018417098, -0.034634385, -0.036090393, 0.018298337, -0.04450177, -0.048604358, 0.005160968, 0.051063128, -0.0019159523, 0.05904592, 0.03499788, -0.00030837877, 0.060808882, 0.0044350848, 0.032631855, 0.04696743, -0.08244822, -0.021040497, -0.015347125, -0.007841086, 0.027144095, 0.019066783, 0.03639024, 0.10202969, -0.030341854, -0.07939621, 0.0012606734, -0.021512624, 0.046205178, 0.044364393, -0.042856228, 0.007482244, -0.07440788, -0.0379734, -0.017066153, -0.012597599, 0.043378875, 0.01257382, 0.055178326, -0.024468243, -0.021804225, 0.060988452, 0.042390205, 0.0049336986, -0.073535636, 0.01608951, 0.004770671, 0.045871228, 0.054330043, 0.03350778, -0.0014521625, -0.026229158, 0.049176093, 0.046621963, 0.007634542, -0.021884348, 0.012471543, -0.01080223, 0.0030419778, 0.006097331, -0.050032288, 0.065230064, -0.055330265, 0.024594229, -0.011658118, 0.008556673, 0.01104873, 0.0023335412, 0.009453569, -0.01044572, 0.012317408, -0.013243263, 0.029412916, 0.013648068, -0.07283111, 0.016371174, 0.02175924, 0.058697745, -0.02588694, 0.055256095, 0.04571936, -0.06464845, 0.013852876, 0.06337885, 0.0074937386, 0.017543992, 0.0957526, -0.0032676614, 0.047690656, 0.038866397, 0.033890173, 0.053825878, -0.024521494, 0.0011908717, 0.02696237, 0.02574416, -0.09303432, -0.032898087, -0.062302098, 0.032037087, 0.033121273, 0.023267658, -0.02788361, -0.03301304, -0.021543302, -0.025683891, -0.010035143, 0.053849064, -0.043677304, -0.04138562, -0.035006266, -0.0221966, -0.008322889, 0.021780314, 0.0079186, 0.011578791, 0.041794106, -0.057900716, -0.013911583, -0.047303196, -0.037507884, 0.05398776, -0.03767498, -0.08134369, 0.023528783, 0.018027596, 0.05780794, 0.036838923, 0.031652935, 0.039830472, -0.015910737, -0.0071560354, -0.016130993, 0.024222517, 0.042326912, -0.02252287, -0.074739605, 0.01243972, -0.043742813, -0.011162992, -0.010031037, -0.09127692, -0.015512113, 0.0101769, 0.030259496, -0.051297843, -0.06402501, 5.0025956e-05, -0.0046117324, 0.01752314, 0.013863558, -0.025623024, -0.0032457656, -0.049639847, -0.019388704, -0.02122493, -0.012937106, 0.007322242, -0.009814481, -0.054679196, 0.034098074, 0.016346231, 0.038466968, -0.052556757, -0.014597776, -0.023507835, 0.033992182, 0.06204748, 0.016602965, -0.0037922086, 0.008126546, 0.04297178, 0.0019072786, 0.012987022, 0.009762839, 0.005457056, -0.024512405, 0.045124684, -0.04041046, 0.046108715, -0.027431639, 0.045121633, 0.05148965, -0.027777884, -0.04224333, 0.024023367, -0.043870937, 0.023507511, -0.061584882, -0.018358005, -0.01624735, -0.031010866, -0.005778115, -0.0031502103, -0.0027354981, -0.017997893, 0.061696067, -0.042376027, -0.07111801, 0.04202688, 0.09596422, -0.008896546, 0.03866772, 0.011610476, -0.036800515, -0.0003562328, 0.027715024, 0.030739985, 0.0023382725, -0.015368987, 0.076085255, -0.044962935, -0.0276196, 0.049883153, -0.032070413, -0.014424739, -0.03237573, -0.025137562, -0.00917539, 0.014935583, -0.019038515, 0.055773072, 0.010674643, -0.009561543, 0.026345005, -0.026525, 0.00239589, 0.0063353027, -0.056441974, -0.031665217, 0.037312508, 0.03180424, -0.055227887, -0.03399269, 0.03618019, 0.062579565, -0.011404837, -0.00566233, -0.018172221, 0.04988377, -0.01051933, 0.063926525, 0.002915952, 0.003947791, 0.07110723, -0.025589293, 0.023371618, -0.048002575, 0.013475944, -0.05945439, -0.0038836496, -0.0036669374, -0.0051968056, -0.046373826, -0.035130665, -0.007606457, -0.0076590152, -0.017842034, 0.014326116, -0.04646312, 0.009449316, 0.004480577, 0.05933251, 0.02799503, 0.04902354, -0.030494878, -0.053546887, 0.016851515, 0.03448578, -0.033737585, -0.0051362435, 0.017530242, -0.035401292, -0.01002646, -0.018345768, 0.0047644665, -0.048367403, -0.03885881, 0.0134026725, 0.015731644, 0.017613046, 0.028027607, 0.03184088, -0.005162377, 0.06643755, 0.004330549, 0.004237002, -0.026058491, -0.03203678, 0.0065220986, -0.052023508, -0.0011905539, 0.02205257, 0.029392371, 0.018790185, -0.021368654, -0.027341682, -0.03372739, -0.007248249, -0.029055903, 0.02182004, -0.09493315, 0.03258842, -0.03092905, -0.03249701, -0.04707941, -0.015180415, -0.018252226, -0.0063160327, 0.049088694, -0.005337031, 0.011000416, 0.012062828, -0.07605947, -0.02609442, -0.024629807, 0.05607988, -0.04016381, -0.0050308895, -0.019741645, 0.0010877517, 0.04053932, 0.04351491, -0.0430483, 0.05046877, -0.024267463, -0.03155957, 0.013163453, -0.03052551, 0.021201404, -0.0834144, -0.029016402, -0.008388813, 0.011852535, 0.026098656, 0.00845935, -0.019518444, 0.005813988, 0.055904236, 0.022988899, -0.018956538, 0.041024797, 0.011037487, 0.03606091, -0.008137818, -0.082539044, -0.04094322, -0.047754798, -0.080411494, 0.07211718, 0.042462304, 0.083044216, -0.0057597193, 0.032008685, -0.036509752, 0.015438502, 0.090110816, -0.034808133, 0.023715531, -0.030766139, -0.01865178, -0.015373671, 0.0062014335, 0.013278195, -0.0041980525, 0.008094469, 0.074207306, -0.020026594, 0.0121156275, -0.0054401797, 0.020379055, 0.0067103487, 0.0022297455, -0.0035074344, -0.09194966, -0.0040683253, 0.055130053, -0.03776474, -0.0022838153, 0.016018678, -0.016643217, 0.004413826, -0.032936953, 0.017058903, -0.018320559, 0.0592145, -0.0025738904, -0.0052502328, 0.022317193, 0.0035010264, 0.0034872254, -0.029640628, 0.04287895, -0.0008669975, 0.048367284, 0.049915336, -0.0022631702, 0.031358894, 0.005409237, -0.08149163, 0.009053454, -0.020091705, -0.043226846, 0.026922088, 0.00951764, -0.013251903, -0.00855176, -0.0013300555, -0.026440999, 0.019532079, 0.01933276, -0.042854138, -0.035642877, -0.01690282, 0.047308736, 0.026986472, 0.048414364, -0.0010883844, -0.058255088, -0.016945833, 0.03169084, -0.07148872, -0.0014596367, -0.0015167678, 0.037061088, -0.02112187, 0.03716974, -0.028106796, -0.012945708, -0.0058041797, -0.05719215, 0.03668257, 0.045904364, 0.022865666, -0.04351047, 0.03014706, -0.015867792, -0.051983103, 0.075981535, 0.081311755, 0.013201398, -0.018000305, -0.07350482, 0.034230754, -0.0734936, 0.028762288, -0.012358543, 0.013989587, 0.025008092, -0.021240592, -0.004982368, 0.033298377, 0.010011259, -0.062239897, 0.038131297, -0.026571374, 0.045902282, 0.01856965, -0.02297006, -0.017238017, 0.027757403, 0.031917777, 0.02308945, -0.052720495, 0.007704739, -0.017868226, -0.07139077, -0.03887578, 0.050598145, 0.003954116, -0.006605912, -0.022189554, 0.040516034, 0.012096921, -0.004647899, 0.004916617, 0.02567265, -0.009011827, -0.02066389, -0.026459664, 0.07991191, 0.0758022, 0.07052877, 0.028677966, 0.026332235, 0.02088737, -0.035961572, -0.00041237846, -0.02803654, 0.036442354, 0.0036102035, 0.05024483, -0.049970318, -0.00047016417, 0.049894203, -0.021489944, -0.021254439, 0.017310254, -0.0109884655, -0.08358184, -0.065110296, -0.012880087, -0.044329327, -0.013426735, 0.047277696, -0.022340802, 0.011052728, 0.011769178, -0.0013245728, -0.0061208946, 0.05522634, 0.0282166, -0.0048589497, 0.03209408, 0.010704258, -0.009102072, 0.009898779, -0.030558614, -0.038480908, -0.047984693, -0.0140481945, 0.042309716, -0.03162952, 0.04117167, 0.03603992, -0.021860918, 0.041736025, 0.009433795, -0.00967261, 0.034773916, 0.013447345, 0.0323399, -0.05685067, 0.028343357, -0.006602013, 0.0046088975, 0.01669993, 0.031171605, -0.043556497, 0.0043243114, -0.037542365, -0.010708932, 0.0028500366, -0.03195939, 0.0040194755, 0.005226347, 0.031051371, 0.011218204, -0.023009304, -0.035236634, -0.022880234, 0.0026298156, -0.007171839, -0.033924285, 0.0016954348, 0.00700197, -0.0032252066, 0.0059920894, 0.0051230644, 0.010853027, 0.056677416, -0.004816632, 0.034110427, -0.025292337, 0.0053697717, 0.037289448, -0.0026217774, -0.020497844, -0.012540489, -0.027822534, -0.03226386, 0.018911572, 0.03740877, -0.050708663, 0.029226655, 0.0024878855, -0.049404375, 0.023406021, -0.033698615, -0.00944341, -0.010998675, -0.013502704, 0.018186742, -0.057844833, -0.012752531, 0.025435086, -0.032798186, 0.038757764, 0.006831602, 0.044877015, -0.003325687, -0.08931035, -0.016581118, -0.013127261, -0.009274503, 0.07537369, 0.04413222, -0.0259374, -0.025346113, -0.020058364, -0.0034784845, -0.044490643, -0.042846512, -0.015863378, -0.021355191, 0.06437895, 0.040514767, -0.037089877, 0.012446909, -0.006791107, -0.011816216, -0.012122452, -0.03025296, -0.033382297, -0.018095093, -0.0018675475, 0.05840907, 0.0235504, -0.023757977, 0.017844062], "6ec07935-7cd1-4a62-8dc7-b7d189acada5": [0.016198954, -0.07172039, -0.035069197, 0.0027183683, 0.04782525, 0.060995832, 0.059146076, 0.021094892, 0.01906341, 0.042835563, 0.035805818, 0.03189268, -0.0072845276, -0.005565513, -0.005372099, -0.099909775, 0.021498, 0.04005337, 0.03435284, -0.031664938, 0.020038325, -0.014874113, 0.023663895, -0.016488368, -0.027135067, -0.037486933, -0.03272547, -0.108067736, -0.030378036, 0.011085849, -0.033710487, 0.0123785, -0.027145354, 0.030510312, 0.023910096, -0.014799442, -0.018786093, 0.05336981, -0.00404464, 0.05617501, 0.03445425, -0.030242937, -0.0376034, -0.031686716, -0.02945676, -0.031257197, -0.0038297498, 0.028844915, 0.0039963257, -0.057714667, -0.014244754, 0.015259197, 0.06917693, -0.015504119, 0.03301593, -0.02504344, 0.011293838, -0.0102254, 0.036243394, 0.03269968, 0.011136386, 0.001684158, -0.013083434, 0.011815991, -0.0118712485, -0.09359452, -0.043730948, -0.024664864, 0.037143856, -0.0070834095, 0.0011070599, 0.017556498, 0.08462023, -0.0166217, -0.03930309, -0.10670564, -0.01970125, 0.068285294, 0.03734653, -8.3638595e-05, 0.014933126, -0.006228766, -0.06886966, -0.07290505, -0.084447615, 0.021885972, -0.009296487, -0.026797945, -0.04903673, 0.017895184, -0.04487769, -0.032701943, 0.023623839, -0.052512635, 0.011361433, 0.059823994, -0.006630654, -0.027947329, 0.015890444, -0.035042193, 0.023545286, -0.057629284, 0.0013836586, 0.0072879996, 0.008796297, 0.030734178, -0.032902703, 0.076018706, -0.03729256, 0.030008832, -0.033108927, -0.0066356547, -0.005592804, -0.043711327, 0.05868045, -0.07575261, 0.018211793, 0.026851838, 0.05377771, 0.0667518, 0.011573437, 0.011071122, 0.057641663, -0.005528594, 0.022318626, 0.043271437, 0.0071267537, -0.0020720474, 0.08141489, -0.003891955, 0.032464825, -0.029796205, -0.026676813, 0.007264083, -0.0016883805, 0.058980282, 0.047153722, -0.028438222, -0.0030241192, 0.021000588, -0.033280022, 0.013439057, 0.0045379116, 0.021972932, -0.025313921, 0.05660785, -0.06051847, 0.0010130014, 0.010342443, -0.02932258, -0.03255297, 0.01733792, -0.044887077, -0.041390996, 0.025261486, 0.025387416, 0.009935085, 0.063787304, 0.04611402, -0.038928404, 0.0912733, 0.021489719, 0.012021235, 0.038057774, -0.07091538, -0.010133843, -0.02295643, -0.012171187, -0.009162825, 0.024802212, 0.02198788, 0.11231011, -0.041033033, -0.07210413, -0.009320634, -0.0037638743, 0.011697875, 0.07445354, -0.019330356, 0.020104386, -0.058939666, -0.06258709, -0.0035874895, 0.04911454, 0.03379775, -0.0017190272, 0.06641046, -0.039467305, -0.04139342, 0.025022535, -0.0039575268, -0.018351132, -0.08033097, -0.010314388, 0.019832402, 0.051602382, 0.05130198, 0.031873673, 0.0071965824, -0.046555616, 0.027376741, 0.04466669, 0.037230846, 0.0009968791, 0.055553533, -0.01543593, 0.018136427, 0.021339437, -0.055183176, 0.06233831, -0.09420432, 0.0050670956, 0.0026333681, 0.011029361, 0.011282062, 0.010342232, 0.018035028, 0.02187243, 0.019351019, -0.050254624, -0.020416642, 0.05155591, -0.06452836, 0.012515367, -0.02658747, 0.04802771, -0.024777684, 0.027294433, 0.036914457, -0.037563358, 0.025313295, 0.087204576, -0.009381575, -0.0136165405, 0.095647216, -0.0030683095, 0.03390375, 0.035767864, 0.027082799, 0.046557, -0.0236432, 0.00808728, 0.037848048, 0.0379222, -0.10517363, -0.038211048, -0.03783263, 0.029692769, -0.0019854978, 0.03612082, -0.053659886, -0.066774726, -0.009551313, -0.02184704, -0.044499397, 0.014509707, -0.037369747, -0.013350024, -0.050532717, 0.0035184945, 0.02337733, 0.032075185, 0.0132914195, -0.014285818, 0.011312631, -0.0451209, 0.015922977, -0.046814054, -0.023769768, 0.062763356, -0.023959704, -0.10270536, 0.043958496, 0.0009651654, 0.0019259028, 0.026510078, 0.002864716, 0.033722017, -0.01047781, -0.0039356695, 0.014367435, 0.034618497, 0.018752454, -0.034873288, -0.055814784, 0.031853847, -0.006188141, -0.02436405, -0.0059986636, -0.070082076, 0.003929127, 0.030732239, 0.009776079, -0.07962525, -0.05906102, -0.008467927, 0.01288981, 0.0010614473, 0.00053072226, -0.052684925, 0.010997498, -0.070733875, -0.0063243047, -0.03588042, -0.01990649, 0.028430633, 0.0033158022, -0.05589991, 0.044757664, 0.008229027, -0.00573162, -0.070636585, -0.00093369675, -0.007081874, 0.025159579, 0.066771716, 0.016711056, 0.039556127, -0.012885618, 0.01837559, -0.0053887283, -0.008200765, -0.012132223, 0.00013700366, 0.017729117, 0.03816738, -0.042376902, 0.082250595, -0.05703486, 0.02552485, 0.042048562, -0.007933212, -0.04515937, 0.040227003, -0.03810187, 0.010539134, -0.040832788, -0.018186715, -0.029399658, -0.01878189, -0.017073339, -0.020217983, 0.0062107956, 0.008770815, 0.05343544, -0.03788796, -0.048746876, -0.00048289038, 0.091358244, -0.008194418, 0.022797558, 0.041488502, -0.033131916, 0.025813583, 0.034206804, -0.030288566, 0.017430384, 0.01220207, 0.07931881, -0.010968182, -0.008959114, -0.002285085, -0.033072874, -0.016016353, 0.032175038, -0.022723198, -0.0045123408, 0.032749675, -0.03755061, 0.03899816, -0.0013681514, -0.02009248, 0.0073501905, 0.0089854635, -0.0015117483, -0.020963954, -0.05584009, -0.025173333, 0.020151785, -0.013366048, -0.026133396, -0.036638323, 0.017814878, 0.04584352, -0.0039030658, -0.024052568, 0.017831082, 0.032279126, -0.026594806, 0.07252763, 0.036888804, 0.010398961, 0.103614084, -0.032982104, 0.031721473, -0.0124983955, -0.013240257, -0.06587945, 0.037812233, 0.009268474, 0.010284231, -0.022781366, -0.04356027, -0.006200644, -0.03599308, -0.03499288, -0.015899679, -0.05932784, 0.032580737, 0.0077959015, 0.008778017, 0.039605908, 0.077550694, -0.012394787, -0.024386967, -0.0021959292, 0.06846253, -0.018754672, 0.011702668, 0.00015359861, -0.009130081, -0.040926974, 0.030576913, -0.0022765703, -0.054995105, -0.06205378, 0.0106503, 0.004067076, -0.013724391, 0.008000668, 0.0376168, -0.014896069, 0.033011872, -0.011267543, -0.0014428985, -0.017260874, 0.0068757096, 0.035448447, -0.019027082, -0.011810049, 0.020983446, -0.00054969866, 0.028805247, -0.019773109, -0.036629546, -0.016165009, 0.005051026, -0.011308443, 0.06862159, -0.07150163, 0.048540927, -0.017857902, -0.072334625, -0.038757123, -0.0038362185, -0.047672816, -0.0040895417, 0.021648915, -0.0229483, -0.014052043, 0.041782156, -0.03982219, -0.001781177, -0.039337378, 0.036779806, -0.047284715, -0.0033760502, -0.029847983, 0.022719886, 0.045419324, -0.018147698, -0.06736301, 0.03367351, -0.058972243, -0.007756987, 0.0055828514, -0.049585372, 0.06303025, 0.010460307, -0.032369267, -0.0053915675, 0.008903307, 0.017363198, 0.0218527, -0.00327585, 0.023580678, 0.03110342, 0.02368712, -0.050925557, 0.03196598, 0.012506565, 0.021106245, -0.017480776, -0.042035207, -0.00419376, -0.015747285, -0.046990942, 0.057148024, 0.015834924, 0.046271503, -0.020222874, 0.008721987, -0.03886144, -0.014053136, 0.09993875, -0.03979886, 0.038702797, 0.008182068, -0.023661349, -0.004395826, -0.0055081733, 0.008873089, 0.0071921134, 0.017791342, 0.065165214, -0.012790786, 0.0031803157, 0.029835531, 0.04432195, 0.010640109, 0.010688218, -0.034072675, -0.06603403, -0.009979316, 0.02832301, -0.05924587, 0.0072010034, -0.013610168, -0.009829284, 0.012703627, -0.015665974, -0.009369642, -0.06648096, 0.024325492, -0.0014832718, -0.016407035, 0.05721315, 0.014157127, 0.03821027, -0.026236305, 0.04479965, 0.022497239, 0.008710907, 0.029367873, -0.017221432, 0.035117976, -0.015596036, -0.07967808, 0.016195357, 0.004018931, -0.0471379, 0.008728403, 0.013071117, -0.022986261, 0.008322139, -0.02383166, -0.0010772486, 0.02258946, 0.02242077, -0.029527169, -0.05035348, -0.019047841, 0.025163162, 0.018380145, 0.06861033, 0.00033468276, -0.032084823, -0.011122494, 0.033368316, -0.031506334, 0.02082442, -0.0046918024, 0.022303745, 0.005616211, 0.07956462, -0.06714106, -0.013931593, 0.00682256, -0.02501808, 0.03836343, 0.02000686, 0.024699312, -0.051613614, 0.05370934, -0.029611215, -0.056685433, 0.035930462, 0.037055463, 0.02687956, -0.017716106, -0.05523333, 0.05347642, -0.05398677, 0.0042669033, 0.01209322, -0.008872054, 0.023393365, -0.014554434, -0.049823124, 0.055084378, 0.006616077, -0.060356747, -0.0028283466, -0.022899516, 0.04095536, 0.04531954, -0.011818502, 0.023664096, 0.021368654, 0.007426678, 0.02730308, -0.022390202, 0.04066086, -0.0446454, -0.027361218, -0.06432591, 0.03129216, 0.004164807, -0.025639977, -0.014120819, 0.02383094, 0.045383144, -0.0100920405, 0.010116115, 0.034983993, 0.02907894, -0.04919764, 0.012107085, 0.08870391, 0.0490052, 0.05179325, 0.035864096, -0.0034462654, 0.005210557, -0.034496922, 0.015066476, -0.022442603, 0.027287554, 0.032356534, 0.01629338, -0.016713656, 0.011531842, 0.019157218, -0.03936111, -0.003493055, 0.038820755, -0.010897358, -0.106139556, -0.05954082, 0.02330997, -0.048475184, -0.030962672, 0.012747422, -0.021730643, 0.015781501, 0.018987665, -0.0041417438, -0.014029184, 0.062281284, -0.019541707, -0.042997014, 0.03149683, -0.0067029414, -0.020807933, -0.01926803, -0.057505865, -0.024967352, -0.06764778, -0.03218152, 0.021621712, -0.033463188, 0.03071382, 0.06477265, -0.029598914, 0.020735823, 0.031786863, 0.009000186, 0.07238073, 0.016730726, -0.013643618, -0.027639793, 0.012094414, -0.04076461, 0.01106919, 0.017883018, 0.024170773, -0.036853675, -0.0051005837, -0.059004158, 0.017518718, 0.010020036, -0.0007209405, 0.00065101497, 0.036870394, 0.047688715, -0.013006518, -0.036002323, -0.033211827, 0.014707284, 0.010818933, -0.035211228, -0.010539702, 0.0017507896, -0.0035107145, 0.007505744, -0.004999884, -0.011177441, 0.03624487, 0.0105347745, 0.010430237, 0.023565069, -0.019369356, 0.0012064709, 0.036097452, -0.02243877, -0.030794373, -0.011443556, 0.00347536, -0.023348058, 0.009263637, 0.04730755, -0.0031562776, 0.019070147, -0.030237818, -0.018899562, 0.0016080155, -0.013682193, -0.006652669, 0.018303156, 0.014279733, 0.031462356, -0.055128317, -0.025386984, 0.039921388, -0.024187667, 0.033111554, 0.020770254, 0.040069044, 0.010902106, -0.072891966, -0.012747457, -0.0053766426, 0.006394033, 0.014996383, 0.028322998, -0.027273843, 0.0021305047, -0.030572198, 0.002965478, -0.065148436, -0.06385231, 0.007861129, -0.014604137, 0.07060488, 0.062272716, -0.05506379, -0.0036843056, -0.008986861, -0.019498182, 0.0020227847, -0.03272569, 0.0024898807, -0.013916462, 0.005839653, 0.04174996, 0.04496326, -0.030062376, 0.016551664]}, "text_id_to_ref_doc_id": {"35be54dc-30ad-446a-8ceb-55211de07da6": "e853545c-0ca1-4b7e-9681-02919ad26522", "eb04d635-c6d9-411d-8d43-fffdbf9963c8": "e853545c-0ca1-4b7e-9681-02919ad26522", "0f57e92b-7644-4f0d-a6bd-5e039a0228d1": "e853545c-0ca1-4b7e-9681-02919ad26522", "db26e25e-87d0-4733-a486-40d71ccd51c6": "e853545c-0ca1-4b7e-9681-02919ad26522", "465ffc8b-5db9-4da0-a722-cfe37443f6b9": "e853545c-0ca1-4b7e-9681-02919ad26522", "6ec07935-7cd1-4a62-8dc7-b7d189acada5": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "metadata_dict": {"35be54dc-30ad-446a-8ceb-55211de07da6": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "eb04d635-c6d9-411d-8d43-fffdbf9963c8": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "0f57e92b-7644-4f0d-a6bd-5e039a0228d1": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "db26e25e-87d0-4733-a486-40d71ccd51c6": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "465ffc8b-5db9-4da0-a722-cfe37443f6b9": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "6ec07935-7cd1-4a62-8dc7-b7d189acada5": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Experiments/storage/docstore.json
================================================
{"docstore/metadata": {"e853545c-0ca1-4b7e-9681-02919ad26522": {"doc_hash": "1adc40efe6dabc0a3eddca0cbda5a4c97bb0422c87110fdb1847ae3406fa69a2"}, "35be54dc-30ad-446a-8ceb-55211de07da6": {"doc_hash": "1a661fe3f4f38fb2d3c9d2c0c3519e1959b5ff9a3d4bbfc2b8e967b0ea807636", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "eb04d635-c6d9-411d-8d43-fffdbf9963c8": {"doc_hash": "ff69bacd5f898a093a5afa7fc4a7c23e8f8c2a15da3b9f46bbb7b2e07479cb65", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "0f57e92b-7644-4f0d-a6bd-5e039a0228d1": {"doc_hash": "bf0b169726e1856d83166d32bd957040e0df7ccb6677e02e591572d245876f5d", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "db26e25e-87d0-4733-a486-40d71ccd51c6": {"doc_hash": "eae6bcd6e6af56b2e3134e98a354b08b28f6634150e58e118b68bd1f3604f53d", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "465ffc8b-5db9-4da0-a722-cfe37443f6b9": {"doc_hash": "3cd3debe9e3d6767b01c8b3ba5e025e90d959b5a4878704cdad6ffca9a96f195", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}, "6ec07935-7cd1-4a62-8dc7-b7d189acada5": {"doc_hash": "7ec5fb582e5e3626a0446fc4523a06b41ce8570b0a96058e2c2602cde2676d7f", "ref_doc_id": "e853545c-0ca1-4b7e-9681-02919ad26522"}}, "docstore/data": {"35be54dc-30ad-446a-8ceb-55211de07da6": {"__data__": {"id_": "35be54dc-30ad-446a-8ceb-55211de07da6", "embedding": null, "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "node_type": "4", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "1adc40efe6dabc0a3eddca0cbda5a4c97bb0422c87110fdb1847ae3406fa69a2", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "eb04d635-c6d9-411d-8d43-fffdbf9963c8", "node_type": "1", "metadata": {}, "hash": "b5bb6713ef0cad990c8e4fb8ef958b6362f13d1f8efc7c5ef6ca2d0745aaa8db", "class_name": "RelatedNodeInfo"}}, "text": "What is machine learning?\nMachine learning is a branch of artificial intelligence (AI) and computer science which\nfocuses on the use of data and algorithms to imitate the way that humans learn,\ngradually improving its accuracy.\nIBM has a rich history with machine learning. One of its own, Arthur Samuel, is credited\nfor coining the term, \u201cmachine learning\u201d with his research (link resides outside ibm.com)\naround the game of checkers. Robert Nealey, the self-proclaimed checkers master,\nplayed the game on an IBM 7094 computer in 1962, and he lost to the computer.\nCompared to what can be done today, this feat seems trivial, but it\u2019s considered a major\nmilestone in the field of artificial intelligence.\nOver the last couple of decades, the technological advances in storage and processing\npower have enabled some innovative products based on machine learning, such as\nNetflix\u2019s recommendation engine and self-driving cars.\nMachine learning is an important component of the growing field of data science.\nThrough the use of statistical methods, algorithms are trained to make classifications or\npredictions, and to uncover key insights in data mining projects. These insights\nsubsequently drive decision making within applications and businesses, ideally\nimpacting key growth metrics. As big data continues to expand and grow, the market\ndemand for new data scientists will increase. They will be required to help identify the\nmost relevant business questions and the data to answer them.\nMachine learning algorithms are typically created using frameworks such as Python that\naccelerate solution development by using platforms like TensorFlow or PyTorch.\nNow available: watsonx.ai\nThe all-new enterprise studio that brings together traditional machine learning along\nwith new generative AI capabilities powered by foundation models.\nTry watsonx.ai\nBegin your journey to AI\nLearn how to scale AI\nExplore the AI Academy\nMachine Learning vs. Deep Learning vs. Neural Networks\nSince deep learning and machine learning tend to be used interchangeably, it\u2019s worth\nnoting the nuances between the two. Machine learning, deep learning, and neural\nnetworks are all sub-fields of artificial intelligence. However, neural networks is actually\na sub-field of machine learning, and deep learning is a sub-field of neural networks.\nThe way in which deep learning and machine learning differ is in how each algorithm\nlearns. \"Deep\" machine learning can use labeled datasets, also known as supervised\nlearning, to inform its algorithm, but it doesn\u2019t necessarily require a labeled dataset. The\ndeep learning process can ingest unstructured data in its raw form (e.g., text or images),\nand it can automatically determine the set of features which distinguish different\ncategories of data from one another. This eliminates some of the human intervention\nrequired and enables the use of large amounts of data. You can think of deep learning\nas \"scalable machine learning\" as Lex Fridman notes in this MIT lecture (link resides\noutside ibm.com).\nClassical, or \"non-deep,\" machine learning is more dependent on human intervention to\nlearn. Human experts determine the set of features to understand the differences\nbetween data inputs, usually requiring more structured data to learn.\nNeural networks, or artificial neural networks (ANNs), are comprised of node layers,\ncontaining an input layer, one or more hidden layers, and an output layer. Each node, or\nartificial neuron, connects to another and has an associated weight and threshold. If the\noutput of any individual node is above the specified threshold value, that node is\nactivated, sending data to the next layer of the network. Otherwise, no data is passed\nalong to the next layer of the network by that node.", "start_char_idx": 0, "end_char_idx": 3750, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "eb04d635-c6d9-411d-8d43-fffdbf9963c8": {"__data__": {"id_": "eb04d635-c6d9-411d-8d43-fffdbf9963c8", "embedding": null, "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "node_type": "4", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "1adc40efe6dabc0a3eddca0cbda5a4c97bb0422c87110fdb1847ae3406fa69a2", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "35be54dc-30ad-446a-8ceb-55211de07da6", "node_type": "1", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "1a661fe3f4f38fb2d3c9d2c0c3519e1959b5ff9a3d4bbfc2b8e967b0ea807636", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "0f57e92b-7644-4f0d-a6bd-5e039a0228d1", "node_type": "1", "metadata": {}, "hash": "7a55aae2f58a0465d55081eaddd06bb92fb3060cab95884bcd232cfc95f624c7", "class_name": "RelatedNodeInfo"}}, "text": "Otherwise, no data is passed\nalong to the next layer of the network by that node. The \u201cdeep\u201d in deep learning is just\nreferring to the number of layers in a neural network. A neural network that consists of\nmore than three layers\u2014which would be inclusive of the input and the output\u2014can be\nconsidered a deep learning algorithm or a deep neural network. A neural network that\nonly has three layers is just a basic neural network.\nDeep learning and neural networks are credited with accelerating progress in areas\nsuch as computer vision, natural language processing, and speech recognition.\nSee the blog post \u201cAI vs. Machine Learning vs. Deep Learning vs. Neural Networks:\nWhat\u2019s the Difference?\u201d for a closer look at how the different concepts relate.\nRelated content\nExplore the watsonx.ai interactive demo\nDownload \u201cMachine learning for Dummies\u201d\n- This link downloads a pdf\nExplore Gen AI for developers\nHow does machine learning work?\nUC Berkeley (link resides outside ibm.com) breaks out the learning system of a\nmachine learning algorithm into three main parts.\nA Decision Process: In general, machine learning algorithms are used to make a\nprediction or classification. Based on some input data, which can be labeled or\nunlabeled, your algorithm will produce an estimate about a pattern in the data.\nAn Error Function: An error function evaluates the prediction of the model. If\nthere are known examples, an error function can make a comparison to assess\nthe accuracy of the model.\nA Model Optimization Process: If the model can fit better to the data points in the\ntraining set, then weights are adjusted to reduce the discrepancy between the\nknown example and the model estimate. The algorithm will repeat this iterative\n\u201cevaluate and optimize\u201d process, updating weights autonomously until a\nthreshold of accuracy has been met.\nMachine learning methods\nMachine learning models fall into three primary categories.\nSupervised machine learning\nSupervised learning, also known as supervised machine learning, is defined by its use\nof labeled datasets to train algorithms to classify data or predict outcomes accurately.\nAs input data is fed into the model, the model adjusts its weights until it has been fitted\nappropriately. This occurs as part of the cross validation process to ensure that the\nmodel avoids overfitting or underfitting. Supervised learning helps organizations solve a\nvariety of real-world problems at scale, such as classifying spam in a separate folder\nfrom your inbox. Some methods used in supervised learning include neural networks,\nna\u00efve bayes, linear regression, logistic regression, random forest, and support vector\nmachine (SVM).\nUnsupervised machine learning\nUnsupervised learning, also known as unsupervised machine learning, uses machine\nlearning algorithms to analyze and cluster unlabeled datasets (subsets called clusters).\nThese algorithms discover hidden patterns or data groupings without the need for\nhuman intervention. This method\u2019s ability to discover similarities and differences in\ninformation make it ideal for exploratory data analysis, cross-selling strategies,\ncustomer segmentation, and image and pattern recognition. It\u2019s also used to reduce the\nnumber of features in a model through the process of dimensionality reduction. Principal\ncomponent analysis (PCA) and singular value decomposition (SVD) are two common\napproaches for this. Other algorithms used in unsupervised learning include neural\nnetworks, k-means clustering, and probabilistic clustering methods.\nSemi-supervised learning\nSemi-supervised learning offers a happy medium between supervised and\nunsupervised learning. During training, it uses a smaller labeled data set to guide\nclassification and feature extraction from a larger, unlabeled data set. Semi-supervised\nlearning can solve the problem of not having enough labeled data for a supervised\nlearning algorithm.", "start_char_idx": 3669, "end_char_idx": 7558, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "0f57e92b-7644-4f0d-a6bd-5e039a0228d1": {"__data__": {"id_": "0f57e92b-7644-4f0d-a6bd-5e039a0228d1", "embedding": null, "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "node_type": "4", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "1adc40efe6dabc0a3eddca0cbda5a4c97bb0422c87110fdb1847ae3406fa69a2", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "eb04d635-c6d9-411d-8d43-fffdbf9963c8", "node_type": "1", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "ff69bacd5f898a093a5afa7fc4a7c23e8f8c2a15da3b9f46bbb7b2e07479cb65", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "db26e25e-87d0-4733-a486-40d71ccd51c6", "node_type": "1", "metadata": {}, "hash": "98bd0c2ea89796e2a164b7e6a49d4a22646993923c40216341d6ff153d82f5f0", "class_name": "RelatedNodeInfo"}}, "text": "It also helps if it\u2019s too costly to label enough data.\nFor a deep dive into the differences between these approaches, check out \"Supervised\nvs. Unsupervised Learning: What's the Difference?\"\nReinforcement machine learning\nReinforcement machine learning is a machine learning model that is similar to\nsupervised learning, but the algorithm isn\u2019t trained using sample data. This model learns\nas it goes by using trial and error. A sequence of successful outcomes will be reinforced\nto develop the best recommendation or policy for a given problem.\nThe IBM Watson\u00ae system that won the Jeopardy! challenge in 2011 is a good example.\nThe system used reinforcement learning to learn when to attempt an answer (or\nquestion, as it were), which square to select on the board, and how much to\nwager\u2014especially on daily doubles.\nLearn more about reinforcement learning\nCommon machine learning algorithms\nA number of machine learning algorithms are commonly used. These include:\nNeural networks: Neural networks simulate the way the human brain works, with\na huge number of linked processing nodes. Neural networks are good at\nrecognizing patterns and play an important role in applications including natural\nlanguage translation, image recognition, speech recognition, and image creation.\nLinear regression: This algorithm is used to predict numerical values, based on a\nlinear relationship between different values. For example, the technique could be\nused to predict house prices based on historical data for the area.\nLogistic regression: This supervised learning algorithm makes predictions for\ncategorical response variables, such as \u201cyes/no\u201d answers to questions. It can be\nused for applications such as classifying spam and quality control on a\nproduction line.\nClustering: Using unsupervised learning, clustering algorithms can identify\npatterns in data so that it can be grouped. Computers can help data scientists by\nidentifying differences between data items that humans have overlooked.\nDecision trees: Decision trees can be used for both predicting numerical values\n(regression) and classifying data into categories. Decision trees use a branching\nsequence of linked decisions that can be represented with a tree diagram. One of\nthe advantages of decision trees is that they are easy to validate and audit,\nunlike the black box of the neural network.\nRandom forests: In a random forest, the machine learning algorithm predicts a\nvalue or category by combining the results from a number of decision trees.\nAdvantages and disadvantages of machine learning algorithms\nDepending on your budget, need for speed and precision required, each algorithm\ntype\u2014supervised, unsupervised, semi-supervised, or reinforcement\u2014has its own\nadvantages and disadvantages. For example, decision tree algorithms are used for both\npredicting numerical values (regression problems) and classifying data into categories.\nDecision trees use a branching sequence of linked decisions that may be represented\nwith a tree diagram. A prime advantage of decision trees is that they are easier to\nvalidate and audit than a neural network. The bad news is that they can be more\nunstable than other decision predictors.\nOverall, there are many advantages to machine learning that businesses can leverage\nfor new efficiencies. These include machine learning identifying patterns and trends in\nmassive volumes of data that humans might not spot at all. And this analysis requires\nlittle human intervention: just feed in the dataset of interest and let the machine learning\nsystem assemble and refine its own algorithms\u2014which will continually improve with\nmore data input over time. Customers and users can enjoy a more personalized\nexperience as the model learns more with every experience with that person.\nOn the downside, machine learning requires large training datasets that are accurate\nand unbiased. GIGO is the operative factor: garbage in / garbage out.", "start_char_idx": 7559, "end_char_idx": 11486, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "db26e25e-87d0-4733-a486-40d71ccd51c6": {"__data__": {"id_": "db26e25e-87d0-4733-a486-40d71ccd51c6", "embedding": null, "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "node_type": "4", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "1adc40efe6dabc0a3eddca0cbda5a4c97bb0422c87110fdb1847ae3406fa69a2", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "0f57e92b-7644-4f0d-a6bd-5e039a0228d1", "node_type": "1", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "bf0b169726e1856d83166d32bd957040e0df7ccb6677e02e591572d245876f5d", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "465ffc8b-5db9-4da0-a722-cfe37443f6b9", "node_type": "1", "metadata": {}, "hash": "1cab36cf26e435222503b8fdc466f00ea23e4c859f0b0d136eb6431cbf925bf8", "class_name": "RelatedNodeInfo"}}, "text": "GIGO is the operative factor: garbage in / garbage out. Gathering\nsufficient data and having a system robust enough to run it might also be a drain on\nresources. Machine learning can also be prone to error, depending on the input. With\ntoo small a sample, the system could produce a perfectly logical algorithm that is\ncompletely wrong or misleading. To avoid wasting budget or displeasing customers,\norganizations should act on the answers only when there is high confidence in the\noutput.\nReal-world machine learning use cases\nHere are just a few examples of machine learning you might encounter every day:\nSpeech recognition: It is also known as automatic speech recognition (ASR), computer\nspeech recognition, or speech-to-text, and it is a capability which uses natural language\nprocessing (NLP) to translate human speech into a written format. Many mobile devices\nincorporate speech recognition into their systems to conduct voice search\u2014e.g. Siri\u2014or\nimprove accessibility for texting.\nCustomer service: Online chatbots are replacing human agents along the customer\njourney, changing the way we think about customer engagement across websites and\nsocial media platforms. Chatbots answer frequently asked questions (FAQs) about\ntopics such as shipping, or provide personalized advice, cross-selling products or\nsuggesting sizes for users. Examples include virtual agents on e-commerce sites;\nmessaging bots, using Slack and Facebook Messenger; and tasks usually done by\nvirtual assistants and voice assistants.\nComputer vision: This AI technology enables computers to derive meaningful\ninformation from digital images, videos, and other visual inputs, and then take the\nappropriate action. Powered by convolutional neural networks, computer vision has\napplications in photo tagging on social media, radiology imaging in healthcare, and\nself-driving cars in the automotive industry.\nRecommendation engines: Using past consumption behavior data, AI algorithms can\nhelp to discover data trends that can be used to develop more effective cross-selling\nstrategies. Recommendation engines are used by online retailers to make relevant\nproduct recommendations to customers during the checkout process.\nRobotic process automation (RPA): Also known as software robotics, RPA uses\nintelligent automation technologies to perform repetitive manual tasks.\nAutomated stock trading: Designed to optimize stock portfolios, AI-driven\nhigh-frequency trading platforms make thousands or even millions of trades per day\nwithout human intervention.\nFraud detection: Banks and other financial institutions can use machine learning to spot\nsuspicious transactions. Supervised learning can train a model using information about\nknown fraudulent transactions. Anomaly detection can identify transactions that look\natypical and deserve further investigation.\nChallenges of machine learning\nAs machine learning technology has developed, it has certainly made our lives easier.\nHowever, implementing machine learning in businesses has also raised a number of\nethical concerns about AI technologies. Some of these include:\nTechnological singularity\nWhile this topic garners a lot of public attention, many researchers are not concerned\nwith the idea of AI surpassing human intelligence in the near future. Technological\nsingularity is also referred to as strong AI or superintelligence. Philosopher Nick\nBostrum defines superintelligence as \u201cany intellect that vastly outperforms the best\nhuman brains in practically every field, including scientific creativity, general wisdom,\nand social skills.\u201d Despite the fact that superintelligence is not imminent in society, the\nidea of it raises some interesting questions as we consider the use of autonomous\nsystems, like self-driving cars. It\u2019s unrealistic to think that a driverless car would never\nhave an accident, but who is responsible and liable under those circumstances? Should\nwe still develop autonomous vehicles, or do we limit this technology to\nsemi-autonomous vehicles which help people drive safely?", "start_char_idx": 11431, "end_char_idx": 15467, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "465ffc8b-5db9-4da0-a722-cfe37443f6b9": {"__data__": {"id_": "465ffc8b-5db9-4da0-a722-cfe37443f6b9", "embedding": null, "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "node_type": "4", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "1adc40efe6dabc0a3eddca0cbda5a4c97bb0422c87110fdb1847ae3406fa69a2", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "db26e25e-87d0-4733-a486-40d71ccd51c6", "node_type": "1", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "eae6bcd6e6af56b2e3134e98a354b08b28f6634150e58e118b68bd1f3604f53d", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "6ec07935-7cd1-4a62-8dc7-b7d189acada5", "node_type": "1", "metadata": {}, "hash": "245f82c83f6c9ab4743d5c35b0d85af2c0d153e11ad7aff32569e35fc4e656bd", "class_name": "RelatedNodeInfo"}}, "text": "The jury is still out on this,\nbut these are the types of ethical debates that are occurring as new, innovative AI\ntechnology develops.\nAI impact on jobs\nWhile a lot of public perception of artificial intelligence centers around job losses, this\nconcern should probably be reframed. With every disruptive, new technology, we see\nthat the market demand for specific job roles shifts. For example, when we look at the\nautomotive industry, many manufacturers, like GM, are shifting to focus on electric\nvehicle production to align with green initiatives. The energy industry isn\u2019t going away,\nbut the source of energy is shifting from a fuel economy to an electric one.\nIn a similar way, artificial intelligence will shift the demand for jobs to other areas. There\nwill need to be individuals to help manage AI systems. There will still need to be people\nto address more complex problems within the industries that are most likely to be\naffected by job demand shifts, such as customer service. The biggest challenge with\nartificial intelligence and its effect on the job market will be helping people to transition\nto new roles that are in demand.\nPrivacy\nPrivacy tends to be discussed in the context of data privacy, data protection, and data\nsecurity. These concerns have allowed policymakers to make more strides in recent\nyears. For example, in 2016, GDPR legislation was created to protect the personal data\nof people in the European Union and European Economic Area, giving individuals more\ncontrol of their data. In the United States, individual states are developing policies, such\nas the California Consumer Privacy Act (CCPA), which was introduced in 2018 and\nrequires businesses to inform consumers about the collection of their data. Legislation\nsuch as this has forced companies to rethink how they store and use personally\nidentifiable information (PII). As a result, investments in security have become an\nincreasing priority for businesses as they seek to eliminate any vulnerabilities and\nopportunities for surveillance, hacking, and cyberattacks.\nBias and discrimination\nInstances of bias and discrimination across a number of machine learning systems have\nraised many ethical questions regarding the use of artificial intelligence. How can we\nsafeguard against bias and discrimination when the training data itself may be\ngenerated by biased human processes? While companies typically have good\nintentions for their automation efforts, Reuters (link resides outside ibm.com) highlights\nsome of the unforeseen consequences of incorporating AI into hiring practices. In their\neffort to automate and simplify a process, Amazon unintentionally discriminated against\njob candidates by gender for technical roles, and the company ultimately had to scrap\nthe project. Harvard Business Review (link resides outside ibm.com) has raised other\npointed questions about the use of AI in hiring practices, such as what data you should\nbe able to use when evaluating a candidate for a role.\nBias and discrimination aren\u2019t limited to the human resources function either; they can\nbe found in a number of applications from facial recognition software to social media\nalgorithms.\nAs businesses become more aware of the risks with AI, they\u2019ve also become more\nactive in this discussion around AI ethics and values. For example, IBM has sunset its\ngeneral purpose facial recognition and analysis products. IBM CEO Arvind Krishna\nwrote: \u201cIBM firmly opposes and will not condone uses of any technology, including facial\nrecognition technology offered by other vendors, for mass surveillance, racial profiling,\nviolations of basic human rights and freedoms, or any purpose which is not consistent\nwith our values and Principles of Trust and Transparency.\u201d\nAccountability\nSince there isn\u2019t significant legislation to regulate AI practices, there is no real\nenforcement mechanism to ensure that ethical AI is practiced.", "start_char_idx": 15468, "end_char_idx": 19378, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "6ec07935-7cd1-4a62-8dc7-b7d189acada5": {"__data__": {"id_": "6ec07935-7cd1-4a62-8dc7-b7d189acada5", "embedding": null, "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "e853545c-0ca1-4b7e-9681-02919ad26522", "node_type": "4", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "1adc40efe6dabc0a3eddca0cbda5a4c97bb0422c87110fdb1847ae3406fa69a2", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "465ffc8b-5db9-4da0-a722-cfe37443f6b9", "node_type": "1", "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "3cd3debe9e3d6767b01c8b3ba5e025e90d959b5a4878704cdad6ffca9a96f195", "class_name": "RelatedNodeInfo"}}, "text": "The current incentives for\ncompanies to be ethical are the negative repercussions of an unethical AI system on the\nbottom line. To fill the gap, ethical frameworks have emerged as part of a collaboration\nbetween ethicists and researchers to govern the construction and distribution of AI\nmodels within society. However, at the moment, these only serve to guide. Some\nresearch (link resides outside ibm.com) shows that the combination of distributed\nresponsibility and a lack of foresight into potential consequences aren\u2019t conducive to\npreventing harm to society.\nRead more about IBM's position on AI Ethics\nHow to choose the right AI platform for machine learning\nSelecting a platform can be a challenging process, as the wrong system can drive up\ncosts, or limit the use of other valuable tools or technologies. When reviewing multiple\nvendors to select an AI platform, there is often a tendency to think that more features =\na better system. Maybe so, but reviewers should start by thinking through what the AI\nplatform will be doing for their organization. What machine learning capabilities need to\nbe delivered and what features are important to accomplish them? One missing feature\nmight doom the usefulness of an entire system. Here are some features to consider.\nMLOps capabilities. Does the system have:\na unified interface for ease of management?\nautomated machine learning tools for faster model creation with low-code\nand no-code functionality?\ndecision optimization to streamline the selection and deployment of\noptimization models?\nvisual modeling to combine visual data science with open-source libraries\nand notebook-based interfaces on a unified data and AI studio?\nautomated development for beginners to get started quickly and more\nadvanced data scientists to experiment?\nsynthetic data generator as an alternative or supplement to real-world data\nwhen real-world data is not readily available?\nGenerative AI capabilities. Does the system have:\na content generator that can generate text, images and other content\nbased on the data it was trained on?\nautomated classification to read and classify written input, such as\nevaluating and sorting customer complaints or reviewing customer\nfeedback sentiment?\na summary generator that can transform dense text into a high-quality\nsummary, capture key points from financial reports, and generate meeting\ntranscriptions?\na data extraction capability to sort through complex details and quickly pull\nthe necessary information from large documents?", "start_char_idx": 19379, "end_char_idx": 21888, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}}, "docstore/ref_doc_info": {"e853545c-0ca1-4b7e-9681-02919ad26522": {"node_ids": ["35be54dc-30ad-446a-8ceb-55211de07da6", "eb04d635-c6d9-411d-8d43-fffdbf9963c8", "0f57e92b-7644-4f0d-a6bd-5e039a0228d1", "db26e25e-87d0-4733-a486-40d71ccd51c6", "465ffc8b-5db9-4da0-a722-cfe37443f6b9", "6ec07935-7cd1-4a62-8dc7-b7d189acada5"], "metadata": {"file_path": "..\\Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}}}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Experiments/storage/graph_store.json
================================================
{"graph_dict": {}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Experiments/storage/image__vector_store.json
================================================
{"embedding_dict": {}, "text_id_to_ref_doc_id": {}, "metadata_dict": {}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Experiments/storage/index_store.json
================================================
{"index_store/data": {"f7d0f6e4-6ef2-489e-b7a2-4e5e22a937b6": {"__type__": "vector_store", "__data__": "{\"index_id\": \"f7d0f6e4-6ef2-489e-b7a2-4e5e22a937b6\", \"summary\": null, \"nodes_dict\": {\"35be54dc-30ad-446a-8ceb-55211de07da6\": \"35be54dc-30ad-446a-8ceb-55211de07da6\", \"eb04d635-c6d9-411d-8d43-fffdbf9963c8\": \"eb04d635-c6d9-411d-8d43-fffdbf9963c8\", \"0f57e92b-7644-4f0d-a6bd-5e039a0228d1\": \"0f57e92b-7644-4f0d-a6bd-5e039a0228d1\", \"db26e25e-87d0-4733-a486-40d71ccd51c6\": \"db26e25e-87d0-4733-a486-40d71ccd51c6\", \"465ffc8b-5db9-4da0-a722-cfe37443f6b9\": \"465ffc8b-5db9-4da0-a722-cfe37443f6b9\", \"6ec07935-7cd1-4a62-8dc7-b7d189acada5\": \"6ec07935-7cd1-4a62-8dc7-b7d189acada5\"}, \"doc_id_dict\": {}, \"embeddings_dict\": {}}"}}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Logger.py
================================================
import logging
import os
from datetime import datetime
LOG_FILE=f"{datetime.now().strftime('%m_%d_%Y_%H_%M_%S')}.log"
log_path=os.path.join(os.getcwd(),"logs")
os.makedirs(log_path,exist_ok=True)
LOG_FILEPATH=os.path.join(log_path,LOG_FILE)
logging.basicConfig(level=logging.INFO,
filename=LOG_FILEPATH,
format="[%(asctime)s] %(lineno)d %(name)s - %(levelname)s - %(message)s"
)
#[2024-01-10 15:57:26,997] 6 root - INFO - this my second tesgting
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/QAWithPDF/__init__.py
================================================
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/QAWithPDF/data_ingestion.py
================================================
from llama_index.core import SimpleDirectoryReader
import sys
from Exception import customexception
from Logger import logging
def load_data(data):
"""
Load PDF documents from a specified directory.
Parameters:
- data (str): The path to the directory containing PDF files.
Returns:
- A list of loaded PDF documents. The specific type of documents may vary.
"""
try:
logging.info("data loading started...")
loader = SimpleDirectoryReader("Data")
documents=loader.load_data()
logging.info("data loading completed...")
return documents
except Exception as e:
logging.info("exception in loading data...")
raise customexception(e,sys)
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/QAWithPDF/embeddings.py
================================================
from llama_index.core import VectorStoreIndex
from llama_index.core import ServiceContext
from llama_index.core import StorageContext, load_index_from_storage
from llama_index.embeddings.gemini import GeminiEmbedding
from QAWithPDF.data_ingestion import load_data
from QAWithPDF.model_api import load_model
import sys
from Exception import customexception
from Logger import logging
def download_gemini_embedding(model,document):
"""
Downloads and initializes a Gemini Embedding model for vector embeddings.
Returns:
- VectorStoreIndex: An index of vector embeddings for efficient similarity queries.
"""
try:
logging.info("")
gemini_embed_model = GeminiEmbedding(model_name="models/embedding-001")
service_context = ServiceContext.from_defaults(llm=model,embed_model=gemini_embed_model, chunk_size=800, chunk_overlap=20)
logging.info("")
index = VectorStoreIndex.from_documents(document,service_context=service_context)
index.storage_context.persist()
logging.info("")
query_engine = index.as_query_engine()
return query_engine
except Exception as e:
raise customexception(e,sys)
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/QAWithPDF/model_api.py
================================================
import os
from dotenv import load_dotenv
import sys
from llama_index.llms.gemini import Gemini
from IPython.display import Markdown, display
import google.generativeai as genai
from Exception import customexception
from Logger import logging
load_dotenv()
GOOGLE_API_KEY=os.getenv("GOOGLE_API_KEY")
genai.configure(api_key=GOOGLE_API_KEY)
def load_model():
"""
Loads a Gemini-Pro model for natural language processing.
Returns:
- Gemini: An instance of the Gemini class initialized with the 'gemini-pro' model.
"""
try:
model=Gemini(models='gemini-pro',api_key=GOOGLE_API_KEY)
return model
except Exception as e:
raise customexception(e,sys)
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/StreamlitApp.py
================================================
import streamlit as st
from QAWithPDF.data_ingestion import load_data
from QAWithPDF.embeddings import download_gemini_embedding
from QAWithPDF.model_api import load_model
def main():
st.set_page_config("QA with Documents")
doc=st.file_uploader("upload your document")
st.header("QA with Documents(Information Retrieval)")
user_question= st.text_input("Ask your question")
if st.button("submit & process"):
with st.spinner("Processing..."):
document=load_data(doc)
model=load_model()
query_engine=download_gemini_embedding(model,document)
response = query_engine.query(user_question)
st.write(response.response)
if __name__=="__main__":
main()
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/Template.py
================================================
import os
from pathlib import Path
import logging
list_of_files=[
"QAWithPDF/__init__.py",
"QAWithPDF/helper.py",
"Experiments/experiment.ipynb",
"StreamlitApp.py",
"logger.py",
"exception.py"
]
for filepath in list_of_files:
filepath = Path(filepath)
filedir, filename = os.path.split(filepath)
if filedir !="":
os.makedirs(filedir, exist_ok=True)
logging.info(f"Creating directory; {filedir} for the file {filename}")
if (not os.path.exists(filepath)) or (os.path.getsize(filepath) == 0):
with open(filepath, 'w') as f:
pass
logging.info(f"Creating empty file: {filepath}")
else:
logging.info(f"{filename} is already created")
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/logs/02_15_2024_16_21_43.log
================================================
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/logs/02_15_2024_16_22_49.log
================================================
[2024-02-15 16:23:21,778] 17 root - INFO - data loading started...
[2024-02-15 16:23:22,114] 23 root - INFO - exception in loading data...
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/logs/02_15_2024_16_23_52.log
================================================
[2024-02-15 16:24:13,493] 17 root - INFO - data loading started...
[2024-02-15 16:24:13,796] 20 root - INFO - data loading completed...
[2024-02-15 16:24:15,237] 21 root - INFO -
[2024-02-15 16:24:15,554] 25 root - INFO -
[2024-02-15 16:24:29,527] 29 root - INFO -
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/logs/02_15_2024_16_26_42.log
================================================
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/logs/02_15_2024_16_27_41.log
================================================
[2024-02-15 16:28:32,771] 17 root - INFO - data loading started...
[2024-02-15 16:28:33,067] 20 root - INFO - data loading completed...
[2024-02-15 16:28:34,357] 21 root - INFO -
[2024-02-15 16:28:34,669] 25 root - INFO -
[2024-02-15 16:28:48,579] 29 root - INFO -
[2024-02-15 16:30:32,214] 17 root - INFO - data loading started...
[2024-02-15 16:30:32,451] 20 root - INFO - data loading completed...
[2024-02-15 16:30:33,923] 21 root - INFO -
[2024-02-15 16:30:33,928] 25 root - INFO -
[2024-02-15 16:30:47,788] 29 root - INFO -
[2024-02-15 16:31:06,611] 17 root - INFO - data loading started...
[2024-02-15 16:31:06,833] 20 root - INFO - data loading completed...
[2024-02-15 16:31:08,105] 21 root - INFO -
[2024-02-15 16:31:08,110] 25 root - INFO -
[2024-02-15 16:31:22,051] 29 root - INFO -
[2024-02-15 16:32:44,855] 17 root - INFO - data loading started...
[2024-02-15 16:32:45,094] 20 root - INFO - data loading completed...
[2024-02-15 16:32:46,365] 21 root - INFO -
[2024-02-15 16:32:46,371] 25 root - INFO -
[2024-02-15 16:33:00,273] 29 root - INFO -
[2024-02-15 16:33:36,596] 17 root - INFO - data loading started...
[2024-02-15 16:33:36,867] 20 root - INFO - data loading completed...
[2024-02-15 16:33:38,141] 21 root - INFO -
[2024-02-15 16:33:38,152] 25 root - INFO -
[2024-02-15 16:33:51,828] 29 root - INFO -
[2024-02-15 16:35:47,106] 17 root - INFO - data loading started...
[2024-02-15 16:35:47,346] 20 root - INFO - data loading completed...
[2024-02-15 16:35:48,753] 21 root - INFO -
[2024-02-15 16:35:48,760] 25 root - INFO -
[2024-02-15 16:36:02,763] 29 root - INFO -
[2024-02-15 16:36:32,124] 17 root - INFO - data loading started...
[2024-02-15 16:36:32,356] 20 root - INFO - data loading completed...
[2024-02-15 16:36:33,626] 21 root - INFO -
[2024-02-15 16:36:33,631] 25 root - INFO -
[2024-02-15 16:36:47,654] 29 root - INFO -
[2024-02-15 16:37:45,526] 17 root - INFO - data loading started...
[2024-02-15 16:37:45,773] 20 root - INFO - data loading completed...
[2024-02-15 16:37:47,050] 21 root - INFO -
[2024-02-15 16:37:47,056] 25 root - INFO -
[2024-02-15 16:38:01,017] 29 root - INFO -
[2024-02-15 16:41:22,311] 17 root - INFO - data loading started...
[2024-02-15 16:41:22,313] 20 root - INFO - data loading completed...
[2024-02-15 16:41:23,759] 21 root - INFO -
[2024-02-15 16:41:23,765] 25 root - INFO -
[2024-02-15 16:41:25,203] 29 root - INFO -
[2024-02-15 16:43:17,278] 17 root - INFO - data loading started...
[2024-02-15 16:43:17,282] 20 root - INFO - data loading completed...
[2024-02-15 16:43:18,551] 21 root - INFO -
[2024-02-15 16:43:18,556] 25 root - INFO -
[2024-02-15 16:43:20,026] 29 root - INFO -
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/logs/02_15_2024_16_45_53.log
================================================
[2024-02-15 16:46:23,481] 17 root - INFO - data loading started...
[2024-02-15 16:46:23,570] 20 root - INFO - data loading completed...
[2024-02-15 16:46:24,998] 21 root - INFO -
[2024-02-15 16:46:25,254] 25 root - INFO -
[2024-02-15 16:46:26,693] 29 root - INFO -
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/logs/02_15_2024_16_58_10.log
================================================
[2024-02-15 16:59:17,283] 17 root - INFO - data loading started...
[2024-02-15 16:59:17,318] 20 root - INFO - data loading completed...
[2024-02-15 16:59:18,801] 21 root - INFO -
[2024-02-15 16:59:19,058] 25 root - INFO -
[2024-02-15 16:59:23,776] 29 root - INFO -
[2024-02-15 16:59:57,445] 17 root - INFO - data loading started...
[2024-02-15 16:59:57,447] 20 root - INFO - data loading completed...
[2024-02-15 16:59:58,713] 21 root - INFO -
[2024-02-15 16:59:58,717] 25 root - INFO -
[2024-02-15 17:00:03,011] 29 root - INFO -
[2024-02-15 17:00:46,881] 17 root - INFO - data loading started...
[2024-02-15 17:00:46,883] 20 root - INFO - data loading completed...
[2024-02-15 17:00:48,158] 21 root - INFO -
[2024-02-15 17:00:48,164] 25 root - INFO -
[2024-02-15 17:00:52,865] 29 root - INFO -
[2024-02-15 17:01:23,993] 17 root - INFO - data loading started...
[2024-02-15 17:01:23,994] 20 root - INFO - data loading completed...
[2024-02-15 17:01:25,268] 21 root - INFO -
[2024-02-15 17:01:25,277] 25 root - INFO -
[2024-02-15 17:01:29,961] 29 root - INFO -
[2024-02-15 17:03:09,292] 17 root - INFO - data loading started...
[2024-02-15 17:03:09,297] 20 root - INFO - data loading completed...
[2024-02-15 17:03:10,563] 21 root - INFO -
[2024-02-15 17:03:10,568] 25 root - INFO -
[2024-02-15 17:03:15,249] 29 root - INFO -
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/requirements.txt
================================================
llama-index
google-generativeai
llama-index-llms-gemini
pypdf
python-dotenv
IPython
llama-index-embeddings-gemini
streamlit
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/setup.py
================================================
from setuptools import find_packages, setup
setup(
name = 'QApplication',
version= '0.0.1',
author= 'sunny savita',
author_email= 'sunny.savita@gmail.com',
packages= find_packages(),
install_requires = []
)
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/storage/default__vector_store.json
================================================
{"embedding_dict": {"488d9176-adb9-4aa4-be31-c79adbf45c9a": [-0.003852138, -0.061276186, -0.047077414, 0.0011844443, 0.060794484, 0.022305408, 0.0005401673, -0.01412325, 0.013982589, 0.017736057, -0.010627608, 0.034142908, 0.009226106, -0.026668709, -0.0043618367, -0.06816779, 0.021812676, 0.04737672, 0.019740243, -0.020609727, -0.0077337697, 0.004573156, 0.004269788, -0.033530798, -0.013060476, -0.036118627, -0.003548419, -0.08812537, -0.050797146, 0.058747005, -0.03549059, 0.015946526, -0.007802678, 0.058608577, 0.012106461, -0.014546282, 0.0065971734, 0.04021186, 0.010219882, -0.022799892, 0.009263706, -0.046624515, -0.00824291, -0.0054744543, -0.008656531, -0.029492691, 0.008188304, 0.010613113, 0.02576002, -0.07604761, 0.016095966, 0.012655053, 0.056717455, -0.0022508744, 0.045436285, -0.032397136, 0.0045820633, 0.016745975, -0.00037501997, 0.00081090495, 0.0107026715, 0.01472055, -0.01944821, 0.025549488, 0.045073647, -0.023985805, -0.07461258, 0.028215118, 0.0051959916, 0.0016332627, 0.01641553, 0.0033524544, 0.07347818, -0.023254793, -0.029150426, -0.09737253, -0.03181088, 0.07137937, 0.031471405, 0.017346688, 0.011461012, -0.027663998, -0.018715246, -0.06305269, -0.0622558, -0.0038444123, -0.0037758944, -0.034212146, -0.035697572, 0.056295473, -0.00905029, 0.017012121, 0.06300307, -0.06129285, -0.0090636285, 0.06006898, 0.0020984234, -0.030408183, 0.022591608, -0.053834554, 0.04103467, -0.007348313, -0.021316264, 0.022899067, 0.032631442, 3.3747165e-05, -0.070665866, 0.07020648, -0.00024905938, 0.024505824, -0.011164506, -0.02915362, -0.034942728, -0.018414982, 0.05013134, 0.0030212284, 0.012550406, 0.017156264, 0.027398022, 0.049795415, 0.012877317, 0.035832528, 0.051878408, -0.037690964, -0.0138490135, 0.045279693, -0.0018439138, 0.0071700495, 0.03251133, -0.016142752, 0.0067674033, -0.053094927, -0.018145679, -0.002343423, -0.018450957, 0.07941921, 0.036368407, -0.0036989013, 0.033805065, 0.06483147, -0.029076045, 0.0003721102, 0.019360967, 0.02233511, 0.014239349, 0.023028644, -0.04228167, -0.018969677, -0.016689952, -0.017414864, -0.041758362, 0.020353602, -0.06286454, -0.03157509, 0.025890775, -0.0031532382, -0.03227536, 0.06452823, 0.0256505, 0.023049401, 0.07021464, 0.02635128, 0.018978436, 0.071373925, -0.048129827, -0.054490086, 0.011413519, -0.0021736945, 0.0005592066, 0.019330459, 0.02395187, 0.12791531, -0.052448187, -0.04172162, -0.009450293, -0.040078938, 0.027776385, 0.04411522, -0.0097109685, -0.014435375, -0.03196173, -0.04682097, -0.0051426254, 0.032117717, 0.022760436, 0.029364983, 0.062120833, -0.015178072, -0.059511904, 0.035592355, -0.027870964, 0.0029604703, -0.06567347, -0.00010961049, -0.0074674813, 0.07634051, 0.028348697, 0.01618314, 0.022106307, -0.02417291, 0.020538613, 0.03625446, -0.004585577, -0.032153837, 0.03258881, -0.010771559, 0.068967886, -0.028969567, -0.09059125, 0.04033357, -0.059789278, 0.025205776, -0.015239412, 0.03928174, 0.030107068, 0.023099044, -0.0062337727, -0.024153389, -0.019234858, -0.03295013, -0.024734948, 0.020519579, -0.043641627, 0.021500196, 0.015036, 0.05631521, -0.010997993, 0.037345033, 0.021516902, -0.05775138, 0.017096784, 0.079970635, -0.0012657873, -0.0066382075, 0.06089156, -0.044966005, 0.03898269, 0.022270616, 0.050036382, 0.033586316, -0.017390108, 0.005041151, 0.046238516, -0.0120008, -0.0707891, -0.045511276, -0.012459588, 0.03882602, 0.013154815, 0.03079569, -0.0015192147, -0.02635927, -0.030225601, 0.019205121, -0.048035473, 0.046966694, 0.00055690645, 0.027638046, -0.02565777, -0.0001617356, -0.026486274, 0.054151498, 0.0071786395, 0.010229337, 0.019135023, -0.0266956, -0.02414379, -0.06560728, -0.011916749, 0.05164698, -0.050506517, -0.067354515, 0.029219428, 0.0056268573, 0.015427284, 0.030340532, 0.003980587, 0.036910407, -0.03287431, -0.019645995, 0.010488023, 0.015249719, 0.04549606, -0.023679074, -0.045529526, 0.033143282, -0.015125781, 0.003976065, -0.0046908925, -0.053893335, -0.025409125, 0.022467015, 0.008032244, -0.069166854, -0.0582546, -0.0067681973, -0.0073394696, 0.06468138, -0.036443677, -0.032353476, -0.002842509, -0.07453044, 0.020595351, -0.071014725, 0.014968473, 0.027220465, -0.011755604, -0.059296187, 0.020137688, 0.04545994, 0.030869186, -0.054060213, -0.046173014, -0.027252259, 0.048760347, 0.06276069, 0.04471571, 0.02191728, -0.033562236, 0.0205351, 0.018863766, 0.065341935, -0.013674963, 0.009023712, -0.017098082, 0.036765996, -0.033256244, 0.04634764, -0.042930204, 0.026719362, 0.0096211145, 0.015800284, -0.0631567, 0.05538662, -0.015065971, -0.023440477, -0.02809825, -0.01834312, -0.021562807, -0.037505098, -0.014663999, 0.01752669, -0.0030478274, -0.006426082, 0.0401406, -0.039406735, -0.0464021, 0.029877491, 0.0955085, 0.0015143135, 0.011940094, 0.055243313, -0.048460104, 0.0020205253, 0.045234453, -0.006297653, 0.03414942, 0.0030086911, 0.06789295, -0.05923476, -0.030792028, 0.036857367, -0.038409147, -0.0012622143, -0.012583322, -0.008529399, -0.02339556, 0.031816494, -0.0069588795, 0.014119569, 0.032075137, -0.0136341, 0.03135381, -0.037982147, -0.006820778, -0.047560852, -0.05258189, -0.04642885, 0.016090326, -0.008195353, -0.03882639, -0.019608868, 0.05762761, 0.09089298, 0.009237148, 0.015184288, 0.0017288702, 0.046333816, -0.03049902, 0.017104011, -0.0122461235, 0.031858068, 0.07570864, 0.0039164005, 0.014837794, 0.0025485987, -0.035484478, -0.0916056, 0.017013773, 0.024654249, -0.017086033, -0.034073174, -0.06473451, -0.034191668, -0.020368269, 0.023725145, -0.022589458, -0.01798836, 0.008307387, -0.0010502255, 0.005271835, 0.030345626, 0.04080434, -0.028109673, -0.019717954, -0.011993643, 0.0657738, -0.0099911, 0.009209258, 0.07301753, -0.0022129393, -0.045006886, 0.027565151, 0.0063680075, -0.0742673, -0.0075028, 0.03988902, 0.009077222, 0.026715832, 0.022306584, 0.03979926, -0.03711299, 0.016560765, -0.007459423, -0.025096647, -0.027673598, -0.002537831, 0.060340285, -0.01662417, -0.0072715576, 0.013203417, 0.012309909, 0.0070228497, -0.019253107, -0.06052632, -0.058068275, -0.030211765, -0.043964762, 0.033980798, -0.0851438, 0.051637273, 0.004042461, -0.067993835, -0.024625022, 0.004492607, -0.019143237, -0.007481646, 0.032244995, 0.005096737, -0.0080188345, 0.039034948, -0.028082479, -0.02138558, -0.026703747, 0.04683832, -0.06376919, 0.0052835983, -0.056561347, 0.012824116, 0.040505543, -0.0017766068, -0.017032433, 0.036207672, -0.03018944, 0.011926607, -0.012704641, -0.06507482, 0.055860844, -0.07277459, -0.011348043, -0.019692639, 0.040413156, 0.048749313, -0.021307074, -0.04308595, 0.02035367, 0.045531202, 0.033915654, -0.0483236, 0.011538226, 0.0073479293, 0.029182527, -0.051528364, -0.011947549, -0.03135733, 0.00013632118, -0.028983207, 0.098489724, 0.023555119, 0.05704598, -0.023419466, 0.010373979, -0.016481774, 0.003439941, 0.055834036, -0.0976254, 0.0149839325, 0.011159815, -0.01868148, 0.019037414, 0.019728573, 0.042164553, -0.0072612413, 0.013744626, 0.056984227, -0.037133336, 0.00038496547, -0.024123037, 0.034532793, -0.00093748304, 0.050597016, -0.019578675, -0.080390394, 0.0047906325, 0.04031371, -0.057382803, 0.023215337, -0.0018894507, -0.026743492, 0.0021209663, -0.04022459, 0.036826823, -0.078110255, 0.017833358, 0.016330527, -0.025727432, -0.01856945, 0.015179869, 0.030535793, -0.04009765, 0.025551531, 0.009799979, 0.03159966, 0.017995117, -0.032772902, 0.0030052753, -0.035969596, -0.092815526, 0.03832216, -0.036237683, -0.022776514, -0.013853839, 0.05335264, -0.02873286, 0.03771051, -0.010113412, -0.004206626, -0.014714412, -0.006873049, -0.007918709, -0.05465087, 0.05771526, 0.017038913, 0.01174938, 0.0553496, -0.0078605125, -0.009611197, -0.010244467, 0.06643808, -0.067194276, -0.0157218, -0.03210138, -0.0016000168, 0.016181719, 0.05588269, -0.053949717, 0.013127721, -0.005966352, -0.06013722, 0.03813997, 0.028220339, 0.0016162841, 0.0011038493, 0.025532044, -0.00023747278, -0.029035214, 0.036583256, 0.05093265, 0.029697802, -0.045147296, -0.024819849, 0.050269067, -0.028462201, -0.027834505, 7.1875045e-05, -0.0068186787, 0.035943635, -0.024270095, -0.04360828, 0.02875245, -0.006150675, -0.037382077, 0.040278938, -0.018545657, 0.035446003, 0.043161545, 0.017758261, 0.02770077, 0.020725405, 0.014140497, -0.01312913, -0.031422768, -0.008493931, -0.051795617, -0.056064438, -0.029919205, 0.050454687, 0.054759428, -0.03194909, -0.06255235, 0.036630016, -0.0151123535, 0.010227994, 0.015279913, 0.018812621, -0.021693522, -0.015528042, 0.011433739, 0.062079247, 0.057058293, 0.066434294, 0.015256387, 0.06893915, 0.009625966, -0.025634779, -0.024207512, -0.074661076, -0.01566666, 0.008153024, 0.010623766, -0.07396616, 0.017387962, -0.013164548, -0.037395757, 0.0017455239, 0.0136288125, -0.023585025, -0.059625566, -0.011730501, -0.0012560518, -0.04945098, -0.029593637, 0.028799722, -0.021277713, 0.058829095, 0.00016151805, 0.022352437, -0.014576662, 0.032034718, -0.034645036, -0.041827515, 0.023800295, 0.00041087542, -0.0014366187, -0.0032171954, -0.052046563, 0.0101117985, -0.06509469, -0.00978197, 0.020506693, -0.04729544, 0.0092510125, 0.045527235, -0.005555496, 0.0499217, 0.02482421, -0.048523504, 0.05683094, 0.009982877, 0.012042143, -0.034443155, 0.014005327, -0.009739289, -0.01228032, -0.032751262, 0.01588844, -0.00088459195, 0.005818355, -0.036488876, -0.052618917, 0.0012438004, 0.019492473, -0.01226905, 0.039291456, 0.06766182, 0.0147162145, -0.03108134, -0.024001054, 0.036297753, 0.07613414, -0.02195333, -0.034952328, -0.012631005, 0.026240518, 0.042140342, -0.03493964, 0.006262344, 0.016724437, 0.006003758, 0.045878, 0.024882857, -0.019353746, 0.035412215, -0.010722574, -1.8982262e-05, -0.06113739, 0.0038904503, -0.0065545207, -0.018119318, 0.0011196508, 0.039990414, 0.016078683, 0.023530466, -0.043948095, -0.0875243, 0.04842949, -0.035717785, -0.034309376, -0.005653434, 0.033581495, 0.006358108, -0.041710045, -0.030502858, 0.028692834, -0.037246358, 0.07512885, 0.024902461, 0.03205471, 0.004322143, -0.08429526, -0.0191295, -0.01985802, 0.008082696, 0.027710052, 0.04845065, -0.052515563, -0.03683034, -0.05364968, 0.017649524, -0.029765332, -0.0317979, -0.038699098, -0.01682811, 0.009857122, 0.06502937, -0.0455899, -0.017679887, -0.0052599567, -0.0036529603, -0.012582555, -0.023541529, 0.0033277387, 0.00626273, -0.007315422, 0.042858742, 0.034814477, -0.027677475, 0.048023555], "3df58e2a-eb97-4ce7-a7b8-8504521e12ef": [5.3766114e-05, -0.064364485, -0.03976549, 0.008714552, 0.04437889, -0.0043496215, 0.021822179, -0.0034417075, 0.009015436, 0.020095654, -0.04236921, 0.024260648, 0.012953749, -0.023757748, 0.0026454555, -0.070426784, 0.0024284604, 0.04493709, 0.019776523, -0.0030355232, 0.0032231335, -0.0052413587, 0.0361183, -0.04425943, -0.029331105, -0.054435886, 0.0005533417, -0.07758469, -0.0400505, 0.05568952, -0.02973413, 0.0332139, -0.024247924, 0.051845513, 0.013853228, -0.02692352, 0.01502288, 0.071387164, -0.004589941, -0.010963494, 0.016505085, -0.0446494, 0.0072352174, 0.011055451, -0.008427531, 0.012508312, -0.012085067, -0.0024038581, -0.0030616813, -0.070101865, 0.004245775, -0.005620315, 0.06230136, 0.011076482, 0.010917464, -0.02375765, -0.0071837874, -0.016477846, -0.0035925861, 0.009875481, -0.008584053, 0.025662351, -0.025591804, 0.014625848, 0.008045325, -0.037834495, -0.049650807, 0.0084604565, 0.021810865, -0.0031426516, -0.015415633, -0.012522866, 0.08232621, -0.038983025, -0.010044565, -0.11822643, -0.012298947, 0.061378982, 0.02949857, 0.031137643, 0.028001983, -0.047056038, -0.027306473, -0.057636, -0.06693876, 0.015641237, -0.02176024, -0.02840806, -0.03305468, 0.06792887, -0.0075107496, -0.03102968, 0.061449375, -0.060011648, 0.0021969618, 0.05737317, -0.006844008, -0.030706959, 0.031106705, -0.047144927, 0.009596262, 0.0051983134, -0.03819567, -0.033599965, 0.031869747, 0.007957255, -0.067156635, 0.06800394, -0.008130278, 0.0030243366, 0.0051237317, -0.0104686925, -0.03409442, -0.031790365, 0.08037933, -0.009798569, 0.026378963, 0.04550908, 0.021871427, 0.04096616, 0.015255586, 0.030435912, 0.016518133, -0.050489854, -0.046943635, 0.033937383, 0.016855814, 0.020402426, 0.034354374, -0.016628988, -0.00056826527, -0.02875605, -0.018698908, -0.0076944903, 0.0059471284, 0.0906705, 0.035606228, 0.0137968585, 0.0080109, 0.061037973, -0.02729402, 0.010997979, 0.026185378, 0.02979196, 0.006772453, 0.029999638, -0.024361603, 0.011081196, 0.00847374, -0.02669129, -0.0417332, 0.019265331, -0.059042435, -0.026662732, 0.037139706, 0.011229478, -0.04323647, 0.051325254, 0.025670912, 0.011629968, 0.057146173, 0.016943006, 0.013310253, 0.061900433, -0.028354255, -0.017948622, 0.031850874, 0.028828878, -0.0034811979, 0.025415905, -0.00032256165, 0.12609886, -0.047448713, -0.05206301, 0.0054565887, -0.029554103, 0.041645642, 0.0475524, 0.007297469, -0.02967784, -0.0059060734, -0.048575606, -9.6438e-05, 0.0007863797, 0.031086106, -0.0067711477, 0.07080891, -0.016006686, -0.038120456, -0.0028507826, -0.02282639, -0.0017650998, -0.034375742, 0.014220873, -0.0097062, 0.046075314, 0.01769402, 0.011572906, 0.04283992, -0.03346538, 0.029787429, 0.019237632, -0.0027864892, -0.016613085, 0.049142774, 0.0011930255, 0.06664227, -0.03719216, -0.07865806, 0.02011631, -0.054540824, -0.003642518, -0.013445991, 0.045692895, 0.011774111, 0.013047418, 0.005612273, -0.0022254402, -0.025536986, -0.06375346, -0.018719709, 0.014313563, -0.026563615, 0.02546409, 0.024858793, 0.06812807, -0.02111989, 0.030619645, 0.030537928, -0.04267237, 0.015369765, 0.062066857, 0.007677938, -0.0070589157, 0.046606783, -0.034383345, 0.036629, 0.023467911, 0.03690191, 0.0050065196, -0.035864633, 0.011276575, 0.05667032, 0.010089202, -0.072525196, -0.048117053, 0.0050218734, 0.048848685, -0.011152641, 0.0014279246, -0.06472005, -0.041562665, -0.017442655, 0.019862542, -0.029997619, 0.070335194, -0.0011760333, 0.004556516, -0.044072945, 0.005439029, 0.00761495, 0.07360698, 0.017038396, 0.017646989, 0.021327684, -0.0395852, -0.014582732, -0.06181434, -0.031740896, 0.03385281, -0.065327704, -0.062089954, 0.021028433, 0.01786384, 0.005678862, 0.025239794, -0.008922341, 0.030664844, 0.005397075, -0.00822918, 0.0177816, 0.021787768, 0.038771845, -0.017287847, -0.0368827, 0.009138539, -0.00737481, -0.008446237, -0.019291911, -0.05639142, -0.019184059, -0.0043302695, 0.0132721, -0.080102265, -0.040736128, 0.00034987027, 0.019664, 0.05543213, -0.021728143, -0.054431763, -0.008221508, -0.07373526, 0.011960871, -0.07380793, 0.034845732, 0.0073380345, -0.0152212335, -0.059904367, 0.020266917, 0.057376247, 0.051521007, -0.042703845, -0.056787062, -0.013734043, 0.07417769, 0.064597964, 0.046614796, 0.0048863087, -0.044390764, 0.020643367, -0.010409642, 0.064842656, 0.01297924, 0.0053547407, -0.027174802, 0.036530226, -0.046070244, 0.012098312, -0.03850394, 0.0441116, 0.018818082, 0.010441771, -0.026476808, 0.050820075, -0.021986453, -0.010132047, -0.05494925, -0.011659174, -0.035092026, -0.027900109, -0.011778613, 0.018498784, -0.006976674, -0.02371807, 0.050687667, -0.018285906, -0.053248916, 0.018590458, 0.10826702, 0.0063097985, 0.0044100387, 0.043381225, -0.041368358, -0.0018345367, 0.04223728, -0.011364538, 0.03853699, -0.009660026, 0.097421974, -0.062331952, -0.040077914, 0.020146469, -0.038353853, -0.0139293615, 0.009997909, -0.008034753, -0.015752992, 0.046866547, -0.01987462, 0.023346687, 0.0048556835, -0.033365015, 0.012843278, -0.024208099, 0.005752746, -0.009323345, -0.034543402, -0.04710065, 0.01797202, -0.0083780885, -0.06859497, -0.007010892, 0.025399672, 0.06381925, 0.020973606, -0.014552481, 0.024554033, 0.01322145, -0.020923171, 0.029258145, -0.021996366, 0.04454416, 0.067677714, -0.0012076779, 0.03524139, -0.021813596, -0.03184183, -0.08067629, 0.04092256, 0.021808416, -0.012968811, -0.017126331, -0.06741184, -0.035787884, -0.02092263, 0.029799081, -0.01776688, -0.05072889, 0.00015662023, -0.0033539906, 0.017224858, 0.026292557, 0.032568395, -0.009357647, -0.039298125, 0.013294584, 0.06753376, -0.03322004, 0.013171311, 0.02746974, -0.015509203, -0.04003379, 0.02028699, 0.020661382, -0.085669816, -0.039721042, 0.013901213, 0.026445076, 0.021502746, 0.024937151, 0.05310479, -0.023231229, 0.022048777, -0.0040989234, -0.018477457, -0.025004368, 0.0014422052, 0.05070834, -0.0073341345, -0.022445628, 0.01720875, -0.0069408333, -0.017767742, -0.01702403, -0.050486818, -0.04259264, -0.010838974, -0.038171846, 0.03827046, -0.090162404, 0.023175899, -0.016164834, -0.06478914, -0.030835595, 0.021167269, -0.01734457, 0.0014794734, 0.027940093, 3.0503194e-05, -0.027431713, 0.06128952, -0.026252007, -0.038934503, -0.036414187, 0.0656346, -0.077730745, 0.0076263044, -0.061945472, 0.02252889, 0.033955432, 0.020782398, -0.0006674037, 0.03499913, -0.06379147, -0.020061767, -0.00029376632, -0.064985216, 0.068283334, -0.057467986, 0.0035247332, -0.023597306, 0.043312896, 0.035049405, -0.030990256, -0.05391002, 0.005613999, 0.027121037, 0.024777647, -0.05344901, -0.0058693727, 0.001141248, 0.020355918, -0.051232286, -0.02959161, -0.0026953164, -0.021590993, -0.013670309, 0.10060576, 0.01762614, 0.046861794, -0.015559021, 0.023512557, 0.013948182, -0.009712357, 0.027219407, -0.0948146, 0.030956015, 0.021973832, -0.028681096, 0.012978597, -0.0057335556, -0.00023049705, -0.028866269, 0.0020545803, 0.05864254, -0.048855968, 0.0010501897, -0.017953025, 5.3942964e-05, 0.0053034653, 0.007457521, -0.014961272, -0.065252304, -0.0056494353, 0.057740215, -0.08585229, -0.018792987, 0.0124548115, -0.05025876, 0.016802508, -0.02438714, 0.039636232, -0.05946965, 0.017949559, 0.027983155, -0.021231024, -0.0073142303, -0.0017922694, 0.03060799, -0.04342376, 0.027643718, 0.029587349, 0.043218974, 0.025496963, -0.06923432, -0.0071630897, -0.03221914, -0.08500227, 0.036465578, -0.030648226, -0.056700803, 0.009036114, 0.05102734, -0.017179523, 0.03548741, -0.037816882, 0.015921744, 0.0063257897, 0.008443724, -0.016389908, -0.03723436, 0.04428673, -0.0030276089, -0.008187677, 0.038921777, -0.04136724, -0.010730656, -0.005327932, 0.052880835, -0.06884766, -0.03207755, -0.0312542, 0.013643171, 0.026214665, 0.06056365, -0.06816824, -0.0115831895, -0.017353872, -0.06675896, 0.014436263, 0.026466677, -0.006573758, -0.0009954143, 0.04198273, -0.030371357, -0.019923536, 0.038072396, 0.03376138, 0.037766866, -0.03920084, -0.028188769, 0.05792249, -0.03177698, -0.069185935, 0.008088974, 0.009742564, 0.040555857, -0.038372133, -0.03166697, 0.034667585, 0.0053558205, -0.02449126, 0.065915175, -0.025029011, 0.042544775, 0.051389355, 0.037803866, 0.023572031, 0.03799292, 0.003135306, -0.011715339, -0.018324627, -0.017602678, -0.04127847, -0.051461846, -0.017615896, 0.07782073, 0.05112169, -0.017067876, -0.053497043, 0.043239176, 0.011527969, 0.0120787155, 0.014220007, 0.02995817, -0.0072351675, -0.024919443, -0.00855406, 0.07728426, 0.058922738, 0.055026095, 0.018755939, 0.044079553, -0.011372538, -0.04052573, -0.009455484, -0.06488842, 0.006743684, 0.037376896, -0.0014605793, -0.08858413, -0.010083737, -0.03838803, -0.021838494, 0.030445047, 0.01160192, -0.0029670144, -0.08780737, -0.025239838, -0.016098212, -0.06086352, -0.0066644866, 0.0249122, -0.05214724, 0.046326064, -0.008367367, 0.038151283, -0.002106088, 0.031678323, -0.026574414, -0.045734797, 0.02685538, 0.020281192, 0.014714033, -0.020529216, -0.05412844, 0.005615446, -0.048030924, -0.042683393, 0.015830472, -0.040507946, 0.020547008, 0.030295668, -0.0057541537, 0.039952233, 0.02986737, -0.009622474, 0.05593315, 0.016186241, 0.016131256, -0.03428049, 0.0180998, -0.009415914, -0.031251013, -0.01083247, 0.004052533, 0.0007294103, 0.028505305, -0.045368038, -0.04716516, 0.0003398959, -0.0008178457, 0.007724073, 0.009271362, 0.07746129, 0.010752812, -0.02028956, -0.036713302, 0.03422673, 0.060959827, -0.008916484, -0.06448237, -0.017457306, 0.015239988, 0.012571254, -0.04316459, -0.0033433721, 0.027067387, 0.0033123086, 0.0227691, 0.03750647, -0.031723943, 0.013511421, 0.022214234, -0.009261352, -0.057106785, -0.0036562458, -0.0069746766, -0.008936406, 0.0022127773, 0.013361775, 0.008295825, 0.0040476564, -0.008096704, -0.077799395, 0.04039115, -0.040255215, -0.008705534, 0.004054098, 0.020019397, 0.022461824, -0.04531171, -0.010261506, 0.037856255, -0.022026557, 0.0753328, 0.018242884, 0.014260066, -9.653311e-05, -0.08539432, -0.020275004, -0.016204027, -0.012246925, 0.04304192, 0.049669143, -0.06151984, -0.01570151, -0.053081166, 0.029531285, -0.031425003, -0.034005526, -0.0042829113, -0.031556394, 0.0017064649, 0.034125812, -0.041998465, -0.015865047, 0.006353213, -0.011853677, 0.0025648302, -0.0143977, 0.006449943, -0.00658717, 0.016443973, 0.04702969, 0.021870473, -0.015204782, 0.06293451], "cf355bc0-79e1-4c78-8f7e-e63738ba59f4": [0.0027129017, -0.065092124, -0.036470335, 0.022237102, 0.026512302, -0.009969877, 0.005943337, -0.007973482, 0.0012457297, -0.0014648502, -0.00016676397, 0.024177002, 0.011910719, -0.0032331885, -0.0017957988, -0.054419182, 0.002865891, 0.018782668, 0.01629505, -0.04375043, -0.0043236297, -0.013084012, 0.00017222996, -0.04396574, -0.0076650544, -0.022126028, -0.0017951422, -0.075283535, -0.031324383, 0.06837821, -0.0066189105, 0.0130805215, -0.032120977, 0.038442146, 0.005137629, -0.038982704, 0.013829733, 0.04603631, 0.036553454, 0.0015240523, 0.00640856, -0.039588097, -0.02822846, 0.007012995, -0.019334445, -0.016000831, 0.00781923, 0.008679589, 0.040066373, -0.07931164, 0.019206043, 0.024835462, 0.06405707, -0.015608443, 0.058311965, -0.023365237, 0.0080988165, -0.04437602, -0.006242867, -0.012470059, 0.0020366868, -0.0034666967, -0.032991797, 0.006291295, -0.0012717117, -0.009640822, -0.111303724, -0.013128842, 0.008495796, 0.009487069, 0.00315457, 0.03980686, 0.06809711, 0.015648287, -0.031727083, -0.095416375, -0.040082484, 0.06964597, 0.021311248, 0.048857383, 0.043754395, -0.044545908, -0.039467804, -0.06883958, -0.06820925, 0.018280094, -0.03086109, -0.045069758, -0.030277671, 0.04594689, -0.00532669, -0.008787352, 0.01849104, -0.0023533974, 0.010842335, 0.07878083, -0.0036505116, -0.06268163, 0.056357343, -0.06505031, 0.04730049, 0.033048827, 0.011883642, 0.023591455, 0.027153816, 0.06509047, -0.057480182, 0.040162113, -0.006527118, -0.011039414, -0.03619297, -0.0021882048, -0.0075458996, -0.05474161, 0.07123148, -0.046410367, 0.02149716, 0.060727503, 0.012668655, 0.01363829, 0.031492114, 0.026066583, 0.023338895, -0.042343657, -0.03585883, 0.045377623, 0.025250237, 0.02242454, 0.061457675, -0.010572838, -0.0017969365, -0.017633522, 0.0051443237, -1.842258e-05, 0.020002747, 0.05986055, 0.04817788, -0.0039305096, 0.011847593, 0.017123748, -0.010743663, -0.00915299, 0.034123536, 0.035000514, -0.036160983, 0.038277924, -0.022775466, -0.009149224, -0.00697247, -0.025660789, -0.050677724, 0.04299239, -0.06486947, -0.016873322, 0.025689086, -0.009685578, -0.015434366, 0.028806292, 0.027342834, -0.0062104813, 0.06319403, 0.04424171, 0.014327023, 0.052337606, -0.03751888, -0.021828214, 0.032920558, 0.0016434557, 0.018076913, 0.020110885, 0.0071556843, 0.12211307, -0.06795764, -0.060508616, -0.00095928164, -0.01600633, 0.035104495, 0.032818977, 0.007841411, -0.01212579, -0.055357363, -0.046280667, -0.026511794, 0.04082885, 0.057867616, 0.026822237, 0.093116395, -0.030477297, -0.049638584, -0.011180545, -0.035560045, -0.0017295886, -0.04411793, 0.033941805, -0.020915104, 0.056021933, 0.005206295, 0.051095616, 0.03442485, -0.031147564, 0.017690314, 0.07274637, 0.015465176, -0.010589123, 0.045086756, -0.018701172, 0.06463363, -0.053898122, -0.057553813, 0.05394875, -0.04614037, 0.020373262, 0.0065052263, 0.04584131, 0.015545965, 0.013798196, -0.0015989083, -0.0024030637, -0.003326472, -0.03135937, -0.018650744, 0.008092046, -0.023507306, 0.024836408, -0.027125148, 0.047909714, -0.0075559192, 0.013558942, 0.03680664, -0.048174266, 0.035101786, 0.067569144, 0.015398487, 0.0048391465, 0.047561035, -0.00092837785, 0.027499199, 0.028243981, 0.04101917, 0.057320375, -0.042865984, 0.025110025, 0.03553826, -0.0015206792, -0.094204105, -0.030542972, 0.0005998901, 0.058000054, 0.036898464, -0.0016890913, -0.0466558, -0.02062488, -0.038038027, 0.0022148443, -0.010963909, 0.045183722, -0.0041165315, -0.013269583, -0.012686097, -0.00531953, -0.002091686, 0.031755045, 0.025000386, 0.005376946, 0.029403731, -0.031861655, 0.0026860784, -0.050102223, 0.028828708, 0.078811646, -0.032574058, -0.07590154, -0.009284678, 0.008644392, 0.026894478, 0.008576405, -0.0023644916, 0.017296677, -0.008668417, -0.01740381, 0.005357213, 0.0041840198, 0.054674886, -0.01898544, -0.033549298, 0.023834575, -0.014276268, -0.040907707, -0.026550895, -0.06360628, 0.023751331, 0.005200521, 0.0059997807, -0.07738721, -0.06652308, 0.029402051, 0.00803966, 0.028783055, -0.018875321, -0.0038621658, -0.019933939, -0.03753927, -0.0005933507, -0.051860962, 0.0073116226, 0.007674554, -0.038421467, -0.0539511, 0.026583143, 0.019425046, 0.043493412, -0.023840457, -0.010624284, -0.0074735414, 0.069936454, 0.05116183, 0.043613505, 0.008108981, -0.046740998, 0.01614374, -0.017886955, 0.04811252, 0.0011904486, -0.0054321573, -0.04550658, 0.06065376, -0.04744526, 0.0012289637, -0.035960183, 0.00875375, 0.025691293, 0.01021524, -0.035999686, 0.035942204, -0.0041844486, 0.0016350899, -0.037049837, -0.05069132, -0.019972002, -0.033209935, 0.019334882, -0.018583376, 0.0025883396, -0.007855585, 0.02372925, -0.021167373, -0.068262845, -0.00826577, 0.119081974, -0.011070143, 0.008409465, 0.045726642, -0.045439143, -0.0006317298, 0.04460536, -0.003949442, 0.011348854, 0.01849567, 0.0963765, -0.06138822, -0.034380324, 0.009603616, -0.038963653, 0.019008042, 0.019597469, -0.017008347, 0.012732973, 0.02907417, -0.023497622, 0.0163726, 0.015491197, -0.009935866, 0.020609025, -0.03478764, 0.010108852, -0.005009364, -0.025894035, -0.05143406, 0.022992594, -0.006972698, -0.024293276, -0.018860893, 0.021944314, 0.042878088, -0.00047924864, 0.004384811, 0.023810351, 0.042502318, -0.01889265, 0.058642436, -0.008687884, 0.026469627, 0.08111168, 0.009048247, -0.0003583116, -0.0004614519, 0.0037734509, -0.08904337, 0.015277361, -0.0014097221, -0.027780388, -0.05575231, -0.068914935, -0.03817348, -0.0053172754, 0.012159304, -0.04050191, -0.087293714, 0.0023535253, 0.03669056, -0.005148836, -0.011917223, 0.029728848, -0.044467974, -0.060635835, 0.0124355955, 0.041664127, -0.013522629, 0.01969149, 0.033789176, -0.007474989, -0.045139056, 0.003396289, 0.016144287, -0.04376857, -0.035374872, 0.038331226, -0.009679496, 0.024379557, 0.031186853, 0.047609903, -0.045359626, 0.052533668, -0.011555815, 0.0073120277, -0.012097843, -0.011928929, 0.049048185, -0.02419773, 0.008771181, 0.04802565, -0.0011573073, -0.022378407, -0.01589256, -0.039228234, -0.053164486, 0.0011087564, -0.049629755, 0.022539277, -0.05347267, 0.029980905, -0.020656575, -0.06770105, -0.011768146, 0.013834106, -0.042078782, -0.010027659, 0.020446576, 0.008787459, 0.00966065, 0.054031778, -0.041593555, -0.018892905, -0.046346966, 0.06025458, -0.055327307, 0.018138703, -0.054135602, 0.027587056, 0.035321094, 0.009614909, -0.047052756, 0.028534591, -0.06734926, -0.028400002, -0.017890843, -0.061192557, 0.040680245, -0.064417355, -0.009222024, 0.008874886, 0.040432595, 0.04347778, -0.055646643, -0.036430903, 0.036046814, 0.04451195, 0.0033366375, -0.042370714, 0.05417946, 0.00026827565, -0.0048390576, -0.008355279, -0.06654393, -0.016615214, -0.02115638, -0.04719758, 0.087897204, 0.015179784, 0.033741683, -0.040237974, 0.009074097, 0.0011328693, 0.0024647315, 0.062784344, -0.06771395, 0.01827934, 0.0031617566, -0.029932223, -0.013313607, 0.0031934131, 0.037532236, -0.032851767, 0.023847135, 0.057167538, -0.047988147, -0.017981777, -0.005035241, 0.030767879, 0.0013926143, 0.024621412, -0.01153783, -0.042547233, 0.00014543485, 0.044297013, -0.053680398, -0.0236918, 0.019145261, -0.04059873, -0.00242726, -0.02979335, 0.020395681, -0.06399952, 0.03473067, 0.023195343, -0.013373055, -0.008648926, -9.2516144e-05, 0.018301724, -0.0441172, 0.028509453, 0.022520343, 0.02143001, 0.05195885, -0.030301731, -0.006849185, -0.004904286, -0.10408912, 0.009095697, -0.05168448, -0.025775032, 0.04204338, 0.028149704, -0.0067969337, 0.049403373, -0.029733881, -0.0004207324, 0.00619797, 0.012250764, -0.050836172, -0.04702138, 0.04095791, 0.009318629, -0.01872129, 0.05273932, 0.004059747, -0.009065266, -0.009634543, 0.068296105, -0.0731856, -0.0071178684, -0.027810317, 0.030306298, -0.008212478, 0.062155627, -0.06665621, 0.015028101, -0.0019829713, -0.07780437, 0.03709632, 0.061464403, 0.0021853074, -0.010608797, 0.04957111, -0.04064764, -0.015684854, 0.0132637005, 0.04391835, 0.031190312, 0.0016589635, -0.04209831, 0.049464833, -0.018139949, -0.028635088, -0.031143593, 0.039920237, 0.005739127, -0.031172452, -0.03807487, 0.034200042, -0.02553162, -0.06538754, 0.042260315, 0.0005250641, 0.055705626, 0.010042914, 0.022414662, 0.033914447, 0.026906213, -0.0033065944, -0.013504181, -0.020773347, 0.010674499, -0.06912123, -0.03145625, -0.0091263, 0.074964456, 0.033556156, -0.017435236, -0.032708045, 0.058441352, 0.026435584, 0.03519807, -0.017625816, 0.025762228, 0.041763347, -0.049484115, 0.020312905, 0.06208869, 0.057566527, 0.06161873, -0.009520863, 0.06155811, 0.0067042927, -0.050201833, -0.018288134, -0.06863244, -0.005873679, 0.031543177, 0.017049782, -0.06389385, -0.0095196515, -0.022358006, -0.012385934, -0.02367178, 0.006942951, 0.00018405395, -0.08052641, -0.06902793, 0.0034323414, -0.05629325, 0.026290013, 0.038165785, -0.028952526, 0.056765396, -0.01266415, 0.0045946166, -0.012381542, 0.024992242, 0.0108828945, -0.044975754, 0.047559507, 0.039001957, 0.025040492, -0.012575287, -0.040740535, 0.0001592451, -0.055817157, -0.04830023, 0.032516442, -0.059362203, -0.02611507, -0.0036436229, -0.047105934, 0.019569714, 0.0043158247, -0.01932282, 0.042542472, -0.016561393, 0.018657593, -0.030051105, -0.03383916, 0.0096626645, -0.024875946, -0.01075538, 0.018874506, -0.01863521, 0.019414067, -0.05665577, -0.016376492, -0.0041574175, 0.004025168, 0.0019284817, -0.02454007, 0.05003198, 0.017479822, -0.019079983, -0.033352956, -0.0053157536, 0.07116709, 0.003118455, -0.024735682, -0.041558307, -9.899177e-05, 0.035021015, -0.0013879942, 0.021430645, 0.04747498, 0.007149192, 0.0071941945, 0.0007304615, -0.044729162, -0.006236001, 0.00495239, 0.00032580708, -0.05439175, 0.005071572, -0.027920937, -0.05964012, -0.035140123, 0.03878922, 0.010414016, 0.022694336, -0.032935463, -0.05569769, 0.052693836, -0.036030892, -0.007949854, -0.0063857124, -0.0020045664, -0.0020730717, -0.054984003, -0.008379609, 0.040919784, -0.045835882, 0.07582701, 0.019464025, 0.016366957, -0.0050695413, -0.07617696, -3.932192e-05, -0.008705835, -0.03391197, 0.038797617, 0.06431827, -0.031952295, -0.028126637, -0.011632366, -0.025814077, -0.04845314, -0.055648096, -0.003267104, -0.01894468, 0.06972019, 0.040651027, -0.041427255, 0.009258753, -0.00510335, -0.01949575, 0.02636369, -0.030337645, 0.0037095938, 0.013732034, 0.00020991139, 0.035235245, -0.0042572524, -0.0018467343, 0.011212586], "2f38847c-3c65-41ae-84d8-b2bb890ae9ec": [0.013036115, -0.058033038, -0.02783132, 0.033422396, 0.07273963, 0.020531144, 0.018375425, -0.0041939938, 0.0062098666, 0.013866467, 0.047710225, 0.060587157, 0.01568542, -0.005874919, 0.020181933, -0.08365482, 0.009086485, 0.046213176, -0.008671944, -0.059325043, -0.026423784, -0.05429451, -0.010578124, -0.045297984, -0.042115316, 0.010653886, 0.014935738, -0.0601009, -0.038427662, 0.035856828, -0.026294777, 0.023591531, -0.02073796, 0.032114815, 0.02193782, -0.017979955, 0.019250706, 0.049071524, 0.040222656, 0.04017519, 0.009935786, -0.003753926, -0.023102151, 0.0017397747, -0.02268373, -0.011798374, -0.011118317, 0.028948503, 0.018198945, -0.052892603, 0.014202688, 0.017313598, 0.088224106, -0.0078072296, 0.03333636, -0.023404345, 0.028389655, -0.023359817, 0.013423812, -0.016035777, -0.0030092478, -0.0033434485, -0.030970268, 0.015910147, -0.0057198447, -0.009244596, -0.06886117, -0.021187732, 0.0004465704, -0.0076823365, 0.0201465, 0.015862463, 0.078175426, -0.0032835642, -0.043365195, -0.110197015, -0.04812991, 0.06908279, 0.033291057, 0.020516267, 0.041394636, -0.052637435, -0.051994715, -0.050141744, -0.066173315, 0.0006589413, -0.033732843, -0.02594324, -0.036653098, 0.0101275, 0.00014193915, -0.004571949, 0.034867384, -0.0070939604, -0.012692958, 0.07595257, 0.011329107, -0.06407941, 0.041248165, -0.07363761, 0.041109603, 0.004106107, 0.0030976343, 0.026895154, 0.02553549, 0.07238423, -0.05607671, 0.04643749, -0.027828882, -0.002907315, -0.044567693, -0.040456988, -0.0066802353, -0.074761644, 0.06013306, -0.036998216, 0.024612108, 0.059205137, 0.004388718, 0.0023781946, 0.03006626, 0.008007091, 0.048891287, -0.011594704, -0.018195914, 0.042663887, 0.027607651, 0.015377692, 0.070644796, -0.0028763297, 0.013017441, -0.0016436938, 0.006517191, -0.01455349, 0.027444774, 0.077315815, 0.018769775, -0.0073795863, 0.02467426, 0.04277621, 0.011089832, 0.02737508, 0.0109612215, 0.012141467, -0.037232626, 0.023329586, -0.031095117, -0.007899514, 0.021170914, -0.03346462, -0.035546582, 0.006467694, -0.059459716, -0.04997959, 0.048562143, 0.024623286, 0.00826303, 0.05082744, 0.01177125, 0.043163702, 0.022380386, 0.060315184, 0.015943378, 0.03818579, -0.043195385, 0.0065665166, 0.021041133, -0.0068432796, 0.009018831, 0.003953735, -0.013922989, 0.118756145, -0.061297413, -0.07074964, -0.009026647, -0.022813974, 0.06551927, 0.052975703, 0.0071254363, -0.015999611, -0.07532198, -0.030697115, -0.009825763, 0.037480425, 0.039744146, 0.02858062, 0.0680808, -0.00901817, -0.026685098, 0.0035594264, 0.00833847, -0.010205808, -0.03404955, 0.04149808, 0.009306554, 0.04070476, 0.03851867, 0.024012214, 0.038189337, -0.05824716, 0.021636268, 0.06405186, 0.011742938, -0.014438263, 0.05283231, 0.0020819653, 0.03771149, -0.02660554, -0.067759395, 0.051071685, -0.061389223, 0.01603951, -0.0062797586, -0.00026101974, 0.038890626, 0.0064800805, 0.005000047, 0.025021581, -0.0071128635, -0.0058491216, 0.0059684175, 0.003417221, -0.030113526, 0.01892851, -0.032093108, 0.035048153, -0.019192673, 0.012939738, 0.041269172, -0.048466474, 0.020646213, 0.036379255, -0.0033316049, -0.0054114866, 0.053261515, 0.011536001, 0.0019360803, 0.058134094, 0.045038167, 0.06417919, -0.028968178, 0.011462896, 0.035135105, -0.0044775843, -0.08515881, -0.02490257, 0.013684908, 0.005324937, 0.011822917, 0.028293619, -0.032377124, -0.043084823, -0.03585436, -0.0013088128, 0.0186051, 0.07451939, -0.028057016, -0.034721054, 0.009995549, -0.016801326, -0.0031907058, 0.03416029, 0.02381731, 0.012590365, 0.012920466, -0.037640426, -0.00013691459, -0.0639339, 0.02078922, 0.065958664, -0.016591288, -0.04941186, 0.004931888, -0.0006041799, 0.018627742, -0.014746076, 0.03520799, 0.005218047, 0.005836199, 0.0038206247, 0.0018438048, -0.0005228044, 0.023260383, -0.010225117, -0.025421046, 0.0044176383, -0.0410323, -0.035428174, 0.0037889075, -0.07013654, 0.0108930385, 0.020371836, 0.005282437, -0.07903555, -0.062033687, 0.03356027, -0.014615077, 0.053515866, 0.009740213, -0.00014203196, -0.009880875, -0.027893113, -0.028671578, -0.040720414, 0.013583879, 0.020901382, -0.023470841, -0.04948827, 0.018996533, -0.01071331, 0.02399624, -0.05758187, -0.0007778144, -0.0066456273, 0.03684382, 0.026136681, 0.04327029, 0.028145337, -0.02751893, 0.021311985, -0.020837711, 0.03234988, 0.017515546, 0.009065034, -0.037816655, 0.05971888, -0.047322728, 0.02909726, -0.0013589327, 0.011180227, 0.05128427, -0.008587665, -0.046927754, 0.021638438, -0.004759718, 0.007215644, -0.07712222, -0.040294584, 0.011642096, -0.019243484, 0.0013936727, 0.0049646734, 0.015226943, -0.027859803, 0.026668675, -0.009968191, -0.06433795, -0.003975992, 0.0870749, -0.012512243, 0.038936753, 0.051720753, -0.039003115, -0.0032025592, 0.07824624, 0.027295973, 0.031164022, 0.021854006, 0.12309676, -0.036304172, -0.069774054, 0.016050374, -0.028081262, 0.012549867, 0.041549, -0.0123541625, -0.0013270812, 0.01493886, -0.014518722, 0.049214628, 0.0002970163, 0.011963391, -0.005331483, -0.027830392, -0.00016770685, -0.021524083, -0.047233004, -0.046100657, 0.04827692, -0.011311054, -0.028223544, -0.008160578, 0.039167717, 0.040523104, 0.0091547705, -0.02428034, 0.0016646783, 0.03808417, 0.010708188, 0.05140349, -0.033572476, 0.0077906004, 0.047882944, -0.016881777, 0.013592352, 5.8881244e-05, -0.02324982, -0.078337796, 0.02419667, 0.0050451825, -0.040325776, -0.047655184, -0.05336315, -0.037908334, -0.020303166, -0.029092127, -0.022630224, -0.08583124, -0.0012726991, 0.031897333, 0.025194732, -0.020118997, 0.036660057, -0.039913934, -0.030868104, 0.03469838, 0.041952256, -0.01782913, 0.026239384, 0.015467451, -0.04124489, -0.028224735, -0.018078282, 0.01100083, -0.071260974, -0.062158477, 0.022520138, -0.017734263, 0.049941443, 0.013952341, 0.05518502, -0.034148566, 0.06503819, 0.0067546447, -0.010665351, -0.029704338, -0.02048218, 0.02401776, -0.038182177, 0.018977659, 0.041018408, 0.025690384, -0.017023876, -0.020054761, -0.030172387, -0.028049745, -0.007318989, -0.035886407, 0.03127803, -0.07806658, 0.04427789, -0.013923524, -0.049344465, -0.023509117, -0.0058871056, -0.07190561, 0.0070998436, 0.035460822, 0.005025909, 0.034779985, 0.042820193, -0.048686612, -0.02516385, -0.027470589, 0.042903077, -0.036233082, 0.026128901, -0.057322808, 0.014705154, 0.036363497, 0.022004448, -0.046101302, 0.035853982, -0.028908633, -0.009426105, -0.025863355, -0.050769523, 0.052687004, -0.041955236, 0.006042791, 0.014104701, 0.019297887, 0.02821441, -0.029495815, -0.024068981, 0.040027115, 0.054722562, -0.0034070062, -0.0040432857, 0.04457094, -0.026962332, 0.0035072854, -0.020922726, -0.052413225, -0.004212489, -0.010700166, -0.06936899, 0.0739665, 0.04895469, 0.04810624, -0.025536455, -0.02430812, -0.016611138, 0.00082846836, 0.1038979, -0.05915894, 0.017850628, -0.016411675, -0.016875325, 0.001906962, 0.005405446, 0.045941867, -0.0025457186, 0.0072507095, 0.06935299, -0.044918127, -0.02214672, -0.016749457, 0.027665699, 0.023988744, 0.05150853, -0.041866753, -0.10216063, 0.0022857338, 0.05638799, -0.06400766, -0.008413259, -0.0018483774, -0.06098499, -0.0065269787, -0.019540755, 0.030228944, -0.069396995, 0.069117315, 0.039167788, -0.004059824, -0.010474051, 0.02948016, 0.011156833, -0.009870921, 0.035313196, -0.0033673258, 0.063563906, 0.05610867, -0.025731444, -0.0050437255, 0.022224516, -0.103628114, 0.008671855, -0.03539444, -0.041424006, 0.036398035, 0.010427841, -0.0029570092, 0.042422373, -0.004273618, 0.0073089786, 0.013347013, 0.011607773, -0.031467475, -0.03410239, 0.04187664, 0.04454423, 0.0010005891, 0.044883408, 0.013734911, -0.03045046, 0.0067934967, 0.039806515, -0.080752514, 0.0063978503, 0.0012803983, 0.055026934, -0.041561235, 0.05159395, -0.046193603, 0.0054288763, -0.0032127963, -0.07902122, 0.027555969, 0.05448866, -0.0014818638, -0.016054228, 0.049674943, -0.033732686, -0.031413708, 0.039455988, 0.061851658, -0.009283897, -0.0083806915, -0.04944399, 0.045566827, -0.045345817, -0.006926729, -0.018378742, 0.032693423, -0.0027867225, -0.02789395, -0.04609213, 0.016748013, -0.00047905464, -0.03666106, 0.05279065, -0.0036968123, 0.036457684, 0.0073912535, 0.02120769, -0.0047017816, 0.03360339, 0.0012872779, -0.014538748, -0.031926785, 0.016336495, -0.04716, -0.034242596, -0.039905265, 0.09229415, 0.032062326, -0.039338283, -0.025690705, 0.05442176, 0.028503189, 0.029268526, -0.0054382146, 0.0033069013, 0.0076569193, -0.03241526, 0.015129461, 0.07580407, 0.04034292, 0.08574507, -0.010556049, 0.021401731, -0.030421212, -0.059404008, -0.02565243, -0.037203163, 0.0020695638, 0.03510534, -0.00785313, -0.033486597, -0.008452574, 0.004434188, -0.017499896, -0.029339554, 0.0555491, -0.023359498, -0.10693766, -0.06674799, 0.0029787705, -0.04844117, 0.017265983, 0.035610583, -0.013921927, 0.024474166, -0.007953868, -0.029991407, -0.0058927275, 0.015558147, 0.011386467, -0.03393015, 0.043063283, 0.03601344, 0.003824925, 0.002837477, -0.027420413, -0.012745, -0.060752533, -0.05096734, 0.046494417, -0.059069615, -0.011578821, 0.010892322, -0.024151979, 0.021965414, 0.02941484, -0.030085724, 0.029248362, -0.00082158396, 0.032973804, -0.03468649, -0.0071831867, 0.02009228, -0.032500762, -0.0049053105, 0.022175135, -0.018389223, -0.03342259, -0.042047583, -0.031936977, 0.009408646, 0.012253523, 0.00072364573, 0.008488448, 0.030914327, -0.011120012, -0.03694114, -0.0530595, -0.003480512, 0.041136365, 0.0082106115, -0.009771473, -0.022700371, 0.021836793, 0.008549505, 0.018533178, 0.007418626, 0.035656266, 0.032790568, 0.0088271415, 0.007195505, -0.0343646, 0.022525392, 0.041573264, 0.021468809, -0.03578025, 0.02076654, -0.0116159795, -0.006121544, 0.02519489, 0.019813055, 0.0020743555, 0.03759515, -0.026014073, -0.034695383, 0.06006958, -7.817839e-05, -0.018678049, -0.0071847443, -0.0013630593, 0.0041605323, -0.06796776, -0.013159443, 0.04627048, -0.035160452, 0.05156763, 0.009897271, 0.02986663, -0.0057137054, -0.061058525, -0.0048096105, -0.03018098, -0.029322201, 0.08751756, 0.04554473, -0.016828945, -0.01708906, -0.0032144412, -0.028786734, -0.004300752, -0.06773083, -0.0156052355, -0.013334137, 0.10209731, 0.046905566, -0.048906043, -0.015688106, -0.0043862932, -0.0092671765, 0.0032090598, -0.022709267, 0.0018167779, 0.002389672, 0.015790652, 0.02516033, 0.01059413, -0.03015946, 0.016073335], "42325499-9ed6-4beb-87e5-ab16ddcfd70f": [-0.014747472, -0.05013751, -0.004094118, -0.0038866333, 0.03245054, 0.041070707, 0.05475119, 0.03834402, 0.033147786, 0.0358132, 0.024258975, 0.021229599, -0.0042981943, 0.00123746, 0.008450937, -0.102168754, 0.01341434, 0.063241884, -0.0086480435, -0.03559958, 0.03201275, -0.016460504, 0.015105421, -0.026905172, -0.015804492, -0.023690734, 0.0016561544, -0.078248814, -0.012175836, 0.023676205, 0.006117081, 0.035657536, -0.006093291, 0.006531143, -0.00346487, -0.034301214, -0.018263461, 0.025726935, 0.0358827, 0.023407947, -0.010689078, -0.02444437, -0.0293037, -0.018006437, -0.0029908842, -0.032368388, -0.010986906, 0.018622035, 0.04269414, -0.06058974, -0.0119662015, 0.043924358, 0.06360342, 0.0062233927, 0.015691733, -0.0027572287, 0.026075508, 0.014259185, 0.046781875, 0.0070153996, -0.016238248, 0.007229881, -0.009991837, -0.016394239, -0.0017173666, -0.06844547, -0.031781636, 0.015864274, 0.05184678, 0.0023439857, 0.024405852, 0.019537704, 0.09753309, -0.021387845, -0.051380213, -0.08161267, -0.060098924, 0.07508979, 0.07043724, -0.026234906, 0.009238393, -0.056727786, -0.06347245, -0.050125334, -0.10236801, -0.0029719635, 0.013123995, -0.02575834, -0.03322816, 0.004946937, -0.03268742, -0.0043225694, 0.02926357, -0.04061676, -0.01702878, 0.0709611, 0.0037890628, -0.03707705, 0.023225319, -0.05334312, 0.027255226, -0.084153034, -0.024902323, 0.034683235, 0.015217495, 0.035581805, -0.02373492, 0.05214569, -0.010349133, 0.0385773, -0.022006446, -0.009732892, -0.0067250095, -0.0697148, 0.016248452, -0.06884027, 0.014844093, 0.03430109, 0.051841263, 0.03639946, -0.004170605, 0.025851578, 0.077499285, -0.027595986, 0.028779868, 0.04907724, 0.05526892, -0.014722702, 0.063220136, -0.018609427, 0.00063388346, -0.016119506, -0.02211555, 0.005323216, 0.0026792155, 0.06412286, 0.01307563, -0.009186715, 0.00647, -0.015315966, -0.011023369, -0.0026990396, -0.006920982, 0.021857511, -0.032352407, 0.04397536, -0.06478466, 0.019412214, 0.020395162, -0.034692045, -0.035874423, 0.017612465, -0.043582134, -0.048189133, 0.0068893554, 0.05157146, -0.00070315244, 0.05956158, 0.03452688, -8.51305e-05, 0.060961735, 0.0057502827, 0.032923233, 0.048552394, -0.08350183, -0.020163095, -0.013148858, -0.008060441, 0.027997607, 0.0205112, 0.03513857, 0.10145078, -0.030143267, -0.07935663, -0.00039355693, -0.022752404, 0.046485256, 0.04377388, -0.044073608, 0.0077610537, -0.07425804, -0.038925335, -0.015932666, -0.013211039, 0.043517035, 0.013848322, 0.0560969, -0.02435177, -0.019970689, 0.06294875, 0.043007877, 0.005577105, -0.07187606, 0.016769974, 0.0033616726, 0.04465602, 0.056497365, 0.035158783, -0.0010312736, -0.02608925, 0.049815927, 0.048383087, 0.0066043567, -0.024189852, 0.011056575, -0.009619274, 0.0031241095, 0.007788977, -0.048761614, 0.06512485, -0.05683413, 0.024265597, -0.009590745, 0.00897353, 0.010514436, 0.0032672423, 0.011645045, -0.009506947, 0.012500607, -0.012879112, 0.031191824, 0.014368066, -0.071642816, 0.017901476, 0.021398691, 0.059804775, -0.02571471, 0.054228097, 0.043394744, -0.06553448, 0.014233693, 0.062402975, 0.008821932, 0.018489582, 0.09457303, -0.002513252, 0.047620818, 0.038769078, 0.036598623, 0.054016408, -0.024447454, 0.0010343407, 0.026038708, 0.025250815, -0.091969706, -0.032630473, -0.06416899, 0.031873424, 0.03348731, 0.023590073, -0.027382202, -0.031424165, -0.02170473, -0.023608927, -0.0105200345, 0.053364582, -0.045866977, -0.043440517, -0.03683525, -0.020613346, -0.008260213, 0.021369074, 0.008059362, 0.012932887, 0.040126335, -0.058204126, -0.013970266, -0.04585332, -0.03806962, 0.053165987, -0.036885157, -0.08151609, 0.02323595, 0.01641161, 0.05695995, 0.037287544, 0.031905293, 0.03791169, -0.016465347, -0.008246443, -0.017145969, 0.022221679, 0.04171038, -0.020763645, -0.07189421, 0.011718192, -0.044454094, -0.011336607, -0.009725546, -0.09120119, -0.017799024, 0.010637418, 0.0293983, -0.05009205, -0.06553385, 0.00022188846, -0.003947822, 0.017310446, 0.015581597, -0.023963008, -0.0029299185, -0.048251096, -0.018938538, -0.021773066, -0.013858256, 0.008738756, -0.009247739, -0.054803837, 0.035408016, 0.016859628, 0.04094321, -0.051257513, -0.012091775, -0.024267653, 0.035548374, 0.0619076, 0.0147690745, -0.004894152, 0.008400973, 0.044222984, 0.0031632385, 0.013858874, 0.008347402, 0.0047801128, -0.026012242, 0.044242997, -0.040220432, 0.0446204, -0.027191041, 0.045785166, 0.051728304, -0.028625386, -0.042174097, 0.024580047, -0.04175848, 0.02341298, -0.060694855, -0.017165335, -0.0142755825, -0.031270005, -0.0041009774, -0.004812892, -0.0026710671, -0.01819614, 0.06189358, -0.04387383, -0.070942916, 0.043590058, 0.095833674, -0.009053625, 0.03852613, 0.010140993, -0.03466038, -0.00046917566, 0.026809823, 0.030981323, 0.0029819694, -0.015529967, 0.0789427, -0.045558453, -0.02719524, 0.049120553, -0.03376611, -0.013883538, -0.03262772, -0.023920475, -0.009356271, 0.013000517, -0.018968755, 0.056448285, 0.010488352, -0.007290459, 0.026370892, -0.028196298, 0.003250751, 0.007177512, -0.055740073, -0.03237904, 0.036389813, 0.032156587, -0.057861406, -0.032675106, 0.03659408, 0.06258458, -0.010314802, -0.0051279245, -0.019604804, 0.049405564, -0.010817323, 0.06750299, 0.0026620645, 0.0025167507, 0.07140068, -0.02479968, 0.023645697, -0.049089443, 0.015071317, -0.058170516, -0.006636173, -0.0035731476, -0.005859036, -0.04645594, -0.03216084, -0.007255519, -0.005968756, -0.017743817, 0.016505176, -0.044583533, 0.011007939, 0.0036978964, 0.060602278, 0.02481224, 0.048641477, -0.029566817, -0.052302055, 0.018855212, 0.033269554, -0.03291984, -0.0040872693, 0.015476349, -0.035798322, -0.009836222, -0.019853722, 0.0044452483, -0.04884772, -0.039542496, 0.014275767, 0.014827873, 0.01805611, 0.028234709, 0.03166242, -0.0049395617, 0.06720199, 0.004247568, 0.0038022408, -0.025709424, -0.031451605, 0.0063112928, -0.052161824, 0.0011378634, 0.021409674, 0.0299747, 0.016916655, -0.02273221, -0.02972769, -0.034148626, -0.0070872772, -0.029373055, 0.022346687, -0.094520055, 0.032664184, -0.03127946, -0.030729918, -0.047029316, -0.013478722, -0.019749857, -0.0068621477, 0.04858484, -0.006094853, 0.011629182, 0.0125631755, -0.07597015, -0.026124783, -0.025034714, 0.05598816, -0.039893992, -0.007032019, -0.01844717, -0.00046098596, 0.03940986, 0.042738624, -0.043461494, 0.05182635, -0.023271058, -0.033798855, 0.01341002, -0.02894628, 0.021626385, -0.08387083, -0.029552974, -0.007630714, 0.012272452, 0.028278755, 0.009100356, -0.020005379, 0.004941391, 0.057571735, 0.023696078, -0.017647935, 0.039053075, 0.010854701, 0.036489233, -0.005857571, -0.08372741, -0.041100867, -0.04822129, -0.081209995, 0.07179961, 0.04252622, 0.08232185, -0.0073642754, 0.03157053, -0.036807682, 0.01663503, 0.08970574, -0.035162617, 0.022746703, -0.03160488, -0.016794894, -0.01515236, 0.0063306326, 0.015987316, -0.005527505, 0.008102759, 0.07271834, -0.01889747, 0.010825763, -0.0052891574, 0.022468338, 0.008075286, 0.00035273648, -0.0011799979, -0.090833366, -0.004395592, 0.05464407, -0.037059125, -0.0030013113, 0.017282601, -0.018946018, 0.0035653047, -0.032257922, 0.017247139, -0.017422298, 0.06021677, -0.0009117271, -0.0059296554, 0.02232808, 0.0045638205, 0.003203061, -0.029181173, 0.040236104, -0.0017870419, 0.046856035, 0.05076563, -0.0014789467, 0.030472817, 0.008697039, -0.081919625, 0.009085326, -0.01987083, -0.041758694, 0.028259644, 0.009664536, -0.012048825, -0.010657625, -0.00079772127, -0.027447088, 0.019692801, 0.01817414, -0.043654807, -0.035340622, -0.017328195, 0.04741601, 0.029713629, 0.04843623, -0.00032465727, -0.057653416, -0.017713718, 0.030120613, -0.07126261, -0.0017603012, -0.0016434703, 0.03672929, -0.021901298, 0.034797613, -0.025200203, -0.014379884, -0.0050014397, -0.05815463, 0.036193136, 0.046852734, 0.022303157, -0.043009598, 0.029040968, -0.015913283, -0.050220646, 0.07561093, 0.08098074, 0.01498441, -0.017826417, -0.07436965, 0.03445587, -0.07414422, 0.029085536, -0.012763093, 0.016814664, 0.024883967, -0.020991797, -0.0036824967, 0.03196727, 0.010117699, -0.06300837, 0.038855966, -0.027563922, 0.046295095, 0.017474119, -0.021724617, -0.017924832, 0.026689027, 0.03152847, 0.023080064, -0.05281197, 0.00821496, -0.018187186, -0.0710123, -0.038722962, 0.050236642, 0.005858843, -0.0068318476, -0.021105062, 0.040603373, 0.012402743, -0.004248529, 0.005826493, 0.024521412, -0.011117747, -0.022263223, -0.02657325, 0.07811003, 0.077695064, 0.07013037, 0.028110968, 0.02796614, 0.020998128, -0.037113864, 4.5344263e-05, -0.0290442, 0.038358644, 0.0026537315, 0.053525433, -0.048603293, -0.0010272083, 0.05056913, -0.021428535, -0.021549024, 0.01919376, -0.012325357, -0.082309455, -0.065618865, -0.013389828, -0.046562556, -0.013005988, 0.049748927, -0.02032138, 0.0111812325, 0.012130765, -1.3960713e-05, -0.006855897, 0.05489305, 0.030405605, -0.0041497927, 0.032504693, 0.010635176, -0.009246049, 0.009778962, -0.027348125, -0.038897187, -0.047276348, -0.014141594, 0.0438386, -0.032029007, 0.040112447, 0.03616915, -0.021812672, 0.04347011, 0.008382644, -0.009826449, 0.03406965, 0.011387066, 0.033581726, -0.058475073, 0.030327778, -0.0068434477, 0.003914744, 0.01404163, 0.030653069, -0.0430945, 0.0042182147, -0.036149368, -0.009637548, 0.00041698784, -0.03384045, 0.007063572, 0.005645048, 0.030528666, 0.010734183, -0.022935642, -0.03390784, -0.024526753, 0.0029126736, -0.0067800772, -0.035045914, 0.0023085033, 0.0055270386, -0.0025162662, 0.007940729, 0.0052944967, 0.009716042, 0.056926224, -0.005177863, 0.03453332, -0.02675443, 0.003876261, 0.03837947, -0.0017027722, -0.020130506, -0.013612921, -0.02849517, -0.032837737, 0.01870976, 0.036339905, -0.04880587, 0.028355435, 0.0028093457, -0.04903535, 0.025419375, -0.03598133, -0.009345632, -0.011483282, -0.013697786, 0.01709256, -0.056393605, -0.014088094, 0.02402597, -0.03070134, 0.040448885, 0.0064518475, 0.04207592, -0.0029283192, -0.088590205, -0.016249603, -0.013640379, -0.008545781, 0.07821269, 0.04383632, -0.024072064, -0.026588706, -0.018568428, -0.0010086483, -0.04557587, -0.04319705, -0.017165741, -0.02114582, 0.06776031, 0.03998816, -0.036472015, 0.014611268, -0.008958442, -0.012225827, -0.013468775, -0.029126989, -0.032915074, -0.016342906, -0.00041771613, 0.059546776, 0.023263164, -0.02500754, 0.016457895], "bd38690f-c8a3-40b2-a999-f233f0c228e1": [0.013793554, -0.07375386, -0.035505667, 0.004244932, 0.047122024, 0.062725104, 0.060097158, 0.021795366, 0.019379174, 0.042592186, 0.037352998, 0.032804318, -0.0062467875, -0.005218659, -0.0040187216, -0.10057054, 0.021684794, 0.040164877, 0.03311238, -0.03165615, 0.019421205, -0.014502365, 0.024140764, -0.018231213, -0.026220271, -0.036895882, -0.03277316, -0.10901497, -0.030214174, 0.009993847, -0.034030482, 0.010640638, -0.023885494, 0.03221344, 0.022210265, -0.014730081, -0.019136801, 0.05106255, -0.0033157782, 0.059072636, 0.0318136, -0.030084206, -0.037313, -0.03198674, -0.02846044, -0.03259379, -0.0012857293, 0.03161733, 0.005264544, -0.055935107, -0.013420406, 0.013565205, 0.06957675, -0.016026463, 0.034454532, -0.026265755, 0.009410379, -0.0114452, 0.036353048, 0.033223815, 0.011408132, 0.00031167577, -0.013184938, 0.0111419335, -0.012025548, -0.095096886, -0.044867337, -0.024448609, 0.03719958, -0.008582709, 0.00039790422, 0.019131457, 0.086255826, -0.016320582, -0.040168133, -0.105137296, -0.021132058, 0.06684411, 0.037534114, 0.0013103002, 0.014258284, -0.005465589, -0.06867567, -0.07263022, -0.08221893, 0.022599675, -0.008862588, -0.02472575, -0.047103643, 0.018587556, -0.045025878, -0.03246675, 0.022478815, -0.05148754, 0.010876078, 0.058095332, -0.006649846, -0.02681528, 0.015362297, -0.035449434, 0.022969427, -0.05887238, 0.00020647756, 0.007837459, 0.01009829, 0.0319446, -0.033610396, 0.0758958, -0.035655893, 0.030018903, -0.03278217, -0.006640631, -0.007274927, -0.04324537, 0.059221715, -0.07698891, 0.017673902, 0.02703145, 0.051494073, 0.067025155, 0.01213091, 0.011506013, 0.057003833, -0.007329397, 0.021944053, 0.04215411, 0.0057575814, -0.0035239647, 0.081036985, -0.002244101, 0.03452429, -0.028572323, -0.026518935, 0.005552206, -0.001185403, 0.058324195, 0.048299916, -0.029452372, -0.0022489184, 0.019089857, -0.033699643, 0.014669534, 0.0049281945, 0.02213217, -0.02818953, 0.05734054, -0.057588115, -0.00027457494, 0.010198641, -0.029282732, -0.033018354, 0.01733534, -0.044380907, -0.041368525, 0.02658976, 0.025098167, 0.012223905, 0.0641106, 0.04611869, -0.038841825, 0.09343881, 0.021101043, 0.0113983, 0.039241828, -0.07113231, -0.01159753, -0.022152383, -0.01178691, -0.009596572, 0.026019981, 0.020901423, 0.11214047, -0.04038304, -0.0725594, -0.013047047, -0.005369514, 0.01156824, 0.07585208, -0.018909732, 0.0203269, -0.058870494, -0.06391664, -0.0030792977, 0.04827428, 0.03438779, -0.0019549076, 0.06774433, -0.038673196, -0.041284043, 0.026068266, -0.0036059401, -0.019322606, -0.078525946, -0.008964764, 0.017919887, 0.051567405, 0.05285377, 0.032968637, 0.009749983, -0.04598796, 0.026578661, 0.045729317, 0.037990298, -0.001058188, 0.055144355, -0.014975157, 0.019387618, 0.023158807, -0.05683323, 0.06088309, -0.095068224, 0.0051500066, 0.0050983676, 0.011205336, 0.012358315, 0.011860069, 0.019011883, 0.021053229, 0.019864196, -0.05020248, -0.020866444, 0.05487191, -0.063342206, 0.014413149, -0.025957307, 0.04810247, -0.024030883, 0.026824616, 0.035944622, -0.03688294, 0.026343852, 0.086525254, -0.0070044524, -0.012385604, 0.093017824, -0.0027926143, 0.034569148, 0.035845343, 0.028037863, 0.045114085, -0.023155423, 0.0075690732, 0.03900068, 0.036942884, -0.10541652, -0.037192587, -0.037202902, 0.029357854, -0.0015894293, 0.036816135, -0.053890128, -0.06584751, -0.009743667, -0.022165224, -0.045763746, 0.013040111, -0.040354937, -0.014011444, -0.054069422, 0.0041597136, 0.02304213, 0.03211034, 0.014611123, -0.013984906, 0.009624603, -0.04541371, 0.015499575, -0.04276964, -0.024837991, 0.06304568, -0.022727069, -0.10321395, 0.042853057, -0.00022660804, 0.0020256601, 0.027006775, 0.0030366627, 0.03147375, -0.010115186, -0.002490639, 0.013218924, 0.03437043, 0.01880894, -0.033352878, -0.054887693, 0.03165777, -0.005553938, -0.024107188, -0.007752178, -0.069797665, 0.003422685, 0.03019217, 0.009203797, -0.07958341, -0.05964404, -0.008662176, 0.012021947, 0.0009472595, 0.00040660723, -0.051474366, 0.011904334, -0.06887265, -0.007114506, -0.03805258, -0.020752529, 0.02942702, 0.0011132903, -0.05526811, 0.044967115, 0.008992932, -0.002674218, -0.06966015, 0.0018567079, -0.0075283456, 0.022794748, 0.067450985, 0.016249971, 0.037527774, -0.013517017, 0.019799847, -0.004099793, -0.008046276, -0.013449933, -0.0011345423, 0.016098069, 0.036589984, -0.040619843, 0.08209346, -0.0565074, 0.024994874, 0.042498514, -0.0075533106, -0.04435644, 0.041123416, -0.038116816, 0.008602847, -0.039776694, -0.017418906, -0.028265055, -0.018954597, -0.014039685, -0.023926139, 0.007539277, 0.00855833, 0.05450239, -0.039710537, -0.04964138, -0.0019343194, 0.090945855, -0.0070231175, 0.022170866, 0.039679497, -0.032270946, 0.02449539, 0.034057446, -0.03038037, 0.018776821, 0.01320603, 0.08126142, -0.011362019, -0.009013334, -0.0018056277, -0.03634081, -0.015006009, 0.031932686, -0.023253916, -0.00455746, 0.031201476, -0.03573236, 0.039352372, -0.0017360335, -0.018140865, 0.0067784423, 0.009448252, -0.00092711917, -0.020543415, -0.05526261, -0.023385536, 0.01975219, -0.013772564, -0.026483973, -0.034859467, 0.017023606, 0.046328407, -0.0026981984, -0.024175458, 0.017501434, 0.033205014, -0.02784706, 0.07514095, 0.038573727, 0.009543039, 0.10414554, -0.033682223, 0.02956101, -0.012254013, -0.012441949, -0.06586849, 0.03606817, 0.010010151, 0.009841535, -0.02109855, -0.04067979, -0.0061402833, -0.036448643, -0.035088334, -0.018140055, -0.059481733, 0.034585446, 0.0070854356, 0.0091467025, 0.037671532, 0.07781037, -0.010347098, -0.024415102, -0.0021809689, 0.06699166, -0.019257693, 0.012152272, -0.0012748602, -0.009182788, -0.042518817, 0.029960385, -0.0022659234, -0.055174205, -0.062222853, 0.011629338, 0.003379123, -0.013825043, 0.0073453053, 0.038368613, -0.014880253, 0.032904852, -0.010590736, -0.003149814, -0.015781876, 0.008301283, 0.03506781, -0.019396769, -0.0089793755, 0.020962844, 0.00040558653, 0.027897634, -0.01938812, -0.03855047, -0.016051428, 0.00494692, -0.011976742, 0.06876156, -0.07070612, 0.048125062, -0.017205168, -0.07203888, -0.037883796, -0.002592581, -0.048828945, -0.0038611873, 0.0196792, -0.021962427, -0.014829258, 0.041289885, -0.039952468, -0.0020336953, -0.039108314, 0.03697189, -0.04642167, -0.0037176337, -0.02908851, 0.021990899, 0.044841405, -0.019850558, -0.067593224, 0.034745835, -0.059232436, -0.007024258, 0.0072077163, -0.049598083, 0.064465284, 0.009778577, -0.03191103, -0.0056209303, 0.008160486, 0.019837301, 0.021265235, -0.005244997, 0.024333911, 0.03297731, 0.02239574, -0.05109631, 0.031564407, 0.011927159, 0.020984896, -0.015730591, -0.041123316, -0.0050406475, -0.015621752, -0.045722485, 0.056806125, 0.016244123, 0.044918597, -0.020883622, 0.008226584, -0.03899276, -0.0124532785, 0.101204805, -0.042308453, 0.040426195, 0.007799068, -0.021993391, -0.0043017482, -0.004850313, 0.012176454, 0.0060459883, 0.018657165, 0.06407867, -0.0126741715, 0.0009884246, 0.031493265, 0.045181785, 0.011834439, 0.00977698, -0.03342185, -0.0648776, -0.013002659, 0.027073191, -0.05835708, 0.006760466, -0.013939323, -0.011140784, 0.013095647, -0.014481404, -0.009066239, -0.06424877, 0.023856677, 0.00045917006, -0.01655879, 0.058235392, 0.014448966, 0.038060103, -0.024707176, 0.04354644, 0.021601211, 0.006463286, 0.031140639, -0.015864003, 0.03457535, -0.014864188, -0.08212884, 0.01676483, 0.0050551803, -0.048057847, 0.0095715495, 0.012708018, -0.023477564, 0.00684658, -0.025138468, -0.0017528612, 0.023494547, 0.0213103, -0.03157416, -0.050493438, -0.015902054, 0.025882373, 0.020788955, 0.068449214, 0.0016148739, -0.03189795, -0.010857393, 0.033287305, -0.031224657, 0.02072214, -0.0046972865, 0.020907875, 0.0066857995, 0.07882764, -0.06604817, -0.014558596, 0.007290363, -0.02743545, 0.039420616, 0.02206063, 0.0244222, -0.05110247, 0.052966803, -0.031022774, -0.05471264, 0.03448188, 0.035912108, 0.028127382, -0.017863594, -0.05642955, 0.05473287, -0.053938113, 0.0032409942, 0.01208869, -0.0060135256, 0.023408461, -0.015549131, -0.049079485, 0.05446444, 0.0057265717, -0.06206449, -0.0015372366, -0.023426594, 0.04180429, 0.045678906, -0.012812797, 0.023154862, 0.020368224, 0.005521493, 0.026431113, -0.022235619, 0.04104261, -0.045581706, -0.026189229, -0.062105726, 0.031007523, 0.0065445863, -0.025877994, -0.013239896, 0.024911176, 0.045319784, -0.008698567, 0.010828029, 0.035108354, 0.02815052, -0.049820025, 0.01326498, 0.08673566, 0.05061801, 0.05127393, 0.035030466, -0.00017339265, 0.0037552183, -0.033982657, 0.015268256, -0.023150181, 0.028008625, 0.030085532, 0.01806888, -0.01707579, 0.010533502, 0.019202495, -0.040121492, -0.0037841601, 0.04085743, -0.010904734, -0.1051856, -0.060832437, 0.02496197, -0.05030478, -0.033352695, 0.013065419, -0.021003092, 0.015616297, 0.017160324, -0.0028006188, -0.013280626, 0.061420664, -0.018747477, -0.04323239, 0.032808762, -0.0074533164, -0.020455346, -0.01970634, -0.056263145, -0.024336383, -0.064935446, -0.032572113, 0.021015536, -0.032548297, 0.029634826, 0.06364361, -0.0305912, 0.02210334, 0.030633084, 0.008783519, 0.07231105, 0.014680874, -0.013061822, -0.02915865, 0.012711165, -0.0429175, 0.010541883, 0.016961955, 0.024240652, -0.0388623, -0.0056185136, -0.057919778, 0.020242892, 0.009976574, -3.6494373e-05, 0.003001602, 0.035584677, 0.0479311, -0.012618149, -0.036738764, -0.031795293, 0.015381263, 0.01167147, -0.035121903, -0.01055779, 0.0025542392, -0.0061479365, 0.007653242, -0.0038415568, -0.011726871, 0.035434406, 0.01248521, 0.008704073, 0.02176793, -0.020166429, 0.0017059863, 0.036179423, -0.021499822, -0.030130083, -0.014369688, 0.004662341, -0.025512302, 0.0067121014, 0.04629309, -0.0016372483, 0.01734022, -0.030509844, -0.020305984, 0.0033804628, -0.015705109, -0.0066142753, 0.018091733, 0.013872455, 0.03053481, -0.054952417, -0.025853902, 0.038984384, -0.021772893, 0.034891926, 0.021334175, 0.036908515, 0.011555696, -0.0721232, -0.012125837, -0.0036883042, 0.0075207404, 0.016341599, 0.028368786, -0.026342345, 0.0027030408, -0.028842436, 0.0031192948, -0.06749628, -0.06559193, 0.006675526, -0.013955883, 0.07217767, 0.061881803, -0.055648897, -0.0033456767, -0.009612144, -0.018939985, -0.0008462419, -0.03256847, 0.0032752438, -0.01390001, 0.006269306, 0.044018608, 0.046959057, -0.030783487, 0.017453134]}, "text_id_to_ref_doc_id": {"488d9176-adb9-4aa4-be31-c79adbf45c9a": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "3df58e2a-eb97-4ce7-a7b8-8504521e12ef": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "cf355bc0-79e1-4c78-8f7e-e63738ba59f4": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "2f38847c-3c65-41ae-84d8-b2bb890ae9ec": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "42325499-9ed6-4beb-87e5-ab16ddcfd70f": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "bd38690f-c8a3-40b2-a999-f233f0c228e1": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "metadata_dict": {"488d9176-adb9-4aa4-be31-c79adbf45c9a": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "3df58e2a-eb97-4ce7-a7b8-8504521e12ef": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "cf355bc0-79e1-4c78-8f7e-e63738ba59f4": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "2f38847c-3c65-41ae-84d8-b2bb890ae9ec": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "42325499-9ed6-4beb-87e5-ab16ddcfd70f": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "bd38690f-c8a3-40b2-a999-f233f0c228e1": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15", "_node_type": "TextNode", "document_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/storage/docstore.json
================================================
{"docstore/metadata": {"f82f40b2-29b4-4536-b1a3-9f272306d5cd": {"doc_hash": "233d2f3b87af08e48b322323d0b7ce130fce41f511ab2b93f31d7733e0583293"}, "488d9176-adb9-4aa4-be31-c79adbf45c9a": {"doc_hash": "a5227e9280f8e2078c1cceaf200c082abd32260a6523109cc76bce7fc6080dc7", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "3df58e2a-eb97-4ce7-a7b8-8504521e12ef": {"doc_hash": "d12e001404d5dcf101b2b06cde42dfb3e030d2fe10873160bf87649abe0beb35", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "cf355bc0-79e1-4c78-8f7e-e63738ba59f4": {"doc_hash": "e768326d3ad52040c74db90bfa292ec09ac418a3337534e16021fac1892db575", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "2f38847c-3c65-41ae-84d8-b2bb890ae9ec": {"doc_hash": "12c67cbd452c9ff6c9f6523f769e458d0bb4686972a6bdac215aacc695bd8a52", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "42325499-9ed6-4beb-87e5-ab16ddcfd70f": {"doc_hash": "d7f042335366cca2a16135b60ffcd39f6bbbcf8e349addb67afbf2116c49aea7", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}, "bd38690f-c8a3-40b2-a999-f233f0c228e1": {"doc_hash": "7def49f1ecad1ffd85d5088aa9522447851647e8ff03a7af5ef5fb8bf19c8f26", "ref_doc_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd"}}, "docstore/data": {"488d9176-adb9-4aa4-be31-c79adbf45c9a": {"__data__": {"id_": "488d9176-adb9-4aa4-be31-c79adbf45c9a", "embedding": null, "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "node_type": "4", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "233d2f3b87af08e48b322323d0b7ce130fce41f511ab2b93f31d7733e0583293", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "3df58e2a-eb97-4ce7-a7b8-8504521e12ef", "node_type": "1", "metadata": {}, "hash": "b5bb6713ef0cad990c8e4fb8ef958b6362f13d1f8efc7c5ef6ca2d0745aaa8db", "class_name": "RelatedNodeInfo"}}, "text": "What is machine learning?\nMachine learning is a branch of artificial intelligence (AI) and computer science which\nfocuses on the use of data and algorithms to imitate the way that humans learn,\ngradually improving its accuracy.\nIBM has a rich history with machine learning. One of its own, Arthur Samuel, is credited\nfor coining the term, \u201cmachine learning\u201d with his research (link resides outside ibm.com)\naround the game of checkers. Robert Nealey, the self-proclaimed checkers master,\nplayed the game on an IBM 7094 computer in 1962, and he lost to the computer.\nCompared to what can be done today, this feat seems trivial, but it\u2019s considered a major\nmilestone in the field of artificial intelligence.\nOver the last couple of decades, the technological advances in storage and processing\npower have enabled some innovative products based on machine learning, such as\nNetflix\u2019s recommendation engine and self-driving cars.\nMachine learning is an important component of the growing field of data science.\nThrough the use of statistical methods, algorithms are trained to make classifications or\npredictions, and to uncover key insights in data mining projects. These insights\nsubsequently drive decision making within applications and businesses, ideally\nimpacting key growth metrics. As big data continues to expand and grow, the market\ndemand for new data scientists will increase. They will be required to help identify the\nmost relevant business questions and the data to answer them.\nMachine learning algorithms are typically created using frameworks such as Python that\naccelerate solution development by using platforms like TensorFlow or PyTorch.\nNow available: watsonx.ai\nThe all-new enterprise studio that brings together traditional machine learning along\nwith new generative AI capabilities powered by foundation models.\nTry watsonx.ai\nBegin your journey to AI\nLearn how to scale AI\nExplore the AI Academy\nMachine Learning vs. Deep Learning vs. Neural Networks\nSince deep learning and machine learning tend to be used interchangeably, it\u2019s worth\nnoting the nuances between the two. Machine learning, deep learning, and neural\nnetworks are all sub-fields of artificial intelligence. However, neural networks is actually\na sub-field of machine learning, and deep learning is a sub-field of neural networks.\nThe way in which deep learning and machine learning differ is in how each algorithm\nlearns. \"Deep\" machine learning can use labeled datasets, also known as supervised\nlearning, to inform its algorithm, but it doesn\u2019t necessarily require a labeled dataset. The\ndeep learning process can ingest unstructured data in its raw form (e.g., text or images),\nand it can automatically determine the set of features which distinguish different\ncategories of data from one another. This eliminates some of the human intervention\nrequired and enables the use of large amounts of data. You can think of deep learning\nas \"scalable machine learning\" as Lex Fridman notes in this MIT lecture (link resides\noutside ibm.com).\nClassical, or \"non-deep,\" machine learning is more dependent on human intervention to\nlearn. Human experts determine the set of features to understand the differences\nbetween data inputs, usually requiring more structured data to learn.\nNeural networks, or artificial neural networks (ANNs), are comprised of node layers,\ncontaining an input layer, one or more hidden layers, and an output layer. Each node, or\nartificial neuron, connects to another and has an associated weight and threshold. If the\noutput of any individual node is above the specified threshold value, that node is\nactivated, sending data to the next layer of the network. Otherwise, no data is passed\nalong to the next layer of the network by that node.", "start_char_idx": 0, "end_char_idx": 3750, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "3df58e2a-eb97-4ce7-a7b8-8504521e12ef": {"__data__": {"id_": "3df58e2a-eb97-4ce7-a7b8-8504521e12ef", "embedding": null, "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "node_type": "4", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "233d2f3b87af08e48b322323d0b7ce130fce41f511ab2b93f31d7733e0583293", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "488d9176-adb9-4aa4-be31-c79adbf45c9a", "node_type": "1", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "a5227e9280f8e2078c1cceaf200c082abd32260a6523109cc76bce7fc6080dc7", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "cf355bc0-79e1-4c78-8f7e-e63738ba59f4", "node_type": "1", "metadata": {}, "hash": "7a55aae2f58a0465d55081eaddd06bb92fb3060cab95884bcd232cfc95f624c7", "class_name": "RelatedNodeInfo"}}, "text": "Otherwise, no data is passed\nalong to the next layer of the network by that node. The \u201cdeep\u201d in deep learning is just\nreferring to the number of layers in a neural network. A neural network that consists of\nmore than three layers\u2014which would be inclusive of the input and the output\u2014can be\nconsidered a deep learning algorithm or a deep neural network. A neural network that\nonly has three layers is just a basic neural network.\nDeep learning and neural networks are credited with accelerating progress in areas\nsuch as computer vision, natural language processing, and speech recognition.\nSee the blog post \u201cAI vs. Machine Learning vs. Deep Learning vs. Neural Networks:\nWhat\u2019s the Difference?\u201d for a closer look at how the different concepts relate.\nRelated content\nExplore the watsonx.ai interactive demo\nDownload \u201cMachine learning for Dummies\u201d\n- This link downloads a pdf\nExplore Gen AI for developers\nHow does machine learning work?\nUC Berkeley (link resides outside ibm.com) breaks out the learning system of a\nmachine learning algorithm into three main parts.\nA Decision Process: In general, machine learning algorithms are used to make a\nprediction or classification. Based on some input data, which can be labeled or\nunlabeled, your algorithm will produce an estimate about a pattern in the data.\nAn Error Function: An error function evaluates the prediction of the model. If\nthere are known examples, an error function can make a comparison to assess\nthe accuracy of the model.\nA Model Optimization Process: If the model can fit better to the data points in the\ntraining set, then weights are adjusted to reduce the discrepancy between the\nknown example and the model estimate. The algorithm will repeat this iterative\n\u201cevaluate and optimize\u201d process, updating weights autonomously until a\nthreshold of accuracy has been met.\nMachine learning methods\nMachine learning models fall into three primary categories.\nSupervised machine learning\nSupervised learning, also known as supervised machine learning, is defined by its use\nof labeled datasets to train algorithms to classify data or predict outcomes accurately.\nAs input data is fed into the model, the model adjusts its weights until it has been fitted\nappropriately. This occurs as part of the cross validation process to ensure that the\nmodel avoids overfitting or underfitting. Supervised learning helps organizations solve a\nvariety of real-world problems at scale, such as classifying spam in a separate folder\nfrom your inbox. Some methods used in supervised learning include neural networks,\nna\u00efve bayes, linear regression, logistic regression, random forest, and support vector\nmachine (SVM).\nUnsupervised machine learning\nUnsupervised learning, also known as unsupervised machine learning, uses machine\nlearning algorithms to analyze and cluster unlabeled datasets (subsets called clusters).\nThese algorithms discover hidden patterns or data groupings without the need for\nhuman intervention. This method\u2019s ability to discover similarities and differences in\ninformation make it ideal for exploratory data analysis, cross-selling strategies,\ncustomer segmentation, and image and pattern recognition. It\u2019s also used to reduce the\nnumber of features in a model through the process of dimensionality reduction. Principal\ncomponent analysis (PCA) and singular value decomposition (SVD) are two common\napproaches for this. Other algorithms used in unsupervised learning include neural\nnetworks, k-means clustering, and probabilistic clustering methods.\nSemi-supervised learning\nSemi-supervised learning offers a happy medium between supervised and\nunsupervised learning. During training, it uses a smaller labeled data set to guide\nclassification and feature extraction from a larger, unlabeled data set. Semi-supervised\nlearning can solve the problem of not having enough labeled data for a supervised\nlearning algorithm.", "start_char_idx": 3669, "end_char_idx": 7558, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "cf355bc0-79e1-4c78-8f7e-e63738ba59f4": {"__data__": {"id_": "cf355bc0-79e1-4c78-8f7e-e63738ba59f4", "embedding": null, "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "node_type": "4", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "233d2f3b87af08e48b322323d0b7ce130fce41f511ab2b93f31d7733e0583293", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "3df58e2a-eb97-4ce7-a7b8-8504521e12ef", "node_type": "1", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "d12e001404d5dcf101b2b06cde42dfb3e030d2fe10873160bf87649abe0beb35", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "2f38847c-3c65-41ae-84d8-b2bb890ae9ec", "node_type": "1", "metadata": {}, "hash": "98bd0c2ea89796e2a164b7e6a49d4a22646993923c40216341d6ff153d82f5f0", "class_name": "RelatedNodeInfo"}}, "text": "It also helps if it\u2019s too costly to label enough data.\nFor a deep dive into the differences between these approaches, check out \"Supervised\nvs. Unsupervised Learning: What's the Difference?\"\nReinforcement machine learning\nReinforcement machine learning is a machine learning model that is similar to\nsupervised learning, but the algorithm isn\u2019t trained using sample data. This model learns\nas it goes by using trial and error. A sequence of successful outcomes will be reinforced\nto develop the best recommendation or policy for a given problem.\nThe IBM Watson\u00ae system that won the Jeopardy! challenge in 2011 is a good example.\nThe system used reinforcement learning to learn when to attempt an answer (or\nquestion, as it were), which square to select on the board, and how much to\nwager\u2014especially on daily doubles.\nLearn more about reinforcement learning\nCommon machine learning algorithms\nA number of machine learning algorithms are commonly used. These include:\nNeural networks: Neural networks simulate the way the human brain works, with\na huge number of linked processing nodes. Neural networks are good at\nrecognizing patterns and play an important role in applications including natural\nlanguage translation, image recognition, speech recognition, and image creation.\nLinear regression: This algorithm is used to predict numerical values, based on a\nlinear relationship between different values. For example, the technique could be\nused to predict house prices based on historical data for the area.\nLogistic regression: This supervised learning algorithm makes predictions for\ncategorical response variables, such as \u201cyes/no\u201d answers to questions. It can be\nused for applications such as classifying spam and quality control on a\nproduction line.\nClustering: Using unsupervised learning, clustering algorithms can identify\npatterns in data so that it can be grouped. Computers can help data scientists by\nidentifying differences between data items that humans have overlooked.\nDecision trees: Decision trees can be used for both predicting numerical values\n(regression) and classifying data into categories. Decision trees use a branching\nsequence of linked decisions that can be represented with a tree diagram. One of\nthe advantages of decision trees is that they are easy to validate and audit,\nunlike the black box of the neural network.\nRandom forests: In a random forest, the machine learning algorithm predicts a\nvalue or category by combining the results from a number of decision trees.\nAdvantages and disadvantages of machine learning algorithms\nDepending on your budget, need for speed and precision required, each algorithm\ntype\u2014supervised, unsupervised, semi-supervised, or reinforcement\u2014has its own\nadvantages and disadvantages. For example, decision tree algorithms are used for both\npredicting numerical values (regression problems) and classifying data into categories.\nDecision trees use a branching sequence of linked decisions that may be represented\nwith a tree diagram. A prime advantage of decision trees is that they are easier to\nvalidate and audit than a neural network. The bad news is that they can be more\nunstable than other decision predictors.\nOverall, there are many advantages to machine learning that businesses can leverage\nfor new efficiencies. These include machine learning identifying patterns and trends in\nmassive volumes of data that humans might not spot at all. And this analysis requires\nlittle human intervention: just feed in the dataset of interest and let the machine learning\nsystem assemble and refine its own algorithms\u2014which will continually improve with\nmore data input over time. Customers and users can enjoy a more personalized\nexperience as the model learns more with every experience with that person.\nOn the downside, machine learning requires large training datasets that are accurate\nand unbiased. GIGO is the operative factor: garbage in / garbage out.", "start_char_idx": 7559, "end_char_idx": 11486, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "2f38847c-3c65-41ae-84d8-b2bb890ae9ec": {"__data__": {"id_": "2f38847c-3c65-41ae-84d8-b2bb890ae9ec", "embedding": null, "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "node_type": "4", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "233d2f3b87af08e48b322323d0b7ce130fce41f511ab2b93f31d7733e0583293", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "cf355bc0-79e1-4c78-8f7e-e63738ba59f4", "node_type": "1", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "e768326d3ad52040c74db90bfa292ec09ac418a3337534e16021fac1892db575", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "42325499-9ed6-4beb-87e5-ab16ddcfd70f", "node_type": "1", "metadata": {}, "hash": "1cab36cf26e435222503b8fdc466f00ea23e4c859f0b0d136eb6431cbf925bf8", "class_name": "RelatedNodeInfo"}}, "text": "GIGO is the operative factor: garbage in / garbage out. Gathering\nsufficient data and having a system robust enough to run it might also be a drain on\nresources. Machine learning can also be prone to error, depending on the input. With\ntoo small a sample, the system could produce a perfectly logical algorithm that is\ncompletely wrong or misleading. To avoid wasting budget or displeasing customers,\norganizations should act on the answers only when there is high confidence in the\noutput.\nReal-world machine learning use cases\nHere are just a few examples of machine learning you might encounter every day:\nSpeech recognition: It is also known as automatic speech recognition (ASR), computer\nspeech recognition, or speech-to-text, and it is a capability which uses natural language\nprocessing (NLP) to translate human speech into a written format. Many mobile devices\nincorporate speech recognition into their systems to conduct voice search\u2014e.g. Siri\u2014or\nimprove accessibility for texting.\nCustomer service: Online chatbots are replacing human agents along the customer\njourney, changing the way we think about customer engagement across websites and\nsocial media platforms. Chatbots answer frequently asked questions (FAQs) about\ntopics such as shipping, or provide personalized advice, cross-selling products or\nsuggesting sizes for users. Examples include virtual agents on e-commerce sites;\nmessaging bots, using Slack and Facebook Messenger; and tasks usually done by\nvirtual assistants and voice assistants.\nComputer vision: This AI technology enables computers to derive meaningful\ninformation from digital images, videos, and other visual inputs, and then take the\nappropriate action. Powered by convolutional neural networks, computer vision has\napplications in photo tagging on social media, radiology imaging in healthcare, and\nself-driving cars in the automotive industry.\nRecommendation engines: Using past consumption behavior data, AI algorithms can\nhelp to discover data trends that can be used to develop more effective cross-selling\nstrategies. Recommendation engines are used by online retailers to make relevant\nproduct recommendations to customers during the checkout process.\nRobotic process automation (RPA): Also known as software robotics, RPA uses\nintelligent automation technologies to perform repetitive manual tasks.\nAutomated stock trading: Designed to optimize stock portfolios, AI-driven\nhigh-frequency trading platforms make thousands or even millions of trades per day\nwithout human intervention.\nFraud detection: Banks and other financial institutions can use machine learning to spot\nsuspicious transactions. Supervised learning can train a model using information about\nknown fraudulent transactions. Anomaly detection can identify transactions that look\natypical and deserve further investigation.\nChallenges of machine learning\nAs machine learning technology has developed, it has certainly made our lives easier.\nHowever, implementing machine learning in businesses has also raised a number of\nethical concerns about AI technologies. Some of these include:\nTechnological singularity\nWhile this topic garners a lot of public attention, many researchers are not concerned\nwith the idea of AI surpassing human intelligence in the near future. Technological\nsingularity is also referred to as strong AI or superintelligence. Philosopher Nick\nBostrum defines superintelligence as \u201cany intellect that vastly outperforms the best\nhuman brains in practically every field, including scientific creativity, general wisdom,\nand social skills.\u201d Despite the fact that superintelligence is not imminent in society, the\nidea of it raises some interesting questions as we consider the use of autonomous\nsystems, like self-driving cars. It\u2019s unrealistic to think that a driverless car would never\nhave an accident, but who is responsible and liable under those circumstances? Should\nwe still develop autonomous vehicles, or do we limit this technology to\nsemi-autonomous vehicles which help people drive safely?", "start_char_idx": 11431, "end_char_idx": 15467, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "42325499-9ed6-4beb-87e5-ab16ddcfd70f": {"__data__": {"id_": "42325499-9ed6-4beb-87e5-ab16ddcfd70f", "embedding": null, "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "node_type": "4", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "233d2f3b87af08e48b322323d0b7ce130fce41f511ab2b93f31d7733e0583293", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "2f38847c-3c65-41ae-84d8-b2bb890ae9ec", "node_type": "1", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "12c67cbd452c9ff6c9f6523f769e458d0bb4686972a6bdac215aacc695bd8a52", "class_name": "RelatedNodeInfo"}, "3": {"node_id": "bd38690f-c8a3-40b2-a999-f233f0c228e1", "node_type": "1", "metadata": {}, "hash": "245f82c83f6c9ab4743d5c35b0d85af2c0d153e11ad7aff32569e35fc4e656bd", "class_name": "RelatedNodeInfo"}}, "text": "The jury is still out on this,\nbut these are the types of ethical debates that are occurring as new, innovative AI\ntechnology develops.\nAI impact on jobs\nWhile a lot of public perception of artificial intelligence centers around job losses, this\nconcern should probably be reframed. With every disruptive, new technology, we see\nthat the market demand for specific job roles shifts. For example, when we look at the\nautomotive industry, many manufacturers, like GM, are shifting to focus on electric\nvehicle production to align with green initiatives. The energy industry isn\u2019t going away,\nbut the source of energy is shifting from a fuel economy to an electric one.\nIn a similar way, artificial intelligence will shift the demand for jobs to other areas. There\nwill need to be individuals to help manage AI systems. There will still need to be people\nto address more complex problems within the industries that are most likely to be\naffected by job demand shifts, such as customer service. The biggest challenge with\nartificial intelligence and its effect on the job market will be helping people to transition\nto new roles that are in demand.\nPrivacy\nPrivacy tends to be discussed in the context of data privacy, data protection, and data\nsecurity. These concerns have allowed policymakers to make more strides in recent\nyears. For example, in 2016, GDPR legislation was created to protect the personal data\nof people in the European Union and European Economic Area, giving individuals more\ncontrol of their data. In the United States, individual states are developing policies, such\nas the California Consumer Privacy Act (CCPA), which was introduced in 2018 and\nrequires businesses to inform consumers about the collection of their data. Legislation\nsuch as this has forced companies to rethink how they store and use personally\nidentifiable information (PII). As a result, investments in security have become an\nincreasing priority for businesses as they seek to eliminate any vulnerabilities and\nopportunities for surveillance, hacking, and cyberattacks.\nBias and discrimination\nInstances of bias and discrimination across a number of machine learning systems have\nraised many ethical questions regarding the use of artificial intelligence. How can we\nsafeguard against bias and discrimination when the training data itself may be\ngenerated by biased human processes? While companies typically have good\nintentions for their automation efforts, Reuters (link resides outside ibm.com) highlights\nsome of the unforeseen consequences of incorporating AI into hiring practices. In their\neffort to automate and simplify a process, Amazon unintentionally discriminated against\njob candidates by gender for technical roles, and the company ultimately had to scrap\nthe project. Harvard Business Review (link resides outside ibm.com) has raised other\npointed questions about the use of AI in hiring practices, such as what data you should\nbe able to use when evaluating a candidate for a role.\nBias and discrimination aren\u2019t limited to the human resources function either; they can\nbe found in a number of applications from facial recognition software to social media\nalgorithms.\nAs businesses become more aware of the risks with AI, they\u2019ve also become more\nactive in this discussion around AI ethics and values. For example, IBM has sunset its\ngeneral purpose facial recognition and analysis products. IBM CEO Arvind Krishna\nwrote: \u201cIBM firmly opposes and will not condone uses of any technology, including facial\nrecognition technology offered by other vendors, for mass surveillance, racial profiling,\nviolations of basic human rights and freedoms, or any purpose which is not consistent\nwith our values and Principles of Trust and Transparency.\u201d\nAccountability\nSince there isn\u2019t significant legislation to regulate AI practices, there is no real\nenforcement mechanism to ensure that ethical AI is practiced.", "start_char_idx": 15468, "end_char_idx": 19378, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}, "bd38690f-c8a3-40b2-a999-f233f0c228e1": {"__data__": {"id_": "bd38690f-c8a3-40b2-a999-f233f0c228e1", "embedding": null, "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "excluded_embed_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "excluded_llm_metadata_keys": ["file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date"], "relationships": {"1": {"node_id": "f82f40b2-29b4-4536-b1a3-9f272306d5cd", "node_type": "4", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "233d2f3b87af08e48b322323d0b7ce130fce41f511ab2b93f31d7733e0583293", "class_name": "RelatedNodeInfo"}, "2": {"node_id": "42325499-9ed6-4beb-87e5-ab16ddcfd70f", "node_type": "1", "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}, "hash": "d7f042335366cca2a16135b60ffcd39f6bbbcf8e349addb67afbf2116c49aea7", "class_name": "RelatedNodeInfo"}}, "text": "The current incentives for\ncompanies to be ethical are the negative repercussions of an unethical AI system on the\nbottom line. To fill the gap, ethical frameworks have emerged as part of a collaboration\nbetween ethicists and researchers to govern the construction and distribution of AI\nmodels within society. However, at the moment, these only serve to guide. Some\nresearch (link resides outside ibm.com) shows that the combination of distributed\nresponsibility and a lack of foresight into potential consequences aren\u2019t conducive to\npreventing harm to society.\nRead more about IBM's position on AI Ethics\nHow to choose the right AI platform for machine learning\nSelecting a platform can be a challenging process, as the wrong system can drive up\ncosts, or limit the use of other valuable tools or technologies. When reviewing multiple\nvendors to select an AI platform, there is often a tendency to think that more features =\na better system. Maybe so, but reviewers should start by thinking through what the AI\nplatform will be doing for their organization. What machine learning capabilities need to\nbe delivered and what features are important to accomplish them? One missing feature\nmight doom the usefulness of an entire system. Here are some features to consider.\nMLOps capabilities. Does the system have:\na unified interface for ease of management?\nautomated machine learning tools for faster model creation with low-code\nand no-code functionality?\ndecision optimization to streamline the selection and deployment of\noptimization models?\nvisual modeling to combine visual data science with open-source libraries\nand notebook-based interfaces on a unified data and AI studio?\nautomated development for beginners to get started quickly and more\nadvanced data scientists to experiment?\nsynthetic data generator as an alternative or supplement to real-world data\nwhen real-world data is not readily available?\nGenerative AI capabilities. Does the system have:\na content generator that can generate text, images and other content\nbased on the data it was trained on?\nautomated classification to read and classify written input, such as\nevaluating and sorting customer complaints or reviewing customer\nfeedback sentiment?\na summary generator that can transform dense text into a high-quality\nsummary, capture key points from financial reports, and generate meeting\ntranscriptions?\na data extraction capability to sort through complex details and quickly pull\nthe necessary information from large documents?", "start_char_idx": 19379, "end_char_idx": 21888, "text_template": "{metadata_str}\n\n{content}", "metadata_template": "{key}: {value}", "metadata_seperator": "\n", "class_name": "TextNode"}, "__type__": "1"}}, "docstore/ref_doc_info": {"f82f40b2-29b4-4536-b1a3-9f272306d5cd": {"node_ids": ["488d9176-adb9-4aa4-be31-c79adbf45c9a", "3df58e2a-eb97-4ce7-a7b8-8504521e12ef", "cf355bc0-79e1-4c78-8f7e-e63738ba59f4", "2f38847c-3c65-41ae-84d8-b2bb890ae9ec", "42325499-9ed6-4beb-87e5-ab16ddcfd70f", "bd38690f-c8a3-40b2-a999-f233f0c228e1"], "metadata": {"file_path": "Data\\MLDOC.txt", "file_name": "MLDOC.txt", "file_type": "text/plain", "file_size": 22273, "creation_date": "2024-02-15", "last_modified_date": "2024-02-15", "last_accessed_date": "2024-02-15"}}}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/storage/graph_store.json
================================================
{"graph_dict": {}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/storage/image__vector_store.json
================================================
{"embedding_dict": {}, "text_id_to_ref_doc_id": {}, "metadata_dict": {}}
================================================
FILE: QA_With_Doc_Using_LlamaIndex_Gemini/storage/index_store.json
================================================
{"index_store/data": {"3a5a6a94-7296-41c3-b23a-b18b995074ee": {"__type__": "vector_store", "__data__": "{\"index_id\": \"3a5a6a94-7296-41c3-b23a-b18b995074ee\", \"summary\": null, \"nodes_dict\": {\"488d9176-adb9-4aa4-be31-c79adbf45c9a\": \"488d9176-adb9-4aa4-be31-c79adbf45c9a\", \"3df58e2a-eb97-4ce7-a7b8-8504521e12ef\": \"3df58e2a-eb97-4ce7-a7b8-8504521e12ef\", \"cf355bc0-79e1-4c78-8f7e-e63738ba59f4\": \"cf355bc0-79e1-4c78-8f7e-e63738ba59f4\", \"2f38847c-3c65-41ae-84d8-b2bb890ae9ec\": \"2f38847c-3c65-41ae-84d8-b2bb890ae9ec\", \"42325499-9ed6-4beb-87e5-ab16ddcfd70f\": \"42325499-9ed6-4beb-87e5-ab16ddcfd70f\", \"bd38690f-c8a3-40b2-a999-f233f0c228e1\": \"bd38690f-c8a3-40b2-a999-f233f0c228e1\"}, \"doc_id_dict\": {}, \"embeddings_dict\": {}}"}}}
================================================
FILE: RAG App using Haystack & OpenAI/RAG_Application_Using_Haystack_and_OpenAI.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "ozHSXlNCxdsr"
},
"source": [
"# **Haystack**\n",
"\n",
"We talked about LangChain’s features, and how to utilise them to build language applications. While LangChain supports quite a lot of different use cases in NLP, we are going to talk about another open-source tool called Haystack that is used in building large-scale search systems. Information retrieval which is an area of focus for Haystack, and is also an area of overlap with LangChain. Haystack also supports prompting to achieve summarization, question-answering, translation, etc.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3xiYMPv3xieD"
},
"source": [
"# **What is Haystack?**\n",
"\n",
"Haystack is a versatile open-source Python framework that provides developers with a toolkit to create powerful search systems that can efficiently handle large document collections. Whether you’re building a search engine for a web application, an e-commerce platform, or a knowledge management system, Haystack makes it easy to integrate advanced search capabilities into your project.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "S_qF8EKixeQ1",
"outputId": "84437b52-beb9-4694-9ac4-37364801d263"
},
"outputs": [],
"source": [
"%%bash\n",
"\n",
"pip install haystack-ai\n",
"pip install \"datasets>=2.6.1\"\n",
"pip install \"sentence-transformers>=2.2.0\"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "L0kjpt8jxvf9"
},
"outputs": [],
"source": [
"from haystack.document_stores.in_memory import InMemoryDocumentStore\n",
"\n",
"document_store = InMemoryDocumentStore()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NP0X2WrCygfu"
},
"outputs": [],
"source": [
"from datasets import load_dataset\n",
"from haystack import Document"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 237,
"referenced_widgets": [
"ef7566a525604a02a8ba67c37bbc2be3",
"96ecf1627b594904baf3f6a8eedec8c2",
"6a594b93a9b24d82948afafd40f66574",
"0e352d533059496c8b21a4b8aa1492af",
"342f83b86d6948779373566a006ba814",
"ffc325f13ad84b9488fd88de64bd80b0",
"90062a47c01641269cc6f0f49212460a",
"030e3e5ec61a425bb79fb81cce3641ff",
"d0546637d1da41aab7d939060ff6217f",
"aa1ad3206b7a4156b3ef4abc851089c2",
"32bb6ac13bfa413d9d82c9ba01307627",
"ff5d16365f03454c8820625cd2c4f478",
"a685fbcd0b0b4299a5945ff4af01d96c",
"3f8abdfae1c548939b1a6ddeb03bee9a",
"c13ad33366ef4ddb8e3544331803b387",
"ff570a7525674f5097a315455c69c4ea",
"cd976ae1d5ee4d95948fab4e44413a2f",
"ae36304150e840a5974817fc13551483",
"dbf22ba7b3084b5aa50f3aaea67683d1",
"c954c68cb43a4fdca0b9fb81f93314e2",
"91c8ef5978db4c0b83f9d448023f4b27",
"1d99c6cf1d9741c8aa73baf6b0527c9d",
"0e7993ed95c84e4bb50b934dd667d3a4",
"1652bd5c8063469aa3b45feb62156a2b",
"e92169f51cee4813aa829f28aa04e64d",
"712a353b73f84bf686650c45b3c0c38a",
"bb5a401a7a2a4617a7118aa7da8bb941",
"8b3ec13e06d94e3b99d0ccceb87d6fc2",
"d9e8f02e5c8f492594f9c1bad8ce3538",
"6f04e34e4f5f44889324f2f65102c4f0",
"cc82cb866442463e85c958de0276c37d",
"d97abfac932b442f907775e5ca5432dc",
"086a1f164e19472392efac15e76028e6"
]
},
"id": "EsPzgVMGyx7W",
"outputId": "a7375316-0774-4909-9d28-89c9e6d323c0"
},
"outputs": [],
"source": [
"dataset=load_dataset(\"bilgeyucel/seven-wonders\", split=\"train\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "VeasS2BSy3Jt",
"outputId": "fe258b13-5916-4159-b9f0-73dde1b43a8d"
},
"outputs": [],
"source": [
"dataset"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "LTd7lM_Zy7Bu",
"outputId": "a9122183-482d-48c4-a6ee-140de612b4e4"
},
"outputs": [],
"source": [
"for doc in dataset:\n",
" print(doc['content'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vRN8YXjczDUV"
},
"outputs": [],
"source": [
"docs = [Document(content=doc[\"content\"], meta=doc[\"meta\"]) for doc in dataset]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "etqehQ2Hz179",
"outputId": "cf949d32-9aeb-477d-a2b4-4f8ab25ac450"
},
"outputs": [],
"source": [
"docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 369,
"referenced_widgets": [
"942b8731409b452fb9bc19e48fd1e82b",
"c4d768a9eeb3419cb09057423a2d7c08",
"15127217ea3b47528eb3045e2747ee99",
"7d6c12ad1aa6456bbe234046ed2ba7e9",
"fa3d4ee314e945fe8e0788fbee763cf6",
"2eaba357a0e24e8abd58981d1f60d934",
"6fe6b725b56f4ba0a7f5e6d7d4fbc66b",
"dc63b42943c54495b8c2170374b11272",
"bd54017b3cac4c78a4a0510f6cbd7c4e",
"60ee050449b14d5f90aeddebbe651931",
"1f2fb85d6e044bc39bdbc84f5ab77a52",
"f0d4dbf082264ce9b8b832430e5a7ecf",
"1db7434c3d7d4e6aa9efe3678f953601",
"45d6ce5c956f4b46a8f75c29588acf86",
"5a77abc6ca654b1fb1efd0b0f55469ab",
"90261afb84b342798a2cdb6a88a2692c",
"6b7e5cb4d9464ceca398e2e311a3bde3",
"fa5c5cf86d7c4b7880d1511ef18dbd80",
"bbef43f07e9845459fba1de3ef9d61a1",
"dc4858f619014fc390e67a467978641d",
"8e2fdf2b7bee454096271fe349b5ada0",
"fdde0894e6274e20aeeb79b9f9da8668",
"516dc86368774c1eb2c31f8eeb3c06fc",
"b8c645d33f4045f6ad4ef538a1334384",
"24bd3082d21f4ae892f0c40caedac621",
"5375f09b2fe442c294c7f9d46d8524d5",
"2d9da9b145084bd387b73f9f250d0273",
"9e6728039bbe43e5bbea7f72859d0a7a",
"6824e8fb91ff460995d0a4de8b421a51",
"571e8c1e85db4cdba625a20704a3ccae",
"6194e2f997e24e40af1bf27ea5c418f0",
"8c24c14bf33e40ea8bfdd05cf666dcd1",
"37c7fe137b3a4faf9890d7fb0eaecb3a",
"474a6c9dd07a41598b7798516dfab95d",
"a3792801002e40318c0456bd247ab48f",
"507c7947945147ddb2852de1f2e0f4f9",
"88285bd07fe847429b160bd3e7448135",
"f718f555689541d7b94c7c60c61f63d5",
"b0154726c8ce4220a692a232f37315d7",
"6258e7758bcf4481bd2f1f031a6b81cf",
"7ee10a3051fe459dbc09bf588b97b268",
"04a4e3729d4645e8b74ae8ea385afc78",
"c5fdf1dd84f3405a806d9824cf567085",
"8eccac235c1f4dd9ba141264f9baa2a8",
"e5f3b174f766427ba72ceb7fd1940ba6",
"188d54b5de38494c8073133f32abc767",
"4764ee6e7a204475aa489c990241a605",
"3d2ed6b853a74051a73a8b5fae2d8e82",
"d2f3c99a63ae4f2daa498c5aeab149fe",
"e1fd1a310a8f49ef9693a8a36b28a76e",
"ba7980f40aab4efca479f8809f53b7d4",
"cb53db6a40a047939ddee176c9dc341b",
"aa95f50c7e0b4b7ba8ef432aab100bb9",
"d030c77e7ed94d2ab678d281e098d392",
"f72275b10dd8469aaa09e04780e4b421",
"ddfcb69627d7499390fe9fc5f88cdb47",
"5d54bb66d7b543a88c7b5c6a3db9086a",
"fa58d40ac8d64546b020e914a26cac6c",
"4e913c1794c2444da7d1ad7e481543aa",
"6e7cc5e0ff8f4018b6fb54ad0816266e",
"8a7edc64fe09415f9817cb1f29c87a6f",
"952d7df44ddd4ba69ca07ac0d127d86c",
"26f7d51e94ab49ae849f4fcba776a6de",
"fa53b16a2cfa461ab0797e94eee1aab2",
"32b44cf9c941403e9e49bc8201818069",
"ae2ad99e57094596aa113ea6a195d681",
"8483e66f968a4897b81ff70cc8deb010",
"1f3a0efbfdd84286b7e9a2f55999bbc7",
"23614648a0414ae1969df902ed6b1b75",
"011dfbe1eaae45be885042e412b5531d",
"704ef417daac4a6f82785d1010563f3d",
"cd81d38f1b454392af2ab1594c51076c",
"e30adc89a4c548d8b487d520e409becb",
"de76464c70c64cfd9ef5231389c372e4",
"e634d0a5ddd645a2b262fa4030b02e60",
"c4988cb98d4e44748facf4aac2f1ffd2",
"24e4fe92b2af4be28f8465160c189fb5",
"bc1653ec0143434cae66a2cd918fd315",
"89cbc118105440c4aafcb8a03260cbe1",
"2d9884f0d7714843ba0fbefc874ecc2f",
"cc3f6ecc6ae34fa5b82c6bb03e1097ce",
"cc4bbd53cfd04e268c1fb21eb65310c0",
"e98857c8088f4f4b916da7cb6901852c",
"35915104c37142dc98249186eb188668",
"a9e4d4e6f66f48898bbd6327b3dc162c",
"d5312699e6944c0d9d1082e54c4fce85",
"52d261a0764e4cb9825446b4fd3329f2",
"b92ab4ede05d4a31b529c3177d626972",
"e8bf8f895b1b48b99578c0aa67ddaf20",
"c3812f5f5e41479ca996763d1ef57b91",
"e6ef2310b42b4c6ba1feb9e4fb173ac8",
"2f5c2139211943bc89966bcf3d9bf515",
"fa4c561027f14a5da67d179dea1b0a3c",
"f26bc917d3de40adaed88572efd3e33e",
"c311511b9bbd46f29e980539ddad3096",
"c04c44f53f534feea78ba9bc7d354f52",
"99abde327f604b0ab465fa70ad7bd983",
"059fe9d119724e469aacf777257302dd",
"310971fe6bdd41a5acb236d9a3e96c2e",
"d18ec71436e148dbb2224ac6c1af8faf",
"2234b075f28843acab21b3ae192d53cd",
"9aa4c199437d4064a2bdeaa224cdbdfa",
"5ba84c9c32774be98e9a69ac1750fdfa",
"47faba900da142558ce4504e02937a7c",
"5c034eaaaa864db3a5f3a9d2a7d8764a",
"a80b74fedfc6480ab568a828052d42d3",
"80845ab2e95740a2b54cc97304843c4f",
"7a0e3dad73824584abd12b6b1445b049",
"da05e89a3768474ba0fc9bcc5976b063",
"1ed72f7221cd4507b896b8a69ac1e3ec",
"7446469c07774065a42baf82445812f3",
"b25f633d6005474c9c47d814a8b5df6a",
"7f63fc4eee584038b929b38b9c05acc4",
"402c92e76734405bb96d0ad8109e5e4a",
"290af72e02b44764b7d7f8ba31b1d703",
"15712c42af6540da89f564f2c28ab31c",
"40ecc5e6ce434f329c5f2090252723dc",
"e935155e3bdb470fa1c07ddd273f4fbd",
"2700b2cc16894047b72869ec4409ad50",
"e69ca932a4bc40ea920660fbd9a60be9",
"3ba0a0c60c604c6ebd8bca40ad5819af"
]
},
"id": "m8CnMliD0AU9",
"outputId": "f37d2eab-3e0b-4ad5-feb0-eb5a3fb201cb"
},
"outputs": [],
"source": [
"from haystack.components.embedders import SentenceTransformersDocumentEmbedder\n",
"\n",
"doc_embedder = SentenceTransformersDocumentEmbedder(model=\"sentence-transformers/all-MiniLM-L6-v2\")\n",
"doc_embedder.warm_up()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 49,
"referenced_widgets": [
"ef3412c2bb4c4a309e636f3bb41dd493",
"127f2730175d465a95a0bff717957c12",
"c922091c7c5a4ec38737af285e2c5bca",
"42da910943cf4effa55b57b0a3d72e7d",
"44e8a631a5ae4631a2f36e97f4cb0e97",
"bdae788bf2dc4210af889c37af5192ee",
"31c3170f6bde472dbd6767b3634cabc9",
"1edc708f53cb4a6197fd4022533891c6",
"56cda94693ad4d4887e329ff195c9b7f",
"2443004f68aa4e049f9c1414bf3f83f5",
"b7c8378f951f4b1a94f3d0c8e8360533"
]
},
"id": "-ReEJzw-0ZoV",
"outputId": "fb7f607f-4682-48b9-a30e-c6359a783752"
},
"outputs": [],
"source": [
"docs_with_embeddings = doc_embedder.run(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "l6qgsc-J0OmT",
"outputId": "8cb82df1-76f6-4604-d306-43eea8290d1d"
},
"outputs": [],
"source": [
"document_store.write_documents(docs_with_embeddings[\"documents\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TauMKmRX0dIv"
},
"outputs": [],
"source": [
"from haystack.components.embedders import SentenceTransformersTextEmbedder\n",
"\n",
"text_embedder = SentenceTransformersTextEmbedder(model=\"sentence-transformers/all-MiniLM-L6-v2\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2k0yWLhY0xM9"
},
"outputs": [],
"source": [
"from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever\n",
"\n",
"retriever = InMemoryEmbeddingRetriever(document_store)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EdHGnbKp1E0d"
},
"outputs": [],
"source": [
"from haystack.components.builders import PromptBuilder\n",
"\n",
"template = \"\"\"\n",
"Given the following information, answer the question.\n",
"\n",
"Context:\n",
"{% for document in documents %}\n",
" {{ document.content }}\n",
"{% endfor %}\n",
"\n",
"Question: {{question}}\n",
"Answer:\n",
"\"\"\"\n",
"\n",
"prompt_builder = PromptBuilder(template=template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "oy3DxvzT1W3D"
},
"outputs": [],
"source": [
"import os\n",
"from getpass import getpass\n",
"from haystack.components.generators import OpenAIGenerator"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rrUI_si31JW9",
"outputId": "097dde18-09e2-4846-f76f-cf3c57fb4717"
},
"outputs": [],
"source": [
"if \"OPENAI_API_KEY\" not in os.environ:\n",
" os.environ[\"OPENAI_API_KEY\"] = getpass(\"Enter OpenAI API key:\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RBZ7hrKw1d8N"
},
"outputs": [],
"source": [
"generator = OpenAIGenerator(model=\"gpt-3.5-turbo\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NhEpSkcS1xCN"
},
"outputs": [],
"source": [
"from haystack import Pipeline\n",
"\n",
"basic_rag_pipeline = Pipeline()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bbkgQ6rg1uae"
},
"outputs": [],
"source": [
"# Add components to your pipeline\n",
"basic_rag_pipeline.add_component(\"text_embedder\", text_embedder)\n",
"basic_rag_pipeline.add_component(\"retriever\", retriever)\n",
"basic_rag_pipeline.add_component(\"prompt_builder\", prompt_builder)\n",
"basic_rag_pipeline.add_component(\"llm\", generator)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "R2Uw3eat1ile",
"outputId": "a02327ed-cbc0-43b9-a4fc-169f355631f5"
},
"outputs": [],
"source": [
"# Now, connect the components to each other\n",
"basic_rag_pipeline.connect(\"text_embedder.embedding\", \"retriever.query_embedding\")\n",
"basic_rag_pipeline.connect(\"retriever\", \"prompt_builder.documents\")\n",
"basic_rag_pipeline.connect(\"prompt_builder\", \"llm\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "oo0fR0K52fpd"
},
"outputs": [],
"source": [
"question = \"What does Rhodes Statue look like?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 49,
"referenced_widgets": [
"4eb92ff424b4451f873d4366e22eb268",
"70fd931d9e9a4eb78d9aeff0d9b106e1",
"e343e037493e40f9bda18fdaaa8588d8",
"208f70a9f2d1435390c4ada68087f7b7",
"3584b71403ac4139a6da3758aa778d4a",
"80d1759a43ec4e5c91a89ad6452402f3",
"29831268cc6e4b4bb9ee3a18bd9409b8",
"6eb0ae16b6204f52ae8769c2fee06979",
"faec10cbbb3840918be936c15e433ca4",
"a83d6e316986412cb050554a7092ca6d",
"73d1c41ade7f4b55b3a474d418bdcd1c"
]
},
"id": "10Dq0YjJ2i6-",
"outputId": "f027ebd3-463e-4693-c879-c17f26181cf3"
},
"outputs": [],
"source": [
"response = basic_rag_pipeline.run({\"text_embedder\": {\"text\": question}, \"prompt_builder\": {\"question\": question}})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "U825wp1n2oPj"
},
"outputs": [],
"source": [
"examples = [\n",
" \"Where is Gardens of Babylon?\",\n",
" \"Why did people build Great Pyramid of Giza?\",\n",
" \"What does Rhodes Statue look like?\",\n",
" \"Why did people visit the Temple of Artemis?\",\n",
" \"What is the importance of Colossus of Rhodes?\",\n",
" \"What happened to the Tomb of Mausolus?\",\n",
" \"How did Colossus of Rhodes collapse?\",\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "uRludzSK4Box"
},
"outputs": [],
"source": [
"question=\"Why did people visit the Temple of Artemis?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 49,
"referenced_widgets": [
"194af2981f324e5f85658e96c8d94948",
"6b985b11836945f0874b6ffbdf904f61",
"4b352da78e05468aa9c8a31efde70b5c",
"34c1a4267e794fa38bf8df1b317f80c2",
"63194f3d125d48ed8185859831b91ff0",
"5ea53d848a3e4a3cadbaaa8cf63c6599",
"1a49136b479640928be5afdd831a2093",
"a05b87abd0cf48a688b3f5671fb75dda",
"4eea3ee687a345018fe1a00a0f5bc382",
"ccf3f7946642476f9599574f8948f7a0",
"d270c37c90524229a8073170132b3193"
]
},
"id": "1WVPYKfk4D4e",
"outputId": "aa891eda-77df-4d0a-f39b-46f33f7dbdfd"
},
"outputs": [],
"source": [
"response = basic_rag_pipeline.run({\"text_embedder\": {\"text\": question}, \"prompt_builder\": {\"question\": question}})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 105
},
"id": "OWGiRXyF4JI_",
"outputId": "1697c956-852e-4c2d-910e-9361508ab0c1"
},
"outputs": [],
"source": [
"response[\"llm\"][\"replies\"][0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2pPSaD8-4L1O"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: RAG App using LLAMAINDEX & MistralAI/RAG_Application_Using_LlamaIndex_and_Mistral_AI.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hT98mSf6USb8",
"outputId": "23875c09-1677-411d-cb26-ef76d618bc7d"
},
"outputs": [],
"source": [
"%pip install llama-index-llms-huggingface"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8ujTBSlVxWce",
"outputId": "a1d4041d-31c9-499f-cc08-fedb3228b937"
},
"outputs": [],
"source": [
"!pip install llama-index"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kJnGN2Krxby3"
},
"outputs": [],
"source": [
"from llama_index.core import VectorStoreIndex, SimpleDirectoryReader\n",
"from llama_index.llms.huggingface import HuggingFaceLLM"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "D31Z5mDXx9n-"
},
"outputs": [],
"source": [
"!mkdir data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nP14A9EByIvt"
},
"outputs": [],
"source": [
"# load documents\n",
"documents = SimpleDirectoryReader(\"./data/\").load_data()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "S2_y2X4SyVOp",
"outputId": "8be4fadf-33c9-4c9e-db98-a65954b5d0b3"
},
"outputs": [],
"source": [
"print(documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "a5X17y7FyWlF"
},
"outputs": [],
"source": [
"# setup prompts - specific to StableLM\n",
"from llama_index.core import PromptTemplate\n",
"\n",
"system_prompt = \"\"\"<|SYSTEM|># You are a Q&A assistant. Your goal is to answer questions as\n",
"accurately as possible based on the instructions and context provided.\n",
"\"\"\"\n",
"\n",
"# This will wrap the default prompts that are internal to llama-index\n",
"query_wrapper_prompt = PromptTemplate(\"<|USER|>{query_str}<|ASSISTANT|>\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nOTyc8jS0XYT"
},
"source": [
"https://github.com/run-llama/llama_index/blob/main/llama-index-integrations/llms/llama-index-llms-huggingface/llama_index/llms/huggingface/base.py"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 511,
"referenced_widgets": [
"dd5cbd1a967c43cd8520fff6227a41b5",
"8444d16768d8412db16f592c663ac2ee",
"9bf68b229b554df1827b74efaffbbb5e",
"1293aad1760d4bf68e58cf5d9888df78",
"b8407a3d1ce845ce9183f378daf35c18",
"5d372cc0a3294f21959367ae2408dfd6",
"8983e11d5a2d4c6d986d7133877f5298",
"b418f4a18d594d688b30095d6c307289",
"a5fdf629d03f423ab810a33863b756a7",
"695fbba5151e493ebd8e5637db31f18d",
"8aaa86a36a084b979e8de9c19295473d",
"492fbd0296944481987615718e8d9d9b",
"1e0dd6926dd64f12ad95b17202b9dbaa",
"79a2d832f73a4f1f9058de2b5489f07e",
"13656119cab642f1979ecb7a6a224dec",
"28ca702f4f604cc482dae607b828e917",
"c2c5810a3c14495f91499b2d6b3c4627",
"b61a39f8ce064b62a328d7da0823abb7",
"22cbe78cd06d431688e7c44a3a790b79",
"f2f3587adfbc44e5ab32f6c13c81f631",
"afc409c61ddb4ea3abff15438b1c91c2",
"7e96f952ee82402b903a1f2c23c8cf96",
"cb50e138a59d4bdaab38a2ef6ea02339",
"fe9526f59e774754a2ad4176d3db3c8c",
"2fe02108b8ba458285603f50cda06c23",
"2e4fdb1949b2498888c4a41c2f0a4d8e",
"ee2acada158b4e03ad3b1c91667b73c8",
"1e8dfc158ecf4706af5ccda8c4940b88",
"3d25b560105344e0b2e55bea057c1459",
"0968757ddc9c476f85311f7826b015ef",
"b8404f1636d24c93831331f2ded431d8",
"c85467854127467ba34e3c2a491d373c",
"eafc35172453428bb6f9a7ed738be365",
"6686977b63404f6db04e5586b6191e04",
"b10835c6cfe44fb3b06c6a8a426f95da",
"c987da924207433da56cd7180a1e3638",
"d87dbe1bc9f9437db5db7b0346c7604d",
"3db55bbcd3964060be33c17e768baf2a",
"519ea56649674f678fa1294da9b7e4f5",
"9f0b688cfc6647eda521ce087ef81667",
"e955c27a42374a8a8d363fa77200cfa9",
"67c028c10ce64914b83cf294375a4071",
"26b14d42b2a744c38a3bc94150c8e36a",
"c3b84d376faf4e6a8cd2f800be94783a",
"2e645764024f44b197a15eb40f68aa52",
"e45f5736462f472088e63e59f518f789",
"50224ccf914d435c86f328fd04695022",
"614e3411b6084ad69f72fbc047f60869",
"abc08239af24459b95f7aa9be86da030",
"e6fdd9c2150144098b7178d362b83b10",
"977a192392194c3ba2dac845d940a92f",
"1138b12d28a34eabbfb73030fc3055ca",
"3a2c956b8eac434b91711f13da391d4f",
"1720c99486e84def869dcd57197a443b",
"19b34ddde5054448b9693b8bba725dc1",
"e59a1f02c2c64c82a98ed4ec8126ac17",
"0f76a73f9f4f4d73abbb23755d1d817f",
"da756ae49de344eab2163133df806531",
"583dbec04078405abd29cc56cb3a11a0",
"226ea5b4838f45e2a24c2efb1849e34c",
"a3ad56dc686b457b91daae39dca24835",
"2dc829c8294a4c1491ff5d56364b72f6",
"f25f2cef80c64cd0b40fe6d8dc09f5c8",
"b8aa3c7b39494e95b7a710a742b5dbf9",
"873b746879ee4a2eaa97e0c54e9a126b",
"1797ce9fd78142c8b18a08716f4e7d28",
"6870db13150147aabd935aa70ec350f1",
"fd1cb02b527944eaab2783a99294d172",
"217e56acadab4417b3a44eb8145732d5",
"0513257d81154388870ffc7eab2317b1",
"aa09362e2f3140d08c74dac129f170c3",
"a3131bf61b7c4c5c80b5ade0d960cd1f",
"325e80a4379240688d632ba3cad2e6aa",
"33d52b220a3f4d90a340cffb51cb8333",
"4b7e966f1ecd4b4f9e7bb5c55b7e1a7d",
"29ae8e293137446fbea1384cdc78bfb9",
"9f621c6a68394952963c27f049e195ce",
"ac8fb708a6334bb3989c8dcdb9522b49",
"33f55a66a8a84bf5a82662c15413103c",
"f67a8d5b90b641e8ac3187c6831de143",
"e22e792c0616459a97d62940fd15e669",
"ee1f169d0091425286f200524a780a12",
"aa01c4758dbf45f7959a2f3490ad2037",
"b64410fdc9b049f9b996d54b3b5dec82",
"77b8d398a61148f689b576a823f9f1f2",
"4cf031673e284e54bcbc3ccf5b9e3868",
"1b7f4d24fdd5473fba8e564452139e92",
"5c395df37f6d4b049ce4c7c1a6b6eac6",
"07cf3c551f3b4ca3a63f0b3e7501cd67",
"c26643d93235443ea99f59a77f1c7b0a",
"e87dcccfb96f47ba9099622c7b2d8a51",
"379eb11fc5814f8799b8f45eeba8072c",
"5eab37bc6617483ca2744c790e13d87d",
"aa631f6a79ab4c2c9e2b11cc356a5633",
"cf418f17a87744449c86c3b3db57dcad",
"880554b7a0404dca997ce1d94da9c97f",
"f580ddc5778649c2be1648cfdefe1b61",
"b31241c7e9d341e7a61483d9aa47c898",
"3a78b7b56320489aabb947d86b933f0c",
"946da7977691449ca379b06a315334d5",
"9b5c5c479edc49579fb61c406aea54bd",
"80768bfd36b045fcaaf026d7047e3a44",
"184e6a7917b14c6eb8edcf03288940f9",
"225ad10f0d1048bba62990287fdb8f76",
"a958a8da218a4a8b9ade2f643d293a78",
"45e72108de31456a909f038b2e7487c3",
"098cadbfe744497f91f54ad42c38f3b7",
"b3642d7f5e8c48e7a1fb39822f1d1c2d",
"588d0237a1774ab494c46ec13b7ab578",
"9f734da521f74696a51e6ecf1420823f",
"b56d4ded73cf4630afd9b6cbde49e0d5",
"4f6b296e5ae2415592250b60d10a4a24",
"f714e4af7d91463a8a228ede9a7f18c1",
"2f583b4ef0bd47628b9145ef7f60e387",
"a4b3af280d9845e291e621eafc51ab8c",
"ce663a1b3d7c4d11ab52b813cb0a0f3a",
"3b14dd425ff645c3a3b2f757e74990ef",
"5c32940ce356438da6ec2bd7f42e7d47",
"ebb47d7a41e3488cb7d7278497d8ee8c",
"c9675199f6fb4fd3b28d49827299409c",
"b5a4f9ddbf1a4dd9999c208261bde0ad"
]
},
"id": "F7RpE_7PzHIV",
"outputId": "05315c69-eb1d-4204-bd4c-9ad31fc64dd2"
},
"outputs": [],
"source": [
"import torch\n",
"\n",
"llm = HuggingFaceLLM(\n",
" context_window=4096,\n",
" max_new_tokens=256,\n",
" generate_kwargs={\"temperature\": 0.7, \"do_sample\": False},\n",
" system_prompt=system_prompt,\n",
" query_wrapper_prompt=query_wrapper_prompt,\n",
" tokenizer_name=\"mistralai/Mistral-7B-Instruct-v0.1\",\n",
" model_name=\"mistralai/Mistral-7B-Instruct-v0.1\",\n",
" device_map=\"auto\",\n",
" stopping_ids=[50278, 50279, 50277, 1, 0],\n",
" tokenizer_kwargs={\"max_length\": 4096},\n",
" # uncomment this if using CUDA to reduce memory usage\n",
" model_kwargs={\"torch_dtype\": torch.float16}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "FjgUy4py0aGU",
"outputId": "e35875f7-609d-4eb3-81d4-07fbc080199a"
},
"outputs": [],
"source": [
"%pip install llama-index-embeddings-huggingface\n",
"%pip install llama-index-embeddings-instructor"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 369,
"referenced_widgets": [
"b374c20dc50e4850857b31dbad215cf1",
"9a1c114114f04a4abbc9f163a0804f7a",
"fc3ea5e27b974c51a7a5c6971474b5fb",
"4f282fc21c1340148e43a3b56f0e8fc0",
"d2649cc4517f4af9a23277131fa64a5a",
"70238250c0684cdca666a931596c6dde",
"f76ebed4482744eea4521c6250a867dd",
"6140734d619e46018982df0fe5a7bb86",
"f72a1a9f8cd845ea94587b6f6fab5474",
"84c5417bada246d8b26122b4a76db143",
"bd7eda890cd94ea9b5b5dfd23508b220",
"ee5b6806f1fc491fbbe8bd6a5457f229",
"92db8f39ebbc433896abb720a3324753",
"e4450c44e4f84531a80a94a356c0094f",
"ebdd0568585c4731865a2ac85ec677ee",
"7ae45bc5a20b496da43a3d74c4eccee4",
"e71c56df2aab4e208badc5b0225f3796",
"0855dce963744867924d027baad24c4c",
"e829a83fe16545f09deccafab0cec555",
"a27b123120ce4238ab8f44e04dcb9595",
"34b54e53fe314dfe8d5db61b927eee79",
"3d10cb8d75954abc88868d7cbbf3d4c9",
"6ac493552765456a903f531f421740e2",
"d6bf34f7d3764d65bd296a29be4763ec",
"c9650e654e16421ba3c565b2d16fde4e",
"2fb0a9256f7045829c1685aeb5e88010",
"1ef32d22d4524c21b990e261e9dc9a41",
"d81fd21044d24fb09f4b288a4f005525",
"64d9c7dabbaa45fc8164f7d95a0db63d",
"3b0e122de9a64dfd8849d16864a1e8dc",
"03a32c88fe8c49c6b178ea0bd17bcca8",
"d56321d81f574c248134b6a697e52982",
"4f59356e38e14dc19cac4292183ca035",
"e0f873a9077f4375ad68e52b87e689ff",
"7888f27f6c8b416ba66945ba108b94e9",
"fd85bfbe602344bfb1a8a2e4d65b8e48",
"82601baaec594014822c0d5b15b922e5",
"89cb8953aaf844b69829754affbbe02f",
"b89a7d6a6d15479fb0010a8a27094df8",
"e0f24e6310e640bbbbb24585d32de2de",
"84519662745849d19b56973752f0e0f6",
"077b75340d484d348f30b2087963b3ad",
"61cc455588a0412f909f93f549d905cc",
"058abc0d7d8b4c18afe8a52b88186af3",
"6d22979dddfe4a79a18444ac17533e5c",
"79ed361591b9419cbea46987d5a54c89",
"96890db6d3cb4ff1967baeecf66cc21d",
"882cd564839d474f8da666f9706cb5b2",
"d8d54ea71ee7470687fb24b21a4280b3",
"df51d71be5c74703b00383c39b27a999",
"fe6fcc6691034b42bd9851d36ac664cf",
"a6a5f2d7bb26485cac86ec5ba3306ae8",
"2774719aa3b44699a21d63824f48e087",
"bfe1515c12f74d69a4f2ef0095faf929",
"27ba43b61b8f4142a09f58e96e224fbd",
"1c08c7dee27c49c2b9928dfb995aab8d",
"0921f03f08d44083b6f4fa7d228cb12a",
"7f9e0bf6f2aa4f5a8f074f4618ce14fa",
"03f15f89737c4bf2899fea40abd4f57f",
"e033814b8576426c8c129bb0cc7d5989",
"5af78e959b904d2a8d674ff0f50cafc2",
"378145700f0e40ebb2c69c3a2bb6cc75",
"da426d0e899c49e6ae78efac337a256d",
"037e87bc8039471c88175b65c98f8462",
"a23cd24e713a49abacb2beea0c49db4d",
"7f138e0339a2497a982177e146d9b778",
"d773fd1010e54c1290965df31f45c57a",
"9b4f9d70e14448db901592b1cd2c808f",
"040d315fbe5f46cfaa3b56be7199a9e0",
"ecb43e36f20a49859bc7695bb4a21089",
"cbc9f166ccbc4f169112ef848bdf2cdf",
"4c6fb5207f6a4e36bc73acb94c761080",
"d89c07fb26db4783931c37c0c76917cb",
"82e0a7d44ddd4a26b44e374de4af4ae9",
"bda3531228994266aafda2501676ae4d",
"e3394b0da30f4e758059711db0ed665f",
"3511d760002d4d68a424b00724c363f6",
"30d7f94a0bb8465b85a5f297095d6745",
"b1d1b6c881284bd69b74121fc24620ca",
"b2ac29c1fb614df4ab71afb8bada8f1e",
"33f9b51d2cba4e0585ccc9e6a2781dd2",
"df1348af99a74a0ebe1203202475461b",
"37a415f6e70b47449a76a6bce1030031",
"caa295fb977d4017b4524c0fbf343c7d",
"cbae3ab46e4b4019b51071836917f301",
"63c27f553f1449a9b21cbe944426bfef",
"54916166e38c433a998808b638d88840",
"79255c6e47ca40a2ad1c2bd037ab649e",
"e746226ce13f4875b81dbc746997ad84",
"7e7b314134614b9d96a3c9f95a742c25",
"d67e9a5c64634e759d571b7774d204b6",
"90c4de7de9e2435ca36f5a4960b15fbb",
"99b9da0ac0cd4919b715c19f7465af67",
"ef5bde446e8142818ec57969144cd6b2",
"e14d67be717a4f9587643dd4af32c345",
"b682fbc3e6c849e2ac70934f52028323",
"d389de267d0b4ac5a3555714f1cfe80b",
"83c26a9b20444f26b60776ece61f69b2",
"ddf58aa133254cd3b95f31ccaf08b880",
"8edffee4a0f3481ea460c50721cc13e5",
"db1c6b1f0cfe4c598caf741168068f25",
"6af1bee1967a40b89f8cfbd2687d96f9",
"15d13e6b1fba4ddabe0f5bbe5988bd94",
"da98dc04099a4786b2f8f6232fd7c4c6",
"d40e5726111a403c9101820dd1ab12c4",
"9d1b889b5d3044a680075411a4970a7e",
"933559963a5242a4943dadefca235ada",
"b5d7a637707d48918217a68eeb8c4163",
"dd2a965527ae449f88696fe8a1e07a3e",
"d0893bc09aaf4bc88f5045ad0c3430b9",
"25b636ca56bb4ceb9f8125899ee00297",
"165bac09663343c38c5e73c4d2494090",
"ce8a9d6496c04350a209c55f2b4cd37f",
"fb0ef984cde04b8e92c5fa41c59d3663",
"61a2a20be6b64e8782237c6167d89745",
"65d1cdaeb86d4f2c91d5f3cede8a24f4",
"d277f862ebb24112b16a53e3ae2282b8",
"cb7a4d55396743dfa0895cac3c4fd87a",
"68eb1154ac74496786e34b767ccdee66",
"83ac4442dc4d4b88b8ffdac2564fffdb",
"49d914e1fd794ed9835c74227fb345f8"
]
},
"id": "C6-l096Z06Zf",
"outputId": "5d8daa0d-33eb-493d-a362-f2f2f37ef73e"
},
"outputs": [],
"source": [
"from llama_index.embeddings.huggingface import HuggingFaceEmbedding\n",
"embed_model =HuggingFaceEmbedding(model_name=\"sentence-transformers/all-mpnet-base-v2\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "4SiB7uf11quG"
},
"source": [
"https://github.com/run-llama/llama_index/blob/main/llama-index-core/llama_index/core/service_context.py"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "S-HVDRiW1R6V",
"outputId": "34c9f625-a563-4ec9-c4d4-95696a1699d3"
},
"outputs": [],
"source": [
"from llama_index.core import VectorStoreIndex, ServiceContext\n",
"\n",
"service_context = ServiceContext.from_defaults(\n",
" chunk_size=1024,\n",
" llm=llm,\n",
" embed_model=embed_model\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cpkAB41D1sxN"
},
"outputs": [],
"source": [
"index = VectorStoreIndex.from_documents(documents, service_context=service_context)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ueC80L6422mV"
},
"outputs": [],
"source": [
"query_engine = index.as_query_engine()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "WdHRSPfZ29fN",
"outputId": "c2f8b40b-6a8e-4b38-eeea-73340b495fb0"
},
"outputs": [],
"source": [
"query_engine.query(\"what is attention?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "s5mHS65_3HGd",
"outputId": "de5e6184-feea-405b-8296-0d7f818cdd3c"
},
"outputs": [],
"source": [
"query_engine.query(\"how attention is different from rnn and lstm\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IfBLY3pm3Pnf"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: RAG App using Langchain Mistral Weaviate/RAG_Application_Using_LangChain_Mistral_and_Weviate.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "y7z6_whzm23H",
"outputId": "383384d8-de22-424b-8a23-a2c2e57009a1"
},
"outputs": [],
"source": [
"!pip install weaviate-client langchain tiktoken pypdf rapidocr-onnxruntime"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TA6SWl0KnV_E"
},
"outputs": [],
"source": [
"WEAVIATE_CLUSTER=\"https://mylangchainproject-z88ava1x.weaviate.network\"\n",
"WEAVIATE_API_KEY=\"\" # Add your Weaviate API key here"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NjSE_cFAnvuA"
},
"outputs": [],
"source": [
"from langchain.vectorstores import Weaviate\n",
"import weaviate\n",
"\n",
"WEAVIATE_URL = WEAVIATE_CLUSTER\n",
"WEAVIATE_API_KEY = WEAVIATE_API_KEY\n",
"\n",
"client = weaviate.Client(\n",
" url=WEAVIATE_URL, auth_client_secret=weaviate.AuthApiKey(WEAVIATE_API_KEY)\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UiPYOR0EocFe"
},
"outputs": [],
"source": [
"# fixing unicode error in google colab\n",
"import locale\n",
"locale.getpreferredencoding = lambda: \"UTF-8\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "aYyME3XbqnBL",
"outputId": "23723780-f312-47bc-ac5a-f7c957d1a16e"
},
"outputs": [],
"source": [
"!pip install sentence-transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 493,
"referenced_widgets": [
"e84b2a9a1740434fb6b8861efb3312af",
"4dbdf69df7ee48f0b7b6f62085a4336e",
"fca9e2fe67b4497b823b5134fea5a736",
"26a1c028d889456e803598e1531fefaa",
"4a903db9cd3c490fbddbdfee0db4cc47",
"616d99ddbe18408db18a85c37625014d",
"3329c6debbcc456a99f82b43eb1d9dce",
"fe97ceb98d1e4c22ac386549564ba2f6",
"cbf51dc4ebfc4962b7f23f277d7e20d4",
"2633fe257e3240efb020d512e0647381",
"6a07e94c3b35489cbb06f6c78f0a3059",
"d49fde6298f142ec844387f4a302f320",
"ce8873428ece4d0d9215927f1300e1d9",
"cf5d5061460a4a7ea0608e6ddc2175a4",
"7889413ec63f49e08d84fbf2c44725d8",
"0e429fce0f6c48f799e6c5dda3d650da",
"45ef437c64814da993620e391796cdd9",
"d3a0df6679c54a51ae76171bfb97d5fe",
"3d2707ff05824a5fbbd95bb637db838d",
"5a0080ac33dc4714a78c11a41310277c",
"381d72f3ad754726b2bb4fe38fdfc14d",
"b9cd0e64b9d64fd796706033e7c76c20",
"0bc5f0065f7d427894e04e804f870d1f",
"0790ed27ffc64a30b233ffd99c887832",
"a1fff71f64c24670b2b3de5096a604e9",
"43fdafe04ec94cfa90949e13bada9af8",
"a3f9dfc42a9545e7b5473a3e4d46cdc1",
"bbed2678a37e4d1da8217a027f3a5276",
"8271c13521a14558ad1e56c56ace3a37",
"b4b124405a274a6db38806cb4cff8de9",
"907d9d117fa649aa8fdc6c73252286f1",
"7d0011068c424329add6961d52760115",
"eb198933e6824c32b855bd106e1ec49f",
"5643a8a739f949ecbb5a31a7ef7d7be2",
"701d231d3aab4940937c87eda8e061ff",
"0e177c2d9b83416bb6100ac385a04929",
"d7ebe401f50a438d9f55c8eec19c017b",
"e32511c27cc04f049d8221d8291c74ca",
"26b1c7172626484e9e275cd17ad75038",
"8c517421a26d447081172c7b2c338068",
"739aad34e5e04f9e997f7a481c1c740d",
"6f92013ea1924f739d0c6552ba0ac362",
"804631e6b9cf480bb3a06036e6349beb",
"d9a945d711ff4afc8cdab8155fab2f3f",
"d2fc565185c443a8a6e9401f700c4178",
"8cb855c39f254c15bafe1cecf9e0379a",
"3f1981d29c804593969405b5bef1895c",
"7bccbc4904ed4bf79427274c9098bf2f",
"e37147192a1644ad8ab5dcbcfd8c4cb5",
"1922cc6d1cee4e2cb3d9c20df7fe8c96",
"2ee34c5f27c345e682681540f1f1aa10",
"fe609465091b45e2be9dd56b084b9ceb",
"46a967e072ad4a0d97b4fa3ae0cc9fdc",
"e014290748294aba9929c98e9dc2a2f9",
"a77907217a6340a3a8fccad5976de4f1",
"0a04b7d000234b7dbd6da536740e0ccd",
"6bfc56f6c2e54095b0ef0d3b6bd5778d",
"6cf453f3a54446808ce2cd0b6e472031",
"b0c1a600ea594da093b6609e96dcedb5",
"8902e2d51915467fa85b73b277650ad4",
"46a022889a0c4f4898720027dccc537e",
"89c04c6a67584f40b49632989a8afe45",
"07bfb5ef68004a229299d621d8743811",
"cb72f7924dad4bcf88acf339cdc317eb",
"fbe9a4b0a015460a8edd80e8ed17f9d1",
"f266974305af4d269c1657a9fbf4e026",
"ee79b8d34e9147bb8a98a3c3595cba89",
"ef9f53eddff2406898d22f4f7e11d0b7",
"944e43e1d8184fb3839f2a36e2249e34",
"49ec7c8b25f24ba9823d4df8452ea873",
"b1f26085277f4958b6204a9477d45ba1",
"d810e614b09644468a77e45865a61eaa",
"9db9bf5dfcbb4c7b8e505220fc8ded76",
"a6fc52b6bc924ec69adfa035bde09617",
"623465c9c926493595d5cc090c956f82",
"d592b7b6baaa478986fd01b27f2e94e1",
"190e44d1036b4eecb7dbfbffaf0c1ec2",
"d506e084a29d40f39d64cf0822c801d7",
"198ab2f45ed341a19f817c3020785906",
"dd36a78b619844da9753fcfdb552c479",
"31aea98379fd407caf515cb2900adbbd",
"95221e2d2e064c93a4bee68e76b70df3",
"1218d786f4644e659527780a57013a5a",
"865c84e6337149bc95ceffea04c54a5f",
"87c2c4b80fe542acb461ebc8f5f72e0f",
"89dfeeb9b40240968210e5b51d3d63ff",
"e6cd47c0f8024ea7b868daca3e71e795",
"553cce0be8694d6f9b703a60084e61d9",
"5b6e93ec87b34053985cb04e88f616e2",
"d4cd5aaf4f504e7d9e1e64c09647af27",
"404092a77b6040cdba69c354d812ab83",
"d208f427da784f8ea66cf557b0983ea3",
"d079490dfeb64dada549e0284d32fe23",
"382e20255f6a4421bcdb31453ff80336",
"dba3379c1cd1418b9897f80ad82b0c3f",
"c9251c439ddb4ef58f1d916a75df282d",
"281400a864c44df288cafae32c39986a",
"b763b331a780410489c5c5be443eea1a",
"62f1dc6f8f1f461495e9ed551694179e",
"53e061c920a946f18f9a7ccb75780a45",
"9ab93b923e8042ed87610a67654169d5",
"cf32c7a599f6453296962d6ea0d4dfb6",
"a16de14019eb47d98a7e4a6e6d377dad",
"b719bfd43eb9421a8b2b89102ccb9b39",
"3bb282017aaf41798b6938cd4bbf13c5",
"ce594d2f0dc44470b017997a98742589",
"bc3bfa5ee2194ed9ae640662006d11a0",
"31861bb5717045d09a500f088de105f9",
"52eea7d6153846f495ff104d1e4a7967",
"f094f5dab603420790b1b016fccb0d49",
"926b7aa7a8c843c1a7677db4ac1e4d21",
"0bfe4459cc0d45f78576e657e408fbeb",
"74eba064d1f347ba830d0aa3e29a38c0",
"8889a72dde804679863d6204ad275e5e",
"f4e04d7a1e144831bbdb358ca2b526fd",
"c43664b349aa4ff9a9e607cc348a30b5",
"6560f016bbb04bf9b4844ea1c7445c9c",
"d4a9fc50fed04255974951c405ed0917",
"ccaae9ce3b8e4f479598d0a3de81ca8f",
"e04d055c328342f6b0cf9ee679400125",
"fb4f5bf291cc4d01b5422953452b9bc6"
]
},
"id": "oLyzB1XMojKG",
"outputId": "021d83d8-b77a-4863-ceaa-5c88df1d0b7a"
},
"outputs": [],
"source": [
"# specify embedding model (using huggingface sentence transformer)\n",
"from langchain.embeddings import HuggingFaceEmbeddings\n",
"embedding_model_name = \"sentence-transformers/all-mpnet-base-v2\"\n",
"#model_kwargs = {\"device\": \"cuda\"}\n",
"embeddings = HuggingFaceEmbeddings(\n",
" model_name=embedding_model_name,\n",
" #model_kwargs=model_kwargs\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "WHwqV_H6pFqW"
},
"source": [
"# you can load multiple types of pdf using the langchain just check with the document\n",
"\n",
"https://python.langchain.com/docs/modules/data_connection/document_loaders/pdf/"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0-YiQTCmo74-"
},
"outputs": [],
"source": [
"from langchain.document_loaders import PyPDFLoader\n",
"loader = PyPDFLoader(\"/content/RAG.pdf\", extract_images=True)\n",
"pages = loader.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "18DG7rJtqEsV",
"outputId": "30dd8c4b-eba7-4653-df4e-f58d1c5ad11a"
},
"outputs": [],
"source": [
"pages"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "o3ynVE9IqLry"
},
"outputs": [],
"source": [
"# Split text into chunks\n",
"from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
"text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=20)\n",
"docs = text_splitter.split_documents(pages)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "eW1VQ-TrscRo",
"outputId": "72f6ce94-1f60-440f-cb08-139a05ec6f51"
},
"outputs": [],
"source": [
"docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zluFUYQ3sdxX"
},
"outputs": [],
"source": [
"vector_db = Weaviate.from_documents(\n",
" docs, embeddings, client=client, by_text=False\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Y8qLjlXYtoFk",
"outputId": "692c1514-012b-4383-86a5-1deb43deb3a6"
},
"outputs": [],
"source": [
"print(vector_db.similarity_search(\"what is rag?\", k=3)[0].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "vVj7MAw-uE9B",
"outputId": "01f81a6b-7026-4e69-a8b3-18ec57339249"
},
"outputs": [],
"source": [
"print(vector_db.similarity_search(\"what is rag?\", k=3)[1].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6oudP8LruHJj",
"outputId": "11bb882b-4a28-470f-a552-a80084319830"
},
"outputs": [],
"source": [
"print(vector_db.similarity_search(\"what is rag?\", k=3)[2].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "dsvgQsH2tgvT",
"outputId": "38d1fa3c-eebf-490e-c7e2-e9c6d1d521ad"
},
"outputs": [],
"source": [
"print(\n",
" vector_db.similarity_search(\n",
" \"what is attention?\", k=3)\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "r-iUy_kqs3sz"
},
"outputs": [],
"source": [
"from langchain.prompts import ChatPromptTemplate\n",
"\n",
"template=\"\"\"You are an assistant for question-answering tasks.\n",
"Use the following pieces of retrieved context to answer the question.\n",
"If you don't know the answer, just say that you don't know.\n",
"Use ten sentences maximum and keep the answer concise.\n",
"Question: {question}\n",
"Context: {context}\n",
"Answer:\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IPQkyjuXuTJH"
},
"outputs": [],
"source": [
"prompt=ChatPromptTemplate.from_template(template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tuwzW99bucki",
"outputId": "b8cda52e-6d01-474b-a808-37ffa380262f"
},
"outputs": [],
"source": [
"prompt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AlFnn-9GueFz"
},
"outputs": [],
"source": [
"from langchain import HuggingFaceHub"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fhJ2KAlivPFH"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"huggingfacehub_api_token=userdata.get('HuGGINGFACE_TOKEN')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "inS4srvcvAy8",
"outputId": "4347ebb3-72c9-407d-e528-aa2fcac781ec"
},
"outputs": [],
"source": [
"model = HuggingFaceHub(\n",
" huggingfacehub_api_token=huggingfacehub_api_token,\n",
" repo_id=\"mistralai/Mistral-7B-Instruct-v0.1\",\n",
" model_kwargs={\"temperature\":1, \"max_length\":180}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0OOsmfqkve6T"
},
"outputs": [],
"source": [
"from langchain.schema.runnable import RunnablePassthrough\n",
"from langchain.schema.output_parser import StrOutputParser"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qHwkkEyfvtlr"
},
"outputs": [],
"source": [
"output_parser=StrOutputParser()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "I18V6AE4v359"
},
"outputs": [],
"source": [
"retriever=vector_db.as_retriever()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XgIZfslPvlDu"
},
"outputs": [],
"source": [
"rag_chain = (\n",
" {\"context\": retriever, \"question\": RunnablePassthrough()}\n",
" | prompt\n",
" | model\n",
" | output_parser\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1oVtr-_5vmAG",
"outputId": "a4b5c919-f850-4a9a-a760-3b92468068e1"
},
"outputs": [],
"source": [
"print(rag_chain.invoke(\"what is rag system?\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XQbbKG2FvpNB",
"outputId": "acf66b66-d104-430a-d8a2-7a3a0c4aa28c"
},
"outputs": [],
"source": [
"print(rag_chain.invoke(\"How does the RAG model differ from traditional language generation models?\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gHjbemJtwmpq"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: RAG App using Langchain OpenAI FAISS/RAG_Application_using_Langchain_OpenAI_API_and_FAISS.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "6JUkLoO0l9RC"
},
"source": [
"#What is the RAG system?\n",
"\n",
"## Defination:\n",
"\n",
"This is called retrieval augmented generation (RAG), as you would retrieve the relevant data and use it as augmented context for the LLM. Instead of relying solely on knowledge derived from the training data, a RAG workflow pulls relevant information and connects static LLMs with real-time data retrieval.\n",
"\n",
"## Architecture:\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "hR_g22LnmCQP"
},
"source": [
"## Why we create a RAG System?\n",
"\n",
"Retrieval systems (RAG) give LLM systems access to factual, access-controlled, timely information.\n",
"\n",
"1. RAG REDUCES HALLUCINATION\n",
"\n",
"Example: In the financial services industry, providing accurate information on investment options is crucial because it directly impacts customers' purchasing decisions and financial well-being. RAG can help ensure that the information generated about stocks, bonds, or mutual funds\n",
"\n",
"2. COST-EFFECTIVE ALTERNATIVE\n",
"\n",
"Example: Banks often need to assess the creditworthiness of potential borrowers. Fine-tuning pre-trained language models to analyse credit histories can be resource-intensive. RAG architecture offers a cost-effective alternative by retrieving relevant financial data and credit history information from existing databases, combining this with pre-trained language models\n",
"\n",
"3. CREDIBLE AND ACCURATE RESPONSES\n",
"\n",
"Example: In customer support, providing accurate and helpful responses is essential for maintaining customer trust, as it demonstrates the company's commitment to providing reliable information and support. The RAG technique is able to do this very effectively by retrieving data from catalogues, policies, and past customer interactions to generate context-aware insights, ensuring that customers receive reliable information on product features, returns, and other inquiries.\n",
"\n",
"4. DOMAIN-SPECIFIC INFORMATION\n",
"\n",
"Example: In the legal industry, clients often require advice specific to their case or jurisdiction because different legal systems have unique rules and regulations, and understanding these nuances is crucial for effective legal representation. RAG can access domain-specific knowledge bases, such as local statutes and case law, to provide tailored information relevant to clients' legal needs.\n",
"\n",
"https://www.advancinganalytics.co.uk/blog/2023/11/7/10-reasons-why-you-need-to-implement-rag-a-game-changer-in-ai\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "8WZp8J48mB68"
},
"source": [
"# RAG Practical Usecase\n",
"\n",
"1. Document Question Answering Systems\n",
"2. Conversational agents\n",
"3. Real-time Event Commentary\n",
"4. Content Generation\n",
"5. Personalised Recommendation\n",
"6. Virtual Assistants"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "R-fUCj0KmJGX"
},
"source": [
"## Installing the necessary libraries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "zD4C31_TmFbY",
"outputId": "5c332332-d246-4bab-c1e2-83534c8c2ac4"
},
"outputs": [],
"source": [
"!pip install langchain openai tiktoken rapidocr-onnxruntime"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "gJ4mHOgxmIu_"
},
"source": [
"## Fetching OpenAI API key"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "jmGu5Lr-mPZG"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "6TN6ZHo-uaWd"
},
"source": [
"## Setting Enviornment Variable"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "phbDr1pcuWl7"
},
"outputs": [],
"source": [
"import os\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "oYPoOcMVutNQ"
},
"source": [
"1. Data Ingestion\n",
"2. Data Reterival\n",
"3. Data Generation"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "cVSNQSzju1se"
},
"source": [
"# Data Ingestion\n",
"\n",
"https://en.wikipedia.org/wiki/State_of_the_Union#:~:text=Though%20the%20language%20of%20the,as%20late%20as%20March%207"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TOkAHEuRu0jg"
},
"outputs": [],
"source": [
"from langchain.document_loaders import TextLoader\n",
"from langchain.vectorstores import FAISS"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PPqWneqdvy_o"
},
"outputs": [],
"source": [
"with open(\"state_of_the_union.txt\",\"r\", encoding=\"utf8\") as f:\n",
" data = f.read()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "muXK-ABgv6vY"
},
"outputs": [],
"source": [
"loder=TextLoader('state_of_the_union.txt', encoding=\"utf8\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LHt7Z4ZjwP03"
},
"outputs": [],
"source": [
"document=loder.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "iCTmsK8KwW7H",
"outputId": "4cb9de6f-6ced-4de8-c358-35bb5ab700f9"
},
"outputs": [],
"source": [
"print(document[0].page_content)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Bi-WS695wvpq"
},
"source": [
"# Chunking of the Data"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "djfRyVb8xVjR"
},
"source": [
"# Here is all the text splitter which is available in Langchain\n",
"\n",
"https://python.langchain.com/docs/how_to/#text-splitters\n",
"\n",
"## CharacterTextSplitter v/s RecursiveCharacterTextSplitter\n",
"\n",
"## you can visualise the chunking also\n",
"\n",
"https://chunkviz.up.railway.app/\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1-SEIxghwYTX"
},
"outputs": [],
"source": [
"from langchain.text_splitter import RecursiveCharacterTextSplitter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hmdC_UTaw104"
},
"outputs": [],
"source": [
"text_splitter=RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=50)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cmEcfiNOykdA"
},
"outputs": [],
"source": [
"text_chunks=text_splitter.split_documents(document)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ME1HhJytzQou",
"outputId": "00d9f9bf-93e2-458d-8753-153ba49b540f"
},
"outputs": [],
"source": [
"text_chunks"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "_jW9bahwyrpF",
"outputId": "d04660f4-002d-4dca-c0fb-2721f729c451"
},
"outputs": [],
"source": [
"print(text_chunks[3].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Ur_SVI_CzWFw"
},
"outputs": [],
"source": [
"from langchain.embeddings import OpenAIEmbeddings\n",
"from langchain.vectorstores import FAISS"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7v6pC9yrzmBA",
"outputId": "da9de162-bbbf-4fd1-9dcf-038637a841ef"
},
"outputs": [],
"source": [
"embeddings=OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "K1z0Nqe8z1B3",
"outputId": "e204d916-da6a-4d6a-bc9b-c91ab94af523"
},
"outputs": [],
"source": [
"!pip install faiss-cpu"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zl-jy02QzrJ7"
},
"outputs": [],
"source": [
"vectorstore=FAISS.from_documents(text_chunks, embeddings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YQGI-QvHzyhp"
},
"outputs": [],
"source": [
"retriever=vectorstore.as_retriever()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "W3fHisQz0XSn"
},
"outputs": [],
"source": [
"from langchain.prompts import ChatPromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "i79AEhET0rJY"
},
"outputs": [],
"source": [
"template=\"\"\"You are an assistant for question-answering tasks.\n",
"Use the following pieces of retrieved context to answer the question.\n",
"If you don't know the answer, just say that you don't know.\n",
"Use ten sentences maximum and keep the answer concise.\n",
"Question: {question}\n",
"Context: {context}\n",
"Answer:\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XjPxHyCq0xNB"
},
"outputs": [],
"source": [
"prompt=ChatPromptTemplate.from_template(template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1jDm8miC0zCY"
},
"outputs": [],
"source": [
"from langchain.chat_models import ChatOpenAI\n",
"from langchain.schema.runnable import RunnablePassthrough\n",
"from langchain.schema.output_parser import StrOutputParser"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NGR2XWLh1t9S"
},
"outputs": [],
"source": [
"output_parser=StrOutputParser()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "yMCDVqyM1Ma2",
"outputId": "a68041b0-c5f1-4e9a-99d1-3d3a19ab6c66"
},
"outputs": [],
"source": [
"llm_model=ChatOpenAI(openai_api_key=OPENAI_API_KEY,model_name=\"gpt-3.5-turbo\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "FJjxzAZn1p6-"
},
"outputs": [],
"source": [
"rag_chain = (\n",
" {\"context\": retriever, \"question\": RunnablePassthrough()}\n",
" | prompt\n",
" | llm_model\n",
" | output_parser\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 157
},
"id": "pr1POQp02Kmo",
"outputId": "add0bf05-9483-4063-fe06-6af3d34a2638"
},
"outputs": [],
"source": [
"rag_chain.invoke(\"How is the United States supporting Ukraine economically and militarily?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 157
},
"id": "ekErMhoI2wtZ",
"outputId": "f5cafd34-d185-404f-c4ef-218b4e25458a"
},
"outputs": [],
"source": [
"rag_chain.invoke(\"What action is the U.S. taking to address rising gas prices?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "smZhFGIe3EB6"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: RAG App using Langchain OpenAI FAISS/state_of_the_union.txt
================================================
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.
Last year COVID-19 kept us apart. This year we are finally together again.
Tonight, we meet as Democrats Republicans and Independents. But most importantly as Americans.
With a duty to one another to the American people to the Constitution.
And with an unwavering resolve that freedom will always triumph over tyranny.
Six days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways. But he badly miscalculated.
He thought he could roll into Ukraine and the world would roll over. Instead he met a wall of strength he never imagined.
He met the Ukrainian people.
From President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world.
Groups of citizens blocking tanks with their bodies. Everyone from students to retirees teachers turned soldiers defending their homeland.
In this struggle as President Zelenskyy said in his speech to the European Parliament “Light will win over darkness.” The Ukrainian Ambassador to the United States is here tonight.
Let each of us here tonight in this Chamber send an unmistakable signal to Ukraine and to the world.
Please rise if you are able and show that, Yes, we the United States of America stand with the Ukrainian people.
Throughout our history we’ve learned this lesson when dictators do not pay a price for their aggression they cause more chaos.
They keep moving.
And the costs and the threats to America and the world keep rising.
That’s why the NATO Alliance was created to secure peace and stability in Europe after World War 2.
The United States is a member along with 29 other nations.
It matters. American diplomacy matters. American resolve matters.
Putin’s latest attack on Ukraine was premeditated and unprovoked.
He rejected repeated efforts at diplomacy.
He thought the West and NATO wouldn’t respond. And he thought he could divide us at home. Putin was wrong. We were ready. Here is what we did.
We prepared extensively and carefully.
We spent months building a coalition of other freedom-loving nations from Europe and the Americas to Asia and Africa to confront Putin.
I spent countless hours unifying our European allies. We shared with the world in advance what we knew Putin was planning and precisely how he would try to falsely justify his aggression.
We countered Russia’s lies with truth.
And now that he has acted the free world is holding him accountable.
Along with twenty-seven members of the European Union including France, Germany, Italy, as well as countries like the United Kingdom, Canada, Japan, Korea, Australia, New Zealand, and many others, even Switzerland.
We are inflicting pain on Russia and supporting the people of Ukraine. Putin is now isolated from the world more than ever.
Together with our allies –we are right now enforcing powerful economic sanctions.
We are cutting off Russia’s largest banks from the international financial system.
Preventing Russia’s central bank from defending the Russian Ruble making Putin’s $630 Billion “war fund” worthless.
We are choking off Russia’s access to technology that will sap its economic strength and weaken its military for years to come.
Tonight I say to the Russian oligarchs and corrupt leaders who have bilked billions of dollars off this violent regime no more.
The U.S. Department of Justice is assembling a dedicated task force to go after the crimes of Russian oligarchs.
We are joining with our European allies to find and seize your yachts your luxury apartments your private jets. We are coming for your ill-begotten gains.
And tonight I am announcing that we will join our allies in closing off American air space to all Russian flights – further isolating Russia – and adding an additional squeeze –on their economy. The Ruble has lost 30% of its value.
The Russian stock market has lost 40% of its value and trading remains suspended. Russia’s economy is reeling and Putin alone is to blame.
Together with our allies we are providing support to the Ukrainians in their fight for freedom. Military assistance. Economic assistance. Humanitarian assistance.
We are giving more than $1 Billion in direct assistance to Ukraine.
And we will continue to aid the Ukrainian people as they defend their country and to help ease their suffering.
Let me be clear, our forces are not engaged and will not engage in conflict with Russian forces in Ukraine.
Our forces are not going to Europe to fight in Ukraine, but to defend our NATO Allies – in the event that Putin decides to keep moving west.
For that purpose we’ve mobilized American ground forces, air squadrons, and ship deployments to protect NATO countries including Poland, Romania, Latvia, Lithuania, and Estonia.
As I have made crystal clear the United States and our Allies will defend every inch of territory of NATO countries with the full force of our collective power.
And we remain clear-eyed. The Ukrainians are fighting back with pure courage. But the next few days weeks, months, will be hard on them.
Putin has unleashed violence and chaos. But while he may make gains on the battlefield – he will pay a continuing high price over the long run.
And a proud Ukrainian people, who have known 30 years of independence, have repeatedly shown that they will not tolerate anyone who tries to take their country backwards.
To all Americans, I will be honest with you, as I’ve always promised. A Russian dictator, invading a foreign country, has costs around the world.
And I’m taking robust action to make sure the pain of our sanctions is targeted at Russia’s economy. And I will use every tool at our disposal to protect American businesses and consumers.
Tonight, I can announce that the United States has worked with 30 other countries to release 60 Million barrels of oil from reserves around the world.
America will lead that effort, releasing 30 Million barrels from our own Strategic Petroleum Reserve. And we stand ready to do more if necessary, unified with our allies.
These steps will help blunt gas prices here at home. And I know the news about what’s happening can seem alarming.
But I want you to know that we are going to be okay.
When the history of this era is written Putin’s war on Ukraine will have left Russia weaker and the rest of the world stronger.
While it shouldn’t have taken something so terrible for people around the world to see what’s at stake now everyone sees it clearly.
We see the unity among leaders of nations and a more unified Europe a more unified West. And we see unity among the people who are gathering in cities in large crowds around the world even in Russia to demonstrate their support for Ukraine.
In the battle between democracy and autocracy, democracies are rising to the moment, and the world is clearly choosing the side of peace and security.
This is a real test. It’s going to take time. So let us continue to draw inspiration from the iron will of the Ukrainian people.
To our fellow Ukrainian Americans who forge a deep bond that connects our two nations we stand with you.
Putin may circle Kyiv with tanks, but he will never gain the hearts and souls of the Ukrainian people.
He will never extinguish their love of freedom. He will never weaken the resolve of the free world.
We meet tonight in an America that has lived through two of the hardest years this nation has ever faced.
The pandemic has been punishing.
And so many families are living paycheck to paycheck, struggling to keep up with the rising cost of food, gas, housing, and so much more.
I understand.
I remember when my Dad had to leave our home in Scranton, Pennsylvania to find work. I grew up in a family where if the price of food went up, you felt it.
That’s why one of the first things I did as President was fight to pass the American Rescue Plan.
Because people were hurting. We needed to act, and we did.
Few pieces of legislation have done more in a critical moment in our history to lift us out of crisis.
It fueled our efforts to vaccinate the nation and combat COVID-19. It delivered immediate economic relief for tens of millions of Americans.
Helped put food on their table, keep a roof over their heads, and cut the cost of health insurance.
And as my Dad used to say, it gave people a little breathing room.
And unlike the $2 Trillion tax cut passed in the previous administration that benefitted the top 1% of Americans, the American Rescue Plan helped working people—and left no one behind.
And it worked. It created jobs. Lots of jobs.
In fact—our economy created over 6.5 Million new jobs just last year, more jobs created in one year
than ever before in the history of America.
Our economy grew at a rate of 5.7% last year, the strongest growth in nearly 40 years, the first step in bringing fundamental change to an economy that hasn’t worked for the working people of this nation for too long.
For the past 40 years we were told that if we gave tax breaks to those at the very top, the benefits would trickle down to everyone else.
But that trickle-down theory led to weaker economic growth, lower wages, bigger deficits, and the widest gap between those at the top and everyone else in nearly a century.
Vice President Harris and I ran for office with a new economic vision for America.
Invest in America. Educate Americans. Grow the workforce. Build the economy from the bottom up
and the middle out, not from the top down.
Because we know that when the middle class grows, the poor have a ladder up and the wealthy do very well.
America used to have the best roads, bridges, and airports on Earth.
Now our infrastructure is ranked 13th in the world.
We won’t be able to compete for the jobs of the 21st Century if we don’t fix that.
That’s why it was so important to pass the Bipartisan Infrastructure Law—the most sweeping investment to rebuild America in history.
This was a bipartisan effort, and I want to thank the members of both parties who worked to make it happen.
We’re done talking about infrastructure weeks.
We’re going to have an infrastructure decade.
It is going to transform America and put us on a path to win the economic competition of the 21st Century that we face with the rest of the world—particularly with China.
As I’ve told Xi Jinping, it is never a good bet to bet against the American people.
We’ll create good jobs for millions of Americans, modernizing roads, airports, ports, and waterways all across America.
And we’ll do it all to withstand the devastating effects of the climate crisis and promote environmental justice.
We’ll build a national network of 500,000 electric vehicle charging stations, begin to replace poisonous lead pipes—so every child—and every American—has clean water to drink at home and at school, provide affordable high-speed internet for every American—urban, suburban, rural, and tribal communities.
4,000 projects have already been announced.
And tonight, I’m announcing that this year we will start fixing over 65,000 miles of highway and 1,500 bridges in disrepair.
When we use taxpayer dollars to rebuild America – we are going to Buy American: buy American products to support American jobs.
The federal government spends about $600 Billion a year to keep the country safe and secure.
There’s been a law on the books for almost a century
to make sure taxpayers’ dollars support American jobs and businesses.
Every Administration says they’ll do it, but we are actually doing it.
We will buy American to make sure everything from the deck of an aircraft carrier to the steel on highway guardrails are made in America.
But to compete for the best jobs of the future, we also need to level the playing field with China and other competitors.
That’s why it is so important to pass the Bipartisan Innovation Act sitting in Congress that will make record investments in emerging technologies and American manufacturing.
Let me give you one example of why it’s so important to pass it.
If you travel 20 miles east of Columbus, Ohio, you’ll find 1,000 empty acres of land.
It won’t look like much, but if you stop and look closely, you’ll see a “Field of dreams,” the ground on which America’s future will be built.
This is where Intel, the American company that helped build Silicon Valley, is going to build its $20 billion semiconductor “mega site”.
Up to eight state-of-the-art factories in one place. 10,000 new good-paying jobs.
Some of the most sophisticated manufacturing in the world to make computer chips the size of a fingertip that power the world and our everyday lives.
Smartphones. The Internet. Technology we have yet to invent.
But that’s just the beginning.
Intel’s CEO, Pat Gelsinger, who is here tonight, told me they are ready to increase their investment from
$20 billion to $100 billion.
That would be one of the biggest investments in manufacturing in American history.
And all they’re waiting for is for you to pass this bill.
So let’s not wait any longer. Send it to my desk. I’ll sign it.
And we will really take off.
And Intel is not alone.
There’s something happening in America.
Just look around and you’ll see an amazing story.
The rebirth of the pride that comes from stamping products “Made In America.” The revitalization of American manufacturing.
Companies are choosing to build new factories here, when just a few years ago, they would have built them overseas.
That’s what is happening. Ford is investing $11 billion to build electric vehicles, creating 11,000 jobs across the country.
GM is making the largest investment in its history—$7 billion to build electric vehicles, creating 4,000 jobs in Michigan.
All told, we created 369,000 new manufacturing jobs in America just last year.
Powered by people I’ve met like JoJo Burgess, from generations of union steelworkers from Pittsburgh, who’s here with us tonight.
As Ohio Senator Sherrod Brown says, “It’s time to bury the label “Rust Belt.”
It’s time.
But with all the bright spots in our economy, record job growth and higher wages, too many families are struggling to keep up with the bills.
Inflation is robbing them of the gains they might otherwise feel.
I get it. That’s why my top priority is getting prices under control.
Look, our economy roared back faster than most predicted, but the pandemic meant that businesses had a hard time hiring enough workers to keep up production in their factories.
The pandemic also disrupted global supply chains.
When factories close, it takes longer to make goods and get them from the warehouse to the store, and prices go up.
Look at cars.
Last year, there weren’t enough semiconductors to make all the cars that people wanted to buy.
And guess what, prices of automobiles went up.
So—we have a choice.
One way to fight inflation is to drive down wages and make Americans poorer.
I have a better plan to fight inflation.
Lower your costs, not your wages.
Make more cars and semiconductors in America.
More infrastructure and innovation in America.
More goods moving faster and cheaper in America.
More jobs where you can earn a good living in America.
And instead of relying on foreign supply chains, let’s make it in America.
Economists call it “increasing the productive capacity of our economy.”
I call it building a better America.
My plan to fight inflation will lower your costs and lower the deficit.
17 Nobel laureates in economics say my plan will ease long-term inflationary pressures. Top business leaders and most Americans support my plan. And here’s the plan:
First – cut the cost of prescription drugs. Just look at insulin. One in ten Americans has diabetes. In Virginia, I met a 13-year-old boy named Joshua Davis.
He and his Dad both have Type 1 diabetes, which means they need insulin every day. Insulin costs about $10 a vial to make.
But drug companies charge families like Joshua and his Dad up to 30 times more. I spoke with Joshua’s mom.
Imagine what it’s like to look at your child who needs insulin and have no idea how you’re going to pay for it.
What it does to your dignity, your ability to look your child in the eye, to be the parent you expect to be.
Joshua is here with us tonight. Yesterday was his birthday. Happy birthday, buddy.
For Joshua, and for the 200,000 other young people with Type 1 diabetes, let’s cap the cost of insulin at $35 a month so everyone can afford it.
Drug companies will still do very well. And while we’re at it let Medicare negotiate lower prices for prescription drugs, like the VA already does.
Look, the American Rescue Plan is helping millions of families on Affordable Care Act plans save $2,400 a year on their health care premiums. Let’s close the coverage gap and make those savings permanent.
Second – cut energy costs for families an average of $500 a year by combatting climate change.
Let’s provide investments and tax credits to weatherize your homes and businesses to be energy efficient and you get a tax credit; double America’s clean energy production in solar, wind, and so much more; lower the price of electric vehicles, saving you another $80 a month because you’ll never have to pay at the gas pump again.
Third – cut the cost of child care. Many families pay up to $14,000 a year for child care per child.
Middle-class and working families shouldn’t have to pay more than 7% of their income for care of young children.
My plan will cut the cost in half for most families and help parents, including millions of women, who left the workforce during the pandemic because they couldn’t afford child care, to be able to get back to work.
My plan doesn’t stop there. It also includes home and long-term care. More affordable housing. And Pre-K for every 3- and 4-year-old.
All of these will lower costs.
And under my plan, nobody earning less than $400,000 a year will pay an additional penny in new taxes. Nobody.
The one thing all Americans agree on is that the tax system is not fair. We have to fix it.
I’m not looking to punish anyone. But let’s make sure corporations and the wealthiest Americans start paying their fair share.
Just last year, 55 Fortune 500 corporations earned $40 billion in profits and paid zero dollars in federal income tax.
That’s simply not fair. That’s why I’ve proposed a 15% minimum tax rate for corporations.
We got more than 130 countries to agree on a global minimum tax rate so companies can’t get out of paying their taxes at home by shipping jobs and factories overseas.
That’s why I’ve proposed closing loopholes so the very wealthy don’t pay a lower tax rate than a teacher or a firefighter.
So that’s my plan. It will grow the economy and lower costs for families.
So what are we waiting for? Let’s get this done. And while you’re at it, confirm my nominees to the Federal Reserve, which plays a critical role in fighting inflation.
My plan will not only lower costs to give families a fair shot, it will lower the deficit.
The previous Administration not only ballooned the deficit with tax cuts for the very wealthy and corporations, it undermined the watchdogs whose job was to keep pandemic relief funds from being wasted.
But in my administration, the watchdogs have been welcomed back.
We’re going after the criminals who stole billions in relief money meant for small businesses and millions of Americans.
And tonight, I’m announcing that the Justice Department will name a chief prosecutor for pandemic fraud.
By the end of this year, the deficit will be down to less than half what it was before I took office.
The only president ever to cut the deficit by more than one trillion dollars in a single year.
Lowering your costs also means demanding more competition.
I’m a capitalist, but capitalism without competition isn’t capitalism.
It’s exploitation—and it drives up prices.
When corporations don’t have to compete, their profits go up, your prices go up, and small businesses and family farmers and ranchers go under.
We see it happening with ocean carriers moving goods in and out of America.
During the pandemic, these foreign-owned companies raised prices by as much as 1,000% and made record profits.
Tonight, I’m announcing a crackdown on these companies overcharging American businesses and consumers.
And as Wall Street firms take over more nursing homes, quality in those homes has gone down and costs have gone up.
That ends on my watch.
Medicare is going to set higher standards for nursing homes and make sure your loved ones get the care they deserve and expect.
We’ll also cut costs and keep the economy going strong by giving workers a fair shot, provide more training and apprenticeships, hire them based on their skills not degrees.
Let’s pass the Paycheck Fairness Act and paid leave.
Raise the minimum wage to $15 an hour and extend the Child Tax Credit, so no one has to raise a family in poverty.
Let’s increase Pell Grants and increase our historic support of HBCUs, and invest in what Jill—our First Lady who teaches full-time—calls America’s best-kept secret: community colleges.
And let’s pass the PRO Act when a majority of workers want to form a union—they shouldn’t be stopped.
When we invest in our workers, when we build the economy from the bottom up and the middle out together, we can do something we haven’t done in a long time: build a better America.
For more than two years, COVID-19 has impacted every decision in our lives and the life of the nation.
And I know you’re tired, frustrated, and exhausted.
But I also know this.
Because of the progress we’ve made, because of your resilience and the tools we have, tonight I can say
we are moving forward safely, back to more normal routines.
We’ve reached a new moment in the fight against COVID-19, with severe cases down to a level not seen since last July.
Just a few days ago, the Centers for Disease Control and Prevention—the CDC—issued new mask guidelines.
Under these new guidelines, most Americans in most of the country can now be mask free.
And based on the projections, more of the country will reach that point across the next couple of weeks.
Thanks to the progress we have made this past year, COVID-19 need no longer control our lives.
I know some are talking about “living with COVID-19”. Tonight – I say that we will never just accept living with COVID-19.
We will continue to combat the virus as we do other diseases. And because this is a virus that mutates and spreads, we will stay on guard.
Here are four common sense steps as we move forward safely.
First, stay protected with vaccines and treatments. We know how incredibly effective vaccines are. If you’re vaccinated and boosted you have the highest degree of protection.
We will never give up on vaccinating more Americans. Now, I know parents with kids under 5 are eager to see a vaccine authorized for their children.
The scientists are working hard to get that done and we’ll be ready with plenty of vaccines when they do.
We’re also ready with anti-viral treatments. If you get COVID-19, the Pfizer pill reduces your chances of ending up in the hospital by 90%.
We’ve ordered more of these pills than anyone in the world. And Pfizer is working overtime to get us 1 Million pills this month and more than double that next month.
And we’re launching the “Test to Treat” initiative so people can get tested at a pharmacy, and if they’re positive, receive antiviral pills on the spot at no cost.
If you’re immunocompromised or have some other vulnerability, we have treatments and free high-quality masks.
We’re leaving no one behind or ignoring anyone’s needs as we move forward.
And on testing, we have made hundreds of millions of tests available for you to order for free.
Even if you already ordered free tests tonight, I am announcing that you can order more from covidtests.gov starting next week.
Second – we must prepare for new variants. Over the past year, we’ve gotten much better at detecting new variants.
If necessary, we’ll be able to deploy new vaccines within 100 days instead of many more months or years.
And, if Congress provides the funds we need, we’ll have new stockpiles of tests, masks, and pills ready if needed.
I cannot promise a new variant won’t come. But I can promise you we’ll do everything within our power to be ready if it does.
Third – we can end the shutdown of schools and businesses. We have the tools we need.
It’s time for Americans to get back to work and fill our great downtowns again. People working from home can feel safe to begin to return to the office.
We’re doing that here in the federal government. The vast majority of federal workers will once again work in person.
Our schools are open. Let’s keep it that way. Our kids need to be in school.
And with 75% of adult Americans fully vaccinated and hospitalizations down by 77%, most Americans can remove their masks, return to work, stay in the classroom, and move forward safely.
We achieved this because we provided free vaccines, treatments, tests, and masks.
Of course, continuing this costs money.
I will soon send Congress a request.
The vast majority of Americans have used these tools and may want to again, so I expect Congress to pass it quickly.
Fourth, we will continue vaccinating the world.
We’ve sent 475 Million vaccine doses to 112 countries, more than any other nation.
And we won’t stop.
We have lost so much to COVID-19. Time with one another. And worst of all, so much loss of life.
Let’s use this moment to reset. Let’s stop looking at COVID-19 as a partisan dividing line and see it for what it is: A God-awful disease.
Let’s stop seeing each other as enemies, and start seeing each other for who we really are: Fellow Americans.
We can’t change how divided we’ve been. But we can change how we move forward—on COVID-19 and other issues we must face together.
I recently visited the New York City Police Department days after the funerals of Officer Wilbert Mora and his partner, Officer Jason Rivera.
They were responding to a 9-1-1 call when a man shot and killed them with a stolen gun.
Officer Mora was 27 years old.
Officer Rivera was 22.
Both Dominican Americans who’d grown up on the same streets they later chose to patrol as police officers.
I spoke with their families and told them that we are forever in debt for their sacrifice, and we will carry on their mission to restore the trust and safety every community deserves.
I’ve worked on these issues a long time.
I know what works: Investing in crime prevention and community police officers who’ll walk the beat, who’ll know the neighborhood, and who can restore trust and safety.
So let’s not abandon our streets. Or choose between safety and equal justice.
Let’s come together to protect our communities, restore trust, and hold law enforcement accountable.
That’s why the Justice Department required body cameras, banned chokeholds, and restricted no-knock warrants for its officers.
That’s why the American Rescue Plan provided $350 Billion that cities, states, and counties can use to hire more police and invest in proven strategies like community violence interruption—trusted messengers breaking the cycle of violence and trauma and giving young people hope.
We should all agree: The answer is not to Defund the police. The answer is to FUND the police with the resources and training they need to protect our communities.
I ask Democrats and Republicans alike: Pass my budget and keep our neighborhoods safe.
And I will keep doing everything in my power to crack down on gun trafficking and ghost guns you can buy online and make at home—they have no serial numbers and can’t be traced.
And I ask Congress to pass proven measures to reduce gun violence. Pass universal background checks. Why should anyone on a terrorist list be able to purchase a weapon?
Ban assault weapons and high-capacity magazines.
Repeal the liability shield that makes gun manufacturers the only industry in America that can’t be sued.
These laws don’t infringe on the Second Amendment. They save lives.
The most fundamental right in America is the right to vote – and to have it counted. And it’s under assault.
In state after state, new laws have been passed, not only to suppress the vote, but to subvert entire elections.
We cannot let this happen.
Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections.
Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service.
One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court.
And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.
A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans.
And if we are to advance liberty and justice, we need to secure the Border and fix the immigration system.
We can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling.
We’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers.
We’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster.
We’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders.
We can do all this while keeping lit the torch of liberty that has led generations of immigrants to this land—my forefathers and so many of yours.
Provide a pathway to citizenship for Dreamers, those on temporary status, farm workers, and essential workers.
Revise our laws so businesses have the workers they need and families don’t wait decades to reunite.
It’s not only the right thing to do—it’s the economically smart thing to do.
That’s why immigration reform is supported by everyone from labor unions to religious leaders to the U.S. Chamber of Commerce.
Let’s get it done once and for all.
Advancing liberty and justice also requires protecting the rights of women.
The constitutional right affirmed in Roe v. Wade—standing precedent for half a century—is under attack as never before.
If we want to go forward—not backward—we must protect access to health care. Preserve a woman’s right to choose. And let’s continue to advance maternal health care in America.
And for our LGBTQ+ Americans, let’s finally get the bipartisan Equality Act to my desk. The onslaught of state laws targeting transgender Americans and their families is wrong.
As I said last year, especially to our younger transgender Americans, I will always have your back as your President, so you can be yourself and reach your God-given potential.
While it often appears that we never agree, that isn’t true. I signed 80 bipartisan bills into law last year. From preventing government shutdowns to protecting Asian-Americans from still-too-common hate crimes to reforming military justice.
And soon, we’ll strengthen the Violence Against Women Act that I first wrote three decades ago. It is important for us to show the nation that we can come together and do big things.
So tonight I’m offering a Unity Agenda for the Nation. Four big things we can do together.
First, beat the opioid epidemic.
There is so much we can do. Increase funding for prevention, treatment, harm reduction, and recovery.
Get rid of outdated rules that stop doctors from prescribing treatments. And stop the flow of illicit drugs by working with state and local law enforcement to go after traffickers.
If you’re suffering from addiction, know you are not alone. I believe in recovery, and I celebrate the 23 million Americans in recovery.
Second, let’s take on mental health. Especially among our children, whose lives and education have been turned upside down.
The American Rescue Plan gave schools money to hire teachers and help students make up for lost learning.
I urge every parent to make sure your school does just that. And we can all play a part—sign up to be a tutor or a mentor.
Children were also struggling before the pandemic. Bullying, violence, trauma, and the harms of social media.
As Frances Haugen, who is here with us tonight, has shown, we must hold social media platforms accountable for the national experiment they’re conducting on our children for profit.
It’s time to strengthen privacy protections, ban targeted advertising to children, demand tech companies stop collecting personal data on our children.
And let’s get all Americans the mental health services they need. More people they can turn to for help, and full parity between physical and mental health care.
Third, support our veterans.
Veterans are the best of us.
I’ve always believed that we have a sacred obligation to equip all those we send to war and care for them and their families when they come home.
My administration is providing assistance with job training and housing, and now helping lower-income veterans get VA care debt-free.
Our troops in Iraq and Afghanistan faced many dangers.
One was stationed at bases and breathing in toxic smoke from “burn pits” that incinerated wastes of war—medical and hazard material, jet fuel, and more.
When they came home, many of the world’s fittest and best trained warriors were never the same.
Headaches. Numbness. Dizziness.
A cancer that would put them in a flag-draped coffin.
I know.
One of those soldiers was my son Major Beau Biden.
We don’t know for sure if a burn pit was the cause of his brain cancer, or the diseases of so many of our troops.
But I’m committed to finding out everything we can.
Committed to military families like Danielle Robinson from Ohio.
The widow of Sergeant First Class Heath Robinson.
He was born a soldier. Army National Guard. Combat medic in Kosovo and Iraq.
Stationed near Baghdad, just yards from burn pits the size of football fields.
Heath’s widow Danielle is here with us tonight. They loved going to Ohio State football games. He loved building Legos with their daughter.
But cancer from prolonged exposure to burn pits ravaged Heath’s lungs and body.
Danielle says Heath was a fighter to the very end.
He didn’t know how to stop fighting, and neither did she.
Through her pain she found purpose to demand we do better.
Tonight, Danielle—we are.
The VA is pioneering new ways of linking toxic exposures to diseases, already helping more veterans get benefits.
And tonight, I’m announcing we’re expanding eligibility to veterans suffering from nine respiratory cancers.
I’m also calling on Congress: pass a law to make sure veterans devastated by toxic exposures in Iraq and Afghanistan finally get the benefits and comprehensive health care they deserve.
And fourth, let’s end cancer as we know it.
This is personal to me and Jill, to Kamala, and to so many of you.
Cancer is the #2 cause of death in America–second only to heart disease.
Last month, I announced our plan to supercharge
the Cancer Moonshot that President Obama asked me to lead six years ago.
Our goal is to cut the cancer death rate by at least 50% over the next 25 years, turn more cancers from death sentences into treatable diseases.
More support for patients and families.
To get there, I call on Congress to fund ARPA-H, the Advanced Research Projects Agency for Health.
It’s based on DARPA—the Defense Department project that led to the Internet, GPS, and so much more.
ARPA-H will have a singular purpose—to drive breakthroughs in cancer, Alzheimer’s, diabetes, and more.
A unity agenda for the nation.
We can do this.
My fellow Americans—tonight , we have gathered in a sacred space—the citadel of our democracy.
In this Capitol, generation after generation, Americans have debated great questions amid great strife, and have done great things.
We have fought for freedom, expanded liberty, defeated totalitarianism and terror.
And built the strongest, freest, and most prosperous nation the world has ever known.
Now is the hour.
Our moment of responsibility.
Our test of resolve and conscience, of history itself.
It is in this moment that our character is formed. Our purpose is found. Our future is forged.
Well I know this nation.
We will meet the test.
To protect freedom and liberty, to expand fairness and opportunity.
We will save democracy.
As hard as these times have been, I am more optimistic about America today than I have been my whole life.
Because I see the future that is within our grasp.
Because I know there is simply nothing beyond our capacity.
We are the only nation on Earth that has always turned every crisis we have faced into an opportunity.
The only nation that can be defined by a single word: possibilities.
So on this night, in our 245th year as a nation, I have come to report on the State of the Union.
And my report is this: the State of the Union is strong—because you, the American people, are strong.
We are stronger today than we were a year ago.
And we will be stronger a year from now than we are today.
Now is our moment to meet and overcome the challenges of our time.
And we will, as one people.
One America.
The United States of America.
May God bless you all. May God protect our troops.
================================================
FILE: RAG App with Mongo Vector Search & Gemma/rag_with_huggingface_and_mongodb.ipynb
================================================
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "L1-5cYCKA4XS"
},
"outputs": [],
"source": [
"!pip install datasets pandas pymongo sentence_transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "M6NY-e6rBSc-"
},
"outputs": [],
"source": [
"!pip install -U transformers accelerate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "a4Jz416BBa24"
},
"outputs": [],
"source": [
"from datasets import load_dataset"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GfCrKhm4Bo6A"
},
"outputs": [],
"source": [
"import pandas as pd"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 241,
"referenced_widgets": [
"3f309906c3df4839adda52a49f4fe21b",
"41a6d5e69aa348a7983d25177d2214a7",
"998cbe356eb347648285856b2f7352ab",
"a46b2eee5ec843febb1c21b3e9c3fd7b",
"de0c2802cf5141cf8668c4f21204393b",
"ba2694c02ac5440ca03832e3a225c4f4",
"35cdcadceab24b2c8dccd6e76b3cc5a6",
"6201d6e452094d38aa8d00137c4c9669",
"5737bec22aa044ac84a25d2f4e9ca449",
"58355a851a9744c98141c6fe11658914",
"72940d04f0ce4dd89ceadfb860d12f0e",
"5d7b37b44c28421995adf61a7d5108f4",
"45496f36318d451bac01fa3e75b5c03d",
"934c2f44ca00478d8d5c1c9a600f69e9",
"7639123873a04981bce3eebcedb05bc2",
"50251331bf394aa9891ff6d86d5b40b6",
"eab40b86b6bd44babb6460e699642353",
"9adaa78a04f2467e987e03429cb078c4",
"d75ca9da26ce430ab50984cdff9f194a",
"a349772820384569bf7813f5438fffad",
"23bb33cf23ce4e18907b3ed502888a17",
"ef852d5daab24444aeb111a47f458e26",
"ea1c95a13aca491292e89b5a131e1588",
"486aed18a359459399cc033abc2174d2",
"4a4b2569d3354662872f4bd40af9276e",
"10c2bbf999554c6bbd5d53d6c6d4d834",
"7f9e54f173c349f79541e6e0c4fb1764",
"6e56ba4c8c2647d49f2c2f17ae85c675",
"19c192e61e614935ace983a7a7a7604e",
"ceeee6ba7bd945a6bf21f7d387cf1506",
"9aa6542ddea540a2b8d88c1097948efc",
"d0ec19cd581942e49f7df50434a2aa1e",
"2eb8224adfb44f8ab9ecb973b42ce0f2"
]
},
"id": "E-nODsvZBrdF",
"outputId": "8c87f156-7055-4df5-e598-c4bfa754a2b9"
},
"outputs": [],
"source": [
"#dataset=load_dataset(\"AIatMongoDB/embedded_movies\")\n",
"dataset=load_dataset(\"MongoDB/embedded_movies\")\n",
"#MongoDB/embedded_movies"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "3wk5EYTxCAZf",
"outputId": "2237dded-075c-4cb9-ec50-7a4d76279534"
},
"outputs": [],
"source": [
"dataset"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xltqOeu6COVW"
},
"outputs": [],
"source": [
"dataset_df=pd.DataFrame(dataset[\"train\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 145
},
"id": "waeeI5UTCS3H",
"outputId": "011ffcf2-0c7e-4792-8fd6-b11bb2acf009"
},
"outputs": [],
"source": [
"dataset_df.head()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Zjhr9tDmDaLK",
"outputId": "b7587c56-4a47-4a25-81a7-579a83d9e46d"
},
"outputs": [],
"source": [
"dataset_df.columns"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"id": "LPF7YagwDdYp",
"outputId": "9eb3e65b-30a0-41d4-8eae-f8d0298a40b4"
},
"outputs": [],
"source": [
"dataset_df[\"plot\"][0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
},
"id": "zXWsEeAEDqH5",
"outputId": "ed409b1e-7931-4fa7-eb15-cd9cb0522dea"
},
"outputs": [],
"source": [
"dataset_df[\"fullplot\"][0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "d8_96aRXErjt",
"outputId": "905f2434-e51a-464a-82e8-d8ba85d58475"
},
"outputs": [],
"source": [
"dataset_df[\"num_mflix_comments\"][0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "kvtEJnEFD_Xz",
"outputId": "ece6f77d-14c7-4774-876c-21d9433eaa95"
},
"outputs": [],
"source": [
"dataset_df[\"fullplot\"].isnull().sum()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Xxx5lbXnEHma",
"outputId": "80dd89e2-b7d6-421d-affe-521741d45e44"
},
"outputs": [],
"source": [
"dataset_df.shape"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"id": "dey3wEVxETOs",
"outputId": "141c3b67-c983-4c5a-f719-5da55ebf9f8b"
},
"outputs": [],
"source": [
"dataset_df[\"poster\"][0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "IjLSpkw9ChG3",
"outputId": "e975d9d5-8e7c-47d3-e127-411aed90df80"
},
"outputs": [],
"source": [
"dataset_df.isnull().sum()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "KGeAho8GDCSK"
},
"outputs": [],
"source": [
"dataset_df=dataset_df.dropna(subset=[\"fullplot\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5TFDYus1FQTn",
"outputId": "bdcbd6a3-f946-40b0-904b-b18b8a3c3565"
},
"outputs": [],
"source": [
"dataset_df[\"fullplot\"].isnull().sum()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9ANR6TtxFVZe"
},
"outputs": [],
"source": [
"dataset_df = dataset_df.drop(columns=[\"plot_embedding\"])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 340
},
"id": "abCIIPGXFhU_",
"outputId": "0d303adb-e8ea-47d7-b23d-aed3e70cecde"
},
"outputs": [],
"source": [
"dataset_df.head(2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 452
},
"id": "kdqa7Mv8F3UI",
"outputId": "afc3e3d3-c2d6-4562-b9f6-23d871f7af36"
},
"outputs": [],
"source": [
"# @title metacritic\n",
"\n",
"from matplotlib import pyplot as plt\n",
"dataset_df['metacritic'].plot(kind='hist', bins=20, title='metacritic')\n",
"plt.gca().spines[['top', 'right',]].set_visible(False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5XrEBgWmFjWe"
},
"outputs": [],
"source": [
"from sentence_transformers import SentenceTransformer\n",
"embedding_model = SentenceTransformer(\"thenlper/gte-large\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 72
},
"id": "ayplIvvLGyk_",
"outputId": "a24bbaca-c893-41b9-a317-83cf80025401"
},
"outputs": [],
"source": [
"dataset_df[\"fullplot\"][2]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5YCL4funHlqB"
},
"outputs": [],
"source": [
"text=\" sunny savita is a data scientist who create prodcut of data\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zlLEC4-THzi9"
},
"outputs": [],
"source": [
"text=\" sunny savita is a data scientist who create prodcut of data \"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "fXxPwQGCH2LM",
"outputId": "29323172-ea5a-4c6a-ac97-a8c80ef13d99"
},
"outputs": [],
"source": [
"text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "eVqlQFEXHtnK",
"outputId": "5fe2fa48-8c99-4f12-9070-fd6b55c4e5f4"
},
"outputs": [],
"source": [
"text.strip()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Zge4b2p_HAV0"
},
"outputs": [],
"source": [
"def get_embedding(text:str)->list[float]:\n",
"\n",
" if not text.strip():\n",
" print(\"attempted to get embedding for empty text.\")\n",
" return []\n",
"\n",
" embedding=embedding_model.encode(text)\n",
" return embedding.tolist()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mtLUR8QwIJcP"
},
"outputs": [],
"source": [
"dataset_df[\"embedding\"]=dataset_df[\"fullplot\"].apply(get_embedding)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 475
},
"id": "6guCtolpIWt5",
"outputId": "84eb4d62-b5ed-47de-9e8c-e66b30d4279e"
},
"outputs": [],
"source": [
"dataset_df.head(3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gBa-qzx3RNdV",
"outputId": "8cc9a744-259c-40bb-d690-0a6a0f3f8b7c"
},
"outputs": [],
"source": [
"!python --version"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kXbZFM5RIqYU"
},
"outputs": [],
"source": [
"import pymongo"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xbEDquRoMrAx"
},
"outputs": [],
"source": [
"#!python -m pip install \"pymongo[srv]\"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lNB6bSnNRmUy"
},
"outputs": [],
"source": [
"from pymongo.mongo_client import MongoClient"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GfV1Qe1YSX8f"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"uri=userdata.get('MONGO_URI')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hIPRAlsRRq2v"
},
"outputs": [],
"source": [
"# Create a new client and connect to the server\n",
"client = MongoClient(uri)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mInjJ-kLMvSV"
},
"outputs": [],
"source": [
"# Send a ping to confirm a successful connection\n",
"try:\n",
" client.admin.command('ping')\n",
" print(\"Pinged your deployment. You successfully connected to MongoDB!\")\n",
"except Exception as e:\n",
" print(e)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pcrtipaDRtbm"
},
"outputs": [],
"source": [
"def get_mongo_client(uri):\n",
" try:\n",
" client = MongoClient(uri)\n",
" client.admin.command('ping')\n",
" print(\"Pinged your deployment. You successfully connected to MongoDB!\")\n",
" return client\n",
" except Exception as e:\n",
" print(e)\n",
" return None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4LG9ETvISsHL"
},
"outputs": [],
"source": [
"mongo_client=get_mongo_client(uri)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Vl0eY7amTHje"
},
"outputs": [],
"source": [
"db=mongo_client[\"moviedb2\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TPTjqFyZUGwc"
},
"outputs": [],
"source": [
"collection=db[\"moviecollection2\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "UYhC_ocpUMLL",
"outputId": "2dbd62d2-a543-42b6-c1dc-d8c286adaae3"
},
"outputs": [],
"source": [
"collection.insert_one({\"name\":\"sunny\",\n",
" \"designation\": \"genai engineer\",\n",
" \"location\":\"bangaluru\",\n",
" \"mailid\":\"sunny.savita@ineuron.ai\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "b06bukanU8U1",
"outputId": "41b72c83-a2b2-4ce4-8bbe-5ba7136fb1d7"
},
"outputs": [],
"source": [
"collection.insert_one({\"name\":\"dipesh\",\n",
" \"designation\": \"ops manager\",\n",
" \"location\":\"bangaluru\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zTZA1nVCVhyk"
},
"outputs": [],
"source": [
"collection2=db[\"moviecollectionsecond\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5zEeouaAVsus",
"outputId": "3a190c16-0376-4f52-d374-805f1a650074"
},
"outputs": [],
"source": [
"collection2.insert_one({\"name\":\"krish\",\n",
" \"designation\": \"tech lead\",\n",
" \"location\":\"bangaluru\",\n",
" \"phonenumber\":57454745834})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "TPGUbL3-V2Y0",
"outputId": "d3c2e655-f617-4e1d-9fcf-ef1d0614dbfa"
},
"outputs": [],
"source": [
"collection.delete_many({})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 423
},
"id": "I-vVy61IWP-5",
"outputId": "74eab1fc-374f-47de-eafe-4790fcd37200"
},
"outputs": [],
"source": [
"dataset_df.tail(3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UloWvipUWauA"
},
"outputs": [],
"source": [
"document=dataset_df.to_dict(\"records\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JCkSCIGXWg1_",
"outputId": "cdaac8fc-6239-4dc6-dded-6023a2570bd8"
},
"outputs": [],
"source": [
"collection.insert_many(document)\n",
"\n",
"print(\"data ingestion in mongodb is completed\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "YZzMTxVF-EZK"
},
"source": [
"# Data Retrival"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "WKQxVJ-n-MAB"
},
"outputs": [],
"source": [
"{\n",
" key:value\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1DwzWaZOYk4i",
"outputId": "8721d1b5-7300-48aa-8fa7-2f2574572fa9"
},
"outputs": [],
"source": [
"{\n",
" \"fields\": [{\n",
" \"numDimensions\": 1024,\n",
" \"path\": \"embedding\",\n",
" \"similarity\": \"cosine\",\n",
" \"type\": \"vector\"\n",
" }]\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Yc0Ycu_J_e7O"
},
"outputs": [],
"source": [
"user_query=\"what is the best horror movie?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RabgPRe1_YEn"
},
"outputs": [],
"source": [
"query_embedding=get_embedding(user_query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "DFdCIpsZ9ThG",
"outputId": "4b28823e-3e1f-4f34-b288-89639d675384"
},
"outputs": [],
"source": [
"query_embedding"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "t2cu9AAT_YHI"
},
"outputs": [],
"source": [
"print(query_embedding)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0xfcIBkkAwX-"
},
"source": [
"https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EA1A6f0GEyhg"
},
"outputs": [],
"source": [
"pipeline = [\n",
"\n",
" {\n",
" \"$vectorSearch\": {\n",
" \"index\": \"vector_index\",\n",
" \"queryVector\": query_embedding,\n",
" \"path\": \"embedding\",\n",
" \"numCandidates\": 150, # Number of candidate matches to consider\n",
" \"limit\": 4, # Return top 4 matches\n",
" }\n",
" },\n",
" {\n",
" \"$project\": {\n",
" \"fullplot\": 1, # Include the plot field\n",
" \"title\": 1, # Include the title field\n",
" \"genres\": 1, # Include the genres field\n",
" \"score\": {\"$meta\": \"vectorSearchScore\"}, # Include the search score\n",
" }\n",
" }\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gQSzWEaIGn3w",
"outputId": "8404e42a-7bc8-4423-ecc4-87b6d0b8a9db"
},
"outputs": [],
"source": [
"collection.aggregate(pipeline)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "N7C8l1_a_YM-",
"outputId": "4c8186c1-f27c-4190-9b05-de0fb1e7f3c2"
},
"outputs": [],
"source": [
"list(collection.aggregate(pipeline))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9ToJEOAYD8gY"
},
"outputs": [],
"source": [
"def get_embedding(text:str)->list[float]:\n",
"\n",
" if not text.strip():\n",
" print(\"attempted to get embedding for empty text.\")\n",
" return []\n",
"\n",
" embedding=embedding_model.encode(text)\n",
" return embedding.tolist()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5kwa6hwXXI45"
},
"outputs": [],
"source": [
"def vector_search(user_query,collection):\n",
"\n",
" query_embedding=get_embedding(user_query)\n",
" print(query_embedding)\n",
"\n",
" if query_embedding is None:\n",
" return \"Invalid query or embeddig is failed\"\n",
"\n",
" pipeline=[\n",
"\n",
" {\n",
" \"$vectorSearch\":{\n",
"\n",
" \"index\": \"vector_index\",\n",
" \"queryVector\": query_embedding,\n",
" \"path\": \"embedding\",\n",
" \"numCandidates\": 150, # Number of candidate matches to consider\n",
" \"limit\": 4, # Return top 4 matches\n",
"\n",
"\n",
" }\n",
"\n",
" },\n",
"\n",
" {\n",
" \"$project\":{\n",
"\n",
" \"fullplot\": 1, # Include the plot field\n",
" \"title\": 1, # Include the title field\n",
" \"genres\": 1, # Include the genres field\n",
" \"score\": {\"$meta\": \"vectorSearchScore\"}, # Include the search score\n",
" }\n",
"\n",
" }\n",
"\n",
" ]\n",
"\n",
" result=collection.aggregate(pipeline)\n",
" return list(result)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fZVDFWsDbWv-",
"outputId": "dd1cd472-3bd6-4339-a5e4-22e03205ff6f"
},
"outputs": [],
"source": [
"vector_search(\"what is the best horror movie to watch and why?\",collection)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "iaSjGap8ZJtT"
},
"outputs": [],
"source": [
"def get_search_result(query,collection):\n",
"\n",
" get_knowledge=vector_search(query,collection)\n",
"\n",
" search_result=\"\"\n",
"\n",
" for result in get_knowledge:\n",
" search_result += f\"Title: {result.get('title', 'N/A')}, Plot: {result.get('fullplot', 'N/A')}\\n\"\n",
"\n",
" return search_result\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "iotY_NQmDlIu"
},
"outputs": [],
"source": [
"query=\"what is the best comedy movie to watch and why?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ToATwGLTDp5G",
"outputId": "9cf39f1b-3f15-4046-e391-38d9f5f3fea6"
},
"outputs": [],
"source": [
"collection"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EHZGjhJ7Z6b1"
},
"outputs": [],
"source": [
"source_information=get_search_result(query,collection)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 162
},
"id": "t6k9DevnaRDc",
"outputId": "4649da5a-497e-4c75-a0cd-98e0eeaa2813"
},
"outputs": [],
"source": [
"source_information"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "A4QC_8z8cfz8"
},
"outputs": [],
"source": [
"combined_information = f\"Query: {query}\\nContinue to answer the query by using the Search Results:\\n{source_information}.\"\n",
"\n",
"print(combined_information)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "4gjf2IDhEqQk"
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "WxxaFCFvEqkt"
},
"source": [
"# generation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ZWrbMuA3w1Uw",
"outputId": "3383a626-58ed-431a-fe67-d03206fff2fb"
},
"outputs": [],
"source": [
"!pip install --upgrade huggingface_hub"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zzWyfr858jdv"
},
"outputs": [],
"source": [
"HF_TOKEN=\"\" # Replace with your Hugging Face API token "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 145,
"referenced_widgets": [
"e0855a93f7b6468e8bff6162436bef3f",
"444f505d10484eee82ed6f5d514a71ad",
"e240ea85aff04edd809836b43fa9d505",
"a34630c975fe4f6c9fdf9edc34c2e33b",
"80ec675222844c2581c94f6bfbf74274",
"a5b65e6845b94fd8adeb074084ffe7a8",
"016d5c2235a9477e8d873334d09a7466",
"ee1603395c9c48ca802f174e3bb5124e",
"f8faaf294ba14b74bd79bca279bf2cdc",
"3a615a0bf70a42b5b707d59cb2ebf814",
"3f3ad2143dc449bdb7ecb2f25f612be9",
"db398f3bf987456cb4aac8af36799184",
"1a691494160e412982fc18e45fb03b7e",
"4bc717574a9e45aca41967accaaa9dbc",
"0a30b4c4c66f4e8a8925340167ac6663",
"d53443b290014ee59053d15fb92f5445",
"24dea166a3e24ef89e954dd2408162bf",
"26605b34bce049bfb2859122ecb0ad41",
"a9fa44da58bf4d949f4517dace95ad7d",
"2bd1e78816ee4c80877b67d786f430ae",
"8d8a779bf1ee4fcd83597d31235bc0b3",
"58c864f40c204de8972a829f1729581b",
"7a24372fd1e24730916bd9eeb6ed7f9b",
"75860f7b7f494dac9867e4aedcaca9d6",
"8ac102ec74754fc2a9c4f8fc771335a6",
"4b5335731f124774a93704b615c27a8b",
"f59ac8c7be464d00a96775ad3145bbc9",
"d014da1e7eb4421997f674cabf49debb",
"8320fb213c1045b6922968638a8c958a",
"ff64e6a1ea2d4fa7801e867b5572b205",
"59595d60c3ae4aafbd4803535233d857",
"5d05a0a67e224406b83ec1d51cc64b48"
]
},
"id": "qHMWc9t79LHt",
"outputId": "bb956ea0-80e6-46e3-e243-764169e2a0ef"
},
"outputs": [],
"source": [
"from huggingface_hub import notebook_login\n",
"notebook_login()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "jxsf6vWtctkV",
"outputId": "4d493502-1cf4-4eb7-d196-1475e8c00066"
},
"outputs": [],
"source": [
"from transformers import AutoTokenizer, AutoModelForCausalLM\n",
"\n",
"tokenizer = AutoTokenizer.from_pretrained(\"google/gemma-2b-it\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 297,
"referenced_widgets": [
"6eb1d3d3c8bf4d56aef808c6b3bd89f4",
"4d67ea2973114972b98485402f5d8d6f",
"9790f948c9b449cbb0036eb94d2e41fa",
"3757925570654ae896bac66ba60b94b6",
"51182936959e4e679a462de9d0d3ef1b",
"b6b89009090d43f2836ffd4077b376c2",
"4a555f28bedd421f85dcdb7d6279d63f",
"c88acc50c0cc48b1b2fc376985d8478c",
"61a6055a422b4a8ca005ea0a2fd82dbf",
"47c1f461a56d4cf6af1d7c881c06cab1",
"05332eff981c4ad7b4a02436c80be3b8",
"20ff1e88a1f54123bb3b33b08ea9a1c8",
"10266043f9114d28bf848eac2005ccf4",
"e78f13c26b60442186db553226c4d5ec",
"15ff1ac2e12841b3804a6aa2ad96aab4",
"76ca9667b6804f52aaefd2d11a8e059d",
"31994a6f7a7e4a8d940ac51dfaa6ac45",
"06b057d181fe4a349af7f4b92f5ce0dd",
"26be190591434d04a7bec1bc1f669686",
"95cb93b87a6c434091f59fa6de57d8e7",
"fb9928d287f84853b07e3643166b6442",
"5c36f59e886e4b919dd7e7af973d1eb8",
"8e8dcf66c9c44bbbbb4997d4710e8287",
"64773f9cc5df4855ae14688300fe3aa5",
"d12532307781486ca7a03ebd01cd241a",
"a153892754a1482291103a58c2ddd520",
"fa1da6680d3e48b2a10c0cc2eb4cdb3d",
"3ce876dc96aa42008a5514a247b503e5",
"84be888f3d1b4cb8a11e9ce3330b2e2b",
"3e811c162f784869ae11b4470b052ff1",
"b4e3edc3a31e42b7ac9c45905dc30d2b",
"437086a01d864a07a6bb5017987a0047",
"3c48bcee76224da380251c413e19225f",
"fef483e4d45241d39d9938194e789905",
"0605e8e7d28f404da608da824675415a",
"f97adde44a95445ebd39e8bfeb171ff4",
"76683333237f44a8add1f6a9a8196128",
"a13ef5b831404c54b5f061907b00fdbc",
"5e080a4acd6e4ea3a5a45ae4cc459012",
"0bca73a9861d44e394bc8993da52989d",
"ce25d50ec03f4c179c5f9020d0abcc87",
"87ad808e10414608af47a44cd62c84d1",
"6ae5acfd6b9e4b81a0359d0dd22466de",
"2d61f7f1689d43628229b454efa34bf7",
"d88becf303a748369a5b314614443116",
"3ef221c8c6924055aa8ef7e4905db17d",
"4571a28e55e44fd494a401300b0ddab8",
"12e44a765871464b833908837d718083",
"8ceb43ad70944eb698aaa5fb99ff1110",
"ccd6fb4130734b428f14f97862d7803a",
"85fe3cd737c442df9712fad106a9cbbe",
"56ccff9ccdb7450881d75a8bea8f22b3",
"65f34680ba8d4e03b0abde0cbc847b56",
"abf6d58d80214433a4fe2de42a557ec8",
"883eb8629e8b45cf9237c5ccc56a2d2b",
"b433221312b442e195b449bba090b1fa",
"b5e5b04111d64a4688ed7d41d8aead68",
"f081afd78e2841b0a4ad33f1b0cf9e03",
"9eebaad76ccd410eb06428a44e1b5f06",
"c52d07ee754d4c43b8936feffcba32a1",
"ce96d0ff79d54332b5042400e0db6964",
"1e49eb479e04475a91411cb24a709717",
"1869e671ca7848b1a4fb2649d85850c0",
"458eed408e79435e8c607689e50723fc",
"c2ae724cfccf4bacb1d96cec613b7f7d",
"7fda043ec959475d93f515416bd5655f",
"9d747b7ad7034e80a8b04ce2c0057f64",
"076c9b718192470caaab601e6e7680eb",
"7245344850be44fdb324b71c66f6ebb5",
"4b10b4b6f7154952ba758630bbc1d77a",
"78fafeca67ca413eb576882d54dc9836",
"8708554f42ed441c94f72427ffd44f77",
"cbc5116f87d141359c800ac8fbae0bed",
"a40680ddcdda442d8a14247b3699d7c8",
"5ea7d095ef744c4a9c5b0139345ea3c3",
"1f7ab5f7f853469885e7f9ae2088220b",
"e620b034ee35425d970148c5e8f64d89"
]
},
"id": "NMAP5qXfaSTU",
"outputId": "822164c8-cbd9-48d2-ed96-5de1ba1273b1"
},
"outputs": [],
"source": [
"# CPU Enabled uncomment below 👇🏽\n",
"# model = AutoModelForCausalLM.from_pretrained(\"google/gemma-2b-it\")\n",
"# GPU Enabled use below 👇🏽\n",
"model = AutoModelForCausalLM.from_pretrained(\"google/gemma-2b-it\", device_map=\"auto\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cgaBBvZ3coGx"
},
"outputs": [],
"source": [
"# Moving tensors to GPU\n",
"input_ids = tokenizer(combined_information, return_tensors=\"pt\").to(\"cuda\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SXoUYd1Ycprt"
},
"outputs": [],
"source": [
"response = model.generate(**input_ids, max_new_tokens=500)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Kmjpg_yFcTlq"
},
"outputs": [],
"source": [
"print(tokenizer.decode(response[0]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "e3VU1q0ugQ-u"
},
"outputs": [],
"source": [
"#https://python.langchain.com/docs/integrations/retrievers/weaviate-hybrid/\n",
"\n",
"\n",
"https://towardsdatascience.com/improving-retrieval-performance-in-rag-pipelines-with-hybrid-search-c75203c2f2f5\n",
"https://esteininger.medium.com/mongodb-and-pinecone-building-real-time-ai-applications-cd8e0482a3c7"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vZpiaKKYGCgm"
},
"outputs": [],
"source": [
"# you are supposed to solve these two thing(hybrid search,combination of db(pinecone+mongodb)) you can send me this notebook"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "JRH4rYUcGXKA"
},
"outputs": [],
"source": [
"# i will upload these notebook in resource section with your name"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lkV_aeoCGeAs"
},
"outputs": [],
"source": [
"# i will create one video which will be dedicated to that best solution and i will do linkedin post from my linkedin account and i wll mention that person as well."
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: RAG Pipeline from Scratch/RAG_Implementation_from _Scartch.ipynb
================================================
{
"cells": [
{
"attachments": {
"image.png": {
"image/png": "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DBs2LI0dOzYNGDAg9evXL1177bXpmmuuST169EhXXXVVuvLKK9Nll13mu46I/Ba0J4888kj63vd/kHr36ZvWr119dkvbUOASEREREZG6ohSDoPrJUi+dJlGusnzNKZudPiIiInKp+Pjjj7OYdebMmexy8L333ktHjx7NAautgwcP5inbseZi+wcffJA++uij1Lt37yxsMe3Tp0/q1q1bFraGDBmSA8LX1VdfnQWvK6644myOIiIKXCIiIiIiIiIiIiLSArDSQpxCpAr3g3Q0HzlyJAtZCFEIXqdPn85xe/bsmQUshKvLL788B7qPSYPtMY+FF/vjrpD4vXr1ytNBgwZlS6/rr78+i2BYdflzj4gocImIiIiIiIiIiIjIBSnH06JjGQut48eP52XWY6FFt/DQoUPTwIEDsziF5RVCVffu3bOwhTDFmKKRHvGZYgVGGohcWHidOnUq7d+/P+fDPiF0jRgxIg0ePDj17dtXiy6RLo4Cl4iIiIiIiIiIiIg0CQIUFlYIWbt3706bNm1KO3fuzCIUYhUuBBGdELYQoRhHC0EKd4MtGT8rBC8C+WHJhVUYeW3fvj3nhzvD8ePHpwkTJuS8ELnK9KNbWgsvkc6PApeIiIiIiIiIiIiI1BSHsKxCaEJk2rx5c9q6dWvat29fFrbGjRuXpk2blsaMGXPOSivcELK9tSJTlCOENSy73n777fTmm2+m9evX53G+GJ9rypQpaeTIkVlMO581F+kpeIl0PhS4REREREREREREROS3BC4EJiyo1q5dm1577bV06NChPJ7WqFGj0tixY7PFVv/+/bO4FZZasW97CUqUiYDQhvvCgwcPpo0bN2axizyx5po8eXK2IGNsrlqwvwKXSOejowSuf3KiKiIiIiIiIiIiIiINQSkCIW6dPn06W0wtXbo0uyYcPnx4euCBB9KXvvSlNGfOnDR69Oh0zTXXZGEpxtWCEKXaA8pE2uRBXliN3X777WnevHl5+0svvZTFN4S4Tz75JK+rorglIi1BgUtERERERERERESkwUAMQpw6c+ZMFreef/75tGfPnnTzzTenhx9+OAtLAwcOzO4Imxpfi3XtLSqFYIYrwuuuuy7Nnj07/f7v/3624Fq2bFlasmRJHiMMYa5Ke4ltItI1UOASERERERERERERaTAQg3AFiFvCxx9/PLsAmzFjRrrjjjuyS0IsqUrxivghIIU41h6U6UIpmjGlHAht99xzTx4H7PXXX0+//vWv044dO9KHH36Y4wVleTuK9jpuEbn0KHCJiIiIiIiIiIiINBiMdcVYWwhce/fuTRMmTMhWWyNGjEjdunU7G+ufCBGqI8SdEKWaSpvtWHMhulG+iRMnppUrV6ZXX301HThwoEl3hR3FxRDRROTioMAlIiIiIiIiIiIi0kAgJuGaEGELSyhEowULFqQxY8ZkcasUcULYqgo77Sn0kNaF0rv88svTDTfckO677740efLk7FZx9erV6dSpU+0uvMUxx3xJe+clIpcOBS4RERERERERERGRBoLxq44ePZp27dqVrrrqqmwZNWrUqNSzZ88sNJUiTik+XUiE6miw5MJd4f33358tzTZv3pw2bNiQXS12FLWOWZFLpHOgwCUiIiIiIiIiIiLSQHz00UfZPeFbb72VraJGjx6devfunT7/+X/u7q1XEQdLrmHDhqXp06enyy67LItchw8f/q3xuJoLx0l9nD59Op04cSK9//77WQAsYd3bb7+drcUutktEEek4FLhEREREREREREREGgQEmnfffTeLQghaWEL169cvC0clCD/1KnIhbCHKjRw5Mo/DtXHjxixAVYWp5sA+iFtbt25N69atS0eOHMnjk8WxMz127FhatWpVWrNmTTp58mS71UvUcQQRubgocImIiIiIiIiISJfGTmppJBBvsNzCRWH//v3TkCFD8rhbYb0VLgkjBNX1ES4Vffv2zWOGAQLXzp07s6VVS+9B6gNRC/EKd4cIWIhecWykh2XXihUr0iuvvJLrju0ErMZwj4hARt6lMHYhiFcvdSnSVVHgEhEREREREREREWkAEFUQZY4fP57d7SFwYb2FRVQJYguCVz2KL1EWysx4XMOHD88C1LZt286JTy0B94RYaJHGlVdemV01Ys1WPWaELOKdOXMmvffee+ngwYNZWFu+fHlaunRpdpWI0FXmzzxxsZbbv39/Lh/5cR4IpEWa+/bty5ZolCG2i0jHo8AlIiIiIiIiIiIi0gAguOCekPG3EFJ69eqVrbcgRJdGAQEOK64bb7wxL2PBhSVWS8fIwuoKqy1AMLvmmmt+y10joiDpXnHFFVmwQkxbvHhxWrRoUbbqQuRiHaJhCFzEx20irg9feuml9Nxzz6U33ngjC1kffPBBFrf27NmTtz366KPpySefTK+//noWu8ISTaFLpGNR4BIRERERERERERFpABBfsDLCaqh79+6pR48eNa2VGgUsroYNG5aPAYsqjgsxqiXCEEIU+yBeXX311emqq67K60NgIiCcIQxi3bV3797061//Ov3sZz9L27dvT9dff32aPHlyGjp0aK5PhDfqGSs5LLueeOKJLIC9/PLL6Te/+U0WxBAYEbJY96tf/Sqvf/7559PChQuzcIbwRbka9byINAoKXCIiIiIiIiIiIgVaXUi9gtUWVka42xswYEAWdBCHGvWaRQBCVOI4OAYsphCiworqQrAPcZkilhHKscgAa6pdu3blemO8MqzeyAcBC0ss8sdNIqFnz555P6y8XnvttfTYY49l14UzZ85MN910U3ZRiKUXAteWLVvy/IgRI9If//Efp29+85tZKCN/rLuaewwi0noUuERERERERERERAq0upB6BXd8WHARcO+HWBOCTqPCWFxYUSE0MYYVQhTH2VzifkX8K8e/Yoq4tWPHjrRhw4YsOCFGTZkyJX39619PDz30UBbEVq9end0Mrly5MluRIR5i8YU7Qiy8KAvLiFt9+vTJbhBJG1eFbJs2bVqaO3dumj9/frrvvvvSggULsjUY5YqyiEjHoMAlIiIiIiIiIiIiUucgliDgIMAgcOGSj9DoAhdCEK4DcS2I5RSiVHPH4WJfLNgIiGO7d+/OQhQuC0kLV4GPP/54Hhtr0KBBaeTIkVlMQ5D6l//yX6Y//MM/zJZwK1asSL/4xS+ye0GsvdgPK6+JEyem/v37Z9eD69aty8LVrFmz0rXXXputv8ifeSzQCORxww035HWcmxDfRKRjUOASERERERERERERqXMQuBBucOFHQDxpdHELOC6OpQwtAWEM4QoLsFdffTX93d/9XfrpT3+afvjDH6b/9t/+W/r7v//7dOutt2aLLcQthCnEKlwQYj32la98JX33u99NN998c7b0euaZZ9KmTZuyQHXXXXelP//zP0//9b/+1/SXf/mXWRAbN25cLmNY0nFOSneErTkGEWkdClwiIiIiIiIiIiIiDQQWS4gznUFIQaQrj6OlAhFuBhk/a86cOdl6at++fdm94M6dO7Ml1be+9a0sTE2aNCmLYYDLQSy7/vt//+9ZEMNyizG19u/fny2/qFvEKyy5GE9r8ODBadiwYdklJC4UcU9IPNLjXJTl1S2hyMXjsr/4lLPzIiIiIiIiIiIi8imdQTiQzgXCCZZbiC4ILOPHj8/jQXXr1u1sjH+ika7dcLuIW0DGv8JV4ejRo9M111yTLaiaA8eLyMWYZNddd10WtXAViHvB2bNnZ+sthC8svIiLoIbFFeNn4Q4RIQu3j4hVY8eOTTNmzEijRo1Kx44dy5Zc1DX1fvjw4bR169a0ZMmSPO3evXuaMGFCuvHGG3OelIH0bTtEfhsEYYTnlStXfXqvdUvf/c63z25pG5/7tBFRUhYRERERERERkS5LtXvMDmqpR7hOsTxaunRpdsX34IMPpmnTpmVhp6SRrl+EJsQjxrhas2ZNGjFiRLrjjjvyWFcIdxxzc44n7mHEMlwGMoYXllWITghlZTrMEwdR6+TJkzngthCBq1+/fllcw4ILEeuVV17JFmHsE2NqkQfjdk2ePDmLW4zRRT7sIyK1QTB+5JFH0ve+/4PUu0/ftH7t6rNb2oYuCkVEREREREREREQaAEQWLIcIiDiERgdLqrfeeuucFRWhpWIRwhMBoQk3goh+PXv2PGcFVopkzJMHVleM3TVlypQ8/hYuDHFD2KdPn2zthYXcF7/4xTx219y5c9PMmTPTggUL0sMPP5zXTZ8+PVuKcS4Ut0QuDQpcIiIiIiIiIiIiInUOwgyCDW78EGAQhHD7hRVUo4JlFMeBwIVYhyiFYIQbwYsBdYo4heAVFlph7UU5cG2I+DV//vwccHnI8pgxY7K1l8KWyKVFgUtERERERERERLo0dGaLNAKIMGGddOjQofT2229nC6hGBVELcevMmTPZcgqrqlLgau29iUjVWtg3AvlT17ghJFD3iGEhhInIpUWBS0REREREREREujx0WEcQqVcYVwoXfIQQuBgTqtEIAYmxrw4cOJDef//9bBEV41m1x33YUgEqBK1q3k2lY3shculR4BIRERERERERERFpALBswj0hYhBWTydOnMjiUEvFnEtJlJXpu+++m3bu3JmFLsSta665pt3c/rVWfCr3U8ASqW8UuEREREREREREREQaAAQuXOYNHDgwC11Hjx49N35VI4CoFQIXY4cdOXIk7dmzJ3Xr1i0NGTIkjy+GqFTGaw2tEaaqwlYstyYtEbk4KHCJiIiIiIiIiIiINAi48EPgGjx4cBa49u7de86KqxHEmBCPsEDbtWtXOn36dBo2bFgaPnx4Hn9LYUlEmosCl4iIiIiIiIiIiEiDwDhcuCgcMWJEHn9r48aNeTwu3Py1xeqpI4lyhbgFhw8fTtu3b8/jiU2YMCENGDDgnHtCxS0RaQ4KXCIiIiIiIiIiIiINAuIPLv2w4MKl36ZNm7LIxXhcuP2rRyhziFxMEea2bduW9u3bl4W6sWPHZqFLYUtEWoICl4iIiIiIiIiIiEgDgRUXY1aNHz8+i0JLlixJO3bsOOeqsF6gLNXyIMIdOHAgrV27Ngt1U6ZMSddff/056y0RkeaiwCUiIiIiIiIiIiLSYDBeFZZPM2fOTMeOHUsvvPBCeuONN9Lbb7+dPvnkk7OxLg0haiG+hfUWU8pF+RYvXpzHD7v55puze8Krrroqx68ncU5E6h8FLhEREREREREREZEGAyuuQYMGZYFr8uTJ2d0fwhGWUW+99VZ2A3ipqLoaZBnLLcStlStXplWrVqXhw4enSZMmpb59+56LX91PROR8KHCJiIiIiIiIiIiINBiIQT169EhjxoxJd9xxRxaMdu/enV566aUsch0/fvy3LLlKC6mOsJY6X5pnzpxJW7ZsScuXL0/XXXddmj9/fh5/C9eE7Kf1loi0FAUuERERERERERERkQYEkYtxrMaNG5fmzJmTRo4cmQ4fPpxFpBUrVmSrrg8++OCceFRaSLWXtVQpTJFmVaxi/sMPP0zbtm3LlltXXHFFuvvuu7MwF64JoyzlfiIiF0KBS0RERERERERERKRBQRzq2bNnHstq9uzZafTo0dlaatOmTVnkwmrqyJEj6f33389uAttbRKoKZSyH0PXxxx9nt4SUBdeE5D9t2rQsbmF99vnP/3P3dOwnItJcFLhEREREREREREREGhiEof79+6cpU6ZkS64bbrghi0tbt25Nr776ahaXdu7cmcfmQvxCaOpISJ98Dh48mEW2p59+OotsCFuUkXG3cE0oItIWFLhEREREREREREREGpSwerryyiuzyDVx4sQ0c+bMNGrUqLzt0KFDafv27WnNmjVZ6NqxY0c6evRoOn36dProo4/aZNHFvuX+zOMSkfG/ENdefPHF9MILL6Rjx46lsWPHpptuuimPv6W4JSLtgQKXiIiIiIiIiIiISAMS4lKIXAhHWEdhKTV58uQ8Ntf111+ft2G9tXfv3rR58+a0du3aPN2/f386ceJEq626yJfAvoyzFcIWVmMLFy7M1luUCauyGTNmpAEDBqTLL7/87N4iIm3jc582go7cJyIiIiIiIiIiItJgVAUulmP+vffeS4cPH0779u3L7gGx2MK6ChCZGAPr6quvTn369MnTfv36pV69eqWrrroqi1IhXkV6JeRDwA0iY3uR9qlTp3Je27ZtS7t3787rBg8enGbNmpWmTp2arr322nTFFVfULKuIdG6w4nzkkUfS977/g9S7T9+0fu3qs1vahgKXiIiIiIiIiIiISANSikTRzcv085//J8dduCBE6KJzGdEJiy1EKfZhG4IXcRG2cG+ICNW7d+/UrVu3LHIhSCF4hTCFpRb7Ya2F1dc777yTx9nCDSIWYgSEre7du2eXhAhbI0eOzAJaVcxS3BLpOihwiYiIiIiIiIiIiEiTlF29CEgsExCkTp48mcfewpqLzmZcEyJ+sR2RKwQs4hJC+GLMLIQvrL4QxxCwcEVIWm+//Xb65JNPclxEMKzBhgwZkkaPHp2GDx+ercIQuxxzS6Rro8AlIiIiIiIiIiIiIs2m7PpFvMJiC6GLzmZEKgQqrLBwM8g25rHy2rNnT55HsLrhhhuyaNWzZ88sgmG5hTtCrLUQyHBDiJg1cODAPN4X42xdc8012QViuDoUka6NApeIiIiIiIiIiIiInJfo7g1hCWGL+VJoYh2WV4hUuBhE9IrtjNu1YsWKtGXLluyqcNKkSWnUqFGpb9++WbTCIuvKK6/M2yKEK0PmsfSqJWpRrlrrRaTzo8AlIiIiIiIiIiIiIm0muoRD6CIA6xlPa9GiRWn16tXZKuvuu+/O42khXoUrw5iWAapTIE0C+4hI16SjBC5bFREREREREREREZEuRIhSuBAsrbGwzsJSC3eErGee8bd69+6dtxEHSy22YbWFtRZpVAUvCBGtXCci0p4ocImIiIiIiIiIiIh0cUKQQrhCsMKqC2GqKWutKtX15XJT+4iItAUFLhEREREREREREZEuTohXIUaFa8FYbo5IFfuEWCYi0pEocImIiIiIiIiIiIh0QUKIKoUtpmHF9fHHH6ePPvroM8JVhJJYjnQiLRGRjkSBS0RERERERERERKQLUkuIYh3jbCFwvf/+++nMmTPpH//xH89u/Seq+yloicilQIFLRERERERERERERDKIVd26dUvdu3fPIlcJ2xSzRKReUOASERERERERERER6YQ05UrwfCBgXXbZZVnkIlx++eU1Ra1argqbS3P2a0v6ItI1UOASERERERERERER6YS0xtoqBC7cEjIG1yeffHLRhSaFLRFpDgpcIiIiIiIiIiIiInVICD0ITYyH9e6776b33nsvj4v14YcffiZ89NFHOV5MQ5xCqIp0miN4hfUWccnvgw8+OLvls7C9NQJaFcUsEWktn/u0AbEFEREREREREREREalDEKhOnDiR9u3bl8UtXAYyPtZVV111zsoKoYnxskJwQqQClonPcmyLKd3CMcZWuY00d+7cmZ5//vkscN1+++1p8uTJ50QvQqQPkU6ZP1TTBvaLeAT2je7piFddLvcXkcbk2LFj6ZFHHknf+/4PUu8+fdP6tavPbmkbClwiIiIiIiIiIiIidQpWWIcOHUpr165Nu3btyoJWjx49suDENqy3mIZ4xDSEI8QhBK4YRyuEKLYhZIUIFfGJx7rjx4+nNWvWpHfeeSdNmDAhjRo1KgtqpEH6zBMvxLVSRIt8SzELIt4VV1yRt8U6juXqq6/OU5YpV8ByBBFpXBS4RERERERERERERLoYCD6nT59O27ZtS6tXr0779+/PghZCEcIP8yE0XXnllXl9uCkERKYIbEdcYh9CWIAR6CYOUQrLrb1792aLseuuuy4H1hOfOKRDfMQ1QLgCthPYFnmGOBXbQrAif9IZP358mjNnTho8eHBOu9pdHfGBbTEvIo2DApeIiIiIiIiIiIhIFyIEHcSgkydPph07dmThiXnWISCVolBYR7EN0aoUutgWohjxa8UBRKhTp05lazHyGTBgQLr++uvzthDCGJeLQBohaEV65boQo5iSD0Id4hnb2b9Xr17pwQcfTF/96lfTiBEj8vGISOdDgUtERERERERERESkC0IXLtZSCE4IRIhFBMSkUkgC5gmITYhIiEmxnrgRv6n9CIz5tWzZsmwtxvhbEydOzNZWwZkzZ3L+EOlECMrlmIYABpQLV4fDhw9Pw4YNO+eiUEQ6HwpcIiIiIiIiIiIiIl0UunFL66gITcG2ELeCiF8VokqIg8D19NNPpzfffDPNnz8/zZo1K3Xv3v1cXNIlnC+d6nJQlhmLrbA6K90ZikjnQoFLRERERERERERERDoUuovfeuut9OSTT+ZxvxYsWJDHyMKdYHsKUNEtTZohxDFf5lHtuma5GkdE6p+OErh0aioiIiIiIiIiIiJykUGsqQo4Jefb1tFgTUX+uEUkhNVYR0F+tSy4Ik8s1xgXjDHIcJv4/vvv5/UQcS5lfYnIpUGBS0REREREREREROQiU8sSCZEmwqW2UqIMjJlVujksy9dWah1/SdQBU8YdW7VqVfrhD3+YHn/88bRz5848DljECdqjXCLSOChwiYiIiIiIiIiIiFxCEGYQk7CWClGpo8Qa0i3TrpUP1lSMi4V4VJblfIJUR4LFFqLWSy+9lJ566qn08ssvpz179uT11eMRka6DApeIiIiIiIiIiIjIJQIB6Z133kkHDhxImzdvzm743n777Sx0dQSIVBcSqi6//PLUo0ePdNVVV51d808gJDVn//Yg8mB6xRVXpO7du6du3bqlrVu3pl/+8pd5jLAtW7ak06dP5zq8WOUSkfpBgUtERERERERERETkIoMog+u9ffv2Zfd7zz33XHriiSfS66+/nsWuDz74IMfpaGqJQghcISiVY2NdbAEpRCsErmuvvTYNHDgwz+/evTvX17PPPpvWrFmTDh8+fM6aS0S6DgpcIiIiIiIiIiIiIhcJLLNOnjyZRRrEmeeffz4tWrQoWyYh0PTs2TOLS7gIRFy6VJRuCi81lKNPnz7puuuuS8OHD0+DBg1KJ06cyGIgdffGG2/k+sSa65NPPjm7l4h0dhS4RERERERERERERDqAcnwoplgZ7d+/PwsyuNj71a9+lV577bVsrTVu3Lh0//33p3nz5qVhw4b9lnvAi0VYTdUTCFx9+/ZN11xzTa6bqVOnZqHr1KlTaf369Wn58uXZCm779u3prbfeSh999JHWXCJdAAUuERERERERERERkQ4ghCIErEOHDqXVq1enp556Kj322GNZkMGaC7EGYeuuu+5KEyZMSP3798/i1qUUmcgbN4W4A6wHsYuyIG5h2UbdjBkzJs2YMSO7LETMwkXhtm3b0rp167LghTUX4lcta64QHRXARBofBS4RERERERERERGRdgYB5cyZM+no0aNp48aNecwohC3c6n344YdpypQp6Stf+Up68MEH0/Tp09PQoUNTjx49zrkFvJTCEmW/8sorL7nQFoSLwl69emVBiyl1duONN2bRi3p+5513soi4YcOGXMebNm06NzZXOZZZeTyKXCKNjQKXiIiIiIiIiIiISDuBaBLjbGFV9MILL6Rf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oaY14kBXhHqKIK2nufVXFcIQo+bMmZOGDRuWXn311WxxhRDVUsEsiP1Id+rUqdmi8b333ssWj4z7FW4QW5u+iDQPBS4REREREREREZEuBhYmH374YXapxrhES5YsyVZbdPz36tUr3XXXXenhhx/OosD111+frbiq42qBHfhSz3B9EhiPa+TIkdm9JiIZAu6bb76Z3n///RZfw8QPoY17ol+/fmnatGnZDeKePXvSihUr0v79+7NFpIh0LApcIiIiIiIiIiIinZzoxGf60UcfpVOnTmVLE8YNQthatmxZXo8lyj333JNuvfXWNHr06NS7d+/fErbCEimCSL0R12V5nXItT58+Pc2cOTOdPHkyrVq1Kh04cCALvdBcoat6zeMCkXtl9uzZ2eoRkZi0T5w4oatCkQ5GgUtERERERERERKQTUnbYR6c8FiuHDh1Ky5cvTz/4wQ/SwoULs7A1Y8aMdN999+WxisaOHZvdEV5++eW/1Zkv0qgg1CJyIUSNGDEi7d69O4tRCFFhlcU07puWCF5XX311Fodvv/32LGotXrw4j8d15syZZqcjIi1HgUtERERERERERKQTUXbSA67SGGOLDv2lS5emp556Kr3++uupf//+2QUh7gjnzp2bxowZkzvqr7jiitxpXwawo14akep1e+2112YxiinjziFEVa2tWnqtI55x74SFGKLxCy+8kLZt25bH5vLeEekYFLhEREREREREREQ6IXSqY0Fy8ODBtHLlyvTMM8+kNWvWZMHrxhtvzMLW/Pnz0/jx47PYhau1WuNsBSF0iTQyWCYOGzYsTZ06Nd8jWHExHldbra1I97rrrssCFy4LcVP4yiuvpL17955zgygi7YsCl4iIiIiIiIiISCcCIQoLkmPHjmXrFNylEY4fP5479rHWwpXapEmT8phBPXr0yPtgwaKliXQ2SmE2ru9evXqliRMnpgkTJmTrRkSuw4cP5/sG2Kc1gi4iF+4PcYOIaPzaa6+dc4PoeFwi7Y8Cl4iIiIiIiIiISJ1TCk9NiVB0oDPG1v79+9Pq1auzi7Tnn38+d9zT6X7HHXd8xmLrqquuyp341bSbSl+k0Ynr/bLLLsvjzOGqkHsDK8cVK1ako0ePpk8++eRs7NbRvXv3bCF5//3352WsJjdv3pzeeecd7y2RdkaBS0REREREREREpM65kDXJBx98kI4cOZLWrVuXRa1FixblMbfoxL/55puzuDVt2rQ0cODAJl0RttZqRaQRwdqK++Gmm27K98mGDRvSli1b0qlTp87GaB3cW/369ctWXLfccku2nMSSa9euXdkNooi0HwpcIiIiIiIiIiIiDQrWJrg/o2M+XBHSkY6IhaD1wAMP5E72IUOGfEbYwpJEQUu6GlULKu6JkSNHZnedbMOd4J49e/KYWWXcC1lesT0CIJ4NHjw4j3N3ww035DG+sBA7dOhQdoN4ofREpHkocImIiIiIiIiIiNQ5Zec5ohTzJ0+eTFu3bk0vvvhidke4bdu27B7t1ltvTQ8//HBasGBBFrZ69uz5GWELSmGrKnIpeklnhWu7en337t07j8WFyMW4dStXrkxvvfXWZ8bMau49UcbDDSLi2W233ZZdgmIhhqtC7lsFLpH2QYFLRERERERERESkDihFrJJyHRZbuFDbuHFjFrWeeeaZPMbPFVdckV2iPfjgg9liC+sRxK5arghrER3zze3IF2l04r7iHrnmmmuyxePw4cPTjh07sktBhKiWjMdV3jvMExjnbty4cWnevHlZMGNsPITod9999zMCmoi0DgUuERERERERERGROiI63kvBi+l7772Xx9V69dVX069+9asscNEJP3369OyKcO7cudkdGhYpCF4tFasUt6QrwfUe9xj3C6Lw1KlTszC8cOHCtGnTpixExT14Ppq6d1iPeDZlypRszbV9+/b08ssvZxGN8bgifxFpHQpcIiIiIiIiIiIil5Do5C47yWOZKWP24DKNMXx+/OMfpx/96EfZlRrC1u/8zu+k++67L40ePTq7IqzV0R7pA9trxRHpqsS90aNHjzR+/PgsciFsPf/881lQ5v5rKZEm4KrwuuuuS3fccUfq169fWrVqVVq2bFk6evRothDzfhRpPQpcIiIiIiIiIiIil5AQnegUj85u3Je9//776dChQ3lMoKeeeipbfnz88cfpzjvvTH/4h3+Y3RGOGTMmXXnllXmfpoj0ReSzxL0R90evXr2ytdU999yTjh8/nl0Kcg9WXRWWAlYtyvuNeSzEsOB66KGHsstChDOsuU6cOKGrQpE2oMAlIiIiIiIiIiJSJ9CRjivCgwcPpvXr16fly5dngQsLrlGjRqV77703C1s33XRTtgphjJ+yM11EWkZ5/1x++eXp+uuvz+4+b7zxxixCYXHFuHelENXSe45xvrAQmzRpUpozZ07O54033shuEN95550LCmYiUhsFLhERERERERERkUsMnedYZ7399ttpy5Yt6bnnnkuPPvponqfD/a677srjbM2cOTMNGjQojxNEp3kVxS6R1oPQhGg8fPjwLHLBokWL0ptvvnluzCxgGuFCRBzuV8bjQuTCimvfvn1pyZIlefrhhx82Ky0R+SwKXCIiIiIiIiIiIpcIOrXp3GY8ng0bNmRXhD//+c/Ttm3b8rhat99+e5o/f362Jrn66quzO0JFLJGOBZeC3H8IyozH9cQTT2SxuRS5oDn3YhkHkQvLyxkzZmT3ogcOHMiuR48cOZIFblDoEmk+ClwiIiIiIiIiIiLNpLWdz+xX7ovFFp3lIWy98MILaeHChenw4cO54/u2225Lt956a5o4cWLq37+/wpbIRYB7LALjcU2ePDmLUQjOuBTcv39/FqIiTmvgXh4yZEiaOnVq6tOnT1qxYkVas2ZNdkOKi9LWpivSFVHgEhERERERERERaQYIVK3pfI79COGK8OTJk9nt2dKlS7MLtL1796Zrr702TZ8+Pd1xxx15nJ4RI0bkDvDLLrus1cKaiLQOrK0GDhyYheaRI0dmCy7GxePe5T4O0bql9ybp9uzZM7spROTCWox2YOvWrVn0FpHmo8AlIiIiIiIiIiLSDFprWRH70Sn+3nvvpZ07d6Zly5alF198MVuGIGJhJXLvvfemWbNm5fF/+vbte85qK4KIXFwYjwtxi/HvsOjavHlz2r59e76PW0MIYohcWGZyv8+bNy9bb9EmMB5XSwUzka6MApeIiIiIiIiIiEgT0Nn8/vvvpxMnTqRTp06ljz76qMUd0Ahbp0+fPmex9eSTT6aVK1fmTu6bb745j7OFwDVs2LDciX755Zef3VNELiUIyz169MiuCm+55ZYsbC1fvjzt2LEjW1uF+BzCVUsIV4WIXGPHjs3tA2nTVtBmiMiFUeASERERERERERGpAa4Ejx8/nl2HEY4dO/ZbAldTndqsD1eEWGy9/vrr2WLr1VdfzR3jWIXghpDObVwRYrGFK0IRqS8Qonv37p0mTZqUrStpCxCiDhw40GLBu7TEZD9ErqFDh6aZM2fmPF577bUsfiOoK3KJXBgFLhERERERERER6fJUO6k/+eSTdOjQodzh/MYbb+R54oQIxTyhlvUG81h94W6MjvAnnngiLVmyJL399tvZSuvOO+9M99xzT5o4cWIWthiDp+z4FpH6gvtzwIAB2dKSsfJwVRjjcZX3fnOoilzdunVLN910U7YQ++CDD9Kjjz6a02+tG0SRroQCl4iIiIiIiIiIdHmi05kOZywn9u7dm15++eVsecU6hKnrr7/+M2IU6wksxzqELfbFUuuxxx5LixcvzpZfWH7cfffd6Utf+lJ2d0YnOdYbVcrObxG5tHB/B9yvWF4yVt7VV1+dNmzY8BkhqiX3brQZBCzErrnmmmzNiVXn2rVrc/uxZ8+ebCEmIk2jwCUiIiIiIiIiIvIpdGYjUG3ZsiVbXWG5RUf29OnT8xg5PXv2zJ3R0ZFddmjjjnD//v3ZUuvXv/51eu6557IF18CBA9N9992X7r///uzirH///ql79+7ZEqzcX0Tqj+o9Gq4Kp0yZksfkw0ITQRvLq7ZAezBo0KBsxTVu3Li0Zs2a3P5g9amrQpGmUeASERERERERERH5FCwxNm7cmH70ox+lp59+Ondm33777Wn8+PGpV69eWdwKiw46vglYWBw9ejRbczz11FPpxz/+cXrllVdy/AcffDB94xvfSHPnzs2d11dddVXep7QKEZH6h3uWQBvQp0+fLHAhVtNerFq1KltpVoWolt7ntA+jR49O3/zmN7Ngjni2adOm9M4779hmiDTBZX/xKWfnRUREREREREREuhx0Hp85cya7BvvJT36SO5bvuOOO9OUvfzmLW4yRE5YcIVAhbJ04cSJt3bo1Pf/883ncnCNHjqQJEyakL3zhC9lqC0sMRDKsM6KDOoQxEWkcynsWkQsxqkePHlnY2rlzZ77PcTvKemjNfU4bcfnll6fBgwfn6bZt2/LYf9ddd122JHWsPmlk+IEEq8SVK1d9ep90S9/9zrfPbmkbWnCJiIiIiIiIiEiXhA5lrC5wS8hYOi+88EI6fvx4+spXvpLHyhozZsw5qysgLq7IiIPlxpNPPpldGTJWDkIY+yCKzZ49O4/XxZg9dIaXkGeIXSLSGHDPhmjFPKI37cP8+fNT3759sxXX+vXrcyd+W+5v0qfdmDFjRnaNitvTZcuWpd27d6cPP/zwbCwRCRS4RERERERERESkS0JHNOLWrl278phZTGfOnJkFLqyvsNCgwxlhC4stxtwhzuuvv54WLVqU/0ZnPC1cEH7ta1/Lnd0jRozI7gmxwAhhLIgO8up6EalvqvcswjXC1sSJE/OYXCdPnkxLly5NBw4cyCJ4a0Susm0YMGBAmjVrVho5cmS25GJMLlyhfvLJJ3m7iPwTClwiIiIiIiIiItIlQbTCMmLhwoVpyZIlWdTCtSAiVTleFh3WuApD0PrlL3+ZnnnmmWypcdddd+Uxtu6+++40fPjwLGzhjrDaGU4a1XUi0pjEvYzIhftArK2GDh2atmzZkq2t3nrrrd8aj6sl0F7Q/tAe3X///dmiizH+cIfKeFykTZzWiGginQ0FLhERERERERER6XIgbmFtgWiFe0LcCt5+++25oxqR6uOPP05vv/122r59e1q8eHH6+c9/nl588cXUs2fPPD7XQw89lG699dY0aNCg7K6sdEVY7XxW3BLpXMQ9zr2NO9Jbbrkluyx8+eWX0+rVq7PI1VYBinZl7Nixub0hLSxHseZCXAfbFREFLhERERERERER6WLg5gvxCqsILLiwvkLcooMaa4nTp0/n9StXrkzPP/98dg+Gy8GpU6emefPm5c5srCv69euX45cdzW3t1BaR+qe857G2wpUgY2bhsvS1117L1lxYfrYFhHbcIE6ZMiW3TYcPH84iF+NyIdCLiAKXiIiIiIiIiIh0ckrRCfdejKWF1Rad0FdffXW655570uTJk/OYW1heIGg9+eST6ZVXXsljdCFm3XnnndklIePtMD4OHdl0cpN2mT7rIohI5yXucaa0I7QNiN+MlYVl6JEjR1o8Zla0JdGGIHJhIXbzzTdna9E333wzbdy4MQv0WJlW2x+RroYCl4iIiIiIiIiIdGqiI5qOYMStTZs2pVWrVqXevXufcy2G269169Zliy2ELYSwiRMnZvdgWG3hKgyLrdIdYXRCR/oi0jVBiGI8Llydjh8/PgtRtCNYXSFEtYRqe4KVKBZic+bMyW0QAhdtVYzHZfsjXRkFLhERERERERGRBib+4C//4i/Xleuhuq0MnRmOjw7hrVu3ZoErxre54oor0vr169PTTz+dx9g6ePBgGjZsWJo7d24Wtuis7t+/f3ZDFunQqRwBCw1ckSGQ4TaMdS2ty6j/pvYrt7cmiEjHUArcCFG0HYjmiOePPvpoWr58ebYKpV1oLtV7lvR79eqV2yLcpNLWLF26NFuhYmHqPS5dGQUuEREREREREZEGo6UdmhG/q3aEctzvvvtu2rFjRxa3mMfdF53OjMNFZzGWFtdee22aMWNGHo8rXBEihNHBjJBFxzLux/bu3ZstNBDL6GRmumfPnjx2F/FaUs8dfU607hDpeELoQghHOJ82bVo6fvx4WrRoUXaFihDVFrAQu+aaa7Ir1dGjR6dDhw6ll19+Oe3bty99+OGHZ2OJdD0u+4tPOTsvIiIiIiIiIiINQClaRMdqU+vKbbXWl6GzgYCFdRUdzQhRr732WrbQohMaYQlR6uTJk1nYwjICCwncjLGN9ceOHcvj6BDYD4GM8blIB1EMF2SrV69OJ06cSJdffnkeh4exueiMbqo+SbvcVtY/oRS8Il41TkuCiHQ85T2HVSjj+dH2IKDTHgwcODD17ds3z5+P8923uEZFcCfganX79u3Zaoy0sfBqaj+ReoAfRBibbuXKVZ8+g7ul737n22e3tA0FLhERERERERGRLkRVYOmsYEn19ttv5w5mOtVeffXVbL2Fm0JcCbINqwpciYWohTUE1hZr16492xG3MltnYbGF5RZCFgHxi3TOnDmTxbJRo0ZlqwpcGdL5fD6Bq7o+BK1YzzSCiDQW0b4idNOu0HYcOHAgtwlYhCJ8xRh+LYW0SYc0ELb279+f0+/Zs2caOnRoFtltN6Re6SiB63Of3hhd0zZdRERERERERKTOKbtt6LiMztOSWusuBtUupeaWIfbr6DLjtgtxauHChdnqCissRC86ngn9+vXLghTWFh9//HEWvcK9YFh+0RGNdRfuDOmcJj6dydGRzHaWcR3GNDquW3JsHV0fl+r6EOmKcL/FPUe7gpXnr371q9w2fPGLX0wzZ87MllytuSfLe5lxvRgz8Mknn8xt1B/+4R+mG2+8MQtfIvUIFtGPPPJI+t73f5B69+mb1q9dfXZL21DgEhERERERERGpY8oOU6aIL4gxpSBTwvbYB8rtsa1KNU5QjcsyoRonyhbLQTkf1FpXwvaIU3YCXyhdKONTP1hkMQYOAhdWV1hb4coLqy0CncHsQ+dznz59sotBOp8Rs3D7xTr2QdACjpvAPhHKsoTAVYU4Zdkg9o/5oNZ8rXhBrW3MUxbKTUDEO59VmYi0jabaJKxWnn322SxGIZQ/8MADady4cVlkD2q1DxeCdgi3qT/72c/yWFxTpkxJ3/rWt3K75b0u9YgCl4iIiIiIiIhIF4XOTDpKcY9HJxEBwQYro7Jrh3lELwL71NrGNEItWF9r35hG2rFcTmM/QsSB2F52upbxYnu5X3WfWvGBeeKUodyOpcPhw4ezNQWCFcJW6UaQKcuIQCyTPstYZLEu8uS4Q1SM/QgQ+UWaLJdlANYTYh7iWBGjYns1TqyLOFXKfYHyQRwDx4u1Woh3pQVarfREpHXEPR9T7i/uR8b6Q+BatWpVHufvjjvuSGPGjDknsLcW2v+NGzemX//61+mFF15I/+pf/at01113ZSEt2iaRekGBS6RO4RYqH0bVZREREREREZHWggBCJybjRe3cuTO9+eab+a/9d999N2+jEzOshuJ7lHUhYJTfqEzDkodOVwLzEdiHKbBfVTiJaVCuL+OVVL+Ry3m2ESDW11oXxHKIQkGZB1NCpBF1g7jFOjqUscgiDts4XqZsI04E6oZ1EYKYZ59IG8p4MR/LUC07+5IPY3jhSjG2l/swT/zquoD5ELMglsO6j+Ww4OK4EfeGDBmSO9YHDx6cBS+OP/IWkbbDfRdtUMwz1h/uUn/5y19mV6mzZ8/OQhT3YYjorbkP2e/UqVNpxYoV6ec//3le95WvfCXNmTMni9ki9YQCl0idEbdOPITi4RXryhddERERERERkZbCtyVWW/z9v3r16uxmDzGEv/OHDh2aBQusdBAw4nuUb1M6TBE0QqyKjlO+UyN+CDjECZEnxK8yPvPxfRvroVbazEcIyKNcrgeq5Ym6K6m1LigFNuKFCBXra+1LnmVc6qsUuFgXAcq45XzkASzHeQTmI5AmgfSx9Dtw4EAWRrFkwz3a/Pnz0/Tp0/PYPeU5F5H2Ie7d4J133klvvPFGFqK45x566KE0a9asLDRHG0v8ltyLxKdN4B4n7R/+8Idp0qRJ6eGHH873OW26SL2gwCVSR9S6beJlFZjGw0lERERERESkuZTflfHX/5IlS7K4deONN+ZxVui4RJhAqOJbtPwejeWYr1LrW7Uar9Z+0NT64ELbOyNR71DOV4m6qcZhuan9asWt0lQcpgQ6v0PkwnJky5YtafPmzTkOViS33HJLuu6663JHeFc8fyIdDfcg9xZT3KUuXrw4LVu2LF1zzTV5PC5cFvbo0ePcvduS+zDucwKWXL/61a/S2rVr08SJE3Pa/AyhyCX1QkcJXJf9xaecnReRdqLWw8gXRREREREREWkuWN/s2rUrLV26NO3fvz+NHTs23XrrrbnjEkGie/fu2UorrK4Qu5hnGoH11YDAdaHA92trQlekVj20JNSq/wi1zl81lOe7DHEtcI1wrTAOV//+/bOLQlyXcX3t3r07p8EycchTRNoPhCfuc2AabTbWXHv37s2uRLn/sMblXox4zaEUxCLtXr16ZRENV7akx48Q3ttSL2CRjqXhypWr0lVXdUvf/c63z25pG17dIq0gHjbxMIFyvqSp9SIiIiIiIiJV+N7kO/LEiRNp48aN2a3c8OHD0x133JHFLTos6ciMePHNGfOxXIta284XX+qLlpyrMi6d29H5jUXHjBkzsms01nGN4QITa0GvBZH2JcSnANGJcbemTZuWxWbGVcT9LJYtuCxtC6TNs4L7G0GbdLdt25bFtNK1qUhnQ4FLpJXwgOIlMR5W5XwZYr2IiIiIiIhIc/jggw9yxyfuCbHWmjlzZho9enR2YxXfl4gR8d0Z863B79XGoSXnKq6N2IdrJK4TrEVGjRqVbrrpptyxjrUHVh+M3SUi7UspHHP/9ezZM40ZMyYLUYhSK1asSOvWrUunT59u0T1Y3t8BYyzi8nDevHnZNSmubbEExmJTpLOiwCUiIiIiIiIiUifwpz2iA+7j+GGSzsoRI0bkjsuSasdm0NR6ON826TpwXWHhQSc77su43hC42mpBIiLnhzY47j/czjKu4rvvvpuef/75PD4eLtxKQaw5kGbZtuPycNKkSfnHiAMHDmQBbd++ffnHiRC6W5qHSD2jwCUiIiIiIiIiUifQCYm4dfjw4exODnELi5vmCFfniyNdm+q1wThAuLskYDWCi0KmdnyLtC+12mUst/r165emTp2aRS4E5uXLl+e2v63WVjH2FgIXbhBJc+3aten48eNaaUqnRIFLRERERERERKRO4G9+/rpHcBg6dGjuqESMgKYELNYrbsmFKK8TpozB1b9//3TVVVdl6y3H6RHpGMp7DxGZeaxyR44cmebOnZtdhm7YsCGPm/X222/neG2Be5vnB24Qub8RuBiPCwuxQEsu6SwocImIiIiISKfDD3YRaURouxC46ITs1atXGjBgQHYhR2dotGvRSXo+ouPStlDOB5YeV1999blrTIFLpOMp23DGVWR8xenTp6fLL788uxNEjMKKqzXtN2lHQNgaN25cmjJlSh7f64033sjWXB999NFn4ok0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"
}
},
"cell_type": "markdown",
"id": "0",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"corpus_of_documents = [\n",
" \"Take a leisurely walk in the park and enjoy the fresh air.\",\n",
" \"Visit a local museum and discover something new.\",\n",
" \"Attend a live music concert and feel the rhythm.\",\n",
" \"Go for a hike and admire the natural scenery.\",\n",
" \"Have a picnic with friends and share some laughs.\",\n",
" \"Explore a new cuisine by dining at an ethnic restaurant.\",\n",
" \"Take a yoga class and stretch your body and mind.\",\n",
" \"Join a local sports league and enjoy some friendly competition.\",\n",
" \"Attend a workshop or lecture on a topic you're interested in.\",\n",
" \"Visit an amusement park and ride the roller coasters.\"\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2",
"metadata": {},
"outputs": [],
"source": [
"corpus_of_documents"
]
},
{
"attachments": {
"image.png": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABcsAAAJxCAYAAACdYupLAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAP+lSURBVHhe7P13lyXXed5/F2aQARJEJDIRiRwZQRIEKVISZdlej6y1vPyHl98K9GIky1q2bIWfAsUcRBKByDnnnEEiY/Ccz+6+D/YUzunumenc17dnT9WpsGOdqr2vfZ+7DtqzZ89HQwghhBBCCCGEEEIIIYSwg9m1uAwhhBBCCCGEEEIIIYQQdiwRy0MIIYQQQgghhBBCCCHseCKWhxBCCCGEEEIIIYQQQtjxRCwPIYQQQgghhBBCCCGEsOOJWB5CCCGEEEIIIYQQQghhxxOxPIQQQgghhBBCCCGEEMKOJ2J5CCGEEEIIIYQQQgghhB1PxPIQQgghhBBCCCGEEEIIO56I5SGEEEIIIYQQQgghhBB2PBHLQwghhBBCCCGEEEIIIex4IpaHEEIIIYQQQgghhBBC2PFELA8hhBBCCCGEEEIIIYSw44lYHkIIIYQQQgghhBBCCGHHE7E8hBBCCCGEEEIIIYQQwo4nYnkIIYQQQgghhBBCCCGEHU/E8hBCCCGEEEIIIYQQQgg7nojlIYQQQgghhBBCCCGEEHY8EctDCCGEEEIIIYQQQggh7HgilocQQgghhBBCCCGEEELY8UQsDyGEEEIIIYQQQgghhLDjiVgeQgghhBBCCCGEEEIIYccTsTyEEEIIIYQQQgghhBDCjidieQghhBBCCCGEEEIIIYQdT8TyEEIIIYQQQgghhBBCCDueiOUhhBBCCCGEEEIIIYQQdjwRy0MIIYQQQgghhBBCCCHseCKWhxBCCCGEEEIIIYQQQtjxRCwPIYQQQgghhBBCCCGEsOOJWB5CCCGEEEIIIYQQQghhxxOxPIQQQgghhBBCCCGEEMKOJ2J5CCGEEEIIIYQQQgghhB1PxPIQQgghhBBCCCGEEEIIO56I5SGEEEIIIYQQQgghhBB2PBHLQwghhBBCCCGEEEIIIex4IpaHEEIIIYQQQgghhBBC2PFELA8hhBBCCCGEEEIIIYSw44lYHkIIIYQQQgghhLXno4Xw0UcftRBCCCFsNg7as2dPnlAhhBBCCCGEEEJYklkC90EHHbS4Ngfi+MJ/ix/3jsP5y8YRQgghrBOxLA8hhBBCCCGEEMKSzLMEX9JCvHZNlo7b89Ge4aM9H7WwZ89kPdblIYQQNhmxLA8hhBBCCCGEEMI+0QvdsyzD2/5FkXz62XJRQS+L8gqzhPNZ8YYQQghrSSzLQwghhBBCCCGEsM8QuCv01GeW5BVAKK99s4Tyiqs+hxBCCOtNLMtDCCGEEEIIIYSwIsp9yltvvTX8/ve/Hz788MO2/ZBDDhmOOOKI4dBDDx127949tQp37J4P97Tj3nv/veG9994b3n///RYc4zzhsMMOa+fu2rVren7FEUIIIawXEctDCCGEEEIIIYSwIojewssvvzy8+OKLw7vvvtsE8SOPPHI47rjjhk996lNN/D744IOnYjeBXCCu/+53v2tLwX4C+1FHHTV8+tOfHo4++uipeE40j1geQghhvYlYHkIIIYQQQgghhBXxyiuvtPDwww8PDzzwwPDmm2828ZzY/bnPfW44/fTTh5NOOqkJ58VLL73UxHXB+quvvjq89tprTWQnlB977LHtnDrP58MPP7yFCOYhhBDWk4jlIYQQQgghhBBCWBEPPfRQCzfffPNw0003DS+88EJzqXLCCScMl1566XDJJZcMF1988XDOOee047lteeSRR1p48sknh6eeemp4/vnn23n2EdlPPPHE4ayzzmpiu6Xwmc98poWI5SGEENaT3ddff/1fLK6HEEIIIYQQQghhh1Iv1qwliNVE7d//7vfDq6+9Ojz++OPDY4891qzLywWL/R988MHw9ttvN0tz6++8804TxIUSyPk5dyzf5FyusCrnrsXx3LK88cYbLT37BS5derFcWuO8hRBCCKtJLMtDCCGEEEIIIYTQhOh6YSchmt9wELOffebZ4ZlnnhkeefSR4dFHH21iNrGbwP3ss88OTz/9dLMcd+y55547nHnmmdOXdhblm9ySj3P+y4nvZXFOTL/yyiuHK664Ymqh7vzdu3YPH03+CO3y1ectgnkIIYTVJJblIYQQQgghhBBCaJTldv+CTW5WHnv8seH+++4fXn7p5eH3b/2++Re/4IILmqsUsCgnohO9vcyTlbnzxOMlnscff/xwyimnNFcrhHRL1uWOJbgT24nxJbCzKncOoXz3wbuHgyZ/BPMSyytvEctDCCGsJgtTsSGEEEIIIYQQQtjx7N69ey+hnHhO9OZO5YEHHxhef+P19uJNL+Ikfp988snNXzlx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rXYskVjoxfKyuhY2E8sJ07V/uSWqjLU84ogjhs985jPDscceOxx33HHDpz71qcUjl6aPc7ujrqq++jqtEEIIO4WI5SGEEEIIIYQQwhahRM0SMN99993hnXfeGR588MHhgQceGJ5++ukmmrOsPvTQQ/cSy1HnCz19nGvNOP1xXuZR+bMcr9dnKK/JBJMI77333vDpT396OP3004ezzjprOP/884dTTz118cil6ePciozrdV55qj1MxAhVn/2vEurcinNeXCGEsNWJWB5CCCGEEEIIIWwRerHSeonl99xzz3DXXXc10Vx48803pyJnL3palsU5QdlnrIcIWmmwXq5gW7/eB9SymLW98lzLKi/hl2B+wgknDOeee+5w0UUXDV/4wheG8847b1ofS7GWdbHWqB91ir5++jLVMSZWXEevvfZaC4cddlgLRx111HD00Ue3SZf6JUPV+1aumzHKVKEY19Vq0Mc/ZlZ64+OX2r/aeQ1hJxOxPIQQQgghhBBC2CKMBVCW08ROYvndd9893H777cMtt9zSrMuJ6GUpTBzms5vwWSJo+fEeC21rJbyVIFkitjBeF3rhvF+vz46terCtliWS9+coy8knnzx8/vOfH6666qrhm9/85nD55ZdPJwuWYq3qYT2oeiyqbqBcVT+uHRMrRPJHHnmkBZb43Naccsopw2mnndY+u07qfGzluoGyF9bH9aV8fXlXkz7totqn6rXapz92vL9fLtceW729QlhPIpaHEEIIIYQQQghbgF48I34JxE7iMZHz4YcfHn77298ON9xwQ/v88ssvNx/mznEswZPFML/d5b/b8vDDD28ieomDayWsVf5LHF9JUL4qo2BywCSAZe0vkb3qpP+sTJ/97GebNTmr8u9+97vDF7/4xeHII49svsyXYq3qYT2oOihmibHq7ve///3w1FNPDU888cRw7733Dvfdd1+rr5pguPDCC5tlvuvGBEOxleumrkNBHbmOXFPqwzaYSBHq8zyW2z9m3vHqtiYk6nsI9VzXcd9+EBeBv/YvxVZurxDWm4jlIYQQQgghhBDCFqEX2whgxD6CGWH8pZdeGu64447h5ptvblbm3LF48WcJygQ1gtxJJ53UBNELLrigBZ8J5wTztRTV5F0oIVe+K9Q2eSWEv/322+1FpQJBt9aJ/2+88UazhrZuH6GzrOj7OJVFYCXNTzmL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"
}
},
"cell_type": "markdown",
"id": "3",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {},
"outputs": [],
"source": [
"user_query=\"i am an indian and i live in india\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5",
"metadata": {},
"outputs": [],
"source": [
"document=\"india is a country for the indians and for eveyone\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6",
"metadata": {},
"outputs": [],
"source": [
"from collections import Counter\n",
"import math"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7",
"metadata": {},
"outputs": [],
"source": [
"query_tokens=user_query.lower().split(\" \")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8",
"metadata": {},
"outputs": [],
"source": [
"query_tokens"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9",
"metadata": {},
"outputs": [],
"source": [
"document_tokens=document.lower().split(\" \")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10",
"metadata": {},
"outputs": [],
"source": [
"document_tokens"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "11",
"metadata": {},
"outputs": [],
"source": [
"query_counter=Counter(query_tokens)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12",
"metadata": {},
"outputs": [],
"source": [
"query_counter"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
"metadata": {},
"outputs": [],
"source": [
"document_counter=Counter(document_tokens)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "14",
"metadata": {},
"outputs": [],
"source": [
"document_counter"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15",
"metadata": {},
"outputs": [],
"source": [
"lst=[]\n",
"for token in query_counter.keys():\n",
" lst.append(query_counter[token])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "16",
"metadata": {},
"outputs": [],
"source": [
"user_query=\"i am an indian and i live in india\"\n",
"document=\"india is a country for the indians and for eveyone\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "17",
"metadata": {},
"outputs": [],
"source": [
"#sentance vector\n",
"lst"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18",
"metadata": {},
"outputs": [],
"source": [
"for tokens in query_counter.keys() & document_counter.keys():\n",
" print(tokens)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "19",
"metadata": {},
"outputs": [],
"source": [
"mylist=[]\n",
"for tokens in query_counter.keys() & document_counter.keys():\n",
" mylist.append(query_counter[tokens]*document_counter[tokens])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "20",
"metadata": {},
"outputs": [],
"source": [
"mylist"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21",
"metadata": {},
"outputs": [],
"source": [
"dot_prod=sum(mylist)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "22",
"metadata": {},
"outputs": [],
"source": [
"query_magnitude = math.sqrt(sum(query_counter[token] ** 2 for token in query_counter))\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23",
"metadata": {},
"outputs": [],
"source": [
"query_magnitude"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "24",
"metadata": {},
"outputs": [],
"source": [
"document_magnitude = math.sqrt(sum(document_counter[token] ** 2 for token in document_counter))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "25",
"metadata": {},
"outputs": [],
"source": [
"document_magnitude"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "26",
"metadata": {},
"outputs": [],
"source": [
"similarity=(dot_prod)/(query_magnitude*document_magnitude)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "27",
"metadata": {},
"outputs": [],
"source": [
"similarity"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "28",
"metadata": {},
"outputs": [],
"source": [
"user_query=\"is yoga good for health\"\n",
"document=\"yoga is very good for living healthy lifesytle.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "29",
"metadata": {},
"outputs": [],
"source": [
"def cosine_similarity(query, document):\n",
" # Tokenize and convert to lowercase\n",
" query_tokens = query.lower().split(\" \")\n",
" document_tokens = document.lower().split(\" \")\n",
"\n",
" # Create Counters for query and document\n",
" query_counter = Counter(query_tokens)\n",
" document_counter = Counter(document_tokens)\n",
"\n",
" # Calculate dot product\n",
" dot_product = sum(query_counter[token] * document_counter[token] for token in query_counter.keys() & document_counter.keys())\n",
"\n",
" # Calculate magnitudes\n",
" query_magnitude = math.sqrt(sum(query_counter[token] ** 2 for token in query_counter))\n",
" document_magnitude = math.sqrt(sum(document_counter[token] ** 2 for token in document_counter))\n",
"\n",
" # Calculate cosine similarity\n",
" similarity = dot_product / (query_magnitude * document_magnitude) if query_magnitude * document_magnitude != 0 else 0\n",
"\n",
" return similarity"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "30",
"metadata": {},
"outputs": [],
"source": [
"cosine_similarity(user_query,document)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "31",
"metadata": {},
"outputs": [],
"source": [
"def return_response(query, corpus):\n",
" similarities = []\n",
" for doc in corpus:\n",
" similarity = cosine_similarity(query, doc)\n",
" similarities.append(similarity)\n",
" return corpus_of_documents[similarities.index(max(similarities))]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "32",
"metadata": {},
"outputs": [],
"source": [
"corpus_of_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "33",
"metadata": {},
"outputs": [],
"source": [
"user_input=\"i like fresh air.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "34",
"metadata": {},
"outputs": [],
"source": [
"relevant_document=return_response(query,corpus_of_documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "35",
"metadata": {},
"outputs": [],
"source": [
"user_input=\"i like to do yoga\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36",
"metadata": {},
"outputs": [],
"source": [
"relevant_document=return_response(user_input,corpus_of_documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "37",
"metadata": {},
"outputs": [],
"source": [
"relevant_document"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38",
"metadata": {},
"outputs": [],
"source": [
"# how you can configure llm in your local system\n",
"# LLAMA2\n",
"#hugging face(we are not going to use this one)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39",
"metadata": {},
"outputs": [],
"source": [
"# augument this response by using llama2 model"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "40",
"metadata": {},
"outputs": [],
"source": [
"import requests\n",
"import json\n",
"full_response = []"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41",
"metadata": {},
"outputs": [],
"source": [
"full_response = []\n",
"prompt = \"\"\"\n",
"You are a bot that makes recommendations for activities. You answer in very short sentences and do not include extra information.\n",
"This is the recommended activity: {relevant_document}\n",
"The user input is: {user_input}\n",
"Compile a recommendation to the user based on the recommended activity and the user input.\n",
"\"\"\"\n",
"\n",
"url = 'http://localhost:11434/api/generate'\n",
"\n",
"\n",
"data = {\n",
" \"model\": \"llama2\",\n",
" \"prompt\": prompt.format(user_input=user_input, relevant_document=relevant_document)\n",
"}\n",
"\n",
"headers = {'Content-Type': 'application/json'}\n",
"\n",
"response = requests.post(url, data=json.dumps(data), headers=headers, stream=True)\n",
"\n",
"\n",
"try:\n",
" for line in response.iter_lines():\n",
" # filter out keep-alive new lines\n",
" if line:\n",
" decoded_line = json.loads(line.decode('utf-8'))\n",
" # print(decoded_line['response']) # uncomment to results, token by token\n",
" full_response.append(decoded_line['response'])\n",
"finally:\n",
" response.close()\n",
" \n",
" \n",
"print(''.join(full_response))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "42",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
================================================
FILE: RAG_Fusion.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "EpLLP3t0mvaI"
},
"source": [
"# RAG Fusion"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RRYSu48huSUW",
"outputId": "d1881d05-974b-4747-975b-a2dc7a3da3df"
},
"outputs": [],
"source": [
"!pip -q install langchain huggingftiktace_hub oken pypdf\n",
"!pip -q install google-generativeai chromadb\n",
"!pip -q install sentence_transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "nEGa4_ghPMBt",
"outputId": "69bcd619-304d-4eb8-e170-2c54fc44214d"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Fw9wTjZG9I30"
},
"source": [
"### Download the Data & Utils"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "jZpiqO_eM9ZF"
},
"outputs": [],
"source": [
"import textwrap\n",
"def wrap_text(text, width=90): #preserve_newlines\n",
" # Split the input text into lines based on newline characters\n",
" lines = text.split('\\n')\n",
"\n",
" # Wrap each line individually\n",
" wrapped_lines = [textwrap.fill(line, width=width) for line in lines]\n",
"\n",
" # Join the wrapped lines back together using newline characters\n",
" wrapped_text = '\\n'.join(wrapped_lines)\n",
"\n",
" return wrapped_text\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dMHgDv1mPDYv"
},
"outputs": [],
"source": [
"import os\n",
"from google.colab import userdata\n",
"\n",
"GOOGLE_API_KEY = userdata.get('GOOGLE_API_KEY')\n",
"os.environ[\"GOOGLE_API_KEY\"] = GOOGLE_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "A-wSv_zVOzje"
},
"outputs": [],
"source": [
"%pip install --upgrade --quiet langchain-google-genai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qoUdE7I-O2F-"
},
"outputs": [],
"source": [
"from langchain_google_genai import ChatGoogleGenerativeAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "B4hEWBvCO6pg",
"outputId": "c2f15165-2a14-4887-c779-26c78bb90663"
},
"outputs": [],
"source": [
"llm = ChatGoogleGenerativeAI(model=\"gemini-1.5-pro\")\n",
"result = llm.invoke(\"Write a ballad about LangChain\")\n",
"print(result.content)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "QmX0tg21rHYG"
},
"source": [
"## Google"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PMV2IlE4GkMH"
},
"source": [
"## Imports"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "K1i89ZetrjxS"
},
"outputs": [],
"source": [
"from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
"from langchain.vectorstores.chroma import Chroma\n",
"import langchain"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "a6_wyaR7GmzK"
},
"source": [
"## Load in Docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "WPiv5FGi-AN-"
},
"outputs": [],
"source": [
"from langchain.document_loaders import DirectoryLoader\n",
"from langchain.document_loaders import TextLoader"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "q0oi9VRKPcYP",
"outputId": "9fd3685e-1fc6-46b9-e407-88042e71b048"
},
"outputs": [],
"source": [
"from google.colab import drive\n",
"drive.mount('/content/drive')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qRjNB_MKP0Jm"
},
"outputs": [],
"source": [
"data_path=\"/content/drive/MyDrive/English\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "U7wIIk-liy-Y",
"outputId": "747c87b2-f820-4b93-aad0-2e8c1a56e84a"
},
"outputs": [],
"source": [
"!pip install unstructured"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"background_save": true,
"base_uri": "https://localhost:8080/"
},
"id": "cMUCoHNk-Fdi",
"outputId": "d97f8ed6-c507-4bc5-ea03-b2885180c0aa"
},
"outputs": [],
"source": [
"%%time\n",
"loader = DirectoryLoader(data_path, glob=\"*.txt\", show_progress=True)\n",
"docs = loader.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "I7qI6T6mQdD3",
"outputId": "5a6d2b90-a862-4dca-e782-edd01fd32a42"
},
"outputs": [],
"source": [
"len(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lCzMJ2S7KaDW",
"outputId": "a23b49d1-627f-4f65-c9e4-4a5bb5fd23bb"
},
"outputs": [],
"source": [
"docs = docs[:50]\n",
"len(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "aef8c3ea-26e9-4a09-8314-0d1e7580ae26",
"outputId": "2dda7c15-20aa-417c-909f-5b6e5e088964"
},
"outputs": [],
"source": [
"docs[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "RJNlVST3QiUe",
"outputId": "9dbcd32d-bc88-4dad-b155-31b80e4d6235"
},
"outputs": [],
"source": [
"print(docs[2].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xBLcnHH5QsBg",
"outputId": "c3ebd828-fb4e-4e70-d00c-57a9e2d35823"
},
"outputs": [],
"source": [
"print(docs[1].page_content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "k2RnQCm-rkDt"
},
"outputs": [],
"source": [
"raw_text = ''\n",
"for i, doc in enumerate(docs):\n",
" text = doc.page_content\n",
" if text:\n",
" raw_text += text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "LOBVIoA4UKr9",
"outputId": "947477ff-71ad-42ca-e03f-2fa13509bdae"
},
"outputs": [],
"source": [
"print(raw_text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gSp3TatO9gx-"
},
"outputs": [],
"source": [
"text_splitter = RecursiveCharacterTextSplitter(\n",
" chunk_size = 500,\n",
" chunk_overlap = 100,\n",
" length_function = len,\n",
" is_separator_regex = False,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "-T4wxtXmrwEq"
},
"outputs": [],
"source": [
"texts = text_splitter.split_text(raw_text)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "76tCK-JtBvjU",
"outputId": "564d3839-e558-4e0c-9a38-c109d5be3cd2"
},
"outputs": [],
"source": [
"len(texts)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MugV2iv1B5KC",
"outputId": "97598e36-aa37-4890-96cf-3655321b3bfe"
},
"outputs": [],
"source": [
"print(texts[4])"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "NGwCBmlDGr0U"
},
"source": [
"## BGE Embeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dTjFYKf7U4oV"
},
"outputs": [],
"source": [
"from langchain.embeddings import HuggingFaceBgeEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "a3nh9giwU6cV"
},
"outputs": [],
"source": [
"model_name = \"BAAI/bge-small-en-v1.5\"\n",
"encode_kwargs = {'normalize_embeddings': True} # set True to compute cosine similarity"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 528,
"referenced_widgets": [
"daf4b4a852744209907991a6c2966cb3",
"96f8ccaf07794391af50c4b46123ff0c",
"9ab8f8b6252445faa03312eb0a694675",
"9f4e436970aa48bf96afd75f4088ddf9",
"368b2f9e73c24e1793b0893a203dcd9d",
"26441ab08b3449348fd347ceb209490b",
"ff98934b96d54296a3fa72afd491b84d",
"fbbf539537a64c3da3b3fedc95801c83",
"31596ec6290f48298332b33382f00766",
"c2ce3ca4017340bd87cfa290456d5015",
"851619bd487f4606aaec560b36f23fa7",
"b6be12de5cea495fb1eddd78c41f21d0",
"0e76f659b48b4f819feda2b4243264de",
"154d7104c893421189ed0c9efabbe28f",
"405bc96f7d59488aac24f038635bd331",
"7c96b7cd72464969b77d82e5383276a3",
"fa9b5d5bef634bdc82b87c87c29f92d3",
"008e25861fcc458a90c04cc8c33b4367",
"2f71a982cecc4fb8ad7617884dccd139",
"cd50d5d5175a46be9ed0d19a37e441c3",
"c307f87abdc64c7b929c37e9b05f91ee",
"3d27fc8f14714ba49e3599315486578c",
"48512d17ea054e068deec4eea4863dbf",
"9fdbb8bb2b6143ddb6009fe6d9f0e472",
"f4230a23cb304a068efa66544a09f557",
"5d1cb00ceb7748789226fda1f58b0a4e",
"fd7ea0696e6d4c0ea7661b4a91772324",
"bcd7d01133c24ba49f8691a734ffb8e6",
"9fa39ded11174699ac0fc2249c76b180",
"8dd7662de1c040dca74d7512bd576daa",
"9883747427aa41f184380248c7cc826b",
"bcb290e3be8c4d5a8ecf2c80aac219db",
"9c1d45b811364f3aa247eb71f6b3f797",
"7e503f9772aa4ddab7b85464b6cc9708",
"2cdcd3f2d413478f91fd04b012195490",
"91e47a9730d14238a9a37a821e1c2b5c",
"5871110cc3b642a6a1484da093d444b3",
"f0446b0d33b743f3949dc3d1f0cb824a",
"f80d571e3d794001bdff4a262a23aea7",
"23ddefb9b7b74569b60bf8d67bfdf936",
"939b3dff330d478cac30436e5250f569",
"27c67b594fc54d0cacbf9e3f572c3b00",
"f826e95b30544cf489899049ecd24071",
"b471bdafabb54964a175702b5b3ac1e6",
"9e4bba31701b419d95fe0df93d1b089f",
"3562215502ba4d4fa245aa2664532166",
"08cbd7b62b5a4ba88a1bbddb3cbeea48",
"cd6e56c80c1a47b393c91e2a0091fe61",
"135a506df5224098a12c4d484627c7b8",
"42e9fa4852d242648dc6b6b208c9342d",
"88c80fea2a1440f480a96a1e476ddec7",
"7cc665e9dd714b1285fcff1e3d235c84",
"22886fc9beac482fbd0e70e4673383d7",
"75592dea95fc41d7b6b4ef6bad7f8f72",
"93af90cf63d94f9daf8d0f133dd9a9aa",
"ce41452db26a4ee68d235a433b8da8ed",
"c766e3e9235749c6b085529f5f90979e",
"d82e3c5ba4f84a45a18ec099f89823e2",
"93f615374410475f9d5c6a42d9a342d9",
"ff22b99be102448a83c2a834c1b317ac",
"09b50d5f77b543cbab1b7729fa991ead",
"a1cc666b195c444bac2e58233971f7c8",
"4dbd12c4ffb44429826cd6e1cafee6f0",
"c2168c78e05741ebbd922ee2f1099c95",
"6d012696dc804c58990e4c707efe5af5",
"dc55034b980d489bbc4b92b787267dd2",
"9029e54ea2f74ff58d47e21b1b7f4dfd",
"3102ef78b0064210bf5fa819e9c02985",
"b380faaac82b47c48b52cc00255385ae",
"1667ad42b84a45659665382ea7b6eb8c",
"2027dfd21e16443f90b4fab1466f321c",
"102829f6002d4891ab0fea657f47d552",
"5e81eb28076d4b67be6413c960419e4a",
"0272abcbbc0846bc8ba7530d1bb0199f",
"1c55cec7f7ef4ab29c5427e4e1039dd9",
"cf51836aceaa4967a50bf51d97e96b0e",
"4433344c254347f8ac48eccb3faf1325",
"ff60ace5006647fba858f1217be96f81",
"b91a3c61cff04b96a199181513befe03",
"e73d07340f9a417993b65ce135443b6b",
"2840ea0bb8ce4a6bafdaee2d6ee26855",
"40c790b6e63f43b8be4a1ed1154ef073",
"f41156f5cf7244bfbc95ae35f3850e80",
"0af61f0b3bd447738f6ad185e42c8876",
"0c7cf72284bd44f0a4cc98842437b31d",
"9ad330d5afc24e64b7d44462467dd7e2",
"02dc492b85264d31a428450b60da9ccc",
"71f3267bf86642ea83f9b6b5579fb97b",
"3f77adb9c44745ba9445b929c4b5a400",
"ebc0c08856a54400a36c177a3c3da053",
"d59946acd45e498db9ffa7b00fcefe08",
"850b3f190fcb4f58985dcd013dd7a6c3",
"46fce79af203421f8705c540bad9b1da",
"d26d79af6a8d43c1ae0d39b0b4a9b063",
"73cea16ea6034b5184621cf320fe3eed",
"5a5733e0c41a4677838bf70b937df5ed",
"fbffd93a1b5446439e3bf26efe2bf7f3",
"a894726354e24ee6b43fed5442a31ac2",
"effd66db2abe4a71820c7a5389b35e98",
"8b13c6e1a7604317a7d740027e120ef2",
"f123e162e5af45459d49572bcc49b912",
"a7b447f2c5d84decb830e4bb02b887f8",
"165df076279f489c8bfe32a37eab27c2",
"4e76c2d6b11548ac850865a0e038ffd3",
"a3434ac854404b6ebf456f9260e63162",
"8d18616942ad4258a65a3a144b13e3ad",
"d636658c996c40a88c2458c5bc6ddc92",
"64732181d80c428cb78cfafe583441ac",
"cbefc3cef96d45e1aaab536cc3a066c8",
"88fac99bc696470f8aea85b97c94e375",
"e7eabda9b5534691a6b6d7efdfa70b63",
"81b22795c9cc4292a910f03da0a1b766",
"add326d655e5437e8607cd151ef19736",
"0b9c5d14cfdc4b15af92f8c3e1f47799",
"d866d7aceb30462fb3afb24a22b7008f",
"1f4293e41f2e47c88ba7cb3155b3ca68",
"12c3078628524eb297e58fc347643c62",
"c2d8dd2bd77a4d818e0a785e815b2cc0",
"247d18d2f8314f59ad5bf65e1d53c0b2",
"5958b3659e754912956498e1e248bc81",
"0c4e03dfdb0c4f4f934fb94bf2fb309e"
]
},
"id": "B4AIp2aXJQzm",
"outputId": "11d7c106-da47-481b-9e36-a6d643e80e80"
},
"outputs": [],
"source": [
"embedding_function = HuggingFaceBgeEmbeddings(\n",
" model_name=model_name,\n",
" #model_kwargs={'device': 'cuda'},\n",
" encode_kwargs=encode_kwargs,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "09TG9FsGGt1f"
},
"source": [
"## Vector DB"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gdAljZyxG92C",
"outputId": "d27ae793-b9fd-438d-af88-7b5828fa6f4f"
},
"outputs": [],
"source": [
"%%time\n",
"### Make the chroma and persiste to disk\n",
"db = Chroma.from_texts(texts,embedding_function,persist_directory=\"./chroma_db\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "WzCj8F8PuzyG",
"outputId": "54fec0b0-b306-4f8e-dd89-c78c8c51c84f"
},
"outputs": [],
"source": [
"query = \"Tell me about Universal Studios Singapore?\"\n",
"\n",
"db.similarity_search(query, k=5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "A_Q6wbhaHCFY"
},
"source": [
"## Setup a Retriever"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Yb4whROY5dC6",
"outputId": "3e8b9188-d4e8-4a32-a047-dc25a329658c"
},
"outputs": [],
"source": [
"retriever = db.as_retriever() # can add mmr fetch_k=20, search_type=\"mmr\"\n",
"\n",
"retriever.get_relevant_documents(query)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2Im-BIOGFuOY"
},
"source": [
"## Chat chain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Xg3Q51MKNTY0"
},
"outputs": [],
"source": [
"from operator import itemgetter\n",
"from langchain.prompts import ChatPromptTemplate\n",
"from langchain.schema.output_parser import StrOutputParser\n",
"from langchain.schema.runnable import RunnableLambda, RunnablePassthrough"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5PzPuNnuWTmH"
},
"outputs": [],
"source": [
"template = \"\"\"Answer the question based only on the following context:\n",
"{context}\n",
"\n",
"Question: {question}\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "eBxQ074NWVeO"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_template(template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "F7AlJ1MvlmFd",
"outputId": "b7cb79e3-1058-4425-e9a0-0f625823324a"
},
"outputs": [],
"source": [
"prompt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "w5W4odwSFvZy",
"outputId": "2d47f7f1-3df7-416c-b6fd-5a9583301288"
},
"outputs": [],
"source": [
"llm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cYxeU1OeHZcB"
},
"outputs": [],
"source": [
"chain = (\n",
" {\"context\": retriever, \"question\": RunnablePassthrough()}\n",
" | prompt\n",
" | llm\n",
" | StrOutputParser()\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6aHFCXHrHgpI",
"outputId": "2919309d-ddaf-4c79-d3bb-2cf73425c363"
},
"outputs": [],
"source": [
"text_reply = chain.invoke(\"Tell me about Universal Studio Singapore\")\n",
"\n",
"print(wrap_text(text_reply))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "6FRIkxHGb9Dy"
},
"source": [
"## With RagFusion"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "sbVhVYwXb_X5"
},
"outputs": [],
"source": [
"from langchain.schema.output_parser import StrOutputParser\n",
"from langchain.prompts import SystemMessagePromptTemplate, HumanMessagePromptTemplate\n",
"from langchain.prompts import ChatMessagePromptTemplate, PromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8uGvc1E2cN7S"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate(input_variables=['original_query'],\n",
" messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[],template='You are a helpful assistant that generates multiple search queries based on a single input query.')),\n",
" HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['original_query'], template='Generate multiple search queries related to: {question} \\n OUTPUT (4 queries):'))])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ZqlMkWance2k"
},
"outputs": [],
"source": [
"original_query = \"universal studios Singapore\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Q71Fs_sFcXOO"
},
"outputs": [],
"source": [
"generate_queries = (\n",
" prompt | llm | StrOutputParser() | (lambda x: x.split(\"\\n\"))\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "_EBSsEO2YSxn",
"outputId": "19bafec4-55b5-43d0-b720-26f57b8aae75"
},
"outputs": [],
"source": [
"generate_queries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "wxv9EXxpczgA"
},
"outputs": [],
"source": [
"from langchain.load import dumps, loads\n",
"\n",
"\n",
"def reciprocal_rank_fusion(results: list[list], k=60):\n",
" fused_scores = {}\n",
" for docs in results:\n",
" # Assumes the docs are returned in sorted order of relevance\n",
" for rank, doc in enumerate(docs):\n",
" doc_str = dumps(doc)\n",
" if doc_str not in fused_scores:\n",
" fused_scores[doc_str] = 0\n",
" previous_score = fused_scores[doc_str]\n",
" fused_scores[doc_str] += 1 / (rank + k)\n",
"\n",
" reranked_results = [\n",
" (loads(doc), score)\n",
" for doc, score in sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)\n",
" ]\n",
" return reranked_results"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "C1TYLuNNc1Mz"
},
"outputs": [],
"source": [
"ragfusion_chain = generate_queries | retriever.map() | reciprocal_rank_fusion"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_PPYsBf2g8TR"
},
"outputs": [],
"source": [
"langchain.debug = True"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "UZbsNg7EhfbP",
"outputId": "dbd7a873-1ee2-4268-c32a-0799fb5d8c07"
},
"outputs": [],
"source": [
"ragfusion_chain.input_schema.schema()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tsQWIOjVc5gt",
"outputId": "0453b304-3f24-4011-ab4f-f97eefb8c59b"
},
"outputs": [],
"source": [
"ragfusion_chain.invoke({\"question\": original_query})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8_YX1u6lc7nB"
},
"outputs": [],
"source": [
"from langchain.schema.runnable import RunnablePassthrough\n",
"template = \"\"\"Answer the question based only on the following context:\n",
"{context}\n",
"\n",
"Question: {question}\n",
"\"\"\"\n",
"prompt = ChatPromptTemplate.from_template(template)\n",
"\n",
"full_rag_fusion_chain = (\n",
" {\n",
" \"context\": ragfusion_chain,\n",
" \"question\": RunnablePassthrough()\n",
" }\n",
" | prompt\n",
" | llm\n",
" | StrOutputParser()\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "9dFNAi7vhool",
"outputId": "a0499a0f-62fb-4c28-c501-07f68a9867ef"
},
"outputs": [],
"source": [
"full_rag_fusion_chain.input_schema.schema()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "04iV9SY0fAz0",
"outputId": "3b6e490c-36b6-4ec8-feab-033ef53e86c3"
},
"outputs": [],
"source": [
"full_rag_fusion_chain.invoke({\"question\": \"Tell me about Singapore’s nightlife scene?\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GXJEjyjunk5E"
},
"outputs": [],
"source": [
"Singapore’s nightlife scene is incredibly diverse, offering a blend of high-energy clubs and more relaxed options for a night out. You can dance to music from world-renowned DJs at a megaclub, savor a unique drink at a low-key cocktail bar, or enjoy live music before laughing the night away at a comedy club.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "W3Yj7xLbocKQ"
},
"source": [
"Singapore’s nightlife scene is incredibly diverse, offering a blend of high-energy clubs and more relaxed options for a night out. You can dance to music from world-renowned DJs at a megaclub, savor a unique drink at a low-key cocktail bar, or enjoy live music before laughing the night away at a comedy club.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "uoF_Tledoco6"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: RAG_With_Knowledge_graph(Neo4j).ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "xB3OyiU14byv"
},
"source": [
"# langchain-core\n",
"\n",
"contains simple, core abstractions that have emerged as a standard, as well as LangChain Expression Language as a way to compose these components together. This package is now at version 0.1 and all breaking changes will be accompanied by a minor version bump.\n",
"\n",
"# langchain-community\n",
"contains all third party integrations. We will work with partners on splitting key integrations out into standalone packages over the next month.\n",
"\n",
"# langchain\n",
"contains higher-level and use-case specific chains, agents, and retrieval algorithms that are at the core of your application's cognitive architecture. We are targeting a launch of a stable 0.1 release for langchain in early January.#"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "usWcdmOr7GAH",
"outputId": "dcbfc75b-28d2-4a52-db53-83c63a862798"
},
"outputs": [],
"source": [
"%pip install --upgrade --quiet langchain langchain-community langchain-openai langchain-experimental neo4j wikipedia tiktoken yfiles_jupyter_graphs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "q8EzdaTJFTbx"
},
"outputs": [],
"source": [
"from langchain_core.runnables import (\n",
" RunnableBranch,\n",
" RunnableLambda,\n",
" RunnableParallel,\n",
" RunnablePassthrough,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vKkxxyasFWPh"
},
"outputs": [],
"source": [
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_core.prompts.prompt import PromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SksHz3Q356JQ"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GCEgNy7LFXS4"
},
"outputs": [],
"source": [
"from typing import Tuple, List, Optional"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ymZquwggFaNr"
},
"outputs": [],
"source": [
"from langchain_core.messages import AIMessage, HumanMessage\n",
"from langchain_core.output_parsers import StrOutputParser"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nitfT-ktFaQQ"
},
"outputs": [],
"source": [
"from langchain_core.runnables import ConfigurableField"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "fzOPupw0FaSy"
},
"outputs": [],
"source": [
"from yfiles_jupyter_graphs import GraphWidget\n",
"from neo4j import GraphDatabase\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "g6kjt1HkFaVZ"
},
"outputs": [],
"source": [
"import os"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IR5TLMjpFhE-"
},
"outputs": [],
"source": [
"try:\n",
" import google.colab\n",
" from google.colab import output\n",
" output.enable_custom_widget_manager()\n",
"except:\n",
" pass"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pSgOwI9SFhHr"
},
"outputs": [],
"source": [
"from langchain_community.vectorstores import Neo4jVector"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "lyOvwiijFlQF"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YiKFX23n4tl3"
},
"outputs": [],
"source": [
"NEO4J_URI=\"neo4j+s://7b0ac3fd.databases.neo4j.io\"\n",
"NEO4J_USERNAME=\"neo4j\"\n",
"NEO4J_PASSWORD=\"al6q_y6NWn8e98YXHElSBED010quYdte4FaNxL-hESg\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gHiqiwau7Tat"
},
"outputs": [],
"source": [
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n",
"os.environ[\"NEO4J_URI\"] = NEO4J_URI\n",
"os.environ[\"NEO4J_USERNAME\"] = NEO4J_USERNAME\n",
"os.environ[\"NEO4J_PASSWORD\"] = NEO4J_PASSWORD"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zpIPagYu6BAp"
},
"outputs": [],
"source": [
"from langchain_community.graphs import Neo4jGraph"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0xzi4bRD6Bx9"
},
"outputs": [],
"source": [
"graph = Neo4jGraph()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XKqtMDVY6WwW",
"outputId": "c432ea29-28d4-4501-e01e-dececbc2d748"
},
"outputs": [],
"source": [
"from langchain.document_loaders import WikipediaLoader\n",
"raw_documents = WikipediaLoader(query=\"Elizabeth I\").load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ACWeDt0O7yc2",
"outputId": "14415b49-96a8-4c23-e8f0-c962afbe1135"
},
"outputs": [],
"source": [
"len(raw_documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "skFy3n30732l",
"outputId": "95a859ac-436a-4de9-e1fa-146aa92c07d0"
},
"outputs": [],
"source": [
"raw_documents[:3]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5ChZ008I6paW"
},
"outputs": [],
"source": [
"from langchain.text_splitter import TokenTextSplitter\n",
"text_splitter = TokenTextSplitter(chunk_size=512, chunk_overlap=24)\n",
"documents = text_splitter.split_documents(raw_documents[:3])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "IMh_IpRb78rs"
},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"llm=ChatOpenAI(temperature=0, model_name=\"gpt-3.5-turbo-0125\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Mer51fZA9pa1"
},
"outputs": [],
"source": [
"from langchain_experimental.graph_transformers import LLMGraphTransformer\n",
"llm_transformer = LLMGraphTransformer(llm=llm)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pZP64uFM9vLk"
},
"outputs": [],
"source": [
"graph_documents = llm_transformer.convert_to_graph_documents(documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "3Nwjd5yR92VE",
"outputId": "1c707732-3f56-4228-be36-5e376a481aac"
},
"outputs": [],
"source": [
"graph_documents"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ib_g3U1d97th"
},
"outputs": [],
"source": [
"graph.add_graph_documents(\n",
" graph_documents,\n",
" baseEntityLabel=True,\n",
" include_source=True\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "rC-4O5FQ99yH"
},
"outputs": [],
"source": [
"# directly show the graph resulting from the given Cypher query\n",
"default_cypher = \"MATCH (s)-[r:!MENTIONS]->(t) RETURN s,r,t LIMIT 50\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "K-91BluK_62t"
},
"outputs": [],
"source": [
"from yfiles_jupyter_graphs import GraphWidget\n",
"from neo4j import GraphDatabase"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "djVL6Gh4_4sV"
},
"outputs": [],
"source": [
"try:\n",
" import google.colab\n",
" from google.colab import output\n",
" output.enable_custom_widget_manager()\n",
"except:\n",
" pass"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "0Ll2WNnO-Ahf"
},
"outputs": [],
"source": [
"def showGraph(cypher: str = default_cypher):\n",
" # create a neo4j session to run queries\n",
" driver = GraphDatabase.driver(\n",
" uri = os.environ[\"NEO4J_URI\"],\n",
" auth = (os.environ[\"NEO4J_USERNAME\"],\n",
" os.environ[\"NEO4J_PASSWORD\"]))\n",
" session = driver.session()\n",
" widget = GraphWidget(graph = session.run(cypher).graph())\n",
" widget.node_label_mapping = 'id'\n",
" display(widget)\n",
" return widget"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000,
"referenced_widgets": [
"e8b6acc77d8f4d208b74b4f1d05144e5",
"5caa1675fb9b47e89ceeab4a5aabb705"
]
},
"id": "kz-O4c0k-C_4",
"outputId": "9d9fa858-6d4b-45cb-bc6c-9e39297ffbef"
},
"outputs": [],
"source": [
"showGraph()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zHSkb7LeBghn"
},
"outputs": [],
"source": [
"from typing import Tuple, List, Optional"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TuDVi4vHBjXP"
},
"outputs": [],
"source": [
"from langchain_community.vectorstores import Neo4jVector"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "M_JloAimBlcK"
},
"outputs": [],
"source": [
"from langchain_openai import OpenAIEmbeddings\n",
"vector_index = Neo4jVector.from_existing_graph(\n",
" OpenAIEmbeddings(),\n",
" search_type=\"hybrid\",\n",
" node_label=\"Document\",\n",
" text_node_properties=[\"text\"],\n",
" embedding_node_property=\"embedding\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "e0EXdSStG-Oe",
"outputId": "d8c21f17-913c-4af0-acdb-1a9eb49dbba7"
},
"outputs": [],
"source": [
"graph.query(\"CREATE FULLTEXT INDEX entity IF NOT EXISTS FOR (e:__Entity__) ON EACH [e.id]\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qksArGKrAvie"
},
"outputs": [],
"source": [
"from langchain_core.pydantic_v1 import BaseModel, Field\n",
"# Extract entities from text\n",
"class Entities(BaseModel):\n",
" \"\"\"Identifying information about entities.\"\"\"\n",
"\n",
" names: List[str] = Field(\n",
" ...,\n",
" description=\"All the person, organization, or business entities that \"\n",
" \"appear in the text\",\n",
" )\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Mx6sfpgRBrs-"
},
"outputs": [],
"source": [
"from langchain_core.prompts import ChatPromptTemplate\n",
"from langchain_core.prompts.prompt import PromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xUobRC1wAx-_"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_messages(\n",
" [\n",
" (\n",
" \"system\",\n",
" \"You are extracting organization and person entities from the text.\",\n",
" ),\n",
" (\n",
" \"human\",\n",
" \"Use the given format to extract information from the following \"\n",
" \"input: {question}\",\n",
" ),\n",
" ]\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "KGR6ocjkA0I_"
},
"outputs": [],
"source": [
"entity_chain = prompt | llm.with_structured_output(Entities)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xPLkIEmkA2R2",
"outputId": "fecf9433-32c4-4203-ad94-ca1c56ee60ee"
},
"outputs": [],
"source": [
"entity_chain.invoke({\"question\": \"Where was Amelia Earhart born?\"}).names"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RpbOzL5BA6hW"
},
"outputs": [],
"source": [
"from langchain_community.vectorstores.neo4j_vector import remove_lucene_chars"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7gHCkvGKA86t"
},
"outputs": [],
"source": [
"def generate_full_text_query(input: str) -> str:\n",
" full_text_query = \"\"\n",
" words = [el for el in remove_lucene_chars(input).split() if el]\n",
" for word in words[:-1]:\n",
" full_text_query += f\" {word}~2 AND\"\n",
" full_text_query += f\" {words[-1]}~2\"\n",
" return full_text_query.strip()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "kjPkmFJbA_lv"
},
"outputs": [],
"source": [
"# Fulltext index query\n",
"def structured_retriever(question: str) -> str:\n",
" result = \"\"\n",
" entities = entity_chain.invoke({\"question\": question})\n",
" for entity in entities.names:\n",
" response = graph.query(\n",
" \"\"\"CALL db.index.fulltext.queryNodes('entity', $query, {limit:2})\n",
" YIELD node,score\n",
" CALL {\n",
" WITH node\n",
" MATCH (node)-[r:!MENTIONS]->(neighbor)\n",
" RETURN node.id + ' - ' + type(r) + ' -> ' + neighbor.id AS output\n",
" UNION ALL\n",
" WITH node\n",
" MATCH (node)<-[r:!MENTIONS]-(neighbor)\n",
" RETURN neighbor.id + ' - ' + type(r) + ' -> ' + node.id AS output\n",
" }\n",
" RETURN output LIMIT 50\n",
" \"\"\",\n",
" {\"query\": generate_full_text_query(entity)},\n",
" )\n",
" result += \"\\n\".join([el['output'] for el in response])\n",
" return result"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "nIla9QpzBA8u",
"outputId": "c521c295-5964-45bd-9ce3-29c65ad3f823"
},
"outputs": [],
"source": [
"print(structured_retriever(\"Who is Elizabeth I?\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Zo1QoB_iBDfO"
},
"outputs": [],
"source": [
"def retriever(question: str):\n",
" print(f\"Search query: {question}\")\n",
" structured_data = structured_retriever(question)\n",
" unstructured_data = [el.page_content for el in vector_index.similarity_search(question)]\n",
" final_data = f\"\"\"Structured data:\n",
"{structured_data}\n",
"Unstructured data:\n",
"{\"#Document \". join(unstructured_data)}\n",
" \"\"\"\n",
" return final_data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nDLnOXBTBFaf"
},
"outputs": [],
"source": [
"_template = \"\"\"Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question,\n",
"in its original language.\n",
"Chat History:\n",
"{chat_history}\n",
"Follow Up Input: {question}\n",
"Standalone question:\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hozfZicpBG2G"
},
"outputs": [],
"source": [
"CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template(_template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "A9Oi3AEeBIPf"
},
"outputs": [],
"source": [
"def _format_chat_history(chat_history: List[Tuple[str, str]]) -> List:\n",
" buffer = []\n",
" for human, ai in chat_history:\n",
" buffer.append(HumanMessage(content=human))\n",
" buffer.append(AIMessage(content=ai))\n",
" return buffer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vXV65bjDBJwO"
},
"outputs": [],
"source": [
"_search_query = RunnableBranch(\n",
" # If input includes chat_history, we condense it with the follow-up question\n",
" (\n",
" RunnableLambda(lambda x: bool(x.get(\"chat_history\"))).with_config(\n",
" run_name=\"HasChatHistoryCheck\"\n",
" ), # Condense follow-up question and chat into a standalone_question\n",
" RunnablePassthrough.assign(\n",
" chat_history=lambda x: _format_chat_history(x[\"chat_history\"])\n",
" )\n",
" | CONDENSE_QUESTION_PROMPT\n",
" | ChatOpenAI(temperature=0)\n",
" | StrOutputParser(),\n",
" ),\n",
" # Else, we have no chat history, so just pass through the question\n",
" RunnableLambda(lambda x : x[\"question\"]),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zuVyoD1iBLgt"
},
"outputs": [],
"source": [
"template = \"\"\"Answer the question based only on the following context:\n",
"{context}\n",
"\n",
"Question: {question}\n",
"Use natural language and be concise.\n",
"Answer:\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ehex9TRGBM4m"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_template(template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UI6LVwkpBOOA"
},
"outputs": [],
"source": [
"chain = (\n",
" RunnableParallel(\n",
" {\n",
" \"context\": _search_query | retriever,\n",
" \"question\": RunnablePassthrough(),\n",
" }\n",
" )\n",
" | prompt\n",
" | llm\n",
" | StrOutputParser()\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"id": "GZAq-jz3BOrn",
"outputId": "d438df41-4a7e-437a-a022-902d8290e4cb"
},
"outputs": [],
"source": [
"chain.invoke({\"question\": \"Which house did Elizabeth I belong to?\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"id": "b8bO9V_MIBZ5",
"outputId": "d5d3cfa2-c4ec-4089-e715-0233e688bf85"
},
"outputs": [],
"source": [
"chain.invoke(\n",
" {\n",
" \"question\": \"When was she born?\",\n",
" \"chat_history\": [(\"Which house did Elizabeth I belong to?\", \"House Of Tudor\")],\n",
" }\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qyIlAGROIUKC"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"authorship_tag": "ABX9TyMIuVjJKqR/9fsypmYd/Dng",
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: RAG_with_LLAMA3_1.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "gqitMEIzPJU0"
},
"source": [
"https://medium.com/@lucnguyen_61589/llama-2-using-huggingface-part-1-3a29fdbaa9ed"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Xf8QnelFHAzT"
},
"source": [
"https://medium.com/@mauryaanoop3/running-ollama-on-google-colab-free-tier-a-step-by-step-guide-9ef74b1f8f7a"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8i8wxZxrtO3H",
"outputId": "c50be7f0-7c0e-4037-cb37-997985765dcd"
},
"outputs": [],
"source": [
"!pip install langchain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tzPoOd35tiwB",
"outputId": "32f1accd-6af4-4e0e-f4ad-1977302b2cb8"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "59OSBMxeu5zu",
"outputId": "1bdb101a-1ed6-4382-8555-c9f193e631cd"
},
"outputs": [],
"source": [
"!pip install sentence-transformers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rIyr18ITxZo_",
"outputId": "b48499d8-1101-4116-898c-b01ef8f04d59"
},
"outputs": [],
"source": [
"!pip install faiss-gpu"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "wLO3pzTUHUA5",
"outputId": "ffcc95b5-801b-4708-8428-59edef6a220c"
},
"outputs": [],
"source": [
"!pip install pypdf"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "xw4CvvWFHWXr"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1ABjVT_7H8c6"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "K4ZJLIy2wTJn"
},
"source": [
"# RAG Having Three main Stages\n",
"\n",
"1. Data Ingestion\n",
"2. Data Retrieval\n",
"3. Data Generation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "23FwJKsx-d3k"
},
"outputs": [],
"source": [
"from langchain.document_loaders import PyPDFLoader\n",
"from langchain.text_splitter import CharacterTextSplitter\n",
"from langchain.embeddings import HuggingFaceEmbeddings\n",
"from langchain.vectorstores import FAISS\n",
"from langchain.chains import RetrievalQA"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dFBlm-P1uZGY"
},
"outputs": [],
"source": [
"# Load document using PyPDFLoader document loader\n",
"loader = PyPDFLoader(\"/content/got.pdf\")\n",
"documents = loader.load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "sFDITrbbubxI"
},
"outputs": [],
"source": [
"#Splitting the data into chunk\n",
"text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=30, separator=\"\\n\")\n",
"docs = text_splitter.split_documents(documents=documents)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "D3LjeGq8vWCH"
},
"source": [
"# MTEB: Massive Text Embedding Benchmark\n",
"\n",
"#### The all-mpnet-base-v2 model provides the best quality, while all-MiniLM-L6-v2 is 5 times faster and still offers good quality.\n",
"\n",
"BGE(BAAI general embedding)\n",
"BAAI: https://huggingface.co/BAAI\n",
"\n",
"**Dataset size:** Larger datasets generally benefit from more powerful models like MPNet.\n",
"\n",
"**Computational resources:** If you have limited resources, BGE Small En or MiniLM might be better options.\n",
"\n",
"**Task complexity:** For complex tasks like question answering or text summarization, MPNet is often preferred.\n",
"\n",
"**Embedding dimensionality:** Different models produce embeddings of varying dimensions.Choose based on downstream task requirements.\n",
"\n",
"**Performance vs. efficiency trade-off:** Decide if you prioritize high accuracy or faster processing\n",
"\n",
"#####Experimentation is key. Try different models and evaluate their performance on your specific task and dataset to find the best fit.\n",
"\n",
"MPNET: Masked and Permuted Pre-training for Language Understanding.\n",
"\n",
"https://huggingface.co/sentence-transformers\n",
"\n",
"https://huggingface.co/spaces/mteb/leaderboard\n",
"\n",
"https://huggingface.co/blog/mteb\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 563,
"referenced_widgets": [
"ea4258e4fffd49d6a2772455f1816ed0",
"86ecd031a30d415c9a57c369dd973ad2",
"b571ec7d542d4731ab32d265c84c041a",
"83ad367f927441cdbaf5394f316595f8",
"804dede1a0574353807479a3d0f3c473",
"2bbc842448d5415ebd3e85c50ec9b506",
"42f5bc2d747d4d5d8ffb5907d50b3a24",
"75d76b34473549c7b7349b1bcd914049",
"ee50f33af3d04948962e172cf5c979cb",
"d513148416a04881a47e9d8c3487c98e",
"d6baa19068e04d4387231aaca8714fcf",
"783c3297014f42a79b2299f77bbb5d7d",
"4f9f11a16edf441f867ac5d2ad2bcc03",
"f89eaf1ba0f0467683f5039dab0560fc",
"38b07bf6458b465da7a631bcaf72e434",
"0cba5ad82718408d99ecfb7bdfb3c878",
"84eaa7953de54aebb8c9f2940e023f8b",
"dc9ee81f922b4556a1118bf717a5a775",
"102b91016537435f9dcab268b0acea43",
"88500eb1ecbb43d2a623cc2ab5f3d33f",
"166d6dcc24144c8a8356eb2b5319e083",
"4d8eabcd51fb4858a0022bec0a4c3511",
"3e2e0601f8c0458caa64f8be1004e84f",
"c9e03d2462184c1b881476809899bbd6",
"edbb40fb65a8499d97ab97c418e0b99e",
"b1c00868471d4523846e5552edcba9cb",
"a7f5b15d7adb4b9889c4b0b1e3734669",
"33c2e0df773b4e3b88562ca28ccb5ddc",
"c2184eec63b24c31b4f0ffc89b8ce297",
"4d1258ed717a467e8a9b9cc02e90e67e",
"314fb23a0d5b4485bea6678aa954f757",
"5d133ad7a2ec4f01951bace2fa897d1f",
"677a2ea0d0d44e90b9e65f0610f34ab3",
"57f934d324cc45deb44c355e130d0e64",
"bc93ebdbda304957bd2e8644d8483b12",
"7866c87424494bcaab5c1d29da6b187c",
"123ad64ca8914df9b4612beb7795a7b7",
"5e6f600aac0748adad67def720c5b653",
"f0b240017351487eb82886a2a529da87",
"f62d6bad41ae4471a59b2ef11ad61ea9",
"846fd8ba1b674f6abd6029230abe4575",
"9c0e2bdf21654ec4a5f9fef2c6123a5e",
"256baeb50da94dc282483a4a73193cad",
"195e01f914a240dc8797523c4ecf20dc",
"72a422a92a4544db8f802eeb22fcadeb",
"8ac84fbcc253406c9c64a262e7c9faac",
"1d47eba9f16147d2af15b9f5ce5c6bd5",
"ce7af37fb6d544f8b2d3eb0b4483c19f",
"bbb7351c2fa54339b2e60591a6bc56de",
"11422844d4f647d1bd1170fc9798d596",
"8c5c2761230e41b58ce57d211543bb13",
"38da895d9e434dfc83a5c63e3da13182",
"47f1dc6d36fa4128b2558efa8d096228",
"d18fbd001b584565a579807c3023ce52",
"a09240f995794398ab65b6788672aa45",
"4d58cb32ce7f47c299735c51d494254f",
"6a4cf0ccb3ea48cdaf2f49ca9164d2d4",
"f9ea7e03d54249148dd3caf1b12ef552",
"cefcb1eb4440484c982f938217fc82ff",
"ef797838f5b04de2b71f2abaa15593b7",
"ae3b01843c994ff18f19d655aa2123ec",
"e244b01c11d740a685cbabb67bd2faa2",
"40b1d302b7154a5e94704d2ba6721dbf",
"5dfb4f6022874ebba4072e53c0e78161",
"3bf5100fef4b4bbe91ee6730999c895d",
"926bc4ae3e8046bfb4eac4d35e6ace53",
"2b14de8ddbbf48c8be7140cbe7ec3bd5",
"fa5457ac9ce14787a79b3c93ac5355d3",
"7267d19c08fa415e93ae433e5b90b3f2",
"60f9158ca72c453b99381c6b22a9be0e",
"c9589525d5794bb59b8aa918e2f207c2",
"b455395261ca4c26939aa2120890ec4a",
"fe3efdf8c14a4c34b18df901a69de83e",
"6ab144aee62d44368fd611bb64583668",
"8e37e31babb94ce085270e54b25b2482",
"6b83581b426a4f1e846d881f17cc5169",
"c31fd7ff3bf04116b0e1f87dc63bb2f8",
"ee6efa467cfc4782bacc91bcc1d9c17e",
"e46fd93e2f4040d5b71bf9595a422d36",
"fc6013fe7ccf40808656e31031aa93ce",
"b7f03f7b9b6a4d619e7bd478da81eff2",
"ffed7e90058c4755b848ad0f8acae76c",
"a8fab2222c1c499ab3e68e46c98d2892",
"ff47981e159241ef99c7e372a2fb6b21",
"9eca2ee50a374edb90694bd3296dbf85",
"abc51d5914cb4d86a767a62e6877afd7",
"454ed1e9f0a44a9280a301d426db4c3d",
"0bcfebc8aac14acf849ab70d75a1428a",
"c386113b3f584dc7b88ec89d6122d9ec",
"2212c9bfc3a5466caf06a977ff1ad369",
"86e8c0ab62b64138ab1b0d4962740e31",
"6b2c2be837e7467082afc9eec178a53a",
"3347a31384854a5788258f2c536648fa",
"d5302c7bb92b496795b4e1fa88afe258",
"403d2647181f4c55833b8b70b51ee5b4",
"9aec9b93f7ff4f2ca94e478a94e2dedf",
"7c8be5864349487290e44b3c0d3e8353",
"6b5e645000134d22b9d523f595e8472b",
"9b7c5a6200e340868568284586faf501",
"39f782c4b7da455c9ec72d23fca0b78f",
"534fa9747d714acca3958a7bfaa32164",
"a57f325a8af24d568301bad6e0c0fceb",
"5c6852b1187a4abcb9d301b718f126d8",
"8bbf2f04ff834a2ca8bc609de0233a8f",
"e9d7e228d2dd44d5b94c767c967cc309",
"63fff23ae3944fabb7fa7ac987e44d9c",
"9ed7c234bf7147c88c65b306d8bcbfca",
"d720c5dc708b44f3b8e70c724edc7ed4",
"2d46be9ae94b4c8b87b9f543326b78ed",
"1d4a7b0bacac4b019b0a65957c77d6d7",
"9fcd12f1bbad467b97ee00ed3c151354",
"3b6dd7a1898747bdbbc97e571252598a",
"1163c653fb6c4eca920f684a518ffbe5",
"434dc88a7006464c932678ac9573fc04",
"e9d8d46dfa744d32886bf9fb668dd030",
"5b185bba4037481a95f599b7a67a0981",
"8acf4f6e26b147c1b6b447e126c5934f",
"b3d6802fe620446aa8eaabd5ffbdd9d9",
"a6f4843a80804f9588af323dcd46d1bf",
"6f331c1c8e034ac6acc2ee41c16dc5de",
"4fb26478773544cc85ab657f3a34b024"
]
},
"id": "iwhonhgFufzd",
"outputId": "e35b0d2e-6010-4c90-d078-7df3e90696c5"
},
"outputs": [],
"source": [
"#loading the embedding model from huggingface\n",
"embedding_model_name = \"sentence-transformers/all-mpnet-base-v2\"\n",
"model_kwargs = {\"device\": \"cuda\"}\n",
"embeddings = HuggingFaceEmbeddings(\n",
" model_name=embedding_model_name,\n",
" model_kwargs=model_kwargs\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VBHaomQbv-li"
},
"source": [
"# Why Use FAISS\n",
"\n",
"1. Efficiency\n",
"2. Versatility\n",
"3. Scalability\n",
"4. Integration\n",
"5. GPU Support\n",
"\n",
"# Security Considerations\n",
"\n",
"1. Data Control\n",
"2. Reduced Exposure\n",
"3. Compliance\n",
"4. Latency and Performance\n",
"5. Network Security"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 53
},
"id": "ElIuZRyYxdhp",
"outputId": "c4a7fff8-42b0-4305-a7fa-dd4b80e821af"
},
"outputs": [],
"source": [
"'''\n",
"from langchain.vectorstores import FAISS\n",
"vectorstore=FAISS.from_documents(text_chunks, embeddings)\n",
"retriever=vectorstore.as_retriever()\n",
"'''"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SfQzANNWuvkK"
},
"outputs": [],
"source": [
"#loading the data and correspond embedding into the FAISS\n",
"vectorstore = FAISS.from_documents(docs, embeddings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pWiAxukJwiAP"
},
"outputs": [],
"source": [
"# Persist the vectors locally on disk\n",
"vectorstore.save_local(\"faiss_index_\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gKm216qzwkM2"
},
"outputs": [],
"source": [
"# Load from local storage\n",
"persisted_vectorstore = FAISS.load_local(\"faiss_index_\", embeddings,allow_dangerous_deserialization=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9Zz6LrNjx6ZM"
},
"outputs": [],
"source": [
"#creating a retriever on top of database\n",
"retriever = persisted_vectorstore.as_retriever()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gE9cJ-Eoy22e",
"outputId": "80c611ff-6c4f-4499-a1fe-c14855a86cab"
},
"outputs": [],
"source": [
"!pip install langchain_ollama"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "bmwP94r_yc4g",
"outputId": "0b9c60fe-064f-40f5-ced3-d731c354a0c2"
},
"outputs": [],
"source": [
"#loading the llama3.1 model using Ollama\n",
"!pip install colab-xterm #https://pypi.org/project/colab-xterm/\n",
"%load_ext colabxterm"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "FuC6Qd37tMCI"
},
"source": [
"curl -fsSL https://ollama.com/install.sh | sh\n",
"\n",
"ollama serve & ollama pull llama3.1"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 839,
"resources": {
"https://localhost:10000/": {
"data": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGhlYWQ+PG1ldGEgY2hhcnNldD0idXRmLTgiLz48c2NyaXB0IGRlZmVyPSJkZWZlciIgc3JjPSJtYWluLmpzIj48L3NjcmlwdD48L2hlYWQ+PGJvZHk+PGRpdiBpZD0idGVybWluYWwiPjwvZGl2PjwvYm9keT48L2h0bWw+",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/Aw==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/DQ==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/G1syMDB+Y3VybCAtZnNTTCBodHRwczovL29sbGFtYS5jb20vaW5zdGFsbC5zaCB8IHNoG1syMDF+": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/G1syMDB+b2xsYW1hIHB1bGwgbGxhbWEyG1syMDF+": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/G1syMDB+b2xsYW1hIHNlcnZlG1syMDF+": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/G1tD": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/G1tE": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/IA==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/Jg==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/LjE=": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/Mw==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/YW1h": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/b2xsYW1hIHB1bGwgbGxhbWEy": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/bA==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/bGw=": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/bGxh": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/bGxhbWE=": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/bw==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/c2Vy": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/cHU=": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/dmU=": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/f38=": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/f39/": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/f39/f38=": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/f39/fw==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/in/fw==": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/main.js": {
"data": "LyohIEZvciBsaWNlbnNlIGluZm9ybWF0aW9uIHBsZWFzZSBzZWUgbWFpbi5qcy5MSUNFTlNFLnR4dCAqLwooKCk9Pnt2YXIgZT17MTAyOihlLHQscik9PnsidXNlIHN0cmljdCI7ci5kKHQse1o6KCk9PmF9KTt2YXIgaT1yKDgxKSxuPXIubihpKSxvPXIoNjQ1KSxzPXIubihvKSgpKG4oKSk7cy5wdXNoKFtlLmlkLCcvKipcbiAqIENvcHlyaWdodCAoYykgMjAxNCBUaGUgeHRlcm0uanMgYXV0aG9ycy4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqIENvcHlyaWdodCAoYykgMjAxMi0yMDEzLCBDaHJpc3RvcGhlciBKZWZmcmV5IChNSVQgTGljZW5zZSlcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9jaGpqL3Rlcm0uanNcbiAqIEBsaWNlbnNlIE1JVFxuICpcbiAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbiAqIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsXG4gKiBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4gKiB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4gKiBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbiAqIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gKlxuICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbiAqIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuICpcbiAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4gKiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbiAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuICogQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbiAqIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbiAqIFRIRSBTT0ZUV0FSRS5cbiAqXG4gKiBPcmlnaW5hbGx5IGZvcmtlZCBmcm9tICh3aXRoIHRoZSBhdXRob3JcJ3MgcGVybWlzc2lvbik6XG4gKiAgIEZhYnJpY2UgQmVsbGFyZFwncyBqYXZhc2NyaXB0IHZ0MTAwIGZvciBqc2xpbnV4OlxuICogICBodHRwOi8vYmVsbGFyZC5vcmcvanNsaW51eC9cbiAqICAgQ29weXJpZ2h0IChjKSAyMDExIEZhYnJpY2UgQmVsbGFyZFxuICogICBUaGUgb3JpZ2luYWwgZGVzaWduIHJlbWFpbnMuIFRoZSB0ZXJtaW5hbCBpdHNlbGZcbiAqICAgaGFzIGJlZW4gZXh0ZW5kZWQgdG8gaW5jbHVkZSB4dGVybSBDU0kgY29kZXMsIGFtb25nXG4gKiAgIG90aGVyIGZlYXR1cmVzLlxuICovXG5cbi8qKlxuICogIERlZmF1bHQgc3R5bGVzIGZvciB4dGVybS5qc1xuICovXG5cbi54dGVybSB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XG4gICAgICAgICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgICAtbXMtdXNlci1zZWxlY3Q6IG5vbmU7XG4gICAgLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTtcbn1cblxuLnh0ZXJtLmZvY3VzLFxuLnh0ZXJtOmZvY3VzIHtcbiAgICBvdXRsaW5lOiBub25lO1xufVxuXG4ueHRlcm0gLnh0ZXJtLWhlbHBlcnMge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDA7XG4gICAgLyoqXG4gICAgICogVGhlIHotaW5kZXggb2YgdGhlIGhlbHBlcnMgbXVzdCBiZSBoaWdoZXIgdGhhbiB0aGUgY2FudmFzZXMgaW4gb3JkZXIgZm9yXG4gICAgICogSU1FcyB0byBhcHBlYXIgb24gdG9wLlxuICAgICAqL1xuICAgIHotaW5kZXg6IDU7XG59XG5cbi54dGVybSAueHRlcm0taGVscGVyLXRleHRhcmVhIHtcbiAgICBwYWRkaW5nOiAwO1xuICAgIGJvcmRlcjogMDtcbiAgICBtYXJnaW46IDA7XG4gICAgLyogTW92ZSB0ZXh0YXJlYSBvdXQgb2YgdGhlIHNjcmVlbiB0byB0aGUgZmFyIGxlZnQsIHNvIHRoYXQgdGhlIGN1cnNvciBpcyBub3QgdmlzaWJsZSAqL1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICBvcGFjaXR5OiAwO1xuICAgIGxlZnQ6IC05OTk5ZW07XG4gICAgdG9wOiAwO1xuICAgIHdpZHRoOiAwO1xuICAgIGhlaWdodDogMDtcbiAgICB6LWluZGV4OiAtNTtcbiAgICAvKiogUHJldmVudCB3cmFwcGluZyBzbyB0aGUgSU1FIGFwcGVhcnMgYWdhaW5zdCB0aGUgdGV4dGFyZWEgYXQgdGhlIGNvcnJlY3QgcG9zaXRpb24gKi9cbiAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgcmVzaXplOiBub25lO1xufVxuXG4ueHRlcm0gLmNvbXBvc2l0aW9uLXZpZXcge1xuICAgIC8qIFRPRE86IENvbXBvc2l0aW9uIHBvc2l0aW9uIGdvdCBtZXNzZWQgdXAgc29tZXdoZXJlICovXG4gICAgYmFja2dyb3VuZDogIzAwMDtcbiAgICBjb2xvcjogI0ZGRjtcbiAgICBkaXNwbGF5OiBub25lO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICAgIHotaW5kZXg6IDE7XG59XG5cbi54dGVybSAuY29tcG9zaXRpb24tdmlldy5hY3RpdmUge1xuICAgIGRpc3BsYXk6IGJsb2NrO1xufVxuXG4ueHRlcm0gLnh0ZXJtLXZpZXdwb3J0IHtcbiAgICAvKiBPbiBPUyBYIHRoaXMgaXMgcmVxdWlyZWQgaW4gb3JkZXIgZm9yIHRoZSBzY3JvbGwgYmFyIHRvIGFwcGVhciBmdWxseSBvcGFxdWUgKi9cbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwO1xuICAgIG92ZXJmbG93LXk6IHNjcm9sbDtcbiAgICBjdXJzb3I6IGRlZmF1bHQ7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHJpZ2h0OiAwO1xuICAgIGxlZnQ6IDA7XG4gICAgdG9wOiAwO1xuICAgIGJvdHRvbTogMDtcbn1cblxuLnh0ZXJtIC54dGVybS1zY3JlZW4ge1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbn1cblxuLnh0ZXJtIC54dGVybS1zY3JlZW4gY2FudmFzIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgbGVmdDogMDtcbiAgICB0b3A6IDA7XG59XG5cbi54dGVybSAueHRlcm0tc2Nyb2xsLWFyZWEge1xuICAgIHZpc2liaWxpdHk6IGhpZGRlbjtcbn1cblxuLnh0ZXJtLWNoYXItbWVhc3VyZS1lbGVtZW50IHtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgdmlzaWJpbGl0eTogaGlkZGVuO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDA7XG4gICAgbGVmdDogLTk5OTllbTtcbiAgICBsaW5lLWhlaWdodDogbm9ybWFsO1xufVxuXG4ueHRlcm0ge1xuICAgIGN1cnNvcjogdGV4dDtcbn1cblxuLnh0ZXJtLmVuYWJsZS1tb3VzZS1ldmVudHMge1xuICAgIC8qIFdoZW4gbW91c2UgZXZlbnRzIGFyZSBlbmFibGVkIChlZy4gdG11eCksIHJldmVydCB0byB0aGUgc3RhbmRhcmQgcG9pbnRlciBjdXJzb3IgKi9cbiAgICBjdXJzb3I6IGRlZmF1bHQ7XG59XG5cbi54dGVybS54dGVybS1jdXJzb3ItcG9pbnRlcixcbi54dGVybSAueHRlcm0tY3Vyc29yLXBvaW50ZXIge1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbn1cblxuLnh0ZXJtLmNvbHVtbi1zZWxlY3QuZm9jdXMge1xuICAgIC8qIENvbHVtbiBzZWxlY3Rpb24gbW9kZSAqL1xuICAgIGN1cnNvcjogY3Jvc3NoYWlyO1xufVxuXG4ueHRlcm0gLnh0ZXJtLWFjY2Vzc2liaWxpdHksXG4ueHRlcm0gLnh0ZXJtLW1lc3NhZ2Uge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICBsZWZ0OiAwO1xuICAgIHRvcDogMDtcbiAgICBib3R0b206IDA7XG4gICAgcmlnaHQ6IDA7XG4gICAgei1pbmRleDogMTA7XG4gICAgY29sb3I6IHRyYW5zcGFyZW50O1xufVxuXG4ueHRlcm0gLmxpdmUtcmVnaW9uIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgbGVmdDogLTk5OTlweDtcbiAgICB3aWR0aDogMXB4O1xuICAgIGhlaWdodDogMXB4O1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG59XG5cbi54dGVybS1kaW0ge1xuICAgIG9wYWNpdHk6IDAuNTtcbn1cblxuLnh0ZXJtLXVuZGVybGluZSB7XG4gICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XG59XG5cbi54dGVybS1zdHJpa2V0aHJvdWdoIHtcbiAgICB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDtcbn1cbicsIiJdKTtjb25zdCBhPXN9LDY0NTplPT57InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdD1bXTtyZXR1cm4gdC50b1N0cmluZz1mdW5jdGlvbigpe3JldHVybiB0aGlzLm1hcCgoZnVuY3Rpb24odCl7dmFyIHI9IiIsaT12b2lkIDAhPT10WzVdO3JldHVybiB0WzRdJiYocis9IkBzdXBwb3J0cyAoIi5jb25jYXQodFs0XSwiKSB7IikpLHRbMl0mJihyKz0iQG1lZGlhICIuY29uY2F0KHRbMl0sIiB7IikpLGkmJihyKz0iQGxheWVyIi5jb25jYXQodFs1XS5sZW5ndGg+MD8iICIuY29uY2F0KHRbNV0pOiIiLCIgeyIpKSxyKz1lKHQpLGkmJihyKz0ifSIpLHRbMl0mJihyKz0ifSIpLHRbNF0mJihyKz0ifSIpLHJ9KSkuam9pbigiIil9LHQuaT1mdW5jdGlvbihlLHIsaSxuLG8peyJzdHJpbmciPT10eXBlb2YgZSYmKGU9W1tudWxsLGUsdm9pZCAwXV0pO3ZhciBzPXt9O2lmKGkpZm9yKHZhciBhPTA7YTx0aGlzLmxlbmd0aDthKyspe3ZhciBjPXRoaXNbYV1bMF07bnVsbCE9YyYmKHNbY109ITApfWZvcih2YXIgbD0wO2w8ZS5sZW5ndGg7bCsrKXt2YXIgdT1bXS5jb25jYXQoZVtsXSk7aSYmc1t1WzBdXXx8KHZvaWQgMCE9PW8mJih2b2lkIDA9PT11WzVdfHwodVsxXT0iQGxheWVyIi5jb25jYXQodVs1XS5sZW5ndGg+MD8iICIuY29uY2F0KHVbNV0pOiIiLCIgeyIpLmNvbmNhdCh1WzFdLCJ9IikpLHVbNV09byksciYmKHVbMl0/KHVbMV09IkBtZWRpYSAiLmNvbmNhdCh1WzJdLCIgeyIpLmNvbmNhdCh1WzFdLCJ9IiksdVsyXT1yKTp1WzJdPXIpLG4mJih1WzRdPyh1WzFdPSJAc3VwcG9ydHMgKCIuY29uY2F0KHVbNF0sIikgeyIpLmNvbmNhdCh1WzFdLCJ9IiksdVs0XT1uKTp1WzRdPSIiLmNvbmNhdChuKSksdC5wdXNoKHUpKX19LHR9fSw4MTplPT57InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXtyZXR1cm4gZVsxXX19LDQ4NjpmdW5jdGlvbihlLHQscil7dmFyIGk7ZT1yLm5tZChlKSxmdW5jdGlvbigpe3ZhciBuLG89IkV4cGVjdGVkIGEgZnVuY3Rpb24iLHM9Il9fbG9kYXNoX2hhc2hfdW5kZWZpbmVkX18iLGE9Il9fbG9kYXNoX3BsYWNlaG9sZGVyX18iLGM9MzIsbD0xMjgsdT0xLzAsaD05MDA3MTk5MjU0NzQwOTkxLGY9TmFOLF89NDI5NDk2NzI5NSxkPVtbImFyeSIsbF0sWyJiaW5kIiwxXSxbImJpbmRLZXkiLDJdLFsiY3VycnkiLDhdLFsiY3VycnlSaWdodCIsMTZdLFsiZmxpcCIsNTEyXSxbInBhcnRpYWwiLGNdLFsicGFydGlhbFJpZ2h0Iiw2NF0sWyJyZWFyZyIsMjU2XV0scD0iW29iamVjdCBBcmd1bWVudHNdIix2PSJbb2JqZWN0IEFycmF5XSIsZz0iW29iamVjdCBCb29sZWFuXSIseT0iW29iamVjdCBEYXRlXSIsbT0iW29iamVjdCBFcnJvcl0iLGI9IltvYmplY3QgRnVuY3Rpb25dIixTPSJbb2JqZWN0IEdlbmVyYXRvckZ1bmN0aW9uXSIsQz0iW29iamVjdCBNYXBdIix3PSJbb2JqZWN0IE51bWJlcl0iLEw9IltvYmplY3QgT2JqZWN0XSIsRT0iW29iamVjdCBQcm9taXNlXSIseD0iW29iamVjdCBSZWdFeHBdIixBPSJbb2JqZWN0IFNldF0iLGs9IltvYmplY3QgU3RyaW5nXSIsTT0iW29iamVjdCBTeW1ib2xdIixSPSJbb2JqZWN0IFdlYWtNYXBdIixUPSJbb2JqZWN0IEFycmF5QnVmZmVyXSIsTz0iW29iamVjdCBEYXRhVmlld10iLEI9IltvYmplY3QgRmxvYXQzMkFycmF5XSIsRD0iW29iamVjdCBGbG9hdDY0QXJyYXldIixQPSJbb2JqZWN0IEludDhBcnJheV0iLEk9IltvYmplY3QgSW50MTZBcnJheV0iLEg9IltvYmplY3QgSW50MzJBcnJheV0iLGo9IltvYmplY3QgVWludDhBcnJheV0iLEY9IltvYmplY3QgVWludDhDbGFtcGVkQXJyYXldIixXPSJbb2JqZWN0IFVpbnQxNkFycmF5XSIsVT0iW29iamVjdCBVaW50MzJBcnJheV0iLHE9L1xiX19wIFwrPSAnJzsvZyxOPS9cYihfX3AgXCs9KSAnJyBcKy9nLHo9LyhfX2VcKC4qP1wpfFxiX190XCkpIFwrXG4nJzsvZyxLPS8mKD86YW1wfGx0fGd0fHF1b3R8IzM5KTsvZyxWPS9bJjw+IiddL2csRz1SZWdFeHAoSy5zb3VyY2UpLFk9UmVnRXhwKFYuc291cmNlKSxYPS88JS0oW1xzXFNdKz8pJT4vZyxaPS88JShbXHNcU10rPyklPi9nLEo9LzwlPShbXHNcU10rPyklPi9nLCQ9L1wufFxbKD86W15bXF1dKnwoWyInXSkoPzooPyFcMSlbXlxcXXxcXC4pKj9cMSlcXS8sUT0vXlx3KiQvLGVlPS9bXi5bXF1dK3xcWyg/OigtP1xkKyg/OlwuXGQrKT8pfChbIiddKSgoPzooPyFcMilbXlxcXXxcXC4pKj8pXDIpXF18KD89KD86XC58XFtcXSkoPzpcLnxcW1xdfCQpKS9nLHRlPS9bXFxeJC4qKz8oKVtcXXt9fF0vZyxyZT1SZWdFeHAodGUuc291cmNlKSxpZT0vXlxzKy8sbmU9L1xzLyxvZT0vXHsoPzpcblwvXCogXFt3cmFwcGVkIHdpdGggLitcXSBcKlwvKT9cbj8vLHNlPS9ce1xuXC9cKiBcW3dyYXBwZWQgd2l0aCAoLispXF0gXCovLGFlPS8sPyAmIC8sY2U9L1teXHgwMC1ceDJmXHgzYS1ceDQwXHg1Yi1ceDYwXHg3Yi1ceDdmXSsvZyxsZT0vWygpPSx7fVxbXF1cL1xzXS8sdWU9L1xcKFxcKT8vZyxoZT0vXCRceyhbXlxcfV0qKD86XFwuW15cXH1dKikqKVx9L2csZmU9L1x3KiQvLF9lPS9eWy0rXTB4WzAtOWEtZl0rJC9pLGRlPS9eMGJbMDFdKyQvaSxwZT0vXlxbb2JqZWN0IC4rP0NvbnN0cnVjdG9yXF0kLyx2ZT0vXjBvWzAtN10rJC9pLGdlPS9eKD86MHxbMS05XVxkKikkLyx5ZT0vW1x4YzAtXHhkNlx4ZDgtXHhmNlx4ZjgtXHhmZlx1MDEwMC1cdTAxN2ZdL2csbWU9LygkXikvLGJlPS9bJ1xuXHJcdTIwMjhcdTIwMjlcXF0vZyxTZT0iXFx1MDMwMC1cXHUwMzZmXFx1ZmUyMC1cXHVmZTJmXFx1MjBkMC1cXHUyMGZmIixDZT0iYS16XFx4ZGYtXFx4ZjZcXHhmOC1cXHhmZiIsd2U9IkEtWlxceGMwLVxceGQ2XFx4ZDgtXFx4ZGUiLExlPSJcXHhhY1xceGIxXFx4ZDdcXHhmN1xceDAwLVxceDJmXFx4M2EtXFx4NDBcXHg1Yi1cXHg2MFxceDdiLVxceGJmXFx1MjAwMC1cXHUyMDZmIFxcdFxceDBiXFxmXFx4YTBcXHVmZWZmXFxuXFxyXFx1MjAyOFxcdTIwMjlcXHUxNjgwXFx1MTgwZVxcdTIwMDBcXHUyMDAxXFx1MjAwMlxcdTIwMDNcXHUyMDA0XFx1MjAwNVxcdTIwMDZcXHUyMDA3XFx1MjAwOFxcdTIwMDlcXHUyMDBhXFx1MjAyZlxcdTIwNWZcXHUzMDAwIixFZT0iWyIrTGUrIl0iLHhlPSJbIitTZSsiXSIsQWU9IlxcZCsiLGtlPSJbIitDZSsiXSIsTWU9IlteXFx1ZDgwMC1cXHVkZmZmIitMZStBZSsiXFx1MjcwMC1cXHUyN2JmIitDZSt3ZSsiXSIsUmU9IlxcdWQ4M2NbXFx1ZGZmYi1cXHVkZmZmXSIsVGU9IlteXFx1ZDgwMC1cXHVkZmZmXSIsT2U9Iig/OlxcdWQ4M2NbXFx1ZGRlNi1cXHVkZGZmXSl7Mn0iLEJlPSJbXFx1ZDgwMC1cXHVkYmZmXVtcXHVkYzAwLVxcdWRmZmZdIixEZT0iWyIrd2UrIl0iLFBlPSIoPzoiK2tlKyJ8IitNZSsiKSIsSWU9Iig/OiIrRGUrInwiK01lKyIpIixIZT0iKD86WyfigJldKD86ZHxsbHxtfHJlfHN8dHx2ZSkpPyIsamU9Iig/Olsn4oCZXSg/OkR8TEx8TXxSRXxTfFR8VkUpKT8iLEZlPSIoPzoiK3hlKyJ8IitSZSsiKT8iLFdlPSJbXFx1ZmUwZVxcdWZlMGZdPyIsVWU9V2UrRmUrIig/OlxcdTIwMGQoPzoiK1tUZSxPZSxCZV0uam9pbigifCIpKyIpIitXZStGZSsiKSoiLHFlPSIoPzoiK1siW1xcdTI3MDAtXFx1MjdiZl0iLE9lLEJlXS5qb2luKCJ8IikrIikiK1VlLE5lPSIoPzoiK1tUZSt4ZSsiPyIseGUsT2UsQmUsIltcXHVkODAwLVxcdWRmZmZdIl0uam9pbigifCIpKyIpIix6ZT1SZWdFeHAoIlsn4oCZXSIsImciKSxLZT1SZWdFeHAoeGUsImciKSxWZT1SZWdFeHAoUmUrIig/PSIrUmUrIil8IitOZStVZSwiZyIpLEdlPVJlZ0V4cChbRGUrIj8iK2tlKyIrIitIZSsiKD89IitbRWUsRGUsIiQiXS5qb2luKCJ8IikrIikiLEllKyIrIitqZSsiKD89IitbRWUsRGUrUGUsIiQiXS5qb2luKCJ8IikrIikiLERlKyI/IitQZSsiKyIrSGUsRGUrIisiK2plLCJcXGQqKD86MVNUfDJORHwzUkR8KD8hWzEyM10pXFxkVEgpKD89XFxifFthLXpfXSkiLCJcXGQqKD86MXN0fDJuZHwzcmR8KD8hWzEyM10pXFxkdGgpKD89XFxifFtBLVpfXSkiLEFlLHFlXS5qb2luKCJ8IiksImciKSxZZT1SZWdFeHAoIltcXHUyMDBkXFx1ZDgwMC1cXHVkZmZmIitTZSsiXFx1ZmUwZVxcdWZlMGZdIiksWGU9L1thLXpdW0EtWl18W0EtWl17Mn1bYS16XXxbMC05XVthLXpBLVpdfFthLXpBLVpdWzAtOV18W15hLXpBLVowLTkgXS8sWmU9WyJBcnJheSIsIkJ1ZmZlciIsIkRhdGFWaWV3IiwiRGF0ZSIsIkVycm9yIiwiRmxvYXQzMkFycmF5IiwiRmxvYXQ2NEFycmF5IiwiRnVuY3Rpb24iLCJJbnQ4QXJyYXkiLCJJbnQxNkFycmF5IiwiSW50MzJBcnJheSIsIk1hcCIsIk1hdGgiLCJPYmplY3QiLCJQcm9taXNlIiwiUmVnRXhwIiwiU2V0IiwiU3RyaW5nIiwiU3ltYm9sIiwiVHlwZUVycm9yIiwiVWludDhBcnJheSIsIlVpbnQ4Q2xhbXBlZEFycmF5IiwiVWludDE2QXJyYXkiLCJVaW50MzJBcnJheSIsIldlYWtNYXAiLCJfIiwiY2xlYXJUaW1lb3V0IiwiaXNGaW5pdGUiLCJwYXJzZUludCIsInNldFRpbWVvdXQiXSxKZT0tMSwkZT17fTskZVtCXT0kZVtEXT0kZVtQXT0kZVtJXT0kZVtIXT0kZVtqXT0kZVtGXT0kZVtXXT0kZVtVXT0hMCwkZVtwXT0kZVt2XT0kZVtUXT0kZVtnXT0kZVtPXT0kZVt5XT0kZVttXT0kZVtiXT0kZVtDXT0kZVt3XT0kZVtMXT0kZVt4XT0kZVtBXT0kZVtrXT0kZVtSXT0hMTt2YXIgUWU9e307UWVbcF09UWVbdl09UWVbVF09UWVbT109UWVbZ109UWVbeV09UWVbQl09UWVbRF09UWVbUF09UWVbSV09UWVbSF09UWVbQ109UWVbd109UWVbTF09UWVbeF09UWVbQV09UWVba109UWVbTV09UWVbal09UWVbRl09UWVbV109UWVbVV09ITAsUWVbbV09UWVbYl09UWVbUl09ITE7dmFyIGV0PXsiXFwiOiJcXCIsIiciOiInIiwiXG4iOiJuIiwiXHIiOiJyIiwiXHUyMDI4IjoidTIwMjgiLCJcdTIwMjkiOiJ1MjAyOSJ9LHR0PXBhcnNlRmxvYXQscnQ9cGFyc2VJbnQsaXQ9Im9iamVjdCI9PXR5cGVvZiByLmcmJnIuZyYmci5nLk9iamVjdD09PU9iamVjdCYmci5nLG50PSJvYmplY3QiPT10eXBlb2Ygc2VsZiYmc2VsZiYmc2VsZi5PYmplY3Q9PT1PYmplY3QmJnNlbGYsb3Q9aXR8fG50fHxGdW5jdGlvbigicmV0dXJuIHRoaXMiKSgpLHN0PXQmJiF0Lm5vZGVUeXBlJiZ0LGF0PXN0JiZlJiYhZS5ub2RlVHlwZSYmZSxjdD1hdCYmYXQuZXhwb3J0cz09PXN0LGx0PWN0JiZpdC5wcm9jZXNzLHV0PWZ1bmN0aW9uKCl7dHJ5e3JldHVybiBhdCYmYXQucmVxdWlyZSYmYXQucmVxdWlyZSgidXRpbCIpLnR5cGVzfHxsdCYmbHQuYmluZGluZyYmbHQuYmluZGluZygidXRpbCIpfWNhdGNoKGUpe319KCksaHQ9dXQmJnV0LmlzQXJyYXlCdWZmZXIsZnQ9dXQmJnV0LmlzRGF0ZSxfdD11dCYmdXQuaXNNYXAsZHQ9dXQmJnV0LmlzUmVnRXhwLHB0PXV0JiZ1dC5pc1NldCx2dD11dCYmdXQuaXNUeXBlZEFycmF5O2Z1bmN0aW9uIGd0KGUsdCxyKXtzd2l0Y2goci5sZW5ndGgpe2Nhc2UgMDpyZXR1cm4gZS5jYWxsKHQpO2Nhc2UgMTpyZXR1cm4gZS5jYWxsKHQsclswXSk7Y2FzZSAyOnJldHVybiBlLmNhbGwodCxyWzBdLHJbMV0pO2Nhc2UgMzpyZXR1cm4gZS5jYWxsKHQsclswXSxyWzFdLHJbMl0pfXJldHVybiBlLmFwcGx5KHQscil9ZnVuY3Rpb24geXQoZSx0LHIsaSl7Zm9yKHZhciBuPS0xLG89bnVsbD09ZT8wOmUubGVuZ3RoOysrbjxvOyl7dmFyIHM9ZVtuXTt0KGkscyxyKHMpLGUpfXJldHVybiBpfWZ1bmN0aW9uIG10KGUsdCl7Zm9yKHZhciByPS0xLGk9bnVsbD09ZT8wOmUubGVuZ3RoOysrcjxpJiYhMSE9PXQoZVtyXSxyLGUpOyk7cmV0dXJuIGV9ZnVuY3Rpb24gYnQoZSx0KXtmb3IodmFyIHI9bnVsbD09ZT8wOmUubGVuZ3RoO3ItLSYmITEhPT10KGVbcl0scixlKTspO3JldHVybiBlfWZ1bmN0aW9uIFN0KGUsdCl7Zm9yKHZhciByPS0xLGk9bnVsbD09ZT8wOmUubGVuZ3RoOysrcjxpOylpZighdChlW3JdLHIsZSkpcmV0dXJuITE7cmV0dXJuITB9ZnVuY3Rpb24gQ3QoZSx0KXtmb3IodmFyIHI9LTEsaT1udWxsPT1lPzA6ZS5sZW5ndGgsbj0wLG89W107KytyPGk7KXt2YXIgcz1lW3JdO3QocyxyLGUpJiYob1tuKytdPXMpfXJldHVybiBvfWZ1bmN0aW9uIHd0KGUsdCl7cmV0dXJuIShudWxsPT1lfHwhZS5sZW5ndGgpJiZCdChlLHQsMCk+LTF9ZnVuY3Rpb24gTHQoZSx0LHIpe2Zvcih2YXIgaT0tMSxuPW51bGw9PWU/MDplLmxlbmd0aDsrK2k8bjspaWYocih0LGVbaV0pKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIEV0KGUsdCl7Zm9yKHZhciByPS0xLGk9bnVsbD09ZT8wOmUubGVuZ3RoLG49QXJyYXkoaSk7KytyPGk7KW5bcl09dChlW3JdLHIsZSk7cmV0dXJuIG59ZnVuY3Rpb24geHQoZSx0KXtmb3IodmFyIHI9LTEsaT10Lmxlbmd0aCxuPWUubGVuZ3RoOysrcjxpOyllW24rcl09dFtyXTtyZXR1cm4gZX1mdW5jdGlvbiBBdChlLHQscixpKXt2YXIgbj0tMSxvPW51bGw9PWU/MDplLmxlbmd0aDtmb3IoaSYmbyYmKHI9ZVsrK25dKTsrK248bzspcj10KHIsZVtuXSxuLGUpO3JldHVybiByfWZ1bmN0aW9uIGt0KGUsdCxyLGkpe3ZhciBuPW51bGw9PWU/MDplLmxlbmd0aDtmb3IoaSYmbiYmKHI9ZVstLW5dKTtuLS07KXI9dChyLGVbbl0sbixlKTtyZXR1cm4gcn1mdW5jdGlvbiBNdChlLHQpe2Zvcih2YXIgcj0tMSxpPW51bGw9PWU/MDplLmxlbmd0aDsrK3I8aTspaWYodChlW3JdLHIsZSkpcmV0dXJuITA7cmV0dXJuITF9dmFyIFJ0PUh0KCJsZW5ndGgiKTtmdW5jdGlvbiBUdChlLHQscil7dmFyIGk7cmV0dXJuIHIoZSwoZnVuY3Rpb24oZSxyLG4pe2lmKHQoZSxyLG4pKXJldHVybiBpPXIsITF9KSksaX1mdW5jdGlvbiBPdChlLHQscixpKXtmb3IodmFyIG49ZS5sZW5ndGgsbz1yKyhpPzE6LTEpO2k/by0tOisrbzxuOylpZih0KGVbb10sbyxlKSlyZXR1cm4gbztyZXR1cm4tMX1mdW5jdGlvbiBCdChlLHQscil7cmV0dXJuIHQ9PXQ/ZnVuY3Rpb24oZSx0LHIpe2Zvcih2YXIgaT1yLTEsbj1lLmxlbmd0aDsrK2k8bjspaWYoZVtpXT09PXQpcmV0dXJuIGk7cmV0dXJuLTF9KGUsdCxyKTpPdChlLFB0LHIpfWZ1bmN0aW9uIER0KGUsdCxyLGkpe2Zvcih2YXIgbj1yLTEsbz1lLmxlbmd0aDsrK248bzspaWYoaShlW25dLHQpKXJldHVybiBuO3JldHVybi0xfWZ1bmN0aW9uIFB0KGUpe3JldHVybiBlIT1lfWZ1bmN0aW9uIEl0KGUsdCl7dmFyIHI9bnVsbD09ZT8wOmUubGVuZ3RoO3JldHVybiByP1d0KGUsdCkvcjpmfWZ1bmN0aW9uIEh0KGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gbnVsbD09dD9uOnRbZV19fWZ1bmN0aW9uIGp0KGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gbnVsbD09ZT9uOmVbdF19fWZ1bmN0aW9uIEZ0KGUsdCxyLGksbil7cmV0dXJuIG4oZSwoZnVuY3Rpb24oZSxuLG8pe3I9aT8oaT0hMSxlKTp0KHIsZSxuLG8pfSkpLHJ9ZnVuY3Rpb24gV3QoZSx0KXtmb3IodmFyIHIsaT0tMSxvPWUubGVuZ3RoOysraTxvOyl7dmFyIHM9dChlW2ldKTtzIT09biYmKHI9cj09PW4/czpyK3MpfXJldHVybiByfWZ1bmN0aW9uIFV0KGUsdCl7Zm9yKHZhciByPS0xLGk9QXJyYXkoZSk7KytyPGU7KWlbcl09dChyKTtyZXR1cm4gaX1mdW5jdGlvbiBxdChlKXtyZXR1cm4gZT9lLnNsaWNlKDAsc3IoZSkrMSkucmVwbGFjZShpZSwiIik6ZX1mdW5jdGlvbiBOdChlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIGUodCl9fWZ1bmN0aW9uIHp0KGUsdCl7cmV0dXJuIEV0KHQsKGZ1bmN0aW9uKHQpe3JldHVybiBlW3RdfSkpfWZ1bmN0aW9uIEt0KGUsdCl7cmV0dXJuIGUuaGFzKHQpfWZ1bmN0aW9uIFZ0KGUsdCl7Zm9yKHZhciByPS0xLGk9ZS5sZW5ndGg7KytyPGkmJkJ0KHQsZVtyXSwwKT4tMTspO3JldHVybiByfWZ1bmN0aW9uIEd0KGUsdCl7Zm9yKHZhciByPWUubGVuZ3RoO3ItLSYmQnQodCxlW3JdLDApPi0xOyk7cmV0dXJuIHJ9ZnVuY3Rpb24gWXQoZSx0KXtmb3IodmFyIHI9ZS5sZW5ndGgsaT0wO3ItLTspZVtyXT09PXQmJisraTtyZXR1cm4gaX12YXIgWHQ9anQoe8OAOiJBIizDgToiQSIsw4I6IkEiLMODOiJBIizDhDoiQSIsw4U6IkEiLMOgOiJhIizDoToiYSIsw6I6ImEiLMOjOiJhIizDpDoiYSIsw6U6ImEiLMOHOiJDIizDpzoiYyIsw5A6IkQiLMOwOiJkIizDiDoiRSIsw4k6IkUiLMOKOiJFIizDizoiRSIsw6g6ImUiLMOpOiJlIizDqjoiZSIsw6s6ImUiLMOMOiJJIizDjToiSSIsw446IkkiLMOPOiJJIizDrDoiaSIsw606ImkiLMOuOiJpIizDrzoiaSIsw5E6Ik4iLMOxOiJuIizDkjoiTyIsw5M6Ik8iLMOUOiJPIizDlToiTyIsw5Y6Ik8iLMOYOiJPIizDsjoibyIsw7M6Im8iLMO0OiJvIizDtToibyIsw7Y6Im8iLMO4OiJvIizDmToiVSIsw5o6IlUiLMObOiJVIizDnDoiVSIsw7k6InUiLMO6OiJ1IizDuzoidSIsw7w6InUiLMOdOiJZIizDvToieSIsw786InkiLMOGOiJBZSIsw6Y6ImFlIizDnjoiVGgiLMO+OiJ0aCIsw586InNzIizEgDoiQSIsxII6IkEiLMSEOiJBIizEgToiYSIsxIM6ImEiLMSFOiJhIizEhjoiQyIsxIg6IkMiLMSKOiJDIizEjDoiQyIsxIc6ImMiLMSJOiJjIizEizoiYyIsxI06ImMiLMSOOiJEIizEkDoiRCIsxI86ImQiLMSROiJkIizEkjoiRSIsxJQ6IkUiLMSWOiJFIizEmDoiRSIsxJo6IkUiLMSTOiJlIizElToiZSIsxJc6ImUiLMSZOiJlIizEmzoiZSIsxJw6IkciLMSeOiJHIizEoDoiRyIsxKI6IkciLMSdOiJnIizEnzoiZyIsxKE6ImciLMSjOiJnIizEpDoiSCIsxKY6IkgiLMSlOiJoIizEpzoiaCIsxKg6IkkiLMSqOiJJIizErDoiSSIsxK46IkkiLMSwOiJJIizEqToiaSIsxKs6ImkiLMStOiJpIizErzoiaSIsxLE6ImkiLMS0OiJKIizEtToiaiIsxLY6IksiLMS3OiJrIizEuDoiayIsxLk6IkwiLMS7OiJMIizEvToiTCIsxL86IkwiLMWBOiJMIizEujoibCIsxLw6ImwiLMS+OiJsIizFgDoibCIsxYI6ImwiLMWDOiJOIizFhToiTiIsxYc6Ik4iLMWKOiJOIizFhDoibiIsxYY6Im4iLMWIOiJuIizFizoibiIsxYw6Ik8iLMWOOiJPIizFkDoiTyIsxY06Im8iLMWPOiJvIizFkToibyIsxZQ6IlIiLMWWOiJSIizFmDoiUiIsxZU6InIiLMWXOiJyIizFmToiciIsxZo6IlMiLMWcOiJTIizFnjoiUyIsxaA6IlMiLMWbOiJzIizFnToicyIsxZ86InMiLMWhOiJzIizFojoiVCIsxaQ6IlQiLMWmOiJUIizFozoidCIsxaU6InQiLMWnOiJ0IizFqDoiVSIsxao6IlUiLMWsOiJVIizFrjoiVSIsxbA6IlUiLMWyOiJVIizFqToidSIsxas6InUiLMWtOiJ1IizFrzoidSIsxbE6InUiLMWzOiJ1IizFtDoiVyIsxbU6InciLMW2OiJZIizFtzoieSIsxbg6IlkiLMW5OiJaIizFuzoiWiIsxb06IloiLMW6OiJ6IizFvDoieiIsxb46InoiLMSyOiJJSiIsxLM6ImlqIizFkjoiT2UiLMWTOiJvZSIsxYk6IiduIizFvzoicyJ9KSxadD1qdCh7IiYiOiImYW1wOyIsIjwiOiImbHQ7IiwiPiI6IiZndDsiLCciJzoiJnF1b3Q7IiwiJyI6IiYjMzk7In0pO2Z1bmN0aW9uIEp0KGUpe3JldHVybiJcXCIrZXRbZV19ZnVuY3Rpb24gJHQoZSl7cmV0dXJuIFllLnRlc3QoZSl9ZnVuY3Rpb24gUXQoZSl7dmFyIHQ9LTEscj1BcnJheShlLnNpemUpO3JldHVybiBlLmZvckVhY2goKGZ1bmN0aW9uKGUsaSl7clsrK3RdPVtpLGVdfSkpLHJ9ZnVuY3Rpb24gZXIoZSx0KXtyZXR1cm4gZnVuY3Rpb24ocil7cmV0dXJuIGUodChyKSl9fWZ1bmN0aW9uIHRyKGUsdCl7Zm9yKHZhciByPS0xLGk9ZS5sZW5ndGgsbj0wLG89W107KytyPGk7KXt2YXIgcz1lW3JdO3MhPT10JiZzIT09YXx8KGVbcl09YSxvW24rK109cil9cmV0dXJuIG99ZnVuY3Rpb24gcnIoZSl7dmFyIHQ9LTEscj1BcnJheShlLnNpemUpO3JldHVybiBlLmZvckVhY2goKGZ1bmN0aW9uKGUpe3JbKyt0XT1lfSkpLHJ9ZnVuY3Rpb24gaXIoZSl7dmFyIHQ9LTEscj1BcnJheShlLnNpemUpO3JldHVybiBlLmZvckVhY2goKGZ1bmN0aW9uKGUpe3JbKyt0XT1bZSxlXX0pKSxyfWZ1bmN0aW9uIG5yKGUpe3JldHVybiAkdChlKT9mdW5jdGlvbihlKXtmb3IodmFyIHQ9VmUubGFzdEluZGV4PTA7VmUudGVzdChlKTspKyt0O3JldHVybiB0fShlKTpSdChlKX1mdW5jdGlvbiBvcihlKXtyZXR1cm4gJHQoZSk/ZnVuY3Rpb24oZSl7cmV0dXJuIGUubWF0Y2goVmUpfHxbXX0oZSk6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc3BsaXQoIiIpfShlKX1mdW5jdGlvbiBzcihlKXtmb3IodmFyIHQ9ZS5sZW5ndGg7dC0tJiZuZS50ZXN0KGUuY2hhckF0KHQpKTspO3JldHVybiB0fXZhciBhcj1qdCh7IiZhbXA7IjoiJiIsIiZsdDsiOiI8IiwiJmd0OyI6Ij4iLCImcXVvdDsiOiciJywiJiMzOTsiOiInIn0pLGNyPWZ1bmN0aW9uIGUodCl7dmFyIHIsaT0odD1udWxsPT10P290OmNyLmRlZmF1bHRzKG90Lk9iamVjdCgpLHQsY3IucGljayhvdCxaZSkpKS5BcnJheSxuZT10LkRhdGUsU2U9dC5FcnJvcixDZT10LkZ1bmN0aW9uLHdlPXQuTWF0aCxMZT10Lk9iamVjdCxFZT10LlJlZ0V4cCx4ZT10LlN0cmluZyxBZT10LlR5cGVFcnJvcixrZT1pLnByb3RvdHlwZSxNZT1DZS5wcm90b3R5cGUsUmU9TGUucHJvdG90eXBlLFRlPXRbIl9fY29yZS1qc19zaGFyZWRfXyJdLE9lPU1lLnRvU3RyaW5nLEJlPVJlLmhhc093blByb3BlcnR5LERlPTAsUGU9KHI9L1teLl0rJC8uZXhlYyhUZSYmVGUua2V5cyYmVGUua2V5cy5JRV9QUk9UT3x8IiIpKT8iU3ltYm9sKHNyYylfMS4iK3I6IiIsSWU9UmUudG9TdHJpbmcsSGU9T2UuY2FsbChMZSksamU9b3QuXyxGZT1FZSgiXiIrT2UuY2FsbChCZSkucmVwbGFjZSh0ZSwiXFwkJiIpLnJlcGxhY2UoL2hhc093blByb3BlcnR5fChmdW5jdGlvbikuKj8oPz1cXFwoKXwgZm9yIC4rPyg/PVxcXF0pL2csIiQxLio/IikrIiQiKSxXZT1jdD90LkJ1ZmZlcjpuLFVlPXQuU3ltYm9sLHFlPXQuVWludDhBcnJheSxOZT1XZT9XZS5hbGxvY1Vuc2FmZTpuLFZlPWVyKExlLmdldFByb3RvdHlwZU9mLExlKSxZZT1MZS5jcmVhdGUsZXQ9UmUucHJvcGVydHlJc0VudW1lcmFibGUsaXQ9a2Uuc3BsaWNlLG50PVVlP1VlLmlzQ29uY2F0U3ByZWFkYWJsZTpuLHN0PVVlP1VlLml0ZXJhdG9yOm4sYXQ9VWU/VWUudG9TdHJpbmdUYWc6bixsdD1mdW5jdGlvbigpe3RyeXt2YXIgZT1sbyhMZSwiZGVmaW5lUHJvcGVydHkiKTtyZXR1cm4gZSh7fSwiIix7fSksZX1jYXRjaChlKXt9fSgpLHV0PXQuY2xlYXJUaW1lb3V0IT09b3QuY2xlYXJUaW1lb3V0JiZ0LmNsZWFyVGltZW91dCxSdD1uZSYmbmUubm93IT09b3QuRGF0ZS5ub3cmJm5lLm5vdyxqdD10LnNldFRpbWVvdXQhPT1vdC5zZXRUaW1lb3V0JiZ0LnNldFRpbWVvdXQsbHI9d2UuY2VpbCx1cj13ZS5mbG9vcixocj1MZS5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMsZnI9V2U/V2UuaXNCdWZmZXI6bixfcj10LmlzRmluaXRlLGRyPWtlLmpvaW4scHI9ZXIoTGUua2V5cyxMZSksdnI9d2UubWF4LGdyPXdlLm1pbix5cj1uZS5ub3csbXI9dC5wYXJzZUludCxicj13ZS5yYW5kb20sU3I9a2UucmV2ZXJzZSxDcj1sbyh0LCJEYXRhVmlldyIpLHdyPWxvKHQsIk1hcCIpLExyPWxvKHQsIlByb21pc2UiKSxFcj1sbyh0LCJTZXQiKSx4cj1sbyh0LCJXZWFrTWFwIiksQXI9bG8oTGUsImNyZWF0ZSIpLGtyPXhyJiZuZXcgeHIsTXI9e30sUnI9Rm8oQ3IpLFRyPUZvKHdyKSxPcj1GbyhMciksQnI9Rm8oRXIpLERyPUZvKHhyKSxQcj1VZT9VZS5wcm90b3R5cGU6bixJcj1Qcj9Qci52YWx1ZU9mOm4sSHI9UHI/UHIudG9TdHJpbmc6bjtmdW5jdGlvbiBqcihlKXtpZihyYShlKSYmIUtzKGUpJiYhKGUgaW5zdGFuY2VvZiBxcikpe2lmKGUgaW5zdGFuY2VvZiBVcilyZXR1cm4gZTtpZihCZS5jYWxsKGUsIl9fd3JhcHBlZF9fIikpcmV0dXJuIFdvKGUpfXJldHVybiBuZXcgVXIoZSl9dmFyIEZyPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe31yZXR1cm4gZnVuY3Rpb24odCl7aWYoIXRhKHQpKXJldHVybnt9O2lmKFllKXJldHVybiBZZSh0KTtlLnByb3RvdHlwZT10O3ZhciByPW5ldyBlO3JldHVybiBlLnByb3RvdHlwZT1uLHJ9fSgpO2Z1bmN0aW9uIFdyKCl7fWZ1bmN0aW9uIFVyKGUsdCl7dGhpcy5fX3dyYXBwZWRfXz1lLHRoaXMuX19hY3Rpb25zX189W10sdGhpcy5fX2NoYWluX189ISF0LHRoaXMuX19pbmRleF9fPTAsdGhpcy5fX3ZhbHVlc19fPW59ZnVuY3Rpb24gcXIoZSl7dGhpcy5fX3dyYXBwZWRfXz1lLHRoaXMuX19hY3Rpb25zX189W10sdGhpcy5fX2Rpcl9fPTEsdGhpcy5fX2ZpbHRlcmVkX189ITEsdGhpcy5fX2l0ZXJhdGVlc19fPVtdLHRoaXMuX190YWtlQ291bnRfXz1fLHRoaXMuX192aWV3c19fPVtdfWZ1bmN0aW9uIE5yKGUpe3ZhciB0PS0xLHI9bnVsbD09ZT8wOmUubGVuZ3RoO2Zvcih0aGlzLmNsZWFyKCk7Kyt0PHI7KXt2YXIgaT1lW3RdO3RoaXMuc2V0KGlbMF0saVsxXSl9fWZ1bmN0aW9uIHpyKGUpe3ZhciB0PS0xLHI9bnVsbD09ZT8wOmUubGVuZ3RoO2Zvcih0aGlzLmNsZWFyKCk7Kyt0PHI7KXt2YXIgaT1lW3RdO3RoaXMuc2V0KGlbMF0saVsxXSl9fWZ1bmN0aW9uIEtyKGUpe3ZhciB0PS0xLHI9bnVsbD09ZT8wOmUubGVuZ3RoO2Zvcih0aGlzLmNsZWFyKCk7Kyt0PHI7KXt2YXIgaT1lW3RdO3RoaXMuc2V0KGlbMF0saVsxXSl9fWZ1bmN0aW9uIFZyKGUpe3ZhciB0PS0xLHI9bnVsbD09ZT8wOmUubGVuZ3RoO2Zvcih0aGlzLl9fZGF0YV9fPW5ldyBLcjsrK3Q8cjspdGhpcy5hZGQoZVt0XSl9ZnVuY3Rpb24gR3IoZSl7dmFyIHQ9dGhpcy5fX2RhdGFfXz1uZXcgenIoZSk7dGhpcy5zaXplPXQuc2l6ZX1mdW5jdGlvbiBZcihlLHQpe3ZhciByPUtzKGUpLGk9IXImJnpzKGUpLG49IXImJiFpJiZYcyhlKSxvPSFyJiYhaSYmIW4mJnVhKGUpLHM9cnx8aXx8bnx8byxhPXM/VXQoZS5sZW5ndGgseGUpOltdLGM9YS5sZW5ndGg7Zm9yKHZhciBsIGluIGUpIXQmJiFCZS5jYWxsKGUsbCl8fHMmJigibGVuZ3RoIj09bHx8biYmKCJvZmZzZXQiPT1sfHwicGFyZW50Ij09bCl8fG8mJigiYnVmZmVyIj09bHx8ImJ5dGVMZW5ndGgiPT1sfHwiYnl0ZU9mZnNldCI9PWwpfHxnbyhsLGMpKXx8YS5wdXNoKGwpO3JldHVybiBhfWZ1bmN0aW9uIFhyKGUpe3ZhciB0PWUubGVuZ3RoO3JldHVybiB0P2VbS2koMCx0LTEpXTpufWZ1bmN0aW9uIFpyKGUsdCl7cmV0dXJuIERvKEFuKGUpLG9pKHQsMCxlLmxlbmd0aCkpfWZ1bmN0aW9uIEpyKGUpe3JldHVybiBEbyhBbihlKSl9ZnVuY3Rpb24gJHIoZSx0LHIpeyhyIT09biYmIVVzKGVbdF0scil8fHI9PT1uJiYhKHQgaW4gZSkpJiZpaShlLHQscil9ZnVuY3Rpb24gUXIoZSx0LHIpe3ZhciBpPWVbdF07QmUuY2FsbChlLHQpJiZVcyhpLHIpJiYociE9PW58fHQgaW4gZSl8fGlpKGUsdCxyKX1mdW5jdGlvbiBlaShlLHQpe2Zvcih2YXIgcj1lLmxlbmd0aDtyLS07KWlmKFVzKGVbcl1bMF0sdCkpcmV0dXJuIHI7cmV0dXJuLTF9ZnVuY3Rpb24gdGkoZSx0LHIsaSl7cmV0dXJuIHVpKGUsKGZ1bmN0aW9uKGUsbixvKXt0KGksZSxyKGUpLG8pfSkpLGl9ZnVuY3Rpb24gcmkoZSx0KXtyZXR1cm4gZSYma24odCxPYSh0KSxlKX1mdW5jdGlvbiBpaShlLHQscil7Il9fcHJvdG9fXyI9PXQmJmx0P2x0KGUsdCx7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITAsdmFsdWU6cix3cml0YWJsZTohMH0pOmVbdF09cn1mdW5jdGlvbiBuaShlLHQpe2Zvcih2YXIgcj0tMSxvPXQubGVuZ3RoLHM9aShvKSxhPW51bGw9PWU7KytyPG87KXNbcl09YT9uOkFhKGUsdFtyXSk7cmV0dXJuIHN9ZnVuY3Rpb24gb2koZSx0LHIpe3JldHVybiBlPT1lJiYociE9PW4mJihlPWU8PXI/ZTpyKSx0IT09biYmKGU9ZT49dD9lOnQpKSxlfWZ1bmN0aW9uIHNpKGUsdCxyLGksbyxzKXt2YXIgYSxjPTEmdCxsPTImdCx1PTQmdDtpZihyJiYoYT1vP3IoZSxpLG8scyk6cihlKSksYSE9PW4pcmV0dXJuIGE7aWYoIXRhKGUpKXJldHVybiBlO3ZhciBoPUtzKGUpO2lmKGgpe2lmKGE9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5sZW5ndGgscj1uZXcgZS5jb25zdHJ1Y3Rvcih0KTtyZXR1cm4gdCYmInN0cmluZyI9PXR5cGVvZiBlWzBdJiZCZS5jYWxsKGUsImluZGV4IikmJihyLmluZGV4PWUuaW5kZXgsci5pbnB1dD1lLmlucHV0KSxyfShlKSwhYylyZXR1cm4gQW4oZSxhKX1lbHNle3ZhciBmPWZvKGUpLF89Zj09Ynx8Zj09UztpZihYcyhlKSlyZXR1cm4gU24oZSxjKTtpZihmPT1MfHxmPT1wfHxfJiYhbyl7aWYoYT1sfHxfP3t9OnBvKGUpLCFjKXJldHVybiBsP2Z1bmN0aW9uKGUsdCl7cmV0dXJuIGtuKGUsaG8oZSksdCl9KGUsZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSYma24odCxCYSh0KSxlKX0oYSxlKSk6ZnVuY3Rpb24oZSx0KXtyZXR1cm4ga24oZSx1byhlKSx0KX0oZSxyaShhLGUpKX1lbHNle2lmKCFRZVtmXSlyZXR1cm4gbz9lOnt9O2E9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49ZS5jb25zdHJ1Y3Rvcjtzd2l0Y2godCl7Y2FzZSBUOnJldHVybiBDbihlKTtjYXNlIGc6Y2FzZSB5OnJldHVybiBuZXcgbigrZSk7Y2FzZSBPOnJldHVybiBmdW5jdGlvbihlLHQpe3ZhciByPXQ/Q24oZS5idWZmZXIpOmUuYnVmZmVyO3JldHVybiBuZXcgZS5jb25zdHJ1Y3RvcihyLGUuYnl0ZU9mZnNldCxlLmJ5dGVMZW5ndGgpfShlLHIpO2Nhc2UgQjpjYXNlIEQ6Y2FzZSBQOmNhc2UgSTpjYXNlIEg6Y2FzZSBqOmNhc2UgRjpjYXNlIFc6Y2FzZSBVOnJldHVybiB3bihlLHIpO2Nhc2UgQzpyZXR1cm4gbmV3IG47Y2FzZSB3OmNhc2UgazpyZXR1cm4gbmV3IG4oZSk7Y2FzZSB4OnJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1uZXcgZS5jb25zdHJ1Y3RvcihlLnNvdXJjZSxmZS5leGVjKGUpKTtyZXR1cm4gdC5sYXN0SW5kZXg9ZS5sYXN0SW5kZXgsdH0oZSk7Y2FzZSBBOnJldHVybiBuZXcgbjtjYXNlIE06cmV0dXJuIGk9ZSxJcj9MZShJci5jYWxsKGkpKTp7fX19KGUsZixjKX19c3x8KHM9bmV3IEdyKTt2YXIgZD1zLmdldChlKTtpZihkKXJldHVybiBkO3Muc2V0KGUsYSksYWEoZSk/ZS5mb3JFYWNoKChmdW5jdGlvbihpKXthLmFkZChzaShpLHQscixpLGUscykpfSkpOmlhKGUpJiZlLmZvckVhY2goKGZ1bmN0aW9uKGksbil7YS5zZXQobixzaShpLHQscixuLGUscykpfSkpO3ZhciB2PWg/bjoodT9sP3JvOnRvOmw/QmE6T2EpKGUpO3JldHVybiBtdCh2fHxlLChmdW5jdGlvbihpLG4pe3YmJihpPWVbbj1pXSksUXIoYSxuLHNpKGksdCxyLG4sZSxzKSl9KSksYX1mdW5jdGlvbiBhaShlLHQscil7dmFyIGk9ci5sZW5ndGg7aWYobnVsbD09ZSlyZXR1cm4haTtmb3IoZT1MZShlKTtpLS07KXt2YXIgbz1yW2ldLHM9dFtvXSxhPWVbb107aWYoYT09PW4mJiEobyBpbiBlKXx8IXMoYSkpcmV0dXJuITF9cmV0dXJuITB9ZnVuY3Rpb24gY2koZSx0LHIpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBlKXRocm93IG5ldyBBZShvKTtyZXR1cm4gUm8oKGZ1bmN0aW9uKCl7ZS5hcHBseShuLHIpfSksdCl9ZnVuY3Rpb24gbGkoZSx0LHIsaSl7dmFyIG49LTEsbz13dCxzPSEwLGE9ZS5sZW5ndGgsYz1bXSxsPXQubGVuZ3RoO2lmKCFhKXJldHVybiBjO3ImJih0PUV0KHQsTnQocikpKSxpPyhvPUx0LHM9ITEpOnQubGVuZ3RoPj0yMDAmJihvPUt0LHM9ITEsdD1uZXcgVnIodCkpO2U6Zm9yKDsrK248YTspe3ZhciB1PWVbbl0saD1udWxsPT1yP3U6cih1KTtpZih1PWl8fDAhPT11P3U6MCxzJiZoPT1oKXtmb3IodmFyIGY9bDtmLS07KWlmKHRbZl09PT1oKWNvbnRpbnVlIGU7Yy5wdXNoKHUpfWVsc2Ugbyh0LGgsaSl8fGMucHVzaCh1KX1yZXR1cm4gY31qci50ZW1wbGF0ZVNldHRpbmdzPXtlc2NhcGU6WCxldmFsdWF0ZTpaLGludGVycG9sYXRlOkosdmFyaWFibGU6IiIsaW1wb3J0czp7Xzpqcn19LGpyLnByb3RvdHlwZT1Xci5wcm90b3R5cGUsanIucHJvdG90eXBlLmNvbnN0cnVjdG9yPWpyLFVyLnByb3RvdHlwZT1GcihXci5wcm90b3R5cGUpLFVyLnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj1Vcixxci5wcm90b3R5cGU9RnIoV3IucHJvdG90eXBlKSxxci5wcm90b3R5cGUuY29uc3RydWN0b3I9cXIsTnIucHJvdG90eXBlLmNsZWFyPWZ1bmN0aW9uKCl7dGhpcy5fX2RhdGFfXz1Bcj9BcihudWxsKTp7fSx0aGlzLnNpemU9MH0sTnIucHJvdG90eXBlLmRlbGV0ZT1mdW5jdGlvbihlKXt2YXIgdD10aGlzLmhhcyhlKSYmZGVsZXRlIHRoaXMuX19kYXRhX19bZV07cmV0dXJuIHRoaXMuc2l6ZS09dD8xOjAsdH0sTnIucHJvdG90eXBlLmdldD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9fZGF0YV9fO2lmKEFyKXt2YXIgcj10W2VdO3JldHVybiByPT09cz9uOnJ9cmV0dXJuIEJlLmNhbGwodCxlKT90W2VdOm59LE5yLnByb3RvdHlwZS5oYXM9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fX2RhdGFfXztyZXR1cm4gQXI/dFtlXSE9PW46QmUuY2FsbCh0LGUpfSxOci5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUsdCl7dmFyIHI9dGhpcy5fX2RhdGFfXztyZXR1cm4gdGhpcy5zaXplKz10aGlzLmhhcyhlKT8wOjEscltlXT1BciYmdD09PW4/czp0LHRoaXN9LHpyLnByb3RvdHlwZS5jbGVhcj1mdW5jdGlvbigpe3RoaXMuX19kYXRhX189W10sdGhpcy5zaXplPTB9LHpyLnByb3RvdHlwZS5kZWxldGU9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fX2RhdGFfXyxyPWVpKHQsZSk7cmV0dXJuIShyPDB8fChyPT10Lmxlbmd0aC0xP3QucG9wKCk6aXQuY2FsbCh0LHIsMSksLS10aGlzLnNpemUsMCkpfSx6ci5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuX19kYXRhX18scj1laSh0LGUpO3JldHVybiByPDA/bjp0W3JdWzFdfSx6ci5wcm90b3R5cGUuaGFzPWZ1bmN0aW9uKGUpe3JldHVybiBlaSh0aGlzLl9fZGF0YV9fLGUpPi0xfSx6ci5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUsdCl7dmFyIHI9dGhpcy5fX2RhdGFfXyxpPWVpKHIsZSk7cmV0dXJuIGk8MD8oKyt0aGlzLnNpemUsci5wdXNoKFtlLHRdKSk6cltpXVsxXT10LHRoaXN9LEtyLnByb3RvdHlwZS5jbGVhcj1mdW5jdGlvbigpe3RoaXMuc2l6ZT0wLHRoaXMuX19kYXRhX189e2hhc2g6bmV3IE5yLG1hcDpuZXcod3J8fHpyKSxzdHJpbmc6bmV3IE5yfX0sS3IucHJvdG90eXBlLmRlbGV0ZT1mdW5jdGlvbihlKXt2YXIgdD1hbyh0aGlzLGUpLmRlbGV0ZShlKTtyZXR1cm4gdGhpcy5zaXplLT10PzE6MCx0fSxLci5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUpe3JldHVybiBhbyh0aGlzLGUpLmdldChlKX0sS3IucHJvdG90eXBlLmhhcz1mdW5jdGlvbihlKXtyZXR1cm4gYW8odGhpcyxlKS5oYXMoZSl9LEtyLnByb3RvdHlwZS5zZXQ9ZnVuY3Rpb24oZSx0KXt2YXIgcj1hbyh0aGlzLGUpLGk9ci5zaXplO3JldHVybiByLnNldChlLHQpLHRoaXMuc2l6ZSs9ci5zaXplPT1pPzA6MSx0aGlzfSxWci5wcm90b3R5cGUuYWRkPVZyLnByb3RvdHlwZS5wdXNoPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9fZGF0YV9fLnNldChlLHMpLHRoaXN9LFZyLnByb3RvdHlwZS5oYXM9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX19kYXRhX18uaGFzKGUpfSxHci5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXt0aGlzLl9fZGF0YV9fPW5ldyB6cix0aGlzLnNpemU9MH0sR3IucHJvdG90eXBlLmRlbGV0ZT1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9fZGF0YV9fLHI9dC5kZWxldGUoZSk7cmV0dXJuIHRoaXMuc2l6ZT10LnNpemUscn0sR3IucHJvdG90eXBlLmdldD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fX2RhdGFfXy5nZXQoZSl9LEdyLnByb3RvdHlwZS5oYXM9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX19kYXRhX18uaGFzKGUpfSxHci5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUsdCl7dmFyIHI9dGhpcy5fX2RhdGFfXztpZihyIGluc3RhbmNlb2YgenIpe3ZhciBpPXIuX19kYXRhX187aWYoIXdyfHxpLmxlbmd0aDwxOTkpcmV0dXJuIGkucHVzaChbZSx0XSksdGhpcy5zaXplPSsrci5zaXplLHRoaXM7cj10aGlzLl9fZGF0YV9fPW5ldyBLcihpKX1yZXR1cm4gci5zZXQoZSx0KSx0aGlzLnNpemU9ci5zaXplLHRoaXN9O3ZhciB1aT1Ubih5aSksaGk9VG4obWksITApO2Z1bmN0aW9uIGZpKGUsdCl7dmFyIHI9ITA7cmV0dXJuIHVpKGUsKGZ1bmN0aW9uKGUsaSxuKXtyZXR1cm4gcj0hIXQoZSxpLG4pfSkpLHJ9ZnVuY3Rpb24gX2koZSx0LHIpe2Zvcih2YXIgaT0tMSxvPWUubGVuZ3RoOysraTxvOyl7dmFyIHM9ZVtpXSxhPXQocyk7aWYobnVsbCE9YSYmKGM9PT1uP2E9PWEmJiFsYShhKTpyKGEsYykpKXZhciBjPWEsbD1zfXJldHVybiBsfWZ1bmN0aW9uIGRpKGUsdCl7dmFyIHI9W107cmV0dXJuIHVpKGUsKGZ1bmN0aW9uKGUsaSxuKXt0KGUsaSxuKSYmci5wdXNoKGUpfSkpLHJ9ZnVuY3Rpb24gcGkoZSx0LHIsaSxuKXt2YXIgbz0tMSxzPWUubGVuZ3RoO2ZvcihyfHwocj12byksbnx8KG49W10pOysrbzxzOyl7dmFyIGE9ZVtvXTt0PjAmJnIoYSk/dD4xP3BpKGEsdC0xLHIsaSxuKTp4dChuLGEpOml8fChuW24ubGVuZ3RoXT1hKX1yZXR1cm4gbn12YXIgdmk9T24oKSxnaT1PbighMCk7ZnVuY3Rpb24geWkoZSx0KXtyZXR1cm4gZSYmdmkoZSx0LE9hKX1mdW5jdGlvbiBtaShlLHQpe3JldHVybiBlJiZnaShlLHQsT2EpfWZ1bmN0aW9uIGJpKGUsdCl7cmV0dXJuIEN0KHQsKGZ1bmN0aW9uKHQpe3JldHVybiAkcyhlW3RdKX0pKX1mdW5jdGlvbiBTaShlLHQpe2Zvcih2YXIgcj0wLGk9KHQ9Z24odCxlKSkubGVuZ3RoO251bGwhPWUmJnI8aTspZT1lW2pvKHRbcisrXSldO3JldHVybiByJiZyPT1pP2U6bn1mdW5jdGlvbiBDaShlLHQscil7dmFyIGk9dChlKTtyZXR1cm4gS3MoZSk/aTp4dChpLHIoZSkpfWZ1bmN0aW9uIHdpKGUpe3JldHVybiBudWxsPT1lP2U9PT1uPyJbb2JqZWN0IFVuZGVmaW5lZF0iOiJbb2JqZWN0IE51bGxdIjphdCYmYXQgaW4gTGUoZSk/ZnVuY3Rpb24oZSl7dmFyIHQ9QmUuY2FsbChlLGF0KSxyPWVbYXRdO3RyeXtlW2F0XT1uO3ZhciBpPSEwfWNhdGNoKGUpe312YXIgbz1JZS5jYWxsKGUpO3JldHVybiBpJiYodD9lW2F0XT1yOmRlbGV0ZSBlW2F0XSksb30oZSk6ZnVuY3Rpb24oZSl7cmV0dXJuIEllLmNhbGwoZSl9KGUpfWZ1bmN0aW9uIExpKGUsdCl7cmV0dXJuIGU+dH1mdW5jdGlvbiBFaShlLHQpe3JldHVybiBudWxsIT1lJiZCZS5jYWxsKGUsdCl9ZnVuY3Rpb24geGkoZSx0KXtyZXR1cm4gbnVsbCE9ZSYmdCBpbiBMZShlKX1mdW5jdGlvbiBBaShlLHQscil7Zm9yKHZhciBvPXI/THQ6d3Qscz1lWzBdLmxlbmd0aCxhPWUubGVuZ3RoLGM9YSxsPWkoYSksdT0xLzAsaD1bXTtjLS07KXt2YXIgZj1lW2NdO2MmJnQmJihmPUV0KGYsTnQodCkpKSx1PWdyKGYubGVuZ3RoLHUpLGxbY109IXImJih0fHxzPj0xMjAmJmYubGVuZ3RoPj0xMjApP25ldyBWcihjJiZmKTpufWY9ZVswXTt2YXIgXz0tMSxkPWxbMF07ZTpmb3IoOysrXzxzJiZoLmxlbmd0aDx1Oyl7dmFyIHA9ZltfXSx2PXQ/dChwKTpwO2lmKHA9cnx8MCE9PXA/cDowLCEoZD9LdChkLHYpOm8oaCx2LHIpKSl7Zm9yKGM9YTstLWM7KXt2YXIgZz1sW2NdO2lmKCEoZz9LdChnLHYpOm8oZVtjXSx2LHIpKSljb250aW51ZSBlfWQmJmQucHVzaCh2KSxoLnB1c2gocCl9fXJldHVybiBofWZ1bmN0aW9uIGtpKGUsdCxyKXt2YXIgaT1udWxsPT0oZT14byhlLHQ9Z24odCxlKSkpP2U6ZVtqbyhKbyh0KSldO3JldHVybiBudWxsPT1pP246Z3QoaSxlLHIpfWZ1bmN0aW9uIE1pKGUpe3JldHVybiByYShlKSYmd2koZSk9PXB9ZnVuY3Rpb24gUmkoZSx0LHIsaSxvKXtyZXR1cm4gZT09PXR8fChudWxsPT1lfHxudWxsPT10fHwhcmEoZSkmJiFyYSh0KT9lIT1lJiZ0IT10OmZ1bmN0aW9uKGUsdCxyLGksbyxzKXt2YXIgYT1LcyhlKSxjPUtzKHQpLGw9YT92OmZvKGUpLHU9Yz92OmZvKHQpLGg9KGw9bD09cD9MOmwpPT1MLGY9KHU9dT09cD9MOnUpPT1MLF89bD09dTtpZihfJiZYcyhlKSl7aWYoIVhzKHQpKXJldHVybiExO2E9ITAsaD0hMX1pZihfJiYhaClyZXR1cm4gc3x8KHM9bmV3IEdyKSxhfHx1YShlKT9RbihlLHQscixpLG8scyk6ZnVuY3Rpb24oZSx0LHIsaSxuLG8scyl7c3dpdGNoKHIpe2Nhc2UgTzppZihlLmJ5dGVMZW5ndGghPXQuYnl0ZUxlbmd0aHx8ZS5ieXRlT2Zmc2V0IT10LmJ5dGVPZmZzZXQpcmV0dXJuITE7ZT1lLmJ1ZmZlcix0PXQuYnVmZmVyO2Nhc2UgVDpyZXR1cm4hKGUuYnl0ZUxlbmd0aCE9dC5ieXRlTGVuZ3RofHwhbyhuZXcgcWUoZSksbmV3IHFlKHQpKSk7Y2FzZSBnOmNhc2UgeTpjYXNlIHc6cmV0dXJuIFVzKCtlLCt0KTtjYXNlIG06cmV0dXJuIGUubmFtZT09dC5uYW1lJiZlLm1lc3NhZ2U9PXQubWVzc2FnZTtjYXNlIHg6Y2FzZSBrOnJldHVybiBlPT10KyIiO2Nhc2UgQzp2YXIgYT1RdDtjYXNlIEE6dmFyIGM9MSZpO2lmKGF8fChhPXJyKSxlLnNpemUhPXQuc2l6ZSYmIWMpcmV0dXJuITE7dmFyIGw9cy5nZXQoZSk7aWYobClyZXR1cm4gbD09dDtpfD0yLHMuc2V0KGUsdCk7dmFyIHU9UW4oYShlKSxhKHQpLGksbixvLHMpO3JldHVybiBzLmRlbGV0ZShlKSx1O2Nhc2UgTTppZihJcilyZXR1cm4gSXIuY2FsbChlKT09SXIuY2FsbCh0KX1yZXR1cm4hMX0oZSx0LGwscixpLG8scyk7aWYoISgxJnIpKXt2YXIgZD1oJiZCZS5jYWxsKGUsIl9fd3JhcHBlZF9fIiksYj1mJiZCZS5jYWxsKHQsIl9fd3JhcHBlZF9fIik7aWYoZHx8Yil7dmFyIFM9ZD9lLnZhbHVlKCk6ZSxFPWI/dC52YWx1ZSgpOnQ7cmV0dXJuIHN8fChzPW5ldyBHciksbyhTLEUscixpLHMpfX1yZXR1cm4hIV8mJihzfHwocz1uZXcgR3IpLGZ1bmN0aW9uKGUsdCxyLGksbyxzKXt2YXIgYT0xJnIsYz10byhlKSxsPWMubGVuZ3RoO2lmKGwhPXRvKHQpLmxlbmd0aCYmIWEpcmV0dXJuITE7Zm9yKHZhciB1PWw7dS0tOyl7dmFyIGg9Y1t1XTtpZighKGE/aCBpbiB0OkJlLmNhbGwodCxoKSkpcmV0dXJuITF9dmFyIGY9cy5nZXQoZSksXz1zLmdldCh0KTtpZihmJiZfKXJldHVybiBmPT10JiZfPT1lO3ZhciBkPSEwO3Muc2V0KGUsdCkscy5zZXQodCxlKTtmb3IodmFyIHA9YTsrK3U8bDspe3ZhciB2PWVbaD1jW3VdXSxnPXRbaF07aWYoaSl2YXIgeT1hP2koZyx2LGgsdCxlLHMpOmkodixnLGgsZSx0LHMpO2lmKCEoeT09PW4/dj09PWd8fG8odixnLHIsaSxzKTp5KSl7ZD0hMTticmVha31wfHwocD0iY29uc3RydWN0b3IiPT1oKX1pZihkJiYhcCl7dmFyIG09ZS5jb25zdHJ1Y3RvcixiPXQuY29uc3RydWN0b3I7bT09Ynx8ISgiY29uc3RydWN0b3IiaW4gZSl8fCEoImNvbnN0cnVjdG9yImluIHQpfHwiZnVuY3Rpb24iPT10eXBlb2YgbSYmbSBpbnN0YW5jZW9mIG0mJiJmdW5jdGlvbiI9PXR5cGVvZiBiJiZiIGluc3RhbmNlb2YgYnx8KGQ9ITEpfXJldHVybiBzLmRlbGV0ZShlKSxzLmRlbGV0ZSh0KSxkfShlLHQscixpLG8scykpfShlLHQscixpLFJpLG8pKX1mdW5jdGlvbiBUaShlLHQscixpKXt2YXIgbz1yLmxlbmd0aCxzPW8sYT0haTtpZihudWxsPT1lKXJldHVybiFzO2ZvcihlPUxlKGUpO28tLTspe3ZhciBjPXJbb107aWYoYSYmY1syXT9jWzFdIT09ZVtjWzBdXTohKGNbMF1pbiBlKSlyZXR1cm4hMX1mb3IoOysrbzxzOyl7dmFyIGw9KGM9cltvXSlbMF0sdT1lW2xdLGg9Y1sxXTtpZihhJiZjWzJdKXtpZih1PT09biYmIShsIGluIGUpKXJldHVybiExfWVsc2V7dmFyIGY9bmV3IEdyO2lmKGkpdmFyIF89aSh1LGgsbCxlLHQsZik7aWYoIShfPT09bj9SaShoLHUsMyxpLGYpOl8pKXJldHVybiExfX1yZXR1cm4hMH1mdW5jdGlvbiBPaShlKXtyZXR1cm4hKCF0YShlKXx8KHQ9ZSxQZSYmUGUgaW4gdCkpJiYoJHMoZSk/RmU6cGUpLnRlc3QoRm8oZSkpO3ZhciB0fWZ1bmN0aW9uIEJpKGUpe3JldHVybiJmdW5jdGlvbiI9PXR5cGVvZiBlP2U6bnVsbD09ZT9uYzoib2JqZWN0Ij09dHlwZW9mIGU/S3MoZSk/amkoZVswXSxlWzFdKTpIaShlKTpfYyhlKX1mdW5jdGlvbiBEaShlKXtpZighQ28oZSkpcmV0dXJuIHByKGUpO3ZhciB0PVtdO2Zvcih2YXIgciBpbiBMZShlKSlCZS5jYWxsKGUscikmJiJjb25zdHJ1Y3RvciIhPXImJnQucHVzaChyKTtyZXR1cm4gdH1mdW5jdGlvbiBQaShlLHQpe3JldHVybiBlPHR9ZnVuY3Rpb24gSWkoZSx0KXt2YXIgcj0tMSxuPUdzKGUpP2koZS5sZW5ndGgpOltdO3JldHVybiB1aShlLChmdW5jdGlvbihlLGksbyl7blsrK3JdPXQoZSxpLG8pfSkpLG59ZnVuY3Rpb24gSGkoZSl7dmFyIHQ9Y28oZSk7cmV0dXJuIDE9PXQubGVuZ3RoJiZ0WzBdWzJdP0xvKHRbMF1bMF0sdFswXVsxXSk6ZnVuY3Rpb24ocil7cmV0dXJuIHI9PT1lfHxUaShyLGUsdCl9fWZ1bmN0aW9uIGppKGUsdCl7cmV0dXJuIG1vKGUpJiZ3byh0KT9MbyhqbyhlKSx0KTpmdW5jdGlvbihyKXt2YXIgaT1BYShyLGUpO3JldHVybiBpPT09biYmaT09PXQ/a2EocixlKTpSaSh0LGksMyl9fWZ1bmN0aW9uIEZpKGUsdCxyLGksbyl7ZSE9PXQmJnZpKHQsKGZ1bmN0aW9uKHMsYSl7aWYob3x8KG89bmV3IEdyKSx0YShzKSkhZnVuY3Rpb24oZSx0LHIsaSxvLHMsYSl7dmFyIGM9a28oZSxyKSxsPWtvKHQsciksdT1hLmdldChsKTtpZih1KSRyKGUscix1KTtlbHNle3ZhciBoPXM/cyhjLGwscisiIixlLHQsYSk6bixmPWg9PT1uO2lmKGYpe3ZhciBfPUtzKGwpLGQ9IV8mJlhzKGwpLHA9IV8mJiFkJiZ1YShsKTtoPWwsX3x8ZHx8cD9LcyhjKT9oPWM6WXMoYyk/aD1BbihjKTpkPyhmPSExLGg9U24obCwhMCkpOnA/KGY9ITEsaD13bihsLCEwKSk6aD1bXTpvYShsKXx8enMobCk/KGg9Yyx6cyhjKT9oPXlhKGMpOnRhKGMpJiYhJHMoYyl8fChoPXBvKGwpKSk6Zj0hMX1mJiYoYS5zZXQobCxoKSxvKGgsbCxpLHMsYSksYS5kZWxldGUobCkpLCRyKGUscixoKX19KGUsdCxhLHIsRmksaSxvKTtlbHNle3ZhciBjPWk/aShrbyhlLGEpLHMsYSsiIixlLHQsbyk6bjtjPT09biYmKGM9cyksJHIoZSxhLGMpfX0pLEJhKX1mdW5jdGlvbiBXaShlLHQpe3ZhciByPWUubGVuZ3RoO2lmKHIpcmV0dXJuIGdvKHQrPXQ8MD9yOjAscik/ZVt0XTpufWZ1bmN0aW9uIFVpKGUsdCxyKXt0PXQubGVuZ3RoP0V0KHQsKGZ1bmN0aW9uKGUpe3JldHVybiBLcyhlKT9mdW5jdGlvbih0KXtyZXR1cm4gU2kodCwxPT09ZS5sZW5ndGg/ZVswXTplKX06ZX0pKTpbbmNdO3ZhciBpPS0xO3Q9RXQodCxOdChzbygpKSk7dmFyIG49SWkoZSwoZnVuY3Rpb24oZSxyLG4pe3ZhciBvPUV0KHQsKGZ1bmN0aW9uKHQpe3JldHVybiB0KGUpfSkpO3JldHVybntjcml0ZXJpYTpvLGluZGV4OisraSx2YWx1ZTplfX0pKTtyZXR1cm4gZnVuY3Rpb24oZSx0KXt2YXIgaT1lLmxlbmd0aDtmb3IoZS5zb3J0KChmdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbihlLHQscil7Zm9yKHZhciBpPS0xLG49ZS5jcml0ZXJpYSxvPXQuY3JpdGVyaWEscz1uLmxlbmd0aCxhPXIubGVuZ3RoOysraTxzOyl7dmFyIGM9TG4obltpXSxvW2ldKTtpZihjKXJldHVybiBpPj1hP2M6YyooImRlc2MiPT1yW2ldPy0xOjEpfXJldHVybiBlLmluZGV4LXQuaW5kZXh9KGUsdCxyKX0pKTtpLS07KWVbaV09ZVtpXS52YWx1ZTtyZXR1cm4gZX0obil9ZnVuY3Rpb24gcWkoZSx0LHIpe2Zvcih2YXIgaT0tMSxuPXQubGVuZ3RoLG89e307KytpPG47KXt2YXIgcz10W2ldLGE9U2koZSxzKTtyKGEscykmJlppKG8sZ24ocyxlKSxhKX1yZXR1cm4gb31mdW5jdGlvbiBOaShlLHQscixpKXt2YXIgbj1pP0R0OkJ0LG89LTEscz10Lmxlbmd0aCxhPWU7Zm9yKGU9PT10JiYodD1Bbih0KSksciYmKGE9RXQoZSxOdChyKSkpOysrbzxzOylmb3IodmFyIGM9MCxsPXRbb10sdT1yP3IobCk6bDsoYz1uKGEsdSxjLGkpKT4tMTspYSE9PWUmJml0LmNhbGwoYSxjLDEpLGl0LmNhbGwoZSxjLDEpO3JldHVybiBlfWZ1bmN0aW9uIHppKGUsdCl7Zm9yKHZhciByPWU/dC5sZW5ndGg6MCxpPXItMTtyLS07KXt2YXIgbj10W3JdO2lmKHI9PWl8fG4hPT1vKXt2YXIgbz1uO2dvKG4pP2l0LmNhbGwoZSxuLDEpOmxuKGUsbil9fXJldHVybiBlfWZ1bmN0aW9uIEtpKGUsdCl7cmV0dXJuIGUrdXIoYnIoKSoodC1lKzEpKX1mdW5jdGlvbiBWaShlLHQpe3ZhciByPSIiO2lmKCFlfHx0PDF8fHQ+aClyZXR1cm4gcjtkb3t0JTImJihyKz1lKSwodD11cih0LzIpKSYmKGUrPWUpfXdoaWxlKHQpO3JldHVybiByfWZ1bmN0aW9uIEdpKGUsdCl7cmV0dXJuIFRvKEVvKGUsdCxuYyksZSsiIil9ZnVuY3Rpb24gWWkoZSl7cmV0dXJuIFhyKFVhKGUpKX1mdW5jdGlvbiBYaShlLHQpe3ZhciByPVVhKGUpO3JldHVybiBEbyhyLG9pKHQsMCxyLmxlbmd0aCkpfWZ1bmN0aW9uIFppKGUsdCxyLGkpe2lmKCF0YShlKSlyZXR1cm4gZTtmb3IodmFyIG89LTEscz0odD1nbih0LGUpKS5sZW5ndGgsYT1zLTEsYz1lO251bGwhPWMmJisrbzxzOyl7dmFyIGw9am8odFtvXSksdT1yO2lmKCJfX3Byb3RvX18iPT09bHx8ImNvbnN0cnVjdG9yIj09PWx8fCJwcm90b3R5cGUiPT09bClyZXR1cm4gZTtpZihvIT1hKXt2YXIgaD1jW2xdOyh1PWk/aShoLGwsYyk6bik9PT1uJiYodT10YShoKT9oOmdvKHRbbysxXSk/W106e30pfVFyKGMsbCx1KSxjPWNbbF19cmV0dXJuIGV9dmFyIEppPWtyP2Z1bmN0aW9uKGUsdCl7cmV0dXJuIGtyLnNldChlLHQpLGV9Om5jLCRpPWx0P2Z1bmN0aW9uKGUsdCl7cmV0dXJuIGx0KGUsInRvU3RyaW5nIix7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITEsdmFsdWU6dGModCksd3JpdGFibGU6ITB9KX06bmM7ZnVuY3Rpb24gUWkoZSl7cmV0dXJuIERvKFVhKGUpKX1mdW5jdGlvbiBlbihlLHQscil7dmFyIG49LTEsbz1lLmxlbmd0aDt0PDAmJih0PS10Pm8/MDpvK3QpLChyPXI+bz9vOnIpPDAmJihyKz1vKSxvPXQ+cj8wOnItdD4+PjAsdD4+Pj0wO2Zvcih2YXIgcz1pKG8pOysrbjxvOylzW25dPWVbbit0XTtyZXR1cm4gc31mdW5jdGlvbiB0bihlLHQpe3ZhciByO3JldHVybiB1aShlLChmdW5jdGlvbihlLGksbil7cmV0dXJuIShyPXQoZSxpLG4pKX0pKSwhIXJ9ZnVuY3Rpb24gcm4oZSx0LHIpe3ZhciBpPTAsbj1udWxsPT1lP2k6ZS5sZW5ndGg7aWYoIm51bWJlciI9PXR5cGVvZiB0JiZ0PT10JiZuPD0yMTQ3NDgzNjQ3KXtmb3IoO2k8bjspe3ZhciBvPWkrbj4+PjEscz1lW29dO251bGwhPT1zJiYhbGEocykmJihyP3M8PXQ6czx0KT9pPW8rMTpuPW99cmV0dXJuIG59cmV0dXJuIG5uKGUsdCxuYyxyKX1mdW5jdGlvbiBubihlLHQscixpKXt2YXIgbz0wLHM9bnVsbD09ZT8wOmUubGVuZ3RoO2lmKDA9PT1zKXJldHVybiAwO2Zvcih2YXIgYT0odD1yKHQpKSE9dCxjPW51bGw9PT10LGw9bGEodCksdT10PT09bjtvPHM7KXt2YXIgaD11cigobytzKS8yKSxmPXIoZVtoXSksXz1mIT09bixkPW51bGw9PT1mLHA9Zj09Zix2PWxhKGYpO2lmKGEpdmFyIGc9aXx8cDtlbHNlIGc9dT9wJiYoaXx8Xyk6Yz9wJiZfJiYoaXx8IWQpOmw/cCYmXyYmIWQmJihpfHwhdik6IWQmJiF2JiYoaT9mPD10OmY8dCk7Zz9vPWgrMTpzPWh9cmV0dXJuIGdyKHMsNDI5NDk2NzI5NCl9ZnVuY3Rpb24gb24oZSx0KXtmb3IodmFyIHI9LTEsaT1lLmxlbmd0aCxuPTAsbz1bXTsrK3I8aTspe3ZhciBzPWVbcl0sYT10P3Qocyk6cztpZighcnx8IVVzKGEsYykpe3ZhciBjPWE7b1tuKytdPTA9PT1zPzA6c319cmV0dXJuIG99ZnVuY3Rpb24gc24oZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlP2U6bGEoZSk/ZjorZX1mdW5jdGlvbiBhbihlKXtpZigic3RyaW5nIj09dHlwZW9mIGUpcmV0dXJuIGU7aWYoS3MoZSkpcmV0dXJuIEV0KGUsYW4pKyIiO2lmKGxhKGUpKXJldHVybiBIcj9Ici5jYWxsKGUpOiIiO3ZhciB0PWUrIiI7cmV0dXJuIjAiPT10JiYxL2U9PS0xLzA/Ii0wIjp0fWZ1bmN0aW9uIGNuKGUsdCxyKXt2YXIgaT0tMSxuPXd0LG89ZS5sZW5ndGgscz0hMCxhPVtdLGM9YTtpZihyKXM9ITEsbj1MdDtlbHNlIGlmKG8+PTIwMCl7dmFyIGw9dD9udWxsOkduKGUpO2lmKGwpcmV0dXJuIHJyKGwpO3M9ITEsbj1LdCxjPW5ldyBWcn1lbHNlIGM9dD9bXTphO2U6Zm9yKDsrK2k8bzspe3ZhciB1PWVbaV0saD10P3QodSk6dTtpZih1PXJ8fDAhPT11P3U6MCxzJiZoPT1oKXtmb3IodmFyIGY9Yy5sZW5ndGg7Zi0tOylpZihjW2ZdPT09aCljb250aW51ZSBlO3QmJmMucHVzaChoKSxhLnB1c2godSl9ZWxzZSBuKGMsaCxyKXx8KGMhPT1hJiZjLnB1c2goaCksYS5wdXNoKHUpKX1yZXR1cm4gYX1mdW5jdGlvbiBsbihlLHQpe3JldHVybiBudWxsPT0oZT14byhlLHQ9Z24odCxlKSkpfHxkZWxldGUgZVtqbyhKbyh0KSldfWZ1bmN0aW9uIHVuKGUsdCxyLGkpe3JldHVybiBaaShlLHQscihTaShlLHQpKSxpKX1mdW5jdGlvbiBobihlLHQscixpKXtmb3IodmFyIG49ZS5sZW5ndGgsbz1pP246LTE7KGk/by0tOisrbzxuKSYmdChlW29dLG8sZSk7KTtyZXR1cm4gcj9lbihlLGk/MDpvLGk/bysxOm4pOmVuKGUsaT9vKzE6MCxpP246byl9ZnVuY3Rpb24gZm4oZSx0KXt2YXIgcj1lO3JldHVybiByIGluc3RhbmNlb2YgcXImJihyPXIudmFsdWUoKSksQXQodCwoZnVuY3Rpb24oZSx0KXtyZXR1cm4gdC5mdW5jLmFwcGx5KHQudGhpc0FyZyx4dChbZV0sdC5hcmdzKSl9KSxyKX1mdW5jdGlvbiBfbihlLHQscil7dmFyIG49ZS5sZW5ndGg7aWYobjwyKXJldHVybiBuP2NuKGVbMF0pOltdO2Zvcih2YXIgbz0tMSxzPWkobik7KytvPG47KWZvcih2YXIgYT1lW29dLGM9LTE7KytjPG47KWMhPW8mJihzW29dPWxpKHNbb118fGEsZVtjXSx0LHIpKTtyZXR1cm4gY24ocGkocywxKSx0LHIpfWZ1bmN0aW9uIGRuKGUsdCxyKXtmb3IodmFyIGk9LTEsbz1lLmxlbmd0aCxzPXQubGVuZ3RoLGE9e307KytpPG87KXt2YXIgYz1pPHM/dFtpXTpuO3IoYSxlW2ldLGMpfXJldHVybiBhfWZ1bmN0aW9uIHBuKGUpe3JldHVybiBZcyhlKT9lOltdfWZ1bmN0aW9uIHZuKGUpe3JldHVybiJmdW5jdGlvbiI9PXR5cGVvZiBlP2U6bmN9ZnVuY3Rpb24gZ24oZSx0KXtyZXR1cm4gS3MoZSk/ZTptbyhlLHQpP1tlXTpIbyhtYShlKSl9dmFyIHluPUdpO2Z1bmN0aW9uIG1uKGUsdCxyKXt2YXIgaT1lLmxlbmd0aDtyZXR1cm4gcj1yPT09bj9pOnIsIXQmJnI+PWk/ZTplbihlLHQscil9dmFyIGJuPXV0fHxmdW5jdGlvbihlKXtyZXR1cm4gb3QuY2xlYXJUaW1lb3V0KGUpfTtmdW5jdGlvbiBTbihlLHQpe2lmKHQpcmV0dXJuIGUuc2xpY2UoKTt2YXIgcj1lLmxlbmd0aCxpPU5lP05lKHIpOm5ldyBlLmNvbnN0cnVjdG9yKHIpO3JldHVybiBlLmNvcHkoaSksaX1mdW5jdGlvbiBDbihlKXt2YXIgdD1uZXcgZS5jb25zdHJ1Y3RvcihlLmJ5dGVMZW5ndGgpO3JldHVybiBuZXcgcWUodCkuc2V0KG5ldyBxZShlKSksdH1mdW5jdGlvbiB3bihlLHQpe3ZhciByPXQ/Q24oZS5idWZmZXIpOmUuYnVmZmVyO3JldHVybiBuZXcgZS5jb25zdHJ1Y3RvcihyLGUuYnl0ZU9mZnNldCxlLmxlbmd0aCl9ZnVuY3Rpb24gTG4oZSx0KXtpZihlIT09dCl7dmFyIHI9ZSE9PW4saT1udWxsPT09ZSxvPWU9PWUscz1sYShlKSxhPXQhPT1uLGM9bnVsbD09PXQsbD10PT10LHU9bGEodCk7aWYoIWMmJiF1JiYhcyYmZT50fHxzJiZhJiZsJiYhYyYmIXV8fGkmJmEmJmx8fCFyJiZsfHwhbylyZXR1cm4gMTtpZighaSYmIXMmJiF1JiZlPHR8fHUmJnImJm8mJiFpJiYhc3x8YyYmciYmb3x8IWEmJm98fCFsKXJldHVybi0xfXJldHVybiAwfWZ1bmN0aW9uIEVuKGUsdCxyLG4pe2Zvcih2YXIgbz0tMSxzPWUubGVuZ3RoLGE9ci5sZW5ndGgsYz0tMSxsPXQubGVuZ3RoLHU9dnIocy1hLDApLGg9aShsK3UpLGY9IW47KytjPGw7KWhbY109dFtjXTtmb3IoOysrbzxhOykoZnx8bzxzKSYmKGhbcltvXV09ZVtvXSk7Zm9yKDt1LS07KWhbYysrXT1lW28rK107cmV0dXJuIGh9ZnVuY3Rpb24geG4oZSx0LHIsbil7Zm9yKHZhciBvPS0xLHM9ZS5sZW5ndGgsYT0tMSxjPXIubGVuZ3RoLGw9LTEsdT10Lmxlbmd0aCxoPXZyKHMtYywwKSxmPWkoaCt1KSxfPSFuOysrbzxoOylmW29dPWVbb107Zm9yKHZhciBkPW87KytsPHU7KWZbZCtsXT10W2xdO2Zvcig7KythPGM7KShffHxvPHMpJiYoZltkK3JbYV1dPWVbbysrXSk7cmV0dXJuIGZ9ZnVuY3Rpb24gQW4oZSx0KXt2YXIgcj0tMSxuPWUubGVuZ3RoO2Zvcih0fHwodD1pKG4pKTsrK3I8bjspdFtyXT1lW3JdO3JldHVybiB0fWZ1bmN0aW9uIGtuKGUsdCxyLGkpe3ZhciBvPSFyO3J8fChyPXt9KTtmb3IodmFyIHM9LTEsYT10Lmxlbmd0aDsrK3M8YTspe3ZhciBjPXRbc10sbD1pP2kocltjXSxlW2NdLGMscixlKTpuO2w9PT1uJiYobD1lW2NdKSxvP2lpKHIsYyxsKTpRcihyLGMsbCl9cmV0dXJuIHJ9ZnVuY3Rpb24gTW4oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt2YXIgbj1LcyhyKT95dDp0aSxvPXQ/dCgpOnt9O3JldHVybiBuKHIsZSxzbyhpLDIpLG8pfX1mdW5jdGlvbiBSbihlKXtyZXR1cm4gR2koKGZ1bmN0aW9uKHQscil7dmFyIGk9LTEsbz1yLmxlbmd0aCxzPW8+MT9yW28tMV06bixhPW8+Mj9yWzJdOm47Zm9yKHM9ZS5sZW5ndGg+MyYmImZ1bmN0aW9uIj09dHlwZW9mIHM/KG8tLSxzKTpuLGEmJnlvKHJbMF0sclsxXSxhKSYmKHM9bzwzP246cyxvPTEpLHQ9TGUodCk7KytpPG87KXt2YXIgYz1yW2ldO2MmJmUodCxjLGkscyl9cmV0dXJuIHR9KSl9ZnVuY3Rpb24gVG4oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXtpZihudWxsPT1yKXJldHVybiByO2lmKCFHcyhyKSlyZXR1cm4gZShyLGkpO2Zvcih2YXIgbj1yLmxlbmd0aCxvPXQ/bjotMSxzPUxlKHIpOyh0P28tLTorK288bikmJiExIT09aShzW29dLG8scyk7KTtyZXR1cm4gcn19ZnVuY3Rpb24gT24oZSl7cmV0dXJuIGZ1bmN0aW9uKHQscixpKXtmb3IodmFyIG49LTEsbz1MZSh0KSxzPWkodCksYT1zLmxlbmd0aDthLS07KXt2YXIgYz1zW2U/YTorK25dO2lmKCExPT09cihvW2NdLGMsbykpYnJlYWt9cmV0dXJuIHR9fWZ1bmN0aW9uIEJuKGUpe3JldHVybiBmdW5jdGlvbih0KXt2YXIgcj0kdCh0PW1hKHQpKT9vcih0KTpuLGk9cj9yWzBdOnQuY2hhckF0KDApLG89cj9tbihyLDEpLmpvaW4oIiIpOnQuc2xpY2UoMSk7cmV0dXJuIGlbZV0oKStvfX1mdW5jdGlvbiBEbihlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIEF0KCRhKHphKHQpLnJlcGxhY2UoemUsIiIpKSxlLCIiKX19ZnVuY3Rpb24gUG4oZSl7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIHQ9YXJndW1lbnRzO3N3aXRjaCh0Lmxlbmd0aCl7Y2FzZSAwOnJldHVybiBuZXcgZTtjYXNlIDE6cmV0dXJuIG5ldyBlKHRbMF0pO2Nhc2UgMjpyZXR1cm4gbmV3IGUodFswXSx0WzFdKTtjYXNlIDM6cmV0dXJuIG5ldyBlKHRbMF0sdFsxXSx0WzJdKTtjYXNlIDQ6cmV0dXJuIG5ldyBlKHRbMF0sdFsxXSx0WzJdLHRbM10pO2Nhc2UgNTpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0sdFszXSx0WzRdKTtjYXNlIDY6cmV0dXJuIG5ldyBlKHRbMF0sdFsxXSx0WzJdLHRbM10sdFs0XSx0WzVdKTtjYXNlIDc6cmV0dXJuIG5ldyBlKHRbMF0sdFsxXSx0WzJdLHRbM10sdFs0XSx0WzVdLHRbNl0pfXZhciByPUZyKGUucHJvdG90eXBlKSxpPWUuYXBwbHkocix0KTtyZXR1cm4gdGEoaSk/aTpyfX1mdW5jdGlvbiBJbihlKXtyZXR1cm4gZnVuY3Rpb24odCxyLGkpe3ZhciBvPUxlKHQpO2lmKCFHcyh0KSl7dmFyIHM9c28ociwzKTt0PU9hKHQpLHI9ZnVuY3Rpb24oZSl7cmV0dXJuIHMob1tlXSxlLG8pfX12YXIgYT1lKHQscixpKTtyZXR1cm4gYT4tMT9vW3M/dFthXTphXTpufX1mdW5jdGlvbiBIbihlKXtyZXR1cm4gZW8oKGZ1bmN0aW9uKHQpe3ZhciByPXQubGVuZ3RoLGk9cixzPVVyLnByb3RvdHlwZS50aHJ1O2ZvcihlJiZ0LnJldmVyc2UoKTtpLS07KXt2YXIgYT10W2ldO2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBhKXRocm93IG5ldyBBZShvKTtpZihzJiYhYyYmIndyYXBwZXIiPT1ubyhhKSl2YXIgYz1uZXcgVXIoW10sITApfWZvcihpPWM/aTpyOysraTxyOyl7dmFyIGw9bm8oYT10W2ldKSx1PSJ3cmFwcGVyIj09bD9pbyhhKTpuO2M9dSYmYm8odVswXSkmJjQyND09dVsxXSYmIXVbNF0ubGVuZ3RoJiYxPT11WzldP2Nbbm8odVswXSldLmFwcGx5KGMsdVszXSk6MT09YS5sZW5ndGgmJmJvKGEpP2NbbF0oKTpjLnRocnUoYSl9cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIGU9YXJndW1lbnRzLGk9ZVswXTtpZihjJiYxPT1lLmxlbmd0aCYmS3MoaSkpcmV0dXJuIGMucGxhbnQoaSkudmFsdWUoKTtmb3IodmFyIG49MCxvPXI/dFtuXS5hcHBseSh0aGlzLGUpOmk7KytuPHI7KW89dFtuXS5jYWxsKHRoaXMsbyk7cmV0dXJuIG99fSkpfWZ1bmN0aW9uIGpuKGUsdCxyLG8scyxhLGMsdSxoLGYpe3ZhciBfPXQmbCxkPTEmdCxwPTImdCx2PTI0JnQsZz01MTImdCx5PXA/bjpQbihlKTtyZXR1cm4gZnVuY3Rpb24gbigpe2Zvcih2YXIgbD1hcmd1bWVudHMubGVuZ3RoLG09aShsKSxiPWw7Yi0tOyltW2JdPWFyZ3VtZW50c1tiXTtpZih2KXZhciBTPW9vKG4pLEM9WXQobSxTKTtpZihvJiYobT1FbihtLG8scyx2KSksYSYmKG09eG4obSxhLGMsdikpLGwtPUMsdiYmbDxmKXt2YXIgdz10cihtLFMpO3JldHVybiBLbihlLHQsam4sbi5wbGFjZWhvbGRlcixyLG0sdyx1LGgsZi1sKX12YXIgTD1kP3I6dGhpcyxFPXA/TFtlXTplO3JldHVybiBsPW0ubGVuZ3RoLHU/bT1BbyhtLHUpOmcmJmw+MSYmbS5yZXZlcnNlKCksXyYmaDxsJiYobS5sZW5ndGg9aCksdGhpcyYmdGhpcyE9PW90JiZ0aGlzIGluc3RhbmNlb2YgbiYmKEU9eXx8UG4oRSkpLEUuYXBwbHkoTCxtKX19ZnVuY3Rpb24gRm4oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXtyZXR1cm4gZnVuY3Rpb24oZSx0LHIsaSl7cmV0dXJuIHlpKGUsKGZ1bmN0aW9uKGUsbixvKXt0KGkscihlKSxuLG8pfSkpLGl9KHIsZSx0KGkpLHt9KX19ZnVuY3Rpb24gV24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt2YXIgbztpZihyPT09biYmaT09PW4pcmV0dXJuIHQ7aWYociE9PW4mJihvPXIpLGkhPT1uKXtpZihvPT09bilyZXR1cm4gaTsic3RyaW5nIj09dHlwZW9mIHJ8fCJzdHJpbmciPT10eXBlb2YgaT8ocj1hbihyKSxpPWFuKGkpKToocj1zbihyKSxpPXNuKGkpKSxvPWUocixpKX1yZXR1cm4gb319ZnVuY3Rpb24gVW4oZSl7cmV0dXJuIGVvKChmdW5jdGlvbih0KXtyZXR1cm4gdD1FdCh0LE50KHNvKCkpKSxHaSgoZnVuY3Rpb24ocil7dmFyIGk9dGhpcztyZXR1cm4gZSh0LChmdW5jdGlvbihlKXtyZXR1cm4gZ3QoZSxpLHIpfSkpfSkpfSkpfWZ1bmN0aW9uIHFuKGUsdCl7dmFyIHI9KHQ9dD09PW4/IiAiOmFuKHQpKS5sZW5ndGg7aWYocjwyKXJldHVybiByP1ZpKHQsZSk6dDt2YXIgaT1WaSh0LGxyKGUvbnIodCkpKTtyZXR1cm4gJHQodCk/bW4ob3IoaSksMCxlKS5qb2luKCIiKTppLnNsaWNlKDAsZSl9ZnVuY3Rpb24gTm4oZSl7cmV0dXJuIGZ1bmN0aW9uKHQscixvKXtyZXR1cm4gbyYmIm51bWJlciIhPXR5cGVvZiBvJiZ5byh0LHIsbykmJihyPW89biksdD1kYSh0KSxyPT09bj8ocj10LHQ9MCk6cj1kYShyKSxmdW5jdGlvbihlLHQscixuKXtmb3IodmFyIG89LTEscz12cihscigodC1lKS8ocnx8MSkpLDApLGE9aShzKTtzLS07KWFbbj9zOisrb109ZSxlKz1yO3JldHVybiBhfSh0LHIsbz1vPT09bj90PHI/MTotMTpkYShvKSxlKX19ZnVuY3Rpb24gem4oZSl7cmV0dXJuIGZ1bmN0aW9uKHQscil7cmV0dXJuInN0cmluZyI9PXR5cGVvZiB0JiYic3RyaW5nIj09dHlwZW9mIHJ8fCh0PWdhKHQpLHI9Z2EocikpLGUodCxyKX19ZnVuY3Rpb24gS24oZSx0LHIsaSxvLHMsYSxsLHUsaCl7dmFyIGY9OCZ0O3R8PWY/Yzo2NCw0Jih0Jj1+KGY/NjQ6YykpfHwodCY9LTQpO3ZhciBfPVtlLHQsbyxmP3M6bixmP2E6bixmP246cyxmP246YSxsLHUsaF0sZD1yLmFwcGx5KG4sXyk7cmV0dXJuIGJvKGUpJiZNbyhkLF8pLGQucGxhY2Vob2xkZXI9aSxPbyhkLGUsdCl9ZnVuY3Rpb24gVm4oZSl7dmFyIHQ9d2VbZV07cmV0dXJuIGZ1bmN0aW9uKGUscil7aWYoZT1nYShlKSwocj1udWxsPT1yPzA6Z3IocGEociksMjkyKSkmJl9yKGUpKXt2YXIgaT0obWEoZSkrImUiKS5zcGxpdCgiZSIpO3JldHVybisoKGk9KG1hKHQoaVswXSsiZSIrKCtpWzFdK3IpKSkrImUiKS5zcGxpdCgiZSIpKVswXSsiZSIrKCtpWzFdLXIpKX1yZXR1cm4gdChlKX19dmFyIEduPUVyJiYxL3JyKG5ldyBFcihbLC0wXSkpWzFdPT11P2Z1bmN0aW9uKGUpe3JldHVybiBuZXcgRXIoZSl9OmxjO2Z1bmN0aW9uIFluKGUpe3JldHVybiBmdW5jdGlvbih0KXt2YXIgcj1mbyh0KTtyZXR1cm4gcj09Qz9RdCh0KTpyPT1BP2lyKHQpOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIEV0KHQsKGZ1bmN0aW9uKHQpe3JldHVyblt0LGVbdF1dfSkpfSh0LGUodCkpfX1mdW5jdGlvbiBYbihlLHQscixzLHUsaCxmLF8pe3ZhciBkPTImdDtpZighZCYmImZ1bmN0aW9uIiE9dHlwZW9mIGUpdGhyb3cgbmV3IEFlKG8pO3ZhciBwPXM/cy5sZW5ndGg6MDtpZihwfHwodCY9LTk3LHM9dT1uKSxmPWY9PT1uP2Y6dnIocGEoZiksMCksXz1fPT09bj9fOnBhKF8pLHAtPXU/dS5sZW5ndGg6MCw2NCZ0KXt2YXIgdj1zLGc9dTtzPXU9bn12YXIgeT1kP246aW8oZSksbT1bZSx0LHIscyx1LHYsZyxoLGYsX107aWYoeSYmZnVuY3Rpb24oZSx0KXt2YXIgcj1lWzFdLGk9dFsxXSxuPXJ8aSxvPW48MTMxLHM9aT09bCYmOD09cnx8aT09bCYmMjU2PT1yJiZlWzddLmxlbmd0aDw9dFs4XXx8Mzg0PT1pJiZ0WzddLmxlbmd0aDw9dFs4XSYmOD09cjtpZighbyYmIXMpcmV0dXJuIGU7MSZpJiYoZVsyXT10WzJdLG58PTEmcj8wOjQpO3ZhciBjPXRbM107aWYoYyl7dmFyIHU9ZVszXTtlWzNdPXU/RW4odSxjLHRbNF0pOmMsZVs0XT11P3RyKGVbM10sYSk6dFs0XX0oYz10WzVdKSYmKHU9ZVs1XSxlWzVdPXU/eG4odSxjLHRbNl0pOmMsZVs2XT11P3RyKGVbNV0sYSk6dFs2XSksKGM9dFs3XSkmJihlWzddPWMpLGkmbCYmKGVbOF09bnVsbD09ZVs4XT90WzhdOmdyKGVbOF0sdFs4XSkpLG51bGw9PWVbOV0mJihlWzldPXRbOV0pLGVbMF09dFswXSxlWzFdPW59KG0seSksZT1tWzBdLHQ9bVsxXSxyPW1bMl0scz1tWzNdLHU9bVs0XSwhKF89bVs5XT1tWzldPT09bj9kPzA6ZS5sZW5ndGg6dnIobVs5XS1wLDApKSYmMjQmdCYmKHQmPS0yNSksdCYmMSE9dCliPTg9PXR8fDE2PT10P2Z1bmN0aW9uKGUsdCxyKXt2YXIgbz1QbihlKTtyZXR1cm4gZnVuY3Rpb24gcygpe2Zvcih2YXIgYT1hcmd1bWVudHMubGVuZ3RoLGM9aShhKSxsPWEsdT1vbyhzKTtsLS07KWNbbF09YXJndW1lbnRzW2xdO3ZhciBoPWE8MyYmY1swXSE9PXUmJmNbYS0xXSE9PXU/W106dHIoYyx1KTtyZXR1cm4oYS09aC5sZW5ndGgpPHI/S24oZSx0LGpuLHMucGxhY2Vob2xkZXIsbixjLGgsbixuLHItYSk6Z3QodGhpcyYmdGhpcyE9PW90JiZ0aGlzIGluc3RhbmNlb2Ygcz9vOmUsdGhpcyxjKX19KGUsdCxfKTp0IT1jJiYzMyE9dHx8dS5sZW5ndGg/am4uYXBwbHkobixtKTpmdW5jdGlvbihlLHQscixuKXt2YXIgbz0xJnQscz1QbihlKTtyZXR1cm4gZnVuY3Rpb24gdCgpe2Zvcih2YXIgYT0tMSxjPWFyZ3VtZW50cy5sZW5ndGgsbD0tMSx1PW4ubGVuZ3RoLGg9aSh1K2MpLGY9dGhpcyYmdGhpcyE9PW90JiZ0aGlzIGluc3RhbmNlb2YgdD9zOmU7KytsPHU7KWhbbF09bltsXTtmb3IoO2MtLTspaFtsKytdPWFyZ3VtZW50c1srK2FdO3JldHVybiBndChmLG8/cjp0aGlzLGgpfX0oZSx0LHIscyk7ZWxzZSB2YXIgYj1mdW5jdGlvbihlLHQscil7dmFyIGk9MSZ0LG49UG4oZSk7cmV0dXJuIGZ1bmN0aW9uIHQoKXtyZXR1cm4odGhpcyYmdGhpcyE9PW90JiZ0aGlzIGluc3RhbmNlb2YgdD9uOmUpLmFwcGx5KGk/cjp0aGlzLGFyZ3VtZW50cyl9fShlLHQscik7cmV0dXJuIE9vKCh5P0ppOk1vKShiLG0pLGUsdCl9ZnVuY3Rpb24gWm4oZSx0LHIsaSl7cmV0dXJuIGU9PT1ufHxVcyhlLFJlW3JdKSYmIUJlLmNhbGwoaSxyKT90OmV9ZnVuY3Rpb24gSm4oZSx0LHIsaSxvLHMpe3JldHVybiB0YShlKSYmdGEodCkmJihzLnNldCh0LGUpLEZpKGUsdCxuLEpuLHMpLHMuZGVsZXRlKHQpKSxlfWZ1bmN0aW9uICRuKGUpe3JldHVybiBvYShlKT9uOmV9ZnVuY3Rpb24gUW4oZSx0LHIsaSxvLHMpe3ZhciBhPTEmcixjPWUubGVuZ3RoLGw9dC5sZW5ndGg7aWYoYyE9bCYmIShhJiZsPmMpKXJldHVybiExO3ZhciB1PXMuZ2V0KGUpLGg9cy5nZXQodCk7aWYodSYmaClyZXR1cm4gdT09dCYmaD09ZTt2YXIgZj0tMSxfPSEwLGQ9MiZyP25ldyBWcjpuO2ZvcihzLnNldChlLHQpLHMuc2V0KHQsZSk7KytmPGM7KXt2YXIgcD1lW2ZdLHY9dFtmXTtpZihpKXZhciBnPWE/aSh2LHAsZix0LGUscyk6aShwLHYsZixlLHQscyk7aWYoZyE9PW4pe2lmKGcpY29udGludWU7Xz0hMTticmVha31pZihkKXtpZighTXQodCwoZnVuY3Rpb24oZSx0KXtpZighS3QoZCx0KSYmKHA9PT1lfHxvKHAsZSxyLGkscykpKXJldHVybiBkLnB1c2godCl9KSkpe189ITE7YnJlYWt9fWVsc2UgaWYocCE9PXYmJiFvKHAsdixyLGkscykpe189ITE7YnJlYWt9fXJldHVybiBzLmRlbGV0ZShlKSxzLmRlbGV0ZSh0KSxffWZ1bmN0aW9uIGVvKGUpe3JldHVybiBUbyhFbyhlLG4sVm8pLGUrIiIpfWZ1bmN0aW9uIHRvKGUpe3JldHVybiBDaShlLE9hLHVvKX1mdW5jdGlvbiBybyhlKXtyZXR1cm4gQ2koZSxCYSxobyl9dmFyIGlvPWtyP2Z1bmN0aW9uKGUpe3JldHVybiBrci5nZXQoZSl9OmxjO2Z1bmN0aW9uIG5vKGUpe2Zvcih2YXIgdD1lLm5hbWUrIiIscj1Nclt0XSxpPUJlLmNhbGwoTXIsdCk/ci5sZW5ndGg6MDtpLS07KXt2YXIgbj1yW2ldLG89bi5mdW5jO2lmKG51bGw9PW98fG89PWUpcmV0dXJuIG4ubmFtZX1yZXR1cm4gdH1mdW5jdGlvbiBvbyhlKXtyZXR1cm4oQmUuY2FsbChqciwicGxhY2Vob2xkZXIiKT9qcjplKS5wbGFjZWhvbGRlcn1mdW5jdGlvbiBzbygpe3ZhciBlPWpyLml0ZXJhdGVlfHxvYztyZXR1cm4gZT1lPT09b2M/Qmk6ZSxhcmd1bWVudHMubGVuZ3RoP2UoYXJndW1lbnRzWzBdLGFyZ3VtZW50c1sxXSk6ZX1mdW5jdGlvbiBhbyhlLHQpe3ZhciByLGksbj1lLl9fZGF0YV9fO3JldHVybigic3RyaW5nIj09KGk9dHlwZW9mKHI9dCkpfHwibnVtYmVyIj09aXx8InN5bWJvbCI9PWl8fCJib29sZWFuIj09aT8iX19wcm90b19fIiE9PXI6bnVsbD09PXIpP25bInN0cmluZyI9PXR5cGVvZiB0PyJzdHJpbmciOiJoYXNoIl06bi5tYXB9ZnVuY3Rpb24gY28oZSl7Zm9yKHZhciB0PU9hKGUpLHI9dC5sZW5ndGg7ci0tOyl7dmFyIGk9dFtyXSxuPWVbaV07dFtyXT1baSxuLHdvKG4pXX1yZXR1cm4gdH1mdW5jdGlvbiBsbyhlLHQpe3ZhciByPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIG51bGw9PWU/bjplW3RdfShlLHQpO3JldHVybiBPaShyKT9yOm59dmFyIHVvPWhyP2Z1bmN0aW9uKGUpe3JldHVybiBudWxsPT1lP1tdOihlPUxlKGUpLEN0KGhyKGUpLChmdW5jdGlvbih0KXtyZXR1cm4gZXQuY2FsbChlLHQpfSkpKX06dmMsaG89aHI/ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PVtdO2U7KXh0KHQsdW8oZSkpLGU9VmUoZSk7cmV0dXJuIHR9OnZjLGZvPXdpO2Z1bmN0aW9uIF9vKGUsdCxyKXtmb3IodmFyIGk9LTEsbj0odD1nbih0LGUpKS5sZW5ndGgsbz0hMTsrK2k8bjspe3ZhciBzPWpvKHRbaV0pO2lmKCEobz1udWxsIT1lJiZyKGUscykpKWJyZWFrO2U9ZVtzXX1yZXR1cm4gb3x8KytpIT1uP286ISEobj1udWxsPT1lPzA6ZS5sZW5ndGgpJiZlYShuKSYmZ28ocyxuKSYmKEtzKGUpfHx6cyhlKSl9ZnVuY3Rpb24gcG8oZSl7cmV0dXJuImZ1bmN0aW9uIiE9dHlwZW9mIGUuY29uc3RydWN0b3J8fENvKGUpP3t9OkZyKFZlKGUpKX1mdW5jdGlvbiB2byhlKXtyZXR1cm4gS3MoZSl8fHpzKGUpfHwhIShudCYmZSYmZVtudF0pfWZ1bmN0aW9uIGdvKGUsdCl7dmFyIHI9dHlwZW9mIGU7cmV0dXJuISEodD1udWxsPT10P2g6dCkmJigibnVtYmVyIj09cnx8InN5bWJvbCIhPXImJmdlLnRlc3QoZSkpJiZlPi0xJiZlJTE9PTAmJmU8dH1mdW5jdGlvbiB5byhlLHQscil7aWYoIXRhKHIpKXJldHVybiExO3ZhciBpPXR5cGVvZiB0O3JldHVybiEhKCJudW1iZXIiPT1pP0dzKHIpJiZnbyh0LHIubGVuZ3RoKToic3RyaW5nIj09aSYmdCBpbiByKSYmVXMoclt0XSxlKX1mdW5jdGlvbiBtbyhlLHQpe2lmKEtzKGUpKXJldHVybiExO3ZhciByPXR5cGVvZiBlO3JldHVybiEoIm51bWJlciIhPXImJiJzeW1ib2wiIT1yJiYiYm9vbGVhbiIhPXImJm51bGwhPWUmJiFsYShlKSl8fFEudGVzdChlKXx8ISQudGVzdChlKXx8bnVsbCE9dCYmZSBpbiBMZSh0KX1mdW5jdGlvbiBibyhlKXt2YXIgdD1ubyhlKSxyPWpyW3RdO2lmKCJmdW5jdGlvbiIhPXR5cGVvZiByfHwhKHQgaW4gcXIucHJvdG90eXBlKSlyZXR1cm4hMTtpZihlPT09cilyZXR1cm4hMDt2YXIgaT1pbyhyKTtyZXR1cm4hIWkmJmU9PT1pWzBdfShDciYmZm8obmV3IENyKG5ldyBBcnJheUJ1ZmZlcigxKSkpIT1PfHx3ciYmZm8obmV3IHdyKSE9Q3x8THImJmZvKExyLnJlc29sdmUoKSkhPUV8fEVyJiZmbyhuZXcgRXIpIT1BfHx4ciYmZm8obmV3IHhyKSE9UikmJihmbz1mdW5jdGlvbihlKXt2YXIgdD13aShlKSxyPXQ9PUw/ZS5jb25zdHJ1Y3RvcjpuLGk9cj9GbyhyKToiIjtpZihpKXN3aXRjaChpKXtjYXNlIFJyOnJldHVybiBPO2Nhc2UgVHI6cmV0dXJuIEM7Y2FzZSBPcjpyZXR1cm4gRTtjYXNlIEJyOnJldHVybiBBO2Nhc2UgRHI6cmV0dXJuIFJ9cmV0dXJuIHR9KTt2YXIgU289VGU/JHM6Z2M7ZnVuY3Rpb24gQ28oZSl7dmFyIHQ9ZSYmZS5jb25zdHJ1Y3RvcjtyZXR1cm4gZT09PSgiZnVuY3Rpb24iPT10eXBlb2YgdCYmdC5wcm90b3R5cGV8fFJlKX1mdW5jdGlvbiB3byhlKXtyZXR1cm4gZT09ZSYmIXRhKGUpfWZ1bmN0aW9uIExvKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIpe3JldHVybiBudWxsIT1yJiZyW2VdPT09dCYmKHQhPT1ufHxlIGluIExlKHIpKX19ZnVuY3Rpb24gRW8oZSx0LHIpe3JldHVybiB0PXZyKHQ9PT1uP2UubGVuZ3RoLTE6dCwwKSxmdW5jdGlvbigpe2Zvcih2YXIgbj1hcmd1bWVudHMsbz0tMSxzPXZyKG4ubGVuZ3RoLXQsMCksYT1pKHMpOysrbzxzOylhW29dPW5bdCtvXTtvPS0xO2Zvcih2YXIgYz1pKHQrMSk7KytvPHQ7KWNbb109bltvXTtyZXR1cm4gY1t0XT1yKGEpLGd0KGUsdGhpcyxjKX19ZnVuY3Rpb24geG8oZSx0KXtyZXR1cm4gdC5sZW5ndGg8Mj9lOlNpKGUsZW4odCwwLC0xKSl9ZnVuY3Rpb24gQW8oZSx0KXtmb3IodmFyIHI9ZS5sZW5ndGgsaT1ncih0Lmxlbmd0aCxyKSxvPUFuKGUpO2ktLTspe3ZhciBzPXRbaV07ZVtpXT1nbyhzLHIpP29bc106bn1yZXR1cm4gZX1mdW5jdGlvbiBrbyhlLHQpe2lmKCgiY29uc3RydWN0b3IiIT09dHx8ImZ1bmN0aW9uIiE9dHlwZW9mIGVbdF0pJiYiX19wcm90b19fIiE9dClyZXR1cm4gZVt0XX12YXIgTW89Qm8oSmkpLFJvPWp0fHxmdW5jdGlvbihlLHQpe3JldHVybiBvdC5zZXRUaW1lb3V0KGUsdCl9LFRvPUJvKCRpKTtmdW5jdGlvbiBPbyhlLHQscil7dmFyIGk9dCsiIjtyZXR1cm4gVG8oZSxmdW5jdGlvbihlLHQpe3ZhciByPXQubGVuZ3RoO2lmKCFyKXJldHVybiBlO3ZhciBpPXItMTtyZXR1cm4gdFtpXT0ocj4xPyImICI6IiIpK3RbaV0sdD10LmpvaW4ocj4yPyIsICI6IiAiKSxlLnJlcGxhY2Uob2UsIntcbi8qIFt3cmFwcGVkIHdpdGggIit0KyJdICovXG4iKX0oaSxmdW5jdGlvbihlLHQpe3JldHVybiBtdChkLChmdW5jdGlvbihyKXt2YXIgaT0iXy4iK3JbMF07dCZyWzFdJiYhd3QoZSxpKSYmZS5wdXNoKGkpfSkpLGUuc29ydCgpfShmdW5jdGlvbihlKXt2YXIgdD1lLm1hdGNoKHNlKTtyZXR1cm4gdD90WzFdLnNwbGl0KGFlKTpbXX0oaSkscikpKX1mdW5jdGlvbiBCbyhlKXt2YXIgdD0wLHI9MDtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgaT15cigpLG89MTYtKGktcik7aWYocj1pLG8+MCl7aWYoKyt0Pj04MDApcmV0dXJuIGFyZ3VtZW50c1swXX1lbHNlIHQ9MDtyZXR1cm4gZS5hcHBseShuLGFyZ3VtZW50cyl9fWZ1bmN0aW9uIERvKGUsdCl7dmFyIHI9LTEsaT1lLmxlbmd0aCxvPWktMTtmb3IodD10PT09bj9pOnQ7KytyPHQ7KXt2YXIgcz1LaShyLG8pLGE9ZVtzXTtlW3NdPWVbcl0sZVtyXT1hfXJldHVybiBlLmxlbmd0aD10LGV9dmFyIFBvLElvLEhvPShQbz1QcygoZnVuY3Rpb24oZSl7dmFyIHQ9W107cmV0dXJuIDQ2PT09ZS5jaGFyQ29kZUF0KDApJiZ0LnB1c2goIiIpLGUucmVwbGFjZShlZSwoZnVuY3Rpb24oZSxyLGksbil7dC5wdXNoKGk/bi5yZXBsYWNlKHVlLCIkMSIpOnJ8fGUpfSkpLHR9KSwoZnVuY3Rpb24oZSl7cmV0dXJuIDUwMD09PUlvLnNpemUmJklvLmNsZWFyKCksZX0pKSxJbz1Qby5jYWNoZSxQbyk7ZnVuY3Rpb24gam8oZSl7aWYoInN0cmluZyI9PXR5cGVvZiBlfHxsYShlKSlyZXR1cm4gZTt2YXIgdD1lKyIiO3JldHVybiIwIj09dCYmMS9lPT0tMS8wPyItMCI6dH1mdW5jdGlvbiBGbyhlKXtpZihudWxsIT1lKXt0cnl7cmV0dXJuIE9lLmNhbGwoZSl9Y2F0Y2goZSl7fXRyeXtyZXR1cm4gZSsiIn1jYXRjaChlKXt9fXJldHVybiIifWZ1bmN0aW9uIFdvKGUpe2lmKGUgaW5zdGFuY2VvZiBxcilyZXR1cm4gZS5jbG9uZSgpO3ZhciB0PW5ldyBVcihlLl9fd3JhcHBlZF9fLGUuX19jaGFpbl9fKTtyZXR1cm4gdC5fX2FjdGlvbnNfXz1BbihlLl9fYWN0aW9uc19fKSx0Ll9faW5kZXhfXz1lLl9faW5kZXhfXyx0Ll9fdmFsdWVzX189ZS5fX3ZhbHVlc19fLHR9dmFyIFVvPUdpKChmdW5jdGlvbihlLHQpe3JldHVybiBZcyhlKT9saShlLHBpKHQsMSxZcywhMCkpOltdfSkpLHFvPUdpKChmdW5jdGlvbihlLHQpe3ZhciByPUpvKHQpO3JldHVybiBZcyhyKSYmKHI9biksWXMoZSk/bGkoZSxwaSh0LDEsWXMsITApLHNvKHIsMikpOltdfSkpLE5vPUdpKChmdW5jdGlvbihlLHQpe3ZhciByPUpvKHQpO3JldHVybiBZcyhyKSYmKHI9biksWXMoZSk/bGkoZSxwaSh0LDEsWXMsITApLG4scik6W119KSk7ZnVuY3Rpb24gem8oZSx0LHIpe3ZhciBpPW51bGw9PWU/MDplLmxlbmd0aDtpZighaSlyZXR1cm4tMTt2YXIgbj1udWxsPT1yPzA6cGEocik7cmV0dXJuIG48MCYmKG49dnIoaStuLDApKSxPdChlLHNvKHQsMyksbil9ZnVuY3Rpb24gS28oZSx0LHIpe3ZhciBpPW51bGw9PWU/MDplLmxlbmd0aDtpZighaSlyZXR1cm4tMTt2YXIgbz1pLTE7cmV0dXJuIHIhPT1uJiYobz1wYShyKSxvPXI8MD92cihpK28sMCk6Z3IobyxpLTEpKSxPdChlLHNvKHQsMyksbywhMCl9ZnVuY3Rpb24gVm8oZSl7cmV0dXJuIG51bGwhPWUmJmUubGVuZ3RoP3BpKGUsMSk6W119ZnVuY3Rpb24gR28oZSl7cmV0dXJuIGUmJmUubGVuZ3RoP2VbMF06bn12YXIgWW89R2koKGZ1bmN0aW9uKGUpe3ZhciB0PUV0KGUscG4pO3JldHVybiB0Lmxlbmd0aCYmdFswXT09PWVbMF0/QWkodCk6W119KSksWG89R2koKGZ1bmN0aW9uKGUpe3ZhciB0PUpvKGUpLHI9RXQoZSxwbik7cmV0dXJuIHQ9PT1KbyhyKT90PW46ci5wb3AoKSxyLmxlbmd0aCYmclswXT09PWVbMF0/QWkocixzbyh0LDIpKTpbXX0pKSxabz1HaSgoZnVuY3Rpb24oZSl7dmFyIHQ9Sm8oZSkscj1FdChlLHBuKTtyZXR1cm4odD0iZnVuY3Rpb24iPT10eXBlb2YgdD90Om4pJiZyLnBvcCgpLHIubGVuZ3RoJiZyWzBdPT09ZVswXT9BaShyLG4sdCk6W119KSk7ZnVuY3Rpb24gSm8oZSl7dmFyIHQ9bnVsbD09ZT8wOmUubGVuZ3RoO3JldHVybiB0P2VbdC0xXTpufXZhciAkbz1HaShRbyk7ZnVuY3Rpb24gUW8oZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGgmJnQmJnQubGVuZ3RoP05pKGUsdCk6ZX12YXIgZXM9ZW8oKGZ1bmN0aW9uKGUsdCl7dmFyIHI9bnVsbD09ZT8wOmUubGVuZ3RoLGk9bmkoZSx0KTtyZXR1cm4gemkoZSxFdCh0LChmdW5jdGlvbihlKXtyZXR1cm4gZ28oZSxyKT8rZTplfSkpLnNvcnQoTG4pKSxpfSkpO2Z1bmN0aW9uIHRzKGUpe3JldHVybiBudWxsPT1lP2U6U3IuY2FsbChlKX12YXIgcnM9R2koKGZ1bmN0aW9uKGUpe3JldHVybiBjbihwaShlLDEsWXMsITApKX0pKSxpcz1HaSgoZnVuY3Rpb24oZSl7dmFyIHQ9Sm8oZSk7cmV0dXJuIFlzKHQpJiYodD1uKSxjbihwaShlLDEsWXMsITApLHNvKHQsMikpfSkpLG5zPUdpKChmdW5jdGlvbihlKXt2YXIgdD1KbyhlKTtyZXR1cm4gdD0iZnVuY3Rpb24iPT10eXBlb2YgdD90Om4sY24ocGkoZSwxLFlzLCEwKSxuLHQpfSkpO2Z1bmN0aW9uIG9zKGUpe2lmKCFlfHwhZS5sZW5ndGgpcmV0dXJuW107dmFyIHQ9MDtyZXR1cm4gZT1DdChlLChmdW5jdGlvbihlKXtpZihZcyhlKSlyZXR1cm4gdD12cihlLmxlbmd0aCx0KSwhMH0pKSxVdCh0LChmdW5jdGlvbih0KXtyZXR1cm4gRXQoZSxIdCh0KSl9KSl9ZnVuY3Rpb24gc3MoZSx0KXtpZighZXx8IWUubGVuZ3RoKXJldHVybltdO3ZhciByPW9zKGUpO3JldHVybiBudWxsPT10P3I6RXQociwoZnVuY3Rpb24oZSl7cmV0dXJuIGd0KHQsbixlKX0pKX12YXIgYXM9R2koKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIFlzKGUpP2xpKGUsdCk6W119KSksY3M9R2koKGZ1bmN0aW9uKGUpe3JldHVybiBfbihDdChlLFlzKSl9KSksbHM9R2koKGZ1bmN0aW9uKGUpe3ZhciB0PUpvKGUpO3JldHVybiBZcyh0KSYmKHQ9biksX24oQ3QoZSxZcyksc28odCwyKSl9KSksdXM9R2koKGZ1bmN0aW9uKGUpe3ZhciB0PUpvKGUpO3JldHVybiB0PSJmdW5jdGlvbiI9PXR5cGVvZiB0P3Q6bixfbihDdChlLFlzKSxuLHQpfSkpLGhzPUdpKG9zKSxmcz1HaSgoZnVuY3Rpb24oZSl7dmFyIHQ9ZS5sZW5ndGgscj10PjE/ZVt0LTFdOm47cmV0dXJuIHI9ImZ1bmN0aW9uIj09dHlwZW9mIHI/KGUucG9wKCkscik6bixzcyhlLHIpfSkpO2Z1bmN0aW9uIF9zKGUpe3ZhciB0PWpyKGUpO3JldHVybiB0Ll9fY2hhaW5fXz0hMCx0fWZ1bmN0aW9uIGRzKGUsdCl7cmV0dXJuIHQoZSl9dmFyIHBzPWVvKChmdW5jdGlvbihlKXt2YXIgdD1lLmxlbmd0aCxyPXQ/ZVswXTowLGk9dGhpcy5fX3dyYXBwZWRfXyxvPWZ1bmN0aW9uKHQpe3JldHVybiBuaSh0LGUpfTtyZXR1cm4hKHQ+MXx8dGhpcy5fX2FjdGlvbnNfXy5sZW5ndGgpJiZpIGluc3RhbmNlb2YgcXImJmdvKHIpPygoaT1pLnNsaWNlKHIsK3IrKHQ/MTowKSkpLl9fYWN0aW9uc19fLnB1c2goe2Z1bmM6ZHMsYXJnczpbb10sdGhpc0FyZzpufSksbmV3IFVyKGksdGhpcy5fX2NoYWluX18pLnRocnUoKGZ1bmN0aW9uKGUpe3JldHVybiB0JiYhZS5sZW5ndGgmJmUucHVzaChuKSxlfSkpKTp0aGlzLnRocnUobyl9KSksdnM9TW4oKGZ1bmN0aW9uKGUsdCxyKXtCZS5jYWxsKGUscik/KytlW3JdOmlpKGUsciwxKX0pKSxncz1Jbih6bykseXM9SW4oS28pO2Z1bmN0aW9uIG1zKGUsdCl7cmV0dXJuKEtzKGUpP210OnVpKShlLHNvKHQsMykpfWZ1bmN0aW9uIGJzKGUsdCl7cmV0dXJuKEtzKGUpP2J0OmhpKShlLHNvKHQsMykpfXZhciBTcz1NbigoZnVuY3Rpb24oZSx0LHIpe0JlLmNhbGwoZSxyKT9lW3JdLnB1c2godCk6aWkoZSxyLFt0XSl9KSksQ3M9R2koKGZ1bmN0aW9uKGUsdCxyKXt2YXIgbj0tMSxvPSJmdW5jdGlvbiI9PXR5cGVvZiB0LHM9R3MoZSk/aShlLmxlbmd0aCk6W107cmV0dXJuIHVpKGUsKGZ1bmN0aW9uKGUpe3NbKytuXT1vP2d0KHQsZSxyKTpraShlLHQscil9KSksc30pKSx3cz1NbigoZnVuY3Rpb24oZSx0LHIpe2lpKGUscix0KX0pKTtmdW5jdGlvbiBMcyhlLHQpe3JldHVybihLcyhlKT9FdDpJaSkoZSxzbyh0LDMpKX12YXIgRXM9TW4oKGZ1bmN0aW9uKGUsdCxyKXtlW3I/MDoxXS5wdXNoKHQpfSksKGZ1bmN0aW9uKCl7cmV0dXJuW1tdLFtdXX0pKSx4cz1HaSgoZnVuY3Rpb24oZSx0KXtpZihudWxsPT1lKXJldHVybltdO3ZhciByPXQubGVuZ3RoO3JldHVybiByPjEmJnlvKGUsdFswXSx0WzFdKT90PVtdOnI+MiYmeW8odFswXSx0WzFdLHRbMl0pJiYodD1bdFswXV0pLFVpKGUscGkodCwxKSxbXSl9KSksQXM9UnR8fGZ1bmN0aW9uKCl7cmV0dXJuIG90LkRhdGUubm93KCl9O2Z1bmN0aW9uIGtzKGUsdCxyKXtyZXR1cm4gdD1yP246dCx0PWUmJm51bGw9PXQ/ZS5sZW5ndGg6dCxYbihlLGwsbixuLG4sbix0KX1mdW5jdGlvbiBNcyhlLHQpe3ZhciByO2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0KXRocm93IG5ldyBBZShvKTtyZXR1cm4gZT1wYShlKSxmdW5jdGlvbigpe3JldHVybi0tZT4wJiYocj10LmFwcGx5KHRoaXMsYXJndW1lbnRzKSksZTw9MSYmKHQ9bikscn19dmFyIFJzPUdpKChmdW5jdGlvbihlLHQscil7dmFyIGk9MTtpZihyLmxlbmd0aCl7dmFyIG49dHIocixvbyhScykpO2l8PWN9cmV0dXJuIFhuKGUsaSx0LHIsbil9KSksVHM9R2koKGZ1bmN0aW9uKGUsdCxyKXt2YXIgaT0zO2lmKHIubGVuZ3RoKXt2YXIgbj10cihyLG9vKFRzKSk7aXw9Y31yZXR1cm4gWG4odCxpLGUscixuKX0pKTtmdW5jdGlvbiBPcyhlLHQscil7dmFyIGkscyxhLGMsbCx1LGg9MCxmPSExLF89ITEsZD0hMDtpZigiZnVuY3Rpb24iIT10eXBlb2YgZSl0aHJvdyBuZXcgQWUobyk7ZnVuY3Rpb24gcCh0KXt2YXIgcj1pLG89cztyZXR1cm4gaT1zPW4saD10LGM9ZS5hcHBseShvLHIpfWZ1bmN0aW9uIHYoZSl7cmV0dXJuIGg9ZSxsPVJvKHksdCksZj9wKGUpOmN9ZnVuY3Rpb24gZyhlKXt2YXIgcj1lLXU7cmV0dXJuIHU9PT1ufHxyPj10fHxyPDB8fF8mJmUtaD49YX1mdW5jdGlvbiB5KCl7dmFyIGU9QXMoKTtpZihnKGUpKXJldHVybiBtKGUpO2w9Um8oeSxmdW5jdGlvbihlKXt2YXIgcj10LShlLXUpO3JldHVybiBfP2dyKHIsYS0oZS1oKSk6cn0oZSkpfWZ1bmN0aW9uIG0oZSl7cmV0dXJuIGw9bixkJiZpP3AoZSk6KGk9cz1uLGMpfWZ1bmN0aW9uIGIoKXt2YXIgZT1BcygpLHI9ZyhlKTtpZihpPWFyZ3VtZW50cyxzPXRoaXMsdT1lLHIpe2lmKGw9PT1uKXJldHVybiB2KHUpO2lmKF8pcmV0dXJuIGJuKGwpLGw9Um8oeSx0KSxwKHUpfXJldHVybiBsPT09biYmKGw9Um8oeSx0KSksY31yZXR1cm4gdD1nYSh0KXx8MCx0YShyKSYmKGY9ISFyLmxlYWRpbmcsYT0oXz0ibWF4V2FpdCJpbiByKT92cihnYShyLm1heFdhaXQpfHwwLHQpOmEsZD0idHJhaWxpbmciaW4gcj8hIXIudHJhaWxpbmc6ZCksYi5jYW5jZWw9ZnVuY3Rpb24oKXtsIT09biYmYm4obCksaD0wLGk9dT1zPWw9bn0sYi5mbHVzaD1mdW5jdGlvbigpe3JldHVybiBsPT09bj9jOm0oQXMoKSl9LGJ9dmFyIEJzPUdpKChmdW5jdGlvbihlLHQpe3JldHVybiBjaShlLDEsdCl9KSksRHM9R2koKGZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gY2koZSxnYSh0KXx8MCxyKX0pKTtmdW5jdGlvbiBQcyhlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBlfHxudWxsIT10JiYiZnVuY3Rpb24iIT10eXBlb2YgdCl0aHJvdyBuZXcgQWUobyk7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgaT1hcmd1bWVudHMsbj10P3QuYXBwbHkodGhpcyxpKTppWzBdLG89ci5jYWNoZTtpZihvLmhhcyhuKSlyZXR1cm4gby5nZXQobik7dmFyIHM9ZS5hcHBseSh0aGlzLGkpO3JldHVybiByLmNhY2hlPW8uc2V0KG4scyl8fG8sc307cmV0dXJuIHIuY2FjaGU9bmV3KFBzLkNhY2hlfHxLcikscn1mdW5jdGlvbiBJcyhlKXtpZigiZnVuY3Rpb24iIT10eXBlb2YgZSl0aHJvdyBuZXcgQWUobyk7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIHQ9YXJndW1lbnRzO3N3aXRjaCh0Lmxlbmd0aCl7Y2FzZSAwOnJldHVybiFlLmNhbGwodGhpcyk7Y2FzZSAxOnJldHVybiFlLmNhbGwodGhpcyx0WzBdKTtjYXNlIDI6cmV0dXJuIWUuY2FsbCh0aGlzLHRbMF0sdFsxXSk7Y2FzZSAzOnJldHVybiFlLmNhbGwodGhpcyx0WzBdLHRbMV0sdFsyXSl9cmV0dXJuIWUuYXBwbHkodGhpcyx0KX19UHMuQ2FjaGU9S3I7dmFyIEhzPXluKChmdW5jdGlvbihlLHQpe3ZhciByPSh0PTE9PXQubGVuZ3RoJiZLcyh0WzBdKT9FdCh0WzBdLE50KHNvKCkpKTpFdChwaSh0LDEpLE50KHNvKCkpKSkubGVuZ3RoO3JldHVybiBHaSgoZnVuY3Rpb24oaSl7Zm9yKHZhciBuPS0xLG89Z3IoaS5sZW5ndGgscik7KytuPG87KWlbbl09dFtuXS5jYWxsKHRoaXMsaVtuXSk7cmV0dXJuIGd0KGUsdGhpcyxpKX0pKX0pKSxqcz1HaSgoZnVuY3Rpb24oZSx0KXt2YXIgcj10cih0LG9vKGpzKSk7cmV0dXJuIFhuKGUsYyxuLHQscil9KSksRnM9R2koKGZ1bmN0aW9uKGUsdCl7dmFyIHI9dHIodCxvbyhGcykpO3JldHVybiBYbihlLDY0LG4sdCxyKX0pKSxXcz1lbygoZnVuY3Rpb24oZSx0KXtyZXR1cm4gWG4oZSwyNTYsbixuLG4sdCl9KSk7ZnVuY3Rpb24gVXMoZSx0KXtyZXR1cm4gZT09PXR8fGUhPWUmJnQhPXR9dmFyIHFzPXpuKExpKSxOcz16bigoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZT49dH0pKSx6cz1NaShmdW5jdGlvbigpe3JldHVybiBhcmd1bWVudHN9KCkpP01pOmZ1bmN0aW9uKGUpe3JldHVybiByYShlKSYmQmUuY2FsbChlLCJjYWxsZWUiKSYmIWV0LmNhbGwoZSwiY2FsbGVlIil9LEtzPWkuaXNBcnJheSxWcz1odD9OdChodCk6ZnVuY3Rpb24oZSl7cmV0dXJuIHJhKGUpJiZ3aShlKT09VH07ZnVuY3Rpb24gR3MoZSl7cmV0dXJuIG51bGwhPWUmJmVhKGUubGVuZ3RoKSYmISRzKGUpfWZ1bmN0aW9uIFlzKGUpe3JldHVybiByYShlKSYmR3MoZSl9dmFyIFhzPWZyfHxnYyxacz1mdD9OdChmdCk6ZnVuY3Rpb24oZSl7cmV0dXJuIHJhKGUpJiZ3aShlKT09eX07ZnVuY3Rpb24gSnMoZSl7aWYoIXJhKGUpKXJldHVybiExO3ZhciB0PXdpKGUpO3JldHVybiB0PT1tfHwiW29iamVjdCBET01FeGNlcHRpb25dIj09dHx8InN0cmluZyI9PXR5cGVvZiBlLm1lc3NhZ2UmJiJzdHJpbmciPT10eXBlb2YgZS5uYW1lJiYhb2EoZSl9ZnVuY3Rpb24gJHMoZSl7aWYoIXRhKGUpKXJldHVybiExO3ZhciB0PXdpKGUpO3JldHVybiB0PT1ifHx0PT1TfHwiW29iamVjdCBBc3luY0Z1bmN0aW9uXSI9PXR8fCJbb2JqZWN0IFByb3h5XSI9PXR9ZnVuY3Rpb24gUXMoZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlJiZlPT1wYShlKX1mdW5jdGlvbiBlYShlKXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGUmJmU+LTEmJmUlMT09MCYmZTw9aH1mdW5jdGlvbiB0YShlKXt2YXIgdD10eXBlb2YgZTtyZXR1cm4gbnVsbCE9ZSYmKCJvYmplY3QiPT10fHwiZnVuY3Rpb24iPT10KX1mdW5jdGlvbiByYShlKXtyZXR1cm4gbnVsbCE9ZSYmIm9iamVjdCI9PXR5cGVvZiBlfXZhciBpYT1fdD9OdChfdCk6ZnVuY3Rpb24oZSl7cmV0dXJuIHJhKGUpJiZmbyhlKT09Q307ZnVuY3Rpb24gbmEoZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlfHxyYShlKSYmd2koZSk9PXd9ZnVuY3Rpb24gb2EoZSl7aWYoIXJhKGUpfHx3aShlKSE9TClyZXR1cm4hMTt2YXIgdD1WZShlKTtpZihudWxsPT09dClyZXR1cm4hMDt2YXIgcj1CZS5jYWxsKHQsImNvbnN0cnVjdG9yIikmJnQuY29uc3RydWN0b3I7cmV0dXJuImZ1bmN0aW9uIj09dHlwZW9mIHImJnIgaW5zdGFuY2VvZiByJiZPZS5jYWxsKHIpPT1IZX12YXIgc2E9ZHQ/TnQoZHQpOmZ1bmN0aW9uKGUpe3JldHVybiByYShlKSYmd2koZSk9PXh9LGFhPXB0P050KHB0KTpmdW5jdGlvbihlKXtyZXR1cm4gcmEoZSkmJmZvKGUpPT1BfTtmdW5jdGlvbiBjYShlKXtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGV8fCFLcyhlKSYmcmEoZSkmJndpKGUpPT1rfWZ1bmN0aW9uIGxhKGUpe3JldHVybiJzeW1ib2wiPT10eXBlb2YgZXx8cmEoZSkmJndpKGUpPT1NfXZhciB1YT12dD9OdCh2dCk6ZnVuY3Rpb24oZSl7cmV0dXJuIHJhKGUpJiZlYShlLmxlbmd0aCkmJiEhJGVbd2koZSldfSxoYT16bihQaSksZmE9em4oKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGU8PXR9KSk7ZnVuY3Rpb24gX2EoZSl7aWYoIWUpcmV0dXJuW107aWYoR3MoZSkpcmV0dXJuIGNhKGUpP29yKGUpOkFuKGUpO2lmKHN0JiZlW3N0XSlyZXR1cm4gZnVuY3Rpb24oZSl7Zm9yKHZhciB0LHI9W107ISh0PWUubmV4dCgpKS5kb25lOylyLnB1c2godC52YWx1ZSk7cmV0dXJuIHJ9KGVbc3RdKCkpO3ZhciB0PWZvKGUpO3JldHVybih0PT1DP1F0OnQ9PUE/cnI6VWEpKGUpfWZ1bmN0aW9uIGRhKGUpe3JldHVybiBlPyhlPWdhKGUpKT09PXV8fGU9PT0tMS8wPzE3OTc2OTMxMzQ4NjIzMTU3ZTI5MiooZTwwPy0xOjEpOmU9PWU/ZTowOjA9PT1lP2U6MH1mdW5jdGlvbiBwYShlKXt2YXIgdD1kYShlKSxyPXQlMTtyZXR1cm4gdD09dD9yP3Qtcjp0OjB9ZnVuY3Rpb24gdmEoZSl7cmV0dXJuIGU/b2kocGEoZSksMCxfKTowfWZ1bmN0aW9uIGdhKGUpe2lmKCJudW1iZXIiPT10eXBlb2YgZSlyZXR1cm4gZTtpZihsYShlKSlyZXR1cm4gZjtpZih0YShlKSl7dmFyIHQ9ImZ1bmN0aW9uIj09dHlwZW9mIGUudmFsdWVPZj9lLnZhbHVlT2YoKTplO2U9dGEodCk/dCsiIjp0fWlmKCJzdHJpbmciIT10eXBlb2YgZSlyZXR1cm4gMD09PWU/ZTorZTtlPXF0KGUpO3ZhciByPWRlLnRlc3QoZSk7cmV0dXJuIHJ8fHZlLnRlc3QoZSk/cnQoZS5zbGljZSgyKSxyPzI6OCk6X2UudGVzdChlKT9mOitlfWZ1bmN0aW9uIHlhKGUpe3JldHVybiBrbihlLEJhKGUpKX1mdW5jdGlvbiBtYShlKXtyZXR1cm4gbnVsbD09ZT8iIjphbihlKX12YXIgYmE9Um4oKGZ1bmN0aW9uKGUsdCl7aWYoQ28odCl8fEdzKHQpKWtuKHQsT2EodCksZSk7ZWxzZSBmb3IodmFyIHIgaW4gdClCZS5jYWxsKHQscikmJlFyKGUscix0W3JdKX0pKSxTYT1SbigoZnVuY3Rpb24oZSx0KXtrbih0LEJhKHQpLGUpfSkpLENhPVJuKChmdW5jdGlvbihlLHQscixpKXtrbih0LEJhKHQpLGUsaSl9KSksd2E9Um4oKGZ1bmN0aW9uKGUsdCxyLGkpe2tuKHQsT2EodCksZSxpKX0pKSxMYT1lbyhuaSksRWE9R2koKGZ1bmN0aW9uKGUsdCl7ZT1MZShlKTt2YXIgcj0tMSxpPXQubGVuZ3RoLG89aT4yP3RbMl06bjtmb3IobyYmeW8odFswXSx0WzFdLG8pJiYoaT0xKTsrK3I8aTspZm9yKHZhciBzPXRbcl0sYT1CYShzKSxjPS0xLGw9YS5sZW5ndGg7KytjPGw7KXt2YXIgdT1hW2NdLGg9ZVt1XTsoaD09PW58fFVzKGgsUmVbdV0pJiYhQmUuY2FsbChlLHUpKSYmKGVbdV09c1t1XSl9cmV0dXJuIGV9KSkseGE9R2koKGZ1bmN0aW9uKGUpe3JldHVybiBlLnB1c2gobixKbiksZ3QoUGEsbixlKX0pKTtmdW5jdGlvbiBBYShlLHQscil7dmFyIGk9bnVsbD09ZT9uOlNpKGUsdCk7cmV0dXJuIGk9PT1uP3I6aX1mdW5jdGlvbiBrYShlLHQpe3JldHVybiBudWxsIT1lJiZfbyhlLHQseGkpfXZhciBNYT1GbigoZnVuY3Rpb24oZSx0LHIpe251bGwhPXQmJiJmdW5jdGlvbiIhPXR5cGVvZiB0LnRvU3RyaW5nJiYodD1JZS5jYWxsKHQpKSxlW3RdPXJ9KSx0YyhuYykpLFJhPUZuKChmdW5jdGlvbihlLHQscil7bnVsbCE9dCYmImZ1bmN0aW9uIiE9dHlwZW9mIHQudG9TdHJpbmcmJih0PUllLmNhbGwodCkpLEJlLmNhbGwoZSx0KT9lW3RdLnB1c2gocik6ZVt0XT1bcl19KSxzbyksVGE9R2koa2kpO2Z1bmN0aW9uIE9hKGUpe3JldHVybiBHcyhlKT9ZcihlKTpEaShlKX1mdW5jdGlvbiBCYShlKXtyZXR1cm4gR3MoZSk/WXIoZSwhMCk6ZnVuY3Rpb24oZSl7aWYoIXRhKGUpKXJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1bXTtpZihudWxsIT1lKWZvcih2YXIgciBpbiBMZShlKSl0LnB1c2gocik7cmV0dXJuIHR9KGUpO3ZhciB0PUNvKGUpLHI9W107Zm9yKHZhciBpIGluIGUpKCJjb25zdHJ1Y3RvciIhPWl8fCF0JiZCZS5jYWxsKGUsaSkpJiZyLnB1c2goaSk7cmV0dXJuIHJ9KGUpfXZhciBEYT1SbigoZnVuY3Rpb24oZSx0LHIpe0ZpKGUsdCxyKX0pKSxQYT1SbigoZnVuY3Rpb24oZSx0LHIsaSl7RmkoZSx0LHIsaSl9KSksSWE9ZW8oKGZ1bmN0aW9uKGUsdCl7dmFyIHI9e307aWYobnVsbD09ZSlyZXR1cm4gcjt2YXIgaT0hMTt0PUV0KHQsKGZ1bmN0aW9uKHQpe3JldHVybiB0PWduKHQsZSksaXx8KGk9dC5sZW5ndGg+MSksdH0pKSxrbihlLHJvKGUpLHIpLGkmJihyPXNpKHIsNywkbikpO2Zvcih2YXIgbj10Lmxlbmd0aDtuLS07KWxuKHIsdFtuXSk7cmV0dXJuIHJ9KSksSGE9ZW8oKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG51bGw9PWU/e306ZnVuY3Rpb24oZSx0KXtyZXR1cm4gcWkoZSx0LChmdW5jdGlvbih0LHIpe3JldHVybiBrYShlLHIpfSkpfShlLHQpfSkpO2Z1bmN0aW9uIGphKGUsdCl7aWYobnVsbD09ZSlyZXR1cm57fTt2YXIgcj1FdChybyhlKSwoZnVuY3Rpb24oZSl7cmV0dXJuW2VdfSkpO3JldHVybiB0PXNvKHQpLHFpKGUsciwoZnVuY3Rpb24oZSxyKXtyZXR1cm4gdChlLHJbMF0pfSkpfXZhciBGYT1ZbihPYSksV2E9WW4oQmEpO2Z1bmN0aW9uIFVhKGUpe3JldHVybiBudWxsPT1lP1tdOnp0KGUsT2EoZSkpfXZhciBxYT1EbigoZnVuY3Rpb24oZSx0LHIpe3JldHVybiB0PXQudG9Mb3dlckNhc2UoKSxlKyhyP05hKHQpOnQpfSkpO2Z1bmN0aW9uIE5hKGUpe3JldHVybiBKYShtYShlKS50b0xvd2VyQ2FzZSgpKX1mdW5jdGlvbiB6YShlKXtyZXR1cm4oZT1tYShlKSkmJmUucmVwbGFjZSh5ZSxYdCkucmVwbGFjZShLZSwiIil9dmFyIEthPURuKChmdW5jdGlvbihlLHQscil7cmV0dXJuIGUrKHI/Ii0iOiIiKSt0LnRvTG93ZXJDYXNlKCl9KSksVmE9RG4oKGZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gZSsocj8iICI6IiIpK3QudG9Mb3dlckNhc2UoKX0pKSxHYT1CbigidG9Mb3dlckNhc2UiKSxZYT1EbigoZnVuY3Rpb24oZSx0LHIpe3JldHVybiBlKyhyPyJfIjoiIikrdC50b0xvd2VyQ2FzZSgpfSkpLFhhPURuKChmdW5jdGlvbihlLHQscil7cmV0dXJuIGUrKHI/IiAiOiIiKStKYSh0KX0pKSxaYT1EbigoZnVuY3Rpb24oZSx0LHIpe3JldHVybiBlKyhyPyIgIjoiIikrdC50b1VwcGVyQ2FzZSgpfSkpLEphPUJuKCJ0b1VwcGVyQ2FzZSIpO2Z1bmN0aW9uICRhKGUsdCxyKXtyZXR1cm4gZT1tYShlKSwodD1yP246dCk9PT1uP2Z1bmN0aW9uKGUpe3JldHVybiBYZS50ZXN0KGUpfShlKT9mdW5jdGlvbihlKXtyZXR1cm4gZS5tYXRjaChHZSl8fFtdfShlKTpmdW5jdGlvbihlKXtyZXR1cm4gZS5tYXRjaChjZSl8fFtdfShlKTplLm1hdGNoKHQpfHxbXX12YXIgUWE9R2koKGZ1bmN0aW9uKGUsdCl7dHJ5e3JldHVybiBndChlLG4sdCl9Y2F0Y2goZSl7cmV0dXJuIEpzKGUpP2U6bmV3IFNlKGUpfX0pKSxlYz1lbygoZnVuY3Rpb24oZSx0KXtyZXR1cm4gbXQodCwoZnVuY3Rpb24odCl7dD1qbyh0KSxpaShlLHQsUnMoZVt0XSxlKSl9KSksZX0pKTtmdW5jdGlvbiB0YyhlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gZX19dmFyIHJjPUhuKCksaWM9SG4oITApO2Z1bmN0aW9uIG5jKGUpe3JldHVybiBlfWZ1bmN0aW9uIG9jKGUpe3JldHVybiBCaSgiZnVuY3Rpb24iPT10eXBlb2YgZT9lOnNpKGUsMSkpfXZhciBzYz1HaSgoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocil7cmV0dXJuIGtpKHIsZSx0KX19KSksYWM9R2koKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIpe3JldHVybiBraShlLHIsdCl9fSkpO2Z1bmN0aW9uIGNjKGUsdCxyKXt2YXIgaT1PYSh0KSxuPWJpKHQsaSk7bnVsbCE9cnx8dGEodCkmJihuLmxlbmd0aHx8IWkubGVuZ3RoKXx8KHI9dCx0PWUsZT10aGlzLG49YmkodCxPYSh0KSkpO3ZhciBvPSEodGEocikmJiJjaGFpbiJpbiByJiYhci5jaGFpbikscz0kcyhlKTtyZXR1cm4gbXQobiwoZnVuY3Rpb24ocil7dmFyIGk9dFtyXTtlW3JdPWkscyYmKGUucHJvdG90eXBlW3JdPWZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5fX2NoYWluX187aWYob3x8dCl7dmFyIHI9ZSh0aGlzLl9fd3JhcHBlZF9fKSxuPXIuX19hY3Rpb25zX189QW4odGhpcy5fX2FjdGlvbnNfXyk7cmV0dXJuIG4ucHVzaCh7ZnVuYzppLGFyZ3M6YXJndW1lbnRzLHRoaXNBcmc6ZX0pLHIuX19jaGFpbl9fPXQscn1yZXR1cm4gaS5hcHBseShlLHh0KFt0aGlzLnZhbHVlKCldLGFyZ3VtZW50cykpfSl9KSksZX1mdW5jdGlvbiBsYygpe312YXIgdWM9VW4oRXQpLGhjPVVuKFN0KSxmYz1VbihNdCk7ZnVuY3Rpb24gX2MoZSl7cmV0dXJuIG1vKGUpP0h0KGpvKGUpKTpmdW5jdGlvbihlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIFNpKHQsZSl9fShlKX12YXIgZGM9Tm4oKSxwYz1ObighMCk7ZnVuY3Rpb24gdmMoKXtyZXR1cm5bXX1mdW5jdGlvbiBnYygpe3JldHVybiExfXZhciB5YyxtYz1XbigoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSt0fSksMCksYmM9Vm4oImNlaWwiKSxTYz1XbigoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS90fSksMSksQ2M9Vm4oImZsb29yIiksd2M9V24oKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUqdH0pLDEpLExjPVZuKCJyb3VuZCIpLEVjPVduKChmdW5jdGlvbihlLHQpe3JldHVybiBlLXR9KSwwKTtyZXR1cm4ganIuYWZ0ZXI9ZnVuY3Rpb24oZSx0KXtpZigiZnVuY3Rpb24iIT10eXBlb2YgdCl0aHJvdyBuZXcgQWUobyk7cmV0dXJuIGU9cGEoZSksZnVuY3Rpb24oKXtpZigtLWU8MSlyZXR1cm4gdC5hcHBseSh0aGlzLGFyZ3VtZW50cyl9fSxqci5hcnk9a3MsanIuYXNzaWduPWJhLGpyLmFzc2lnbkluPVNhLGpyLmFzc2lnbkluV2l0aD1DYSxqci5hc3NpZ25XaXRoPXdhLGpyLmF0PUxhLGpyLmJlZm9yZT1Ncyxqci5iaW5kPVJzLGpyLmJpbmRBbGw9ZWMsanIuYmluZEtleT1Ucyxqci5jYXN0QXJyYXk9ZnVuY3Rpb24oKXtpZighYXJndW1lbnRzLmxlbmd0aClyZXR1cm5bXTt2YXIgZT1hcmd1bWVudHNbMF07cmV0dXJuIEtzKGUpP2U6W2VdfSxqci5jaGFpbj1fcyxqci5jaHVuaz1mdW5jdGlvbihlLHQscil7dD0ocj95byhlLHQscik6dD09PW4pPzE6dnIocGEodCksMCk7dmFyIG89bnVsbD09ZT8wOmUubGVuZ3RoO2lmKCFvfHx0PDEpcmV0dXJuW107Zm9yKHZhciBzPTAsYT0wLGM9aShscihvL3QpKTtzPG87KWNbYSsrXT1lbihlLHMscys9dCk7cmV0dXJuIGN9LGpyLmNvbXBhY3Q9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PS0xLHI9bnVsbD09ZT8wOmUubGVuZ3RoLGk9MCxuPVtdOysrdDxyOyl7dmFyIG89ZVt0XTtvJiYobltpKytdPW8pfXJldHVybiBufSxqci5jb25jYXQ9ZnVuY3Rpb24oKXt2YXIgZT1hcmd1bWVudHMubGVuZ3RoO2lmKCFlKXJldHVybltdO2Zvcih2YXIgdD1pKGUtMSkscj1hcmd1bWVudHNbMF0sbj1lO24tLTspdFtuLTFdPWFyZ3VtZW50c1tuXTtyZXR1cm4geHQoS3Mocik/QW4ocik6W3JdLHBpKHQsMSkpfSxqci5jb25kPWZ1bmN0aW9uKGUpe3ZhciB0PW51bGw9PWU/MDplLmxlbmd0aCxyPXNvKCk7cmV0dXJuIGU9dD9FdChlLChmdW5jdGlvbihlKXtpZigiZnVuY3Rpb24iIT10eXBlb2YgZVsxXSl0aHJvdyBuZXcgQWUobyk7cmV0dXJuW3IoZVswXSksZVsxXV19KSk6W10sR2koKGZ1bmN0aW9uKHIpe2Zvcih2YXIgaT0tMTsrK2k8dDspe3ZhciBuPWVbaV07aWYoZ3QoblswXSx0aGlzLHIpKXJldHVybiBndChuWzFdLHRoaXMscil9fSkpfSxqci5jb25mb3Jtcz1mdW5jdGlvbihlKXtyZXR1cm4gZnVuY3Rpb24oZSl7dmFyIHQ9T2EoZSk7cmV0dXJuIGZ1bmN0aW9uKHIpe3JldHVybiBhaShyLGUsdCl9fShzaShlLDEpKX0sanIuY29uc3RhbnQ9dGMsanIuY291bnRCeT12cyxqci5jcmVhdGU9ZnVuY3Rpb24oZSx0KXt2YXIgcj1GcihlKTtyZXR1cm4gbnVsbD09dD9yOnJpKHIsdCl9LGpyLmN1cnJ5PWZ1bmN0aW9uIGUodCxyLGkpe3ZhciBvPVhuKHQsOCxuLG4sbixuLG4scj1pP246cik7cmV0dXJuIG8ucGxhY2Vob2xkZXI9ZS5wbGFjZWhvbGRlcixvfSxqci5jdXJyeVJpZ2h0PWZ1bmN0aW9uIGUodCxyLGkpe3ZhciBvPVhuKHQsMTYsbixuLG4sbixuLHI9aT9uOnIpO3JldHVybiBvLnBsYWNlaG9sZGVyPWUucGxhY2Vob2xkZXIsb30sanIuZGVib3VuY2U9T3MsanIuZGVmYXVsdHM9RWEsanIuZGVmYXVsdHNEZWVwPXhhLGpyLmRlZmVyPUJzLGpyLmRlbGF5PURzLGpyLmRpZmZlcmVuY2U9VW8sanIuZGlmZmVyZW5jZUJ5PXFvLGpyLmRpZmZlcmVuY2VXaXRoPU5vLGpyLmRyb3A9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPW51bGw9PWU/MDplLmxlbmd0aDtyZXR1cm4gaT9lbihlLCh0PXJ8fHQ9PT1uPzE6cGEodCkpPDA/MDp0LGkpOltdfSxqci5kcm9wUmlnaHQ9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPW51bGw9PWU/MDplLmxlbmd0aDtyZXR1cm4gaT9lbihlLDAsKHQ9aS0odD1yfHx0PT09bj8xOnBhKHQpKSk8MD8wOnQpOltdfSxqci5kcm9wUmlnaHRXaGlsZT1mdW5jdGlvbihlLHQpe3JldHVybiBlJiZlLmxlbmd0aD9obihlLHNvKHQsMyksITAsITApOltdfSxqci5kcm9wV2hpbGU9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGg/aG4oZSxzbyh0LDMpLCEwKTpbXX0sanIuZmlsbD1mdW5jdGlvbihlLHQscixpKXt2YXIgbz1udWxsPT1lPzA6ZS5sZW5ndGg7cmV0dXJuIG8/KHImJiJudW1iZXIiIT10eXBlb2YgciYmeW8oZSx0LHIpJiYocj0wLGk9byksZnVuY3Rpb24oZSx0LHIsaSl7dmFyIG89ZS5sZW5ndGg7Zm9yKChyPXBhKHIpKTwwJiYocj0tcj5vPzA6bytyKSwoaT1pPT09bnx8aT5vP286cGEoaSkpPDAmJihpKz1vKSxpPXI+aT8wOnZhKGkpO3I8aTspZVtyKytdPXQ7cmV0dXJuIGV9KGUsdCxyLGkpKTpbXX0sanIuZmlsdGVyPWZ1bmN0aW9uKGUsdCl7cmV0dXJuKEtzKGUpP0N0OmRpKShlLHNvKHQsMykpfSxqci5mbGF0TWFwPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHBpKExzKGUsdCksMSl9LGpyLmZsYXRNYXBEZWVwPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHBpKExzKGUsdCksdSl9LGpyLmZsYXRNYXBEZXB0aD1mdW5jdGlvbihlLHQscil7cmV0dXJuIHI9cj09PW4/MTpwYShyKSxwaShMcyhlLHQpLHIpfSxqci5mbGF0dGVuPVZvLGpyLmZsYXR0ZW5EZWVwPWZ1bmN0aW9uKGUpe3JldHVybiBudWxsIT1lJiZlLmxlbmd0aD9waShlLHUpOltdfSxqci5mbGF0dGVuRGVwdGg9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gbnVsbCE9ZSYmZS5sZW5ndGg/cGkoZSx0PXQ9PT1uPzE6cGEodCkpOltdfSxqci5mbGlwPWZ1bmN0aW9uKGUpe3JldHVybiBYbihlLDUxMil9LGpyLmZsb3c9cmMsanIuZmxvd1JpZ2h0PWljLGpyLmZyb21QYWlycz1mdW5jdGlvbihlKXtmb3IodmFyIHQ9LTEscj1udWxsPT1lPzA6ZS5sZW5ndGgsaT17fTsrK3Q8cjspe3ZhciBuPWVbdF07aVtuWzBdXT1uWzFdfXJldHVybiBpfSxqci5mdW5jdGlvbnM9ZnVuY3Rpb24oZSl7cmV0dXJuIG51bGw9PWU/W106YmkoZSxPYShlKSl9LGpyLmZ1bmN0aW9uc0luPWZ1bmN0aW9uKGUpe3JldHVybiBudWxsPT1lP1tdOmJpKGUsQmEoZSkpfSxqci5ncm91cEJ5PVNzLGpyLmluaXRpYWw9ZnVuY3Rpb24oZSl7cmV0dXJuIG51bGwhPWUmJmUubGVuZ3RoP2VuKGUsMCwtMSk6W119LGpyLmludGVyc2VjdGlvbj1Zbyxqci5pbnRlcnNlY3Rpb25CeT1Ybyxqci5pbnRlcnNlY3Rpb25XaXRoPVpvLGpyLmludmVydD1NYSxqci5pbnZlcnRCeT1SYSxqci5pbnZva2VNYXA9Q3MsanIuaXRlcmF0ZWU9b2MsanIua2V5Qnk9d3MsanIua2V5cz1PYSxqci5rZXlzSW49QmEsanIubWFwPUxzLGpyLm1hcEtleXM9ZnVuY3Rpb24oZSx0KXt2YXIgcj17fTtyZXR1cm4gdD1zbyh0LDMpLHlpKGUsKGZ1bmN0aW9uKGUsaSxuKXtpaShyLHQoZSxpLG4pLGUpfSkpLHJ9LGpyLm1hcFZhbHVlcz1mdW5jdGlvbihlLHQpe3ZhciByPXt9O3JldHVybiB0PXNvKHQsMykseWkoZSwoZnVuY3Rpb24oZSxpLG4pe2lpKHIsaSx0KGUsaSxuKSl9KSkscn0sanIubWF0Y2hlcz1mdW5jdGlvbihlKXtyZXR1cm4gSGkoc2koZSwxKSl9LGpyLm1hdGNoZXNQcm9wZXJ0eT1mdW5jdGlvbihlLHQpe3JldHVybiBqaShlLHNpKHQsMSkpfSxqci5tZW1vaXplPVBzLGpyLm1lcmdlPURhLGpyLm1lcmdlV2l0aD1QYSxqci5tZXRob2Q9c2MsanIubWV0aG9kT2Y9YWMsanIubWl4aW49Y2MsanIubmVnYXRlPUlzLGpyLm50aEFyZz1mdW5jdGlvbihlKXtyZXR1cm4gZT1wYShlKSxHaSgoZnVuY3Rpb24odCl7cmV0dXJuIFdpKHQsZSl9KSl9LGpyLm9taXQ9SWEsanIub21pdEJ5PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGphKGUsSXMoc28odCkpKX0sanIub25jZT1mdW5jdGlvbihlKXtyZXR1cm4gTXMoMixlKX0sanIub3JkZXJCeT1mdW5jdGlvbihlLHQscixpKXtyZXR1cm4gbnVsbD09ZT9bXTooS3ModCl8fCh0PW51bGw9PXQ/W106W3RdKSxLcyhyPWk/bjpyKXx8KHI9bnVsbD09cj9bXTpbcl0pLFVpKGUsdCxyKSl9LGpyLm92ZXI9dWMsanIub3ZlckFyZ3M9SHMsanIub3ZlckV2ZXJ5PWhjLGpyLm92ZXJTb21lPWZjLGpyLnBhcnRpYWw9anMsanIucGFydGlhbFJpZ2h0PUZzLGpyLnBhcnRpdGlvbj1Fcyxqci5waWNrPUhhLGpyLnBpY2tCeT1qYSxqci5wcm9wZXJ0eT1fYyxqci5wcm9wZXJ0eU9mPWZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gbnVsbD09ZT9uOlNpKGUsdCl9fSxqci5wdWxsPSRvLGpyLnB1bGxBbGw9UW8sanIucHVsbEFsbEJ5PWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gZSYmZS5sZW5ndGgmJnQmJnQubGVuZ3RoP05pKGUsdCxzbyhyLDIpKTplfSxqci5wdWxsQWxsV2l0aD1mdW5jdGlvbihlLHQscil7cmV0dXJuIGUmJmUubGVuZ3RoJiZ0JiZ0Lmxlbmd0aD9OaShlLHQsbixyKTplfSxqci5wdWxsQXQ9ZXMsanIucmFuZ2U9ZGMsanIucmFuZ2VSaWdodD1wYyxqci5yZWFyZz1Xcyxqci5yZWplY3Q9ZnVuY3Rpb24oZSx0KXtyZXR1cm4oS3MoZSk/Q3Q6ZGkpKGUsSXMoc28odCwzKSkpfSxqci5yZW1vdmU9ZnVuY3Rpb24oZSx0KXt2YXIgcj1bXTtpZighZXx8IWUubGVuZ3RoKXJldHVybiByO3ZhciBpPS0xLG49W10sbz1lLmxlbmd0aDtmb3IodD1zbyh0LDMpOysraTxvOyl7dmFyIHM9ZVtpXTt0KHMsaSxlKSYmKHIucHVzaChzKSxuLnB1c2goaSkpfXJldHVybiB6aShlLG4pLHJ9LGpyLnJlc3Q9ZnVuY3Rpb24oZSx0KXtpZigiZnVuY3Rpb24iIT10eXBlb2YgZSl0aHJvdyBuZXcgQWUobyk7cmV0dXJuIEdpKGUsdD10PT09bj90OnBhKHQpKX0sanIucmV2ZXJzZT10cyxqci5zYW1wbGVTaXplPWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gdD0ocj95byhlLHQscik6dD09PW4pPzE6cGEodCksKEtzKGUpP1pyOlhpKShlLHQpfSxqci5zZXQ9ZnVuY3Rpb24oZSx0LHIpe3JldHVybiBudWxsPT1lP2U6WmkoZSx0LHIpfSxqci5zZXRXaXRoPWZ1bmN0aW9uKGUsdCxyLGkpe3JldHVybiBpPSJmdW5jdGlvbiI9PXR5cGVvZiBpP2k6bixudWxsPT1lP2U6WmkoZSx0LHIsaSl9LGpyLnNodWZmbGU9ZnVuY3Rpb24oZSl7cmV0dXJuKEtzKGUpP0pyOlFpKShlKX0sanIuc2xpY2U9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPW51bGw9PWU/MDplLmxlbmd0aDtyZXR1cm4gaT8ociYmIm51bWJlciIhPXR5cGVvZiByJiZ5byhlLHQscik/KHQ9MCxyPWkpOih0PW51bGw9PXQ/MDpwYSh0KSxyPXI9PT1uP2k6cGEocikpLGVuKGUsdCxyKSk6W119LGpyLnNvcnRCeT14cyxqci5zb3J0ZWRVbmlxPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLmxlbmd0aD9vbihlKTpbXX0sanIuc29ydGVkVW5pcUJ5PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUmJmUubGVuZ3RoP29uKGUsc28odCwyKSk6W119LGpyLnNwbGl0PWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gciYmIm51bWJlciIhPXR5cGVvZiByJiZ5byhlLHQscikmJih0PXI9biksKHI9cj09PW4/XzpyPj4+MCk/KGU9bWEoZSkpJiYoInN0cmluZyI9PXR5cGVvZiB0fHxudWxsIT10JiYhc2EodCkpJiYhKHQ9YW4odCkpJiYkdChlKT9tbihvcihlKSwwLHIpOmUuc3BsaXQodCxyKTpbXX0sanIuc3ByZWFkPWZ1bmN0aW9uKGUsdCl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIGUpdGhyb3cgbmV3IEFlKG8pO3JldHVybiB0PW51bGw9PXQ/MDp2cihwYSh0KSwwKSxHaSgoZnVuY3Rpb24ocil7dmFyIGk9clt0XSxuPW1uKHIsMCx0KTtyZXR1cm4gaSYmeHQobixpKSxndChlLHRoaXMsbil9KSl9LGpyLnRhaWw9ZnVuY3Rpb24oZSl7dmFyIHQ9bnVsbD09ZT8wOmUubGVuZ3RoO3JldHVybiB0P2VuKGUsMSx0KTpbXX0sanIudGFrZT1mdW5jdGlvbihlLHQscil7cmV0dXJuIGUmJmUubGVuZ3RoP2VuKGUsMCwodD1yfHx0PT09bj8xOnBhKHQpKTwwPzA6dCk6W119LGpyLnRha2VSaWdodD1mdW5jdGlvbihlLHQscil7dmFyIGk9bnVsbD09ZT8wOmUubGVuZ3RoO3JldHVybiBpP2VuKGUsKHQ9aS0odD1yfHx0PT09bj8xOnBhKHQpKSk8MD8wOnQsaSk6W119LGpyLnRha2VSaWdodFdoaWxlPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUmJmUubGVuZ3RoP2huKGUsc28odCwzKSwhMSwhMCk6W119LGpyLnRha2VXaGlsZT1mdW5jdGlvbihlLHQpe3JldHVybiBlJiZlLmxlbmd0aD9obihlLHNvKHQsMykpOltdfSxqci50YXA9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdChlKSxlfSxqci50aHJvdHRsZT1mdW5jdGlvbihlLHQscil7dmFyIGk9ITAsbj0hMDtpZigiZnVuY3Rpb24iIT10eXBlb2YgZSl0aHJvdyBuZXcgQWUobyk7cmV0dXJuIHRhKHIpJiYoaT0ibGVhZGluZyJpbiByPyEhci5sZWFkaW5nOmksbj0idHJhaWxpbmciaW4gcj8hIXIudHJhaWxpbmc6biksT3MoZSx0LHtsZWFkaW5nOmksbWF4V2FpdDp0LHRyYWlsaW5nOm59KX0sanIudGhydT1kcyxqci50b0FycmF5PV9hLGpyLnRvUGFpcnM9RmEsanIudG9QYWlyc0luPVdhLGpyLnRvUGF0aD1mdW5jdGlvbihlKXtyZXR1cm4gS3MoZSk/RXQoZSxqbyk6bGEoZSk/W2VdOkFuKEhvKG1hKGUpKSl9LGpyLnRvUGxhaW5PYmplY3Q9eWEsanIudHJhbnNmb3JtPWZ1bmN0aW9uKGUsdCxyKXt2YXIgaT1LcyhlKSxuPWl8fFhzKGUpfHx1YShlKTtpZih0PXNvKHQsNCksbnVsbD09cil7dmFyIG89ZSYmZS5jb25zdHJ1Y3RvcjtyPW4/aT9uZXcgbzpbXTp0YShlKSYmJHMobyk/RnIoVmUoZSkpOnt9fXJldHVybihuP210OnlpKShlLChmdW5jdGlvbihlLGksbil7cmV0dXJuIHQocixlLGksbil9KSkscn0sanIudW5hcnk9ZnVuY3Rpb24oZSl7cmV0dXJuIGtzKGUsMSl9LGpyLnVuaW9uPXJzLGpyLnVuaW9uQnk9aXMsanIudW5pb25XaXRoPW5zLGpyLnVuaXE9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUubGVuZ3RoP2NuKGUpOltdfSxqci51bmlxQnk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGg/Y24oZSxzbyh0LDIpKTpbXX0sanIudW5pcVdpdGg9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdD0iZnVuY3Rpb24iPT10eXBlb2YgdD90Om4sZSYmZS5sZW5ndGg/Y24oZSxuLHQpOltdfSxqci51bnNldD1mdW5jdGlvbihlLHQpe3JldHVybiBudWxsPT1lfHxsbihlLHQpfSxqci51bnppcD1vcyxqci51bnppcFdpdGg9c3MsanIudXBkYXRlPWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gbnVsbD09ZT9lOnVuKGUsdCx2bihyKSl9LGpyLnVwZGF0ZVdpdGg9ZnVuY3Rpb24oZSx0LHIsaSl7cmV0dXJuIGk9ImZ1bmN0aW9uIj09dHlwZW9mIGk/aTpuLG51bGw9PWU/ZTp1bihlLHQsdm4ociksaSl9LGpyLnZhbHVlcz1VYSxqci52YWx1ZXNJbj1mdW5jdGlvbihlKXtyZXR1cm4gbnVsbD09ZT9bXTp6dChlLEJhKGUpKX0sanIud2l0aG91dD1hcyxqci53b3Jkcz0kYSxqci53cmFwPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGpzKHZuKHQpLGUpfSxqci54b3I9Y3MsanIueG9yQnk9bHMsanIueG9yV2l0aD11cyxqci56aXA9aHMsanIuemlwT2JqZWN0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGRuKGV8fFtdLHR8fFtdLFFyKX0sanIuemlwT2JqZWN0RGVlcD1mdW5jdGlvbihlLHQpe3JldHVybiBkbihlfHxbXSx0fHxbXSxaaSl9LGpyLnppcFdpdGg9ZnMsanIuZW50cmllcz1GYSxqci5lbnRyaWVzSW49V2EsanIuZXh0ZW5kPVNhLGpyLmV4dGVuZFdpdGg9Q2EsY2MoanIsanIpLGpyLmFkZD1tYyxqci5hdHRlbXB0PVFhLGpyLmNhbWVsQ2FzZT1xYSxqci5jYXBpdGFsaXplPU5hLGpyLmNlaWw9YmMsanIuY2xhbXA9ZnVuY3Rpb24oZSx0LHIpe3JldHVybiByPT09biYmKHI9dCx0PW4pLHIhPT1uJiYocj0ocj1nYShyKSk9PXI/cjowKSx0IT09biYmKHQ9KHQ9Z2EodCkpPT10P3Q6MCksb2koZ2EoZSksdCxyKX0sanIuY2xvbmU9ZnVuY3Rpb24oZSl7cmV0dXJuIHNpKGUsNCl9LGpyLmNsb25lRGVlcD1mdW5jdGlvbihlKXtyZXR1cm4gc2koZSw1KX0sanIuY2xvbmVEZWVwV2l0aD1mdW5jdGlvbihlLHQpe3JldHVybiBzaShlLDUsdD0iZnVuY3Rpb24iPT10eXBlb2YgdD90Om4pfSxqci5jbG9uZVdpdGg9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gc2koZSw0LHQ9ImZ1bmN0aW9uIj09dHlwZW9mIHQ/dDpuKX0sanIuY29uZm9ybXNUbz1mdW5jdGlvbihlLHQpe3JldHVybiBudWxsPT10fHxhaShlLHQsT2EodCkpfSxqci5kZWJ1cnI9emEsanIuZGVmYXVsdFRvPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIG51bGw9PWV8fGUhPWU/dDplfSxqci5kaXZpZGU9U2MsanIuZW5kc1dpdGg9ZnVuY3Rpb24oZSx0LHIpe2U9bWEoZSksdD1hbih0KTt2YXIgaT1lLmxlbmd0aCxvPXI9cj09PW4/aTpvaShwYShyKSwwLGkpO3JldHVybihyLT10Lmxlbmd0aCk+PTAmJmUuc2xpY2UocixvKT09dH0sanIuZXE9VXMsanIuZXNjYXBlPWZ1bmN0aW9uKGUpe3JldHVybihlPW1hKGUpKSYmWS50ZXN0KGUpP2UucmVwbGFjZShWLFp0KTplfSxqci5lc2NhcGVSZWdFeHA9ZnVuY3Rpb24oZSl7cmV0dXJuKGU9bWEoZSkpJiZyZS50ZXN0KGUpP2UucmVwbGFjZSh0ZSwiXFwkJiIpOmV9LGpyLmV2ZXJ5PWZ1bmN0aW9uKGUsdCxyKXt2YXIgaT1LcyhlKT9TdDpmaTtyZXR1cm4gciYmeW8oZSx0LHIpJiYodD1uKSxpKGUsc28odCwzKSl9LGpyLmZpbmQ9Z3MsanIuZmluZEluZGV4PXpvLGpyLmZpbmRLZXk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gVHQoZSxzbyh0LDMpLHlpKX0sanIuZmluZExhc3Q9eXMsanIuZmluZExhc3RJbmRleD1Lbyxqci5maW5kTGFzdEtleT1mdW5jdGlvbihlLHQpe3JldHVybiBUdChlLHNvKHQsMyksbWkpfSxqci5mbG9vcj1DYyxqci5mb3JFYWNoPW1zLGpyLmZvckVhY2hSaWdodD1icyxqci5mb3JJbj1mdW5jdGlvbihlLHQpe3JldHVybiBudWxsPT1lP2U6dmkoZSxzbyh0LDMpLEJhKX0sanIuZm9ySW5SaWdodD1mdW5jdGlvbihlLHQpe3JldHVybiBudWxsPT1lP2U6Z2koZSxzbyh0LDMpLEJhKX0sanIuZm9yT3duPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUmJnlpKGUsc28odCwzKSl9LGpyLmZvck93blJpZ2h0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUmJm1pKGUsc28odCwzKSl9LGpyLmdldD1BYSxqci5ndD1xcyxqci5ndGU9TnMsanIuaGFzPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIG51bGwhPWUmJl9vKGUsdCxFaSl9LGpyLmhhc0luPWthLGpyLmhlYWQ9R28sanIuaWRlbnRpdHk9bmMsanIuaW5jbHVkZXM9ZnVuY3Rpb24oZSx0LHIsaSl7ZT1HcyhlKT9lOlVhKGUpLHI9ciYmIWk/cGEocik6MDt2YXIgbj1lLmxlbmd0aDtyZXR1cm4gcjwwJiYocj12cihuK3IsMCkpLGNhKGUpP3I8PW4mJmUuaW5kZXhPZih0LHIpPi0xOiEhbiYmQnQoZSx0LHIpPi0xfSxqci5pbmRleE9mPWZ1bmN0aW9uKGUsdCxyKXt2YXIgaT1udWxsPT1lPzA6ZS5sZW5ndGg7aWYoIWkpcmV0dXJuLTE7dmFyIG49bnVsbD09cj8wOnBhKHIpO3JldHVybiBuPDAmJihuPXZyKGkrbiwwKSksQnQoZSx0LG4pfSxqci5pblJhbmdlPWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gdD1kYSh0KSxyPT09bj8ocj10LHQ9MCk6cj1kYShyKSxmdW5jdGlvbihlLHQscil7cmV0dXJuIGU+PWdyKHQscikmJmU8dnIodCxyKX0oZT1nYShlKSx0LHIpfSxqci5pbnZva2U9VGEsanIuaXNBcmd1bWVudHM9enMsanIuaXNBcnJheT1Lcyxqci5pc0FycmF5QnVmZmVyPVZzLGpyLmlzQXJyYXlMaWtlPUdzLGpyLmlzQXJyYXlMaWtlT2JqZWN0PVlzLGpyLmlzQm9vbGVhbj1mdW5jdGlvbihlKXtyZXR1cm4hMD09PWV8fCExPT09ZXx8cmEoZSkmJndpKGUpPT1nfSxqci5pc0J1ZmZlcj1Ycyxqci5pc0RhdGU9WnMsanIuaXNFbGVtZW50PWZ1bmN0aW9uKGUpe3JldHVybiByYShlKSYmMT09PWUubm9kZVR5cGUmJiFvYShlKX0sanIuaXNFbXB0eT1mdW5jdGlvbihlKXtpZihudWxsPT1lKXJldHVybiEwO2lmKEdzKGUpJiYoS3MoZSl8fCJzdHJpbmciPT10eXBlb2YgZXx8ImZ1bmN0aW9uIj09dHlwZW9mIGUuc3BsaWNlfHxYcyhlKXx8dWEoZSl8fHpzKGUpKSlyZXR1cm4hZS5sZW5ndGg7dmFyIHQ9Zm8oZSk7aWYodD09Q3x8dD09QSlyZXR1cm4hZS5zaXplO2lmKENvKGUpKXJldHVybiFEaShlKS5sZW5ndGg7Zm9yKHZhciByIGluIGUpaWYoQmUuY2FsbChlLHIpKXJldHVybiExO3JldHVybiEwfSxqci5pc0VxdWFsPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIFJpKGUsdCl9LGpyLmlzRXF1YWxXaXRoPWZ1bmN0aW9uKGUsdCxyKXt2YXIgaT0ocj0iZnVuY3Rpb24iPT10eXBlb2Ygcj9yOm4pP3IoZSx0KTpuO3JldHVybiBpPT09bj9SaShlLHQsbixyKTohIWl9LGpyLmlzRXJyb3I9SnMsanIuaXNGaW5pdGU9ZnVuY3Rpb24oZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlJiZfcihlKX0sanIuaXNGdW5jdGlvbj0kcyxqci5pc0ludGVnZXI9UXMsanIuaXNMZW5ndGg9ZWEsanIuaXNNYXA9aWEsanIuaXNNYXRjaD1mdW5jdGlvbihlLHQpe3JldHVybiBlPT09dHx8VGkoZSx0LGNvKHQpKX0sanIuaXNNYXRjaFdpdGg9ZnVuY3Rpb24oZSx0LHIpe3JldHVybiByPSJmdW5jdGlvbiI9PXR5cGVvZiByP3I6bixUaShlLHQsY28odCkscil9LGpyLmlzTmFOPWZ1bmN0aW9uKGUpe3JldHVybiBuYShlKSYmZSE9K2V9LGpyLmlzTmF0aXZlPWZ1bmN0aW9uKGUpe2lmKFNvKGUpKXRocm93IG5ldyBTZSgiVW5zdXBwb3J0ZWQgY29yZS1qcyB1c2UuIFRyeSBodHRwczovL25wbXMuaW8vc2VhcmNoP3E9cG9ueWZpbGwuIik7cmV0dXJuIE9pKGUpfSxqci5pc05pbD1mdW5jdGlvbihlKXtyZXR1cm4gbnVsbD09ZX0sanIuaXNOdWxsPWZ1bmN0aW9uKGUpe3JldHVybiBudWxsPT09ZX0sanIuaXNOdW1iZXI9bmEsanIuaXNPYmplY3Q9dGEsanIuaXNPYmplY3RMaWtlPXJhLGpyLmlzUGxhaW5PYmplY3Q9b2EsanIuaXNSZWdFeHA9c2EsanIuaXNTYWZlSW50ZWdlcj1mdW5jdGlvbihlKXtyZXR1cm4gUXMoZSkmJmU+PS05MDA3MTk5MjU0NzQwOTkxJiZlPD1ofSxqci5pc1NldD1hYSxqci5pc1N0cmluZz1jYSxqci5pc1N5bWJvbD1sYSxqci5pc1R5cGVkQXJyYXk9dWEsanIuaXNVbmRlZmluZWQ9ZnVuY3Rpb24oZSl7cmV0dXJuIGU9PT1ufSxqci5pc1dlYWtNYXA9ZnVuY3Rpb24oZSl7cmV0dXJuIHJhKGUpJiZmbyhlKT09Un0sanIuaXNXZWFrU2V0PWZ1bmN0aW9uKGUpe3JldHVybiByYShlKSYmIltvYmplY3QgV2Vha1NldF0iPT13aShlKX0sanIuam9pbj1mdW5jdGlvbihlLHQpe3JldHVybiBudWxsPT1lPyIiOmRyLmNhbGwoZSx0KX0sanIua2ViYWJDYXNlPUthLGpyLmxhc3Q9Sm8sanIubGFzdEluZGV4T2Y9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPW51bGw9PWU/MDplLmxlbmd0aDtpZighaSlyZXR1cm4tMTt2YXIgbz1pO3JldHVybiByIT09biYmKG89KG89cGEocikpPDA/dnIoaStvLDApOmdyKG8saS0xKSksdD09dD9mdW5jdGlvbihlLHQscil7Zm9yKHZhciBpPXIrMTtpLS07KWlmKGVbaV09PT10KXJldHVybiBpO3JldHVybiBpfShlLHQsbyk6T3QoZSxQdCxvLCEwKX0sanIubG93ZXJDYXNlPVZhLGpyLmxvd2VyRmlyc3Q9R2EsanIubHQ9aGEsanIubHRlPWZhLGpyLm1heD1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5sZW5ndGg/X2koZSxuYyxMaSk6bn0sanIubWF4Qnk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGg/X2koZSxzbyh0LDIpLExpKTpufSxqci5tZWFuPWZ1bmN0aW9uKGUpe3JldHVybiBJdChlLG5jKX0sanIubWVhbkJ5PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIEl0KGUsc28odCwyKSl9LGpyLm1pbj1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5sZW5ndGg/X2koZSxuYyxQaSk6bn0sanIubWluQnk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGg/X2koZSxzbyh0LDIpLFBpKTpufSxqci5zdHViQXJyYXk9dmMsanIuc3R1YkZhbHNlPWdjLGpyLnN0dWJPYmplY3Q9ZnVuY3Rpb24oKXtyZXR1cm57fX0sanIuc3R1YlN0cmluZz1mdW5jdGlvbigpe3JldHVybiIifSxqci5zdHViVHJ1ZT1mdW5jdGlvbigpe3JldHVybiEwfSxqci5tdWx0aXBseT13Yyxqci5udGg9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGg/V2koZSxwYSh0KSk6bn0sanIubm9Db25mbGljdD1mdW5jdGlvbigpe3JldHVybiBvdC5fPT09dGhpcyYmKG90Ll89amUpLHRoaXN9LGpyLm5vb3A9bGMsanIubm93PUFzLGpyLnBhZD1mdW5jdGlvbihlLHQscil7ZT1tYShlKTt2YXIgaT0odD1wYSh0KSk/bnIoZSk6MDtpZighdHx8aT49dClyZXR1cm4gZTt2YXIgbj0odC1pKS8yO3JldHVybiBxbih1cihuKSxyKStlK3FuKGxyKG4pLHIpfSxqci5wYWRFbmQ9ZnVuY3Rpb24oZSx0LHIpe2U9bWEoZSk7dmFyIGk9KHQ9cGEodCkpP25yKGUpOjA7cmV0dXJuIHQmJmk8dD9lK3FuKHQtaSxyKTplfSxqci5wYWRTdGFydD1mdW5jdGlvbihlLHQscil7ZT1tYShlKTt2YXIgaT0odD1wYSh0KSk/bnIoZSk6MDtyZXR1cm4gdCYmaTx0P3FuKHQtaSxyKStlOmV9LGpyLnBhcnNlSW50PWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gcnx8bnVsbD09dD90PTA6dCYmKHQ9K3QpLG1yKG1hKGUpLnJlcGxhY2UoaWUsIiIpLHR8fDApfSxqci5yYW5kb209ZnVuY3Rpb24oZSx0LHIpe2lmKHImJiJib29sZWFuIiE9dHlwZW9mIHImJnlvKGUsdCxyKSYmKHQ9cj1uKSxyPT09biYmKCJib29sZWFuIj09dHlwZW9mIHQ/KHI9dCx0PW4pOiJib29sZWFuIj09dHlwZW9mIGUmJihyPWUsZT1uKSksZT09PW4mJnQ9PT1uPyhlPTAsdD0xKTooZT1kYShlKSx0PT09bj8odD1lLGU9MCk6dD1kYSh0KSksZT50KXt2YXIgaT1lO2U9dCx0PWl9aWYocnx8ZSUxfHx0JTEpe3ZhciBvPWJyKCk7cmV0dXJuIGdyKGUrbyoodC1lK3R0KCIxZS0iKygobysiIikubGVuZ3RoLTEpKSksdCl9cmV0dXJuIEtpKGUsdCl9LGpyLnJlZHVjZT1mdW5jdGlvbihlLHQscil7dmFyIGk9S3MoZSk/QXQ6RnQsbj1hcmd1bWVudHMubGVuZ3RoPDM7cmV0dXJuIGkoZSxzbyh0LDQpLHIsbix1aSl9LGpyLnJlZHVjZVJpZ2h0PWZ1bmN0aW9uKGUsdCxyKXt2YXIgaT1LcyhlKT9rdDpGdCxuPWFyZ3VtZW50cy5sZW5ndGg8MztyZXR1cm4gaShlLHNvKHQsNCkscixuLGhpKX0sanIucmVwZWF0PWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gdD0ocj95byhlLHQscik6dD09PW4pPzE6cGEodCksVmkobWEoZSksdCl9LGpyLnJlcGxhY2U9ZnVuY3Rpb24oKXt2YXIgZT1hcmd1bWVudHMsdD1tYShlWzBdKTtyZXR1cm4gZS5sZW5ndGg8Mz90OnQucmVwbGFjZShlWzFdLGVbMl0pfSxqci5yZXN1bHQ9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPS0xLG89KHQ9Z24odCxlKSkubGVuZ3RoO2ZvcihvfHwobz0xLGU9bik7KytpPG87KXt2YXIgcz1udWxsPT1lP246ZVtqbyh0W2ldKV07cz09PW4mJihpPW8scz1yKSxlPSRzKHMpP3MuY2FsbChlKTpzfXJldHVybiBlfSxqci5yb3VuZD1MYyxqci5ydW5JbkNvbnRleHQ9ZSxqci5zYW1wbGU9ZnVuY3Rpb24oZSl7cmV0dXJuKEtzKGUpP1hyOllpKShlKX0sanIuc2l6ZT1mdW5jdGlvbihlKXtpZihudWxsPT1lKXJldHVybiAwO2lmKEdzKGUpKXJldHVybiBjYShlKT9ucihlKTplLmxlbmd0aDt2YXIgdD1mbyhlKTtyZXR1cm4gdD09Q3x8dD09QT9lLnNpemU6RGkoZSkubGVuZ3RofSxqci5zbmFrZUNhc2U9WWEsanIuc29tZT1mdW5jdGlvbihlLHQscil7dmFyIGk9S3MoZSk/TXQ6dG47cmV0dXJuIHImJnlvKGUsdCxyKSYmKHQ9biksaShlLHNvKHQsMykpfSxqci5zb3J0ZWRJbmRleD1mdW5jdGlvbihlLHQpe3JldHVybiBybihlLHQpfSxqci5zb3J0ZWRJbmRleEJ5PWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gbm4oZSx0LHNvKHIsMikpfSxqci5zb3J0ZWRJbmRleE9mPWZ1bmN0aW9uKGUsdCl7dmFyIHI9bnVsbD09ZT8wOmUubGVuZ3RoO2lmKHIpe3ZhciBpPXJuKGUsdCk7aWYoaTxyJiZVcyhlW2ldLHQpKXJldHVybiBpfXJldHVybi0xfSxqci5zb3J0ZWRMYXN0SW5kZXg9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gcm4oZSx0LCEwKX0sanIuc29ydGVkTGFzdEluZGV4Qnk9ZnVuY3Rpb24oZSx0LHIpe3JldHVybiBubihlLHQsc28ociwyKSwhMCl9LGpyLnNvcnRlZExhc3RJbmRleE9mPWZ1bmN0aW9uKGUsdCl7aWYobnVsbCE9ZSYmZS5sZW5ndGgpe3ZhciByPXJuKGUsdCwhMCktMTtpZihVcyhlW3JdLHQpKXJldHVybiByfXJldHVybi0xfSxqci5zdGFydENhc2U9WGEsanIuc3RhcnRzV2l0aD1mdW5jdGlvbihlLHQscil7cmV0dXJuIGU9bWEoZSkscj1udWxsPT1yPzA6b2kocGEociksMCxlLmxlbmd0aCksdD1hbih0KSxlLnNsaWNlKHIscit0Lmxlbmd0aCk9PXR9LGpyLnN1YnRyYWN0PUVjLGpyLnN1bT1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5sZW5ndGg/V3QoZSxuYyk6MH0sanIuc3VtQnk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGg/V3QoZSxzbyh0LDIpKTowfSxqci50ZW1wbGF0ZT1mdW5jdGlvbihlLHQscil7dmFyIGk9anIudGVtcGxhdGVTZXR0aW5ncztyJiZ5byhlLHQscikmJih0PW4pLGU9bWEoZSksdD1DYSh7fSx0LGksWm4pO3ZhciBvLHMsYT1DYSh7fSx0LmltcG9ydHMsaS5pbXBvcnRzLFpuKSxjPU9hKGEpLGw9enQoYSxjKSx1PTAsaD10LmludGVycG9sYXRlfHxtZSxmPSJfX3AgKz0gJyIsXz1FZSgodC5lc2NhcGV8fG1lKS5zb3VyY2UrInwiK2guc291cmNlKyJ8IisoaD09PUo/aGU6bWUpLnNvdXJjZSsifCIrKHQuZXZhbHVhdGV8fG1lKS5zb3VyY2UrInwkIiwiZyIpLGQ9Ii8vIyBzb3VyY2VVUkw9IisoQmUuY2FsbCh0LCJzb3VyY2VVUkwiKT8odC5zb3VyY2VVUkwrIiIpLnJlcGxhY2UoL1xzL2csIiAiKToibG9kYXNoLnRlbXBsYXRlU291cmNlc1siKyArK0plKyJdIikrIlxuIjtlLnJlcGxhY2UoXywoZnVuY3Rpb24odCxyLGksbixhLGMpe3JldHVybiBpfHwoaT1uKSxmKz1lLnNsaWNlKHUsYykucmVwbGFjZShiZSxKdCksciYmKG89ITAsZis9IicgK1xuX19lKCIrcisiKSArXG4nIiksYSYmKHM9ITAsZis9Iic7XG4iK2ErIjtcbl9fcCArPSAnIiksaSYmKGYrPSInICtcbigoX190ID0gKCIraSsiKSkgPT0gbnVsbCA/ICcnIDogX190KSArXG4nIiksdT1jK3QubGVuZ3RoLHR9KSksZis9Iic7XG4iO3ZhciBwPUJlLmNhbGwodCwidmFyaWFibGUiKSYmdC52YXJpYWJsZTtpZihwKXtpZihsZS50ZXN0KHApKXRocm93IG5ldyBTZSgiSW52YWxpZCBgdmFyaWFibGVgIG9wdGlvbiBwYXNzZWQgaW50byBgXy50ZW1wbGF0ZWAiKX1lbHNlIGY9IndpdGggKG9iaikge1xuIitmKyJcbn1cbiI7Zj0ocz9mLnJlcGxhY2UocSwiIik6ZikucmVwbGFjZShOLCIkMSIpLnJlcGxhY2UoeiwiJDE7IiksZj0iZnVuY3Rpb24oIisocHx8Im9iaiIpKyIpIHtcbiIrKHA/IiI6Im9iaiB8fCAob2JqID0ge30pO1xuIikrInZhciBfX3QsIF9fcCA9ICcnIisobz8iLCBfX2UgPSBfLmVzY2FwZSI6IiIpKyhzPyIsIF9faiA9IEFycmF5LnByb3RvdHlwZS5qb2luO1xuZnVuY3Rpb24gcHJpbnQoKSB7IF9fcCArPSBfX2ouY2FsbChhcmd1bWVudHMsICcnKSB9XG4iOiI7XG4iKStmKyJyZXR1cm4gX19wXG59Ijt2YXIgdj1RYSgoZnVuY3Rpb24oKXtyZXR1cm4gQ2UoYyxkKyJyZXR1cm4gIitmKS5hcHBseShuLGwpfSkpO2lmKHYuc291cmNlPWYsSnModikpdGhyb3cgdjtyZXR1cm4gdn0sanIudGltZXM9ZnVuY3Rpb24oZSx0KXtpZigoZT1wYShlKSk8MXx8ZT5oKXJldHVybltdO3ZhciByPV8saT1ncihlLF8pO3Q9c28odCksZS09Xztmb3IodmFyIG49VXQoaSx0KTsrK3I8ZTspdChyKTtyZXR1cm4gbn0sanIudG9GaW5pdGU9ZGEsanIudG9JbnRlZ2VyPXBhLGpyLnRvTGVuZ3RoPXZhLGpyLnRvTG93ZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIG1hKGUpLnRvTG93ZXJDYXNlKCl9LGpyLnRvTnVtYmVyPWdhLGpyLnRvU2FmZUludGVnZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIGU/b2kocGEoZSksLTkwMDcxOTkyNTQ3NDA5OTEsaCk6MD09PWU/ZTowfSxqci50b1N0cmluZz1tYSxqci50b1VwcGVyPWZ1bmN0aW9uKGUpe3JldHVybiBtYShlKS50b1VwcGVyQ2FzZSgpfSxqci50cmltPWZ1bmN0aW9uKGUsdCxyKXtpZigoZT1tYShlKSkmJihyfHx0PT09bikpcmV0dXJuIHF0KGUpO2lmKCFlfHwhKHQ9YW4odCkpKXJldHVybiBlO3ZhciBpPW9yKGUpLG89b3IodCk7cmV0dXJuIG1uKGksVnQoaSxvKSxHdChpLG8pKzEpLmpvaW4oIiIpfSxqci50cmltRW5kPWZ1bmN0aW9uKGUsdCxyKXtpZigoZT1tYShlKSkmJihyfHx0PT09bikpcmV0dXJuIGUuc2xpY2UoMCxzcihlKSsxKTtpZighZXx8ISh0PWFuKHQpKSlyZXR1cm4gZTt2YXIgaT1vcihlKTtyZXR1cm4gbW4oaSwwLEd0KGksb3IodCkpKzEpLmpvaW4oIiIpfSxqci50cmltU3RhcnQ9ZnVuY3Rpb24oZSx0LHIpe2lmKChlPW1hKGUpKSYmKHJ8fHQ9PT1uKSlyZXR1cm4gZS5yZXBsYWNlKGllLCIiKTtpZighZXx8ISh0PWFuKHQpKSlyZXR1cm4gZTt2YXIgaT1vcihlKTtyZXR1cm4gbW4oaSxWdChpLG9yKHQpKSkuam9pbigiIil9LGpyLnRydW5jYXRlPWZ1bmN0aW9uKGUsdCl7dmFyIHI9MzAsaT0iLi4uIjtpZih0YSh0KSl7dmFyIG89InNlcGFyYXRvciJpbiB0P3Quc2VwYXJhdG9yOm87cj0ibGVuZ3RoImluIHQ/cGEodC5sZW5ndGgpOnIsaT0ib21pc3Npb24iaW4gdD9hbih0Lm9taXNzaW9uKTppfXZhciBzPShlPW1hKGUpKS5sZW5ndGg7aWYoJHQoZSkpe3ZhciBhPW9yKGUpO3M9YS5sZW5ndGh9aWYocj49cylyZXR1cm4gZTt2YXIgYz1yLW5yKGkpO2lmKGM8MSlyZXR1cm4gaTt2YXIgbD1hP21uKGEsMCxjKS5qb2luKCIiKTplLnNsaWNlKDAsYyk7aWYobz09PW4pcmV0dXJuIGwraTtpZihhJiYoYys9bC5sZW5ndGgtYyksc2Eobykpe2lmKGUuc2xpY2UoYykuc2VhcmNoKG8pKXt2YXIgdSxoPWw7Zm9yKG8uZ2xvYmFsfHwobz1FZShvLnNvdXJjZSxtYShmZS5leGVjKG8pKSsiZyIpKSxvLmxhc3RJbmRleD0wO3U9by5leGVjKGgpOyl2YXIgZj11LmluZGV4O2w9bC5zbGljZSgwLGY9PT1uP2M6Zil9fWVsc2UgaWYoZS5pbmRleE9mKGFuKG8pLGMpIT1jKXt2YXIgXz1sLmxhc3RJbmRleE9mKG8pO18+LTEmJihsPWwuc2xpY2UoMCxfKSl9cmV0dXJuIGwraX0sanIudW5lc2NhcGU9ZnVuY3Rpb24oZSl7cmV0dXJuKGU9bWEoZSkpJiZHLnRlc3QoZSk/ZS5yZXBsYWNlKEssYXIpOmV9LGpyLnVuaXF1ZUlkPWZ1bmN0aW9uKGUpe3ZhciB0PSsrRGU7cmV0dXJuIG1hKGUpK3R9LGpyLnVwcGVyQ2FzZT1aYSxqci51cHBlckZpcnN0PUphLGpyLmVhY2g9bXMsanIuZWFjaFJpZ2h0PWJzLGpyLmZpcnN0PUdvLGNjKGpyLCh5Yz17fSx5aShqciwoZnVuY3Rpb24oZSx0KXtCZS5jYWxsKGpyLnByb3RvdHlwZSx0KXx8KHljW3RdPWUpfSkpLHljKSx7Y2hhaW46ITF9KSxqci5WRVJTSU9OPSI0LjE3LjIxIixtdChbImJpbmQiLCJiaW5kS2V5IiwiY3VycnkiLCJjdXJyeVJpZ2h0IiwicGFydGlhbCIsInBhcnRpYWxSaWdodCJdLChmdW5jdGlvbihlKXtqcltlXS5wbGFjZWhvbGRlcj1qcn0pKSxtdChbImRyb3AiLCJ0YWtlIl0sKGZ1bmN0aW9uKGUsdCl7cXIucHJvdG90eXBlW2VdPWZ1bmN0aW9uKHIpe3I9cj09PW4/MTp2cihwYShyKSwwKTt2YXIgaT10aGlzLl9fZmlsdGVyZWRfXyYmIXQ/bmV3IHFyKHRoaXMpOnRoaXMuY2xvbmUoKTtyZXR1cm4gaS5fX2ZpbHRlcmVkX18/aS5fX3Rha2VDb3VudF9fPWdyKHIsaS5fX3Rha2VDb3VudF9fKTppLl9fdmlld3NfXy5wdXNoKHtzaXplOmdyKHIsXyksdHlwZTplKyhpLl9fZGlyX188MD8iUmlnaHQiOiIiKX0pLGl9LHFyLnByb3RvdHlwZVtlKyJSaWdodCJdPWZ1bmN0aW9uKHQpe3JldHVybiB0aGlzLnJldmVyc2UoKVtlXSh0KS5yZXZlcnNlKCl9fSkpLG10KFsiZmlsdGVyIiwibWFwIiwidGFrZVdoaWxlIl0sKGZ1bmN0aW9uKGUsdCl7dmFyIHI9dCsxLGk9MT09cnx8Mz09cjtxci5wcm90b3R5cGVbZV09ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5jbG9uZSgpO3JldHVybiB0Ll9faXRlcmF0ZWVzX18ucHVzaCh7aXRlcmF0ZWU6c28oZSwzKSx0eXBlOnJ9KSx0Ll9fZmlsdGVyZWRfXz10Ll9fZmlsdGVyZWRfX3x8aSx0fX0pKSxtdChbImhlYWQiLCJsYXN0Il0sKGZ1bmN0aW9uKGUsdCl7dmFyIHI9InRha2UiKyh0PyJSaWdodCI6IiIpO3FyLnByb3RvdHlwZVtlXT1mdW5jdGlvbigpe3JldHVybiB0aGlzW3JdKDEpLnZhbHVlKClbMF19fSkpLG10KFsiaW5pdGlhbCIsInRhaWwiXSwoZnVuY3Rpb24oZSx0KXt2YXIgcj0iZHJvcCIrKHQ/IiI6IlJpZ2h0Iik7cXIucHJvdG90eXBlW2VdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX19maWx0ZXJlZF9fP25ldyBxcih0aGlzKTp0aGlzW3JdKDEpfX0pKSxxci5wcm90b3R5cGUuY29tcGFjdD1mdW5jdGlvbigpe3JldHVybiB0aGlzLmZpbHRlcihuYyl9LHFyLnByb3RvdHlwZS5maW5kPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLmZpbHRlcihlKS5oZWFkKCl9LHFyLnByb3RvdHlwZS5maW5kTGFzdD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5yZXZlcnNlKCkuZmluZChlKX0scXIucHJvdG90eXBlLmludm9rZU1hcD1HaSgoZnVuY3Rpb24oZSx0KXtyZXR1cm4iZnVuY3Rpb24iPT10eXBlb2YgZT9uZXcgcXIodGhpcyk6dGhpcy5tYXAoKGZ1bmN0aW9uKHIpe3JldHVybiBraShyLGUsdCl9KSl9KSkscXIucHJvdG90eXBlLnJlamVjdD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5maWx0ZXIoSXMoc28oZSkpKX0scXIucHJvdG90eXBlLnNsaWNlPWZ1bmN0aW9uKGUsdCl7ZT1wYShlKTt2YXIgcj10aGlzO3JldHVybiByLl9fZmlsdGVyZWRfXyYmKGU+MHx8dDwwKT9uZXcgcXIocik6KGU8MD9yPXIudGFrZVJpZ2h0KC1lKTplJiYocj1yLmRyb3AoZSkpLHQhPT1uJiYocj0odD1wYSh0KSk8MD9yLmRyb3BSaWdodCgtdCk6ci50YWtlKHQtZSkpLHIpfSxxci5wcm90b3R5cGUudGFrZVJpZ2h0V2hpbGU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMucmV2ZXJzZSgpLnRha2VXaGlsZShlKS5yZXZlcnNlKCl9LHFyLnByb3RvdHlwZS50b0FycmF5PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudGFrZShfKX0seWkocXIucHJvdG90eXBlLChmdW5jdGlvbihlLHQpe3ZhciByPS9eKD86ZmlsdGVyfGZpbmR8bWFwfHJlamVjdCl8V2hpbGUkLy50ZXN0KHQpLGk9L14oPzpoZWFkfGxhc3QpJC8udGVzdCh0KSxvPWpyW2k/InRha2UiKygibGFzdCI9PXQ/IlJpZ2h0IjoiIik6dF0scz1pfHwvXmZpbmQvLnRlc3QodCk7byYmKGpyLnByb3RvdHlwZVt0XT1mdW5jdGlvbigpe3ZhciB0PXRoaXMuX193cmFwcGVkX18sYT1pP1sxXTphcmd1bWVudHMsYz10IGluc3RhbmNlb2YgcXIsbD1hWzBdLHU9Y3x8S3ModCksaD1mdW5jdGlvbihlKXt2YXIgdD1vLmFwcGx5KGpyLHh0KFtlXSxhKSk7cmV0dXJuIGkmJmY/dFswXTp0fTt1JiZyJiYiZnVuY3Rpb24iPT10eXBlb2YgbCYmMSE9bC5sZW5ndGgmJihjPXU9ITEpO3ZhciBmPXRoaXMuX19jaGFpbl9fLF89ISF0aGlzLl9fYWN0aW9uc19fLmxlbmd0aCxkPXMmJiFmLHA9YyYmIV87aWYoIXMmJnUpe3Q9cD90Om5ldyBxcih0aGlzKTt2YXIgdj1lLmFwcGx5KHQsYSk7cmV0dXJuIHYuX19hY3Rpb25zX18ucHVzaCh7ZnVuYzpkcyxhcmdzOltoXSx0aGlzQXJnOm59KSxuZXcgVXIodixmKX1yZXR1cm4gZCYmcD9lLmFwcGx5KHRoaXMsYSk6KHY9dGhpcy50aHJ1KGgpLGQ/aT92LnZhbHVlKClbMF06di52YWx1ZSgpOnYpfSl9KSksbXQoWyJwb3AiLCJwdXNoIiwic2hpZnQiLCJzb3J0Iiwic3BsaWNlIiwidW5zaGlmdCJdLChmdW5jdGlvbihlKXt2YXIgdD1rZVtlXSxyPS9eKD86cHVzaHxzb3J0fHVuc2hpZnQpJC8udGVzdChlKT8idGFwIjoidGhydSIsaT0vXig/OnBvcHxzaGlmdCkkLy50ZXN0KGUpO2pyLnByb3RvdHlwZVtlXT1mdW5jdGlvbigpe3ZhciBlPWFyZ3VtZW50cztpZihpJiYhdGhpcy5fX2NoYWluX18pe3ZhciBuPXRoaXMudmFsdWUoKTtyZXR1cm4gdC5hcHBseShLcyhuKT9uOltdLGUpfXJldHVybiB0aGlzW3JdKChmdW5jdGlvbihyKXtyZXR1cm4gdC5hcHBseShLcyhyKT9yOltdLGUpfSkpfX0pKSx5aShxci5wcm90b3R5cGUsKGZ1bmN0aW9uKGUsdCl7dmFyIHI9anJbdF07aWYocil7dmFyIGk9ci5uYW1lKyIiO0JlLmNhbGwoTXIsaSl8fChNcltpXT1bXSksTXJbaV0ucHVzaCh7bmFtZTp0LGZ1bmM6cn0pfX0pKSxNcltqbihuLDIpLm5hbWVdPVt7bmFtZToid3JhcHBlciIsZnVuYzpufV0scXIucHJvdG90eXBlLmNsb25lPWZ1bmN0aW9uKCl7dmFyIGU9bmV3IHFyKHRoaXMuX193cmFwcGVkX18pO3JldHVybiBlLl9fYWN0aW9uc19fPUFuKHRoaXMuX19hY3Rpb25zX18pLGUuX19kaXJfXz10aGlzLl9fZGlyX18sZS5fX2ZpbHRlcmVkX189dGhpcy5fX2ZpbHRlcmVkX18sZS5fX2l0ZXJhdGVlc19fPUFuKHRoaXMuX19pdGVyYXRlZXNfXyksZS5fX3Rha2VDb3VudF9fPXRoaXMuX190YWtlQ291bnRfXyxlLl9fdmlld3NfXz1Bbih0aGlzLl9fdmlld3NfXyksZX0scXIucHJvdG90eXBlLnJldmVyc2U9ZnVuY3Rpb24oKXtpZih0aGlzLl9fZmlsdGVyZWRfXyl7dmFyIGU9bmV3IHFyKHRoaXMpO2UuX19kaXJfXz0tMSxlLl9fZmlsdGVyZWRfXz0hMH1lbHNlKGU9dGhpcy5jbG9uZSgpKS5fX2Rpcl9fKj0tMTtyZXR1cm4gZX0scXIucHJvdG90eXBlLnZhbHVlPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5fX3dyYXBwZWRfXy52YWx1ZSgpLHQ9dGhpcy5fX2Rpcl9fLHI9S3MoZSksaT10PDAsbj1yP2UubGVuZ3RoOjAsbz1mdW5jdGlvbihlLHQscil7Zm9yKHZhciBpPS0xLG49ci5sZW5ndGg7KytpPG47KXt2YXIgbz1yW2ldLHM9by5zaXplO3N3aXRjaChvLnR5cGUpe2Nhc2UiZHJvcCI6ZSs9czticmVhaztjYXNlImRyb3BSaWdodCI6dC09czticmVhaztjYXNlInRha2UiOnQ9Z3IodCxlK3MpO2JyZWFrO2Nhc2UidGFrZVJpZ2h0IjplPXZyKGUsdC1zKX19cmV0dXJue3N0YXJ0OmUsZW5kOnR9fSgwLG4sdGhpcy5fX3ZpZXdzX18pLHM9by5zdGFydCxhPW8uZW5kLGM9YS1zLGw9aT9hOnMtMSx1PXRoaXMuX19pdGVyYXRlZXNfXyxoPXUubGVuZ3RoLGY9MCxfPWdyKGMsdGhpcy5fX3Rha2VDb3VudF9fKTtpZighcnx8IWkmJm49PWMmJl89PWMpcmV0dXJuIGZuKGUsdGhpcy5fX2FjdGlvbnNfXyk7dmFyIGQ9W107ZTpmb3IoO2MtLSYmZjxfOyl7Zm9yKHZhciBwPS0xLHY9ZVtsKz10XTsrK3A8aDspe3ZhciBnPXVbcF0seT1nLml0ZXJhdGVlLG09Zy50eXBlLGI9eSh2KTtpZigyPT1tKXY9YjtlbHNlIGlmKCFiKXtpZigxPT1tKWNvbnRpbnVlIGU7YnJlYWsgZX19ZFtmKytdPXZ9cmV0dXJuIGR9LGpyLnByb3RvdHlwZS5hdD1wcyxqci5wcm90b3R5cGUuY2hhaW49ZnVuY3Rpb24oKXtyZXR1cm4gX3ModGhpcyl9LGpyLnByb3RvdHlwZS5jb21taXQ9ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IFVyKHRoaXMudmFsdWUoKSx0aGlzLl9fY2hhaW5fXyl9LGpyLnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKCl7dGhpcy5fX3ZhbHVlc19fPT09biYmKHRoaXMuX192YWx1ZXNfXz1fYSh0aGlzLnZhbHVlKCkpKTt2YXIgZT10aGlzLl9faW5kZXhfXz49dGhpcy5fX3ZhbHVlc19fLmxlbmd0aDtyZXR1cm57ZG9uZTplLHZhbHVlOmU/bjp0aGlzLl9fdmFsdWVzX19bdGhpcy5fX2luZGV4X18rK119fSxqci5wcm90b3R5cGUucGxhbnQ9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LHI9dGhpcztyIGluc3RhbmNlb2YgV3I7KXt2YXIgaT1XbyhyKTtpLl9faW5kZXhfXz0wLGkuX192YWx1ZXNfXz1uLHQ/by5fX3dyYXBwZWRfXz1pOnQ9aTt2YXIgbz1pO3I9ci5fX3dyYXBwZWRfX31yZXR1cm4gby5fX3dyYXBwZWRfXz1lLHR9LGpyLnByb3RvdHlwZS5yZXZlcnNlPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5fX3dyYXBwZWRfXztpZihlIGluc3RhbmNlb2YgcXIpe3ZhciB0PWU7cmV0dXJuIHRoaXMuX19hY3Rpb25zX18ubGVuZ3RoJiYodD1uZXcgcXIodGhpcykpLCh0PXQucmV2ZXJzZSgpKS5fX2FjdGlvbnNfXy5wdXNoKHtmdW5jOmRzLGFyZ3M6W3RzXSx0aGlzQXJnOm59KSxuZXcgVXIodCx0aGlzLl9fY2hhaW5fXyl9cmV0dXJuIHRoaXMudGhydSh0cyl9LGpyLnByb3RvdHlwZS50b0pTT049anIucHJvdG90eXBlLnZhbHVlT2Y9anIucHJvdG90eXBlLnZhbHVlPWZ1bmN0aW9uKCl7cmV0dXJuIGZuKHRoaXMuX193cmFwcGVkX18sdGhpcy5fX2FjdGlvbnNfXyl9LGpyLnByb3RvdHlwZS5maXJzdD1qci5wcm90b3R5cGUuaGVhZCxzdCYmKGpyLnByb3RvdHlwZVtzdF09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLGpyfSgpO290Ll89Y3IsKGk9ZnVuY3Rpb24oKXtyZXR1cm4gY3J9LmNhbGwodCxyLHQsZSkpPT09bnx8KGUuZXhwb3J0cz1pKX0uY2FsbCh0aGlzKX0sMzc5OmU9PnsidXNlIHN0cmljdCI7dmFyIHQ9W107ZnVuY3Rpb24gcihlKXtmb3IodmFyIHI9LTEsaT0wO2k8dC5sZW5ndGg7aSsrKWlmKHRbaV0uaWRlbnRpZmllcj09PWUpe3I9aTticmVha31yZXR1cm4gcn1mdW5jdGlvbiBpKGUsaSl7Zm9yKHZhciBvPXt9LHM9W10sYT0wO2E8ZS5sZW5ndGg7YSsrKXt2YXIgYz1lW2FdLGw9aS5iYXNlP2NbMF0raS5iYXNlOmNbMF0sdT1vW2xdfHwwLGg9IiIuY29uY2F0KGwsIiAiKS5jb25jYXQodSk7b1tsXT11KzE7dmFyIGY9cihoKSxfPXtjc3M6Y1sxXSxtZWRpYTpjWzJdLHNvdXJjZU1hcDpjWzNdLHN1cHBvcnRzOmNbNF0sbGF5ZXI6Y1s1XX07aWYoLTEhPT1mKXRbZl0ucmVmZXJlbmNlcysrLHRbZl0udXBkYXRlcihfKTtlbHNle3ZhciBkPW4oXyxpKTtpLmJ5SW5kZXg9YSx0LnNwbGljZShhLDAse2lkZW50aWZpZXI6aCx1cGRhdGVyOmQscmVmZXJlbmNlczoxfSl9cy5wdXNoKGgpfXJldHVybiBzfWZ1bmN0aW9uIG4oZSx0KXt2YXIgcj10LmRvbUFQSSh0KTtyZXR1cm4gci51cGRhdGUoZSksZnVuY3Rpb24odCl7aWYodCl7aWYodC5jc3M9PT1lLmNzcyYmdC5tZWRpYT09PWUubWVkaWEmJnQuc291cmNlTWFwPT09ZS5zb3VyY2VNYXAmJnQuc3VwcG9ydHM9PT1lLnN1cHBvcnRzJiZ0LmxheWVyPT09ZS5sYXllcilyZXR1cm47ci51cGRhdGUoZT10KX1lbHNlIHIucmVtb3ZlKCl9fWUuZXhwb3J0cz1mdW5jdGlvbihlLG4pe3ZhciBvPWkoZT1lfHxbXSxuPW58fHt9KTtyZXR1cm4gZnVuY3Rpb24oZSl7ZT1lfHxbXTtmb3IodmFyIHM9MDtzPG8ubGVuZ3RoO3MrKyl7dmFyIGE9cihvW3NdKTt0W2FdLnJlZmVyZW5jZXMtLX1mb3IodmFyIGM9aShlLG4pLGw9MDtsPG8ubGVuZ3RoO2wrKyl7dmFyIHU9cihvW2xdKTswPT09dFt1XS5yZWZlcmVuY2VzJiYodFt1XS51cGRhdGVyKCksdC5zcGxpY2UodSwxKSl9bz1jfX19LDU2OTplPT57InVzZSBzdHJpY3QiO3ZhciB0PXt9O2UuZXhwb3J0cz1mdW5jdGlvbihlLHIpe3ZhciBpPWZ1bmN0aW9uKGUpe2lmKHZvaWQgMD09PXRbZV0pe3ZhciByPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZSk7aWYod2luZG93LkhUTUxJRnJhbWVFbGVtZW50JiZyIGluc3RhbmNlb2Ygd2luZG93LkhUTUxJRnJhbWVFbGVtZW50KXRyeXtyPXIuY29udGVudERvY3VtZW50LmhlYWR9Y2F0Y2goZSl7cj1udWxsfXRbZV09cn1yZXR1cm4gdFtlXX0oZSk7aWYoIWkpdGhyb3cgbmV3IEVycm9yKCJDb3VsZG4ndCBmaW5kIGEgc3R5bGUgdGFyZ2V0LiBUaGlzIHByb2JhYmx5IG1lYW5zIHRoYXQgdGhlIHZhbHVlIGZvciB0aGUgJ2luc2VydCcgcGFyYW1ldGVyIGlzIGludmFsaWQuIik7aS5hcHBlbmRDaGlsZChyKX19LDIxNjplPT57InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzdHlsZSIpO3JldHVybiBlLnNldEF0dHJpYnV0ZXModCxlLmF0dHJpYnV0ZXMpLGUuaW5zZXJ0KHQsZS5vcHRpb25zKSx0fX0sNTY1OihlLHQscik9PnsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0PXIubmM7dCYmZS5zZXRBdHRyaWJ1dGUoIm5vbmNlIix0KX19LDc5NTplPT57InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdD1lLmluc2VydFN0eWxlRWxlbWVudChlKTtyZXR1cm57dXBkYXRlOmZ1bmN0aW9uKHIpeyFmdW5jdGlvbihlLHQscil7dmFyIGk9IiI7ci5zdXBwb3J0cyYmKGkrPSJAc3VwcG9ydHMgKCIuY29uY2F0KHIuc3VwcG9ydHMsIikgeyIpKSxyLm1lZGlhJiYoaSs9IkBtZWRpYSAiLmNvbmNhdChyLm1lZGlhLCIgeyIpKTt2YXIgbj12b2lkIDAhPT1yLmxheWVyO24mJihpKz0iQGxheWVyIi5jb25jYXQoci5sYXllci5sZW5ndGg+MD8iICIuY29uY2F0KHIubGF5ZXIpOiIiLCIgeyIpKSxpKz1yLmNzcyxuJiYoaSs9In0iKSxyLm1lZGlhJiYoaSs9In0iKSxyLnN1cHBvcnRzJiYoaSs9In0iKTt2YXIgbz1yLnNvdXJjZU1hcDtvJiYidW5kZWZpbmVkIiE9dHlwZW9mIGJ0b2EmJihpKz0iXG4vKiMgc291cmNlTWFwcGluZ1VSTD1kYXRhOmFwcGxpY2F0aW9uL2pzb247YmFzZTY0LCIuY29uY2F0KGJ0b2EodW5lc2NhcGUoZW5jb2RlVVJJQ29tcG9uZW50KEpTT04uc3RyaW5naWZ5KG8pKSkpLCIgKi8iKSksdC5zdHlsZVRhZ1RyYW5zZm9ybShpLGUsdC5vcHRpb25zKX0odCxlLHIpfSxyZW1vdmU6ZnVuY3Rpb24oKXshZnVuY3Rpb24oZSl7aWYobnVsbD09PWUucGFyZW50Tm9kZSlyZXR1cm4hMTtlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZSl9KHQpfX19fSw1ODk6ZT0+eyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0KXtpZih0LnN0eWxlU2hlZXQpdC5zdHlsZVNoZWV0LmNzc1RleHQ9ZTtlbHNle2Zvcig7dC5maXJzdENoaWxkOyl0LnJlbW92ZUNoaWxkKHQuZmlyc3RDaGlsZCk7dC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShlKSl9fX0sNjE3OmU9PntzZWxmLGUuZXhwb3J0cz0oKCk9PnsidXNlIHN0cmljdCI7dmFyIGU9ezc3NTooZSx0KT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkZpdEFkZG9uPXZvaWQgMDt2YXIgcj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt9cmV0dXJuIGUucHJvdG90eXBlLmFjdGl2YXRlPWZ1bmN0aW9uKGUpe3RoaXMuX3Rlcm1pbmFsPWV9LGUucHJvdG90eXBlLmRpc3Bvc2U9ZnVuY3Rpb24oKXt9LGUucHJvdG90eXBlLmZpdD1mdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcG9zZURpbWVuc2lvbnMoKTtpZihlJiZ0aGlzLl90ZXJtaW5hbCl7dmFyIHQ9dGhpcy5fdGVybWluYWwuX2NvcmU7dGhpcy5fdGVybWluYWwucm93cz09PWUucm93cyYmdGhpcy5fdGVybWluYWwuY29scz09PWUuY29sc3x8KHQuX3JlbmRlclNlcnZpY2UuY2xlYXIoKSx0aGlzLl90ZXJtaW5hbC5yZXNpemUoZS5jb2xzLGUucm93cykpfX0sZS5wcm90b3R5cGUucHJvcG9zZURpbWVuc2lvbnM9ZnVuY3Rpb24oKXtpZih0aGlzLl90ZXJtaW5hbCYmdGhpcy5fdGVybWluYWwuZWxlbWVudCYmdGhpcy5fdGVybWluYWwuZWxlbWVudC5wYXJlbnRFbGVtZW50KXt2YXIgZT10aGlzLl90ZXJtaW5hbC5fY29yZTtpZigwIT09ZS5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLmFjdHVhbENlbGxXaWR0aCYmMCE9PWUuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0KXt2YXIgdD13aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSh0aGlzLl90ZXJtaW5hbC5lbGVtZW50LnBhcmVudEVsZW1lbnQpLHI9cGFyc2VJbnQodC5nZXRQcm9wZXJ0eVZhbHVlKCJoZWlnaHQiKSksaT1NYXRoLm1heCgwLHBhcnNlSW50KHQuZ2V0UHJvcGVydHlWYWx1ZSgid2lkdGgiKSkpLG49d2luZG93LmdldENvbXB1dGVkU3R5bGUodGhpcy5fdGVybWluYWwuZWxlbWVudCksbz1yLShwYXJzZUludChuLmdldFByb3BlcnR5VmFsdWUoInBhZGRpbmctdG9wIikpK3BhcnNlSW50KG4uZ2V0UHJvcGVydHlWYWx1ZSgicGFkZGluZy1ib3R0b20iKSkpLHM9aS0ocGFyc2VJbnQobi5nZXRQcm9wZXJ0eVZhbHVlKCJwYWRkaW5nLXJpZ2h0IikpK3BhcnNlSW50KG4uZ2V0UHJvcGVydHlWYWx1ZSgicGFkZGluZy1sZWZ0IikpKS1lLnZpZXdwb3J0LnNjcm9sbEJhcldpZHRoO3JldHVybntjb2xzOk1hdGgubWF4KDIsTWF0aC5mbG9vcihzL2UuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucy5hY3R1YWxDZWxsV2lkdGgpKSxyb3dzOk1hdGgubWF4KDEsTWF0aC5mbG9vcihvL2UuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0KSl9fX19LGV9KCk7dC5GaXRBZGRvbj1yfX0sdD17fTtyZXR1cm4gZnVuY3Rpb24gcihpKXtpZih0W2ldKXJldHVybiB0W2ldLmV4cG9ydHM7dmFyIG49dFtpXT17ZXhwb3J0czp7fX07cmV0dXJuIGVbaV0obixuLmV4cG9ydHMsciksbi5leHBvcnRzfSg3NzUpfSkoKX0sMzIwOmU9PntzZWxmLGUuZXhwb3J0cz0oKCk9PnsidXNlIHN0cmljdCI7dmFyIGU9ezQ1Njc6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49dGhpcyYmdGhpcy5fX2V4dGVuZHN8fChpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGk9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQscikmJihlW3JdPXRbcl0pfSxpKGUsdCl9LGZ1bmN0aW9uKGUsdCl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIkNsYXNzIGV4dGVuZHMgdmFsdWUgIitTdHJpbmcodCkrIiBpcyBub3QgYSBjb25zdHJ1Y3RvciBvciBudWxsIik7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1pKGUsdCksZS5wcm90b3R5cGU9bnVsbD09PXQ/T2JqZWN0LmNyZWF0ZSh0KTooci5wcm90b3R5cGU9dC5wcm90b3R5cGUsbmV3IHIpfSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQWNjZXNzaWJpbGl0eU1hbmFnZXI9dm9pZCAwO3ZhciBvPXIoOTA0Mikscz1yKDYxMTQpLGE9cig5OTI0KSxjPXIoMzY1NiksbD1yKDg0NCksdT1yKDU1OTYpLGg9cig5NjMxKSxmPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCxyKXt2YXIgaT1lLmNhbGwodGhpcyl8fHRoaXM7aS5fdGVybWluYWw9dCxpLl9yZW5kZXJTZXJ2aWNlPXIsaS5fbGl2ZVJlZ2lvbkxpbmVDb3VudD0wLGkuX2NoYXJzVG9Db25zdW1lPVtdLGkuX2NoYXJzVG9Bbm5vdW5jZT0iIixpLl9hY2Nlc3NpYmlsaXR5VHJlZVJvb3Q9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IiksaS5fYWNjZXNzaWJpbGl0eVRyZWVSb290LnNldEF0dHJpYnV0ZSgicm9sZSIsImRvY3VtZW50IiksaS5fYWNjZXNzaWJpbGl0eVRyZWVSb290LmNsYXNzTGlzdC5hZGQoInh0ZXJtLWFjY2Vzc2liaWxpdHkiKSxpLl9hY2Nlc3NpYmlsaXR5VHJlZVJvb3QudGFiSW5kZXg9MCxpLl9yb3dDb250YWluZXI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IiksaS5fcm93Q29udGFpbmVyLnNldEF0dHJpYnV0ZSgicm9sZSIsImxpc3QiKSxpLl9yb3dDb250YWluZXIuY2xhc3NMaXN0LmFkZCgieHRlcm0tYWNjZXNzaWJpbGl0eS10cmVlIiksaS5fcm93RWxlbWVudHM9W107Zm9yKHZhciBuPTA7bjxpLl90ZXJtaW5hbC5yb3dzO24rKylpLl9yb3dFbGVtZW50c1tuXT1pLl9jcmVhdGVBY2Nlc3NpYmlsaXR5VHJlZU5vZGUoKSxpLl9yb3dDb250YWluZXIuYXBwZW5kQ2hpbGQoaS5fcm93RWxlbWVudHNbbl0pO2lmKGkuX3RvcEJvdW5kYXJ5Rm9jdXNMaXN0ZW5lcj1mdW5jdGlvbihlKXtyZXR1cm4gaS5fb25Cb3VuZGFyeUZvY3VzKGUsMCl9LGkuX2JvdHRvbUJvdW5kYXJ5Rm9jdXNMaXN0ZW5lcj1mdW5jdGlvbihlKXtyZXR1cm4gaS5fb25Cb3VuZGFyeUZvY3VzKGUsMSl9LGkuX3Jvd0VsZW1lbnRzWzBdLmFkZEV2ZW50TGlzdGVuZXIoImZvY3VzIixpLl90b3BCb3VuZGFyeUZvY3VzTGlzdGVuZXIpLGkuX3Jvd0VsZW1lbnRzW2kuX3Jvd0VsZW1lbnRzLmxlbmd0aC0xXS5hZGRFdmVudExpc3RlbmVyKCJmb2N1cyIsaS5fYm90dG9tQm91bmRhcnlGb2N1c0xpc3RlbmVyKSxpLl9yZWZyZXNoUm93c0RpbWVuc2lvbnMoKSxpLl9hY2Nlc3NpYmlsaXR5VHJlZVJvb3QuYXBwZW5kQ2hpbGQoaS5fcm93Q29udGFpbmVyKSxpLl9yZW5kZXJSb3dzRGVib3VuY2VyPW5ldyBhLlRpbWVCYXNlZERlYm91bmNlcihpLl9yZW5kZXJSb3dzLmJpbmQoaSkpLGkuX3JlZnJlc2hSb3dzKCksaS5fbGl2ZVJlZ2lvbj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKSxpLl9saXZlUmVnaW9uLmNsYXNzTGlzdC5hZGQoImxpdmUtcmVnaW9uIiksaS5fbGl2ZVJlZ2lvbi5zZXRBdHRyaWJ1dGUoImFyaWEtbGl2ZSIsImFzc2VydGl2ZSIpLGkuX2FjY2Vzc2liaWxpdHlUcmVlUm9vdC5hcHBlbmRDaGlsZChpLl9saXZlUmVnaW9uKSwhaS5fdGVybWluYWwuZWxlbWVudCl0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBlbmFibGUgYWNjZXNzaWJpbGl0eSBiZWZvcmUgVGVybWluYWwub3BlbiIpO3JldHVybiBpLl90ZXJtaW5hbC5lbGVtZW50Lmluc2VydEFkamFjZW50RWxlbWVudCgiYWZ0ZXJiZWdpbiIsaS5fYWNjZXNzaWJpbGl0eVRyZWVSb290KSxpLnJlZ2lzdGVyKGkuX3JlbmRlclJvd3NEZWJvdW5jZXIpLGkucmVnaXN0ZXIoaS5fdGVybWluYWwub25SZXNpemUoKGZ1bmN0aW9uKGUpe3JldHVybiBpLl9vblJlc2l6ZShlLnJvd3MpfSkpKSxpLnJlZ2lzdGVyKGkuX3Rlcm1pbmFsLm9uUmVuZGVyKChmdW5jdGlvbihlKXtyZXR1cm4gaS5fcmVmcmVzaFJvd3MoZS5zdGFydCxlLmVuZCl9KSkpLGkucmVnaXN0ZXIoaS5fdGVybWluYWwub25TY3JvbGwoKGZ1bmN0aW9uKCl7cmV0dXJuIGkuX3JlZnJlc2hSb3dzKCl9KSkpLGkucmVnaXN0ZXIoaS5fdGVybWluYWwub25BMTF5Q2hhcigoZnVuY3Rpb24oZSl7cmV0dXJuIGkuX29uQ2hhcihlKX0pKSksaS5yZWdpc3RlcihpLl90ZXJtaW5hbC5vbkxpbmVGZWVkKChmdW5jdGlvbigpe3JldHVybiBpLl9vbkNoYXIoIlxuIil9KSkpLGkucmVnaXN0ZXIoaS5fdGVybWluYWwub25BMTF5VGFiKChmdW5jdGlvbihlKXtyZXR1cm4gaS5fb25UYWIoZSl9KSkpLGkucmVnaXN0ZXIoaS5fdGVybWluYWwub25LZXkoKGZ1bmN0aW9uKGUpe3JldHVybiBpLl9vbktleShlLmtleSl9KSkpLGkucmVnaXN0ZXIoaS5fdGVybWluYWwub25CbHVyKChmdW5jdGlvbigpe3JldHVybiBpLl9jbGVhckxpdmVSZWdpb24oKX0pKSksaS5yZWdpc3RlcihpLl9yZW5kZXJTZXJ2aWNlLm9uRGltZW5zaW9uc0NoYW5nZSgoZnVuY3Rpb24oKXtyZXR1cm4gaS5fcmVmcmVzaFJvd3NEaW1lbnNpb25zKCl9KSkpLGkuX3NjcmVlbkRwck1vbml0b3I9bmV3IHUuU2NyZWVuRHByTW9uaXRvcixpLnJlZ2lzdGVyKGkuX3NjcmVlbkRwck1vbml0b3IpLGkuX3NjcmVlbkRwck1vbml0b3Iuc2V0TGlzdGVuZXIoKGZ1bmN0aW9uKCl7cmV0dXJuIGkuX3JlZnJlc2hSb3dzRGltZW5zaW9ucygpfSkpLGkucmVnaXN0ZXIoKDAsYy5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHdpbmRvdywicmVzaXplIiwoZnVuY3Rpb24oKXtyZXR1cm4gaS5fcmVmcmVzaFJvd3NEaW1lbnNpb25zKCl9KSkpLGl9cmV0dXJuIG4odCxlKSx0LnByb3RvdHlwZS5kaXNwb3NlPWZ1bmN0aW9uKCl7ZS5wcm90b3R5cGUuZGlzcG9zZS5jYWxsKHRoaXMpLCgwLGgucmVtb3ZlRWxlbWVudEZyb21QYXJlbnQpKHRoaXMuX2FjY2Vzc2liaWxpdHlUcmVlUm9vdCksdGhpcy5fcm93RWxlbWVudHMubGVuZ3RoPTB9LHQucHJvdG90eXBlLl9vbkJvdW5kYXJ5Rm9jdXM9ZnVuY3Rpb24oZSx0KXt2YXIgcj1lLnRhcmdldCxpPXRoaXMuX3Jvd0VsZW1lbnRzWzA9PT10PzE6dGhpcy5fcm93RWxlbWVudHMubGVuZ3RoLTJdO2lmKHIuZ2V0QXR0cmlidXRlKCJhcmlhLXBvc2luc2V0IikhPT0oMD09PXQ/IjEiOiIiK3RoaXMuX3Rlcm1pbmFsLmJ1ZmZlci5saW5lcy5sZW5ndGgpJiZlLnJlbGF0ZWRUYXJnZXQ9PT1pKXt2YXIgbixvO2lmKDA9PT10PyhuPXIsbz10aGlzLl9yb3dFbGVtZW50cy5wb3AoKSx0aGlzLl9yb3dDb250YWluZXIucmVtb3ZlQ2hpbGQobykpOihuPXRoaXMuX3Jvd0VsZW1lbnRzLnNoaWZ0KCksbz1yLHRoaXMuX3Jvd0NvbnRhaW5lci5yZW1vdmVDaGlsZChuKSksbi5yZW1vdmVFdmVudExpc3RlbmVyKCJmb2N1cyIsdGhpcy5fdG9wQm91bmRhcnlGb2N1c0xpc3RlbmVyKSxvLnJlbW92ZUV2ZW50TGlzdGVuZXIoImZvY3VzIix0aGlzLl9ib3R0b21Cb3VuZGFyeUZvY3VzTGlzdGVuZXIpLDA9PT10KXt2YXIgcz10aGlzLl9jcmVhdGVBY2Nlc3NpYmlsaXR5VHJlZU5vZGUoKTt0aGlzLl9yb3dFbGVtZW50cy51bnNoaWZ0KHMpLHRoaXMuX3Jvd0NvbnRhaW5lci5pbnNlcnRBZGphY2VudEVsZW1lbnQoImFmdGVyYmVnaW4iLHMpfWVsc2Ugcz10aGlzLl9jcmVhdGVBY2Nlc3NpYmlsaXR5VHJlZU5vZGUoKSx0aGlzLl9yb3dFbGVtZW50cy5wdXNoKHMpLHRoaXMuX3Jvd0NvbnRhaW5lci5hcHBlbmRDaGlsZChzKTt0aGlzLl9yb3dFbGVtZW50c1swXS5hZGRFdmVudExpc3RlbmVyKCJmb2N1cyIsdGhpcy5fdG9wQm91bmRhcnlGb2N1c0xpc3RlbmVyKSx0aGlzLl9yb3dFbGVtZW50c1t0aGlzLl9yb3dFbGVtZW50cy5sZW5ndGgtMV0uYWRkRXZlbnRMaXN0ZW5lcigiZm9jdXMiLHRoaXMuX2JvdHRvbUJvdW5kYXJ5Rm9jdXNMaXN0ZW5lciksdGhpcy5fdGVybWluYWwuc2Nyb2xsTGluZXMoMD09PXQ/LTE6MSksdGhpcy5fcm93RWxlbWVudHNbMD09PXQ/MTp0aGlzLl9yb3dFbGVtZW50cy5sZW5ndGgtMl0uZm9jdXMoKSxlLnByZXZlbnREZWZhdWx0KCksZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKX19LHQucHJvdG90eXBlLl9vblJlc2l6ZT1mdW5jdGlvbihlKXt0aGlzLl9yb3dFbGVtZW50c1t0aGlzLl9yb3dFbGVtZW50cy5sZW5ndGgtMV0ucmVtb3ZlRXZlbnRMaXN0ZW5lcigiZm9jdXMiLHRoaXMuX2JvdHRvbUJvdW5kYXJ5Rm9jdXNMaXN0ZW5lcik7Zm9yKHZhciB0PXRoaXMuX3Jvd0NvbnRhaW5lci5jaGlsZHJlbi5sZW5ndGg7dDx0aGlzLl90ZXJtaW5hbC5yb3dzO3QrKyl0aGlzLl9yb3dFbGVtZW50c1t0XT10aGlzLl9jcmVhdGVBY2Nlc3NpYmlsaXR5VHJlZU5vZGUoKSx0aGlzLl9yb3dDb250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5fcm93RWxlbWVudHNbdF0pO2Zvcig7dGhpcy5fcm93RWxlbWVudHMubGVuZ3RoPmU7KXRoaXMuX3Jvd0NvbnRhaW5lci5yZW1vdmVDaGlsZCh0aGlzLl9yb3dFbGVtZW50cy5wb3AoKSk7dGhpcy5fcm93RWxlbWVudHNbdGhpcy5fcm93RWxlbWVudHMubGVuZ3RoLTFdLmFkZEV2ZW50TGlzdGVuZXIoImZvY3VzIix0aGlzLl9ib3R0b21Cb3VuZGFyeUZvY3VzTGlzdGVuZXIpLHRoaXMuX3JlZnJlc2hSb3dzRGltZW5zaW9ucygpfSx0LnByb3RvdHlwZS5fY3JlYXRlQWNjZXNzaWJpbGl0eVRyZWVOb2RlPWZ1bmN0aW9uKCl7dmFyIGU9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7cmV0dXJuIGUuc2V0QXR0cmlidXRlKCJyb2xlIiwibGlzdGl0ZW0iKSxlLnRhYkluZGV4PS0xLHRoaXMuX3JlZnJlc2hSb3dEaW1lbnNpb25zKGUpLGV9LHQucHJvdG90eXBlLl9vblRhYj1mdW5jdGlvbihlKXtmb3IodmFyIHQ9MDt0PGU7dCsrKXRoaXMuX29uQ2hhcigiICIpfSx0LnByb3RvdHlwZS5fb25DaGFyPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7dGhpcy5fbGl2ZVJlZ2lvbkxpbmVDb3VudDwyMSYmKHRoaXMuX2NoYXJzVG9Db25zdW1lLmxlbmd0aD4wP3RoaXMuX2NoYXJzVG9Db25zdW1lLnNoaWZ0KCkhPT1lJiYodGhpcy5fY2hhcnNUb0Fubm91bmNlKz1lKTp0aGlzLl9jaGFyc1RvQW5ub3VuY2UrPWUsIlxuIj09PWUmJih0aGlzLl9saXZlUmVnaW9uTGluZUNvdW50KyssMjE9PT10aGlzLl9saXZlUmVnaW9uTGluZUNvdW50JiYodGhpcy5fbGl2ZVJlZ2lvbi50ZXh0Q29udGVudCs9by50b29NdWNoT3V0cHV0KSkscy5pc01hYyYmdGhpcy5fbGl2ZVJlZ2lvbi50ZXh0Q29udGVudCYmdGhpcy5fbGl2ZVJlZ2lvbi50ZXh0Q29udGVudC5sZW5ndGg+MCYmIXRoaXMuX2xpdmVSZWdpb24ucGFyZW50Tm9kZSYmc2V0VGltZW91dCgoZnVuY3Rpb24oKXt0Ll9hY2Nlc3NpYmlsaXR5VHJlZVJvb3QuYXBwZW5kQ2hpbGQodC5fbGl2ZVJlZ2lvbil9KSwwKSl9LHQucHJvdG90eXBlLl9jbGVhckxpdmVSZWdpb249ZnVuY3Rpb24oKXt0aGlzLl9saXZlUmVnaW9uLnRleHRDb250ZW50PSIiLHRoaXMuX2xpdmVSZWdpb25MaW5lQ291bnQ9MCxzLmlzTWFjJiYoMCxoLnJlbW92ZUVsZW1lbnRGcm9tUGFyZW50KSh0aGlzLl9saXZlUmVnaW9uKX0sdC5wcm90b3R5cGUuX29uS2V5PWZ1bmN0aW9uKGUpe3RoaXMuX2NsZWFyTGl2ZVJlZ2lvbigpLHRoaXMuX2NoYXJzVG9Db25zdW1lLnB1c2goZSl9LHQucHJvdG90eXBlLl9yZWZyZXNoUm93cz1mdW5jdGlvbihlLHQpe3RoaXMuX3JlbmRlclJvd3NEZWJvdW5jZXIucmVmcmVzaChlLHQsdGhpcy5fdGVybWluYWwucm93cyl9LHQucHJvdG90eXBlLl9yZW5kZXJSb3dzPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPXRoaXMuX3Rlcm1pbmFsLmJ1ZmZlcixpPXIubGluZXMubGVuZ3RoLnRvU3RyaW5nKCksbj1lO248PXQ7bisrKXt2YXIgbz1yLnRyYW5zbGF0ZUJ1ZmZlckxpbmVUb1N0cmluZyhyLnlkaXNwK24sITApLHM9KHIueWRpc3ArbisxKS50b1N0cmluZygpLGE9dGhpcy5fcm93RWxlbWVudHNbbl07YSYmKDA9PT1vLmxlbmd0aD9hLmlubmVyVGV4dD0iwqAiOmEudGV4dENvbnRlbnQ9byxhLnNldEF0dHJpYnV0ZSgiYXJpYS1wb3NpbnNldCIscyksYS5zZXRBdHRyaWJ1dGUoImFyaWEtc2V0c2l6ZSIsaSkpfXRoaXMuX2Fubm91bmNlQ2hhcmFjdGVycygpfSx0LnByb3RvdHlwZS5fcmVmcmVzaFJvd3NEaW1lbnNpb25zPWZ1bmN0aW9uKCl7aWYodGhpcy5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLmFjdHVhbENlbGxIZWlnaHQpe3RoaXMuX3Jvd0VsZW1lbnRzLmxlbmd0aCE9PXRoaXMuX3Rlcm1pbmFsLnJvd3MmJnRoaXMuX29uUmVzaXplKHRoaXMuX3Rlcm1pbmFsLnJvd3MpO2Zvcih2YXIgZT0wO2U8dGhpcy5fdGVybWluYWwucm93cztlKyspdGhpcy5fcmVmcmVzaFJvd0RpbWVuc2lvbnModGhpcy5fcm93RWxlbWVudHNbZV0pfX0sdC5wcm90b3R5cGUuX3JlZnJlc2hSb3dEaW1lbnNpb25zPWZ1bmN0aW9uKGUpe2Uuc3R5bGUuaGVpZ2h0PXRoaXMuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0KyJweCJ9LHQucHJvdG90eXBlLl9hbm5vdW5jZUNoYXJhY3RlcnM9ZnVuY3Rpb24oKXswIT09dGhpcy5fY2hhcnNUb0Fubm91bmNlLmxlbmd0aCYmKHRoaXMuX2xpdmVSZWdpb24udGV4dENvbnRlbnQrPXRoaXMuX2NoYXJzVG9Bbm5vdW5jZSx0aGlzLl9jaGFyc1RvQW5ub3VuY2U9IiIpfSx0fShsLkRpc3Bvc2FibGUpO3QuQWNjZXNzaWJpbGl0eU1hbmFnZXI9Zn0sMzYxNDooZSx0KT0+e2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUucmVwbGFjZSgvXHI/XG4vZywiXHIiKX1mdW5jdGlvbiBpKGUsdCl7cmV0dXJuIHQ/IhtbMjAwfiIrZSsiG1syMDF+IjplfWZ1bmN0aW9uIG4oZSx0LG4pe2U9aShlPXIoZSksbi5kZWNQcml2YXRlTW9kZXMuYnJhY2tldGVkUGFzdGVNb2RlKSxuLnRyaWdnZXJEYXRhRXZlbnQoZSwhMCksdC52YWx1ZT0iIn1mdW5jdGlvbiBvKGUsdCxyKXt2YXIgaT1yLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLG49ZS5jbGllbnRYLWkubGVmdC0xMCxvPWUuY2xpZW50WS1pLnRvcC0xMDt0LnN0eWxlLndpZHRoPSIyMHB4Iix0LnN0eWxlLmhlaWdodD0iMjBweCIsdC5zdHlsZS5sZWZ0PW4rInB4Iix0LnN0eWxlLnRvcD1vKyJweCIsdC5zdHlsZS56SW5kZXg9IjEwMDAiLHQuZm9jdXMoKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5yaWdodENsaWNrSGFuZGxlcj10Lm1vdmVUZXh0QXJlYVVuZGVyTW91c2VDdXJzb3I9dC5wYXN0ZT10LmhhbmRsZVBhc3RlRXZlbnQ9dC5jb3B5SGFuZGxlcj10LmJyYWNrZXRUZXh0Rm9yUGFzdGU9dC5wcmVwYXJlVGV4dEZvclRlcm1pbmFsPXZvaWQgMCx0LnByZXBhcmVUZXh0Rm9yVGVybWluYWw9cix0LmJyYWNrZXRUZXh0Rm9yUGFzdGU9aSx0LmNvcHlIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7ZS5jbGlwYm9hcmREYXRhJiZlLmNsaXBib2FyZERhdGEuc2V0RGF0YSgidGV4dC9wbGFpbiIsdC5zZWxlY3Rpb25UZXh0KSxlLnByZXZlbnREZWZhdWx0KCl9LHQuaGFuZGxlUGFzdGVFdmVudD1mdW5jdGlvbihlLHQscil7ZS5zdG9wUHJvcGFnYXRpb24oKSxlLmNsaXBib2FyZERhdGEmJm4oZS5jbGlwYm9hcmREYXRhLmdldERhdGEoInRleHQvcGxhaW4iKSx0LHIpfSx0LnBhc3RlPW4sdC5tb3ZlVGV4dEFyZWFVbmRlck1vdXNlQ3Vyc29yPW8sdC5yaWdodENsaWNrSGFuZGxlcj1mdW5jdGlvbihlLHQscixpLG4pe28oZSx0LHIpLG4mJmkucmlnaHRDbGlja1NlbGVjdChlKSx0LnZhbHVlPWkuc2VsZWN0aW9uVGV4dCx0LnNlbGVjdCgpfX0sNDc3NDooZSx0KT0+e3ZhciByLGksbixvO2Z1bmN0aW9uIHMoZSl7dmFyIHQ9ZS50b1N0cmluZygxNik7cmV0dXJuIHQubGVuZ3RoPDI/IjAiK3Q6dH1mdW5jdGlvbiBhKGUsdCl7cmV0dXJuIGU8dD8odCsuMDUpLyhlKy4wNSk6KGUrLjA1KS8odCsuMDUpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmNvbnRyYXN0UmF0aW89dC50b1BhZGRlZEhleD10LnJnYmE9dC5yZ2I9dC5jc3M9dC5jb2xvcj10LmNoYW5uZWxzPXZvaWQgMCxmdW5jdGlvbihlKXtlLnRvQ3NzPWZ1bmN0aW9uKGUsdCxyLGkpe3JldHVybiB2b2lkIDAhPT1pPyIjIitzKGUpK3ModCkrcyhyKStzKGkpOiIjIitzKGUpK3ModCkrcyhyKX0sZS50b1JnYmE9ZnVuY3Rpb24oZSx0LHIsaSl7cmV0dXJuIHZvaWQgMD09PWkmJihpPTI1NSksKGU8PDI0fHQ8PDE2fHI8PDh8aSk+Pj4wfX0ocj10LmNoYW5uZWxzfHwodC5jaGFubmVscz17fSkpLChpPXQuY29sb3J8fCh0LmNvbG9yPXt9KSkuYmxlbmQ9ZnVuY3Rpb24oZSx0KXt2YXIgaT0oMjU1JnQucmdiYSkvMjU1O2lmKDE9PT1pKXJldHVybntjc3M6dC5jc3MscmdiYTp0LnJnYmF9O3ZhciBuPXQucmdiYT4+MjQmMjU1LG89dC5yZ2JhPj4xNiYyNTUscz10LnJnYmE+PjgmMjU1LGE9ZS5yZ2JhPj4yNCYyNTUsYz1lLnJnYmE+PjE2JjI1NSxsPWUucmdiYT4+OCYyNTUsdT1hK01hdGgucm91bmQoKG4tYSkqaSksaD1jK01hdGgucm91bmQoKG8tYykqaSksZj1sK01hdGgucm91bmQoKHMtbCkqaSk7cmV0dXJue2NzczpyLnRvQ3NzKHUsaCxmKSxyZ2JhOnIudG9SZ2JhKHUsaCxmKX19LGkuaXNPcGFxdWU9ZnVuY3Rpb24oZSl7cmV0dXJuIDI1NT09KDI1NSZlLnJnYmEpfSxpLmVuc3VyZUNvbnRyYXN0UmF0aW89ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPW8uZW5zdXJlQ29udHJhc3RSYXRpbyhlLnJnYmEsdC5yZ2JhLHIpO2lmKGkpcmV0dXJuIG8udG9Db2xvcihpPj4yNCYyNTUsaT4+MTYmMjU1LGk+PjgmMjU1KX0saS5vcGFxdWU9ZnVuY3Rpb24oZSl7dmFyIHQ9KDI1NXxlLnJnYmEpPj4+MCxpPW8udG9DaGFubmVscyh0KSxuPWlbMF0scz1pWzFdLGE9aVsyXTtyZXR1cm57Y3NzOnIudG9Dc3MobixzLGEpLHJnYmE6dH19LGkub3BhY2l0eT1mdW5jdGlvbihlLHQpe3ZhciBpPU1hdGgucm91bmQoMjU1KnQpLG49by50b0NoYW5uZWxzKGUucmdiYSkscz1uWzBdLGE9blsxXSxjPW5bMl07cmV0dXJue2NzczpyLnRvQ3NzKHMsYSxjLGkpLHJnYmE6ci50b1JnYmEocyxhLGMsaSl9fSxpLnRvQ29sb3JSR0I9ZnVuY3Rpb24oZSl7cmV0dXJuW2UucmdiYT4+MjQmMjU1LGUucmdiYT4+MTYmMjU1LGUucmdiYT4+OCYyNTVdfSwodC5jc3N8fCh0LmNzcz17fSkpLnRvQ29sb3I9ZnVuY3Rpb24oZSl7c3dpdGNoKGUubGVuZ3RoKXtjYXNlIDc6cmV0dXJue2NzczplLHJnYmE6KHBhcnNlSW50KGUuc2xpY2UoMSksMTYpPDw4fDI1NSk+Pj4wfTtjYXNlIDk6cmV0dXJue2NzczplLHJnYmE6cGFyc2VJbnQoZS5zbGljZSgxKSwxNik+Pj4wfX10aHJvdyBuZXcgRXJyb3IoImNzcy50b0NvbG9yOiBVbnN1cHBvcnRlZCBjc3MgZm9ybWF0Iil9LGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSx0LHIpe3ZhciBpPWUvMjU1LG49dC8yNTUsbz1yLzI1NTtyZXR1cm4uMjEyNiooaTw9LjAzOTI4P2kvMTIuOTI6TWF0aC5wb3coKGkrLjA1NSkvMS4wNTUsMi40KSkrLjcxNTIqKG48PS4wMzkyOD9uLzEyLjkyOk1hdGgucG93KChuKy4wNTUpLzEuMDU1LDIuNCkpKy4wNzIyKihvPD0uMDM5Mjg/by8xMi45MjpNYXRoLnBvdygobysuMDU1KS8xLjA1NSwyLjQpKX1lLnJlbGF0aXZlTHVtaW5hbmNlPWZ1bmN0aW9uKGUpe3JldHVybiB0KGU+PjE2JjI1NSxlPj44JjI1NSwyNTUmZSl9LGUucmVsYXRpdmVMdW1pbmFuY2UyPXR9KG49dC5yZ2J8fCh0LnJnYj17fSkpLGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSx0LHIpe2Zvcih2YXIgaT1lPj4yNCYyNTUsbz1lPj4xNiYyNTUscz1lPj44JjI1NSxjPXQ+PjI0JjI1NSxsPXQ+PjE2JjI1NSx1PXQ+PjgmMjU1LGg9YShuLnJlbGF0aXZlTHVtaW5hbmNlMihjLHUsbCksbi5yZWxhdGl2ZUx1bWluYW5jZTIoaSxvLHMpKTtoPHImJihjPjB8fGw+MHx8dT4wKTspYy09TWF0aC5tYXgoMCxNYXRoLmNlaWwoLjEqYykpLGwtPU1hdGgubWF4KDAsTWF0aC5jZWlsKC4xKmwpKSx1LT1NYXRoLm1heCgwLE1hdGguY2VpbCguMSp1KSksaD1hKG4ucmVsYXRpdmVMdW1pbmFuY2UyKGMsdSxsKSxuLnJlbGF0aXZlTHVtaW5hbmNlMihpLG8scykpO3JldHVybihjPDwyNHxsPDwxNnx1PDw4fDI1NSk+Pj4wfWZ1bmN0aW9uIGkoZSx0LHIpe2Zvcih2YXIgaT1lPj4yNCYyNTUsbz1lPj4xNiYyNTUscz1lPj44JjI1NSxjPXQ+PjI0JjI1NSxsPXQ+PjE2JjI1NSx1PXQ+PjgmMjU1LGg9YShuLnJlbGF0aXZlTHVtaW5hbmNlMihjLHUsbCksbi5yZWxhdGl2ZUx1bWluYW5jZTIoaSxvLHMpKTtoPHImJihjPDI1NXx8bDwyNTV8fHU8MjU1KTspYz1NYXRoLm1pbigyNTUsYytNYXRoLmNlaWwoLjEqKDI1NS1jKSkpLGw9TWF0aC5taW4oMjU1LGwrTWF0aC5jZWlsKC4xKigyNTUtbCkpKSx1PU1hdGgubWluKDI1NSx1K01hdGguY2VpbCguMSooMjU1LXUpKSksaD1hKG4ucmVsYXRpdmVMdW1pbmFuY2UyKGMsdSxsKSxuLnJlbGF0aXZlTHVtaW5hbmNlMihpLG8scykpO3JldHVybihjPDwyNHxsPDwxNnx1PDw4fDI1NSk+Pj4wfWUuZW5zdXJlQ29udHJhc3RSYXRpbz1mdW5jdGlvbihlLHIsbyl7dmFyIHM9bi5yZWxhdGl2ZUx1bWluYW5jZShlPj44KSxjPW4ucmVsYXRpdmVMdW1pbmFuY2Uocj4+OCk7aWYoYShzLGMpPG8pcmV0dXJuIGM8cz90KGUscixvKTppKGUscixvKX0sZS5yZWR1Y2VMdW1pbmFuY2U9dCxlLmluY3JlYXNlTHVtaW5hbmNlPWksZS50b0NoYW5uZWxzPWZ1bmN0aW9uKGUpe3JldHVybltlPj4yNCYyNTUsZT4+MTYmMjU1LGU+PjgmMjU1LDI1NSZlXX0sZS50b0NvbG9yPWZ1bmN0aW9uKGUsdCxpKXtyZXR1cm57Y3NzOnIudG9Dc3MoZSx0LGkpLHJnYmE6ci50b1JnYmEoZSx0LGkpfX19KG89dC5yZ2JhfHwodC5yZ2JhPXt9KSksdC50b1BhZGRlZEhleD1zLHQuY29udHJhc3RSYXRpbz1hfSw3MjM5OihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQ29sb3JDb250cmFzdENhY2hlPXZvaWQgMDt2YXIgcj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt0aGlzLl9jb2xvcj17fSx0aGlzLl9yZ2JhPXt9fXJldHVybiBlLnByb3RvdHlwZS5jbGVhcj1mdW5jdGlvbigpe3RoaXMuX2NvbG9yPXt9LHRoaXMuX3JnYmE9e319LGUucHJvdG90eXBlLnNldENzcz1mdW5jdGlvbihlLHQscil7dGhpcy5fcmdiYVtlXXx8KHRoaXMuX3JnYmFbZV09e30pLHRoaXMuX3JnYmFbZV1bdF09cn0sZS5wcm90b3R5cGUuZ2V0Q3NzPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuX3JnYmFbZV0/dGhpcy5fcmdiYVtlXVt0XTp2b2lkIDB9LGUucHJvdG90eXBlLnNldENvbG9yPWZ1bmN0aW9uKGUsdCxyKXt0aGlzLl9jb2xvcltlXXx8KHRoaXMuX2NvbG9yW2VdPXt9KSx0aGlzLl9jb2xvcltlXVt0XT1yfSxlLnByb3RvdHlwZS5nZXRDb2xvcj1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLl9jb2xvcltlXT90aGlzLl9jb2xvcltlXVt0XTp2b2lkIDB9LGV9KCk7dC5Db2xvckNvbnRyYXN0Q2FjaGU9cn0sNTY4MDpmdW5jdGlvbihlLHQscil7dmFyIGk9dGhpcyYmdGhpcy5fX3NwcmVhZEFycmF5fHxmdW5jdGlvbihlLHQscil7aWYocnx8Mj09PWFyZ3VtZW50cy5sZW5ndGgpZm9yKHZhciBpLG49MCxvPXQubGVuZ3RoO248bztuKyspIWkmJm4gaW4gdHx8KGl8fChpPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHQsMCxuKSksaVtuXT10W25dKTtyZXR1cm4gZS5jb25jYXQoaXx8QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodCkpfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Db2xvck1hbmFnZXI9dC5ERUZBVUxUX0FOU0lfQ09MT1JTPXZvaWQgMDt2YXIgbj1yKDQ3NzQpLG89cig3MjM5KSxzPW4uY3NzLnRvQ29sb3IoIiNmZmZmZmYiKSxhPW4uY3NzLnRvQ29sb3IoIiMwMDAwMDAiKSxjPW4uY3NzLnRvQ29sb3IoIiNmZmZmZmYiKSxsPW4uY3NzLnRvQ29sb3IoIiMwMDAwMDAiKSx1PXtjc3M6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC4zKSIscmdiYTo0Mjk0OTY3MTE3fTt0LkRFRkFVTFRfQU5TSV9DT0xPUlM9T2JqZWN0LmZyZWV6ZShmdW5jdGlvbigpe2Zvcih2YXIgZT1bbi5jc3MudG9Db2xvcigiIzJlMzQzNiIpLG4uY3NzLnRvQ29sb3IoIiNjYzAwMDAiKSxuLmNzcy50b0NvbG9yKCIjNGU5YTA2Iiksbi5jc3MudG9Db2xvcigiI2M0YTAwMCIpLG4uY3NzLnRvQ29sb3IoIiMzNDY1YTQiKSxuLmNzcy50b0NvbG9yKCIjNzU1MDdiIiksbi5jc3MudG9Db2xvcigiIzA2OTg5YSIpLG4uY3NzLnRvQ29sb3IoIiNkM2Q3Y2YiKSxuLmNzcy50b0NvbG9yKCIjNTU1NzUzIiksbi5jc3MudG9Db2xvcigiI2VmMjkyOSIpLG4uY3NzLnRvQ29sb3IoIiM4YWUyMzQiKSxuLmNzcy50b0NvbG9yKCIjZmNlOTRmIiksbi5jc3MudG9Db2xvcigiIzcyOWZjZiIpLG4uY3NzLnRvQ29sb3IoIiNhZDdmYTgiKSxuLmNzcy50b0NvbG9yKCIjMzRlMmUyIiksbi5jc3MudG9Db2xvcigiI2VlZWVlYyIpXSx0PVswLDk1LDEzNSwxNzUsMjE1LDI1NV0scj0wO3I8MjE2O3IrKyl7dmFyIGk9dFtyLzM2JTZ8MF0sbz10W3IvNiU2fDBdLHM9dFtyJTZdO2UucHVzaCh7Y3NzOm4uY2hhbm5lbHMudG9Dc3MoaSxvLHMpLHJnYmE6bi5jaGFubmVscy50b1JnYmEoaSxvLHMpfSl9Zm9yKHI9MDtyPDI0O3IrKyl7dmFyIGE9OCsxMCpyO2UucHVzaCh7Y3NzOm4uY2hhbm5lbHMudG9Dc3MoYSxhLGEpLHJnYmE6bi5jaGFubmVscy50b1JnYmEoYSxhLGEpfSl9cmV0dXJuIGV9KCkpO3ZhciBoPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHIpe3RoaXMuYWxsb3dUcmFuc3BhcmVuY3k9cjt2YXIgaT1lLmNyZWF0ZUVsZW1lbnQoImNhbnZhcyIpO2kud2lkdGg9MSxpLmhlaWdodD0xO3ZhciBoPWkuZ2V0Q29udGV4dCgiMmQiKTtpZighaCl0aHJvdyBuZXcgRXJyb3IoIkNvdWxkIG5vdCBnZXQgcmVuZGVyaW5nIGNvbnRleHQiKTt0aGlzLl9jdHg9aCx0aGlzLl9jdHguZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSJjb3B5Iix0aGlzLl9saXRtdXNDb2xvcj10aGlzLl9jdHguY3JlYXRlTGluZWFyR3JhZGllbnQoMCwwLDEsMSksdGhpcy5fY29udHJhc3RDYWNoZT1uZXcgby5Db2xvckNvbnRyYXN0Q2FjaGUsdGhpcy5jb2xvcnM9e2ZvcmVncm91bmQ6cyxiYWNrZ3JvdW5kOmEsY3Vyc29yOmMsY3Vyc29yQWNjZW50Omwsc2VsZWN0aW9uVHJhbnNwYXJlbnQ6dSxzZWxlY3Rpb25PcGFxdWU6bi5jb2xvci5ibGVuZChhLHUpLGFuc2k6dC5ERUZBVUxUX0FOU0lfQ09MT1JTLnNsaWNlKCksY29udHJhc3RDYWNoZTp0aGlzLl9jb250cmFzdENhY2hlfSx0aGlzLl91cGRhdGVSZXN0b3JlQ29sb3JzKCl9cmV0dXJuIGUucHJvdG90eXBlLm9uT3B0aW9uc0NoYW5nZT1mdW5jdGlvbihlKXsibWluaW11bUNvbnRyYXN0UmF0aW8iPT09ZSYmdGhpcy5fY29udHJhc3RDYWNoZS5jbGVhcigpfSxlLnByb3RvdHlwZS5zZXRUaGVtZT1mdW5jdGlvbihlKXt2b2lkIDA9PT1lJiYoZT17fSksdGhpcy5jb2xvcnMuZm9yZWdyb3VuZD10aGlzLl9wYXJzZUNvbG9yKGUuZm9yZWdyb3VuZCxzKSx0aGlzLmNvbG9ycy5iYWNrZ3JvdW5kPXRoaXMuX3BhcnNlQ29sb3IoZS5iYWNrZ3JvdW5kLGEpLHRoaXMuY29sb3JzLmN1cnNvcj10aGlzLl9wYXJzZUNvbG9yKGUuY3Vyc29yLGMsITApLHRoaXMuY29sb3JzLmN1cnNvckFjY2VudD10aGlzLl9wYXJzZUNvbG9yKGUuY3Vyc29yQWNjZW50LGwsITApLHRoaXMuY29sb3JzLnNlbGVjdGlvblRyYW5zcGFyZW50PXRoaXMuX3BhcnNlQ29sb3IoZS5zZWxlY3Rpb24sdSwhMCksdGhpcy5jb2xvcnMuc2VsZWN0aW9uT3BhcXVlPW4uY29sb3IuYmxlbmQodGhpcy5jb2xvcnMuYmFja2dyb3VuZCx0aGlzLmNvbG9ycy5zZWxlY3Rpb25UcmFuc3BhcmVudCksbi5jb2xvci5pc09wYXF1ZSh0aGlzLmNvbG9ycy5zZWxlY3Rpb25UcmFuc3BhcmVudCkmJih0aGlzLmNvbG9ycy5zZWxlY3Rpb25UcmFuc3BhcmVudD1uLmNvbG9yLm9wYWNpdHkodGhpcy5jb2xvcnMuc2VsZWN0aW9uVHJhbnNwYXJlbnQsLjMpKSx0aGlzLmNvbG9ycy5hbnNpWzBdPXRoaXMuX3BhcnNlQ29sb3IoZS5ibGFjayx0LkRFRkFVTFRfQU5TSV9DT0xPUlNbMF0pLHRoaXMuY29sb3JzLmFuc2lbMV09dGhpcy5fcGFyc2VDb2xvcihlLnJlZCx0LkRFRkFVTFRfQU5TSV9DT0xPUlNbMV0pLHRoaXMuY29sb3JzLmFuc2lbMl09dGhpcy5fcGFyc2VDb2xvcihlLmdyZWVuLHQuREVGQVVMVF9BTlNJX0NPTE9SU1syXSksdGhpcy5jb2xvcnMuYW5zaVszXT10aGlzLl9wYXJzZUNvbG9yKGUueWVsbG93LHQuREVGQVVMVF9BTlNJX0NPTE9SU1szXSksdGhpcy5jb2xvcnMuYW5zaVs0XT10aGlzLl9wYXJzZUNvbG9yKGUuYmx1ZSx0LkRFRkFVTFRfQU5TSV9DT0xPUlNbNF0pLHRoaXMuY29sb3JzLmFuc2lbNV09dGhpcy5fcGFyc2VDb2xvcihlLm1hZ2VudGEsdC5ERUZBVUxUX0FOU0lfQ09MT1JTWzVdKSx0aGlzLmNvbG9ycy5hbnNpWzZdPXRoaXMuX3BhcnNlQ29sb3IoZS5jeWFuLHQuREVGQVVMVF9BTlNJX0NPTE9SU1s2XSksdGhpcy5jb2xvcnMuYW5zaVs3XT10aGlzLl9wYXJzZUNvbG9yKGUud2hpdGUsdC5ERUZBVUxUX0FOU0lfQ09MT1JTWzddKSx0aGlzLmNvbG9ycy5hbnNpWzhdPXRoaXMuX3BhcnNlQ29sb3IoZS5icmlnaHRCbGFjayx0LkRFRkFVTFRfQU5TSV9DT0xPUlNbOF0pLHRoaXMuY29sb3JzLmFuc2lbOV09dGhpcy5fcGFyc2VDb2xvcihlLmJyaWdodFJlZCx0LkRFRkFVTFRfQU5TSV9DT0xPUlNbOV0pLHRoaXMuY29sb3JzLmFuc2lbMTBdPXRoaXMuX3BhcnNlQ29sb3IoZS5icmlnaHRHcmVlbix0LkRFRkFVTFRfQU5TSV9DT0xPUlNbMTBdKSx0aGlzLmNvbG9ycy5hbnNpWzExXT10aGlzLl9wYXJzZUNvbG9yKGUuYnJpZ2h0WWVsbG93LHQuREVGQVVMVF9BTlNJX0NPTE9SU1sxMV0pLHRoaXMuY29sb3JzLmFuc2lbMTJdPXRoaXMuX3BhcnNlQ29sb3IoZS5icmlnaHRCbHVlLHQuREVGQVVMVF9BTlNJX0NPTE9SU1sxMl0pLHRoaXMuY29sb3JzLmFuc2lbMTNdPXRoaXMuX3BhcnNlQ29sb3IoZS5icmlnaHRNYWdlbnRhLHQuREVGQVVMVF9BTlNJX0NPTE9SU1sxM10pLHRoaXMuY29sb3JzLmFuc2lbMTRdPXRoaXMuX3BhcnNlQ29sb3IoZS5icmlnaHRDeWFuLHQuREVGQVVMVF9BTlNJX0NPTE9SU1sxNF0pLHRoaXMuY29sb3JzLmFuc2lbMTVdPXRoaXMuX3BhcnNlQ29sb3IoZS5icmlnaHRXaGl0ZSx0LkRFRkFVTFRfQU5TSV9DT0xPUlNbMTVdKSx0aGlzLl9jb250cmFzdENhY2hlLmNsZWFyKCksdGhpcy5fdXBkYXRlUmVzdG9yZUNvbG9ycygpfSxlLnByb3RvdHlwZS5yZXN0b3JlQ29sb3I9ZnVuY3Rpb24oZSl7aWYodm9pZCAwIT09ZSlzd2l0Y2goZSl7Y2FzZSAyNTY6dGhpcy5jb2xvcnMuZm9yZWdyb3VuZD10aGlzLl9yZXN0b3JlQ29sb3JzLmZvcmVncm91bmQ7YnJlYWs7Y2FzZSAyNTc6dGhpcy5jb2xvcnMuYmFja2dyb3VuZD10aGlzLl9yZXN0b3JlQ29sb3JzLmJhY2tncm91bmQ7YnJlYWs7Y2FzZSAyNTg6dGhpcy5jb2xvcnMuY3Vyc29yPXRoaXMuX3Jlc3RvcmVDb2xvcnMuY3Vyc29yO2JyZWFrO2RlZmF1bHQ6dGhpcy5jb2xvcnMuYW5zaVtlXT10aGlzLl9yZXN0b3JlQ29sb3JzLmFuc2lbZV19ZWxzZSBmb3IodmFyIHQ9MDt0PHRoaXMuX3Jlc3RvcmVDb2xvcnMuYW5zaS5sZW5ndGg7Kyt0KXRoaXMuY29sb3JzLmFuc2lbdF09dGhpcy5fcmVzdG9yZUNvbG9ycy5hbnNpW3RdfSxlLnByb3RvdHlwZS5fdXBkYXRlUmVzdG9yZUNvbG9ycz1mdW5jdGlvbigpe3RoaXMuX3Jlc3RvcmVDb2xvcnM9e2ZvcmVncm91bmQ6dGhpcy5jb2xvcnMuZm9yZWdyb3VuZCxiYWNrZ3JvdW5kOnRoaXMuY29sb3JzLmJhY2tncm91bmQsY3Vyc29yOnRoaXMuY29sb3JzLmN1cnNvcixhbnNpOmkoW10sdGhpcy5jb2xvcnMuYW5zaSwhMCl9fSxlLnByb3RvdHlwZS5fcGFyc2VDb2xvcj1mdW5jdGlvbihlLHQscil7aWYodm9pZCAwPT09ciYmKHI9dGhpcy5hbGxvd1RyYW5zcGFyZW5jeSksdm9pZCAwPT09ZSlyZXR1cm4gdDtpZih0aGlzLl9jdHguZmlsbFN0eWxlPXRoaXMuX2xpdG11c0NvbG9yLHRoaXMuX2N0eC5maWxsU3R5bGU9ZSwic3RyaW5nIiE9dHlwZW9mIHRoaXMuX2N0eC5maWxsU3R5bGUpcmV0dXJuIGNvbnNvbGUud2FybigiQ29sb3I6ICIrZSsiIGlzIGludmFsaWQgdXNpbmcgZmFsbGJhY2sgIit0LmNzcyksdDt0aGlzLl9jdHguZmlsbFJlY3QoMCwwLDEsMSk7dmFyIGk9dGhpcy5fY3R4LmdldEltYWdlRGF0YSgwLDAsMSwxKS5kYXRhO2lmKDI1NSE9PWlbM10pe2lmKCFyKXJldHVybiBjb25zb2xlLndhcm4oIkNvbG9yOiAiK2UrIiBpcyB1c2luZyB0cmFuc3BhcmVuY3ksIGJ1dCBhbGxvd1RyYW5zcGFyZW5jeSBpcyBmYWxzZS4gVXNpbmcgZmFsbGJhY2sgIit0LmNzcysiLiIpLHQ7dmFyIG89dGhpcy5fY3R4LmZpbGxTdHlsZS5zdWJzdHJpbmcoNSx0aGlzLl9jdHguZmlsbFN0eWxlLmxlbmd0aC0xKS5zcGxpdCgiLCIpLm1hcCgoZnVuY3Rpb24oZSl7cmV0dXJuIE51bWJlcihlKX0pKSxzPW9bMF0sYT1vWzFdLGM9b1syXSxsPW9bM10sdT1NYXRoLnJvdW5kKDI1NSpsKTtyZXR1cm57cmdiYTpuLmNoYW5uZWxzLnRvUmdiYShzLGEsYyx1KSxjc3M6ZX19cmV0dXJue2Nzczp0aGlzLl9jdHguZmlsbFN0eWxlLHJnYmE6bi5jaGFubmVscy50b1JnYmEoaVswXSxpWzFdLGlbMl0saVszXSl9fSxlfSgpO3QuQ29sb3JNYW5hZ2VyPWh9LDk2MzE6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5yZW1vdmVFbGVtZW50RnJvbVBhcmVudD12b2lkIDAsdC5yZW1vdmVFbGVtZW50RnJvbVBhcmVudD1mdW5jdGlvbigpe2Zvcih2YXIgZSx0PVtdLHI9MDtyPGFyZ3VtZW50cy5sZW5ndGg7cisrKXRbcl09YXJndW1lbnRzW3JdO2Zvcih2YXIgaT0wLG49dDtpPG4ubGVuZ3RoO2krKyl7dmFyIG89bltpXTtudWxsPT09KGU9bnVsbD09bz92b2lkIDA6by5wYXJlbnRFbGVtZW50KXx8dm9pZCAwPT09ZXx8ZS5yZW1vdmVDaGlsZChvKX19fSwzNjU2OihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuYWRkRGlzcG9zYWJsZURvbUxpc3RlbmVyPXZvaWQgMCx0LmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcj1mdW5jdGlvbihlLHQscixpKXtlLmFkZEV2ZW50TGlzdGVuZXIodCxyLGkpO3ZhciBuPSExO3JldHVybntkaXNwb3NlOmZ1bmN0aW9uKCl7bnx8KG49ITAsZS5yZW1vdmVFdmVudExpc3RlbmVyKHQscixpKSl9fX19LDM1NTE6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXMmJnRoaXMuX19kZWNvcmF0ZXx8ZnVuY3Rpb24oZSx0LHIsaSl7dmFyIG4sbz1hcmd1bWVudHMubGVuZ3RoLHM9bzwzP3Q6bnVsbD09PWk/aT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHQscik6aTtpZigib2JqZWN0Ij09dHlwZW9mIFJlZmxlY3QmJiJmdW5jdGlvbiI9PXR5cGVvZiBSZWZsZWN0LmRlY29yYXRlKXM9UmVmbGVjdC5kZWNvcmF0ZShlLHQscixpKTtlbHNlIGZvcih2YXIgYT1lLmxlbmd0aC0xO2E+PTA7YS0tKShuPWVbYV0pJiYocz0obzwzP24ocyk6bz4zP24odCxyLHMpOm4odCxyKSl8fHMpO3JldHVybiBvPjMmJnMmJk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LHIscyksc30sbj10aGlzJiZ0aGlzLl9fcGFyYW18fGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIsaSl7dChyLGksZSl9fTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Nb3VzZVpvbmU9dC5MaW5raWZpZXI9dm9pZCAwO3ZhciBvPXIoODQ2MCkscz1yKDI1ODUpLGE9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxyKXt0aGlzLl9idWZmZXJTZXJ2aWNlPWUsdGhpcy5fbG9nU2VydmljZT10LHRoaXMuX3VuaWNvZGVTZXJ2aWNlPXIsdGhpcy5fbGlua01hdGNoZXJzPVtdLHRoaXMuX25leHRMaW5rTWF0Y2hlcklkPTAsdGhpcy5fb25TaG93TGlua1VuZGVybGluZT1uZXcgby5FdmVudEVtaXR0ZXIsdGhpcy5fb25IaWRlTGlua1VuZGVybGluZT1uZXcgby5FdmVudEVtaXR0ZXIsdGhpcy5fb25MaW5rVG9vbHRpcD1uZXcgby5FdmVudEVtaXR0ZXIsdGhpcy5fcm93c1RvTGlua2lmeT17c3RhcnQ6dm9pZCAwLGVuZDp2b2lkIDB9fXJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uU2hvd0xpbmtVbmRlcmxpbmUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25TaG93TGlua1VuZGVybGluZS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uSGlkZUxpbmtVbmRlcmxpbmUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25IaWRlTGlua1VuZGVybGluZS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uTGlua1Rvb2x0aXAiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25MaW5rVG9vbHRpcC5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxlLnByb3RvdHlwZS5hdHRhY2hUb0RvbT1mdW5jdGlvbihlLHQpe3RoaXMuX2VsZW1lbnQ9ZSx0aGlzLl9tb3VzZVpvbmVNYW5hZ2VyPXR9LGUucHJvdG90eXBlLmxpbmtpZnlSb3dzPWZ1bmN0aW9uKHQscil7dmFyIGk9dGhpczt0aGlzLl9tb3VzZVpvbmVNYW5hZ2VyJiYodm9pZCAwPT09dGhpcy5fcm93c1RvTGlua2lmeS5zdGFydHx8dm9pZCAwPT09dGhpcy5fcm93c1RvTGlua2lmeS5lbmQ/KHRoaXMuX3Jvd3NUb0xpbmtpZnkuc3RhcnQ9dCx0aGlzLl9yb3dzVG9MaW5raWZ5LmVuZD1yKToodGhpcy5fcm93c1RvTGlua2lmeS5zdGFydD1NYXRoLm1pbih0aGlzLl9yb3dzVG9MaW5raWZ5LnN0YXJ0LHQpLHRoaXMuX3Jvd3NUb0xpbmtpZnkuZW5kPU1hdGgubWF4KHRoaXMuX3Jvd3NUb0xpbmtpZnkuZW5kLHIpKSx0aGlzLl9tb3VzZVpvbmVNYW5hZ2VyLmNsZWFyQWxsKHQsciksdGhpcy5fcm93c1RpbWVvdXRJZCYmY2xlYXJUaW1lb3V0KHRoaXMuX3Jvd3NUaW1lb3V0SWQpLHRoaXMuX3Jvd3NUaW1lb3V0SWQ9c2V0VGltZW91dCgoZnVuY3Rpb24oKXtyZXR1cm4gaS5fbGlua2lmeVJvd3MoKX0pLGUuX3RpbWVCZWZvcmVMYXRlbmN5KSl9LGUucHJvdG90eXBlLl9saW5raWZ5Um93cz1mdW5jdGlvbigpe3RoaXMuX3Jvd3NUaW1lb3V0SWQ9dm9pZCAwO3ZhciBlPXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyO2lmKHZvaWQgMCE9PXRoaXMuX3Jvd3NUb0xpbmtpZnkuc3RhcnQmJnZvaWQgMCE9PXRoaXMuX3Jvd3NUb0xpbmtpZnkuZW5kKXt2YXIgdD1lLnlkaXNwK3RoaXMuX3Jvd3NUb0xpbmtpZnkuc3RhcnQ7aWYoISh0Pj1lLmxpbmVzLmxlbmd0aCkpe2Zvcih2YXIgcj1lLnlkaXNwK01hdGgubWluKHRoaXMuX3Jvd3NUb0xpbmtpZnkuZW5kLHRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cykrMSxpPU1hdGguY2VpbCgyZTMvdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzKSxuPXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLml0ZXJhdG9yKCExLHQscixpLGkpO24uaGFzTmV4dCgpOylmb3IodmFyIG89bi5uZXh0KCkscz0wO3M8dGhpcy5fbGlua01hdGNoZXJzLmxlbmd0aDtzKyspdGhpcy5fZG9MaW5raWZ5Um93KG8ucmFuZ2UuZmlyc3Qsby5jb250ZW50LHRoaXMuX2xpbmtNYXRjaGVyc1tzXSk7dGhpcy5fcm93c1RvTGlua2lmeS5zdGFydD12b2lkIDAsdGhpcy5fcm93c1RvTGlua2lmeS5lbmQ9dm9pZCAwfX1lbHNlIHRoaXMuX2xvZ1NlcnZpY2UuZGVidWcoIl9yb3dUb0xpbmtpZnkgd2FzIHVuc2V0IGJlZm9yZSBfbGlua2lmeVJvd3Mgd2FzIGNhbGxlZCIpfSxlLnByb3RvdHlwZS5yZWdpc3RlckxpbmtNYXRjaGVyPWZ1bmN0aW9uKGUsdCxyKXtpZih2b2lkIDA9PT1yJiYocj17fSksIXQpdGhyb3cgbmV3IEVycm9yKCJoYW5kbGVyIG11c3QgYmUgZGVmaW5lZCIpO3ZhciBpPXtpZDp0aGlzLl9uZXh0TGlua01hdGNoZXJJZCsrLHJlZ2V4OmUsaGFuZGxlcjp0LG1hdGNoSW5kZXg6ci5tYXRjaEluZGV4LHZhbGlkYXRpb25DYWxsYmFjazpyLnZhbGlkYXRpb25DYWxsYmFjayxob3ZlclRvb2x0aXBDYWxsYmFjazpyLnRvb2x0aXBDYWxsYmFjayxob3ZlckxlYXZlQ2FsbGJhY2s6ci5sZWF2ZUNhbGxiYWNrLHdpbGxMaW5rQWN0aXZhdGU6ci53aWxsTGlua0FjdGl2YXRlLHByaW9yaXR5OnIucHJpb3JpdHl8fDB9O3JldHVybiB0aGlzLl9hZGRMaW5rTWF0Y2hlclRvTGlzdChpKSxpLmlkfSxlLnByb3RvdHlwZS5fYWRkTGlua01hdGNoZXJUb0xpc3Q9ZnVuY3Rpb24oZSl7aWYoMCE9PXRoaXMuX2xpbmtNYXRjaGVycy5sZW5ndGgpe2Zvcih2YXIgdD10aGlzLl9saW5rTWF0Y2hlcnMubGVuZ3RoLTE7dD49MDt0LS0paWYoZS5wcmlvcml0eTw9dGhpcy5fbGlua01hdGNoZXJzW3RdLnByaW9yaXR5KXJldHVybiB2b2lkIHRoaXMuX2xpbmtNYXRjaGVycy5zcGxpY2UodCsxLDAsZSk7dGhpcy5fbGlua01hdGNoZXJzLnNwbGljZSgwLDAsZSl9ZWxzZSB0aGlzLl9saW5rTWF0Y2hlcnMucHVzaChlKX0sZS5wcm90b3R5cGUuZGVyZWdpc3RlckxpbmtNYXRjaGVyPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0wO3Q8dGhpcy5fbGlua01hdGNoZXJzLmxlbmd0aDt0KyspaWYodGhpcy5fbGlua01hdGNoZXJzW3RdLmlkPT09ZSlyZXR1cm4gdGhpcy5fbGlua01hdGNoZXJzLnNwbGljZSh0LDEpLCEwO3JldHVybiExfSxlLnByb3RvdHlwZS5fZG9MaW5raWZ5Um93PWZ1bmN0aW9uKGUsdCxyKXtmb3IodmFyIGksbj10aGlzLG89bmV3IFJlZ0V4cChyLnJlZ2V4LnNvdXJjZSwoci5yZWdleC5mbGFnc3x8IiIpKyJnIikscz0tMSxhPWZ1bmN0aW9uKCl7dmFyIGE9aVsibnVtYmVyIiE9dHlwZW9mIHIubWF0Y2hJbmRleD8wOnIubWF0Y2hJbmRleF07aWYoIWEpcmV0dXJuIGMuX2xvZ1NlcnZpY2UuZGVidWcoIm1hdGNoIGZvdW5kIHdpdGhvdXQgY29ycmVzcG9uZGluZyBtYXRjaEluZGV4IixpLHIpLCJicmVhayI7aWYocz10LmluZGV4T2YoYSxzKzEpLG8ubGFzdEluZGV4PXMrYS5sZW5ndGgsczwwKXJldHVybiJicmVhayI7dmFyIGw9Yy5fYnVmZmVyU2VydmljZS5idWZmZXIuc3RyaW5nSW5kZXhUb0J1ZmZlckluZGV4KGUscyk7aWYobFswXTwwKXJldHVybiJicmVhayI7dmFyIHU9Yy5fYnVmZmVyU2VydmljZS5idWZmZXIubGluZXMuZ2V0KGxbMF0pO2lmKCF1KXJldHVybiJicmVhayI7dmFyIGg9dS5nZXRGZyhsWzFdKSxmPWg/aD4+OSY1MTE6dm9pZCAwO3IudmFsaWRhdGlvbkNhbGxiYWNrP3IudmFsaWRhdGlvbkNhbGxiYWNrKGEsKGZ1bmN0aW9uKGUpe24uX3Jvd3NUaW1lb3V0SWR8fGUmJm4uX2FkZExpbmsobFsxXSxsWzBdLW4uX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwLGEscixmKX0pKTpjLl9hZGRMaW5rKGxbMV0sbFswXS1jLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55ZGlzcCxhLHIsZil9LGM9dGhpcztudWxsIT09KGk9by5leGVjKHQpKSYmImJyZWFrIiE9PWEoKTspO30sZS5wcm90b3R5cGUuX2FkZExpbms9ZnVuY3Rpb24oZSx0LHIsaSxuKXt2YXIgbz10aGlzO2lmKHRoaXMuX21vdXNlWm9uZU1hbmFnZXImJnRoaXMuX2VsZW1lbnQpe3ZhciBzPXRoaXMuX3VuaWNvZGVTZXJ2aWNlLmdldFN0cmluZ0NlbGxXaWR0aChyKSxhPWUldGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLGw9dCtNYXRoLmZsb29yKGUvdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzKSx1PShhK3MpJXRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyxoPWwrTWF0aC5mbG9vcigoYStzKS90aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMpOzA9PT11JiYodT10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsaC0tKSx0aGlzLl9tb3VzZVpvbmVNYW5hZ2VyLmFkZChuZXcgYyhhKzEsbCsxLHUrMSxoKzEsKGZ1bmN0aW9uKGUpe2lmKGkuaGFuZGxlcilyZXR1cm4gaS5oYW5kbGVyKGUscik7dmFyIHQ9d2luZG93Lm9wZW4oKTt0Pyh0Lm9wZW5lcj1udWxsLHQubG9jYXRpb24uaHJlZj1yKTpjb25zb2xlLndhcm4oIk9wZW5pbmcgbGluayBibG9ja2VkIGFzIG9wZW5lciBjb3VsZCBub3QgYmUgY2xlYXJlZCIpfSksKGZ1bmN0aW9uKCl7by5fb25TaG93TGlua1VuZGVybGluZS5maXJlKG8uX2NyZWF0ZUxpbmtIb3ZlckV2ZW50KGEsbCx1LGgsbikpLG8uX2VsZW1lbnQuY2xhc3NMaXN0LmFkZCgieHRlcm0tY3Vyc29yLXBvaW50ZXIiKX0pLChmdW5jdGlvbihlKXtvLl9vbkxpbmtUb29sdGlwLmZpcmUoby5fY3JlYXRlTGlua0hvdmVyRXZlbnQoYSxsLHUsaCxuKSksaS5ob3ZlclRvb2x0aXBDYWxsYmFjayYmaS5ob3ZlclRvb2x0aXBDYWxsYmFjayhlLHIse3N0YXJ0Ont4OmEseTpsfSxlbmQ6e3g6dSx5Omh9fSl9KSwoZnVuY3Rpb24oKXtvLl9vbkhpZGVMaW5rVW5kZXJsaW5lLmZpcmUoby5fY3JlYXRlTGlua0hvdmVyRXZlbnQoYSxsLHUsaCxuKSksby5fZWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKCJ4dGVybS1jdXJzb3ItcG9pbnRlciIpLGkuaG92ZXJMZWF2ZUNhbGxiYWNrJiZpLmhvdmVyTGVhdmVDYWxsYmFjaygpfSksKGZ1bmN0aW9uKGUpe3JldHVybiFpLndpbGxMaW5rQWN0aXZhdGV8fGkud2lsbExpbmtBY3RpdmF0ZShlLHIpfSkpKX19LGUucHJvdG90eXBlLl9jcmVhdGVMaW5rSG92ZXJFdmVudD1mdW5jdGlvbihlLHQscixpLG4pe3JldHVybnt4MTplLHkxOnQseDI6cix5MjppLGNvbHM6dGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLGZnOm59fSxlLl90aW1lQmVmb3JlTGF0ZW5jeT0yMDAsZT1pKFtuKDAscy5JQnVmZmVyU2VydmljZSksbigxLHMuSUxvZ1NlcnZpY2UpLG4oMixzLklVbmljb2RlU2VydmljZSldLGUpfSgpO3QuTGlua2lmaWVyPWE7dmFyIGM9ZnVuY3Rpb24oZSx0LHIsaSxuLG8scyxhLGMpe3RoaXMueDE9ZSx0aGlzLnkxPXQsdGhpcy54Mj1yLHRoaXMueTI9aSx0aGlzLmNsaWNrQ2FsbGJhY2s9bix0aGlzLmhvdmVyQ2FsbGJhY2s9byx0aGlzLnRvb2x0aXBDYWxsYmFjaz1zLHRoaXMubGVhdmVDYWxsYmFjaz1hLHRoaXMud2lsbExpbmtBY3RpdmF0ZT1jfTt0Lk1vdXNlWm9uZT1jfSw2NDY1OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkxpbmtpZmllcjI9dm9pZCAwO3ZhciBhPXIoMjU4NSksYz1yKDg0NjApLGw9cig4NDQpLHU9cigzNjU2KSxoPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIHI9ZS5jYWxsKHRoaXMpfHx0aGlzO3JldHVybiByLl9idWZmZXJTZXJ2aWNlPXQsci5fbGlua1Byb3ZpZGVycz1bXSxyLl9saW5rQ2FjaGVEaXNwb3NhYmxlcz1bXSxyLl9pc01vdXNlT3V0PSEwLHIuX2FjdGl2ZUxpbmU9LTEsci5fb25TaG93TGlua1VuZGVybGluZT1yLnJlZ2lzdGVyKG5ldyBjLkV2ZW50RW1pdHRlciksci5fb25IaWRlTGlua1VuZGVybGluZT1yLnJlZ2lzdGVyKG5ldyBjLkV2ZW50RW1pdHRlciksci5yZWdpc3RlcigoMCxsLmdldERpc3Bvc2VBcnJheURpc3Bvc2FibGUpKHIuX2xpbmtDYWNoZURpc3Bvc2FibGVzKSkscn1yZXR1cm4gbih0LGUpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwiY3VycmVudExpbmsiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fY3VycmVudExpbmt9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvblNob3dMaW5rVW5kZXJsaW5lIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uU2hvd0xpbmtVbmRlcmxpbmUuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvbkhpZGVMaW5rVW5kZXJsaW5lIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uSGlkZUxpbmtVbmRlcmxpbmUuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUucmVnaXN0ZXJMaW5rUHJvdmlkZXI9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcztyZXR1cm4gdGhpcy5fbGlua1Byb3ZpZGVycy5wdXNoKGUpLHtkaXNwb3NlOmZ1bmN0aW9uKCl7dmFyIHI9dC5fbGlua1Byb3ZpZGVycy5pbmRleE9mKGUpOy0xIT09ciYmdC5fbGlua1Byb3ZpZGVycy5zcGxpY2UociwxKX19fSx0LnByb3RvdHlwZS5hdHRhY2hUb0RvbT1mdW5jdGlvbihlLHQscil7dmFyIGk9dGhpczt0aGlzLl9lbGVtZW50PWUsdGhpcy5fbW91c2VTZXJ2aWNlPXQsdGhpcy5fcmVuZGVyU2VydmljZT1yLHRoaXMucmVnaXN0ZXIoKDAsdS5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMuX2VsZW1lbnQsIm1vdXNlbGVhdmUiLChmdW5jdGlvbigpe2kuX2lzTW91c2VPdXQ9ITAsaS5fY2xlYXJDdXJyZW50TGluaygpfSkpKSx0aGlzLnJlZ2lzdGVyKCgwLHUuYWRkRGlzcG9zYWJsZURvbUxpc3RlbmVyKSh0aGlzLl9lbGVtZW50LCJtb3VzZW1vdmUiLHRoaXMuX29uTW91c2VNb3ZlLmJpbmQodGhpcykpKSx0aGlzLnJlZ2lzdGVyKCgwLHUuYWRkRGlzcG9zYWJsZURvbUxpc3RlbmVyKSh0aGlzLl9lbGVtZW50LCJjbGljayIsdGhpcy5fb25DbGljay5iaW5kKHRoaXMpKSl9LHQucHJvdG90eXBlLl9vbk1vdXNlTW92ZT1mdW5jdGlvbihlKXtpZih0aGlzLl9sYXN0TW91c2VFdmVudD1lLHRoaXMuX2VsZW1lbnQmJnRoaXMuX21vdXNlU2VydmljZSl7dmFyIHQ9dGhpcy5fcG9zaXRpb25Gcm9tTW91c2VFdmVudChlLHRoaXMuX2VsZW1lbnQsdGhpcy5fbW91c2VTZXJ2aWNlKTtpZih0KXt0aGlzLl9pc01vdXNlT3V0PSExO2Zvcih2YXIgcj1lLmNvbXBvc2VkUGF0aCgpLGk9MDtpPHIubGVuZ3RoO2krKyl7dmFyIG49cltpXTtpZihuLmNsYXNzTGlzdC5jb250YWlucygieHRlcm0iKSlicmVhaztpZihuLmNsYXNzTGlzdC5jb250YWlucygieHRlcm0taG92ZXIiKSlyZXR1cm59dGhpcy5fbGFzdEJ1ZmZlckNlbGwmJnQueD09PXRoaXMuX2xhc3RCdWZmZXJDZWxsLngmJnQueT09PXRoaXMuX2xhc3RCdWZmZXJDZWxsLnl8fCh0aGlzLl9vbkhvdmVyKHQpLHRoaXMuX2xhc3RCdWZmZXJDZWxsPXQpfX19LHQucHJvdG90eXBlLl9vbkhvdmVyPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2FjdGl2ZUxpbmUhPT1lLnkpcmV0dXJuIHRoaXMuX2NsZWFyQ3VycmVudExpbmsoKSx2b2lkIHRoaXMuX2Fza0ZvckxpbmsoZSwhMSk7dGhpcy5fY3VycmVudExpbmsmJnRoaXMuX2xpbmtBdFBvc2l0aW9uKHRoaXMuX2N1cnJlbnRMaW5rLmxpbmssZSl8fCh0aGlzLl9jbGVhckN1cnJlbnRMaW5rKCksdGhpcy5fYXNrRm9yTGluayhlLCEwKSl9LHQucHJvdG90eXBlLl9hc2tGb3JMaW5rPWZ1bmN0aW9uKGUsdCl7dmFyIHIsaT10aGlzO3RoaXMuX2FjdGl2ZVByb3ZpZGVyUmVwbGllcyYmdHx8KG51bGw9PT0ocj10aGlzLl9hY3RpdmVQcm92aWRlclJlcGxpZXMpfHx2b2lkIDA9PT1yfHxyLmZvckVhY2goKGZ1bmN0aW9uKGUpe251bGw9PWV8fGUuZm9yRWFjaCgoZnVuY3Rpb24oZSl7ZS5saW5rLmRpc3Bvc2UmJmUubGluay5kaXNwb3NlKCl9KSl9KSksdGhpcy5fYWN0aXZlUHJvdmlkZXJSZXBsaWVzPW5ldyBNYXAsdGhpcy5fYWN0aXZlTGluZT1lLnkpO3ZhciBuPSExO3RoaXMuX2xpbmtQcm92aWRlcnMuZm9yRWFjaCgoZnVuY3Rpb24ocixvKXt2YXIgczt0PyhudWxsPT09KHM9aS5fYWN0aXZlUHJvdmlkZXJSZXBsaWVzKXx8dm9pZCAwPT09cz92b2lkIDA6cy5nZXQobykpJiYobj1pLl9jaGVja0xpbmtQcm92aWRlclJlc3VsdChvLGUsbikpOnIucHJvdmlkZUxpbmtzKGUueSwoZnVuY3Rpb24odCl7dmFyIHIscztpZighaS5faXNNb3VzZU91dCl7dmFyIGE9bnVsbD09dD92b2lkIDA6dC5tYXAoKGZ1bmN0aW9uKGUpe3JldHVybntsaW5rOmV9fSkpO251bGw9PT0ocj1pLl9hY3RpdmVQcm92aWRlclJlcGxpZXMpfHx2b2lkIDA9PT1yfHxyLnNldChvLGEpLG49aS5fY2hlY2tMaW5rUHJvdmlkZXJSZXN1bHQobyxlLG4pLChudWxsPT09KHM9aS5fYWN0aXZlUHJvdmlkZXJSZXBsaWVzKXx8dm9pZCAwPT09cz92b2lkIDA6cy5zaXplKT09PWkuX2xpbmtQcm92aWRlcnMubGVuZ3RoJiZpLl9yZW1vdmVJbnRlcnNlY3RpbmdMaW5rcyhlLnksaS5fYWN0aXZlUHJvdmlkZXJSZXBsaWVzKX19KSl9KSl9LHQucHJvdG90eXBlLl9yZW1vdmVJbnRlcnNlY3RpbmdMaW5rcz1mdW5jdGlvbihlLHQpe2Zvcih2YXIgcj1uZXcgU2V0LGk9MDtpPHQuc2l6ZTtpKyspe3ZhciBuPXQuZ2V0KGkpO2lmKG4pZm9yKHZhciBvPTA7bzxuLmxlbmd0aDtvKyspZm9yKHZhciBzPW5bb10sYT1zLmxpbmsucmFuZ2Uuc3RhcnQueTxlPzA6cy5saW5rLnJhbmdlLnN0YXJ0LngsYz1zLmxpbmsucmFuZ2UuZW5kLnk+ZT90aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHM6cy5saW5rLnJhbmdlLmVuZC54LGw9YTtsPD1jO2wrKyl7aWYoci5oYXMobCkpe24uc3BsaWNlKG8tLSwxKTticmVha31yLmFkZChsKX19fSx0LnByb3RvdHlwZS5fY2hlY2tMaW5rUHJvdmlkZXJSZXN1bHQ9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49dGhpcztpZighdGhpcy5fYWN0aXZlUHJvdmlkZXJSZXBsaWVzKXJldHVybiByO2Zvcih2YXIgbz10aGlzLl9hY3RpdmVQcm92aWRlclJlcGxpZXMuZ2V0KGUpLHM9ITEsYT0wO2E8ZTthKyspdGhpcy5fYWN0aXZlUHJvdmlkZXJSZXBsaWVzLmhhcyhhKSYmIXRoaXMuX2FjdGl2ZVByb3ZpZGVyUmVwbGllcy5nZXQoYSl8fChzPSEwKTtpZighcyYmbyl7dmFyIGM9by5maW5kKChmdW5jdGlvbihlKXtyZXR1cm4gbi5fbGlua0F0UG9zaXRpb24oZS5saW5rLHQpfSkpO2MmJihyPSEwLHRoaXMuX2hhbmRsZU5ld0xpbmsoYykpfWlmKHRoaXMuX2FjdGl2ZVByb3ZpZGVyUmVwbGllcy5zaXplPT09dGhpcy5fbGlua1Byb3ZpZGVycy5sZW5ndGgmJiFyKWZvcihhPTA7YTx0aGlzLl9hY3RpdmVQcm92aWRlclJlcGxpZXMuc2l6ZTthKyspe3ZhciBsPW51bGw9PT0oaT10aGlzLl9hY3RpdmVQcm92aWRlclJlcGxpZXMuZ2V0KGEpKXx8dm9pZCAwPT09aT92b2lkIDA6aS5maW5kKChmdW5jdGlvbihlKXtyZXR1cm4gbi5fbGlua0F0UG9zaXRpb24oZS5saW5rLHQpfSkpO2lmKGwpe3I9ITAsdGhpcy5faGFuZGxlTmV3TGluayhsKTticmVha319cmV0dXJuIHJ9LHQucHJvdG90eXBlLl9vbkNsaWNrPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2VsZW1lbnQmJnRoaXMuX21vdXNlU2VydmljZSYmdGhpcy5fY3VycmVudExpbmspe3ZhciB0PXRoaXMuX3Bvc2l0aW9uRnJvbU1vdXNlRXZlbnQoZSx0aGlzLl9lbGVtZW50LHRoaXMuX21vdXNlU2VydmljZSk7dCYmdGhpcy5fbGlua0F0UG9zaXRpb24odGhpcy5fY3VycmVudExpbmsubGluayx0KSYmdGhpcy5fY3VycmVudExpbmsubGluay5hY3RpdmF0ZShlLHRoaXMuX2N1cnJlbnRMaW5rLmxpbmsudGV4dCl9fSx0LnByb3RvdHlwZS5fY2xlYXJDdXJyZW50TGluaz1mdW5jdGlvbihlLHQpe3RoaXMuX2VsZW1lbnQmJnRoaXMuX2N1cnJlbnRMaW5rJiZ0aGlzLl9sYXN0TW91c2VFdmVudCYmKCFlfHwhdHx8dGhpcy5fY3VycmVudExpbmsubGluay5yYW5nZS5zdGFydC55Pj1lJiZ0aGlzLl9jdXJyZW50TGluay5saW5rLnJhbmdlLmVuZC55PD10KSYmKHRoaXMuX2xpbmtMZWF2ZSh0aGlzLl9lbGVtZW50LHRoaXMuX2N1cnJlbnRMaW5rLmxpbmssdGhpcy5fbGFzdE1vdXNlRXZlbnQpLHRoaXMuX2N1cnJlbnRMaW5rPXZvaWQgMCwoMCxsLmRpc3Bvc2VBcnJheSkodGhpcy5fbGlua0NhY2hlRGlzcG9zYWJsZXMpKX0sdC5wcm90b3R5cGUuX2hhbmRsZU5ld0xpbms9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcztpZih0aGlzLl9lbGVtZW50JiZ0aGlzLl9sYXN0TW91c2VFdmVudCYmdGhpcy5fbW91c2VTZXJ2aWNlKXt2YXIgcj10aGlzLl9wb3NpdGlvbkZyb21Nb3VzZUV2ZW50KHRoaXMuX2xhc3RNb3VzZUV2ZW50LHRoaXMuX2VsZW1lbnQsdGhpcy5fbW91c2VTZXJ2aWNlKTtyJiZ0aGlzLl9saW5rQXRQb3NpdGlvbihlLmxpbmsscikmJih0aGlzLl9jdXJyZW50TGluaz1lLHRoaXMuX2N1cnJlbnRMaW5rLnN0YXRlPXtkZWNvcmF0aW9uczp7dW5kZXJsaW5lOnZvaWQgMD09PWUubGluay5kZWNvcmF0aW9uc3x8ZS5saW5rLmRlY29yYXRpb25zLnVuZGVybGluZSxwb2ludGVyQ3Vyc29yOnZvaWQgMD09PWUubGluay5kZWNvcmF0aW9uc3x8ZS5saW5rLmRlY29yYXRpb25zLnBvaW50ZXJDdXJzb3J9LGlzSG92ZXJlZDohMH0sdGhpcy5fbGlua0hvdmVyKHRoaXMuX2VsZW1lbnQsZS5saW5rLHRoaXMuX2xhc3RNb3VzZUV2ZW50KSxlLmxpbmsuZGVjb3JhdGlvbnM9e30sT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoZS5saW5rLmRlY29yYXRpb25zLHtwb2ludGVyQ3Vyc29yOntnZXQ6ZnVuY3Rpb24oKXt2YXIgZSxyO3JldHVybiBudWxsPT09KHI9bnVsbD09PShlPXQuX2N1cnJlbnRMaW5rKXx8dm9pZCAwPT09ZT92b2lkIDA6ZS5zdGF0ZSl8fHZvaWQgMD09PXI/dm9pZCAwOnIuZGVjb3JhdGlvbnMucG9pbnRlckN1cnNvcn0sc2V0OmZ1bmN0aW9uKGUpe3ZhciByLGk7KG51bGw9PT0ocj10Ll9jdXJyZW50TGluayl8fHZvaWQgMD09PXI/dm9pZCAwOnIuc3RhdGUpJiZ0Ll9jdXJyZW50TGluay5zdGF0ZS5kZWNvcmF0aW9ucy5wb2ludGVyQ3Vyc29yIT09ZSYmKHQuX2N1cnJlbnRMaW5rLnN0YXRlLmRlY29yYXRpb25zLnBvaW50ZXJDdXJzb3I9ZSx0Ll9jdXJyZW50TGluay5zdGF0ZS5pc0hvdmVyZWQmJihudWxsPT09KGk9dC5fZWxlbWVudCl8fHZvaWQgMD09PWl8fGkuY2xhc3NMaXN0LnRvZ2dsZSgieHRlcm0tY3Vyc29yLXBvaW50ZXIiLGUpKSl9fSx1bmRlcmxpbmU6e2dldDpmdW5jdGlvbigpe3ZhciBlLHI7cmV0dXJuIG51bGw9PT0ocj1udWxsPT09KGU9dC5fY3VycmVudExpbmspfHx2b2lkIDA9PT1lP3ZvaWQgMDplLnN0YXRlKXx8dm9pZCAwPT09cj92b2lkIDA6ci5kZWNvcmF0aW9ucy51bmRlcmxpbmV9LHNldDpmdW5jdGlvbihyKXt2YXIgaSxuLG87KG51bGw9PT0oaT10Ll9jdXJyZW50TGluayl8fHZvaWQgMD09PWk/dm9pZCAwOmkuc3RhdGUpJiYobnVsbD09PShvPW51bGw9PT0obj10Ll9jdXJyZW50TGluayl8fHZvaWQgMD09PW4/dm9pZCAwOm4uc3RhdGUpfHx2b2lkIDA9PT1vP3ZvaWQgMDpvLmRlY29yYXRpb25zLnVuZGVybGluZSkhPT1yJiYodC5fY3VycmVudExpbmsuc3RhdGUuZGVjb3JhdGlvbnMudW5kZXJsaW5lPXIsdC5fY3VycmVudExpbmsuc3RhdGUuaXNIb3ZlcmVkJiZ0Ll9maXJlVW5kZXJsaW5lRXZlbnQoZS5saW5rLHIpKX19fSksdGhpcy5fcmVuZGVyU2VydmljZSYmdGhpcy5fbGlua0NhY2hlRGlzcG9zYWJsZXMucHVzaCh0aGlzLl9yZW5kZXJTZXJ2aWNlLm9uUmVuZGVyZWRCdWZmZXJDaGFuZ2UoKGZ1bmN0aW9uKGUpe3ZhciByPTA9PT1lLnN0YXJ0PzA6ZS5zdGFydCsxK3QuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwO3QuX2NsZWFyQ3VycmVudExpbmsocixlLmVuZCsxK3QuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwKX0pKSkpfX0sdC5wcm90b3R5cGUuX2xpbmtIb3Zlcj1mdW5jdGlvbihlLHQscil7dmFyIGk7KG51bGw9PT0oaT10aGlzLl9jdXJyZW50TGluayl8fHZvaWQgMD09PWk/dm9pZCAwOmkuc3RhdGUpJiYodGhpcy5fY3VycmVudExpbmsuc3RhdGUuaXNIb3ZlcmVkPSEwLHRoaXMuX2N1cnJlbnRMaW5rLnN0YXRlLmRlY29yYXRpb25zLnVuZGVybGluZSYmdGhpcy5fZmlyZVVuZGVybGluZUV2ZW50KHQsITApLHRoaXMuX2N1cnJlbnRMaW5rLnN0YXRlLmRlY29yYXRpb25zLnBvaW50ZXJDdXJzb3ImJmUuY2xhc3NMaXN0LmFkZCgieHRlcm0tY3Vyc29yLXBvaW50ZXIiKSksdC5ob3ZlciYmdC5ob3ZlcihyLHQudGV4dCl9LHQucHJvdG90eXBlLl9maXJlVW5kZXJsaW5lRXZlbnQ9ZnVuY3Rpb24oZSx0KXt2YXIgcj1lLnJhbmdlLGk9dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueWRpc3Asbj10aGlzLl9jcmVhdGVMaW5rVW5kZXJsaW5lRXZlbnQoci5zdGFydC54LTEsci5zdGFydC55LWktMSxyLmVuZC54LHIuZW5kLnktaS0xLHZvaWQgMCk7KHQ/dGhpcy5fb25TaG93TGlua1VuZGVybGluZTp0aGlzLl9vbkhpZGVMaW5rVW5kZXJsaW5lKS5maXJlKG4pfSx0LnByb3RvdHlwZS5fbGlua0xlYXZlPWZ1bmN0aW9uKGUsdCxyKXt2YXIgaTsobnVsbD09PShpPXRoaXMuX2N1cnJlbnRMaW5rKXx8dm9pZCAwPT09aT92b2lkIDA6aS5zdGF0ZSkmJih0aGlzLl9jdXJyZW50TGluay5zdGF0ZS5pc0hvdmVyZWQ9ITEsdGhpcy5fY3VycmVudExpbmsuc3RhdGUuZGVjb3JhdGlvbnMudW5kZXJsaW5lJiZ0aGlzLl9maXJlVW5kZXJsaW5lRXZlbnQodCwhMSksdGhpcy5fY3VycmVudExpbmsuc3RhdGUuZGVjb3JhdGlvbnMucG9pbnRlckN1cnNvciYmZS5jbGFzc0xpc3QucmVtb3ZlKCJ4dGVybS1jdXJzb3ItcG9pbnRlciIpKSx0LmxlYXZlJiZ0LmxlYXZlKHIsdC50ZXh0KX0sdC5wcm90b3R5cGUuX2xpbmtBdFBvc2l0aW9uPWZ1bmN0aW9uKGUsdCl7dmFyIHI9ZS5yYW5nZS5zdGFydC55PT09ZS5yYW5nZS5lbmQueSxpPWUucmFuZ2Uuc3RhcnQueTx0Lnksbj1lLnJhbmdlLmVuZC55PnQueTtyZXR1cm4ociYmZS5yYW5nZS5zdGFydC54PD10LngmJmUucmFuZ2UuZW5kLng+PXQueHx8aSYmZS5yYW5nZS5lbmQueD49dC54fHxuJiZlLnJhbmdlLnN0YXJ0Lng8PXQueHx8aSYmbikmJmUucmFuZ2Uuc3RhcnQueTw9dC55JiZlLnJhbmdlLmVuZC55Pj10Lnl9LHQucHJvdG90eXBlLl9wb3NpdGlvbkZyb21Nb3VzZUV2ZW50PWZ1bmN0aW9uKGUsdCxyKXt2YXIgaT1yLmdldENvb3JkcyhlLHQsdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLHRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyk7aWYoaSlyZXR1cm57eDppWzBdLHk6aVsxXSt0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55ZGlzcH19LHQucHJvdG90eXBlLl9jcmVhdGVMaW5rVW5kZXJsaW5lRXZlbnQ9ZnVuY3Rpb24oZSx0LHIsaSxuKXtyZXR1cm57eDE6ZSx5MTp0LHgyOnIseTI6aSxjb2xzOnRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyxmZzpufX0sbyhbcygwLGEuSUJ1ZmZlclNlcnZpY2UpXSx0KX0obC5EaXNwb3NhYmxlKTt0LkxpbmtpZmllcjI9aH0sOTA0MjooZSx0KT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnRvb011Y2hPdXRwdXQ9dC5wcm9tcHRMYWJlbD12b2lkIDAsdC5wcm9tcHRMYWJlbD0iVGVybWluYWwgaW5wdXQiLHQudG9vTXVjaE91dHB1dD0iVG9vIG11Y2ggb3V0cHV0IHRvIGFubm91bmNlLCBuYXZpZ2F0ZSB0byByb3dzIG1hbnVhbGx5IHRvIHJlYWQifSw2OTU0OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0Lk1vdXNlWm9uZU1hbmFnZXI9dm9pZCAwO3ZhciBhPXIoODQ0KSxjPXIoMzY1NiksbD1yKDQ3MjUpLHU9cigyNTg1KSxoPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCxyLGksbixvLHMpe3ZhciBhPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gYS5fZWxlbWVudD10LGEuX3NjcmVlbkVsZW1lbnQ9cixhLl9idWZmZXJTZXJ2aWNlPWksYS5fbW91c2VTZXJ2aWNlPW4sYS5fc2VsZWN0aW9uU2VydmljZT1vLGEuX29wdGlvbnNTZXJ2aWNlPXMsYS5fem9uZXM9W10sYS5fYXJlWm9uZXNBY3RpdmU9ITEsYS5fbGFzdEhvdmVyQ29vcmRzPVt2b2lkIDAsdm9pZCAwXSxhLl9pbml0aWFsU2VsZWN0aW9uTGVuZ3RoPTAsYS5yZWdpc3RlcigoMCxjLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikoYS5fZWxlbWVudCwibW91c2Vkb3duIiwoZnVuY3Rpb24oZSl7cmV0dXJuIGEuX29uTW91c2VEb3duKGUpfSkpKSxhLl9tb3VzZU1vdmVMaXN0ZW5lcj1mdW5jdGlvbihlKXtyZXR1cm4gYS5fb25Nb3VzZU1vdmUoZSl9LGEuX21vdXNlTGVhdmVMaXN0ZW5lcj1mdW5jdGlvbihlKXtyZXR1cm4gYS5fb25Nb3VzZUxlYXZlKGUpfSxhLl9jbGlja0xpc3RlbmVyPWZ1bmN0aW9uKGUpe3JldHVybiBhLl9vbkNsaWNrKGUpfSxhfXJldHVybiBuKHQsZSksdC5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe2UucHJvdG90eXBlLmRpc3Bvc2UuY2FsbCh0aGlzKSx0aGlzLl9kZWFjdGl2YXRlKCl9LHQucHJvdG90eXBlLmFkZD1mdW5jdGlvbihlKXt0aGlzLl96b25lcy5wdXNoKGUpLDE9PT10aGlzLl96b25lcy5sZW5ndGgmJnRoaXMuX2FjdGl2YXRlKCl9LHQucHJvdG90eXBlLmNsZWFyQWxsPWZ1bmN0aW9uKGUsdCl7aWYoMCE9PXRoaXMuX3pvbmVzLmxlbmd0aCl7ZSYmdHx8KGU9MCx0PXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cy0xKTtmb3IodmFyIHI9MDtyPHRoaXMuX3pvbmVzLmxlbmd0aDtyKyspe3ZhciBpPXRoaXMuX3pvbmVzW3JdOyhpLnkxPmUmJmkueTE8PXQrMXx8aS55Mj5lJiZpLnkyPD10KzF8fGkueTE8ZSYmaS55Mj50KzEpJiYodGhpcy5fY3VycmVudFpvbmUmJnRoaXMuX2N1cnJlbnRab25lPT09aSYmKHRoaXMuX2N1cnJlbnRab25lLmxlYXZlQ2FsbGJhY2soKSx0aGlzLl9jdXJyZW50Wm9uZT12b2lkIDApLHRoaXMuX3pvbmVzLnNwbGljZShyLS0sMSkpfTA9PT10aGlzLl96b25lcy5sZW5ndGgmJnRoaXMuX2RlYWN0aXZhdGUoKX19LHQucHJvdG90eXBlLl9hY3RpdmF0ZT1mdW5jdGlvbigpe3RoaXMuX2FyZVpvbmVzQWN0aXZlfHwodGhpcy5fYXJlWm9uZXNBY3RpdmU9ITAsdGhpcy5fZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLHRoaXMuX21vdXNlTW92ZUxpc3RlbmVyKSx0aGlzLl9lbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlbGVhdmUiLHRoaXMuX21vdXNlTGVhdmVMaXN0ZW5lciksdGhpcy5fZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsdGhpcy5fY2xpY2tMaXN0ZW5lcikpfSx0LnByb3RvdHlwZS5fZGVhY3RpdmF0ZT1mdW5jdGlvbigpe3RoaXMuX2FyZVpvbmVzQWN0aXZlJiYodGhpcy5fYXJlWm9uZXNBY3RpdmU9ITEsdGhpcy5fZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLHRoaXMuX21vdXNlTW92ZUxpc3RlbmVyKSx0aGlzLl9lbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNlbGVhdmUiLHRoaXMuX21vdXNlTGVhdmVMaXN0ZW5lciksdGhpcy5fZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJjbGljayIsdGhpcy5fY2xpY2tMaXN0ZW5lcikpfSx0LnByb3RvdHlwZS5fb25Nb3VzZU1vdmU9ZnVuY3Rpb24oZSl7dGhpcy5fbGFzdEhvdmVyQ29vcmRzWzBdPT09ZS5wYWdlWCYmdGhpcy5fbGFzdEhvdmVyQ29vcmRzWzFdPT09ZS5wYWdlWXx8KHRoaXMuX29uSG92ZXIoZSksdGhpcy5fbGFzdEhvdmVyQ29vcmRzPVtlLnBhZ2VYLGUucGFnZVldKX0sdC5wcm90b3R5cGUuX29uSG92ZXI9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcyxyPXRoaXMuX2ZpbmRab25lRXZlbnRBdChlKTtyIT09dGhpcy5fY3VycmVudFpvbmUmJih0aGlzLl9jdXJyZW50Wm9uZSYmKHRoaXMuX2N1cnJlbnRab25lLmxlYXZlQ2FsbGJhY2soKSx0aGlzLl9jdXJyZW50Wm9uZT12b2lkIDAsdGhpcy5fdG9vbHRpcFRpbWVvdXQmJmNsZWFyVGltZW91dCh0aGlzLl90b29sdGlwVGltZW91dCkpLHImJih0aGlzLl9jdXJyZW50Wm9uZT1yLHIuaG92ZXJDYWxsYmFjayYmci5ob3ZlckNhbGxiYWNrKGUpLHRoaXMuX3Rvb2x0aXBUaW1lb3V0PXdpbmRvdy5zZXRUaW1lb3V0KChmdW5jdGlvbigpe3JldHVybiB0Ll9vblRvb2x0aXAoZSl9KSx0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmxpbmtUb29sdGlwSG92ZXJEdXJhdGlvbikpKX0sdC5wcm90b3R5cGUuX29uVG9vbHRpcD1mdW5jdGlvbihlKXt0aGlzLl90b29sdGlwVGltZW91dD12b2lkIDA7dmFyIHQ9dGhpcy5fZmluZFpvbmVFdmVudEF0KGUpO251bGw9PXR8fHQudG9vbHRpcENhbGxiYWNrKGUpfSx0LnByb3RvdHlwZS5fb25Nb3VzZURvd249ZnVuY3Rpb24oZSl7aWYodGhpcy5faW5pdGlhbFNlbGVjdGlvbkxlbmd0aD10aGlzLl9nZXRTZWxlY3Rpb25MZW5ndGgoKSx0aGlzLl9hcmVab25lc0FjdGl2ZSl7dmFyIHQ9dGhpcy5fZmluZFpvbmVFdmVudEF0KGUpOyhudWxsPT10P3ZvaWQgMDp0LndpbGxMaW5rQWN0aXZhdGUoZSkpJiYoZS5wcmV2ZW50RGVmYXVsdCgpLGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCkpfX0sdC5wcm90b3R5cGUuX29uTW91c2VMZWF2ZT1mdW5jdGlvbihlKXt0aGlzLl9jdXJyZW50Wm9uZSYmKHRoaXMuX2N1cnJlbnRab25lLmxlYXZlQ2FsbGJhY2soKSx0aGlzLl9jdXJyZW50Wm9uZT12b2lkIDAsdGhpcy5fdG9vbHRpcFRpbWVvdXQmJmNsZWFyVGltZW91dCh0aGlzLl90b29sdGlwVGltZW91dCkpfSx0LnByb3RvdHlwZS5fb25DbGljaz1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9maW5kWm9uZUV2ZW50QXQoZSkscj10aGlzLl9nZXRTZWxlY3Rpb25MZW5ndGgoKTt0JiZyPT09dGhpcy5faW5pdGlhbFNlbGVjdGlvbkxlbmd0aCYmKHQuY2xpY2tDYWxsYmFjayhlKSxlLnByZXZlbnREZWZhdWx0KCksZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKSl9LHQucHJvdG90eXBlLl9nZXRTZWxlY3Rpb25MZW5ndGg9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdGlvblRleHQ7cmV0dXJuIGU/ZS5sZW5ndGg6MH0sdC5wcm90b3R5cGUuX2ZpbmRab25lRXZlbnRBdD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9tb3VzZVNlcnZpY2UuZ2V0Q29vcmRzKGUsdGhpcy5fc2NyZWVuRWxlbWVudCx0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsdGhpcy5fYnVmZmVyU2VydmljZS5yb3dzKTtpZih0KWZvcih2YXIgcj10WzBdLGk9dFsxXSxuPTA7bjx0aGlzLl96b25lcy5sZW5ndGg7bisrKXt2YXIgbz10aGlzLl96b25lc1tuXTtpZihvLnkxPT09by55Mil7aWYoaT09PW8ueTEmJnI+PW8ueDEmJnI8by54MilyZXR1cm4gb31lbHNlIGlmKGk9PT1vLnkxJiZyPj1vLngxfHxpPT09by55MiYmcjxvLngyfHxpPm8ueTEmJmk8by55MilyZXR1cm4gb319LG8oW3MoMix1LklCdWZmZXJTZXJ2aWNlKSxzKDMsbC5JTW91c2VTZXJ2aWNlKSxzKDQsbC5JU2VsZWN0aW9uU2VydmljZSkscyg1LHUuSU9wdGlvbnNTZXJ2aWNlKV0sdCl9KGEuRGlzcG9zYWJsZSk7dC5Nb3VzZVpvbmVNYW5hZ2VyPWh9LDYxOTM6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5SZW5kZXJEZWJvdW5jZXI9dm9pZCAwO3ZhciByPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLl9yZW5kZXJDYWxsYmFjaz1lfXJldHVybiBlLnByb3RvdHlwZS5kaXNwb3NlPWZ1bmN0aW9uKCl7dGhpcy5fYW5pbWF0aW9uRnJhbWUmJih3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUodGhpcy5fYW5pbWF0aW9uRnJhbWUpLHRoaXMuX2FuaW1hdGlvbkZyYW1lPXZvaWQgMCl9LGUucHJvdG90eXBlLnJlZnJlc2g9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXM7dGhpcy5fcm93Q291bnQ9cixlPXZvaWQgMCE9PWU/ZTowLHQ9dm9pZCAwIT09dD90OnRoaXMuX3Jvd0NvdW50LTEsdGhpcy5fcm93U3RhcnQ9dm9pZCAwIT09dGhpcy5fcm93U3RhcnQ/TWF0aC5taW4odGhpcy5fcm93U3RhcnQsZSk6ZSx0aGlzLl9yb3dFbmQ9dm9pZCAwIT09dGhpcy5fcm93RW5kP01hdGgubWF4KHRoaXMuX3Jvd0VuZCx0KTp0LHRoaXMuX2FuaW1hdGlvbkZyYW1lfHwodGhpcy5fYW5pbWF0aW9uRnJhbWU9d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoZnVuY3Rpb24oKXtyZXR1cm4gaS5faW5uZXJSZWZyZXNoKCl9KSkpfSxlLnByb3RvdHlwZS5faW5uZXJSZWZyZXNoPWZ1bmN0aW9uKCl7aWYodm9pZCAwIT09dGhpcy5fcm93U3RhcnQmJnZvaWQgMCE9PXRoaXMuX3Jvd0VuZCYmdm9pZCAwIT09dGhpcy5fcm93Q291bnQpe3ZhciBlPU1hdGgubWF4KHRoaXMuX3Jvd1N0YXJ0LDApLHQ9TWF0aC5taW4odGhpcy5fcm93RW5kLHRoaXMuX3Jvd0NvdW50LTEpO3RoaXMuX3Jvd1N0YXJ0PXZvaWQgMCx0aGlzLl9yb3dFbmQ9dm9pZCAwLHRoaXMuX2FuaW1hdGlvbkZyYW1lPXZvaWQgMCx0aGlzLl9yZW5kZXJDYWxsYmFjayhlLHQpfX0sZX0oKTt0LlJlbmRlckRlYm91bmNlcj1yfSw1NTk2OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlNjcmVlbkRwck1vbml0b3I9dm9pZCAwO3ZhciBvPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXt2YXIgdD1udWxsIT09ZSYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXM7cmV0dXJuIHQuX2N1cnJlbnREZXZpY2VQaXhlbFJhdGlvPXdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLHR9cmV0dXJuIG4odCxlKSx0LnByb3RvdHlwZS5zZXRMaXN0ZW5lcj1mdW5jdGlvbihlKXt2YXIgdD10aGlzO3RoaXMuX2xpc3RlbmVyJiZ0aGlzLmNsZWFyTGlzdGVuZXIoKSx0aGlzLl9saXN0ZW5lcj1lLHRoaXMuX291dGVyTGlzdGVuZXI9ZnVuY3Rpb24oKXt0Ll9saXN0ZW5lciYmKHQuX2xpc3RlbmVyKHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLHQuX2N1cnJlbnREZXZpY2VQaXhlbFJhdGlvKSx0Ll91cGRhdGVEcHIoKSl9LHRoaXMuX3VwZGF0ZURwcigpfSx0LnByb3RvdHlwZS5kaXNwb3NlPWZ1bmN0aW9uKCl7ZS5wcm90b3R5cGUuZGlzcG9zZS5jYWxsKHRoaXMpLHRoaXMuY2xlYXJMaXN0ZW5lcigpfSx0LnByb3RvdHlwZS5fdXBkYXRlRHByPWZ1bmN0aW9uKCl7dmFyIGU7dGhpcy5fb3V0ZXJMaXN0ZW5lciYmKG51bGw9PT0oZT10aGlzLl9yZXNvbHV0aW9uTWVkaWFNYXRjaExpc3QpfHx2b2lkIDA9PT1lfHxlLnJlbW92ZUxpc3RlbmVyKHRoaXMuX291dGVyTGlzdGVuZXIpLHRoaXMuX2N1cnJlbnREZXZpY2VQaXhlbFJhdGlvPXdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLHRoaXMuX3Jlc29sdXRpb25NZWRpYU1hdGNoTGlzdD13aW5kb3cubWF0Y2hNZWRpYSgic2NyZWVuIGFuZCAocmVzb2x1dGlvbjogIit3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbysiZHBweCkiKSx0aGlzLl9yZXNvbHV0aW9uTWVkaWFNYXRjaExpc3QuYWRkTGlzdGVuZXIodGhpcy5fb3V0ZXJMaXN0ZW5lcikpfSx0LnByb3RvdHlwZS5jbGVhckxpc3RlbmVyPWZ1bmN0aW9uKCl7dGhpcy5fcmVzb2x1dGlvbk1lZGlhTWF0Y2hMaXN0JiZ0aGlzLl9saXN0ZW5lciYmdGhpcy5fb3V0ZXJMaXN0ZW5lciYmKHRoaXMuX3Jlc29sdXRpb25NZWRpYU1hdGNoTGlzdC5yZW1vdmVMaXN0ZW5lcih0aGlzLl9vdXRlckxpc3RlbmVyKSx0aGlzLl9yZXNvbHV0aW9uTWVkaWFNYXRjaExpc3Q9dm9pZCAwLHRoaXMuX2xpc3RlbmVyPXZvaWQgMCx0aGlzLl9vdXRlckxpc3RlbmVyPXZvaWQgMCl9LHR9KHIoODQ0KS5EaXNwb3NhYmxlKTt0LlNjcmVlbkRwck1vbml0b3I9b30sMzIzNjpmdW5jdGlvbihlLHQscil7dmFyIGksbj10aGlzJiZ0aGlzLl9fZXh0ZW5kc3x8KGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gaT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIHIgaW4gdClPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxyKSYmKGVbcl09dFtyXSl9LGkoZSx0KX0sZnVuY3Rpb24oZSx0KXtpZigiZnVuY3Rpb24iIT10eXBlb2YgdCYmbnVsbCE9PXQpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2xhc3MgZXh0ZW5kcyB2YWx1ZSAiK1N0cmluZyh0KSsiIGlzIG5vdCBhIGNvbnN0cnVjdG9yIG9yIG51bGwiKTtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj1lfWkoZSx0KSxlLnByb3RvdHlwZT1udWxsPT09dD9PYmplY3QuY3JlYXRlKHQpOihyLnByb3RvdHlwZT10LnByb3RvdHlwZSxuZXcgcil9KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5UZXJtaW5hbD12b2lkIDA7dmFyIG89cigyOTUwKSxzPXIoMTY4MCksYT1yKDM2MTQpLGM9cigyNTg0KSxsPXIoNTQzNSksdT1yKDM1MjUpLGg9cigzNTUxKSxmPXIoOTMxMiksXz1yKDYxMTQpLGQ9cigzNjU2KSxwPXIoOTA0Miksdj1yKDM1NyksZz1yKDY5NTQpLHk9cig0NTY3KSxtPXIoMTI5NiksYj1yKDczOTkpLFM9cig4NDYwKSxDPXIoODQzNyksdz1yKDU2ODApLEw9cigzMjMwKSxFPXIoNDcyNSkseD1yKDQyOCksQT1yKDg5MzQpLGs9cig2NDY1KSxNPXIoNTExNCksUj1yKDg5NjkpLFQ9cig0Nzc0KSxPPXIoNDI2OSksQj1yKDU5NDEpLEQ9InVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3c/d2luZG93LmRvY3VtZW50Om51bGwsUD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3ZvaWQgMD09PXQmJih0PXt9KTt2YXIgcj1lLmNhbGwodGhpcyx0KXx8dGhpcztyZXR1cm4gci5icm93c2VyPV8sci5fa2V5RG93bkhhbmRsZWQ9ITEsci5fa2V5UHJlc3NIYW5kbGVkPSExLHIuX3VucHJvY2Vzc2VkRGVhZEtleT0hMSxyLl9vbkN1cnNvck1vdmU9bmV3IFMuRXZlbnRFbWl0dGVyLHIuX29uS2V5PW5ldyBTLkV2ZW50RW1pdHRlcixyLl9vblJlbmRlcj1uZXcgUy5FdmVudEVtaXR0ZXIsci5fb25TZWxlY3Rpb25DaGFuZ2U9bmV3IFMuRXZlbnRFbWl0dGVyLHIuX29uVGl0bGVDaGFuZ2U9bmV3IFMuRXZlbnRFbWl0dGVyLHIuX29uQmVsbD1uZXcgUy5FdmVudEVtaXR0ZXIsci5fb25Gb2N1cz1uZXcgUy5FdmVudEVtaXR0ZXIsci5fb25CbHVyPW5ldyBTLkV2ZW50RW1pdHRlcixyLl9vbkExMXlDaGFyRW1pdHRlcj1uZXcgUy5FdmVudEVtaXR0ZXIsci5fb25BMTF5VGFiRW1pdHRlcj1uZXcgUy5FdmVudEVtaXR0ZXIsci5fc2V0dXAoKSxyLmxpbmtpZmllcj1yLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZShoLkxpbmtpZmllciksci5saW5raWZpZXIyPXIucmVnaXN0ZXIoci5faW5zdGFudGlhdGlvblNlcnZpY2UuY3JlYXRlSW5zdGFuY2Uoay5MaW5raWZpZXIyKSksci5yZWdpc3RlcihyLl9pbnB1dEhhbmRsZXIub25SZXF1ZXN0QmVsbCgoZnVuY3Rpb24oKXtyZXR1cm4gci5iZWxsKCl9KSkpLHIucmVnaXN0ZXIoci5faW5wdXRIYW5kbGVyLm9uUmVxdWVzdFJlZnJlc2hSb3dzKChmdW5jdGlvbihlLHQpe3JldHVybiByLnJlZnJlc2goZSx0KX0pKSksci5yZWdpc3RlcihyLl9pbnB1dEhhbmRsZXIub25SZXF1ZXN0U2VuZEZvY3VzKChmdW5jdGlvbigpe3JldHVybiByLl9yZXBvcnRGb2N1cygpfSkpKSxyLnJlZ2lzdGVyKHIuX2lucHV0SGFuZGxlci5vblJlcXVlc3RSZXNldCgoZnVuY3Rpb24oKXtyZXR1cm4gci5yZXNldCgpfSkpKSxyLnJlZ2lzdGVyKHIuX2lucHV0SGFuZGxlci5vblJlcXVlc3RXaW5kb3dzT3B0aW9uc1JlcG9ydCgoZnVuY3Rpb24oZSl7cmV0dXJuIHIuX3JlcG9ydFdpbmRvd3NPcHRpb25zKGUpfSkpKSxyLnJlZ2lzdGVyKHIuX2lucHV0SGFuZGxlci5vbkNvbG9yKChmdW5jdGlvbihlKXtyZXR1cm4gci5faGFuZGxlQ29sb3JFdmVudChlKX0pKSksci5yZWdpc3RlcigoMCxTLmZvcndhcmRFdmVudCkoci5faW5wdXRIYW5kbGVyLm9uQ3Vyc29yTW92ZSxyLl9vbkN1cnNvck1vdmUpKSxyLnJlZ2lzdGVyKCgwLFMuZm9yd2FyZEV2ZW50KShyLl9pbnB1dEhhbmRsZXIub25UaXRsZUNoYW5nZSxyLl9vblRpdGxlQ2hhbmdlKSksci5yZWdpc3RlcigoMCxTLmZvcndhcmRFdmVudCkoci5faW5wdXRIYW5kbGVyLm9uQTExeUNoYXIsci5fb25BMTF5Q2hhckVtaXR0ZXIpKSxyLnJlZ2lzdGVyKCgwLFMuZm9yd2FyZEV2ZW50KShyLl9pbnB1dEhhbmRsZXIub25BMTF5VGFiLHIuX29uQTExeVRhYkVtaXR0ZXIpKSxyLnJlZ2lzdGVyKHIuX2J1ZmZlclNlcnZpY2Uub25SZXNpemUoKGZ1bmN0aW9uKGUpe3JldHVybiByLl9hZnRlclJlc2l6ZShlLmNvbHMsZS5yb3dzKX0pKSkscn1yZXR1cm4gbih0LGUpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25DdXJzb3JNb3ZlIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uQ3Vyc29yTW92ZS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uS2V5Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uS2V5LmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25SZW5kZXIiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25SZW5kZXIuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvblNlbGVjdGlvbkNoYW5nZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vblNlbGVjdGlvbkNoYW5nZS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uVGl0bGVDaGFuZ2UiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25UaXRsZUNoYW5nZS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uQmVsbCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vbkJlbGwuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvbkZvY3VzIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uRm9jdXMuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvbkJsdXIiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25CbHVyLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25BMTF5Q2hhciIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vbkExMXlDaGFyRW1pdHRlci5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uQTExeVRhYiIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vbkExMXlUYWJFbWl0dGVyLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLHQucHJvdG90eXBlLl9oYW5kbGVDb2xvckV2ZW50PWZ1bmN0aW9uKGUpe3ZhciB0LHI7aWYodGhpcy5fY29sb3JNYW5hZ2VyKXtmb3IodmFyIGk9MCxuPWU7aTxuLmxlbmd0aDtpKyspe3ZhciBvPW5baV0scz12b2lkIDAsYT0iIjtzd2l0Y2goby5pbmRleCl7Y2FzZSAyNTY6cz0iZm9yZWdyb3VuZCIsYT0iMTAiO2JyZWFrO2Nhc2UgMjU3OnM9ImJhY2tncm91bmQiLGE9IjExIjticmVhaztjYXNlIDI1ODpzPSJjdXJzb3IiLGE9IjEyIjticmVhaztkZWZhdWx0OnM9ImFuc2kiLGE9IjQ7IitvLmluZGV4fWlmKHMpc3dpdGNoKG8udHlwZSl7Y2FzZSAwOnZhciBsPVQuY29sb3IudG9Db2xvclJHQigiYW5zaSI9PT1zP3RoaXMuX2NvbG9yTWFuYWdlci5jb2xvcnMuYW5zaVtvLmluZGV4XTp0aGlzLl9jb2xvck1hbmFnZXIuY29sb3JzW3NdKTt0aGlzLmNvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQoYy5DMC5FU0MrIl0iK2ErIjsiKygwLEIudG9SZ2JTdHJpbmcpKGwpK2MuQzAuQkVMKTticmVhaztjYXNlIDE6ImFuc2kiPT09cz90aGlzLl9jb2xvck1hbmFnZXIuY29sb3JzLmFuc2lbby5pbmRleF09VC5yZ2JhLnRvQ29sb3IuYXBwbHkoVC5yZ2JhLG8uY29sb3IpOnRoaXMuX2NvbG9yTWFuYWdlci5jb2xvcnNbc109VC5yZ2JhLnRvQ29sb3IuYXBwbHkoVC5yZ2JhLG8uY29sb3IpO2JyZWFrO2Nhc2UgMjp0aGlzLl9jb2xvck1hbmFnZXIucmVzdG9yZUNvbG9yKG8uaW5kZXgpfX1udWxsPT09KHQ9dGhpcy5fcmVuZGVyU2VydmljZSl8fHZvaWQgMD09PXR8fHQuc2V0Q29sb3JzKHRoaXMuX2NvbG9yTWFuYWdlci5jb2xvcnMpLG51bGw9PT0ocj10aGlzLnZpZXdwb3J0KXx8dm9pZCAwPT09cnx8ci5vblRoZW1lQ2hhbmdlKHRoaXMuX2NvbG9yTWFuYWdlci5jb2xvcnMpfX0sdC5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe3ZhciB0LHIsaTt0aGlzLl9pc0Rpc3Bvc2VkfHwoZS5wcm90b3R5cGUuZGlzcG9zZS5jYWxsKHRoaXMpLG51bGw9PT0odD10aGlzLl9yZW5kZXJTZXJ2aWNlKXx8dm9pZCAwPT09dHx8dC5kaXNwb3NlKCksdGhpcy5fY3VzdG9tS2V5RXZlbnRIYW5kbGVyPXZvaWQgMCx0aGlzLndyaXRlPWZ1bmN0aW9uKCl7fSxudWxsPT09KGk9bnVsbD09PShyPXRoaXMuZWxlbWVudCl8fHZvaWQgMD09PXI/dm9pZCAwOnIucGFyZW50Tm9kZSl8fHZvaWQgMD09PWl8fGkucmVtb3ZlQ2hpbGQodGhpcy5lbGVtZW50KSl9LHQucHJvdG90eXBlLl9zZXR1cD1mdW5jdGlvbigpe2UucHJvdG90eXBlLl9zZXR1cC5jYWxsKHRoaXMpLHRoaXMuX2N1c3RvbUtleUV2ZW50SGFuZGxlcj12b2lkIDB9LE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwiYnVmZmVyIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYnVmZmVycy5hY3RpdmV9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuZm9jdXM9ZnVuY3Rpb24oKXt0aGlzLnRleHRhcmVhJiZ0aGlzLnRleHRhcmVhLmZvY3VzKHtwcmV2ZW50U2Nyb2xsOiEwfSl9LHQucHJvdG90eXBlLl91cGRhdGVPcHRpb25zPWZ1bmN0aW9uKHQpe3ZhciByLGksbixvO3N3aXRjaChlLnByb3RvdHlwZS5fdXBkYXRlT3B0aW9ucy5jYWxsKHRoaXMsdCksdCl7Y2FzZSJmb250RmFtaWx5IjpjYXNlImZvbnRTaXplIjpudWxsPT09KHI9dGhpcy5fcmVuZGVyU2VydmljZSl8fHZvaWQgMD09PXJ8fHIuY2xlYXIoKSxudWxsPT09KGk9dGhpcy5fY2hhclNpemVTZXJ2aWNlKXx8dm9pZCAwPT09aXx8aS5tZWFzdXJlKCk7YnJlYWs7Y2FzZSJjdXJzb3JCbGluayI6Y2FzZSJjdXJzb3JTdHlsZSI6dGhpcy5yZWZyZXNoKHRoaXMuYnVmZmVyLnksdGhpcy5idWZmZXIueSk7YnJlYWs7Y2FzZSJjdXN0b21HbHlwaHMiOmNhc2UiZHJhd0JvbGRUZXh0SW5CcmlnaHRDb2xvcnMiOmNhc2UibGV0dGVyU3BhY2luZyI6Y2FzZSJsaW5lSGVpZ2h0IjpjYXNlImZvbnRXZWlnaHQiOmNhc2UiZm9udFdlaWdodEJvbGQiOmNhc2UibWluaW11bUNvbnRyYXN0UmF0aW8iOnRoaXMuX3JlbmRlclNlcnZpY2UmJih0aGlzLl9yZW5kZXJTZXJ2aWNlLmNsZWFyKCksdGhpcy5fcmVuZGVyU2VydmljZS5vblJlc2l6ZSh0aGlzLmNvbHMsdGhpcy5yb3dzKSx0aGlzLnJlZnJlc2goMCx0aGlzLnJvd3MtMSkpO2JyZWFrO2Nhc2UicmVuZGVyZXJUeXBlIjp0aGlzLl9yZW5kZXJTZXJ2aWNlJiYodGhpcy5fcmVuZGVyU2VydmljZS5zZXRSZW5kZXJlcih0aGlzLl9jcmVhdGVSZW5kZXJlcigpKSx0aGlzLl9yZW5kZXJTZXJ2aWNlLm9uUmVzaXplKHRoaXMuY29scyx0aGlzLnJvd3MpKTticmVhaztjYXNlInNjcm9sbGJhY2siOm51bGw9PT0obj10aGlzLnZpZXdwb3J0KXx8dm9pZCAwPT09bnx8bi5zeW5jU2Nyb2xsQXJlYSgpO2JyZWFrO2Nhc2Uic2NyZWVuUmVhZGVyTW9kZSI6dGhpcy5vcHRpb25zU2VydmljZS5vcHRpb25zLnNjcmVlblJlYWRlck1vZGU/IXRoaXMuX2FjY2Vzc2liaWxpdHlNYW5hZ2VyJiZ0aGlzLl9yZW5kZXJTZXJ2aWNlJiYodGhpcy5fYWNjZXNzaWJpbGl0eU1hbmFnZXI9bmV3IHkuQWNjZXNzaWJpbGl0eU1hbmFnZXIodGhpcyx0aGlzLl9yZW5kZXJTZXJ2aWNlKSk6KG51bGw9PT0obz10aGlzLl9hY2Nlc3NpYmlsaXR5TWFuYWdlcil8fHZvaWQgMD09PW98fG8uZGlzcG9zZSgpLHRoaXMuX2FjY2Vzc2liaWxpdHlNYW5hZ2VyPXZvaWQgMCk7YnJlYWs7Y2FzZSJ0YWJTdG9wV2lkdGgiOnRoaXMuYnVmZmVycy5zZXR1cFRhYlN0b3BzKCk7YnJlYWs7Y2FzZSJ0aGVtZSI6dGhpcy5fc2V0VGhlbWUodGhpcy5vcHRpb25zU2VydmljZS5vcHRpb25zLnRoZW1lKX19LHQucHJvdG90eXBlLl9vblRleHRBcmVhRm9jdXM9ZnVuY3Rpb24oZSl7dGhpcy5jb3JlU2VydmljZS5kZWNQcml2YXRlTW9kZXMuc2VuZEZvY3VzJiZ0aGlzLmNvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQoYy5DMC5FU0MrIltJIiksdGhpcy51cGRhdGVDdXJzb3JTdHlsZShlKSx0aGlzLmVsZW1lbnQuY2xhc3NMaXN0LmFkZCgiZm9jdXMiKSx0aGlzLl9zaG93Q3Vyc29yKCksdGhpcy5fb25Gb2N1cy5maXJlKCl9LHQucHJvdG90eXBlLmJsdXI9ZnVuY3Rpb24oKXt2YXIgZTtyZXR1cm4gbnVsbD09PShlPXRoaXMudGV4dGFyZWEpfHx2b2lkIDA9PT1lP3ZvaWQgMDplLmJsdXIoKX0sdC5wcm90b3R5cGUuX29uVGV4dEFyZWFCbHVyPWZ1bmN0aW9uKCl7dGhpcy50ZXh0YXJlYS52YWx1ZT0iIix0aGlzLnJlZnJlc2godGhpcy5idWZmZXIueSx0aGlzLmJ1ZmZlci55KSx0aGlzLmNvcmVTZXJ2aWNlLmRlY1ByaXZhdGVNb2Rlcy5zZW5kRm9jdXMmJnRoaXMuY29yZVNlcnZpY2UudHJpZ2dlckRhdGFFdmVudChjLkMwLkVTQysiW08iKSx0aGlzLmVsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZSgiZm9jdXMiKSx0aGlzLl9vbkJsdXIuZmlyZSgpfSx0LnByb3RvdHlwZS5fc3luY1RleHRBcmVhPWZ1bmN0aW9uKCl7aWYodGhpcy50ZXh0YXJlYSYmdGhpcy5idWZmZXIuaXNDdXJzb3JJblZpZXdwb3J0JiYhdGhpcy5fY29tcG9zaXRpb25IZWxwZXIuaXNDb21wb3NpbmcmJnRoaXMuX3JlbmRlclNlcnZpY2Upe3ZhciBlPXRoaXMuYnVmZmVyLnliYXNlK3RoaXMuYnVmZmVyLnksdD10aGlzLmJ1ZmZlci5saW5lcy5nZXQoZSk7aWYodCl7dmFyIHI9TWF0aC5taW4odGhpcy5idWZmZXIueCx0aGlzLmNvbHMtMSksaT10aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbEhlaWdodCxuPXQuZ2V0V2lkdGgociksbz10aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbFdpZHRoKm4scz10aGlzLmJ1ZmZlci55KnRoaXMuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0LGE9cip0aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbFdpZHRoO3RoaXMudGV4dGFyZWEuc3R5bGUubGVmdD1hKyJweCIsdGhpcy50ZXh0YXJlYS5zdHlsZS50b3A9cysicHgiLHRoaXMudGV4dGFyZWEuc3R5bGUud2lkdGg9bysicHgiLHRoaXMudGV4dGFyZWEuc3R5bGUuaGVpZ2h0PWkrInB4Iix0aGlzLnRleHRhcmVhLnN0eWxlLmxpbmVIZWlnaHQ9aSsicHgiLHRoaXMudGV4dGFyZWEuc3R5bGUuekluZGV4PSItNSJ9fX0sdC5wcm90b3R5cGUuX2luaXRHbG9iYWw9ZnVuY3Rpb24oKXt2YXIgZT10aGlzO3RoaXMuX2JpbmRLZXlzKCksdGhpcy5yZWdpc3RlcigoMCxkLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikodGhpcy5lbGVtZW50LCJjb3B5IiwoZnVuY3Rpb24odCl7ZS5oYXNTZWxlY3Rpb24oKSYmKDAsYS5jb3B5SGFuZGxlcikodCxlLl9zZWxlY3Rpb25TZXJ2aWNlKX0pKSk7dmFyIHQ9ZnVuY3Rpb24odCl7cmV0dXJuKDAsYS5oYW5kbGVQYXN0ZUV2ZW50KSh0LGUudGV4dGFyZWEsZS5jb3JlU2VydmljZSl9O3RoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMudGV4dGFyZWEsInBhc3RlIix0KSksdGhpcy5yZWdpc3RlcigoMCxkLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikodGhpcy5lbGVtZW50LCJwYXN0ZSIsdCkpLF8uaXNGaXJlZm94P3RoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMuZWxlbWVudCwibW91c2Vkb3duIiwoZnVuY3Rpb24odCl7Mj09PXQuYnV0dG9uJiYoMCxhLnJpZ2h0Q2xpY2tIYW5kbGVyKSh0LGUudGV4dGFyZWEsZS5zY3JlZW5FbGVtZW50LGUuX3NlbGVjdGlvblNlcnZpY2UsZS5vcHRpb25zLnJpZ2h0Q2xpY2tTZWxlY3RzV29yZCl9KSkpOnRoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMuZWxlbWVudCwiY29udGV4dG1lbnUiLChmdW5jdGlvbih0KXsoMCxhLnJpZ2h0Q2xpY2tIYW5kbGVyKSh0LGUudGV4dGFyZWEsZS5zY3JlZW5FbGVtZW50LGUuX3NlbGVjdGlvblNlcnZpY2UsZS5vcHRpb25zLnJpZ2h0Q2xpY2tTZWxlY3RzV29yZCl9KSkpLF8uaXNMaW51eCYmdGhpcy5yZWdpc3RlcigoMCxkLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikodGhpcy5lbGVtZW50LCJhdXhjbGljayIsKGZ1bmN0aW9uKHQpezE9PT10LmJ1dHRvbiYmKDAsYS5tb3ZlVGV4dEFyZWFVbmRlck1vdXNlQ3Vyc29yKSh0LGUudGV4dGFyZWEsZS5zY3JlZW5FbGVtZW50KX0pKSl9LHQucHJvdG90eXBlLl9iaW5kS2V5cz1mdW5jdGlvbigpe3ZhciBlPXRoaXM7dGhpcy5yZWdpc3RlcigoMCxkLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikodGhpcy50ZXh0YXJlYSwia2V5dXAiLChmdW5jdGlvbih0KXtyZXR1cm4gZS5fa2V5VXAodCl9KSwhMCkpLHRoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMudGV4dGFyZWEsImtleWRvd24iLChmdW5jdGlvbih0KXtyZXR1cm4gZS5fa2V5RG93bih0KX0pLCEwKSksdGhpcy5yZWdpc3RlcigoMCxkLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikodGhpcy50ZXh0YXJlYSwia2V5cHJlc3MiLChmdW5jdGlvbih0KXtyZXR1cm4gZS5fa2V5UHJlc3ModCl9KSwhMCkpLHRoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMudGV4dGFyZWEsImNvbXBvc2l0aW9uc3RhcnQiLChmdW5jdGlvbigpe3JldHVybiBlLl9jb21wb3NpdGlvbkhlbHBlci5jb21wb3NpdGlvbnN0YXJ0KCl9KSkpLHRoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMudGV4dGFyZWEsImNvbXBvc2l0aW9udXBkYXRlIiwoZnVuY3Rpb24odCl7cmV0dXJuIGUuX2NvbXBvc2l0aW9uSGVscGVyLmNvbXBvc2l0aW9udXBkYXRlKHQpfSkpKSx0aGlzLnJlZ2lzdGVyKCgwLGQuYWRkRGlzcG9zYWJsZURvbUxpc3RlbmVyKSh0aGlzLnRleHRhcmVhLCJjb21wb3NpdGlvbmVuZCIsKGZ1bmN0aW9uKCl7cmV0dXJuIGUuX2NvbXBvc2l0aW9uSGVscGVyLmNvbXBvc2l0aW9uZW5kKCl9KSkpLHRoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMudGV4dGFyZWEsImlucHV0IiwoZnVuY3Rpb24odCl7cmV0dXJuIGUuX2lucHV0RXZlbnQodCl9KSwhMCkpLHRoaXMucmVnaXN0ZXIodGhpcy5vblJlbmRlcigoZnVuY3Rpb24oKXtyZXR1cm4gZS5fY29tcG9zaXRpb25IZWxwZXIudXBkYXRlQ29tcG9zaXRpb25FbGVtZW50cygpfSkpKSx0aGlzLnJlZ2lzdGVyKHRoaXMub25SZW5kZXIoKGZ1bmN0aW9uKHQpe3JldHVybiBlLl9xdWV1ZUxpbmtpZmljYXRpb24odC5zdGFydCx0LmVuZCl9KSkpfSx0LnByb3RvdHlwZS5vcGVuPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7aWYoIWUpdGhyb3cgbmV3IEVycm9yKCJUZXJtaW5hbCByZXF1aXJlcyBhIHBhcmVudCBlbGVtZW50LiIpO2UuaXNDb25uZWN0ZWR8fHRoaXMuX2xvZ1NlcnZpY2UuZGVidWcoIlRlcm1pbmFsLm9wZW4gd2FzIGNhbGxlZCBvbiBhbiBlbGVtZW50IHRoYXQgd2FzIG5vdCBhdHRhY2hlZCB0byB0aGUgRE9NIiksdGhpcy5fZG9jdW1lbnQ9ZS5vd25lckRvY3VtZW50LHRoaXMuZWxlbWVudD10aGlzLl9kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKSx0aGlzLmVsZW1lbnQuZGlyPSJsdHIiLHRoaXMuZWxlbWVudC5jbGFzc0xpc3QuYWRkKCJ0ZXJtaW5hbCIpLHRoaXMuZWxlbWVudC5jbGFzc0xpc3QuYWRkKCJ4dGVybSIpLHRoaXMuZWxlbWVudC5zZXRBdHRyaWJ1dGUoInRhYmluZGV4IiwiMCIpLGUuYXBwZW5kQ2hpbGQodGhpcy5lbGVtZW50KTt2YXIgcj1ELmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTt0aGlzLl92aWV3cG9ydEVsZW1lbnQ9RC5jcmVhdGVFbGVtZW50KCJkaXYiKSx0aGlzLl92aWV3cG9ydEVsZW1lbnQuY2xhc3NMaXN0LmFkZCgieHRlcm0tdmlld3BvcnQiKSxyLmFwcGVuZENoaWxkKHRoaXMuX3ZpZXdwb3J0RWxlbWVudCksdGhpcy5fdmlld3BvcnRTY3JvbGxBcmVhPUQuY3JlYXRlRWxlbWVudCgiZGl2IiksdGhpcy5fdmlld3BvcnRTY3JvbGxBcmVhLmNsYXNzTGlzdC5hZGQoInh0ZXJtLXNjcm9sbC1hcmVhIiksdGhpcy5fdmlld3BvcnRFbGVtZW50LmFwcGVuZENoaWxkKHRoaXMuX3ZpZXdwb3J0U2Nyb2xsQXJlYSksdGhpcy5zY3JlZW5FbGVtZW50PUQuY3JlYXRlRWxlbWVudCgiZGl2IiksdGhpcy5zY3JlZW5FbGVtZW50LmNsYXNzTGlzdC5hZGQoInh0ZXJtLXNjcmVlbiIpLHRoaXMuX2hlbHBlckNvbnRhaW5lcj1ELmNyZWF0ZUVsZW1lbnQoImRpdiIpLHRoaXMuX2hlbHBlckNvbnRhaW5lci5jbGFzc0xpc3QuYWRkKCJ4dGVybS1oZWxwZXJzIiksdGhpcy5zY3JlZW5FbGVtZW50LmFwcGVuZENoaWxkKHRoaXMuX2hlbHBlckNvbnRhaW5lciksci5hcHBlbmRDaGlsZCh0aGlzLnNjcmVlbkVsZW1lbnQpLHRoaXMudGV4dGFyZWE9RC5jcmVhdGVFbGVtZW50KCJ0ZXh0YXJlYSIpLHRoaXMudGV4dGFyZWEuY2xhc3NMaXN0LmFkZCgieHRlcm0taGVscGVyLXRleHRhcmVhIiksdGhpcy50ZXh0YXJlYS5zZXRBdHRyaWJ1dGUoImFyaWEtbGFiZWwiLHAucHJvbXB0TGFiZWwpLHRoaXMudGV4dGFyZWEuc2V0QXR0cmlidXRlKCJhcmlhLW11bHRpbGluZSIsImZhbHNlIiksdGhpcy50ZXh0YXJlYS5zZXRBdHRyaWJ1dGUoImF1dG9jb3JyZWN0Iiwib2ZmIiksdGhpcy50ZXh0YXJlYS5zZXRBdHRyaWJ1dGUoImF1dG9jYXBpdGFsaXplIiwib2ZmIiksdGhpcy50ZXh0YXJlYS5zZXRBdHRyaWJ1dGUoInNwZWxsY2hlY2siLCJmYWxzZSIpLHRoaXMudGV4dGFyZWEudGFiSW5kZXg9MCx0aGlzLnJlZ2lzdGVyKCgwLGQuYWRkRGlzcG9zYWJsZURvbUxpc3RlbmVyKSh0aGlzLnRleHRhcmVhLCJmb2N1cyIsKGZ1bmN0aW9uKGUpe3JldHVybiB0Ll9vblRleHRBcmVhRm9jdXMoZSl9KSkpLHRoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHRoaXMudGV4dGFyZWEsImJsdXIiLChmdW5jdGlvbigpe3JldHVybiB0Ll9vblRleHRBcmVhQmx1cigpfSkpKSx0aGlzLl9oZWxwZXJDb250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy50ZXh0YXJlYSk7dmFyIGk9dGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2UuY3JlYXRlSW5zdGFuY2UoTS5Db3JlQnJvd3NlclNlcnZpY2UsdGhpcy50ZXh0YXJlYSk7dGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2Uuc2V0U2VydmljZShFLklDb3JlQnJvd3NlclNlcnZpY2UsaSksdGhpcy5fY2hhclNpemVTZXJ2aWNlPXRoaXMuX2luc3RhbnRpYXRpb25TZXJ2aWNlLmNyZWF0ZUluc3RhbmNlKHguQ2hhclNpemVTZXJ2aWNlLHRoaXMuX2RvY3VtZW50LHRoaXMuX2hlbHBlckNvbnRhaW5lciksdGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2Uuc2V0U2VydmljZShFLklDaGFyU2l6ZVNlcnZpY2UsdGhpcy5fY2hhclNpemVTZXJ2aWNlKSx0aGlzLl90aGVtZT10aGlzLm9wdGlvbnMudGhlbWV8fHRoaXMuX3RoZW1lLHRoaXMuX2NvbG9yTWFuYWdlcj1uZXcgdy5Db2xvck1hbmFnZXIoRCx0aGlzLm9wdGlvbnMuYWxsb3dUcmFuc3BhcmVuY3kpLHRoaXMucmVnaXN0ZXIodGhpcy5vcHRpb25zU2VydmljZS5vbk9wdGlvbkNoYW5nZSgoZnVuY3Rpb24oZSl7cmV0dXJuIHQuX2NvbG9yTWFuYWdlci5vbk9wdGlvbnNDaGFuZ2UoZSl9KSkpLHRoaXMuX2NvbG9yTWFuYWdlci5zZXRUaGVtZSh0aGlzLl90aGVtZSksdGhpcy5fY2hhcmFjdGVySm9pbmVyU2VydmljZT10aGlzLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZShPLkNoYXJhY3RlckpvaW5lclNlcnZpY2UpLHRoaXMuX2luc3RhbnRpYXRpb25TZXJ2aWNlLnNldFNlcnZpY2UoRS5JQ2hhcmFjdGVySm9pbmVyU2VydmljZSx0aGlzLl9jaGFyYWN0ZXJKb2luZXJTZXJ2aWNlKTt2YXIgbj10aGlzLl9jcmVhdGVSZW5kZXJlcigpO3RoaXMuX3JlbmRlclNlcnZpY2U9dGhpcy5yZWdpc3Rlcih0aGlzLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZShMLlJlbmRlclNlcnZpY2Usbix0aGlzLnJvd3MsdGhpcy5zY3JlZW5FbGVtZW50KSksdGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2Uuc2V0U2VydmljZShFLklSZW5kZXJTZXJ2aWNlLHRoaXMuX3JlbmRlclNlcnZpY2UpLHRoaXMucmVnaXN0ZXIodGhpcy5fcmVuZGVyU2VydmljZS5vblJlbmRlcmVkQnVmZmVyQ2hhbmdlKChmdW5jdGlvbihlKXtyZXR1cm4gdC5fb25SZW5kZXIuZmlyZShlKX0pKSksdGhpcy5vblJlc2l6ZSgoZnVuY3Rpb24oZSl7cmV0dXJuIHQuX3JlbmRlclNlcnZpY2UucmVzaXplKGUuY29scyxlLnJvd3MpfSkpLHRoaXMuX2NvbXBvc2l0aW9uVmlldz1ELmNyZWF0ZUVsZW1lbnQoImRpdiIpLHRoaXMuX2NvbXBvc2l0aW9uVmlldy5jbGFzc0xpc3QuYWRkKCJjb21wb3NpdGlvbi12aWV3IiksdGhpcy5fY29tcG9zaXRpb25IZWxwZXI9dGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2UuY3JlYXRlSW5zdGFuY2Uoby5Db21wb3NpdGlvbkhlbHBlcix0aGlzLnRleHRhcmVhLHRoaXMuX2NvbXBvc2l0aW9uVmlldyksdGhpcy5faGVscGVyQ29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMuX2NvbXBvc2l0aW9uVmlldyksdGhpcy5lbGVtZW50LmFwcGVuZENoaWxkKHIpLHRoaXMuX3NvdW5kU2VydmljZT10aGlzLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZSh2LlNvdW5kU2VydmljZSksdGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2Uuc2V0U2VydmljZShFLklTb3VuZFNlcnZpY2UsdGhpcy5fc291bmRTZXJ2aWNlKSx0aGlzLl9tb3VzZVNlcnZpY2U9dGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2UuY3JlYXRlSW5zdGFuY2UoQS5Nb3VzZVNlcnZpY2UpLHRoaXMuX2luc3RhbnRpYXRpb25TZXJ2aWNlLnNldFNlcnZpY2UoRS5JTW91c2VTZXJ2aWNlLHRoaXMuX21vdXNlU2VydmljZSksdGhpcy52aWV3cG9ydD10aGlzLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZShzLlZpZXdwb3J0LChmdW5jdGlvbihlKXtyZXR1cm4gdC5zY3JvbGxMaW5lcyhlLCEwLDEpfSksdGhpcy5fdmlld3BvcnRFbGVtZW50LHRoaXMuX3ZpZXdwb3J0U2Nyb2xsQXJlYSx0aGlzLmVsZW1lbnQpLHRoaXMudmlld3BvcnQub25UaGVtZUNoYW5nZSh0aGlzLl9jb2xvck1hbmFnZXIuY29sb3JzKSx0aGlzLnJlZ2lzdGVyKHRoaXMuX2lucHV0SGFuZGxlci5vblJlcXVlc3RTeW5jU2Nyb2xsQmFyKChmdW5jdGlvbigpe3JldHVybiB0LnZpZXdwb3J0LnN5bmNTY3JvbGxBcmVhKCl9KSkpLHRoaXMucmVnaXN0ZXIodGhpcy52aWV3cG9ydCksdGhpcy5yZWdpc3Rlcih0aGlzLm9uQ3Vyc29yTW92ZSgoZnVuY3Rpb24oKXt0Ll9yZW5kZXJTZXJ2aWNlLm9uQ3Vyc29yTW92ZSgpLHQuX3N5bmNUZXh0QXJlYSgpfSkpKSx0aGlzLnJlZ2lzdGVyKHRoaXMub25SZXNpemUoKGZ1bmN0aW9uKCl7cmV0dXJuIHQuX3JlbmRlclNlcnZpY2Uub25SZXNpemUodC5jb2xzLHQucm93cyl9KSkpLHRoaXMucmVnaXN0ZXIodGhpcy5vbkJsdXIoKGZ1bmN0aW9uKCl7cmV0dXJuIHQuX3JlbmRlclNlcnZpY2Uub25CbHVyKCl9KSkpLHRoaXMucmVnaXN0ZXIodGhpcy5vbkZvY3VzKChmdW5jdGlvbigpe3JldHVybiB0Ll9yZW5kZXJTZXJ2aWNlLm9uRm9jdXMoKX0pKSksdGhpcy5yZWdpc3Rlcih0aGlzLl9yZW5kZXJTZXJ2aWNlLm9uRGltZW5zaW9uc0NoYW5nZSgoZnVuY3Rpb24oKXtyZXR1cm4gdC52aWV3cG9ydC5zeW5jU2Nyb2xsQXJlYSgpfSkpKSx0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlPXRoaXMucmVnaXN0ZXIodGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2UuY3JlYXRlSW5zdGFuY2UoZi5TZWxlY3Rpb25TZXJ2aWNlLHRoaXMuZWxlbWVudCx0aGlzLnNjcmVlbkVsZW1lbnQsdGhpcy5saW5raWZpZXIyKSksdGhpcy5faW5zdGFudGlhdGlvblNlcnZpY2Uuc2V0U2VydmljZShFLklTZWxlY3Rpb25TZXJ2aWNlLHRoaXMuX3NlbGVjdGlvblNlcnZpY2UpLHRoaXMucmVnaXN0ZXIodGhpcy5fc2VsZWN0aW9uU2VydmljZS5vblJlcXVlc3RTY3JvbGxMaW5lcygoZnVuY3Rpb24oZSl7cmV0dXJuIHQuc2Nyb2xsTGluZXMoZS5hbW91bnQsZS5zdXBwcmVzc1Njcm9sbEV2ZW50KX0pKSksdGhpcy5yZWdpc3Rlcih0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLm9uU2VsZWN0aW9uQ2hhbmdlKChmdW5jdGlvbigpe3JldHVybiB0Ll9vblNlbGVjdGlvbkNoYW5nZS5maXJlKCl9KSkpLHRoaXMucmVnaXN0ZXIodGhpcy5fc2VsZWN0aW9uU2VydmljZS5vblJlcXVlc3RSZWRyYXcoKGZ1bmN0aW9uKGUpe3JldHVybiB0Ll9yZW5kZXJTZXJ2aWNlLm9uU2VsZWN0aW9uQ2hhbmdlZChlLnN0YXJ0LGUuZW5kLGUuY29sdW1uU2VsZWN0TW9kZSl9KSkpLHRoaXMucmVnaXN0ZXIodGhpcy5fc2VsZWN0aW9uU2VydmljZS5vbkxpbnV4TW91c2VTZWxlY3Rpb24oKGZ1bmN0aW9uKGUpe3QudGV4dGFyZWEudmFsdWU9ZSx0LnRleHRhcmVhLmZvY3VzKCksdC50ZXh0YXJlYS5zZWxlY3QoKX0pKSksdGhpcy5yZWdpc3Rlcih0aGlzLl9vblNjcm9sbC5ldmVudCgoZnVuY3Rpb24oZSl7dC52aWV3cG9ydC5zeW5jU2Nyb2xsQXJlYSgpLHQuX3NlbGVjdGlvblNlcnZpY2UucmVmcmVzaCgpfSkpKSx0aGlzLnJlZ2lzdGVyKCgwLGQuYWRkRGlzcG9zYWJsZURvbUxpc3RlbmVyKSh0aGlzLl92aWV3cG9ydEVsZW1lbnQsInNjcm9sbCIsKGZ1bmN0aW9uKCl7cmV0dXJuIHQuX3NlbGVjdGlvblNlcnZpY2UucmVmcmVzaCgpfSkpKSx0aGlzLl9tb3VzZVpvbmVNYW5hZ2VyPXRoaXMuX2luc3RhbnRpYXRpb25TZXJ2aWNlLmNyZWF0ZUluc3RhbmNlKGcuTW91c2Vab25lTWFuYWdlcix0aGlzLmVsZW1lbnQsdGhpcy5zY3JlZW5FbGVtZW50KSx0aGlzLnJlZ2lzdGVyKHRoaXMuX21vdXNlWm9uZU1hbmFnZXIpLHRoaXMucmVnaXN0ZXIodGhpcy5vblNjcm9sbCgoZnVuY3Rpb24oKXtyZXR1cm4gdC5fbW91c2Vab25lTWFuYWdlci5jbGVhckFsbCgpfSkpKSx0aGlzLmxpbmtpZmllci5hdHRhY2hUb0RvbSh0aGlzLmVsZW1lbnQsdGhpcy5fbW91c2Vab25lTWFuYWdlciksdGhpcy5saW5raWZpZXIyLmF0dGFjaFRvRG9tKHRoaXMuc2NyZWVuRWxlbWVudCx0aGlzLl9tb3VzZVNlcnZpY2UsdGhpcy5fcmVuZGVyU2VydmljZSksdGhpcy5yZWdpc3RlcigoMCxkLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikodGhpcy5lbGVtZW50LCJtb3VzZWRvd24iLChmdW5jdGlvbihlKXtyZXR1cm4gdC5fc2VsZWN0aW9uU2VydmljZS5vbk1vdXNlRG93bihlKX0pKSksdGhpcy5jb3JlTW91c2VTZXJ2aWNlLmFyZU1vdXNlRXZlbnRzQWN0aXZlPyh0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmRpc2FibGUoKSx0aGlzLmVsZW1lbnQuY2xhc3NMaXN0LmFkZCgiZW5hYmxlLW1vdXNlLWV2ZW50cyIpKTp0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmVuYWJsZSgpLHRoaXMub3B0aW9ucy5zY3JlZW5SZWFkZXJNb2RlJiYodGhpcy5fYWNjZXNzaWJpbGl0eU1hbmFnZXI9bmV3IHkuQWNjZXNzaWJpbGl0eU1hbmFnZXIodGhpcyx0aGlzLl9yZW5kZXJTZXJ2aWNlKSksdGhpcy5fY2hhclNpemVTZXJ2aWNlLm1lYXN1cmUoKSx0aGlzLnJlZnJlc2goMCx0aGlzLnJvd3MtMSksdGhpcy5faW5pdEdsb2JhbCgpLHRoaXMuYmluZE1vdXNlKCl9LHQucHJvdG90eXBlLl9jcmVhdGVSZW5kZXJlcj1mdW5jdGlvbigpe3N3aXRjaCh0aGlzLm9wdGlvbnMucmVuZGVyZXJUeXBlKXtjYXNlImNhbnZhcyI6cmV0dXJuIHRoaXMuX2luc3RhbnRpYXRpb25TZXJ2aWNlLmNyZWF0ZUluc3RhbmNlKHUuUmVuZGVyZXIsdGhpcy5fY29sb3JNYW5hZ2VyLmNvbG9ycyx0aGlzLnNjcmVlbkVsZW1lbnQsdGhpcy5saW5raWZpZXIsdGhpcy5saW5raWZpZXIyKTtjYXNlImRvbSI6cmV0dXJuIHRoaXMuX2luc3RhbnRpYXRpb25TZXJ2aWNlLmNyZWF0ZUluc3RhbmNlKG0uRG9tUmVuZGVyZXIsdGhpcy5fY29sb3JNYW5hZ2VyLmNvbG9ycyx0aGlzLmVsZW1lbnQsdGhpcy5zY3JlZW5FbGVtZW50LHRoaXMuX3ZpZXdwb3J0RWxlbWVudCx0aGlzLmxpbmtpZmllcix0aGlzLmxpbmtpZmllcjIpO2RlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCdVbnJlY29nbml6ZWQgcmVuZGVyZXJUeXBlICInK3RoaXMub3B0aW9ucy5yZW5kZXJlclR5cGUrJyInKX19LHQucHJvdG90eXBlLl9zZXRUaGVtZT1mdW5jdGlvbihlKXt2YXIgdCxyLGk7dGhpcy5fdGhlbWU9ZSxudWxsPT09KHQ9dGhpcy5fY29sb3JNYW5hZ2VyKXx8dm9pZCAwPT09dHx8dC5zZXRUaGVtZShlKSxudWxsPT09KHI9dGhpcy5fcmVuZGVyU2VydmljZSl8fHZvaWQgMD09PXJ8fHIuc2V0Q29sb3JzKHRoaXMuX2NvbG9yTWFuYWdlci5jb2xvcnMpLG51bGw9PT0oaT10aGlzLnZpZXdwb3J0KXx8dm9pZCAwPT09aXx8aS5vblRoZW1lQ2hhbmdlKHRoaXMuX2NvbG9yTWFuYWdlci5jb2xvcnMpfSx0LnByb3RvdHlwZS5iaW5kTW91c2U9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLHQ9dGhpcyxyPXRoaXMuZWxlbWVudDtmdW5jdGlvbiBpKGUpe3ZhciByLGksbj10Ll9tb3VzZVNlcnZpY2UuZ2V0UmF3Qnl0ZUNvb3JkcyhlLHQuc2NyZWVuRWxlbWVudCx0LmNvbHMsdC5yb3dzKTtpZighbilyZXR1cm4hMTtzd2l0Y2goZS5vdmVycmlkZVR5cGV8fGUudHlwZSl7Y2FzZSJtb3VzZW1vdmUiOmk9MzIsdm9pZCAwPT09ZS5idXR0b25zPyhyPTMsdm9pZCAwIT09ZS5idXR0b24mJihyPWUuYnV0dG9uPDM/ZS5idXR0b246MykpOnI9MSZlLmJ1dHRvbnM/MDo0JmUuYnV0dG9ucz8xOjImZS5idXR0b25zPzI6MzticmVhaztjYXNlIm1vdXNldXAiOmk9MCxyPWUuYnV0dG9uPDM/ZS5idXR0b246MzticmVhaztjYXNlIm1vdXNlZG93biI6aT0xLHI9ZS5idXR0b248Mz9lLmJ1dHRvbjozO2JyZWFrO2Nhc2Uid2hlZWwiOjAhPT1lLmRlbHRhWSYmKGk9ZS5kZWx0YVk8MD8wOjEpLHI9NDticmVhaztkZWZhdWx0OnJldHVybiExfXJldHVybiEodm9pZCAwPT09aXx8dm9pZCAwPT09cnx8cj40KSYmdC5jb3JlTW91c2VTZXJ2aWNlLnRyaWdnZXJNb3VzZUV2ZW50KHtjb2w6bi54LTMzLHJvdzpuLnktMzMsYnV0dG9uOnIsYWN0aW9uOmksY3RybDplLmN0cmxLZXksYWx0OmUuYWx0S2V5LHNoaWZ0OmUuc2hpZnRLZXl9KX12YXIgbj17bW91c2V1cDpudWxsLHdoZWVsOm51bGwsbW91c2VkcmFnOm51bGwsbW91c2Vtb3ZlOm51bGx9LG89ZnVuY3Rpb24odCl7cmV0dXJuIGkodCksdC5idXR0b25zfHwoZS5fZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsbi5tb3VzZXVwKSxuLm1vdXNlZHJhZyYmZS5fZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2Vtb3ZlIixuLm1vdXNlZHJhZykpLGUuY2FuY2VsKHQpfSxzPWZ1bmN0aW9uKHQpe3JldHVybiBpKHQpLGUuY2FuY2VsKHQsITApfSxhPWZ1bmN0aW9uKGUpe2UuYnV0dG9ucyYmaShlKX0sbD1mdW5jdGlvbihlKXtlLmJ1dHRvbnN8fGkoZSl9O3RoaXMucmVnaXN0ZXIodGhpcy5jb3JlTW91c2VTZXJ2aWNlLm9uUHJvdG9jb2xDaGFuZ2UoKGZ1bmN0aW9uKHQpe3Q/KCJkZWJ1ZyI9PT1lLm9wdGlvbnNTZXJ2aWNlLm9wdGlvbnMubG9nTGV2ZWwmJmUuX2xvZ1NlcnZpY2UuZGVidWcoIkJpbmRpbmcgdG8gbW91c2UgZXZlbnRzOiIsZS5jb3JlTW91c2VTZXJ2aWNlLmV4cGxhaW5FdmVudHModCkpLGUuZWxlbWVudC5jbGFzc0xpc3QuYWRkKCJlbmFibGUtbW91c2UtZXZlbnRzIiksZS5fc2VsZWN0aW9uU2VydmljZS5kaXNhYmxlKCkpOihlLl9sb2dTZXJ2aWNlLmRlYnVnKCJVbmJpbmRpbmcgZnJvbSBtb3VzZSBldmVudHMuIiksZS5lbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoImVuYWJsZS1tb3VzZS1ldmVudHMiKSxlLl9zZWxlY3Rpb25TZXJ2aWNlLmVuYWJsZSgpKSw4JnQ/bi5tb3VzZW1vdmV8fChyLmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlbW92ZSIsbCksbi5tb3VzZW1vdmU9bCk6KHIucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2Vtb3ZlIixuLm1vdXNlbW92ZSksbi5tb3VzZW1vdmU9bnVsbCksMTYmdD9uLndoZWVsfHwoci5hZGRFdmVudExpc3RlbmVyKCJ3aGVlbCIscyx7cGFzc2l2ZTohMX0pLG4ud2hlZWw9cyk6KHIucmVtb3ZlRXZlbnRMaXN0ZW5lcigid2hlZWwiLG4ud2hlZWwpLG4ud2hlZWw9bnVsbCksMiZ0P24ubW91c2V1cHx8KG4ubW91c2V1cD1vKTooZS5fZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsbi5tb3VzZXVwKSxuLm1vdXNldXA9bnVsbCksNCZ0P24ubW91c2VkcmFnfHwobi5tb3VzZWRyYWc9YSk6KGUuX2RvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNlbW92ZSIsbi5tb3VzZWRyYWcpLG4ubW91c2VkcmFnPW51bGwpfSkpKSx0aGlzLmNvcmVNb3VzZVNlcnZpY2UuYWN0aXZlUHJvdG9jb2w9dGhpcy5jb3JlTW91c2VTZXJ2aWNlLmFjdGl2ZVByb3RvY29sLHRoaXMucmVnaXN0ZXIoKDAsZC5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHIsIm1vdXNlZG93biIsKGZ1bmN0aW9uKHQpe2lmKHQucHJldmVudERlZmF1bHQoKSxlLmZvY3VzKCksZS5jb3JlTW91c2VTZXJ2aWNlLmFyZU1vdXNlRXZlbnRzQWN0aXZlJiYhZS5fc2VsZWN0aW9uU2VydmljZS5zaG91bGRGb3JjZVNlbGVjdGlvbih0KSlyZXR1cm4gaSh0KSxuLm1vdXNldXAmJmUuX2RvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNldXAiLG4ubW91c2V1cCksbi5tb3VzZWRyYWcmJmUuX2RvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlbW92ZSIsbi5tb3VzZWRyYWcpLGUuY2FuY2VsKHQpfSkpKSx0aGlzLnJlZ2lzdGVyKCgwLGQuYWRkRGlzcG9zYWJsZURvbUxpc3RlbmVyKShyLCJ3aGVlbCIsKGZ1bmN0aW9uKHQpe2lmKCFuLndoZWVsKXtpZighZS5idWZmZXIuaGFzU2Nyb2xsYmFjayl7dmFyIHI9ZS52aWV3cG9ydC5nZXRMaW5lc1Njcm9sbGVkKHQpO2lmKDA9PT1yKXJldHVybjtmb3IodmFyIGk9Yy5DMC5FU0MrKGUuY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLmFwcGxpY2F0aW9uQ3Vyc29yS2V5cz8iTyI6IlsiKSsodC5kZWx0YVk8MD8iQSI6IkIiKSxvPSIiLHM9MDtzPE1hdGguYWJzKHIpO3MrKylvKz1pO3JldHVybiBlLmNvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQobywhMCksZS5jYW5jZWwodCwhMCl9cmV0dXJuIGUudmlld3BvcnQub25XaGVlbCh0KT9lLmNhbmNlbCh0KTp2b2lkIDB9fSkse3Bhc3NpdmU6ITF9KSksdGhpcy5yZWdpc3RlcigoMCxkLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikociwidG91Y2hzdGFydCIsKGZ1bmN0aW9uKHQpe2lmKCFlLmNvcmVNb3VzZVNlcnZpY2UuYXJlTW91c2VFdmVudHNBY3RpdmUpcmV0dXJuIGUudmlld3BvcnQub25Ub3VjaFN0YXJ0KHQpLGUuY2FuY2VsKHQpfSkse3Bhc3NpdmU6ITB9KSksdGhpcy5yZWdpc3RlcigoMCxkLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikociwidG91Y2htb3ZlIiwoZnVuY3Rpb24odCl7aWYoIWUuY29yZU1vdXNlU2VydmljZS5hcmVNb3VzZUV2ZW50c0FjdGl2ZSlyZXR1cm4gZS52aWV3cG9ydC5vblRvdWNoTW92ZSh0KT92b2lkIDA6ZS5jYW5jZWwodCl9KSx7cGFzc2l2ZTohMX0pKX0sdC5wcm90b3R5cGUucmVmcmVzaD1mdW5jdGlvbihlLHQpe3ZhciByO251bGw9PT0ocj10aGlzLl9yZW5kZXJTZXJ2aWNlKXx8dm9pZCAwPT09cnx8ci5yZWZyZXNoUm93cyhlLHQpfSx0LnByb3RvdHlwZS5fcXVldWVMaW5raWZpY2F0aW9uPWZ1bmN0aW9uKGUsdCl7dmFyIHI7bnVsbD09PShyPXRoaXMubGlua2lmaWVyKXx8dm9pZCAwPT09cnx8ci5saW5raWZ5Um93cyhlLHQpfSx0LnByb3RvdHlwZS51cGRhdGVDdXJzb3JTdHlsZT1mdW5jdGlvbihlKXt2YXIgdDsobnVsbD09PSh0PXRoaXMuX3NlbGVjdGlvblNlcnZpY2UpfHx2b2lkIDA9PT10P3ZvaWQgMDp0LnNob3VsZENvbHVtblNlbGVjdChlKSk/dGhpcy5lbGVtZW50LmNsYXNzTGlzdC5hZGQoImNvbHVtbi1zZWxlY3QiKTp0aGlzLmVsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZSgiY29sdW1uLXNlbGVjdCIpfSx0LnByb3RvdHlwZS5fc2hvd0N1cnNvcj1mdW5jdGlvbigpe3RoaXMuY29yZVNlcnZpY2UuaXNDdXJzb3JJbml0aWFsaXplZHx8KHRoaXMuY29yZVNlcnZpY2UuaXNDdXJzb3JJbml0aWFsaXplZD0hMCx0aGlzLnJlZnJlc2godGhpcy5idWZmZXIueSx0aGlzLmJ1ZmZlci55KSl9LHQucHJvdG90eXBlLnNjcm9sbExpbmVzPWZ1bmN0aW9uKHQscixpKXt2b2lkIDA9PT1pJiYoaT0wKSxlLnByb3RvdHlwZS5zY3JvbGxMaW5lcy5jYWxsKHRoaXMsdCxyLGkpLHRoaXMucmVmcmVzaCgwLHRoaXMucm93cy0xKX0sdC5wcm90b3R5cGUucGFzdGU9ZnVuY3Rpb24oZSl7KDAsYS5wYXN0ZSkoZSx0aGlzLnRleHRhcmVhLHRoaXMuY29yZVNlcnZpY2UpfSx0LnByb3RvdHlwZS5hdHRhY2hDdXN0b21LZXlFdmVudEhhbmRsZXI9ZnVuY3Rpb24oZSl7dGhpcy5fY3VzdG9tS2V5RXZlbnRIYW5kbGVyPWV9LHQucHJvdG90eXBlLnJlZ2lzdGVyTGlua01hdGNoZXI9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXMubGlua2lmaWVyLnJlZ2lzdGVyTGlua01hdGNoZXIoZSx0LHIpO3JldHVybiB0aGlzLnJlZnJlc2goMCx0aGlzLnJvd3MtMSksaX0sdC5wcm90b3R5cGUuZGVyZWdpc3RlckxpbmtNYXRjaGVyPWZ1bmN0aW9uKGUpe3RoaXMubGlua2lmaWVyLmRlcmVnaXN0ZXJMaW5rTWF0Y2hlcihlKSYmdGhpcy5yZWZyZXNoKDAsdGhpcy5yb3dzLTEpfSx0LnByb3RvdHlwZS5yZWdpc3RlckxpbmtQcm92aWRlcj1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5saW5raWZpZXIyLnJlZ2lzdGVyTGlua1Byb3ZpZGVyKGUpfSx0LnByb3RvdHlwZS5yZWdpc3RlckNoYXJhY3RlckpvaW5lcj1mdW5jdGlvbihlKXtpZighdGhpcy5fY2hhcmFjdGVySm9pbmVyU2VydmljZSl0aHJvdyBuZXcgRXJyb3IoIlRlcm1pbmFsIG11c3QgYmUgb3BlbmVkIGZpcnN0Iik7dmFyIHQ9dGhpcy5fY2hhcmFjdGVySm9pbmVyU2VydmljZS5yZWdpc3RlcihlKTtyZXR1cm4gdGhpcy5yZWZyZXNoKDAsdGhpcy5yb3dzLTEpLHR9LHQucHJvdG90eXBlLmRlcmVnaXN0ZXJDaGFyYWN0ZXJKb2luZXI9ZnVuY3Rpb24oZSl7aWYoIXRoaXMuX2NoYXJhY3RlckpvaW5lclNlcnZpY2UpdGhyb3cgbmV3IEVycm9yKCJUZXJtaW5hbCBtdXN0IGJlIG9wZW5lZCBmaXJzdCIpO3RoaXMuX2NoYXJhY3RlckpvaW5lclNlcnZpY2UuZGVyZWdpc3RlcihlKSYmdGhpcy5yZWZyZXNoKDAsdGhpcy5yb3dzLTEpfSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm1hcmtlcnMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5idWZmZXIubWFya2Vyc30sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSx0LnByb3RvdHlwZS5hZGRNYXJrZXI9ZnVuY3Rpb24oZSl7aWYodGhpcy5idWZmZXI9PT10aGlzLmJ1ZmZlcnMubm9ybWFsKXJldHVybiB0aGlzLmJ1ZmZlci5hZGRNYXJrZXIodGhpcy5idWZmZXIueWJhc2UrdGhpcy5idWZmZXIueStlKX0sdC5wcm90b3R5cGUuaGFzU2VsZWN0aW9uPWZ1bmN0aW9uKCl7cmV0dXJuISF0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlJiZ0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmhhc1NlbGVjdGlvbn0sdC5wcm90b3R5cGUuc2VsZWN0PWZ1bmN0aW9uKGUsdCxyKXt0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLnNldFNlbGVjdGlvbihlLHQscil9LHQucHJvdG90eXBlLmdldFNlbGVjdGlvbj1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlP3RoaXMuX3NlbGVjdGlvblNlcnZpY2Uuc2VsZWN0aW9uVGV4dDoiIn0sdC5wcm90b3R5cGUuZ2V0U2VsZWN0aW9uUG9zaXRpb249ZnVuY3Rpb24oKXtpZih0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlJiZ0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLmhhc1NlbGVjdGlvbilyZXR1cm57c3RhcnRDb2x1bW46dGhpcy5fc2VsZWN0aW9uU2VydmljZS5zZWxlY3Rpb25TdGFydFswXSxzdGFydFJvdzp0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdGlvblN0YXJ0WzFdLGVuZENvbHVtbjp0aGlzLl9zZWxlY3Rpb25TZXJ2aWNlLnNlbGVjdGlvbkVuZFswXSxlbmRSb3c6dGhpcy5fc2VsZWN0aW9uU2VydmljZS5zZWxlY3Rpb25FbmRbMV19fSx0LnByb3RvdHlwZS5jbGVhclNlbGVjdGlvbj1mdW5jdGlvbigpe3ZhciBlO251bGw9PT0oZT10aGlzLl9zZWxlY3Rpb25TZXJ2aWNlKXx8dm9pZCAwPT09ZXx8ZS5jbGVhclNlbGVjdGlvbigpfSx0LnByb3RvdHlwZS5zZWxlY3RBbGw9ZnVuY3Rpb24oKXt2YXIgZTtudWxsPT09KGU9dGhpcy5fc2VsZWN0aW9uU2VydmljZSl8fHZvaWQgMD09PWV8fGUuc2VsZWN0QWxsKCl9LHQucHJvdG90eXBlLnNlbGVjdExpbmVzPWZ1bmN0aW9uKGUsdCl7dmFyIHI7bnVsbD09PShyPXRoaXMuX3NlbGVjdGlvblNlcnZpY2UpfHx2b2lkIDA9PT1yfHxyLnNlbGVjdExpbmVzKGUsdCl9LHQucHJvdG90eXBlLl9rZXlEb3duPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2tleURvd25IYW5kbGVkPSExLHRoaXMuX2N1c3RvbUtleUV2ZW50SGFuZGxlciYmITE9PT10aGlzLl9jdXN0b21LZXlFdmVudEhhbmRsZXIoZSkpcmV0dXJuITE7aWYoIXRoaXMuX2NvbXBvc2l0aW9uSGVscGVyLmtleWRvd24oZSkpcmV0dXJuIHRoaXMuYnVmZmVyLnliYXNlIT09dGhpcy5idWZmZXIueWRpc3AmJnRoaXMuX2J1ZmZlclNlcnZpY2Uuc2Nyb2xsVG9Cb3R0b20oKSwhMTsiRGVhZCIhPT1lLmtleSYmIkFsdEdyYXBoIiE9PWUua2V5fHwodGhpcy5fdW5wcm9jZXNzZWREZWFkS2V5PSEwKTt2YXIgdD0oMCxiLmV2YWx1YXRlS2V5Ym9hcmRFdmVudCkoZSx0aGlzLmNvcmVTZXJ2aWNlLmRlY1ByaXZhdGVNb2Rlcy5hcHBsaWNhdGlvbkN1cnNvcktleXMsdGhpcy5icm93c2VyLmlzTWFjLHRoaXMub3B0aW9ucy5tYWNPcHRpb25Jc01ldGEpO2lmKHRoaXMudXBkYXRlQ3Vyc29yU3R5bGUoZSksMz09PXQudHlwZXx8Mj09PXQudHlwZSl7dmFyIHI9dGhpcy5yb3dzLTE7cmV0dXJuIHRoaXMuc2Nyb2xsTGluZXMoMj09PXQudHlwZT8tcjpyKSx0aGlzLmNhbmNlbChlLCEwKX1yZXR1cm4gMT09PXQudHlwZSYmdGhpcy5zZWxlY3RBbGwoKSwhIXRoaXMuX2lzVGhpcmRMZXZlbFNoaWZ0KHRoaXMuYnJvd3NlcixlKXx8KHQuY2FuY2VsJiZ0aGlzLmNhbmNlbChlLCEwKSwhdC5rZXl8fCh0aGlzLl91bnByb2Nlc3NlZERlYWRLZXk/KHRoaXMuX3VucHJvY2Vzc2VkRGVhZEtleT0hMSwhMCk6KHQua2V5IT09Yy5DMC5FVFgmJnQua2V5IT09Yy5DMC5DUnx8KHRoaXMudGV4dGFyZWEudmFsdWU9IiIpLHRoaXMuX29uS2V5LmZpcmUoe2tleTp0LmtleSxkb21FdmVudDplfSksdGhpcy5fc2hvd0N1cnNvcigpLHRoaXMuY29yZVNlcnZpY2UudHJpZ2dlckRhdGFFdmVudCh0LmtleSwhMCksdGhpcy5vcHRpb25zU2VydmljZS5vcHRpb25zLnNjcmVlblJlYWRlck1vZGU/dm9pZCh0aGlzLl9rZXlEb3duSGFuZGxlZD0hMCk6dGhpcy5jYW5jZWwoZSwhMCkpKSl9LHQucHJvdG90eXBlLl9pc1RoaXJkTGV2ZWxTaGlmdD1mdW5jdGlvbihlLHQpe3ZhciByPWUuaXNNYWMmJiF0aGlzLm9wdGlvbnMubWFjT3B0aW9uSXNNZXRhJiZ0LmFsdEtleSYmIXQuY3RybEtleSYmIXQubWV0YUtleXx8ZS5pc1dpbmRvd3MmJnQuYWx0S2V5JiZ0LmN0cmxLZXkmJiF0Lm1ldGFLZXl8fGUuaXNXaW5kb3dzJiZ0LmdldE1vZGlmaWVyU3RhdGUoIkFsdEdyYXBoIik7cmV0dXJuImtleXByZXNzIj09PXQudHlwZT9yOnImJighdC5rZXlDb2RlfHx0LmtleUNvZGU+NDcpfSx0LnByb3RvdHlwZS5fa2V5VXA9ZnVuY3Rpb24oZSl7dGhpcy5fY3VzdG9tS2V5RXZlbnRIYW5kbGVyJiYhMT09PXRoaXMuX2N1c3RvbUtleUV2ZW50SGFuZGxlcihlKXx8KGZ1bmN0aW9uKGUpe3JldHVybiAxNj09PWUua2V5Q29kZXx8MTc9PT1lLmtleUNvZGV8fDE4PT09ZS5rZXlDb2RlfShlKXx8dGhpcy5mb2N1cygpLHRoaXMudXBkYXRlQ3Vyc29yU3R5bGUoZSksdGhpcy5fa2V5UHJlc3NIYW5kbGVkPSExKX0sdC5wcm90b3R5cGUuX2tleVByZXNzPWZ1bmN0aW9uKGUpe3ZhciB0O2lmKHRoaXMuX2tleVByZXNzSGFuZGxlZD0hMSx0aGlzLl9rZXlEb3duSGFuZGxlZClyZXR1cm4hMTtpZih0aGlzLl9jdXN0b21LZXlFdmVudEhhbmRsZXImJiExPT09dGhpcy5fY3VzdG9tS2V5RXZlbnRIYW5kbGVyKGUpKXJldHVybiExO2lmKHRoaXMuY2FuY2VsKGUpLGUuY2hhckNvZGUpdD1lLmNoYXJDb2RlO2Vsc2UgaWYobnVsbD09PWUud2hpY2h8fHZvaWQgMD09PWUud2hpY2gpdD1lLmtleUNvZGU7ZWxzZXtpZigwPT09ZS53aGljaHx8MD09PWUuY2hhckNvZGUpcmV0dXJuITE7dD1lLndoaWNofXJldHVybiEoIXR8fChlLmFsdEtleXx8ZS5jdHJsS2V5fHxlLm1ldGFLZXkpJiYhdGhpcy5faXNUaGlyZExldmVsU2hpZnQodGhpcy5icm93c2VyLGUpfHwodD1TdHJpbmcuZnJvbUNoYXJDb2RlKHQpLHRoaXMuX29uS2V5LmZpcmUoe2tleTp0LGRvbUV2ZW50OmV9KSx0aGlzLl9zaG93Q3Vyc29yKCksdGhpcy5jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KHQsITApLHRoaXMuX2tleVByZXNzSGFuZGxlZD0hMCx0aGlzLl91bnByb2Nlc3NlZERlYWRLZXk9ITEsMCkpfSx0LnByb3RvdHlwZS5faW5wdXRFdmVudD1mdW5jdGlvbihlKXtpZihlLmRhdGEmJiJpbnNlcnRUZXh0Ij09PWUuaW5wdXRUeXBlJiYhZS5jb21wb3NlZCYmIXRoaXMub3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5zY3JlZW5SZWFkZXJNb2RlKXtpZih0aGlzLl9rZXlQcmVzc0hhbmRsZWQpcmV0dXJuITE7dGhpcy5fdW5wcm9jZXNzZWREZWFkS2V5PSExO3ZhciB0PWUuZGF0YTtyZXR1cm4gdGhpcy5jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KHQsITApLHRoaXMuY2FuY2VsKGUpLCEwfXJldHVybiExfSx0LnByb3RvdHlwZS5iZWxsPWZ1bmN0aW9uKCl7dmFyIGU7dGhpcy5fc291bmRCZWxsKCkmJihudWxsPT09KGU9dGhpcy5fc291bmRTZXJ2aWNlKXx8dm9pZCAwPT09ZXx8ZS5wbGF5QmVsbFNvdW5kKCkpLHRoaXMuX29uQmVsbC5maXJlKCl9LHQucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbih0LHIpe3QhPT10aGlzLmNvbHN8fHIhPT10aGlzLnJvd3M/ZS5wcm90b3R5cGUucmVzaXplLmNhbGwodGhpcyx0LHIpOnRoaXMuX2NoYXJTaXplU2VydmljZSYmIXRoaXMuX2NoYXJTaXplU2VydmljZS5oYXNWYWxpZFNpemUmJnRoaXMuX2NoYXJTaXplU2VydmljZS5tZWFzdXJlKCl9LHQucHJvdG90eXBlLl9hZnRlclJlc2l6ZT1mdW5jdGlvbihlLHQpe3ZhciByLGk7bnVsbD09PShyPXRoaXMuX2NoYXJTaXplU2VydmljZSl8fHZvaWQgMD09PXJ8fHIubWVhc3VyZSgpLG51bGw9PT0oaT10aGlzLnZpZXdwb3J0KXx8dm9pZCAwPT09aXx8aS5zeW5jU2Nyb2xsQXJlYSghMCl9LHQucHJvdG90eXBlLmNsZWFyPWZ1bmN0aW9uKCl7aWYoMCE9PXRoaXMuYnVmZmVyLnliYXNlfHwwIT09dGhpcy5idWZmZXIueSl7dGhpcy5idWZmZXIubGluZXMuc2V0KDAsdGhpcy5idWZmZXIubGluZXMuZ2V0KHRoaXMuYnVmZmVyLnliYXNlK3RoaXMuYnVmZmVyLnkpKSx0aGlzLmJ1ZmZlci5saW5lcy5sZW5ndGg9MSx0aGlzLmJ1ZmZlci55ZGlzcD0wLHRoaXMuYnVmZmVyLnliYXNlPTAsdGhpcy5idWZmZXIueT0wO2Zvcih2YXIgZT0xO2U8dGhpcy5yb3dzO2UrKyl0aGlzLmJ1ZmZlci5saW5lcy5wdXNoKHRoaXMuYnVmZmVyLmdldEJsYW5rTGluZShDLkRFRkFVTFRfQVRUUl9EQVRBKSk7dGhpcy5yZWZyZXNoKDAsdGhpcy5yb3dzLTEpLHRoaXMuX29uU2Nyb2xsLmZpcmUoe3Bvc2l0aW9uOnRoaXMuYnVmZmVyLnlkaXNwLHNvdXJjZTowfSl9fSx0LnByb3RvdHlwZS5yZXNldD1mdW5jdGlvbigpe3ZhciB0LHI7dGhpcy5vcHRpb25zLnJvd3M9dGhpcy5yb3dzLHRoaXMub3B0aW9ucy5jb2xzPXRoaXMuY29sczt2YXIgaT10aGlzLl9jdXN0b21LZXlFdmVudEhhbmRsZXI7dGhpcy5fc2V0dXAoKSxlLnByb3RvdHlwZS5yZXNldC5jYWxsKHRoaXMpLG51bGw9PT0odD10aGlzLl9zZWxlY3Rpb25TZXJ2aWNlKXx8dm9pZCAwPT09dHx8dC5yZXNldCgpLHRoaXMuX2N1c3RvbUtleUV2ZW50SGFuZGxlcj1pLHRoaXMucmVmcmVzaCgwLHRoaXMucm93cy0xKSxudWxsPT09KHI9dGhpcy52aWV3cG9ydCl8fHZvaWQgMD09PXJ8fHIuc3luY1Njcm9sbEFyZWEoKX0sdC5wcm90b3R5cGUuY2xlYXJUZXh0dXJlQXRsYXM9ZnVuY3Rpb24oKXt2YXIgZTtudWxsPT09KGU9dGhpcy5fcmVuZGVyU2VydmljZSl8fHZvaWQgMD09PWV8fGUuY2xlYXJUZXh0dXJlQXRsYXMoKX0sdC5wcm90b3R5cGUuX3JlcG9ydEZvY3VzPWZ1bmN0aW9uKCl7dmFyIGU7KG51bGw9PT0oZT10aGlzLmVsZW1lbnQpfHx2b2lkIDA9PT1lP3ZvaWQgMDplLmNsYXNzTGlzdC5jb250YWlucygiZm9jdXMiKSk/dGhpcy5jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KGMuQzAuRVNDKyJbSSIpOnRoaXMuY29yZVNlcnZpY2UudHJpZ2dlckRhdGFFdmVudChjLkMwLkVTQysiW08iKX0sdC5wcm90b3R5cGUuX3JlcG9ydFdpbmRvd3NPcHRpb25zPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX3JlbmRlclNlcnZpY2Upc3dpdGNoKGUpe2Nhc2UgbC5XaW5kb3dzT3B0aW9uc1JlcG9ydFR5cGUuR0VUX1dJTl9TSVpFX1BJWEVMUzp2YXIgdD10aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuc2NhbGVkQ2FudmFzV2lkdGgudG9GaXhlZCgwKSxyPXRoaXMuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucy5zY2FsZWRDYW52YXNIZWlnaHQudG9GaXhlZCgwKTt0aGlzLmNvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQoYy5DMC5FU0MrIls0OyIrcisiOyIrdCsidCIpO2JyZWFrO2Nhc2UgbC5XaW5kb3dzT3B0aW9uc1JlcG9ydFR5cGUuR0VUX0NFTExfU0laRV9QSVhFTFM6dmFyIGk9dGhpcy5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLnNjYWxlZENlbGxXaWR0aC50b0ZpeGVkKDApLG49dGhpcy5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLnNjYWxlZENlbGxIZWlnaHQudG9GaXhlZCgwKTt0aGlzLmNvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQoYy5DMC5FU0MrIls2OyIrbisiOyIraSsidCIpfX0sdC5wcm90b3R5cGUuY2FuY2VsPWZ1bmN0aW9uKGUsdCl7aWYodGhpcy5vcHRpb25zLmNhbmNlbEV2ZW50c3x8dClyZXR1cm4gZS5wcmV2ZW50RGVmYXVsdCgpLGUuc3RvcFByb3BhZ2F0aW9uKCksITF9LHQucHJvdG90eXBlLl92aXN1YWxCZWxsPWZ1bmN0aW9uKCl7cmV0dXJuITF9LHQucHJvdG90eXBlLl9zb3VuZEJlbGw9ZnVuY3Rpb24oKXtyZXR1cm4ic291bmQiPT09dGhpcy5vcHRpb25zLmJlbGxTdHlsZX0sdH0oUi5Db3JlVGVybWluYWwpO3QuVGVybWluYWw9UH0sOTkyNDooZSx0KT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlRpbWVCYXNlZERlYm91bmNlcj12b2lkIDA7dmFyIHI9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dm9pZCAwPT09dCYmKHQ9MWUzKSx0aGlzLl9yZW5kZXJDYWxsYmFjaz1lLHRoaXMuX2RlYm91bmNlVGhyZXNob2xkTVM9dCx0aGlzLl9sYXN0UmVmcmVzaE1zPTAsdGhpcy5fYWRkaXRpb25hbFJlZnJlc2hSZXF1ZXN0ZWQ9ITF9cmV0dXJuIGUucHJvdG90eXBlLmRpc3Bvc2U9ZnVuY3Rpb24oKXt0aGlzLl9yZWZyZXNoVGltZW91dElEJiZjbGVhclRpbWVvdXQodGhpcy5fcmVmcmVzaFRpbWVvdXRJRCl9LGUucHJvdG90eXBlLnJlZnJlc2g9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXM7dGhpcy5fcm93Q291bnQ9cixlPXZvaWQgMCE9PWU/ZTowLHQ9dm9pZCAwIT09dD90OnRoaXMuX3Jvd0NvdW50LTEsdGhpcy5fcm93U3RhcnQ9dm9pZCAwIT09dGhpcy5fcm93U3RhcnQ/TWF0aC5taW4odGhpcy5fcm93U3RhcnQsZSk6ZSx0aGlzLl9yb3dFbmQ9dm9pZCAwIT09dGhpcy5fcm93RW5kP01hdGgubWF4KHRoaXMuX3Jvd0VuZCx0KTp0O3ZhciBuPURhdGUubm93KCk7aWYobi10aGlzLl9sYXN0UmVmcmVzaE1zPj10aGlzLl9kZWJvdW5jZVRocmVzaG9sZE1TKXRoaXMuX2xhc3RSZWZyZXNoTXM9bix0aGlzLl9pbm5lclJlZnJlc2goKTtlbHNlIGlmKCF0aGlzLl9hZGRpdGlvbmFsUmVmcmVzaFJlcXVlc3RlZCl7dmFyIG89bi10aGlzLl9sYXN0UmVmcmVzaE1zLHM9dGhpcy5fZGVib3VuY2VUaHJlc2hvbGRNUy1vO3RoaXMuX2FkZGl0aW9uYWxSZWZyZXNoUmVxdWVzdGVkPSEwLHRoaXMuX3JlZnJlc2hUaW1lb3V0SUQ9d2luZG93LnNldFRpbWVvdXQoKGZ1bmN0aW9uKCl7aS5fbGFzdFJlZnJlc2hNcz1EYXRlLm5vdygpLGkuX2lubmVyUmVmcmVzaCgpLGkuX2FkZGl0aW9uYWxSZWZyZXNoUmVxdWVzdGVkPSExLGkuX3JlZnJlc2hUaW1lb3V0SUQ9dm9pZCAwfSkscyl9fSxlLnByb3RvdHlwZS5faW5uZXJSZWZyZXNoPWZ1bmN0aW9uKCl7aWYodm9pZCAwIT09dGhpcy5fcm93U3RhcnQmJnZvaWQgMCE9PXRoaXMuX3Jvd0VuZCYmdm9pZCAwIT09dGhpcy5fcm93Q291bnQpe3ZhciBlPU1hdGgubWF4KHRoaXMuX3Jvd1N0YXJ0LDApLHQ9TWF0aC5taW4odGhpcy5fcm93RW5kLHRoaXMuX3Jvd0NvdW50LTEpO3RoaXMuX3Jvd1N0YXJ0PXZvaWQgMCx0aGlzLl9yb3dFbmQ9dm9pZCAwLHRoaXMuX3JlbmRlckNhbGxiYWNrKGUsdCl9fSxlfSgpO3QuVGltZUJhc2VkRGVib3VuY2VyPXJ9LDE2ODA6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49dGhpcyYmdGhpcy5fX2V4dGVuZHN8fChpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGk9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQscikmJihlW3JdPXRbcl0pfSxpKGUsdCl9LGZ1bmN0aW9uKGUsdCl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIkNsYXNzIGV4dGVuZHMgdmFsdWUgIitTdHJpbmcodCkrIiBpcyBub3QgYSBjb25zdHJ1Y3RvciBvciBudWxsIik7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1pKGUsdCksZS5wcm90b3R5cGU9bnVsbD09PXQ/T2JqZWN0LmNyZWF0ZSh0KTooci5wcm90b3R5cGU9dC5wcm90b3R5cGUsbmV3IHIpfSksbz10aGlzJiZ0aGlzLl9fZGVjb3JhdGV8fGZ1bmN0aW9uKGUsdCxyLGkpe3ZhciBuLG89YXJndW1lbnRzLmxlbmd0aCxzPW88Mz90Om51bGw9PT1pP2k9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0LHIpOmk7aWYoIm9iamVjdCI9PXR5cGVvZiBSZWZsZWN0JiYiZnVuY3Rpb24iPT10eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSlzPVJlZmxlY3QuZGVjb3JhdGUoZSx0LHIsaSk7ZWxzZSBmb3IodmFyIGE9ZS5sZW5ndGgtMTthPj0wO2EtLSkobj1lW2FdKSYmKHM9KG88Mz9uKHMpOm8+Mz9uKHQscixzKTpuKHQscikpfHxzKTtyZXR1cm4gbz4zJiZzJiZPYmplY3QuZGVmaW5lUHJvcGVydHkodCxyLHMpLHN9LHM9dGhpcyYmdGhpcy5fX3BhcmFtfHxmdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbihyLGkpe3QocixpLGUpfX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuVmlld3BvcnQ9dm9pZCAwO3ZhciBhPXIoODQ0KSxjPXIoMzY1NiksbD1yKDQ3MjUpLHU9cigyNTg1KSxoPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCxyLGksbixvLHMsYSxsKXt2YXIgdT1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIHUuX3Njcm9sbExpbmVzPXQsdS5fdmlld3BvcnRFbGVtZW50PXIsdS5fc2Nyb2xsQXJlYT1pLHUuX2VsZW1lbnQ9bix1Ll9idWZmZXJTZXJ2aWNlPW8sdS5fb3B0aW9uc1NlcnZpY2U9cyx1Ll9jaGFyU2l6ZVNlcnZpY2U9YSx1Ll9yZW5kZXJTZXJ2aWNlPWwsdS5zY3JvbGxCYXJXaWR0aD0wLHUuX2N1cnJlbnRSb3dIZWlnaHQ9MCx1Ll9jdXJyZW50U2NhbGVkQ2VsbEhlaWdodD0wLHUuX2xhc3RSZWNvcmRlZEJ1ZmZlckxlbmd0aD0wLHUuX2xhc3RSZWNvcmRlZFZpZXdwb3J0SGVpZ2h0PTAsdS5fbGFzdFJlY29yZGVkQnVmZmVySGVpZ2h0PTAsdS5fbGFzdFRvdWNoWT0wLHUuX2xhc3RTY3JvbGxUb3A9MCx1Ll9sYXN0SGFkU2Nyb2xsQmFyPSExLHUuX3doZWVsUGFydGlhbFNjcm9sbD0wLHUuX3JlZnJlc2hBbmltYXRpb25GcmFtZT1udWxsLHUuX2lnbm9yZU5leHRTY3JvbGxFdmVudD0hMSx1LnNjcm9sbEJhcldpZHRoPXUuX3ZpZXdwb3J0RWxlbWVudC5vZmZzZXRXaWR0aC11Ll9zY3JvbGxBcmVhLm9mZnNldFdpZHRofHwxNSx1Ll9sYXN0SGFkU2Nyb2xsQmFyPSEwLHUucmVnaXN0ZXIoKDAsYy5hZGREaXNwb3NhYmxlRG9tTGlzdGVuZXIpKHUuX3ZpZXdwb3J0RWxlbWVudCwic2Nyb2xsIix1Ll9vblNjcm9sbC5iaW5kKHUpKSksdS5fYWN0aXZlQnVmZmVyPXUuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLHUucmVnaXN0ZXIodS5fYnVmZmVyU2VydmljZS5idWZmZXJzLm9uQnVmZmVyQWN0aXZhdGUoKGZ1bmN0aW9uKGUpe3JldHVybiB1Ll9hY3RpdmVCdWZmZXI9ZS5hY3RpdmVCdWZmZXJ9KSkpLHUuX3JlbmRlckRpbWVuc2lvbnM9dS5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLHUucmVnaXN0ZXIodS5fcmVuZGVyU2VydmljZS5vbkRpbWVuc2lvbnNDaGFuZ2UoKGZ1bmN0aW9uKGUpe3JldHVybiB1Ll9yZW5kZXJEaW1lbnNpb25zPWV9KSkpLHNldFRpbWVvdXQoKGZ1bmN0aW9uKCl7cmV0dXJuIHUuc3luY1Njcm9sbEFyZWEoKX0pLDApLHV9cmV0dXJuIG4odCxlKSx0LnByb3RvdHlwZS5vblRoZW1lQ2hhbmdlPWZ1bmN0aW9uKGUpe3RoaXMuX3ZpZXdwb3J0RWxlbWVudC5zdHlsZS5iYWNrZ3JvdW5kQ29sb3I9ZS5iYWNrZ3JvdW5kLmNzc30sdC5wcm90b3R5cGUuX3JlZnJlc2g9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcztpZihlKXJldHVybiB0aGlzLl9pbm5lclJlZnJlc2goKSx2b2lkKG51bGwhPT10aGlzLl9yZWZyZXNoQW5pbWF0aW9uRnJhbWUmJmNhbmNlbEFuaW1hdGlvbkZyYW1lKHRoaXMuX3JlZnJlc2hBbmltYXRpb25GcmFtZSkpO251bGw9PT10aGlzLl9yZWZyZXNoQW5pbWF0aW9uRnJhbWUmJih0aGlzLl9yZWZyZXNoQW5pbWF0aW9uRnJhbWU9cmVxdWVzdEFuaW1hdGlvbkZyYW1lKChmdW5jdGlvbigpe3JldHVybiB0Ll9pbm5lclJlZnJlc2goKX0pKSl9LHQucHJvdG90eXBlLl9pbm5lclJlZnJlc2g9ZnVuY3Rpb24oKXtpZih0aGlzLl9jaGFyU2l6ZVNlcnZpY2UuaGVpZ2h0PjApe3RoaXMuX2N1cnJlbnRSb3dIZWlnaHQ9dGhpcy5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLnNjYWxlZENlbGxIZWlnaHQvd2luZG93LmRldmljZVBpeGVsUmF0aW8sdGhpcy5fY3VycmVudFNjYWxlZENlbGxIZWlnaHQ9dGhpcy5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLnNjYWxlZENlbGxIZWlnaHQsdGhpcy5fbGFzdFJlY29yZGVkVmlld3BvcnRIZWlnaHQ9dGhpcy5fdmlld3BvcnRFbGVtZW50Lm9mZnNldEhlaWdodDt2YXIgZT1NYXRoLnJvdW5kKHRoaXMuX2N1cnJlbnRSb3dIZWlnaHQqdGhpcy5fbGFzdFJlY29yZGVkQnVmZmVyTGVuZ3RoKSsodGhpcy5fbGFzdFJlY29yZGVkVmlld3BvcnRIZWlnaHQtdGhpcy5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLmNhbnZhc0hlaWdodCk7dGhpcy5fbGFzdFJlY29yZGVkQnVmZmVySGVpZ2h0IT09ZSYmKHRoaXMuX2xhc3RSZWNvcmRlZEJ1ZmZlckhlaWdodD1lLHRoaXMuX3Njcm9sbEFyZWEuc3R5bGUuaGVpZ2h0PXRoaXMuX2xhc3RSZWNvcmRlZEJ1ZmZlckhlaWdodCsicHgiKX12YXIgdD10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55ZGlzcCp0aGlzLl9jdXJyZW50Um93SGVpZ2h0O3RoaXMuX3ZpZXdwb3J0RWxlbWVudC5zY3JvbGxUb3AhPT10JiYodGhpcy5faWdub3JlTmV4dFNjcm9sbEV2ZW50PSEwLHRoaXMuX3ZpZXdwb3J0RWxlbWVudC5zY3JvbGxUb3A9dCksMD09PXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuc2Nyb2xsYmFjaz90aGlzLnNjcm9sbEJhcldpZHRoPTA6dGhpcy5zY3JvbGxCYXJXaWR0aD10aGlzLl92aWV3cG9ydEVsZW1lbnQub2Zmc2V0V2lkdGgtdGhpcy5fc2Nyb2xsQXJlYS5vZmZzZXRXaWR0aHx8MTUsdGhpcy5fbGFzdEhhZFNjcm9sbEJhcj10aGlzLnNjcm9sbEJhcldpZHRoPjA7dmFyIHI9d2luZG93LmdldENvbXB1dGVkU3R5bGUodGhpcy5fZWxlbWVudCksaT1wYXJzZUludChyLnBhZGRpbmdMZWZ0KStwYXJzZUludChyLnBhZGRpbmdSaWdodCk7dGhpcy5fdmlld3BvcnRFbGVtZW50LnN0eWxlLndpZHRoPSh0aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbFdpZHRoKnRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyt0aGlzLnNjcm9sbEJhcldpZHRoKyh0aGlzLl9sYXN0SGFkU2Nyb2xsQmFyP2k6MCkpLnRvU3RyaW5nKCkrInB4Iix0aGlzLl9yZWZyZXNoQW5pbWF0aW9uRnJhbWU9bnVsbH0sdC5wcm90b3R5cGUuc3luY1Njcm9sbEFyZWE9ZnVuY3Rpb24oZSl7aWYodm9pZCAwPT09ZSYmKGU9ITEpLHRoaXMuX2xhc3RSZWNvcmRlZEJ1ZmZlckxlbmd0aCE9PXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLmxpbmVzLmxlbmd0aClyZXR1cm4gdGhpcy5fbGFzdFJlY29yZGVkQnVmZmVyTGVuZ3RoPXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLmxpbmVzLmxlbmd0aCx2b2lkIHRoaXMuX3JlZnJlc2goZSk7dGhpcy5fbGFzdFJlY29yZGVkVmlld3BvcnRIZWlnaHQ9PT10aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuY2FudmFzSGVpZ2h0JiZ0aGlzLl9sYXN0U2Nyb2xsVG9wPT09dGhpcy5fYWN0aXZlQnVmZmVyLnlkaXNwKnRoaXMuX2N1cnJlbnRSb3dIZWlnaHQmJnRoaXMuX3JlbmRlckRpbWVuc2lvbnMuc2NhbGVkQ2VsbEhlaWdodD09PXRoaXMuX2N1cnJlbnRTY2FsZWRDZWxsSGVpZ2h0P3RoaXMuX2xhc3RIYWRTY3JvbGxCYXIhPT10aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLnNjcm9sbGJhY2s+MCYmdGhpcy5fcmVmcmVzaChlKTp0aGlzLl9yZWZyZXNoKGUpfSx0LnByb3RvdHlwZS5fb25TY3JvbGw9ZnVuY3Rpb24oZSl7aWYodGhpcy5fbGFzdFNjcm9sbFRvcD10aGlzLl92aWV3cG9ydEVsZW1lbnQuc2Nyb2xsVG9wLHRoaXMuX3ZpZXdwb3J0RWxlbWVudC5vZmZzZXRQYXJlbnQpe2lmKHRoaXMuX2lnbm9yZU5leHRTY3JvbGxFdmVudClyZXR1cm4gdGhpcy5faWdub3JlTmV4dFNjcm9sbEV2ZW50PSExLHZvaWQgdGhpcy5fc2Nyb2xsTGluZXMoMCk7dmFyIHQ9TWF0aC5yb3VuZCh0aGlzLl9sYXN0U2Nyb2xsVG9wL3RoaXMuX2N1cnJlbnRSb3dIZWlnaHQpLXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwO3RoaXMuX3Njcm9sbExpbmVzKHQpfX0sdC5wcm90b3R5cGUuX2J1YmJsZVNjcm9sbD1mdW5jdGlvbihlLHQpe3ZhciByPXRoaXMuX3ZpZXdwb3J0RWxlbWVudC5zY3JvbGxUb3ArdGhpcy5fbGFzdFJlY29yZGVkVmlld3BvcnRIZWlnaHQ7cmV0dXJuISh0PDAmJjAhPT10aGlzLl92aWV3cG9ydEVsZW1lbnQuc2Nyb2xsVG9wfHx0PjAmJnI8dGhpcy5fbGFzdFJlY29yZGVkQnVmZmVySGVpZ2h0KXx8KGUuY2FuY2VsYWJsZSYmZS5wcmV2ZW50RGVmYXVsdCgpLCExKX0sdC5wcm90b3R5cGUub25XaGVlbD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9nZXRQaXhlbHNTY3JvbGxlZChlKTtyZXR1cm4gMCE9PXQmJih0aGlzLl92aWV3cG9ydEVsZW1lbnQuc2Nyb2xsVG9wKz10LHRoaXMuX2J1YmJsZVNjcm9sbChlLHQpKX0sdC5wcm90b3R5cGUuX2dldFBpeGVsc1Njcm9sbGVkPWZ1bmN0aW9uKGUpe2lmKDA9PT1lLmRlbHRhWXx8ZS5zaGlmdEtleSlyZXR1cm4gMDt2YXIgdD10aGlzLl9hcHBseVNjcm9sbE1vZGlmaWVyKGUuZGVsdGFZLGUpO3JldHVybiBlLmRlbHRhTW9kZT09PVdoZWVsRXZlbnQuRE9NX0RFTFRBX0xJTkU/dCo9dGhpcy5fY3VycmVudFJvd0hlaWdodDplLmRlbHRhTW9kZT09PVdoZWVsRXZlbnQuRE9NX0RFTFRBX1BBR0UmJih0Kj10aGlzLl9jdXJyZW50Um93SGVpZ2h0KnRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyksdH0sdC5wcm90b3R5cGUuZ2V0TGluZXNTY3JvbGxlZD1mdW5jdGlvbihlKXtpZigwPT09ZS5kZWx0YVl8fGUuc2hpZnRLZXkpcmV0dXJuIDA7dmFyIHQ9dGhpcy5fYXBwbHlTY3JvbGxNb2RpZmllcihlLmRlbHRhWSxlKTtyZXR1cm4gZS5kZWx0YU1vZGU9PT1XaGVlbEV2ZW50LkRPTV9ERUxUQV9QSVhFTD8odC89dGhpcy5fY3VycmVudFJvd0hlaWdodCswLHRoaXMuX3doZWVsUGFydGlhbFNjcm9sbCs9dCx0PU1hdGguZmxvb3IoTWF0aC5hYnModGhpcy5fd2hlZWxQYXJ0aWFsU2Nyb2xsKSkqKHRoaXMuX3doZWVsUGFydGlhbFNjcm9sbD4wPzE6LTEpLHRoaXMuX3doZWVsUGFydGlhbFNjcm9sbCU9MSk6ZS5kZWx0YU1vZGU9PT1XaGVlbEV2ZW50LkRPTV9ERUxUQV9QQUdFJiYodCo9dGhpcy5fYnVmZmVyU2VydmljZS5yb3dzKSx0fSx0LnByb3RvdHlwZS5fYXBwbHlTY3JvbGxNb2RpZmllcj1mdW5jdGlvbihlLHQpe3ZhciByPXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuZmFzdFNjcm9sbE1vZGlmaWVyO3JldHVybiJhbHQiPT09ciYmdC5hbHRLZXl8fCJjdHJsIj09PXImJnQuY3RybEtleXx8InNoaWZ0Ij09PXImJnQuc2hpZnRLZXk/ZSp0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmZhc3RTY3JvbGxTZW5zaXRpdml0eSp0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLnNjcm9sbFNlbnNpdGl2aXR5OmUqdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5zY3JvbGxTZW5zaXRpdml0eX0sdC5wcm90b3R5cGUub25Ub3VjaFN0YXJ0PWZ1bmN0aW9uKGUpe3RoaXMuX2xhc3RUb3VjaFk9ZS50b3VjaGVzWzBdLnBhZ2VZfSx0LnByb3RvdHlwZS5vblRvdWNoTW92ZT1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9sYXN0VG91Y2hZLWUudG91Y2hlc1swXS5wYWdlWTtyZXR1cm4gdGhpcy5fbGFzdFRvdWNoWT1lLnRvdWNoZXNbMF0ucGFnZVksMCE9PXQmJih0aGlzLl92aWV3cG9ydEVsZW1lbnQuc2Nyb2xsVG9wKz10LHRoaXMuX2J1YmJsZVNjcm9sbChlLHQpKX0sbyhbcyg0LHUuSUJ1ZmZlclNlcnZpY2UpLHMoNSx1LklPcHRpb25zU2VydmljZSkscyg2LGwuSUNoYXJTaXplU2VydmljZSkscyg3LGwuSVJlbmRlclNlcnZpY2UpXSx0KX0oYS5EaXNwb3NhYmxlKTt0LlZpZXdwb3J0PWh9LDI5NTA6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXMmJnRoaXMuX19kZWNvcmF0ZXx8ZnVuY3Rpb24oZSx0LHIsaSl7dmFyIG4sbz1hcmd1bWVudHMubGVuZ3RoLHM9bzwzP3Q6bnVsbD09PWk/aT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHQscik6aTtpZigib2JqZWN0Ij09dHlwZW9mIFJlZmxlY3QmJiJmdW5jdGlvbiI9PXR5cGVvZiBSZWZsZWN0LmRlY29yYXRlKXM9UmVmbGVjdC5kZWNvcmF0ZShlLHQscixpKTtlbHNlIGZvcih2YXIgYT1lLmxlbmd0aC0xO2E+PTA7YS0tKShuPWVbYV0pJiYocz0obzwzP24ocyk6bz4zP24odCxyLHMpOm4odCxyKSl8fHMpO3JldHVybiBvPjMmJnMmJk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LHIscyksc30sbj10aGlzJiZ0aGlzLl9fcGFyYW18fGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIsaSl7dChyLGksZSl9fTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Db21wb3NpdGlvbkhlbHBlcj12b2lkIDA7dmFyIG89cig0NzI1KSxzPXIoMjU4NSksYT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0LHIsaSxuLG8pe3RoaXMuX3RleHRhcmVhPWUsdGhpcy5fY29tcG9zaXRpb25WaWV3PXQsdGhpcy5fYnVmZmVyU2VydmljZT1yLHRoaXMuX29wdGlvbnNTZXJ2aWNlPWksdGhpcy5fY29yZVNlcnZpY2U9bix0aGlzLl9yZW5kZXJTZXJ2aWNlPW8sdGhpcy5faXNDb21wb3Npbmc9ITEsdGhpcy5faXNTZW5kaW5nQ29tcG9zaXRpb249ITEsdGhpcy5fY29tcG9zaXRpb25Qb3NpdGlvbj17c3RhcnQ6MCxlbmQ6MH0sdGhpcy5fZGF0YUFscmVhZHlTZW50PSIifXJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImlzQ29tcG9zaW5nIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2lzQ29tcG9zaW5nfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLmNvbXBvc2l0aW9uc3RhcnQ9ZnVuY3Rpb24oKXt0aGlzLl9pc0NvbXBvc2luZz0hMCx0aGlzLl9jb21wb3NpdGlvblBvc2l0aW9uLnN0YXJ0PXRoaXMuX3RleHRhcmVhLnZhbHVlLmxlbmd0aCx0aGlzLl9jb21wb3NpdGlvblZpZXcudGV4dENvbnRlbnQ9IiIsdGhpcy5fZGF0YUFscmVhZHlTZW50PSIiLHRoaXMuX2NvbXBvc2l0aW9uVmlldy5jbGFzc0xpc3QuYWRkKCJhY3RpdmUiKX0sZS5wcm90b3R5cGUuY29tcG9zaXRpb251cGRhdGU9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpczt0aGlzLl9jb21wb3NpdGlvblZpZXcudGV4dENvbnRlbnQ9ZS5kYXRhLHRoaXMudXBkYXRlQ29tcG9zaXRpb25FbGVtZW50cygpLHNldFRpbWVvdXQoKGZ1bmN0aW9uKCl7dC5fY29tcG9zaXRpb25Qb3NpdGlvbi5lbmQ9dC5fdGV4dGFyZWEudmFsdWUubGVuZ3RofSksMCl9LGUucHJvdG90eXBlLmNvbXBvc2l0aW9uZW5kPWZ1bmN0aW9uKCl7dGhpcy5fZmluYWxpemVDb21wb3NpdGlvbighMCl9LGUucHJvdG90eXBlLmtleWRvd249ZnVuY3Rpb24oZSl7aWYodGhpcy5faXNDb21wb3Npbmd8fHRoaXMuX2lzU2VuZGluZ0NvbXBvc2l0aW9uKXtpZigyMjk9PT1lLmtleUNvZGUpcmV0dXJuITE7aWYoMTY9PT1lLmtleUNvZGV8fDE3PT09ZS5rZXlDb2RlfHwxOD09PWUua2V5Q29kZSlyZXR1cm4hMTt0aGlzLl9maW5hbGl6ZUNvbXBvc2l0aW9uKCExKX1yZXR1cm4gMjI5IT09ZS5rZXlDb2RlfHwodGhpcy5faGFuZGxlQW55VGV4dGFyZWFDaGFuZ2VzKCksITEpfSxlLnByb3RvdHlwZS5fZmluYWxpemVDb21wb3NpdGlvbj1mdW5jdGlvbihlKXt2YXIgdD10aGlzO2lmKHRoaXMuX2NvbXBvc2l0aW9uVmlldy5jbGFzc0xpc3QucmVtb3ZlKCJhY3RpdmUiKSx0aGlzLl9pc0NvbXBvc2luZz0hMSxlKXt2YXIgcj17c3RhcnQ6dGhpcy5fY29tcG9zaXRpb25Qb3NpdGlvbi5zdGFydCxlbmQ6dGhpcy5fY29tcG9zaXRpb25Qb3NpdGlvbi5lbmR9O3RoaXMuX2lzU2VuZGluZ0NvbXBvc2l0aW9uPSEwLHNldFRpbWVvdXQoKGZ1bmN0aW9uKCl7dmFyIGU7dC5faXNTZW5kaW5nQ29tcG9zaXRpb24mJih0Ll9pc1NlbmRpbmdDb21wb3NpdGlvbj0hMSxyLnN0YXJ0Kz10Ll9kYXRhQWxyZWFkeVNlbnQubGVuZ3RoLChlPXQuX2lzQ29tcG9zaW5nP3QuX3RleHRhcmVhLnZhbHVlLnN1YnN0cmluZyhyLnN0YXJ0LHIuZW5kKTp0Ll90ZXh0YXJlYS52YWx1ZS5zdWJzdHJpbmcoci5zdGFydCkpLmxlbmd0aD4wJiZ0Ll9jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KGUsITApKX0pLDApfWVsc2V7dGhpcy5faXNTZW5kaW5nQ29tcG9zaXRpb249ITE7dmFyIGk9dGhpcy5fdGV4dGFyZWEudmFsdWUuc3Vic3RyaW5nKHRoaXMuX2NvbXBvc2l0aW9uUG9zaXRpb24uc3RhcnQsdGhpcy5fY29tcG9zaXRpb25Qb3NpdGlvbi5lbmQpO3RoaXMuX2NvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQoaSwhMCl9fSxlLnByb3RvdHlwZS5faGFuZGxlQW55VGV4dGFyZWFDaGFuZ2VzPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PXRoaXMuX3RleHRhcmVhLnZhbHVlO3NldFRpbWVvdXQoKGZ1bmN0aW9uKCl7aWYoIWUuX2lzQ29tcG9zaW5nKXt2YXIgcj1lLl90ZXh0YXJlYS52YWx1ZS5yZXBsYWNlKHQsIiIpO3IubGVuZ3RoPjAmJihlLl9kYXRhQWxyZWFkeVNlbnQ9cixlLl9jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KHIsITApKX19KSwwKX0sZS5wcm90b3R5cGUudXBkYXRlQ29tcG9zaXRpb25FbGVtZW50cz1mdW5jdGlvbihlKXt2YXIgdD10aGlzO2lmKHRoaXMuX2lzQ29tcG9zaW5nKXtpZih0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci5pc0N1cnNvckluVmlld3BvcnQpe3ZhciByPU1hdGgubWluKHRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLngsdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLTEpLGk9dGhpcy5fcmVuZGVyU2VydmljZS5kaW1lbnNpb25zLmFjdHVhbENlbGxIZWlnaHQsbj10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55KnRoaXMuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0LG89cip0aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbFdpZHRoO3RoaXMuX2NvbXBvc2l0aW9uVmlldy5zdHlsZS5sZWZ0PW8rInB4Iix0aGlzLl9jb21wb3NpdGlvblZpZXcuc3R5bGUudG9wPW4rInB4Iix0aGlzLl9jb21wb3NpdGlvblZpZXcuc3R5bGUuaGVpZ2h0PWkrInB4Iix0aGlzLl9jb21wb3NpdGlvblZpZXcuc3R5bGUubGluZUhlaWdodD1pKyJweCIsdGhpcy5fY29tcG9zaXRpb25WaWV3LnN0eWxlLmZvbnRGYW1pbHk9dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5mb250RmFtaWx5LHRoaXMuX2NvbXBvc2l0aW9uVmlldy5zdHlsZS5mb250U2l6ZT10aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmZvbnRTaXplKyJweCI7dmFyIHM9dGhpcy5fY29tcG9zaXRpb25WaWV3LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO3RoaXMuX3RleHRhcmVhLnN0eWxlLmxlZnQ9bysicHgiLHRoaXMuX3RleHRhcmVhLnN0eWxlLnRvcD1uKyJweCIsdGhpcy5fdGV4dGFyZWEuc3R5bGUud2lkdGg9TWF0aC5tYXgocy53aWR0aCwxKSsicHgiLHRoaXMuX3RleHRhcmVhLnN0eWxlLmhlaWdodD1NYXRoLm1heChzLmhlaWdodCwxKSsicHgiLHRoaXMuX3RleHRhcmVhLnN0eWxlLmxpbmVIZWlnaHQ9cy5oZWlnaHQrInB4In1lfHxzZXRUaW1lb3V0KChmdW5jdGlvbigpe3JldHVybiB0LnVwZGF0ZUNvbXBvc2l0aW9uRWxlbWVudHMoITApfSksMCl9fSxpKFtuKDIscy5JQnVmZmVyU2VydmljZSksbigzLHMuSU9wdGlvbnNTZXJ2aWNlKSxuKDQscy5JQ29yZVNlcnZpY2UpLG4oNSxvLklSZW5kZXJTZXJ2aWNlKV0sZSl9KCk7dC5Db21wb3NpdGlvbkhlbHBlcj1hfSw5ODA2OihlLHQpPT57ZnVuY3Rpb24gcihlLHQpe3ZhciByPXQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7cmV0dXJuW2UuY2xpZW50WC1yLmxlZnQsZS5jbGllbnRZLXIudG9wXX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5nZXRSYXdCeXRlQ29vcmRzPXQuZ2V0Q29vcmRzPXQuZ2V0Q29vcmRzUmVsYXRpdmVUb0VsZW1lbnQ9dm9pZCAwLHQuZ2V0Q29vcmRzUmVsYXRpdmVUb0VsZW1lbnQ9cix0LmdldENvb3Jkcz1mdW5jdGlvbihlLHQsaSxuLG8scyxhLGMpe2lmKG8pe3ZhciBsPXIoZSx0KTtpZihsKXJldHVybiBsWzBdPU1hdGguY2VpbCgobFswXSsoYz9zLzI6MCkpL3MpLGxbMV09TWF0aC5jZWlsKGxbMV0vYSksbFswXT1NYXRoLm1pbihNYXRoLm1heChsWzBdLDEpLGkrKGM/MTowKSksbFsxXT1NYXRoLm1pbihNYXRoLm1heChsWzFdLDEpLG4pLGx9fSx0LmdldFJhd0J5dGVDb29yZHM9ZnVuY3Rpb24oZSl7aWYoZSlyZXR1cm57eDplWzBdKzMyLHk6ZVsxXSszMn19fSw5NTA0OihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5tb3ZlVG9DZWxsU2VxdWVuY2U9dm9pZCAwO3ZhciBpPXIoMjU4NCk7ZnVuY3Rpb24gbihlLHQscixpKXt2YXIgbj1lLW8ocixlKSxhPXQtbyhyLHQpLHU9TWF0aC5hYnMobi1hKS1mdW5jdGlvbihlLHQscil7Zm9yKHZhciBpPTAsbj1lLW8ocixlKSxhPXQtbyhyLHQpLGM9MDtjPE1hdGguYWJzKG4tYSk7YysrKXt2YXIgbD0iQSI9PT1zKGUsdCk/LTE6MSx1PXIuYnVmZmVyLmxpbmVzLmdldChuK2wqYyk7KG51bGw9PXU/dm9pZCAwOnUuaXNXcmFwcGVkKSYmaSsrfXJldHVybiBpfShlLHQscik7cmV0dXJuIGwodSxjKHMoZSx0KSxpKSl9ZnVuY3Rpb24gbyhlLHQpe2Zvcih2YXIgcj0wLGk9ZS5idWZmZXIubGluZXMuZ2V0KHQpLG49bnVsbD09aT92b2lkIDA6aS5pc1dyYXBwZWQ7biYmdD49MCYmdDxlLnJvd3M7KXIrKyxuPW51bGw9PShpPWUuYnVmZmVyLmxpbmVzLmdldCgtLXQpKT92b2lkIDA6aS5pc1dyYXBwZWQ7cmV0dXJuIHJ9ZnVuY3Rpb24gcyhlLHQpe3JldHVybiBlPnQ/IkEiOiJCIn1mdW5jdGlvbiBhKGUsdCxyLGksbixvKXtmb3IodmFyIHM9ZSxhPXQsYz0iIjtzIT09cnx8YSE9PWk7KXMrPW4/MTotMSxuJiZzPm8uY29scy0xPyhjKz1vLmJ1ZmZlci50cmFuc2xhdGVCdWZmZXJMaW5lVG9TdHJpbmcoYSwhMSxlLHMpLHM9MCxlPTAsYSsrKTohbiYmczwwJiYoYys9by5idWZmZXIudHJhbnNsYXRlQnVmZmVyTGluZVRvU3RyaW5nKGEsITEsMCxlKzEpLGU9cz1vLmNvbHMtMSxhLS0pO3JldHVybiBjK28uYnVmZmVyLnRyYW5zbGF0ZUJ1ZmZlckxpbmVUb1N0cmluZyhhLCExLGUscyl9ZnVuY3Rpb24gYyhlLHQpe3ZhciByPXQ/Ik8iOiJbIjtyZXR1cm4gaS5DMC5FU0MrcitlfWZ1bmN0aW9uIGwoZSx0KXtlPU1hdGguZmxvb3IoZSk7Zm9yKHZhciByPSIiLGk9MDtpPGU7aSsrKXIrPXQ7cmV0dXJuIHJ9dC5tb3ZlVG9DZWxsU2VxdWVuY2U9ZnVuY3Rpb24oZSx0LHIsaSl7dmFyIHMsdT1yLmJ1ZmZlci54LGg9ci5idWZmZXIueTtpZighci5idWZmZXIuaGFzU2Nyb2xsYmFjaylyZXR1cm4gZnVuY3Rpb24oZSx0LHIsaSxzLHUpe3JldHVybiAwPT09bih0LGkscyx1KS5sZW5ndGg/IiI6bChhKGUsdCxlLHQtbyhzLHQpLCExLHMpLmxlbmd0aCxjKCJEIix1KSl9KHUsaCwwLHQscixpKStuKGgsdCxyLGkpK2Z1bmN0aW9uKGUsdCxyLGkscyx1KXt2YXIgaDtoPW4odCxpLHMsdSkubGVuZ3RoPjA/aS1vKHMsaSk6dDt2YXIgZj1pLF89ZnVuY3Rpb24oZSx0LHIsaSxzLGEpe3ZhciBjO3JldHVybiBjPW4ocixpLHMsYSkubGVuZ3RoPjA/aS1vKHMsaSk6dCxlPHImJmM8PWl8fGU+PXImJmM8aT8iQyI6IkQifShlLHQscixpLHMsdSk7cmV0dXJuIGwoYShlLGgscixmLCJDIj09PV8scykubGVuZ3RoLGMoXyx1KSl9KHUsaCxlLHQscixpKTtpZihoPT09dClyZXR1cm4gcz11PmU/IkQiOiJDIixsKE1hdGguYWJzKHUtZSksYyhzLGkpKTtzPWg+dD8iRCI6IkMiO3ZhciBmPU1hdGguYWJzKGgtdCk7cmV0dXJuIGwoZnVuY3Rpb24oZSx0KXtyZXR1cm4gdC5jb2xzLWV9KGg+dD9lOnUscikrKGYtMSkqci5jb2xzKzErKChoPnQ/dTplKS0xKSxjKHMsaSkpfX0sMTU0NjooZSx0LHIpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQmFzZVJlbmRlckxheWVyPXZvaWQgMDt2YXIgaT1yKDY0Myksbj1yKDg4MDMpLG89cigxNDIwKSxzPXIoMzczNCksYT1yKDE3NTIpLGM9cig0Nzc0KSxsPXIoOTYzMSksdT1yKDg5NzgpLGg9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxyLGksbixvLHMsYSl7dGhpcy5fY29udGFpbmVyPWUsdGhpcy5fYWxwaGE9aSx0aGlzLl9jb2xvcnM9bix0aGlzLl9yZW5kZXJlcklkPW8sdGhpcy5fYnVmZmVyU2VydmljZT1zLHRoaXMuX29wdGlvbnNTZXJ2aWNlPWEsdGhpcy5fc2NhbGVkQ2hhcldpZHRoPTAsdGhpcy5fc2NhbGVkQ2hhckhlaWdodD0wLHRoaXMuX3NjYWxlZENlbGxXaWR0aD0wLHRoaXMuX3NjYWxlZENlbGxIZWlnaHQ9MCx0aGlzLl9zY2FsZWRDaGFyTGVmdD0wLHRoaXMuX3NjYWxlZENoYXJUb3A9MCx0aGlzLl9jdXJyZW50R2x5cGhJZGVudGlmaWVyPXtjaGFyczoiIixjb2RlOjAsYmc6MCxmZzowLGJvbGQ6ITEsZGltOiExLGl0YWxpYzohMX0sdGhpcy5fY2FudmFzPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImNhbnZhcyIpLHRoaXMuX2NhbnZhcy5jbGFzc0xpc3QuYWRkKCJ4dGVybS0iK3QrIi1sYXllciIpLHRoaXMuX2NhbnZhcy5zdHlsZS56SW5kZXg9ci50b1N0cmluZygpLHRoaXMuX2luaXRDYW52YXMoKSx0aGlzLl9jb250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5fY2FudmFzKX1yZXR1cm4gZS5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe3ZhciBlOygwLGwucmVtb3ZlRWxlbWVudEZyb21QYXJlbnQpKHRoaXMuX2NhbnZhcyksbnVsbD09PShlPXRoaXMuX2NoYXJBdGxhcyl8fHZvaWQgMD09PWV8fGUuZGlzcG9zZSgpfSxlLnByb3RvdHlwZS5faW5pdENhbnZhcz1mdW5jdGlvbigpe3RoaXMuX2N0eD0oMCxhLnRocm93SWZGYWxzeSkodGhpcy5fY2FudmFzLmdldENvbnRleHQoIjJkIix7YWxwaGE6dGhpcy5fYWxwaGF9KSksdGhpcy5fYWxwaGF8fHRoaXMuX2NsZWFyQWxsKCl9LGUucHJvdG90eXBlLm9uT3B0aW9uc0NoYW5nZWQ9ZnVuY3Rpb24oKXt9LGUucHJvdG90eXBlLm9uQmx1cj1mdW5jdGlvbigpe30sZS5wcm90b3R5cGUub25Gb2N1cz1mdW5jdGlvbigpe30sZS5wcm90b3R5cGUub25DdXJzb3JNb3ZlPWZ1bmN0aW9uKCl7fSxlLnByb3RvdHlwZS5vbkdyaWRDaGFuZ2VkPWZ1bmN0aW9uKGUsdCl7fSxlLnByb3RvdHlwZS5vblNlbGVjdGlvbkNoYW5nZWQ9ZnVuY3Rpb24oZSx0LHIpe3ZvaWQgMD09PXImJihyPSExKX0sZS5wcm90b3R5cGUuc2V0Q29sb3JzPWZ1bmN0aW9uKGUpe3RoaXMuX3JlZnJlc2hDaGFyQXRsYXMoZSl9LGUucHJvdG90eXBlLl9zZXRUcmFuc3BhcmVuY3k9ZnVuY3Rpb24oZSl7aWYoZSE9PXRoaXMuX2FscGhhKXt2YXIgdD10aGlzLl9jYW52YXM7dGhpcy5fYWxwaGE9ZSx0aGlzLl9jYW52YXM9dGhpcy5fY2FudmFzLmNsb25lTm9kZSgpLHRoaXMuX2luaXRDYW52YXMoKSx0aGlzLl9jb250YWluZXIucmVwbGFjZUNoaWxkKHRoaXMuX2NhbnZhcyx0KSx0aGlzLl9yZWZyZXNoQ2hhckF0bGFzKHRoaXMuX2NvbG9ycyksdGhpcy5vbkdyaWRDaGFuZ2VkKDAsdGhpcy5fYnVmZmVyU2VydmljZS5yb3dzLTEpfX0sZS5wcm90b3R5cGUuX3JlZnJlc2hDaGFyQXRsYXM9ZnVuY3Rpb24oZSl7dGhpcy5fc2NhbGVkQ2hhcldpZHRoPD0wJiZ0aGlzLl9zY2FsZWRDaGFySGVpZ2h0PD0wfHwodGhpcy5fY2hhckF0bGFzPSgwLG8uYWNxdWlyZUNoYXJBdGxhcykodGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucyx0aGlzLl9yZW5kZXJlcklkLGUsdGhpcy5fc2NhbGVkQ2hhcldpZHRoLHRoaXMuX3NjYWxlZENoYXJIZWlnaHQpLHRoaXMuX2NoYXJBdGxhcy53YXJtVXAoKSl9LGUucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbihlKXt0aGlzLl9zY2FsZWRDZWxsV2lkdGg9ZS5zY2FsZWRDZWxsV2lkdGgsdGhpcy5fc2NhbGVkQ2VsbEhlaWdodD1lLnNjYWxlZENlbGxIZWlnaHQsdGhpcy5fc2NhbGVkQ2hhcldpZHRoPWUuc2NhbGVkQ2hhcldpZHRoLHRoaXMuX3NjYWxlZENoYXJIZWlnaHQ9ZS5zY2FsZWRDaGFySGVpZ2h0LHRoaXMuX3NjYWxlZENoYXJMZWZ0PWUuc2NhbGVkQ2hhckxlZnQsdGhpcy5fc2NhbGVkQ2hhclRvcD1lLnNjYWxlZENoYXJUb3AsdGhpcy5fY2FudmFzLndpZHRoPWUuc2NhbGVkQ2FudmFzV2lkdGgsdGhpcy5fY2FudmFzLmhlaWdodD1lLnNjYWxlZENhbnZhc0hlaWdodCx0aGlzLl9jYW52YXMuc3R5bGUud2lkdGg9ZS5jYW52YXNXaWR0aCsicHgiLHRoaXMuX2NhbnZhcy5zdHlsZS5oZWlnaHQ9ZS5jYW52YXNIZWlnaHQrInB4Iix0aGlzLl9hbHBoYXx8dGhpcy5fY2xlYXJBbGwoKSx0aGlzLl9yZWZyZXNoQ2hhckF0bGFzKHRoaXMuX2NvbG9ycyl9LGUucHJvdG90eXBlLmNsZWFyVGV4dHVyZUF0bGFzPWZ1bmN0aW9uKCl7dmFyIGU7bnVsbD09PShlPXRoaXMuX2NoYXJBdGxhcyl8fHZvaWQgMD09PWV8fGUuY2xlYXIoKX0sZS5wcm90b3R5cGUuX2ZpbGxDZWxscz1mdW5jdGlvbihlLHQscixpKXt0aGlzLl9jdHguZmlsbFJlY3QoZSp0aGlzLl9zY2FsZWRDZWxsV2lkdGgsdCp0aGlzLl9zY2FsZWRDZWxsSGVpZ2h0LHIqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLGkqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodCl9LGUucHJvdG90eXBlLl9maWxsTWlkZGxlTGluZUF0Q2VsbHM9ZnVuY3Rpb24oZSx0LHIpe3ZvaWQgMD09PXImJihyPTEpO3ZhciBpPU1hdGguY2VpbCguNSp0aGlzLl9zY2FsZWRDZWxsSGVpZ2h0KTt0aGlzLl9jdHguZmlsbFJlY3QoZSp0aGlzLl9zY2FsZWRDZWxsV2lkdGgsKHQrMSkqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodC1pLXdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLHIqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvKX0sZS5wcm90b3R5cGUuX2ZpbGxCb3R0b21MaW5lQXRDZWxscz1mdW5jdGlvbihlLHQscil7dm9pZCAwPT09ciYmKHI9MSksdGhpcy5fY3R4LmZpbGxSZWN0KGUqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLCh0KzEpKnRoaXMuX3NjYWxlZENlbGxIZWlnaHQtd2luZG93LmRldmljZVBpeGVsUmF0aW8tMSxyKnRoaXMuX3NjYWxlZENlbGxXaWR0aCx3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyl9LGUucHJvdG90eXBlLl9maWxsTGVmdExpbmVBdENlbGw9ZnVuY3Rpb24oZSx0LHIpe3RoaXMuX2N0eC5maWxsUmVjdChlKnRoaXMuX3NjYWxlZENlbGxXaWR0aCx0KnRoaXMuX3NjYWxlZENlbGxIZWlnaHQsd2luZG93LmRldmljZVBpeGVsUmF0aW8qcix0aGlzLl9zY2FsZWRDZWxsSGVpZ2h0KX0sZS5wcm90b3R5cGUuX3N0cm9rZVJlY3RBdENlbGw9ZnVuY3Rpb24oZSx0LHIsaSl7dGhpcy5fY3R4LmxpbmVXaWR0aD13aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyx0aGlzLl9jdHguc3Ryb2tlUmVjdChlKnRoaXMuX3NjYWxlZENlbGxXaWR0aCt3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpby8yLHQqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodCt3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpby8yLHIqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLXdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLGkqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodC13aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyl9LGUucHJvdG90eXBlLl9jbGVhckFsbD1mdW5jdGlvbigpe3RoaXMuX2FscGhhP3RoaXMuX2N0eC5jbGVhclJlY3QoMCwwLHRoaXMuX2NhbnZhcy53aWR0aCx0aGlzLl9jYW52YXMuaGVpZ2h0KToodGhpcy5fY3R4LmZpbGxTdHlsZT10aGlzLl9jb2xvcnMuYmFja2dyb3VuZC5jc3MsdGhpcy5fY3R4LmZpbGxSZWN0KDAsMCx0aGlzLl9jYW52YXMud2lkdGgsdGhpcy5fY2FudmFzLmhlaWdodCkpfSxlLnByb3RvdHlwZS5fY2xlYXJDZWxscz1mdW5jdGlvbihlLHQscixpKXt0aGlzLl9hbHBoYT90aGlzLl9jdHguY2xlYXJSZWN0KGUqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLHQqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodCxyKnRoaXMuX3NjYWxlZENlbGxXaWR0aCxpKnRoaXMuX3NjYWxlZENlbGxIZWlnaHQpOih0aGlzLl9jdHguZmlsbFN0eWxlPXRoaXMuX2NvbG9ycy5iYWNrZ3JvdW5kLmNzcyx0aGlzLl9jdHguZmlsbFJlY3QoZSp0aGlzLl9zY2FsZWRDZWxsV2lkdGgsdCp0aGlzLl9zY2FsZWRDZWxsSGVpZ2h0LHIqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLGkqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodCkpfSxlLnByb3RvdHlwZS5fZmlsbENoYXJUcnVlQ29sb3I9ZnVuY3Rpb24oZSx0LHIpe3RoaXMuX2N0eC5mb250PXRoaXMuX2dldEZvbnQoITEsITEpLHRoaXMuX2N0eC50ZXh0QmFzZWxpbmU9bi5URVhUX0JBU0VMSU5FLHRoaXMuX2NsaXBSb3cocik7dmFyIGk9ITE7ITEhPT10aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmN1c3RvbUdseXBocyYmKGk9KDAsdS50cnlEcmF3Q3VzdG9tQ2hhcikodGhpcy5fY3R4LGUuZ2V0Q2hhcnMoKSx0KnRoaXMuX3NjYWxlZENlbGxXaWR0aCxyKnRoaXMuX3NjYWxlZENlbGxIZWlnaHQsdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLHRoaXMuX3NjYWxlZENlbGxIZWlnaHQpKSxpfHx0aGlzLl9jdHguZmlsbFRleHQoZS5nZXRDaGFycygpLHQqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoK3RoaXMuX3NjYWxlZENoYXJMZWZ0LHIqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodCt0aGlzLl9zY2FsZWRDaGFyVG9wK3RoaXMuX3NjYWxlZENoYXJIZWlnaHQpfSxlLnByb3RvdHlwZS5fZHJhd0NoYXJzPWZ1bmN0aW9uKGUsdCxyKXt2YXIgbyxzLGEsYz10aGlzLl9nZXRDb250cmFzdENvbG9yKGUpO2N8fGUuaXNGZ1JHQigpfHxlLmlzQmdSR0IoKT90aGlzLl9kcmF3VW5jYWNoZWRDaGFycyhlLHQscixjKTooZS5pc0ludmVyc2UoKT8ocz1lLmlzQmdEZWZhdWx0KCk/bi5JTlZFUlRFRF9ERUZBVUxUX0NPTE9SOmUuZ2V0QmdDb2xvcigpLGE9ZS5pc0ZnRGVmYXVsdCgpP24uSU5WRVJURURfREVGQVVMVF9DT0xPUjplLmdldEZnQ29sb3IoKSk6KGE9ZS5pc0JnRGVmYXVsdCgpP2kuREVGQVVMVF9DT0xPUjplLmdldEJnQ29sb3IoKSxzPWUuaXNGZ0RlZmF1bHQoKT9pLkRFRkFVTFRfQ09MT1I6ZS5nZXRGZ0NvbG9yKCkpLHMrPXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuZHJhd0JvbGRUZXh0SW5CcmlnaHRDb2xvcnMmJmUuaXNCb2xkKCkmJnM8OD84OjAsdGhpcy5fY3VycmVudEdseXBoSWRlbnRpZmllci5jaGFycz1lLmdldENoYXJzKCl8fGkuV0hJVEVTUEFDRV9DRUxMX0NIQVIsdGhpcy5fY3VycmVudEdseXBoSWRlbnRpZmllci5jb2RlPWUuZ2V0Q29kZSgpfHxpLldISVRFU1BBQ0VfQ0VMTF9DT0RFLHRoaXMuX2N1cnJlbnRHbHlwaElkZW50aWZpZXIuYmc9YSx0aGlzLl9jdXJyZW50R2x5cGhJZGVudGlmaWVyLmZnPXMsdGhpcy5fY3VycmVudEdseXBoSWRlbnRpZmllci5ib2xkPSEhZS5pc0JvbGQoKSx0aGlzLl9jdXJyZW50R2x5cGhJZGVudGlmaWVyLmRpbT0hIWUuaXNEaW0oKSx0aGlzLl9jdXJyZW50R2x5cGhJZGVudGlmaWVyLml0YWxpYz0hIWUuaXNJdGFsaWMoKSwobnVsbD09PShvPXRoaXMuX2NoYXJBdGxhcyl8fHZvaWQgMD09PW8/dm9pZCAwOm8uZHJhdyh0aGlzLl9jdHgsdGhpcy5fY3VycmVudEdseXBoSWRlbnRpZmllcix0KnRoaXMuX3NjYWxlZENlbGxXaWR0aCt0aGlzLl9zY2FsZWRDaGFyTGVmdCxyKnRoaXMuX3NjYWxlZENlbGxIZWlnaHQrdGhpcy5fc2NhbGVkQ2hhclRvcCkpfHx0aGlzLl9kcmF3VW5jYWNoZWRDaGFycyhlLHQscikpfSxlLnByb3RvdHlwZS5fZHJhd1VuY2FjaGVkQ2hhcnM9ZnVuY3Rpb24oZSx0LHIsaSl7aWYodGhpcy5fY3R4LnNhdmUoKSx0aGlzLl9jdHguZm9udD10aGlzLl9nZXRGb250KCEhZS5pc0JvbGQoKSwhIWUuaXNJdGFsaWMoKSksdGhpcy5fY3R4LnRleHRCYXNlbGluZT1uLlRFWFRfQkFTRUxJTkUsZS5pc0ludmVyc2UoKSlpZihpKXRoaXMuX2N0eC5maWxsU3R5bGU9aS5jc3M7ZWxzZSBpZihlLmlzQmdEZWZhdWx0KCkpdGhpcy5fY3R4LmZpbGxTdHlsZT1jLmNvbG9yLm9wYXF1ZSh0aGlzLl9jb2xvcnMuYmFja2dyb3VuZCkuY3NzO2Vsc2UgaWYoZS5pc0JnUkdCKCkpdGhpcy5fY3R4LmZpbGxTdHlsZT0icmdiKCIrcy5BdHRyaWJ1dGVEYXRhLnRvQ29sb3JSR0IoZS5nZXRCZ0NvbG9yKCkpLmpvaW4oIiwiKSsiKSI7ZWxzZXt2YXIgbz1lLmdldEJnQ29sb3IoKTt0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmRyYXdCb2xkVGV4dEluQnJpZ2h0Q29sb3JzJiZlLmlzQm9sZCgpJiZvPDgmJihvKz04KSx0aGlzLl9jdHguZmlsbFN0eWxlPXRoaXMuX2NvbG9ycy5hbnNpW29dLmNzc31lbHNlIGlmKGkpdGhpcy5fY3R4LmZpbGxTdHlsZT1pLmNzcztlbHNlIGlmKGUuaXNGZ0RlZmF1bHQoKSl0aGlzLl9jdHguZmlsbFN0eWxlPXRoaXMuX2NvbG9ycy5mb3JlZ3JvdW5kLmNzcztlbHNlIGlmKGUuaXNGZ1JHQigpKXRoaXMuX2N0eC5maWxsU3R5bGU9InJnYigiK3MuQXR0cmlidXRlRGF0YS50b0NvbG9yUkdCKGUuZ2V0RmdDb2xvcigpKS5qb2luKCIsIikrIikiO2Vsc2V7dmFyIGE9ZS5nZXRGZ0NvbG9yKCk7dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5kcmF3Qm9sZFRleHRJbkJyaWdodENvbG9ycyYmZS5pc0JvbGQoKSYmYTw4JiYoYSs9OCksdGhpcy5fY3R4LmZpbGxTdHlsZT10aGlzLl9jb2xvcnMuYW5zaVthXS5jc3N9dGhpcy5fY2xpcFJvdyhyKSxlLmlzRGltKCkmJih0aGlzLl9jdHguZ2xvYmFsQWxwaGE9bi5ESU1fT1BBQ0lUWSk7dmFyIGw9ITE7ITEhPT10aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmN1c3RvbUdseXBocyYmKGw9KDAsdS50cnlEcmF3Q3VzdG9tQ2hhcikodGhpcy5fY3R4LGUuZ2V0Q2hhcnMoKSx0KnRoaXMuX3NjYWxlZENlbGxXaWR0aCxyKnRoaXMuX3NjYWxlZENlbGxIZWlnaHQsdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLHRoaXMuX3NjYWxlZENlbGxIZWlnaHQpKSxsfHx0aGlzLl9jdHguZmlsbFRleHQoZS5nZXRDaGFycygpLHQqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoK3RoaXMuX3NjYWxlZENoYXJMZWZ0LHIqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodCt0aGlzLl9zY2FsZWRDaGFyVG9wK3RoaXMuX3NjYWxlZENoYXJIZWlnaHQpLHRoaXMuX2N0eC5yZXN0b3JlKCl9LGUucHJvdG90eXBlLl9jbGlwUm93PWZ1bmN0aW9uKGUpe3RoaXMuX2N0eC5iZWdpblBhdGgoKSx0aGlzLl9jdHgucmVjdCgwLGUqdGhpcy5fc2NhbGVkQ2VsbEhlaWdodCx0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMqdGhpcy5fc2NhbGVkQ2VsbFdpZHRoLHRoaXMuX3NjYWxlZENlbGxIZWlnaHQpLHRoaXMuX2N0eC5jbGlwKCl9LGUucHJvdG90eXBlLl9nZXRGb250PWZ1bmN0aW9uKGUsdCl7cmV0dXJuKHQ/Iml0YWxpYyI6IiIpKyIgIisoZT90aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmZvbnRXZWlnaHRCb2xkOnRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuZm9udFdlaWdodCkrIiAiK3RoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuZm9udFNpemUqd2luZG93LmRldmljZVBpeGVsUmF0aW8rInB4ICIrdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5mb250RmFtaWx5fSxlLnByb3RvdHlwZS5fZ2V0Q29udHJhc3RDb2xvcj1mdW5jdGlvbihlKXtpZigxIT09dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5taW5pbXVtQ29udHJhc3RSYXRpbyl7dmFyIHQ9dGhpcy5fY29sb3JzLmNvbnRyYXN0Q2FjaGUuZ2V0Q29sb3IoZS5iZyxlLmZnKTtpZih2b2lkIDAhPT10KXJldHVybiB0fHx2b2lkIDA7dmFyIHI9ZS5nZXRGZ0NvbG9yKCksaT1lLmdldEZnQ29sb3JNb2RlKCksbj1lLmdldEJnQ29sb3IoKSxvPWUuZ2V0QmdDb2xvck1vZGUoKSxzPSEhZS5pc0ludmVyc2UoKSxhPSEhZS5pc0ludmVyc2UoKTtpZihzKXt2YXIgbD1yO3I9bixuPWw7dmFyIHU9aTtpPW8sbz11fXZhciBoPXRoaXMuX3Jlc29sdmVCYWNrZ3JvdW5kUmdiYShvLG4scyksZj10aGlzLl9yZXNvbHZlRm9yZWdyb3VuZFJnYmEoaSxyLHMsYSksXz1jLnJnYmEuZW5zdXJlQ29udHJhc3RSYXRpbyhoLGYsdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5taW5pbXVtQ29udHJhc3RSYXRpbyk7aWYoXyl7dmFyIGQ9e2NzczpjLmNoYW5uZWxzLnRvQ3NzKF8+PjI0JjI1NSxfPj4xNiYyNTUsXz4+OCYyNTUpLHJnYmE6X307cmV0dXJuIHRoaXMuX2NvbG9ycy5jb250cmFzdENhY2hlLnNldENvbG9yKGUuYmcsZS5mZyxkKSxkfXRoaXMuX2NvbG9ycy5jb250cmFzdENhY2hlLnNldENvbG9yKGUuYmcsZS5mZyxudWxsKX19LGUucHJvdG90eXBlLl9yZXNvbHZlQmFja2dyb3VuZFJnYmE9ZnVuY3Rpb24oZSx0LHIpe3N3aXRjaChlKXtjYXNlIDE2Nzc3MjE2OmNhc2UgMzM1NTQ0MzI6cmV0dXJuIHRoaXMuX2NvbG9ycy5hbnNpW3RdLnJnYmE7Y2FzZSA1MDMzMTY0ODpyZXR1cm4gdDw8ODtkZWZhdWx0OnJldHVybiByP3RoaXMuX2NvbG9ycy5mb3JlZ3JvdW5kLnJnYmE6dGhpcy5fY29sb3JzLmJhY2tncm91bmQucmdiYX19LGUucHJvdG90eXBlLl9yZXNvbHZlRm9yZWdyb3VuZFJnYmE9ZnVuY3Rpb24oZSx0LHIsaSl7c3dpdGNoKGUpe2Nhc2UgMTY3NzcyMTY6Y2FzZSAzMzU1NDQzMjpyZXR1cm4gdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5kcmF3Qm9sZFRleHRJbkJyaWdodENvbG9ycyYmaSYmdDw4JiYodCs9OCksdGhpcy5fY29sb3JzLmFuc2lbdF0ucmdiYTtjYXNlIDUwMzMxNjQ4OnJldHVybiB0PDw4O2RlZmF1bHQ6cmV0dXJuIHI/dGhpcy5fY29sb3JzLmJhY2tncm91bmQucmdiYTp0aGlzLl9jb2xvcnMuZm9yZWdyb3VuZC5yZ2JhfX0sZX0oKTt0LkJhc2VSZW5kZXJMYXllcj1ofSwyNTEyOmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkN1cnNvclJlbmRlckxheWVyPXZvaWQgMDt2YXIgYT1yKDE1NDYpLGM9cig1MTEpLGw9cigyNTg1KSx1PXIoNDcyNSksaD02MDAsZj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQscixpLG4sbyxzLGEsbCx1KXt2YXIgaD1lLmNhbGwodGhpcyx0LCJjdXJzb3IiLHIsITAsaSxuLHMsYSl8fHRoaXM7cmV0dXJuIGguX29uUmVxdWVzdFJlZHJhdz1vLGguX2NvcmVTZXJ2aWNlPWwsaC5fY29yZUJyb3dzZXJTZXJ2aWNlPXUsaC5fY2VsbD1uZXcgYy5DZWxsRGF0YSxoLl9zdGF0ZT17eDowLHk6MCxpc0ZvY3VzZWQ6ITEsc3R5bGU6IiIsd2lkdGg6MH0saC5fY3Vyc29yUmVuZGVyZXJzPXtiYXI6aC5fcmVuZGVyQmFyQ3Vyc29yLmJpbmQoaCksYmxvY2s6aC5fcmVuZGVyQmxvY2tDdXJzb3IuYmluZChoKSx1bmRlcmxpbmU6aC5fcmVuZGVyVW5kZXJsaW5lQ3Vyc29yLmJpbmQoaCl9LGh9cmV0dXJuIG4odCxlKSx0LnByb3RvdHlwZS5kaXNwb3NlPWZ1bmN0aW9uKCl7dGhpcy5fY3Vyc29yQmxpbmtTdGF0ZU1hbmFnZXImJih0aGlzLl9jdXJzb3JCbGlua1N0YXRlTWFuYWdlci5kaXNwb3NlKCksdGhpcy5fY3Vyc29yQmxpbmtTdGF0ZU1hbmFnZXI9dm9pZCAwKSxlLnByb3RvdHlwZS5kaXNwb3NlLmNhbGwodGhpcyl9LHQucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbih0KXtlLnByb3RvdHlwZS5yZXNpemUuY2FsbCh0aGlzLHQpLHRoaXMuX3N0YXRlPXt4OjAseTowLGlzRm9jdXNlZDohMSxzdHlsZToiIix3aWR0aDowfX0sdC5wcm90b3R5cGUucmVzZXQ9ZnVuY3Rpb24oKXt2YXIgZTt0aGlzLl9jbGVhckN1cnNvcigpLG51bGw9PT0oZT10aGlzLl9jdXJzb3JCbGlua1N0YXRlTWFuYWdlcil8fHZvaWQgMD09PWV8fGUucmVzdGFydEJsaW5rQW5pbWF0aW9uKCksdGhpcy5vbk9wdGlvbnNDaGFuZ2VkKCl9LHQucHJvdG90eXBlLm9uQmx1cj1mdW5jdGlvbigpe3ZhciBlO251bGw9PT0oZT10aGlzLl9jdXJzb3JCbGlua1N0YXRlTWFuYWdlcil8fHZvaWQgMD09PWV8fGUucGF1c2UoKSx0aGlzLl9vblJlcXVlc3RSZWRyYXcuZmlyZSh7c3RhcnQ6dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueSxlbmQ6dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueX0pfSx0LnByb3RvdHlwZS5vbkZvY3VzPWZ1bmN0aW9uKCl7dmFyIGU7bnVsbD09PShlPXRoaXMuX2N1cnNvckJsaW5rU3RhdGVNYW5hZ2VyKXx8dm9pZCAwPT09ZXx8ZS5yZXN1bWUoKSx0aGlzLl9vblJlcXVlc3RSZWRyYXcuZmlyZSh7c3RhcnQ6dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueSxlbmQ6dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueX0pfSx0LnByb3RvdHlwZS5vbk9wdGlvbnNDaGFuZ2VkPWZ1bmN0aW9uKCl7dmFyIGUsdD10aGlzO3RoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuY3Vyc29yQmxpbms/dGhpcy5fY3Vyc29yQmxpbmtTdGF0ZU1hbmFnZXJ8fCh0aGlzLl9jdXJzb3JCbGlua1N0YXRlTWFuYWdlcj1uZXcgXyh0aGlzLl9jb3JlQnJvd3NlclNlcnZpY2UuaXNGb2N1c2VkLChmdW5jdGlvbigpe3QuX3JlbmRlcighMCl9KSkpOihudWxsPT09KGU9dGhpcy5fY3Vyc29yQmxpbmtTdGF0ZU1hbmFnZXIpfHx2b2lkIDA9PT1lfHxlLmRpc3Bvc2UoKSx0aGlzLl9jdXJzb3JCbGlua1N0YXRlTWFuYWdlcj12b2lkIDApLHRoaXMuX29uUmVxdWVzdFJlZHJhdy5maXJlKHtzdGFydDp0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55LGVuZDp0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55fSl9LHQucHJvdG90eXBlLm9uQ3Vyc29yTW92ZT1mdW5jdGlvbigpe3ZhciBlO251bGw9PT0oZT10aGlzLl9jdXJzb3JCbGlua1N0YXRlTWFuYWdlcil8fHZvaWQgMD09PWV8fGUucmVzdGFydEJsaW5rQW5pbWF0aW9uKCl9LHQucHJvdG90eXBlLm9uR3JpZENoYW5nZWQ9ZnVuY3Rpb24oZSx0KXshdGhpcy5fY3Vyc29yQmxpbmtTdGF0ZU1hbmFnZXJ8fHRoaXMuX2N1cnNvckJsaW5rU3RhdGVNYW5hZ2VyLmlzUGF1c2VkP3RoaXMuX3JlbmRlcighMSk6dGhpcy5fY3Vyc29yQmxpbmtTdGF0ZU1hbmFnZXIucmVzdGFydEJsaW5rQW5pbWF0aW9uKCl9LHQucHJvdG90eXBlLl9yZW5kZXI9ZnVuY3Rpb24oZSl7aWYodGhpcy5fY29yZVNlcnZpY2UuaXNDdXJzb3JJbml0aWFsaXplZCYmIXRoaXMuX2NvcmVTZXJ2aWNlLmlzQ3Vyc29ySGlkZGVuKXt2YXIgdD10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55YmFzZSt0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55LHI9dC10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55ZGlzcDtpZihyPDB8fHI+PXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyl0aGlzLl9jbGVhckN1cnNvcigpO2Vsc2V7dmFyIGk9TWF0aC5taW4odGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueCx0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMtMSk7aWYodGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIubGluZXMuZ2V0KHQpLmxvYWRDZWxsKGksdGhpcy5fY2VsbCksdm9pZCAwIT09dGhpcy5fY2VsbC5jb250ZW50KXtpZighdGhpcy5fY29yZUJyb3dzZXJTZXJ2aWNlLmlzRm9jdXNlZCl7dGhpcy5fY2xlYXJDdXJzb3IoKSx0aGlzLl9jdHguc2F2ZSgpLHRoaXMuX2N0eC5maWxsU3R5bGU9dGhpcy5fY29sb3JzLmN1cnNvci5jc3M7dmFyIG49dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5jdXJzb3JTdHlsZTtyZXR1cm4gbiYmImJsb2NrIiE9PW4/dGhpcy5fY3Vyc29yUmVuZGVyZXJzW25dKGkscix0aGlzLl9jZWxsKTp0aGlzLl9yZW5kZXJCbHVyQ3Vyc29yKGkscix0aGlzLl9jZWxsKSx0aGlzLl9jdHgucmVzdG9yZSgpLHRoaXMuX3N0YXRlLng9aSx0aGlzLl9zdGF0ZS55PXIsdGhpcy5fc3RhdGUuaXNGb2N1c2VkPSExLHRoaXMuX3N0YXRlLnN0eWxlPW4sdm9pZCh0aGlzLl9zdGF0ZS53aWR0aD10aGlzLl9jZWxsLmdldFdpZHRoKCkpfWlmKCF0aGlzLl9jdXJzb3JCbGlua1N0YXRlTWFuYWdlcnx8dGhpcy5fY3Vyc29yQmxpbmtTdGF0ZU1hbmFnZXIuaXNDdXJzb3JWaXNpYmxlKXtpZih0aGlzLl9zdGF0ZSl7aWYodGhpcy5fc3RhdGUueD09PWkmJnRoaXMuX3N0YXRlLnk9PT1yJiZ0aGlzLl9zdGF0ZS5pc0ZvY3VzZWQ9PT10aGlzLl9jb3JlQnJvd3NlclNlcnZpY2UuaXNGb2N1c2VkJiZ0aGlzLl9zdGF0ZS5zdHlsZT09PXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuY3Vyc29yU3R5bGUmJnRoaXMuX3N0YXRlLndpZHRoPT09dGhpcy5fY2VsbC5nZXRXaWR0aCgpKXJldHVybjt0aGlzLl9jbGVhckN1cnNvcigpfXRoaXMuX2N0eC5zYXZlKCksdGhpcy5fY3Vyc29yUmVuZGVyZXJzW3RoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuY3Vyc29yU3R5bGV8fCJibG9jayJdKGkscix0aGlzLl9jZWxsKSx0aGlzLl9jdHgucmVzdG9yZSgpLHRoaXMuX3N0YXRlLng9aSx0aGlzLl9zdGF0ZS55PXIsdGhpcy5fc3RhdGUuaXNGb2N1c2VkPSExLHRoaXMuX3N0YXRlLnN0eWxlPXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuY3Vyc29yU3R5bGUsdGhpcy5fc3RhdGUud2lkdGg9dGhpcy5fY2VsbC5nZXRXaWR0aCgpfWVsc2UgdGhpcy5fY2xlYXJDdXJzb3IoKX19fWVsc2UgdGhpcy5fY2xlYXJDdXJzb3IoKX0sdC5wcm90b3R5cGUuX2NsZWFyQ3Vyc29yPWZ1bmN0aW9uKCl7dGhpcy5fc3RhdGUmJih3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbzwxP3RoaXMuX2NsZWFyQWxsKCk6dGhpcy5fY2xlYXJDZWxscyh0aGlzLl9zdGF0ZS54LHRoaXMuX3N0YXRlLnksdGhpcy5fc3RhdGUud2lkdGgsMSksdGhpcy5fc3RhdGU9e3g6MCx5OjAsaXNGb2N1c2VkOiExLHN0eWxlOiIiLHdpZHRoOjB9KX0sdC5wcm90b3R5cGUuX3JlbmRlckJhckN1cnNvcj1mdW5jdGlvbihlLHQscil7dGhpcy5fY3R4LnNhdmUoKSx0aGlzLl9jdHguZmlsbFN0eWxlPXRoaXMuX2NvbG9ycy5jdXJzb3IuY3NzLHRoaXMuX2ZpbGxMZWZ0TGluZUF0Q2VsbChlLHQsdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5jdXJzb3JXaWR0aCksdGhpcy5fY3R4LnJlc3RvcmUoKX0sdC5wcm90b3R5cGUuX3JlbmRlckJsb2NrQ3Vyc29yPWZ1bmN0aW9uKGUsdCxyKXt0aGlzLl9jdHguc2F2ZSgpLHRoaXMuX2N0eC5maWxsU3R5bGU9dGhpcy5fY29sb3JzLmN1cnNvci5jc3MsdGhpcy5fZmlsbENlbGxzKGUsdCxyLmdldFdpZHRoKCksMSksdGhpcy5fY3R4LmZpbGxTdHlsZT10aGlzLl9jb2xvcnMuY3Vyc29yQWNjZW50LmNzcyx0aGlzLl9maWxsQ2hhclRydWVDb2xvcihyLGUsdCksdGhpcy5fY3R4LnJlc3RvcmUoKX0sdC5wcm90b3R5cGUuX3JlbmRlclVuZGVybGluZUN1cnNvcj1mdW5jdGlvbihlLHQscil7dGhpcy5fY3R4LnNhdmUoKSx0aGlzLl9jdHguZmlsbFN0eWxlPXRoaXMuX2NvbG9ycy5jdXJzb3IuY3NzLHRoaXMuX2ZpbGxCb3R0b21MaW5lQXRDZWxscyhlLHQpLHRoaXMuX2N0eC5yZXN0b3JlKCl9LHQucHJvdG90eXBlLl9yZW5kZXJCbHVyQ3Vyc29yPWZ1bmN0aW9uKGUsdCxyKXt0aGlzLl9jdHguc2F2ZSgpLHRoaXMuX2N0eC5zdHJva2VTdHlsZT10aGlzLl9jb2xvcnMuY3Vyc29yLmNzcyx0aGlzLl9zdHJva2VSZWN0QXRDZWxsKGUsdCxyLmdldFdpZHRoKCksMSksdGhpcy5fY3R4LnJlc3RvcmUoKX0sbyhbcyg1LGwuSUJ1ZmZlclNlcnZpY2UpLHMoNixsLklPcHRpb25zU2VydmljZSkscyg3LGwuSUNvcmVTZXJ2aWNlKSxzKDgsdS5JQ29yZUJyb3dzZXJTZXJ2aWNlKV0sdCl9KGEuQmFzZVJlbmRlckxheWVyKTt0LkN1cnNvclJlbmRlckxheWVyPWY7dmFyIF89ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy5fcmVuZGVyQ2FsbGJhY2s9dCx0aGlzLmlzQ3Vyc29yVmlzaWJsZT0hMCxlJiZ0aGlzLl9yZXN0YXJ0SW50ZXJ2YWwoKX1yZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJpc1BhdXNlZCIse2dldDpmdW5jdGlvbigpe3JldHVybiEodGhpcy5fYmxpbmtTdGFydFRpbWVvdXR8fHRoaXMuX2JsaW5rSW50ZXJ2YWwpfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLmRpc3Bvc2U9ZnVuY3Rpb24oKXt0aGlzLl9ibGlua0ludGVydmFsJiYod2luZG93LmNsZWFySW50ZXJ2YWwodGhpcy5fYmxpbmtJbnRlcnZhbCksdGhpcy5fYmxpbmtJbnRlcnZhbD12b2lkIDApLHRoaXMuX2JsaW5rU3RhcnRUaW1lb3V0JiYod2luZG93LmNsZWFyVGltZW91dCh0aGlzLl9ibGlua1N0YXJ0VGltZW91dCksdGhpcy5fYmxpbmtTdGFydFRpbWVvdXQ9dm9pZCAwKSx0aGlzLl9hbmltYXRpb25GcmFtZSYmKHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZSh0aGlzLl9hbmltYXRpb25GcmFtZSksdGhpcy5fYW5pbWF0aW9uRnJhbWU9dm9pZCAwKX0sZS5wcm90b3R5cGUucmVzdGFydEJsaW5rQW5pbWF0aW9uPWZ1bmN0aW9uKCl7dmFyIGU9dGhpczt0aGlzLmlzUGF1c2VkfHwodGhpcy5fYW5pbWF0aW9uVGltZVJlc3RhcnRlZD1EYXRlLm5vdygpLHRoaXMuaXNDdXJzb3JWaXNpYmxlPSEwLHRoaXMuX2FuaW1hdGlvbkZyYW1lfHwodGhpcy5fYW5pbWF0aW9uRnJhbWU9d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoZnVuY3Rpb24oKXtlLl9yZW5kZXJDYWxsYmFjaygpLGUuX2FuaW1hdGlvbkZyYW1lPXZvaWQgMH0pKSkpfSxlLnByb3RvdHlwZS5fcmVzdGFydEludGVydmFsPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7dm9pZCAwPT09ZSYmKGU9aCksdGhpcy5fYmxpbmtJbnRlcnZhbCYmKHdpbmRvdy5jbGVhckludGVydmFsKHRoaXMuX2JsaW5rSW50ZXJ2YWwpLHRoaXMuX2JsaW5rSW50ZXJ2YWw9dm9pZCAwKSx0aGlzLl9ibGlua1N0YXJ0VGltZW91dD13aW5kb3cuc2V0VGltZW91dCgoZnVuY3Rpb24oKXtpZih0Ll9hbmltYXRpb25UaW1lUmVzdGFydGVkKXt2YXIgZT1oLShEYXRlLm5vdygpLXQuX2FuaW1hdGlvblRpbWVSZXN0YXJ0ZWQpO2lmKHQuX2FuaW1hdGlvblRpbWVSZXN0YXJ0ZWQ9dm9pZCAwLGU+MClyZXR1cm4gdm9pZCB0Ll9yZXN0YXJ0SW50ZXJ2YWwoZSl9dC5pc0N1cnNvclZpc2libGU9ITEsdC5fYW5pbWF0aW9uRnJhbWU9d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoZnVuY3Rpb24oKXt0Ll9yZW5kZXJDYWxsYmFjaygpLHQuX2FuaW1hdGlvbkZyYW1lPXZvaWQgMH0pKSx0Ll9ibGlua0ludGVydmFsPXdpbmRvdy5zZXRJbnRlcnZhbCgoZnVuY3Rpb24oKXtpZih0Ll9hbmltYXRpb25UaW1lUmVzdGFydGVkKXt2YXIgZT1oLShEYXRlLm5vdygpLXQuX2FuaW1hdGlvblRpbWVSZXN0YXJ0ZWQpO3JldHVybiB0Ll9hbmltYXRpb25UaW1lUmVzdGFydGVkPXZvaWQgMCx2b2lkIHQuX3Jlc3RhcnRJbnRlcnZhbChlKX10LmlzQ3Vyc29yVmlzaWJsZT0hdC5pc0N1cnNvclZpc2libGUsdC5fYW5pbWF0aW9uRnJhbWU9d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSgoZnVuY3Rpb24oKXt0Ll9yZW5kZXJDYWxsYmFjaygpLHQuX2FuaW1hdGlvbkZyYW1lPXZvaWQgMH0pKX0pLGgpfSksZSl9LGUucHJvdG90eXBlLnBhdXNlPWZ1bmN0aW9uKCl7dGhpcy5pc0N1cnNvclZpc2libGU9ITAsdGhpcy5fYmxpbmtJbnRlcnZhbCYmKHdpbmRvdy5jbGVhckludGVydmFsKHRoaXMuX2JsaW5rSW50ZXJ2YWwpLHRoaXMuX2JsaW5rSW50ZXJ2YWw9dm9pZCAwKSx0aGlzLl9ibGlua1N0YXJ0VGltZW91dCYmKHdpbmRvdy5jbGVhclRpbWVvdXQodGhpcy5fYmxpbmtTdGFydFRpbWVvdXQpLHRoaXMuX2JsaW5rU3RhcnRUaW1lb3V0PXZvaWQgMCksdGhpcy5fYW5pbWF0aW9uRnJhbWUmJih3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUodGhpcy5fYW5pbWF0aW9uRnJhbWUpLHRoaXMuX2FuaW1hdGlvbkZyYW1lPXZvaWQgMCl9LGUucHJvdG90eXBlLnJlc3VtZT1mdW5jdGlvbigpe3RoaXMucGF1c2UoKSx0aGlzLl9hbmltYXRpb25UaW1lUmVzdGFydGVkPXZvaWQgMCx0aGlzLl9yZXN0YXJ0SW50ZXJ2YWwoKSx0aGlzLnJlc3RhcnRCbGlua0FuaW1hdGlvbigpfSxlfSgpfSw4OTc4OihlLHQscik9Pnt2YXIgaSxuLG8scyxhLGMsbCx1LGgsZixfLGQscCx2LGcseSxtLGIsUyxDLHcsTCxFLHgsQSxrLE0sUixULE8sQixELFAsSSxILGosRixXLFUscSxOLHosSyxWLEcsWSxYLFosSiwkLFEsZWUsdGUscmUsaWUsbmUsb2Usc2UsYWUsY2UsbGUsdWUsaGUsZmUsX2UsZGUscGUsdmUsZ2UseWUsbWUsYmUsU2UsQ2Usd2UsTGUsRWUseGUsQWUsa2UsTWUsUmUsVGUsT2UsQmUsRGUsUGUsSWUsSGUsamUsRmUsV2UsVWUscWUsTmUsemUsS2UsVmUsR2UsWWUsWGUsWmUsSmUsJGUsUWUsZXQsdHQscnQsaXQsbnQsb3Qsc3QsYXQsY3QsbHQsdXQsaHQsZnQsX3QsZHQscHQsdnQsZ3QseXQsbXQsYnQsU3QsQ3Q7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQudHJ5RHJhd0N1c3RvbUNoYXI9dC5ib3hEcmF3aW5nRGVmaW5pdGlvbnM9dC5ibG9ja0VsZW1lbnREZWZpbml0aW9ucz12b2lkIDA7dmFyIHd0PXIoMTc1Mik7dC5ibG9ja0VsZW1lbnREZWZpbml0aW9ucz17IuKWgCI6W3t4OjAseTowLHc6OCxoOjR9XSwi4paBIjpbe3g6MCx5Ojcsdzo4LGg6MX1dLCLiloIiOlt7eDowLHk6Nix3OjgsaDoyfV0sIuKWgyI6W3t4OjAseTo1LHc6OCxoOjN9XSwi4paEIjpbe3g6MCx5OjQsdzo4LGg6NH1dLCLiloUiOlt7eDowLHk6Myx3OjgsaDo1fV0sIuKWhiI6W3t4OjAseToyLHc6OCxoOjZ9XSwi4paHIjpbe3g6MCx5OjEsdzo4LGg6N31dLCLilogiOlt7eDowLHk6MCx3OjgsaDo4fV0sIuKWiSI6W3t4OjAseTowLHc6NyxoOjh9XSwi4paKIjpbe3g6MCx5OjAsdzo2LGg6OH1dLCLilosiOlt7eDowLHk6MCx3OjUsaDo4fV0sIuKWjCI6W3t4OjAseTowLHc6NCxoOjh9XSwi4paNIjpbe3g6MCx5OjAsdzozLGg6OH1dLCLilo4iOlt7eDowLHk6MCx3OjIsaDo4fV0sIuKWjyI6W3t4OjAseTowLHc6MSxoOjh9XSwi4paQIjpbe3g6NCx5OjAsdzo0LGg6OH1dLCLilpQiOlt7eDowLHk6MCx3OjksaDoxfV0sIuKWlSI6W3t4OjcseTowLHc6MSxoOjh9XSwi4paWIjpbe3g6MCx5OjQsdzo0LGg6NH1dLCLilpciOlt7eDo0LHk6NCx3OjQsaDo0fV0sIuKWmCI6W3t4OjAseTowLHc6NCxoOjR9XSwi4paZIjpbe3g6MCx5OjAsdzo0LGg6OH0se3g6MCx5OjQsdzo4LGg6NH1dLCLilpoiOlt7eDowLHk6MCx3OjQsaDo0fSx7eDo0LHk6NCx3OjQsaDo0fV0sIuKWmyI6W3t4OjAseTowLHc6NCxoOjh9LHt4OjAseTowLHc6NCxoOjh9XSwi4pacIjpbe3g6MCx5OjAsdzo4LGg6NH0se3g6NCx5OjAsdzo0LGg6OH1dLCLilp0iOlt7eDo0LHk6MCx3OjQsaDo0fV0sIuKWniI6W3t4OjQseTowLHc6NCxoOjR9LHt4OjAseTo0LHc6NCxoOjR9XSwi4pafIjpbe3g6NCx5OjAsdzo0LGg6OH0se3g6MCx5OjQsdzo4LGg6NH1dLCLwn62wIjpbe3g6MSx5OjAsdzoxLGg6OH1dLCLwn62xIjpbe3g6Mix5OjAsdzoxLGg6OH1dLCLwn62yIjpbe3g6Myx5OjAsdzoxLGg6OH1dLCLwn62zIjpbe3g6NCx5OjAsdzoxLGg6OH1dLCLwn620Ijpbe3g6NSx5OjAsdzoxLGg6OH1dLCLwn621Ijpbe3g6Nix5OjAsdzoxLGg6OH1dLCLwn622Ijpbe3g6MCx5OjEsdzo4LGg6MX1dLCLwn623Ijpbe3g6MCx5OjIsdzo4LGg6MX1dLCLwn624Ijpbe3g6MCx5OjMsdzo4LGg6MX1dLCLwn625Ijpbe3g6MCx5OjQsdzo4LGg6MX1dLCLwn626Ijpbe3g6MCx5OjUsdzo4LGg6MX1dLCLwn627Ijpbe3g6MCx5OjYsdzo4LGg6MX1dLCLwn628Ijpbe3g6MCx5OjAsdzoxLGg6OH0se3g6MCx5Ojcsdzo4LGg6MX1dLCLwn629Ijpbe3g6MCx5OjAsdzoxLGg6OH0se3g6MCx5OjAsdzo4LGg6MX1dLCLwn62+Ijpbe3g6Nyx5OjAsdzoxLGg6OH0se3g6MCx5OjAsdzo4LGg6MX1dLCLwn62/Ijpbe3g6Nyx5OjAsdzoxLGg6OH0se3g6MCx5Ojcsdzo4LGg6MX1dLCLwn66AIjpbe3g6MCx5OjAsdzo4LGg6MX0se3g6MCx5Ojcsdzo4LGg6MX1dLCLwn66BIjpbe3g6MCx5OjAsdzo4LGg6MX0se3g6MCx5OjIsdzo4LGg6MX0se3g6MCx5OjQsdzo4LGg6MX0se3g6MCx5Ojcsdzo4LGg6MX1dLCLwn66CIjpbe3g6MCx5OjAsdzo4LGg6Mn1dLCLwn66DIjpbe3g6MCx5OjAsdzo4LGg6M31dLCLwn66EIjpbe3g6MCx5OjAsdzo4LGg6NX1dLCLwn66FIjpbe3g6MCx5OjAsdzo4LGg6Nn1dLCLwn66GIjpbe3g6MCx5OjAsdzo4LGg6N31dLCLwn66HIjpbe3g6Nix5OjAsdzoyLGg6OH1dLCLwn66IIjpbe3g6NSx5OjAsdzozLGg6OH1dLCLwn66JIjpbe3g6Myx5OjAsdzo1LGg6OH1dLCLwn66KIjpbe3g6Mix5OjAsdzo2LGg6OH1dLCLwn66LIjpbe3g6MSx5OjAsdzo3LGg6OH1dLCLwn66VIjpbe3g6MCx5OjAsdzoyLGg6Mn0se3g6NCx5OjAsdzoyLGg6Mn0se3g6Mix5OjIsdzoyLGg6Mn0se3g6Nix5OjIsdzoyLGg6Mn0se3g6MCx5OjQsdzoyLGg6Mn0se3g6NCx5OjQsdzoyLGg6Mn0se3g6Mix5OjYsdzoyLGg6Mn0se3g6Nix5OjYsdzoyLGg6Mn1dLCLwn66WIjpbe3g6Mix5OjAsdzoyLGg6Mn0se3g6Nix5OjAsdzoyLGg6Mn0se3g6MCx5OjIsdzoyLGg6Mn0se3g6NCx5OjIsdzoyLGg6Mn0se3g6Mix5OjQsdzoyLGg6Mn0se3g6Nix5OjQsdzoyLGg6Mn0se3g6MCx5OjYsdzoyLGg6Mn0se3g6NCx5OjYsdzoyLGg6Mn1dLCLwn66XIjpbe3g6MCx5OjIsdzo4LGg6Mn0se3g6MCx5OjYsdzo4LGg6Mn1dfTt2YXIgTHQ9eyLilpEiOltbMSwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMSwwXSxbMCwwLDAsMF1dLCLilpIiOltbMSwwXSxbMCwwXSxbMCwxXSxbMCwwXV0sIuKWkyI6W1swLDFdLFsxLDFdLFsxLDBdLFsxLDFdXX07dC5ib3hEcmF3aW5nRGVmaW5pdGlvbnM9eyLilIAiOihpPXt9LGlbMV09Ik0wLC41IEwxLC41IixpKSwi4pSBIjoobj17fSxuWzNdPSJNMCwuNSBMMSwuNSIsbiksIuKUgiI6KG89e30sb1sxXT0iTS41LDAgTC41LDEiLG8pLCLilIMiOihzPXt9LHNbM109Ik0uNSwwIEwuNSwxIixzKSwi4pSMIjooYT17fSxhWzFdPSJNMC41LDEgTC41LC41IEwxLC41IixhKSwi4pSPIjooYz17fSxjWzNdPSJNMC41LDEgTC41LC41IEwxLC41IixjKSwi4pSQIjoobD17fSxsWzFdPSJNMCwuNSBMLjUsLjUgTC41LDEiLGwpLCLilJMiOih1PXt9LHVbM109Ik0wLC41IEwuNSwuNSBMLjUsMSIsdSksIuKUlCI6KGg9e30saFsxXT0iTS41LDAgTC41LC41IEwxLC41IixoKSwi4pSXIjooZj17fSxmWzNdPSJNLjUsMCBMLjUsLjUgTDEsLjUiLGYpLCLilJgiOihfPXt9LF9bMV09Ik0uNSwwIEwuNSwuNSBMMCwuNSIsXyksIuKUmyI6KGQ9e30sZFszXT0iTS41LDAgTC41LC41IEwwLC41IixkKSwi4pScIjoocD17fSxwWzFdPSJNLjUsMCBMLjUsMSBNLjUsLjUgTDEsLjUiLHApLCLilKMiOih2PXt9LHZbM109Ik0uNSwwIEwuNSwxIE0uNSwuNSBMMSwuNSIsdiksIuKUpCI6KGc9e30sZ1sxXT0iTS41LDAgTC41LDEgTS41LC41IEwwLC41IixnKSwi4pSrIjooeT17fSx5WzNdPSJNLjUsMCBMLjUsMSBNLjUsLjUgTDAsLjUiLHkpLCLilKwiOihtPXt9LG1bMV09Ik0wLC41IEwxLC41IE0uNSwuNSBMLjUsMSIsbSksIuKUsyI6KGI9e30sYlszXT0iTTAsLjUgTDEsLjUgTS41LC41IEwuNSwxIixiKSwi4pS0IjooUz17fSxTWzFdPSJNMCwuNSBMMSwuNSBNLjUsLjUgTC41LDAiLFMpLCLilLsiOihDPXt9LENbM109Ik0wLC41IEwxLC41IE0uNSwuNSBMLjUsMCIsQyksIuKUvCI6KHc9e30sd1sxXT0iTTAsLjUgTDEsLjUgTS41LDAgTC41LDEiLHcpLCLilYsiOihMPXt9LExbM109Ik0wLC41IEwxLC41IE0uNSwwIEwuNSwxIixMKSwi4pW0IjooRT17fSxFWzFdPSJNLjUsLjUgTDAsLjUiLEUpLCLilbgiOih4PXt9LHhbM109Ik0uNSwuNSBMMCwuNSIseCksIuKVtSI6KEE9e30sQVsxXT0iTS41LC41IEwuNSwwIixBKSwi4pW5Ijooaz17fSxrWzNdPSJNLjUsLjUgTC41LDAiLGspLCLilbYiOihNPXt9LE1bMV09Ik0uNSwuNSBMMSwuNSIsTSksIuKVuiI6KFI9e30sUlszXT0iTS41LC41IEwxLC41IixSKSwi4pW3IjooVD17fSxUWzFdPSJNLjUsLjUgTC41LDEiLFQpLCLilbsiOihPPXt9LE9bM109Ik0uNSwuNSBMLjUsMSIsTyksIuKVkCI6KEI9e30sQlsxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNMCwiKyguNS10KSsiIEwxLCIrKC41LXQpKyIgTTAsIisoLjUrdCkrIiBMMSwiKyguNSt0KX0sQiksIuKVkSI6KEQ9e30sRFsxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNIisoLjUtZSkrIiwwIEwiKyguNS1lKSsiLDEgTSIrKC41K2UpKyIsMCBMIisoLjUrZSkrIiwxIn0sRCksIuKVkiI6KFA9e30sUFsxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNLjUsMSBMLjUsIisoLjUtdCkrIiBMMSwiKyguNS10KSsiIE0uNSwiKyguNSt0KSsiIEwxLCIrKC41K3QpfSxQKSwi4pWTIjooST17fSxJWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0iKyguNS1lKSsiLDEgTCIrKC41LWUpKyIsLjUgTDEsLjUgTSIrKC41K2UpKyIsLjUgTCIrKC41K2UpKyIsMSJ9LEkpLCLilZQiOihIPXt9LEhbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTTEsIisoLjUtdCkrIiBMIisoLjUtZSkrIiwiKyguNS10KSsiIEwiKyguNS1lKSsiLDEgTTEsIisoLjUrdCkrIiBMIisoLjUrZSkrIiwiKyguNSt0KSsiIEwiKyguNStlKSsiLDEifSxIKSwi4pWVIjooaj17fSxqWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0wLCIrKC41LXQpKyIgTC41LCIrKC41LXQpKyIgTC41LDEgTTAsIisoLjUrdCkrIiBMLjUsIisoLjUrdCl9LGopLCLilZYiOihGPXt9LEZbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTSIrKC41K2UpKyIsMSBMIisoLjUrZSkrIiwuNSBMMCwuNSBNIisoLjUtZSkrIiwuNSBMIisoLjUtZSkrIiwxIn0sRiksIuKVlyI6KFc9e30sV1sxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNMCwiKyguNSt0KSsiIEwiKyguNS1lKSsiLCIrKC41K3QpKyIgTCIrKC41LWUpKyIsMSBNMCwiKyguNS10KSsiIEwiKyguNStlKSsiLCIrKC41LXQpKyIgTCIrKC41K2UpKyIsMSJ9LFcpLCLilZgiOihVPXt9LFVbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTS41LDAgTC41LCIrKC41K3QpKyIgTDEsIisoLjUrdCkrIiBNLjUsIisoLjUtdCkrIiBMMSwiKyguNS10KX0sVSksIuKVmSI6KHE9e30scVsxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNMSwuNSBMIisoLjUtZSkrIiwuNSBMIisoLjUtZSkrIiwwIE0iKyguNStlKSsiLC41IEwiKyguNStlKSsiLDAifSxxKSwi4pWaIjooTj17fSxOWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0xLCIrKC41LXQpKyIgTCIrKC41K2UpKyIsIisoLjUtdCkrIiBMIisoLjUrZSkrIiwwIE0xLCIrKC41K3QpKyIgTCIrKC41LWUpKyIsIisoLjUrdCkrIiBMIisoLjUtZSkrIiwwIn0sTiksIuKVmyI6KHo9e30selsxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNMCwiKyguNSt0KSsiIEwuNSwiKyguNSt0KSsiIEwuNSwwIE0wLCIrKC41LXQpKyIgTC41LCIrKC41LXQpfSx6KSwi4pWcIjooSz17fSxLWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0wLC41IEwiKyguNStlKSsiLC41IEwiKyguNStlKSsiLDAgTSIrKC41LWUpKyIsLjUgTCIrKC41LWUpKyIsMCJ9LEspLCLilZ0iOihWPXt9LFZbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTTAsIisoLjUtdCkrIiBMIisoLjUtZSkrIiwiKyguNS10KSsiIEwiKyguNS1lKSsiLDAgTTAsIisoLjUrdCkrIiBMIisoLjUrZSkrIiwiKyguNSt0KSsiIEwiKyguNStlKSsiLDAifSxWKSwi4pWeIjooRz17fSxHWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0uNSwwIEwuNSwxIE0uNSwiKyguNS10KSsiIEwxLCIrKC41LXQpKyIgTS41LCIrKC41K3QpKyIgTDEsIisoLjUrdCl9LEcpLCLilZ8iOihZPXt9LFlbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTSIrKC41LWUpKyIsMCBMIisoLjUtZSkrIiwxIE0iKyguNStlKSsiLDAgTCIrKC41K2UpKyIsMSBNIisoLjUrZSkrIiwuNSBMMSwuNSJ9LFkpLCLilaAiOihYPXt9LFhbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTSIrKC41LWUpKyIsMCBMIisoLjUtZSkrIiwxIE0xLCIrKC41K3QpKyIgTCIrKC41K2UpKyIsIisoLjUrdCkrIiBMIisoLjUrZSkrIiwxIE0xLCIrKC41LXQpKyIgTCIrKC41K2UpKyIsIisoLjUtdCkrIiBMIisoLjUrZSkrIiwwIn0sWCksIuKVoSI6KFo9e30sWlsxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNLjUsMCBMLjUsMSBNMCwiKyguNS10KSsiIEwuNSwiKyguNS10KSsiIE0wLCIrKC41K3QpKyIgTC41LCIrKC41K3QpfSxaKSwi4pWiIjooSj17fSxKWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0wLC41IEwiKyguNS1lKSsiLC41IE0iKyguNS1lKSsiLDAgTCIrKC41LWUpKyIsMSBNIisoLjUrZSkrIiwwIEwiKyguNStlKSsiLDEifSxKKSwi4pWjIjooJD17fSwkWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0iKyguNStlKSsiLDAgTCIrKC41K2UpKyIsMSBNMCwiKyguNSt0KSsiIEwiKyguNS1lKSsiLCIrKC41K3QpKyIgTCIrKC41LWUpKyIsMSBNMCwiKyguNS10KSsiIEwiKyguNS1lKSsiLCIrKC41LXQpKyIgTCIrKC41LWUpKyIsMCJ9LCQpLCLilaQiOihRPXt9LFFbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTTAsIisoLjUtdCkrIiBMMSwiKyguNS10KSsiIE0wLCIrKC41K3QpKyIgTDEsIisoLjUrdCkrIiBNLjUsIisoLjUrdCkrIiBMLjUsMSJ9LFEpLCLilaUiOihlZT17fSxlZVsxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNMCwuNSBMMSwuNSBNIisoLjUtZSkrIiwuNSBMIisoLjUtZSkrIiwxIE0iKyguNStlKSsiLC41IEwiKyguNStlKSsiLDEifSxlZSksIuKVpiI6KHRlPXt9LHRlWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0wLCIrKC41LXQpKyIgTDEsIisoLjUtdCkrIiBNMCwiKyguNSt0KSsiIEwiKyguNS1lKSsiLCIrKC41K3QpKyIgTCIrKC41LWUpKyIsMSBNMSwiKyguNSt0KSsiIEwiKyguNStlKSsiLCIrKC41K3QpKyIgTCIrKC41K2UpKyIsMSJ9LHRlKSwi4pWnIjoocmU9e30scmVbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTS41LDAgTC41LCIrKC41LXQpKyIgTTAsIisoLjUtdCkrIiBMMSwiKyguNS10KSsiIE0wLCIrKC41K3QpKyIgTDEsIisoLjUrdCl9LHJlKSwi4pWoIjooaWU9e30saWVbMV09ZnVuY3Rpb24oZSx0KXtyZXR1cm4iTTAsLjUgTDEsLjUgTSIrKC41LWUpKyIsLjUgTCIrKC41LWUpKyIsMCBNIisoLjUrZSkrIiwuNSBMIisoLjUrZSkrIiwwIn0saWUpLCLilakiOihuZT17fSxuZVsxXT1mdW5jdGlvbihlLHQpe3JldHVybiJNMCwiKyguNSt0KSsiIEwxLCIrKC41K3QpKyIgTTAsIisoLjUtdCkrIiBMIisoLjUtZSkrIiwiKyguNS10KSsiIEwiKyguNS1lKSsiLDAgTTEsIisoLjUtdCkrIiBMIisoLjUrZSkrIiwiKyguNS10KSsiIEwiKyguNStlKSsiLDAifSxuZSksIuKVqiI6KG9lPXt9LG9lWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0uNSwwIEwuNSwxIE0wLCIrKC41LXQpKyIgTDEsIisoLjUtdCkrIiBNMCwiKyguNSt0KSsiIEwxLCIrKC41K3QpfSxvZSksIuKVqyI6KHNlPXt9LHNlWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0wLC41IEwxLC41IE0iKyguNS1lKSsiLDAgTCIrKC41LWUpKyIsMSBNIisoLjUrZSkrIiwwIEwiKyguNStlKSsiLDEifSxzZSksIuKVrCI6KGFlPXt9LGFlWzFdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIk0wLCIrKC41K3QpKyIgTCIrKC41LWUpKyIsIisoLjUrdCkrIiBMIisoLjUtZSkrIiwxIE0xLCIrKC41K3QpKyIgTCIrKC41K2UpKyIsIisoLjUrdCkrIiBMIisoLjUrZSkrIiwxIE0wLCIrKC41LXQpKyIgTCIrKC41LWUpKyIsIisoLjUtdCkrIiBMIisoLjUtZSkrIiwwIE0xLCIrKC41LXQpKyIgTCIrKC41K2UpKyIsIisoLjUtdCkrIiBMIisoLjUrZSkrIiwwIn0sYWUpLCLilbEiOihjZT17fSxjZVsxXT0iTTEsMCBMMCwxIixjZSksIuKVsiI6KGxlPXt9LGxlWzFdPSJNMCwwIEwxLDEiLGxlKSwi4pWzIjoodWU9e30sdWVbMV09Ik0xLDAgTDAsMSBNMCwwIEwxLDEiLHVlKSwi4pW8IjooaGU9e30saGVbMV09Ik0uNSwuNSBMMCwuNSIsaGVbM109Ik0uNSwuNSBMMSwuNSIsaGUpLCLilb0iOihmZT17fSxmZVsxXT0iTS41LC41IEwuNSwwIixmZVszXT0iTS41LC41IEwuNSwxIixmZSksIuKVviI6KF9lPXt9LF9lWzFdPSJNLjUsLjUgTDEsLjUiLF9lWzNdPSJNLjUsLjUgTDAsLjUiLF9lKSwi4pW/IjooZGU9e30sZGVbMV09Ik0uNSwuNSBMLjUsMSIsZGVbM109Ik0uNSwuNSBMLjUsMCIsZGUpLCLilI0iOihwZT17fSxwZVsxXT0iTS41LC41IEwuNSwxIixwZVszXT0iTS41LC41IEwxLC41IixwZSksIuKUjiI6KHZlPXt9LHZlWzFdPSJNLjUsLjUgTDEsLjUiLHZlWzNdPSJNLjUsLjUgTC41LDEiLHZlKSwi4pSRIjooZ2U9e30sZ2VbMV09Ik0uNSwuNSBMLjUsMSIsZ2VbM109Ik0uNSwuNSBMMCwuNSIsZ2UpLCLilJIiOih5ZT17fSx5ZVsxXT0iTS41LC41IEwwLC41Iix5ZVszXT0iTS41LC41IEwuNSwxIix5ZSksIuKUlSI6KG1lPXt9LG1lWzFdPSJNLjUsLjUgTC41LDAiLG1lWzNdPSJNLjUsLjUgTDEsLjUiLG1lKSwi4pSWIjooYmU9e30sYmVbMV09Ik0uNSwuNSBMMSwuNSIsYmVbM109Ik0uNSwuNSBMLjUsMCIsYmUpLCLilJkiOihTZT17fSxTZVsxXT0iTS41LC41IEwuNSwwIixTZVszXT0iTS41LC41IEwwLC41IixTZSksIuKUmiI6KENlPXt9LENlWzFdPSJNLjUsLjUgTDAsLjUiLENlWzNdPSJNLjUsLjUgTC41LDAiLENlKSwi4pSdIjood2U9e30sd2VbMV09Ik0uNSwwIEwuNSwxIix3ZVszXT0iTS41LC41IEwxLC41Iix3ZSksIuKUniI6KExlPXt9LExlWzFdPSJNMC41LDEgTC41LC41IEwxLC41IixMZVszXT0iTS41LC41IEwuNSwwIixMZSksIuKUnyI6KEVlPXt9LEVlWzFdPSJNLjUsMCBMLjUsLjUgTDEsLjUiLEVlWzNdPSJNLjUsLjUgTC41LDEiLEVlKSwi4pSgIjooeGU9e30seGVbMV09Ik0uNSwuNSBMMSwuNSIseGVbM109Ik0uNSwwIEwuNSwxIix4ZSksIuKUoSI6KEFlPXt9LEFlWzFdPSJNLjUsLjUgTC41LDEiLEFlWzNdPSJNLjUsMCBMLjUsLjUgTDEsLjUiLEFlKSwi4pSiIjooa2U9e30sa2VbMV09Ik0uNSwuNSBMLjUsMCIsa2VbM109Ik0wLjUsMSBMLjUsLjUgTDEsLjUiLGtlKSwi4pSlIjooTWU9e30sTWVbMV09Ik0uNSwwIEwuNSwxIixNZVszXT0iTS41LC41IEwwLC41IixNZSksIuKUpiI6KFJlPXt9LFJlWzFdPSJNMCwuNSBMLjUsLjUgTC41LDEiLFJlWzNdPSJNLjUsLjUgTC41LDAiLFJlKSwi4pSnIjooVGU9e30sVGVbMV09Ik0uNSwwIEwuNSwuNSBMMCwuNSIsVGVbM109Ik0uNSwuNSBMLjUsMSIsVGUpLCLilKgiOihPZT17fSxPZVsxXT0iTS41LC41IEwwLC41IixPZVszXT0iTS41LDAgTC41LDEiLE9lKSwi4pSpIjooQmU9e30sQmVbMV09Ik0uNSwuNSBMLjUsMSIsQmVbM109Ik0uNSwwIEwuNSwuNSBMMCwuNSIsQmUpLCLilKoiOihEZT17fSxEZVsxXT0iTS41LC41IEwuNSwwIixEZVszXT0iTTAsLjUgTC41LC41IEwuNSwxIixEZSksIuKUrSI6KFBlPXt9LFBlWzFdPSJNMC41LDEgTC41LC41IEwxLC41IixQZVszXT0iTS41LC41IEwwLC41IixQZSksIuKUriI6KEllPXt9LEllWzFdPSJNMCwuNSBMLjUsLjUgTC41LDEiLEllWzNdPSJNLjUsLjUgTDEsLjUiLEllKSwi4pSvIjooSGU9e30sSGVbMV09Ik0uNSwuNSBMLjUsMSIsSGVbM109Ik0wLC41IEwxLC41IixIZSksIuKUsCI6KGplPXt9LGplWzFdPSJNMCwuNSBMMSwuNSIsamVbM109Ik0uNSwuNSBMLjUsMSIsamUpLCLilLEiOihGZT17fSxGZVsxXT0iTS41LC41IEwxLC41IixGZVszXT0iTTAsLjUgTC41LC41IEwuNSwxIixGZSksIuKUsiI6KFdlPXt9LFdlWzFdPSJNLjUsLjUgTDAsLjUiLFdlWzNdPSJNMC41LDEgTC41LC41IEwxLC41IixXZSksIuKUtSI6KFVlPXt9LFVlWzFdPSJNLjUsMCBMLjUsLjUgTDEsLjUiLFVlWzNdPSJNLjUsLjUgTDAsLjUiLFVlKSwi4pS2IjoocWU9e30scWVbMV09Ik0uNSwwIEwuNSwuNSBMMCwuNSIscWVbM109Ik0uNSwuNSBMMSwuNSIscWUpLCLilLciOihOZT17fSxOZVsxXT0iTS41LC41IEwuNSwwIixOZVszXT0iTTAsLjUgTDEsLjUiLE5lKSwi4pS4IjooemU9e30semVbMV09Ik0wLC41IEwxLC41Iix6ZVszXT0iTS41LC41IEwuNSwwIix6ZSksIuKUuSI6KEtlPXt9LEtlWzFdPSJNLjUsLjUgTDEsLjUiLEtlWzNdPSJNLjUsMCBMLjUsLjUgTDAsLjUiLEtlKSwi4pS6IjooVmU9e30sVmVbMV09Ik0uNSwuNSBMMCwuNSIsVmVbM109Ik0uNSwwIEwuNSwuNSBMMSwuNSIsVmUpLCLilL0iOihHZT17fSxHZVsxXT0iTS41LDAgTC41LDEgTS41LC41IEwxLC41IixHZVszXT0iTS41LC41IEwwLC41IixHZSksIuKUviI6KFllPXt9LFllWzFdPSJNLjUsMCBMLjUsMSBNLjUsLjUgTDAsLjUiLFllWzNdPSJNLjUsLjUgTDEsLjUiLFllKSwi4pS/IjooWGU9e30sWGVbMV09Ik0uNSwwIEwuNSwxIixYZVszXT0iTTAsLjUgTDEsLjUiLFhlKSwi4pWAIjooWmU9e30sWmVbMV09Ik0wLC41IEwxLC41IE0uNSwuNSBMLjUsMSIsWmVbM109Ik0uNSwuNSBMLjUsMCIsWmUpLCLilYEiOihKZT17fSxKZVsxXT0iTS41LC41IEwuNSwwIE0wLC41IEwxLC41IixKZVszXT0iTS41LC41IEwuNSwxIixKZSksIuKVgiI6KCRlPXt9LCRlWzFdPSJNMCwuNSBMMSwuNSIsJGVbM109Ik0uNSwwIEwuNSwxIiwkZSksIuKVgyI6KFFlPXt9LFFlWzFdPSJNMC41LDEgTC41LC41IEwxLC41IixRZVszXT0iTS41LDAgTC41LC41IEwwLC41IixRZSksIuKVhCI6KGV0PXt9LGV0WzFdPSJNMCwuNSBMLjUsLjUgTC41LDEiLGV0WzNdPSJNLjUsMCBMLjUsLjUgTDEsLjUiLGV0KSwi4pWFIjoodHQ9e30sdHRbMV09Ik0uNSwwIEwuNSwuNSBMMSwuNSIsdHRbM109Ik0wLC41IEwuNSwuNSBMLjUsMSIsdHQpLCLilYYiOihydD17fSxydFsxXT0iTS41LDAgTC41LC41IEwwLC41IixydFszXT0iTTAuNSwxIEwuNSwuNSBMMSwuNSIscnQpLCLilYciOihpdD17fSxpdFsxXT0iTS41LC41IEwuNSwxIixpdFszXT0iTS41LC41IEwuNSwwIE0wLC41IEwxLC41IixpdCksIuKViCI6KG50PXt9LG50WzFdPSJNLjUsLjUgTC41LDAiLG50WzNdPSJNMCwuNSBMMSwuNSBNLjUsLjUgTC41LDEiLG50KSwi4pWJIjoob3Q9e30sb3RbMV09Ik0uNSwuNSBMMSwuNSIsb3RbM109Ik0uNSwwIEwuNSwxIE0uNSwuNSBMMCwuNSIsb3QpLCLilYoiOihzdD17fSxzdFsxXT0iTS41LC41IEwwLC41IixzdFszXT0iTS41LDAgTC41LDEgTS41LC41IEwxLC41IixzdCksIuKVjCI6KGF0PXt9LGF0WzFdPSJNLjEsLjUgTC40LC41IE0uNiwuNSBMLjksLjUiLGF0KSwi4pWNIjooY3Q9e30sY3RbM109Ik0uMSwuNSBMLjQsLjUgTS42LC41IEwuOSwuNSIsY3QpLCLilIQiOihsdD17fSxsdFsxXT0iTS4wNjY3LC41IEwuMjY2NywuNSBNLjQsLjUgTC42LC41IE0uNzMzMywuNSBMLjkzMzMsLjUiLGx0KSwi4pSFIjoodXQ9e30sdXRbM109Ik0uMDY2NywuNSBMLjI2NjcsLjUgTS40LC41IEwuNiwuNSBNLjczMzMsLjUgTC45MzMzLC41Iix1dCksIuKUiCI6KGh0PXt9LGh0WzFdPSJNLjA1LC41IEwuMiwuNSBNLjMsLjUgTC40NSwuNSBNLjU1LC41IEwuNywuNSBNLjgsLjUgTC45NSwuNSIsaHQpLCLilIkiOihmdD17fSxmdFszXT0iTS4wNSwuNSBMLjIsLjUgTS4zLC41IEwuNDUsLjUgTS41NSwuNSBMLjcsLjUgTS44LC41IEwuOTUsLjUiLGZ0KSwi4pWOIjooX3Q9e30sX3RbMV09Ik0uNSwuMSBMLjUsLjQgTS41LC42IEwuNSwuOSIsX3QpLCLilY8iOihkdD17fSxkdFszXT0iTS41LC4xIEwuNSwuNCBNLjUsLjYgTC41LC45IixkdCksIuKUhiI6KHB0PXt9LHB0WzFdPSJNLjUsLjA2NjcgTC41LC4yNjY3IE0uNSwuNCBMLjUsLjYgTS41LC43MzMzIEwuNSwuOTMzMyIscHQpLCLilIciOih2dD17fSx2dFszXT0iTS41LC4wNjY3IEwuNSwuMjY2NyBNLjUsLjQgTC41LC42IE0uNSwuNzMzMyBMLjUsLjkzMzMiLHZ0KSwi4pSKIjooZ3Q9e30sZ3RbMV09Ik0uNSwuMDUgTC41LC4yIE0uNSwuMyBMLjUsLjQ1IEwuNSwuNTUgTS41LC43IEwuNSwuOTUiLGd0KSwi4pSLIjooeXQ9e30seXRbM109Ik0uNSwuMDUgTC41LC4yIE0uNSwuMyBMLjUsLjQ1IEwuNSwuNTUgTS41LC43IEwuNSwuOTUiLHl0KSwi4pWtIjoobXQ9e30sbXRbMV09IkMuNSwxLC41LC41LDEsLjUiLG10KSwi4pWuIjooYnQ9e30sYnRbMV09IkMuNSwxLC41LC41LDAsLjUiLGJ0KSwi4pWvIjooU3Q9e30sU3RbMV09IkMuNSwwLC41LC41LDAsLjUiLFN0KSwi4pWwIjooQ3Q9e30sQ3RbMV09IkMuNSwwLC41LC41LDEsLjUiLEN0KX0sdC50cnlEcmF3Q3VzdG9tQ2hhcj1mdW5jdGlvbihlLHIsaSxuLG8scyl7dmFyIGE9dC5ibG9ja0VsZW1lbnREZWZpbml0aW9uc1tyXTtpZihhKXJldHVybiBmdW5jdGlvbihlLHQscixpLG4sbyl7Zm9yKHZhciBzPTA7czx0Lmxlbmd0aDtzKyspe3ZhciBhPXRbc10sYz1uLzgsbD1vLzg7ZS5maWxsUmVjdChyK2EueCpjLGkrYS55KmwsYS53KmMsYS5oKmwpfX0oZSxhLGksbixvLHMpLCEwO3ZhciBjPUx0W3JdO2lmKGMpcmV0dXJuIGZ1bmN0aW9uKGUsdCxyLGksbixvKXt2YXIgcyxhPUV0LmdldCh0KTthfHwoYT1uZXcgTWFwLEV0LnNldCh0LGEpKTt2YXIgYz1lLmZpbGxTdHlsZTtpZigic3RyaW5nIiE9dHlwZW9mIGMpdGhyb3cgbmV3IEVycm9yKCdVbmV4cGVjdGVkIGZpbGxTdHlsZSB0eXBlICInK2MrJyInKTt2YXIgbD1hLmdldChjKTtpZighbCl7dmFyIHU9dFswXS5sZW5ndGgsaD10Lmxlbmd0aCxmPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImNhbnZhcyIpO2Yud2lkdGg9dSxmLmhlaWdodD1oO3ZhciBfPSgwLHd0LnRocm93SWZGYWxzeSkoZi5nZXRDb250ZXh0KCIyZCIpKSxkPW5ldyBJbWFnZURhdGEodSxoKSxwPXZvaWQgMCx2PXZvaWQgMCxnPXZvaWQgMCx5PXZvaWQgMDtpZihjLnN0YXJ0c1dpdGgoIiMiKSlwPXBhcnNlSW50KGMuc3Vic3RyKDEsMiksMTYpLHY9cGFyc2VJbnQoYy5zdWJzdHIoMywyKSwxNiksZz1wYXJzZUludChjLnN1YnN0cig1LDIpLDE2KSx5PWMubGVuZ3RoPjcmJnBhcnNlSW50KGMuc3Vic3RyKDcsMiksMTYpfHwxO2Vsc2V7aWYoIWMuc3RhcnRzV2l0aCgicmdiYSIpKXRocm93IG5ldyBFcnJvcignVW5leHBlY3RlZCBmaWxsU3R5bGUgY29sb3IgZm9ybWF0ICInK2MrJyIgd2hlbiBkcmF3aW5nIHBhdHRlcm4gZ2x5cGgnKTtwPShzPWMuc3Vic3RyaW5nKDUsYy5sZW5ndGgtMSkuc3BsaXQoIiwiKS5tYXAoKGZ1bmN0aW9uKGUpe3JldHVybiBwYXJzZUZsb2F0KGUpfSkpKVswXSx2PXNbMV0sZz1zWzJdLHk9c1szXX1mb3IodmFyIG09MDttPGg7bSsrKWZvcih2YXIgYj0wO2I8dTtiKyspZC5kYXRhWzQqKG0qdStiKV09cCxkLmRhdGFbNCoobSp1K2IpKzFdPXYsZC5kYXRhWzQqKG0qdStiKSsyXT1nLGQuZGF0YVs0KihtKnUrYikrM109dFttXVtiXSooMjU1KnkpO18ucHV0SW1hZ2VEYXRhKGQsMCwwKSxsPSgwLHd0LnRocm93SWZGYWxzeSkoZS5jcmVhdGVQYXR0ZXJuKGYsbnVsbCkpLGEuc2V0KGMsbCl9ZS5maWxsU3R5bGU9bCxlLmZpbGxSZWN0KHIsaSxuLG8pfShlLGMsaSxuLG8scyksITA7dmFyIGw9dC5ib3hEcmF3aW5nRGVmaW5pdGlvbnNbcl07cmV0dXJuISFsJiYoZnVuY3Rpb24oZSx0LHIsaSxuLG8pe2Uuc3Ryb2tlU3R5bGU9ZS5maWxsU3R5bGU7Zm9yKHZhciBzPTAsYT1PYmplY3QuZW50cmllcyh0KTtzPGEubGVuZ3RoO3MrKyl7dmFyIGM9YVtzXSxsPWNbMF0sdT1jWzFdO2UuYmVnaW5QYXRoKCksZS5saW5lV2lkdGg9d2luZG93LmRldmljZVBpeGVsUmF0aW8qTnVtYmVyLnBhcnNlSW50KGwpO2Zvcih2YXIgaD0wLGY9KCJmdW5jdGlvbiI9PXR5cGVvZiB1P3UoLjE1LC4xNS9vKm4pOnUpLnNwbGl0KCIgIik7aDxmLmxlbmd0aDtoKyspe3ZhciBfPWZbaF0sZD1fWzBdLHA9QXRbZF07aWYocCl7dmFyIHY9Xy5zdWJzdHJpbmcoMSkuc3BsaXQoIiwiKTt2WzBdJiZ2WzFdJiZwKGUsa3QodixuLG8scixpKSl9ZWxzZSBjb25zb2xlLmVycm9yKCdDb3VsZCBub3QgZmluZCBkcmF3aW5nIGluc3RydWN0aW9ucyBmb3IgIicrZCsnIicpfWUuc3Ryb2tlKCksZS5jbG9zZVBhdGgoKX19KGUsbCxpLG4sbyxzKSwhMCl9O3ZhciBFdD1uZXcgTWFwO2Z1bmN0aW9uIHh0KGUsdCxyKXtyZXR1cm4gdm9pZCAwPT09ciYmKHI9MCksTWF0aC5tYXgoTWF0aC5taW4oZSx0KSxyKX12YXIgQXQ9e0M6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5iZXppZXJDdXJ2ZVRvKHRbMF0sdFsxXSx0WzJdLHRbM10sdFs0XSx0WzVdKX0sTDpmdW5jdGlvbihlLHQpe3JldHVybiBlLmxpbmVUbyh0WzBdLHRbMV0pfSxNOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUubW92ZVRvKHRbMF0sdFsxXSl9fTtmdW5jdGlvbiBrdChlLHQscixpLG4pe3ZhciBvPWUubWFwKChmdW5jdGlvbihlKXtyZXR1cm4gcGFyc2VGbG9hdChlKXx8cGFyc2VJbnQoZSl9KSk7aWYoby5sZW5ndGg8Mil0aHJvdyBuZXcgRXJyb3IoIlRvbyBmZXcgYXJndW1lbnRzIGZvciBpbnN0cnVjdGlvbiIpO2Zvcih2YXIgcz0wO3M8by5sZW5ndGg7cys9MilvW3NdKj10LDAhPT1vW3NdJiYob1tzXT14dChNYXRoLnJvdW5kKG9bc10rLjUpLS41LHQsMCkpLG9bc10rPWk7Zm9yKHZhciBhPTE7YTxvLmxlbmd0aDthKz0yKW9bYV0qPXIsMCE9PW9bYV0mJihvW2FdPXh0KE1hdGgucm91bmQob1thXSsuNSktLjUsciwwKSksb1thXSs9bjtyZXR1cm4gb319LDM3MDA6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5HcmlkQ2FjaGU9dm9pZCAwO3ZhciByPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMuY2FjaGU9W119cmV0dXJuIGUucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbihlLHQpe2Zvcih2YXIgcj0wO3I8ZTtyKyspe3RoaXMuY2FjaGUubGVuZ3RoPD1yJiZ0aGlzLmNhY2hlLnB1c2goW10pO2Zvcih2YXIgaT10aGlzLmNhY2hlW3JdLmxlbmd0aDtpPHQ7aSsrKXRoaXMuY2FjaGVbcl0ucHVzaCh2b2lkIDApO3RoaXMuY2FjaGVbcl0ubGVuZ3RoPXR9dGhpcy5jYWNoZS5sZW5ndGg9ZX0sZS5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXtmb3IodmFyIGU9MDtlPHRoaXMuY2FjaGUubGVuZ3RoO2UrKylmb3IodmFyIHQ9MDt0PHRoaXMuY2FjaGVbZV0ubGVuZ3RoO3QrKyl0aGlzLmNhY2hlW2VdW3RdPXZvaWQgMH0sZX0oKTt0LkdyaWRDYWNoZT1yfSw1MDk4OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkxpbmtSZW5kZXJMYXllcj12b2lkIDA7dmFyIGE9cigxNTQ2KSxjPXIoODgwMyksbD1yKDIwNDApLHU9cigyNTg1KSxoPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCxyLGksbixvLHMsYSxjKXt2YXIgbD1lLmNhbGwodGhpcyx0LCJsaW5rIixyLCEwLGksbixhLGMpfHx0aGlzO3JldHVybiBvLm9uU2hvd0xpbmtVbmRlcmxpbmUoKGZ1bmN0aW9uKGUpe3JldHVybiBsLl9vblNob3dMaW5rVW5kZXJsaW5lKGUpfSkpLG8ub25IaWRlTGlua1VuZGVybGluZSgoZnVuY3Rpb24oZSl7cmV0dXJuIGwuX29uSGlkZUxpbmtVbmRlcmxpbmUoZSl9KSkscy5vblNob3dMaW5rVW5kZXJsaW5lKChmdW5jdGlvbihlKXtyZXR1cm4gbC5fb25TaG93TGlua1VuZGVybGluZShlKX0pKSxzLm9uSGlkZUxpbmtVbmRlcmxpbmUoKGZ1bmN0aW9uKGUpe3JldHVybiBsLl9vbkhpZGVMaW5rVW5kZXJsaW5lKGUpfSkpLGx9cmV0dXJuIG4odCxlKSx0LnByb3RvdHlwZS5yZXNpemU9ZnVuY3Rpb24odCl7ZS5wcm90b3R5cGUucmVzaXplLmNhbGwodGhpcyx0KSx0aGlzLl9zdGF0ZT12b2lkIDB9LHQucHJvdG90eXBlLnJlc2V0PWZ1bmN0aW9uKCl7dGhpcy5fY2xlYXJDdXJyZW50TGluaygpfSx0LnByb3RvdHlwZS5fY2xlYXJDdXJyZW50TGluaz1mdW5jdGlvbigpe2lmKHRoaXMuX3N0YXRlKXt0aGlzLl9jbGVhckNlbGxzKHRoaXMuX3N0YXRlLngxLHRoaXMuX3N0YXRlLnkxLHRoaXMuX3N0YXRlLmNvbHMtdGhpcy5fc3RhdGUueDEsMSk7dmFyIGU9dGhpcy5fc3RhdGUueTItdGhpcy5fc3RhdGUueTEtMTtlPjAmJnRoaXMuX2NsZWFyQ2VsbHMoMCx0aGlzLl9zdGF0ZS55MSsxLHRoaXMuX3N0YXRlLmNvbHMsZSksdGhpcy5fY2xlYXJDZWxscygwLHRoaXMuX3N0YXRlLnkyLHRoaXMuX3N0YXRlLngyLDEpLHRoaXMuX3N0YXRlPXZvaWQgMH19LHQucHJvdG90eXBlLl9vblNob3dMaW5rVW5kZXJsaW5lPWZ1bmN0aW9uKGUpe2lmKGUuZmc9PT1jLklOVkVSVEVEX0RFRkFVTFRfQ09MT1I/dGhpcy5fY3R4LmZpbGxTdHlsZT10aGlzLl9jb2xvcnMuYmFja2dyb3VuZC5jc3M6ZS5mZyYmKDAsbC5pczI1NkNvbG9yKShlLmZnKT90aGlzLl9jdHguZmlsbFN0eWxlPXRoaXMuX2NvbG9ycy5hbnNpW2UuZmddLmNzczp0aGlzLl9jdHguZmlsbFN0eWxlPXRoaXMuX2NvbG9ycy5mb3JlZ3JvdW5kLmNzcyxlLnkxPT09ZS55Mil0aGlzLl9maWxsQm90dG9tTGluZUF0Q2VsbHMoZS54MSxlLnkxLGUueDItZS54MSk7ZWxzZXt0aGlzLl9maWxsQm90dG9tTGluZUF0Q2VsbHMoZS54MSxlLnkxLGUuY29scy1lLngxKTtmb3IodmFyIHQ9ZS55MSsxO3Q8ZS55Mjt0KyspdGhpcy5fZmlsbEJvdHRvbUxpbmVBdENlbGxzKDAsdCxlLmNvbHMpO3RoaXMuX2ZpbGxCb3R0b21MaW5lQXRDZWxscygwLGUueTIsZS54Mil9dGhpcy5fc3RhdGU9ZX0sdC5wcm90b3R5cGUuX29uSGlkZUxpbmtVbmRlcmxpbmU9ZnVuY3Rpb24oZSl7dGhpcy5fY2xlYXJDdXJyZW50TGluaygpfSxvKFtzKDYsdS5JQnVmZmVyU2VydmljZSkscyg3LHUuSU9wdGlvbnNTZXJ2aWNlKV0sdCl9KGEuQmFzZVJlbmRlckxheWVyKTt0LkxpbmtSZW5kZXJMYXllcj1ofSwzNTI1OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlJlbmRlcmVyPXZvaWQgMDt2YXIgYT1yKDk1OTYpLGM9cig0MTQ5KSxsPXIoMjUxMiksdT1yKDUwOTgpLGg9cig4NDQpLGY9cig0NzI1KSxfPXIoMjU4NSksZD1yKDE0MjApLHA9cig4NDYwKSx2PTEsZz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQscixpLG4sbyxzLGgsZil7dmFyIF89ZS5jYWxsKHRoaXMpfHx0aGlzO18uX2NvbG9ycz10LF8uX3NjcmVlbkVsZW1lbnQ9cixfLl9idWZmZXJTZXJ2aWNlPXMsXy5fY2hhclNpemVTZXJ2aWNlPWgsXy5fb3B0aW9uc1NlcnZpY2U9ZixfLl9pZD12KyssXy5fb25SZXF1ZXN0UmVkcmF3PW5ldyBwLkV2ZW50RW1pdHRlcjt2YXIgZD1fLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmFsbG93VHJhbnNwYXJlbmN5O3JldHVybiBfLl9yZW5kZXJMYXllcnM9W28uY3JlYXRlSW5zdGFuY2UoYS5UZXh0UmVuZGVyTGF5ZXIsXy5fc2NyZWVuRWxlbWVudCwwLF8uX2NvbG9ycyxkLF8uX2lkKSxvLmNyZWF0ZUluc3RhbmNlKGMuU2VsZWN0aW9uUmVuZGVyTGF5ZXIsXy5fc2NyZWVuRWxlbWVudCwxLF8uX2NvbG9ycyxfLl9pZCksby5jcmVhdGVJbnN0YW5jZSh1LkxpbmtSZW5kZXJMYXllcixfLl9zY3JlZW5FbGVtZW50LDIsXy5fY29sb3JzLF8uX2lkLGksbiksby5jcmVhdGVJbnN0YW5jZShsLkN1cnNvclJlbmRlckxheWVyLF8uX3NjcmVlbkVsZW1lbnQsMyxfLl9jb2xvcnMsXy5faWQsXy5fb25SZXF1ZXN0UmVkcmF3KV0sXy5kaW1lbnNpb25zPXtzY2FsZWRDaGFyV2lkdGg6MCxzY2FsZWRDaGFySGVpZ2h0OjAsc2NhbGVkQ2VsbFdpZHRoOjAsc2NhbGVkQ2VsbEhlaWdodDowLHNjYWxlZENoYXJMZWZ0OjAsc2NhbGVkQ2hhclRvcDowLHNjYWxlZENhbnZhc1dpZHRoOjAsc2NhbGVkQ2FudmFzSGVpZ2h0OjAsY2FudmFzV2lkdGg6MCxjYW52YXNIZWlnaHQ6MCxhY3R1YWxDZWxsV2lkdGg6MCxhY3R1YWxDZWxsSGVpZ2h0OjB9LF8uX2RldmljZVBpeGVsUmF0aW89d2luZG93LmRldmljZVBpeGVsUmF0aW8sXy5fdXBkYXRlRGltZW5zaW9ucygpLF8ub25PcHRpb25zQ2hhbmdlZCgpLF99cmV0dXJuIG4odCxlKSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uUmVxdWVzdFJlZHJhdyIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vblJlcXVlc3RSZWRyYXcuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe2Zvcih2YXIgdD0wLHI9dGhpcy5fcmVuZGVyTGF5ZXJzO3Q8ci5sZW5ndGg7dCsrKXJbdF0uZGlzcG9zZSgpO2UucHJvdG90eXBlLmRpc3Bvc2UuY2FsbCh0aGlzKSwoMCxkLnJlbW92ZVRlcm1pbmFsRnJvbUNhY2hlKSh0aGlzLl9pZCl9LHQucHJvdG90eXBlLm9uRGV2aWNlUGl4ZWxSYXRpb0NoYW5nZT1mdW5jdGlvbigpe3RoaXMuX2RldmljZVBpeGVsUmF0aW8hPT13aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyYmKHRoaXMuX2RldmljZVBpeGVsUmF0aW89d2luZG93LmRldmljZVBpeGVsUmF0aW8sdGhpcy5vblJlc2l6ZSh0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsdGhpcy5fYnVmZmVyU2VydmljZS5yb3dzKSl9LHQucHJvdG90eXBlLnNldENvbG9ycz1mdW5jdGlvbihlKXt0aGlzLl9jb2xvcnM9ZTtmb3IodmFyIHQ9MCxyPXRoaXMuX3JlbmRlckxheWVyczt0PHIubGVuZ3RoO3QrKyl7dmFyIGk9clt0XTtpLnNldENvbG9ycyh0aGlzLl9jb2xvcnMpLGkucmVzZXQoKX19LHQucHJvdG90eXBlLm9uUmVzaXplPWZ1bmN0aW9uKGUsdCl7dGhpcy5fdXBkYXRlRGltZW5zaW9ucygpO2Zvcih2YXIgcj0wLGk9dGhpcy5fcmVuZGVyTGF5ZXJzO3I8aS5sZW5ndGg7cisrKWlbcl0ucmVzaXplKHRoaXMuZGltZW5zaW9ucyk7dGhpcy5fc2NyZWVuRWxlbWVudC5zdHlsZS53aWR0aD10aGlzLmRpbWVuc2lvbnMuY2FudmFzV2lkdGgrInB4Iix0aGlzLl9zY3JlZW5FbGVtZW50LnN0eWxlLmhlaWdodD10aGlzLmRpbWVuc2lvbnMuY2FudmFzSGVpZ2h0KyJweCJ9LHQucHJvdG90eXBlLm9uQ2hhclNpemVDaGFuZ2VkPWZ1bmN0aW9uKCl7dGhpcy5vblJlc2l6ZSh0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsdGhpcy5fYnVmZmVyU2VydmljZS5yb3dzKX0sdC5wcm90b3R5cGUub25CbHVyPWZ1bmN0aW9uKCl7dGhpcy5fcnVuT3BlcmF0aW9uKChmdW5jdGlvbihlKXtyZXR1cm4gZS5vbkJsdXIoKX0pKX0sdC5wcm90b3R5cGUub25Gb2N1cz1mdW5jdGlvbigpe3RoaXMuX3J1bk9wZXJhdGlvbigoZnVuY3Rpb24oZSl7cmV0dXJuIGUub25Gb2N1cygpfSkpfSx0LnByb3RvdHlwZS5vblNlbGVjdGlvbkNoYW5nZWQ9ZnVuY3Rpb24oZSx0LHIpe3ZvaWQgMD09PXImJihyPSExKSx0aGlzLl9ydW5PcGVyYXRpb24oKGZ1bmN0aW9uKGkpe3JldHVybiBpLm9uU2VsZWN0aW9uQ2hhbmdlZChlLHQscil9KSl9LHQucHJvdG90eXBlLm9uQ3Vyc29yTW92ZT1mdW5jdGlvbigpe3RoaXMuX3J1bk9wZXJhdGlvbigoZnVuY3Rpb24oZSl7cmV0dXJuIGUub25DdXJzb3JNb3ZlKCl9KSl9LHQucHJvdG90eXBlLm9uT3B0aW9uc0NoYW5nZWQ9ZnVuY3Rpb24oKXt0aGlzLl9ydW5PcGVyYXRpb24oKGZ1bmN0aW9uKGUpe3JldHVybiBlLm9uT3B0aW9uc0NoYW5nZWQoKX0pKX0sdC5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXt0aGlzLl9ydW5PcGVyYXRpb24oKGZ1bmN0aW9uKGUpe3JldHVybiBlLnJlc2V0KCl9KSl9LHQucHJvdG90eXBlLl9ydW5PcGVyYXRpb249ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTAscj10aGlzLl9yZW5kZXJMYXllcnM7dDxyLmxlbmd0aDt0KyspZShyW3RdKX0sdC5wcm90b3R5cGUucmVuZGVyUm93cz1mdW5jdGlvbihlLHQpe2Zvcih2YXIgcj0wLGk9dGhpcy5fcmVuZGVyTGF5ZXJzO3I8aS5sZW5ndGg7cisrKWlbcl0ub25HcmlkQ2hhbmdlZChlLHQpfSx0LnByb3RvdHlwZS5jbGVhclRleHR1cmVBdGxhcz1mdW5jdGlvbigpe2Zvcih2YXIgZT0wLHQ9dGhpcy5fcmVuZGVyTGF5ZXJzO2U8dC5sZW5ndGg7ZSsrKXRbZV0uY2xlYXJUZXh0dXJlQXRsYXMoKX0sdC5wcm90b3R5cGUuX3VwZGF0ZURpbWVuc2lvbnM9ZnVuY3Rpb24oKXt0aGlzLl9jaGFyU2l6ZVNlcnZpY2UuaGFzVmFsaWRTaXplJiYodGhpcy5kaW1lbnNpb25zLnNjYWxlZENoYXJXaWR0aD1NYXRoLmZsb29yKHRoaXMuX2NoYXJTaXplU2VydmljZS53aWR0aCp3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyksdGhpcy5kaW1lbnNpb25zLnNjYWxlZENoYXJIZWlnaHQ9TWF0aC5jZWlsKHRoaXMuX2NoYXJTaXplU2VydmljZS5oZWlnaHQqd2luZG93LmRldmljZVBpeGVsUmF0aW8pLHRoaXMuZGltZW5zaW9ucy5zY2FsZWRDZWxsSGVpZ2h0PU1hdGguZmxvb3IodGhpcy5kaW1lbnNpb25zLnNjYWxlZENoYXJIZWlnaHQqdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5saW5lSGVpZ2h0KSx0aGlzLmRpbWVuc2lvbnMuc2NhbGVkQ2hhclRvcD0xPT09dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5saW5lSGVpZ2h0PzA6TWF0aC5yb3VuZCgodGhpcy5kaW1lbnNpb25zLnNjYWxlZENlbGxIZWlnaHQtdGhpcy5kaW1lbnNpb25zLnNjYWxlZENoYXJIZWlnaHQpLzIpLHRoaXMuZGltZW5zaW9ucy5zY2FsZWRDZWxsV2lkdGg9dGhpcy5kaW1lbnNpb25zLnNjYWxlZENoYXJXaWR0aCtNYXRoLnJvdW5kKHRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMubGV0dGVyU3BhY2luZyksdGhpcy5kaW1lbnNpb25zLnNjYWxlZENoYXJMZWZ0PU1hdGguZmxvb3IodGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5sZXR0ZXJTcGFjaW5nLzIpLHRoaXMuZGltZW5zaW9ucy5zY2FsZWRDYW52YXNIZWlnaHQ9dGhpcy5fYnVmZmVyU2VydmljZS5yb3dzKnRoaXMuZGltZW5zaW9ucy5zY2FsZWRDZWxsSGVpZ2h0LHRoaXMuZGltZW5zaW9ucy5zY2FsZWRDYW52YXNXaWR0aD10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMqdGhpcy5kaW1lbnNpb25zLnNjYWxlZENlbGxXaWR0aCx0aGlzLmRpbWVuc2lvbnMuY2FudmFzSGVpZ2h0PU1hdGgucm91bmQodGhpcy5kaW1lbnNpb25zLnNjYWxlZENhbnZhc0hlaWdodC93aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyksdGhpcy5kaW1lbnNpb25zLmNhbnZhc1dpZHRoPU1hdGgucm91bmQodGhpcy5kaW1lbnNpb25zLnNjYWxlZENhbnZhc1dpZHRoL3dpbmRvdy5kZXZpY2VQaXhlbFJhdGlvKSx0aGlzLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbEhlaWdodD10aGlzLmRpbWVuc2lvbnMuY2FudmFzSGVpZ2h0L3RoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyx0aGlzLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbFdpZHRoPXRoaXMuZGltZW5zaW9ucy5jYW52YXNXaWR0aC90aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMpfSxvKFtzKDQsXy5JSW5zdGFudGlhdGlvblNlcnZpY2UpLHMoNSxfLklCdWZmZXJTZXJ2aWNlKSxzKDYsZi5JQ2hhclNpemVTZXJ2aWNlKSxzKDcsXy5JT3B0aW9uc1NlcnZpY2UpXSx0KX0oaC5EaXNwb3NhYmxlKTt0LlJlbmRlcmVyPWd9LDE3NTI6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC50aHJvd0lmRmFsc3k9dm9pZCAwLHQudGhyb3dJZkZhbHN5PWZ1bmN0aW9uKGUpe2lmKCFlKXRocm93IG5ldyBFcnJvcigidmFsdWUgbXVzdCBub3QgYmUgZmFsc3kiKTtyZXR1cm4gZX19LDQxNDk6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49dGhpcyYmdGhpcy5fX2V4dGVuZHN8fChpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGk9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQscikmJihlW3JdPXRbcl0pfSxpKGUsdCl9LGZ1bmN0aW9uKGUsdCl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIkNsYXNzIGV4dGVuZHMgdmFsdWUgIitTdHJpbmcodCkrIiBpcyBub3QgYSBjb25zdHJ1Y3RvciBvciBudWxsIik7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1pKGUsdCksZS5wcm90b3R5cGU9bnVsbD09PXQ/T2JqZWN0LmNyZWF0ZSh0KTooci5wcm90b3R5cGU9dC5wcm90b3R5cGUsbmV3IHIpfSksbz10aGlzJiZ0aGlzLl9fZGVjb3JhdGV8fGZ1bmN0aW9uKGUsdCxyLGkpe3ZhciBuLG89YXJndW1lbnRzLmxlbmd0aCxzPW88Mz90Om51bGw9PT1pP2k9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0LHIpOmk7aWYoIm9iamVjdCI9PXR5cGVvZiBSZWZsZWN0JiYiZnVuY3Rpb24iPT10eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSlzPVJlZmxlY3QuZGVjb3JhdGUoZSx0LHIsaSk7ZWxzZSBmb3IodmFyIGE9ZS5sZW5ndGgtMTthPj0wO2EtLSkobj1lW2FdKSYmKHM9KG88Mz9uKHMpOm8+Mz9uKHQscixzKTpuKHQscikpfHxzKTtyZXR1cm4gbz4zJiZzJiZPYmplY3QuZGVmaW5lUHJvcGVydHkodCxyLHMpLHN9LHM9dGhpcyYmdGhpcy5fX3BhcmFtfHxmdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbihyLGkpe3QocixpLGUpfX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuU2VsZWN0aW9uUmVuZGVyTGF5ZXI9dm9pZCAwO3ZhciBhPXIoMTU0NiksYz1yKDI1ODUpLGw9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0LHIsaSxuLG8scyl7dmFyIGE9ZS5jYWxsKHRoaXMsdCwic2VsZWN0aW9uIixyLCEwLGksbixvLHMpfHx0aGlzO3JldHVybiBhLl9jbGVhclN0YXRlKCksYX1yZXR1cm4gbih0LGUpLHQucHJvdG90eXBlLl9jbGVhclN0YXRlPWZ1bmN0aW9uKCl7dGhpcy5fc3RhdGU9e3N0YXJ0OnZvaWQgMCxlbmQ6dm9pZCAwLGNvbHVtblNlbGVjdE1vZGU6dm9pZCAwLHlkaXNwOnZvaWQgMH19LHQucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbih0KXtlLnByb3RvdHlwZS5yZXNpemUuY2FsbCh0aGlzLHQpLHRoaXMuX2NsZWFyU3RhdGUoKX0sdC5wcm90b3R5cGUucmVzZXQ9ZnVuY3Rpb24oKXt0aGlzLl9zdGF0ZS5zdGFydCYmdGhpcy5fc3RhdGUuZW5kJiYodGhpcy5fY2xlYXJTdGF0ZSgpLHRoaXMuX2NsZWFyQWxsKCkpfSx0LnByb3RvdHlwZS5vblNlbGVjdGlvbkNoYW5nZWQ9ZnVuY3Rpb24oZSx0LHIpe2lmKHRoaXMuX2RpZFN0YXRlQ2hhbmdlKGUsdCxyLHRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwKSlpZih0aGlzLl9jbGVhckFsbCgpLGUmJnQpe3ZhciBpPWVbMV0tdGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueWRpc3Asbj10WzFdLXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwLG89TWF0aC5tYXgoaSwwKSxzPU1hdGgubWluKG4sdGhpcy5fYnVmZmVyU2VydmljZS5yb3dzLTEpO2lmKG8+PXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93c3x8czwwKXRoaXMuX3N0YXRlLnlkaXNwPXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwO2Vsc2V7aWYodGhpcy5fY3R4LmZpbGxTdHlsZT10aGlzLl9jb2xvcnMuc2VsZWN0aW9uVHJhbnNwYXJlbnQuY3NzLHIpe3ZhciBhPWVbMF0sYz10WzBdLWEsbD1zLW8rMTt0aGlzLl9maWxsQ2VsbHMoYSxvLGMsbCl9ZWxzZXthPWk9PT1vP2VbMF06MDt2YXIgdT1vPT09bj90WzBdOnRoaXMuX2J1ZmZlclNlcnZpY2UuY29sczt0aGlzLl9maWxsQ2VsbHMoYSxvLHUtYSwxKTt2YXIgaD1NYXRoLm1heChzLW8tMSwwKTtpZih0aGlzLl9maWxsQ2VsbHMoMCxvKzEsdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLGgpLG8hPT1zKXt2YXIgZj1uPT09cz90WzBdOnRoaXMuX2J1ZmZlclNlcnZpY2UuY29sczt0aGlzLl9maWxsQ2VsbHMoMCxzLGYsMSl9fXRoaXMuX3N0YXRlLnN0YXJ0PVtlWzBdLGVbMV1dLHRoaXMuX3N0YXRlLmVuZD1bdFswXSx0WzFdXSx0aGlzLl9zdGF0ZS5jb2x1bW5TZWxlY3RNb2RlPXIsdGhpcy5fc3RhdGUueWRpc3A9dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueWRpc3B9fWVsc2UgdGhpcy5fY2xlYXJTdGF0ZSgpfSx0LnByb3RvdHlwZS5fZGlkU3RhdGVDaGFuZ2U9ZnVuY3Rpb24oZSx0LHIsaSl7cmV0dXJuIXRoaXMuX2FyZUNvb3JkaW5hdGVzRXF1YWwoZSx0aGlzLl9zdGF0ZS5zdGFydCl8fCF0aGlzLl9hcmVDb29yZGluYXRlc0VxdWFsKHQsdGhpcy5fc3RhdGUuZW5kKXx8ciE9PXRoaXMuX3N0YXRlLmNvbHVtblNlbGVjdE1vZGV8fGkhPT10aGlzLl9zdGF0ZS55ZGlzcH0sdC5wcm90b3R5cGUuX2FyZUNvb3JkaW5hdGVzRXF1YWw9ZnVuY3Rpb24oZSx0KXtyZXR1cm4hKCFlfHwhdCkmJmVbMF09PT10WzBdJiZlWzFdPT09dFsxXX0sbyhbcyg0LGMuSUJ1ZmZlclNlcnZpY2UpLHMoNSxjLklPcHRpb25zU2VydmljZSldLHQpfShhLkJhc2VSZW5kZXJMYXllcik7dC5TZWxlY3Rpb25SZW5kZXJMYXllcj1sfSw5NTk2OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlRleHRSZW5kZXJMYXllcj12b2lkIDA7dmFyIGE9cigzNzAwKSxjPXIoMTU0NiksbD1yKDM3MzQpLHU9cig2NDMpLGg9cig1MTEpLGY9cigyNTg1KSxfPXIoNDcyNSksZD1yKDQyNjkpLHA9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0LHIsaSxuLG8scyxjLGwpe3ZhciB1PWUuY2FsbCh0aGlzLHQsInRleHQiLHIsbixpLG8scyxjKXx8dGhpcztyZXR1cm4gdS5fY2hhcmFjdGVySm9pbmVyU2VydmljZT1sLHUuX2NoYXJhY3RlcldpZHRoPTAsdS5fY2hhcmFjdGVyRm9udD0iIix1Ll9jaGFyYWN0ZXJPdmVybGFwQ2FjaGU9e30sdS5fd29ya0NlbGw9bmV3IGguQ2VsbERhdGEsdS5fc3RhdGU9bmV3IGEuR3JpZENhY2hlLHV9cmV0dXJuIG4odCxlKSx0LnByb3RvdHlwZS5yZXNpemU9ZnVuY3Rpb24odCl7ZS5wcm90b3R5cGUucmVzaXplLmNhbGwodGhpcyx0KTt2YXIgcj10aGlzLl9nZXRGb250KCExLCExKTt0aGlzLl9jaGFyYWN0ZXJXaWR0aD09PXQuc2NhbGVkQ2hhcldpZHRoJiZ0aGlzLl9jaGFyYWN0ZXJGb250PT09cnx8KHRoaXMuX2NoYXJhY3RlcldpZHRoPXQuc2NhbGVkQ2hhcldpZHRoLHRoaXMuX2NoYXJhY3RlckZvbnQ9cix0aGlzLl9jaGFyYWN0ZXJPdmVybGFwQ2FjaGU9e30pLHRoaXMuX3N0YXRlLmNsZWFyKCksdGhpcy5fc3RhdGUucmVzaXplKHRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyx0aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MpfSx0LnByb3RvdHlwZS5yZXNldD1mdW5jdGlvbigpe3RoaXMuX3N0YXRlLmNsZWFyKCksdGhpcy5fY2xlYXJBbGwoKX0sdC5wcm90b3R5cGUuX2ZvckVhY2hDZWxsPWZ1bmN0aW9uKGUsdCxyKXtmb3IodmFyIGk9ZTtpPD10O2krKylmb3IodmFyIG49aSt0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55ZGlzcCxvPXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLmxpbmVzLmdldChuKSxzPXRoaXMuX2NoYXJhY3RlckpvaW5lclNlcnZpY2UuZ2V0Sm9pbmVkQ2hhcmFjdGVycyhuKSxhPTA7YTx0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHM7YSsrKXtvLmxvYWRDZWxsKGEsdGhpcy5fd29ya0NlbGwpO3ZhciBjPXRoaXMuX3dvcmtDZWxsLGw9ITEsaD1hO2lmKDAhPT1jLmdldFdpZHRoKCkpe2lmKHMubGVuZ3RoPjAmJmE9PT1zWzBdWzBdKXtsPSEwO3ZhciBmPXMuc2hpZnQoKTtjPW5ldyBkLkpvaW5lZENlbGxEYXRhKHRoaXMuX3dvcmtDZWxsLG8udHJhbnNsYXRlVG9TdHJpbmcoITAsZlswXSxmWzFdKSxmWzFdLWZbMF0pLGg9ZlsxXS0xfSFsJiZ0aGlzLl9pc092ZXJsYXBwaW5nKGMpJiZoPG8ubGVuZ3RoLTEmJm8uZ2V0Q29kZVBvaW50KGgrMSk9PT11Lk5VTExfQ0VMTF9DT0RFJiYoYy5jb250ZW50Jj0tMTI1ODI5MTMsYy5jb250ZW50fD0yPDwyMikscihjLGEsaSksYT1ofX19LHQucHJvdG90eXBlLl9kcmF3QmFja2dyb3VuZD1mdW5jdGlvbihlLHQpe3ZhciByPXRoaXMsaT10aGlzLl9jdHgsbj10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsbz0wLHM9MCxhPW51bGw7aS5zYXZlKCksdGhpcy5fZm9yRWFjaENlbGwoZSx0LChmdW5jdGlvbihlLHQsYyl7dmFyIHU9bnVsbDtlLmlzSW52ZXJzZSgpP3U9ZS5pc0ZnRGVmYXVsdCgpP3IuX2NvbG9ycy5mb3JlZ3JvdW5kLmNzczplLmlzRmdSR0IoKT8icmdiKCIrbC5BdHRyaWJ1dGVEYXRhLnRvQ29sb3JSR0IoZS5nZXRGZ0NvbG9yKCkpLmpvaW4oIiwiKSsiKSI6ci5fY29sb3JzLmFuc2lbZS5nZXRGZ0NvbG9yKCldLmNzczplLmlzQmdSR0IoKT91PSJyZ2IoIitsLkF0dHJpYnV0ZURhdGEudG9Db2xvclJHQihlLmdldEJnQ29sb3IoKSkuam9pbigiLCIpKyIpIjplLmlzQmdQYWxldHRlKCkmJih1PXIuX2NvbG9ycy5hbnNpW2UuZ2V0QmdDb2xvcigpXS5jc3MpLG51bGw9PT1hJiYobz10LHM9YyksYyE9PXM/KGkuZmlsbFN0eWxlPWF8fCIiLHIuX2ZpbGxDZWxscyhvLHMsbi1vLDEpLG89dCxzPWMpOmEhPT11JiYoaS5maWxsU3R5bGU9YXx8IiIsci5fZmlsbENlbGxzKG8scyx0LW8sMSksbz10LHM9YyksYT11fSkpLG51bGwhPT1hJiYoaS5maWxsU3R5bGU9YSx0aGlzLl9maWxsQ2VsbHMobyxzLG4tbywxKSksaS5yZXN0b3JlKCl9LHQucHJvdG90eXBlLl9kcmF3Rm9yZWdyb3VuZD1mdW5jdGlvbihlLHQpe3ZhciByPXRoaXM7dGhpcy5fZm9yRWFjaENlbGwoZSx0LChmdW5jdGlvbihlLHQsaSl7aWYoIWUuaXNJbnZpc2libGUoKSYmKHIuX2RyYXdDaGFycyhlLHQsaSksZS5pc1VuZGVybGluZSgpfHxlLmlzU3RyaWtldGhyb3VnaCgpKSl7aWYoci5fY3R4LnNhdmUoKSxlLmlzSW52ZXJzZSgpKWlmKGUuaXNCZ0RlZmF1bHQoKSlyLl9jdHguZmlsbFN0eWxlPXIuX2NvbG9ycy5iYWNrZ3JvdW5kLmNzcztlbHNlIGlmKGUuaXNCZ1JHQigpKXIuX2N0eC5maWxsU3R5bGU9InJnYigiK2wuQXR0cmlidXRlRGF0YS50b0NvbG9yUkdCKGUuZ2V0QmdDb2xvcigpKS5qb2luKCIsIikrIikiO2Vsc2V7dmFyIG49ZS5nZXRCZ0NvbG9yKCk7ci5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5kcmF3Qm9sZFRleHRJbkJyaWdodENvbG9ycyYmZS5pc0JvbGQoKSYmbjw4JiYobis9OCksci5fY3R4LmZpbGxTdHlsZT1yLl9jb2xvcnMuYW5zaVtuXS5jc3N9ZWxzZSBpZihlLmlzRmdEZWZhdWx0KCkpci5fY3R4LmZpbGxTdHlsZT1yLl9jb2xvcnMuZm9yZWdyb3VuZC5jc3M7ZWxzZSBpZihlLmlzRmdSR0IoKSlyLl9jdHguZmlsbFN0eWxlPSJyZ2IoIitsLkF0dHJpYnV0ZURhdGEudG9Db2xvclJHQihlLmdldEZnQ29sb3IoKSkuam9pbigiLCIpKyIpIjtlbHNle3ZhciBvPWUuZ2V0RmdDb2xvcigpO3IuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuZHJhd0JvbGRUZXh0SW5CcmlnaHRDb2xvcnMmJmUuaXNCb2xkKCkmJm88OCYmKG8rPTgpLHIuX2N0eC5maWxsU3R5bGU9ci5fY29sb3JzLmFuc2lbb10uY3NzfWUuaXNTdHJpa2V0aHJvdWdoKCkmJnIuX2ZpbGxNaWRkbGVMaW5lQXRDZWxscyh0LGksZS5nZXRXaWR0aCgpKSxlLmlzVW5kZXJsaW5lKCkmJnIuX2ZpbGxCb3R0b21MaW5lQXRDZWxscyh0LGksZS5nZXRXaWR0aCgpKSxyLl9jdHgucmVzdG9yZSgpfX0pKX0sdC5wcm90b3R5cGUub25HcmlkQ2hhbmdlZD1mdW5jdGlvbihlLHQpezAhPT10aGlzLl9zdGF0ZS5jYWNoZS5sZW5ndGgmJih0aGlzLl9jaGFyQXRsYXMmJnRoaXMuX2NoYXJBdGxhcy5iZWdpbkZyYW1lKCksdGhpcy5fY2xlYXJDZWxscygwLGUsdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLHQtZSsxKSx0aGlzLl9kcmF3QmFja2dyb3VuZChlLHQpLHRoaXMuX2RyYXdGb3JlZ3JvdW5kKGUsdCkpfSx0LnByb3RvdHlwZS5vbk9wdGlvbnNDaGFuZ2VkPWZ1bmN0aW9uKCl7dGhpcy5fc2V0VHJhbnNwYXJlbmN5KHRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuYWxsb3dUcmFuc3BhcmVuY3kpfSx0LnByb3RvdHlwZS5faXNPdmVybGFwcGluZz1mdW5jdGlvbihlKXtpZigxIT09ZS5nZXRXaWR0aCgpKXJldHVybiExO2lmKGUuZ2V0Q29kZSgpPDI1NilyZXR1cm4hMTt2YXIgdD1lLmdldENoYXJzKCk7aWYodGhpcy5fY2hhcmFjdGVyT3ZlcmxhcENhY2hlLmhhc093blByb3BlcnR5KHQpKXJldHVybiB0aGlzLl9jaGFyYWN0ZXJPdmVybGFwQ2FjaGVbdF07dGhpcy5fY3R4LnNhdmUoKSx0aGlzLl9jdHguZm9udD10aGlzLl9jaGFyYWN0ZXJGb250O3ZhciByPU1hdGguZmxvb3IodGhpcy5fY3R4Lm1lYXN1cmVUZXh0KHQpLndpZHRoKT50aGlzLl9jaGFyYWN0ZXJXaWR0aDtyZXR1cm4gdGhpcy5fY3R4LnJlc3RvcmUoKSx0aGlzLl9jaGFyYWN0ZXJPdmVybGFwQ2FjaGVbdF09cixyfSxvKFtzKDUsZi5JQnVmZmVyU2VydmljZSkscyg2LGYuSU9wdGlvbnNTZXJ2aWNlKSxzKDcsXy5JQ2hhcmFjdGVySm9pbmVyU2VydmljZSldLHQpfShjLkJhc2VSZW5kZXJMYXllcik7dC5UZXh0UmVuZGVyTGF5ZXI9cH0sOTYxNjooZSx0KT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkJhc2VDaGFyQXRsYXM9dm9pZCAwO3ZhciByPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMuX2RpZFdhcm1VcD0hMX1yZXR1cm4gZS5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe30sZS5wcm90b3R5cGUud2FybVVwPWZ1bmN0aW9uKCl7dGhpcy5fZGlkV2FybVVwfHwodGhpcy5fZG9XYXJtVXAoKSx0aGlzLl9kaWRXYXJtVXA9ITApfSxlLnByb3RvdHlwZS5fZG9XYXJtVXA9ZnVuY3Rpb24oKXt9LGUucHJvdG90eXBlLmNsZWFyPWZ1bmN0aW9uKCl7fSxlLnByb3RvdHlwZS5iZWdpbkZyYW1lPWZ1bmN0aW9uKCl7fSxlfSgpO3QuQmFzZUNoYXJBdGxhcz1yfSwxNDIwOihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5yZW1vdmVUZXJtaW5hbEZyb21DYWNoZT10LmFjcXVpcmVDaGFyQXRsYXM9dm9pZCAwO3ZhciBpPXIoMjA0MCksbj1yKDE5MDYpLG89W107dC5hY3F1aXJlQ2hhckF0bGFzPWZ1bmN0aW9uKGUsdCxyLHMsYSl7Zm9yKHZhciBjPSgwLGkuZ2VuZXJhdGVDb25maWcpKHMsYSxlLHIpLGw9MDtsPG8ubGVuZ3RoO2wrKyl7dmFyIHU9KGg9b1tsXSkub3duZWRCeS5pbmRleE9mKHQpO2lmKHU+PTApe2lmKCgwLGkuY29uZmlnRXF1YWxzKShoLmNvbmZpZyxjKSlyZXR1cm4gaC5hdGxhczsxPT09aC5vd25lZEJ5Lmxlbmd0aD8oaC5hdGxhcy5kaXNwb3NlKCksby5zcGxpY2UobCwxKSk6aC5vd25lZEJ5LnNwbGljZSh1LDEpO2JyZWFrfX1mb3IobD0wO2w8by5sZW5ndGg7bCsrKXt2YXIgaD1vW2xdO2lmKCgwLGkuY29uZmlnRXF1YWxzKShoLmNvbmZpZyxjKSlyZXR1cm4gaC5vd25lZEJ5LnB1c2godCksaC5hdGxhc312YXIgZj17YXRsYXM6bmV3IG4uRHluYW1pY0NoYXJBdGxhcyhkb2N1bWVudCxjKSxjb25maWc6Yyxvd25lZEJ5Olt0XX07cmV0dXJuIG8ucHVzaChmKSxmLmF0bGFzfSx0LnJlbW92ZVRlcm1pbmFsRnJvbUNhY2hlPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0wO3Q8by5sZW5ndGg7dCsrKXt2YXIgcj1vW3RdLm93bmVkQnkuaW5kZXhPZihlKTtpZigtMSE9PXIpezE9PT1vW3RdLm93bmVkQnkubGVuZ3RoPyhvW3RdLmF0bGFzLmRpc3Bvc2UoKSxvLnNwbGljZSh0LDEpKTpvW3RdLm93bmVkQnkuc3BsaWNlKHIsMSk7YnJlYWt9fX19LDIwNDA6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXMmJnRoaXMuX19zcHJlYWRBcnJheXx8ZnVuY3Rpb24oZSx0LHIpe2lmKHJ8fDI9PT1hcmd1bWVudHMubGVuZ3RoKWZvcih2YXIgaSxuPTAsbz10Lmxlbmd0aDtuPG87bisrKSFpJiZuIGluIHR8fChpfHwoaT1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0LDAsbikpLGlbbl09dFtuXSk7cmV0dXJuIGUuY29uY2F0KGl8fEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHQpKX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuaXMyNTZDb2xvcj10LmNvbmZpZ0VxdWFscz10LmdlbmVyYXRlQ29uZmlnPXZvaWQgMDt2YXIgbj1yKDY0Myk7dC5nZW5lcmF0ZUNvbmZpZz1mdW5jdGlvbihlLHQscixuKXt2YXIgbz17Zm9yZWdyb3VuZDpuLmZvcmVncm91bmQsYmFja2dyb3VuZDpuLmJhY2tncm91bmQsY3Vyc29yOnZvaWQgMCxjdXJzb3JBY2NlbnQ6dm9pZCAwLHNlbGVjdGlvbjp2b2lkIDAsYW5zaTppKFtdLG4uYW5zaSwhMCl9O3JldHVybntkZXZpY2VQaXhlbFJhdGlvOndpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLHNjYWxlZENoYXJXaWR0aDplLHNjYWxlZENoYXJIZWlnaHQ6dCxmb250RmFtaWx5OnIuZm9udEZhbWlseSxmb250U2l6ZTpyLmZvbnRTaXplLGZvbnRXZWlnaHQ6ci5mb250V2VpZ2h0LGZvbnRXZWlnaHRCb2xkOnIuZm9udFdlaWdodEJvbGQsYWxsb3dUcmFuc3BhcmVuY3k6ci5hbGxvd1RyYW5zcGFyZW5jeSxjb2xvcnM6b319LHQuY29uZmlnRXF1YWxzPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPTA7cjxlLmNvbG9ycy5hbnNpLmxlbmd0aDtyKyspaWYoZS5jb2xvcnMuYW5zaVtyXS5yZ2JhIT09dC5jb2xvcnMuYW5zaVtyXS5yZ2JhKXJldHVybiExO3JldHVybiBlLmRldmljZVBpeGVsUmF0aW89PT10LmRldmljZVBpeGVsUmF0aW8mJmUuZm9udEZhbWlseT09PXQuZm9udEZhbWlseSYmZS5mb250U2l6ZT09PXQuZm9udFNpemUmJmUuZm9udFdlaWdodD09PXQuZm9udFdlaWdodCYmZS5mb250V2VpZ2h0Qm9sZD09PXQuZm9udFdlaWdodEJvbGQmJmUuYWxsb3dUcmFuc3BhcmVuY3k9PT10LmFsbG93VHJhbnNwYXJlbmN5JiZlLnNjYWxlZENoYXJXaWR0aD09PXQuc2NhbGVkQ2hhcldpZHRoJiZlLnNjYWxlZENoYXJIZWlnaHQ9PT10LnNjYWxlZENoYXJIZWlnaHQmJmUuY29sb3JzLmZvcmVncm91bmQ9PT10LmNvbG9ycy5mb3JlZ3JvdW5kJiZlLmNvbG9ycy5iYWNrZ3JvdW5kPT09dC5jb2xvcnMuYmFja2dyb3VuZH0sdC5pczI1NkNvbG9yPWZ1bmN0aW9uKGUpe3JldHVybiBlPG4uREVGQVVMVF9DT0xPUn19LDg4MDM6KGUsdCxyKT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkNIQVJfQVRMQVNfQ0VMTF9TUEFDSU5HPXQuVEVYVF9CQVNFTElORT10LkRJTV9PUEFDSVRZPXQuSU5WRVJURURfREVGQVVMVF9DT0xPUj12b2lkIDA7dmFyIGk9cig2MTE0KTt0LklOVkVSVEVEX0RFRkFVTFRfQ09MT1I9MjU3LHQuRElNX09QQUNJVFk9LjUsdC5URVhUX0JBU0VMSU5FPWkuaXNGaXJlZm94PyJib3R0b20iOiJpZGVvZ3JhcGhpYyIsdC5DSEFSX0FUTEFTX0NFTExfU1BBQ0lORz0xfSwxOTA2OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0Lk5vbmVDaGFyQXRsYXM9dC5EeW5hbWljQ2hhckF0bGFzPXQuZ2V0R2x5cGhDYWNoZUtleT12b2lkIDA7dmFyIG89cig4ODAzKSxzPXIoOTYxNiksYT1yKDU2ODApLGM9cig3MDAxKSxsPXIoNjExNCksdT1yKDE3NTIpLGg9cig0Nzc0KSxmPTEwMjQsXz0xMDI0LGQ9e2NzczoicmdiYSgwLCAwLCAwLCAwKSIscmdiYTowfTtmdW5jdGlvbiBwKGUpe3JldHVybiBlLmNvZGU8PDIxfGUuYmc8PDEyfGUuZmc8PDN8KGUuYm9sZD8wOjQpKyhlLmRpbT8wOjIpKyhlLml0YWxpYz8wOjEpfXQuZ2V0R2x5cGhDYWNoZUtleT1wO3ZhciB2PWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCxyKXt2YXIgaT1lLmNhbGwodGhpcyl8fHRoaXM7aS5fY29uZmlnPXIsaS5fZHJhd1RvQ2FjaGVDb3VudD0wLGkuX2dseXBoc1dhaXRpbmdPbkJpdG1hcD1bXSxpLl9iaXRtYXBDb21taXRUaW1lb3V0PW51bGwsaS5fYml0bWFwPW51bGwsaS5fY2FjaGVDYW52YXM9dC5jcmVhdGVFbGVtZW50KCJjYW52YXMiKSxpLl9jYWNoZUNhbnZhcy53aWR0aD1mLGkuX2NhY2hlQ2FudmFzLmhlaWdodD1fLGkuX2NhY2hlQ3R4PSgwLHUudGhyb3dJZkZhbHN5KShpLl9jYWNoZUNhbnZhcy5nZXRDb250ZXh0KCIyZCIse2FscGhhOiEwfSkpO3ZhciBuPXQuY3JlYXRlRWxlbWVudCgiY2FudmFzIik7bi53aWR0aD1pLl9jb25maWcuc2NhbGVkQ2hhcldpZHRoLG4uaGVpZ2h0PWkuX2NvbmZpZy5zY2FsZWRDaGFySGVpZ2h0LGkuX3RtcEN0eD0oMCx1LnRocm93SWZGYWxzeSkobi5nZXRDb250ZXh0KCIyZCIse2FscGhhOmkuX2NvbmZpZy5hbGxvd1RyYW5zcGFyZW5jeX0pKSxpLl93aWR0aD1NYXRoLmZsb29yKGYvaS5fY29uZmlnLnNjYWxlZENoYXJXaWR0aCksaS5faGVpZ2h0PU1hdGguZmxvb3IoXy9pLl9jb25maWcuc2NhbGVkQ2hhckhlaWdodCk7dmFyIG89aS5fd2lkdGgqaS5faGVpZ2h0O3JldHVybiBpLl9jYWNoZU1hcD1uZXcgYy5MUlVNYXAobyksaS5fY2FjaGVNYXAucHJlYWxsb2MobyksaX1yZXR1cm4gbih0LGUpLHQucHJvdG90eXBlLmRpc3Bvc2U9ZnVuY3Rpb24oKXtudWxsIT09dGhpcy5fYml0bWFwQ29tbWl0VGltZW91dCYmKHdpbmRvdy5jbGVhclRpbWVvdXQodGhpcy5fYml0bWFwQ29tbWl0VGltZW91dCksdGhpcy5fYml0bWFwQ29tbWl0VGltZW91dD1udWxsKX0sdC5wcm90b3R5cGUuYmVnaW5GcmFtZT1mdW5jdGlvbigpe3RoaXMuX2RyYXdUb0NhY2hlQ291bnQ9MH0sdC5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXtpZih0aGlzLl9jYWNoZU1hcC5zaXplPjApe3ZhciBlPXRoaXMuX3dpZHRoKnRoaXMuX2hlaWdodDt0aGlzLl9jYWNoZU1hcD1uZXcgYy5MUlVNYXAoZSksdGhpcy5fY2FjaGVNYXAucHJlYWxsb2MoZSl9dGhpcy5fY2FjaGVDdHguY2xlYXJSZWN0KDAsMCxmLF8pLHRoaXMuX3RtcEN0eC5jbGVhclJlY3QoMCwwLHRoaXMuX2NvbmZpZy5zY2FsZWRDaGFyV2lkdGgsdGhpcy5fY29uZmlnLnNjYWxlZENoYXJIZWlnaHQpfSx0LnByb3RvdHlwZS5kcmF3PWZ1bmN0aW9uKGUsdCxyLGkpe2lmKDMyPT09dC5jb2RlKXJldHVybiEwO2lmKCF0aGlzLl9jYW5DYWNoZSh0KSlyZXR1cm4hMTt2YXIgbj1wKHQpLG89dGhpcy5fY2FjaGVNYXAuZ2V0KG4pO2lmKG51bGwhPW8pcmV0dXJuIHRoaXMuX2RyYXdGcm9tQ2FjaGUoZSxvLHIsaSksITA7aWYodGhpcy5fZHJhd1RvQ2FjaGVDb3VudDwxMDApe3ZhciBzO3M9dGhpcy5fY2FjaGVNYXAuc2l6ZTx0aGlzLl9jYWNoZU1hcC5jYXBhY2l0eT90aGlzLl9jYWNoZU1hcC5zaXplOnRoaXMuX2NhY2hlTWFwLnBlZWsoKS5pbmRleDt2YXIgYT10aGlzLl9kcmF3VG9DYWNoZSh0LHMpO3JldHVybiB0aGlzLl9jYWNoZU1hcC5zZXQobixhKSx0aGlzLl9kcmF3RnJvbUNhY2hlKGUsYSxyLGkpLCEwfXJldHVybiExfSx0LnByb3RvdHlwZS5fY2FuQ2FjaGU9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuY29kZTwyNTZ9LHQucHJvdG90eXBlLl90b0Nvb3JkaW5hdGVYPWZ1bmN0aW9uKGUpe3JldHVybiBlJXRoaXMuX3dpZHRoKnRoaXMuX2NvbmZpZy5zY2FsZWRDaGFyV2lkdGh9LHQucHJvdG90eXBlLl90b0Nvb3JkaW5hdGVZPWZ1bmN0aW9uKGUpe3JldHVybiBNYXRoLmZsb29yKGUvdGhpcy5fd2lkdGgpKnRoaXMuX2NvbmZpZy5zY2FsZWRDaGFySGVpZ2h0fSx0LnByb3RvdHlwZS5fZHJhd0Zyb21DYWNoZT1mdW5jdGlvbihlLHQscixpKXtpZighdC5pc0VtcHR5KXt2YXIgbj10aGlzLl90b0Nvb3JkaW5hdGVYKHQuaW5kZXgpLG89dGhpcy5fdG9Db29yZGluYXRlWSh0LmluZGV4KTtlLmRyYXdJbWFnZSh0LmluQml0bWFwP3RoaXMuX2JpdG1hcDp0aGlzLl9jYWNoZUNhbnZhcyxuLG8sdGhpcy5fY29uZmlnLnNjYWxlZENoYXJXaWR0aCx0aGlzLl9jb25maWcuc2NhbGVkQ2hhckhlaWdodCxyLGksdGhpcy5fY29uZmlnLnNjYWxlZENoYXJXaWR0aCx0aGlzLl9jb25maWcuc2NhbGVkQ2hhckhlaWdodCl9fSx0LnByb3RvdHlwZS5fZ2V0Q29sb3JGcm9tQW5zaUluZGV4PWZ1bmN0aW9uKGUpe3JldHVybiBlPHRoaXMuX2NvbmZpZy5jb2xvcnMuYW5zaS5sZW5ndGg/dGhpcy5fY29uZmlnLmNvbG9ycy5hbnNpW2VdOmEuREVGQVVMVF9BTlNJX0NPTE9SU1tlXX0sdC5wcm90b3R5cGUuX2dldEJhY2tncm91bmRDb2xvcj1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fY29uZmlnLmFsbG93VHJhbnNwYXJlbmN5P2Q6ZS5iZz09PW8uSU5WRVJURURfREVGQVVMVF9DT0xPUj90aGlzLl9jb25maWcuY29sb3JzLmZvcmVncm91bmQ6ZS5iZzwyNTY/dGhpcy5fZ2V0Q29sb3JGcm9tQW5zaUluZGV4KGUuYmcpOnRoaXMuX2NvbmZpZy5jb2xvcnMuYmFja2dyb3VuZH0sdC5wcm90b3R5cGUuX2dldEZvcmVncm91bmRDb2xvcj1mdW5jdGlvbihlKXtyZXR1cm4gZS5mZz09PW8uSU5WRVJURURfREVGQVVMVF9DT0xPUj9oLmNvbG9yLm9wYXF1ZSh0aGlzLl9jb25maWcuY29sb3JzLmJhY2tncm91bmQpOmUuZmc8MjU2P3RoaXMuX2dldENvbG9yRnJvbUFuc2lJbmRleChlLmZnKTp0aGlzLl9jb25maWcuY29sb3JzLmZvcmVncm91bmR9LHQucHJvdG90eXBlLl9kcmF3VG9DYWNoZT1mdW5jdGlvbihlLHQpe3RoaXMuX2RyYXdUb0NhY2hlQ291bnQrKyx0aGlzLl90bXBDdHguc2F2ZSgpO3ZhciByPXRoaXMuX2dldEJhY2tncm91bmRDb2xvcihlKTt0aGlzLl90bXBDdHguZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSJjb3B5Iix0aGlzLl90bXBDdHguZmlsbFN0eWxlPXIuY3NzLHRoaXMuX3RtcEN0eC5maWxsUmVjdCgwLDAsdGhpcy5fY29uZmlnLnNjYWxlZENoYXJXaWR0aCx0aGlzLl9jb25maWcuc2NhbGVkQ2hhckhlaWdodCksdGhpcy5fdG1wQ3R4Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbj0ic291cmNlLW92ZXIiO3ZhciBpPWUuYm9sZD90aGlzLl9jb25maWcuZm9udFdlaWdodEJvbGQ6dGhpcy5fY29uZmlnLmZvbnRXZWlnaHQsbj1lLml0YWxpYz8iaXRhbGljIjoiIjt0aGlzLl90bXBDdHguZm9udD1uKyIgIitpKyIgIit0aGlzLl9jb25maWcuZm9udFNpemUqdGhpcy5fY29uZmlnLmRldmljZVBpeGVsUmF0aW8rInB4ICIrdGhpcy5fY29uZmlnLmZvbnRGYW1pbHksdGhpcy5fdG1wQ3R4LnRleHRCYXNlbGluZT1vLlRFWFRfQkFTRUxJTkUsdGhpcy5fdG1wQ3R4LmZpbGxTdHlsZT10aGlzLl9nZXRGb3JlZ3JvdW5kQ29sb3IoZSkuY3NzLGUuZGltJiYodGhpcy5fdG1wQ3R4Lmdsb2JhbEFscGhhPW8uRElNX09QQUNJVFkpLHRoaXMuX3RtcEN0eC5maWxsVGV4dChlLmNoYXJzLDAsdGhpcy5fY29uZmlnLnNjYWxlZENoYXJIZWlnaHQpO3ZhciBzPXRoaXMuX3RtcEN0eC5nZXRJbWFnZURhdGEoMCwwLHRoaXMuX2NvbmZpZy5zY2FsZWRDaGFyV2lkdGgsdGhpcy5fY29uZmlnLnNjYWxlZENoYXJIZWlnaHQpLGE9ITE7aWYodGhpcy5fY29uZmlnLmFsbG93VHJhbnNwYXJlbmN5fHwoYT15KHMscikpLGEmJiJfIj09PWUuY2hhcnMmJiF0aGlzLl9jb25maWcuYWxsb3dUcmFuc3BhcmVuY3kpZm9yKHZhciBjPTE7Yzw9NSYmKHRoaXMuX3RtcEN0eC5maWxsVGV4dChlLmNoYXJzLDAsdGhpcy5fY29uZmlnLnNjYWxlZENoYXJIZWlnaHQtYyksYT15KHM9dGhpcy5fdG1wQ3R4LmdldEltYWdlRGF0YSgwLDAsdGhpcy5fY29uZmlnLnNjYWxlZENoYXJXaWR0aCx0aGlzLl9jb25maWcuc2NhbGVkQ2hhckhlaWdodCkscikpO2MrKyk7dGhpcy5fdG1wQ3R4LnJlc3RvcmUoKTt2YXIgbD10aGlzLl90b0Nvb3JkaW5hdGVYKHQpLHU9dGhpcy5fdG9Db29yZGluYXRlWSh0KTt0aGlzLl9jYWNoZUN0eC5wdXRJbWFnZURhdGEocyxsLHUpO3ZhciBoPXtpbmRleDp0LGlzRW1wdHk6YSxpbkJpdG1hcDohMX07cmV0dXJuIHRoaXMuX2FkZEdseXBoVG9CaXRtYXAoaCksaH0sdC5wcm90b3R5cGUuX2FkZEdseXBoVG9CaXRtYXA9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpczshKCJjcmVhdGVJbWFnZUJpdG1hcCJpbiB3aW5kb3cpfHxsLmlzRmlyZWZveHx8bC5pc1NhZmFyaXx8KHRoaXMuX2dseXBoc1dhaXRpbmdPbkJpdG1hcC5wdXNoKGUpLG51bGw9PT10aGlzLl9iaXRtYXBDb21taXRUaW1lb3V0JiYodGhpcy5fYml0bWFwQ29tbWl0VGltZW91dD13aW5kb3cuc2V0VGltZW91dCgoZnVuY3Rpb24oKXtyZXR1cm4gdC5fZ2VuZXJhdGVCaXRtYXAoKX0pLDEwMCkpKX0sdC5wcm90b3R5cGUuX2dlbmVyYXRlQml0bWFwPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PXRoaXMuX2dseXBoc1dhaXRpbmdPbkJpdG1hcDt0aGlzLl9nbHlwaHNXYWl0aW5nT25CaXRtYXA9W10sd2luZG93LmNyZWF0ZUltYWdlQml0bWFwKHRoaXMuX2NhY2hlQ2FudmFzKS50aGVuKChmdW5jdGlvbihyKXtlLl9iaXRtYXA9cjtmb3IodmFyIGk9MDtpPHQubGVuZ3RoO2krKyl0W2ldLmluQml0bWFwPSEwfSkpLHRoaXMuX2JpdG1hcENvbW1pdFRpbWVvdXQ9bnVsbH0sdH0ocy5CYXNlQ2hhckF0bGFzKTt0LkR5bmFtaWNDaGFyQXRsYXM9djt2YXIgZz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQscil7cmV0dXJuIGUuY2FsbCh0aGlzKXx8dGhpc31yZXR1cm4gbih0LGUpLHQucHJvdG90eXBlLmRyYXc9ZnVuY3Rpb24oZSx0LHIsaSl7cmV0dXJuITF9LHR9KHMuQmFzZUNoYXJBdGxhcyk7ZnVuY3Rpb24geShlLHQpe2Zvcih2YXIgcj0hMCxpPXQucmdiYT4+PjI0LG49dC5yZ2JhPj4+MTYmMjU1LG89dC5yZ2JhPj4+OCYyNTUscz0wO3M8ZS5kYXRhLmxlbmd0aDtzKz00KWUuZGF0YVtzXT09PWkmJmUuZGF0YVtzKzFdPT09biYmZS5kYXRhW3MrMl09PT1vP2UuZGF0YVtzKzNdPTA6cj0hMTtyZXR1cm4gcn10Lk5vbmVDaGFyQXRsYXM9Z30sNzAwMTooZSx0KT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkxSVU1hcD12b2lkIDA7dmFyIHI9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMuY2FwYWNpdHk9ZSx0aGlzLl9tYXA9e30sdGhpcy5faGVhZD1udWxsLHRoaXMuX3RhaWw9bnVsbCx0aGlzLl9ub2RlUG9vbD1bXSx0aGlzLnNpemU9MH1yZXR1cm4gZS5wcm90b3R5cGUuX3VubGlua05vZGU9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5wcmV2LHI9ZS5uZXh0O2U9PT10aGlzLl9oZWFkJiYodGhpcy5faGVhZD1yKSxlPT09dGhpcy5fdGFpbCYmKHRoaXMuX3RhaWw9dCksbnVsbCE9PXQmJih0Lm5leHQ9ciksbnVsbCE9PXImJihyLnByZXY9dCl9LGUucHJvdG90eXBlLl9hcHBlbmROb2RlPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuX3RhaWw7bnVsbCE9PXQmJih0Lm5leHQ9ZSksZS5wcmV2PXQsZS5uZXh0PW51bGwsdGhpcy5fdGFpbD1lLG51bGw9PT10aGlzLl9oZWFkJiYodGhpcy5faGVhZD1lKX0sZS5wcm90b3R5cGUucHJlYWxsb2M9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PXRoaXMuX25vZGVQb29sLHI9MDtyPGU7cisrKXQucHVzaCh7cHJldjpudWxsLG5leHQ6bnVsbCxrZXk6bnVsbCx2YWx1ZTpudWxsfSl9LGUucHJvdG90eXBlLmdldD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9tYXBbZV07cmV0dXJuIHZvaWQgMCE9PXQ/KHRoaXMuX3VubGlua05vZGUodCksdGhpcy5fYXBwZW5kTm9kZSh0KSx0LnZhbHVlKTpudWxsfSxlLnByb3RvdHlwZS5wZWVrVmFsdWU9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fbWFwW2VdO3JldHVybiB2b2lkIDAhPT10P3QudmFsdWU6bnVsbH0sZS5wcm90b3R5cGUucGVlaz1mdW5jdGlvbigpe3ZhciBlPXRoaXMuX2hlYWQ7cmV0dXJuIG51bGw9PT1lP251bGw6ZS52YWx1ZX0sZS5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUsdCl7dmFyIHI9dGhpcy5fbWFwW2VdO2lmKHZvaWQgMCE9PXIpcj10aGlzLl9tYXBbZV0sdGhpcy5fdW5saW5rTm9kZShyKSxyLnZhbHVlPXQ7ZWxzZSBpZih0aGlzLnNpemU+PXRoaXMuY2FwYWNpdHkpcj10aGlzLl9oZWFkLHRoaXMuX3VubGlua05vZGUociksZGVsZXRlIHRoaXMuX21hcFtyLmtleV0sci5rZXk9ZSxyLnZhbHVlPXQsdGhpcy5fbWFwW2VdPXI7ZWxzZXt2YXIgaT10aGlzLl9ub2RlUG9vbDtpLmxlbmd0aD4wPygocj1pLnBvcCgpKS5rZXk9ZSxyLnZhbHVlPXQpOnI9e3ByZXY6bnVsbCxuZXh0Om51bGwsa2V5OmUsdmFsdWU6dH0sdGhpcy5fbWFwW2VdPXIsdGhpcy5zaXplKyt9dGhpcy5fYXBwZW5kTm9kZShyKX0sZX0oKTt0LkxSVU1hcD1yfSwxMjk2OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkRvbVJlbmRlcmVyPXZvaWQgMDt2YXIgYT1yKDM3ODcpLGM9cig4ODAzKSxsPXIoODQ0KSx1PXIoNDcyNSksaD1yKDI1ODUpLGY9cig4NDYwKSxfPXIoNDc3NCksZD1yKDk2MzEpLHA9Inh0ZXJtLWRvbS1yZW5kZXJlci1vd25lci0iLHY9Inh0ZXJtLWZnLSIsZz0ieHRlcm0tYmctIix5PSJ4dGVybS1mb2N1cyIsbT0xLGI9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0LHIsaSxuLG8scyxjLGwsdSxoKXt2YXIgZj1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIGYuX2NvbG9ycz10LGYuX2VsZW1lbnQ9cixmLl9zY3JlZW5FbGVtZW50PWksZi5fdmlld3BvcnRFbGVtZW50PW4sZi5fbGlua2lmaWVyPW8sZi5fbGlua2lmaWVyMj1zLGYuX2NoYXJTaXplU2VydmljZT1sLGYuX29wdGlvbnNTZXJ2aWNlPXUsZi5fYnVmZmVyU2VydmljZT1oLGYuX3Rlcm1pbmFsQ2xhc3M9bSsrLGYuX3Jvd0VsZW1lbnRzPVtdLGYuX3Jvd0NvbnRhaW5lcj1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKSxmLl9yb3dDb250YWluZXIuY2xhc3NMaXN0LmFkZCgieHRlcm0tcm93cyIpLGYuX3Jvd0NvbnRhaW5lci5zdHlsZS5saW5lSGVpZ2h0PSJub3JtYWwiLGYuX3Jvd0NvbnRhaW5lci5zZXRBdHRyaWJ1dGUoImFyaWEtaGlkZGVuIiwidHJ1ZSIpLGYuX3JlZnJlc2hSb3dFbGVtZW50cyhmLl9idWZmZXJTZXJ2aWNlLmNvbHMsZi5fYnVmZmVyU2VydmljZS5yb3dzKSxmLl9zZWxlY3Rpb25Db250YWluZXI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IiksZi5fc2VsZWN0aW9uQ29udGFpbmVyLmNsYXNzTGlzdC5hZGQoInh0ZXJtLXNlbGVjdGlvbiIpLGYuX3NlbGVjdGlvbkNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoImFyaWEtaGlkZGVuIiwidHJ1ZSIpLGYuZGltZW5zaW9ucz17c2NhbGVkQ2hhcldpZHRoOjAsc2NhbGVkQ2hhckhlaWdodDowLHNjYWxlZENlbGxXaWR0aDowLHNjYWxlZENlbGxIZWlnaHQ6MCxzY2FsZWRDaGFyTGVmdDowLHNjYWxlZENoYXJUb3A6MCxzY2FsZWRDYW52YXNXaWR0aDowLHNjYWxlZENhbnZhc0hlaWdodDowLGNhbnZhc1dpZHRoOjAsY2FudmFzSGVpZ2h0OjAsYWN0dWFsQ2VsbFdpZHRoOjAsYWN0dWFsQ2VsbEhlaWdodDowfSxmLl91cGRhdGVEaW1lbnNpb25zKCksZi5faW5qZWN0Q3NzKCksZi5fcm93RmFjdG9yeT1jLmNyZWF0ZUluc3RhbmNlKGEuRG9tUmVuZGVyZXJSb3dGYWN0b3J5LGRvY3VtZW50LGYuX2NvbG9ycyksZi5fZWxlbWVudC5jbGFzc0xpc3QuYWRkKHArZi5fdGVybWluYWxDbGFzcyksZi5fc2NyZWVuRWxlbWVudC5hcHBlbmRDaGlsZChmLl9yb3dDb250YWluZXIpLGYuX3NjcmVlbkVsZW1lbnQuYXBwZW5kQ2hpbGQoZi5fc2VsZWN0aW9uQ29udGFpbmVyKSxmLl9saW5raWZpZXIub25TaG93TGlua1VuZGVybGluZSgoZnVuY3Rpb24oZSl7cmV0dXJuIGYuX29uTGlua0hvdmVyKGUpfSkpLGYuX2xpbmtpZmllci5vbkhpZGVMaW5rVW5kZXJsaW5lKChmdW5jdGlvbihlKXtyZXR1cm4gZi5fb25MaW5rTGVhdmUoZSl9KSksZi5fbGlua2lmaWVyMi5vblNob3dMaW5rVW5kZXJsaW5lKChmdW5jdGlvbihlKXtyZXR1cm4gZi5fb25MaW5rSG92ZXIoZSl9KSksZi5fbGlua2lmaWVyMi5vbkhpZGVMaW5rVW5kZXJsaW5lKChmdW5jdGlvbihlKXtyZXR1cm4gZi5fb25MaW5rTGVhdmUoZSl9KSksZn1yZXR1cm4gbih0LGUpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25SZXF1ZXN0UmVkcmF3Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuKG5ldyBmLkV2ZW50RW1pdHRlcikuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe3RoaXMuX2VsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZShwK3RoaXMuX3Rlcm1pbmFsQ2xhc3MpLCgwLGQucmVtb3ZlRWxlbWVudEZyb21QYXJlbnQpKHRoaXMuX3Jvd0NvbnRhaW5lcix0aGlzLl9zZWxlY3Rpb25Db250YWluZXIsdGhpcy5fdGhlbWVTdHlsZUVsZW1lbnQsdGhpcy5fZGltZW5zaW9uc1N0eWxlRWxlbWVudCksZS5wcm90b3R5cGUuZGlzcG9zZS5jYWxsKHRoaXMpfSx0LnByb3RvdHlwZS5fdXBkYXRlRGltZW5zaW9ucz1mdW5jdGlvbigpe3RoaXMuZGltZW5zaW9ucy5zY2FsZWRDaGFyV2lkdGg9dGhpcy5fY2hhclNpemVTZXJ2aWNlLndpZHRoKndpbmRvdy5kZXZpY2VQaXhlbFJhdGlvLHRoaXMuZGltZW5zaW9ucy5zY2FsZWRDaGFySGVpZ2h0PU1hdGguY2VpbCh0aGlzLl9jaGFyU2l6ZVNlcnZpY2UuaGVpZ2h0KndpbmRvdy5kZXZpY2VQaXhlbFJhdGlvKSx0aGlzLmRpbWVuc2lvbnMuc2NhbGVkQ2VsbFdpZHRoPXRoaXMuZGltZW5zaW9ucy5zY2FsZWRDaGFyV2lkdGgrTWF0aC5yb3VuZCh0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmxldHRlclNwYWNpbmcpLHRoaXMuZGltZW5zaW9ucy5zY2FsZWRDZWxsSGVpZ2h0PU1hdGguZmxvb3IodGhpcy5kaW1lbnNpb25zLnNjYWxlZENoYXJIZWlnaHQqdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5saW5lSGVpZ2h0KSx0aGlzLmRpbWVuc2lvbnMuc2NhbGVkQ2hhckxlZnQ9MCx0aGlzLmRpbWVuc2lvbnMuc2NhbGVkQ2hhclRvcD0wLHRoaXMuZGltZW5zaW9ucy5zY2FsZWRDYW52YXNXaWR0aD10aGlzLmRpbWVuc2lvbnMuc2NhbGVkQ2VsbFdpZHRoKnRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyx0aGlzLmRpbWVuc2lvbnMuc2NhbGVkQ2FudmFzSGVpZ2h0PXRoaXMuZGltZW5zaW9ucy5zY2FsZWRDZWxsSGVpZ2h0KnRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyx0aGlzLmRpbWVuc2lvbnMuY2FudmFzV2lkdGg9TWF0aC5yb3VuZCh0aGlzLmRpbWVuc2lvbnMuc2NhbGVkQ2FudmFzV2lkdGgvd2luZG93LmRldmljZVBpeGVsUmF0aW8pLHRoaXMuZGltZW5zaW9ucy5jYW52YXNIZWlnaHQ9TWF0aC5yb3VuZCh0aGlzLmRpbWVuc2lvbnMuc2NhbGVkQ2FudmFzSGVpZ2h0L3dpbmRvdy5kZXZpY2VQaXhlbFJhdGlvKSx0aGlzLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbFdpZHRoPXRoaXMuZGltZW5zaW9ucy5jYW52YXNXaWR0aC90aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsdGhpcy5kaW1lbnNpb25zLmFjdHVhbENlbGxIZWlnaHQ9dGhpcy5kaW1lbnNpb25zLmNhbnZhc0hlaWdodC90aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3M7Zm9yKHZhciBlPTAsdD10aGlzLl9yb3dFbGVtZW50cztlPHQubGVuZ3RoO2UrKyl7dmFyIHI9dFtlXTtyLnN0eWxlLndpZHRoPXRoaXMuZGltZW5zaW9ucy5jYW52YXNXaWR0aCsicHgiLHIuc3R5bGUuaGVpZ2h0PXRoaXMuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0KyJweCIsci5zdHlsZS5saW5lSGVpZ2h0PXRoaXMuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0KyJweCIsci5zdHlsZS5vdmVyZmxvdz0iaGlkZGVuIn10aGlzLl9kaW1lbnNpb25zU3R5bGVFbGVtZW50fHwodGhpcy5fZGltZW5zaW9uc1N0eWxlRWxlbWVudD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzdHlsZSIpLHRoaXMuX3NjcmVlbkVsZW1lbnQuYXBwZW5kQ2hpbGQodGhpcy5fZGltZW5zaW9uc1N0eWxlRWxlbWVudCkpO3ZhciBpPXRoaXMuX3Rlcm1pbmFsU2VsZWN0b3IrIiAueHRlcm0tcm93cyBzcGFuIHsgZGlzcGxheTogaW5saW5lLWJsb2NrOyBoZWlnaHQ6IDEwMCU7IHZlcnRpY2FsLWFsaWduOiB0b3A7IHdpZHRoOiAiK3RoaXMuZGltZW5zaW9ucy5hY3R1YWxDZWxsV2lkdGgrInB4fSI7dGhpcy5fZGltZW5zaW9uc1N0eWxlRWxlbWVudC50ZXh0Q29udGVudD1pLHRoaXMuX3NlbGVjdGlvbkNvbnRhaW5lci5zdHlsZS5oZWlnaHQ9dGhpcy5fdmlld3BvcnRFbGVtZW50LnN0eWxlLmhlaWdodCx0aGlzLl9zY3JlZW5FbGVtZW50LnN0eWxlLndpZHRoPXRoaXMuZGltZW5zaW9ucy5jYW52YXNXaWR0aCsicHgiLHRoaXMuX3NjcmVlbkVsZW1lbnQuc3R5bGUuaGVpZ2h0PXRoaXMuZGltZW5zaW9ucy5jYW52YXNIZWlnaHQrInB4In0sdC5wcm90b3R5cGUuc2V0Q29sb3JzPWZ1bmN0aW9uKGUpe3RoaXMuX2NvbG9ycz1lLHRoaXMuX2luamVjdENzcygpfSx0LnByb3RvdHlwZS5faW5qZWN0Q3NzPWZ1bmN0aW9uKCl7dmFyIGU9dGhpczt0aGlzLl90aGVtZVN0eWxlRWxlbWVudHx8KHRoaXMuX3RoZW1lU3R5bGVFbGVtZW50PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInN0eWxlIiksdGhpcy5fc2NyZWVuRWxlbWVudC5hcHBlbmRDaGlsZCh0aGlzLl90aGVtZVN0eWxlRWxlbWVudCkpO3ZhciB0PXRoaXMuX3Rlcm1pbmFsU2VsZWN0b3IrIiAueHRlcm0tcm93cyB7IGNvbG9yOiAiK3RoaXMuX2NvbG9ycy5mb3JlZ3JvdW5kLmNzcysiOyBmb250LWZhbWlseTogIit0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmZvbnRGYW1pbHkrIjsgZm9udC1zaXplOiAiK3RoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuZm9udFNpemUrInB4O30iO3QrPXRoaXMuX3Rlcm1pbmFsU2VsZWN0b3IrIiBzcGFuOm5vdCguIithLkJPTERfQ0xBU1MrIikgeyBmb250LXdlaWdodDogIit0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmZvbnRXZWlnaHQrIjt9Iit0aGlzLl90ZXJtaW5hbFNlbGVjdG9yKyIgc3Bhbi4iK2EuQk9MRF9DTEFTUysiIHsgZm9udC13ZWlnaHQ6ICIrdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5mb250V2VpZ2h0Qm9sZCsiO30iK3RoaXMuX3Rlcm1pbmFsU2VsZWN0b3IrIiBzcGFuLiIrYS5JVEFMSUNfQ0xBU1MrIiB7IGZvbnQtc3R5bGU6IGl0YWxpYzt9Iix0Kz0iQGtleWZyYW1lcyBibGlua19ib3hfc2hhZG93XyIrdGhpcy5fdGVybWluYWxDbGFzcysiIHsgNTAlIHsgIGJveC1zaGFkb3c6IG5vbmU7IH19Iix0Kz0iQGtleWZyYW1lcyBibGlua19ibG9ja18iK3RoaXMuX3Rlcm1pbmFsQ2xhc3MrIiB7IDAlIHsgIGJhY2tncm91bmQtY29sb3I6ICIrdGhpcy5fY29sb3JzLmN1cnNvci5jc3MrIjsgIGNvbG9yOiAiK3RoaXMuX2NvbG9ycy5jdXJzb3JBY2NlbnQuY3NzKyI7IH0gNTAlIHsgIGJhY2tncm91bmQtY29sb3I6ICIrdGhpcy5fY29sb3JzLmN1cnNvckFjY2VudC5jc3MrIjsgIGNvbG9yOiAiK3RoaXMuX2NvbG9ycy5jdXJzb3IuY3NzKyI7IH19Iix0Kz10aGlzLl90ZXJtaW5hbFNlbGVjdG9yKyIgLnh0ZXJtLXJvd3M6bm90KC54dGVybS1mb2N1cykgLiIrYS5DVVJTT1JfQ0xBU1MrIi4iK2EuQ1VSU09SX1NUWUxFX0JMT0NLX0NMQVNTKyIgeyBvdXRsaW5lOiAxcHggc29saWQgIit0aGlzLl9jb2xvcnMuY3Vyc29yLmNzcysiOyBvdXRsaW5lLW9mZnNldDogLTFweDt9Iit0aGlzLl90ZXJtaW5hbFNlbGVjdG9yKyIgLnh0ZXJtLXJvd3MueHRlcm0tZm9jdXMgLiIrYS5DVVJTT1JfQ0xBU1MrIi4iK2EuQ1VSU09SX0JMSU5LX0NMQVNTKyI6bm90KC4iK2EuQ1VSU09SX1NUWUxFX0JMT0NLX0NMQVNTKyIpIHsgYW5pbWF0aW9uOiBibGlua19ib3hfc2hhZG93XyIrdGhpcy5fdGVybWluYWxDbGFzcysiIDFzIHN0ZXAtZW5kIGluZmluaXRlO30iK3RoaXMuX3Rlcm1pbmFsU2VsZWN0b3IrIiAueHRlcm0tcm93cy54dGVybS1mb2N1cyAuIithLkNVUlNPUl9DTEFTUysiLiIrYS5DVVJTT1JfQkxJTktfQ0xBU1MrIi4iK2EuQ1VSU09SX1NUWUxFX0JMT0NLX0NMQVNTKyIgeyBhbmltYXRpb246IGJsaW5rX2Jsb2NrXyIrdGhpcy5fdGVybWluYWxDbGFzcysiIDFzIHN0ZXAtZW5kIGluZmluaXRlO30iK3RoaXMuX3Rlcm1pbmFsU2VsZWN0b3IrIiAueHRlcm0tcm93cy54dGVybS1mb2N1cyAuIithLkNVUlNPUl9DTEFTUysiLiIrYS5DVVJTT1JfU1RZTEVfQkxPQ0tfQ0xBU1MrIiB7IGJhY2tncm91bmQtY29sb3I6ICIrdGhpcy5fY29sb3JzLmN1cnNvci5jc3MrIjsgY29sb3I6ICIrdGhpcy5fY29sb3JzLmN1cnNvckFjY2VudC5jc3MrIjt9Iit0aGlzLl90ZXJtaW5hbFNlbGVjdG9yKyIgLnh0ZXJtLXJvd3MgLiIrYS5DVVJTT1JfQ0xBU1MrIi4iK2EuQ1VSU09SX1NUWUxFX0JBUl9DTEFTUysiIHsgYm94LXNoYWRvdzogIit0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmN1cnNvcldpZHRoKyJweCAwIDAgIit0aGlzLl9jb2xvcnMuY3Vyc29yLmNzcysiIGluc2V0O30iK3RoaXMuX3Rlcm1pbmFsU2VsZWN0b3IrIiAueHRlcm0tcm93cyAuIithLkNVUlNPUl9DTEFTUysiLiIrYS5DVVJTT1JfU1RZTEVfVU5ERVJMSU5FX0NMQVNTKyIgeyBib3gtc2hhZG93OiAwIC0xcHggMCAiK3RoaXMuX2NvbG9ycy5jdXJzb3IuY3NzKyIgaW5zZXQ7fSIsdCs9dGhpcy5fdGVybWluYWxTZWxlY3RvcisiIC54dGVybS1zZWxlY3Rpb24geyBwb3NpdGlvbjogYWJzb2x1dGU7IHRvcDogMDsgbGVmdDogMDsgei1pbmRleDogMTsgcG9pbnRlci1ldmVudHM6IG5vbmU7fSIrdGhpcy5fdGVybWluYWxTZWxlY3RvcisiIC54dGVybS1zZWxlY3Rpb24gZGl2IHsgcG9zaXRpb246IGFic29sdXRlOyBiYWNrZ3JvdW5kLWNvbG9yOiAiK3RoaXMuX2NvbG9ycy5zZWxlY3Rpb25UcmFuc3BhcmVudC5jc3MrIjt9Iix0aGlzLl9jb2xvcnMuYW5zaS5mb3JFYWNoKChmdW5jdGlvbihyLGkpe3QrPWUuX3Rlcm1pbmFsU2VsZWN0b3IrIiAuIit2K2krIiB7IGNvbG9yOiAiK3IuY3NzKyI7IH0iK2UuX3Rlcm1pbmFsU2VsZWN0b3IrIiAuIitnK2krIiB7IGJhY2tncm91bmQtY29sb3I6ICIrci5jc3MrIjsgfSJ9KSksdCs9dGhpcy5fdGVybWluYWxTZWxlY3RvcisiIC4iK3YrYy5JTlZFUlRFRF9ERUZBVUxUX0NPTE9SKyIgeyBjb2xvcjogIitfLmNvbG9yLm9wYXF1ZSh0aGlzLl9jb2xvcnMuYmFja2dyb3VuZCkuY3NzKyI7IH0iK3RoaXMuX3Rlcm1pbmFsU2VsZWN0b3IrIiAuIitnK2MuSU5WRVJURURfREVGQVVMVF9DT0xPUisiIHsgYmFja2dyb3VuZC1jb2xvcjogIit0aGlzLl9jb2xvcnMuZm9yZWdyb3VuZC5jc3MrIjsgfSIsdGhpcy5fdGhlbWVTdHlsZUVsZW1lbnQudGV4dENvbnRlbnQ9dH0sdC5wcm90b3R5cGUub25EZXZpY2VQaXhlbFJhdGlvQ2hhbmdlPWZ1bmN0aW9uKCl7dGhpcy5fdXBkYXRlRGltZW5zaW9ucygpfSx0LnByb3RvdHlwZS5fcmVmcmVzaFJvd0VsZW1lbnRzPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPXRoaXMuX3Jvd0VsZW1lbnRzLmxlbmd0aDtyPD10O3IrKyl7dmFyIGk9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7dGhpcy5fcm93Q29udGFpbmVyLmFwcGVuZENoaWxkKGkpLHRoaXMuX3Jvd0VsZW1lbnRzLnB1c2goaSl9Zm9yKDt0aGlzLl9yb3dFbGVtZW50cy5sZW5ndGg+dDspdGhpcy5fcm93Q29udGFpbmVyLnJlbW92ZUNoaWxkKHRoaXMuX3Jvd0VsZW1lbnRzLnBvcCgpKX0sdC5wcm90b3R5cGUub25SZXNpemU9ZnVuY3Rpb24oZSx0KXt0aGlzLl9yZWZyZXNoUm93RWxlbWVudHMoZSx0KSx0aGlzLl91cGRhdGVEaW1lbnNpb25zKCl9LHQucHJvdG90eXBlLm9uQ2hhclNpemVDaGFuZ2VkPWZ1bmN0aW9uKCl7dGhpcy5fdXBkYXRlRGltZW5zaW9ucygpfSx0LnByb3RvdHlwZS5vbkJsdXI9ZnVuY3Rpb24oKXt0aGlzLl9yb3dDb250YWluZXIuY2xhc3NMaXN0LnJlbW92ZSh5KX0sdC5wcm90b3R5cGUub25Gb2N1cz1mdW5jdGlvbigpe3RoaXMuX3Jvd0NvbnRhaW5lci5jbGFzc0xpc3QuYWRkKHkpfSx0LnByb3RvdHlwZS5vblNlbGVjdGlvbkNoYW5nZWQ9ZnVuY3Rpb24oZSx0LHIpe2Zvcig7dGhpcy5fc2VsZWN0aW9uQ29udGFpbmVyLmNoaWxkcmVuLmxlbmd0aDspdGhpcy5fc2VsZWN0aW9uQ29udGFpbmVyLnJlbW92ZUNoaWxkKHRoaXMuX3NlbGVjdGlvbkNvbnRhaW5lci5jaGlsZHJlblswXSk7aWYoZSYmdCl7dmFyIGk9ZVsxXS10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55ZGlzcCxuPXRbMV0tdGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueWRpc3Asbz1NYXRoLm1heChpLDApLHM9TWF0aC5taW4obix0aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MtMSk7aWYoIShvPj10aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3N8fHM8MCkpe3ZhciBhPWRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtpZihyKWEuYXBwZW5kQ2hpbGQodGhpcy5fY3JlYXRlU2VsZWN0aW9uRWxlbWVudChvLGVbMF0sdFswXSxzLW8rMSkpO2Vsc2V7dmFyIGM9aT09PW8/ZVswXTowLGw9bz09PW4/dFswXTp0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHM7YS5hcHBlbmRDaGlsZCh0aGlzLl9jcmVhdGVTZWxlY3Rpb25FbGVtZW50KG8sYyxsKSk7dmFyIHU9cy1vLTE7aWYoYS5hcHBlbmRDaGlsZCh0aGlzLl9jcmVhdGVTZWxlY3Rpb25FbGVtZW50KG8rMSwwLHRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyx1KSksbyE9PXMpe3ZhciBoPW49PT1zP3RbMF06dGhpcy5fYnVmZmVyU2VydmljZS5jb2xzO2EuYXBwZW5kQ2hpbGQodGhpcy5fY3JlYXRlU2VsZWN0aW9uRWxlbWVudChzLDAsaCkpfX10aGlzLl9zZWxlY3Rpb25Db250YWluZXIuYXBwZW5kQ2hpbGQoYSl9fX0sdC5wcm90b3R5cGUuX2NyZWF0ZVNlbGVjdGlvbkVsZW1lbnQ9ZnVuY3Rpb24oZSx0LHIsaSl7dm9pZCAwPT09aSYmKGk9MSk7dmFyIG49ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7cmV0dXJuIG4uc3R5bGUuaGVpZ2h0PWkqdGhpcy5kaW1lbnNpb25zLmFjdHVhbENlbGxIZWlnaHQrInB4IixuLnN0eWxlLnRvcD1lKnRoaXMuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0KyJweCIsbi5zdHlsZS5sZWZ0PXQqdGhpcy5kaW1lbnNpb25zLmFjdHVhbENlbGxXaWR0aCsicHgiLG4uc3R5bGUud2lkdGg9dGhpcy5kaW1lbnNpb25zLmFjdHVhbENlbGxXaWR0aCooci10KSsicHgiLG59LHQucHJvdG90eXBlLm9uQ3Vyc29yTW92ZT1mdW5jdGlvbigpe30sdC5wcm90b3R5cGUub25PcHRpb25zQ2hhbmdlZD1mdW5jdGlvbigpe3RoaXMuX3VwZGF0ZURpbWVuc2lvbnMoKSx0aGlzLl9pbmplY3RDc3MoKX0sdC5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXtmb3IodmFyIGU9MCx0PXRoaXMuX3Jvd0VsZW1lbnRzO2U8dC5sZW5ndGg7ZSsrKXRbZV0uaW5uZXJUZXh0PSIifSx0LnByb3RvdHlwZS5yZW5kZXJSb3dzPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnliYXNlK3RoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnksaT1NYXRoLm1pbih0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci54LHRoaXMuX2J1ZmZlclNlcnZpY2UuY29scy0xKSxuPXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuY3Vyc29yQmxpbmssbz1lO288PXQ7bysrKXt2YXIgcz10aGlzLl9yb3dFbGVtZW50c1tvXTtzLmlubmVyVGV4dD0iIjt2YXIgYT1vK3RoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwLGM9dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIubGluZXMuZ2V0KGEpLGw9dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5jdXJzb3JTdHlsZTtzLmFwcGVuZENoaWxkKHRoaXMuX3Jvd0ZhY3RvcnkuY3JlYXRlUm93KGMsYSxhPT09cixsLGksbix0aGlzLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbFdpZHRoLHRoaXMuX2J1ZmZlclNlcnZpY2UuY29scykpfX0sT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJfdGVybWluYWxTZWxlY3RvciIse2dldDpmdW5jdGlvbigpe3JldHVybiIuIitwK3RoaXMuX3Rlcm1pbmFsQ2xhc3N9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuX29uTGlua0hvdmVyPWZ1bmN0aW9uKGUpe3RoaXMuX3NldENlbGxVbmRlcmxpbmUoZS54MSxlLngyLGUueTEsZS55MixlLmNvbHMsITApfSx0LnByb3RvdHlwZS5fb25MaW5rTGVhdmU9ZnVuY3Rpb24oZSl7dGhpcy5fc2V0Q2VsbFVuZGVybGluZShlLngxLGUueDIsZS55MSxlLnkyLGUuY29scywhMSl9LHQucHJvdG90eXBlLl9zZXRDZWxsVW5kZXJsaW5lPWZ1bmN0aW9uKGUsdCxyLGksbixvKXtmb3IoO2UhPT10fHxyIT09aTspe3ZhciBzPXRoaXMuX3Jvd0VsZW1lbnRzW3JdO2lmKCFzKXJldHVybjt2YXIgYT1zLmNoaWxkcmVuW2VdO2EmJihhLnN0eWxlLnRleHREZWNvcmF0aW9uPW8/InVuZGVybGluZSI6Im5vbmUiKSwrK2U+PW4mJihlPTAscisrKX19LG8oW3MoNixoLklJbnN0YW50aWF0aW9uU2VydmljZSkscyg3LHUuSUNoYXJTaXplU2VydmljZSkscyg4LGguSU9wdGlvbnNTZXJ2aWNlKSxzKDksaC5JQnVmZmVyU2VydmljZSldLHQpfShsLkRpc3Bvc2FibGUpO3QuRG9tUmVuZGVyZXI9Yn0sMzc4NzpmdW5jdGlvbihlLHQscil7dmFyIGk9dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxuPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkRvbVJlbmRlcmVyUm93RmFjdG9yeT10LkNVUlNPUl9TVFlMRV9VTkRFUkxJTkVfQ0xBU1M9dC5DVVJTT1JfU1RZTEVfQkFSX0NMQVNTPXQuQ1VSU09SX1NUWUxFX0JMT0NLX0NMQVNTPXQuQ1VSU09SX0JMSU5LX0NMQVNTPXQuQ1VSU09SX0NMQVNTPXQuU1RSSUtFVEhST1VHSF9DTEFTUz10LlVOREVSTElORV9DTEFTUz10LklUQUxJQ19DTEFTUz10LkRJTV9DTEFTUz10LkJPTERfQ0xBU1M9dm9pZCAwO3ZhciBvPXIoODgwMykscz1yKDY0MyksYT1yKDUxMSksYz1yKDI1ODUpLGw9cig0Nzc0KSx1PXIoNDcyNSksaD1yKDQyNjkpO3QuQk9MRF9DTEFTUz0ieHRlcm0tYm9sZCIsdC5ESU1fQ0xBU1M9Inh0ZXJtLWRpbSIsdC5JVEFMSUNfQ0xBU1M9Inh0ZXJtLWl0YWxpYyIsdC5VTkRFUkxJTkVfQ0xBU1M9Inh0ZXJtLXVuZGVybGluZSIsdC5TVFJJS0VUSFJPVUdIX0NMQVNTPSJ4dGVybS1zdHJpa2V0aHJvdWdoIix0LkNVUlNPUl9DTEFTUz0ieHRlcm0tY3Vyc29yIix0LkNVUlNPUl9CTElOS19DTEFTUz0ieHRlcm0tY3Vyc29yLWJsaW5rIix0LkNVUlNPUl9TVFlMRV9CTE9DS19DTEFTUz0ieHRlcm0tY3Vyc29yLWJsb2NrIix0LkNVUlNPUl9TVFlMRV9CQVJfQ0xBU1M9Inh0ZXJtLWN1cnNvci1iYXIiLHQuQ1VSU09SX1NUWUxFX1VOREVSTElORV9DTEFTUz0ieHRlcm0tY3Vyc29yLXVuZGVybGluZSI7dmFyIGY9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxyLGksbil7dGhpcy5fZG9jdW1lbnQ9ZSx0aGlzLl9jb2xvcnM9dCx0aGlzLl9jaGFyYWN0ZXJKb2luZXJTZXJ2aWNlPXIsdGhpcy5fb3B0aW9uc1NlcnZpY2U9aSx0aGlzLl9jb3JlU2VydmljZT1uLHRoaXMuX3dvcmtDZWxsPW5ldyBhLkNlbGxEYXRhfXJldHVybiBlLnByb3RvdHlwZS5zZXRDb2xvcnM9ZnVuY3Rpb24oZSl7dGhpcy5fY29sb3JzPWV9LGUucHJvdG90eXBlLmNyZWF0ZVJvdz1mdW5jdGlvbihlLHIsaSxuLGEsYyx1LGYpe2Zvcih2YXIgZD10aGlzLl9kb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCkscD10aGlzLl9jaGFyYWN0ZXJKb2luZXJTZXJ2aWNlLmdldEpvaW5lZENoYXJhY3RlcnMociksdj0wLGc9TWF0aC5taW4oZS5sZW5ndGgsZiktMTtnPj0wO2ctLSlpZihlLmxvYWRDZWxsKGcsdGhpcy5fd29ya0NlbGwpLmdldENvZGUoKSE9PXMuTlVMTF9DRUxMX0NPREV8fGkmJmc9PT1hKXt2PWcrMTticmVha31mb3IoZz0wO2c8djtnKyspe2UubG9hZENlbGwoZyx0aGlzLl93b3JrQ2VsbCk7dmFyIHk9dGhpcy5fd29ya0NlbGwuZ2V0V2lkdGgoKTtpZigwIT09eSl7dmFyIG09ITEsYj1nLFM9dGhpcy5fd29ya0NlbGw7aWYocC5sZW5ndGg+MCYmZz09PXBbMF1bMF0pe209ITA7dmFyIEM9cC5zaGlmdCgpO1M9bmV3IGguSm9pbmVkQ2VsbERhdGEodGhpcy5fd29ya0NlbGwsZS50cmFuc2xhdGVUb1N0cmluZyghMCxDWzBdLENbMV0pLENbMV0tQ1swXSksYj1DWzFdLTEseT1TLmdldFdpZHRoKCl9dmFyIHc9dGhpcy5fZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3BhbiIpO2lmKHk+MSYmKHcuc3R5bGUud2lkdGg9dSp5KyJweCIpLG0mJih3LnN0eWxlLmRpc3BsYXk9ImlubGluZSIsYT49ZyYmYTw9YiYmKGE9ZykpLCF0aGlzLl9jb3JlU2VydmljZS5pc0N1cnNvckhpZGRlbiYmaSYmZz09PWEpc3dpdGNoKHcuY2xhc3NMaXN0LmFkZCh0LkNVUlNPUl9DTEFTUyksYyYmdy5jbGFzc0xpc3QuYWRkKHQuQ1VSU09SX0JMSU5LX0NMQVNTKSxuKXtjYXNlImJhciI6dy5jbGFzc0xpc3QuYWRkKHQuQ1VSU09SX1NUWUxFX0JBUl9DTEFTUyk7YnJlYWs7Y2FzZSJ1bmRlcmxpbmUiOncuY2xhc3NMaXN0LmFkZCh0LkNVUlNPUl9TVFlMRV9VTkRFUkxJTkVfQ0xBU1MpO2JyZWFrO2RlZmF1bHQ6dy5jbGFzc0xpc3QuYWRkKHQuQ1VSU09SX1NUWUxFX0JMT0NLX0NMQVNTKX1TLmlzQm9sZCgpJiZ3LmNsYXNzTGlzdC5hZGQodC5CT0xEX0NMQVNTKSxTLmlzSXRhbGljKCkmJncuY2xhc3NMaXN0LmFkZCh0LklUQUxJQ19DTEFTUyksUy5pc0RpbSgpJiZ3LmNsYXNzTGlzdC5hZGQodC5ESU1fQ0xBU1MpLFMuaXNVbmRlcmxpbmUoKSYmdy5jbGFzc0xpc3QuYWRkKHQuVU5ERVJMSU5FX0NMQVNTKSxTLmlzSW52aXNpYmxlKCk/dy50ZXh0Q29udGVudD1zLldISVRFU1BBQ0VfQ0VMTF9DSEFSOncudGV4dENvbnRlbnQ9Uy5nZXRDaGFycygpfHxzLldISVRFU1BBQ0VfQ0VMTF9DSEFSLFMuaXNTdHJpa2V0aHJvdWdoKCkmJncuY2xhc3NMaXN0LmFkZCh0LlNUUklLRVRIUk9VR0hfQ0xBU1MpO3ZhciBMPVMuZ2V0RmdDb2xvcigpLEU9Uy5nZXRGZ0NvbG9yTW9kZSgpLHg9Uy5nZXRCZ0NvbG9yKCksQT1TLmdldEJnQ29sb3JNb2RlKCksaz0hIVMuaXNJbnZlcnNlKCk7aWYoayl7dmFyIE09TDtMPXgseD1NO3ZhciBSPUU7RT1BLEE9Un1zd2l0Y2goRSl7Y2FzZSAxNjc3NzIxNjpjYXNlIDMzNTU0NDMyOlMuaXNCb2xkKCkmJkw8OCYmdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5kcmF3Qm9sZFRleHRJbkJyaWdodENvbG9ycyYmKEwrPTgpLHRoaXMuX2FwcGx5TWluaW11bUNvbnRyYXN0KHcsdGhpcy5fY29sb3JzLmJhY2tncm91bmQsdGhpcy5fY29sb3JzLmFuc2lbTF0pfHx3LmNsYXNzTGlzdC5hZGQoInh0ZXJtLWZnLSIrTCk7YnJlYWs7Y2FzZSA1MDMzMTY0ODp2YXIgVD1sLnJnYmEudG9Db2xvcihMPj4xNiYyNTUsTD4+OCYyNTUsMjU1JkwpO3RoaXMuX2FwcGx5TWluaW11bUNvbnRyYXN0KHcsdGhpcy5fY29sb3JzLmJhY2tncm91bmQsVCl8fHRoaXMuX2FkZFN0eWxlKHcsImNvbG9yOiMiK18oTC50b1N0cmluZygxNiksIjAiLDYpKTticmVhaztkZWZhdWx0OnRoaXMuX2FwcGx5TWluaW11bUNvbnRyYXN0KHcsdGhpcy5fY29sb3JzLmJhY2tncm91bmQsdGhpcy5fY29sb3JzLmZvcmVncm91bmQpfHxrJiZ3LmNsYXNzTGlzdC5hZGQoInh0ZXJtLWZnLSIrby5JTlZFUlRFRF9ERUZBVUxUX0NPTE9SKX1zd2l0Y2goQSl7Y2FzZSAxNjc3NzIxNjpjYXNlIDMzNTU0NDMyOncuY2xhc3NMaXN0LmFkZCgieHRlcm0tYmctIit4KTticmVhaztjYXNlIDUwMzMxNjQ4OnRoaXMuX2FkZFN0eWxlKHcsImJhY2tncm91bmQtY29sb3I6IyIrXyh4LnRvU3RyaW5nKDE2KSwiMCIsNikpO2JyZWFrO2RlZmF1bHQ6ayYmdy5jbGFzc0xpc3QuYWRkKCJ4dGVybS1iZy0iK28uSU5WRVJURURfREVGQVVMVF9DT0xPUil9ZC5hcHBlbmRDaGlsZCh3KSxnPWJ9fXJldHVybiBkfSxlLnByb3RvdHlwZS5fYXBwbHlNaW5pbXVtQ29udHJhc3Q9ZnVuY3Rpb24oZSx0LHIpe2lmKDE9PT10aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLm1pbmltdW1Db250cmFzdFJhdGlvKXJldHVybiExO3ZhciBpPXRoaXMuX2NvbG9ycy5jb250cmFzdENhY2hlLmdldENvbG9yKHRoaXMuX3dvcmtDZWxsLmJnLHRoaXMuX3dvcmtDZWxsLmZnKTtyZXR1cm4gdm9pZCAwPT09aSYmKGk9bC5jb2xvci5lbnN1cmVDb250cmFzdFJhdGlvKHQscix0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLm1pbmltdW1Db250cmFzdFJhdGlvKSx0aGlzLl9jb2xvcnMuY29udHJhc3RDYWNoZS5zZXRDb2xvcih0aGlzLl93b3JrQ2VsbC5iZyx0aGlzLl93b3JrQ2VsbC5mZyxudWxsIT1pP2k6bnVsbCkpLCEhaSYmKHRoaXMuX2FkZFN0eWxlKGUsImNvbG9yOiIraS5jc3MpLCEwKX0sZS5wcm90b3R5cGUuX2FkZFN0eWxlPWZ1bmN0aW9uKGUsdCl7ZS5zZXRBdHRyaWJ1dGUoInN0eWxlIiwiIisoZS5nZXRBdHRyaWJ1dGUoInN0eWxlIil8fCIiKSt0KyI7Iil9LGkoW24oMix1LklDaGFyYWN0ZXJKb2luZXJTZXJ2aWNlKSxuKDMsYy5JT3B0aW9uc1NlcnZpY2UpLG4oNCxjLklDb3JlU2VydmljZSldLGUpfSgpO2Z1bmN0aW9uIF8oZSx0LHIpe2Zvcig7ZS5sZW5ndGg8cjspZT10K2U7cmV0dXJuIGV9dC5Eb21SZW5kZXJlclJvd0ZhY3Rvcnk9Zn0sNDU2OihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuU2VsZWN0aW9uTW9kZWw9dm9pZCAwO3ZhciByPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLl9idWZmZXJTZXJ2aWNlPWUsdGhpcy5pc1NlbGVjdEFsbEFjdGl2ZT0hMSx0aGlzLnNlbGVjdGlvblN0YXJ0TGVuZ3RoPTB9cmV0dXJuIGUucHJvdG90eXBlLmNsZWFyU2VsZWN0aW9uPWZ1bmN0aW9uKCl7dGhpcy5zZWxlY3Rpb25TdGFydD12b2lkIDAsdGhpcy5zZWxlY3Rpb25FbmQ9dm9pZCAwLHRoaXMuaXNTZWxlY3RBbGxBY3RpdmU9ITEsdGhpcy5zZWxlY3Rpb25TdGFydExlbmd0aD0wfSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImZpbmFsU2VsZWN0aW9uU3RhcnQiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5pc1NlbGVjdEFsbEFjdGl2ZT9bMCwwXTp0aGlzLnNlbGVjdGlvbkVuZCYmdGhpcy5zZWxlY3Rpb25TdGFydCYmdGhpcy5hcmVTZWxlY3Rpb25WYWx1ZXNSZXZlcnNlZCgpP3RoaXMuc2VsZWN0aW9uRW5kOnRoaXMuc2VsZWN0aW9uU3RhcnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJmaW5hbFNlbGVjdGlvbkVuZCIse2dldDpmdW5jdGlvbigpe2lmKHRoaXMuaXNTZWxlY3RBbGxBY3RpdmUpcmV0dXJuW3RoaXMuX2J1ZmZlclNlcnZpY2UuY29scyx0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55YmFzZSt0aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MtMV07aWYodGhpcy5zZWxlY3Rpb25TdGFydCl7aWYoIXRoaXMuc2VsZWN0aW9uRW5kfHx0aGlzLmFyZVNlbGVjdGlvblZhbHVlc1JldmVyc2VkKCkpe3ZhciBlPXRoaXMuc2VsZWN0aW9uU3RhcnRbMF0rdGhpcy5zZWxlY3Rpb25TdGFydExlbmd0aDtyZXR1cm4gZT50aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHM/ZSV0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHM9PTA/W3RoaXMuX2J1ZmZlclNlcnZpY2UuY29scyx0aGlzLnNlbGVjdGlvblN0YXJ0WzFdK01hdGguZmxvb3IoZS90aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMpLTFdOltlJXRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyx0aGlzLnNlbGVjdGlvblN0YXJ0WzFdK01hdGguZmxvb3IoZS90aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMpXTpbZSx0aGlzLnNlbGVjdGlvblN0YXJ0WzFdXX1yZXR1cm4gdGhpcy5zZWxlY3Rpb25TdGFydExlbmd0aCYmdGhpcy5zZWxlY3Rpb25FbmRbMV09PT10aGlzLnNlbGVjdGlvblN0YXJ0WzFdP1tNYXRoLm1heCh0aGlzLnNlbGVjdGlvblN0YXJ0WzBdK3RoaXMuc2VsZWN0aW9uU3RhcnRMZW5ndGgsdGhpcy5zZWxlY3Rpb25FbmRbMF0pLHRoaXMuc2VsZWN0aW9uRW5kWzFdXTp0aGlzLnNlbGVjdGlvbkVuZH19LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksZS5wcm90b3R5cGUuYXJlU2VsZWN0aW9uVmFsdWVzUmV2ZXJzZWQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnNlbGVjdGlvblN0YXJ0LHQ9dGhpcy5zZWxlY3Rpb25FbmQ7cmV0dXJuISghZXx8IXQpJiYoZVsxXT50WzFdfHxlWzFdPT09dFsxXSYmZVswXT50WzBdKX0sZS5wcm90b3R5cGUub25UcmltPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnNlbGVjdGlvblN0YXJ0JiYodGhpcy5zZWxlY3Rpb25TdGFydFsxXS09ZSksdGhpcy5zZWxlY3Rpb25FbmQmJih0aGlzLnNlbGVjdGlvbkVuZFsxXS09ZSksdGhpcy5zZWxlY3Rpb25FbmQmJnRoaXMuc2VsZWN0aW9uRW5kWzFdPDA/KHRoaXMuY2xlYXJTZWxlY3Rpb24oKSwhMCk6KHRoaXMuc2VsZWN0aW9uU3RhcnQmJnRoaXMuc2VsZWN0aW9uU3RhcnRbMV08MCYmKHRoaXMuc2VsZWN0aW9uU3RhcnRbMV09MCksITEpfSxlfSgpO3QuU2VsZWN0aW9uTW9kZWw9cn0sNDI4OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaT10aGlzJiZ0aGlzLl9fZGVjb3JhdGV8fGZ1bmN0aW9uKGUsdCxyLGkpe3ZhciBuLG89YXJndW1lbnRzLmxlbmd0aCxzPW88Mz90Om51bGw9PT1pP2k9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0LHIpOmk7aWYoIm9iamVjdCI9PXR5cGVvZiBSZWZsZWN0JiYiZnVuY3Rpb24iPT10eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSlzPVJlZmxlY3QuZGVjb3JhdGUoZSx0LHIsaSk7ZWxzZSBmb3IodmFyIGE9ZS5sZW5ndGgtMTthPj0wO2EtLSkobj1lW2FdKSYmKHM9KG88Mz9uKHMpOm8+Mz9uKHQscixzKTpuKHQscikpfHxzKTtyZXR1cm4gbz4zJiZzJiZPYmplY3QuZGVmaW5lUHJvcGVydHkodCxyLHMpLHN9LG49dGhpcyYmdGhpcy5fX3BhcmFtfHxmdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbihyLGkpe3QocixpLGUpfX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQ2hhclNpemVTZXJ2aWNlPXZvaWQgMDt2YXIgbz1yKDI1ODUpLHM9cig4NDYwKSxhPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQscil7dGhpcy5fb3B0aW9uc1NlcnZpY2U9cix0aGlzLndpZHRoPTAsdGhpcy5oZWlnaHQ9MCx0aGlzLl9vbkNoYXJTaXplQ2hhbmdlPW5ldyBzLkV2ZW50RW1pdHRlcix0aGlzLl9tZWFzdXJlU3RyYXRlZ3k9bmV3IGMoZSx0LHRoaXMuX29wdGlvbnNTZXJ2aWNlKX1yZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJoYXNWYWxpZFNpemUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy53aWR0aD4wJiZ0aGlzLmhlaWdodD4wfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwib25DaGFyU2l6ZUNoYW5nZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vbkNoYXJTaXplQ2hhbmdlLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLm1lYXN1cmU9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLl9tZWFzdXJlU3RyYXRlZ3kubWVhc3VyZSgpO2Uud2lkdGg9PT10aGlzLndpZHRoJiZlLmhlaWdodD09PXRoaXMuaGVpZ2h0fHwodGhpcy53aWR0aD1lLndpZHRoLHRoaXMuaGVpZ2h0PWUuaGVpZ2h0LHRoaXMuX29uQ2hhclNpemVDaGFuZ2UuZmlyZSgpKX0saShbbigyLG8uSU9wdGlvbnNTZXJ2aWNlKV0sZSl9KCk7dC5DaGFyU2l6ZVNlcnZpY2U9YTt2YXIgYz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0LHIpe3RoaXMuX2RvY3VtZW50PWUsdGhpcy5fcGFyZW50RWxlbWVudD10LHRoaXMuX29wdGlvbnNTZXJ2aWNlPXIsdGhpcy5fcmVzdWx0PXt3aWR0aDowLGhlaWdodDowfSx0aGlzLl9tZWFzdXJlRWxlbWVudD10aGlzLl9kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzcGFuIiksdGhpcy5fbWVhc3VyZUVsZW1lbnQuY2xhc3NMaXN0LmFkZCgieHRlcm0tY2hhci1tZWFzdXJlLWVsZW1lbnQiKSx0aGlzLl9tZWFzdXJlRWxlbWVudC50ZXh0Q29udGVudD0iVyIsdGhpcy5fbWVhc3VyZUVsZW1lbnQuc2V0QXR0cmlidXRlKCJhcmlhLWhpZGRlbiIsInRydWUiKSx0aGlzLl9wYXJlbnRFbGVtZW50LmFwcGVuZENoaWxkKHRoaXMuX21lYXN1cmVFbGVtZW50KX1yZXR1cm4gZS5wcm90b3R5cGUubWVhc3VyZT1mdW5jdGlvbigpe3RoaXMuX21lYXN1cmVFbGVtZW50LnN0eWxlLmZvbnRGYW1pbHk9dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5mb250RmFtaWx5LHRoaXMuX21lYXN1cmVFbGVtZW50LnN0eWxlLmZvbnRTaXplPXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuZm9udFNpemUrInB4Ijt2YXIgZT10aGlzLl9tZWFzdXJlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtyZXR1cm4gMCE9PWUud2lkdGgmJjAhPT1lLmhlaWdodCYmKHRoaXMuX3Jlc3VsdC53aWR0aD1lLndpZHRoLHRoaXMuX3Jlc3VsdC5oZWlnaHQ9TWF0aC5jZWlsKGUuaGVpZ2h0KSksdGhpcy5fcmVzdWx0fSxlfSgpfSw0MjY5OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkNoYXJhY3RlckpvaW5lclNlcnZpY2U9dC5Kb2luZWRDZWxsRGF0YT12b2lkIDA7dmFyIGE9cigzNzM0KSxjPXIoNjQzKSxsPXIoNTExKSx1PXIoMjU4NSksaD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQscixpKXt2YXIgbj1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIG4uY29udGVudD0wLG4uY29tYmluZWREYXRhPSIiLG4uZmc9dC5mZyxuLmJnPXQuYmcsbi5jb21iaW5lZERhdGE9cixuLl93aWR0aD1pLG59cmV0dXJuIG4odCxlKSx0LnByb3RvdHlwZS5pc0NvbWJpbmVkPWZ1bmN0aW9uKCl7cmV0dXJuIDIwOTcxNTJ9LHQucHJvdG90eXBlLmdldFdpZHRoPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3dpZHRofSx0LnByb3RvdHlwZS5nZXRDaGFycz1mdW5jdGlvbigpe3JldHVybiB0aGlzLmNvbWJpbmVkRGF0YX0sdC5wcm90b3R5cGUuZ2V0Q29kZT1mdW5jdGlvbigpe3JldHVybiAyMDk3MTUxfSx0LnByb3RvdHlwZS5zZXRGcm9tQ2hhckRhdGE9ZnVuY3Rpb24oZSl7dGhyb3cgbmV3IEVycm9yKCJub3QgaW1wbGVtZW50ZWQiKX0sdC5wcm90b3R5cGUuZ2V0QXNDaGFyRGF0YT1mdW5jdGlvbigpe3JldHVyblt0aGlzLmZnLHRoaXMuZ2V0Q2hhcnMoKSx0aGlzLmdldFdpZHRoKCksdGhpcy5nZXRDb2RlKCldfSx0fShhLkF0dHJpYnV0ZURhdGEpO3QuSm9pbmVkQ2VsbERhdGE9aDt2YXIgZj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy5fYnVmZmVyU2VydmljZT1lLHRoaXMuX2NoYXJhY3RlckpvaW5lcnM9W10sdGhpcy5fbmV4dENoYXJhY3RlckpvaW5lcklkPTAsdGhpcy5fd29ya0NlbGw9bmV3IGwuQ2VsbERhdGF9cmV0dXJuIGUucHJvdG90eXBlLnJlZ2lzdGVyPWZ1bmN0aW9uKGUpe3ZhciB0PXtpZDp0aGlzLl9uZXh0Q2hhcmFjdGVySm9pbmVySWQrKyxoYW5kbGVyOmV9O3JldHVybiB0aGlzLl9jaGFyYWN0ZXJKb2luZXJzLnB1c2godCksdC5pZH0sZS5wcm90b3R5cGUuZGVyZWdpc3Rlcj1mdW5jdGlvbihlKXtmb3IodmFyIHQ9MDt0PHRoaXMuX2NoYXJhY3RlckpvaW5lcnMubGVuZ3RoO3QrKylpZih0aGlzLl9jaGFyYWN0ZXJKb2luZXJzW3RdLmlkPT09ZSlyZXR1cm4gdGhpcy5fY2hhcmFjdGVySm9pbmVycy5zcGxpY2UodCwxKSwhMDtyZXR1cm4hMX0sZS5wcm90b3R5cGUuZ2V0Sm9pbmVkQ2hhcmFjdGVycz1mdW5jdGlvbihlKXtpZigwPT09dGhpcy5fY2hhcmFjdGVySm9pbmVycy5sZW5ndGgpcmV0dXJuW107dmFyIHQ9dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIubGluZXMuZ2V0KGUpO2lmKCF0fHwwPT09dC5sZW5ndGgpcmV0dXJuW107Zm9yKHZhciByPVtdLGk9dC50cmFuc2xhdGVUb1N0cmluZyghMCksbj0wLG89MCxzPTAsYT10LmdldEZnKDApLGw9dC5nZXRCZygwKSx1PTA7dTx0LmdldFRyaW1tZWRMZW5ndGgoKTt1KyspaWYodC5sb2FkQ2VsbCh1LHRoaXMuX3dvcmtDZWxsKSwwIT09dGhpcy5fd29ya0NlbGwuZ2V0V2lkdGgoKSl7aWYodGhpcy5fd29ya0NlbGwuZmchPT1hfHx0aGlzLl93b3JrQ2VsbC5iZyE9PWwpe2lmKHUtbj4xKWZvcih2YXIgaD10aGlzLl9nZXRKb2luZWRSYW5nZXMoaSxzLG8sdCxuKSxmPTA7ZjxoLmxlbmd0aDtmKyspci5wdXNoKGhbZl0pO249dSxzPW8sYT10aGlzLl93b3JrQ2VsbC5mZyxsPXRoaXMuX3dvcmtDZWxsLmJnfW8rPXRoaXMuX3dvcmtDZWxsLmdldENoYXJzKCkubGVuZ3RofHxjLldISVRFU1BBQ0VfQ0VMTF9DSEFSLmxlbmd0aH1pZih0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMtbj4xKWZvcihoPXRoaXMuX2dldEpvaW5lZFJhbmdlcyhpLHMsbyx0LG4pLGY9MDtmPGgubGVuZ3RoO2YrKylyLnB1c2goaFtmXSk7cmV0dXJuIHJ9LGUucHJvdG90eXBlLl9nZXRKb2luZWRSYW5nZXM9ZnVuY3Rpb24odCxyLGksbixvKXt2YXIgcz10LnN1YnN0cmluZyhyLGkpLGE9W107dHJ5e2E9dGhpcy5fY2hhcmFjdGVySm9pbmVyc1swXS5oYW5kbGVyKHMpfWNhdGNoKGUpe2NvbnNvbGUuZXJyb3IoZSl9Zm9yKHZhciBjPTE7Yzx0aGlzLl9jaGFyYWN0ZXJKb2luZXJzLmxlbmd0aDtjKyspdHJ5e2Zvcih2YXIgbD10aGlzLl9jaGFyYWN0ZXJKb2luZXJzW2NdLmhhbmRsZXIocyksdT0wO3U8bC5sZW5ndGg7dSsrKWUuX21lcmdlUmFuZ2VzKGEsbFt1XSl9Y2F0Y2goZSl7Y29uc29sZS5lcnJvcihlKX1yZXR1cm4gdGhpcy5fc3RyaW5nUmFuZ2VzVG9DZWxsUmFuZ2VzKGEsbixvKSxhfSxlLnByb3RvdHlwZS5fc3RyaW5nUmFuZ2VzVG9DZWxsUmFuZ2VzPWZ1bmN0aW9uKGUsdCxyKXt2YXIgaT0wLG49ITEsbz0wLHM9ZVtpXTtpZihzKXtmb3IodmFyIGE9cjthPHRoaXMuX2J1ZmZlclNlcnZpY2UuY29sczthKyspe3ZhciBsPXQuZ2V0V2lkdGgoYSksdT10LmdldFN0cmluZyhhKS5sZW5ndGh8fGMuV0hJVEVTUEFDRV9DRUxMX0NIQVIubGVuZ3RoO2lmKDAhPT1sKXtpZighbiYmc1swXTw9byYmKHNbMF09YSxuPSEwKSxzWzFdPD1vKXtpZihzWzFdPWEsIShzPWVbKytpXSkpYnJlYWs7c1swXTw9bz8oc1swXT1hLG49ITApOm49ITF9bys9dX19cyYmKHNbMV09dGhpcy5fYnVmZmVyU2VydmljZS5jb2xzKX19LGUuX21lcmdlUmFuZ2VzPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPSExLGk9MDtpPGUubGVuZ3RoO2krKyl7dmFyIG49ZVtpXTtpZihyKXtpZih0WzFdPD1uWzBdKXJldHVybiBlW2ktMV1bMV09dFsxXSxlO2lmKHRbMV08PW5bMV0pcmV0dXJuIGVbaS0xXVsxXT1NYXRoLm1heCh0WzFdLG5bMV0pLGUuc3BsaWNlKGksMSksZTtlLnNwbGljZShpLDEpLGktLX1lbHNle2lmKHRbMV08PW5bMF0pcmV0dXJuIGUuc3BsaWNlKGksMCx0KSxlO2lmKHRbMV08PW5bMV0pcmV0dXJuIG5bMF09TWF0aC5taW4odFswXSxuWzBdKSxlO3RbMF08blsxXSYmKG5bMF09TWF0aC5taW4odFswXSxuWzBdKSxyPSEwKX19cmV0dXJuIHI/ZVtlLmxlbmd0aC0xXVsxXT10WzFdOmUucHVzaCh0KSxlfSxlPW8oW3MoMCx1LklCdWZmZXJTZXJ2aWNlKV0sZSl9KCk7dC5DaGFyYWN0ZXJKb2luZXJTZXJ2aWNlPWZ9LDUxMTQ6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Db3JlQnJvd3NlclNlcnZpY2U9dm9pZCAwO3ZhciByPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLl90ZXh0YXJlYT1lfXJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImlzRm9jdXNlZCIse2dldDpmdW5jdGlvbigpe3JldHVybih0aGlzLl90ZXh0YXJlYS5nZXRSb290Tm9kZT90aGlzLl90ZXh0YXJlYS5nZXRSb290Tm9kZSgpOmRvY3VtZW50KS5hY3RpdmVFbGVtZW50PT09dGhpcy5fdGV4dGFyZWEmJmRvY3VtZW50Lmhhc0ZvY3VzKCl9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksZX0oKTt0LkNvcmVCcm93c2VyU2VydmljZT1yfSw4OTM0OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaT10aGlzJiZ0aGlzLl9fZGVjb3JhdGV8fGZ1bmN0aW9uKGUsdCxyLGkpe3ZhciBuLG89YXJndW1lbnRzLmxlbmd0aCxzPW88Mz90Om51bGw9PT1pP2k9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0LHIpOmk7aWYoIm9iamVjdCI9PXR5cGVvZiBSZWZsZWN0JiYiZnVuY3Rpb24iPT10eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSlzPVJlZmxlY3QuZGVjb3JhdGUoZSx0LHIsaSk7ZWxzZSBmb3IodmFyIGE9ZS5sZW5ndGgtMTthPj0wO2EtLSkobj1lW2FdKSYmKHM9KG88Mz9uKHMpOm8+Mz9uKHQscixzKTpuKHQscikpfHxzKTtyZXR1cm4gbz4zJiZzJiZPYmplY3QuZGVmaW5lUHJvcGVydHkodCxyLHMpLHN9LG49dGhpcyYmdGhpcy5fX3BhcmFtfHxmdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbihyLGkpe3QocixpLGUpfX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuTW91c2VTZXJ2aWNlPXZvaWQgMDt2YXIgbz1yKDQ3MjUpLHM9cig5ODA2KSxhPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMuX3JlbmRlclNlcnZpY2U9ZSx0aGlzLl9jaGFyU2l6ZVNlcnZpY2U9dH1yZXR1cm4gZS5wcm90b3R5cGUuZ2V0Q29vcmRzPWZ1bmN0aW9uKGUsdCxyLGksbil7cmV0dXJuKDAscy5nZXRDb29yZHMpKGUsdCxyLGksdGhpcy5fY2hhclNpemVTZXJ2aWNlLmhhc1ZhbGlkU2l6ZSx0aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuYWN0dWFsQ2VsbFdpZHRoLHRoaXMuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucy5hY3R1YWxDZWxsSGVpZ2h0LG4pfSxlLnByb3RvdHlwZS5nZXRSYXdCeXRlQ29vcmRzPWZ1bmN0aW9uKGUsdCxyLGkpe3ZhciBuPXRoaXMuZ2V0Q29vcmRzKGUsdCxyLGkpO3JldHVybigwLHMuZ2V0UmF3Qnl0ZUNvb3Jkcykobil9LGkoW24oMCxvLklSZW5kZXJTZXJ2aWNlKSxuKDEsby5JQ2hhclNpemVTZXJ2aWNlKV0sZSl9KCk7dC5Nb3VzZVNlcnZpY2U9YX0sMzIzMDpmdW5jdGlvbihlLHQscil7dmFyIGksbj10aGlzJiZ0aGlzLl9fZXh0ZW5kc3x8KGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gaT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIHIgaW4gdClPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxyKSYmKGVbcl09dFtyXSl9LGkoZSx0KX0sZnVuY3Rpb24oZSx0KXtpZigiZnVuY3Rpb24iIT10eXBlb2YgdCYmbnVsbCE9PXQpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2xhc3MgZXh0ZW5kcyB2YWx1ZSAiK1N0cmluZyh0KSsiIGlzIG5vdCBhIGNvbnN0cnVjdG9yIG9yIG51bGwiKTtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj1lfWkoZSx0KSxlLnByb3RvdHlwZT1udWxsPT09dD9PYmplY3QuY3JlYXRlKHQpOihyLnByb3RvdHlwZT10LnByb3RvdHlwZSxuZXcgcil9KSxvPXRoaXMmJnRoaXMuX19kZWNvcmF0ZXx8ZnVuY3Rpb24oZSx0LHIsaSl7dmFyIG4sbz1hcmd1bWVudHMubGVuZ3RoLHM9bzwzP3Q6bnVsbD09PWk/aT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHQscik6aTtpZigib2JqZWN0Ij09dHlwZW9mIFJlZmxlY3QmJiJmdW5jdGlvbiI9PXR5cGVvZiBSZWZsZWN0LmRlY29yYXRlKXM9UmVmbGVjdC5kZWNvcmF0ZShlLHQscixpKTtlbHNlIGZvcih2YXIgYT1lLmxlbmd0aC0xO2E+PTA7YS0tKShuPWVbYV0pJiYocz0obzwzP24ocyk6bz4zP24odCxyLHMpOm4odCxyKSl8fHMpO3JldHVybiBvPjMmJnMmJk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LHIscyksc30scz10aGlzJiZ0aGlzLl9fcGFyYW18fGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIsaSl7dChyLGksZSl9fTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5SZW5kZXJTZXJ2aWNlPXZvaWQgMDt2YXIgYT1yKDYxOTMpLGM9cig4NDYwKSxsPXIoODQ0KSx1PXIoNTU5NiksaD1yKDM2NTYpLGY9cigyNTg1KSxfPXIoNDcyNSksZD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQscixpLG4sbyxzKXt2YXIgbD1lLmNhbGwodGhpcyl8fHRoaXM7aWYobC5fcmVuZGVyZXI9dCxsLl9yb3dDb3VudD1yLGwuX2NoYXJTaXplU2VydmljZT1vLGwuX2lzUGF1c2VkPSExLGwuX25lZWRzRnVsbFJlZnJlc2g9ITEsbC5faXNOZXh0UmVuZGVyUmVkcmF3T25seT0hMCxsLl9uZWVkc1NlbGVjdGlvblJlZnJlc2g9ITEsbC5fY2FudmFzV2lkdGg9MCxsLl9jYW52YXNIZWlnaHQ9MCxsLl9zZWxlY3Rpb25TdGF0ZT17c3RhcnQ6dm9pZCAwLGVuZDp2b2lkIDAsY29sdW1uU2VsZWN0TW9kZTohMX0sbC5fb25EaW1lbnNpb25zQ2hhbmdlPW5ldyBjLkV2ZW50RW1pdHRlcixsLl9vblJlbmRlcj1uZXcgYy5FdmVudEVtaXR0ZXIsbC5fb25SZWZyZXNoUmVxdWVzdD1uZXcgYy5FdmVudEVtaXR0ZXIsbC5yZWdpc3Rlcih7ZGlzcG9zZTpmdW5jdGlvbigpe3JldHVybiBsLl9yZW5kZXJlci5kaXNwb3NlKCl9fSksbC5fcmVuZGVyRGVib3VuY2VyPW5ldyBhLlJlbmRlckRlYm91bmNlcigoZnVuY3Rpb24oZSx0KXtyZXR1cm4gbC5fcmVuZGVyUm93cyhlLHQpfSkpLGwucmVnaXN0ZXIobC5fcmVuZGVyRGVib3VuY2VyKSxsLl9zY3JlZW5EcHJNb25pdG9yPW5ldyB1LlNjcmVlbkRwck1vbml0b3IsbC5fc2NyZWVuRHByTW9uaXRvci5zZXRMaXN0ZW5lcigoZnVuY3Rpb24oKXtyZXR1cm4gbC5vbkRldmljZVBpeGVsUmF0aW9DaGFuZ2UoKX0pKSxsLnJlZ2lzdGVyKGwuX3NjcmVlbkRwck1vbml0b3IpLGwucmVnaXN0ZXIocy5vblJlc2l6ZSgoZnVuY3Rpb24oZSl7cmV0dXJuIGwuX2Z1bGxSZWZyZXNoKCl9KSkpLGwucmVnaXN0ZXIobi5vbk9wdGlvbkNoYW5nZSgoZnVuY3Rpb24oKXtyZXR1cm4gbC5fcmVuZGVyZXIub25PcHRpb25zQ2hhbmdlZCgpfSkpKSxsLnJlZ2lzdGVyKGwuX2NoYXJTaXplU2VydmljZS5vbkNoYXJTaXplQ2hhbmdlKChmdW5jdGlvbigpe3JldHVybiBsLm9uQ2hhclNpemVDaGFuZ2VkKCl9KSkpLGwuX3JlbmRlcmVyLm9uUmVxdWVzdFJlZHJhdygoZnVuY3Rpb24oZSl7cmV0dXJuIGwucmVmcmVzaFJvd3MoZS5zdGFydCxlLmVuZCwhMCl9KSksbC5yZWdpc3RlcigoMCxoLmFkZERpc3Bvc2FibGVEb21MaXN0ZW5lcikod2luZG93LCJyZXNpemUiLChmdW5jdGlvbigpe3JldHVybiBsLm9uRGV2aWNlUGl4ZWxSYXRpb0NoYW5nZSgpfSkpKSwiSW50ZXJzZWN0aW9uT2JzZXJ2ZXIiaW4gd2luZG93KXt2YXIgZj1uZXcgSW50ZXJzZWN0aW9uT2JzZXJ2ZXIoKGZ1bmN0aW9uKGUpe3JldHVybiBsLl9vbkludGVyc2VjdGlvbkNoYW5nZShlW2UubGVuZ3RoLTFdKX0pLHt0aHJlc2hvbGQ6MH0pO2Yub2JzZXJ2ZShpKSxsLnJlZ2lzdGVyKHtkaXNwb3NlOmZ1bmN0aW9uKCl7cmV0dXJuIGYuZGlzY29ubmVjdCgpfX0pfXJldHVybiBsfXJldHVybiBuKHQsZSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvbkRpbWVuc2lvbnNDaGFuZ2UiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25EaW1lbnNpb25zQ2hhbmdlLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25SZW5kZXJlZEJ1ZmZlckNoYW5nZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vblJlbmRlci5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uUmVmcmVzaFJlcXVlc3QiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25SZWZyZXNoUmVxdWVzdC5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsImRpbWVuc2lvbnMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fcmVuZGVyZXIuZGltZW5zaW9uc30sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSx0LnByb3RvdHlwZS5fb25JbnRlcnNlY3Rpb25DaGFuZ2U9ZnVuY3Rpb24oZSl7dGhpcy5faXNQYXVzZWQ9dm9pZCAwPT09ZS5pc0ludGVyc2VjdGluZz8wPT09ZS5pbnRlcnNlY3Rpb25SYXRpbzohZS5pc0ludGVyc2VjdGluZyx0aGlzLl9pc1BhdXNlZHx8dGhpcy5fY2hhclNpemVTZXJ2aWNlLmhhc1ZhbGlkU2l6ZXx8dGhpcy5fY2hhclNpemVTZXJ2aWNlLm1lYXN1cmUoKSwhdGhpcy5faXNQYXVzZWQmJnRoaXMuX25lZWRzRnVsbFJlZnJlc2gmJih0aGlzLnJlZnJlc2hSb3dzKDAsdGhpcy5fcm93Q291bnQtMSksdGhpcy5fbmVlZHNGdWxsUmVmcmVzaD0hMSl9LHQucHJvdG90eXBlLnJlZnJlc2hSb3dzPWZ1bmN0aW9uKGUsdCxyKXt2b2lkIDA9PT1yJiYocj0hMSksdGhpcy5faXNQYXVzZWQ/dGhpcy5fbmVlZHNGdWxsUmVmcmVzaD0hMDoocnx8KHRoaXMuX2lzTmV4dFJlbmRlclJlZHJhd09ubHk9ITEpLHRoaXMuX3JlbmRlckRlYm91bmNlci5yZWZyZXNoKGUsdCx0aGlzLl9yb3dDb3VudCkpfSx0LnByb3RvdHlwZS5fcmVuZGVyUm93cz1mdW5jdGlvbihlLHQpe3RoaXMuX3JlbmRlcmVyLnJlbmRlclJvd3MoZSx0KSx0aGlzLl9uZWVkc1NlbGVjdGlvblJlZnJlc2gmJih0aGlzLl9yZW5kZXJlci5vblNlbGVjdGlvbkNoYW5nZWQodGhpcy5fc2VsZWN0aW9uU3RhdGUuc3RhcnQsdGhpcy5fc2VsZWN0aW9uU3RhdGUuZW5kLHRoaXMuX3NlbGVjdGlvblN0YXRlLmNvbHVtblNlbGVjdE1vZGUpLHRoaXMuX25lZWRzU2VsZWN0aW9uUmVmcmVzaD0hMSksdGhpcy5faXNOZXh0UmVuZGVyUmVkcmF3T25seXx8dGhpcy5fb25SZW5kZXIuZmlyZSh7c3RhcnQ6ZSxlbmQ6dH0pLHRoaXMuX2lzTmV4dFJlbmRlclJlZHJhd09ubHk9ITB9LHQucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbihlLHQpe3RoaXMuX3Jvd0NvdW50PXQsdGhpcy5fZmlyZU9uQ2FudmFzUmVzaXplKCl9LHQucHJvdG90eXBlLmNoYW5nZU9wdGlvbnM9ZnVuY3Rpb24oKXt0aGlzLl9yZW5kZXJlci5vbk9wdGlvbnNDaGFuZ2VkKCksdGhpcy5yZWZyZXNoUm93cygwLHRoaXMuX3Jvd0NvdW50LTEpLHRoaXMuX2ZpcmVPbkNhbnZhc1Jlc2l6ZSgpfSx0LnByb3RvdHlwZS5fZmlyZU9uQ2FudmFzUmVzaXplPWZ1bmN0aW9uKCl7dGhpcy5fcmVuZGVyZXIuZGltZW5zaW9ucy5jYW52YXNXaWR0aD09PXRoaXMuX2NhbnZhc1dpZHRoJiZ0aGlzLl9yZW5kZXJlci5kaW1lbnNpb25zLmNhbnZhc0hlaWdodD09PXRoaXMuX2NhbnZhc0hlaWdodHx8dGhpcy5fb25EaW1lbnNpb25zQ2hhbmdlLmZpcmUodGhpcy5fcmVuZGVyZXIuZGltZW5zaW9ucyl9LHQucHJvdG90eXBlLmRpc3Bvc2U9ZnVuY3Rpb24oKXtlLnByb3RvdHlwZS5kaXNwb3NlLmNhbGwodGhpcyl9LHQucHJvdG90eXBlLnNldFJlbmRlcmVyPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7dGhpcy5fcmVuZGVyZXIuZGlzcG9zZSgpLHRoaXMuX3JlbmRlcmVyPWUsdGhpcy5fcmVuZGVyZXIub25SZXF1ZXN0UmVkcmF3KChmdW5jdGlvbihlKXtyZXR1cm4gdC5yZWZyZXNoUm93cyhlLnN0YXJ0LGUuZW5kLCEwKX0pKSx0aGlzLl9uZWVkc1NlbGVjdGlvblJlZnJlc2g9ITAsdGhpcy5fZnVsbFJlZnJlc2goKX0sdC5wcm90b3R5cGUuX2Z1bGxSZWZyZXNoPWZ1bmN0aW9uKCl7dGhpcy5faXNQYXVzZWQ/dGhpcy5fbmVlZHNGdWxsUmVmcmVzaD0hMDp0aGlzLnJlZnJlc2hSb3dzKDAsdGhpcy5fcm93Q291bnQtMSl9LHQucHJvdG90eXBlLmNsZWFyVGV4dHVyZUF0bGFzPWZ1bmN0aW9uKCl7dmFyIGUsdDtudWxsPT09KHQ9bnVsbD09PShlPXRoaXMuX3JlbmRlcmVyKXx8dm9pZCAwPT09ZT92b2lkIDA6ZS5jbGVhclRleHR1cmVBdGxhcyl8fHZvaWQgMD09PXR8fHQuY2FsbChlKSx0aGlzLl9mdWxsUmVmcmVzaCgpfSx0LnByb3RvdHlwZS5zZXRDb2xvcnM9ZnVuY3Rpb24oZSl7dGhpcy5fcmVuZGVyZXIuc2V0Q29sb3JzKGUpLHRoaXMuX2Z1bGxSZWZyZXNoKCl9LHQucHJvdG90eXBlLm9uRGV2aWNlUGl4ZWxSYXRpb0NoYW5nZT1mdW5jdGlvbigpe3RoaXMuX2NoYXJTaXplU2VydmljZS5tZWFzdXJlKCksdGhpcy5fcmVuZGVyZXIub25EZXZpY2VQaXhlbFJhdGlvQ2hhbmdlKCksdGhpcy5yZWZyZXNoUm93cygwLHRoaXMuX3Jvd0NvdW50LTEpfSx0LnByb3RvdHlwZS5vblJlc2l6ZT1mdW5jdGlvbihlLHQpe3RoaXMuX3JlbmRlcmVyLm9uUmVzaXplKGUsdCksdGhpcy5fZnVsbFJlZnJlc2goKX0sdC5wcm90b3R5cGUub25DaGFyU2l6ZUNoYW5nZWQ9ZnVuY3Rpb24oKXt0aGlzLl9yZW5kZXJlci5vbkNoYXJTaXplQ2hhbmdlZCgpfSx0LnByb3RvdHlwZS5vbkJsdXI9ZnVuY3Rpb24oKXt0aGlzLl9yZW5kZXJlci5vbkJsdXIoKX0sdC5wcm90b3R5cGUub25Gb2N1cz1mdW5jdGlvbigpe3RoaXMuX3JlbmRlcmVyLm9uRm9jdXMoKX0sdC5wcm90b3R5cGUub25TZWxlY3Rpb25DaGFuZ2VkPWZ1bmN0aW9uKGUsdCxyKXt0aGlzLl9zZWxlY3Rpb25TdGF0ZS5zdGFydD1lLHRoaXMuX3NlbGVjdGlvblN0YXRlLmVuZD10LHRoaXMuX3NlbGVjdGlvblN0YXRlLmNvbHVtblNlbGVjdE1vZGU9cix0aGlzLl9yZW5kZXJlci5vblNlbGVjdGlvbkNoYW5nZWQoZSx0LHIpfSx0LnByb3RvdHlwZS5vbkN1cnNvck1vdmU9ZnVuY3Rpb24oKXt0aGlzLl9yZW5kZXJlci5vbkN1cnNvck1vdmUoKX0sdC5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXt0aGlzLl9yZW5kZXJlci5jbGVhcigpfSxvKFtzKDMsZi5JT3B0aW9uc1NlcnZpY2UpLHMoNCxfLklDaGFyU2l6ZVNlcnZpY2UpLHMoNSxmLklCdWZmZXJTZXJ2aWNlKV0sdCl9KGwuRGlzcG9zYWJsZSk7dC5SZW5kZXJTZXJ2aWNlPWR9LDkzMTI6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49dGhpcyYmdGhpcy5fX2V4dGVuZHN8fChpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGk9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQscikmJihlW3JdPXRbcl0pfSxpKGUsdCl9LGZ1bmN0aW9uKGUsdCl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIkNsYXNzIGV4dGVuZHMgdmFsdWUgIitTdHJpbmcodCkrIiBpcyBub3QgYSBjb25zdHJ1Y3RvciBvciBudWxsIik7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1pKGUsdCksZS5wcm90b3R5cGU9bnVsbD09PXQ/T2JqZWN0LmNyZWF0ZSh0KTooci5wcm90b3R5cGU9dC5wcm90b3R5cGUsbmV3IHIpfSksbz10aGlzJiZ0aGlzLl9fZGVjb3JhdGV8fGZ1bmN0aW9uKGUsdCxyLGkpe3ZhciBuLG89YXJndW1lbnRzLmxlbmd0aCxzPW88Mz90Om51bGw9PT1pP2k9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0LHIpOmk7aWYoIm9iamVjdCI9PXR5cGVvZiBSZWZsZWN0JiYiZnVuY3Rpb24iPT10eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSlzPVJlZmxlY3QuZGVjb3JhdGUoZSx0LHIsaSk7ZWxzZSBmb3IodmFyIGE9ZS5sZW5ndGgtMTthPj0wO2EtLSkobj1lW2FdKSYmKHM9KG88Mz9uKHMpOm8+Mz9uKHQscixzKTpuKHQscikpfHxzKTtyZXR1cm4gbz4zJiZzJiZPYmplY3QuZGVmaW5lUHJvcGVydHkodCxyLHMpLHN9LHM9dGhpcyYmdGhpcy5fX3BhcmFtfHxmdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbihyLGkpe3QocixpLGUpfX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuU2VsZWN0aW9uU2VydmljZT12b2lkIDA7dmFyIGE9cig2MTE0KSxjPXIoNDU2KSxsPXIoNTExKSx1PXIoODQ2MCksaD1yKDQ3MjUpLGY9cigyNTg1KSxfPXIoOTgwNiksZD1yKDk1MDQpLHA9cig4NDQpLHY9cig0ODQxKSxnPVN0cmluZy5mcm9tQ2hhckNvZGUoMTYwKSx5PW5ldyBSZWdFeHAoZywiZyIpLG09ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0LHIsaSxuLG8scyxhLGgpe3ZhciBmPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gZi5fZWxlbWVudD10LGYuX3NjcmVlbkVsZW1lbnQ9cixmLl9saW5raWZpZXI9aSxmLl9idWZmZXJTZXJ2aWNlPW4sZi5fY29yZVNlcnZpY2U9byxmLl9tb3VzZVNlcnZpY2U9cyxmLl9vcHRpb25zU2VydmljZT1hLGYuX3JlbmRlclNlcnZpY2U9aCxmLl9kcmFnU2Nyb2xsQW1vdW50PTAsZi5fZW5hYmxlZD0hMCxmLl93b3JrQ2VsbD1uZXcgbC5DZWxsRGF0YSxmLl9tb3VzZURvd25UaW1lU3RhbXA9MCxmLl9vbGRIYXNTZWxlY3Rpb249ITEsZi5fb2xkU2VsZWN0aW9uU3RhcnQ9dm9pZCAwLGYuX29sZFNlbGVjdGlvbkVuZD12b2lkIDAsZi5fb25MaW51eE1vdXNlU2VsZWN0aW9uPWYucmVnaXN0ZXIobmV3IHUuRXZlbnRFbWl0dGVyKSxmLl9vblJlZHJhd1JlcXVlc3Q9Zi5yZWdpc3RlcihuZXcgdS5FdmVudEVtaXR0ZXIpLGYuX29uU2VsZWN0aW9uQ2hhbmdlPWYucmVnaXN0ZXIobmV3IHUuRXZlbnRFbWl0dGVyKSxmLl9vblJlcXVlc3RTY3JvbGxMaW5lcz1mLnJlZ2lzdGVyKG5ldyB1LkV2ZW50RW1pdHRlciksZi5fbW91c2VNb3ZlTGlzdGVuZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIGYuX29uTW91c2VNb3ZlKGUpfSxmLl9tb3VzZVVwTGlzdGVuZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIGYuX29uTW91c2VVcChlKX0sZi5fY29yZVNlcnZpY2Uub25Vc2VySW5wdXQoKGZ1bmN0aW9uKCl7Zi5oYXNTZWxlY3Rpb24mJmYuY2xlYXJTZWxlY3Rpb24oKX0pKSxmLl90cmltTGlzdGVuZXI9Zi5fYnVmZmVyU2VydmljZS5idWZmZXIubGluZXMub25UcmltKChmdW5jdGlvbihlKXtyZXR1cm4gZi5fb25UcmltKGUpfSkpLGYucmVnaXN0ZXIoZi5fYnVmZmVyU2VydmljZS5idWZmZXJzLm9uQnVmZmVyQWN0aXZhdGUoKGZ1bmN0aW9uKGUpe3JldHVybiBmLl9vbkJ1ZmZlckFjdGl2YXRlKGUpfSkpKSxmLmVuYWJsZSgpLGYuX21vZGVsPW5ldyBjLlNlbGVjdGlvbk1vZGVsKGYuX2J1ZmZlclNlcnZpY2UpLGYuX2FjdGl2ZVNlbGVjdGlvbk1vZGU9MCxmfXJldHVybiBuKHQsZSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvbkxpbnV4TW91c2VTZWxlY3Rpb24iLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25MaW51eE1vdXNlU2VsZWN0aW9uLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25SZXF1ZXN0UmVkcmF3Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uUmVkcmF3UmVxdWVzdC5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uU2VsZWN0aW9uQ2hhbmdlIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uU2VsZWN0aW9uQ2hhbmdlLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25SZXF1ZXN0U2Nyb2xsTGluZXMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25SZXF1ZXN0U2Nyb2xsTGluZXMuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe3RoaXMuX3JlbW92ZU1vdXNlRG93bkxpc3RlbmVycygpfSx0LnByb3RvdHlwZS5yZXNldD1mdW5jdGlvbigpe3RoaXMuY2xlYXJTZWxlY3Rpb24oKX0sdC5wcm90b3R5cGUuZGlzYWJsZT1mdW5jdGlvbigpe3RoaXMuY2xlYXJTZWxlY3Rpb24oKSx0aGlzLl9lbmFibGVkPSExfSx0LnByb3RvdHlwZS5lbmFibGU9ZnVuY3Rpb24oKXt0aGlzLl9lbmFibGVkPSEwfSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsInNlbGVjdGlvblN0YXJ0Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX21vZGVsLmZpbmFsU2VsZWN0aW9uU3RhcnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJzZWxlY3Rpb25FbmQiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fbW9kZWwuZmluYWxTZWxlY3Rpb25FbmR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJoYXNTZWxlY3Rpb24iLHtnZXQ6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLl9tb2RlbC5maW5hbFNlbGVjdGlvblN0YXJ0LHQ9dGhpcy5fbW9kZWwuZmluYWxTZWxlY3Rpb25FbmQ7cmV0dXJuISghZXx8IXR8fGVbMF09PT10WzBdJiZlWzFdPT09dFsxXSl9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJzZWxlY3Rpb25UZXh0Iix7Z2V0OmZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5fbW9kZWwuZmluYWxTZWxlY3Rpb25TdGFydCx0PXRoaXMuX21vZGVsLmZpbmFsU2VsZWN0aW9uRW5kO2lmKCFlfHwhdClyZXR1cm4iIjt2YXIgcj10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlcixpPVtdO2lmKDM9PT10aGlzLl9hY3RpdmVTZWxlY3Rpb25Nb2RlKXtpZihlWzBdPT09dFswXSlyZXR1cm4iIjtmb3IodmFyIG49ZVsxXTtuPD10WzFdO24rKyl7dmFyIG89ci50cmFuc2xhdGVCdWZmZXJMaW5lVG9TdHJpbmcobiwhMCxlWzBdLHRbMF0pO2kucHVzaChvKX19ZWxzZXt2YXIgcz1lWzFdPT09dFsxXT90WzBdOnZvaWQgMDtmb3IoaS5wdXNoKHIudHJhbnNsYXRlQnVmZmVyTGluZVRvU3RyaW5nKGVbMV0sITAsZVswXSxzKSksbj1lWzFdKzE7bjw9dFsxXS0xO24rKyl7dmFyIGM9ci5saW5lcy5nZXQobik7bz1yLnRyYW5zbGF0ZUJ1ZmZlckxpbmVUb1N0cmluZyhuLCEwKSwobnVsbD09Yz92b2lkIDA6Yy5pc1dyYXBwZWQpP2lbaS5sZW5ndGgtMV0rPW86aS5wdXNoKG8pfWVbMV0hPT10WzFdJiYoYz1yLmxpbmVzLmdldCh0WzFdKSxvPXIudHJhbnNsYXRlQnVmZmVyTGluZVRvU3RyaW5nKHRbMV0sITAsMCx0WzBdKSxjJiZjLmlzV3JhcHBlZD9pW2kubGVuZ3RoLTFdKz1vOmkucHVzaChvKSl9cmV0dXJuIGkubWFwKChmdW5jdGlvbihlKXtyZXR1cm4gZS5yZXBsYWNlKHksIiAiKX0pKS5qb2luKGEuaXNXaW5kb3dzPyJcclxuIjoiXG4iKX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSx0LnByb3RvdHlwZS5jbGVhclNlbGVjdGlvbj1mdW5jdGlvbigpe3RoaXMuX21vZGVsLmNsZWFyU2VsZWN0aW9uKCksdGhpcy5fcmVtb3ZlTW91c2VEb3duTGlzdGVuZXJzKCksdGhpcy5yZWZyZXNoKCksdGhpcy5fb25TZWxlY3Rpb25DaGFuZ2UuZmlyZSgpfSx0LnByb3RvdHlwZS5yZWZyZXNoPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7dGhpcy5fcmVmcmVzaEFuaW1hdGlvbkZyYW1lfHwodGhpcy5fcmVmcmVzaEFuaW1hdGlvbkZyYW1lPXdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKGZ1bmN0aW9uKCl7cmV0dXJuIHQuX3JlZnJlc2goKX0pKSksYS5pc0xpbnV4JiZlJiZ0aGlzLnNlbGVjdGlvblRleHQubGVuZ3RoJiZ0aGlzLl9vbkxpbnV4TW91c2VTZWxlY3Rpb24uZmlyZSh0aGlzLnNlbGVjdGlvblRleHQpfSx0LnByb3RvdHlwZS5fcmVmcmVzaD1mdW5jdGlvbigpe3RoaXMuX3JlZnJlc2hBbmltYXRpb25GcmFtZT12b2lkIDAsdGhpcy5fb25SZWRyYXdSZXF1ZXN0LmZpcmUoe3N0YXJ0OnRoaXMuX21vZGVsLmZpbmFsU2VsZWN0aW9uU3RhcnQsZW5kOnRoaXMuX21vZGVsLmZpbmFsU2VsZWN0aW9uRW5kLGNvbHVtblNlbGVjdE1vZGU6Mz09PXRoaXMuX2FjdGl2ZVNlbGVjdGlvbk1vZGV9KX0sdC5wcm90b3R5cGUuX2lzQ2xpY2tJblNlbGVjdGlvbj1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9nZXRNb3VzZUJ1ZmZlckNvb3JkcyhlKSxyPXRoaXMuX21vZGVsLmZpbmFsU2VsZWN0aW9uU3RhcnQsaT10aGlzLl9tb2RlbC5maW5hbFNlbGVjdGlvbkVuZDtyZXR1cm4hIShyJiZpJiZ0KSYmdGhpcy5fYXJlQ29vcmRzSW5TZWxlY3Rpb24odCxyLGkpfSx0LnByb3RvdHlwZS5fYXJlQ29vcmRzSW5TZWxlY3Rpb249ZnVuY3Rpb24oZSx0LHIpe3JldHVybiBlWzFdPnRbMV0mJmVbMV08clsxXXx8dFsxXT09PXJbMV0mJmVbMV09PT10WzFdJiZlWzBdPj10WzBdJiZlWzBdPHJbMF18fHRbMV08clsxXSYmZVsxXT09PXJbMV0mJmVbMF08clswXXx8dFsxXTxyWzFdJiZlWzFdPT09dFsxXSYmZVswXT49dFswXX0sdC5wcm90b3R5cGUuX3NlbGVjdFdvcmRBdEN1cnNvcj1mdW5jdGlvbihlLHQpe3ZhciByLGksbj1udWxsPT09KGk9bnVsbD09PShyPXRoaXMuX2xpbmtpZmllci5jdXJyZW50TGluayl8fHZvaWQgMD09PXI/dm9pZCAwOnIubGluayl8fHZvaWQgMD09PWk/dm9pZCAwOmkucmFuZ2U7aWYobilyZXR1cm4gdGhpcy5fbW9kZWwuc2VsZWN0aW9uU3RhcnQ9W24uc3RhcnQueC0xLG4uc3RhcnQueS0xXSx0aGlzLl9tb2RlbC5zZWxlY3Rpb25TdGFydExlbmd0aD0oMCx2LmdldFJhbmdlTGVuZ3RoKShuLHRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyksdGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kPXZvaWQgMCwhMDt2YXIgbz10aGlzLl9nZXRNb3VzZUJ1ZmZlckNvb3JkcyhlKTtyZXR1cm4hIW8mJih0aGlzLl9zZWxlY3RXb3JkQXQobyx0KSx0aGlzLl9tb2RlbC5zZWxlY3Rpb25FbmQ9dm9pZCAwLCEwKX0sdC5wcm90b3R5cGUuc2VsZWN0QWxsPWZ1bmN0aW9uKCl7dGhpcy5fbW9kZWwuaXNTZWxlY3RBbGxBY3RpdmU9ITAsdGhpcy5yZWZyZXNoKCksdGhpcy5fb25TZWxlY3Rpb25DaGFuZ2UuZmlyZSgpfSx0LnByb3RvdHlwZS5zZWxlY3RMaW5lcz1mdW5jdGlvbihlLHQpe3RoaXMuX21vZGVsLmNsZWFyU2VsZWN0aW9uKCksZT1NYXRoLm1heChlLDApLHQ9TWF0aC5taW4odCx0aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci5saW5lcy5sZW5ndGgtMSksdGhpcy5fbW9kZWwuc2VsZWN0aW9uU3RhcnQ9WzAsZV0sdGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kPVt0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsdF0sdGhpcy5yZWZyZXNoKCksdGhpcy5fb25TZWxlY3Rpb25DaGFuZ2UuZmlyZSgpfSx0LnByb3RvdHlwZS5fb25UcmltPWZ1bmN0aW9uKGUpe3RoaXMuX21vZGVsLm9uVHJpbShlKSYmdGhpcy5yZWZyZXNoKCl9LHQucHJvdG90eXBlLl9nZXRNb3VzZUJ1ZmZlckNvb3Jkcz1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9tb3VzZVNlcnZpY2UuZ2V0Q29vcmRzKGUsdGhpcy5fc2NyZWVuRWxlbWVudCx0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsdGhpcy5fYnVmZmVyU2VydmljZS5yb3dzLCEwKTtpZih0KXJldHVybiB0WzBdLS0sdFsxXS0tLHRbMV0rPXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnlkaXNwLHR9LHQucHJvdG90eXBlLl9nZXRNb3VzZUV2ZW50U2Nyb2xsQW1vdW50PWZ1bmN0aW9uKGUpe3ZhciB0PSgwLF8uZ2V0Q29vcmRzUmVsYXRpdmVUb0VsZW1lbnQpKGUsdGhpcy5fc2NyZWVuRWxlbWVudClbMV0scj10aGlzLl9yZW5kZXJTZXJ2aWNlLmRpbWVuc2lvbnMuY2FudmFzSGVpZ2h0O3JldHVybiB0Pj0wJiZ0PD1yPzA6KHQ+ciYmKHQtPXIpLHQ9TWF0aC5taW4oTWF0aC5tYXgodCwtNTApLDUwKSwodC89NTApL01hdGguYWJzKHQpK01hdGgucm91bmQoMTQqdCkpfSx0LnByb3RvdHlwZS5zaG91bGRGb3JjZVNlbGVjdGlvbj1mdW5jdGlvbihlKXtyZXR1cm4gYS5pc01hYz9lLmFsdEtleSYmdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5tYWNPcHRpb25DbGlja0ZvcmNlc1NlbGVjdGlvbjplLnNoaWZ0S2V5fSx0LnByb3RvdHlwZS5vbk1vdXNlRG93bj1mdW5jdGlvbihlKXtpZih0aGlzLl9tb3VzZURvd25UaW1lU3RhbXA9ZS50aW1lU3RhbXAsKDIhPT1lLmJ1dHRvbnx8IXRoaXMuaGFzU2VsZWN0aW9uKSYmMD09PWUuYnV0dG9uKXtpZighdGhpcy5fZW5hYmxlZCl7aWYoIXRoaXMuc2hvdWxkRm9yY2VTZWxlY3Rpb24oZSkpcmV0dXJuO2Uuc3RvcFByb3BhZ2F0aW9uKCl9ZS5wcmV2ZW50RGVmYXVsdCgpLHRoaXMuX2RyYWdTY3JvbGxBbW91bnQ9MCx0aGlzLl9lbmFibGVkJiZlLnNoaWZ0S2V5P3RoaXMuX29uSW5jcmVtZW50YWxDbGljayhlKToxPT09ZS5kZXRhaWw/dGhpcy5fb25TaW5nbGVDbGljayhlKToyPT09ZS5kZXRhaWw/dGhpcy5fb25Eb3VibGVDbGljayhlKTozPT09ZS5kZXRhaWwmJnRoaXMuX29uVHJpcGxlQ2xpY2soZSksdGhpcy5fYWRkTW91c2VEb3duTGlzdGVuZXJzKCksdGhpcy5yZWZyZXNoKCEwKX19LHQucHJvdG90eXBlLl9hZGRNb3VzZURvd25MaXN0ZW5lcnM9ZnVuY3Rpb24oKXt2YXIgZT10aGlzO3RoaXMuX3NjcmVlbkVsZW1lbnQub3duZXJEb2N1bWVudCYmKHRoaXMuX3NjcmVlbkVsZW1lbnQub3duZXJEb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLHRoaXMuX21vdXNlTW92ZUxpc3RlbmVyKSx0aGlzLl9zY3JlZW5FbGVtZW50Lm93bmVyRG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsdGhpcy5fbW91c2VVcExpc3RlbmVyKSksdGhpcy5fZHJhZ1Njcm9sbEludGVydmFsVGltZXI9d2luZG93LnNldEludGVydmFsKChmdW5jdGlvbigpe3JldHVybiBlLl9kcmFnU2Nyb2xsKCl9KSw1MCl9LHQucHJvdG90eXBlLl9yZW1vdmVNb3VzZURvd25MaXN0ZW5lcnM9ZnVuY3Rpb24oKXt0aGlzLl9zY3JlZW5FbGVtZW50Lm93bmVyRG9jdW1lbnQmJih0aGlzLl9zY3JlZW5FbGVtZW50Lm93bmVyRG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2Vtb3ZlIix0aGlzLl9tb3VzZU1vdmVMaXN0ZW5lciksdGhpcy5fc2NyZWVuRWxlbWVudC5vd25lckRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNldXAiLHRoaXMuX21vdXNlVXBMaXN0ZW5lcikpLGNsZWFySW50ZXJ2YWwodGhpcy5fZHJhZ1Njcm9sbEludGVydmFsVGltZXIpLHRoaXMuX2RyYWdTY3JvbGxJbnRlcnZhbFRpbWVyPXZvaWQgMH0sdC5wcm90b3R5cGUuX29uSW5jcmVtZW50YWxDbGljaz1mdW5jdGlvbihlKXt0aGlzLl9tb2RlbC5zZWxlY3Rpb25TdGFydCYmKHRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZD10aGlzLl9nZXRNb3VzZUJ1ZmZlckNvb3JkcyhlKSl9LHQucHJvdG90eXBlLl9vblNpbmdsZUNsaWNrPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0TGVuZ3RoPTAsdGhpcy5fbW9kZWwuaXNTZWxlY3RBbGxBY3RpdmU9ITEsdGhpcy5fYWN0aXZlU2VsZWN0aW9uTW9kZT10aGlzLnNob3VsZENvbHVtblNlbGVjdChlKT8zOjAsdGhpcy5fbW9kZWwuc2VsZWN0aW9uU3RhcnQ9dGhpcy5fZ2V0TW91c2VCdWZmZXJDb29yZHMoZSksdGhpcy5fbW9kZWwuc2VsZWN0aW9uU3RhcnQpe3RoaXMuX21vZGVsLnNlbGVjdGlvbkVuZD12b2lkIDA7dmFyIHQ9dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIubGluZXMuZ2V0KHRoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0WzFdKTt0JiZ0Lmxlbmd0aCE9PXRoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0WzBdJiYwPT09dC5oYXNXaWR0aCh0aGlzLl9tb2RlbC5zZWxlY3Rpb25TdGFydFswXSkmJnRoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0WzBdKyt9fSx0LnByb3RvdHlwZS5fb25Eb3VibGVDbGljaz1mdW5jdGlvbihlKXt0aGlzLl9zZWxlY3RXb3JkQXRDdXJzb3IoZSwhMCkmJih0aGlzLl9hY3RpdmVTZWxlY3Rpb25Nb2RlPTEpfSx0LnByb3RvdHlwZS5fb25UcmlwbGVDbGljaz1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9nZXRNb3VzZUJ1ZmZlckNvb3JkcyhlKTt0JiYodGhpcy5fYWN0aXZlU2VsZWN0aW9uTW9kZT0yLHRoaXMuX3NlbGVjdExpbmVBdCh0WzFdKSl9LHQucHJvdG90eXBlLnNob3VsZENvbHVtblNlbGVjdD1mdW5jdGlvbihlKXtyZXR1cm4gZS5hbHRLZXkmJiEoYS5pc01hYyYmdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5tYWNPcHRpb25DbGlja0ZvcmNlc1NlbGVjdGlvbil9LHQucHJvdG90eXBlLl9vbk1vdXNlTW92ZT1mdW5jdGlvbihlKXtpZihlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpLHRoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0KXt2YXIgdD10aGlzLl9tb2RlbC5zZWxlY3Rpb25FbmQ/W3RoaXMuX21vZGVsLnNlbGVjdGlvbkVuZFswXSx0aGlzLl9tb2RlbC5zZWxlY3Rpb25FbmRbMV1dOm51bGw7aWYodGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kPXRoaXMuX2dldE1vdXNlQnVmZmVyQ29vcmRzKGUpLHRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZCl7Mj09PXRoaXMuX2FjdGl2ZVNlbGVjdGlvbk1vZGU/dGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kWzFdPHRoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0WzFdP3RoaXMuX21vZGVsLnNlbGVjdGlvbkVuZFswXT0wOnRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZFswXT10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHM6MT09PXRoaXMuX2FjdGl2ZVNlbGVjdGlvbk1vZGUmJnRoaXMuX3NlbGVjdFRvV29yZEF0KHRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZCksdGhpcy5fZHJhZ1Njcm9sbEFtb3VudD10aGlzLl9nZXRNb3VzZUV2ZW50U2Nyb2xsQW1vdW50KGUpLDMhPT10aGlzLl9hY3RpdmVTZWxlY3Rpb25Nb2RlJiYodGhpcy5fZHJhZ1Njcm9sbEFtb3VudD4wP3RoaXMuX21vZGVsLnNlbGVjdGlvbkVuZFswXT10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHM6dGhpcy5fZHJhZ1Njcm9sbEFtb3VudDwwJiYodGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kWzBdPTApKTt2YXIgcj10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlcjtpZih0aGlzLl9tb2RlbC5zZWxlY3Rpb25FbmRbMV08ci5saW5lcy5sZW5ndGgpe3ZhciBpPXIubGluZXMuZ2V0KHRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZFsxXSk7aSYmMD09PWkuaGFzV2lkdGgodGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kWzBdKSYmdGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kWzBdKyt9dCYmdFswXT09PXRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZFswXSYmdFsxXT09PXRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZFsxXXx8dGhpcy5yZWZyZXNoKCEwKX1lbHNlIHRoaXMucmVmcmVzaCghMCl9fSx0LnByb3RvdHlwZS5fZHJhZ1Njcm9sbD1mdW5jdGlvbigpe2lmKHRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZCYmdGhpcy5fbW9kZWwuc2VsZWN0aW9uU3RhcnQmJnRoaXMuX2RyYWdTY3JvbGxBbW91bnQpe3RoaXMuX29uUmVxdWVzdFNjcm9sbExpbmVzLmZpcmUoe2Ftb3VudDp0aGlzLl9kcmFnU2Nyb2xsQW1vdW50LHN1cHByZXNzU2Nyb2xsRXZlbnQ6ITF9KTt2YXIgZT10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlcjt0aGlzLl9kcmFnU2Nyb2xsQW1vdW50PjA/KDMhPT10aGlzLl9hY3RpdmVTZWxlY3Rpb25Nb2RlJiYodGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kWzBdPXRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyksdGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kWzFdPU1hdGgubWluKGUueWRpc3ArdGhpcy5fYnVmZmVyU2VydmljZS5yb3dzLGUubGluZXMubGVuZ3RoLTEpKTooMyE9PXRoaXMuX2FjdGl2ZVNlbGVjdGlvbk1vZGUmJih0aGlzLl9tb2RlbC5zZWxlY3Rpb25FbmRbMF09MCksdGhpcy5fbW9kZWwuc2VsZWN0aW9uRW5kWzFdPWUueWRpc3ApLHRoaXMucmVmcmVzaCgpfX0sdC5wcm90b3R5cGUuX29uTW91c2VVcD1mdW5jdGlvbihlKXt2YXIgdD1lLnRpbWVTdGFtcC10aGlzLl9tb3VzZURvd25UaW1lU3RhbXA7aWYodGhpcy5fcmVtb3ZlTW91c2VEb3duTGlzdGVuZXJzKCksdGhpcy5zZWxlY3Rpb25UZXh0Lmxlbmd0aDw9MSYmdDw1MDAmJmUuYWx0S2V5JiZ0aGlzLl9vcHRpb25zU2VydmljZS5nZXRPcHRpb24oImFsdENsaWNrTW92ZXNDdXJzb3IiKSl7aWYodGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueWJhc2U9PT10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55ZGlzcCl7dmFyIHI9dGhpcy5fbW91c2VTZXJ2aWNlLmdldENvb3JkcyhlLHRoaXMuX2VsZW1lbnQsdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLHRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cywhMSk7aWYociYmdm9pZCAwIT09clswXSYmdm9pZCAwIT09clsxXSl7dmFyIGk9KDAsZC5tb3ZlVG9DZWxsU2VxdWVuY2UpKHJbMF0tMSxyWzFdLTEsdGhpcy5fYnVmZmVyU2VydmljZSx0aGlzLl9jb3JlU2VydmljZS5kZWNQcml2YXRlTW9kZXMuYXBwbGljYXRpb25DdXJzb3JLZXlzKTt0aGlzLl9jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KGksITApfX19ZWxzZSB0aGlzLl9maXJlRXZlbnRJZlNlbGVjdGlvbkNoYW5nZWQoKX0sdC5wcm90b3R5cGUuX2ZpcmVFdmVudElmU2VsZWN0aW9uQ2hhbmdlZD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuX21vZGVsLmZpbmFsU2VsZWN0aW9uU3RhcnQsdD10aGlzLl9tb2RlbC5maW5hbFNlbGVjdGlvbkVuZCxyPSEoIWV8fCF0fHxlWzBdPT09dFswXSYmZVsxXT09PXRbMV0pO3I/ZSYmdCYmKHRoaXMuX29sZFNlbGVjdGlvblN0YXJ0JiZ0aGlzLl9vbGRTZWxlY3Rpb25FbmQmJmVbMF09PT10aGlzLl9vbGRTZWxlY3Rpb25TdGFydFswXSYmZVsxXT09PXRoaXMuX29sZFNlbGVjdGlvblN0YXJ0WzFdJiZ0WzBdPT09dGhpcy5fb2xkU2VsZWN0aW9uRW5kWzBdJiZ0WzFdPT09dGhpcy5fb2xkU2VsZWN0aW9uRW5kWzFdfHx0aGlzLl9maXJlT25TZWxlY3Rpb25DaGFuZ2UoZSx0LHIpKTp0aGlzLl9vbGRIYXNTZWxlY3Rpb24mJnRoaXMuX2ZpcmVPblNlbGVjdGlvbkNoYW5nZShlLHQscil9LHQucHJvdG90eXBlLl9maXJlT25TZWxlY3Rpb25DaGFuZ2U9ZnVuY3Rpb24oZSx0LHIpe3RoaXMuX29sZFNlbGVjdGlvblN0YXJ0PWUsdGhpcy5fb2xkU2VsZWN0aW9uRW5kPXQsdGhpcy5fb2xkSGFzU2VsZWN0aW9uPXIsdGhpcy5fb25TZWxlY3Rpb25DaGFuZ2UuZmlyZSgpfSx0LnByb3RvdHlwZS5fb25CdWZmZXJBY3RpdmF0ZT1mdW5jdGlvbihlKXt2YXIgdD10aGlzO3RoaXMuY2xlYXJTZWxlY3Rpb24oKSx0aGlzLl90cmltTGlzdGVuZXIuZGlzcG9zZSgpLHRoaXMuX3RyaW1MaXN0ZW5lcj1lLmFjdGl2ZUJ1ZmZlci5saW5lcy5vblRyaW0oKGZ1bmN0aW9uKGUpe3JldHVybiB0Ll9vblRyaW0oZSl9KSl9LHQucHJvdG90eXBlLl9jb252ZXJ0Vmlld3BvcnRDb2xUb0NoYXJhY3RlckluZGV4PWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPXRbMF0saT0wO3RbMF0+PWk7aSsrKXt2YXIgbj1lLmxvYWRDZWxsKGksdGhpcy5fd29ya0NlbGwpLmdldENoYXJzKCkubGVuZ3RoOzA9PT10aGlzLl93b3JrQ2VsbC5nZXRXaWR0aCgpP3ItLTpuPjEmJnRbMF0hPT1pJiYocis9bi0xKX1yZXR1cm4gcn0sdC5wcm90b3R5cGUuc2V0U2VsZWN0aW9uPWZ1bmN0aW9uKGUsdCxyKXt0aGlzLl9tb2RlbC5jbGVhclNlbGVjdGlvbigpLHRoaXMuX3JlbW92ZU1vdXNlRG93bkxpc3RlbmVycygpLHRoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0PVtlLHRdLHRoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0TGVuZ3RoPXIsdGhpcy5yZWZyZXNoKCl9LHQucHJvdG90eXBlLnJpZ2h0Q2xpY2tTZWxlY3Q9ZnVuY3Rpb24oZSl7dGhpcy5faXNDbGlja0luU2VsZWN0aW9uKGUpfHwodGhpcy5fc2VsZWN0V29yZEF0Q3Vyc29yKGUsITEpJiZ0aGlzLnJlZnJlc2goITApLHRoaXMuX2ZpcmVFdmVudElmU2VsZWN0aW9uQ2hhbmdlZCgpKX0sdC5wcm90b3R5cGUuX2dldFdvcmRBdD1mdW5jdGlvbihlLHQscixpKXtpZih2b2lkIDA9PT1yJiYocj0hMCksdm9pZCAwPT09aSYmKGk9ITApLCEoZVswXT49dGhpcy5fYnVmZmVyU2VydmljZS5jb2xzKSl7dmFyIG49dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIsbz1uLmxpbmVzLmdldChlWzFdKTtpZihvKXt2YXIgcz1uLnRyYW5zbGF0ZUJ1ZmZlckxpbmVUb1N0cmluZyhlWzFdLCExKSxhPXRoaXMuX2NvbnZlcnRWaWV3cG9ydENvbFRvQ2hhcmFjdGVySW5kZXgobyxlKSxjPWEsbD1lWzBdLWEsdT0wLGg9MCxmPTAsXz0wO2lmKCIgIj09PXMuY2hhckF0KGEpKXtmb3IoO2E+MCYmIiAiPT09cy5jaGFyQXQoYS0xKTspYS0tO2Zvcig7YzxzLmxlbmd0aCYmIiAiPT09cy5jaGFyQXQoYysxKTspYysrfWVsc2V7dmFyIGQ9ZVswXSxwPWVbMF07MD09PW8uZ2V0V2lkdGgoZCkmJih1KyssZC0tKSwyPT09by5nZXRXaWR0aChwKSYmKGgrKyxwKyspO3ZhciB2PW8uZ2V0U3RyaW5nKHApLmxlbmd0aDtmb3Iodj4xJiYoXys9di0xLGMrPXYtMSk7ZD4wJiZhPjAmJiF0aGlzLl9pc0NoYXJXb3JkU2VwYXJhdG9yKG8ubG9hZENlbGwoZC0xLHRoaXMuX3dvcmtDZWxsKSk7KXtvLmxvYWRDZWxsKGQtMSx0aGlzLl93b3JrQ2VsbCk7dmFyIGc9dGhpcy5fd29ya0NlbGwuZ2V0Q2hhcnMoKS5sZW5ndGg7MD09PXRoaXMuX3dvcmtDZWxsLmdldFdpZHRoKCk/KHUrKyxkLS0pOmc+MSYmKGYrPWctMSxhLT1nLTEpLGEtLSxkLS19Zm9yKDtwPG8ubGVuZ3RoJiZjKzE8cy5sZW5ndGgmJiF0aGlzLl9pc0NoYXJXb3JkU2VwYXJhdG9yKG8ubG9hZENlbGwocCsxLHRoaXMuX3dvcmtDZWxsKSk7KXtvLmxvYWRDZWxsKHArMSx0aGlzLl93b3JrQ2VsbCk7dmFyIHk9dGhpcy5fd29ya0NlbGwuZ2V0Q2hhcnMoKS5sZW5ndGg7Mj09PXRoaXMuX3dvcmtDZWxsLmdldFdpZHRoKCk/KGgrKyxwKyspOnk+MSYmKF8rPXktMSxjKz15LTEpLGMrKyxwKyt9fWMrKzt2YXIgbT1hK2wtdStmLGI9TWF0aC5taW4odGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLGMtYSt1K2gtZi1fKTtpZih0fHwiIiE9PXMuc2xpY2UoYSxjKS50cmltKCkpe2lmKHImJjA9PT1tJiYzMiE9PW8uZ2V0Q29kZVBvaW50KDApKXt2YXIgUz1uLmxpbmVzLmdldChlWzFdLTEpO2lmKFMmJm8uaXNXcmFwcGVkJiYzMiE9PVMuZ2V0Q29kZVBvaW50KHRoaXMuX2J1ZmZlclNlcnZpY2UuY29scy0xKSl7dmFyIEM9dGhpcy5fZ2V0V29yZEF0KFt0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMtMSxlWzFdLTFdLCExLCEwLCExKTtpZihDKXt2YXIgdz10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMtQy5zdGFydDttLT13LGIrPXd9fX1pZihpJiZtK2I9PT10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMmJjMyIT09by5nZXRDb2RlUG9pbnQodGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLTEpKXt2YXIgTD1uLmxpbmVzLmdldChlWzFdKzEpO2lmKChudWxsPT1MP3ZvaWQgMDpMLmlzV3JhcHBlZCkmJjMyIT09TC5nZXRDb2RlUG9pbnQoMCkpe3ZhciBFPXRoaXMuX2dldFdvcmRBdChbMCxlWzFdKzFdLCExLCExLCEwKTtFJiYoYis9RS5sZW5ndGgpfX1yZXR1cm57c3RhcnQ6bSxsZW5ndGg6Yn19fX19LHQucHJvdG90eXBlLl9zZWxlY3RXb3JkQXQ9ZnVuY3Rpb24oZSx0KXt2YXIgcj10aGlzLl9nZXRXb3JkQXQoZSx0KTtpZihyKXtmb3IoO3Iuc3RhcnQ8MDspci5zdGFydCs9dGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLGVbMV0tLTt0aGlzLl9tb2RlbC5zZWxlY3Rpb25TdGFydD1bci5zdGFydCxlWzFdXSx0aGlzLl9tb2RlbC5zZWxlY3Rpb25TdGFydExlbmd0aD1yLmxlbmd0aH19LHQucHJvdG90eXBlLl9zZWxlY3RUb1dvcmRBdD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9nZXRXb3JkQXQoZSwhMCk7aWYodCl7Zm9yKHZhciByPWVbMV07dC5zdGFydDwwOyl0LnN0YXJ0Kz10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsci0tO2lmKCF0aGlzLl9tb2RlbC5hcmVTZWxlY3Rpb25WYWx1ZXNSZXZlcnNlZCgpKWZvcig7dC5zdGFydCt0Lmxlbmd0aD50aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHM7KXQubGVuZ3RoLT10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMscisrO3RoaXMuX21vZGVsLnNlbGVjdGlvbkVuZD1bdGhpcy5fbW9kZWwuYXJlU2VsZWN0aW9uVmFsdWVzUmV2ZXJzZWQoKT90LnN0YXJ0OnQuc3RhcnQrdC5sZW5ndGgscl19fSx0LnByb3RvdHlwZS5faXNDaGFyV29yZFNlcGFyYXRvcj1mdW5jdGlvbihlKXtyZXR1cm4gMCE9PWUuZ2V0V2lkdGgoKSYmdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy53b3JkU2VwYXJhdG9yLmluZGV4T2YoZS5nZXRDaGFycygpKT49MH0sdC5wcm90b3R5cGUuX3NlbGVjdExpbmVBdD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci5nZXRXcmFwcGVkUmFuZ2VGb3JMaW5lKGUpO3RoaXMuX21vZGVsLnNlbGVjdGlvblN0YXJ0PVswLHQuZmlyc3RdLHRoaXMuX21vZGVsLnNlbGVjdGlvbkVuZD1bdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLHQubGFzdF0sdGhpcy5fbW9kZWwuc2VsZWN0aW9uU3RhcnRMZW5ndGg9MH0sbyhbcygzLGYuSUJ1ZmZlclNlcnZpY2UpLHMoNCxmLklDb3JlU2VydmljZSkscyg1LGguSU1vdXNlU2VydmljZSkscyg2LGYuSU9wdGlvbnNTZXJ2aWNlKSxzKDcsaC5JUmVuZGVyU2VydmljZSldLHQpfShwLkRpc3Bvc2FibGUpO3QuU2VsZWN0aW9uU2VydmljZT1tfSw0NzI1OihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5JQ2hhcmFjdGVySm9pbmVyU2VydmljZT10LklTb3VuZFNlcnZpY2U9dC5JU2VsZWN0aW9uU2VydmljZT10LklSZW5kZXJTZXJ2aWNlPXQuSU1vdXNlU2VydmljZT10LklDb3JlQnJvd3NlclNlcnZpY2U9dC5JQ2hhclNpemVTZXJ2aWNlPXZvaWQgMDt2YXIgaT1yKDgzNDMpO3QuSUNoYXJTaXplU2VydmljZT0oMCxpLmNyZWF0ZURlY29yYXRvcikoIkNoYXJTaXplU2VydmljZSIpLHQuSUNvcmVCcm93c2VyU2VydmljZT0oMCxpLmNyZWF0ZURlY29yYXRvcikoIkNvcmVCcm93c2VyU2VydmljZSIpLHQuSU1vdXNlU2VydmljZT0oMCxpLmNyZWF0ZURlY29yYXRvcikoIk1vdXNlU2VydmljZSIpLHQuSVJlbmRlclNlcnZpY2U9KDAsaS5jcmVhdGVEZWNvcmF0b3IpKCJSZW5kZXJTZXJ2aWNlIiksdC5JU2VsZWN0aW9uU2VydmljZT0oMCxpLmNyZWF0ZURlY29yYXRvcikoIlNlbGVjdGlvblNlcnZpY2UiKSx0LklTb3VuZFNlcnZpY2U9KDAsaS5jcmVhdGVEZWNvcmF0b3IpKCJTb3VuZFNlcnZpY2UiKSx0LklDaGFyYWN0ZXJKb2luZXJTZXJ2aWNlPSgwLGkuY3JlYXRlRGVjb3JhdG9yKSgiQ2hhcmFjdGVySm9pbmVyU2VydmljZSIpfSwzNTc6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXMmJnRoaXMuX19kZWNvcmF0ZXx8ZnVuY3Rpb24oZSx0LHIsaSl7dmFyIG4sbz1hcmd1bWVudHMubGVuZ3RoLHM9bzwzP3Q6bnVsbD09PWk/aT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHQscik6aTtpZigib2JqZWN0Ij09dHlwZW9mIFJlZmxlY3QmJiJmdW5jdGlvbiI9PXR5cGVvZiBSZWZsZWN0LmRlY29yYXRlKXM9UmVmbGVjdC5kZWNvcmF0ZShlLHQscixpKTtlbHNlIGZvcih2YXIgYT1lLmxlbmd0aC0xO2E+PTA7YS0tKShuPWVbYV0pJiYocz0obzwzP24ocyk6bz4zP24odCxyLHMpOm4odCxyKSl8fHMpO3JldHVybiBvPjMmJnMmJk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LHIscyksc30sbj10aGlzJiZ0aGlzLl9fcGFyYW18fGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIsaSl7dChyLGksZSl9fTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Tb3VuZFNlcnZpY2U9dm9pZCAwO3ZhciBvPXIoMjU4NSkscz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy5fb3B0aW9uc1NlcnZpY2U9ZX1yZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsImF1ZGlvQ29udGV4dCIse2dldDpmdW5jdGlvbigpe2lmKCFlLl9hdWRpb0NvbnRleHQpe3ZhciB0PXdpbmRvdy5BdWRpb0NvbnRleHR8fHdpbmRvdy53ZWJraXRBdWRpb0NvbnRleHQ7aWYoIXQpcmV0dXJuIGNvbnNvbGUud2FybigiV2ViIEF1ZGlvIEFQSSBpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoaXMgYnJvd3Nlci4gQ29uc2lkZXIgdXBncmFkaW5nIHRvIHRoZSBsYXRlc3QgdmVyc2lvbiIpLG51bGw7ZS5fYXVkaW9Db250ZXh0PW5ldyB0fXJldHVybiBlLl9hdWRpb0NvbnRleHR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksZS5wcm90b3R5cGUucGxheUJlbGxTb3VuZD1mdW5jdGlvbigpe3ZhciB0PWUuYXVkaW9Db250ZXh0O2lmKHQpe3ZhciByPXQuY3JlYXRlQnVmZmVyU291cmNlKCk7dC5kZWNvZGVBdWRpb0RhdGEodGhpcy5fYmFzZTY0VG9BcnJheUJ1ZmZlcih0aGlzLl9yZW1vdmVNaW1lVHlwZSh0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmJlbGxTb3VuZCkpLChmdW5jdGlvbihlKXtyLmJ1ZmZlcj1lLHIuY29ubmVjdCh0LmRlc3RpbmF0aW9uKSxyLnN0YXJ0KDApfSkpfX0sZS5wcm90b3R5cGUuX2Jhc2U2NFRvQXJyYXlCdWZmZXI9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PXdpbmRvdy5hdG9iKGUpLHI9dC5sZW5ndGgsaT1uZXcgVWludDhBcnJheShyKSxuPTA7bjxyO24rKylpW25dPXQuY2hhckNvZGVBdChuKTtyZXR1cm4gaS5idWZmZXJ9LGUucHJvdG90eXBlLl9yZW1vdmVNaW1lVHlwZT1mdW5jdGlvbihlKXtyZXR1cm4gZS5zcGxpdCgiLCIpWzFdfSxlPWkoW24oMCxvLklPcHRpb25zU2VydmljZSldLGUpfSgpO3QuU291bmRTZXJ2aWNlPXN9LDYzNDk6KGUsdCxyKT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkNpcmN1bGFyTGlzdD12b2lkIDA7dmFyIGk9cig4NDYwKSxuPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLl9tYXhMZW5ndGg9ZSx0aGlzLm9uRGVsZXRlRW1pdHRlcj1uZXcgaS5FdmVudEVtaXR0ZXIsdGhpcy5vbkluc2VydEVtaXR0ZXI9bmV3IGkuRXZlbnRFbWl0dGVyLHRoaXMub25UcmltRW1pdHRlcj1uZXcgaS5FdmVudEVtaXR0ZXIsdGhpcy5fYXJyYXk9bmV3IEFycmF5KHRoaXMuX21heExlbmd0aCksdGhpcy5fc3RhcnRJbmRleD0wLHRoaXMuX2xlbmd0aD0wfXJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uRGVsZXRlIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMub25EZWxldGVFbWl0dGVyLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwib25JbnNlcnQiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5vbkluc2VydEVtaXR0ZXIuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJvblRyaW0iLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5vblRyaW1FbWl0dGVyLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwibWF4TGVuZ3RoIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX21heExlbmd0aH0sc2V0OmZ1bmN0aW9uKGUpe2lmKHRoaXMuX21heExlbmd0aCE9PWUpe2Zvcih2YXIgdD1uZXcgQXJyYXkoZSkscj0wO3I8TWF0aC5taW4oZSx0aGlzLmxlbmd0aCk7cisrKXRbcl09dGhpcy5fYXJyYXlbdGhpcy5fZ2V0Q3ljbGljSW5kZXgocildO3RoaXMuX2FycmF5PXQsdGhpcy5fbWF4TGVuZ3RoPWUsdGhpcy5fc3RhcnRJbmRleD0wfX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImxlbmd0aCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9sZW5ndGh9LHNldDpmdW5jdGlvbihlKXtpZihlPnRoaXMuX2xlbmd0aClmb3IodmFyIHQ9dGhpcy5fbGVuZ3RoO3Q8ZTt0KyspdGhpcy5fYXJyYXlbdF09dm9pZCAwO3RoaXMuX2xlbmd0aD1lfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLmdldD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fYXJyYXlbdGhpcy5fZ2V0Q3ljbGljSW5kZXgoZSldfSxlLnByb3RvdHlwZS5zZXQ9ZnVuY3Rpb24oZSx0KXt0aGlzLl9hcnJheVt0aGlzLl9nZXRDeWNsaWNJbmRleChlKV09dH0sZS5wcm90b3R5cGUucHVzaD1mdW5jdGlvbihlKXt0aGlzLl9hcnJheVt0aGlzLl9nZXRDeWNsaWNJbmRleCh0aGlzLl9sZW5ndGgpXT1lLHRoaXMuX2xlbmd0aD09PXRoaXMuX21heExlbmd0aD8odGhpcy5fc3RhcnRJbmRleD0rK3RoaXMuX3N0YXJ0SW5kZXgldGhpcy5fbWF4TGVuZ3RoLHRoaXMub25UcmltRW1pdHRlci5maXJlKDEpKTp0aGlzLl9sZW5ndGgrK30sZS5wcm90b3R5cGUucmVjeWNsZT1mdW5jdGlvbigpe2lmKHRoaXMuX2xlbmd0aCE9PXRoaXMuX21heExlbmd0aCl0aHJvdyBuZXcgRXJyb3IoIkNhbiBvbmx5IHJlY3ljbGUgd2hlbiB0aGUgYnVmZmVyIGlzIGZ1bGwiKTtyZXR1cm4gdGhpcy5fc3RhcnRJbmRleD0rK3RoaXMuX3N0YXJ0SW5kZXgldGhpcy5fbWF4TGVuZ3RoLHRoaXMub25UcmltRW1pdHRlci5maXJlKDEpLHRoaXMuX2FycmF5W3RoaXMuX2dldEN5Y2xpY0luZGV4KHRoaXMuX2xlbmd0aC0xKV19LE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwiaXNGdWxsIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2xlbmd0aD09PXRoaXMuX21heExlbmd0aH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxlLnByb3RvdHlwZS5wb3A9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fYXJyYXlbdGhpcy5fZ2V0Q3ljbGljSW5kZXgodGhpcy5fbGVuZ3RoLS0tMSldfSxlLnByb3RvdHlwZS5zcGxpY2U9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIHI9W10saT0yO2k8YXJndW1lbnRzLmxlbmd0aDtpKyspcltpLTJdPWFyZ3VtZW50c1tpXTtpZih0KXtmb3IodmFyIG49ZTtuPHRoaXMuX2xlbmd0aC10O24rKyl0aGlzLl9hcnJheVt0aGlzLl9nZXRDeWNsaWNJbmRleChuKV09dGhpcy5fYXJyYXlbdGhpcy5fZ2V0Q3ljbGljSW5kZXgobit0KV07dGhpcy5fbGVuZ3RoLT10LHRoaXMub25EZWxldGVFbWl0dGVyLmZpcmUoe2luZGV4OmUsYW1vdW50OnR9KX1mb3Iobj10aGlzLl9sZW5ndGgtMTtuPj1lO24tLSl0aGlzLl9hcnJheVt0aGlzLl9nZXRDeWNsaWNJbmRleChuK3IubGVuZ3RoKV09dGhpcy5fYXJyYXlbdGhpcy5fZ2V0Q3ljbGljSW5kZXgobildO2ZvcihuPTA7bjxyLmxlbmd0aDtuKyspdGhpcy5fYXJyYXlbdGhpcy5fZ2V0Q3ljbGljSW5kZXgoZStuKV09cltuXTtpZihyLmxlbmd0aCYmdGhpcy5vbkluc2VydEVtaXR0ZXIuZmlyZSh7aW5kZXg6ZSxhbW91bnQ6ci5sZW5ndGh9KSx0aGlzLl9sZW5ndGgrci5sZW5ndGg+dGhpcy5fbWF4TGVuZ3RoKXt2YXIgbz10aGlzLl9sZW5ndGgrci5sZW5ndGgtdGhpcy5fbWF4TGVuZ3RoO3RoaXMuX3N0YXJ0SW5kZXgrPW8sdGhpcy5fbGVuZ3RoPXRoaXMuX21heExlbmd0aCx0aGlzLm9uVHJpbUVtaXR0ZXIuZmlyZShvKX1lbHNlIHRoaXMuX2xlbmd0aCs9ci5sZW5ndGh9LGUucHJvdG90eXBlLnRyaW1TdGFydD1mdW5jdGlvbihlKXtlPnRoaXMuX2xlbmd0aCYmKGU9dGhpcy5fbGVuZ3RoKSx0aGlzLl9zdGFydEluZGV4Kz1lLHRoaXMuX2xlbmd0aC09ZSx0aGlzLm9uVHJpbUVtaXR0ZXIuZmlyZShlKX0sZS5wcm90b3R5cGUuc2hpZnRFbGVtZW50cz1mdW5jdGlvbihlLHQscil7aWYoISh0PD0wKSl7aWYoZTwwfHxlPj10aGlzLl9sZW5ndGgpdGhyb3cgbmV3IEVycm9yKCJzdGFydCBhcmd1bWVudCBvdXQgb2YgcmFuZ2UiKTtpZihlK3I8MCl0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBzaGlmdCBlbGVtZW50cyBpbiBsaXN0IGJleW9uZCBpbmRleCAwIik7aWYocj4wKXtmb3IodmFyIGk9dC0xO2k+PTA7aS0tKXRoaXMuc2V0KGUraStyLHRoaXMuZ2V0KGUraSkpO3ZhciBuPWUrdCtyLXRoaXMuX2xlbmd0aDtpZihuPjApZm9yKHRoaXMuX2xlbmd0aCs9bjt0aGlzLl9sZW5ndGg+dGhpcy5fbWF4TGVuZ3RoOyl0aGlzLl9sZW5ndGgtLSx0aGlzLl9zdGFydEluZGV4KyssdGhpcy5vblRyaW1FbWl0dGVyLmZpcmUoMSl9ZWxzZSBmb3IoaT0wO2k8dDtpKyspdGhpcy5zZXQoZStpK3IsdGhpcy5nZXQoZStpKSl9fSxlLnByb3RvdHlwZS5fZ2V0Q3ljbGljSW5kZXg9ZnVuY3Rpb24oZSl7cmV0dXJuKHRoaXMuX3N0YXJ0SW5kZXgrZSkldGhpcy5fbWF4TGVuZ3RofSxlfSgpO3QuQ2lyY3VsYXJMaXN0PW59LDE0Mzk6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5jbG9uZT12b2lkIDAsdC5jbG9uZT1mdW5jdGlvbiBlKHQscil7aWYodm9pZCAwPT09ciYmKHI9NSksIm9iamVjdCIhPXR5cGVvZiB0KXJldHVybiB0O3ZhciBpPUFycmF5LmlzQXJyYXkodCk/W106e307Zm9yKHZhciBuIGluIHQpaVtuXT1yPD0xP3Rbbl06dFtuXSYmZSh0W25dLHItMSk7cmV0dXJuIGl9fSw4OTY5OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkNvcmVUZXJtaW5hbD12b2lkIDA7dmFyIG89cig4NDQpLHM9cigyNTg1KSxhPXIoNDM0OCksYz1yKDc4NjYpLGw9cig3NDQpLHU9cig3MzAyKSxoPXIoNjk3NSksZj1yKDg0NjApLF89cigxNzUzKSxkPXIoMzczMCkscD1yKDE0ODApLHY9cig3OTk0KSxnPXIoOTI4MikseT1yKDU0MzUpLG09cig1OTgxKSxiPSExLFM9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0KXt2YXIgcj1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIHIuX29uQmluYXJ5PW5ldyBmLkV2ZW50RW1pdHRlcixyLl9vbkRhdGE9bmV3IGYuRXZlbnRFbWl0dGVyLHIuX29uTGluZUZlZWQ9bmV3IGYuRXZlbnRFbWl0dGVyLHIuX29uUmVzaXplPW5ldyBmLkV2ZW50RW1pdHRlcixyLl9vblNjcm9sbD1uZXcgZi5FdmVudEVtaXR0ZXIsci5faW5zdGFudGlhdGlvblNlcnZpY2U9bmV3IGEuSW5zdGFudGlhdGlvblNlcnZpY2Usci5vcHRpb25zU2VydmljZT1uZXcgdS5PcHRpb25zU2VydmljZSh0KSxyLl9pbnN0YW50aWF0aW9uU2VydmljZS5zZXRTZXJ2aWNlKHMuSU9wdGlvbnNTZXJ2aWNlLHIub3B0aW9uc1NlcnZpY2UpLHIuX2J1ZmZlclNlcnZpY2U9ci5yZWdpc3RlcihyLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZShsLkJ1ZmZlclNlcnZpY2UpKSxyLl9pbnN0YW50aWF0aW9uU2VydmljZS5zZXRTZXJ2aWNlKHMuSUJ1ZmZlclNlcnZpY2Usci5fYnVmZmVyU2VydmljZSksci5fbG9nU2VydmljZT1yLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZShjLkxvZ1NlcnZpY2UpLHIuX2luc3RhbnRpYXRpb25TZXJ2aWNlLnNldFNlcnZpY2Uocy5JTG9nU2VydmljZSxyLl9sb2dTZXJ2aWNlKSxyLmNvcmVTZXJ2aWNlPXIucmVnaXN0ZXIoci5faW5zdGFudGlhdGlvblNlcnZpY2UuY3JlYXRlSW5zdGFuY2UoaC5Db3JlU2VydmljZSwoZnVuY3Rpb24oKXtyZXR1cm4gci5zY3JvbGxUb0JvdHRvbSgpfSkpKSxyLl9pbnN0YW50aWF0aW9uU2VydmljZS5zZXRTZXJ2aWNlKHMuSUNvcmVTZXJ2aWNlLHIuY29yZVNlcnZpY2UpLHIuY29yZU1vdXNlU2VydmljZT1yLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZShfLkNvcmVNb3VzZVNlcnZpY2UpLHIuX2luc3RhbnRpYXRpb25TZXJ2aWNlLnNldFNlcnZpY2Uocy5JQ29yZU1vdXNlU2VydmljZSxyLmNvcmVNb3VzZVNlcnZpY2UpLHIuX2RpcnR5Um93U2VydmljZT1yLl9pbnN0YW50aWF0aW9uU2VydmljZS5jcmVhdGVJbnN0YW5jZShkLkRpcnR5Um93U2VydmljZSksci5faW5zdGFudGlhdGlvblNlcnZpY2Uuc2V0U2VydmljZShzLklEaXJ0eVJvd1NlcnZpY2Usci5fZGlydHlSb3dTZXJ2aWNlKSxyLnVuaWNvZGVTZXJ2aWNlPXIuX2luc3RhbnRpYXRpb25TZXJ2aWNlLmNyZWF0ZUluc3RhbmNlKHAuVW5pY29kZVNlcnZpY2UpLHIuX2luc3RhbnRpYXRpb25TZXJ2aWNlLnNldFNlcnZpY2Uocy5JVW5pY29kZVNlcnZpY2Usci51bmljb2RlU2VydmljZSksci5fY2hhcnNldFNlcnZpY2U9ci5faW5zdGFudGlhdGlvblNlcnZpY2UuY3JlYXRlSW5zdGFuY2Uodi5DaGFyc2V0U2VydmljZSksci5faW5zdGFudGlhdGlvblNlcnZpY2Uuc2V0U2VydmljZShzLklDaGFyc2V0U2VydmljZSxyLl9jaGFyc2V0U2VydmljZSksci5faW5wdXRIYW5kbGVyPW5ldyB5LklucHV0SGFuZGxlcihyLl9idWZmZXJTZXJ2aWNlLHIuX2NoYXJzZXRTZXJ2aWNlLHIuY29yZVNlcnZpY2Usci5fZGlydHlSb3dTZXJ2aWNlLHIuX2xvZ1NlcnZpY2Usci5vcHRpb25zU2VydmljZSxyLmNvcmVNb3VzZVNlcnZpY2Usci51bmljb2RlU2VydmljZSksci5yZWdpc3RlcigoMCxmLmZvcndhcmRFdmVudCkoci5faW5wdXRIYW5kbGVyLm9uTGluZUZlZWQsci5fb25MaW5lRmVlZCkpLHIucmVnaXN0ZXIoci5faW5wdXRIYW5kbGVyKSxyLnJlZ2lzdGVyKCgwLGYuZm9yd2FyZEV2ZW50KShyLl9idWZmZXJTZXJ2aWNlLm9uUmVzaXplLHIuX29uUmVzaXplKSksci5yZWdpc3RlcigoMCxmLmZvcndhcmRFdmVudCkoci5jb3JlU2VydmljZS5vbkRhdGEsci5fb25EYXRhKSksci5yZWdpc3RlcigoMCxmLmZvcndhcmRFdmVudCkoci5jb3JlU2VydmljZS5vbkJpbmFyeSxyLl9vbkJpbmFyeSkpLHIucmVnaXN0ZXIoci5vcHRpb25zU2VydmljZS5vbk9wdGlvbkNoYW5nZSgoZnVuY3Rpb24oZSl7cmV0dXJuIHIuX3VwZGF0ZU9wdGlvbnMoZSl9KSkpLHIucmVnaXN0ZXIoci5fYnVmZmVyU2VydmljZS5vblNjcm9sbCgoZnVuY3Rpb24oZSl7ci5fb25TY3JvbGwuZmlyZSh7cG9zaXRpb246ci5fYnVmZmVyU2VydmljZS5idWZmZXIueWRpc3Asc291cmNlOjB9KSxyLl9kaXJ0eVJvd1NlcnZpY2UubWFya1JhbmdlRGlydHkoci5fYnVmZmVyU2VydmljZS5idWZmZXIuc2Nyb2xsVG9wLHIuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnNjcm9sbEJvdHRvbSl9KSkpLHIucmVnaXN0ZXIoci5faW5wdXRIYW5kbGVyLm9uU2Nyb2xsKChmdW5jdGlvbihlKXtyLl9vblNjcm9sbC5maXJlKHtwb3NpdGlvbjpyLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci55ZGlzcCxzb3VyY2U6MH0pLHIuX2RpcnR5Um93U2VydmljZS5tYXJrUmFuZ2VEaXJ0eShyLl9idWZmZXJTZXJ2aWNlLmJ1ZmZlci5zY3JvbGxUb3Asci5fYnVmZmVyU2VydmljZS5idWZmZXIuc2Nyb2xsQm90dG9tKX0pKSksci5fd3JpdGVCdWZmZXI9bmV3IG0uV3JpdGVCdWZmZXIoKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHIuX2lucHV0SGFuZGxlci5wYXJzZShlLHQpfSkpLHJ9cmV0dXJuIG4odCxlKSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uQmluYXJ5Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uQmluYXJ5LmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25EYXRhIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uRGF0YS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uTGluZUZlZWQiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25MaW5lRmVlZC5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uUmVzaXplIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uUmVzaXplLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25TY3JvbGwiLHtnZXQ6ZnVuY3Rpb24oKXt2YXIgZT10aGlzO3JldHVybiB0aGlzLl9vblNjcm9sbEFwaXx8KHRoaXMuX29uU2Nyb2xsQXBpPW5ldyBmLkV2ZW50RW1pdHRlcix0aGlzLnJlZ2lzdGVyKHRoaXMuX29uU2Nyb2xsLmV2ZW50KChmdW5jdGlvbih0KXt2YXIgcjtudWxsPT09KHI9ZS5fb25TY3JvbGxBcGkpfHx2b2lkIDA9PT1yfHxyLmZpcmUodC5wb3NpdGlvbil9KSkpKSx0aGlzLl9vblNjcm9sbEFwaS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsImNvbHMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwicm93cyIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3N9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJidWZmZXJzIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyc30sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9wdGlvbnMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5vcHRpb25zU2VydmljZS5vcHRpb25zfSxzZXQ6ZnVuY3Rpb24oZSl7Zm9yKHZhciB0IGluIGUpdGhpcy5vcHRpb25zU2VydmljZS5vcHRpb25zW3RdPWVbdF19LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe3ZhciB0O3RoaXMuX2lzRGlzcG9zZWR8fChlLnByb3RvdHlwZS5kaXNwb3NlLmNhbGwodGhpcyksbnVsbD09PSh0PXRoaXMuX3dpbmRvd3NNb2RlKXx8dm9pZCAwPT09dHx8dC5kaXNwb3NlKCksdGhpcy5fd2luZG93c01vZGU9dm9pZCAwKX0sdC5wcm90b3R5cGUud3JpdGU9ZnVuY3Rpb24oZSx0KXt0aGlzLl93cml0ZUJ1ZmZlci53cml0ZShlLHQpfSx0LnByb3RvdHlwZS53cml0ZVN5bmM9ZnVuY3Rpb24oZSx0KXt0aGlzLl9sb2dTZXJ2aWNlLmxvZ0xldmVsPD1zLkxvZ0xldmVsRW51bS5XQVJOJiYhYiYmKHRoaXMuX2xvZ1NlcnZpY2Uud2Fybigid3JpdGVTeW5jIGlzIHVucmVsaWFibGUgYW5kIHdpbGwgYmUgcmVtb3ZlZCBzb29uLiIpLGI9ITApLHRoaXMuX3dyaXRlQnVmZmVyLndyaXRlU3luYyhlLHQpfSx0LnByb3RvdHlwZS5yZXNpemU9ZnVuY3Rpb24oZSx0KXtpc05hTihlKXx8aXNOYU4odCl8fChlPU1hdGgubWF4KGUsbC5NSU5JTVVNX0NPTFMpLHQ9TWF0aC5tYXgodCxsLk1JTklNVU1fUk9XUyksdGhpcy5fYnVmZmVyU2VydmljZS5yZXNpemUoZSx0KSl9LHQucHJvdG90eXBlLnNjcm9sbD1mdW5jdGlvbihlLHQpe3ZvaWQgMD09PXQmJih0PSExKSx0aGlzLl9idWZmZXJTZXJ2aWNlLnNjcm9sbChlLHQpfSx0LnByb3RvdHlwZS5zY3JvbGxMaW5lcz1mdW5jdGlvbihlLHQscil7dGhpcy5fYnVmZmVyU2VydmljZS5zY3JvbGxMaW5lcyhlLHQscil9LHQucHJvdG90eXBlLnNjcm9sbFBhZ2VzPWZ1bmN0aW9uKGUpe3RoaXMuX2J1ZmZlclNlcnZpY2Uuc2Nyb2xsUGFnZXMoZSl9LHQucHJvdG90eXBlLnNjcm9sbFRvVG9wPWZ1bmN0aW9uKCl7dGhpcy5fYnVmZmVyU2VydmljZS5zY3JvbGxUb1RvcCgpfSx0LnByb3RvdHlwZS5zY3JvbGxUb0JvdHRvbT1mdW5jdGlvbigpe3RoaXMuX2J1ZmZlclNlcnZpY2Uuc2Nyb2xsVG9Cb3R0b20oKX0sdC5wcm90b3R5cGUuc2Nyb2xsVG9MaW5lPWZ1bmN0aW9uKGUpe3RoaXMuX2J1ZmZlclNlcnZpY2Uuc2Nyb2xsVG9MaW5lKGUpfSx0LnByb3RvdHlwZS5yZWdpc3RlckVzY0hhbmRsZXI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5faW5wdXRIYW5kbGVyLnJlZ2lzdGVyRXNjSGFuZGxlcihlLHQpfSx0LnByb3RvdHlwZS5yZWdpc3RlckRjc0hhbmRsZXI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5faW5wdXRIYW5kbGVyLnJlZ2lzdGVyRGNzSGFuZGxlcihlLHQpfSx0LnByb3RvdHlwZS5yZWdpc3RlckNzaUhhbmRsZXI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5faW5wdXRIYW5kbGVyLnJlZ2lzdGVyQ3NpSGFuZGxlcihlLHQpfSx0LnByb3RvdHlwZS5yZWdpc3Rlck9zY0hhbmRsZXI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5faW5wdXRIYW5kbGVyLnJlZ2lzdGVyT3NjSGFuZGxlcihlLHQpfSx0LnByb3RvdHlwZS5fc2V0dXA9ZnVuY3Rpb24oKXt0aGlzLm9wdGlvbnNTZXJ2aWNlLm9wdGlvbnMud2luZG93c01vZGUmJnRoaXMuX2VuYWJsZVdpbmRvd3NNb2RlKCl9LHQucHJvdG90eXBlLnJlc2V0PWZ1bmN0aW9uKCl7dGhpcy5faW5wdXRIYW5kbGVyLnJlc2V0KCksdGhpcy5fYnVmZmVyU2VydmljZS5yZXNldCgpLHRoaXMuX2NoYXJzZXRTZXJ2aWNlLnJlc2V0KCksdGhpcy5jb3JlU2VydmljZS5yZXNldCgpLHRoaXMuY29yZU1vdXNlU2VydmljZS5yZXNldCgpfSx0LnByb3RvdHlwZS5fdXBkYXRlT3B0aW9ucz1mdW5jdGlvbihlKXt2YXIgdDtzd2l0Y2goZSl7Y2FzZSJzY3JvbGxiYWNrIjp0aGlzLmJ1ZmZlcnMucmVzaXplKHRoaXMuY29scyx0aGlzLnJvd3MpO2JyZWFrO2Nhc2Uid2luZG93c01vZGUiOnRoaXMub3B0aW9uc1NlcnZpY2Uub3B0aW9ucy53aW5kb3dzTW9kZT90aGlzLl9lbmFibGVXaW5kb3dzTW9kZSgpOihudWxsPT09KHQ9dGhpcy5fd2luZG93c01vZGUpfHx2b2lkIDA9PT10fHx0LmRpc3Bvc2UoKSx0aGlzLl93aW5kb3dzTW9kZT12b2lkIDApfX0sdC5wcm90b3R5cGUuX2VuYWJsZVdpbmRvd3NNb2RlPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcztpZighdGhpcy5fd2luZG93c01vZGUpe3ZhciB0PVtdO3QucHVzaCh0aGlzLm9uTGluZUZlZWQoZy51cGRhdGVXaW5kb3dzTW9kZVdyYXBwZWRTdGF0ZS5iaW5kKG51bGwsdGhpcy5fYnVmZmVyU2VydmljZSkpKSx0LnB1c2godGhpcy5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJIIn0sKGZ1bmN0aW9uKCl7cmV0dXJuKDAsZy51cGRhdGVXaW5kb3dzTW9kZVdyYXBwZWRTdGF0ZSkoZS5fYnVmZmVyU2VydmljZSksITF9KSkpLHRoaXMuX3dpbmRvd3NNb2RlPXtkaXNwb3NlOmZ1bmN0aW9uKCl7Zm9yKHZhciBlPTAscj10O2U8ci5sZW5ndGg7ZSsrKXJbZV0uZGlzcG9zZSgpfX19fSx0fShvLkRpc3Bvc2FibGUpO3QuQ29yZVRlcm1pbmFsPVN9LDg0NjA6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5mb3J3YXJkRXZlbnQ9dC5FdmVudEVtaXR0ZXI9dm9pZCAwO3ZhciByPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMuX2xpc3RlbmVycz1bXSx0aGlzLl9kaXNwb3NlZD0hMX1yZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJldmVudCIse2dldDpmdW5jdGlvbigpe3ZhciBlPXRoaXM7cmV0dXJuIHRoaXMuX2V2ZW50fHwodGhpcy5fZXZlbnQ9ZnVuY3Rpb24odCl7cmV0dXJuIGUuX2xpc3RlbmVycy5wdXNoKHQpLHtkaXNwb3NlOmZ1bmN0aW9uKCl7aWYoIWUuX2Rpc3Bvc2VkKWZvcih2YXIgcj0wO3I8ZS5fbGlzdGVuZXJzLmxlbmd0aDtyKyspaWYoZS5fbGlzdGVuZXJzW3JdPT09dClyZXR1cm4gdm9pZCBlLl9saXN0ZW5lcnMuc3BsaWNlKHIsMSl9fX0pLHRoaXMuX2V2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLmZpcmU9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIHI9W10saT0wO2k8dGhpcy5fbGlzdGVuZXJzLmxlbmd0aDtpKyspci5wdXNoKHRoaXMuX2xpc3RlbmVyc1tpXSk7Zm9yKGk9MDtpPHIubGVuZ3RoO2krKylyW2ldLmNhbGwodm9pZCAwLGUsdCl9LGUucHJvdG90eXBlLmRpc3Bvc2U9ZnVuY3Rpb24oKXt0aGlzLl9saXN0ZW5lcnMmJih0aGlzLl9saXN0ZW5lcnMubGVuZ3RoPTApLHRoaXMuX2Rpc3Bvc2VkPSEwfSxlfSgpO3QuRXZlbnRFbWl0dGVyPXIsdC5mb3J3YXJkRXZlbnQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSgoZnVuY3Rpb24oZSl7cmV0dXJuIHQuZmlyZShlKX0pKX19LDU0MzU6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49dGhpcyYmdGhpcy5fX2V4dGVuZHN8fChpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGk9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQscikmJihlW3JdPXRbcl0pfSxpKGUsdCl9LGZ1bmN0aW9uKGUsdCl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIkNsYXNzIGV4dGVuZHMgdmFsdWUgIitTdHJpbmcodCkrIiBpcyBub3QgYSBjb25zdHJ1Y3RvciBvciBudWxsIik7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1pKGUsdCksZS5wcm90b3R5cGU9bnVsbD09PXQ/T2JqZWN0LmNyZWF0ZSh0KTooci5wcm90b3R5cGU9dC5wcm90b3R5cGUsbmV3IHIpfSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuSW5wdXRIYW5kbGVyPXQuV2luZG93c09wdGlvbnNSZXBvcnRUeXBlPXZvaWQgMDt2YXIgbyxzPXIoMjU4NCksYT1yKDcxMTYpLGM9cigyMDE1KSxsPXIoODQ0KSx1PXIoODI3MyksaD1yKDQ4MiksZj1yKDg0MzcpLF89cig4NDYwKSxkPXIoNjQzKSxwPXIoNTExKSx2PXIoMzczNCksZz1yKDI1ODUpLHk9cig2MjQyKSxtPXIoNjM1MSksYj1yKDU5NDEpLFM9eyIoIjowLCIpIjoxLCIqIjoyLCIrIjozLCItIjoxLCIuIjoyfSxDPTEzMTA3MjtmdW5jdGlvbiB3KGUsdCl7aWYoZT4yNClyZXR1cm4gdC5zZXRXaW5MaW5lc3x8ITE7c3dpdGNoKGUpe2Nhc2UgMTpyZXR1cm4hIXQucmVzdG9yZVdpbjtjYXNlIDI6cmV0dXJuISF0Lm1pbmltaXplV2luO2Nhc2UgMzpyZXR1cm4hIXQuc2V0V2luUG9zaXRpb247Y2FzZSA0OnJldHVybiEhdC5zZXRXaW5TaXplUGl4ZWxzO2Nhc2UgNTpyZXR1cm4hIXQucmFpc2VXaW47Y2FzZSA2OnJldHVybiEhdC5sb3dlcldpbjtjYXNlIDc6cmV0dXJuISF0LnJlZnJlc2hXaW47Y2FzZSA4OnJldHVybiEhdC5zZXRXaW5TaXplQ2hhcnM7Y2FzZSA5OnJldHVybiEhdC5tYXhpbWl6ZVdpbjtjYXNlIDEwOnJldHVybiEhdC5mdWxsc2NyZWVuV2luO2Nhc2UgMTE6cmV0dXJuISF0LmdldFdpblN0YXRlO2Nhc2UgMTM6cmV0dXJuISF0LmdldFdpblBvc2l0aW9uO2Nhc2UgMTQ6cmV0dXJuISF0LmdldFdpblNpemVQaXhlbHM7Y2FzZSAxNTpyZXR1cm4hIXQuZ2V0U2NyZWVuU2l6ZVBpeGVscztjYXNlIDE2OnJldHVybiEhdC5nZXRDZWxsU2l6ZVBpeGVscztjYXNlIDE4OnJldHVybiEhdC5nZXRXaW5TaXplQ2hhcnM7Y2FzZSAxOTpyZXR1cm4hIXQuZ2V0U2NyZWVuU2l6ZUNoYXJzO2Nhc2UgMjA6cmV0dXJuISF0LmdldEljb25UaXRsZTtjYXNlIDIxOnJldHVybiEhdC5nZXRXaW5UaXRsZTtjYXNlIDIyOnJldHVybiEhdC5wdXNoVGl0bGU7Y2FzZSAyMzpyZXR1cm4hIXQucG9wVGl0bGU7Y2FzZSAyNDpyZXR1cm4hIXQuc2V0V2luTGluZXN9cmV0dXJuITF9IWZ1bmN0aW9uKGUpe2VbZS5HRVRfV0lOX1NJWkVfUElYRUxTPTBdPSJHRVRfV0lOX1NJWkVfUElYRUxTIixlW2UuR0VUX0NFTExfU0laRV9QSVhFTFM9MV09IkdFVF9DRUxMX1NJWkVfUElYRUxTIn0obz10LldpbmRvd3NPcHRpb25zUmVwb3J0VHlwZXx8KHQuV2luZG93c09wdGlvbnNSZXBvcnRUeXBlPXt9KSk7dmFyIEw9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxyLGkpe3RoaXMuX2J1ZmZlclNlcnZpY2U9ZSx0aGlzLl9jb3JlU2VydmljZT10LHRoaXMuX2xvZ1NlcnZpY2U9cix0aGlzLl9vcHRpb25zU2VydmljZT1pLHRoaXMuX2RhdGE9bmV3IFVpbnQzMkFycmF5KDApfXJldHVybiBlLnByb3RvdHlwZS5ob29rPWZ1bmN0aW9uKGUpe3RoaXMuX2RhdGE9bmV3IFVpbnQzMkFycmF5KDApfSxlLnByb3RvdHlwZS5wdXQ9ZnVuY3Rpb24oZSx0LHIpe3RoaXMuX2RhdGE9KDAsdS5jb25jYXQpKHRoaXMuX2RhdGEsZS5zdWJhcnJheSh0LHIpKX0sZS5wcm90b3R5cGUudW5ob29rPWZ1bmN0aW9uKGUpe2lmKCFlKXJldHVybiB0aGlzLl9kYXRhPW5ldyBVaW50MzJBcnJheSgwKSwhMDt2YXIgdD0oMCxoLnV0ZjMyVG9TdHJpbmcpKHRoaXMuX2RhdGEpO3N3aXRjaCh0aGlzLl9kYXRhPW5ldyBVaW50MzJBcnJheSgwKSx0KXtjYXNlJyJxJzp0aGlzLl9jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KHMuQzAuRVNDKydQMSRyMCJxJytzLkMwLkVTQysiXFwiKTticmVhaztjYXNlJyJwJzp0aGlzLl9jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KHMuQzAuRVNDKydQMSRyNjE7MSJwJytzLkMwLkVTQysiXFwiKTticmVhaztjYXNlInIiOnZhciByPXRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLnNjcm9sbFRvcCsxKyI7IisodGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIuc2Nyb2xsQm90dG9tKzEpKyJyIjt0aGlzLl9jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KHMuQzAuRVNDKyJQMSRyIityK3MuQzAuRVNDKyJcXCIpO2JyZWFrO2Nhc2UibSI6dGhpcy5fY29yZVNlcnZpY2UudHJpZ2dlckRhdGFFdmVudChzLkMwLkVTQysiUDEkcjBtIitzLkMwLkVTQysiXFwiKTticmVhaztjYXNlIiBxIjp2YXIgaT17YmxvY2s6Mix1bmRlcmxpbmU6NCxiYXI6Nn1bdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5jdXJzb3JTdHlsZV07aS09dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5jdXJzb3JCbGluaz8xOjAsdGhpcy5fY29yZVNlcnZpY2UudHJpZ2dlckRhdGFFdmVudChzLkMwLkVTQysiUDEkciIraSsiIHEiK3MuQzAuRVNDKyJcXCIpO2JyZWFrO2RlZmF1bHQ6dGhpcy5fbG9nU2VydmljZS5kZWJ1ZygiVW5rbm93biBEQ1MgJHEgJXMiLHQpLHRoaXMuX2NvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQocy5DMC5FU0MrIlAwJHIiK3MuQzAuRVNDKyJcXCIpfXJldHVybiEwfSxlfSgpLEU9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0LHIsaSxuLG8sbCx1LGQsdil7dm9pZCAwPT09diYmKHY9bmV3IGMuRXNjYXBlU2VxdWVuY2VQYXJzZXIpO3ZhciBnPWUuY2FsbCh0aGlzKXx8dGhpcztnLl9idWZmZXJTZXJ2aWNlPXQsZy5fY2hhcnNldFNlcnZpY2U9cixnLl9jb3JlU2VydmljZT1pLGcuX2RpcnR5Um93U2VydmljZT1uLGcuX2xvZ1NlcnZpY2U9byxnLl9vcHRpb25zU2VydmljZT1sLGcuX2NvcmVNb3VzZVNlcnZpY2U9dSxnLl91bmljb2RlU2VydmljZT1kLGcuX3BhcnNlcj12LGcuX3BhcnNlQnVmZmVyPW5ldyBVaW50MzJBcnJheSg0MDk2KSxnLl9zdHJpbmdEZWNvZGVyPW5ldyBoLlN0cmluZ1RvVXRmMzIsZy5fdXRmOERlY29kZXI9bmV3IGguVXRmOFRvVXRmMzIsZy5fd29ya0NlbGw9bmV3IHAuQ2VsbERhdGEsZy5fd2luZG93VGl0bGU9IiIsZy5faWNvbk5hbWU9IiIsZy5fd2luZG93VGl0bGVTdGFjaz1bXSxnLl9pY29uTmFtZVN0YWNrPVtdLGcuX2N1ckF0dHJEYXRhPWYuREVGQVVMVF9BVFRSX0RBVEEuY2xvbmUoKSxnLl9lcmFzZUF0dHJEYXRhSW50ZXJuYWw9Zi5ERUZBVUxUX0FUVFJfREFUQS5jbG9uZSgpLGcuX29uUmVxdWVzdEJlbGw9bmV3IF8uRXZlbnRFbWl0dGVyLGcuX29uUmVxdWVzdFJlZnJlc2hSb3dzPW5ldyBfLkV2ZW50RW1pdHRlcixnLl9vblJlcXVlc3RSZXNldD1uZXcgXy5FdmVudEVtaXR0ZXIsZy5fb25SZXF1ZXN0U2VuZEZvY3VzPW5ldyBfLkV2ZW50RW1pdHRlcixnLl9vblJlcXVlc3RTeW5jU2Nyb2xsQmFyPW5ldyBfLkV2ZW50RW1pdHRlcixnLl9vblJlcXVlc3RXaW5kb3dzT3B0aW9uc1JlcG9ydD1uZXcgXy5FdmVudEVtaXR0ZXIsZy5fb25BMTF5Q2hhcj1uZXcgXy5FdmVudEVtaXR0ZXIsZy5fb25BMTF5VGFiPW5ldyBfLkV2ZW50RW1pdHRlcixnLl9vbkN1cnNvck1vdmU9bmV3IF8uRXZlbnRFbWl0dGVyLGcuX29uTGluZUZlZWQ9bmV3IF8uRXZlbnRFbWl0dGVyLGcuX29uU2Nyb2xsPW5ldyBfLkV2ZW50RW1pdHRlcixnLl9vblRpdGxlQ2hhbmdlPW5ldyBfLkV2ZW50RW1pdHRlcixnLl9vbkNvbG9yPW5ldyBfLkV2ZW50RW1pdHRlcixnLl9wYXJzZVN0YWNrPXtwYXVzZWQ6ITEsY3Vyc29yU3RhcnRYOjAsY3Vyc29yU3RhcnRZOjAsZGVjb2RlZExlbmd0aDowLHBvc2l0aW9uOjB9LGcuX3NwZWNpYWxDb2xvcnM9WzI1NiwyNTcsMjU4XSxnLnJlZ2lzdGVyKGcuX3BhcnNlciksZy5fYWN0aXZlQnVmZmVyPWcuX2J1ZmZlclNlcnZpY2UuYnVmZmVyLGcucmVnaXN0ZXIoZy5fYnVmZmVyU2VydmljZS5idWZmZXJzLm9uQnVmZmVyQWN0aXZhdGUoKGZ1bmN0aW9uKGUpe3JldHVybiBnLl9hY3RpdmVCdWZmZXI9ZS5hY3RpdmVCdWZmZXJ9KSkpLGcuX3BhcnNlci5zZXRDc2lIYW5kbGVyRmFsbGJhY2soKGZ1bmN0aW9uKGUsdCl7Zy5fbG9nU2VydmljZS5kZWJ1ZygiVW5rbm93biBDU0kgY29kZTogIix7aWRlbnRpZmllcjpnLl9wYXJzZXIuaWRlbnRUb1N0cmluZyhlKSxwYXJhbXM6dC50b0FycmF5KCl9KX0pKSxnLl9wYXJzZXIuc2V0RXNjSGFuZGxlckZhbGxiYWNrKChmdW5jdGlvbihlKXtnLl9sb2dTZXJ2aWNlLmRlYnVnKCJVbmtub3duIEVTQyBjb2RlOiAiLHtpZGVudGlmaWVyOmcuX3BhcnNlci5pZGVudFRvU3RyaW5nKGUpfSl9KSksZy5fcGFyc2VyLnNldEV4ZWN1dGVIYW5kbGVyRmFsbGJhY2soKGZ1bmN0aW9uKGUpe2cuX2xvZ1NlcnZpY2UuZGVidWcoIlVua25vd24gRVhFQ1VURSBjb2RlOiAiLHtjb2RlOmV9KX0pKSxnLl9wYXJzZXIuc2V0T3NjSGFuZGxlckZhbGxiYWNrKChmdW5jdGlvbihlLHQscil7Zy5fbG9nU2VydmljZS5kZWJ1ZygiVW5rbm93biBPU0MgY29kZTogIix7aWRlbnRpZmllcjplLGFjdGlvbjp0LGRhdGE6cn0pfSkpLGcuX3BhcnNlci5zZXREY3NIYW5kbGVyRmFsbGJhY2soKGZ1bmN0aW9uKGUsdCxyKXsiSE9PSyI9PT10JiYocj1yLnRvQXJyYXkoKSksZy5fbG9nU2VydmljZS5kZWJ1ZygiVW5rbm93biBEQ1MgY29kZTogIix7aWRlbnRpZmllcjpnLl9wYXJzZXIuaWRlbnRUb1N0cmluZyhlKSxhY3Rpb246dCxwYXlsb2FkOnJ9KX0pKSxnLl9wYXJzZXIuc2V0UHJpbnRIYW5kbGVyKChmdW5jdGlvbihlLHQscil7cmV0dXJuIGcucHJpbnQoZSx0LHIpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJAIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmluc2VydENoYXJzKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ludGVybWVkaWF0ZXM6IiAiLGZpbmFsOiJAIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNjcm9sbExlZnQoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7ZmluYWw6IkEifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcuY3Vyc29yVXAoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiICIsZmluYWw6IkEifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcuc2Nyb2xsUmlnaHQoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7ZmluYWw6IkIifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcuY3Vyc29yRG93bihlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtmaW5hbDoiQyJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5jdXJzb3JGb3J3YXJkKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJEIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmN1cnNvckJhY2t3YXJkKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJFIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmN1cnNvck5leHRMaW5lKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJGIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmN1cnNvclByZWNlZGluZ0xpbmUoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7ZmluYWw6IkcifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcuY3Vyc29yQ2hhckFic29sdXRlKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJIIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmN1cnNvclBvc2l0aW9uKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJJIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmN1cnNvckZvcndhcmRUYWIoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7ZmluYWw6IkoifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcuZXJhc2VJbkRpc3BsYXkoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7cHJlZml4OiI/IixmaW5hbDoiSiJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5lcmFzZUluRGlzcGxheShlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtmaW5hbDoiSyJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5lcmFzZUluTGluZShlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtwcmVmaXg6Ij8iLGZpbmFsOiJLIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmVyYXNlSW5MaW5lKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJMIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmluc2VydExpbmVzKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJNIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmRlbGV0ZUxpbmVzKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJQIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmRlbGV0ZUNoYXJzKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJTIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNjcm9sbFVwKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJUIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNjcm9sbERvd24oZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7ZmluYWw6IlgifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcuZXJhc2VDaGFycyhlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtmaW5hbDoiWiJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5jdXJzb3JCYWNrd2FyZFRhYihlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtmaW5hbDoiYCJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5jaGFyUG9zQWJzb2x1dGUoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7ZmluYWw6ImEifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcuaFBvc2l0aW9uUmVsYXRpdmUoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7ZmluYWw6ImIifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcucmVwZWF0UHJlY2VkaW5nQ2hhcmFjdGVyKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJjIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNlbmREZXZpY2VBdHRyaWJ1dGVzUHJpbWFyeShlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtwcmVmaXg6Ij4iLGZpbmFsOiJjIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNlbmREZXZpY2VBdHRyaWJ1dGVzU2Vjb25kYXJ5KGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJkIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmxpbmVQb3NBYnNvbHV0ZShlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtmaW5hbDoiZSJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy52UG9zaXRpb25SZWxhdGl2ZShlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtmaW5hbDoiZiJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5oVlBvc2l0aW9uKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJnIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnRhYkNsZWFyKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJoIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNldE1vZGUoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7cHJlZml4OiI/IixmaW5hbDoiaCJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5zZXRNb2RlUHJpdmF0ZShlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtmaW5hbDoibCJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5yZXNldE1vZGUoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7cHJlZml4OiI/IixmaW5hbDoibCJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5yZXNldE1vZGVQcml2YXRlKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJtIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmNoYXJBdHRyaWJ1dGVzKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJuIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmRldmljZVN0YXR1cyhlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtwcmVmaXg6Ij8iLGZpbmFsOiJuIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmRldmljZVN0YXR1c1ByaXZhdGUoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiISIsZmluYWw6InAifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcuc29mdFJlc2V0KGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ludGVybWVkaWF0ZXM6IiAiLGZpbmFsOiJxIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNldEN1cnNvclN0eWxlKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJyIn0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNldFNjcm9sbFJlZ2lvbihlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtmaW5hbDoicyJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5zYXZlQ3Vyc29yKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ZpbmFsOiJ0In0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLndpbmRvd09wdGlvbnMoZSl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyQ3NpSGFuZGxlcih7ZmluYWw6InUifSwoZnVuY3Rpb24oZSl7cmV0dXJuIGcucmVzdG9yZUN1cnNvcihlKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKHtpbnRlcm1lZGlhdGVzOiInIixmaW5hbDoifSJ9LChmdW5jdGlvbihlKXtyZXR1cm4gZy5pbnNlcnRDb2x1bW5zKGUpfSkpLGcuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoe2ludGVybWVkaWF0ZXM6IiciLGZpbmFsOiJ+In0sKGZ1bmN0aW9uKGUpe3JldHVybiBnLmRlbGV0ZUNvbHVtbnMoZSl9KSksZy5fcGFyc2VyLnNldEV4ZWN1dGVIYW5kbGVyKHMuQzAuQkVMLChmdW5jdGlvbigpe3JldHVybiBnLmJlbGwoKX0pKSxnLl9wYXJzZXIuc2V0RXhlY3V0ZUhhbmRsZXIocy5DMC5MRiwoZnVuY3Rpb24oKXtyZXR1cm4gZy5saW5lRmVlZCgpfSkpLGcuX3BhcnNlci5zZXRFeGVjdXRlSGFuZGxlcihzLkMwLlZULChmdW5jdGlvbigpe3JldHVybiBnLmxpbmVGZWVkKCl9KSksZy5fcGFyc2VyLnNldEV4ZWN1dGVIYW5kbGVyKHMuQzAuRkYsKGZ1bmN0aW9uKCl7cmV0dXJuIGcubGluZUZlZWQoKX0pKSxnLl9wYXJzZXIuc2V0RXhlY3V0ZUhhbmRsZXIocy5DMC5DUiwoZnVuY3Rpb24oKXtyZXR1cm4gZy5jYXJyaWFnZVJldHVybigpfSkpLGcuX3BhcnNlci5zZXRFeGVjdXRlSGFuZGxlcihzLkMwLkJTLChmdW5jdGlvbigpe3JldHVybiBnLmJhY2tzcGFjZSgpfSkpLGcuX3BhcnNlci5zZXRFeGVjdXRlSGFuZGxlcihzLkMwLkhULChmdW5jdGlvbigpe3JldHVybiBnLnRhYigpfSkpLGcuX3BhcnNlci5zZXRFeGVjdXRlSGFuZGxlcihzLkMwLlNPLChmdW5jdGlvbigpe3JldHVybiBnLnNoaWZ0T3V0KCl9KSksZy5fcGFyc2VyLnNldEV4ZWN1dGVIYW5kbGVyKHMuQzAuU0ksKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2hpZnRJbigpfSkpLGcuX3BhcnNlci5zZXRFeGVjdXRlSGFuZGxlcihzLkMxLklORCwoZnVuY3Rpb24oKXtyZXR1cm4gZy5pbmRleCgpfSkpLGcuX3BhcnNlci5zZXRFeGVjdXRlSGFuZGxlcihzLkMxLk5FTCwoZnVuY3Rpb24oKXtyZXR1cm4gZy5uZXh0TGluZSgpfSkpLGcuX3BhcnNlci5zZXRFeGVjdXRlSGFuZGxlcihzLkMxLkhUUywoZnVuY3Rpb24oKXtyZXR1cm4gZy50YWJTZXQoKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJPc2NIYW5kbGVyKDAsbmV3IHkuT3NjSGFuZGxlcigoZnVuY3Rpb24oZSl7cmV0dXJuIGcuc2V0VGl0bGUoZSksZy5zZXRJY29uTmFtZShlKSwhMH0pKSksZy5fcGFyc2VyLnJlZ2lzdGVyT3NjSGFuZGxlcigxLG5ldyB5Lk9zY0hhbmRsZXIoKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNldEljb25OYW1lKGUpfSkpKSxnLl9wYXJzZXIucmVnaXN0ZXJPc2NIYW5kbGVyKDIsbmV3IHkuT3NjSGFuZGxlcigoZnVuY3Rpb24oZSl7cmV0dXJuIGcuc2V0VGl0bGUoZSl9KSkpLGcuX3BhcnNlci5yZWdpc3Rlck9zY0hhbmRsZXIoNCxuZXcgeS5Pc2NIYW5kbGVyKChmdW5jdGlvbihlKXtyZXR1cm4gZy5zZXRPclJlcG9ydEluZGV4ZWRDb2xvcihlKX0pKSksZy5fcGFyc2VyLnJlZ2lzdGVyT3NjSGFuZGxlcigxMCxuZXcgeS5Pc2NIYW5kbGVyKChmdW5jdGlvbihlKXtyZXR1cm4gZy5zZXRPclJlcG9ydEZnQ29sb3IoZSl9KSkpLGcuX3BhcnNlci5yZWdpc3Rlck9zY0hhbmRsZXIoMTEsbmV3IHkuT3NjSGFuZGxlcigoZnVuY3Rpb24oZSl7cmV0dXJuIGcuc2V0T3JSZXBvcnRCZ0NvbG9yKGUpfSkpKSxnLl9wYXJzZXIucmVnaXN0ZXJPc2NIYW5kbGVyKDEyLG5ldyB5Lk9zY0hhbmRsZXIoKGZ1bmN0aW9uKGUpe3JldHVybiBnLnNldE9yUmVwb3J0Q3Vyc29yQ29sb3IoZSl9KSkpLGcuX3BhcnNlci5yZWdpc3Rlck9zY0hhbmRsZXIoMTA0LG5ldyB5Lk9zY0hhbmRsZXIoKGZ1bmN0aW9uKGUpe3JldHVybiBnLnJlc3RvcmVJbmRleGVkQ29sb3IoZSl9KSkpLGcuX3BhcnNlci5yZWdpc3Rlck9zY0hhbmRsZXIoMTEwLG5ldyB5Lk9zY0hhbmRsZXIoKGZ1bmN0aW9uKGUpe3JldHVybiBnLnJlc3RvcmVGZ0NvbG9yKGUpfSkpKSxnLl9wYXJzZXIucmVnaXN0ZXJPc2NIYW5kbGVyKDExMSxuZXcgeS5Pc2NIYW5kbGVyKChmdW5jdGlvbihlKXtyZXR1cm4gZy5yZXN0b3JlQmdDb2xvcihlKX0pKSksZy5fcGFyc2VyLnJlZ2lzdGVyT3NjSGFuZGxlcigxMTIsbmV3IHkuT3NjSGFuZGxlcigoZnVuY3Rpb24oZSl7cmV0dXJuIGcucmVzdG9yZUN1cnNvckNvbG9yKGUpfSkpKSxnLl9wYXJzZXIucmVnaXN0ZXJFc2NIYW5kbGVyKHtmaW5hbDoiNyJ9LChmdW5jdGlvbigpe3JldHVybiBnLnNhdmVDdXJzb3IoKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJFc2NIYW5kbGVyKHtmaW5hbDoiOCJ9LChmdW5jdGlvbigpe3JldHVybiBnLnJlc3RvcmVDdXJzb3IoKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJFc2NIYW5kbGVyKHtmaW5hbDoiRCJ9LChmdW5jdGlvbigpe3JldHVybiBnLmluZGV4KCl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7ZmluYWw6IkUifSwoZnVuY3Rpb24oKXtyZXR1cm4gZy5uZXh0TGluZSgpfSkpLGcuX3BhcnNlci5yZWdpc3RlckVzY0hhbmRsZXIoe2ZpbmFsOiJIIn0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcudGFiU2V0KCl9KSksZy5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7ZmluYWw6Ik0ifSwoZnVuY3Rpb24oKXtyZXR1cm4gZy5yZXZlcnNlSW5kZXgoKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJFc2NIYW5kbGVyKHtmaW5hbDoiPSJ9LChmdW5jdGlvbigpe3JldHVybiBnLmtleXBhZEFwcGxpY2F0aW9uTW9kZSgpfSkpLGcuX3BhcnNlci5yZWdpc3RlckVzY0hhbmRsZXIoe2ZpbmFsOiI+In0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcua2V5cGFkTnVtZXJpY01vZGUoKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJFc2NIYW5kbGVyKHtmaW5hbDoiYyJ9LChmdW5jdGlvbigpe3JldHVybiBnLmZ1bGxSZXNldCgpfSkpLGcuX3BhcnNlci5yZWdpc3RlckVzY0hhbmRsZXIoe2ZpbmFsOiJuIn0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2V0Z0xldmVsKDIpfSkpLGcuX3BhcnNlci5yZWdpc3RlckVzY0hhbmRsZXIoe2ZpbmFsOiJvIn0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2V0Z0xldmVsKDMpfSkpLGcuX3BhcnNlci5yZWdpc3RlckVzY0hhbmRsZXIoe2ZpbmFsOiJ8In0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2V0Z0xldmVsKDMpfSkpLGcuX3BhcnNlci5yZWdpc3RlckVzY0hhbmRsZXIoe2ZpbmFsOiJ9In0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2V0Z0xldmVsKDIpfSkpLGcuX3BhcnNlci5yZWdpc3RlckVzY0hhbmRsZXIoe2ZpbmFsOiJ+In0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2V0Z0xldmVsKDEpfSkpLGcuX3BhcnNlci5yZWdpc3RlckVzY0hhbmRsZXIoe2ludGVybWVkaWF0ZXM6IiUiLGZpbmFsOiJAIn0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2VsZWN0RGVmYXVsdENoYXJzZXQoKX0pKSxnLl9wYXJzZXIucmVnaXN0ZXJFc2NIYW5kbGVyKHtpbnRlcm1lZGlhdGVzOiIlIixmaW5hbDoiRyJ9LChmdW5jdGlvbigpe3JldHVybiBnLnNlbGVjdERlZmF1bHRDaGFyc2V0KCl9KSk7dmFyIG09ZnVuY3Rpb24oZSl7Yi5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiKCIsZmluYWw6ZX0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2VsZWN0Q2hhcnNldCgiKCIrZSl9KSksYi5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiKSIsZmluYWw6ZX0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2VsZWN0Q2hhcnNldCgiKSIrZSl9KSksYi5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiKiIsZmluYWw6ZX0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2VsZWN0Q2hhcnNldCgiKiIrZSl9KSksYi5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiKyIsZmluYWw6ZX0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2VsZWN0Q2hhcnNldCgiKyIrZSl9KSksYi5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiLSIsZmluYWw6ZX0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2VsZWN0Q2hhcnNldCgiLSIrZSl9KSksYi5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiLiIsZmluYWw6ZX0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2VsZWN0Q2hhcnNldCgiLiIrZSl9KSksYi5fcGFyc2VyLnJlZ2lzdGVyRXNjSGFuZGxlcih7aW50ZXJtZWRpYXRlczoiLyIsZmluYWw6ZX0sKGZ1bmN0aW9uKCl7cmV0dXJuIGcuc2VsZWN0Q2hhcnNldCgiLyIrZSl9KSl9LGI9dGhpcztmb3IodmFyIFMgaW4gYS5DSEFSU0VUUyltKFMpO3JldHVybiBnLl9wYXJzZXIucmVnaXN0ZXJFc2NIYW5kbGVyKHtpbnRlcm1lZGlhdGVzOiIjIixmaW5hbDoiOCJ9LChmdW5jdGlvbigpe3JldHVybiBnLnNjcmVlbkFsaWdubWVudFBhdHRlcm4oKX0pKSxnLl9wYXJzZXIuc2V0RXJyb3JIYW5kbGVyKChmdW5jdGlvbihlKXtyZXR1cm4gZy5fbG9nU2VydmljZS5lcnJvcigiUGFyc2luZyBlcnJvcjogIixlKSxlfSkpLGcuX3BhcnNlci5yZWdpc3RlckRjc0hhbmRsZXIoe2ludGVybWVkaWF0ZXM6IiQiLGZpbmFsOiJxIn0sbmV3IEwoZy5fYnVmZmVyU2VydmljZSxnLl9jb3JlU2VydmljZSxnLl9sb2dTZXJ2aWNlLGcuX29wdGlvbnNTZXJ2aWNlKSksZ31yZXR1cm4gbih0LGUpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25SZXF1ZXN0QmVsbCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vblJlcXVlc3RCZWxsLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25SZXF1ZXN0UmVmcmVzaFJvd3MiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25SZXF1ZXN0UmVmcmVzaFJvd3MuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvblJlcXVlc3RSZXNldCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vblJlcXVlc3RSZXNldC5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uUmVxdWVzdFNlbmRGb2N1cyIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vblJlcXVlc3RTZW5kRm9jdXMuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvblJlcXVlc3RTeW5jU2Nyb2xsQmFyIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uUmVxdWVzdFN5bmNTY3JvbGxCYXIuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvblJlcXVlc3RXaW5kb3dzT3B0aW9uc1JlcG9ydCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vblJlcXVlc3RXaW5kb3dzT3B0aW9uc1JlcG9ydC5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uQTExeUNoYXIiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25BMTF5Q2hhci5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uQTExeVRhYiIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vbkExMXlUYWIuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvbkN1cnNvck1vdmUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25DdXJzb3JNb3ZlLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25MaW5lRmVlZCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vbkxpbmVGZWVkLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25TY3JvbGwiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25TY3JvbGwuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvblRpdGxlQ2hhbmdlIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uVGl0bGVDaGFuZ2UuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvbkNvbG9yIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uQ29sb3IuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe2UucHJvdG90eXBlLmRpc3Bvc2UuY2FsbCh0aGlzKX0sdC5wcm90b3R5cGUuX3ByZXNlcnZlU3RhY2s9ZnVuY3Rpb24oZSx0LHIsaSl7dGhpcy5fcGFyc2VTdGFjay5wYXVzZWQ9ITAsdGhpcy5fcGFyc2VTdGFjay5jdXJzb3JTdGFydFg9ZSx0aGlzLl9wYXJzZVN0YWNrLmN1cnNvclN0YXJ0WT10LHRoaXMuX3BhcnNlU3RhY2suZGVjb2RlZExlbmd0aD1yLHRoaXMuX3BhcnNlU3RhY2sucG9zaXRpb249aX0sdC5wcm90b3R5cGUuX2xvZ1Nsb3dSZXNvbHZpbmdBc3luYz1mdW5jdGlvbihlKXt0aGlzLl9sb2dTZXJ2aWNlLmxvZ0xldmVsPD1nLkxvZ0xldmVsRW51bS5XQVJOJiZQcm9taXNlLnJhY2UoW2UsbmV3IFByb21pc2UoKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHNldFRpbWVvdXQoKGZ1bmN0aW9uKCl7cmV0dXJuIHQoIiNTTE9XX1RJTUVPVVQiKX0pLDVlMyl9KSldKS5jYXRjaCgoZnVuY3Rpb24oZSl7aWYoIiNTTE9XX1RJTUVPVVQiIT09ZSl0aHJvdyBlO2NvbnNvbGUud2FybigiYXN5bmMgcGFyc2VyIGhhbmRsZXIgdGFraW5nIGxvbmdlciB0aGFuIDUwMDAgbXMiKX0pKX0sdC5wcm90b3R5cGUucGFyc2U9ZnVuY3Rpb24oZSx0KXt2YXIgcixpPXRoaXMuX2FjdGl2ZUJ1ZmZlci54LG49dGhpcy5fYWN0aXZlQnVmZmVyLnksbz0wLHM9dGhpcy5fcGFyc2VTdGFjay5wYXVzZWQ7aWYocyl7aWYocj10aGlzLl9wYXJzZXIucGFyc2UodGhpcy5fcGFyc2VCdWZmZXIsdGhpcy5fcGFyc2VTdGFjay5kZWNvZGVkTGVuZ3RoLHQpKXJldHVybiB0aGlzLl9sb2dTbG93UmVzb2x2aW5nQXN5bmMocikscjtpPXRoaXMuX3BhcnNlU3RhY2suY3Vyc29yU3RhcnRYLG49dGhpcy5fcGFyc2VTdGFjay5jdXJzb3JTdGFydFksdGhpcy5fcGFyc2VTdGFjay5wYXVzZWQ9ITEsZS5sZW5ndGg+QyYmKG89dGhpcy5fcGFyc2VTdGFjay5wb3NpdGlvbitDKX1pZih0aGlzLl9sb2dTZXJ2aWNlLmxvZ0xldmVsPD1nLkxvZ0xldmVsRW51bS5ERUJVRyYmdGhpcy5fbG9nU2VydmljZS5kZWJ1ZygicGFyc2luZyBkYXRhIisoInN0cmluZyI9PXR5cGVvZiBlPycgIicrZSsnIic6IiIpLCJzdHJpbmciPT10eXBlb2YgZT9lLnNwbGl0KCIiKS5tYXAoKGZ1bmN0aW9uKGUpe3JldHVybiBlLmNoYXJDb2RlQXQoMCl9KSk6ZSksdGhpcy5fcGFyc2VCdWZmZXIubGVuZ3RoPGUubGVuZ3RoJiZ0aGlzLl9wYXJzZUJ1ZmZlci5sZW5ndGg8QyYmKHRoaXMuX3BhcnNlQnVmZmVyPW5ldyBVaW50MzJBcnJheShNYXRoLm1pbihlLmxlbmd0aCxDKSkpLHN8fHRoaXMuX2RpcnR5Um93U2VydmljZS5jbGVhclJhbmdlKCksZS5sZW5ndGg+Qylmb3IodmFyIGE9bzthPGUubGVuZ3RoO2ErPUMpe3ZhciBjPWErQzxlLmxlbmd0aD9hK0M6ZS5sZW5ndGgsbD0ic3RyaW5nIj09dHlwZW9mIGU/dGhpcy5fc3RyaW5nRGVjb2Rlci5kZWNvZGUoZS5zdWJzdHJpbmcoYSxjKSx0aGlzLl9wYXJzZUJ1ZmZlcik6dGhpcy5fdXRmOERlY29kZXIuZGVjb2RlKGUuc3ViYXJyYXkoYSxjKSx0aGlzLl9wYXJzZUJ1ZmZlcik7aWYocj10aGlzLl9wYXJzZXIucGFyc2UodGhpcy5fcGFyc2VCdWZmZXIsbCkpcmV0dXJuIHRoaXMuX3ByZXNlcnZlU3RhY2soaSxuLGwsYSksdGhpcy5fbG9nU2xvd1Jlc29sdmluZ0FzeW5jKHIpLHJ9ZWxzZSBpZighcyYmKGw9InN0cmluZyI9PXR5cGVvZiBlP3RoaXMuX3N0cmluZ0RlY29kZXIuZGVjb2RlKGUsdGhpcy5fcGFyc2VCdWZmZXIpOnRoaXMuX3V0ZjhEZWNvZGVyLmRlY29kZShlLHRoaXMuX3BhcnNlQnVmZmVyKSxyPXRoaXMuX3BhcnNlci5wYXJzZSh0aGlzLl9wYXJzZUJ1ZmZlcixsKSkpcmV0dXJuIHRoaXMuX3ByZXNlcnZlU3RhY2soaSxuLGwsMCksdGhpcy5fbG9nU2xvd1Jlc29sdmluZ0FzeW5jKHIpLHI7dGhpcy5fYWN0aXZlQnVmZmVyLng9PT1pJiZ0aGlzLl9hY3RpdmVCdWZmZXIueT09PW58fHRoaXMuX29uQ3Vyc29yTW92ZS5maXJlKCksdGhpcy5fb25SZXF1ZXN0UmVmcmVzaFJvd3MuZmlyZSh0aGlzLl9kaXJ0eVJvd1NlcnZpY2Uuc3RhcnQsdGhpcy5fZGlydHlSb3dTZXJ2aWNlLmVuZCl9LHQucHJvdG90eXBlLnByaW50PWZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuLG89dGhpcy5fY2hhcnNldFNlcnZpY2UuY2hhcnNldCxzPXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuc2NyZWVuUmVhZGVyTW9kZSxhPXRoaXMuX2J1ZmZlclNlcnZpY2UuY29scyxjPXRoaXMuX2NvcmVTZXJ2aWNlLmRlY1ByaXZhdGVNb2Rlcy53cmFwYXJvdW5kLGw9dGhpcy5fY29yZVNlcnZpY2UubW9kZXMuaW5zZXJ0TW9kZSx1PXRoaXMuX2N1ckF0dHJEYXRhLGY9dGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLmdldCh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrdGhpcy5fYWN0aXZlQnVmZmVyLnkpO3RoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrRGlydHkodGhpcy5fYWN0aXZlQnVmZmVyLnkpLHRoaXMuX2FjdGl2ZUJ1ZmZlci54JiZyLXQ+MCYmMj09PWYuZ2V0V2lkdGgodGhpcy5fYWN0aXZlQnVmZmVyLngtMSkmJmYuc2V0Q2VsbEZyb21Db2RlUG9pbnQodGhpcy5fYWN0aXZlQnVmZmVyLngtMSwwLDEsdS5mZyx1LmJnLHUuZXh0ZW5kZWQpO2Zvcih2YXIgXz10O188cjsrK18pe2lmKGk9ZVtfXSxuPXRoaXMuX3VuaWNvZGVTZXJ2aWNlLndjd2lkdGgoaSksaTwxMjcmJm8pe3ZhciBwPW9bU3RyaW5nLmZyb21DaGFyQ29kZShpKV07cCYmKGk9cC5jaGFyQ29kZUF0KDApKX1pZihzJiZ0aGlzLl9vbkExMXlDaGFyLmZpcmUoKDAsaC5zdHJpbmdGcm9tQ29kZVBvaW50KShpKSksbnx8IXRoaXMuX2FjdGl2ZUJ1ZmZlci54KXtpZih0aGlzLl9hY3RpdmVCdWZmZXIueCtuLTE+PWEpaWYoYyl7Zm9yKDt0aGlzLl9hY3RpdmVCdWZmZXIueDxhOylmLnNldENlbGxGcm9tQ29kZVBvaW50KHRoaXMuX2FjdGl2ZUJ1ZmZlci54KyssMCwxLHUuZmcsdS5iZyx1LmV4dGVuZGVkKTt0aGlzLl9hY3RpdmVCdWZmZXIueD0wLHRoaXMuX2FjdGl2ZUJ1ZmZlci55KyssdGhpcy5fYWN0aXZlQnVmZmVyLnk9PT10aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tKzE/KHRoaXMuX2FjdGl2ZUJ1ZmZlci55LS0sdGhpcy5fYnVmZmVyU2VydmljZS5zY3JvbGwodGhpcy5fZXJhc2VBdHRyRGF0YSgpLCEwKSk6KHRoaXMuX2FjdGl2ZUJ1ZmZlci55Pj10aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MmJih0aGlzLl9hY3RpdmVCdWZmZXIueT10aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MtMSksdGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLmdldCh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrdGhpcy5fYWN0aXZlQnVmZmVyLnkpLmlzV3JhcHBlZD0hMCksZj10aGlzLl9hY3RpdmVCdWZmZXIubGluZXMuZ2V0KHRoaXMuX2FjdGl2ZUJ1ZmZlci55YmFzZSt0aGlzLl9hY3RpdmVCdWZmZXIueSl9ZWxzZSBpZih0aGlzLl9hY3RpdmVCdWZmZXIueD1hLTEsMj09PW4pY29udGludWU7aWYobCYmKGYuaW5zZXJ0Q2VsbHModGhpcy5fYWN0aXZlQnVmZmVyLngsbix0aGlzLl9hY3RpdmVCdWZmZXIuZ2V0TnVsbENlbGwodSksdSksMj09PWYuZ2V0V2lkdGgoYS0xKSYmZi5zZXRDZWxsRnJvbUNvZGVQb2ludChhLTEsZC5OVUxMX0NFTExfQ09ERSxkLk5VTExfQ0VMTF9XSURUSCx1LmZnLHUuYmcsdS5leHRlbmRlZCkpLGYuc2V0Q2VsbEZyb21Db2RlUG9pbnQodGhpcy5fYWN0aXZlQnVmZmVyLngrKyxpLG4sdS5mZyx1LmJnLHUuZXh0ZW5kZWQpLG4+MClmb3IoOy0tbjspZi5zZXRDZWxsRnJvbUNvZGVQb2ludCh0aGlzLl9hY3RpdmVCdWZmZXIueCsrLDAsMCx1LmZnLHUuYmcsdS5leHRlbmRlZCl9ZWxzZSBmLmdldFdpZHRoKHRoaXMuX2FjdGl2ZUJ1ZmZlci54LTEpP2YuYWRkQ29kZXBvaW50VG9DZWxsKHRoaXMuX2FjdGl2ZUJ1ZmZlci54LTEsaSk6Zi5hZGRDb2RlcG9pbnRUb0NlbGwodGhpcy5fYWN0aXZlQnVmZmVyLngtMixpKX1yLXQ+MCYmKGYubG9hZENlbGwodGhpcy5fYWN0aXZlQnVmZmVyLngtMSx0aGlzLl93b3JrQ2VsbCksMj09PXRoaXMuX3dvcmtDZWxsLmdldFdpZHRoKCl8fHRoaXMuX3dvcmtDZWxsLmdldENvZGUoKT42NTUzNT90aGlzLl9wYXJzZXIucHJlY2VkaW5nQ29kZXBvaW50PTA6dGhpcy5fd29ya0NlbGwuaXNDb21iaW5lZCgpP3RoaXMuX3BhcnNlci5wcmVjZWRpbmdDb2RlcG9pbnQ9dGhpcy5fd29ya0NlbGwuZ2V0Q2hhcnMoKS5jaGFyQ29kZUF0KDApOnRoaXMuX3BhcnNlci5wcmVjZWRpbmdDb2RlcG9pbnQ9dGhpcy5fd29ya0NlbGwuY29udGVudCksdGhpcy5fYWN0aXZlQnVmZmVyLng8YSYmci10PjAmJjA9PT1mLmdldFdpZHRoKHRoaXMuX2FjdGl2ZUJ1ZmZlci54KSYmIWYuaGFzQ29udGVudCh0aGlzLl9hY3RpdmVCdWZmZXIueCkmJmYuc2V0Q2VsbEZyb21Db2RlUG9pbnQodGhpcy5fYWN0aXZlQnVmZmVyLngsMCwxLHUuZmcsdS5iZyx1LmV4dGVuZGVkKSx0aGlzLl9kaXJ0eVJvd1NlcnZpY2UubWFya0RpcnR5KHRoaXMuX2FjdGl2ZUJ1ZmZlci55KX0sdC5wcm90b3R5cGUucmVnaXN0ZXJDc2lIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7dmFyIHI9dGhpcztyZXR1cm4idCIhPT1lLmZpbmFsfHxlLnByZWZpeHx8ZS5pbnRlcm1lZGlhdGVzP3RoaXMuX3BhcnNlci5yZWdpc3RlckNzaUhhbmRsZXIoZSx0KTp0aGlzLl9wYXJzZXIucmVnaXN0ZXJDc2lIYW5kbGVyKGUsKGZ1bmN0aW9uKGUpe3JldHVybiF3KGUucGFyYW1zWzBdLHIuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMud2luZG93T3B0aW9ucyl8fHQoZSl9KSl9LHQucHJvdG90eXBlLnJlZ2lzdGVyRGNzSGFuZGxlcj1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLl9wYXJzZXIucmVnaXN0ZXJEY3NIYW5kbGVyKGUsbmV3IG0uRGNzSGFuZGxlcih0KSl9LHQucHJvdG90eXBlLnJlZ2lzdGVyRXNjSGFuZGxlcj1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLl9wYXJzZXIucmVnaXN0ZXJFc2NIYW5kbGVyKGUsdCl9LHQucHJvdG90eXBlLnJlZ2lzdGVyT3NjSGFuZGxlcj1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLl9wYXJzZXIucmVnaXN0ZXJPc2NIYW5kbGVyKGUsbmV3IHkuT3NjSGFuZGxlcih0KSl9LHQucHJvdG90eXBlLmJlbGw9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25SZXF1ZXN0QmVsbC5maXJlKCksITB9LHQucHJvdG90eXBlLmxpbmVGZWVkPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrRGlydHkodGhpcy5fYWN0aXZlQnVmZmVyLnkpLHRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuY29udmVydEVvbCYmKHRoaXMuX2FjdGl2ZUJ1ZmZlci54PTApLHRoaXMuX2FjdGl2ZUJ1ZmZlci55KyssdGhpcy5fYWN0aXZlQnVmZmVyLnk9PT10aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tKzE/KHRoaXMuX2FjdGl2ZUJ1ZmZlci55LS0sdGhpcy5fYnVmZmVyU2VydmljZS5zY3JvbGwodGhpcy5fZXJhc2VBdHRyRGF0YSgpKSk6dGhpcy5fYWN0aXZlQnVmZmVyLnk+PXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyYmKHRoaXMuX2FjdGl2ZUJ1ZmZlci55PXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cy0xKSx0aGlzLl9hY3RpdmVCdWZmZXIueD49dGhpcy5fYnVmZmVyU2VydmljZS5jb2xzJiZ0aGlzLl9hY3RpdmVCdWZmZXIueC0tLHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrRGlydHkodGhpcy5fYWN0aXZlQnVmZmVyLnkpLHRoaXMuX29uTGluZUZlZWQuZmlyZSgpLCEwfSx0LnByb3RvdHlwZS5jYXJyaWFnZVJldHVybj1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9hY3RpdmVCdWZmZXIueD0wLCEwfSx0LnByb3RvdHlwZS5iYWNrc3BhY2U9ZnVuY3Rpb24oKXt2YXIgZTtpZighdGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLnJldmVyc2VXcmFwYXJvdW5kKXJldHVybiB0aGlzLl9yZXN0cmljdEN1cnNvcigpLHRoaXMuX2FjdGl2ZUJ1ZmZlci54PjAmJnRoaXMuX2FjdGl2ZUJ1ZmZlci54LS0sITA7aWYodGhpcy5fcmVzdHJpY3RDdXJzb3IodGhpcy5fYnVmZmVyU2VydmljZS5jb2xzKSx0aGlzLl9hY3RpdmVCdWZmZXIueD4wKXRoaXMuX2FjdGl2ZUJ1ZmZlci54LS07ZWxzZSBpZigwPT09dGhpcy5fYWN0aXZlQnVmZmVyLngmJnRoaXMuX2FjdGl2ZUJ1ZmZlci55PnRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3AmJnRoaXMuX2FjdGl2ZUJ1ZmZlci55PD10aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tJiYobnVsbD09PShlPXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5nZXQodGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3RoaXMuX2FjdGl2ZUJ1ZmZlci55KSl8fHZvaWQgMD09PWU/dm9pZCAwOmUuaXNXcmFwcGVkKSl7dGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLmdldCh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrdGhpcy5fYWN0aXZlQnVmZmVyLnkpLmlzV3JhcHBlZD0hMSx0aGlzLl9hY3RpdmVCdWZmZXIueS0tLHRoaXMuX2FjdGl2ZUJ1ZmZlci54PXRoaXMuX2J1ZmZlclNlcnZpY2UuY29scy0xO3ZhciB0PXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5nZXQodGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3RoaXMuX2FjdGl2ZUJ1ZmZlci55KTt0Lmhhc1dpZHRoKHRoaXMuX2FjdGl2ZUJ1ZmZlci54KSYmIXQuaGFzQ29udGVudCh0aGlzLl9hY3RpdmVCdWZmZXIueCkmJnRoaXMuX2FjdGl2ZUJ1ZmZlci54LS19cmV0dXJuIHRoaXMuX3Jlc3RyaWN0Q3Vyc29yKCksITB9LHQucHJvdG90eXBlLnRhYj1mdW5jdGlvbigpe2lmKHRoaXMuX2FjdGl2ZUJ1ZmZlci54Pj10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMpcmV0dXJuITA7dmFyIGU9dGhpcy5fYWN0aXZlQnVmZmVyLng7cmV0dXJuIHRoaXMuX2FjdGl2ZUJ1ZmZlci54PXRoaXMuX2FjdGl2ZUJ1ZmZlci5uZXh0U3RvcCgpLHRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuc2NyZWVuUmVhZGVyTW9kZSYmdGhpcy5fb25BMTF5VGFiLmZpcmUodGhpcy5fYWN0aXZlQnVmZmVyLngtZSksITB9LHQucHJvdG90eXBlLnNoaWZ0T3V0PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2NoYXJzZXRTZXJ2aWNlLnNldGdMZXZlbCgxKSwhMH0sdC5wcm90b3R5cGUuc2hpZnRJbj1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9jaGFyc2V0U2VydmljZS5zZXRnTGV2ZWwoMCksITB9LHQucHJvdG90eXBlLl9yZXN0cmljdEN1cnNvcj1mdW5jdGlvbihlKXt2b2lkIDA9PT1lJiYoZT10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMtMSksdGhpcy5fYWN0aXZlQnVmZmVyLng9TWF0aC5taW4oZSxNYXRoLm1heCgwLHRoaXMuX2FjdGl2ZUJ1ZmZlci54KSksdGhpcy5fYWN0aXZlQnVmZmVyLnk9dGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLm9yaWdpbj9NYXRoLm1pbih0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tLE1hdGgubWF4KHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3AsdGhpcy5fYWN0aXZlQnVmZmVyLnkpKTpNYXRoLm1pbih0aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MtMSxNYXRoLm1heCgwLHRoaXMuX2FjdGl2ZUJ1ZmZlci55KSksdGhpcy5fZGlydHlSb3dTZXJ2aWNlLm1hcmtEaXJ0eSh0aGlzLl9hY3RpdmVCdWZmZXIueSl9LHQucHJvdG90eXBlLl9zZXRDdXJzb3I9ZnVuY3Rpb24oZSx0KXt0aGlzLl9kaXJ0eVJvd1NlcnZpY2UubWFya0RpcnR5KHRoaXMuX2FjdGl2ZUJ1ZmZlci55KSx0aGlzLl9jb3JlU2VydmljZS5kZWNQcml2YXRlTW9kZXMub3JpZ2luPyh0aGlzLl9hY3RpdmVCdWZmZXIueD1lLHRoaXMuX2FjdGl2ZUJ1ZmZlci55PXRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3ArdCk6KHRoaXMuX2FjdGl2ZUJ1ZmZlci54PWUsdGhpcy5fYWN0aXZlQnVmZmVyLnk9dCksdGhpcy5fcmVzdHJpY3RDdXJzb3IoKSx0aGlzLl9kaXJ0eVJvd1NlcnZpY2UubWFya0RpcnR5KHRoaXMuX2FjdGl2ZUJ1ZmZlci55KX0sdC5wcm90b3R5cGUuX21vdmVDdXJzb3I9ZnVuY3Rpb24oZSx0KXt0aGlzLl9yZXN0cmljdEN1cnNvcigpLHRoaXMuX3NldEN1cnNvcih0aGlzLl9hY3RpdmVCdWZmZXIueCtlLHRoaXMuX2FjdGl2ZUJ1ZmZlci55K3QpfSx0LnByb3RvdHlwZS5jdXJzb3JVcD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9hY3RpdmVCdWZmZXIueS10aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wO3JldHVybiB0Pj0wP3RoaXMuX21vdmVDdXJzb3IoMCwtTWF0aC5taW4odCxlLnBhcmFtc1swXXx8MSkpOnRoaXMuX21vdmVDdXJzb3IoMCwtKGUucGFyYW1zWzBdfHwxKSksITB9LHQucHJvdG90eXBlLmN1cnNvckRvd249ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbS10aGlzLl9hY3RpdmVCdWZmZXIueTtyZXR1cm4gdD49MD90aGlzLl9tb3ZlQ3Vyc29yKDAsTWF0aC5taW4odCxlLnBhcmFtc1swXXx8MSkpOnRoaXMuX21vdmVDdXJzb3IoMCxlLnBhcmFtc1swXXx8MSksITB9LHQucHJvdG90eXBlLmN1cnNvckZvcndhcmQ9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX21vdmVDdXJzb3IoZS5wYXJhbXNbMF18fDEsMCksITB9LHQucHJvdG90eXBlLmN1cnNvckJhY2t3YXJkPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9tb3ZlQ3Vyc29yKC0oZS5wYXJhbXNbMF18fDEpLDApLCEwfSx0LnByb3RvdHlwZS5jdXJzb3JOZXh0TGluZT1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5jdXJzb3JEb3duKGUpLHRoaXMuX2FjdGl2ZUJ1ZmZlci54PTAsITB9LHQucHJvdG90eXBlLmN1cnNvclByZWNlZGluZ0xpbmU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuY3Vyc29yVXAoZSksdGhpcy5fYWN0aXZlQnVmZmVyLng9MCwhMH0sdC5wcm90b3R5cGUuY3Vyc29yQ2hhckFic29sdXRlPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9zZXRDdXJzb3IoKGUucGFyYW1zWzBdfHwxKS0xLHRoaXMuX2FjdGl2ZUJ1ZmZlci55KSwhMH0sdC5wcm90b3R5cGUuY3Vyc29yUG9zaXRpb249ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX3NldEN1cnNvcihlLmxlbmd0aD49Mj8oZS5wYXJhbXNbMV18fDEpLTE6MCwoZS5wYXJhbXNbMF18fDEpLTEpLCEwfSx0LnByb3RvdHlwZS5jaGFyUG9zQWJzb2x1dGU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX3NldEN1cnNvcigoZS5wYXJhbXNbMF18fDEpLTEsdGhpcy5fYWN0aXZlQnVmZmVyLnkpLCEwfSx0LnByb3RvdHlwZS5oUG9zaXRpb25SZWxhdGl2ZT1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fbW92ZUN1cnNvcihlLnBhcmFtc1swXXx8MSwwKSwhMH0sdC5wcm90b3R5cGUubGluZVBvc0Fic29sdXRlPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9zZXRDdXJzb3IodGhpcy5fYWN0aXZlQnVmZmVyLngsKGUucGFyYW1zWzBdfHwxKS0xKSwhMH0sdC5wcm90b3R5cGUudlBvc2l0aW9uUmVsYXRpdmU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX21vdmVDdXJzb3IoMCxlLnBhcmFtc1swXXx8MSksITB9LHQucHJvdG90eXBlLmhWUG9zaXRpb249ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuY3Vyc29yUG9zaXRpb24oZSksITB9LHQucHJvdG90eXBlLnRhYkNsZWFyPWZ1bmN0aW9uKGUpe3ZhciB0PWUucGFyYW1zWzBdO3JldHVybiAwPT09dD9kZWxldGUgdGhpcy5fYWN0aXZlQnVmZmVyLnRhYnNbdGhpcy5fYWN0aXZlQnVmZmVyLnhdOjM9PT10JiYodGhpcy5fYWN0aXZlQnVmZmVyLnRhYnM9e30pLCEwfSx0LnByb3RvdHlwZS5jdXJzb3JGb3J3YXJkVGFiPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2FjdGl2ZUJ1ZmZlci54Pj10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMpcmV0dXJuITA7Zm9yKHZhciB0PWUucGFyYW1zWzBdfHwxO3QtLTspdGhpcy5fYWN0aXZlQnVmZmVyLng9dGhpcy5fYWN0aXZlQnVmZmVyLm5leHRTdG9wKCk7cmV0dXJuITB9LHQucHJvdG90eXBlLmN1cnNvckJhY2t3YXJkVGFiPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2FjdGl2ZUJ1ZmZlci54Pj10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMpcmV0dXJuITA7Zm9yKHZhciB0PWUucGFyYW1zWzBdfHwxO3QtLTspdGhpcy5fYWN0aXZlQnVmZmVyLng9dGhpcy5fYWN0aXZlQnVmZmVyLnByZXZTdG9wKCk7cmV0dXJuITB9LHQucHJvdG90eXBlLl9lcmFzZUluQnVmZmVyTGluZT1mdW5jdGlvbihlLHQscixpKXt2b2lkIDA9PT1pJiYoaT0hMSk7dmFyIG49dGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLmdldCh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrZSk7bi5yZXBsYWNlQ2VsbHModCxyLHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXROdWxsQ2VsbCh0aGlzLl9lcmFzZUF0dHJEYXRhKCkpLHRoaXMuX2VyYXNlQXR0ckRhdGEoKSksaSYmKG4uaXNXcmFwcGVkPSExKX0sdC5wcm90b3R5cGUuX3Jlc2V0QnVmZmVyTGluZT1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9hY3RpdmVCdWZmZXIubGluZXMuZ2V0KHRoaXMuX2FjdGl2ZUJ1ZmZlci55YmFzZStlKTt0LmZpbGwodGhpcy5fYWN0aXZlQnVmZmVyLmdldE51bGxDZWxsKHRoaXMuX2VyYXNlQXR0ckRhdGEoKSkpLHQuaXNXcmFwcGVkPSExfSx0LnByb3RvdHlwZS5lcmFzZUluRGlzcGxheT1mdW5jdGlvbihlKXt2YXIgdDtzd2l0Y2godGhpcy5fcmVzdHJpY3RDdXJzb3IodGhpcy5fYnVmZmVyU2VydmljZS5jb2xzKSxlLnBhcmFtc1swXSl7Y2FzZSAwOmZvcih0PXRoaXMuX2FjdGl2ZUJ1ZmZlci55LHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrRGlydHkodCksdGhpcy5fZXJhc2VJbkJ1ZmZlckxpbmUodCsrLHRoaXMuX2FjdGl2ZUJ1ZmZlci54LHRoaXMuX2J1ZmZlclNlcnZpY2UuY29scywwPT09dGhpcy5fYWN0aXZlQnVmZmVyLngpO3Q8dGhpcy5fYnVmZmVyU2VydmljZS5yb3dzO3QrKyl0aGlzLl9yZXNldEJ1ZmZlckxpbmUodCk7dGhpcy5fZGlydHlSb3dTZXJ2aWNlLm1hcmtEaXJ0eSh0KTticmVhaztjYXNlIDE6Zm9yKHQ9dGhpcy5fYWN0aXZlQnVmZmVyLnksdGhpcy5fZGlydHlSb3dTZXJ2aWNlLm1hcmtEaXJ0eSh0KSx0aGlzLl9lcmFzZUluQnVmZmVyTGluZSh0LDAsdGhpcy5fYWN0aXZlQnVmZmVyLngrMSwhMCksdGhpcy5fYWN0aXZlQnVmZmVyLngrMT49dGhpcy5fYnVmZmVyU2VydmljZS5jb2xzJiYodGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLmdldCh0KzEpLmlzV3JhcHBlZD0hMSk7dC0tOyl0aGlzLl9yZXNldEJ1ZmZlckxpbmUodCk7dGhpcy5fZGlydHlSb3dTZXJ2aWNlLm1hcmtEaXJ0eSgwKTticmVhaztjYXNlIDI6Zm9yKHQ9dGhpcy5fYnVmZmVyU2VydmljZS5yb3dzLHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrRGlydHkodC0xKTt0LS07KXRoaXMuX3Jlc2V0QnVmZmVyTGluZSh0KTt0aGlzLl9kaXJ0eVJvd1NlcnZpY2UubWFya0RpcnR5KDApO2JyZWFrO2Nhc2UgMzp2YXIgcj10aGlzLl9hY3RpdmVCdWZmZXIubGluZXMubGVuZ3RoLXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cztyPjAmJih0aGlzLl9hY3RpdmVCdWZmZXIubGluZXMudHJpbVN0YXJ0KHIpLHRoaXMuX2FjdGl2ZUJ1ZmZlci55YmFzZT1NYXRoLm1heCh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UtciwwKSx0aGlzLl9hY3RpdmVCdWZmZXIueWRpc3A9TWF0aC5tYXgodGhpcy5fYWN0aXZlQnVmZmVyLnlkaXNwLXIsMCksdGhpcy5fb25TY3JvbGwuZmlyZSgwKSl9cmV0dXJuITB9LHQucHJvdG90eXBlLmVyYXNlSW5MaW5lPWZ1bmN0aW9uKGUpe3N3aXRjaCh0aGlzLl9yZXN0cmljdEN1cnNvcih0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMpLGUucGFyYW1zWzBdKXtjYXNlIDA6dGhpcy5fZXJhc2VJbkJ1ZmZlckxpbmUodGhpcy5fYWN0aXZlQnVmZmVyLnksdGhpcy5fYWN0aXZlQnVmZmVyLngsdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLDA9PT10aGlzLl9hY3RpdmVCdWZmZXIueCk7YnJlYWs7Y2FzZSAxOnRoaXMuX2VyYXNlSW5CdWZmZXJMaW5lKHRoaXMuX2FjdGl2ZUJ1ZmZlci55LDAsdGhpcy5fYWN0aXZlQnVmZmVyLngrMSwhMSk7YnJlYWs7Y2FzZSAyOnRoaXMuX2VyYXNlSW5CdWZmZXJMaW5lKHRoaXMuX2FjdGl2ZUJ1ZmZlci55LDAsdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzLCEwKX1yZXR1cm4gdGhpcy5fZGlydHlSb3dTZXJ2aWNlLm1hcmtEaXJ0eSh0aGlzLl9hY3RpdmVCdWZmZXIueSksITB9LHQucHJvdG90eXBlLmluc2VydExpbmVzPWZ1bmN0aW9uKGUpe3RoaXMuX3Jlc3RyaWN0Q3Vyc29yKCk7dmFyIHQ9ZS5wYXJhbXNbMF18fDE7aWYodGhpcy5fYWN0aXZlQnVmZmVyLnk+dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbXx8dGhpcy5fYWN0aXZlQnVmZmVyLnk8dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbFRvcClyZXR1cm4hMDtmb3IodmFyIHI9dGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3RoaXMuX2FjdGl2ZUJ1ZmZlci55LGk9dGhpcy5fYnVmZmVyU2VydmljZS5yb3dzLTEtdGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbSxuPXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cy0xK3RoaXMuX2FjdGl2ZUJ1ZmZlci55YmFzZS1pKzE7dC0tOyl0aGlzLl9hY3RpdmVCdWZmZXIubGluZXMuc3BsaWNlKG4tMSwxKSx0aGlzLl9hY3RpdmVCdWZmZXIubGluZXMuc3BsaWNlKHIsMCx0aGlzLl9hY3RpdmVCdWZmZXIuZ2V0QmxhbmtMaW5lKHRoaXMuX2VyYXNlQXR0ckRhdGEoKSkpO3JldHVybiB0aGlzLl9kaXJ0eVJvd1NlcnZpY2UubWFya1JhbmdlRGlydHkodGhpcy5fYWN0aXZlQnVmZmVyLnksdGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbSksdGhpcy5fYWN0aXZlQnVmZmVyLng9MCwhMH0sdC5wcm90b3R5cGUuZGVsZXRlTGluZXM9ZnVuY3Rpb24oZSl7dGhpcy5fcmVzdHJpY3RDdXJzb3IoKTt2YXIgdD1lLnBhcmFtc1swXXx8MTtpZih0aGlzLl9hY3RpdmVCdWZmZXIueT50aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tfHx0aGlzLl9hY3RpdmVCdWZmZXIueTx0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wKXJldHVybiEwO3ZhciByLGk9dGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3RoaXMuX2FjdGl2ZUJ1ZmZlci55O2ZvcihyPXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cy0xLXRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b20scj10aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MtMSt0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2Utcjt0LS07KXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5zcGxpY2UoaSwxKSx0aGlzLl9hY3RpdmVCdWZmZXIubGluZXMuc3BsaWNlKHIsMCx0aGlzLl9hY3RpdmVCdWZmZXIuZ2V0QmxhbmtMaW5lKHRoaXMuX2VyYXNlQXR0ckRhdGEoKSkpO3JldHVybiB0aGlzLl9kaXJ0eVJvd1NlcnZpY2UubWFya1JhbmdlRGlydHkodGhpcy5fYWN0aXZlQnVmZmVyLnksdGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbSksdGhpcy5fYWN0aXZlQnVmZmVyLng9MCwhMH0sdC5wcm90b3R5cGUuaW5zZXJ0Q2hhcnM9ZnVuY3Rpb24oZSl7dGhpcy5fcmVzdHJpY3RDdXJzb3IoKTt2YXIgdD10aGlzLl9hY3RpdmVCdWZmZXIubGluZXMuZ2V0KHRoaXMuX2FjdGl2ZUJ1ZmZlci55YmFzZSt0aGlzLl9hY3RpdmVCdWZmZXIueSk7cmV0dXJuIHQmJih0Lmluc2VydENlbGxzKHRoaXMuX2FjdGl2ZUJ1ZmZlci54LGUucGFyYW1zWzBdfHwxLHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXROdWxsQ2VsbCh0aGlzLl9lcmFzZUF0dHJEYXRhKCkpLHRoaXMuX2VyYXNlQXR0ckRhdGEoKSksdGhpcy5fZGlydHlSb3dTZXJ2aWNlLm1hcmtEaXJ0eSh0aGlzLl9hY3RpdmVCdWZmZXIueSkpLCEwfSx0LnByb3RvdHlwZS5kZWxldGVDaGFycz1mdW5jdGlvbihlKXt0aGlzLl9yZXN0cmljdEN1cnNvcigpO3ZhciB0PXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5nZXQodGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3RoaXMuX2FjdGl2ZUJ1ZmZlci55KTtyZXR1cm4gdCYmKHQuZGVsZXRlQ2VsbHModGhpcy5fYWN0aXZlQnVmZmVyLngsZS5wYXJhbXNbMF18fDEsdGhpcy5fYWN0aXZlQnVmZmVyLmdldE51bGxDZWxsKHRoaXMuX2VyYXNlQXR0ckRhdGEoKSksdGhpcy5fZXJhc2VBdHRyRGF0YSgpKSx0aGlzLl9kaXJ0eVJvd1NlcnZpY2UubWFya0RpcnR5KHRoaXMuX2FjdGl2ZUJ1ZmZlci55KSksITB9LHQucHJvdG90eXBlLnNjcm9sbFVwPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1lLnBhcmFtc1swXXx8MTt0LS07KXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5zcGxpY2UodGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3RoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3AsMSksdGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLnNwbGljZSh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrdGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbSwwLHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXRCbGFua0xpbmUodGhpcy5fZXJhc2VBdHRyRGF0YSgpKSk7cmV0dXJuIHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrUmFuZ2VEaXJ0eSh0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wLHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b20pLCEwfSx0LnByb3RvdHlwZS5zY3JvbGxEb3duPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1lLnBhcmFtc1swXXx8MTt0LS07KXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5zcGxpY2UodGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3RoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b20sMSksdGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLnNwbGljZSh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrdGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbFRvcCwwLHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXRCbGFua0xpbmUoZi5ERUZBVUxUX0FUVFJfREFUQSkpO3JldHVybiB0aGlzLl9kaXJ0eVJvd1NlcnZpY2UubWFya1JhbmdlRGlydHkodGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbFRvcCx0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tKSwhMH0sdC5wcm90b3R5cGUuc2Nyb2xsTGVmdD1mdW5jdGlvbihlKXtpZih0aGlzLl9hY3RpdmVCdWZmZXIueT50aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tfHx0aGlzLl9hY3RpdmVCdWZmZXIueTx0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wKXJldHVybiEwO2Zvcih2YXIgdD1lLnBhcmFtc1swXXx8MSxyPXRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3A7cjw9dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbTsrK3Ipe3ZhciBpPXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5nZXQodGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3IpO2kuZGVsZXRlQ2VsbHMoMCx0LHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXROdWxsQ2VsbCh0aGlzLl9lcmFzZUF0dHJEYXRhKCkpLHRoaXMuX2VyYXNlQXR0ckRhdGEoKSksaS5pc1dyYXBwZWQ9ITF9cmV0dXJuIHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrUmFuZ2VEaXJ0eSh0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wLHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b20pLCEwfSx0LnByb3RvdHlwZS5zY3JvbGxSaWdodD1mdW5jdGlvbihlKXtpZih0aGlzLl9hY3RpdmVCdWZmZXIueT50aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tfHx0aGlzLl9hY3RpdmVCdWZmZXIueTx0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wKXJldHVybiEwO2Zvcih2YXIgdD1lLnBhcmFtc1swXXx8MSxyPXRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3A7cjw9dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbTsrK3Ipe3ZhciBpPXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5nZXQodGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3IpO2kuaW5zZXJ0Q2VsbHMoMCx0LHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXROdWxsQ2VsbCh0aGlzLl9lcmFzZUF0dHJEYXRhKCkpLHRoaXMuX2VyYXNlQXR0ckRhdGEoKSksaS5pc1dyYXBwZWQ9ITF9cmV0dXJuIHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrUmFuZ2VEaXJ0eSh0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wLHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b20pLCEwfSx0LnByb3RvdHlwZS5pbnNlcnRDb2x1bW5zPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2FjdGl2ZUJ1ZmZlci55PnRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b218fHRoaXMuX2FjdGl2ZUJ1ZmZlci55PHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3ApcmV0dXJuITA7Zm9yKHZhciB0PWUucGFyYW1zWzBdfHwxLHI9dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbFRvcDtyPD10aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tOysrcil7dmFyIGk9dGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLmdldCh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2Urcik7aS5pbnNlcnRDZWxscyh0aGlzLl9hY3RpdmVCdWZmZXIueCx0LHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXROdWxsQ2VsbCh0aGlzLl9lcmFzZUF0dHJEYXRhKCkpLHRoaXMuX2VyYXNlQXR0ckRhdGEoKSksaS5pc1dyYXBwZWQ9ITF9cmV0dXJuIHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrUmFuZ2VEaXJ0eSh0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wLHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b20pLCEwfSx0LnByb3RvdHlwZS5kZWxldGVDb2x1bW5zPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2FjdGl2ZUJ1ZmZlci55PnRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b218fHRoaXMuX2FjdGl2ZUJ1ZmZlci55PHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3ApcmV0dXJuITA7Zm9yKHZhciB0PWUucGFyYW1zWzBdfHwxLHI9dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbFRvcDtyPD10aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tOysrcil7dmFyIGk9dGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLmdldCh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2Urcik7aS5kZWxldGVDZWxscyh0aGlzLl9hY3RpdmVCdWZmZXIueCx0LHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXROdWxsQ2VsbCh0aGlzLl9lcmFzZUF0dHJEYXRhKCkpLHRoaXMuX2VyYXNlQXR0ckRhdGEoKSksaS5pc1dyYXBwZWQ9ITF9cmV0dXJuIHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrUmFuZ2VEaXJ0eSh0aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wLHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b20pLCEwfSx0LnByb3RvdHlwZS5lcmFzZUNoYXJzPWZ1bmN0aW9uKGUpe3RoaXMuX3Jlc3RyaWN0Q3Vyc29yKCk7dmFyIHQ9dGhpcy5fYWN0aXZlQnVmZmVyLmxpbmVzLmdldCh0aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrdGhpcy5fYWN0aXZlQnVmZmVyLnkpO3JldHVybiB0JiYodC5yZXBsYWNlQ2VsbHModGhpcy5fYWN0aXZlQnVmZmVyLngsdGhpcy5fYWN0aXZlQnVmZmVyLngrKGUucGFyYW1zWzBdfHwxKSx0aGlzLl9hY3RpdmVCdWZmZXIuZ2V0TnVsbENlbGwodGhpcy5fZXJhc2VBdHRyRGF0YSgpKSx0aGlzLl9lcmFzZUF0dHJEYXRhKCkpLHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrRGlydHkodGhpcy5fYWN0aXZlQnVmZmVyLnkpKSwhMH0sdC5wcm90b3R5cGUucmVwZWF0UHJlY2VkaW5nQ2hhcmFjdGVyPWZ1bmN0aW9uKGUpe2lmKCF0aGlzLl9wYXJzZXIucHJlY2VkaW5nQ29kZXBvaW50KXJldHVybiEwO2Zvcih2YXIgdD1lLnBhcmFtc1swXXx8MSxyPW5ldyBVaW50MzJBcnJheSh0KSxpPTA7aTx0OysraSlyW2ldPXRoaXMuX3BhcnNlci5wcmVjZWRpbmdDb2RlcG9pbnQ7cmV0dXJuIHRoaXMucHJpbnQociwwLHIubGVuZ3RoKSwhMH0sdC5wcm90b3R5cGUuc2VuZERldmljZUF0dHJpYnV0ZXNQcmltYXJ5PWZ1bmN0aW9uKGUpe3JldHVybiBlLnBhcmFtc1swXT4wfHwodGhpcy5faXMoInh0ZXJtIil8fHRoaXMuX2lzKCJyeHZ0LXVuaWNvZGUiKXx8dGhpcy5faXMoInNjcmVlbiIpP3RoaXMuX2NvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQocy5DMC5FU0MrIls/MTsyYyIpOnRoaXMuX2lzKCJsaW51eCIpJiZ0aGlzLl9jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KHMuQzAuRVNDKyJbPzZjIikpLCEwfSx0LnByb3RvdHlwZS5zZW5kRGV2aWNlQXR0cmlidXRlc1NlY29uZGFyeT1mdW5jdGlvbihlKXtyZXR1cm4gZS5wYXJhbXNbMF0+MHx8KHRoaXMuX2lzKCJ4dGVybSIpP3RoaXMuX2NvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQocy5DMC5FU0MrIls+MDsyNzY7MGMiKTp0aGlzLl9pcygicnh2dC11bmljb2RlIik/dGhpcy5fY29yZVNlcnZpY2UudHJpZ2dlckRhdGFFdmVudChzLkMwLkVTQysiWz44NTs5NTswYyIpOnRoaXMuX2lzKCJsaW51eCIpP3RoaXMuX2NvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQoZS5wYXJhbXNbMF0rImMiKTp0aGlzLl9pcygic2NyZWVuIikmJnRoaXMuX2NvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQocy5DMC5FU0MrIls+ODM7NDAwMDM7MGMiKSksITB9LHQucHJvdG90eXBlLl9pcz1mdW5jdGlvbihlKXtyZXR1cm4gMD09PSh0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLnRlcm1OYW1lKyIiKS5pbmRleE9mKGUpfSx0LnByb3RvdHlwZS5zZXRNb2RlPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0wO3Q8ZS5sZW5ndGg7dCsrKTQ9PT1lLnBhcmFtc1t0XSYmKHRoaXMuX2NvcmVTZXJ2aWNlLm1vZGVzLmluc2VydE1vZGU9ITApO3JldHVybiEwfSx0LnByb3RvdHlwZS5zZXRNb2RlUHJpdmF0ZT1mdW5jdGlvbihlKXtmb3IodmFyIHQ9MDt0PGUubGVuZ3RoO3QrKylzd2l0Y2goZS5wYXJhbXNbdF0pe2Nhc2UgMTp0aGlzLl9jb3JlU2VydmljZS5kZWNQcml2YXRlTW9kZXMuYXBwbGljYXRpb25DdXJzb3JLZXlzPSEwO2JyZWFrO2Nhc2UgMjp0aGlzLl9jaGFyc2V0U2VydmljZS5zZXRnQ2hhcnNldCgwLGEuREVGQVVMVF9DSEFSU0VUKSx0aGlzLl9jaGFyc2V0U2VydmljZS5zZXRnQ2hhcnNldCgxLGEuREVGQVVMVF9DSEFSU0VUKSx0aGlzLl9jaGFyc2V0U2VydmljZS5zZXRnQ2hhcnNldCgyLGEuREVGQVVMVF9DSEFSU0VUKSx0aGlzLl9jaGFyc2V0U2VydmljZS5zZXRnQ2hhcnNldCgzLGEuREVGQVVMVF9DSEFSU0VUKTticmVhaztjYXNlIDM6dGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy53aW5kb3dPcHRpb25zLnNldFdpbkxpbmVzJiYodGhpcy5fYnVmZmVyU2VydmljZS5yZXNpemUoMTMyLHRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyksdGhpcy5fb25SZXF1ZXN0UmVzZXQuZmlyZSgpKTticmVhaztjYXNlIDY6dGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLm9yaWdpbj0hMCx0aGlzLl9zZXRDdXJzb3IoMCwwKTticmVhaztjYXNlIDc6dGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLndyYXBhcm91bmQ9ITA7YnJlYWs7Y2FzZSAxMjpicmVhaztjYXNlIDQ1OnRoaXMuX2NvcmVTZXJ2aWNlLmRlY1ByaXZhdGVNb2Rlcy5yZXZlcnNlV3JhcGFyb3VuZD0hMDticmVhaztjYXNlIDY2OnRoaXMuX2xvZ1NlcnZpY2UuZGVidWcoIlNlcmlhbCBwb3J0IHJlcXVlc3RlZCBhcHBsaWNhdGlvbiBrZXlwYWQuIiksdGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLmFwcGxpY2F0aW9uS2V5cGFkPSEwLHRoaXMuX29uUmVxdWVzdFN5bmNTY3JvbGxCYXIuZmlyZSgpO2JyZWFrO2Nhc2UgOTp0aGlzLl9jb3JlTW91c2VTZXJ2aWNlLmFjdGl2ZVByb3RvY29sPSJYMTAiO2JyZWFrO2Nhc2UgMWUzOnRoaXMuX2NvcmVNb3VzZVNlcnZpY2UuYWN0aXZlUHJvdG9jb2w9IlZUMjAwIjticmVhaztjYXNlIDEwMDI6dGhpcy5fY29yZU1vdXNlU2VydmljZS5hY3RpdmVQcm90b2NvbD0iRFJBRyI7YnJlYWs7Y2FzZSAxMDAzOnRoaXMuX2NvcmVNb3VzZVNlcnZpY2UuYWN0aXZlUHJvdG9jb2w9IkFOWSI7YnJlYWs7Y2FzZSAxMDA0OnRoaXMuX2NvcmVTZXJ2aWNlLmRlY1ByaXZhdGVNb2Rlcy5zZW5kRm9jdXM9ITAsdGhpcy5fb25SZXF1ZXN0U2VuZEZvY3VzLmZpcmUoKTticmVhaztjYXNlIDEwMDU6dGhpcy5fbG9nU2VydmljZS5kZWJ1ZygiREVDU0VUIDEwMDUgbm90IHN1cHBvcnRlZCAoc2VlICMyNTA3KSIpO2JyZWFrO2Nhc2UgMTAwNjp0aGlzLl9jb3JlTW91c2VTZXJ2aWNlLmFjdGl2ZUVuY29kaW5nPSJTR1IiO2JyZWFrO2Nhc2UgMTAxNTp0aGlzLl9sb2dTZXJ2aWNlLmRlYnVnKCJERUNTRVQgMTAxNSBub3Qgc3VwcG9ydGVkIChzZWUgIzI1MDcpIik7YnJlYWs7Y2FzZSAyNTp0aGlzLl9jb3JlU2VydmljZS5pc0N1cnNvckhpZGRlbj0hMTticmVhaztjYXNlIDEwNDg6dGhpcy5zYXZlQ3Vyc29yKCk7YnJlYWs7Y2FzZSAxMDQ5OnRoaXMuc2F2ZUN1cnNvcigpO2Nhc2UgNDc6Y2FzZSAxMDQ3OnRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVycy5hY3RpdmF0ZUFsdEJ1ZmZlcih0aGlzLl9lcmFzZUF0dHJEYXRhKCkpLHRoaXMuX2NvcmVTZXJ2aWNlLmlzQ3Vyc29ySW5pdGlhbGl6ZWQ9ITAsdGhpcy5fb25SZXF1ZXN0UmVmcmVzaFJvd3MuZmlyZSgwLHRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cy0xKSx0aGlzLl9vblJlcXVlc3RTeW5jU2Nyb2xsQmFyLmZpcmUoKTticmVhaztjYXNlIDIwMDQ6dGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLmJyYWNrZXRlZFBhc3RlTW9kZT0hMH1yZXR1cm4hMH0sdC5wcm90b3R5cGUucmVzZXRNb2RlPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0wO3Q8ZS5sZW5ndGg7dCsrKTQ9PT1lLnBhcmFtc1t0XSYmKHRoaXMuX2NvcmVTZXJ2aWNlLm1vZGVzLmluc2VydE1vZGU9ITEpO3JldHVybiEwfSx0LnByb3RvdHlwZS5yZXNldE1vZGVQcml2YXRlPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0wO3Q8ZS5sZW5ndGg7dCsrKXN3aXRjaChlLnBhcmFtc1t0XSl7Y2FzZSAxOnRoaXMuX2NvcmVTZXJ2aWNlLmRlY1ByaXZhdGVNb2Rlcy5hcHBsaWNhdGlvbkN1cnNvcktleXM9ITE7YnJlYWs7Y2FzZSAzOnRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMud2luZG93T3B0aW9ucy5zZXRXaW5MaW5lcyYmKHRoaXMuX2J1ZmZlclNlcnZpY2UucmVzaXplKDgwLHRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyksdGhpcy5fb25SZXF1ZXN0UmVzZXQuZmlyZSgpKTticmVhaztjYXNlIDY6dGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLm9yaWdpbj0hMSx0aGlzLl9zZXRDdXJzb3IoMCwwKTticmVhaztjYXNlIDc6dGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLndyYXBhcm91bmQ9ITE7YnJlYWs7Y2FzZSAxMjpicmVhaztjYXNlIDQ1OnRoaXMuX2NvcmVTZXJ2aWNlLmRlY1ByaXZhdGVNb2Rlcy5yZXZlcnNlV3JhcGFyb3VuZD0hMTticmVhaztjYXNlIDY2OnRoaXMuX2xvZ1NlcnZpY2UuZGVidWcoIlN3aXRjaGluZyBiYWNrIHRvIG5vcm1hbCBrZXlwYWQuIiksdGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLmFwcGxpY2F0aW9uS2V5cGFkPSExLHRoaXMuX29uUmVxdWVzdFN5bmNTY3JvbGxCYXIuZmlyZSgpO2JyZWFrO2Nhc2UgOTpjYXNlIDFlMzpjYXNlIDEwMDI6Y2FzZSAxMDAzOnRoaXMuX2NvcmVNb3VzZVNlcnZpY2UuYWN0aXZlUHJvdG9jb2w9Ik5PTkUiO2JyZWFrO2Nhc2UgMTAwNDp0aGlzLl9jb3JlU2VydmljZS5kZWNQcml2YXRlTW9kZXMuc2VuZEZvY3VzPSExO2JyZWFrO2Nhc2UgMTAwNTp0aGlzLl9sb2dTZXJ2aWNlLmRlYnVnKCJERUNSU1QgMTAwNSBub3Qgc3VwcG9ydGVkIChzZWUgIzI1MDcpIik7YnJlYWs7Y2FzZSAxMDA2OnRoaXMuX2NvcmVNb3VzZVNlcnZpY2UuYWN0aXZlRW5jb2Rpbmc9IkRFRkFVTFQiO2JyZWFrO2Nhc2UgMTAxNTp0aGlzLl9sb2dTZXJ2aWNlLmRlYnVnKCJERUNSU1QgMTAxNSBub3Qgc3VwcG9ydGVkIChzZWUgIzI1MDcpIik7YnJlYWs7Y2FzZSAyNTp0aGlzLl9jb3JlU2VydmljZS5pc0N1cnNvckhpZGRlbj0hMDticmVhaztjYXNlIDEwNDg6dGhpcy5yZXN0b3JlQ3Vyc29yKCk7YnJlYWs7Y2FzZSAxMDQ5OmNhc2UgNDc6Y2FzZSAxMDQ3OnRoaXMuX2J1ZmZlclNlcnZpY2UuYnVmZmVycy5hY3RpdmF0ZU5vcm1hbEJ1ZmZlcigpLDEwNDk9PT1lLnBhcmFtc1t0XSYmdGhpcy5yZXN0b3JlQ3Vyc29yKCksdGhpcy5fY29yZVNlcnZpY2UuaXNDdXJzb3JJbml0aWFsaXplZD0hMCx0aGlzLl9vblJlcXVlc3RSZWZyZXNoUm93cy5maXJlKDAsdGhpcy5fYnVmZmVyU2VydmljZS5yb3dzLTEpLHRoaXMuX29uUmVxdWVzdFN5bmNTY3JvbGxCYXIuZmlyZSgpO2JyZWFrO2Nhc2UgMjAwNDp0aGlzLl9jb3JlU2VydmljZS5kZWNQcml2YXRlTW9kZXMuYnJhY2tldGVkUGFzdGVNb2RlPSExfXJldHVybiEwfSx0LnByb3RvdHlwZS5fdXBkYXRlQXR0ckNvbG9yPWZ1bmN0aW9uKGUsdCxyLGksbil7cmV0dXJuIDI9PT10PyhlfD01MDMzMTY0OCxlJj0tMTY3NzcyMTYsZXw9di5BdHRyaWJ1dGVEYXRhLmZyb21Db2xvclJHQihbcixpLG5dKSk6NT09PXQmJihlJj0tNTAzMzE5MDQsZXw9MzM1NTQ0MzJ8MjU1JnIpLGV9LHQucHJvdG90eXBlLl9leHRyYWN0Q29sb3I9ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPVswLDAsLTEsMCwwLDBdLG49MCxvPTA7ZG97aWYoaVtvK25dPWUucGFyYW1zW3Qrb10sZS5oYXNTdWJQYXJhbXModCtvKSl7dmFyIHM9ZS5nZXRTdWJQYXJhbXModCtvKSxhPTA7ZG97NT09PWlbMV0mJihuPTEpLGlbbythKzErbl09c1thXX13aGlsZSgrK2E8cy5sZW5ndGgmJmErbysxK248aS5sZW5ndGgpO2JyZWFrfWlmKDU9PT1pWzFdJiZvK24+PTJ8fDI9PT1pWzFdJiZvK24+PTUpYnJlYWs7aVsxXSYmKG49MSl9d2hpbGUoKytvK3Q8ZS5sZW5ndGgmJm8rbjxpLmxlbmd0aCk7Zm9yKGE9MjthPGkubGVuZ3RoOysrYSktMT09PWlbYV0mJihpW2FdPTApO3N3aXRjaChpWzBdKXtjYXNlIDM4OnIuZmc9dGhpcy5fdXBkYXRlQXR0ckNvbG9yKHIuZmcsaVsxXSxpWzNdLGlbNF0saVs1XSk7YnJlYWs7Y2FzZSA0ODpyLmJnPXRoaXMuX3VwZGF0ZUF0dHJDb2xvcihyLmJnLGlbMV0saVszXSxpWzRdLGlbNV0pO2JyZWFrO2Nhc2UgNTg6ci5leHRlbmRlZD1yLmV4dGVuZGVkLmNsb25lKCksci5leHRlbmRlZC51bmRlcmxpbmVDb2xvcj10aGlzLl91cGRhdGVBdHRyQ29sb3Ioci5leHRlbmRlZC51bmRlcmxpbmVDb2xvcixpWzFdLGlbM10saVs0XSxpWzVdKX1yZXR1cm4gb30sdC5wcm90b3R5cGUuX3Byb2Nlc3NVbmRlcmxpbmU9ZnVuY3Rpb24oZSx0KXt0LmV4dGVuZGVkPXQuZXh0ZW5kZWQuY2xvbmUoKSwoIX5lfHxlPjUpJiYoZT0xKSx0LmV4dGVuZGVkLnVuZGVybGluZVN0eWxlPWUsdC5mZ3w9MjY4NDM1NDU2LDA9PT1lJiYodC5mZyY9LTI2ODQzNTQ1NyksdC51cGRhdGVFeHRlbmRlZCgpfSx0LnByb3RvdHlwZS5jaGFyQXR0cmlidXRlcz1mdW5jdGlvbihlKXtpZigxPT09ZS5sZW5ndGgmJjA9PT1lLnBhcmFtc1swXSlyZXR1cm4gdGhpcy5fY3VyQXR0ckRhdGEuZmc9Zi5ERUZBVUxUX0FUVFJfREFUQS5mZyx0aGlzLl9jdXJBdHRyRGF0YS5iZz1mLkRFRkFVTFRfQVRUUl9EQVRBLmJnLCEwO2Zvcih2YXIgdCxyPWUubGVuZ3RoLGk9dGhpcy5fY3VyQXR0ckRhdGEsbj0wO248cjtuKyspKHQ9ZS5wYXJhbXNbbl0pPj0zMCYmdDw9Mzc/KGkuZmcmPS01MDMzMTkwNCxpLmZnfD0xNjc3NzIxNnx0LTMwKTp0Pj00MCYmdDw9NDc/KGkuYmcmPS01MDMzMTkwNCxpLmJnfD0xNjc3NzIxNnx0LTQwKTp0Pj05MCYmdDw9OTc/KGkuZmcmPS01MDMzMTkwNCxpLmZnfD0xNjc3NzIyNHx0LTkwKTp0Pj0xMDAmJnQ8PTEwNz8oaS5iZyY9LTUwMzMxOTA0LGkuYmd8PTE2Nzc3MjI0fHQtMTAwKTowPT09dD8oaS5mZz1mLkRFRkFVTFRfQVRUUl9EQVRBLmZnLGkuYmc9Zi5ERUZBVUxUX0FUVFJfREFUQS5iZyk6MT09PXQ/aS5mZ3w9MTM0MjE3NzI4OjM9PT10P2kuYmd8PTY3MTA4ODY0OjQ9PT10PyhpLmZnfD0yNjg0MzU0NTYsdGhpcy5fcHJvY2Vzc1VuZGVybGluZShlLmhhc1N1YlBhcmFtcyhuKT9lLmdldFN1YlBhcmFtcyhuKVswXToxLGkpKTo1PT09dD9pLmZnfD01MzY4NzA5MTI6Nz09PXQ/aS5mZ3w9NjcxMDg4NjQ6OD09PXQ/aS5mZ3w9MTA3Mzc0MTgyNDo5PT09dD9pLmZnfD0yMTQ3NDgzNjQ4OjI9PT10P2kuYmd8PTEzNDIxNzcyODoyMT09PXQ/dGhpcy5fcHJvY2Vzc1VuZGVybGluZSgyLGkpOjIyPT09dD8oaS5mZyY9LTEzNDIxNzcyOSxpLmJnJj0tMTM0MjE3NzI5KToyMz09PXQ/aS5iZyY9LTY3MTA4ODY1OjI0PT09dD9pLmZnJj0tMjY4NDM1NDU3OjI1PT09dD9pLmZnJj0tNTM2ODcwOTEzOjI3PT09dD9pLmZnJj0tNjcxMDg4NjU6Mjg9PT10P2kuZmcmPS0xMDczNzQxODI1OjI5PT09dD9pLmZnJj0yMTQ3NDgzNjQ3OjM5PT09dD8oaS5mZyY9LTY3MTA4ODY0LGkuZmd8PTE2Nzc3MjE1JmYuREVGQVVMVF9BVFRSX0RBVEEuZmcpOjQ5PT09dD8oaS5iZyY9LTY3MTA4ODY0LGkuYmd8PTE2Nzc3MjE1JmYuREVGQVVMVF9BVFRSX0RBVEEuYmcpOjM4PT09dHx8NDg9PT10fHw1OD09PXQ/bis9dGhpcy5fZXh0cmFjdENvbG9yKGUsbixpKTo1OT09PXQ/KGkuZXh0ZW5kZWQ9aS5leHRlbmRlZC5jbG9uZSgpLGkuZXh0ZW5kZWQudW5kZXJsaW5lQ29sb3I9LTEsaS51cGRhdGVFeHRlbmRlZCgpKToxMDA9PT10PyhpLmZnJj0tNjcxMDg4NjQsaS5mZ3w9MTY3NzcyMTUmZi5ERUZBVUxUX0FUVFJfREFUQS5mZyxpLmJnJj0tNjcxMDg4NjQsaS5iZ3w9MTY3NzcyMTUmZi5ERUZBVUxUX0FUVFJfREFUQS5iZyk6dGhpcy5fbG9nU2VydmljZS5kZWJ1ZygiVW5rbm93biBTR1IgYXR0cmlidXRlOiAlZC4iLHQpO3JldHVybiEwfSx0LnByb3RvdHlwZS5kZXZpY2VTdGF0dXM9ZnVuY3Rpb24oZSl7c3dpdGNoKGUucGFyYW1zWzBdKXtjYXNlIDU6dGhpcy5fY29yZVNlcnZpY2UudHJpZ2dlckRhdGFFdmVudChzLkMwLkVTQysiWzBuIik7YnJlYWs7Y2FzZSA2OnZhciB0PXRoaXMuX2FjdGl2ZUJ1ZmZlci55KzEscj10aGlzLl9hY3RpdmVCdWZmZXIueCsxO3RoaXMuX2NvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQocy5DMC5FU0MrIlsiK3QrIjsiK3IrIlIiKX1yZXR1cm4hMH0sdC5wcm90b3R5cGUuZGV2aWNlU3RhdHVzUHJpdmF0ZT1mdW5jdGlvbihlKXtpZig2PT09ZS5wYXJhbXNbMF0pe3ZhciB0PXRoaXMuX2FjdGl2ZUJ1ZmZlci55KzEscj10aGlzLl9hY3RpdmVCdWZmZXIueCsxO3RoaXMuX2NvcmVTZXJ2aWNlLnRyaWdnZXJEYXRhRXZlbnQocy5DMC5FU0MrIls/Iit0KyI7IityKyJSIil9cmV0dXJuITB9LHQucHJvdG90eXBlLnNvZnRSZXNldD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fY29yZVNlcnZpY2UuaXNDdXJzb3JIaWRkZW49ITEsdGhpcy5fb25SZXF1ZXN0U3luY1Njcm9sbEJhci5maXJlKCksdGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbFRvcD0wLHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b209dGhpcy5fYnVmZmVyU2VydmljZS5yb3dzLTEsdGhpcy5fY3VyQXR0ckRhdGE9Zi5ERUZBVUxUX0FUVFJfREFUQS5jbG9uZSgpLHRoaXMuX2NvcmVTZXJ2aWNlLnJlc2V0KCksdGhpcy5fY2hhcnNldFNlcnZpY2UucmVzZXQoKSx0aGlzLl9hY3RpdmVCdWZmZXIuc2F2ZWRYPTAsdGhpcy5fYWN0aXZlQnVmZmVyLnNhdmVkWT10aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UsdGhpcy5fYWN0aXZlQnVmZmVyLnNhdmVkQ3VyQXR0ckRhdGEuZmc9dGhpcy5fY3VyQXR0ckRhdGEuZmcsdGhpcy5fYWN0aXZlQnVmZmVyLnNhdmVkQ3VyQXR0ckRhdGEuYmc9dGhpcy5fY3VyQXR0ckRhdGEuYmcsdGhpcy5fYWN0aXZlQnVmZmVyLnNhdmVkQ2hhcnNldD10aGlzLl9jaGFyc2V0U2VydmljZS5jaGFyc2V0LHRoaXMuX2NvcmVTZXJ2aWNlLmRlY1ByaXZhdGVNb2Rlcy5vcmlnaW49ITEsITB9LHQucHJvdG90eXBlLnNldEN1cnNvclN0eWxlPWZ1bmN0aW9uKGUpe3ZhciB0PWUucGFyYW1zWzBdfHwxO3N3aXRjaCh0KXtjYXNlIDE6Y2FzZSAyOnRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuY3Vyc29yU3R5bGU9ImJsb2NrIjticmVhaztjYXNlIDM6Y2FzZSA0OnRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuY3Vyc29yU3R5bGU9InVuZGVybGluZSI7YnJlYWs7Y2FzZSA1OmNhc2UgNjp0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmN1cnNvclN0eWxlPSJiYXIifXZhciByPXQlMj09MTtyZXR1cm4gdGhpcy5fb3B0aW9uc1NlcnZpY2Uub3B0aW9ucy5jdXJzb3JCbGluaz1yLCEwfSx0LnByb3RvdHlwZS5zZXRTY3JvbGxSZWdpb249ZnVuY3Rpb24oZSl7dmFyIHQscj1lLnBhcmFtc1swXXx8MTtyZXR1cm4oZS5sZW5ndGg8Mnx8KHQ9ZS5wYXJhbXNbMV0pPnRoaXMuX2J1ZmZlclNlcnZpY2Uucm93c3x8MD09PXQpJiYodD10aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MpLHQ+ciYmKHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3A9ci0xLHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxCb3R0b209dC0xLHRoaXMuX3NldEN1cnNvcigwLDApKSwhMH0sdC5wcm90b3R5cGUud2luZG93T3B0aW9ucz1mdW5jdGlvbihlKXtpZighdyhlLnBhcmFtc1swXSx0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLndpbmRvd09wdGlvbnMpKXJldHVybiEwO3ZhciB0PWUubGVuZ3RoPjE/ZS5wYXJhbXNbMV06MDtzd2l0Y2goZS5wYXJhbXNbMF0pe2Nhc2UgMTQ6MiE9PXQmJnRoaXMuX29uUmVxdWVzdFdpbmRvd3NPcHRpb25zUmVwb3J0LmZpcmUoby5HRVRfV0lOX1NJWkVfUElYRUxTKTticmVhaztjYXNlIDE2OnRoaXMuX29uUmVxdWVzdFdpbmRvd3NPcHRpb25zUmVwb3J0LmZpcmUoby5HRVRfQ0VMTF9TSVpFX1BJWEVMUyk7YnJlYWs7Y2FzZSAxODp0aGlzLl9idWZmZXJTZXJ2aWNlJiZ0aGlzLl9jb3JlU2VydmljZS50cmlnZ2VyRGF0YUV2ZW50KHMuQzAuRVNDKyJbODsiK3RoaXMuX2J1ZmZlclNlcnZpY2Uucm93cysiOyIrdGhpcy5fYnVmZmVyU2VydmljZS5jb2xzKyJ0Iik7YnJlYWs7Y2FzZSAyMjowIT09dCYmMiE9PXR8fCh0aGlzLl93aW5kb3dUaXRsZVN0YWNrLnB1c2godGhpcy5fd2luZG93VGl0bGUpLHRoaXMuX3dpbmRvd1RpdGxlU3RhY2subGVuZ3RoPjEwJiZ0aGlzLl93aW5kb3dUaXRsZVN0YWNrLnNoaWZ0KCkpLDAhPT10JiYxIT09dHx8KHRoaXMuX2ljb25OYW1lU3RhY2sucHVzaCh0aGlzLl9pY29uTmFtZSksdGhpcy5faWNvbk5hbWVTdGFjay5sZW5ndGg+MTAmJnRoaXMuX2ljb25OYW1lU3RhY2suc2hpZnQoKSk7YnJlYWs7Y2FzZSAyMzowIT09dCYmMiE9PXR8fHRoaXMuX3dpbmRvd1RpdGxlU3RhY2subGVuZ3RoJiZ0aGlzLnNldFRpdGxlKHRoaXMuX3dpbmRvd1RpdGxlU3RhY2sucG9wKCkpLDAhPT10JiYxIT09dHx8dGhpcy5faWNvbk5hbWVTdGFjay5sZW5ndGgmJnRoaXMuc2V0SWNvbk5hbWUodGhpcy5faWNvbk5hbWVTdGFjay5wb3AoKSl9cmV0dXJuITB9LHQucHJvdG90eXBlLnNhdmVDdXJzb3I9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX2FjdGl2ZUJ1ZmZlci5zYXZlZFg9dGhpcy5fYWN0aXZlQnVmZmVyLngsdGhpcy5fYWN0aXZlQnVmZmVyLnNhdmVkWT10aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrdGhpcy5fYWN0aXZlQnVmZmVyLnksdGhpcy5fYWN0aXZlQnVmZmVyLnNhdmVkQ3VyQXR0ckRhdGEuZmc9dGhpcy5fY3VyQXR0ckRhdGEuZmcsdGhpcy5fYWN0aXZlQnVmZmVyLnNhdmVkQ3VyQXR0ckRhdGEuYmc9dGhpcy5fY3VyQXR0ckRhdGEuYmcsdGhpcy5fYWN0aXZlQnVmZmVyLnNhdmVkQ2hhcnNldD10aGlzLl9jaGFyc2V0U2VydmljZS5jaGFyc2V0LCEwfSx0LnByb3RvdHlwZS5yZXN0b3JlQ3Vyc29yPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9hY3RpdmVCdWZmZXIueD10aGlzLl9hY3RpdmVCdWZmZXIuc2F2ZWRYfHwwLHRoaXMuX2FjdGl2ZUJ1ZmZlci55PU1hdGgubWF4KHRoaXMuX2FjdGl2ZUJ1ZmZlci5zYXZlZFktdGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlLDApLHRoaXMuX2N1ckF0dHJEYXRhLmZnPXRoaXMuX2FjdGl2ZUJ1ZmZlci5zYXZlZEN1ckF0dHJEYXRhLmZnLHRoaXMuX2N1ckF0dHJEYXRhLmJnPXRoaXMuX2FjdGl2ZUJ1ZmZlci5zYXZlZEN1ckF0dHJEYXRhLmJnLHRoaXMuX2NoYXJzZXRTZXJ2aWNlLmNoYXJzZXQ9dGhpcy5fc2F2ZWRDaGFyc2V0LHRoaXMuX2FjdGl2ZUJ1ZmZlci5zYXZlZENoYXJzZXQmJih0aGlzLl9jaGFyc2V0U2VydmljZS5jaGFyc2V0PXRoaXMuX2FjdGl2ZUJ1ZmZlci5zYXZlZENoYXJzZXQpLHRoaXMuX3Jlc3RyaWN0Q3Vyc29yKCksITB9LHQucHJvdG90eXBlLnNldFRpdGxlPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl93aW5kb3dUaXRsZT1lLHRoaXMuX29uVGl0bGVDaGFuZ2UuZmlyZShlKSwhMH0sdC5wcm90b3R5cGUuc2V0SWNvbk5hbWU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX2ljb25OYW1lPWUsITB9LHQucHJvdG90eXBlLnNldE9yUmVwb3J0SW5kZXhlZENvbG9yPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1bXSxyPWUuc3BsaXQoIjsiKTtyLmxlbmd0aD4xOyl7dmFyIGk9ci5zaGlmdCgpLG49ci5zaGlmdCgpO2lmKC9eXGQrJC8uZXhlYyhpKSl7dmFyIG89cGFyc2VJbnQoaSk7aWYoMDw9byYmbzwyNTYpaWYoIj8iPT09bil0LnB1c2goe3R5cGU6MCxpbmRleDpvfSk7ZWxzZXt2YXIgcz0oMCxiLnBhcnNlQ29sb3IpKG4pO3MmJnQucHVzaCh7dHlwZToxLGluZGV4Om8sY29sb3I6c30pfX19cmV0dXJuIHQubGVuZ3RoJiZ0aGlzLl9vbkNvbG9yLmZpcmUodCksITB9LHQucHJvdG90eXBlLl9zZXRPclJlcG9ydFNwZWNpYWxDb2xvcj1mdW5jdGlvbihlLHQpe2Zvcih2YXIgcj1lLnNwbGl0KCI7IiksaT0wO2k8ci5sZW5ndGgmJiEodD49dGhpcy5fc3BlY2lhbENvbG9ycy5sZW5ndGgpOysraSwrK3QpaWYoIj8iPT09cltpXSl0aGlzLl9vbkNvbG9yLmZpcmUoW3t0eXBlOjAsaW5kZXg6dGhpcy5fc3BlY2lhbENvbG9yc1t0XX1dKTtlbHNle3ZhciBuPSgwLGIucGFyc2VDb2xvcikocltpXSk7biYmdGhpcy5fb25Db2xvci5maXJlKFt7dHlwZToxLGluZGV4OnRoaXMuX3NwZWNpYWxDb2xvcnNbdF0sY29sb3I6bn1dKX1yZXR1cm4hMH0sdC5wcm90b3R5cGUuc2V0T3JSZXBvcnRGZ0NvbG9yPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9zZXRPclJlcG9ydFNwZWNpYWxDb2xvcihlLDApfSx0LnByb3RvdHlwZS5zZXRPclJlcG9ydEJnQ29sb3I9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX3NldE9yUmVwb3J0U3BlY2lhbENvbG9yKGUsMSl9LHQucHJvdG90eXBlLnNldE9yUmVwb3J0Q3Vyc29yQ29sb3I9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX3NldE9yUmVwb3J0U3BlY2lhbENvbG9yKGUsMil9LHQucHJvdG90eXBlLnJlc3RvcmVJbmRleGVkQ29sb3I9ZnVuY3Rpb24oZSl7aWYoIWUpcmV0dXJuIHRoaXMuX29uQ29sb3IuZmlyZShbe3R5cGU6Mn1dKSwhMDtmb3IodmFyIHQ9W10scj1lLnNwbGl0KCI7IiksaT0wO2k8ci5sZW5ndGg7KytpKWlmKC9eXGQrJC8uZXhlYyhyW2ldKSl7dmFyIG49cGFyc2VJbnQocltpXSk7MDw9biYmbjwyNTYmJnQucHVzaCh7dHlwZToyLGluZGV4Om59KX1yZXR1cm4gdC5sZW5ndGgmJnRoaXMuX29uQ29sb3IuZmlyZSh0KSwhMH0sdC5wcm90b3R5cGUucmVzdG9yZUZnQ29sb3I9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX29uQ29sb3IuZmlyZShbe3R5cGU6MixpbmRleDoyNTZ9XSksITB9LHQucHJvdG90eXBlLnJlc3RvcmVCZ0NvbG9yPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9vbkNvbG9yLmZpcmUoW3t0eXBlOjIsaW5kZXg6MjU3fV0pLCEwfSx0LnByb3RvdHlwZS5yZXN0b3JlQ3Vyc29yQ29sb3I9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX29uQ29sb3IuZmlyZShbe3R5cGU6MixpbmRleDoyNTh9XSksITB9LHQucHJvdG90eXBlLm5leHRMaW5lPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2FjdGl2ZUJ1ZmZlci54PTAsdGhpcy5pbmRleCgpLCEwfSx0LnByb3RvdHlwZS5rZXlwYWRBcHBsaWNhdGlvbk1vZGU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fbG9nU2VydmljZS5kZWJ1ZygiU2VyaWFsIHBvcnQgcmVxdWVzdGVkIGFwcGxpY2F0aW9uIGtleXBhZC4iKSx0aGlzLl9jb3JlU2VydmljZS5kZWNQcml2YXRlTW9kZXMuYXBwbGljYXRpb25LZXlwYWQ9ITAsdGhpcy5fb25SZXF1ZXN0U3luY1Njcm9sbEJhci5maXJlKCksITB9LHQucHJvdG90eXBlLmtleXBhZE51bWVyaWNNb2RlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2xvZ1NlcnZpY2UuZGVidWcoIlN3aXRjaGluZyBiYWNrIHRvIG5vcm1hbCBrZXlwYWQuIiksdGhpcy5fY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLmFwcGxpY2F0aW9uS2V5cGFkPSExLHRoaXMuX29uUmVxdWVzdFN5bmNTY3JvbGxCYXIuZmlyZSgpLCEwfSx0LnByb3RvdHlwZS5zZWxlY3REZWZhdWx0Q2hhcnNldD1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9jaGFyc2V0U2VydmljZS5zZXRnTGV2ZWwoMCksdGhpcy5fY2hhcnNldFNlcnZpY2Uuc2V0Z0NoYXJzZXQoMCxhLkRFRkFVTFRfQ0hBUlNFVCksITB9LHQucHJvdG90eXBlLnNlbGVjdENoYXJzZXQ9ZnVuY3Rpb24oZSl7cmV0dXJuIDIhPT1lLmxlbmd0aD8odGhpcy5zZWxlY3REZWZhdWx0Q2hhcnNldCgpLCEwKTooIi8iPT09ZVswXXx8dGhpcy5fY2hhcnNldFNlcnZpY2Uuc2V0Z0NoYXJzZXQoU1tlWzBdXSxhLkNIQVJTRVRTW2VbMV1dfHxhLkRFRkFVTFRfQ0hBUlNFVCksITApfSx0LnByb3RvdHlwZS5pbmRleD1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9yZXN0cmljdEN1cnNvcigpLHRoaXMuX2FjdGl2ZUJ1ZmZlci55KyssdGhpcy5fYWN0aXZlQnVmZmVyLnk9PT10aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsQm90dG9tKzE/KHRoaXMuX2FjdGl2ZUJ1ZmZlci55LS0sdGhpcy5fYnVmZmVyU2VydmljZS5zY3JvbGwodGhpcy5fZXJhc2VBdHRyRGF0YSgpKSk6dGhpcy5fYWN0aXZlQnVmZmVyLnk+PXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cyYmKHRoaXMuX2FjdGl2ZUJ1ZmZlci55PXRoaXMuX2J1ZmZlclNlcnZpY2Uucm93cy0xKSx0aGlzLl9yZXN0cmljdEN1cnNvcigpLCEwfSx0LnByb3RvdHlwZS50YWJTZXQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fYWN0aXZlQnVmZmVyLnRhYnNbdGhpcy5fYWN0aXZlQnVmZmVyLnhdPSEwLCEwfSx0LnByb3RvdHlwZS5yZXZlcnNlSW5kZXg9ZnVuY3Rpb24oKXtpZih0aGlzLl9yZXN0cmljdEN1cnNvcigpLHRoaXMuX2FjdGl2ZUJ1ZmZlci55PT09dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbFRvcCl7dmFyIGU9dGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbS10aGlzLl9hY3RpdmVCdWZmZXIuc2Nyb2xsVG9wO3RoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5zaGlmdEVsZW1lbnRzKHRoaXMuX2FjdGl2ZUJ1ZmZlci55YmFzZSt0aGlzLl9hY3RpdmVCdWZmZXIueSxlLDEpLHRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5zZXQodGhpcy5fYWN0aXZlQnVmZmVyLnliYXNlK3RoaXMuX2FjdGl2ZUJ1ZmZlci55LHRoaXMuX2FjdGl2ZUJ1ZmZlci5nZXRCbGFua0xpbmUodGhpcy5fZXJhc2VBdHRyRGF0YSgpKSksdGhpcy5fZGlydHlSb3dTZXJ2aWNlLm1hcmtSYW5nZURpcnR5KHRoaXMuX2FjdGl2ZUJ1ZmZlci5zY3JvbGxUb3AsdGhpcy5fYWN0aXZlQnVmZmVyLnNjcm9sbEJvdHRvbSl9ZWxzZSB0aGlzLl9hY3RpdmVCdWZmZXIueS0tLHRoaXMuX3Jlc3RyaWN0Q3Vyc29yKCk7cmV0dXJuITB9LHQucHJvdG90eXBlLmZ1bGxSZXNldD1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9wYXJzZXIucmVzZXQoKSx0aGlzLl9vblJlcXVlc3RSZXNldC5maXJlKCksITB9LHQucHJvdG90eXBlLnJlc2V0PWZ1bmN0aW9uKCl7dGhpcy5fY3VyQXR0ckRhdGE9Zi5ERUZBVUxUX0FUVFJfREFUQS5jbG9uZSgpLHRoaXMuX2VyYXNlQXR0ckRhdGFJbnRlcm5hbD1mLkRFRkFVTFRfQVRUUl9EQVRBLmNsb25lKCl9LHQucHJvdG90eXBlLl9lcmFzZUF0dHJEYXRhPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2VyYXNlQXR0ckRhdGFJbnRlcm5hbC5iZyY9LTY3MTA4ODY0LHRoaXMuX2VyYXNlQXR0ckRhdGFJbnRlcm5hbC5iZ3w9NjcxMDg4NjMmdGhpcy5fY3VyQXR0ckRhdGEuYmcsdGhpcy5fZXJhc2VBdHRyRGF0YUludGVybmFsfSx0LnByb3RvdHlwZS5zZXRnTGV2ZWw9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX2NoYXJzZXRTZXJ2aWNlLnNldGdMZXZlbChlKSwhMH0sdC5wcm90b3R5cGUuc2NyZWVuQWxpZ25tZW50UGF0dGVybj1mdW5jdGlvbigpe3ZhciBlPW5ldyBwLkNlbGxEYXRhO2UuY29udGVudD0xPDwyMnwiRSIuY2hhckNvZGVBdCgwKSxlLmZnPXRoaXMuX2N1ckF0dHJEYXRhLmZnLGUuYmc9dGhpcy5fY3VyQXR0ckRhdGEuYmcsdGhpcy5fc2V0Q3Vyc29yKDAsMCk7Zm9yKHZhciB0PTA7dDx0aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3M7Kyt0KXt2YXIgcj10aGlzLl9hY3RpdmVCdWZmZXIueWJhc2UrdGhpcy5fYWN0aXZlQnVmZmVyLnkrdCxpPXRoaXMuX2FjdGl2ZUJ1ZmZlci5saW5lcy5nZXQocik7aSYmKGkuZmlsbChlKSxpLmlzV3JhcHBlZD0hMSl9cmV0dXJuIHRoaXMuX2RpcnR5Um93U2VydmljZS5tYXJrQWxsRGlydHkoKSx0aGlzLl9zZXRDdXJzb3IoMCwwKSwhMH0sdH0obC5EaXNwb3NhYmxlKTt0LklucHV0SGFuZGxlcj1FfSw4NDQ6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5nZXREaXNwb3NlQXJyYXlEaXNwb3NhYmxlPXQuZGlzcG9zZUFycmF5PXQuRGlzcG9zYWJsZT12b2lkIDA7dmFyIHI9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7dGhpcy5fZGlzcG9zYWJsZXM9W10sdGhpcy5faXNEaXNwb3NlZD0hMX1yZXR1cm4gZS5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe3RoaXMuX2lzRGlzcG9zZWQ9ITA7Zm9yKHZhciBlPTAsdD10aGlzLl9kaXNwb3NhYmxlcztlPHQubGVuZ3RoO2UrKyl0W2VdLmRpc3Bvc2UoKTt0aGlzLl9kaXNwb3NhYmxlcy5sZW5ndGg9MH0sZS5wcm90b3R5cGUucmVnaXN0ZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX2Rpc3Bvc2FibGVzLnB1c2goZSksZX0sZS5wcm90b3R5cGUudW5yZWdpc3Rlcj1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9kaXNwb3NhYmxlcy5pbmRleE9mKGUpOy0xIT09dCYmdGhpcy5fZGlzcG9zYWJsZXMuc3BsaWNlKHQsMSl9LGV9KCk7ZnVuY3Rpb24gaShlKXtmb3IodmFyIHQ9MCxyPWU7dDxyLmxlbmd0aDt0Kyspclt0XS5kaXNwb3NlKCk7ZS5sZW5ndGg9MH10LkRpc3Bvc2FibGU9cix0LmRpc3Bvc2VBcnJheT1pLHQuZ2V0RGlzcG9zZUFycmF5RGlzcG9zYWJsZT1mdW5jdGlvbihlKXtyZXR1cm57ZGlzcG9zZTpmdW5jdGlvbigpe3JldHVybiBpKGUpfX19fSw2MTE0OihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuaXNMaW51eD10LmlzV2luZG93cz10LmlzSXBob25lPXQuaXNJcGFkPXQuaXNNYWM9dC5pc1NhZmFyaT10LmlzRmlyZWZveD12b2lkIDA7dmFyIHI9InVuZGVmaW5lZCI9PXR5cGVvZiBuYXZpZ2F0b3IsaT1yPyJub2RlIjpuYXZpZ2F0b3IudXNlckFnZW50LG49cj8ibm9kZSI6bmF2aWdhdG9yLnBsYXRmb3JtO3QuaXNGaXJlZm94PWkuaW5jbHVkZXMoIkZpcmVmb3giKSx0LmlzU2FmYXJpPS9eKCg/IWNocm9tZXxhbmRyb2lkKS4pKnNhZmFyaS9pLnRlc3QoaSksdC5pc01hYz1bIk1hY2ludG9zaCIsIk1hY0ludGVsIiwiTWFjUFBDIiwiTWFjNjhLIl0uaW5jbHVkZXMobiksdC5pc0lwYWQ9ImlQYWQiPT09bix0LmlzSXBob25lPSJpUGhvbmUiPT09bix0LmlzV2luZG93cz1bIldpbmRvd3MiLCJXaW4xNiIsIldpbjMyIiwiV2luQ0UiXS5pbmNsdWRlcyhuKSx0LmlzTGludXg9bi5pbmRleE9mKCJMaW51eCIpPj0wfSw4MjczOihlLHQpPT57ZnVuY3Rpb24gcihlLHQscixpKXtpZih2b2lkIDA9PT1yJiYocj0wKSx2b2lkIDA9PT1pJiYoaT1lLmxlbmd0aCkscj49ZS5sZW5ndGgpcmV0dXJuIGU7cj0oZS5sZW5ndGgrciklZS5sZW5ndGgsaT1pPj1lLmxlbmd0aD9lLmxlbmd0aDooZS5sZW5ndGgraSklZS5sZW5ndGg7Zm9yKHZhciBuPXI7bjxpOysrbillW25dPXQ7cmV0dXJuIGV9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuY29uY2F0PXQuZmlsbEZhbGxiYWNrPXQuZmlsbD12b2lkIDAsdC5maWxsPWZ1bmN0aW9uKGUsdCxpLG4pe3JldHVybiBlLmZpbGw/ZS5maWxsKHQsaSxuKTpyKGUsdCxpLG4pfSx0LmZpbGxGYWxsYmFjaz1yLHQuY29uY2F0PWZ1bmN0aW9uKGUsdCl7dmFyIHI9bmV3IGUuY29uc3RydWN0b3IoZS5sZW5ndGgrdC5sZW5ndGgpO3JldHVybiByLnNldChlKSxyLnNldCh0LGUubGVuZ3RoKSxyfX0sOTI4MjooZSx0LHIpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQudXBkYXRlV2luZG93c01vZGVXcmFwcGVkU3RhdGU9dm9pZCAwO3ZhciBpPXIoNjQzKTt0LnVwZGF0ZVdpbmRvd3NNb2RlV3JhcHBlZFN0YXRlPWZ1bmN0aW9uKGUpe3ZhciB0PWUuYnVmZmVyLmxpbmVzLmdldChlLmJ1ZmZlci55YmFzZStlLmJ1ZmZlci55LTEpLHI9bnVsbD09dD92b2lkIDA6dC5nZXQoZS5jb2xzLTEpLG49ZS5idWZmZXIubGluZXMuZ2V0KGUuYnVmZmVyLnliYXNlK2UuYnVmZmVyLnkpO24mJnImJihuLmlzV3JhcHBlZD1yW2kuQ0hBUl9EQVRBX0NPREVfSU5ERVhdIT09aS5OVUxMX0NFTExfQ09ERSYmcltpLkNIQVJfREFUQV9DT0RFX0lOREVYXSE9PWkuV0hJVEVTUEFDRV9DRUxMX0NPREUpfX0sMzczNDooZSx0KT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkV4dGVuZGVkQXR0cnM9dC5BdHRyaWJ1dGVEYXRhPXZvaWQgMDt2YXIgcj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt0aGlzLmZnPTAsdGhpcy5iZz0wLHRoaXMuZXh0ZW5kZWQ9bmV3IGl9cmV0dXJuIGUudG9Db2xvclJHQj1mdW5jdGlvbihlKXtyZXR1cm5bZT4+PjE2JjI1NSxlPj4+OCYyNTUsMjU1JmVdfSxlLmZyb21Db2xvclJHQj1mdW5jdGlvbihlKXtyZXR1cm4oMjU1JmVbMF0pPDwxNnwoMjU1JmVbMV0pPDw4fDI1NSZlWzJdfSxlLnByb3RvdHlwZS5jbG9uZT1mdW5jdGlvbigpe3ZhciB0PW5ldyBlO3JldHVybiB0LmZnPXRoaXMuZmcsdC5iZz10aGlzLmJnLHQuZXh0ZW5kZWQ9dGhpcy5leHRlbmRlZC5jbG9uZSgpLHR9LGUucHJvdG90eXBlLmlzSW52ZXJzZT1mdW5jdGlvbigpe3JldHVybiA2NzEwODg2NCZ0aGlzLmZnfSxlLnByb3RvdHlwZS5pc0JvbGQ9ZnVuY3Rpb24oKXtyZXR1cm4gMTM0MjE3NzI4JnRoaXMuZmd9LGUucHJvdG90eXBlLmlzVW5kZXJsaW5lPWZ1bmN0aW9uKCl7cmV0dXJuIDI2ODQzNTQ1NiZ0aGlzLmZnfSxlLnByb3RvdHlwZS5pc0JsaW5rPWZ1bmN0aW9uKCl7cmV0dXJuIDUzNjg3MDkxMiZ0aGlzLmZnfSxlLnByb3RvdHlwZS5pc0ludmlzaWJsZT1mdW5jdGlvbigpe3JldHVybiAxMDczNzQxODI0JnRoaXMuZmd9LGUucHJvdG90eXBlLmlzSXRhbGljPWZ1bmN0aW9uKCl7cmV0dXJuIDY3MTA4ODY0JnRoaXMuYmd9LGUucHJvdG90eXBlLmlzRGltPWZ1bmN0aW9uKCl7cmV0dXJuIDEzNDIxNzcyOCZ0aGlzLmJnfSxlLnByb3RvdHlwZS5pc1N0cmlrZXRocm91Z2g9ZnVuY3Rpb24oKXtyZXR1cm4gMjE0NzQ4MzY0OCZ0aGlzLmZnfSxlLnByb3RvdHlwZS5nZXRGZ0NvbG9yTW9kZT1mdW5jdGlvbigpe3JldHVybiA1MDMzMTY0OCZ0aGlzLmZnfSxlLnByb3RvdHlwZS5nZXRCZ0NvbG9yTW9kZT1mdW5jdGlvbigpe3JldHVybiA1MDMzMTY0OCZ0aGlzLmJnfSxlLnByb3RvdHlwZS5pc0ZnUkdCPWZ1bmN0aW9uKCl7cmV0dXJuIDUwMzMxNjQ4PT0oNTAzMzE2NDgmdGhpcy5mZyl9LGUucHJvdG90eXBlLmlzQmdSR0I9ZnVuY3Rpb24oKXtyZXR1cm4gNTAzMzE2NDg9PSg1MDMzMTY0OCZ0aGlzLmJnKX0sZS5wcm90b3R5cGUuaXNGZ1BhbGV0dGU9ZnVuY3Rpb24oKXtyZXR1cm4gMTY3NzcyMTY9PSg1MDMzMTY0OCZ0aGlzLmZnKXx8MzM1NTQ0MzI9PSg1MDMzMTY0OCZ0aGlzLmZnKX0sZS5wcm90b3R5cGUuaXNCZ1BhbGV0dGU9ZnVuY3Rpb24oKXtyZXR1cm4gMTY3NzcyMTY9PSg1MDMzMTY0OCZ0aGlzLmJnKXx8MzM1NTQ0MzI9PSg1MDMzMTY0OCZ0aGlzLmJnKX0sZS5wcm90b3R5cGUuaXNGZ0RlZmF1bHQ9ZnVuY3Rpb24oKXtyZXR1cm4gMD09KDUwMzMxNjQ4JnRoaXMuZmcpfSxlLnByb3RvdHlwZS5pc0JnRGVmYXVsdD1mdW5jdGlvbigpe3JldHVybiAwPT0oNTAzMzE2NDgmdGhpcy5iZyl9LGUucHJvdG90eXBlLmlzQXR0cmlidXRlRGVmYXVsdD1mdW5jdGlvbigpe3JldHVybiAwPT09dGhpcy5mZyYmMD09PXRoaXMuYmd9LGUucHJvdG90eXBlLmdldEZnQ29sb3I9ZnVuY3Rpb24oKXtzd2l0Y2goNTAzMzE2NDgmdGhpcy5mZyl7Y2FzZSAxNjc3NzIxNjpjYXNlIDMzNTU0NDMyOnJldHVybiAyNTUmdGhpcy5mZztjYXNlIDUwMzMxNjQ4OnJldHVybiAxNjc3NzIxNSZ0aGlzLmZnO2RlZmF1bHQ6cmV0dXJuLTF9fSxlLnByb3RvdHlwZS5nZXRCZ0NvbG9yPWZ1bmN0aW9uKCl7c3dpdGNoKDUwMzMxNjQ4JnRoaXMuYmcpe2Nhc2UgMTY3NzcyMTY6Y2FzZSAzMzU1NDQzMjpyZXR1cm4gMjU1JnRoaXMuYmc7Y2FzZSA1MDMzMTY0ODpyZXR1cm4gMTY3NzcyMTUmdGhpcy5iZztkZWZhdWx0OnJldHVybi0xfX0sZS5wcm90b3R5cGUuaGFzRXh0ZW5kZWRBdHRycz1mdW5jdGlvbigpe3JldHVybiAyNjg0MzU0NTYmdGhpcy5iZ30sZS5wcm90b3R5cGUudXBkYXRlRXh0ZW5kZWQ9ZnVuY3Rpb24oKXt0aGlzLmV4dGVuZGVkLmlzRW1wdHkoKT90aGlzLmJnJj0tMjY4NDM1NDU3OnRoaXMuYmd8PTI2ODQzNTQ1Nn0sZS5wcm90b3R5cGUuZ2V0VW5kZXJsaW5lQ29sb3I9ZnVuY3Rpb24oKXtpZigyNjg0MzU0NTYmdGhpcy5iZyYmfnRoaXMuZXh0ZW5kZWQudW5kZXJsaW5lQ29sb3Ipc3dpdGNoKDUwMzMxNjQ4JnRoaXMuZXh0ZW5kZWQudW5kZXJsaW5lQ29sb3Ipe2Nhc2UgMTY3NzcyMTY6Y2FzZSAzMzU1NDQzMjpyZXR1cm4gMjU1JnRoaXMuZXh0ZW5kZWQudW5kZXJsaW5lQ29sb3I7Y2FzZSA1MDMzMTY0ODpyZXR1cm4gMTY3NzcyMTUmdGhpcy5leHRlbmRlZC51bmRlcmxpbmVDb2xvcjtkZWZhdWx0OnJldHVybiB0aGlzLmdldEZnQ29sb3IoKX1yZXR1cm4gdGhpcy5nZXRGZ0NvbG9yKCl9LGUucHJvdG90eXBlLmdldFVuZGVybGluZUNvbG9yTW9kZT1mdW5jdGlvbigpe3JldHVybiAyNjg0MzU0NTYmdGhpcy5iZyYmfnRoaXMuZXh0ZW5kZWQudW5kZXJsaW5lQ29sb3I/NTAzMzE2NDgmdGhpcy5leHRlbmRlZC51bmRlcmxpbmVDb2xvcjp0aGlzLmdldEZnQ29sb3JNb2RlKCl9LGUucHJvdG90eXBlLmlzVW5kZXJsaW5lQ29sb3JSR0I9ZnVuY3Rpb24oKXtyZXR1cm4gMjY4NDM1NDU2JnRoaXMuYmcmJn50aGlzLmV4dGVuZGVkLnVuZGVybGluZUNvbG9yPzUwMzMxNjQ4PT0oNTAzMzE2NDgmdGhpcy5leHRlbmRlZC51bmRlcmxpbmVDb2xvcik6dGhpcy5pc0ZnUkdCKCl9LGUucHJvdG90eXBlLmlzVW5kZXJsaW5lQ29sb3JQYWxldHRlPWZ1bmN0aW9uKCl7cmV0dXJuIDI2ODQzNTQ1NiZ0aGlzLmJnJiZ+dGhpcy5leHRlbmRlZC51bmRlcmxpbmVDb2xvcj8xNjc3NzIxNj09KDUwMzMxNjQ4JnRoaXMuZXh0ZW5kZWQudW5kZXJsaW5lQ29sb3IpfHwzMzU1NDQzMj09KDUwMzMxNjQ4JnRoaXMuZXh0ZW5kZWQudW5kZXJsaW5lQ29sb3IpOnRoaXMuaXNGZ1BhbGV0dGUoKX0sZS5wcm90b3R5cGUuaXNVbmRlcmxpbmVDb2xvckRlZmF1bHQ9ZnVuY3Rpb24oKXtyZXR1cm4gMjY4NDM1NDU2JnRoaXMuYmcmJn50aGlzLmV4dGVuZGVkLnVuZGVybGluZUNvbG9yPzA9PSg1MDMzMTY0OCZ0aGlzLmV4dGVuZGVkLnVuZGVybGluZUNvbG9yKTp0aGlzLmlzRmdEZWZhdWx0KCl9LGUucHJvdG90eXBlLmdldFVuZGVybGluZVN0eWxlPWZ1bmN0aW9uKCl7cmV0dXJuIDI2ODQzNTQ1NiZ0aGlzLmZnPzI2ODQzNTQ1NiZ0aGlzLmJnP3RoaXMuZXh0ZW5kZWQudW5kZXJsaW5lU3R5bGU6MTowfSxlfSgpO3QuQXR0cmlidXRlRGF0YT1yO3ZhciBpPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3ZvaWQgMD09PWUmJihlPTApLHZvaWQgMD09PXQmJih0PS0xKSx0aGlzLnVuZGVybGluZVN0eWxlPWUsdGhpcy51bmRlcmxpbmVDb2xvcj10fXJldHVybiBlLnByb3RvdHlwZS5jbG9uZT1mdW5jdGlvbigpe3JldHVybiBuZXcgZSh0aGlzLnVuZGVybGluZVN0eWxlLHRoaXMudW5kZXJsaW5lQ29sb3IpfSxlLnByb3RvdHlwZS5pc0VtcHR5PWZ1bmN0aW9uKCl7cmV0dXJuIDA9PT10aGlzLnVuZGVybGluZVN0eWxlfSxlfSgpO3QuRXh0ZW5kZWRBdHRycz1pfSw5MDkyOihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5CdWZmZXJTdHJpbmdJdGVyYXRvcj10LkJ1ZmZlcj10Lk1BWF9CVUZGRVJfU0laRT12b2lkIDA7dmFyIGk9cig2MzQ5KSxuPXIoODQzNyksbz1yKDUxMSkscz1yKDY0MyksYT1yKDQ2MzQpLGM9cig0ODYzKSxsPXIoNzExNiksdT1yKDM3MzQpO3QuTUFYX0JVRkZFUl9TSVpFPTQyOTQ5NjcyOTU7dmFyIGg9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxyKXt0aGlzLl9oYXNTY3JvbGxiYWNrPWUsdGhpcy5fb3B0aW9uc1NlcnZpY2U9dCx0aGlzLl9idWZmZXJTZXJ2aWNlPXIsdGhpcy55ZGlzcD0wLHRoaXMueWJhc2U9MCx0aGlzLnk9MCx0aGlzLng9MCx0aGlzLnNhdmVkWT0wLHRoaXMuc2F2ZWRYPTAsdGhpcy5zYXZlZEN1ckF0dHJEYXRhPW4uREVGQVVMVF9BVFRSX0RBVEEuY2xvbmUoKSx0aGlzLnNhdmVkQ2hhcnNldD1sLkRFRkFVTFRfQ0hBUlNFVCx0aGlzLm1hcmtlcnM9W10sdGhpcy5fbnVsbENlbGw9by5DZWxsRGF0YS5mcm9tQ2hhckRhdGEoWzAscy5OVUxMX0NFTExfQ0hBUixzLk5VTExfQ0VMTF9XSURUSCxzLk5VTExfQ0VMTF9DT0RFXSksdGhpcy5fd2hpdGVzcGFjZUNlbGw9by5DZWxsRGF0YS5mcm9tQ2hhckRhdGEoWzAscy5XSElURVNQQUNFX0NFTExfQ0hBUixzLldISVRFU1BBQ0VfQ0VMTF9XSURUSCxzLldISVRFU1BBQ0VfQ0VMTF9DT0RFXSksdGhpcy5fY29scz10aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsdGhpcy5fcm93cz10aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MsdGhpcy5saW5lcz1uZXcgaS5DaXJjdWxhckxpc3QodGhpcy5fZ2V0Q29ycmVjdEJ1ZmZlckxlbmd0aCh0aGlzLl9yb3dzKSksdGhpcy5zY3JvbGxUb3A9MCx0aGlzLnNjcm9sbEJvdHRvbT10aGlzLl9yb3dzLTEsdGhpcy5zZXR1cFRhYlN0b3BzKCl9cmV0dXJuIGUucHJvdG90eXBlLmdldE51bGxDZWxsPWZ1bmN0aW9uKGUpe3JldHVybiBlPyh0aGlzLl9udWxsQ2VsbC5mZz1lLmZnLHRoaXMuX251bGxDZWxsLmJnPWUuYmcsdGhpcy5fbnVsbENlbGwuZXh0ZW5kZWQ9ZS5leHRlbmRlZCk6KHRoaXMuX251bGxDZWxsLmZnPTAsdGhpcy5fbnVsbENlbGwuYmc9MCx0aGlzLl9udWxsQ2VsbC5leHRlbmRlZD1uZXcgdS5FeHRlbmRlZEF0dHJzKSx0aGlzLl9udWxsQ2VsbH0sZS5wcm90b3R5cGUuZ2V0V2hpdGVzcGFjZUNlbGw9ZnVuY3Rpb24oZSl7cmV0dXJuIGU/KHRoaXMuX3doaXRlc3BhY2VDZWxsLmZnPWUuZmcsdGhpcy5fd2hpdGVzcGFjZUNlbGwuYmc9ZS5iZyx0aGlzLl93aGl0ZXNwYWNlQ2VsbC5leHRlbmRlZD1lLmV4dGVuZGVkKToodGhpcy5fd2hpdGVzcGFjZUNlbGwuZmc9MCx0aGlzLl93aGl0ZXNwYWNlQ2VsbC5iZz0wLHRoaXMuX3doaXRlc3BhY2VDZWxsLmV4dGVuZGVkPW5ldyB1LkV4dGVuZGVkQXR0cnMpLHRoaXMuX3doaXRlc3BhY2VDZWxsfSxlLnByb3RvdHlwZS5nZXRCbGFua0xpbmU9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gbmV3IG4uQnVmZmVyTGluZSh0aGlzLl9idWZmZXJTZXJ2aWNlLmNvbHMsdGhpcy5nZXROdWxsQ2VsbChlKSx0KX0sT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJoYXNTY3JvbGxiYWNrIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2hhc1Njcm9sbGJhY2smJnRoaXMubGluZXMubWF4TGVuZ3RoPnRoaXMuX3Jvd3N9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJpc0N1cnNvckluVmlld3BvcnQiLHtnZXQ6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnliYXNlK3RoaXMueS10aGlzLnlkaXNwO3JldHVybiBlPj0wJiZlPHRoaXMuX3Jvd3N9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksZS5wcm90b3R5cGUuX2dldENvcnJlY3RCdWZmZXJMZW5ndGg9ZnVuY3Rpb24oZSl7aWYoIXRoaXMuX2hhc1Njcm9sbGJhY2spcmV0dXJuIGU7dmFyIHI9ZSt0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLnNjcm9sbGJhY2s7cmV0dXJuIHI+dC5NQVhfQlVGRkVSX1NJWkU/dC5NQVhfQlVGRkVSX1NJWkU6cn0sZS5wcm90b3R5cGUuZmlsbFZpZXdwb3J0Um93cz1mdW5jdGlvbihlKXtpZigwPT09dGhpcy5saW5lcy5sZW5ndGgpe3ZvaWQgMD09PWUmJihlPW4uREVGQVVMVF9BVFRSX0RBVEEpO2Zvcih2YXIgdD10aGlzLl9yb3dzO3QtLTspdGhpcy5saW5lcy5wdXNoKHRoaXMuZ2V0QmxhbmtMaW5lKGUpKX19LGUucHJvdG90eXBlLmNsZWFyPWZ1bmN0aW9uKCl7dGhpcy55ZGlzcD0wLHRoaXMueWJhc2U9MCx0aGlzLnk9MCx0aGlzLng9MCx0aGlzLmxpbmVzPW5ldyBpLkNpcmN1bGFyTGlzdCh0aGlzLl9nZXRDb3JyZWN0QnVmZmVyTGVuZ3RoKHRoaXMuX3Jvd3MpKSx0aGlzLnNjcm9sbFRvcD0wLHRoaXMuc2Nyb2xsQm90dG9tPXRoaXMuX3Jvd3MtMSx0aGlzLnNldHVwVGFiU3RvcHMoKX0sZS5wcm90b3R5cGUucmVzaXplPWZ1bmN0aW9uKGUsdCl7dmFyIHI9dGhpcy5nZXROdWxsQ2VsbChuLkRFRkFVTFRfQVRUUl9EQVRBKSxpPXRoaXMuX2dldENvcnJlY3RCdWZmZXJMZW5ndGgodCk7aWYoaT50aGlzLmxpbmVzLm1heExlbmd0aCYmKHRoaXMubGluZXMubWF4TGVuZ3RoPWkpLHRoaXMubGluZXMubGVuZ3RoPjApe2lmKHRoaXMuX2NvbHM8ZSlmb3IodmFyIG89MDtvPHRoaXMubGluZXMubGVuZ3RoO28rKyl0aGlzLmxpbmVzLmdldChvKS5yZXNpemUoZSxyKTt2YXIgcz0wO2lmKHRoaXMuX3Jvd3M8dClmb3IodmFyIGE9dGhpcy5fcm93czthPHQ7YSsrKXRoaXMubGluZXMubGVuZ3RoPHQrdGhpcy55YmFzZSYmKHRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMud2luZG93c01vZGU/dGhpcy5saW5lcy5wdXNoKG5ldyBuLkJ1ZmZlckxpbmUoZSxyKSk6dGhpcy55YmFzZT4wJiZ0aGlzLmxpbmVzLmxlbmd0aDw9dGhpcy55YmFzZSt0aGlzLnkrcysxPyh0aGlzLnliYXNlLS0scysrLHRoaXMueWRpc3A+MCYmdGhpcy55ZGlzcC0tKTp0aGlzLmxpbmVzLnB1c2gobmV3IG4uQnVmZmVyTGluZShlLHIpKSk7ZWxzZSBmb3IoYT10aGlzLl9yb3dzO2E+dDthLS0pdGhpcy5saW5lcy5sZW5ndGg+dCt0aGlzLnliYXNlJiYodGhpcy5saW5lcy5sZW5ndGg+dGhpcy55YmFzZSt0aGlzLnkrMT90aGlzLmxpbmVzLnBvcCgpOih0aGlzLnliYXNlKyssdGhpcy55ZGlzcCsrKSk7aWYoaTx0aGlzLmxpbmVzLm1heExlbmd0aCl7dmFyIGM9dGhpcy5saW5lcy5sZW5ndGgtaTtjPjAmJih0aGlzLmxpbmVzLnRyaW1TdGFydChjKSx0aGlzLnliYXNlPU1hdGgubWF4KHRoaXMueWJhc2UtYywwKSx0aGlzLnlkaXNwPU1hdGgubWF4KHRoaXMueWRpc3AtYywwKSx0aGlzLnNhdmVkWT1NYXRoLm1heCh0aGlzLnNhdmVkWS1jLDApKSx0aGlzLmxpbmVzLm1heExlbmd0aD1pfXRoaXMueD1NYXRoLm1pbih0aGlzLngsZS0xKSx0aGlzLnk9TWF0aC5taW4odGhpcy55LHQtMSkscyYmKHRoaXMueSs9cyksdGhpcy5zYXZlZFg9TWF0aC5taW4odGhpcy5zYXZlZFgsZS0xKSx0aGlzLnNjcm9sbFRvcD0wfWlmKHRoaXMuc2Nyb2xsQm90dG9tPXQtMSx0aGlzLl9pc1JlZmxvd0VuYWJsZWQmJih0aGlzLl9yZWZsb3coZSx0KSx0aGlzLl9jb2xzPmUpKWZvcihvPTA7bzx0aGlzLmxpbmVzLmxlbmd0aDtvKyspdGhpcy5saW5lcy5nZXQobykucmVzaXplKGUscik7dGhpcy5fY29scz1lLHRoaXMuX3Jvd3M9dH0sT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJfaXNSZWZsb3dFbmFibGVkIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2hhc1Njcm9sbGJhY2smJiF0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLndpbmRvd3NNb2RlfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLl9yZWZsb3c9ZnVuY3Rpb24oZSx0KXt0aGlzLl9jb2xzIT09ZSYmKGU+dGhpcy5fY29scz90aGlzLl9yZWZsb3dMYXJnZXIoZSx0KTp0aGlzLl9yZWZsb3dTbWFsbGVyKGUsdCkpfSxlLnByb3RvdHlwZS5fcmVmbG93TGFyZ2VyPWZ1bmN0aW9uKGUsdCl7dmFyIHI9KDAsYS5yZWZsb3dMYXJnZXJHZXRMaW5lc1RvUmVtb3ZlKSh0aGlzLmxpbmVzLHRoaXMuX2NvbHMsZSx0aGlzLnliYXNlK3RoaXMueSx0aGlzLmdldE51bGxDZWxsKG4uREVGQVVMVF9BVFRSX0RBVEEpKTtpZihyLmxlbmd0aD4wKXt2YXIgaT0oMCxhLnJlZmxvd0xhcmdlckNyZWF0ZU5ld0xheW91dCkodGhpcy5saW5lcyxyKTsoMCxhLnJlZmxvd0xhcmdlckFwcGx5TmV3TGF5b3V0KSh0aGlzLmxpbmVzLGkubGF5b3V0KSx0aGlzLl9yZWZsb3dMYXJnZXJBZGp1c3RWaWV3cG9ydChlLHQsaS5jb3VudFJlbW92ZWQpfX0sZS5wcm90b3R5cGUuX3JlZmxvd0xhcmdlckFkanVzdFZpZXdwb3J0PWZ1bmN0aW9uKGUsdCxyKXtmb3IodmFyIGk9dGhpcy5nZXROdWxsQ2VsbChuLkRFRkFVTFRfQVRUUl9EQVRBKSxvPXI7by0tID4wOykwPT09dGhpcy55YmFzZT8odGhpcy55PjAmJnRoaXMueS0tLHRoaXMubGluZXMubGVuZ3RoPHQmJnRoaXMubGluZXMucHVzaChuZXcgbi5CdWZmZXJMaW5lKGUsaSkpKToodGhpcy55ZGlzcD09PXRoaXMueWJhc2UmJnRoaXMueWRpc3AtLSx0aGlzLnliYXNlLS0pO3RoaXMuc2F2ZWRZPU1hdGgubWF4KHRoaXMuc2F2ZWRZLXIsMCl9LGUucHJvdG90eXBlLl9yZWZsb3dTbWFsbGVyPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPXRoaXMuZ2V0TnVsbENlbGwobi5ERUZBVUxUX0FUVFJfREFUQSksaT1bXSxvPTAscz10aGlzLmxpbmVzLmxlbmd0aC0xO3M+PTA7cy0tKXt2YXIgYz10aGlzLmxpbmVzLmdldChzKTtpZighKCFjfHwhYy5pc1dyYXBwZWQmJmMuZ2V0VHJpbW1lZExlbmd0aCgpPD1lKSl7Zm9yKHZhciBsPVtjXTtjLmlzV3JhcHBlZCYmcz4wOyljPXRoaXMubGluZXMuZ2V0KC0tcyksbC51bnNoaWZ0KGMpO3ZhciB1PXRoaXMueWJhc2UrdGhpcy55O2lmKCEodT49cyYmdTxzK2wubGVuZ3RoKSl7dmFyIGgsZj1sW2wubGVuZ3RoLTFdLmdldFRyaW1tZWRMZW5ndGgoKSxfPSgwLGEucmVmbG93U21hbGxlckdldE5ld0xpbmVMZW5ndGhzKShsLHRoaXMuX2NvbHMsZSksZD1fLmxlbmd0aC1sLmxlbmd0aDtoPTA9PT10aGlzLnliYXNlJiZ0aGlzLnkhPT10aGlzLmxpbmVzLmxlbmd0aC0xP01hdGgubWF4KDAsdGhpcy55LXRoaXMubGluZXMubWF4TGVuZ3RoK2QpOk1hdGgubWF4KDAsdGhpcy5saW5lcy5sZW5ndGgtdGhpcy5saW5lcy5tYXhMZW5ndGgrZCk7Zm9yKHZhciBwPVtdLHY9MDt2PGQ7disrKXt2YXIgZz10aGlzLmdldEJsYW5rTGluZShuLkRFRkFVTFRfQVRUUl9EQVRBLCEwKTtwLnB1c2goZyl9cC5sZW5ndGg+MCYmKGkucHVzaCh7c3RhcnQ6cytsLmxlbmd0aCtvLG5ld0xpbmVzOnB9KSxvKz1wLmxlbmd0aCksbC5wdXNoLmFwcGx5KGwscCk7dmFyIHk9Xy5sZW5ndGgtMSxtPV9beV07MD09PW0mJihtPV9bLS15XSk7Zm9yKHZhciBiPWwubGVuZ3RoLWQtMSxTPWY7Yj49MDspe3ZhciBDPU1hdGgubWluKFMsbSk7aWYobFt5XS5jb3B5Q2VsbHNGcm9tKGxbYl0sUy1DLG0tQyxDLCEwKSwwPT0obS09QykmJihtPV9bLS15XSksMD09KFMtPUMpKXtiLS07dmFyIHc9TWF0aC5tYXgoYiwwKTtTPSgwLGEuZ2V0V3JhcHBlZExpbmVUcmltbWVkTGVuZ3RoKShsLHcsdGhpcy5fY29scyl9fWZvcih2PTA7djxsLmxlbmd0aDt2KyspX1t2XTxlJiZsW3ZdLnNldENlbGwoX1t2XSxyKTtmb3IodmFyIEw9ZC1oO0wtLSA+MDspMD09PXRoaXMueWJhc2U/dGhpcy55PHQtMT8odGhpcy55KyssdGhpcy5saW5lcy5wb3AoKSk6KHRoaXMueWJhc2UrKyx0aGlzLnlkaXNwKyspOnRoaXMueWJhc2U8TWF0aC5taW4odGhpcy5saW5lcy5tYXhMZW5ndGgsdGhpcy5saW5lcy5sZW5ndGgrbyktdCYmKHRoaXMueWJhc2U9PT10aGlzLnlkaXNwJiZ0aGlzLnlkaXNwKyssdGhpcy55YmFzZSsrKTt0aGlzLnNhdmVkWT1NYXRoLm1pbih0aGlzLnNhdmVkWStkLHRoaXMueWJhc2UrdC0xKX19fWlmKGkubGVuZ3RoPjApe3ZhciBFPVtdLHg9W107Zm9yKHY9MDt2PHRoaXMubGluZXMubGVuZ3RoO3YrKyl4LnB1c2godGhpcy5saW5lcy5nZXQodikpO3ZhciBBPXRoaXMubGluZXMubGVuZ3RoLGs9QS0xLE09MCxSPWlbTV07dGhpcy5saW5lcy5sZW5ndGg9TWF0aC5taW4odGhpcy5saW5lcy5tYXhMZW5ndGgsdGhpcy5saW5lcy5sZW5ndGgrbyk7dmFyIFQ9MDtmb3Iodj1NYXRoLm1pbih0aGlzLmxpbmVzLm1heExlbmd0aC0xLEErby0xKTt2Pj0wO3YtLSlpZihSJiZSLnN0YXJ0PmsrVCl7Zm9yKHZhciBPPVIubmV3TGluZXMubGVuZ3RoLTE7Tz49MDtPLS0pdGhpcy5saW5lcy5zZXQodi0tLFIubmV3TGluZXNbT10pO3YrKyxFLnB1c2goe2luZGV4OmsrMSxhbW91bnQ6Ui5uZXdMaW5lcy5sZW5ndGh9KSxUKz1SLm5ld0xpbmVzLmxlbmd0aCxSPWlbKytNXX1lbHNlIHRoaXMubGluZXMuc2V0KHYseFtrLS1dKTt2YXIgQj0wO2Zvcih2PUUubGVuZ3RoLTE7dj49MDt2LS0pRVt2XS5pbmRleCs9Qix0aGlzLmxpbmVzLm9uSW5zZXJ0RW1pdHRlci5maXJlKEVbdl0pLEIrPUVbdl0uYW1vdW50O3ZhciBEPU1hdGgubWF4KDAsQStvLXRoaXMubGluZXMubWF4TGVuZ3RoKTtEPjAmJnRoaXMubGluZXMub25UcmltRW1pdHRlci5maXJlKEQpfX0sZS5wcm90b3R5cGUuc3RyaW5nSW5kZXhUb0J1ZmZlckluZGV4PWZ1bmN0aW9uKGUsdCxyKXtmb3Iodm9pZCAwPT09ciYmKHI9ITEpO3Q7KXt2YXIgaT10aGlzLmxpbmVzLmdldChlKTtpZighaSlyZXR1cm5bLTEsLTFdO2Zvcih2YXIgbj1yP2kuZ2V0VHJpbW1lZExlbmd0aCgpOmkubGVuZ3RoLG89MDtvPG47KytvKWlmKGkuZ2V0KG8pW3MuQ0hBUl9EQVRBX1dJRFRIX0lOREVYXSYmKHQtPWkuZ2V0KG8pW3MuQ0hBUl9EQVRBX0NIQVJfSU5ERVhdLmxlbmd0aHx8MSksdDwwKXJldHVybltlLG9dO2UrK31yZXR1cm5bZSwwXX0sZS5wcm90b3R5cGUudHJhbnNsYXRlQnVmZmVyTGluZVRvU3RyaW5nPWZ1bmN0aW9uKGUsdCxyLGkpe3ZvaWQgMD09PXImJihyPTApO3ZhciBuPXRoaXMubGluZXMuZ2V0KGUpO3JldHVybiBuP24udHJhbnNsYXRlVG9TdHJpbmcodCxyLGkpOiIifSxlLnByb3RvdHlwZS5nZXRXcmFwcGVkUmFuZ2VGb3JMaW5lPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1lLHI9ZTt0PjAmJnRoaXMubGluZXMuZ2V0KHQpLmlzV3JhcHBlZDspdC0tO2Zvcig7cisxPHRoaXMubGluZXMubGVuZ3RoJiZ0aGlzLmxpbmVzLmdldChyKzEpLmlzV3JhcHBlZDspcisrO3JldHVybntmaXJzdDp0LGxhc3Q6cn19LGUucHJvdG90eXBlLnNldHVwVGFiU3RvcHM9ZnVuY3Rpb24oZSl7Zm9yKG51bGwhPWU/dGhpcy50YWJzW2VdfHwoZT10aGlzLnByZXZTdG9wKGUpKToodGhpcy50YWJzPXt9LGU9MCk7ZTx0aGlzLl9jb2xzO2UrPXRoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMudGFiU3RvcFdpZHRoKXRoaXMudGFic1tlXT0hMH0sZS5wcm90b3R5cGUucHJldlN0b3A9ZnVuY3Rpb24oZSl7Zm9yKG51bGw9PWUmJihlPXRoaXMueCk7IXRoaXMudGFic1stLWVdJiZlPjA7KTtyZXR1cm4gZT49dGhpcy5fY29scz90aGlzLl9jb2xzLTE6ZTwwPzA6ZX0sZS5wcm90b3R5cGUubmV4dFN0b3A9ZnVuY3Rpb24oZSl7Zm9yKG51bGw9PWUmJihlPXRoaXMueCk7IXRoaXMudGFic1srK2VdJiZlPHRoaXMuX2NvbHM7KTtyZXR1cm4gZT49dGhpcy5fY29scz90aGlzLl9jb2xzLTE6ZTwwPzA6ZX0sZS5wcm90b3R5cGUuYWRkTWFya2VyPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMscj1uZXcgYy5NYXJrZXIoZSk7cmV0dXJuIHRoaXMubWFya2Vycy5wdXNoKHIpLHIucmVnaXN0ZXIodGhpcy5saW5lcy5vblRyaW0oKGZ1bmN0aW9uKGUpe3IubGluZS09ZSxyLmxpbmU8MCYmci5kaXNwb3NlKCl9KSkpLHIucmVnaXN0ZXIodGhpcy5saW5lcy5vbkluc2VydCgoZnVuY3Rpb24oZSl7ci5saW5lPj1lLmluZGV4JiYoci5saW5lKz1lLmFtb3VudCl9KSkpLHIucmVnaXN0ZXIodGhpcy5saW5lcy5vbkRlbGV0ZSgoZnVuY3Rpb24oZSl7ci5saW5lPj1lLmluZGV4JiZyLmxpbmU8ZS5pbmRleCtlLmFtb3VudCYmci5kaXNwb3NlKCksci5saW5lPmUuaW5kZXgmJihyLmxpbmUtPWUuYW1vdW50KX0pKSksci5yZWdpc3RlcihyLm9uRGlzcG9zZSgoZnVuY3Rpb24oKXtyZXR1cm4gdC5fcmVtb3ZlTWFya2VyKHIpfSkpKSxyfSxlLnByb3RvdHlwZS5fcmVtb3ZlTWFya2VyPWZ1bmN0aW9uKGUpe3RoaXMubWFya2Vycy5zcGxpY2UodGhpcy5tYXJrZXJzLmluZGV4T2YoZSksMSl9LGUucHJvdG90eXBlLml0ZXJhdG9yPWZ1bmN0aW9uKGUsdCxyLGksbil7cmV0dXJuIG5ldyBmKHRoaXMsZSx0LHIsaSxuKX0sZX0oKTt0LkJ1ZmZlcj1oO3ZhciBmPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQscixpLG4sbyl7dm9pZCAwPT09ciYmKHI9MCksdm9pZCAwPT09aSYmKGk9ZS5saW5lcy5sZW5ndGgpLHZvaWQgMD09PW4mJihuPTApLHZvaWQgMD09PW8mJihvPTApLHRoaXMuX2J1ZmZlcj1lLHRoaXMuX3RyaW1SaWdodD10LHRoaXMuX3N0YXJ0SW5kZXg9cix0aGlzLl9lbmRJbmRleD1pLHRoaXMuX3N0YXJ0T3ZlcnNjYW49bix0aGlzLl9lbmRPdmVyc2Nhbj1vLHRoaXMuX3N0YXJ0SW5kZXg8MCYmKHRoaXMuX3N0YXJ0SW5kZXg9MCksdGhpcy5fZW5kSW5kZXg+dGhpcy5fYnVmZmVyLmxpbmVzLmxlbmd0aCYmKHRoaXMuX2VuZEluZGV4PXRoaXMuX2J1ZmZlci5saW5lcy5sZW5ndGgpLHRoaXMuX2N1cnJlbnQ9dGhpcy5fc3RhcnRJbmRleH1yZXR1cm4gZS5wcm90b3R5cGUuaGFzTmV4dD1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9jdXJyZW50PHRoaXMuX2VuZEluZGV4fSxlLnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5fYnVmZmVyLmdldFdyYXBwZWRSYW5nZUZvckxpbmUodGhpcy5fY3VycmVudCk7ZS5maXJzdDx0aGlzLl9zdGFydEluZGV4LXRoaXMuX3N0YXJ0T3ZlcnNjYW4mJihlLmZpcnN0PXRoaXMuX3N0YXJ0SW5kZXgtdGhpcy5fc3RhcnRPdmVyc2NhbiksZS5sYXN0PnRoaXMuX2VuZEluZGV4K3RoaXMuX2VuZE92ZXJzY2FuJiYoZS5sYXN0PXRoaXMuX2VuZEluZGV4K3RoaXMuX2VuZE92ZXJzY2FuKSxlLmZpcnN0PU1hdGgubWF4KGUuZmlyc3QsMCksZS5sYXN0PU1hdGgubWluKGUubGFzdCx0aGlzLl9idWZmZXIubGluZXMubGVuZ3RoKTtmb3IodmFyIHQ9IiIscj1lLmZpcnN0O3I8PWUubGFzdDsrK3IpdCs9dGhpcy5fYnVmZmVyLnRyYW5zbGF0ZUJ1ZmZlckxpbmVUb1N0cmluZyhyLHRoaXMuX3RyaW1SaWdodCk7cmV0dXJuIHRoaXMuX2N1cnJlbnQ9ZS5sYXN0KzEse3JhbmdlOmUsY29udGVudDp0fX0sZX0oKTt0LkJ1ZmZlclN0cmluZ0l0ZXJhdG9yPWZ9LDg0Mzc6KGUsdCxyKT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkJ1ZmZlckxpbmU9dC5ERUZBVUxUX0FUVFJfREFUQT12b2lkIDA7dmFyIGk9cig0ODIpLG49cig2NDMpLG89cig1MTEpLHM9cigzNzM0KTt0LkRFRkFVTFRfQVRUUl9EQVRBPU9iamVjdC5mcmVlemUobmV3IHMuQXR0cmlidXRlRGF0YSk7dmFyIGE9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxyKXt2b2lkIDA9PT1yJiYocj0hMSksdGhpcy5pc1dyYXBwZWQ9cix0aGlzLl9jb21iaW5lZD17fSx0aGlzLl9leHRlbmRlZEF0dHJzPXt9LHRoaXMuX2RhdGE9bmV3IFVpbnQzMkFycmF5KDMqZSk7Zm9yKHZhciBpPXR8fG8uQ2VsbERhdGEuZnJvbUNoYXJEYXRhKFswLG4uTlVMTF9DRUxMX0NIQVIsbi5OVUxMX0NFTExfV0lEVEgsbi5OVUxMX0NFTExfQ09ERV0pLHM9MDtzPGU7KytzKXRoaXMuc2V0Q2VsbChzLGkpO3RoaXMubGVuZ3RoPWV9cmV0dXJuIGUucHJvdG90eXBlLmdldD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9kYXRhWzMqZSswXSxyPTIwOTcxNTEmdDtyZXR1cm5bdGhpcy5fZGF0YVszKmUrMV0sMjA5NzE1MiZ0P3RoaXMuX2NvbWJpbmVkW2VdOnI/KDAsaS5zdHJpbmdGcm9tQ29kZVBvaW50KShyKToiIix0Pj4yMiwyMDk3MTUyJnQ/dGhpcy5fY29tYmluZWRbZV0uY2hhckNvZGVBdCh0aGlzLl9jb21iaW5lZFtlXS5sZW5ndGgtMSk6cl19LGUucHJvdG90eXBlLnNldD1mdW5jdGlvbihlLHQpe3RoaXMuX2RhdGFbMyplKzFdPXRbbi5DSEFSX0RBVEFfQVRUUl9JTkRFWF0sdFtuLkNIQVJfREFUQV9DSEFSX0lOREVYXS5sZW5ndGg+MT8odGhpcy5fY29tYmluZWRbZV09dFsxXSx0aGlzLl9kYXRhWzMqZSswXT0yMDk3MTUyfGV8dFtuLkNIQVJfREFUQV9XSURUSF9JTkRFWF08PDIyKTp0aGlzLl9kYXRhWzMqZSswXT10W24uQ0hBUl9EQVRBX0NIQVJfSU5ERVhdLmNoYXJDb2RlQXQoMCl8dFtuLkNIQVJfREFUQV9XSURUSF9JTkRFWF08PDIyfSxlLnByb3RvdHlwZS5nZXRXaWR0aD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fZGF0YVszKmUrMF0+PjIyfSxlLnByb3RvdHlwZS5oYXNXaWR0aD1mdW5jdGlvbihlKXtyZXR1cm4gMTI1ODI5MTImdGhpcy5fZGF0YVszKmUrMF19LGUucHJvdG90eXBlLmdldEZnPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9kYXRhWzMqZSsxXX0sZS5wcm90b3R5cGUuZ2V0Qmc9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuX2RhdGFbMyplKzJdfSxlLnByb3RvdHlwZS5oYXNDb250ZW50PWZ1bmN0aW9uKGUpe3JldHVybiA0MTk0MzAzJnRoaXMuX2RhdGFbMyplKzBdfSxlLnByb3RvdHlwZS5nZXRDb2RlUG9pbnQ9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fZGF0YVszKmUrMF07cmV0dXJuIDIwOTcxNTImdD90aGlzLl9jb21iaW5lZFtlXS5jaGFyQ29kZUF0KHRoaXMuX2NvbWJpbmVkW2VdLmxlbmd0aC0xKToyMDk3MTUxJnR9LGUucHJvdG90eXBlLmlzQ29tYmluZWQ9ZnVuY3Rpb24oZSl7cmV0dXJuIDIwOTcxNTImdGhpcy5fZGF0YVszKmUrMF19LGUucHJvdG90eXBlLmdldFN0cmluZz1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9kYXRhWzMqZSswXTtyZXR1cm4gMjA5NzE1MiZ0P3RoaXMuX2NvbWJpbmVkW2VdOjIwOTcxNTEmdD8oMCxpLnN0cmluZ0Zyb21Db2RlUG9pbnQpKDIwOTcxNTEmdCk6IiJ9LGUucHJvdG90eXBlLmxvYWRDZWxsPWZ1bmN0aW9uKGUsdCl7dmFyIHI9MyplO3JldHVybiB0LmNvbnRlbnQ9dGhpcy5fZGF0YVtyKzBdLHQuZmc9dGhpcy5fZGF0YVtyKzFdLHQuYmc9dGhpcy5fZGF0YVtyKzJdLDIwOTcxNTImdC5jb250ZW50JiYodC5jb21iaW5lZERhdGE9dGhpcy5fY29tYmluZWRbZV0pLDI2ODQzNTQ1NiZ0LmJnJiYodC5leHRlbmRlZD10aGlzLl9leHRlbmRlZEF0dHJzW2VdKSx0fSxlLnByb3RvdHlwZS5zZXRDZWxsPWZ1bmN0aW9uKGUsdCl7MjA5NzE1MiZ0LmNvbnRlbnQmJih0aGlzLl9jb21iaW5lZFtlXT10LmNvbWJpbmVkRGF0YSksMjY4NDM1NDU2JnQuYmcmJih0aGlzLl9leHRlbmRlZEF0dHJzW2VdPXQuZXh0ZW5kZWQpLHRoaXMuX2RhdGFbMyplKzBdPXQuY29udGVudCx0aGlzLl9kYXRhWzMqZSsxXT10LmZnLHRoaXMuX2RhdGFbMyplKzJdPXQuYmd9LGUucHJvdG90eXBlLnNldENlbGxGcm9tQ29kZVBvaW50PWZ1bmN0aW9uKGUsdCxyLGksbixvKXsyNjg0MzU0NTYmbiYmKHRoaXMuX2V4dGVuZGVkQXR0cnNbZV09byksdGhpcy5fZGF0YVszKmUrMF09dHxyPDwyMix0aGlzLl9kYXRhWzMqZSsxXT1pLHRoaXMuX2RhdGFbMyplKzJdPW59LGUucHJvdG90eXBlLmFkZENvZGVwb2ludFRvQ2VsbD1mdW5jdGlvbihlLHQpe3ZhciByPXRoaXMuX2RhdGFbMyplKzBdOzIwOTcxNTImcj90aGlzLl9jb21iaW5lZFtlXSs9KDAsaS5zdHJpbmdGcm9tQ29kZVBvaW50KSh0KTooMjA5NzE1MSZyPyh0aGlzLl9jb21iaW5lZFtlXT0oMCxpLnN0cmluZ0Zyb21Db2RlUG9pbnQpKDIwOTcxNTEmcikrKDAsaS5zdHJpbmdGcm9tQ29kZVBvaW50KSh0KSxyJj0tMjA5NzE1MixyfD0yMDk3MTUyKTpyPXR8MTw8MjIsdGhpcy5fZGF0YVszKmUrMF09cil9LGUucHJvdG90eXBlLmluc2VydENlbGxzPWZ1bmN0aW9uKGUsdCxyLGkpe2lmKChlJT10aGlzLmxlbmd0aCkmJjI9PT10aGlzLmdldFdpZHRoKGUtMSkmJnRoaXMuc2V0Q2VsbEZyb21Db2RlUG9pbnQoZS0xLDAsMSwobnVsbD09aT92b2lkIDA6aS5mZyl8fDAsKG51bGw9PWk/dm9pZCAwOmkuYmcpfHwwLChudWxsPT1pP3ZvaWQgMDppLmV4dGVuZGVkKXx8bmV3IHMuRXh0ZW5kZWRBdHRycyksdDx0aGlzLmxlbmd0aC1lKXtmb3IodmFyIG49bmV3IG8uQ2VsbERhdGEsYT10aGlzLmxlbmd0aC1lLXQtMTthPj0wOy0tYSl0aGlzLnNldENlbGwoZSt0K2EsdGhpcy5sb2FkQ2VsbChlK2EsbikpO2ZvcihhPTA7YTx0OysrYSl0aGlzLnNldENlbGwoZSthLHIpfWVsc2UgZm9yKGE9ZTthPHRoaXMubGVuZ3RoOysrYSl0aGlzLnNldENlbGwoYSxyKTsyPT09dGhpcy5nZXRXaWR0aCh0aGlzLmxlbmd0aC0xKSYmdGhpcy5zZXRDZWxsRnJvbUNvZGVQb2ludCh0aGlzLmxlbmd0aC0xLDAsMSwobnVsbD09aT92b2lkIDA6aS5mZyl8fDAsKG51bGw9PWk/dm9pZCAwOmkuYmcpfHwwLChudWxsPT1pP3ZvaWQgMDppLmV4dGVuZGVkKXx8bmV3IHMuRXh0ZW5kZWRBdHRycyl9LGUucHJvdG90eXBlLmRlbGV0ZUNlbGxzPWZ1bmN0aW9uKGUsdCxyLGkpe2lmKGUlPXRoaXMubGVuZ3RoLHQ8dGhpcy5sZW5ndGgtZSl7Zm9yKHZhciBuPW5ldyBvLkNlbGxEYXRhLGE9MDthPHRoaXMubGVuZ3RoLWUtdDsrK2EpdGhpcy5zZXRDZWxsKGUrYSx0aGlzLmxvYWRDZWxsKGUrdCthLG4pKTtmb3IoYT10aGlzLmxlbmd0aC10O2E8dGhpcy5sZW5ndGg7KythKXRoaXMuc2V0Q2VsbChhLHIpfWVsc2UgZm9yKGE9ZTthPHRoaXMubGVuZ3RoOysrYSl0aGlzLnNldENlbGwoYSxyKTtlJiYyPT09dGhpcy5nZXRXaWR0aChlLTEpJiZ0aGlzLnNldENlbGxGcm9tQ29kZVBvaW50KGUtMSwwLDEsKG51bGw9PWk/dm9pZCAwOmkuZmcpfHwwLChudWxsPT1pP3ZvaWQgMDppLmJnKXx8MCwobnVsbD09aT92b2lkIDA6aS5leHRlbmRlZCl8fG5ldyBzLkV4dGVuZGVkQXR0cnMpLDAhPT10aGlzLmdldFdpZHRoKGUpfHx0aGlzLmhhc0NvbnRlbnQoZSl8fHRoaXMuc2V0Q2VsbEZyb21Db2RlUG9pbnQoZSwwLDEsKG51bGw9PWk/dm9pZCAwOmkuZmcpfHwwLChudWxsPT1pP3ZvaWQgMDppLmJnKXx8MCwobnVsbD09aT92b2lkIDA6aS5leHRlbmRlZCl8fG5ldyBzLkV4dGVuZGVkQXR0cnMpfSxlLnByb3RvdHlwZS5yZXBsYWNlQ2VsbHM9ZnVuY3Rpb24oZSx0LHIsaSl7Zm9yKGUmJjI9PT10aGlzLmdldFdpZHRoKGUtMSkmJnRoaXMuc2V0Q2VsbEZyb21Db2RlUG9pbnQoZS0xLDAsMSwobnVsbD09aT92b2lkIDA6aS5mZyl8fDAsKG51bGw9PWk/dm9pZCAwOmkuYmcpfHwwLChudWxsPT1pP3ZvaWQgMDppLmV4dGVuZGVkKXx8bmV3IHMuRXh0ZW5kZWRBdHRycyksdDx0aGlzLmxlbmd0aCYmMj09PXRoaXMuZ2V0V2lkdGgodC0xKSYmdGhpcy5zZXRDZWxsRnJvbUNvZGVQb2ludCh0LDAsMSwobnVsbD09aT92b2lkIDA6aS5mZyl8fDAsKG51bGw9PWk/dm9pZCAwOmkuYmcpfHwwLChudWxsPT1pP3ZvaWQgMDppLmV4dGVuZGVkKXx8bmV3IHMuRXh0ZW5kZWRBdHRycyk7ZTx0JiZlPHRoaXMubGVuZ3RoOyl0aGlzLnNldENlbGwoZSsrLHIpfSxlLnByb3RvdHlwZS5yZXNpemU9ZnVuY3Rpb24oZSx0KXtpZihlIT09dGhpcy5sZW5ndGgpe2lmKGU+dGhpcy5sZW5ndGgpe3ZhciByPW5ldyBVaW50MzJBcnJheSgzKmUpO3RoaXMubGVuZ3RoJiYoMyplPHRoaXMuX2RhdGEubGVuZ3RoP3Iuc2V0KHRoaXMuX2RhdGEuc3ViYXJyYXkoMCwzKmUpKTpyLnNldCh0aGlzLl9kYXRhKSksdGhpcy5fZGF0YT1yO2Zvcih2YXIgaT10aGlzLmxlbmd0aDtpPGU7KytpKXRoaXMuc2V0Q2VsbChpLHQpfWVsc2UgaWYoZSl7KHI9bmV3IFVpbnQzMkFycmF5KDMqZSkpLnNldCh0aGlzLl9kYXRhLnN1YmFycmF5KDAsMyplKSksdGhpcy5fZGF0YT1yO3ZhciBuPU9iamVjdC5rZXlzKHRoaXMuX2NvbWJpbmVkKTtmb3IoaT0wO2k8bi5sZW5ndGg7aSsrKXt2YXIgbz1wYXJzZUludChuW2ldLDEwKTtvPj1lJiZkZWxldGUgdGhpcy5fY29tYmluZWRbb119fWVsc2UgdGhpcy5fZGF0YT1uZXcgVWludDMyQXJyYXkoMCksdGhpcy5fY29tYmluZWQ9e307dGhpcy5sZW5ndGg9ZX19LGUucHJvdG90eXBlLmZpbGw9ZnVuY3Rpb24oZSl7dGhpcy5fY29tYmluZWQ9e30sdGhpcy5fZXh0ZW5kZWRBdHRycz17fTtmb3IodmFyIHQ9MDt0PHRoaXMubGVuZ3RoOysrdCl0aGlzLnNldENlbGwodCxlKX0sZS5wcm90b3R5cGUuY29weUZyb209ZnVuY3Rpb24oZSl7Zm9yKHZhciB0IGluIHRoaXMubGVuZ3RoIT09ZS5sZW5ndGg/dGhpcy5fZGF0YT1uZXcgVWludDMyQXJyYXkoZS5fZGF0YSk6dGhpcy5fZGF0YS5zZXQoZS5fZGF0YSksdGhpcy5sZW5ndGg9ZS5sZW5ndGgsdGhpcy5fY29tYmluZWQ9e30sZS5fY29tYmluZWQpdGhpcy5fY29tYmluZWRbdF09ZS5fY29tYmluZWRbdF07Zm9yKHZhciB0IGluIHRoaXMuX2V4dGVuZGVkQXR0cnM9e30sZS5fZXh0ZW5kZWRBdHRycyl0aGlzLl9leHRlbmRlZEF0dHJzW3RdPWUuX2V4dGVuZGVkQXR0cnNbdF07dGhpcy5pc1dyYXBwZWQ9ZS5pc1dyYXBwZWR9LGUucHJvdG90eXBlLmNsb25lPWZ1bmN0aW9uKCl7dmFyIHQ9bmV3IGUoMCk7Zm9yKHZhciByIGluIHQuX2RhdGE9bmV3IFVpbnQzMkFycmF5KHRoaXMuX2RhdGEpLHQubGVuZ3RoPXRoaXMubGVuZ3RoLHRoaXMuX2NvbWJpbmVkKXQuX2NvbWJpbmVkW3JdPXRoaXMuX2NvbWJpbmVkW3JdO2Zvcih2YXIgciBpbiB0aGlzLl9leHRlbmRlZEF0dHJzKXQuX2V4dGVuZGVkQXR0cnNbcl09dGhpcy5fZXh0ZW5kZWRBdHRyc1tyXTtyZXR1cm4gdC5pc1dyYXBwZWQ9dGhpcy5pc1dyYXBwZWQsdH0sZS5wcm90b3R5cGUuZ2V0VHJpbW1lZExlbmd0aD1mdW5jdGlvbigpe2Zvcih2YXIgZT10aGlzLmxlbmd0aC0xO2U+PTA7LS1lKWlmKDQxOTQzMDMmdGhpcy5fZGF0YVszKmUrMF0pcmV0dXJuIGUrKHRoaXMuX2RhdGFbMyplKzBdPj4yMik7cmV0dXJuIDB9LGUucHJvdG90eXBlLmNvcHlDZWxsc0Zyb209ZnVuY3Rpb24oZSx0LHIsaSxuKXt2YXIgbz1lLl9kYXRhO2lmKG4pZm9yKHZhciBzPWktMTtzPj0wO3MtLSlmb3IodmFyIGE9MDthPDM7YSsrKXRoaXMuX2RhdGFbMyoocitzKSthXT1vWzMqKHQrcykrYV07ZWxzZSBmb3Iocz0wO3M8aTtzKyspZm9yKGE9MDthPDM7YSsrKXRoaXMuX2RhdGFbMyoocitzKSthXT1vWzMqKHQrcykrYV07dmFyIGM9T2JqZWN0LmtleXMoZS5fY29tYmluZWQpO2ZvcihhPTA7YTxjLmxlbmd0aDthKyspe3ZhciBsPXBhcnNlSW50KGNbYV0sMTApO2w+PXQmJih0aGlzLl9jb21iaW5lZFtsLXQrcl09ZS5fY29tYmluZWRbbF0pfX0sZS5wcm90b3R5cGUudHJhbnNsYXRlVG9TdHJpbmc9ZnVuY3Rpb24oZSx0LHIpe3ZvaWQgMD09PWUmJihlPSExKSx2b2lkIDA9PT10JiYodD0wKSx2b2lkIDA9PT1yJiYocj10aGlzLmxlbmd0aCksZSYmKHI9TWF0aC5taW4ocix0aGlzLmdldFRyaW1tZWRMZW5ndGgoKSkpO2Zvcih2YXIgbz0iIjt0PHI7KXt2YXIgcz10aGlzLl9kYXRhWzMqdCswXSxhPTIwOTcxNTEmcztvKz0yMDk3MTUyJnM/dGhpcy5fY29tYmluZWRbdF06YT8oMCxpLnN0cmluZ0Zyb21Db2RlUG9pbnQpKGEpOm4uV0hJVEVTUEFDRV9DRUxMX0NIQVIsdCs9cz4+MjJ8fDF9cmV0dXJuIG99LGV9KCk7dC5CdWZmZXJMaW5lPWF9LDQ4NDE6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5nZXRSYW5nZUxlbmd0aD12b2lkIDAsdC5nZXRSYW5nZUxlbmd0aD1mdW5jdGlvbihlLHQpe2lmKGUuc3RhcnQueT5lLmVuZC55KXRocm93IG5ldyBFcnJvcigiQnVmZmVyIHJhbmdlIGVuZCAoIitlLmVuZC54KyIsICIrZS5lbmQueSsiKSBjYW5ub3QgYmUgYmVmb3JlIHN0YXJ0ICgiK2Uuc3RhcnQueCsiLCAiK2Uuc3RhcnQueSsiKSIpO3JldHVybiB0KihlLmVuZC55LWUuc3RhcnQueSkrKGUuZW5kLngtZS5zdGFydC54KzEpfX0sNDYzNDooZSx0KT0+e2Z1bmN0aW9uIHIoZSx0LHIpe2lmKHQ9PT1lLmxlbmd0aC0xKXJldHVybiBlW3RdLmdldFRyaW1tZWRMZW5ndGgoKTt2YXIgaT0hZVt0XS5oYXNDb250ZW50KHItMSkmJjE9PT1lW3RdLmdldFdpZHRoKHItMSksbj0yPT09ZVt0KzFdLmdldFdpZHRoKDApO3JldHVybiBpJiZuP3ItMTpyfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmdldFdyYXBwZWRMaW5lVHJpbW1lZExlbmd0aD10LnJlZmxvd1NtYWxsZXJHZXROZXdMaW5lTGVuZ3Rocz10LnJlZmxvd0xhcmdlckFwcGx5TmV3TGF5b3V0PXQucmVmbG93TGFyZ2VyQ3JlYXRlTmV3TGF5b3V0PXQucmVmbG93TGFyZ2VyR2V0TGluZXNUb1JlbW92ZT12b2lkIDAsdC5yZWZsb3dMYXJnZXJHZXRMaW5lc1RvUmVtb3ZlPWZ1bmN0aW9uKGUsdCxpLG4sbyl7Zm9yKHZhciBzPVtdLGE9MDthPGUubGVuZ3RoLTE7YSsrKXt2YXIgYz1hLGw9ZS5nZXQoKytjKTtpZihsLmlzV3JhcHBlZCl7Zm9yKHZhciB1PVtlLmdldChhKV07YzxlLmxlbmd0aCYmbC5pc1dyYXBwZWQ7KXUucHVzaChsKSxsPWUuZ2V0KCsrYyk7aWYobj49YSYmbjxjKWErPXUubGVuZ3RoLTE7ZWxzZXtmb3IodmFyIGg9MCxmPXIodSxoLHQpLF89MSxkPTA7Xzx1Lmxlbmd0aDspe3ZhciBwPXIodSxfLHQpLHY9cC1kLGc9aS1mLHk9TWF0aC5taW4odixnKTt1W2hdLmNvcHlDZWxsc0Zyb20odVtfXSxkLGYseSwhMSksKGYrPXkpPT09aSYmKGgrKyxmPTApLChkKz15KT09PXAmJihfKyssZD0wKSwwPT09ZiYmMCE9PWgmJjI9PT11W2gtMV0uZ2V0V2lkdGgoaS0xKSYmKHVbaF0uY29weUNlbGxzRnJvbSh1W2gtMV0saS0xLGYrKywxLCExKSx1W2gtMV0uc2V0Q2VsbChpLTEsbykpfXVbaF0ucmVwbGFjZUNlbGxzKGYsaSxvKTtmb3IodmFyIG09MCxiPXUubGVuZ3RoLTE7Yj4wJiYoYj5ofHwwPT09dVtiXS5nZXRUcmltbWVkTGVuZ3RoKCkpO2ItLSltKys7bT4wJiYocy5wdXNoKGErdS5sZW5ndGgtbSkscy5wdXNoKG0pKSxhKz11Lmxlbmd0aC0xfX19cmV0dXJuIHN9LHQucmVmbG93TGFyZ2VyQ3JlYXRlTmV3TGF5b3V0PWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPVtdLGk9MCxuPXRbaV0sbz0wLHM9MDtzPGUubGVuZ3RoO3MrKylpZihuPT09cyl7dmFyIGE9dFsrK2ldO2Uub25EZWxldGVFbWl0dGVyLmZpcmUoe2luZGV4OnMtbyxhbW91bnQ6YX0pLHMrPWEtMSxvKz1hLG49dFsrK2ldfWVsc2Ugci5wdXNoKHMpO3JldHVybntsYXlvdXQ6cixjb3VudFJlbW92ZWQ6b319LHQucmVmbG93TGFyZ2VyQXBwbHlOZXdMYXlvdXQ9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIHI9W10saT0wO2k8dC5sZW5ndGg7aSsrKXIucHVzaChlLmdldCh0W2ldKSk7Zm9yKGk9MDtpPHIubGVuZ3RoO2krKyllLnNldChpLHJbaV0pO2UubGVuZ3RoPXQubGVuZ3RofSx0LnJlZmxvd1NtYWxsZXJHZXROZXdMaW5lTGVuZ3Rocz1mdW5jdGlvbihlLHQsaSl7Zm9yKHZhciBuPVtdLG89ZS5tYXAoKGZ1bmN0aW9uKGksbil7cmV0dXJuIHIoZSxuLHQpfSkpLnJlZHVjZSgoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSt0fSkpLHM9MCxhPTAsYz0wO2M8bzspe2lmKG8tYzxpKXtuLnB1c2goby1jKTticmVha31zKz1pO3ZhciBsPXIoZSxhLHQpO3M+bCYmKHMtPWwsYSsrKTt2YXIgdT0yPT09ZVthXS5nZXRXaWR0aChzLTEpO3UmJnMtLTt2YXIgaD11P2ktMTppO24ucHVzaChoKSxjKz1ofXJldHVybiBufSx0LmdldFdyYXBwZWRMaW5lVHJpbW1lZExlbmd0aD1yfSw1Mjk1OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkJ1ZmZlclNldD12b2lkIDA7dmFyIG89cig5MDkyKSxzPXIoODQ2MCksYT1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQscil7dmFyIGk9ZS5jYWxsKHRoaXMpfHx0aGlzO3JldHVybiBpLl9vcHRpb25zU2VydmljZT10LGkuX2J1ZmZlclNlcnZpY2U9cixpLl9vbkJ1ZmZlckFjdGl2YXRlPWkucmVnaXN0ZXIobmV3IHMuRXZlbnRFbWl0dGVyKSxpLnJlc2V0KCksaX1yZXR1cm4gbih0LGUpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25CdWZmZXJBY3RpdmF0ZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9vbkJ1ZmZlckFjdGl2YXRlLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLHQucHJvdG90eXBlLnJlc2V0PWZ1bmN0aW9uKCl7dGhpcy5fbm9ybWFsPW5ldyBvLkJ1ZmZlcighMCx0aGlzLl9vcHRpb25zU2VydmljZSx0aGlzLl9idWZmZXJTZXJ2aWNlKSx0aGlzLl9ub3JtYWwuZmlsbFZpZXdwb3J0Um93cygpLHRoaXMuX2FsdD1uZXcgby5CdWZmZXIoITEsdGhpcy5fb3B0aW9uc1NlcnZpY2UsdGhpcy5fYnVmZmVyU2VydmljZSksdGhpcy5fYWN0aXZlQnVmZmVyPXRoaXMuX25vcm1hbCx0aGlzLl9vbkJ1ZmZlckFjdGl2YXRlLmZpcmUoe2FjdGl2ZUJ1ZmZlcjp0aGlzLl9ub3JtYWwsaW5hY3RpdmVCdWZmZXI6dGhpcy5fYWx0fSksdGhpcy5zZXR1cFRhYlN0b3BzKCl9LE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwiYWx0Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2FsdH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsImFjdGl2ZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9hY3RpdmVCdWZmZXJ9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJub3JtYWwiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fbm9ybWFsfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLHQucHJvdG90eXBlLmFjdGl2YXRlTm9ybWFsQnVmZmVyPWZ1bmN0aW9uKCl7dGhpcy5fYWN0aXZlQnVmZmVyIT09dGhpcy5fbm9ybWFsJiYodGhpcy5fbm9ybWFsLng9dGhpcy5fYWx0LngsdGhpcy5fbm9ybWFsLnk9dGhpcy5fYWx0LnksdGhpcy5fYWx0LmNsZWFyKCksdGhpcy5fYWN0aXZlQnVmZmVyPXRoaXMuX25vcm1hbCx0aGlzLl9vbkJ1ZmZlckFjdGl2YXRlLmZpcmUoe2FjdGl2ZUJ1ZmZlcjp0aGlzLl9ub3JtYWwsaW5hY3RpdmVCdWZmZXI6dGhpcy5fYWx0fSkpfSx0LnByb3RvdHlwZS5hY3RpdmF0ZUFsdEJ1ZmZlcj1mdW5jdGlvbihlKXt0aGlzLl9hY3RpdmVCdWZmZXIhPT10aGlzLl9hbHQmJih0aGlzLl9hbHQuZmlsbFZpZXdwb3J0Um93cyhlKSx0aGlzLl9hbHQueD10aGlzLl9ub3JtYWwueCx0aGlzLl9hbHQueT10aGlzLl9ub3JtYWwueSx0aGlzLl9hY3RpdmVCdWZmZXI9dGhpcy5fYWx0LHRoaXMuX29uQnVmZmVyQWN0aXZhdGUuZmlyZSh7YWN0aXZlQnVmZmVyOnRoaXMuX2FsdCxpbmFjdGl2ZUJ1ZmZlcjp0aGlzLl9ub3JtYWx9KSl9LHQucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbihlLHQpe3RoaXMuX25vcm1hbC5yZXNpemUoZSx0KSx0aGlzLl9hbHQucmVzaXplKGUsdCl9LHQucHJvdG90eXBlLnNldHVwVGFiU3RvcHM9ZnVuY3Rpb24oZSl7dGhpcy5fbm9ybWFsLnNldHVwVGFiU3RvcHMoZSksdGhpcy5fYWx0LnNldHVwVGFiU3RvcHMoZSl9LHR9KHIoODQ0KS5EaXNwb3NhYmxlKTt0LkJ1ZmZlclNldD1hfSw1MTE6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49dGhpcyYmdGhpcy5fX2V4dGVuZHN8fChpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGk9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQscikmJihlW3JdPXRbcl0pfSxpKGUsdCl9LGZ1bmN0aW9uKGUsdCl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIkNsYXNzIGV4dGVuZHMgdmFsdWUgIitTdHJpbmcodCkrIiBpcyBub3QgYSBjb25zdHJ1Y3RvciBvciBudWxsIik7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1pKGUsdCksZS5wcm90b3R5cGU9bnVsbD09PXQ/T2JqZWN0LmNyZWF0ZSh0KTooci5wcm90b3R5cGU9dC5wcm90b3R5cGUsbmV3IHIpfSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQ2VsbERhdGE9dm9pZCAwO3ZhciBvPXIoNDgyKSxzPXIoNjQzKSxhPXIoMzczNCksYz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7dmFyIHQ9bnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzO3JldHVybiB0LmNvbnRlbnQ9MCx0LmZnPTAsdC5iZz0wLHQuZXh0ZW5kZWQ9bmV3IGEuRXh0ZW5kZWRBdHRycyx0LmNvbWJpbmVkRGF0YT0iIix0fXJldHVybiBuKHQsZSksdC5mcm9tQ2hhckRhdGE9ZnVuY3Rpb24oZSl7dmFyIHI9bmV3IHQ7cmV0dXJuIHIuc2V0RnJvbUNoYXJEYXRhKGUpLHJ9LHQucHJvdG90eXBlLmlzQ29tYmluZWQ9ZnVuY3Rpb24oKXtyZXR1cm4gMjA5NzE1MiZ0aGlzLmNvbnRlbnR9LHQucHJvdG90eXBlLmdldFdpZHRoPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuY29udGVudD4+MjJ9LHQucHJvdG90eXBlLmdldENoYXJzPWZ1bmN0aW9uKCl7cmV0dXJuIDIwOTcxNTImdGhpcy5jb250ZW50P3RoaXMuY29tYmluZWREYXRhOjIwOTcxNTEmdGhpcy5jb250ZW50PygwLG8uc3RyaW5nRnJvbUNvZGVQb2ludCkoMjA5NzE1MSZ0aGlzLmNvbnRlbnQpOiIifSx0LnByb3RvdHlwZS5nZXRDb2RlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuaXNDb21iaW5lZCgpP3RoaXMuY29tYmluZWREYXRhLmNoYXJDb2RlQXQodGhpcy5jb21iaW5lZERhdGEubGVuZ3RoLTEpOjIwOTcxNTEmdGhpcy5jb250ZW50fSx0LnByb3RvdHlwZS5zZXRGcm9tQ2hhckRhdGE9ZnVuY3Rpb24oZSl7dGhpcy5mZz1lW3MuQ0hBUl9EQVRBX0FUVFJfSU5ERVhdLHRoaXMuYmc9MDt2YXIgdD0hMTtpZihlW3MuQ0hBUl9EQVRBX0NIQVJfSU5ERVhdLmxlbmd0aD4yKXQ9ITA7ZWxzZSBpZigyPT09ZVtzLkNIQVJfREFUQV9DSEFSX0lOREVYXS5sZW5ndGgpe3ZhciByPWVbcy5DSEFSX0RBVEFfQ0hBUl9JTkRFWF0uY2hhckNvZGVBdCgwKTtpZig1NTI5Njw9ciYmcjw9NTYzMTkpe3ZhciBpPWVbcy5DSEFSX0RBVEFfQ0hBUl9JTkRFWF0uY2hhckNvZGVBdCgxKTs1NjMyMDw9aSYmaTw9NTczNDM/dGhpcy5jb250ZW50PTEwMjQqKHItNTUyOTYpK2ktNTYzMjArNjU1MzZ8ZVtzLkNIQVJfREFUQV9XSURUSF9JTkRFWF08PDIyOnQ9ITB9ZWxzZSB0PSEwfWVsc2UgdGhpcy5jb250ZW50PWVbcy5DSEFSX0RBVEFfQ0hBUl9JTkRFWF0uY2hhckNvZGVBdCgwKXxlW3MuQ0hBUl9EQVRBX1dJRFRIX0lOREVYXTw8MjI7dCYmKHRoaXMuY29tYmluZWREYXRhPWVbcy5DSEFSX0RBVEFfQ0hBUl9JTkRFWF0sdGhpcy5jb250ZW50PTIwOTcxNTJ8ZVtzLkNIQVJfREFUQV9XSURUSF9JTkRFWF08PDIyKX0sdC5wcm90b3R5cGUuZ2V0QXNDaGFyRGF0YT1mdW5jdGlvbigpe3JldHVyblt0aGlzLmZnLHRoaXMuZ2V0Q2hhcnMoKSx0aGlzLmdldFdpZHRoKCksdGhpcy5nZXRDb2RlKCldfSx0fShhLkF0dHJpYnV0ZURhdGEpO3QuQ2VsbERhdGE9Y30sNjQzOihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuV0hJVEVTUEFDRV9DRUxMX0NPREU9dC5XSElURVNQQUNFX0NFTExfV0lEVEg9dC5XSElURVNQQUNFX0NFTExfQ0hBUj10Lk5VTExfQ0VMTF9DT0RFPXQuTlVMTF9DRUxMX1dJRFRIPXQuTlVMTF9DRUxMX0NIQVI9dC5DSEFSX0RBVEFfQ09ERV9JTkRFWD10LkNIQVJfREFUQV9XSURUSF9JTkRFWD10LkNIQVJfREFUQV9DSEFSX0lOREVYPXQuQ0hBUl9EQVRBX0FUVFJfSU5ERVg9dC5ERUZBVUxUX0FUVFI9dC5ERUZBVUxUX0NPTE9SPXZvaWQgMCx0LkRFRkFVTFRfQ09MT1I9MjU2LHQuREVGQVVMVF9BVFRSPTI1Nnx0LkRFRkFVTFRfQ09MT1I8PDksdC5DSEFSX0RBVEFfQVRUUl9JTkRFWD0wLHQuQ0hBUl9EQVRBX0NIQVJfSU5ERVg9MSx0LkNIQVJfREFUQV9XSURUSF9JTkRFWD0yLHQuQ0hBUl9EQVRBX0NPREVfSU5ERVg9Myx0Lk5VTExfQ0VMTF9DSEFSPSIiLHQuTlVMTF9DRUxMX1dJRFRIPTEsdC5OVUxMX0NFTExfQ09ERT0wLHQuV0hJVEVTUEFDRV9DRUxMX0NIQVI9IiAiLHQuV0hJVEVTUEFDRV9DRUxMX1dJRFRIPTEsdC5XSElURVNQQUNFX0NFTExfQ09ERT0zMn0sNDg2MzpmdW5jdGlvbihlLHQscil7dmFyIGksbj10aGlzJiZ0aGlzLl9fZXh0ZW5kc3x8KGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gaT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIHIgaW4gdClPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxyKSYmKGVbcl09dFtyXSl9LGkoZSx0KX0sZnVuY3Rpb24oZSx0KXtpZigiZnVuY3Rpb24iIT10eXBlb2YgdCYmbnVsbCE9PXQpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2xhc3MgZXh0ZW5kcyB2YWx1ZSAiK1N0cmluZyh0KSsiIGlzIG5vdCBhIGNvbnN0cnVjdG9yIG9yIG51bGwiKTtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj1lfWkoZSx0KSxlLnByb3RvdHlwZT1udWxsPT09dD9PYmplY3QuY3JlYXRlKHQpOihyLnByb3RvdHlwZT10LnByb3RvdHlwZSxuZXcgcil9KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5NYXJrZXI9dm9pZCAwO3ZhciBvPXIoODQ2MCkscz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHIpe3ZhciBpPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gaS5saW5lPXIsaS5faWQ9dC5fbmV4dElkKyssaS5pc0Rpc3Bvc2VkPSExLGkuX29uRGlzcG9zZT1uZXcgby5FdmVudEVtaXR0ZXIsaX1yZXR1cm4gbih0LGUpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwiaWQiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5faWR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvbkRpc3Bvc2UiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25EaXNwb3NlLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLHQucHJvdG90eXBlLmRpc3Bvc2U9ZnVuY3Rpb24oKXt0aGlzLmlzRGlzcG9zZWR8fCh0aGlzLmlzRGlzcG9zZWQ9ITAsdGhpcy5saW5lPS0xLHRoaXMuX29uRGlzcG9zZS5maXJlKCksZS5wcm90b3R5cGUuZGlzcG9zZS5jYWxsKHRoaXMpKX0sdC5fbmV4dElkPTEsdH0ocig4NDQpLkRpc3Bvc2FibGUpO3QuTWFya2VyPXN9LDcxMTY6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5ERUZBVUxUX0NIQVJTRVQ9dC5DSEFSU0VUUz12b2lkIDAsdC5DSEFSU0VUUz17fSx0LkRFRkFVTFRfQ0hBUlNFVD10LkNIQVJTRVRTLkIsdC5DSEFSU0VUU1swXT17ImAiOiLil4YiLGE6IuKWkiIsYjoi4pCJIixjOiLikIwiLGQ6IuKQjSIsZToi4pCKIixmOiLCsCIsZzoiwrEiLGg6IuKQpCIsaToi4pCLIixqOiLilJgiLGs6IuKUkCIsbDoi4pSMIixtOiLilJQiLG46IuKUvCIsbzoi4o66IixwOiLijrsiLHE6IuKUgCIscjoi4o68IixzOiLijr0iLHQ6IuKUnCIsdToi4pSkIix2OiLilLQiLHc6IuKUrCIseDoi4pSCIix5OiLiiaQiLHo6IuKJpSIsInsiOiLPgCIsInwiOiLiiaAiLCJ9IjoiwqMiLCJ+IjoiwrcifSx0LkNIQVJTRVRTLkE9eyIjIjoiwqMifSx0LkNIQVJTRVRTLkI9dm9pZCAwLHQuQ0hBUlNFVFNbNF09eyIjIjoiwqMiLCJAIjoiwr4iLCJbIjoiaWoiLCJcXCI6IsK9IiwiXSI6InwiLCJ7IjoiwqgiLCJ8IjoiZiIsIn0iOiLCvCIsIn4iOiLCtCJ9LHQuQ0hBUlNFVFMuQz10LkNIQVJTRVRTWzVdPXsiWyI6IsOEIiwiXFwiOiLDliIsIl0iOiLDhSIsIl4iOiLDnCIsImAiOiLDqSIsInsiOiLDpCIsInwiOiLDtiIsIn0iOiLDpSIsIn4iOiLDvCJ9LHQuQ0hBUlNFVFMuUj17IiMiOiLCoyIsIkAiOiLDoCIsIlsiOiLCsCIsIlxcIjoiw6ciLCJdIjoiwqciLCJ7Ijoiw6kiLCJ8Ijoiw7kiLCJ9Ijoiw6giLCJ+IjoiwqgifSx0LkNIQVJTRVRTLlE9eyJAIjoiw6AiLCJbIjoiw6IiLCJcXCI6IsOnIiwiXSI6IsOqIiwiXiI6IsOuIiwiYCI6IsO0IiwieyI6IsOpIiwifCI6IsO5IiwifSI6IsOoIiwifiI6IsO7In0sdC5DSEFSU0VUUy5LPXsiQCI6IsKnIiwiWyI6IsOEIiwiXFwiOiLDliIsIl0iOiLDnCIsInsiOiLDpCIsInwiOiLDtiIsIn0iOiLDvCIsIn4iOiLDnyJ9LHQuQ0hBUlNFVFMuWT17IiMiOiLCoyIsIkAiOiLCpyIsIlsiOiLCsCIsIlxcIjoiw6ciLCJdIjoiw6kiLCJgIjoiw7kiLCJ7Ijoiw6AiLCJ8Ijoiw7IiLCJ9Ijoiw6giLCJ+Ijoiw6wifSx0LkNIQVJTRVRTLkU9dC5DSEFSU0VUU1s2XT17IkAiOiLDhCIsIlsiOiLDhiIsIlxcIjoiw5giLCJdIjoiw4UiLCJeIjoiw5wiLCJgIjoiw6QiLCJ7Ijoiw6YiLCJ8Ijoiw7giLCJ9Ijoiw6UiLCJ+Ijoiw7wifSx0LkNIQVJTRVRTLlo9eyIjIjoiwqMiLCJAIjoiwqciLCJbIjoiwqEiLCJcXCI6IsORIiwiXSI6IsK/IiwieyI6IsKwIiwifCI6IsOxIiwifSI6IsOnIn0sdC5DSEFSU0VUUy5IPXQuQ0hBUlNFVFNbN109eyJAIjoiw4kiLCJbIjoiw4QiLCJcXCI6IsOWIiwiXSI6IsOFIiwiXiI6IsOcIiwiYCI6IsOpIiwieyI6IsOkIiwifCI6IsO2IiwifSI6IsOlIiwifiI6IsO8In0sdC5DSEFSU0VUU1siPSJdPXsiIyI6IsO5IiwiQCI6IsOgIiwiWyI6IsOpIiwiXFwiOiLDpyIsIl0iOiLDqiIsIl4iOiLDriIsXzoiw6giLCJgIjoiw7QiLCJ7Ijoiw6QiLCJ8Ijoiw7YiLCJ9Ijoiw7wiLCJ+Ijoiw7sifX0sMjU4NDooZSx0KT0+e3ZhciByLGk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQzE9dC5DMD12b2lkIDAsKGk9dC5DMHx8KHQuQzA9e30pKS5OVUw9IlwwIixpLlNPSD0iASIsaS5TVFg9IgIiLGkuRVRYPSIDIixpLkVPVD0iBCIsaS5FTlE9IgUiLGkuQUNLPSIGIixpLkJFTD0iByIsaS5CUz0iXGIiLGkuSFQ9Ilx0IixpLkxGPSJcbiIsaS5WVD0iXHYiLGkuRkY9IlxmIixpLkNSPSJcciIsaS5TTz0iDiIsaS5TST0iDyIsaS5ETEU9IhAiLGkuREMxPSIRIixpLkRDMj0iEiIsaS5EQzM9IhMiLGkuREM0PSIUIixpLk5BSz0iFSIsaS5TWU49IhYiLGkuRVRCPSIXIixpLkNBTj0iGCIsaS5FTT0iGSIsaS5TVUI9IhoiLGkuRVNDPSIbIixpLkZTPSIcIixpLkdTPSIdIixpLlJTPSIeIixpLlVTPSIfIixpLlNQPSIgIixpLkRFTD0ifyIsKHI9dC5DMXx8KHQuQzE9e30pKS5QQUQ9IsKAIixyLkhPUD0iwoEiLHIuQlBIPSLCgiIsci5OQkg9IsKDIixyLklORD0iwoQiLHIuTkVMPSLChSIsci5TU0E9IsKGIixyLkVTQT0iwociLHIuSFRTPSLCiCIsci5IVEo9IsKJIixyLlZUUz0iwooiLHIuUExEPSLCiyIsci5QTFU9IsKMIixyLlJJPSLCjSIsci5TUzI9IsKOIixyLlNTMz0iwo8iLHIuRENTPSLCkCIsci5QVTE9IsKRIixyLlBVMj0iwpIiLHIuU1RTPSLCkyIsci5DQ0g9IsKUIixyLk1XPSLClSIsci5TUEE9IsKWIixyLkVQQT0iwpciLHIuU09TPSLCmCIsci5TR0NJPSLCmSIsci5TQ0k9IsKaIixyLkNTST0iwpsiLHIuU1Q9IsKcIixyLk9TQz0iwp0iLHIuUE09IsKeIixyLkFQQz0iwp8ifSw3Mzk5OihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5ldmFsdWF0ZUtleWJvYXJkRXZlbnQ9dm9pZCAwO3ZhciBpPXIoMjU4NCksbj17NDg6WyIwIiwiKSJdLDQ5OlsiMSIsIiEiXSw1MDpbIjIiLCJAIl0sNTE6WyIzIiwiIyJdLDUyOlsiNCIsIiQiXSw1MzpbIjUiLCIlIl0sNTQ6WyI2IiwiXiJdLDU1OlsiNyIsIiYiXSw1NjpbIjgiLCIqIl0sNTc6WyI5IiwiKCJdLDE4NjpbIjsiLCI6Il0sMTg3OlsiPSIsIisiXSwxODg6WyIsIiwiPCJdLDE4OTpbIi0iLCJfIl0sMTkwOlsiLiIsIj4iXSwxOTE6WyIvIiwiPyJdLDE5MjpbImAiLCJ+Il0sMjE5OlsiWyIsInsiXSwyMjA6WyJcXCIsInwiXSwyMjE6WyJdIiwifSJdLDIyMjpbIiciLCciJ119O3QuZXZhbHVhdGVLZXlib2FyZEV2ZW50PWZ1bmN0aW9uKGUsdCxyLG8pe3ZhciBzPXt0eXBlOjAsY2FuY2VsOiExLGtleTp2b2lkIDB9LGE9KGUuc2hpZnRLZXk/MTowKXwoZS5hbHRLZXk/MjowKXwoZS5jdHJsS2V5PzQ6MCl8KGUubWV0YUtleT84OjApO3N3aXRjaChlLmtleUNvZGUpe2Nhc2UgMDoiVUlLZXlJbnB1dFVwQXJyb3ciPT09ZS5rZXk/cy5rZXk9dD9pLkMwLkVTQysiT0EiOmkuQzAuRVNDKyJbQSI6IlVJS2V5SW5wdXRMZWZ0QXJyb3ciPT09ZS5rZXk/cy5rZXk9dD9pLkMwLkVTQysiT0QiOmkuQzAuRVNDKyJbRCI6IlVJS2V5SW5wdXRSaWdodEFycm93Ij09PWUua2V5P3Mua2V5PXQ/aS5DMC5FU0MrIk9DIjppLkMwLkVTQysiW0MiOiJVSUtleUlucHV0RG93bkFycm93Ij09PWUua2V5JiYocy5rZXk9dD9pLkMwLkVTQysiT0IiOmkuQzAuRVNDKyJbQiIpO2JyZWFrO2Nhc2UgODppZihlLnNoaWZ0S2V5KXtzLmtleT1pLkMwLkJTO2JyZWFrfWlmKGUuYWx0S2V5KXtzLmtleT1pLkMwLkVTQytpLkMwLkRFTDticmVha31zLmtleT1pLkMwLkRFTDticmVhaztjYXNlIDk6aWYoZS5zaGlmdEtleSl7cy5rZXk9aS5DMC5FU0MrIltaIjticmVha31zLmtleT1pLkMwLkhULHMuY2FuY2VsPSEwO2JyZWFrO2Nhc2UgMTM6cy5rZXk9ZS5hbHRLZXk/aS5DMC5FU0MraS5DMC5DUjppLkMwLkNSLHMuY2FuY2VsPSEwO2JyZWFrO2Nhc2UgMjc6cy5rZXk9aS5DMC5FU0MsZS5hbHRLZXkmJihzLmtleT1pLkMwLkVTQytpLkMwLkVTQykscy5jYW5jZWw9ITA7YnJlYWs7Y2FzZSAzNzppZihlLm1ldGFLZXkpYnJlYWs7YT8ocy5rZXk9aS5DMC5FU0MrIlsxOyIrKGErMSkrIkQiLHMua2V5PT09aS5DMC5FU0MrIlsxOzNEIiYmKHMua2V5PWkuQzAuRVNDKyhyPyJiIjoiWzE7NUQiKSkpOnMua2V5PXQ/aS5DMC5FU0MrIk9EIjppLkMwLkVTQysiW0QiO2JyZWFrO2Nhc2UgMzk6aWYoZS5tZXRhS2V5KWJyZWFrO2E/KHMua2V5PWkuQzAuRVNDKyJbMTsiKyhhKzEpKyJDIixzLmtleT09PWkuQzAuRVNDKyJbMTszQyImJihzLmtleT1pLkMwLkVTQysocj8iZiI6IlsxOzVDIikpKTpzLmtleT10P2kuQzAuRVNDKyJPQyI6aS5DMC5FU0MrIltDIjticmVhaztjYXNlIDM4OmlmKGUubWV0YUtleSlicmVhazthPyhzLmtleT1pLkMwLkVTQysiWzE7IisoYSsxKSsiQSIscnx8cy5rZXkhPT1pLkMwLkVTQysiWzE7M0EifHwocy5rZXk9aS5DMC5FU0MrIlsxOzVBIikpOnMua2V5PXQ/aS5DMC5FU0MrIk9BIjppLkMwLkVTQysiW0EiO2JyZWFrO2Nhc2UgNDA6aWYoZS5tZXRhS2V5KWJyZWFrO2E/KHMua2V5PWkuQzAuRVNDKyJbMTsiKyhhKzEpKyJCIixyfHxzLmtleSE9PWkuQzAuRVNDKyJbMTszQiJ8fChzLmtleT1pLkMwLkVTQysiWzE7NUIiKSk6cy5rZXk9dD9pLkMwLkVTQysiT0IiOmkuQzAuRVNDKyJbQiI7YnJlYWs7Y2FzZSA0NTplLnNoaWZ0S2V5fHxlLmN0cmxLZXl8fChzLmtleT1pLkMwLkVTQysiWzJ+Iik7YnJlYWs7Y2FzZSA0NjpzLmtleT1hP2kuQzAuRVNDKyJbMzsiKyhhKzEpKyJ+IjppLkMwLkVTQysiWzN+IjticmVhaztjYXNlIDM2OnMua2V5PWE/aS5DMC5FU0MrIlsxOyIrKGErMSkrIkgiOnQ/aS5DMC5FU0MrIk9IIjppLkMwLkVTQysiW0giO2JyZWFrO2Nhc2UgMzU6cy5rZXk9YT9pLkMwLkVTQysiWzE7IisoYSsxKSsiRiI6dD9pLkMwLkVTQysiT0YiOmkuQzAuRVNDKyJbRiI7YnJlYWs7Y2FzZSAzMzplLnNoaWZ0S2V5P3MudHlwZT0yOnMua2V5PWkuQzAuRVNDKyJbNX4iO2JyZWFrO2Nhc2UgMzQ6ZS5zaGlmdEtleT9zLnR5cGU9MzpzLmtleT1pLkMwLkVTQysiWzZ+IjticmVhaztjYXNlIDExMjpzLmtleT1hP2kuQzAuRVNDKyJbMTsiKyhhKzEpKyJQIjppLkMwLkVTQysiT1AiO2JyZWFrO2Nhc2UgMTEzOnMua2V5PWE/aS5DMC5FU0MrIlsxOyIrKGErMSkrIlEiOmkuQzAuRVNDKyJPUSI7YnJlYWs7Y2FzZSAxMTQ6cy5rZXk9YT9pLkMwLkVTQysiWzE7IisoYSsxKSsiUiI6aS5DMC5FU0MrIk9SIjticmVhaztjYXNlIDExNTpzLmtleT1hP2kuQzAuRVNDKyJbMTsiKyhhKzEpKyJTIjppLkMwLkVTQysiT1MiO2JyZWFrO2Nhc2UgMTE2OnMua2V5PWE/aS5DMC5FU0MrIlsxNTsiKyhhKzEpKyJ+IjppLkMwLkVTQysiWzE1fiI7YnJlYWs7Y2FzZSAxMTc6cy5rZXk9YT9pLkMwLkVTQysiWzE3OyIrKGErMSkrIn4iOmkuQzAuRVNDKyJbMTd+IjticmVhaztjYXNlIDExODpzLmtleT1hP2kuQzAuRVNDKyJbMTg7IisoYSsxKSsifiI6aS5DMC5FU0MrIlsxOH4iO2JyZWFrO2Nhc2UgMTE5OnMua2V5PWE/aS5DMC5FU0MrIlsxOTsiKyhhKzEpKyJ+IjppLkMwLkVTQysiWzE5fiI7YnJlYWs7Y2FzZSAxMjA6cy5rZXk9YT9pLkMwLkVTQysiWzIwOyIrKGErMSkrIn4iOmkuQzAuRVNDKyJbMjB+IjticmVhaztjYXNlIDEyMTpzLmtleT1hP2kuQzAuRVNDKyJbMjE7IisoYSsxKSsifiI6aS5DMC5FU0MrIlsyMX4iO2JyZWFrO2Nhc2UgMTIyOnMua2V5PWE/aS5DMC5FU0MrIlsyMzsiKyhhKzEpKyJ+IjppLkMwLkVTQysiWzIzfiI7YnJlYWs7Y2FzZSAxMjM6cy5rZXk9YT9pLkMwLkVTQysiWzI0OyIrKGErMSkrIn4iOmkuQzAuRVNDKyJbMjR+IjticmVhaztkZWZhdWx0OmlmKCFlLmN0cmxLZXl8fGUuc2hpZnRLZXl8fGUuYWx0S2V5fHxlLm1ldGFLZXkpaWYociYmIW98fCFlLmFsdEtleXx8ZS5tZXRhS2V5KSFyfHxlLmFsdEtleXx8ZS5jdHJsS2V5fHxlLnNoaWZ0S2V5fHwhZS5tZXRhS2V5P2Uua2V5JiYhZS5jdHJsS2V5JiYhZS5hbHRLZXkmJiFlLm1ldGFLZXkmJmUua2V5Q29kZT49NDgmJjE9PT1lLmtleS5sZW5ndGg/cy5rZXk9ZS5rZXk6ZS5rZXkmJmUuY3RybEtleSYmIl8iPT09ZS5rZXkmJihzLmtleT1pLkMwLlVTKTo2NT09PWUua2V5Q29kZSYmKHMudHlwZT0xKTtlbHNle3ZhciBjPW5bZS5rZXlDb2RlXSxsPW51bGw9PWM/dm9pZCAwOmNbZS5zaGlmdEtleT8xOjBdO2lmKGwpcy5rZXk9aS5DMC5FU0MrbDtlbHNlIGlmKGUua2V5Q29kZT49NjUmJmUua2V5Q29kZTw9OTApe3ZhciB1PWUuY3RybEtleT9lLmtleUNvZGUtNjQ6ZS5rZXlDb2RlKzMyO3Mua2V5PWkuQzAuRVNDK1N0cmluZy5mcm9tQ2hhckNvZGUodSl9fWVsc2UgZS5rZXlDb2RlPj02NSYmZS5rZXlDb2RlPD05MD9zLmtleT1TdHJpbmcuZnJvbUNoYXJDb2RlKGUua2V5Q29kZS02NCk6MzI9PT1lLmtleUNvZGU/cy5rZXk9aS5DMC5OVUw6ZS5rZXlDb2RlPj01MSYmZS5rZXlDb2RlPD01NT9zLmtleT1TdHJpbmcuZnJvbUNoYXJDb2RlKGUua2V5Q29kZS01MSsyNyk6NTY9PT1lLmtleUNvZGU/cy5rZXk9aS5DMC5ERUw6MjE5PT09ZS5rZXlDb2RlP3Mua2V5PWkuQzAuRVNDOjIyMD09PWUua2V5Q29kZT9zLmtleT1pLkMwLkZTOjIyMT09PWUua2V5Q29kZSYmKHMua2V5PWkuQzAuR1MpfXJldHVybiBzfX0sNDgyOihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuVXRmOFRvVXRmMzI9dC5TdHJpbmdUb1V0ZjMyPXQudXRmMzJUb1N0cmluZz10LnN0cmluZ0Zyb21Db2RlUG9pbnQ9dm9pZCAwLHQuc3RyaW5nRnJvbUNvZGVQb2ludD1mdW5jdGlvbihlKXtyZXR1cm4gZT42NTUzNT8oZS09NjU1MzYsU3RyaW5nLmZyb21DaGFyQ29kZSg1NTI5NisoZT4+MTApKStTdHJpbmcuZnJvbUNoYXJDb2RlKGUlMTAyNCs1NjMyMCkpOlN0cmluZy5mcm9tQ2hhckNvZGUoZSl9LHQudXRmMzJUb1N0cmluZz1mdW5jdGlvbihlLHQscil7dm9pZCAwPT09dCYmKHQ9MCksdm9pZCAwPT09ciYmKHI9ZS5sZW5ndGgpO2Zvcih2YXIgaT0iIixuPXQ7bjxyOysrbil7dmFyIG89ZVtuXTtvPjY1NTM1PyhvLT02NTUzNixpKz1TdHJpbmcuZnJvbUNoYXJDb2RlKDU1Mjk2KyhvPj4xMCkpK1N0cmluZy5mcm9tQ2hhckNvZGUobyUxMDI0KzU2MzIwKSk6aSs9U3RyaW5nLmZyb21DaGFyQ29kZShvKX1yZXR1cm4gaX07dmFyIHI9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7dGhpcy5faW50ZXJpbT0wfXJldHVybiBlLnByb3RvdHlwZS5jbGVhcj1mdW5jdGlvbigpe3RoaXMuX2ludGVyaW09MH0sZS5wcm90b3R5cGUuZGVjb2RlPWZ1bmN0aW9uKGUsdCl7dmFyIHI9ZS5sZW5ndGg7aWYoIXIpcmV0dXJuIDA7dmFyIGk9MCxuPTA7dGhpcy5faW50ZXJpbSYmKDU2MzIwPD0oYT1lLmNoYXJDb2RlQXQobisrKSkmJmE8PTU3MzQzP3RbaSsrXT0xMDI0Kih0aGlzLl9pbnRlcmltLTU1Mjk2KSthLTU2MzIwKzY1NTM2Oih0W2krK109dGhpcy5faW50ZXJpbSx0W2krK109YSksdGhpcy5faW50ZXJpbT0wKTtmb3IodmFyIG89bjtvPHI7KytvKXt2YXIgcz1lLmNoYXJDb2RlQXQobyk7aWYoNTUyOTY8PXMmJnM8PTU2MzE5KXtpZigrK28+PXIpcmV0dXJuIHRoaXMuX2ludGVyaW09cyxpO3ZhciBhOzU2MzIwPD0oYT1lLmNoYXJDb2RlQXQobykpJiZhPD01NzM0Mz90W2krK109MTAyNCoocy01NTI5NikrYS01NjMyMCs2NTUzNjoodFtpKytdPXMsdFtpKytdPWEpfWVsc2UgNjUyNzkhPT1zJiYodFtpKytdPXMpfXJldHVybiBpfSxlfSgpO3QuU3RyaW5nVG9VdGYzMj1yO3ZhciBpPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMuaW50ZXJpbT1uZXcgVWludDhBcnJheSgzKX1yZXR1cm4gZS5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXt0aGlzLmludGVyaW0uZmlsbCgwKX0sZS5wcm90b3R5cGUuZGVjb2RlPWZ1bmN0aW9uKGUsdCl7dmFyIHI9ZS5sZW5ndGg7aWYoIXIpcmV0dXJuIDA7dmFyIGksbixvLHMsYT0wLGM9MCxsPTA7aWYodGhpcy5pbnRlcmltWzBdKXt2YXIgdT0hMSxoPXRoaXMuaW50ZXJpbVswXTtoJj0xOTI9PSgyMjQmaCk/MzE6MjI0PT0oMjQwJmgpPzE1Ojc7Zm9yKHZhciBmPTAsXz12b2lkIDA7KF89NjMmdGhpcy5pbnRlcmltWysrZl0pJiZmPDQ7KWg8PD02LGh8PV87Zm9yKHZhciBkPTE5Mj09KDIyNCZ0aGlzLmludGVyaW1bMF0pPzI6MjI0PT0oMjQwJnRoaXMuaW50ZXJpbVswXSk/Mzo0LHA9ZC1mO2w8cDspe2lmKGw+PXIpcmV0dXJuIDA7aWYoMTI4IT0oMTkyJihfPWVbbCsrXSkpKXtsLS0sdT0hMDticmVha310aGlzLmludGVyaW1bZisrXT1fLGg8PD02LGh8PTYzJl99dXx8KDI9PT1kP2g8MTI4P2wtLTp0W2ErK109aDozPT09ZD9oPDIwNDh8fGg+PTU1Mjk2JiZoPD01NzM0M3x8NjUyNzk9PT1ofHwodFthKytdPWgpOmg8NjU1MzZ8fGg+MTExNDExMXx8KHRbYSsrXT1oKSksdGhpcy5pbnRlcmltLmZpbGwoMCl9Zm9yKHZhciB2PXItNCxnPWw7ZzxyOyl7Zm9yKDshKCEoZzx2KXx8MTI4JihpPWVbZ10pfHwxMjgmKG49ZVtnKzFdKXx8MTI4JihvPWVbZysyXSl8fDEyOCYocz1lW2crM10pKTspdFthKytdPWksdFthKytdPW4sdFthKytdPW8sdFthKytdPXMsZys9NDtpZigoaT1lW2crK10pPDEyOCl0W2ErK109aTtlbHNlIGlmKDE5Mj09KDIyNCZpKSl7aWYoZz49cilyZXR1cm4gdGhpcy5pbnRlcmltWzBdPWksYTtpZigxMjghPSgxOTImKG49ZVtnKytdKSkpe2ctLTtjb250aW51ZX1pZigoYz0oMzEmaSk8PDZ8NjMmbik8MTI4KXtnLS07Y29udGludWV9dFthKytdPWN9ZWxzZSBpZigyMjQ9PSgyNDAmaSkpe2lmKGc+PXIpcmV0dXJuIHRoaXMuaW50ZXJpbVswXT1pLGE7aWYoMTI4IT0oMTkyJihuPWVbZysrXSkpKXtnLS07Y29udGludWV9aWYoZz49cilyZXR1cm4gdGhpcy5pbnRlcmltWzBdPWksdGhpcy5pbnRlcmltWzFdPW4sYTtpZigxMjghPSgxOTImKG89ZVtnKytdKSkpe2ctLTtjb250aW51ZX1pZigoYz0oMTUmaSk8PDEyfCg2MyZuKTw8Nnw2MyZvKTwyMDQ4fHxjPj01NTI5NiYmYzw9NTczNDN8fDY1Mjc5PT09Yyljb250aW51ZTt0W2ErK109Y31lbHNlIGlmKDI0MD09KDI0OCZpKSl7aWYoZz49cilyZXR1cm4gdGhpcy5pbnRlcmltWzBdPWksYTtpZigxMjghPSgxOTImKG49ZVtnKytdKSkpe2ctLTtjb250aW51ZX1pZihnPj1yKXJldHVybiB0aGlzLmludGVyaW1bMF09aSx0aGlzLmludGVyaW1bMV09bixhO2lmKDEyOCE9KDE5MiYobz1lW2crK10pKSl7Zy0tO2NvbnRpbnVlfWlmKGc+PXIpcmV0dXJuIHRoaXMuaW50ZXJpbVswXT1pLHRoaXMuaW50ZXJpbVsxXT1uLHRoaXMuaW50ZXJpbVsyXT1vLGE7aWYoMTI4IT0oMTkyJihzPWVbZysrXSkpKXtnLS07Y29udGludWV9aWYoKGM9KDcmaSk8PDE4fCg2MyZuKTw8MTJ8KDYzJm8pPDw2fDYzJnMpPDY1NTM2fHxjPjExMTQxMTEpY29udGludWU7dFthKytdPWN9fXJldHVybiBhfSxlfSgpO3QuVXRmOFRvVXRmMzI9aX0sMjI1OihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Vbmljb2RlVjY9dm9pZCAwO3ZhciBpLG49cig4MjczKSxvPVtbNzY4LDg3OV0sWzExNTUsMTE1OF0sWzExNjAsMTE2MV0sWzE0MjUsMTQ2OV0sWzE0NzEsMTQ3MV0sWzE0NzMsMTQ3NF0sWzE0NzYsMTQ3N10sWzE0NzksMTQ3OV0sWzE1MzYsMTUzOV0sWzE1NTIsMTU1N10sWzE2MTEsMTYzMF0sWzE2NDgsMTY0OF0sWzE3NTAsMTc2NF0sWzE3NjcsMTc2OF0sWzE3NzAsMTc3M10sWzE4MDcsMTgwN10sWzE4MDksMTgwOV0sWzE4NDAsMTg2Nl0sWzE5NTgsMTk2OF0sWzIwMjcsMjAzNV0sWzIzMDUsMjMwNl0sWzIzNjQsMjM2NF0sWzIzNjksMjM3Nl0sWzIzODEsMjM4MV0sWzIzODUsMjM4OF0sWzI0MDIsMjQwM10sWzI0MzMsMjQzM10sWzI0OTIsMjQ5Ml0sWzI0OTcsMjUwMF0sWzI1MDksMjUwOV0sWzI1MzAsMjUzMV0sWzI1NjEsMjU2Ml0sWzI2MjAsMjYyMF0sWzI2MjUsMjYyNl0sWzI2MzEsMjYzMl0sWzI2MzUsMjYzN10sWzI2NzIsMjY3M10sWzI2ODksMjY5MF0sWzI3NDgsMjc0OF0sWzI3NTMsMjc1N10sWzI3NTksMjc2MF0sWzI3NjUsMjc2NV0sWzI3ODYsMjc4N10sWzI4MTcsMjgxN10sWzI4NzYsMjg3Nl0sWzI4NzksMjg3OV0sWzI4ODEsMjg4M10sWzI4OTMsMjg5M10sWzI5MDIsMjkwMl0sWzI5NDYsMjk0Nl0sWzMwMDgsMzAwOF0sWzMwMjEsMzAyMV0sWzMxMzQsMzEzNl0sWzMxNDIsMzE0NF0sWzMxNDYsMzE0OV0sWzMxNTcsMzE1OF0sWzMyNjAsMzI2MF0sWzMyNjMsMzI2M10sWzMyNzAsMzI3MF0sWzMyNzYsMzI3N10sWzMyOTgsMzI5OV0sWzMzOTMsMzM5NV0sWzM0MDUsMzQwNV0sWzM1MzAsMzUzMF0sWzM1MzgsMzU0MF0sWzM1NDIsMzU0Ml0sWzM2MzMsMzYzM10sWzM2MzYsMzY0Ml0sWzM2NTUsMzY2Ml0sWzM3NjEsMzc2MV0sWzM3NjQsMzc2OV0sWzM3NzEsMzc3Ml0sWzM3ODQsMzc4OV0sWzM4NjQsMzg2NV0sWzM4OTMsMzg5M10sWzM4OTUsMzg5NV0sWzM4OTcsMzg5N10sWzM5NTMsMzk2Nl0sWzM5NjgsMzk3Ml0sWzM5NzQsMzk3NV0sWzM5ODQsMzk5MV0sWzM5OTMsNDAyOF0sWzQwMzgsNDAzOF0sWzQxNDEsNDE0NF0sWzQxNDYsNDE0Nl0sWzQxNTAsNDE1MV0sWzQxNTMsNDE1M10sWzQxODQsNDE4NV0sWzQ0NDgsNDYwN10sWzQ5NTksNDk1OV0sWzU5MDYsNTkwOF0sWzU5MzgsNTk0MF0sWzU5NzAsNTk3MV0sWzYwMDIsNjAwM10sWzYwNjgsNjA2OV0sWzYwNzEsNjA3N10sWzYwODYsNjA4Nl0sWzYwODksNjA5OV0sWzYxMDksNjEwOV0sWzYxNTUsNjE1N10sWzYzMTMsNjMxM10sWzY0MzIsNjQzNF0sWzY0MzksNjQ0MF0sWzY0NTAsNjQ1MF0sWzY0NTcsNjQ1OV0sWzY2NzksNjY4MF0sWzY5MTIsNjkxNV0sWzY5NjQsNjk2NF0sWzY5NjYsNjk3MF0sWzY5NzIsNjk3Ml0sWzY5NzgsNjk3OF0sWzcwMTksNzAyN10sWzc2MTYsNzYyNl0sWzc2NzgsNzY3OV0sWzgyMDMsODIwN10sWzgyMzQsODIzOF0sWzgyODgsODI5MV0sWzgyOTgsODMwM10sWzg0MDAsODQzMV0sWzEyMzMwLDEyMzM1XSxbMTI0NDEsMTI0NDJdLFs0MzAxNCw0MzAxNF0sWzQzMDE5LDQzMDE5XSxbNDMwNDUsNDMwNDZdLFs2NDI4Niw2NDI4Nl0sWzY1MDI0LDY1MDM5XSxbNjUwNTYsNjUwNTldLFs2NTI3OSw2NTI3OV0sWzY1NTI5LDY1NTMxXV0scz1bWzY4MDk3LDY4MDk5XSxbNjgxMDEsNjgxMDJdLFs2ODEwOCw2ODExMV0sWzY4MTUyLDY4MTU0XSxbNjgxNTksNjgxNTldLFsxMTkxNDMsMTE5MTQ1XSxbMTE5MTU1LDExOTE3MF0sWzExOTE3MywxMTkxNzldLFsxMTkyMTAsMTE5MjEzXSxbMTE5MzYyLDExOTM2NF0sWzkxNzUwNSw5MTc1MDVdLFs5MTc1MzYsOTE3NjMxXSxbOTE3NzYwLDkxNzk5OV1dLGE9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7aWYodGhpcy52ZXJzaW9uPSI2IiwhaSl7aT1uZXcgVWludDhBcnJheSg2NTUzNiksKDAsbi5maWxsKShpLDEpLGlbMF09MCwoMCxuLmZpbGwpKGksMCwxLDMyKSwoMCxuLmZpbGwpKGksMCwxMjcsMTYwKSwoMCxuLmZpbGwpKGksMiw0MzUyLDQ0NDgpLGlbOTAwMV09MixpWzkwMDJdPTIsKDAsbi5maWxsKShpLDIsMTE5MDQsNDIxOTIpLGlbMTIzNTFdPTEsKDAsbi5maWxsKShpLDIsNDQwMzIsNTUyMDQpLCgwLG4uZmlsbCkoaSwyLDYzNzQ0LDY0MjU2KSwoMCxuLmZpbGwpKGksMiw2NTA0MCw2NTA1MCksKDAsbi5maWxsKShpLDIsNjUwNzIsNjUxMzYpLCgwLG4uZmlsbCkoaSwyLDY1MjgwLDY1Mzc3KSwoMCxuLmZpbGwpKGksMiw2NTUwNCw2NTUxMSk7Zm9yKHZhciBlPTA7ZTxvLmxlbmd0aDsrK2UpKDAsbi5maWxsKShpLDAsb1tlXVswXSxvW2VdWzFdKzEpfX1yZXR1cm4gZS5wcm90b3R5cGUud2N3aWR0aD1mdW5jdGlvbihlKXtyZXR1cm4gZTwzMj8wOmU8MTI3PzE6ZTw2NTUzNj9pW2VdOmZ1bmN0aW9uKGUsdCl7dmFyIHIsaT0wLG49dC5sZW5ndGgtMTtpZihlPHRbMF1bMF18fGU+dFtuXVsxXSlyZXR1cm4hMTtmb3IoO24+PWk7KWlmKGU+dFtyPWkrbj4+MV1bMV0paT1yKzE7ZWxzZXtpZighKGU8dFtyXVswXSkpcmV0dXJuITA7bj1yLTF9cmV0dXJuITF9KGUscyk/MDplPj0xMzEwNzImJmU8PTE5NjYwNXx8ZT49MTk2NjA4JiZlPD0yNjIxNDE/MjoxfSxlfSgpO3QuVW5pY29kZVY2PWF9LDU5ODE6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Xcml0ZUJ1ZmZlcj12b2lkIDA7dmFyIHI9InVuZGVmaW5lZCI9PXR5cGVvZiBxdWV1ZU1pY3JvdGFzaz9mdW5jdGlvbihlKXtQcm9taXNlLnJlc29sdmUoKS50aGVuKGUpfTpxdWV1ZU1pY3JvdGFzayxpPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLl9hY3Rpb249ZSx0aGlzLl93cml0ZUJ1ZmZlcj1bXSx0aGlzLl9jYWxsYmFja3M9W10sdGhpcy5fcGVuZGluZ0RhdGE9MCx0aGlzLl9idWZmZXJPZmZzZXQ9MCx0aGlzLl9pc1N5bmNXcml0aW5nPSExLHRoaXMuX3N5bmNDYWxscz0wfXJldHVybiBlLnByb3RvdHlwZS53cml0ZVN5bmM9ZnVuY3Rpb24oZSx0KXtpZih2b2lkIDAhPT10JiZ0aGlzLl9zeW5jQ2FsbHM+dCl0aGlzLl9zeW5jQ2FsbHM9MDtlbHNlIGlmKHRoaXMuX3BlbmRpbmdEYXRhKz1lLmxlbmd0aCx0aGlzLl93cml0ZUJ1ZmZlci5wdXNoKGUpLHRoaXMuX2NhbGxiYWNrcy5wdXNoKHZvaWQgMCksdGhpcy5fc3luY0NhbGxzKyssIXRoaXMuX2lzU3luY1dyaXRpbmcpe3ZhciByO2Zvcih0aGlzLl9pc1N5bmNXcml0aW5nPSEwO3I9dGhpcy5fd3JpdGVCdWZmZXIuc2hpZnQoKTspe3RoaXMuX2FjdGlvbihyKTt2YXIgaT10aGlzLl9jYWxsYmFja3Muc2hpZnQoKTtpJiZpKCl9dGhpcy5fcGVuZGluZ0RhdGE9MCx0aGlzLl9idWZmZXJPZmZzZXQ9MjE0NzQ4MzY0Nyx0aGlzLl9pc1N5bmNXcml0aW5nPSExLHRoaXMuX3N5bmNDYWxscz0wfX0sZS5wcm90b3R5cGUud3JpdGU9ZnVuY3Rpb24oZSx0KXt2YXIgcj10aGlzO2lmKHRoaXMuX3BlbmRpbmdEYXRhPjVlNyl0aHJvdyBuZXcgRXJyb3IoIndyaXRlIGRhdGEgZGlzY2FyZGVkLCB1c2UgZmxvdyBjb250cm9sIHRvIGF2b2lkIGxvc2luZyBkYXRhIik7dGhpcy5fd3JpdGVCdWZmZXIubGVuZ3RofHwodGhpcy5fYnVmZmVyT2Zmc2V0PTAsc2V0VGltZW91dCgoZnVuY3Rpb24oKXtyZXR1cm4gci5faW5uZXJXcml0ZSgpfSkpKSx0aGlzLl9wZW5kaW5nRGF0YSs9ZS5sZW5ndGgsdGhpcy5fd3JpdGVCdWZmZXIucHVzaChlKSx0aGlzLl9jYWxsYmFja3MucHVzaCh0KX0sZS5wcm90b3R5cGUuX2lubmVyV3JpdGU9ZnVuY3Rpb24oZSx0KXt2YXIgaT10aGlzO3ZvaWQgMD09PWUmJihlPTApLHZvaWQgMD09PXQmJih0PSEwKTtmb3IodmFyIG49ZXx8RGF0ZS5ub3coKTt0aGlzLl93cml0ZUJ1ZmZlci5sZW5ndGg+dGhpcy5fYnVmZmVyT2Zmc2V0Oyl7dmFyIG89dGhpcy5fd3JpdGVCdWZmZXJbdGhpcy5fYnVmZmVyT2Zmc2V0XSxzPXRoaXMuX2FjdGlvbihvLHQpO2lmKHMpcmV0dXJuIHZvaWQgcy5jYXRjaCgoZnVuY3Rpb24oZSl7cmV0dXJuIHIoKGZ1bmN0aW9uKCl7dGhyb3cgZX0pKSxQcm9taXNlLnJlc29sdmUoITEpfSkpLnRoZW4oKGZ1bmN0aW9uKGUpe3JldHVybiBEYXRlLm5vdygpLW4+PTEyP3NldFRpbWVvdXQoKGZ1bmN0aW9uKCl7cmV0dXJuIGkuX2lubmVyV3JpdGUoMCxlKX0pKTppLl9pbm5lcldyaXRlKG4sZSl9KSk7dmFyIGE9dGhpcy5fY2FsbGJhY2tzW3RoaXMuX2J1ZmZlck9mZnNldF07aWYoYSYmYSgpLHRoaXMuX2J1ZmZlck9mZnNldCsrLHRoaXMuX3BlbmRpbmdEYXRhLT1vLmxlbmd0aCxEYXRlLm5vdygpLW4+PTEyKWJyZWFrfXRoaXMuX3dyaXRlQnVmZmVyLmxlbmd0aD50aGlzLl9idWZmZXJPZmZzZXQ/KHRoaXMuX2J1ZmZlck9mZnNldD41MCYmKHRoaXMuX3dyaXRlQnVmZmVyPXRoaXMuX3dyaXRlQnVmZmVyLnNsaWNlKHRoaXMuX2J1ZmZlck9mZnNldCksdGhpcy5fY2FsbGJhY2tzPXRoaXMuX2NhbGxiYWNrcy5zbGljZSh0aGlzLl9idWZmZXJPZmZzZXQpLHRoaXMuX2J1ZmZlck9mZnNldD0wKSxzZXRUaW1lb3V0KChmdW5jdGlvbigpe3JldHVybiBpLl9pbm5lcldyaXRlKCl9KSkpOih0aGlzLl93cml0ZUJ1ZmZlci5sZW5ndGg9MCx0aGlzLl9jYWxsYmFja3MubGVuZ3RoPTAsdGhpcy5fcGVuZGluZ0RhdGE9MCx0aGlzLl9idWZmZXJPZmZzZXQ9MCl9LGV9KCk7dC5Xcml0ZUJ1ZmZlcj1pfSw1OTQxOihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQudG9SZ2JTdHJpbmc9dC5wYXJzZUNvbG9yPXZvaWQgMDt2YXIgcj0vXihbXGRhLWZdezF9KVwvKFtcZGEtZl17MX0pXC8oW1xkYS1mXXsxfSkkfF4oW1xkYS1mXXsyfSlcLyhbXGRhLWZdezJ9KVwvKFtcZGEtZl17Mn0pJHxeKFtcZGEtZl17M30pXC8oW1xkYS1mXXszfSlcLyhbXGRhLWZdezN9KSR8XihbXGRhLWZdezR9KVwvKFtcZGEtZl17NH0pXC8oW1xkYS1mXXs0fSkkLyxpPS9eW1xkYS1mXSskLztmdW5jdGlvbiBuKGUsdCl7dmFyIHI9ZS50b1N0cmluZygxNiksaT1yLmxlbmd0aDwyPyIwIityOnI7c3dpdGNoKHQpe2Nhc2UgNDpyZXR1cm4gclswXTtjYXNlIDg6cmV0dXJuIGk7Y2FzZSAxMjpyZXR1cm4oaStpKS5zbGljZSgwLDMpO2RlZmF1bHQ6cmV0dXJuIGkraX19dC5wYXJzZUNvbG9yPWZ1bmN0aW9uKGUpe2lmKGUpe3ZhciB0PWUudG9Mb3dlckNhc2UoKTtpZigwPT09dC5pbmRleE9mKCJyZ2I6Iikpe3Q9dC5zbGljZSg0KTt2YXIgbj1yLmV4ZWModCk7aWYobil7dmFyIG89blsxXT8xNTpuWzRdPzI1NTpuWzddPzQwOTU6NjU1MzU7cmV0dXJuW01hdGgucm91bmQocGFyc2VJbnQoblsxXXx8bls0XXx8bls3XXx8blsxMF0sMTYpL28qMjU1KSxNYXRoLnJvdW5kKHBhcnNlSW50KG5bMl18fG5bNV18fG5bOF18fG5bMTFdLDE2KS9vKjI1NSksTWF0aC5yb3VuZChwYXJzZUludChuWzNdfHxuWzZdfHxuWzldfHxuWzEyXSwxNikvbyoyNTUpXX19ZWxzZSBpZigwPT09dC5pbmRleE9mKCIjIikmJih0PXQuc2xpY2UoMSksaS5leGVjKHQpJiZbMyw2LDksMTJdLmluY2x1ZGVzKHQubGVuZ3RoKSkpe2Zvcih2YXIgcz10Lmxlbmd0aC8zLGE9WzAsMCwwXSxjPTA7YzwzOysrYyl7dmFyIGw9cGFyc2VJbnQodC5zbGljZShzKmMscypjK3MpLDE2KTthW2NdPTE9PT1zP2w8PDQ6Mj09PXM/bDozPT09cz9sPj40Omw+Pjh9cmV0dXJuIGF9fX0sdC50b1JnYlN0cmluZz1mdW5jdGlvbihlLHQpe3ZvaWQgMD09PXQmJih0PTE2KTt2YXIgcj1lWzBdLGk9ZVsxXSxvPWVbMl07cmV0dXJuInJnYjoiK24ocix0KSsiLyIrbihpLHQpKyIvIituKG8sdCl9fSw1NzcwOihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuUEFZTE9BRF9MSU1JVD12b2lkIDAsdC5QQVlMT0FEX0xJTUlUPTFlN30sNjM1MTooZSx0LHIpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuRGNzSGFuZGxlcj10LkRjc1BhcnNlcj12b2lkIDA7dmFyIGk9cig0ODIpLG49cig4NzQyKSxvPXIoNTc3MCkscz1bXSxhPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMuX2hhbmRsZXJzPU9iamVjdC5jcmVhdGUobnVsbCksdGhpcy5fYWN0aXZlPXMsdGhpcy5faWRlbnQ9MCx0aGlzLl9oYW5kbGVyRmI9ZnVuY3Rpb24oKXt9LHRoaXMuX3N0YWNrPXtwYXVzZWQ6ITEsbG9vcFBvc2l0aW9uOjAsZmFsbFRocm91Z2g6ITF9fXJldHVybiBlLnByb3RvdHlwZS5kaXNwb3NlPWZ1bmN0aW9uKCl7dGhpcy5faGFuZGxlcnM9T2JqZWN0LmNyZWF0ZShudWxsKSx0aGlzLl9oYW5kbGVyRmI9ZnVuY3Rpb24oKXt9LHRoaXMuX2FjdGl2ZT1zfSxlLnByb3RvdHlwZS5yZWdpc3RlckhhbmRsZXI9ZnVuY3Rpb24oZSx0KXt2b2lkIDA9PT10aGlzLl9oYW5kbGVyc1tlXSYmKHRoaXMuX2hhbmRsZXJzW2VdPVtdKTt2YXIgcj10aGlzLl9oYW5kbGVyc1tlXTtyZXR1cm4gci5wdXNoKHQpLHtkaXNwb3NlOmZ1bmN0aW9uKCl7dmFyIGU9ci5pbmRleE9mKHQpOy0xIT09ZSYmci5zcGxpY2UoZSwxKX19fSxlLnByb3RvdHlwZS5jbGVhckhhbmRsZXI9ZnVuY3Rpb24oZSl7dGhpcy5faGFuZGxlcnNbZV0mJmRlbGV0ZSB0aGlzLl9oYW5kbGVyc1tlXX0sZS5wcm90b3R5cGUuc2V0SGFuZGxlckZhbGxiYWNrPWZ1bmN0aW9uKGUpe3RoaXMuX2hhbmRsZXJGYj1lfSxlLnByb3RvdHlwZS5yZXNldD1mdW5jdGlvbigpe2lmKHRoaXMuX2FjdGl2ZS5sZW5ndGgpZm9yKHZhciBlPXRoaXMuX3N0YWNrLnBhdXNlZD90aGlzLl9zdGFjay5sb29wUG9zaXRpb24tMTp0aGlzLl9hY3RpdmUubGVuZ3RoLTE7ZT49MDstLWUpdGhpcy5fYWN0aXZlW2VdLnVuaG9vayghMSk7dGhpcy5fc3RhY2sucGF1c2VkPSExLHRoaXMuX2FjdGl2ZT1zLHRoaXMuX2lkZW50PTB9LGUucHJvdG90eXBlLmhvb2s9ZnVuY3Rpb24oZSx0KXtpZih0aGlzLnJlc2V0KCksdGhpcy5faWRlbnQ9ZSx0aGlzLl9hY3RpdmU9dGhpcy5faGFuZGxlcnNbZV18fHMsdGhpcy5fYWN0aXZlLmxlbmd0aClmb3IodmFyIHI9dGhpcy5fYWN0aXZlLmxlbmd0aC0xO3I+PTA7ci0tKXRoaXMuX2FjdGl2ZVtyXS5ob29rKHQpO2Vsc2UgdGhpcy5faGFuZGxlckZiKHRoaXMuX2lkZW50LCJIT09LIix0KX0sZS5wcm90b3R5cGUucHV0PWZ1bmN0aW9uKGUsdCxyKXtpZih0aGlzLl9hY3RpdmUubGVuZ3RoKWZvcih2YXIgbj10aGlzLl9hY3RpdmUubGVuZ3RoLTE7bj49MDtuLS0pdGhpcy5fYWN0aXZlW25dLnB1dChlLHQscik7ZWxzZSB0aGlzLl9oYW5kbGVyRmIodGhpcy5faWRlbnQsIlBVVCIsKDAsaS51dGYzMlRvU3RyaW5nKShlLHQscikpfSxlLnByb3RvdHlwZS51bmhvb2s9ZnVuY3Rpb24oZSx0KXtpZih2b2lkIDA9PT10JiYodD0hMCksdGhpcy5fYWN0aXZlLmxlbmd0aCl7dmFyIHI9ITEsaT10aGlzLl9hY3RpdmUubGVuZ3RoLTEsbj0hMTtpZih0aGlzLl9zdGFjay5wYXVzZWQmJihpPXRoaXMuX3N0YWNrLmxvb3BQb3NpdGlvbi0xLHI9dCxuPXRoaXMuX3N0YWNrLmZhbGxUaHJvdWdoLHRoaXMuX3N0YWNrLnBhdXNlZD0hMSksIW4mJiExPT09cil7Zm9yKDtpPj0wJiYhMCE9PShyPXRoaXMuX2FjdGl2ZVtpXS51bmhvb2soZSkpO2ktLSlpZihyIGluc3RhbmNlb2YgUHJvbWlzZSlyZXR1cm4gdGhpcy5fc3RhY2sucGF1c2VkPSEwLHRoaXMuX3N0YWNrLmxvb3BQb3NpdGlvbj1pLHRoaXMuX3N0YWNrLmZhbGxUaHJvdWdoPSExLHI7aS0tfWZvcig7aT49MDtpLS0paWYoKHI9dGhpcy5fYWN0aXZlW2ldLnVuaG9vayghMSkpaW5zdGFuY2VvZiBQcm9taXNlKXJldHVybiB0aGlzLl9zdGFjay5wYXVzZWQ9ITAsdGhpcy5fc3RhY2subG9vcFBvc2l0aW9uPWksdGhpcy5fc3RhY2suZmFsbFRocm91Z2g9ITAscn1lbHNlIHRoaXMuX2hhbmRsZXJGYih0aGlzLl9pZGVudCwiVU5IT09LIixlKTt0aGlzLl9hY3RpdmU9cyx0aGlzLl9pZGVudD0wfSxlfSgpO3QuRGNzUGFyc2VyPWE7dmFyIGM9bmV3IG4uUGFyYW1zO2MuYWRkUGFyYW0oMCk7dmFyIGw9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMuX2hhbmRsZXI9ZSx0aGlzLl9kYXRhPSIiLHRoaXMuX3BhcmFtcz1jLHRoaXMuX2hpdExpbWl0PSExfXJldHVybiBlLnByb3RvdHlwZS5ob29rPWZ1bmN0aW9uKGUpe3RoaXMuX3BhcmFtcz1lLmxlbmd0aD4xfHxlLnBhcmFtc1swXT9lLmNsb25lKCk6Yyx0aGlzLl9kYXRhPSIiLHRoaXMuX2hpdExpbWl0PSExfSxlLnByb3RvdHlwZS5wdXQ9ZnVuY3Rpb24oZSx0LHIpe3RoaXMuX2hpdExpbWl0fHwodGhpcy5fZGF0YSs9KDAsaS51dGYzMlRvU3RyaW5nKShlLHQsciksdGhpcy5fZGF0YS5sZW5ndGg+by5QQVlMT0FEX0xJTUlUJiYodGhpcy5fZGF0YT0iIix0aGlzLl9oaXRMaW1pdD0hMCkpfSxlLnByb3RvdHlwZS51bmhvb2s9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcyxyPSExO2lmKHRoaXMuX2hpdExpbWl0KXI9ITE7ZWxzZSBpZihlJiYocj10aGlzLl9oYW5kbGVyKHRoaXMuX2RhdGEsdGhpcy5fcGFyYW1zKSlpbnN0YW5jZW9mIFByb21pc2UpcmV0dXJuIHIudGhlbigoZnVuY3Rpb24oZSl7cmV0dXJuIHQuX3BhcmFtcz1jLHQuX2RhdGE9IiIsdC5faGl0TGltaXQ9ITEsZX0pKTtyZXR1cm4gdGhpcy5fcGFyYW1zPWMsdGhpcy5fZGF0YT0iIix0aGlzLl9oaXRMaW1pdD0hMSxyfSxlfSgpO3QuRGNzSGFuZGxlcj1sfSwyMDE1OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkVzY2FwZVNlcXVlbmNlUGFyc2VyPXQuVlQ1MDBfVFJBTlNJVElPTl9UQUJMRT10LlRyYW5zaXRpb25UYWJsZT12b2lkIDA7dmFyIG89cig4NDQpLHM9cig4MjczKSxhPXIoODc0MiksYz1yKDYyNDIpLGw9cig2MzUxKSx1PWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnRhYmxlPW5ldyBVaW50OEFycmF5KGUpfXJldHVybiBlLnByb3RvdHlwZS5zZXREZWZhdWx0PWZ1bmN0aW9uKGUsdCl7KDAscy5maWxsKSh0aGlzLnRhYmxlLGU8PDR8dCl9LGUucHJvdG90eXBlLmFkZD1mdW5jdGlvbihlLHQscixpKXt0aGlzLnRhYmxlW3Q8PDh8ZV09cjw8NHxpfSxlLnByb3RvdHlwZS5hZGRNYW55PWZ1bmN0aW9uKGUsdCxyLGkpe2Zvcih2YXIgbj0wO248ZS5sZW5ndGg7bisrKXRoaXMudGFibGVbdDw8OHxlW25dXT1yPDw0fGl9LGV9KCk7dC5UcmFuc2l0aW9uVGFibGU9dTt2YXIgaD0xNjA7dC5WVDUwMF9UUkFOU0lUSU9OX1RBQkxFPWZ1bmN0aW9uKCl7dmFyIGU9bmV3IHUoNDA5NSksdD1BcnJheS5hcHBseShudWxsLEFycmF5KDI1NikpLm1hcCgoZnVuY3Rpb24oZSx0KXtyZXR1cm4gdH0pKSxyPWZ1bmN0aW9uKGUscil7cmV0dXJuIHQuc2xpY2UoZSxyKX0saT1yKDMyLDEyNyksbj1yKDAsMjQpO24ucHVzaCgyNSksbi5wdXNoLmFwcGx5KG4scigyOCwzMikpO3ZhciBvLHM9cigwLDE0KTtmb3IobyBpbiBlLnNldERlZmF1bHQoMSwwKSxlLmFkZE1hbnkoaSwwLDIsMCkscyllLmFkZE1hbnkoWzI0LDI2LDE1MywxNTRdLG8sMywwKSxlLmFkZE1hbnkocigxMjgsMTQ0KSxvLDMsMCksZS5hZGRNYW55KHIoMTQ0LDE1MiksbywzLDApLGUuYWRkKDE1NixvLDAsMCksZS5hZGQoMjcsbywxMSwxKSxlLmFkZCgxNTcsbyw0LDgpLGUuYWRkTWFueShbMTUyLDE1OCwxNTldLG8sMCw3KSxlLmFkZCgxNTUsbywxMSwzKSxlLmFkZCgxNDQsbywxMSw5KTtyZXR1cm4gZS5hZGRNYW55KG4sMCwzLDApLGUuYWRkTWFueShuLDEsMywxKSxlLmFkZCgxMjcsMSwwLDEpLGUuYWRkTWFueShuLDgsMCw4KSxlLmFkZE1hbnkobiwzLDMsMyksZS5hZGQoMTI3LDMsMCwzKSxlLmFkZE1hbnkobiw0LDMsNCksZS5hZGQoMTI3LDQsMCw0KSxlLmFkZE1hbnkobiw2LDMsNiksZS5hZGRNYW55KG4sNSwzLDUpLGUuYWRkKDEyNyw1LDAsNSksZS5hZGRNYW55KG4sMiwzLDIpLGUuYWRkKDEyNywyLDAsMiksZS5hZGQoOTMsMSw0LDgpLGUuYWRkTWFueShpLDgsNSw4KSxlLmFkZCgxMjcsOCw1LDgpLGUuYWRkTWFueShbMTU2LDI3LDI0LDI2LDddLDgsNiwwKSxlLmFkZE1hbnkocigyOCwzMiksOCwwLDgpLGUuYWRkTWFueShbODgsOTQsOTVdLDEsMCw3KSxlLmFkZE1hbnkoaSw3LDAsNyksZS5hZGRNYW55KG4sNywwLDcpLGUuYWRkKDE1Niw3LDAsMCksZS5hZGQoMTI3LDcsMCw3KSxlLmFkZCg5MSwxLDExLDMpLGUuYWRkTWFueShyKDY0LDEyNyksMyw3LDApLGUuYWRkTWFueShyKDQ4LDYwKSwzLDgsNCksZS5hZGRNYW55KFs2MCw2MSw2Miw2M10sMyw5LDQpLGUuYWRkTWFueShyKDQ4LDYwKSw0LDgsNCksZS5hZGRNYW55KHIoNjQsMTI3KSw0LDcsMCksZS5hZGRNYW55KFs2MCw2MSw2Miw2M10sNCwwLDYpLGUuYWRkTWFueShyKDMyLDY0KSw2LDAsNiksZS5hZGQoMTI3LDYsMCw2KSxlLmFkZE1hbnkocig2NCwxMjcpLDYsMCwwKSxlLmFkZE1hbnkocigzMiw0OCksMyw5LDUpLGUuYWRkTWFueShyKDMyLDQ4KSw1LDksNSksZS5hZGRNYW55KHIoNDgsNjQpLDUsMCw2KSxlLmFkZE1hbnkocig2NCwxMjcpLDUsNywwKSxlLmFkZE1hbnkocigzMiw0OCksNCw5LDUpLGUuYWRkTWFueShyKDMyLDQ4KSwxLDksMiksZS5hZGRNYW55KHIoMzIsNDgpLDIsOSwyKSxlLmFkZE1hbnkocig0OCwxMjcpLDIsMTAsMCksZS5hZGRNYW55KHIoNDgsODApLDEsMTAsMCksZS5hZGRNYW55KHIoODEsODgpLDEsMTAsMCksZS5hZGRNYW55KFs4OSw5MCw5Ml0sMSwxMCwwKSxlLmFkZE1hbnkocig5NiwxMjcpLDEsMTAsMCksZS5hZGQoODAsMSwxMSw5KSxlLmFkZE1hbnkobiw5LDAsOSksZS5hZGQoMTI3LDksMCw5KSxlLmFkZE1hbnkocigyOCwzMiksOSwwLDkpLGUuYWRkTWFueShyKDMyLDQ4KSw5LDksMTIpLGUuYWRkTWFueShyKDQ4LDYwKSw5LDgsMTApLGUuYWRkTWFueShbNjAsNjEsNjIsNjNdLDksOSwxMCksZS5hZGRNYW55KG4sMTEsMCwxMSksZS5hZGRNYW55KHIoMzIsMTI4KSwxMSwwLDExKSxlLmFkZE1hbnkocigyOCwzMiksMTEsMCwxMSksZS5hZGRNYW55KG4sMTAsMCwxMCksZS5hZGQoMTI3LDEwLDAsMTApLGUuYWRkTWFueShyKDI4LDMyKSwxMCwwLDEwKSxlLmFkZE1hbnkocig0OCw2MCksMTAsOCwxMCksZS5hZGRNYW55KFs2MCw2MSw2Miw2M10sMTAsMCwxMSksZS5hZGRNYW55KHIoMzIsNDgpLDEwLDksMTIpLGUuYWRkTWFueShuLDEyLDAsMTIpLGUuYWRkKDEyNywxMiwwLDEyKSxlLmFkZE1hbnkocigyOCwzMiksMTIsMCwxMiksZS5hZGRNYW55KHIoMzIsNDgpLDEyLDksMTIpLGUuYWRkTWFueShyKDQ4LDY0KSwxMiwwLDExKSxlLmFkZE1hbnkocig2NCwxMjcpLDEyLDEyLDEzKSxlLmFkZE1hbnkocig2NCwxMjcpLDEwLDEyLDEzKSxlLmFkZE1hbnkocig2NCwxMjcpLDksMTIsMTMpLGUuYWRkTWFueShuLDEzLDEzLDEzKSxlLmFkZE1hbnkoaSwxMywxMywxMyksZS5hZGQoMTI3LDEzLDAsMTMpLGUuYWRkTWFueShbMjcsMTU2LDI0LDI2XSwxMywxNCwwKSxlLmFkZChoLDAsMiwwKSxlLmFkZChoLDgsNSw4KSxlLmFkZChoLDYsMCw2KSxlLmFkZChoLDExLDAsMTEpLGUuYWRkKGgsMTMsMTMsMTMpLGV9KCk7dmFyIGY9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gcihyKXt2b2lkIDA9PT1yJiYocj10LlZUNTAwX1RSQU5TSVRJT05fVEFCTEUpO3ZhciBpPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gaS5fdHJhbnNpdGlvbnM9cixpLl9wYXJzZVN0YWNrPXtzdGF0ZTowLGhhbmRsZXJzOltdLGhhbmRsZXJQb3M6MCx0cmFuc2l0aW9uOjAsY2h1bmtQb3M6MH0saS5pbml0aWFsU3RhdGU9MCxpLmN1cnJlbnRTdGF0ZT1pLmluaXRpYWxTdGF0ZSxpLl9wYXJhbXM9bmV3IGEuUGFyYW1zLGkuX3BhcmFtcy5hZGRQYXJhbSgwKSxpLl9jb2xsZWN0PTAsaS5wcmVjZWRpbmdDb2RlcG9pbnQ9MCxpLl9wcmludEhhbmRsZXJGYj1mdW5jdGlvbihlLHQscil7fSxpLl9leGVjdXRlSGFuZGxlckZiPWZ1bmN0aW9uKGUpe30saS5fY3NpSGFuZGxlckZiPWZ1bmN0aW9uKGUsdCl7fSxpLl9lc2NIYW5kbGVyRmI9ZnVuY3Rpb24oZSl7fSxpLl9lcnJvckhhbmRsZXJGYj1mdW5jdGlvbihlKXtyZXR1cm4gZX0saS5fcHJpbnRIYW5kbGVyPWkuX3ByaW50SGFuZGxlckZiLGkuX2V4ZWN1dGVIYW5kbGVycz1PYmplY3QuY3JlYXRlKG51bGwpLGkuX2NzaUhhbmRsZXJzPU9iamVjdC5jcmVhdGUobnVsbCksaS5fZXNjSGFuZGxlcnM9T2JqZWN0LmNyZWF0ZShudWxsKSxpLl9vc2NQYXJzZXI9bmV3IGMuT3NjUGFyc2VyLGkuX2Rjc1BhcnNlcj1uZXcgbC5EY3NQYXJzZXIsaS5fZXJyb3JIYW5kbGVyPWkuX2Vycm9ySGFuZGxlckZiLGkucmVnaXN0ZXJFc2NIYW5kbGVyKHtmaW5hbDoiXFwifSwoZnVuY3Rpb24oKXtyZXR1cm4hMH0pKSxpfXJldHVybiBuKHIsZSksci5wcm90b3R5cGUuX2lkZW50aWZpZXI9ZnVuY3Rpb24oZSx0KXt2b2lkIDA9PT10JiYodD1bNjQsMTI2XSk7dmFyIHI9MDtpZihlLnByZWZpeCl7aWYoZS5wcmVmaXgubGVuZ3RoPjEpdGhyb3cgbmV3IEVycm9yKCJvbmx5IG9uZSBieXRlIGFzIHByZWZpeCBzdXBwb3J0ZWQiKTtpZigocj1lLnByZWZpeC5jaGFyQ29kZUF0KDApKSYmNjA+cnx8cj42Myl0aHJvdyBuZXcgRXJyb3IoInByZWZpeCBtdXN0IGJlIGluIHJhbmdlIDB4M2MgLi4gMHgzZiIpfWlmKGUuaW50ZXJtZWRpYXRlcyl7aWYoZS5pbnRlcm1lZGlhdGVzLmxlbmd0aD4yKXRocm93IG5ldyBFcnJvcigib25seSB0d28gYnl0ZXMgYXMgaW50ZXJtZWRpYXRlcyBhcmUgc3VwcG9ydGVkIik7Zm9yKHZhciBpPTA7aTxlLmludGVybWVkaWF0ZXMubGVuZ3RoOysraSl7dmFyIG49ZS5pbnRlcm1lZGlhdGVzLmNoYXJDb2RlQXQoaSk7aWYoMzI+bnx8bj40Nyl0aHJvdyBuZXcgRXJyb3IoImludGVybWVkaWF0ZSBtdXN0IGJlIGluIHJhbmdlIDB4MjAgLi4gMHgyZiIpO3I8PD04LHJ8PW59fWlmKDEhPT1lLmZpbmFsLmxlbmd0aCl0aHJvdyBuZXcgRXJyb3IoImZpbmFsIG11c3QgYmUgYSBzaW5nbGUgYnl0ZSIpO3ZhciBvPWUuZmluYWwuY2hhckNvZGVBdCgwKTtpZih0WzBdPm98fG8+dFsxXSl0aHJvdyBuZXcgRXJyb3IoImZpbmFsIG11c3QgYmUgaW4gcmFuZ2UgIit0WzBdKyIgLi4gIit0WzFdKTtyZXR1cm4ocjw8PTgpfG99LHIucHJvdG90eXBlLmlkZW50VG9TdHJpbmc9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PVtdO2U7KXQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKDI1NSZlKSksZT4+PTg7cmV0dXJuIHQucmV2ZXJzZSgpLmpvaW4oIiIpfSxyLnByb3RvdHlwZS5kaXNwb3NlPWZ1bmN0aW9uKCl7dGhpcy5fY3NpSGFuZGxlcnM9T2JqZWN0LmNyZWF0ZShudWxsKSx0aGlzLl9leGVjdXRlSGFuZGxlcnM9T2JqZWN0LmNyZWF0ZShudWxsKSx0aGlzLl9lc2NIYW5kbGVycz1PYmplY3QuY3JlYXRlKG51bGwpLHRoaXMuX29zY1BhcnNlci5kaXNwb3NlKCksdGhpcy5fZGNzUGFyc2VyLmRpc3Bvc2UoKX0sci5wcm90b3R5cGUuc2V0UHJpbnRIYW5kbGVyPWZ1bmN0aW9uKGUpe3RoaXMuX3ByaW50SGFuZGxlcj1lfSxyLnByb3RvdHlwZS5jbGVhclByaW50SGFuZGxlcj1mdW5jdGlvbigpe3RoaXMuX3ByaW50SGFuZGxlcj10aGlzLl9wcmludEhhbmRsZXJGYn0sci5wcm90b3R5cGUucmVnaXN0ZXJFc2NIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7dmFyIHI9dGhpcy5faWRlbnRpZmllcihlLFs0OCwxMjZdKTt2b2lkIDA9PT10aGlzLl9lc2NIYW5kbGVyc1tyXSYmKHRoaXMuX2VzY0hhbmRsZXJzW3JdPVtdKTt2YXIgaT10aGlzLl9lc2NIYW5kbGVyc1tyXTtyZXR1cm4gaS5wdXNoKHQpLHtkaXNwb3NlOmZ1bmN0aW9uKCl7dmFyIGU9aS5pbmRleE9mKHQpOy0xIT09ZSYmaS5zcGxpY2UoZSwxKX19fSxyLnByb3RvdHlwZS5jbGVhckVzY0hhbmRsZXI9ZnVuY3Rpb24oZSl7dGhpcy5fZXNjSGFuZGxlcnNbdGhpcy5faWRlbnRpZmllcihlLFs0OCwxMjZdKV0mJmRlbGV0ZSB0aGlzLl9lc2NIYW5kbGVyc1t0aGlzLl9pZGVudGlmaWVyKGUsWzQ4LDEyNl0pXX0sci5wcm90b3R5cGUuc2V0RXNjSGFuZGxlckZhbGxiYWNrPWZ1bmN0aW9uKGUpe3RoaXMuX2VzY0hhbmRsZXJGYj1lfSxyLnByb3RvdHlwZS5zZXRFeGVjdXRlSGFuZGxlcj1mdW5jdGlvbihlLHQpe3RoaXMuX2V4ZWN1dGVIYW5kbGVyc1tlLmNoYXJDb2RlQXQoMCldPXR9LHIucHJvdG90eXBlLmNsZWFyRXhlY3V0ZUhhbmRsZXI9ZnVuY3Rpb24oZSl7dGhpcy5fZXhlY3V0ZUhhbmRsZXJzW2UuY2hhckNvZGVBdCgwKV0mJmRlbGV0ZSB0aGlzLl9leGVjdXRlSGFuZGxlcnNbZS5jaGFyQ29kZUF0KDApXX0sci5wcm90b3R5cGUuc2V0RXhlY3V0ZUhhbmRsZXJGYWxsYmFjaz1mdW5jdGlvbihlKXt0aGlzLl9leGVjdXRlSGFuZGxlckZiPWV9LHIucHJvdG90eXBlLnJlZ2lzdGVyQ3NpSGFuZGxlcj1mdW5jdGlvbihlLHQpe3ZhciByPXRoaXMuX2lkZW50aWZpZXIoZSk7dm9pZCAwPT09dGhpcy5fY3NpSGFuZGxlcnNbcl0mJih0aGlzLl9jc2lIYW5kbGVyc1tyXT1bXSk7dmFyIGk9dGhpcy5fY3NpSGFuZGxlcnNbcl07cmV0dXJuIGkucHVzaCh0KSx7ZGlzcG9zZTpmdW5jdGlvbigpe3ZhciBlPWkuaW5kZXhPZih0KTstMSE9PWUmJmkuc3BsaWNlKGUsMSl9fX0sci5wcm90b3R5cGUuY2xlYXJDc2lIYW5kbGVyPWZ1bmN0aW9uKGUpe3RoaXMuX2NzaUhhbmRsZXJzW3RoaXMuX2lkZW50aWZpZXIoZSldJiZkZWxldGUgdGhpcy5fY3NpSGFuZGxlcnNbdGhpcy5faWRlbnRpZmllcihlKV19LHIucHJvdG90eXBlLnNldENzaUhhbmRsZXJGYWxsYmFjaz1mdW5jdGlvbihlKXt0aGlzLl9jc2lIYW5kbGVyRmI9ZX0sci5wcm90b3R5cGUucmVnaXN0ZXJEY3NIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuX2Rjc1BhcnNlci5yZWdpc3RlckhhbmRsZXIodGhpcy5faWRlbnRpZmllcihlKSx0KX0sci5wcm90b3R5cGUuY2xlYXJEY3NIYW5kbGVyPWZ1bmN0aW9uKGUpe3RoaXMuX2Rjc1BhcnNlci5jbGVhckhhbmRsZXIodGhpcy5faWRlbnRpZmllcihlKSl9LHIucHJvdG90eXBlLnNldERjc0hhbmRsZXJGYWxsYmFjaz1mdW5jdGlvbihlKXt0aGlzLl9kY3NQYXJzZXIuc2V0SGFuZGxlckZhbGxiYWNrKGUpfSxyLnByb3RvdHlwZS5yZWdpc3Rlck9zY0hhbmRsZXI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5fb3NjUGFyc2VyLnJlZ2lzdGVySGFuZGxlcihlLHQpfSxyLnByb3RvdHlwZS5jbGVhck9zY0hhbmRsZXI9ZnVuY3Rpb24oZSl7dGhpcy5fb3NjUGFyc2VyLmNsZWFySGFuZGxlcihlKX0sci5wcm90b3R5cGUuc2V0T3NjSGFuZGxlckZhbGxiYWNrPWZ1bmN0aW9uKGUpe3RoaXMuX29zY1BhcnNlci5zZXRIYW5kbGVyRmFsbGJhY2soZSl9LHIucHJvdG90eXBlLnNldEVycm9ySGFuZGxlcj1mdW5jdGlvbihlKXt0aGlzLl9lcnJvckhhbmRsZXI9ZX0sci5wcm90b3R5cGUuY2xlYXJFcnJvckhhbmRsZXI9ZnVuY3Rpb24oKXt0aGlzLl9lcnJvckhhbmRsZXI9dGhpcy5fZXJyb3JIYW5kbGVyRmJ9LHIucHJvdG90eXBlLnJlc2V0PWZ1bmN0aW9uKCl7dGhpcy5jdXJyZW50U3RhdGU9dGhpcy5pbml0aWFsU3RhdGUsdGhpcy5fb3NjUGFyc2VyLnJlc2V0KCksdGhpcy5fZGNzUGFyc2VyLnJlc2V0KCksdGhpcy5fcGFyYW1zLnJlc2V0KCksdGhpcy5fcGFyYW1zLmFkZFBhcmFtKDApLHRoaXMuX2NvbGxlY3Q9MCx0aGlzLnByZWNlZGluZ0NvZGVwb2ludD0wLDAhPT10aGlzLl9wYXJzZVN0YWNrLnN0YXRlJiYodGhpcy5fcGFyc2VTdGFjay5zdGF0ZT0yLHRoaXMuX3BhcnNlU3RhY2suaGFuZGxlcnM9W10pfSxyLnByb3RvdHlwZS5fcHJlc2VydmVTdGFjaz1mdW5jdGlvbihlLHQscixpLG4pe3RoaXMuX3BhcnNlU3RhY2suc3RhdGU9ZSx0aGlzLl9wYXJzZVN0YWNrLmhhbmRsZXJzPXQsdGhpcy5fcGFyc2VTdGFjay5oYW5kbGVyUG9zPXIsdGhpcy5fcGFyc2VTdGFjay50cmFuc2l0aW9uPWksdGhpcy5fcGFyc2VTdGFjay5jaHVua1Bvcz1ufSxyLnByb3RvdHlwZS5wYXJzZT1mdW5jdGlvbihlLHQscil7dmFyIGksbj0wLG89MCxzPTA7aWYodGhpcy5fcGFyc2VTdGFjay5zdGF0ZSlpZigyPT09dGhpcy5fcGFyc2VTdGFjay5zdGF0ZSl0aGlzLl9wYXJzZVN0YWNrLnN0YXRlPTAscz10aGlzLl9wYXJzZVN0YWNrLmNodW5rUG9zKzE7ZWxzZXtpZih2b2lkIDA9PT1yfHwxPT09dGhpcy5fcGFyc2VTdGFjay5zdGF0ZSl0aHJvdyB0aGlzLl9wYXJzZVN0YWNrLnN0YXRlPTEsbmV3IEVycm9yKCJpbXByb3BlciBjb250aW51YXRpb24gZHVlIHRvIHByZXZpb3VzIGFzeW5jIGhhbmRsZXIsIGdpdmluZyB1cCBwYXJzaW5nIik7dmFyIGE9dGhpcy5fcGFyc2VTdGFjay5oYW5kbGVycyxjPXRoaXMuX3BhcnNlU3RhY2suaGFuZGxlclBvcy0xO3N3aXRjaCh0aGlzLl9wYXJzZVN0YWNrLnN0YXRlKXtjYXNlIDM6aWYoITE9PT1yJiZjPi0xKWZvcig7Yz49MCYmITAhPT0oaT1hW2NdKHRoaXMuX3BhcmFtcykpO2MtLSlpZihpIGluc3RhbmNlb2YgUHJvbWlzZSlyZXR1cm4gdGhpcy5fcGFyc2VTdGFjay5oYW5kbGVyUG9zPWMsaTt0aGlzLl9wYXJzZVN0YWNrLmhhbmRsZXJzPVtdO2JyZWFrO2Nhc2UgNDppZighMT09PXImJmM+LTEpZm9yKDtjPj0wJiYhMCE9PShpPWFbY10oKSk7Yy0tKWlmKGkgaW5zdGFuY2VvZiBQcm9taXNlKXJldHVybiB0aGlzLl9wYXJzZVN0YWNrLmhhbmRsZXJQb3M9YyxpO3RoaXMuX3BhcnNlU3RhY2suaGFuZGxlcnM9W107YnJlYWs7Y2FzZSA2OmlmKG49ZVt0aGlzLl9wYXJzZVN0YWNrLmNodW5rUG9zXSxpPXRoaXMuX2Rjc1BhcnNlci51bmhvb2soMjQhPT1uJiYyNiE9PW4scikpcmV0dXJuIGk7Mjc9PT1uJiYodGhpcy5fcGFyc2VTdGFjay50cmFuc2l0aW9ufD0xKSx0aGlzLl9wYXJhbXMucmVzZXQoKSx0aGlzLl9wYXJhbXMuYWRkUGFyYW0oMCksdGhpcy5fY29sbGVjdD0wO2JyZWFrO2Nhc2UgNTppZihuPWVbdGhpcy5fcGFyc2VTdGFjay5jaHVua1Bvc10saT10aGlzLl9vc2NQYXJzZXIuZW5kKDI0IT09biYmMjYhPT1uLHIpKXJldHVybiBpOzI3PT09biYmKHRoaXMuX3BhcnNlU3RhY2sudHJhbnNpdGlvbnw9MSksdGhpcy5fcGFyYW1zLnJlc2V0KCksdGhpcy5fcGFyYW1zLmFkZFBhcmFtKDApLHRoaXMuX2NvbGxlY3Q9MH10aGlzLl9wYXJzZVN0YWNrLnN0YXRlPTAscz10aGlzLl9wYXJzZVN0YWNrLmNodW5rUG9zKzEsdGhpcy5wcmVjZWRpbmdDb2RlcG9pbnQ9MCx0aGlzLmN1cnJlbnRTdGF0ZT0xNSZ0aGlzLl9wYXJzZVN0YWNrLnRyYW5zaXRpb259Zm9yKHZhciBsPXM7bDx0OysrbCl7c3dpdGNoKG49ZVtsXSwobz10aGlzLl90cmFuc2l0aW9ucy50YWJsZVt0aGlzLmN1cnJlbnRTdGF0ZTw8OHwobjwxNjA/bjpoKV0pPj40KXtjYXNlIDI6Zm9yKHZhciB1PWwrMTs7Kyt1KXtpZih1Pj10fHwobj1lW3VdKTwzMnx8bj4xMjYmJm48aCl7dGhpcy5fcHJpbnRIYW5kbGVyKGUsbCx1KSxsPXUtMTticmVha31pZigrK3U+PXR8fChuPWVbdV0pPDMyfHxuPjEyNiYmbjxoKXt0aGlzLl9wcmludEhhbmRsZXIoZSxsLHUpLGw9dS0xO2JyZWFrfWlmKCsrdT49dHx8KG49ZVt1XSk8MzJ8fG4+MTI2JiZuPGgpe3RoaXMuX3ByaW50SGFuZGxlcihlLGwsdSksbD11LTE7YnJlYWt9aWYoKyt1Pj10fHwobj1lW3VdKTwzMnx8bj4xMjYmJm48aCl7dGhpcy5fcHJpbnRIYW5kbGVyKGUsbCx1KSxsPXUtMTticmVha319YnJlYWs7Y2FzZSAzOnRoaXMuX2V4ZWN1dGVIYW5kbGVyc1tuXT90aGlzLl9leGVjdXRlSGFuZGxlcnNbbl0oKTp0aGlzLl9leGVjdXRlSGFuZGxlckZiKG4pLHRoaXMucHJlY2VkaW5nQ29kZXBvaW50PTA7YnJlYWs7Y2FzZSAwOmJyZWFrO2Nhc2UgMTppZih0aGlzLl9lcnJvckhhbmRsZXIoe3Bvc2l0aW9uOmwsY29kZTpuLGN1cnJlbnRTdGF0ZTp0aGlzLmN1cnJlbnRTdGF0ZSxjb2xsZWN0OnRoaXMuX2NvbGxlY3QscGFyYW1zOnRoaXMuX3BhcmFtcyxhYm9ydDohMX0pLmFib3J0KXJldHVybjticmVhaztjYXNlIDc6Zm9yKHZhciBmPShhPXRoaXMuX2NzaUhhbmRsZXJzW3RoaXMuX2NvbGxlY3Q8PDh8bl0pP2EubGVuZ3RoLTE6LTE7Zj49MCYmITAhPT0oaT1hW2ZdKHRoaXMuX3BhcmFtcykpO2YtLSlpZihpIGluc3RhbmNlb2YgUHJvbWlzZSlyZXR1cm4gdGhpcy5fcHJlc2VydmVTdGFjaygzLGEsZixvLGwpLGk7ZjwwJiZ0aGlzLl9jc2lIYW5kbGVyRmIodGhpcy5fY29sbGVjdDw8OHxuLHRoaXMuX3BhcmFtcyksdGhpcy5wcmVjZWRpbmdDb2RlcG9pbnQ9MDticmVhaztjYXNlIDg6ZG97c3dpdGNoKG4pe2Nhc2UgNTk6dGhpcy5fcGFyYW1zLmFkZFBhcmFtKDApO2JyZWFrO2Nhc2UgNTg6dGhpcy5fcGFyYW1zLmFkZFN1YlBhcmFtKC0xKTticmVhaztkZWZhdWx0OnRoaXMuX3BhcmFtcy5hZGREaWdpdChuLTQ4KX19d2hpbGUoKytsPHQmJihuPWVbbF0pPjQ3JiZuPDYwKTtsLS07YnJlYWs7Y2FzZSA5OnRoaXMuX2NvbGxlY3Q8PD04LHRoaXMuX2NvbGxlY3R8PW47YnJlYWs7Y2FzZSAxMDpmb3IodmFyIF89dGhpcy5fZXNjSGFuZGxlcnNbdGhpcy5fY29sbGVjdDw8OHxuXSxkPV8/Xy5sZW5ndGgtMTotMTtkPj0wJiYhMCE9PShpPV9bZF0oKSk7ZC0tKWlmKGkgaW5zdGFuY2VvZiBQcm9taXNlKXJldHVybiB0aGlzLl9wcmVzZXJ2ZVN0YWNrKDQsXyxkLG8sbCksaTtkPDAmJnRoaXMuX2VzY0hhbmRsZXJGYih0aGlzLl9jb2xsZWN0PDw4fG4pLHRoaXMucHJlY2VkaW5nQ29kZXBvaW50PTA7YnJlYWs7Y2FzZSAxMTp0aGlzLl9wYXJhbXMucmVzZXQoKSx0aGlzLl9wYXJhbXMuYWRkUGFyYW0oMCksdGhpcy5fY29sbGVjdD0wO2JyZWFrO2Nhc2UgMTI6dGhpcy5fZGNzUGFyc2VyLmhvb2sodGhpcy5fY29sbGVjdDw8OHxuLHRoaXMuX3BhcmFtcyk7YnJlYWs7Y2FzZSAxMzpmb3IodmFyIHA9bCsxOzsrK3ApaWYocD49dHx8MjQ9PT0obj1lW3BdKXx8MjY9PT1ufHwyNz09PW58fG4+MTI3JiZuPGgpe3RoaXMuX2Rjc1BhcnNlci5wdXQoZSxsLHApLGw9cC0xO2JyZWFrfWJyZWFrO2Nhc2UgMTQ6aWYoaT10aGlzLl9kY3NQYXJzZXIudW5ob29rKDI0IT09biYmMjYhPT1uKSlyZXR1cm4gdGhpcy5fcHJlc2VydmVTdGFjayg2LFtdLDAsbyxsKSxpOzI3PT09biYmKG98PTEpLHRoaXMuX3BhcmFtcy5yZXNldCgpLHRoaXMuX3BhcmFtcy5hZGRQYXJhbSgwKSx0aGlzLl9jb2xsZWN0PTAsdGhpcy5wcmVjZWRpbmdDb2RlcG9pbnQ9MDticmVhaztjYXNlIDQ6dGhpcy5fb3NjUGFyc2VyLnN0YXJ0KCk7YnJlYWs7Y2FzZSA1OmZvcih2YXIgdj1sKzE7O3YrKylpZih2Pj10fHwobj1lW3ZdKTwzMnx8bj4xMjcmJm48aCl7dGhpcy5fb3NjUGFyc2VyLnB1dChlLGwsdiksbD12LTE7YnJlYWt9YnJlYWs7Y2FzZSA2OmlmKGk9dGhpcy5fb3NjUGFyc2VyLmVuZCgyNCE9PW4mJjI2IT09bikpcmV0dXJuIHRoaXMuX3ByZXNlcnZlU3RhY2soNSxbXSwwLG8sbCksaTsyNz09PW4mJihvfD0xKSx0aGlzLl9wYXJhbXMucmVzZXQoKSx0aGlzLl9wYXJhbXMuYWRkUGFyYW0oMCksdGhpcy5fY29sbGVjdD0wLHRoaXMucHJlY2VkaW5nQ29kZXBvaW50PTB9dGhpcy5jdXJyZW50U3RhdGU9MTUmb319LHJ9KG8uRGlzcG9zYWJsZSk7dC5Fc2NhcGVTZXF1ZW5jZVBhcnNlcj1mfSw2MjQyOihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Pc2NIYW5kbGVyPXQuT3NjUGFyc2VyPXZvaWQgMDt2YXIgaT1yKDU3NzApLG49cig0ODIpLG89W10scz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt0aGlzLl9zdGF0ZT0wLHRoaXMuX2FjdGl2ZT1vLHRoaXMuX2lkPS0xLHRoaXMuX2hhbmRsZXJzPU9iamVjdC5jcmVhdGUobnVsbCksdGhpcy5faGFuZGxlckZiPWZ1bmN0aW9uKCl7fSx0aGlzLl9zdGFjaz17cGF1c2VkOiExLGxvb3BQb3NpdGlvbjowLGZhbGxUaHJvdWdoOiExfX1yZXR1cm4gZS5wcm90b3R5cGUucmVnaXN0ZXJIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7dm9pZCAwPT09dGhpcy5faGFuZGxlcnNbZV0mJih0aGlzLl9oYW5kbGVyc1tlXT1bXSk7dmFyIHI9dGhpcy5faGFuZGxlcnNbZV07cmV0dXJuIHIucHVzaCh0KSx7ZGlzcG9zZTpmdW5jdGlvbigpe3ZhciBlPXIuaW5kZXhPZih0KTstMSE9PWUmJnIuc3BsaWNlKGUsMSl9fX0sZS5wcm90b3R5cGUuY2xlYXJIYW5kbGVyPWZ1bmN0aW9uKGUpe3RoaXMuX2hhbmRsZXJzW2VdJiZkZWxldGUgdGhpcy5faGFuZGxlcnNbZV19LGUucHJvdG90eXBlLnNldEhhbmRsZXJGYWxsYmFjaz1mdW5jdGlvbihlKXt0aGlzLl9oYW5kbGVyRmI9ZX0sZS5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe3RoaXMuX2hhbmRsZXJzPU9iamVjdC5jcmVhdGUobnVsbCksdGhpcy5faGFuZGxlckZiPWZ1bmN0aW9uKCl7fSx0aGlzLl9hY3RpdmU9b30sZS5wcm90b3R5cGUucmVzZXQ9ZnVuY3Rpb24oKXtpZigyPT09dGhpcy5fc3RhdGUpZm9yKHZhciBlPXRoaXMuX3N0YWNrLnBhdXNlZD90aGlzLl9zdGFjay5sb29wUG9zaXRpb24tMTp0aGlzLl9hY3RpdmUubGVuZ3RoLTE7ZT49MDstLWUpdGhpcy5fYWN0aXZlW2VdLmVuZCghMSk7dGhpcy5fc3RhY2sucGF1c2VkPSExLHRoaXMuX2FjdGl2ZT1vLHRoaXMuX2lkPS0xLHRoaXMuX3N0YXRlPTB9LGUucHJvdG90eXBlLl9zdGFydD1mdW5jdGlvbigpe2lmKHRoaXMuX2FjdGl2ZT10aGlzLl9oYW5kbGVyc1t0aGlzLl9pZF18fG8sdGhpcy5fYWN0aXZlLmxlbmd0aClmb3IodmFyIGU9dGhpcy5fYWN0aXZlLmxlbmd0aC0xO2U+PTA7ZS0tKXRoaXMuX2FjdGl2ZVtlXS5zdGFydCgpO2Vsc2UgdGhpcy5faGFuZGxlckZiKHRoaXMuX2lkLCJTVEFSVCIpfSxlLnByb3RvdHlwZS5fcHV0PWZ1bmN0aW9uKGUsdCxyKXtpZih0aGlzLl9hY3RpdmUubGVuZ3RoKWZvcih2YXIgaT10aGlzLl9hY3RpdmUubGVuZ3RoLTE7aT49MDtpLS0pdGhpcy5fYWN0aXZlW2ldLnB1dChlLHQscik7ZWxzZSB0aGlzLl9oYW5kbGVyRmIodGhpcy5faWQsIlBVVCIsKDAsbi51dGYzMlRvU3RyaW5nKShlLHQscikpfSxlLnByb3RvdHlwZS5zdGFydD1mdW5jdGlvbigpe3RoaXMucmVzZXQoKSx0aGlzLl9zdGF0ZT0xfSxlLnByb3RvdHlwZS5wdXQ9ZnVuY3Rpb24oZSx0LHIpe2lmKDMhPT10aGlzLl9zdGF0ZSl7aWYoMT09PXRoaXMuX3N0YXRlKWZvcig7dDxyOyl7dmFyIGk9ZVt0KytdO2lmKDU5PT09aSl7dGhpcy5fc3RhdGU9Mix0aGlzLl9zdGFydCgpO2JyZWFrfWlmKGk8NDh8fDU3PGkpcmV0dXJuIHZvaWQodGhpcy5fc3RhdGU9Myk7LTE9PT10aGlzLl9pZCYmKHRoaXMuX2lkPTApLHRoaXMuX2lkPTEwKnRoaXMuX2lkK2ktNDh9Mj09PXRoaXMuX3N0YXRlJiZyLXQ+MCYmdGhpcy5fcHV0KGUsdCxyKX19LGUucHJvdG90eXBlLmVuZD1mdW5jdGlvbihlLHQpe2lmKHZvaWQgMD09PXQmJih0PSEwKSwwIT09dGhpcy5fc3RhdGUpe2lmKDMhPT10aGlzLl9zdGF0ZSlpZigxPT09dGhpcy5fc3RhdGUmJnRoaXMuX3N0YXJ0KCksdGhpcy5fYWN0aXZlLmxlbmd0aCl7dmFyIHI9ITEsaT10aGlzLl9hY3RpdmUubGVuZ3RoLTEsbj0hMTtpZih0aGlzLl9zdGFjay5wYXVzZWQmJihpPXRoaXMuX3N0YWNrLmxvb3BQb3NpdGlvbi0xLHI9dCxuPXRoaXMuX3N0YWNrLmZhbGxUaHJvdWdoLHRoaXMuX3N0YWNrLnBhdXNlZD0hMSksIW4mJiExPT09cil7Zm9yKDtpPj0wJiYhMCE9PShyPXRoaXMuX2FjdGl2ZVtpXS5lbmQoZSkpO2ktLSlpZihyIGluc3RhbmNlb2YgUHJvbWlzZSlyZXR1cm4gdGhpcy5fc3RhY2sucGF1c2VkPSEwLHRoaXMuX3N0YWNrLmxvb3BQb3NpdGlvbj1pLHRoaXMuX3N0YWNrLmZhbGxUaHJvdWdoPSExLHI7aS0tfWZvcig7aT49MDtpLS0paWYoKHI9dGhpcy5fYWN0aXZlW2ldLmVuZCghMSkpaW5zdGFuY2VvZiBQcm9taXNlKXJldHVybiB0aGlzLl9zdGFjay5wYXVzZWQ9ITAsdGhpcy5fc3RhY2subG9vcFBvc2l0aW9uPWksdGhpcy5fc3RhY2suZmFsbFRocm91Z2g9ITAscn1lbHNlIHRoaXMuX2hhbmRsZXJGYih0aGlzLl9pZCwiRU5EIixlKTt0aGlzLl9hY3RpdmU9byx0aGlzLl9pZD0tMSx0aGlzLl9zdGF0ZT0wfX0sZX0oKTt0Lk9zY1BhcnNlcj1zO3ZhciBhPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLl9oYW5kbGVyPWUsdGhpcy5fZGF0YT0iIix0aGlzLl9oaXRMaW1pdD0hMX1yZXR1cm4gZS5wcm90b3R5cGUuc3RhcnQ9ZnVuY3Rpb24oKXt0aGlzLl9kYXRhPSIiLHRoaXMuX2hpdExpbWl0PSExfSxlLnByb3RvdHlwZS5wdXQ9ZnVuY3Rpb24oZSx0LHIpe3RoaXMuX2hpdExpbWl0fHwodGhpcy5fZGF0YSs9KDAsbi51dGYzMlRvU3RyaW5nKShlLHQsciksdGhpcy5fZGF0YS5sZW5ndGg+aS5QQVlMT0FEX0xJTUlUJiYodGhpcy5fZGF0YT0iIix0aGlzLl9oaXRMaW1pdD0hMCkpfSxlLnByb3RvdHlwZS5lbmQ9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcyxyPSExO2lmKHRoaXMuX2hpdExpbWl0KXI9ITE7ZWxzZSBpZihlJiYocj10aGlzLl9oYW5kbGVyKHRoaXMuX2RhdGEpKWluc3RhbmNlb2YgUHJvbWlzZSlyZXR1cm4gci50aGVuKChmdW5jdGlvbihlKXtyZXR1cm4gdC5fZGF0YT0iIix0Ll9oaXRMaW1pdD0hMSxlfSkpO3JldHVybiB0aGlzLl9kYXRhPSIiLHRoaXMuX2hpdExpbWl0PSExLHJ9LGV9KCk7dC5Pc2NIYW5kbGVyPWF9LDg3NDI6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5QYXJhbXM9dm9pZCAwO3ZhciByPTIxNDc0ODM2NDcsaT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXtpZih2b2lkIDA9PT1lJiYoZT0zMiksdm9pZCAwPT09dCYmKHQ9MzIpLHRoaXMubWF4TGVuZ3RoPWUsdGhpcy5tYXhTdWJQYXJhbXNMZW5ndGg9dCx0PjI1Nil0aHJvdyBuZXcgRXJyb3IoIm1heFN1YlBhcmFtc0xlbmd0aCBtdXN0IG5vdCBiZSBncmVhdGVyIHRoYW4gMjU2Iik7dGhpcy5wYXJhbXM9bmV3IEludDMyQXJyYXkoZSksdGhpcy5sZW5ndGg9MCx0aGlzLl9zdWJQYXJhbXM9bmV3IEludDMyQXJyYXkodCksdGhpcy5fc3ViUGFyYW1zTGVuZ3RoPTAsdGhpcy5fc3ViUGFyYW1zSWR4PW5ldyBVaW50MTZBcnJheShlKSx0aGlzLl9yZWplY3REaWdpdHM9ITEsdGhpcy5fcmVqZWN0U3ViRGlnaXRzPSExLHRoaXMuX2RpZ2l0SXNTdWI9ITF9cmV0dXJuIGUuZnJvbUFycmF5PWZ1bmN0aW9uKHQpe3ZhciByPW5ldyBlO2lmKCF0Lmxlbmd0aClyZXR1cm4gcjtmb3IodmFyIGk9QXJyYXkuaXNBcnJheSh0WzBdKT8xOjA7aTx0Lmxlbmd0aDsrK2kpe3ZhciBuPXRbaV07aWYoQXJyYXkuaXNBcnJheShuKSlmb3IodmFyIG89MDtvPG4ubGVuZ3RoOysrbylyLmFkZFN1YlBhcmFtKG5bb10pO2Vsc2Ugci5hZGRQYXJhbShuKX1yZXR1cm4gcn0sZS5wcm90b3R5cGUuY2xvbmU9ZnVuY3Rpb24oKXt2YXIgdD1uZXcgZSh0aGlzLm1heExlbmd0aCx0aGlzLm1heFN1YlBhcmFtc0xlbmd0aCk7cmV0dXJuIHQucGFyYW1zLnNldCh0aGlzLnBhcmFtcyksdC5sZW5ndGg9dGhpcy5sZW5ndGgsdC5fc3ViUGFyYW1zLnNldCh0aGlzLl9zdWJQYXJhbXMpLHQuX3N1YlBhcmFtc0xlbmd0aD10aGlzLl9zdWJQYXJhbXNMZW5ndGgsdC5fc3ViUGFyYW1zSWR4LnNldCh0aGlzLl9zdWJQYXJhbXNJZHgpLHQuX3JlamVjdERpZ2l0cz10aGlzLl9yZWplY3REaWdpdHMsdC5fcmVqZWN0U3ViRGlnaXRzPXRoaXMuX3JlamVjdFN1YkRpZ2l0cyx0Ll9kaWdpdElzU3ViPXRoaXMuX2RpZ2l0SXNTdWIsdH0sZS5wcm90b3R5cGUudG9BcnJheT1mdW5jdGlvbigpe2Zvcih2YXIgZT1bXSx0PTA7dDx0aGlzLmxlbmd0aDsrK3Qpe2UucHVzaCh0aGlzLnBhcmFtc1t0XSk7dmFyIHI9dGhpcy5fc3ViUGFyYW1zSWR4W3RdPj44LGk9MjU1JnRoaXMuX3N1YlBhcmFtc0lkeFt0XTtpLXI+MCYmZS5wdXNoKEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHRoaXMuX3N1YlBhcmFtcyxyLGkpKX1yZXR1cm4gZX0sZS5wcm90b3R5cGUucmVzZXQ9ZnVuY3Rpb24oKXt0aGlzLmxlbmd0aD0wLHRoaXMuX3N1YlBhcmFtc0xlbmd0aD0wLHRoaXMuX3JlamVjdERpZ2l0cz0hMSx0aGlzLl9yZWplY3RTdWJEaWdpdHM9ITEsdGhpcy5fZGlnaXRJc1N1Yj0hMX0sZS5wcm90b3R5cGUuYWRkUGFyYW09ZnVuY3Rpb24oZSl7aWYodGhpcy5fZGlnaXRJc1N1Yj0hMSx0aGlzLmxlbmd0aD49dGhpcy5tYXhMZW5ndGgpdGhpcy5fcmVqZWN0RGlnaXRzPSEwO2Vsc2V7aWYoZTwtMSl0aHJvdyBuZXcgRXJyb3IoInZhbHVlcyBsZXNzZXIgdGhhbiAtMSBhcmUgbm90IGFsbG93ZWQiKTt0aGlzLl9zdWJQYXJhbXNJZHhbdGhpcy5sZW5ndGhdPXRoaXMuX3N1YlBhcmFtc0xlbmd0aDw8OHx0aGlzLl9zdWJQYXJhbXNMZW5ndGgsdGhpcy5wYXJhbXNbdGhpcy5sZW5ndGgrK109ZT5yP3I6ZX19LGUucHJvdG90eXBlLmFkZFN1YlBhcmFtPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2RpZ2l0SXNTdWI9ITAsdGhpcy5sZW5ndGgpaWYodGhpcy5fcmVqZWN0RGlnaXRzfHx0aGlzLl9zdWJQYXJhbXNMZW5ndGg+PXRoaXMubWF4U3ViUGFyYW1zTGVuZ3RoKXRoaXMuX3JlamVjdFN1YkRpZ2l0cz0hMDtlbHNle2lmKGU8LTEpdGhyb3cgbmV3IEVycm9yKCJ2YWx1ZXMgbGVzc2VyIHRoYW4gLTEgYXJlIG5vdCBhbGxvd2VkIik7dGhpcy5fc3ViUGFyYW1zW3RoaXMuX3N1YlBhcmFtc0xlbmd0aCsrXT1lPnI/cjplLHRoaXMuX3N1YlBhcmFtc0lkeFt0aGlzLmxlbmd0aC0xXSsrfX0sZS5wcm90b3R5cGUuaGFzU3ViUGFyYW1zPWZ1bmN0aW9uKGUpe3JldHVybigyNTUmdGhpcy5fc3ViUGFyYW1zSWR4W2VdKS0odGhpcy5fc3ViUGFyYW1zSWR4W2VdPj44KT4wfSxlLnByb3RvdHlwZS5nZXRTdWJQYXJhbXM9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fc3ViUGFyYW1zSWR4W2VdPj44LHI9MjU1JnRoaXMuX3N1YlBhcmFtc0lkeFtlXTtyZXR1cm4gci10PjA/dGhpcy5fc3ViUGFyYW1zLnN1YmFycmF5KHQscik6bnVsbH0sZS5wcm90b3R5cGUuZ2V0U3ViUGFyYW1zQWxsPWZ1bmN0aW9uKCl7Zm9yKHZhciBlPXt9LHQ9MDt0PHRoaXMubGVuZ3RoOysrdCl7dmFyIHI9dGhpcy5fc3ViUGFyYW1zSWR4W3RdPj44LGk9MjU1JnRoaXMuX3N1YlBhcmFtc0lkeFt0XTtpLXI+MCYmKGVbdF09dGhpcy5fc3ViUGFyYW1zLnNsaWNlKHIsaSkpfXJldHVybiBlfSxlLnByb3RvdHlwZS5hZGREaWdpdD1mdW5jdGlvbihlKXt2YXIgdDtpZighKHRoaXMuX3JlamVjdERpZ2l0c3x8ISh0PXRoaXMuX2RpZ2l0SXNTdWI/dGhpcy5fc3ViUGFyYW1zTGVuZ3RoOnRoaXMubGVuZ3RoKXx8dGhpcy5fZGlnaXRJc1N1YiYmdGhpcy5fcmVqZWN0U3ViRGlnaXRzKSl7dmFyIGk9dGhpcy5fZGlnaXRJc1N1Yj90aGlzLl9zdWJQYXJhbXM6dGhpcy5wYXJhbXMsbj1pW3QtMV07aVt0LTFdPX5uP01hdGgubWluKDEwKm4rZSxyKTplfX0sZX0oKTt0LlBhcmFtcz1pfSw1NzQxOihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQWRkb25NYW5hZ2VyPXZvaWQgMDt2YXIgcj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt0aGlzLl9hZGRvbnM9W119cmV0dXJuIGUucHJvdG90eXBlLmRpc3Bvc2U9ZnVuY3Rpb24oKXtmb3IodmFyIGU9dGhpcy5fYWRkb25zLmxlbmd0aC0xO2U+PTA7ZS0tKXRoaXMuX2FkZG9uc1tlXS5pbnN0YW5jZS5kaXNwb3NlKCl9LGUucHJvdG90eXBlLmxvYWRBZGRvbj1mdW5jdGlvbihlLHQpe3ZhciByPXRoaXMsaT17aW5zdGFuY2U6dCxkaXNwb3NlOnQuZGlzcG9zZSxpc0Rpc3Bvc2VkOiExfTt0aGlzLl9hZGRvbnMucHVzaChpKSx0LmRpc3Bvc2U9ZnVuY3Rpb24oKXtyZXR1cm4gci5fd3JhcHBlZEFkZG9uRGlzcG9zZShpKX0sdC5hY3RpdmF0ZShlKX0sZS5wcm90b3R5cGUuX3dyYXBwZWRBZGRvbkRpc3Bvc2U9ZnVuY3Rpb24oZSl7aWYoIWUuaXNEaXNwb3NlZCl7Zm9yKHZhciB0PS0xLHI9MDtyPHRoaXMuX2FkZG9ucy5sZW5ndGg7cisrKWlmKHRoaXMuX2FkZG9uc1tyXT09PWUpe3Q9cjticmVha31pZigtMT09PXQpdGhyb3cgbmV3IEVycm9yKCJDb3VsZCBub3QgZGlzcG9zZSBhbiBhZGRvbiB0aGF0IGhhcyBub3QgYmVlbiBsb2FkZWQiKTtlLmlzRGlzcG9zZWQ9ITAsZS5kaXNwb3NlLmFwcGx5KGUuaW5zdGFuY2UpLHRoaXMuX2FkZG9ucy5zcGxpY2UodCwxKX19LGV9KCk7dC5BZGRvbk1hbmFnZXI9cn0sODc3MTooZSx0LHIpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQnVmZmVyQXBpVmlldz12b2lkIDA7dmFyIGk9cigzNzg1KSxuPXIoNTExKSxvPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMuX2J1ZmZlcj1lLHRoaXMudHlwZT10fXJldHVybiBlLnByb3RvdHlwZS5pbml0PWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9idWZmZXI9ZSx0aGlzfSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImN1cnNvclkiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fYnVmZmVyLnl9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJjdXJzb3JYIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2J1ZmZlci54fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwidmlld3BvcnRZIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2J1ZmZlci55ZGlzcH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImJhc2VZIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2J1ZmZlci55YmFzZX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImxlbmd0aCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9idWZmZXIubGluZXMubGVuZ3RofSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLmdldExpbmU9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fYnVmZmVyLmxpbmVzLmdldChlKTtpZih0KXJldHVybiBuZXcgaS5CdWZmZXJMaW5lQXBpVmlldyh0KX0sZS5wcm90b3R5cGUuZ2V0TnVsbENlbGw9ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IG4uQ2VsbERhdGF9LGV9KCk7dC5CdWZmZXJBcGlWaWV3PW99LDM3ODU6KGUsdCxyKT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkJ1ZmZlckxpbmVBcGlWaWV3PXZvaWQgMDt2YXIgaT1yKDUxMSksbj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy5fbGluZT1lfXJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImlzV3JhcHBlZCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9saW5lLmlzV3JhcHBlZH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImxlbmd0aCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9saW5lLmxlbmd0aH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxlLnByb3RvdHlwZS5nZXRDZWxsPWZ1bmN0aW9uKGUsdCl7aWYoIShlPDB8fGU+PXRoaXMuX2xpbmUubGVuZ3RoKSlyZXR1cm4gdD8odGhpcy5fbGluZS5sb2FkQ2VsbChlLHQpLHQpOnRoaXMuX2xpbmUubG9hZENlbGwoZSxuZXcgaS5DZWxsRGF0YSl9LGUucHJvdG90eXBlLnRyYW5zbGF0ZVRvU3RyaW5nPWZ1bmN0aW9uKGUsdCxyKXtyZXR1cm4gdGhpcy5fbGluZS50cmFuc2xhdGVUb1N0cmluZyhlLHQscil9LGV9KCk7dC5CdWZmZXJMaW5lQXBpVmlldz1ufSw4Mjg1OihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5CdWZmZXJOYW1lc3BhY2VBcGk9dm9pZCAwO3ZhciBpPXIoODc3MSksbj1yKDg0NjApLG89ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3ZhciB0PXRoaXM7dGhpcy5fY29yZT1lLHRoaXMuX29uQnVmZmVyQ2hhbmdlPW5ldyBuLkV2ZW50RW1pdHRlcix0aGlzLl9ub3JtYWw9bmV3IGkuQnVmZmVyQXBpVmlldyh0aGlzLl9jb3JlLmJ1ZmZlcnMubm9ybWFsLCJub3JtYWwiKSx0aGlzLl9hbHRlcm5hdGU9bmV3IGkuQnVmZmVyQXBpVmlldyh0aGlzLl9jb3JlLmJ1ZmZlcnMuYWx0LCJhbHRlcm5hdGUiKSx0aGlzLl9jb3JlLmJ1ZmZlcnMub25CdWZmZXJBY3RpdmF0ZSgoZnVuY3Rpb24oKXtyZXR1cm4gdC5fb25CdWZmZXJDaGFuZ2UuZmlyZSh0LmFjdGl2ZSl9KSl9cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwib25CdWZmZXJDaGFuZ2UiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25CdWZmZXJDaGFuZ2UuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJhY3RpdmUiLHtnZXQ6ZnVuY3Rpb24oKXtpZih0aGlzLl9jb3JlLmJ1ZmZlcnMuYWN0aXZlPT09dGhpcy5fY29yZS5idWZmZXJzLm5vcm1hbClyZXR1cm4gdGhpcy5ub3JtYWw7aWYodGhpcy5fY29yZS5idWZmZXJzLmFjdGl2ZT09PXRoaXMuX2NvcmUuYnVmZmVycy5hbHQpcmV0dXJuIHRoaXMuYWx0ZXJuYXRlO3Rocm93IG5ldyBFcnJvcigiQWN0aXZlIGJ1ZmZlciBpcyBuZWl0aGVyIG5vcm1hbCBub3IgYWx0ZXJuYXRlIil9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJub3JtYWwiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fbm9ybWFsLmluaXQodGhpcy5fY29yZS5idWZmZXJzLm5vcm1hbCl9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJhbHRlcm5hdGUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fYWx0ZXJuYXRlLmluaXQodGhpcy5fY29yZS5idWZmZXJzLmFsdCl9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksZX0oKTt0LkJ1ZmZlck5hbWVzcGFjZUFwaT1vfSw3OTc1OihlLHQpPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuUGFyc2VyQXBpPXZvaWQgMDt2YXIgcj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy5fY29yZT1lfXJldHVybiBlLnByb3RvdHlwZS5yZWdpc3RlckNzaUhhbmRsZXI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5fY29yZS5yZWdpc3RlckNzaUhhbmRsZXIoZSwoZnVuY3Rpb24oZSl7cmV0dXJuIHQoZS50b0FycmF5KCkpfSkpfSxlLnByb3RvdHlwZS5hZGRDc2lIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMucmVnaXN0ZXJDc2lIYW5kbGVyKGUsdCl9LGUucHJvdG90eXBlLnJlZ2lzdGVyRGNzSGFuZGxlcj1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLl9jb3JlLnJlZ2lzdGVyRGNzSGFuZGxlcihlLChmdW5jdGlvbihlLHIpe3JldHVybiB0KGUsci50b0FycmF5KCkpfSkpfSxlLnByb3RvdHlwZS5hZGREY3NIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMucmVnaXN0ZXJEY3NIYW5kbGVyKGUsdCl9LGUucHJvdG90eXBlLnJlZ2lzdGVyRXNjSGFuZGxlcj1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLl9jb3JlLnJlZ2lzdGVyRXNjSGFuZGxlcihlLHQpfSxlLnByb3RvdHlwZS5hZGRFc2NIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMucmVnaXN0ZXJFc2NIYW5kbGVyKGUsdCl9LGUucHJvdG90eXBlLnJlZ2lzdGVyT3NjSGFuZGxlcj1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLl9jb3JlLnJlZ2lzdGVyT3NjSGFuZGxlcihlLHQpfSxlLnByb3RvdHlwZS5hZGRPc2NIYW5kbGVyPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMucmVnaXN0ZXJPc2NIYW5kbGVyKGUsdCl9LGV9KCk7dC5QYXJzZXJBcGk9cn0sNzA5MDooZSx0KT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlVuaWNvZGVBcGk9dm9pZCAwO3ZhciByPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLl9jb3JlPWV9cmV0dXJuIGUucHJvdG90eXBlLnJlZ2lzdGVyPWZ1bmN0aW9uKGUpe3RoaXMuX2NvcmUudW5pY29kZVNlcnZpY2UucmVnaXN0ZXIoZSl9LE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwidmVyc2lvbnMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fY29yZS51bmljb2RlU2VydmljZS52ZXJzaW9uc30sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImFjdGl2ZVZlcnNpb24iLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fY29yZS51bmljb2RlU2VydmljZS5hY3RpdmVWZXJzaW9ufSxzZXQ6ZnVuY3Rpb24oZSl7dGhpcy5fY29yZS51bmljb2RlU2VydmljZS5hY3RpdmVWZXJzaW9uPWV9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksZX0oKTt0LlVuaWNvZGVBcGk9cn0sNzQ0OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaSxuPXRoaXMmJnRoaXMuX19leHRlbmRzfHwoaT1mdW5jdGlvbihlLHQpe3JldHVybiBpPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgciBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LHIpJiYoZVtyXT10W3JdKX0saShlLHQpfSxmdW5jdGlvbihlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPWV9aShlLHQpLGUucHJvdG90eXBlPW51bGw9PT10P09iamVjdC5jcmVhdGUodCk6KHIucHJvdG90eXBlPXQucHJvdG90eXBlLG5ldyByKX0pLG89dGhpcyYmdGhpcy5fX2RlY29yYXRlfHxmdW5jdGlvbihlLHQscixpKXt2YXIgbixvPWFyZ3VtZW50cy5sZW5ndGgscz1vPDM/dDpudWxsPT09aT9pPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodCxyKTppO2lmKCJvYmplY3QiPT10eXBlb2YgUmVmbGVjdCYmImZ1bmN0aW9uIj09dHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUpcz1SZWZsZWN0LmRlY29yYXRlKGUsdCxyLGkpO2Vsc2UgZm9yKHZhciBhPWUubGVuZ3RoLTE7YT49MDthLS0pKG49ZVthXSkmJihzPShvPDM/bihzKTpvPjM/bih0LHIscyk6bih0LHIpKXx8cyk7cmV0dXJuIG8+MyYmcyYmT2JqZWN0LmRlZmluZVByb3BlcnR5KHQscixzKSxzfSxzPXRoaXMmJnRoaXMuX19wYXJhbXx8ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocixpKXt0KHIsaSxlKX19O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkJ1ZmZlclNlcnZpY2U9dC5NSU5JTVVNX1JPV1M9dC5NSU5JTVVNX0NPTFM9dm9pZCAwO3ZhciBhPXIoMjU4NSksYz1yKDUyOTUpLGw9cig4NDYwKSx1PXIoODQ0KTt0Lk1JTklNVU1fQ09MUz0yLHQuTUlOSU1VTV9ST1dTPTE7dmFyIGg9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gcihyKXt2YXIgaT1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIGkuX29wdGlvbnNTZXJ2aWNlPXIsaS5pc1VzZXJTY3JvbGxpbmc9ITEsaS5fb25SZXNpemU9bmV3IGwuRXZlbnRFbWl0dGVyLGkuX29uU2Nyb2xsPW5ldyBsLkV2ZW50RW1pdHRlcixpLmNvbHM9TWF0aC5tYXgoci5vcHRpb25zLmNvbHN8fDAsdC5NSU5JTVVNX0NPTFMpLGkucm93cz1NYXRoLm1heChyLm9wdGlvbnMucm93c3x8MCx0Lk1JTklNVU1fUk9XUyksaS5idWZmZXJzPW5ldyBjLkJ1ZmZlclNldChyLGkpLGl9cmV0dXJuIG4ocixlKSxPYmplY3QuZGVmaW5lUHJvcGVydHkoci5wcm90b3R5cGUsIm9uUmVzaXplIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uUmVzaXplLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShyLnByb3RvdHlwZSwib25TY3JvbGwiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25TY3JvbGwuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHIucHJvdG90eXBlLCJidWZmZXIiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5idWZmZXJzLmFjdGl2ZX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxyLnByb3RvdHlwZS5kaXNwb3NlPWZ1bmN0aW9uKCl7ZS5wcm90b3R5cGUuZGlzcG9zZS5jYWxsKHRoaXMpLHRoaXMuYnVmZmVycy5kaXNwb3NlKCl9LHIucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbihlLHQpe3RoaXMuY29scz1lLHRoaXMucm93cz10LHRoaXMuYnVmZmVycy5yZXNpemUoZSx0KSx0aGlzLmJ1ZmZlcnMuc2V0dXBUYWJTdG9wcyh0aGlzLmNvbHMpLHRoaXMuX29uUmVzaXplLmZpcmUoe2NvbHM6ZSxyb3dzOnR9KX0sci5wcm90b3R5cGUucmVzZXQ9ZnVuY3Rpb24oKXt0aGlzLmJ1ZmZlcnMucmVzZXQoKSx0aGlzLmlzVXNlclNjcm9sbGluZz0hMX0sci5wcm90b3R5cGUuc2Nyb2xsPWZ1bmN0aW9uKGUsdCl7dm9pZCAwPT09dCYmKHQ9ITEpO3ZhciByLGk9dGhpcy5idWZmZXI7KHI9dGhpcy5fY2FjaGVkQmxhbmtMaW5lKSYmci5sZW5ndGg9PT10aGlzLmNvbHMmJnIuZ2V0RmcoMCk9PT1lLmZnJiZyLmdldEJnKDApPT09ZS5iZ3x8KHI9aS5nZXRCbGFua0xpbmUoZSx0KSx0aGlzLl9jYWNoZWRCbGFua0xpbmU9ciksci5pc1dyYXBwZWQ9dDt2YXIgbj1pLnliYXNlK2kuc2Nyb2xsVG9wLG89aS55YmFzZStpLnNjcm9sbEJvdHRvbTtpZigwPT09aS5zY3JvbGxUb3Ape3ZhciBzPWkubGluZXMuaXNGdWxsO289PT1pLmxpbmVzLmxlbmd0aC0xP3M/aS5saW5lcy5yZWN5Y2xlKCkuY29weUZyb20ocik6aS5saW5lcy5wdXNoKHIuY2xvbmUoKSk6aS5saW5lcy5zcGxpY2UobysxLDAsci5jbG9uZSgpKSxzP3RoaXMuaXNVc2VyU2Nyb2xsaW5nJiYoaS55ZGlzcD1NYXRoLm1heChpLnlkaXNwLTEsMCkpOihpLnliYXNlKyssdGhpcy5pc1VzZXJTY3JvbGxpbmd8fGkueWRpc3ArKyl9ZWxzZXt2YXIgYT1vLW4rMTtpLmxpbmVzLnNoaWZ0RWxlbWVudHMobisxLGEtMSwtMSksaS5saW5lcy5zZXQobyxyLmNsb25lKCkpfXRoaXMuaXNVc2VyU2Nyb2xsaW5nfHwoaS55ZGlzcD1pLnliYXNlKSx0aGlzLl9vblNjcm9sbC5maXJlKGkueWRpc3ApfSxyLnByb3RvdHlwZS5zY3JvbGxMaW5lcz1mdW5jdGlvbihlLHQscil7dmFyIGk9dGhpcy5idWZmZXI7aWYoZTwwKXtpZigwPT09aS55ZGlzcClyZXR1cm47dGhpcy5pc1VzZXJTY3JvbGxpbmc9ITB9ZWxzZSBlK2kueWRpc3A+PWkueWJhc2UmJih0aGlzLmlzVXNlclNjcm9sbGluZz0hMSk7dmFyIG49aS55ZGlzcDtpLnlkaXNwPU1hdGgubWF4KE1hdGgubWluKGkueWRpc3ArZSxpLnliYXNlKSwwKSxuIT09aS55ZGlzcCYmKHR8fHRoaXMuX29uU2Nyb2xsLmZpcmUoaS55ZGlzcCkpfSxyLnByb3RvdHlwZS5zY3JvbGxQYWdlcz1mdW5jdGlvbihlKXt0aGlzLnNjcm9sbExpbmVzKGUqKHRoaXMucm93cy0xKSl9LHIucHJvdG90eXBlLnNjcm9sbFRvVG9wPWZ1bmN0aW9uKCl7dGhpcy5zY3JvbGxMaW5lcygtdGhpcy5idWZmZXIueWRpc3ApfSxyLnByb3RvdHlwZS5zY3JvbGxUb0JvdHRvbT1mdW5jdGlvbigpe3RoaXMuc2Nyb2xsTGluZXModGhpcy5idWZmZXIueWJhc2UtdGhpcy5idWZmZXIueWRpc3ApfSxyLnByb3RvdHlwZS5zY3JvbGxUb0xpbmU9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS10aGlzLmJ1ZmZlci55ZGlzcDswIT09dCYmdGhpcy5zY3JvbGxMaW5lcyh0KX0sbyhbcygwLGEuSU9wdGlvbnNTZXJ2aWNlKV0scil9KHUuRGlzcG9zYWJsZSk7dC5CdWZmZXJTZXJ2aWNlPWh9LDc5OTQ6KGUsdCk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5DaGFyc2V0U2VydmljZT12b2lkIDA7dmFyIHI9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7dGhpcy5nbGV2ZWw9MCx0aGlzLl9jaGFyc2V0cz1bXX1yZXR1cm4gZS5wcm90b3R5cGUucmVzZXQ9ZnVuY3Rpb24oKXt0aGlzLmNoYXJzZXQ9dm9pZCAwLHRoaXMuX2NoYXJzZXRzPVtdLHRoaXMuZ2xldmVsPTB9LGUucHJvdG90eXBlLnNldGdMZXZlbD1mdW5jdGlvbihlKXt0aGlzLmdsZXZlbD1lLHRoaXMuY2hhcnNldD10aGlzLl9jaGFyc2V0c1tlXX0sZS5wcm90b3R5cGUuc2V0Z0NoYXJzZXQ9ZnVuY3Rpb24oZSx0KXt0aGlzLl9jaGFyc2V0c1tlXT10LHRoaXMuZ2xldmVsPT09ZSYmKHRoaXMuY2hhcnNldD10KX0sZX0oKTt0LkNoYXJzZXRTZXJ2aWNlPXJ9LDE3NTM6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXMmJnRoaXMuX19kZWNvcmF0ZXx8ZnVuY3Rpb24oZSx0LHIsaSl7dmFyIG4sbz1hcmd1bWVudHMubGVuZ3RoLHM9bzwzP3Q6bnVsbD09PWk/aT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHQscik6aTtpZigib2JqZWN0Ij09dHlwZW9mIFJlZmxlY3QmJiJmdW5jdGlvbiI9PXR5cGVvZiBSZWZsZWN0LmRlY29yYXRlKXM9UmVmbGVjdC5kZWNvcmF0ZShlLHQscixpKTtlbHNlIGZvcih2YXIgYT1lLmxlbmd0aC0xO2E+PTA7YS0tKShuPWVbYV0pJiYocz0obzwzP24ocyk6bz4zP24odCxyLHMpOm4odCxyKSl8fHMpO3JldHVybiBvPjMmJnMmJk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LHIscyksc30sbj10aGlzJiZ0aGlzLl9fcGFyYW18fGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIsaSl7dChyLGksZSl9fTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Db3JlTW91c2VTZXJ2aWNlPXZvaWQgMDt2YXIgbz1yKDI1ODUpLHM9cig4NDYwKSxhPXtOT05FOntldmVudHM6MCxyZXN0cmljdDpmdW5jdGlvbigpe3JldHVybiExfX0sWDEwOntldmVudHM6MSxyZXN0cmljdDpmdW5jdGlvbihlKXtyZXR1cm4gNCE9PWUuYnV0dG9uJiYxPT09ZS5hY3Rpb24mJihlLmN0cmw9ITEsZS5hbHQ9ITEsZS5zaGlmdD0hMSwhMCl9fSxWVDIwMDp7ZXZlbnRzOjE5LHJlc3RyaWN0OmZ1bmN0aW9uKGUpe3JldHVybiAzMiE9PWUuYWN0aW9ufX0sRFJBRzp7ZXZlbnRzOjIzLHJlc3RyaWN0OmZ1bmN0aW9uKGUpe3JldHVybiAzMiE9PWUuYWN0aW9ufHwzIT09ZS5idXR0b259fSxBTlk6e2V2ZW50czozMSxyZXN0cmljdDpmdW5jdGlvbihlKXtyZXR1cm4hMH19fTtmdW5jdGlvbiBjKGUsdCl7dmFyIHI9KGUuY3RybD8xNjowKXwoZS5zaGlmdD80OjApfChlLmFsdD84OjApO3JldHVybiA0PT09ZS5idXR0b24/KHJ8PTY0LHJ8PWUuYWN0aW9uKToocnw9MyZlLmJ1dHRvbiw0JmUuYnV0dG9uJiYocnw9NjQpLDgmZS5idXR0b24mJihyfD0xMjgpLDMyPT09ZS5hY3Rpb24/cnw9MzI6MCE9PWUuYWN0aW9ufHx0fHwocnw9MykpLHJ9dmFyIGw9U3RyaW5nLmZyb21DaGFyQ29kZSx1PXtERUZBVUxUOmZ1bmN0aW9uKGUpe3ZhciB0PVtjKGUsITEpKzMyLGUuY29sKzMyLGUucm93KzMyXTtyZXR1cm4gdFswXT4yNTV8fHRbMV0+MjU1fHx0WzJdPjI1NT8iIjoiG1tNIitsKHRbMF0pK2wodFsxXSkrbCh0WzJdKX0sU0dSOmZ1bmN0aW9uKGUpe3ZhciB0PTA9PT1lLmFjdGlvbiYmNCE9PWUuYnV0dG9uPyJtIjoiTSI7cmV0dXJuIhtbPCIrYyhlLCEwKSsiOyIrZS5jb2wrIjsiK2Uucm93K3R9fSxoPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMuX2J1ZmZlclNlcnZpY2U9ZSx0aGlzLl9jb3JlU2VydmljZT10LHRoaXMuX3Byb3RvY29scz17fSx0aGlzLl9lbmNvZGluZ3M9e30sdGhpcy5fYWN0aXZlUHJvdG9jb2w9IiIsdGhpcy5fYWN0aXZlRW5jb2Rpbmc9IiIsdGhpcy5fb25Qcm90b2NvbENoYW5nZT1uZXcgcy5FdmVudEVtaXR0ZXIsdGhpcy5fbGFzdEV2ZW50PW51bGw7Zm9yKHZhciByPTAsaT1PYmplY3Qua2V5cyhhKTtyPGkubGVuZ3RoO3IrKyl7dmFyIG49aVtyXTt0aGlzLmFkZFByb3RvY29sKG4sYVtuXSl9Zm9yKHZhciBvPTAsYz1PYmplY3Qua2V5cyh1KTtvPGMubGVuZ3RoO28rKyl7dmFyIGw9Y1tvXTt0aGlzLmFkZEVuY29kaW5nKGwsdVtsXSl9dGhpcy5yZXNldCgpfXJldHVybiBlLnByb3RvdHlwZS5hZGRQcm90b2NvbD1mdW5jdGlvbihlLHQpe3RoaXMuX3Byb3RvY29sc1tlXT10fSxlLnByb3RvdHlwZS5hZGRFbmNvZGluZz1mdW5jdGlvbihlLHQpe3RoaXMuX2VuY29kaW5nc1tlXT10fSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImFjdGl2ZVByb3RvY29sIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2FjdGl2ZVByb3RvY29sfSxzZXQ6ZnVuY3Rpb24oZSl7aWYoIXRoaXMuX3Byb3RvY29sc1tlXSl0aHJvdyBuZXcgRXJyb3IoJ3Vua25vd24gcHJvdG9jb2wgIicrZSsnIicpO3RoaXMuX2FjdGl2ZVByb3RvY29sPWUsdGhpcy5fb25Qcm90b2NvbENoYW5nZS5maXJlKHRoaXMuX3Byb3RvY29sc1tlXS5ldmVudHMpfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwiYXJlTW91c2VFdmVudHNBY3RpdmUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gMCE9PXRoaXMuX3Byb3RvY29sc1t0aGlzLl9hY3RpdmVQcm90b2NvbF0uZXZlbnRzfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwiYWN0aXZlRW5jb2RpbmciLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fYWN0aXZlRW5jb2Rpbmd9LHNldDpmdW5jdGlvbihlKXtpZighdGhpcy5fZW5jb2RpbmdzW2VdKXRocm93IG5ldyBFcnJvcigndW5rbm93biBlbmNvZGluZyAiJytlKyciJyk7dGhpcy5fYWN0aXZlRW5jb2Rpbmc9ZX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxlLnByb3RvdHlwZS5yZXNldD1mdW5jdGlvbigpe3RoaXMuYWN0aXZlUHJvdG9jb2w9Ik5PTkUiLHRoaXMuYWN0aXZlRW5jb2Rpbmc9IkRFRkFVTFQiLHRoaXMuX2xhc3RFdmVudD1udWxsfSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uUHJvdG9jb2xDaGFuZ2UiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25Qcm90b2NvbENoYW5nZS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxlLnByb3RvdHlwZS50cmlnZ2VyTW91c2VFdmVudD1mdW5jdGlvbihlKXtpZihlLmNvbDwwfHxlLmNvbD49dGhpcy5fYnVmZmVyU2VydmljZS5jb2xzfHxlLnJvdzwwfHxlLnJvdz49dGhpcy5fYnVmZmVyU2VydmljZS5yb3dzKXJldHVybiExO2lmKDQ9PT1lLmJ1dHRvbiYmMzI9PT1lLmFjdGlvbilyZXR1cm4hMTtpZigzPT09ZS5idXR0b24mJjMyIT09ZS5hY3Rpb24pcmV0dXJuITE7aWYoNCE9PWUuYnV0dG9uJiYoMj09PWUuYWN0aW9ufHwzPT09ZS5hY3Rpb24pKXJldHVybiExO2lmKGUuY29sKyssZS5yb3crKywzMj09PWUuYWN0aW9uJiZ0aGlzLl9sYXN0RXZlbnQmJnRoaXMuX2NvbXBhcmVFdmVudHModGhpcy5fbGFzdEV2ZW50LGUpKXJldHVybiExO2lmKCF0aGlzLl9wcm90b2NvbHNbdGhpcy5fYWN0aXZlUHJvdG9jb2xdLnJlc3RyaWN0KGUpKXJldHVybiExO3ZhciB0PXRoaXMuX2VuY29kaW5nc1t0aGlzLl9hY3RpdmVFbmNvZGluZ10oZSk7cmV0dXJuIHQmJigiREVGQVVMVCI9PT10aGlzLl9hY3RpdmVFbmNvZGluZz90aGlzLl9jb3JlU2VydmljZS50cmlnZ2VyQmluYXJ5RXZlbnQodCk6dGhpcy5fY29yZVNlcnZpY2UudHJpZ2dlckRhdGFFdmVudCh0LCEwKSksdGhpcy5fbGFzdEV2ZW50PWUsITB9LGUucHJvdG90eXBlLmV4cGxhaW5FdmVudHM9ZnVuY3Rpb24oZSl7cmV0dXJue2Rvd246ISEoMSZlKSx1cDohISgyJmUpLGRyYWc6ISEoNCZlKSxtb3ZlOiEhKDgmZSksd2hlZWw6ISEoMTYmZSl9fSxlLnByb3RvdHlwZS5fY29tcGFyZUV2ZW50cz1mdW5jdGlvbihlLHQpe3JldHVybiBlLmNvbD09PXQuY29sJiZlLnJvdz09PXQucm93JiZlLmJ1dHRvbj09PXQuYnV0dG9uJiZlLmFjdGlvbj09PXQuYWN0aW9uJiZlLmN0cmw9PT10LmN0cmwmJmUuYWx0PT09dC5hbHQmJmUuc2hpZnQ9PT10LnNoaWZ0fSxpKFtuKDAsby5JQnVmZmVyU2VydmljZSksbigxLG8uSUNvcmVTZXJ2aWNlKV0sZSl9KCk7dC5Db3JlTW91c2VTZXJ2aWNlPWh9LDY5NzU6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpLG49dGhpcyYmdGhpcy5fX2V4dGVuZHN8fChpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGk9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQscikmJihlW3JdPXRbcl0pfSxpKGUsdCl9LGZ1bmN0aW9uKGUsdCl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIkNsYXNzIGV4dGVuZHMgdmFsdWUgIitTdHJpbmcodCkrIiBpcyBub3QgYSBjb25zdHJ1Y3RvciBvciBudWxsIik7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1pKGUsdCksZS5wcm90b3R5cGU9bnVsbD09PXQ/T2JqZWN0LmNyZWF0ZSh0KTooci5wcm90b3R5cGU9dC5wcm90b3R5cGUsbmV3IHIpfSksbz10aGlzJiZ0aGlzLl9fZGVjb3JhdGV8fGZ1bmN0aW9uKGUsdCxyLGkpe3ZhciBuLG89YXJndW1lbnRzLmxlbmd0aCxzPW88Mz90Om51bGw9PT1pP2k9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0LHIpOmk7aWYoIm9iamVjdCI9PXR5cGVvZiBSZWZsZWN0JiYiZnVuY3Rpb24iPT10eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSlzPVJlZmxlY3QuZGVjb3JhdGUoZSx0LHIsaSk7ZWxzZSBmb3IodmFyIGE9ZS5sZW5ndGgtMTthPj0wO2EtLSkobj1lW2FdKSYmKHM9KG88Mz9uKHMpOm8+Mz9uKHQscixzKTpuKHQscikpfHxzKTtyZXR1cm4gbz4zJiZzJiZPYmplY3QuZGVmaW5lUHJvcGVydHkodCxyLHMpLHN9LHM9dGhpcyYmdGhpcy5fX3BhcmFtfHxmdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbihyLGkpe3QocixpLGUpfX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQ29yZVNlcnZpY2U9dm9pZCAwO3ZhciBhPXIoMjU4NSksYz1yKDg0NjApLGw9cigxNDM5KSx1PXIoODQ0KSxoPU9iamVjdC5mcmVlemUoe2luc2VydE1vZGU6ITF9KSxmPU9iamVjdC5mcmVlemUoe2FwcGxpY2F0aW9uQ3Vyc29yS2V5czohMSxhcHBsaWNhdGlvbktleXBhZDohMSxicmFja2V0ZWRQYXN0ZU1vZGU6ITEsb3JpZ2luOiExLHJldmVyc2VXcmFwYXJvdW5kOiExLHNlbmRGb2N1czohMSx3cmFwYXJvdW5kOiEwfSksXz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQscixpLG4pe3ZhciBvPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gby5fYnVmZmVyU2VydmljZT1yLG8uX2xvZ1NlcnZpY2U9aSxvLl9vcHRpb25zU2VydmljZT1uLG8uaXNDdXJzb3JJbml0aWFsaXplZD0hMSxvLmlzQ3Vyc29ySGlkZGVuPSExLG8uX29uRGF0YT1vLnJlZ2lzdGVyKG5ldyBjLkV2ZW50RW1pdHRlciksby5fb25Vc2VySW5wdXQ9by5yZWdpc3RlcihuZXcgYy5FdmVudEVtaXR0ZXIpLG8uX29uQmluYXJ5PW8ucmVnaXN0ZXIobmV3IGMuRXZlbnRFbWl0dGVyKSxvLl9zY3JvbGxUb0JvdHRvbT10LG8ucmVnaXN0ZXIoe2Rpc3Bvc2U6ZnVuY3Rpb24oKXtyZXR1cm4gby5fc2Nyb2xsVG9Cb3R0b209dm9pZCAwfX0pLG8ubW9kZXM9KDAsbC5jbG9uZSkoaCksby5kZWNQcml2YXRlTW9kZXM9KDAsbC5jbG9uZSkoZiksb31yZXR1cm4gbih0LGUpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25EYXRhIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uRGF0YS5ldmVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodC5wcm90b3R5cGUsIm9uVXNlcklucHV0Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uVXNlcklucHV0LmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib25CaW5hcnkiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25CaW5hcnkuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUucmVzZXQ9ZnVuY3Rpb24oKXt0aGlzLm1vZGVzPSgwLGwuY2xvbmUpKGgpLHRoaXMuZGVjUHJpdmF0ZU1vZGVzPSgwLGwuY2xvbmUpKGYpfSx0LnByb3RvdHlwZS50cmlnZ2VyRGF0YUV2ZW50PWZ1bmN0aW9uKGUsdCl7aWYodm9pZCAwPT09dCYmKHQ9ITEpLCF0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmRpc2FibGVTdGRpbil7dmFyIHI9dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXI7ci55YmFzZSE9PXIueWRpc3AmJnRoaXMuX3Njcm9sbFRvQm90dG9tKCksdCYmdGhpcy5fb25Vc2VySW5wdXQuZmlyZSgpLHRoaXMuX2xvZ1NlcnZpY2UuZGVidWcoJ3NlbmRpbmcgZGF0YSAiJytlKyciJywoZnVuY3Rpb24oKXtyZXR1cm4gZS5zcGxpdCgiIikubWFwKChmdW5jdGlvbihlKXtyZXR1cm4gZS5jaGFyQ29kZUF0KDApfSkpfSkpLHRoaXMuX29uRGF0YS5maXJlKGUpfX0sdC5wcm90b3R5cGUudHJpZ2dlckJpbmFyeUV2ZW50PWZ1bmN0aW9uKGUpe3RoaXMuX29wdGlvbnNTZXJ2aWNlLm9wdGlvbnMuZGlzYWJsZVN0ZGlufHwodGhpcy5fbG9nU2VydmljZS5kZWJ1Zygnc2VuZGluZyBiaW5hcnkgIicrZSsnIicsKGZ1bmN0aW9uKCl7cmV0dXJuIGUuc3BsaXQoIiIpLm1hcCgoZnVuY3Rpb24oZSl7cmV0dXJuIGUuY2hhckNvZGVBdCgwKX0pKX0pKSx0aGlzLl9vbkJpbmFyeS5maXJlKGUpKX0sbyhbcygxLGEuSUJ1ZmZlclNlcnZpY2UpLHMoMixhLklMb2dTZXJ2aWNlKSxzKDMsYS5JT3B0aW9uc1NlcnZpY2UpXSx0KX0odS5EaXNwb3NhYmxlKTt0LkNvcmVTZXJ2aWNlPV99LDM3MzA6ZnVuY3Rpb24oZSx0LHIpe3ZhciBpPXRoaXMmJnRoaXMuX19kZWNvcmF0ZXx8ZnVuY3Rpb24oZSx0LHIsaSl7dmFyIG4sbz1hcmd1bWVudHMubGVuZ3RoLHM9bzwzP3Q6bnVsbD09PWk/aT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHQscik6aTtpZigib2JqZWN0Ij09dHlwZW9mIFJlZmxlY3QmJiJmdW5jdGlvbiI9PXR5cGVvZiBSZWZsZWN0LmRlY29yYXRlKXM9UmVmbGVjdC5kZWNvcmF0ZShlLHQscixpKTtlbHNlIGZvcih2YXIgYT1lLmxlbmd0aC0xO2E+PTA7YS0tKShuPWVbYV0pJiYocz0obzwzP24ocyk6bz4zP24odCxyLHMpOm4odCxyKSl8fHMpO3JldHVybiBvPjMmJnMmJk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LHIscyksc30sbj10aGlzJiZ0aGlzLl9fcGFyYW18fGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIsaSl7dChyLGksZSl9fTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5EaXJ0eVJvd1NlcnZpY2U9dm9pZCAwO3ZhciBvPXIoMjU4NSkscz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy5fYnVmZmVyU2VydmljZT1lLHRoaXMuY2xlYXJSYW5nZSgpfXJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsInN0YXJ0Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3N0YXJ0fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwiZW5kIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2VuZH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxlLnByb3RvdHlwZS5jbGVhclJhbmdlPWZ1bmN0aW9uKCl7dGhpcy5fc3RhcnQ9dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueSx0aGlzLl9lbmQ9dGhpcy5fYnVmZmVyU2VydmljZS5idWZmZXIueX0sZS5wcm90b3R5cGUubWFya0RpcnR5PWZ1bmN0aW9uKGUpe2U8dGhpcy5fc3RhcnQ/dGhpcy5fc3RhcnQ9ZTplPnRoaXMuX2VuZCYmKHRoaXMuX2VuZD1lKX0sZS5wcm90b3R5cGUubWFya1JhbmdlRGlydHk9ZnVuY3Rpb24oZSx0KXtpZihlPnQpe3ZhciByPWU7ZT10LHQ9cn1lPHRoaXMuX3N0YXJ0JiYodGhpcy5fc3RhcnQ9ZSksdD50aGlzLl9lbmQmJih0aGlzLl9lbmQ9dCl9LGUucHJvdG90eXBlLm1hcmtBbGxEaXJ0eT1mdW5jdGlvbigpe3RoaXMubWFya1JhbmdlRGlydHkoMCx0aGlzLl9idWZmZXJTZXJ2aWNlLnJvd3MtMSl9LGkoW24oMCxvLklCdWZmZXJTZXJ2aWNlKV0sZSl9KCk7dC5EaXJ0eVJvd1NlcnZpY2U9c30sNDM0ODpmdW5jdGlvbihlLHQscil7dmFyIGk9dGhpcyYmdGhpcy5fX3NwcmVhZEFycmF5fHxmdW5jdGlvbihlLHQscil7aWYocnx8Mj09PWFyZ3VtZW50cy5sZW5ndGgpZm9yKHZhciBpLG49MCxvPXQubGVuZ3RoO248bztuKyspIWkmJm4gaW4gdHx8KGl8fChpPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHQsMCxuKSksaVtuXT10W25dKTtyZXR1cm4gZS5jb25jYXQoaXx8QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodCkpfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5JbnN0YW50aWF0aW9uU2VydmljZT10LlNlcnZpY2VDb2xsZWN0aW9uPXZvaWQgMDt2YXIgbj1yKDI1ODUpLG89cig4MzQzKSxzPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt0aGlzLl9lbnRyaWVzPW5ldyBNYXA7Zm9yKHZhciByPTAsaT1lO3I8aS5sZW5ndGg7cisrKXt2YXIgbj1pW3JdLG89blswXSxzPW5bMV07dGhpcy5zZXQobyxzKX19cmV0dXJuIGUucHJvdG90eXBlLnNldD1mdW5jdGlvbihlLHQpe3ZhciByPXRoaXMuX2VudHJpZXMuZ2V0KGUpO3JldHVybiB0aGlzLl9lbnRyaWVzLnNldChlLHQpLHJ9LGUucHJvdG90eXBlLmZvckVhY2g9ZnVuY3Rpb24oZSl7dGhpcy5fZW50cmllcy5mb3JFYWNoKChmdW5jdGlvbih0LHIpe3JldHVybiBlKHIsdCl9KSl9LGUucHJvdG90eXBlLmhhcz1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fZW50cmllcy5oYXMoZSl9LGUucHJvdG90eXBlLmdldD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fZW50cmllcy5nZXQoZSl9LGV9KCk7dC5TZXJ2aWNlQ29sbGVjdGlvbj1zO3ZhciBhPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMuX3NlcnZpY2VzPW5ldyBzLHRoaXMuX3NlcnZpY2VzLnNldChuLklJbnN0YW50aWF0aW9uU2VydmljZSx0aGlzKX1yZXR1cm4gZS5wcm90b3R5cGUuc2V0U2VydmljZT1mdW5jdGlvbihlLHQpe3RoaXMuX3NlcnZpY2VzLnNldChlLHQpfSxlLnByb3RvdHlwZS5nZXRTZXJ2aWNlPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9zZXJ2aWNlcy5nZXQoZSl9LGUucHJvdG90eXBlLmNyZWF0ZUluc3RhbmNlPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1bXSxyPTE7cjxhcmd1bWVudHMubGVuZ3RoO3IrKyl0W3ItMV09YXJndW1lbnRzW3JdO2Zvcih2YXIgbj0oMCxvLmdldFNlcnZpY2VEZXBlbmRlbmNpZXMpKGUpLnNvcnQoKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuaW5kZXgtdC5pbmRleH0pKSxzPVtdLGE9MCxjPW47YTxjLmxlbmd0aDthKyspe3ZhciBsPWNbYV0sdT10aGlzLl9zZXJ2aWNlcy5nZXQobC5pZCk7aWYoIXUpdGhyb3cgbmV3IEVycm9yKCJbY3JlYXRlSW5zdGFuY2VdICIrZS5uYW1lKyIgZGVwZW5kcyBvbiBVTktOT1dOIHNlcnZpY2UgIitsLmlkKyIuIik7cy5wdXNoKHUpfXZhciBoPW4ubGVuZ3RoPjA/blswXS5pbmRleDp0Lmxlbmd0aDtpZih0Lmxlbmd0aCE9PWgpdGhyb3cgbmV3IEVycm9yKCJbY3JlYXRlSW5zdGFuY2VdIEZpcnN0IHNlcnZpY2UgZGVwZW5kZW5jeSBvZiAiK2UubmFtZSsiIGF0IHBvc2l0aW9uICIrKGgrMSkrIiBjb25mbGljdHMgd2l0aCAiK3QubGVuZ3RoKyIgc3RhdGljIGFyZ3VtZW50cyIpO3JldHVybiBuZXcoZS5iaW5kLmFwcGx5KGUsaShbdm9pZCAwXSxpKGkoW10sdCwhMCkscywhMCksITEpKSl9LGV9KCk7dC5JbnN0YW50aWF0aW9uU2VydmljZT1hfSw3ODY2OmZ1bmN0aW9uKGUsdCxyKXt2YXIgaT10aGlzJiZ0aGlzLl9fZGVjb3JhdGV8fGZ1bmN0aW9uKGUsdCxyLGkpe3ZhciBuLG89YXJndW1lbnRzLmxlbmd0aCxzPW88Mz90Om51bGw9PT1pP2k9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0LHIpOmk7aWYoIm9iamVjdCI9PXR5cGVvZiBSZWZsZWN0JiYiZnVuY3Rpb24iPT10eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSlzPVJlZmxlY3QuZGVjb3JhdGUoZSx0LHIsaSk7ZWxzZSBmb3IodmFyIGE9ZS5sZW5ndGgtMTthPj0wO2EtLSkobj1lW2FdKSYmKHM9KG88Mz9uKHMpOm8+Mz9uKHQscixzKTpuKHQscikpfHxzKTtyZXR1cm4gbz4zJiZzJiZPYmplY3QuZGVmaW5lUHJvcGVydHkodCxyLHMpLHN9LG49dGhpcyYmdGhpcy5fX3BhcmFtfHxmdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbihyLGkpe3QocixpLGUpfX0sbz10aGlzJiZ0aGlzLl9fc3ByZWFkQXJyYXl8fGZ1bmN0aW9uKGUsdCxyKXtpZihyfHwyPT09YXJndW1lbnRzLmxlbmd0aClmb3IodmFyIGksbj0wLG89dC5sZW5ndGg7bjxvO24rKykhaSYmbiBpbiB0fHwoaXx8KGk9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodCwwLG4pKSxpW25dPXRbbl0pO3JldHVybiBlLmNvbmNhdChpfHxBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0KSl9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkxvZ1NlcnZpY2U9dm9pZCAwO3ZhciBzPXIoMjU4NSksYT17ZGVidWc6cy5Mb2dMZXZlbEVudW0uREVCVUcsaW5mbzpzLkxvZ0xldmVsRW51bS5JTkZPLHdhcm46cy5Mb2dMZXZlbEVudW0uV0FSTixlcnJvcjpzLkxvZ0xldmVsRW51bS5FUlJPUixvZmY6cy5Mb2dMZXZlbEVudW0uT0ZGfSxjPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt2YXIgdD10aGlzO3RoaXMuX29wdGlvbnNTZXJ2aWNlPWUsdGhpcy5sb2dMZXZlbD1zLkxvZ0xldmVsRW51bS5PRkYsdGhpcy5fdXBkYXRlTG9nTGV2ZWwoKSx0aGlzLl9vcHRpb25zU2VydmljZS5vbk9wdGlvbkNoYW5nZSgoZnVuY3Rpb24oZSl7ImxvZ0xldmVsIj09PWUmJnQuX3VwZGF0ZUxvZ0xldmVsKCl9KSl9cmV0dXJuIGUucHJvdG90eXBlLl91cGRhdGVMb2dMZXZlbD1mdW5jdGlvbigpe3RoaXMubG9nTGV2ZWw9YVt0aGlzLl9vcHRpb25zU2VydmljZS5vcHRpb25zLmxvZ0xldmVsXX0sZS5wcm90b3R5cGUuX2V2YWxMYXp5T3B0aW9uYWxQYXJhbXM9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTA7dDxlLmxlbmd0aDt0KyspImZ1bmN0aW9uIj09dHlwZW9mIGVbdF0mJihlW3RdPWVbdF0oKSl9LGUucHJvdG90eXBlLl9sb2c9ZnVuY3Rpb24oZSx0LHIpe3RoaXMuX2V2YWxMYXp5T3B0aW9uYWxQYXJhbXMociksZS5jYWxsLmFwcGx5KGUsbyhbY29uc29sZSwieHRlcm0uanM6ICIrdF0sciwhMSkpfSxlLnByb3RvdHlwZS5kZWJ1Zz1mdW5jdGlvbihlKXtmb3IodmFyIHQ9W10scj0xO3I8YXJndW1lbnRzLmxlbmd0aDtyKyspdFtyLTFdPWFyZ3VtZW50c1tyXTt0aGlzLmxvZ0xldmVsPD1zLkxvZ0xldmVsRW51bS5ERUJVRyYmdGhpcy5fbG9nKGNvbnNvbGUubG9nLGUsdCl9LGUucHJvdG90eXBlLmluZm89ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PVtdLHI9MTtyPGFyZ3VtZW50cy5sZW5ndGg7cisrKXRbci0xXT1hcmd1bWVudHNbcl07dGhpcy5sb2dMZXZlbDw9cy5Mb2dMZXZlbEVudW0uSU5GTyYmdGhpcy5fbG9nKGNvbnNvbGUuaW5mbyxlLHQpfSxlLnByb3RvdHlwZS53YXJuPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1bXSxyPTE7cjxhcmd1bWVudHMubGVuZ3RoO3IrKyl0W3ItMV09YXJndW1lbnRzW3JdO3RoaXMubG9nTGV2ZWw8PXMuTG9nTGV2ZWxFbnVtLldBUk4mJnRoaXMuX2xvZyhjb25zb2xlLndhcm4sZSx0KX0sZS5wcm90b3R5cGUuZXJyb3I9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PVtdLHI9MTtyPGFyZ3VtZW50cy5sZW5ndGg7cisrKXRbci0xXT1hcmd1bWVudHNbcl07dGhpcy5sb2dMZXZlbDw9cy5Mb2dMZXZlbEVudW0uRVJST1ImJnRoaXMuX2xvZyhjb25zb2xlLmVycm9yLGUsdCl9LGkoW24oMCxzLklPcHRpb25zU2VydmljZSldLGUpfSgpO3QuTG9nU2VydmljZT1jfSw3MzAyOmZ1bmN0aW9uKGUsdCxyKXt2YXIgaT10aGlzJiZ0aGlzLl9fYXNzaWdufHxmdW5jdGlvbigpe3JldHVybiBpPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxyPTEsaT1hcmd1bWVudHMubGVuZ3RoO3I8aTtyKyspZm9yKHZhciBuIGluIHQ9YXJndW1lbnRzW3JdKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LG4pJiYoZVtuXT10W25dKTtyZXR1cm4gZX0saS5hcHBseSh0aGlzLGFyZ3VtZW50cyl9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0Lk9wdGlvbnNTZXJ2aWNlPXQuREVGQVVMVF9PUFRJT05TPXQuREVGQVVMVF9CRUxMX1NPVU5EPXZvaWQgMDt2YXIgbj1yKDg0NjApLG89cig2MTE0KTt0LkRFRkFVTFRfQkVMTF9TT1VORD0iZGF0YTphdWRpby9tcDM7YmFzZTY0LFNVUXpCQUFBQUFBQUkxUlRVMFVBQUFBUEFBQURUR0YyWmpVNExqTXlMakV3TkFBQUFBQUFBQUFBQUFBQS8vdFF4QUFEQjhBaFNteGhJSUVWQ1NpSnJEQ1FCVGN1M1VyQUl3VWRrUmdRYkZBWkMxQ1FFd1RKOW1qUnZCQTRVT0xEOG5LVk9XZmgrVWxLM3ovMTc3T1hyZk9kS2w3cHluM1hmLy9XcmV5VFJVb0FXZ0Jna09BR2JaSEJnRzFPRjZ6TTgyRFdiWmFVbU1CcHRnUWhHanN5WXFjOWFlOVhGejI4MDk0OE5NQldJbmxqeXpzTlJGTFBXZG5aR1dyZGREc2pLMXVudVNyVk45akpzSzhLdVF0UUN0TUJqQ0V0SW1JU2ROS0pPb3BJcEJGcE5TTWJJSENTUnBSUjVpYWtqVGl5ekxoY2hVVUJ3Q2d5S2l3ZUJ2LzdVc1FiZzhpc1ZOb01QTWpBQUFBMGdBQUFCRVZGR21ncUsvLy8vOWJQLzZYQ3lreEJUVVV6TGpFd01LcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXEiLHQuREVGQVVMVF9PUFRJT05TPXtjb2xzOjgwLHJvd3M6MjQsY3Vyc29yQmxpbms6ITEsY3Vyc29yU3R5bGU6ImJsb2NrIixjdXJzb3JXaWR0aDoxLGN1c3RvbUdseXBoczohMCxiZWxsU291bmQ6dC5ERUZBVUxUX0JFTExfU09VTkQsYmVsbFN0eWxlOiJub25lIixkcmF3Qm9sZFRleHRJbkJyaWdodENvbG9yczohMCxmYXN0U2Nyb2xsTW9kaWZpZXI6ImFsdCIsZmFzdFNjcm9sbFNlbnNpdGl2aXR5OjUsZm9udEZhbWlseToiY291cmllci1uZXcsIGNvdXJpZXIsIG1vbm9zcGFjZSIsZm9udFNpemU6MTUsZm9udFdlaWdodDoibm9ybWFsIixmb250V2VpZ2h0Qm9sZDoiYm9sZCIsbGluZUhlaWdodDoxLGxpbmtUb29sdGlwSG92ZXJEdXJhdGlvbjo1MDAsbGV0dGVyU3BhY2luZzowLGxvZ0xldmVsOiJpbmZvIixzY3JvbGxiYWNrOjFlMyxzY3JvbGxTZW5zaXRpdml0eToxLHNjcmVlblJlYWRlck1vZGU6ITEsbWFjT3B0aW9uSXNNZXRhOiExLG1hY09wdGlvbkNsaWNrRm9yY2VzU2VsZWN0aW9uOiExLG1pbmltdW1Db250cmFzdFJhdGlvOjEsZGlzYWJsZVN0ZGluOiExLGFsbG93UHJvcG9zZWRBcGk6ITAsYWxsb3dUcmFuc3BhcmVuY3k6ITEsdGFiU3RvcFdpZHRoOjgsdGhlbWU6e30scmlnaHRDbGlja1NlbGVjdHNXb3JkOm8uaXNNYWMscmVuZGVyZXJUeXBlOiJjYW52YXMiLHdpbmRvd09wdGlvbnM6e30sd2luZG93c01vZGU6ITEsd29yZFNlcGFyYXRvcjoiICgpW117fScsXCJgIixhbHRDbGlja01vdmVzQ3Vyc29yOiEwLGNvbnZlcnRFb2w6ITEsdGVybU5hbWU6Inh0ZXJtIixjYW5jZWxFdmVudHM6ITF9O3ZhciBzPVsibm9ybWFsIiwiYm9sZCIsIjEwMCIsIjIwMCIsIjMwMCIsIjQwMCIsIjUwMCIsIjYwMCIsIjcwMCIsIjgwMCIsIjkwMCJdLGE9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe2Zvcih2YXIgciBpbiB0aGlzLl9vbk9wdGlvbkNoYW5nZT1uZXcgbi5FdmVudEVtaXR0ZXIsdGhpcy5fb3B0aW9ucz1pKHt9LHQuREVGQVVMVF9PUFRJT05TKSxlKWlmKHIgaW4gdGhpcy5fb3B0aW9ucyl0cnl7dmFyIG89ZVtyXTt0aGlzLl9vcHRpb25zW3JdPXRoaXMuX3Nhbml0aXplQW5kVmFsaWRhdGVPcHRpb24ocixvKX1jYXRjaChlKXtjb25zb2xlLmVycm9yKGUpfXRoaXMub3B0aW9ucz10aGlzLl9zZXR1cE9wdGlvbnModGhpcy5fb3B0aW9ucyl9cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwib25PcHRpb25DaGFuZ2UiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fb25PcHRpb25DaGFuZ2UuZXZlbnR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksZS5wcm90b3R5cGUuX3NldHVwT3B0aW9ucz1mdW5jdGlvbihlKXt2YXIgcj10aGlzLG49aSh7fSxlKSxvPWZ1bmN0aW9uKGUpe09iamVjdC5kZWZpbmVQcm9wZXJ0eShuLGUse2dldDpmdW5jdGlvbigpe2lmKCEoZSBpbiB0LkRFRkFVTFRfT1BUSU9OUykpdGhyb3cgbmV3IEVycm9yKCdObyBvcHRpb24gd2l0aCBrZXkgIicrZSsnIicpO3JldHVybiByLl9vcHRpb25zW2VdfSxzZXQ6ZnVuY3Rpb24oaSl7aWYoIShlIGluIHQuREVGQVVMVF9PUFRJT05TKSl0aHJvdyBuZXcgRXJyb3IoJ05vIG9wdGlvbiB3aXRoIGtleSAiJytlKyciJyk7aT1yLl9zYW5pdGl6ZUFuZFZhbGlkYXRlT3B0aW9uKGUsaSksci5fb3B0aW9uc1tlXSE9PWkmJihyLl9vcHRpb25zW2VdPWksci5fb25PcHRpb25DaGFuZ2UuZmlyZShlKSl9fSl9O2Zvcih2YXIgcyBpbiBuKW8ocyk7cmV0dXJuIG59LGUucHJvdG90eXBlLnNldE9wdGlvbj1mdW5jdGlvbihlLHQpe3RoaXMub3B0aW9uc1tlXT10fSxlLnByb3RvdHlwZS5fc2FuaXRpemVBbmRWYWxpZGF0ZU9wdGlvbj1mdW5jdGlvbihlLHIpe3N3aXRjaChlKXtjYXNlImJlbGxTdHlsZSI6Y2FzZSJjdXJzb3JTdHlsZSI6Y2FzZSJyZW5kZXJlclR5cGUiOmNhc2Uid29yZFNlcGFyYXRvciI6cnx8KHI9dC5ERUZBVUxUX09QVElPTlNbZV0pO2JyZWFrO2Nhc2UiZm9udFdlaWdodCI6Y2FzZSJmb250V2VpZ2h0Qm9sZCI6aWYoIm51bWJlciI9PXR5cGVvZiByJiYxPD1yJiZyPD0xZTMpYnJlYWs7cj1zLmluY2x1ZGVzKHIpP3I6dC5ERUZBVUxUX09QVElPTlNbZV07YnJlYWs7Y2FzZSJjdXJzb3JXaWR0aCI6cj1NYXRoLmZsb29yKHIpO2Nhc2UibGluZUhlaWdodCI6Y2FzZSJ0YWJTdG9wV2lkdGgiOmlmKHI8MSl0aHJvdyBuZXcgRXJyb3IoZSsiIGNhbm5vdCBiZSBsZXNzIHRoYW4gMSwgdmFsdWU6ICIrcik7YnJlYWs7Y2FzZSJtaW5pbXVtQ29udHJhc3RSYXRpbyI6cj1NYXRoLm1heCgxLE1hdGgubWluKDIxLE1hdGgucm91bmQoMTAqcikvMTApKTticmVhaztjYXNlInNjcm9sbGJhY2siOmlmKChyPU1hdGgubWluKHIsNDI5NDk2NzI5NSkpPDApdGhyb3cgbmV3IEVycm9yKGUrIiBjYW5ub3QgYmUgbGVzcyB0aGFuIDAsIHZhbHVlOiAiK3IpO2JyZWFrO2Nhc2UiZmFzdFNjcm9sbFNlbnNpdGl2aXR5IjpjYXNlInNjcm9sbFNlbnNpdGl2aXR5IjppZihyPD0wKXRocm93IG5ldyBFcnJvcihlKyIgY2Fubm90IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byAwLCB2YWx1ZTogIityKTtjYXNlInJvd3MiOmNhc2UiY29scyI6aWYoIXImJjAhPT1yKXRocm93IG5ldyBFcnJvcihlKyIgbXVzdCBiZSBudW1lcmljLCB2YWx1ZTogIityKX1yZXR1cm4gcn0sZS5wcm90b3R5cGUuZ2V0T3B0aW9uPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLm9wdGlvbnNbZV19LGV9KCk7dC5PcHRpb25zU2VydmljZT1hfSw4MzQzOihlLHQpPT57ZnVuY3Rpb24gcihlLHQscil7dC5kaSR0YXJnZXQ9PT10P3QuZGkkZGVwZW5kZW5jaWVzLnB1c2goe2lkOmUsaW5kZXg6cn0pOih0LmRpJGRlcGVuZGVuY2llcz1be2lkOmUsaW5kZXg6cn1dLHQuZGkkdGFyZ2V0PXQpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmNyZWF0ZURlY29yYXRvcj10LmdldFNlcnZpY2VEZXBlbmRlbmNpZXM9dC5zZXJ2aWNlUmVnaXN0cnk9dm9pZCAwLHQuc2VydmljZVJlZ2lzdHJ5PW5ldyBNYXAsdC5nZXRTZXJ2aWNlRGVwZW5kZW5jaWVzPWZ1bmN0aW9uKGUpe3JldHVybiBlLmRpJGRlcGVuZGVuY2llc3x8W119LHQuY3JlYXRlRGVjb3JhdG9yPWZ1bmN0aW9uKGUpe2lmKHQuc2VydmljZVJlZ2lzdHJ5LmhhcyhlKSlyZXR1cm4gdC5zZXJ2aWNlUmVnaXN0cnkuZ2V0KGUpO3ZhciBpPWZ1bmN0aW9uKGUsdCxuKXtpZigzIT09YXJndW1lbnRzLmxlbmd0aCl0aHJvdyBuZXcgRXJyb3IoIkBJU2VydmljZU5hbWUtZGVjb3JhdG9yIGNhbiBvbmx5IGJlIHVzZWQgdG8gZGVjb3JhdGUgYSBwYXJhbWV0ZXIiKTtyKGksZSxuKX07cmV0dXJuIGkudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gZX0sdC5zZXJ2aWNlUmVnaXN0cnkuc2V0KGUsaSksaX19LDI1ODU6KGUsdCxyKT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LklVbmljb2RlU2VydmljZT10LklPcHRpb25zU2VydmljZT10LklMb2dTZXJ2aWNlPXQuTG9nTGV2ZWxFbnVtPXQuSUluc3RhbnRpYXRpb25TZXJ2aWNlPXQuSURpcnR5Um93U2VydmljZT10LklDaGFyc2V0U2VydmljZT10LklDb3JlU2VydmljZT10LklDb3JlTW91c2VTZXJ2aWNlPXQuSUJ1ZmZlclNlcnZpY2U9dm9pZCAwO3ZhciBpLG49cig4MzQzKTt0LklCdWZmZXJTZXJ2aWNlPSgwLG4uY3JlYXRlRGVjb3JhdG9yKSgiQnVmZmVyU2VydmljZSIpLHQuSUNvcmVNb3VzZVNlcnZpY2U9KDAsbi5jcmVhdGVEZWNvcmF0b3IpKCJDb3JlTW91c2VTZXJ2aWNlIiksdC5JQ29yZVNlcnZpY2U9KDAsbi5jcmVhdGVEZWNvcmF0b3IpKCJDb3JlU2VydmljZSIpLHQuSUNoYXJzZXRTZXJ2aWNlPSgwLG4uY3JlYXRlRGVjb3JhdG9yKSgiQ2hhcnNldFNlcnZpY2UiKSx0LklEaXJ0eVJvd1NlcnZpY2U9KDAsbi5jcmVhdGVEZWNvcmF0b3IpKCJEaXJ0eVJvd1NlcnZpY2UiKSx0LklJbnN0YW50aWF0aW9uU2VydmljZT0oMCxuLmNyZWF0ZURlY29yYXRvcikoIkluc3RhbnRpYXRpb25TZXJ2aWNlIiksKGk9dC5Mb2dMZXZlbEVudW18fCh0LkxvZ0xldmVsRW51bT17fSkpW2kuREVCVUc9MF09IkRFQlVHIixpW2kuSU5GTz0xXT0iSU5GTyIsaVtpLldBUk49Ml09IldBUk4iLGlbaS5FUlJPUj0zXT0iRVJST1IiLGlbaS5PRkY9NF09Ik9GRiIsdC5JTG9nU2VydmljZT0oMCxuLmNyZWF0ZURlY29yYXRvcikoIkxvZ1NlcnZpY2UiKSx0LklPcHRpb25zU2VydmljZT0oMCxuLmNyZWF0ZURlY29yYXRvcikoIk9wdGlvbnNTZXJ2aWNlIiksdC5JVW5pY29kZVNlcnZpY2U9KDAsbi5jcmVhdGVEZWNvcmF0b3IpKCJVbmljb2RlU2VydmljZSIpfSwxNDgwOihlLHQscik9PntPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Vbmljb2RlU2VydmljZT12b2lkIDA7dmFyIGk9cig4NDYwKSxuPXIoMjI1KSxvPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMuX3Byb3ZpZGVycz1PYmplY3QuY3JlYXRlKG51bGwpLHRoaXMuX2FjdGl2ZT0iIix0aGlzLl9vbkNoYW5nZT1uZXcgaS5FdmVudEVtaXR0ZXI7dmFyIGU9bmV3IG4uVW5pY29kZVY2O3RoaXMucmVnaXN0ZXIoZSksdGhpcy5fYWN0aXZlPWUudmVyc2lvbix0aGlzLl9hY3RpdmVQcm92aWRlcj1lfXJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uQ2hhbmdlIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX29uQ2hhbmdlLmV2ZW50fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwidmVyc2lvbnMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gT2JqZWN0LmtleXModGhpcy5fcHJvdmlkZXJzKX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImFjdGl2ZVZlcnNpb24iLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fYWN0aXZlfSxzZXQ6ZnVuY3Rpb24oZSl7aWYoIXRoaXMuX3Byb3ZpZGVyc1tlXSl0aHJvdyBuZXcgRXJyb3IoJ3Vua25vd24gVW5pY29kZSB2ZXJzaW9uICInK2UrJyInKTt0aGlzLl9hY3RpdmU9ZSx0aGlzLl9hY3RpdmVQcm92aWRlcj10aGlzLl9wcm92aWRlcnNbZV0sdGhpcy5fb25DaGFuZ2UuZmlyZShlKX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxlLnByb3RvdHlwZS5yZWdpc3Rlcj1mdW5jdGlvbihlKXt0aGlzLl9wcm92aWRlcnNbZS52ZXJzaW9uXT1lfSxlLnByb3RvdHlwZS53Y3dpZHRoPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9hY3RpdmVQcm92aWRlci53Y3dpZHRoKGUpfSxlLnByb3RvdHlwZS5nZXRTdHJpbmdDZWxsV2lkdGg9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTAscj1lLmxlbmd0aCxpPTA7aTxyOysraSl7dmFyIG49ZS5jaGFyQ29kZUF0KGkpO2lmKDU1Mjk2PD1uJiZuPD01NjMxOSl7aWYoKytpPj1yKXJldHVybiB0K3RoaXMud2N3aWR0aChuKTt2YXIgbz1lLmNoYXJDb2RlQXQoaSk7NTYzMjA8PW8mJm88PTU3MzQzP249MTAyNCoobi01NTI5Nikrby01NjMyMCs2NTUzNjp0Kz10aGlzLndjd2lkdGgobyl9dCs9dGhpcy53Y3dpZHRoKG4pfXJldHVybiB0fSxlfSgpO3QuVW5pY29kZVNlcnZpY2U9b319LHQ9e307ZnVuY3Rpb24gcihpKXt2YXIgbj10W2ldO2lmKHZvaWQgMCE9PW4pcmV0dXJuIG4uZXhwb3J0czt2YXIgbz10W2ldPXtleHBvcnRzOnt9fTtyZXR1cm4gZVtpXS5jYWxsKG8uZXhwb3J0cyxvLG8uZXhwb3J0cyxyKSxvLmV4cG9ydHN9dmFyIGk9e307cmV0dXJuKCgpPT57dmFyIGU9aTtPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksZS5UZXJtaW5hbD12b2lkIDA7dmFyIHQ9cigzMjM2KSxuPXIoOTA0Miksbz1yKDc5NzUpLHM9cig3MDkwKSxhPXIoNTc0MSksYz1yKDgyODUpLGw9WyJjb2xzIiwicm93cyJdLHU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3ZhciByPXRoaXM7dGhpcy5fY29yZT1uZXcgdC5UZXJtaW5hbChlKSx0aGlzLl9hZGRvbk1hbmFnZXI9bmV3IGEuQWRkb25NYW5hZ2VyLHRoaXMuX3B1YmxpY09wdGlvbnM9e307dmFyIGk9ZnVuY3Rpb24oZSl7T2JqZWN0LmRlZmluZVByb3BlcnR5KG4uX3B1YmxpY09wdGlvbnMsZSx7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIuX2NvcmUub3B0aW9uc1tlXX0sc2V0OmZ1bmN0aW9uKHQpe3IuX2NoZWNrUmVhZG9ubHlPcHRpb25zKGUpLHIuX2NvcmUub3B0aW9uc1tlXT10fX0pfSxuPXRoaXM7Zm9yKHZhciBvIGluIHRoaXMuX2NvcmUub3B0aW9ucylpKG8pfXJldHVybiBlLnByb3RvdHlwZS5fY2hlY2tSZWFkb25seU9wdGlvbnM9ZnVuY3Rpb24oZSl7aWYobC5pbmNsdWRlcyhlKSl0aHJvdyBuZXcgRXJyb3IoJ09wdGlvbiAiJytlKyciIGNhbiBvbmx5IGJlIHNldCBpbiB0aGUgY29uc3RydWN0b3InKX0sZS5wcm90b3R5cGUuX2NoZWNrUHJvcG9zZWRBcGk9ZnVuY3Rpb24oKXtpZighdGhpcy5fY29yZS5vcHRpb25zU2VydmljZS5vcHRpb25zLmFsbG93UHJvcG9zZWRBcGkpdGhyb3cgbmV3IEVycm9yKCJZb3UgbXVzdCBzZXQgdGhlIGFsbG93UHJvcG9zZWRBcGkgb3B0aW9uIHRvIHRydWUgdG8gdXNlIHByb3Bvc2VkIEFQSSIpfSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uQmVsbCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLm9uQmVsbH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uQmluYXJ5Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2NvcmUub25CaW5hcnl9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJvbkN1cnNvck1vdmUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fY29yZS5vbkN1cnNvck1vdmV9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJvbkRhdGEiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fY29yZS5vbkRhdGF9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJvbktleSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLm9uS2V5fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwib25MaW5lRmVlZCIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLm9uTGluZUZlZWR9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJvblJlbmRlciIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLm9uUmVuZGVyfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwib25SZXNpemUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fY29yZS5vblJlc2l6ZX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsIm9uU2Nyb2xsIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2NvcmUub25TY3JvbGx9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJvblNlbGVjdGlvbkNoYW5nZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLm9uU2VsZWN0aW9uQ2hhbmdlfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwib25UaXRsZUNoYW5nZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLm9uVGl0bGVDaGFuZ2V9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJlbGVtZW50Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2NvcmUuZWxlbWVudH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsInBhcnNlciIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9jaGVja1Byb3Bvc2VkQXBpKCksdGhpcy5fcGFyc2VyfHwodGhpcy5fcGFyc2VyPW5ldyBvLlBhcnNlckFwaSh0aGlzLl9jb3JlKSksdGhpcy5fcGFyc2VyfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwidW5pY29kZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9jaGVja1Byb3Bvc2VkQXBpKCksbmV3IHMuVW5pY29kZUFwaSh0aGlzLl9jb3JlKX0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsInRleHRhcmVhIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2NvcmUudGV4dGFyZWF9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJyb3dzIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2NvcmUucm93c30sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wcm90b3R5cGUsImNvbHMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fY29yZS5jb2xzfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwiYnVmZmVyIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2NoZWNrUHJvcG9zZWRBcGkoKSx0aGlzLl9idWZmZXJ8fCh0aGlzLl9idWZmZXI9bmV3IGMuQnVmZmVyTmFtZXNwYWNlQXBpKHRoaXMuX2NvcmUpKSx0aGlzLl9idWZmZXJ9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJtYXJrZXJzIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2NoZWNrUHJvcG9zZWRBcGkoKSx0aGlzLl9jb3JlLm1hcmtlcnN9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJtb2RlcyIse2dldDpmdW5jdGlvbigpe3ZhciBlPXRoaXMuX2NvcmUuY29yZVNlcnZpY2UuZGVjUHJpdmF0ZU1vZGVzLHQ9Im5vbmUiO3N3aXRjaCh0aGlzLl9jb3JlLmNvcmVNb3VzZVNlcnZpY2UuYWN0aXZlUHJvdG9jb2wpe2Nhc2UiWDEwIjp0PSJ4MTAiO2JyZWFrO2Nhc2UiVlQyMDAiOnQ9InZ0MjAwIjticmVhaztjYXNlIkRSQUciOnQ9ImRyYWciO2JyZWFrO2Nhc2UiQU5ZIjp0PSJhbnkifXJldHVybnthcHBsaWNhdGlvbkN1cnNvcktleXNNb2RlOmUuYXBwbGljYXRpb25DdXJzb3JLZXlzLGFwcGxpY2F0aW9uS2V5cGFkTW9kZTplLmFwcGxpY2F0aW9uS2V5cGFkLGJyYWNrZXRlZFBhc3RlTW9kZTplLmJyYWNrZXRlZFBhc3RlTW9kZSxpbnNlcnRNb2RlOnRoaXMuX2NvcmUuY29yZVNlcnZpY2UubW9kZXMuaW5zZXJ0TW9kZSxtb3VzZVRyYWNraW5nTW9kZTp0LG9yaWdpbk1vZGU6ZS5vcmlnaW4scmV2ZXJzZVdyYXBhcm91bmRNb2RlOmUucmV2ZXJzZVdyYXBhcm91bmQsc2VuZEZvY3VzTW9kZTplLnNlbmRGb2N1cyx3cmFwYXJvdW5kTW9kZTplLndyYXBhcm91bmR9fSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLnByb3RvdHlwZSwib3B0aW9ucyIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9wdWJsaWNPcHRpb25zfSxzZXQ6ZnVuY3Rpb24oZSl7Zm9yKHZhciB0IGluIGUpdGhpcy5fcHVibGljT3B0aW9uc1t0XT1lW3RdfSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLmJsdXI9ZnVuY3Rpb24oKXt0aGlzLl9jb3JlLmJsdXIoKX0sZS5wcm90b3R5cGUuZm9jdXM9ZnVuY3Rpb24oKXt0aGlzLl9jb3JlLmZvY3VzKCl9LGUucHJvdG90eXBlLnJlc2l6ZT1mdW5jdGlvbihlLHQpe3RoaXMuX3ZlcmlmeUludGVnZXJzKGUsdCksdGhpcy5fY29yZS5yZXNpemUoZSx0KX0sZS5wcm90b3R5cGUub3Blbj1mdW5jdGlvbihlKXt0aGlzLl9jb3JlLm9wZW4oZSl9LGUucHJvdG90eXBlLmF0dGFjaEN1c3RvbUtleUV2ZW50SGFuZGxlcj1mdW5jdGlvbihlKXt0aGlzLl9jb3JlLmF0dGFjaEN1c3RvbUtleUV2ZW50SGFuZGxlcihlKX0sZS5wcm90b3R5cGUucmVnaXN0ZXJMaW5rTWF0Y2hlcj1mdW5jdGlvbihlLHQscil7cmV0dXJuIHRoaXMuX2NoZWNrUHJvcG9zZWRBcGkoKSx0aGlzLl9jb3JlLnJlZ2lzdGVyTGlua01hdGNoZXIoZSx0LHIpfSxlLnByb3RvdHlwZS5kZXJlZ2lzdGVyTGlua01hdGNoZXI9ZnVuY3Rpb24oZSl7dGhpcy5fY2hlY2tQcm9wb3NlZEFwaSgpLHRoaXMuX2NvcmUuZGVyZWdpc3RlckxpbmtNYXRjaGVyKGUpfSxlLnByb3RvdHlwZS5yZWdpc3RlckxpbmtQcm92aWRlcj1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fY2hlY2tQcm9wb3NlZEFwaSgpLHRoaXMuX2NvcmUucmVnaXN0ZXJMaW5rUHJvdmlkZXIoZSl9LGUucHJvdG90eXBlLnJlZ2lzdGVyQ2hhcmFjdGVySm9pbmVyPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9jaGVja1Byb3Bvc2VkQXBpKCksdGhpcy5fY29yZS5yZWdpc3RlckNoYXJhY3RlckpvaW5lcihlKX0sZS5wcm90b3R5cGUuZGVyZWdpc3RlckNoYXJhY3RlckpvaW5lcj1mdW5jdGlvbihlKXt0aGlzLl9jaGVja1Byb3Bvc2VkQXBpKCksdGhpcy5fY29yZS5kZXJlZ2lzdGVyQ2hhcmFjdGVySm9pbmVyKGUpfSxlLnByb3RvdHlwZS5yZWdpc3Rlck1hcmtlcj1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fY2hlY2tQcm9wb3NlZEFwaSgpLHRoaXMuX3ZlcmlmeUludGVnZXJzKGUpLHRoaXMuX2NvcmUuYWRkTWFya2VyKGUpfSxlLnByb3RvdHlwZS5hZGRNYXJrZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMucmVnaXN0ZXJNYXJrZXIoZSl9LGUucHJvdG90eXBlLmhhc1NlbGVjdGlvbj1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLmhhc1NlbGVjdGlvbigpfSxlLnByb3RvdHlwZS5zZWxlY3Q9ZnVuY3Rpb24oZSx0LHIpe3RoaXMuX3ZlcmlmeUludGVnZXJzKGUsdCxyKSx0aGlzLl9jb3JlLnNlbGVjdChlLHQscil9LGUucHJvdG90eXBlLmdldFNlbGVjdGlvbj1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLmdldFNlbGVjdGlvbigpfSxlLnByb3RvdHlwZS5nZXRTZWxlY3Rpb25Qb3NpdGlvbj1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9jb3JlLmdldFNlbGVjdGlvblBvc2l0aW9uKCl9LGUucHJvdG90eXBlLmNsZWFyU2VsZWN0aW9uPWZ1bmN0aW9uKCl7dGhpcy5fY29yZS5jbGVhclNlbGVjdGlvbigpfSxlLnByb3RvdHlwZS5zZWxlY3RBbGw9ZnVuY3Rpb24oKXt0aGlzLl9jb3JlLnNlbGVjdEFsbCgpfSxlLnByb3RvdHlwZS5zZWxlY3RMaW5lcz1mdW5jdGlvbihlLHQpe3RoaXMuX3ZlcmlmeUludGVnZXJzKGUsdCksdGhpcy5fY29yZS5zZWxlY3RMaW5lcyhlLHQpfSxlLnByb3RvdHlwZS5kaXNwb3NlPWZ1bmN0aW9uKCl7dGhpcy5fYWRkb25NYW5hZ2VyLmRpc3Bvc2UoKSx0aGlzLl9jb3JlLmRpc3Bvc2UoKX0sZS5wcm90b3R5cGUuc2Nyb2xsTGluZXM9ZnVuY3Rpb24oZSl7dGhpcy5fdmVyaWZ5SW50ZWdlcnMoZSksdGhpcy5fY29yZS5zY3JvbGxMaW5lcyhlKX0sZS5wcm90b3R5cGUuc2Nyb2xsUGFnZXM9ZnVuY3Rpb24oZSl7dGhpcy5fdmVyaWZ5SW50ZWdlcnMoZSksdGhpcy5fY29yZS5zY3JvbGxQYWdlcyhlKX0sZS5wcm90b3R5cGUuc2Nyb2xsVG9Ub3A9ZnVuY3Rpb24oKXt0aGlzLl9jb3JlLnNjcm9sbFRvVG9wKCl9LGUucHJvdG90eXBlLnNjcm9sbFRvQm90dG9tPWZ1bmN0aW9uKCl7dGhpcy5fY29yZS5zY3JvbGxUb0JvdHRvbSgpfSxlLnByb3RvdHlwZS5zY3JvbGxUb0xpbmU9ZnVuY3Rpb24oZSl7dGhpcy5fdmVyaWZ5SW50ZWdlcnMoZSksdGhpcy5fY29yZS5zY3JvbGxUb0xpbmUoZSl9LGUucHJvdG90eXBlLmNsZWFyPWZ1bmN0aW9uKCl7dGhpcy5fY29yZS5jbGVhcigpfSxlLnByb3RvdHlwZS53cml0ZT1mdW5jdGlvbihlLHQpe3RoaXMuX2NvcmUud3JpdGUoZSx0KX0sZS5wcm90b3R5cGUud3JpdGVVdGY4PWZ1bmN0aW9uKGUsdCl7dGhpcy5fY29yZS53cml0ZShlLHQpfSxlLnByb3RvdHlwZS53cml0ZWxuPWZ1bmN0aW9uKGUsdCl7dGhpcy5fY29yZS53cml0ZShlKSx0aGlzLl9jb3JlLndyaXRlKCJcclxuIix0KX0sZS5wcm90b3R5cGUucGFzdGU9ZnVuY3Rpb24oZSl7dGhpcy5fY29yZS5wYXN0ZShlKX0sZS5wcm90b3R5cGUuZ2V0T3B0aW9uPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9jb3JlLm9wdGlvbnNTZXJ2aWNlLmdldE9wdGlvbihlKX0sZS5wcm90b3R5cGUuc2V0T3B0aW9uPWZ1bmN0aW9uKGUsdCl7dGhpcy5fY2hlY2tSZWFkb25seU9wdGlvbnMoZSksdGhpcy5fY29yZS5vcHRpb25zU2VydmljZS5zZXRPcHRpb24oZSx0KX0sZS5wcm90b3R5cGUucmVmcmVzaD1mdW5jdGlvbihlLHQpe3RoaXMuX3ZlcmlmeUludGVnZXJzKGUsdCksdGhpcy5fY29yZS5yZWZyZXNoKGUsdCl9LGUucHJvdG90eXBlLnJlc2V0PWZ1bmN0aW9uKCl7dGhpcy5fY29yZS5yZXNldCgpfSxlLnByb3RvdHlwZS5jbGVhclRleHR1cmVBdGxhcz1mdW5jdGlvbigpe3RoaXMuX2NvcmUuY2xlYXJUZXh0dXJlQXRsYXMoKX0sZS5wcm90b3R5cGUubG9hZEFkZG9uPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9hZGRvbk1hbmFnZXIubG9hZEFkZG9uKHRoaXMsZSl9LE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJzdHJpbmdzIix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG59LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksZS5wcm90b3R5cGUuX3ZlcmlmeUludGVnZXJzPWZ1bmN0aW9uKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO2Zvcih2YXIgcj0wLGk9ZTtyPGkubGVuZ3RoO3IrKyl7dmFyIG49aVtyXTtpZihuPT09MS8wfHxpc05hTihuKXx8biUxIT0wKXRocm93IG5ldyBFcnJvcigiVGhpcyBBUEkgb25seSBhY2NlcHRzIGludGVnZXJzIil9fSxlfSgpO2UuVGVybWluYWw9dX0pKCksaX0pKCl9fSx0PXt9O2Z1bmN0aW9uIHIoaSl7dmFyIG49dFtpXTtpZih2b2lkIDAhPT1uKXJldHVybiBuLmV4cG9ydHM7dmFyIG89dFtpXT17aWQ6aSxsb2FkZWQ6ITEsZXhwb3J0czp7fX07cmV0dXJuIGVbaV0uY2FsbChvLmV4cG9ydHMsbyxvLmV4cG9ydHMsciksby5sb2FkZWQ9ITAsby5leHBvcnRzfXIubj1lPT57dmFyIHQ9ZSYmZS5fX2VzTW9kdWxlPygpPT5lLmRlZmF1bHQ6KCk9PmU7cmV0dXJuIHIuZCh0LHthOnR9KSx0fSxyLmQ9KGUsdCk9Pntmb3IodmFyIGkgaW4gdClyLm8odCxpKSYmIXIubyhlLGkpJiZPYmplY3QuZGVmaW5lUHJvcGVydHkoZSxpLHtlbnVtZXJhYmxlOiEwLGdldDp0W2ldfSl9LHIuZz1mdW5jdGlvbigpe2lmKCJvYmplY3QiPT10eXBlb2YgZ2xvYmFsVGhpcylyZXR1cm4gZ2xvYmFsVGhpczt0cnl7cmV0dXJuIHRoaXN8fG5ldyBGdW5jdGlvbigicmV0dXJuIHRoaXMiKSgpfWNhdGNoKGUpe2lmKCJvYmplY3QiPT10eXBlb2Ygd2luZG93KXJldHVybiB3aW5kb3d9fSgpLHIubz0oZSx0KT0+T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUsdCksci5ubWQ9ZT0+KGUucGF0aHM9W10sZS5jaGlsZHJlbnx8KGUuY2hpbGRyZW49W10pLGUpLCgoKT0+eyJ1c2Ugc3RyaWN0Ijt2YXIgZT1yKDM3OSksdD1yLm4oZSksaT1yKDc5NSksbj1yLm4oaSksbz1yKDU2OSkscz1yLm4obyksYT1yKDU2NSksYz1yLm4oYSksbD1yKDIxNiksdT1yLm4obCksaD1yKDU4OSksZj1yLm4oaCksXz1yKDEwMiksZD17fTtkLnN0eWxlVGFnVHJhbnNmb3JtPWYoKSxkLnNldEF0dHJpYnV0ZXM9YygpLGQuaW5zZXJ0PXMoKS5iaW5kKG51bGwsImhlYWQiKSxkLmRvbUFQST1uKCksZC5pbnNlcnRTdHlsZUVsZW1lbnQ9dSgpLHQoKShfLlosZCksXy5aJiZfLloubG9jYWxzJiZfLloubG9jYWxzO3ZhciBwPXIoMzIwKSx2PXIoNjE3KSxnPXIoNDg2KSx5PXIubihnKSxtPWZ1bmN0aW9uKGUsdCxyLGkpe3JldHVybiBuZXcocnx8KHI9UHJvbWlzZSkpKChmdW5jdGlvbihuLG8pe2Z1bmN0aW9uIHMoZSl7dHJ5e2MoaS5uZXh0KGUpKX1jYXRjaChlKXtvKGUpfX1mdW5jdGlvbiBhKGUpe3RyeXtjKGkudGhyb3coZSkpfWNhdGNoKGUpe28oZSl9fWZ1bmN0aW9uIGMoZSl7dmFyIHQ7ZS5kb25lP24oZS52YWx1ZSk6KHQ9ZS52YWx1ZSx0IGluc3RhbmNlb2Ygcj90Om5ldyByKChmdW5jdGlvbihlKXtlKHQpfSkpKS50aGVuKHMsYSl9YygoaT1pLmFwcGx5KGUsdHx8W10pKS5uZXh0KCkpfSkpfSxiPWZ1bmN0aW9uKGUsdCl7dmFyIHIsaSxuLG8scz17bGFiZWw6MCxzZW50OmZ1bmN0aW9uKCl7aWYoMSZuWzBdKXRocm93IG5bMV07cmV0dXJuIG5bMV19LHRyeXM6W10sb3BzOltdfTtyZXR1cm4gbz17bmV4dDphKDApLHRocm93OmEoMSkscmV0dXJuOmEoMil9LCJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJihvW1N5bWJvbC5pdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLG87ZnVuY3Rpb24gYShvKXtyZXR1cm4gZnVuY3Rpb24oYSl7cmV0dXJuIGZ1bmN0aW9uKG8pe2lmKHIpdGhyb3cgbmV3IFR5cGVFcnJvcigiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLiIpO2Zvcig7czspdHJ5e2lmKHI9MSxpJiYobj0yJm9bMF0/aS5yZXR1cm46b1swXT9pLnRocm93fHwoKG49aS5yZXR1cm4pJiZuLmNhbGwoaSksMCk6aS5uZXh0KSYmIShuPW4uY2FsbChpLG9bMV0pKS5kb25lKXJldHVybiBuO3N3aXRjaChpPTAsbiYmKG89WzImb1swXSxuLnZhbHVlXSksb1swXSl7Y2FzZSAwOmNhc2UgMTpuPW87YnJlYWs7Y2FzZSA0OnJldHVybiBzLmxhYmVsKysse3ZhbHVlOm9bMV0sZG9uZTohMX07Y2FzZSA1OnMubGFiZWwrKyxpPW9bMV0sbz1bMF07Y29udGludWU7Y2FzZSA3Om89cy5vcHMucG9wKCkscy50cnlzLnBvcCgpO2NvbnRpbnVlO2RlZmF1bHQ6aWYoISgobj0obj1zLnRyeXMpLmxlbmd0aD4wJiZuW24ubGVuZ3RoLTFdKXx8NiE9PW9bMF0mJjIhPT1vWzBdKSl7cz0wO2NvbnRpbnVlfWlmKDM9PT1vWzBdJiYoIW58fG9bMV0+blswXSYmb1sxXTxuWzNdKSl7cy5sYWJlbD1vWzFdO2JyZWFrfWlmKDY9PT1vWzBdJiZzLmxhYmVsPG5bMV0pe3MubGFiZWw9blsxXSxuPW87YnJlYWt9aWYobiYmcy5sYWJlbDxuWzJdKXtzLmxhYmVsPW5bMl0scy5vcHMucHVzaChvKTticmVha31uWzJdJiZzLm9wcy5wb3AoKSxzLnRyeXMucG9wKCk7Y29udGludWV9bz10LmNhbGwoZSxzKX1jYXRjaChlKXtvPVs2LGVdLGk9MH1maW5hbGx5e3I9bj0wfWlmKDUmb1swXSl0aHJvdyBvWzFdO3JldHVybnt2YWx1ZTpvWzBdP29bMV06dm9pZCAwLGRvbmU6ITB9fShbbyxhXSl9fX07d2luZG93Lm9ubG9hZD1mdW5jdGlvbigpe3ZhciBlPW5ldyBwLlRlcm1pbmFsLHQ9bmV3IHYuRml0QWRkb247d2luZG93LnRlcm09ZSx3aW5kb3cuZml0QWRkb249dCxlLmxvYWRBZGRvbih0KSxlLm9wZW4oZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInRlcm1pbmFsIikpO3ZhciByPWZ1bmN0aW9uKCl7ZS5lbGVtZW50LnBhcmVudEVsZW1lbnQuc3R5bGUuaGVpZ2h0PXdpbmRvdy5pbm5lckhlaWdodC0xNisicHgiLHQuZml0KCksZmV0Y2goIi9yZXNpemU/cm93cz0iK2Uucm93cysiJmNvbHM9IitlLmNvbHMpfTtyKCksd2luZG93Lm9ucmVzaXplPXI7dmFyIGk9W107ZS5vbkRhdGEoKGZ1bmN0aW9uKGUpe2kucHVzaChlKX0pKSxtKHRoaXMsdm9pZCAwLHZvaWQgMCwoZnVuY3Rpb24oKXt2YXIgZSx0LHI7cmV0dXJuIGIodGhpcywoZnVuY3Rpb24obil7c3dpdGNoKG4ubGFiZWwpe2Nhc2UgMDplPWZ1bmN0aW9uKGUpe3JldHVybiBuZXcgUHJvbWlzZSgoZnVuY3Rpb24odCl7cmV0dXJuIHNldFRpbWVvdXQodCxlKX0pKX0sbi5sYWJlbD0xO2Nhc2UgMTpuLnRyeXMucHVzaChbMSwsNyw4XSksbi5sYWJlbD0yO2Nhc2UgMjpyZXR1cm5bNCxlKDEwMCldO2Nhc2UgMzpyZXR1cm4gbi5zZW50KCkseSgpLmlzRW1wdHkoaSk/WzMsNV06KHQ9aS5qb2luKCIiKSxyPXdpbmRvdy5idG9hKHQpLGkubGVuZ3RoPTAsWzQsZmV0Y2goIi9pbi8iK3IpXSk7Y2FzZSA0Om4uc2VudCgpLG4ubGFiZWw9NTtjYXNlIDU6cmV0dXJuWzMsMl07Y2FzZSA2OnJldHVyblszLDhdO2Nhc2UgNzpyZXR1cm4gY29uc29sZS5sb2coImlucHV0IGRpc2Nvbm5lY3QhIiksWzddO2Nhc2UgODpyZXR1cm5bMl19fSkpfSkpLGZ1bmN0aW9uKCl7bSh0aGlzLHZvaWQgMCx2b2lkIDAsKGZ1bmN0aW9uKCl7dmFyIHQscixpO3JldHVybiBiKHRoaXMsKGZ1bmN0aW9uKG4pe3N3aXRjaChuLmxhYmVsKXtjYXNlIDA6bi50cnlzLnB1c2goWzAsLDUsNl0pLG4ubGFiZWw9MTtjYXNlIDE6cmV0dXJuWzQsZmV0Y2goIi9vdXQiKV07Y2FzZSAyOnJldHVybiB0PW4uc2VudCgpLGk9VWludDhBcnJheS5iaW5kLFs0LHQuYXJyYXlCdWZmZXIoKV07Y2FzZSAzOnJldHVybiByPW5ldyhpLmFwcGx5KFVpbnQ4QXJyYXksW3ZvaWQgMCxuLnNlbnQoKV0pKSx0JiZlLndyaXRlKHIpLFszLDFdO2Nhc2UgNDpyZXR1cm5bMyw2XTtjYXNlIDU6cmV0dXJuIGNvbnNvbGUubG9nKCJpbnB1dCBkaXNjb25uZWN0ISIpLFs3XTtjYXNlIDY6cmV0dXJuWzJdfX0pKX0pKX0oKX19KSgpfSkoKTs=",
"headers": [
[
"content-type",
"text/javascript"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/out": {
"data": "W0dJTl0gMjAyNC8wOC8wMyAtIDE1OjQyOjI4IHwbWzk3OzQybSAyMDAgG1swbXwgIDMuNTQyNDYyNjkxcyB8ICAgICAgIDEyNy4wLjAuMSB8G1s5Nzs0Nm0gUE9TVCAgICAbWzBtICIvYXBpL2dlbmVyYXRlIg0K",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/resize?rows=45&cols=122": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
},
"https://localhost:10000/resize?rows=45&cols=87": {
"data": "",
"headers": [
[
"content-type",
"text/html; charset=UTF-8"
]
],
"ok": true,
"status": 200,
"status_text": ""
}
}
},
"id": "3Y_UIpLVzBrI",
"outputId": "6669f14e-371a-469c-fd66-f5a98cc2f6f4"
},
"outputs": [],
"source": [
"%xterm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "WgMMxn_1uBeF"
},
"outputs": [],
"source": [
"from langchain_community.llms import Ollama"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "RfB3IE7Eug8J"
},
"outputs": [],
"source": [
"# Initialize an instance of the Ollama model\n",
"llm = Ollama(model=\"llama3.1\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Yy8LQktRzH9v",
"outputId": "01e91478-4564-4ce0-9eaa-a7aaa0be1440"
},
"outputs": [],
"source": [
"# Invoke the model to generate responses\n",
"response = llm.invoke(\"Tell me a joke\")\n",
"print(response)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xMcV-9QFvs2a"
},
"outputs": [],
"source": [
"'''from langchain_ollama.llms import OllamaLLM\n",
"#loading the ollama model\n",
"model = OllamaLLM(model=\"llama3.1\")'''"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SZkShd7jwlWe"
},
"outputs": [],
"source": [
" #Use RetrievalQA chain for orchestration\n",
"qa = RetrievalQA.from_chain_type(llm=llm, chain_type=\"stuff\", retriever=retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "EHsE6vxpVtEB",
"outputId": "d2dc5df5-b9d8-4da1-ec7b-aab2db0a5461"
},
"outputs": [],
"source": [
"while True:\n",
" query = input(\"Type your query if you want to exit type Exit: \\n\")\n",
" if query == \"Exit\":\n",
" break\n",
" result = qa.run(query)\n",
" print(result)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "UJiJM7F7I_M6"
},
"outputs": [],
"source": [
"query1= \"Describe the relationship and dynamic between Will, Gared, and Ser Waymar Royce\"\n",
"query2= \"How long have Gared and Will been part of the Night's Watch?\""
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: README.md
================================================
# All of the tutorials are available on my YouTube channel; please visit there.
Youtube Channel Link: https://youtube.com/@sunnysavita10?si=m0A0Cznge6VM3bTI
================================================
FILE: basic_retrieval_and_contextual_compression_retrieval.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "pTe8iIaNM4zk"
},
"source": [
"https://github.com/langchain-ai/langchain/tree/master/libs/langchain/langchain/retrievers/document_compressors"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "qUKL4xoQLk2l"
},
"source": [
"https://blog.langchain.dev/improving-document-retrieval-with-contextual-compression/"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "QOY6EbacxP4a",
"outputId": "246a240a-add3-4a5b-930c-25904382bedd"
},
"outputs": [],
"source": [
"!pip install langchain_community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "atsXMM1OxU-A",
"outputId": "974a2892-1770-4532-ee06-64434f6dc517"
},
"outputs": [],
"source": [
"!pip install langchain_openai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Xl1eTvuKxb3Z",
"outputId": "1ae75a8a-1b82-46bf-985c-024b186819d9"
},
"outputs": [],
"source": [
"#facebook ai similarity search\n",
"!pip install faiss-cpu"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "CQS1GvoVxjKg"
},
"outputs": [],
"source": [
"from langchain_community.document_loaders import TextLoader\n",
"from langchain_community.vectorstores import FAISS\n",
"from langchain_openai import OpenAIEmbeddings\n",
"from langchain_text_splitters import CharacterTextSplitter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "s1qf4CaMxpmY"
},
"outputs": [],
"source": [
"documents = TextLoader(\"/content/state_of_the_union.txt\").load()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7x6yIAuDx8FQ"
},
"outputs": [],
"source": [
"text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=100)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ltWbdNzVyGzY"
},
"outputs": [],
"source": [
"texts = text_splitter.split_documents(documents)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tTmFHn1basDU",
"outputId": "56652ee9-323d-4a82-c415-179dbcca00c6"
},
"outputs": [],
"source": [
"texts"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pKjzmrYIyIZg"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TVpbGd5PyKXQ"
},
"outputs": [],
"source": [
"import os\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "pPvs2OcUyL0R"
},
"outputs": [],
"source": [
"retriever = FAISS.from_documents(texts, OpenAIEmbeddings()).as_retriever()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "KlUX12WNyM-Z"
},
"outputs": [],
"source": [
"docs = retriever.invoke(\"What did the president say about Ketanji Brown Jackson\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "MYvh_OXfZf6b"
},
"outputs": [],
"source": [
"# Helper function for printing docs\n",
"\n",
"def pretty_print_docs(docs):\n",
" print(\n",
" f\"\\n{'-' * 100}\\n\".join(\n",
" [f\"Document {i+1}:\\n\\n\" + d.page_content for i, d in enumerate(docs)]\n",
" )\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "cY1HATqwCx7B",
"outputId": "1fe9468a-1865-445c-f942-a9c65758e0c1"
},
"outputs": [],
"source": [
"pretty_print_docs(docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GXqglThB8riU"
},
"outputs": [],
"source": [
"docs2 = retriever.invoke(\"What were the top three priorities outlined in the most recent State of the Union address?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "S74TsmSNcOnl",
"outputId": "4426b97c-6b27-44fa-a254-8af0926e14c6"
},
"outputs": [],
"source": [
"pretty_print_docs(docs2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "uW2rdKph9FiW"
},
"outputs": [],
"source": [
"docs3 = retriever.invoke(\"How did the President propose to tackle the issue of climate change?\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "sP-B8YZGyOhA",
"outputId": "cd3bb7ec-1212-4322-c589-2ccb5f14c4bc"
},
"outputs": [],
"source": [
"pretty_print_docs(docs3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "D7wlQBDTclX8"
},
"outputs": [],
"source": [
"from langchain_openai import OpenAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AnY_CqOkZ3I0"
},
"outputs": [],
"source": [
"llm=OpenAI(temperature=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SxyNIxARczyC"
},
"outputs": [],
"source": [
"from langchain.chains import RetrievalQA"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ZTnmk8w8Ic75"
},
"outputs": [],
"source": [
"chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "NQxPyJsPZ6qT"
},
"outputs": [],
"source": [
"query=\"What were the top three priorities outlined in the most recent State of the Union address?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "WnPhNQO8Iimd",
"outputId": "087ce491-378b-430a-e58d-f6b47e8d1758"
},
"outputs": [],
"source": [
"chain.invoke(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "dR6-pw9DI3Mh",
"outputId": "57501773-d922-415a-81ab-01f318b4973c"
},
"outputs": [],
"source": [
"print(chain.invoke(query)['result'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "rbPk6dwNyPjA"
},
"outputs": [],
"source": [
"from langchain.retrievers import ContextualCompressionRetriever\n",
"from langchain.retrievers.document_compressors import LLMChainExtractor\n",
"from langchain_openai import OpenAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "88ew_BD76xaA"
},
"outputs": [],
"source": [
"compressor = LLMChainExtractor.from_llm(llm)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Z2k9nibH645g"
},
"outputs": [],
"source": [
"compression_retriever=ContextualCompressionRetriever(base_compressor=compressor, base_retriever=retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dNXg5XbG7hG5"
},
"outputs": [],
"source": [
"compressed_docs = compression_retriever.invoke(\"What did the president say about Ketanji Jackson Brown\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "9k8HzK7WeUCr",
"outputId": "d4aa9b4d-09c1-4cb2-e201-1ad07361e8d8"
},
"outputs": [],
"source": [
"compressed_docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "l__guBnv7oTg"
},
"outputs": [],
"source": [
"compressed_docs = compression_retriever.invoke(\"What were the top three priorities outlined in the most recent State of the Union address?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "2HAq8DSA8gdQ",
"outputId": "38e374e4-2d8e-4808-cb63-142e2b11727a"
},
"outputs": [],
"source": [
"compressed_docs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Y2fcGeun8h6o",
"outputId": "5b8d0f15-8ff0-42cf-eaed-9b23bfb83858"
},
"outputs": [],
"source": [
"pretty_print_docs(compressed_docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "h91DraTx9Xmn"
},
"outputs": [],
"source": [
"compressed_docs2 = compression_retriever.invoke(\"How did the President propose to tackle the issue of climate change?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7vwNOc-a9UY5",
"outputId": "5b5ff4a3-8cb3-44aa-fe32-8dd5c9542224"
},
"outputs": [],
"source": [
"pretty_print_docs(compressed_docs2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "yy67l-QZ88lR"
},
"outputs": [],
"source": [
"from langchain.retrievers.document_compressors import LLMChainFilter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mfrMzQVvBrm5"
},
"outputs": [],
"source": [
"filter = LLMChainFilter.from_llm(llm)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Viop2pL7BtZ5"
},
"outputs": [],
"source": [
"compression_retriever2 = ContextualCompressionRetriever(base_compressor=filter, base_retriever=retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Cl3JN_lYB2TZ"
},
"outputs": [],
"source": [
"compressed_docs3 = compression_retriever2.invoke(\"What were the top three priorities outlined in the most recent State of the Union address?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "H-K0qV4iCEYp",
"outputId": "4afb4e19-de5f-4a35-d7c4-37ce759000b1"
},
"outputs": [],
"source": [
"pretty_print_docs(compressed_docs3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "qrhbWxSYCIap"
},
"outputs": [],
"source": [
"original_contexts_len = len(\"\\n\\n\".join([d.page_content for i, d in enumerate(docs2)]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "hqz1IoaqCquy",
"outputId": "beca2fde-210c-49c1-882e-140f67c1ca22"
},
"outputs": [],
"source": [
"original_contexts_len"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "i3akD7BNCrEY"
},
"outputs": [],
"source": [
"compressed_contexts_len = len(\"\\n\\n\".join([d.page_content for i, d in enumerate(compressed_docs)]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ES55u8v2DAow",
"outputId": "ecdf5b18-40be-4be9-d474-525c65191b00"
},
"outputs": [],
"source": [
"compressed_contexts_len"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MjSbvEhsDSfI",
"outputId": "162d47dd-db75-41a6-bb7f-3ec1b4986732"
},
"outputs": [],
"source": [
"print(\"Original context length:\", original_contexts_len)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XsW0VCPHDafl",
"outputId": "322168c7-a0d8-4f2c-c7c3-d7c2a7e76bf7"
},
"outputs": [],
"source": [
"print(\"Compressed context length:\", compressed_contexts_len)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MKRrrgTUDBwx",
"outputId": "ffdad194-adaf-4ea9-810c-f226d4d0c7d5"
},
"outputs": [],
"source": [
"print(\"Compressed Ratio:\", f\"{original_contexts_len/(compressed_contexts_len + 1e-5):.2f}x\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nr7_yB-0Dcfy"
},
"outputs": [],
"source": [
"from langchain.retrievers.document_compressors import EmbeddingsFilter"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SXZoPZiADuwp"
},
"outputs": [],
"source": [
"from langchain_openai import OpenAIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "MdVHZfxtDzm6"
},
"outputs": [],
"source": [
"embeddings = OpenAIEmbeddings()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Zk4XUWnxD1Gy"
},
"outputs": [],
"source": [
"embeddings_filter = EmbeddingsFilter(embeddings=embeddings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9x3cyCl_D6-R"
},
"outputs": [],
"source": [
"compression_retriever3 = ContextualCompressionRetriever(base_compressor=embeddings_filter, base_retriever=retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7oYTzFlHgqyz"
},
"outputs": [],
"source": [
"compressed_docs4 = compression_retriever3.invoke(\"What were the top three priorities outlined in the most recent State of the Union address?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "G2TzhtGKD8nJ",
"outputId": "479b0a4b-44f8-43da-ffe6-a1bd78f60f86"
},
"outputs": [],
"source": [
"pretty_print_docs(compressed_docs4)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "WLCVDKclD-b5",
"outputId": "667bad3f-747b-4bcc-8d93-f64f8396cb8d"
},
"outputs": [],
"source": [
"print(\"Original context length:\", original_contexts_len)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "BF7G0XBNEiTR"
},
"outputs": [],
"source": [
"compressed_contexts_len = len(\"\\n\\n\".join([d.page_content for i, d in enumerate(compressed_docs)]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lFcGtUV1EU_E",
"outputId": "cb40984e-51ca-472b-8513-5aba75d96b4f"
},
"outputs": [],
"source": [
"print(\"Compressed context length:\", compressed_contexts_len)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "62D7JNojENBJ",
"outputId": "546b0513-cf41-4dec-e867-b9833aab47bb"
},
"outputs": [],
"source": [
"print(\"Compressed Ratio:\", f\"{original_contexts_len/(compressed_contexts_len + 1e-5):.2f}x\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nX-r8QUGEots"
},
"outputs": [],
"source": [
"from langchain.retrievers.document_compressors import DocumentCompressorPipeline\n",
"from langchain_community.document_transformers import EmbeddingsRedundantFilter\n",
"from langchain_text_splitters import CharacterTextSplitter\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1rsxdeB5EtHJ"
},
"outputs": [],
"source": [
"splitter = CharacterTextSplitter(chunk_size=300, chunk_overlap=0, separator=\". \")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "J_7Do4-xFYy5"
},
"outputs": [],
"source": [
"redundant_filter = EmbeddingsRedundantFilter(embeddings=embeddings)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AVaEjtW9Fbi5"
},
"outputs": [],
"source": [
"relevant_filter = EmbeddingsFilter(embeddings=embeddings, similarity_threshold=0.76)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "udt5IW7YFeDh"
},
"outputs": [],
"source": [
"pipeline_compressor = DocumentCompressorPipeline(transformers=[splitter, redundant_filter, relevant_filter])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Wdz30jmyFhjp"
},
"outputs": [],
"source": [
"compression_retriever = ContextualCompressionRetriever(base_compressor=pipeline_compressor, base_retriever=retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Ix-Gx3IkFlBJ"
},
"outputs": [],
"source": [
"compressed_docs = compression_retriever.invoke(\"What were the top three priorities outlined in the most recent State of the Union address?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "M-0-wZOpFtqx",
"outputId": "0e9d2cf4-47b8-4600-a5eb-02cc32ab2254"
},
"outputs": [],
"source": [
"pretty_print_docs(compressed_docs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "X0C714p9Fvwp"
},
"outputs": [],
"source": [
"from langchain_openai import ChatOpenAI\n",
"llm = ChatOpenAI(temperature=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dfRixlJZHa9J"
},
"outputs": [],
"source": [
"from langchain.chains import RetrievalQA"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "A5Mk1nxWHjja"
},
"outputs": [],
"source": [
"chain = RetrievalQA.from_chain_type(llm=llm, retriever=compression_retriever)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "I-Hf4k_1H3Q6"
},
"outputs": [],
"source": [
"query=\"What were the top three priorities outlined in the most recent State of the Union address?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "nQH1xIP1H1Lx",
"outputId": "c3b7c1c1-46b0-4329-8ccf-fb6b5eb2a6f7"
},
"outputs": [],
"source": [
"chain.invoke(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "dI5v_c62IJiZ",
"outputId": "74e28fb3-bba4-4b27-a528-142c0d2f7a64"
},
"outputs": [],
"source": [
"print(chain.invoke(query)['result'])"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "kqaJuOidJBJA"
},
"source": [
"The top three priorities outlined in the most recent State of the Union address were:\n",
"\n",
"1. Beating the opioid epidemic by increasing funding for prevention, treatment, harm reduction, and recovery.\n",
"2. Strengthening infrastructure and innovation in America to improve transportation and create more jobs.\n",
"3. Promoting domestic production and reducing reliance on foreign supply chains to boost the economy and create more opportunities for Americans."
]
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyNBvnzKXZ1f2uW1KiWpVbJ7",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: self_query_retrieval.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PBxuDQ4DKddt"
},
"source": [
"# Basic RAG Flow"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "AzoZKDjuK6OL"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Vg5iIbnyKgsc"
},
"source": [
"## When to use it:\n",
"\n",
"This is the most basic flow but would be very effective in documents like Pdfs where there is linearity in data and no major interdependency among different parts of documents."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "y49qSaVAKgvE"
},
"source": [
"## Issue:\n",
"\n",
"Similarity Search will filter out only top-k similar chunk which is similar to the user query but...\n",
"\n",
"1. It might not be relevant chunk.\n",
"\n",
"2. It will give top-k chunk only based on the words present in the query without having knowledge of its dependency on other chunks. This will result in Information loss."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "YntyqWOOKgxc"
},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "9lGCTvc8S7tE",
"outputId": "76b5a18e-aa89-401b-9098-fe51685e8386"
},
"outputs": [],
"source": [
"!pip -q install langchain openai tiktoken PyPDF2 faiss-cpu"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "KIjxALFMDeHi",
"outputId": "63bd02fa-d913-4de4-8513-22607e320a1a"
},
"outputs": [],
"source": [
"!pip install langchain_openai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "pAVx9tS6HxXs",
"outputId": "0634c8c5-1aff-4b95-c558-7a7bd8310554"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "MKZfLjW1DPnH",
"outputId": "ec87f1f8-3599-4b6e-b22a-470dc37762cb"
},
"outputs": [],
"source": [
"!pip install langchain_chroma"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 87
},
"id": "ZQ2jx6K-JxGe",
"outputId": "d07f9d7a-5008-4ecd-8bee-b45f837a6caf"
},
"outputs": [],
"source": [
"####if you want to use gemini feel free to use this code.\n",
"\n",
"'''\n",
"%pip install --upgrade --quiet google-generativeai langchain-google-genai\n",
"\n",
"import os\n",
"from google.colab import userdata\n",
"\n",
"GOOGLE_API_KEY = userdata.get('GOOGLE_API_KEY')\n",
"os.environ[\"GOOGLE_API_KEY\"] = GOOGLE_API_KEY\n",
"\n",
"from langchain_google_genai import GoogleGenerativeAIEmbeddings\n",
"gemini_embeddings = GoogleGenerativeAIEmbeddings(model=\"models/embedding-001\")\n",
"\n",
"from langchain_google_genai import ChatGoogleGenerativeAI\n",
"llm = ChatGoogleGenerativeAI(model=\"gemini-1.5-pro\")\n",
"\n",
"result = llm.invoke(\"Write a ballad about LangChain\")\n",
"print(result.content)\n",
"'''"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XLiHiHPJHnC2"
},
"outputs": [],
"source": [
"from google.colab import userdata\n",
"OPENAI_API_KEY=userdata.get('OPENAI_API_KEY')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TgjLGyO2HnFm"
},
"outputs": [],
"source": [
"import os\n",
"os.environ[\"OPENAI_API_KEY\"]=OPENAI_API_KEY"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "YNnkfnVzJlP0"
},
"outputs": [],
"source": [
"from langchain_chroma import Chroma\n",
"from langchain_core.documents import Document\n",
"from langchain_openai import OpenAIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nAioNXP8HnIO"
},
"outputs": [],
"source": [
"embedding = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "bkE6PFBfDFCX"
},
"outputs": [],
"source": [
"from langchain_core.documents import Document"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XgS5nkYtKsq5"
},
"outputs": [],
"source": [
"docs = [\n",
" Document(\n",
" page_content=\"A bunch of scientists bring back dinosaurs and mayhem breaks loose\",\n",
" metadata={\"year\": 1993, \"rating\": 7.7, \"genre\": \"science fiction\"},\n",
" ),\n",
" Document(\n",
" page_content=\"Leo DiCaprio gets lost in a dream within a dream within a dream within a ...\",\n",
" metadata={\"year\": 2010, \"director\": \"Christopher Nolan\", \"rating\": 8.2},\n",
" ),\n",
" Document(\n",
" page_content=\"A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea\",\n",
" metadata={\"year\": 2006, \"director\": \"Satoshi Kon\", \"rating\": 8.6},\n",
" ),\n",
" Document(\n",
" page_content=\"A bunch of normal-sized women are supremely wholesome and some men pine after them\",\n",
" metadata={\"year\": 2019, \"director\": \"Greta Gerwig\", \"rating\": 8.3},\n",
" ),\n",
" Document(\n",
" page_content=\"Toys come alive and have a blast doing so\",\n",
" metadata={\"year\": 1995, \"genre\": \"animated\"},\n",
" ),\n",
" Document(\n",
" page_content=\"A hacker discovers reality is a simulation and leads a rebellion against the machines controlling it.\",\n",
" metadata={\"year\": 1999, \"director\": \"Lana Wachowski, Lilly Wachowski\", \"rating\": 8.7, \"genre\": \"science fiction\"},\n",
" ),\n",
" Document(\n",
" page_content=\"A young lion prince flees his kingdom only to learn the true meaning of responsibility and bravery.\",\n",
" metadata={\"year\": 1994, \"rating\": 8.5, \"genre\": \"animated\"},\n",
" ),\n",
" Document(\n",
" page_content=\"Batman faces off against the Joker, a criminal mastermind who plunges Gotham into chaos.\",\n",
" metadata={\"year\": 2008, \"director\": \"Christopher Nolan\", \"rating\": 9.0, \"genre\": \"action\"},\n",
" ),\n",
" Document(\n",
" page_content=\"A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.\",\n",
" metadata={\"year\": 2014, \"director\": \"Christopher Nolan\", \"rating\": 8.6, \"genre\": \"science fiction\"},\n",
" )\n",
"]\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "LH_Te8rbO42F"
},
"outputs": [],
"source": [
"vectorstore = Chroma.from_documents(docs, embedding)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "c2CFZ2TGCiQX"
},
"outputs": [],
"source": [
"question1 = \"Which 1994 animated movie has a rating of 8.5?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gGfmDywVCi0R"
},
"outputs": [],
"source": [
"question2 = \"Which movie features Batman facing off against the Joker and who directed it?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "aicEDAEPCwWX"
},
"outputs": [],
"source": [
"question3 = \"What genre is the movie 'The Matrix' and who directed it?\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tIc5K__6QCVb",
"outputId": "744ba12f-b431-431d-eadd-2df77791214e"
},
"outputs": [],
"source": [
"vectorstore.similarity_search(question1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "q_rWwadnCbvZ",
"outputId": "a934067a-0706-4240-f1d5-4c5441665962"
},
"outputs": [],
"source": [
"vectorstore.similarity_search(question2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "KZD_6g1PQCaM"
},
"outputs": [],
"source": [
"retriever = vectorstore.as_retriever(search_type=\"similarity\", search_kwargs={\"k\": 3})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "mqzXhs1dRPfc"
},
"outputs": [],
"source": [
"from langchain.chat_models import ChatOpenAI\n",
"\n",
"from operator import itemgetter\n",
"from langchain.prompts import ChatPromptTemplate\n",
"from langchain.schema.output_parser import StrOutputParser\n",
"from langchain.schema.runnable import RunnableLambda, RunnablePassthrough\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "qZBZ3BT7P7dT",
"outputId": "18285d61-9386-482d-c762-0615dc17b115"
},
"outputs": [],
"source": [
"llm = ChatOpenAI(temperature=0.7)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "03euBVg-O48T"
},
"outputs": [],
"source": [
"import textwrap\n",
"def wrap_text(text, width=90): #preserve_newlines\n",
" # Split the input text into lines based on newline characters\n",
" lines = text.split('\\n')\n",
"\n",
" # Wrap each line individually\n",
" wrapped_lines = [textwrap.fill(line, width=width) for line in lines]\n",
"\n",
" # Join the wrapped lines back together using newline characters\n",
" wrapped_text = '\\n'.join(wrapped_lines)\n",
"\n",
" return wrapped_text"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PdJig9FhP0ks"
},
"outputs": [],
"source": [
"template = \"\"\"Answer the question based only on the following context:\n",
"{context}\n",
"\n",
"Question: {question}\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_e5sau9FP10j"
},
"outputs": [],
"source": [
"prompt = ChatPromptTemplate.from_template(template)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5rTr9oesP2y8"
},
"outputs": [],
"source": [
"chain = (\n",
" {\"context\": retriever, \"question\": RunnablePassthrough()}\n",
" | prompt\n",
" | llm\n",
" | StrOutputParser()\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"id": "9sMfSKUUKyso",
"outputId": "2440d77c-354c-401c-f418-a81c5ebd0074"
},
"outputs": [],
"source": [
"question1"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "DiIBOtGXP4X1"
},
"outputs": [],
"source": [
"text_reply = chain.invoke(question1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "mpRI_8oWHnK7",
"outputId": "3db8e016-f627-4d27-cafa-b182c3672a34"
},
"outputs": [],
"source": [
"print(wrap_text(text_reply))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "BtaPThxbK_Mp"
},
"outputs": [],
"source": [
"text_reply = chain.invoke(\"Tell me about the movie which have rating more than 7.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "jCS1KSejK4fZ"
},
"outputs": [],
"source": [
"text_reply = chain.invoke(question3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "QATWhyWBRzw7"
},
"outputs": [],
"source": [
"\"Tell me about the movie which have rating more than 7.\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "j-TnWmpuLBLm",
"outputId": "e2b81a52-9fac-44a0-9ea8-32b21d28ac12"
},
"outputs": [],
"source": [
"print(wrap_text(text_reply))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "td-AtyFpLMns"
},
"source": [
"# Self Query Retrieval"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "KwGuQGyrR0DU"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2dWwE2jfSWQN"
},
"source": [
"A self-query retriever is a retrieval system that can analyze a natural language question and use it to query itself. Here's how it works:\n",
"\n",
"**User Input:** You provide a question in plain English.\n",
"Understanding the Question: The retriever uses a large language model (LLM) to understand the intent and meaning behind your question.\n",
"\n",
"**Building a Structured Query:** The LLM then translates your question into a structured query that a search engine can understand. This structured query might include keywords and filters based on the details you provided in your question.\n",
"\n",
"**Searching the Datastore:** The retriever uses the structured query to search its underlying datastore, which is typically a vector store.\n",
"\n",
"**Returning Results:** The retriever retrieves the documents from the datastore that are most relevant to your question.\n",
"\n",
"We use metadata-filtering to filter out the important chunks.\n",
"\n",
"When it can be used: It will be effective where you have to search in a small subset of the large document. Suppose you want to know about a particular department type like “Sales” in the whole document. Then you need to add this metadata info of department type in each chunk. And filter accordingly.\n",
"\n",
"#### Overall, self-query retrieval is a powerful technique that leverages the capabilities of LLMs to achieve a more sophisticated and user-centric approach to information retrieval within LangChain models."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "QEFgiP7bykm5",
"outputId": "c7ad3121-28bb-4984-a192-1be1275e6eed"
},
"outputs": [],
"source": [
"!pip install langchain"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "VoKRepz1y37B"
},
"outputs": [],
"source": [
"%pip install --upgrade --quiet langchain-chroma"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "n9YHZpvYzGiA",
"outputId": "f8696878-5f84-4471-9f06-4059e546a32a"
},
"outputs": [],
"source": [
"!pip install langchain_openai"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "FvZIEmOFOi8N",
"outputId": "2e55b3f5-9ea4-40bc-81ee-bb9bb7539dd2"
},
"outputs": [],
"source": [
"!pip install langchain_chroma"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "aBXs1QqGy8Fq"
},
"outputs": [],
"source": [
"from langchain_chroma import Chroma\n",
"from langchain_core.documents import Document\n",
"from langchain_openai import OpenAIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Hs6gn8S2OY-l"
},
"outputs": [],
"source": [
"docs = [\n",
" Document(\n",
" page_content=\"A bunch of scientists bring back dinosaurs and mayhem breaks loose\",\n",
" metadata={\"year\": 1993, \"rating\": 7.7, \"genre\": \"science fiction\"},\n",
" ),\n",
" Document(\n",
" page_content=\"Leo DiCaprio gets lost in a dream within a dream within a dream within a ...\",\n",
" metadata={\"year\": 2010, \"director\": \"Christopher Nolan\", \"rating\": 8.2},\n",
" ),\n",
" Document(\n",
" page_content=\"A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea\",\n",
" metadata={\"year\": 2006, \"director\": \"Satoshi Kon\", \"rating\": 8.6},\n",
" ),\n",
" Document(\n",
" page_content=\"A bunch of normal-sized women are supremely wholesome and some men pine after them\",\n",
" metadata={\"year\": 2019, \"director\": \"Greta Gerwig\", \"rating\": 8.3},\n",
" ),\n",
" Document(\n",
" page_content=\"Toys come alive and have a blast doing so\",\n",
" metadata={\"year\": 1995, \"genre\": \"animated\"},\n",
" ),\n",
" Document(\n",
" page_content=\"A hacker discovers reality is a simulation and leads a rebellion against the machines controlling it.\",\n",
" metadata={\"year\": 1999, \"director\": \"Lana Wachowski, Lilly Wachowski\", \"rating\": 8.7, \"genre\": \"science fiction\"},\n",
" ),\n",
" Document(\n",
" page_content=\"A young lion prince flees his kingdom only to learn the true meaning of responsibility and bravery.\",\n",
" metadata={\"year\": 1994, \"rating\": 8.5, \"genre\": \"animated\"},\n",
" ),\n",
" Document(\n",
" page_content=\"Batman faces off against the Joker, a criminal mastermind who plunges Gotham into chaos.\",\n",
" metadata={\"year\": 2008, \"director\": \"Christopher Nolan\", \"rating\": 9.0, \"genre\": \"action\"},\n",
" ),\n",
" Document(\n",
" page_content=\"A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.\",\n",
" metadata={\"year\": 2014, \"director\": \"Christopher Nolan\", \"rating\": 8.6, \"genre\": \"science fiction\"},\n",
" )\n",
"]\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hwTY5PtPzNrS"
},
"outputs": [],
"source": [
"vectorstore = Chroma.from_documents(docs, embedding())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "I9ZhQxsXzUig"
},
"outputs": [],
"source": [
"from langchain.chains.query_constructor.base import AttributeInfo\n",
"from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
"from langchain_openai import ChatOpenAI"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "dsywdsapzW_w"
},
"outputs": [],
"source": [
"metadata_field_info = [\n",
" AttributeInfo(\n",
" name=\"genre\",\n",
" description=\"The genre of the movie. One of ['science fiction', 'comedy', 'drama', 'thriller', 'romance', 'action', 'animated']\",\n",
" type=\"string\",\n",
" ),\n",
" AttributeInfo(\n",
" name=\"year\",\n",
" description=\"The year the movie was released\",\n",
" type=\"integer\",\n",
" ),\n",
" AttributeInfo(\n",
" name=\"director\",\n",
" description=\"The name of the movie director\",\n",
" type=\"string\",\n",
" ),\n",
" AttributeInfo(\n",
" name=\"rating\", description=\"A 1-10 rating for the movie\", type=\"float\"\n",
" ),\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "XyF_rSyGzdRJ"
},
"outputs": [],
"source": [
"document_content_description = \"Brief summary of a movie\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PrYeu2jl0XzI"
},
"outputs": [],
"source": [
"from langchain.chains.query_constructor.base import (\n",
" StructuredQueryOutputParser,\n",
" get_query_constructor_prompt,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "gaFP7pslzt5x"
},
"outputs": [],
"source": [
"prompt = get_query_constructor_prompt(\n",
" document_content_description,\n",
" metadata_field_info,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "SocePKXYzvj5",
"outputId": "51b1c827-e549-4876-c95b-811c2d5a7aad"
},
"outputs": [],
"source": [
"prompt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "_jLPttCvz63R",
"outputId": "74b04d04-4184-4176-ba75-5578d9a1313d"
},
"outputs": [],
"source": [
"!pip install lark"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tsz1M9KVz2Ib"
},
"outputs": [],
"source": [
"output_parser = StructuredQueryOutputParser.from_components()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "cee-pgJvLxRb"
},
"outputs": [],
"source": [
"query_constructor = prompt | llm | output_parser"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "FP1kwZ5G02Wn",
"outputId": "334422d1-4f3b-4173-adad-dd24c4ef36c2"
},
"outputs": [],
"source": [
"print(prompt.format(query=\"dummy question\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "lVm6aHuK08In",
"outputId": "55b1167a-6926-4ed2-858a-11b651bfbeff"
},
"outputs": [],
"source": [
"query_constructor.invoke(\n",
" {\n",
" \"query\": \"What are some sci-fi movies from the 90's directed by Luc Besson about taxi drivers\"\n",
" }\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 158
},
"id": "tWRteKd618xQ",
"outputId": "04f38e29-f5e5-44bf-a2c2-b645d98d7852"
},
"outputs": [],
"source": [
"#StructuredQuery(query='taxi driver', filter=Operation(operator=, arguments=[Comparison(comparator=, attribute='genre', value='science fiction'), Operation(operator=, arguments=[Comparison(comparator=, attribute='year', value=1990), Comparison(comparator=, attribute='year', value=2000)]), Comparison(comparator=, attribute='director', value='Luc Besson')]), limit=None)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "nr05KF5K2E6f"
},
"outputs": [],
"source": [
"from langchain.retrievers.self_query.chroma import ChromaTranslator\n",
"\n",
"retriever = SelfQueryRetriever(\n",
" query_constructor=query_constructor,\n",
" vectorstore=vectorstore,\n",
" structured_query_translator=ChromaTranslator(),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "sAh8cvDc2aXw",
"outputId": "12701520-3077-443e-be87-7d535a2b9d8c"
},
"outputs": [],
"source": [
"!pip install -U langchain-community"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Y7Z-lHwp2quP",
"outputId": "448ddfc3-95b7-4893-e294-50c81b8c4bbe"
},
"outputs": [],
"source": [
"retriever.invoke(\n",
" \"What's a movie after 1990 but before 2005 that's all about toys, and preferably is animated\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "TBhsAYyg2xju"
},
"outputs": [],
"source": [
"\n",
"from operator import itemgetter\n",
"from langchain.prompts import ChatPromptTemplate\n",
"from langchain.schema.output_parser import StrOutputParser\n",
"from langchain.schema.runnable import RunnableLambda, RunnablePassthrough\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "7n4rEgzd4t9o"
},
"outputs": [],
"source": [
"\n",
"template = \"\"\"Answer the question based only on the following context:\n",
"{context}\n",
"\n",
"Question: {question}\n",
"\"\"\"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "rkoVeILY4wjv"
},
"outputs": [],
"source": [
"\n",
"chain = (\n",
" {\"context\": retriever, \"question\": RunnablePassthrough()}\n",
" | prompt\n",
" | llm\n",
" | StrOutputParser()\n",
")\n",
"\n",
"text_reply = chain.invoke(\"Tell me about the movie which have rating more than 7.\")\n",
"\n",
"print(wrap_text(text_reply))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "C0F9OED54zf3",
"outputId": "ad18b957-8524-4e68-9bde-80889403366c"
},
"outputs": [],
"source": [
"text_reply = chain.invoke(\"Tell me about the movie which have rating more than 7.\")\n",
"\n",
"print(wrap_text(text_reply))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "xcqpk8Qh47a_"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"authorship_tag": "ABX9TyMQn0/iuXCCHW/P3nRyAYov",
"include_colab_link": true,
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}