Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts.

This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 (CC BY-NC 3.0) United States License.

To cite this case study please use:

Wright, Carrie and Wang, Kexin and Meng, Qier and Jager, Leah and Taub, Margaret and Hicks, Stephanie. (2020). https://github.com/opencasestudies/ocs-bp-opioid-rural-urban Opioids in the United States (Version v1.0.0).

To access the GitHub Repository for this case study see here: https://github.com/opencasestudies/ocs-bp-opioid-rural-urban/

You may also access and download the data using our OCSdata package. To learn more about this package including examples, see this link. Here is how you would install this package:

install.packages("OCSdata")

This case study is part of a series of public health case studies for the Bloomberg American Health Initiative.


The total reading time for this case study is calculated via koRpus and shown below:

Reading Time Method
88 minutes koRpus

Readability Score:

A readability index estimates the reading difficulty level of a particular text. Flesch-Kincaid, FORCAST, and SMOG are three common readability indices that were calculated for this case study via koRpus. These indices provide an estimation of the minimum reading level required to comprehend this case study by grade and age.

Text language: en 
index grade age
Flesch-Kincaid 9 14
FORCAST 10 15
SMOG 12 17

Please help us by filling out our survey.

Motivation


In this case study we will be examining the number of opioid pills (specifically oxycodone and hydrocodone, as they are the top two most misused opioids) shipped to pharmacies and practitioners at the county-level around the United States (US) from 2006 to 2014.

This data comes from the DEA Automated Reports and Consolidated Ordering System (ARCOS) and was released by the Washington Post after legal action by the owner of the Charleston Gazette-Mail in West Virginia and the Washington Post.

We will investigate how the number of shipped pills has changed across time and between rural and urban counties in the US. This analysis will demonstrate how different regions of the country may have been more at risk for opioid addiction crises due to differing rates of opioid prescription (using the number of pills as a proxy for prescription rates). This will help inform students about how evidence-based intervention decisions are made in this area.

This case study is motivated by this article:

García, M. C. et al. Opioid Prescribing Rates in Nonmetropolitan and Metropolitan Counties Among Primary Care Providers Using an Electronic Health Record System — United States, 2014–2017. MMWR Morb. Mortal. Wkly. Rep. 68, 25–30 (2019). DOI: 10.15585/mmwr.mm6802a1

This article explores rates of opioid prescriptions in rural and urban communities in the United States using the Athenahealth electronic health record (EHR) system for 31,422 primary care providers from January 2014 to March 2017.

The main takeaways from this article were:

Among 70,237 fatal drug overdoses in 2017, prescription opioids were involved in 17,029 (24.2%).

The percentage of patients prescribed an opioid was higher in rural than in urban areas.

Higher opioid prescribing rates put patients at risk for addiction and overdose.

Indeed, this was confirmed by another article, which surveyed people who use heroin in the Survey of Key Informants’ Patients Program and the Researchers and Participants Interacting Directly (RAPID) program.

Cicero, T. J., Ellis, M. S., Surratt, H. L. & Kurtz, S. P. The Changing Face of Heroin Use in the United States: A Retrospective Analysis of the Past 50 Years. JAMA Psychiatry 71, 821 (2014). DOI:10.1001/jamapsychiatry.2014.366

They found that:

Respondents who began using heroin in the 1960s were predominantly young men (82.8%; mean age, 16.5 years) whose first opioid of abuse was heroin (80%).

Meaning that 80% of the people who use heroin who started using heroin in the 1960s, started with heroin directly, while 20% first used another opioid and then became people who use heroin.

However, more recent users were older (mean age, 22.9 years) men and women living in less urban areas (75.2%) who were introduced to opioids through prescription drugs (75.0%).

[source]

Heroin use has changed from an inner-city, minority-centered problem to one that has a more widespread geographical distribution, involving primarily white men and women in their late 20s living outside of large urban areas.

Photo by James Yarema on Unsplash

A much greater percentage of heroin users completing the survey in the SKIP Program reported currently living in small urban or nonurban areas than in large urban areas (75.2% vs 24.8%) at the time of survey completion.

This survey used self-declared area of current residence (large urban, small urban, suburban, or rural).

Main Question


Our main question:

How did opioid shipment rates differ between rural and urban regions over time in the US from 2006-2014?

Learning Objectives


In this case study, we will demonstrate how to obtain data from an Application Programming Interface (API), which is an interface that allows users to more easily interact with a database. We will also especially focus on using packages and functions from the Tidyverse, such as dplyr, tidyr. The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R more legible and intuitive.

The skills, methods, and concepts that students will be familiar with by the end of this case study are:

Data Science Learning Objectives:

  1. Importing data from an API (httr and jsonlite)
  2. How to join data with dplyr
  3. How to reshape data by pivoting between “long” and “wide” formats and drop rows with NA values (tidyr)
  4. How to create formatted tables of data with formattable
  5. How to look for missing data in a dataset (naniar)
  6. How to create data visualizations with ggplot2
  7. How to create interactive plots that are difficult to label because they have many elements (ggiraph)
  8. How to combine individual plots into one figure with patchwork

Statistical Learning Objectives:

  1. Understanding of when and why data normalization is useful
  2. Understanding of how group definitions can change results
  3. Understanding of when to use a Wilcoxon rank sum test (also called Mann Whitney U test)
  4. How to implement a Wilcoxon rank sum test in R
  5. How to interpret a Wilcoxon rank sum test

We will begin by loading the packages that we will need:

library(readxl)
library(tibble)
library(httr)
library(jsonlite)
library(stringr)
library(magrittr)
library(dplyr)
library(tidyr)
library(naniar)
library(ggplot2)
library(formattable)
library(forcats)
library(Hmisc)
library(ggpol)
library(ggiraph)
library(patchwork)
library(directlabels)
library(usdata)
# if you are not using the OCSdata package to download data you do not need to load it
library(OCSdata)

Packages used in this case study:

Package Use in this case study
readxl to import an excel file
httr to retrieve data from an API
tibble to create tibbles (the tidyverse version of dataframes)
jsonlite to parse json files
stringr to manipulate character strings within the data (subset and detect parts of strings)
dplyr to filter, subset, join, and modify and summarize the data
magrittr to pipe sequential commands
tidyr to change the shape or format of tibbles to wide and long
naniar to get a sense of missing data
ggplot2 to create plots
formattable to create a formatted table
forcats to reorder factor for plot
Hmisc to calculate different features about the data
ggpol to create plots that have jitter and half boxplots
ggiraph to create interactive plots
patchwork to combine plots
directlabels to add labels directly on lines within plots
usdata to add full state names to plots based on the state abbreviations
OCSdata to access and download the data used in this case study

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

Context


What exactly are opioids?

According to the DEA and the Alta Mira addiction treatment center:

Opioids (also known as narcotics), describes a class of drugs that contain opium (the poppy plant - Papaver somniferum), are derived from opium, or contain a semi-synthetic or synthetic substitute for opium.

Photo by Ingo Doerrie on Unsplash

However, technically, opioids are substances that bind to the opioid receptors in the body, which are involved in the sensation of pain and the experience of reward. There are actually opioids that naturally are made by the human body, the most well known being the endorphins.


Click here to learn about why opioids are addictive

Opioid drugs tend to be addictive because they modulate the reward system. This is the part of the brain that reinforces behaviors (normally these are behaviors such as drinking water or eating food) by causing the experience of pleasure (through the release of a neurotransmitter called dopamine).

This same system can be activated by both opioids that naturally occur in the body, as well as opioid prescription drugs and other addictive drugs. Activation of this system by drug use leads to very high releases of Dopamine and the sensation of pleasure which ultimately leads to reinforced use of that drug.

[source]


In general, opioid drugs have been found to dull the senses, relieve pain, suppress cough, reduce respiration and heart rate, induce constipation, and induce feelings of euphoria. They have a high potential for abuse and addiction.

Drugs within this class include (with prescription drug brand names are shown in parentheses):

  1. Non-synthetic purified: Morphine, Codeine, Thebaine
  2. Semi-synthetic: Heroin, Oxycodone (Oxycontin, Oxecta, Roxicodone), and Hydrocodone ( Vicodin, Lortab, Lorcet)), oxymorphone (Opana), Hydromorphone (Dilaudid, Exalgo)
  3. Synthetic: Meperidine (Demerol), Methadone (Methadose, Dolophine), and Fentanyl (Abstral, Actiq, Fentora, Duragesic, Lazanda, Subsys), Tramadol (ConZip, Ryzolt, Ultram)

[source]

Opium comes from the fluid (which is also called poppy tears) inside the seed capsules of the Papaver somniferum plant. This contains morphine, codeine, and thebaine. This is then dried.

Opium has been used by humans since 5000 BCE and it has been used across the world. See here for an interesting overview of the history.


Click here to learn about the history of opioids in the US

Opium derived medications were historically used in United States to treat a variety of ailments besides pain including: cholera, dysentery, tuberculosis, and mental illness.

Of note, they state that “from 1898 to 1910 heroin was marketed as a non-addictive morphine substitute and cough medicine for children”!

Here you can see a photo of a bottle of heroin:

[source]

Opioids have continued to be used in the treatment of pain.


The Opioid Epidemic


The rate of opioid overdose deaths rapidly increased in the US in the 1990s.

According to the US department of health and human services (HHS):

In the late 1990s, pharmaceutical companies reassured the medical community that patients would not become addicted to opioid pain relievers and healthcare providers began to prescribe them at greater rates.

Increased prescription of opioid medications led to widespread misuse of both prescription and non-prescription opioids before it became clear that these medications could indeed be highly addictive.

In 2017 the HHS declared a public health emergency

See here for a time line of the epidemic in the US and here for more details about the epidemic.

According to this article from the Morbidity and Mortality Weekly Report (MMWR) of the Centers for Disease Control and Prevention (CDC):

Drug overdose is the leading cause of unintentional injury-associated death in the United States.

[source]

According to the CDC, there were 3 waves of the epidemic:

[source]

You can see that most recent overdose deaths were due to the use of synthetic opioids, where as previous high levels of overdoses (till about 2015) were attributable to natural and semi-synthetic opioids (which is what we will look at in this case study).

They state that:

From 1999–2018, almost 450,000 people died from an overdose involving any opioid, including prescription and illicit opioids.

Importantly rates appear to differ across states, according to this CDC report

[source]

According to the motivating report for our case study:

Prescription rates are now declining, however, prescription of opioids was found to be higher in rural areas rather than urban ares.

[source]

It is important to identify locations where people are particularly vulnerable to target interventions for communities that need it the most.

Limitations


There are some important considerations regarding this data analysis to keep in mind:

According to the Washington Post database, they state about the DEA data:

[Washington Post]… cleaned the data to include only information on shipments of oxycodone and hydrocodone pills. We did not include data on 10 other opioids because they were shipped in much lower quantities…

“It’s important to remember that the number of pills in each county does not necessarily mean those pills went to people who live in that county. The data only shows us what pharmacies the pills are shipped to and nothing else.”

Furthermore, we will define counties as being rural or urban however there can be great variation within a county and we used land area values from only 2010 even though these can fluctuate. Therefore, the way we categorized counties should be seen as an approximation. Additionally, other aspects about a county besides population level and density can be influential for creating an environment that would increase the vulnerability of community members to drug abuse and addiction. These include socioeconomic factors among others.

Finally, overdose deaths are often due to the use of multiple substances. Simply because a county received more pills does not mean that people in that county would experience more drug overdoses. It is also important to remember that prescription opioids only account for a portion of the drug overdose deaths reported in this time period. However, according to this article, 75% of people who use heroin surveyed were introduced to opioids through prescription drug use.

The recent overdose deaths in the US opioid crisis are mostly due to synthetic opioids. Understanding what makes communities vulnerable to these types of opioids is an area of active research but not a focus of this case study.

What are the data?


We will use data from two sources:

  1. The US census for land area of counties to allow us to estimate county-level population density. This was obtained from here and contains county, state, and national land area estimates (for a few years in a few different ways, we will explain more about that later).

  2. The Washington Post data from the Drug Enforcement Administration (DEA) about opioid (oxycodone and hydrocodone) pill shipments to pharmacies and practitioners around the US at the county-level from 2006 to 2014.

This second dataset was released in July of 2019 and has been controversial as according to the Washington Post:

The disclosure is part of a civil action brought by 2,500 cities, towns, counties and tribal nations alleging that nearly two dozen drug companies conspired to saturate the nation with opioids.

See here for more details about how this database was released.

This data was part of the Automated Reports and Consolidated Ordering System (ARCOS) of the DEA in which:

manufacturers and distributors report their controlled substances transactions

Their website indicates that:

The Controlled Substances Act of 1970 created the requirement for Manufacturers and Distributors to report their controlled substances transactions to the Attorney General. The Attorney General delegates this authority to the Drug Enforcement Administration (DEA).

ARCOS is an automated, comprehensive drug reporting system which monitors the flow of DEA controlled substances from their point of manufacture through commercial distribution channels to point of sale or distribution at the dispensing/retail level - hospitals, retail pharmacies, practitioners, mid-level practitioners, and teaching institutions. Included in the list of controlled substance transactions tracked by ARCOS are the following: All Schedules I and II materials (manufacturers and distributors); Schedule III narcotic and gamma-hydroxybutyric acid (GHB) materials (manufacturers and distributors); and selected Schedule III and IV psychotropic drugs (manufacturers only).

The annual report about the data from 2019, can be found here.

As this is a very large dataset, thus the Washington Post created an application prgoramming interface (API) to make it easier for users to access the data.

An API is a computational interface that simplifies interactions with a data or file system for a user. It is similar to a Graphical User Interface (GUI), yet it allows the user some more flexibility/functionality.

This YouTube video gives an overview of what an API is.

[source]

This link takes you to the Washington Post ARCOS API.

There was also an R package on cran called arcos for interacting with the API, but this has been archived. This package is however still available here on GitHub.

See here for more information about how to get access the Washington Post DEA database.

Importantly, the API also includes population estimates for the years (2006 to 2014) and counties within the DEA database.

Data Import


Note that if you have trouble with the data import from the API, we have saved files after getting the data from the API that you may import into your R environment using the OCSdata package and the load() function:

# install.packages("OCSdata")
# library(OCSdata)
imported_data("ocs-bp-opioid-rural-urban", outpath = getwd())
load(here::here("OCSdata", "data", "imported", "land_area.rda"))
load(here::here("OCSdata", "data", "imported", "county_pop_arcos.rda"))
load(here::here("OCSdata", "data", "imported", "county_annual.rda"))

You may also obtain these files from the data/imported directory of our GitHub repository.

Land Area


We will need county land area data for our calculations of population density.

We obtained county land area data from the US census Bureau at this link.

This data contains land areas (in a few different ways for a number of years) at the national, state, and county level.

This link explains how the data is formatted.

Based on this we determined that we want to use the LND110210D column which is the data from the year 2010.

Let’s break this down to understand the meaning of the column.

  • LND = Land Area
  • 110 = Land Area unit in square miles (subgroup-code of the group)
  • 2 = century
  • 10 = 2010 (based on the century)
  • D = Data

We will use the read_excel() function of the readxl package to import the data. We will also convert the data into a tibble (which is a the tidyverse version of a data frame) by using the as_tibble() function of the tibble package.

If you did not clone our github repository or do not have this data already, you may download this data using the OCSdata package:

# install.packages("OCSdata")
# library(OCSdata)

raw_data("ocs-bp-opioid-rural-urban", outpath = getwd())
# This function creates a "OCSdata" sub-directory in your current working directory.
# It also creates a "raw" sub-directory within "data" which contains the .xls file.

In our case, we downloaded this data and put it within a “raw” subdirectory of a “data” directory for our project. If you use an RStudio project, then you can use the here() function of the here package to make the path for importing this data simpler. The here package automatically starts looking for files based on where you have a .Rproj file which is created when you start a new RStudio project. We can specify that we want to look for the “LND01.xls” file within the “raw” directory within the “data” directory where our .Rproj file is located by separating the names of these directories using commas and listing “data” first.


Click here to see more about creating new projects in R

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects.


land <- readxl::read_excel(here::here("data", "raw", "LND01.xls"))
land <- as_tibble(land)

We can take a look at the data using the base head() function which will show the first 3 rows.

head(land, n=3)
# A tibble: 3 x 34
  Areaname      STCOU LND010190F LND010190D LND010190N1 LND010190N2 LND010200F
  <chr>         <chr>      <dbl>      <dbl> <chr>       <chr>            <dbl>
1 UNITED STATES 00000          0   3787425. 0000        0000                 0
2 ALABAMA       01000          0     52423. 0000        0000                 0
3 Autauga, AL   01001          0       604. 0000        0000                 0
# ... with 27 more variables: LND010200D <dbl>, LND010200N1 <chr>,
#   LND010200N2 <chr>, LND110180F <dbl>, LND110180D <dbl>, LND110180N1 <chr>,
#   LND110180N2 <chr>, LND110190F <dbl>, LND110190D <dbl>, LND110190N1 <chr>,
#   LND110190N2 <chr>, LND110200F <dbl>, LND110200D <dbl>, LND110200N1 <chr>,
#   LND110200N2 <chr>, LND110210F <dbl>, LND110210D <dbl>, LND110210N1 <chr>,
#   LND110210N2 <chr>, LND210190F <dbl>, LND210190D <dbl>, LND210190N1 <chr>,
#   LND210190N2 <chr>, LND210200F <dbl>, LND210200D <dbl>, ...

Indeed, this looks as expected with both the US, state, and county level land areas. We will look into this further in later sections.

Looks good!

Now we will save our data in the data directory within a subdirectory called “imported”:

save(land, file =  here::here("data", "imported", "land_area.rda"))

Accessing data with APIs


The httr package creates what are called “GET requests” so that we can make these requests inside of R. This allows for the data to be retrieved from the API within R.

The jsonlite package allows you to convert the data from JSON (often used by APIs) to a different format that is easier to work with.

APIs typically require a password or key to gain access or authenticate your data request. The httr package helps to authenticate your data request. Often these keys are something that you do not want to share, unless the API is public.

In our case the API is indeed public, and currently “uO4EK6I” is publicly published as a key to use on the github page for the arcos package. We will use that here to access the API.

County Population Data


We are interested in the county level data. Conveniently, the API also includes county-level population data (the number of people per county in each state in the US from 2006 to 2014)

We can access it from the API by:

  1. Pressing the GET button on the API.

  1. Pressing the “Try it out” button.

  1. Entering the key (which we got from here).

  1. Clicking the “Execute” button.

This gives us the following output:

curl -X GET "https://arcos-api.ext.nile.works/v1/county_population?key=uO4EK6I" -H "accept: application/json"

We can copy the URL section "https://arcos-api.ext.nile.works/v1/county_population?key=uO4EK6I" and use it in the GET() function of the httr package :

count_url <- "https://arcos-api.ext.nile.works/v1/county_population?key=uO4EK6I"

county_pop_json <- 
  httr::GET(url = count_url)

If we needed to specify a username and password, we would do so using the authenticate() function of the httr package within the GET function. The authenticate() function takes user, password and type arguments.

Here is an example:

GET(url = "https://exampleURL", 
    authenticate(user = "username", 
                 password = "password", 
                 type = "basic"))

The default authentication request type is "basic" and typically what is needed.

Now that we have used the GET function, let’s see what the data are.

county_pop_json
Response [https://arcos-api.ext.nile.works/v1/county_population?key=uO4EK6I]
  Date: 2022-03-22 06:00
  Status: 200
  Content-Type: application/json
  Size: 5.75 MB

Here we can see that the object called county_pop_json is a json object. A JavaScript Object Notation (JSON) object (or file format) is lightweight meaning that it does not take up much memory and they are human readable files to make transmitting data from websites easier.

You will also see that the Status is 200, which means that we were successful in retrieving the data from the API.

Now we can use the content() function of the httr package to extract the text from the file:

county_pop_text <- 
  httr::content(county_pop_json, "text")

This will be a very large string at this point, we can take a look at part of it by using the str_sub() function of the stringr package. In this case we will only look at the first 400 characters.

What is a string or a character?


Click here for an explanation about character strings if you are not yet familiar

There are several classes of data in R programming. Character is one of these classes. A character string is an individual data value made up of characters. This can be a paragraph, like the legend for the table, or it can be a single letter or number like the letter "a" or the number "3".

If data are of class character, than the numeric values will not be processed like a numeric value in a mathematical sense.


stringr::str_sub(county_pop_text, start = 1, end = 400)
[1] "[{\"BUYER_COUNTY\":\"AUTAUGA\",\"BUYER_STATE\":\"AL\",\"countyfips\":\"01001\",\"STATE\":1,\"COUNTY\":1,\"county_name\":\"Autauga\",\"NAME\":\"Autauga County, Alabama\",\"variable\":\"B01003_001\",\"year\":2006,\"population\":51328},{\"BUYER_COUNTY\":\"BALDWIN\",\"BUYER_STATE\":\"AL\",\"countyfips\":\"01003\",\"STATE\":1,\"COUNTY\":3,\"county_name\":\"Baldwin\",\"NAME\":\"Baldwin County, Alabama\",\"variable\":\"B01003_001\",\"year\":2006,\"population\":168121"

To get the data into a more readable format, we can use the fromJSON() function of the jsonlite package and again create a tibble of the data using as_tibble()

county_pop <- 
  jsonlite::fromJSON(county_pop_text, 
                     flatten = TRUE)

county_pop <- as_tibble(county_pop)

We can use the glimpse() function and the distinct() function of the dplyr package to get a better sense of the data. The distinct() function allows us to take a look at the unique values of the year variable.

dplyr::glimpse(county_pop)
Rows: 28,265
Columns: 10
$ BUYER_COUNTY <chr> "AUTAUGA", "BALDWIN", "BARBOUR", "BIBB", "BLOUNT", "BULLO~
$ BUYER_STATE  <chr> "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL~
$ countyfips   <chr> "01001", "01003", "01005", "01007", "01009", "01011", "01~
$ STATE        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
$ COUNTY       <int> 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31~
$ county_name  <chr> "Autauga", "Baldwin", "Barbour", "Bibb", "Blount", "Bullo~
$ NAME         <chr> "Autauga County, Alabama", "Baldwin County, Alabama", "Ba~
$ variable     <chr> "B01003_001", "B01003_001", "B01003_001", "B01003_001", "~
$ year         <int> 2006, 2006, 2006, 2006, 2006, 2006, 2006, 2006, 2006, 200~
$ population   <int> 51328, 168121, 27861, 22099, 55485, 10776, 20815, 115388,~
dplyr::distinct(county_pop, year)
# A tibble: 9 x 1
   year
  <int>
1  2006
2  2007
3  2008
4  2009
5  2010
6  2011
7  2012
8  2013
9  2014

It looks like we have the full data from 2006-2014.

Now let’s save this data:

save(county_pop, file =  here::here("data", "imported",  "county_pop_arcos.rda"))

Annual Shipment Data


We are also interested in the number of opioid pill shipped at the county level.

Here is the result of the same steps using the API for the combined_county_annual data:

curl -X GET "https://arcos-api.ext.nile.works/v1/combined_county_annual?key=uO4EK6I" 
     -H  "accept: application/json"

or in R, the URL is

annual_url <- 
  "https://arcos-api.ext.nile.works/v1/combined_county_annual?key=uO4EK6I"

Question Opportunity

See if you can modify the import code without looking at the code for the population data.


Click here to reveal the code.
county_annual_json <- 
  httr::GET(url =  annual_url)

county_annual_json_text <- 
  httr::content(county_annual_json, "text")

county_annual <- 
  jsonlite::fromJSON(county_annual_json_text, flatten = TRUE)

annualDosage <- 
  tibble::as_tibble(county_annual)

Now we will also save this data:

save(annualDosage, file = here::here("data", "imported", "county_annual.rda"))

Now let’s take a look at the data:

glimpse(annualDosage)
Rows: 27,758
Columns: 6
$ BUYER_COUNTY <chr> "ABBEVILLE", "ABBEVILLE", "ABBEVILLE", "ABBEVILLE", "ABBE~
$ BUYER_STATE  <chr> "SC", "SC", "SC", "SC", "SC", "SC", "SC", "SC", "SC", "LA~
$ year         <int> 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 200~
$ count        <int> 877, 908, 871, 930, 1197, 1327, 1509, 1572, 1558, 5802, 5~
$ DOSAGE_UNIT  <dbl> 363620, 402940, 424590, 467230, 539280, 566560, 589010, 5~
$ countyfips   <chr> "45001", "45001", "45001", "45001", "45001", "45001", "45~
distinct(annualDosage, year)
# A tibble: 9 x 1
   year
  <int>
1  2006
2  2007
3  2008
4  2009
5  2010
6  2011
7  2012
8  2013
9  2014

Looks like we have the same years of data.

Data Exploration


If you have been following along but stopped, we could load our imported data from the “data” directory like so:

load(here::here("data", "imported", "land_area.rda"))
load(here::here("data", "imported", "county_pop_arcos.rda"))
load(here::here("data", "imported", "county_annual.rda"))

If you skipped the data import section click here.

First you need to install and load the OCSdata package:

install.packages("OCSdata")
library(OCSdata)

Then, you may load the imported data into your R environment using the following code:

imported_data("ocs-bp-opioid-rural-urban", outpath = getwd())
load(here::here("OCSdata", "data", "imported", "land_area.rda"))
load(here::here("OCSdata", "data", "imported", "county_pop_arcos.rda"))
load(here::here("OCSdata", "data", "imported", "county_annual.rda"))

Alternatively, you may download the raw data as well as the CSV files for simpler import using the following function:

simpler_import_data("ocs-bp-opioid-rural-urban", outpath = getwd())

If the package does not work for you, the RDA files (stands for R data) of the data can be found in our GitHub repository. Download these files and then place them in your current working directory within a subdirectory called “imported” within a subdirectory called “data” to copy and paste our code. We used an RStudio project and the here package to navigate to the files more easily.

load(here::here("data", "imported", "land_area.rda"))
load(here::here("data", "imported", "county_pop_arcos.rda"))
load(here::here("data", "imported", "county_annual.rda"))

Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



Now let’s take a deeper look at the data to see if we have any missing data using the naniar package.

We can use the vis_miss() function to create a plot of missing data, which will use a heatmap to show if there are missing data (black) or no missing data (gray).

Let’s start with the land area data.

naniar:: vis_miss(land)

Looks like there is no missing data.

How about the population data:

vis_miss(county_pop)

Although it is very hard to see in the figure, we appear to be missing some values for the NAME and variable data, but we do not intend to use these, so this should be OK. It is however a good idea to check these rows to see if anything strange is happening.

Let’s use the filter() function of the dplyr package and the is.na() base function to see more about the data that does not have NAME values.

We will also start using the %>% pipe of the magrittr package for our assignments.


Click here if you are unfamiliar with piping in R, which uses this %>% operator

By piping we mean using the %>% pipe operator which is accessible after loading the tidyverse or several of the packages within the tidyverse like dplyr because they load the magrittr package. This allows us to perform multiple sequential steps on one data input.


county_pop %>% 
  filter(is.na(NAME))
# A tibble: 15 x 10
   BUYER_COUNTY   BUYER_STATE countyfips STATE COUNTY county_name NAME  variable
   <chr>          <chr>       <chr>      <int>  <int> <chr>       <chr> <chr>   
 1 PRINCE OF WAL~ AK          02198          2    201 Prince of ~ <NA>  <NA>    
 2 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
 3 WRANGELL       AK          02275          2    280 Wrangell    <NA>  <NA>    
 4 PRINCE OF WAL~ AK          02198          2    201 Prince of ~ <NA>  <NA>    
 5 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
 6 WRANGELL       AK          02275          2    280 Wrangell    <NA>  <NA>    
 7 PRINCE OF WAL~ AK          02198          2    201 Prince of ~ <NA>  <NA>    
 8 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
 9 WRANGELL       AK          02275          2    280 Wrangell    <NA>  <NA>    
10 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
11 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
12 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
13 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
14 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
15 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
# ... with 2 more variables: year <int>, population <int>

This looks OK. Let’s move on to the annualDosage data.

vis_miss(annualDosage)

Interesting, we appear to be missing countyfips codes (recall that FIPS stands for the Federal Information Processing Standards (FIPS) code) for a small percentage of our annual data.

Let’s take a look at this data:

annualDosage %>% 
  filter(is.na(countyfips))
# A tibble: 760 x 6
   BUYER_COUNTY BUYER_STATE  year count DOSAGE_UNIT countyfips
   <chr>        <chr>       <int> <int>       <dbl> <chr>     
 1 ADJUNTAS     PR           2006   147      102800 <NA>      
 2 ADJUNTAS     PR           2007   153      104800 <NA>      
 3 ADJUNTAS     PR           2008   153       45400 <NA>      
 4 ADJUNTAS     PR           2009   184       54200 <NA>      
 5 ADJUNTAS     PR           2010   190       56200 <NA>      
 6 ADJUNTAS     PR           2011   186       65530 <NA>      
 7 ADJUNTAS     PR           2012   138       57330 <NA>      
 8 ADJUNTAS     PR           2013   138       65820 <NA>      
 9 ADJUNTAS     PR           2014    90       59490 <NA>      
10 AGUADA       PR           2006   160       49200 <NA>      
# ... with 750 more rows

We can see that the first rows with missing data for countyfips is data for Puerto Rico - it might make sense for Puerto Rico to be missing these codes.

Let’s see if there are any data other than data for Puerto Rico that is also missing countyfips values. We can use the != operator which indicates not equal to.

annualDosage %>% 
  filter(is.na(countyfips)) %>%
  filter(BUYER_STATE != "PR")

# A tibble: 74 x 6
   BUYER_COUNTY             BUYER_STATE  year count DOSAGE_UNIT countyfips
   <chr>                    <chr>       <int> <int>       <dbl> <chr>     
 1 GUAM                     GU           2006   319      265348 <NA>      
 2 GUAM                     GU           2007   330      275600 <NA>      
 3 GUAM                     GU           2008   313      286900 <NA>      
 4 GUAM                     GU           2009   390      355300 <NA>      
 5 GUAM                     GU           2010   510      413800 <NA>      
 6 GUAM                     GU           2011   559      475600 <NA>      
 7 GUAM                     GU           2012   616      564800 <NA>      
 8 GUAM                     GU           2013   728      623200 <NA>      
 9 GUAM                     GU           2014   712      558960 <NA>      
10 MONTGOMERY               AR           2006   469      175390 <NA>      
11 MONTGOMERY               AR           2007   597      241270 <NA>      
12 MONTGOMERY               AR           2008   561      251760 <NA>      
13 MONTGOMERY               AR           2009   554      244160 <NA>      
14 MONTGOMERY               AR           2010   449      247990 <NA>      
15 MONTGOMERY               AR           2011   560      313800 <NA>      
16 MONTGOMERY               AR           2012   696      339520 <NA>      
17 MONTGOMERY               AR           2013   703      382300 <NA>      
18 MONTGOMERY               AR           2014   491      396900 <NA>      
19 NORTHERN MARIANA ISLANDS MP           2006   165      117850 <NA>      
20 NORTHERN MARIANA ISLANDS MP           2007   157      117500 <NA>      
21 NORTHERN MARIANA ISLANDS MP           2008   204      143000 <NA>      
22 NORTHERN MARIANA ISLANDS MP           2009   269      186900 <NA>      
23 NORTHERN MARIANA ISLANDS MP           2010   231      196360 <NA>      
24 NORTHERN MARIANA ISLANDS MP           2011   264      208500 <NA>      
25 NORTHERN MARIANA ISLANDS MP           2012   290      217400 <NA>      
26 NORTHERN MARIANA ISLANDS MP           2013   258      231400 <NA>      
27 NORTHERN MARIANA ISLANDS MP           2014   260      239200 <NA>      
28 PALAU                    PW           2006     5       14000 <NA>      
29 PALAU                    PW           2007     9       26600 <NA>      
30 PALAU                    PW           2008     2        7500 <NA>      
31 PALAU                    PW           2009     3       10000 <NA>      
32 PALAU                    PW           2013     1        1000 <NA>      
33 SAINT CROIX              VI           2006   544      198800 <NA>      
34 SAINT CROIX              VI           2007   612      237120 <NA>      
35 SAINT CROIX              VI           2008   694      254020 <NA>      
36 SAINT CROIX              VI           2009   601      233860 <NA>      
37 SAINT CROIX              VI           2010   764      316260 <NA>      
38 SAINT CROIX              VI           2011   756      320850 <NA>      
39 SAINT CROIX              VI           2012   755      314690 <NA>      
40 SAINT CROIX              VI           2013   802      328410 <NA>      
41 SAINT CROIX              VI           2014   684      269040 <NA>      
42 SAINT JOHN               VI           2006    65       22200 <NA>      
43 SAINT JOHN               VI           2007    60       21800 <NA>      
44 SAINT JOHN               VI           2008    70       24700 <NA>      
45 SAINT JOHN               VI           2009    58       23100 <NA>      
46 SAINT JOHN               VI           2010    75       23500 <NA>      
47 SAINT JOHN               VI           2011    89       30200 <NA>      
48 SAINT JOHN               VI           2012    85       30200 <NA>      
49 SAINT JOHN               VI           2013    66       22000 <NA>      
50 SAINT JOHN               VI           2014    63       20400 <NA>      
51 SAINT THOMAS             VI           2006   628      219100 <NA>      
52 SAINT THOMAS             VI           2007   757      249480 <NA>      
53 SAINT THOMAS             VI           2008   815      294250 <NA>      
54 SAINT THOMAS             VI           2009   798      313200 <NA>      
55 SAINT THOMAS             VI           2010   802      318630 <NA>      
56 SAINT THOMAS             VI           2011   932      383350 <NA>      
57 SAINT THOMAS             VI           2012   939      373280 <NA>      
58 SAINT THOMAS             VI           2013   988      376400 <NA>      
59 SAINT THOMAS             VI           2014  1021      314440 <NA>      
60 <NA>                     AE           2006     2         330 <NA>      
61 <NA>                     CA           2006    47       12600 <NA>      
62 <NA>                     CT           2006   305       78700 <NA>      
63 <NA>                     CT           2007   112       30900 <NA>      
64 <NA>                     CT           2008    48       15000 <NA>      
65 <NA>                     FL           2006     9         900 <NA>      
66 <NA>                     FL           2007     7         700 <NA>      
67 <NA>                     GA           2006   114       51700 <NA>      
68 <NA>                     IA           2006     7        2300 <NA>      
69 <NA>                     IN           2006   292       39300 <NA>      
70 <NA>                     MA           2006   247      114900 <NA>      
71 <NA>                     NV           2006   380      173600 <NA>      
72 <NA>                     NV           2007   447      200600 <NA>      
73 <NA>                     NV           2008     5        2200 <NA>      
74 <NA>                     OH           2006    23        5100 <NA>      

It looks like there is also data for other territories in the dataset, as well as some counties with no name.

For some reason the rows for the Montgomery county of Arkansas are also missing a countyfips value.

annualDosage %>% 
  filter(is.na(countyfips)) %>%
  filter(BUYER_STATE == "AR")
# A tibble: 9 x 6
  BUYER_COUNTY BUYER_STATE  year count DOSAGE_UNIT countyfips
  <chr>        <chr>       <int> <int>       <dbl> <chr>     
1 MONTGOMERY   AR           2006   469      175390 <NA>      
2 MONTGOMERY   AR           2007   597      241270 <NA>      
3 MONTGOMERY   AR           2008   561      251760 <NA>      
4 MONTGOMERY   AR           2009   554      244160 <NA>      
5 MONTGOMERY   AR           2010   449      247990 <NA>      
6 MONTGOMERY   AR           2011   560      313800 <NA>      
7 MONTGOMERY   AR           2012   696      339520 <NA>      
8 MONTGOMERY   AR           2013   703      382300 <NA>      
9 MONTGOMERY   AR           2014   491      396900 <NA>      

According to this website the FIPS code is 05097.

We will update these values in the next section.

Data Wrangling


If you have been following along but stopped, we could load our imported data from the “data” directory like so:

load(here::here("data", "imported", "land_area.rda"))
load(here::here("data", "imported", "county_pop_arcos.rda"))
load(here::here("data", "imported", "county_annual.rda"))

If you skipped the previous sections click here.

First you need to install and load the OCSdata package:

install.packages("OCSdata")
library(OCSdata)

Then, you may load the imported data into your R environment using the following code:

imported_data("ocs-bp-opioid-rural-urban", outpath = getwd())
load(here::here("OCSdata", "data", "imported", "land_area.rda"))
load(here::here("OCSdata", "data", "imported", "county_pop_arcos.rda"))
load(here::here("OCSdata", "data", "imported", "county_annual.rda"))

Alternatively, you may download the raw data as well as the CSV files for simpler import using the following function:

simpler_import_data("ocs-bp-opioid-rural-urban", outpath = getwd())

If the package does not work for you, the RDA files (stands for R data) of the data can be found in our GitHub repository. Download these files and then place them in your current working directory within a subdirectory called “imported” within a subdirectory called “data” to copy and paste our code. We used an RStudio project and the here package to navigate to the files more easily.

load(here::here("data", "imported", "land_area.rda"))
load(here::here("data", "imported", "county_pop_arcos.rda"))
load(here::here("data", "imported", "county_annual.rda"))

Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



Cleaning land data


Recall that we want to use the LND110210D column which is the data from the year 2010.

This link and this link explain what each of the column names indicate.

Using these we see that our column of interest LND110210D stands for: - LND = Area - 110 = Land Area in square miles (subgroup code of the group) - 2 = century - 10 = year code - 2010 (based on the century) - D = Data (data type: F = flag, D = data value, N1 = Footnote 1, N2 = Footnote 2)

The 010 subgroup code indicates total area (including land and water).
The 210 subgroup code indicates water area.


Click here to see some other census code explanations.

LND010190D Total area in square miles 1990
LND010200D Total area in square miles 2000
LND110180D Land area in square miles 1980
LND110190D Land area in square miles 1990
LND110200D Land area in square miles 2000
LND110210D Land area in square miles 2010
LND210190D Water area in square miles 1990
LND210200D Water area in square miles 2000


We also want to be able to identify what land area is for what county, thus we will also keep the the column with area names as well as the column called STCOU. This variable contains numeric codes that are used to identify states and counties called Federal Information Processing Standards (FIPS). In this dataset we have national state, and county codes, so this variable is called STCOU (short for State and County).

We can select just the names, the county/state numeric codes (STCOU), and the LND110210D column by using the select() function of the dplyr package.

land_area <- 
  land %>% 
  select(Areaname, STCOU, LND110210D)

land_area
# A tibble: 3,198 x 3
   Areaname      STCOU LND110210D
   <chr>         <chr>      <dbl>
 1 UNITED STATES 00000   3531905.
 2 ALABAMA       01000     50645.
 3 Autauga, AL   01001       594.
 4 Baldwin, AL   01003      1590.
 5 Barbour, AL   01005       885.
 6 Bibb, AL      01007       623.
 7 Blount, AL    01009       645.
 8 Bullock, AL   01011       623.
 9 Butler, AL    01013       777.
10 Calhoun, AL   01015       606.
# ... with 3,188 more rows

Thus, we still have state-level and full US measurements of land area in addition to the county data. But we will join this with our other datasets in a bit based on the county name/county FIPS code and thus only keep the county level data.

Updating countyfips


We will use the case_when() function of the dplyr package recode the NA values for countyfips for the rows for the MONGOMERY county of AR to be 05097.

First, we need to identify these particular rows. Because Montgomery may be a county name in other states, we need to evaluate when the BUYER_STATE is AR and when the BUYER_COUNTY is MONTGOMERY. We will use the & operator to indicate that both conditions must be true.

Then, We will recode the coutryfips values for these rows to be "05097" using the ~ symbol. All other values need to stay the same.

We need to use TRUE ~ to recode all the other countyfips values to what they currently are. Otherwise these would automatically be set to NA.

We are also going to use a special pipe operator from the magrittr package called the compound assignment pipe operator or sometimes the double pipe operator.

This allows us to use the annualDosage as our input and, in the same step, reassign it to take the updated value of the tibble, after all the subsequent steps have been performed. In this case, it is only one step, but this saves us typing and avoids creating an intermediate version of the tibble.

annualDosage %<>% 
  mutate(countyfips = case_when(BUYER_STATE == "AR" & 
                                BUYER_COUNTY == "MONTGOMERY" ~ as.character("05097"),
                                TRUE ~ countyfips))

Now we can check that we indeed fixed our data.

annualDosage %>% 
  filter(is.na(countyfips)) %>%
  filter(BUYER_STATE == "AR")
# A tibble: 0 x 6
# ... with 6 variables: BUYER_COUNTY <chr>, BUYER_STATE <chr>, year <int>,
#   count <int>, DOSAGE_UNIT <dbl>, countyfips <chr>
annualDosage %>% 
  filter(BUYER_COUNTY == "MONTGOMERY") %>%
  filter(BUYER_STATE == "AR")
# A tibble: 9 x 6
  BUYER_COUNTY BUYER_STATE  year count DOSAGE_UNIT countyfips
  <chr>        <chr>       <int> <int>       <dbl> <chr>     
1 MONTGOMERY   AR           2006   469      175390 05097     
2 MONTGOMERY   AR           2007   597      241270 05097     
3 MONTGOMERY   AR           2008   561      251760 05097     
4 MONTGOMERY   AR           2009   554      244160 05097     
5 MONTGOMERY   AR           2010   449      247990 05097     
6 MONTGOMERY   AR           2011   560      313800 05097     
7 MONTGOMERY   AR           2012   696      339520 05097     
8 MONTGOMERY   AR           2013   703      382300 05097     
9 MONTGOMERY   AR           2014   491      396900 05097     

Great! We fixed it.

OK, we also had some rows that did not have county names because they were just missing or the data was for US territories. We will remove the values that do not have county names.

First, let’s take a look at them again.

annualDosage %>% 
  filter(is.na(BUYER_COUNTY))
# A tibble: 17 x 6
   BUYER_COUNTY BUYER_STATE  year count DOSAGE_UNIT countyfips
   <chr>        <chr>       <int> <int>       <dbl> <chr>     
 1 <NA>         AE           2006     2         330 <NA>      
 2 <NA>         CA           2006    47       12600 <NA>      
 3 <NA>         CT           2006   305       78700 <NA>      
 4 <NA>         CT           2007   112       30900 <NA>      
 5 <NA>         CT           2008    48       15000 <NA>      
 6 <NA>         FL           2006     9         900 <NA>      
 7 <NA>         FL           2007     7         700 <NA>      
 8 <NA>         GA           2006   114       51700 <NA>      
 9 <NA>         IA           2006     7        2300 <NA>      
10 <NA>         IN           2006   292       39300 <NA>      
11 <NA>         MA           2006   247      114900 <NA>      
12 <NA>         NV           2006   380      173600 <NA>      
13 <NA>         NV           2007   447      200600 <NA>      
14 <NA>         NV           2008     5        2200 <NA>      
15 <NA>         OH           2006    23        5100 <NA>      
16 <NA>         PR           2006    10       17800 <NA>      
17 <NA>         PR           2007     2        1300 <NA>      

We can remove these rows from our data set using the filter() command along with the ! (exclamation point) before the is.na() function.

annualDosage %<>% 
  filter(!is.na(BUYER_COUNTY))

Now let’s check that these NA values are gone:

annualDosage %>% 
  filter(is.na(BUYER_COUNTY))
# A tibble: 0 x 6
# ... with 6 variables: BUYER_COUNTY <chr>, BUYER_STATE <chr>, year <int>,
#   count <int>, DOSAGE_UNIT <dbl>, countyfips <chr>

As we have seen, our annualDosage object has data for US territories. So let’s check to see if our land area data also has information for US territories, which would allow us to investigate them as well, a potentially interesting addition to our analysis. If not, we will remove the data for the territories in our annualDosage data.

As a first case, we can use the str_detect() function of the stringr package, which contains lots of functions for looking for patterns in character strings, to look for data from Puerto Rico.

The str_detect() function allows us to look for a particular pattern. It does not have to be the full value, i.e., a partial match is allowed. We can look to see if there are any PR strings within the values of the the Areaname variable.

land_area %>% 
  filter(str_detect(string = Areaname, pattern = "PR"))
# A tibble: 0 x 3
# ... with 3 variables: Areaname <chr>, STCOU <chr>, LND110210D <dbl>

It does not look as if there are any entries for Puerto Rico, but let’s check our code. You can see using a different abbreviation, that this code works as intended:

land_area %>% 
  filter(str_detect(string = Areaname, pattern = "AR"))
# A tibble: 81 x 3
   Areaname     STCOU LND110210D
   <chr>        <chr>      <dbl>
 1 ARIZONA      04000    113594.
 2 ARKANSAS     05000     52035.
 3 Arkansas, AR 05001       989.
 4 Ashley, AR   05003       925.
 5 Baxter, AR   05005       554.
 6 Benton, AR   05007       847.
 7 Boone, AR    05009       590.
 8 Bradley, AR  05011       649.
 9 Calhoun, AR  05013       629.
10 Carroll, AR  05015       630.
# ... with 71 more rows

OK, so it does not look like there is any territory land area data in this dataset. Thus, we will also remove these from the annualDosage tibble.

Question Opportunity

Do you recall how to do this?


Click here to reveal the code.
annualDosage %<>% 
  filter(!is.na(countyfips))

naniar:: vis_miss(annualDosage)

Great! Now there is no missing data in our annual data.

Rural and Urban Counties


Defining if a region is rural or urban is actually quite complicated as the overall population, the structure of our towns and cities, and the access between different locations all change over time. Please see this report form the US Census Bureau about the history of this definition.

According to several definitions - urban areas are often defined as those with greater than 50,000 people. However, there are also definitions of rural areas being based on “population densities of less than 500 people per square mile and places with fewer than 2,500 people”. Typically counties are made up of multiple areas, making it complicated to assign a single “rural” or “urban” label at the county level.

The census re-defines rural and urban areas around the US relatively often. However, census collections about these measurements do not occur every year.

We will define a county as rural or urban based on the population density following the USDA definition that we described above:

  1. rural = population densities of less than 500 people per square mile, as well as places with fewer than 2,500 people
  2. urban = population densities of greater than 500 people per square mile

Ideally, we would want land area from each year, as these do fluctuate a bit, however, the 2010 data should be a decent approximation as 2010 is in the middle of our time span.

We will calculate the density as the number of people per square mile by dividing the population values by the land area values. To do so we first need to combine our land_area and our county_pop data together.

First, we want to make sure that we have one column, in our case the column that contains the numeric code for the counties, in the same format and with the same name in both the tibbles that we wish to combine. We can check the class of data for this column in both datasets using the glimpse()function.


Click here for an explanation of data classes in R

There are several classes of data in R programming. Character is one of these classes. A character string is an individual data value made up of characters. This can be a paragraph, like the legend for the table, or it can be a single letter or number like the letter "a" or the number "3".

If data are of class character, than the numeric values will not be processed like a numeric value in a mathematical sense.

If you want your numeric values to be interpreted that way, they need to be converted to a numeric class. The options typically used are integer (which has no decimal place) and double precision (which has a decimal place).

A variable that is a factor has a set of particular values called levels. Even if these are numeric, they will be interpreted as levels (i.e., as if they were characters) not as mathematical numbers. The values of a factor are assumed to have a particular ordering; by default the order is alphabetical, but this is not always the correct/intuitive ordering. You can modify the order of these levels with the forcats package.


glimpse(land_area)
Rows: 3,198
Columns: 3
$ Areaname   <chr> "UNITED STATES", "ALABAMA", "Autauga, AL", "Baldwin, AL", "~
$ STCOU      <chr> "00000", "01000", "01001", "01003", "01005", "01007", "0100~
$ LND110210D <dbl> 3531905.43, 50645.33, 594.44, 1589.78, 884.88, 622.58, 644.~
glimpse(county_pop)
Rows: 28,265
Columns: 10
$ BUYER_COUNTY <chr> "AUTAUGA", "BALDWIN", "BARBOUR", "BIBB", "BLOUNT", "BULLO~
$ BUYER_STATE  <chr> "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL~
$ countyfips   <chr> "01001", "01003", "01005", "01007", "01009", "01011", "01~
$ STATE        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
$ COUNTY       <int> 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31~
$ county_name  <chr> "Autauga", "Baldwin", "Barbour", "Bibb", "Blount", "Bullo~
$ NAME         <chr> "Autauga County, Alabama", "Baldwin County, Alabama", "Ba~
$ variable     <chr> "B01003_001", "B01003_001", "B01003_001", "B01003_001", "~
$ year         <int> 2006, 2006, 2006, 2006, 2006, 2006, 2006, 2006, 2006, 200~
$ population   <int> 51328, 168121, 27861, 22099, 55485, 10776, 20815, 115388,~

Great, it looks like both are character strings based on the <chr> next to the column names. However, the columns in both tibbles need to have the same name.

We can use the rename() function of the dplyr package to rename the STCOU column from the land_area data set to be countyfips. The new name is always listed first before the old name with this function like so: rename(new_name = old_name).

land_area %<>%
  rename(countyfips = STCOU)

Great! Now we are ready to combine our data together.

We can do so using one of the *_join()functions of the dplyr package.

There are several ways to join data using the dplyr package.

[source]

Here is a visualization of these options:

[source]

See here for more details about joining data.

Since the population data came from the API, we probably have information about opioid pill shipments for each of the included counties. Since the land area data came from a different source, it may contain additional counties that are not in our population or drug shipment data.

To address this, we will use the left_join(x,y) function where x in this case will be the county_pop and y will be the country_area. Here, we will add the LND110210D (land area) values for all counties that match county_pop based on the countyfips column that they have in common.

county_info <- 
  left_join(x = county_pop, y = land_area, by = "countyfips")

It is not actually necessary to list x and y like this, you can simply rely on the x being listed first and the y being listed second.

Thus, this works too:

county_info <- 
  left_join(county_pop, land_area, by = "countyfips")

You can check to see that the county_info tibble has the same number of rows as the county_pop tibble, i.e., our join preserved the data points in the county_pop tibble and added values from the land_area tibble where there was a match on the countyfips variable.

nrow(county_info) == nrow(county_pop)
[1] TRUE

We are now ready to calculate the population density per square mile. We create a new column with this data using the mutate() function and the / to divide the population value by the land area value (in square miles) for each county. Let’s also make the year variable a factor. We can do using the as.factor() base function. If you are not familiar with factors, please see the click to expand section above about data classes in R.

county_info %<>%
  mutate(density = population/LND110210D,
         year = as.factor(year))

glimpse(county_info)
Rows: 28,265
Columns: 13
$ BUYER_COUNTY <chr> "AUTAUGA", "BALDWIN", "BARBOUR", "BIBB", "BLOUNT", "BULLO~
$ BUYER_STATE  <chr> "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL~
$ countyfips   <chr> "01001", "01003", "01005", "01007", "01009", "01011", "01~
$ STATE        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
$ COUNTY       <int> 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31~
$ county_name  <chr> "Autauga", "Baldwin", "Barbour", "Bibb", "Blount", "Bullo~
$ NAME         <chr> "Autauga County, Alabama", "Baldwin County, Alabama", "Ba~
$ variable     <chr> "B01003_001", "B01003_001", "B01003_001", "B01003_001", "~
$ year         <fct> 2006, 2006, 2006, 2006, 2006, 2006, 2006, 2006, 2006, 200~
$ population   <int> 51328, 168121, 27861, 22099, 55485, 10776, 20815, 115388,~
$ Areaname     <chr> "Autauga, AL", "Baldwin, AL", "Barbour, AL", "Bibb, AL", ~
$ LND110210D   <dbl> 594.44, 1589.78, 884.88, 622.58, 644.78, 622.81, 776.83, ~
$ density      <dbl> 86.34681, 105.75111, 31.48563, 35.49584, 86.05261, 17.302~

Great, now we are ready to create a variable that classifies if a county was rural or urban based on our definition of rural counties being those with less than 500 people per square mile as well as those with less than 2,500 people.

We will use the case_when() function of the dplyr package to classify the new rural_urban variable as either "Urban" or "Rural" based on the evaluations of the density and the population variables.

  • If the density is greater than or equal to 500 people per square mile, then the county will be coded as "Urban".
  • Alternatively if the density is less than 500 people per square mile or the population is less than 2500, than the county will be coded as "Rural".

The | operator is used to indicate that either expression should result in coding the county as "Rural"

county_info %<>%
  mutate(rural_urban = case_when(density  >= 500 ~ "Urban",
                                 density  <  500 | population < 2500 ~ "Rural"))

We can use the count() function of the dplyr package to see how many of each this resulted in:

count(county_info, rural_urban)
# A tibble: 2 x 2
  rural_urban     n
  <chr>       <int>
1 Rural       26065
2 Urban        2200

We will now combine the annualDosage data with the count_info tibble.

Question Opportunity

How might we do this?


Click here to reveal the code.
annualDosage %<>%
  mutate(countyfips = as.factor(countyfips),
         year = as.factor(year))
  
Annual <- 
  left_join(annualDosage, county_info)

glimpse(Annual)
Rows: 27,007
Columns: 16
$ BUYER_COUNTY <chr> "ABBEVILLE", "ABBEVILLE", "ABBEVILLE", "ABBEVILLE", "ABBE~
$ BUYER_STATE  <chr> "SC", "SC", "SC", "SC", "SC", "SC", "SC", "SC", "SC", "LA~
$ year         <fct> 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 200~
$ count        <int> 877, 908, 871, 930, 1197, 1327, 1509, 1572, 1558, 5802, 5~
$ DOSAGE_UNIT  <dbl> 363620, 402940, 424590, 467230, 539280, 566560, 589010, 5~
$ countyfips   <chr> "45001", "45001", "45001", "45001", "45001", "45001", "45~
$ STATE        <int> 45, 45, 45, 45, 45, 45, 45, 45, 45, 22, 22, 22, 22, 22, 2~
$ COUNTY       <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
$ county_name  <chr> "Abbeville", "Abbeville", "Abbeville", "Abbeville", "Abbe~
$ NAME         <chr> "Abbeville County, South Carolina", "Abbeville County, So~
$ variable     <chr> "B01003_001", "B01003_001", "B01003_001", "B01003_001", "~
$ population   <int> 25821, 25745, 25699, 25347, 25643, 25515, 25387, 25233, 2~
$ Areaname     <chr> "Abbeville, SC", "Abbeville, SC", "Abbeville, SC", "Abbev~
$ LND110210D   <dbl> 490.48, 490.48, 490.48, 490.48, 490.48, 490.48, 490.48, 4~
$ density      <dbl> 52.64435, 52.48940, 52.39561, 51.67795, 52.28144, 52.0204~
$ rural_urban  <chr> "Rural", "Rural", "Rural", "Rural", "Rural", "Rural", "Ru~

Great, now we should have the data that we need to answer our question, but first let’s do some additional checks before we proceed with our analysis.

Notice how there is a variable called DOSAGE_UNIT. This variable gives the number of pills shipped to a pharmacy in this county that were either oxycodone or hydrocodone.

Let’s do a check to see how complete our data is now that we have combined our country_info data with the annualDosage data.

We have NA values for any counties present in the DAE data, but not in our land area data. We can use the gg_miss_var() function from the naniar package to create a plot that shows if we have any missing data.

naniar:: gg_miss_var(Annual)

We can see that several variables are missing for some of our counties.

Let’s take a look at the counties that are missing density.

Annual %>%
  filter(is.na(density))
# A tibble: 27 x 16
   BUYER_COUNTY      BUYER_STATE year  count DOSAGE_UNIT countyfips STATE COUNTY
   <chr>             <chr>       <fct> <int>       <dbl> <chr>      <int>  <int>
 1 MONTGOMERY        AR          2006    469      175390 05097         NA     NA
 2 MONTGOMERY        AR          2007    597      241270 05097         NA     NA
 3 MONTGOMERY        AR          2008    561      251760 05097         NA     NA
 4 MONTGOMERY        AR          2009    554      244160 05097         NA     NA
 5 MONTGOMERY        AR          2010    449      247990 05097         NA     NA
 6 MONTGOMERY        AR          2011    560      313800 05097         NA     NA
 7 MONTGOMERY        AR          2012    696      339520 05097         NA     NA
 8 MONTGOMERY        AR          2013    703      382300 05097         NA     NA
 9 MONTGOMERY        AR          2014    491      396900 05097         NA     NA
10 PRINCE OF WALES ~ AK          2006    190       62700 02201         NA     NA
# ... with 17 more rows, and 8 more variables: county_name <chr>, NAME <chr>,
#   variable <chr>, population <int>, Areaname <chr>, LND110210D <dbl>,
#   density <dbl>, rural_urban <chr>

There does not appear to be land area and/or population data for these counties.

Let’s take a look back at our original data tibbles (prior to merging) for a few of these counties to see where the data first went missing.

county_info %>% 
  filter(countyfips == "01001") # example of other data that does have values
# A tibble: 9 x 14
  BUYER_COUNTY BUYER_STATE countyfips STATE COUNTY county_name NAME     variable
  <chr>        <chr>       <chr>      <int>  <int> <chr>       <chr>    <chr>   
1 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
2 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
3 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
4 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
5 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
6 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
7 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
8 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
9 AUTAUGA      AL          01001          1      1 Autauga     Autauga~ B01003_~
# ... with 6 more variables: year <fct>, population <int>, Areaname <chr>,
#   LND110210D <dbl>, density <dbl>, rural_urban <chr>
county_info %>% 
  filter(countyfips == "05097")
# A tibble: 0 x 14
# ... with 14 variables: BUYER_COUNTY <chr>, BUYER_STATE <chr>,
#   countyfips <chr>, STATE <int>, COUNTY <int>, county_name <chr>, NAME <chr>,
#   variable <chr>, year <fct>, population <int>, Areaname <chr>,
#   LND110210D <dbl>, density <dbl>, rural_urban <chr>
county_info %>% 
  filter(countyfips == "02201")
# A tibble: 0 x 14
# ... with 14 variables: BUYER_COUNTY <chr>, BUYER_STATE <chr>,
#   countyfips <chr>, STATE <int>, COUNTY <int>, county_name <chr>, NAME <chr>,
#   variable <chr>, year <fct>, population <int>, Areaname <chr>,
#   LND110210D <dbl>, density <dbl>, rural_urban <chr>
county_info %>% 
  filter(countyfips == "02280")
# A tibble: 0 x 14
# ... with 14 variables: BUYER_COUNTY <chr>, BUYER_STATE <chr>,
#   countyfips <chr>, STATE <int>, COUNTY <int>, county_name <chr>, NAME <chr>,
#   variable <chr>, year <fct>, population <int>, Areaname <chr>,
#   LND110210D <dbl>, density <dbl>, rural_urban <chr>

Ah ha, it looks like there wasn’t information for it in the county_info tibble. If you recall this was created by joining the land_area data with the county_pop data.

Let’s take a look in these tibbles.

There is land data for the first county, but that’s all:

land_area %>% 
  filter(countyfips == "05097")
# A tibble: 1 x 3
  Areaname       countyfips LND110210D
  <chr>          <chr>           <dbl>
1 Montgomery, AR 05097            780.
land_area %>% 
  filter(countyfips == "02201")
# A tibble: 0 x 3
# ... with 3 variables: Areaname <chr>, countyfips <chr>, LND110210D <dbl>
land_area %>% 
  filter(countyfips == "02280")
# A tibble: 0 x 3
# ... with 3 variables: Areaname <chr>, countyfips <chr>, LND110210D <dbl>

Did we have population data for the Montgomery, AR county?

county_pop %>% 
  filter(countyfips == "05097")
# A tibble: 0 x 10
# ... with 10 variables: BUYER_COUNTY <chr>, BUYER_STATE <chr>,
#   countyfips <chr>, STATE <int>, COUNTY <int>, county_name <chr>, NAME <chr>,
#   variable <chr>, year <int>, population <int>
county_pop %>% 
  filter(BUYER_COUNTY == "MONTGOMERY"& BUYER_STATE =="AK")
# A tibble: 0 x 10
# ... with 10 variables: BUYER_COUNTY <chr>, BUYER_STATE <chr>,
#   countyfips <chr>, STATE <int>, COUNTY <int>, county_name <chr>, NAME <chr>,
#   variable <chr>, year <int>, population <int>

It looks like we didn’t.

It’s a good idea to check your original data, to make sure that you didn’t lose values simply from the process of joining data together. It does not look like that was the case for us.

We will now remove these rows before further analysis:

Question Opportunity

Do you recall how you would do this?


Click here to reveal the code.
Annual %<>% 
  filter(!is.na(STATE))

naniar:: gg_miss_var(Annual)

Nice! Now we have no missing data.

Let’s also check if there were any counties in county_info that were not in the DEA annualDosage data.

This time we will use the left_join() function but with the county_info listed first, to preserve all values of the county_info tibble.

checking <-
  left_join(county_info, annualDosage)
gg_miss_var(checking)

We can see that there are over one thousand NA values for the DOSAGE_UNIT variable.

We can use the filter() function again to see what counties don’t have any DOSAGE_UNIT values and thus don’t appear to have this data in the Washington Post DEA data.

checking %>%
  filter(is.na(DOSAGE_UNIT))
# A tibble: 1,285 x 16
   BUYER_COUNTY   BUYER_STATE countyfips STATE COUNTY county_name NAME  variable
   <chr>          <chr>       <chr>      <int>  <int> <chr>       <chr> <chr>   
 1 BRISTOL BAY    AK          02060          2     60 Bristol Bay Bris~ B01003_~
 2 DILLINGHAM     AK          02070          2     70 Dillingham  Dill~ B01003_~
 3 LAKE AND PENI~ AK          02164          2    164 Lake and P~ Lake~ B01003_~
 4 NOME           AK          02180          2    180 Nome        Nome~ B01003_~
 5 PRINCE OF WAL~ AK          02198          2    201 Prince of ~ <NA>  <NA>    
 6 SKAGWAY HOONA~ AK          02232          2    232 Skagway Ho~ <NA>  <NA>    
 7 SOUTHEAST FAI~ AK          02240          2    240 Southeast ~ Sout~ B01003_~
 8 WADE HAMPTON   AK          02270          2    270 Wade Hampt~ Wade~ B01003_~
 9 WRANGELL       AK          02275          2    280 Wrangell    <NA>  <NA>    
10 YAKUTAT        AK          02282          2    282 Yakutat     Yaku~ B01003_~
# ... with 1,275 more rows, and 8 more variables: year <fct>, population <int>,
#   Areaname <chr>, LND110210D <dbl>, density <dbl>, rural_urban <chr>,
#   count <int>, DOSAGE_UNIT <dbl>
checking %>%
  filter(is.na(DOSAGE_UNIT)) %>% 
  distinct(countyfips) 
# A tibble: 174 x 1
   countyfips
   <chr>     
 1 02060     
 2 02070     
 3 02164     
 4 02180     
 5 02198     
 6 02232     
 7 02240     
 8 02270     
 9 02275     
10 02282     
# ... with 164 more rows

It looks like there are 174 counties that do not have any data in the DEA data.

It is unclear why these counties are not included. A Google search of some of these counties did not indicate anything unusual about the counties in terms of when it was established or if it became part of another county later in time.

Thus, it is important to keep in mind as we continue to analyze this data, that the ARCOS data from the DEA released by the Washington Post does not include pill shipment information for all US counties.

Let’s save this data now in a directory called “wrangled” within the “data” directory. We will also write csv file versions which could be useful to give to a collaborator for example.

write.csv(Annual, file = here::here("data","wrangled", "Annual_opioid_data.csv"))
save(Annual, file =  here::here("data","wrangled", "Annual_opioid_data.rda"))
write.csv(county_info, file = here::here("data", "wrangled", "county_info.csv"))
save(county_info, file = here::here("data", "wrangled", "county_info.rda"))

Data Visualization


If you have been following along but stopped, we could load our wrangled data from the “data” directory like so:

load(file = here::here("data", "wrangled", "Annual_opioid_data.rda"))
load(file = here::here("data", "wrangled", "county_info.rda"))

If you skipped the previous sections click here.

First you need to install and load the OCSdata package:

install.packages("OCSdata")
library(OCSdata)

Then, you may download and load the wrangled data into your R environment using the following code:

wrangled_rda("ocs-bp-opioid-rural-urban", outpath = getwd())
load(file = here::here("OCSdata", "data", "wrangled", "Annual_opioid_data.rda"))
load(file = here::here("OCSdata", "data", "wrangled", "county_info.rda"))

If the package does not work for you, alternatively, the RDA files (stands for R data) of the data can be found in our GitHub repository. Download these files and then place them in your current working directory within a subdirectory called “wrangled” within a subdirectory called “data” to copy and paste our code. We used an RStudio project and the here package to navigate to the files more easily.

load(file = here::here("data","wrangled", "Annual_opioid_data.rda"))
load(file = here::here("data", "wrangled", "county_info.rda"))

Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



We will begin by taking a deeper look at our data with some visualizations. We will use the ggplot2 package to create these visualizations.


Click here for an introduction about this package if you are new to using ggplot2

The ggplot2 package is generally intuitive for beginners because it is based on a grammar of graphics or the gg in ggplot2. The idea is that you can construct many sentences by learning just a few nouns, adjectives, and verbs. There are specific “words” that we will need to learn and once we do, you will be able to create (or “write”) hundreds of different plots.

The critical part to making graphics using ggplot2 is the data needs to be in a tidy format. Given that we have just spent time putting our data in tidy format, we are primed to take advantage of all that ggplot2 has to offer!

We will show how it is easy to pipe tidy data (output) as input to other functions that create plots. This all works because we are working within the tidyverse.

What is the ggplot() function? As explained by Hadley Wickham:

The grammar tells us that a statistical graphic is a mapping from data to aesthetic attributes (colour, shape, size) of geometric objects (points, lines, bars). The plot may also contain statistical transformations of the data and is drawn on a specific coordinates system.

ggplot2 Terminology:

  • ggplot - the main function where you specify the dataset and variables to plot (this is where we define the x and y variable names)
  • geoms - geometric objects
    • e.g. geom_point(), geom_bar(), geom_line(), geom_histogram()
  • aes - aesthetics
    • shape, transparency, color, fill, line types
  • scales - define how your data will be plotted
    • continuous, discrete, log, etc

The function aes() is an aesthetic mapping function inside the ggplot() object. We use this function to specify plot attributes (e.g. x and y variable names) that will not change as we add more layers.

Anything that goes in the ggplot() object becomes a global setting. From there, we use the geom objects to add more layers to the base ggplot() object. These will define what we are interested in illustrating using the data.


Population density


Let’s make a plot to see how population density has changed over time in each state.

To do this, we want to calculate a mean population density (across all the counties) for each state for each year.

We can do this using the group_by() and summarize() functions of the dplyr package. The group_by functions allows for the data to be arranged into groups for subsequent functions.

If we group only by BUYER_STATE, you see that this results in 51 groups (one for each state including Washington DC). This does not change anything about the data itself (or even how it is printed aside from the groups written above the table), just how it is handled in subsequent steps.

Annual %>% 
  group_by(BUYER_STATE)
# A tibble: 26,980 x 16
# Groups:   BUYER_STATE [51]
   BUYER_COUNTY BUYER_STATE year  count DOSAGE_UNIT countyfips STATE COUNTY
   <chr>        <chr>       <fct> <int>       <dbl> <chr>      <int>  <int>
 1 ABBEVILLE    SC          2006    877      363620 45001         45      1
 2 ABBEVILLE    SC          2007    908      402940 45001         45      1
 3 ABBEVILLE    SC          2008    871      424590 45001         45      1
 4 ABBEVILLE    SC          2009    930      467230 45001         45      1
 5 ABBEVILLE    SC          2010   1197      539280 45001         45      1
 6 ABBEVILLE    SC          2011   1327      566560 45001         45      1
 7 ABBEVILLE    SC          2012   1509      589010 45001         45      1
 8 ABBEVILLE    SC          2013   1572      596420 45001         45      1
 9 ABBEVILLE    SC          2014   1558      641350 45001         45      1
10 ACADIA       LA          2006   5802     1969720 22001         22      1
# ... with 26,970 more rows, and 8 more variables: county_name <chr>,
#   NAME <chr>, variable <chr>, population <int>, Areaname <chr>,
#   LND110210D <dbl>, density <dbl>, rural_urban <chr>

Alternatively, if we group by year this results in 9 groups of data, one for each year.

Annual %>% 
  group_by(year)
# A tibble: 26,980 x 16
# Groups:   year [9]
   BUYER_COUNTY BUYER_STATE year  count DOSAGE_UNIT countyfips STATE COUNTY
   <chr>        <chr>       <fct> <int>       <dbl> <chr>      <int>  <int>
 1 ABBEVILLE    SC          2006    877      363620 45001         45      1
 2 ABBEVILLE    SC          2007    908      402940 45001         45      1
 3 ABBEVILLE    SC          2008    871      424590 45001         45      1
 4 ABBEVILLE    SC          2009    930      467230 45001         45      1
 5 ABBEVILLE    SC          2010   1197      539280 45001         45      1
 6 ABBEVILLE    SC          2011   1327      566560 45001         45      1
 7 ABBEVILLE    SC          2012   1509      589010 45001         45      1
 8 ABBEVILLE    SC          2013   1572      596420 45001         45      1
 9 ABBEVILLE    SC          2014   1558      641350 45001         45      1
10 ACADIA       LA          2006   5802     1969720 22001         22      1
# ... with 26,970 more rows, and 8 more variables: county_name <chr>,
#   NAME <chr>, variable <chr>, population <int>, Areaname <chr>,
#   LND110210D <dbl>, density <dbl>, rural_urban <chr>

We want to group by both BUYER_STATE and year, so that we get the mean of all the counties for each state for each year. If we only did by BUYER_STATE, we would only get 51 summarized results, one for each state representing a mean across the years.

Annual %>% 
  group_by(BUYER_STATE, year)
# A tibble: 26,980 x 16
# Groups:   BUYER_STATE, year [459]
   BUYER_COUNTY BUYER_STATE year  count DOSAGE_UNIT countyfips STATE COUNTY
   <chr>        <chr>       <fct> <int>       <dbl> <chr>      <int>  <int>
 1 ABBEVILLE    SC          2006    877      363620 45001         45      1
 2 ABBEVILLE    SC          2007    908      402940 45001         45      1
 3 ABBEVILLE    SC          2008    871      424590 45001         45      1
 4 ABBEVILLE    SC          2009    930      467230 45001         45      1
 5 ABBEVILLE    SC          2010   1197      539280 45001         45      1
 6 ABBEVILLE    SC          2011   1327      566560 45001         45      1
 7 ABBEVILLE    SC          2012   1509      589010 45001         45      1
 8 ABBEVILLE    SC          2013   1572      596420 45001         45      1
 9 ABBEVILLE    SC          2014   1558      641350 45001         45      1
10 ACADIA       LA          2006   5802     1969720 22001         22      1
# ... with 26,970 more rows, and 8 more variables: county_name <chr>,
#   NAME <chr>, variable <chr>, population <int>, Areaname <chr>,
#   LND110210D <dbl>, density <dbl>, rural_urban <chr>

We can see that this results in 459 groups. This makes sense because 51 groups over 9 years is 51 multiplied by 9, which equals 459.

Next, we will need to use the summarize() function of the dplyr package. Notice that the Hmisc package that we loaded at the beginning of this case study also has a function called summarize(), and therefore, creating a conflict. Since we loaded Hmisc after we loaded dplyr, the summarize() function of the dplyr package is masked by the summarize() function of the Hmisc package, meaning that if we do not specify which package we want to use, R will use the summarize() function of the Hmisc package by default. To deal with this, we can use dplyr::summarize() to specify that we want to use the function of the dplyr package. However, since we will be using this function several times later in the case study, we might want to tell R that when we use the summarize() function, we want to use the function of the dplyr package. We can do this like so:

summarize <- dplyr::summarize

You may also follow this link to learn about the conflicted package.

We can use the summarize() function of the dplyr package to create a new variable called mean_DENS, which will be equal to the mean of the population density variable for all the counties within each of the 449 groups. If we had missing values we would need to use the na.rm = TRUE argument to remove any missing values in our calculation.

Annual %>% 
  group_by(BUYER_STATE, year) %>%
  summarize(mean_DENS = mean(density, na.rm = TRUE))
# A tibble: 459 x 3
# Groups:   BUYER_STATE [51]
   BUYER_STATE year  mean_DENS
   <chr>       <fct>     <dbl>
 1 AK          2006       11.6
 2 AK          2007       12.2
 3 AK          2008       13.9
 4 AK          2009       13.0
 5 AK          2010       13.2
 6 AK          2011       14.2
 7 AK          2012       13.5
 8 AK          2013       14.6
 9 AK          2014       14.7
10 AL          2006       87.3
# ... with 449 more rows

OK! Now we are ready to make our first plot.

We will start with the ggplot()function to specify what variables will be used for the x-axis and y-axis, as well as if any variable should be used to specify different colors on the plot. This will result in a blank plot.

We need to use a geom_* function to specify what type of plot we would like to make.

If you type geom_ into the console of RStudio, you will see a list of options.

We will create a scatter plot using the geom_point() function. We will also use the theme_minimal() function to change the overall aesthetics of the plot. See here for a list of options.

We will also use the theme() function to further specify how we want the plot to be displayed. We would like the x-axis text to be angled by 90 degrees. We can use the element_text() function to change aspects about the text and we can use the axis.text.x argument to specify that we want to specifically change the text of the x-axis.

You can type theme() in the RStudio console and press tab to see a list of argument options for things that you can change in your plot.

Finally, we can use the labs() function of the ggplot2 package to specify the labels of the plot.

Annual %>% 
  group_by(BUYER_STATE, year) %>%
  summarize(mean_DENS = mean(density, na.rm = TRUE)) %>%
  ggplot(aes(x = BUYER_STATE, y = mean_DENS, col = year)) + 
    geom_point() + 
    theme_minimal()+
    theme(axis.title.x = element_blank(),
           axis.text.x = element_text(angle = 90)) +
    labs(x = "State",
         title = "Mean County Population Density of each State",
         y = "Mean Population Density (People per square mile)")

We can see that the average state population density is fairly similar for most states. However DC, MA, NJ, NY, RI, and VA have much higher average county densities. We also see that DC shows the largest change over time, as we can see the other individual points for each year. For other states the change was so small that they are overlapping.

What about overall population density, how did the national average of all US counties change?

We will ignore the different states in this case and we will calculate the mean of all US counties for each year.

Question Opportunity

How might you create this plot?


Click here to reveal the code.
USavg_dens <- 
  Annual %>% 
  group_by(year) %>%
  summarize(mean_DENS = mean(density)) %>%
  ggplot(aes(x = year, y = mean_DENS)) + 
    geom_point() +
    theme_minimal() +
    theme(axis.title.x=element_blank()) +
    labs(title = "US mean population density",
         x = "year",
         y = "population density (people per square mile)")

In this case we saved the plot to an object called USavg_dens.


USavg_dens

Overall the density has increased, if you take a look at the y-axis you can see that the density has changed by about 13 people per square mile from 2006 to 2014.

How does this compare with raw population values?

To make this plot, we will take the sum of the population values for each county rather than the mean.

Question Opportunity

How might you create this plot?


Click here to reveal the code.
overall_density <- 
  Annual %>% 
  group_by(year) %>%
  summarize(total_population = sum(population)) %>%
  ggplot(aes(x = year, y = total_population)) + 
      geom_point() +
      geom_smooth() +
      theme_minimal() +
      theme(axis.title.x = element_blank()) +
      labs(title = "US Population from 2006-2014",
           x = "year",
           y = "US total population")
overall_density

Rural and Urban areas


How have the number of rural and urban areas changed over years?

To determine how the number of each type of county has changed over time, we will use the count() function of the dplyr package after grouping by the year variable to count the number of occurrences of the unique values (which are Rural and Urban) in the rural_ubran variable.

Annual %>% 
  group_by(year) %>%
  count(rural_urban)
# A tibble: 18 x 3
# Groups:   year [9]
   year  rural_urban     n
   <fct> <chr>       <int>
 1 2006  Rural        2769
 2 2006  Urban         235
 3 2007  Rural        2760
 4 2007  Urban         238
 5 2008  Rural        2753
 6 2008  Urban         238
 7 2009  Rural        2756
 8 2009  Urban         236
 9 2010  Rural        2753
10 2010  Urban         238
11 2011  Rural        2756
12 2011  Urban         243
13 2012  Rural        2761
14 2012  Urban         243
15 2013  Rural        2754
16 2013  Urban         246
17 2014  Rural        2753
18 2014  Urban         248

In this case, we can make a plot using two different geom_* layers together. Whatever geom_* layer is added last will be displayed on top.

We will use geom_point() and geom_smooth() to add a line connecting the points of the scatter plot of the geom_point() function. We can also use the facet_wrap() function of the ggplot2 package to create subplots based on the rural_urban variable.

This creates a subplot for the Rural values and another for the Urban values. The scales = "free" argument allows for each to have a different scale for the y-axis.

Annual %>% 
  group_by(year) %>%
  count(rural_urban) %>%
  ggplot(aes(x = year, y = n, col = rural_urban, 
             group = rural_urban)) + 
    geom_point() + 
    geom_smooth() +
    facet_wrap(~ rural_urban, scales = "free") +
    theme_minimal() +
    theme(axis.title.x = element_blank(),
          axis.text.x = element_text(angle = 90),
          legend.title = element_blank()) +
    labs(y = "Number of Counties", 
         x = "Year",
         title = "Change in the number of the rural and urban counties in the US over time")

As one might expect, it looks like the number of urban areas has increased, while the number of rural areas has decreased over time.

Let’s also create a table to look at the number of rural and urban counties over time. To do this we can use the package formattable. We will convert our data into a format needed for the formattable package.

We previously counted the number of Rural and Urban counties for each year. However, the data was presented in a format that is called long format. In this format, variables that could possibly be presented as separate columns are condensed into fewer columns, while still maintaining only a single value per cell.

The opposite of this format is called wide format data, which therefore has more columns and fewer rows. This is best illustrated with an example.

[source]

On the left is “wide” dataset with more columns and fewer rows. On the right is a “long” dataset where the month columns have been collapsed into two longer columns (one with the name of the month and one with the numeric value) resulting in fewer columns and more rows.

While long format is very useful for creating plots with ggplot2 it is helpful to have the data in wide format for tables that someone would quickly read, which is our current goal.


Click here to see another example.

Here is an example of wide data about different measurements of a variety species of Iris flowers.

   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1           4.3         3.0          1.1         0.1     setosa
2           5.0         3.3          1.4         0.2     setosa
3           7.7         3.8          6.7         2.2  virginica
4           4.4         3.2          1.3         0.2     setosa
5           5.9         3.0          5.1         1.8  virginica
6           6.5         3.0          5.2         2.0  virginica
7           5.5         2.5          4.0         1.3 versicolor
8           5.5         2.6          4.4         1.2 versicolor
9           5.8         2.7          5.1         1.9  virginica
10          6.1         3.0          4.6         1.4 versicolor

OK, so currently we have 4 different columns about measurements of different flowers. Since all of these measurements are similar, one might produce a new variable that is made up of the names of the first four variables and another that is the numeric value like so:

# A tibble: 40 x 3
   Species   Measurement  Value
   <fct>     <chr>        <dbl>
 1 setosa    Sepal.Length   4.3
 2 setosa    Sepal.Width    3  
 3 setosa    Petal.Length   1.1
 4 setosa    Petal.Width    0.1
 5 setosa    Sepal.Length   5  
 6 setosa    Sepal.Width    3.3
 7 setosa    Petal.Length   1.4
 8 setosa    Petal.Width    0.2
 9 virginica Sepal.Length   7.7
10 virginica Sepal.Width    3.8
# ... with 30 more rows

Next, we demonstrate how to convert the counts of Rural and Urban data into wide format from long format. Here is our original data:

Annual  %>% 
  group_by(year) %>%
  count(rural_urban)
# A tibble: 18 x 3
# Groups:   year [9]
   year  rural_urban     n
   <fct> <chr>       <int>
 1 2006  Rural        2769
 2 2006  Urban         235
 3 2007  Rural        2760
 4 2007  Urban         238
 5 2008  Rural        2753
 6 2008  Urban         238
 7 2009  Rural        2756
 8 2009  Urban         236
 9 2010  Rural        2753
10 2010  Urban         238
11 2011  Rural        2756
12 2011  Urban         243
13 2012  Rural        2761
14 2012  Urban         243
15 2013  Rural        2754
16 2013  Urban         246
17 2014  Rural        2753
18 2014  Urban         248

We would like the rural_urban data to be shown in two different columns; one that shows Rural counts and one that shows Urban counts. We can use the pivot_wider() function of the tidyr package to do this. This takes two important arguments:

  1. names_from: this argument indicates what variable to use to create the names of the new variables
  2. values_from: this argument indicates what variable to use to fill in the values of the new variables

In our case, we use the names from the rural_urban variable and the values from the n variable.

Annual %>% 
  group_by(year) %>%
  count(rural_urban) %>%
  tidyr::pivot_wider(names_from = rural_urban, 
                     values_from = n)
# A tibble: 9 x 3
# Groups:   year [9]
  year  Rural Urban
  <fct> <int> <int>
1 2006   2769   235
2 2007   2760   238
3 2008   2753   238
4 2009   2756   236
5 2010   2753   238
6 2011   2756   243
7 2012   2761   243
8 2013   2754   246
9 2014   2753   248

Nice!

Now, let’s also create two new variables that show the change in count of rural and urban counties from one year to the next. We can do so using the lag() function of the dplyr package. This function will find the previous value thus Rural - lag(Rural) will take the current row and subtract the previous row’s value. Note that is necessary to include the ungroup() function to stop grouping by year.

Annual %>% 
  group_by(year) %>%
  count(rural_urban) %>%
  tidyr::pivot_wider(names_from = rural_urban,
                     values_from = n) %>%
  ungroup() %>% 
  mutate("Rural Change" = Rural - lag(Rural), 
         "Urban Change" = Urban - lag(Urban))
# A tibble: 9 x 5
  year  Rural Urban `Rural Change` `Urban Change`
  <fct> <int> <int>          <int>          <int>
1 2006   2769   235             NA             NA
2 2007   2760   238             -9              3
3 2008   2753   238             -7              0
4 2009   2756   236              3             -2
5 2010   2753   238             -3              2
6 2011   2756   243              3              5
7 2012   2761   243              5              0
8 2013   2754   246             -7              3
9 2014   2753   248             -1              2

Let’s also add a column about the percent urban for each year. We use the base round() function to round the percentages to 2 digits after the decimal using the digits = 2 argument.

Finally, we rename the year variable to be Year using the rename() function of the dplyr package, which requires that the new name be listed before the = sign followed by the old name.

R_U <- 
  Annual %>% 
  group_by(year) %>%
  count(rural_urban) %>%
  tidyr::pivot_wider(names_from = rural_urban,
                     values_from = n) %>%
  ungroup() %>% 
  mutate("Rural Change" = Rural - lag(Rural), 
         "Urban Change" = Urban - lag(Urban),
         "Percent Urban" = round((Urban/(Urban + Rural))*100, 
                                 digits = 2)) %>%
  rename("Year" = "year")

R_U
# A tibble: 9 x 6
  Year  Rural Urban `Rural Change` `Urban Change` `Percent Urban`
  <fct> <int> <int>          <int>          <int>           <dbl>
1 2006   2769   235             NA             NA            7.82
2 2007   2760   238             -9              3            7.94
3 2008   2753   238             -7              0            7.96
4 2009   2756   236              3             -2            7.89
5 2010   2753   238             -3              2            7.96
6 2011   2756   243              3              5            8.1 
7 2012   2761   243              5              0            8.09
8 2013   2754   246             -7              3            8.2 
9 2014   2753   248             -1              2            8.26

Nice, now it is pretty easy to interpret table, but we can make it even easier to quickly assess trends in the data using the formattable package.

The formmattable() function creates a formatted table, and takes a list of variables and a stylized version of each variable in which to add special formatting.

As a simple example, we will use the color_bar() function of this package to add color bars to the percent_urban column which shows changes in values by the width of a color bar.

formattable::formattable(R_U, list(`Percent Urban` = 
                                     formattable::color_bar("#FA614B")))
Year Rural Urban Rural Change Urban Change Percent Urban
2006 2769 235 NA NA 7.82
2007 2760 238 -9 3 7.94
2008 2753 238 -7 0 7.96
2009 2756 236 3 -2 7.89
2010 2753 238 -3 2 7.96
2011 2756 243 3 5 8.10
2012 2761 243 5 0 8.09
2013 2754 246 -7 3 8.20
2014 2753 248 -1 2 8.26

Nice, now we can see how much the percentage has changed over time.

US shipments over time


Now let’s get a sense of how the shipments of oxycodone and hydrocodone changed over time across all counties in the US.

First, we create a new variable in the Annual data that is the number of pills (in millions), as this is easier for us to interpret.

Annual %<>% 
  mutate(Pills_in_millions = DOSAGE_UNIT/1000000)

Next, let’s make a plot using the stat_summary() function rather than a geom_* function, because this allows a user to calculate different features about the data to plot using custom functions that are wrappers for the smean.* functions from the Hmisc package.

For example, the stat_summary(fun.data = mean_sd) is a wrapper around the smean.sd function from the Hmisc package.

See the documentation for the Hmisc package to learn more about these functions.

ggplot2 wrapper Hmisc function Details
mean_cl_normal smean.cl.normal computes 3 summary variables: the sample mean and lower and upper Gaussian confidence limits based on the t-distribution
mean_sd smean.sd computes the mean plus or minus the standard deviation
mean_sdl smean.sdl computes the mean plus or minus a constant times the standard deviation
mean_cl_boot smean.cl.boot fast implementation of the basic nonparametric bootstrap for obtaining confidence limits for the population mean without assuming normality (default is 1000 bootstrap samples)
median_hilow smedian.hilow computes the sample median and a selected pair of outer quantiles having equal tail areas

We will use the mean_cl_boot() function to create our plot. As noted above, this function uses something called a “bootstrap” calculate confidence limits for the population mean. Let’s dig into a bit how this works.

The bootstrap is based on the idea of random sampling with replacement. Let’s assume we take a random sample from a population and calculate the sample mean \(\bar{x}\) = \(\frac{1}{n} \sum_{i=1}^n x_i\), which resulted in \(\bar{x}=3.2\) number of shipped pills (in millions). However, a different random sample might have yielded \(\bar{x}=3.0\), or \(\bar{x}=3.5\). It would be nice to get a sense of the accuracy of the original estimate.

To do that, we need to understand how the proportions \(\bar{x}\) vary sample to sample, or due to random sampling. But first, we need to define a sampling distribution.

Sampling distribution

If we took 50 different random samples of the number of pills shipped in a given year for a given county, we could see a distribution of the \(\bar{x}\) from the recorded numbers from the different random samples taken (\(\bar{x}_1, \ldots, \bar{x}_{50}\)).

The most important thing to understand about sampling distributions is it’s the distribution of a test statistic (e.g. \(\bar{x}\)) that summarizes a dataset and represents how the statistic varies across many random datasets.

A histogram of one set of observations drawn from a population does not represent a sampling distribution.

A histogram of permutation means, each from one sample, does represent a sampling distribution.

We call the standard deviation of a statistic the standard error.

The bootstrap

In the scenario where the true population mean is unknown, all we have are the data and a statistic estimated from the data. We need to estimate the sampling distribution of \(\bar{x}\) to understand how much variability or uncertainty there is.

Here, we will use what’s called the bootstrap to create a new distribution called the bootstrap distribution, which approximates the sampling distribution for test statistics.

How does the bootstrap work?

To find the bootstrap distribution of sample mean, we draw samples (called resamples or bootstrap samples) of size \(n\), with replacement, from the original sample and then compute the mean of each resample.

A few things to note about bootstrap distributions:

  1. We treat the original sample as the population. If the original sample is representative of the population, then the bootstrap distribution of the test statistics will look approximately like the sampling distribution of the test statistic (same spread and shape).

  2. The bootstrap standard error is the standard deviation of the bootstrap distribution of that statistic.

  3. However, the mean of the bootstrap distribution will be the same as the mean of the original sample (not necessarily that of the original population).

Steps to construct the bootstrap distribution

  1. Start with a sample of size \(n\) from a population
  2. Draw a resample of size \(n\) with replacement from the sample
  3. Compute a statistic that describes the sample, such as the sample mean
  4. Repeat the resampling process many times
  5. Construct the bootstrap distribution of the statistic. Inspect the spread, bias and shape.

Bootstrap percentile confidence intervals

The interval between the 2.5 and 97.5 percentiles of the bootstrap distribution of a statistic is a 95% bootstrap percentile confidence interval for the corresponding parameter.

We can then say that we are 95% confident that the true statistic lies within this interval.

See here for more details about how this process works.

Back to the bootstrap

We can use the mean_cl_boot function in our plot with stat_summary(fun.data = mean_cl_boot) to calculate the 95% bootstrap confidence intervals.

We can also add a position argument so that our two groups are not overlapping by choosing the position_doge option which takes an argument of width which specifies how far apart the two groups should be plotted.

The confidence intervals are then plotted as a line through a point which shows the range of other possible values for the mean based on the bootstrap samples.

We will also use the stat_summary() function to create a line between the points based on the mean.

raw_average <- 
  Annual %>% 
  group_by(year) %>%
  ggplot(aes(x = year, y = Pills_in_millions)) + 
    stat_summary(fun.data = mean_cl_boot,
                 position = position_dodge(width=0.5)) +
    stat_summary(fun = mean, geom = "line") +
    labs(title = "Average Number of Opioid Pills Shipped to a US County",
         y = "Number of pills in millions") +
  theme_minimal()

raw_average

It looks like the average number of opioid pills shipped to a county peaked in 2011 and has slowly declined.

We can look a bit deeper if we only calculate a mean for each state. To make a visual of this we will use the geom_boxjitter() function of the ggpol package.

raw_state_avg <- 
  Annual %>% 
  group_by(BUYER_STATE, year) %>%
  summarize( mean_DOSAGE = mean(Pills_in_millions)) %>% 
  ungroup() %>%
  ggplot(aes(x = year, y = (mean_DOSAGE))) + 
    ggpol::geom_boxjitter() +
    labs(title = "Average number of opioid pills shipped to a given county for each state",
         y = "Number of pills in millions") + 
  theme_minimal()

raw_state_avg

Again we see the same general overall trend, we also see that the spread was quite large with some states receiving many more pills than others.

State Shipments over time


To get a better sense of how each state changed over time we can create a line plot instead.

Annual %>% 
  group_by(BUYER_STATE, year) %>%
  summarize(mean_DOSAGE = mean(Pills_in_millions)) %>%
  ungroup() %>% 
  ggplot(aes(x = year, y = mean_DOSAGE, group = BUYER_STATE, 
             color = BUYER_STATE)) + 
    geom_line() +
    labs(title = "Average number of opioid pills shipped to a given county for each state",
         y = "Number of pills in millions")+
    theme_minimal()

Since we have so many states, the legend is not very useful. Instead we can use the girafe package to create an interactive plot that will tell people what state each line represents when they hover over different data points.

g <- 
  Annual %>% 
  group_by(BUYER_STATE, year) %>%
  summarize(mean_DOSAGE = mean(Pills_in_millions)) %>%
  ungroup() %>% 
  ggplot(aes(x = year, y = mean_DOSAGE, group = BUYER_STATE, 
             color = BUYER_STATE)) +
    geom_line() +
    labs(title = "Average number of opioid pills shipped to a given county for each state",
         y = "Number of pills in millions") +
    theme_minimal()


g <- 
  g + geom_point_interactive(aes(color = BUYER_STATE, 
                                 tooltip = usdata::abbr2state(BUYER_STATE)), 
                             size = 2, alpha = 3/10) +
  theme(legend.position = "none")
 
girafe(code = print(g))

In this plot, it appears that the largest number of pills were shipped to counties in California. However, since we did not account for population or population density, this could simply be because it is the most populated state.

To account for this we will perform something called normalization (or in this case we will adjust for differences in population or population density across different states) to make a more fair comparison.

Normalization of number of shipped pills


The term data normalization actually has a variety of meanings.

In some cases, it indicates the process of making data “more normally distributed”, which means that the data is transformed in a such way that when the frequencies of the various data points are plotted, it resembles that of the normal distribution, which looks like a “bell curve”. This may be helpful for performing certain statistical tests that assume that the data is normally distributed.

In other cases, it may mean the process of transforming the data to a common scale so that comparisons can be made fairly.

In our case, we want to compare the number of pills shipped to each county. However, using the raw data results in an unfair comparison as the counties themselves have very different populations. Therefore, if a county has a very large population, we may assume that the large number of pills shipped to that county may indicate that this county received a particularly high amount of opioids, however, it may actually be that this county received far fewer pills per person than a smaller county.

If we divide (or scale) the number of pills shipped to be relative to the number of people in a given county, then we have the number of pills shipped per person. Therefore, the data will be on a similar scale for each county.

This can be extended to evaluating differences between states and rural or urban counties by taking the mean of the normalized pill counts per person for each county within each group.

See here for more information about how this type of normalization is used in Geographic information system (GIS) analyses.

This may be best illustrated with some example data.

Here, we create a tibble for three imaginary counties. Each has a different population but received the same number of pills.

Next, we calculate the number of pills per person by dividing the number of pills shipped to that county by the population of that county.

example_data <- 
  tibble(population = c(10, 50, 100),
         pills = c(100, 100, 100))

example_data %<>% 
  mutate(norm_pills = pills/population)

example_data
# A tibble: 3 x 3
  population pills norm_pills
       <dbl> <dbl>      <dbl>
1         10   100         10
2         50   100          2
3        100   100          1

You can see that on average 10 pills were shipped for each person for the first county.

In the second row, the population is much larger. Despite the same number of pills being shipped to this example county, there were only enough pills shipped for on average 2 per person. In the final row, the population is very large. Only enough pills were shipped to give on average 1 per person.

Note that however, it is likely that only a small portion of the county populations actually received the pills that were shipped to a given county, but this helps us get a sense of the relative amount shipped to each county and likely used by people in the county where the pills were shipped (although this also not certain).

Back to our example: we create a new variable called pop_DOSAGE that is the number of pills shipped per county divided by the population of that county:

Annual %<>%
  mutate(pop_DOSAGE =  DOSAGE_UNIT / population)

glimpse(Annual)
Rows: 26,980
Columns: 18
$ BUYER_COUNTY      <chr> "ABBEVILLE", "ABBEVILLE", "ABBEVILLE", "ABBEVILLE", ~
$ BUYER_STATE       <chr> "SC", "SC", "SC", "SC", "SC", "SC", "SC", "SC", "SC"~
$ year              <fct> 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014~
$ count             <int> 877, 908, 871, 930, 1197, 1327, 1509, 1572, 1558, 58~
$ DOSAGE_UNIT       <dbl> 363620, 402940, 424590, 467230, 539280, 566560, 5890~
$ countyfips        <chr> "45001", "45001", "45001", "45001", "45001", "45001"~
$ STATE             <int> 45, 45, 45, 45, 45, 45, 45, 45, 45, 22, 22, 22, 22, ~
$ COUNTY            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1~
$ county_name       <chr> "Abbeville", "Abbeville", "Abbeville", "Abbeville", ~
$ NAME              <chr> "Abbeville County, South Carolina", "Abbeville Count~
$ variable          <chr> "B01003_001", "B01003_001", "B01003_001", "B01003_00~
$ population        <int> 25821, 25745, 25699, 25347, 25643, 25515, 25387, 252~
$ Areaname          <chr> "Abbeville, SC", "Abbeville, SC", "Abbeville, SC", "~
$ LND110210D        <dbl> 490.48, 490.48, 490.48, 490.48, 490.48, 490.48, 490.~
$ density           <dbl> 52.64435, 52.48940, 52.39561, 51.67795, 52.28144, 52~
$ rural_urban       <chr> "Rural", "Rural", "Rural", "Rural", "Rural", "Rural"~
$ Pills_in_millions <dbl> 0.363620, 0.402940, 0.424590, 0.467230, 0.539280, 0.~
$ pop_DOSAGE        <dbl> 14.08234, 15.65119, 16.52165, 18.43335, 21.03030, 22~

We create a plot of the national county average for this normalized pill count over time.

norm_average <- 
  Annual %>% 
  group_by(year) %>%
  ggplot(aes(x = year, y = pop_DOSAGE)) + 
    stat_summary(fun.data = mean_cl_boot,
                 position = position_dodge(width=0.5)) +
    stat_summary(fun = mean,
                 geom = "line") +
    labs(title = "Average Number of pills shipped per person for a given county",
         y = "Number of pills per capita") +
    theme_minimal()

norm_average

Let’s make a plot comparing this plot with the data on the raw scale using the patchwork package, using a + to combine plots together.

We continue to use the theme() function of the ggplot2 package to remove the previous titles and then use the plot_annotation() function of the patchwork package to add an overall title using the title argument. This function can also be used with the theme argument and then using the ggplot2 theme() function as usual. This will apply changes to all plots that are combined but only regarding to the titles plot margin and background.

raw_average +
    theme(axis.text.x = element_text(angle = 90)) +
norm_average + 
  theme(plot.title = element_blank(), axis.text.x = element_text(angle = 90)) +
  patchwork::plot_annotation(title = "Raw vs Normalized Data")

We can see that the variability of the sample mean is much lower for the normalized data (however this is in part because the scale is different), but we see the same general trend from one year to the next.

This is now also a bit easier to interpret. It is easier to think about 30 vs 50 pills per person as opposed to 10 million pills vs 20 million pills for a given county.

Again let’s take a deeper look at the states and create a combined box plot and jitter plot figure.

Question Opportunity

Do you recall how to do this? How would you combine the previous plot of the raw data with this plot?


Click here to reveal the code.
norm_state_avg <-
  Annual %>% 
  group_by(BUYER_STATE, year) %>%
  summarize(mean_DOSAGE = mean(pop_DOSAGE)) %>% 
  ungroup() %>%
  ggplot(aes(x = year, y = (mean_DOSAGE))) + 
    geom_boxjitter() + 
    labs(title = "Average number of opioid pills shipped to a given county for each state",
         y = "Number of Pills Per Capita")+
    theme_minimal()

norm_state_avg 

together <- 
  raw_state_avg + 
  theme(axis.text.x = element_text(angle = 90)) +
  norm_state_avg + 
  theme(plot.title = element_blank(), 
        axis.text.x = element_text(angle = 90)) +
  plot_annotation(title = "Raw vs Normalized Data")

together

We see a similar spread and the same general trend although the difference from one year to the next appears to be steeper for the normalized data.

Now, let’s see how normalization changes the state specific data.

Question Opportunity

Do you recall how to create the state specific and interactive plot?


Click here to reveal the code.
g2 <- 
  Annual %>% 
  group_by(BUYER_STATE,year) %>%
  summarize(mean_DOSAGE = mean(pop_DOSAGE)) %>% 
  ungroup() %>%
  ggplot(aes(x = year, y = mean_DOSAGE, group = BUYER_STATE,
             color = BUYER_STATE)) +
    geom_line()

g2 <- 
  g2 + geom_point_interactive(aes(color = BUYER_STATE, 
                                  tooltip = usdata::abbr2state(BUYER_STATE)), 
                              size = 2, alpha = 3/10) + 
  theme(legend.position = "none")

girafe(code = print(g2))

This dramatically changed the resulting plot!

We can see that now Tennessee, Kentucky, and West Virginia were among the top to receive pills relative to their populations. California is no longer at the top of the plot.

Rural and Urban Differences


OK, now that we can make fair comparisons between counties, we can now take a look at the differences between rural and urban counties.

To make this plot we will again use the stat_summary() function of the ggplot2 package.

We want to include both the raw data and the normalized data in the same plot.

Recall that we can do this using the facet_wrap() function.


Click here to see how this can be done using facet_wrap()

In this option we use the labeller argument of the facet_wrap() function to change what the strip.text labels will be (which is the text above each plot - the location of which can be changed).

Annual %>% 
  pivot_longer(names_to = "type", 
               values_to  = "value", 
               cols = c(Pills_in_millions, 
                        pop_DOSAGE))%>%
  mutate(type = forcats::fct_inorder(type)) %>%
  ggplot(aes(y = value, x = year, colour = rural_urban, 
             group = rural_urban)) + 
    stat_summary(fun.data = mean_cl_boot,
                 position = position_dodge(width = 0.5),
                 geom = "pointrange") +
    stat_summary(fun = mean, geom = "line") +
    facet_wrap( ~ type, scales = "free", labeller = 
                  as_labeller(c(Pills_in_millions = "Raw Data", 
                                pop_DOSAGE = "Normalized Data (pills per capita)"))) +
    labs(title = "Difference in Opioid Shipments With and Without Normalization",
         y = "Number of Pills", x = NULL)+
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 90),
          legend.title = element_blank())+
    scale_color_manual(values = c("#20A387FF", "#481567FF"))


Or, instead we can continue to use patchwork to combine two different plots. Both options allow for a more flexibility about specifying different aspects of the plot.

In both cases, we use a manual color scheme to color the two groups using the scale_color_manual() function of the ggplot2 package. This function takes a values argument that must be a list of colors that is equal to the number of groups to be colored. Also the element_text(hjust = 0.5) of the theme() function, allows for the titles to be centered.

Raw_Data <- 
  Annual %>% 
  ggplot(aes(y = Pills_in_millions, x = year, colour = rural_urban, 
             group = rural_urban)) + 
    stat_summary(fun.data = mean_cl_boot,
                 position = position_dodge(width = 0.5),
                 geom = "pointrange") +
    stat_summary(fun = mean, geom = "line") +
    labs(title = "Raw Data",
         y = "Number of Pills in millions",
         x = NULL) +
    theme_linedraw() +
    theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
          axis.text.x = element_text(angle = 90),
          axis.text = element_text(size = 10),
          legend.title = element_blank(),
          legend.position = "none") +
    scale_color_manual(values = c("#20A387FF", "#481567FF"))


Norm_Data <- 
  Annual %>%
  ggplot( aes(y = pop_DOSAGE, x = year, colour = rural_urban, 
              group = rural_urban)) + 
    stat_summary(fun.data = mean_cl_boot,
                 position = position_dodge(width = 0.5),
                 geom = "pointrange") +
    stat_summary(fun = mean, geom = "line") +
    labs(title = "Normalized Data",
         y = "Number of Pills Per Capita",
         x = NULL) +
    theme_linedraw() +
    theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
          axis.text.x = element_text(angle = 90),
          axis.text = element_text(size = 10),
          legend.title = element_blank()) +
  scale_color_manual(values = c("#20A387FF", "#481567FF"))

Raw_Data + 
  Norm_Data + 
  plot_annotation(title = "Difference in Opioid Shipments across different types of counties")

We can see that without accounting for population, the urban counties received many more pills than the rural counties. In contrast, when population is taken into account, the rates appear to be very similar.

We can also see that there appears to be much higher variability among the urban counties as compared to the rural counties.

Let’s save our theme() function code as an actual theme to be used for our future plots so that they can be stylized similarly.

theme_county <- function() {
  theme_linedraw() +
  theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
        axis.text.x = element_text(angle = 90),
        axis.text = element_text(size = 10),
        legend.title = element_blank())
}

Now we simply need to type county_theme() instead to achieve the same style for our plot.

Greater granularity of density


Recall that the article that surveyed people who use heroin in the Survey of Key Informants’ Patients Program and the Researchers and Participants Interacting Directly (RAPID) program found that:

A much greater percentage of heroin users completing the survey in the SKIP Program reported currently living in small urban or nonurban areas than in large urban areas (75.2% vs 24.8%) at the time of survey completion.

This survey used self-declared area of current residence (large urban, small urban, suburban, or rural).

Given that we saw a large degree of variability among the urban counties, we will now parse this group further to see if examining counties that were either large urban or smaller (including small urban and rural) seems reasonable.

According to the Organization for Economic Co-operation and Development (OECD):

Urban population by city size is determined by population density and commuting patterns; this better reflects the economic function of cities in addition to their administrative boundaries. Urban areas in OECD countries are classified as: large metropolitan areas if they have a population of 1.5 million or more; metropolitan areas if their population is between 500 000 and 1.5 million; medium-size urban areas if their population is between 200 000 and 500 000; and, small urban areas if their population is between 50 000 and 200 000. This indicator is measured as a percentage of the national population.

Thus we could try a cutoff for small urban populations as less than 200,000. Of note this is not as ideal as having commuting patterns etc, however it is a starting point.

According to the Economic Reserach Service of the US department of Agriculture (USDA):

Population thresholds used to differentiate rural and urban communities range from 2,500 up to 50,000, depending on the definition.

To also use a population threshold to redefine the rural category (to be consistent with our other definitions of large and small urban populations) we will use a cutoff of less than 50,000.

So now we will make a new variable with three categories of counties: large urban vs small urban vs rural.

Thus we will use the & operator to indicate that the small urban category is greater than 50,000 and also less than 200,000.

Annual %<>% 
  mutate(category = case_when(population >= 200000 ~ "Large Urban",
                              population >= 50000 & 
                              population < 200000 ~ "Small Urban",
                              population < 50000 ~ "Rural"))

Let’s take a look at this with our formatted table and plots as before.

Question Opportunity

Do you recall how we might do this?

Click here to reveal the code.
R_U <-Annual%>% 
  group_by(year) %>%
  count(category) %>%
  tidyr::pivot_wider(names_from = category,
                     values_from = n) %>%
  ungroup() %>% 
  mutate("Rural Change" = Rural - lag(Rural), 
         "Small Urban Change" = `Small Urban` - lag(`Small Urban`),
         "Large Urban Change" = `Large Urban` - lag(`Large Urban`),
        "Percent Large Urban" = 
  round((`Large Urban`/(`Large Urban` + `Small Urban` + Rural))*100, digits = 2)) %>%
  rename("Year" = "year")

R_U
# A tibble: 9 x 8
  Year  `Large Urban` Rural `Small Urban` `Rural Change` `Small Urban Change`
  <fct>         <int> <int>         <int>          <int>                <int>
1 2006            294  2049           661             NA                   NA
2 2007            299  2038           661            -11                    0
3 2008            303  2022           666            -16                    5
4 2009            300  2039           653             17                  -13
5 2010            302  2024           665            -15                   12
6 2011            306  2027           666              3                    1
7 2012            312  2030           662              3                   -4
8 2013            312  2022           666             -8                    4
9 2014            316  2020           665             -2                   -1
# ... with 2 more variables: `Large Urban Change` <int>,
#   `Percent Large Urban` <dbl>
table_cat <- formattable::formattable(R_U, list(`Percent Large Urban` = 
                                     formattable::color_bar("#FA614B")))
table_cat
Year Large Urban Rural Small Urban Rural Change Small Urban Change Large Urban Change Percent Large Urban
2006 294 2049 661 NA NA NA 9.79
2007 299 2038 661 -11 0 5 9.97
2008 303 2022 666 -16 5 4 10.13
2009 300 2039 653 17 -13 -3 10.03
2010 302 2024 665 -15 12 2 10.10
2011 306 2027 666 3 1 4 10.20
2012 312 2030 662 3 -4 6 10.39
2013 312 2022 666 -8 4 0 10.40
2014 316 2020 665 -2 -1 4 10.53

This time when we create our plot we will add labels directly to the lines of our plot using the directlabels package.

To do this we will use the direct.label() function. This requires a list of arguments. The dl.trans() function modifies the location of all labels, while the dl.move() function can move a specific label to a specified location. Method options are shown here. See this case study and this case study for more details.

plot_cat_raw <-Annual %>%
ggplot( aes(y = Pills_in_millions, x = year, colour = category, group = category)) + 
  stat_summary(fun.data = mean_cl_boot,
             position=position_dodge(width=0.5)) +
  stat_summary(fun = mean,
                geom = "line") +
  labs(title = "Raw Data",
          y = "Pills in millions",
          x = NULL)+
  theme_county()+
  theme(strip.text = element_text(size = 14, face = "bold"))+
  scale_color_manual(values = c("#481567FF", "#20A387FF", "#453781FF"))

 plot_cat_raw<- directlabels::direct.label(plot_cat_raw, 
                                           method = list(dl.trans(y = y +0.5),
                                                     "far.from.others.borders",
                                                     fontface = 'bold'))
  
  plot_cat_norm <-Annual %>%
ggplot( aes(y = pop_DOSAGE, x = year, colour = category, group = category)) + 
  stat_summary(fun.data = mean_cl_boot,
             position=position_dodge(width=0.5)) +
  stat_summary(fun = mean,
                geom = "line") +
  labs(title = "Normalized Data",
          y = "Number of Pills Per Capita",
           x = NULL)+
  theme_county()+
  theme(strip.text = element_text(size = 14, face = "bold"))+
  scale_color_manual(values = c("#481567FF", "#20A387FF", "#453781FF"))

 plot_cat_norm<- direct.label(plot_cat_norm, method = list(dl.trans(y = y +0.5),
                                                     "far.from.others.borders",
                                                     fontface = 'bold'))
 
 plot_cat_raw + plot_cat_norm + plot_annotation(title = "Difference in opioid pill shipments between types of counties",
       subtitle = "Oxycodone and Hydrocodone pills in the US",)

Wow, we can see here that the two urban categories actually have larger differences in normalized pill counts from each other than either has with the rural counties!

Thus it seems reasonable to lump the rural and small urban categories together, rather than grouping large urban and small urban as we were doing.

We will modify our original code with the population thresholds which was:

Annual %<>% 
  mutate(category = case_when(population >= 200000 ~ "Large Urban",
                              population >= 50000 & 
                              population < 200000 ~ "Small Urban",
                              population < 50000 ~ "Rural"))

Now we will just replace the labels for the small urban and rural counties to be the same value “Small Urban or Rural” for this new variable called “large_urban”:

Annual %<>% 
  mutate(large_urban = case_when(population >= 200000 ~ "Large Urban",
                                 population >= 50000 & 
                                 population < 200000 ~ "Small Urban or Rural",
                                 population < 50000 ~ "Small Urban or Rural"))
plot_2cat_raw <-Annual %>%
ggplot( aes(y = Pills_in_millions, x = year, 
            colour = large_urban, group = large_urban)) + 
  stat_summary(fun.data = mean_cl_boot,
             position=position_dodge(width=0.5)) +
  stat_summary(fun = mean,
              geom = "line") +
  labs(title = "Raw Data",
           y = "Pills in Millions",
           x = NULL)+
  theme_county()+
scale_color_manual(values = c("#481567FF", "#20A387FF"))

plot_2cat_raw <-direct.label(plot_2cat_raw, method = list(dl.trans(y = y +.6),
                                                     "far.from.others.borders",
                                                     fontface = 'bold',
                                                    cex = 0.8))

plot_2cat_norm<-Annual %>%
ggplot( aes(y = pop_DOSAGE, x = year, 
            colour = large_urban, group = large_urban)) + 
  stat_summary(fun.data = mean_cl_boot,
             position=position_dodge(width=0.5)) +
  stat_summary(fun = mean,
              geom = "line") +
  labs(title = "Normalized Data",
           y = "Pills Per Capita",
           x = NULL)+
  theme_county()+
scale_color_manual(values = c("#481567FF", "#20A387FF"))

plot_2cat_norm <-direct.label(plot_2cat_norm, method = list(dl.trans(y = y +.6),
                                                     "far.from.others.borders",
                                                     fontface = 'bold',
                                                      cex = 0.8))


plot_2cat_raw +plot_2cat_norm + plot_annotation(
  title = "Difference in opioid pill shipments between types of counties",
       subtitle = "Oxycodone and Hydrocodone pills in the US")

Indeed when we evaluate the data in this way, we see that small urban and rural counties received higher numbers of pills per person than large urban counties.

Data Analysis


If you have been following along but stopped, we could load our wrangled data from the “data” directory like so:

load(file = here::here("data", "wrangled", "Annual_opioid_data.rda"))
load(file = here::here("data", "wrangled", "county_info.rda"))

If you skipped the previous sections click here.

First you need to install the OCSdata package:

install.packages("OCSdata")
library(OCSdata)

Then, you may download and load the wrangled data into your R environment using the following code:

wrangled_rda("ocs-bp-opioid-rural-urban", outpath = getwd())
load(file = here::here("OCSdata", "data", "wrangled", "Annual_opioid_data.rda"))
load(file = here::here("OCSdata", "data", "wrangled", "county_info.rda"))

If the package does not work for you, alternatively, the RDA files (stands for R data) of the data can be found in our GitHub repository. Download these files and then place them in your current working directory within a subdirectory called “wrangled” within a subdirectory called “data” to copy and paste our code. We used an RStudio project and the here package to navigate to the files more easily.

load(file = here::here("data", "wrangled", "Annual_opioid_data.rda"))
load(file = here::here("data", "wrangled", "county_info.rda"))

Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



If you are starting here, we will also perform a few extra steps with the data that we did during the visualization section:

# We create a new variable called `pop_DOSAGE` that is the number of pills shipped per county divided by the population of that county
Annual%<>%  mutate(pop_DOSAGE =  DOSAGE_UNIT / population)


# we create a new variable called `Pills_in_millions` that is the number of pills shiped per county divided by 1 million
Annual %<>% 
  mutate(Pills_in_millions = DOSAGE_UNIT/1000000)

#We make a new variable based on being either large urban or small urban/rural based off a threshold of population because of our visualizations
Annual %<>% 
  mutate(large_urban = case_when(population >= 200000 ~ "Large Urban",
                                 population >= 50000 & 
                                 population < 200000 ~ "Small Urban or Rural",
                                 population < 50000 ~ "Small Urban or Rural"))

Student’s t-test


OK, we can tell that there appears to be a difference between small urban and rural counties compared to large urban counties by looking at this plot, however is the difference between these two categories of counties meaningful, or is it just due to random differences from sampling? To evaluate this we may consider employing a statistical test called the Student’s \(t\)-test, which can be used to determine if two group means are different.

Let’s remind ourselves of one of our original questions,

Has there been a difference between opioid pill shipments to rural and urban counties in the US?

In hypothesis testing, we are interested in comparing two different hypotheses: a “null” hypothesis (can be thought of like a baseline e.g. the means between two groups are the same, or there is a difference of 0 between the means of the two groups) compared to an “alternative” hypothesis (e.g. the means between two groups are different). We are going to ask if there is enough evidence in our data to reject the null hypothesis.

Let’s try to formalize this a bit.

Using Student’s t-test, we can test whether the mean number of pills shipped to the rural counties is the same as the mean number of pills shipped to the urban areas. If we call the true unknown population means of the two groups \(\mu_U\) and \(\mu_R\), for the urban and rural areas, respectively, then we can define the null hypothesis that there is no difference in the two means:

\[ H_0: \mu_U = \mu_R \]

In contrast, we also define an alternative hypothesis that there is a difference between the mean number of pills shipped to each type of county:

\[ H_a: \mu_U \neq \mu_R \]

The idea behind a hypothesis test is that we assume the null hypothesis is true and we use our data to help us identify if there is enough evidence to reject the null hypothesis.

This is similar to the idea of assuming that individuals are not guilty until proven otherwise. If there is not enough evidence in the data, then we say we “fail to reject the null hypothesis”.

However, performing this test depends on certain assumptions about our data:

  1. The data for each group is normally distributed.
  2. The variance of both groups is similar.
  3. The observations from the two groups are independent (meaning that observations do not influence each other).
  4. The observations within each group are independent (meaning that observations do not influence each other).

We will start by showing you a tool to assess whether the first assumption seems to be true in our data. We can observe visually whether each group to be tested appears to be normally distributed by making what is called a “quantile-quantile” plot (or Q-Q plot for short). When we talk about a quantile, we are talking about dividing up the distribution of the data into equal portions where roughly the same number of observations fall into each portion. For example, if you divide your data into 100 quantiles, you can think about this as percentiles, but you could also divide your data into 10 quantiles and these would be called deciles.

If our data are normally distributed, then the quantiles of our data points should in some way match the quantiles of a certain normal distribution. A Q-Q plot can allow us to see visually whether this seems to be the case.

Why Q-Q plots? Q-Q plots allow us to compare the quantiles of two distributions to one another. For example, we may want to compare (1) quantiles of a known theoretical distribution (like the normal distribution) to (2) quantiles of the distribution of our data. If the quantiles from these two distributions line up in the plot, then that is a visual piece of evidence that our data have a distribution that is similar to that theoretical distribution (like the normal distribution).

How does this work? To do this we will plot the quantiles of our data on the y-axis and the quantiles of the theoretical normal distribution on the x-axis. If the quantiles line up then we can say that our data is fairly normal. See here for more information about Q-Q plots.

Using the stat_qq() function of the ggplot2 package, we can easily create a Q-Q plot for quantiles from our data (“sample”) and compare it to the quantiles from a normal distribution, i.e. using data randomly sampled from a normal distribution (“theoretical”). The default comparison distribution for these functions is the normal distribution, so we don’t need to specify it in our code. Here, we will look at both pop_DOSAGE and DOSAGE_UNIT values from both types of our urban/rural categorization, and see what their distributions look like.

Annual %>% pivot_longer(names_to = "type", values_to = "value", cols = c(pop_DOSAGE, DOSAGE_UNIT)) %>%
  ggplot(aes(sample = value)) +
  stat_qq() + 
  stat_qq_line() +
  facet_wrap(~large_urban + type, scales = "free")

Annual %>% pivot_longer(names_to = "type", values_to = "value", cols = c(pop_DOSAGE, DOSAGE_UNIT)) %>%
  ggplot(aes(sample = value)) +
  stat_qq() + 
  stat_qq_line() +
  facet_wrap(~rural_urban + type, scales = "free")

The stat_qq_line() function is used to add a line (with a particular slope and intercept) to the plot. If the points lie on this straight line, this is evidence that the data have some normal distribution, not that the data have a particular normal distribution.

OK, we can see that in all cases the points appear to deviate from the line for at least one group, indicating that the quantiles are fairly dissimilar between the observed and theoretical data.

Sometimes using a data transformation, like the log transformation, can help make our sample data look more normal. So we can see if we can overcome this observed deviation from normality by transforming the data, taking the log (base \(e\)) of the number of pills or the normalized number of pills.

Annual %>% pivot_longer(names_to = "type", values_to = "value", cols = c(pop_DOSAGE, DOSAGE_UNIT)) %>%
  ggplot(aes(sample = log(value))) +
  stat_qq() + 
  stat_qq_line() +
  facet_wrap(~large_urban + type, scales = "free")

Annual %>% pivot_longer(names_to = "type", values_to = "value", cols = c(pop_DOSAGE, DOSAGE_UNIT)) %>%
  ggplot(aes(sample = log(value))) +
  stat_qq() + 
  stat_qq_line() +
  facet_wrap(~rural_urban + type, scales = "free")

OK, this did not help very much; we can still see large deviations of the points from the lines. So now we have two options. One is that we can continue with the Student’s \(t\)-test because this test is fairly robust to violations of the normality assumption if the sample size is relatively large, due to what is called the central limit theorem, which states that as samples get larger, the sample mean has an approximate normal distribution. Since we are trying to make inference about the population mean by using our sample mean, as long as the sample mean has a normal distribution, it is OK that our data themselves are not normal.

Annual %>%
  count(large_urban)
# A tibble: 2 x 2
  large_urban              n
  <chr>                <int>
1 Large Urban           2744
2 Small Urban or Rural 24236
Annual %>%
   count(rural_urban)
# A tibble: 2 x 2
  rural_urban     n
  <chr>       <int>
1 Rural       24815
2 Urban        2165

Our samples are indeed quite large, thus it would probably be reasonable to continue with the \(t\)-test.

However, our second option is to perform a test called the Mann Whitney U test also known as the Wilcoxon rank sum test or the two-sample Wilcox test or the Mann–Whitney–Wilcoxon (MWW) test. Importantly, this test does not rely on the assumption that the data are normally distributed and it is more robust than the t-test to outliers (extreme values compared to the others). Given that the data appears to be quite different from the normal distribution, we will proceed using this test.

Mann–Whitney–Wilcoxon (MWW) test (Wilcox test for short)


In this test, the hypothesis is slightly different. Instead of comparing means, this test evaluates the following null hypothesis for comparing the two groups (adapted from Wikipedia):

the probability that a randomly selected value of the first group (X) is greater than a randomly selected value of the second group (Y) is equal to the probability that a randomly selected value of the second group (Y) is greater than a randomly selected value of the first group (X).

The alternative hypothesis would then be that these probabilities are not equal, i.e., random values of one group are more likely to be larger than random values from the other group.

We can also use what is called a one-sided alternative to test that random values of X are more likely to be greater than random values of Y or that random values of X are less likely to be greater than random values Y, if we are interested in a particular direction of comparison, as we might be here (i.e., we could ask the more specific question of whether opioid shipment rates are higher for rural compared to urban counties).

Another way of describing this null hypothesis is that the distributions of the probabilities of the occurrences of the possible values of X and Y are equal or have a shift of 0. Whereas, the alternative would be that the shift between the probability distributions is not zero. Similarly, the one-sided alternatives are either that the shift in probability distributions is greater than zero or that it is less than zero.

Here you can see an illustration of the null hypothesis on the left and a one-sided alternative hypothesis on the right:

[source]

So in our case, using the Wilcox test, we can test the null hypothesis that the following two probabilities are the same: (1) the probability that a random county categorized as rural has a larger number of pills shipped than a random county categorized as urban and (2) the probability that a random county categorized as urban has a larger number of pills shipped than a random county categorized as rural (or similarly comparing small urban and rural counties to large urban counties).

If we call the random counties \(U\) and \(R\), for the urban and rural areas, respectively, then we can define the null hypothesis that there is no difference in the probabilities \(P\):

\[ H_0: P(U > R) = P(R>U) \]

In contrast, we also define an alternative hypothesis that there is a difference (two-sided):

\[ H_a: P(U > R) \neq P(R>U)\]

With a one-sided alternative that a larger number of pills are shipped per person to rural counties as:

\[ H_a: P(R>U) > P(U > R) \] Here the probability that a random rural county had a larger number of pills shipped than a random urban county is greater than the probability that a random urban county had a larger number of pills shipped than a random rural county.

We can extend this to the small urban/rural vs the large rural county comparison.

To implement this test in R we will use the wilcox.test() function in the stats package. This function always orders the groups in alphabetical order: X is automatically the group that comes first alphabetically, while Y is the group that comes second alphabetically.

Thus for the rural_urban variable, the **R**ural values would be the X group, while the **U**rban would be the Y group, as R comes before U in the alphabet.

For the large_urban variable, the **L**arge Urban group values would be the X group, while the **S**mall Urban or Rural values would be the Y group.

The test statistic for the Wilcoxon test, \(W\), is actually quite simple to calculate manually with small sample sizes.


Click here to see how \(W\) is calculated manually

Let’s say that the US only had 3 counties that were rural and 3 counties that were urban and we wanted to compare the distributions using this test.

The number of pills shipped to each of the 3 rural counties was:
1) 10
2) 50
3) 30

The number of pills shipped to each of the 3 urban counties was:
1) 20
2) 25
3) 12

We can calculate our Wilcoxon test statistic in two ways: either using the sum of the ranks of the ordered values from the two groups combined, or the number of “wins” in for each group in all pairwise comparisons of values from the two groups. While this is not obvious, it turns out that these two methods will give the same results.

Using the rank-sum method, the first step is to list the counties in order of the number of pills shipped, labeling them with their group membership. We will use “R” or “U” if the number came from a rural or urban county:

County: R U U U R R
pills: 10 12 20 25 30 40
rank: 1 2 3 4 5 6

sum of ranks \((R_1)\) for R: \(1+ 5 +6 = 12\)
sum of ranks \((R_2)\) for U: \(2+3+4 = 9\)

Now two \(W\) statistics are calculated, one for each group like so (where \(n\) is the sample size for that group):

\[W_1 = R_1-\frac{n_1(n_1+1)}{2}\]

\[W_2 = R_2-\frac{n_2(n_2+1)}{2}\]

Using our example data:

\(W_1\) is for rural counties
\(W_1 = R_1-\frac{n_1(n_1+1)}{2}\)
\(W_1 = 12 -(3(4)/2) = 12-6 = 6\)

\(W_2\) = U for urban counties
\(W_2 = R_2-\frac{n_2(n_2+1)}{2}\)
\(W_2 = 9-(3(4)/2) = 9-6 = 3\)

We now want to use these two values to get one overall test statistic for our hypothesis test. It turns out that this test statistic can be defined in different ways. Often \(W\) is defined as follows:

\(W = min(W_1, W_2) = 3\). However, R takes the value \(W_1\) or \(W_2\) for \(W\) depending on what sample is listed first. Thus for this data set, the R output will give the value \(W_1\) for the test statistic in this case.

In our case the first group (rural counties) had a \(W\) of 6.

From the documentation for the stats package for the wilcox.text() function:

R’s value can also be computed as the number of all pairs (x[i], y[j]) for which y[j] is not greater than x[i], the most common definition of the Mann-Whitney test.

If you are familiar with linear algebra, we can calculate this value in a clever way in R by getting all the pairwise comparisons of values between the two groups using the outer() base function and using the > (instead of the product or * function as this is typically used by default to get the outer product) to determine how often the rural counties have a greater value than the urban counties.

example <-tibble(pills = c(10,12, 20, 25,30, 40), county = c("R", "U", "U", "U", "R", "R"))
example
# A tibble: 6 x 2
  pills county
  <dbl> <chr> 
1    10 R     
2    12 U     
3    20 U     
4    25 U     
5    30 R     
6    40 R     
R = c(10,30, 40)
U = c(12, 20, 25)

outer(R,U, ">")
      [,1]  [,2]  [,3]
[1,] FALSE FALSE FALSE
[2,]  TRUE  TRUE  TRUE
[3,]  TRUE  TRUE  TRUE
# 10 is less than 12, 20, and 25 (R is always less than U for all 3 comparisons)
# 30 is greater than 12, 20, and 25 (3 times that R is greater than U)
# 40 is greather than 12, 20, and 25 ( 3 tiems that R is greater than U)

# 3+3 = 6 pairs out of 9 where R was greater than U thus W is equal to 6

sum(outer(R,U, ">"))
[1] 6
wilcox.test(data = example,  paired = FALSE,  alternative = "greater", pills~ county)

    Wilcoxon rank sum exact test

data:  pills by county
W = 6, p-value = 0.35
alternative hypothesis: true location shift is greater than 0

We can also see that if we switch the order of our counties (i.e., we make the values that were for urban now the values for rural) we then get the \(W\) for what was previously our second group in the result. (Remember whatever is alphabetically first will be the first group - so again the results are for “R”.)

example <-tibble(pills = c(10,12, 20, 25,30, 40), county = c("U", "R", "R", "R", "U", "U"))
example
# A tibble: 6 x 2
  pills county
  <dbl> <chr> 
1    10 U     
2    12 R     
3    20 R     
4    25 R     
5    30 U     
6    40 U     
wilcox.test(data = example,  paired = FALSE,  alternative = "greater", pills~ county)

    Wilcoxon rank sum exact test

data:  pills by county
W = 3, p-value = 0.8
alternative hypothesis: true location shift is greater than 0

For small samples, the statistic \(W\) can then be compared to a critical \(W\) table (note here that what we refer to as \(W\) is called \(U\) in the table) to determine significance. If \(W\) is lower than the critical value, it suggests that the null hypothesis should be rejected. From this table we see that our example has so few values that the null can’t be reliably rejected.

For larger samples (like our actual data, or in general at least 20 per group) the \(W\) statistic is instead used to calculate a \(Z\) statistic like so:

\[Z = \frac{W-\mu_W}{\sigma_W}\]

Where \(\mu_W\) is the expected \(W\) if the two groups have identical distributions and \(\sigma_W\) is the standard deviation.

They are calculated as follows:

\[\mu_W = \frac{n_1n_2}{2}\]

\[\sigma_W = \sqrt{\frac{n_1n_2(n_1+n_2+1)}{12}}\] This can then be used in a \(Z\) table or using a calculator to determine a \(p\)-value.

Here is also a link to a video for a more detailed explanation about calculating this by hand.


Now, to implement this test in R we can use the wilcox.test() function of the stats package.

We need to specify that we want to look for differences of normalized pill counts (pop_DOSAGE) between the rural_urban groups. We can do so by using the ~ to indicate the dependent variable on the left and the independent variable on the right. We assume that the number of normalized pills depends on the county group, thus the normalized pill count is the dependent variable. Our data are not paired, thus we use the paried = FALSE argument. We would have paired data for example in the case where we had comparable rural and urban counties for every state, but that is not the case. See this case study for an example of the paired version of this test. We will use thealternative = argument to specify that we expect the first of the groups by alphabet (which would would be Rural of the rural_urban variable) to have greater values than the Urban group by setting it to “greater”. Thus we will also use the alternative = "less" argument for the large_urban group comparison as we expect the first group (alphabetically) Large Urban to have smaller values than the Small Urban or Rural group.

wilcox.test(pop_DOSAGE ~ rural_urban, data = Annual,
                                    paired = FALSE, 
                               alternative = "greater", 
                                  conf.int = TRUE,
                                  estimate = TRUE)

    Wilcoxon rank sum test with continuity correction

data:  pop_DOSAGE by rural_urban
W = 27731707, p-value = 0.00618
alternative hypothesis: true location shift is greater than 0
95 percent confidence interval:
 0.3459493       Inf
sample estimates:
difference in location 
               1.00955 
wilcox.test(pop_DOSAGE ~ large_urban, data = Annual, 
                                    paired = FALSE, 
                               alternative = "less", 
                                  conf.int = TRUE,
                                  estimate = TRUE)

    Wilcoxon rank sum test with continuity correction

data:  pop_DOSAGE by large_urban
W = 31010485, p-value = 3.393e-09
alternative hypothesis: true location shift is less than 0
95 percent confidence interval:
      -Inf -1.429283
sample estimates:
difference in location 
             -1.999459 

Both results have \(p\) values that are less than 0.05, which is the threshold commonly used in hypothesis testing to determine if there is enough evidence to reject the null hypothesis.

In both cases this indicates that indeed there is enough evidence, and we can reject the null hypothesis. Furthermore, the confidence interval does not overlap zero for either test, suggesting that the Rural group is larger for the first test (as both confidence interval limits are positive) and that the Large Rural group is smaller for the second test (as both confidence interval limits are negative).

For the second test, the absolute value of the difference estimate is larger than that of the first test suggesting that there is a larger difference between the Large Urban and Small Urban or Rural groups than the Rural and Urban groups.

If we had not normalized the data, what would our results look like?

wilcox.test(DOSAGE_UNIT ~ rural_urban, data = Annual,
                                    paired = FALSE, 
                               alternative = "greater", 
                                  conf.int = TRUE,
                                  estimate = TRUE)

    Wilcoxon rank sum test with continuity correction

data:  DOSAGE_UNIT by rural_urban
W = 4153441, p-value = 1
alternative hypothesis: true location shift is greater than 0
95 percent confidence interval:
 -12298340       Inf
sample estimates:
difference in location 
             -11884730 
wilcox.test(DOSAGE_UNIT ~ large_urban, data = Annual, 
                                    paired = FALSE, 
                               alternative = "less", 
                                  conf.int = TRUE,
                                  estimate = TRUE)

    Wilcoxon rank sum test with continuity correction

data:  DOSAGE_UNIT by large_urban
W = 65792795, p-value = 1
alternative hypothesis: true location shift is less than 0
95 percent confidence interval:
     -Inf 13268551
sample estimates:
difference in location 
              13013868 

Using the raw data, we see that there is no difference between the rural and urban categories, and the rural data actually show lower values than the urban (based on the sign of the estimated difference). Similarly, there is no difference between small urban and rural counties vs. large urban counties. In this case the large urban counties (the first group alphabetically) also had larger values (based on the sign of the estimated difference).

Notice that in both of these tests the confidence interval overlaps zero, while this is not the case for the previous tests. When the confidence interval overlaps zero that indicates that there is the possibility that the two populations have in fact no difference.

The main conclusion here is that we can see very different results depending on how we define the data and how we normalize the data!

Summary


Summary Plot


Now, let’s create a plot that summarizes our main findings.

We will use some of our plots from the Data Visualization section, including Raw_Data, Norm_Data and plot_cat_norm, and create a multi-panel figure, where each plot is connected to the next with an arrow.

To make these arrow connectors, we will create a plot that is just a single arrow using geom_segment() function of ggplot2. We are doing this because we want to create a layout where the different panels are joined by arrows.

Creating this arrow requires the following arguments : 1) x: x coordinate of starting point of the arrow 2) y: y coordinate of starting point of the arrow 3) xend: x coordinate of end point of the arrow 4) yend: y coordinate of end point if the arrow

(Note: You can make a straight arrow using geom_curve() with the same arguments.)

Also, since ggplot requires a data input, we will create a dummy data.frame to create the y axis value for the arrow. We will use the aes() function to define the length and location of the arrow.

We need to use the arrow argument with the arrow() function to create an arrow. The lineend and linejoin arguments specify what styles to use. The size() function specifies how thick the arrow is displayed.

See here for different arrow style options.

Then we will use the xlim() function of the ggplot2 package to specify the overall size of the plot relative to the arrow.

arrow_df <- data.frame( y = 1)
arrow_df
  y
1 1
arrowplot<-ggplot(arrow_df, aes(x = .5, y = 1, xend = .7, yend = 1)) +
                geom_segment(arrow = arrow(),
                           lineend = "butt",
                          linejoin = "mitre",
                              size = 3)+
                xlim(0.5, 0.75)

arrowplot

Then we will use theme_void() remove the background.

arrowplot <- arrowplot +  theme_void()
arrowplot

We can move the legend to the plot area using the legend.justification and legend.position arguments of the theme() function. The relative position on the plot area needs to be specified like so c(x,y). Thus c(0.7,0.2) is about 70% across the x axis from right to left and about 20% up from the x axis.

Finally, we can build our three panel plot with the arrow connectors as follows:

main_plot <- Raw_Data  + 
  theme(legend.justification = c(0.7,0.2),
             legend.position = c(0.7,.2)) +
             arrowplot +
             Norm_Data +
  theme(legend.justification = c(0.7,0.1),
             legend.position = c(0.7,.1)) +
             arrowplot +
             plot_cat_norm + 
  labs(title = "Normalized &\nStratified Data") + 
  plot_layout( nrow = 1, widths = c(5,1.3,5,1.3,5))+
 #theme(title = element_text(hjust = 0.5)) +
  plot_annotation(title = "Opioid pill shipments to different types of counties in the US", subtitle = "How we normalize opioid (oxycodone and hydrocone) pill shipment data and how we stratify by different \ntypes of counties can yield very different pictures about shipments") &
  theme(plot.title = element_text(size = 18, face = "bold" ),
        plot.subtitle = element_text(size = 14))

Now we can see the steps that we went through, from our raw data through to our normalized an stratified data, and how our choices impacted the apparent relationship between county classification and number of pills.

png 
  2 

Synopsis


In this case study we evaluated the number of oxycodone and hydrocodone pills shipped to pharmacies and practitioners at the county-level around the United States (US) from 2006 to 2014. This data comes form the Automated Reports and Consolidated Ordering System (ARCOS) of the DEA and was released by the Washington Post. We compared counties based on the level of urbanicity using the fact that previous research suggests that regions of the country that are more rural may have communities that were more vulnerable to opioid abuse than those of large urban areas due to likely higher prescription rates for opioid pills in the time period that we evaluated.

Our results also suggest that this is the case, as we identified higher numbers of opioid pill shipments to counties that were more rural and less urban. However we learned that how regions are defined and how the data are normalized can have a great impact on the results of such comparisons. Furthermore, other factors may be involved in creating a situation that may leave members of communities more vulnerable to drug abuse and addiction, such as socioeconomic factors. Further research is necessary to better understand why the opioid crisis became such a problem in the US and particularly to better understand what current populations are particularly vulnerable and why.

Suggested Homework


Students could focus on the counties of a particular state and perform the same analyses and visualizations to see how the different types of counties compared for opioid pill shipments. Students could be asked to work on different states. Discussion could follow about how and why the states show different results.

Additional Information


Note: Monthly data is also available within the data directory. This could be used for time series analysis.

Session Info


sessionInfo()
R version 4.1.2 (2021-11-01)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19044)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] OCSdata_1.0.2             usdata_0.2.0             
 [3] directlabels_2021.1.13    patchwork_1.1.1          
 [5] ggiraph_0.8.2             ggpol_0.0.7              
 [7] Hmisc_4.6-0               Formula_1.2-4            
 [9] survival_3.2-13           lattice_0.20-45          
[11] forcats_0.5.1             formattable_0.2.1        
[13] ggplot2_3.3.5             naniar_0.6.1             
[15] tidyr_1.1.4               dplyr_1.0.7              
[17] stringr_1.4.0             jsonlite_1.8.0           
[19] httr_1.4.2                tibble_3.1.6             
[21] readxl_1.3.1              koRpus.lang.en_0.1-4     
[23] koRpus_0.13-8             sylly_0.1-6              
[25] read.so_0.1.1             wordcountaddin_0.3.0.9000
[27] magrittr_2.0.2            readr_2.1.1              
[29] knitr_1.37                here_1.0.1               

loaded via a namespace (and not attached):
 [1] nlme_3.1-153        fs_1.5.2            usethis_2.1.5      
 [4] RColorBrewer_1.1-2  rprojroot_2.0.2     tools_4.1.2        
 [7] backports_1.4.1     bslib_0.3.1         utf8_1.2.2         
[10] R6_2.5.1            rpart_4.1-15        mgcv_1.8-38        
[13] DBI_1.1.2           colorspace_2.0-2    nnet_7.3-16        
[16] withr_2.5.0         tidyselect_1.1.2    gridExtra_2.3      
[19] curl_4.3.2          compiler_4.1.2      cli_3.2.0          
[22] htmlTable_2.4.0     labeling_0.4.2      sass_0.4.0         
[25] scales_1.1.1        checkmate_2.0.0     quadprog_1.5-8     
[28] systemfonts_1.0.4   digest_0.6.29       foreign_0.8-81     
[31] rmarkdown_2.11      base64enc_0.1-3     jpeg_0.1-9         
[34] pkgconfig_2.0.3     htmltools_0.5.2     fastmap_1.1.0      
[37] highr_0.9           htmlwidgets_1.5.4   rlang_1.0.1        
[40] rstudioapi_0.13     farver_2.1.0        jquerylib_0.1.4    
[43] generics_0.1.1      Matrix_1.3-4        Rcpp_1.0.8         
[46] munsell_0.5.0       fansi_1.0.2         lifecycle_1.0.1    
[49] visdat_0.5.3        stringi_1.7.6       yaml_2.3.5         
[52] plyr_1.8.6          grid_4.1.2          crayon_1.5.0       
[55] splines_4.1.2       hms_1.1.1           pillar_1.7.0       
[58] uuid_1.0-3          glue_1.6.1          evaluate_0.15      
[61] latticeExtra_0.6-29 data.table_1.14.2   remotes_2.4.2      
[64] png_0.1-7           vctrs_0.3.8         tzdb_0.2.0         
[67] cellranger_1.1.0    gtable_0.3.0        purrr_0.3.4        
[70] assertthat_0.2.1    xfun_0.29           sylly.en_0.1-3     
[73] cluster_2.1.2       ellipsis_0.3.2     

Estimate of RMarkdown Compilation Time:

About 103 - 113 seconds

This compilation time was measured on a PC machine operating on Windows 10. This range should only be used as an estimate as compilation time will vary with different machines and operating systems.

Acknowledgments


We would like to acknowledge Brendan Saloner for assisting in framing the major direction of the case study.

We would like to acknowledge Michael Breshock for his contributions to this case study and developing the OCSdata package.

We would also like to acknowledge the Bloomberg American Health Initiative for funding this work.

LS0tDQp0aXRsZTogIk9wZW4gQ2FzZSBTdHVkaWVzOiBPcGlvaWRzIGluIFVuaXRlZCBTdGF0ZXMiDQpjc3M6IHN0eWxlLmNzcw0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGluY2x1ZGVzOg0KICAgICAgaW5faGVhZGVyOiBHQV9TY3JpcHQuUmh0bWwNCiAgICBzZWxmX2NvbnRhaW5lZDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogY29zbW8NCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICB3b3JkX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQoNCi0tLQ0KDQoNCg0KPHN0eWxlPg0KI1RPQyB7DQogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL2ltZy9pY29uLWJhaGkucG5nIik7DQogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsNCiAgcGFkZGluZy10b3A6IDI0MHB4ICFpbXBvcnRhbnQ7DQogIGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7DQp9DQo8L3N0eWxlPg0KDQoNCjwhLS0gT3BlbiBhbGwgbGlua3MgaW4gbmV3IHRhYi0tPiAgDQo8YmFzZSB0YXJnZXQ9Il9ibGFuayIvPiAgDQo8ZGl2IGlkPSJnb29nbGVfdHJhbnNsYXRlX2VsZW1lbnQiPjwvZGl2Pg0KDQo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPScvL3RyYW5zbGF0ZS5nb29nbGUuY29tL3RyYW5zbGF0ZV9hL2VsZW1lbnQuanM/Y2I9Z29vZ2xlVHJhbnNsYXRlRWxlbWVudEluaXQnPjwvc2NyaXB0Pg0KDQo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+DQpmdW5jdGlvbiBnb29nbGVUcmFuc2xhdGVFbGVtZW50SW5pdCgpIHsNCiAgbmV3IGdvb2dsZS50cmFuc2xhdGUuVHJhbnNsYXRlRWxlbWVudCh7cGFnZUxhbmd1YWdlOiAnZW4nfSwgJ2dvb2dsZV90cmFuc2xhdGVfZWxlbWVudCcpOw0KfQ0KPC9zY3JpcHQ+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIsIG91dC53aWR0aCA9ICc5MCUnKQ0KbGlicmFyeShoZXJlKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImJlbm1hcndpY2svd29yZGNvdW50YWRkaW4iLCB0eXBlID0gInNvdXJjZSIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQpyZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiYWxpc3RhaXJlNDcvcmVhZC5zbyIpDQpsaWJyYXJ5KHdvcmRjb3VudGFkZGluKQ0KbGlicmFyeShyZWFkLnNvKQ0KDQpybWFya2Rvd246OjpwZXJmX3RpbWVyX3Jlc2V0X2FsbCgpDQpybWFya2Rvd246OjpwZXJmX3RpbWVyX3N0YXJ0KCJyZW5kZXIiKQ0KYGBgDQoNCiMjIyMgey5vdXRsaW5lIH0NCmBgYHtyLCBlY2hvPUZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1haW5wbG90LnBuZyIpKQ0KYGBgDQoNCiMjIyMNCg0KIyMjIyB7LmRpc2NsYWltZXJfYmxvY2t9DQoNCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL3d3dy5vcGVuY2FzZXN0dWRpZXMub3JnKXt0YXJnZXQ9Il9ibGFuayJ9IHByb2plY3QgaXMgKip0byBkZW1vbnN0cmF0ZSB0aGUgdXNlIG9mIHZhcmlvdXMgZGF0YSBzY2llbmNlIG1ldGhvZHMsIHRvb2xzLCBhbmQgc29mdHdhcmUgaW4gdGhlIGNvbnRleHQgb2YgbWVzc3ksIHJlYWwtd29ybGQgZGF0YSoqLiBBIGdpdmVuIGNhc2Ugc3R1ZHkgZG9lcyBub3QgY292ZXIgYWxsIGFzcGVjdHMgb2YgdGhlIHJlc2VhcmNoIHByb2Nlc3MsIGlzIG5vdCBjbGFpbWluZyB0byBiZSB0aGUgbW9zdCBhcHByb3ByaWF0ZSB3YXkgdG8gYW5hbHl6ZSBhIGdpdmVuIGRhdGEgc2V0LCBhbmQgc2hvdWxkIG5vdCBiZSB1c2VkIGluIHRoZSBjb250ZXh0IG9mIG1ha2luZyBwb2xpY3kgZGVjaXNpb25zIHdpdGhvdXQgZXh0ZXJuYWwgY29uc3VsdGF0aW9uIGZyb20gc2NpZW50aWZpYyBleHBlcnRzLiANCg0KIyMjIw0KDQojIyMjIHsubGljZW5zZV9ibG9ja30NCg0KVGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBDcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLU5vbkNvbW1lcmNpYWwgMy4wIFsoQ0MgQlktTkMgMy4wKV0oaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLzMuMC91cy8pe3RhcmdldD0iX2JsYW5rIn0gVW5pdGVkIFN0YXRlcyBMaWNlbnNlLg0KDQojIyMjDQoNCiMjIyMgey5yZWZlcmVuY2VfYmxvY2t9DQoNClRvIGNpdGUgdGhpcyBjYXNlIHN0dWR5IHBsZWFzZSB1c2U6DQoNCldyaWdodCwgQ2FycmllIGFuZCBXYW5nLCBLZXhpbiBhbmQgTWVuZywgUWllciBhbmQgSmFnZXIsIExlYWggYW5kIFRhdWIsIE1hcmdhcmV0IGFuZCBIaWNrcywgU3RlcGhhbmllLiAoMjAyMCkuIFtodHRwczovL2dpdGh1Yi5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1vcGlvaWQtcnVyYWwtdXJiYW5dKGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLW9waW9pZC1ydXJhbC11cmJhbikgT3Bpb2lkcyBpbiB0aGUgVW5pdGVkIFN0YXRlcyAoVmVyc2lvbiB2MS4wLjApLg0KDQojIyMjDQoNClRvIGFjY2VzcyB0aGUgR2l0SHViIFJlcG9zaXRvcnkgZm9yIHRoaXMgY2FzZSBzdHVkeSBzZWUgaGVyZTogaHR0cHM6Ly9naXRodWIuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtb3Bpb2lkLXJ1cmFsLXVyYmFuLw0KDQpZb3UgbWF5IGFsc28gYWNjZXNzIGFuZCBkb3dubG9hZCB0aGUgZGF0YSB1c2luZyBvdXIgYE9DU2RhdGFgIHBhY2thZ2UuIFRvIGxlYXJuIG1vcmUgYWJvdXQgdGhpcyBwYWNrYWdlIGluY2x1ZGluZyBleGFtcGxlcywgc2VlIHRoaXMgW2xpbmtdKGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvT0NTZGF0YSkuIEhlcmUgaXMgaG93IHlvdSB3b3VsZCBpbnN0YWxsIHRoaXMgcGFja2FnZToNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQppbnN0YWxsLnBhY2thZ2VzKCJPQ1NkYXRhIikNCmBgYA0KDQpUaGlzIGNhc2Ugc3R1ZHkgaXMgcGFydCBvZiBhIHNlcmllcyBvZiBwdWJsaWMgaGVhbHRoIGNhc2Ugc3R1ZGllcyBmb3IgdGhlIFtCbG9vbWJlcmcgQW1lcmljYW4gSGVhbHRoICBJbml0aWF0aXZlXShodHRwczovL2FtZXJpY2FuaGVhbHRoLmpodS5lZHUvb3Blbi1jYXNlLXN0dWRpZXMpLg0KDQoqKioNCg0KVGhlIHRvdGFsIHJlYWRpbmcgdGltZSBmb3IgdGhpcyBjYXNlIHN0dWR5IGlzIGNhbGN1bGF0ZWQgdmlhIFtrb1JwdXNdKGh0dHBzOi8vZ2l0aHViLmNvbS91bkRvY1VNZWFudEl0L2tvUnB1cykgYW5kIHNob3duIGJlbG93OiANCg0KYGBge3IsIGVjaG89RkFMU0V9DQpyZWFkdGFibGUgPSB0ZXh0X3N0YXRzKCJpbmRleC5SbWQiKSAjIHByb2R1Y2luZyByZWFkaW5nIHRpbWUgbWFya2Rvd24gdGFibGUNCnJlYWR0aW1lID0gcmVhZC5zbzo6cmVhZC5tZChyZWFkdGFibGUpICU+JSBkcGx5cjo6c2VsZWN0KE1ldGhvZCwga29ScHVzKSAlPiUgIyByZWFkaW5nIHRhYmxlIGludG8gZGF0YWZyYW1lLCBzZWxlY3RpbmcgcmVsZXZhbnQgZmFjdG9ycw0KICBkcGx5cjo6ZmlsdGVyKE1ldGhvZCA9PSAiUmVhZGluZyB0aW1lIikgJT4lICMgZHJvcHBpbmcgdW5uZWNlc3Nhcnkgcm93cw0KICBkcGx5cjo6bXV0YXRlKGtvUnB1cyA9IHBhc3RlKHJvdW5kKGFzLm51bWVyaWMoc3RyaW5ncjo6c3RyX3NwbGl0KGtvUnB1cywgIiAiKVtbMV1dWzFdKSksICJtaW51dGVzIikpICU+JSAjIHJvdW5kaW5nIHJlYWRpbmcgdGltZSBlc3RpbWF0ZQ0KICBkcGx5cjo6bXV0YXRlKE1ldGhvZCA9ICJrb1JwdXMiKSAlPiUgZHBseXI6OnJlbG9jYXRlKGtvUnB1cywgLmJlZm9yZSA9IE1ldGhvZCkgJT4lIGRwbHlyOjpyZW5hbWUoYFJlYWRpbmcgVGltZWAgPSBrb1JwdXMpICMgcmVvcmdhbml6aW5nIHRhYmxlDQprbml0cjo6a2FibGUocmVhZHRpbWUsIGZvcm1hdD0ibWFya2Rvd24iKQ0KYGBgDQoNCioqKg0KDQoqKlJlYWRhYmlsaXR5IFNjb3JlOiAqKg0KDQpBIHJlYWRhYmlsaXR5IGluZGV4IGVzdGltYXRlcyB0aGUgcmVhZGluZyBkaWZmaWN1bHR5IGxldmVsIG9mIGEgcGFydGljdWxhciB0ZXh0LiBGbGVzY2gtS2luY2FpZCwgRk9SQ0FTVCwgYW5kIFNNT0cgYXJlIHRocmVlIGNvbW1vbiByZWFkYWJpbGl0eSBpbmRpY2VzIHRoYXQgd2VyZSBjYWxjdWxhdGVkIGZvciB0aGlzIGNhc2Ugc3R1ZHkgdmlhIFtrb1JwdXNdKGh0dHBzOi8vZ2l0aHViLmNvbS91bkRvY1VNZWFudEl0L2tvUnB1cykuIFRoZXNlIGluZGljZXMgcHJvdmlkZSBhbiBlc3RpbWF0aW9uIG9mIHRoZSBtaW5pbXVtIHJlYWRpbmcgbGV2ZWwgcmVxdWlyZWQgdG8gY29tcHJlaGVuZCB0aGlzIGNhc2Ugc3R1ZHkgYnkgZ3JhZGUgYW5kIGFnZS4gDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KcnQgPSB3b3JkY291bnRhZGRpbjo6cmVhZGFiaWxpdHkoImluZGV4LlJtZCIsIHF1aWV0PVRSVUUpICMgcHJvZHVjaW5nIHJlYWRhYmlsaXR5IG1hcmtkb3duIHRhYmxlDQpkZiA9IHJlYWQuc286OnJlYWQubWQocnQpICU+JSBkcGx5cjo6c2VsZWN0KGluZGV4LCBncmFkZSwgYWdlKSAlPiUgICMgcmVhZGluZyB0YWJsZSBpbnRvIGRhdGFmcmFtZSwgc2VsZWN0aW5nIHJlbGV2YW50IGZhY3RvcnMNCiAgdGlkeXI6OmRyb3BfbmEoKSAlPiUgZHBseXI6Om11dGF0ZShncmFkZSA9IHJvdW5kKGFzLm51bWVyaWMoZ3JhZGUpKSwgIyBkcm9wcGluZyByb3dzIHdpdGggbWlzc2luZyB2YWx1ZXMsIHJvdW5kaW5nIGFnZSBhbmQgZ3JhZGUgY29sdW1ucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9IHJvdW5kKGFzLm51bWVyaWMoYWdlKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQprbml0cjo6a2FibGUoZGYsIGZvcm1hdD0ibWFya2Rvd24iKQ0KYGBgDQoNCioqKg0KDQpQbGVhc2UgaGVscCB1cyBieSBmaWxsaW5nIG91dCBvdXIgc3VydmV5Lg0KDQoNCjxkaXYgc3R5bGU9ImRpc3BsYXk6IGZsZXg7IGp1c3RpZnktY29udGVudDogY2VudGVyOyI+PGlmcmFtZSBzcmM9Imh0dHBzOi8vZG9jcy5nb29nbGUuY29tL2Zvcm1zL2QvZS8xRkFJcFFMU2ZwTjRGTjNLRUxxQk5FZ2YyQXRwaTdXeTdOcXkyYmVTa0ZRSU5MN1k1c0FNVjVfdy92aWV3Zm9ybT9lbWJlZGRlZD10cnVlIiB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI3MDAiIGZyYW1lYm9yZGVyPSIwIiBtYXJnaW5oZWlnaHQ9IjAiIG1hcmdpbndpZHRoPSIwIj5Mb2FkaW5n4oCmPC9pZnJhbWU+PC9kaXY+DQoNCg0KIyAqKk1vdGl2YXRpb24qKg0KKioqIA0KDQoNCkluIHRoaXMgY2FzZSBzdHVkeSB3ZSB3aWxsIGJlIGV4YW1pbmluZyB0aGUgbnVtYmVyIG9mIG9waW9pZCBwaWxscyAoc3BlY2lmaWNhbGx5IFtveHljb2RvbmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL09waW9pZF9lcGlkZW1pY19pbl90aGVfVW5pdGVkX1N0YXRlcykgYW5kIFtoeWRyb2NvZG9uZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvT3Bpb2lkX2VwaWRlbWljX2luX3RoZV9Vbml0ZWRfU3RhdGVzKSwgYXMgdGhleSBhcmUgdGhlIHRvcCB0d28gbW9zdCBtaXN1c2VkIG9waW9pZHMpIHNoaXBwZWQgdG8gcGhhcm1hY2llcyBhbmQgcHJhY3RpdGlvbmVycyBhdCB0aGUgY291bnR5LWxldmVsIGFyb3VuZCB0aGUgVW5pdGVkIFN0YXRlcyAoVVMpIGZyb20gMjAwNiB0byAyMDE0Lg0KDQpUaGlzIGRhdGEgY29tZXMgZnJvbSB0aGUgW0RFQV0oaHR0cHM6Ly93d3cuZGVhLmdvdi8pIFtBdXRvbWF0ZWQgUmVwb3J0cyBhbmQgQ29uc29saWRhdGVkIE9yZGVyaW5nIFN5c3RlbSAoQVJDT1MpXShodHRwczovL3d3dy5kZWFkaXZlcnNpb24udXNkb2ouZ292L2FyY29zL3JldGFpbF9kcnVnX3N1bW1hcnkvKSBhbmQgd2FzIHJlbGVhc2VkIGJ5IHRoZSBbV2FzaGluZ3RvbiBQb3N0XShodHRwczovL3d3dy53YXNoaW5ndG9ucG9zdC5jb20vKSBhZnRlciBsZWdhbCBhY3Rpb24gYnkgdGhlIG93bmVyIG9mIHRoZSBbQ2hhcmxlc3RvbiBHYXpldHRlLU1haWxdKGh0dHBzOi8vd3d3Lnd2Z2F6ZXR0ZW1haWwuY29tLykgaW4gV2VzdCBWaXJnaW5pYSBhbmQgdGhlIFtXYXNoaW5ndG9uIFBvc3RdKGh0dHBzOi8vd3d3Lndhc2hpbmd0b25wb3N0LmNvbS8pLg0KDQpXZSB3aWxsIGludmVzdGlnYXRlIGhvdyB0aGUgbnVtYmVyIG9mIHNoaXBwZWQgcGlsbHMgaGFzIGNoYW5nZWQgYWNyb3NzIHRpbWUgYW5kIGJldHdlZW4gcnVyYWwgYW5kIHVyYmFuIGNvdW50aWVzIGluIHRoZSBVUy4gVGhpcyBhbmFseXNpcyB3aWxsIGRlbW9uc3RyYXRlIGhvdyBkaWZmZXJlbnQgcmVnaW9ucyBvZiB0aGUgY291bnRyeSBtYXkgaGF2ZSBiZWVuIG1vcmUgYXQgcmlzayBmb3Igb3Bpb2lkIGFkZGljdGlvbiBjcmlzZXMgZHVlIHRvIGRpZmZlcmluZyByYXRlcyBvZiBvcGlvaWQgcHJlc2NyaXB0aW9uICh1c2luZyB0aGUgbnVtYmVyIG9mIHBpbGxzIGFzIGEgcHJveHkgZm9yIHByZXNjcmlwdGlvbiByYXRlcykuIFRoaXMgd2lsbCBoZWxwIGluZm9ybSBzdHVkZW50cyBhYm91dCBob3cgZXZpZGVuY2UtYmFzZWQgaW50ZXJ2ZW50aW9uIGRlY2lzaW9ucyBhcmUgbWFkZSBpbiB0aGlzIGFyZWEuICANCg0KVGhpcyBjYXNlIHN0dWR5IGlzIG1vdGl2YXRlZCBieSB0aGlzIFthcnRpY2xlXShodHRwczovL3d3dy5jZGMuZ292L21td3Ivdm9sdW1lcy82OC93ci9tbTY4MDJhMS5odG0/c19jaWQ9bW02ODAyYTFfdyk6DQoNCiMjIyMgey5yZWZlcmVuY2VfYmxvY2t9DQoNCkdhcmPDrWEsIE0uIEMuIGV0IGFsLiBPcGlvaWQgUHJlc2NyaWJpbmcgUmF0ZXMgaW4gTm9ubWV0cm9wb2xpdGFuIGFuZCBNZXRyb3BvbGl0YW4gQ291bnRpZXMgQW1vbmcgUHJpbWFyeSBDYXJlIFByb3ZpZGVycyBVc2luZyBhbiBFbGVjdHJvbmljIEhlYWx0aCBSZWNvcmQgU3lzdGVtIOKAlCBVbml0ZWQgU3RhdGVzLCAyMDE04oCTMjAxNy4gTU1XUiBNb3JiLiBNb3J0YWwuIFdrbHkuIFJlcC4gNjgsIDI14oCTMzAgKDIwMTkpLiBET0k6IFsxMC4xNTU4NS9tbXdyLm1tNjgwMmExXShodHRwOi8vZHguZG9pLm9yZy8xMC4xNTU4NS9tbXdyLm1tNjgwMmExKQ0KDQojIyMjDQoNClRoaXMgYXJ0aWNsZSBleHBsb3JlcyByYXRlcyBvZiBvcGlvaWQgcHJlc2NyaXB0aW9ucyBpbiBydXJhbCBhbmQgdXJiYW4gY29tbXVuaXRpZXMgaW4gdGhlIFVuaXRlZCBTdGF0ZXMgdXNpbmcgdGhlIFtBdGhlbmFoZWFsdGggZWxlY3Ryb25pYyBoZWFsdGggcmVjb3JkIChFSFIpIHN5c3RlbV0oaHR0cHM6Ly9sYW5kaW5nLmF0aGVuYWhlYWx0aC5jb20vZy9pbXByb3ZlY2FyZT9jbXA9MTA2NzI5NDEpIGZvciAzMSw0MjIgcHJpbWFyeSBjYXJlIHByb3ZpZGVycyBmcm9tIEphbnVhcnkgMjAxNCB0byBNYXJjaCAyMDE3Lg0KDQpUaGUgbWFpbiB0YWtlYXdheXMgZnJvbSB0aGlzIGFydGljbGUgd2VyZToNCg0KPiBBbW9uZyA3MCwyMzcgZmF0YWwgZHJ1ZyBvdmVyZG9zZXMgaW4gMjAxNywgcHJlc2NyaXB0aW9uIG9waW9pZHMgd2VyZSBpbnZvbHZlZCBpbiAxNywwMjkgKDI0LjIlKS4NCg0KPiBUaGUgcGVyY2VudGFnZSBvZiBwYXRpZW50cyBwcmVzY3JpYmVkIGFuIG9waW9pZCB3YXMgaGlnaGVyIGluICoqcnVyYWwqKiB0aGFuIGluIHVyYmFuIGFyZWFzLiANCg0KPiBIaWdoZXIgb3Bpb2lkIHByZXNjcmliaW5nIHJhdGVzIHB1dCBwYXRpZW50cyAqKmF0IHJpc2sgZm9yIGFkZGljdGlvbiBhbmQgb3ZlcmRvc2UqKi4NCg0KSW5kZWVkLCB0aGlzIHdhcyBjb25maXJtZWQgYnkgYW5vdGhlciBbYXJ0aWNsZV0oaHR0cHM6Ly9qYW1hbmV0d29yay5jb20vam91cm5hbHMvamFtYXBzeWNoaWF0cnkvZnVsbGFydGljbGUvMTg3NDU3NSksIHdoaWNoIHN1cnZleWVkIHBlb3BsZSB3aG8gdXNlIGhlcm9pbiBpbiB0aGUgW1N1cnZleSBvZiBLZXkgSW5mb3JtYW50c+KAmSBQYXRpZW50cyBQcm9ncmFtXShodHRwczovL3d3dy5yYWRhcnMub3JnL3JhZGFycy1zeXN0ZW0tcHJvZ3JhbXMvc3VydmV5LW9mLWtleS1pbmZvcm1hbnRzLXBhdGllbnRzLmh0bWwpIGFuZCB0aGUgW1Jlc2VhcmNoZXJzIGFuZCBQYXJ0aWNpcGFudHMgSW50ZXJhY3RpbmcgRGlyZWN0bHkgKFJBUElEKSBwcm9ncmFtXShodHRwczovL3d3dy5yYWRhcnMub3JnL3JhZGFycy1zeXN0ZW0tcHJvZ3JhbXMvcmVzZWFyY2hlcnMtYW5kLXBhcnRpY2lwYW50cy1pbnRlcmFjdGluZy1kaXJlY3RseS5odG1sKS4NCg0KIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30NCg0KQ2ljZXJvLCBULiBKLiwgRWxsaXMsIE0uIFMuLCBTdXJyYXR0LCBILiBMLiAmIEt1cnR6LCBTLiBQLiBUaGUgQ2hhbmdpbmcgRmFjZSBvZiBIZXJvaW4gVXNlIGluIHRoZSBVbml0ZWQgU3RhdGVzOiBBIFJldHJvc3BlY3RpdmUgQW5hbHlzaXMgb2YgdGhlIFBhc3QgNTAgWWVhcnMuIEpBTUEgUHN5Y2hpYXRyeSA3MSwgODIxICgyMDE0KS4gW0RPSToxMC4xMDAxL2phbWFwc3ljaGlhdHJ5LjIwMTQuMzY2XShodHRwczovL2RvaS5vcmcvMTAuMTAwMS9qYW1hcHN5Y2hpYXRyeS4yMDE0LjM2NikNCg0KIyMjIw0KDQpUaGV5IGZvdW5kIHRoYXQ6DQoNCj4gUmVzcG9uZGVudHMgd2hvIGJlZ2FuIHVzaW5nIGhlcm9pbiBpbiB0aGUgMTk2MHMgd2VyZSBwcmVkb21pbmFudGx5IHlvdW5nIG1lbiAoODIuOCU7IG1lYW4gYWdlLCAxNi41IHllYXJzKSB3aG9zZSBmaXJzdCBvcGlvaWQgb2YgYWJ1c2Ugd2FzIGhlcm9pbiAoODAlKS4NCg0KTWVhbmluZyB0aGF0IDgwJSBvZiB0aGUgcGVvcGxlIHdobyB1c2UgaGVyb2luIHdobyBzdGFydGVkIHVzaW5nIGhlcm9pbiBpbiB0aGUgMTk2MHMsIHN0YXJ0ZWQgd2l0aCBoZXJvaW4gZGlyZWN0bHksIHdoaWxlICAyMCUgZmlyc3QgdXNlZCBhbm90aGVyIG9waW9pZCBhbmQgdGhlbiBiZWNhbWUgcGVvcGxlIHdobyB1c2UgaGVyb2luLiANCg0KPiBIb3dldmVyLCBtb3JlICoqcmVjZW50IHVzZXJzKiogd2VyZSBvbGRlciAobWVhbiBhZ2UsIDIyLjkgeWVhcnMpIG1lbiBhbmQgd29tZW4gKipsaXZpbmcgaW4gbGVzcyB1cmJhbiBhcmVhcyAoNzUuMiUpKiogd2hvIHdlcmUgKippbnRyb2R1Y2VkIHRvIG9waW9pZHMgdGhyb3VnaCBwcmVzY3JpcHRpb24gZHJ1Z3MgKDc1LjAlKSoqLg0KDQpgYGB7ciwgb3V0LndpZHRoID0gIjgwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0NCmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImludHJvZHVjZWRieXByZXNjcmlwdGlvbi5wbmciKSkNCmBgYA0KDQojIyMjIyBbW3NvdXJjZV1dKChodHRwczovL2RvaS5vcmcvMTAuMTAwMS9qYW1hcHN5Y2hpYXRyeS4yMDE0LjM2NikpDQoNCj4gSGVyb2luIHVzZSBoYXMgKipjaGFuZ2VkIGZyb20gYW4gaW5uZXItY2l0eSoqLCBtaW5vcml0eS1jZW50ZXJlZCBwcm9ibGVtIHRvIG9uZSB0aGF0IGhhcyBhIG1vcmUgd2lkZXNwcmVhZCBnZW9ncmFwaGljYWwgZGlzdHJpYnV0aW9uLCBpbnZvbHZpbmcgcHJpbWFyaWx5IHdoaXRlIG1lbiBhbmQgd29tZW4gaW4gdGhlaXIgbGF0ZSAyMHMgbGl2aW5nICoqb3V0c2lkZSBvZiBsYXJnZSB1cmJhbiBhcmVhcyoqLg0KDQpgYGB7ciwgb3V0LndpZHRoID0gIjUwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0NCmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImphbWVzLXlhcmVtYS01dHlNZ2FnMHdSby11bnNwbGFzaC5qcGciKSkNCmBgYA0KDQo8c3Bhbj5QaG90byBieSA8YSBocmVmPSJodHRwczovL3Vuc3BsYXNoLmNvbS9AamFtZXN5YXJlbWE/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPkphbWVzIFlhcmVtYTwvYT4gb24gPGEgaHJlZj0iaHR0cHM6Ly91bnNwbGFzaC5jb20vcy9waG90b3MvcGlsbHM/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPlVuc3BsYXNoPC9hPjwvc3Bhbj4NCg0KPiBBIG11Y2ggZ3JlYXRlciBwZXJjZW50YWdlIG9mIGhlcm9pbiB1c2VycyBjb21wbGV0aW5nIHRoZSBzdXJ2ZXkgaW4gdGhlIFNLSVAgUHJvZ3JhbSByZXBvcnRlZCBjdXJyZW50bHkgbGl2aW5nIGluICoqc21hbGwgdXJiYW4gb3Igbm9udXJiYW4gYXJlYXMqKiB0aGFuIGluIGxhcmdlIHVyYmFuIGFyZWFzICg3NS4yJSB2cyAyNC44JSkgYXQgdGhlIHRpbWUgb2Ygc3VydmV5IGNvbXBsZXRpb24uIA0KDQpUaGlzIHN1cnZleSB1c2VkIHNlbGYtZGVjbGFyZWQgYXJlYSBvZiBjdXJyZW50IHJlc2lkZW5jZSAobGFyZ2UgdXJiYW4sIHNtYWxsIHVyYmFuLCBzdWJ1cmJhbiwgb3IgcnVyYWwpLg0KDQoNCiMgKipNYWluIFF1ZXN0aW9uKioNCioqKiANCg0KIyMjIyB7Lm1haW5fcXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb246IDwvdT48L2I+DQoNCkhvdyBkaWQgb3Bpb2lkIHNoaXBtZW50IHJhdGVzIGRpZmZlciBiZXR3ZWVuIHJ1cmFsIGFuZCB1cmJhbiByZWdpb25zIG92ZXIgdGltZSBpbiB0aGUgVVMgZnJvbSAyMDA2LTIwMTQ/DQoNCg0KIyMjIw0KDQojICoqTGVhcm5pbmcgT2JqZWN0aXZlcyoqIA0KKioqIA0KDQpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvIG9idGFpbiBkYXRhIGZyb20gYW4gW0FwcGxpY2F0aW9uIFByb2dyYW1taW5nIEludGVyZmFjZSAoQVBJKV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQVBJKSwgd2hpY2ggaXMgYW4gaW50ZXJmYWNlIHRoYXQgYWxsb3dzIHVzZXJzIHRvIG1vcmUgZWFzaWx5IGludGVyYWN0IHdpdGggYSBkYXRhYmFzZS4gV2Ugd2lsbCBhbHNvIGVzcGVjaWFsbHkgZm9jdXMgb24gdXNpbmcgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyBmcm9tIHRoZSBbYFRpZHl2ZXJzZWBdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9LCBzdWNoIGFzIGBkcGx5cmAsIGB0aWR5cmAuIFRoZSB0aWR5dmVyc2UgaXMgYSBsaWJyYXJ5IG9mIHBhY2thZ2VzIGNyZWF0ZWQgYnkgUlN0dWRpby4gV2hpbGUgc29tZSBzdHVkZW50cyBtYXkgYmUgZmFtaWxpYXIgd2l0aCBwcmV2aW91cyBSIHByb2dyYW1taW5nIHBhY2thZ2VzLCB0aGVzZSBwYWNrYWdlcyBtYWtlIGRhdGEgc2NpZW5jZSBpbiBSIG1vcmUgbGVnaWJsZSBhbmQgaW50dWl0aXZlLg0KDQoNCmBgYHtyLCBvdXQud2lkdGggPSAiMjAlIiwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIifQ0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpDQpgYGANCg0KVGhlIHNraWxscywgbWV0aG9kcywgYW5kIGNvbmNlcHRzIHRoYXQgc3R1ZGVudHMgd2lsbCBiZSBmYW1pbGlhciB3aXRoIGJ5IHRoZSBlbmQgb2YgdGhpcyBjYXNlIHN0dWR5IGFyZToNCg0KPHU+KipEYXRhIFNjaWVuY2UgTGVhcm5pbmcgT2JqZWN0aXZlczoqKjwvdT4gIA0KICANCjEuIEltcG9ydGluZyBkYXRhIGZyb20gYW4gW0FQSV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQVBJKSAoYGh0dHJgIGFuZCBganNvbmxpdGVgKSAgDQoyLiBIb3cgdG8gam9pbiBkYXRhIHdpdGggYGRwbHlyYA0KMy4gSG93IHRvIHJlc2hhcGUgZGF0YSBieSBwaXZvdGluZyBiZXR3ZWVuICJsb25nIiBhbmQgIndpZGUiIGZvcm1hdHMgYW5kIGRyb3Agcm93cyB3aXRoIGBOQWAgdmFsdWVzIChgdGlkeXJgKSAgDQo0LiBIb3cgdG8gY3JlYXRlIGZvcm1hdHRlZCB0YWJsZXMgb2YgZGF0YSB3aXRoIGBmb3JtYXR0YWJsZWAgIA0KNS4gSG93IHRvIGxvb2sgZm9yIG1pc3NpbmcgZGF0YSBpbiBhIGRhdGFzZXQgKGBuYW5pYXJgKSAgDQo2LiBIb3cgdG8gY3JlYXRlIGRhdGEgdmlzdWFsaXphdGlvbnMgd2l0aCBgZ2dwbG90MmAgDQo3LiBIb3cgdG8gY3JlYXRlIGludGVyYWN0aXZlIHBsb3RzIHRoYXQgYXJlIGRpZmZpY3VsdCB0byBsYWJlbCBiZWNhdXNlIHRoZXkgaGF2ZSAgbWFueSBlbGVtZW50cyAoYGdnaXJhcGhgKSAgDQo4LiBIb3cgdG8gY29tYmluZSBpbmRpdmlkdWFsIHBsb3RzIGludG8gb25lIGZpZ3VyZSB3aXRoIGBwYXRjaHdvcmtgDQoNCiAgDQo8dT4qKlN0YXRpc3RpY2FsIExlYXJuaW5nIE9iamVjdGl2ZXM6Kio8L3U+ICANCiAgDQoxLiBVbmRlcnN0YW5kaW5nIG9mIHdoZW4gYW5kIHdoeSBkYXRhIG5vcm1hbGl6YXRpb24gaXMgdXNlZnVsICANCjIuIFVuZGVyc3RhbmRpbmcgb2YgaG93IGdyb3VwIGRlZmluaXRpb25zIGNhbiBjaGFuZ2UgcmVzdWx0cyAgDQozLiBVbmRlcnN0YW5kaW5nIG9mIHdoZW4gdG8gdXNlIGEgV2lsY294b24gcmFuayBzdW0gdGVzdCAoYWxzbyBjYWxsZWQgTWFubiBXaGl0bmV5IFUgdGVzdCkgIA0KNC4gSG93IHRvIGltcGxlbWVudCBhIFdpbGNveG9uIHJhbmsgc3VtIHRlc3QgaW4gUiAgDQo1LiBIb3cgdG8gaW50ZXJwcmV0IGEgV2lsY294b24gcmFuayBzdW0gdGVzdCAgICANCg0KKioqIA0KDQoNCldlIHdpbGwgYmVnaW4gYnkgbG9hZGluZyB0aGUgcGFja2FnZXMgdGhhdCB3ZSB3aWxsIG5lZWQ6DQoNCmBgYHtyfQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHRpYmJsZSkNCmxpYnJhcnkoaHR0cikNCmxpYnJhcnkoanNvbmxpdGUpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KG5hbmlhcikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZm9ybWF0dGFibGUpDQpsaWJyYXJ5KGZvcmNhdHMpDQpsaWJyYXJ5KEhtaXNjKQ0KbGlicmFyeShnZ3BvbCkNCmxpYnJhcnkoZ2dpcmFwaCkNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KbGlicmFyeShkaXJlY3RsYWJlbHMpDQpsaWJyYXJ5KHVzZGF0YSkNCiMgaWYgeW91IGFyZSBub3QgdXNpbmcgdGhlIE9DU2RhdGEgcGFja2FnZSB0byBkb3dubG9hZCBkYXRhIHlvdSBkbyBub3QgbmVlZCB0byBsb2FkIGl0DQpsaWJyYXJ5KE9DU2RhdGEpDQpgYGANCg0KDQoNCiA8dT4qKlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OioqIDwvdT4NCg0KUGFja2FnZSAgIHwgVXNlIGluIHRoaXMgY2FzZSBzdHVkeSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCi0tLS0tLS0tLS0gfC0tLS0tLS0tLS0tLS0NCltyZWFkeGxdKGh0dHBzOi8vcmVhZHhsLnRpZHl2ZXJzZS5vcmcvaW5kZXguaHRtbCkgfCB0byBpbXBvcnQgYW4gZXhjZWwgZmlsZSAgIA0KW2h0dHJdKGh0dHBzOi8vaHR0ci5yLWxpYi5vcmcvKSB8IHRvIHJldHJpZXZlIGRhdGEgZnJvbSBhbiBBUEkgICANClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKSB8IHRvIGNyZWF0ZSB0aWJibGVzICh0aGUgdGlkeXZlcnNlIHZlcnNpb24gb2YgZGF0YWZyYW1lcykgICANCltqc29ubGl0ZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2pzb25saXRlL2pzb25saXRlLnBkZikgfCB0byBwYXJzZSBqc29uIGZpbGVzICAgDQpbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBtYW5pcHVsYXRlICBjaGFyYWN0ZXIgc3RyaW5ncyB3aXRoaW4gdGhlIGRhdGEgKHN1YnNldCBhbmQgZGV0ZWN0IHBhcnRzIG9mIHN0cmluZ3MpICAgIA0KW2RwbHlyXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBmaWx0ZXIsIHN1YnNldCwgam9pbiwgYW5kIG1vZGlmeSBhbmQgc3VtbWFyaXplIHRoZSBkYXRhICAgDQpbbWFncml0dHJdKGh0dHBzOi8vbWFncml0dHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHBpcGUgc2VxdWVudGlhbCBjb21tYW5kcyAgIA0KW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBjaGFuZ2UgdGhlIHNoYXBlIG9yIGZvcm1hdCBvZiB0aWJibGVzIHRvIHdpZGUgYW5kIGxvbmcgICANCltuYW5pYXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9uYW5pYXIvdmlnbmV0dGVzL2dldHRpbmctc3RhcnRlZC13LW5hbmlhci5odG1sKSB8IHRvIGdldCBhIHNlbnNlIG9mIG1pc3NpbmcgZGF0YSAgIA0KW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gY3JlYXRlIHBsb3RzDQpbZm9ybWF0dGFibGVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9mb3JtYXR0YWJsZS9mb3JtYXR0YWJsZS5wZGYpIHwgdG8gY3JlYXRlIGEgZm9ybWF0dGVkIHRhYmxlDQpbZm9yY2F0c10oaHR0cHM6Ly9mb3JjYXRzLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byByZW9yZGVyIGZhY3RvciBmb3IgcGxvdA0KW0htaXNjXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvSG1pc2MvSG1pc2MucGRmKSB8IHRvIGNhbGN1bGF0ZSBkaWZmZXJlbnQgZmVhdHVyZXMgYWJvdXQgdGhlIGRhdGENCltnZ3BvbF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dncG9sL2dncG9sLnBkZikgfCB0byBjcmVhdGUgcGxvdHMgdGhhdCBoYXZlIGppdHRlciBhbmQgaGFsZiBib3hwbG90cyAgIA0KW2dnaXJhcGhdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ2lyYXBoL2dnaXJhcGgucGRmKSAgIHwgdG8gY3JlYXRlIGludGVyYWN0aXZlIHBsb3RzDQpbcGF0Y2h3b3JrXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcGF0Y2h3b3JrL3BhdGNod29yay5wZGYpIHwgdG8gY29tYmluZSBwbG90cw0KW2RpcmVjdGxhYmVsc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2RpcmVjdGxhYmVscy9kaXJlY3RsYWJlbHMucGRmKSB8IHRvIGFkZCBsYWJlbHMgZGlyZWN0bHkgb24gbGluZXMgd2l0aGluIHBsb3RzDQpbdXNkYXRhXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdXNkYXRhL3VzZGF0YS5wZGYpIHwgdG8gYWRkIGZ1bGwgc3RhdGUgbmFtZXMgdG8gcGxvdHMgYmFzZWQgb24gdGhlIHN0YXRlIGFiYnJldmlhdGlvbnMNCltPQ1NkYXRhXShodHRwczovL2dpdGh1Yi5jb20vb3BlbmNhc2VzdHVkaWVzL09DU2RhdGEpIHwgdG8gYWNjZXNzIGFuZCBkb3dubG9hZCB0aGUgZGF0YSB1c2VkIGluIHRoaXMgY2FzZSBzdHVkeQ0KDQpUaGUgZmlyc3QgdGltZSB3ZSB1c2UgYSBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgdGhlIGA6OmAgdG8gaW5kaWNhdGUgd2hpY2ggcGFja2FnZSB3ZSBhcmUgdXNpbmcuIFVubGVzcyB3ZSBoYXZlIG92ZXJsYXBwaW5nIGZ1bmN0aW9uIG5hbWVzLCB0aGlzIGlzIG5vdCBuZWNlc3NhcnksIGJ1dCB3ZSB3aWxsIGluY2x1ZGUgaXQgaGVyZSB0byBiZSBpbmZvcm1hdGl2ZSBhYm91dCB3aGVyZSB0aGUgZnVuY3Rpb25zIHdlIHdpbGwgdXNlIGNvbWUgZnJvbS4NCg0KDQojICoqQ29udGV4dCoqDQoqKiogDQoqKldoYXQgZXhhY3RseSBhcmUgb3Bpb2lkcz8qKg0KDQpBY2NvcmRpbmcgdG8gdGhlIFtERUFdKGh0dHBzOi8vd3d3LmRlYS5nb3YvdGF4b25vbXkvdGVybS8zMzEpIGFuZCB0aGUgW0FsdGEgTWlyYSBhZGRpY3Rpb24gdHJlYXRtZW50IGNlbnRlcl0oaHR0cHM6Ly93d3cuYWx0YW1pcmFyZWNvdmVyeS5jb20vb3BpYXRlcy9kaWZmZXJlbmNlLW9waWF0ZXMtb3Bpb2lkcy8pOg0KDQpPcGlvaWRzIChhbHNvIGtub3duIGFzIG5hcmNvdGljcyksIGRlc2NyaWJlcyBhIGNsYXNzIG9mIGRydWdzIHRoYXQgY29udGFpbiBbb3BpdW1dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL09waXVtKSAodGhlIHBvcHB5IHBsYW50IC0gWypQYXBhdmVyIHNvbW5pZmVydW0qXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QYXBhdmVyX3NvbW5pZmVydW0pKSwgYXJlIGRlcml2ZWQgZnJvbSBvcGl1bSwgb3IgY29udGFpbiBhIHNlbWktc3ludGhldGljIG9yIHN5bnRoZXRpYyBzdWJzdGl0dXRlIGZvciBvcGl1bS4NCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsImluZ28tZG9lcnJpZS1UaTZTazVyWlJQOC11bnNwbGFzaC5qcGciICkpDQoNCmBgYA0KDQo8c3Bhbj5QaG90byBieSA8YSBocmVmPSJodHRwczovL3Vuc3BsYXNoLmNvbS9AaW5nb2RvZXJyaWU/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPkluZ28gRG9lcnJpZTwvYT4gb24gPGEgaHJlZj0iaHR0cHM6Ly91bnNwbGFzaC5jb20vcy9waG90b3Mvb3BpdW0/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPlVuc3BsYXNoPC9hPjwvc3Bhbj4NCg0KDQpIb3dldmVyLCB0ZWNobmljYWxseSwgb3Bpb2lkcyBhcmUgc3Vic3RhbmNlcyB0aGF0IGJpbmQgdG8gdGhlIFtvcGlvaWQgcmVjZXB0b3JzXShodHRwczovL3d3dy5zY2llbmNlZGFpbHkuY29tL3JlbGVhc2VzLzIwMDcvMTAvMDcxMDE0MTYzNjQ3Lmh0bSM6fjp0ZXh0PVRoZSUyMG9waW9pZCUyMHN5c3RlbSUyMGNvbnNpc3RzJTIwb2YsYW5kJTIwcG90ZW50aWFsbHklMjBpbml0aWF0aW5nJTIwYWRkaWN0aXZlJTIwYmVoYXZpb3JzLikgaW4gdGhlIGJvZHksIHdoaWNoIGFyZSBpbnZvbHZlZCBpbiB0aGUgc2Vuc2F0aW9uIG9mIGBwYWluYCBhbmQgdGhlIGV4cGVyaWVuY2Ugb2YgW3Jld2FyZF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmV3YXJkX3N5c3RlbSM6fjp0ZXh0PVRoZSUyMHJld2FyZCUyMHN5c3RlbSUyMGlzJTIwYSxpbnZvbHZlJTIwcGxlYXN1cmUlMjBhcyUyMGElMjBjb3JlKS4gVGhlcmUgYXJlIGFjdHVhbGx5IG9waW9pZHMgdGhhdCBuYXR1cmFsbHkgYXJlIG1hZGUgYnkgdGhlIGh1bWFuIGJvZHksIHRoZSBtb3N0IHdlbGwga25vd24gYmVpbmcgdGhlIFtlbmRvcnBoaW5zXShodHRwczovL3d3dy5tZWRpY2FsbmV3c3RvZGF5LmNvbS9hcnRpY2xlcy8zMjA4MzkjOn46dGV4dD1FbmRvcnBoaW5zJTIwYXJlJTIwY2hlbWljYWxzJTIwcHJvZHVjZWQlMjBieSxzdXJnZXJ5JTIwb3IlMjBmb3IlMjBwYWluJTJEcmVsaWVmLikuDQoNCioqKg0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gbGVhcm4gYWJvdXQgd2h5IG9waW9pZHMgYXJlIGFkZGljdGl2ZSA8L3N1bW1hcnk+DQoNCk9waW9pZCBkcnVncyB0ZW5kIHRvIGJlIGFkZGljdGl2ZSBiZWNhdXNlIHRoZXkgbW9kdWxhdGUgdGhlIFtyZXdhcmQgc3lzdGVtXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9SZXdhcmRfc3lzdGVtIzp+OnRleHQ9VGhlJTIwcmV3YXJkJTIwc3lzdGVtJTIwaXMlMjBhLGludm9sdmUlMjBwbGVhc3VyZSUyMGFzJTIwYSUyMGNvcmUpLiBUaGlzIGlzIHRoZSBwYXJ0IG9mIHRoZSBicmFpbiB0aGF0IHJlaW5mb3JjZXMgYmVoYXZpb3JzIChub3JtYWxseSB0aGVzZSBhcmUgYmVoYXZpb3JzIHN1Y2ggYXMgZHJpbmtpbmcgd2F0ZXIgb3IgZWF0aW5nIGZvb2QpIGJ5IGNhdXNpbmcgdGhlIGV4cGVyaWVuY2Ugb2YgcGxlYXN1cmUgKHRocm91Z2ggdGhlIHJlbGVhc2Ugb2YgYSBuZXVyb3RyYW5zbWl0dGVyIGNhbGxlZCBbZG9wYW1pbmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0RvcGFtaW5lKSkuIA0KDQpUaGlzIHNhbWUgc3lzdGVtIGNhbiBiZSBhY3RpdmF0ZWQgYnkgYm90aCBvcGlvaWRzIHRoYXQgbmF0dXJhbGx5IG9jY3VyIGluIHRoZSBib2R5LCBhcyB3ZWxsIGFzIG9waW9pZCBwcmVzY3JpcHRpb24gZHJ1Z3MgYW5kIG90aGVyIGFkZGljdGl2ZSBkcnVncy4gQWN0aXZhdGlvbiBvZiB0aGlzIHN5c3RlbSBieSBkcnVnIHVzZSAgbGVhZHMgdG8gdmVyeSBoaWdoIHJlbGVhc2VzIG9mIERvcGFtaW5lIGFuZCB0aGUgc2Vuc2F0aW9uIG9mIHBsZWFzdXJlIHdoaWNoIHVsdGltYXRlbHkgbGVhZHMgdG8gcmVpbmZvcmNlZCB1c2Ugb2YgdGhhdCBkcnVnLg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vd3d3LmRydWdhYnVzZS5nb3Yvc2l0ZXMvZGVmYXVsdC9maWxlcy9zdHlsZXMvY29udGVudF9pbWFnZV9sYXJnZS9wdWJsaWMvZHJ1Z3N0YXJnZXR0aGVicmFpbnNwbGVhc3VyZWNlbnRlci5naWY/aXRvaz1GZmRfUENlYiIpDQpgYGANCg0KW1tzb3VyY2VdKGh0dHBzOi8vd3d3LmRydWdhYnVzZS5nb3YvcHVibGljYXRpb25zL2RydWdzLWJyYWlucy1iZWhhdmlvci1zY2llbmNlLWFkZGljdGlvbi9kcnVncy1icmFpbildDQoNCjwvZGV0YWlscz4gDQoNCioqKg0KDQpJbiBnZW5lcmFsLCBvcGlvaWQgZHJ1Z3MgaGF2ZSBiZWVuIGZvdW5kIHRvIGR1bGwgdGhlIHNlbnNlcywgcmVsaWV2ZSBwYWluLCBzdXBwcmVzcyBjb3VnaCwgcmVkdWNlIHJlc3BpcmF0aW9uIGFuZCBoZWFydCByYXRlLCBpbmR1Y2UgY29uc3RpcGF0aW9uLCBhbmQgaW5kdWNlIGZlZWxpbmdzIG9mIGV1cGhvcmlhLiBUaGV5IGhhdmUgYSBoaWdoIHBvdGVudGlhbCBmb3IgYWJ1c2UgYW5kIGFkZGljdGlvbi4NCg0KRHJ1Z3Mgd2l0aGluIHRoaXMgY2xhc3MgaW5jbHVkZSAod2l0aCBwcmVzY3JpcHRpb24gZHJ1ZyBicmFuZCBuYW1lcyBhcmUgc2hvd24gaW4gcGFyZW50aGVzZXMpOiANCg0KMSkgTm9uLXN5bnRoZXRpYyBwdXJpZmllZDogTW9ycGhpbmUsIENvZGVpbmUsIFRoZWJhaW5lDQoyKSBTZW1pLXN5bnRoZXRpYzogIEhlcm9pbiwgT3h5Y29kb25lIChPeHljb250aW4sIE94ZWN0YSwgUm94aWNvZG9uZSksIGFuZCBIeWRyb2NvZG9uZSAoIFZpY29kaW4sIExvcnRhYiwgTG9yY2V0KSksIG94eW1vcnBob25lIChPcGFuYSksIEh5ZHJvbW9ycGhvbmUgKERpbGF1ZGlkLCBFeGFsZ28pDQozKSBTeW50aGV0aWM6IE1lcGVyaWRpbmUgKERlbWVyb2wpLCBNZXRoYWRvbmUgKE1ldGhhZG9zZSwgRG9sb3BoaW5lKSwgYW5kIEZlbnRhbnlsIChBYnN0cmFsLCBBY3RpcSwgRmVudG9yYSwgRHVyYWdlc2ljLCBMYXphbmRhLCBTdWJzeXMpLCBUcmFtYWRvbCAoQ29uWmlwLCBSeXpvbHQsIFVsdHJhbSkNCg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjQwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJPcGl1bV9wb2RfY3V0X3RvX2RlbW9uc3RyYXRlX2ZsdWlkX2V4dHJhY3Rpb24xLmpwZyIgKSkNCg0KYGBgDQoNCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRmlsZTpPcGl1bV9wb2RfY3V0X3RvX2RlbW9uc3RyYXRlX2ZsdWlkX2V4dHJhY3Rpb24xLmpwZykNCg0KT3BpdW0gY29tZXMgZnJvbSB0aGUgZmx1aWQgKHdoaWNoIGlzIGFsc28gY2FsbGVkIHBvcHB5IHRlYXJzKSBpbnNpZGUgdGhlIHNlZWQgY2Fwc3VsZXMgb2YgdGhlIFsqUGFwYXZlciBzb21uaWZlcnVtKl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUGFwYXZlcl9zb21uaWZlcnVtKSBwbGFudC4gVGhpcyBjb250YWlucyBtb3JwaGluZSwgY29kZWluZSwgYW5kIHRoZWJhaW5lLiBUaGlzIGlzIHRoZW4gZHJpZWQuIA0KDQpPcGl1bSBoYXMgYmVlbiB1c2VkIGJ5IGh1bWFucyBzaW5jZSA1MDAwIEJDRSBhbmQgaXQgaGFzIGJlZW4gdXNlZCBhY3Jvc3MgdGhlIHdvcmxkLiBTZWUgW2hlcmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL09waXVtKSBmb3IgYW4gaW50ZXJlc3Rpbmcgb3ZlcnZpZXcgb2YgdGhlIGhpc3RvcnkuIA0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBsZWFybiBhYm91dCB0aGUgaGlzdG9yeSBvZiBvcGlvaWRzIGluIHRoZSBVUyA8L3N1bW1hcnk+DQoNCk9waXVtIGRlcml2ZWQgbWVkaWNhdGlvbnMgd2VyZSBoaXN0b3JpY2FsbHkgdXNlZCBpbiBVbml0ZWQgU3RhdGVzIHRvIHRyZWF0IGEgdmFyaWV0eSBvZiBhaWxtZW50cyBiZXNpZGVzIHBhaW4gaW5jbHVkaW5nOiBjaG9sZXJhLCBkeXNlbnRlcnksIHR1YmVyY3Vsb3NpcywgYW5kIG1lbnRhbCBpbGxuZXNzLiAgDQoNCk9mIG5vdGUsIHRoZXkgc3RhdGUgdGhhdCAiZnJvbSAxODk4IHRvIDE5MTAgaGVyb2luIHdhcyBtYXJrZXRlZCBhcyBhIG5vbi1hZGRpY3RpdmUgbW9ycGhpbmUgc3Vic3RpdHV0ZSBhbmQgY291Z2ggbWVkaWNpbmUgZm9yIGNoaWxkcmVuIiENCg0KSGVyZSB5b3UgY2FuIHNlZSBhIHBob3RvIG9mIGEgYm90dGxlIG9mIGhlcm9pbjoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI0MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvdGh1bWIvZi9mZi9CYXllcl9IZXJvaW5fYm90dGxlLmpwZy8yMjBweC1CYXllcl9IZXJvaW5fYm90dGxlLmpwZyIpDQpgYGANCg0KW1tzb3VyY2VdKGh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvdGh1bWIvZi9mZi9CYXllcl9IZXJvaW5fYm90dGxlLmpwZy8yMjBweC1CYXllcl9IZXJvaW5fYm90dGxlLmpwZyldDQoNCk9waW9pZHMgaGF2ZSBjb250aW51ZWQgdG8gYmUgdXNlZCBpbiB0aGUgdHJlYXRtZW50IG9mIHBhaW4uIA0KDQo8L2RldGFpbHM+IA0KDQoqKioNCg0KIyMgKipUaGUgT3Bpb2lkIEVwaWRlbWljKioNCioqKg0KDQpUaGUgcmF0ZSBvZiBvcGlvaWQgb3ZlcmRvc2UgZGVhdGhzIHJhcGlkbHkgaW5jcmVhc2VkIGluIHRoZSBVUyBpbiB0aGUgMTk5MHMuIA0KDQpBY2NvcmRpbmcgdG8gdGhlIFtVUyBkZXBhcnRtZW50IG9mIGhlYWx0aCBhbmQgaHVtYW4gc2VydmljZXMgKEhIUyldKA0KaHR0cHM6Ly93d3cuaGhzLmdvdi9vcGlvaWRzL2Fib3V0LXRoZS1lcGlkZW1pYy9pbmRleC5odG1sKToNCg0KPiBJbiB0aGUgbGF0ZSAxOTkwcywgcGhhcm1hY2V1dGljYWwgY29tcGFuaWVzIHJlYXNzdXJlZCB0aGUgbWVkaWNhbCBjb21tdW5pdHkgdGhhdCBwYXRpZW50cyB3b3VsZCBub3QgYmVjb21lIGFkZGljdGVkIHRvIG9waW9pZCBwYWluIHJlbGlldmVycyBhbmQgaGVhbHRoY2FyZSBwcm92aWRlcnMgYmVnYW4gdG8gcHJlc2NyaWJlIHRoZW0gYXQgZ3JlYXRlciByYXRlcy4NCg0KPiBJbmNyZWFzZWQgcHJlc2NyaXB0aW9uIG9mIG9waW9pZCBtZWRpY2F0aW9ucyBsZWQgdG8gKip3aWRlc3ByZWFkIG1pc3VzZSoqIG9mIGJvdGggcHJlc2NyaXB0aW9uIGFuZCBub24tcHJlc2NyaXB0aW9uIG9waW9pZHMgYmVmb3JlIGl0IGJlY2FtZSBjbGVhciB0aGF0IHRoZXNlIG1lZGljYXRpb25zIGNvdWxkIGluZGVlZCBiZSBoaWdobHkgYWRkaWN0aXZlLg0KDQo+IEluIDIwMTcgdGhlIFtISFNdKGh0dHBzOi8vd3d3Lmhocy5nb3YpIGRlY2xhcmVkIGEgcHVibGljIGhlYWx0aCBlbWVyZ2VuY3kgDQoNClNlZSBbaGVyZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVGltZWxpbmVfb2ZfdGhlX29waW9pZF9lcGlkZW1pYykgZm9yIGEgdGltZSBsaW5lIG9mIHRoZSBlcGlkZW1pYyBpbiB0aGUgVVMgYW5kIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9PcGlvaWRfZXBpZGVtaWNfaW5fdGhlX1VuaXRlZF9TdGF0ZXMpIGZvciBtb3JlIGRldGFpbHMgYWJvdXQgdGhlIGVwaWRlbWljLg0KDQoNCkFjY29yZGluZyB0byB0aGlzIFthcnRpY2xlXShodHRwczovL3d3dy5jZGMuZ292L21td3Ivdm9sdW1lcy82OC93ci9tbTY4MDJhMS5odG0/c19jaWQ9bW02ODAyYTFfdykgZnJvbSB0aGUgW01vcmJpZGl0eSBhbmQgTW9ydGFsaXR5IFdlZWtseSBSZXBvcnQgKE1NV1IpXShodHRwczovL3d3dy5jZGMuZ292L21td3IvYWJvdXQuaHRtbCkgb2YgdGhlIFtDZW50ZXJzIGZvciBEaXNlYXNlIENvbnRyb2wgYW5kIFByZXZlbnRpb24gKENEQyldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NlbnRlcnNfZm9yX0Rpc2Vhc2VfQ29udHJvbF9hbmRfUHJldmVudGlvbik6DQoNCj4gRHJ1ZyBvdmVyZG9zZSBpcyB0aGUgKipsZWFkaW5nIGNhdXNlKiogb2YgdW5pbnRlbnRpb25hbCBpbmp1cnktYXNzb2NpYXRlZCBkZWF0aCBpbiB0aGUgVW5pdGVkIFN0YXRlcy4NCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJPcGlvaWRzX0luZm9ncmFwaGljLnBuZyIpKQ0KYGBgDQoNCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly93d3cuaGhzLmdvdi9vcGlvaWRzL3NpdGVzL2RlZmF1bHQvZmlsZXMvMjAxOS0xMS9PcGlvaWRzJTIwSW5mb2dyYXBoaWNfbGV0dGVyU2l6ZVBERl8xMC0wMi0xOS5wZGYpDQoNCg0KQWNjb3JkaW5nIHRvIHRoZSBbQ0RDXShodHRwczovL3d3dy5jZGMuZ292L2RydWdvdmVyZG9zZS9lcGlkZW1pYy9pbmRleC5odG1sKSwgdGhlcmUgd2VyZSAzIHdhdmVzIG9mIHRoZSBlcGlkZW1pYzoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICIyMDE4LTMtV2F2ZS1MaW5lcy1Nb3J0YWxpdHkucG5nIikpDQoNCmBgYA0KDQojIyMjIFtbc291cmNlXV0oaHR0cHM6Ly93d3cuY2RjLmdvdi9kcnVnb3ZlcmRvc2UvaW1hZ2VzL2VwaWRlbWljLzIwMTgtMy1XYXZlLUxpbmVzLU1vcnRhbGl0eS5wbmcpDQoNCllvdSBjYW4gc2VlIHRoYXQgbW9zdCByZWNlbnQgb3ZlcmRvc2UgZGVhdGhzIHdlcmUgZHVlIHRvIHRoZSB1c2Ugb2YgKipzeW50aGV0aWMgb3Bpb2lkcyoqLCB3aGVyZSBhcyBwcmV2aW91cyBoaWdoIGxldmVscyBvZiBvdmVyZG9zZXMgKHRpbGwgYWJvdXQgMjAxNSkgd2VyZSBhdHRyaWJ1dGFibGUgdG8gbmF0dXJhbCBhbmQgc2VtaS1zeW50aGV0aWMgb3Bpb2lkcyAod2hpY2ggaXMgd2hhdCB3ZSB3aWxsIGxvb2sgYXQgaW4gdGhpcyBjYXNlIHN0dWR5KS4NCg0KVGhleSBzdGF0ZSB0aGF0OiANCg0KPiBGcm9tIDE5OTnigJMyMDE4LCBhbG1vc3QgKio0NTAsMDAwKiogcGVvcGxlIGRpZWQgZnJvbSBhbiAqKm92ZXJkb3NlIGludm9sdmluZyBhbnkgb3Bpb2lkKiosIGluY2x1ZGluZyBwcmVzY3JpcHRpb24gYW5kIGlsbGljaXQgb3Bpb2lkcy4NCg0KDQpJbXBvcnRhbnRseSByYXRlcyBhcHBlYXIgdG8gZGlmZmVyIGFjcm9zcyBzdGF0ZXMsIGFjY29yZGluZyB0byB0aGlzIFtDREMgcmVwb3J0XShodHRwczovL3d3dy5jZGMuZ292L21td3Ivdm9sdW1lcy82Ny93ci9tbTY3NTE1MmUxLmh0bT9zX2NpZD1tbTY3NTE1MmUxX3cpIA0KDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly93d3cuY2RjLmdvdi9tbXdyL3ZvbHVtZXMvNjcvd3IvZmlndXJlcy9tbTY3NTE1MmUxLUYuZ2lmIikNCg0KYGBgDQoNCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly93d3cuY2RjLmdvdi9tbXdyL3ZvbHVtZXMvNjcvd3IvZmlndXJlcy9tbTY3NTE1MmUxLUYuZ2lmKQ0KDQoNCkFjY29yZGluZyB0byB0aGUgW21vdGl2YXRpbmcgcmVwb3J0XShodHRwczovL3d3dy5jZGMuZ292L21td3Ivdm9sdW1lcy82OC93ci9wZGZzL21tNjgwMmExLUgucGRmKSBmb3Igb3VyIGNhc2Ugc3R1ZHk6IA0KDQpQcmVzY3JpcHRpb24gcmF0ZXMgYXJlIG5vdyBkZWNsaW5pbmcsIGhvd2V2ZXIsIHByZXNjcmlwdGlvbiBvZiBvcGlvaWRzIHdhcyBmb3VuZCB0byBiZSBoaWdoZXIgaW4gcnVyYWwgYXJlYXMgcmF0aGVyIHRoYW4gdXJiYW4gYXJlcy4gDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiY29udGV4dC5wbmciKSkNCg0KYGBgDQoNCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly93d3cuY2RjLmdvdi9tbXdyL3ZvbHVtZXMvNjgvd3IvcGRmcy9tbTY4MDJhMS1ILnBkZikNCiANCkl0IGlzIGltcG9ydGFudCB0byBpZGVudGlmeSBsb2NhdGlvbnMgd2hlcmUgcGVvcGxlIGFyZSBwYXJ0aWN1bGFybHkgdnVsbmVyYWJsZSB0byB0YXJnZXQgaW50ZXJ2ZW50aW9ucyBmb3IgY29tbXVuaXRpZXMgdGhhdCBuZWVkIGl0IHRoZSBtb3N0Lg0KDQogDQojICoqTGltaXRhdGlvbnMqKg0KKioqIA0KDQpUaGVyZSBhcmUgc29tZSBpbXBvcnRhbnQgY29uc2lkZXJhdGlvbnMgcmVnYXJkaW5nIHRoaXMgZGF0YSBhbmFseXNpcyB0byBrZWVwIGluIG1pbmQ6IA0KDQpBY2NvcmRpbmcgdG8gdGhlIFtXYXNoaW5ndG9uIFBvc3QgZGF0YWJhc2VdKGh0dHBzOi8vd3d3Lndhc2hpbmd0b25wb3N0LmNvbS9uYXRpb25hbC8yMDE5LzA3LzE4L2hvdy1kb3dubG9hZC11c2UtZGVhLXBhaW4tcGlsbHMtZGF0YWJhc2UvKSwgdGhleSBzdGF0ZSBhYm91dCB0aGUgREVBIGRhdGE6DQoNCj4gW1dhc2hpbmd0b24gUG9zdF0uLi4gY2xlYW5lZCB0aGUgZGF0YSB0byBpbmNsdWRlIG9ubHkgaW5mb3JtYXRpb24gb24gc2hpcG1lbnRzIG9mIG94eWNvZG9uZSBhbmQgaHlkcm9jb2RvbmUgcGlsbHMuIFdlIGRpZCBub3QgaW5jbHVkZSBkYXRhIG9uIDEwIG90aGVyIG9waW9pZHMgYmVjYXVzZSB0aGV5IHdlcmUgc2hpcHBlZCBpbiBtdWNoIGxvd2VyIHF1YW50aXRpZXMuLi4NCg0KPiAiSXTigJlzIGltcG9ydGFudCB0byByZW1lbWJlciB0aGF0IHRoZSBudW1iZXIgb2YgcGlsbHMgaW4gZWFjaCBjb3VudHkgZG9lcyBub3QgbmVjZXNzYXJpbHkgbWVhbiB0aG9zZSBwaWxscyB3ZW50IHRvIHBlb3BsZSB3aG8gbGl2ZSBpbiB0aGF0IGNvdW50eS4gVGhlIGRhdGEgb25seSBzaG93cyB1cyB3aGF0IHBoYXJtYWNpZXMgdGhlIHBpbGxzIGFyZSBzaGlwcGVkIHRvIGFuZCBub3RoaW5nIGVsc2UuIg0KDQpGdXJ0aGVybW9yZSwgd2Ugd2lsbCBkZWZpbmUgY291bnRpZXMgYXMgYmVpbmcgcnVyYWwgb3IgdXJiYW4gaG93ZXZlciB0aGVyZSBjYW4gYmUgZ3JlYXQgdmFyaWF0aW9uIHdpdGhpbiBhIGNvdW50eSBhbmQgd2UgdXNlZCBsYW5kIGFyZWEgdmFsdWVzIGZyb20gb25seSAyMDEwIGV2ZW4gdGhvdWdoIHRoZXNlIGNhbiBmbHVjdHVhdGUuIFRoZXJlZm9yZSwgdGhlIHdheSB3ZSBjYXRlZ29yaXplZCBjb3VudGllcyBzaG91bGQgYmUgc2VlbiBhcyBhbiBhcHByb3hpbWF0aW9uLiBBZGRpdGlvbmFsbHksIG90aGVyIGFzcGVjdHMgYWJvdXQgYSBjb3VudHkgYmVzaWRlcyBwb3B1bGF0aW9uIGxldmVsIGFuZCBkZW5zaXR5IGNhbiBiZSBpbmZsdWVudGlhbCBmb3IgY3JlYXRpbmcgYW4gZW52aXJvbm1lbnQgdGhhdCB3b3VsZCBpbmNyZWFzZSB0aGUgdnVsbmVyYWJpbGl0eSBvZiBjb21tdW5pdHkgbWVtYmVycyB0byBkcnVnIGFidXNlIGFuZCBhZGRpY3Rpb24uIFRoZXNlIGluY2x1ZGUgc29jaW9lY29ub21pYyBmYWN0b3JzIGFtb25nIG90aGVycy4gDQoNCkZpbmFsbHksIG92ZXJkb3NlIGRlYXRocyBhcmUgb2Z0ZW4gZHVlIHRvIHRoZSB1c2Ugb2YgbXVsdGlwbGUgc3Vic3RhbmNlcy4gU2ltcGx5IGJlY2F1c2UgYSBjb3VudHkgcmVjZWl2ZWQgbW9yZSBwaWxscyBkb2VzIG5vdCBtZWFuIHRoYXQgcGVvcGxlIGluIHRoYXQgY291bnR5IHdvdWxkIGV4cGVyaWVuY2UgbW9yZSBkcnVnIG92ZXJkb3Nlcy4gSXQgaXMgYWxzbyBpbXBvcnRhbnQgdG8gcmVtZW1iZXIgdGhhdCBwcmVzY3JpcHRpb24gb3Bpb2lkcyBvbmx5IGFjY291bnQgZm9yIGEgcG9ydGlvbiBvZiB0aGUgZHJ1ZyBvdmVyZG9zZSBkZWF0aHMgcmVwb3J0ZWQgaW4gdGhpcyB0aW1lIHBlcmlvZC4gSG93ZXZlciwgYWNjb3JkaW5nIHRvIHRoaXMgW2FydGljbGVdKGh0dHBzOi8vamFtYW5ldHdvcmsuY29tL2pvdXJuYWxzL2phbWFwc3ljaGlhdHJ5L2Z1bGxhcnRpY2xlLzE4NzQ1NzUpLCA3NSUgb2YgcGVvcGxlIHdobyB1c2UgaGVyb2luIHN1cnZleWVkIHdlcmUgaW50cm9kdWNlZCB0byBvcGlvaWRzIHRocm91Z2ggcHJlc2NyaXB0aW9uIGRydWcgdXNlLg0KDQpUaGUgcmVjZW50IG92ZXJkb3NlIGRlYXRocyBpbiB0aGUgVVMgb3Bpb2lkIGNyaXNpcyBhcmUgbW9zdGx5IGR1ZSB0byBzeW50aGV0aWMgb3Bpb2lkcy4gVW5kZXJzdGFuZGluZyB3aGF0IG1ha2VzIGNvbW11bml0aWVzIHZ1bG5lcmFibGUgdG8gdGhlc2UgdHlwZXMgb2Ygb3Bpb2lkcyBpcyBhbiBhcmVhIG9mIGFjdGl2ZSByZXNlYXJjaCBidXQgbm90IGEgZm9jdXMgb2YgdGhpcyBjYXNlIHN0dWR5Lg0KDQojICoqV2hhdCBhcmUgdGhlIGRhdGE/KioNCioqKiANCg0KV2Ugd2lsbCB1c2UgZGF0YSBmcm9tIHR3byBzb3VyY2VzOg0KDQoxLiBUaGUgVVMgY2Vuc3VzIGZvciBsYW5kIGFyZWEgb2YgY291bnRpZXMgdG8gYWxsb3cgdXMgdG8gZXN0aW1hdGUgY291bnR5LWxldmVsIHBvcHVsYXRpb24gZGVuc2l0eS4gVGhpcyB3YXMgb2J0YWluZWQgZnJvbSBbaGVyZV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9saWJyYXJ5L3B1YmxpY2F0aW9ucy8yMDExL2NvbXBlbmRpYS91c2EtY291bnRpZXMtMjAxMS5odG1sI0xORCkgYW5kIGNvbnRhaW5zIGNvdW50eSwgc3RhdGUsIGFuZCBuYXRpb25hbCBsYW5kIGFyZWEgZXN0aW1hdGVzIChmb3IgYSBmZXcgeWVhcnMgaW4gYSBmZXcgZGlmZmVyZW50IHdheXMsIHdlIHdpbGwgZXhwbGFpbiBtb3JlIGFib3V0IHRoYXQgbGF0ZXIpLg0KIA0KDQoyLiBUaGUgW1dhc2hpbmd0b24gUG9zdCBkYXRhXShodHRwczovL3d3dy53YXNoaW5ndG9ucG9zdC5jb20vbmF0aW9uYWwvMjAxOS8wNy8xOC9ob3ctZG93bmxvYWQtdXNlLWRlYS1wYWluLXBpbGxzLWRhdGFiYXNlLykgZnJvbSB0aGUgW0RydWcgRW5mb3JjZW1lbnQgQWRtaW5pc3RyYXRpb24gKERFQSldKGh0dHBzOi8vd3d3LmRlYS5nb3YvKSBhYm91dCBvcGlvaWQgKFtveHljb2RvbmVdKGh0dHBzOi8vd3d3LmRlYS5nb3Yvc2l0ZXMvZGVmYXVsdC9maWxlcy8yMDIwLTA2L094eWNvZG9uZS0yMDIwXzAucGRmKSBhbmQgW2h5ZHJvY29kb25lXShodHRwczovL3d3dy5kZWFkaXZlcnNpb24udXNkb2ouZ292L2RydWdfY2hlbV9pbmZvL2h5ZHJvY29kb25lLnBkZikpIHBpbGwgc2hpcG1lbnRzIHRvIHBoYXJtYWNpZXMgYW5kIHByYWN0aXRpb25lcnMgYXJvdW5kIHRoZSBVUyBhdCB0aGUgY291bnR5LWxldmVsIGZyb20gMjAwNiB0byAyMDE0Lg0KDQpUaGlzIHNlY29uZCBkYXRhc2V0IHdhcyByZWxlYXNlZCBpbiBKdWx5IG9mIDIwMTkgYW5kIGhhcyBiZWVuIGNvbnRyb3ZlcnNpYWwgYXMgYWNjb3JkaW5nIHRvIHRoZSBXYXNoaW5ndG9uIFBvc3Q6DQoNCj4gVGhlIGRpc2Nsb3N1cmUgaXMgcGFydCBvZiBhIGNpdmlsIGFjdGlvbiBicm91Z2h0IGJ5IDIsNTAwIGNpdGllcywgdG93bnMsIGNvdW50aWVzIGFuZCB0cmliYWwgbmF0aW9ucyBhbGxlZ2luZyB0aGF0IG5lYXJseSB0d28gZG96ZW4gZHJ1ZyBjb21wYW5pZXMgKipjb25zcGlyZWQgdG8gc2F0dXJhdGUgdGhlIG5hdGlvbiB3aXRoIG9waW9pZHMqKi4NCg0KU2VlIFtoZXJlXShodHRwczovL3d3dy53YXNoaW5ndG9ucG9zdC5jb20vbmF0aW9uYWwvMjAxOS8wNy8yMC9vcGlvaWQtZmlsZXMvP2FyYzQwND10cnVlKSBmb3IgbW9yZSBkZXRhaWxzIGFib3V0IGhvdyB0aGlzIGRhdGFiYXNlIHdhcyByZWxlYXNlZC4NCg0KVGhpcyBkYXRhIHdhcyBwYXJ0IG9mIHRoZSBbQXV0b21hdGVkIFJlcG9ydHMgYW5kIENvbnNvbGlkYXRlZCBPcmRlcmluZyBTeXN0ZW0gKEFSQ09TKV0oaHR0cHM6Ly93d3cuZGVhZGl2ZXJzaW9uLnVzZG9qLmdvdi9hcmNvcy9yZXRhaWxfZHJ1Z19zdW1tYXJ5Lykgb2YgdGhlIERFQSBpbiB3aGljaDoNCg0KPiBtYW51ZmFjdHVyZXJzIGFuZCBkaXN0cmlidXRvcnMgcmVwb3J0IHRoZWlyIGNvbnRyb2xsZWQgc3Vic3RhbmNlcyB0cmFuc2FjdGlvbnMNCg0KVGhlaXIgW3dlYnNpdGVdKGh0dHBzOi8vd3d3LmRlYWRpdmVyc2lvbi51c2Rvai5nb3YvYXJjb3MvaW5kZXguaHRtbCNiYWNrZ3JvdW5kKSBpbmRpY2F0ZXMgdGhhdDogDQoNCj4gVGhlIENvbnRyb2xsZWQgU3Vic3RhbmNlcyBBY3Qgb2YgMTk3MCBjcmVhdGVkIHRoZSByZXF1aXJlbWVudCBmb3IgTWFudWZhY3R1cmVycyBhbmQgRGlzdHJpYnV0b3JzIHRvIHJlcG9ydCB0aGVpciBjb250cm9sbGVkIHN1YnN0YW5jZXMgdHJhbnNhY3Rpb25zIHRvIHRoZSBBdHRvcm5leSBHZW5lcmFsLiBUaGUgQXR0b3JuZXkgR2VuZXJhbCBkZWxlZ2F0ZXMgdGhpcyBhdXRob3JpdHkgdG8gdGhlIERydWcgRW5mb3JjZW1lbnQgQWRtaW5pc3RyYXRpb24gKERFQSkuDQoNCj4gQVJDT1MgaXMgYW4gYXV0b21hdGVkLCBjb21wcmVoZW5zaXZlIGRydWcgcmVwb3J0aW5nIHN5c3RlbSB3aGljaCBtb25pdG9ycyB0aGUgZmxvdyBvZiBERUEgY29udHJvbGxlZCBzdWJzdGFuY2VzIGZyb20gdGhlaXIgcG9pbnQgb2YgbWFudWZhY3R1cmUgdGhyb3VnaCBjb21tZXJjaWFsIGRpc3RyaWJ1dGlvbiBjaGFubmVscyB0byBwb2ludCBvZiBzYWxlIG9yIGRpc3RyaWJ1dGlvbiBhdCB0aGUgZGlzcGVuc2luZy9yZXRhaWwgbGV2ZWwgLSBob3NwaXRhbHMsIHJldGFpbCBwaGFybWFjaWVzLCBwcmFjdGl0aW9uZXJzLCBtaWQtbGV2ZWwgcHJhY3RpdGlvbmVycywgYW5kIHRlYWNoaW5nIGluc3RpdHV0aW9ucy4gSW5jbHVkZWQgaW4gdGhlIGxpc3Qgb2YgY29udHJvbGxlZCBzdWJzdGFuY2UgdHJhbnNhY3Rpb25zIHRyYWNrZWQgYnkgQVJDT1MgYXJlIHRoZSBmb2xsb3dpbmc6IEFsbCBTY2hlZHVsZXMgSSBhbmQgSUkgbWF0ZXJpYWxzIChtYW51ZmFjdHVyZXJzIGFuZCBkaXN0cmlidXRvcnMpOyBTY2hlZHVsZSBJSUkgbmFyY290aWMgYW5kIGdhbW1hLWh5ZHJveHlidXR5cmljIGFjaWQgKEdIQikgbWF0ZXJpYWxzIChtYW51ZmFjdHVyZXJzIGFuZCBkaXN0cmlidXRvcnMpOyBhbmQgc2VsZWN0ZWQgU2NoZWR1bGUgSUlJIGFuZCBJViBwc3ljaG90cm9waWMgZHJ1Z3MgKG1hbnVmYWN0dXJlcnMgb25seSkuDQoNClRoZSBhbm51YWwgcmVwb3J0IGFib3V0IHRoZSBkYXRhIGZyb20gMjAxOSwgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3d3dy5kZWFkaXZlcnNpb24udXNkb2ouZ292L2FyY29zL3JldGFpbF9kcnVnX3N1bW1hcnkvcmVwb3J0X3lyXzIwMTkucGRmKS4NCg0KQXMgdGhpcyBpcyBhIHZlcnkgbGFyZ2UgZGF0YXNldCwgdGh1cyB0aGUgV2FzaGluZ3RvbiBQb3N0IGNyZWF0ZWQgYW4gW2FwcGxpY2F0aW9uIHByZ29yYW1taW5nIGludGVyZmFjZSAoQVBJKV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQVBJKSAgdG8gbWFrZSBpdCBlYXNpZXIgZm9yIHVzZXJzIHRvIGFjY2VzcyB0aGUgZGF0YS4gDQoNCkFuIEFQSSBpcyBhIGNvbXB1dGF0aW9uYWwgaW50ZXJmYWNlIHRoYXQgc2ltcGxpZmllcyBpbnRlcmFjdGlvbnMgd2l0aCBhIGRhdGEgb3IgZmlsZSBzeXN0ZW0gZm9yIGEgdXNlci4gSXQgaXMgc2ltaWxhciB0byBhIFtHcmFwaGljYWwgVXNlciBJbnRlcmZhY2UgKEdVSSldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dyYXBoaWNhbF91c2VyX2ludGVyZmFjZSksIHlldCBpdCBhbGxvd3MgdGhlIHVzZXIgc29tZSBtb3JlIGZsZXhpYmlsaXR5L2Z1bmN0aW9uYWxpdHkuDQoNClRoaXMgWW91VHViZSB2aWRlbyBnaXZlcyBhbiBvdmVydmlldyBvZiB3aGF0IGFuIEFQSSBpcy4NCg0KPHAgYWxpZ24gPSJjZW50ZXIiPjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvczd3bWlTMm1TWFkiIHRpdGxlPSJZb3VUdWJlIHZpZGVvIHBsYXllciIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+IDwvcD4NCg0KIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PXM3d21pUzJtU1hZKQ0KDQpUaGlzIFtsaW5rXShodHRwczovL2FyY29zLWFwaS5leHQubmlsZS53b3Jrcy9fX3N3YWdnZXJfXy8pIHRha2VzIHlvdSB0byB0aGUgV2FzaGluZ3RvbiBQb3N0IEFSQ09TIEFQSS4gDQoNClRoZXJlIHdhcyBhbHNvIGFuIFIgcGFja2FnZSBvbiBjcmFuIGNhbGxlZCBbYXJjb3NdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3BhY2thZ2U9YXJjb3MpIGZvciBpbnRlcmFjdGluZyB3aXRoIHRoZSBBUEksIGJ1dCB0aGlzIGhhcyBiZWVuIGFyY2hpdmVkLiAgVGhpcyBwYWNrYWdlIGlzIGhvd2V2ZXIgc3RpbGwgYXZhaWxhYmxlIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vd3BpbnZlc3RpZ2F0aXZlL2FyY29zKSBvbiBHaXRIdWIuDQoNClNlZSBbaGVyZV0oaHR0cHM6Ly93d3cud2FzaGluZ3RvbnBvc3QuY29tL25hdGlvbmFsLzIwMTkvMDcvMTgvaG93LWRvd25sb2FkLXVzZS1kZWEtcGFpbi1waWxscy1kYXRhYmFzZS8pIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGhvdyB0byBnZXQgYWNjZXNzIHRoZSBXYXNoaW5ndG9uIFBvc3QgREVBIGRhdGFiYXNlLg0KDQpJbXBvcnRhbnRseSwgdGhlIEFQSSBhbHNvIGluY2x1ZGVzIHBvcHVsYXRpb24gZXN0aW1hdGVzIGZvciB0aGUgeWVhcnMgKDIwMDYgdG8gMjAxNCkgYW5kIGNvdW50aWVzIHdpdGhpbiB0aGUgREVBIGRhdGFiYXNlLg0KDQojICoqRGF0YSBJbXBvcnQqKg0KKioqIA0KDQpOb3RlIHRoYXQgaWYgeW91IGhhdmUgdHJvdWJsZSB3aXRoIHRoZSBkYXRhIGltcG9ydCBmcm9tIHRoZSBBUEksIHdlIGhhdmUgc2F2ZWQgZmlsZXMgYWZ0ZXIgZ2V0dGluZyB0aGUgZGF0YSBmcm9tIHRoZSBBUEkgdGhhdCB5b3UgbWF5IGltcG9ydCBpbnRvIHlvdXIgUiBlbnZpcm9ubWVudCB1c2luZyB0aGUgYE9DU2RhdGFgIHBhY2thZ2UgYW5kIHRoZSBgbG9hZCgpYCBmdW5jdGlvbjoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIGluc3RhbGwucGFja2FnZXMoIk9DU2RhdGEiKQ0KIyBsaWJyYXJ5KE9DU2RhdGEpDQppbXBvcnRlZF9kYXRhKCJvY3MtYnAtb3Bpb2lkLXJ1cmFsLXVyYmFuIiwgb3V0cGF0aCA9IGdldHdkKCkpDQpsb2FkKGhlcmU6OmhlcmUoIk9DU2RhdGEiLCAiZGF0YSIsICJpbXBvcnRlZCIsICJsYW5kX2FyZWEucmRhIikpDQpsb2FkKGhlcmU6OmhlcmUoIk9DU2RhdGEiLCAiZGF0YSIsICJpbXBvcnRlZCIsICJjb3VudHlfcG9wX2FyY29zLnJkYSIpKQ0KbG9hZChoZXJlOjpoZXJlKCJPQ1NkYXRhIiwgImRhdGEiLCAiaW1wb3J0ZWQiLCAiY291bnR5X2FubnVhbC5yZGEiKSkNCmBgYA0KDQpZb3UgbWF5IGFsc28gb2J0YWluIHRoZXNlIGZpbGVzIGZyb20gdGhlIGBkYXRhL2ltcG9ydGVkYCBkaXJlY3Rvcnkgb2Ygb3VyIFtHaXRIdWIgcmVwb3NpdG9yeV0oaHR0cHM6Ly9naXRodWIuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtb3Bpb2lkLXJ1cmFsLXVyYmFuLykuDQoNCiMjICoqTGFuZCBBcmVhKioNCioqKg0KDQpXZSB3aWxsIG5lZWQgY291bnR5IGxhbmQgYXJlYSBkYXRhIGZvciBvdXIgY2FsY3VsYXRpb25zIG9mIHBvcHVsYXRpb24gZGVuc2l0eS4gDQoNCldlIG9idGFpbmVkIGNvdW50eSBsYW5kIGFyZWEgZGF0YSBmcm9tIHRoZSBVUyBjZW5zdXMgQnVyZWF1IGF0IHRoaXMgW2xpbmtdKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvbGlicmFyeS9wdWJsaWNhdGlvbnMvMjAxMS9jb21wZW5kaWEvdXNhLWNvdW50aWVzLTIwMTEuaHRtbCNMTkQpLg0KDQpUaGlzIGRhdGEgY29udGFpbnMgbGFuZCBhcmVhcyAoaW4gYSBmZXcgZGlmZmVyZW50IHdheXMgZm9yIGEgbnVtYmVyIG9mIHllYXJzKSBhdCB0aGUgbmF0aW9uYWwsIHN0YXRlLCBhbmQgY291bnR5IGxldmVsLg0KDQpUaGlzIFtsaW5rXShodHRwczovL3d3dy5jZW5zdXMuZ292L2xpYnJhcnkvcHVibGljYXRpb25zLzIwMTEvY29tcGVuZGlhL3VzYS1jb3VudGllcy0yMDExL2ZpbGUtbGF5b3V0Lmh0bWwpIGV4cGxhaW5zIGhvdyB0aGUgZGF0YSBpcyBmb3JtYXR0ZWQuDQoNCkJhc2VkIG9uIHRoaXMgd2UgZGV0ZXJtaW5lZCB0aGF0IHdlIHdhbnQgdG8gdXNlIHRoZSBgTE5EMTEwMjEwRGAgY29sdW1uIHdoaWNoIGlzIHRoZSBkYXRhIGZyb20gdGhlIHllYXIgMjAxMC4NCg0KTGV0J3MgYnJlYWsgdGhpcyBkb3duIHRvIHVuZGVyc3RhbmQgdGhlIG1lYW5pbmcgb2YgdGhlIGNvbHVtbi4gDQoNCi0gTE5EID0gTGFuZCBBcmVhDQotIDExMCA9IExhbmQgQXJlYSB1bml0IGluIHNxdWFyZSBtaWxlcyAoc3ViZ3JvdXAtY29kZSBvZiB0aGUgZ3JvdXApDQotIDIgPSBjZW50dXJ5DQotIDEwID0gMjAxMCAoYmFzZWQgb24gdGhlIGNlbnR1cnkpDQotIEQgPSBEYXRhDQoNCldlIHdpbGwgdXNlIHRoZSBgcmVhZF9leGNlbCgpYCBmdW5jdGlvbiBvZiB0aGUgYHJlYWR4bGAgcGFja2FnZSB0byBpbXBvcnQgdGhlIGRhdGEuIFdlIHdpbGwgYWxzbyBjb252ZXJ0IHRoZSBkYXRhIGludG8gYSBbdGliYmxlXShodHRwczovL3RpYmJsZS50aWR5dmVyc2Uub3JnLykgKHdoaWNoIGlzIGEgdGhlIHRpZHl2ZXJzZSB2ZXJzaW9uIG9mIGEgZGF0YSBmcmFtZSkgYnkgdXNpbmcgdGhlIGBhc190aWJibGUoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWJibGVgIHBhY2thZ2UuIA0KDQpJZiB5b3UgZGlkIG5vdCBjbG9uZSBvdXIgZ2l0aHViIHJlcG9zaXRvcnkgb3IgZG8gbm90IGhhdmUgdGhpcyBkYXRhIGFscmVhZHksIHlvdSBtYXkgZG93bmxvYWQgdGhpcyBkYXRhIHVzaW5nIHRoZSBgT0NTZGF0YWAgcGFja2FnZToNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIGluc3RhbGwucGFja2FnZXMoIk9DU2RhdGEiKQ0KIyBsaWJyYXJ5KE9DU2RhdGEpDQoNCnJhd19kYXRhKCJvY3MtYnAtb3Bpb2lkLXJ1cmFsLXVyYmFuIiwgb3V0cGF0aCA9IGdldHdkKCkpDQojIFRoaXMgZnVuY3Rpb24gY3JlYXRlcyBhICJPQ1NkYXRhIiBzdWItZGlyZWN0b3J5IGluIHlvdXIgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4NCiMgSXQgYWxzbyBjcmVhdGVzIGEgInJhdyIgc3ViLWRpcmVjdG9yeSB3aXRoaW4gImRhdGEiIHdoaWNoIGNvbnRhaW5zIHRoZSAueGxzIGZpbGUuDQpgYGANCg0KSW4gb3VyIGNhc2UsIHdlIGRvd25sb2FkZWQgdGhpcyBkYXRhIGFuZCBwdXQgaXQgd2l0aGluIGEgInJhdyIgc3ViZGlyZWN0b3J5IG9mIGEgImRhdGEiIGRpcmVjdG9yeSBmb3Igb3VyIHByb2plY3QuIElmIHlvdSB1c2UgYW4gUlN0dWRpbyBwcm9qZWN0LCB0aGVuIHlvdSBjYW4gdXNlIHRoZSBgaGVyZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGhlcmVgIHBhY2thZ2UgdG8gbWFrZSB0aGUgcGF0aCBmb3IgaW1wb3J0aW5nIHRoaXMgZGF0YSBzaW1wbGVyLiBUaGUgYGhlcmVgIHBhY2thZ2UgYXV0b21hdGljYWxseSBzdGFydHMgbG9va2luZyBmb3IgZmlsZXMgYmFzZWQgb24gd2hlcmUgeW91IGhhdmUgYSBgLlJwcm9qYCBmaWxlIHdoaWNoIGlzIGNyZWF0ZWQgd2hlbiB5b3Ugc3RhcnQgYSBuZXcgUlN0dWRpbyBwcm9qZWN0LiBXZSBjYW4gc3BlY2lmeSB0aGF0IHdlIHdhbnQgdG8gbG9vayBmb3IgdGhlICJMTkQwMS54bHMiIGZpbGUgd2l0aGluIHRoZSAicmF3IiBkaXJlY3Rvcnkgd2l0aGluIHRoZSAiZGF0YSIgZGlyZWN0b3J5IHdoZXJlIG91ciBgLlJwcm9qYCBmaWxlIGlzIGxvY2F0ZWQgYnkgc2VwYXJhdGluZyB0aGUgbmFtZXMgb2YgdGhlc2UgZGlyZWN0b3JpZXMgdXNpbmcgY29tbWFzIGFuZCBsaXN0aW5nICJkYXRhIiBmaXJzdC4gDQoNCioqKg0KPGRldGFpbHM+IDxzdW1tYXJ5PkNsaWNrIGhlcmUgdG8gc2VlIG1vcmUgYWJvdXQgY3JlYXRpbmcgbmV3IHByb2plY3RzIGluIFIgPC9zdW1tYXJ5Pg0KDQpZb3UgY2FuIGNyZWF0ZSBhIHByb2plY3QgYnkgZ29pbmcgdG8gdGhlIEZpbGUgbWVudSBvZiBSU3R1ZGlvIGxpa2Ugc286DQoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJOZXdfcHJvamVjdC5wbmciKSkNCmBgYA0KDQpZb3UgY2FuIGFsc28gZG8gc28gYnkgY2xpY2tpbmcgdGhlIHByb2plY3QgYnV0dG9uOg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInByb2plY3RfYnV0dG9uLnBuZyIpKQ0KYGBgDQoNCg0KU2VlIFtoZXJlXShodHRwczovL3N1cHBvcnQucnN0dWRpby5jb20vaGMvZW4tdXMvYXJ0aWNsZXMvMjAwNTI2MjA3LVVzaW5nLVByb2plY3RzKSB0byBsZWFybiBtb3JlIGFib3V0IHVzaW5nIFJTdHVkaW8gcHJvamVjdHMuIA0KDQo8L2RldGFpbHM+DQoNCioqKg0KDQpgYGB7cn0NCmxhbmQgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKGhlcmU6OmhlcmUoImRhdGEiLCAicmF3IiwgIkxORDAxLnhscyIpKQ0KbGFuZCA8LSBhc190aWJibGUobGFuZCkNCmBgYA0KDQpXZSBjYW4gdGFrZSBhIGxvb2sgYXQgdGhlIGRhdGEgdXNpbmcgdGhlIGJhc2UgYGhlYWQoKWAgZnVuY3Rpb24gd2hpY2ggd2lsbCBzaG93IHRoZSBmaXJzdCAzIHJvd3MuDQoNCmBgYHtyfQ0KaGVhZChsYW5kLCBuPTMpDQpgYGANCg0KSW5kZWVkLCB0aGlzIGxvb2tzIGFzIGV4cGVjdGVkIHdpdGggYm90aCB0aGUgVVMsIHN0YXRlLCBhbmQgY291bnR5IGxldmVsIGxhbmQgYXJlYXMuIFdlIHdpbGwgbG9vayBpbnRvIHRoaXMgZnVydGhlciBpbiBsYXRlciBzZWN0aW9ucy4NCg0KTG9va3MgZ29vZCENCg0KTm93IHdlIHdpbGwgc2F2ZSBvdXIgZGF0YSBpbiB0aGUgZGF0YSBkaXJlY3Rvcnkgd2l0aGluIGEgc3ViZGlyZWN0b3J5IGNhbGxlZCAiaW1wb3J0ZWQiOg0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQojIGZvciBpbnN0cnVjdG9ycyB3aG8gd2FudCB0byBkbyBhIHNpbXBsZXIgdmVyc2lvbiBvZiBpbXBvcnQNCndyaXRlLmNzdihsYW5kLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJzaW1wbGVyX2ltcG9ydCIsICJsYW5kX2FyZWEuY3N2IikpDQpgYGANCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCnNhdmUobGFuZCwgZmlsZSA9ICBoZXJlOjpoZXJlKCJkYXRhIiwgImltcG9ydGVkIiwgImxhbmRfYXJlYS5yZGEiKSkNCmBgYA0KDQoNCiMjICoqQWNjZXNzaW5nIGRhdGEgd2l0aCBBUElzKioNCioqKg0KDQpUaGUgYGh0dHJgIHBhY2thZ2UgY3JlYXRlcyB3aGF0IGFyZSBjYWxsZWQgIkdFVCByZXF1ZXN0cyIgc28gdGhhdCB3ZSBjYW4gbWFrZSB0aGVzZSByZXF1ZXN0cyBpbnNpZGUgb2YgUi4gVGhpcyBhbGxvd3MgZm9yIHRoZSBkYXRhIHRvIGJlIHJldHJpZXZlZCBmcm9tIHRoZSBBUEkgd2l0aGluIFIuDQoNClRoZSBganNvbmxpdGVgIHBhY2thZ2UgYWxsb3dzIHlvdSB0byBjb252ZXJ0IHRoZSBkYXRhIGZyb20gYEpTT05gIChvZnRlbiB1c2VkIGJ5IEFQSXMpIHRvIGEgZGlmZmVyZW50IGZvcm1hdCB0aGF0IGlzIGVhc2llciB0byB3b3JrIHdpdGguDQoNCkFQSXMgdHlwaWNhbGx5IHJlcXVpcmUgYSBwYXNzd29yZCBvciBrZXkgdG8gZ2FpbiBhY2Nlc3Mgb3IgYXV0aGVudGljYXRlIHlvdXIgZGF0YSByZXF1ZXN0LiBUaGUgYGh0dHJgIHBhY2thZ2UgaGVscHMgdG8gYXV0aGVudGljYXRlIHlvdXIgZGF0YSByZXF1ZXN0LiBPZnRlbiB0aGVzZSBrZXlzIGFyZSBzb21ldGhpbmcgdGhhdCB5b3UgZG8gbm90IHdhbnQgdG8gc2hhcmUsIHVubGVzcyB0aGUgQVBJIGlzIHB1YmxpYy4NCg0KSW4gb3VyIGNhc2UgdGhlIFtBUEldKGh0dHBzOi8vYXJjb3MtYXBpLmV4dC5uaWxlLndvcmtzL19fc3dhZ2dlcl9fLykgaXMgaW5kZWVkIHB1YmxpYywgYW5kIGN1cnJlbnRseSAidU80RUs2SSIgaXMgcHVibGljbHkgcHVibGlzaGVkIGFzIGEga2V5IHRvIHVzZSBvbiB0aGUgW2dpdGh1YiBwYWdlXShodHRwczovL2dpdGh1Yi5jb20vd3BpbnZlc3RpZ2F0aXZlL2FyY29zKSBmb3IgdGhlIGBhcmNvc2AgcGFja2FnZS4gV2Ugd2lsbCB1c2UgdGhhdCBoZXJlIHRvIGFjY2VzcyB0aGUgQVBJLg0KDQoNCiMjICoqQ291bnR5IFBvcHVsYXRpb24gRGF0YSoqDQoqKioNCg0KV2UgYXJlIGludGVyZXN0ZWQgaW4gdGhlIGNvdW50eSBsZXZlbCBkYXRhLiBDb252ZW5pZW50bHksIHRoZSBBUEkgYWxzbyBpbmNsdWRlcyBjb3VudHktbGV2ZWwgcG9wdWxhdGlvbiBkYXRhICh0aGUgbnVtYmVyIG9mIHBlb3BsZSBwZXIgY291bnR5IGluIGVhY2ggc3RhdGUgaW4gdGhlIFVTIGZyb20gMjAwNiB0byAyMDE0KQ0KDQpXZSBjYW4gYWNjZXNzIGl0IGZyb20gdGhlIEFQSSBieToNCg0KMS4gUHJlc3NpbmcgdGhlIGBHRVRgIGJ1dHRvbiBvbiB0aGUgQVBJLg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJnZXQucG5nIikpDQoNCmBgYA0KDQoyLiBQcmVzc2luZyB0aGUgIlRyeSBpdCBvdXQiIGJ1dHRvbi4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAidHJ5aXRvdXQucG5nIikpDQpgYGANCg0KMy4gRW50ZXJpbmcgdGhlIGtleSAod2hpY2ggd2UgZ290IGZyb20gW2hlcmVdKFtnaXRodWIgcGFnZV0oaHR0cHM6Ly9naXRodWIuY29tL3dwaW52ZXN0aWdhdGl2ZS9hcmNvcykpKS4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAia2V5LnBuZyIpKQ0KYGBgDQoNCjQuIENsaWNraW5nIHRoZSAiRXhlY3V0ZSIgYnV0dG9uLg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJleGVjdXRlLnBuZyIpKQ0KYGBgDQoNClRoaXMgZ2l2ZXMgdXMgdGhlIGZvbGxvd2luZyBvdXRwdXQ6DQoNCmBjdXJsIC1YIEdFVCAiaHR0cHM6Ly9hcmNvcy1hcGkuZXh0Lm5pbGUud29ya3MvdjEvY291bnR5X3BvcHVsYXRpb24/a2V5PXVPNEVLNkkiIC1IICAiYWNjZXB0OiBhcHBsaWNhdGlvbi9qc29uImANCg0KV2UgY2FuIGNvcHkgdGhlIFVSTCBzZWN0aW9uIGAiaHR0cHM6Ly9hcmNvcy1hcGkuZXh0Lm5pbGUud29ya3MvdjEvY291bnR5X3BvcHVsYXRpb24/a2V5PXVPNEVLNkkiYCBhbmQgdXNlIGl0IGluIHRoZSBgR0VUKClgIGZ1bmN0aW9uIG9mIHRoZSBgaHR0cmAgcGFja2FnZSA6DQoNCmBgYHtyfQ0KY291bnRfdXJsIDwtICJodHRwczovL2FyY29zLWFwaS5leHQubmlsZS53b3Jrcy92MS9jb3VudHlfcG9wdWxhdGlvbj9rZXk9dU80RUs2SSINCg0KY291bnR5X3BvcF9qc29uIDwtIA0KICBodHRyOjpHRVQodXJsID0gY291bnRfdXJsKQ0KYGBgDQoNCklmIHdlIG5lZWRlZCB0byBzcGVjaWZ5IGEgdXNlcm5hbWUgYW5kIHBhc3N3b3JkLCB3ZSB3b3VsZCBkbyBzbyB1c2luZyB0aGUgYGF1dGhlbnRpY2F0ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGh0dHJgIHBhY2thZ2Ugd2l0aGluIHRoZSBgR0VUYCBmdW5jdGlvbi4gVGhlIGBhdXRoZW50aWNhdGUoKWAgZnVuY3Rpb24gdGFrZXMgYHVzZXJgLCBgcGFzc3dvcmRgIGFuZCBgdHlwZWAgYXJndW1lbnRzLg0KDQpIZXJlIGlzIGFuIGV4YW1wbGU6DQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQpHRVQodXJsID0gImh0dHBzOi8vZXhhbXBsZVVSTCIsIA0KICAgIGF1dGhlbnRpY2F0ZSh1c2VyID0gInVzZXJuYW1lIiwgDQogICAgICAgICAgICAgICAgIHBhc3N3b3JkID0gInBhc3N3b3JkIiwgDQogICAgICAgICAgICAgICAgIHR5cGUgPSAiYmFzaWMiKSkNCmBgYA0KDQpUaGUgZGVmYXVsdCBhdXRoZW50aWNhdGlvbiByZXF1ZXN0IHR5cGUgaXMgYCJiYXNpYyJgIGFuZCB0eXBpY2FsbHkgd2hhdCBpcyBuZWVkZWQuDQoNCk5vdyB0aGF0IHdlIGhhdmUgdXNlZCB0aGUgYEdFVGAgZnVuY3Rpb24sIGxldCdzIHNlZSB3aGF0IHRoZSBkYXRhIGFyZS4gDQoNCmBgYHtyfQ0KY291bnR5X3BvcF9qc29uDQpgYGANCg0KSGVyZSB3ZSBjYW4gc2VlIHRoYXQgdGhlIG9iamVjdCBjYWxsZWQgYGNvdW50eV9wb3BfanNvbmAgaXMgYSBganNvbmAgb2JqZWN0LiANCkEgW0phdmFTY3JpcHQgT2JqZWN0IE5vdGF0aW9uIChKU09OKV0oaHR0cHM6Ly9maWxlaW5mby5jb20vZXh0ZW5zaW9uL2pzb24jOn46dGV4dD1BJTIwSlNPTiUyMGZpbGUlMjBpcyUyMGEsd2ViJTIwYXBwbGljYXRpb24lMjBhbmQlMjBhJTIwc2VydmVyLikgb2JqZWN0IChvciBmaWxlIGZvcm1hdCkgaXMgW2xpZ2h0d2VpZ2h0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MaWdodHdlaWdodF9wcm9ncmFtbWluZ19sYW5ndWFnZSkgbWVhbmluZyB0aGF0IGl0IGRvZXMgbm90IHRha2UgdXAgbXVjaCBtZW1vcnkgYW5kIHRoZXkgYXJlIGh1bWFuIHJlYWRhYmxlIGZpbGVzIHRvIG1ha2UgdHJhbnNtaXR0aW5nIGRhdGEgZnJvbSB3ZWJzaXRlcyBlYXNpZXIuDQoNCllvdSB3aWxsIGFsc28gc2VlIHRoYXQgdGhlIGBTdGF0dXNgIGlzIGAyMDBgLCB3aGljaCBtZWFucyB0aGF0IHdlIHdlcmUgc3VjY2Vzc2Z1bCBpbiByZXRyaWV2aW5nIHRoZSBkYXRhIGZyb20gdGhlIEFQSS4NCg0KTm93IHdlIGNhbiB1c2UgdGhlIGBjb250ZW50KClgIGZ1bmN0aW9uIG9mIHRoZSBgaHR0cmAgcGFja2FnZSB0byBleHRyYWN0IHRoZSB0ZXh0IGZyb20gdGhlIGZpbGU6DQoNCmBgYHtyfQ0KY291bnR5X3BvcF90ZXh0IDwtIA0KICBodHRyOjpjb250ZW50KGNvdW50eV9wb3BfanNvbiwgInRleHQiKQ0KYGBgDQoNClRoaXMgd2lsbCBiZSBhIHZlcnkgbGFyZ2Ugc3RyaW5nIGF0IHRoaXMgcG9pbnQsIHdlIGNhbiB0YWtlIGEgbG9vayBhdCBwYXJ0IG9mIGl0IGJ5IHVzaW5nIHRoZSBgc3RyX3N1YigpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIEluIHRoaXMgY2FzZSB3ZSB3aWxsIG9ubHkgbG9vayBhdCB0aGUgZmlyc3QgNDAwIGNoYXJhY3RlcnMuDQoNCldoYXQgaXMgYSBzdHJpbmcgb3IgYSBjaGFyYWN0ZXI/DQoNCioqKg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciBhbiBleHBsYW5hdGlvbiBhYm91dCBjaGFyYWN0ZXIgc3RyaW5ncyBpZiB5b3UgYXJlIG5vdCB5ZXQgZmFtaWxpYXIgPC9zdW1tYXJ5Pg0KDQpUaGVyZSBhcmUgc2V2ZXJhbCBjbGFzc2VzIG9mIGRhdGEgaW4gUiBwcm9ncmFtbWluZy4gDQpDaGFyYWN0ZXIgaXMgb25lIG9mIHRoZXNlIGNsYXNzZXMuIA0KQSBjaGFyYWN0ZXIgc3RyaW5nIGlzIGFuIGluZGl2aWR1YWwgZGF0YSB2YWx1ZSBtYWRlIHVwIG9mIGNoYXJhY3RlcnMuIA0KVGhpcyBjYW4gYmUgYSBwYXJhZ3JhcGgsIGxpa2UgdGhlIGxlZ2VuZCBmb3IgdGhlIHRhYmxlLCBvciBpdCBjYW4gYmUgYSBzaW5nbGUgbGV0dGVyIG9yIG51bWJlciBsaWtlIHRoZSBsZXR0ZXIgYCJhImAgb3IgdGhlIG51bWJlciBgIjMiYC4gDQoNCklmIGRhdGEgYXJlIG9mIGNsYXNzIGNoYXJhY3RlciwgdGhhbiB0aGUgbnVtZXJpYyB2YWx1ZXMgd2lsbCBub3QgYmUgcHJvY2Vzc2VkIGxpa2UgYSBudW1lcmljIHZhbHVlIGluIGEgbWF0aGVtYXRpY2FsIHNlbnNlLiANCg0KPC9kZXRhaWxzPg0KKioqDQoNCmBgYHtyfQ0Kc3RyaW5ncjo6c3RyX3N1Yihjb3VudHlfcG9wX3RleHQsIHN0YXJ0ID0gMSwgZW5kID0gNDAwKQ0KYGBgDQoNCg0KVG8gZ2V0IHRoZSBkYXRhIGludG8gYSBtb3JlIHJlYWRhYmxlIGZvcm1hdCwgd2UgY2FuIHVzZSB0aGUgYGZyb21KU09OKClgIGZ1bmN0aW9uIG9mIHRoZSBganNvbmxpdGVgIHBhY2thZ2UgYW5kIGFnYWluIGNyZWF0ZSBhIHRpYmJsZSBvZiB0aGUgZGF0YSB1c2luZyBgYXNfdGliYmxlKClgIA0KDQpgYGB7cn0NCmNvdW50eV9wb3AgPC0gDQogIGpzb25saXRlOjpmcm9tSlNPTihjb3VudHlfcG9wX3RleHQsIA0KICAgICAgICAgICAgICAgICAgICAgZmxhdHRlbiA9IFRSVUUpDQoNCmNvdW50eV9wb3AgPC0gYXNfdGliYmxlKGNvdW50eV9wb3ApDQpgYGANCg0KV2UgY2FuIHVzZSB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gYW5kIHRoZSBgZGlzdGluY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBnZXQgYSBiZXR0ZXIgc2Vuc2Ugb2YgdGhlIGRhdGEuIFRoZSBgZGlzdGluY3QoKWAgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIHRha2UgYSBsb29rIGF0IHRoZSB1bmlxdWUgdmFsdWVzIG9mIHRoZSBgeWVhcmAgdmFyaWFibGUuDQoNCmBgYHtyfQ0KZHBseXI6OmdsaW1wc2UoY291bnR5X3BvcCkNCmRwbHlyOjpkaXN0aW5jdChjb3VudHlfcG9wLCB5ZWFyKQ0KYGBgDQoNCkl0IGxvb2tzIGxpa2Ugd2UgaGF2ZSB0aGUgZnVsbCBkYXRhIGZyb20gMjAwNi0yMDE0Lg0KDQpOb3cgbGV0J3Mgc2F2ZSB0aGlzIGRhdGE6DQoNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCiMgRm9yIGluc3RydWN0b3JzIHdobyB3YW50IHRvIGRvIGEgc2ltcGxlciB2ZXJzaW9uIG9mIGltcG9ydA0Kd3JpdGUuY3N2KGNvdW50eV9wb3AsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgInNpbXBsZXJfaW1wb3J0IiwgImNvdW50eV9wb3BfYXJjb3MuY3N2IikpDQpgYGANCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCnNhdmUoY291bnR5X3BvcCwgZmlsZSA9ICBoZXJlOjpoZXJlKCJkYXRhIiwgImltcG9ydGVkIiwgICJjb3VudHlfcG9wX2FyY29zLnJkYSIpKQ0KYGBgDQoNCg0KIyMgKipBbm51YWwgU2hpcG1lbnQgRGF0YSoqDQoqKioNCg0KV2UgYXJlIGFsc28gaW50ZXJlc3RlZCBpbiB0aGUgbnVtYmVyIG9mIG9waW9pZCBwaWxsIHNoaXBwZWQgYXQgdGhlIGNvdW50eSBsZXZlbC4gDQoNCkhlcmUgaXMgdGhlIHJlc3VsdCBvZiB0aGUgc2FtZSBzdGVwcyB1c2luZyB0aGUgQVBJIGZvciB0aGUgYGNvbWJpbmVkX2NvdW50eV9hbm51YWxgIGRhdGE6DQoNCmBgYA0KY3VybCAtWCBHRVQgImh0dHBzOi8vYXJjb3MtYXBpLmV4dC5uaWxlLndvcmtzL3YxL2NvbWJpbmVkX2NvdW50eV9hbm51YWw/a2V5PXVPNEVLNkkiIA0KICAgICAtSCAgImFjY2VwdDogYXBwbGljYXRpb24vanNvbiINCmBgYCAgICAgDQoNCm9yIGluIFIsIHRoZSBVUkwgaXMgDQoNCmBgYHtyfQ0KYW5udWFsX3VybCA8LSANCiAgImh0dHBzOi8vYXJjb3MtYXBpLmV4dC5uaWxlLndvcmtzL3YxL2NvbWJpbmVkX2NvdW50eV9hbm51YWw/a2V5PXVPNEVLNkkiDQpgYGANCg0KDQojIyMjIHsucmVjYWxsX2NvZGVfcXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KU2VlIGlmIHlvdSBjYW4gbW9kaWZ5IHRoZSBpbXBvcnQgY29kZSB3aXRob3V0IGxvb2tpbmcgYXQgdGhlIGNvZGUgZm9yIHRoZSBwb3B1bGF0aW9uIGRhdGEuDQoNCiMjIyMNCg0KKioqDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCmNvdW50eV9hbm51YWxfanNvbiA8LSANCiAgaHR0cjo6R0VUKHVybCA9ICBhbm51YWxfdXJsKQ0KDQpjb3VudHlfYW5udWFsX2pzb25fdGV4dCA8LSANCiAgaHR0cjo6Y29udGVudChjb3VudHlfYW5udWFsX2pzb24sICJ0ZXh0IikNCg0KY291bnR5X2FubnVhbCA8LSANCiAganNvbmxpdGU6OmZyb21KU09OKGNvdW50eV9hbm51YWxfanNvbl90ZXh0LCBmbGF0dGVuID0gVFJVRSkNCg0KYW5udWFsRG9zYWdlIDwtIA0KICB0aWJibGU6OmFzX3RpYmJsZShjb3VudHlfYW5udWFsKQ0KYGBgDQoNCjwvZGV0YWlscz4NCg0KKioqDQoNCk5vdyB3ZSB3aWxsIGFsc28gc2F2ZSB0aGlzIGRhdGE6DQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIGV2YWwgPSBGQUxTRX0NCiMgZm9yIGluc3RydWN0b3JzIHdobyB3YW50IHRvIGRvIGEgc2ltcGxlciB2ZXJzaW9uIG9mIGltcG9ydA0Kd3JpdGUuY3N2KGFubnVhbERvc2FnZSwgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAic2ltcGxlcl9pbXBvcnQiLCAiY291bnR5X2FubnVhbC5jc3YiKSkNCmBgYA0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0Kc2F2ZShhbm51YWxEb3NhZ2UsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgImltcG9ydGVkIiwgImNvdW50eV9hbm51YWwucmRhIikpDQpgYGANCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmxvYWQoaGVyZTo6aGVyZSgiZGF0YSIsICJpbXBvcnRlZCIsICJjb3VudHlfYW5udWFsLnJkYSIpKQ0KYGBgDQoNCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgZGF0YToNCmBgYHtyfQ0KZ2xpbXBzZShhbm51YWxEb3NhZ2UpDQpkaXN0aW5jdChhbm51YWxEb3NhZ2UsIHllYXIpDQpgYGANCg0KTG9va3MgbGlrZSB3ZSBoYXZlIHRoZSBzYW1lIHllYXJzIG9mIGRhdGEuDQoNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCiMgV2UgYWxzbyByZXRyaWV2ZWQgdGhlIG1vbnRobHkgZGF0YSBmb3IgaW5zdHJ1Y3RvcnMgd2hvIHdpc2ggdG8gdXNlIHRoaXMgZGF0YQ0KY291bnR5anNvbiA8LSANCiAgaHR0cjo6R0VUKHVybCA9ICJodHRwczovL2FyY29zLWFwaS5leHQubmlsZS53b3Jrcy92MS9jb21iaW5lZF9jb3VudHlfbW9udGhseT9rZXk9dU80RUs2SSIpDQoNCmNvdW50eWpzb25fdGV4dCA8LSANCiAgaHR0cjo6Y29udGVudChjb3VudHlqc29uLCAidGV4dCIpDQoNCmNvdW50eSA8LSANCiAganNvbmxpdGU6OmZyb21KU09OKGNvdW50eWpzb25fdGV4dCwgZmxhdHRlbiA9IFRSVUUpDQoNCm1vbnRobHlEb3NhZ2UgPC0gDQogIHRpYmJsZTo6YXNfdGliYmxlKGNvdW50eSkNCg0KIyBmb3IgaW5zdHJ1Y3RvcnMgd2hvIHdhbnQgdG8gZG8gYSBzaW1wbGVyIHZlcnNpb24gb2YgaW1wb3J0DQp3cml0ZS5jc3YobW9udGhseURvc2FnZSwgDQogICAgICAgICAgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCJleHRyYSIsICJjb3VudHlfbW9udGhseS5jc3YiKSkNCg0Kc2F2ZShtb250aGx5RG9zYWdlLCANCiAgICAgZmlsZSA9ICBoZXJlOjpoZXJlKCJkYXRhIiwgImV4dHJhIiwgImNvdW50eV9tb250aGx5LnJkYSIpKQ0KYGBgDQoNCg0KIyAqKkRhdGEgRXhwbG9yYXRpb24qKg0KKioqDQoNCklmIHlvdSBoYXZlIGJlZW4gZm9sbG93aW5nIGFsb25nIGJ1dCBzdG9wcGVkLCB3ZSBjb3VsZCBsb2FkIG91ciBpbXBvcnRlZCBkYXRhIGZyb20gdGhlICJkYXRhIiBkaXJlY3RvcnkgbGlrZSBzbzoNCg0KYGBge3J9DQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAibGFuZF9hcmVhLnJkYSIpKQ0KbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgImltcG9ydGVkIiwgImNvdW50eV9wb3BfYXJjb3MucmRhIikpDQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAiY291bnR5X2FubnVhbC5yZGEiKSkNCmBgYA0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gSWYgeW91IHNraXBwZWQgdGhlIGRhdGEgaW1wb3J0IHNlY3Rpb24gY2xpY2sgaGVyZS4gPC9zdW1tYXJ5Pg0KDQpGaXJzdCB5b3UgbmVlZCB0byBpbnN0YWxsIGFuZCBsb2FkIHRoZSBgT0NTZGF0YWAgcGFja2FnZToNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQppbnN0YWxsLnBhY2thZ2VzKCJPQ1NkYXRhIikNCmxpYnJhcnkoT0NTZGF0YSkNCmBgYA0KDQpUaGVuLCB5b3UgbWF5IGxvYWQgdGhlIGltcG9ydGVkIGRhdGEgaW50byB5b3VyIFIgZW52aXJvbm1lbnQgdXNpbmcgdGhlIGZvbGxvd2luZyBjb2RlOg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmltcG9ydGVkX2RhdGEoIm9jcy1icC1vcGlvaWQtcnVyYWwtdXJiYW4iLCBvdXRwYXRoID0gZ2V0d2QoKSkNCmxvYWQoaGVyZTo6aGVyZSgiT0NTZGF0YSIsICJkYXRhIiwgImltcG9ydGVkIiwgImxhbmRfYXJlYS5yZGEiKSkNCmxvYWQoaGVyZTo6aGVyZSgiT0NTZGF0YSIsICJkYXRhIiwgImltcG9ydGVkIiwgImNvdW50eV9wb3BfYXJjb3MucmRhIikpDQpsb2FkKGhlcmU6OmhlcmUoIk9DU2RhdGEiLCAiZGF0YSIsICJpbXBvcnRlZCIsICJjb3VudHlfYW5udWFsLnJkYSIpKQ0KYGBgDQoNCkFsdGVybmF0aXZlbHksIHlvdSBtYXkgZG93bmxvYWQgdGhlIHJhdyBkYXRhIGFzIHdlbGwgYXMgdGhlIENTViBmaWxlcyBmb3Igc2ltcGxlciBpbXBvcnQgdXNpbmcgdGhlIGZvbGxvd2luZyBmdW5jdGlvbjoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpzaW1wbGVyX2ltcG9ydF9kYXRhKCJvY3MtYnAtb3Bpb2lkLXJ1cmFsLXVyYmFuIiwgb3V0cGF0aCA9IGdldHdkKCkpDQpgYGANCg0KSWYgdGhlIHBhY2thZ2UgZG9lcyBub3Qgd29yayBmb3IgeW91LCB0aGUgUkRBIGZpbGVzIChzdGFuZHMgZm9yIFIgZGF0YSkgb2YgdGhlIGRhdGEgY2FuIGJlIGZvdW5kIGluIG91ciBbR2l0SHViIHJlcG9zaXRvcnldKGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLW9waW9pZC1ydXJhbC11cmJhbi90cmVlL21hc3Rlci9kYXRhL2ltcG9ydGVkKS4gRG93bmxvYWQgdGhlc2UgZmlsZXMgYW5kIHRoZW4gcGxhY2UgdGhlbSBpbiB5b3VyIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnkgd2l0aGluIGEgc3ViZGlyZWN0b3J5IGNhbGxlZCAiaW1wb3J0ZWQiIHdpdGhpbiBhIHN1YmRpcmVjdG9yeSBjYWxsZWQgImRhdGEiIHRvIGNvcHkgYW5kIHBhc3RlIG91ciBjb2RlLiBXZSB1c2VkIGFuIFJTdHVkaW8gcHJvamVjdCBhbmQgdGhlIFtgaGVyZWAgcGFja2FnZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSB0byBuYXZpZ2F0ZSB0byB0aGUgZmlsZXMgbW9yZSBlYXNpbHkuIA0KDQpgYGB7cn0NCmxvYWQoaGVyZTo6aGVyZSgiZGF0YSIsICJpbXBvcnRlZCIsICJsYW5kX2FyZWEucmRhIikpDQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAiY291bnR5X3BvcF9hcmNvcy5yZGEiKSkNCmxvYWQoaGVyZTo6aGVyZSgiZGF0YSIsICJpbXBvcnRlZCIsICJjb3VudHlfYW5udWFsLnJkYSIpKQ0KYGBgDQoNCioqKg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBtb3JlIGFib3V0IGNyZWF0aW5nIG5ldyBwcm9qZWN0cyBpbiBSU3R1ZGlvLiA8L3N1bW1hcnk+DQoNCllvdSBjYW4gY3JlYXRlIGEgcHJvamVjdCBieSBnb2luZyB0byB0aGUgRmlsZSBtZW51IG9mIFJTdHVkaW8gbGlrZSBzbzoNCg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiTmV3X3Byb2plY3QucG5nIikpDQpgYGANCg0KWW91IGNhbiBhbHNvIGRvIHNvIGJ5IGNsaWNraW5nIHRoZSBwcm9qZWN0IGJ1dHRvbjoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInByb2plY3RfYnV0dG9uLnBuZyIpKQ0KYGBgDQoNClNlZSBbaGVyZV0oaHR0cHM6Ly9zdXBwb3J0LnJzdHVkaW8uY29tL2hjL2VuLXVzL2FydGljbGVzLzIwMDUyNjIwNy1Vc2luZy1Qcm9qZWN0cykgdG8gbGVhcm4gbW9yZSBhYm91dCB1c2luZyBSU3R1ZGlvIHByb2plY3RzIGFuZCBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSB0byBsZWFybiBtb3JlIGFib3V0IHRoZSBgaGVyZWAgcGFja2FnZS4NCg0KPC9kZXRhaWxzPg0KKioqDQo8L2RldGFpbHM+DQoNCioqKg0KDQpOb3cgbGV0J3MgdGFrZSBhIGRlZXBlciBsb29rIGF0IHRoZSBkYXRhIHRvIHNlZSBpZiB3ZSBoYXZlIGFueSBtaXNzaW5nIGRhdGEgdXNpbmcgdGhlIGBuYW5pYXJgIHBhY2thZ2UuDQoNCldlIGNhbiB1c2UgdGhlIGB2aXNfbWlzcygpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSBwbG90IG9mIG1pc3NpbmcgZGF0YSwgd2hpY2ggd2lsbCB1c2UgYSBoZWF0bWFwIHRvIHNob3cgaWYgdGhlcmUgYXJlIG1pc3NpbmcgZGF0YSAoYmxhY2spIG9yIG5vIG1pc3NpbmcgZGF0YSAoZ3JheSkuIA0KDQpMZXQncyBzdGFydCB3aXRoIHRoZSBsYW5kIGFyZWEgZGF0YS4NCmBgYHtyfQ0KbmFuaWFyOjogdmlzX21pc3MobGFuZCkNCmBgYA0KTG9va3MgbGlrZSB0aGVyZSBpcyBubyBtaXNzaW5nIGRhdGEuDQoNCkhvdyBhYm91dCB0aGUgcG9wdWxhdGlvbiBkYXRhOg0KDQpgYGB7cn0NCnZpc19taXNzKGNvdW50eV9wb3ApDQpgYGANCg0KQWx0aG91Z2ggaXQgaXMgdmVyeSBoYXJkIHRvIHNlZSBpbiB0aGUgZmlndXJlLCB3ZSBhcHBlYXIgdG8gYmUgbWlzc2luZyBzb21lIHZhbHVlcyBmb3IgdGhlIGBOQU1FYCBhbmQgYHZhcmlhYmxlYCBkYXRhLCBidXQgd2UgZG8gbm90IGludGVuZCB0byB1c2UgdGhlc2UsIHNvIHRoaXMgc2hvdWxkIGJlIE9LLiBJdCBpcyBob3dldmVyIGEgZ29vZCBpZGVhIHRvIGNoZWNrIHRoZXNlIHJvd3MgdG8gc2VlIGlmIGFueXRoaW5nIHN0cmFuZ2UgaXMgaGFwcGVuaW5nLg0KDQpMZXQncyB1c2UgdGhlIGBmaWx0ZXIoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSBhbmQgdGhlIGBpcy5uYSgpYCBiYXNlIGZ1bmN0aW9uIHRvIHNlZSBtb3JlIGFib3V0IHRoZSBkYXRhIHRoYXQgZG9lcyBub3QgaGF2ZSBgTkFNRWAgdmFsdWVzLg0KDQpXZSB3aWxsIGFsc28gc3RhcnQgdXNpbmcgdGhlIGAlPiVgIHBpcGUgb2YgdGhlIGBtYWdyaXR0cmAgcGFja2FnZSBmb3Igb3VyIGFzc2lnbm1lbnRzLg0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSBpZiB5b3UgYXJlIHVuZmFtaWxpYXIgd2l0aCBwaXBpbmcgaW4gUiwgd2hpY2ggdXNlcyB0aGlzIGAlPiVgIG9wZXJhdG9yPC9zdW1tYXJ5PiAgDQoNCg0KQnkgW3BpcGluZ10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHdlIG1lYW4gdXNpbmcgdGhlIGAlPiVgIHBpcGUgb3BlcmF0b3Igd2hpY2ggaXMgYWNjZXNzaWJsZSBhZnRlciBsb2FkaW5nIHRoZSBgdGlkeXZlcnNlYCBvciBzZXZlcmFsIG9mIHRoZSBwYWNrYWdlcyB3aXRoaW4gdGhlIHRpZHl2ZXJzZSBsaWtlIGBkcGx5cmAgYmVjYXVzZSB0aGV5IGxvYWQgdGhlIFtgbWFncml0dHJgIHBhY2thZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4gDQpUaGlzIGFsbG93cyB1cyB0byBwZXJmb3JtIG11bHRpcGxlIHNlcXVlbnRpYWwgc3RlcHMgb24gb25lIGRhdGEgaW5wdXQuIA0KDQo8L2RldGFpbHM+IA0KKioqDQoNCmBgYHtyfQ0KY291bnR5X3BvcCAlPiUgDQogIGZpbHRlcihpcy5uYShOQU1FKSkNCmBgYA0KDQpUaGlzIGxvb2tzIE9LLiBMZXQncyBtb3ZlIG9uIHRvIHRoZSBgYW5udWFsRG9zYWdlYCBkYXRhLiANCmBgYHtyfQ0KdmlzX21pc3MoYW5udWFsRG9zYWdlKQ0KYGBgDQoNCkludGVyZXN0aW5nLCB3ZSBhcHBlYXIgdG8gYmUgbWlzc2luZyBgY291bnR5Zmlwc2AgY29kZXMgKHJlY2FsbCB0aGF0IEZJUFMgc3RhbmRzIGZvciB0aGUgW0ZlZGVyYWwgSW5mb3JtYXRpb24gUHJvY2Vzc2luZyBTdGFuZGFyZHMgKEZJUFMpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9GZWRlcmFsX0luZm9ybWF0aW9uX1Byb2Nlc3NpbmdfU3RhbmRhcmRzKSBjb2RlKSBmb3IgYSBzbWFsbCBwZXJjZW50YWdlIG9mIG91ciBhbm51YWwgZGF0YS4NCg0KDQpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGlzIGRhdGE6DQoNCmBgYHtyfQ0KYW5udWFsRG9zYWdlICU+JSANCiAgZmlsdGVyKGlzLm5hKGNvdW50eWZpcHMpKQ0KYGBgDQoNCldlIGNhbiBzZWUgdGhhdCB0aGUgZmlyc3Qgcm93cyB3aXRoIG1pc3NpbmcgZGF0YSBmb3IgYGNvdW50eWZpcHNgIGlzIGRhdGEgZm9yIFB1ZXJ0byBSaWNvIC0gaXQgbWlnaHQgbWFrZSBzZW5zZSBmb3IgUHVlcnRvIFJpY28gdG8gYmUgbWlzc2luZyB0aGVzZSBjb2Rlcy4NCg0KTGV0J3Mgc2VlIGlmIHRoZXJlIGFyZSBhbnkgZGF0YSBvdGhlciB0aGFuIGRhdGEgZm9yIFB1ZXJ0byBSaWNvIHRoYXQgaXMgYWxzbyBtaXNzaW5nIGBjb3VudHlmaXBzYCB2YWx1ZXMuIFdlIGNhbiB1c2UgdGhlIGAhPWAgb3BlcmF0b3Igd2hpY2ggaW5kaWNhdGVzIG5vdCBlcXVhbCB0by4NCg0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0KYW5udWFsRG9zYWdlICU+JSANCiAgZmlsdGVyKGlzLm5hKGNvdW50eWZpcHMpKSAlPiUNCiAgZmlsdGVyKEJVWUVSX1NUQVRFICE9ICJQUiIpDQpgYGANCg0KIyMjIyB7LnNjcm9sbGFibGUgfQ0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmFubnVhbERvc2FnZSAlPiUgDQogIGZpbHRlcihpcy5uYShjb3VudHlmaXBzKSkgJT4lDQogIGZpbHRlcihCVVlFUl9TVEFURSAhPSAiUFIiKSAlPiUNCiAgIyB0aGlzIGFsbG93cyB1cyB0byBzaG93IHRoZSBmdWxsIG91dHB1dCBpbiB0aGUgcmVuZGVyZWQgcm1hcmtkb3duDQogIHByaW50KG4gPSAxZTQpDQpgYGANCiMjIyMNCg0KSXQgbG9va3MgbGlrZSB0aGVyZSBpcyBhbHNvIGRhdGEgZm9yIG90aGVyIHRlcnJpdG9yaWVzIGluIHRoZSBkYXRhc2V0LCBhcyB3ZWxsIGFzIHNvbWUgY291bnRpZXMgd2l0aCBubyBuYW1lLg0KDQpGb3Igc29tZSByZWFzb24gdGhlIHJvd3MgZm9yIHRoZSBNb250Z29tZXJ5IGNvdW50eSBvZiBBcmthbnNhcyBhcmUgYWxzbyBtaXNzaW5nIGEgYGNvdW50eWZpcHNgIHZhbHVlLg0KDQpgYGB7cn0NCmFubnVhbERvc2FnZSAlPiUgDQogIGZpbHRlcihpcy5uYShjb3VudHlmaXBzKSkgJT4lDQogIGZpbHRlcihCVVlFUl9TVEFURSA9PSAiQVIiKQ0KYGBgDQoNCkFjY29yZGluZyB0byB0aGlzIFt3ZWJzaXRlXShodHRwczovL3d3dy5ucmNzLnVzZGEuZ292L3dwcy9wb3J0YWwvbnJjcy9kZXRhaWwvbmF0aW9uYWwvaG9tZS8/Y2lkPW5yY3MxNDNfMDEzNjk3KSB0aGUgRklQUyBjb2RlIGlzIDA1MDk3Lg0KDQpXZSB3aWxsIHVwZGF0ZSB0aGVzZSB2YWx1ZXMgaW4gdGhlIG5leHQgc2VjdGlvbi4NCg0KDQojICoqRGF0YSBXcmFuZ2xpbmcqKg0KKioqDQoNCklmIHlvdSBoYXZlIGJlZW4gZm9sbG93aW5nIGFsb25nIGJ1dCBzdG9wcGVkLCB3ZSBjb3VsZCBsb2FkIG91ciBpbXBvcnRlZCBkYXRhIGZyb20gdGhlICJkYXRhIiBkaXJlY3RvcnkgbGlrZSBzbzoNCg0KYGBge3J9DQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAibGFuZF9hcmVhLnJkYSIpKQ0KbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgImltcG9ydGVkIiwgImNvdW50eV9wb3BfYXJjb3MucmRhIikpDQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAiY291bnR5X2FubnVhbC5yZGEiKSkNCmBgYA0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gSWYgeW91IHNraXBwZWQgdGhlIHByZXZpb3VzIHNlY3Rpb25zIGNsaWNrIGhlcmUuIDwvc3VtbWFyeT4NCg0KRmlyc3QgeW91IG5lZWQgdG8gaW5zdGFsbCBhbmQgbG9hZCB0aGUgYE9DU2RhdGFgIHBhY2thZ2U6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KaW5zdGFsbC5wYWNrYWdlcygiT0NTZGF0YSIpDQpsaWJyYXJ5KE9DU2RhdGEpDQpgYGANCg0KVGhlbiwgeW91IG1heSBsb2FkIHRoZSBpbXBvcnRlZCBkYXRhIGludG8geW91ciBSIGVudmlyb25tZW50IHVzaW5nIHRoZSBmb2xsb3dpbmcgY29kZToNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQppbXBvcnRlZF9kYXRhKCJvY3MtYnAtb3Bpb2lkLXJ1cmFsLXVyYmFuIiwgb3V0cGF0aCA9IGdldHdkKCkpDQpsb2FkKGhlcmU6OmhlcmUoIk9DU2RhdGEiLCAiZGF0YSIsICJpbXBvcnRlZCIsICJsYW5kX2FyZWEucmRhIikpDQpsb2FkKGhlcmU6OmhlcmUoIk9DU2RhdGEiLCAiZGF0YSIsICJpbXBvcnRlZCIsICJjb3VudHlfcG9wX2FyY29zLnJkYSIpKQ0KbG9hZChoZXJlOjpoZXJlKCJPQ1NkYXRhIiwgImRhdGEiLCAiaW1wb3J0ZWQiLCAiY291bnR5X2FubnVhbC5yZGEiKSkNCmBgYA0KDQpBbHRlcm5hdGl2ZWx5LCB5b3UgbWF5IGRvd25sb2FkIHRoZSByYXcgZGF0YSBhcyB3ZWxsIGFzIHRoZSBDU1YgZmlsZXMgZm9yIHNpbXBsZXIgaW1wb3J0IHVzaW5nIHRoZSBmb2xsb3dpbmcgZnVuY3Rpb246DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0Kc2ltcGxlcl9pbXBvcnRfZGF0YSgib2NzLWJwLW9waW9pZC1ydXJhbC11cmJhbiIsIG91dHBhdGggPSBnZXR3ZCgpKQ0KYGBgDQoNCklmIHRoZSBwYWNrYWdlIGRvZXMgbm90IHdvcmsgZm9yIHlvdSwgdGhlIFJEQSBmaWxlcyAoc3RhbmRzIGZvciBSIGRhdGEpIG9mIHRoZSBkYXRhIGNhbiBiZSBmb3VuZCBpbiBvdXIgW0dpdEh1YiByZXBvc2l0b3J5XShodHRwczovL2dpdGh1Yi5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1vcGlvaWQtcnVyYWwtdXJiYW4vdHJlZS9tYXN0ZXIvZGF0YS9pbXBvcnRlZCkuIERvd25sb2FkIHRoZXNlIGZpbGVzIGFuZCB0aGVuIHBsYWNlIHRoZW0gaW4geW91ciBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IHdpdGhpbiBhIHN1YmRpcmVjdG9yeSBjYWxsZWQgImltcG9ydGVkIiB3aXRoaW4gYSBzdWJkaXJlY3RvcnkgY2FsbGVkICJkYXRhIiB0byBjb3B5IGFuZCBwYXN0ZSBvdXIgY29kZS4gV2UgdXNlZCBhbiBSU3R1ZGlvIHByb2plY3QgYW5kIHRoZSBbYGhlcmVgIHBhY2thZ2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbmF2aWdhdGUgdG8gdGhlIGZpbGVzIG1vcmUgZWFzaWx5LiANCg0KYGBge3J9DQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAibGFuZF9hcmVhLnJkYSIpKQ0KbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgImltcG9ydGVkIiwgImNvdW50eV9wb3BfYXJjb3MucmRhIikpDQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAiY291bnR5X2FubnVhbC5yZGEiKSkNCmBgYA0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgbW9yZSBhYm91dCBjcmVhdGluZyBuZXcgcHJvamVjdHMgaW4gUlN0dWRpby4gPC9zdW1tYXJ5Pg0KDQpZb3UgY2FuIGNyZWF0ZSBhIHByb2plY3QgYnkgZ29pbmcgdG8gdGhlIEZpbGUgbWVudSBvZiBSU3R1ZGlvIGxpa2Ugc286DQoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIk5ld19wcm9qZWN0LnBuZyIpKQ0KYGBgDQoNCllvdSBjYW4gYWxzbyBkbyBzbyBieSBjbGlja2luZyB0aGUgcHJvamVjdCBidXR0b246DQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJwcm9qZWN0X2J1dHRvbi5wbmciKSkNCmBgYA0KDQpTZWUgW2hlcmVdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdXNpbmcgUlN0dWRpbyBwcm9qZWN0cyBhbmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgYGhlcmVgIHBhY2thZ2UuDQoNCjwvZGV0YWlscz4NCioqKg0KPC9kZXRhaWxzPg0KDQoqKioNCg0KIyMgKipDbGVhbmluZyBsYW5kIGRhdGEqKg0KKioqDQoNClJlY2FsbCB0aGF0IHdlIHdhbnQgdG8gdXNlIHRoZSBgTE5EMTEwMjEwRGAgY29sdW1uIHdoaWNoIGlzIHRoZSBkYXRhIGZyb20gdGhlIHllYXIgMjAxMC4NCg0KVGhpcyBbbGlua10oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9saWJyYXJ5L3B1YmxpY2F0aW9ucy8yMDExL2NvbXBlbmRpYS91c2EtY291bnRpZXMtMjAxMS9maWxlLWxheW91dC5odG1sKSBhbmQgdGhpcyBbbGlua10oaHR0cHM6Ly93d3cyLmNlbnN1cy5nb3YvbGlicmFyeS9wdWJsaWNhdGlvbnMvMjAxMS9jb21wZW5kaWEvdXNhLWNvdW50aWVzL2V4Y2VsL01hc3RkYXRhLnhscykgZXhwbGFpbiB3aGF0IGVhY2ggb2YgdGhlIGNvbHVtbiBuYW1lcyBpbmRpY2F0ZS4NCg0KVXNpbmcgdGhlc2Ugd2Ugc2VlIHRoYXQgb3VyIGNvbHVtbiBvZiBpbnRlcmVzdCBgTE5EMTEwMjEwRGAgc3RhbmRzIGZvcjoNCi0gTE5EID0gQXJlYQ0KLSAxMTAgPSBMYW5kIEFyZWEgaW4gc3F1YXJlIG1pbGVzIChzdWJncm91cCBjb2RlIG9mIHRoZSBncm91cCkNCi0gMiA9IGNlbnR1cnkNCi0gMTAgPSB5ZWFyIGNvZGUgLSAyMDEwIChiYXNlZCBvbiB0aGUgY2VudHVyeSkNCi0gRCA9IERhdGEgKGRhdGEgdHlwZTogRiA9IGZsYWcsIEQgPSBkYXRhIHZhbHVlLCBOMSA9IEZvb3Rub3RlIDEsIE4yID0gRm9vdG5vdGUgMikNCg0KVGhlIDAxMCBzdWJncm91cCBjb2RlIGluZGljYXRlcyB0b3RhbCBhcmVhIChpbmNsdWRpbmcgbGFuZCBhbmQgd2F0ZXIpLiAgDQpUaGUgMjEwIHN1Ymdyb3VwIGNvZGUgaW5kaWNhdGVzIHdhdGVyIGFyZWEuICANCg0KKioqDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIHNvbWUgb3RoZXIgY2Vuc3VzIGNvZGUgZXhwbGFuYXRpb25zLiA8L3N1bW1hcnk+DQpMTkQwMTAxOTBECVRvdGFsIGFyZWEgaW4gc3F1YXJlIG1pbGVzIDE5OTAgIA0KTE5EMDEwMjAwRAlUb3RhbCBhcmVhIGluIHNxdWFyZSBtaWxlcyAyMDAwICANCkxORDExMDE4MEQJTGFuZCBhcmVhIGluIHNxdWFyZSBtaWxlcyAxOTgwICANCkxORDExMDE5MEQJTGFuZCBhcmVhIGluIHNxdWFyZSBtaWxlcyAxOTkwICANCkxORDExMDIwMEQJTGFuZCBhcmVhIGluIHNxdWFyZSBtaWxlcyAyMDAwICANCkxORDExMDIxMEQJTGFuZCBhcmVhIGluIHNxdWFyZSBtaWxlcyAyMDEwICANCkxORDIxMDE5MEQJV2F0ZXIgYXJlYSBpbiBzcXVhcmUgbWlsZXMgMTk5MCAgDQpMTkQyMTAyMDBECVdhdGVyIGFyZWEgaW4gc3F1YXJlIG1pbGVzIDIwMDANCg0KPC9kZXRhaWxzPg0KKioqKg0KDQpXZSBhbHNvIHdhbnQgdG8gYmUgYWJsZSB0byBpZGVudGlmeSB3aGF0IGxhbmQgYXJlYSBpcyBmb3Igd2hhdCBjb3VudHksIHRodXMgd2Ugd2lsbCBhbHNvIGtlZXAgdGhlIHRoZSBjb2x1bW4gd2l0aCBhcmVhIG5hbWVzIGFzIHdlbGwgYXMgdGhlIGNvbHVtbiBjYWxsZWQgYFNUQ09VYC4gVGhpcyB2YXJpYWJsZSBjb250YWlucyBudW1lcmljIGNvZGVzIHRoYXQgYXJlIHVzZWQgdG8gaWRlbnRpZnkgc3RhdGVzIGFuZCBjb3VudGllcyBjYWxsZWQgW0ZlZGVyYWwgSW5mb3JtYXRpb24gUHJvY2Vzc2luZyBTdGFuZGFyZHMgKEZJUFMpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9GZWRlcmFsX0luZm9ybWF0aW9uX1Byb2Nlc3NpbmdfU3RhbmRhcmRzKS4gSW4gdGhpcyBkYXRhc2V0IHdlIGhhdmUgbmF0aW9uYWwgc3RhdGUsIGFuZCBjb3VudHkgY29kZXMsIHNvIHRoaXMgdmFyaWFibGUgaXMgY2FsbGVkIGBTVENPVWAgKHNob3J0IGZvciBTdGF0ZSBhbmQgQ291bnR5KS4gIA0KDQpXZSBjYW4gc2VsZWN0IGp1c3QgdGhlIG5hbWVzLCB0aGUgY291bnR5L3N0YXRlIG51bWVyaWMgY29kZXMgKGBTVENPVWApLCBhbmQgdGhlIGBMTkQxMTAyMTBEYCBjb2x1bW4gYnkgdXNpbmcgdGhlIGBzZWxlY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4NCg0KYGBge3J9DQpsYW5kX2FyZWEgPC0gDQogIGxhbmQgJT4lIA0KICBzZWxlY3QoQXJlYW5hbWUsIFNUQ09VLCBMTkQxMTAyMTBEKQ0KDQpsYW5kX2FyZWENCmBgYA0KDQpUaHVzLCB3ZSBzdGlsbCBoYXZlIHN0YXRlLWxldmVsIGFuZCBmdWxsIFVTIG1lYXN1cmVtZW50cyBvZiBsYW5kIGFyZWEgaW4gYWRkaXRpb24gdG8gdGhlIGNvdW50eSBkYXRhLiBCdXQgd2Ugd2lsbCBqb2luIHRoaXMgd2l0aCBvdXIgb3RoZXIgZGF0YXNldHMgaW4gYSBiaXQgYmFzZWQgb24gdGhlIGNvdW50eSBuYW1lL2NvdW50eSBGSVBTIGNvZGUgYW5kIHRodXMgb25seSBrZWVwIHRoZSBjb3VudHkgbGV2ZWwgZGF0YS4gDQoNCg0KIyMgKipVcGRhdGluZyBgY291bnR5Zmlwc2AqKg0KKioqDQoNCldlIHdpbGwgdXNlIHRoZSBgY2FzZV93aGVuKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgcmVjb2RlIHRoZSBgTkFgIHZhbHVlcyBmb3IgYGNvdW50eWZpcHNgIGZvciB0aGUgcm93cyBmb3IgdGhlIGBNT05HT01FUllgIGNvdW50eSBvZiBgQVJgIHRvIGJlIGAwNTA5N2AuIA0KDQpGaXJzdCwgd2UgbmVlZCB0byBpZGVudGlmeSB0aGVzZSBwYXJ0aWN1bGFyIHJvd3MuIEJlY2F1c2UgTW9udGdvbWVyeSBtYXkgYmUgYSBjb3VudHkgbmFtZSBpbiBvdGhlciBzdGF0ZXMsIHdlIG5lZWQgdG8gZXZhbHVhdGUgd2hlbiB0aGUgYEJVWUVSX1NUQVRFYCBpcyBgQVJgIGFuZCB3aGVuIHRoZSBgQlVZRVJfQ09VTlRZYCBpcyBgTU9OVEdPTUVSWWAuIFdlIHdpbGwgdXNlIHRoZSBgJmAgb3BlcmF0b3IgdG8gaW5kaWNhdGUgdGhhdCBib3RoIGNvbmRpdGlvbnMgbXVzdCBiZSB0cnVlLiANCg0KVGhlbiwgV2Ugd2lsbCByZWNvZGUgdGhlIGBjb3V0cnlmaXBzYCB2YWx1ZXMgZm9yIHRoZXNlIHJvd3MgdG8gYmUgYCIwNTA5NyJgIHVzaW5nIHRoZSBgfmAgc3ltYm9sLiBBbGwgb3RoZXIgdmFsdWVzIG5lZWQgdG8gc3RheSB0aGUgc2FtZS4gDQoNCldlIG5lZWQgdG8gdXNlIGBUUlVFIH5gIHRvIHJlY29kZSBhbGwgdGhlIG90aGVyIGBjb3VudHlmaXBzYCB2YWx1ZXMgdG8gd2hhdCB0aGV5IGN1cnJlbnRseSBhcmUuIE90aGVyd2lzZSB0aGVzZSB3b3VsZCBhdXRvbWF0aWNhbGx5IGJlIHNldCB0byBgTkFgLg0KDQpXZSBhcmUgYWxzbyBnb2luZyB0byB1c2UgYSBzcGVjaWFsIHBpcGUgb3BlcmF0b3IgZnJvbSB0aGUgW2BtYWdyaXR0cmAgcGFja2FnZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKSBjYWxsZWQgdGhlICpjb21wb3VuZCBhc3NpZ25tZW50IHBpcGUgb3BlcmF0b3IqIG9yIHNvbWV0aW1lcyB0aGUgKmRvdWJsZSBwaXBlIG9wZXJhdG9yKi4gDQoNClRoaXMgYWxsb3dzIHVzIHRvIHVzZSB0aGUgYGFubnVhbERvc2FnZWAgYXMgb3VyIGlucHV0IGFuZCwgaW4gdGhlIHNhbWUgc3RlcCwgcmVhc3NpZ24gaXQgdG8gdGFrZSB0aGUgdXBkYXRlZCB2YWx1ZSBvZiB0aGUgdGliYmxlLCBhZnRlciBhbGwgdGhlIHN1YnNlcXVlbnQgc3RlcHMgaGF2ZSBiZWVuIHBlcmZvcm1lZC4gSW4gdGhpcyBjYXNlLCBpdCBpcyBvbmx5IG9uZSBzdGVwLCBidXQgdGhpcyBzYXZlcyB1cyB0eXBpbmcgYW5kIGF2b2lkcyBjcmVhdGluZyBhbiBpbnRlcm1lZGlhdGUgdmVyc2lvbiBvZiB0aGUgdGliYmxlLg0KDQpgYGB7cn0NCmFubnVhbERvc2FnZSAlPD4lIA0KICBtdXRhdGUoY291bnR5ZmlwcyA9IGNhc2Vfd2hlbihCVVlFUl9TVEFURSA9PSAiQVIiICYgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJVWUVSX0NPVU5UWSA9PSAiTU9OVEdPTUVSWSIgfiBhcy5jaGFyYWN0ZXIoIjA1MDk3IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBjb3VudHlmaXBzKSkNCmBgYA0KDQpOb3cgd2UgY2FuIGNoZWNrIHRoYXQgd2UgaW5kZWVkIGZpeGVkIG91ciBkYXRhLg0KDQpgYGB7cn0NCmFubnVhbERvc2FnZSAlPiUgDQogIGZpbHRlcihpcy5uYShjb3VudHlmaXBzKSkgJT4lDQogIGZpbHRlcihCVVlFUl9TVEFURSA9PSAiQVIiKQ0KDQphbm51YWxEb3NhZ2UgJT4lIA0KICBmaWx0ZXIoQlVZRVJfQ09VTlRZID09ICJNT05UR09NRVJZIikgJT4lDQogIGZpbHRlcihCVVlFUl9TVEFURSA9PSAiQVIiKQ0KYGBgDQoNCkdyZWF0ISBXZSBmaXhlZCBpdC4NCg0KT0ssIHdlIGFsc28gaGFkIHNvbWUgcm93cyB0aGF0IGRpZCBub3QgaGF2ZSBjb3VudHkgbmFtZXMgYmVjYXVzZSB0aGV5IHdlcmUganVzdCBtaXNzaW5nIG9yIHRoZSBkYXRhIHdhcyBmb3IgVVMgdGVycml0b3JpZXMuIFdlIHdpbGwgcmVtb3ZlIHRoZSB2YWx1ZXMgdGhhdCBkbyBub3QgaGF2ZSBjb3VudHkgbmFtZXMuDQoNCkZpcnN0LCBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGVtIGFnYWluLg0KDQpgYGB7cn0NCmFubnVhbERvc2FnZSAlPiUgDQogIGZpbHRlcihpcy5uYShCVVlFUl9DT1VOVFkpKQ0KYGBgDQoNCldlIGNhbiByZW1vdmUgdGhlc2Ugcm93cyBmcm9tIG91ciBkYXRhIHNldCB1c2luZyB0aGUgYGZpbHRlcigpYCBjb21tYW5kIGFsb25nIHdpdGggdGhlIGAhYCAoZXhjbGFtYXRpb24gcG9pbnQpIGJlZm9yZSB0aGUgYGlzLm5hKClgIGZ1bmN0aW9uLg0KDQpgYGB7cn0NCmFubnVhbERvc2FnZSAlPD4lIA0KICBmaWx0ZXIoIWlzLm5hKEJVWUVSX0NPVU5UWSkpDQpgYGANCg0KTm93IGxldCdzIGNoZWNrIHRoYXQgdGhlc2UgYE5BYCB2YWx1ZXMgYXJlIGdvbmU6DQoNCmBgYHtyfQ0KYW5udWFsRG9zYWdlICU+JSANCiAgZmlsdGVyKGlzLm5hKEJVWUVSX0NPVU5UWSkpDQpgYGANCg0KQXMgd2UgaGF2ZSBzZWVuLCBvdXIgYGFubnVhbERvc2FnZWAgb2JqZWN0IGhhcyBkYXRhIGZvciBVUyB0ZXJyaXRvcmllcy4gU28gbGV0J3MgY2hlY2sgdG8gc2VlIGlmIG91ciBsYW5kIGFyZWEgZGF0YSBhbHNvIGhhcyBpbmZvcm1hdGlvbiBmb3IgVVMgdGVycml0b3JpZXMsIHdoaWNoIHdvdWxkIGFsbG93IHVzIHRvIGludmVzdGlnYXRlIHRoZW0gYXMgd2VsbCwgYSBwb3RlbnRpYWxseSBpbnRlcmVzdGluZyBhZGRpdGlvbiB0byBvdXIgYW5hbHlzaXMuIElmIG5vdCwgd2Ugd2lsbCByZW1vdmUgdGhlIGRhdGEgZm9yIHRoZSB0ZXJyaXRvcmllcyBpbiBvdXIgYGFubnVhbERvc2FnZWAgZGF0YS4gDQoNCkFzIGEgZmlyc3QgY2FzZSwgd2UgY2FuIHVzZSB0aGUgYHN0cl9kZXRlY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlLCB3aGljaCBjb250YWlucyBsb3RzIG9mIGZ1bmN0aW9ucyBmb3IgbG9va2luZyBmb3IgcGF0dGVybnMgaW4gY2hhcmFjdGVyIHN0cmluZ3MsIHRvIGxvb2sgZm9yIGRhdGEgZnJvbSBQdWVydG8gUmljby4gDQoNClRoZSBgc3RyX2RldGVjdCgpYCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gbG9vayBmb3IgYSBwYXJ0aWN1bGFyIHBhdHRlcm4uIEl0IGRvZXMgbm90IGhhdmUgdG8gYmUgdGhlIGZ1bGwgdmFsdWUsIGkuZS4sIGEgcGFydGlhbCBtYXRjaCBpcyBhbGxvd2VkLiBXZSBjYW4gbG9vayB0byBzZWUgaWYgdGhlcmUgYXJlIGFueSBgUFJgIHN0cmluZ3Mgd2l0aGluIHRoZSB2YWx1ZXMgb2YgdGhlIHRoZSBgQXJlYW5hbWVgIHZhcmlhYmxlLiANCg0KYGBge3J9DQpsYW5kX2FyZWEgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChzdHJpbmcgPSBBcmVhbmFtZSwgcGF0dGVybiA9ICJQUiIpKQ0KYGBgDQoNCkl0IGRvZXMgbm90IGxvb2sgYXMgaWYgdGhlcmUgYXJlIGFueSBlbnRyaWVzIGZvciBQdWVydG8gUmljbywgYnV0IGxldCdzIGNoZWNrIG91ciBjb2RlLiBZb3UgY2FuIHNlZSB1c2luZyBhIGRpZmZlcmVudCBhYmJyZXZpYXRpb24sIHRoYXQgdGhpcyBjb2RlIHdvcmtzIGFzIGludGVuZGVkOg0KDQpgYGB7cn0NCmxhbmRfYXJlYSAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHN0cmluZyA9IEFyZWFuYW1lLCBwYXR0ZXJuID0gIkFSIikpDQpgYGANCg0KT0ssIHNvIGl0IGRvZXMgbm90IGxvb2sgbGlrZSB0aGVyZSBpcyBhbnkgdGVycml0b3J5IGxhbmQgYXJlYSBkYXRhIGluIHRoaXMgZGF0YXNldC4gVGh1cywgd2Ugd2lsbCBhbHNvIHJlbW92ZSB0aGVzZSBmcm9tIHRoZSBgYW5udWFsRG9zYWdlYCB0aWJibGUuDQoNCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpEbyB5b3UgcmVjYWxsIGhvdyB0byBkbyB0aGlzPw0KDQoNCiMjIyMNCg0KKioqDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCmBgYHtyfQ0KYW5udWFsRG9zYWdlICU8PiUgDQogIGZpbHRlcighaXMubmEoY291bnR5ZmlwcykpDQpgYGANCjwvZGV0YWlscz4gDQoNCioqKg0KDQpgYGB7cn0NCm5hbmlhcjo6IHZpc19taXNzKGFubnVhbERvc2FnZSkNCmBgYA0KDQpHcmVhdCEgTm93IHRoZXJlIGlzIG5vIG1pc3NpbmcgZGF0YSBpbiBvdXIgYW5udWFsIGRhdGEuDQoNCg0KIyMgKipSdXJhbCBhbmQgVXJiYW4gQ291bnRpZXMqKg0KKioqDQoNCkRlZmluaW5nIGlmIGEgcmVnaW9uIGlzIHJ1cmFsIG9yIHVyYmFuIGlzIGFjdHVhbGx5IHF1aXRlIGNvbXBsaWNhdGVkIGFzIHRoZSBvdmVyYWxsIHBvcHVsYXRpb24sIHRoZSBzdHJ1Y3R1cmUgb2Ygb3VyIHRvd25zIGFuZCBjaXRpZXMsIGFuZCB0aGUgYWNjZXNzIGJldHdlZW4gZGlmZmVyZW50IGxvY2F0aW9ucyBhbGwgY2hhbmdlIG92ZXIgdGltZS4gUGxlYXNlIHNlZSB0aGlzIFtyZXBvcnRdKGh0dHBzOi8vd3d3Mi5jZW5zdXMuZ292L2dlby9wZGZzL3JlZmVyZW5jZS91YS9EZWZpbmluZ19SdXJhbC5wZGYpIGZvcm0gdGhlIFVTIENlbnN1cyBCdXJlYXUgYWJvdXQgdGhlIGhpc3Rvcnkgb2YgdGhpcyBkZWZpbml0aW9uLiANCg0KQWNjb3JkaW5nIHRvIHNldmVyYWwgW2RlZmluaXRpb25zXShodHRwczovL3d3dy5ocnNhLmdvdi9ydXJhbC1oZWFsdGgvYWJvdXQtdXMvZGVmaW5pdGlvbi9pbmRleC5odG1sKSAtIHVyYmFuICoqYXJlYXMqKiBhcmUgb2Z0ZW4gZGVmaW5lZCBhcyB0aG9zZSB3aXRoIGdyZWF0ZXIgdGhhbiA1MCwwMDAgcGVvcGxlLiBIb3dldmVyLCB0aGVyZSBhcmUgYWxzbw0KW2RlZmluaXRpb25zXShodHRwczovL3d3dy5lcnMudXNkYS5nb3YvdG9waWNzL3J1cmFsLWVjb25vbXktcG9wdWxhdGlvbi9ydXJhbC1jbGFzc2lmaWNhdGlvbnMvd2hhdC1pcy1ydXJhbC8pIG9mIHJ1cmFsIGFyZWFzIGJlaW5nIGJhc2VkIG9uICJwb3B1bGF0aW9uIGRlbnNpdGllcyBvZiBsZXNzIHRoYW4gNTAwIHBlb3BsZSBwZXIgc3F1YXJlIG1pbGUgYW5kIHBsYWNlcyB3aXRoIGZld2VyIHRoYW4gMiw1MDAgcGVvcGxlIi4gVHlwaWNhbGx5IGNvdW50aWVzIGFyZSBtYWRlIHVwIG9mIG11bHRpcGxlIGFyZWFzLCBtYWtpbmcgaXQgY29tcGxpY2F0ZWQgdG8gYXNzaWduIGEgc2luZ2xlICJydXJhbCIgb3IgInVyYmFuIiBsYWJlbCBhdCB0aGUgY291bnR5IGxldmVsLiANCg0KVGhlIGNlbnN1cyByZS1kZWZpbmVzIHJ1cmFsIGFuZCB1cmJhbiBhcmVhcyBhcm91bmQgdGhlIFVTIHJlbGF0aXZlbHkgb2Z0ZW4uIEhvd2V2ZXIsIGNlbnN1cyBjb2xsZWN0aW9ucyBhYm91dCB0aGVzZSBtZWFzdXJlbWVudHMgZG8gbm90IG9jY3VyIGV2ZXJ5IHllYXIuDQoNCldlIHdpbGwgZGVmaW5lIGEgY291bnR5IGFzIHJ1cmFsIG9yIHVyYmFuIGJhc2VkIG9uIHRoZSBwb3B1bGF0aW9uIGRlbnNpdHkgZm9sbG93aW5nIHRoZSBVU0RBIFtkZWZpbml0aW9uXSgoaHR0cHM6Ly93d3cuZXJzLnVzZGEuZ292L3RvcGljcy9ydXJhbC1lY29ub215LXBvcHVsYXRpb24vcnVyYWwtY2xhc3NpZmljYXRpb25zL3doYXQtaXMtcnVyYWwvKSkgdGhhdCB3ZSBkZXNjcmliZWQgYWJvdmU6DQoNCjEuICoqcnVyYWwqKiAgPSBwb3B1bGF0aW9uIGRlbnNpdGllcyBvZiBsZXNzIHRoYW4gNTAwIHBlb3BsZSBwZXIgc3F1YXJlIG1pbGUsIGFzIHdlbGwgYXMgcGxhY2VzIHdpdGggZmV3ZXIgdGhhbiAyLDUwMCBwZW9wbGUgICAgIA0KMi4gKip1cmJhbioqID0gcG9wdWxhdGlvbiBkZW5zaXRpZXMgb2YgZ3JlYXRlciB0aGFuIDUwMCBwZW9wbGUgcGVyIHNxdWFyZSBtaWxlICANCg0KSWRlYWxseSwgd2Ugd291bGQgd2FudCBsYW5kIGFyZWEgZnJvbSBlYWNoIHllYXIsIGFzIHRoZXNlIGRvIGZsdWN0dWF0ZSBhIGJpdCwgaG93ZXZlciwgdGhlIDIwMTAgZGF0YSBzaG91bGQgYmUgYSBkZWNlbnQgYXBwcm94aW1hdGlvbiBhcyAyMDEwIGlzIGluIHRoZSBtaWRkbGUgb2Ygb3VyIHRpbWUgc3Bhbi4NCg0KV2Ugd2lsbCBjYWxjdWxhdGUgdGhlIGRlbnNpdHkgYXMgdGhlIG51bWJlciBvZiBwZW9wbGUgcGVyIHNxdWFyZSBtaWxlIGJ5IGRpdmlkaW5nIHRoZSBwb3B1bGF0aW9uIHZhbHVlcyBieSB0aGUgbGFuZCBhcmVhIHZhbHVlcy4gVG8gZG8gc28gd2UgZmlyc3QgbmVlZCB0byBjb21iaW5lIG91ciBgbGFuZF9hcmVhYCBhbmQgb3VyIGBjb3VudHlfcG9wYCBkYXRhIHRvZ2V0aGVyLiANCg0KRmlyc3QsIHdlIHdhbnQgdG8gbWFrZSBzdXJlIHRoYXQgd2UgaGF2ZSBvbmUgY29sdW1uLCBpbiBvdXIgY2FzZSB0aGUgY29sdW1uIHRoYXQgY29udGFpbnMgdGhlIG51bWVyaWMgY29kZSBmb3IgdGhlIGNvdW50aWVzLCBpbiB0aGUgc2FtZSBmb3JtYXQgYW5kIHdpdGggdGhlIHNhbWUgbmFtZSBpbiBib3RoIHRoZSB0aWJibGVzIHRoYXQgd2Ugd2lzaCB0byBjb21iaW5lLiBXZSBjYW4gY2hlY2sgdGhlIGNsYXNzIG9mIGRhdGEgZm9yIHRoaXMgY29sdW1uIGluIGJvdGggZGF0YXNldHMgdXNpbmcgdGhlIGBnbGltcHNlKClgZnVuY3Rpb24uDQoNCg0KKioqDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgZm9yIGFuIGV4cGxhbmF0aW9uIG9mIGRhdGEgY2xhc3NlcyBpbiBSIDwvc3VtbWFyeT4NCg0KVGhlcmUgYXJlIHNldmVyYWwgY2xhc3NlcyBvZiBkYXRhIGluIFIgcHJvZ3JhbW1pbmcuIA0KQ2hhcmFjdGVyIGlzIG9uZSBvZiB0aGVzZSBjbGFzc2VzLiANCkEgY2hhcmFjdGVyIHN0cmluZyBpcyBhbiBpbmRpdmlkdWFsIGRhdGEgdmFsdWUgbWFkZSB1cCBvZiBjaGFyYWN0ZXJzLiANClRoaXMgY2FuIGJlIGEgcGFyYWdyYXBoLCBsaWtlIHRoZSBsZWdlbmQgZm9yIHRoZSB0YWJsZSwgb3IgaXQgY2FuIGJlIGEgc2luZ2xlIGxldHRlciBvciBudW1iZXIgbGlrZSB0aGUgbGV0dGVyIGAiYSJgIG9yIHRoZSBudW1iZXIgYCIzImAuIA0KDQpJZiBkYXRhIGFyZSBvZiBjbGFzcyBjaGFyYWN0ZXIsIHRoYW4gdGhlIG51bWVyaWMgdmFsdWVzIHdpbGwgbm90IGJlIHByb2Nlc3NlZCBsaWtlIGEgbnVtZXJpYyB2YWx1ZSBpbiBhIG1hdGhlbWF0aWNhbCBzZW5zZS4gDQoNCklmIHlvdSB3YW50IHlvdXIgbnVtZXJpYyB2YWx1ZXMgdG8gYmUgaW50ZXJwcmV0ZWQgdGhhdCB3YXksIHRoZXkgbmVlZCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBudW1lcmljIGNsYXNzLiANClRoZSBvcHRpb25zIHR5cGljYWxseSB1c2VkIGFyZSBpbnRlZ2VyICh3aGljaCBoYXMgbm8gZGVjaW1hbCBwbGFjZSkgYW5kIGRvdWJsZSBwcmVjaXNpb24gKHdoaWNoIGhhcyBhIGRlY2ltYWwgcGxhY2UpLiANCg0KQSB2YXJpYWJsZSB0aGF0IGlzIGEgW2ZhY3Rvcl0oaHR0cHM6Ly93d3cuc3RhdC5iZXJrZWxleS5lZHUvfnMxMzMvZmFjdG9ycy5odG1sIzp+OnRleHQ9Q29uY2VwdHVhbGx5JTJDJTIwZmFjdG9ycyUyMGFyZSUyMHZhcmlhYmxlcyUyMGluLHJlZmVyZWQlMjB0byUyMGFzJTIwY2F0ZWdvcmljYWwlMjB2YXJpYWJsZXMuJnRleHQ9RmFjdG9ycyUyMGluJTIwUiUyMGFyZSUyMHN0b3JlZCx3aGVuJTIwdGhlJTIwZmFjdG9yJTIwaXMlMjBkaXNwbGF5ZWQuKSBoYXMgYSBzZXQgb2YgcGFydGljdWxhciB2YWx1ZXMgY2FsbGVkIGxldmVscy4gRXZlbiBpZiB0aGVzZSBhcmUgbnVtZXJpYywgdGhleSB3aWxsIGJlIGludGVycHJldGVkIGFzIGxldmVscyAoaS5lLiwgYXMgaWYgdGhleSB3ZXJlIGNoYXJhY3RlcnMpIG5vdCBhcyBtYXRoZW1hdGljYWwgbnVtYmVycy4gVGhlIHZhbHVlcyBvZiBhIGZhY3RvciBhcmUgYXNzdW1lZCB0byBoYXZlIGEgcGFydGljdWxhciBvcmRlcmluZzsgYnkgZGVmYXVsdCB0aGUgb3JkZXIgaXMgYWxwaGFiZXRpY2FsLCBidXQgdGhpcyBpcyBub3QgYWx3YXlzIHRoZSBjb3JyZWN0L2ludHVpdGl2ZSBvcmRlcmluZy4gWW91IGNhbiBtb2RpZnkgdGhlIG9yZGVyIG9mIHRoZXNlIGxldmVscyB3aXRoIHRoZSBgZm9yY2F0c2AgcGFja2FnZS4NCg0KPC9kZXRhaWxzPg0KDQoNCioqKg0KDQpgYGB7cn0NCmdsaW1wc2UobGFuZF9hcmVhKQ0KZ2xpbXBzZShjb3VudHlfcG9wKQ0KYGBgDQoNCkdyZWF0LCBpdCBsb29rcyBsaWtlIGJvdGggYXJlIGNoYXJhY3RlciBzdHJpbmdzIGJhc2VkIG9uIHRoZSBgPGNocj5gIG5leHQgdG8gdGhlIGNvbHVtbiBuYW1lcy4gSG93ZXZlciwgdGhlIGNvbHVtbnMgaW4gYm90aCB0aWJibGVzIG5lZWQgdG8gaGF2ZSB0aGUgc2FtZSBuYW1lLg0KDQpXZSBjYW4gdXNlIHRoZSBgcmVuYW1lKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gcmVuYW1lIHRoZSBgU1RDT1VgIGNvbHVtbiBmcm9tIHRoZSBgbGFuZF9hcmVhYCBkYXRhIHNldCB0byBiZSBgY291bnR5Zmlwc2AuIFRoZSBuZXcgbmFtZSBpcyBhbHdheXMgbGlzdGVkIGZpcnN0IGJlZm9yZSB0aGUgb2xkIG5hbWUgd2l0aCB0aGlzIGZ1bmN0aW9uIGxpa2Ugc286IGByZW5hbWUobmV3X25hbWUgPSBvbGRfbmFtZSlgLg0KDQpgYGB7cn0NCmxhbmRfYXJlYSAlPD4lDQogIHJlbmFtZShjb3VudHlmaXBzID0gU1RDT1UpDQpgYGANCg0KR3JlYXQhIE5vdyB3ZSBhcmUgcmVhZHkgdG8gY29tYmluZSBvdXIgZGF0YSB0b2dldGhlci4NCg0KV2UgY2FuIGRvIHNvIHVzaW5nIG9uZSBvZiB0aGUgIGAqX2pvaW4oKWBmdW5jdGlvbnMgb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4NCg0KVGhlcmUgYXJlIHNldmVyYWwgd2F5cyB0byBqb2luIGRhdGEgdXNpbmcgdGhlIGBkcGx5cmAgcGFja2FnZS4NCg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXR3aWR0aCA9ICI1MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImpvaW4ucG5nIikpDQpgYGANCg0KIyMjIyMgW1tzb3VyY2VdXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2pvaW4uaHRtbCkNCg0KSGVyZSBpcyBhIHZpc3VhbGl6YXRpb24gb2YgdGhlc2Ugb3B0aW9uczoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0d2lkdGggPSAiMzAlIn0NCiMgaW5uZXJfam9pbg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9nYWRlbmJ1aWUvdGlkeWV4cGxhaW4vbWFzdGVyL2ltYWdlcy9pbm5lci1qb2luLmdpZiIpDQpgYGANCg0KIyMjIyMgW1tzb3VyY2VdXShodHRwczovL2dpdGh1Yi5jb20vZ2FkZW5idWllL3RpZHlleHBsYWluL2Jsb2IvbWFzdGVyL2ltYWdlcy9pbm5lci1qb2luLmdpZikNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0d2lkdGggPSAiMzAlIn0NCiMgbGVmdF9qb2luDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2dhZGVuYnVpZS90aWR5ZXhwbGFpbi9tYXN0ZXIvaW1hZ2VzL2xlZnQtam9pbi5naWYiKQ0KYGBgDQoNCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly9naXRodWIuY29tL2dhZGVuYnVpZS90aWR5ZXhwbGFpbi9ibG9iL21hc3Rlci9pbWFnZXMvbGVmdC1qb2luLmdpZikNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0d2lkdGggPSAiMzAlIn0NCiMgcmlnaHRfam9pbg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9nYWRlbmJ1aWUvdGlkeWV4cGxhaW4vbWFzdGVyL2ltYWdlcy9yaWdodC1qb2luLmdpZiIpDQpgYGANCg0KIyMjIyMgW1tzb3VyY2VdXShodHRwczovL2dpdGh1Yi5jb20vZ2FkZW5idWllL3RpZHlleHBsYWluL2Jsb2IvbWFzdGVyL2ltYWdlcy9yaWdodC1qb2luLmdpZikNCg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXR3aWR0aCA9ICIzMCUifQ0KIyBmdWxsX2pvaW4NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZ2FkZW5idWllL3RpZHlleHBsYWluL21hc3Rlci9pbWFnZXMvZnVsbC1qb2luLmdpZiIpDQpgYGANCg0KIyMjIyMgW1tzb3VyY2VdXShodHRwczovL2dpdGh1Yi5jb20vZ2FkZW5idWllL3RpZHlleHBsYWluL2Jsb2IvbWFzdGVyL2ltYWdlcy9mdWxsLWpvaW4uZ2lmKQ0KDQpTZWUgW2hlcmVdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2Uvam9pbi5odG1sKSBmb3IgbW9yZSBkZXRhaWxzIGFib3V0IGpvaW5pbmcgZGF0YS4NCg0KU2luY2UgdGhlIHBvcHVsYXRpb24gZGF0YSBjYW1lIGZyb20gdGhlIEFQSSwgd2UgcHJvYmFibHkgaGF2ZSBpbmZvcm1hdGlvbiBhYm91dCBvcGlvaWQgcGlsbCBzaGlwbWVudHMgZm9yIGVhY2ggb2YgdGhlIGluY2x1ZGVkIGNvdW50aWVzLiBTaW5jZSB0aGUgbGFuZCBhcmVhIGRhdGEgY2FtZSBmcm9tIGEgZGlmZmVyZW50IHNvdXJjZSwgaXQgbWF5IGNvbnRhaW4gYWRkaXRpb25hbCBjb3VudGllcyB0aGF0IGFyZSBub3QgaW4gb3VyIHBvcHVsYXRpb24gb3IgZHJ1ZyBzaGlwbWVudCBkYXRhLiAgDQoNClRvIGFkZHJlc3MgdGhpcywgd2Ugd2lsbCB1c2UgdGhlIGBsZWZ0X2pvaW4oeCx5KWAgZnVuY3Rpb24gd2hlcmUgYHhgIGluIHRoaXMgY2FzZSB3aWxsIGJlIHRoZSBgY291bnR5X3BvcGAgYW5kIGB5YCB3aWxsIGJlIHRoZSBgY291bnRyeV9hcmVhYC4gSGVyZSwgd2Ugd2lsbCBhZGQgdGhlIGBMTkQxMTAyMTBEYCAobGFuZCBhcmVhKSB2YWx1ZXMgZm9yIGFsbCBjb3VudGllcyB0aGF0IG1hdGNoIGBjb3VudHlfcG9wYCBiYXNlZCBvbiB0aGUgYGNvdW50eWZpcHNgIGNvbHVtbiB0aGF0IHRoZXkgaGF2ZSBpbiBjb21tb24uIA0KDQoNCmBgYHtyfQ0KY291bnR5X2luZm8gPC0gDQogIGxlZnRfam9pbih4ID0gY291bnR5X3BvcCwgeSA9IGxhbmRfYXJlYSwgYnkgPSAiY291bnR5ZmlwcyIpDQpgYGANCg0KSXQgaXMgbm90IGFjdHVhbGx5IG5lY2Vzc2FyeSB0byBsaXN0IGB4YCBhbmQgYHlgIGxpa2UgdGhpcywgeW91IGNhbiBzaW1wbHkgcmVseSBvbiB0aGUgYHhgIGJlaW5nIGxpc3RlZCBmaXJzdCBhbmQgdGhlIGB5YCBiZWluZyBsaXN0ZWQgc2Vjb25kLiANCg0KVGh1cywgdGhpcyB3b3JrcyB0b286DQoNCmBgYHtyfQ0KY291bnR5X2luZm8gPC0gDQogIGxlZnRfam9pbihjb3VudHlfcG9wLCBsYW5kX2FyZWEsIGJ5ID0gImNvdW50eWZpcHMiKQ0KYGBgDQoNCllvdSBjYW4gY2hlY2sgdG8gc2VlIHRoYXQgdGhlIGBjb3VudHlfaW5mb2AgdGliYmxlIGhhcyB0aGUgc2FtZSBudW1iZXIgb2Ygcm93cyBhcyB0aGUgYGNvdW50eV9wb3BgIHRpYmJsZSwgaS5lLiwgb3VyIGpvaW4gcHJlc2VydmVkIHRoZSBkYXRhIHBvaW50cyBpbiB0aGUgYGNvdW50eV9wb3BgIHRpYmJsZSBhbmQgYWRkZWQgdmFsdWVzIGZyb20gdGhlIGBsYW5kX2FyZWFgIHRpYmJsZSB3aGVyZSB0aGVyZSB3YXMgYSBtYXRjaCBvbiB0aGUgYGNvdW50eWZpcHNgIHZhcmlhYmxlLg0KDQpgYGB7cn0NCm5yb3coY291bnR5X2luZm8pID09IG5yb3coY291bnR5X3BvcCkNCmBgYA0KDQpXZSBhcmUgbm93IHJlYWR5IHRvIGNhbGN1bGF0ZSB0aGUgcG9wdWxhdGlvbiBkZW5zaXR5IHBlciBzcXVhcmUgbWlsZS4gV2UgY3JlYXRlIGEgbmV3IGNvbHVtbiB3aXRoIHRoaXMgZGF0YSB1c2luZyB0aGUgYG11dGF0ZSgpYCBmdW5jdGlvbiBhbmQgdGhlIGAvYCB0byBkaXZpZGUgdGhlIGBwb3B1bGF0aW9uYCB2YWx1ZSBieSB0aGUgbGFuZCBhcmVhIHZhbHVlIChpbiBzcXVhcmUgbWlsZXMpIGZvciBlYWNoIGNvdW50eS4gTGV0J3MgYWxzbyBtYWtlIHRoZSBgeWVhcmAgdmFyaWFibGUgYSBmYWN0b3IuIFdlIGNhbiBkbyB1c2luZyB0aGUgYGFzLmZhY3RvcigpYCBiYXNlIGZ1bmN0aW9uLiBJZiB5b3UgYXJlIG5vdCBmYW1pbGlhciB3aXRoIGZhY3RvcnMsIHBsZWFzZSBzZWUgdGhlIGNsaWNrIHRvIGV4cGFuZCBzZWN0aW9uIGFib3ZlIGFib3V0IGRhdGEgY2xhc3NlcyBpbiBSLiANCg0KYGBge3J9DQpjb3VudHlfaW5mbyAlPD4lDQogIG11dGF0ZShkZW5zaXR5ID0gcG9wdWxhdGlvbi9MTkQxMTAyMTBELA0KICAgICAgICAgeWVhciA9IGFzLmZhY3Rvcih5ZWFyKSkNCg0KZ2xpbXBzZShjb3VudHlfaW5mbykNCmBgYA0KDQpHcmVhdCwgbm93IHdlIGFyZSByZWFkeSB0byBjcmVhdGUgYSB2YXJpYWJsZSB0aGF0IGNsYXNzaWZpZXMgaWYgYSBjb3VudHkgd2FzIHJ1cmFsIG9yIHVyYmFuIGJhc2VkIG9uIG91ciBkZWZpbml0aW9uIG9mIHJ1cmFsIGNvdW50aWVzIGJlaW5nIHRob3NlIHdpdGggbGVzcyB0aGFuIDUwMCBwZW9wbGUgcGVyIHNxdWFyZSBtaWxlIGFzIHdlbGwgYXMgdGhvc2Ugd2l0aCBsZXNzIHRoYW4gMiw1MDAgcGVvcGxlLiANCg0KV2Ugd2lsbCB1c2UgdGhlIGBjYXNlX3doZW4oKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBjbGFzc2lmeSB0aGUgbmV3IGBydXJhbF91cmJhbmAgdmFyaWFibGUgYXMgZWl0aGVyIGAiVXJiYW4iYCBvciBgIlJ1cmFsImAgYmFzZWQgb24gdGhlIGV2YWx1YXRpb25zIG9mIHRoZSBgZGVuc2l0eWAgYW5kIHRoZSBgcG9wdWxhdGlvbmAgdmFyaWFibGVzLiANCg0KLSBJZiB0aGUgZGVuc2l0eSBpcyBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gNTAwIHBlb3BsZSBwZXIgc3F1YXJlIG1pbGUsIHRoZW4gdGhlIGNvdW50eSB3aWxsIGJlIGNvZGVkIGFzIGAiVXJiYW4iYC4gDQotIEFsdGVybmF0aXZlbHkgaWYgdGhlIGRlbnNpdHkgaXMgbGVzcyB0aGFuIDUwMCBwZW9wbGUgcGVyIHNxdWFyZSBtaWxlIG9yIHRoZSBwb3B1bGF0aW9uIGlzIGxlc3MgdGhhbiAyNTAwLCB0aGFuIHRoZSBjb3VudHkgd2lsbCBiZSBjb2RlZCBhcyBgIlJ1cmFsImAuIA0KDQpUaGUgYHxgIG9wZXJhdG9yIGlzIHVzZWQgdG8gaW5kaWNhdGUgdGhhdCBlaXRoZXIgZXhwcmVzc2lvbiBzaG91bGQgcmVzdWx0IGluIGNvZGluZyB0aGUgY291bnR5IGFzIGAiUnVyYWwiYA0KDQpgYGB7cn0NCmNvdW50eV9pbmZvICU8PiUNCiAgbXV0YXRlKHJ1cmFsX3VyYmFuID0gY2FzZV93aGVuKGRlbnNpdHkgID49IDUwMCB+ICJVcmJhbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZW5zaXR5ICA8ICA1MDAgfCBwb3B1bGF0aW9uIDwgMjUwMCB+ICJSdXJhbCIpKQ0KYGBgDQoNCldlIGNhbiB1c2UgdGhlIGBjb3VudCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIHNlZSBob3cgbWFueSBvZiBlYWNoIHRoaXMgcmVzdWx0ZWQgaW46DQoNCmBgYHtyfQ0KY291bnQoY291bnR5X2luZm8sIHJ1cmFsX3VyYmFuKQ0KYGBgDQoNCldlIHdpbGwgbm93IGNvbWJpbmUgdGhlIGBhbm51YWxEb3NhZ2VgIGRhdGEgd2l0aCB0aGUgYGNvdW50X2luZm9gIHRpYmJsZS4NCg0KIyMjIyB7LnRoaW5rX3F1ZXN0aW9uX2Jsb2NrfQ0KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+DQoNCkhvdyBtaWdodCB3ZSBkbyB0aGlzPw0KDQojIyMjDQoNCioqKg0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQoNCmBgYHtyfQ0KYW5udWFsRG9zYWdlICU8PiUNCiAgbXV0YXRlKGNvdW50eWZpcHMgPSBhcy5mYWN0b3IoY291bnR5ZmlwcyksDQogICAgICAgICB5ZWFyID0gYXMuZmFjdG9yKHllYXIpKQ0KICANCkFubnVhbCA8LSANCiAgbGVmdF9qb2luKGFubnVhbERvc2FnZSwgY291bnR5X2luZm8pDQpgYGANCjwvZGV0YWlscz4NCg0KKioqDQoNCmBgYHtyfQ0KZ2xpbXBzZShBbm51YWwpDQpgYGANCg0KR3JlYXQsIG5vdyB3ZSBzaG91bGQgaGF2ZSB0aGUgZGF0YSB0aGF0IHdlIG5lZWQgdG8gYW5zd2VyIG91ciBxdWVzdGlvbiwgYnV0IGZpcnN0IGxldCdzIGRvIHNvbWUgYWRkaXRpb25hbCBjaGVja3MgYmVmb3JlIHdlIHByb2NlZWQgd2l0aCBvdXIgYW5hbHlzaXMuDQoNCioqTm90aWNlKiogaG93IHRoZXJlIGlzIGEgdmFyaWFibGUgY2FsbGVkIGBET1NBR0VfVU5JVGAuIFRoaXMgdmFyaWFibGUgZ2l2ZXMgdGhlIG51bWJlciBvZiBwaWxscyBzaGlwcGVkIHRvIGEgcGhhcm1hY3kgaW4gdGhpcyBjb3VudHkgdGhhdCB3ZXJlIGVpdGhlciBbb3h5Y29kb25lXShodHRwczovL3d3dy5kZWEuZ292L3NpdGVzL2RlZmF1bHQvZmlsZXMvMjAyMC0wNi9PeHljb2RvbmUtMjAyMF8wLnBkZikgb3IgW2h5ZHJvY29kb25lXShodHRwczovL3d3dy5kZWFkaXZlcnNpb24udXNkb2ouZ292L2RydWdfY2hlbV9pbmZvL2h5ZHJvY29kb25lLnBkZikuDQoNCkxldCdzIGRvIGEgY2hlY2sgdG8gc2VlIGhvdyBjb21wbGV0ZSBvdXIgZGF0YSBpcyBub3cgdGhhdCB3ZSBoYXZlIGNvbWJpbmVkIG91ciBgY291bnRyeV9pbmZvYCBkYXRhIHdpdGggdGhlIGBhbm51YWxEb3NhZ2VgIGRhdGEuIA0KDQpXZSBoYXZlIE5BIHZhbHVlcyBmb3IgYW55IGNvdW50aWVzIHByZXNlbnQgaW4gdGhlIERBRSBkYXRhLCBidXQgbm90IGluIG91ciBsYW5kIGFyZWEgZGF0YS4gV2UgY2FuIHVzZSB0aGUgYGdnX21pc3NfdmFyKClgIGZ1bmN0aW9uIGZyb20gdGhlIGBuYW5pYXJgIHBhY2thZ2UgdG8gY3JlYXRlIGEgcGxvdCB0aGF0IHNob3dzIGlmIHdlIGhhdmUgYW55IG1pc3NpbmcgZGF0YS4NCg0KYGBge3J9DQpuYW5pYXI6OiBnZ19taXNzX3ZhcihBbm51YWwpDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHNldmVyYWwgdmFyaWFibGVzIGFyZSBtaXNzaW5nIGZvciBzb21lIG9mIG91ciBjb3VudGllcy4NCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGNvdW50aWVzIHRoYXQgYXJlIG1pc3NpbmcgZGVuc2l0eS4NCg0KIyMjIyB7LnNjcm9sbGFibGUgfQ0KDQpgYGB7cn0NCkFubnVhbCAlPiUNCiAgZmlsdGVyKGlzLm5hKGRlbnNpdHkpKQ0KYGBgDQojIyMjDQoNClRoZXJlIGRvZXMgbm90IGFwcGVhciB0byBiZSBsYW5kIGFyZWEgYW5kL29yIHBvcHVsYXRpb24gZGF0YSBmb3IgdGhlc2UgY291bnRpZXMuDQoNCkxldCdzIHRha2UgYSBsb29rIGJhY2sgYXQgb3VyIG9yaWdpbmFsIGRhdGEgdGliYmxlcyAocHJpb3IgdG8gbWVyZ2luZykgZm9yIGEgZmV3IG9mIHRoZXNlIGNvdW50aWVzIHRvIHNlZSB3aGVyZSB0aGUgZGF0YSBmaXJzdCB3ZW50IG1pc3NpbmcuDQoNCmBgYHtyfQ0KY291bnR5X2luZm8gJT4lIA0KICBmaWx0ZXIoY291bnR5ZmlwcyA9PSAiMDEwMDEiKSAjIGV4YW1wbGUgb2Ygb3RoZXIgZGF0YSB0aGF0IGRvZXMgaGF2ZSB2YWx1ZXMNCg0KY291bnR5X2luZm8gJT4lIA0KICBmaWx0ZXIoY291bnR5ZmlwcyA9PSAiMDUwOTciKQ0KDQpjb3VudHlfaW5mbyAlPiUgDQogIGZpbHRlcihjb3VudHlmaXBzID09ICIwMjIwMSIpDQoNCmNvdW50eV9pbmZvICU+JSANCiAgZmlsdGVyKGNvdW50eWZpcHMgPT0gIjAyMjgwIikNCmBgYA0KDQpBaCBoYSwgaXQgbG9va3MgbGlrZSB0aGVyZSB3YXNuJ3QgaW5mb3JtYXRpb24gZm9yIGl0IGluIHRoZSBgY291bnR5X2luZm9gIHRpYmJsZS4gSWYgeW91IHJlY2FsbCB0aGlzIHdhcyBjcmVhdGVkIGJ5IGpvaW5pbmcgdGhlIGBsYW5kX2FyZWFgIGRhdGEgd2l0aCB0aGUgYGNvdW50eV9wb3BgIGRhdGEuDQoNCkxldCdzIHRha2UgYSBsb29rIGluIHRoZXNlIHRpYmJsZXMuDQoNCg0KVGhlcmUgaXMgbGFuZCBkYXRhIGZvciB0aGUgZmlyc3QgY291bnR5LCBidXQgdGhhdCdzIGFsbDoNCmBgYHtyfQ0KbGFuZF9hcmVhICU+JSANCiAgZmlsdGVyKGNvdW50eWZpcHMgPT0gIjA1MDk3IikNCg0KbGFuZF9hcmVhICU+JSANCiAgZmlsdGVyKGNvdW50eWZpcHMgPT0gIjAyMjAxIikNCg0KbGFuZF9hcmVhICU+JSANCiAgZmlsdGVyKGNvdW50eWZpcHMgPT0gIjAyMjgwIikNCmBgYA0KDQpEaWQgd2UgaGF2ZSBwb3B1bGF0aW9uIGRhdGEgZm9yIHRoZSBNb250Z29tZXJ5LCBBUiBjb3VudHk/DQoNCmBgYHtyfQ0KY291bnR5X3BvcCAlPiUgDQogIGZpbHRlcihjb3VudHlmaXBzID09ICIwNTA5NyIpDQoNCmNvdW50eV9wb3AgJT4lIA0KICBmaWx0ZXIoQlVZRVJfQ09VTlRZID09ICJNT05UR09NRVJZIiYgQlVZRVJfU1RBVEUgPT0iQUsiKQ0KYGBgDQoNCkl0IGxvb2tzIGxpa2Ugd2UgZGlkbid0Lg0KDQpJdCdzIGEgZ29vZCBpZGVhIHRvIGNoZWNrIHlvdXIgb3JpZ2luYWwgZGF0YSwgdG8gbWFrZSBzdXJlIHRoYXQgeW91IGRpZG4ndCBsb3NlIHZhbHVlcyBzaW1wbHkgZnJvbSB0aGUgcHJvY2VzcyBvZiBqb2luaW5nIGRhdGEgdG9nZXRoZXIuIEl0IGRvZXMgbm90IGxvb2sgbGlrZSB0aGF0IHdhcyB0aGUgY2FzZSBmb3IgdXMuICANCg0KV2Ugd2lsbCBub3cgcmVtb3ZlIHRoZXNlIHJvd3MgYmVmb3JlIGZ1cnRoZXIgYW5hbHlzaXM6DQoNCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpEbyB5b3UgcmVjYWxsIGhvdyB5b3Ugd291bGQgZG8gdGhpcz8NCg0KIyMjIw0KDQoqKioNCg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHJldmVhbCB0aGUgY29kZS4gPC9zdW1tYXJ5Pg0KDQpgYGB7cn0NCkFubnVhbCAlPD4lIA0KICBmaWx0ZXIoIWlzLm5hKFNUQVRFKSkNCmBgYA0KDQo8L2RldGFpbHM+DQoNCioqKiANCg0KYGBge3J9DQpuYW5pYXI6OiBnZ19taXNzX3ZhcihBbm51YWwpDQpgYGANCg0KTmljZSEgTm93IHdlIGhhdmUgbm8gbWlzc2luZyBkYXRhLg0KDQpMZXQncyBhbHNvIGNoZWNrIGlmIHRoZXJlIHdlcmUgYW55IGNvdW50aWVzIGluIGBjb3VudHlfaW5mb2AgdGhhdCB3ZXJlIG5vdCBpbiB0aGUgREVBIGBhbm51YWxEb3NhZ2VgIGRhdGEuDQoNClRoaXMgdGltZSB3ZSB3aWxsIHVzZSB0aGUgYGxlZnRfam9pbigpYCBmdW5jdGlvbiBidXQgd2l0aCB0aGUgYGNvdW50eV9pbmZvYCBsaXN0ZWQgZmlyc3QsIHRvIHByZXNlcnZlIGFsbCB2YWx1ZXMgb2YgdGhlIGBjb3VudHlfaW5mb2AgdGliYmxlLiANCg0KYGBge3J9DQpjaGVja2luZyA8LQ0KICBsZWZ0X2pvaW4oY291bnR5X2luZm8sIGFubnVhbERvc2FnZSkNCmdnX21pc3NfdmFyKGNoZWNraW5nKQ0KYGBgDQpXZSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIG92ZXIgb25lIHRob3VzYW5kIGBOQWAgdmFsdWVzIGZvciB0aGUgYERPU0FHRV9VTklUYCB2YXJpYWJsZS4NCg0KV2UgY2FuIHVzZSB0aGUgYGZpbHRlcigpYCBmdW5jdGlvbiBhZ2FpbiB0byBzZWUgd2hhdCBjb3VudGllcyBkb24ndCBoYXZlIGFueSBgRE9TQUdFX1VOSVRgIHZhbHVlcyBhbmQgdGh1cyBkb24ndCBhcHBlYXIgdG8gaGF2ZSB0aGlzIGRhdGEgaW4gdGhlIFdhc2hpbmd0b24gUG9zdCBERUEgZGF0YS4NCg0KYGBge3J9DQpjaGVja2luZyAlPiUNCiAgZmlsdGVyKGlzLm5hKERPU0FHRV9VTklUKSkNCiAgDQpjaGVja2luZyAlPiUNCiAgZmlsdGVyKGlzLm5hKERPU0FHRV9VTklUKSkgJT4lIA0KICBkaXN0aW5jdChjb3VudHlmaXBzKSANCmBgYA0KSXQgbG9va3MgbGlrZSB0aGVyZSBhcmUgMTc0IGNvdW50aWVzIHRoYXQgZG8gbm90IGhhdmUgYW55IGRhdGEgaW4gdGhlIERFQSBkYXRhLg0KDQpJdCBpcyB1bmNsZWFyIHdoeSB0aGVzZSBjb3VudGllcyBhcmUgbm90IGluY2x1ZGVkLiBBIEdvb2dsZSBzZWFyY2ggb2Ygc29tZSBvZiB0aGVzZSBjb3VudGllcyBkaWQgbm90IGluZGljYXRlIGFueXRoaW5nIHVudXN1YWwgYWJvdXQgdGhlIGNvdW50aWVzIGluIHRlcm1zIG9mIHdoZW4gaXQgd2FzIGVzdGFibGlzaGVkIG9yIGlmIGl0IGJlY2FtZSBwYXJ0IG9mIGFub3RoZXIgY291bnR5IGxhdGVyIGluIHRpbWUuIA0KDQpUaHVzLCBpdCBpcyBpbXBvcnRhbnQgdG8ga2VlcCBpbiBtaW5kIGFzIHdlIGNvbnRpbnVlIHRvIGFuYWx5emUgdGhpcyBkYXRhLCB0aGF0IHRoZSBBUkNPUyBkYXRhIGZyb20gdGhlIERFQSByZWxlYXNlZCBieSB0aGUgV2FzaGluZ3RvbiBQb3N0ICoqZG9lcyBub3QgaW5jbHVkZSBwaWxsIHNoaXBtZW50IGluZm9ybWF0aW9uIGZvciBhbGwgVVMgY291bnRpZXMqKi4gDQoNCkxldCdzIHNhdmUgdGhpcyBkYXRhIG5vdyBpbiBhIGRpcmVjdG9yeSBjYWxsZWQgIndyYW5nbGVkIiB3aXRoaW4gdGhlICJkYXRhIiBkaXJlY3RvcnkuIFdlIHdpbGwgYWxzbyB3cml0ZSBjc3YgZmlsZSB2ZXJzaW9ucyB3aGljaCBjb3VsZCBiZSB1c2VmdWwgdG8gZ2l2ZSB0byBhIGNvbGxhYm9yYXRvciBmb3IgZXhhbXBsZS4NCg0KYGBge3J9DQp3cml0ZS5jc3YoQW5udWFsLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsIndyYW5nbGVkIiwgIkFubnVhbF9vcGlvaWRfZGF0YS5jc3YiKSkNCnNhdmUoQW5udWFsLCBmaWxlID0gIGhlcmU6OmhlcmUoImRhdGEiLCJ3cmFuZ2xlZCIsICJBbm51YWxfb3Bpb2lkX2RhdGEucmRhIikpDQp3cml0ZS5jc3YoY291bnR5X2luZm8sIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgImNvdW50eV9pbmZvLmNzdiIpKQ0Kc2F2ZShjb3VudHlfaW5mbywgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWQiLCAiY291bnR5X2luZm8ucmRhIikpDQpgYGANCg0KIyAqKkRhdGEgVmlzdWFsaXphdGlvbioqDQoqKioNCg0KSWYgeW91IGhhdmUgYmVlbiBmb2xsb3dpbmcgYWxvbmcgYnV0IHN0b3BwZWQsIHdlIGNvdWxkIGxvYWQgb3VyIHdyYW5nbGVkIGRhdGEgZnJvbSB0aGUgImRhdGEiIGRpcmVjdG9yeSBsaWtlIHNvOg0KDQpgYGB7cn0NCmxvYWQoZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWQiLCAiQW5udWFsX29waW9pZF9kYXRhLnJkYSIpKQ0KbG9hZChmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJjb3VudHlfaW5mby5yZGEiKSkNCmBgYA0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gSWYgeW91IHNraXBwZWQgdGhlIHByZXZpb3VzIHNlY3Rpb25zIGNsaWNrIGhlcmUuIDwvc3VtbWFyeT4NCg0KRmlyc3QgeW91IG5lZWQgdG8gaW5zdGFsbCBhbmQgbG9hZCB0aGUgYE9DU2RhdGFgIHBhY2thZ2U6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KaW5zdGFsbC5wYWNrYWdlcygiT0NTZGF0YSIpDQpsaWJyYXJ5KE9DU2RhdGEpDQpgYGANCg0KVGhlbiwgeW91IG1heSBkb3dubG9hZCBhbmQgbG9hZCB0aGUgd3JhbmdsZWQgZGF0YSBpbnRvIHlvdXIgUiBlbnZpcm9ubWVudCB1c2luZyB0aGUgZm9sbG93aW5nIGNvZGU6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0Kd3JhbmdsZWRfcmRhKCJvY3MtYnAtb3Bpb2lkLXJ1cmFsLXVyYmFuIiwgb3V0cGF0aCA9IGdldHdkKCkpDQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJPQ1NkYXRhIiwgImRhdGEiLCAid3JhbmdsZWQiLCAiQW5udWFsX29waW9pZF9kYXRhLnJkYSIpKQ0KbG9hZChmaWxlID0gaGVyZTo6aGVyZSgiT0NTZGF0YSIsICJkYXRhIiwgIndyYW5nbGVkIiwgImNvdW50eV9pbmZvLnJkYSIpKQ0KYGBgDQoNCklmIHRoZSBwYWNrYWdlIGRvZXMgbm90IHdvcmsgZm9yIHlvdSwgYWx0ZXJuYXRpdmVseSwgdGhlIFJEQSBmaWxlcyAoc3RhbmRzIGZvciBSIGRhdGEpIG9mIHRoZSBkYXRhIGNhbiBiZSBmb3VuZCBpbiBvdXIgW0dpdEh1YiByZXBvc2l0b3J5XShodHRwczovL2dpdGh1Yi5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1vcGlvaWQtcnVyYWwtdXJiYW4vdHJlZS9tYXN0ZXIvZGF0YS93cmFuZ2xlZCkuIERvd25sb2FkIHRoZXNlIGZpbGVzIGFuZCB0aGVuIHBsYWNlIHRoZW0gaW4geW91ciBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IHdpdGhpbiBhIHN1YmRpcmVjdG9yeSBjYWxsZWQgIndyYW5nbGVkIiB3aXRoaW4gYSBzdWJkaXJlY3RvcnkgY2FsbGVkICJkYXRhIiB0byBjb3B5IGFuZCBwYXN0ZSBvdXIgY29kZS4gV2UgdXNlZCBhbiBSU3R1ZGlvIHByb2plY3QgYW5kIHRoZSBbYGhlcmVgIHBhY2thZ2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbmF2aWdhdGUgdG8gdGhlIGZpbGVzIG1vcmUgZWFzaWx5LiANCg0KYGBge3J9DQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwid3JhbmdsZWQiLCAiQW5udWFsX29waW9pZF9kYXRhLnJkYSIpKQ0KbG9hZChmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJjb3VudHlfaW5mby5yZGEiKSkNCmBgYA0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgbW9yZSBhYm91dCBjcmVhdGluZyBuZXcgcHJvamVjdHMgaW4gUlN0dWRpby4gPC9zdW1tYXJ5Pg0KDQpZb3UgY2FuIGNyZWF0ZSBhIHByb2plY3QgYnkgZ29pbmcgdG8gdGhlIEZpbGUgbWVudSBvZiBSU3R1ZGlvIGxpa2Ugc286DQoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIk5ld19wcm9qZWN0LnBuZyIpKQ0KYGBgDQoNCllvdSBjYW4gYWxzbyBkbyBzbyBieSBjbGlja2luZyB0aGUgcHJvamVjdCBidXR0b246DQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJwcm9qZWN0X2J1dHRvbi5wbmciKSkNCmBgYA0KDQpTZWUgW2hlcmVdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdXNpbmcgUlN0dWRpbyBwcm9qZWN0cyBhbmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgYGhlcmVgIHBhY2thZ2UuDQoNCjwvZGV0YWlscz4NCioqKg0KPC9kZXRhaWxzPg0KDQoqKioNCg0KV2Ugd2lsbCBiZWdpbiBieSB0YWtpbmcgYSBkZWVwZXIgbG9vayBhdCBvdXIgZGF0YSB3aXRoIHNvbWUgdmlzdWFsaXphdGlvbnMuIFdlIHdpbGwgdXNlIHRoZSBgZ2dwbG90MmAgcGFja2FnZSB0byBjcmVhdGUgdGhlc2UgdmlzdWFsaXphdGlvbnMuDQoNCioqKg0KPGRldGFpbHM+PHN1bW1hcnk+IENsaWNrIGhlcmUgZm9yIGFuIGludHJvZHVjdGlvbiBhYm91dCB0aGlzIHBhY2thZ2UgaWYgeW91IGFyZSAgbmV3IHRvIHVzaW5nIGBnZ3Bsb3QyYCA8L3N1bW1hcnk+DQoNClRoZSBbZ2dwbG90MiBwYWNrYWdlXShodHRwOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnKSBpcyBnZW5lcmFsbHkgaW50dWl0aXZlIGZvciBiZWdpbm5lcnMgYmVjYXVzZSBpdCBpcyBiYXNlZCBvbiBhICBbZ3JhbW1hciBvZiBncmFwaGljc10oaHR0cDovL3ZpdGEuaGFkLmNvLm56L3BhcGVycy9sYXllcmVkLWdyYW1tYXIuaHRtbCkgb3IgdGhlIGBnZ2AgaW4gYGdncGxvdDJgLiANClRoZSBpZGVhIGlzIHRoYXQgeW91IGNhbiBjb25zdHJ1Y3QgbWFueSBzZW50ZW5jZXMgYnkgbGVhcm5pbmcganVzdCBhIGZldyBub3VucywgYWRqZWN0aXZlcywgYW5kIHZlcmJzLiBUaGVyZSBhcmUgc3BlY2lmaWMg4oCcd29yZHPigJ0gdGhhdCB3ZSB3aWxsIG5lZWQgdG8gbGVhcm4gYW5kIG9uY2Ugd2UgZG8sIHlvdSB3aWxsIGJlIGFibGUgdG8gY3JlYXRlIChvciDigJx3cml0ZeKAnSkgaHVuZHJlZHMgb2YgZGlmZmVyZW50IHBsb3RzLg0KDQpUaGUgY3JpdGljYWwgcGFydCB0byBtYWtpbmcgZ3JhcGhpY3MgdXNpbmcgYGdncGxvdDJgIGlzIHRoZSBkYXRhIG5lZWRzIHRvIGJlIGluIGEgX3RpZHlfIGZvcm1hdC4gDQpHaXZlbiB0aGF0IHdlIGhhdmUganVzdCBzcGVudCB0aW1lIHB1dHRpbmcgb3VyIGRhdGEgaW4gX3RpZHlfIGZvcm1hdCwgd2UgYXJlIHByaW1lZCB0byB0YWtlIGFkdmFudGFnZSBvZiBhbGwgdGhhdCBgZ2dwbG90MmAgaGFzIHRvIG9mZmVyISANCg0KV2Ugd2lsbCBzaG93IGhvdyBpdCBpcyBlYXN5IHRvIHBpcGUgX3RpZHlfIGRhdGEgKG91dHB1dCkgYXMgaW5wdXQgdG8gb3RoZXIgZnVuY3Rpb25zIHRoYXQgY3JlYXRlIHBsb3RzLiANClRoaXMgYWxsIHdvcmtzIGJlY2F1c2Ugd2UgYXJlIHdvcmtpbmcgDQp3aXRoaW4gdGhlIF90aWR5dmVyc2VfLiANCg0KKipXaGF0IGlzIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uPyoqIA0KQXMgZXhwbGFpbmVkIGJ5IEhhZGxleSBXaWNraGFtOg0KDQo+IFRoZSBncmFtbWFyIHRlbGxzIHVzIHRoYXQgYSBzdGF0aXN0aWNhbCBncmFwaGljIGlzIGEgbWFwcGluZyBmcm9tIGRhdGEgdG8gYWVzdGhldGljIGF0dHJpYnV0ZXMgKGNvbG91ciwgc2hhcGUsIHNpemUpIG9mIGdlb21ldHJpYyBvYmplY3RzIChwb2ludHMsIGxpbmVzLCBiYXJzKS4gVGhlIHBsb3QgbWF5IGFsc28gY29udGFpbiBzdGF0aXN0aWNhbCB0cmFuc2Zvcm1hdGlvbnMgb2YgdGhlIGRhdGEgYW5kIGlzIGRyYXduIG9uIGEgc3BlY2lmaWMgY29vcmRpbmF0ZXMgc3lzdGVtLg0KDQpgZ2dwbG90MmAgVGVybWlub2xvZ3k6IA0KDQotICoqZ2dwbG90KiogLSB0aGUgbWFpbiBmdW5jdGlvbiB3aGVyZSB5b3Ugc3BlY2lmeSB0aGUgZGF0YXNldCBhbmQgdmFyaWFibGVzIHRvIHBsb3QgKHRoaXMgaXMgd2hlcmUgd2UgZGVmaW5lIHRoZSBgeGAgYW5kDQpgeWAgdmFyaWFibGUgbmFtZXMpDQotICoqZ2VvbXMqKiAtIGdlb21ldHJpYyBvYmplY3RzDQogICAgLSBlLmcuIGBnZW9tX3BvaW50KClgLCBgZ2VvbV9iYXIoKWAsIGBnZW9tX2xpbmUoKWAsIGBnZW9tX2hpc3RvZ3JhbSgpYA0KLSAqKmFlcyoqIC0gYWVzdGhldGljcw0KICAgIC0gc2hhcGUsIHRyYW5zcGFyZW5jeSwgY29sb3IsIGZpbGwsIGxpbmUgdHlwZXMNCi0gKipzY2FsZXMqKiAtIGRlZmluZSBob3cgeW91ciBkYXRhIHdpbGwgYmUgcGxvdHRlZA0KICAgIC0gY29udGludW91cywgZGlzY3JldGUsIGxvZywgZXRjDQoNClRoZSBmdW5jdGlvbiBgYWVzKClgIGlzIGFuIGFlc3RoZXRpYyBtYXBwaW5nIGZ1bmN0aW9uIGluc2lkZSB0aGUgYGdncGxvdCgpYCBvYmplY3QuIA0KV2UgdXNlIHRoaXMgZnVuY3Rpb24gdG8gc3BlY2lmeSBwbG90IGF0dHJpYnV0ZXMgKGUuZy4gYHhgIGFuZCBgeWAgdmFyaWFibGUgbmFtZXMpIHRoYXQgd2lsbCBub3QgY2hhbmdlIGFzIHdlIGFkZCBtb3JlIGxheWVycy4gIA0KDQpBbnl0aGluZyB0aGF0IGdvZXMgaW4gdGhlIGBnZ3Bsb3QoKWAgb2JqZWN0IGJlY29tZXMgYSBnbG9iYWwgc2V0dGluZy4gDQpGcm9tIHRoZXJlLCB3ZSB1c2UgdGhlIGBnZW9tYCBvYmplY3RzIHRvIGFkZCBtb3JlIGxheWVycyB0byB0aGUgYmFzZSBgZ2dwbG90KClgIG9iamVjdC4gDQpUaGVzZSB3aWxsIGRlZmluZSB3aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluIGlsbHVzdHJhdGluZyB1c2luZyB0aGUgZGF0YS4NCg0KPC9kZXRhaWxzPg0KDQoqKioNCg0KIyMgKipQb3B1bGF0aW9uIGRlbnNpdHkqKg0KKioqDQoNCkxldCdzIG1ha2UgYSBwbG90IHRvIHNlZSBob3cgcG9wdWxhdGlvbiBkZW5zaXR5IGhhcyBjaGFuZ2VkIG92ZXIgdGltZSBpbiBlYWNoIHN0YXRlLg0KDQpUbyBkbyB0aGlzLCB3ZSB3YW50IHRvIGNhbGN1bGF0ZSBhIG1lYW4gcG9wdWxhdGlvbiBkZW5zaXR5IChhY3Jvc3MgYWxsIHRoZSBjb3VudGllcykgZm9yIGVhY2ggc3RhdGUgZm9yIGVhY2ggeWVhci4gDQoNCldlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBgZ3JvdXBfYnkoKWAgIGFuZCBgc3VtbWFyaXplKClgIGZ1bmN0aW9ucyBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGUgYGdyb3VwX2J5YCBmdW5jdGlvbnMgYWxsb3dzIGZvciB0aGUgZGF0YSB0byBiZSBhcnJhbmdlZCBpbnRvIGdyb3VwcyBmb3Igc3Vic2VxdWVudCBmdW5jdGlvbnMuIA0KDQpJZiB3ZSBncm91cCBvbmx5IGJ5IGBCVVlFUl9TVEFURWAsIHlvdSBzZWUgdGhhdCB0aGlzIHJlc3VsdHMgaW4gNTEgZ3JvdXBzIChvbmUgZm9yIGVhY2ggc3RhdGUgaW5jbHVkaW5nIFdhc2hpbmd0b24gREMpLiBUaGlzIGRvZXMgbm90IGNoYW5nZSBhbnl0aGluZyBhYm91dCB0aGUgZGF0YSBpdHNlbGYgKG9yIGV2ZW4gaG93IGl0IGlzIHByaW50ZWQgYXNpZGUgZnJvbSB0aGUgZ3JvdXBzIHdyaXR0ZW4gYWJvdmUgdGhlIHRhYmxlKSwganVzdCBob3cgaXQgaXMgaGFuZGxlZCBpbiBzdWJzZXF1ZW50IHN0ZXBzLg0KDQpgYGB7cn0NCkFubnVhbCAlPiUgDQogIGdyb3VwX2J5KEJVWUVSX1NUQVRFKQ0KYGBgDQoNCkFsdGVybmF0aXZlbHksIGlmIHdlIGdyb3VwIGJ5IGB5ZWFyYCB0aGlzIHJlc3VsdHMgaW4gOSBncm91cHMgb2YgZGF0YSwgb25lIGZvciBlYWNoIHllYXIuDQoNCmBgYHtyfQ0KQW5udWFsICU+JSANCiAgZ3JvdXBfYnkoeWVhcikNCmBgYA0KDQpXZSB3YW50IHRvIGdyb3VwIGJ5IGJvdGggYEJVWUVSX1NUQVRFYCBhbmQgYHllYXJgLCBzbyB0aGF0IHdlIGdldCB0aGUgbWVhbiBvZiBhbGwgdGhlIGNvdW50aWVzIGZvciBlYWNoIHN0YXRlIGZvciBlYWNoIHllYXIuIElmIHdlIG9ubHkgZGlkIGJ5IGBCVVlFUl9TVEFURWAsIHdlIHdvdWxkIG9ubHkgZ2V0IDUxIHN1bW1hcml6ZWQgcmVzdWx0cywgb25lIGZvciBlYWNoIHN0YXRlIHJlcHJlc2VudGluZyBhIG1lYW4gYWNyb3NzIHRoZSB5ZWFycy4gDQoNCmBgYHtyfQ0KQW5udWFsICU+JSANCiAgZ3JvdXBfYnkoQlVZRVJfU1RBVEUsIHllYXIpDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoaXMgcmVzdWx0cyBpbiA0NTkgZ3JvdXBzLiBUaGlzIG1ha2VzIHNlbnNlIGJlY2F1c2UgNTEgZ3JvdXBzIG92ZXIgOSB5ZWFycyBpcyA1MSBtdWx0aXBsaWVkIGJ5IDksIHdoaWNoIGVxdWFscyA0NTkuIA0KDQpOZXh0LCB3ZSB3aWxsIG5lZWQgdG8gdXNlIHRoZSBgc3VtbWFyaXplKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIE5vdGljZSB0aGF0IHRoZSBgSG1pc2NgIHBhY2thZ2UgdGhhdCB3ZSBsb2FkZWQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGlzIGNhc2Ugc3R1ZHkgYWxzbyBoYXMgYSBmdW5jdGlvbiBjYWxsZWQgYHN1bW1hcml6ZSgpYCwgYW5kIHRoZXJlZm9yZSwgY3JlYXRpbmcgYSBjb25mbGljdC4gU2luY2Ugd2UgbG9hZGVkIGBIbWlzY2AgYWZ0ZXIgd2UgbG9hZGVkIGBkcGx5cmAsIHRoZSBgc3VtbWFyaXplKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgaXMgbWFza2VkIGJ5IHRoZSBgc3VtbWFyaXplKClgIGZ1bmN0aW9uIG9mIHRoZSBgSG1pc2NgIHBhY2thZ2UsIG1lYW5pbmcgdGhhdCBpZiB3ZSBkbyBub3Qgc3BlY2lmeSB3aGljaCBwYWNrYWdlIHdlIHdhbnQgdG8gdXNlLCBSIHdpbGwgdXNlIHRoZSBgc3VtbWFyaXplKClgIGZ1bmN0aW9uIG9mIHRoZSBgSG1pc2NgIHBhY2thZ2UgYnkgZGVmYXVsdC4gVG8gZGVhbCB3aXRoIHRoaXMsIHdlIGNhbiB1c2UgYGRwbHlyOjpzdW1tYXJpemUoKWAgdG8gc3BlY2lmeSB0aGF0IHdlIHdhbnQgdG8gdXNlIHRoZSBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBIb3dldmVyLCBzaW5jZSB3ZSB3aWxsIGJlIHVzaW5nIHRoaXMgZnVuY3Rpb24gc2V2ZXJhbCB0aW1lcyBsYXRlciBpbiB0aGUgY2FzZSBzdHVkeSwgd2UgbWlnaHQgd2FudCB0byB0ZWxsIFIgdGhhdCB3aGVuIHdlIHVzZSB0aGUgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbiwgd2Ugd2FudCB0byB1c2UgdGhlIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFdlIGNhbiBkbyB0aGlzIGxpa2Ugc286DQoNCmBgYHtyfQ0Kc3VtbWFyaXplIDwtIGRwbHlyOjpzdW1tYXJpemUNCmBgYA0KDQpZb3UgbWF5IGFsc28gZm9sbG93IHRoaXMgW2xpbmtdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvYmxvZy8yMDE4LzA2L2NvbmZsaWN0ZWQvKSB0byBsZWFybiBhYm91dCB0aGUgYGNvbmZsaWN0ZWRgIHBhY2thZ2UuDQoNCldlIGNhbiB1c2UgdGhlIGBzdW1tYXJpemUoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIGBtZWFuX0RFTlNgLCB3aGljaCB3aWxsIGJlIGVxdWFsIHRvIHRoZSBtZWFuIG9mIHRoZSBwb3B1bGF0aW9uIGBkZW5zaXR5YCB2YXJpYWJsZSBmb3IgYWxsIHRoZSBjb3VudGllcyB3aXRoaW4gZWFjaCBvZiB0aGUgNDQ5IGdyb3Vwcy4gSWYgd2UgaGFkIG1pc3NpbmcgdmFsdWVzIHdlIHdvdWxkIG5lZWQgdG8gdXNlIHRoZSBgbmEucm0gPSBUUlVFYCBhcmd1bWVudCB0byByZW1vdmUgYW55IG1pc3NpbmcgdmFsdWVzIGluIG91ciBjYWxjdWxhdGlvbi4NCg0KYGBge3J9DQpBbm51YWwgJT4lIA0KICBncm91cF9ieShCVVlFUl9TVEFURSwgeWVhcikgJT4lDQogIHN1bW1hcml6ZShtZWFuX0RFTlMgPSBtZWFuKGRlbnNpdHksIG5hLnJtID0gVFJVRSkpDQpgYGANCg0KT0shIE5vdyB3ZSBhcmUgcmVhZHkgdG8gbWFrZSBvdXIgZmlyc3QgcGxvdC4gDQoNCldlIHdpbGwgc3RhcnQgd2l0aCB0aGUgYGdncGxvdCgpYGZ1bmN0aW9uIHRvIHNwZWNpZnkgd2hhdCB2YXJpYWJsZXMgd2lsbCBiZSB1c2VkIGZvciB0aGUgeC1heGlzIGFuZCB5LWF4aXMsIGFzIHdlbGwgYXMgaWYgYW55IHZhcmlhYmxlIHNob3VsZCBiZSB1c2VkIHRvIHNwZWNpZnkgZGlmZmVyZW50IGNvbG9ycyBvbiB0aGUgcGxvdC4gVGhpcyB3aWxsIHJlc3VsdCBpbiBhIGJsYW5rIHBsb3QuIA0KDQpXZSBuZWVkIHRvIHVzZSBhIGBnZW9tXypgIGZ1bmN0aW9uIHRvIHNwZWNpZnkgd2hhdCB0eXBlIG9mIHBsb3Qgd2Ugd291bGQgbGlrZSB0byBtYWtlLiANCg0KSWYgeW91IHR5cGUgYGdlb21fYCBpbnRvIHRoZSBjb25zb2xlIG9mIFJTdHVkaW8sIHlvdSB3aWxsIHNlZSBhIGxpc3Qgb2Ygb3B0aW9ucy4gDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImdlb20ucG5nIikpDQpgYGANCg0KV2Ugd2lsbCBjcmVhdGUgYSBzY2F0dGVyIHBsb3QgdXNpbmcgdGhlIGBnZW9tX3BvaW50KClgIGZ1bmN0aW9uLiBXZSB3aWxsIGFsc28gdXNlIHRoZSBgdGhlbWVfbWluaW1hbCgpYCBmdW5jdGlvbiB0byBjaGFuZ2UgdGhlIG92ZXJhbGwgYWVzdGhldGljcyBvZiB0aGUgcGxvdC4gU2VlIFtoZXJlXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2d0aGVtZS5odG1sKSBmb3IgYSBsaXN0IG9mIG9wdGlvbnMuDQoNCldlIHdpbGwgYWxzbyB1c2UgdGhlIGB0aGVtZSgpYCBmdW5jdGlvbiB0byBmdXJ0aGVyIHNwZWNpZnkgaG93IHdlIHdhbnQgdGhlIHBsb3QgdG8gYmUgZGlzcGxheWVkLiBXZSB3b3VsZCBsaWtlIHRoZSB4LWF4aXMgdGV4dCB0byBiZSBhbmdsZWQgYnkgOTAgZGVncmVlcy4gV2UgY2FuIHVzZSB0aGUgYGVsZW1lbnRfdGV4dCgpYCBmdW5jdGlvbiB0byBjaGFuZ2UgYXNwZWN0cyBhYm91dCB0aGUgdGV4dCBhbmQgd2UgY2FuIHVzZSB0aGUgYGF4aXMudGV4dC54YCBhcmd1bWVudCB0byBzcGVjaWZ5IHRoYXQgd2Ugd2FudCB0byBzcGVjaWZpY2FsbHkgY2hhbmdlIHRoZSB0ZXh0IG9mIHRoZSB4LWF4aXMuIA0KDQpZb3UgY2FuIHR5cGUgYHRoZW1lKClgIGluIHRoZSBSU3R1ZGlvIGNvbnNvbGUgYW5kIHByZXNzIHRhYiB0byBzZWUgYSBsaXN0IG9mIGFyZ3VtZW50IG9wdGlvbnMgZm9yIHRoaW5ncyB0aGF0IHlvdSBjYW4gY2hhbmdlIGluIHlvdXIgcGxvdC4gDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInRoZW1lLnBuZyIpKQ0KYGBgDQpGaW5hbGx5LCB3ZSBjYW4gdXNlIHRoZSBgbGFicygpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UgdG8gc3BlY2lmeSB0aGUgbGFiZWxzIG9mIHRoZSBwbG90LiANCg0KYGBge3J9DQpBbm51YWwgJT4lIA0KICBncm91cF9ieShCVVlFUl9TVEFURSwgeWVhcikgJT4lDQogIHN1bW1hcml6ZShtZWFuX0RFTlMgPSBtZWFuKGRlbnNpdHksIG5hLnJtID0gVFJVRSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBCVVlFUl9TVEFURSwgeSA9IG1lYW5fREVOUywgY29sID0geWVhcikpICsgDQogICAgZ2VvbV9wb2ludCgpICsgDQogICAgdGhlbWVfbWluaW1hbCgpKw0KICAgIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsNCiAgICBsYWJzKHggPSAiU3RhdGUiLA0KICAgICAgICAgdGl0bGUgPSAiTWVhbiBDb3VudHkgUG9wdWxhdGlvbiBEZW5zaXR5IG9mIGVhY2ggU3RhdGUiLA0KICAgICAgICAgeSA9ICJNZWFuIFBvcHVsYXRpb24gRGVuc2l0eSAoUGVvcGxlIHBlciBzcXVhcmUgbWlsZSkiKQ0KYGBgDQoNCldlIGNhbiBzZWUgdGhhdCB0aGUgYXZlcmFnZSBzdGF0ZSBwb3B1bGF0aW9uIGRlbnNpdHkgaXMgZmFpcmx5IHNpbWlsYXIgZm9yIG1vc3Qgc3RhdGVzLiBIb3dldmVyIERDLCBNQSwgTkosIE5ZLCBSSSwgYW5kIFZBIGhhdmUgbXVjaCBoaWdoZXIgYXZlcmFnZSBjb3VudHkgZGVuc2l0aWVzLiBXZSBhbHNvIHNlZSB0aGF0IERDIHNob3dzIHRoZSBsYXJnZXN0IGNoYW5nZSBvdmVyIHRpbWUsIGFzIHdlIGNhbiBzZWUgdGhlIG90aGVyIGluZGl2aWR1YWwgcG9pbnRzIGZvciBlYWNoIHllYXIuIEZvciBvdGhlciBzdGF0ZXMgdGhlIGNoYW5nZSB3YXMgc28gc21hbGwgdGhhdCB0aGV5IGFyZSBvdmVybGFwcGluZy4NCg0KV2hhdCBhYm91dCBvdmVyYWxsIHBvcHVsYXRpb24gZGVuc2l0eSwgaG93IGRpZCB0aGUgbmF0aW9uYWwgYXZlcmFnZSBvZiBhbGwgVVMgY291bnRpZXMgY2hhbmdlPw0KDQpXZSB3aWxsIGlnbm9yZSB0aGUgZGlmZmVyZW50IHN0YXRlcyBpbiB0aGlzIGNhc2UgYW5kIHdlIHdpbGwgY2FsY3VsYXRlIHRoZSBtZWFuIG9mIGFsbCBVUyBjb3VudGllcyBmb3IgZWFjaCB5ZWFyLg0KDQojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KSG93IG1pZ2h0IHlvdSBjcmVhdGUgdGhpcyBwbG90Pw0KDQojIyMjDQoNCioqKg0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQoNCmBgYHtyfQ0KVVNhdmdfZGVucyA8LSANCiAgQW5udWFsICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHN1bW1hcml6ZShtZWFuX0RFTlMgPSBtZWFuKGRlbnNpdHkpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IG1lYW5fREVOUykpICsgDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCkpICsNCiAgICBsYWJzKHRpdGxlID0gIlVTIG1lYW4gcG9wdWxhdGlvbiBkZW5zaXR5IiwNCiAgICAgICAgIHggPSAieWVhciIsDQogICAgICAgICB5ID0gInBvcHVsYXRpb24gZGVuc2l0eSAocGVvcGxlIHBlciBzcXVhcmUgbWlsZSkiKQ0KYGBgDQoNCkluIHRoaXMgY2FzZSB3ZSBzYXZlZCB0aGUgcGxvdCB0byBhbiBvYmplY3QgY2FsbGVkIGBVU2F2Z19kZW5zYC4NCg0KPC9kZXRhaWxzPg0KKioqDQoNCg0KYGBge3J9DQpVU2F2Z19kZW5zDQpgYGANCg0KT3ZlcmFsbCB0aGUgZGVuc2l0eSBoYXMgaW5jcmVhc2VkLCBpZiB5b3UgdGFrZSBhIGxvb2sgYXQgdGhlIHktYXhpcyB5b3UgY2FuIHNlZSB0aGF0IHRoZSBkZW5zaXR5IGhhcyBjaGFuZ2VkIGJ5IGFib3V0IDEzIHBlb3BsZSBwZXIgc3F1YXJlIG1pbGUgZnJvbSAyMDA2IHRvIDIwMTQuIA0KDQpIb3cgZG9lcyB0aGlzIGNvbXBhcmUgd2l0aCByYXcgcG9wdWxhdGlvbiB2YWx1ZXM/DQoNClRvIG1ha2UgdGhpcyBwbG90LCB3ZSB3aWxsIHRha2UgdGhlIHN1bSBvZiB0aGUgcG9wdWxhdGlvbiB2YWx1ZXMgZm9yIGVhY2ggY291bnR5IHJhdGhlciB0aGFuIHRoZSBtZWFuLiANCg0KDQojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KSG93IG1pZ2h0IHlvdSBjcmVhdGUgdGhpcyBwbG90Pw0KDQojIyMjDQoNCioqKg0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQoNCg0KYGBge3J9DQpvdmVyYWxsX2RlbnNpdHkgPC0gDQogIEFubnVhbCAlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBzdW1tYXJpemUodG90YWxfcG9wdWxhdGlvbiA9IHN1bShwb3B1bGF0aW9uKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9wb3B1bGF0aW9uKSkgKyANCiAgICAgIGdlb21fcG9pbnQoKSArDQogICAgICBnZW9tX3Ntb290aCgpICsNCiAgICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgICAgIGxhYnModGl0bGUgPSAiVVMgUG9wdWxhdGlvbiBmcm9tIDIwMDYtMjAxNCIsDQogICAgICAgICAgIHggPSAieWVhciIsDQogICAgICAgICAgIHkgPSAiVVMgdG90YWwgcG9wdWxhdGlvbiIpDQogDQpgYGANCg0KPC9kZXRhaWxzPg0KDQpgYGB7cn0NCm92ZXJhbGxfZGVuc2l0eQ0KYGBgDQoNCiMjICoqUnVyYWwgYW5kIFVyYmFuIGFyZWFzKioNCioqKg0KDQpIb3cgaGF2ZSB0aGUgbnVtYmVyIG9mIHJ1cmFsIGFuZCB1cmJhbiBhcmVhcyBjaGFuZ2VkIG92ZXIgeWVhcnM/DQoNClRvIGRldGVybWluZSBob3cgdGhlIG51bWJlciBvZiBlYWNoIHR5cGUgb2YgY291bnR5IGhhcyBjaGFuZ2VkIG92ZXIgdGltZSwgd2Ugd2lsbCB1c2UgdGhlIGBjb3VudCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIGFmdGVyIGdyb3VwaW5nIGJ5IHRoZSBgeWVhcmAgdmFyaWFibGUgdG8gY291bnQgdGhlIG51bWJlciBvZiBvY2N1cnJlbmNlcyBvZiB0aGUgdW5pcXVlIHZhbHVlcyAod2hpY2ggYXJlIGBSdXJhbGAgYW5kIGBVcmJhbmApIGluIHRoZSBgcnVyYWxfdWJyYW5gIHZhcmlhYmxlLg0KDQoNCmBgYHtyfQ0KQW5udWFsICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIGNvdW50KHJ1cmFsX3VyYmFuKQ0KYGBgDQoNCkluIHRoaXMgY2FzZSwgd2UgY2FuIG1ha2UgYSBwbG90IHVzaW5nIHR3byBkaWZmZXJlbnQgYGdlb21fKmAgbGF5ZXJzIHRvZ2V0aGVyLiBXaGF0ZXZlciBgZ2VvbV8qYCBsYXllciBpcyBhZGRlZCBsYXN0IHdpbGwgYmUgZGlzcGxheWVkIG9uIHRvcC4gDQoNCldlIHdpbGwgdXNlIGBnZW9tX3BvaW50KClgIGFuZCBgZ2VvbV9zbW9vdGgoKWAgdG8gYWRkIGEgbGluZSBjb25uZWN0aW5nIHRoZSBwb2ludHMgb2YgdGhlIHNjYXR0ZXIgcGxvdCBvZiB0aGUgYGdlb21fcG9pbnQoKWAgZnVuY3Rpb24uIFdlIGNhbiBhbHNvIHVzZSB0aGUgYGZhY2V0X3dyYXAoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIHRvIGNyZWF0ZSBzdWJwbG90cyBiYXNlZCBvbiB0aGUgYHJ1cmFsX3VyYmFuYCB2YXJpYWJsZS4gDQoNClRoaXMgY3JlYXRlcyBhIHN1YnBsb3QgZm9yIHRoZSBgUnVyYWxgIHZhbHVlcyBhbmQgYW5vdGhlciBmb3IgdGhlIGBVcmJhbmAgdmFsdWVzLiBUaGUgYHNjYWxlcyA9ICJmcmVlImAgYXJndW1lbnQgYWxsb3dzIGZvciBlYWNoIHRvIGhhdmUgYSBkaWZmZXJlbnQgc2NhbGUgZm9yIHRoZSB5LWF4aXMuDQoNCmBgYHtyLCBmaWcud2lkdGg9MTB9DQpBbm51YWwgJT4lIA0KICBncm91cF9ieSh5ZWFyKSAlPiUNCiAgY291bnQocnVyYWxfdXJiYW4pICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbiwgY29sID0gcnVyYWxfdXJiYW4sIA0KICAgICAgICAgICAgIGdyb3VwID0gcnVyYWxfdXJiYW4pKSArIA0KICAgIGdlb21fcG9pbnQoKSArIA0KICAgIGdlb21fc21vb3RoKCkgKw0KICAgIGZhY2V0X3dyYXAofiBydXJhbF91cmJhbiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgdGhlbWVfbWluaW1hbCgpICsNCiAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArDQogICAgbGFicyh5ID0gIk51bWJlciBvZiBDb3VudGllcyIsIA0KICAgICAgICAgeCA9ICJZZWFyIiwNCiAgICAgICAgIHRpdGxlID0gIkNoYW5nZSBpbiB0aGUgbnVtYmVyIG9mIHRoZSBydXJhbCBhbmQgdXJiYW4gY291bnRpZXMgaW4gdGhlIFVTIG92ZXIgdGltZSIpDQpgYGANCg0KQXMgb25lIG1pZ2h0IGV4cGVjdCwgaXQgbG9va3MgbGlrZSB0aGUgbnVtYmVyIG9mIHVyYmFuIGFyZWFzIGhhcyBpbmNyZWFzZWQsIHdoaWxlIHRoZSBudW1iZXIgb2YgcnVyYWwgYXJlYXMgaGFzIGRlY3JlYXNlZCBvdmVyIHRpbWUuDQoNCkxldCdzIGFsc28gY3JlYXRlIGEgdGFibGUgdG8gbG9vayBhdCB0aGUgbnVtYmVyIG9mIHJ1cmFsIGFuZCB1cmJhbiBjb3VudGllcyBvdmVyIHRpbWUuIFRvIGRvIHRoaXMgd2UgY2FuIHVzZSB0aGUgcGFja2FnZSBgZm9ybWF0dGFibGVgLiBXZSB3aWxsIGNvbnZlcnQgb3VyIGRhdGEgaW50byBhIGZvcm1hdCBuZWVkZWQgZm9yIHRoZSBgZm9ybWF0dGFibGVgIHBhY2thZ2UuIA0KDQpXZSBwcmV2aW91c2x5IGNvdW50ZWQgdGhlIG51bWJlciBvZiBgUnVyYWxgIGFuZCBgVXJiYW5gIGNvdW50aWVzIGZvciBlYWNoIHllYXIuIEhvd2V2ZXIsIHRoZSBkYXRhIHdhcyBwcmVzZW50ZWQgaW4gYSBmb3JtYXQgdGhhdCBpcyBjYWxsZWQgW2xvbmcgZm9ybWF0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XaWRlX2FuZF9uYXJyb3dfZGF0YSkuIEluIHRoaXMgZm9ybWF0LCB2YXJpYWJsZXMgdGhhdCBjb3VsZCBwb3NzaWJseSBiZSBwcmVzZW50ZWQgYXMgc2VwYXJhdGUgY29sdW1ucyBhcmUgY29uZGVuc2VkIGludG8gZmV3ZXIgY29sdW1ucywgd2hpbGUgc3RpbGwgbWFpbnRhaW5pbmcgb25seSBhIHNpbmdsZSB2YWx1ZSBwZXIgY2VsbC4NCg0KVGhlIG9wcG9zaXRlIG9mIHRoaXMgZm9ybWF0IGlzIGNhbGxlZCBbd2lkZSBmb3JtYXRdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1dpZGVfYW5kX25hcnJvd19kYXRhKSBkYXRhLCB3aGljaCB0aGVyZWZvcmUgaGFzIG1vcmUgY29sdW1ucyBhbmQgZmV3ZXIgcm93cy4gVGhpcyBpcyBiZXN0IGlsbHVzdHJhdGVkIHdpdGggYW4gZXhhbXBsZS4NCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL2Zsb3VyaXNoLnN0dWRpby9pbWFnZXMvYmxvZy93aWRlLXRvLWxvbmcucG5nIikNCmBgYA0KDQojIyMjIFtbc291cmNlXV0oaHR0cHM6Ly9mbG91cmlzaC5zdHVkaW8vaW1hZ2VzL2Jsb2cvd2lkZS10by1sb25nLnBuZykNCg0KT24gdGhlIGxlZnQgaXMgIndpZGUiIGRhdGFzZXQgd2l0aCBtb3JlIGNvbHVtbnMgYW5kIGZld2VyIHJvd3MuIA0KT24gdGhlIHJpZ2h0IGlzIGEgImxvbmciIGRhdGFzZXQgd2hlcmUgdGhlIG1vbnRoIGNvbHVtbnMgaGF2ZSBiZWVuIGNvbGxhcHNlZCBpbnRvIHR3byBsb25nZXIgY29sdW1ucyAob25lIHdpdGggdGhlIG5hbWUgb2YgdGhlIG1vbnRoIGFuZCBvbmUgd2l0aCB0aGUgbnVtZXJpYyB2YWx1ZSkgcmVzdWx0aW5nIGluIGZld2VyIGNvbHVtbnMgYW5kIG1vcmUgcm93cy4gDQoNCldoaWxlIGxvbmcgZm9ybWF0IGlzIHZlcnkgdXNlZnVsIGZvciBjcmVhdGluZyBwbG90cyB3aXRoIGBnZ3Bsb3QyYCBpdCBpcyBoZWxwZnVsIHRvIGhhdmUgdGhlIGRhdGEgaW4gd2lkZSBmb3JtYXQgZm9yIHRhYmxlcyB0aGF0IHNvbWVvbmUgd291bGQgcXVpY2tseSByZWFkLCB3aGljaCBpcyBvdXIgY3VycmVudCBnb2FsLg0KDQoNCioqKg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBhbm90aGVyIGV4YW1wbGUuIDwvc3VtbWFyeT4NCg0KSGVyZSBpcyBhbiBleGFtcGxlIG9mIHdpZGUgZGF0YSBhYm91dCBkaWZmZXJlbnQgbWVhc3VyZW1lbnRzIG9mIGEgdmFyaWV0eSBzcGVjaWVzIG9mIElyaXMgZmxvd2Vycy4gDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Kc2V0LnNlZWQoMTIzKQ0Kd2lkZTEgPC1zbGljZV9zYW1wbGUoaXJpcywgbiA9IDEwKQ0Kd2lkZTENCmBgYA0KDQpPSywgc28gY3VycmVudGx5IHdlIGhhdmUgNCBkaWZmZXJlbnQgY29sdW1ucyBhYm91dCBtZWFzdXJlbWVudHMgb2YgZGlmZmVyZW50IGZsb3dlcnMuIFNpbmNlIGFsbCBvZiB0aGVzZSBtZWFzdXJlbWVudHMgYXJlIHNpbWlsYXIsIG9uZSBtaWdodCBwcm9kdWNlIGEgbmV3IHZhcmlhYmxlIHRoYXQgaXMgbWFkZSB1cCBvZiB0aGUgbmFtZXMgb2YgdGhlIGZpcnN0IGZvdXIgdmFyaWFibGVzIGFuZCBhbm90aGVyIHRoYXQgaXMgdGhlIG51bWVyaWMgdmFsdWUgbGlrZSBzbzoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmxvbmcgPC1waXZvdF9sb25nZXIod2lkZTEsIGNvbHMgPSAtU3BlY2llcywgbmFtZXNfdG8gPSAiTWVhc3VyZW1lbnQiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKQ0KbG9uZw0KYGBgDQoNCjwvZGV0YWlscz4NCioqKg0KDQpOZXh0LCB3ZSBkZW1vbnN0cmF0ZSBob3cgdG8gY29udmVydCB0aGUgY291bnRzIG9mIGBSdXJhbGAgYW5kIGBVcmJhbmAgZGF0YSBpbnRvIHdpZGUgZm9ybWF0IGZyb20gbG9uZyBmb3JtYXQuIEhlcmUgaXMgb3VyIG9yaWdpbmFsIGRhdGE6DQoNCmBgYHtyfQ0KQW5udWFsICAlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBjb3VudChydXJhbF91cmJhbikNCmBgYA0KDQpXZSB3b3VsZCBsaWtlIHRoZSBgcnVyYWxfdXJiYW5gIGRhdGEgdG8gYmUgc2hvd24gaW4gdHdvIGRpZmZlcmVudCBjb2x1bW5zOyBvbmUgdGhhdCBzaG93cyBgUnVyYWxgIGNvdW50cyBhbmQgb25lIHRoYXQgc2hvd3MgYFVyYmFuYCBjb3VudHMuIFdlIGNhbiB1c2UgdGhlIGBwaXZvdF93aWRlcigpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlIHRvIGRvIHRoaXMuIFRoaXMgdGFrZXMgdHdvIGltcG9ydGFudCBhcmd1bWVudHM6DQoNCjEuIGBuYW1lc19mcm9tYDogdGhpcyBhcmd1bWVudCBpbmRpY2F0ZXMgd2hhdCB2YXJpYWJsZSB0byB1c2UgdG8gY3JlYXRlIHRoZSBuYW1lcyBvZiB0aGUgbmV3IHZhcmlhYmxlcw0KMi4gYHZhbHVlc19mcm9tYDogdGhpcyBhcmd1bWVudCBpbmRpY2F0ZXMgd2hhdCB2YXJpYWJsZSB0byB1c2UgdG8gZmlsbCBpbiB0aGUgdmFsdWVzIG9mIHRoZSBuZXcgdmFyaWFibGVzDQoNCkluIG91ciBjYXNlLCB3ZSB1c2UgdGhlIG5hbWVzIGZyb20gdGhlIGBydXJhbF91cmJhbmAgdmFyaWFibGUgYW5kIHRoZSB2YWx1ZXMgZnJvbSB0aGUgYG5gIHZhcmlhYmxlLg0KDQpgYGB7cn0NCkFubnVhbCAlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBjb3VudChydXJhbF91cmJhbikgJT4lDQogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcnVyYWxfdXJiYW4sIA0KICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBuKQ0KYGBgDQoNCk5pY2UhDQoNCk5vdywgbGV0J3MgYWxzbyBjcmVhdGUgdHdvIG5ldyB2YXJpYWJsZXMgdGhhdCBzaG93IHRoZSBjaGFuZ2UgaW4gY291bnQgb2YgcnVyYWwgYW5kIHVyYmFuIGNvdW50aWVzIGZyb20gb25lIHllYXIgdG8gdGhlIG5leHQuIFdlIGNhbiBkbyBzbyB1c2luZyB0aGUgYGxhZygpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGlzIGZ1bmN0aW9uIHdpbGwgZmluZCB0aGUgcHJldmlvdXMgdmFsdWUgdGh1cyBgUnVyYWwgLSBsYWcoUnVyYWwpYCB3aWxsIHRha2UgdGhlIGN1cnJlbnQgcm93IGFuZCBzdWJ0cmFjdCB0aGUgcHJldmlvdXMgcm93J3MgdmFsdWUuIE5vdGUgdGhhdCBpcyBuZWNlc3NhcnkgdG8gaW5jbHVkZSB0aGUgYHVuZ3JvdXAoKWAgZnVuY3Rpb24gdG8gc3RvcCBncm91cGluZyBieSB5ZWFyLg0KDQpgYGB7cn0NCkFubnVhbCAlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBjb3VudChydXJhbF91cmJhbikgJT4lDQogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcnVyYWxfdXJiYW4sDQogICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IG4pICU+JQ0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUoIlJ1cmFsIENoYW5nZSIgPSBSdXJhbCAtIGxhZyhSdXJhbCksIA0KICAgICAgICAgIlVyYmFuIENoYW5nZSIgPSBVcmJhbiAtIGxhZyhVcmJhbikpDQpgYGANCg0KTGV0J3MgYWxzbyBhZGQgYSBjb2x1bW4gYWJvdXQgdGhlIHBlcmNlbnQgdXJiYW4gZm9yIGVhY2ggeWVhci4gV2UgdXNlIHRoZSBiYXNlIGByb3VuZCgpYCBmdW5jdGlvbiB0byByb3VuZCB0aGUgcGVyY2VudGFnZXMgdG8gMiBkaWdpdHMgYWZ0ZXIgdGhlIGRlY2ltYWwgdXNpbmcgdGhlIGBkaWdpdHMgPSAyYCBhcmd1bWVudC4gDQoNCkZpbmFsbHksIHdlIHJlbmFtZSB0aGUgYHllYXJgIHZhcmlhYmxlIHRvIGJlIGBZZWFyYCB1c2luZyB0aGUgYHJlbmFtZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLCB3aGljaCByZXF1aXJlcyB0aGF0IHRoZSBuZXcgbmFtZSBiZSBsaXN0ZWQgYmVmb3JlIHRoZSBgPWAgc2lnbiBmb2xsb3dlZCBieSB0aGUgb2xkIG5hbWUuIA0KDQpgYGB7cn0NClJfVSA8LSANCiAgQW5udWFsICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIGNvdW50KHJ1cmFsX3VyYmFuKSAlPiUNCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBydXJhbF91cmJhbiwNCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gbikgJT4lDQogIHVuZ3JvdXAoKSAlPiUgDQogIG11dGF0ZSgiUnVyYWwgQ2hhbmdlIiA9IFJ1cmFsIC0gbGFnKFJ1cmFsKSwgDQogICAgICAgICAiVXJiYW4gQ2hhbmdlIiA9IFVyYmFuIC0gbGFnKFVyYmFuKSwNCiAgICAgICAgICJQZXJjZW50IFVyYmFuIiA9IHJvdW5kKChVcmJhbi8oVXJiYW4gKyBSdXJhbCkpKjEwMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyKSkgJT4lDQogIHJlbmFtZSgiWWVhciIgPSAieWVhciIpDQoNClJfVQ0KYGBgDQoNCk5pY2UsIG5vdyBpdCBpcyBwcmV0dHkgZWFzeSB0byBpbnRlcnByZXQgdGFibGUsIGJ1dCB3ZSBjYW4gbWFrZSBpdCBldmVuIGVhc2llciB0byBxdWlja2x5IGFzc2VzcyB0cmVuZHMgaW4gdGhlIGRhdGEgdXNpbmcgdGhlIGBmb3JtYXR0YWJsZWAgcGFja2FnZS4gDQoNClRoZSBgZm9ybW1hdHRhYmxlKClgIGZ1bmN0aW9uIGNyZWF0ZXMgYSBmb3JtYXR0ZWQgdGFibGUsIGFuZCB0YWtlcyBhIGxpc3Qgb2YgdmFyaWFibGVzIGFuZCBhIHN0eWxpemVkIHZlcnNpb24gb2YgZWFjaCB2YXJpYWJsZSBpbiB3aGljaCB0byBhZGQgc3BlY2lhbCBmb3JtYXR0aW5nLg0KDQpBcyBhIHNpbXBsZSBleGFtcGxlLCB3ZSB3aWxsIHVzZSB0aGUgYGNvbG9yX2JhcigpYCBmdW5jdGlvbiBvZiB0aGlzIHBhY2thZ2UgdG8gYWRkIGNvbG9yIGJhcnMgdG8gdGhlIGBwZXJjZW50X3VyYmFuYCBjb2x1bW4gd2hpY2ggc2hvd3MgY2hhbmdlcyBpbiB2YWx1ZXMgYnkgdGhlIHdpZHRoIG9mIGEgY29sb3IgYmFyLg0KDQpgYGB7cn0NCmZvcm1hdHRhYmxlOjpmb3JtYXR0YWJsZShSX1UsIGxpc3QoYFBlcmNlbnQgVXJiYW5gID0gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0dGFibGU6OmNvbG9yX2JhcigiI0ZBNjE0QiIpKSkNCmBgYA0KDQpOaWNlLCBub3cgd2UgY2FuIHNlZSBob3cgbXVjaCB0aGUgcGVyY2VudGFnZSBoYXMgY2hhbmdlZCBvdmVyIHRpbWUuIA0KDQoNCiMjICoqVVMgc2hpcG1lbnRzIG92ZXIgdGltZSoqDQoqKioNCg0KTm93IGxldCdzIGdldCBhIHNlbnNlIG9mIGhvdyB0aGUgc2hpcG1lbnRzIG9mIFtveHljb2RvbmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL09waW9pZF9lcGlkZW1pY19pbl90aGVfVW5pdGVkX1N0YXRlcykgYW5kIFtoeWRyb2NvZG9uZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvT3Bpb2lkX2VwaWRlbWljX2luX3RoZV9Vbml0ZWRfU3RhdGVzKSBjaGFuZ2VkIG92ZXIgdGltZSBhY3Jvc3MgYWxsIGNvdW50aWVzIGluIHRoZSBVUy4NCg0KRmlyc3QsIHdlIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBpbiB0aGUgYEFubnVhbGAgZGF0YSB0aGF0IGlzIHRoZSBudW1iZXIgb2YgcGlsbHMgKGluIG1pbGxpb25zKSwgYXMgdGhpcyBpcyBlYXNpZXIgZm9yIHVzIHRvIGludGVycHJldC4NCg0KYGBge3J9DQpBbm51YWwgJTw+JSANCiAgbXV0YXRlKFBpbGxzX2luX21pbGxpb25zID0gRE9TQUdFX1VOSVQvMTAwMDAwMCkNCmBgYA0KDQpOZXh0LCBsZXQncyBtYWtlIGEgcGxvdCB1c2luZyB0aGUgYHN0YXRfc3VtbWFyeSgpYCBmdW5jdGlvbiByYXRoZXIgdGhhbiBhIGBnZW9tXypgIGZ1bmN0aW9uLCBiZWNhdXNlIHRoaXMgYWxsb3dzIGEgdXNlciB0byBjYWxjdWxhdGUgZGlmZmVyZW50IGZlYXR1cmVzIGFib3V0IHRoZSBkYXRhIHRvIHBsb3QgdXNpbmcgY3VzdG9tIGZ1bmN0aW9ucyB0aGF0IGFyZSB3cmFwcGVycyBmb3IgdGhlIGBzbWVhbi4qYCBmdW5jdGlvbnMgZnJvbSB0aGUgYEhtaXNjYCBwYWNrYWdlLiANCg0KRm9yIGV4YW1wbGUsIHRoZSBgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZClgIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIGBzbWVhbi5zZGAgZnVuY3Rpb24gZnJvbSB0aGUgYEhtaXNjYCBwYWNrYWdlLiANCg0KU2VlIHRoZSBbZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL0htaXNjL0htaXNjLnBkZikgZm9yIHRoZSBgSG1pc2NgIHBhY2thZ2UgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGVzZSBmdW5jdGlvbnMuDQoNCmdncGxvdDIgd3JhcHBlciB8IEhtaXNjIGZ1bmN0aW9uIHwgRGV0YWlscw0KLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmBtZWFuX2NsX25vcm1hbGAgfCBgc21lYW4uY2wubm9ybWFsYCB8IGNvbXB1dGVzIDMgc3VtbWFyeSB2YXJpYWJsZXM6IHRoZSBzYW1wbGUgbWVhbiBhbmQgbG93ZXIgYW5kIHVwcGVyIEdhdXNzaWFuIGNvbmZpZGVuY2UgbGltaXRzIGJhc2VkIG9uIHRoZSB0LWRpc3RyaWJ1dGlvbiAgDQpgbWVhbl9zZGAgfCBgc21lYW4uc2RgIHwgY29tcHV0ZXMgdGhlIG1lYW4gcGx1cyBvciBtaW51cyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uICAgDQpgbWVhbl9zZGxgICB8IGBzbWVhbi5zZGxgIHwgY29tcHV0ZXMgdGhlIG1lYW4gcGx1cyBvciBtaW51cyBhIGNvbnN0YW50IHRpbWVzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24NCmBtZWFuX2NsX2Jvb3RgIHwgYHNtZWFuLmNsLmJvb3RgIHwgZmFzdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgYmFzaWMgbm9ucGFyYW1ldHJpYyBib290c3RyYXAgZm9yIG9idGFpbmluZyBjb25maWRlbmNlIGxpbWl0cyBmb3IgdGhlIHBvcHVsYXRpb24gbWVhbiB3aXRob3V0IGFzc3VtaW5nIG5vcm1hbGl0eSAoZGVmYXVsdCBpcyAxMDAwIGJvb3RzdHJhcCBzYW1wbGVzKQ0KYG1lZGlhbl9oaWxvd2AgfCBgc21lZGlhbi5oaWxvd2AgfCBjb21wdXRlcyB0aGUgc2FtcGxlIG1lZGlhbiBhbmQgYSBzZWxlY3RlZCBwYWlyIG9mIG91dGVyIHF1YW50aWxlcyBoYXZpbmcgZXF1YWwgdGFpbCBhcmVhcyAgDQoNCldlIHdpbGwgdXNlIHRoZSBgbWVhbl9jbF9ib290KClgIGZ1bmN0aW9uIHRvIGNyZWF0ZSBvdXIgcGxvdC4gQXMgbm90ZWQgYWJvdmUsIHRoaXMgZnVuY3Rpb24gdXNlcyBzb21ldGhpbmcgY2FsbGVkIGEgImJvb3RzdHJhcCIgY2FsY3VsYXRlIGNvbmZpZGVuY2UgbGltaXRzIGZvciB0aGUgcG9wdWxhdGlvbiBtZWFuLiBMZXQncyBkaWcgaW50byBhIGJpdCBob3cgdGhpcyB3b3Jrcy4gDQoNClRoZSBib290c3RyYXAgaXMgYmFzZWQgb24gdGhlIGlkZWEgb2YgKipyYW5kb20gc2FtcGxpbmcgd2l0aCByZXBsYWNlbWVudCoqLiBMZXQncyBhc3N1bWUgd2UgdGFrZSBhIHJhbmRvbSBzYW1wbGUgZnJvbSBhIHBvcHVsYXRpb24gYW5kIGNhbGN1bGF0ZSB0aGUgc2FtcGxlIG1lYW4gJFxiYXJ7eH0kID0gJFxmcmFjezF9e259IFxzdW1fe2k9MX1ebiB4X2kkLCB3aGljaCByZXN1bHRlZCBpbiAkXGJhcnt4fT0zLjIkIG51bWJlciBvZiBzaGlwcGVkIHBpbGxzIChpbiBtaWxsaW9ucykuIEhvd2V2ZXIsIGEgZGlmZmVyZW50IHJhbmRvbSBzYW1wbGUgbWlnaHQgaGF2ZSB5aWVsZGVkICRcYmFye3h9PTMuMCQsIG9yICRcYmFye3h9PTMuNSQuIEl0IHdvdWxkIGJlIG5pY2UgdG8gDQpnZXQgYSBzZW5zZSBvZiB0aGUgYWNjdXJhY3kgb2YgdGhlIG9yaWdpbmFsIGVzdGltYXRlLiANCg0KVG8gZG8gdGhhdCwgd2UgbmVlZCB0byB1bmRlcnN0YW5kIGhvdyB0aGUgcHJvcG9ydGlvbnMgJFxiYXJ7eH0kIHZhcnkgc2FtcGxlIHRvIHNhbXBsZSwgb3IgZHVlIHRvIHJhbmRvbSBzYW1wbGluZy4gQnV0IGZpcnN0LCB3ZSBuZWVkIHRvIGRlZmluZSBhIF9zYW1wbGluZyBkaXN0cmlidXRpb25fLiANCg0KIyMjIFNhbXBsaW5nIGRpc3RyaWJ1dGlvbg0KDQpJZiB3ZSB0b29rIDUwIGRpZmZlcmVudCByYW5kb20gc2FtcGxlcyBvZiB0aGUgbnVtYmVyIG9mIHBpbGxzIHNoaXBwZWQgaW4gYSBnaXZlbiB5ZWFyIGZvciBhIGdpdmVuIGNvdW50eSwgd2UgY291bGQgc2VlIGEgZGlzdHJpYnV0aW9uIG9mIHRoZSAkXGJhcnt4fSQgZnJvbSB0aGUgcmVjb3JkZWQgbnVtYmVycyBmcm9tIHRoZSBkaWZmZXJlbnQgcmFuZG9tIHNhbXBsZXMgdGFrZW4gKCRcYmFye3h9XzEsIFxsZG90cywgXGJhcnt4fV97NTB9JCkuIA0KDQpUaGUgbW9zdCBpbXBvcnRhbnQgdGhpbmcgdG8gdW5kZXJzdGFuZCBhYm91dCBzYW1wbGluZyBkaXN0cmlidXRpb25zIGlzIGl0J3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIHRlc3Qgc3RhdGlzdGljIChlLmcuICRcYmFye3h9JCkgdGhhdCBzdW1tYXJpemVzIGEgZGF0YXNldCBhbmQgcmVwcmVzZW50cyBob3cgdGhlIHN0YXRpc3RpYyANCnZhcmllcyBhY3Jvc3MgbWFueSByYW5kb20gZGF0YXNldHMuIA0KDQoqKkEgaGlzdG9ncmFtIG9mIG9uZSBzZXQgb2Ygb2JzZXJ2YXRpb25zIGRyYXduIGZyb20gYSBwb3B1bGF0aW9uIGRvZXMgbm90IHJlcHJlc2VudCBhIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbioqLiANCg0KKipBIGhpc3RvZ3JhbSBvZiBwZXJtdXRhdGlvbiBtZWFucywgZWFjaCBmcm9tIG9uZSBzYW1wbGUsIGRvZXMgcmVwcmVzZW50IGEgc2FtcGxpbmcgZGlzdHJpYnV0aW9uKiouIA0KDQpXZSBjYWxsIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYSBzdGF0aXN0aWMgdGhlIF9zdGFuZGFyZCBlcnJvcl8uIA0KDQoNCiMjIyBUaGUgYm9vdHN0cmFwDQoNCkluIHRoZSBzY2VuYXJpbyB3aGVyZSB0aGUgdHJ1ZSBwb3B1bGF0aW9uIG1lYW4gaXMgdW5rbm93biwgYWxsIHdlIGhhdmUgYXJlIHRoZSBkYXRhIGFuZCBhIHN0YXRpc3RpYyBlc3RpbWF0ZWQgZnJvbSB0aGUgZGF0YS4gV2UgbmVlZCB0byBlc3RpbWF0ZSB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mICRcYmFye3h9JCB0byB1bmRlcnN0YW5kIGhvdyBtdWNoIHZhcmlhYmlsaXR5IG9yIHVuY2VydGFpbnR5IHRoZXJlIGlzLiANCg0KSGVyZSwgd2Ugd2lsbCB1c2Ugd2hhdCdzIGNhbGxlZCB0aGUgX2Jvb3RzdHJhcF8gdG8gY3JlYXRlIGEgbmV3IGRpc3RyaWJ1dGlvbiBjYWxsZWQgdGhlIF9ib290c3RyYXAgZGlzdHJpYnV0aW9uXywgd2hpY2ggYXBwcm94aW1hdGVzIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gZm9yIHRlc3Qgc3RhdGlzdGljcy4gDQoNCg0KIyMjIyBIb3cgZG9lcyB0aGUgYm9vdHN0cmFwIHdvcms/IA0KDQpUbyBmaW5kIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uIG9mIHNhbXBsZSBtZWFuLCB3ZSBkcmF3IHNhbXBsZXMgKGNhbGxlZCBfcmVzYW1wbGVzXyBvciBfYm9vdHN0cmFwIHNhbXBsZXNfKSBvZiBzaXplICRuJCwgd2l0aCByZXBsYWNlbWVudCwgZnJvbSB0aGUgb3JpZ2luYWwgc2FtcGxlIGFuZCB0aGVuIGNvbXB1dGUgdGhlIG1lYW4gb2YgZWFjaCByZXNhbXBsZS4gDQoNCkEgZmV3IHRoaW5ncyB0byBub3RlIGFib3V0IGJvb3RzdHJhcCBkaXN0cmlidXRpb25zOiANCg0KMS4gV2UgdHJlYXQgdGhlIG9yaWdpbmFsIHNhbXBsZSBhcyB0aGUgcG9wdWxhdGlvbi4gSWYgdGhlIG9yaWdpbmFsIHNhbXBsZSBpcyByZXByZXNlbnRhdGl2ZSBvZiB0aGUgcG9wdWxhdGlvbiwgdGhlbiB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdGVzdCBzdGF0aXN0aWNzIHdpbGwgbG9vayBhcHByb3hpbWF0ZWx5IGxpa2UgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdGVzdCBzdGF0aXN0aWMgKHNhbWUgc3ByZWFkIGFuZCBzaGFwZSkuIA0KDQoyLiBUaGUgYm9vdHN0cmFwIHN0YW5kYXJkIGVycm9yIGlzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gb2YgdGhhdCBzdGF0aXN0aWMuIA0KDQozLiBIb3dldmVyLCB0aGUgbWVhbiBvZiB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiB3aWxsIGJlIHRoZSBzYW1lIGFzIHRoZSBtZWFuIG9mIHRoZSBvcmlnaW5hbCBzYW1wbGUgKG5vdCBuZWNlc3NhcmlseSB0aGF0IG9mIHRoZSBvcmlnaW5hbCBwb3B1bGF0aW9uKS4gDQoNCg0KIyMjIyBTdGVwcyB0byBjb25zdHJ1Y3QgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24NCg0KMS4gU3RhcnQgd2l0aCBhIHNhbXBsZSBvZiBzaXplICRuJCBmcm9tIGEgcG9wdWxhdGlvbg0KMi4gRHJhdyBhIHJlc2FtcGxlIG9mIHNpemUgJG4kIHdpdGggcmVwbGFjZW1lbnQgZnJvbSB0aGUgc2FtcGxlDQozLiBDb21wdXRlIGEgc3RhdGlzdGljIHRoYXQgZGVzY3JpYmVzIHRoZSBzYW1wbGUsIHN1Y2ggYXMgdGhlIHNhbXBsZSBtZWFuDQo0LiBSZXBlYXQgdGhlIHJlc2FtcGxpbmcgcHJvY2VzcyBtYW55IHRpbWVzDQo1LiBDb25zdHJ1Y3QgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gb2YgdGhlIHN0YXRpc3RpYy4gSW5zcGVjdCB0aGUgc3ByZWFkLCBiaWFzIGFuZCBzaGFwZS4gDQoNCiMjIyMgQm9vdHN0cmFwIHBlcmNlbnRpbGUgY29uZmlkZW5jZSBpbnRlcnZhbHMNCg0KVGhlIGludGVydmFsIGJldHdlZW4gdGhlIDIuNSBhbmQgOTcuNSBwZXJjZW50aWxlcyBvZiB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiBvZiBhIHN0YXRpc3RpYyBpcyBhIDk1JSBfYm9vdHN0cmFwIHBlcmNlbnRpbGUgY29uZmlkZW5jZSBpbnRlcnZhbF8gZm9yIHRoZSBjb3JyZXNwb25kaW5nIHBhcmFtZXRlci4gIA0KDQoqKldlIGNhbiB0aGVuIHNheSB0aGF0IHdlIGFyZSA5NSUgY29uZmlkZW50IHRoYXQgdGhlIHRydWUgc3RhdGlzdGljIGxpZXMgd2l0aGluIHRoaXMgaW50ZXJ2YWwuKioNCg0KU2VlIFtoZXJlXShodHRwczovL2FjY2xhYi5naXRodWIuaW8vYm9vdHN0cmFwLWNvbmZpZGVuY2UtaW50ZXJ2YWxzLmh0bWwpIGZvciBtb3JlIGRldGFpbHMgYWJvdXQgaG93IHRoaXMgcHJvY2VzcyB3b3Jrcy4NCg0KIyMjIyBCYWNrIHRvIHRoZSBib290c3RyYXANCg0KV2UgY2FuIHVzZSB0aGUgYG1lYW5fY2xfYm9vdGAgZnVuY3Rpb24gaW4gb3VyIHBsb3Qgd2l0aCBgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ib290KWAgdG8gY2FsY3VsYXRlIHRoZSA5NSUgYm9vdHN0cmFwIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLg0KDQpXZSBjYW4gYWxzbyBhZGQgYSBwb3NpdGlvbiBhcmd1bWVudCBzbyB0aGF0IG91ciB0d28gZ3JvdXBzIGFyZSBub3Qgb3ZlcmxhcHBpbmcgYnkgY2hvb3NpbmcgdGhlIGBwb3NpdGlvbl9kb2dlYCBvcHRpb24gd2hpY2ggdGFrZXMgYW4gYXJndW1lbnQgb2YgYHdpZHRoYCB3aGljaCBzcGVjaWZpZXMgaG93IGZhciBhcGFydCB0aGUgdHdvIGdyb3VwcyBzaG91bGQgYmUgcGxvdHRlZC4gDQoNClRoZSBjb25maWRlbmNlIGludGVydmFscyBhcmUgdGhlbiBwbG90dGVkIGFzIGEgbGluZSB0aHJvdWdoIGEgcG9pbnQgd2hpY2ggc2hvd3MgdGhlIHJhbmdlIG9mIG90aGVyIHBvc3NpYmxlIHZhbHVlcyBmb3IgdGhlIG1lYW4gYmFzZWQgb24gdGhlIGJvb3RzdHJhcCBzYW1wbGVzLiANCg0KV2Ugd2lsbCBhbHNvIHVzZSB0aGUgYHN0YXRfc3VtbWFyeSgpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSBsaW5lIGJldHdlZW4gdGhlIHBvaW50cyBiYXNlZCBvbiB0aGUgbWVhbi4NCg0KYGBge3J9DQpyYXdfYXZlcmFnZSA8LSANCiAgQW5udWFsICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBQaWxsc19pbl9taWxsaW9ucykpICsgDQogICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ib290LA0KICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuNSkpICsNCiAgICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJsaW5lIikgKw0KICAgIGxhYnModGl0bGUgPSAiQXZlcmFnZSBOdW1iZXIgb2YgT3Bpb2lkIFBpbGxzIFNoaXBwZWQgdG8gYSBVUyBDb3VudHkiLA0KICAgICAgICAgeSA9ICJOdW1iZXIgb2YgcGlsbHMgaW4gbWlsbGlvbnMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpyYXdfYXZlcmFnZQ0KYGBgDQoNCkl0IGxvb2tzIGxpa2UgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIG9waW9pZCBwaWxscyBzaGlwcGVkIHRvIGEgY291bnR5IHBlYWtlZCBpbiAyMDExIGFuZCBoYXMgc2xvd2x5IGRlY2xpbmVkLiANCg0KV2UgY2FuIGxvb2sgYSBiaXQgZGVlcGVyIGlmIHdlIG9ubHkgY2FsY3VsYXRlIGEgbWVhbiBmb3IgZWFjaCBzdGF0ZS4gVG8gbWFrZSBhIHZpc3VhbCBvZiB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgZ2VvbV9ib3hqaXR0ZXIoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3BvbGAgcGFja2FnZS4NCg0KYGBge3J9DQpyYXdfc3RhdGVfYXZnIDwtIA0KICBBbm51YWwgJT4lIA0KICBncm91cF9ieShCVVlFUl9TVEFURSwgeWVhcikgJT4lDQogIHN1bW1hcml6ZSggbWVhbl9ET1NBR0UgPSBtZWFuKFBpbGxzX2luX21pbGxpb25zKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSAobWVhbl9ET1NBR0UpKSkgKyANCiAgICBnZ3BvbDo6Z2VvbV9ib3hqaXR0ZXIoKSArDQogICAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIG51bWJlciBvZiBvcGlvaWQgcGlsbHMgc2hpcHBlZCB0byBhIGdpdmVuIGNvdW50eSBmb3IgZWFjaCBzdGF0ZSIsDQogICAgICAgICB5ID0gIk51bWJlciBvZiBwaWxscyBpbiBtaWxsaW9ucyIpICsgDQogIHRoZW1lX21pbmltYWwoKQ0KDQpyYXdfc3RhdGVfYXZnDQpgYGANCg0KQWdhaW4gd2Ugc2VlIHRoZSBzYW1lIGdlbmVyYWwgb3ZlcmFsbCB0cmVuZCwgd2UgYWxzbyBzZWUgdGhhdCB0aGUgc3ByZWFkIHdhcyBxdWl0ZSBsYXJnZSB3aXRoIHNvbWUgc3RhdGVzIHJlY2VpdmluZyBtYW55IG1vcmUgcGlsbHMgdGhhbiBvdGhlcnMuIA0KDQoNCiMjICoqU3RhdGUgU2hpcG1lbnRzIG92ZXIgdGltZSoqDQoqKioNCg0KVG8gZ2V0IGEgYmV0dGVyIHNlbnNlIG9mIGhvdyBlYWNoIHN0YXRlIGNoYW5nZWQgb3ZlciB0aW1lIHdlIGNhbiBjcmVhdGUgYSBsaW5lIHBsb3QgaW5zdGVhZC4NCg0KYGBge3J9DQpBbm51YWwgJT4lIA0KICBncm91cF9ieShCVVlFUl9TVEFURSwgeWVhcikgJT4lDQogIHN1bW1hcml6ZShtZWFuX0RPU0FHRSA9IG1lYW4oUGlsbHNfaW5fbWlsbGlvbnMpKSAlPiUNCiAgdW5ncm91cCgpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IG1lYW5fRE9TQUdFLCBncm91cCA9IEJVWUVSX1NUQVRFLCANCiAgICAgICAgICAgICBjb2xvciA9IEJVWUVSX1NUQVRFKSkgKyANCiAgICBnZW9tX2xpbmUoKSArDQogICAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIG51bWJlciBvZiBvcGlvaWQgcGlsbHMgc2hpcHBlZCB0byBhIGdpdmVuIGNvdW50eSBmb3IgZWFjaCBzdGF0ZSIsDQogICAgICAgICB5ID0gIk51bWJlciBvZiBwaWxscyBpbiBtaWxsaW9ucyIpKw0KICAgIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNClNpbmNlIHdlIGhhdmUgc28gbWFueSBzdGF0ZXMsIHRoZSBsZWdlbmQgaXMgbm90IHZlcnkgdXNlZnVsLiBJbnN0ZWFkIHdlIGNhbiB1c2UgdGhlIGBnaXJhZmVgIHBhY2thZ2UgdG8gY3JlYXRlIGFuICoqaW50ZXJhY3RpdmUgcGxvdCoqIHRoYXQgd2lsbCB0ZWxsIHBlb3BsZSB3aGF0IHN0YXRlIGVhY2ggbGluZSByZXByZXNlbnRzIHdoZW4gdGhleSBob3ZlciBvdmVyIGRpZmZlcmVudCBkYXRhIHBvaW50cy4NCg0KYGBge3J9DQpnIDwtIA0KICBBbm51YWwgJT4lIA0KICBncm91cF9ieShCVVlFUl9TVEFURSwgeWVhcikgJT4lDQogIHN1bW1hcml6ZShtZWFuX0RPU0FHRSA9IG1lYW4oUGlsbHNfaW5fbWlsbGlvbnMpKSAlPiUNCiAgdW5ncm91cCgpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IG1lYW5fRE9TQUdFLCBncm91cCA9IEJVWUVSX1NUQVRFLCANCiAgICAgICAgICAgICBjb2xvciA9IEJVWUVSX1NUQVRFKSkgKw0KICAgIGdlb21fbGluZSgpICsNCiAgICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgbnVtYmVyIG9mIG9waW9pZCBwaWxscyBzaGlwcGVkIHRvIGEgZ2l2ZW4gY291bnR5IGZvciBlYWNoIHN0YXRlIiwNCiAgICAgICAgIHkgPSAiTnVtYmVyIG9mIHBpbGxzIGluIG1pbGxpb25zIikgKw0KICAgIHRoZW1lX21pbmltYWwoKQ0KDQoNCmcgPC0gDQogIGcgKyBnZW9tX3BvaW50X2ludGVyYWN0aXZlKGFlcyhjb2xvciA9IEJVWUVSX1NUQVRFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2x0aXAgPSB1c2RhdGE6OmFiYnIyc3RhdGUoQlVZRVJfU1RBVEUpKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAyLCBhbHBoYSA9IDMvMTApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KIA0KZ2lyYWZlKGNvZGUgPSBwcmludChnKSkNCmBgYA0KDQpJbiB0aGlzIHBsb3QsIGl0IGFwcGVhcnMgdGhhdCB0aGUgbGFyZ2VzdCBudW1iZXIgb2YgcGlsbHMgd2VyZSBzaGlwcGVkIHRvIGNvdW50aWVzIGluIENhbGlmb3JuaWEuIEhvd2V2ZXIsIHNpbmNlIHdlIGRpZCBub3QgYWNjb3VudCBmb3IgcG9wdWxhdGlvbiBvciBwb3B1bGF0aW9uIGRlbnNpdHksIHRoaXMgY291bGQgc2ltcGx5IGJlIGJlY2F1c2UgaXQgaXMgdGhlIG1vc3QgcG9wdWxhdGVkIHN0YXRlLiANCg0KVG8gYWNjb3VudCBmb3IgdGhpcyB3ZSB3aWxsIHBlcmZvcm0gc29tZXRoaW5nIGNhbGxlZCAqKm5vcm1hbGl6YXRpb24qKiAob3IgaW4gdGhpcyBjYXNlIHdlIHdpbGwgYWRqdXN0IGZvciBkaWZmZXJlbmNlcyBpbiBwb3B1bGF0aW9uIG9yIHBvcHVsYXRpb24gZGVuc2l0eSBhY3Jvc3MgZGlmZmVyZW50IHN0YXRlcykgdG8gbWFrZSBhIG1vcmUgZmFpciBjb21wYXJpc29uLg0KDQojIyAqKk5vcm1hbGl6YXRpb24gb2YgbnVtYmVyIG9mIHNoaXBwZWQgcGlsbHMqKg0KKioqDQoNClRoZSB0ZXJtIGRhdGEgW25vcm1hbGl6YXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL05vcm1hbGl6YXRpb25fKHN0YXRpc3RpY3MpKSBhY3R1YWxseSBoYXMgYSB2YXJpZXR5IG9mIG1lYW5pbmdzLiANCg0KSW4gc29tZSBjYXNlcywgaXQgaW5kaWNhdGVzIHRoZSBwcm9jZXNzIG9mIG1ha2luZyBkYXRhICJtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIiwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgZGF0YSBpcyB0cmFuc2Zvcm1lZCBpbiBhIHN1Y2ggd2F5IHRoYXQgd2hlbiB0aGUgZnJlcXVlbmNpZXMgb2YgdGhlIHZhcmlvdXMgZGF0YSBwb2ludHMgYXJlIHBsb3R0ZWQsIGl0IHJlc2VtYmxlcyB0aGF0IG9mIHRoZSBbbm9ybWFsIGRpc3RyaWJ1dGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTm9ybWFsX2Rpc3RyaWJ1dGlvbiksIHdoaWNoIGxvb2tzIGxpa2UgYSAiYmVsbCBjdXJ2ZSIuIFRoaXMgbWF5IGJlIGhlbHBmdWwgZm9yIHBlcmZvcm1pbmcgY2VydGFpbiBzdGF0aXN0aWNhbCB0ZXN0cyB0aGF0IGFzc3VtZSB0aGF0IHRoZSBkYXRhIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLg0KDQpJbiBvdGhlciBjYXNlcywgaXQgbWF5IG1lYW4gdGhlIHByb2Nlc3Mgb2YgdHJhbnNmb3JtaW5nIHRoZSBkYXRhIHRvIGEgY29tbW9uIHNjYWxlIHNvIHRoYXQgY29tcGFyaXNvbnMgY2FuIGJlIG1hZGUgZmFpcmx5LiANCg0KSW4gb3VyIGNhc2UsIHdlIHdhbnQgdG8gY29tcGFyZSB0aGUgbnVtYmVyIG9mIHBpbGxzIHNoaXBwZWQgdG8gZWFjaCBjb3VudHkuIEhvd2V2ZXIsIHVzaW5nIHRoZSByYXcgZGF0YSByZXN1bHRzIGluIGFuIHVuZmFpciBjb21wYXJpc29uIGFzIHRoZSBjb3VudGllcyB0aGVtc2VsdmVzIGhhdmUgdmVyeSBkaWZmZXJlbnQgcG9wdWxhdGlvbnMuIFRoZXJlZm9yZSwgaWYgYSBjb3VudHkgaGFzIGEgdmVyeSBsYXJnZSBwb3B1bGF0aW9uLCB3ZSBtYXkgYXNzdW1lIHRoYXQgdGhlIGxhcmdlIG51bWJlciBvZiBwaWxscyBzaGlwcGVkIHRvIHRoYXQgY291bnR5IG1heSBpbmRpY2F0ZSB0aGF0IHRoaXMgY291bnR5IHJlY2VpdmVkIGEgcGFydGljdWxhcmx5IGhpZ2ggYW1vdW50IG9mIG9waW9pZHMsIGhvd2V2ZXIsIGl0IG1heSBhY3R1YWxseSBiZSB0aGF0IHRoaXMgY291bnR5IHJlY2VpdmVkIGZhciBmZXdlciBwaWxscyBwZXIgcGVyc29uIHRoYW4gYSBzbWFsbGVyIGNvdW50eS4NCg0KSWYgd2UgZGl2aWRlIChvciBzY2FsZSkgdGhlIG51bWJlciBvZiBwaWxscyBzaGlwcGVkIHRvIGJlIHJlbGF0aXZlIHRvIHRoZSBudW1iZXIgb2YgcGVvcGxlIGluIGEgZ2l2ZW4gY291bnR5LCB0aGVuIHdlIGhhdmUgdGhlIG51bWJlciBvZiBwaWxscyBzaGlwcGVkIHBlciBwZXJzb24uIFRoZXJlZm9yZSwgdGhlIGRhdGEgd2lsbCBiZSBvbiBhIHNpbWlsYXIgc2NhbGUgZm9yIGVhY2ggY291bnR5LiANCg0KVGhpcyBjYW4gYmUgZXh0ZW5kZWQgdG8gZXZhbHVhdGluZyBkaWZmZXJlbmNlcyBiZXR3ZWVuIHN0YXRlcyBhbmQgcnVyYWwgb3IgdXJiYW4gY291bnRpZXMgYnkgdGFraW5nIHRoZSBtZWFuIG9mIHRoZSBub3JtYWxpemVkIHBpbGwgY291bnRzIHBlciBwZXJzb24gZm9yIGVhY2ggY291bnR5IHdpdGhpbiBlYWNoIGdyb3VwLg0KDQpTZWUgW2hlcmVdKGh0dHA6Ly93d3cucGJjZ2lzLmNvbS9ub3JtYWxpemUvIzp+OnRleHQ9VG8lMjBub3JtYWxpemUlMkMlMjBpbiUyMGElMjBzdGF0aXN0aWNhbCxvdmVyJTIwdW5lcXVhbCUyMGFyZWFzJTIwb3IlMjBwb3B1bGF0aW9ucy4pIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGhvdyB0aGlzIHR5cGUgb2Ygbm9ybWFsaXphdGlvbiBpcyB1c2VkIGluIFtHZW9ncmFwaGljIGluZm9ybWF0aW9uIHN5c3RlbSAoR0lTKV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvR2VvZ3JhcGhpY19pbmZvcm1hdGlvbl9zeXN0ZW0pIGFuYWx5c2VzLg0KDQpUaGlzIG1heSBiZSBiZXN0IGlsbHVzdHJhdGVkIHdpdGggc29tZSBleGFtcGxlIGRhdGEuIA0KDQpIZXJlLCB3ZSBjcmVhdGUgYSB0aWJibGUgZm9yIHRocmVlIGltYWdpbmFyeSBjb3VudGllcy4gRWFjaCBoYXMgYSBkaWZmZXJlbnQgcG9wdWxhdGlvbiBidXQgcmVjZWl2ZWQgdGhlIHNhbWUgbnVtYmVyIG9mIHBpbGxzLiANCg0KTmV4dCwgd2UgY2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgcGlsbHMgcGVyIHBlcnNvbiBieSBkaXZpZGluZyB0aGUgbnVtYmVyIG9mIHBpbGxzIHNoaXBwZWQgdG8gdGhhdCBjb3VudHkgYnkgdGhlIHBvcHVsYXRpb24gb2YgdGhhdCBjb3VudHkuDQoNCmBgYHtyfQ0KZXhhbXBsZV9kYXRhIDwtIA0KICB0aWJibGUocG9wdWxhdGlvbiA9IGMoMTAsIDUwLCAxMDApLA0KICAgICAgICAgcGlsbHMgPSBjKDEwMCwgMTAwLCAxMDApKQ0KDQpleGFtcGxlX2RhdGEgJTw+JSANCiAgbXV0YXRlKG5vcm1fcGlsbHMgPSBwaWxscy9wb3B1bGF0aW9uKQ0KDQpleGFtcGxlX2RhdGENCmBgYA0KDQpZb3UgY2FuIHNlZSB0aGF0IG9uIGF2ZXJhZ2UgMTAgcGlsbHMgd2VyZSBzaGlwcGVkIGZvciBlYWNoIHBlcnNvbiBmb3IgdGhlIGZpcnN0IGNvdW50eS4NCg0KSW4gdGhlIHNlY29uZCByb3csIHRoZSBwb3B1bGF0aW9uIGlzIG11Y2ggbGFyZ2VyLiBEZXNwaXRlIHRoZSBzYW1lIG51bWJlciBvZiBwaWxscyBiZWluZyBzaGlwcGVkIHRvIHRoaXMgZXhhbXBsZSBjb3VudHksIHRoZXJlIHdlcmUgb25seSBlbm91Z2ggcGlsbHMgc2hpcHBlZCBmb3Igb24gYXZlcmFnZSAyIHBlciBwZXJzb24uIEluIHRoZSBmaW5hbCByb3csIHRoZSBwb3B1bGF0aW9uIGlzIHZlcnkgbGFyZ2UuIE9ubHkgZW5vdWdoIHBpbGxzIHdlcmUgc2hpcHBlZCB0byBnaXZlIG9uIGF2ZXJhZ2UgMSBwZXIgcGVyc29uLg0KDQpOb3RlIHRoYXQgaG93ZXZlciwgaXQgaXMgbGlrZWx5IHRoYXQgb25seSBhIHNtYWxsIHBvcnRpb24gb2YgdGhlIGNvdW50eSBwb3B1bGF0aW9ucyBhY3R1YWxseSByZWNlaXZlZCB0aGUgcGlsbHMgdGhhdCB3ZXJlIHNoaXBwZWQgdG8gYSBnaXZlbiBjb3VudHksIGJ1dCB0aGlzIGhlbHBzIHVzIGdldCBhIHNlbnNlIG9mIHRoZSByZWxhdGl2ZSBhbW91bnQgc2hpcHBlZCB0byBlYWNoIGNvdW50eSBhbmQgbGlrZWx5IHVzZWQgYnkgcGVvcGxlIGluIHRoZSBjb3VudHkgd2hlcmUgdGhlIHBpbGxzIHdlcmUgc2hpcHBlZCAoYWx0aG91Z2ggdGhpcyBhbHNvIG5vdCBjZXJ0YWluKS4NCg0KQmFjayB0byBvdXIgZXhhbXBsZTogd2UgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBgcG9wX0RPU0FHRWAgdGhhdCBpcyB0aGUgbnVtYmVyIG9mIHBpbGxzIHNoaXBwZWQgcGVyIGNvdW50eSBkaXZpZGVkIGJ5IHRoZSBwb3B1bGF0aW9uIG9mIHRoYXQgY291bnR5Og0KDQpgYGB7cn0NCkFubnVhbCAlPD4lDQogIG11dGF0ZShwb3BfRE9TQUdFID0gIERPU0FHRV9VTklUIC8gcG9wdWxhdGlvbikNCg0KZ2xpbXBzZShBbm51YWwpDQpgYGANCg0KV2UgY3JlYXRlIGEgcGxvdCBvZiB0aGUgbmF0aW9uYWwgY291bnR5IGF2ZXJhZ2UgZm9yIHRoaXMgbm9ybWFsaXplZCBwaWxsIGNvdW50IG92ZXIgdGltZS4NCg0KYGBge3J9DQpub3JtX2F2ZXJhZ2UgPC0gDQogIEFubnVhbCAlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gcG9wX0RPU0FHRSkpICsgDQogICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ib290LA0KICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuNSkpICsNCiAgICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwNCiAgICAgICAgICAgICAgICAgZ2VvbSA9ICJsaW5lIikgKw0KICAgIGxhYnModGl0bGUgPSAiQXZlcmFnZSBOdW1iZXIgb2YgcGlsbHMgc2hpcHBlZCBwZXIgcGVyc29uIGZvciBhIGdpdmVuIGNvdW50eSIsDQogICAgICAgICB5ID0gIk51bWJlciBvZiBwaWxscyBwZXIgY2FwaXRhIikgKw0KICAgIHRoZW1lX21pbmltYWwoKQ0KDQpub3JtX2F2ZXJhZ2UNCmBgYA0KDQpMZXQncyBtYWtlIGEgcGxvdCBjb21wYXJpbmcgdGhpcyBwbG90IHdpdGggdGhlIGRhdGEgb24gdGhlIHJhdyBzY2FsZSB1c2luZyB0aGUgYHBhdGNod29ya2AgcGFja2FnZSwgdXNpbmcgYSBgK2AgdG8gY29tYmluZSBwbG90cyB0b2dldGhlci4NCg0KV2UgY29udGludWUgdG8gdXNlIHRoZSBgdGhlbWUoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIHRvIHJlbW92ZSB0aGUgcHJldmlvdXMgdGl0bGVzIGFuZCB0aGVuIHVzZSB0aGUgYHBsb3RfYW5ub3RhdGlvbigpYCBmdW5jdGlvbiBvZiB0aGUgYHBhdGNod29ya2AgcGFja2FnZSB0byBhZGQgYW4gb3ZlcmFsbCB0aXRsZSB1c2luZyB0aGUgYHRpdGxlYCBhcmd1bWVudC4gVGhpcyBmdW5jdGlvbiBjYW4gYWxzbyBiZSB1c2VkIHdpdGggdGhlIGB0aGVtZWAgYXJndW1lbnQgYW5kIHRoZW4gdXNpbmcgdGhlIGBnZ3Bsb3QyYCBgdGhlbWUoKWAgZnVuY3Rpb24gYXMgdXN1YWwuIFRoaXMgd2lsbCBhcHBseSBjaGFuZ2VzIHRvIGFsbCBwbG90cyB0aGF0IGFyZSBjb21iaW5lZCBidXQgb25seSByZWdhcmRpbmcgdG8gdGhlIHRpdGxlcyBwbG90IG1hcmdpbiBhbmQgYmFja2dyb3VuZC4NCg0KYGBge3J9DQpyYXdfYXZlcmFnZSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsNCm5vcm1fYXZlcmFnZSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKw0KICBwYXRjaHdvcms6OnBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJSYXcgdnMgTm9ybWFsaXplZCBEYXRhIikNCmBgYA0KDQpXZSBjYW4gc2VlIHRoYXQgdGhlIHZhcmlhYmlsaXR5IG9mIHRoZSBzYW1wbGUgbWVhbiBpcyBtdWNoIGxvd2VyIGZvciB0aGUgbm9ybWFsaXplZCBkYXRhIChob3dldmVyIHRoaXMgaXMgaW4gcGFydCBiZWNhdXNlIHRoZSBzY2FsZSBpcyBkaWZmZXJlbnQpLCBidXQgd2Ugc2VlIHRoZSBzYW1lIGdlbmVyYWwgdHJlbmQgZnJvbSBvbmUgeWVhciB0byB0aGUgbmV4dC4gDQoNClRoaXMgaXMgbm93IGFsc28gYSBiaXQgZWFzaWVyIHRvIGludGVycHJldC4gSXQgaXMgZWFzaWVyIHRvIHRoaW5rIGFib3V0IDMwIHZzIDUwIHBpbGxzIHBlciBwZXJzb24gYXMgb3Bwb3NlZCB0byAxMCBtaWxsaW9uIHBpbGxzIHZzIDIwIG1pbGxpb24gcGlsbHMgZm9yIGEgZ2l2ZW4gY291bnR5Lg0KDQpBZ2FpbiBsZXQncyB0YWtlIGEgZGVlcGVyIGxvb2sgYXQgdGhlIHN0YXRlcyBhbmQgY3JlYXRlIGEgY29tYmluZWQgYm94IHBsb3QgYW5kIGppdHRlciBwbG90IGZpZ3VyZS4NCg0KIyMjIyB7LnJlY2FsbF9jb2RlX3F1ZXN0aW9uX2Jsb2NrfQ0KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+DQoNCkRvIHlvdSByZWNhbGwgaG93IHRvIGRvIHRoaXM/IEhvdyB3b3VsZCB5b3UgY29tYmluZSB0aGUgcHJldmlvdXMgcGxvdCBvZiB0aGUgcmF3IGRhdGEgd2l0aCB0aGlzIHBsb3Q/DQoNCiMjIyMNCg0KKioqDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCg0KDQpgYGB7cn0NCm5vcm1fc3RhdGVfYXZnIDwtDQogIEFubnVhbCAlPiUgDQogIGdyb3VwX2J5KEJVWUVSX1NUQVRFLCB5ZWFyKSAlPiUNCiAgc3VtbWFyaXplKG1lYW5fRE9TQUdFID0gbWVhbihwb3BfRE9TQUdFKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSAobWVhbl9ET1NBR0UpKSkgKyANCiAgICBnZW9tX2JveGppdHRlcigpICsgDQogICAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIG51bWJlciBvZiBvcGlvaWQgcGlsbHMgc2hpcHBlZCB0byBhIGdpdmVuIGNvdW50eSBmb3IgZWFjaCBzdGF0ZSIsDQogICAgICAgICB5ID0gIk51bWJlciBvZiBQaWxscyBQZXIgQ2FwaXRhIikrDQogICAgdGhlbWVfbWluaW1hbCgpDQoNCm5vcm1fc3RhdGVfYXZnIA0KDQp0b2dldGhlciA8LSANCiAgcmF3X3N0YXRlX2F2ZyArIA0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKw0KICBub3JtX3N0YXRlX2F2ZyArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsNCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIlJhdyB2cyBOb3JtYWxpemVkIERhdGEiKQ0KYGBgDQoNCjwvZGV0YWlscz4NCg0KKioqIA0KDQpgYGB7cn0NCnRvZ2V0aGVyDQpgYGANCg0KV2Ugc2VlIGEgc2ltaWxhciBzcHJlYWQgYW5kIHRoZSBzYW1lIGdlbmVyYWwgdHJlbmQgYWx0aG91Z2ggdGhlIGRpZmZlcmVuY2UgZnJvbSBvbmUgeWVhciB0byB0aGUgbmV4dCBhcHBlYXJzIHRvIGJlIHN0ZWVwZXIgZm9yIHRoZSBub3JtYWxpemVkIGRhdGEuDQoNCk5vdywgbGV0J3Mgc2VlIGhvdyBub3JtYWxpemF0aW9uIGNoYW5nZXMgdGhlIHN0YXRlIHNwZWNpZmljIGRhdGEuDQoNCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpEbyB5b3UgcmVjYWxsIGhvdyB0byBjcmVhdGUgdGhlIHN0YXRlIHNwZWNpZmljIGFuZCBpbnRlcmFjdGl2ZSBwbG90Pw0KDQojIyMjDQoNCioqKg0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQoNCg0KYGBge3J9DQpnMiA8LSANCiAgQW5udWFsICU+JSANCiAgZ3JvdXBfYnkoQlVZRVJfU1RBVEUseWVhcikgJT4lDQogIHN1bW1hcml6ZShtZWFuX0RPU0FHRSA9IG1lYW4ocG9wX0RPU0FHRSkpICU+JSANCiAgdW5ncm91cCgpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbWVhbl9ET1NBR0UsIGdyb3VwID0gQlVZRVJfU1RBVEUsDQogICAgICAgICAgICAgY29sb3IgPSBCVVlFUl9TVEFURSkpICsNCiAgICBnZW9tX2xpbmUoKQ0KDQpnMiA8LSANCiAgZzIgKyBnZW9tX3BvaW50X2ludGVyYWN0aXZlKGFlcyhjb2xvciA9IEJVWUVSX1NUQVRFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sdGlwID0gdXNkYXRhOjphYmJyMnN0YXRlKEJVWUVSX1NUQVRFKSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIsIGFscGhhID0gMy8xMCkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQogDQo8L2RldGFpbHM+IA0KDQoqKiogDQoNCmBgYHtyfQ0KZ2lyYWZlKGNvZGUgPSBwcmludChnMikpDQpgYGANCg0KVGhpcyBkcmFtYXRpY2FsbHkgY2hhbmdlZCB0aGUgcmVzdWx0aW5nIHBsb3QhDQoNCldlIGNhbiBzZWUgdGhhdCBub3cgVGVubmVzc2VlLCBLZW50dWNreSwgYW5kIFdlc3QgVmlyZ2luaWEgd2VyZSBhbW9uZyB0aGUgdG9wIHRvIHJlY2VpdmUgcGlsbHMgcmVsYXRpdmUgdG8gdGhlaXIgcG9wdWxhdGlvbnMuIENhbGlmb3JuaWEgaXMgbm8gbG9uZ2VyIGF0IHRoZSB0b3Agb2YgdGhlIHBsb3QuDQoNCg0KIyMgKipSdXJhbCBhbmQgVXJiYW4gRGlmZmVyZW5jZXMqKg0KKioqDQoNCk9LLCBub3cgdGhhdCB3ZSBjYW4gbWFrZSBmYWlyIGNvbXBhcmlzb25zIGJldHdlZW4gY291bnRpZXMsIHdlIGNhbiBub3cgdGFrZSBhIGxvb2sgYXQgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gcnVyYWwgYW5kIHVyYmFuIGNvdW50aWVzLg0KDQpUbyBtYWtlIHRoaXMgcGxvdCB3ZSB3aWxsIGFnYWluIHVzZSB0aGUgYHN0YXRfc3VtbWFyeSgpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuIA0KDQpXZSB3YW50IHRvIGluY2x1ZGUgYm90aCB0aGUgcmF3IGRhdGEgYW5kIHRoZSBub3JtYWxpemVkIGRhdGEgaW4gdGhlIHNhbWUgcGxvdC4gDQoNClJlY2FsbCB0aGF0IHdlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBgZmFjZXRfd3JhcCgpYCBmdW5jdGlvbi4gDQoNCioqKg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBob3cgdGhpcyBjYW4gYmUgZG9uZSB1c2luZyBgZmFjZXRfd3JhcCgpYCA8L3N1bW1hcnk+DQoNCkluIHRoaXMgb3B0aW9uIHdlIHVzZSB0aGUgYGxhYmVsbGVyYCBhcmd1bWVudCBvZiB0aGUgYGZhY2V0X3dyYXAoKWAgZnVuY3Rpb24gdG8gY2hhbmdlIHdoYXQgdGhlIGBzdHJpcC50ZXh0YCBsYWJlbHMgd2lsbCBiZSAod2hpY2ggaXMgdGhlIHRleHQgYWJvdmUgZWFjaCBwbG90IC0gdGhlIGxvY2F0aW9uIG9mIHdoaWNoIGNhbiBiZSBjaGFuZ2VkKS4NCg0KYGBge3J9DQpBbm51YWwgJT4lIA0KICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAidHlwZSIsIA0KICAgICAgICAgICAgICAgdmFsdWVzX3RvICA9ICJ2YWx1ZSIsIA0KICAgICAgICAgICAgICAgY29scyA9IGMoUGlsbHNfaW5fbWlsbGlvbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgcG9wX0RPU0FHRSkpJT4lDQogIG11dGF0ZSh0eXBlID0gZm9yY2F0czo6ZmN0X2lub3JkZXIodHlwZSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSB2YWx1ZSwgeCA9IHllYXIsIGNvbG91ciA9IHJ1cmFsX3VyYmFuLCANCiAgICAgICAgICAgICBncm91cCA9IHJ1cmFsX3VyYmFuKSkgKyANCiAgICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX2Jvb3QsDQogICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLA0KICAgICAgICAgICAgICAgICBnZW9tID0gInBvaW50cmFuZ2UiKSArDQogICAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIpICsNCiAgICBmYWNldF93cmFwKCB+IHR5cGUsIHNjYWxlcyA9ICJmcmVlIiwgbGFiZWxsZXIgPSANCiAgICAgICAgICAgICAgICAgIGFzX2xhYmVsbGVyKGMoUGlsbHNfaW5fbWlsbGlvbnMgPSAiUmF3IERhdGEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wX0RPU0FHRSA9ICJOb3JtYWxpemVkIERhdGEgKHBpbGxzIHBlciBjYXBpdGEpIikpKSArDQogICAgbGFicyh0aXRsZSA9ICJEaWZmZXJlbmNlIGluIE9waW9pZCBTaGlwbWVudHMgV2l0aCBhbmQgV2l0aG91dCBOb3JtYWxpemF0aW9uIiwNCiAgICAgICAgIHkgPSAiTnVtYmVyIG9mIFBpbGxzIiwgeCA9IE5VTEwpKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsNCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzIwQTM4N0ZGIiwgIiM0ODE1NjdGRiIpKQ0KYGBgDQoNCjwvZGV0YWlscz4gDQoqKioNCg0KT3IsIGluc3RlYWQgd2UgY2FuIGNvbnRpbnVlIHRvIHVzZSBgcGF0Y2h3b3JrYCB0byBjb21iaW5lIHR3byBkaWZmZXJlbnQgcGxvdHMuIEJvdGggb3B0aW9ucyBhbGxvdyBmb3IgYSBtb3JlIGZsZXhpYmlsaXR5IGFib3V0IHNwZWNpZnlpbmcgZGlmZmVyZW50IGFzcGVjdHMgb2YgdGhlIHBsb3QuIA0KDQpJbiBib3RoIGNhc2VzLCB3ZSB1c2UgYSBtYW51YWwgY29sb3Igc2NoZW1lIHRvIGNvbG9yIHRoZSB0d28gZ3JvdXBzIHVzaW5nIHRoZSBgc2NhbGVfY29sb3JfbWFudWFsKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4gVGhpcyBmdW5jdGlvbiB0YWtlcyBhIGB2YWx1ZXNgIGFyZ3VtZW50IHRoYXQgbXVzdCBiZSBhIGxpc3Qgb2YgY29sb3JzIHRoYXQgaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiBncm91cHMgdG8gYmUgY29sb3JlZC4gQWxzbyB0aGUgYGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSlgIG9mIHRoZSBgdGhlbWUoKWAgZnVuY3Rpb24sIGFsbG93cyBmb3IgdGhlIHRpdGxlcyB0byBiZSBjZW50ZXJlZC4NCg0KYGBge3IsIGZpZy53aWR0aD0xMH0NClJhd19EYXRhIDwtIA0KICBBbm51YWwgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBQaWxsc19pbl9taWxsaW9ucywgeCA9IHllYXIsIGNvbG91ciA9IHJ1cmFsX3VyYmFuLCANCiAgICAgICAgICAgICBncm91cCA9IHJ1cmFsX3VyYmFuKSkgKyANCiAgICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX2Jvb3QsDQogICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLA0KICAgICAgICAgICAgICAgICBnZW9tID0gInBvaW50cmFuZ2UiKSArDQogICAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIpICsNCiAgICBsYWJzKHRpdGxlID0gIlJhdyBEYXRhIiwNCiAgICAgICAgIHkgPSAiTnVtYmVyIG9mIFBpbGxzIGluIG1pbGxpb25zIiwNCiAgICAgICAgIHggPSBOVUxMKSArDQogICAgdGhlbWVfbGluZWRyYXcoKSArDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiMyMEEzODdGRiIsICIjNDgxNTY3RkYiKSkNCg0KDQpOb3JtX0RhdGEgPC0gDQogIEFubnVhbCAlPiUNCiAgZ2dwbG90KCBhZXMoeSA9IHBvcF9ET1NBR0UsIHggPSB5ZWFyLCBjb2xvdXIgPSBydXJhbF91cmJhbiwgDQogICAgICAgICAgICAgIGdyb3VwID0gcnVyYWxfdXJiYW4pKSArIA0KICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfYm9vdCwNCiAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksDQogICAgICAgICAgICAgICAgIGdlb20gPSAicG9pbnRyYW5nZSIpICsNCiAgICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJsaW5lIikgKw0KICAgIGxhYnModGl0bGUgPSAiTm9ybWFsaXplZCBEYXRhIiwNCiAgICAgICAgIHkgPSAiTnVtYmVyIG9mIFBpbGxzIFBlciBDYXBpdGEiLA0KICAgICAgICAgeCA9IE5VTEwpICsNCiAgICB0aGVtZV9saW5lZHJhdygpICsNCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzIwQTM4N0ZGIiwgIiM0ODE1NjdGRiIpKQ0KDQpSYXdfRGF0YSArIA0KICBOb3JtX0RhdGEgKyANCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkRpZmZlcmVuY2UgaW4gT3Bpb2lkIFNoaXBtZW50cyBhY3Jvc3MgZGlmZmVyZW50IHR5cGVzIG9mIGNvdW50aWVzIikNCmBgYA0KDQoNCldlIGNhbiBzZWUgdGhhdCB3aXRob3V0IGFjY291bnRpbmcgZm9yIHBvcHVsYXRpb24sIHRoZSB1cmJhbiBjb3VudGllcyByZWNlaXZlZCBtYW55IG1vcmUgcGlsbHMgdGhhbiB0aGUgcnVyYWwgY291bnRpZXMuIEluIGNvbnRyYXN0LCB3aGVuIHBvcHVsYXRpb24gaXMgdGFrZW4gaW50byBhY2NvdW50LCB0aGUgcmF0ZXMgYXBwZWFyIHRvIGJlIHZlcnkgc2ltaWxhci4NCg0KV2UgY2FuIGFsc28gc2VlIHRoYXQgdGhlcmUgYXBwZWFycyB0byBiZSBtdWNoIGhpZ2hlciAqKnZhcmlhYmlsaXR5KiogYW1vbmcgdGhlICoqdXJiYW4qKiBjb3VudGllcyBhcyBjb21wYXJlZCB0byB0aGUgcnVyYWwgY291bnRpZXMuIA0KDQpMZXQncyBzYXZlIG91ciBgdGhlbWUoKWAgZnVuY3Rpb24gY29kZSBhcyBhbiBhY3R1YWwgdGhlbWUgdG8gYmUgdXNlZCBmb3Igb3VyIGZ1dHVyZSBwbG90cyBzbyB0aGF0IHRoZXkgY2FuIGJlIHN0eWxpemVkIHNpbWlsYXJseS4NCg0KYGBge3J9DQp0aGVtZV9jb3VudHkgPC0gZnVuY3Rpb24oKSB7DQogIHRoZW1lX2xpbmVkcmF3KCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCn0NCmBgYA0KTm93IHdlIHNpbXBseSBuZWVkIHRvIHR5cGUgYGNvdW50eV90aGVtZSgpYCBpbnN0ZWFkIHRvIGFjaGlldmUgdGhlIHNhbWUgc3R5bGUgZm9yIG91ciBwbG90Lg0KDQojIyAqKkdyZWF0ZXIgZ3JhbnVsYXJpdHkgb2YgZGVuc2l0eSoqDQoqKioNCg0KUmVjYWxsIHRoYXQgdGhlIFthcnRpY2xlXShodHRwczovL2phbWFuZXR3b3JrLmNvbS9qb3VybmFscy9qYW1hcHN5Y2hpYXRyeS9mdWxsYXJ0aWNsZS8xODc0NTc1KSB0aGF0IHN1cnZleWVkIHBlb3BsZSB3aG8gdXNlIGhlcm9pbiBpbiB0aGUgW1N1cnZleSBvZiBLZXkgSW5mb3JtYW50c+KAmSBQYXRpZW50cyBQcm9ncmFtXShodHRwczovL3d3dy5yYWRhcnMub3JnL3JhZGFycy1zeXN0ZW0tcHJvZ3JhbXMvc3VydmV5LW9mLWtleS1pbmZvcm1hbnRzLXBhdGllbnRzLmh0bWwpIGFuZCB0aGUgW1Jlc2VhcmNoZXJzIGFuZCBQYXJ0aWNpcGFudHMgSW50ZXJhY3RpbmcgRGlyZWN0bHkgKFJBUElEKSBwcm9ncmFtXShodHRwczovL3d3dy5yYWRhcnMub3JnL3JhZGFycy1zeXN0ZW0tcHJvZ3JhbXMvcmVzZWFyY2hlcnMtYW5kLXBhcnRpY2lwYW50cy1pbnRlcmFjdGluZy1kaXJlY3RseS5odG1sKSBmb3VuZCB0aGF0Og0KDQo+IEEgbXVjaCBncmVhdGVyIHBlcmNlbnRhZ2Ugb2YgaGVyb2luIHVzZXJzIGNvbXBsZXRpbmcgdGhlIHN1cnZleSBpbiB0aGUgU0tJUCBQcm9ncmFtIHJlcG9ydGVkIGN1cnJlbnRseSBsaXZpbmcgaW4gc21hbGwgdXJiYW4gb3Igbm9udXJiYW4gYXJlYXMgdGhhbiBpbiBsYXJnZSB1cmJhbiBhcmVhcyAoNzUuMiUgdnMgMjQuOCUpIGF0IHRoZSB0aW1lIG9mIHN1cnZleSBjb21wbGV0aW9uLiANCg0KVGhpcyBzdXJ2ZXkgdXNlZCBzZWxmLWRlY2xhcmVkIGFyZWEgb2YgY3VycmVudCByZXNpZGVuY2UgKGxhcmdlIHVyYmFuLCBzbWFsbCB1cmJhbiwgc3VidXJiYW4sIG9yIHJ1cmFsKS4NCg0KR2l2ZW4gdGhhdCB3ZSBzYXcgYSBsYXJnZSBkZWdyZWUgb2YgdmFyaWFiaWxpdHkgYW1vbmcgdGhlIHVyYmFuIGNvdW50aWVzLCB3ZSB3aWxsIG5vdyBwYXJzZSB0aGlzIGdyb3VwIGZ1cnRoZXIgdG8gc2VlIGlmIGV4YW1pbmluZyBjb3VudGllcyB0aGF0IHdlcmUgZWl0aGVyIGxhcmdlIHVyYmFuIG9yIHNtYWxsZXIgKGluY2x1ZGluZyBzbWFsbCB1cmJhbiBhbmQgcnVyYWwpIHNlZW1zIHJlYXNvbmFibGUuDQoNCkFjY29yZGluZyB0byB0aGUgW09yZ2FuaXphdGlvbiBmb3IgRWNvbm9taWMgQ28tb3BlcmF0aW9uIGFuZCBEZXZlbG9wbWVudCAoT0VDRCldKGh0dHBzOi8vZGF0YS5vZWNkLm9yZy9wb3ByZWdpb24vdXJiYW4tcG9wdWxhdGlvbi1ieS1jaXR5LXNpemUuaHRtIzp+OnRleHQ9dGhlaXIlMjBhZG1pbmlzdHJhdGl2ZSUyMGJvdW5kYXJpZXMuLSxVcmJhbiUyMGFyZWFzJTIwaW4lMjBPRUNEJTIwY291bnRyaWVzJTIwYXJlJTIwY2xhc3NpZmllZCUyMGFzJTNBJTIwbGFyZ2UlMjBtZXRyb3BvbGl0YW4sYXJlYXMlMjBpZiUyMHRoZWlyJTIwcG9wdWxhdGlvbiUyMGlzKToNCg0KPiBVcmJhbiBwb3B1bGF0aW9uIGJ5IGNpdHkgc2l6ZSBpcyBkZXRlcm1pbmVkIGJ5IHBvcHVsYXRpb24gZGVuc2l0eSBhbmQgY29tbXV0aW5nIHBhdHRlcm5zOyB0aGlzIGJldHRlciByZWZsZWN0cyB0aGUgZWNvbm9taWMgZnVuY3Rpb24gb2YgY2l0aWVzIGluIGFkZGl0aW9uIHRvIHRoZWlyIGFkbWluaXN0cmF0aXZlIGJvdW5kYXJpZXMuIFVyYmFuIGFyZWFzIGluIE9FQ0QgY291bnRyaWVzIGFyZSBjbGFzc2lmaWVkIGFzOiBsYXJnZSBtZXRyb3BvbGl0YW4gYXJlYXMgaWYgdGhleSBoYXZlIGEgcG9wdWxhdGlvbiBvZiAxLjUgbWlsbGlvbiBvciBtb3JlOyBtZXRyb3BvbGl0YW4gYXJlYXMgaWYgdGhlaXIgcG9wdWxhdGlvbiBpcyBiZXR3ZWVuIDUwMCAwMDAgYW5kIDEuNSBtaWxsaW9uOyBtZWRpdW0tc2l6ZSB1cmJhbiBhcmVhcyBpZiB0aGVpciBwb3B1bGF0aW9uIGlzIGJldHdlZW4gMjAwIDAwMCBhbmQgNTAwIDAwMDsgYW5kLCBzbWFsbCB1cmJhbiBhcmVhcyBpZiB0aGVpciBwb3B1bGF0aW9uIGlzIGJldHdlZW4gNTAgMDAwIGFuZCAyMDAgMDAwLiBUaGlzIGluZGljYXRvciBpcyBtZWFzdXJlZCBhcyBhIHBlcmNlbnRhZ2Ugb2YgdGhlIG5hdGlvbmFsIHBvcHVsYXRpb24uDQoNClRodXMgd2UgY291bGQgdHJ5IGEgY3V0b2ZmIGZvciBzbWFsbCB1cmJhbiBwb3B1bGF0aW9ucyBhcyBsZXNzIHRoYW4gMjAwLDAwMC4gT2Ygbm90ZSB0aGlzIGlzIG5vdCBhcyBpZGVhbCBhcyBoYXZpbmcgY29tbXV0aW5nIHBhdHRlcm5zIGV0YywgaG93ZXZlciBpdCBpcyBhIHN0YXJ0aW5nIHBvaW50Lg0KDQpBY2NvcmRpbmcgdG8gdGhlIFtFY29ub21pYyBSZXNlcmFjaCBTZXJ2aWNlIG9mIHRoZSBVUyBkZXBhcnRtZW50IG9mIEFncmljdWx0dXJlIChVU0RBKV0oaHR0cHM6Ly93d3cuZXJzLnVzZGEuZ292L3RvcGljcy9ydXJhbC1lY29ub215LXBvcHVsYXRpb24vcnVyYWwtY2xhc3NpZmljYXRpb25zL3doYXQtaXMtcnVyYWwuYXNweCM6fjp0ZXh0PVNtYWxsJTIwcG9wdWxhdGlvbiUyMHNpemUlMjB0eXBpY2FsbHklMjBjaGFyYWN0ZXJpemVzLDUwJTJDMDAwJTJDJTIwZGVwZW5kaW5nJTIwb24lMjB0aGUlMjBkZWZpbml0aW9uKToNCg0KPiBQb3B1bGF0aW9uIHRocmVzaG9sZHMgdXNlZCB0byBkaWZmZXJlbnRpYXRlIHJ1cmFsIGFuZCB1cmJhbiBjb21tdW5pdGllcyByYW5nZSBmcm9tIDIsNTAwIHVwIHRvIDUwLDAwMCwgZGVwZW5kaW5nIG9uIHRoZSBkZWZpbml0aW9uLg0KDQpUbyBhbHNvIHVzZSBhIHBvcHVsYXRpb24gdGhyZXNob2xkIHRvIHJlZGVmaW5lIHRoZSBydXJhbCBjYXRlZ29yeSAodG8gYmUgY29uc2lzdGVudCB3aXRoIG91ciBvdGhlciBkZWZpbml0aW9ucyBvZiBsYXJnZSBhbmQgc21hbGwgdXJiYW4gcG9wdWxhdGlvbnMpIHdlIHdpbGwgdXNlIGEgY3V0b2ZmIG9mIGxlc3MgdGhhbiA1MCwwMDAuDQoNClNvIG5vdyB3ZSB3aWxsIG1ha2UgYSBuZXcgdmFyaWFibGUgd2l0aCB0aHJlZSBjYXRlZ29yaWVzIG9mIGNvdW50aWVzOiBsYXJnZSB1cmJhbiB2cyBzbWFsbCB1cmJhbiB2cyBydXJhbC4gDQoNClRodXMgd2Ugd2lsbCB1c2UgdGhlIGAmYCBvcGVyYXRvciB0byBpbmRpY2F0ZSB0aGF0IHRoZSBzbWFsbCB1cmJhbiBjYXRlZ29yeSBpcyBncmVhdGVyIHRoYW4gNTAsMDAwIGFuZCBhbHNvIGxlc3MgdGhhbiAyMDAsMDAwLg0KDQoNCmBgYHtyfQ0KDQpBbm51YWwgJTw+JSANCiAgbXV0YXRlKGNhdGVnb3J5ID0gY2FzZV93aGVuKHBvcHVsYXRpb24gPj0gMjAwMDAwIH4gIkxhcmdlIFVyYmFuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb24gPj0gNTAwMDAgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb24gPCAyMDAwMDAgfiAiU21hbGwgVXJiYW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbiA8IDUwMDAwIH4gIlJ1cmFsIikpDQoNCmBgYA0KDQpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGlzIHdpdGggb3VyIGZvcm1hdHRlZCB0YWJsZSBhbmQgcGxvdHMgYXMgYmVmb3JlLg0KDQoNCiMjIyMgey50aGlua19xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpEbyB5b3UgcmVjYWxsIGhvdyB3ZSBtaWdodCBkbyB0aGlzPw0KDQojIyMjDQoNCg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHJldmVhbCB0aGUgY29kZS4gPC9zdW1tYXJ5Pg0KDQoNCmBgYHtyfQ0KDQpSX1UgPC1Bbm51YWwlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBjb3VudChjYXRlZ29yeSkgJT4lDQogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2F0ZWdvcnksDQogICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IG4pICU+JQ0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUoIlJ1cmFsIENoYW5nZSIgPSBSdXJhbCAtIGxhZyhSdXJhbCksIA0KICAgICAgICAgIlNtYWxsIFVyYmFuIENoYW5nZSIgPSBgU21hbGwgVXJiYW5gIC0gbGFnKGBTbWFsbCBVcmJhbmApLA0KICAgICAgICAgIkxhcmdlIFVyYmFuIENoYW5nZSIgPSBgTGFyZ2UgVXJiYW5gIC0gbGFnKGBMYXJnZSBVcmJhbmApLA0KICAgICAgICAiUGVyY2VudCBMYXJnZSBVcmJhbiIgPSANCiAgcm91bmQoKGBMYXJnZSBVcmJhbmAvKGBMYXJnZSBVcmJhbmAgKyBgU21hbGwgVXJiYW5gICsgUnVyYWwpKSoxMDAsIGRpZ2l0cyA9IDIpKSAlPiUNCiAgcmVuYW1lKCJZZWFyIiA9ICJ5ZWFyIikNCg0KUl9VDQoNCnRhYmxlX2NhdCA8LSBmb3JtYXR0YWJsZTo6Zm9ybWF0dGFibGUoUl9VLCBsaXN0KGBQZXJjZW50IExhcmdlIFVyYmFuYCA9IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdHRhYmxlOjpjb2xvcl9iYXIoIiNGQTYxNEIiKSkpDQpgYGANCjwvZGV0YWlscz4gDQoNCmBgYHtyfQ0KdGFibGVfY2F0DQpgYGANCg0KDQoNClRoaXMgdGltZSB3aGVuIHdlIGNyZWF0ZSBvdXIgcGxvdCB3ZSB3aWxsIGFkZCBsYWJlbHMgZGlyZWN0bHkgdG8gdGhlIGxpbmVzIG9mIG91ciBwbG90IHVzaW5nIHRoZSBgZGlyZWN0bGFiZWxzYCBwYWNrYWdlLiANCg0KVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYGRpcmVjdC5sYWJlbCgpYCBmdW5jdGlvbi4gVGhpcyByZXF1aXJlcyBhIGxpc3Qgb2YgYXJndW1lbnRzLiBUaGUgYGRsLnRyYW5zKClgIGZ1bmN0aW9uIG1vZGlmaWVzIHRoZSBsb2NhdGlvbiBvZiBhbGwgbGFiZWxzLCB3aGlsZSB0aGUgYGRsLm1vdmUoKWAgZnVuY3Rpb24gY2FuIG1vdmUgYSBzcGVjaWZpYyBsYWJlbCB0byBhIHNwZWNpZmllZCBsb2NhdGlvbi4gTWV0aG9kIG9wdGlvbnMgYXJlIHNob3duIFtoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZGlyZWN0bGFiZWxzL2RpcmVjdGxhYmVscy5wZGYpLiBTZWUgW3RoaXMgY2FzZSBzdHVkeV0oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL29jcy1icC1jbzItZW1pc3Npb25zLykgYW5kIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAteW91dGgtZGlzY29ubmVjdGlvbi8pIGZvciBtb3JlIGRldGFpbHMuIA0KIA0KDQpgYGB7cn0NCg0KcGxvdF9jYXRfcmF3IDwtQW5udWFsICU+JQ0KZ2dwbG90KCBhZXMoeSA9IFBpbGxzX2luX21pbGxpb25zLCB4ID0geWVhciwgY29sb3VyID0gY2F0ZWdvcnksIGdyb3VwID0gY2F0ZWdvcnkpKSArIA0KICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX2Jvb3QsDQogICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC41KSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwNCiAgICAgICAgICAgICAgICBnZW9tID0gImxpbmUiKSArDQogIGxhYnModGl0bGUgPSAiUmF3IERhdGEiLA0KICAgICAgICAgIHkgPSAiUGlsbHMgaW4gbWlsbGlvbnMiLA0KICAgICAgICAgIHggPSBOVUxMKSsNCiAgdGhlbWVfY291bnR5KCkrDQogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSkrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjNDgxNTY3RkYiLCAiIzIwQTM4N0ZGIiwgIiM0NTM3ODFGRiIpKQ0KDQogcGxvdF9jYXRfcmF3PC0gZGlyZWN0bGFiZWxzOjpkaXJlY3QubGFiZWwocGxvdF9jYXRfcmF3LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSBsaXN0KGRsLnRyYW5zKHkgPSB5ICswLjUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZmFyLmZyb20ub3RoZXJzLmJvcmRlcnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICdib2xkJykpDQogIA0KICBwbG90X2NhdF9ub3JtIDwtQW5udWFsICU+JQ0KZ2dwbG90KCBhZXMoeSA9IHBvcF9ET1NBR0UsIHggPSB5ZWFyLCBjb2xvdXIgPSBjYXRlZ29yeSwgZ3JvdXAgPSBjYXRlZ29yeSkpICsgDQogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfYm9vdCwNCiAgICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjUpKSArDQogIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLA0KICAgICAgICAgICAgICAgIGdlb20gPSAibGluZSIpICsNCiAgbGFicyh0aXRsZSA9ICJOb3JtYWxpemVkIERhdGEiLA0KICAgICAgICAgIHkgPSAiTnVtYmVyIG9mIFBpbGxzIFBlciBDYXBpdGEiLA0KICAgICAgICAgICB4ID0gTlVMTCkrDQogIHRoZW1lX2NvdW50eSgpKw0KICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIikpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzQ4MTU2N0ZGIiwgIiMyMEEzODdGRiIsICIjNDUzNzgxRkYiKSkNCg0KIHBsb3RfY2F0X25vcm08LSBkaXJlY3QubGFiZWwocGxvdF9jYXRfbm9ybSwgbWV0aG9kID0gbGlzdChkbC50cmFucyh5ID0geSArMC41KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImZhci5mcm9tLm90aGVycy5ib3JkZXJzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAnYm9sZCcpKQ0KIA0KIHBsb3RfY2F0X3JhdyArIHBsb3RfY2F0X25vcm0gKyBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiRGlmZmVyZW5jZSBpbiBvcGlvaWQgcGlsbCBzaGlwbWVudHMgYmV0d2VlbiB0eXBlcyBvZiBjb3VudGllcyIsDQogICAgICAgc3VidGl0bGUgPSAiT3h5Y29kb25lIGFuZCBIeWRyb2NvZG9uZSBwaWxscyBpbiB0aGUgVVMiLCkNCmBgYA0KDQoNCldvdywgd2UgY2FuIHNlZSBoZXJlIHRoYXQgdGhlIHR3byB1cmJhbiBjYXRlZ29yaWVzIGFjdHVhbGx5IGhhdmUgbGFyZ2VyIGRpZmZlcmVuY2VzIGluIG5vcm1hbGl6ZWQgcGlsbCBjb3VudHMgZnJvbSBlYWNoIG90aGVyIHRoYW4gZWl0aGVyIGhhcyB3aXRoIHRoZSBydXJhbCBjb3VudGllcyENCg0KVGh1cyBpdCBzZWVtcyByZWFzb25hYmxlIHRvIGx1bXAgdGhlIHJ1cmFsIGFuZCBzbWFsbCB1cmJhbiBjYXRlZ29yaWVzIHRvZ2V0aGVyLCByYXRoZXIgdGhhbiBncm91cGluZyBsYXJnZSB1cmJhbiBhbmQgc21hbGwgdXJiYW4gYXMgd2Ugd2VyZSBkb2luZy4NCg0KDQpXZSB3aWxsIG1vZGlmeSBvdXIgb3JpZ2luYWwgY29kZSB3aXRoIHRoZSBwb3B1bGF0aW9uIHRocmVzaG9sZHMgd2hpY2ggd2FzOg0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0KQW5udWFsICU8PiUgDQogIG11dGF0ZShjYXRlZ29yeSA9IGNhc2Vfd2hlbihwb3B1bGF0aW9uID49IDIwMDAwMCB+ICJMYXJnZSBVcmJhbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uID49IDUwMDAwICYgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uIDwgMjAwMDAwIH4gIlNtYWxsIFVyYmFuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb24gPCA1MDAwMCB+ICJSdXJhbCIpKQ0KDQpgYGANCg0KTm93IHdlIHdpbGwganVzdCByZXBsYWNlIHRoZSBsYWJlbHMgZm9yIHRoZSBzbWFsbCB1cmJhbiBhbmQgcnVyYWwgY291bnRpZXMgdG8gYmUgdGhlIHNhbWUgdmFsdWUgIlNtYWxsIFVyYmFuIG9yIFJ1cmFsIiBmb3IgdGhpcyBuZXcgdmFyaWFibGUgY2FsbGVkICJsYXJnZV91cmJhbiI6DQoNCmBgYHtyfQ0KDQpBbm51YWwgJTw+JSANCiAgbXV0YXRlKGxhcmdlX3VyYmFuID0gY2FzZV93aGVuKHBvcHVsYXRpb24gPj0gMjAwMDAwIH4gIkxhcmdlIFVyYmFuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb24gPj0gNTAwMDAgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb24gPCAyMDAwMDAgfiAiU21hbGwgVXJiYW4gb3IgUnVyYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbiA8IDUwMDAwIH4gIlNtYWxsIFVyYmFuIG9yIFJ1cmFsIikpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdF8yY2F0X3JhdyA8LUFubnVhbCAlPiUNCmdncGxvdCggYWVzKHkgPSBQaWxsc19pbl9taWxsaW9ucywgeCA9IHllYXIsIA0KICAgICAgICAgICAgY29sb3VyID0gbGFyZ2VfdXJiYW4sIGdyb3VwID0gbGFyZ2VfdXJiYW4pKSArIA0KICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX2Jvb3QsDQogICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC41KSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwNCiAgICAgICAgICAgICAgZ2VvbSA9ICJsaW5lIikgKw0KICBsYWJzKHRpdGxlID0gIlJhdyBEYXRhIiwNCiAgICAgICAgICAgeSA9ICJQaWxscyBpbiBNaWxsaW9ucyIsDQogICAgICAgICAgIHggPSBOVUxMKSsNCiAgdGhlbWVfY291bnR5KCkrDQpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzQ4MTU2N0ZGIiwgIiMyMEEzODdGRiIpKQ0KDQpwbG90XzJjYXRfcmF3IDwtZGlyZWN0LmxhYmVsKHBsb3RfMmNhdF9yYXcsIG1ldGhvZCA9IGxpc3QoZGwudHJhbnMoeSA9IHkgKy42KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImZhci5mcm9tLm90aGVycy5ib3JkZXJzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAnYm9sZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2V4ID0gMC44KSkNCg0KcGxvdF8yY2F0X25vcm08LUFubnVhbCAlPiUNCmdncGxvdCggYWVzKHkgPSBwb3BfRE9TQUdFLCB4ID0geWVhciwgDQogICAgICAgICAgICBjb2xvdXIgPSBsYXJnZV91cmJhbiwgZ3JvdXAgPSBsYXJnZV91cmJhbikpICsgDQogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfYm9vdCwNCiAgICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjUpKSArDQogIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLA0KICAgICAgICAgICAgICBnZW9tID0gImxpbmUiKSArDQogIGxhYnModGl0bGUgPSAiTm9ybWFsaXplZCBEYXRhIiwNCiAgICAgICAgICAgeSA9ICJQaWxscyBQZXIgQ2FwaXRhIiwNCiAgICAgICAgICAgeCA9IE5VTEwpKw0KICB0aGVtZV9jb3VudHkoKSsNCnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjNDgxNTY3RkYiLCAiIzIwQTM4N0ZGIikpDQoNCnBsb3RfMmNhdF9ub3JtIDwtZGlyZWN0LmxhYmVsKHBsb3RfMmNhdF9ub3JtLCBtZXRob2QgPSBsaXN0KGRsLnRyYW5zKHkgPSB5ICsuNiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmYXIuZnJvbS5vdGhlcnMuYm9yZGVycyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gJ2JvbGQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2V4ID0gMC44KSkNCg0KDQpwbG90XzJjYXRfcmF3ICtwbG90XzJjYXRfbm9ybSArIHBsb3RfYW5ub3RhdGlvbigNCiAgdGl0bGUgPSAiRGlmZmVyZW5jZSBpbiBvcGlvaWQgcGlsbCBzaGlwbWVudHMgYmV0d2VlbiB0eXBlcyBvZiBjb3VudGllcyIsDQogICAgICAgc3VidGl0bGUgPSAiT3h5Y29kb25lIGFuZCBIeWRyb2NvZG9uZSBwaWxscyBpbiB0aGUgVVMiKQ0KYGBgDQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KSW5kZWVkIHdoZW4gd2UgZXZhbHVhdGUgdGhlIGRhdGEgaW4gdGhpcyB3YXksIHdlIHNlZSB0aGF0IHNtYWxsIHVyYmFuIGFuZCBydXJhbCBjb3VudGllcyByZWNlaXZlZCBoaWdoZXIgbnVtYmVycyBvZiBwaWxscyBwZXIgcGVyc29uIHRoYW4gbGFyZ2UgdXJiYW4gY291bnRpZXMuDQoNCiMgKipEYXRhIEFuYWx5c2lzKioNCioqKg0KDQpJZiB5b3UgaGF2ZSBiZWVuIGZvbGxvd2luZyBhbG9uZyBidXQgc3RvcHBlZCwgd2UgY291bGQgbG9hZCBvdXIgd3JhbmdsZWQgZGF0YSBmcm9tIHRoZSAiZGF0YSIgZGlyZWN0b3J5IGxpa2Ugc286DQoNCmBgYHtyfQ0KbG9hZChmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJBbm51YWxfb3Bpb2lkX2RhdGEucmRhIikpDQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgImNvdW50eV9pbmZvLnJkYSIpKQ0KYGBgDQoNCioqKg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBJZiB5b3Ugc2tpcHBlZCB0aGUgcHJldmlvdXMgc2VjdGlvbnMgY2xpY2sgaGVyZS4gPC9zdW1tYXJ5Pg0KDQpGaXJzdCB5b3UgbmVlZCB0byBpbnN0YWxsIHRoZSBgT0NTZGF0YWAgcGFja2FnZToNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQppbnN0YWxsLnBhY2thZ2VzKCJPQ1NkYXRhIikNCmxpYnJhcnkoT0NTZGF0YSkNCmBgYA0KDQpUaGVuLCB5b3UgbWF5IGRvd25sb2FkIGFuZCBsb2FkIHRoZSB3cmFuZ2xlZCBkYXRhIGludG8geW91ciBSIGVudmlyb25tZW50IHVzaW5nIHRoZSBmb2xsb3dpbmcgY29kZToNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQp3cmFuZ2xlZF9yZGEoIm9jcy1icC1vcGlvaWQtcnVyYWwtdXJiYW4iLCBvdXRwYXRoID0gZ2V0d2QoKSkNCmxvYWQoZmlsZSA9IGhlcmU6OmhlcmUoIk9DU2RhdGEiLCAiZGF0YSIsICJ3cmFuZ2xlZCIsICJBbm51YWxfb3Bpb2lkX2RhdGEucmRhIikpDQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJPQ1NkYXRhIiwgImRhdGEiLCAid3JhbmdsZWQiLCAiY291bnR5X2luZm8ucmRhIikpDQpgYGANCg0KSWYgdGhlIHBhY2thZ2UgZG9lcyBub3Qgd29yayBmb3IgeW91LCBhbHRlcm5hdGl2ZWx5LCB0aGUgUkRBIGZpbGVzIChzdGFuZHMgZm9yIFIgZGF0YSkgb2YgdGhlIGRhdGEgY2FuIGJlIGZvdW5kIGluIG91ciBbR2l0SHViIHJlcG9zaXRvcnldKGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLW9waW9pZC1ydXJhbC11cmJhbi90cmVlL21hc3Rlci9kYXRhL3dyYW5nbGVkKS4gRG93bmxvYWQgdGhlc2UgZmlsZXMgYW5kIHRoZW4gcGxhY2UgdGhlbSBpbiB5b3VyIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnkgd2l0aGluIGEgc3ViZGlyZWN0b3J5IGNhbGxlZCAid3JhbmdsZWQiIHdpdGhpbiBhIHN1YmRpcmVjdG9yeSBjYWxsZWQgImRhdGEiIHRvIGNvcHkgYW5kIHBhc3RlIG91ciBjb2RlLiBXZSB1c2VkIGFuIFJTdHVkaW8gcHJvamVjdCBhbmQgdGhlIFtgaGVyZWAgcGFja2FnZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSB0byBuYXZpZ2F0ZSB0byB0aGUgZmlsZXMgbW9yZSBlYXNpbHkuIA0KDQpgYGB7cn0NCmxvYWQoZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWQiLCAiQW5udWFsX29waW9pZF9kYXRhLnJkYSIpKQ0KbG9hZChmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJjb3VudHlfaW5mby5yZGEiKSkNCmBgYA0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgbW9yZSBhYm91dCBjcmVhdGluZyBuZXcgcHJvamVjdHMgaW4gUlN0dWRpby4gPC9zdW1tYXJ5Pg0KDQpZb3UgY2FuIGNyZWF0ZSBhIHByb2plY3QgYnkgZ29pbmcgdG8gdGhlIEZpbGUgbWVudSBvZiBSU3R1ZGlvIGxpa2Ugc286DQoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIk5ld19wcm9qZWN0LnBuZyIpKQ0KYGBgDQoNCllvdSBjYW4gYWxzbyBkbyBzbyBieSBjbGlja2luZyB0aGUgcHJvamVjdCBidXR0b246DQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJwcm9qZWN0X2J1dHRvbi5wbmciKSkNCmBgYA0KDQpTZWUgW2hlcmVdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdXNpbmcgUlN0dWRpbyBwcm9qZWN0cyBhbmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgYGhlcmVgIHBhY2thZ2UuDQoNCjwvZGV0YWlscz4NCioqKg0KPC9kZXRhaWxzPg0KDQoqKioNCg0KDQpJZiB5b3UgYXJlIHN0YXJ0aW5nIGhlcmUsIHdlIHdpbGwgYWxzbyBwZXJmb3JtIGEgZmV3IGV4dHJhIHN0ZXBzIHdpdGggdGhlIGRhdGEgdGhhdCB3ZSBkaWQgZHVyaW5nIHRoZSB2aXN1YWxpemF0aW9uIHNlY3Rpb246DQoNCmBgYHtyfQ0KIyBXZSBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIGBwb3BfRE9TQUdFYCB0aGF0IGlzIHRoZSBudW1iZXIgb2YgcGlsbHMgc2hpcHBlZCBwZXIgY291bnR5IGRpdmlkZWQgYnkgdGhlIHBvcHVsYXRpb24gb2YgdGhhdCBjb3VudHkNCkFubnVhbCU8PiUgIG11dGF0ZShwb3BfRE9TQUdFID0gIERPU0FHRV9VTklUIC8gcG9wdWxhdGlvbikNCg0KDQojIHdlIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYFBpbGxzX2luX21pbGxpb25zYCB0aGF0IGlzIHRoZSBudW1iZXIgb2YgcGlsbHMgc2hpcGVkIHBlciBjb3VudHkgZGl2aWRlZCBieSAxIG1pbGxpb24NCkFubnVhbCAlPD4lIA0KICBtdXRhdGUoUGlsbHNfaW5fbWlsbGlvbnMgPSBET1NBR0VfVU5JVC8xMDAwMDAwKQ0KDQojV2UgbWFrZSBhIG5ldyB2YXJpYWJsZSBiYXNlZCBvbiBiZWluZyBlaXRoZXIgbGFyZ2UgdXJiYW4gb3Igc21hbGwgdXJiYW4vcnVyYWwgYmFzZWQgb2ZmIGEgdGhyZXNob2xkIG9mIHBvcHVsYXRpb24gYmVjYXVzZSBvZiBvdXIgdmlzdWFsaXphdGlvbnMNCkFubnVhbCAlPD4lIA0KICBtdXRhdGUobGFyZ2VfdXJiYW4gPSBjYXNlX3doZW4ocG9wdWxhdGlvbiA+PSAyMDAwMDAgfiAiTGFyZ2UgVXJiYW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbiA+PSA1MDAwMCAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbiA8IDIwMDAwMCB+ICJTbWFsbCBVcmJhbiBvciBSdXJhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uIDwgNTAwMDAgfiAiU21hbGwgVXJiYW4gb3IgUnVyYWwiKSkNCg0KYGBgDQoNCg0KIyMgKipTdHVkZW50J3MgdC10ZXN0KioNCioqKg0KT0ssIHdlIGNhbiB0ZWxsIHRoYXQgdGhlcmUgYXBwZWFycyB0byBiZSBhIGRpZmZlcmVuY2UgYmV0d2VlbiBzbWFsbCB1cmJhbiBhbmQgcnVyYWwgY291bnRpZXMgY29tcGFyZWQgdG8gbGFyZ2UgdXJiYW4gY291bnRpZXMgYnkgbG9va2luZyBhdCB0aGlzIHBsb3QsIGhvd2V2ZXIgaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGVzZSB0d28gY2F0ZWdvcmllcyBvZiBjb3VudGllcyBtZWFuaW5nZnVsLCBvciBpcyBpdCBqdXN0IGR1ZSB0byByYW5kb20gZGlmZmVyZW5jZXMgZnJvbSBzYW1wbGluZz8gVG8gZXZhbHVhdGUgdGhpcyB3ZSBtYXkgY29uc2lkZXIgZW1wbG95aW5nIGEgc3RhdGlzdGljYWwgdGVzdCBjYWxsZWQgdGhlIFtTdHVkZW50J3MgJHQkLXRlc3RdKGh0dHBzOi8vc3RhdHRyZWsuY29tL3N0YXRpc3RpY3MvZGljdGlvbmFyeS5hc3B4P2RlZmluaXRpb249dHdvLXNhbXBsZSUyMHQtdGVzdCksIHdoaWNoIGNhbiBiZSB1c2VkIHRvIGRldGVybWluZSBpZiBbdHdvIGdyb3VwIG1lYW5zIGFyZSBkaWZmZXJlbnRdKGh0dHA6Ly9vbmxpbmVzdGF0Ym9vay5jb20vMi9lc3RpbWF0aW9uL2RpZmZlcmVuY2VfbWVhbnMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4NCg0KTGV0J3MgcmVtaW5kIG91cnNlbHZlcyBvZiBvbmUgb2Ygb3VyIG9yaWdpbmFsIHF1ZXN0aW9ucywgDQoNCj4gSGFzIHRoZXJlIGJlZW4gYSBkaWZmZXJlbmNlIGJldHdlZW4gb3Bpb2lkIHBpbGwgc2hpcG1lbnRzIHRvIHJ1cmFsIGFuZCB1cmJhbiBjb3VudGllcyBpbiB0aGUgVVM/DQoNCkluIGh5cG90aGVzaXMgdGVzdGluZywgd2UgYXJlIGludGVyZXN0ZWQgaW4gY29tcGFyaW5nIHR3byBkaWZmZXJlbnQgaHlwb3RoZXNlczogYSAibnVsbCIgaHlwb3RoZXNpcyAoY2FuIGJlIHRob3VnaHQgb2YgbGlrZSBhIGJhc2VsaW5lIGUuZy4gdGhlIG1lYW5zIGJldHdlZW4gdHdvIGdyb3VwcyBhcmUgdGhlIHNhbWUsIG9yIHRoZXJlIGlzIGEgZGlmZmVyZW5jZSBvZiAwIGJldHdlZW4gdGhlIG1lYW5zIG9mIHRoZSB0d28gZ3JvdXBzKSBjb21wYXJlZCB0byBhbiAiYWx0ZXJuYXRpdmUiIGh5cG90aGVzaXMgKGUuZy4gdGhlIG1lYW5zIGJldHdlZW4gdHdvIGdyb3VwcyBhcmUgZGlmZmVyZW50KS4gV2UgYXJlIGdvaW5nIHRvIGFzayBpZiB0aGVyZSBpcyBlbm91Z2ggZXZpZGVuY2UgaW4gb3VyIGRhdGEgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuICANCg0KTGV0J3MgdHJ5IHRvIGZvcm1hbGl6ZSB0aGlzIGEgYml0LiANCg0KVXNpbmcgU3R1ZGVudCdzIHQtdGVzdCwgIHdlIGNhbiB0ZXN0IHdoZXRoZXIgdGhlIG1lYW4gbnVtYmVyIG9mIHBpbGxzIHNoaXBwZWQgdG8gdGhlIHJ1cmFsIGNvdW50aWVzIGlzIHRoZSBzYW1lIGFzIHRoZSBtZWFuICBudW1iZXIgb2YgcGlsbHMgc2hpcHBlZCB0byB0aGUgdXJiYW4gYXJlYXMuIElmIHdlIGNhbGwgdGhlIHRydWUgdW5rbm93biBwb3B1bGF0aW9uIG1lYW5zIG9mIHRoZSB0d28gZ3JvdXBzICRcbXVfVSQgYW5kICRcbXVfUiQsIGZvciB0aGUgdXJiYW4gYW5kIHJ1cmFsIGFyZWFzLCByZXNwZWN0aXZlbHksIHRoZW4gd2UgY2FuIGRlZmluZSB0aGUgPGI+bnVsbCBoeXBvdGhlc2lzPC9iPiB0aGF0IHRoZXJlIGlzIG5vIGRpZmZlcmVuY2UgaW4gdGhlIHR3byBtZWFuczoNCg0KJCQgSF8wOiBcbXVfVSA9IFxtdV9SICQkICANCg0KSW4gY29udHJhc3QsIHdlIGFsc28gZGVmaW5lIGFuIDxiPmFsdGVybmF0aXZlIGh5cG90aGVzaXM8L2I+IHRoYXQgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1lYW4gbnVtYmVyIG9mIHBpbGxzIHNoaXBwZWQgdG8gZWFjaCB0eXBlIG9mIGNvdW50eTogDQoNCiQkIEhfYTogXG11X1UgXG5lcSBcbXVfUiAkJA0KDQpUaGUgaWRlYSBiZWhpbmQgYSBoeXBvdGhlc2lzIHRlc3QgaXMgdGhhdCB3ZSBhc3N1bWUgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0cnVlIGFuZCB3ZSB1c2Ugb3VyIGRhdGEgdG8gaGVscCB1cyBpZGVudGlmeSBpZiB0aGVyZSBpcyBlbm91Z2ggZXZpZGVuY2UgdG8gX3JlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzXy4gDQoNClRoaXMgaXMgc2ltaWxhciB0byB0aGUgaWRlYSBvZiBhc3N1bWluZyB0aGF0IGluZGl2aWR1YWxzIGFyZSBub3QgZ3VpbHR5IHVudGlsIHByb3ZlbiBvdGhlcndpc2UuDQpJZiB0aGVyZSBpcyBub3QgZW5vdWdoIGV2aWRlbmNlIGluIHRoZSBkYXRhLCB0aGVuIHdlIHNheSB3ZSAiZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyIuDQoNCg0KSG93ZXZlciwgcGVyZm9ybWluZyB0aGlzIHRlc3QgZGVwZW5kcyBvbiBjZXJ0YWluIGFzc3VtcHRpb25zIGFib3V0IG91ciBkYXRhOg0KDQoxKSBUaGUgZGF0YSBmb3IgZWFjaCBncm91cCBpcyBbbm9ybWFsbHkgZGlzdHJpYnV0ZWRdKGh0dHA6Ly9vbmxpbmVzdGF0Ym9vay5jb20vMi9pbnRyb2R1Y3Rpb24vZGlzdHJpYnV0aW9ucy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9Lg0KMikgVGhlIFt2YXJpYW5jZV0oaHR0cHM6Ly9zdGF0dHJlay5jb20vc3RhdGlzdGljcy9kaWN0aW9uYXJ5LmFzcHg/ZGVmaW5pdGlvbj12YXJpYW5jZSl7dGFyZ2V0PSJfYmxhbmsifSBvZiBib3RoIGdyb3VwcyBpcyBzaW1pbGFyLg0KMykgVGhlIG9ic2VydmF0aW9ucyBmcm9tIHRoZSB0d28gZ3JvdXBzIGFyZSBbaW5kZXBlbmRlbnRdKGh0dHBzOi8vd3d3LnN0YXQuY211LmVkdS9+Y3NoYWxpemkvMzYtMjIwL2xlY3R1cmUtNS5wZGYpe3RhcmdldD0iX2JsYW5rIn0gKG1lYW5pbmcgdGhhdCBvYnNlcnZhdGlvbnMgZG8gbm90IGluZmx1ZW5jZSBlYWNoIG90aGVyKS4NCjQpIFRoZSBvYnNlcnZhdGlvbnMgd2l0aGluIGVhY2ggZ3JvdXAgYXJlIFtpbmRlcGVuZGVudF0oaHR0cHM6Ly93d3cuc3RhdC5jbXUuZWR1L35jc2hhbGl6aS8zNi0yMjAvbGVjdHVyZS01LnBkZil7dGFyZ2V0PSJfYmxhbmsifSAobWVhbmluZyB0aGF0IG9ic2VydmF0aW9ucyBkbyBub3QgaW5mbHVlbmNlIGVhY2ggb3RoZXIpLg0KDQoNCldlIHdpbGwgc3RhcnQgYnkgc2hvd2luZyB5b3UgYSB0b29sIHRvIGFzc2VzcyB3aGV0aGVyIHRoZSBmaXJzdCBhc3N1bXB0aW9uIHNlZW1zIHRvIGJlIHRydWUgaW4gb3VyIGRhdGEuIFdlIGNhbiBvYnNlcnZlIHZpc3VhbGx5IHdoZXRoZXIgZWFjaCBncm91cCB0byBiZSB0ZXN0ZWQgYXBwZWFycyB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZCBieSBtYWtpbmcgd2hhdCBpcyBjYWxsZWQgYSAicXVhbnRpbGUtcXVhbnRpbGUiIHBsb3QgKG9yIDxiPlEtUSBwbG90PC9iPiBmb3Igc2hvcnQpLiBXaGVuIHdlIHRhbGsgYWJvdXQgYSA8Yj5xdWFudGlsZTwvYj4sIHdlIGFyZSB0YWxraW5nIGFib3V0IGRpdmlkaW5nIHVwIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGRhdGEgaW50byBlcXVhbCBwb3J0aW9ucyB3aGVyZSByb3VnaGx5IHRoZSBzYW1lIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgZmFsbCBpbnRvIGVhY2ggcG9ydGlvbi4gRm9yIGV4YW1wbGUsIGlmIHlvdSBkaXZpZGUgeW91ciBkYXRhIGludG8gMTAwIHF1YW50aWxlcywgeW91IGNhbiB0aGluayBhYm91dCB0aGlzIGFzIHBlcmNlbnRpbGVzLCBidXQgeW91IGNvdWxkIGFsc28gZGl2aWRlIHlvdXIgZGF0YSBpbnRvIDEwIHF1YW50aWxlcyBhbmQgdGhlc2Ugd291bGQgYmUgY2FsbGVkIGRlY2lsZXMuIA0KDQpJZiBvdXIgZGF0YSBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHRoZW4gdGhlIHF1YW50aWxlcyBvZiBvdXIgZGF0YSBwb2ludHMgc2hvdWxkIGluIHNvbWUgd2F5IG1hdGNoIHRoZSBxdWFudGlsZXMgb2YgYSBjZXJ0YWluIG5vcm1hbCBkaXN0cmlidXRpb24uIEEgUS1RIHBsb3QgY2FuIGFsbG93IHVzIHRvIHNlZSB2aXN1YWxseSB3aGV0aGVyIHRoaXMgc2VlbXMgdG8gYmUgdGhlIGNhc2UuDQoNCjxiPldoeSBRLVEgcGxvdHM/PC9iPiBRLVEgcGxvdHMgYWxsb3cgdXMgdG8gY29tcGFyZSB0aGUgcXVhbnRpbGVzIG9mIHR3byBkaXN0cmlidXRpb25zIHRvIG9uZSBhbm90aGVyLiBGb3IgZXhhbXBsZSwgd2UgbWF5IHdhbnQgdG8gY29tcGFyZSAoMSkgcXVhbnRpbGVzIG9mIGEga25vd24gdGhlb3JldGljYWwgZGlzdHJpYnV0aW9uIChsaWtlIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uKSB0byAoMikgcXVhbnRpbGVzIG9mIHRoZSBkaXN0cmlidXRpb24gb2Ygb3VyIGRhdGEuICBJZiB0aGUgcXVhbnRpbGVzIGZyb20gdGhlc2UgdHdvIGRpc3RyaWJ1dGlvbnMgbGluZSB1cCBpbiB0aGUgcGxvdCwgdGhlbiB0aGF0IGlzIGEgdmlzdWFsIHBpZWNlIG9mIGV2aWRlbmNlIHRoYXQgb3VyIGRhdGEgaGF2ZSBhIGRpc3RyaWJ1dGlvbiB0aGF0IGlzIHNpbWlsYXIgdG8gdGhhdCB0aGVvcmV0aWNhbCBkaXN0cmlidXRpb24gKGxpa2UgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24pLiAgDQoNCjxiPkhvdyBkb2VzIHRoaXMgd29yaz88L2I+IFRvIGRvIHRoaXMgd2Ugd2lsbCBwbG90IHRoZSBxdWFudGlsZXMgb2Ygb3VyIGRhdGEgb24gdGhlIHktYXhpcyBhbmQgdGhlIHF1YW50aWxlcyBvZiB0aGUgdGhlb3JldGljYWwgbm9ybWFsIGRpc3RyaWJ1dGlvbiBvbiB0aGUgeC1heGlzLiBJZiB0aGUgcXVhbnRpbGVzIGxpbmUgdXAgdGhlbiB3ZSBjYW4gc2F5IHRoYXQgb3VyIGRhdGEgaXMgZmFpcmx5IG5vcm1hbC4gU2VlIFtoZXJlXShodHRwOi8vb25saW5lc3RhdGJvb2suY29tLzIvYWR2YW5jZWRfZ3JhcGhzL3EtcV9wbG90cy5odG1sKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCBRLVEgcGxvdHMuDQoNClVzaW5nIHRoZSBgc3RhdF9xcSgpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UsIHdlIGNhbiBlYXNpbHkgY3JlYXRlIGEgUS1RIHBsb3QgZm9yIHF1YW50aWxlcyBmcm9tIG91ciBkYXRhICgic2FtcGxlIikgYW5kIGNvbXBhcmUgaXQgdG8gdGhlIHF1YW50aWxlcyBmcm9tIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgaS5lLiB1c2luZyBkYXRhIHJhbmRvbWx5IHNhbXBsZWQgZnJvbSBhIG5vcm1hbCBkaXN0cmlidXRpb24gKCJ0aGVvcmV0aWNhbCIpLiAgVGhlIGRlZmF1bHQgY29tcGFyaXNvbiBkaXN0cmlidXRpb24gZm9yIHRoZXNlIGZ1bmN0aW9ucyBpcyB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgc28gd2UgZG9uJ3QgbmVlZCB0byBzcGVjaWZ5IGl0IGluIG91ciBjb2RlLiBIZXJlLCB3ZSB3aWxsIGxvb2sgYXQgYm90aCBgcG9wX0RPU0FHRWAgYW5kIGBET1NBR0VfVU5JVGAgdmFsdWVzIGZyb20gYm90aCB0eXBlcyBvZiBvdXIgdXJiYW4vcnVyYWwgY2F0ZWdvcml6YXRpb24sIGFuZCBzZWUgd2hhdCB0aGVpciBkaXN0cmlidXRpb25zIGxvb2sgbGlrZS4NCg0KYGBge3J9DQpBbm51YWwgJT4lIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIiwgY29scyA9IGMocG9wX0RPU0FHRSwgRE9TQUdFX1VOSVQpKSAlPiUNCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSB2YWx1ZSkpICsNCiAgc3RhdF9xcSgpICsgDQogIHN0YXRfcXFfbGluZSgpICsNCiAgZmFjZXRfd3JhcCh+bGFyZ2VfdXJiYW4gKyB0eXBlLCBzY2FsZXMgPSAiZnJlZSIpDQoNCkFubnVhbCAlPiUgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiLCBjb2xzID0gYyhwb3BfRE9TQUdFLCBET1NBR0VfVU5JVCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHNhbXBsZSA9IHZhbHVlKSkgKw0KICBzdGF0X3FxKCkgKyANCiAgc3RhdF9xcV9saW5lKCkgKw0KICBmYWNldF93cmFwKH5ydXJhbF91cmJhbiArIHR5cGUsIHNjYWxlcyA9ICJmcmVlIikNCmBgYA0KDQpUaGUgYHN0YXRfcXFfbGluZSgpYCBmdW5jdGlvbiBpcyB1c2VkIHRvIGFkZCBhIGxpbmUgKHdpdGggYSBwYXJ0aWN1bGFyIHNsb3BlIGFuZCBpbnRlcmNlcHQpIHRvIHRoZSBwbG90LiBJZiB0aGUgcG9pbnRzIGxpZSBvbiB0aGlzIHN0cmFpZ2h0IGxpbmUsIHRoaXMgaXMgZXZpZGVuY2UgdGhhdCB0aGUgZGF0YSBoYXZlIHNvbWUgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgbm90IHRoYXQgdGhlIGRhdGEgaGF2ZSBhIHBhcnRpY3VsYXIgbm9ybWFsIGRpc3RyaWJ1dGlvbi4NCg0KT0ssIHdlIGNhbiBzZWUgdGhhdCBpbiBhbGwgY2FzZXMgdGhlIHBvaW50cyBhcHBlYXIgdG8gZGV2aWF0ZSBmcm9tIHRoZSBsaW5lIGZvciBhdCBsZWFzdCBvbmUgZ3JvdXAsIGluZGljYXRpbmcgdGhhdCB0aGUgcXVhbnRpbGVzIGFyZSBmYWlybHkgZGlzc2ltaWxhciBiZXR3ZWVuIHRoZSBvYnNlcnZlZCBhbmQgdGhlb3JldGljYWwgZGF0YS4NCg0KU29tZXRpbWVzIHVzaW5nIGEgZGF0YSB0cmFuc2Zvcm1hdGlvbiwgbGlrZSB0aGUgbG9nIHRyYW5zZm9ybWF0aW9uLCBjYW4gaGVscCBtYWtlIG91ciBzYW1wbGUgZGF0YSBsb29rIG1vcmUgbm9ybWFsLiBTbyB3ZSBjYW4gc2VlIGlmIHdlIGNhbiBvdmVyY29tZSB0aGlzIG9ic2VydmVkIGRldmlhdGlvbiBmcm9tIG5vcm1hbGl0eSBieSB0cmFuc2Zvcm1pbmcgdGhlIGRhdGEsIHRha2luZyB0aGUgbG9nIChiYXNlICRlJCkgb2YgdGhlIG51bWJlciBvZiBwaWxscyBvciB0aGUgbm9ybWFsaXplZCBudW1iZXIgb2YgcGlsbHMuIA0KDQpgYGB7cn0NCg0KQW5udWFsICU+JSBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIsIGNvbHMgPSBjKHBvcF9ET1NBR0UsIERPU0FHRV9VTklUKSkgJT4lDQogIGdncGxvdChhZXMoc2FtcGxlID0gbG9nKHZhbHVlKSkpICsNCiAgc3RhdF9xcSgpICsgDQogIHN0YXRfcXFfbGluZSgpICsNCiAgZmFjZXRfd3JhcCh+bGFyZ2VfdXJiYW4gKyB0eXBlLCBzY2FsZXMgPSAiZnJlZSIpDQoNCkFubnVhbCAlPiUgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiLCBjb2xzID0gYyhwb3BfRE9TQUdFLCBET1NBR0VfVU5JVCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHNhbXBsZSA9IGxvZyh2YWx1ZSkpKSArDQogIHN0YXRfcXEoKSArIA0KICBzdGF0X3FxX2xpbmUoKSArDQogIGZhY2V0X3dyYXAofnJ1cmFsX3VyYmFuICsgdHlwZSwgc2NhbGVzID0gImZyZWUiKQ0KICANCmBgYA0KDQpPSywgdGhpcyBkaWQgbm90IGhlbHAgdmVyeSBtdWNoOyB3ZSBjYW4gc3RpbGwgc2VlIGxhcmdlIGRldmlhdGlvbnMgb2YgdGhlIHBvaW50cyBmcm9tIHRoZSBsaW5lcy4gU28gbm93IHdlIGhhdmUgdHdvIG9wdGlvbnMuIE9uZSBpcyB0aGF0IHdlIGNhbiBjb250aW51ZSB3aXRoIHRoZSBbU3R1ZGVudCdzICR0JC10ZXN0XShodHRwczovL3N0YXR0cmVrLmNvbS9zdGF0aXN0aWNzL2RpY3Rpb25hcnkuYXNweD9kZWZpbml0aW9uPXR3by1zYW1wbGUlMjB0LXRlc3QpIGJlY2F1c2UgdGhpcyB0ZXN0IGlzIGZhaXJseSAqKnJvYnVzdCoqIHRvIHZpb2xhdGlvbnMgb2YgdGhlIG5vcm1hbGl0eSBhc3N1bXB0aW9uIGlmIHRoZSBzYW1wbGUgc2l6ZSBpcyByZWxhdGl2ZWx5IGxhcmdlLCBkdWUgdG8gd2hhdCBpcyBjYWxsZWQgdGhlIFtjZW50cmFsIGxpbWl0IHRoZW9yZW1dKGh0dHBzOi8vd3d3LmFuYWx5dGljc3ZpZGh5YS5jb20vYmxvZy8yMDE5LzA1L3N0YXRpc3RpY3MtMTAxLWludHJvZHVjdGlvbi1jZW50cmFsLWxpbWl0LXRoZW9yZW0vKXt0YXJnZXQ9Il9ibGFuayJ9LCB3aGljaCBzdGF0ZXMgdGhhdCBhcyBzYW1wbGVzIGdldCBsYXJnZXIsIHRoZSBzYW1wbGUgbWVhbiBoYXMgYW4gYXBwcm94aW1hdGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gU2luY2Ugd2UgYXJlIHRyeWluZyB0byBtYWtlIGluZmVyZW5jZSBhYm91dCB0aGUgcG9wdWxhdGlvbiBtZWFuIGJ5IHVzaW5nIG91ciBzYW1wbGUgbWVhbiwgYXMgbG9uZyBhcyB0aGUgc2FtcGxlIG1lYW4gaGFzIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgaXQgaXMgT0sgdGhhdCBvdXIgZGF0YSB0aGVtc2VsdmVzIGFyZSBub3Qgbm9ybWFsLiANCiANCmBgYHtyfQ0KQW5udWFsICU+JQ0KICBjb3VudChsYXJnZV91cmJhbikNCg0KQW5udWFsICU+JQ0KICAgY291bnQocnVyYWxfdXJiYW4pDQpgYGANCg0KT3VyIHNhbXBsZXMgYXJlIGluZGVlZCBxdWl0ZSBsYXJnZSwgdGh1cyBpdCB3b3VsZCBwcm9iYWJseSBiZSByZWFzb25hYmxlIHRvIGNvbnRpbnVlIHdpdGggdGhlICR0JC10ZXN0LiANCg0KSG93ZXZlciwgb3VyIHNlY29uZCBvcHRpb24gaXMgdG8gcGVyZm9ybSBhIHRlc3QgY2FsbGVkIHRoZSANCltNYW5uIFdoaXRuZXkgVSB0ZXN0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9NYW5uJUUyJTgwJTkzV2hpdG5leV9VX3Rlc3QpIGFsc28ga25vd24gYXMgdGhlIFdpbGNveG9uIHJhbmsgc3VtIHRlc3Qgb3IgdGhlIHR3by1zYW1wbGUgV2lsY294IHRlc3Qgb3IgdGhlIE1hbm7igJNXaGl0bmV54oCTV2lsY294b24gKE1XVykgdGVzdC4gSW1wb3J0YW50bHksIHRoaXMgdGVzdCBkb2VzIG5vdCByZWx5IG9uIHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlIGRhdGEgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGFuZCBpdCBpcyBtb3JlIHJvYnVzdCB0aGFuIHRoZSB0LXRlc3QgdG8gW291dGxpZXJzXShodHRwczovL3d3dy5pdGwubmlzdC5nb3YvZGl2ODk4L2hhbmRib29rL3ByYy9zZWN0aW9uMS9wcmMxNi5odG0pIChleHRyZW1lIHZhbHVlcyBjb21wYXJlZCB0byB0aGUgb3RoZXJzKS4gR2l2ZW4gdGhhdCB0aGUgZGF0YSBhcHBlYXJzIHRvIGJlIHF1aXRlIGRpZmZlcmVudCBmcm9tIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uLCB3ZSB3aWxsIHByb2NlZWQgdXNpbmcgdGhpcyB0ZXN0LiANCg0KIyMgKipNYW5u4oCTV2hpdG5leeKAk1dpbGNveG9uIChNV1cpIHRlc3QgKFdpbGNveCB0ZXN0IGZvciBzaG9ydCkqKg0KKioqDQpJbiB0aGlzIHRlc3QsIHRoZSBoeXBvdGhlc2lzIGlzIHNsaWdodGx5IGRpZmZlcmVudC4gSW5zdGVhZCBvZiBjb21wYXJpbmcgbWVhbnMsIHRoaXMgdGVzdCBldmFsdWF0ZXMgdGhlIGZvbGxvd2luZyBudWxsIGh5cG90aGVzaXMgZm9yIGNvbXBhcmluZyB0aGUgdHdvIGdyb3VwcyAoYWRhcHRlZCBmcm9tIFdpa2lwZWRpYSk6DQoNCj4gdGhlIHByb2JhYmlsaXR5IHRoYXQgYSByYW5kb21seSBzZWxlY3RlZCB2YWx1ZSBvZiB0aGUgZmlyc3QgZ3JvdXAgKFgpIGlzIGdyZWF0ZXIgdGhhbiBhIHJhbmRvbWx5IHNlbGVjdGVkIHZhbHVlIG9mIHRoZSBzZWNvbmQgZ3JvdXAgKFkpIGlzIGVxdWFsIHRvIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGEgcmFuZG9tbHkgc2VsZWN0ZWQgdmFsdWUgb2YgdGhlIHNlY29uZCBncm91cCAoWSkgaXMgZ3JlYXRlciB0aGFuIGEgcmFuZG9tbHkgc2VsZWN0ZWQgdmFsdWUgb2YgdGhlIGZpcnN0IGdyb3VwIChYKS4NCg0KVGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgd291bGQgdGhlbiBiZSB0aGF0IHRoZXNlIHByb2JhYmlsaXRpZXMgYXJlIG5vdCBlcXVhbCwgaS5lLiwgcmFuZG9tIHZhbHVlcyBvZiBvbmUgZ3JvdXAgYXJlIG1vcmUgbGlrZWx5IHRvIGJlIGxhcmdlciB0aGFuIHJhbmRvbSB2YWx1ZXMgZnJvbSB0aGUgb3RoZXIgZ3JvdXAuIA0KDQpXZSBjYW4gYWxzbyB1c2Ugd2hhdCBpcyBjYWxsZWQgYSAqb25lLXNpZGVkIGFsdGVybmF0aXZlKiB0byB0ZXN0IHRoYXQgcmFuZG9tIHZhbHVlcyBvZiBYIGFyZSBtb3JlIGxpa2VseSB0byBiZSBncmVhdGVyIHRoYW4gcmFuZG9tIHZhbHVlcyBvZiBZIG9yIHRoYXQgcmFuZG9tIHZhbHVlcyBvZiBYIGFyZSBsZXNzIGxpa2VseSB0byBiZSBncmVhdGVyIHRoYW4gcmFuZG9tIHZhbHVlcyBZLCBpZiB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBhIHBhcnRpY3VsYXIgZGlyZWN0aW9uIG9mIGNvbXBhcmlzb24sIGFzIHdlIG1pZ2h0IGJlIGhlcmUgKGkuZS4sIHdlIGNvdWxkIGFzayB0aGUgbW9yZSBzcGVjaWZpYyBxdWVzdGlvbiBvZiB3aGV0aGVyIG9waW9pZCBzaGlwbWVudCByYXRlcyBhcmUgaGlnaGVyIGZvciBydXJhbCBjb21wYXJlZCB0byB1cmJhbiBjb3VudGllcykuIA0KDQpBbm90aGVyIHdheSBvZiBkZXNjcmliaW5nIHRoaXMgbnVsbCBoeXBvdGhlc2lzIGlzIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIHByb2JhYmlsaXRpZXMgb2YgdGhlIG9jY3VycmVuY2VzIG9mIHRoZSBwb3NzaWJsZSB2YWx1ZXMgb2YgWCBhbmQgWSBhcmUgZXF1YWwgb3IgaGF2ZSBhIHNoaWZ0IG9mIDAuIFdoZXJlYXMsIHRoZSBhbHRlcm5hdGl2ZSB3b3VsZCBiZSB0aGF0IHRoZSBzaGlmdCBiZXR3ZWVuIHRoZSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb25zIGlzIG5vdCB6ZXJvLiBTaW1pbGFybHksIHRoZSBvbmUtc2lkZWQgYWx0ZXJuYXRpdmVzIGFyZSBlaXRoZXIgdGhhdCB0aGUgc2hpZnQgaW4gcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9ucyBpcyBncmVhdGVyIHRoYW4gemVybyBvciB0aGF0IGl0IGlzIGxlc3MgdGhhbiB6ZXJvLiANCg0KSGVyZSB5b3UgY2FuIHNlZSBhbiBpbGx1c3RyYXRpb24gb2YgdGhlIG51bGwgaHlwb3RoZXNpcyBvbiB0aGUgbGVmdCBhbmQgYSBvbmUtc2lkZWQgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBvbiB0aGUgcmlnaHQ6DQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KaW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAibnVsbC5wbmciKSkNCmBgYA0KDQojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3LnN0YXQuYXVja2xhbmQuYWMubnovfndpbGQvQ2hhbmNlRW5jL0NoMTAud2lsY294b24ucGRmKQ0KDQoNClNvIGluIG91ciBjYXNlLCB1c2luZyB0aGUgV2lsY294IHRlc3QsIHdlIGNhbiB0ZXN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgZm9sbG93aW5nIHR3byBwcm9iYWJpbGl0aWVzIGFyZSB0aGUgc2FtZTogKDEpIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGEgcmFuZG9tIGNvdW50eSBjYXRlZ29yaXplZCBhcyBydXJhbCBoYXMgYSBsYXJnZXIgbnVtYmVyIG9mIHBpbGxzIHNoaXBwZWQgdGhhbiBhIHJhbmRvbSBjb3VudHkgY2F0ZWdvcml6ZWQgYXMgdXJiYW4gYW5kICgyKSB0aGUgcHJvYmFiaWxpdHkgdGhhdCBhIHJhbmRvbSBjb3VudHkgY2F0ZWdvcml6ZWQgYXMgdXJiYW4gaGFzIGEgbGFyZ2VyIG51bWJlciBvZiBwaWxscyBzaGlwcGVkIHRoYW4gYSByYW5kb20gY291bnR5IGNhdGVnb3JpemVkIGFzIHJ1cmFsIChvciBzaW1pbGFybHkgY29tcGFyaW5nIHNtYWxsIHVyYmFuIGFuZCBydXJhbCBjb3VudGllcyB0byBsYXJnZSB1cmJhbiBjb3VudGllcykuIA0KDQpJZiB3ZSBjYWxsIHRoZSByYW5kb20gY291bnRpZXMgJFUkIGFuZCAkUiQsIGZvciB0aGUgdXJiYW4gYW5kIHJ1cmFsIGFyZWFzLCByZXNwZWN0aXZlbHksIHRoZW4gd2UgY2FuIGRlZmluZSB0aGUgPGI+bnVsbCBoeXBvdGhlc2lzPC9iPiB0aGF0IHRoZXJlIGlzIG5vIGRpZmZlcmVuY2UgaW4gdGhlIHByb2JhYmlsaXRpZXMgJFAkOg0KDQokJCBIXzA6IFAoVSA+IFIpID0gUChSPlUpICQkICANCg0KSW4gY29udHJhc3QsIHdlIGFsc28gZGVmaW5lIGFuIDxiPmFsdGVybmF0aXZlIGh5cG90aGVzaXM8L2I+IHRoYXQgdGhlcmUgaXMgYSBkaWZmZXJlbmNlICh0d28tc2lkZWQpOiANCg0KJCQgSF9hOiBQKFUgPiBSKSBcbmVxIFAoUj5VKSQkDQoNCldpdGggYSBvbmUtc2lkZWQgYWx0ZXJuYXRpdmUgdGhhdCBhIGxhcmdlciBudW1iZXIgb2YgcGlsbHMgYXJlIHNoaXBwZWQgcGVyIHBlcnNvbiB0byBydXJhbCBjb3VudGllcyBhczoNCg0KJCQgSF9hOiBQKFI+VSkgPiBQKFUgPiBSKSAkJA0KSGVyZSB0aGUgcHJvYmFiaWxpdHkgdGhhdCBhIHJhbmRvbSBydXJhbCBjb3VudHkgaGFkIGEgbGFyZ2VyIG51bWJlciBvZiBwaWxscyBzaGlwcGVkIHRoYW4gYSByYW5kb20gdXJiYW4gY291bnR5IGlzIGdyZWF0ZXIgdGhhbiB0aGUgcHJvYmFiaWxpdHkgdGhhdCBhIHJhbmRvbSB1cmJhbiBjb3VudHkgaGFkIGEgbGFyZ2VyIG51bWJlciBvZiBwaWxscyBzaGlwcGVkIHRoYW4gYSByYW5kb20gcnVyYWwgY291bnR5LiANCg0KV2UgY2FuIGV4dGVuZCB0aGlzIHRvIHRoZSBzbWFsbCB1cmJhbi9ydXJhbCB2cyB0aGUgbGFyZ2UgcnVyYWwgY291bnR5IGNvbXBhcmlzb24uDQoNCg0KVG8gaW1wbGVtZW50IHRoaXMgdGVzdCBpbiBSIHdlIHdpbGwgdXNlIHRoZSBgd2lsY294LnRlc3QoKWAgZnVuY3Rpb24gaW4gIHRoZSBgc3RhdHNgIHBhY2thZ2UuIFRoaXMgZnVuY3Rpb24gYWx3YXlzIG9yZGVycyB0aGUgZ3JvdXBzIGluIGFscGhhYmV0aWNhbCBvcmRlcjogWCBpcyBhdXRvbWF0aWNhbGx5IHRoZSBncm91cCB0aGF0IGNvbWVzIGZpcnN0IGFscGhhYmV0aWNhbGx5LCB3aGlsZSBZIGlzIHRoZSBncm91cCB0aGF0IGNvbWVzIHNlY29uZCBhbHBoYWJldGljYWxseS4gDQoNClRodXMgZm9yIHRoZSBgcnVyYWxfdXJiYW5gIHZhcmlhYmxlLCB0aGUgYCoqUioqdXJhbGAgdmFsdWVzIHdvdWxkIGJlIHRoZSBYIGdyb3VwLCB3aGlsZSB0aGUgYCoqVSoqcmJhbmAgd291bGQgYmUgdGhlIFkgZ3JvdXAsIGFzIFIgY29tZXMgYmVmb3JlIFUgaW4gdGhlIGFscGhhYmV0Lg0KDQpGb3IgdGhlIGBsYXJnZV91cmJhbmAgdmFyaWFibGUsIHRoZSBgKipMKiphcmdlIFVyYmFuYCBncm91cCB2YWx1ZXMgd291bGQgYmUgdGhlIFggZ3JvdXAsIHdoaWxlIHRoZSBgKipTKiptYWxsIFVyYmFuIG9yIFJ1cmFsYCB2YWx1ZXMgd291bGQgYmUgdGhlIFkgZ3JvdXAuDQoNCg0KVGhlIHRlc3Qgc3RhdGlzdGljIGZvciB0aGUgV2lsY294b24gdGVzdCwgJFckLCBpcyBhY3R1YWxseSBxdWl0ZSBzaW1wbGUgdG8gY2FsY3VsYXRlIG1hbnVhbGx5IHdpdGggc21hbGwgc2FtcGxlIHNpemVzLiANCg0KKioqDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgaG93ICRXJCBpcyBjYWxjdWxhdGVkIG1hbnVhbGx5IDwvc3VtbWFyeT4NCg0KTGV0J3Mgc2F5IHRoYXQgdGhlIFVTIG9ubHkgaGFkIDMgY291bnRpZXMgdGhhdCB3ZXJlIHJ1cmFsIGFuZCAzIGNvdW50aWVzIHRoYXQgd2VyZSB1cmJhbiBhbmQgd2Ugd2FudGVkIHRvIGNvbXBhcmUgdGhlIGRpc3RyaWJ1dGlvbnMgdXNpbmcgdGhpcyB0ZXN0Lg0KDQoNClRoZSBudW1iZXIgb2YgcGlsbHMgc2hpcHBlZCB0byBlYWNoIG9mIHRoZSAzIHJ1cmFsIGNvdW50aWVzIHdhczogICANCjEpIDEwICAgDQoyKSA1MCAgDQozKSAzMCAgDQoNClRoZSBudW1iZXIgb2YgcGlsbHMgc2hpcHBlZCB0byBlYWNoIG9mIHRoZSAzIHVyYmFuIGNvdW50aWVzIHdhczogIA0KMSkgMjAgIA0KMikgMjUgIA0KMykgMTIgIA0KDQoNCldlIGNhbiBjYWxjdWxhdGUgb3VyIFdpbGNveG9uIHRlc3Qgc3RhdGlzdGljIGluIHR3byB3YXlzOiBlaXRoZXIgdXNpbmcgdGhlIHN1bSBvZiB0aGUgcmFua3Mgb2YgdGhlIG9yZGVyZWQgdmFsdWVzIGZyb20gdGhlIHR3byBncm91cHMgY29tYmluZWQsIG9yIHRoZSBudW1iZXIgb2YgIndpbnMiIGluIGZvciBlYWNoIGdyb3VwIGluIGFsbCBwYWlyd2lzZSBjb21wYXJpc29ucyBvZiB2YWx1ZXMgZnJvbSB0aGUgdHdvIGdyb3Vwcy4gV2hpbGUgdGhpcyBpcyBub3Qgb2J2aW91cywgaXQgdHVybnMgb3V0IHRoYXQgdGhlc2UgdHdvIG1ldGhvZHMgd2lsbCBnaXZlIHRoZSBzYW1lIHJlc3VsdHMuDQoNClVzaW5nIHRoZSByYW5rLXN1bSBtZXRob2QsIHRoZSBmaXJzdCBzdGVwIGlzIHRvIGxpc3QgdGhlIGNvdW50aWVzIGluIG9yZGVyIG9mIHRoZSBudW1iZXIgb2YgcGlsbHMgc2hpcHBlZCwgbGFiZWxpbmcgdGhlbSB3aXRoIHRoZWlyIGdyb3VwIG1lbWJlcnNoaXAuIFdlIHdpbGwgdXNlICAiUiIgb3IgIlUiIGlmIHRoZSBudW1iZXIgY2FtZSBmcm9tIGEgcnVyYWwgb3IgdXJiYW4gY291bnR5OiAgIA0KDQpDb3VudHk6IFIgICBVICAgVSAgICBVICAgUiAgICBSICAgDQogcGlsbHM6IDEwICAxMiAgMjAgICAyNSAgMzAgICA0MCAgIA0KICByYW5rOiAxICAgMiAgIDMgICAgNCAgIDUgICAgNiAgDQogIA0KICANCnN1bSBvZiByYW5rcyAkKFJfMSkkIGZvciBSOiAkMSsgNSArNiA9IDEyJCAgDQpzdW0gb2YgcmFua3MgJChSXzIpJCBmb3IgVTogJDIrMys0ID0gOSQgIA0KICANCg0KTm93IHR3byAkVyQgc3RhdGlzdGljcyBhcmUgY2FsY3VsYXRlZCwgb25lIGZvciBlYWNoIGdyb3VwIGxpa2Ugc28gKHdoZXJlICRuJCBpcyB0aGUgc2FtcGxlIHNpemUgZm9yIHRoYXQgZ3JvdXApOiAgDQoNCiAgJCRXXzEgPSBSXzEtXGZyYWN7bl8xKG5fMSsxKX17Mn0kJCAgDQoNCiAgJCRXXzIgPSBSXzItXGZyYWN7bl8yKG5fMisxKX17Mn0kJCAgDQogIA0KICAgDQpVc2luZyBvdXIgZXhhbXBsZSBkYXRhOiAgDQoNCiAgJFdfMSQgaXMgZm9yIHJ1cmFsIGNvdW50aWVzICANCiAgJFdfMSA9IFJfMS1cZnJhY3tuXzEobl8xKzEpfXsyfSQgIA0KICAkV18xID0gMTIgLSgzKDQpLzIpID0gMTItNiA9IDYkICANCiAgDQogICRXXzIkID0gVSBmb3IgdXJiYW4gY291bnRpZXMgIA0KICAkV18yID0gUl8yLVxmcmFje25fMihuXzIrMSl9ezJ9JCAgDQogICRXXzIgPSA5LSgzKDQpLzIpID0gOS02ID0gMyQgIA0KICANCldlIG5vdyB3YW50IHRvIHVzZSB0aGVzZSB0d28gdmFsdWVzIHRvIGdldCBvbmUgb3ZlcmFsbCB0ZXN0IHN0YXRpc3RpYyBmb3Igb3VyIGh5cG90aGVzaXMgdGVzdC4gSXQgdHVybnMgb3V0IHRoYXQgdGhpcyB0ZXN0IHN0YXRpc3RpYyBjYW4gYmUgZGVmaW5lZCBpbiBkaWZmZXJlbnQgd2F5cy4gT2Z0ZW4gJFckIGlzIGRlZmluZWQgYXMgZm9sbG93czogIA0KDQogICRXID0gbWluKFdfMSwgV18yKSA9IDMkLiBIb3dldmVyLCBSIHRha2VzIHRoZSB2YWx1ZSAkV18xJCBvciAkV18yJCBmb3IgJFckIGRlcGVuZGluZyBvbiB3aGF0IHNhbXBsZSBpcyBsaXN0ZWQgZmlyc3QuIFRodXMgZm9yIHRoaXMgZGF0YSBzZXQsIHRoZSBSIG91dHB1dCB3aWxsIGdpdmUgdGhlIHZhbHVlICRXXzEkIGZvciB0aGUgdGVzdCBzdGF0aXN0aWMgaW4gdGhpcyBjYXNlLiANCiAgDQogIEluIG91ciBjYXNlIHRoZSBmaXJzdCBncm91cCAocnVyYWwgY291bnRpZXMpIGhhZCBhICRXJCBvZiA2LiAgDQoNCkZyb20gdGhlIGRvY3VtZW50YXRpb24gZm9yIHRoZSBgc3RhdHNgIHBhY2thZ2UgZm9yIHRoZSBgd2lsY294LnRleHQoKWAgZnVuY3Rpb246ICANCiAgDQo+IFIncyB2YWx1ZSBjYW4gYWxzbyBiZSBjb21wdXRlZCBhcyB0aGUgbnVtYmVyIG9mIGFsbCBwYWlycyAoeFtpXSwgeVtqXSkgZm9yIHdoaWNoIHlbal0gaXMgbm90IGdyZWF0ZXIgdGhhbiB4W2ldLCB0aGUgbW9zdCBjb21tb24gZGVmaW5pdGlvbiBvZiB0aGUgTWFubi1XaGl0bmV5IHRlc3QuICANCg0KSWYgeW91IGFyZSBmYW1pbGlhciB3aXRoIGxpbmVhciBhbGdlYnJhLCB3ZSBjYW4gY2FsY3VsYXRlIHRoaXMgdmFsdWUgaW4gYSBjbGV2ZXIgd2F5IGluIFIgYnkgZ2V0dGluZyBhbGwgdGhlIHBhaXJ3aXNlIGNvbXBhcmlzb25zIG9mIHZhbHVlcyBiZXR3ZWVuIHRoZSB0d28gZ3JvdXBzIHVzaW5nIHRoZSBgb3V0ZXIoKWAgYmFzZSBmdW5jdGlvbiBhbmQgdXNpbmcgdGhlIGA+YCAoaW5zdGVhZCBvZiB0aGUgcHJvZHVjdCBvciBgKmAgZnVuY3Rpb24gYXMgdGhpcyBpcyB0eXBpY2FsbHkgdXNlZCBieSBkZWZhdWx0IHRvIGdldCB0aGUgW291dGVyIHByb2R1Y3RdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL091dGVyX3Byb2R1Y3QpKSB0byBkZXRlcm1pbmUgaG93IG9mdGVuIHRoZSBydXJhbCBjb3VudGllcyBoYXZlIGEgZ3JlYXRlciB2YWx1ZSB0aGFuIHRoZSB1cmJhbiBjb3VudGllcy4NCg0KYGBge3J9DQpleGFtcGxlIDwtdGliYmxlKHBpbGxzID0gYygxMCwxMiwgMjAsIDI1LDMwLCA0MCksIGNvdW50eSA9IGMoIlIiLCAiVSIsICJVIiwgIlUiLCAiUiIsICJSIikpDQpleGFtcGxlDQoNClIgPSBjKDEwLDMwLCA0MCkNClUgPSBjKDEyLCAyMCwgMjUpDQoNCm91dGVyKFIsVSwgIj4iKQ0KDQojIDEwIGlzIGxlc3MgdGhhbiAxMiwgMjAsIGFuZCAyNSAoUiBpcyBhbHdheXMgbGVzcyB0aGFuIFUgZm9yIGFsbCAzIGNvbXBhcmlzb25zKQ0KIyAzMCBpcyBncmVhdGVyIHRoYW4gMTIsIDIwLCBhbmQgMjUgKDMgdGltZXMgdGhhdCBSIGlzIGdyZWF0ZXIgdGhhbiBVKQ0KIyA0MCBpcyBncmVhdGhlciB0aGFuIDEyLCAyMCwgYW5kIDI1ICggMyB0aWVtcyB0aGF0IFIgaXMgZ3JlYXRlciB0aGFuIFUpDQoNCiMgMyszID0gNiBwYWlycyBvdXQgb2YgOSB3aGVyZSBSIHdhcyBncmVhdGVyIHRoYW4gVSB0aHVzIFcgaXMgZXF1YWwgdG8gNg0KDQpzdW0ob3V0ZXIoUixVLCAiPiIpKQ0Kd2lsY294LnRlc3QoZGF0YSA9IGV4YW1wbGUsICBwYWlyZWQgPSBGQUxTRSwgIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiLCBwaWxsc34gY291bnR5KQ0KDQpgYGANCg0KDQpXZSBjYW4gYWxzbyBzZWUgdGhhdCBpZiB3ZSBzd2l0Y2ggdGhlIG9yZGVyIG9mIG91ciBjb3VudGllcyAoaS5lLiwgd2UgbWFrZSB0aGUgdmFsdWVzIHRoYXQgd2VyZSBmb3IgdXJiYW4gbm93IHRoZSB2YWx1ZXMgZm9yIHJ1cmFsKSB3ZSB0aGVuIGdldCB0aGUgJFckIGZvciB3aGF0IHdhcyBwcmV2aW91c2x5IG91ciBzZWNvbmQgZ3JvdXAgaW4gdGhlIHJlc3VsdC4gKFJlbWVtYmVyIHdoYXRldmVyIGlzIGFscGhhYmV0aWNhbGx5IGZpcnN0IHdpbGwgYmUgdGhlIGZpcnN0IGdyb3VwIC0gc28gYWdhaW4gdGhlIHJlc3VsdHMgYXJlIGZvciAiUiIuKQ0KDQpgYGB7ciB9DQoNCmV4YW1wbGUgPC10aWJibGUocGlsbHMgPSBjKDEwLDEyLCAyMCwgMjUsMzAsIDQwKSwgY291bnR5ID0gYygiVSIsICJSIiwgIlIiLCAiUiIsICJVIiwgIlUiKSkNCmV4YW1wbGUNCg0Kd2lsY294LnRlc3QoZGF0YSA9IGV4YW1wbGUsICBwYWlyZWQgPSBGQUxTRSwgIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiLCBwaWxsc34gY291bnR5KQ0KDQpgYGANCg0KRm9yIHNtYWxsIHNhbXBsZXMsIHRoZSBzdGF0aXN0aWMgJFckIGNhbiB0aGVuIGJlIGNvbXBhcmVkIHRvIGEgW2NyaXRpY2FsICRXJCB0YWJsZV0oaHR0cHM6Ly9tYXRoLnVzYXNrLmNhL35sYXZlcnR5L1MyNDUvVGFibGVzL3dtdy5wZGYpIChub3RlIGhlcmUgdGhhdCB3aGF0IHdlIHJlZmVyIHRvIGFzICRXJCBpcyBjYWxsZWQgJFUkIGluIHRoZSB0YWJsZSkgdG8gZGV0ZXJtaW5lIHNpZ25pZmljYW5jZS4gSWYgJFckIGlzIGxvd2VyIHRoYW4gdGhlIGNyaXRpY2FsIHZhbHVlLCBpdCBzdWdnZXN0cyB0aGF0IHRoZSBudWxsIGh5cG90aGVzaXMgc2hvdWxkIGJlIHJlamVjdGVkLiBGcm9tIHRoaXMgdGFibGUgd2Ugc2VlIHRoYXQgb3VyIGV4YW1wbGUgaGFzIHNvIGZldyB2YWx1ZXMgdGhhdCB0aGUgbnVsbCBjYW4ndCBiZSByZWxpYWJseSByZWplY3RlZC4gDQoNCkZvciBsYXJnZXIgc2FtcGxlcyAobGlrZSBvdXIgYWN0dWFsIGRhdGEsIG9yIGluIGdlbmVyYWwgYXQgbGVhc3QgMjAgcGVyIGdyb3VwKSB0aGUgJFckIHN0YXRpc3RpYyBpcyBpbnN0ZWFkIHVzZWQgdG8gY2FsY3VsYXRlIGEgJFokIHN0YXRpc3RpYyBsaWtlIHNvOg0KDQokJFogPSBcZnJhY3tXLVxtdV9XfXtcc2lnbWFfV30kJA0KDQpXaGVyZSAkXG11X1ckIGlzIHRoZSBleHBlY3RlZCAkVyQgaWYgdGhlIHR3byBncm91cHMgaGF2ZSBpZGVudGljYWwgZGlzdHJpYnV0aW9ucyBhbmQgJFxzaWdtYV9XJCBpcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uLiANCg0KVGhleSBhcmUgY2FsY3VsYXRlZCBhcyBmb2xsb3dzOg0KDQokJFxtdV9XID0gXGZyYWN7bl8xbl8yfXsyfSQkDQoNCiQkXHNpZ21hX1cgPSBcc3FydHtcZnJhY3tuXzFuXzIobl8xK25fMisxKX17MTJ9fSQkDQpUaGlzIGNhbiB0aGVuIGJlIHVzZWQgaW4gYSBbJFokIHRhYmxlXShodHRwczovL3d3dy5zaW1wbHlwc3ljaG9sb2d5Lm9yZy96LXRhYmxlLmh0bWwjOn46dGV4dD1BJTIweiUyRHRhYmxlJTJDJTIwYWxzbyUyMGNhbGxlZCxzdGFuZGFyZCUyMG5vcm1hbCUyMGRpc3RyaWJ1dGlvbiUyMChTTkQpLikgb3IgdXNpbmcgYSBbY2FsY3VsYXRvcl0oaHR0cHM6Ly93d3cuc29jc2Npc3RhdGlzdGljcy5jb20vcHZhbHVlcy9ub3JtYWxkaXN0cmlidXRpb24uYXNweCkgdG8gZGV0ZXJtaW5lIGEgJHAkLXZhbHVlLg0KDQpIZXJlIGlzIGFsc28gYSBbbGlua10oaHR0cHM6Ly95b3V0dS5iZS9CVDFGS2QxUXpqdykgdG8gYSB2aWRlbyBmb3IgYSBtb3JlIGRldGFpbGVkIGV4cGxhbmF0aW9uIGFib3V0IGNhbGN1bGF0aW5nIHRoaXMgYnkgaGFuZC4NCg0KPC9kZXRhaWxzPg0KKioqDQoNCk5vdywgdG8gaW1wbGVtZW50IHRoaXMgdGVzdCBpbiBSIHdlIGNhbiB1c2UgdGhlIGB3aWxjb3gudGVzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0YXRzYCBwYWNrYWdlLiANCg0KV2UgbmVlZCB0byBzcGVjaWZ5IHRoYXQgd2Ugd2FudCB0byBsb29rIGZvciBkaWZmZXJlbmNlcyBvZiBub3JtYWxpemVkIHBpbGwgY291bnRzIChgcG9wX0RPU0FHRWApIGJldHdlZW4gdGhlIGBydXJhbF91cmJhbmAgZ3JvdXBzLiBXZSBjYW4gZG8gc28gYnkgdXNpbmcgdGhlIGB+YCB0byBpbmRpY2F0ZSB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIG9uIHRoZSBsZWZ0IGFuZCB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgb24gdGhlIHJpZ2h0LiBXZSBhc3N1bWUgdGhhdCB0aGUgbnVtYmVyIG9mIG5vcm1hbGl6ZWQgcGlsbHMgZGVwZW5kcyBvbiB0aGUgY291bnR5IGdyb3VwLCB0aHVzIHRoZSBub3JtYWxpemVkIHBpbGwgY291bnQgaXMgdGhlIGRlcGVuZGVudCB2YXJpYWJsZS4gT3VyIGRhdGEgYXJlIG5vdCBwYWlyZWQsIHRodXMgd2UgdXNlIHRoZSBgcGFyaWVkID0gRkFMU0VgIGFyZ3VtZW50LiBXZSB3b3VsZCBoYXZlIHBhaXJlZCBkYXRhIGZvciBleGFtcGxlIGluIHRoZSBjYXNlIHdoZXJlIHdlIGhhZCBjb21wYXJhYmxlIHJ1cmFsIGFuZCB1cmJhbiBjb3VudGllcyBmb3IgZXZlcnkgc3RhdGUsIGJ1dCB0aGF0IGlzIG5vdCB0aGUgY2FzZS4gU2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtcnVyYWwtYW5kLXVyYmFuLW9iZXNpdHkvKSBmb3IgYW4gZXhhbXBsZSBvZiB0aGUgcGFpcmVkIHZlcnNpb24gb2YgdGhpcyB0ZXN0LiBXZSB3aWxsIHVzZSB0aGVgIGFsdGVybmF0aXZlID1gIGFyZ3VtZW50IHRvIHNwZWNpZnkgdGhhdCB3ZSBleHBlY3QgdGhlIGZpcnN0IG9mIHRoZSBncm91cHMgYnkgYWxwaGFiZXQgKHdoaWNoIHdvdWxkICB3b3VsZCBiZSBgUnVyYWxgIG9mIHRoZSBgcnVyYWxfdXJiYW5gIHZhcmlhYmxlKSB0byBoYXZlIGdyZWF0ZXIgdmFsdWVzIHRoYW4gdGhlIGBVcmJhbmAgZ3JvdXAgYnkgc2V0dGluZyBpdCB0byAiZ3JlYXRlciIuIFRodXMgd2Ugd2lsbCBhbHNvIHVzZSB0aGUgYGFsdGVybmF0aXZlID0gImxlc3MiYCBhcmd1bWVudCBmb3IgdGhlIGBsYXJnZV91cmJhbmAgZ3JvdXAgY29tcGFyaXNvbiBhcyB3ZSBleHBlY3QgdGhlIGZpcnN0IGdyb3VwIChhbHBoYWJldGljYWxseSkgYExhcmdlIFVyYmFuYCB0byBoYXZlIHNtYWxsZXIgdmFsdWVzIHRoYW4gdGhlIGBTbWFsbCBVcmJhbiBvciBSdXJhbGAgZ3JvdXAuDQoNCmBgYHtyfQ0KDQp3aWxjb3gudGVzdChwb3BfRE9TQUdFIH4gcnVyYWxfdXJiYW4sIGRhdGEgPSBBbm51YWwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWlyZWQgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmYuaW50ID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWF0ZSA9IFRSVUUpDQoNCg0Kd2lsY294LnRlc3QocG9wX0RPU0FHRSB+IGxhcmdlX3VyYmFuLCBkYXRhID0gQW5udWFsLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhaXJlZCA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZSA9ICJsZXNzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZi5pbnQgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlID0gVFJVRSkNCmBgYA0KDQpCb3RoIHJlc3VsdHMgaGF2ZSAkcCQgdmFsdWVzIHRoYXQgYXJlIGxlc3MgdGhhbiAwLjA1LCB3aGljaCBpcyB0aGUgdGhyZXNob2xkIGNvbW1vbmx5IHVzZWQgaW4gaHlwb3RoZXNpcyB0ZXN0aW5nIHRvIGRldGVybWluZSBpZiB0aGVyZSBpcyBlbm91Z2ggZXZpZGVuY2UgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuIA0KDQpJbiBib3RoIGNhc2VzIHRoaXMgaW5kaWNhdGVzIHRoYXQgaW5kZWVkIHRoZXJlIGlzIGVub3VnaCBldmlkZW5jZSwgYW5kIHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4gRnVydGhlcm1vcmUsIHRoZSBjb25maWRlbmNlIGludGVydmFsIGRvZXMgbm90IG92ZXJsYXAgemVybyBmb3IgZWl0aGVyIHRlc3QsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgYFJ1cmFsYCBncm91cCBpcyBsYXJnZXIgZm9yIHRoZSBmaXJzdCB0ZXN0IChhcyBib3RoIGNvbmZpZGVuY2UgaW50ZXJ2YWwgbGltaXRzIGFyZSBwb3NpdGl2ZSkgYW5kIHRoYXQgdGhlIGBMYXJnZSBSdXJhbGAgZ3JvdXAgaXMgc21hbGxlciBmb3IgdGhlIHNlY29uZCB0ZXN0IChhcyBib3RoIGNvbmZpZGVuY2UgaW50ZXJ2YWwgbGltaXRzIGFyZSBuZWdhdGl2ZSkuDQoNCkZvciB0aGUgc2Vjb25kIHRlc3QsIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiB0aGUgZGlmZmVyZW5jZSBlc3RpbWF0ZSBpcyBsYXJnZXIgdGhhbiB0aGF0IG9mIHRoZSBmaXJzdCB0ZXN0IHN1Z2dlc3RpbmcgdGhhdCB0aGVyZSBpcyBhIGxhcmdlciBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGBMYXJnZSBVcmJhbmAgYW5kIGBTbWFsbCBVcmJhbiBvciBSdXJhbGAgZ3JvdXBzIHRoYW4gdGhlIGBSdXJhbGAgYW5kIGBVcmJhbmAgZ3JvdXBzLg0KDQpJZiB3ZSBoYWQgbm90IG5vcm1hbGl6ZWQgdGhlIGRhdGEsIHdoYXQgd291bGQgb3VyIHJlc3VsdHMgbG9vayBsaWtlPw0KDQpgYGB7cn0NCg0Kd2lsY294LnRlc3QoRE9TQUdFX1VOSVQgfiBydXJhbF91cmJhbiwgZGF0YSA9IEFubnVhbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhaXJlZCA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZi5pbnQgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlID0gVFJVRSkNCg0KDQp3aWxjb3gudGVzdChET1NBR0VfVU5JVCB+IGxhcmdlX3VyYmFuLCBkYXRhID0gQW5udWFsLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhaXJlZCA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZSA9ICJsZXNzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZi5pbnQgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlID0gVFJVRSkNCg0KDQpgYGANCg0KVXNpbmcgdGhlIHJhdyBkYXRhLCB3ZSBzZWUgdGhhdCB0aGVyZSBpcyBubyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHJ1cmFsIGFuZCB1cmJhbiBjYXRlZ29yaWVzLCBhbmQgdGhlIHJ1cmFsIGRhdGEgYWN0dWFsbHkgc2hvdyBsb3dlciB2YWx1ZXMgdGhhbiB0aGUgdXJiYW4gKGJhc2VkIG9uIHRoZSBzaWduIG9mIHRoZSBlc3RpbWF0ZWQgZGlmZmVyZW5jZSkuIFNpbWlsYXJseSwgdGhlcmUgaXMgbm8gZGlmZmVyZW5jZSBiZXR3ZWVuIHNtYWxsIHVyYmFuIGFuZCBydXJhbCBjb3VudGllcyB2cy4gbGFyZ2UgdXJiYW4gY291bnRpZXMuIEluIHRoaXMgY2FzZSB0aGUgbGFyZ2UgdXJiYW4gY291bnRpZXMgKHRoZSBmaXJzdCBncm91cCBhbHBoYWJldGljYWxseSkgYWxzbyBoYWQgbGFyZ2VyIHZhbHVlcyAoYmFzZWQgb24gdGhlIHNpZ24gb2YgdGhlIGVzdGltYXRlZCBkaWZmZXJlbmNlKS4NCg0KTm90aWNlIHRoYXQgaW4gYm90aCBvZiB0aGVzZSB0ZXN0cyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBvdmVybGFwcyB6ZXJvLCB3aGlsZSB0aGlzIGlzIG5vdCB0aGUgY2FzZSBmb3IgdGhlIHByZXZpb3VzIHRlc3RzLiBXaGVuIHRoZSBjb25maWRlbmNlIGludGVydmFsIG92ZXJsYXBzIHplcm8gdGhhdCBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyB0aGUgcG9zc2liaWxpdHkgdGhhdCB0aGUgdHdvIHBvcHVsYXRpb25zIGhhdmUgaW4gZmFjdCBubyBkaWZmZXJlbmNlLg0KDQpUaGUgbWFpbiBjb25jbHVzaW9uIGhlcmUgaXMgdGhhdCB3ZSBjYW4gc2VlIHZlcnkgZGlmZmVyZW50IHJlc3VsdHMgZGVwZW5kaW5nIG9uIGhvdyB3ZSBkZWZpbmUgdGhlIGRhdGEgYW5kIGhvdyB3ZSBub3JtYWxpemUgdGhlIGRhdGEhDQoNCg0KIyAqKlN1bW1hcnkqKg0KKioqIA0KDQojIyAqKlN1bW1hcnkgUGxvdCoqDQoqKioNCg0KTm93LCBsZXQncyBjcmVhdGUgYSBwbG90IHRoYXQgc3VtbWFyaXplcyBvdXIgbWFpbiBmaW5kaW5ncy4NCg0KDQpXZSB3aWxsIHVzZSBzb21lIG9mIG91ciBwbG90cyBmcm9tIHRoZSBEYXRhIFZpc3VhbGl6YXRpb24gc2VjdGlvbiwgaW5jbHVkaW5nIGBSYXdfRGF0YWAsIGBOb3JtX0RhdGFgIGFuZCBgcGxvdF9jYXRfbm9ybWAsIGFuZCBjcmVhdGUgYSBtdWx0aS1wYW5lbCBmaWd1cmUsIHdoZXJlIGVhY2ggcGxvdCBpcyBjb25uZWN0ZWQgdG8gdGhlIG5leHQgd2l0aCBhbiBhcnJvdy4gDQoNClRvIG1ha2UgdGhlc2UgYXJyb3cgY29ubmVjdG9ycywgd2Ugd2lsbCBjcmVhdGUgYSBwbG90IHRoYXQgaXMganVzdCBhIHNpbmdsZSBhcnJvdyB1c2luZyBgZ2VvbV9zZWdtZW50KClgIGZ1bmN0aW9uIG9mIGBnZ3Bsb3QyYC4gV2UgYXJlIGRvaW5nIHRoaXMgYmVjYXVzZSB3ZSB3YW50IHRvIGNyZWF0ZSBhIGxheW91dCB3aGVyZSB0aGUgZGlmZmVyZW50IHBhbmVscyBhcmUgam9pbmVkIGJ5IGFycm93cy4NCg0KDQpDcmVhdGluZyB0aGlzIGFycm93IHJlcXVpcmVzIHRoZSBmb2xsb3dpbmcgYXJndW1lbnRzIDoNCjEpIHg6ICB4IGNvb3JkaW5hdGUgb2Ygc3RhcnRpbmcgcG9pbnQgb2YgdGhlIGFycm93DQoyKSB5OiB5IGNvb3JkaW5hdGUgb2Ygc3RhcnRpbmcgcG9pbnQgb2YgdGhlIGFycm93DQozKSB4ZW5kOiAgeCBjb29yZGluYXRlIG9mIGVuZCBwb2ludCBvZiB0aGUgYXJyb3cNCjQpIHllbmQ6IHkgY29vcmRpbmF0ZSBvZiBlbmQgcG9pbnQgaWYgdGhlIGFycm93DQoNCihOb3RlOiBZb3UgY2FuIG1ha2UgYSBzdHJhaWdodCBhcnJvdyB1c2luZyBgZ2VvbV9jdXJ2ZSgpYCB3aXRoIHRoZSBzYW1lIGFyZ3VtZW50cy4pDQoNCkFsc28sIHNpbmNlIGBnZ3Bsb3RgIHJlcXVpcmVzIGEgZGF0YSBpbnB1dCwgd2Ugd2lsbCBjcmVhdGUgYSBkdW1teSBgZGF0YS5mcmFtZWAgdG8gY3JlYXRlIHRoZSB5IGF4aXMgdmFsdWUgZm9yIHRoZSBhcnJvdy4gV2Ugd2lsbCB1c2UgdGhlIGBhZXMoKWAgZnVuY3Rpb24gdG8gZGVmaW5lIHRoZSBsZW5ndGggYW5kIGxvY2F0aW9uIG9mIHRoZSBhcnJvdy4NCg0KDQpXZSBuZWVkIHRvIHVzZSB0aGUgYGFycm93YCBhcmd1bWVudCB3aXRoIHRoZSBgYXJyb3coKWAgZnVuY3Rpb24gdG8gY3JlYXRlIGFuIGFycm93LiBUaGUgYGxpbmVlbmRgIGFuZCBgbGluZWpvaW5gIGFyZ3VtZW50cyBzcGVjaWZ5IHdoYXQgc3R5bGVzIHRvIHVzZS4gVGhlIGBzaXplKClgIGZ1bmN0aW9uIHNwZWNpZmllcyBob3cgdGhpY2sgdGhlIGFycm93IGlzIGRpc3BsYXllZC4NCg0KU2VlIFtoZXJlXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9zZWdtZW50Lmh0bWwpIGZvciBkaWZmZXJlbnQgYXJyb3cgc3R5bGUgb3B0aW9ucy4NCg0KVGhlbiB3ZSB3aWxsIHVzZSB0aGUgYHhsaW0oKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIHRvIHNwZWNpZnkgdGhlIG92ZXJhbGwgc2l6ZSBvZiB0aGUgcGxvdCByZWxhdGl2ZSB0byB0aGUgYXJyb3cuDQoNCg0KDQpgYGB7cn0NCmFycm93X2RmIDwtIGRhdGEuZnJhbWUoIHkgPSAxKQ0KYXJyb3dfZGYNCg0KYXJyb3dwbG90PC1nZ3Bsb3QoYXJyb3dfZGYsIGFlcyh4ID0gLjUsIHkgPSAxLCB4ZW5kID0gLjcsIHllbmQgPSAxKSkgKw0KICAgICAgICAgICAgICAgIGdlb21fc2VnbWVudChhcnJvdyA9IGFycm93KCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5lZW5kID0gImJ1dHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5lam9pbiA9ICJtaXRyZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMykrDQogICAgICAgICAgICAgICAgeGxpbSgwLjUsIDAuNzUpDQoNCmFycm93cGxvdA0KYGBgDQoNClRoZW4gd2Ugd2lsbCB1c2UgYHRoZW1lX3ZvaWQoKWAgcmVtb3ZlICB0aGUgYmFja2dyb3VuZC4NCg0KDQpgYGB7cn0NCmFycm93cGxvdCA8LSBhcnJvd3Bsb3QgKyAgdGhlbWVfdm9pZCgpDQphcnJvd3Bsb3QNCmBgYA0KDQpXZSBjYW4gbW92ZSB0aGUgbGVnZW5kIHRvIHRoZSBwbG90IGFyZWEgdXNpbmcgdGhlIGBsZWdlbmQuanVzdGlmaWNhdGlvbmAgYW5kIGBsZWdlbmQucG9zaXRpb25gIGFyZ3VtZW50cyBvZiB0aGUgYHRoZW1lKClgIGZ1bmN0aW9uLiBUaGUgcmVsYXRpdmUgcG9zaXRpb24gb24gdGhlIHBsb3QgYXJlYSBuZWVkcyB0byBiZSBzcGVjaWZpZWQgbGlrZSBzbyBgYyh4LHkpYC4gVGh1cyBgYygwLjcsMC4yKWAgaXMgYWJvdXQgNzAlIGFjcm9zcyB0aGUgeCBheGlzIGZyb20gcmlnaHQgdG8gbGVmdCBhbmQgYWJvdXQgMjAlIHVwIGZyb20gdGhlIHggYXhpcy4gDQoNCkZpbmFsbHksIHdlIGNhbiBidWlsZCBvdXIgdGhyZWUgcGFuZWwgcGxvdCB3aXRoIHRoZSBhcnJvdyBjb25uZWN0b3JzIGFzIGZvbGxvd3M6DQoNCmBgYHtyfQ0KDQptYWluX3Bsb3QgPC0gUmF3X0RhdGEgICsgDQogIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLjcsMC4yKSwNCiAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuNywuMikpICsNCiAgICAgICAgICAgICBhcnJvd3Bsb3QgKw0KICAgICAgICAgICAgIE5vcm1fRGF0YSArDQogIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLjcsMC4xKSwNCiAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuNywuMSkpICsNCiAgICAgICAgICAgICBhcnJvd3Bsb3QgKw0KICAgICAgICAgICAgIHBsb3RfY2F0X25vcm0gKyANCiAgbGFicyh0aXRsZSA9ICJOb3JtYWxpemVkICZcblN0cmF0aWZpZWQgRGF0YSIpICsgDQogIHBsb3RfbGF5b3V0KCBucm93ID0gMSwgd2lkdGhzID0gYyg1LDEuMyw1LDEuMyw1KSkrDQogI3RoZW1lKHRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiT3Bpb2lkIHBpbGwgc2hpcG1lbnRzIHRvIGRpZmZlcmVudCB0eXBlcyBvZiBjb3VudGllcyBpbiB0aGUgVVMiLCBzdWJ0aXRsZSA9ICJIb3cgd2Ugbm9ybWFsaXplIG9waW9pZCAob3h5Y29kb25lIGFuZCBoeWRyb2NvbmUpIHBpbGwgc2hpcG1lbnQgZGF0YSBhbmQgaG93IHdlIHN0cmF0aWZ5IGJ5IGRpZmZlcmVudCBcbnR5cGVzIG9mIGNvdW50aWVzIGNhbiB5aWVsZCB2ZXJ5IGRpZmZlcmVudCBwaWN0dXJlcyBhYm91dCBzaGlwbWVudHMiKSAmDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYWNlID0gImJvbGQiICksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSkNCg0KYGBgDQoNCk5vdyB3ZSBjYW4gc2VlIHRoZSBzdGVwcyB0aGF0IHdlIHdlbnQgdGhyb3VnaCwgZnJvbSBvdXIgcmF3IGRhdGEgdGhyb3VnaCB0byBvdXIgbm9ybWFsaXplZCBhbiBzdHJhdGlmaWVkIGRhdGEsIGFuZCBob3cgb3VyIGNob2ljZXMgaW1wYWN0ZWQgdGhlIGFwcGFyZW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNvdW50eSBjbGFzc2lmaWNhdGlvbiBhbmQgbnVtYmVyIG9mIHBpbGxzLg0KDQoNCmBgYHtyLCBlY2hvPSBGQUxTRX0NCnBuZyhmaWxlbmFtZSA9IGhlcmU6OmhlcmUoImltZyIsICJtYWlucGxvdC5wbmciKSwgDQogICAgICAgICByZXMgPSAzMDAsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIHVuaXRzID0gImluIikNCm1haW5fcGxvdA0KZGV2Lm9mZigpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFpbnBsb3QucG5nIikpDQpgYGANCg0KIyMgKipTeW5vcHNpcyoqDQoqKioNCg0KSW4gdGhpcyBjYXNlIHN0dWR5IHdlIGV2YWx1YXRlZCB0aGUgbnVtYmVyIG9mIFtveHljb2RvbmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL09waW9pZF9lcGlkZW1pY19pbl90aGVfVW5pdGVkX1N0YXRlcykgYW5kIFtoeWRyb2NvZG9uZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvT3Bpb2lkX2VwaWRlbWljX2luX3RoZV9Vbml0ZWRfU3RhdGVzKSBwaWxscyBzaGlwcGVkIHRvIHBoYXJtYWNpZXMgYW5kIHByYWN0aXRpb25lcnMgYXQgdGhlIGNvdW50eS1sZXZlbCBhcm91bmQgdGhlIFVuaXRlZCBTdGF0ZXMgKFVTKSBmcm9tIDIwMDYgdG8gMjAxNC4gVGhpcyBkYXRhIGNvbWVzIGZvcm0gdGhlIFtBdXRvbWF0ZWQgUmVwb3J0cyBhbmQgQ29uc29saWRhdGVkIE9yZGVyaW5nIFN5c3RlbSAoQVJDT1MpXShodHRwczovL3d3dy5kZWFkaXZlcnNpb24udXNkb2ouZ292L2FyY29zL3JldGFpbF9kcnVnX3N1bW1hcnkvKSBvZiB0aGUgW0RFQV0oaHR0cHM6Ly93d3cuZGVhLmdvdi8pIGFuZCB3YXMgcmVsZWFzZWQgYnkgdGhlIFtXYXNoaW5ndG9uIFBvc3RdKGh0dHBzOi8vd3d3Lndhc2hpbmd0b25wb3N0LmNvbS8pLiBXZSBjb21wYXJlZCBjb3VudGllcyBiYXNlZCBvbiB0aGUgbGV2ZWwgb2YgdXJiYW5pY2l0eSB1c2luZyB0aGUgZmFjdCB0aGF0IHByZXZpb3VzIHJlc2VhcmNoIHN1Z2dlc3RzIHRoYXQgcmVnaW9ucyBvZiB0aGUgY291bnRyeSB0aGF0IGFyZSBtb3JlIHJ1cmFsIG1heSBoYXZlIGNvbW11bml0aWVzIHRoYXQgd2VyZSBtb3JlIHZ1bG5lcmFibGUgdG8gb3Bpb2lkIGFidXNlIHRoYW4gdGhvc2Ugb2YgbGFyZ2UgdXJiYW4gYXJlYXMgZHVlIHRvIGxpa2VseSBoaWdoZXIgcHJlc2NyaXB0aW9uIHJhdGVzIGZvciBvcGlvaWQgcGlsbHMgaW4gdGhlIHRpbWUgcGVyaW9kIHRoYXQgd2UgZXZhbHVhdGVkLiANCg0KT3VyIHJlc3VsdHMgYWxzbyBzdWdnZXN0IHRoYXQgdGhpcyBpcyB0aGUgY2FzZSwgYXMgd2UgaWRlbnRpZmllZCBoaWdoZXIgbnVtYmVycyBvZiBvcGlvaWQgcGlsbCBzaGlwbWVudHMgdG8gY291bnRpZXMgdGhhdCB3ZXJlIG1vcmUgcnVyYWwgYW5kIGxlc3MgdXJiYW4uIEhvd2V2ZXIgd2UgbGVhcm5lZCB0aGF0IGhvdyByZWdpb25zIGFyZSBkZWZpbmVkIGFuZCBob3cgdGhlIGRhdGEgYXJlIG5vcm1hbGl6ZWQgY2FuIGhhdmUgYSBncmVhdCBpbXBhY3Qgb24gdGhlIHJlc3VsdHMgb2Ygc3VjaCBjb21wYXJpc29ucy4gRnVydGhlcm1vcmUsIG90aGVyIGZhY3RvcnMgbWF5IGJlIGludm9sdmVkIGluIGNyZWF0aW5nIGEgc2l0dWF0aW9uIHRoYXQgbWF5IGxlYXZlIG1lbWJlcnMgb2YgY29tbXVuaXRpZXMgbW9yZSB2dWxuZXJhYmxlIHRvIGRydWcgYWJ1c2UgYW5kIGFkZGljdGlvbiwgc3VjaCBhcyBzb2Npb2Vjb25vbWljIGZhY3RvcnMuIEZ1cnRoZXIgcmVzZWFyY2ggaXMgbmVjZXNzYXJ5IHRvIGJldHRlciB1bmRlcnN0YW5kIHdoeSB0aGUgb3Bpb2lkIGNyaXNpcyBiZWNhbWUgc3VjaCBhIHByb2JsZW0gaW4gdGhlIFVTIGFuZCBwYXJ0aWN1bGFybHkgdG8gYmV0dGVyIHVuZGVyc3RhbmQgd2hhdCBjdXJyZW50IHBvcHVsYXRpb25zIGFyZSBwYXJ0aWN1bGFybHkgdnVsbmVyYWJsZSBhbmQgd2h5LiANCg0KDQojICoqU3VnZ2VzdGVkIEhvbWV3b3JrKioNCioqKiANCg0KU3R1ZGVudHMgY291bGQgZm9jdXMgb24gdGhlIGNvdW50aWVzIG9mIGEgcGFydGljdWxhciBzdGF0ZSBhbmQgcGVyZm9ybSB0aGUgc2FtZSBhbmFseXNlcyBhbmQgdmlzdWFsaXphdGlvbnMgdG8gc2VlIGhvdyB0aGUgZGlmZmVyZW50IHR5cGVzIG9mIGNvdW50aWVzIGNvbXBhcmVkIGZvciBvcGlvaWQgcGlsbCBzaGlwbWVudHMuIFN0dWRlbnRzIGNvdWxkIGJlIGFza2VkIHRvIHdvcmsgb24gZGlmZmVyZW50IHN0YXRlcy4gRGlzY3Vzc2lvbiBjb3VsZCBmb2xsb3cgYWJvdXQgaG93IGFuZCB3aHkgdGhlIHN0YXRlcyBzaG93IGRpZmZlcmVudCByZXN1bHRzLg0KDQojICoqQWRkaXRpb25hbCBJbmZvcm1hdGlvbioqDQoqKioNCg0KTm90ZTogTW9udGhseSBkYXRhIGlzIGFsc28gYXZhaWxhYmxlIHdpdGhpbiB0aGUgYGRhdGFgIGRpcmVjdG9yeS4gVGhpcyBjb3VsZCBiZSB1c2VkIGZvciB0aW1lIHNlcmllcyBhbmFseXNpcy4gDQoNCiMjICoqSGVscGZ1bCBMaW5rcyoqDQoqKioNCg0KW1JTdHVkaW9dKGh0dHBzOi8vcnN0dWRpby5jb20vcHJvZHVjdHMvcnN0dWRpby9mZWF0dXJlcy8pe3RhcmdldD0iX2JsYW5rIn0gIA0KW0NoZWF0c2hlZXQgb24gUlN0dWlkbyBJREVdKGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL2NoZWF0c2hlZXRzL3Jhdy9tYXN0ZXIvcnN0dWRpby1pZGUucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICANCltPdGhlciBSU3R1ZGlvIGNoZWF0c2hlZXRzXShodHRwczovL3JzdHVkaW8uY29tL3Jlc291cmNlcy9jaGVhdHNoZWV0cy8pe3RhcmdldD0iX2JsYW5rIn0gICANCltSU3R1ZGlvIHByb2plY3RzXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3dvcmtmbG93LXByb2plY3RzLmh0bWwpDQoNCltUaWR5dmVyc2VdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgDQoNCiAgIA0KW1BpcGluZyBpbiBSXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICANCg0KW2FwcGxpY2F0aW9uIHByZ29yYW1taW5nIGludGVyZmFjZSAoQVBJKV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQVBJKSAgDQpbSmF2YVNjcmlwdCBPYmplY3QgTm90YXRpb24gKEpTT04pXShodHRwczovL2ZpbGVpbmZvLmNvbS9leHRlbnNpb24vanNvbiM6fjp0ZXh0PUElMjBKU09OJTIwZmlsZSUyMGlzJTIwYSx3ZWIlMjBhcHBsaWNhdGlvbiUyMGFuZCUyMGElMjBzZXJ2ZXIuKSAgDQpbTGlnaHR3ZWlnaHQgcHJvZ3JhbW1pbmcgbGFuZ3VhZ25lc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlnaHR3ZWlnaHRfcHJvZ3JhbW1pbmdfbGFuZ3VhZ2UpICAgDQoNCltUYWJsZSBmb3JtYXRzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XaWRlX2FuZF9uYXJyb3dfZGF0YSl7dGFyZ2V0PSJfYmxhbmsifQ0KDQpbYGdncGxvdDJgIHBhY2thZ2VdKGh0dHA6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcpe3RhcmdldD0iX2JsYW5rIn0gICAgDQpQbGVhc2Ugc2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtY28yLWVtaXNzaW9ucy8pICBmb3IgbW9yZSBkZXRhaWxzIG9uIHVzaW5nIGBnZ3Bsb3QyYCAgICANCltncmFtbWFyIG9mIGdyYXBoaWNzXShodHRwOi8vdml0YS5oYWQuY28ubnovcGFwZXJzL2xheWVyZWQtZ3JhbW1hci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgDQpbYGdncGxvdDJgIHRoZW1lc10oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dndGhlbWUuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgIA0KW05vcm1hbGl6YXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL05vcm1hbGl6YXRpb25fKHN0YXRpc3RpY3MpKSAgDQpbTWFubuKAk1doaXRuZXnigJNXaWxjb3hvbiAoTVdXKSB0ZXN0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9NYW5uJUUyJTgwJTkzV2hpdG5leV9VX3Rlc3QpIGFsc28ga25vd24gYXMgdGhlIFdpbGNveG9uIHJhbmsgc3VtIHRlc3Qgb3IgdGhlIHR3by1zYW1wbGUgV2lsY294IHRlc3QgICANCg0KQWxzbyBzZWUgW2hlcmVdKGh0dHBzOi8vd3d3LnN0YXQuYXVja2xhbmQuYWMubnovfndpbGQvQ2hhbmNlRW5jL0NoMTAud2lsY294b24ucGRmKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGlzIHRlc3QgYW5kIFtoZXJlXShodHRwczovL3lvdXR1LmJlL0JUMUZLZDFRemp3KSBmb3IgYSB2aWRlbyBmb3IgYSBtb3JlIGRldGFpbGVkIGV4cGxhbmF0aW9uIGFib3V0IHBlcmZvcm1pbmcgdGhpcyB0ZXN0IGJ5IGhhbmQuDQoNCg0KW091dGxpZXJzXShodHRwczovL3d3dy5pdGwubmlzdC5nb3YvZGl2ODk4L2hhbmRib29rL3ByYy9zZWN0aW9uMS9wcmMxNi5odG0pICANCltOb3JtYWwgZGlzdHJpYnV0aW9uXShodHRwOi8vb25saW5lc3RhdGJvb2suY29tLzIvaW50cm9kdWN0aW9uL2Rpc3RyaWJ1dGlvbnMuaHRtbCkNCltRLVEgcGxvdHNdKGh0dHA6Ly9vbmxpbmVzdGF0Ym9vay5jb20vMi9hZHZhbmNlZF9ncmFwaHMvcS1xX3Bsb3RzLmh0bWwpIA0KW1N0dWRlbnQncyAkdCQtdGVzdF0oaHR0cHM6Ly9zdGF0dHJlay5jb20vc3RhdGlzdGljcy9kaWN0aW9uYXJ5LmFzcHg/ZGVmaW5pdGlvbj10d28tc2FtcGxlJTIwdC10ZXN0KSAgDQpbQ29uZmlkZW5jZSBpbnRlcnZhbF0oaHR0cDovL29ubGluZXN0YXRib29rLmNvbS8yL2VzdGltYXRpb24vbWVhbi5odG1sKSAgIA0KW1NhbXBsaW5nIGRpc3RyaWJ1dGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2FtcGxpbmdfZGlzdHJpYnV0aW9uKSAgIA0KW0Jvb3RzdHJhcHBpbmddKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Jvb3RzdHJhcHBpbmdfKHN0YXRpc3RpY3MpKSAgICBbUmVzYW1wbGluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVzYW1wbGluZ18oc3RhdGlzdGljcykpICANCg0KW01vdGl2YXRpbmcgcmVwb3J0IGZvciB0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vd3d3LmNkYy5nb3YvbW13ci92b2x1bWVzLzY4L3dyL3BkZnMvbW02ODAyYTEtSC5wZGYpICANCg0KQWxzbyBzZWUgdGhpcyBbYXJ0aWNsZV0oaHR0cHM6Ly9qYW1hbmV0d29yay5jb20vam91cm5hbHMvamFtYXBzeWNoaWF0cnkvZnVsbGFydGljbGUvMTg3NDU3NSkgd2hpY2ggc3VydmV5ZWQgcGVvcGxlIHdobyB1c2UgaGVyb2luIGluIHRoZSBbU3VydmV5IG9mIEtleSBJbmZvcm1hbnRz4oCZIFBhdGllbnRzIFByb2dyYW1dKGh0dHBzOi8vd3d3LnJhZGFycy5vcmcvcmFkYXJzLXN5c3RlbS1wcm9ncmFtcy9zdXJ2ZXktb2Yta2V5LWluZm9ybWFudHMtcGF0aWVudHMuaHRtbCkgYW5kIHRoZSBbUmVzZWFyY2hlcnMgYW5kIFBhcnRpY2lwYW50cyBJbnRlcmFjdGluZyBEaXJlY3RseSAoUkFQSUQpIHByb2dyYW1dKGh0dHBzOi8vd3d3LnJhZGFycy5vcmcvcmFkYXJzLXN5c3RlbS1wcm9ncmFtcy9yZXNlYXJjaGVycy1hbmQtcGFydGljaXBhbnRzLWludGVyYWN0aW5nLWRpcmVjdGx5Lmh0bWwpLiAgDQoNCg0KVGhlIGRhdGEgZm9yIHRoaXMgY2FzZSBzdHVkeSBpcyBhdmFpbGFibGUgYXQgdGhpcyBbQVBJXShodHRwczovL2FyY29zLWFwaS5leHQubmlsZS53b3Jrcy9fX3N3YWdnZXJfXy8pLiANCg0KVGhpcyBkYXRhIGlzIGZyb20gdGhlIFtERUFdKGh0dHBzOi8vd3d3LmRlYS5nb3YvKSBbQXV0b21hdGVkIFJlcG9ydHMgYW5kIENvbnNvbGlkYXRlZCBPcmRlcmluZyBTeXN0ZW0gKEFSQ09TKV0oaHR0cHM6Ly93d3cuZGVhZGl2ZXJzaW9uLnVzZG9qLmdvdi9hcmNvcy9yZXRhaWxfZHJ1Z19zdW1tYXJ5LykgYW5kIHdhcyByZWxlYXNlZCBieSB0aGUgW1dhc2hpbmd0b24gUG9zdF0oaHR0cHM6Ly93d3cud2FzaGluZ3RvbnBvc3QuY29tLykuICAgDQoNCkEgd3JhcHBlciBwYWNrYWdlIGFib3V0IHRoaXMgQVBJIGlzIGF2YWlsYWJsZSBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL3dwaW52ZXN0aWdhdGl2ZS9hcmNvcykuDQoNCiA8dT4qKlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OioqIDwvdT4NCg0KUGFja2FnZSAgIHwgVXNlIGluIHRoaXMgY2FzZSBzdHVkeSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCi0tLS0tLS0tLS0gfC0tLS0tLS0tLS0tLS0NCltyZWFkeGxdKGh0dHBzOi8vcmVhZHhsLnRpZHl2ZXJzZS5vcmcvaW5kZXguaHRtbCkgfCB0byBpbXBvcnQgYW4gZXhjZWwgZmlsZSAgIA0KW2h0dHJdKGh0dHBzOi8vaHR0ci5yLWxpYi5vcmcvKSB8IHRvIHJldHJpZXZlIGRhdGEgZnJvbSBhbiBBUEkgICANClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKSB8IHRvIGNyZWF0ZSB0aWJibGVzICh0aGUgdGlkeXZlcnNlIHZlcnNpb24gb2YgZGF0YWZyYW1lcykgICANCltqc29ubGl0ZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2pzb25saXRlL2pzb25saXRlLnBkZikgfCB0byBwYXJzZSBqc29uIGZpbGVzICAgDQpbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBtYW5pcHVsYXRlICBjaGFyYWN0ZXIgc3RyaW5ncyB3aXRoaW4gdGhlIGRhdGEgKHN1YnNldCBhbmQgZGV0ZWN0IHBhcnRzIG9mIHN0cmluZ3MpICAgIA0KW2RwbHlyXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBmaWx0ZXIsIHN1YnNldCwgam9pbiwgYW5kIG1vZGlmeSBhbmQgc3VtbWFyaXplIHRoZSBkYXRhICAgDQpbbWFncml0dHJdKGh0dHBzOi8vbWFncml0dHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHBpcGUgc2VxdWVudGlhbCBjb21tYW5kcyAgIA0KW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBjaGFuZ2UgdGhlIHNoYXBlIG9yIGZvcm1hdCBvZiB0aWJibGVzIHRvIHdpZGUgYW5kIGxvbmcgICANCltuYW5pYXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9uYW5pYXIvdmlnbmV0dGVzL2dldHRpbmctc3RhcnRlZC13LW5hbmlhci5odG1sKSB8IHRvIGdldCBhIHNlbnNlIG9mIG1pc3NpbmcgZGF0YSAgIA0KW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gY3JlYXRlIHBsb3RzDQpbZm9ybWF0dGFibGVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9mb3JtYXR0YWJsZS9mb3JtYXR0YWJsZS5wZGYpIHwgdG8gY3JlYXRlIGEgZm9ybWF0dGVkIHRhYmxlDQpbZm9yY2F0c10oaHR0cHM6Ly9mb3JjYXRzLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byByZW9yZGVyIGZhY3RvciBmb3IgcGxvdA0KW2dncG9sXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2dwb2wvZ2dwb2wucGRmKSB8IHRvIGNyZWF0ZSBwbG90cyB0aGF0IGFyZSBoYXZlIGppdHRlciBhbmQgaGFsZiBib3hwbG90cyAgIA0KW2dnaXJhcGhdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ2lyYXBoL2dnaXJhcGgucGRmKSAgIHwgdG8gY3JlYXRlIGludGVyYWN0aXZlIHBsb3RzDQpbcGF0Y2h3b3JrXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcGF0Y2h3b3JrL3BhdGNod29yay5wZGYpIHwgdG8gY29tYmluZSBwbG90cw0KW2RpcmVjdGxhYmVsc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2RpcmVjdGxhYmVscy9kaXJlY3RsYWJlbHMucGRmKSB8IHRvIGFkZCBsYWJlbHMgZGlyZWN0bHkgb24gbGluZXMgd2l0aGluIHBsb3RzDQpbdXNkYXRhXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdXNkYXRhL3VzZGF0YS5wZGYpIHwgdG8gYWRkIGZ1bGwgc3RhdGUgbmFtZXMgdG8gcGxvdHMgYmFzZWQgb24gdGhlIHN0YXRlIGFiYnJldmlhdGlvbnMNCg0KDQojIyMjIHsuZW1waGFzaXNfYmxvY2t9DQoNCklmIHlvdSBvciBhIGxvdmVkIG9uZSBpcyBzdHJ1Z2dsaW5nIHdpdGggb3Bpb2lkIGFkZGljdGlvbiwgY29udGFjdCB0aGUgU0FNSFNB4oCZcyBOYXRpb25hbCBIZWxwbGluZSBhdCBbMS04MDAtNjYyLUhFTFAgKDQzNTcpXSh0ZWw6MS04MDAtNjYyLUhFTFAgKDQzNTcpKS4gDQoNCkl0IGlzIGEgZnJlZSwgY29uZmlkZW50aWFsLCAyNC83LCAzNjUtZGF5LWEteWVhciB0cmVhdG1lbnQgcmVmZXJyYWwgYW5kIGluZm9ybWF0aW9uIHNlcnZpY2UgKGluIEVuZ2xpc2ggYW5kIFNwYW5pc2gpIGZvciBpbmRpdmlkdWFscyBhbmQgZmFtaWxpZXMgZmFjaW5nIG1lbnRhbCBhbmQvb3Igc3Vic3RhbmNlIHVzZSBkaXNvcmRlcnMuDQoNCllvdSBjYW4gYWxzbyBjb250YWN0IHRoZSBbQWRkaWN0aW9uIENlbnRlcl0oaHR0cHM6Ly93d3cuYWRkaWN0aW9uY2VudGVyLmNvbS9kcnVncy9vdmVyZG9zZS8pIGF0IFsoODc3KTg3MS0zNTc1XSh0ZWw6ODc3ODcxLTM1NzUpIHdoaWNoIGFsc28gaGFzIGEgY29uZmlkZW50aWFsIDI0LzcgbGl2ZSBjaGF0IGF0Og0KW2h0dHBzOi8vd3d3LmFkZGljdGlvbmNlbnRlci5jb20vZHJ1Z3Mvb3ZlcmRvc2UvXShodHRwczovL3d3dy5hZGRpY3Rpb25jZW50ZXIuY29tL2RydWdzL292ZXJkb3NlLykuDQoNCkFjY29yZGluZyB0byB0aGVpciB3ZWJzaXRlOg0KDQo+UmVtZW1iZXIsIHRoYXQgYmVpbmcgYWJsZSB0byB0cmVhdCBhbiBvdmVyZG9zZSBhdCBob21lIGlzIG5vdCBhIHJlcGxhY2VtZW50IGZvciBhIGhvc3BpdGFsLiBFdmVuIGlmIHRoZSBtb21lbnQgaGFzIHBhc3NlZCwgYW5kIHRoZSB2aWN0aW0gc2VlbXMgZmluZSwgdGhlcmUgaXMgc3RpbGwgYSBjaGFuY2UgdGhhdCBzb21ldGhpbmcgaXMgZ29pbmcgb24gdGhhdCBjYW5ub3QgYmUgc2VlbiBieSB0aGUgaHVtYW4gZXllLiBUYWtpbmcgdGhlIHZpY3RpbSB0byB0aGUgaG9zcGl0YWwsIGNhbiBtZWFuIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gbGlmZSBhbmQgZGVhdGguDQoNCj4gT3ZlcmRvc2UgaXMgYSBzY2FyeSB3b3JkLiBXZSBvZnRlbiBhc3NvY2lhdGUgaXQgd2l0aCBkZWF0aCwgYnV0IHRoZSB0d28gYXJlIG5vdCBhbHdheXMgY29ubmVjdGVkLiBMaWZlIGNhbiBnbyBvbiBhZnRlciBhbiBvdmVyZG9zZSwgYnV0IG9ubHkgaWYgdGhlIHBlcnNvbiBzdWZmZXJpbmcgdW5kZXJzdGFuZHMgYW5kIGxlYXJucyBmcm9tIGl0LiBHZXR0aW5nIG9uIHRoZSByb2FkIHRvIHJlY292ZXJ5IGlzIG5vdCBlYXNpbHkgZG9uZSBidXQgaXQgaXMgYWx3YXlzIHBvc3NpYmxlLCBhbmQgdGhlIG9ubHkgZ3VhcmFudGVlZCB3YXkgdG8gbmV2ZXIgc3VmZmVyIGFuIG92ZXJkb3NlIGFnYWluLiBJZiB5b3UgZG9u4oCZdCBrbm93IHdoZXJlIHRoaXMgcGF0aCBiZWdpbnMsIG9yIG5lZWQgaGVscCBnZXR0aW5nIGhlbHAgZm9yIGEgbG92ZWQgb25lLCBwbGVhc2UgcmVhY2ggb3V0IHRvIGEgZGVkaWNhdGVkIHRyZWF0bWVudCBwcm92aWRlci4gVGhleeKAmXJlIGhlcmUsIDI0LzcsIHRvIGFuc3dlciBhbnkgcXVlc3Rpb25zIHlvdSBtYXkgaGF2ZS4gQmUgaXQgZm9yIHlvdXJzZWxmIG9yIHNvbWVvbmUgZWxzZS4NCg0KQWNjb3JkaW5nIHRvIFtoYXJtcmVkdWN0aW9uLm9yZ10oaHR0cHM6Ly9oYXJtcmVkdWN0aW9uLm9yZy9pc3N1ZXMvb3ZlcmRvc2UtcHJldmVudGlvbi9vdmVydmlldy9vdmVyZG9zZS1iYXNpY3MvcmVjb2duaXppbmctb3Bpb2lkLW92ZXJkb3NlLyksIHRoZSBmb2xsb3dpbmcgYXJlIHNpZ25zIG9mIGFuIG92ZXJkb3NlOg0KDQotIExvc3Mgb2YgY29uc2Npb3VzbmVzcw0KLVVucmVzcG9uc2l2ZSB0byBvdXRzaWRlIHN0aW11bHVzDQotIEF3YWtlLCBidXQgdW5hYmxlIHRvIHRhbGsNCi0gQnJlYXRoaW5nIGlzIHZlcnkgc2xvdyBhbmQgc2hhbGxvdywgZXJyYXRpYywgb3IgaGFzIHN0b3BwZWQNCi0gRm9yIGxpZ2h0ZXIgc2tpbm5lZCBwZW9wbGUsIHRoZSBza2luIHRvbmUgdHVybnMgYmx1aXNoIHB1cnBsZSwgZm9yIGRhcmtlciBza2lubmVkIHBlb3BsZSwgaXQgdHVybnMgZ3JheWlzaCBvciBhc2hlbi4NCi0gQ2hva2luZyBzb3VuZHMsIG9yIGEgc25vcmUtbGlrZSBndXJnbGluZyBub2lzZSAoc29tZXRpbWVzIGNhbGxlZCB0aGUg4oCcZGVhdGggcmF0dGxl4oCdKQ0KLSBWb21pdGluZw0KLSBCb2R5IGlzIHZlcnkgbGltcA0KLSBGYWNlIGlzIHZlcnkgcGFsZSBvciBjbGFtbXkNCi0gRmluZ2VybmFpbHMgYW5kIGxpcHMgdHVybiBibHVlIG9yIHB1cnBsaXNoIGJsYWNrDQotIFB1bHNlIChoZWFydGJlYXQpIGlzIHNsb3csIGVycmF0aWMsIG9yIG5vdCB0aGVyZSBhdCBhbGwNCiANCklmIHNvbWVvbmUgaXMgbWFraW5nIHVuZmFtaWxpYXIgc291bmRzIHdoaWxlIOKAnHNsZWVwaW5n4oCdIGl0IGlzIHdvcnRoIHRyeWluZyB0byB3YWtlIGhpbSBvciBoZXIgdXAuIE1hbnkgbG92ZWQgb25lcyBvZiB1c2VycyB0aGluayBhIHBlcnNvbiB3YXMgc25vcmluZywgd2hlbiBpbiBmYWN0IHRoZSBwZXJzb24gd2FzIG92ZXJkb3NpbmcuIFRoZXNlIHNpdHVhdGlvbnMgYXJlIGEgbWlzc2VkIG9wcG9ydHVuaXR5IHRvIGludGVydmVuZSBhbmQgc2F2ZSBhIGxpZmUuDQoNClNvbWV0aW1lcyBpdCBjYW4gYmUgZGlmZmljdWx0IHRvIHRlbGwgaWYgYSBwZXJzb24gaXMganVzdCB2ZXJ5IGhpZ2gsIG9yIGV4cGVyaWVuY2luZyBhbiBvdmVyZG9zZS4gIElmIHlvdeKAmXJlIGhhdmluZyBhIGhhcmQgdGltZSB0ZWxsaW5nIHRoZSBkaWZmZXJlbmNlLCBpdCBpcyBiZXN0IHRvIHRyZWF0IHRoZSBzaXR1YXRpb24gbGlrZSBhbiBvdmVyZG9zZSDigJMgaXQgY291bGQgc2F2ZSBzb21lb25l4oCZcyBsaWZlLg0KDQoqKlRoZSBtb3N0IGltcG9ydGFudCB0aGluZyBpcyB0byBhY3QgcmlnaHQgYXdheSEqKg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vbWlyby5tZWRpdW0uY29tL21heC83MDAvMSpDZGlTQXIzT29tVkZIQzZfMUVfWEt3LnBuZyIpDQpgYGANCg0KIyMjIyMgW1tzb3VyY2VdXShodHRwczovL21lZGl1bS5jb20vZHItbWluZy1rYW8vb3Bpb2lkLWFkdmVyc2UtZWZmZWN0cy1hbHRlcm5hdGl2ZXMtM2ZhZTY2YjdkMjQ3KQ0KDQojIyMjDQoNCiMjICoqU2Vzc2lvbiBJbmZvKioNCioqKg0KDQpgYGB7cn0NCnNlc3Npb25JbmZvKCkNCmBgYA0KDQoqKkVzdGltYXRlIG9mIFJNYXJrZG93biBDb21waWxhdGlvbiBUaW1lOiAqKg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCnJtYXJrZG93bjo6OnBlcmZfdGltZXJfc3RvcCgicmVuZGVyIikNCnB0cyA9IHJtYXJrZG93bjo6OnBlcmZfdGltZXJfc3VtbWFyeSgpDQpjYXQoIkFib3V0Iiwgcm91bmQocHRzJHRpbWVbMV0vMTAwMCArIDUpLCAiLSIsIHJvdW5kKHB0cyR0aW1lWzFdLzEwMDAgKyAxNSksInNlY29uZHMiKQ0KYGBgDQoNClRoaXMgY29tcGlsYXRpb24gdGltZSB3YXMgbWVhc3VyZWQgb24gYSBQQyBtYWNoaW5lIG9wZXJhdGluZyBvbiBXaW5kb3dzIDEwLiBUaGlzIHJhbmdlIHNob3VsZCBvbmx5IGJlIHVzZWQgYXMgYW4gZXN0aW1hdGUgYXMgY29tcGlsYXRpb24gdGltZSB3aWxsIHZhcnkgd2l0aCBkaWZmZXJlbnQgbWFjaGluZXMgYW5kIG9wZXJhdGluZyBzeXN0ZW1zLg0KDQojIyAqKkFja25vd2xlZGdtZW50cyoqDQoqKioNCg0KV2Ugd291bGQgbGlrZSB0byBhY2tub3dsZWRnZSBbQnJlbmRhbiBTYWxvbmVyXShodHRwczovL3d3dy5qaHNwaC5lZHUvZmFjdWx0eS9kaXJlY3RvcnkvcHJvZmlsZS8yOTI5L2JyZW5kYW4tc2Fsb25lcikgZm9yIGFzc2lzdGluZyBpbiBmcmFtaW5nIHRoZSBtYWpvciBkaXJlY3Rpb24gb2YgdGhlIGNhc2Ugc3R1ZHkuDQoNCldlIHdvdWxkIGxpa2UgdG8gYWNrbm93bGVkZ2UgW01pY2hhZWwgQnJlc2hvY2tdKGh0dHBzOi8vbWJyZXNob2NrLmdpdGh1Yi5pby8pIGZvciBoaXMgY29udHJpYnV0aW9ucyB0byB0aGlzIGNhc2Ugc3R1ZHkgYW5kIGRldmVsb3BpbmcgdGhlIGBPQ1NkYXRhYCBwYWNrYWdlLiANCg0KV2Ugd291bGQgYWxzbyBsaWtlIHRvIGFja25vd2xlZGdlIHRoZSBbQmxvb21iZXJnIEFtZXJpY2FuIEhlYWx0aCBJbml0aWF0aXZlXShodHRwczovL2FtZXJpY2FuaGVhbHRoLmpodS5lZHUvKSBmb3IgZnVuZGluZyB0aGlzIHdvcmsuIA0KDQoNCjxzY3JpcHQgdHlwZT0ndGV4dC9qYXZhc2NyaXB0JyBpZD0nY2x1c3RybWFwcycgc3JjPScvL2Nkbi5jbHVzdHJtYXBzLmNvbS9tYXBfdjIuanM/Y2w9MDgwODA4Jnc9MzAwJnQ9dHQmZD1HOWU1dWFHTHZfb21DZ01ZM3RWYU5aNWRDNDh6cmlmdFh1ajRVNXZ4Q0xjJmNvPWZmZmZmZiZjbW89M2FjYzNhJmNtbj1mZjUzNTMmY3Q9ODA4MDgwJz48L3NjcmlwdD4NCg==