📈 Emerging EdTech Innovators


| Introduction and Objective


The primary objective of this project was to explore emerging companies and trends in the EdTech industry, as featured on HolonIQ’s list. This initiative aimed to gain a comprehensive understanding of the current market landscape, categorize the startups based on their focus areas, and pinpoint potential clients, providers, partners, competitors, or emerging markets. The analysis was structured to examine these entities by geographic regions and industry verticals, ultimately providing strategic insights to understand edunext’s position within the industry and enhance its market positioning and growth.

🚨 Why the HolonIQ EdTech Ranking was Selected

The HolonIQ EdTech ranking was selected due to its reputation as a comprehensive and authoritative source of information on the most innovative and high-potential EdTech startups globally. The ranking provides valuable insights into the leading companies in the EdTech sector, making it an ideal resource for identifying key players and emerging trends in the industry. By leveraging this ranking, eduNext can ensure its analysis is based on credible and up-to-date information, enabling informed decision-making and strategic planning.

💫 Company Overview

Edunext is an infrastructure-as-a-service provider and software company dedicated to the Open edX platform. It empowers organizations worldwide by delivering robust, scalable, and customizable online learning solutions. Edunext’s mission is to enhance the quality of education through technology, supporting successful online learning initiatives across various sectors.


| Project Overview


The project involved generating a list of the 1000 EdTech startups featured in the HolonIQ ranking. This list included links to their LinkedIn profiles. A scraper was developed to extract information from LinkedIn, and additional data was gathered from the startups’ websites, which were saved in text files. This collected information was then used to feed the ChatGPT API with specific prompts. The purpose of these prompts was to build detailed profiles of each company and obtain better answers to questions oriented toward classifying and identifying potential business opportunities for eduNext. This methodology provided a comprehensive and detailed understanding of each startup, facilitating strategic insights for edunext’s market positioning and growth.


| HolonIQ EdTech Ranking Overview


📘 Introduction to HolonIQ

HolonIQ is a global market intelligence firm specializing in the education, climate, and health sectors. Each year, it publishes the Global EdTech 1000 list, which highlights the most promising startups in the educational technology (EdTech) field at both global and regional levels. Sublists include the “Top 200 EdTech in North America,” the “Top 50 EdTech in Australia and New Zealand,” and many more for different regions worldwide.

🔍 How Does the HolonIQ Ranking Work?

Evaluation and Selection:

Evaluation Criteria:

Selection Process:

📊 Importance of the Ranking

These rankings not only highlight the most promising startups but also help connect different regions of the world and share innovations that can improve educational outcomes globally. Promising startups are those that show exceptional potential in terms of innovation, market impact, and growth trajectory, making them key players in driving the future of education. Additionally, they provide investors and other stakeholders with a clear view of emerging trends and the companies leading the change in education.

For more details on HolonIQ rankings and methodologies, you can visit their official website: HolonIQ.


| Methodology


📋 Generate the list with the 1000 companies

The project leveraged a curated list of 1,000 EdTech startups compiled by Holoniq. This list, provided in image format, segmented the startups by geographic region (Africa, Nordic-Baltic, South Asia, etc.). To facilitate further analysis, the initial step involved meticulously extracting key information from each entry. This information included the company name, LinkedIn profile URL, and company website address. The data extraction process was a collaborative effort, requiring manual work from multiple team members. Additionally, support tools like Gemini and GPT-3 were employed to enhance efficiency.

This is an example of the source format of the lists mentioned above.


The Global EdTech 1000 list for this case includes:

We used the 2023 HolonIQ EdTech lists for our analysis.

Once this process was done, the list looked like this:


📋 LinkedIn Scraper

Initially, there were 1,046 companies in the list. After reviewing, it was found that only 937 were unique, as the list was manually compiled by several team members and some entries were duplicated. Of these 937 unique companies, 117 had no LinkedIn page. The LinkedIn scraping process was therefore conducted with 820 companies, yielding 703 successful responses.

The results are summarized in the following table:

Category Number of companies
Total Companies in List 1046
Total Unique Companies 937
Companies without LinkedIn in list 117
Total companies with LinkedIn 820
LinkedIn Retrieved 707
LinkedIn Not Retrieved (Needs Review) 113
LinkedIn Retrieved Webpage 703

The links that could not be retrieved are often in school format rather than company format. Here is an example of the links from which information could not be collected:

Failed Links:

While the links that have company format worked correctly. Here are some examples:

Successful Links:

Company Name URL
byteXL https://in.linkedin.com/company/bytexl
Toodle https://in.linkedin.com/company/toodlerungta
Eupheus Learning https://in.linkedin.com/company/eupheus-learning
10 Minute School https://bd.linkedin.com/company/10ms
Adda247 https://in.linkedin.com/company/adda247
Apars Classroom https://bd.linkedin.com/company/aparsclassroom
EduGorilla https://in.linkedin.com/company/edugorilla-pvt-ltd
Infinity Learn https://in.linkedin.com/company/infinity-learn-by-sri-chaitanya

Note: If you want to see the technical information of the process, please click the button below.

Document Technical Information

This section explains the technical details of how we collected and processed the data. Here is an easy-to-understand breakdown:

  1. Guest Mode: The code acts like a guest browsing LinkedIn, meaning it doesn’t log in but still retrieves the necessary information.
  2. Fetching Data: It fetches web pages from LinkedIn and other company websites to get the HTML content. This content includes all the visible information about a company.
  3. Parsing Data: After getting the HTML content, the code extracts the important details like company name, address, number of employees, and description. This is done using special tools that can read and understand HTML code.
  4. Storing Data: The extracted information is then neatly organized into tables (dataframes) and saved as Excel files. This makes it easy to review and analyze the data later.
  5. Error Handling: If there are any issues while fetching the data, the code tries a few more times before giving up. This ensures that as much data as possible is collected reliably.

This approach allowed us to gather comprehensive information about each company, which was then analyzed to identify potential business opportunities for EduNext.


import jmespath
import asyncio
import json
from typing import List, Dict
from httpx import AsyncClient, Response, RemoteProtocolError
from parsel import Selector
from loguru import logger as log
import pandas as pd
import re
from bs4 import BeautifulSoup
from urllib.parse import urlparse, parse_qs
import os
import time
import requests

# Initialize an async httpx client
client = AsyncClient(
    http2=True,
    headers={
        "Accept-Language": "en-US,en;q=0.9",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding": "gzip, deflate, br",
    },
    follow_redirects=True
)

def strip_text(text):
    """Remove extra spaces while handling None values."""
    return text.strip() if text is not None else text

def get_actual_url(link):
    parsed_url = urlparse(link)
    query_params = parse_qs(parsed_url.query)
    return query_params['url'][0] if 'url' in query_params else link

def parse_company(response_text: str) -> Dict:
    """Parse company main overview page."""
    selector = Selector(response_text)
    script_data = selector.xpath("//script[@type='application/ld+json']/text()").get()
    if script_data:
        script_data = json.loads(script_data)
    else:
        script_data = {}
    script_data = jmespath.search(
        """{
        name: name,
        url: url,
        mainAddress: address,
        description: description,
        numberOfEmployees: numberOfEmployees.value,
        logo: logo
        }""",
        script_data
    ) or {}
    data = {}
    for element in selector.xpath("//div[contains(@data-test-id, 'about-us')]"):
        name = element.xpath(".//dt/text()").get().strip()
        value = element.xpath(".//dd/text()").get().strip()
        data[name] = value
    addresses = []
    for element in selector.xpath("//div[contains(@id, 'address') and @id != 'address-0']"):
        address_lines = element.xpath(".//p/text()").getall()
        address = ", ".join(line.replace("\n", "").strip() for line in address_lines)
        addresses.append(address)
    affiliated_pages = []
    for element in selector.xpath("//section[@data-test-id='affiliated-pages']/div/div/ul/li"):
        affiliated_pages.append({
            "name": element.xpath(".//a/div/h3/text()").get().strip(),
            "industry": strip_text(element.xpath(".//a/div/p[1]/text()").get()),
            "address": strip_text(element.xpath(".//a/div/p[2]/text()").get()),
            "linkeinUrl": element.xpath(".//a/@href").get().split("?")[0]
        })
    similar_pages = []
    for element in selector.xpath("//section[@data-test-id='similar-pages']/div/div/ul/li"):
        similar_pages.append({
            "name": element.xpath(".//a/div/h3/text()").get().strip(),
            "industry": strip_text(element.xpath(".//a/div/p[1]/text()").get()),
            "address": strip_text(element.xpath(".//a/div/p[2]/text()").get()),
            "linkeinUrl": element.xpath(".//a/@href").get().split("?")[0]
        })

    # Additional fields from the second script
    soup = BeautifulSoup(response_text, 'html.parser')
    title_tag = soup.find('title')
    designation_tag = soup.find('h2')
    followers_tag = soup.find('meta', {"property": "og:description"})
    description_tag = soup.find('p', class_='break-words')
    website_tag = soup.find('a', attrs={'data-tracking-control-name': 'about_website'})
    website = get_actual_url(website_tag['href']) if website_tag else "Website not found"
    description_span = soup.find('h4', class_='top-card-layout__second-subline')
    description = description_span.get_text(strip=True) if description_span else "Description not found"
    
    # Crunchbase funding information
    funding_section = soup.find('section', attrs={'data-test-id': 'funding'})
    if funding_section:
        all_rounds_tag = funding_section.find('a', attrs={'data-tracking-control-name': 'funding_all-rounds'})
        if all_rounds_tag:
            all_rounds_match = re.search(r'(\d+ total rounds)', all_rounds_tag.get_text(strip=True))
            all_rounds_info = all_rounds_match.group(1) if all_rounds_match else "All rounds info not found"
        else:
            all_rounds_info = "All rounds info not found"

        last_round_tag = funding_section.find('a', attrs={'data-tracking-control-name': 'funding_last-round'})
        if last_round_tag:
            last_round_info = last_round_tag.find('time').get_text(strip=True)
            last_round_amount_tag = funding_section.find('p', class_='text-display-lg')
            last_round_amount = last_round_amount_tag.get_text(strip=True) if last_round_amount_tag else "Last round amount not found"
            last_round_link = last_round_tag['href']
            last_round_formatted_date = last_round_tag.find('time')['datetime']
        else:
            last_round_info = "Last round info not found"
            last_round_amount = "Last round amount not found"
            last_round_link = "Last round link not found"
            last_round_formatted_date = "Last round date not found"

        investors_tag = funding_section.find('a', attrs={'data-tracking-control-name': 'funding_investors'})
        investors_info = investors_tag.get_text(strip=True) if investors_tag else "Investors info not found"
    else:
        all_rounds_info = "Crunchbase funding info not found"
        last_round_info = "Last round info not found"
        last_round_amount = "Last round amount not found"
        investors_info = "Investors info not found"
        last_round_link = "Last round link not found"
        last_round_formatted_date = "Last round date not found"

    # Check if the tags are found before calling get_text()
    name = title_tag.get_text(strip=True).split("|")[0].strip() if title_tag else "Profile Name not found"
    designation = designation_tag.get_text(strip=True) if designation_tag else "Designation not found"
    followers_match = re.search(r'\b(\d[\d,.]*)\s+followers\b', followers_tag["content"]) if followers_tag else None
    followers_count = followers_match.group(1) if followers_match else "Followers count not found"
    description_profile = description_tag.get_text(strip=True) if description_tag else "Profile Description not found"

    additional_data = {
        "profileName": name,
        "designation": designation,
        "followersCount": followers_count,
        "profileDescription": description_profile,
        "website": website,
        "crunchbaseAllRoundsInfo": all_rounds_info,
        "crunchbaseLastRoundInfo": last_round_info,
        "crunchbaseLastRoundAmount": last_round_amount,
        "crunchbaseInvestorsInfo": investors_info,
        "lastRoundFormattedDate": last_round_formatted_date,
        "crunchbaseLink": last_round_link,
    }

    data = {**script_data, **data, **additional_data}
    data["addresses"] = addresses    
    data["affiliatedPages"] = affiliated_pages
    data["similarPages"] = similar_pages
    return data

def read_links_from_file(file_path: str) -> List[str]:
    """Read URLs from a text or Excel file."""
    if file_path.endswith('.txt'):
        with open(file_path, 'r') as file:
            urls = file.read().splitlines()
    elif file_path.endswith('.xlsx'):
        df = pd.read_excel(file_path)
        urls = df['Links'].tolist()
    else:
        raise ValueError("Unsupported file format. Please use a .txt or .xlsx file.")
    return urls

# Initialize dataframes globally
df_company_info = pd.DataFrame()
df_company_addresses = pd.DataFrame()
df_affiliated_pages = pd.DataFrame()
df_similar_pages = pd.DataFrame()

async def fetch_with_retry(url, retries=3, backoff_factor=0.5):
    for attempt in range(retries):
        try:
            response = await client.get(url)
            return response
        except RemoteProtocolError as e:
            log.error(f"Attempt {attempt + 1} for {url} failed: {e}")
            time.sleep(backoff_factor * (2 ** attempt))
    raise Exception(f"All {retries} attempts failed for {url}")

def fetch_with_requests(url, retries=3, backoff_factor=0.5):
    headers = {
        "User-Agent": "Guest",
    }
    for attempt in range(retries):
        try:
            response = requests.get(url, headers=headers)
            if response.status_code == 200:
                return response
        except requests.RequestException as e:
            log.error(f"Attempt {attempt + 1} for {url} failed: {e}")
            time.sleep(backoff_factor * (2 ** attempt))
    raise Exception(f"All {retries} attempts failed for {url}")

async def scrape_company(urls: List[str]) -> List[Dict]:
    """Scrape public LinkedIn company pages."""
    data = []
    failed_links = []
    for url in urls:
        try:
            response = await fetch_with_retry(url)
            if response.status_code == 200:
                data.append(parse_company(response.text))
                log.success(f"Successfully scraped {url}")
            elif response.status_code == 999:  # Use requests as fallback
                log.warning(f"Status code 999 for {url}, switching to requests")
                response = fetch_with_requests(url)
                if response.status_code == 200:
                    data.append(parse_company(response.text))
                    log.success(f"Successfully scraped {url} with requests fallback")
                else:
                    failed_links.append(url)
                    log.error(f"Failed to scrape {url} with status code {response.status_code}")
            else:
                failed_links.append(url)
                log.error(f"Failed to scrape {url} with status code {response.status_code}")
            # Delay between requests to avoid rate limiting
            time.sleep(1)
        except Exception as e:
            failed_links.append(url)
            log.error(f"Error scraping {url}: {e}")
    return data, failed_links

async def run():
    urls = read_links_from_file('profiles.txt')  # Using the 'profiles.txt' file
    profile_data, failed_links = await scrape_company(urls)
    
    global df_company_info, df_company_addresses, df_affiliated_pages, df_similar_pages

    for company in profile_data:
        main_address = company.get('mainAddress', {})
        company_info = {
            "name": company.get("name"),
            "url": company.get("url"),
            "streetAddress": main_address.get("streetAddress") if main_address else None,
            "addressLocality": main_address.get("addressLocality") if main_address else None,
            "addressRegion": main_address.get("addressRegion") if main_address else None,
            "postalCode": main_address.get("postalCode") if main_address else None,
            "addressCountry": main_address.get("addressCountry") if main_address else None,
            "description": company.get("description"),
            "numberOfEmployees": company.get("numberOfEmployees"),
            "Industry": company.get("Industry"),
            "Company size": company.get("Company size"),
            "Headquarters": company.get("Headquarters"),
            "Type": company.get("Type"),
            "Specialties": company.get("Specialties"),
            "profileName": company.get("profileName"),
            "designation": company.get("designation"),
            "followersCount": company.get("followersCount"),
            "profileDescription": company.get("profileDescription"),
            "website": company.get("website"),
            "crunchbaseAllRoundsInfo": company.get("crunchbaseAllRoundsInfo"),
            "crunchbaseLastRoundInfo": company.get("crunchbaseLastRoundInfo"),
            "crunchbaseLastRoundAmount": company.get("crunchbaseLastRoundAmount"),
            "crunchbaseInvestorsInfo": company.get("crunchbaseInvestorsInfo"),
            "lastRoundFormattedDate": company.get("lastRoundFormattedDate"),
            "crunchbaseLink": company.get("crunchbaseLink"),
        }
        df_company_info = pd.concat([df_company_info, pd.DataFrame([company_info])])

        for address in company.get("addresses", []):
            parts = address.split(", ")
            country = parts[-1] if parts else ""
            company_address = {
                "name": company.get("name"),
                "url": company.get("url"),
                "addresses": address,
                "country offices": country
            }
            df_company_addresses = pd.concat([df_company_addresses, pd.DataFrame([company_address])])

        for affiliated in company.get("affiliatedPages", []):
            affiliated_page = {
                "name": company.get("name"),
                "url": company.get("url"),
                "affiliated_name": affiliated["name"],
                "industry": affiliated["industry"],
                "address": affiliated["address"],
                "linkeinUrl": affiliated["linkeinUrl"]
            }
            df_affiliated_pages = pd.concat([df_affiliated_pages, pd.DataFrame([affiliated_page])])

        for similar in company.get("similarPages", []):
            similar_page = {
                "name": company.get("name"),
                "url": company.get("url"),
                "similar_name": similar["name"],
                "industry": similar["industry"],
                "address": similar["address"],
                "linkeinUrl": similar["linkeinUrl"]
            }
            df_similar_pages = pd.concat([df_similar_pages, pd.DataFrame([similar_page])])

        # Save to Excel after each company
        df_company_info.to_excel("company_information.xlsx", index=False)
        df_company_addresses.to_excel("company_addresses.xlsx", index=False)
        df_affiliated_pages.to_excel("affiliated_pages.xlsx", index=False)
        df_similar_pages.to_excel("similar_pages.xlsx", index=False)

    if failed_links:
        df_failed_links = pd.DataFrame({"failed_links": failed_links})
        df_failed_links.to_excel("failed_links.xlsx", index=False)

if __name__ == "__main__":
    try:
        asyncio.run(run())
    except Exception as e:
        log.error(f"Script terminated due to an error: {e}")

        # Save what has been scraped so far
        if not df_company_info.empty:
            df_company_info.to_excel("company_information.xlsx", index=False)
        if not df_company_addresses.empty:
            df_company_addresses.to_excel("company_addresses.xlsx", index=False)
        if not df_affiliated_pages.empty:
            df_affiliated_pages.to_excel("affiliated_pages.xlsx", index=False)
        if not df_similar_pages.empty:
            df_similar_pages.to_excel("similar_pages.xlsx", index=False)


The data collection and analysis process generates four main outputs.

1. LinkedIn Info

The first is called “LinkedIn Info” and contains the following columns:

Company Name Eupheus Learning
URL https://in.linkedin.com/company/eupheus-learning
Street Address A-12, Mohan Co-operative Industrial Estate
Locality New Delhi
Region New Delhi
Postal Code 110044
Country IN
Description “Eupheus in Greek means -”“Active seeking of knowledge”“​ Our Vision is to offer pedagogically differentiated technology driven solutions that lead to critical thinking and achievement of higher learning outcomes by seamlessly integrating in-class and at home learning in the private school segment of the Pre-K to 12 market. Our aim is to bridge the gap between what is taught in-class using institutional textbook driven solutions and retail at-home learning providers by seamlessly integrating both.”
Number of Employees 275
Industry E-Learning Providers
Company Size 51-200 employees
Headquarters New Delhi, New Delhi
Company Type Privately Held
Specialties Education, K-12, Curricular, E Learning, Pre Primary, Middle School Solutions, Senior School Solutions, Digital Reference Resources, Language Learning, Primary School Solutions, Teacher Support, Age Appropriate Resource, Digital, Learning, Print, Live Books, Fiction e Books, Coding, Kinesthetic Learning, CBSE Aligned Text Book, ICSE Aligned Text Book, Digital Library, Reading Program, Atal Tinkering Lab, and TOEFL
Profile Name Eupheus Learning
Designation E-Learning Providers
Followers Count 9,981
Profile Description “Eupheus in Greek means -”“Active seeking of knowledge”“​ Our Vision is to offer pedagogically differentiated technology driven solutions that lead to critical thinking and achievement of higher learning outcomes by seamlessly integrating in-class and at home learning in the private school segment of the Pre-K to 12 market. Our aim is to bridge the gap between what is taught in-class using institutional textbook driven solutions and retail at-home learning providers by seamlessly integrating both.”
Website https://www.eupheus.in
Crunchbase All Rounds Info 4 total rounds
Crunchbase Last Round Info Oct 14, 2021
Crunchbase Last Round Amount US$ 10.0M
Crunchbase Investors Info Lightrock
Last Round Formatted Date 14/10/2021
Crunchbase Link Crunchbase Link

For more detailed information, you can refer to the complete dataset here.

2. Afilliated Pages LinkedIn

The second output is called “Affiliated Pages LinkedIn” and contains information about affiliated pages (i.e., other pages related to the same company). Below is an example of the data collected:

Name upGrad
URL https://in.linkedin.com/company/ueducation
Affiliated Name upGrad Placements
Industry Human Resources Services
Address
LinkedIn URL https://in.linkedin.com/company/upgrad-placements-

For more detailed information, you can refer to the complete dataset here.

3. Similar Pages LinkedIn

The third output is called “Similar Pages LinkedIn” and contains the similar pages recommended by the LinkedIn algorithm. These are pages that LinkedIn suggests as being similar based on various factors such as industry, company size, and other attributes. Below is an example of the data collected:

Name byteXL
URL https://in.linkedin.com/company/bytexl
Similar Company CODINGCLUB
Industry Education
Address Vadodara, GUJARAT
LinkedIn URL https://in.linkedin.com/company/codingclub36

For more detailed information, you can refer to the complete dataset here.

4. Country Offices Address LinkedIn

The fourth output is called “Country Offices Addresses LinkedIn” and contains information about the different office locations and countries where the company has a presence. Below is an example of the data collected:

Name byteXL
URL https://in.linkedin.com/company/bytexl
Addresses Plano, TX, US
Country Offices US

For more detailed information, you can refer to the complete dataset here.

🪟 Website Scraper

Following the generation of a list containing 1000 ed-tech startups from the HolonIQ list, along with their LinkedIn links, the team proceeded to scrape the information available on LinkedIn. Utilizing the websites retrieved by the LinkedIn scraper (rather than those manually added during the initial list generation to ensure greater accuracy), they developed a scraper for the companies’ web pages. This information was then cleanly written into txt files to capture more comprehensive details about each company.

Note: If you want to see the technical information of the process, please click the button below.

Document Technical Information

This section explains the technical details of how we collected and processed the data. Here is an easy-to-understand breakdown:

  1. Cleaning Text: The clean_text function removes excess whitespace and special characters from the text to make it more readable.
  2. Language Detection: The detect_language_from_html and detect_language functions identify the language of the text, either from the HTML tag or the text content itself.
  3. Fetching HTML Content: The get_html_with_selenium function uses Selenium to load web pages and ensure all content is captured, especially for pages that load content dynamically.
  4. Saving Web Page Content: The save_formatted_webpage_content function retrieves web page content, cleans it, detects the language, and saves it to a text file. If the initial token count is insufficient, it switches to using Selenium for a more thorough scrape.
  5. Handling Requests and Errors: The function handles various exceptions to ensure robustness, including request errors and general exceptions.
  6. Main Processing Loop: The main function reads input data from an Excel file, processes each company’s website, and saves the results and any errors to separate Excel files.

This approach allowed us to gather comprehensive information about each company, which was then analyzed to identify potential business opportunities for EduNext.


import os
import re
import time
import pandas as pd
import requests
from bs4 import BeautifulSoup
from langdetect import detect, LangDetectException
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

from webdriver_manager.chrome import ChromeDriverManager

def clean_text(text):
    text = re.sub(r'\s+', ' ', text)
    text = text.replace('\xa0', ' ')
    return text.strip()

def detect_language_from_html(soup):
    html_tag = soup.find('html')
    if html_tag and html_tag.get('lang'):
        return html_tag['lang']
    else:
        return None

def detect_language(text):
    try:
        return detect(text)
    except LangDetectException:
        return 'unknown'

def get_html_with_selenium(url):
    options = Options()
    options.add_argument("--headless")
    options.add_argument("--disable-gpu")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-features=SameSiteByDefaultCookies")
    options.add_argument("--disable-features=CookiesWithoutSameSiteMustBeSecure")
    options.add_argument("log-level=3")  # Reduce logging output
    
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
    driver.get(url)
    
    try:
        # Wait for the body content to be loaded
        WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.TAG_NAME, 'body')))
        # Scroll to the bottom to ensure all content is loaded
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(5)  # Wait for content to load
        # Additionally, wait for the specific element that indicates the content is fully loaded
        WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH, "//p")))
    except Exception as e:
        print(f"Error waiting for the page to load: {e}")
    
    html_content = driver.page_source
    driver.quit()
    
    return html_content

def save_formatted_webpage_content(url, company_name):
    try:
        print(f"Retrieving content from {url} for {company_name}...")

        response = requests.get(url, timeout=10)
        response.raise_for_status()
        response.encoding = response.apparent_encoding
        html_content = response.text

        soup = BeautifulSoup(html_content, 'html.parser')
        paragraphs = soup.find_all('p')

        paragraph_texts = '\n\n'.join([clean_text(p.get_text()) for p in paragraphs])
        token_count = len(paragraph_texts.split())

        # If the token count is less than 300, use Selenium
        if token_count < 300:
            print(f"Insufficient token count retrieved from {url} using requests. Switching to Selenium...")
            html_content = get_html_with_selenium(url)
            soup = BeautifulSoup(html_content, 'html.parser')
            paragraphs = soup.find_all('p')
            paragraph_texts = '\n\n'.join([clean_text(p.get_text()) for p in paragraphs])
            token_count = len(paragraph_texts.split())

        # Check if HTML content is retrieved
        if not soup.body:
            print(f"No body content found for {company_name} at {url}.")
            return None, None, f"No body content found at {url}"
        
        title = clean_text(soup.title.string) if soup.title else 'No Title Found'
        formatted_content = f"Title: {title}\n\n{paragraph_texts}"

        # Detect language
        language = detect_language_from_html(soup)
        if not language:
            language = detect_language(paragraph_texts)
        
        filepath = os.path.join('webpages', f"{company_name}.txt")
        with open(filepath, 'w', encoding='utf-8') as file:
            file.write(formatted_content)
        
        print(f"Content retrieved and saved for {company_name}. Token count: {token_count}, Language: {language}.")
        return token_count, language, None
    except requests.exceptions.RequestException as req_err:
        print(f"Request error for {company_name}: {req_err}")
        return None, None, f"Request error: {req_err}"
    except Exception as err:
        print(f"Error for {company_name}: {err}")
        return None, None, f"Error: {err}"

def main():
    input_filename = 'cleaned_company_information.xlsx'
    output_data_filename = 'company_token_counts.xlsx'
    output_errors_filename = 'website_errors.xlsx'
    
    # Read the input file
    df = pd.read_excel(input_filename)
    
    # Ensure the 'webpages' directory exists
    if not os.path.exists('webpages'):
        os.makedirs('webpages')
    
    # Lists to store results and errors
    results = []
    errors = []

    # Iterate over the rows in the DataFrame
    for index, row in df.iterrows():
        print(f"Processing {index + 1}/{len(df)}: {row['Company Name']} ({row['Website']})")
        company_name = row['Company Name']
        website = row['Website']
        token_count, language, error = save_formatted_webpage_content(website, company_name)
        
        if token_count is not None:
            results.append({'Company Name': company_name, 'Website': website, 'Token Count': token_count, 'Language': language})
        if error is not None:
            errors.append({'Company Name': company_name, 'Website': website, 'Error': error})
    
    # Save the results to an Excel file
    results_df = pd.DataFrame(results)
    results_df.to_excel(output_data_filename, index=False)
    
    # Save the errors to an Excel file
    errors_df = pd.DataFrame(errors)
    errors_df.to_excel(output_errors_filename, index=False)

    print(f"Process completed. Data saved to {output_data_filename} and errors saved to {output_errors_filename}.")

if __name__ == '__main__':
    main()

  

Following the web scraping process, the output of this part is a folder 📁 containing various txt files, with each file corresponding to a specific company. These files contain detailed information extracted from the companies’ web pages. This approach ensures that all relevant data is captured and organized systematically for further analysis.

As shown in the following example:

🔧 Integration with Chat-GPT

The next step involved integrating with OpenAI using the GPT-3.5 model to leverage the LinkedIn information and the Txt files with website information. These data sources were used to feed the model and answer specific questions designed to build a comprehensive profile of each company. The following questions were asked of the model:

The code leverages additional data from several Excel tables to enrich the analysis:

📄 Role Definitions
Provides detailed definitions for roles like client, partner, competitor, and provider, as well as information about Edunext.

Role Detailed Definitions
Edunext Edunext is the company driving this analysis. It is a software and services company dedicated to the Open edX platform.
CLIENT An entity that is likely to require hosting, maintenance, or professional services for the Open edX platform.
PARTNER An entity that provides instructional design services or a technology aggregator that may subcontract hosting or professional services for the Open edX platform to Edunext, as it is not part of its core business. It can also be an entity that provides a tool for online learning that can be integrated into the Open edX LMS or uses standard interoperability protocols such as LTI.
COMPETITOR An entity that has Open edX hosting, maintenance, or custom development as part of their core business offering and expertise.
PROVIDER An entity that supplies services that may be relevant and useful to Edunext to enhance its value proposition or raise its productivity.

📄 Verticals

These additional sources ensure the accuracy and comprehensiveness of the analysis, allowing the GPT-3.5 model to generate more precise and contextually relevant responses.

Vertical Name Vertical Definition
K-12 Education Technologies and platforms aimed at primary and secondary education.
Higher Education Solutions tailored for colleges, universities, and other tertiary education institutions.
Professional Development & Corporate Training Tools and programs designed for employee training, upskilling, and professional certifications.
Language Learning Apps, platforms, and services focused on teaching new languages.
STEM Education Resources and tools specific to Science, Technology, Engineering, and Mathematics education.
Learning Management Systems (LMS) Platforms that provide a comprehensive management system for learning processes, often used by institutions and corporations.
Tutoring and Mentoring Services and platforms that connect students with tutors and mentors.
Online Courses and MOOCs (Massive Open Online Courses) Platforms offering a variety of courses across different subjects, typically available to a large audience.
Content Creation and Publishing Tools and platforms for creating, sharing, and publishing educational content.
Edutainment Educational tools and resources that incorporate entertainment, such as educational games and interactive learning tools.
Special Education Technologies designed to support learners with special needs.
Assessment and Testing Solutions that focus on student evaluation, testing, and examination.
Early Childhood Education Platforms and tools aimed at pre-K education.
Virtual and Augmented Reality (VR/AR) in Education Immersive technologies used to enhance the learning experience.
Coding and Programming Platforms and tools that teach coding and programming skills.
Collaboration and Communication Tools Solutions that facilitate communication and collaboration among students, teachers, and parents.
School Administration and Management Systems designed to manage school operations, such as attendance, grades, and resource planning.
Educational Hardware Devices and physical technologies used in educational settings, like tablets, interactive whiteboards, and robotics kits.
Adaptive Learning Technologies that use data and analytics to personalize the learning experience.
EdTech Infrastructure Backend technologies and services that support educational platforms and tools, like cloud services, data management, and cybersecurity solutions.

📄 Capabilities

The following list of capabilities was used to analyze the potential and competencies of each company. These capabilities are categorized under main categories and sub-categories to ensure a comprehensive evaluation. The list is based on the HolonIQ framework, which can be found at Digital Capability Framework. The image provided below, sourced from HolonIQ, illustrates these capabilities. However, the list below has been reformatted for ease of understanding and to ensure better performance when processed by the ChatGPT algorithm.

The list shown below is a reinterpretation of the previous image to categorize the capabilities and be able to pass them through the gpt chat api, so that it could be interpreted in a more understandable way and in text format.

Main Category Sub-Category Capability
DEMAND AND DISCOVERY PRODUCT STRATEGY MARKET INSIGHTS & TRENDS
DEMAND AND DISCOVERY PRODUCT STRATEGY UNDERSTAND CUSTOMER NEEDS
DEMAND AND DISCOVERY PRODUCT STRATEGY COMPETITORS & ALTERNATES
DEMAND AND DISCOVERY PRODUCT STRATEGY NEW BUSINESS MODELS
DEMAND AND DISCOVERY PRODUCT STRATEGY B2B RECRUITMENT & PARTNERSHIPS
DEMAND AND DISCOVERY MARKETING PROCESSES STUDENT RELATIONSHIP MANAGEMENT (CRM)
DEMAND AND DISCOVERY MARKETING PROCESSES COMMS & CAMPAIGN MANAGEMENT
DEMAND AND DISCOVERY MARKETING PROCESSES MARKETING AUTOMATION
DEMAND AND DISCOVERY MARKETING PROCESSES SOCIAL MEDIA & COMMUNITY MANAGEMENT
DEMAND AND DISCOVERY STUDENT RECRUITMENT RECRUITMENT EVENTS
DEMAND AND DISCOVERY STUDENT RECRUITMENT CHANNEL PARTNERSHIPS
DEMAND AND DISCOVERY STUDENT RECRUITMENT SCHOOLS & COMMUNITY OUTREACH
DEMAND AND DISCOVERY STUDENT RECRUITMENT SCHOLARSHIP PROGRAM
DEMAND AND DISCOVERY ENROLLMENT MANAGEMENT COURSE SELECTION & GUIDANCE
DEMAND AND DISCOVERY ENROLLMENT MANAGEMENT APPLICATION & ADMISSIONS
DEMAND AND DISCOVERY ENROLLMENT MANAGEMENT RECOGNIZING PRIOR LEARNING
DEMAND AND DISCOVERY ENROLLMENT MANAGEMENT TUITION FINANCING
LEARNING DESIGN CURRICULUM DESIGN DIGITAL DESIGN PRINCIPLES
LEARNING DESIGN CURRICULUM DESIGN PROGRAM ARCHITECTURE
LEARNING DESIGN CURRICULUM DESIGN LEARNING ENVIRONMENTS & PLATFORMS
LEARNING DESIGN CURRICULUM DESIGN LEARNING DELIVERY MODELS
LEARNING DESIGN CURRICULUM DESIGN ACCREDITATION
LEARNING DESIGN CURRICULUM DESIGN CURRICULUM QUALITY MANAGEMENT
LEARNING DESIGN DIGITAL CONTENT & COURSEWARE DIGITAL CONTENT CREATION
LEARNING DESIGN DIGITAL CONTENT & COURSEWARE IMMERSION, SIMULATION & LAB
LEARNING DESIGN DIGITAL CONTENT & COURSEWARE OER & CONTENT LICENSING
LEARNING DESIGN DIGITAL CONTENT & COURSEWARE MANAGING INTEGRATED CONTENT
LEARNING DESIGN SUBJECT MATTER EXPERTISE DESIGNING FOR DIGITAL LEARNING
LEARNING DESIGN SUBJECT MATTER EXPERTISE FACULTY EXPERTISE & SPECIALISMS
LEARNING DESIGN SUBJECT MATTER EXPERTISE SOURCING & MANAGING EXPERTISE
LEARNING DESIGN SUBJECT MATTER EXPERTISE SPECIALIST INDUSTRY PARTNERS
LEARNING DESIGN TEACHING STRATEGIES LEARNER NEEDS & ANALYTICS
LEARNING DESIGN TEACHING STRATEGIES DESIGNING ASSESSMENT
LEARNING DESIGN TEACHING STRATEGIES EXPERIENTIAL LEARNING APPROACHES
LEARNING DESIGN TEACHING STRATEGIES DESIGNING GROUP WORK
LEARNING DESIGN TEACHING STRATEGIES PERSONALIZED & ADAPTIVE LEARNING
LEARNER EXPERIENCE ACADEMIC ADMINISTRATION FACULTY PROFESSIONAL DEVELOPMENT
LEARNER EXPERIENCE ACADEMIC ADMINISTRATION FACULTY MANAGEMENT & SUPPORT
LEARNER EXPERIENCE ACADEMIC ADMINISTRATION TIMETABLING & SCHEDULE MANAGEMENT
LEARNER EXPERIENCE ACADEMIC ADMINISTRATION RETENTION & LEARNING SUPPORT
LEARNER EXPERIENCE ACADEMIC ADMINISTRATION REPORTING & REGULATORY COMPLIANCE
LEARNER EXPERIENCE ACADEMIC ADMINISTRATION LIBRARY SERVICES
LEARNER EXPERIENCE LEARNING & ACADEMIC EXPERIENCE STUDENT PORTAL & LMS
LEARNER EXPERIENCE LEARNING & ACADEMIC EXPERIENCE SYNCHRONOUS LEARNING EXPERIENCES
LEARNER EXPERIENCE LEARNING & ACADEMIC EXPERIENCE ASYNCHRONOUS LEARNING EXPERIENCES
LEARNER EXPERIENCE LEARNING & ACADEMIC EXPERIENCE VOICE, CHAT & INTERACTIVE LEARNING
LEARNER EXPERIENCE LEARNING & ACADEMIC EXPERIENCE INDEPENDENT LEARNING RESOURCES
LEARNER EXPERIENCE LEARNING & ACADEMIC EXPERIENCE EXCHANGE PROGRAMS
LEARNER EXPERIENCE STUDENT LIFE ONBOARDING & ORIENTATION
LEARNER EXPERIENCE STUDENT LIFE WELLBEING & MENTAL HEALTH
LEARNER EXPERIENCE STUDENT LIFE STUDENT COMMUNITIES, CLUBS & SOCIETIES
LEARNER EXPERIENCE STUDENT LIFE VOLUNTEERING & STUDENT LEADERSHIP
LEARNER EXPERIENCE STUDENT LIFE STUDENT VOICE & SURVEYS
LEARNER EXPERIENCE STUDENT LIFE GRADUATION & SUCCESS
LEARNER EXPERIENCE ASSESSMENT & VERIFICATION TESTS & EXAMS
LEARNER EXPERIENCE ASSESSMENT & VERIFICATION PORTFOLIOS & PRACTICAL
LEARNER EXPERIENCE ASSESSMENT & VERIFICATION ASSESSMENT FEEDBACK
LEARNER EXPERIENCE ASSESSMENT & VERIFICATION PEER & GROUP ASSESSMENT
LEARNER EXPERIENCE ASSESSMENT & VERIFICATION BADGING & CREDENTIALING
WORK AND LIFELONG LEARNING WORK INTEGRATED LEARNING EMPLOYABILITY SKILLS BUILDING
WORK AND LIFELONG LEARNING WORK INTEGRATED LEARNING WORKPLACE SIMULATION & PROJECTS
WORK AND LIFELONG LEARNING WORK INTEGRATED LEARNING INTERNSHIPS & PLACEMENTS
WORK AND LIFELONG LEARNING WORK INTEGRATED LEARNING STUDENT WORK
WORK AND LIFELONG LEARNING WORK INTEGRATED LEARNING ENTREPRENEURSHIP & STARTUPS
WORK AND LIFELONG LEARNING CAREER PLANNING & PLACEMENT COMPETENCIES & SKILLS EVALUATION
WORK AND LIFELONG LEARNING CAREER PLANNING & PLACEMENT CAREER PLANNING SERVICES
WORK AND LIFELONG LEARNING CAREER PLANNING & PLACEMENT CAREER & RECRUITMENT EVENTS
WORK AND LIFELONG LEARNING CAREER PLANNING & PLACEMENT JOB APPLICATION SUPPORT
WORK AND LIFELONG LEARNING CAREER PLANNING & PLACEMENT JOB FINDING & GRADUATE PLACEMENT
WORK AND LIFELONG LEARNING INDUSTRY & BUSINESS ENGAGEMENT INDUSTRY COLLABS & PARTNERSHIPS
WORK AND LIFELONG LEARNING INDUSTRY & BUSINESS ENGAGEMENT PROFESSIONAL & INDUSTRY ASSOCIATIONS
WORK AND LIFELONG LEARNING INDUSTRY & BUSINESS ENGAGEMENT CUSTOMIZED PROGRAMS (B2B)
WORK AND LIFELONG LEARNING INDUSTRY & BUSINESS ENGAGEMENT EDUCATION AS EMPLOYEE BENEFIT
WORK AND LIFELONG LEARNING ALUMNI & CONTINUING EDUCATION CONTINUING EDUCATION
WORK AND LIFELONG LEARNING ALUMNI & CONTINUING EDUCATION INDUSTRY MENTORING & NETWORKS
WORK AND LIFELONG LEARNING ALUMNI & CONTINUING EDUCATION ALUMNI ENGAGEMENT

Note: If you want to see the technical information of the process, please click the button below.

Document Technical Information

This section explains the technical details of how we collected and processed the data. Here is an easy-to-understand breakdown:

  1. OpenAI API Interaction: The query_openai_api function handles the interaction with the OpenAI API, including retry logic to manage errors.
  2. Role Categorization: The categorize_potential_role function determines the potential role of the company (client, partner, competitor, or provider) based on the API response.
  3. Vertical Categorization: The categorize_potential_vertical function identifies the appropriate vertical for the company from a predefined list.
  4. Capability Extraction and Validation: The extract_and_validate_capabilities function extracts and validates the capabilities of the company, ensuring exactly five unique capabilities.
  5. Company Processing: The process_company_column function processes each company’s data, constructs prompts, queries the API, and compiles the results.
  6. Progress Saving: The save_progress function periodically saves the progress of the analysis to an Excel file.
  7. Main Processing Loop: The script processes each company in the dataset, reads webpage content, handles errors, and saves the final results to an Excel file.

This approach allowed us to gather comprehensive information about each company, which was then analyzed to identify potential business opportunities for EduNext.


import openai
import pandas as pd
import logging
import time
from random import random
import os

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Set your OpenAI API key
openai.api_key = 'ADD THE KEY'

# Load the LinkedIn data
linkedIn_data = pd.read_excel('cleaned_company_information.xlsx', skiprows=range(1, 660))

# Load the capabilities data
capabilities_data = pd.read_excel('Input/capabilities.xlsx')
valid_capabilities = set(capabilities_data['Capability'].str.upper().tolist())

# Load the role definitions
role_definitions = pd.read_excel('Input/company_profile.xlsx')

# Load the vertical data
vertical_data = pd.read_excel('Input/vertical.xlsx')

# Define valid roles and verticals
valid_roles = ['CLIENT', 'PARTNER', 'COMPETITOR', 'PROVIDER']
valid_verticals = vertical_data['Vertical'].tolist()

# Prepare the output DataFrame
output_columns = [
    'Company Name', 'URL (LinkedIn profile link)', 'Website', 'OpenedX Connection',
    'Main Product', 'Competitors', 'Customers', 'B2B or B2C',
    'Number of Customers', 'Country', 'Potential Role', 'Potential Vertical',
    'Capability 1', 'Capability 2', 'Capability 3', 'Capability 4', 'Capability 5'
]

output_data = pd.DataFrame(columns=output_columns)
backup_interval = 10  # Save progress every 10 companies

# Function to query OpenAI API with retry logic
def query_openai_api(prompt, model="gpt-3.5-turbo", max_tokens=512, retries=5):
    for i in range(retries):
        try:
            response = openai.ChatCompletion.create(
                model=model,
                messages=[
                    {"role": "system", "content": "You are an assistant that helps analyze company data."},
                    {"role": "user", "content": prompt}
                ],
                max_tokens=max_tokens,
                temperature=0.7
            )
            return response.choices[0].message['content'].strip()
        except openai.error.OpenAIError as e:
            logging.error(f"APIError encountered: {e}. Retrying {i + 1}/{retries}...")
            time.sleep((2 ** i) + random())
    return "API request failed."

# Function to categorize potential role
def categorize_potential_role(response):
    response = response.lower()
    if "client" in response:
        return "CLIENT"
    if "partner" in response:
        return "PARTNER"
    if "competitor" in response:
        return "COMPETITOR"
    if "provider" in response:
        return "PROVIDER"
    return ""

# Function to categorize potential vertical
def categorize_potential_vertical(response):
    verticals = vertical_data['Vertical'].tolist()
    for vertical in verticals:
        if vertical.lower() in response.lower():
            return vertical
    return ""

# Function to ensure the capabilities list has exactly 5 unique entries
def ensure_unique_capabilities(capabilities):
    unique_capabilities = list(dict.fromkeys(capabilities))  # Remove duplicates while preserving order
    while len(unique_capabilities) < 5:
        remaining_capabilities = list(valid_capabilities - set(unique_capabilities))
        if remaining_capabilities:
            unique_capabilities.append(remaining_capabilities[0])  # Add a remaining valid capability
        else:
            unique_capabilities.append('')  # If no valid capabilities are left, append an empty string
    return unique_capabilities[:5]

# Function to extract and validate capabilities
def extract_and_validate_capabilities(response, company_name):
    capabilities = []
    logging.debug(f"Raw API capabilities response for {company_name}: {response}")
    for line in response.split('\n'):
        for capability in valid_capabilities:
            if capability.lower() in line.lower() and capability not in capabilities:
                capabilities.append(capability)
                break
    validated_capabilities = ensure_unique_capabilities(capabilities)
    logging.debug(f"Validated capabilities for {company_name}: {validated_capabilities}")
    return validated_capabilities

# Function to process each company and column
def process_company_column(company_info, webpage_content):
    base_prompt = f"Company LinkedIn Info:\n{company_info}\n\nCompany Webpage Content:\n{webpage_content}\n\n"
    capabilities_list = ', '.join(valid_capabilities)

    # Constructing more detailed prompts with additional context
    prompts = {
        'OpenedX Connection': base_prompt + "Taking into account the information provided and your knowledge about the company, does the company have any connection or use the Open edX platform?",
        'Main Product': base_prompt + "Taking into account the information provided and your knowledge about the company, what is the main product or service the company offers?",
        'Competitors': base_prompt + "Taking into account the information provided and your knowledge about the company, list three main competitors of the company including their names and websites.",
        'Customers': base_prompt + "Taking into account the information provided and your knowledge about the company, list three main customers of the company.",
        'B2B or B2C': base_prompt + "Taking into account the information provided and your knowledge about the company, is the company primarily focused on B2B (business-to-business) or B2C (business-to-consumer) operations?",
        'Number of Customers': base_prompt + "Taking into account the information provided and your knowledge about the company, estimate the number of customers the company has.",
        'Country': base_prompt + "Taking into account the information provided and your knowledge about the company, in which country does the company primarily operate?",
        'Potential Role': base_prompt + "Taking into account the information provided and your knowledge about the company, determine if the company is a potential client, partner, competitor, or provider for Edunext.",
        'Potential Vertical': base_prompt + "Taking into account the information provided and your knowledge about the company, determine the potential vertical for the company from the following list:\n" +
            '\n'.join([f"{row['Vertical']} - {row['Definition']}" for _, row in vertical_data.iterrows()]) + "\nWhat is the potential vertical of this company?",
        'Capability 1': base_prompt + f"Based on the provided information and any additional research, what is the primary capability of the company? Choose from the following: {capabilities_list}",
        'Capability 2': base_prompt + f"Considering the capabilities already mentioned, what is the second main capability of the company? Choose from the following: {capabilities_list}",
        'Capability 3': base_prompt + f"Considering the capabilities already mentioned, what is the third main capability of the company? Choose from the following: {capabilities_list}",
        'Capability 4': base_prompt + f"Considering the capabilities already mentioned, what is the fourth main capability of the company? Choose from the following: {capabilities_list}",
        'Capability 5': base_prompt + f"Considering the capabilities already mentioned, what is the fifth main capability of the company? Choose from the following: {capabilities_list}"
    }
    
    responses = {key: query_openai_api(prompt) for key, prompt in prompts.items()}

    # Log raw responses for debugging
    logging.debug(f"Raw API response for company {company_info['Company Name']}: {responses}")

    # Extract and validate capabilities
    capabilities = extract_and_validate_capabilities("\n".join([responses.get(f'Capability {i}', '') for i in range(1, 6)]), company_info['Company Name'])

    output_row = {
        'Company Name': company_info['Company Name'],
        'URL (LinkedIn profile link)': company_info['URL'],
        'Website': company_info['Website'],
        'OpenedX Connection': responses['OpenedX Connection'],
        'Main Product': responses['Main Product'],
        'Competitors': responses['Competitors'],
        'Customers': responses['Customers'],
        'B2B or B2C': "B2B" if "B2B" in responses['B2B or B2C'] else "B2C",
        'Number of Customers': responses['Number of Customers'],
        'Country': responses['Country'].strip(),
        'Potential Role': categorize_potential_role(responses['Potential Role']),
        'Potential Vertical': categorize_potential_vertical(responses['Potential Vertical']),
        'Capability 1': capabilities[0],
        'Capability 2': capabilities[1],
        'Capability 3': capabilities[2],
        'Capability 4': capabilities[3],
        'Capability 5': capabilities[4]
    }

    return output_row

# Function to save progress periodically
def save_progress(data, filename='company_analysis_backup.xlsx'):
    df = pd.DataFrame(data, columns=output_columns)
    df.to_excel(filename, index=False)
    logging.info(f"Progress saved to {filename}")

# Process companies sequentially with logging
results = []
for idx, row in linkedIn_data.iterrows():
    company_info = row.to_dict()
    company_name = company_info['Company Name']
    logging.info(f"Processing company: {company_name}")

    try:
        # Try to read the webpage content for the company, handle missing or invalid files
        webpage_content = ""
        filepath = os.path.join('webpages', f"{company_name}.txt")
        try:
            with open(filepath, 'r', encoding='utf-8') as file:
                webpage_content = file.read()
        except (FileNotFoundError, OSError) as e:
            logging.warning(f"Could not read file for {company_name}: {e}")
        
        output_row = process_company_column(company_info, webpage_content)
        results.append(output_row)
        logging.info(f"Completed processing for {company_name} ({idx + 1}/{len(linkedIn_data)})")
        
        # Save progress periodically
        if (idx + 1) % backup_interval == 0:
            save_progress(results)

    except Exception as e:
        logging.error(f"Error processing company {company_name}: {e}")

# Save final results
output_data = pd.DataFrame(results, columns=output_columns)
output_data.to_excel('company_analysis.xlsx', index=False)
logging.info("All companies processed and saved to company_analysis.xlsx")
  

Company Information Output

The fourth output is called “Company Information Output” and contains detailed information about various analyzed companies. Below is an example of the data collected:

Company Name byteXL
URL (LinkedIn profile link) https://in.linkedin.com/company/bytexl
Website https://bytexl.com
OpenedX Connection Based on the information provided, there is no direct mention of the company byteXL using or having a connection with the Open edX platform. The company’s focus seems to be on transforming engineering colleges in India through their own integrated college transformation model and proprietary platform, rather than utilizing external platforms like Open edX.
Main Product Based on the information provided from the company’s LinkedIn profile and webpage content, the main product or service offered by byteXL is an experiential learning online platform for IT programming aspirants. This platform integrates curriculum, content, and practical learning to enhance students’ skills and awareness on employability. The company partners with colleges to transform their teaching methodology and learning pedagogy to increase the employability quotient of their students. The platform includes features such as academic & skilling content, online editor, student reports, dashboards on individual college performance, and coding challenges.
Competitors Based on the information provided about byteXL, three main competitors of the company in the E-learning industry could be:

1. Company Name: UpGrad
Website: https://www.upgrad.com/

2. Company Name: Simplilearn
Website: https://www.simplilearn.com/

3. Company Name: Coursera
Website: https://www.coursera.org/
Customers Based on the information provided, three main customers of byteXL are:

1. Tejashri Student from Malineni Lakshmaiah Women’s Engineering College

2. A. Sanyasirao, Head of Electronics & Communication Engineering Department at Christu Jyothi Institute of Technology & Science

3. Kalyani, a student of Malineni Lakshmaiah Women’s Engineering College

These customers have shared their positive experiences with byteXL’s teaching methodology and its impact on their academic journey and career prospects.
B2B or B2C B2B
Number of Customers Based on the content provided, it seems like byteXL has several customers who are students and colleges across India. The webpage content mentions testimonials and success stories from students and faculty at various engineering colleges who have benefited from byteXL’s training and mentorship programs.

While the exact number of customers is not explicitly mentioned in the data provided, we can infer that the company has a significant customer base across multiple colleges and individual students. The testimonials and success stories highlight the impact byteXL has had on students’ academic journeys and career paths, indicating a wide reach and positive reputation among customers.

Therefore, based on the information available, we can estimate that byteXL likely has hundreds or even thousands of customers consisting of both colleges and individual students who have engaged with their educational programs and services.
Country The company, byteXL, primarily operates in India. This is indicated by the company’s headquarters being in Hyderabad, India, the focus on transforming engineering colleges in India, partnerships with Indian colleges such as Malineni Lakshmaiah Women’s Engineering College and Christu Jyothi Institute of Technology & Science, and the testimonials and success stories from Indian students and educational institutions. The company’s efforts and impact are centered around the Indian education system and industry, supporting the employability and skills development of Indian engineering students.
Country Only India
Potential Role CLIENT
Potential Vertical Higher Education
Capability 1 PERSONALIZED & ADAPTIVE LEARNING
Capability 2 WORKPLACE SIMULATION & PROJECTS
Capability 3 IMMERSION, SIMULATION & LAB
Capability 4 VOLUNTEERING & STUDENT LEADERSHIP
Capability 5 DIGITAL DESIGN PRINCIPLES

For more detailed information, you can refer to the complete dataset here.


| Analysis and Results

With the data resulting from this exercise, the analysis begins with geographical insights. The first part will focus on the number of startups by country, while the second part will analyze the amount of investment. The geographical location in these charts is provided by LinkedIn, indicating where the company is based, and the investment data also comes from LinkedIn information in conjunction with Crunchbase. It is important to note that not all companies have this information available, and not all investments were made in this or the past year. To verify the date of investment by company, this link can be consulted: Investment Date Verification

Number of startups

The first map provides a visual representation of the number of startups by country based on data sourced from LinkedIn. The map uses a gradient color scale to indicate the density of startups in each country, with lighter shades of blue representing fewer startups and darker shades of blue indicating a higher number of startups.


The second map illustrates the number of startups by country, categorized by their estimated size based on employee count from LinkedIn data. Startups are classified into Small, Medium, Large, and Very Large using employee quartiles. The map features interactive tooltips with country names, estimated sizes, and startup counts. Bubble sizes indicate the number of startups, while colors (Yellow for Small, Orange for Medium, Red for Large, Dark Red for Very Large, and Grey for Unknown) represent size categories. This visualization helps identify the distribution of different-sized startups globally, emphasizing regions with diverse entrepreneurial activities.

Estimated Size Definition
Small Employees ≤ 1st quartile
Medium 1st quartile < Employees ≤ 2nd quartile
Large 2nd quartile < Employees ≤ 3rd quartile
Very Large Employees > 3rd quartile
Unknown Missing employee data
Size based on number of employees
Country Small Medium Large Very Large Unknown Total
United States 60 35 0 50 36 181
India 10 4 0 43 3 60
United Kingdom 13 18 0 10 15 56
Unknown 5 8 1 4 9 27
Brazil 5 7 0 4 9 25
Germany 7 7 0 4 3 21
France 5 6 0 3 7 21
Singapore 6 4 0 4 7 21
Canada 4 4 0 3 7 18
Spain 1 1 0 4 9 15
Mexico 4 4 0 5 1 14
Egypt 5 3 0 2 3 13
Nigeria 3 2 0 1 7 13
South Africa 3 3 0 1 6 13
Sweden 1 3 0 2 6 12
Finland 0 4 1 1 5 11
Italy 4 4 0 1 0 9
Indonesia 0 1 0 6 1 8
South Korea 2 3 1 1 1 8
Norway 0 3 1 0 4 8
Vietnam 3 0 0 4 1 8
United Arab Emirates 3 2 1 1 0 7
Colombia 2 3 0 1 1 7
Switzerland 2 3 0 0 1 6
Kenya 1 1 0 0 4 6
Netherlands 3 2 0 0 1 6
Saudi Arabia 1 1 0 3 1 6
Bangladesh 0 2 0 3 0 5
Ireland 0 1 0 2 2 5
Israel 0 2 0 0 3 5
Argentina 0 2 0 2 0 4
Chile 0 1 0 0 3 4
China 0 2 0 1 1 4
Hungary 0 1 0 1 2 4
Japan 1 1 0 0 2 4
Pakistan 4 0 0 0 0 4
Poland 1 2 0 1 0 4
Austria 0 1 0 1 1 3
Denmark 0 0 0 2 1 3
Iceland 0 0 0 0 3 3
Jordan 1 0 0 2 0 3
Kazakhstan 0 2 0 0 1 3
Portugal 1 1 0 0 1 3
Belgium 1 0 0 0 1 2
Cameroon 0 1 0 0 1 2
Estonia 0 1 0 0 1 2
Kuwait 1 0 0 0 1 2
Lithuania 0 0 0 0 2 2
Malaysia 2 0 0 0 0 2
Peru 0 1 0 0 1 2
Romania 0 2 0 0 0 2
Tunisia 0 0 0 0 2 2
Taiwan 0 2 0 0 0 2
Tanzania 0 1 0 0 1 2
Ukraine 0 0 0 1 1 2
Venezuela 0 1 0 0 1 2
Australia 1 0 0 0 0 1
Bahrain 0 1 0 0 0 1
Congo - Kinshasa 1 0 0 0 0 1
Costa Rica 0 0 0 0 1 1
Czechia 0 0 0 0 1 1
Dominican Republic 0 0 0 0 1 1
Ecuador 0 1 0 0 0 1
Ghana 0 0 0 0 1 1
Greece 0 1 0 0 0 1
Lebanon 0 1 0 0 0 1
Morocco 0 1 0 0 0 1
Madagascar 1 0 0 0 0 1
Panama 0 0 0 0 1 1
Philippines 0 1 0 0 0 1
Thailand 1 0 0 0 0 1
Uzbekistan 1 0 0 0 0 1
Amount of investments

The chart is built using data from LinkedIn, listing countries where offices are based and the last round of investment amounts. This chart shows the sum of all money invested in startups by country, providing a visual representation of global investment distribution. Each country is colored based on the total investment amount, with interactive tooltips offering detailed information about the investments.


This interactive map visualizes the median investment in startups by country based on data from LinkedIn. The map uses the median to avoid the impact of outliers. China is highlighted in violet because it is an outlier, with only one company providing information on the last investment round, which was exceptionally large. The gradient color scale from red to yellow to green indicates low to high median investments in millions of dollars, allowing for a clear comparison of investment levels across countries.


This map illustrates the number of startups by country, categorized by their estimated investment size based on data from LinkedIn. Investment sizes are classified into Small, Medium, Large, and Very Large using quartiles of the last round investment amounts. The map features interactive tooltips with country names and estimated investment sizes. Bubble sizes indicate the number of startups, while colors (Light Green for Small, Green for Medium, Dark Green for Large, Forest Green for Very Large, and Grey for Unknown) represent investment size categories. This visualization helps identify the distribution of startups with varying investment sizes globally, highlighting regions with diverse levels of startup funding.

Estimated Investment Size Definition
Small Investment ≤ 1st quartile
Medium 1st quartile < Investment ≤ 2nd quartile
Large 2nd quartile < Investment ≤ 3rd quartile
Very Large Investment > 3rd quartile
Unknown Missing investment data

Size based on last round amount
Country Small Medium Large Very Large Unknown Total
United States 23 14 32 0 50 119
India 11 9 8 0 10 38
United Kingdom 9 8 13 0 6 36
Germany 5 2 3 0 4 14
France 4 3 5 0 1 13
Canada 4 1 1 0 6 12
Unknown 4 1 3 0 2 10
Spain 2 4 0 0 3 9
Brazil 4 1 1 1 0 7
Singapore 2 1 1 0 3 7
South Korea 2 0 4 0 0 6
Mexico 1 1 2 0 2 6
Egypt 0 4 1 0 0 5
Israel 1 2 2 0 0 5
Italy 2 1 2 0 0 5
Sweden 1 1 2 0 1 5
Colombia 1 2 1 0 0 4
Nigeria 1 3 0 0 0 4
Netherlands 2 2 0 0 0 4
Vietnam 0 0 4 0 0 4
Denmark 0 1 0 0 2 3
Finland 1 1 0 0 1 3
Hungary 0 3 0 0 0 3
Indonesia 1 0 1 0 1 3
Japan 0 1 1 0 1 3
Norway 1 1 1 0 0 3
Portugal 2 1 0 0 0 3
South Africa 0 3 0 0 0 3
United Arab Emirates 1 1 0 0 0 2
Bangladesh 0 1 1 0 0 2
Belgium 0 0 2 0 0 2
Chile 0 2 0 0 0 2
Estonia 0 1 1 0 0 2
Ireland 0 2 0 0 0 2
Kenya 0 2 0 0 0 2
Malaysia 1 1 0 0 0 2
Pakistan 2 0 0 0 0 2
Poland 2 0 0 0 0 2
Romania 0 2 0 0 0 2
Saudi Arabia 1 1 0 0 0 2
Tunisia 0 2 0 0 0 2
Congo - Kinshasa 0 1 0 0 0 1
Switzerland 0 0 1 0 0 1
China 0 0 0 0 1 1
Costa Rica 0 1 0 0 0 1
Czechia 0 1 0 0 0 1
Ghana 0 1 0 0 0 1
Iceland 0 1 0 0 0 1
Jordan 0 0 0 0 1 1
Kuwait 1 0 0 0 0 1
Kazakhstan 1 0 0 0 0 1
Madagascar 0 1 0 0 0 1
Peru 0 1 0 0 0 1
Thailand 1 0 0 0 0 1
Taiwan 0 0 1 0 0 1
Uzbekistan 0 1 0 0 0 1
Venezuela 0 1 0 0 0 1


Time analysis

📄 By country

Number of startups

This stacked bar chart illustrates the number of companies receiving investments each year, broken down by country. Each bar represents a year, and the different colored segments within each bar denote the number of companies from various countries that received investments in that particular year. The legend on the right-hand side identifies the countries corresponding to each color. This visualization helps track investment trends over time and highlights which countries have seen increasing or decreasing investment activity in the EdTech sector.

Amount of investments

This stacked bar chart illustrates the total amount of investment received by companies each year, broken down by country. Each bar represents a year, and the different colored segments within each bar denote the total investment received by companies from various countries in that particular year. The legend on the right-hand side identifies the countries corresponding to each color. This visualization helps track investment trends over time and highlights which countries have received the most significant financial investments in the EdTech sector.


📄 By Vertical

Number of startups

This stacked bar chart displays the number of companies by year, categorized by verticals. Each bar represents a year, and the different colored segments within each bar denote the number of companies within specific verticals for that particular year. The legend on the right-hand side identifies the verticals corresponding to each color. This visualization helps track trends over time and highlights the growth or decline of companies within each vertical in the EdTech sector.

Note: The verticals were defined and selected by the EduNext team, and the detailed definitions of these verticals are provided earlier in the report.

Amount of investment

This stacked bar chart displays the total amount of investment by year, categorized by verticals. Each bar represents a year, and the different colored segments within each bar denote the total investment received by companies within specific verticals for that particular year. The legend on the right-hand side identifies the verticals corresponding to each color. This visualization helps track investment trends over time and highlights the growth or decline of investment within each vertical in the EdTech sector.

Note: The verticals were defined and selected by the EduNext team, and the detailed definitions of these verticals are provided earlier in the report.


📄 By B2B or B2C

Number of startups

This stacked bar chart illustrates the number of companies making investments each year, categorized by their business model: B2B (Business to Business) and B2C (Business to Consumer). Each bar represents a year, and the different colored segments within each bar denote the number of companies in each category for that particular year. The legend on the right-hand side identifies the categories corresponding to each color. This visualization helps track investment activity trends over time, highlighting the dynamics between B2B and B2C companies in the EdTech sector.

Amount of investment

This stacked bar chart illustrates the total amount of investment by year, categorized by business model: B2B (Business to Business) and B2C (Business to Consumer). Each bar represents a year, and the different colored segments within each bar denote the total investment received by companies in each category for that particular year. The legend on the right-hand side identifies the categories corresponding to each color. This visualization helps track investment trends over time, highlighting the dynamics between B2B and B2C companies in the EdTech sector.

📄 By Industry

Number of startups

This treemap chart displays the distribution of companies by industry, based on the information available on their LinkedIn profiles. Each rectangle represents an industry, with the size of the rectangle proportional to the number of companies in that industry. The color and size of the rectangles provide a quick visual reference for the prevalence of different industries among the analyzed companies. This visualization helps to identify which industries are most common in the EdTech sector and how companies are distributed across various fields.

Note: According to LinkedIn, EduNext operates in the E-learning industry. This classification is based on the information available on their LinkedIn profile.

Amount of investment

This treemap chart displays the distribution of investment by industry, based on the information available on the companies’ LinkedIn profiles. Each rectangle represents an industry, with the size of the rectangle proportional to the total investment received by companies in that industry. The color and size of the rectangles provide a quick visual reference for the allocation of investments across different industries among the analyzed companies. This visualization helps to identify which industries attract the most investment in the EdTech sector.

Note: According to LinkedIn, EduNext operates in the E-learning industry. This classification is based on the information available on their LinkedIn profile.

📄 By Role

Role

This donut chart visualizes the distribution of potential roles identified for companies, based on their relevance to EduNext. The chart segments represent the percentage of companies classified as partners, clients, competitors, and providers. The legend indicates the role corresponding to each color. This visualization helps to understand the predominant roles among the analyzed companies.

Note: The EduNext team chose the roles and definitions for each role.

Potential Clients

This table lists the companies identified as potential clients for EduNext. The columns include company name, size, country, type, number of employees, industry, business model (B2B or B2C), potential vertical, and the amount of the last funding round as reported by Crunchbase. This table provides detailed information on potential clients, aiding strategic decision-making.

Note: The EduNext team chose the roles and definitions for each role.

Potential partners
This table lists the companies identified as potential partners for EduNext. The columns include company name, size, country, type, number of employees, industry, business model (B2B or B2C), potential vertical, and the amount of the last funding round as reported by Crunchbase. This table provides detailed information on potential partners, aiding strategic collaborations.

Note: The EduNext team chose the roles and definitions for each role.

Potential competitors

This table lists the companies identified as potential competitors for EduNext. The columns include company name, size, country, type, number of employees, industry, business model (B2B or B2C), potential vertical, and the amount of the last funding round as reported by Crunchbase. This table provides detailed information on potential competitors, aiding competitive analysis.

Note: The EduNext team chose the roles and definitions for each role.

Potential providers

This table lists the companies identified as potential providers for EduNext. The columns include company name, size, country, type, number of employees, industry, business model (B2B or B2C), potential vertical, and the amount of the last funding round as reported by Crunchbase. This table provides detailed information on potential providers, aiding strategic sourcing decisions.

Ranking of startups

This horizontal bar chart ranks companies by the amount of their most recent investment, as reported by Crunchbase. The length of each bar represents the size of the investment, and the company names are listed along the vertical axis. This visualization helps to quickly identify the most heavily funded companies within the EdTech sector.

Note: The EduNext team chose the roles and definitions for each role.


📄 By Capabilities

Number of companies

This table lists various capabilities identified in the analyzed companies, showing how many companies possess each capability. The columns represent different capabilities, while the rows display the count of companies that possess each capability. The “Total” column sums up the number of companies for each capability. This table provides a detailed overview of the distribution of specific capabilities across companies, aiding in understanding the strengths and focus areas within the EdTech sector.

Note: The capabilities were taken from the HolonIQ source and are explained in more detail earlier in the report.

Number of Appearances
Capability Capability 1 Capability 2 Capability 3 Capability 4 Capability 5 Total
PERSONALIZED & ADAPTIVE LEARNING 375 178 88 46 14 701
IMMERSION, SIMULATION & LAB 5 198 225 149 67 644
VOLUNTEERING & STUDENT LEADERSHIP 1 2 205 223 147 578
DIGITAL DESIGN PRINCIPLES 8 37 17 209 213 484
ACCREDITATION 4 13 7 3 214 241
DIGITAL CONTENT CREATION 49 27 10 0 2 88
CUSTOMIZED PROGRAMS (B2B) 11 22 17 5 0 55
ASSESSMENT FEEDBACK 6 37 7 3 0 53
JOB APPLICATION SUPPORT 10 24 11 4 0 49
BADGING & CREDENTIALING 3 7 14 12 8 44
DESIGNING ASSESSMENT 17 15 7 2 0 41
PROFESSIONAL & INDUSTRY ASSOCIATIONS 3 13 8 4 8 36
FACULTY MANAGEMENT & SUPPORT 0 0 8 14 12 34
REPORTING & REGULATORY COMPLIANCE 3 17 8 4 0 32
JOB FINDING & GRADUATE PLACEMENT 11 15 3 1 1 31
STUDENT COMMUNITIES, CLUBS & SOCIETIES 8 8 13 1 0 30
TESTS & EXAMS 2 2 2 7 14 27
TUITION FINANCING 26 0 1 0 0 27
CAREER PLANNING SERVICES 9 9 4 2 2 26
WELLBEING & MENTAL HEALTH 21 5 0 0 0 26
COURSE SELECTION & GUIDANCE 7 8 3 4 0 22
APPLICATION & ADMISSIONS 17 1 0 1 0 19
STUDENT PORTAL & LMS 4 6 3 3 0 16
UNDERSTAND CUSTOMER NEEDS 3 6 6 0 0 15
WORKPLACE SIMULATION & PROJECTS 10 4 1 0 0 15
EXPERIENTIAL LEARNING APPROACHES 5 4 2 1 0 12
STUDENT RELATIONSHIP MANAGEMENT (CRM) 5 4 1 1 0 11
RETENTION & LEARNING SUPPORT 3 4 3 0 0 10
COMPETITORS & ALTERNATES 1 3 3 2 0 9
PEER & GROUP ASSESSMENT 3 5 1 0 0 9
PROGRAM ARCHITECTURE 2 1 6 0 0 9
ASYNCH. LEARNING EXPERIENCES 1 3 2 0 1 7
EDUCATION AS EMPLOYEE BENEFIT 6 1 0 0 0 7
ENTREPRENEURSHIP & STARTUPS 6 1 0 0 0 7
INDUSTRY MENTORING & NETWORKS 6 1 0 0 0 7
LEARNING DELIVERY MODELS 3 4 0 0 0 7
ONBOARDING & ORIENTATION 7 0 0 0 0 7
VOICE, CHAT & INTERACTIVE LEARNING 6 1 0 0 0 7
COMPETENCIES & SKILLS EVALUATION 6 0 0 0 0 6
EMPLOYABILITY SKILLS BUILDING 3 0 3 0 0 6
INDUSTRY COLLABS & PARTNERSHIPS 2 3 0 0 0 5
LEARNER NEEDS & ANALYTICS 0 4 1 0 0 5
TIMETABLING & SCHEDULE MANAGEMENT 3 1 1 0 0 5
B2B RECRUITMENT & PARTNERSHIPS 4 0 0 0 0 4
SCHOOLS & COMMUNITY OUTREACH 2 1 1 0 0 4
SOURCING & MANAGING EXPERTISE 2 1 1 0 0 4
STUDENT VOICE & SURVEYS 0 1 3 0 0 4
DESIGNING GROUP WORK 0 1 1 1 0 3
GRADUATION & SUCCESS 1 0 1 1 0 3
INTERNSHIPS & PLACEMENTS 1 1 1 0 0 3
OER & CONTENT LICENSING 3 0 0 0 0 3
SYNCHRONOUS LEARNING EXPERIENCES 2 1 0 0 0 3
EXCHANGE PROGRAMS 0 0 2 0 0 2
LEARNING ENVIRONMENTS & PLATFORMS 2 0 0 0 0 2
LIBRARY SERVICES 1 1 0 0 0 2
RECRUITMENT EVENTS 1 1 0 0 0 2
SCHOLARSHIP PROGRAM 1 0 1 0 0 2
DESIGNING FOR DIGITAL LEARNING 0 1 0 0 0 1
FACULTY EXPERTISE & SPECIALISMS 0 0 1 0 0 1
MANAGING INTEGRATED CONTENT 1 0 0 0 0 1
MARKETING AUTOMATION 1 0 0 0 0 1
Score

Score by Capabilities

This table assigns a weighted importance to each capability based on its position to measure and rank the most important capabilities effectively. The weights are assigned as follows:

  • Capability 1 is multiplied by 5
  • Capability 2 is multiplied by 4
  • Capability 3 is multiplied by 3
  • Capability 4 is multiplied by 2
  • Capability 5 is multiplied by 1

The total score for each capability is then calculated by summing these weighted values, ensuring that higher importance is given to capabilities listed earlier. This method reflects the significance of each capability in the overall ranking. The table includes columns for each capability’s score and the total score for each row.

Note: The capabilities were taken from the HolonIQ source and are explained in more detail earlier in the report.

Score
Capability Capability 1 Capability 2 Capability 3 Capability 4 Capability 5 Score
PERSONALIZED & ADAPTIVE LEARNING 375 178 88 46 14 2957
IMMERSION, SIMULATION & LAB 5 198 225 149 67 1857
VOLUNTEERING & STUDENT LEADERSHIP 1 2 205 223 147 1221
DIGITAL DESIGN PRINCIPLES 8 37 17 209 213 870
DIGITAL CONTENT CREATION 49 27 10 0 2 385
ACCREDITATION 4 13 7 3 214 313
ASSESSMENT FEEDBACK 6 37 7 3 0 205
CUSTOMIZED PROGRAMS (B2B) 11 22 17 5 0 204
JOB APPLICATION SUPPORT 10 24 11 4 0 187
DESIGNING ASSESSMENT 17 15 7 2 0 170
TUITION FINANCING 26 0 1 0 0 133
JOB FINDING & GRADUATE PLACEMENT 11 15 3 1 1 127
WELLBEING & MENTAL HEALTH 21 5 0 0 0 125
BADGING & CREDENTIALING 3 7 14 12 8 117
REPORTING & REGULATORY COMPLIANCE 3 17 8 4 0 115
STUDENT COMMUNITIES, CLUBS & SOCIETIES 8 8 13 1 0 113
PROFESSIONAL & INDUSTRY ASSOCIATIONS 3 13 8 4 8 107
CAREER PLANNING SERVICES 9 9 4 2 2 99
APPLICATION & ADMISSIONS 17 1 0 1 0 91
COURSE SELECTION & GUIDANCE 7 8 3 4 0 84
WORKPLACE SIMULATION & PROJECTS 10 4 1 0 0 69
FACULTY MANAGEMENT & SUPPORT 0 0 8 14 12 64
STUDENT PORTAL & LMS 4 6 3 3 0 59
UNDERSTAND CUSTOMER NEEDS 3 6 6 0 0 57
TESTS & EXAMS 2 2 2 7 14 52
EXPERIENTIAL LEARNING APPROACHES 5 4 2 1 0 49
STUDENT RELATIONSHIP MANAGEMENT (CRM) 5 4 1 1 0 46
RETENTION & LEARNING SUPPORT 3 4 3 0 0 40
PEER & GROUP ASSESSMENT 3 5 1 0 0 38
ONBOARDING & ORIENTATION 7 0 0 0 0 35
EDUCATION AS EMPLOYEE BENEFIT 6 1 0 0 0 34
ENTREPRENEURSHIP & STARTUPS 6 1 0 0 0 34
INDUSTRY MENTORING & NETWORKS 6 1 0 0 0 34
VOICE, CHAT & INTERACTIVE LEARNING 6 1 0 0 0 34
PROGRAM ARCHITECTURE 2 1 6 0 0 32
LEARNING DELIVERY MODELS 3 4 0 0 0 31
COMPETENCIES & SKILLS EVALUATION 6 0 0 0 0 30
COMPETITORS & ALTERNATES 1 3 3 2 0 30
ASYNCH. LEARNING EXPERIENCES 1 3 2 0 1 24
EMPLOYABILITY SKILLS BUILDING 3 0 3 0 0 24
INDUSTRY COLLABS & PARTNERSHIPS 2 3 0 0 0 22
TIMETABLING & SCHEDULE MANAGEMENT 3 1 1 0 0 22
B2B RECRUITMENT & PARTNERSHIPS 4 0 0 0 0 20
LEARNER NEEDS & ANALYTICS 0 4 1 0 0 19
SCHOOLS & COMMUNITY OUTREACH 2 1 1 0 0 17
SOURCING & MANAGING EXPERTISE 2 1 1 0 0 17
OER & CONTENT LICENSING 3 0 0 0 0 15
SYNCHRONOUS LEARNING EXPERIENCES 2 1 0 0 0 14
STUDENT VOICE & SURVEYS 0 1 3 0 0 13
INTERNSHIPS & PLACEMENTS 1 1 1 0 0 12
GRADUATION & SUCCESS 1 0 1 1 0 10
LEARNING ENVIRONMENTS & PLATFORMS 2 0 0 0 0 10
DESIGNING GROUP WORK 0 1 1 1 0 9
LIBRARY SERVICES 1 1 0 0 0 9
RECRUITMENT EVENTS 1 1 0 0 0 9
SCHOLARSHIP PROGRAM 1 0 1 0 0 8
EXCHANGE PROGRAMS 0 0 2 0 0 6
MANAGING INTEGRATED CONTENT 1 0 0 0 0 5
MARKETING AUTOMATION 1 0 0 0 0 5
DESIGNING FOR DIGITAL LEARNING 0 1 0 0 0 4
FACULTY EXPERTISE & SPECIALISMS 0 0 1 0 0 3

| Opportunities for Improvement

The analysis of EdTech companies has revealed several areas for improvement:

  • Data Refinement: Enhancing the data regarding the relationship of these companies with the Open edX platform is crucial. Clear and accurate information in this aspect will lead to more precise insights.
  • Definition of eduNEXT: The definition and concept of “eduNEXT” needs to be well-defined and incorporated into the model training. This will ensure a better understanding and identification of the company’s role in the EdTech ecosystem.
  • Client vs. Partner Roles: Addressing the ambiguity between ‘client’ and ‘partner’ roles is essential. Leveraging advanced models such as GPT-4-O can provide deeper contextual analysis and differentiation.
  • Role Classification: When asking for roles using the ChatGPT algorithm, including a “none of the above” category would have been beneficial. This approach would prevent the forceful assignment of a nonexistent relationship.
  • Investment Data Source: The investment information used in the analysis was based solely on data retrieved from Crunchbase via LinkedIn. To enhance the comprehensiveness of future analyses, considering additional sources of investment data, especially for companies in Asia where LinkedIn usage is less prevalent, would be beneficial.

The project shows significant potential for further exploration and development. As it is still in progress, any feedback and recommendations are highly appreciated to refine and improve the results.


Go to Top

LS0tDQphdXRob3I6ICJEYW5pZWxhIFJpb3MiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIG1hdGhqYXg6IHRydWUNCiAgICBrZWVwX21kOiB0cnVlDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgdGhlbWU6ICBzcGFjZWxhYg0KICBwZGZfZG9jdW1lbnQ6DQphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZQ0KLS0tDQoNCg0KYGBge3Igc2V0dXAsIGVjaG89RkFMU0V9DQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGNvbW1lbnQgPSBOQSkNCg0KYGBgDQoNCiFbXShCYW5uZXIuanBnKQ0KDQoqKioNCg0KPHNwYW4+PGgxIHN0eWxlID0gImZvbnQtZmFtaWx5OiB2ZXJkYW5hOyBmb250LXNpemU6IDI2cHg7IGZvbnQtc3R5bGU6IG5vcm1hbDsgbGV0dGVyLXNwY2Fpbmc6IDNweDsgYmFja2dyb3VuZC1jb2xvcjogI2U3ZjNmZTsgY29sb3IgOiMwMDAwMDA7IGJvcmRlci1yYWRpdXM6IDEwMHB4IDEwMHB4OyB0ZXh0LWFsaWduOmNlbnRlciI+8J+TiCBFbWVyZ2luZyBFZFRlY2ggSW5ub3ZhdG9ycyA8L2gxPjwvc3Bhbj4NCg0KDQo8ZGl2IGlkPSJ0YWJsZS1vZi1jb250ZW50cyIgc3R5bGU9Ig0KICAgIGJvcmRlcjogMXB4IHNvbGlkICNkZGQ7DQogICAgcGFkZGluZzogMjBweDsNCiAgICBtYXJnaW4tdG9wOiAxMHB4Ow0KICAgIG1hcmdpbi1ib3R0b206IDIwcHg7DQogICAgYm94LXNoYWRvdzogMCAycHggNHB4IHJnYmEoMCwwLDAsMC4wNSk7DQogICAgZm9udC1mYW1pbHk6ICdTZWdvZSBVSScsIFRhaG9tYSwgR2VuZXZhLCBWZXJkYW5hLCBzYW5zLXNlcmlmOyI+DQoNCjxoMiBzdHlsZT0iDQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBtYXJnaW4tdG9wOiAwOw0KICAgIG1hcmdpbi1ib3R0b206IDEwcHg7DQogICAgcGFkZGluZy1ib3R0b206IDVweDsNCiAgICBib3JkZXItYm90dG9tOiAycHggc29saWQgIzJhN2FlMjsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBjb2xvcjogIzJhN2FlMjsiPg0KICAgIFRhYmxlIG9mIENvbnRlbnRzDQo8L2gyPg0KDQo8b2wgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICM1NTU7IHBhZGRpbmctbGVmdDogMjBweDsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICAgIDxsaSBzdHlsZT0ibWFyZ2luLWJvdHRvbTogOHB4OyI+PGEgaHJlZj0iI2ludHJvZHVjdGlvbi1vYmplY3RpdmUiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246IG5vbmU7IGNvbG9yOiAjMmE3YWUyOyI+SW50cm9kdWN0aW9uIGFuZCBPYmplY3RpdmU8L2E+PC9saT4NCiAgICA8bGkgc3R5bGU9Im1hcmdpbi1ib3R0b206IDhweDsiPjxhIGhyZWY9IiNvdmVydmlldyIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjogbm9uZTsgY29sb3I6ICMyYTdhZTI7Ij5Qcm9qZWN0IG92ZXJ2aWV3PC9hPjwvbGk+DQogICAgPGxpIHN0eWxlPSJtYXJnaW4tYm90dG9tOiA4cHg7Ij48YSBocmVmPSIjaG9sb25pcS1vdmVydmlldyIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjogbm9uZTsgY29sb3I6ICMyYTdhZTI7Ij5Ib2xvbklRIEVkVGVjaCBSYW5raW5nIE92ZXJ2aWV3PC9hPjwvbGk+DQogICAgPGxpIHN0eWxlPSJtYXJnaW4tYm90dG9tOiA4cHg7Ij48YSBocmVmPSIjbWV0aG9kb2xvZ3kiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246IG5vbmU7IGNvbG9yOiAjMmE3YWUyOyI+TWV0aG9kb2xvZ3k8L2E+PC9saT4NCiAgICA8bGkgc3R5bGU9Im1hcmdpbi1ib3R0b206IDhweDsiPjxhIGhyZWY9IiNhbmFseXNpcy1yZXN1bHRzIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOiBub25lOyBjb2xvcjogIzJhN2FlMjsiPkFuYWx5c2lzIGFuZCBSZXN1bHRzPC9hPjwvbGk+DQogICAgPGxpIHN0eWxlPSJtYXJnaW4tYm90dG9tOiA4cHg7Ij48YSBocmVmPSIjZGlzY3Vzc2lvbiIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjogbm9uZTsgY29sb3I6ICMyYTdhZTI7Ij5PcHBvcnR1bml0aWVzIGZvciBJbXByb3ZlbWVudDwvYT48L2xpPg0KPC9vbD4NCg0KPC9kaXY+DQoNCg0KDQo8c3BhbiBpZD0idG9wIj48L3NwYW4+DQoNCg0KPGEgaWQ9ImludHJvZHVjdGlvbi1vYmplY3RpdmUiPjwvYT4NCg0KKioqDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDIycHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBjZW50ZXI7IG1hcmdpbi1ib3R0b206IDIwcHg7Ij4NCiAgPGI+PHNwYW4gc3R5bGU9ImNvbG9yOiAjOTM4MWZmOyBmb250LXNpemU6IDI2cHg7Ij4gfDwvc3Bhbj4gSW50cm9kdWN0aW9uIGFuZCBPYmplY3RpdmU8L2I+DQo8L3A+DQoNCioqKg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgcHJpbWFyeSBvYmplY3RpdmUgb2YgdGhpcyBwcm9qZWN0IHdhcyB0byBleHBsb3JlIGVtZXJnaW5nIGNvbXBhbmllcyBhbmQgdHJlbmRzIGluIHRoZSBFZFRlY2ggaW5kdXN0cnksIGFzIGZlYXR1cmVkIG9uIEhvbG9uSVHigJlzIGxpc3QuIFRoaXMgaW5pdGlhdGl2ZSBhaW1lZCB0byBnYWluIGEgY29tcHJlaGVuc2l2ZSB1bmRlcnN0YW5kaW5nIG9mIHRoZSBjdXJyZW50IG1hcmtldCBsYW5kc2NhcGUsIGNhdGVnb3JpemUgdGhlIHN0YXJ0dXBzIGJhc2VkIG9uIHRoZWlyIGZvY3VzIGFyZWFzLCBhbmQgcGlucG9pbnQgcG90ZW50aWFsIGNsaWVudHMsIHByb3ZpZGVycywgcGFydG5lcnMsIGNvbXBldGl0b3JzLCBvciBlbWVyZ2luZyBtYXJrZXRzLiBUaGUgYW5hbHlzaXMgd2FzIHN0cnVjdHVyZWQgdG8gZXhhbWluZSB0aGVzZSBlbnRpdGllcyBieSBnZW9ncmFwaGljIHJlZ2lvbnMgYW5kIGluZHVzdHJ5IHZlcnRpY2FscywgdWx0aW1hdGVseSBwcm92aWRpbmcgc3RyYXRlZ2ljIGluc2lnaHRzIHRvIHVuZGVyc3RhbmQgZWR1bmV4dOKAmXMgcG9zaXRpb24gd2l0aGluIHRoZSBpbmR1c3RyeSBhbmQgZW5oYW5jZSBpdHMgbWFya2V0IHBvc2l0aW9uaW5nIGFuZCBncm93dGguDQo8L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTZweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7IG1hcmdpbi1ib3R0b206IDIwcHg7Ij4NCiAgPHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2YyZWJmYjsgY29sb3I6YmxhY2s7IGJvcmRlci1yYWRpdXM6NXB4OyBwYWRkaW5nOiAwLjJlbSAwLjVlbTsgZGlzcGxheTogaW5saW5lLWJsb2NrOyI+8J+aqCA8Yj5XaHkgdGhlIEhvbG9uSVEgRWRUZWNoIFJhbmtpbmcgd2FzIFNlbGVjdGVkPC9iPjwvc3Bhbj4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhlIEhvbG9uSVEgRWRUZWNoIHJhbmtpbmcgd2FzIHNlbGVjdGVkIGR1ZSB0byBpdHMgcmVwdXRhdGlvbiBhcyBhIGNvbXByZWhlbnNpdmUgYW5kIGF1dGhvcml0YXRpdmUgc291cmNlIG9mIGluZm9ybWF0aW9uIG9uIHRoZSBtb3N0IGlubm92YXRpdmUgYW5kIGhpZ2gtcG90ZW50aWFsIEVkVGVjaCBzdGFydHVwcyBnbG9iYWxseS4gVGhlIHJhbmtpbmcgcHJvdmlkZXMgdmFsdWFibGUgaW5zaWdodHMgaW50byB0aGUgbGVhZGluZyBjb21wYW5pZXMgaW4gdGhlIEVkVGVjaCBzZWN0b3IsIG1ha2luZyBpdCBhbiBpZGVhbCByZXNvdXJjZSBmb3IgaWRlbnRpZnlpbmcga2V5IHBsYXllcnMgYW5kIGVtZXJnaW5nIHRyZW5kcyBpbiB0aGUgaW5kdXN0cnkuIEJ5IGxldmVyYWdpbmcgdGhpcyByYW5raW5nLCBlZHVOZXh0IGNhbiBlbnN1cmUgaXRzIGFuYWx5c2lzIGlzIGJhc2VkIG9uIGNyZWRpYmxlIGFuZCB1cC10by1kYXRlIGluZm9ybWF0aW9uLCBlbmFibGluZyBpbmZvcm1lZCBkZWNpc2lvbi1tYWtpbmcgYW5kIHN0cmF0ZWdpYyBwbGFubmluZy4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNnB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZjJlYmZiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij7wn5KrIDxiPkNvbXBhbnkgT3ZlcnZpZXc8L2I+PC9zcGFuPg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpFZHVuZXh0IGlzIGFuIGluZnJhc3RydWN0dXJlLWFzLWEtc2VydmljZSBwcm92aWRlciBhbmQgc29mdHdhcmUgY29tcGFueSBkZWRpY2F0ZWQgdG8gdGhlIE9wZW4gZWRYIHBsYXRmb3JtLiBJdCBlbXBvd2VycyBvcmdhbml6YXRpb25zIHdvcmxkd2lkZSBieSBkZWxpdmVyaW5nIHJvYnVzdCwgc2NhbGFibGUsIGFuZCBjdXN0b21pemFibGUgb25saW5lIGxlYXJuaW5nIHNvbHV0aW9ucy4gRWR1bmV4dCdzIG1pc3Npb24gaXMgdG8gZW5oYW5jZSB0aGUgcXVhbGl0eSBvZiBlZHVjYXRpb24gdGhyb3VnaCB0ZWNobm9sb2d5LCBzdXBwb3J0aW5nIHN1Y2Nlc3NmdWwgb25saW5lIGxlYXJuaW5nIGluaXRpYXRpdmVzIGFjcm9zcyB2YXJpb3VzIHNlY3RvcnMuDQo8L3A+DQoNCjxhIGlkPSJvdmVydmlldyI+PC9hPg0KDQoqKioNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMjJweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGNlbnRlcjsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8Yj48c3BhbiBzdHlsZT0iY29sb3I6ICM5MzgxZmY7IGZvbnQtc2l6ZTogMjZweDsiPiB8PC9zcGFuPiBQcm9qZWN0IE92ZXJ2aWV3PC9iPg0KPC9wPg0KDQoqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhlIHByb2plY3QgaW52b2x2ZWQgZ2VuZXJhdGluZyBhIGxpc3Qgb2YgdGhlIDEwMDAgRWRUZWNoIHN0YXJ0dXBzIGZlYXR1cmVkIGluIHRoZSBIb2xvbklRIHJhbmtpbmcuIFRoaXMgbGlzdCBpbmNsdWRlZCBsaW5rcyB0byB0aGVpciBMaW5rZWRJbiBwcm9maWxlcy4gQSBzY3JhcGVyIHdhcyBkZXZlbG9wZWQgdG8gZXh0cmFjdCBpbmZvcm1hdGlvbiBmcm9tIExpbmtlZEluLCBhbmQgYWRkaXRpb25hbCBkYXRhIHdhcyBnYXRoZXJlZCBmcm9tIHRoZSBzdGFydHVwcycgd2Vic2l0ZXMsIHdoaWNoIHdlcmUgc2F2ZWQgaW4gdGV4dCBmaWxlcy4gVGhpcyBjb2xsZWN0ZWQgaW5mb3JtYXRpb24gd2FzIHRoZW4gdXNlZCB0byBmZWVkIHRoZSBDaGF0R1BUIEFQSSB3aXRoIHNwZWNpZmljIHByb21wdHMuIFRoZSBwdXJwb3NlIG9mIHRoZXNlIHByb21wdHMgd2FzIHRvIGJ1aWxkIGRldGFpbGVkIHByb2ZpbGVzIG9mIGVhY2ggY29tcGFueSBhbmQgb2J0YWluIGJldHRlciBhbnN3ZXJzIHRvIHF1ZXN0aW9ucyBvcmllbnRlZCB0b3dhcmQgY2xhc3NpZnlpbmcgYW5kIGlkZW50aWZ5aW5nIHBvdGVudGlhbCBidXNpbmVzcyBvcHBvcnR1bml0aWVzIGZvciBlZHVOZXh0LiBUaGlzIG1ldGhvZG9sb2d5IHByb3ZpZGVkIGEgY29tcHJlaGVuc2l2ZSBhbmQgZGV0YWlsZWQgdW5kZXJzdGFuZGluZyBvZiBlYWNoIHN0YXJ0dXAsIGZhY2lsaXRhdGluZyBzdHJhdGVnaWMgaW5zaWdodHMgZm9yIGVkdW5leHQncyBtYXJrZXQgcG9zaXRpb25pbmcgYW5kIGdyb3d0aC4NCjwvcD4NCg0KDQoqKioNCjxhIGlkPSJob2xvbmlxLW92ZXJ2aWV3Ij48L2E+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMjJweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGNlbnRlcjsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8Yj48c3BhbiBzdHlsZT0iY29sb3I6ICM5MzgxZmY7IGZvbnQtc2l6ZTogMjZweDsiPiB8PC9zcGFuPiBIb2xvbklRIEVkVGVjaCBSYW5raW5nIE92ZXJ2aWV3PC9iPg0KPC9wPg0KDQoqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNnB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZjJlYmZiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij7wn5OYIDxiPkludHJvZHVjdGlvbiB0byBIb2xvbklRPC9iPjwvc3Bhbj4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KSG9sb25JUSBpcyBhIGdsb2JhbCBtYXJrZXQgaW50ZWxsaWdlbmNlIGZpcm0gc3BlY2lhbGl6aW5nIGluIHRoZSBlZHVjYXRpb24sIGNsaW1hdGUsIGFuZCBoZWFsdGggc2VjdG9ycy4gRWFjaCB5ZWFyLCBpdCBwdWJsaXNoZXMgdGhlIEdsb2JhbCBFZFRlY2ggMTAwMCBsaXN0LCB3aGljaCBoaWdobGlnaHRzIHRoZSBtb3N0IHByb21pc2luZyBzdGFydHVwcyBpbiB0aGUgZWR1Y2F0aW9uYWwgdGVjaG5vbG9neSAoRWRUZWNoKSBmaWVsZCBhdCBib3RoIGdsb2JhbCBhbmQgcmVnaW9uYWwgbGV2ZWxzLiBTdWJsaXN0cyBpbmNsdWRlIHRoZSAiVG9wIDIwMCBFZFRlY2ggaW4gTm9ydGggQW1lcmljYSwiIHRoZSAiVG9wIDUwIEVkVGVjaCBpbiBBdXN0cmFsaWEgYW5kIE5ldyBaZWFsYW5kLCIgYW5kIG1hbnkgbW9yZSBmb3IgZGlmZmVyZW50IHJlZ2lvbnMgd29ybGR3aWRlLg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE2cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyBtYXJnaW4tYm90dG9tOiAyMHB4OyI+DQogIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmMmViZmI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPvCflI0gPGI+SG93IERvZXMgdGhlIEhvbG9uSVEgUmFua2luZyBXb3JrPzwvYj48L3NwYW4+DQo8L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCjxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlOWY1ZGI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPioqRXZhbHVhdGlvbiBhbmQgU2VsZWN0aW9uOioqPC9zcGFuPg0KPC9wPg0KPHVsIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgPGxpPjxiPkRhdGFiYXNlOjwvYj4gSG9sb25JUSBzdGFydHMgd2l0aCBhIGdsb2JhbCBkYXRhYmFzZSBjb250YWluaW5nIHRob3VzYW5kcyBvZiBFZFRlY2ggb3JnYW5pemF0aW9ucy4gSXQgdXNlcyBpdHMgZ2xvYmFsIGludGVsbGlnZW5jZSBwbGF0Zm9ybSB0byBnYXRoZXIgZGV0YWlsZWQgZGF0YSBvbiB0aGVzZSBjb21wYW5pZXMuPC9saT4NCiAgPGxpPjxiPkV4cGVydCBQYW5lbDo8L2I+IEEgcGFuZWwgb2YgcmVnaW9uYWwgZXhwZXJ0cyBldmFsdWF0ZXMgZWFjaCBvcmdhbml6YXRpb24gYmFzZWQgb24gYSBzZXQgb2YgcHJlZGV0ZXJtaW5lZCBjcml0ZXJpYS48L2xpPg0KPC91bD4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KPHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2U5ZjVkYjsgY29sb3I6YmxhY2s7IGJvcmRlci1yYWRpdXM6NXB4OyBwYWRkaW5nOiAwLjJlbSAwLjVlbTsgZGlzcGxheTogaW5saW5lLWJsb2NrOyI+KipFdmFsdWF0aW9uIENyaXRlcmlhOioqPC9zcGFuPg0KPC9wPg0KPHVsIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgPGxpPjxiPk1hcmtldDo8L2I+IFRoZSBxdWFsaXR5IGFuZCByZWxhdGl2ZSBhdHRyYWN0aXZlbmVzcyBvZiB0aGUgbWFya2V0IGluIHdoaWNoIHRoZSBjb21wYW55IGNvbXBldGVzLCBpbmNsdWRpbmcgYm90aCB0aGUgZ2VvZ3JhcGhpY2FsIG1hcmtldCBhbmQgdGhlIHNwZWNpZmljIHNlY3RvciAoZS5nLiwgbGFuZ3VhZ2UgbGVhcm5pbmcsIHR1dG9yaW5nKS48L2xpPg0KICA8bGk+PGI+UHJvZHVjdDo8L2I+IFRoZSBxdWFsaXR5IGFuZCB1bmlxdWVuZXNzIG9mIHRoZSBjb21wYW55J3MgcHJvZHVjdCwgYXMgd2VsbCBhcyBpdHMgaW1wYWN0IG9uIHRoZSBlZHVjYXRpb25hbCBzZWN0b3IuPC9saT4NCiAgPGxpPjxiPlRlYW06PC9iPiBUaGUgZXhwZXJpZW5jZSBhbmQgZGl2ZXJzaXR5IG9mIHRoZSBmb3VuZGluZyBhbmQgbGVhZGVyc2hpcCB0ZWFtLjwvbGk+DQogIDxsaT48Yj5DYXBpdGFsOjwvYj4gVGhlIGZpbmFuY2lhbCBoZWFsdGggb2YgdGhlIGNvbXBhbnksIGluY2x1ZGluZyBpdHMgYWJpbGl0eSB0byBnZW5lcmF0ZSBvciBzZWN1cmUgc3VmZmljaWVudCBmdW5kaW5nIHRocm91Z2ggcmV2ZW51ZSBvciBleHRlcm5hbCBpbnZlc3RtZW50cy48L2xpPg0KICA8bGk+PGI+TW9tZW50dW06PC9iPiBQb3NpdGl2ZSBjaGFuZ2VzIGluIHRoZSBjb21wYW55J3Mgc2l6ZSBhbmQgZ3Jvd3RoIHJhdGUgb3ZlciB0aW1lLCBpbmNsdWRpbmcgdGhlIG51bWJlciBvZiBlbXBsb3llZXMgYW5kIHJldmVudWUuPC9saT4NCjwvdWw+DQo8L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCjxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlOWY1ZGI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPioqU2VsZWN0aW9uIFByb2Nlc3M6Kio8L3NwYW4+DQo8L3A+DQo8dWwgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8bGk+PGI+RGF0YSBBbmFseXNpczo8L2I+IFV0aWxpemVzIGJvdGggaW50ZXJuYWwgZGF0YSBhbmQgaW5mb3JtYXRpb24gcHJvdmlkZWQgdGhyb3VnaCBhbiBhcHBsaWNhdGlvbiBwcm9jZXNzLjwvbGk+DQogIDxsaT48Yj5FeHBlcnQgRmVlZGJhY2s6PC9iPiBMb2NhbCBleHBlcnRzIGluIGVhY2ggbWFya2V0IHJldmlldyBhbmQgcHJvdmlkZSBmZWVkYmFjayB0byBlbnN1cmUgYWNjdXJhdGUgZXZhbHVhdGlvbi48L2xpPg0KICA8bGk+PGI+RGl2ZXJzaXR5IG9mIElubm92YXRpb25zOjwvYj4gQWltcyB0byBpbmNsdWRlIGNvbXBhbmllcyBvZiB2YXJpb3VzIHNpemVzIGFuZCBzZWN0b3JzIHdpdGhpbiBFZFRlY2ggdG8gcmVmbGVjdCBnbG9iYWwgdHJlbmRzIGFuZCBpbm5vdmF0aW9uLjwvbGk+DQo8L3VsPg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE2cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyBtYXJnaW4tYm90dG9tOiAyMHB4OyI+DQogIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmMmViZmI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPvCfk4ogPGI+SW1wb3J0YW5jZSBvZiB0aGUgUmFua2luZzwvYj48L3NwYW4+DQo8L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoZXNlIHJhbmtpbmdzIG5vdCBvbmx5IGhpZ2hsaWdodCB0aGUgbW9zdCBwcm9taXNpbmcgc3RhcnR1cHMgYnV0IGFsc28gaGVscCBjb25uZWN0IGRpZmZlcmVudCByZWdpb25zIG9mIHRoZSB3b3JsZCBhbmQgc2hhcmUgaW5ub3ZhdGlvbnMgdGhhdCBjYW4gaW1wcm92ZSBlZHVjYXRpb25hbCBvdXRjb21lcyBnbG9iYWxseS4gUHJvbWlzaW5nIHN0YXJ0dXBzIGFyZSB0aG9zZSB0aGF0IHNob3cgZXhjZXB0aW9uYWwgcG90ZW50aWFsIGluIHRlcm1zIG9mIGlubm92YXRpb24sIG1hcmtldCBpbXBhY3QsIGFuZCBncm93dGggdHJhamVjdG9yeSwgbWFraW5nIHRoZW0ga2V5IHBsYXllcnMgaW4gZHJpdmluZyB0aGUgZnV0dXJlIG9mIGVkdWNhdGlvbi4gQWRkaXRpb25hbGx5LCB0aGV5IHByb3ZpZGUgaW52ZXN0b3JzIGFuZCBvdGhlciBzdGFrZWhvbGRlcnMgd2l0aCBhIGNsZWFyIHZpZXcgb2YgZW1lcmdpbmcgdHJlbmRzIGFuZCB0aGUgY29tcGFuaWVzIGxlYWRpbmcgdGhlIGNoYW5nZSBpbiBlZHVjYXRpb24uDQo8L3A+DQoNCg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpGb3IgbW9yZSBkZXRhaWxzIG9uIEhvbG9uSVEgcmFua2luZ3MgYW5kIG1ldGhvZG9sb2dpZXMsIHlvdSBjYW4gdmlzaXQgdGhlaXIgb2ZmaWNpYWwgd2Vic2l0ZTogPGEgaHJlZj0iaHR0cHM6Ly93d3cuaG9sb25pcS5jb20iIHN0eWxlPSJjb2xvcjogIzJhN2FlMjsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyI+SG9sb25JUTwvYT4uDQo8L3A+DQoNCioqKg0KPGEgaWQ9Im1ldGhvZG9sb2d5Ij48L2E+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMjJweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGNlbnRlcjsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8Yj48c3BhbiBzdHlsZT0iY29sb3I6ICM5MzgxZmY7IGZvbnQtc2l6ZTogMjZweDsiPiB8PC9zcGFuPiBNZXRob2RvbG9neTwvYj4NCjwvcD4NCg0KKioqDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTZweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7IG1hcmdpbi1ib3R0b206IDIwcHg7Ij4NCiAgPHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2YyZWJmYjsgY29sb3I6YmxhY2s7IGJvcmRlci1yYWRpdXM6NXB4OyBwYWRkaW5nOiAwLjJlbSAwLjVlbTsgZGlzcGxheTogaW5saW5lLWJsb2NrOyI+8J+TiyA8Yj5HZW5lcmF0ZSB0aGUgbGlzdCB3aXRoIHRoZSAxMDAwIGNvbXBhbmllczwvYj48L3NwYW4+DQo8L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoZSBwcm9qZWN0IGxldmVyYWdlZCBhIGN1cmF0ZWQgbGlzdCBvZiAxLDAwMCBFZFRlY2ggc3RhcnR1cHMgY29tcGlsZWQgYnkgSG9sb25pcS4gVGhpcyBsaXN0LCBwcm92aWRlZCBpbiBpbWFnZSBmb3JtYXQsIHNlZ21lbnRlZCB0aGUgc3RhcnR1cHMgYnkgZ2VvZ3JhcGhpYyByZWdpb24gKEFmcmljYSwgTm9yZGljLUJhbHRpYywgU291dGggQXNpYSwgZXRjLikuIFRvIGZhY2lsaXRhdGUgZnVydGhlciBhbmFseXNpcywgdGhlIGluaXRpYWwgc3RlcCBpbnZvbHZlZCBtZXRpY3Vsb3VzbHkgZXh0cmFjdGluZyBrZXkgaW5mb3JtYXRpb24gZnJvbSBlYWNoIGVudHJ5LiBUaGlzIGluZm9ybWF0aW9uIGluY2x1ZGVkIHRoZSBjb21wYW55IG5hbWUsIExpbmtlZEluIHByb2ZpbGUgVVJMLCBhbmQgY29tcGFueSB3ZWJzaXRlIGFkZHJlc3MuIFRoZSBkYXRhIGV4dHJhY3Rpb24gcHJvY2VzcyB3YXMgYSBjb2xsYWJvcmF0aXZlIGVmZm9ydCwgcmVxdWlyaW5nIG1hbnVhbCB3b3JrIGZyb20gbXVsdGlwbGUgdGVhbSBtZW1iZXJzLiBBZGRpdGlvbmFsbHksIHN1cHBvcnQgdG9vbHMgbGlrZSBHZW1pbmkgYW5kIEdQVC0zIHdlcmUgZW1wbG95ZWQgdG8gZW5oYW5jZSBlZmZpY2llbmN5Lg0KPC9wPg0KDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoaXMgaXMgYW4gZXhhbXBsZSBvZiB0aGUgc291cmNlIGZvcm1hdCBvZiB0aGUgbGlzdHMgbWVudGlvbmVkIGFib3ZlLg0KPC9wPg0KDQohW10oZWR0ZWNoXzIwMF9OQS5wbmcpDQoNCioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmRmOGUxOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij48Yj5UaGUgR2xvYmFsIEVkVGVjaCAxMDAwIGxpc3QgZm9yIHRoaXMgY2FzZSBpbmNsdWRlczo8L2I+PC9zcGFuPg0KPC9wPg0KDQo8cD5XZSB1c2VkIHRoZSAyMDIzIEhvbG9uSVEgRWRUZWNoIGxpc3RzIGZvciBvdXIgYW5hbHlzaXMuPC9wPg0KDQo8dWwgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8bGk+QWZyaWNhIEVkVGVjaCA1MDwvbGk+DQogIDxsaT5Ob3JkaWMtQmFsdGljIEVkVGVjaCA1MDwvbGk+DQogIDxsaT5Tb3V0aCBBc2lhIEVkVGVjaCAxMDA8L2xpPg0KICA8bGk+TWlkZGxlIEVhc3QgJiBOb3J0aCBBZnJpY2EgRWRUZWNoIDUwPC9saT4NCiAgPGxpPkVhc3QgQXNpYSBFZFRlY2ggMTUwPC9saT4NCiAgPGxpPkV1cm9wZSBFZFRlY2ggMjAwPC9saT4NCiAgPGxpPlNvdXRoZWFzdCBBc2lhIEVkVGVjaCA1MDwvbGk+DQogIDxsaT5BdXN0cmFsaWEgJiBOZXcgWmVhbGFuZCBFZFRlY2ggNTA8L2xpPg0KICA8bGk+Tm9ydGggQW1lcmljYSBFZFRlY2ggMjAwPC9saT4NCiAgPGxpPkxhdGluIEFtZXJpY2EgRWRUZWNoIDEwMDwvbGk+DQo8L3VsPg0KDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCk9uY2UgdGhpcyBwcm9jZXNzIHdhcyBkb25lLCB0aGUgbGlzdCBsb29rZWQgbGlrZSB0aGlzOg0KPC9wPg0KDQoNCiFbXShsaXNfMS5wbmcpDQoNCioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNnB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZjJlYmZiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij7wn5OLIDxiPkxpbmtlZEluIFNjcmFwZXI8L2I+PC9zcGFuPg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpJbml0aWFsbHksIHRoZXJlIHdlcmUgMSwwNDYgY29tcGFuaWVzIGluIHRoZSBsaXN0LiBBZnRlciByZXZpZXdpbmcsIGl0IHdhcyBmb3VuZCB0aGF0IG9ubHkgOTM3IHdlcmUgdW5pcXVlLCBhcyB0aGUgbGlzdCB3YXMgbWFudWFsbHkgY29tcGlsZWQgYnkgc2V2ZXJhbCB0ZWFtIG1lbWJlcnMgYW5kIHNvbWUgZW50cmllcyB3ZXJlIGR1cGxpY2F0ZWQuIE9mIHRoZXNlIDkzNyB1bmlxdWUgY29tcGFuaWVzLCAxMTcgaGFkIG5vIExpbmtlZEluIHBhZ2UuIFRoZSBMaW5rZWRJbiBzY3JhcGluZyBwcm9jZXNzIHdhcyB0aGVyZWZvcmUgY29uZHVjdGVkIHdpdGggODIwIGNvbXBhbmllcywgeWllbGRpbmcgNzAzIHN1Y2Nlc3NmdWwgcmVzcG9uc2VzLg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgcmVzdWx0cyBhcmUgc3VtbWFyaXplZCBpbiB0aGUgZm9sbG93aW5nIHRhYmxlOg0KPC9wPg0KDQo8dGFibGUgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgd2lkdGg6IDEwMCU7IG1heC13aWR0aDogNjAwcHg7Ij4NCiAgPHRoZWFkPg0KICAgIDx0ciBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZjJlYmZiOyI+DQogICAgICA8dGggc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsgdGV4dC1hbGlnbjogbGVmdDsiPkNhdGVnb3J5PC90aD4NCiAgICAgIDx0aCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyB0ZXh0LWFsaWduOiBsZWZ0OyI+TnVtYmVyIG9mIGNvbXBhbmllczwvdGg+DQogICAgPC90cj4NCiAgPC90aGVhZD4NCiAgPHRib2R5Pg0KICAgIDx0cj4NCiAgICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyI+VG90YWwgQ29tcGFuaWVzIGluIExpc3Q8L3RkPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij4xMDQ2PC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyI+VG90YWwgVW5pcXVlIENvbXBhbmllczwvdGQ+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPjkzNzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPkNvbXBhbmllcyB3aXRob3V0IExpbmtlZEluIGluIGxpc3Q8L3RkPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij4xMTc8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij5Ub3RhbCBjb21wYW5pZXMgd2l0aCBMaW5rZWRJbjwvdGQ+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPjgyMDwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPkxpbmtlZEluIFJldHJpZXZlZDwvdGQ+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPjcwNzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPkxpbmtlZEluIE5vdCBSZXRyaWV2ZWQgKE5lZWRzIFJldmlldyk8L3RkPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij4xMTM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij5MaW5rZWRJbiBSZXRyaWV2ZWQgV2VicGFnZTwvdGQ+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsgYmFja2dyb3VuZC1jb2xvcjogI2Q0ZWRkYTsgY29sb3I6ICMxNTU3MjQ7IGZvbnQtd2VpZ2h0OiBib2xkOyI+NzAzPC90ZD4NCiAgICA8L3RyPg0KICA8L3Rib2R5Pg0KPC90YWJsZT4NCg0KKioqKg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgbGlua3MgdGhhdCBjb3VsZCBub3QgYmUgcmV0cmlldmVkIGFyZSBvZnRlbiBpbiA8c3BhbiBzdHlsZT0iZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjZmYwMDAwOyI+c2Nob29sPC9zcGFuPiBmb3JtYXQgcmF0aGVyIHRoYW4gY29tcGFueSBmb3JtYXQuIEhlcmUgaXMgYW4gZXhhbXBsZSBvZiB0aGUgbGlua3MgZnJvbSB3aGljaCBpbmZvcm1hdGlvbiBjb3VsZCBub3QgYmUgY29sbGVjdGVkOg0KPC9wPg0KDQo8aDIgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNnB4OyBjb2xvcjogIzMzMzMzMzsgdGV4dC1hbGlnbjogbGVmdDsgZm9udC13ZWlnaHQ6IGJvbGQ7Ij5GYWlsZWQgTGlua3M6PC9oMj4NCg0KPHVsIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICNmZjAwMDA7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL3NjaG9vbC9rYWx2aXVtLyIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vaW4ubGlua2VkaW4uY29tL3NjaG9vbC9rYWx2aXVtLzwvYT48L2xpPg0KICA8bGk+PGEgaHJlZj0iaHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vc2Nob29sL21hc3RlcnN1bmlvbi8iIHRhcmdldD0iX2JsYW5rIj5odHRwczovL2luLmxpbmtlZGluLmNvbS9zY2hvb2wvbWFzdGVyc3VuaW9uLzwvYT48L2xpPg0KICA8bGk+PGEgaHJlZj0iaHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vc2Nob29sL3Zpcm9oYW4vIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vc2Nob29sL3Zpcm9oYW4vPC9hPjwvbGk+DQogIDxsaT48YSBocmVmPSJodHRwczovL2luLmxpbmtlZGluLmNvbS9zY2hvb2wvZ2Vla3N0ZXJpbi8iIHRhcmdldD0iX2JsYW5rIj5odHRwczovL2luLmxpbmtlZGluLmNvbS9zY2hvb2wvZ2Vla3N0ZXJpbi88L2E+PC9saT4NCiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9zY2hvb2wvMTUxNTAyNTEvIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly93d3cubGlua2VkaW4uY29tL3NjaG9vbC8xNTE1MDI1MS88L2E+PC9saT4NCiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL3NjaG9vbC9ueHR3YXZldGVjaC8iIHRhcmdldD0iX2JsYW5rIj5odHRwczovL2luLmxpbmtlZGluLmNvbS9zY2hvb2wvbnh0d2F2ZXRlY2gvPC9hPjwvbGk+DQogIDxsaT48YSBocmVmPSJodHRwczovL2luLmxpbmtlZGluLmNvbS9zY2hvb2wvcHJlcGluc3RhLyIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vaW4ubGlua2VkaW4uY29tL3NjaG9vbC9wcmVwaW5zdGEvPC9hPjwvbGk+DQogIDxsaT48YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vcHJvZHVjdHMvc2tpbGwtbHluYy8iIHRhcmdldD0iX2JsYW5rIj5odHRwczovL3d3dy5saW5rZWRpbi5jb20vcHJvZHVjdHMvc2tpbGwtbHluYy88L2E+PC9saT4NCjwvdWw+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCldoaWxlIHRoZSBsaW5rcyB0aGF0IGhhdmUgPHNwYW4gc3R5bGU9ImZvbnQtd2VpZ2h0OiBib2xkOyBjb2xvcjogIzI4YTc0NTsiPmNvbXBhbnk8L3NwYW4+IGZvcm1hdCB3b3JrZWQgY29ycmVjdGx5LiBIZXJlIGFyZSBzb21lIGV4YW1wbGVzOg0KPC9wPg0KDQo8aDIgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNnB4OyBjb2xvcjogIzMzMzMzMzsgdGV4dC1hbGlnbjogbGVmdDsgZm9udC13ZWlnaHQ6IGJvbGQ7Ij5TdWNjZXNzZnVsIExpbmtzOjwvaDI+DQoNCjx0YWJsZSBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlOyB3aWR0aDogMTAwJTsgbWF4LXdpZHRoOiA2MDBweDsiPg0KICA8dGhlYWQ+DQogICAgPHRyIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNkNGVkZGE7Ij4NCiAgICAgIDx0aCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyB0ZXh0LWFsaWduOiBsZWZ0OyI+Q29tcGFueSBOYW1lPC90aD4NCiAgICAgIDx0aCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyB0ZXh0LWFsaWduOiBsZWZ0OyI+VVJMPC90aD4NCiAgICA8L3RyPg0KICA8L3RoZWFkPg0KICA8dGJvZHk+DQogICAgPHRyPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij5ieXRlWEw8L3RkPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij48YSBocmVmPSJodHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2J5dGV4bCIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvYnl0ZXhsPC9hPjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPlRvb2RsZTwvdGQ+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPjxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvdG9vZGxlcnVuZ3RhIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vY29tcGFueS90b29kbGVydW5ndGE8L2E+PC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyI+RXVwaGV1cyBMZWFybmluZzwvdGQ+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPjxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvZXVwaGV1cy1sZWFybmluZyIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvZXVwaGV1cy1sZWFybmluZzwvYT48L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij4xMCBNaW51dGUgU2Nob29sPC90ZD4NCiAgICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyI+PGEgaHJlZj0iaHR0cHM6Ly9iZC5saW5rZWRpbi5jb20vY29tcGFueS8xMG1zIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9iZC5saW5rZWRpbi5jb20vY29tcGFueS8xMG1zPC9hPjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPkFkZGEyNDc8L3RkPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij48YSBocmVmPSJodHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2FkZGEyNDciIHRhcmdldD0iX2JsYW5rIj5odHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2FkZGEyNDc8L2E+PC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyI+QXBhcnMgQ2xhc3Nyb29tPC90ZD4NCiAgICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyI+PGEgaHJlZj0iaHR0cHM6Ly9iZC5saW5rZWRpbi5jb20vY29tcGFueS9hcGFyc2NsYXNzcm9vbSIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vYmQubGlua2VkaW4uY29tL2NvbXBhbnkvYXBhcnNjbGFzc3Jvb208L2E+PC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyI+RWR1R29yaWxsYTwvdGQ+DQogICAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGRkZGQ7IHBhZGRpbmc6IDhweDsiPjxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvZWR1Z29yaWxsYS1wdnQtbHRkIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vY29tcGFueS9lZHVnb3JpbGxhLXB2dC1sdGQ8L2E+PC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsgcGFkZGluZzogOHB4OyI+SW5maW5pdHkgTGVhcm48L3RkPg0KICAgICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOyBwYWRkaW5nOiA4cHg7Ij48YSBocmVmPSJodHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2luZmluaXR5LWxlYXJuLWJ5LXNyaS1jaGFpdGFueWEiIHRhcmdldD0iX2JsYW5rIj5odHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2luZmluaXR5LWxlYXJuLWJ5LXNyaS1jaGFpdGFueWE8L2E+PC90ZD4NCiAgICA8L3RyPg0KICA8L3Rib2R5Pg0KPC90YWJsZT4NCg0KDQo8ZGl2IHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmOWY5Zjk7IGJvcmRlci1sZWZ0OjVweCBzb2xpZCAjY2NjOyBwYWRkaW5nOjEwcHg7IG1hcmdpbjoxMHB4IDA7Ij4NCiAgPHA+PHN0cm9uZz5Ob3RlOjwvc3Ryb25nPiBJZiB5b3Ugd2FudCB0byBzZWUgdGhlIHRlY2huaWNhbCBpbmZvcm1hdGlvbiBvZiB0aGUgcHJvY2VzcywgcGxlYXNlIGNsaWNrIHRoZSBidXR0b24gYmVsb3cuPC9wPg0KPC9kaXY+DQoNCg0KPGhlYWQ+DQogIDxtZXRhIGNoYXJzZXQ9IlVURi04Ij4NCiAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjAiPg0KICA8dGl0bGU+RG9jdW1lbnQ8L3RpdGxlPg0KICA8IS0tIEluY2x1eWUgUHJpc20uanMgQ1NTIHBhcmEgZWwgdGVtYSAiVG9tb3Jyb3ciIC0tPg0KICA8bGluayBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9wcmlzbS8xLjI1LjAvdGhlbWVzL3ByaXNtLXRvbW9ycm93Lm1pbi5jc3MiIHJlbD0ic3R5bGVzaGVldCIgLz4NCjwvaGVhZD4NCjxib2R5Pg0KDQoNCjxzdW1tYXJ5IHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmN2ViZmQ7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjE4cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1hbGlnbjogbGVmdDsiPioqVGVjaG5pY2FsIEluZm9ybWF0aW9uKio8L3N1bW1hcnk+DQo8ZGl2IHN0eWxlPSJtYXJnaW4tdG9wOiAxMHB4OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQogIDxwPlRoaXMgc2VjdGlvbiBleHBsYWlucyB0aGUgdGVjaG5pY2FsIGRldGFpbHMgb2YgaG93IHdlIGNvbGxlY3RlZCBhbmQgcHJvY2Vzc2VkIHRoZSBkYXRhLiBIZXJlIGlzIGFuIGVhc3ktdG8tdW5kZXJzdGFuZCBicmVha2Rvd246PC9wPg0KICA8b2wgc3R5bGU9InBhZGRpbmctbGVmdDogMzBweDsiPg0KICAgIDxsaT48c3Ryb25nPkd1ZXN0IE1vZGU6PC9zdHJvbmc+IFRoZSBjb2RlIGFjdHMgbGlrZSBhIGd1ZXN0IGJyb3dzaW5nIExpbmtlZEluLCBtZWFuaW5nIGl0IGRvZXNuJ3QgbG9nIGluIGJ1dCBzdGlsbCByZXRyaWV2ZXMgdGhlIG5lY2Vzc2FyeSBpbmZvcm1hdGlvbi48L2xpPg0KICAgIDxsaT48c3Ryb25nPkZldGNoaW5nIERhdGE6PC9zdHJvbmc+IEl0IGZldGNoZXMgd2ViIHBhZ2VzIGZyb20gTGlua2VkSW4gYW5kIG90aGVyIGNvbXBhbnkgd2Vic2l0ZXMgdG8gZ2V0IHRoZSBIVE1MIGNvbnRlbnQuIFRoaXMgY29udGVudCBpbmNsdWRlcyBhbGwgdGhlIHZpc2libGUgaW5mb3JtYXRpb24gYWJvdXQgYSBjb21wYW55LjwvbGk+DQogICAgPGxpPjxzdHJvbmc+UGFyc2luZyBEYXRhOjwvc3Ryb25nPiBBZnRlciBnZXR0aW5nIHRoZSBIVE1MIGNvbnRlbnQsIHRoZSBjb2RlIGV4dHJhY3RzIHRoZSBpbXBvcnRhbnQgZGV0YWlscyBsaWtlIGNvbXBhbnkgbmFtZSwgYWRkcmVzcywgbnVtYmVyIG9mIGVtcGxveWVlcywgYW5kIGRlc2NyaXB0aW9uLiBUaGlzIGlzIGRvbmUgdXNpbmcgc3BlY2lhbCB0b29scyB0aGF0IGNhbiByZWFkIGFuZCB1bmRlcnN0YW5kIEhUTUwgY29kZS48L2xpPg0KICAgIDxsaT48c3Ryb25nPlN0b3JpbmcgRGF0YTo8L3N0cm9uZz4gVGhlIGV4dHJhY3RlZCBpbmZvcm1hdGlvbiBpcyB0aGVuIG5lYXRseSBvcmdhbml6ZWQgaW50byB0YWJsZXMgKGRhdGFmcmFtZXMpIGFuZCBzYXZlZCBhcyBFeGNlbCBmaWxlcy4gVGhpcyBtYWtlcyBpdCBlYXN5IHRvIHJldmlldyBhbmQgYW5hbHl6ZSB0aGUgZGF0YSBsYXRlci48L2xpPg0KICAgIDxsaT48c3Ryb25nPkVycm9yIEhhbmRsaW5nOjwvc3Ryb25nPiBJZiB0aGVyZSBhcmUgYW55IGlzc3VlcyB3aGlsZSBmZXRjaGluZyB0aGUgZGF0YSwgdGhlIGNvZGUgdHJpZXMgYSBmZXcgbW9yZSB0aW1lcyBiZWZvcmUgZ2l2aW5nIHVwLiBUaGlzIGVuc3VyZXMgdGhhdCBhcyBtdWNoIGRhdGEgYXMgcG9zc2libGUgaXMgY29sbGVjdGVkIHJlbGlhYmx5LjwvbGk+DQogIDwvb2w+DQogIDxwPlRoaXMgYXBwcm9hY2ggYWxsb3dlZCB1cyB0byBnYXRoZXIgY29tcHJlaGVuc2l2ZSBpbmZvcm1hdGlvbiBhYm91dCBlYWNoIGNvbXBhbnksIHdoaWNoIHdhcyB0aGVuIGFuYWx5emVkIHRvIGlkZW50aWZ5IHBvdGVudGlhbCBidXNpbmVzcyBvcHBvcnR1bml0aWVzIGZvciBFZHVOZXh0LjwvcD4NCiAgPHByZT48Y29kZSBjbGFzcz0ibGFuZ3VhZ2UtcHl0aG9uIj4NCmltcG9ydCBqbWVzcGF0aA0KaW1wb3J0IGFzeW5jaW8NCmltcG9ydCBqc29uDQpmcm9tIHR5cGluZyBpbXBvcnQgTGlzdCwgRGljdA0KZnJvbSBodHRweCBpbXBvcnQgQXN5bmNDbGllbnQsIFJlc3BvbnNlLCBSZW1vdGVQcm90b2NvbEVycm9yDQpmcm9tIHBhcnNlbCBpbXBvcnQgU2VsZWN0b3INCmZyb20gbG9ndXJ1IGltcG9ydCBsb2dnZXIgYXMgbG9nDQppbXBvcnQgcGFuZGFzIGFzIHBkDQppbXBvcnQgcmUNCmZyb20gYnM0IGltcG9ydCBCZWF1dGlmdWxTb3VwDQpmcm9tIHVybGxpYi5wYXJzZSBpbXBvcnQgdXJscGFyc2UsIHBhcnNlX3FzDQppbXBvcnQgb3MNCmltcG9ydCB0aW1lDQppbXBvcnQgcmVxdWVzdHMNCg0KIyBJbml0aWFsaXplIGFuIGFzeW5jIGh0dHB4IGNsaWVudA0KY2xpZW50ID0gQXN5bmNDbGllbnQoDQogICAgaHR0cDI9VHJ1ZSwNCiAgICBoZWFkZXJzPXsNCiAgICAgICAgIkFjY2VwdC1MYW5ndWFnZSI6ICJlbi1VUyxlbjtxPTAuOSIsDQogICAgICAgICJVc2VyLUFnZW50IjogIk1vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdpbjY0OyB4NjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS85Ni4wLjQ2NjQuMTEwIFNhZmFyaS81MzcuMzYiLA0KICAgICAgICAiQWNjZXB0IjogInRleHQvaHRtbCxhcHBsaWNhdGlvbi94aHRtbCt4bWwsYXBwbGljYXRpb24veG1sO3E9MC45LGltYWdlL3dlYnAsaW1hZ2UvYXBuZywqLyo7cT0wLjgiLA0KICAgICAgICAiQWNjZXB0LUVuY29kaW5nIjogImd6aXAsIGRlZmxhdGUsIGJyIiwNCiAgICB9LA0KICAgIGZvbGxvd19yZWRpcmVjdHM9VHJ1ZQ0KKQ0KDQpkZWYgc3RyaXBfdGV4dCh0ZXh0KToNCiAgICAiIiJSZW1vdmUgZXh0cmEgc3BhY2VzIHdoaWxlIGhhbmRsaW5nIE5vbmUgdmFsdWVzLiIiIg0KICAgIHJldHVybiB0ZXh0LnN0cmlwKCkgaWYgdGV4dCBpcyBub3QgTm9uZSBlbHNlIHRleHQNCg0KZGVmIGdldF9hY3R1YWxfdXJsKGxpbmspOg0KICAgIHBhcnNlZF91cmwgPSB1cmxwYXJzZShsaW5rKQ0KICAgIHF1ZXJ5X3BhcmFtcyA9IHBhcnNlX3FzKHBhcnNlZF91cmwucXVlcnkpDQogICAgcmV0dXJuIHF1ZXJ5X3BhcmFtc1sndXJsJ11bMF0gaWYgJ3VybCcgaW4gcXVlcnlfcGFyYW1zIGVsc2UgbGluaw0KDQpkZWYgcGFyc2VfY29tcGFueShyZXNwb25zZV90ZXh0OiBzdHIpIC0+IERpY3Q6DQogICAgIiIiUGFyc2UgY29tcGFueSBtYWluIG92ZXJ2aWV3IHBhZ2UuIiIiDQogICAgc2VsZWN0b3IgPSBTZWxlY3RvcihyZXNwb25zZV90ZXh0KQ0KICAgIHNjcmlwdF9kYXRhID0gc2VsZWN0b3IueHBhdGgoIi8vc2NyaXB0W0B0eXBlPSdhcHBsaWNhdGlvbi9sZCtqc29uJ10vdGV4dCgpIikuZ2V0KCkNCiAgICBpZiBzY3JpcHRfZGF0YToNCiAgICAgICAgc2NyaXB0X2RhdGEgPSBqc29uLmxvYWRzKHNjcmlwdF9kYXRhKQ0KICAgIGVsc2U6DQogICAgICAgIHNjcmlwdF9kYXRhID0ge30NCiAgICBzY3JpcHRfZGF0YSA9IGptZXNwYXRoLnNlYXJjaCgNCiAgICAgICAgIiIiew0KICAgICAgICBuYW1lOiBuYW1lLA0KICAgICAgICB1cmw6IHVybCwNCiAgICAgICAgbWFpbkFkZHJlc3M6IGFkZHJlc3MsDQogICAgICAgIGRlc2NyaXB0aW9uOiBkZXNjcmlwdGlvbiwNCiAgICAgICAgbnVtYmVyT2ZFbXBsb3llZXM6IG51bWJlck9mRW1wbG95ZWVzLnZhbHVlLA0KICAgICAgICBsb2dvOiBsb2dvDQogICAgICAgIH0iIiIsDQogICAgICAgIHNjcmlwdF9kYXRhDQogICAgKSBvciB7fQ0KICAgIGRhdGEgPSB7fQ0KICAgIGZvciBlbGVtZW50IGluIHNlbGVjdG9yLnhwYXRoKCIvL2Rpdltjb250YWlucyhAZGF0YS10ZXN0LWlkLCAnYWJvdXQtdXMnKV0iKToNCiAgICAgICAgbmFtZSA9IGVsZW1lbnQueHBhdGgoIi4vL2R0L3RleHQoKSIpLmdldCgpLnN0cmlwKCkNCiAgICAgICAgdmFsdWUgPSBlbGVtZW50LnhwYXRoKCIuLy9kZC90ZXh0KCkiKS5nZXQoKS5zdHJpcCgpDQogICAgICAgIGRhdGFbbmFtZV0gPSB2YWx1ZQ0KICAgIGFkZHJlc3NlcyA9IFtdDQogICAgZm9yIGVsZW1lbnQgaW4gc2VsZWN0b3IueHBhdGgoIi8vZGl2W2NvbnRhaW5zKEBpZCwgJ2FkZHJlc3MnKSBhbmQgQGlkICE9ICdhZGRyZXNzLTAnXSIpOg0KICAgICAgICBhZGRyZXNzX2xpbmVzID0gZWxlbWVudC54cGF0aCgiLi8vcC90ZXh0KCkiKS5nZXRhbGwoKQ0KICAgICAgICBhZGRyZXNzID0gIiwgIi5qb2luKGxpbmUucmVwbGFjZSgiXG4iLCAiIikuc3RyaXAoKSBmb3IgbGluZSBpbiBhZGRyZXNzX2xpbmVzKQ0KICAgICAgICBhZGRyZXNzZXMuYXBwZW5kKGFkZHJlc3MpDQogICAgYWZmaWxpYXRlZF9wYWdlcyA9IFtdDQogICAgZm9yIGVsZW1lbnQgaW4gc2VsZWN0b3IueHBhdGgoIi8vc2VjdGlvbltAZGF0YS10ZXN0LWlkPSdhZmZpbGlhdGVkLXBhZ2VzJ10vZGl2L2Rpdi91bC9saSIpOg0KICAgICAgICBhZmZpbGlhdGVkX3BhZ2VzLmFwcGVuZCh7DQogICAgICAgICAgICAibmFtZSI6IGVsZW1lbnQueHBhdGgoIi4vL2EvZGl2L2gzL3RleHQoKSIpLmdldCgpLnN0cmlwKCksDQogICAgICAgICAgICAiaW5kdXN0cnkiOiBzdHJpcF90ZXh0KGVsZW1lbnQueHBhdGgoIi4vL2EvZGl2L3BbMV0vdGV4dCgpIikuZ2V0KCkpLA0KICAgICAgICAgICAgImFkZHJlc3MiOiBzdHJpcF90ZXh0KGVsZW1lbnQueHBhdGgoIi4vL2EvZGl2L3BbMl0vdGV4dCgpIikuZ2V0KCkpLA0KICAgICAgICAgICAgImxpbmtlaW5VcmwiOiBlbGVtZW50LnhwYXRoKCIuLy9hL0BocmVmIikuZ2V0KCkuc3BsaXQoIj8iKVswXQ0KICAgICAgICB9KQ0KICAgIHNpbWlsYXJfcGFnZXMgPSBbXQ0KICAgIGZvciBlbGVtZW50IGluIHNlbGVjdG9yLnhwYXRoKCIvL3NlY3Rpb25bQGRhdGEtdGVzdC1pZD0nc2ltaWxhci1wYWdlcyddL2Rpdi9kaXYvdWwvbGkiKToNCiAgICAgICAgc2ltaWxhcl9wYWdlcy5hcHBlbmQoew0KICAgICAgICAgICAgIm5hbWUiOiBlbGVtZW50LnhwYXRoKCIuLy9hL2Rpdi9oMy90ZXh0KCkiKS5nZXQoKS5zdHJpcCgpLA0KICAgICAgICAgICAgImluZHVzdHJ5Ijogc3RyaXBfdGV4dChlbGVtZW50LnhwYXRoKCIuLy9hL2Rpdi9wWzFdL3RleHQoKSIpLmdldCgpKSwNCiAgICAgICAgICAgICJhZGRyZXNzIjogc3RyaXBfdGV4dChlbGVtZW50LnhwYXRoKCIuLy9hL2Rpdi9wWzJdL3RleHQoKSIpLmdldCgpKSwNCiAgICAgICAgICAgICJsaW5rZWluVXJsIjogZWxlbWVudC54cGF0aCgiLi8vYS9AaHJlZiIpLmdldCgpLnNwbGl0KCI/IilbMF0NCiAgICAgICAgfSkNCg0KICAgICMgQWRkaXRpb25hbCBmaWVsZHMgZnJvbSB0aGUgc2Vjb25kIHNjcmlwdA0KICAgIHNvdXAgPSBCZWF1dGlmdWxTb3VwKHJlc3BvbnNlX3RleHQsICdodG1sLnBhcnNlcicpDQogICAgdGl0bGVfdGFnID0gc291cC5maW5kKCd0aXRsZScpDQogICAgZGVzaWduYXRpb25fdGFnID0gc291cC5maW5kKCdoMicpDQogICAgZm9sbG93ZXJzX3RhZyA9IHNvdXAuZmluZCgnbWV0YScsIHsicHJvcGVydHkiOiAib2c6ZGVzY3JpcHRpb24ifSkNCiAgICBkZXNjcmlwdGlvbl90YWcgPSBzb3VwLmZpbmQoJ3AnLCBjbGFzc189J2JyZWFrLXdvcmRzJykNCiAgICB3ZWJzaXRlX3RhZyA9IHNvdXAuZmluZCgnYScsIGF0dHJzPXsnZGF0YS10cmFja2luZy1jb250cm9sLW5hbWUnOiAnYWJvdXRfd2Vic2l0ZSd9KQ0KICAgIHdlYnNpdGUgPSBnZXRfYWN0dWFsX3VybCh3ZWJzaXRlX3RhZ1snaHJlZiddKSBpZiB3ZWJzaXRlX3RhZyBlbHNlICJXZWJzaXRlIG5vdCBmb3VuZCINCiAgICBkZXNjcmlwdGlvbl9zcGFuID0gc291cC5maW5kKCdoNCcsIGNsYXNzXz0ndG9wLWNhcmQtbGF5b3V0X19zZWNvbmQtc3VibGluZScpDQogICAgZGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbl9zcGFuLmdldF90ZXh0KHN0cmlwPVRydWUpIGlmIGRlc2NyaXB0aW9uX3NwYW4gZWxzZSAiRGVzY3JpcHRpb24gbm90IGZvdW5kIg0KICAgIA0KICAgICMgQ3J1bmNoYmFzZSBmdW5kaW5nIGluZm9ybWF0aW9uDQogICAgZnVuZGluZ19zZWN0aW9uID0gc291cC5maW5kKCdzZWN0aW9uJywgYXR0cnM9eydkYXRhLXRlc3QtaWQnOiAnZnVuZGluZyd9KQ0KICAgIGlmIGZ1bmRpbmdfc2VjdGlvbjoNCiAgICAgICAgYWxsX3JvdW5kc190YWcgPSBmdW5kaW5nX3NlY3Rpb24uZmluZCgnYScsIGF0dHJzPXsnZGF0YS10cmFja2luZy1jb250cm9sLW5hbWUnOiAnZnVuZGluZ19hbGwtcm91bmRzJ30pDQogICAgICAgIGlmIGFsbF9yb3VuZHNfdGFnOg0KICAgICAgICAgICAgYWxsX3JvdW5kc19tYXRjaCA9IHJlLnNlYXJjaChyJyhcZCsgdG90YWwgcm91bmRzKScsIGFsbF9yb3VuZHNfdGFnLmdldF90ZXh0KHN0cmlwPVRydWUpKQ0KICAgICAgICAgICAgYWxsX3JvdW5kc19pbmZvID0gYWxsX3JvdW5kc19tYXRjaC5ncm91cCgxKSBpZiBhbGxfcm91bmRzX21hdGNoIGVsc2UgIkFsbCByb3VuZHMgaW5mbyBub3QgZm91bmQiDQogICAgICAgIGVsc2U6DQogICAgICAgICAgICBhbGxfcm91bmRzX2luZm8gPSAiQWxsIHJvdW5kcyBpbmZvIG5vdCBmb3VuZCINCg0KICAgICAgICBsYXN0X3JvdW5kX3RhZyA9IGZ1bmRpbmdfc2VjdGlvbi5maW5kKCdhJywgYXR0cnM9eydkYXRhLXRyYWNraW5nLWNvbnRyb2wtbmFtZSc6ICdmdW5kaW5nX2xhc3Qtcm91bmQnfSkNCiAgICAgICAgaWYgbGFzdF9yb3VuZF90YWc6DQogICAgICAgICAgICBsYXN0X3JvdW5kX2luZm8gPSBsYXN0X3JvdW5kX3RhZy5maW5kKCd0aW1lJykuZ2V0X3RleHQoc3RyaXA9VHJ1ZSkNCiAgICAgICAgICAgIGxhc3Rfcm91bmRfYW1vdW50X3RhZyA9IGZ1bmRpbmdfc2VjdGlvbi5maW5kKCdwJywgY2xhc3NfPSd0ZXh0LWRpc3BsYXktbGcnKQ0KICAgICAgICAgICAgbGFzdF9yb3VuZF9hbW91bnQgPSBsYXN0X3JvdW5kX2Ftb3VudF90YWcuZ2V0X3RleHQoc3RyaXA9VHJ1ZSkgaWYgbGFzdF9yb3VuZF9hbW91bnRfdGFnIGVsc2UgIkxhc3Qgcm91bmQgYW1vdW50IG5vdCBmb3VuZCINCiAgICAgICAgICAgIGxhc3Rfcm91bmRfbGluayA9IGxhc3Rfcm91bmRfdGFnWydocmVmJ10NCiAgICAgICAgICAgIGxhc3Rfcm91bmRfZm9ybWF0dGVkX2RhdGUgPSBsYXN0X3JvdW5kX3RhZy5maW5kKCd0aW1lJylbJ2RhdGV0aW1lJ10NCiAgICAgICAgZWxzZToNCiAgICAgICAgICAgIGxhc3Rfcm91bmRfaW5mbyA9ICJMYXN0IHJvdW5kIGluZm8gbm90IGZvdW5kIg0KICAgICAgICAgICAgbGFzdF9yb3VuZF9hbW91bnQgPSAiTGFzdCByb3VuZCBhbW91bnQgbm90IGZvdW5kIg0KICAgICAgICAgICAgbGFzdF9yb3VuZF9saW5rID0gIkxhc3Qgcm91bmQgbGluayBub3QgZm91bmQiDQogICAgICAgICAgICBsYXN0X3JvdW5kX2Zvcm1hdHRlZF9kYXRlID0gIkxhc3Qgcm91bmQgZGF0ZSBub3QgZm91bmQiDQoNCiAgICAgICAgaW52ZXN0b3JzX3RhZyA9IGZ1bmRpbmdfc2VjdGlvbi5maW5kKCdhJywgYXR0cnM9eydkYXRhLXRyYWNraW5nLWNvbnRyb2wtbmFtZSc6ICdmdW5kaW5nX2ludmVzdG9ycyd9KQ0KICAgICAgICBpbnZlc3RvcnNfaW5mbyA9IGludmVzdG9yc190YWcuZ2V0X3RleHQoc3RyaXA9VHJ1ZSkgaWYgaW52ZXN0b3JzX3RhZyBlbHNlICJJbnZlc3RvcnMgaW5mbyBub3QgZm91bmQiDQogICAgZWxzZToNCiAgICAgICAgYWxsX3JvdW5kc19pbmZvID0gIkNydW5jaGJhc2UgZnVuZGluZyBpbmZvIG5vdCBmb3VuZCINCiAgICAgICAgbGFzdF9yb3VuZF9pbmZvID0gIkxhc3Qgcm91bmQgaW5mbyBub3QgZm91bmQiDQogICAgICAgIGxhc3Rfcm91bmRfYW1vdW50ID0gIkxhc3Qgcm91bmQgYW1vdW50IG5vdCBmb3VuZCINCiAgICAgICAgaW52ZXN0b3JzX2luZm8gPSAiSW52ZXN0b3JzIGluZm8gbm90IGZvdW5kIg0KICAgICAgICBsYXN0X3JvdW5kX2xpbmsgPSAiTGFzdCByb3VuZCBsaW5rIG5vdCBmb3VuZCINCiAgICAgICAgbGFzdF9yb3VuZF9mb3JtYXR0ZWRfZGF0ZSA9ICJMYXN0IHJvdW5kIGRhdGUgbm90IGZvdW5kIg0KDQogICAgIyBDaGVjayBpZiB0aGUgdGFncyBhcmUgZm91bmQgYmVmb3JlIGNhbGxpbmcgZ2V0X3RleHQoKQ0KICAgIG5hbWUgPSB0aXRsZV90YWcuZ2V0X3RleHQoc3RyaXA9VHJ1ZSkuc3BsaXQoInwiKVswXS5zdHJpcCgpIGlmIHRpdGxlX3RhZyBlbHNlICJQcm9maWxlIE5hbWUgbm90IGZvdW5kIg0KICAgIGRlc2lnbmF0aW9uID0gZGVzaWduYXRpb25fdGFnLmdldF90ZXh0KHN0cmlwPVRydWUpIGlmIGRlc2lnbmF0aW9uX3RhZyBlbHNlICJEZXNpZ25hdGlvbiBub3QgZm91bmQiDQogICAgZm9sbG93ZXJzX21hdGNoID0gcmUuc2VhcmNoKHInXGIoXGRbXGQsLl0qKVxzK2ZvbGxvd2Vyc1xiJywgZm9sbG93ZXJzX3RhZ1siY29udGVudCJdKSBpZiBmb2xsb3dlcnNfdGFnIGVsc2UgTm9uZQ0KICAgIGZvbGxvd2Vyc19jb3VudCA9IGZvbGxvd2Vyc19tYXRjaC5ncm91cCgxKSBpZiBmb2xsb3dlcnNfbWF0Y2ggZWxzZSAiRm9sbG93ZXJzIGNvdW50IG5vdCBmb3VuZCINCiAgICBkZXNjcmlwdGlvbl9wcm9maWxlID0gZGVzY3JpcHRpb25fdGFnLmdldF90ZXh0KHN0cmlwPVRydWUpIGlmIGRlc2NyaXB0aW9uX3RhZyBlbHNlICJQcm9maWxlIERlc2NyaXB0aW9uIG5vdCBmb3VuZCINCg0KICAgIGFkZGl0aW9uYWxfZGF0YSA9IHsNCiAgICAgICAgInByb2ZpbGVOYW1lIjogbmFtZSwNCiAgICAgICAgImRlc2lnbmF0aW9uIjogZGVzaWduYXRpb24sDQogICAgICAgICJmb2xsb3dlcnNDb3VudCI6IGZvbGxvd2Vyc19jb3VudCwNCiAgICAgICAgInByb2ZpbGVEZXNjcmlwdGlvbiI6IGRlc2NyaXB0aW9uX3Byb2ZpbGUsDQogICAgICAgICJ3ZWJzaXRlIjogd2Vic2l0ZSwNCiAgICAgICAgImNydW5jaGJhc2VBbGxSb3VuZHNJbmZvIjogYWxsX3JvdW5kc19pbmZvLA0KICAgICAgICAiY3J1bmNoYmFzZUxhc3RSb3VuZEluZm8iOiBsYXN0X3JvdW5kX2luZm8sDQogICAgICAgICJjcnVuY2hiYXNlTGFzdFJvdW5kQW1vdW50IjogbGFzdF9yb3VuZF9hbW91bnQsDQogICAgICAgICJjcnVuY2hiYXNlSW52ZXN0b3JzSW5mbyI6IGludmVzdG9yc19pbmZvLA0KICAgICAgICAibGFzdFJvdW5kRm9ybWF0dGVkRGF0ZSI6IGxhc3Rfcm91bmRfZm9ybWF0dGVkX2RhdGUsDQogICAgICAgICJjcnVuY2hiYXNlTGluayI6IGxhc3Rfcm91bmRfbGluaywNCiAgICB9DQoNCiAgICBkYXRhID0geyoqc2NyaXB0X2RhdGEsICoqZGF0YSwgKiphZGRpdGlvbmFsX2RhdGF9DQogICAgZGF0YVsiYWRkcmVzc2VzIl0gPSBhZGRyZXNzZXMgICAgDQogICAgZGF0YVsiYWZmaWxpYXRlZFBhZ2VzIl0gPSBhZmZpbGlhdGVkX3BhZ2VzDQogICAgZGF0YVsic2ltaWxhclBhZ2VzIl0gPSBzaW1pbGFyX3BhZ2VzDQogICAgcmV0dXJuIGRhdGENCg0KZGVmIHJlYWRfbGlua3NfZnJvbV9maWxlKGZpbGVfcGF0aDogc3RyKSAtPiBMaXN0W3N0cl06DQogICAgIiIiUmVhZCBVUkxzIGZyb20gYSB0ZXh0IG9yIEV4Y2VsIGZpbGUuIiIiDQogICAgaWYgZmlsZV9wYXRoLmVuZHN3aXRoKCcudHh0Jyk6DQogICAgICAgIHdpdGggb3BlbihmaWxlX3BhdGgsICdyJykgYXMgZmlsZToNCiAgICAgICAgICAgIHVybHMgPSBmaWxlLnJlYWQoKS5zcGxpdGxpbmVzKCkNCiAgICBlbGlmIGZpbGVfcGF0aC5lbmRzd2l0aCgnLnhsc3gnKToNCiAgICAgICAgZGYgPSBwZC5yZWFkX2V4Y2VsKGZpbGVfcGF0aCkNCiAgICAgICAgdXJscyA9IGRmWydMaW5rcyddLnRvbGlzdCgpDQogICAgZWxzZToNCiAgICAgICAgcmFpc2UgVmFsdWVFcnJvcigiVW5zdXBwb3J0ZWQgZmlsZSBmb3JtYXQuIFBsZWFzZSB1c2UgYSAudHh0IG9yIC54bHN4IGZpbGUuIikNCiAgICByZXR1cm4gdXJscw0KDQojIEluaXRpYWxpemUgZGF0YWZyYW1lcyBnbG9iYWxseQ0KZGZfY29tcGFueV9pbmZvID0gcGQuRGF0YUZyYW1lKCkNCmRmX2NvbXBhbnlfYWRkcmVzc2VzID0gcGQuRGF0YUZyYW1lKCkNCmRmX2FmZmlsaWF0ZWRfcGFnZXMgPSBwZC5EYXRhRnJhbWUoKQ0KZGZfc2ltaWxhcl9wYWdlcyA9IHBkLkRhdGFGcmFtZSgpDQoNCmFzeW5jIGRlZiBmZXRjaF93aXRoX3JldHJ5KHVybCwgcmV0cmllcz0zLCBiYWNrb2ZmX2ZhY3Rvcj0wLjUpOg0KICAgIGZvciBhdHRlbXB0IGluIHJhbmdlKHJldHJpZXMpOg0KICAgICAgICB0cnk6DQogICAgICAgICAgICByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5nZXQodXJsKQ0KICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlDQogICAgICAgIGV4Y2VwdCBSZW1vdGVQcm90b2NvbEVycm9yIGFzIGU6DQogICAgICAgICAgICBsb2cuZXJyb3IoZiJBdHRlbXB0IHthdHRlbXB0ICsgMX0gZm9yIHt1cmx9IGZhaWxlZDoge2V9IikNCiAgICAgICAgICAgIHRpbWUuc2xlZXAoYmFja29mZl9mYWN0b3IgKiAoMiAqKiBhdHRlbXB0KSkNCiAgICByYWlzZSBFeGNlcHRpb24oZiJBbGwge3JldHJpZXN9IGF0dGVtcHRzIGZhaWxlZCBmb3Ige3VybH0iKQ0KDQpkZWYgZmV0Y2hfd2l0aF9yZXF1ZXN0cyh1cmwsIHJldHJpZXM9MywgYmFja29mZl9mYWN0b3I9MC41KToNCiAgICBoZWFkZXJzID0gew0KICAgICAgICAiVXNlci1BZ2VudCI6ICJHdWVzdCIsDQogICAgfQ0KICAgIGZvciBhdHRlbXB0IGluIHJhbmdlKHJldHJpZXMpOg0KICAgICAgICB0cnk6DQogICAgICAgICAgICByZXNwb25zZSA9IHJlcXVlc3RzLmdldCh1cmwsIGhlYWRlcnM9aGVhZGVycykNCiAgICAgICAgICAgIGlmIHJlc3BvbnNlLnN0YXR1c19jb2RlID09IDIwMDoNCiAgICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2UNCiAgICAgICAgZXhjZXB0IHJlcXVlc3RzLlJlcXVlc3RFeGNlcHRpb24gYXMgZToNCiAgICAgICAgICAgIGxvZy5lcnJvcihmIkF0dGVtcHQge2F0dGVtcHQgKyAxfSBmb3Ige3VybH0gZmFpbGVkOiB7ZX0iKQ0KICAgICAgICAgICAgdGltZS5zbGVlcChiYWNrb2ZmX2ZhY3RvciAqICgyICoqIGF0dGVtcHQpKQ0KICAgIHJhaXNlIEV4Y2VwdGlvbihmIkFsbCB7cmV0cmllc30gYXR0ZW1wdHMgZmFpbGVkIGZvciB7dXJsfSIpDQoNCmFzeW5jIGRlZiBzY3JhcGVfY29tcGFueSh1cmxzOiBMaXN0W3N0cl0pIC0+IExpc3RbRGljdF06DQogICAgIiIiU2NyYXBlIHB1YmxpYyBMaW5rZWRJbiBjb21wYW55IHBhZ2VzLiIiIg0KICAgIGRhdGEgPSBbXQ0KICAgIGZhaWxlZF9saW5rcyA9IFtdDQogICAgZm9yIHVybCBpbiB1cmxzOg0KICAgICAgICB0cnk6DQogICAgICAgICAgICByZXNwb25zZSA9IGF3YWl0IGZldGNoX3dpdGhfcmV0cnkodXJsKQ0KICAgICAgICAgICAgaWYgcmVzcG9uc2Uuc3RhdHVzX2NvZGUgPT0gMjAwOg0KICAgICAgICAgICAgICAgIGRhdGEuYXBwZW5kKHBhcnNlX2NvbXBhbnkocmVzcG9uc2UudGV4dCkpDQogICAgICAgICAgICAgICAgbG9nLnN1Y2Nlc3MoZiJTdWNjZXNzZnVsbHkgc2NyYXBlZCB7dXJsfSIpDQogICAgICAgICAgICBlbGlmIHJlc3BvbnNlLnN0YXR1c19jb2RlID09IDk5OTogICMgVXNlIHJlcXVlc3RzIGFzIGZhbGxiYWNrDQogICAgICAgICAgICAgICAgbG9nLndhcm5pbmcoZiJTdGF0dXMgY29kZSA5OTkgZm9yIHt1cmx9LCBzd2l0Y2hpbmcgdG8gcmVxdWVzdHMiKQ0KICAgICAgICAgICAgICAgIHJlc3BvbnNlID0gZmV0Y2hfd2l0aF9yZXF1ZXN0cyh1cmwpDQogICAgICAgICAgICAgICAgaWYgcmVzcG9uc2Uuc3RhdHVzX2NvZGUgPT0gMjAwOg0KICAgICAgICAgICAgICAgICAgICBkYXRhLmFwcGVuZChwYXJzZV9jb21wYW55KHJlc3BvbnNlLnRleHQpKQ0KICAgICAgICAgICAgICAgICAgICBsb2cuc3VjY2VzcyhmIlN1Y2Nlc3NmdWxseSBzY3JhcGVkIHt1cmx9IHdpdGggcmVxdWVzdHMgZmFsbGJhY2siKQ0KICAgICAgICAgICAgICAgIGVsc2U6DQogICAgICAgICAgICAgICAgICAgIGZhaWxlZF9saW5rcy5hcHBlbmQodXJsKQ0KICAgICAgICAgICAgICAgICAgICBsb2cuZXJyb3IoZiJGYWlsZWQgdG8gc2NyYXBlIHt1cmx9IHdpdGggc3RhdHVzIGNvZGUge3Jlc3BvbnNlLnN0YXR1c19jb2RlfSIpDQogICAgICAgICAgICBlbHNlOg0KICAgICAgICAgICAgICAgIGZhaWxlZF9saW5rcy5hcHBlbmQodXJsKQ0KICAgICAgICAgICAgICAgIGxvZy5lcnJvcihmIkZhaWxlZCB0byBzY3JhcGUge3VybH0gd2l0aCBzdGF0dXMgY29kZSB7cmVzcG9uc2Uuc3RhdHVzX2NvZGV9IikNCiAgICAgICAgICAgICMgRGVsYXkgYmV0d2VlbiByZXF1ZXN0cyB0byBhdm9pZCByYXRlIGxpbWl0aW5nDQogICAgICAgICAgICB0aW1lLnNsZWVwKDEpDQogICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToNCiAgICAgICAgICAgIGZhaWxlZF9saW5rcy5hcHBlbmQodXJsKQ0KICAgICAgICAgICAgbG9nLmVycm9yKGYiRXJyb3Igc2NyYXBpbmcge3VybH06IHtlfSIpDQogICAgcmV0dXJuIGRhdGEsIGZhaWxlZF9saW5rcw0KDQphc3luYyBkZWYgcnVuKCk6DQogICAgdXJscyA9IHJlYWRfbGlua3NfZnJvbV9maWxlKCdwcm9maWxlcy50eHQnKSAgIyBVc2luZyB0aGUgJ3Byb2ZpbGVzLnR4dCcgZmlsZQ0KICAgIHByb2ZpbGVfZGF0YSwgZmFpbGVkX2xpbmtzID0gYXdhaXQgc2NyYXBlX2NvbXBhbnkodXJscykNCiAgICANCiAgICBnbG9iYWwgZGZfY29tcGFueV9pbmZvLCBkZl9jb21wYW55X2FkZHJlc3NlcywgZGZfYWZmaWxpYXRlZF9wYWdlcywgZGZfc2ltaWxhcl9wYWdlcw0KDQogICAgZm9yIGNvbXBhbnkgaW4gcHJvZmlsZV9kYXRhOg0KICAgICAgICBtYWluX2FkZHJlc3MgPSBjb21wYW55LmdldCgnbWFpbkFkZHJlc3MnLCB7fSkNCiAgICAgICAgY29tcGFueV9pbmZvID0gew0KICAgICAgICAgICAgIm5hbWUiOiBjb21wYW55LmdldCgibmFtZSIpLA0KICAgICAgICAgICAgInVybCI6IGNvbXBhbnkuZ2V0KCJ1cmwiKSwNCiAgICAgICAgICAgICJzdHJlZXRBZGRyZXNzIjogbWFpbl9hZGRyZXNzLmdldCgic3RyZWV0QWRkcmVzcyIpIGlmIG1haW5fYWRkcmVzcyBlbHNlIE5vbmUsDQogICAgICAgICAgICAiYWRkcmVzc0xvY2FsaXR5IjogbWFpbl9hZGRyZXNzLmdldCgiYWRkcmVzc0xvY2FsaXR5IikgaWYgbWFpbl9hZGRyZXNzIGVsc2UgTm9uZSwNCiAgICAgICAgICAgICJhZGRyZXNzUmVnaW9uIjogbWFpbl9hZGRyZXNzLmdldCgiYWRkcmVzc1JlZ2lvbiIpIGlmIG1haW5fYWRkcmVzcyBlbHNlIE5vbmUsDQogICAgICAgICAgICAicG9zdGFsQ29kZSI6IG1haW5fYWRkcmVzcy5nZXQoInBvc3RhbENvZGUiKSBpZiBtYWluX2FkZHJlc3MgZWxzZSBOb25lLA0KICAgICAgICAgICAgImFkZHJlc3NDb3VudHJ5IjogbWFpbl9hZGRyZXNzLmdldCgiYWRkcmVzc0NvdW50cnkiKSBpZiBtYWluX2FkZHJlc3MgZWxzZSBOb25lLA0KICAgICAgICAgICAgImRlc2NyaXB0aW9uIjogY29tcGFueS5nZXQoImRlc2NyaXB0aW9uIiksDQogICAgICAgICAgICAibnVtYmVyT2ZFbXBsb3llZXMiOiBjb21wYW55LmdldCgibnVtYmVyT2ZFbXBsb3llZXMiKSwNCiAgICAgICAgICAgICJJbmR1c3RyeSI6IGNvbXBhbnkuZ2V0KCJJbmR1c3RyeSIpLA0KICAgICAgICAgICAgIkNvbXBhbnkgc2l6ZSI6IGNvbXBhbnkuZ2V0KCJDb21wYW55IHNpemUiKSwNCiAgICAgICAgICAgICJIZWFkcXVhcnRlcnMiOiBjb21wYW55LmdldCgiSGVhZHF1YXJ0ZXJzIiksDQogICAgICAgICAgICAiVHlwZSI6IGNvbXBhbnkuZ2V0KCJUeXBlIiksDQogICAgICAgICAgICAiU3BlY2lhbHRpZXMiOiBjb21wYW55LmdldCgiU3BlY2lhbHRpZXMiKSwNCiAgICAgICAgICAgICJwcm9maWxlTmFtZSI6IGNvbXBhbnkuZ2V0KCJwcm9maWxlTmFtZSIpLA0KICAgICAgICAgICAgImRlc2lnbmF0aW9uIjogY29tcGFueS5nZXQoImRlc2lnbmF0aW9uIiksDQogICAgICAgICAgICAiZm9sbG93ZXJzQ291bnQiOiBjb21wYW55LmdldCgiZm9sbG93ZXJzQ291bnQiKSwNCiAgICAgICAgICAgICJwcm9maWxlRGVzY3JpcHRpb24iOiBjb21wYW55LmdldCgicHJvZmlsZURlc2NyaXB0aW9uIiksDQogICAgICAgICAgICAid2Vic2l0ZSI6IGNvbXBhbnkuZ2V0KCJ3ZWJzaXRlIiksDQogICAgICAgICAgICAiY3J1bmNoYmFzZUFsbFJvdW5kc0luZm8iOiBjb21wYW55LmdldCgiY3J1bmNoYmFzZUFsbFJvdW5kc0luZm8iKSwNCiAgICAgICAgICAgICJjcnVuY2hiYXNlTGFzdFJvdW5kSW5mbyI6IGNvbXBhbnkuZ2V0KCJjcnVuY2hiYXNlTGFzdFJvdW5kSW5mbyIpLA0KICAgICAgICAgICAgImNydW5jaGJhc2VMYXN0Um91bmRBbW91bnQiOiBjb21wYW55LmdldCgiY3J1bmNoYmFzZUxhc3RSb3VuZEFtb3VudCIpLA0KICAgICAgICAgICAgImNydW5jaGJhc2VJbnZlc3RvcnNJbmZvIjogY29tcGFueS5nZXQoImNydW5jaGJhc2VJbnZlc3RvcnNJbmZvIiksDQogICAgICAgICAgICAibGFzdFJvdW5kRm9ybWF0dGVkRGF0ZSI6IGNvbXBhbnkuZ2V0KCJsYXN0Um91bmRGb3JtYXR0ZWREYXRlIiksDQogICAgICAgICAgICAiY3J1bmNoYmFzZUxpbmsiOiBjb21wYW55LmdldCgiY3J1bmNoYmFzZUxpbmsiKSwNCiAgICAgICAgfQ0KICAgICAgICBkZl9jb21wYW55X2luZm8gPSBwZC5jb25jYXQoW2RmX2NvbXBhbnlfaW5mbywgcGQuRGF0YUZyYW1lKFtjb21wYW55X2luZm9dKV0pDQoNCiAgICAgICAgZm9yIGFkZHJlc3MgaW4gY29tcGFueS5nZXQoImFkZHJlc3NlcyIsIFtdKToNCiAgICAgICAgICAgIHBhcnRzID0gYWRkcmVzcy5zcGxpdCgiLCAiKQ0KICAgICAgICAgICAgY291bnRyeSA9IHBhcnRzWy0xXSBpZiBwYXJ0cyBlbHNlICIiDQogICAgICAgICAgICBjb21wYW55X2FkZHJlc3MgPSB7DQogICAgICAgICAgICAgICAgIm5hbWUiOiBjb21wYW55LmdldCgibmFtZSIpLA0KICAgICAgICAgICAgICAgICJ1cmwiOiBjb21wYW55LmdldCgidXJsIiksDQogICAgICAgICAgICAgICAgImFkZHJlc3NlcyI6IGFkZHJlc3MsDQogICAgICAgICAgICAgICAgImNvdW50cnkgb2ZmaWNlcyI6IGNvdW50cnkNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIGRmX2NvbXBhbnlfYWRkcmVzc2VzID0gcGQuY29uY2F0KFtkZl9jb21wYW55X2FkZHJlc3NlcywgcGQuRGF0YUZyYW1lKFtjb21wYW55X2FkZHJlc3NdKV0pDQoNCiAgICAgICAgZm9yIGFmZmlsaWF0ZWQgaW4gY29tcGFueS5nZXQoImFmZmlsaWF0ZWRQYWdlcyIsIFtdKToNCiAgICAgICAgICAgIGFmZmlsaWF0ZWRfcGFnZSA9IHsNCiAgICAgICAgICAgICAgICAibmFtZSI6IGNvbXBhbnkuZ2V0KCJuYW1lIiksDQogICAgICAgICAgICAgICAgInVybCI6IGNvbXBhbnkuZ2V0KCJ1cmwiKSwNCiAgICAgICAgICAgICAgICAiYWZmaWxpYXRlZF9uYW1lIjogYWZmaWxpYXRlZFsibmFtZSJdLA0KICAgICAgICAgICAgICAgICJpbmR1c3RyeSI6IGFmZmlsaWF0ZWRbImluZHVzdHJ5Il0sDQogICAgICAgICAgICAgICAgImFkZHJlc3MiOiBhZmZpbGlhdGVkWyJhZGRyZXNzIl0sDQogICAgICAgICAgICAgICAgImxpbmtlaW5VcmwiOiBhZmZpbGlhdGVkWyJsaW5rZWluVXJsIl0NCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIGRmX2FmZmlsaWF0ZWRfcGFnZXMgPSBwZC5jb25jYXQoW2RmX2FmZmlsaWF0ZWRfcGFnZXMsIHBkLkRhdGFGcmFtZShbYWZmaWxpYXRlZF9wYWdlXSldKQ0KDQogICAgICAgIGZvciBzaW1pbGFyIGluIGNvbXBhbnkuZ2V0KCJzaW1pbGFyUGFnZXMiLCBbXSk6DQogICAgICAgICAgICBzaW1pbGFyX3BhZ2UgPSB7DQogICAgICAgICAgICAgICAgIm5hbWUiOiBjb21wYW55LmdldCgibmFtZSIpLA0KICAgICAgICAgICAgICAgICJ1cmwiOiBjb21wYW55LmdldCgidXJsIiksDQogICAgICAgICAgICAgICAgInNpbWlsYXJfbmFtZSI6IHNpbWlsYXJbIm5hbWUiXSwNCiAgICAgICAgICAgICAgICAiaW5kdXN0cnkiOiBzaW1pbGFyWyJpbmR1c3RyeSJdLA0KICAgICAgICAgICAgICAgICJhZGRyZXNzIjogc2ltaWxhclsiYWRkcmVzcyJdLA0KICAgICAgICAgICAgICAgICJsaW5rZWluVXJsIjogc2ltaWxhclsibGlua2VpblVybCJdDQogICAgICAgICAgICB9DQogICAgICAgICAgICBkZl9zaW1pbGFyX3BhZ2VzID0gcGQuY29uY2F0KFtkZl9zaW1pbGFyX3BhZ2VzLCBwZC5EYXRhRnJhbWUoW3NpbWlsYXJfcGFnZV0pXSkNCg0KICAgICAgICAjIFNhdmUgdG8gRXhjZWwgYWZ0ZXIgZWFjaCBjb21wYW55DQogICAgICAgIGRmX2NvbXBhbnlfaW5mby50b19leGNlbCgiY29tcGFueV9pbmZvcm1hdGlvbi54bHN4IiwgaW5kZXg9RmFsc2UpDQogICAgICAgIGRmX2NvbXBhbnlfYWRkcmVzc2VzLnRvX2V4Y2VsKCJjb21wYW55X2FkZHJlc3Nlcy54bHN4IiwgaW5kZXg9RmFsc2UpDQogICAgICAgIGRmX2FmZmlsaWF0ZWRfcGFnZXMudG9fZXhjZWwoImFmZmlsaWF0ZWRfcGFnZXMueGxzeCIsIGluZGV4PUZhbHNlKQ0KICAgICAgICBkZl9zaW1pbGFyX3BhZ2VzLnRvX2V4Y2VsKCJzaW1pbGFyX3BhZ2VzLnhsc3giLCBpbmRleD1GYWxzZSkNCg0KICAgIGlmIGZhaWxlZF9saW5rczoNCiAgICAgICAgZGZfZmFpbGVkX2xpbmtzID0gcGQuRGF0YUZyYW1lKHsiZmFpbGVkX2xpbmtzIjogZmFpbGVkX2xpbmtzfSkNCiAgICAgICAgZGZfZmFpbGVkX2xpbmtzLnRvX2V4Y2VsKCJmYWlsZWRfbGlua3MueGxzeCIsIGluZGV4PUZhbHNlKQ0KDQppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOg0KICAgIHRyeToNCiAgICAgICAgYXN5bmNpby5ydW4ocnVuKCkpDQogICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOg0KICAgICAgICBsb2cuZXJyb3IoZiJTY3JpcHQgdGVybWluYXRlZCBkdWUgdG8gYW4gZXJyb3I6IHtlfSIpDQoNCiAgICAgICAgIyBTYXZlIHdoYXQgaGFzIGJlZW4gc2NyYXBlZCBzbyBmYXINCiAgICAgICAgaWYgbm90IGRmX2NvbXBhbnlfaW5mby5lbXB0eToNCiAgICAgICAgICAgIGRmX2NvbXBhbnlfaW5mby50b19leGNlbCgiY29tcGFueV9pbmZvcm1hdGlvbi54bHN4IiwgaW5kZXg9RmFsc2UpDQogICAgICAgIGlmIG5vdCBkZl9jb21wYW55X2FkZHJlc3Nlcy5lbXB0eToNCiAgICAgICAgICAgIGRmX2NvbXBhbnlfYWRkcmVzc2VzLnRvX2V4Y2VsKCJjb21wYW55X2FkZHJlc3Nlcy54bHN4IiwgaW5kZXg9RmFsc2UpDQogICAgICAgIGlmIG5vdCBkZl9hZmZpbGlhdGVkX3BhZ2VzLmVtcHR5Og0KICAgICAgICAgICAgZGZfYWZmaWxpYXRlZF9wYWdlcy50b19leGNlbCgiYWZmaWxpYXRlZF9wYWdlcy54bHN4IiwgaW5kZXg9RmFsc2UpDQogICAgICAgIGlmIG5vdCBkZl9zaW1pbGFyX3BhZ2VzLmVtcHR5Og0KICAgICAgICAgICAgZGZfc2ltaWxhcl9wYWdlcy50b19leGNlbCgic2ltaWxhcl9wYWdlcy54bHN4IiwgaW5kZXg9RmFsc2UpDQoNCjwvY29kZT48L3ByZT4NCjwvZGl2Pg0KDQoNCjwhLS0gSW5jbHV5ZSBQcmlzbS5qcyAtLT4NCjxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9wcmlzbS8xLjI1LjAvcHJpc20ubWluLmpzIj48L3NjcmlwdD4NCjxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9wcmlzbS8xLjI1LjAvY29tcG9uZW50cy9wcmlzbS1weXRob24ubWluLmpzIj48L3NjcmlwdD4NCg0KPC9ib2R5Pg0KPC9odG1sPg0KDQoqKioqDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoZSBkYXRhIGNvbGxlY3Rpb24gYW5kIGFuYWx5c2lzIHByb2Nlc3MgZ2VuZXJhdGVzIGZvdXIgbWFpbiBvdXRwdXRzLg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyBtYXJnaW4tYm90dG9tOiAyMHB4OyI+DQogIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlOWY1ZGI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPjxiPjEuIExpbmtlZEluIEluZm88L2I+PC9zcGFuPg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgZmlyc3QgaXMgY2FsbGVkICJMaW5rZWRJbiBJbmZvIiBhbmQgY29udGFpbnMgdGhlIGZvbGxvd2luZyBjb2x1bW5zOg0KPC9wPg0KDQo8dGFibGUgc3R5bGU9IndpZHRoOjEwMCU7IGJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkNvbXBhbnkgTmFtZTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5FdXBoZXVzIExlYXJuaW5nPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPlVSTDwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij48YSBocmVmPSJodHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2V1cGhldXMtbGVhcm5pbmciIHRhcmdldD0iX2JsYW5rIj5odHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2V1cGhldXMtbGVhcm5pbmc8L2E+PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPlN0cmVldCBBZGRyZXNzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPkEtMTIsIE1vaGFuIENvLW9wZXJhdGl2ZSBJbmR1c3RyaWFsIEVzdGF0ZTwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5Mb2NhbGl0eTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5OZXcgRGVsaGk8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+UmVnaW9uPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPk5ldyBEZWxoaTwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5Qb3N0YWwgQ29kZTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij4xMTAwNDQ8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+Q291bnRyeTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5JTjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5EZXNjcmlwdGlvbjwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij4iRXVwaGV1cyBpbiBHcmVlayBtZWFucyAtICIiQWN0aXZlIHNlZWtpbmcgb2Yga25vd2xlZGdlIiLigIsgT3VyIFZpc2lvbiBpcyB0byBvZmZlciBwZWRhZ29naWNhbGx5IGRpZmZlcmVudGlhdGVkIHRlY2hub2xvZ3kgZHJpdmVuIHNvbHV0aW9ucyB0aGF0IGxlYWQgdG8gY3JpdGljYWwgdGhpbmtpbmcgYW5kIGFjaGlldmVtZW50IG9mIGhpZ2hlciBsZWFybmluZyBvdXRjb21lcyBieSBzZWFtbGVzc2x5IGludGVncmF0aW5nIGluLWNsYXNzIGFuZCBhdCBob21lIGxlYXJuaW5nIGluIHRoZSBwcml2YXRlIHNjaG9vbCBzZWdtZW50IG9mIHRoZSBQcmUtSyB0byAxMiBtYXJrZXQuIE91ciBhaW0gaXMgdG8gYnJpZGdlIHRoZSBnYXAgYmV0d2VlbiB3aGF0IGlzIHRhdWdodCBpbi1jbGFzcyB1c2luZyBpbnN0aXR1dGlvbmFsIHRleHRib29rIGRyaXZlbiBzb2x1dGlvbnMgYW5kIHJldGFpbCBhdC1ob21lIGxlYXJuaW5nIHByb3ZpZGVycyBieSBzZWFtbGVzc2x5IGludGVncmF0aW5nIGJvdGguIjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5OdW1iZXIgb2YgRW1wbG95ZWVzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPjI3NTwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5JbmR1c3RyeTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5FLUxlYXJuaW5nIFByb3ZpZGVyczwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5Db21wYW55IFNpemU8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+NTEtMjAwIGVtcGxveWVlczwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5IZWFkcXVhcnRlcnM8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+TmV3IERlbGhpLCBOZXcgRGVsaGk8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+Q29tcGFueSBUeXBlPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPlByaXZhdGVseSBIZWxkPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPlNwZWNpYWx0aWVzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPkVkdWNhdGlvbiwgSy0xMiwgQ3VycmljdWxhciwgRSBMZWFybmluZywgUHJlIFByaW1hcnksIE1pZGRsZSBTY2hvb2wgU29sdXRpb25zLCBTZW5pb3IgU2Nob29sIFNvbHV0aW9ucywgRGlnaXRhbCBSZWZlcmVuY2UgUmVzb3VyY2VzLCBMYW5ndWFnZSBMZWFybmluZywgUHJpbWFyeSBTY2hvb2wgU29sdXRpb25zLCBUZWFjaGVyIFN1cHBvcnQsIEFnZSBBcHByb3ByaWF0ZSBSZXNvdXJjZSwgRGlnaXRhbCwgTGVhcm5pbmcsIFByaW50LCBMaXZlIEJvb2tzLCBGaWN0aW9uIGUgQm9va3MsIENvZGluZywgS2luZXN0aGV0aWMgTGVhcm5pbmcsIENCU0UgQWxpZ25lZCBUZXh0IEJvb2ssIElDU0UgQWxpZ25lZCBUZXh0IEJvb2ssIERpZ2l0YWwgTGlicmFyeSwgUmVhZGluZyBQcm9ncmFtLCBBdGFsIFRpbmtlcmluZyBMYWIsIGFuZCBUT0VGTDwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5Qcm9maWxlIE5hbWU8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+RXVwaGV1cyBMZWFybmluZzwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5EZXNpZ25hdGlvbjwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5FLUxlYXJuaW5nIFByb3ZpZGVyczwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5Gb2xsb3dlcnMgQ291bnQ8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+OSw5ODE8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+UHJvZmlsZSBEZXNjcmlwdGlvbjwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij4iRXVwaGV1cyBpbiBHcmVlayBtZWFucyAtICIiQWN0aXZlIHNlZWtpbmcgb2Yga25vd2xlZGdlIiLigIsgT3VyIFZpc2lvbiBpcyB0byBvZmZlciBwZWRhZ29naWNhbGx5IGRpZmZlcmVudGlhdGVkIHRlY2hub2xvZ3kgZHJpdmVuIHNvbHV0aW9ucyB0aGF0IGxlYWQgdG8gY3JpdGljYWwgdGhpbmtpbmcgYW5kIGFjaGlldmVtZW50IG9mIGhpZ2hlciBsZWFybmluZyBvdXRjb21lcyBieSBzZWFtbGVzc2x5IGludGVncmF0aW5nIGluLWNsYXNzIGFuZCBhdCBob21lIGxlYXJuaW5nIGluIHRoZSBwcml2YXRlIHNjaG9vbCBzZWdtZW50IG9mIHRoZSBQcmUtSyB0byAxMiBtYXJrZXQuIE91ciBhaW0gaXMgdG8gYnJpZGdlIHRoZSBnYXAgYmV0d2VlbiB3aGF0IGlzIHRhdWdodCBpbi1jbGFzcyB1c2luZyBpbnN0aXR1dGlvbmFsIHRleHRib29rIGRyaXZlbiBzb2x1dGlvbnMgYW5kIHJldGFpbCBhdC1ob21lIGxlYXJuaW5nIHByb3ZpZGVycyBieSBzZWFtbGVzc2x5IGludGVncmF0aW5nIGJvdGguIjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5XZWJzaXRlPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmV1cGhldXMuaW4iIHRhcmdldD0iX2JsYW5rIj5odHRwczovL3d3dy5ldXBoZXVzLmluPC9hPjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5DcnVuY2hiYXNlIEFsbCBSb3VuZHMgSW5mbzwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij40IHRvdGFsIHJvdW5kczwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5DcnVuY2hiYXNlIExhc3QgUm91bmQgSW5mbzwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5PY3QgMTQsIDIwMjE8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+Q3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudDwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5VUyQgMTAuME08L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+Q3J1bmNoYmFzZSBJbnZlc3RvcnMgSW5mbzwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5MaWdodHJvY2s8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+TGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij4xNC8xMC8yMDIxPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkNydW5jaGJhc2UgTGluazwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij48YSBocmVmPSJodHRwczovL3d3dy5jcnVuY2hiYXNlLmNvbS9mdW5kaW5nX3JvdW5kL2V1cGhldXMtbGVhcm5pbmctc2VyaWVzLWMtLTY1ODAyNDgxP3V0bV9zb3VyY2U9bGlua2VkaW4mdXRtX21lZGl1bT1yZWZlcnJhbCZ1dG1fY2FtcGFpZ249bGlua2VkaW5fY29tcGFuaWVzJnV0bV9jb250ZW50PWxhc3RfZnVuZGluZ19hbm9uJnRyaz1mdW5kaW5nX2xhc3Qtcm91bmQiIHRhcmdldD0iX2JsYW5rIj5DcnVuY2hiYXNlIExpbms8L2E+PC90ZD4NCiAgPC90cj4NCjwvdGFibGU+DQoNCioqKioqDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpGb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgeW91IGNhbiByZWZlciB0byB0aGUgY29tcGxldGUgZGF0YXNldCBbaGVyZV0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVV0SzN0TXFtdWtSRUJvUHZMeElDbzl6dDFyaXpidGI0MVFfcmVoVGg0VW8vZWRpdD9naWQ9MTA0NTE5NTg4MiNnaWQ9MTA0NTE5NTg4MikuDQo8L3A+DQoNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZTlmNWRiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij48Yj4yLiBBZmlsbGlhdGVkIFBhZ2VzIExpbmtlZEluPC9iPjwvc3Bhbj4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhlIHNlY29uZCBvdXRwdXQgaXMgY2FsbGVkICJBZmZpbGlhdGVkIFBhZ2VzIExpbmtlZEluIiBhbmQgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgYWZmaWxpYXRlZCBwYWdlcyAoaS5lLiwgb3RoZXIgcGFnZXMgcmVsYXRlZCB0byB0aGUgc2FtZSBjb21wYW55KS4gQmVsb3cgaXMgYW4gZXhhbXBsZSBvZiB0aGUgZGF0YSBjb2xsZWN0ZWQ6DQo8L3A+DQoNCjx0YWJsZSBzdHlsZT0id2lkdGg6MTAwJTsgYm9yZGVyOiAxcHggc29saWQgI2RkZDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+TmFtZTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij51cEdyYWQ8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+VVJMPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPjxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvdWVkdWNhdGlvbiIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvdWVkdWNhdGlvbjwvYT48L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+QWZmaWxpYXRlZCBOYW1lPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPnVwR3JhZCBQbGFjZW1lbnRzPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkluZHVzdHJ5PC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPkh1bWFuIFJlc291cmNlcyBTZXJ2aWNlczwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5BZGRyZXNzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5MaW5rZWRJbiBVUkw8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+PGEgaHJlZj0iaHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vY29tcGFueS91cGdyYWQtcGxhY2VtZW50cy0iIHRhcmdldD0iX2JsYW5rIj5odHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L3VwZ3JhZC1wbGFjZW1lbnRzLTwvYT48L3RkPg0KICA8L3RyPg0KPC90YWJsZT4NCg0KKioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHlvdSBjYW4gcmVmZXIgdG8gdGhlIGNvbXBsZXRlIGRhdGFzZXQgW2hlcmVdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFVdEszdE1xbXVrUkVCb1B2THhJQ285enQxcml6YnRiNDFRX3JlaFRoNFVvL2VkaXQ/Z2lkPTEwODE4MDA4MzkjZ2lkPTEwODE4MDA4MzkpLg0KPC9wPg0KDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7IG1hcmdpbi1ib3R0b206IDIwcHg7Ij4NCiAgPHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2U5ZjVkYjsgY29sb3I6YmxhY2s7IGJvcmRlci1yYWRpdXM6NXB4OyBwYWRkaW5nOiAwLjJlbSAwLjVlbTsgZGlzcGxheTogaW5saW5lLWJsb2NrOyI+PGI+My4gU2ltaWxhciBQYWdlcyBMaW5rZWRJbjwvYj48L3NwYW4+DQo8L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoZSB0aGlyZCBvdXRwdXQgaXMgY2FsbGVkICJTaW1pbGFyIFBhZ2VzIExpbmtlZEluIiBhbmQgY29udGFpbnMgdGhlIHNpbWlsYXIgcGFnZXMgcmVjb21tZW5kZWQgYnkgdGhlIExpbmtlZEluIGFsZ29yaXRobS4gVGhlc2UgYXJlIHBhZ2VzIHRoYXQgTGlua2VkSW4gc3VnZ2VzdHMgYXMgYmVpbmcgc2ltaWxhciBiYXNlZCBvbiB2YXJpb3VzIGZhY3RvcnMgc3VjaCBhcyBpbmR1c3RyeSwgY29tcGFueSBzaXplLCBhbmQgb3RoZXIgYXR0cmlidXRlcy4gQmVsb3cgaXMgYW4gZXhhbXBsZSBvZiB0aGUgZGF0YSBjb2xsZWN0ZWQ6DQo8L3A+DQoNCjx0YWJsZSBzdHlsZT0id2lkdGg6MTAwJTsgYm9yZGVyOiAxcHggc29saWQgI2RkZDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+TmFtZTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5ieXRlWEw8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+VVJMPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPjxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvYnl0ZXhsIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vY29tcGFueS9ieXRleGw8L2E+PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPlNpbWlsYXIgQ29tcGFueTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5DT0RJTkdDTFVCPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkluZHVzdHJ5PC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPkVkdWNhdGlvbjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5BZGRyZXNzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPlZhZG9kYXJhLCBHVUpBUkFUPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkxpbmtlZEluIFVSTDwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij48YSBocmVmPSJodHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2NvZGluZ2NsdWIzNiIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvY29kaW5nY2x1YjM2PC9hPjwvdGQ+DQogIDwvdHI+DQo8L3RhYmxlPg0KDQoqKioqKg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpGb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgeW91IGNhbiByZWZlciB0byB0aGUgY29tcGxldGUgZGF0YXNldCBbaGVyZV0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVV0SzN0TXFtdWtSRUJvUHZMeElDbzl6dDFyaXpidGI0MVFfcmVoVGg0VW8vZWRpdD9naWQ9OTI1MzE1MjgxI2dpZD05MjUzMTUyODEpLg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyBtYXJnaW4tYm90dG9tOiAyMHB4OyI+DQogIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlOWY1ZGI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPjxiPjQuIENvdW50cnkgT2ZmaWNlcyBBZGRyZXNzIExpbmtlZEluPC9iPjwvc3Bhbj4NCjwvcD4NCg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgZm91cnRoIG91dHB1dCBpcyBjYWxsZWQgIkNvdW50cnkgT2ZmaWNlcyBBZGRyZXNzZXMgTGlua2VkSW4iIGFuZCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZGlmZmVyZW50IG9mZmljZSBsb2NhdGlvbnMgYW5kIGNvdW50cmllcyB3aGVyZSB0aGUgY29tcGFueSBoYXMgYSBwcmVzZW5jZS4gQmVsb3cgaXMgYW4gZXhhbXBsZSBvZiB0aGUgZGF0YSBjb2xsZWN0ZWQ6DQo8L3A+DQoNCg0KPHRhYmxlIHN0eWxlPSJ3aWR0aDoxMDAlOyBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlOyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5OYW1lPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPmJ5dGVYTDwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5VUkw8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+PGEgaHJlZj0iaHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vY29tcGFueS9ieXRleGwiIHRhcmdldD0iX2JsYW5rIj5odHRwczovL2luLmxpbmtlZGluLmNvbS9jb21wYW55L2J5dGV4bDwvYT48L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+QWRkcmVzc2VzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPlBsYW5vLCBUWCwgVVM8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+Q291bnRyeSBPZmZpY2VzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPlVTPC90ZD4NCiAgPC90cj4NCjwvdGFibGU+DQoNCioqKioqDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB5b3UgY2FuIHJlZmVyIHRvIHRoZSBjb21wbGV0ZSBkYXRhc2V0IFtoZXJlXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xVXRLM3RNcW11a1JFQm9Qdkx4SUNvOXp0MXJpemJ0YjQxUV9yZWhUaDRVby9lZGl0P2dpZD0xODg4NjYyODQ2I2dpZD0xODg4NjYyODQ2KS4NCjwvcD4NCg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE2cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyBtYXJnaW4tYm90dG9tOiAyMHB4OyI+DQogIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmMmViZmI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPvCfqp8gPGI+V2Vic2l0ZSBTY3JhcGVyPC9iPjwvc3Bhbj4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KRm9sbG93aW5nIHRoZSBnZW5lcmF0aW9uIG9mIGEgbGlzdCBjb250YWluaW5nIDEwMDAgZWQtdGVjaCBzdGFydHVwcyBmcm9tIHRoZSBIb2xvbklRIGxpc3QsIGFsb25nIHdpdGggdGhlaXIgTGlua2VkSW4gbGlua3MsIHRoZSB0ZWFtIHByb2NlZWRlZCB0byBzY3JhcGUgdGhlIGluZm9ybWF0aW9uIGF2YWlsYWJsZSBvbiBMaW5rZWRJbi4gVXRpbGl6aW5nIHRoZSB3ZWJzaXRlcyByZXRyaWV2ZWQgYnkgdGhlIExpbmtlZEluIHNjcmFwZXIgKHJhdGhlciB0aGFuIHRob3NlIG1hbnVhbGx5IGFkZGVkIGR1cmluZyB0aGUgaW5pdGlhbCBsaXN0IGdlbmVyYXRpb24gdG8gZW5zdXJlIGdyZWF0ZXIgYWNjdXJhY3kpLCB0aGV5IGRldmVsb3BlZCBhIHNjcmFwZXIgZm9yIHRoZSBjb21wYW5pZXMnIHdlYiBwYWdlcy4gVGhpcyBpbmZvcm1hdGlvbiB3YXMgdGhlbiBjbGVhbmx5IHdyaXR0ZW4gaW50byB0eHQgZmlsZXMgdG8gY2FwdHVyZSBtb3JlIGNvbXByZWhlbnNpdmUgZGV0YWlscyBhYm91dCBlYWNoIGNvbXBhbnkuDQo8L3A+DQoNCg0KPGRpdiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZjlmOWY5OyBib3JkZXItbGVmdDo1cHggc29saWQgI2NjYzsgcGFkZGluZzoxMHB4OyBtYXJnaW46MTBweCAwOyI+DQogIDxwPjxzdHJvbmc+Tm90ZTo8L3N0cm9uZz4gSWYgeW91IHdhbnQgdG8gc2VlIHRoZSB0ZWNobmljYWwgaW5mb3JtYXRpb24gb2YgdGhlIHByb2Nlc3MsIHBsZWFzZSBjbGljayB0aGUgYnV0dG9uIGJlbG93LjwvcD4NCjwvZGl2Pg0KDQo8aGVhZD4NCiAgPG1ldGEgY2hhcnNldD0iVVRGLTgiPg0KICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCI+DQogIDx0aXRsZT5Eb2N1bWVudDwvdGl0bGU+DQogIDwhLS0gSW5jbHVkZSBQcmlzbS5qcyBDU1MgZm9yIHRoZSAiVG9tb3Jyb3ciIHRoZW1lIC0tPg0KICA8bGluayBocmVmPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9wcmlzbS8xLjI1LjAvdGhlbWVzL3ByaXNtLXRvbW9ycm93Lm1pbi5jc3MiIHJlbD0ic3R5bGVzaGVldCIgLz4NCjwvaGVhZD4NCjxib2R5Pg0KDQoNCjxzdW1tYXJ5IHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmN2ViZmQ7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjE4cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1hbGlnbjogbGVmdDsiPioqVGVjaG5pY2FsIEluZm9ybWF0aW9uKio8L3N1bW1hcnk+DQo8ZGl2IHN0eWxlPSJtYXJnaW4tdG9wOiAxMHB4OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQogIDxwPlRoaXMgc2VjdGlvbiBleHBsYWlucyB0aGUgdGVjaG5pY2FsIGRldGFpbHMgb2YgaG93IHdlIGNvbGxlY3RlZCBhbmQgcHJvY2Vzc2VkIHRoZSBkYXRhLiBIZXJlIGlzIGFuIGVhc3ktdG8tdW5kZXJzdGFuZCBicmVha2Rvd246PC9wPg0KICA8b2wgc3R5bGU9InBhZGRpbmctbGVmdDogMzBweDsiPg0KICAgIDxsaT48c3Ryb25nPkNsZWFuaW5nIFRleHQ6PC9zdHJvbmc+IFRoZSBgY2xlYW5fdGV4dGAgZnVuY3Rpb24gcmVtb3ZlcyBleGNlc3Mgd2hpdGVzcGFjZSBhbmQgc3BlY2lhbCBjaGFyYWN0ZXJzIGZyb20gdGhlIHRleHQgdG8gbWFrZSBpdCBtb3JlIHJlYWRhYmxlLjwvbGk+DQogICAgPGxpPjxzdHJvbmc+TGFuZ3VhZ2UgRGV0ZWN0aW9uOjwvc3Ryb25nPiBUaGUgYGRldGVjdF9sYW5ndWFnZV9mcm9tX2h0bWxgIGFuZCBgZGV0ZWN0X2xhbmd1YWdlYCBmdW5jdGlvbnMgaWRlbnRpZnkgdGhlIGxhbmd1YWdlIG9mIHRoZSB0ZXh0LCBlaXRoZXIgZnJvbSB0aGUgSFRNTCB0YWcgb3IgdGhlIHRleHQgY29udGVudCBpdHNlbGYuPC9saT4NCiAgICA8bGk+PHN0cm9uZz5GZXRjaGluZyBIVE1MIENvbnRlbnQ6PC9zdHJvbmc+IFRoZSBgZ2V0X2h0bWxfd2l0aF9zZWxlbml1bWAgZnVuY3Rpb24gdXNlcyBTZWxlbml1bSB0byBsb2FkIHdlYiBwYWdlcyBhbmQgZW5zdXJlIGFsbCBjb250ZW50IGlzIGNhcHR1cmVkLCBlc3BlY2lhbGx5IGZvciBwYWdlcyB0aGF0IGxvYWQgY29udGVudCBkeW5hbWljYWxseS48L2xpPg0KICAgIDxsaT48c3Ryb25nPlNhdmluZyBXZWIgUGFnZSBDb250ZW50Ojwvc3Ryb25nPiBUaGUgYHNhdmVfZm9ybWF0dGVkX3dlYnBhZ2VfY29udGVudGAgZnVuY3Rpb24gcmV0cmlldmVzIHdlYiBwYWdlIGNvbnRlbnQsIGNsZWFucyBpdCwgZGV0ZWN0cyB0aGUgbGFuZ3VhZ2UsIGFuZCBzYXZlcyBpdCB0byBhIHRleHQgZmlsZS4gSWYgdGhlIGluaXRpYWwgdG9rZW4gY291bnQgaXMgaW5zdWZmaWNpZW50LCBpdCBzd2l0Y2hlcyB0byB1c2luZyBTZWxlbml1bSBmb3IgYSBtb3JlIHRob3JvdWdoIHNjcmFwZS48L2xpPg0KICAgIDxsaT48c3Ryb25nPkhhbmRsaW5nIFJlcXVlc3RzIGFuZCBFcnJvcnM6PC9zdHJvbmc+IFRoZSBmdW5jdGlvbiBoYW5kbGVzIHZhcmlvdXMgZXhjZXB0aW9ucyB0byBlbnN1cmUgcm9idXN0bmVzcywgaW5jbHVkaW5nIHJlcXVlc3QgZXJyb3JzIGFuZCBnZW5lcmFsIGV4Y2VwdGlvbnMuPC9saT4NCiAgICA8bGk+PHN0cm9uZz5NYWluIFByb2Nlc3NpbmcgTG9vcDo8L3N0cm9uZz4gVGhlIGBtYWluYCBmdW5jdGlvbiByZWFkcyBpbnB1dCBkYXRhIGZyb20gYW4gRXhjZWwgZmlsZSwgcHJvY2Vzc2VzIGVhY2ggY29tcGFueSdzIHdlYnNpdGUsIGFuZCBzYXZlcyB0aGUgcmVzdWx0cyBhbmQgYW55IGVycm9ycyB0byBzZXBhcmF0ZSBFeGNlbCBmaWxlcy48L2xpPg0KICA8L29sPg0KICA8cD5UaGlzIGFwcHJvYWNoIGFsbG93ZWQgdXMgdG8gZ2F0aGVyIGNvbXByZWhlbnNpdmUgaW5mb3JtYXRpb24gYWJvdXQgZWFjaCBjb21wYW55LCB3aGljaCB3YXMgdGhlbiBhbmFseXplZCB0byBpZGVudGlmeSBwb3RlbnRpYWwgYnVzaW5lc3Mgb3Bwb3J0dW5pdGllcyBmb3IgRWR1TmV4dC48L3A+DQogIDxwcmU+PGNvZGUgY2xhc3M9Imxhbmd1YWdlLXB5dGhvbiI+DQppbXBvcnQgb3MNCmltcG9ydCByZQ0KaW1wb3J0IHRpbWUNCmltcG9ydCBwYW5kYXMgYXMgcGQNCmltcG9ydCByZXF1ZXN0cw0KZnJvbSBiczQgaW1wb3J0IEJlYXV0aWZ1bFNvdXANCmZyb20gbGFuZ2RldGVjdCBpbXBvcnQgZGV0ZWN0LCBMYW5nRGV0ZWN0RXhjZXB0aW9uDQpmcm9tIHNlbGVuaXVtIGltcG9ydCB3ZWJkcml2ZXINCmZyb20gc2VsZW5pdW0ud2ViZHJpdmVyLmNocm9tZS5zZXJ2aWNlIGltcG9ydCBTZXJ2aWNlDQpmcm9tIHNlbGVuaXVtLndlYmRyaXZlci5jaHJvbWUub3B0aW9ucyBpbXBvcnQgT3B0aW9ucw0KZnJvbSBzZWxlbml1bS53ZWJkcml2ZXIuc3VwcG9ydC51aSBpbXBvcnQgV2ViRHJpdmVyV2FpdA0KZnJvbSBzZWxlbml1bS53ZWJkcml2ZXIuc3VwcG9ydCBpbXBvcnQgZXhwZWN0ZWRfY29uZGl0aW9ucyBhcyBFQw0KZnJvbSBzZWxlbml1bS53ZWJkcml2ZXIuY29tbW9uLmJ5IGltcG9ydCBCeQ0KDQpmcm9tIHdlYmRyaXZlcl9tYW5hZ2VyLmNocm9tZSBpbXBvcnQgQ2hyb21lRHJpdmVyTWFuYWdlcg0KDQpkZWYgY2xlYW5fdGV4dCh0ZXh0KToNCiAgICB0ZXh0ID0gcmUuc3ViKHInXHMrJywgJyAnLCB0ZXh0KQ0KICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoJ1x4YTAnLCAnICcpDQogICAgcmV0dXJuIHRleHQuc3RyaXAoKQ0KDQpkZWYgZGV0ZWN0X2xhbmd1YWdlX2Zyb21faHRtbChzb3VwKToNCiAgICBodG1sX3RhZyA9IHNvdXAuZmluZCgnaHRtbCcpDQogICAgaWYgaHRtbF90YWcgYW5kIGh0bWxfdGFnLmdldCgnbGFuZycpOg0KICAgICAgICByZXR1cm4gaHRtbF90YWdbJ2xhbmcnXQ0KICAgIGVsc2U6DQogICAgICAgIHJldHVybiBOb25lDQoNCmRlZiBkZXRlY3RfbGFuZ3VhZ2UodGV4dCk6DQogICAgdHJ5Og0KICAgICAgICByZXR1cm4gZGV0ZWN0KHRleHQpDQogICAgZXhjZXB0IExhbmdEZXRlY3RFeGNlcHRpb246DQogICAgICAgIHJldHVybiAndW5rbm93bicNCg0KZGVmIGdldF9odG1sX3dpdGhfc2VsZW5pdW0odXJsKToNCiAgICBvcHRpb25zID0gT3B0aW9ucygpDQogICAgb3B0aW9ucy5hZGRfYXJndW1lbnQoIi0taGVhZGxlc3MiKQ0KICAgIG9wdGlvbnMuYWRkX2FyZ3VtZW50KCItLWRpc2FibGUtZ3B1IikNCiAgICBvcHRpb25zLmFkZF9hcmd1bWVudCgiLS1uby1zYW5kYm94IikNCiAgICBvcHRpb25zLmFkZF9hcmd1bWVudCgiLS1kaXNhYmxlLWZlYXR1cmVzPVNhbWVTaXRlQnlEZWZhdWx0Q29va2llcyIpDQogICAgb3B0aW9ucy5hZGRfYXJndW1lbnQoIi0tZGlzYWJsZS1mZWF0dXJlcz1Db29raWVzV2l0aG91dFNhbWVTaXRlTXVzdEJlU2VjdXJlIikNCiAgICBvcHRpb25zLmFkZF9hcmd1bWVudCgibG9nLWxldmVsPTMiKSAgIyBSZWR1Y2UgbG9nZ2luZyBvdXRwdXQNCiAgICANCiAgICBkcml2ZXIgPSB3ZWJkcml2ZXIuQ2hyb21lKHNlcnZpY2U9U2VydmljZShDaHJvbWVEcml2ZXJNYW5hZ2VyKCkuaW5zdGFsbCgpKSwgb3B0aW9ucz1vcHRpb25zKQ0KICAgIGRyaXZlci5nZXQodXJsKQ0KICAgIA0KICAgIHRyeToNCiAgICAgICAgIyBXYWl0IGZvciB0aGUgYm9keSBjb250ZW50IHRvIGJlIGxvYWRlZA0KICAgICAgICBXZWJEcml2ZXJXYWl0KGRyaXZlciwgMjApLnVudGlsKEVDLnByZXNlbmNlX29mX2VsZW1lbnRfbG9jYXRlZCgoQnkuVEFHX05BTUUsICdib2R5JykpKQ0KICAgICAgICAjIFNjcm9sbCB0byB0aGUgYm90dG9tIHRvIGVuc3VyZSBhbGwgY29udGVudCBpcyBsb2FkZWQNCiAgICAgICAgZHJpdmVyLmV4ZWN1dGVfc2NyaXB0KCJ3aW5kb3cuc2Nyb2xsVG8oMCwgZG9jdW1lbnQuYm9keS5zY3JvbGxIZWlnaHQpOyIpDQogICAgICAgIHRpbWUuc2xlZXAoNSkgICMgV2FpdCBmb3IgY29udGVudCB0byBsb2FkDQogICAgICAgICMgQWRkaXRpb25hbGx5LCB3YWl0IGZvciB0aGUgc3BlY2lmaWMgZWxlbWVudCB0aGF0IGluZGljYXRlcyB0aGUgY29udGVudCBpcyBmdWxseSBsb2FkZWQNCiAgICAgICAgV2ViRHJpdmVyV2FpdChkcml2ZXIsIDIwKS51bnRpbChFQy5wcmVzZW5jZV9vZl9lbGVtZW50X2xvY2F0ZWQoKEJ5LlhQQVRILCAiLy9wIikpKQ0KICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToNCiAgICAgICAgcHJpbnQoZiJFcnJvciB3YWl0aW5nIGZvciB0aGUgcGFnZSB0byBsb2FkOiB7ZX0iKQ0KICAgIA0KICAgIGh0bWxfY29udGVudCA9IGRyaXZlci5wYWdlX3NvdXJjZQ0KICAgIGRyaXZlci5xdWl0KCkNCiAgICANCiAgICByZXR1cm4gaHRtbF9jb250ZW50DQoNCmRlZiBzYXZlX2Zvcm1hdHRlZF93ZWJwYWdlX2NvbnRlbnQodXJsLCBjb21wYW55X25hbWUpOg0KICAgIHRyeToNCiAgICAgICAgcHJpbnQoZiJSZXRyaWV2aW5nIGNvbnRlbnQgZnJvbSB7dXJsfSBmb3Ige2NvbXBhbnlfbmFtZX0uLi4iKQ0KDQogICAgICAgIHJlc3BvbnNlID0gcmVxdWVzdHMuZ2V0KHVybCwgdGltZW91dD0xMCkNCiAgICAgICAgcmVzcG9uc2UucmFpc2VfZm9yX3N0YXR1cygpDQogICAgICAgIHJlc3BvbnNlLmVuY29kaW5nID0gcmVzcG9uc2UuYXBwYXJlbnRfZW5jb2RpbmcNCiAgICAgICAgaHRtbF9jb250ZW50ID0gcmVzcG9uc2UudGV4dA0KDQogICAgICAgIHNvdXAgPSBCZWF1dGlmdWxTb3VwKGh0bWxfY29udGVudCwgJ2h0bWwucGFyc2VyJykNCiAgICAgICAgcGFyYWdyYXBocyA9IHNvdXAuZmluZF9hbGwoJ3AnKQ0KDQogICAgICAgIHBhcmFncmFwaF90ZXh0cyA9ICdcblxuJy5qb2luKFtjbGVhbl90ZXh0KHAuZ2V0X3RleHQoKSkgZm9yIHAgaW4gcGFyYWdyYXBoc10pDQogICAgICAgIHRva2VuX2NvdW50ID0gbGVuKHBhcmFncmFwaF90ZXh0cy5zcGxpdCgpKQ0KDQogICAgICAgICMgSWYgdGhlIHRva2VuIGNvdW50IGlzIGxlc3MgdGhhbiAzMDAsIHVzZSBTZWxlbml1bQ0KICAgICAgICBpZiB0b2tlbl9jb3VudCA8IDMwMDoNCiAgICAgICAgICAgIHByaW50KGYiSW5zdWZmaWNpZW50IHRva2VuIGNvdW50IHJldHJpZXZlZCBmcm9tIHt1cmx9IHVzaW5nIHJlcXVlc3RzLiBTd2l0Y2hpbmcgdG8gU2VsZW5pdW0uLi4iKQ0KICAgICAgICAgICAgaHRtbF9jb250ZW50ID0gZ2V0X2h0bWxfd2l0aF9zZWxlbml1bSh1cmwpDQogICAgICAgICAgICBzb3VwID0gQmVhdXRpZnVsU291cChodG1sX2NvbnRlbnQsICdodG1sLnBhcnNlcicpDQogICAgICAgICAgICBwYXJhZ3JhcGhzID0gc291cC5maW5kX2FsbCgncCcpDQogICAgICAgICAgICBwYXJhZ3JhcGhfdGV4dHMgPSAnXG5cbicuam9pbihbY2xlYW5fdGV4dChwLmdldF90ZXh0KCkpIGZvciBwIGluIHBhcmFncmFwaHNdKQ0KICAgICAgICAgICAgdG9rZW5fY291bnQgPSBsZW4ocGFyYWdyYXBoX3RleHRzLnNwbGl0KCkpDQoNCiAgICAgICAgIyBDaGVjayBpZiBIVE1MIGNvbnRlbnQgaXMgcmV0cmlldmVkDQogICAgICAgIGlmIG5vdCBzb3VwLmJvZHk6DQogICAgICAgICAgICBwcmludChmIk5vIGJvZHkgY29udGVudCBmb3VuZCBmb3Ige2NvbXBhbnlfbmFtZX0gYXQge3VybH0uIikNCiAgICAgICAgICAgIHJldHVybiBOb25lLCBOb25lLCBmIk5vIGJvZHkgY29udGVudCBmb3VuZCBhdCB7dXJsfSINCiAgICAgICAgDQogICAgICAgIHRpdGxlID0gY2xlYW5fdGV4dChzb3VwLnRpdGxlLnN0cmluZykgaWYgc291cC50aXRsZSBlbHNlICdObyBUaXRsZSBGb3VuZCcNCiAgICAgICAgZm9ybWF0dGVkX2NvbnRlbnQgPSBmIlRpdGxlOiB7dGl0bGV9XG5cbntwYXJhZ3JhcGhfdGV4dHN9Ig0KDQogICAgICAgICMgRGV0ZWN0IGxhbmd1YWdlDQogICAgICAgIGxhbmd1YWdlID0gZGV0ZWN0X2xhbmd1YWdlX2Zyb21faHRtbChzb3VwKQ0KICAgICAgICBpZiBub3QgbGFuZ3VhZ2U6DQogICAgICAgICAgICBsYW5ndWFnZSA9IGRldGVjdF9sYW5ndWFnZShwYXJhZ3JhcGhfdGV4dHMpDQogICAgICAgIA0KICAgICAgICBmaWxlcGF0aCA9IG9zLnBhdGguam9pbignd2VicGFnZXMnLCBmIntjb21wYW55X25hbWV9LnR4dCIpDQogICAgICAgIHdpdGggb3BlbihmaWxlcGF0aCwgJ3cnLCBlbmNvZGluZz0ndXRmLTgnKSBhcyBmaWxlOg0KICAgICAgICAgICAgZmlsZS53cml0ZShmb3JtYXR0ZWRfY29udGVudCkNCiAgICAgICAgDQogICAgICAgIHByaW50KGYiQ29udGVudCByZXRyaWV2ZWQgYW5kIHNhdmVkIGZvciB7Y29tcGFueV9uYW1lfS4gVG9rZW4gY291bnQ6IHt0b2tlbl9jb3VudH0sIExhbmd1YWdlOiB7bGFuZ3VhZ2V9LiIpDQogICAgICAgIHJldHVybiB0b2tlbl9jb3VudCwgbGFuZ3VhZ2UsIE5vbmUNCiAgICBleGNlcHQgcmVxdWVzdHMuZXhjZXB0aW9ucy5SZXF1ZXN0RXhjZXB0aW9uIGFzIHJlcV9lcnI6DQogICAgICAgIHByaW50KGYiUmVxdWVzdCBlcnJvciBmb3Ige2NvbXBhbnlfbmFtZX06IHtyZXFfZXJyfSIpDQogICAgICAgIHJldHVybiBOb25lLCBOb25lLCBmIlJlcXVlc3QgZXJyb3I6IHtyZXFfZXJyfSINCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGVycjoNCiAgICAgICAgcHJpbnQoZiJFcnJvciBmb3Ige2NvbXBhbnlfbmFtZX06IHtlcnJ9IikNCiAgICAgICAgcmV0dXJuIE5vbmUsIE5vbmUsIGYiRXJyb3I6IHtlcnJ9Ig0KDQpkZWYgbWFpbigpOg0KICAgIGlucHV0X2ZpbGVuYW1lID0gJ2NsZWFuZWRfY29tcGFueV9pbmZvcm1hdGlvbi54bHN4Jw0KICAgIG91dHB1dF9kYXRhX2ZpbGVuYW1lID0gJ2NvbXBhbnlfdG9rZW5fY291bnRzLnhsc3gnDQogICAgb3V0cHV0X2Vycm9yc19maWxlbmFtZSA9ICd3ZWJzaXRlX2Vycm9ycy54bHN4Jw0KICAgIA0KICAgICMgUmVhZCB0aGUgaW5wdXQgZmlsZQ0KICAgIGRmID0gcGQucmVhZF9leGNlbChpbnB1dF9maWxlbmFtZSkNCiAgICANCiAgICAjIEVuc3VyZSB0aGUgJ3dlYnBhZ2VzJyBkaXJlY3RvcnkgZXhpc3RzDQogICAgaWYgbm90IG9zLnBhdGguZXhpc3RzKCd3ZWJwYWdlcycpOg0KICAgICAgICBvcy5tYWtlZGlycygnd2VicGFnZXMnKQ0KICAgIA0KICAgICMgTGlzdHMgdG8gc3RvcmUgcmVzdWx0cyBhbmQgZXJyb3JzDQogICAgcmVzdWx0cyA9IFtdDQogICAgZXJyb3JzID0gW10NCg0KICAgICMgSXRlcmF0ZSBvdmVyIHRoZSByb3dzIGluIHRoZSBEYXRhRnJhbWUNCiAgICBmb3IgaW5kZXgsIHJvdyBpbiBkZi5pdGVycm93cygpOg0KICAgICAgICBwcmludChmIlByb2Nlc3Npbmcge2luZGV4ICsgMX0ve2xlbihkZil9OiB7cm93WydDb21wYW55IE5hbWUnXX0gKHtyb3dbJ1dlYnNpdGUnXX0pIikNCiAgICAgICAgY29tcGFueV9uYW1lID0gcm93WydDb21wYW55IE5hbWUnXQ0KICAgICAgICB3ZWJzaXRlID0gcm93WydXZWJzaXRlJ10NCiAgICAgICAgdG9rZW5fY291bnQsIGxhbmd1YWdlLCBlcnJvciA9IHNhdmVfZm9ybWF0dGVkX3dlYnBhZ2VfY29udGVudCh3ZWJzaXRlLCBjb21wYW55X25hbWUpDQogICAgICAgIA0KICAgICAgICBpZiB0b2tlbl9jb3VudCBpcyBub3QgTm9uZToNCiAgICAgICAgICAgIHJlc3VsdHMuYXBwZW5kKHsnQ29tcGFueSBOYW1lJzogY29tcGFueV9uYW1lLCAnV2Vic2l0ZSc6IHdlYnNpdGUsICdUb2tlbiBDb3VudCc6IHRva2VuX2NvdW50LCAnTGFuZ3VhZ2UnOiBsYW5ndWFnZX0pDQogICAgICAgIGlmIGVycm9yIGlzIG5vdCBOb25lOg0KICAgICAgICAgICAgZXJyb3JzLmFwcGVuZCh7J0NvbXBhbnkgTmFtZSc6IGNvbXBhbnlfbmFtZSwgJ1dlYnNpdGUnOiB3ZWJzaXRlLCAnRXJyb3InOiBlcnJvcn0pDQogICAgDQogICAgIyBTYXZlIHRoZSByZXN1bHRzIHRvIGFuIEV4Y2VsIGZpbGUNCiAgICByZXN1bHRzX2RmID0gcGQuRGF0YUZyYW1lKHJlc3VsdHMpDQogICAgcmVzdWx0c19kZi50b19leGNlbChvdXRwdXRfZGF0YV9maWxlbmFtZSwgaW5kZXg9RmFsc2UpDQogICAgDQogICAgIyBTYXZlIHRoZSBlcnJvcnMgdG8gYW4gRXhjZWwgZmlsZQ0KICAgIGVycm9yc19kZiA9IHBkLkRhdGFGcmFtZShlcnJvcnMpDQogICAgZXJyb3JzX2RmLnRvX2V4Y2VsKG91dHB1dF9lcnJvcnNfZmlsZW5hbWUsIGluZGV4PUZhbHNlKQ0KDQogICAgcHJpbnQoZiJQcm9jZXNzIGNvbXBsZXRlZC4gRGF0YSBzYXZlZCB0byB7b3V0cHV0X2RhdGFfZmlsZW5hbWV9IGFuZCBlcnJvcnMgc2F2ZWQgdG8ge291dHB1dF9lcnJvcnNfZmlsZW5hbWV9LiIpDQoNCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6DQogICAgbWFpbigpDQoNCiAgPC9jb2RlPjwvcHJlPg0KPC9kaXY+DQoNCjwhLS0gSW5jbHVkZSBQcmlzbS5qcyAtLT4NCjxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9wcmlzbS8xLjI1LjAvcHJpc20ubWluLmpzIj48L3NjcmlwdD4NCjxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9wcmlzbS8xLjI1LjAvY29tcG9uZW50cy9wcmlzbS1weXRob24ubWluLmpzIj48L3NjcmlwdD4NCg0KPC9ib2R5Pg0KPC9odG1sPg0KDQoqKioqKg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpGb2xsb3dpbmcgdGhlIHdlYiBzY3JhcGluZyBwcm9jZXNzLCB0aGUgb3V0cHV0IG9mIHRoaXMgcGFydCBpcyBhIGZvbGRlciDwn5OBIGNvbnRhaW5pbmcgdmFyaW91cyB0eHQgZmlsZXMsIHdpdGggZWFjaCBmaWxlIGNvcnJlc3BvbmRpbmcgdG8gYSBzcGVjaWZpYyBjb21wYW55LiBUaGVzZSBmaWxlcyBjb250YWluIGRldGFpbGVkIGluZm9ybWF0aW9uIGV4dHJhY3RlZCBmcm9tIHRoZSBjb21wYW5pZXMnIHdlYiBwYWdlcy4gVGhpcyBhcHByb2FjaCBlbnN1cmVzIHRoYXQgYWxsIHJlbGV2YW50IGRhdGEgaXMgY2FwdHVyZWQgYW5kIG9yZ2FuaXplZCBzeXN0ZW1hdGljYWxseSBmb3IgZnVydGhlciBhbmFseXNpcy4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KQXMgc2hvd24gaW4gdGhlIGZvbGxvd2luZyBleGFtcGxlOg0KPC9wPg0KDQoNCiFbXSh3ZWJwYWdlX3NjcmFwZXJfZXhhbXBsZS5wbmcpDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTZweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7IG1hcmdpbi1ib3R0b206IDIwcHg7Ij4NCiAgPHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2YyZWJmYjsgY29sb3I6YmxhY2s7IGJvcmRlci1yYWRpdXM6NXB4OyBwYWRkaW5nOiAwLjJlbSAwLjVlbTsgZGlzcGxheTogaW5saW5lLWJsb2NrOyI+8J+UpyA8Yj5JbnRlZ3JhdGlvbiB3aXRoIENoYXQtR1BUPC9iPjwvc3Bhbj4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhlIG5leHQgc3RlcCBpbnZvbHZlZCBpbnRlZ3JhdGluZyB3aXRoIE9wZW5BSSB1c2luZyB0aGUgR1BULTMuNSBtb2RlbCB0byBsZXZlcmFnZSB0aGUgTGlua2VkSW4gaW5mb3JtYXRpb24gYW5kIHRoZSBUeHQgZmlsZXMgd2l0aCB3ZWJzaXRlIGluZm9ybWF0aW9uLiBUaGVzZSBkYXRhIHNvdXJjZXMgd2VyZSB1c2VkIHRvIGZlZWQgdGhlIG1vZGVsIGFuZCBhbnN3ZXIgc3BlY2lmaWMgcXVlc3Rpb25zIGRlc2lnbmVkIHRvIGJ1aWxkIGEgY29tcHJlaGVuc2l2ZSBwcm9maWxlIG9mIGVhY2ggY29tcGFueS4gVGhlIGZvbGxvd2luZyBxdWVzdGlvbnMgd2VyZSBhc2tlZCBvZiB0aGUgbW9kZWw6DQo8L3A+DQoNCg0KPHVsIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjg7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgICA8bGk+RG9lcyB0aGUgY29tcGFueSBoYXZlIGFueSBjb25uZWN0aW9uIG9yIHVzZSB0aGUgT3BlbiBlZFggcGxhdGZvcm0/PC9saT4NCiAgICA8bGk+V2hhdCBpcyB0aGUgbWFpbiBwcm9kdWN0IG9yIHNlcnZpY2UgdGhlIGNvbXBhbnkgb2ZmZXJzPzwvbGk+DQogICAgPGxpPkxpc3QgdGhyZWUgbWFpbiBjb21wZXRpdG9ycyBvZiB0aGUgY29tcGFueSwgaW5jbHVkaW5nIHRoZWlyIG5hbWVzIGFuZCB3ZWJzaXRlcy48L2xpPg0KICAgIDxsaT5MaXN0IHRocmVlIG1haW4gY3VzdG9tZXJzIG9mIHRoZSBjb21wYW55LjwvbGk+DQogICAgPGxpPklzIHRoZSBjb21wYW55IHByaW1hcmlseSBmb2N1c2VkIG9uIEIyQiAoYnVzaW5lc3MtdG8tYnVzaW5lc3MpIG9yIEIyQyAoYnVzaW5lc3MtdG8tY29uc3VtZXIpIG9wZXJhdGlvbnM/PC9saT4NCiAgICA8bGk+RXN0aW1hdGUgdGhlIG51bWJlciBvZiBjdXN0b21lcnMgdGhlIGNvbXBhbnkgaGFzLjwvbGk+DQogICAgPGxpPkluIHdoaWNoIGNvdW50cnkgZG9lcyB0aGUgY29tcGFueSBwcmltYXJpbHkgb3BlcmF0ZT88L2xpPg0KICAgIDxsaT5EZXRlcm1pbmUgaWYgdGhlIGNvbXBhbnkgaXMgYSBwb3RlbnRpYWwgY2xpZW50LCBwYXJ0bmVyLCBjb21wZXRpdG9yLCBvciBwcm92aWRlciBmb3IgRWR1bmV4dC48L2xpPg0KICAgIDxsaT5EZXRlcm1pbmUgdGhlIHBvdGVudGlhbCB2ZXJ0aWNhbCBmb3IgdGhlIGNvbXBhbnkgZnJvbSB0aGUgZ2l2ZW4gbGlzdCBvZiB2ZXJ0aWNhbHMuPC9saT4NCiAgICA8bGk+QmFzZWQgb24gdGhlIHByb3ZpZGVkIGluZm9ybWF0aW9uIGFuZCBhbnkgYWRkaXRpb25hbCByZXNlYXJjaCwgd2hhdCBhcmUgdGhlIHByaW1hcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSBjb21wYW55PyAoVGhpcyB3YXMgcmVwZWF0ZWQgdG8gaWRlbnRpZnkgdXAgdG8gZml2ZSBjYXBhYmlsaXRpZXMpPC9saT4NCjwvdWw+DQoNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhlIGNvZGUgbGV2ZXJhZ2VzIGFkZGl0aW9uYWwgZGF0YSBmcm9tIHNldmVyYWwgRXhjZWwgdGFibGVzIHRvIGVucmljaCB0aGUgYW5hbHlzaXM6DQo8L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgPHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2U5ZjVkYjsgY29sb3I6YmxhY2s7IGJvcmRlci1yYWRpdXM6NXB4OyBwYWRkaW5nOiAwLjJlbSAwLjVlbTsgZGlzcGxheTogaW5saW5lLWJsb2NrOyI+8J+ThCA8Yj5Sb2xlIERlZmluaXRpb25zPC9iPjwvc3Bhbj4NCiAgPGJyPlByb3ZpZGVzIGRldGFpbGVkIGRlZmluaXRpb25zIGZvciByb2xlcyBsaWtlIGNsaWVudCwgcGFydG5lciwgY29tcGV0aXRvciwgYW5kIHByb3ZpZGVyLCBhcyB3ZWxsIGFzIGluZm9ybWF0aW9uIGFib3V0IEVkdW5leHQuDQo8L3A+DQoNCg0KPHN0eWxlPg0KICB0YWJsZSB7DQogICAgd2lkdGg6IDEwMCU7DQogICAgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7DQogICAgZm9udC1zaXplOiAxNHB4Ow0KICAgIGNvbG9yOiAjMzMzMzMzOw0KICB9DQogIHRoLCB0ZCB7DQogICAgYm9yZGVyOiAxcHggc29saWQgI2RkZGRkZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KICAgIHBhZGRpbmc6IDhweDsNCiAgfQ0KICB0aCB7DQogICAgYmFja2dyb3VuZC1jb2xvcjogI2YyZjJmMjsNCiAgfQ0KPC9zdHlsZT4NCg0KPHRhYmxlPg0KICA8dGhlYWQ+DQogICAgPHRyPg0KICAgICAgPHRoPlJvbGU8L3RoPg0KICAgICAgPHRoPkRldGFpbGVkIERlZmluaXRpb25zPC90aD4NCiAgICA8L3RyPg0KICA8L3RoZWFkPg0KICA8dGJvZHk+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+RWR1bmV4dDwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+RWR1bmV4dCBpcyB0aGUgY29tcGFueSBkcml2aW5nIHRoaXMgYW5hbHlzaXMuIEl0IGlzIGEgc29mdHdhcmUgYW5kIHNlcnZpY2VzIGNvbXBhbnkgZGVkaWNhdGVkIHRvIHRoZSBPcGVuIGVkWCBwbGF0Zm9ybS48L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+Q0xJRU5UPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BbiBlbnRpdHkgdGhhdCBpcyBsaWtlbHkgdG8gcmVxdWlyZSBob3N0aW5nLCBtYWludGVuYW5jZSwgb3IgcHJvZmVzc2lvbmFsIHNlcnZpY2VzIGZvciB0aGUgT3BlbiBlZFggcGxhdGZvcm0uPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPlBBUlRORVI8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkFuIGVudGl0eSB0aGF0IHByb3ZpZGVzIGluc3RydWN0aW9uYWwgZGVzaWduIHNlcnZpY2VzIG9yIGEgdGVjaG5vbG9neSBhZ2dyZWdhdG9yIHRoYXQgbWF5IHN1YmNvbnRyYWN0IGhvc3Rpbmcgb3IgcHJvZmVzc2lvbmFsIHNlcnZpY2VzIGZvciB0aGUgT3BlbiBlZFggcGxhdGZvcm0gdG8gRWR1bmV4dCwgYXMgaXQgaXMgbm90IHBhcnQgb2YgaXRzIGNvcmUgYnVzaW5lc3MuIEl0IGNhbiBhbHNvIGJlIGFuIGVudGl0eSB0aGF0IHByb3ZpZGVzIGEgdG9vbCBmb3Igb25saW5lIGxlYXJuaW5nIHRoYXQgY2FuIGJlIGludGVncmF0ZWQgaW50byB0aGUgT3BlbiBlZFggTE1TIG9yIHVzZXMgc3RhbmRhcmQgaW50ZXJvcGVyYWJpbGl0eSBwcm90b2NvbHMgc3VjaCBhcyBMVEkuPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkNPTVBFVElUT1I8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkFuIGVudGl0eSB0aGF0IGhhcyBPcGVuIGVkWCBob3N0aW5nLCBtYWludGVuYW5jZSwgb3IgY3VzdG9tIGRldmVsb3BtZW50IGFzIHBhcnQgb2YgdGhlaXIgY29yZSBidXNpbmVzcyBvZmZlcmluZyBhbmQgZXhwZXJ0aXNlLjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5QUk9WSURFUjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+QW4gZW50aXR5IHRoYXQgc3VwcGxpZXMgc2VydmljZXMgdGhhdCBtYXkgYmUgcmVsZXZhbnQgYW5kIHVzZWZ1bCB0byBFZHVuZXh0IHRvIGVuaGFuY2UgaXRzIHZhbHVlIHByb3Bvc2l0aW9uIG9yIHJhaXNlIGl0cyBwcm9kdWN0aXZpdHkuPC90ZD4NCiAgICA8L3RyPg0KICA8L3Rib2R5Pg0KPC90YWJsZT4NCg0KKioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZTlmNWRiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij7wn5OEIDxiPlZlcnRpY2FsczwvYj48L3NwYW4+DQo8L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoZXNlIGFkZGl0aW9uYWwgc291cmNlcyBlbnN1cmUgdGhlIGFjY3VyYWN5IGFuZCBjb21wcmVoZW5zaXZlbmVzcyBvZiB0aGUgYW5hbHlzaXMsIGFsbG93aW5nIHRoZSBHUFQtMy41IG1vZGVsIHRvIGdlbmVyYXRlIG1vcmUgcHJlY2lzZSBhbmQgY29udGV4dHVhbGx5IHJlbGV2YW50IHJlc3BvbnNlcy4NCjwvcD4NCg0KDQo8dGFibGU+DQogIDx0aGVhZD4NCiAgICA8dHI+DQogICAgICA8dGg+VmVydGljYWwgTmFtZTwvdGg+DQogICAgICA8dGg+VmVydGljYWwgRGVmaW5pdGlvbjwvdGg+DQogICAgPC90cj4NCiAgPC90aGVhZD4NCiAgPHRib2R5Pg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkstMTIgRWR1Y2F0aW9uPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5UZWNobm9sb2dpZXMgYW5kIHBsYXRmb3JtcyBhaW1lZCBhdCBwcmltYXJ5IGFuZCBzZWNvbmRhcnkgZWR1Y2F0aW9uLjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5IaWdoZXIgRWR1Y2F0aW9uPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5Tb2x1dGlvbnMgdGFpbG9yZWQgZm9yIGNvbGxlZ2VzLCB1bml2ZXJzaXRpZXMsIGFuZCBvdGhlciB0ZXJ0aWFyeSBlZHVjYXRpb24gaW5zdGl0dXRpb25zLjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5Qcm9mZXNzaW9uYWwgRGV2ZWxvcG1lbnQgJiBDb3Jwb3JhdGUgVHJhaW5pbmc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlRvb2xzIGFuZCBwcm9ncmFtcyBkZXNpZ25lZCBmb3IgZW1wbG95ZWUgdHJhaW5pbmcsIHVwc2tpbGxpbmcsIGFuZCBwcm9mZXNzaW9uYWwgY2VydGlmaWNhdGlvbnMuPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxhbmd1YWdlIExlYXJuaW5nPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BcHBzLCBwbGF0Zm9ybXMsIGFuZCBzZXJ2aWNlcyBmb2N1c2VkIG9uIHRlYWNoaW5nIG5ldyBsYW5ndWFnZXMuPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPlNURU0gRWR1Y2F0aW9uPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5SZXNvdXJjZXMgYW5kIHRvb2xzIHNwZWNpZmljIHRvIFNjaWVuY2UsIFRlY2hub2xvZ3ksIEVuZ2luZWVyaW5nLCBhbmQgTWF0aGVtYXRpY3MgZWR1Y2F0aW9uLjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MZWFybmluZyBNYW5hZ2VtZW50IFN5c3RlbXMgKExNUyk8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlBsYXRmb3JtcyB0aGF0IHByb3ZpZGUgYSBjb21wcmVoZW5zaXZlIG1hbmFnZW1lbnQgc3lzdGVtIGZvciBsZWFybmluZyBwcm9jZXNzZXMsIG9mdGVuIHVzZWQgYnkgaW5zdGl0dXRpb25zIGFuZCBjb3Jwb3JhdGlvbnMuPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPlR1dG9yaW5nIGFuZCBNZW50b3Jpbmc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlNlcnZpY2VzIGFuZCBwbGF0Zm9ybXMgdGhhdCBjb25uZWN0IHN0dWRlbnRzIHdpdGggdHV0b3JzIGFuZCBtZW50b3JzLjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5PbmxpbmUgQ291cnNlcyBhbmQgTU9PQ3MgKE1hc3NpdmUgT3BlbiBPbmxpbmUgQ291cnNlcyk8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlBsYXRmb3JtcyBvZmZlcmluZyBhIHZhcmlldHkgb2YgY291cnNlcyBhY3Jvc3MgZGlmZmVyZW50IHN1YmplY3RzLCB0eXBpY2FsbHkgYXZhaWxhYmxlIHRvIGEgbGFyZ2UgYXVkaWVuY2UuPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkNvbnRlbnQgQ3JlYXRpb24gYW5kIFB1Ymxpc2hpbmc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlRvb2xzIGFuZCBwbGF0Zm9ybXMgZm9yIGNyZWF0aW5nLCBzaGFyaW5nLCBhbmQgcHVibGlzaGluZyBlZHVjYXRpb25hbCBjb250ZW50LjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5FZHV0YWlubWVudDwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+RWR1Y2F0aW9uYWwgdG9vbHMgYW5kIHJlc291cmNlcyB0aGF0IGluY29ycG9yYXRlIGVudGVydGFpbm1lbnQsIHN1Y2ggYXMgZWR1Y2F0aW9uYWwgZ2FtZXMgYW5kIGludGVyYWN0aXZlIGxlYXJuaW5nIHRvb2xzLjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5TcGVjaWFsIEVkdWNhdGlvbjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+VGVjaG5vbG9naWVzIGRlc2lnbmVkIHRvIHN1cHBvcnQgbGVhcm5lcnMgd2l0aCBzcGVjaWFsIG5lZWRzLjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5Bc3Nlc3NtZW50IGFuZCBUZXN0aW5nPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5Tb2x1dGlvbnMgdGhhdCBmb2N1cyBvbiBzdHVkZW50IGV2YWx1YXRpb24sIHRlc3RpbmcsIGFuZCBleGFtaW5hdGlvbi48L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+RWFybHkgQ2hpbGRob29kIEVkdWNhdGlvbjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+UGxhdGZvcm1zIGFuZCB0b29scyBhaW1lZCBhdCBwcmUtSyBlZHVjYXRpb24uPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPlZpcnR1YWwgYW5kIEF1Z21lbnRlZCBSZWFsaXR5IChWUi9BUikgaW4gRWR1Y2F0aW9uPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5JbW1lcnNpdmUgdGVjaG5vbG9naWVzIHVzZWQgdG8gZW5oYW5jZSB0aGUgbGVhcm5pbmcgZXhwZXJpZW5jZS48L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+Q29kaW5nIGFuZCBQcm9ncmFtbWluZzwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+UGxhdGZvcm1zIGFuZCB0b29scyB0aGF0IHRlYWNoIGNvZGluZyBhbmQgcHJvZ3JhbW1pbmcgc2tpbGxzLjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5Db2xsYWJvcmF0aW9uIGFuZCBDb21tdW5pY2F0aW9uIFRvb2xzPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5Tb2x1dGlvbnMgdGhhdCBmYWNpbGl0YXRlIGNvbW11bmljYXRpb24gYW5kIGNvbGxhYm9yYXRpb24gYW1vbmcgc3R1ZGVudHMsIHRlYWNoZXJzLCBhbmQgcGFyZW50cy48L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+U2Nob29sIEFkbWluaXN0cmF0aW9uIGFuZCBNYW5hZ2VtZW50PC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5TeXN0ZW1zIGRlc2lnbmVkIHRvIG1hbmFnZSBzY2hvb2wgb3BlcmF0aW9ucywgc3VjaCBhcyBhdHRlbmRhbmNlLCBncmFkZXMsIGFuZCByZXNvdXJjZSBwbGFubmluZy48L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+RWR1Y2F0aW9uYWwgSGFyZHdhcmU8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkRldmljZXMgYW5kIHBoeXNpY2FsIHRlY2hub2xvZ2llcyB1c2VkIGluIGVkdWNhdGlvbmFsIHNldHRpbmdzLCBsaWtlIHRhYmxldHMsIGludGVyYWN0aXZlIHdoaXRlYm9hcmRzLCBhbmQgcm9ib3RpY3Mga2l0cy48L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+QWRhcHRpdmUgTGVhcm5pbmc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlRlY2hub2xvZ2llcyB0aGF0IHVzZSBkYXRhIGFuZCBhbmFseXRpY3MgdG8gcGVyc29uYWxpemUgdGhlIGxlYXJuaW5nIGV4cGVyaWVuY2UuPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkVkVGVjaCBJbmZyYXN0cnVjdHVyZTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+QmFja2VuZCB0ZWNobm9sb2dpZXMgYW5kIHNlcnZpY2VzIHRoYXQgc3VwcG9ydCBlZHVjYXRpb25hbCBwbGF0Zm9ybXMgYW5kIHRvb2xzLCBsaWtlIGNsb3VkIHNlcnZpY2VzLCBkYXRhIG1hbmFnZW1lbnQsIGFuZCBjeWJlcnNlY3VyaXR5IHNvbHV0aW9ucy48L3RkPg0KICAgIDwvdHI+DQogIDwvdGJvZHk+DQo8L3RhYmxlPg0KDQoqKioqKg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQogIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlOWY1ZGI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPvCfk4QgPGI+Q2FwYWJpbGl0aWVzPC9iPjwvc3Bhbj4NCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhlIGZvbGxvd2luZyBsaXN0IG9mIGNhcGFiaWxpdGllcyB3YXMgdXNlZCB0byBhbmFseXplIHRoZSBwb3RlbnRpYWwgYW5kIGNvbXBldGVuY2llcyBvZiBlYWNoIGNvbXBhbnkuIFRoZXNlIGNhcGFiaWxpdGllcyBhcmUgY2F0ZWdvcml6ZWQgdW5kZXIgbWFpbiBjYXRlZ29yaWVzIGFuZCBzdWItY2F0ZWdvcmllcyB0byBlbnN1cmUgYSBjb21wcmVoZW5zaXZlIGV2YWx1YXRpb24uIFRoZSBsaXN0IGlzIGJhc2VkIG9uIHRoZSBIb2xvbklRIGZyYW1ld29yaywgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmRpZ2l0YWxjYXBhYmlsaXR5Lm9yZy8jd3Atc2VjdGlvbiIgc3R5bGU9ImNvbG9yOiAjMWE3M2U4OyI+RGlnaXRhbCBDYXBhYmlsaXR5IEZyYW1ld29yazwvYT4uIFRoZSBpbWFnZSBwcm92aWRlZCBiZWxvdywgc291cmNlZCBmcm9tIEhvbG9uSVEsIGlsbHVzdHJhdGVzIHRoZXNlIGNhcGFiaWxpdGllcy4gSG93ZXZlciwgdGhlIGxpc3QgYmVsb3cgaGFzIGJlZW4gcmVmb3JtYXR0ZWQgZm9yIGVhc2Ugb2YgdW5kZXJzdGFuZGluZyBhbmQgdG8gZW5zdXJlIGJldHRlciBwZXJmb3JtYW5jZSB3aGVuIHByb2Nlc3NlZCBieSB0aGUgQ2hhdEdQVCBhbGdvcml0aG0uDQo8L3A+DQoNCg0KIVtdKGhvbG9uX2NhcGFiaWxpdGllcy5wbmcpDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgbGlzdCBzaG93biBiZWxvdyBpcyBhIHJlaW50ZXJwcmV0YXRpb24gb2YgdGhlIHByZXZpb3VzIGltYWdlIHRvIGNhdGVnb3JpemUgdGhlIGNhcGFiaWxpdGllcyBhbmQgYmUgYWJsZSB0byBwYXNzIHRoZW0gdGhyb3VnaCB0aGUgZ3B0IGNoYXQgYXBpLCBzbyB0aGF0IGl0IGNvdWxkIGJlIGludGVycHJldGVkIGluIGEgbW9yZSB1bmRlcnN0YW5kYWJsZSB3YXkgYW5kIGluIHRleHQgZm9ybWF0Lg0KPC9wPg0KDQoNCg0KPHRhYmxlPg0KICA8dGhlYWQ+DQogICAgPHRyPg0KICAgICAgPHRoPk1haW4gQ2F0ZWdvcnk8L3RoPg0KICAgICAgPHRoPlN1Yi1DYXRlZ29yeTwvdGg+DQogICAgICA8dGg+Q2FwYWJpbGl0eTwvdGg+DQogICAgPC90cj4NCiAgPC90aGVhZD4NCiAgPHRib2R5Pg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkRFTUFORCBBTkQgRElTQ09WRVJZPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5QUk9EVUNUIFNUUkFURUdZPC90ZD4NCiAgICAgIDx0ZD5NQVJLRVQgSU5TSUdIVFMgJiBUUkVORFM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+REVNQU5EIEFORCBESVNDT1ZFUlk8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlBST0RVQ1QgU1RSQVRFR1k8L3RkPg0KICAgICAgPHRkPlVOREVSU1RBTkQgQ1VTVE9NRVIgTkVFRFM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+REVNQU5EIEFORCBESVNDT1ZFUlk8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlBST0RVQ1QgU1RSQVRFR1k8L3RkPg0KICAgICAgPHRkPkNPTVBFVElUT1JTICYgQUxURVJOQVRFUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5ERU1BTkQgQU5EIERJU0NPVkVSWTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+UFJPRFVDVCBTVFJBVEVHWTwvdGQ+DQogICAgICA8dGQ+TkVXIEJVU0lORVNTIE1PREVMUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5ERU1BTkQgQU5EIERJU0NPVkVSWTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+UFJPRFVDVCBTVFJBVEVHWTwvdGQ+DQogICAgICA8dGQ+QjJCIFJFQ1JVSVRNRU5UICYgUEFSVE5FUlNISVBTPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkRFTUFORCBBTkQgRElTQ09WRVJZPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5NQVJLRVRJTkcgUFJPQ0VTU0VTPC90ZD4NCiAgICAgIDx0ZD5TVFVERU5UIFJFTEFUSU9OU0hJUCBNQU5BR0VNRU5UIChDUk0pPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkRFTUFORCBBTkQgRElTQ09WRVJZPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5NQVJLRVRJTkcgUFJPQ0VTU0VTPC90ZD4NCiAgICAgIDx0ZD5DT01NUyAmIENBTVBBSUdOIE1BTkFHRU1FTlQ8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+REVNQU5EIEFORCBESVNDT1ZFUlk8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPk1BUktFVElORyBQUk9DRVNTRVM8L3RkPg0KICAgICAgPHRkPk1BUktFVElORyBBVVRPTUFUSU9OPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkRFTUFORCBBTkQgRElTQ09WRVJZPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5NQVJLRVRJTkcgUFJPQ0VTU0VTPC90ZD4NCiAgICAgIDx0ZD5TT0NJQUwgTUVESUEgJiBDT01NVU5JVFkgTUFOQUdFTUVOVDwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5ERU1BTkQgQU5EIERJU0NPVkVSWTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+U1RVREVOVCBSRUNSVUlUTUVOVDwvdGQ+DQogICAgICA8dGQ+UkVDUlVJVE1FTlQgRVZFTlRTPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkRFTUFORCBBTkQgRElTQ09WRVJZPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5TVFVERU5UIFJFQ1JVSVRNRU5UPC90ZD4NCiAgICAgIDx0ZD5DSEFOTkVMIFBBUlRORVJTSElQUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5ERU1BTkQgQU5EIERJU0NPVkVSWTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+U1RVREVOVCBSRUNSVUlUTUVOVDwvdGQ+DQogICAgICA8dGQ+U0NIT09MUyAmIENPTU1VTklUWSBPVVRSRUFDSDwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5ERU1BTkQgQU5EIERJU0NPVkVSWTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+U1RVREVOVCBSRUNSVUlUTUVOVDwvdGQ+DQogICAgICA8dGQ+U0NIT0xBUlNISVAgUFJPR1JBTTwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5ERU1BTkQgQU5EIERJU0NPVkVSWTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+RU5ST0xMTUVOVCBNQU5BR0VNRU5UPC90ZD4NCiAgICAgIDx0ZD5DT1VSU0UgU0VMRUNUSU9OICYgR1VJREFOQ0U8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+REVNQU5EIEFORCBESVNDT1ZFUlk8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkVOUk9MTE1FTlQgTUFOQUdFTUVOVDwvdGQ+DQogICAgICA8dGQ+QVBQTElDQVRJT04gJiBBRE1JU1NJT05TPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkRFTUFORCBBTkQgRElTQ09WRVJZPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5FTlJPTExNRU5UIE1BTkFHRU1FTlQ8L3RkPg0KICAgICAgPHRkPlJFQ09HTklaSU5HIFBSSU9SIExFQVJOSU5HPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkRFTUFORCBBTkQgRElTQ09WRVJZPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5FTlJPTExNRU5UIE1BTkFHRU1FTlQ8L3RkPg0KICAgICAgPHRkPlRVSVRJT04gRklOQU5DSU5HPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJOSU5HIERFU0lHTjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+Q1VSUklDVUxVTSBERVNJR048L3RkPg0KICAgICAgPHRkPkRJR0lUQUwgREVTSUdOIFBSSU5DSVBMRVM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5JTkcgREVTSUdOPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5DVVJSSUNVTFVNIERFU0lHTjwvdGQ+DQogICAgICA8dGQ+UFJPR1JBTSBBUkNISVRFQ1RVUkU8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5JTkcgREVTSUdOPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5DVVJSSUNVTFVNIERFU0lHTjwvdGQ+DQogICAgICA8dGQ+TEVBUk5JTkcgRU5WSVJPTk1FTlRTICYgUExBVEZPUk1TPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJOSU5HIERFU0lHTjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+Q1VSUklDVUxVTSBERVNJR048L3RkPg0KICAgICAgPHRkPkxFQVJOSU5HIERFTElWRVJZIE1PREVMUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTklORyBERVNJR048L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkNVUlJJQ1VMVU0gREVTSUdOPC90ZD4NCiAgICAgIDx0ZD5BQ0NSRURJVEFUSU9OPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJOSU5HIERFU0lHTjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+Q1VSUklDVUxVTSBERVNJR048L3RkPg0KICAgICAgPHRkPkNVUlJJQ1VMVU0gUVVBTElUWSBNQU5BR0VNRU5UPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJOSU5HIERFU0lHTjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+RElHSVRBTCBDT05URU5UICYgQ09VUlNFV0FSRTwvdGQ+DQogICAgICA8dGQ+RElHSVRBTCBDT05URU5UIENSRUFUSU9OPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJOSU5HIERFU0lHTjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+RElHSVRBTCBDT05URU5UICYgQ09VUlNFV0FSRTwvdGQ+DQogICAgICA8dGQ+SU1NRVJTSU9OLCBTSU1VTEFUSU9OICYgTEFCPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJOSU5HIERFU0lHTjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+RElHSVRBTCBDT05URU5UICYgQ09VUlNFV0FSRTwvdGQ+DQogICAgICA8dGQ+T0VSICYgQ09OVEVOVCBMSUNFTlNJTkc8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5JTkcgREVTSUdOPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5ESUdJVEFMIENPTlRFTlQgJiBDT1VSU0VXQVJFPC90ZD4NCiAgICAgIDx0ZD5NQU5BR0lORyBJTlRFR1JBVEVEIENPTlRFTlQ8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5JTkcgREVTSUdOPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5TVUJKRUNUIE1BVFRFUiBFWFBFUlRJU0U8L3RkPg0KICAgICAgPHRkPkRFU0lHTklORyBGT1IgRElHSVRBTCBMRUFSTklORzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTklORyBERVNJR048L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlNVQkpFQ1QgTUFUVEVSIEVYUEVSVElTRTwvdGQ+DQogICAgICA8dGQ+RkFDVUxUWSBFWFBFUlRJU0UgJiBTUEVDSUFMSVNNUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTklORyBERVNJR048L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlNVQkpFQ1QgTUFUVEVSIEVYUEVSVElTRTwvdGQ+DQogICAgICA8dGQ+U09VUkNJTkcgJiBNQU5BR0lORyBFWFBFUlRJU0U8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5JTkcgREVTSUdOPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5TVUJKRUNUIE1BVFRFUiBFWFBFUlRJU0U8L3RkPg0KICAgICAgPHRkPlNQRUNJQUxJU1QgSU5EVVNUUlkgUEFSVE5FUlM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5JTkcgREVTSUdOPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5URUFDSElORyBTVFJBVEVHSUVTPC90ZD4NCiAgICAgIDx0ZD5MRUFSTkVSIE5FRURTICYgQU5BTFlUSUNTPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJOSU5HIERFU0lHTjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+VEVBQ0hJTkcgU1RSQVRFR0lFUzwvdGQ+DQogICAgICA8dGQ+REVTSUdOSU5HIEFTU0VTU01FTlQ8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5JTkcgREVTSUdOPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5URUFDSElORyBTVFJBVEVHSUVTPC90ZD4NCiAgICAgIDx0ZD5FWFBFUklFTlRJQUwgTEVBUk5JTkcgQVBQUk9BQ0hFUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTklORyBERVNJR048L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlRFQUNISU5HIFNUUkFURUdJRVM8L3RkPg0KICAgICAgPHRkPkRFU0lHTklORyBHUk9VUCBXT1JLPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJOSU5HIERFU0lHTjwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+VEVBQ0hJTkcgU1RSQVRFR0lFUzwvdGQ+DQogICAgICA8dGQ+UEVSU09OQUxJWkVEICYgQURBUFRJVkUgTEVBUk5JTkc8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BQ0FERU1JQyBBRE1JTklTVFJBVElPTjwvdGQ+DQogICAgICA8dGQ+RkFDVUxUWSBQUk9GRVNTSU9OQUwgREVWRUxPUE1FTlQ8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BQ0FERU1JQyBBRE1JTklTVFJBVElPTjwvdGQ+DQogICAgICA8dGQ+RkFDVUxUWSBNQU5BR0VNRU5UICYgU1VQUE9SVDwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTkVSIEVYUEVSSUVOQ0U8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkFDQURFTUlDIEFETUlOSVNUUkFUSU9OPC90ZD4NCiAgICAgIDx0ZD5USU1FVEFCTElORyAmIFNDSEVEVUxFIE1BTkFHRU1FTlQ8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BQ0FERU1JQyBBRE1JTklTVFJBVElPTjwvdGQ+DQogICAgICA8dGQ+UkVURU5USU9OICYgTEVBUk5JTkcgU1VQUE9SVDwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTkVSIEVYUEVSSUVOQ0U8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkFDQURFTUlDIEFETUlOSVNUUkFUSU9OPC90ZD4NCiAgICAgIDx0ZD5SRVBPUlRJTkcgJiBSRUdVTEFUT1JZIENPTVBMSUFOQ0U8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BQ0FERU1JQyBBRE1JTklTVFJBVElPTjwvdGQ+DQogICAgICA8dGQ+TElCUkFSWSBTRVJWSUNFUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTkVSIEVYUEVSSUVOQ0U8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkxFQVJOSU5HICYgQUNBREVNSUMgRVhQRVJJRU5DRTwvdGQ+DQogICAgICA8dGQ+U1RVREVOVCBQT1JUQUwgJiBMTVM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5MRUFSTklORyAmIEFDQURFTUlDIEVYUEVSSUVOQ0U8L3RkPg0KICAgICAgPHRkPlNZTkNIUk9OT1VTIExFQVJOSU5HIEVYUEVSSUVOQ0VTPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJORVIgRVhQRVJJRU5DRTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+TEVBUk5JTkcgJiBBQ0FERU1JQyBFWFBFUklFTkNFPC90ZD4NCiAgICAgIDx0ZD5BU1lOQ0hST05PVVMgTEVBUk5JTkcgRVhQRVJJRU5DRVM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5MRUFSTklORyAmIEFDQURFTUlDIEVYUEVSSUVOQ0U8L3RkPg0KICAgICAgPHRkPlZPSUNFLCBDSEFUICYgSU5URVJBQ1RJVkUgTEVBUk5JTkc8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5MRUFSTklORyAmIEFDQURFTUlDIEVYUEVSSUVOQ0U8L3RkPg0KICAgICAgPHRkPklOREVQRU5ERU5UIExFQVJOSU5HIFJFU09VUkNFUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTkVSIEVYUEVSSUVOQ0U8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkxFQVJOSU5HICYgQUNBREVNSUMgRVhQRVJJRU5DRTwvdGQ+DQogICAgICA8dGQ+RVhDSEFOR0UgUFJPR1JBTVM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5TVFVERU5UIExJRkU8L3RkPg0KICAgICAgPHRkPk9OQk9BUkRJTkcgJiBPUklFTlRBVElPTjwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTkVSIEVYUEVSSUVOQ0U8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlNUVURFTlQgTElGRTwvdGQ+DQogICAgICA8dGQ+V0VMTEJFSU5HICYgTUVOVEFMIEhFQUxUSDwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTkVSIEVYUEVSSUVOQ0U8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlNUVURFTlQgTElGRTwvdGQ+DQogICAgICA8dGQ+U1RVREVOVCBDT01NVU5JVElFUywgQ0xVQlMgJiBTT0NJRVRJRVM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5TVFVERU5UIExJRkU8L3RkPg0KICAgICAgPHRkPlZPTFVOVEVFUklORyAmIFNUVURFTlQgTEVBREVSU0hJUDwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTkVSIEVYUEVSSUVOQ0U8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPlNUVURFTlQgTElGRTwvdGQ+DQogICAgICA8dGQ+U1RVREVOVCBWT0lDRSAmIFNVUlZFWVM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5TVFVERU5UIExJRkU8L3RkPg0KICAgICAgPHRkPkdSQURVQVRJT04gJiBTVUNDRVNTPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJORVIgRVhQRVJJRU5DRTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+QVNTRVNTTUVOVCAmIFZFUklGSUNBVElPTjwvdGQ+DQogICAgICA8dGQ+VEVTVFMgJiBFWEFNUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5MRUFSTkVSIEVYUEVSSUVOQ0U8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkFTU0VTU01FTlQgJiBWRVJJRklDQVRJT048L3RkPg0KICAgICAgPHRkPlBPUlRGT0xJT1MgJiBQUkFDVElDQUw8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BU1NFU1NNRU5UICYgVkVSSUZJQ0FUSU9OPC90ZD4NCiAgICAgIDx0ZD5BU1NFU1NNRU5UIEZFRURCQUNLPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPkxFQVJORVIgRVhQRVJJRU5DRTwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+QVNTRVNTTUVOVCAmIFZFUklGSUNBVElPTjwvdGQ+DQogICAgICA8dGQ+UEVFUiAmIEdST1VQIEFTU0VTU01FTlQ8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+TEVBUk5FUiBFWFBFUklFTkNFPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BU1NFU1NNRU5UICYgVkVSSUZJQ0FUSU9OPC90ZD4NCiAgICAgIDx0ZD5CQURHSU5HICYgQ1JFREVOVElBTElORzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5XT1JLIEFORCBMSUZFTE9ORyBMRUFSTklORzwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+V09SSyBJTlRFR1JBVEVEIExFQVJOSU5HPC90ZD4NCiAgICAgIDx0ZD5FTVBMT1lBQklMSVRZIFNLSUxMUyBCVUlMRElORzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5XT1JLIEFORCBMSUZFTE9ORyBMRUFSTklORzwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+V09SSyBJTlRFR1JBVEVEIExFQVJOSU5HPC90ZD4NCiAgICAgIDx0ZD5XT1JLUExBQ0UgU0lNVUxBVElPTiAmIFBST0pFQ1RTPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPldPUksgQU5EIExJRkVMT05HIExFQVJOSU5HPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5XT1JLIElOVEVHUkFURUQgTEVBUk5JTkc8L3RkPg0KICAgICAgPHRkPklOVEVSTlNISVBTICYgUExBQ0VNRU5UUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5XT1JLIEFORCBMSUZFTE9ORyBMRUFSTklORzwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+V09SSyBJTlRFR1JBVEVEIExFQVJOSU5HPC90ZD4NCiAgICAgIDx0ZD5TVFVERU5UIFdPUks8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+V09SSyBBTkQgTElGRUxPTkcgTEVBUk5JTkc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPldPUksgSU5URUdSQVRFRCBMRUFSTklORzwvdGQ+DQogICAgICA8dGQ+RU5UUkVQUkVORVVSU0hJUCAmIFNUQVJUVVBTPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPldPUksgQU5EIExJRkVMT05HIExFQVJOSU5HPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5DQVJFRVIgUExBTk5JTkcgJiBQTEFDRU1FTlQ8L3RkPg0KICAgICAgPHRkPkNPTVBFVEVOQ0lFUyAmIFNLSUxMUyBFVkFMVUFUSU9OPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPldPUksgQU5EIExJRkVMT05HIExFQVJOSU5HPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5DQVJFRVIgUExBTk5JTkcgJiBQTEFDRU1FTlQ8L3RkPg0KICAgICAgPHRkPkNBUkVFUiBQTEFOTklORyBTRVJWSUNFUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5XT1JLIEFORCBMSUZFTE9ORyBMRUFSTklORzwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+Q0FSRUVSIFBMQU5OSU5HICYgUExBQ0VNRU5UPC90ZD4NCiAgICAgIDx0ZD5DQVJFRVIgJiBSRUNSVUlUTUVOVCBFVkVOVFM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+V09SSyBBTkQgTElGRUxPTkcgTEVBUk5JTkc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkNBUkVFUiBQTEFOTklORyAmIFBMQUNFTUVOVDwvdGQ+DQogICAgICA8dGQ+Sk9CIEFQUExJQ0FUSU9OIFNVUFBPUlQ8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+V09SSyBBTkQgTElGRUxPTkcgTEVBUk5JTkc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkNBUkVFUiBQTEFOTklORyAmIFBMQUNFTUVOVDwvdGQ+DQogICAgICA8dGQ+Sk9CIEZJTkRJTkcgJiBHUkFEVUFURSBQTEFDRU1FTlQ8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+V09SSyBBTkQgTElGRUxPTkcgTEVBUk5JTkc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPklORFVTVFJZICYgQlVTSU5FU1MgRU5HQUdFTUVOVDwvdGQ+DQogICAgICA8dGQ+SU5EVVNUUlkgQ09MTEFCUyAmIFBBUlRORVJTSElQUzwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5XT1JLIEFORCBMSUZFTE9ORyBMRUFSTklORzwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+SU5EVVNUUlkgJiBCVVNJTkVTUyBFTkdBR0VNRU5UPC90ZD4NCiAgICAgIDx0ZD5QUk9GRVNTSU9OQUwgJiBJTkRVU1RSWSBBU1NPQ0lBVElPTlM8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+V09SSyBBTkQgTElGRUxPTkcgTEVBUk5JTkc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPklORFVTVFJZICYgQlVTSU5FU1MgRU5HQUdFTUVOVDwvdGQ+DQogICAgICA8dGQ+Q1VTVE9NSVpFRCBQUk9HUkFNUyAoQjJCKTwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5XT1JLIEFORCBMSUZFTE9ORyBMRUFSTklORzwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+SU5EVVNUUlkgJiBCVVNJTkVTUyBFTkdBR0VNRU5UPC90ZD4NCiAgICAgIDx0ZD5FRFVDQVRJT04gQVMgRU1QTE9ZRUUgQkVORUZJVDwvdGQ+DQogICAgPC90cj4NCiAgICA8dHI+DQogICAgICA8dGQ+PHN0cm9uZz5XT1JLIEFORCBMSUZFTE9ORyBMRUFSTklORzwvc3Ryb25nPjwvdGQ+DQogICAgICA8dGQ+QUxVTU5JICYgQ09OVElOVUlORyBFRFVDQVRJT048L3RkPg0KICAgICAgPHRkPkNPTlRJTlVJTkcgRURVQ0FUSU9OPC90ZD4NCiAgICA8L3RyPg0KICAgIDx0cj4NCiAgICAgIDx0ZD48c3Ryb25nPldPUksgQU5EIExJRkVMT05HIExFQVJOSU5HPC9zdHJvbmc+PC90ZD4NCiAgICAgIDx0ZD5BTFVNTkkgJiBDT05USU5VSU5HIEVEVUNBVElPTjwvdGQ+DQogICAgICA8dGQ+SU5EVVNUUlkgTUVOVE9SSU5HICYgTkVUV09SS1M8L3RkPg0KICAgIDwvdHI+DQogICAgPHRyPg0KICAgICAgPHRkPjxzdHJvbmc+V09SSyBBTkQgTElGRUxPTkcgTEVBUk5JTkc8L3N0cm9uZz48L3RkPg0KICAgICAgPHRkPkFMVU1OSSAmIENPTlRJTlVJTkcgRURVQ0FUSU9OPC90ZD4NCiAgICAgIDx0ZD5BTFVNTkkgRU5HQUdFTUVOVDwvdGQ+DQogICAgPC90cj4NCiAgPC90Ym9keT4NCjwvdGFibGU+DQoNCg0KDQo8ZGl2IHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmOWY5Zjk7IGJvcmRlci1sZWZ0OjVweCBzb2xpZCAjY2NjOyBwYWRkaW5nOjEwcHg7IG1hcmdpbjoxMHB4IDA7Ij4NCiAgPHA+PHN0cm9uZz5Ob3RlOjwvc3Ryb25nPiBJZiB5b3Ugd2FudCB0byBzZWUgdGhlIHRlY2huaWNhbCBpbmZvcm1hdGlvbiBvZiB0aGUgcHJvY2VzcywgcGxlYXNlIGNsaWNrIHRoZSBidXR0b24gYmVsb3cuPC9wPg0KPC9kaXY+DQoNCg0KPGhlYWQ+DQogIDxtZXRhIGNoYXJzZXQ9IlVURi04Ij4NCiAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjAiPg0KICA8dGl0bGU+RG9jdW1lbnQ8L3RpdGxlPg0KICA8IS0tIEluY2x1ZGUgUHJpc20uanMgQ1NTIGZvciB0aGUgIlRvbW9ycm93IiB0aGVtZSAtLT4NCiAgPGxpbmsgaHJlZj0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvcHJpc20vMS4yNS4wL3RoZW1lcy9wcmlzbS10b21vcnJvdy5taW4uY3NzIiByZWw9InN0eWxlc2hlZXQiIC8+DQo8L2hlYWQ+DQo8Ym9keT4NCg0KPHN1bW1hcnkgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2Y3ZWJmZDsgY29sb3I6YmxhY2s7IGJvcmRlci1yYWRpdXM6MThweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWFsaWduOiBsZWZ0OyI+KipUZWNobmljYWwgSW5mb3JtYXRpb24qKjwvc3VtbWFyeT4NCjxkaXYgc3R5bGU9Im1hcmdpbi10b3A6IDEwcHg7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgPHA+VGhpcyBzZWN0aW9uIGV4cGxhaW5zIHRoZSB0ZWNobmljYWwgZGV0YWlscyBvZiBob3cgd2UgY29sbGVjdGVkIGFuZCBwcm9jZXNzZWQgdGhlIGRhdGEuIEhlcmUgaXMgYW4gZWFzeS10by11bmRlcnN0YW5kIGJyZWFrZG93bjo8L3A+DQogIDxvbCBzdHlsZT0icGFkZGluZy1sZWZ0OiAzMHB4OyI+DQogICAgPGxpPjxzdHJvbmc+T3BlbkFJIEFQSSBJbnRlcmFjdGlvbjo8L3N0cm9uZz4gVGhlIGBxdWVyeV9vcGVuYWlfYXBpYCBmdW5jdGlvbiBoYW5kbGVzIHRoZSBpbnRlcmFjdGlvbiB3aXRoIHRoZSBPcGVuQUkgQVBJLCBpbmNsdWRpbmcgcmV0cnkgbG9naWMgdG8gbWFuYWdlIGVycm9ycy48L2xpPg0KICAgIDxsaT48c3Ryb25nPlJvbGUgQ2F0ZWdvcml6YXRpb246PC9zdHJvbmc+IFRoZSBgY2F0ZWdvcml6ZV9wb3RlbnRpYWxfcm9sZWAgZnVuY3Rpb24gZGV0ZXJtaW5lcyB0aGUgcG90ZW50aWFsIHJvbGUgb2YgdGhlIGNvbXBhbnkgKGNsaWVudCwgcGFydG5lciwgY29tcGV0aXRvciwgb3IgcHJvdmlkZXIpIGJhc2VkIG9uIHRoZSBBUEkgcmVzcG9uc2UuPC9saT4NCiAgICA8bGk+PHN0cm9uZz5WZXJ0aWNhbCBDYXRlZ29yaXphdGlvbjo8L3N0cm9uZz4gVGhlIGBjYXRlZ29yaXplX3BvdGVudGlhbF92ZXJ0aWNhbGAgZnVuY3Rpb24gaWRlbnRpZmllcyB0aGUgYXBwcm9wcmlhdGUgdmVydGljYWwgZm9yIHRoZSBjb21wYW55IGZyb20gYSBwcmVkZWZpbmVkIGxpc3QuPC9saT4NCiAgICA8bGk+PHN0cm9uZz5DYXBhYmlsaXR5IEV4dHJhY3Rpb24gYW5kIFZhbGlkYXRpb246PC9zdHJvbmc+IFRoZSBgZXh0cmFjdF9hbmRfdmFsaWRhdGVfY2FwYWJpbGl0aWVzYCBmdW5jdGlvbiBleHRyYWN0cyBhbmQgdmFsaWRhdGVzIHRoZSBjYXBhYmlsaXRpZXMgb2YgdGhlIGNvbXBhbnksIGVuc3VyaW5nIGV4YWN0bHkgZml2ZSB1bmlxdWUgY2FwYWJpbGl0aWVzLjwvbGk+DQogICAgPGxpPjxzdHJvbmc+Q29tcGFueSBQcm9jZXNzaW5nOjwvc3Ryb25nPiBUaGUgYHByb2Nlc3NfY29tcGFueV9jb2x1bW5gIGZ1bmN0aW9uIHByb2Nlc3NlcyBlYWNoIGNvbXBhbnkncyBkYXRhLCBjb25zdHJ1Y3RzIHByb21wdHMsIHF1ZXJpZXMgdGhlIEFQSSwgYW5kIGNvbXBpbGVzIHRoZSByZXN1bHRzLjwvbGk+DQogICAgPGxpPjxzdHJvbmc+UHJvZ3Jlc3MgU2F2aW5nOjwvc3Ryb25nPiBUaGUgYHNhdmVfcHJvZ3Jlc3NgIGZ1bmN0aW9uIHBlcmlvZGljYWxseSBzYXZlcyB0aGUgcHJvZ3Jlc3Mgb2YgdGhlIGFuYWx5c2lzIHRvIGFuIEV4Y2VsIGZpbGUuPC9saT4NCiAgICA8bGk+PHN0cm9uZz5NYWluIFByb2Nlc3NpbmcgTG9vcDo8L3N0cm9uZz4gVGhlIHNjcmlwdCBwcm9jZXNzZXMgZWFjaCBjb21wYW55IGluIHRoZSBkYXRhc2V0LCByZWFkcyB3ZWJwYWdlIGNvbnRlbnQsIGhhbmRsZXMgZXJyb3JzLCBhbmQgc2F2ZXMgdGhlIGZpbmFsIHJlc3VsdHMgdG8gYW4gRXhjZWwgZmlsZS48L2xpPg0KICA8L29sPg0KICA8cD5UaGlzIGFwcHJvYWNoIGFsbG93ZWQgdXMgdG8gZ2F0aGVyIGNvbXByZWhlbnNpdmUgaW5mb3JtYXRpb24gYWJvdXQgZWFjaCBjb21wYW55LCB3aGljaCB3YXMgdGhlbiBhbmFseXplZCB0byBpZGVudGlmeSBwb3RlbnRpYWwgYnVzaW5lc3Mgb3Bwb3J0dW5pdGllcyBmb3IgRWR1TmV4dC48L3A+DQogIDxwcmU+PGNvZGUgY2xhc3M9Imxhbmd1YWdlLXB5dGhvbiI+DQppbXBvcnQgb3BlbmFpDQppbXBvcnQgcGFuZGFzIGFzIHBkDQppbXBvcnQgbG9nZ2luZw0KaW1wb3J0IHRpbWUNCmZyb20gcmFuZG9tIGltcG9ydCByYW5kb20NCmltcG9ydCBvcw0KDQojIFNldCB1cCBsb2dnaW5nDQpsb2dnaW5nLmJhc2ljQ29uZmlnKGxldmVsPWxvZ2dpbmcuSU5GTywgZm9ybWF0PSclKGFzY3RpbWUpcyAtICUobGV2ZWxuYW1lKXMgLSAlKG1lc3NhZ2UpcycpDQoNCiMgU2V0IHlvdXIgT3BlbkFJIEFQSSBrZXkNCm9wZW5haS5hcGlfa2V5ID0gJ0FERCBUSEUgS0VZJw0KDQojIExvYWQgdGhlIExpbmtlZEluIGRhdGENCmxpbmtlZEluX2RhdGEgPSBwZC5yZWFkX2V4Y2VsKCdjbGVhbmVkX2NvbXBhbnlfaW5mb3JtYXRpb24ueGxzeCcsIHNraXByb3dzPXJhbmdlKDEsIDY2MCkpDQoNCiMgTG9hZCB0aGUgY2FwYWJpbGl0aWVzIGRhdGENCmNhcGFiaWxpdGllc19kYXRhID0gcGQucmVhZF9leGNlbCgnSW5wdXQvY2FwYWJpbGl0aWVzLnhsc3gnKQ0KdmFsaWRfY2FwYWJpbGl0aWVzID0gc2V0KGNhcGFiaWxpdGllc19kYXRhWydDYXBhYmlsaXR5J10uc3RyLnVwcGVyKCkudG9saXN0KCkpDQoNCiMgTG9hZCB0aGUgcm9sZSBkZWZpbml0aW9ucw0Kcm9sZV9kZWZpbml0aW9ucyA9IHBkLnJlYWRfZXhjZWwoJ0lucHV0L2NvbXBhbnlfcHJvZmlsZS54bHN4JykNCg0KIyBMb2FkIHRoZSB2ZXJ0aWNhbCBkYXRhDQp2ZXJ0aWNhbF9kYXRhID0gcGQucmVhZF9leGNlbCgnSW5wdXQvdmVydGljYWwueGxzeCcpDQoNCiMgRGVmaW5lIHZhbGlkIHJvbGVzIGFuZCB2ZXJ0aWNhbHMNCnZhbGlkX3JvbGVzID0gWydDTElFTlQnLCAnUEFSVE5FUicsICdDT01QRVRJVE9SJywgJ1BST1ZJREVSJ10NCnZhbGlkX3ZlcnRpY2FscyA9IHZlcnRpY2FsX2RhdGFbJ1ZlcnRpY2FsJ10udG9saXN0KCkNCg0KIyBQcmVwYXJlIHRoZSBvdXRwdXQgRGF0YUZyYW1lDQpvdXRwdXRfY29sdW1ucyA9IFsNCiAgICAnQ29tcGFueSBOYW1lJywgJ1VSTCAoTGlua2VkSW4gcHJvZmlsZSBsaW5rKScsICdXZWJzaXRlJywgJ09wZW5lZFggQ29ubmVjdGlvbicsDQogICAgJ01haW4gUHJvZHVjdCcsICdDb21wZXRpdG9ycycsICdDdXN0b21lcnMnLCAnQjJCIG9yIEIyQycsDQogICAgJ051bWJlciBvZiBDdXN0b21lcnMnLCAnQ291bnRyeScsICdQb3RlbnRpYWwgUm9sZScsICdQb3RlbnRpYWwgVmVydGljYWwnLA0KICAgICdDYXBhYmlsaXR5IDEnLCAnQ2FwYWJpbGl0eSAyJywgJ0NhcGFiaWxpdHkgMycsICdDYXBhYmlsaXR5IDQnLCAnQ2FwYWJpbGl0eSA1Jw0KXQ0KDQpvdXRwdXRfZGF0YSA9IHBkLkRhdGFGcmFtZShjb2x1bW5zPW91dHB1dF9jb2x1bW5zKQ0KYmFja3VwX2ludGVydmFsID0gMTAgICMgU2F2ZSBwcm9ncmVzcyBldmVyeSAxMCBjb21wYW5pZXMNCg0KIyBGdW5jdGlvbiB0byBxdWVyeSBPcGVuQUkgQVBJIHdpdGggcmV0cnkgbG9naWMNCmRlZiBxdWVyeV9vcGVuYWlfYXBpKHByb21wdCwgbW9kZWw9ImdwdC0zLjUtdHVyYm8iLCBtYXhfdG9rZW5zPTUxMiwgcmV0cmllcz01KToNCiAgICBmb3IgaSBpbiByYW5nZShyZXRyaWVzKToNCiAgICAgICAgdHJ5Og0KICAgICAgICAgICAgcmVzcG9uc2UgPSBvcGVuYWkuQ2hhdENvbXBsZXRpb24uY3JlYXRlKA0KICAgICAgICAgICAgICAgIG1vZGVsPW1vZGVsLA0KICAgICAgICAgICAgICAgIG1lc3NhZ2VzPVsNCiAgICAgICAgICAgICAgICAgICAgeyJyb2xlIjogInN5c3RlbSIsICJjb250ZW50IjogIllvdSBhcmUgYW4gYXNzaXN0YW50IHRoYXQgaGVscHMgYW5hbHl6ZSBjb21wYW55IGRhdGEuIn0sDQogICAgICAgICAgICAgICAgICAgIHsicm9sZSI6ICJ1c2VyIiwgImNvbnRlbnQiOiBwcm9tcHR9DQogICAgICAgICAgICAgICAgXSwNCiAgICAgICAgICAgICAgICBtYXhfdG9rZW5zPW1heF90b2tlbnMsDQogICAgICAgICAgICAgICAgdGVtcGVyYXR1cmU9MC43DQogICAgICAgICAgICApDQogICAgICAgICAgICByZXR1cm4gcmVzcG9uc2UuY2hvaWNlc1swXS5tZXNzYWdlWydjb250ZW50J10uc3RyaXAoKQ0KICAgICAgICBleGNlcHQgb3BlbmFpLmVycm9yLk9wZW5BSUVycm9yIGFzIGU6DQogICAgICAgICAgICBsb2dnaW5nLmVycm9yKGYiQVBJRXJyb3IgZW5jb3VudGVyZWQ6IHtlfS4gUmV0cnlpbmcge2kgKyAxfS97cmV0cmllc30uLi4iKQ0KICAgICAgICAgICAgdGltZS5zbGVlcCgoMiAqKiBpKSArIHJhbmRvbSgpKQ0KICAgIHJldHVybiAiQVBJIHJlcXVlc3QgZmFpbGVkLiINCg0KIyBGdW5jdGlvbiB0byBjYXRlZ29yaXplIHBvdGVudGlhbCByb2xlDQpkZWYgY2F0ZWdvcml6ZV9wb3RlbnRpYWxfcm9sZShyZXNwb25zZSk6DQogICAgcmVzcG9uc2UgPSByZXNwb25zZS5sb3dlcigpDQogICAgaWYgImNsaWVudCIgaW4gcmVzcG9uc2U6DQogICAgICAgIHJldHVybiAiQ0xJRU5UIg0KICAgIGlmICJwYXJ0bmVyIiBpbiByZXNwb25zZToNCiAgICAgICAgcmV0dXJuICJQQVJUTkVSIg0KICAgIGlmICJjb21wZXRpdG9yIiBpbiByZXNwb25zZToNCiAgICAgICAgcmV0dXJuICJDT01QRVRJVE9SIg0KICAgIGlmICJwcm92aWRlciIgaW4gcmVzcG9uc2U6DQogICAgICAgIHJldHVybiAiUFJPVklERVIiDQogICAgcmV0dXJuICIiDQoNCiMgRnVuY3Rpb24gdG8gY2F0ZWdvcml6ZSBwb3RlbnRpYWwgdmVydGljYWwNCmRlZiBjYXRlZ29yaXplX3BvdGVudGlhbF92ZXJ0aWNhbChyZXNwb25zZSk6DQogICAgdmVydGljYWxzID0gdmVydGljYWxfZGF0YVsnVmVydGljYWwnXS50b2xpc3QoKQ0KICAgIGZvciB2ZXJ0aWNhbCBpbiB2ZXJ0aWNhbHM6DQogICAgICAgIGlmIHZlcnRpY2FsLmxvd2VyKCkgaW4gcmVzcG9uc2UubG93ZXIoKToNCiAgICAgICAgICAgIHJldHVybiB2ZXJ0aWNhbA0KICAgIHJldHVybiAiIg0KDQojIEZ1bmN0aW9uIHRvIGVuc3VyZSB0aGUgY2FwYWJpbGl0aWVzIGxpc3QgaGFzIGV4YWN0bHkgNSB1bmlxdWUgZW50cmllcw0KZGVmIGVuc3VyZV91bmlxdWVfY2FwYWJpbGl0aWVzKGNhcGFiaWxpdGllcyk6DQogICAgdW5pcXVlX2NhcGFiaWxpdGllcyA9IGxpc3QoZGljdC5mcm9ta2V5cyhjYXBhYmlsaXRpZXMpKSAgIyBSZW1vdmUgZHVwbGljYXRlcyB3aGlsZSBwcmVzZXJ2aW5nIG9yZGVyDQogICAgd2hpbGUgbGVuKHVuaXF1ZV9jYXBhYmlsaXRpZXMpIDwgNToNCiAgICAgICAgcmVtYWluaW5nX2NhcGFiaWxpdGllcyA9IGxpc3QodmFsaWRfY2FwYWJpbGl0aWVzIC0gc2V0KHVuaXF1ZV9jYXBhYmlsaXRpZXMpKQ0KICAgICAgICBpZiByZW1haW5pbmdfY2FwYWJpbGl0aWVzOg0KICAgICAgICAgICAgdW5pcXVlX2NhcGFiaWxpdGllcy5hcHBlbmQocmVtYWluaW5nX2NhcGFiaWxpdGllc1swXSkgICMgQWRkIGEgcmVtYWluaW5nIHZhbGlkIGNhcGFiaWxpdHkNCiAgICAgICAgZWxzZToNCiAgICAgICAgICAgIHVuaXF1ZV9jYXBhYmlsaXRpZXMuYXBwZW5kKCcnKSAgIyBJZiBubyB2YWxpZCBjYXBhYmlsaXRpZXMgYXJlIGxlZnQsIGFwcGVuZCBhbiBlbXB0eSBzdHJpbmcNCiAgICByZXR1cm4gdW5pcXVlX2NhcGFiaWxpdGllc1s6NV0NCg0KIyBGdW5jdGlvbiB0byBleHRyYWN0IGFuZCB2YWxpZGF0ZSBjYXBhYmlsaXRpZXMNCmRlZiBleHRyYWN0X2FuZF92YWxpZGF0ZV9jYXBhYmlsaXRpZXMocmVzcG9uc2UsIGNvbXBhbnlfbmFtZSk6DQogICAgY2FwYWJpbGl0aWVzID0gW10NCiAgICBsb2dnaW5nLmRlYnVnKGYiUmF3IEFQSSBjYXBhYmlsaXRpZXMgcmVzcG9uc2UgZm9yIHtjb21wYW55X25hbWV9OiB7cmVzcG9uc2V9IikNCiAgICBmb3IgbGluZSBpbiByZXNwb25zZS5zcGxpdCgnXG4nKToNCiAgICAgICAgZm9yIGNhcGFiaWxpdHkgaW4gdmFsaWRfY2FwYWJpbGl0aWVzOg0KICAgICAgICAgICAgaWYgY2FwYWJpbGl0eS5sb3dlcigpIGluIGxpbmUubG93ZXIoKSBhbmQgY2FwYWJpbGl0eSBub3QgaW4gY2FwYWJpbGl0aWVzOg0KICAgICAgICAgICAgICAgIGNhcGFiaWxpdGllcy5hcHBlbmQoY2FwYWJpbGl0eSkNCiAgICAgICAgICAgICAgICBicmVhaw0KICAgIHZhbGlkYXRlZF9jYXBhYmlsaXRpZXMgPSBlbnN1cmVfdW5pcXVlX2NhcGFiaWxpdGllcyhjYXBhYmlsaXRpZXMpDQogICAgbG9nZ2luZy5kZWJ1ZyhmIlZhbGlkYXRlZCBjYXBhYmlsaXRpZXMgZm9yIHtjb21wYW55X25hbWV9OiB7dmFsaWRhdGVkX2NhcGFiaWxpdGllc30iKQ0KICAgIHJldHVybiB2YWxpZGF0ZWRfY2FwYWJpbGl0aWVzDQoNCiMgRnVuY3Rpb24gdG8gcHJvY2VzcyBlYWNoIGNvbXBhbnkgYW5kIGNvbHVtbg0KZGVmIHByb2Nlc3NfY29tcGFueV9jb2x1bW4oY29tcGFueV9pbmZvLCB3ZWJwYWdlX2NvbnRlbnQpOg0KICAgIGJhc2VfcHJvbXB0ID0gZiJDb21wYW55IExpbmtlZEluIEluZm86XG57Y29tcGFueV9pbmZvfVxuXG5Db21wYW55IFdlYnBhZ2UgQ29udGVudDpcbnt3ZWJwYWdlX2NvbnRlbnR9XG5cbiINCiAgICBjYXBhYmlsaXRpZXNfbGlzdCA9ICcsICcuam9pbih2YWxpZF9jYXBhYmlsaXRpZXMpDQoNCiAgICAjIENvbnN0cnVjdGluZyBtb3JlIGRldGFpbGVkIHByb21wdHMgd2l0aCBhZGRpdGlvbmFsIGNvbnRleHQNCiAgICBwcm9tcHRzID0gew0KICAgICAgICAnT3BlbmVkWCBDb25uZWN0aW9uJzogYmFzZV9wcm9tcHQgKyAiVGFraW5nIGludG8gYWNjb3VudCB0aGUgaW5mb3JtYXRpb24gcHJvdmlkZWQgYW5kIHlvdXIga25vd2xlZGdlIGFib3V0IHRoZSBjb21wYW55LCBkb2VzIHRoZSBjb21wYW55IGhhdmUgYW55IGNvbm5lY3Rpb24gb3IgdXNlIHRoZSBPcGVuIGVkWCBwbGF0Zm9ybT8iLA0KICAgICAgICAnTWFpbiBQcm9kdWN0JzogYmFzZV9wcm9tcHQgKyAiVGFraW5nIGludG8gYWNjb3VudCB0aGUgaW5mb3JtYXRpb24gcHJvdmlkZWQgYW5kIHlvdXIga25vd2xlZGdlIGFib3V0IHRoZSBjb21wYW55LCB3aGF0IGlzIHRoZSBtYWluIHByb2R1Y3Qgb3Igc2VydmljZSB0aGUgY29tcGFueSBvZmZlcnM/IiwNCiAgICAgICAgJ0NvbXBldGl0b3JzJzogYmFzZV9wcm9tcHQgKyAiVGFraW5nIGludG8gYWNjb3VudCB0aGUgaW5mb3JtYXRpb24gcHJvdmlkZWQgYW5kIHlvdXIga25vd2xlZGdlIGFib3V0IHRoZSBjb21wYW55LCBsaXN0IHRocmVlIG1haW4gY29tcGV0aXRvcnMgb2YgdGhlIGNvbXBhbnkgaW5jbHVkaW5nIHRoZWlyIG5hbWVzIGFuZCB3ZWJzaXRlcy4iLA0KICAgICAgICAnQ3VzdG9tZXJzJzogYmFzZV9wcm9tcHQgKyAiVGFraW5nIGludG8gYWNjb3VudCB0aGUgaW5mb3JtYXRpb24gcHJvdmlkZWQgYW5kIHlvdXIga25vd2xlZGdlIGFib3V0IHRoZSBjb21wYW55LCBsaXN0IHRocmVlIG1haW4gY3VzdG9tZXJzIG9mIHRoZSBjb21wYW55LiIsDQogICAgICAgICdCMkIgb3IgQjJDJzogYmFzZV9wcm9tcHQgKyAiVGFraW5nIGludG8gYWNjb3VudCB0aGUgaW5mb3JtYXRpb24gcHJvdmlkZWQgYW5kIHlvdXIga25vd2xlZGdlIGFib3V0IHRoZSBjb21wYW55LCBpcyB0aGUgY29tcGFueSBwcmltYXJpbHkgZm9jdXNlZCBvbiBCMkIgKGJ1c2luZXNzLXRvLWJ1c2luZXNzKSBvciBCMkMgKGJ1c2luZXNzLXRvLWNvbnN1bWVyKSBvcGVyYXRpb25zPyIsDQogICAgICAgICdOdW1iZXIgb2YgQ3VzdG9tZXJzJzogYmFzZV9wcm9tcHQgKyAiVGFraW5nIGludG8gYWNjb3VudCB0aGUgaW5mb3JtYXRpb24gcHJvdmlkZWQgYW5kIHlvdXIga25vd2xlZGdlIGFib3V0IHRoZSBjb21wYW55LCBlc3RpbWF0ZSB0aGUgbnVtYmVyIG9mIGN1c3RvbWVycyB0aGUgY29tcGFueSBoYXMuIiwNCiAgICAgICAgJ0NvdW50cnknOiBiYXNlX3Byb21wdCArICJUYWtpbmcgaW50byBhY2NvdW50IHRoZSBpbmZvcm1hdGlvbiBwcm92aWRlZCBhbmQgeW91ciBrbm93bGVkZ2UgYWJvdXQgdGhlIGNvbXBhbnksIGluIHdoaWNoIGNvdW50cnkgZG9lcyB0aGUgY29tcGFueSBwcmltYXJpbHkgb3BlcmF0ZT8iLA0KICAgICAgICAnUG90ZW50aWFsIFJvbGUnOiBiYXNlX3Byb21wdCArICJUYWtpbmcgaW50byBhY2NvdW50IHRoZSBpbmZvcm1hdGlvbiBwcm92aWRlZCBhbmQgeW91ciBrbm93bGVkZ2UgYWJvdXQgdGhlIGNvbXBhbnksIGRldGVybWluZSBpZiB0aGUgY29tcGFueSBpcyBhIHBvdGVudGlhbCBjbGllbnQsIHBhcnRuZXIsIGNvbXBldGl0b3IsIG9yIHByb3ZpZGVyIGZvciBFZHVuZXh0LiIsDQogICAgICAgICdQb3RlbnRpYWwgVmVydGljYWwnOiBiYXNlX3Byb21wdCArICJUYWtpbmcgaW50byBhY2NvdW50IHRoZSBpbmZvcm1hdGlvbiBwcm92aWRlZCBhbmQgeW91ciBrbm93bGVkZ2UgYWJvdXQgdGhlIGNvbXBhbnksIGRldGVybWluZSB0aGUgcG90ZW50aWFsIHZlcnRpY2FsIGZvciB0aGUgY29tcGFueSBmcm9tIHRoZSBmb2xsb3dpbmcgbGlzdDpcbiIgKw0KICAgICAgICAgICAgJ1xuJy5qb2luKFtmIntyb3dbJ1ZlcnRpY2FsJ119IC0ge3Jvd1snRGVmaW5pdGlvbiddfSIgZm9yIF8sIHJvdyBpbiB2ZXJ0aWNhbF9kYXRhLml0ZXJyb3dzKCldKSArICJcbldoYXQgaXMgdGhlIHBvdGVudGlhbCB2ZXJ0aWNhbCBvZiB0aGlzIGNvbXBhbnk/IiwNCiAgICAgICAgJ0NhcGFiaWxpdHkgMSc6IGJhc2VfcHJvbXB0ICsgZiJCYXNlZCBvbiB0aGUgcHJvdmlkZWQgaW5mb3JtYXRpb24gYW5kIGFueSBhZGRpdGlvbmFsIHJlc2VhcmNoLCB3aGF0IGlzIHRoZSBwcmltYXJ5IGNhcGFiaWxpdHkgb2YgdGhlIGNvbXBhbnk/IENob29zZSBmcm9tIHRoZSBmb2xsb3dpbmc6IHtjYXBhYmlsaXRpZXNfbGlzdH0iLA0KICAgICAgICAnQ2FwYWJpbGl0eSAyJzogYmFzZV9wcm9tcHQgKyBmIkNvbnNpZGVyaW5nIHRoZSBjYXBhYmlsaXRpZXMgYWxyZWFkeSBtZW50aW9uZWQsIHdoYXQgaXMgdGhlIHNlY29uZCBtYWluIGNhcGFiaWxpdHkgb2YgdGhlIGNvbXBhbnk/IENob29zZSBmcm9tIHRoZSBmb2xsb3dpbmc6IHtjYXBhYmlsaXRpZXNfbGlzdH0iLA0KICAgICAgICAnQ2FwYWJpbGl0eSAzJzogYmFzZV9wcm9tcHQgKyBmIkNvbnNpZGVyaW5nIHRoZSBjYXBhYmlsaXRpZXMgYWxyZWFkeSBtZW50aW9uZWQsIHdoYXQgaXMgdGhlIHRoaXJkIG1haW4gY2FwYWJpbGl0eSBvZiB0aGUgY29tcGFueT8gQ2hvb3NlIGZyb20gdGhlIGZvbGxvd2luZzoge2NhcGFiaWxpdGllc19saXN0fSIsDQogICAgICAgICdDYXBhYmlsaXR5IDQnOiBiYXNlX3Byb21wdCArIGYiQ29uc2lkZXJpbmcgdGhlIGNhcGFiaWxpdGllcyBhbHJlYWR5IG1lbnRpb25lZCwgd2hhdCBpcyB0aGUgZm91cnRoIG1haW4gY2FwYWJpbGl0eSBvZiB0aGUgY29tcGFueT8gQ2hvb3NlIGZyb20gdGhlIGZvbGxvd2luZzoge2NhcGFiaWxpdGllc19saXN0fSIsDQogICAgICAgICdDYXBhYmlsaXR5IDUnOiBiYXNlX3Byb21wdCArIGYiQ29uc2lkZXJpbmcgdGhlIGNhcGFiaWxpdGllcyBhbHJlYWR5IG1lbnRpb25lZCwgd2hhdCBpcyB0aGUgZmlmdGggbWFpbiBjYXBhYmlsaXR5IG9mIHRoZSBjb21wYW55PyBDaG9vc2UgZnJvbSB0aGUgZm9sbG93aW5nOiB7Y2FwYWJpbGl0aWVzX2xpc3R9Ig0KICAgIH0NCiAgICANCiAgICByZXNwb25zZXMgPSB7a2V5OiBxdWVyeV9vcGVuYWlfYXBpKHByb21wdCkgZm9yIGtleSwgcHJvbXB0IGluIHByb21wdHMuaXRlbXMoKX0NCg0KICAgICMgTG9nIHJhdyByZXNwb25zZXMgZm9yIGRlYnVnZ2luZw0KICAgIGxvZ2dpbmcuZGVidWcoZiJSYXcgQVBJIHJlc3BvbnNlIGZvciBjb21wYW55IHtjb21wYW55X2luZm9bJ0NvbXBhbnkgTmFtZSddfToge3Jlc3BvbnNlc30iKQ0KDQogICAgIyBFeHRyYWN0IGFuZCB2YWxpZGF0ZSBjYXBhYmlsaXRpZXMNCiAgICBjYXBhYmlsaXRpZXMgPSBleHRyYWN0X2FuZF92YWxpZGF0ZV9jYXBhYmlsaXRpZXMoIlxuIi5qb2luKFtyZXNwb25zZXMuZ2V0KGYnQ2FwYWJpbGl0eSB7aX0nLCAnJykgZm9yIGkgaW4gcmFuZ2UoMSwgNildKSwgY29tcGFueV9pbmZvWydDb21wYW55IE5hbWUnXSkNCg0KICAgIG91dHB1dF9yb3cgPSB7DQogICAgICAgICdDb21wYW55IE5hbWUnOiBjb21wYW55X2luZm9bJ0NvbXBhbnkgTmFtZSddLA0KICAgICAgICAnVVJMIChMaW5rZWRJbiBwcm9maWxlIGxpbmspJzogY29tcGFueV9pbmZvWydVUkwnXSwNCiAgICAgICAgJ1dlYnNpdGUnOiBjb21wYW55X2luZm9bJ1dlYnNpdGUnXSwNCiAgICAgICAgJ09wZW5lZFggQ29ubmVjdGlvbic6IHJlc3BvbnNlc1snT3BlbmVkWCBDb25uZWN0aW9uJ10sDQogICAgICAgICdNYWluIFByb2R1Y3QnOiByZXNwb25zZXNbJ01haW4gUHJvZHVjdCddLA0KICAgICAgICAnQ29tcGV0aXRvcnMnOiByZXNwb25zZXNbJ0NvbXBldGl0b3JzJ10sDQogICAgICAgICdDdXN0b21lcnMnOiByZXNwb25zZXNbJ0N1c3RvbWVycyddLA0KICAgICAgICAnQjJCIG9yIEIyQyc6ICJCMkIiIGlmICJCMkIiIGluIHJlc3BvbnNlc1snQjJCIG9yIEIyQyddIGVsc2UgIkIyQyIsDQogICAgICAgICdOdW1iZXIgb2YgQ3VzdG9tZXJzJzogcmVzcG9uc2VzWydOdW1iZXIgb2YgQ3VzdG9tZXJzJ10sDQogICAgICAgICdDb3VudHJ5JzogcmVzcG9uc2VzWydDb3VudHJ5J10uc3RyaXAoKSwNCiAgICAgICAgJ1BvdGVudGlhbCBSb2xlJzogY2F0ZWdvcml6ZV9wb3RlbnRpYWxfcm9sZShyZXNwb25zZXNbJ1BvdGVudGlhbCBSb2xlJ10pLA0KICAgICAgICAnUG90ZW50aWFsIFZlcnRpY2FsJzogY2F0ZWdvcml6ZV9wb3RlbnRpYWxfdmVydGljYWwocmVzcG9uc2VzWydQb3RlbnRpYWwgVmVydGljYWwnXSksDQogICAgICAgICdDYXBhYmlsaXR5IDEnOiBjYXBhYmlsaXRpZXNbMF0sDQogICAgICAgICdDYXBhYmlsaXR5IDInOiBjYXBhYmlsaXRpZXNbMV0sDQogICAgICAgICdDYXBhYmlsaXR5IDMnOiBjYXBhYmlsaXRpZXNbMl0sDQogICAgICAgICdDYXBhYmlsaXR5IDQnOiBjYXBhYmlsaXRpZXNbM10sDQogICAgICAgICdDYXBhYmlsaXR5IDUnOiBjYXBhYmlsaXRpZXNbNF0NCiAgICB9DQoNCiAgICByZXR1cm4gb3V0cHV0X3Jvdw0KDQojIEZ1bmN0aW9uIHRvIHNhdmUgcHJvZ3Jlc3MgcGVyaW9kaWNhbGx5DQpkZWYgc2F2ZV9wcm9ncmVzcyhkYXRhLCBmaWxlbmFtZT0nY29tcGFueV9hbmFseXNpc19iYWNrdXAueGxzeCcpOg0KICAgIGRmID0gcGQuRGF0YUZyYW1lKGRhdGEsIGNvbHVtbnM9b3V0cHV0X2NvbHVtbnMpDQogICAgZGYudG9fZXhjZWwoZmlsZW5hbWUsIGluZGV4PUZhbHNlKQ0KICAgIGxvZ2dpbmcuaW5mbyhmIlByb2dyZXNzIHNhdmVkIHRvIHtmaWxlbmFtZX0iKQ0KDQojIFByb2Nlc3MgY29tcGFuaWVzIHNlcXVlbnRpYWxseSB3aXRoIGxvZ2dpbmcNCnJlc3VsdHMgPSBbXQ0KZm9yIGlkeCwgcm93IGluIGxpbmtlZEluX2RhdGEuaXRlcnJvd3MoKToNCiAgICBjb21wYW55X2luZm8gPSByb3cudG9fZGljdCgpDQogICAgY29tcGFueV9uYW1lID0gY29tcGFueV9pbmZvWydDb21wYW55IE5hbWUnXQ0KICAgIGxvZ2dpbmcuaW5mbyhmIlByb2Nlc3NpbmcgY29tcGFueToge2NvbXBhbnlfbmFtZX0iKQ0KDQogICAgdHJ5Og0KICAgICAgICAjIFRyeSB0byByZWFkIHRoZSB3ZWJwYWdlIGNvbnRlbnQgZm9yIHRoZSBjb21wYW55LCBoYW5kbGUgbWlzc2luZyBvciBpbnZhbGlkIGZpbGVzDQogICAgICAgIHdlYnBhZ2VfY29udGVudCA9ICIiDQogICAgICAgIGZpbGVwYXRoID0gb3MucGF0aC5qb2luKCd3ZWJwYWdlcycsIGYie2NvbXBhbnlfbmFtZX0udHh0IikNCiAgICAgICAgdHJ5Og0KICAgICAgICAgICAgd2l0aCBvcGVuKGZpbGVwYXRoLCAncicsIGVuY29kaW5nPSd1dGYtOCcpIGFzIGZpbGU6DQogICAgICAgICAgICAgICAgd2VicGFnZV9jb250ZW50ID0gZmlsZS5yZWFkKCkNCiAgICAgICAgZXhjZXB0IChGaWxlTm90Rm91bmRFcnJvciwgT1NFcnJvcikgYXMgZToNCiAgICAgICAgICAgIGxvZ2dpbmcud2FybmluZyhmIkNvdWxkIG5vdCByZWFkIGZpbGUgZm9yIHtjb21wYW55X25hbWV9OiB7ZX0iKQ0KICAgICAgICANCiAgICAgICAgb3V0cHV0X3JvdyA9IHByb2Nlc3NfY29tcGFueV9jb2x1bW4oY29tcGFueV9pbmZvLCB3ZWJwYWdlX2NvbnRlbnQpDQogICAgICAgIHJlc3VsdHMuYXBwZW5kKG91dHB1dF9yb3cpDQogICAgICAgIGxvZ2dpbmcuaW5mbyhmIkNvbXBsZXRlZCBwcm9jZXNzaW5nIGZvciB7Y29tcGFueV9uYW1lfSAoe2lkeCArIDF9L3tsZW4obGlua2VkSW5fZGF0YSl9KSIpDQogICAgICAgIA0KICAgICAgICAjIFNhdmUgcHJvZ3Jlc3MgcGVyaW9kaWNhbGx5DQogICAgICAgIGlmIChpZHggKyAxKSAlIGJhY2t1cF9pbnRlcnZhbCA9PSAwOg0KICAgICAgICAgICAgc2F2ZV9wcm9ncmVzcyhyZXN1bHRzKQ0KDQogICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOg0KICAgICAgICBsb2dnaW5nLmVycm9yKGYiRXJyb3IgcHJvY2Vzc2luZyBjb21wYW55IHtjb21wYW55X25hbWV9OiB7ZX0iKQ0KDQojIFNhdmUgZmluYWwgcmVzdWx0cw0Kb3V0cHV0X2RhdGEgPSBwZC5EYXRhRnJhbWUocmVzdWx0cywgY29sdW1ucz1vdXRwdXRfY29sdW1ucykNCm91dHB1dF9kYXRhLnRvX2V4Y2VsKCdjb21wYW55X2FuYWx5c2lzLnhsc3gnLCBpbmRleD1GYWxzZSkNCmxvZ2dpbmcuaW5mbygiQWxsIGNvbXBhbmllcyBwcm9jZXNzZWQgYW5kIHNhdmVkIHRvIGNvbXBhbnlfYW5hbHlzaXMueGxzeCIpDQogIDwvY29kZT48L3ByZT4NCg0KPC9kaXY+DQoNCjwhLS0gSW5jbHVkZSBQcmlzbS5qcyAtLT4NCjxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9wcmlzbS8xLjI1LjAvcHJpc20ubWluLmpzIj48L3NjcmlwdD4NCjxzY3JpcHQgc3JjPSJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9wcmlzbS8xLjI1LjAvY29tcG9uZW50cy9wcmlzbS1weXRob24ubWluLmpzIj48L3NjcmlwdD4NCjwvYm9keT4NCjwvaHRtbD4NCg0KKioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZTlmNWRiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij48Yj4gQ29tcGFueSBJbmZvcm1hdGlvbiBPdXRwdXQ8L2I+PC9zcGFuPg0KPC9wPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgZm91cnRoIG91dHB1dCBpcyBjYWxsZWQgIkNvbXBhbnkgSW5mb3JtYXRpb24gT3V0cHV0IiBhbmQgY29udGFpbnMgZGV0YWlsZWQgaW5mb3JtYXRpb24gYWJvdXQgdmFyaW91cyBhbmFseXplZCBjb21wYW5pZXMuIEJlbG93IGlzIGFuIGV4YW1wbGUgb2YgdGhlIGRhdGEgY29sbGVjdGVkOg0KPC9wPg0KDQo8dGFibGUgc3R5bGU9IndpZHRoOjEwMCU7IGJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkNvbXBhbnkgTmFtZTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5ieXRlWEw8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+VVJMIChMaW5rZWRJbiBwcm9maWxlIGxpbmspPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPjxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbXBhbnkvYnl0ZXhsIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vY29tcGFueS9ieXRleGw8L2E+PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPldlYnNpdGU8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+PGEgaHJlZj0iaHR0cHM6Ly9ieXRleGwuY29tIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9ieXRleGwuY29tPC9hPjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5PcGVuZWRYIENvbm5lY3Rpb248L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+QmFzZWQgb24gdGhlIGluZm9ybWF0aW9uIHByb3ZpZGVkLCB0aGVyZSBpcyBubyBkaXJlY3QgbWVudGlvbiBvZiB0aGUgY29tcGFueSBieXRlWEwgdXNpbmcgb3IgaGF2aW5nIGEgY29ubmVjdGlvbiB3aXRoIHRoZSBPcGVuIGVkWCBwbGF0Zm9ybS4gVGhlIGNvbXBhbnkncyBmb2N1cyBzZWVtcyB0byBiZSBvbiB0cmFuc2Zvcm1pbmcgZW5naW5lZXJpbmcgY29sbGVnZXMgaW4gSW5kaWEgdGhyb3VnaCB0aGVpciBvd24gaW50ZWdyYXRlZCBjb2xsZWdlIHRyYW5zZm9ybWF0aW9uIG1vZGVsIGFuZCBwcm9wcmlldGFyeSBwbGF0Zm9ybSwgcmF0aGVyIHRoYW4gdXRpbGl6aW5nIGV4dGVybmFsIHBsYXRmb3JtcyBsaWtlIE9wZW4gZWRYLjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5NYWluIFByb2R1Y3Q8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+QmFzZWQgb24gdGhlIGluZm9ybWF0aW9uIHByb3ZpZGVkIGZyb20gdGhlIGNvbXBhbnkncyBMaW5rZWRJbiBwcm9maWxlIGFuZCB3ZWJwYWdlIGNvbnRlbnQsIHRoZSBtYWluIHByb2R1Y3Qgb3Igc2VydmljZSBvZmZlcmVkIGJ5IGJ5dGVYTCBpcyBhbiBleHBlcmllbnRpYWwgbGVhcm5pbmcgb25saW5lIHBsYXRmb3JtIGZvciBJVCBwcm9ncmFtbWluZyBhc3BpcmFudHMuIFRoaXMgcGxhdGZvcm0gaW50ZWdyYXRlcyBjdXJyaWN1bHVtLCBjb250ZW50LCBhbmQgcHJhY3RpY2FsIGxlYXJuaW5nIHRvIGVuaGFuY2Ugc3R1ZGVudHMnIHNraWxscyBhbmQgYXdhcmVuZXNzIG9uIGVtcGxveWFiaWxpdHkuIFRoZSBjb21wYW55IHBhcnRuZXJzIHdpdGggY29sbGVnZXMgdG8gdHJhbnNmb3JtIHRoZWlyIHRlYWNoaW5nIG1ldGhvZG9sb2d5IGFuZCBsZWFybmluZyBwZWRhZ29neSB0byBpbmNyZWFzZSB0aGUgZW1wbG95YWJpbGl0eSBxdW90aWVudCBvZiB0aGVpciBzdHVkZW50cy4gVGhlIHBsYXRmb3JtIGluY2x1ZGVzIGZlYXR1cmVzIHN1Y2ggYXMgYWNhZGVtaWMgJiBza2lsbGluZyBjb250ZW50LCBvbmxpbmUgZWRpdG9yLCBzdHVkZW50IHJlcG9ydHMsIGRhc2hib2FyZHMgb24gaW5kaXZpZHVhbCBjb2xsZWdlIHBlcmZvcm1hbmNlLCBhbmQgY29kaW5nIGNoYWxsZW5nZXMuPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkNvbXBldGl0b3JzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPkJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvbiBwcm92aWRlZCBhYm91dCBieXRlWEwsIHRocmVlIG1haW4gY29tcGV0aXRvcnMgb2YgdGhlIGNvbXBhbnkgaW4gdGhlIEUtbGVhcm5pbmcgaW5kdXN0cnkgY291bGQgYmU6PGJyPjxicj4xLiBDb21wYW55IE5hbWU6IFVwR3JhZDxicj5XZWJzaXRlOiA8YSBocmVmPSJodHRwczovL3d3dy51cGdyYWQuY29tLyIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vd3d3LnVwZ3JhZC5jb20vPC9hPjxicj48YnI+Mi4gQ29tcGFueSBOYW1lOiBTaW1wbGlsZWFybjxicj5XZWJzaXRlOiA8YSBocmVmPSJodHRwczovL3d3dy5zaW1wbGlsZWFybi5jb20vIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly93d3cuc2ltcGxpbGVhcm4uY29tLzwvYT48YnI+PGJyPjMuIENvbXBhbnkgTmFtZTogQ291cnNlcmE8YnI+V2Vic2l0ZTogPGEgaHJlZj0iaHR0cHM6Ly93d3cuY291cnNlcmEub3JnLyIgdGFyZ2V0PSJfYmxhbmsiPmh0dHBzOi8vd3d3LmNvdXJzZXJhLm9yZy88L2E+PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkN1c3RvbWVyczwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5CYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gcHJvdmlkZWQsIHRocmVlIG1haW4gY3VzdG9tZXJzIG9mIGJ5dGVYTCBhcmU6PGJyPjxicj4xLiBUZWphc2hyaSBTdHVkZW50IGZyb20gTWFsaW5lbmkgTGFrc2htYWlhaCBXb21lbuKAmXMgRW5naW5lZXJpbmcgQ29sbGVnZTxicj48YnI+Mi4gQS4gU2FueWFzaXJhbywgSGVhZCBvZiBFbGVjdHJvbmljcyAmIENvbW11bmljYXRpb24gRW5naW5lZXJpbmcgRGVwYXJ0bWVudCBhdCBDaHJpc3R1IEp5b3RoaSBJbnN0aXR1dGUgb2YgVGVjaG5vbG9neSAmIFNjaWVuY2U8YnI+PGJyPjMuIEthbHlhbmksIGEgc3R1ZGVudCBvZiBNYWxpbmVuaSBMYWtzaG1haWFoIFdvbWVuJ3MgRW5naW5lZXJpbmcgQ29sbGVnZTxicj48YnI+VGhlc2UgY3VzdG9tZXJzIGhhdmUgc2hhcmVkIHRoZWlyIHBvc2l0aXZlIGV4cGVyaWVuY2VzIHdpdGggYnl0ZVhMJ3MgdGVhY2hpbmcgbWV0aG9kb2xvZ3kgYW5kIGl0cyBpbXBhY3Qgb24gdGhlaXIgYWNhZGVtaWMgam91cm5leSBhbmQgY2FyZWVyIHByb3NwZWN0cy48L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+QjJCIG9yIEIyQzwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5CMkI8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+TnVtYmVyIG9mIEN1c3RvbWVyczwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5CYXNlZCBvbiB0aGUgY29udGVudCBwcm92aWRlZCwgaXQgc2VlbXMgbGlrZSBieXRlWEwgaGFzIHNldmVyYWwgY3VzdG9tZXJzIHdobyBhcmUgc3R1ZGVudHMgYW5kIGNvbGxlZ2VzIGFjcm9zcyBJbmRpYS4gVGhlIHdlYnBhZ2UgY29udGVudCBtZW50aW9ucyB0ZXN0aW1vbmlhbHMgYW5kIHN1Y2Nlc3Mgc3RvcmllcyBmcm9tIHN0dWRlbnRzIGFuZCBmYWN1bHR5IGF0IHZhcmlvdXMgZW5naW5lZXJpbmcgY29sbGVnZXMgd2hvIGhhdmUgYmVuZWZpdGVkIGZyb20gYnl0ZVhMJ3MgdHJhaW5pbmcgYW5kIG1lbnRvcnNoaXAgcHJvZ3JhbXMuPGJyPjxicj5XaGlsZSB0aGUgZXhhY3QgbnVtYmVyIG9mIGN1c3RvbWVycyBpcyBub3QgZXhwbGljaXRseSBtZW50aW9uZWQgaW4gdGhlIGRhdGEgcHJvdmlkZWQsIHdlIGNhbiBpbmZlciB0aGF0IHRoZSBjb21wYW55IGhhcyBhIHNpZ25pZmljYW50IGN1c3RvbWVyIGJhc2UgYWNyb3NzIG11bHRpcGxlIGNvbGxlZ2VzIGFuZCBpbmRpdmlkdWFsIHN0dWRlbnRzLiBUaGUgdGVzdGltb25pYWxzIGFuZCBzdWNjZXNzIHN0b3JpZXMgaGlnaGxpZ2h0IHRoZSBpbXBhY3QgYnl0ZVhMIGhhcyBoYWQgb24gc3R1ZGVudHMnIGFjYWRlbWljIGpvdXJuZXlzIGFuZCBjYXJlZXIgcGF0aHMsIGluZGljYXRpbmcgYSB3aWRlIHJlYWNoIGFuZCBwb3NpdGl2ZSByZXB1dGF0aW9uIGFtb25nIGN1c3RvbWVycy48YnI+PGJyPlRoZXJlZm9yZSwgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uIGF2YWlsYWJsZSwgd2UgY2FuIGVzdGltYXRlIHRoYXQgYnl0ZVhMIGxpa2VseSBoYXMgaHVuZHJlZHMgb3IgZXZlbiB0aG91c2FuZHMgb2YgY3VzdG9tZXJzIGNvbnNpc3Rpbmcgb2YgYm90aCBjb2xsZWdlcyBhbmQgaW5kaXZpZHVhbCBzdHVkZW50cyB3aG8gaGF2ZSBlbmdhZ2VkIHdpdGggdGhlaXIgZWR1Y2F0aW9uYWwgcHJvZ3JhbXMgYW5kIHNlcnZpY2VzLjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5Db3VudHJ5PC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPlRoZSBjb21wYW55LCBieXRlWEwsIHByaW1hcmlseSBvcGVyYXRlcyBpbiBJbmRpYS4gVGhpcyBpcyBpbmRpY2F0ZWQgYnkgdGhlIGNvbXBhbnkncyBoZWFkcXVhcnRlcnMgYmVpbmcgaW4gSHlkZXJhYmFkLCBJbmRpYSwgdGhlIGZvY3VzIG9uIHRyYW5zZm9ybWluZyBlbmdpbmVlcmluZyBjb2xsZWdlcyBpbiBJbmRpYSwgcGFydG5lcnNoaXBzIHdpdGggSW5kaWFuIGNvbGxlZ2VzIHN1Y2ggYXMgTWFsaW5lbmkgTGFrc2htYWlhaCBXb21lbuKAmXMgRW5naW5lZXJpbmcgQ29sbGVnZSBhbmQgQ2hyaXN0dSBKeW90aGkgSW5zdGl0dXRlIG9mIFRlY2hub2xvZ3kgJiBTY2llbmNlLCBhbmQgdGhlIHRlc3RpbW9uaWFscyBhbmQgc3VjY2VzcyBzdG9yaWVzIGZyb20gSW5kaWFuIHN0dWRlbnRzIGFuZCBlZHVjYXRpb25hbCBpbnN0aXR1dGlvbnMuIFRoZSBjb21wYW55J3MgZWZmb3J0cyBhbmQgaW1wYWN0IGFyZSBjZW50ZXJlZCBhcm91bmQgdGhlIEluZGlhbiBlZHVjYXRpb24gc3lzdGVtIGFuZCBpbmR1c3RyeSwgc3VwcG9ydGluZyB0aGUgZW1wbG95YWJpbGl0eSBhbmQgc2tpbGxzIGRldmVsb3BtZW50IG9mIEluZGlhbiBlbmdpbmVlcmluZyBzdHVkZW50cy48L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+Q291bnRyeSBPbmx5PC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPkluZGlhPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPlBvdGVudGlhbCBSb2xlPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPkNMSUVOVDwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5Qb3RlbnRpYWwgVmVydGljYWw8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+SGlnaGVyIEVkdWNhdGlvbjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5DYXBhYmlsaXR5IDE8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+UEVSU09OQUxJWkVEICYgQURBUFRJVkUgTEVBUk5JTkc8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+Q2FwYWJpbGl0eSAyPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPldPUktQTEFDRSBTSU1VTEFUSU9OICYgUFJPSkVDVFM8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjBmMGYwOyI+Q2FwYWJpbGl0eSAzPC90ZD4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsiPklNTUVSU0lPTiwgU0lNVUxBVElPTiAmIExBQjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgc3R5bGU9ImJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDhweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQtY29sb3I6ICNmMGYwZjA7Ij5DYXBhYmlsaXR5IDQ8L3RkPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyI+Vk9MVU5URUVSSU5HICYgU1RVREVOVCBMRUFERVJTSElQPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgI2RkZDsgcGFkZGluZzogOHB4OyBmb250LXdlaWdodDogYm9sZDsgYmFja2dyb3VuZC1jb2xvcjogI2YwZjBmMDsiPkNhcGFiaWxpdHkgNTwvdGQ+DQogICAgPHRkIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjZGRkOyBwYWRkaW5nOiA4cHg7Ij5ESUdJVEFMIERFU0lHTiBQUklOQ0lQTEVTPC90ZD4NCiAgPC90cj4NCjwvdGFibGU+DQoNCioqKioqDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB5b3UgY2FuIHJlZmVyIHRvIHRoZSBjb21wbGV0ZSBkYXRhc2V0IDxhIGhyZWY9Imh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFVdEszdE1xbXVrUkVCb1B2THhJQ285enQxcml6YnRiNDFRX3JlaFRoNFVvL2VkaXQ/Z2lkPTE1OTE2Mzg0NDAjZ2lkPTE1OTE2Mzg0NDAiIHRhcmdldD0iX2JsYW5rIj5oZXJlPC9hPi4NCjwvcD4NCg0KDQo8YSBpZD0iYW5hbHlzaXMtcmVzdWx0cyI+PC9hPg0KDQoqKioNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMjJweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGNlbnRlcjsgbWFyZ2luLWJvdHRvbTogMjBweDsiPg0KICA8Yj48c3BhbiBzdHlsZT0iY29sb3I6ICM5MzgxZmY7IGZvbnQtc2l6ZTogMjZweDsiPiB8PC9zcGFuPiBBbmFseXNpcyBhbmQgUmVzdWx0czwvYj4NCjwvcD4NCg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpXaXRoIHRoZSBkYXRhIHJlc3VsdGluZyBmcm9tIHRoaXMgZXhlcmNpc2UsIHRoZSBhbmFseXNpcyBiZWdpbnMgd2l0aCBnZW9ncmFwaGljYWwgaW5zaWdodHMuIFRoZSBmaXJzdCBwYXJ0IHdpbGwgZm9jdXMgb24gdGhlIG51bWJlciBvZiBzdGFydHVwcyBieSBjb3VudHJ5LCB3aGlsZSB0aGUgc2Vjb25kIHBhcnQgd2lsbCBhbmFseXplIHRoZSBhbW91bnQgb2YgaW52ZXN0bWVudC4gVGhlIGdlb2dyYXBoaWNhbCBsb2NhdGlvbiBpbiB0aGVzZSBjaGFydHMgaXMgcHJvdmlkZWQgYnkgTGlua2VkSW4sIGluZGljYXRpbmcgd2hlcmUgdGhlIGNvbXBhbnkgaXMgYmFzZWQsIGFuZCB0aGUgaW52ZXN0bWVudCBkYXRhIGFsc28gY29tZXMgZnJvbSBMaW5rZWRJbiBpbmZvcm1hdGlvbiBpbiBjb25qdW5jdGlvbiB3aXRoIENydW5jaGJhc2UuIEl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgbm90IGFsbCBjb21wYW5pZXMgaGF2ZSB0aGlzIGluZm9ybWF0aW9uIGF2YWlsYWJsZSwgYW5kIG5vdCBhbGwgaW52ZXN0bWVudHMgd2VyZSBtYWRlIGluIHRoaXMgb3IgdGhlIHBhc3QgeWVhci4gVG8gdmVyaWZ5IHRoZSBkYXRlIG9mIGludmVzdG1lbnQgYnkgY29tcGFueSwgdGhpcyBsaW5rIGNhbiBiZSBjb25zdWx0ZWQ6DQpbSW52ZXN0bWVudCBEYXRlIFZlcmlmaWNhdGlvbl0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVV0SzN0TXFtdWtSRUJvUHZMeElDbzl6dDFyaXpidGI0MVFfcmVoVGg0VW8vZWRpdD9naWQ9MTA0NTE5NTg4MiNnaWQ9MTA0NTE5NTg4MikNCjwvcD4NCg0KDQojIyMjICB7LnRhYnNldH0NCg0KDQojIyMjIyBOdW1iZXIgb2Ygc3RhcnR1cHMNCg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgZmlyc3QgbWFwIHByb3ZpZGVzIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBudW1iZXIgb2Ygc3RhcnR1cHMgYnkgY291bnRyeSBiYXNlZCBvbiBkYXRhIHNvdXJjZWQgZnJvbSBMaW5rZWRJbi4gVGhlIG1hcCB1c2VzIGEgZ3JhZGllbnQgY29sb3Igc2NhbGUgdG8gaW5kaWNhdGUgdGhlIGRlbnNpdHkgb2Ygc3RhcnR1cHMgaW4gZWFjaCBjb3VudHJ5LCB3aXRoIGxpZ2h0ZXIgc2hhZGVzIG9mIGJsdWUgcmVwcmVzZW50aW5nIGZld2VyIHN0YXJ0dXBzIGFuZCBkYXJrZXIgc2hhZGVzIG9mIGJsdWUgaW5kaWNhdGluZyBhIGhpZ2hlciBudW1iZXIgb2Ygc3RhcnR1cHMuDQo8L3A+DQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCiMgTG9hZCB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHJuYXR1cmFsZWFydGgpDQpsaWJyYXJ5KHJuYXR1cmFsZWFydGhkYXRhKQ0KbGlicmFyeShzZikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KERUKQ0KbGlicmFyeShjb3VudHJ5Y29kZSkNCg0KIyBMb2FkIHRoZSBkYXRhDQpkYXRhIDwtIHJlYWRfZXhjZWwoImxpbmtlZGluX2luZm8ueGxzeCIpDQoNCiMgQ291bnQgdGhlIG51bWJlciBvZiBzdGFydHVwcyBieSBjb3VudHJ5DQpzdGFydHVwX2NvdW50cyA8LSBkYXRhICU+JQ0KICBncm91cF9ieShDb3VudHJ5KSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbigpKQ0KDQojIENvbnZlcnQgSVNPIGNvdW50cnkgY29kZXMgdG8gY291bnRyeSBuYW1lcw0Kc3RhcnR1cF9jb3VudHMkQ291bnRyeSA8LSBjb3VudHJ5Y29kZShzdGFydHVwX2NvdW50cyRDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIikNCnN0YXJ0dXBfY291bnRzJENvdW50cnlbaXMubmEoc3RhcnR1cF9jb3VudHMkQ291bnRyeSldIDwtICJVbmtub3duIg0KDQojIExvYWQgZ2VvZ3JhcGhpY2FsIGRhdGENCndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpDQoNCiMgSm9pbiBzdGFydHVwIGRhdGEgd2l0aCBnZW9ncmFwaGljYWwgZGF0YQ0KbWFwX2RhdGEgPC0gbGVmdF9qb2luKHdvcmxkLCBzdGFydHVwX2NvdW50cywgYnkgPSBjKCJuYW1lX2xvbmciID0gIkNvdW50cnkiKSkNCg0KIyBDcmVhdGUgbGFiZWxzIGZvciB0b29sdGlwcw0KbWFwX2RhdGEkdG9vbHRpcCA8LSB3aXRoKG1hcF9kYXRhLCBwYXN0ZShuYW1lX2xvbmcsICI8YnI+IiwgIk51bWJlciBvZiBTdGFydHVwczogIiwgQ291bnQpKQ0KDQojIENyZWF0ZSB0aGUgbWFwIHdpdGggZ2dwbG90Mg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IG1hcF9kYXRhKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBDb3VudCwgdGV4dCA9IHRvb2x0aXApLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oDQogICAgY29sb3JzID0gYygiI2RlZWJmNyIsICIjOWVjYWUxIiwgIiMzMTgyYmQiLCAiIzA4NTE5YyIpLA0KICAgIG5hLnZhbHVlID0gImdyZXk1MCIsDQogICAgbmFtZSA9ICJOdW1iZXIgb2YgU3RhcnR1cHMiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBoanVzdCA9IDAuNSksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIk51bWJlciBvZiBTdGFydHVwcyBieSBDb3VudHJ5IiwNCiAgICBzdWJ0aXRsZSA9ICJTb3VyY2U6IExpbmtlZEluIiwNCiAgICBmaWxsID0gIk51bWJlciBvZiBTdGFydHVwcyINCiAgKQ0KDQojIE1ha2UgdGhlIG1hcCBpbnRlcmFjdGl2ZSB3aXRoIHBsb3RseQ0KcF9pbnRlcmFjdGl2ZSA8LSBnZ3Bsb3RseShwLCB0b29sdGlwID0gInRleHQiKQ0KDQojIEFkanVzdCB0aGUgc2l6ZSBmb3IgaG9yaXpvbnRhbCBkaXNwbGF5DQpwX2ludGVyYWN0aXZlIDwtIHBfaW50ZXJhY3RpdmUgJT4lDQogIGxheW91dCgNCiAgICB3aWR0aCA9IDEwMDAsICAjIFNldCB3aWR0aCB0byBtYWtlIHRoZSBtYXAgd2lkZXINCiAgICBoZWlnaHQgPSA1MDAgICMgU2V0IGhlaWdodCBhcHByb3ByaWF0ZWx5DQogICkNCg0KIyBEaXNwbGF5IHRoZSBpbnRlcmFjdGl2ZSBtYXANCnBfaW50ZXJhY3RpdmUNCg0KYGBgDQoNCioqKioqDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoZSBzZWNvbmQgbWFwIGlsbHVzdHJhdGVzIHRoZSBudW1iZXIgb2Ygc3RhcnR1cHMgYnkgY291bnRyeSwgY2F0ZWdvcml6ZWQgYnkgdGhlaXIgZXN0aW1hdGVkIHNpemUgYmFzZWQgb24gZW1wbG95ZWUgY291bnQgZnJvbSBMaW5rZWRJbiBkYXRhLiBTdGFydHVwcyBhcmUgY2xhc3NpZmllZCBpbnRvIFNtYWxsLCBNZWRpdW0sIExhcmdlLCBhbmQgVmVyeSBMYXJnZSB1c2luZyBlbXBsb3llZSBxdWFydGlsZXMuIFRoZSBtYXAgZmVhdHVyZXMgaW50ZXJhY3RpdmUgdG9vbHRpcHMgd2l0aCBjb3VudHJ5IG5hbWVzLCBlc3RpbWF0ZWQgc2l6ZXMsIGFuZCBzdGFydHVwIGNvdW50cy4gQnViYmxlIHNpemVzIGluZGljYXRlIHRoZSBudW1iZXIgb2Ygc3RhcnR1cHMsIHdoaWxlIGNvbG9ycyAoWWVsbG93IGZvciBTbWFsbCwgT3JhbmdlIGZvciBNZWRpdW0sIFJlZCBmb3IgTGFyZ2UsIERhcmsgUmVkIGZvciBWZXJ5IExhcmdlLCBhbmQgR3JleSBmb3IgVW5rbm93bikgcmVwcmVzZW50IHNpemUgY2F0ZWdvcmllcy4gVGhpcyB2aXN1YWxpemF0aW9uIGhlbHBzIGlkZW50aWZ5IHRoZSBkaXN0cmlidXRpb24gb2YgZGlmZmVyZW50LXNpemVkIHN0YXJ0dXBzIGdsb2JhbGx5LCBlbXBoYXNpemluZyByZWdpb25zIHdpdGggZGl2ZXJzZSBlbnRyZXByZW5ldXJpYWwgYWN0aXZpdGllcy4NCjwvcD4NCg0KPHRhYmxlIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7IHdpZHRoOiAxMDAlOyI+DQogIDx0ciBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNkZGQ7Ij4NCiAgICA8dGggc3R5bGU9InBhZGRpbmc6IDhweDsgdGV4dC1hbGlnbjogbGVmdDsiPkVzdGltYXRlZCBTaXplPC90aD4NCiAgICA8dGggc3R5bGU9InBhZGRpbmc6IDhweDsgdGV4dC1hbGlnbjogbGVmdDsiPkRlZmluaXRpb248L3RoPg0KICA8L3RyPg0KICA8dHIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZGRkOyI+DQogICAgPHRkIHN0eWxlPSJwYWRkaW5nOiA4cHg7Ij5TbWFsbDwvdGQ+DQogICAgPHRkIHN0eWxlPSJwYWRkaW5nOiA4cHg7Ij5FbXBsb3llZXMg4omkIDFzdCBxdWFydGlsZTwvdGQ+DQogIDwvdHI+DQogIDx0ciBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNkZGQ7Ij4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPk1lZGl1bTwvdGQ+DQogICAgPHRkIHN0eWxlPSJwYWRkaW5nOiA4cHg7Ij4xc3QgcXVhcnRpbGUgPCBFbXBsb3llZXMg4omkIDJuZCBxdWFydGlsZTwvdGQ+DQogIDwvdHI+DQogIDx0ciBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNkZGQ7Ij4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPkxhcmdlPC90ZD4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPjJuZCBxdWFydGlsZSA8IEVtcGxveWVlcyDiiaQgM3JkIHF1YXJ0aWxlPC90ZD4NCiAgPC90cj4NCiAgPHRyIHN0eWxlPSJib3JkZXItYm90dG9tOiAxcHggc29saWQgI2RkZDsiPg0KICAgIDx0ZCBzdHlsZT0icGFkZGluZzogOHB4OyI+VmVyeSBMYXJnZTwvdGQ+DQogICAgPHRkIHN0eWxlPSJwYWRkaW5nOiA4cHg7Ij5FbXBsb3llZXMgPiAzcmQgcXVhcnRpbGU8L3RkPg0KICA8L3RyPg0KICA8dHIgc3R5bGU9ImJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZGRkOyI+DQogICAgPHRkIHN0eWxlPSJwYWRkaW5nOiA4cHg7Ij5Vbmtub3duPC90ZD4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPk1pc3NpbmcgZW1wbG95ZWUgZGF0YTwvdGQ+DQogIDwvdHI+DQo8L3RhYmxlPg0KDQoNCmBgYHtyICwgZWNobz1GQUxTRX0NCg0KIyBMb2FkIHRoZSBkYXRhDQpkYXRhIDwtIHJlYWRfZXhjZWwoImxpbmtlZGluX2luZm8ueGxzeCIpDQoNCiMgQ2FsY3VsYXRlIHF1YXJ0aWxlcyBmb3IgdGhlIG51bWJlciBvZiBlbXBsb3llZXMNCnF1YXJ0aWxlcyA8LSBxdWFudGlsZShkYXRhJGBOdW1iZXIgb2YgRW1wbG95ZWVzYCwgcHJvYnMgPSBjKDAuMjUsIDAuNSwgMC43NSksIG5hLnJtID0gVFJVRSkNCg0KIyBGdW5jdGlvbiB0byBlc3RpbWF0ZSBzaXplIGJhc2VkIG9uIHF1YXJ0aWxlcw0KZXN0aW1hdGVfc2l6ZSA8LSBmdW5jdGlvbihudW1fZW1wbG95ZWVzKSB7DQogIGlmIChpcy5uYShudW1fZW1wbG95ZWVzKSkgew0KICAgIHJldHVybigiVW5rbm93biIpDQogIH0gZWxzZSBpZiAobnVtX2VtcGxveWVlcyA8PSBxdWFydGlsZXNbMV0pIHsNCiAgICByZXR1cm4oIlNtYWxsIikNCiAgfSBlbHNlIGlmIChudW1fZW1wbG95ZWVzIDw9IHF1YXJ0aWxlc1syXSkgew0KICAgIHJldHVybigiTWVkaXVtIikNCiAgfSBlbHNlIGlmIChudW1fZW1wbG95ZWVzIDw9IHF1YXJ0aWxlc1szXSkgew0KICAgIHJldHVybigiTGFyZ2UiKQ0KICB9IGVsc2Ugew0KICAgIHJldHVybigiVmVyeSBMYXJnZSIpDQogIH0NCn0NCg0KIyBBcHBseSB0aGUgZnVuY3Rpb24gdG8gZXN0aW1hdGUgc2l6ZQ0KZGF0YSRFc3RpbWF0ZWRfU2l6ZSA8LSBzYXBwbHkoZGF0YSRgTnVtYmVyIG9mIEVtcGxveWVlc2AsIGVzdGltYXRlX3NpemUpDQoNCiMgQWdncmVnYXRlIGRhdGEgYnkgY291bnRyeSBhbmQgZXN0aW1hdGVkIHNpemUNCnN0YXJ0dXBfY291bnRzIDwtIGRhdGEgJT4lDQogIGdyb3VwX2J5KENvdW50cnksIEVzdGltYXRlZF9TaXplKSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQojIENvbnZlcnQgSVNPIGNvdW50cnkgY29kZXMgdG8gY291bnRyeSBuYW1lcw0Kc3RhcnR1cF9jb3VudHMkQ291bnRyeSA8LSBjb3VudHJ5Y29kZShzdGFydHVwX2NvdW50cyRDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIikNCnN0YXJ0dXBfY291bnRzJENvdW50cnlbaXMubmEoc3RhcnR1cF9jb3VudHMkQ291bnRyeSldIDwtICJVbmtub3duIg0KDQojIExvYWQgZ2VvZ3JhcGhpY2FsIGRhdGENCndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpDQoNCiMgRXh0cmFjdCBjZW50cm9pZCBjb29yZGluYXRlcyBmb3IgYnViYmxlIHBvc2l0aW9ucw0Kd29ybGRfY2VudHJvaWRzIDwtIHN0X2NlbnRyb2lkKHdvcmxkKQ0KYnViYmxlX2RhdGEgPC0gbGVmdF9qb2luKHdvcmxkX2NlbnRyb2lkcywgc3RhcnR1cF9jb3VudHMsIGJ5ID0gYygibmFtZV9sb25nIiA9ICJDb3VudHJ5IikpDQoNCiMgRmlsdGVyIG91dCByb3dzIHdpdGggTkEgdmFsdWVzDQpidWJibGVfZGF0YSA8LSBidWJibGVfZGF0YVshaXMubmEoYnViYmxlX2RhdGEkQ291bnQpLCBdDQoNCiMgQ29udmVydCBjZW50cm9pZHMgdG8gZGF0YSBmcmFtZSBmb3IgZ2dwbG90Mg0KYnViYmxlX2RhdGFfZGYgPC0gYXMuZGF0YS5mcmFtZShidWJibGVfZGF0YSkNCmJ1YmJsZV9kYXRhX2RmIDwtIGNiaW5kKGJ1YmJsZV9kYXRhX2RmLCBzdF9jb29yZGluYXRlcyhidWJibGVfZGF0YSkpDQoNCiMgQ3JlYXRlIHRoZSBtYXAgd2l0aCBnZ3Bsb3QyDQpwIDwtIGdncGxvdChkYXRhID0gd29ybGQpICsNCiAgZ2VvbV9zZihmaWxsID0gImdyZXk5MCIsIGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3BvaW50KGRhdGEgPSBidWJibGVfZGF0YV9kZiwgYWVzKHggPSBYLCB5ID0gWSwgc2l6ZSA9IENvdW50LCBjb2xvciA9IEVzdGltYXRlZF9TaXplLCB0ZXh0ID0gcGFzdGUobmFtZV9sb25nLCAiPGJyPiIsICJFc3RpbWF0ZWQgU2l6ZTogIiwgRXN0aW1hdGVkX1NpemUsICI8YnI+IiwgIkNvdW50OiAiLCBDb3VudCkpLCBpbmhlcml0LmFlcyA9IEZBTFNFKSArDQogIHNjYWxlX3NpemVfY29udGludW91cyhuYW1lID0gIk51bWJlciBvZiBTdGFydHVwcyIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKA0KICAgIHZhbHVlcyA9IGMoIlNtYWxsIiA9ICJ5ZWxsb3ciLCAiTWVkaXVtIiA9ICJvcmFuZ2UiLCAiTGFyZ2UiID0gInJlZCIsICJWZXJ5IExhcmdlIiA9ICJkYXJrcmVkIiwgIlVua25vd24iID0gImdyZXkiKSwNCiAgICBuYW1lID0gIkVzdGltYXRlZCBTaXplIg0KICApICsNCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDUpKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBoanVzdCA9IDAuNSksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIk51bWJlciBvZiBTdGFydHVwcyBieSBDb3VudHJ5IGFuZCBFc3RpbWF0ZWQgU2l6ZSIsDQogICAgc3VidGl0bGUgPSAiU291cmNlOiBMaW5rZWRJbiIsDQogICAgZmlsbCA9ICJOdW1iZXIgb2YgU3RhcnR1cHMiDQogICkNCg0KIyBNYWtlIHRoZSBtYXAgaW50ZXJhY3RpdmUgd2l0aCBwbG90bHkNCnBfaW50ZXJhY3RpdmUgPC0gZ2dwbG90bHkocCwgdG9vbHRpcCA9ICJ0ZXh0IikNCg0KIyBBZGp1c3QgdGhlIHNpemUgZm9yIGhvcml6b250YWwgZGlzcGxheQ0KcF9pbnRlcmFjdGl2ZSA8LSBwX2ludGVyYWN0aXZlICU+JQ0KICBsYXlvdXQoDQogICAgd2lkdGggPSAxMDAwLCAgIyBTZXQgd2lkdGggdG8gbWFrZSB0aGUgbWFwIHdpZGVyDQogICAgaGVpZ2h0ID0gNTAwLCAgIyBTZXQgaGVpZ2h0IGFwcHJvcHJpYXRlbHkNCiAgICB0aXRsZSA9IGxpc3QodGV4dCA9ICdOdW1iZXIgb2YgU3RhcnR1cHMgYnkgQ291bnRyeSBhbmQgRXN0aW1hdGVkIFNpemUnLCB4ID0gMC41LCB5ID0gMC45NSwgZm9udCA9IGxpc3Qoc2l6ZSA9IDIwKSksDQogICAgbWFyZ2luID0gbGlzdCh0ID0gNTAsIGIgPSA1MCkNCiAgKQ0KDQojIERpc3BsYXkgdGhlIGludGVyYWN0aXZlIG1hcA0KcF9pbnRlcmFjdGl2ZQ0KDQoNCmBgYA0KDQoNCmBgYHtyICwgZWNobz1GQUxTRX0NCg0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoY291bnRyeWNvZGUpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShzY2FsZXMpDQoNCiMgTG9hZCB0aGUgZGF0YQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KDQojIENhbGN1bGF0ZSBxdWFydGlsZXMgZm9yIHRoZSBudW1iZXIgb2YgZW1wbG95ZWVzDQpxdWFydGlsZXMgPC0gcXVhbnRpbGUoZGF0YSRgTnVtYmVyIG9mIEVtcGxveWVlc2AsIHByb2JzID0gYygwLjI1LCAwLjUsIDAuNzUpLCBuYS5ybSA9IFRSVUUpDQoNCiMgRnVuY3Rpb24gdG8gZXN0aW1hdGUgc2l6ZSBiYXNlZCBvbiBxdWFydGlsZXMNCmVzdGltYXRlX3NpemUgPC0gZnVuY3Rpb24obnVtX2VtcGxveWVlcykgew0KICBpZiAoaXMubmEobnVtX2VtcGxveWVlcykpIHsNCiAgICByZXR1cm4oIlVua25vd24iKQ0KICB9IGVsc2UgaWYgKG51bV9lbXBsb3llZXMgPD0gcXVhcnRpbGVzWzFdKSB7DQogICAgcmV0dXJuKCJTbWFsbCIpDQogIH0gZWxzZSBpZiAobnVtX2VtcGxveWVlcyA8PSBxdWFydGlsZXNbMl0pIHsNCiAgICByZXR1cm4oIk1lZGl1bSIpDQogIH0gZWxzZSBpZiAobnVtX2VtcGxveWVlcyA8PSBxdWFydGlsZXNbM10pIHsNCiAgICByZXR1cm4oIkxhcmdlIikNCiAgfSBlbHNlIHsNCiAgICByZXR1cm4oIlZlcnkgTGFyZ2UiKQ0KICB9DQp9DQoNCiMgQXBwbHkgdGhlIGZ1bmN0aW9uIHRvIGVzdGltYXRlIHNpemUNCmRhdGEkRXN0aW1hdGVkX1NpemUgPC0gc2FwcGx5KGRhdGEkYE51bWJlciBvZiBFbXBsb3llZXNgLCBlc3RpbWF0ZV9zaXplKQ0KDQojIEFnZ3JlZ2F0ZSBkYXRhIGJ5IGNvdW50cnkgYW5kIGVzdGltYXRlZCBzaXplDQpzdGFydHVwX2NvdW50cyA8LSBkYXRhICU+JQ0KICBncm91cF9ieShDb3VudHJ5LCBFc3RpbWF0ZWRfU2l6ZSkgJT4lDQogIHN1bW1hcmlzZShDb3VudCA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykNCg0KIyBDb252ZXJ0IElTTyBjb3VudHJ5IGNvZGVzIHRvIGNvdW50cnkgbmFtZXMNCnN0YXJ0dXBfY291bnRzJENvdW50cnkgPC0gY291bnRyeWNvZGUoc3RhcnR1cF9jb3VudHMkQ291bnRyeSwgImlzbzJjIiwgImNvdW50cnkubmFtZSIpDQpzdGFydHVwX2NvdW50cyRDb3VudHJ5W2lzLm5hKHN0YXJ0dXBfY291bnRzJENvdW50cnkpXSA8LSAiVW5rbm93biINCg0KIyBTcHJlYWQgdGhlIGRhdGEgdG8gaGF2ZSBlc3RpbWF0ZWQgc2l6ZXMgYXMgY29sdW1ucw0KdGFibGVfZGF0YSA8LSBzdGFydHVwX2NvdW50cyAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVzdGltYXRlZF9TaXplLCB2YWx1ZXNfZnJvbSA9IENvdW50LCB2YWx1ZXNfZmlsbCA9IGxpc3QoQ291bnQgPSAwKSkgJT4lDQogIG11dGF0ZShUb3RhbCA9IHJvd1N1bXMoc2VsZWN0KC4sIC1Db3VudHJ5KSkpICU+JQ0KICBhcnJhbmdlKGRlc2MoVG90YWwpKSAjIFNvcnQgYnkgVG90YWwgaW4gZGVzY2VuZGluZyBvcmRlcg0KDQojIEN1c3RvbSBjb2xvciBzY2FsZSBmdW5jdGlvbiBmb3IgdGhlIFRvdGFsIGNvbHVtbg0KY29sb3Jfc2NhbGVfdG90YWwgPC0gZnVuY3Rpb24oeCkgew0KICBjb2wgPC0gc2NhbGVzOjpjb2xfbnVtZXJpYyhwYWxldHRlID0gYygiI2RlZWJmNyIsICIjMzE4MmJkIiksIGRvbWFpbiA9IHJhbmdlKHgsIG5hLnJtID0gVFJVRSkpKHgpDQogIHJldHVybihjb2wpDQp9DQoNCiMgQXBwbHkgdGhlIGNvbG9yIHNjYWxlIHRvIHRoZSBUb3RhbCBjb2x1bW4NCnRhYmxlX2RhdGEkVG90YWxfY29sb3IgPC0gY29sb3Jfc2NhbGVfdG90YWwodGFibGVfZGF0YSRUb3RhbCkNCg0KIyBDcmVhdGUgdGhlIHRhYmxlIHdpdGgga2FibGUNCmthYmxlKHRhYmxlX2RhdGEgJT4lIHNlbGVjdCgtVG90YWxfY29sb3IpLCBjb2wubmFtZXMgPSBjKCJDb3VudHJ5IiwgIlNtYWxsIiwgIk1lZGl1bSIsICJMYXJnZSIsICJWZXJ5IExhcmdlIiwgIlVua25vd24iLCAiVG90YWwiKSwgYWxpZ24gPSAnYycpICU+JQ0KICBhZGRfaGVhZGVyX2Fib3ZlKGMoIlNpemUgYmFzZWQgb24gbnVtYmVyIG9mIGVtcGxveWVlcyIgPSA3KSkgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiKSAlPiUNCiAgY29sdW1uX3NwZWMoMSwgYm9sZCA9IFRSVUUpICU+JQ0KICBjb2x1bW5fc3BlYyg3LCBiYWNrZ3JvdW5kID0gdGFibGVfZGF0YSRUb3RhbF9jb2xvciwgYm9sZCA9IFRSVUUpICU+JQ0KICBzY3JvbGxfYm94KGhlaWdodCA9ICI1MDBweCIsIHdpZHRoID0gIjEwMCUiKQ0KDQpgYGANCg0KDQoNCiMjIyMjIEFtb3VudCBvZiBpbnZlc3RtZW50cw0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGUgY2hhcnQgaXMgYnVpbHQgdXNpbmcgZGF0YSBmcm9tIExpbmtlZEluLCBsaXN0aW5nIGNvdW50cmllcyB3aGVyZSBvZmZpY2VzIGFyZSBiYXNlZCBhbmQgdGhlIGxhc3Qgcm91bmQgb2YgaW52ZXN0bWVudCBhbW91bnRzLiBUaGlzIGNoYXJ0IHNob3dzIHRoZSBzdW0gb2YgYWxsIG1vbmV5IGludmVzdGVkIGluIHN0YXJ0dXBzIGJ5IGNvdW50cnksIHByb3ZpZGluZyBhIHZpc3VhbCByZXByZXNlbnRhdGlvbiBvZiBnbG9iYWwgaW52ZXN0bWVudCBkaXN0cmlidXRpb24uIEVhY2ggY291bnRyeSBpcyBjb2xvcmVkIGJhc2VkIG9uIHRoZSB0b3RhbCBpbnZlc3RtZW50IGFtb3VudCwgd2l0aCBpbnRlcmFjdGl2ZSB0b29sdGlwcyBvZmZlcmluZyBkZXRhaWxlZCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgaW52ZXN0bWVudHMuDQo8L3A+DQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KDQojIExvYWQgdGhlIG5lY2Vzc2FyeSBsaWJyYXJpZXMNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShybmF0dXJhbGVhcnRoKQ0KbGlicmFyeShybmF0dXJhbGVhcnRoZGF0YSkNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShjb3VudHJ5Y29kZSkNCg0KIyBMb2FkIHRoZSBkYXRhDQpkYXRhIDwtIHJlYWRfZXhjZWwoImxpbmtlZGluX2luZm8ueGxzeCIpDQoNCiMgUHJlcHJvY2VzcyB0aGUgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudCBjb2x1bW4NCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBhbW91bnQgbm90IGZvdW5kIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgJT4lDQogIG11dGF0ZSgNCiAgICBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAgPSBnc3ViKCJVU1xcJCAiLCAiIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSwNCiAgICBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAgPSBpZmVsc2UoZ3JlcGwoIk0iLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyhzdWIoIk0iLCAiIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgKiAxZTYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIksiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoc3ViKCJLIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWUzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkpDQogICkNCg0KIyBTdW1tYXJpemUgaW52ZXN0bWVudCBhbW91bnRzIGJ5IGNvdW50cnkNCmludmVzdG1lbnRfYnlfY291bnRyeSA8LSBkYXRhICU+JQ0KICBncm91cF9ieShDb3VudHJ5KSAlPiUNCiAgc3VtbWFyaXNlKFRvdGFsX0ludmVzdG1lbnQgPSBzdW0oYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgLCBuYS5ybSA9IFRSVUUpKQ0KDQojIENvbnZlcnQgSVNPIGNvdW50cnkgY29kZXMgdG8gY291bnRyeSBuYW1lcw0KaW52ZXN0bWVudF9ieV9jb3VudHJ5JENvdW50cnkgPC0gY291bnRyeWNvZGUoaW52ZXN0bWVudF9ieV9jb3VudHJ5JENvdW50cnksICJpc28yYyIsICJjb3VudHJ5Lm5hbWUiKQ0KaW52ZXN0bWVudF9ieV9jb3VudHJ5JENvdW50cnlbaXMubmEoaW52ZXN0bWVudF9ieV9jb3VudHJ5JENvdW50cnkpXSA8LSAiVW5rbm93biINCg0KIyBMb2FkIGdlb2dyYXBoaWNhbCBkYXRhDQp3b3JsZCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQ0KDQojIEpvaW4gaW52ZXN0bWVudCBkYXRhIHdpdGggZ2VvZ3JhcGhpY2FsIGRhdGENCm1hcF9kYXRhIDwtIGxlZnRfam9pbih3b3JsZCwgaW52ZXN0bWVudF9ieV9jb3VudHJ5LCBieSA9IGMoIm5hbWVfbG9uZyIgPSAiQ291bnRyeSIpKQ0KDQojIENyZWF0ZSBsYWJlbHMgZm9yIHRvb2x0aXBzDQptYXBfZGF0YSR0b29sdGlwIDwtIHdpdGgobWFwX2RhdGEsIHBhc3RlKG5hbWVfbG9uZywgIjxicj4iLCAiVG90YWwgSW52ZXN0bWVudDogJCIsIGZvcm1hdChUb3RhbF9JbnZlc3RtZW50LCBiaWcubWFyayA9ICIsIikpKQ0KDQojIENyZWF0ZSB0aGUgbWFwIHdpdGggZ2dwbG90Mg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IG1hcF9kYXRhKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBUb3RhbF9JbnZlc3RtZW50LCB0ZXh0ID0gdG9vbHRpcCksIGNvbG9yID0gIndoaXRlIikgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50bigNCiAgICBjb2xvcnMgPSBjKCIjZDczMDI3IiwgIiNmZWUwOGIiLCAiIzFhOTg1MCIpLA0KICAgIG5hLnZhbHVlID0gImdyZXk1MCIsDQogICAgbmFtZSA9ICJUb3RhbCBJbnZlc3RtZW50IiwNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcl9mb3JtYXQoc2NhbGUgPSAxZS05LCBzdWZmaXggPSAiQiIpDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBoanVzdCA9IDAuNSksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlRvdGFsIEludmVzdG1lbnQgaW4gU3RhcnR1cHMgYnkgQ291bnRyeSIsDQogICAgc3VidGl0bGUgPSAiU291cmNlOiBMaW5rZWRJbiIsDQogICAgZmlsbCA9ICJUb3RhbCBJbnZlc3RtZW50Ig0KICApDQoNCiMgTWFrZSB0aGUgbWFwIGludGVyYWN0aXZlIHdpdGggcGxvdGx5DQpwX2ludGVyYWN0aXZlIDwtIGdncGxvdGx5KHAsIHRvb2x0aXAgPSAidGV4dCIpDQoNCiMgQWRqdXN0IHRoZSBzaXplIGZvciBob3Jpem9udGFsIGRpc3BsYXkNCnBfaW50ZXJhY3RpdmUgPC0gcF9pbnRlcmFjdGl2ZSAlPiUNCiAgbGF5b3V0KA0KICAgIHdpZHRoID0gMTAwMCwgICMgU2V0IHdpZHRoIHRvIG1ha2UgdGhlIG1hcCB3aWRlcg0KICAgIGhlaWdodCA9IDUwMCAgIyBTZXQgaGVpZ2h0IGFwcHJvcHJpYXRlbHkNCiAgKQ0KDQojIERpc3BsYXkgdGhlIGludGVyYWN0aXZlIG1hcA0KcF9pbnRlcmFjdGl2ZQ0KDQpgYGANCg0KKioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyBpbnRlcmFjdGl2ZSBtYXAgdmlzdWFsaXplcyB0aGUgbWVkaWFuIGludmVzdG1lbnQgaW4gc3RhcnR1cHMgYnkgY291bnRyeSBiYXNlZCBvbiBkYXRhIGZyb20gTGlua2VkSW4uIFRoZSBtYXAgdXNlcyB0aGUgbWVkaWFuIHRvIGF2b2lkIHRoZSBpbXBhY3Qgb2Ygb3V0bGllcnMuIENoaW5hIGlzIGhpZ2hsaWdodGVkIGluIHZpb2xldCBiZWNhdXNlIGl0IGlzIGFuIG91dGxpZXIsIHdpdGggb25seSBvbmUgY29tcGFueSBwcm92aWRpbmcgaW5mb3JtYXRpb24gb24gdGhlIGxhc3QgaW52ZXN0bWVudCByb3VuZCwgd2hpY2ggd2FzIGV4Y2VwdGlvbmFsbHkgbGFyZ2UuIFRoZSBncmFkaWVudCBjb2xvciBzY2FsZSBmcm9tIHJlZCB0byB5ZWxsb3cgdG8gZ3JlZW4gaW5kaWNhdGVzIGxvdyB0byBoaWdoIG1lZGlhbiBpbnZlc3RtZW50cyBpbiBtaWxsaW9ucyBvZiBkb2xsYXJzLCBhbGxvd2luZyBmb3IgYSBjbGVhciBjb21wYXJpc29uIG9mIGludmVzdG1lbnQgbGV2ZWxzIGFjcm9zcyBjb3VudHJpZXMuDQo8L3A+DQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCiMgTG9hZCB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHJuYXR1cmFsZWFydGgpDQpsaWJyYXJ5KHJuYXR1cmFsZWFydGhkYXRhKQ0KbGlicmFyeShzZikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KbGlicmFyeShzY2FsZXMpDQoNCiMgTG9hZCB0aGUgZGF0YQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KDQojIFByZXByb2Nlc3MgdGhlIENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnQgY29sdW1uDQpkYXRhIDwtIGRhdGEgJT4lDQogIGZpbHRlcighZ3JlcGwoIkxhc3Qgcm91bmQgYW1vdW50IG5vdCBmb3VuZCIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICU+JQ0KICBtdXRhdGUoDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gZ3N1YigiVVNcXCQgIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gaWZlbHNlKGdyZXBsKCJNIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoc3ViKCJNIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJLIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKHN1YigiSyIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKSAqIDFlMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpKQ0KICApDQoNCiMgRXhjbHVkZSBDaGluYSBmcm9tIHRoZSBtZWRpYW4gY2FsY3VsYXRpb24NCmRhdGFfbm9fY2hpbmEgPC0gZGF0YSAlPiUgZmlsdGVyKENvdW50cnkgIT0gIkNOIikNCg0KIyBTdW1tYXJpemUgaW52ZXN0bWVudCBhbW91bnRzIGJ5IGNvdW50cnkgdXNpbmcgdGhlIG1lZGlhbg0KaW52ZXN0bWVudF9ieV9jb3VudHJ5IDwtIGRhdGFfbm9fY2hpbmEgJT4lDQogIGdyb3VwX2J5KENvdW50cnkpICU+JQ0KICBzdW1tYXJpc2UoTWVkaWFuX0ludmVzdG1lbnQgPSBtZWRpYW4oYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgLCBuYS5ybSA9IFRSVUUpKQ0KDQojIEFkZCBDaGluYSBiYWNrIHdpdGggaXRzIG9yaWdpbmFsIHZhbHVlDQpjaGluYV9pbnZlc3RtZW50IDwtIGRhdGEgJT4lDQogIGZpbHRlcihDb3VudHJ5ID09ICJDTiIpICU+JQ0KICBzdW1tYXJpc2UoQ291bnRyeSA9ICJDTiIsIE1lZGlhbl9JbnZlc3RtZW50ID0gbWVkaWFuKGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCwgbmEucm0gPSBUUlVFKSkNCg0KaW52ZXN0bWVudF9ieV9jb3VudHJ5IDwtIGJpbmRfcm93cyhpbnZlc3RtZW50X2J5X2NvdW50cnksIGNoaW5hX2ludmVzdG1lbnQpDQoNCiMgQ29udmVydCBJU08gY291bnRyeSBjb2RlcyB0byBjb3VudHJ5IG5hbWVzDQppbnZlc3RtZW50X2J5X2NvdW50cnkkQ291bnRyeSA8LSBjb3VudHJ5Y29kZShpbnZlc3RtZW50X2J5X2NvdW50cnkkQ291bnRyeSwgImlzbzJjIiwgImNvdW50cnkubmFtZSIpDQppbnZlc3RtZW50X2J5X2NvdW50cnkkQ291bnRyeVtpcy5uYShpbnZlc3RtZW50X2J5X2NvdW50cnkkQ291bnRyeSldIDwtICJVbmtub3duIg0KDQojIExvYWQgZ2VvZ3JhcGhpY2FsIGRhdGENCndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpDQoNCiMgSm9pbiBpbnZlc3RtZW50IGRhdGEgd2l0aCBnZW9ncmFwaGljYWwgZGF0YQ0KbWFwX2RhdGEgPC0gbGVmdF9qb2luKHdvcmxkLCBpbnZlc3RtZW50X2J5X2NvdW50cnksIGJ5ID0gYygibmFtZV9sb25nIiA9ICJDb3VudHJ5IikpDQoNCiMgU2VwYXJhdGUgQ2hpbmEgZnJvbSB0aGUgcmVzdCBvZiB0aGUgY291bnRyaWVzDQptYXBfZGF0YSRjb2xvciA8LSBpZmVsc2UobWFwX2RhdGEkbmFtZV9sb25nID09ICJDaGluYSIsICJwdXJwbGUiLCAiZGVmYXVsdCIpDQoNCiMgQ3JlYXRlIGxhYmVscyBmb3IgdG9vbHRpcHMNCm1hcF9kYXRhJHRvb2x0aXAgPC0gd2l0aChtYXBfZGF0YSwgcGFzdGUobmFtZV9sb25nLCAiPGJyPiIsICJNZWRpYW4gSW52ZXN0bWVudDogJCIsIG51bWJlcihNZWRpYW5fSW52ZXN0bWVudCwgYWNjdXJhY3kgPSAxLCBiaWcubWFyayA9ICIsIikpKQ0KDQojIENyZWF0ZSB0aGUgbWFwIHdpdGggZ2dwbG90Mg0KcCA8LSBnZ3Bsb3QoZGF0YSA9IG1hcF9kYXRhKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBpZmVsc2UoY29sb3IgPT0gImRlZmF1bHQiLCBNZWRpYW5fSW52ZXN0bWVudCwgTkEpLCB0ZXh0ID0gdG9vbHRpcCksIGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3NmKGRhdGEgPSBzdWJzZXQobWFwX2RhdGEsIG5hbWVfbG9uZyA9PSAiQ2hpbmEiKSwgZmlsbCA9ICJwdXJwbGUiLCBjb2xvciA9ICJ3aGl0ZSIsIGFlcyh0ZXh0ID0gdG9vbHRpcCkpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oDQogICAgY29sb3JzID0gYygiI2Q3MzAyNyIsICIjZmVlMDhiIiwgIiMxYTk4NTAiKSwNCiAgICBuYS52YWx1ZSA9ICJncmV5NTAiLA0KICAgIG5hbWUgPSAiTWVkaWFuIEludmVzdG1lbnQiLA0KICAgIGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyX2Zvcm1hdChzY2FsZSA9IDFlLTYsIHN1ZmZpeCA9ICJNIikNCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGhqdXN0ID0gMC41KSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkNCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTWVkaWFuIEludmVzdG1lbnQgaW4gU3RhcnR1cHMgYnkgQ291bnRyeSIsDQogICAgc3VidGl0bGUgPSAiU291cmNlOiBMaW5rZWRJbiIsDQogICAgZmlsbCA9ICJNZWRpYW4gSW52ZXN0bWVudCINCiAgKQ0KDQojIE1ha2UgdGhlIG1hcCBpbnRlcmFjdGl2ZSB3aXRoIHBsb3RseQ0KcF9pbnRlcmFjdGl2ZSA8LSBnZ3Bsb3RseShwLCB0b29sdGlwID0gInRleHQiKQ0KDQojIEFkanVzdCB0aGUgc2l6ZSBmb3IgaG9yaXpvbnRhbCBkaXNwbGF5DQpwX2ludGVyYWN0aXZlIDwtIHBfaW50ZXJhY3RpdmUgJT4lDQogIGxheW91dCgNCiAgICB3aWR0aCA9IDEwMDAsICAjIFNldCB3aWR0aCB0byBtYWtlIHRoZSBtYXAgd2lkZXINCiAgICBoZWlnaHQgPSA1MDAgICMgU2V0IGhlaWdodCBhcHByb3ByaWF0ZWx5DQogICkNCg0KIyBEaXNwbGF5IHRoZSBpbnRlcmFjdGl2ZSBtYXANCnBfaW50ZXJhY3RpdmUNCg0KDQpgYGANCg0KKioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyBtYXAgaWxsdXN0cmF0ZXMgdGhlIG51bWJlciBvZiBzdGFydHVwcyBieSBjb3VudHJ5LCBjYXRlZ29yaXplZCBieSB0aGVpciBlc3RpbWF0ZWQgaW52ZXN0bWVudCBzaXplIGJhc2VkIG9uIGRhdGEgZnJvbSBMaW5rZWRJbi4gSW52ZXN0bWVudCBzaXplcyBhcmUgY2xhc3NpZmllZCBpbnRvIFNtYWxsLCBNZWRpdW0sIExhcmdlLCBhbmQgVmVyeSBMYXJnZSB1c2luZyBxdWFydGlsZXMgb2YgdGhlIGxhc3Qgcm91bmQgaW52ZXN0bWVudCBhbW91bnRzLiBUaGUgbWFwIGZlYXR1cmVzIGludGVyYWN0aXZlIHRvb2x0aXBzIHdpdGggY291bnRyeSBuYW1lcyBhbmQgZXN0aW1hdGVkIGludmVzdG1lbnQgc2l6ZXMuIEJ1YmJsZSBzaXplcyBpbmRpY2F0ZSB0aGUgbnVtYmVyIG9mIHN0YXJ0dXBzLCB3aGlsZSBjb2xvcnMgKExpZ2h0IEdyZWVuIGZvciBTbWFsbCwgR3JlZW4gZm9yIE1lZGl1bSwgRGFyayBHcmVlbiBmb3IgTGFyZ2UsIEZvcmVzdCBHcmVlbiBmb3IgVmVyeSBMYXJnZSwgYW5kIEdyZXkgZm9yIFVua25vd24pIHJlcHJlc2VudCBpbnZlc3RtZW50IHNpemUgY2F0ZWdvcmllcy4gVGhpcyB2aXN1YWxpemF0aW9uIGhlbHBzIGlkZW50aWZ5IHRoZSBkaXN0cmlidXRpb24gb2Ygc3RhcnR1cHMgd2l0aCB2YXJ5aW5nIGludmVzdG1lbnQgc2l6ZXMgZ2xvYmFsbHksIGhpZ2hsaWdodGluZyByZWdpb25zIHdpdGggZGl2ZXJzZSBsZXZlbHMgb2Ygc3RhcnR1cCBmdW5kaW5nLg0KPC9wPg0KDQo8dGFibGUgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgd2lkdGg6IDEwMCU7Ij4NCiAgPHRyIHN0eWxlPSJib3JkZXItYm90dG9tOiAxcHggc29saWQgI2RkZDsiPg0KICAgIDx0aCBzdHlsZT0icGFkZGluZzogOHB4OyB0ZXh0LWFsaWduOiBsZWZ0OyI+RXN0aW1hdGVkIEludmVzdG1lbnQgU2l6ZTwvdGg+DQogICAgPHRoIHN0eWxlPSJwYWRkaW5nOiA4cHg7IHRleHQtYWxpZ246IGxlZnQ7Ij5EZWZpbml0aW9uPC90aD4NCiAgPC90cj4NCiAgPHRyIHN0eWxlPSJib3JkZXItYm90dG9tOiAxcHggc29saWQgI2RkZDsiPg0KICAgIDx0ZCBzdHlsZT0icGFkZGluZzogOHB4OyI+U21hbGw8L3RkPg0KICAgIDx0ZCBzdHlsZT0icGFkZGluZzogOHB4OyI+SW52ZXN0bWVudCDiiaQgMXN0IHF1YXJ0aWxlPC90ZD4NCiAgPC90cj4NCiAgPHRyIHN0eWxlPSJib3JkZXItYm90dG9tOiAxcHggc29saWQgI2RkZDsiPg0KICAgIDx0ZCBzdHlsZT0icGFkZGluZzogOHB4OyI+TWVkaXVtPC90ZD4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPjFzdCBxdWFydGlsZSA8IEludmVzdG1lbnQg4omkIDJuZCBxdWFydGlsZTwvdGQ+DQogIDwvdHI+DQogIDx0ciBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNkZGQ7Ij4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPkxhcmdlPC90ZD4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPjJuZCBxdWFydGlsZSA8IEludmVzdG1lbnQg4omkIDNyZCBxdWFydGlsZTwvdGQ+DQogIDwvdHI+DQogIDx0ciBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNkZGQ7Ij4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPlZlcnkgTGFyZ2U8L3RkPg0KICAgIDx0ZCBzdHlsZT0icGFkZGluZzogOHB4OyI+SW52ZXN0bWVudCA+IDNyZCBxdWFydGlsZTwvdGQ+DQogIDwvdHI+DQogIDx0ciBzdHlsZT0iYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNkZGQ7Ij4NCiAgICA8dGQgc3R5bGU9InBhZGRpbmc6IDhweDsiPlVua25vd248L3RkPg0KICAgIDx0ZCBzdHlsZT0icGFkZGluZzogOHB4OyI+TWlzc2luZyBpbnZlc3RtZW50IGRhdGE8L3RkPg0KICA8L3RyPg0KPC90YWJsZT4NCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCg0KIyBMb2FkIHRoZSBuZWNlc3NhcnkgbGlicmFyaWVzDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkocm5hdHVyYWxlYXJ0aCkNCmxpYnJhcnkocm5hdHVyYWxlYXJ0aGRhdGEpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoY291bnRyeWNvZGUpDQoNCiMgTG9hZCB0aGUgZGF0YQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KDQojIFByZXByb2Nlc3MgdGhlIENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnQgY29sdW1uDQpkYXRhIDwtIGRhdGEgJT4lDQogIGZpbHRlcighZ3JlcGwoIkxhc3Qgcm91bmQgYW1vdW50IG5vdCBmb3VuZCIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICU+JQ0KICBtdXRhdGUoDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gZ3N1YigiVVNcXCQgIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gaWZlbHNlKGdyZXBsKCJNIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoc3ViKCJNIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJLIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKHN1YigiSyIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKSAqIDFlMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpKQ0KICApDQoNCiMgQ2FsY3VsYXRlIHF1YXJ0aWxlcyBmb3IgdGhlIENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnQNCnF1YXJ0aWxlcyA8LSBxdWFudGlsZShkYXRhJGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCwgcHJvYnMgPSBjKDAuMjUsIDAuNSwgMC43NSksIG5hLnJtID0gVFJVRSkNCg0KIyBGdW5jdGlvbiB0byBlc3RpbWF0ZSBzaXplIGJhc2VkIG9uIGludmVzdG1lbnQgcXVhcnRpbGVzDQplc3RpbWF0ZV9pbnZlc3RtZW50X3NpemUgPC0gZnVuY3Rpb24oaW52ZXN0bWVudCkgew0KICBpZiAoaXMubmEoaW52ZXN0bWVudCkpIHsNCiAgICByZXR1cm4oIlVua25vd24iKQ0KICB9IGVsc2UgaWYgKGludmVzdG1lbnQgPD0gcXVhcnRpbGVzWzFdKSB7DQogICAgcmV0dXJuKCJTbWFsbCIpDQogIH0gZWxzZSBpZiAoaW52ZXN0bWVudCA8PSBxdWFydGlsZXNbMl0pIHsNCiAgICByZXR1cm4oIk1lZGl1bSIpDQogIH0gZWxzZSBpZiAoaW52ZXN0bWVudCA8PSBxdWFydGlsZXNbM10pIHsNCiAgICByZXR1cm4oIkxhcmdlIikNCiAgfSBlbHNlIHsNCiAgICByZXR1cm4oIlZlcnkgTGFyZ2UiKQ0KICB9DQp9DQoNCiMgQXBwbHkgdGhlIGZ1bmN0aW9uIHRvIGVzdGltYXRlIHNpemUgYmFzZWQgb24gaW52ZXN0bWVudA0KZGF0YSRFc3RpbWF0ZWRfSW52ZXN0bWVudF9TaXplIDwtIHNhcHBseShkYXRhJGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCwgZXN0aW1hdGVfaW52ZXN0bWVudF9zaXplKQ0KDQojIEFnZ3JlZ2F0ZSBkYXRhIGJ5IGNvdW50cnkgYW5kIGVzdGltYXRlZCBpbnZlc3RtZW50IHNpemUNCmludmVzdG1lbnRfY291bnRzIDwtIGRhdGEgJT4lDQogIGdyb3VwX2J5KENvdW50cnksIEVzdGltYXRlZF9JbnZlc3RtZW50X1NpemUpICU+JQ0KICBzdW1tYXJpc2UoQ291bnQgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpDQoNCiMgQ29udmVydCBJU08gY291bnRyeSBjb2RlcyB0byBjb3VudHJ5IG5hbWVzDQppbnZlc3RtZW50X2NvdW50cyRDb3VudHJ5IDwtIGNvdW50cnljb2RlKGludmVzdG1lbnRfY291bnRzJENvdW50cnksICJpc28yYyIsICJjb3VudHJ5Lm5hbWUiKQ0KaW52ZXN0bWVudF9jb3VudHMkQ291bnRyeVtpcy5uYShpbnZlc3RtZW50X2NvdW50cyRDb3VudHJ5KV0gPC0gIlVua25vd24iDQoNCiMgTG9hZCBnZW9ncmFwaGljYWwgZGF0YQ0Kd29ybGQgPC0gbmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikNCg0KIyBFeHRyYWN0IGNlbnRyb2lkIGNvb3JkaW5hdGVzIGZvciBidWJibGUgcG9zaXRpb25zDQp3b3JsZF9jZW50cm9pZHMgPC0gc3RfY2VudHJvaWQod29ybGQpDQpidWJibGVfZGF0YSA8LSBsZWZ0X2pvaW4od29ybGRfY2VudHJvaWRzLCBpbnZlc3RtZW50X2NvdW50cywgYnkgPSBjKCJuYW1lX2xvbmciID0gIkNvdW50cnkiKSkNCg0KIyBGaWx0ZXIgb3V0IHJvd3Mgd2l0aCBOQSB2YWx1ZXMNCmJ1YmJsZV9kYXRhIDwtIGJ1YmJsZV9kYXRhWyFpcy5uYShidWJibGVfZGF0YSRDb3VudCksIF0NCg0KIyBDb252ZXJ0IGNlbnRyb2lkcyB0byBkYXRhIGZyYW1lIGZvciBnZ3Bsb3QyDQpidWJibGVfZGF0YV9kZiA8LSBhcy5kYXRhLmZyYW1lKGJ1YmJsZV9kYXRhKQ0KYnViYmxlX2RhdGFfZGYgPC0gY2JpbmQoYnViYmxlX2RhdGFfZGYsIHN0X2Nvb3JkaW5hdGVzKGJ1YmJsZV9kYXRhKSkNCg0KIyBDcmVhdGUgdGhlIG1hcCB3aXRoIGdncGxvdDINCnAgPC0gZ2dwbG90KGRhdGEgPSB3b3JsZCkgKw0KICBnZW9tX3NmKGZpbGwgPSAiZ3JleTkwIiwgY29sb3IgPSAid2hpdGUiKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IGJ1YmJsZV9kYXRhX2RmLCBhZXMoeCA9IFgsIHkgPSBZLCBzaXplID0gQ291bnQsIGNvbG9yID0gRXN0aW1hdGVkX0ludmVzdG1lbnRfU2l6ZSwgdGV4dCA9IHBhc3RlKG5hbWVfbG9uZywgIjxicj5JbnZlc3RtZW50IFNpemU6IiwgRXN0aW1hdGVkX0ludmVzdG1lbnRfU2l6ZSwgIjxicj5OdW1iZXIgb2YgU3RhcnR1cHM6IiwgQ291bnQpKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKw0KICBzY2FsZV9zaXplX2NvbnRpbnVvdXMobmFtZSA9ICJOdW1iZXIgb2YgU3RhcnR1cHMiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgNCiAgICB2YWx1ZXMgPSBjKCJTbWFsbCIgPSAibGlnaHRncmVlbiIsICJNZWRpdW0iID0gImdyZWVuIiwgIkxhcmdlIiA9ICJkYXJrZ3JlZW4iLCAiVmVyeSBMYXJnZSIgPSAiZm9yZXN0Z3JlZW4iLCAiVW5rbm93biIgPSAiZ3JleSIpLA0KICAgIG5hbWUgPSAiSW52ZXN0bWVudCBTaXplIg0KICApICsNCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDUpKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBoanVzdCA9IDAuNSksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIk51bWJlciBvZiBTdGFydHVwcyBieSBDb3VudHJ5IGFuZCBJbnZlc3RtZW50IFNpemUiLA0KICAgIHN1YnRpdGxlID0gIlNvdXJjZTogTGlua2VkSW4iLA0KICAgIGZpbGwgPSAiTnVtYmVyIG9mIFN0YXJ0dXBzIg0KICApDQoNCiMgTWFrZSB0aGUgbWFwIGludGVyYWN0aXZlIHdpdGggcGxvdGx5DQpwX2ludGVyYWN0aXZlIDwtIGdncGxvdGx5KHAsIHRvb2x0aXAgPSAidGV4dCIpDQoNCiMgQWRqdXN0IHRoZSBzaXplIGZvciBob3Jpem9udGFsIGRpc3BsYXkNCnBfaW50ZXJhY3RpdmUgPC0gcF9pbnRlcmFjdGl2ZSAlPiUNCiAgbGF5b3V0KA0KICAgIHdpZHRoID0gMTAwMCwgICMgU2V0IHdpZHRoIHRvIG1ha2UgdGhlIG1hcCB3aWRlcg0KICAgIGhlaWdodCA9IDUwMCwgICMgU2V0IGhlaWdodCBhcHByb3ByaWF0ZWx5DQogICAgdGl0bGUgPSBsaXN0KHRleHQgPSAnTnVtYmVyIG9mIFN0YXJ0dXBzIGJ5IENvdW50cnkgYW5kIEludmVzdG1lbnQgU2l6ZScsIHggPSAwLjUsIHkgPSAwLjk1LCBmb250ID0gbGlzdChzaXplID0gMjApKSwNCiAgICBtYXJnaW4gPSBsaXN0KHQgPSA1MCwgYiA9IDUwKQ0KICApDQoNCiMgRGlzcGxheSB0aGUgaW50ZXJhY3RpdmUgbWFwDQpwX2ludGVyYWN0aXZlDQoNCg0KYGBgDQoNCioqKioqDQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkoc2NhbGVzKQ0KDQojIExvYWQgdGhlIGRhdGENCmRhdGEgPC0gcmVhZF9leGNlbCgibGlua2VkaW5faW5mby54bHN4IikNCg0KIyBQcmVwcm9jZXNzIHRoZSBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50IGNvbHVtbg0KZGF0YSA8LSBkYXRhICU+JQ0KICBmaWx0ZXIoIWdyZXBsKCJMYXN0IHJvdW5kIGFtb3VudCBub3QgZm91bmQiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKSAlPiUNCiAgbXV0YXRlKA0KICAgIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCA9IGdzdWIoIlVTXFwkICIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApLA0KICAgIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCA9IGlmZWxzZShncmVwbCgiTSIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKHN1YigiTSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKSAqIDFlNiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiSyIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyhzdWIoIksiLCAiIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgKiAxZTMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyhgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKSkNCiAgKQ0KDQojIENhbGN1bGF0ZSBxdWFydGlsZXMgZm9yIHRoZSBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50DQpxdWFydGlsZXMgPC0gcXVhbnRpbGUoZGF0YSRgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAsIHByb2JzID0gYygwLjI1LCAwLjUsIDAuNzUpLCBuYS5ybSA9IFRSVUUpDQoNCiMgRnVuY3Rpb24gdG8gZXN0aW1hdGUgc2l6ZSBiYXNlZCBvbiBpbnZlc3RtZW50IHF1YXJ0aWxlcw0KZXN0aW1hdGVfaW52ZXN0bWVudF9zaXplIDwtIGZ1bmN0aW9uKGludmVzdG1lbnQpIHsNCiAgaWYgKGlzLm5hKGludmVzdG1lbnQpKSB7DQogICAgcmV0dXJuKCJVbmtub3duIikNCiAgfSBlbHNlIGlmIChpbnZlc3RtZW50IDw9IHF1YXJ0aWxlc1sxXSkgew0KICAgIHJldHVybigiU21hbGwiKQ0KICB9IGVsc2UgaWYgKGludmVzdG1lbnQgPD0gcXVhcnRpbGVzWzJdKSB7DQogICAgcmV0dXJuKCJNZWRpdW0iKQ0KICB9IGVsc2UgaWYgKGludmVzdG1lbnQgPD0gcXVhcnRpbGVzWzNdKSB7DQogICAgcmV0dXJuKCJMYXJnZSIpDQogIH0gZWxzZSB7DQogICAgcmV0dXJuKCJWZXJ5IExhcmdlIikNCiAgfQ0KfQ0KDQojIEFwcGx5IHRoZSBmdW5jdGlvbiB0byBlc3RpbWF0ZSBzaXplIGJhc2VkIG9uIGludmVzdG1lbnQNCmRhdGEkRXN0aW1hdGVkX0ludmVzdG1lbnRfU2l6ZSA8LSBzYXBwbHkoZGF0YSRgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAsIGVzdGltYXRlX2ludmVzdG1lbnRfc2l6ZSkNCg0KIyBBZ2dyZWdhdGUgZGF0YSBieSBjb3VudHJ5IGFuZCBlc3RpbWF0ZWQgaW52ZXN0bWVudCBzaXplDQppbnZlc3RtZW50X2NvdW50cyA8LSBkYXRhICU+JQ0KICBncm91cF9ieShDb3VudHJ5LCBFc3RpbWF0ZWRfSW52ZXN0bWVudF9TaXplKSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQojIENvbnZlcnQgSVNPIGNvdW50cnkgY29kZXMgdG8gY291bnRyeSBuYW1lcw0KaW52ZXN0bWVudF9jb3VudHMkQ291bnRyeSA8LSBjb3VudHJ5Y29kZShpbnZlc3RtZW50X2NvdW50cyRDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIikNCmludmVzdG1lbnRfY291bnRzJENvdW50cnlbaXMubmEoaW52ZXN0bWVudF9jb3VudHMkQ291bnRyeSldIDwtICJVbmtub3duIg0KDQojIFNwcmVhZCB0aGUgZGF0YSB0byBoYXZlIGludmVzdG1lbnQgc2l6ZXMgYXMgY29sdW1ucw0KdGFibGVfZGF0YSA8LSBpbnZlc3RtZW50X2NvdW50cyAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVzdGltYXRlZF9JbnZlc3RtZW50X1NpemUsIHZhbHVlc19mcm9tID0gQ291bnQsIHZhbHVlc19maWxsID0gbGlzdChDb3VudCA9IDApKSAlPiUNCiAgbXV0YXRlKFRvdGFsID0gcm93U3VtcyhzZWxlY3QoLiwgLUNvdW50cnkpKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhUb3RhbCkpICMgU29ydCBieSBUb3RhbCBpbiBkZXNjZW5kaW5nIG9yZGVyDQoNCiMgQ3VzdG9tIGNvbG9yIHNjYWxlIGZ1bmN0aW9uIGZvciB0aGUgVG90YWwgY29sdW1uIChncmVlbiBwYWxldHRlKQ0KY29sb3Jfc2NhbGVfdG90YWwgPC0gZnVuY3Rpb24oeCkgew0KICBjb2wgPC0gc2NhbGVzOjpjb2xfbnVtZXJpYyhwYWxldHRlID0gYygiI2U1ZjVlMCIsICIjYTFkOTliIiwgIiMzMWEzNTQiKSwgZG9tYWluID0gcmFuZ2UoeCwgbmEucm0gPSBUUlVFKSkoeCkNCiAgcmV0dXJuKGNvbCkNCn0NCg0KIyBBcHBseSB0aGUgY29sb3Igc2NhbGUgdG8gdGhlIFRvdGFsIGNvbHVtbg0KdGFibGVfZGF0YSRUb3RhbF9jb2xvciA8LSBjb2xvcl9zY2FsZV90b3RhbCh0YWJsZV9kYXRhJFRvdGFsKQ0KDQojIENyZWF0ZSB0aGUgdGFibGUgd2l0aCBrYWJsZQ0Ka2FibGUodGFibGVfZGF0YSAlPiUgc2VsZWN0KC1Ub3RhbF9jb2xvciksIGNvbC5uYW1lcyA9IGMoIkNvdW50cnkiLCAiU21hbGwiLCAiTWVkaXVtIiwgIkxhcmdlIiwgIlZlcnkgTGFyZ2UiLCAiVW5rbm93biIsICJUb3RhbCIpLCBhbGlnbiA9ICdjJykgJT4lDQogIGFkZF9oZWFkZXJfYWJvdmUoYygiU2l6ZSBiYXNlZCBvbiBsYXN0IHJvdW5kIGFtb3VudCIgPSA3KSkgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiKSAlPiUNCiAgY29sdW1uX3NwZWMoMSwgYm9sZCA9IFRSVUUpICU+JQ0KICBjb2x1bW5fc3BlYyg3LCBiYWNrZ3JvdW5kID0gdGFibGVfZGF0YSRUb3RhbF9jb2xvciwgYm9sZCA9IFRSVUUpICU+JQ0KICBzY3JvbGxfYm94KGhlaWdodCA9ICI1MDBweCIsIHdpZHRoID0gIjEwMCUiKQ0KDQpgYGANCg0KIyMjDQoNCioqKioNCjxoNiBjbGFzcz0ic2VjdGlvbi1zdWJ0aXRsZSIgaWQ9ImRlc2Fycm9sbG8iIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtd2VpZ2h0OiBib2xkOyI+DQogIDxzcGFuIHN0eWxlPSdjb2xvcjojMmE5MTM0OyBmb250LXNpemU6IDE2cHg7Jz5UaW1lIGFuYWx5c2lzPC9zcGFuPg0KPC9oNj4NCioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZTlmNWRiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij7wn5OEIDxiPkJ5IGNvdW50cnk8L2I+PC9zcGFuPg0KPC9wPg0KDQojIyMjICB7LnRhYnNldH0NCg0KDQojIyMjIyBOdW1iZXIgb2Ygc3RhcnR1cHMNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyBzdGFja2VkIGJhciBjaGFydCBpbGx1c3RyYXRlcyB0aGUgbnVtYmVyIG9mIGNvbXBhbmllcyByZWNlaXZpbmcgaW52ZXN0bWVudHMgZWFjaCB5ZWFyLCBicm9rZW4gZG93biBieSBjb3VudHJ5LiBFYWNoIGJhciByZXByZXNlbnRzIGEgeWVhciwgYW5kIHRoZSBkaWZmZXJlbnQgY29sb3JlZCBzZWdtZW50cyB3aXRoaW4gZWFjaCBiYXIgZGVub3RlIHRoZSBudW1iZXIgb2YgY29tcGFuaWVzIGZyb20gdmFyaW91cyBjb3VudHJpZXMgdGhhdCByZWNlaXZlZCBpbnZlc3RtZW50cyBpbiB0aGF0IHBhcnRpY3VsYXIgeWVhci4gVGhlIGxlZ2VuZCBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlIGlkZW50aWZpZXMgdGhlIGNvdW50cmllcyBjb3JyZXNwb25kaW5nIHRvIGVhY2ggY29sb3IuIFRoaXMgdmlzdWFsaXphdGlvbiBoZWxwcyB0cmFjayBpbnZlc3RtZW50IHRyZW5kcyBvdmVyIHRpbWUgYW5kIGhpZ2hsaWdodHMgd2hpY2ggY291bnRyaWVzIGhhdmUgc2VlbiBpbmNyZWFzaW5nIG9yIGRlY3JlYXNpbmcgaW52ZXN0bWVudCBhY3Rpdml0eSBpbiB0aGUgRWRUZWNoIHNlY3Rvci48L3A+DQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCiMgTG9hZCB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoY291bnRyeWNvZGUpDQoNCiMgTG9hZCB0aGUgZGF0YSAoQXNzdW1pbmcgeW91ciBkYXRhIGlzIGluIGEgc3ByZWFkc2hlZXQgbmFtZWQgImxpbmtlZGluX2luZm8ueGxzeCIpDQpkYXRhIDwtIHJlYWRfZXhjZWwoImxpbmtlZGluX2luZm8ueGxzeCIpDQoNCiMgUHJlcHJvY2VzcyB0aGUgZGF0YQ0KZGF0YSA8LSBkYXRhICU+JQ0KICBmaWx0ZXIoIWdyZXBsKCJMYXN0IHJvdW5kIGRhdGUgbm90IGZvdW5kIiwgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSkgJT4lDQogIGZpbHRlcighaXMubmEoYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSkgJT4lDQogIG11dGF0ZSgNCiAgICBgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWAgPSB5bWQoYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSwNCiAgICBZZWFyID0geWVhcihgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApLA0KICAgIENvdW50cnlfTmFtZSA9IGNvdW50cnljb2RlKENvdW50cnksICJpc28yYyIsICJjb3VudHJ5Lm5hbWUiKQ0KICApDQoNCiMgU3VtbWFyaXplIGRhdGEgYnkgWWVhciBhbmQgQ291bnRyeQ0KeWVhcmx5X2RhdGEgPC0gZGF0YSAlPiUNCiAgZ3JvdXBfYnkoQ291bnRyeV9OYW1lLCBZZWFyKSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQojIEdldCB0aGUgbGlzdCBvZiB1bmlxdWUgY291bnRyeSBuYW1lcyBpbiB0aGUgY2hhcnQNCnVuaXF1ZV9jb3VudHJpZXMgPC0gdW5pcXVlKHllYXJseV9kYXRhJENvdW50cnlfTmFtZSkNCg0KIyBDcmVhdGUgYW4gaW50ZXJhY3RpdmUgcGxvdCB1c2luZyBwbG90bHkNCnBsb3RfeWVhciA8LSBwbG90X2x5KCkNCg0KIyBBZGQgZWFjaCBjb3VudHJ5J3MgZGF0YSBhcyBhIHNlcGFyYXRlIHRyYWNlDQpmb3IgKGNvdW50cnkgaW4gdW5pcXVlX2NvdW50cmllcykgew0KICBjb3VudHJ5X2RhdGEgPC0geWVhcmx5X2RhdGEgJT4lIGZpbHRlcihDb3VudHJ5X05hbWUgPT0gY291bnRyeSkNCiAgcGxvdF95ZWFyIDwtIGFkZF90cmFjZSgNCiAgICBwbG90X3llYXIsDQogICAgZGF0YSA9IGNvdW50cnlfZGF0YSwNCiAgICB4ID0gflllYXIsDQogICAgeSA9IH5Db3VudCwNCiAgICBuYW1lID0gY291bnRyeSwNCiAgICB0eXBlID0gJ2JhcicsDQogICAgdGV4dCA9IH5wYXN0ZSgiQ291bnRyeToiLCBDb3VudHJ5X05hbWUsICI8YnI+WWVhcjoiLCBZZWFyLCAiPGJyPkNvdW50OiIsIENvdW50KSwgICMgRGVmaW5lIGhvdmVyIHRleHQNCiAgICBob3ZlcmluZm8gPSAndGV4dCcgICMgU2hvdyBob3ZlciBpbmZvcm1hdGlvbg0KICApDQp9DQoNCiMgQWRkIGEgY291bnRyeSBzZWxlY3RvciAob3B0aW9uYWwpDQojIFlvdSBjYW4gY29tbWVudCBvdXQgdGhpcyBzZWN0aW9uIGlmIHlvdSBkb24ndCB3YW50IHRoZSBkcm9wZG93biBtZW51IGZvciBzZWxlY3RpbmcgY291bnRyaWVzDQoNCmNvdW50cnlfYnV0dG9ucyA8LSBsaXN0KA0KICBsaXN0KA0KICAgIG1ldGhvZCA9ICJyZXN0eWxlIiwNCiAgICBhcmdzID0gbGlzdCgidmlzaWJsZSIsIHJlcChUUlVFLCBsZW5ndGgodW5pcXVlX2NvdW50cmllcykpKSwNCiAgICBsYWJlbCA9ICJBbGwgQ291bnRyaWVzIg0KICApDQopDQoNCmNvdW50cnlfYnV0dG9ucyA8LSBjKGNvdW50cnlfYnV0dG9ucywgbGFwcGx5KHNlcV9hbG9uZyh1bmlxdWVfY291bnRyaWVzKSwgZnVuY3Rpb24oaSkgew0KICB2aXNpYmlsaXR5IDwtIHJlcChGQUxTRSwgbGVuZ3RoKHVuaXF1ZV9jb3VudHJpZXMpKQ0KICB2aXNpYmlsaXR5W2ldIDwtIFRSVUUNCiAgbGlzdCgNCiAgICBtZXRob2QgPSAicmVzdHlsZSIsDQogICAgYXJncyA9IGxpc3QoInZpc2libGUiLCB2aXNpYmlsaXR5KSwNCiAgICBsYWJlbCA9IHVuaXF1ZV9jb3VudHJpZXNbaV0NCiAgKQ0KfSkpDQoNCnBsb3RfeWVhciA8LSBwbG90X3llYXIgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZSA9ICJDb21wYW5pZXMgSW52ZXN0ZWQgYnkgWWVhciIsDQogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlllYXIiLCBkdGljayA9IDEpLA0KICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJOdW1iZXIgb2YgQ29tcGFuaWVzIiksDQogICAgYmFybW9kZSA9ICdzdGFjaycsDQogICAgaG92ZXJtb2RlID0gJ2Nsb3Nlc3QnLA0KICAgIHdpZHRoID0gMTAwMCwgICMgU2V0IHRoZSB3aWR0aCBvZiB0aGUgcGxvdA0KICAgIHVwZGF0ZW1lbnVzID0gbGlzdCggICMgQ29tbWVudCBvdXQgdGhpcyBzZWN0aW9uIHRvIHJlbW92ZSB0aGUgZHJvcGRvd24gbWVudQ0KICAgICAgbGlzdCgNCiAgICAgICAgdHlwZSA9ICJkcm9wZG93biIsDQogICAgICAgIGFjdGl2ZSA9IDAsDQogICAgICAgIGJ1dHRvbnMgPSBjb3VudHJ5X2J1dHRvbnMsDQogICAgICAgIHggPSAwLjg1LCAgIyBBZGp1c3QgcG9zaXRpb24NCiAgICAgICAgeGFuY2hvciA9ICdsZWZ0JywNCiAgICAgICAgeSA9IDEuMTUsDQogICAgICAgIHlhbmNob3IgPSAndG9wJw0KICAgICAgKQ0KICAgICkNCiAgKQ0KDQojIERpc3BsYXkgdGhlIGludGVyYWN0aXZlIHBsb3QNCnBsb3RfeWVhcg0KDQpgYGANCg0KIyMjIyMgQW1vdW50IG9mIGludmVzdG1lbnRzDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoaXMgc3RhY2tlZCBiYXIgY2hhcnQgaWxsdXN0cmF0ZXMgdGhlIHRvdGFsIGFtb3VudCBvZiBpbnZlc3RtZW50IHJlY2VpdmVkIGJ5IGNvbXBhbmllcyBlYWNoIHllYXIsIGJyb2tlbiBkb3duIGJ5IGNvdW50cnkuIEVhY2ggYmFyIHJlcHJlc2VudHMgYSB5ZWFyLCBhbmQgdGhlIGRpZmZlcmVudCBjb2xvcmVkIHNlZ21lbnRzIHdpdGhpbiBlYWNoIGJhciBkZW5vdGUgdGhlIHRvdGFsIGludmVzdG1lbnQgcmVjZWl2ZWQgYnkgY29tcGFuaWVzIGZyb20gdmFyaW91cyBjb3VudHJpZXMgaW4gdGhhdCBwYXJ0aWN1bGFyIHllYXIuIFRoZSBsZWdlbmQgb24gdGhlIHJpZ2h0LWhhbmQgc2lkZSBpZGVudGlmaWVzIHRoZSBjb3VudHJpZXMgY29ycmVzcG9uZGluZyB0byBlYWNoIGNvbG9yLiBUaGlzIHZpc3VhbGl6YXRpb24gaGVscHMgdHJhY2sgaW52ZXN0bWVudCB0cmVuZHMgb3ZlciB0aW1lIGFuZCBoaWdobGlnaHRzIHdoaWNoIGNvdW50cmllcyBoYXZlIHJlY2VpdmVkIHRoZSBtb3N0IHNpZ25pZmljYW50IGZpbmFuY2lhbCBpbnZlc3RtZW50cyBpbiB0aGUgRWRUZWNoIHNlY3Rvci48L3A+DQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQojIExvYWQgdGhlIG5lY2Vzc2FyeSBsaWJyYXJpZXMNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KDQojIExvYWQgdGhlIGRhdGEgKEFzc3VtaW5nIHlvdXIgZGF0YSBpcyBpbiBhIHNwcmVhZHNoZWV0IG5hbWVkICJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KDQojIFByZXByb2Nlc3MgdGhlIGRhdGENCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBkYXRlIG5vdCBmb3VuZCIsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBtdXRhdGUoDQogICAgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgID0geW1kKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCksDQogICAgWWVhciA9IHllYXIoYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSwNCiAgICBDb3VudHJ5X05hbWUgPSBjb3VudHJ5Y29kZShDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIiksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gY2FzZV93aGVuKA0KICAgICAgZ3JlcGwoIk0iLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LA0KICAgICAgZ3JlcGwoIksiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWUzLA0KICAgICAgVFJVRSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKQ0KICAgICkgICMgS2VlcCB0aGUgYW1vdW50IGluIG9yaWdpbmFsIHVuaXRzDQogICkNCg0KIyBDaGVjayBpZiB0aGUgY29udmVyc2lvbiBpcyBjb3JyZWN0DQpkYXRhIDwtIGRhdGEgJT4lIGZpbHRlcighaXMubmEoYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkNCg0KIyBTdW1tYXJpemUgZGF0YSBieSBZZWFyIGFuZCBDb3VudHJ5IHdpdGggdG90YWwgaW52ZXN0bWVudCBhbW91bnQNCnllYXJseV9kYXRhIDwtIGRhdGEgJT4lDQogIGdyb3VwX2J5KENvdW50cnlfTmFtZSwgWWVhcikgJT4lDQogIHN1bW1hcmlzZShUb3RhbF9JbnZlc3RtZW50ID0gc3VtKGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICdkcm9wJykNCg0KIyBHZXQgdGhlIGxpc3Qgb2YgdW5pcXVlIGNvdW50cnkgbmFtZXMgaW4gdGhlIGNoYXJ0DQp1bmlxdWVfY291bnRyaWVzIDwtIHVuaXF1ZSh5ZWFybHlfZGF0YSRDb3VudHJ5X05hbWUpDQoNCiMgQ3JlYXRlIGFuIGludGVyYWN0aXZlIHBsb3QgdXNpbmcgcGxvdGx5DQpwbG90X3llYXIgPC0gcGxvdF9seSgpDQoNCiMgQWRkIGVhY2ggY291bnRyeSdzIGRhdGEgYXMgYSBzZXBhcmF0ZSB0cmFjZQ0KZm9yIChjb3VudHJ5IGluIHVuaXF1ZV9jb3VudHJpZXMpIHsNCiAgY291bnRyeV9kYXRhIDwtIHllYXJseV9kYXRhICU+JSBmaWx0ZXIoQ291bnRyeV9OYW1lID09IGNvdW50cnkpDQogIHBsb3RfeWVhciA8LSBhZGRfdHJhY2UoDQogICAgcGxvdF95ZWFyLA0KICAgIGRhdGEgPSBjb3VudHJ5X2RhdGEsDQogICAgeCA9IH5ZZWFyLA0KICAgIHkgPSB+VG90YWxfSW52ZXN0bWVudCwNCiAgICBuYW1lID0gY291bnRyeSwNCiAgICB0eXBlID0gJ2JhcicsDQogICAgdGV4dCA9IH5wYXN0ZSgiQ291bnRyeToiLCBDb3VudHJ5X05hbWUsICI8YnI+WWVhcjoiLCBZZWFyLCAiPGJyPlRvdGFsIEludmVzdG1lbnQ6ICQiLCBmb3JtYXQoVG90YWxfSW52ZXN0bWVudCwgYmlnLm1hcmsgPSAiLCIpKSwgICMgRGVmaW5lIGhvdmVyIHRleHQNCiAgICBob3ZlcmluZm8gPSAndGV4dCcgICMgU2hvdyBob3ZlciBpbmZvcm1hdGlvbg0KICApDQp9DQoNCiMgQWRkIGEgY291bnRyeSBzZWxlY3Rvcg0KY291bnRyeV9idXR0b25zIDwtIGxpc3QoDQogIGxpc3QoDQogICAgbWV0aG9kID0gInJlc3R5bGUiLA0KICAgIGFyZ3MgPSBsaXN0KCJ2aXNpYmxlIiwgcmVwKFRSVUUsIGxlbmd0aCh1bmlxdWVfY291bnRyaWVzKSkpLA0KICAgIGxhYmVsID0gIkFsbCBDb3VudHJpZXMiDQogICkNCikNCg0KY291bnRyeV9idXR0b25zIDwtIGMoY291bnRyeV9idXR0b25zLCBsYXBwbHkoc2VxX2Fsb25nKHVuaXF1ZV9jb3VudHJpZXMpLCBmdW5jdGlvbihpKSB7DQogIHZpc2liaWxpdHkgPC0gcmVwKEZBTFNFLCBsZW5ndGgodW5pcXVlX2NvdW50cmllcykpDQogIHZpc2liaWxpdHlbaV0gPC0gVFJVRQ0KICBsaXN0KA0KICAgIG1ldGhvZCA9ICJyZXN0eWxlIiwNCiAgICBhcmdzID0gbGlzdCgidmlzaWJsZSIsIHZpc2liaWxpdHkpLA0KICAgIGxhYmVsID0gdW5pcXVlX2NvdW50cmllc1tpXQ0KICApDQp9KSkNCg0KcGxvdF95ZWFyIDwtIHBsb3RfeWVhciAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIlRvdGFsIEludmVzdG1lbnQgUmVjZWl2ZWQgYnkgWWVhciIsDQogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlllYXIiLCBkdGljayA9IDEpLA0KICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJUb3RhbCBJbnZlc3RtZW50IChVU0QpIiksDQogICAgYmFybW9kZSA9ICdzdGFjaycsDQogICAgaG92ZXJtb2RlID0gJ2Nsb3Nlc3QnLA0KICAgIHdpZHRoID0gMTAwMCwgICMgU2V0IHRoZSB3aWR0aCBvZiB0aGUgcGxvdA0KICAgIHVwZGF0ZW1lbnVzID0gbGlzdCgNCiAgICAgIGxpc3QoDQogICAgICAgIHR5cGUgPSAiZHJvcGRvd24iLA0KICAgICAgICBhY3RpdmUgPSAwLA0KICAgICAgICBidXR0b25zID0gY291bnRyeV9idXR0b25zLA0KICAgICAgICB4ID0gMC44NSwgICMgQWRqdXN0IHBvc2l0aW9uDQogICAgICAgIHhhbmNob3IgPSAnbGVmdCcsDQogICAgICAgIHkgPSAxLjE1LA0KICAgICAgICB5YW5jaG9yID0gJ3RvcCcNCiAgICAgICkNCiAgICApDQogICkNCg0KIyBEaXNwbGF5IHRoZSBpbnRlcmFjdGl2ZSBwbG90DQpwbG90X3llYXINCg0KDQpgYGANCg0KIyMjDQoNCioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZTlmNWRiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij7wn5OEIDxiPkJ5IFZlcnRpY2FsPC9iPjwvc3Bhbj4NCjwvcD4NCg0KIyMjIyAgey50YWJzZXR9DQoNCg0KIyMjIyMgTnVtYmVyIG9mIHN0YXJ0dXBzDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoaXMgc3RhY2tlZCBiYXIgY2hhcnQgZGlzcGxheXMgdGhlIG51bWJlciBvZiBjb21wYW5pZXMgYnkgeWVhciwgY2F0ZWdvcml6ZWQgYnkgdmVydGljYWxzLiBFYWNoIGJhciByZXByZXNlbnRzIGEgeWVhciwgYW5kIHRoZSBkaWZmZXJlbnQgY29sb3JlZCBzZWdtZW50cyB3aXRoaW4gZWFjaCBiYXIgZGVub3RlIHRoZSBudW1iZXIgb2YgY29tcGFuaWVzIHdpdGhpbiBzcGVjaWZpYyB2ZXJ0aWNhbHMgZm9yIHRoYXQgcGFydGljdWxhciB5ZWFyLiBUaGUgbGVnZW5kIG9uIHRoZSByaWdodC1oYW5kIHNpZGUgaWRlbnRpZmllcyB0aGUgdmVydGljYWxzIGNvcnJlc3BvbmRpbmcgdG8gZWFjaCBjb2xvci4gVGhpcyB2aXN1YWxpemF0aW9uIGhlbHBzIHRyYWNrIHRyZW5kcyBvdmVyIHRpbWUgYW5kIGhpZ2hsaWdodHMgdGhlIGdyb3d0aCBvciBkZWNsaW5lIG9mIGNvbXBhbmllcyB3aXRoaW4gZWFjaCB2ZXJ0aWNhbCBpbiB0aGUgRWRUZWNoIHNlY3Rvci48L3A+DQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQo8c3Ryb25nPk5vdGU6PC9zdHJvbmc+IFRoZSB2ZXJ0aWNhbHMgd2VyZSBkZWZpbmVkIGFuZCBzZWxlY3RlZCBieSB0aGUgRWR1TmV4dCB0ZWFtLCBhbmQgdGhlIGRldGFpbGVkIGRlZmluaXRpb25zIG9mIHRoZXNlIHZlcnRpY2FscyBhcmUgcHJvdmlkZWQgZWFybGllciBpbiB0aGUgcmVwb3J0LjwvcD4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCiMgQ2FyZ2FyIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KbGlicmFyeShEVCkNCg0KIyBDYXJnYXIgbG9zIGRhdG9zIChBc3VtaWVuZG8gcXVlIGxvcyBkYXRvcyBlc3TDoW4gZW4gdW5hIGhvamEgbGxhbWFkYSAibGlua2VkaW5faW5mby54bHN4IikNCmRhdGEgPC0gcmVhZF9leGNlbCgibGlua2VkaW5faW5mby54bHN4IikNCg0KIyBQcmVwcm9jZXNhciBsb3MgZGF0b3MNCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBkYXRlIG5vdCBmb3VuZCIsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBtdXRhdGUoDQogICAgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgID0geW1kKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCksDQogICAgWWVhciA9IGFzLmludGVnZXIoeWVhcihgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApKSwNCiAgICBDb3VudHJ5X05hbWUgPSBjb3VudHJ5Y29kZShDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIiksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gY2FzZV93aGVuKA0KICAgICAgZ3JlcGwoIk0iLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LA0KICAgICAgZ3JlcGwoIksiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWUzLA0KICAgICAgVFJVRSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKQ0KICAgICkgICMgTWFudGVuZXIgZWwgbW9udG8gZW4gdW5pZGFkZXMgb3JpZ2luYWxlcw0KICApDQoNCiMgQ2FyZ2FyIGxvcyBkYXRvcyBhZGljaW9uYWxlcyBjb24gbGEgaW5mb3JtYWNpw7NuIGRlIGxvcyB2ZXJ0aWNhbGVzIHBvdGVuY2lhbGVzDQphZGRpdGlvbmFsX2RhdGEgPC0gcmVhZF9leGNlbCgiZmluYWxfb3V0cHV0Lnhsc3giKQ0KDQojIEZ1c2lvbmFyIGxvcyBjb25qdW50b3MgZGUgZGF0b3MgYmFzYWRvcyBlbiBlbCBub21icmUgZGUgbGEgZW1wcmVzYQ0KbWVyZ2VkX2RhdGEgPC0gbWVyZ2UoZGF0YSwgYWRkaXRpb25hbF9kYXRhLCBieSA9ICJDb21wYW55IE5hbWUiKQ0KDQojIFJlc3VtaXIgZGF0b3MgcG9yIGHDsW8geSB2ZXJ0aWNhbCBwb3RlbmNpYWwgY29udGFuZG8gZWwgbsO6bWVybyBkZSBlbXByZXNhcw0KeWVhcmx5X3ZlcnRpY2FsX2RhdGEgPC0gbWVyZ2VkX2RhdGEgJT4lDQogIGdyb3VwX2J5KGBQb3RlbnRpYWwgVmVydGljYWxgLCBZZWFyKSAlPiUNCiAgc3VtbWFyaXNlKENvbXBhbnlfQ291bnQgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpDQoNCiMgT2J0ZW5lciBsYSBsaXN0YSBkZSB2ZXJ0aWNhbGVzIHBvdGVuY2lhbGVzIMO6bmljb3MgZW4gZWwgZ3LDoWZpY28NCnVuaXF1ZV92ZXJ0aWNhbHMgPC0gdW5pcXVlKHllYXJseV92ZXJ0aWNhbF9kYXRhJGBQb3RlbnRpYWwgVmVydGljYWxgKQ0KDQojIENyZWFyIGxvcyBib3RvbmVzIHBhcmEgc2VsZWNjaW9uYXIgbG9zIHZlcnRpY2FsZXMNCnZlcnRpY2FsX2J1dHRvbnMgPC0gbGlzdCgNCiAgbGlzdCgNCiAgICBtZXRob2QgPSAicmVzdHlsZSIsDQogICAgYXJncyA9IGxpc3QoInZpc2libGUiLCByZXAoVFJVRSwgbGVuZ3RoKHVuaXF1ZV92ZXJ0aWNhbHMpKSksDQogICAgbGFiZWwgPSAiQWxsIFZlcnRpY2FscyINCiAgKQ0KKQ0KDQp2ZXJ0aWNhbF9idXR0b25zIDwtIGModmVydGljYWxfYnV0dG9ucywgbGFwcGx5KHNlcV9hbG9uZyh1bmlxdWVfdmVydGljYWxzKSwgZnVuY3Rpb24oaSkgew0KICB2aXNpYmlsaXR5IDwtIHJlcChGQUxTRSwgbGVuZ3RoKHVuaXF1ZV92ZXJ0aWNhbHMpKQ0KICB2aXNpYmlsaXR5W2ldIDwtIFRSVUUNCiAgbGlzdCgNCiAgICBtZXRob2QgPSAicmVzdHlsZSIsDQogICAgYXJncyA9IGxpc3QoInZpc2libGUiLCB2aXNpYmlsaXR5KSwNCiAgICBsYWJlbCA9IHVuaXF1ZV92ZXJ0aWNhbHNbaV0NCiAgKQ0KfSkpDQoNCiMgQ3JlYXIgdW4gZ3LDoWZpY28gaW50ZXJhY3Rpdm8gdXNhbmRvIHBsb3RseQ0KcGxvdF95ZWFyIDwtIHBsb3RfbHkoKQ0KDQojIEHDsWFkaXIgbG9zIGRhdG9zIGRlIGNhZGEgdmVydGljYWwgY29tbyB1bmEgdHJhemEgc2VwYXJhZGENCmZvciAodmVydGljYWwgaW4gdW5pcXVlX3ZlcnRpY2Fscykgew0KICB2ZXJ0aWNhbF9kYXRhIDwtIHllYXJseV92ZXJ0aWNhbF9kYXRhICU+JSBmaWx0ZXIoYFBvdGVudGlhbCBWZXJ0aWNhbGAgPT0gdmVydGljYWwpDQogIHBsb3RfeWVhciA8LSBhZGRfdHJhY2UoDQogICAgcGxvdF95ZWFyLA0KICAgIGRhdGEgPSB2ZXJ0aWNhbF9kYXRhLA0KICAgIHggPSB+WWVhciwNCiAgICB5ID0gfkNvbXBhbnlfQ291bnQsDQogICAgbmFtZSA9IHZlcnRpY2FsLA0KICAgIHR5cGUgPSAnYmFyJywNCiAgICB0ZXh0ID0gfnBhc3RlKCJWZXJ0aWNhbDoiLCBgUG90ZW50aWFsIFZlcnRpY2FsYCwgIjxicj5ZZWFyOiIsIFllYXIsICI8YnI+Q29tcGFueSBDb3VudDoiLCBDb21wYW55X0NvdW50KSwgICMgRGVmaW5pciB0ZXh0byBlbWVyZ2VudGUNCiAgICBob3ZlcmluZm8gPSAndGV4dCcgICMgTW9zdHJhciBpbmZvcm1hY2nDs24gZW1lcmdlbnRlDQogICkNCn0NCg0KIyBEZWZpbmlyIGVsIGRpc2XDsW8gZGVsIGdyw6FmaWNvDQpwbG90X3llYXIgPC0gcGxvdF95ZWFyICU+JQ0KICBsYXlvdXQoDQogICAgdGl0bGUgPSBsaXN0KA0KICAgICAgdGV4dCA9ICJOdW1iZXIgb2YgQ29tcGFuaWVzIGJ5IFllYXIgYW5kIFZlcnRpY2FsIiwNCiAgICAgIHggPSAwLjUsDQogICAgICB4YW5jaG9yID0gJ2NlbnRlcicsDQogICAgICB5ID0gMC44NSwNCiAgICAgIHlhbmNob3IgPSAndG9wJw0KICAgICksDQogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlllYXIiLCBkdGljayA9IDEpLA0KICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJOdW1iZXIgb2YgQ29tcGFuaWVzIiksDQogICAgYmFybW9kZSA9ICdzdGFjaycsDQogICAgaG92ZXJtb2RlID0gJ2Nsb3Nlc3QnLA0KICAgIHNob3dsZWdlbmQgPSBGQUxTRSwgICMgT2N1bHRhciBsYSBsZXllbmRhDQogICAgd2lkdGggPSAxMDAwLCAgIyBFc3RhYmxlY2VyIGVsIGFuY2hvIGRlbCBncsOhZmljbw0KICAgIG1hcmdpbiA9IGxpc3QodCA9IDIwMCksICAjIEF1bWVudGFyIGVsIG1hcmdlbiBzdXBlcmlvciBwYXJhIGhhY2VyIGVzcGFjaW8gcGFyYSBlbCBtZW7DuiBkZXNwbGVnYWJsZQ0KICAgIHVwZGF0ZW1lbnVzID0gbGlzdCgNCiAgICAgIGxpc3QoDQogICAgICAgIHR5cGUgPSAiZHJvcGRvd24iLA0KICAgICAgICBhY3RpdmUgPSAwLA0KICAgICAgICBidXR0b25zID0gdmVydGljYWxfYnV0dG9ucywNCiAgICAgICAgeCA9IDAuNSwgICMgUG9zaWNpw7NuIGNlbnRyYWRhDQogICAgICAgIHhhbmNob3IgPSAnY2VudGVyJywNCiAgICAgICAgeSA9IDEuMywNCiAgICAgICAgeWFuY2hvciA9ICd0b3AnDQogICAgICApDQogICAgKQ0KICApDQoNCiMgTW9zdHJhciBlbCBncsOhZmljbyBpbnRlcmFjdGl2bw0KcGxvdF95ZWFyDQoNCg0KYGBgDQoNCg0KDQojIyMjIyBBbW91bnQgb2YgaW52ZXN0bWVudA0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGlzIHN0YWNrZWQgYmFyIGNoYXJ0IGRpc3BsYXlzIHRoZSB0b3RhbCBhbW91bnQgb2YgaW52ZXN0bWVudCBieSB5ZWFyLCBjYXRlZ29yaXplZCBieSB2ZXJ0aWNhbHMuIEVhY2ggYmFyIHJlcHJlc2VudHMgYSB5ZWFyLCBhbmQgdGhlIGRpZmZlcmVudCBjb2xvcmVkIHNlZ21lbnRzIHdpdGhpbiBlYWNoIGJhciBkZW5vdGUgdGhlIHRvdGFsIGludmVzdG1lbnQgcmVjZWl2ZWQgYnkgY29tcGFuaWVzIHdpdGhpbiBzcGVjaWZpYyB2ZXJ0aWNhbHMgZm9yIHRoYXQgcGFydGljdWxhciB5ZWFyLiBUaGUgbGVnZW5kIG9uIHRoZSByaWdodC1oYW5kIHNpZGUgaWRlbnRpZmllcyB0aGUgdmVydGljYWxzIGNvcnJlc3BvbmRpbmcgdG8gZWFjaCBjb2xvci4gVGhpcyB2aXN1YWxpemF0aW9uIGhlbHBzIHRyYWNrIGludmVzdG1lbnQgdHJlbmRzIG92ZXIgdGltZSBhbmQgaGlnaGxpZ2h0cyB0aGUgZ3Jvd3RoIG9yIGRlY2xpbmUgb2YgaW52ZXN0bWVudCB3aXRoaW4gZWFjaCB2ZXJ0aWNhbCBpbiB0aGUgRWRUZWNoIHNlY3Rvci48L3A+DQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQo8c3Ryb25nPk5vdGU6PC9zdHJvbmc+IFRoZSB2ZXJ0aWNhbHMgd2VyZSBkZWZpbmVkIGFuZCBzZWxlY3RlZCBieSB0aGUgRWR1TmV4dCB0ZWFtLCBhbmQgdGhlIGRldGFpbGVkIGRlZmluaXRpb25zIG9mIHRoZXNlIHZlcnRpY2FscyBhcmUgcHJvdmlkZWQgZWFybGllciBpbiB0aGUgcmVwb3J0LjwvcD4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCiMgQ2FyZ2FyIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KbGlicmFyeShEVCkNCg0KIyBDYXJnYXIgbG9zIGRhdG9zIChBc3VtaWVuZG8gcXVlIGxvcyBkYXRvcyBlc3TDoW4gZW4gdW5hIGhvamEgbGxhbWFkYSAibGlua2VkaW5faW5mby54bHN4IikNCmRhdGEgPC0gcmVhZF9leGNlbCgibGlua2VkaW5faW5mby54bHN4IikNCg0KIyBQcmVwcm9jZXNhciBsb3MgZGF0b3MNCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBkYXRlIG5vdCBmb3VuZCIsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBtdXRhdGUoDQogICAgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgID0geW1kKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCksDQogICAgWWVhciA9IGFzLmludGVnZXIoeWVhcihgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApKSwNCiAgICBDb3VudHJ5X05hbWUgPSBjb3VudHJ5Y29kZShDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIiksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gY2FzZV93aGVuKA0KICAgICAgZ3JlcGwoIk0iLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LA0KICAgICAgZ3JlcGwoIksiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWUzLA0KICAgICAgVFJVRSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKQ0KICAgICkgICMgTWFudGVuZXIgZWwgbW9udG8gZW4gdW5pZGFkZXMgb3JpZ2luYWxlcw0KICApDQoNCiMgQ2FyZ2FyIGxvcyBkYXRvcyBhZGljaW9uYWxlcyBjb24gbGEgaW5mb3JtYWNpw7NuIGRlIGxvcyB2ZXJ0aWNhbGVzIHBvdGVuY2lhbGVzDQphZGRpdGlvbmFsX2RhdGEgPC0gcmVhZF9leGNlbCgiZmluYWxfb3V0cHV0Lnhsc3giKQ0KDQojIEZ1c2lvbmFyIGxvcyBjb25qdW50b3MgZGUgZGF0b3MgYmFzYWRvcyBlbiBlbCBub21icmUgZGUgbGEgZW1wcmVzYQ0KbWVyZ2VkX2RhdGEgPC0gbWVyZ2UoZGF0YSwgYWRkaXRpb25hbF9kYXRhLCBieSA9ICJDb21wYW55IE5hbWUiKQ0KDQojIFJlc3VtaXIgZGF0b3MgcG9yIGHDsW8geSB2ZXJ0aWNhbCBwb3RlbmNpYWwgc3VtYW5kbyBsYSBjYW50aWRhZCBkZSBpbnZlcnNpw7NuDQp5ZWFybHlfdmVydGljYWxfZGF0YSA8LSBtZXJnZWRfZGF0YSAlPiUNCiAgZ3JvdXBfYnkoYFBvdGVudGlhbCBWZXJ0aWNhbGAsIFllYXIpICU+JQ0KICBzdW1tYXJpc2UoVG90YWxfSW52ZXN0bWVudCA9IHN1bShgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAnZHJvcCcpDQoNCiMgT2J0ZW5lciBsYSBsaXN0YSBkZSB2ZXJ0aWNhbGVzIHBvdGVuY2lhbGVzIMO6bmljb3MgZW4gZWwgZ3LDoWZpY28NCnVuaXF1ZV92ZXJ0aWNhbHMgPC0gdW5pcXVlKHllYXJseV92ZXJ0aWNhbF9kYXRhJGBQb3RlbnRpYWwgVmVydGljYWxgKQ0KDQojIENyZWFyIGxvcyBib3RvbmVzIHBhcmEgc2VsZWNjaW9uYXIgbG9zIHZlcnRpY2FsZXMNCnZlcnRpY2FsX2J1dHRvbnMgPC0gbGlzdCgNCiAgbGlzdCgNCiAgICBtZXRob2QgPSAicmVzdHlsZSIsDQogICAgYXJncyA9IGxpc3QoInZpc2libGUiLCByZXAoVFJVRSwgbGVuZ3RoKHVuaXF1ZV92ZXJ0aWNhbHMpKSksDQogICAgbGFiZWwgPSAiQWxsIFZlcnRpY2FscyINCiAgKQ0KKQ0KDQp2ZXJ0aWNhbF9idXR0b25zIDwtIGModmVydGljYWxfYnV0dG9ucywgbGFwcGx5KHNlcV9hbG9uZyh1bmlxdWVfdmVydGljYWxzKSwgZnVuY3Rpb24oaSkgew0KICB2aXNpYmlsaXR5IDwtIHJlcChGQUxTRSwgbGVuZ3RoKHVuaXF1ZV92ZXJ0aWNhbHMpKQ0KICB2aXNpYmlsaXR5W2ldIDwtIFRSVUUNCiAgbGlzdCgNCiAgICBtZXRob2QgPSAicmVzdHlsZSIsDQogICAgYXJncyA9IGxpc3QoInZpc2libGUiLCB2aXNpYmlsaXR5KSwNCiAgICBsYWJlbCA9IHVuaXF1ZV92ZXJ0aWNhbHNbaV0NCiAgKQ0KfSkpDQoNCiMgQ3JlYXIgdW4gZ3LDoWZpY28gaW50ZXJhY3Rpdm8gdXNhbmRvIHBsb3RseQ0KcGxvdF95ZWFyIDwtIHBsb3RfbHkoKQ0KDQojIEHDsWFkaXIgbG9zIGRhdG9zIGRlIGNhZGEgdmVydGljYWwgY29tbyB1bmEgdHJhemEgc2VwYXJhZGENCmZvciAodmVydGljYWwgaW4gdW5pcXVlX3ZlcnRpY2Fscykgew0KICB2ZXJ0aWNhbF9kYXRhIDwtIHllYXJseV92ZXJ0aWNhbF9kYXRhICU+JSBmaWx0ZXIoYFBvdGVudGlhbCBWZXJ0aWNhbGAgPT0gdmVydGljYWwpDQogIHBsb3RfeWVhciA8LSBhZGRfdHJhY2UoDQogICAgcGxvdF95ZWFyLA0KICAgIGRhdGEgPSB2ZXJ0aWNhbF9kYXRhLA0KICAgIHggPSB+WWVhciwNCiAgICB5ID0gflRvdGFsX0ludmVzdG1lbnQsDQogICAgbmFtZSA9IHZlcnRpY2FsLA0KICAgIHR5cGUgPSAnYmFyJywNCiAgICB0ZXh0ID0gfnBhc3RlKCJWZXJ0aWNhbDoiLCBgUG90ZW50aWFsIFZlcnRpY2FsYCwgIjxicj5ZZWFyOiIsIFllYXIsICI8YnI+VG90YWwgSW52ZXN0bWVudDogJCIsIGZvcm1hdChUb3RhbF9JbnZlc3RtZW50LCBiaWcubWFyayA9ICIsIikpLCAgIyBEZWZpbmlyIHRleHRvIGVtZXJnZW50ZQ0KICAgIGhvdmVyaW5mbyA9ICd0ZXh0JyAgIyBNb3N0cmFyIGluZm9ybWFjacOzbiBlbWVyZ2VudGUNCiAgKQ0KfQ0KDQojIERlZmluaXIgZWwgZGlzZcOxbyBkZWwgZ3LDoWZpY28NCnBsb3RfeWVhciA8LSBwbG90X3llYXIgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZSA9IGxpc3QoDQogICAgICB0ZXh0ID0gIlRvdGFsIEludmVzdG1lbnQgYnkgWWVhciBhbmQgVmVydGljYWwiLA0KICAgICAgeCA9IDAuNSwNCiAgICAgIHhhbmNob3IgPSAnY2VudGVyJywNCiAgICAgIHkgPSAwLjg1LA0KICAgICAgeWFuY2hvciA9ICd0b3AnDQogICAgKSwNCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiWWVhciIsIGR0aWNrID0gMSksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlRvdGFsIEludmVzdG1lbnQgKFVTRCkiKSwNCiAgICBiYXJtb2RlID0gJ3N0YWNrJywNCiAgICBob3Zlcm1vZGUgPSAnY2xvc2VzdCcsDQogICAgc2hvd2xlZ2VuZCA9IEZBTFNFLCAgIyBPY3VsdGFyIGxhIGxleWVuZGENCiAgICB3aWR0aCA9IDEwMDAsICAjIEVzdGFibGVjZXIgZWwgYW5jaG8gZGVsIGdyw6FmaWNvDQogICAgbWFyZ2luID0gbGlzdCh0ID0gMjAwKSwgICMgQXVtZW50YXIgZWwgbWFyZ2VuIHN1cGVyaW9yIHBhcmEgaGFjZXIgZXNwYWNpbyBwYXJhIGVsIG1lbsO6IGRlc3BsZWdhYmxlDQogICAgdXBkYXRlbWVudXMgPSBsaXN0KA0KICAgICAgbGlzdCgNCiAgICAgICAgdHlwZSA9ICJkcm9wZG93biIsDQogICAgICAgIGFjdGl2ZSA9IDAsDQogICAgICAgIGJ1dHRvbnMgPSB2ZXJ0aWNhbF9idXR0b25zLA0KICAgICAgICB4ID0gMC41LCAgIyBQb3NpY2nDs24gY2VudHJhZGENCiAgICAgICAgeGFuY2hvciA9ICdjZW50ZXInLA0KICAgICAgICB5ID0gMS4zLA0KICAgICAgICB5YW5jaG9yID0gJ3RvcCcNCiAgICAgICkNCiAgICApDQogICkNCg0KIyBNb3N0cmFyIGVsIGdyw6FmaWNvIGludGVyYWN0aXZvDQpwbG90X3llYXINCg0KDQpgYGANCg0KIyMjDQoNCioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZTlmNWRiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij7wn5OEIDxiPkJ5IEIyQiBvciBCMkMgPC9iPjwvc3Bhbj4NCjwvcD4NCg0KDQojIyMjICB7LnRhYnNldH0NCg0KDQojIyMjIyBOdW1iZXIgb2Ygc3RhcnR1cHMNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyBzdGFja2VkIGJhciBjaGFydCBpbGx1c3RyYXRlcyB0aGUgbnVtYmVyIG9mIGNvbXBhbmllcyBtYWtpbmcgaW52ZXN0bWVudHMgZWFjaCB5ZWFyLCBjYXRlZ29yaXplZCBieSB0aGVpciBidXNpbmVzcyBtb2RlbDogQjJCIChCdXNpbmVzcyB0byBCdXNpbmVzcykgYW5kIEIyQyAoQnVzaW5lc3MgdG8gQ29uc3VtZXIpLiBFYWNoIGJhciByZXByZXNlbnRzIGEgeWVhciwgYW5kIHRoZSBkaWZmZXJlbnQgY29sb3JlZCBzZWdtZW50cyB3aXRoaW4gZWFjaCBiYXIgZGVub3RlIHRoZSBudW1iZXIgb2YgY29tcGFuaWVzIGluIGVhY2ggY2F0ZWdvcnkgZm9yIHRoYXQgcGFydGljdWxhciB5ZWFyLiBUaGUgbGVnZW5kIG9uIHRoZSByaWdodC1oYW5kIHNpZGUgaWRlbnRpZmllcyB0aGUgY2F0ZWdvcmllcyBjb3JyZXNwb25kaW5nIHRvIGVhY2ggY29sb3IuIFRoaXMgdmlzdWFsaXphdGlvbiBoZWxwcyB0cmFjayBpbnZlc3RtZW50IGFjdGl2aXR5IHRyZW5kcyBvdmVyIHRpbWUsIGhpZ2hsaWdodGluZyB0aGUgZHluYW1pY3MgYmV0d2VlbiBCMkIgYW5kIEIyQyBjb21wYW5pZXMgaW4gdGhlIEVkVGVjaCBzZWN0b3IuPC9wPg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCg0KIyBMb2FkIHRoZSBuZWNlc3NhcnkgbGlicmFyaWVzDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGxvdGx5KQ0KDQojIExvYWQgdGhlIGRhdGEgKEFzc3VtaW5nIHlvdXIgZGF0YSBpcyBpbiBhIHNwcmVhZHNoZWV0IG5hbWVkICJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KDQojIFByZXByb2Nlc3MgdGhlIGRhdGENCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBkYXRlIG5vdCBmb3VuZCIsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBtdXRhdGUoDQogICAgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgID0geW1kKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCksDQogICAgWWVhciA9IGFzLmludGVnZXIoeWVhcihgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApKQ0KICApDQoNCiMgTG9hZCB0aGUgYWRkaXRpb25hbCBkYXRhIHdpdGggQjJCIG9yIEIyQyBpbmZvcm1hdGlvbg0KYWRkaXRpb25hbF9kYXRhIDwtIHJlYWRfZXhjZWwoImZpbmFsX291dHB1dC54bHN4IikNCg0KIyBNZXJnZSB0aGUgZGF0YXNldHMgYmFzZWQgb24gQ29tcGFueSBOYW1lDQptZXJnZWRfZGF0YSA8LSBtZXJnZShkYXRhLCBhZGRpdGlvbmFsX2RhdGEsIGJ5ID0gIkNvbXBhbnkgTmFtZSIpDQoNCiMgU3VtbWFyaXplIGRhdGEgYnkgWWVhciBhbmQgQjJCIG9yIEIyQw0KeWVhcmx5X2IyYl9iMmNfZGF0YSA8LSBtZXJnZWRfZGF0YSAlPiUNCiAgZ3JvdXBfYnkoYEIyQiBvciBCMkNgLCBZZWFyKSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQojIEdldCB0aGUgbGlzdCBvZiB1bmlxdWUgQjJCIG9yIEIyQyBjYXRlZ29yaWVzIGluIHRoZSBjaGFydA0KdW5pcXVlX2NhdGVnb3JpZXMgPC0gdW5pcXVlKHllYXJseV9iMmJfYjJjX2RhdGEkYEIyQiBvciBCMkNgKQ0KDQojIENyZWF0ZSBhbiBpbnRlcmFjdGl2ZSBwbG90IHVzaW5nIHBsb3RseQ0KcGxvdF95ZWFyIDwtIHBsb3RfbHkoKQ0KDQojIEFkZCBlYWNoIGNhdGVnb3J5J3MgZGF0YSBhcyBhIHNlcGFyYXRlIHRyYWNlDQpmb3IgKGNhdGVnb3J5IGluIHVuaXF1ZV9jYXRlZ29yaWVzKSB7DQogIGNhdGVnb3J5X2RhdGEgPC0geWVhcmx5X2IyYl9iMmNfZGF0YSAlPiUgZmlsdGVyKGBCMkIgb3IgQjJDYCA9PSBjYXRlZ29yeSkNCiAgcGxvdF95ZWFyIDwtIGFkZF90cmFjZSgNCiAgICBwbG90X3llYXIsDQogICAgZGF0YSA9IGNhdGVnb3J5X2RhdGEsDQogICAgeCA9IH5ZZWFyLA0KICAgIHkgPSB+Q291bnQsDQogICAgbmFtZSA9IGNhdGVnb3J5LA0KICAgIHR5cGUgPSAnYmFyJywNCiAgICB0ZXh0ID0gfnBhc3RlKCJDYXRlZ29yeToiLCBgQjJCIG9yIEIyQ2AsICI8YnI+WWVhcjoiLCBZZWFyLCAiPGJyPkNvdW50OiIsIENvdW50KSwgICMgRGVmaW5lIGhvdmVyIHRleHQNCiAgICBob3ZlcmluZm8gPSAndGV4dCcgICMgU2hvdyBob3ZlciBpbmZvcm1hdGlvbg0KICApDQp9DQoNCiMgQWRkIGEgY2F0ZWdvcnkgc2VsZWN0b3INCmNhdGVnb3J5X2J1dHRvbnMgPC0gbGlzdCgNCiAgbGlzdCgNCiAgICBtZXRob2QgPSAicmVzdHlsZSIsDQogICAgYXJncyA9IGxpc3QoInZpc2libGUiLCByZXAoVFJVRSwgbGVuZ3RoKHVuaXF1ZV9jYXRlZ29yaWVzKSkpLA0KICAgIGxhYmVsID0gIkFsbCBDYXRlZ29yaWVzIg0KICApDQopDQoNCmNhdGVnb3J5X2J1dHRvbnMgPC0gYyhjYXRlZ29yeV9idXR0b25zLCBsYXBwbHkoc2VxX2Fsb25nKHVuaXF1ZV9jYXRlZ29yaWVzKSwgZnVuY3Rpb24oaSkgew0KICB2aXNpYmlsaXR5IDwtIHJlcChGQUxTRSwgbGVuZ3RoKHVuaXF1ZV9jYXRlZ29yaWVzKSkNCiAgdmlzaWJpbGl0eVtpXSA8LSBUUlVFDQogIGxpc3QoDQogICAgbWV0aG9kID0gInJlc3R5bGUiLA0KICAgIGFyZ3MgPSBsaXN0KCJ2aXNpYmxlIiwgdmlzaWJpbGl0eSksDQogICAgbGFiZWwgPSB1bmlxdWVfY2F0ZWdvcmllc1tpXQ0KICApDQp9KSkNCg0KcGxvdF95ZWFyIDwtIHBsb3RfeWVhciAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIk51bWJlciBvZiBDb21wYW5pZXMgSW52ZXN0aW5nIGJ5IFllYXIiLA0KICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJZZWFyIiwgZHRpY2sgPSAxKSwNCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiTnVtYmVyIG9mIENvbXBhbmllcyIpLA0KICAgIGJhcm1vZGUgPSAnc3RhY2snLA0KICAgIGhvdmVybW9kZSA9ICdjbG9zZXN0JywNCiAgICB3aWR0aCA9IDEwMDAsICAjIFNldCB0aGUgd2lkdGggb2YgdGhlIHBsb3QNCiAgICB1cGRhdGVtZW51cyA9IGxpc3QoDQogICAgICBsaXN0KA0KICAgICAgICB0eXBlID0gImRyb3Bkb3duIiwNCiAgICAgICAgYWN0aXZlID0gMCwNCiAgICAgICAgYnV0dG9ucyA9IGNhdGVnb3J5X2J1dHRvbnMsDQogICAgICAgIHggPSAwLjg1LCAgIyBBZGp1c3QgcG9zaXRpb24NCiAgICAgICAgeGFuY2hvciA9ICdsZWZ0JywNCiAgICAgICAgeSA9IDEuMTUsDQogICAgICAgIHlhbmNob3IgPSAndG9wJw0KICAgICAgKQ0KICAgICkNCiAgKQ0KDQojIERpc3BsYXkgdGhlIGludGVyYWN0aXZlIHBsb3QNCnBsb3RfeWVhcg0KDQoNCmBgYA0KDQojIyMjIyBBbW91bnQgb2YgaW52ZXN0bWVudA0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGlzIHN0YWNrZWQgYmFyIGNoYXJ0IGlsbHVzdHJhdGVzIHRoZSB0b3RhbCBhbW91bnQgb2YgaW52ZXN0bWVudCBieSB5ZWFyLCBjYXRlZ29yaXplZCBieSBidXNpbmVzcyBtb2RlbDogQjJCIChCdXNpbmVzcyB0byBCdXNpbmVzcykgYW5kIEIyQyAoQnVzaW5lc3MgdG8gQ29uc3VtZXIpLiBFYWNoIGJhciByZXByZXNlbnRzIGEgeWVhciwgYW5kIHRoZSBkaWZmZXJlbnQgY29sb3JlZCBzZWdtZW50cyB3aXRoaW4gZWFjaCBiYXIgZGVub3RlIHRoZSB0b3RhbCBpbnZlc3RtZW50IHJlY2VpdmVkIGJ5IGNvbXBhbmllcyBpbiBlYWNoIGNhdGVnb3J5IGZvciB0aGF0IHBhcnRpY3VsYXIgeWVhci4gVGhlIGxlZ2VuZCBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlIGlkZW50aWZpZXMgdGhlIGNhdGVnb3JpZXMgY29ycmVzcG9uZGluZyB0byBlYWNoIGNvbG9yLiBUaGlzIHZpc3VhbGl6YXRpb24gaGVscHMgdHJhY2sgaW52ZXN0bWVudCB0cmVuZHMgb3ZlciB0aW1lLCBoaWdobGlnaHRpbmcgdGhlIGR5bmFtaWNzIGJldHdlZW4gQjJCIGFuZCBCMkMgY29tcGFuaWVzIGluIHRoZSBFZFRlY2ggc2VjdG9yLjwvcD4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCiMgTG9hZCB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoY291bnRyeWNvZGUpDQoNCiMgTG9hZCB0aGUgZGF0YSAoQXNzdW1pbmcgeW91ciBkYXRhIGlzIGluIGEgc3ByZWFkc2hlZXQgbmFtZWQgImxpbmtlZGluX2luZm8ueGxzeCIpDQpkYXRhIDwtIHJlYWRfZXhjZWwoImxpbmtlZGluX2luZm8ueGxzeCIpDQoNCiMgUHJlcHJvY2VzcyB0aGUgZGF0YQ0KZGF0YSA8LSBkYXRhICU+JQ0KICBmaWx0ZXIoIWdyZXBsKCJMYXN0IHJvdW5kIGRhdGUgbm90IGZvdW5kIiwgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSkgJT4lDQogIGZpbHRlcighaXMubmEoYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSkgJT4lDQogIG11dGF0ZSgNCiAgICBgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWAgPSB5bWQoYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSwNCiAgICBZZWFyID0gYXMuaW50ZWdlcih5ZWFyKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpLA0KICAgIENvdW50cnlfTmFtZSA9IGNvdW50cnljb2RlKENvdW50cnksICJpc28yYyIsICJjb3VudHJ5Lm5hbWUiKSwNCiAgICBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAgPSBjYXNlX3doZW4oDQogICAgICBncmVwbCgiTSIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkgfiBhcy5udW1lcmljKGdzdWIoIlteMC05Ll0iLCAiIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgKiAxZTYsDQogICAgICBncmVwbCgiSyIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkgfiBhcy5udW1lcmljKGdzdWIoIlteMC05Ll0iLCAiIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgKiAxZTMsDQogICAgICBUUlVFIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpDQogICAgKSAgIyBLZWVwIHRoZSBhbW91bnQgaW4gb3JpZ2luYWwgdW5pdHMNCiAgKQ0KDQojIExvYWQgdGhlIGFkZGl0aW9uYWwgZGF0YSB3aXRoIEIyQiBvciBCMkMgaW5mb3JtYXRpb24NCmFkZGl0aW9uYWxfZGF0YSA8LSByZWFkX2V4Y2VsKCJmaW5hbF9vdXRwdXQueGxzeCIpDQoNCiMgTWVyZ2UgdGhlIGRhdGFzZXRzIGJhc2VkIG9uIENvbXBhbnkgTmFtZQ0KbWVyZ2VkX2RhdGEgPC0gbWVyZ2UoZGF0YSwgYWRkaXRpb25hbF9kYXRhLCBieSA9ICJDb21wYW55IE5hbWUiKQ0KDQojIFN1bW1hcml6ZSBkYXRhIGJ5IFllYXIgYW5kIEIyQiBvciBCMkMNCnllYXJseV9iMmJfYjJjX2RhdGEgPC0gbWVyZ2VkX2RhdGEgJT4lDQogIGdyb3VwX2J5KGBCMkIgb3IgQjJDYCwgWWVhcikgJT4lDQogIHN1bW1hcmlzZShUb3RhbF9JbnZlc3RtZW50ID0gc3VtKGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICdkcm9wJykNCg0KIyBHZXQgdGhlIGxpc3Qgb2YgdW5pcXVlIEIyQiBvciBCMkMgY2F0ZWdvcmllcyBpbiB0aGUgY2hhcnQNCnVuaXF1ZV9jYXRlZ29yaWVzIDwtIHVuaXF1ZSh5ZWFybHlfYjJiX2IyY19kYXRhJGBCMkIgb3IgQjJDYCkNCg0KIyBDcmVhdGUgYW4gaW50ZXJhY3RpdmUgcGxvdCB1c2luZyBwbG90bHkNCnBsb3RfeWVhciA8LSBwbG90X2x5KCkNCg0KIyBBZGQgZWFjaCBjYXRlZ29yeSdzIGRhdGEgYXMgYSBzZXBhcmF0ZSB0cmFjZQ0KZm9yIChjYXRlZ29yeSBpbiB1bmlxdWVfY2F0ZWdvcmllcykgew0KICBjYXRlZ29yeV9kYXRhIDwtIHllYXJseV9iMmJfYjJjX2RhdGEgJT4lIGZpbHRlcihgQjJCIG9yIEIyQ2AgPT0gY2F0ZWdvcnkpDQogIHBsb3RfeWVhciA8LSBhZGRfdHJhY2UoDQogICAgcGxvdF95ZWFyLA0KICAgIGRhdGEgPSBjYXRlZ29yeV9kYXRhLA0KICAgIHggPSB+WWVhciwNCiAgICB5ID0gflRvdGFsX0ludmVzdG1lbnQsDQogICAgbmFtZSA9IGNhdGVnb3J5LA0KICAgIHR5cGUgPSAnYmFyJywNCiAgICB0ZXh0ID0gfnBhc3RlKCJDYXRlZ29yeToiLCBgQjJCIG9yIEIyQ2AsICI8YnI+WWVhcjoiLCBZZWFyLCAiPGJyPlRvdGFsIEludmVzdG1lbnQ6ICQiLCBmb3JtYXQoVG90YWxfSW52ZXN0bWVudCwgYmlnLm1hcmsgPSAiLCIpKSwgICMgRGVmaW5lIGhvdmVyIHRleHQNCiAgICBob3ZlcmluZm8gPSAndGV4dCcgICMgU2hvdyBob3ZlciBpbmZvcm1hdGlvbg0KICApDQp9DQoNCiMgQWRkIGEgY2F0ZWdvcnkgc2VsZWN0b3INCmNhdGVnb3J5X2J1dHRvbnMgPC0gbGlzdCgNCiAgbGlzdCgNCiAgICBtZXRob2QgPSAicmVzdHlsZSIsDQogICAgYXJncyA9IGxpc3QoInZpc2libGUiLCByZXAoVFJVRSwgbGVuZ3RoKHVuaXF1ZV9jYXRlZ29yaWVzKSkpLA0KICAgIGxhYmVsID0gIkFsbCBDYXRlZ29yaWVzIg0KICApDQopDQoNCmNhdGVnb3J5X2J1dHRvbnMgPC0gYyhjYXRlZ29yeV9idXR0b25zLCBsYXBwbHkoc2VxX2Fsb25nKHVuaXF1ZV9jYXRlZ29yaWVzKSwgZnVuY3Rpb24oaSkgew0KICB2aXNpYmlsaXR5IDwtIHJlcChGQUxTRSwgbGVuZ3RoKHVuaXF1ZV9jYXRlZ29yaWVzKSkNCiAgdmlzaWJpbGl0eVtpXSA8LSBUUlVFDQogIGxpc3QoDQogICAgbWV0aG9kID0gInJlc3R5bGUiLA0KICAgIGFyZ3MgPSBsaXN0KCJ2aXNpYmxlIiwgdmlzaWJpbGl0eSksDQogICAgbGFiZWwgPSB1bmlxdWVfY2F0ZWdvcmllc1tpXQ0KICApDQp9KSkNCg0KcGxvdF95ZWFyIDwtIHBsb3RfeWVhciAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIlRvdGFsIEludmVzdG1lbnQgYnkgWWVhciBhbmQgQ2F0ZWdvcnkiLA0KICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJZZWFyIiwgZHRpY2sgPSAxKSwNCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiVG90YWwgSW52ZXN0bWVudCAoVVNEKSIpLA0KICAgIGJhcm1vZGUgPSAnc3RhY2snLA0KICAgIGhvdmVybW9kZSA9ICdjbG9zZXN0JywNCiAgICB3aWR0aCA9IDEwMDAsICAjIFNldCB0aGUgd2lkdGggb2YgdGhlIHBsb3QNCiAgICB1cGRhdGVtZW51cyA9IGxpc3QoDQogICAgICBsaXN0KA0KICAgICAgICB0eXBlID0gImRyb3Bkb3duIiwNCiAgICAgICAgYWN0aXZlID0gMCwNCiAgICAgICAgYnV0dG9ucyA9IGNhdGVnb3J5X2J1dHRvbnMsDQogICAgICAgIHggPSAwLjg1LCAgIyBBZGp1c3QgcG9zaXRpb24NCiAgICAgICAgeGFuY2hvciA9ICdsZWZ0JywNCiAgICAgICAgeSA9IDEuMTUsDQogICAgICAgIHlhbmNob3IgPSAndG9wJw0KICAgICAgKQ0KICAgICkNCiAgKQ0KDQojIERpc3BsYXkgdGhlIGludGVyYWN0aXZlIHBsb3QNCnBsb3RfeWVhcg0KDQpgYGANCg0KIyMjDQoNCiMjIyMgIHsudGFic2V0fQ0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQogIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlOWY1ZGI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPvCfk4QgPGI+QnkgSW5kdXN0cnkgPC9iPjwvc3Bhbj4NCjwvcD4NCg0KDQojIyMjIyBOdW1iZXIgb2Ygc3RhcnR1cHMNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyB0cmVlbWFwIGNoYXJ0IGRpc3BsYXlzIHRoZSBkaXN0cmlidXRpb24gb2YgY29tcGFuaWVzIGJ5IGluZHVzdHJ5LCBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gYXZhaWxhYmxlIG9uIHRoZWlyIExpbmtlZEluIHByb2ZpbGVzLiBFYWNoIHJlY3RhbmdsZSByZXByZXNlbnRzIGFuIGluZHVzdHJ5LCB3aXRoIHRoZSBzaXplIG9mIHRoZSByZWN0YW5nbGUgcHJvcG9ydGlvbmFsIHRvIHRoZSBudW1iZXIgb2YgY29tcGFuaWVzIGluIHRoYXQgaW5kdXN0cnkuIFRoZSBjb2xvciBhbmQgc2l6ZSBvZiB0aGUgcmVjdGFuZ2xlcyBwcm92aWRlIGEgcXVpY2sgdmlzdWFsIHJlZmVyZW5jZSBmb3IgdGhlIHByZXZhbGVuY2Ugb2YgZGlmZmVyZW50IGluZHVzdHJpZXMgYW1vbmcgdGhlIGFuYWx5emVkIGNvbXBhbmllcy4gVGhpcyB2aXN1YWxpemF0aW9uIGhlbHBzIHRvIGlkZW50aWZ5IHdoaWNoIGluZHVzdHJpZXMgYXJlIG1vc3QgY29tbW9uIGluIHRoZSBFZFRlY2ggc2VjdG9yIGFuZCBob3cgY29tcGFuaWVzIGFyZSBkaXN0cmlidXRlZCBhY3Jvc3MgdmFyaW91cyBmaWVsZHMuPC9wPg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KDQo8c3Ryb25nPk5vdGU6PC9zdHJvbmc+IEFjY29yZGluZyB0byBMaW5rZWRJbiwgRWR1TmV4dCBvcGVyYXRlcyBpbiB0aGUgRS1sZWFybmluZyBpbmR1c3RyeS4gVGhpcyBjbGFzc2lmaWNhdGlvbiBpcyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gYXZhaWxhYmxlIG9uIHRoZWlyIExpbmtlZEluIHByb2ZpbGUuPC9wPg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KDQojIENhcmdhciBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBsb3RseSkNCg0KIyBDYXJnYXIgbG9zIGRhdG9zIChBc2VndXLDoW5kb3NlIGRlIHF1ZSBsb3MgYXJjaGl2b3MgZXN0w6luIGVuIGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbykNCmRhdGEgPC0gcmVhZF9leGNlbCgibGlua2VkaW5faW5mby54bHN4IikNCmFkZGl0aW9uYWxfZGF0YSA8LSByZWFkX2V4Y2VsKCJmaW5hbF9vdXRwdXQueGxzeCIpDQoNCiMgRnVzaW9uYXIgbG9zIGNvbmp1bnRvcyBkZSBkYXRvcyBiYXNhZG9zIGVuIGVsIG5vbWJyZSBkZSBsYSBlbXByZXNhDQptZXJnZWRfZGF0YSA8LSBtZXJnZShkYXRhLCBhZGRpdGlvbmFsX2RhdGEsIGJ5ID0gIkNvbXBhbnkgTmFtZSIpDQoNCiMgUmVzdW1pciBsb3MgZGF0b3MgcGFyYSBvYnRlbmVyIGVsIGNvbnRlbyBkZSBjYWRhIGluZHVzdHJpYQ0KaW5kdXN0cnlfZGF0YSA8LSBtZXJnZWRfZGF0YSAlPiUNCiAgZ3JvdXBfYnkoSW5kdXN0cnkpICU+JQ0KICBzdW1tYXJpc2UoQ291bnQgPSBuKCkpICU+JQ0KICB1bmdyb3VwKCkNCg0KIyBDYWxjdWxhciBlbCBwb3JjZW50YWplDQppbmR1c3RyeV9kYXRhIDwtIGluZHVzdHJ5X2RhdGEgJT4lDQogIG11dGF0ZShQZXJjZW50YWdlID0gQ291bnQgLyBzdW0oQ291bnQpICogMTAwKQ0KDQojIERlZmluaXIgY29sb3JlcyBwZXJzb25hbGl6YWRvcyBwYXJhIGxvcyBzZWdtZW50b3MNCmNvbG9ycyA8LSBjKCIjRkY1NzMzIiwgIiMzM0ZGNTciLCAiIzMzNTdGRiIsICIjRkYzM0ExIiwgIiNGRkREMzMiLCAiIzMzRkZENyIsICIjRDczM0ZGIiwgIiNGRjU3MzMiKQ0KDQojIENyZWFyIGVsIGdyw6FmaWNvIGRlIMOhcmVhIGRlIHJlY3TDoW5ndWxvcyAodHJlZW1hcCkgdXNhbmRvIHBsb3RseQ0KdHJlZW1hcF9jaGFydCA8LSBwbG90X2x5KA0KICBpbmR1c3RyeV9kYXRhLA0KICBsYWJlbHMgPSB+cGFzdGUoSW5kdXN0cnksICI8YnI+Q291bnQ6ICIsIENvdW50LCAiPGJyPlBlcmNlbnRhZ2U6ICIsIHJvdW5kKFBlcmNlbnRhZ2UsIDIpLCAiJSIpLA0KICBwYXJlbnRzID0gIiIsDQogIHZhbHVlcyA9IH5Db3VudCwNCiAgdHlwZSA9ICd0cmVlbWFwJywNCiAgdGV4dGluZm8gPSAnbGFiZWwnLA0KICBob3ZlcmluZm8gPSAnbGFiZWwrdmFsdWUrcGVyY2VudCcsDQogIG1hcmtlciA9IGxpc3QoY29sb3JzID0gY29sb3JzKQ0KKSAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gbGlzdCgNCiAgICAgIHRleHQgPSAiPGI+RGlzdHJpYnV0aW9uIG9mIENvbXBhbmllcyBieSBJbmR1c3RyeTwvYj4iLA0KICAgICAgeCA9IDAuNSwNCiAgICAgIHkgPSAwLjk1LA0KICAgICAgeGFuY2hvciA9ICdjZW50ZXInLA0KICAgICAgeWFuY2hvciA9ICd0b3AnLA0KICAgICAgZm9udCA9IGxpc3Qoc2l6ZSA9IDI0LCBmYW1pbHkgPSAiQXJpYWwiLCBjb2xvciA9ICIjMzMzMzMzIikNCiAgICApLA0KICAgIG1hcmdpbiA9IGxpc3QodCA9IDEwMCwgYiA9IDEwMCwgbCA9IDUwLCByID0gNTApLCAgIyBBanVzdGFyIG3DoXJnZW5lcyBwYXJhIG1lam9yIGVzcGFjaWFkbw0KICAgIGhlaWdodCA9IDUwMCwgICMgQWp1c3RhciBsYSBhbHR1cmEgcGFyYSB1biBtZWpvciBlc3BhY2lhZG8NCiAgICB3aWR0aCA9IDcwMCAgICMgQWp1c3RhciBlbCBhbmNobyBwYXJhIGNlbnRyYXIgbGEgZ3LDoWZpY2ENCiAgKQ0KDQojIEd1YXJkYXIgZWwgYXJjaGl2byBIVE1MDQpodG1sdG9vbHM6OnNhdmVfaHRtbChodG1sdG9vbHM6OnRhZ0xpc3QodHJlZW1hcF9jaGFydCksICJpbmR1c3RyeV9kaXN0cmlidXRpb25fdHJlZW1hcF9jaGFydC5odG1sIikNCg0KIyBNb3N0cmFyIGVsIGdyw6FmaWNvIGludGVyYWN0aXZvIGVuIGVsIHZpc29yIGRlIFJTdHVkaW8gbyBlbiBlbCBuYXZlZ2Fkb3INCnRyZWVtYXBfY2hhcnQNCg0KDQoNCmBgYA0KDQojIyMjIyBBbW91bnQgb2YgaW52ZXN0bWVudA0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGlzIHRyZWVtYXAgY2hhcnQgZGlzcGxheXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBpbnZlc3RtZW50IGJ5IGluZHVzdHJ5LCBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gYXZhaWxhYmxlIG9uIHRoZSBjb21wYW5pZXMnIExpbmtlZEluIHByb2ZpbGVzLiBFYWNoIHJlY3RhbmdsZSByZXByZXNlbnRzIGFuIGluZHVzdHJ5LCB3aXRoIHRoZSBzaXplIG9mIHRoZSByZWN0YW5nbGUgcHJvcG9ydGlvbmFsIHRvIHRoZSB0b3RhbCBpbnZlc3RtZW50IHJlY2VpdmVkIGJ5IGNvbXBhbmllcyBpbiB0aGF0IGluZHVzdHJ5LiBUaGUgY29sb3IgYW5kIHNpemUgb2YgdGhlIHJlY3RhbmdsZXMgcHJvdmlkZSBhIHF1aWNrIHZpc3VhbCByZWZlcmVuY2UgZm9yIHRoZSBhbGxvY2F0aW9uIG9mIGludmVzdG1lbnRzIGFjcm9zcyBkaWZmZXJlbnQgaW5kdXN0cmllcyBhbW9uZyB0aGUgYW5hbHl6ZWQgY29tcGFuaWVzLiBUaGlzIHZpc3VhbGl6YXRpb24gaGVscHMgdG8gaWRlbnRpZnkgd2hpY2ggaW5kdXN0cmllcyBhdHRyYWN0IHRoZSBtb3N0IGludmVzdG1lbnQgaW4gdGhlIEVkVGVjaCBzZWN0b3IuPC9wPg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KDQo8c3Ryb25nPk5vdGU6PC9zdHJvbmc+IEFjY29yZGluZyB0byBMaW5rZWRJbiwgRWR1TmV4dCBvcGVyYXRlcyBpbiB0aGUgRS1sZWFybmluZyBpbmR1c3RyeS4gVGhpcyBjbGFzc2lmaWNhdGlvbiBpcyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gYXZhaWxhYmxlIG9uIHRoZWlyIExpbmtlZEluIHByb2ZpbGUuPC9wPg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCiMgQ2FyZ2FyIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocGxvdGx5KQ0KDQojIENhcmdhciBsb3MgZGF0b3MgKEFzZWd1csOhbmRvc2UgZGUgcXVlIGxvcyBhcmNoaXZvcyBlc3TDqW4gZW4gZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvKQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KYWRkaXRpb25hbF9kYXRhIDwtIHJlYWRfZXhjZWwoImZpbmFsX291dHB1dC54bHN4IikNCg0KIyBQcmVwcm9jZXNhciBsb3MgZGF0b3MNCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBkYXRlIG5vdCBmb3VuZCIsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBtdXRhdGUoDQogICAgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgID0geW1kKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCksDQogICAgWWVhciA9IGFzLmludGVnZXIoeWVhcihgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApKSwNCiAgICBDb3VudHJ5X05hbWUgPSBjb3VudHJ5Y29kZShDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIiksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gY2FzZV93aGVuKA0KICAgICAgZ3JlcGwoIk0iLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LA0KICAgICAgZ3JlcGwoIksiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWUzLA0KICAgICAgVFJVRSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKQ0KICAgICkgICMgTWFudGVuZXIgZWwgbW9udG8gZW4gdW5pZGFkZXMgb3JpZ2luYWxlcw0KICApDQoNCiMgRnVzaW9uYXIgbG9zIGNvbmp1bnRvcyBkZSBkYXRvcyBiYXNhZG9zIGVuIGVsIG5vbWJyZSBkZSBsYSBlbXByZXNhDQptZXJnZWRfZGF0YSA8LSBtZXJnZShkYXRhLCBhZGRpdGlvbmFsX2RhdGEsIGJ5ID0gIkNvbXBhbnkgTmFtZSIpDQoNCiMgUmVzdW1pciBsb3MgZGF0b3MgcGFyYSBvYnRlbmVyIGxhIGludmVyc2nDs24gdG90YWwgZGUgY2FkYSBpbmR1c3RyaWENCmluZHVzdHJ5X2RhdGEgPC0gbWVyZ2VkX2RhdGEgJT4lDQogIGdyb3VwX2J5KEluZHVzdHJ5KSAlPiUNCiAgc3VtbWFyaXNlKFRvdGFsX0ludmVzdG1lbnQgPSBzdW0oYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgdW5ncm91cCgpDQoNCiMgQ2FsY3VsYXIgZWwgcG9yY2VudGFqZSBkZSBpbnZlcnNpw7NuDQppbmR1c3RyeV9kYXRhIDwtIGluZHVzdHJ5X2RhdGEgJT4lDQogIG11dGF0ZShQZXJjZW50YWdlID0gVG90YWxfSW52ZXN0bWVudCAvIHN1bShUb3RhbF9JbnZlc3RtZW50KSAqIDEwMCkNCg0KIyBEZWZpbmlyIGNvbG9yZXMgcGVyc29uYWxpemFkb3MgcGFyYSBsb3Mgc2VnbWVudG9zDQpjb2xvcnMgPC0gYygiI0ZGNTczMyIsICIjMzNGRjU3IiwgIiMzMzU3RkYiLCAiI0ZGMzNBMSIsICIjRkZERDMzIiwgIiMzM0ZGRDciLCAiI0Q3MzNGRiIsICIjRkY1NzMzIikNCg0KIyBDcmVhciBlbCBncsOhZmljbyBkZSDDoXJlYSBkZSByZWN0w6FuZ3Vsb3MgKHRyZWVtYXApIHVzYW5kbyBwbG90bHkNCnRyZWVtYXBfY2hhcnQgPC0gcGxvdF9seSgNCiAgaW5kdXN0cnlfZGF0YSwNCiAgbGFiZWxzID0gfnBhc3RlKEluZHVzdHJ5LCAiPGJyPkludmVzdG1lbnQ6ICQiLCBmb3JtYXQocm91bmQoVG90YWxfSW52ZXN0bWVudCwgMiksIGJpZy5tYXJrID0gIiwiLCBzY2llbnRpZmljID0gRkFMU0UpLCAiPGJyPlBlcmNlbnRhZ2U6ICIsIHJvdW5kKFBlcmNlbnRhZ2UsIDIpLCAiJSIpLA0KICBwYXJlbnRzID0gIiIsDQogIHZhbHVlcyA9IH5Ub3RhbF9JbnZlc3RtZW50LA0KICB0eXBlID0gJ3RyZWVtYXAnLA0KICB0ZXh0aW5mbyA9ICdsYWJlbCcsDQogIGhvdmVyaW5mbyA9ICdsYWJlbCt2YWx1ZStwZXJjZW50JywNCiAgbWFya2VyID0gbGlzdChjb2xvcnMgPSBjb2xvcnMpDQopICU+JQ0KICBsYXlvdXQoDQogICAgdGl0bGUgPSBsaXN0KA0KICAgICAgdGV4dCA9ICI8Yj5EaXN0cmlidXRpb24gb2YgSW52ZXN0bWVudCBieSBJbmR1c3RyeTwvYj4iLA0KICAgICAgeCA9IDAuNSwNCiAgICAgIHkgPSAwLjk1LA0KICAgICAgeGFuY2hvciA9ICdjZW50ZXInLA0KICAgICAgeWFuY2hvciA9ICd0b3AnLA0KICAgICAgZm9udCA9IGxpc3Qoc2l6ZSA9IDI0LCBmYW1pbHkgPSAiQXJpYWwiLCBjb2xvciA9ICIjMzMzMzMzIikNCiAgICApLA0KICAgIG1hcmdpbiA9IGxpc3QodCA9IDEwMCwgYiA9IDEwMCwgbCA9IDUwLCByID0gNTApLCAgIyBBanVzdGFyIG3DoXJnZW5lcyBwYXJhIG1lam9yIGVzcGFjaWFkbw0KICAgIGhlaWdodCA9IDUwMCwgICMgQWp1c3RhciBsYSBhbHR1cmEgcGFyYSB1biBtZWpvciBlc3BhY2lhZG8NCiAgICB3aWR0aCA9IDcwMCAgICMgQWp1c3RhciBlbCBhbmNobyBwYXJhIGNlbnRyYXIgbGEgZ3LDoWZpY2ENCiAgKQ0KDQojIEd1YXJkYXIgZWwgYXJjaGl2byBIVE1MDQpodG1sdG9vbHM6OnNhdmVfaHRtbChodG1sdG9vbHM6OnRhZ0xpc3QodHJlZW1hcF9jaGFydCksICJpbnZlc3RtZW50X2Rpc3RyaWJ1dGlvbl90cmVlbWFwX2NoYXJ0Lmh0bWwiKQ0KDQojIE1vc3RyYXIgZWwgZ3LDoWZpY28gaW50ZXJhY3Rpdm8gZW4gZWwgdmlzb3IgZGUgUlN0dWRpbyBvIGVuIGVsIG5hdmVnYWRvcg0KdHJlZW1hcF9jaGFydA0KDQoNCg0KYGBgDQoNCg0KIyMjDQoNCiMjIyMgIHsudGFic2V0fQ0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQogIDxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlOWY1ZGI7IGNvbG9yOmJsYWNrOyBib3JkZXItcmFkaXVzOjVweDsgcGFkZGluZzogMC4yZW0gMC41ZW07IGRpc3BsYXk6IGlubGluZS1ibG9jazsiPvCfk4QgPGI+QnkgUm9sZSA8L2I+PC9zcGFuPg0KPC9wPg0KDQoNCiMjIyMjIFJvbGUNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyBkb251dCBjaGFydCB2aXN1YWxpemVzIHRoZSBkaXN0cmlidXRpb24gb2YgcG90ZW50aWFsIHJvbGVzIGlkZW50aWZpZWQgZm9yIGNvbXBhbmllcywgYmFzZWQgb24gdGhlaXIgcmVsZXZhbmNlIHRvIEVkdU5leHQuIFRoZSBjaGFydCBzZWdtZW50cyByZXByZXNlbnQgdGhlIHBlcmNlbnRhZ2Ugb2YgY29tcGFuaWVzIGNsYXNzaWZpZWQgYXMgcGFydG5lcnMsIGNsaWVudHMsIGNvbXBldGl0b3JzLCBhbmQgcHJvdmlkZXJzLiBUaGUgbGVnZW5kIGluZGljYXRlcyB0aGUgcm9sZSBjb3JyZXNwb25kaW5nIHRvIGVhY2ggY29sb3IuIFRoaXMgdmlzdWFsaXphdGlvbiBoZWxwcyB0byB1bmRlcnN0YW5kIHRoZSBwcmVkb21pbmFudCByb2xlcyBhbW9uZyB0aGUgYW5hbHl6ZWQgY29tcGFuaWVzLjwvcD4NCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCjxzdHJvbmc+Tm90ZTo8L3N0cm9uZz4gVGhlIEVkdU5leHQgdGVhbSBjaG9zZSB0aGUgcm9sZXMgYW5kIGRlZmluaXRpb25zIGZvciBlYWNoIHJvbGUuPC9wPg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCg0KIyBDYXJnYXIgbGFzIGxpYnJlcsOtYXMgbmVjZXNhcmlhcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwbG90bHkpDQoNCiMgQ2FyZ2FyIGxvcyBkYXRvcyAoQXN1bWllbmRvIHF1ZSBsb3MgZGF0b3MgZXN0w6FuIGVuIHVuYSBob2phIGxsYW1hZGEgImxpbmtlZGluX2luZm8ueGxzeCIpDQpkYXRhIDwtIHJlYWRfZXhjZWwoImxpbmtlZGluX2luZm8ueGxzeCIpDQoNCiMgQ2FyZ2FyIGxvcyBkYXRvcyBhZGljaW9uYWxlcyBjb24gbGEgaW5mb3JtYWNpw7NuIGRlIGxvcyByb2xlcyBwb3RlbmNpYWxlcw0KYWRkaXRpb25hbF9kYXRhIDwtIHJlYWRfZXhjZWwoImZpbmFsX291dHB1dC54bHN4IikNCg0KIyBGdXNpb25hciBsb3MgY29uanVudG9zIGRlIGRhdG9zIGJhc2Fkb3MgZW4gZWwgbm9tYnJlIGRlIGxhIGVtcHJlc2ENCm1lcmdlZF9kYXRhIDwtIG1lcmdlKGRhdGEsIGFkZGl0aW9uYWxfZGF0YSwgYnkgPSAiQ29tcGFueSBOYW1lIikNCg0KIyBSZXN1bWlyIGxvcyBkYXRvcyBwYXJhIG9idGVuZXIgZWwgY29udGVvIGRlIGNhZGEgcm9sIHBvdGVuY2lhbA0Kcm9sZV9kYXRhIDwtIG1lcmdlZF9kYXRhICU+JQ0KICBncm91cF9ieShgUG90ZW50aWFsIFJvbGVgKSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbigpKSAlPiUNCiAgdW5ncm91cCgpDQoNCiMgRGVmaW5pciBjb2xvcmVzIHBlcnNvbmFsaXphZG9zIHBhcmEgbG9zIHNlZ21lbnRvcw0KY29sb3JzIDwtIGMoIiNGRjU3MzMiLCAiIzMzRkY1NyIsICIjMzM1N0ZGIiwgIiNGRjMzQTEiLCAiI0ZGREQzMyIsICIjMzNGRkQ3IiwgIiNENzMzRkYiLCAiI0ZGNTczMyIpDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgZG9uYSB1c2FuZG8gcGxvdGx5DQpkb251dF9jaGFydCA8LSBwbG90X2x5KA0KICByb2xlX2RhdGEsDQogIGxhYmVscyA9IH5gUG90ZW50aWFsIFJvbGVgLA0KICB2YWx1ZXMgPSB+Q291bnQsDQogIHR5cGUgPSAncGllJywNCiAgaG9sZSA9IDAuNSwgICMgQ3JlYXIgZWwgYWd1amVybyBkZSBsYSBkb25hDQogIHRleHRpbmZvID0gJ2xhYmVsK3BlcmNlbnQnLA0KICBpbnNpZGV0ZXh0b3JpZW50YXRpb24gPSAncmFkaWFsJywNCiAgbWFya2VyID0gbGlzdChjb2xvcnMgPSBjb2xvcnMpDQopICU+JQ0KICBsYXlvdXQoDQogICAgdGl0bGUgPSBsaXN0KA0KICAgICAgdGV4dCA9ICI8Yj5Qcm9wb3J0aW9uIG9mIFBvdGVudGlhbCBSb2xlczwvYj4iLA0KICAgICAgeCA9IDAuNSwNCiAgICAgIHkgPSAwLjk1LA0KICAgICAgeGFuY2hvciA9ICdjZW50ZXInLA0KICAgICAgeWFuY2hvciA9ICd0b3AnLA0KICAgICAgZm9udCA9IGxpc3Qoc2l6ZSA9IDI0LCBmYW1pbHkgPSAiQXJpYWwiLCBjb2xvciA9ICIjMzMzMzMzIikNCiAgICApLA0KICAgIHNob3dsZWdlbmQgPSBUUlVFLA0KICAgIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAnaCcsIHggPSAwLjUsIHkgPSAtMC4zLCB4YW5jaG9yID0gJ2NlbnRlcicpLA0KICAgIG1hcmdpbiA9IGxpc3QodCA9IDEwMCwgYiA9IDEwMCwgbCA9IDUwLCByID0gNTApLCAgIyBBanVzdGFyIG3DoXJnZW5lcyBwYXJhIG1lam9yIGVzcGFjaWFkbw0KICAgIGhlaWdodCA9IDUwMCwgICMgQWp1c3RhciBsYSBhbHR1cmEgcGFyYSB1biBtZWpvciBlc3BhY2lhZG8NCiAgICB3aWR0aCA9IDcwMCwgICAjIEFqdXN0YXIgZWwgYW5jaG8gcGFyYSBjZW50cmFyIGxhIGRvbmENCiAgICBhbm5vdGF0aW9ucyA9IGxpc3QoDQogICAgICBsaXN0KA0KICAgICAgICB4ID0gMC41LA0KICAgICAgICB5ID0gMC41LA0KICAgICAgICB0ZXh0ID0gIiIsDQogICAgICAgIHNob3dhcnJvdyA9IEZBTFNFDQogICAgICApDQogICAgKQ0KICApDQoNCiMgR3VhcmRhciBlbCBhcmNoaXZvIEhUTUwNCmh0bWx0b29sczo6c2F2ZV9odG1sKGh0bWx0b29sczo6dGFnTGlzdChkb251dF9jaGFydCksICJyb2xlX3Byb3BvcnRpb25fZG9udXRfY2hhcnQuaHRtbCIpDQoNCiMgTW9zdHJhciBlbCBncsOhZmljbyBpbnRlcmFjdGl2byBlbiBlbCB2aXNvciBkZSBSU3R1ZGlvIG8gZW4gZWwgbmF2ZWdhZG9yDQpkb251dF9jaGFydA0KDQoNCmBgYA0KDQoNCiMjIyMjIFBvdGVudGlhbCBDbGllbnRzDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoaXMgdGFibGUgbGlzdHMgdGhlIGNvbXBhbmllcyBpZGVudGlmaWVkIGFzIHBvdGVudGlhbCBjbGllbnRzIGZvciBFZHVOZXh0LiBUaGUgY29sdW1ucyBpbmNsdWRlIGNvbXBhbnkgbmFtZSwgc2l6ZSwgY291bnRyeSwgdHlwZSwgbnVtYmVyIG9mIGVtcGxveWVlcywgaW5kdXN0cnksIGJ1c2luZXNzIG1vZGVsIChCMkIgb3IgQjJDKSwgcG90ZW50aWFsIHZlcnRpY2FsLCBhbmQgdGhlIGFtb3VudCBvZiB0aGUgbGFzdCBmdW5kaW5nIHJvdW5kIGFzIHJlcG9ydGVkIGJ5IENydW5jaGJhc2UuIFRoaXMgdGFibGUgcHJvdmlkZXMgZGV0YWlsZWQgaW5mb3JtYXRpb24gb24gcG90ZW50aWFsIGNsaWVudHMsIGFpZGluZyBzdHJhdGVnaWMgZGVjaXNpb24tbWFraW5nLjwvcD4NCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCjxzdHJvbmc+Tm90ZTo8L3N0cm9uZz4gVGhlIEVkdU5leHQgdGVhbSBjaG9zZSB0aGUgcm9sZXMgYW5kIGRlZmluaXRpb25zIGZvciBlYWNoIHJvbGUuPC9wPg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KDQojIENhcmdhciBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoRFQpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KbGlicmFyeShzY2FsZXMpDQoNCiMgQ2FyZ2FyIGxvcyBkYXRvcyAoQXNlZ3Vyw6FuZG9zZSBkZSBxdWUgbG9zIGFyY2hpdm9zIGVzdMOpbiBlbiBlbCBkaXJlY3RvcmlvIGRlIHRyYWJham8pDQpkYXRhIDwtIHJlYWRfZXhjZWwoImxpbmtlZGluX2luZm8ueGxzeCIpDQphZGRpdGlvbmFsX2RhdGEgPC0gcmVhZF9leGNlbCgiZmluYWxfb3V0cHV0Lnhsc3giKQ0KDQojIFByZXByb2Nlc2FyIGxvcyBkYXRvcw0KZGF0YSA8LSBkYXRhICU+JQ0KICBmaWx0ZXIoIWdyZXBsKCJMYXN0IHJvdW5kIGRhdGUgbm90IGZvdW5kIiwgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSkgJT4lDQogIGZpbHRlcighaXMubmEoYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSkgJT4lDQogIG11dGF0ZSgNCiAgICBgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWAgPSB5bWQoYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSwNCiAgICBZZWFyID0gYXMuaW50ZWdlcih5ZWFyKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpLA0KICAgIENvdW50cnlfTmFtZSA9IGNvdW50cnljb2RlKENvdW50cnksICJpc28yYyIsICJjb3VudHJ5Lm5hbWUiKSwNCiAgICBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAgPSBjYXNlX3doZW4oDQogICAgICBncmVwbCgiTSIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkgfiBhcy5udW1lcmljKGdzdWIoIlteMC05Ll0iLCAiIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgKiAxZTYsDQogICAgICBncmVwbCgiSyIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkgfiBhcy5udW1lcmljKGdzdWIoIlteMC05Ll0iLCAiIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgKiAxZTMsDQogICAgICBUUlVFIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpDQogICAgKSAgIyBNYW50ZW5lciBlbCBtb250byBlbiB1bmlkYWRlcyBvcmlnaW5hbGVzDQogICkNCg0KIyBGdXNpb25hciBsb3MgY29uanVudG9zIGRlIGRhdG9zIGJhc2Fkb3MgZW4gZWwgbm9tYnJlIGRlIGxhIGVtcHJlc2ENCm1lcmdlZF9kYXRhIDwtIG1lcmdlKGRhdGEsIGFkZGl0aW9uYWxfZGF0YSwgYnkgPSAiQ29tcGFueSBOYW1lIikNCg0KIyBDb252ZXJ0aXIgZWwgY8OzZGlnbyBkZSBwYcOtcyBJU08gYSBub21icmVzIGRlIHBhw61zZXMgZW4gaW5nbMOpcw0KbWVyZ2VkX2RhdGEkQ291bnRyeSA8LSBjb3VudHJ5Y29kZShtZXJnZWRfZGF0YSRgQ291bnRyeS54YCwgb3JpZ2luID0gJ2lzbzJjJywgZGVzdGluYXRpb24gPSAnY291bnRyeS5uYW1lJykNCg0KIyBGaWx0cmFyIHBhcmEgb2J0ZW5lciBzb2xvIGxhcyBlbXByZXNhcyBxdWUgYXBsaWNhbiBjb21vICJDTElFTlQiIHkgc2VsZWNjaW9uYXIgbGFzIGNvbHVtbmFzIGRpc3BvbmlibGVzDQpjbGllbnRzIDwtIG1lcmdlZF9kYXRhICU+JQ0KICBmaWx0ZXIoYFBvdGVudGlhbCBSb2xlYCA9PSAiQ0xJRU5UIikgJT4lDQogIHNlbGVjdChgQ29tcGFueSBOYW1lYCwgYENvbXBhbnkgU2l6ZWAsIENvdW50cnksIGBDb21wYW55IFR5cGVgLCANCiAgICAgICAgIGBOdW1iZXIgb2YgRW1wbG95ZWVzYCwgYEluZHVzdHJ5YCwgYEIyQiBvciBCMkNgLCANCiAgICAgICAgIGBQb3RlbnRpYWwgVmVydGljYWxgLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkgJT4lDQogIGRpc3RpbmN0KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKSAlPiUNCiAgbXV0YXRlKGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCA9IGRvbGxhcihgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAsIHByZWZpeCA9ICIkIiwgYmlnLm1hcmsgPSAiLiIsIGRlY2ltYWwubWFyayA9ICIsIikpICAjIEZvcm1hdGVhciBsYSBjYW50aWRhZCBkZSBpbnZlcnNpw7NuDQoNCiMgQ3JlYXIgdW5hIHRhYmxhIGludGVyYWN0aXZhIHBhcmEgdmlzdWFsaXphciBsYXMgZW1wcmVzYXMgcXVlIHNvbiAiQ0xJRU5UUyINCmNsaWVudHNfdGFibGUgPC0gZGF0YXRhYmxlKGNsaWVudHMsIA0KICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgYXV0b1dpZHRoID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgZG9tID0gJ3Q8ImJvdHRvbSJscD4nLCAgIyBNb3ZlciBsb3MgY29udHJvbGVzIGRlIHBhZ2luYWNpw7NuIGFiYWpvDQogICAgICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWCA9IFRSVUUpLA0KICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UsIA0KICAgICAgICAgIGNhcHRpb24gPSBodG1sdG9vbHM6OnRhZ3MkY2FwdGlvbigNCiAgICAgICAgICAgIHN0eWxlID0gJ2NhcHRpb24tc2lkZTogdG9wOyB0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtc2l6ZTogMTUwJTsgZm9udC13ZWlnaHQ6IGJvbGQ7JywNCiAgICAgICAgICAgICdMaXN0IG9mIENvbXBhbmllcyB0aGF0IEFwcGx5IGFzIENsaWVudHMnDQogICAgICAgICAgKSkNCg0KIyBHdWFyZGFyIGVsIGFyY2hpdm8gSFRNTA0KaHRtbHRvb2xzOjpzYXZlX2h0bWwoaHRtbHRvb2xzOjp0YWdMaXN0KGNsaWVudHNfdGFibGUpLCAiY2xpZW50c19saXN0Lmh0bWwiKQ0KDQojIE1vc3RyYXIgbGEgdGFibGEgaW50ZXJhY3RpdmEgZW4gZWwgdmlzb3IgZGUgUlN0dWRpbyBvIGVuIGVsIG5hdmVnYWRvcg0KY2xpZW50c190YWJsZQ0KDQoNCg0KYGBgDQoNCiMjIyMjIFBvdGVudGlhbCBwYXJ0bmVycw0KDQoNClRoaXMgdGFibGUgbGlzdHMgdGhlIGNvbXBhbmllcyBpZGVudGlmaWVkIGFzIHBvdGVudGlhbCBwYXJ0bmVycyBmb3IgRWR1TmV4dC4gVGhlIGNvbHVtbnMgaW5jbHVkZSBjb21wYW55IG5hbWUsIHNpemUsIGNvdW50cnksIHR5cGUsIG51bWJlciBvZiBlbXBsb3llZXMsIGluZHVzdHJ5LCBidXNpbmVzcyBtb2RlbCAoQjJCIG9yIEIyQyksIHBvdGVudGlhbCB2ZXJ0aWNhbCwgYW5kIHRoZSBhbW91bnQgb2YgdGhlIGxhc3QgZnVuZGluZyByb3VuZCBhcyByZXBvcnRlZCBieSBDcnVuY2hiYXNlLiBUaGlzIHRhYmxlIHByb3ZpZGVzIGRldGFpbGVkIGluZm9ybWF0aW9uIG9uIHBvdGVudGlhbCBwYXJ0bmVycywgYWlkaW5nIHN0cmF0ZWdpYyBjb2xsYWJvcmF0aW9ucy48L3A+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCjxzdHJvbmc+Tm90ZTo8L3N0cm9uZz4gVGhlIEVkdU5leHQgdGVhbSBjaG9zZSB0aGUgcm9sZXMgYW5kIGRlZmluaXRpb25zIGZvciBlYWNoIHJvbGUuPC9wPg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCiMgQ2FyZ2FyIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkoY291bnRyeWNvZGUpDQpsaWJyYXJ5KHNjYWxlcykNCg0KIyBDYXJnYXIgbG9zIGRhdG9zIChBc2VndXLDoW5kb3NlIGRlIHF1ZSBsb3MgYXJjaGl2b3MgZXN0w6luIGVuIGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbykNCmRhdGEgPC0gcmVhZF9leGNlbCgibGlua2VkaW5faW5mby54bHN4IikNCmFkZGl0aW9uYWxfZGF0YSA8LSByZWFkX2V4Y2VsKCJmaW5hbF9vdXRwdXQueGxzeCIpDQoNCiMgUHJlcHJvY2VzYXIgbG9zIGRhdG9zDQpkYXRhIDwtIGRhdGEgJT4lDQogIGZpbHRlcighZ3JlcGwoIkxhc3Qgcm91bmQgZGF0ZSBub3QgZm91bmQiLCBgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApKSAlPiUNCiAgbXV0YXRlKA0KICAgIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCA9IHltZChgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApLA0KICAgIFllYXIgPSBhcy5pbnRlZ2VyKHllYXIoYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSksDQogICAgQ291bnRyeV9OYW1lID0gY291bnRyeWNvZGUoQ291bnRyeSwgImlzbzJjIiwgImNvdW50cnkubmFtZSIpLA0KICAgIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCA9IGNhc2Vfd2hlbigNCiAgICAgIGdyZXBsKCJNIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKSAqIDFlNiwNCiAgICAgIGdyZXBsKCJLIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKSAqIDFlMywNCiAgICAgIFRSVUUgfiBhcy5udW1lcmljKGdzdWIoIlteMC05Ll0iLCAiIiwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkNCiAgICApICAjIE1hbnRlbmVyIGVsIG1vbnRvIGVuIHVuaWRhZGVzIG9yaWdpbmFsZXMNCiAgKQ0KDQojIEZ1c2lvbmFyIGxvcyBjb25qdW50b3MgZGUgZGF0b3MgYmFzYWRvcyBlbiBlbCBub21icmUgZGUgbGEgZW1wcmVzYQ0KbWVyZ2VkX2RhdGEgPC0gbWVyZ2UoZGF0YSwgYWRkaXRpb25hbF9kYXRhLCBieSA9ICJDb21wYW55IE5hbWUiKQ0KDQojIENvbnZlcnRpciBlbCBjw7NkaWdvIGRlIHBhw61zIElTTyBhIG5vbWJyZXMgZGUgcGHDrXNlcyBlbiBpbmdsw6lzDQptZXJnZWRfZGF0YSRDb3VudHJ5IDwtIGNvdW50cnljb2RlKG1lcmdlZF9kYXRhJGBDb3VudHJ5LnhgLCBvcmlnaW4gPSAnaXNvMmMnLCBkZXN0aW5hdGlvbiA9ICdjb3VudHJ5Lm5hbWUnKQ0KDQojIEZpbHRyYXIgcGFyYSBvYnRlbmVyIHNvbG8gbGFzIGVtcHJlc2FzIHF1ZSBhcGxpY2FuIGNvbW8gIlBBUlRORVIiIHkgc2VsZWNjaW9uYXIgbGFzIGNvbHVtbmFzIGRpc3BvbmlibGVzDQpwYXJ0bmVycyA8LSBtZXJnZWRfZGF0YSAlPiUNCiAgZmlsdGVyKGBQb3RlbnRpYWwgUm9sZWAgPT0gIlBBUlRORVIiKSAlPiUNCiAgc2VsZWN0KGBDb21wYW55IE5hbWVgLCBgQ29tcGFueSBTaXplYCwgQ291bnRyeSwgYENvbXBhbnkgVHlwZWAsIA0KICAgICAgICAgYE51bWJlciBvZiBFbXBsb3llZXNgLCBgSW5kdXN0cnlgLCBgQjJCIG9yIEIyQ2AsIA0KICAgICAgICAgYFBvdGVudGlhbCBWZXJ0aWNhbGAsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCwgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgKSAlPiUNCiAgZGlzdGluY3QoKSAlPiUNCiAgYXJyYW5nZShkZXNjKGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICU+JQ0KICBtdXRhdGUoYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gZG9sbGFyKGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCwgcHJlZml4ID0gIiQiLCBiaWcubWFyayA9ICIuIiwgZGVjaW1hbC5tYXJrID0gIiwiKSkgICMgRm9ybWF0ZWFyIGxhIGNhbnRpZGFkIGRlIGludmVyc2nDs24NCg0KIyBDcmVhciB1bmEgdGFibGEgaW50ZXJhY3RpdmEgcGFyYSB2aXN1YWxpemFyIGxhcyBlbXByZXNhcyBxdWUgc29uICJQQVJUTkVSUyINCnBhcnRuZXJzX3RhYmxlIDwtIGRhdGF0YWJsZShwYXJ0bmVycywgDQogICAgICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBhdXRvV2lkdGggPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAndDwiYm90dG9tImxwPicsICAjIE1vdmVyIGxvcyBjb250cm9sZXMgZGUgcGFnaW5hY2nDs24gYWJham8NCiAgICAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxYID0gVFJVRSksDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwgDQogICAgICAgICAgY2FwdGlvbiA9IGh0bWx0b29sczo6dGFncyRjYXB0aW9uKA0KICAgICAgICAgICAgc3R5bGUgPSAnY2FwdGlvbi1zaWRlOiB0b3A7IHRleHQtYWxpZ246IGNlbnRlcjsgZm9udC1zaXplOiAxNTAlOyBmb250LXdlaWdodDogYm9sZDsnLA0KICAgICAgICAgICAgJ0xpc3Qgb2YgQ29tcGFuaWVzIHRoYXQgQXBwbHkgYXMgUGFydG5lcnMnDQogICAgICAgICAgKSkNCg0KIyBHdWFyZGFyIGVsIGFyY2hpdm8gSFRNTA0KaHRtbHRvb2xzOjpzYXZlX2h0bWwoaHRtbHRvb2xzOjp0YWdMaXN0KHBhcnRuZXJzX3RhYmxlKSwgInBhcnRuZXJzX2xpc3QuaHRtbCIpDQoNCiMgTW9zdHJhciBsYSB0YWJsYSBpbnRlcmFjdGl2YSBlbiBlbCB2aXNvciBkZSBSU3R1ZGlvIG8gZW4gZWwgbmF2ZWdhZG9yDQpwYXJ0bmVyc190YWJsZQ0KDQoNCmBgYA0KDQojIyMjIyBQb3RlbnRpYWwgY29tcGV0aXRvcnMNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyB0YWJsZSBsaXN0cyB0aGUgY29tcGFuaWVzIGlkZW50aWZpZWQgYXMgcG90ZW50aWFsIGNvbXBldGl0b3JzIGZvciBFZHVOZXh0LiBUaGUgY29sdW1ucyBpbmNsdWRlIGNvbXBhbnkgbmFtZSwgc2l6ZSwgY291bnRyeSwgdHlwZSwgbnVtYmVyIG9mIGVtcGxveWVlcywgaW5kdXN0cnksIGJ1c2luZXNzIG1vZGVsIChCMkIgb3IgQjJDKSwgcG90ZW50aWFsIHZlcnRpY2FsLCBhbmQgdGhlIGFtb3VudCBvZiB0aGUgbGFzdCBmdW5kaW5nIHJvdW5kIGFzIHJlcG9ydGVkIGJ5IENydW5jaGJhc2UuIFRoaXMgdGFibGUgcHJvdmlkZXMgZGV0YWlsZWQgaW5mb3JtYXRpb24gb24gcG90ZW50aWFsIGNvbXBldGl0b3JzLCBhaWRpbmcgY29tcGV0aXRpdmUgYW5hbHlzaXMuPC9wPg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KPHN0cm9uZz5Ob3RlOjwvc3Ryb25nPiBUaGUgRWR1TmV4dCB0ZWFtIGNob3NlIHRoZSByb2xlcyBhbmQgZGVmaW5pdGlvbnMgZm9yIGVhY2ggcm9sZS48L3A+DQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBDYXJnYXIgbGFzIGxpYnJlcsOtYXMgbmVjZXNhcmlhcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KERUKQ0KbGlicmFyeShjb3VudHJ5Y29kZSkNCmxpYnJhcnkoc2NhbGVzKQ0KDQojIENhcmdhciBsb3MgZGF0b3MgKEFzZWd1csOhbmRvc2UgZGUgcXVlIGxvcyBhcmNoaXZvcyBlc3TDqW4gZW4gZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvKQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KYWRkaXRpb25hbF9kYXRhIDwtIHJlYWRfZXhjZWwoImZpbmFsX291dHB1dC54bHN4IikNCg0KIyBQcmVwcm9jZXNhciBsb3MgZGF0b3MNCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBkYXRlIG5vdCBmb3VuZCIsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBtdXRhdGUoDQogICAgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgID0geW1kKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCksDQogICAgWWVhciA9IGFzLmludGVnZXIoeWVhcihgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApKSwNCiAgICBDb3VudHJ5X05hbWUgPSBjb3VudHJ5Y29kZShDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIiksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gY2FzZV93aGVuKA0KICAgICAgZ3JlcGwoIk0iLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LA0KICAgICAgZ3JlcGwoIksiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWUzLA0KICAgICAgVFJVRSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKQ0KICAgICkgICMgTWFudGVuZXIgZWwgbW9udG8gZW4gdW5pZGFkZXMgb3JpZ2luYWxlcw0KICApDQoNCiMgRnVzaW9uYXIgbG9zIGNvbmp1bnRvcyBkZSBkYXRvcyBiYXNhZG9zIGVuIGVsIG5vbWJyZSBkZSBsYSBlbXByZXNhDQptZXJnZWRfZGF0YSA8LSBtZXJnZShkYXRhLCBhZGRpdGlvbmFsX2RhdGEsIGJ5ID0gIkNvbXBhbnkgTmFtZSIpDQoNCiMgQ29udmVydGlyIGVsIGPDs2RpZ28gZGUgcGHDrXMgSVNPIGEgbm9tYnJlcyBkZSBwYcOtc2VzIGVuIGluZ2zDqXMNCm1lcmdlZF9kYXRhJENvdW50cnkgPC0gY291bnRyeWNvZGUobWVyZ2VkX2RhdGEkYENvdW50cnkueGAsIG9yaWdpbiA9ICdpc28yYycsIGRlc3RpbmF0aW9uID0gJ2NvdW50cnkubmFtZScpDQoNCiMgRmlsdHJhciBwYXJhIG9idGVuZXIgc29sbyBsYXMgZW1wcmVzYXMgcXVlIGFwbGljYW4gY29tbyAiQ09NUEVUSVRPUiIgeSBzZWxlY2Npb25hciBsYXMgY29sdW1uYXMgZGlzcG9uaWJsZXMNCmNvbXBldGl0b3JzIDwtIG1lcmdlZF9kYXRhICU+JQ0KICBmaWx0ZXIoYFBvdGVudGlhbCBSb2xlYCA9PSAiQ09NUEVUSVRPUiIpICU+JQ0KICBzZWxlY3QoYENvbXBhbnkgTmFtZWAsIGBDb21wYW55IFNpemVgLCBDb3VudHJ5LCBgQ29tcGFueSBUeXBlYCwgDQogICAgICAgICBgTnVtYmVyIG9mIEVtcGxveWVlc2AsIGBJbmR1c3RyeWAsIGBCMkIgb3IgQjJDYCwgDQogICAgICAgICBgUG90ZW50aWFsIFZlcnRpY2FsYCwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgLCBgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApICU+JQ0KICBkaXN0aW5jdCgpICU+JQ0KICBhcnJhbmdlKGRlc2MoYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgJT4lDQogIG11dGF0ZShgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAgPSBkb2xsYXIoYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgLCBwcmVmaXggPSAiJCIsIGJpZy5tYXJrID0gIi4iLCBkZWNpbWFsLm1hcmsgPSAiLCIpKSAgIyBGb3JtYXRlYXIgbGEgY2FudGlkYWQgZGUgaW52ZXJzacOzbg0KDQojIENyZWFyIHVuYSB0YWJsYSBpbnRlcmFjdGl2YSBwYXJhIHZpc3VhbGl6YXIgbGFzIGVtcHJlc2FzIHF1ZSBzb24gIkNPTVBFVElUT1JTIg0KY29tcGV0aXRvcnNfdGFibGUgPC0gZGF0YXRhYmxlKGNvbXBldGl0b3JzLCANCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9XaWR0aCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRvbSA9ICd0PCJib3R0b20ibHA+JywgICMgTW92ZXIgbG9zIGNvbnRyb2xlcyBkZSBwYWdpbmFjacOzbiBhYmFqbw0KICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFggPSBUUlVFKSwNCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLCANCiAgICAgICAgICBjYXB0aW9uID0gaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oDQogICAgICAgICAgICBzdHlsZSA9ICdjYXB0aW9uLXNpZGU6IHRvcDsgdGV4dC1hbGlnbjogY2VudGVyOyBmb250LXNpemU6IDE1MCU7IGZvbnQtd2VpZ2h0OiBib2xkOycsDQogICAgICAgICAgICAnTGlzdCBvZiBDb21wYW5pZXMgdGhhdCBBcHBseSBhcyBDb21wZXRpdG9ycycNCiAgICAgICAgICApKQ0KDQojIEd1YXJkYXIgZWwgYXJjaGl2byBIVE1MDQpodG1sdG9vbHM6OnNhdmVfaHRtbChodG1sdG9vbHM6OnRhZ0xpc3QoY29tcGV0aXRvcnNfdGFibGUpLCAiY29tcGV0aXRvcnNfbGlzdC5odG1sIikNCg0KIyBNb3N0cmFyIGxhIHRhYmxhIGludGVyYWN0aXZhIGVuIGVsIHZpc29yIGRlIFJTdHVkaW8gbyBlbiBlbCBuYXZlZ2Fkb3INCmNvbXBldGl0b3JzX3RhYmxlDQoNCmBgYA0KDQojIyMjIyBQb3RlbnRpYWwgcHJvdmlkZXJzDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoaXMgdGFibGUgbGlzdHMgdGhlIGNvbXBhbmllcyBpZGVudGlmaWVkIGFzIHBvdGVudGlhbCBwcm92aWRlcnMgZm9yIEVkdU5leHQuIFRoZSBjb2x1bW5zIGluY2x1ZGUgY29tcGFueSBuYW1lLCBzaXplLCBjb3VudHJ5LCB0eXBlLCBudW1iZXIgb2YgZW1wbG95ZWVzLCBpbmR1c3RyeSwgYnVzaW5lc3MgbW9kZWwgKEIyQiBvciBCMkMpLCBwb3RlbnRpYWwgdmVydGljYWwsIGFuZCB0aGUgYW1vdW50IG9mIHRoZSBsYXN0IGZ1bmRpbmcgcm91bmQgYXMgcmVwb3J0ZWQgYnkgQ3J1bmNoYmFzZS4gVGhpcyB0YWJsZSBwcm92aWRlcyBkZXRhaWxlZCBpbmZvcm1hdGlvbiBvbiBwb3RlbnRpYWwgcHJvdmlkZXJzLCBhaWRpbmcgc3RyYXRlZ2ljIHNvdXJjaW5nIGRlY2lzaW9ucy48L3A+DQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBDYXJnYXIgbGFzIGxpYnJlcsOtYXMgbmVjZXNhcmlhcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KERUKQ0KbGlicmFyeShjb3VudHJ5Y29kZSkNCmxpYnJhcnkoc2NhbGVzKQ0KDQojIENhcmdhciBsb3MgZGF0b3MgKEFzZWd1csOhbmRvc2UgZGUgcXVlIGxvcyBhcmNoaXZvcyBlc3TDqW4gZW4gZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvKQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJsaW5rZWRpbl9pbmZvLnhsc3giKQ0KYWRkaXRpb25hbF9kYXRhIDwtIHJlYWRfZXhjZWwoImZpbmFsX291dHB1dC54bHN4IikNCg0KIyBQcmVwcm9jZXNhciBsb3MgZGF0b3MNCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBkYXRlIG5vdCBmb3VuZCIsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBtdXRhdGUoDQogICAgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgID0geW1kKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCksDQogICAgWWVhciA9IGFzLmludGVnZXIoeWVhcihgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApKSwNCiAgICBDb3VudHJ5X05hbWUgPSBjb3VudHJ5Y29kZShDb3VudHJ5LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIiksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gY2FzZV93aGVuKA0KICAgICAgZ3JlcGwoIk0iLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LA0KICAgICAgZ3JlcGwoIksiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWUzLA0KICAgICAgVFJVRSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKQ0KICAgICkgICMgTWFudGVuZXIgZWwgbW9udG8gZW4gdW5pZGFkZXMgb3JpZ2luYWxlcw0KICApDQoNCiMgRnVzaW9uYXIgbG9zIGNvbmp1bnRvcyBkZSBkYXRvcyBiYXNhZG9zIGVuIGVsIG5vbWJyZSBkZSBsYSBlbXByZXNhDQptZXJnZWRfZGF0YSA8LSBtZXJnZShkYXRhLCBhZGRpdGlvbmFsX2RhdGEsIGJ5ID0gIkNvbXBhbnkgTmFtZSIpDQoNCiMgQ29udmVydGlyIGVsIGPDs2RpZ28gZGUgcGHDrXMgSVNPIGEgbm9tYnJlcyBkZSBwYcOtc2VzIGVuIGluZ2zDqXMNCm1lcmdlZF9kYXRhJENvdW50cnkgPC0gY291bnRyeWNvZGUobWVyZ2VkX2RhdGEkYENvdW50cnkueGAsIG9yaWdpbiA9ICdpc28yYycsIGRlc3RpbmF0aW9uID0gJ2NvdW50cnkubmFtZScpDQoNCiMgRmlsdHJhciBwYXJhIG9idGVuZXIgc29sbyBsYXMgZW1wcmVzYXMgcXVlIGFwbGljYW4gY29tbyAiUFJPVklERVIiIHkgc2VsZWNjaW9uYXIgbGFzIGNvbHVtbmFzIGRpc3BvbmlibGVzDQpwcm92aWRlcnMgPC0gbWVyZ2VkX2RhdGEgJT4lDQogIGZpbHRlcihgUG90ZW50aWFsIFJvbGVgID09ICJQUk9WSURFUiIpICU+JQ0KICBzZWxlY3QoYENvbXBhbnkgTmFtZWAsIGBDb21wYW55IFNpemVgLCBDb3VudHJ5LCBgQ29tcGFueSBUeXBlYCwgDQogICAgICAgICBgTnVtYmVyIG9mIEVtcGxveWVlc2AsIGBJbmR1c3RyeWAsIGBCMkIgb3IgQjJDYCwgDQogICAgICAgICBgUG90ZW50aWFsIFZlcnRpY2FsYCwgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgLCBgTGFzdCBSb3VuZCBGb3JtYXR0ZWQgRGF0ZWApICU+JQ0KICBkaXN0aW5jdCgpICU+JQ0KICBhcnJhbmdlKGRlc2MoYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgKSkgJT4lDQogIG11dGF0ZShgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAgPSBkb2xsYXIoYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgLCBwcmVmaXggPSAiJCIsIGJpZy5tYXJrID0gIi4iLCBkZWNpbWFsLm1hcmsgPSAiLCIpKSAgIyBGb3JtYXRlYXIgbGEgY2FudGlkYWQgZGUgaW52ZXJzacOzbg0KDQojIENyZWFyIHVuYSB0YWJsYSBpbnRlcmFjdGl2YSBwYXJhIHZpc3VhbGl6YXIgbGFzIGVtcHJlc2FzIHF1ZSBzb24gIlBST1ZJREVSUyINCnByb3ZpZGVyc190YWJsZSA8LSBkYXRhdGFibGUocHJvdmlkZXJzLCANCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9XaWR0aCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRvbSA9ICd0PCJib3R0b20ibHA+JywgICMgTW92ZXIgbG9zIGNvbnRyb2xlcyBkZSBwYWdpbmFjacOzbiBhYmFqbw0KICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFggPSBUUlVFKSwNCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLCANCiAgICAgICAgICBjYXB0aW9uID0gaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oDQogICAgICAgICAgICBzdHlsZSA9ICdjYXB0aW9uLXNpZGU6IHRvcDsgdGV4dC1hbGlnbjogY2VudGVyOyBmb250LXNpemU6IDE1MCU7IGZvbnQtd2VpZ2h0OiBib2xkOycsDQogICAgICAgICAgICAnTGlzdCBvZiBDb21wYW5pZXMgdGhhdCBBcHBseSBhcyBQcm92aWRlcnMnDQogICAgICAgICAgKSkNCg0KIyBHdWFyZGFyIGVsIGFyY2hpdm8gSFRNTA0KaHRtbHRvb2xzOjpzYXZlX2h0bWwoaHRtbHRvb2xzOjp0YWdMaXN0KHByb3ZpZGVyc190YWJsZSksICJwcm92aWRlcnNfbGlzdC5odG1sIikNCg0KIyBNb3N0cmFyIGxhIHRhYmxhIGludGVyYWN0aXZhIGVuIGVsIHZpc29yIGRlIFJTdHVkaW8gbyBlbiBlbCBuYXZlZ2Fkb3INCnByb3ZpZGVyc190YWJsZQ0KDQoNCmBgYA0KDQoNCg0KIyMjIyMgUmFua2luZyBvZiBzdGFydHVwcw0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBsZWZ0OyI+DQpUaGlzIGhvcml6b250YWwgYmFyIGNoYXJ0IHJhbmtzIGNvbXBhbmllcyBieSB0aGUgYW1vdW50IG9mIHRoZWlyIG1vc3QgcmVjZW50IGludmVzdG1lbnQsIGFzIHJlcG9ydGVkIGJ5IENydW5jaGJhc2UuIFRoZSBsZW5ndGggb2YgZWFjaCBiYXIgcmVwcmVzZW50cyB0aGUgc2l6ZSBvZiB0aGUgaW52ZXN0bWVudCwgYW5kIHRoZSBjb21wYW55IG5hbWVzIGFyZSBsaXN0ZWQgYWxvbmcgdGhlIHZlcnRpY2FsIGF4aXMuIFRoaXMgdmlzdWFsaXphdGlvbiBoZWxwcyB0byBxdWlja2x5IGlkZW50aWZ5IHRoZSBtb3N0IGhlYXZpbHkgZnVuZGVkIGNvbXBhbmllcyB3aXRoaW4gdGhlIEVkVGVjaCBzZWN0b3IuPC9wPg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KPHN0cm9uZz5Ob3RlOjwvc3Ryb25nPiBUaGUgRWR1TmV4dCB0ZWFtIGNob3NlIHRoZSByb2xlcyBhbmQgZGVmaW5pdGlvbnMgZm9yIGVhY2ggcm9sZS48L3A+DQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTJ9DQoNCiMgQ2FyZ2FyIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGh0bWx0b29scykNCg0KIyBDYXJnYXIgbG9zIGRhdG9zIChBc3VtaWVuZG8gcXVlIGxvcyBkYXRvcyBlc3TDoW4gZW4gdW5hIGhvamEgbGxhbWFkYSAibGlua2VkaW5faW5mby54bHN4IikNCmRhdGEgPC0gcmVhZF9leGNlbCgibGlua2VkaW5faW5mby54bHN4IikNCg0KIyBQcmVwcm9jZXNhciBsb3MgZGF0b3MNCmRhdGEgPC0gZGF0YSAlPiUNCiAgZmlsdGVyKCFncmVwbCgiTGFzdCByb3VuZCBkYXRlIG5vdCBmb3VuZCIsIGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCkpICU+JQ0KICBtdXRhdGUoDQogICAgYExhc3QgUm91bmQgRm9ybWF0dGVkIERhdGVgID0geW1kKGBMYXN0IFJvdW5kIEZvcm1hdHRlZCBEYXRlYCksDQogICAgYENydW5jaGJhc2UgTGFzdCBSb3VuZCBBbW91bnRgID0gY2FzZV93aGVuKA0KICAgICAgZ3JlcGwoIk0iLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWU2LA0KICAgICAgZ3JlcGwoIksiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApIH4gYXMubnVtZXJpYyhnc3ViKCJbXjAtOS5dIiwgIiIsIGBDcnVuY2hiYXNlIExhc3QgUm91bmQgQW1vdW50YCkpICogMWUzLA0KICAgICAgVFJVRSB+IGFzLm51bWVyaWMoZ3N1YigiW14wLTkuXSIsICIiLCBgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGApKQ0KICAgICkgICMgTWFudGVuZXIgZWwgbW9udG8gZW4gdW5pZGFkZXMgb3JpZ2luYWxlcw0KICApDQoNCiMgQ2FyZ2FyIGxvcyBkYXRvcyBhZGljaW9uYWxlcyBjb24gbGEgaW5mb3JtYWNpw7NuIGRlIGxvcyByb2xlcyBwb3RlbmNpYWxlcw0KYWRkaXRpb25hbF9kYXRhIDwtIHJlYWRfZXhjZWwoImZpbmFsX291dHB1dC54bHN4IikNCg0KIyBGdXNpb25hciBsb3MgY29uanVudG9zIGRlIGRhdG9zIGJhc2Fkb3MgZW4gZWwgbm9tYnJlIGRlIGxhIGVtcHJlc2ENCm1lcmdlZF9kYXRhIDwtIG1lcmdlKGRhdGEsIGFkZGl0aW9uYWxfZGF0YSwgYnkgPSAiQ29tcGFueSBOYW1lIikNCg0KIyBDb25jYXRlbmFyIHJvbGVzIHBhcmEgY2FkYSBlbXByZXNhIHkgY2FsY3VsYXIgbGEgaW52ZXJzacOzbiBtw6FzIHJlY2llbnRlDQptZXJnZWRfZGF0YSA8LSBtZXJnZWRfZGF0YSAlPiUNCiAgZ3JvdXBfYnkoYENvbXBhbnkgTmFtZWApICU+JQ0KICBzdW1tYXJpc2UoDQogICAgUm9sZXMgPSBwYXN0ZSh1bmlxdWUoYFBvdGVudGlhbCBSb2xlYCksIGNvbGxhcHNlID0gIiwgIiksDQogICAgTW9zdF9SZWNlbnRfSW52ZXN0bWVudCA9IG1heChgQ3J1bmNoYmFzZSBMYXN0IFJvdW5kIEFtb3VudGAsIG5hLnJtID0gVFJVRSkNCiAgKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBhcnJhbmdlKGRlc2MoTW9zdF9SZWNlbnRfSW52ZXN0bWVudCkpICU+JQ0KICBoZWFkKDM1KSAgIyBMaW1pdGFyIGEgbGFzIDM1IGVtcHJlc2FzIHByaW5jaXBhbGVzDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGhvcml6b250YWwgdXNhbmRvIHBsb3RseQ0KcGxvdCA8LSBwbG90X2x5KA0KICBtZXJnZWRfZGF0YSwNCiAgeCA9IH5Nb3N0X1JlY2VudF9JbnZlc3RtZW50LA0KICB5ID0gfnJlb3JkZXIoYENvbXBhbnkgTmFtZWAsIE1vc3RfUmVjZW50X0ludmVzdG1lbnQpLA0KICB0eXBlID0gJ2JhcicsDQogIG9yaWVudGF0aW9uID0gJ2gnLA0KICB0ZXh0ID0gfnBhc3RlKCdSb2xlczonLCBSb2xlcywgJzxicj5JbnZlc3RtZW50OiAkJywgZm9ybWF0KE1vc3RfUmVjZW50X0ludmVzdG1lbnQsIGJpZy5tYXJrID0gIiwiKSksDQogIGhvdmVyaW5mbyA9ICd0ZXh0JywNCiAgbWFya2VyID0gbGlzdChjb2xvciA9ICdza3libHVlJykNCikgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZSA9IGxpc3QoDQogICAgICB0ZXh0ID0gIlJhbmtpbmcgb2YgQ29tcGFuaWVzIGJ5IE1vc3QgUmVjZW50IEludmVzdG1lbnQiLA0KICAgICAgeCA9IDAuNSwNCiAgICAgIHkgPSAwLjk1LA0KICAgICAgeGFuY2hvciA9ICdjZW50ZXInLA0KICAgICAgeWFuY2hvciA9ICd0b3AnLA0KICAgICAgZm9udCA9IGxpc3Qoc2l6ZSA9IDE4KQ0KICAgICksDQogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIk1vc3QgUmVjZW50IEludmVzdG1lbnQgKFVTRCkiKSwNCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQ29tcGFueSBOYW1lIiwgYXV0b21hcmdpbiA9IFRSVUUpLA0KICAgIG1hcmdpbiA9IGxpc3QobCA9IDI1MCwgciA9IDUwLCBiID0gNTAsIHQgPSAxMDAsIHBhZCA9IDEwKSwgICMgQWp1c3RhciBtw6FyZ2VuZXMgcGFyYSBhanVzdGFyIGVsIGNvbnRlbmlkbw0KICAgIGhlaWdodCA9IDgwMCwgICMgRXN0YWJsZWNlciBsYSBhbHR1cmEgcGFyYSAzNSBlbXByZXNhcw0KICAgIHdpZHRoID0gMTAwMCwgICMgQWp1c3RhciBlbCBhbmNobyBwYXJhIGV2aXRhciBlbCBkZXNwbGF6YW1pZW50byBob3Jpem9udGFsDQogICAgYmFyZ2FwID0gMC4xICAjIEFqdXN0YXIgZWwgZXNwYWNpbyBlbnRyZSBiYXJyYXMgcGFyYSBoYWNlcmxhcyBtw6FzIGdyYW5kZXMNCiAgKQ0KDQojIEd1YXJkYXIgZWwgYXJjaGl2byBIVE1MDQpodG1sdG9vbHM6OnNhdmVfaHRtbChodG1sdG9vbHM6OnRhZ0xpc3QocGxvdCksICJwbG90X25vX3Njcm9sbC5odG1sIikNCg0KIyBJbmNsdWlyIGVzdGUgY8OzZGlnbyBlbiB0dSBhcmNoaXZvIFIgTWFya2Rvd24NCiMgTW9zdHJhciBlbCBncsOhZmljbyBpbnRlcmFjdGl2byBlbiBlbCBkb2N1bWVudG8gUiBNYXJrZG93bg0KcGxvdA0KDQpgYGANCg0KDQojIyMNCg0KIyMjIyAgey50YWJzZXR9DQoNCioqKioNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KICA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZTlmNWRiOyBjb2xvcjpibGFjazsgYm9yZGVyLXJhZGl1czo1cHg7IHBhZGRpbmc6IDAuMmVtIDAuNWVtOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij7wn5OEIDxiPkJ5IENhcGFiaWxpdGllcyA8L2I+PC9zcGFuPg0KPC9wPg0KDQoNCiMjIyMjIE51bWJlciBvZiBjb21wYW5pZXMNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyB0YWJsZSBsaXN0cyB2YXJpb3VzIGNhcGFiaWxpdGllcyBpZGVudGlmaWVkIGluIHRoZSBhbmFseXplZCBjb21wYW5pZXMsIHNob3dpbmcgaG93IG1hbnkgY29tcGFuaWVzIHBvc3Nlc3MgZWFjaCBjYXBhYmlsaXR5LiBUaGUgY29sdW1ucyByZXByZXNlbnQgZGlmZmVyZW50IGNhcGFiaWxpdGllcywgd2hpbGUgdGhlIHJvd3MgZGlzcGxheSB0aGUgY291bnQgb2YgY29tcGFuaWVzIHRoYXQgcG9zc2VzcyBlYWNoIGNhcGFiaWxpdHkuIFRoZSAiVG90YWwiIGNvbHVtbiBzdW1zIHVwIHRoZSBudW1iZXIgb2YgY29tcGFuaWVzIGZvciBlYWNoIGNhcGFiaWxpdHkuIFRoaXMgdGFibGUgcHJvdmlkZXMgYSBkZXRhaWxlZCBvdmVydmlldyBvZiB0aGUgZGlzdHJpYnV0aW9uIG9mIHNwZWNpZmljIGNhcGFiaWxpdGllcyBhY3Jvc3MgY29tcGFuaWVzLCBhaWRpbmcgaW4gdW5kZXJzdGFuZGluZyB0aGUgc3RyZW5ndGhzIGFuZCBmb2N1cyBhcmVhcyB3aXRoaW4gdGhlIEVkVGVjaCBzZWN0b3IuPC9wPg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KPHN0cm9uZz5Ob3RlOjwvc3Ryb25nPiBUaGUgY2FwYWJpbGl0aWVzIHdlcmUgdGFrZW4gZnJvbSB0aGUgSG9sb25JUSBzb3VyY2UgYW5kIGFyZSBleHBsYWluZWQgaW4gbW9yZSBkZXRhaWwgZWFybGllciBpbiB0aGUgcmVwb3J0LjwvcD4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQoNCiMgTG9hZCB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQoNCiMgTG9hZCB0aGUgZGF0YQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJmaW5hbF9vdXRwdXQueGxzeCIpDQoNCiMgQ29tYmluZSBhbGwgY2FwYWJpbGl0aWVzIGludG8gYSBzaW5nbGUgbG9uZy1mb3JtYXQgZGF0YWZyYW1lDQpjYXBhYmlsaXR5X2RhdGEgPC0gZGF0YSAlPiUNCiAgc2VsZWN0KGBDYXBhYmlsaXR5IDFgLCBgQ2FwYWJpbGl0eSAyYCwgYENhcGFiaWxpdHkgM2AsIGBDYXBhYmlsaXR5IDRgLCBgQ2FwYWJpbGl0eSA1YCkgJT4lDQogIGdhdGhlcihrZXkgPSAiQ2FwYWJpbGl0eV9UeXBlIiwgdmFsdWUgPSAiQ2FwYWJpbGl0eSIpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKENhcGFiaWxpdHkpKQ0KDQojIENvdW50IHRoZSBvY2N1cnJlbmNlcyBvZiBlYWNoIGNhcGFiaWxpdHkgaW4gZWFjaCBjb2x1bW4NCmNhcGFiaWxpdHlfY291bnRzIDwtIGNhcGFiaWxpdHlfZGF0YSAlPiUNCiAgY291bnQoQ2FwYWJpbGl0eV9UeXBlLCBDYXBhYmlsaXR5KSAlPiUNCiAgc3ByZWFkKGtleSA9IENhcGFiaWxpdHlfVHlwZSwgdmFsdWUgPSBuLCBmaWxsID0gMCkgJT4lDQogIG11dGF0ZShUb3RhbCA9IGBDYXBhYmlsaXR5IDFgICsgYENhcGFiaWxpdHkgMmAgKyBgQ2FwYWJpbGl0eSAzYCArIGBDYXBhYmlsaXR5IDRgICsgYENhcGFiaWxpdHkgNWApICU+JQ0KICBhcnJhbmdlKGRlc2MoVG90YWwpKQ0KDQojIENyZWF0ZSB0aGUgdGFibGUgdXNpbmcga2FibGUNCmthYmxlX3RhYmxlIDwtIGNhcGFiaWxpdHlfY291bnRzICU+JQ0KICBrYWJsZSgiaHRtbCIsIGNvbC5uYW1lcyA9IGMoIkNhcGFiaWxpdHkiLCAiQ2FwYWJpbGl0eSAxIiwgIkNhcGFiaWxpdHkgMiIsICJDYXBhYmlsaXR5IDMiLCAiQ2FwYWJpbGl0eSA0IiwgIkNhcGFiaWxpdHkgNSIsICJUb3RhbCIpLCBhbGlnbiA9ICdjJykgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSkgJT4lDQogIGNvbHVtbl9zcGVjKDEsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICJwdXJwbGUiKSAlPiUNCiAgY29sdW1uX3NwZWMoNywgYm9sZCA9IFRSVUUsIGNvbG9yID0gInB1cnBsZSIpICU+JQ0KICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMSwgIk51bWJlciBvZiBBcHBlYXJhbmNlcyIgPSA2KSkgJT4lDQogIHNjcm9sbF9ib3goaGVpZ2h0ID0gIjUwMHB4Iiwgd2lkdGggPSAiMTAwJSIpDQoNCiMgU2F2ZSB0aGUgdGFibGUgYXMgYW4gSFRNTCBmaWxlDQpzYXZlX2thYmxlKGthYmxlX3RhYmxlLCAiY2FwYWJpbGl0eV9yYW5raW5nX3RhYmxlLmh0bWwiLCBzZWxmX2NvbnRhaW5lZCA9IFRSVUUpDQoNCiMgRGlzcGxheSB0aGUgdGFibGUNCmthYmxlX3RhYmxlDQoNCg0KYGBgDQoNCiMjIyMjIFNjb3JlDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCjxzdHJvbmc+U2NvcmUgYnkgQ2FwYWJpbGl0aWVzPC9zdHJvbmc+PC9wPg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhpcyB0YWJsZSBhc3NpZ25zIGEgd2VpZ2h0ZWQgaW1wb3J0YW5jZSB0byBlYWNoIGNhcGFiaWxpdHkgYmFzZWQgb24gaXRzIHBvc2l0aW9uIHRvIG1lYXN1cmUgYW5kIHJhbmsgdGhlIG1vc3QgaW1wb3J0YW50IGNhcGFiaWxpdGllcyBlZmZlY3RpdmVseS4gVGhlIHdlaWdodHMgYXJlIGFzc2lnbmVkIGFzIGZvbGxvd3M6PC9wPg0KPHVsIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCiAgPGxpPkNhcGFiaWxpdHkgMSBpcyBtdWx0aXBsaWVkIGJ5IDU8L2xpPg0KICA8bGk+Q2FwYWJpbGl0eSAyIGlzIG11bHRpcGxpZWQgYnkgNDwvbGk+DQogIDxsaT5DYXBhYmlsaXR5IDMgaXMgbXVsdGlwbGllZCBieSAzPC9saT4NCiAgPGxpPkNhcGFiaWxpdHkgNCBpcyBtdWx0aXBsaWVkIGJ5IDI8L2xpPg0KICA8bGk+Q2FwYWJpbGl0eSA1IGlzIG11bHRpcGxpZWQgYnkgMTwvbGk+DQo8L3VsPg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhlIHRvdGFsIHNjb3JlIGZvciBlYWNoIGNhcGFiaWxpdHkgaXMgdGhlbiBjYWxjdWxhdGVkIGJ5IHN1bW1pbmcgdGhlc2Ugd2VpZ2h0ZWQgdmFsdWVzLCBlbnN1cmluZyB0aGF0IGhpZ2hlciBpbXBvcnRhbmNlIGlzIGdpdmVuIHRvIGNhcGFiaWxpdGllcyBsaXN0ZWQgZWFybGllci4gVGhpcyBtZXRob2QgcmVmbGVjdHMgdGhlIHNpZ25pZmljYW5jZSBvZiBlYWNoIGNhcGFiaWxpdHkgaW4gdGhlIG92ZXJhbGwgcmFua2luZy4gVGhlIHRhYmxlIGluY2x1ZGVzIGNvbHVtbnMgZm9yIGVhY2ggY2FwYWJpbGl0eSdzIHNjb3JlIGFuZCB0aGUgdG90YWwgc2NvcmUgZm9yIGVhY2ggcm93LjwvcD4NCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NCjxzdHJvbmc+Tm90ZTo8L3N0cm9uZz4gVGhlIGNhcGFiaWxpdGllcyB3ZXJlIHRha2VuIGZyb20gdGhlIEhvbG9uSVEgc291cmNlIGFuZCBhcmUgZXhwbGFpbmVkIGluIG1vcmUgZGV0YWlsIGVhcmxpZXIgaW4gdGhlIHJlcG9ydC48L3A+DQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQojIENhcmdhciBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoa2FibGVFeHRyYSkNCg0KIyBDYXJnYXIgbG9zIGRhdG9zDQpkYXRhIDwtIHJlYWRfZXhjZWwoImZpbmFsX291dHB1dC54bHN4IikNCg0KIyBDb21iaW5hciB0b2RhcyBsYXMgY2FwYWNpZGFkZXMgZW4gdW4gc29sbyBkYXRhZnJhbWUgZGUgZm9ybWF0byBsYXJnbw0KY2FwYWJpbGl0eV9kYXRhIDwtIGRhdGEgJT4lDQogIHNlbGVjdChgQ2FwYWJpbGl0eSAxYCwgYENhcGFiaWxpdHkgMmAsIGBDYXBhYmlsaXR5IDNgLCBgQ2FwYWJpbGl0eSA0YCwgYENhcGFiaWxpdHkgNWApICU+JQ0KICBnYXRoZXIoa2V5ID0gIkNhcGFiaWxpdHlfVHlwZSIsIHZhbHVlID0gIkNhcGFiaWxpdHkiKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShDYXBhYmlsaXR5KSkNCg0KIyBDb250YXIgbGFzIG9jdXJyZW5jaWFzIGRlIGNhZGEgY2FwYWNpZGFkIGVuIGNhZGEgY29sdW1uYQ0KY2FwYWJpbGl0eV9jb3VudHMgPC0gY2FwYWJpbGl0eV9kYXRhICU+JQ0KICBjb3VudChDYXBhYmlsaXR5X1R5cGUsIENhcGFiaWxpdHkpICU+JQ0KICBzcHJlYWQoa2V5ID0gQ2FwYWJpbGl0eV9UeXBlLCB2YWx1ZSA9IG4sIGZpbGwgPSAwKSAlPiUNCiAgbXV0YXRlKA0KICAgIFNjb3JlID0gKGBDYXBhYmlsaXR5IDFgICogNSkgKyAoYENhcGFiaWxpdHkgMmAgKiA0KSArIChgQ2FwYWJpbGl0eSAzYCAqIDMpICsgKGBDYXBhYmlsaXR5IDRgICogMikgKyAoYENhcGFiaWxpdHkgNWAgKiAxKQ0KICApICU+JQ0KICBhcnJhbmdlKGRlc2MoU2NvcmUpKQ0KDQojIENyZWFyIGxhIHRhYmxhIHVzYW5kbyBrYWJsZQ0Ka2FibGVfdGFibGUgPC0gY2FwYWJpbGl0eV9jb3VudHMgJT4lDQogIGthYmxlKCJodG1sIiwgY29sLm5hbWVzID0gYygiQ2FwYWJpbGl0eSIsICJDYXBhYmlsaXR5IDEiLCAiQ2FwYWJpbGl0eSAyIiwgIkNhcGFiaWxpdHkgMyIsICJDYXBhYmlsaXR5IDQiLCAiQ2FwYWJpbGl0eSA1IiwgIlNjb3JlIiksIGFsaWduID0gJ2MnKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIHBvc2l0aW9uID0gImNlbnRlciIsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpKSAlPiUNCiAgY29sdW1uX3NwZWMoMSwgYm9sZCA9IFRSVUUsIGNvbG9yID0gInB1cnBsZSIpICU+JQ0KICBjb2x1bW5fc3BlYyg3LCBib2xkID0gVFJVRSwgY29sb3IgPSAicHVycGxlIikgJT4lDQogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAxLCAiU2NvcmUiID0gNSwgIiAiID0gMSkpICU+JQ0KICBzY3JvbGxfYm94KGhlaWdodCA9ICI1MDBweCIsIHdpZHRoID0gIjEwMCUiKQ0KDQojIEd1YXJkYXIgbGEgdGFibGEgY29tbyB1biBhcmNoaXZvIEhUTUwNCnNhdmVfa2FibGUoa2FibGVfdGFibGUsICJjYXBhYmlsaXR5X3JhbmtpbmdfdGFibGVfd2l0aF9zY29yZXMuaHRtbCIsIHNlbGZfY29udGFpbmVkID0gVFJVRSkNCg0KIyBNb3N0cmFyIGxhIHRhYmxhDQprYWJsZV90YWJsZQ0KDQpgYGANCg0KDQoNCiMjIw0KDQo8YSBpZD0iZGlzY3Vzc2lvbiI+PC9hPg0KDQo8cCBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDIycHg7IGNvbG9yOiAjMzMzMzMzOyBsaW5lLWhlaWdodDogMS41OyB0ZXh0LWFsaWduOiBjZW50ZXI7IG1hcmdpbi1ib3R0b206IDIwcHg7Ij4NCiAgPGI+PHNwYW4gc3R5bGU9ImNvbG9yOiAjOTM4MWZmOyBmb250LXNpemU6IDI2cHg7Ij4gfDwvc3Bhbj4gT3Bwb3J0dW5pdGllcyBmb3IgSW1wcm92ZW1lbnQ8L2I+DQo8L3A+DQoNCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsiPg0KVGhlIGFuYWx5c2lzIG9mIEVkVGVjaCBjb21wYW5pZXMgaGFzIHJldmVhbGVkIHNldmVyYWwgYXJlYXMgZm9yIGltcHJvdmVtZW50Og0KPC9wPg0KDQo8dWwgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgbGluZS1oZWlnaHQ6IDEuNTsgdGV4dC1hbGlnbjogbGVmdDsgcGFkZGluZy1sZWZ0OiAyMHB4OyI+DQogICAgPGxpPjxzdHJvbmc+RGF0YSBSZWZpbmVtZW50Ojwvc3Ryb25nPiBFbmhhbmNpbmcgdGhlIGRhdGEgcmVnYXJkaW5nIHRoZSByZWxhdGlvbnNoaXAgb2YgdGhlc2UgY29tcGFuaWVzIHdpdGggdGhlIE9wZW4gZWRYIHBsYXRmb3JtIGlzIGNydWNpYWwuIENsZWFyIGFuZCBhY2N1cmF0ZSBpbmZvcm1hdGlvbiBpbiB0aGlzIGFzcGVjdCB3aWxsIGxlYWQgdG8gbW9yZSBwcmVjaXNlIGluc2lnaHRzLjwvbGk+DQogICAgPGxpPjxzdHJvbmc+RGVmaW5pdGlvbiBvZiBlZHVORVhUOjwvc3Ryb25nPiBUaGUgZGVmaW5pdGlvbiBhbmQgY29uY2VwdCBvZiAiZWR1TkVYVCIgbmVlZHMgdG8gYmUgd2VsbC1kZWZpbmVkIGFuZCBpbmNvcnBvcmF0ZWQgaW50byB0aGUgbW9kZWwgdHJhaW5pbmcuIFRoaXMgd2lsbCBlbnN1cmUgYSBiZXR0ZXIgdW5kZXJzdGFuZGluZyBhbmQgaWRlbnRpZmljYXRpb24gb2YgdGhlIGNvbXBhbnkncyByb2xlIGluIHRoZSBFZFRlY2ggZWNvc3lzdGVtLjwvbGk+DQogICAgPGxpPjxzdHJvbmc+Q2xpZW50IHZzLiBQYXJ0bmVyIFJvbGVzOjwvc3Ryb25nPiBBZGRyZXNzaW5nIHRoZSBhbWJpZ3VpdHkgYmV0d2VlbiAnY2xpZW50JyBhbmQgJ3BhcnRuZXInIHJvbGVzIGlzIGVzc2VudGlhbC4gTGV2ZXJhZ2luZyBhZHZhbmNlZCBtb2RlbHMgc3VjaCBhcyBHUFQtNC1PIGNhbiBwcm92aWRlIGRlZXBlciBjb250ZXh0dWFsIGFuYWx5c2lzIGFuZCBkaWZmZXJlbnRpYXRpb24uPC9saT4NCiAgICA8bGk+PHN0cm9uZz5Sb2xlIENsYXNzaWZpY2F0aW9uOjwvc3Ryb25nPiBXaGVuIGFza2luZyBmb3Igcm9sZXMgdXNpbmcgdGhlIENoYXRHUFQgYWxnb3JpdGhtLCBpbmNsdWRpbmcgYSAibm9uZSBvZiB0aGUgYWJvdmUiIGNhdGVnb3J5IHdvdWxkIGhhdmUgYmVlbiBiZW5lZmljaWFsLiBUaGlzIGFwcHJvYWNoIHdvdWxkIHByZXZlbnQgdGhlIGZvcmNlZnVsIGFzc2lnbm1lbnQgb2YgYSBub25leGlzdGVudCByZWxhdGlvbnNoaXAuPC9saT4NCiAgICA8bGk+PHN0cm9uZz5JbnZlc3RtZW50IERhdGEgU291cmNlOjwvc3Ryb25nPiBUaGUgaW52ZXN0bWVudCBpbmZvcm1hdGlvbiB1c2VkIGluIHRoZSBhbmFseXNpcyB3YXMgYmFzZWQgc29sZWx5IG9uIGRhdGEgcmV0cmlldmVkIGZyb20gQ3J1bmNoYmFzZSB2aWEgTGlua2VkSW4uIFRvIGVuaGFuY2UgdGhlIGNvbXByZWhlbnNpdmVuZXNzIG9mIGZ1dHVyZSBhbmFseXNlcywgY29uc2lkZXJpbmcgYWRkaXRpb25hbCBzb3VyY2VzIG9mIGludmVzdG1lbnQgZGF0YSwgZXNwZWNpYWxseSBmb3IgY29tcGFuaWVzIGluIEFzaWEgd2hlcmUgTGlua2VkSW4gdXNhZ2UgaXMgbGVzcyBwcmV2YWxlbnQsIHdvdWxkIGJlIGJlbmVmaWNpYWwuPC9saT4NCjwvdWw+DQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGxpbmUtaGVpZ2h0OiAxLjU7IHRleHQtYWxpZ246IGxlZnQ7Ij4NClRoZSBwcm9qZWN0IHNob3dzIHNpZ25pZmljYW50IHBvdGVudGlhbCBmb3IgZnVydGhlciBleHBsb3JhdGlvbiBhbmQgZGV2ZWxvcG1lbnQuIEFzIGl0IGlzIHN0aWxsIGluIHByb2dyZXNzLCBhbnkgZmVlZGJhY2sgYW5kIHJlY29tbWVuZGF0aW9ucyBhcmUgaGlnaGx5IGFwcHJlY2lhdGVkIHRvIHJlZmluZSBhbmQgaW1wcm92ZSB0aGUgcmVzdWx0cy4NCjwvcD4NCg0KDQoqKioqDQoNCg0KDQo8YSBocmVmPSIjdG9wIiBjbGFzcz0iZ28tdG9wIj5HbyB0byBUb3A8L2E+DQoNCjxzdHlsZT4NCi5nby10b3Agew0KICBwb3NpdGlvbjogZml4ZWQ7DQogIGJvdHRvbTogMjBweDsNCiAgcmlnaHQ6IDIwcHg7DQogIHRleHQtZGVjb3JhdGlvbjogbm9uZTsNCiAgYmFja2dyb3VuZC1jb2xvcjogI2YyZjJmMjsNCiAgY29sb3I6IGJsYWNrOw0KICBwYWRkaW5nOiAxMHB4IDE1cHg7DQogIGJvcmRlci1yYWRpdXM6IDVweDsNCiAgZm9udC1zaXplOiAxMnB4Ow0KICB6LWluZGV4OiAxMDAwOw0KfQ0KPC9zdHlsZT4NCg0KPHNjcmlwdD4NCmRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5nby10b3AnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKGUpIHsNCiAgZS5wcmV2ZW50RGVmYXVsdCgpOw0KICB3aW5kb3cuc2Nyb2xsVG8oe3RvcDogMCwgYmVoYXZpb3I6ICdzbW9vdGgnfSk7DQp9KTsNCjwvc2NyaXB0Pg==