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 Ontiveros, Michael and Jager, Leah and Taub, Margaret and Hicks, Stephanie C. (2020). https://github.com/opencasestudies/ocs-bp-youth-mental-health. Mental Health of American Youth.

Please be advised that the material in this case study describes and discusses rates of suicide, as well as rates and symptoms of depression.

According to the National Institute of Mental Health (NIMH):

If you are in crisis and need help, call this toll-free number for the National Suicide Prevention Lifeline (NSPL), available 24 hours a day, every day: 1-800-273-TALK (8255). The service is available to everyone. The deaf and hard of hearing can contact the Lifeline via TTY at 1-800-799-4889. All calls are confidential. You can also visit the Lifeline’s website at www.suicidepreventionlifeline.org.

The Crisis Text Line is another free, confidential resource available 24 hours a day, seven days a week. Text “HOME” to 741741 and a trained crisis counselor will respond to you with support and information over text message. Visit www.crisistextline.org.

Also see here for more information about how to recognize and help youths experiencing symptoms of depression.

To access the GitHub repository to obtain the data for this case study see here: https://github.com//opencasestudies/ocs-bp-youth-mental-health.

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
91 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 8 13
FORCAST 10 15
SMOG 11 16

Please help us by filling out our survey.

Motivation


Rates of depression appear to have been increasing among American youths since around 2010 according to a recent report. A recent study also shows that youths appear to be seeking more care from mental health services.

This case study will explore how rates of major depressive episodes have changed since the early 2000s and across different youth subgroups (age, gender, ethnicity). We also will explore how rates of treatment for depression of youths have changed over time.

Photo by K. Mitch Hodge on Unsplash

The major symptoms of a major depressive episode include:

Sleep disorder (increased or decreased)
Interest deficit (anhedonia)
Guilt (worthlessness, hopelessness, regret)
Energy deficit
Concentration deficit
Appetite disorder (increased or decreased)
Psychomotor retardation or agitation
Suicidality

[source]

Click here to see the diagnostic requirements for a major depressive episode (MSE) according to the DSM 5.

A. Five or more of the following symptoms have been present and documented during the same two-week period and represent a change from previous functioning; at least one of the symptoms is either (1) depressed mood or (2) loss of interest or pleasure.

Note: Do not include symptoms that are clearly attributable to another medical condition.

  1. Depressed mood most of the day, nearly every day, as indicated by either subjective report (e.g., feels sad, empty, hopeless) or observation made by others (e.g., appears tearful)

  2. Markedly diminished interest or pleasure in all, or almost all, activities most of the day, nearly every day (as indicated by either subjective account or observation)

  3. Significant weight loss when not dieting or weight gain (e.g., a change of more than 5% of body weight in a month), or decrease or increase in appetite nearly every day

  4. Insomnia or hypersomnia nearly every day

  5. Psychomotor agitation or retardation nearly every day (observable by others, not merely subjective feelings of restlessness or being slowed down)

  6. Fatigue or loss of energy nearly every day

  7. Feelings of worthlessness or excessive or inappropriate guilt (which may be delusional) nearly every day (not merely self-reproach or guilt about being sick)

  8. Diminished ability to think or concentrate, or indecisiveness, nearly every day (either by subjective account or as observed by others)

  9. Recurrent thoughts of death (not just fear of dying), recurrent suicidal ideation without a specific plan, or a suicide attempt or a specific plan for committing suicide

B. The symptoms do not meet criteria for a mixed episode.

C. The episode is not attributable to the physiological effects of a substance or to another medical condition.

Note: Criteria A-C represent a major depressive episode.

Note: Responses to a significant loss (e.g., bereavement, financial ruin, losses from a natural disaster, a serious medical illness or disability) may include feelings of intense sadness, rumination about the loss, insomnia, poor appetite and weight loss noted in Criterion A, which may resemble a depressive episode. Although such symptoms may be understandable or considered appropriate to the loss, the presence of a major depressive episode in addition to the normal response to a significant loss should also be carefully considered. This decision inevitably requires the exercise of clinical judgment based on the individual’s history of and the cultural norms for the expression of distress in the context of loss.

D. The occurrence of the major depressive episode is not better explained by schizoaffective disorder, schizophrenia, schizophreniform disorder, delusional disorder, or other specified and unspecified schizophrenia spectrum and other psychotic disorders.

E. There has never been a manic episode or a hypomanic episode.

Note: This exclusion does not apply if all of the manic-like or hypomanic-like episodes are substance-induced or are attributable to the physiological effects of another medical condition.

[source]


This case study is motivated by the following two articles:

Twenge JM, Cooper AB, Joiner TE, Duffy ME, Binau SG. Age, period, and cohort trends in mood disorder indicators and suicide-related outcomes in a nationally representative dataset, 2005-2017. J Abnorm Psychol.128,3 (2019):185-199. doi:10.1037/abn0000410

Olfson, M., Blanco, C., Wang, S., Laje, G. & Correll, C. U. National Trends in the Mental Health Care of Children, Adolescents, and Adults by Office-Based Physicians. JAMA Psychiatry. 71, 81 (2014):81-90. doi: 10.1001/jamapsychiatry.2013.3074.

The main findings of the first article are:

Rates of major depressive episode in the last year increased 52% 2005–2017 (from 8.7% to 13.2%) among adolescents aged 12 to 17 and 63% 2009–2017 (from 8.1% to 13.2%) among young adults 18–25.

Serious psychological distress in the last month and suicide-related outcomes (suicidal ideation, plans, attempts, and deaths by suicide) in the last year also increased among young adults 18–25 from 2008–2017 (with a 71% increase in serious psychological distress), with less consistent and weaker increases among adults ages 26 and over.

Cultural trends contributing to an increase in mood disorders and suicidal thoughts and behaviors since the mid-2000s, including the rise of electronic communication and digital media and declines in sleep duration, may have had a larger impact on younger people, creating a cohort effect.

While the main findings of the second article are:

Compared with adult mental health care, the mental health care of young people has increased more rapidly…

This means that the number of youths receiving mental health care has increased faster than the number of adults receiving mental health care.

Between 1995-1998 and 2007-2010, visits resulting in mental disorder diagnoses … increased significantly faster for youths (from 7.78 to 15.30 visits) than for adults (from 23.23 to 28.48 visits) (interaction: P < .001).

Psychiatrist visits also increased significantly faster for youths (from 2.86 to 5.71 visits).

Summary: While depression appears to be on the rise for youths, youths also appear to be seeking more mental health care.

In this case study, we will be using data from the National Survey on Drug Use and Health (NSDUH) related to treatment and major depressive episode (MDE) rate to explore how trends in mental health have changed over time and how different groups compare.

This data was also used in the first referenced article.

Main Questions


Our main questions:

  1. How have depression rates in American youth changed since 2004, according to the NSDUH data? How have rates differed between different youth subgroups (age, gender, ethnicity)?
  2. Do mental health services appear to be reaching more youths? Again, how have rates differed between different youth subgroups (age, gender, ethnicity)?

Learning Objectives


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

Data Science Learning Objectives:

  1. Scrape data directly from a website (rvest)
  2. Subset and filter data (dplyr)
  3. Write functions to wrangle data repetitively
  4. Work with character strings (stringr)
  5. Reshape data into different formats (tidyr)
  6. Data visualizations (ggplot2) with labels (directlabels) and facets for different groups
  7. Combine multiple plots (cowplot)
  8. Optional: Create an animated gif (magick)

Statistical Learning Objectives:

  1. Discuss the impact of self-reporting bias on survey responses
  2. Define and create a contingency table
  3. Implementation of a chi-squared test for independence
  4. Interpretation of a chi-squared test for independence

In this case study, we will especially focus on using packages and functions from the Tidyverse, such as rvest. 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.


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

library(here)
library(rvest)
library(dplyr)
library(magrittr)
library(stringr)
library(tidyr)
library(tibble)
library(purrr)
library(ggplot2)
library(directlabels)
library(scales)
library(forcats)
library(ggthemes)
library(rstatix)
library(cowplot)
library(OCSdata)

Packages used in this case study:

Package Use in this case study
here to easily load and save data
rvest to scrape web pages
dplyr to subset and filter the data for specific groups, to replace specific values with NA, rename variables, and perform functions on multiple variables
magrittr to use and reassign data objects using the %<>%pipe operator
stringr to manipulate strings
tidyr to change the shape or format of tibbles to wide and long
tibble to create tibbles and convert values of a column to row names
purrr to apply a function to each column of a tibble or each tibble in a list
ggplot2 to create plots
directlabels to add labels directly to lines in plots
scales to get the current linetype options
forcats to reorder factor for plot
ggthemes to create a plot to see what the different linetypes look like
rstatix to preform proportion test
cowplot to combine plots together
OCSdata to access and download OCS data files

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


To motivate the examination of the mental health of American youths, we begin by exploring the rate of suicide in the United States (US). According to the CDC the rate of suicide has increased for both genders.

[source]

While suicide does appear to be increasing among youths it also appears to be increasing among most age groups in the US over the past decade and a half for both females and males:

[source]

According to the CDC:

Since 2008, suicide has ranked as the 10th leading cause of death for all ages in the United States.

[source]

Furthermore, according to the CDC:

In 2016, suicide became the second leading cause of death among youths.

So although suicide is on the rise for most age groups, suicide is one of the top two contributors to death for youths.

Thus, this warrants further examination of the mental health of American youths.

[source]

Historically, suicide rates were much higher before 1950, however, we are seeing an increase in the last 20 years.

[source]

Besides the US, other countries are also experiencing increased rates of depression in youths.

See this report from the World Health Organization (WHO) about rates of depression in other countries.

See here for an interesting discussion about what may be causing increased depression rates.

Limitations


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

  1. The data that we will use come from a survey and are therefore values from a sample that estimate that of the true population. In our statistical analysis we use these sample values as if they are population estimates (because this is all we have access to). Thus, our results are not necessarily indicative of population differences.

  2. Furthermore, the sampling mechanism utilized for the survey can introduce selection bias in cases where the the sampling methods do not produce a representative sample.

  3. Data are collected from human participants; this presents the potential for information bias, as there is the potential that participants in the sampling frame may for a variety of reasons report inaccurate information.

  4. Data about certain group intersections (meaning for example individuals of a particular gender and ethnicity) or particular groups in general such as specific ethnicities or gender or sexual identity groups such as LGBTQIA+ (lesbian/gay/bisexual/transgender/queer and questioning) or non-binary gender populations is unfortunately not available in the data used in this analysis and in most research about this topic.

Note: While gender and sex are not actually binary, the data used in this analysis unfortunately only contains information for groups of individuals who self-reported as male or female. We also acknowledge that unfortunately not all ethnicities or group intersections are represented in the data either. More research should be devoted to collecting data about the mental health of these groups.

What are the data?


We will be using data from the National Survey on Drug Use and Health (NSDUH) which is directed by the Substance Abuse and Mental Health Services Administration (SAMHSA), an agency in the U.S. Department of Health and Human Services (DHHS).

This survey started in 1971 and is conducted annually in all 50 states and the District of Columbia. Approximately 70,000 people (ages 12 and up) are interviewed each year about health-related issues. Only civilian, non-institutionalized individuals are included. Households are randomly selected and then a professional interviewer visits the addresses and asks one or two of the residents to interview. The interviewer brings a laptop with them that the participants use to fill out the survey, which typically takes an hour to complete. If a participant chooses to participate they receive $30 in cash. All collected information is confidential and is used for disease surveillance and to guide public policy particularly focused on drug and alcohol use as well as mental health. See here for more details about the survey.

The data are made available publicly online on the Substance Abuse & Mental Health Data Archive.

On the website with the survey data, you can see that the results are displayed in many tables. Importantly, there is no obvious way to download the data directly from this particular website.

If you click on the TOC button on the far left upper corner, you will be directed to another website, where a large pdf document containing all of the results can be downloaded.

We are interested in investigating how depression rates have changed and how youths are interacting with mental health services. Thus, the following tables are of interest to us:

Table Details
Table 11.1A Settings Where Mental Health Services Were Received in Past Year among Persons Aged 12 to 17: Numbers in Thousands, 2002-2018
Table 11.1B Settings Where Mental Health Services Were Received in Past Year among Persons Aged 12 to 17: Percentages, 2002-2018
Table 11.2A Major Depressive Episode in Past Year among Persons Aged 12 to 17, by Demographic Characteristics: Numbers in Thousands, 2004-2018
Table 11.2B Major Depressive Episode in Past Year among Persons Aged 12 to 17, by Demographic Characteristics: Percentages, 2004-2018
Table 11.3A Major Depressive Episode with Severe Impairment in Past Year among Persons Aged 12 to 17, by Demographic Characteristics: Numbers in Thousands, 2006-2018
Table 11.3B Major Depressive Episode with Severe Impairment in Past Year among Persons Aged 12 to 17, by Demographic Characteristics: Percentages, 2006-2018
Table 11.4A Receipt of Treatment for Depression in Past Year among Persons Aged 12 to 17 with Major Depressive Episode in Past Year, by Demographic Characteristics: Numbers in Thousands, 2004-2018
Table 11.4B Receipt of Treatment for Depression in Past Year among Persons Aged 12 to 17 with Major Depressive Episode in Past Year, by Demographic Characteristics: Percentages, 2004-2018

Our goal is to bring these data into R so we can explore them.


Click here for the NSDUH defines a major depressive episode (MDE)

According to the NSDUH 2018 report

Respondents were defined as having had an MDE in the past 12 months if they had at least one period of 2 weeks or longer in the past year when they experienced a depressed mood or loss of interest or pleasure in daily activities, accompanied by problems with sleeping, eating, energy, concentration, or self-worth. The MDE questions are based on diagnostic criteria from DSM-5. Some of the wordings of the depression questions for adolescents aged 12 to 17 and adults aged 18 or older differed slightly to make the questions more developmentally appropriate for adolescents.

Adolescents were defined as having an MDE with severe impairment if their depression caused severe problems with their ability to do chores at home, do well at work or school, get along with their family, or have a social life.


Data Import


Data are often made available online. Sometimes, the data we are interested in is made available for download on a web page as a delimited text file or an excel file. However, sometimes data are not made available in this manner, such as the NSDUH survey data.

How do we proceed in this scenario?

We can manually copy each cell of data; however, this process is often inefficient, subject to error, and not reproducible. Say we wanted to run an analysis next year on the next years data and it happens to be formatted in the same way.

Alternatively, we could use R to scrape the data from the web!

Formally, web scraping is the process of extracting data from a webpage. Let’s learn how to do this for our case study.

Basic steps of web scraping


There are two main steps to web scraping:

  1. Identify location of data on the webpage that will be scraped.

  2. Save the webpage element to an R object.

We accomplish STEP 1 with our web browser.

We accomplish STEP 2 in the R programming environment.

The location of the data on the webpage that will be scraped can be identified using a language called XPath, which is short for XML Path Language. It is used to identify pieces (in this case called nodes) of a document written in the XML language. XML which is short for Extensible Markup Language is frequently used for documents on the internet, similar to HTML. One of the major differences between these two is that HTML does not provide structural information, while XML does. This structural information can be used to parse documents so that we can scrape only the data that we are interested in from a website.

Additional resources for web scraping:

The rvest package


In this case study, we will scrape data from the tables on the NSDUH survey website.

Note that these data are available in a large PDF with all the results by year if you wish to use the data from this particular source.

One option to import the data would be to import the PDF. However it is not easy to find this PDF and it would be difficult and time consuming to find our tables of interest and to extract our data of interest from the pdf. However, if one wanted to do this, say if the tables were not available online, they could use the pdftools package. See this other case study and this other case study for two methods to work with PDFs.

Another option could be to copy and paste the data from the website to another file that we would also need to import. But this would not be as efficient or reproducible and might result in errors.

Alternatively, we will use the rvest package to scrape the data directly from the tables on the website.

Assuming the data next year would be displayed in a similar manner, this could allow us to simply modify our code based on the url for the data next year to run the same analysis on the data easily.

However, it is important to keep in mind that one downside of scraping the data directly from the web, is that the website could change - this can be a good thing if the website adds additional data and keeps the same formatting. This would allow us to get additional data very easily. However, if the website changes formatting then this would require that we update our code.

Scraping tables into R


The two web scraping steps for these tables can be broken down even further:

  1. Identify location of data that will be scraped

    • right-click to inspect element (webpage)
    • hover pointer over components of element (webpage) until the data has been found
    • copy XPath of data sought
  2. Save webpage element to an object in R

    • import html code for the webpage
    • extract pieces of HTML documents (webpage) using XPath
    • parse the extracted data into a data frame

Below is a animated overview of the process.

Click here if you want to see how this animation was made!

First the images need to be imported into R using the image_read function of the magick package.

step1 <- magick::image_read(here::here("img", "webpage_screenshot.png"))
step2 <- image_read(here::here("img", "table_screenshot_inspect.png"))
step3 <- image_read(here::here("img", "table_screenshot_inspect_table.png"))
step4 <- image_read(here::here("img", "table_screenshot_inspect_table_xpath.png"))
step5 <- image_read(here::here("img", "table_screenshot_xpath_copy_r.png"))
step5_zoom <- image_read(here::here("img", "table_screenshot_xpath_copy_r_zoom.png"))

The last image is smaller than the others, to get a sense of the size we can use the image_info() function of the magick package.

step5

step5_zoom

image_info(step5)
# A tibble: 1 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG     1440    900 sRGB       TRUE    306274 72x72  
image_info(step5_zoom)
# A tibble: 1 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG      869    231 sRGB       TRUE     57559 72x72  

First let’s re-size the second image to make it a bit larger using the image_resize() function of the magick package. We will re-size the width to be the same as the previous image width and keep the aspect ratio for the height by using “1440x”. If we wanted to just do the same for height we would use “x900”.

step5_zoom <- image_resize(step5_zoom,  "1440x")
step5_zoom

We can add a white boarder around the last image to make the size more similar height-wise using the image_border() function of the magick package. There are many image modification functions in the magick package! See here to learn more.

step5_zoom <- image_border(step5_zoom, "white", "2x334")
step5_zoom

Looks good!

Now we will make the sequence of images for our animation. We also want to indicate how long we want to spend on each relative to the others. We want to linger on the last image so we include it two times.

img <- c(step1,
         step2,
         step3,
         step4,
         step5,
         step5_zoom,
         step5_zoom)

Now, we are ready to create our gif! But first we want to modify our images a bit more.

First we want to make all images within img the exact same size using the image_resize() function. To do this for all images we can use the ! at the end, which ignoring aspect ratios.

image_info(img)
# A tibble: 7 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG     1439    855 sRGB       TRUE    189980 72x72  
2 PNG     1436    857 sRGB       TRUE    232355 72x72  
3 PNG     1439    857 sRGB       TRUE    315277 72x72  
4 PNG     1439    856 sRGB       TRUE    346714 72x72  
5 PNG     1440    900 sRGB       TRUE    306274 72x72  
6 PNG     1444   1051 sRGB       TRUE         0 72x72  
7 PNG     1444   1051 sRGB       TRUE         0 72x72  
img <-image_resize(img, '1440x900!')
image_info(img)
# A tibble: 7 x 7
  format width height colorspace matte filesize density
  <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
1 PNG     1440    900 sRGB       TRUE         0 72x72  
2 PNG     1440    900 sRGB       TRUE         0 72x72  
3 PNG     1440    900 sRGB       TRUE         0 72x72  
4 PNG     1440    900 sRGB       TRUE         0 72x72  
5 PNG     1440    900 sRGB       TRUE         0 72x72  
6 PNG     1440    900 sRGB       TRUE         0 72x72  
7 PNG     1440    900 sRGB       TRUE         0 72x72  

We also want to morph or blend each image into the next so that there appears to be a smooth transition. We can also specify how many frames to include in the morph, to speed up or slow down the blend from one image to another. We will specify that 4 frames should be used in the morph by using the image_morph() function.

To make the final animation we use the image_animate() function Importantly, we want to delay changing from one image to another about 70* 1/100 seconds to give people a chance to see what is happening. So we can use the delay argument. The optimize argument of this function requires that all images are the same size (luckily we did this!) and it causes R to only store the differences between frames.

educational_gif <- 
  image_morph(img, frames = 4) %>%
  image_animate(delay = 70,
                optimize = TRUE)

Now to save our gif we can use the image_write() function of the magick package and the here() function of the here package to easily save it in a directory called img within the directory that contains our .Rproj file. We will name the file educational.gif.

image_write(educational_gif,
      here::here("img", "educational.gif"))


Now let’s go through each step together:

1) Identify location of data that will be scraped

First, let’s go to the web page with all the tables we are interested in scraping

Once on the webpage, there are not any visible options to download the data.

Right-click and select “Inspect”.

A window opens.

This window allows us to glance at the internal mechanics of the webpage. To scrape the data from the webpage, we need to first learn a little bit about the components that make it the web page it is.

Hovering our mouse over the elements of the webpage highlights the respective section of the webpage it represents. By hovering over several elements—and clicking on the elements on the right side of the screen—we can identify the element that contains the data we are looking for. Another option for identifying XPaths is to use the selectorgadget tool.

Right click on the element and copy the XPath. We will need this XPath for the next step.

Now we can return to the R programming environment.


2) Save webpage element to an object in R

For the first table we want to scrape, the XPath is /html/body/div[4]/div[1]/table. We use this XPath with functions from the rvest package to scrape the data from this table.

Let’s explore this step in greater detail:

We need to:

  • import html code for the webpage
  • extract pieces (table) out of HTML documents (webpage) using XPath
  • parse the html table into a data frame

To do this:

  • We import the html code using the read_html() function of the rvest package
  • We extract specific components of the webpage using the html_nodes() function of the rvest package
  • We convert this html table into a dataframe using the html_table()function of the rvest package

The rvest package provides wrappers for the xml2 and httr packages, thus we can just install and load the rvest package and it will install and load dependency packages like xml2 and httr and allow us to use functions from both of these packages.

In fact, when we load rvest the first time we see:

In this case, we are scraping Table 11.1A from the website. First, we assign the URL to a character string to use within the read_html() function in the xml2 package.

NSDUH_url <- "https://www.samhsa.gov/data/sites/default/files/cbhsq-reports/NSDUHDetailedTabs2018R2/NSDUHDetTabsSect11pe2018.htm"

We have also saved the data as it was on this website to our own website to ensure that our case study will remain stable despite possible changes to this website.

Thus we will proceed with this URL:

NSDUH_url <- "https://www.opencasestudies.org/ocs-bp-youth-mental-health/data/raw/samhsa.gov_2020_tables.htm"

One could also directly use the URL but this is less convenient for piping.


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.


Then, the read_html() function allows us to save the html document for the webpage inside R.

webpage <- NSDUH_url %>%
  xml2::read_html() 
webpage
{html_document}
<html lang="en">
[1] <head>\n<!-- Google Tag Manager --><script>(function(w,d,s,l,i){w[l]=w[l] ...
[2] <body>\r\n<!-- Google Tag Manager (noscript) -->\r\n<noscript><iframe src ...

Then, we use the html_nodes() function of the rvest package to select just the Table 11.1A element of the webpage.

See this tutorial (and the answers in case you get stuck) on CSS selectors to understand more about how this function works to use the xpath to select the elements of interest from the webpage.

webpage_element <- webpage %>%
  rvest::html_nodes(xpath='/html/body/div[4]/div[1]/table')
webpage_element 
{xml_nodeset (1)}
[1] <table class="rti">\n<caption>Table 11.1A – Settings Where Mental Health  ...

Finally, the html_table() function of the rvest package parses the html object into a data frame. We can use the glimpse() function of the dplyr package to take a look at the data. This function shows data frames sideways with the columns listed on the far left.

table11.1a <- webpage_element %>%
  rvest::html_table()

print(table11.1a, max = 2)
[[1]]
# A tibble: 21 x 18
   `Setting Where Ment~` `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009`
   <chr>                 <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
 1 "SPECIALTY MENTAL HE~ 2,898a 3,065a 3,348a 3,362a 3,255a 3,104a 3,129a 2,925a
 2 "Outpatient"          2,662a 2,795a 3,015a 3,048a 2,931a 2,787a 2,837a 2,650a
 3 "Private Therapist, ~ 2,254a 2,347a 2,523a 2,573a 2,416a 2,365a 2,408a 2,296a
 4 "Mental Health Clini~ 611a   635a   716a   657a   587a   583a   567a   537a  
 5 "Partial Day Hospita~ 440    425    439    449    471    416    374a   340a  
 6 "In-Home Therapist, ~ 693a   656a   762a   731a   719a   707a   716a   657a  
 7 "Inpatient or Reside~ 509a   542a   629    619    596    581a   539a   524a  
 8 "Hospital"            422a   467a   515    529    516    511a   469a   440a  
 9 "Residential Treatme~ 224a   233a   299    229a   225a   199a   198a   213a  
10 "NONSPECIALTY MENTAL~ nc     nc     nc     nc     nc     nc     nc     3,430a
# ... with 11 more rows, and 9 more variables: `2010` <chr>, `2011` <chr>,
#   `2012` <chr>, `2013` <chr>, `2014` <chr>, `2015` <chr>, `2016` <chr>,
#   `2017` <chr>, `2018` <chr>
glimpse(table11.1a)
List of 1
 $ : tibble [21 x 18] (S3: tbl_df/tbl/data.frame)
  ..$ Setting Where Mental Health ServiceWas Received: chr [1:21] "SPECIALTY MENTAL HEALTH SERVICE1" "Outpatient" "Private Therapist, Psychologist,\r\n   Psychiatrist, Social Worker, or\r\n   Counselor" "Mental Health Clinic or Center" ...
  ..$ 2002                                           : chr [1:21] "2,898a" "2,662a" "2,254a" "611a" ...
  ..$ 2003                                           : chr [1:21] "3,065a" "2,795a" "2,347a" "635a" ...
  ..$ 2004                                           : chr [1:21] "3,348a" "3,015a" "2,523a" "716a" ...
  ..$ 2005                                           : chr [1:21] "3,362a" "3,048a" "2,573a" "657a" ...
  ..$ 2006                                           : chr [1:21] "3,255a" "2,931a" "2,416a" "587a" ...
  ..$ 2007                                           : chr [1:21] "3,104a" "2,787a" "2,365a" "583a" ...
  ..$ 2008                                           : chr [1:21] "3,129a" "2,837a" "2,408a" "567a" ...
  ..$ 2009                                           : chr [1:21] "2,925a" "2,650a" "2,296a" "537a" ...
  ..$ 2010                                           : chr [1:21] "2,920a" "2,635a" "2,265a" "547a" ...
  ..$ 2011                                           : chr [1:21] "3,101a" "2,842a" "2,409a" "547a" ...
  ..$ 2012                                           : chr [1:21] "3,118a" "2,846a" "2,427a" "610a" ...
  ..$ 2013                                           : chr [1:21] "3,341a" "3,064a" "2,572a" "731a" ...
  ..$ 2014                                           : chr [1:21] "3,369a" "3,110a" "2,698a" "760a" ...
  ..$ 2015                                           : chr [1:21] "3,253a" "2,958a" "2,532a" "792a" ...
  ..$ 2016                                           : chr [1:21] "3,598a" "3,239a" "2,819a" "929" ...
  ..$ 2017                                           : chr [1:21] "3,646a" "3,328" "2,908" "995" ...
  ..$ 2018                                           : chr [1:21] "3,901" "3,547" "3,080" "977" ...

We can see that the output is a list with one element, to extract the data from the list we will use brackets [[]] to select the first element of the list.

table11.1a <- table11.1a[[1]]

Putting this all of this together we can do the entire process like this with our pipe operator %>%.

table11.1a <- NSDUH_url %>%
  xml2::read_html() %>%
  rvest::html_nodes(xpath = '/html/body/div[4]/div[1]/table') %>%
  rvest::html_table()
table11.1a <- table11.1a[[1]]

Now, we need to repeat the above process for the other tables we are interested in.

Writing a function to scrape multiple tables


One option is to copy and paste code we wrote above. However, this is not very efficient and is error prone. Alternatively, we can create an R function to accomplish this succinctly. Functions allow us to perform the same process on multiple data inputs. See this other case study for more details about how to write a function.

In general, the process of writing functions involves first specifying an input that is used within the function to create an output. In this case, XPATH will be used as an “input argument” to the function, which will be replaced by an actual XPath and then used in the subsequent steps to scrape the data from each table that an XPath is supplied for.

We will call this function scraper.

scraper <- function(XPATH){
  NSDUH_url <- "https://www.opencasestudies.org/ocs-bp-youth-mental-health/data/raw/samhsa.gov_2020_tables.htm"
  table <- NSDUH_url %>%
    read_html() %>%
    html_nodes(xpath = XPATH) %>%
    html_table()
  output <- table[[1]]
  output
}

Now we can apply the function we created to each of the XPaths for each of the tables on the website that we would like to use in our data analysis.

table11.1b <- scraper(XPATH = "/html/body/div[4]/div[2]/table")
table11.2a <- scraper(XPATH = '/html/body/div[4]/div[3]/table')
table11.2b <- scraper(XPATH = '/html/body/div[4]/div[4]/table')
table11.3a <- scraper(XPATH = '/html/body/div[4]/div[5]/table')
table11.3b <- scraper(XPATH = '/html/body/div[4]/div[6]/table')
table11.4a <- scraper(XPATH = '/html/body/div[4]/div[7]/table')
table11.4b <- scraper(XPATH = '/html/body/div[4]/div[8]/table')

Great! We have successfully scraped the data from the web into R!

Next, we need to wrangle the data.

We will save the imported data now. To do this we will use the base save() function. We will save it within a directory called “imported” of our “data” directory. Make sure you make this directory first.

save(table11.1a, table11.1b, table11.2a, table11.2b, 
     table11.3a, table11.3b, table11.4a, table11.4b, 
     file = here::here("data", "imported", "imported_data.rda"))

Data Wrangling


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

load(file = here::here("data", "imported", "imported_data.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 using the following code:

imported_data("ocs-bp-youth-mental-health", outpath = getwd())
load(here::here("OCSdata", "data", "imported", "imported_data.rda"))

If the package does not work for you, alternatively, an RDA file (stands for R data) of the data can be found here or slightly more directly here. Download this file and then place it 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 file more easily.

load(here::here("data", "imported", "imported_data.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 that we have imported the data, let’s see if we can wrangle a table.

What do we mean by “wrangle”? We mean that we intend to get the data into what is called “tidy” format.

This means that the data:
1) has each observation in single row
2) has a single aspect about each observation as a single column
3) is rectangular (meaning there are no empty cells)
4) the values within the cells are in a format that is useful for making visualizations and for analysis

Check out this paper for more information about tidy data.

Since the data appear to be formatted in a similar way in each of the tables, it is likely that whatever steps we take to wrangle this first table will also be necessary in the wrangling of subsequent tables. This is because well-maintained data sources often format different datasets similarly. We can take advantage of this similarity to speed up the wrangling process.

Table11.1a


Let’s take a look at our table on the website to see what it needs to get it into “tidy” format.

First, we can see that we want to remove the legend of our table.

We can take a look at the last row using the tail function of the dplyr package. We can specify that we only want to see the last row by using the n = 1 argument. To use the dplyr functions we need to first make this table into a tibble, which is the tidyverse version of a dataframe.

Currently table11.1a is a typical dataframe, which we can see using the class function which describes the types of data objects in R.

class(table11.1a)
[1] "data.frame"

We can use the as_tibble() function of the dplyr package to convert table11.1a into a tibble.

table11.1a %>%
  dplyr::as_tibble() %>%
  tail(n = 1)
# A tibble: 1 x 18
  `Setting Where Menta~` `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009`
  <chr>                  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
1 "* = low precision; -~ "* = ~ "* = ~ "* = ~ "* = ~ "* = ~ "* = ~ "* = ~ "* = ~
# ... with 9 more variables: `2010` <chr>, `2011` <chr>, `2012` <chr>,
#   `2013` <chr>, `2014` <chr>, `2015` <chr>, `2016` <chr>, `2017` <chr>,
#   `2018` <chr>

We can see that the legend is repeated for every column. Now, let’s take a look at the year 2004 column.

table11.1a %>%
  dplyr::as_tibble() %>%  
  dplyr::select(`2004`) %>%
  tail(n = 1)
# A tibble: 1 x 1
  `2004`                                                                        
  <chr>                                                                         
1 "* = low precision; -- = not available; da = does not apply; nc = not compara~

Let’s save this to an object called legend so that we can refer back to it later:

legend <- table11.1a %>%
  as_tibble() %>%  
  select(`2004`) %>%
  tail(n = 1)

Another way to look at the last row is to use the n() function of the dplyr package. This function can be used inside other dplyr functions and it counts the total number of observations of a group. Within the slice() function of the dplyr package, it allows you to refer the full length of the object.

table11.1a %>%
  dplyr::as_tibble() %>%
  dplyr::slice(n()) 
# A tibble: 1 x 18
  `Setting Where Menta~` `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009`
  <chr>                  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
1 "* = low precision; -~ "* = ~ "* = ~ "* = ~ "* = ~ "* = ~ "* = ~ "* = ~ "* = ~
# ... with 9 more variables: `2010` <chr>, `2011` <chr>, `2012` <chr>,
#   `2013` <chr>, `2014` <chr>, `2015` <chr>, `2016` <chr>, `2017` <chr>,
#   `2018` <chr>

We can use the slice() function of the dplyr package to remove this row, by using the slicefunction to select from the first row using 1: to the second to last row using n()-1.

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 table11.1a as our input and reassign it at the end after all the steps have been performed.

We will also first change the data to be a tibble, which is the tidyverse version of a data frame using the as_tibble() function of the dplyr package and the tibble package.

table11.1a %<>%
  dplyr::as_tibble() %>%
  slice(1:(n()-1))

Now let’s take a look at the data:

slice_head(table11.1a, n = (length(pull(table11.1a, `2002`))))
# A tibble: 20 x 18
   `Setting Where Ment~` `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009`
   <chr>                 <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
 1 "SPECIALTY MENTAL HE~ "2,89~ "3,06~ "3,34~ "3,36~ "3,25~ "3,10~ "3,12~ "2,92~
 2 "Outpatient"          "2,66~ "2,79~ "3,01~ "3,04~ "2,93~ "2,78~ "2,83~ "2,65~
 3 "Private Therapist, ~ "2,25~ "2,34~ "2,52~ "2,57~ "2,41~ "2,36~ "2,40~ "2,29~
 4 "Mental Health Clini~ "611a" "635a" "716a" "657a" "587a" "583a" "567a" "537a"
 5 "Partial Day Hospita~ "440"  "425"  "439"  "449"  "471"  "416"  "374a" "340a"
 6 "In-Home Therapist, ~ "693a" "656a" "762a" "731a" "719a" "707a" "716a" "657a"
 7 "Inpatient or Reside~ "509a" "542a" "629"  "619"  "596"  "581a" "539a" "524a"
 8 "Hospital"            "422a" "467a" "515"  "529"  "516"  "511a" "469a" "440a"
 9 "Residential Treatme~ "224a" "233a" "299"  "229a" "225a" "199a" "198a" "213a"
10 "NONSPECIALTY MENTAL~ "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "3,43~
11 "Education2,3"        "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "2,93~
12 "School Social Worke~ "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "2,28~
13 "Special School or P~ "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "975a"
14 "General Medicine"    ""     ""     ""     ""     ""     ""     ""     ""    
15 "Pediatrician or Oth~ "657a" "732"  "840"  "810"  "694"  "692"  "710"  "605a"
16 "Juvenile Justice"    ""     ""     ""     ""     ""     ""     ""     ""    
17 "Juvenile Detention ~ "--"   "--"   "--"   "--"   "--"   "--"   "--"   "109a"
18 "Child Welfare"       ""     ""     ""     ""     ""     ""     ""     ""    
19 "Foster Care or Ther~ "157a" "179a" "158a" "143a" "129"  "114"  "118"  "92"  
20 "SPECIALTY MENTAL HE~ "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "nc"   "1,22~
# ... with 9 more variables: `2010` <chr>, `2011` <chr>, `2012` <chr>,
#   `2013` <chr>, `2014` <chr>, `2015` <chr>, `2016` <chr>, `2017` <chr>,
#   `2018` <chr>

Great! We can see the the legend is no longer part of the data.

Now let’s use the legend to recode the data. There are many different values for missing data, that we would like to replace with NA instead. We can use the pull() function of the dplyr package to take a look at the legend data:

dplyr::pull(legend, `2004`)
[1] "* = low precision; -- = not available; da = does not apply; nc = not comparable due to methodological changes; nr = not reported due to measurement issues.\r\nNOTE: Some 2006 to 2010 estimates may differ from previously published estimates due to updates (see Section 3.3.5 in Chapter 3 of the 2018 National Survey on Drug Use and Health: Methodological Summary and Definitions).\r\nNOTE: Mental health services for persons aged 12 to 17 includes treatment/counseling for emotional or behavioral problems not caused by drug or alcohol use. Respondents with unknown mental health service information were excluded.\r\nNOTE: Respondents could indicate multiple service settings; thus, the response categories are not mutually exclusive.a The difference between this estimate and the 2018 estimate is statistically significant at the .05 level. Rounding may make the estimates appear identical.1 Because of revisions in 2013 to Specialty Mental Health Service estimates, these 2002 to 2012 estimates may differ from estimates published prior to the 2013 NSDUH.2 Because of revisions in 2009 to the questions on the Source of Youth Mental Health Education Services, these estimates are not comparable with the education services estimates published prior to the 2009 NSDUH.3 Respondents who did not report their school enrollment status, who reported not being enrolled in school in the past 12 months, or who reported being home-schooled were not asked about receipt of mental health services from this setting; however, respondents who reported not being enrolled in school in the past 12 months were classified as not having received treatment/counseling from this setting.\r\nDefinitions: Measures and terms are defined in Appendix A.\r\nSource: SAMHSA, Center for Behavioral Health Statistics and Quality, National Survey on Drug Use and Health, 2002-2018."

Looks like we want to replace values that are: *, --, da, nc, and nr.

We can use the na_if() function to recode these values to NA.

table11.1a %<>%
  dplyr::na_if("nc") %>%
  dplyr::na_if("--") %>%
  dplyr::na_if("") %>%
  dplyr::na_if("*")

head(table11.1a)
# A tibble: 6 x 18
  `Setting Where Menta~` `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009`
  <chr>                  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
1 "SPECIALTY MENTAL HEA~ 2,898a 3,065a 3,348a 3,362a 3,255a 3,104a 3,129a 2,925a
2 "Outpatient"           2,662a 2,795a 3,015a 3,048a 2,931a 2,787a 2,837a 2,650a
3 "Private Therapist, P~ 2,254a 2,347a 2,523a 2,573a 2,416a 2,365a 2,408a 2,296a
4 "Mental Health Clinic~ 611a   635a   716a   657a   587a   583a   567a   537a  
5 "Partial Day Hospital~ 440    425    439    449    471    416    374a   340a  
6 "In-Home Therapist, C~ 693a   656a   762a   731a   719a   707a   716a   657a  
# ... with 9 more variables: `2010` <chr>, `2011` <chr>, `2012` <chr>,
#   `2013` <chr>, `2014` <chr>, `2015` <chr>, `2016` <chr>, `2017` <chr>,
#   `2018` <chr>

Let’s look at the column names in our table:

colnames(table11.1a)
 [1] "Setting Where Mental Health ServiceWas Received"
 [2] "2002"                                           
 [3] "2003"                                           
 [4] "2004"                                           
 [5] "2005"                                           
 [6] "2006"                                           
 [7] "2007"                                           
 [8] "2008"                                           
 [9] "2009"                                           
[10] "2010"                                           
[11] "2011"                                           
[12] "2012"                                           
[13] "2013"                                           
[14] "2014"                                           
[15] "2015"                                           
[16] "2016"                                           
[17] "2017"                                           
[18] "2018"                                           

Let’s rename the first column using the rename() function of the dplyr package. This requires listing the new name first like so: new_name = old_name.

table11.1a %<>%
  dplyr::rename(MHS_setting = `Setting Where Mental Health ServiceWas Received`)

head(table11.1a)
# A tibble: 6 x 18
  MHS_setting     `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009` `2010`
  <chr>           <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
1 "SPECIALTY MEN~ 2,898a 3,065a 3,348a 3,362a 3,255a 3,104a 3,129a 2,925a 2,920a
2 "Outpatient"    2,662a 2,795a 3,015a 3,048a 2,931a 2,787a 2,837a 2,650a 2,635a
3 "Private Thera~ 2,254a 2,347a 2,523a 2,573a 2,416a 2,365a 2,408a 2,296a 2,265a
4 "Mental Health~ 611a   635a   716a   657a   587a   583a   567a   537a   547a  
5 "Partial Day H~ 440    425    439    449    471    416    374a   340a   362a  
6 "In-Home Thera~ 693a   656a   762a   731a   719a   707a   716a   657a   674a  
# ... with 8 more variables: `2011` <chr>, `2012` <chr>, `2013` <chr>,
#   `2014` <chr>, `2015` <chr>, `2016` <chr>, `2017` <chr>, `2018` <chr>

Nice!

Now you may notice that the individual values for the year columns have an "a" after the numeric value.

According to the legend this indicates if “the difference between this estimate and the 2018 estimate is significant at the \(\alpha\)=.05 level.”

While this is useful information, it makes it difficult to work with our numeric values, so we want to remove them.

Since lower case "a" values occur in the values of the MHS_setting column (like outpatient), we want to make sure that we don’t just remove all "a" values from the table, just those in the subsequent columns.

So how can we do this? We can use the stringr package to modify character strings. Also, we can use the dplyr functions mutate(), select() and across() to specify want columns we want to change.

Currently all of our data are character strings as indicated by the <chr> under the column names.


Click here for an explanation about data classes in R and about character strings.

There are several classes of data in R programming, meaning that certain objects will be treated or interpreted differently. 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).


The stringr package has functions that allow us to replace (using the str_replace() function) or remove (using the str_remove() function) characters.

To use these, we need to be able to specify what we want to remove and replace.

Here is a part of a cheatsheet about string manipulation from RStudio.

We can see that we can refer to any digit (such as 1, 2, 3 etc.) as [:digit:]. We can also see that we can refer to any punctuation mark as [:punct:]. Finally, we see that spaces and tabs can be referred to as [:blank:].

If we take a closer look at just the first column of our table (using the pull() function of the dplyr package), we see that there are also some large white spaces, some numeric values, instances of "\r\n", as well as some commas and other punctuation marks that we would like to remove form this column.

table11.1a %>% 
  pull(MHS_setting)
 [1] "SPECIALTY MENTAL HEALTH SERVICE1"                                                                                
 [2] "Outpatient"                                                                                                      
 [3] "Private Therapist, Psychologist,\r\n   Psychiatrist, Social Worker, or\r\n   Counselor"                          
 [4] "Mental Health Clinic or Center"                                                                                  
 [5] "Partial Day Hospital or Day Treatment\r\n   Program"                                                             
 [6] "In-Home Therapist, Counselor, or Family\r\n   Preservation Worker"                                               
 [7] "Inpatient or Residential1"                                                                                       
 [8] "Hospital"                                                                                                        
 [9] "Residential Treatment Center"                                                                                    
[10] "NONSPECIALTY MENTAL HEALTH\r\nSERVICE2"                                                                          
[11] "Education2,3"                                                                                                    
[12] "School Social Worker, School Psychologist,\r\n   or School Counselor"                                            
[13] "Special School or Program within a Regular\r\n   School for Students with Emotional or\r\n   Behavioral Problems"
[14] "General Medicine"                                                                                                
[15] "Pediatrician or Other Family Doctor"                                                                             
[16] "Juvenile Justice"                                                                                                
[17] "Juvenile Detention Center, Prison, or Jail"                                                                      
[18] "Child Welfare"                                                                                                   
[19] "Foster Care or Therapeutic Foster Care"                                                                          
[20] "SPECIALTY MENTAL HEALTH SERVICES\r\nAND EDUCATION, GENERAL MEDICINE\r\nOR CHILD WELFARE SERVICES1,2,3"           

We can use the str_remove_all() function to remove these unwanted characters from this column specifically.

The str_remove_all() function is a variant of the str_remove() function of the stringr package. It allows us to remove all occurrences of specified characters in each row rather than just the first occurrence (which is what str_remove() does).

Using the mutate() function, we specify that we want to change this particular column and replace it with a version of this column that does not contain characters that are digits, the r\n string that we saw, or punctuation marks.

We need to specify that the character strings that should be used can be found in the MHS_setting column by using the string = argument and the patterns to find and remove are specified using the pattern = argument.

To allow us to look for all three of these patterns at the same time, we can use the | symbol between each pattern.

table11.1a %<>%
mutate(MHS_setting = 
         str_remove_all(string = MHS_setting, 
                        pattern = "[:digit:]|\r\n|[:punct:]|"))

head(table11.1a)
# A tibble: 6 x 18
  MHS_setting     `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009` `2010`
  <chr>           <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
1 SPECIALTY MENT~ 2,898a 3,065a 3,348a 3,362a 3,255a 3,104a 3,129a 2,925a 2,920a
2 Outpatient      2,662a 2,795a 3,015a 3,048a 2,931a 2,787a 2,837a 2,650a 2,635a
3 Private Therap~ 2,254a 2,347a 2,523a 2,573a 2,416a 2,365a 2,408a 2,296a 2,265a
4 Mental Health ~ 611a   635a   716a   657a   587a   583a   567a   537a   547a  
5 Partial Day Ho~ 440    425    439    449    471    416    374a   340a   362a  
6 InHome Therapi~ 693a   656a   762a   731a   719a   707a   716a   657a   674a  
# ... with 8 more variables: `2011` <chr>, `2012` <chr>, `2013` <chr>,
#   `2014` <chr>, `2015` <chr>, `2016` <chr>, `2017` <chr>, `2018` <chr>

We also want to replace the spaces with a single space. We can see that sometimes there appears to be more than one space. We can specify that we want any occurrence of 1 or more to be replaced by using the {1,} notation.

See here for an explanation of this on the cheat sheet:

So, we will use the str_replace_all() function of the stringr package. In this case, we also need to specify a replacement with the replacement = argument. We will use this to specify one space.

table11.1a %<>%
mutate(MHS_setting = 
         str_replace_all(string = MHS_setting,
                         pattern = "[:blank:]{1,}", 
                         replacement = " "))

head(table11.1a)
# A tibble: 6 x 18
  MHS_setting     `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009` `2010`
  <chr>           <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
1 SPECIALTY MENT~ 2,898a 3,065a 3,348a 3,362a 3,255a 3,104a 3,129a 2,925a 2,920a
2 Outpatient      2,662a 2,795a 3,015a 3,048a 2,931a 2,787a 2,837a 2,650a 2,635a
3 Private Therap~ 2,254a 2,347a 2,523a 2,573a 2,416a 2,365a 2,408a 2,296a 2,265a
4 Mental Health ~ 611a   635a   716a   657a   587a   583a   567a   537a   547a  
5 Partial Day Ho~ 440    425    439    449    471    416    374a   340a   362a  
6 InHome Therapi~ 693a   656a   762a   731a   719a   707a   716a   657a   674a  
# ... with 8 more variables: `2011` <chr>, `2012` <chr>, `2013` <chr>,
#   `2014` <chr>, `2015` <chr>, `2016` <chr>, `2017` <chr>, `2018` <chr>

Next, we will remove the "a" values and the commas from the body of the table using the str_remove_all() function yet again.

However, this time to specify that we want all columns except the first column called MHS_setting, we can use the across() function of the dplyr package.

This allows us to specify what columns we want to mutate by using the .cols = argument. We can select all columns except the first column called MHS_setting by using a minus sign - in front of the column name.

table11.1a %<>%
  mutate(dplyr::across(.cols = -MHS_setting,
                       stringr::str_remove_all, "a|,"))

head(table11.1a)
# A tibble: 6 x 18
  MHS_setting     `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009` `2010`
  <chr>           <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
1 SPECIALTY MENT~ 2898   3065   3348   3362   3255   3104   3129   2925   2920  
2 Outpatient      2662   2795   3015   3048   2931   2787   2837   2650   2635  
3 Private Therap~ 2254   2347   2523   2573   2416   2365   2408   2296   2265  
4 Mental Health ~ 611    635    716    657    587    583    567    537    547   
5 Partial Day Ho~ 440    425    439    449    471    416    374    340    362   
6 InHome Therapi~ 693    656    762    731    719    707    716    657    674   
# ... with 8 more variables: `2011` <chr>, `2012` <chr>, `2013` <chr>,
#   `2014` <chr>, `2015` <chr>, `2016` <chr>, `2017` <chr>, `2018` <chr>

Our table is looking much better!

We also want to change our values to be numeric as opposed to character so that we can use them in mathematical functions. We can use the base as.numeric() function. Again we will use the across() function to indicate what variables we wish to mutate.

table11.1a %<>%
  mutate(across(.cols =-MHS_setting, as.numeric))

head(table11.1a)
# A tibble: 6 x 18
  MHS_setting     `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009` `2010`
  <chr>            <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 SPECIALTY MENT~   2898   3065   3348   3362   3255   3104   3129   2925   2920
2 Outpatient        2662   2795   3015   3048   2931   2787   2837   2650   2635
3 Private Therap~   2254   2347   2523   2573   2416   2365   2408   2296   2265
4 Mental Health ~    611    635    716    657    587    583    567    537    547
5 Partial Day Ho~    440    425    439    449    471    416    374    340    362
6 InHome Therapi~    693    656    762    731    719    707    716    657    674
# ... with 8 more variables: `2011` <dbl>, `2012` <dbl>, `2013` <dbl>,
#   `2014` <dbl>, `2015` <dbl>, `2016` <dbl>, `2017` <dbl>, `2018` <dbl>

We would also like to add a type and subtype variable, that specifies the general categories of settings where services were received, as well as remove a couple of rows that are completely empty. These are the rows where the first column values are General Medicine and Juvenile Justice, and Child Welfare. If we look at the website, we can see that these were leading lines with no data.

First, we will add the type and subtype variables using the mutate function.

table11.1a %<>%
  mutate(type = c(rep("Specialty", 9), 
                  rep("Nonspecialty", 11))) %>%
  mutate(subtype = c("Specialty_total", 
                     rep("Outpatient", 5), 
                     rep("Inpatient", 3), 
                     "Nonspecialty_total", 
                     rep("Education", 3), 
                     rep("General_medicine", 2),
                     rep("Juvenile_Justice", 2), 
                     rep("Child_Welfare", 2), 
                     "combination"))

We also want to add a variable with shorter names for labels in plots and statistical output.

table11.1a %<>%
  mutate(short_label = c("Specialty total", 
                         "Outpatient total", 
                         "Therapist", 
                         "Clinic", 
                         "Day program",
                         "In-home Therapist", 
                         "Inpatient total", 
                         "Hospital", 
                         "Residential Center",
                         "Nonspecialty total", 
                         "School total", 
                         "School Therapist", 
                         "School Program", 
                         "General Medicine",
                         "Family Dr",
                         "Justice System",
                         "Justice System",
                         "Welfare", 
                         "Fostercare", 
                         "Specialty Combination"))

We can remove the empty rows using the filter() function of the dplyr package. We can specify that we don’t want to keep these rows by using the != not equal to operator.

table11.1a %<>%
  dplyr::filter(MHS_setting != "General_Medicine") %>%
  dplyr::filter(MHS_setting != "Juvenile_Justice") %>%
  dplyr::filter(MHS_setting != "Child_Welfare")

head(table11.1a)
# A tibble: 6 x 21
  MHS_setting     `2002` `2003` `2004` `2005` `2006` `2007` `2008` `2009` `2010`
  <chr>            <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 SPECIALTY MENT~   2898   3065   3348   3362   3255   3104   3129   2925   2920
2 Outpatient        2662   2795   3015   3048   2931   2787   2837   2650   2635
3 Private Therap~   2254   2347   2523   2573   2416   2365   2408   2296   2265
4 Mental Health ~    611    635    716    657    587    583    567    537    547
5 Partial Day Ho~    440    425    439    449    471    416    374    340    362
6 InHome Therapi~    693    656    762    731    719    707    716    657    674
# ... with 11 more variables: `2011` <dbl>, `2012` <dbl>, `2013` <dbl>,
#   `2014` <dbl>, `2015` <dbl>, `2016` <dbl>, `2017` <dbl>, `2018` <dbl>,
#   type <chr>, subtype <chr>, short_label <chr>

Finally, we would like to change the shape of our table so that we have a new column that represents the year and a new column that represents the value for that year. To do so we will be making our table “longer”, meaning that it will have fewer columns and more rows. See here for more information about different table formats, typically referred to as wide and long or sometimes narrow.

We will use the pivot_longer() function of the tidyr package to change the shape of our table.

There are 3 main arguments in this function:

  1. cols - which specifies what columns to collapse
  2. names_to - which specifies the name of the new column that will be created that will contain the column names of the columns you are collapsing
  3. values_to - which specifies the name of the new column that will be created that will contain the values from the columns you are collapsing

To specify that we want to collapse all the columns that have year values, we can chose those that contain the string "20" using the contains() function of dplyr.

Finally, we will make the Year variable numeric as well.

We will first use the base dim() function to see the dimensions of our table before and after using pivot_longer().

dim(table11.1a)
[1] 20 21
table11.1a %<>%
  tidyr::pivot_longer(cols = contains("20"), 
                      names_to = "Year",
                      values_to = "Number") %>%
  mutate(Year = as.numeric(Year))

dim(table11.1a)
[1] 340   6
head(table11.1a)
# A tibble: 6 x 6
  MHS_setting                     type      subtype     short_label  Year Number
  <chr>                           <chr>     <chr>       <chr>       <dbl>  <dbl>
1 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty_~ Specialty ~  2002   2898
2 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty_~ Specialty ~  2003   3065
3 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty_~ Specialty ~  2004   3348
4 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty_~ Specialty ~  2005   3362
5 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty_~ Specialty ~  2006   3255
6 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty_~ Specialty ~  2007   3104

We can see that our table is now much longer - as we have 340 rows!

Question Opportunity

Why do we have 340 rows now?

Now, we see that the Year and Number variables are of class double because of the <dbl> under the column name.

Let’s remind ourselves what the rest of the tables contain:

Table Details
Table 11.1A Settings Where Mental Health Services Were Received in Past Year among Persons Aged 12 to 17: Numbers in Thousands, 2002-2018
Table 11.1B Settings Where Mental Health Services Were Received in Past Year among Persons Aged 12 to 17: Percentages, 2002-2018
Table 11.2A Major Depressive Episode in Past Year among Persons Aged 12 to 17, by Demographic Characteristics: Numbers in Thousands, 2004-2018
Table 11.2B Major Depressive Episode in Past Year among Persons Aged 12 to 17, by Demographic Characteristics: Percentages, 2004-2018
Table 11.3A Major Depressive Episode with Severe Impairment in Past Year among Persons Aged 12 to 17, by Demographic Characteristics: Numbers in Thousands, 2006-2018
Table 11.3B Major Depressive Episode with Severe Impairment in Past Year among Persons Aged 12 to 17, by Demographic Characteristics: Percentages, 2006-2018
Table 11.4A Receipt of Treatment for Depression in Past Year among Persons Aged 12 to 17 with Major Depressive Episode in Past Year, by Demographic Characteristics: Numbers in Thousands, 2004-2018
Table 11.4B Receipt of Treatment for Depression in Past Year among Persons Aged 12 to 17 with Major Depressive Episode in Past Year, by Demographic Characteristics: Percentages, 2004-2018

OK, so the next table (Table11.1B) is very similar to Table11.1A, while the remaining tables have information about demographics.

As a reminder here are all of the steps that we performed to wrangle table11.1a:

table11.1a %<>%
# make the table into a tibble
  dplyr::as_tibble() %>%
# remove the last row by only keeping the first through the second to last
  slice(1:(n() - 1)) %>%
# make the "nc" values "NA" instead
  dplyr::na_if("nc") %>%
  dplyr::na_if("--") %>%
  dplyr::na_if("") %>%
  dplyr::na_if("*") %>% 
# rename the column to the shorter MHS_setting name
  dplyr::rename(MHS_setting = 
                  `Setting Where Mental Health ServiceWas Received`) %>%
# remove numbers, carriage return, new lines, and punctuation marks from the values for the MHS_setting column
  mutate(MHS_setting = 
         str_remove_all(string = MHS_setting, 
                       pattern = "[:digit:]|\r\n|[:punct:]|")) %>%
# replace the white spaces with a single space
  mutate(MHS_setting = 
         str_replace_all(string = MHS_setting,
                        pattern = "[:blank:]{1,}", 
                    replacement = " ")) %>%
# remove "a" and commas from the values in the columns except the column called MHS_setting
  mutate(dplyr::across(.cols = -MHS_setting,
                stringr::str_remove_all, "a|,")) %>%
# make those columns numeric
  mutate(across(-MHS_setting, as.numeric)) %>%
# create a new type column with the values: "Specialty repeated 9 times followed by "Nonspecialty" repeated 11 times
  mutate(type = c(rep("Specialty", 9), rep("Nonspecialty", 11))) %>%
# create a new variable called subtype 
  mutate(subtype =c("Specialty_total", 
                    rep("Outpatient", 5), 
                    rep("Inpatient", 3), 
                    "Nonspecialty_total", 
                    rep("Education", 3), 
                    rep("General_medicine", 2),
                    rep("Juvenile_Justice", 2),
                    rep("Child_Welfare", 2), 
                    "combination")) %>%
# create a new variabel called short_label
  mutate(short_label = c("Specialty total", "Outpatient total",
                         "Therapist", "Clinic", "Day program", 
                         "In-home Therapist", "Inpatient total",
                         "Hospital", "Residential Center",
                         "Nonspecialty total", "School total", 
                         "School Therapist", "School Program", 
                         "General Medicine", "Family Dr", 
                         "Justice System", "Justice System",
                         "Welfare", "Fostercare", 
                         "Specialty Combination")) %>%
# remove rows with General_Medicine as the value in the MHS_setting column because it is empty
  dplyr::filter(MHS_setting != "General_Medicine") %>%
# remove rows with Juvenile_Justice as the value in the MHS_setting column because it is empty
  dplyr::filter(MHS_setting != "Juvenile_Justice") %>%
# remove rows with Child_Welfare as the value in the MHS_setting column because it is empty
  dplyr::filter(MHS_setting != "Child_Welfare") %>%
# make the table in long format
    tidyr::pivot_longer(cols = contains("20"),
                        names_to = "Year",
                        values_to = "Number") %>%
# make the new Year variable to be numeric
   mutate(Year = as.numeric(Year))

Now we want to wrangle table11.1B which is formatted the most similarly. To do so we can simply run these steps on the using the table11.1B as the input. For the sake of education, however, we will show you how you could make a function if we had several more similar tables to wrangle. This will also make it easier to write a function to wrangle the other demographic tables.

Last time we wrote a function in this case study, we only had one input in our function. This time we will have several inputs. We will have the table that we want to wrangle as TABLE, a new name for the first column called new_col, and an input called pivot_col, which will be the name of the column that will be created after pivoting that will take the values from each of the years.

function(TABLE, new_col, pivot_col){
    <add code here> 
  }

We want to make our function flexible so that it can take any value for the name of the first column. To select the first column we will use this following code, where the base names() function gets the column names of the TABLE input , which is indicated by the . and then to get just the first name the [1] is used.

function(TABLE, new_col, pivot_col){
  dplyr::as_tibble(TABLE) %>%
  #additional steps
  names(.)[1]
  #additional steps
}

And to rename the with the new_col input to the function we can do this:

function(TABLE, new_col, pivot_col){
  dplyr::as_tibble(TABLE) %>%
  #additional steps
  rename({{new_col}} := names(.)[1])
  #additional steps
}

The double curly brackets {{}} allow us to use the input to the function called new_col within the function.

See here for information about the := colon-equals operator. This operator is more flexible than the normal =. It allows expressions on both sides, thus it allows us to use an expression (the values for new_col) as the input value to the expressions that follow the := operator.

We will also add code to remove all rows that have only NA values in a more flexible way, so that we don’t need to know what rows ahead of time.

To do this we will use the filter() and select() functions of the dplyr package.

We will calculate a sum of the count of NA values across the rows for the columns for each year using the base rowSums() function like so:

rowSums(is.na(.))

However to do this we first need to select only the columns that are numeric using: select(., is.numeric), where the . refers to the table after all the previous wrangling steps in our function. Importantly of course, this all needs to happen after we convert the values for each year to numeric.

Anyway, altogether this looks like this:

rowSums(is.na(select(., is.numeric)))`.

Finally, we compare this to the number of columns that are numeric by using: length(select(., is.numeric))), with the idea that if the number of NA values is less than the number of columns that could have NA values, then we know it is not an empty row.

Overall, this would look something like this after we perform a step to convert the columns to be numeric like we did before:

function(TABLE, new_col, pivot_col){
  # previous similar steps to modify and make table values numeric
    filter(rowSums(is.na(select(., is.numeric))) < 
             length(select(., is.numeric))) 
  }

Note that if we were using the summarize() or mutate() function or the dplyr package, then we could use the across() function of the dplyr package to select what columns we wanted to use in our calculation.

OK, so putting everything together from what we did previously for table11.1a and these new flexible steps we can create this function:

data_prep_settings <- function(TABLE, new_col, pivot_col){
# make the table a tibble
  dplyr::as_tibble(TABLE) %>%
# remove the last row
    slice(1:(n() - 1)) %>%
# make "nc" values NA etc.
    na_if("nc") %>%
    na_if("--") %>%
    na_if("") %>%
    na_if("*") %>% 
# rename the first column (names(.)[1]) to be what was specified with the new_col argument
    rename({{new_col}} := names(.)[1]) %>%
# remove the numbers and punctuation marks and carriage returns (\r) and new lines (\n) from the first column
    mutate({{new_col}} := 
        str_remove_all(string = pull(., {{new_col}}), 
                        pattern = "[:digit:]|\r\n|[:punct:]|")) %>%
# replace white spaces with a single space
    mutate({{new_col}} := 
        str_replace_all(string =pull(., {{new_col}}),
                         pattern = "[:blank:]{1,}", 
                         replacement = " ")) %>%
# remove "a" and , from the values for the columns that are not the first column (called new_col)
    mutate(dplyr::across(.cols = -{{new_col}},
                       stringr::str_remove_all, "a|,")) %>%
# make these columns numeric  (all the columns but the first column)
    mutate(across(-{{new_col}}, as.numeric)) %>%
# make a new variable called type with 9 values that are Specialty followed by 11 values of Nonspecialty
    mutate(type = c(rep("Specialty", 9), rep("Nonspecialty", 11))) %>%
# make a new variable called subtype with the following values repeated various times
    mutate(subtype = c("Specialty_total",
                       rep("Outpatient", 5),
                       rep("Inpatient", 3),
                       "Nonspecialty_total",
                       rep("Education", 3),
                       rep("General_medicine", 2),
                       rep("Juvenile_Justice", 2),
                       rep("Child_Welfare", 2),
                       "combination")) %>% 
# make a new variable called short_label to use as labels for plots for the data
    mutate(short_label = c("Specialty total", "Outpatient total",  
                           "Therapist", "Clinic", "Day program", 
                           "In-home Therapist", "Inpatient total",
                           "Hospital", "Residential Center",
                           "Nonspecialty total", "School total", 
                           "School Therapist", "School Program", 
                           "General Medicine", "Family Dr", 
                           "Justice System", "Justice System", 
                           "Welfare", "Fostercare", 
                           "Specialty Combination")) %>%
# remove rows were all the values are NA - 
# the number of `NA` values for a row should be less than the number of columns that could have `NA` values
  filter(rowSums(is.na(select(., is.numeric))) <
           length(select(., is.numeric))) %>%
# make the table into long format so that the year columns are collapsed together 
# the new value column is called what was specified with the "pivot_col" argument
  pivot_longer(cols = contains("20"),
               names_to = "Year", 
               values_to = pivot_col)%>%
# make the new "Year" variable numeric
  mutate(Year = as.numeric(Year))
}

Now we can apply the function to table11.1b.

Table11.1b


table11.1b <- 
  data_prep_settings(TABLE = table11.1b, 
                     new_col = "MHS_setting",
                     pivot_col = "Percent")

head(table11.1b)
# A tibble: 6 x 6
  MHS_setting                     type      subtype    short_label  Year Percent
  <chr>                           <chr>     <chr>      <chr>       <dbl>   <dbl>
1 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty~ Specialty ~  2002    11.8
2 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty~ Specialty ~  2003    12.4
3 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty~ Specialty ~  2004    13.4
4 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty~ Specialty ~  2005    13.4
5 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty~ Specialty ~  2006    13  
6 SPECIALTY MENTAL HEALTH SERVICE Specialty Specialty~ Specialty ~  2007    12.4

Now we have tidy data about the counts and percentages of where youths, who experienced a major depressive episode, received treatment for depression.

What about the subsequent tables?

Demographic Tables


All of the rest of the tables have demographic information and have this general structure:

In these tables, we have age groups in our first column so we don’t want to remove digits or punctuation marks anymore so we need to modify our function a bit to remove that step.

We also want to add the word Age and an underscore in front of the age group listed in the tables. We can use the str_replace() function of the stringr package, because now we want to only replace the first instance of 1 with Age: 1.

We will replace the first column name with Demographic for all of the tables.

We will create a new variable that list the subgroups.

We will also want to only wrangle the data up to the point that we change the shape of the data, so that we can check how the data looks first.

OK let’s put this all together into a data_dem_settings() function:

data_dem_settings <- function(TABLE){
  # make the table a tibble
  dplyr::as_tibble(TABLE) %>%
  # Remove the last row - keep only the 1st through 2nd to last rows
  slice(1:(n()-1)) %>%
  # change the values from "nc, --" etc to NA
  na_if("nc") %>%
  na_if("--") %>%
  na_if("") %>%
  na_if("*") %>%
  # rename the first column to be "Demographic"
  rename(Demographic := names(.)[1]) %>%
  # replace white spaces form the values of the "Demographic" variable with a single space
  mutate(Demographic := str_replace_all(string = pull(., Demographic),
                                        pattern = "[:blank:]{1,}", 
                                        replacement = " ")) %>%
  # replace values where there is a "1" in the "Demographic" variable to be "Age: 1"
  mutate(Demographic = str_replace(string = Demographic, 
                                   pattern = "1", 
                                   replacement = "Age: 1")) %>%
  # create a new variable called subgroup
  mutate(subgroup = c("Total", rep("Age", 4), 
                    rep("Gender", 3), rep("Race/Ethnicity", 9))) %>%
  # remove "a" and commas from the variables that have column names with "20" in them
  mutate(dplyr::across(.cols = contains("20"),
                       stringr::str_remove_all, "a|,")) %>%
  # make the variables with "20" in the names (the year variables) to be numeric
  mutate(across(contains("20"), as.numeric)) %>%
  # remove empty rows - rows were the number of NA values is equal to the number of numeric columns
  filter(rowSums(is.na(select(., is.numeric))) < length(select(., is.numeric)))
  }

Now, we use the data_dem_settings() function to wrangle the next set of tables. We will also add a column to describe what the data are about which will be helpful for merging the data later.

table11.2a <- data_dem_settings(TABLE = table11.2a)
table11.2a %<>% mutate(data_type = "Major_Depressive_Episode")
head(table11.2a)
# A tibble: 6 x 18
  Demographic `2004` `2005` `2006` `2007` `2008` `2009` `2010` `2011` `2012`
  <chr>        <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 TOTAL         2225   2191   1970   2016   2027   1954   1911   2011   2213
2 Age: 12-13     445    417    383    337    366    330    330    312    420
3 Age: 14-15     783    811    684    705    706    741    706    710    844
4 Age: 16-17     997    964    902    974    955    883    876    989    950
5 Male           637    571    539    586    540    577    536    566    581
6 Female        1588   1620   1431   1430   1487   1377   1375   1446   1632
# ... with 8 more variables: `2013` <dbl>, `2014` <dbl>, `2015` <dbl>,
#   `2016` <dbl>, `2017` <dbl>, `2018` <dbl>, subgroup <chr>, data_type <chr>
table11.2b <- data_dem_settings(TABLE = table11.2b)
table11.2b %<>% mutate(data_type = "Major_Depressive_Episode")
head(table11.2b)
# A tibble: 6 x 18
  Demographic `2004` `2005` `2006` `2007` `2008` `2009` `2010` `2011` `2012`
  <chr>        <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 TOTAL          9      8.8    7.9    8.2    8.3    8.1    8      8.2    9.1
2 Age: 12-13     5.4    5.2    4.9    4.3    4.9    4.6    4.3    4.1    5.4
3 Age: 14-15     9.2    9.5    7.9    8.4    8.5    8.8    9      8.6   10.2
4 Age: 16-17    12.3   11.5   10.7   11.5   11.2   10.4   10.6   11.7   11.4
5 Male           5      4.5    4.2    4.6    4.3    4.7    4.4    4.5    4.7
6 Female        13.1   13.3   11.8   11.9   12.5   11.7   11.9   12.1   13.7
# ... with 8 more variables: `2013` <dbl>, `2014` <dbl>, `2015` <dbl>,
#   `2016` <dbl>, `2017` <dbl>, `2018` <dbl>, subgroup <chr>, data_type <chr>
table11.3a <- data_dem_settings(TABLE = table11.3a)
table11.3a %<>% mutate(data_type = "Severe_Major_Depressive_Episode")
head(table11.3a)
# A tibble: 6 x 16
  Demographic `2006` `2007` `2008` `2009` `2010` `2011` `2012` `2013` `2014`
  <chr>        <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 TOTAL         1358   1371   1460   1404   1350   1388   1544   1868   1990
2 Age: 12-13     211    200    239    235    232    218    285    314    375
3 Age: 14-15     518    500    505    521    479    487    590    752    707
4 Age: 16-17     629    671    716    648    639    683    669    801    909
5 Male           335    386    359    391    395    397    373    435    461
6 Female        1023    986   1101   1013    954    991   1172   1432   1529
# ... with 6 more variables: `2015` <dbl>, `2016` <dbl>, `2017` <dbl>,
#   `2018` <dbl>, subgroup <chr>, data_type <chr>
table11.3b <- data_dem_settings(TABLE = table11.3b)
table11.3b %<>% mutate(data_type = "Severe_Major_Depressive_Episode")
head(table11.3b)
# A tibble: 6 x 16
  Demographic `2006` `2007` `2008` `2009` `2010` `2011` `2012` `2013` `2014`
  <chr>        <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 TOTAL          5.5    5.5    6      5.8    5.7    5.7    6.3    7.7    8.2
2 Age: 12-13     2.7    2.5    3.2    3.2    3      2.8    3.7    4.1    4.9
3 Age: 14-15     6      6      6.1    6.2    6.1    5.9    7.1    9.1    8.5
4 Age: 16-17     7.5    7.9    8.4    7.7    7.7    8.1    8      9.7   10.9
5 Male           2.6    3      2.9    3.2    3.2    3.2    3      3.5    3.7
6 Female         8.4    8.2    9.3    8.6    8.2    8.3    9.8   12     13  
# ... with 6 more variables: `2015` <dbl>, `2016` <dbl>, `2017` <dbl>,
#   `2018` <dbl>, subgroup <chr>, data_type <chr>
table11.4a <- data_dem_settings(TABLE = table11.4a)
table11.4a %<>% mutate(data_type = "Treatment")
head(table11.4a)
# A tibble: 6 x 18
  Demographic `2004` `2005` `2006` `2007` `2008` `2009` `2010` `2011` `2012`
  <chr>        <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 TOTAL          895    822    760    782    764    673    721    769    813
2 Age: 12-13     169    136    133    137    122     98    106    112    127
3 Age: 14-15     278    329    263    259    236    244    271    258    307
4 Age: 16-17     448    357    364    386    405    331    343    400    379
5 Male           239    193    189    214    183    168    171    199    163
6 Female         656    629    571    568    581    505    549    570    650
# ... with 8 more variables: `2013` <dbl>, `2014` <dbl>, `2015` <dbl>,
#   `2016` <dbl>, `2017` <dbl>, `2018` <dbl>, subgroup <chr>, data_type <chr>
table11.4b <- data_dem_settings(TABLE = table11.4b)
table11.4b %<>% mutate(data_type = "Treatment")
head(table11.4b)
# A tibble: 6 x 18
  Demographic `2004` `2005` `2006` `2007` `2008` `2009` `2010` `2011` `2012`
  <chr>        <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 TOTAL         40.3   37.8   38.8   39     37.7   34.6   37.8   38.4   37  
2 Age: 12-13    38.2   32.9   35.1   41.5   33.5   30     32.5   36.3   30.7
3 Age: 14-15    35.5   41.1   38.4   36.8   33.6   33.2   38.4   36.3   36.6
4 Age: 16-17    45     37.1   40.7   39.8   42.4   37.5   39.3   40.5   40  
5 Male          37.7   34.1   35.3   36.7   34     29.2   32     35.3   28.3
6 Female        41.3   39     40.2   40     39.1   36.9   40.1   39.5   40.1
# ... with 8 more variables: `2013` <dbl>, `2014` <dbl>, `2015` <dbl>,
#   `2016` <dbl>, `2017` <dbl>, `2018` <dbl>, subgroup <chr>, data_type <chr>

Great! All of the demographic tables look good.

It’s a good idea to regularly check your data to make sure it is as you expect.

Now let’s make a function to check that our data is as we expect. We have quite a few tables which could make this a bit challenging, but you might find yourself in future in a situation where you have lots of data, and checking by looking at the data would not be feasible.

First let’s make sure our tables are tibbles by using the is_tibble() function of the tibble package. We can use the case_when() function to give us a message if the value for the is_tibble() function is TRUE - this is the message after the first ~ and a different message for all other cases using TRUE followed again by ~ and a helpful message about the data.

data_dem_check <- function(TABLE){
  # check that the data is a tibble
  case_when(is_tibble(TABLE) ~ "Good!",
                        TRUE ~ "Not a tibble")
}

Now we will try this on some data we know is for sure a tibble (table11.1a) and data that we know for sure is not.

test_that_should_fail <- c(1,2,3)
class(test_that_should_fail)
[1] "numeric"
class(table11.1a)
[1] "tbl_df"     "tbl"        "data.frame"
data_dem_check(test_that_should_fail)
[1] "Not a tibble"
data_dem_check(table11.1a)
[1] "Good!"

Great! it looks like it’s working! Now we will create more functions to do additional checks on the data.


Click here for more information about each of the check functions.

Next we will check that the legend has been removed. To do this we will make sure that there are no -- = not available (as this was part of the legend) in the last row by using str_detect() to look for --= and slice(n()) to look at the last row specifically.

First let’s take a look again at what the legend looked like:

legend
# A tibble: 1 x 1
  `2004`                                                                        
  <chr>                                                                         
1 "* = low precision; -- = not available; da = does not apply; nc = not compara~
data_dem_check <- function(TABLE){
  # check that the last row does not contain "--" by..
   #first grabbing only the last row
   #pulling one of the years
  case_when(TABLE %>% slice(n()) %>% pull(`2018`) %>%
  # if it is detected print 
            str_detect(pattern = "-- = not available")  ~ "Legend might still be there",
                                                   TRUE ~ "Good!")
}

data_dem_check(table11.4a)
[1] "Good!"

Now we will put these together in a new tibble:

data_dem_check <- function(TABLE){
tibble(tibble_check = case_when(is_tibble(table11.4a) ~ "Good!",
                                                 TRUE ~ "Not a tibble"),
       legend_check = case_when(table11.4a %>% slice(n()) %>%pull(`2004`) %>%
   # if it is detected print 
                          str_detect(pattern = "--")  ~ "Legend might still be there",
                                                 TRUE ~ "Good!"))
}

data_dem_check(table11.4a)
# A tibble: 1 x 2
  tibble_check legend_check
  <chr>        <chr>       
1 Good!        Good!       

Note here that we will make all of the positive checks have the same value of Good!. This will allow us to make an overall check later that all of the checks passed.

Now we will write a function to check if any of the values that were nc,*, -- , or they got converted to NA. We can check for the presence of a value in entire tibble using the base any() function.

data_dem_check <- function(TABLE){
  case_when(any(str_detect(TABLE, pattern = "nc|\\*|--")) 
  # if it is detected, print this:
         ~ "NA not fixed",
  # if not detected, print this:
    TRUE ~ "Good!")
}


data_dem_check(table11.4a)
[1] "Good!"

Now we will check that the first variable is called “Demographic”.

data_dem_check <- function(TABLE){
  case_when(names(TABLE)[1] == "Demographic" ~ "Good!",
                                        TRUE ~ "check first column")
  }

data_dem_check(table11.4a)
[1] "Good!"

Now let’s check that there are no white spaces larger than one space. We can use [:blank:]{2,} to indicate two or more white spaces.

data_dem_check <- function(TABLE){
  case_when(any(str_detect(TABLE, pattern = "[:blank:]{2,}")) 
         ~ "white spaces not fixed",
    TRUE ~ "Good!")
}


data_dem_check(table11.4a)
[1] "Good!"

Now let’s check that all the age values start with Age: for the demographic variable. We can use ^ to look at the beginning of each character string in the Demographic variable. None should start with 1 anymore. Thus we can use ^1 to check if any strings do start with a 1.

data_dem_check <- function(TABLE){
  case_when(any(str_detect(pull(TABLE,Demographic), pattern = "^1"))
  # if it is detected print 
         ~ "Age data not fixed!",
    TRUE ~ "Good!")
}


data_dem_check(table11.4a)
[1] "Good!"

Now we will check that we have a variable called subgroup

data_dem_check <- function(TABLE){
  case_when(any(names(TABLE) == "subgroup")
  # if it is detected print 
         ~ "Good",
    TRUE ~ "No subgroup variable!")
}

data_dem_check(table11.4a)
[1] "Good"

Next we will check that the year variables do not contain “a” or “,”. To do so instead of selecting the columns with names that are years, we will not include the columns that are not years. We will also use themap_df function of the purrr package to check for detecting commas and “a”s for each column separately. Typically this would not be necessary because as long as we aren’t checking for commas it should work. However, str_detect() will coerce the data to be vectorized and to do so it will add commas to our data! Since we are looking for commas this would lead us to detect commas regardless of if they were present in our data. The map functions of the purrr package allows us to perform functions across multiple columns of tibbles. The map_df() function preserves the data frame structure, otherwise we are left with a list, which would be slightly harder to work with. This will create a data frame of TRUE and FALSE values. We can then sum each row as FALSE is evaluated as a zero and TRUE is evaluated as a one. Then to get a single value for our case_when() function, we will sum the sums of the rows. We should have no values with either “a” or “,” thus when we run this check, the sum should be equal to zero. To pipe the data into the map_df() function and then into str_detect(), we need to use the ~ and .x notation. Thus the .X is the columns within the selected columns of the table that will be piped into str_detect. The ~ indicates the function we will be using on each column.

data_dem_check <- function(TABLE){
  case_when(
   TABLE%>% select(-Demographic, -subgroup, -data_type) %>% 
     map_df(~str_detect(.x, pattern ="a|,")) %>%
     rowSums(na.rm = TRUE) %>% 
     sum() == 0
         ~ "Good!",
    TRUE ~ "There may be commas or the letter a in the year columns!")
}


data_dem_check(table11.4a)
[1] "Good!"

Now we will check that the year variables are numeric.

data_dem_check <- function(TABLE){
  case_when(sum(map_dbl(TABLE, is.numeric))== sum(str_count(names(TABLE), "20"))
  # if it is detected print 
         ~ "Good!",
    TRUE ~ "Variables are not numeric!")
}

data_dem_check(table11.4a)
[1] "Good!"

Finally we will make sure that there are no rows where all the year columns have NA values.

data_dem_check <- function(TABLE){
  case_when(nrow(TABLE %>%filter(rowSums(is.na(select(., is.numeric))) > length(select(., is.numeric))))
 >0 
  # if it is detected print 
         ~ "There are empty rows ",
    TRUE ~ "Good!")
}

data_dem_check(table11.4a)
[1] "Good!"

Now let’s put all our check functions together into one large data checking function. Notice that if the result is good for each check it results in a value of “Good!”. We can then use the base all() function to check that all the values in the results tibble that gets created during our overall function yields a value of “Good!”.

We can use the ifelse base function to give our result similar to how we have used case_when(). If all values for each check are “Good!” then we will get “Data looks good!”, otherwise or else we will see all of the check results. There is an if_else() function in dplyr but it only outputs character strings, so this would not work to show what checks failed when not all values were “Good!”.

data_dem_check <- function(TABLE){
results <-tibble(tibble_check = case_when(is_tibble(TABLE) ~ "Good!",
                                                 TRUE ~ "Not a tibble"),
       legend_check = case_when(TABLE %>% slice(n()) %>%pull(`2018`) %>%
   # if it is detected print 
                          str_detect(pattern = "--")  ~ "Legend might still be there",
                                                 TRUE ~ "Good!"),
       NAs_check = case_when(any(str_detect(TABLE, pattern = "nc")) 
                                                      ~ "NA not fixed",
                                                 TRUE ~ "Good!"),
  firstcol_check = case_when(names(TABLE)[1] == "Demographic" 
                                                      ~ "Good!",
                                                 TRUE ~ "check first column"),
  white_space_check = case_when(any(str_detect(TABLE, pattern = "[:blank:]{2,}")) 
                                                      ~ "white spaces not fixed",
                                                 TRUE ~ "Good!"),
  age_data_check = case_when(any(str_detect(pull(TABLE,Demographic), pattern = "^1"))
                                                      ~ "Age data not fixed!",
                                                 TRUE ~ "Good!"),
  subgroup_check = case_when(any(names(TABLE) == "subgroup")
                                                      ~ "Good!",
                                                 TRUE ~ "No subgroup variable!"),
    a_comma_check = case_when(TABLE%>% select(-Demographic, -subgroup, -data_type) %>% 
                                      map_df(~(str_detect(.x, pattern ="a|,"))) %>%
                                           rowSums(na.rm = TRUE) %>% 
                                                sum() == 0
                                                       ~ "Good!",
                                                  TRUE ~ "There may be commas or the letter a in the year columns!"),
numeric_check = case_when(sum(map_dbl(TABLE, is.numeric))== sum(str_count(names(TABLE), "20"))
                                                     ~ "Good!",
                                                TRUE ~ "Variables are not numeric!"),
  empty_row_check = case_when(nrow(TABLE %>%filter(rowSums(is.na(select(., is.numeric))) > 
                                                     length(select(., is.numeric)))) >0 
                                                     ~ "There are empty rows ",
                                                TRUE ~ "Good!"))

ifelse(all(results == "Good!"),
       "Data looks good!", glimpse(results))
}

data_dem_check(table11.4a)
[1] "Data looks good!"

Great! now let’s check all of our wrangled demographic tibbles. We can use the general map() function of the purrr package to check all of our demographic tables efficiently. We will create a list of the names of the tibbles and then apply the data_dem_check() function that we wrote to each tibble by using map().

tables_tocheck <-list(table11.2a, table11.2b, table11.3a, table11.3b, table11.4a, table11.4b)
tables_tocheck %>% map(data_dem_check)
[[1]]
[1] "Data looks good!"

[[2]]
[1] "Data looks good!"

[[3]]
[1] "Data looks good!"

[[4]]
[1] "Data looks good!"

[[5]]
[1] "Data looks good!"

[[6]]
[1] "Data looks good!"

Great! Now that we have checked our data, let’s put it together.

Let’s combine the count data (the “a” tables) and the percent data (the “b” tables) using the bind_rows() function of the dplyr package, which will append each of the subsequent tables together.

We can use the distinct() function of the dplyr package to check that we indeed have all the data types now in these larger tibbles.

counts <- dplyr::bind_rows(table11.2a, table11.3a, table11.4a)
percents <- bind_rows(table11.2b, table11.3b, table11.4b)

counts %>% dplyr::distinct(data_type)
# A tibble: 3 x 1
  data_type                      
  <chr>                          
1 Major_Depressive_Episode       
2 Severe_Major_Depressive_Episode
3 Treatment                      
percents %>% distinct(data_type)
# A tibble: 3 x 1
  data_type                      
  <chr>                          
1 Major_Depressive_Episode       
2 Severe_Major_Depressive_Episode
3 Treatment                      

Great!

Now we will reformat both the counts and percents data to be in the long format using pivot_longer() once again.

counts %<>%
  pivot_longer(cols = contains("20"), 
               names_to = "Year", 
               values_to = "Number") %>%
  mutate(Year = as.numeric(Year))

percents %<>%
  pivot_longer(cols = contains("20"), 
               names_to = "Year", 
               values_to = "Percent") %>%
  mutate(Year = as.numeric(Year))

glimpse(counts)
Rows: 570
Columns: 5
$ Demographic <chr> "TOTAL", "TOTAL", "TOTAL", "TOTAL", "TOTAL", "TOTAL", "TOT~
$ subgroup    <chr> "Total", "Total", "Total", "Total", "Total", "Total", "Tot~
$ data_type   <chr> "Major_Depressive_Episode", "Major_Depressive_Episode", "M~
$ Year        <dbl> 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013~
$ Number      <dbl> 2225, 2191, 1970, 2016, 2027, 1954, 1911, 2011, 2213, 2587~
glimpse(percents)
Rows: 570
Columns: 5
$ Demographic <chr> "TOTAL", "TOTAL", "TOTAL", "TOTAL", "TOTAL", "TOTAL", "TOT~
$ subgroup    <chr> "Total", "Total", "Total", "Total", "Total", "Total", "Tot~
$ data_type   <chr> "Major_Depressive_Episode", "Major_Depressive_Episode", "M~
$ Year        <dbl> 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013~
$ Percent     <dbl> 9.0, 8.8, 7.9, 8.2, 8.3, 8.1, 8.0, 8.2, 9.1, 10.7, 11.4, 1~

Notice also that some of the groups are abbreviated as AIAN and NHOPI.

percents %>% 
  distinct(Demographic)%>%
  pull(Demographic)
 [1] "TOTAL"                     "Age: 12-13"               
 [3] "Age: 14-15"                "Age: 16-17"               
 [5] "Male"                      "Female"                   
 [7] "Not Hispanic or Latino"    "White"                    
 [9] "Black or African American" "AIAN"                     
[11] "NHOPI"                     "Asian"                    
[13] "Two or More Races"         "Hispanic or Latino"       

Using the definitions from the Census Bureau:

  1. AIAN stands for American Indian and Alaska Native
  2. NHOPI stands for Native Hawaiian or Other Pacific Islander

Let’s update our data to reflect these definitions.

However, we would like to note that there is controversy about the best term if any to identify the various groups of people that may have self-reported as one of these categories among the options provided in the survey where the data came from. It is a limitation of the data that more specific racial and ethnic information is not available. We will stick with the abbreviation definitions provided in the tables simply to remain consistent with the original data.

To do this we will use the str_replace() function.

percents %<>% mutate(Demographic = str_replace(string = Demographic, 
                                             pattern = "AIAN",
                                         replacement = "American Indian and Alaska Native"))

percents %<>% mutate(Demographic =  str_replace(string = Demographic, 
                                             pattern = "NHOPI",
                                         replacement = "Native Hawaiian or Other Pacific Islander"))

counts %<>% mutate(Demographic = str_replace(string = Demographic, 
                                             pattern = "AIAN",
                                         replacement = "American Indian and Alaska Native"))

counts %<>% mutate(Demographic =  str_replace(string = Demographic, 
                                             pattern = "NHOPI",
                                         replacement = "Native Hawaiian or Other Pacific Islander"))

Let’s check that this worked.

percents %>% 
  distinct(Demographic)%>%
  pull(Demographic)
 [1] "TOTAL"                                    
 [2] "Age: 12-13"                               
 [3] "Age: 14-15"                               
 [4] "Age: 16-17"                               
 [5] "Male"                                     
 [6] "Female"                                   
 [7] "Not Hispanic or Latino"                   
 [8] "White"                                    
 [9] "Black or African American"                
[10] "American Indian and Alaska Native"        
[11] "Native Hawaiian or Other Pacific Islander"
[12] "Asian"                                    
[13] "Two or More Races"                        
[14] "Hispanic or Latino"                       
counts %>% 
  distinct(Demographic)%>%
  pull(Demographic)
 [1] "TOTAL"                                    
 [2] "Age: 12-13"                               
 [3] "Age: 14-15"                               
 [4] "Age: 16-17"                               
 [5] "Male"                                     
 [6] "Female"                                   
 [7] "Not Hispanic or Latino"                   
 [8] "White"                                    
 [9] "Black or African American"                
[10] "American Indian and Alaska Native"        
[11] "Native Hawaiian or Other Pacific Islander"
[12] "Asian"                                    
[13] "Two or More Races"                        
[14] "Hispanic or Latino"                       

Looks good!

We finished wrangling the data and we are ready to proceed with our analysis. Let’s save our data first. This will allow us to come back without running our previous code. We will save it as an rda file and as a csv file as this is useful to give to collaborators. We will save this in a directory called “wrangled” within our “data” directory of our project. We will use the write_csv() function from the readr package to do this. We need to do this for each tibble separately.

save(percents, counts, table11.1a, table11.1b, 
     file = here::here("data", "wrangled", "wrangled_data.rda"))
readr::write_csv(percents, path = here::here("data", "wrangled", "percents.csv"))
readr::write_csv(counts, path = here::here("data", "wrangled", "counts.csv"))
readr::write_csv(table11.1a, path = here::here("data", "wrangled", "table11.1a.csv"))
readr::write_csv(table11.1b, path = here::here("data", "wrangled", "table11.1b.csv"))

Data Visualization


If you have been following along but stopped, you can load your data like so:

load(file = here::here("data", "wrangled", "wrangled_data.rda"))
If you skipped the data wrangling section click here.

First you need to install and load the OCSdata package:

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

Then, you may load the wrangled data using the following code:

wrangled_rda("ocs-bp-youth-mental-health", outpath = getwd())
load(here::here("OCSdata", "data", "wrangled", "wrangled_data.rda"))

If the package does not work for you, alternatively, an RDA file (stands for R data) of the data can be found here or slightly more directly here. Download this file and then place it 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 file more easily.

load(here::here("data", "wrangled", "wrangled_data.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.



In this section, we will create some data visualizations to explore our data and questions of interest:

Our main questions:

  1. How have depression rates in American youth changed since 2004, according to the NSDUH data? How have rates differed between different youth subgroups (age, gender, ethnicity)?
  2. Do mental health services appear to be reaching more youths? Again, how have rates differed between different youth subgroups (age, gender, ethnicity)?

We are going to use the ggplot2 package to create our plots.


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

The ggplot2 package is a great place to start for beginners because it is based on a grammar of graphics , which is what the gg stands for in ggplot2.

The idea is that there are specific functions and arguments (or “words”) that we will need to learn that can be used in many different combinations 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.


MDE Across Time


We will start by taking a look at the rate of major depressive episodes (MDE) among youths across time in various demographic groups. For this we will use the percents dataset that we wrangled in the section above.

OK, we will start out by using the ggplot() function to specify what data we would like to plot on each axis. We will also indicate that we would like to use the Demographic variable in our dataset to group our data and to color our data. This is our first layer of the plot, thus for subsequent layers we need to use a plus sign +.

Next, we will use the geom_line() function of the ggplot2 package to specify that we would like to create a line plot.

Then, we will add labels for the title and subtitle using the labs() function of the ggplot2 package.

Finally, we will move our legend to the bottom of the plot using the theme() function which helps us control various details about our plot.

percents %>%
  filter(data_type == "Major_Depressive_Episode") %>%
  ggplot2::ggplot(aes(x = Year, y = Percent, 
                      color = Demographic)) +
      geom_line(size = 1) +
      labs(title = "Major Depressive Episode among Persons Aged 12 to 17",
           subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
  theme(legend.position = "bottom")

This plot is very difficult to read because there are so many groups.

Now let’s look at just the total across time. We can do so by first filtering our data for TOTAL values.

It would also be nice to include every year in the x-axis. We can do so by using the scale_x_continuous() function which gives us greater control about how the x-axis is displayed.

Finally, we will drop the legend since we will only have one group using legend.position = "none" and we can change the angle of the x-axis text using axis.text.x = element_text(angle = 90) within the theme() function.

We will also make the line thicker using the size = argument for the geom_line() function.

The theme_classic() function changes the aesthetics of the plot. See here for a list of options.

MDE_total <- percents %>%
  filter(data_type == "Major_Depressive_Episode", 
         Demographic == "TOTAL") %>%
  ggplot(aes(x = Year, y = Percent, color = Demographic)) +
  geom_line(aes(color = Demographic), size = 1.5) +
  scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                     labels = seq(2004, 2018, by = 1),
                     limits = c(2004, 2018)) +
  labs(title = "Percent of Persons Aged 12 to 17 Reporting Having a \n Major Depressive Episode in the Past Year ") +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "none") 

MDE_total

We can see that there is a steep increase after around 2011!

Let’s add a different background color to highlight the years since 2011. We can do so by adding a geom_rect() layer before we plot the line. We just need to specify the location of the rectangle on our plot.

We will add a facet using the facet_wrap() function to add strip of text to the top of the plot to tell more about what is contained within the plot. This function is typically used to create subplots which we will demonstrate next.

We will use the strip.background and strip.text of the theme() function to specify how the text at the top of the plot will look.

We want to change the value TOTAL of the Demographic variable to "Percent of respondants with MDE" so that the text in the strip above the plot shows this instead. We can do so by using the recode() function of the dplyr package.

We will also change the color of the line using the scale_color_manual() function of the ggplot2 package.

MDE_total <- percents %>%
  filter(data_type == "Major_Depressive_Episode", 
         Demographic == "TOTAL") %>%
  mutate(Demographic = recode(Demographic, 
             "TOTAL" = "Percent of respondents with MDE"))%>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
    facet_wrap( ~ Demographic)+
    geom_rect(xmin = 2011, xmax = Inf,  
              ymin = -Inf, ymax = Inf,  
              fill = "light gray") +
    geom_line(aes(color = Demographic), size = 1.5) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) +
    labs(title = "The Rate of Youths Aged 12 to 17 Reporting Having a \n Major Depressive Episode (MDE) is Increasing")+
    theme_classic() +
    theme(axis.text.x = element_text(angle = 90),
          legend.position = "none",
          strip.background = element_rect(fill ="black"),
          strip.text = element_text(face = "bold", 
                                    size = 14, 
                                    color = "white")) +
    scale_color_manual(values = c("blue"))

MDE_total

Nice!

Now let’s say we wanted to save this plot.

We could do so using the using the save() function to save this to a “plots” directory in our working directory as an rda file and we can use the png() function to save a png for collaborators. We need to use dev.off() function to close the graphical device that we will use to create the png version of the plot so that we are ready to make another plot like this.

save(MDE_total, file =here::here("plots", "MDE_total.rda"))
png(here::here("plots", "MDE_total.png"))
MDE_total
dev.off()
png 
  2 

Question Opportunity

What do you expect will happen when if we had used the + symbol to add the geom_rect() function with MDE_total like so? Is that what you anticipated? Why or why not?

MDE_total + 
  geom_rect(xmin = 2011, xmax = Inf,  
            ymin = -Inf, ymax = Inf,  
            fill = "light gray")

We can create a theme for our future similar ggplots like so:

ocs_theme <- function() {
  theme_classic() +
  theme(axis.text.x = element_text(angle = 90),
        strip.background = element_rect(fill = "black"),
        strip.text = element_text(face = "bold",
                                  size = 14,
                                  color = "white"))
  }

You will notice that we didn’t use legend.position = "none" so that this theme is flexible for plots that we do want to plot a legend.

Now let’s look at group differences.

To make sure our plot is not too overwhelming, let’s limit to only age and gender subgroups. Thus, we will filter out the data about totals and different racial/ethnic groups for now. We will also use the facet_wrap() function to make subplots based on the demographic categories, which we put in a variable called subgroups earlier when we wrangled the data.

MDE_age_gender <-percents %>%
  filter(data_type == "Major_Depressive_Episode", 
         subgroup != "Race/Ethnicity", 
         Demographic != "TOTAL") %>%
  ggplot(aes(x = Year, y = Percent, color = Demographic)) +
    geom_line(aes(color = Demographic), size = 1) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) +
    labs(title = "Major Depressive Episode among Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    facet_wrap(~ subgroup) +
    ocs_theme()

MDE_age_gender

Nice! Now it is much easier to tell how each group has changed over time.

We can also add labels directly to the lines using the directlabels package. There are several methods to do so. See here for more information about the options for adding labels with this package.
We use the "far.from.others.borders" method so that our labels do not overlap one another. We also use dl.trans() of the directlabels package to move the labels slightly upward (y = y +0.35) and to the left (x = x -0.1). The dl.move() function of the directlabels package is used to move one of the labels to a particular location.

Note: the dl.move functions are set up for the rendering the R Markdown - so if you are viewing the case study from RStudio the labels will overlap.

We can modify the size of the labels with the cex argument and the style of the font with the fontface argument.

MDE_age_gender <- directlabels::direct.label(
  MDE_age_gender, 
  list(dl.trans(y = y + 0.38, x = x -0.1), 
       "far.from.others.borders",
       cex = .8, 
       fontface=c("bold"), 
       dl.move("Age: 14-15", x = 2007, y = 9.7))
  )

MDE_age_gender 

Finally, let’s color the different age groups in order of age by intensity of color shade.

Let’s also get the colors that we previously used so that we can color the Male and Female groups in a consistent way across our various future plots. This time we can use the show_col() function and the hue_pal() functions of the scales package to see what the hexadecimal code (called hex) for these colors.

It would be nice to switch the colors for males and females so that they might fit what people would expect to avoid confusion and aid in interpretation.

scales::show_col(scales::hue_pal()(6))

Let’s make the age groups different shades of green.

We can get additional shades using the same function but specifying more colors to decide if we want a different color.

scales::show_col(scales::hue_pal()(30))

We can save a few different shades of colors fading from gold to green for the different age groups.

age_col_light <- c("#B79F00")
age_col<- c("#6BB100")
age_col_dark<- c("#00BD5F")

We can also save the male and female colors as more easily recognizable objects to use later.

Female_col <-c("#F564E3")
Male_col <- c("#619CFF")

Now we can change the colors using the scale_color_manual() function and listing the colors in order as they appear in the data.

MDE_age_gender <- MDE_age_gender  +
  scale_color_manual(values = c(age_col_light, 
                                age_col, 
                                age_col_dark, 
                                Female_col, 
                                Male_col))

MDE_age_gender

This looks very clear now!

We can see that the majority of individuals that reported experiencing a major depressive episode in the past year were in an older age bracket (16-17 compared to 12-13). We can also see that the trend has been increasing for all three age brackets since roughly 2011.

We can also see an increase for both genders since about 2011, but there is a steeper increase for females. Furthermore, females have a much higher percentage than males across all years.

Let’s make the same plot with a different shaded background for the years of the increase like we did for the total plot.

Question Opportunity

Try to come up with the code for this plot on your own before you reveal it.


Click here to reveal the code.
MDE_age_gender <-
  percents %>%
  filter(data_type == "Major_Depressive_Episode", 
         subgroup != "Race/Ethnicity", 
         Demographic != "TOTAL") %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
    geom_rect(xmin = 2011, xmax = Inf,  
              ymin = -Inf, ymax = Inf,  
              fill = "light gray") +
    geom_line(aes(color = Demographic), size =1) +
    scale_x_continuous(breaks = seq(2004, 2018, by=1),
                       labels = seq(2004, 2018, by=1),
                       limits = c(2004, 2018)) +
    labs(title = "Major Depressive Episode\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    facet_wrap(~ subgroup) +
    ocs_theme()

MDE_age_gender <- direct.label(
  MDE_age_gender, 
  list(dl.trans(y = y +0.38, x = x -0.2), 
       "far.from.others.borders", 
       cex = .8,
       fontface = "bold",
       dl.move("Age: 14-15", x = 2008, y =10))
  ) + 
  scale_color_manual(values = c(age_col_light, 
                                age_col, 
                                age_col_dark, 
                                Female_col, 
                                Male_col))

MDE_age_gender

Let’s save this plot as well:

save(MDE_age_gender, file =here::here("plots", "MDE_age_gender.rda"))
png(here::here("plots", "MDE_age_gender.png"))
MDE_age_gender
dev.off()
png 
  2 

Nice!

In the next section, we will formally test whether Gender is independent of the differences in rates of MDE across time.

To do this, we will test whether there is a statistically significant difference between the expected frequencies and the observed frequencies in one or more categories of a contingency table.

While, it is very intriguing that there is an increase around 2011, we do not go into details here as to why that might be happening.

However, we summarize a few articles that did investigate increased depression rates.


Click here for a summary on a few articles investigating increased depression rates.

This cross-cultural review article published in 2012 suggests that aspects related to life-style due to modernity may be causing increased depression rates:

Modern populations are increasingly overfed, malnourished, sedentary, sunlight-deficient, sleep-deprived, and socially-isolated. These changes in lifestyle each contribute to poor physical health and affect the incidence and treatment of depression.

And although this may be true globally, the US has been arguably experiencing these modern lifestyle changes for years prior to this steep increase in 2011.

So what might have happened in the US around this time?

There is large amount of literature about how the use of smart phone and social media may have lead to increased depression rates. See this article which links to many scientific articles on the subject.

This has been a controversial topic due to conflicting findings, likely due to focus on different sites and aspects of social media across different studies.

The article points out that the true relationship between social media use and depression may be nuanced. Some individuals who have high face-to-face levels of interaction or lack of the opportunity to interact with others face-to-face (due to various barriers like geography), may actually experience lower risk for depression with more social media use.

Furthermore, different social media platforms may vary for their influence on depression.

Instagram was released in 2010 (which is around when our plot starts to show the upward increase in major depressive episodes, particularly in females) and according to the article:

Image-driven Instagram shows up in surveys as the platform that most leads young people to report feeling anxiety, depression and worries about body image.

Furthermore, it may be secondary effects of social media use, like less physical activity or less sleep that may increase the risk for depression.


Next, let’s take a look at how the rate of major depressive episodes has changed across time for different racial/ethnic groups.

Since we have so many groups, we probably don’t want to directly label the lines this time. Instead, we will rely on the legend that will be automatically created.

We will use the the fct_reorder() function of the forcats package to order the racial/ethnic groups in the legend based on the last value (using tail()) of the Percent variable.

We will also manually color our lines based on a color palette called viridis, which is more discernible for individuals with color-blindness. To do so we will use the scale_color_viridis_d() function of the ggplot2 package, which is intended for coloring discrete values.

MDE_race <- percents %>%
  filter(data_type == "Major_Depressive_Episode", 
         subgroup == "Race/Ethnicity") %>%
  mutate(Demographic = forcats::fct_reorder(Demographic, Percent,
                                            tail, n = 1, .desc = TRUE)) %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
    geom_rect(xmin = 2011, xmax = Inf,   
              ymin = -Inf, ymax = Inf,   
              fill = "light gray") +
    geom_line(aes(color = Demographic), size = 1) +
    facet_wrap( ~ subgroup) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) +
    scale_color_viridis_d() +
    labs(title = "Major Depressive Episode\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    ocs_theme()

MDE_race

Unfortunately, there is only one value for the Native Hawaiian or Other Pacific Islander group, thus since this is a line plot, we do not have enough points (2 at minimum) to create a line, so lets remove this group from the plot to remove the group from the legend.

Question Opportunity

How might we remove the Native Hawaiian or Other Pacific Islander group from the legend?

Click here to reveal the code.
MDE_race <- percents %>%
  filter(data_type == "Major_Depressive_Episode", 
         subgroup == "Race/Ethnicity", 
         Demographic != "Native Hawaiian or Other Pacific Islander") %>%
  mutate(Demographic = fct_reorder(Demographic, Percent,
                                   tail, n = 1, .desc = TRUE)) %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
    geom_rect(xmin = 2011, xmax = Inf,   
              ymin = -Inf, ymax = Inf,   
              fill = "light gray") +
    geom_line(aes(color = Demographic), size = 1) +
    facet_wrap( ~ subgroup) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) +
    scale_color_viridis_d() +
    labs(title = "Major Depressive Episode\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    ocs_theme()

We can see that the group of individuals who reported as being two or more races, had the highest percentages of having a major depressive episode in the past year. Those group who reported as Black or African American had the lowest percentages. However, we can see that most of the racial/ethnic groups are fairly similar and we see an increasing for most groups since around 2011. Keep in mind the limitations listed in the Limitations section as you view these findings. It is possible that this group may be less likely to report experiencing symptoms of depression.

Let’s save this plot too:

save(MDE_race, file =here::here("plots", "MDE_race.rda"))
png(here::here("plots", "MDE_race.png"))
MDE_race
dev.off()
png 
  2 

MDE with Severe Impairment


Now let’s take a look at how the overall rate of youths reporting having a major depressive episode (MDE) with severe impairment has changed over time. See the What are the data? section about how severe impairment was defined.

Question Opportunity

Try to come up with the code for the following two plots on your own before you reveal it. This time we will remove the legend using the theme() function.

Click here to reveal the code.
MDES_total <- percents %>%
  filter(data_type == "Severe_Major_Depressive_Episode",
         Demographic == "TOTAL") %>% 
  mutate(Demographic = recode(Demographic, 
             "TOTAL" = "Percent of respondents with Severe MDE")) %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
    geom_rect(xmin = 2011, xmax = Inf,  
              ymin = -Inf, ymax = Inf,  
              fill = "light gray") +
    geom_line(aes(color = Demographic), size = 1) +
    scale_x_continuous(breaks = seq(2006, 2018, by = 1),
                     labels = seq(2006, 2018, by = 1),
                     limits = c(2006, 2018)) +
    labs(title = "Major Depressive Episode with Severe Impairment\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    facet_wrap( ~ Demographic) +
    ocs_theme() +
    theme(legend.position = "none") +
    scale_color_manual(values = c("blue"))
MDES_total

Next let’s look at age groups and gender differences:

Click here to reveal the code.
MDES_age_gender <-
  percents %>%
  filter(data_type == "Severe_Major_Depressive_Episode", 
         subgroup != "Race/Ethnicity", 
         Demographic != "TOTAL") %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
    geom_rect(xmin = 2011, xmax = Inf,  
              ymin = -Inf, ymax = Inf,  
              fill = "light gray") +
    geom_line(aes(color = Demographic), size = 1)+
    scale_x_continuous(breaks = seq(2006, 2018, by = 1),
                      labels = seq(2006, 2018, by = 1),
                       limits = c(2006, 2018)) +
    labs(title = "Major Depressive Episode with Severe Impairment\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    facet_wrap( ~ subgroup) +
    ocs_theme()

MDES_age_gender  <- direct.label(
  MDES_age_gender, 
  list(dl.trans(y = y +0.39, x = x -0.1), 
       "far.from.others.borders",
       cex = .8, 
       fontface = "bold",
       dl.move("Age: 14-15", x= 2016.5, y = 11))
  ) +
  scale_color_manual(values = c(age_col_light, 
                                age_col, 
                                age_col_dark, 
                                Female_col, 
                                Male_col))

We can see that the majority of individuals that reported experiencing a major depressive episode with severe impairment were in an older age bracket. However, there appears to be a more dramatic change in the middle age group from 2011-2012. We can see a very steep increase in the data for the females after 2011, again this is much more steep than the increase seen for males over time.

Now let’s look at different racial/ethnic groups.

Question Opportunity

Try to come up with the code for this plot on your own before you reveal it.

Click here to reveal the code.
Race_MDES <- percents %>%
  filter(data_type == "Severe_Major_Depressive_Episode", 
         subgroup == "Race/Ethnicity") %>%
  mutate(Demographic = 
           fct_reorder(Demographic, Percent, 
                       tail, n = 1, .desc = TRUE)) %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
    geom_rect(xmin = 2011, xmax = Inf,  
              ymin = -Inf, ymax = Inf,  
              fill = "light gray") +
    geom_line(aes(color = Demographic), size =1) +
    facet_wrap(~ subgroup) +
    scale_x_continuous(breaks = seq(2006, 2018, by = 1),
                       labels = seq(2006, 2018, by = 1),
                       limits = c(2006, 2018)) +
    labs(title = "Major Depressive Episode with Severe Impairment\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics: Percentages, 2006-2018") +
    ocs_theme() +
    scale_color_viridis_d()

We see similar trends as we saw for the previous racial/ethnic group plot. The rate is highest for those who are two are more races and lowest for those who are Black or African American. The data for the American Indian and Alaska Native group is sparse, so it is unclear if their levels would be lowest on the last year.

MDE Treatment


Now we will take a look at those who reported having a MDE and received treatment for depression.

First, let’s look overall using the Demographic == "TOTAL" group. We will remove the legend for this plot.

Question Opportunity

Try to come up with the code for this plot on your own before you reveal it.


Click here to reveal the code.
Treat_total <- percents %>%
  filter(data_type == "Treatment", 
         Demographic == "TOTAL") %>%
  mutate(Demographic = recode(Demographic, 
             "TOTAL" = "Percent of MDE respondents with treatment")) %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
    geom_rect(xmin = 2011, xmax = Inf,  
              ymin = -Inf, ymax = Inf,   
              fill = "light gray") +
    geom_line(aes(color = Demographic), size = 1.5) +
    facet_wrap(~Demographic) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) +
    labs(title = "The Rate of Youths Aged 12 to 17 Receiving Treatment after\nReporting Having a Major Depressive Episode is Increasing") +
    ocs_theme() +
    theme(legend.position = "none") +
    scale_color_manual(values = c("blue"))

Treat_total

Overall, roughly 40 percent of youths who self-reported experiencing a major depressive episode, also received treatment for depression. Thus the majority of youths reporting major depressive episode symptoms are not receiving treatment.

This shows an overall increase in the rate in which youths are receiving treatment since 2011, like the trend seen for the number of youths reporting having had a major depressive episode, yet the data for treatment are much more variable from one year to the next.

Next, we consider differences between males and females and different age groups.

First let’s save this plot:

save(Treat_total, file =here::here("plots", "Treat_total.rda"))
png(here::here("plots", "Treat_total.png"))
Treat_total
dev.off()
png 
  2 

Question Opportunity

Try to come up with the code for this plot on your own before you reveal it.


Click here to reveal the code.
treat <- percents %>%
  filter(data_type == "Treatment", 
         subgroup != "Race/Ethnicity", 
         subgroup != "Total") %>%
  ggplot(aes(x = Year, y = Percent, color = Demographic)) +
    geom_line(size = 1) +
    facet_wrap( ~ subgroup) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) + 
    labs(title = "Receipt of Treatment for Depression among\nPersons Aged 12 to 17 with Major Depressive Episode",
         subtitle = "By Demographic Characteristics: Percentages, 2004-2018") +
    ocs_theme()

treat <- direct.label(
  treat, 
  list(dl.trans(y = y -1.5, x = x -0.4),
       "far.from.others.borders", 
       cex = .8, 
       fontface = "bold",
       dl.move("Age: 16-17", x = 2010, y = 42),
       dl.move("Age: 14-15", x = 2015, y = 38))
  ) +
  scale_color_manual(values = c(age_col_light, 
                                age_col, 
                                age_col_dark, 
                                Female_col, 
                                Male_col))

treat

There seems to be an upward trend, but it isn’t nearly as much as the trend we saw for the increase of major depressive episodes. In general, the data seems to vary much more as well.

Question Opportunity

Create a similar plot on your own for the different race / ethnic groups.

Click here to reveal the code.
Race_treat <- percents %>%
  filter(data_type == "Treatment") %>%
  filter(subgroup == "Race/Ethnicity") %>%
  mutate(Demographic = 
           fct_reorder(Demographic, Percent, 
                       tail, n = 1, .desc = TRUE)) %>%
  ggplot(aes(x = Year, y = Percent, color = Demographic)) +
    geom_line(size = 1) +
    facet_wrap( ~ subgroup) +
    scale_x_continuous(breaks = seq(2009, 2018, by = 1),
                       labels = seq(2009, 2018, by = 1),
                       limits = c(2009, 2018)) +
    labs(title = "Receipt of Treatment for Depression among\nPersons Aged 12 to 17 with Major Depressive Episode",
         subtitle = "By Demographic Characteristics: Percentages, 2004-2018") +
    ocs_theme() +
    scale_color_viridis_d()

It looks as though youths who report as being white received the most care from mental health services.

Mental Health Services


We will also take a look at where youths are receiving treatment by using values from table11.1b which has the percentage values for counts presented in table11.1a.

We can use the str_detect() function of the stringr package to filter for the values of the short_label variable that has the word total in it.

plotMHS <- table11.1b %>%
  filter(stringr::str_detect(short_label, "total") ) %>%
  ggplot(aes(x = Year, y = Percent, 
             group = MHS_setting, color = short_label)) +
    geom_line(size = 1) +
    facet_wrap( ~ type) +
    scale_x_continuous(breaks = seq(2009, 2018, by = 1),
                                labels = seq(2009, 2018, by = 1),
                                limits = c(2009, 2018)) +
    labs(title = "Settings Where Mental Health Services Were Received\namong Persons Aged 12 to 17",
         subtitle = "Percentages, 2002-2018") +
    ocs_theme()

plotMHS <- direct.label(
  plotMHS, 
  list(dl.trans(y = y +0.35, x = x -0.1),
       "far.from.others.borders", 
       cex = .8, 
       dl.move("Outpatient total", x = 2015, y =11))
  )

plotMHS

We can see that youths appear to be receiving care in nonspecialty facilities at a slightly higher rate than that of specialty facilities. See here for more information about these different types of mental health services. A nonspecialty facility provides general health treatment and other services, such as a typical hospital or a school. A specialty facility, in contrast, focuses on the treatment of mental health. Outpatient services are those in which the patient does not stay overnight for even one night at the hospital or treatment facility, while inpatient services are those in which the patient stays overnight for at least one night at the care facility.

However, the rates appear to be very similar and the relative differences appear to be consistent across time.

Let’s take a look at subcategories of mental health services. To do this, we will filter for values within the short_label variable that do not contain the word “total” by using a ! in front of the str_dectect statement.

plotMHSS <- table11.1b %>%
  filter(!str_detect(short_label, "total")) %>%
  ggplot(aes(x = Year, y = Percent, 
         group = MHS_setting, color = short_label)) +
    geom_line(size = 1) +
    facet_wrap( ~ type) +
    scale_x_continuous(breaks = seq(2002, 2019, by = 1),
                       labels = seq(2002, 2019, by = 1),
                       limits = c(2002, 2019)) +
    labs(title = "Settings Where Mental Health Services Were Received\namong Persons Aged 12 to 17",
         subtitle = "Percentages, 2002-2018") +
    ocs_theme() 

plotMHSS <- direct.label(
  plotMHSS, 
  list(dl.trans(y = y +0.3),
       "far.from.others.borders", 
       dl.move("School Therapist", 2010, 10), 
       dl.move("Fostercare", 2010, 1), 
       dl.move("Therapist", x=2009, y = 10.5))
  )

plotMHSS

It looks like most youths are receiving care from either a therapist or a school therapist.

OK, so now we know how the rates of different subgroups compare for having a MDE in the past year, having a MDE with severe impairment, and receiving treatment after a MDE. We also know where youths are typically getting treatment. But, how do the rates of having a MDE in the past year, having a MDE with severe impairment, and receiving treatment compare within each subgroup (e.g. just females)?

This is what we tackle in the next section.

Overall Outcomes by Group


In the next plot, we first filter for Male, Female and Total and then facet by the Demographic variable. We will use different types of lines to indicate the different outcome values by using the scale_linetype_manual() function. We can use the ggthemes package and the scales package in order to see all the current options for different linetypes.

ggthemes::show_linetypes(scales::linetype_pal()(12), labels = TRUE)

We can now use the labels for the different types of lines in the scale_linetype_manual() function to specify specific linetypes.

We will also use the guides() function of the ggplot2 package to remove the legend specifically for the color, not for the linetype by using `guides(color = FALSE).

gender_outcomes <- 
  percents %>%
  filter(Demographic %in% c("Male", "Female", "TOTAL")) %>%
  ggplot(aes(x = Year, y = Percent, color = Demographic)) +
    geom_line(aes(linetype = data_type), size = 1) +
    scale_linetype_manual(values = c("solid", "2262", "13")) +
    scale_color_manual(values = c(Female_col, Male_col, "black")) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) +
    labs(title = "Major Depressive Episodes and Treatment Among Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    facet_wrap( ~ Demographic, strip.position = "top") +
  ocs_theme() +
  theme(legend.title = element_blank(),
        legend.position = "bottom") +
    guides(color = FALSE)

gender_outcomes 

We can see that a large portion of individuals experiencing a major depressive episode have an episode with severe impairment for each group. Females have a higher rate of both types of episode and of treatment. Although females have more than double the rate of reported episodes, they receive a relatively similar rate of treatment as males for depression. This suggests that females are either more likely than males to self-report depression symptoms in surveys, or females may not be receiving as much care despite the larger need.

Question Opportunity

Create a similar plot on your own for different age groups.

Click here to reveal the code.
age_outcomes <-percents %>%
  filter(subgroup == "Age") %>%
  ggplot(aes(x = Year, y = Percent, color = Demographic)) +
    geom_line(aes(linetype= data_type), size = 1) +
    scale_linetype_manual(values = c("solid", "2262", "13")) +
    scale_color_manual(values = c(age_col_light, age_col, age_col_dark)) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) +
    labs(title = "Major Depressive Episode\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    facet_wrap( ~ Demographic, strip.position = "top")+
  ocs_theme() +
  theme(legend.title = element_blank(),
        legend.position = "bottom") +
    guides(color = FALSE)

All age groups show a similar ratio of severe major depressive episodes for those that experienced an episode.

Question Opportunity

Create a similar plot on your own for the different race / ethnic groups.

Click here to reveal the code.
race_outcomes <- percents %>%
  filter(subgroup == "Race/Ethnicity", 
         Demographic != "Native Hawaiian or Other Pacific Islander") %>%
  ggplot(aes(x = Year, y = Percent, color = Demographic)) +
    geom_line(aes(linetype = data_type), size=1) +
    scale_linetype_manual(values = c("solid", "2262", "13")) +
    scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                       labels = seq(2004, 2018, by = 1),
                       limits = c(2004, 2018)) +
    labs(title = "Major Depressive Episode\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    facet_wrap( ~ Demographic, strip.position = "top", nrow = 4) +
  ocs_theme() +
  theme(legend.title = element_blank(),
        legend.position = "bottom") +
    guides(color = FALSE)

All racial and ethnic groups also show a similar rate of severe episodes relative to general episode rate. The rate of receiving treatment is fairly similar relative to the percentage of youths that reported having symptoms for each group.

Data Analysis


If you have been following along but stopped, you can load your data like so:

load(file = here::here("data", "wrangled", "wrangled_data.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 wrangled data using the following code:

wrangled_rda("ocs-bp-youth-mental-health", outpath = getwd())
load(here::here("OCSdata", "data", "wrangled", "wrangled_data.rda"))

If the package does not work for you, alternatively, an RDA file (stands for R data) of the data can be found here or slightly more directly here. Download this file and then place it 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 file more easily.

load(here::here("data", "wrangled", "wrangled_data.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.



Recall what our main questions were:

Our main questions:

  1. How have depression rates in American youth changed since 2004, according to the NSDUH data? How have rates differed between different youth subgroups (age, gender, ethnicity)?
  2. Do mental health services appear to be reaching more youths? Again, how have rates differed between different youth subgroups (age, gender, ethnicity)?

We are specifically interested in how the frequency of recent major depressive episodes among youths differ compared to those in 2004. We are also interested how different subgroups differ. We will start with examining how male and females differ across time.

Chi-Squared Test


Our first question is: Is the rate of reported major depressive episodes across the two years associated with gender?

Since we have counts for the two genders: males and females, and for the two years of interest, 2004 and 2018, we can conduct a Pearson’s chi-squared test for independence, which is also written like this: \({\chi}^2\).

This will allow us to compare if the relative frequencies of major depressive episodes differs from what we would expect by chance if the variables years and gender were independent.

According to wikipedia:

Pearson’s chi-squared test is used to determine whether there is a statistically significant difference between the expected frequencies and the observed frequencies in one or more categories of a contingency table.

The null hypothesis is that the variables are indeed independent, or that the difference in the proportion of observed to expected frequencies is equal to zero.

Thus, to conduct this statistical test, we first need to create a contingency table, which in this case could also be called a 2x2 table, which is the simplest kind of contingency table (only two levels for two variables).

Before we create a contingency table for our data and use the chi-squared test, let’s practice this with a different example.

Click here for an example and more explanation of the Pearson’s chi-squared test.

Consider a hypothetical scenario where we sample 100 individuals and report a contingency table representing the number of hypothetical individuals that we observed who are left and right handed, stratified by males and females (assuming all individuals had binary gender).

observed <- tibble(Gender = c("Male", "Female", "Total"), 
                   Righthanded = c(41,47,88), 
                   Lefthanded = c(9,3, 12), 
                   Total = c(50,50,100))

observed
# A tibble: 3 x 4
  Gender Righthanded Lefthanded Total
  <chr>        <dbl>      <dbl> <dbl>
1 Male            41          9    50
2 Female          47          3    50
3 Total           88         12   100

We can see that there are two variables: Gender and Handedness and each have two levels (Male and Female for Gender and Righthanded and Lefthanded for Handedness).

The table also includes totals of each of the 4 possible groups as well as the overall total.

Next, we create a table of what we expect assuming Gender and Handedness are independent.

  • The total number of individuals who are right-handed is 88 out of 100 which is equal to 88%.
  • The total number of individuals who are left-handed is 12 out of 100 which is equal to 12%.

Thus, if each both Male and Females had the same amount of right-handedness and left-handedness, we would expect 88% of the males to be right-handed and 12% to be left-handed; and we would expect the exact same proportions of 88% right-handed and 12% left-handed for the females.

Since we have 50 males and 50 females and 12% of 50 is 6 and 88% of 50 is 44, we would thus have the following table of expected frequencies:

expected <- tibble(Gender = c("Male", "Female", "Total"), 
                   Righthanded = c(44,44,88), 
                   Lefthanded = c(6,6, 12), 
                   Total = c(50,50,100))

expected
# A tibble: 3 x 4
  Gender Righthanded Lefthanded Total
  <chr>        <dbl>      <dbl> <dbl>
1 Male            44          6    50
2 Female          44          6    50
3 Total           88         12   100

The \({\chi}^2\) test statistics is calculated using the observed (O) and expected (E) frequencies we just calculated above using the following formula:

\[{\chi}^2=\sum_{j=1}^{m} \frac{(O_j - E_j)^2}{E_j}\]

where \(O_j = j^{th}\) observed count and \(E_j = j^{th}\) expected count for the \(j^{th}\) cell of a contingency table with \(m\) cells.

The degrees of freedom (\(df\)) is calculated like so: \(df= (r-1)(c-1)\). Note that as according to Wikipedia: “degrees of freedom is the number of values in the final calculation of a statistic that are free to vary” or “the number of independent pieces of information that go into the estimate of a parameter”.

Where \(r\) = # of rows and \(c\) = the # of columns.

So to calculate the \({\chi}^2\) test statistics for handedness and gender manually, we can do the following for each of the four values in the table (ignoring the Totals) like this:

\[{\chi}^2 = \frac{(41-44)^2}{44} + \frac{(9-6)^2}{6}+ \frac{(47-44)^2}{44}+ \frac{(3-6)^2}{6}\]

Where we calculate the fraction of the square difference of the observed minus the expected, divided by expected for:

  1. right-handed males
  2. left-handed males
  3. right-handed females
  4. left-handed females

After summing these individual terms together, this is equal to

\({\chi}^2\) = 3.4090909

Where the degrees of freedom = \(df = (92-1)(2-1) = 1\)

What does this mean? We need to consult a chi-squared distribution to determine what the \(p\)-value is and if this is significant.

[source]

This website has a simple way to check this, without requiring you to get out a ruler and consult this plot. (Note on this website the notation for \(df\) is \({\nu}\).)

Plugging in 3.409091 as \({\chi}^2\) and 1 as \({\nu}\), we get a \(p\)-value of 0.06484.

Thus, we do not have enough evidence to reject the null hypothesis.

Therefore, our data do not provide evidence to suggest that gender and handedness are related.

See here for a more thorough explanation of the chi-squared test.

Gender and MDE Analysis


Now let’s create a contingency table with our own data and see how we can implement this test in R.

It is critical that we use the counts data, and not the percentage data for our analysis, as the \({\chi}^2\) test requires counts.

We will filter the count data for the Major_Depressive_Episode data, as well as for the Male and Female data from 2004 and 2018.

The following code subsets the data we need and makes the necessary manipulations so that the units of observation are appropriate. If we take a look at the title of the table we can see that the numbers in the table represent individuals by the thousands.

chi_squared_11.2a <- counts %>%
  filter(data_type == "Major_Depressive_Episode") %>%
  filter(Year %in% c(2004, 2018)) %>%
  filter(Demographic %in% c("Male", "Female")) %>%
  mutate(Number = Number * 1000) # becuase the numbers are in thousands

The resulting object contains all the values we need for out contingency table.

chi_squared_11.2a
# A tibble: 4 x 5
  Demographic subgroup data_type                 Year  Number
  <chr>       <chr>    <chr>                    <dbl>   <dbl>
1 Male        Gender   Major_Depressive_Episode  2004  637000
2 Male        Gender   Major_Depressive_Episode  2018  946000
3 Female      Gender   Major_Depressive_Episode  2004 1588000
4 Female      Gender   Major_Depressive_Episode  2018 2537000

A contingency table can now be produced from this data (which currently is in long format) by transforming the data to wide format and re-purposing some values as row names. To reformat the data to wide format, we can use the pivot_wider() function of the tidyr package.

For this function there are several important arguments:

  1. names_from - this is the variable where the names of new columns will come from
  2. values_from - this is the variable where the values for the new columns will come from
  3. names_prefix - if we want to add a prefix to the new columns we can do so using this argument

In our case, we want to spread out the year data into two columns thus the names will come from the Year variable and the values will come from the Number variable. We want to add the word Year to the new columns. We also want the remove the subgroup and data_type variables and only keep the Demographic, Year, and Number variables. To do so we can use the select() function.

Question Opportunity

Using what you just learned about pivot_wider() and select() and without scrolling up, try to come up with the code to do the wrangling for this data.

Click here to reveal the code.
chi_squared_11.2a %<>%
  select(Demographic, Year, Number) %>%
  tidyr::pivot_wider(names_from = Year,
                     names_prefix = "Year", 
                     values_from = Number)
chi_squared_11.2a
# A tibble: 2 x 3
  Demographic Year2004 Year2018
  <chr>          <dbl>    <dbl>
1 Male          637000   946000
2 Female       1588000  2537000

At this point we have three columns, but the first column we only need the Male and Female labels and want to treat it as row names. To convert a column to the names of rows, you can use the column_to_rownames() function of the tibble package to make the Demographic variable levels for the row names. Otherwise, we would need to select the numeric columns to perform the stats test.

chi_squared_11.2a %<>%
  tibble::column_to_rownames("Demographic")

chi_squared_11.2a
       Year2004 Year2018
Male     637000   946000
Female  1588000  2537000

Note: a contingency table would usually also have totals for all groups as well, but this is not necessary for the stats::chisq.test() function.

The chi-squared test for independence can be conducted using the stats::chisq.test() function.

stats::chisq.test(chi_squared_11.2a)

    Pearson's Chi-squared test with Yates' continuity correction

data:  chi_squared_11.2a
X-squared = 1461.2, df = 1, p-value < 2.2e-16

We see that the \(p\)-value is very small, which suggests there is an association between Gender and the number of major depressive episodes across time (2004 compared to 2018).

Question Opportunity

Using what you learned about the Chi-squared test, describe the results in reference to the null hypothesis.

Now that we see that there is likely an association, we want to describe the size of the association between the variables.

We can use the prop_test() function of the rstatix package to test the null hypothesis that the proportion of the reported episodes given by males is the same for each year. This is equivalent to the chi-squared test we’ve already done! Remember that the null hypothesis for the chi-squares test is that the variables are independent. In this case, the null hypothesis is that year and gender are independent. If year and gender are independent, then we’d expect males to have the same proportion of episodes in each of the two years – which is exactly the null hypothesis of a test comparing two proportions. Thinking of our test as comparing two proportions is helpful, because this can give us a confidence interval to learn more about the differences in the proportions. See here for more information.

prop_test(chi_squared_11.2a, detailed = TRUE, correct = TRUE) %>%
glimpse()
Rows: 1
Columns: 13
$ n           <dbl> 5708000
$ n1          <dbl> 1583000
$ n2          <dbl> 4125000
$ estimate1   <dbl> 0.4024005
$ estimate2   <dbl> 0.3849697
$ statistic   <dbl> 1461.23
$ p           <dbl> 1.040008e-319
$ df          <dbl> 1
$ conf.low    <dbl> 0.01653368
$ conf.high   <dbl> 0.01832793
$ method      <chr> "Prop test"
$ alternative <chr> "two.sided"
$ p.signif    <chr> "****"

Here \(n\) is the total for both males and females of both years.
The \(n1\) is the total n for males across both years.
The \(n2\) is the total n for females across both years.
We can see that the statistic is equivalent to the Chi-squared statistic that we saw previously.
Estimate 1 is the proportion of the male reports given in 2004 (out of the total number of males reporting an episode in 2004 and 2018) and estimate 2 to is the equivalent for females.

Thus estimate 1 for males is: \[\text{Males_2004/Males_bothYears} = (637000/( 637000 + 946000)) = (637000/1583000) = (637000/n1) = .40\]

Thus estimate 2 for females is: \[\text{Females_2004/Females_bothYears} =(1588000/(2537000 + 1588000)) = (1588000/(4125000)) = (1588000/n2) = .38\]

So of all the reports given by males in these two years, 40% came in 2004. For females, 38% of the reports came in 2004. The confidence interval gives a range of plausible values for the true difference in these proportions in the population. It gives us a sense of the difference in the proportion of reports that came in 2004 between males and females.

According to our confidence interval, we are 95% confident that the true difference in the proportion of reports that came in 2004 between males and females (out of the total for each) is between 1.65% and 1.83%. OK, so this isn’t a super large change. But we do notice that 0 is not in this confidence interval. This means we are confident that the difference isn’t 0, which suggests that there is indeed a difference between the proportions (this is a similar to checking if the p value is less than 0.05). For more information on the relationship between confidence intervals and p-values, see this paper.

You might notice that the proportions estimated by prop_test() don’t quite match the null hypothesis we stated earlier, which said the proportion of reported episodes by males is the same in each year. Instead, we were comparing the proportion of reported episodes in 2004 between males and females. We can get proportions that match our previously stated null hypothesis by transposing the contingency table we use to have Male/Female in the columns and the Male/Female in the columns and the years in the rows. When we do this, our test result will be the same, since it’s testing for independence of year and gender, but the proportions estimated will be the proportion of males (out of males + females) in 2004 and the proportion of males (out of males + females) in 2018.

We can use the base t() function to transpose our contingency table.

t(chi_squared_11.2a) 
           Male  Female
Year2004 637000 1588000
Year2018 946000 2537000
t(chi_squared_11.2a) %>% 
  prop_test( detailed = TRUE, correct = TRUE) %>%
  glimpse()
Rows: 1
Columns: 13
$ n           <dbl> 5708000
$ n1          <dbl> 2225000
$ n2          <dbl> 3483000
$ estimate1   <dbl> 0.2862921
$ estimate2   <dbl> 0.2716049
$ statistic   <dbl> 1461.23
$ p           <dbl> 1.040008e-319
$ df          <dbl> 1
$ conf.low    <dbl> 0.0139312
$ conf.high   <dbl> 0.01544319
$ method      <chr> "Prop test"
$ alternative <chr> "two.sided"
$ p.signif    <chr> "****"

Here \(n\) is again the total for both males and females of both years.
Now \(n1\) is the total n for males and females in 2004.
The \(n2\) is the total n for males and females in 2018.
We can gain see that the statistic is equivalent to the Chi-squared statistic that we saw previously.
Estimate 1 is the proportion of the male reports given in 2004 (out of the total number of males and females reporting an episode in 2004) and estimate 2 to is the equivalent for 2018.

Thus estimate 1 is: \[\text{Males_2004/Males_and_Females_2004} = (637000/(637000 + 1588000)) = (637000/2225000) = (637000/n1) = .29\]

Thus estimate 2 is:
\[\text{Males_2018/Males_and_Females_2018} = (946000/(946000 + 2537000)) = (946000/3483000) = (637000/n1) = .27\]

Now we can interpret our confidence interval like so: we are 95% confident that the difference in the proportion of males reporting over the two years is between 1.39% and 1.54%. We see around 1.5% more males reporting in 2004 out of the total reports than we do in 2018.

We can also take a look at our plot to assist with interpretation.

This time we will show the same plot as we did before but for counts instead of percentage.

Click here to reveal the code.
MDE_age_gender_counts <-
  counts %>%
  filter(data_type == "Major_Depressive_Episode", 
         subgroup != "Race/Ethnicity", 
         Demographic != "TOTAL") %>%
  ggplot(aes(x = Year, y = Number, group = Demographic)) +
    geom_rect(xmin = 2011, xmax = Inf,  
              ymin = -Inf, ymax = Inf,  
              fill = "light gray") +
    geom_line(aes(color = Demographic), size =1) +
    scale_x_continuous(breaks = seq(2004, 2018, by=1),
                       labels = seq(2004, 2018, by=1),
                       limits = c(2004, 2018)) +
    labs(title = "Major Depressive Episode\namong Persons Aged 12 to 17",
         subtitle = "By Demographic Characteristics, Percentages, 2004-2018") +
    facet_wrap(~ subgroup) +
    ocs_theme()

MDE_age_gender_counts <- direct.label(
  MDE_age_gender_counts, 
  list(dl.trans(y = y +0.38, x = x -0.2), 
       "far.from.others.borders", 
       cex = .8,
       fontface = "bold",
       dl.move("Age: 14-15", x = 2008, y =10))
  ) + 
  scale_color_manual(values = c(age_col_light, 
                                age_col, 
                                age_col_dark, 
                                Female_col, 
                                Male_col))
MDE_age_gender_counts 

We can see that the blue line relative to the sum of the pink and blue lines in 2004 (about 29%) is fairly similar to that of 2018 (about 27%). It can be difficult to see proportions and especially a proportional difference of ~ 1.5%!

How about for severe major depressive episodes?

Gender and Severe MDE Analysis


chi_squared_11.3a <- counts %>%
  filter(data_type == "Severe_Major_Depressive_Episode", 
         Year %in% c(2006, 2018), 
         Demographic %in% c("Male","Female")) %>%
  mutate(Number = Number * 1000) %>%
  select(-data_type, -subgroup) %>%
  pivot_wider(names_from = Year,
              names_prefix = "Year", 
              values_from = Number) %>%
  column_to_rownames("Demographic")

chi_squared_11.3a
       Year2006 Year2018
Male     335000   628000
Female  1023000  1795000
chisq.test(chi_squared_11.3a)

    Pearson's Chi-squared test with Yates' continuity correction

data:  chi_squared_11.3a
X-squared = 715.87, df = 1, p-value < 2.2e-16

There also appears to be an influence of gender on the rate of severe major depressive episodes across the years.

t(chi_squared_11.3a) 
           Male  Female
Year2006 335000 1023000
Year2018 628000 1795000
t(chi_squared_11.3a) %>% 
  prop_test( detailed = TRUE, correct = TRUE) %>%
  glimpse()
Rows: 1
Columns: 13
$ n           <dbl> 3781000
$ n1          <dbl> 1358000
$ n2          <dbl> 2423000
$ estimate1   <dbl> 0.2466863
$ estimate2   <dbl> 0.2591828
$ statistic   <dbl> 715.8654
$ p           <dbl> 1.06e-157
$ df          <dbl> 1
$ conf.low    <dbl> -0.01340819
$ conf.high   <dbl> -0.01158486
$ method      <chr> "Prop test"
$ alternative <chr> "two.sided"
$ p.signif    <chr> "****"

The difference in the proportions of the two years is possibly between 0.013 to 0.012 or -1.3% and -1.2%. This time the proportion of males reporting out of the total reports each year was larger in 2018 (estimate2 = 26%) than in 2006 (estimate1 = 24.7%). Again the difference was quite small and the range does not include 0, thus suggesting that there is indeed an association between gender and and the number of severe major depressive episodes across time (2006 compared to 2018).

How about treatment?

Gender and Treatment Analysis


Question Opportunity

Try performing the same wrangling as we did for the percentage of each demographic that reported having a major depressive episode for the data about treatment.

Click here to reveal the code.
chi_squared_11.4a <- counts %>%
  filter(data_type == "Treatment", 
         Year %in% c(2004, 2018), 
         Demographic %in% c("Male","Female")) %>%
  mutate(Number = Number * 1000) %>%
  select(-data_type, -subgroup) %>%
  pivot_wider(names_from = Year,
              names_prefix = "Year", 
              values_from = Number) %>%
  column_to_rownames("Demographic")

chi_squared_11.4a
       Year2004 Year2018
Male     239000   351000
Female   656000  1081000
chisq.test(chi_squared_11.4a)

    Pearson's Chi-squared test with Yates' continuity correction

data:  chi_squared_11.4a
X-squared = 1399.1, df = 1, p-value < 2.2e-16

There also appears to be an influence of gender on the rate at which youths received treatment across the two years.

t(chi_squared_11.4a) 
           Male  Female
Year2004 239000  656000
Year2018 351000 1081000
t(chi_squared_11.4a) %>% 
  prop_test( detailed = TRUE, correct = TRUE) %>%
  glimpse()
Rows: 1
Columns: 13
$ n           <dbl> 2327000
$ n1          <dbl> 895000
$ n2          <dbl> 1432000
$ estimate1   <dbl> 0.2670391
$ estimate2   <dbl> 0.2451117
$ statistic   <dbl> 1399.097
$ p           <dbl> 3.3e-306
$ df          <dbl> 1
$ conf.low    <dbl> 0.02077041
$ conf.high   <dbl> 0.02308434
$ method      <chr> "Prop test"
$ alternative <chr> "two.sided"
$ p.signif    <chr> "****"

Again the values of our confidence interval suggests that there is a small difference (roughly 2% difference in the proportion of males across the two years receiving treatment) and again the range does not cross 0, suggesting that there is indeed a difference in the proportions.

In this case we find that the males in 2004 made up 27% of all youths reporting receiving treatment for depression that year, and males made up only 25% of the youths reporting receiving treatment in 2018.

Summary


Summary Plot


Let’s make a plot that summarizes our major findings.

We will use the ggdraw() function in the cowplot package. This allows you to add labels and other plot aspects on top of existing plots. Thus if we want to add a title element to our overall plot that we will add to a combined plot of our existing plots we can use ggdraw() to start and then the draw_label() function to add text.

title_plots <-
  ggdraw() +
  draw_label(
    "Self-Reported Depression Among American Youths",
    fontface = 'bold',
    size = 18,
    x = 0,
    hjust = -0.01
  )

The x = 0 argument places the title on the far left edge of the plot area. Thus, if we use a value of -0.01 it will move the title just a bit away from the left edge of the plot area.

Question Opportunity

What happens if we modify the hjust value?

Click here to reveal the answer.

The hjust argument moves the label in the horizontal direction.

We can also make a subtitle in the same way. Here, we create a subtitle called forward, which we will use later on.

forward <- ggdraw() + 
  draw_label(
    "The percentage of youths (age 12-17) experiencing major depressive episodes (MDE) has\nincreased since 2011. Of these youths, the percentage receiving treatment for depression has also\n increased but remains limited to less than 42%.",
    size = 16,
    x = 0,
    hjust = -0.01
  )

Next, we will modify some of our existing plots using the theme() function as we did before to remove the x-axis title, to change the color of the axis text and the title size and color, as well as change the titles of the plots.

First let’s load the plots we intend to use:

load(file = here::here("plots", "MDE_total.rda"))
load(file = here::here("plots", "Treat_total.rda"))
load(file = here::here("plots", "MDE_age_gender.rda"))
load(file = here::here("plots", "MDE_race.rda"))

Using our MDE_total plot:

MDE_total_for_mp <- MDE_total +
  theme(plot.title = element_blank(),
        plot.subtitle = element_blank(),
        axis.text = element_text(color = "black"))

Using our Treat_total plot:

treat_for_mp <- 
  Treat_total +
  theme(plot.title = element_blank(),
        plot.subtitle = element_blank(),
        axis.text = element_text(color = "black"))

Using our MDE_age_gender plot:

MDE_age_gender_for_mp <- 
  MDE_age_gender +
  theme(plot.title= element_text(size = 14, color = "black"),
        plot.subtitle = element_blank(),
        axis.text = element_text(color = "black")) +
  labs(title = "Older youths and females report MDE at the highest rates\nand show the steepest increase") 

For this last plot, we also want to get the legend and save it as a separate object so that we can add it to our plot grid in a way that does not shrink the size of our plot to accommodate the legend. We can use the get_legend() function of the cowplot package to do this. We can also specify how it should be justified using theme(legend.justification =) this takes a number of options including "center", "left", and "right".

However, beforehand, we also want to change the way the legend is displayed. We can use the guides() function of the ggplot2 package to modify the legend to specify that we want the legend to be displayed in 2 columns like so guides(color = guide_legend(ncol = 2)). We need to specify that we are modifying the legend for color.

MDE_race_for_mp_leg <- MDE_race +
  theme(plot.title= element_text(size = 14, color = "black"),
        plot.subtitle = element_blank(),
        axis.text = element_text(color = "black"),
        legend.position = "right", 
        legend.title = element_blank(),
        legend.text = element_text(size = 14)) +
  labs(title = "All racial/ethnic groups show similar\nincreases since 2011") +
  guides(color = guide_legend(ncol = 2))

legend <- get_legend(MDE_race_for_mp_leg +
          theme(legend.justification = "right"))

Now, we will remove the legend for this plot.

Question Opportunity

Do you recall how to do this? Without scrolling up, see if you can figure out how.

Click here to reveal the code.
MDE_race_for_mp <- MDE_race_for_mp_leg +
  theme(legend.position = "none")

OK, now we are ready to start putting our plots together using the plot_grid() function of the cowplot package.

It is helpful to first make rows by combining the plots that we want to be displayed next to each other and then combining these with the title and subtitle, called forward.

We can use the rel_widths (relative column width) argument to modify how wide each plot is displayed. For example, in a two-column grid, rel_widths = c(2, 1) would make the first column twice as wide as the second column.

row_1 <- plot_grid(MDE_total_for_mp,
                   treat_for_mp,
                   nrow = 1)

row_2 <- plot_grid(MDE_age_gender_for_mp,
                   MDE_race_for_mp,
                   nrow = 1, 
                   rel_widths = c(1, 0.6))

Now we can combine everything together using plot_grid() yet again. Now that we have rows, we can combine everything as a single column and easily modify the relative heights using the rel_heights() function so that our title, subtitle and legend are all relative short relative to the plots. We will make the first row half the height of the second row.

Finally, we will use the png() function of the grDevices package which is automatically loaded in RStudio sessions to save the plot. We will use the here() function of the here package, to specify that we want to save it in the img directory and call it mainplot.png. We can also use this function to specify the resolution with res and in doing so, we need to save the image with size specifications to make it larger.

png(filename = here::here("img", "mainplot_orig.png"), 
         res = 300, width = 10, height = 10, units = "in")
plot_grid(title_plots, 
          forward,
          row_1,
          row_2,
          legend,
          ncol = 1, 
          rel_heights = c(0.1,0.2,.8, 1, 0.3))
dev.off()

The dev.off() function is necessary to close the graphics device. This is good practice to allow you to create another plot again later.

OK, this looks pretty good! But it is a bit busy, so we are now going to remove the Race/ethnicity plot so as to simplify our plot.

This time we need to recreate our MDE_age_gender plot again because we want to separate our plots so they look more similar to the total MDE and treatment plots. So we will actually make two separate plots.

We also want to recode the text for the strip above the plot and change the plot so that there are no grid lines like the first row of plots.

Question Opportunity

Try to come up with the code for these plots on your own before you reveal it. We can use our ocs_theme() for these plots to make all the plots look similar.

Click here to reveal the code.
MDE_gender <-percents %>%
  filter(data_type == "Major_Depressive_Episode", 
          subgroup == "Gender") %>%
  mutate(subgroup = recode(subgroup, "Gender" = 
         "Percent of each gender reporting MDE")) %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
  geom_rect(xmin = 2011, xmax = Inf,  
            ymin = -Inf, ymax = Inf,  
            fill = "light gray") +
  geom_line(aes(color = Demographic), size = 1.5) +
  facet_wrap(~subgroup) +
  scale_y_continuous(limits = c(0, 23))+
  scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                     labels = seq(2004, 2018, by = 1),
                     limits = c(2004, 2018)) +
 ocs_theme() +
 scale_color_manual(values = c(Female_col,
                               Male_col))



MDE_gender<- direct.label(
  MDE_gender, 
  list(dl.trans(y = y +0.38, x = x -0.2), 
       "far.from.others.borders", 
       cex = 1,
       fontface=c("bold"))
  )
       

MDE_age <- percents %>%
  filter(data_type == "Major_Depressive_Episode", 
          subgroup == "Age") %>%
  mutate(subgroup = recode(subgroup, "Age" = 
        "Percent of each age group reporting MDE")) %>%
  ggplot(aes(x = Year, y = Percent, group = Demographic)) +
  geom_rect(xmin = 2011, xmax = Inf,  
            ymin = -Inf, ymax = Inf,  
            fill = "light gray") +
  geom_line(aes(color = Demographic), size = 1.5) +
  facet_wrap(~subgroup)+
  scale_y_continuous(limits = c(0, 23))+
  scale_x_continuous(breaks = seq(2004, 2018, by = 1),
                     labels = seq(2004, 2018, by = 1),
                     limits = c(2004, 2018)) +
  ocs_theme() +
  scale_color_manual(values = c(age_col_light,
                                age_col,
                                age_col_dark))

MDE_age <- direct.label(
  MDE_age, 
  list(dl.trans(y = y + 0.38, x = x -0.2), 
       "far.from.others.borders", 
       cex = 1, 
       fontface=c("bold"),
       dl.move("Age: 12-13", x = 2015, y = 9))
  )

We will also make another subtitle for the gender and race plots. This time we will add bold text to our text using the base expression() function and the base paste() function which allows you to combine character strings together. We can specify that we don’t want any spaces or character for our separator.

label <- expression(paste(
    bold("Older "),
    "youths and ",
    bold("females "),
    "report MDE at the highest rate and also show the steepest increase."), sep = "")

forward2 <- ggdraw() + 
  draw_label(label,
    size = 16,
    x = 0,
    hjust = -0.01
  )
row_2 <- plot_grid(MDE_age, MDE_gender,
                   nrow = 1)

png(filename = here::here("img", "mainplot.png"), 
         res = 300, width = 10, height = 10, units = "in")
plot_grid(title_plots, 
          forward,
          row_1,
          forward2,
          row_2,
          ncol = 1, 
          rel_heights = c(0.1, 0.2, 1, 0.1, 1))
dev.off()
png 
  2 

Synopsis


In this case study we evaluated self-reported measures of depression symptoms among youths age 12-17 in the United States, as well as the rate of youths receiving treatment for depression. We learned how to scrape data directly from the web using the rvest package and we learned how to perform and interpret a chi-square test using the chisq.test() function of the stats package.

By analyzing and plotting our data, it is clear that depression rates appear to be increasing, particularly since 2011. However, it is possible that respondents had similar rates in previous years, but now feel less stigma about responding about depression symptoms when filling out the survey. The survey has always been anonymous, but reporting bias can sometimes cause individuals to exaggerate or minimize their symptoms because of what they think researchers want their response to be or out of shame or embarrassment, among other reasons. However, the data suggests that youths may be experiencing more symptoms of depression and that the rate of increase is quite high.

Nearly a quarter of all individuals that were female and of age 12-17 reported experiencing symptoms of depression. This warrants further investigation to see if this is a product of more reporting or if indeed American females are truly more depressed. Furthermore, if they are indeed more depressed, investigation about why young females are more depressed is also of critical importance. One important limitation is that the data does not include subgroup intersections, such as rates of major depressive episodes among females of various ethnic backgrounds.

Considering the very steep increase in females, this warrants further investigation about which females are particularly vulnerable and why.

Homework


Ask students to scrape Tables 11.5A and 11.5B from the website, which contain data about the receipt of treatment among youths who reported having a severe episode. Ask students to create plots and perform Chi-square tests to evaluate how groups compare over time.

Additional Information


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             cowplot_1.1.1            
 [3] rstatix_0.7.0             ggthemes_4.2.4           
 [5] forcats_0.5.1             scales_1.1.1             
 [7] directlabels_2021.1.13    ggplot2_3.3.5            
 [9] purrr_0.3.4               tibble_3.1.6             
[11] tidyr_1.1.4               stringr_1.4.0            
[13] dplyr_1.0.7               rvest_1.0.2              
[15] koRpus.lang.en_0.1-4      koRpus_0.13-8            
[17] sylly_0.1-6               read.so_0.1.1            
[19] wordcountaddin_0.3.0.9000 magrittr_2.0.2           
[21] magick_2.7.3              knitr_1.37               
[23] here_1.0.1               

loaded via a namespace (and not attached):
 [1] httr_1.4.2        sass_0.4.0        viridisLite_0.4.0 bit64_4.0.5      
 [5] vroom_1.5.7       jsonlite_1.8.0    carData_3.0-5     bslib_0.3.1      
 [9] assertthat_0.2.1  highr_0.9         yaml_2.3.5        remotes_2.4.2    
[13] pillar_1.7.0      backports_1.4.1   lattice_0.20-45   glue_1.6.1       
[17] quadprog_1.5-8    digest_0.6.29     colorspace_2.0-2  htmltools_0.5.2  
[21] Matrix_1.3-4      pkgconfig_2.0.3   broom_0.7.11      tzdb_0.2.0       
[25] farver_2.1.0      generics_0.1.1    car_3.0-12        usethis_2.1.5    
[29] ellipsis_0.3.2    withr_2.5.0       cli_3.2.0         crayon_1.5.0     
[33] evaluate_0.15     fs_1.5.2          fansi_1.0.2       xml2_1.3.3       
[37] tools_4.1.2       data.table_1.14.2 hms_1.1.1         lifecycle_1.0.1  
[41] munsell_0.5.0     compiler_4.1.2    jquerylib_0.1.4   rlang_1.0.1      
[45] grid_4.1.2        rstudioapi_0.13   labeling_0.4.2    rmarkdown_2.11   
[49] gtable_0.3.0      abind_1.4-5       DBI_1.1.2         curl_4.3.2       
[53] R6_2.5.1          sylly.en_0.1-3    bit_4.0.4         fastmap_1.1.0    
[57] utf8_1.2.2        rprojroot_2.0.2   readr_2.1.1       stringi_1.7.6    
[61] parallel_4.1.2    Rcpp_1.0.8        vctrs_0.3.8       tidyselect_1.1.2 
[65] xfun_0.29        

Estimate of RMarkdown Compilation Time:

About 35 - 45 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 Tamar Mendelson for assisting in framing the major direction of the case study.

We would like to acknowledge Qier Meng and Michael Breshock for their contributions to this case study.

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

LS0tDQp0aXRsZTogIk9wZW4gQ2FzZSBTdHVkaWVzOiBNZW50YWwgSGVhbHRoIG9mIEFtZXJpY2FuIFlvdXRoIg0KY3NzOiBzdHlsZS5jc3MNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBpbmNsdWRlczoNCiAgICAgICBpbl9oZWFkZXI6IEdBX1NjcmlwdC5SaHRtbA0KICAgIHNlbGZfY29udGFpbmVkOiB5ZXMNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRoZW1lOiBjb3Ntbw0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQo8c3R5bGU+DQojVE9DIHsNCiAgYmFja2dyb3VuZDogdXJsKCJodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vaW1nL2ljb24tYmFoaS5wbmciKTsNCiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOw0KICBwYWRkaW5nLXRvcDogMjQwcHggIWltcG9ydGFudDsNCiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsNCn0NCjwvc3R5bGU+DQoNCjwhLS0gT3BlbiBhbGwgbGlua3MgaW4gbmV3IHRhYi0tPiAgDQo8YmFzZSB0YXJnZXQ9Il9ibGFuayIvPiAgDQoNCjxkaXYgaWQ9Imdvb2dsZV90cmFuc2xhdGVfZWxlbWVudCI+PC9kaXY+DQoNCjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9Jy8vdHJhbnNsYXRlLmdvb2dsZS5jb20vdHJhbnNsYXRlX2EvZWxlbWVudC5qcz9jYj1nb29nbGVUcmFuc2xhdGVFbGVtZW50SW5pdCc+PC9zY3JpcHQ+DQoNCjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij4NCmZ1bmN0aW9uIGdvb2dsZVRyYW5zbGF0ZUVsZW1lbnRJbml0KCkgew0KICBuZXcgZ29vZ2xlLnRyYW5zbGF0ZS5UcmFuc2xhdGVFbGVtZW50KHtwYWdlTGFuZ3VhZ2U6ICdlbid9LCAnZ29vZ2xlX3RyYW5zbGF0ZV9lbGVtZW50Jyk7DQp9DQo8L3NjcmlwdD4NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQpvcHRpb25zKGNyYXlvbi5lbmFibGVkID0gTlVMTCkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gJzkwJScpDQpsaWJyYXJ5KGhlcmUpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShtYWdpY2spICMgdG8gY3JlYXRlIGdpZg0KbGlicmFyeShtYWdyaXR0cikNCnJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJiZW5tYXJ3aWNrL3dvcmRjb3VudGFkZGluIiwgdHlwZSA9ICJzb3VyY2UiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImFsaXN0YWlyZTQ3L3JlYWQuc28iKQ0KbGlicmFyeSh3b3JkY291bnRhZGRpbikNCmxpYnJhcnkocmVhZC5zbykNCg0Kcm1hcmtkb3duOjo6cGVyZl90aW1lcl9yZXNldF9hbGwoKQ0Kcm1hcmtkb3duOjo6cGVyZl90aW1lcl9zdGFydCgicmVuZGVyIikNCmBgYA0KDQojIyMjIHsub3V0bGluZSB9DQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4In0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJtYWlucGxvdC5wbmciKSkNCmBgYA0KDQojIyMjDQoNCiMjIyMgey5kaXNjbGFpbWVyX2Jsb2NrfQ0KDQoqKkRpc2NsYWltZXIqKjogVGhlIHB1cnBvc2Ugb2YgdGhlIFtPcGVuIENhc2UgU3R1ZGllc10oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvKXt0YXJnZXQ9Il9ibGFuayJ9IHByb2plY3QgaXMgKip0byBkZW1vbnN0cmF0ZSB0aGUgdXNlIG9mIHZhcmlvdXMgZGF0YSBzY2llbmNlIG1ldGhvZHMsIHRvb2xzLCBhbmQgc29mdHdhcmUgaW4gdGhlIGNvbnRleHQgb2YgbWVzc3ksIHJlYWwtd29ybGQgZGF0YSoqLiBBIGdpdmVuIGNhc2Ugc3R1ZHkgZG9lcyBub3QgY292ZXIgYWxsIGFzcGVjdHMgb2YgdGhlIHJlc2VhcmNoIHByb2Nlc3MsIGlzIG5vdCBjbGFpbWluZyB0byBiZSB0aGUgbW9zdCBhcHByb3ByaWF0ZSB3YXkgdG8gYW5hbHl6ZSBhIGdpdmVuIGRhdGEgc2V0LCBhbmQgc2hvdWxkIG5vdCBiZSB1c2VkIGluIHRoZSBjb250ZXh0IG9mIG1ha2luZyBwb2xpY3kgZGVjaXNpb25zIHdpdGhvdXQgZXh0ZXJuYWwgY29uc3VsdGF0aW9uIGZyb20gc2NpZW50aWZpYyBleHBlcnRzLiANCg0KIyMjIw0KDQojIyMjIHsubGljZW5zZV9ibG9ja30NCg0KVGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBDcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLU5vbkNvbW1lcmNpYWwgMy4wIFsoQ0MgQlktTkMgMy4wKV0oaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLzMuMC91cy8pe3RhcmdldD0iX2JsYW5rIn0gIFVuaXRlZCBTdGF0ZXMgTGljZW5zZS4NCg0KIyMjIw0KDQojIyMjIHsucmVmZXJlbmNlX2Jsb2NrfQ0KDQpUbyBjaXRlIHRoaXMgY2FzZSBzdHVkeSBwbGVhc2UgdXNlOg0KDQpXcmlnaHQsIENhcnJpZSBhbmQgT250aXZlcm9zLCBNaWNoYWVsIGFuZCBKYWdlciwgTGVhaCBhbmQgVGF1YiwgTWFyZ2FyZXQgYW5kIEhpY2tzLCBTdGVwaGFuaWUgQy4gKDIwMjApLiBodHRwczovL2dpdGh1Yi5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy1icC15b3V0aC1tZW50YWwtaGVhbHRoLiBNZW50YWwgSGVhbHRoIG9mIEFtZXJpY2FuIFlvdXRoLg0KDQojIyMjDQoNCiMjIyMgey5lbXBoYXNpc19ibG9ja30NCg0KKipQbGVhc2UgYmUgYWR2aXNlZCB0aGF0IHRoZSBtYXRlcmlhbCBpbiB0aGlzIGNhc2Ugc3R1ZHkgZGVzY3JpYmVzIGFuZCBkaXNjdXNzZXMgcmF0ZXMgb2Ygc3VpY2lkZSwgYXMgd2VsbCBhcyByYXRlcyBhbmQgc3ltcHRvbXMgb2YgZGVwcmVzc2lvbi4qKg0KDQpBY2NvcmRpbmcgdG8gdGhlIFtOYXRpb25hbCBJbnN0aXR1dGUgb2YgTWVudGFsIEhlYWx0aCAoTklNSCldKGh0dHBzOi8vd3d3Lm5pbWgubmloLmdvdi9oZWFsdGgvcHVibGljYXRpb25zL3RlZW4tZGVwcmVzc2lvbi9pbmRleC5zaHRtbCl7dGFyZ2V0PSJfYmxhbmsifToNCg0KSWYgeW91IGFyZSBpbiBjcmlzaXMgYW5kIG5lZWQgaGVscCwgY2FsbCB0aGlzIHRvbGwtZnJlZSBudW1iZXIgZm9yIHRoZSAqKk5hdGlvbmFsIFN1aWNpZGUgUHJldmVudGlvbiBMaWZlbGluZSAoTlNQTCkqKiwgYXZhaWxhYmxlIDI0IGhvdXJzIGEgZGF5LCBldmVyeSBkYXk6ICoqMS04MDAtMjczLVRBTEsgKDgyNTUpKiouIFRoZSBzZXJ2aWNlIGlzIGF2YWlsYWJsZSB0byBldmVyeW9uZS4gVGhlIGRlYWYgYW5kIGhhcmQgb2YgaGVhcmluZyBjYW4gY29udGFjdCB0aGUgTGlmZWxpbmUgdmlhIFRUWSBhdCAxLTgwMC03OTktNDg4OS4gQWxsIGNhbGxzIGFyZSBjb25maWRlbnRpYWwuIFlvdSBjYW4gYWxzbyB2aXNpdCB0aGUgTGlmZWxpbmXigJlzIHdlYnNpdGUgYXQgW3d3dy5zdWljaWRlcHJldmVudGlvbmxpZmVsaW5lLm9yZ10od3d3LnN1aWNpZGVwcmV2ZW50aW9ubGlmZWxpbmUub3JnKXt0YXJnZXQ9Il9ibGFuayJ9Lg0KDQpUaGUgKipDcmlzaXMgVGV4dCBMaW5lKiogaXMgYW5vdGhlciBmcmVlLCBjb25maWRlbnRpYWwgcmVzb3VyY2UgYXZhaWxhYmxlIDI0IGhvdXJzIGEgZGF5LCBzZXZlbiBkYXlzIGEgd2Vlay4gVGV4dCDigJxIT01F4oCdIHRvICoqNzQxNzQxKiogYW5kIGEgdHJhaW5lZCBjcmlzaXMgY291bnNlbG9yIHdpbGwgcmVzcG9uZCB0byB5b3Ugd2l0aCBzdXBwb3J0IGFuZCBpbmZvcm1hdGlvbiBvdmVyIHRleHQgbWVzc2FnZS4gVmlzaXQgW3d3dy5jcmlzaXN0ZXh0bGluZS5vcmddKHd3dy5jcmlzaXN0ZXh0bGluZS5vcmcpe3RhcmdldD0iX2JsYW5rIn0uDQoNCkFsc28gc2VlIFtoZXJlXShodHRwczovL3d3dy5taGFuYXRpb25hbC5vcmcvZGVwcmVzc2lvbi10ZWVucy0wKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGhvdyB0byByZWNvZ25pemUgYW5kIGhlbHAgeW91dGhzIGV4cGVyaWVuY2luZyBzeW1wdG9tcyBvZiBkZXByZXNzaW9uLg0KDQojIyMjDQoNClRvIGFjY2VzcyB0aGUgR2l0SHViIHJlcG9zaXRvcnkgdG8gb2J0YWluIHRoZSBkYXRhIGZvciB0aGlzIGNhc2Ugc3R1ZHkgc2VlIGhlcmU6IGh0dHBzOi8vZ2l0aHViLmNvbS8vb3BlbmNhc2VzdHVkaWVzL29jcy1icC15b3V0aC1tZW50YWwtaGVhbHRoLiAgDQoNCllvdSBtYXkgYWxzbyBhY2Nlc3MgYW5kIGRvd25sb2FkIHRoZSBkYXRhIHVzaW5nIG91ciBgT0NTZGF0YWAgcGFja2FnZS4gVG8gbGVhcm4gbW9yZSBhYm91dCB0aGlzIHBhY2thZ2UgaW5jbHVkaW5nIGV4YW1wbGVzLCBzZWUgdGhpcyBbbGlua10oaHR0cHM6Ly9naXRodWIuY29tL29wZW5jYXNlc3R1ZGllcy9PQ1NkYXRhKS4gSGVyZSBpcyBob3cgeW91IHdvdWxkIGluc3RhbGwgdGhpcyBwYWNrYWdlOg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmluc3RhbGwucGFja2FnZXMoIk9DU2RhdGEiKQ0KYGBgDQoNClRoaXMgY2FzZSBzdHVkeSBpcyBwYXJ0IG9mIGEgc2VyaWVzIG9mIHB1YmxpYyBoZWFsdGggY2FzZSBzdHVkaWVzIGZvciB0aGUgW0Jsb29tYmVyZyBBbWVyaWNhbiBIZWFsdGggSW5pdGlhdGl2ZV0oaHR0cHM6Ly9hbWVyaWNhbmhlYWx0aC5qaHUuZWR1L29wZW4tY2FzZS1zdHVkaWVzKS4NCg0KKioqDQoNClRoZSB0b3RhbCByZWFkaW5nIHRpbWUgZm9yIHRoaXMgY2FzZSBzdHVkeSBpcyBjYWxjdWxhdGVkIHZpYSBba29ScHVzXShodHRwczovL2dpdGh1Yi5jb20vdW5Eb2NVTWVhbnRJdC9rb1JwdXMpIGFuZCBzaG93biBiZWxvdzogDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KcmVhZHRhYmxlID0gdGV4dF9zdGF0cygiaW5kZXguUm1kIikgIyBwcm9kdWNpbmcgcmVhZGluZyB0aW1lIG1hcmtkb3duIHRhYmxlDQpyZWFkdGltZSA9IHJlYWQuc286OnJlYWQubWQocmVhZHRhYmxlKSAlPiUgZHBseXI6OnNlbGVjdChNZXRob2QsIGtvUnB1cykgJT4lICMgcmVhZGluZyB0YWJsZSBpbnRvIGRhdGFmcmFtZSwgc2VsZWN0aW5nIHJlbGV2YW50IGZhY3RvcnMNCiAgZHBseXI6OmZpbHRlcihNZXRob2QgPT0gIlJlYWRpbmcgdGltZSIpICU+JSAjIGRyb3BwaW5nIHVubmVjZXNzYXJ5IHJvd3MNCiAgZHBseXI6Om11dGF0ZShrb1JwdXMgPSBwYXN0ZShyb3VuZChhcy5udW1lcmljKHN0cmluZ3I6OnN0cl9zcGxpdChrb1JwdXMsICIgIilbWzFdXVsxXSkpLCAibWludXRlcyIpKSAlPiUgIyByb3VuZGluZyByZWFkaW5nIHRpbWUgZXN0aW1hdGUNCiAgZHBseXI6Om11dGF0ZShNZXRob2QgPSAia29ScHVzIikgJT4lIGRwbHlyOjpyZWxvY2F0ZShrb1JwdXMsIC5iZWZvcmUgPSBNZXRob2QpICU+JSBkcGx5cjo6cmVuYW1lKGBSZWFkaW5nIFRpbWVgID0ga29ScHVzKSAjIHJlb3JnYW5pemluZyB0YWJsZQ0Ka25pdHI6OmthYmxlKHJlYWR0aW1lLCBmb3JtYXQ9Im1hcmtkb3duIikNCmBgYA0KDQoqKioNCg0KKipSZWFkYWJpbGl0eSBTY29yZTogKioNCg0KQSByZWFkYWJpbGl0eSBpbmRleCBlc3RpbWF0ZXMgdGhlIHJlYWRpbmcgZGlmZmljdWx0eSBsZXZlbCBvZiBhIHBhcnRpY3VsYXIgdGV4dC4gRmxlc2NoLUtpbmNhaWQsIEZPUkNBU1QsIGFuZCBTTU9HIGFyZSB0aHJlZSBjb21tb24gcmVhZGFiaWxpdHkgaW5kaWNlcyB0aGF0IHdlcmUgY2FsY3VsYXRlZCBmb3IgdGhpcyBjYXNlIHN0dWR5IHZpYSBba29ScHVzXShodHRwczovL2dpdGh1Yi5jb20vdW5Eb2NVTWVhbnRJdC9rb1JwdXMpLiBUaGVzZSBpbmRpY2VzIHByb3ZpZGUgYW4gZXN0aW1hdGlvbiBvZiB0aGUgbWluaW11bSByZWFkaW5nIGxldmVsIHJlcXVpcmVkIHRvIGNvbXByZWhlbmQgdGhpcyBjYXNlIHN0dWR5IGJ5IGdyYWRlIGFuZCBhZ2UuIA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCnJ0ID0gd29yZGNvdW50YWRkaW46OnJlYWRhYmlsaXR5KCJpbmRleC5SbWQiLCBxdWlldD1UUlVFKSAjIHByb2R1Y2luZyByZWFkYWJpbGl0eSBtYXJrZG93biB0YWJsZQ0KZGYgPSByZWFkLnNvOjpyZWFkLm1kKHJ0KSAlPiUgZHBseXI6OnNlbGVjdChpbmRleCwgZ3JhZGUsIGFnZSkgJT4lICAjIHJlYWRpbmcgdGFibGUgaW50byBkYXRhZnJhbWUsIHNlbGVjdGluZyByZWxldmFudCBmYWN0b3JzDQogIHRpZHlyOjpkcm9wX25hKCkgJT4lIGRwbHlyOjptdXRhdGUoZ3JhZGUgPSByb3VuZChhcy5udW1lcmljKGdyYWRlKSksICMgZHJvcHBpbmcgcm93cyB3aXRoIG1pc3NpbmcgdmFsdWVzLCByb3VuZGluZyBhZ2UgYW5kIGdyYWRlIGNvbHVtbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPSByb3VuZChhcy5udW1lcmljKGFnZSkpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0Ka25pdHI6OmthYmxlKGRmLCBmb3JtYXQ9Im1hcmtkb3duIikNCmBgYA0KDQoqKioNCg0KUGxlYXNlIGhlbHAgdXMgYnkgZmlsbGluZyBvdXQgb3VyIHN1cnZleS4NCg0KDQo8ZGl2IHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsiPjxpZnJhbWUgc3JjPSJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9mb3Jtcy9kL2UvMUZBSXBRTFNmcE40Rk4zS0VMcUJORWdmMkF0cGk3V3k3TnF5MmJlU2tGUUlOTDdZNXNBTVY1X3cvdmlld2Zvcm0/ZW1iZWRkZWQ9dHJ1ZSIgd2lkdGg9IjEyMDAiIGhlaWdodD0iNzAwIiBmcmFtZWJvcmRlcj0iMCIgbWFyZ2luaGVpZ2h0PSIwIiBtYXJnaW53aWR0aD0iMCI+TG9hZGluZ+KApjwvaWZyYW1lPjwvZGl2Pg0KDQojIyAqKk1vdGl2YXRpb24qKg0KKioqIA0KDQpSYXRlcyBvZiBkZXByZXNzaW9uIGFwcGVhciB0byBoYXZlIGJlZW4gaW5jcmVhc2luZyBhbW9uZyBBbWVyaWNhbiB5b3V0aHMgc2luY2UgYXJvdW5kIDIwMTAgYWNjb3JkaW5nIHRvIGEgcmVjZW50IFtyZXBvcnRdKGh0dHBzOi8vY29udGVudC5hcGEub3JnL3JlY29yZC8yMDE5LTEyNTc4LTAwMSl7dGFyZ2V0PSJfYmxhbmsifS4gQSBbcmVjZW50IHN0dWR5XShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzI0Mjg1MzgyLyl7dGFyZ2V0PSJfYmxhbmsifSBhbHNvIHNob3dzIHRoYXQgeW91dGhzIGFwcGVhciB0byBiZSBzZWVraW5nIG1vcmUgY2FyZSBmcm9tIG1lbnRhbCBoZWFsdGggc2VydmljZXMuDQoNCg0KDQpUaGlzIGNhc2Ugc3R1ZHkgd2lsbCBleHBsb3JlIGhvdyByYXRlcyBvZiBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGVzIGhhdmUgY2hhbmdlZCBzaW5jZSB0aGUgZWFybHkgMjAwMHMgYW5kIGFjcm9zcyBkaWZmZXJlbnQgeW91dGggc3ViZ3JvdXBzIChhZ2UsIGdlbmRlciwgZXRobmljaXR5KS4gDQpXZSBhbHNvIHdpbGwgZXhwbG9yZSBob3cgcmF0ZXMgb2YgdHJlYXRtZW50IGZvciBkZXByZXNzaW9uIG9mIHlvdXRocyBoYXZlIGNoYW5nZWQgb3ZlciB0aW1lLg0KDQoNCmBgYHtyLGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI0MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImstbWl0Y2gtaG9kZ2UtSXFTYUc5enYyZTAtdW5zcGxhc2guanBnIikpDQpgYGANCjxzcGFuPlBob3RvIGJ5IDxhIGhyZWY9Imh0dHBzOi8vdW5zcGxhc2guY29tL0BrbWl0Y2hob2RnZT91dG1fc291cmNlPXVuc3BsYXNoJmFtcDt1dG1fbWVkaXVtPXJlZmVycmFsJmFtcDt1dG1fY29udGVudD1jcmVkaXRDb3B5VGV4dCI+Sy4gTWl0Y2ggSG9kZ2U8L2E+IG9uIDxhIGhyZWY9Imh0dHBzOi8vdW5zcGxhc2guY29tL3MvcGhvdG9zL2RlcHJlc3Npb24/dXRtX3NvdXJjZT11bnNwbGFzaCZhbXA7dXRtX21lZGl1bT1yZWZlcnJhbCZhbXA7dXRtX2NvbnRlbnQ9Y3JlZGl0Q29weVRleHQiPlVuc3BsYXNoPC9hPjwvc3Bhbj4gIA0KDQoNClRoZSBtYWpvciBzeW1wdG9tcyBvZiBhIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZSBpbmNsdWRlOiAgIA0KDQoqKlMqKmxlZXAgZGlzb3JkZXIgKGluY3JlYXNlZCBvciBkZWNyZWFzZWQpICANCioqSSoqbnRlcmVzdCBkZWZpY2l0IChhbmhlZG9uaWEpICANCioqRyoqdWlsdCAod29ydGhsZXNzbmVzcywgaG9wZWxlc3NuZXNzLCByZWdyZXQpICANCioqRSoqbmVyZ3kgZGVmaWNpdCAgDQoqKkMqKm9uY2VudHJhdGlvbiBkZWZpY2l0ICANCioqQSoqcHBldGl0ZSBkaXNvcmRlciAoaW5jcmVhc2VkIG9yIGRlY3JlYXNlZCkgIA0KKipQKipzeWNob21vdG9yIHJldGFyZGF0aW9uIG9yIGFnaXRhdGlvbiAgDQoqKlMqKnVpY2lkYWxpdHkgIA0KDQojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lmljc2kub3JnL2d1aWRlbGluZS9kZXByZXNzaW9uL2RpYWdub3NlLWFuZC1jaGFyYWN0ZXJpemUtbWFqb3ItZGVwcmVzc2lvbi1wZXJzaXN0ZW50LWRlcHJlc3NpdmUtZGlzb3JkZXItd2l0aC1jbGluaWNhbC1pbnRlcnZpZXcvKXt0YXJnZXQ9Il9ibGFuayJ9ICANCg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjgwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiZGVwcmVzc2lvbi1zeW1wdG9tcy1hbmQtdHJlYXRtZW50LTc2OHg3NjguanBnIikpDQpgYGANCg0KIyMjIyMgW1tzb3VyY2VdXShodHRwczovL25ld21pbGZvcmRjb3Vuc2VsaW5nY2VudGVyLmNvbS9kZXByZXNzaW9uLTIvKXt0YXJnZXQ9Il9ibGFuayJ9ICANCg0KKioqDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgdGhlIGRpYWdub3N0aWMgcmVxdWlyZW1lbnRzIGZvciBhIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZSAoTVNFKSBhY2NvcmRpbmcgdG8gdGhlIFtEU00gNV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRFNNLTUpe3RhcmdldD0iX2JsYW5rIn0uPC9zdW1tYXJ5PiAgICANCg0KQS4gRml2ZSBvciBtb3JlIG9mIHRoZSBmb2xsb3dpbmcgc3ltcHRvbXMgaGF2ZSBiZWVuIHByZXNlbnQgYW5kIGRvY3VtZW50ZWQgZHVyaW5nIHRoZSBzYW1lIHR3by13ZWVrIHBlcmlvZCBhbmQgcmVwcmVzZW50IGEgY2hhbmdlIGZyb20gcHJldmlvdXMgZnVuY3Rpb25pbmc7IGF0IGxlYXN0IG9uZSBvZiB0aGUgc3ltcHRvbXMgaXMgZWl0aGVyICgxKSBkZXByZXNzZWQgbW9vZCBvciAoMikgbG9zcyBvZiBpbnRlcmVzdCBvciBwbGVhc3VyZS4gIA0KDQoqKk5vdGUqKjogRG8gbm90IGluY2x1ZGUgc3ltcHRvbXMgdGhhdCBhcmUgY2xlYXJseSBhdHRyaWJ1dGFibGUgdG8gYW5vdGhlciBtZWRpY2FsIGNvbmRpdGlvbi4gIA0KDQoxLiBEZXByZXNzZWQgbW9vZCBtb3N0IG9mIHRoZSBkYXksIG5lYXJseSBldmVyeSBkYXksIGFzIGluZGljYXRlZCBieSBlaXRoZXIgc3ViamVjdGl2ZSByZXBvcnQgKGUuZy4sIGZlZWxzIHNhZCwgZW1wdHksIGhvcGVsZXNzKSBvciBvYnNlcnZhdGlvbiBtYWRlIGJ5IG90aGVycyAoZS5nLiwgYXBwZWFycyB0ZWFyZnVsKSAgDQoNCjIuIE1hcmtlZGx5IGRpbWluaXNoZWQgaW50ZXJlc3Qgb3IgcGxlYXN1cmUgaW4gYWxsLCBvciBhbG1vc3QgYWxsLCBhY3Rpdml0aWVzIG1vc3Qgb2YgdGhlIGRheSwgbmVhcmx5IGV2ZXJ5IGRheSAoYXMgaW5kaWNhdGVkIGJ5IGVpdGhlciBzdWJqZWN0aXZlIGFjY291bnQgb3Igb2JzZXJ2YXRpb24pICANCg0KMy4gU2lnbmlmaWNhbnQgd2VpZ2h0IGxvc3Mgd2hlbiBub3QgZGlldGluZyBvciB3ZWlnaHQgZ2FpbiAoZS5nLiwgYSBjaGFuZ2Ugb2YgbW9yZSB0aGFuIDUlIG9mIGJvZHkgd2VpZ2h0IGluIGEgbW9udGgpLCBvciBkZWNyZWFzZSBvciBpbmNyZWFzZSBpbiBhcHBldGl0ZSBuZWFybHkgZXZlcnkgZGF5ICANCg0KNC4gSW5zb21uaWEgb3IgaHlwZXJzb21uaWEgbmVhcmx5IGV2ZXJ5IGRheSAgDQoNCjUuIFBzeWNob21vdG9yIGFnaXRhdGlvbiBvciByZXRhcmRhdGlvbiBuZWFybHkgZXZlcnkgZGF5IChvYnNlcnZhYmxlIGJ5IG90aGVycywgbm90IG1lcmVseSBzdWJqZWN0aXZlIGZlZWxpbmdzIG9mIHJlc3RsZXNzbmVzcyBvciBiZWluZyBzbG93ZWQgZG93bikgIA0KDQo2LiBGYXRpZ3VlIG9yIGxvc3Mgb2YgZW5lcmd5IG5lYXJseSBldmVyeSBkYXkgIA0KDQo3LiBGZWVsaW5ncyBvZiB3b3J0aGxlc3NuZXNzIG9yIGV4Y2Vzc2l2ZSBvciBpbmFwcHJvcHJpYXRlIGd1aWx0ICh3aGljaCBtYXkgYmUgZGVsdXNpb25hbCkgbmVhcmx5IGV2ZXJ5IGRheSAobm90IG1lcmVseSBzZWxmLXJlcHJvYWNoIG9yIGd1aWx0IGFib3V0IGJlaW5nIHNpY2spICANCg0KOC4gRGltaW5pc2hlZCBhYmlsaXR5IHRvIHRoaW5rIG9yIGNvbmNlbnRyYXRlLCBvciBpbmRlY2lzaXZlbmVzcywgbmVhcmx5IGV2ZXJ5IGRheSAoZWl0aGVyIGJ5IHN1YmplY3RpdmUgYWNjb3VudCBvciBhcyBvYnNlcnZlZCBieSBvdGhlcnMpICANCg0KOS4gUmVjdXJyZW50IHRob3VnaHRzIG9mIGRlYXRoIChub3QganVzdCBmZWFyIG9mIGR5aW5nKSwgcmVjdXJyZW50IHN1aWNpZGFsIGlkZWF0aW9uIHdpdGhvdXQgYSBzcGVjaWZpYyBwbGFuLCBvciBhIHN1aWNpZGUgYXR0ZW1wdCBvciBhIHNwZWNpZmljIHBsYW4gZm9yIGNvbW1pdHRpbmcgc3VpY2lkZSAgDQoNCkIuIFRoZSBzeW1wdG9tcyBkbyBub3QgbWVldCBjcml0ZXJpYSBmb3IgYSBtaXhlZCBlcGlzb2RlLiAgDQoNCkMuIFRoZSBlcGlzb2RlIGlzIG5vdCBhdHRyaWJ1dGFibGUgdG8gdGhlIHBoeXNpb2xvZ2ljYWwgZWZmZWN0cyBvZiBhIHN1YnN0YW5jZSBvciB0byBhbm90aGVyIG1lZGljYWwgY29uZGl0aW9uLiAgDQoNCioqTm90ZSoqOiBDcml0ZXJpYSBBLUMgcmVwcmVzZW50IGEgbWFqb3IgZGVwcmVzc2l2ZSBlcGlzb2RlLiAgDQoNCioqTm90ZSoqOiBSZXNwb25zZXMgdG8gYSBzaWduaWZpY2FudCBsb3NzIChlLmcuLCBiZXJlYXZlbWVudCwgZmluYW5jaWFsIHJ1aW4sIGxvc3NlcyBmcm9tIGEgbmF0dXJhbCBkaXNhc3RlciwgYSBzZXJpb3VzIG1lZGljYWwgaWxsbmVzcyBvciBkaXNhYmlsaXR5KSBtYXkgaW5jbHVkZSBmZWVsaW5ncyBvZiBpbnRlbnNlIHNhZG5lc3MsIHJ1bWluYXRpb24gYWJvdXQgdGhlIGxvc3MsIGluc29tbmlhLCBwb29yIGFwcGV0aXRlIGFuZCB3ZWlnaHQgbG9zcyBub3RlZCBpbiBDcml0ZXJpb24gQSwgd2hpY2ggbWF5IHJlc2VtYmxlIGEgZGVwcmVzc2l2ZSBlcGlzb2RlLiBBbHRob3VnaCBzdWNoIHN5bXB0b21zIG1heSBiZSB1bmRlcnN0YW5kYWJsZSBvciBjb25zaWRlcmVkIGFwcHJvcHJpYXRlIHRvIHRoZSBsb3NzLCB0aGUgcHJlc2VuY2Ugb2YgYSBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGUgaW4gYWRkaXRpb24gdG8gdGhlIG5vcm1hbCByZXNwb25zZSB0byBhIHNpZ25pZmljYW50IGxvc3Mgc2hvdWxkIGFsc28gYmUgY2FyZWZ1bGx5IGNvbnNpZGVyZWQuIFRoaXMgZGVjaXNpb24gaW5ldml0YWJseSByZXF1aXJlcyB0aGUgZXhlcmNpc2Ugb2YgY2xpbmljYWwganVkZ21lbnQgYmFzZWQgb24gdGhlIGluZGl2aWR1YWzigJlzIGhpc3Rvcnkgb2YgYW5kIHRoZSBjdWx0dXJhbCBub3JtcyBmb3IgdGhlIGV4cHJlc3Npb24gb2YgZGlzdHJlc3MgaW4gdGhlIGNvbnRleHQgb2YgbG9zcy4gIA0KDQpELiBUaGUgb2NjdXJyZW5jZSBvZiB0aGUgbWFqb3IgZGVwcmVzc2l2ZSBlcGlzb2RlIGlzIG5vdCBiZXR0ZXIgZXhwbGFpbmVkIGJ5IHNjaGl6b2FmZmVjdGl2ZSBkaXNvcmRlciwgc2NoaXpvcGhyZW5pYSwgc2NoaXpvcGhyZW5pZm9ybSBkaXNvcmRlciwgZGVsdXNpb25hbCBkaXNvcmRlciwgb3Igb3RoZXIgc3BlY2lmaWVkIGFuZCB1bnNwZWNpZmllZCBzY2hpem9waHJlbmlhIHNwZWN0cnVtIGFuZCBvdGhlciBwc3ljaG90aWMgZGlzb3JkZXJzLiAgDQoNCkUuIFRoZXJlIGhhcyBuZXZlciBiZWVuIGEgbWFuaWMgZXBpc29kZSBvciBhIGh5cG9tYW5pYyBlcGlzb2RlLiAgDQoNCk5vdGU6IFRoaXMgZXhjbHVzaW9uIGRvZXMgbm90IGFwcGx5IGlmIGFsbCBvZiB0aGUgbWFuaWMtbGlrZSBvciBoeXBvbWFuaWMtbGlrZSBlcGlzb2RlcyBhcmUgc3Vic3RhbmNlLWluZHVjZWQgb3IgYXJlIGF0dHJpYnV0YWJsZSB0byB0aGUgcGh5c2lvbG9naWNhbCBlZmZlY3RzIG9mIGFub3RoZXIgbWVkaWNhbCBjb25kaXRpb24uICANCg0KIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lmljc2kub3JnL2d1aWRlbGluZS9kZXByZXNzaW9uL2RpYWdub3NlLWFuZC1jaGFyYWN0ZXJpemUtbWFqb3ItZGVwcmVzc2lvbi1wZXJzaXN0ZW50LWRlcHJlc3NpdmUtZGlzb3JkZXItd2l0aC1jbGluaWNhbC1pbnRlcnZpZXcvKXt0YXJnZXQ9Il9ibGFuayJ9DQoNCjwvZGV0YWlscz4gIA0KDQoNCioqKiAgIA0KDQoNClRoaXMgY2FzZSBzdHVkeSBpcyBtb3RpdmF0ZWQgYnkgdGhlIGZvbGxvd2luZyB0d28gYXJ0aWNsZXM6ICANCg0KIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30NCg0KVHdlbmdlIEpNLCBDb29wZXIgQUIsIEpvaW5lciBURSwgRHVmZnkgTUUsIEJpbmF1IFNHLiBBZ2UsIHBlcmlvZCwgYW5kIGNvaG9ydCB0cmVuZHMgaW4gbW9vZCBkaXNvcmRlciBpbmRpY2F0b3JzIGFuZCBzdWljaWRlLXJlbGF0ZWQgb3V0Y29tZXMgaW4gYSBuYXRpb25hbGx5IHJlcHJlc2VudGF0aXZlIGRhdGFzZXQsIDIwMDUtMjAxNy4gKkogQWJub3JtIFBzeWNob2wqLjEyOCwzICgyMDE5KToxODUtMTk5LiBkb2k6MTAuMTAzNy9hYm4wMDAwNDEwDQoNCg0KT2xmc29uLCBNLiwgQmxhbmNvLCBDLiwgV2FuZywgUy4sIExhamUsIEcuICYgQ29ycmVsbCwgQy4gVS4gTmF0aW9uYWwgVHJlbmRzIGluIHRoZSBNZW50YWwgSGVhbHRoIENhcmUgb2YgQ2hpbGRyZW4sIEFkb2xlc2NlbnRzLCBhbmQgQWR1bHRzIGJ5IE9mZmljZS1CYXNlZCBQaHlzaWNpYW5zLiAqSkFNQSBQc3ljaGlhdHJ5Ki4gNzEsIDgxICgyMDE0KTo4MS05MC4gZG9pOiAxMC4xMDAxL2phbWFwc3ljaGlhdHJ5LjIwMTMuMzA3NC4NCg0KIyMjIw0KDQpUaGUgbWFpbiBmaW5kaW5ncyBvZiB0aGUgZmlyc3QgW2FydGljbGVdKGh0dHBzOi8vY29udGVudC5hcGEub3JnL3JlY29yZC8yMDE5LTEyNTc4LTAwMSl7dGFyZ2V0PSJfYmxhbmsifSBhcmU6DQoNCj4gUmF0ZXMgb2YgbWFqb3IgZGVwcmVzc2l2ZSBlcGlzb2RlIGluIHRoZSBsYXN0IHllYXIgaW5jcmVhc2VkIDUyJSAyMDA14oCTMjAxNyAoZnJvbSA4LjclIHRvIDEzLjIlKSBhbW9uZyBhZG9sZXNjZW50cyBhZ2VkIDEyIHRvIDE3IGFuZCA2MyUgMjAwOeKAkzIwMTcgKGZyb20gOC4xJSB0byAxMy4yJSkgYW1vbmcgeW91bmcgYWR1bHRzIDE44oCTMjUuIA0KDQo+IFNlcmlvdXMgcHN5Y2hvbG9naWNhbCBkaXN0cmVzcyBpbiB0aGUgbGFzdCBtb250aCBhbmQgc3VpY2lkZS1yZWxhdGVkIG91dGNvbWVzIChzdWljaWRhbCBpZGVhdGlvbiwgcGxhbnMsIGF0dGVtcHRzLCBhbmQgZGVhdGhzIGJ5IHN1aWNpZGUpIGluIHRoZSBsYXN0IHllYXIgYWxzbyBpbmNyZWFzZWQgYW1vbmcgeW91bmcgYWR1bHRzIDE44oCTMjUgZnJvbSAyMDA44oCTMjAxNyAod2l0aCBhIDcxJSBpbmNyZWFzZSBpbiBzZXJpb3VzIHBzeWNob2xvZ2ljYWwgZGlzdHJlc3MpLCB3aXRoIGxlc3MgY29uc2lzdGVudCBhbmQgd2Vha2VyIGluY3JlYXNlcyBhbW9uZyBhZHVsdHMgYWdlcyAyNiBhbmQgb3Zlci4gDQoNCj4gQ3VsdHVyYWwgdHJlbmRzIGNvbnRyaWJ1dGluZyB0byBhbiBpbmNyZWFzZSBpbiBtb29kIGRpc29yZGVycyBhbmQgc3VpY2lkYWwgdGhvdWdodHMgYW5kIGJlaGF2aW9ycyBzaW5jZSB0aGUgbWlkLTIwMDBzLCBpbmNsdWRpbmcgdGhlIHJpc2Ugb2YgZWxlY3Ryb25pYyBjb21tdW5pY2F0aW9uIGFuZCBkaWdpdGFsIG1lZGlhIGFuZCBkZWNsaW5lcyBpbiBzbGVlcCBkdXJhdGlvbiwgbWF5IGhhdmUgaGFkIGEgbGFyZ2VyIGltcGFjdCBvbiB5b3VuZ2VyIHBlb3BsZSwgY3JlYXRpbmcgYSBjb2hvcnQgZWZmZWN0Lg0KDQpXaGlsZSB0aGUgbWFpbiBmaW5kaW5ncyBvZiB0aGUgc2Vjb25kIFthcnRpY2xlXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzI0Mjg1MzgyLyl7dGFyZ2V0PSJfYmxhbmsifSBhcmU6DQoNCj4gQ29tcGFyZWQgd2l0aCBhZHVsdCBtZW50YWwgaGVhbHRoIGNhcmUsIHRoZSBtZW50YWwgaGVhbHRoDQpjYXJlIG9mIHlvdW5nIHBlb3BsZSBoYXMgaW5jcmVhc2VkIG1vcmUgcmFwaWRseS4uLg0KDQpUaGlzIG1lYW5zIHRoYXQgdGhlIG51bWJlciBvZiB5b3V0aHMgcmVjZWl2aW5nIG1lbnRhbCBoZWFsdGggY2FyZSBoYXMgaW5jcmVhc2VkIGZhc3RlciB0aGFuIHRoZSBudW1iZXIgb2YgYWR1bHRzIHJlY2VpdmluZyBtZW50YWwgaGVhbHRoIGNhcmUuDQoNCj4gQmV0d2VlbiAxOTk1LTE5OTggYW5kIDIwMDctMjAxMCwgdmlzaXRzIHJlc3VsdGluZyBpbiBtZW50YWwgZGlzb3JkZXIgZGlhZ25vc2VzDQouLi4gaW5jcmVhc2VkIHNpZ25pZmljYW50bHkgZmFzdGVyIGZvciB5b3V0aHMgKGZyb20gNy43OCB0byAxNS4zMCB2aXNpdHMpIHRoYW4gZm9yDQphZHVsdHMgKGZyb20gMjMuMjMgdG8gMjguNDggdmlzaXRzKSAoaW50ZXJhY3Rpb246IFAgPCAuMDAxKS4gDQoNCj4gUHN5Y2hpYXRyaXN0IHZpc2l0cyBhbHNvIGluY3JlYXNlZA0Kc2lnbmlmaWNhbnRseSBmYXN0ZXIgZm9yIHlvdXRocyAoZnJvbSAyLjg2IHRvIDUuNzEgdmlzaXRzKS4NCg0KDQoqKlN1bW1hcnkqKjogV2hpbGUgZGVwcmVzc2lvbiBhcHBlYXJzIHRvIGJlIG9uIHRoZSByaXNlIGZvciB5b3V0aHMsIHlvdXRocyBhbHNvIGFwcGVhciB0byBiZSBzZWVraW5nIG1vcmUgbWVudGFsIGhlYWx0aCBjYXJlLg0KDQpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgYmUgdXNpbmcgZGF0YSBmcm9tIHRoZSBbTmF0aW9uYWwgU3VydmV5IG9uIERydWcgVXNlIGFuZCBIZWFsdGggKE5TRFVIKV0oaHR0cHM6Ly9uc2R1aHdlYi5ydGkub3JnL3Jlc3B3ZWIvaG9tZXBhZ2UuY2ZtKXt0YXJnZXQ9Il9ibGFuayJ9IHJlbGF0ZWQgdG8gdHJlYXRtZW50IGFuZCBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGUgKE1ERSkgcmF0ZSB0byBleHBsb3JlIGhvdyB0cmVuZHMgaW4gbWVudGFsIGhlYWx0aCBoYXZlIGNoYW5nZWQgb3ZlciB0aW1lIGFuZCBob3cgZGlmZmVyZW50IGdyb3VwcyBjb21wYXJlLiANCg0KVGhpcyBkYXRhIHdhcyBhbHNvIHVzZWQgaW4gdGhlIGZpcnN0IHJlZmVyZW5jZWQgYXJ0aWNsZS4gIA0KDQoNCiMjICoqTWFpbiBRdWVzdGlvbnMqKg0KKioqIA0KDQojIyMjIHsubWFpbl9xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBPdXIgbWFpbiBxdWVzdGlvbnM6IDwvdT48L2I+DQoNCjEuIEhvdyBoYXZlIGRlcHJlc3Npb24gcmF0ZXMgaW4gQW1lcmljYW4geW91dGggY2hhbmdlZCBzaW5jZSAyMDA0LCBhY2NvcmRpbmcgdG8gdGhlIE5TRFVIIGRhdGE/IEhvdyBoYXZlIHJhdGVzIGRpZmZlcmVkIGJldHdlZW4gZGlmZmVyZW50IHlvdXRoIHN1Ymdyb3VwcyAoYWdlLCBnZW5kZXIsIGV0aG5pY2l0eSk/DQoyLiBEbyBtZW50YWwgaGVhbHRoIHNlcnZpY2VzIGFwcGVhciB0byBiZSByZWFjaGluZyBtb3JlIHlvdXRocz8gQWdhaW4sIGhvdyBoYXZlIHJhdGVzIGRpZmZlcmVkIGJldHdlZW4gZGlmZmVyZW50IHlvdXRoIHN1Ymdyb3VwcyAoYWdlLCBnZW5kZXIsIGV0aG5pY2l0eSk/DQoNCiMjIyMNCg0KIyMgKipMZWFybmluZyBPYmplY3RpdmVzKiogDQoqKiogDQpUaGUgc2tpbGxzLCBtZXRob2RzLCBhbmQgY29uY2VwdHMgdGhhdCBzdHVkZW50cyB3aWxsIGJlIGZhbWlsaWFyIHdpdGggYnkgdGhlIGVuZCBvZiB0aGlzIGNhc2Ugc3R1ZHkgYXJlOg0KDQo8dT4qKkRhdGEgU2NpZW5jZSBMZWFybmluZyBPYmplY3RpdmVzOioqPC91Pg0KDQoxLiBTY3JhcGUgZGF0YSBkaXJlY3RseSBmcm9tIGEgd2Vic2l0ZSAoYHJ2ZXN0YCkgIA0KMi4gU3Vic2V0IGFuZCBmaWx0ZXIgZGF0YSAoYGRwbHlyYCkgIA0KMy4gV3JpdGUgZnVuY3Rpb25zIHRvIHdyYW5nbGUgZGF0YSByZXBldGl0aXZlbHkgIA0KNC4gV29yayB3aXRoIGNoYXJhY3RlciBzdHJpbmdzIChgc3RyaW5ncmApICANCjUuIFJlc2hhcGUgZGF0YSBpbnRvIGRpZmZlcmVudCBmb3JtYXRzIChgdGlkeXJgKSAgDQo2LiBEYXRhIHZpc3VhbGl6YXRpb25zIChgZ2dwbG90MmApIHdpdGggbGFiZWxzIChgZGlyZWN0bGFiZWxzYCkgYW5kIGZhY2V0cyBmb3IgZGlmZmVyZW50IGdyb3VwcyAgDQo3LiBDb21iaW5lIG11bHRpcGxlIHBsb3RzIChgY293cGxvdGApICANCjguIE9wdGlvbmFsOiBDcmVhdGUgYW4gYW5pbWF0ZWQgZ2lmIChgbWFnaWNrYCkgIA0KDQo8dT4qKlN0YXRpc3RpY2FsIExlYXJuaW5nIE9iamVjdGl2ZXM6Kio8L3U+IA0KDQoxLiBEaXNjdXNzIHRoZSBpbXBhY3Qgb2Ygc2VsZi1yZXBvcnRpbmcgYmlhcyBvbiBzdXJ2ZXkgcmVzcG9uc2VzICANCjIuIERlZmluZSBhbmQgY3JlYXRlIGEgY29udGluZ2VuY3kgdGFibGUgIA0KMy4gSW1wbGVtZW50YXRpb24gb2YgYSBjaGktc3F1YXJlZCB0ZXN0IGZvciBpbmRlcGVuZGVuY2UgIA0KNC4gSW50ZXJwcmV0YXRpb24gb2YgYSBjaGktc3F1YXJlZCB0ZXN0IGZvciBpbmRlcGVuZGVuY2UgIA0KDQpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgZXNwZWNpYWxseSBmb2N1cyBvbiB1c2luZyBwYWNrYWdlcyBhbmQgZnVuY3Rpb25zIGZyb20gdGhlIFtgVGlkeXZlcnNlYF0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0sIHN1Y2ggYXMgW2BydmVzdGBdKGh0dHBzOi8vZ2l0aHViLmNvbS90aWR5dmVyc2UvcnZlc3Qpe3RhcmdldD0iX2JsYW5rIn0uIFRoZSB0aWR5dmVyc2UgaXMgYSBsaWJyYXJ5IG9mIHBhY2thZ2VzIGNyZWF0ZWQgYnkgUlN0dWRpby4gV2hpbGUgc29tZSBzdHVkZW50cyBtYXkgYmUgZmFtaWxpYXIgd2l0aCBwcmV2aW91cyBSIHByb2dyYW1taW5nIHBhY2thZ2VzLCB0aGVzZSBwYWNrYWdlcyBtYWtlIGRhdGEgc2NpZW5jZSBpbiBSIG1vcmUgbGVnaWJsZSBhbmQgaW50dWl0aXZlLg0KDQoNCmBgYHtyLCBvdXQud2lkdGggPSAiMjAlIiwgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIifQ0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpDQpgYGANCg0KKioqIA0KDQpXZSB3aWxsIGJlZ2luIGJ5IGxvYWRpbmcgdGhlIHBhY2thZ2VzIHRoYXQgd2Ugd2lsbCBuZWVkOg0KDQpgYGB7cn0NCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkocnZlc3QpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShtYWdyaXR0cikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHRpYmJsZSkNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRpcmVjdGxhYmVscykNCmxpYnJhcnkoc2NhbGVzKQ0KbGlicmFyeShmb3JjYXRzKQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkocnN0YXRpeCkNCmxpYnJhcnkoY293cGxvdCkNCmxpYnJhcnkoT0NTZGF0YSkNCmBgYA0KDQo8dT4qKlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OioqIDwvdT4NCg0KIFBhY2thZ2UgICB8IFVzZSBpbiB0aGlzIGNhc2Ugc3R1ZHkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQ0KW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSl7dGFyZ2V0PSJfYmxhbmsifSAgICAgICB8IHRvIGVhc2lseSBsb2FkIGFuZCBzYXZlIGRhdGEgIA0KW3J2ZXN0XShodHRwczovL2dpdGh1Yi5jb20vdGlkeXZlcnNlL3J2ZXN0KXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBzY3JhcGUgd2ViIHBhZ2VzICANCltkcGx5cl0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gc3Vic2V0IGFuZCBmaWx0ZXIgdGhlIGRhdGEgZm9yIHNwZWNpZmljIGdyb3VwcywgdG8gcmVwbGFjZSBzcGVjaWZpYyB2YWx1ZXMgd2l0aCBgTkFgLCByZW5hbWUgdmFyaWFibGVzLCAgYW5kIHBlcmZvcm0gZnVuY3Rpb25zIG9uIG11bHRpcGxlIHZhcmlhYmxlcyAgICAgDQpbbWFncml0dHJdKGh0dHBzOi8vbWFncml0dHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHVzZSBhbmQgcmVhc3NpZ24gZGF0YSBvYmplY3RzIHVzaW5nIHRoZSAlPD4lcGlwZSBvcGVyYXRvciAgDQpbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBtYW5pcHVsYXRlIHN0cmluZ3MgIA0KW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBjaGFuZ2UgdGhlIHNoYXBlIG9yIGZvcm1hdCBvZiB0aWJibGVzIHRvIHdpZGUgYW5kIGxvbmcgIA0KW3RpYmJsZV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGNyZWF0ZSB0aWJibGVzIGFuZCBjb252ZXJ0IHZhbHVlcyBvZiBhIGNvbHVtbiB0byByb3cgbmFtZXMgIA0KW3B1cnJyXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gYXBwbHkgYSBmdW5jdGlvbiB0byBlYWNoIGNvbHVtbiBvZiBhIHRpYmJsZSBvciBlYWNoIHRpYmJsZSBpbiBhIGxpc3QgICAgIA0KW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gY3JlYXRlIHBsb3RzICANCltkaXJlY3RsYWJlbHNdKGh0dHA6Ly9kaXJlY3RsYWJlbHMuci1mb3JnZS5yLXByb2plY3Qub3JnL2RvY3MvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gYWRkIGxhYmVscyBkaXJlY3RseSB0byBsaW5lcyBpbiBwbG90cyAgDQpbc2NhbGVzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc2NhbGVzL3NjYWxlcy5wZGYpICB8IHRvIGdldCB0aGUgY3VycmVudCBsaW5ldHlwZSBvcHRpb25zICANCltmb3JjYXRzXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHJlb3JkZXIgZmFjdG9yIGZvciBwbG90DQpbZ2d0aGVtZXNdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3RoZW1lcy9nZ3RoZW1lcy5wZGYpIHwgdG8gY3JlYXRlIGEgcGxvdCB0byBzZWUgd2hhdCB0aGUgZGlmZmVyZW50IGxpbmV0eXBlcyBsb29rIGxpa2UgIA0KW3JzdGF0aXhdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yc3RhdGl4L3JzdGF0aXgucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gcHJlZm9ybSBwcm9wb3J0aW9uIHRlc3QgICANCltjb3dwbG90XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvY293cGxvdC92aWduZXR0ZXMvaW50cm9kdWN0aW9uLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGNvbWJpbmUgcGxvdHMgdG9nZXRoZXINCltPQ1NkYXRhXShodHRwczovL2dpdGh1Yi5jb20vb3BlbmNhc2VzdHVkaWVzL09DU2RhdGEpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBhY2Nlc3MgYW5kIGRvd25sb2FkIE9DUyBkYXRhIGZpbGVzDQoNCg0KVGhlIGZpcnN0IHRpbWUgd2UgdXNlIGEgZnVuY3Rpb24sIHdlIHdpbGwgdXNlIHRoZSBgOjpgIHRvIGluZGljYXRlIHdoaWNoIHBhY2thZ2Ugd2UgYXJlIHVzaW5nLiBVbmxlc3Mgd2UgaGF2ZSBvdmVybGFwcGluZyBmdW5jdGlvbiBuYW1lcywgdGhpcyBpcyBub3QgbmVjZXNzYXJ5LCBidXQgd2Ugd2lsbCBpbmNsdWRlIGl0IGhlcmUgdG8gYmUgaW5mb3JtYXRpdmUgYWJvdXQgd2hlcmUgdGhlIGZ1bmN0aW9ucyB3ZSB3aWxsIHVzZSBjb21lIGZyb20uDQoNCiMjICoqQ29udGV4dCoqDQoqKiogDQoNClRvIG1vdGl2YXRlIHRoZSBleGFtaW5hdGlvbiBvZiB0aGUgbWVudGFsIGhlYWx0aCBvZiBBbWVyaWNhbiB5b3V0aHMsIHdlIGJlZ2luIGJ5IGV4cGxvcmluZyB0aGUgcmF0ZSBvZiBzdWljaWRlIGluIHRoZSBVbml0ZWQgU3RhdGVzIChVUykuIA0KQWNjb3JkaW5nIHRvIHRoZSBDREMgdGhlIHJhdGUgb2Ygc3VpY2lkZSBoYXMgaW5jcmVhc2VkIGZvciBib3RoIGdlbmRlcnMuDQoNCg0KYGBge3IsIG91dC53aWR0aCA9ICI4MCUiLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciJ9DQppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3d3dy5jZGMuZ292L25jaHMvaW1hZ2VzL2RhdGFicmllZnMvMzAxLTM1MC9kYjMwOV9maWcxLnBuZyIpDQoNCmBgYA0KDQojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3LmNkYy5nb3YvbmNocy9wcm9kdWN0cy9kYXRhYnJpZWZzL2RiMzA5Lmh0bSl7dGFyZ2V0PSJfYmxhbmsifQ0KDQoNCldoaWxlIHN1aWNpZGUgZG9lcyBhcHBlYXIgdG8gYmUgaW5jcmVhc2luZyBhbW9uZyB5b3V0aHMgaXQgYWxzbyBhcHBlYXJzIHRvIGJlIGluY3JlYXNpbmcgYW1vbmcgbW9zdCBhZ2UgZ3JvdXBzIGluIHRoZSBVUyBvdmVyIHRoZSBwYXN0IGRlY2FkZSBhbmQgYSBoYWxmIGZvciBib3RoIGZlbWFsZXMgYW5kIG1hbGVzOiANCg0KYGBge3IgaW1hZ2VfZ3JvYnMsIGVjaG8gPSBGQUxTRSwgZmlnLnNob3cgPSAiaG9sZCIsIG91dC53aWR0aCA9ICI1MCUiLCBmaWcuYWxpZ24gPSAiZGVmYXVsdCJ9DQppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3d3dy5jZGMuZ292L25jaHMvaW1hZ2VzL2RhdGFicmllZnMvMzAxLTM1MC9kYjMwOV9maWcyLnBuZyIpDQppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3d3dy5jZGMuZ292L25jaHMvaW1hZ2VzL2RhdGFicmllZnMvMzAxLTM1MC9kYjMwOV9maWczLnBuZyIpDQoNCmBgYA0KDQojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3LmNkYy5nb3YvbmNocy9wcm9kdWN0cy9kYXRhYnJpZWZzL2RiMzA5Lmh0bSl7dGFyZ2V0PSJfYmxhbmsifQ0KDQpBY2NvcmRpbmcgdG8gdGhlIFtDRENdKGh0dHBzOi8vd3d3LmNkYy5nb3YvbmNocy9wcm9kdWN0cy9kYXRhYnJpZWZzL2RiMzA5Lmh0bSl7dGFyZ2V0PSJfYmxhbmsifToNCg0KPiBTaW5jZSAyMDA4LCBzdWljaWRlIGhhcyByYW5rZWQgYXMgdGhlIDEwdGggbGVhZGluZyBjYXVzZSBvZiBkZWF0aCBmb3IgKiphbGwgYWdlcyoqIGluIHRoZSBVbml0ZWQgU3RhdGVzLiANCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI4MDBweCJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJtb3J0YWxpdHkucG5nIikpDQpgYGANCg0KIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5jZGMuZ292L25jaHMvZGF0YS9kYXRhYnJpZWZzL2RiMjkzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgIA0KDQpGdXJ0aGVybW9yZSwgYWNjb3JkaW5nIHRvIHRoZSBbQ0RDXShodHRwczovL3d3dy5jZGMuZ292L25jaHMvcHJvZHVjdHMvZGF0YWJyaWVmcy9kYjMwOS5odG0pe3RhcmdldD0iX2JsYW5rIn06DQoNCj5JbiAyMDE2LCBzdWljaWRlIGJlY2FtZSB0aGUgKipzZWNvbmQgbGVhZGluZyBjYXVzZSBvZiBkZWF0aCoqIGFtb25nIHlvdXRocy4NCg0KDQoqKlNvIGFsdGhvdWdoIHN1aWNpZGUgaXMgb24gdGhlIHJpc2UgZm9yIG1vc3QgYWdlIGdyb3Vwcywgc3VpY2lkZSBpcyBvbmUgb2YgdGhlIHRvcCAqdHdvKiBjb250cmlidXRvcnMgdG8gZGVhdGggZm9yIHlvdXRocy4qKiAgIA0KDQpUaHVzLCB0aGlzIHdhcnJhbnRzIGZ1cnRoZXIgZXhhbWluYXRpb24gb2YgdGhlIG1lbnRhbCBoZWFsdGggb2YgQW1lcmljYW4geW91dGhzLiAgDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iODAwcHgifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwibW9ydGFsaXR5X2FnZS5wbmciKSkNCmBgYA0KDQojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3LmNkYy5nb3YvbmNocy9kYXRhL252c3IvbnZzcjY4L252c3I2OF8wNi01MDgucGRmKXt0YXJnZXQ9Il9ibGFuayJ9DQoNCg0KSGlzdG9yaWNhbGx5LCBzdWljaWRlIHJhdGVzIHdlcmUgbXVjaCBoaWdoZXIgYmVmb3JlIDE5NTAsIGhvd2V2ZXIsIHdlIGFyZSBzZWVpbmcgYW4gaW5jcmVhc2UgaW4gdGhlIGxhc3QgMjAgeWVhcnMuDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iODAwcHgifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwic3VpY2lkZS5wbmciKSkNCmBgYA0KDQojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vdGltZS5jb20vNTYwOTEyNC91cy1zdWljaWRlLXJhdGUtaW5jcmVhc2UvKXt0YXJnZXQ9Il9ibGFuayJ9DQoNCg0KQmVzaWRlcyB0aGUgVVMsIFtvdGhlciBjb3VudHJpZXNdKGh0dHBzOi8vYWNhZGVtaWMub3VwLmNvbS9pamUvYXJ0aWNsZS80OC81LzE2NTAvNTM2NjIxMCl7dGFyZ2V0PSJfYmxhbmsifSBhcmUgYWxzbyBleHBlcmllbmNpbmcgaW5jcmVhc2VkIHJhdGVzIG9mIGRlcHJlc3Npb24gaW4geW91dGhzLiANCg0KU2VlIFt0aGlzIHJlcG9ydF0oaHR0cHM6Ly9hcHBzLndoby5pbnQvaXJpcy9iaXRzdHJlYW0vaGFuZGxlLzEwNjY1LzI1NDYxMC9XSE8tTVNELU1FUi0yMDE3LjItZW5nLnBkZjtqc2Vzc2lvbmlkPUU0NDM2MDA1NUREODNFQUM0NzJBQTQwQzI4NTNEQkZBP3NlcXVlbmNlPTEpe3RhcmdldD0iX2JsYW5rIn0gZnJvbSB0aGUgV29ybGQgSGVhbHRoIE9yZ2FuaXphdGlvbiAoV0hPKSBhYm91dCByYXRlcyBvZiBkZXByZXNzaW9uIGluIG90aGVyIGNvdW50cmllcy4NCg0KU2VlIFtoZXJlXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUMzMzMwMTYxLyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgYW4gaW50ZXJlc3RpbmcgZGlzY3Vzc2lvbiBhYm91dCB3aGF0IG1heSBiZSBjYXVzaW5nIGluY3JlYXNlZCBkZXByZXNzaW9uIHJhdGVzLiANCg0KDQoNCiMjICoqTGltaXRhdGlvbnMqKg0KKioqIA0KDQpUaGVyZSBhcmUgc29tZSBpbXBvcnRhbnQgY29uc2lkZXJhdGlvbnMgcmVnYXJkaW5nIHRoaXMgZGF0YSBhbmFseXNpcyB0byBrZWVwIGluIG1pbmQ6IA0KDQoxLiBUaGUgZGF0YSB0aGF0IHdlIHdpbGwgdXNlIGNvbWUgZnJvbSBhIHN1cnZleSBhbmQgYXJlIHRoZXJlZm9yZSB2YWx1ZXMgZnJvbSBhIHNhbXBsZSB0aGF0IGVzdGltYXRlIHRoYXQgb2YgdGhlIHRydWUgcG9wdWxhdGlvbi4gSW4gb3VyIHN0YXRpc3RpY2FsIGFuYWx5c2lzIHdlIHVzZSB0aGVzZSBzYW1wbGUgdmFsdWVzIGFzIGlmIHRoZXkgYXJlIHBvcHVsYXRpb24gZXN0aW1hdGVzIChiZWNhdXNlIHRoaXMgaXMgYWxsIHdlIGhhdmUgYWNjZXNzIHRvKS4gVGh1cywgb3VyIHJlc3VsdHMgYXJlIG5vdCBuZWNlc3NhcmlseSBpbmRpY2F0aXZlIG9mIHBvcHVsYXRpb24gZGlmZmVyZW5jZXMuDQoNCjIuIEZ1cnRoZXJtb3JlLCB0aGUgc2FtcGxpbmcgbWVjaGFuaXNtIHV0aWxpemVkIGZvciB0aGUgc3VydmV5IGNhbiBpbnRyb2R1Y2UgW3NlbGVjdGlvbiBiaWFzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TZWxlY3Rpb25fYmlhcz9vbGRmb3JtYXQ9dHJ1ZSl7dGFyZ2V0PSJfYmxhbmsifSBpbiBjYXNlcyB3aGVyZSB0aGUgdGhlIFtzYW1wbGluZyBtZXRob2RzIGRvIG5vdCBwcm9kdWNlIGEgcmVwcmVzZW50YXRpdmUgc2FtcGxlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TYW1wbGluZ18oc3RhdGlzdGljcyk/b2xkZm9ybWF0PXRydWUpe3RhcmdldD0iX2JsYW5rIn0uIA0KDQozLiBEYXRhIGFyZSBjb2xsZWN0ZWQgZnJvbSBodW1hbiBwYXJ0aWNpcGFudHM7IHRoaXMgcHJlc2VudHMgdGhlICpwb3RlbnRpYWwqIGZvciBpbmZvcm1hdGlvbiBiaWFzLCBhcyB0aGVyZSBpcyB0aGUgKnBvdGVudGlhbCogdGhhdCBwYXJ0aWNpcGFudHMgaW4gdGhlIFtzYW1wbGluZyBmcmFtZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2FtcGxpbmdfZnJhbWU/b2xkZm9ybWF0PXRydWUpe3RhcmdldD0iX2JsYW5rIn0gbWF5IGZvciBhIHZhcmlldHkgb2YgcmVhc29ucyByZXBvcnQgaW5hY2N1cmF0ZSBpbmZvcm1hdGlvbi4gDQoNCjQuIERhdGEgYWJvdXQgY2VydGFpbiBncm91cCBbaW50ZXJzZWN0aW9uc10oaHR0cHM6Ly93d3cudm94LmNvbS90aGUtaGlnaGxpZ2h0LzIwMTkvNS8yMC8xODU0Mjg0My9pbnRlcnNlY3Rpb25hbGl0eS1jb25zZXJ2YXRpc20tbGF3LXJhY2UtZ2VuZGVyLWRpc2NyaW1pbmF0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9IChtZWFuaW5nIGZvciBleGFtcGxlIGluZGl2aWR1YWxzIG9mIGEgcGFydGljdWxhciBnZW5kZXIgYW5kIGV0aG5pY2l0eSkgb3IgcGFydGljdWxhciBncm91cHMgaW4gZ2VuZXJhbCBzdWNoIGFzIHNwZWNpZmljIGV0aG5pY2l0aWVzIG9yIGdlbmRlciBvciBzZXh1YWwgaWRlbnRpdHkgZ3JvdXBzIHN1Y2ggYXMgTEdCVFFJQSsgKGxlc2JpYW4vZ2F5L2Jpc2V4dWFsL3RyYW5zZ2VuZGVyL3F1ZWVyIGFuZCBxdWVzdGlvbmluZykgb3Igbm9uLWJpbmFyeSBnZW5kZXIgcG9wdWxhdGlvbnMgaXMgdW5mb3J0dW5hdGVseSBub3QgYXZhaWxhYmxlIGluIHRoZSBkYXRhIHVzZWQgaW4gdGhpcyBhbmFseXNpcyBhbmQgaW4gbW9zdCByZXNlYXJjaCBhYm91dCB0aGlzIHRvcGljLg0KDQpOb3RlOiBXaGlsZSBbZ2VuZGVyIGFuZCBzZXhdKGh0dHBzOi8vd3d3Lndoby5pbnQvZ2Vub21pY3MvZ2VuZGVyL2VuL2luZGV4Lmh0bWwpIGFyZSBub3QgYWN0dWFsbHkgYmluYXJ5LCB0aGUgZGF0YSB1c2VkIGluIHRoaXMgYW5hbHlzaXMgdW5mb3J0dW5hdGVseSBvbmx5IGNvbnRhaW5zIGluZm9ybWF0aW9uIGZvciBncm91cHMgb2YgaW5kaXZpZHVhbHMgd2hvIHNlbGYtcmVwb3J0ZWQgYXMgbWFsZSBvciBmZW1hbGUuIFdlIGFsc28gYWNrbm93bGVkZ2UgdGhhdCB1bmZvcnR1bmF0ZWx5IG5vdCBhbGwgZXRobmljaXRpZXMgb3IgZ3JvdXAgaW50ZXJzZWN0aW9ucyBhcmUgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGEgZWl0aGVyLiBNb3JlIHJlc2VhcmNoIHNob3VsZCBiZSBkZXZvdGVkIHRvIGNvbGxlY3RpbmcgZGF0YSBhYm91dCB0aGUgbWVudGFsIGhlYWx0aCBvZiB0aGVzZSBncm91cHMuIA0KDQojIyAqKldoYXQgYXJlIHRoZSBkYXRhPyoqDQoqKiogDQoNCldlIHdpbGwgYmUgdXNpbmcgZGF0YSBmcm9tIHRoZSBbTmF0aW9uYWwgU3VydmV5IG9uIERydWcgVXNlIGFuZCBIZWFsdGggKE5TRFVIKV0oaHR0cHM6Ly9uc2R1aHdlYi5ydGkub3JnL3Jlc3B3ZWIvaG9tZXBhZ2UuY2ZtKXt0YXJnZXQ9Il9ibGFuayJ9IHdoaWNoIGlzIGRpcmVjdGVkIGJ5IHRoZSBbU3Vic3RhbmNlIEFidXNlIGFuZCBNZW50YWwgSGVhbHRoIFNlcnZpY2VzIEFkbWluaXN0cmF0aW9uIChTQU1IU0EpXShodHRwczovL3d3dy5zYW1oc2EuZ292Lyl7dGFyZ2V0PSJfYmxhbmsifSwgYW4gYWdlbmN5IGluIHRoZSBbVS5TLiBEZXBhcnRtZW50IG9mIEhlYWx0aCBhbmQgSHVtYW4gU2VydmljZXMgKERISFMpXShodHRwczovL3d3dy5oaHMuZ292Lyl7dGFyZ2V0PSJfYmxhbmsifS4gDQoNClRoaXMgc3VydmV5IHN0YXJ0ZWQgaW4gMTk3MSBhbmQgaXMgY29uZHVjdGVkIGFubnVhbGx5IGluIGFsbCA1MCBzdGF0ZXMgYW5kIHRoZSBEaXN0cmljdCBvZiBDb2x1bWJpYS4gQXBwcm94aW1hdGVseSA3MCwwMDAgcGVvcGxlIChhZ2VzIDEyIGFuZCB1cCkgYXJlIGludGVydmlld2VkIGVhY2ggeWVhciBhYm91dCBoZWFsdGgtcmVsYXRlZCBpc3N1ZXMuIE9ubHkgY2l2aWxpYW4sIG5vbi1pbnN0aXR1dGlvbmFsaXplZCBpbmRpdmlkdWFscyBhcmUgaW5jbHVkZWQuIEhvdXNlaG9sZHMgYXJlIHJhbmRvbWx5IHNlbGVjdGVkIGFuZCB0aGVuIGEgcHJvZmVzc2lvbmFsIGludGVydmlld2VyIHZpc2l0cyB0aGUgYWRkcmVzc2VzIGFuZCBhc2tzIG9uZSBvciB0d28gb2YgdGhlIHJlc2lkZW50cyB0byBpbnRlcnZpZXcuIFRoZSBpbnRlcnZpZXdlciBicmluZ3MgYSBsYXB0b3Agd2l0aCB0aGVtIHRoYXQgdGhlIHBhcnRpY2lwYW50cyB1c2UgdG8gZmlsbCBvdXQgdGhlIHN1cnZleSwgd2hpY2ggdHlwaWNhbGx5IHRha2VzIGFuIGhvdXIgdG8gY29tcGxldGUuIElmIGEgcGFydGljaXBhbnQgY2hvb3NlcyB0byBwYXJ0aWNpcGF0ZSB0aGV5IHJlY2VpdmUgJDMwIGluIGNhc2guIEFsbCBjb2xsZWN0ZWQgaW5mb3JtYXRpb24gaXMgY29uZmlkZW50aWFsIGFuZCBpcyB1c2VkIGZvciBkaXNlYXNlIHN1cnZlaWxsYW5jZSBhbmQgdG8gZ3VpZGUgcHVibGljIHBvbGljeSBwYXJ0aWN1bGFybHkgZm9jdXNlZCBvbiBkcnVnIGFuZCBhbGNvaG9sIHVzZSBhcyB3ZWxsIGFzIG1lbnRhbCBoZWFsdGguIFNlZSBbaGVyZV0oaHR0cHM6Ly9uc2R1aHdlYi5ydGkub3JnL3Jlc3B3ZWIvYWJvdXRfbnNkdWguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBkZXRhaWxzIGFib3V0IHRoZSBzdXJ2ZXkuDQoNClRoZSBkYXRhIGFyZSBtYWRlIGF2YWlsYWJsZSBwdWJsaWNseSBvbmxpbmUgb24gdGhlIFtTdWJzdGFuY2UgQWJ1c2UgJiBNZW50YWwgSGVhbHRoIERhdGEgQXJjaGl2ZV0oaHR0cHM6Ly9kYXRhZmlsZXMuc2FtaHNhLmdvdi8pe3RhcmdldD0iX2JsYW5rIn0uIA0KDQpgYGB7ciwgb3V0LndpZHRoID0gIjEwMCUiLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ImNlbnRlciJ9DQppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJuc3VkaF9zY3JlZW5zaG90X3dlYnBhZ2UucG5nIikpDQpgYGANCg0KT24gdGhlIFt3ZWJzaXRlXShodHRwczovL3d3dy5zYW1oc2EuZ292L2RhdGEvc2l0ZXMvZGVmYXVsdC9maWxlcy9jYmhzcS1yZXBvcnRzL05TRFVIRGV0YWlsZWRUYWJzMjAxOFIyL05TRFVIRGV0VGFic1NlY3QxMXBlMjAxOC5odG0pe3RhcmdldD0iX2JsYW5rIn0gd2l0aCB0aGUgc3VydmV5IGRhdGEsIHlvdSBjYW4gc2VlIHRoYXQgdGhlIHJlc3VsdHMgYXJlIGRpc3BsYXllZCBpbiBtYW55IHRhYmxlcy4gSW1wb3J0YW50bHksIHRoZXJlIGlzIG5vIG9idmlvdXMgd2F5IHRvIGRvd25sb2FkIHRoZSBkYXRhIGRpcmVjdGx5IGZyb20gdGhpcyBwYXJ0aWN1bGFyIHdlYnNpdGUuDQoNCmBgYHtyLCBvdXQud2lkdGggPSAiMTAwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0NCmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIndlYnNpdGVfb3ZlcnZpZXcucG5nIikpDQpgYGANCg0KDQpJZiB5b3UgY2xpY2sgb24gdGhlIFRPQyBidXR0b24gb24gdGhlIGZhciBsZWZ0IHVwcGVyIGNvcm5lciwgeW91IHdpbGwgYmUgZGlyZWN0ZWQgdG8gYW5vdGhlciBbd2Vic2l0ZV0oaHR0cHM6Ly93d3cuc2FtaHNhLmdvdi9kYXRhL3NpdGVzL2RlZmF1bHQvZmlsZXMvY2Joc3EtcmVwb3J0cy9OU0RVSERldGFpbGVkVGFiczIwMThSMi9OU0RVSERldGFpbGVkVGFic1RPQzIwMTguaHRtI3RvYyl7dGFyZ2V0PSJfYmxhbmsifSwgd2hlcmUgYSBsYXJnZSBbcGRmIGRvY3VtZW50XShodHRwczovL3d3dy5zYW1oc2EuZ292L2RhdGEvc2l0ZXMvZGVmYXVsdC9maWxlcy9jYmhzcS1yZXBvcnRzL05TRFVIRGV0YWlsZWRUYWJzMjAxOFIyL05TRFVIRGV0YWlsZWRUYWJzMjAxOC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gY29udGFpbmluZyBhbGwgb2YgdGhlIHJlc3VsdHMgY2FuIGJlIGRvd25sb2FkZWQuDQoNCg0KV2UgYXJlIGludGVyZXN0ZWQgaW4gaW52ZXN0aWdhdGluZyBob3cgZGVwcmVzc2lvbiByYXRlcyBoYXZlIGNoYW5nZWQgYW5kIGhvdyB5b3V0aHMgYXJlIGludGVyYWN0aW5nIHdpdGggbWVudGFsIGhlYWx0aCBzZXJ2aWNlcy4gVGh1cywgdGhlIGZvbGxvd2luZyB0YWJsZXMgYXJlIG9mIGludGVyZXN0IHRvIHVzOg0KDQpUYWJsZSAgIHwgRGV0YWlscyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCi0tLXwtLS0tLS0tLS0tLS0tDQpUYWJsZSAxMS4xQSAgICAgICB8IFNldHRpbmdzIFdoZXJlIE1lbnRhbCBIZWFsdGggU2VydmljZXMgV2VyZSBSZWNlaXZlZCBpbiBQYXN0IFllYXIgYW1vbmcgUGVyc29ucyBBZ2VkIDEyIHRvIDE3OiBOdW1iZXJzIGluIFRob3VzYW5kcywgMjAwMi0yMDE4ICAgDQpUYWJsZSAxMS4xQiAgICAgICB8IFNldHRpbmdzIFdoZXJlIE1lbnRhbCBIZWFsdGggU2VydmljZXMgV2VyZSBSZWNlaXZlZCBpbiBQYXN0IFllYXIgYW1vbmcgUGVyc29ucyBBZ2VkIDEyIHRvIDE3OiBQZXJjZW50YWdlcywgMjAwMi0yMDE4ICANClRhYmxlIDExLjJBICAgICAgIHwgIE1ham9yIERlcHJlc3NpdmUgRXBpc29kZSBpbiBQYXN0IFllYXIgYW1vbmcgUGVyc29ucyBBZ2VkIDEyIHRvIDE3LCBieSBEZW1vZ3JhcGhpYyBDaGFyYWN0ZXJpc3RpY3M6IE51bWJlcnMgaW4gVGhvdXNhbmRzLCAyMDA0LTIwMTgNClRhYmxlIDExLjJCICAgICAgIHwgTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlIGluIFBhc3QgWWVhciBhbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTcsIGJ5IERlbW9ncmFwaGljIENoYXJhY3RlcmlzdGljczogUGVyY2VudGFnZXMsIDIwMDQtMjAxOA0KVGFibGUgMTEuM0EgICAgICAgfCBNYWpvciBEZXByZXNzaXZlIEVwaXNvZGUgd2l0aCBTZXZlcmUgSW1wYWlybWVudCBpbiBQYXN0IFllYXIgYW1vbmcgUGVyc29ucyBBZ2VkIDEyIHRvIDE3LCBieSBEZW1vZ3JhcGhpYyBDaGFyYWN0ZXJpc3RpY3M6IE51bWJlcnMgaW4gVGhvdXNhbmRzLCAyMDA2LTIwMTgNClRhYmxlIDExLjNCICAgICAgIHwgTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlIHdpdGggU2V2ZXJlIEltcGFpcm1lbnQgaW4gUGFzdCBZZWFyIGFtb25nIFBlcnNvbnMgQWdlZCAxMiB0byAxNywgYnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzOiBQZXJjZW50YWdlcywgMjAwNi0yMDE4DQpUYWJsZSAxMS40QSAgICAgICB8IFJlY2VpcHQgb2YgVHJlYXRtZW50IGZvciBEZXByZXNzaW9uIGluIFBhc3QgWWVhciBhbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTcgd2l0aCBNYWpvciBEZXByZXNzaXZlIEVwaXNvZGUgaW4gUGFzdCBZZWFyLCBieSBEZW1vZ3JhcGhpYyBDaGFyYWN0ZXJpc3RpY3M6IE51bWJlcnMgaW4gVGhvdXNhbmRzLCAyMDA0LTIwMTgNClRhYmxlIDExLjRCICAgICAgIHwgUmVjZWlwdCBvZiBUcmVhdG1lbnQgZm9yIERlcHJlc3Npb24gaW4gUGFzdCBZZWFyIGFtb25nIFBlcnNvbnMgQWdlZCAxMiB0byAxNyB3aXRoIE1ham9yIERlcHJlc3NpdmUgRXBpc29kZSBpbiBQYXN0IFllYXIsIGJ5IERlbW9ncmFwaGljIENoYXJhY3RlcmlzdGljczogUGVyY2VudGFnZXMsIDIwMDQtMjAxOA0KDQpPdXIgZ29hbCBpcyB0byBicmluZyB0aGVzZSBkYXRhIGludG8gUiBzbyB3ZSBjYW4gZXhwbG9yZSB0aGVtLiANCg0KKioqDQo8ZGV0YWlscz4gPHN1bW1hcnk+Q2xpY2sgaGVyZSBmb3IgdGhlIE5TRFVIIGRlZmluZXMgYSBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGUgKE1ERSkgPC9zdW1tYXJ5PiAgDQoNCkFjY29yZGluZyB0byB0aGUgW05TRFVIIDIwMTggcmVwb3J0XShodHRwczovL3d3dy5zYW1oc2EuZ292L2RhdGEvc2l0ZXMvZGVmYXVsdC9maWxlcy9jYmhzcS1yZXBvcnRzL05TRFVITmF0aW9uYWxGaW5kaW5nc1JlcG9ydDIwMTgvTlNEVUhOYXRpb25hbEZpbmRpbmdzUmVwb3J0MjAxOC5wZGYpe3RhcmdldD0iX2JsYW5rIn0NCg0KPiBSZXNwb25kZW50cyB3ZXJlIGRlZmluZWQgYXMgaGF2aW5nIGhhZCBhbiBNREUgaW4NCnRoZSBwYXN0IDEyIG1vbnRocyBpZiB0aGV5IGhhZCBhdCBsZWFzdCBvbmUgcGVyaW9kIG9mIDIgd2Vla3MNCm9yIGxvbmdlciBpbiB0aGUgcGFzdCB5ZWFyIHdoZW4gdGhleSBleHBlcmllbmNlZCBhIGRlcHJlc3NlZA0KbW9vZCBvciBsb3NzIG9mIGludGVyZXN0IG9yIHBsZWFzdXJlIGluIGRhaWx5IGFjdGl2aXRpZXMsDQphY2NvbXBhbmllZCBieSBwcm9ibGVtcyB3aXRoIHNsZWVwaW5nLCBlYXRpbmcsIGVuZXJneSwNCmNvbmNlbnRyYXRpb24sIG9yIHNlbGYtd29ydGguIFRoZSBNREUgcXVlc3Rpb25zIGFyZSBiYXNlZA0Kb24gZGlhZ25vc3RpYyBjcml0ZXJpYSBmcm9tIERTTS01LiBTb21lIG9mIHRoZSB3b3JkaW5ncw0Kb2YgdGhlIGRlcHJlc3Npb24gcXVlc3Rpb25zIGZvciBhZG9sZXNjZW50cyBhZ2VkIDEyIHRvIDE3DQphbmQgYWR1bHRzIGFnZWQgMTggb3Igb2xkZXIgZGlmZmVyZWQgc2xpZ2h0bHkgdG8gbWFrZSB0aGUNCnF1ZXN0aW9ucyBtb3JlIGRldmVsb3BtZW50YWxseSBhcHByb3ByaWF0ZSBmb3IgYWRvbGVzY2VudHMuDQoNCj4gQWRvbGVzY2VudHMgd2VyZSBkZWZpbmVkIGFzIGhhdmluZyBhbiBNREUgd2l0aA0Kc2V2ZXJlIGltcGFpcm1lbnQgaWYgdGhlaXIgZGVwcmVzc2lvbiBjYXVzZWQgc2V2ZXJlIHByb2JsZW1zDQp3aXRoIHRoZWlyIGFiaWxpdHkgdG8gZG8gY2hvcmVzIGF0IGhvbWUsIGRvIHdlbGwgYXQgd29yayBvcg0Kc2Nob29sLCBnZXQgYWxvbmcgd2l0aCB0aGVpciBmYW1pbHksIG9yIGhhdmUgYSBzb2NpYWwgbGlmZS4NCg0KPC9kZXRhaWxzPg0KKioqIA0KDQoNCiMjICoqRGF0YSBJbXBvcnQqKg0KKioqIA0KDQpEYXRhIGFyZSBvZnRlbiBtYWRlIGF2YWlsYWJsZSBvbmxpbmUuIFNvbWV0aW1lcywgdGhlIGRhdGEgd2UgYXJlIGludGVyZXN0ZWQgaW4gaXMgbWFkZSBhdmFpbGFibGUgZm9yIGRvd25sb2FkIG9uIGEgd2ViIHBhZ2UgYXMgYSBkZWxpbWl0ZWQgdGV4dCBmaWxlIG9yIGFuIGV4Y2VsIGZpbGUuIEhvd2V2ZXIsIHNvbWV0aW1lcyBkYXRhIGFyZSBub3QgbWFkZSBhdmFpbGFibGUgaW4gdGhpcyBtYW5uZXIsIHN1Y2ggYXMgdGhlIFtOU0RVSCBzdXJ2ZXkgZGF0YV0oaHR0cHM6Ly93d3cuc2FtaHNhLmdvdi9kYXRhL3NpdGVzL2RlZmF1bHQvZmlsZXMvY2Joc3EtcmVwb3J0cy9OU0RVSERldGFpbGVkVGFiczIwMThSMi9OU0RVSERldFRhYnNTZWN0MTFwZTIwMTguaHRtKXt0YXJnZXQ9Il9ibGFuayJ9Lg0KDQpIb3cgZG8gd2UgcHJvY2VlZCBpbiB0aGlzIHNjZW5hcmlvPw0KDQpXZSBjYW4gbWFudWFsbHkgY29weSBlYWNoIGNlbGwgb2YgZGF0YTsgaG93ZXZlciwgdGhpcyBwcm9jZXNzIGlzIG9mdGVuIGluZWZmaWNpZW50LCBzdWJqZWN0IHRvIGVycm9yLCBhbmQgbm90IHJlcHJvZHVjaWJsZS4gU2F5IHdlIHdhbnRlZCB0byBydW4gYW4gYW5hbHlzaXMgbmV4dCB5ZWFyIG9uIHRoZSBuZXh0IHllYXJzIGRhdGEgYW5kIGl0IGhhcHBlbnMgdG8gYmUgZm9ybWF0dGVkIGluIHRoZSBzYW1lIHdheS4gDQoNCkFsdGVybmF0aXZlbHksIHdlIGNvdWxkIHVzZSBgUmAgdG8gc2NyYXBlIHRoZSBkYXRhIGZyb20gdGhlIHdlYiEgDQoNCkZvcm1hbGx5LCBbd2ViIHNjcmFwaW5nXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XZWJfc2NyYXBpbmc/b2xkZm9ybWF0PXRydWUpe3RhcmdldD0iX2JsYW5rIn0gaXMgdGhlIHByb2Nlc3Mgb2YgZXh0cmFjdGluZyBkYXRhIGZyb20gYSB3ZWJwYWdlLiBMZXQncyBsZWFybiBob3cgdG8gZG8gdGhpcyBmb3Igb3VyIGNhc2Ugc3R1ZHkuDQoNCg0KIyMjICoqQmFzaWMgc3RlcHMgb2Ygd2ViIHNjcmFwaW5nKioNCioqKg0KDQpUaGVyZSBhcmUgdHdvIG1haW4gc3RlcHMgdG8gd2ViIHNjcmFwaW5nOiAgDQoNCjEuIElkZW50aWZ5ICoqbG9jYXRpb24qKiBvZiBkYXRhIG9uIHRoZSB3ZWJwYWdlIHRoYXQgd2lsbCBiZSBzY3JhcGVkLg0KDQoyLiBTYXZlIHRoZSB3ZWJwYWdlICoqZWxlbWVudCoqIHRvIGFuIFIgKipvYmplY3QqKi4NCg0KV2UgYWNjb21wbGlzaCBTVEVQIDEgd2l0aCBvdXIgd2ViIGJyb3dzZXIuDQoNCldlIGFjY29tcGxpc2ggU1RFUCAyIGluIHRoZSBgUmAgcHJvZ3JhbW1pbmcgZW52aXJvbm1lbnQuIA0KDQpUaGUgKipsb2NhdGlvbioqIG9mIHRoZSBkYXRhIG9uIHRoZSB3ZWJwYWdlIHRoYXQgd2lsbCBiZSBzY3JhcGVkIGNhbiBiZSBpZGVudGlmaWVkIHVzaW5nIGEgbGFuZ3VhZ2UgY2FsbGVkIFtYUGF0aF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvWFBhdGgpLCB3aGljaCBpcyBzaG9ydCBmb3IgWE1MIFBhdGggTGFuZ3VhZ2UuIEl0IGlzIHVzZWQgdG8gaWRlbnRpZnkgcGllY2VzIChpbiB0aGlzIGNhc2UgY2FsbGVkICoqbm9kZXMqKikgb2YgYSBkb2N1bWVudCB3cml0dGVuIGluIHRoZSBbWE1MXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9YTUwpIGxhbmd1YWdlLiAgW1hNTF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvWE1MKSB3aGljaCBpcyBzaG9ydCBmb3IgRXh0ZW5zaWJsZSBNYXJrdXAgTGFuZ3VhZ2UgaXMgZnJlcXVlbnRseSB1c2VkIGZvciBkb2N1bWVudHMgb24gdGhlIGludGVybmV0LCBzaW1pbGFyIHRvIFtIVE1MXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9IVE1MKS4gT25lIG9mIHRoZSBbbWFqb3IgZGlmZmVyZW5jZXNdKGh0dHBzOi8vdGVjaGRpZmZlcmVuY2VzLmNvbS9kaWZmZXJlbmNlLWJldHdlZW4teG1sLWFuZC1odG1sLmh0bWwpIGJldHdlZW4gdGhlc2UgdHdvIGlzIHRoYXQgSFRNTCBkb2VzIG5vdCBwcm92aWRlIHN0cnVjdHVyYWwgaW5mb3JtYXRpb24sIHdoaWxlIFhNTCBkb2VzLiBUaGlzIHN0cnVjdHVyYWwgaW5mb3JtYXRpb24gY2FuIGJlIHVzZWQgdG8gcGFyc2UgZG9jdW1lbnRzIHNvIHRoYXQgd2UgY2FuIHNjcmFwZSBvbmx5IHRoZSBkYXRhIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gZnJvbSBhIHdlYnNpdGUuIA0KDQojIyMjIHsucmVzb3VyY2VfYmxvY2t9IA0KDQo8dT5BZGRpdGlvbmFsIHJlc291cmNlcyBmb3Igd2ViIHNjcmFwaW5nPC91PjoNCg0KLSBbVmlnbmV0dGVdKGh0dHBzOi8vcnN0dWRpby1wdWJzLXN0YXRpYy5zMy5hbWF6b25hd3MuY29tLzI2NjQzMF9mM2ZkNDY2MGIyNzQ0NzUxYWIxNDRhYTEzMDc2OGEwNi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9DQotIFtCbG9nXShodHRwOi8vYmxvZy5jb3J5bmlzc2VuLmNvbS8yMDE1LzAxL3VzaW5nLXJ2ZXN0LXRvLXNjcmFwZS1odG1sLXRhYmxlLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0NCi0gW0Jsb2ddKGh0dHA6Ly9yZXNlYXJjaC5saWJkLm9yZy9yc3RhdHNjbHViL3Bvc3QvaW50cm9kdWN0aW9uLXRvLXNjcmFwaW5nLWFuZC13cmFuZ2luZy10YWJsZXMtZnJvbS1yZXNlYXJjaC1hcnRpY2xlcy8jLlh3ODc4Wk5LaFFKKXt0YXJnZXQ9Il9ibGFuayJ9DQotIFtTZWxlY3RvcmdhZGdldCBUb29sXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcnZlc3QvdmlnbmV0dGVzL3NlbGVjdG9yZ2FkZ2V0Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0NCg0KIyMjIw0KDQojIyMgKipUaGUgYHJ2ZXN0YCBwYWNrYWdlKioNCioqKg0KDQpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgc2NyYXBlIGRhdGEgZnJvbSB0aGUgdGFibGVzIG9uIHRoZSBbTlNEVUggc3VydmV5XShodHRwczovL3d3dy5zYW1oc2EuZ292L2RhdGEvc2l0ZXMvZGVmYXVsdC9maWxlcy9jYmhzcS1yZXBvcnRzL05TRFVIRGV0YWlsZWRUYWJzMjAxOFIyL05TRFVIRGV0VGFic1NlY3QxMXBlMjAxOC5odG0pe3RhcmdldD0iX2JsYW5rIn0gd2Vic2l0ZS4gDQoNCk5vdGUgdGhhdCB0aGVzZSBkYXRhIGFyZSBhdmFpbGFibGUgaW4gYSBsYXJnZSBQREYgd2l0aCBhbGwgdGhlIHJlc3VsdHMgYnkgeWVhciBpZiB5b3Ugd2lzaCB0byB1c2UgdGhlIGRhdGEgZnJvbSB0aGlzIHBhcnRpY3VsYXIgc291cmNlLg0KDQpPbmUgb3B0aW9uIHRvIGltcG9ydCB0aGUgZGF0YSB3b3VsZCBiZSB0byBpbXBvcnQgdGhlIFBERi4gSG93ZXZlciBpdCBpcyBub3QgZWFzeSB0byBmaW5kIHRoaXMgUERGIGFuZCBpdCB3b3VsZCBiZSBkaWZmaWN1bHQgYW5kIHRpbWUgY29uc3VtaW5nIHRvIGZpbmQgb3VyIHRhYmxlcyBvZiBpbnRlcmVzdCBhbmQgdG8gZXh0cmFjdCBvdXIgZGF0YSBvZiBpbnRlcmVzdCBmcm9tIHRoZSBwZGYuIEhvd2V2ZXIsIGlmIG9uZSB3YW50ZWQgdG8gZG8gdGhpcywgc2F5IGlmIHRoZSB0YWJsZXMgd2VyZSBub3QgYXZhaWxhYmxlIG9ubGluZSwgdGhleSBjb3VsZCB1c2UgdGhlIGBwZGZ0b29sc2AgcGFja2FnZS4gU2VlIHRoaXMgb3RoZXIgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vd3d3Lm9wZW5jYXNlc3R1ZGllcy5vcmcvb2NzLWJwLWRpZXQvKSBhbmQgdGhpcyBvdGhlciBbY2FzZSBzdHVkeV0oaHR0cHM6Ly93d3cub3BlbmNhc2VzdHVkaWVzLm9yZy9vY3MtYnAteW91dGgtZGlzY29ubmVjdGlvbi8pIGZvciB0d28gbWV0aG9kcyB0byB3b3JrIHdpdGggUERGcy4gDQoNCkFub3RoZXIgb3B0aW9uIGNvdWxkIGJlIHRvIGNvcHkgYW5kIHBhc3RlIHRoZSBkYXRhIGZyb20gdGhlIHdlYnNpdGUgdG8gYW5vdGhlciBmaWxlIHRoYXQgd2Ugd291bGQgYWxzbyBuZWVkIHRvIGltcG9ydC4gQnV0IHRoaXMgd291bGQgbm90IGJlIGFzIGVmZmljaWVudCBvciByZXByb2R1Y2libGUgYW5kIG1pZ2h0IHJlc3VsdCBpbiBlcnJvcnMuIA0KDQpBbHRlcm5hdGl2ZWx5LCB3ZSB3aWxsIHVzZSB0aGUgYHJ2ZXN0YCBwYWNrYWdlIHRvIFtzY3JhcGVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1dlYl9zY3JhcGluZz9vbGRmb3JtYXQ9dHJ1ZSl7dGFyZ2V0PSJfYmxhbmsifSB0aGUgZGF0YSBkaXJlY3RseSBmcm9tIHRoZSB0YWJsZXMgb24gdGhlIHdlYnNpdGUuIA0KDQpBc3N1bWluZyB0aGUgZGF0YSBuZXh0IHllYXIgd291bGQgYmUgZGlzcGxheWVkIGluIGEgc2ltaWxhciBtYW5uZXIsIHRoaXMgY291bGQgYWxsb3cgdXMgdG8gc2ltcGx5IG1vZGlmeSBvdXIgY29kZSBiYXNlZCBvbiB0aGUgdXJsIGZvciB0aGUgZGF0YSBuZXh0IHllYXIgdG8gcnVuIHRoZSBzYW1lIGFuYWx5c2lzIG9uIHRoZSBkYXRhIGVhc2lseS4gDQoNCkhvd2V2ZXIsIGl0IGlzIGltcG9ydGFudCB0byBrZWVwIGluIG1pbmQgdGhhdCBvbmUgZG93bnNpZGUgb2Ygc2NyYXBpbmcgdGhlIGRhdGEgZGlyZWN0bHkgZnJvbSB0aGUgd2ViLCBpcyB0aGF0IHRoZSB3ZWJzaXRlIGNvdWxkIGNoYW5nZSAtIHRoaXMgY2FuIGJlIGEgZ29vZCB0aGluZyBpZiB0aGUgd2Vic2l0ZSBhZGRzIGFkZGl0aW9uYWwgZGF0YSBhbmQga2VlcHMgdGhlIHNhbWUgZm9ybWF0dGluZy4gVGhpcyB3b3VsZCBhbGxvdyB1cyB0byBnZXQgYWRkaXRpb25hbCBkYXRhIHZlcnkgZWFzaWx5LiBIb3dldmVyLCBpZiB0aGUgd2Vic2l0ZSBjaGFuZ2VzIGZvcm1hdHRpbmcgdGhlbiB0aGlzIHdvdWxkIHJlcXVpcmUgdGhhdCB3ZSB1cGRhdGUgb3VyIGNvZGUuIA0KDQojIyMgKipTY3JhcGluZyB0YWJsZXMgaW50byBSKioNCioqKg0KDQpUaGUgdHdvIHdlYiBzY3JhcGluZyBzdGVwcyBmb3IgdGhlc2UgdGFibGVzIGNhbiBiZSBicm9rZW4gZG93biBldmVuIGZ1cnRoZXI6IA0KDQoxLiBJZGVudGlmeSBsb2NhdGlvbiBvZiBkYXRhIHRoYXQgd2lsbCBiZSBzY3JhcGVkDQoNCiAgICArIHJpZ2h0LWNsaWNrIHRvIGluc3BlY3QgZWxlbWVudCAod2VicGFnZSkNCiAgICArIGhvdmVyIHBvaW50ZXIgb3ZlciBjb21wb25lbnRzIG9mIGVsZW1lbnQgKHdlYnBhZ2UpIHVudGlsIHRoZSBkYXRhIGhhcyBiZWVuIGZvdW5kDQogICAgKyBjb3B5IFhQYXRoIG9mIGRhdGEgc291Z2h0DQoNCjIuIFNhdmUgd2VicGFnZSBlbGVtZW50IHRvIGFuIG9iamVjdCBpbiBSDQoNCiAgICArIGltcG9ydCBodG1sIGNvZGUgZm9yIHRoZSB3ZWJwYWdlDQogICAgKyBleHRyYWN0IHBpZWNlcyBvZiBIVE1MIGRvY3VtZW50cyAod2VicGFnZSkgdXNpbmcgWFBhdGgNCiAgICArIHBhcnNlIHRoZSBleHRyYWN0ZWQgZGF0YSBpbnRvIGEgZGF0YSBmcmFtZQ0KDQpCZWxvdyBpcyBhIGFuaW1hdGVkIG92ZXJ2aWV3IG9mIHRoZSBwcm9jZXNzLg0KDQo8ZGV0YWlscz48c3VtbWFyeT4gQ2xpY2sgaGVyZSBpZiB5b3Ugd2FudCB0byBzZWUgaG93IHRoaXMgYW5pbWF0aW9uIHdhcyBtYWRlITwvc3VtbWFyeT4NCg0KRmlyc3QgdGhlIGltYWdlcyBuZWVkIHRvIGJlIGltcG9ydGVkIGludG8gUiB1c2luZyB0aGUgYGltYWdlX3JlYWRgIGZ1bmN0aW9uIG9mIHRoZSBgbWFnaWNrYCBwYWNrYWdlLg0KDQpgYGB7cn0NCnN0ZXAxIDwtIG1hZ2ljazo6aW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAid2VicGFnZV9zY3JlZW5zaG90LnBuZyIpKQ0Kc3RlcDIgPC0gaW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAidGFibGVfc2NyZWVuc2hvdF9pbnNwZWN0LnBuZyIpKQ0Kc3RlcDMgPC0gaW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAidGFibGVfc2NyZWVuc2hvdF9pbnNwZWN0X3RhYmxlLnBuZyIpKQ0Kc3RlcDQgPC0gaW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAidGFibGVfc2NyZWVuc2hvdF9pbnNwZWN0X3RhYmxlX3hwYXRoLnBuZyIpKQ0Kc3RlcDUgPC0gaW1hZ2VfcmVhZChoZXJlOjpoZXJlKCJpbWciLCAidGFibGVfc2NyZWVuc2hvdF94cGF0aF9jb3B5X3IucG5nIikpDQpzdGVwNV96b29tIDwtIGltYWdlX3JlYWQoaGVyZTo6aGVyZSgiaW1nIiwgInRhYmxlX3NjcmVlbnNob3RfeHBhdGhfY29weV9yX3pvb20ucG5nIikpDQpgYGANCg0KVGhlIGxhc3QgaW1hZ2UgaXMgc21hbGxlciB0aGFuIHRoZSBvdGhlcnMsIHRvIGdldCBhIHNlbnNlIG9mIHRoZSBzaXplIHdlIGNhbiB1c2UgdGhlIGBpbWFnZV9pbmZvKClgIGZ1bmN0aW9uIG9mIHRoZSBgbWFnaWNrYCBwYWNrYWdlLg0KDQpgYGB7cn0NCnN0ZXA1DQpzdGVwNV96b29tDQppbWFnZV9pbmZvKHN0ZXA1KQ0KaW1hZ2VfaW5mbyhzdGVwNV96b29tKQ0KYGBgDQoNCkZpcnN0IGxldCdzIHJlLXNpemUgdGhlIHNlY29uZCBpbWFnZSB0byBtYWtlIGl0IGEgYml0IGxhcmdlciB1c2luZyB0aGUgYGltYWdlX3Jlc2l6ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYG1hZ2lja2AgcGFja2FnZS4gV2Ugd2lsbCByZS1zaXplIHRoZSB3aWR0aCB0byBiZSB0aGUgc2FtZSBhcyB0aGUgcHJldmlvdXMgaW1hZ2Ugd2lkdGggYW5kIGtlZXAgdGhlIGFzcGVjdCByYXRpbyBmb3IgdGhlIGhlaWdodCBieSB1c2luZyAiMTQ0MHgiLiBJZiB3ZSB3YW50ZWQgdG8ganVzdCBkbyB0aGUgc2FtZSBmb3IgaGVpZ2h0IHdlIHdvdWxkIHVzZSAieDkwMCIuDQoNCmBgYHtyfQ0Kc3RlcDVfem9vbSA8LSBpbWFnZV9yZXNpemUoc3RlcDVfem9vbSwgICIxNDQweCIpDQpzdGVwNV96b29tDQpgYGANCg0KV2UgY2FuIGFkZCBhIHdoaXRlIGJvYXJkZXIgYXJvdW5kIHRoZSBsYXN0IGltYWdlIHRvIG1ha2UgdGhlIHNpemUgbW9yZSBzaW1pbGFyIGhlaWdodC13aXNlIHVzaW5nIHRoZSBgaW1hZ2VfYm9yZGVyKClgIGZ1bmN0aW9uIG9mIHRoZSBgbWFnaWNrYCBwYWNrYWdlLiBUaGVyZSBhcmUgbWFueSBpbWFnZSBtb2RpZmljYXRpb24gZnVuY3Rpb25zIGluIHRoZSBgbWFnaWNrYCBwYWNrYWdlISBTZWUgW2hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdpY2svdmlnbmV0dGVzL2ludHJvLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gdG8gbGVhcm4gbW9yZS4NCg0KYGBge3J9DQpzdGVwNV96b29tIDwtIGltYWdlX2JvcmRlcihzdGVwNV96b29tLCAid2hpdGUiLCAiMngzMzQiKQ0Kc3RlcDVfem9vbQ0KYGBgDQoNCkxvb2tzIGdvb2QhDQoNCk5vdyB3ZSB3aWxsIG1ha2UgdGhlIHNlcXVlbmNlIG9mIGltYWdlcyBmb3Igb3VyIGFuaW1hdGlvbi4gV2UgYWxzbyB3YW50IHRvIGluZGljYXRlIGhvdyBsb25nIHdlIHdhbnQgdG8gc3BlbmQgb24gZWFjaCByZWxhdGl2ZSB0byB0aGUgb3RoZXJzLiBXZSB3YW50IHRvIGxpbmdlciBvbiB0aGUgbGFzdCBpbWFnZSBzbyB3ZSBpbmNsdWRlIGl0IHR3byB0aW1lcy4NCg0KYGBge3J9DQppbWcgPC0gYyhzdGVwMSwNCiAgICAgICAgIHN0ZXAyLA0KICAgICAgICAgc3RlcDMsDQogICAgICAgICBzdGVwNCwNCiAgICAgICAgIHN0ZXA1LA0KICAgICAgICAgc3RlcDVfem9vbSwNCiAgICAgICAgIHN0ZXA1X3pvb20pDQpgYGANCg0KDQpOb3csIHdlIGFyZSByZWFkeSB0byBjcmVhdGUgb3VyIGdpZiEgQnV0IGZpcnN0IHdlIHdhbnQgdG8gbW9kaWZ5IG91ciBpbWFnZXMgYSBiaXQgbW9yZS4NCg0KRmlyc3Qgd2Ugd2FudCB0byBtYWtlIGFsbCBpbWFnZXMgd2l0aGluIGBpbWdgIHRoZSBleGFjdCBzYW1lIHNpemUgdXNpbmcgdGhlIGBpbWFnZV9yZXNpemUoKWAgZnVuY3Rpb24uIFRvIGRvIHRoaXMgZm9yIGFsbCBpbWFnZXMgd2UgY2FuIHVzZSB0aGUgYCFgIGF0IHRoZSBlbmQsIHdoaWNoIGlnbm9yaW5nIGFzcGVjdCByYXRpb3MuDQoNCmBgYHtyfQ0KaW1hZ2VfaW5mbyhpbWcpDQppbWcgPC1pbWFnZV9yZXNpemUoaW1nLCAnMTQ0MHg5MDAhJykNCmltYWdlX2luZm8oaW1nKQ0KYGBgDQoNCldlIGFsc28gd2FudCB0byBtb3JwaCBvciBibGVuZCBlYWNoIGltYWdlIGludG8gdGhlIG5leHQgc28gdGhhdCB0aGVyZSBhcHBlYXJzIHRvIGJlIGEgc21vb3RoIHRyYW5zaXRpb24uIFdlIGNhbiBhbHNvIHNwZWNpZnkgaG93IG1hbnkgZnJhbWVzIHRvIGluY2x1ZGUgaW4gdGhlIG1vcnBoLCB0byBzcGVlZCB1cCBvciBzbG93IGRvd24gdGhlIGJsZW5kIGZyb20gb25lIGltYWdlIHRvIGFub3RoZXIuIFdlIHdpbGwgc3BlY2lmeSB0aGF0IDQgZnJhbWVzIHNob3VsZCBiZSB1c2VkIGluIHRoZSBtb3JwaCBieSB1c2luZyB0aGUgYGltYWdlX21vcnBoKClgIGZ1bmN0aW9uLiANCg0KVG8gbWFrZSB0aGUgZmluYWwgYW5pbWF0aW9uIHdlIHVzZSB0aGUgYGltYWdlX2FuaW1hdGUoKWAgZnVuY3Rpb24NCkltcG9ydGFudGx5LCB3ZSB3YW50IHRvIGRlbGF5IGNoYW5naW5nIGZyb20gb25lIGltYWdlIHRvIGFub3RoZXIgYWJvdXQgNzAqIDEvMTAwIHNlY29uZHMgdG8gZ2l2ZSBwZW9wbGUgYSBjaGFuY2UgdG8gc2VlIHdoYXQgaXMgaGFwcGVuaW5nLiBTbyB3ZSBjYW4gdXNlIHRoZSBgZGVsYXlgIGFyZ3VtZW50LiBUaGUgb3B0aW1pemUgYXJndW1lbnQgb2YgdGhpcyBmdW5jdGlvbiByZXF1aXJlcyB0aGF0IGFsbCBpbWFnZXMgYXJlIHRoZSBzYW1lIHNpemUgKGx1Y2tpbHkgd2UgZGlkIHRoaXMhKSBhbmQgaXQgY2F1c2VzIFIgdG8gb25seSBzdG9yZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBmcmFtZXMuDQoNCmBgYHtyfQ0KZWR1Y2F0aW9uYWxfZ2lmIDwtIA0KICBpbWFnZV9tb3JwaChpbWcsIGZyYW1lcyA9IDQpICU+JQ0KICBpbWFnZV9hbmltYXRlKGRlbGF5ID0gNzAsDQogICAgICAgICAgICAgICAgb3B0aW1pemUgPSBUUlVFKQ0KYGBgDQoNCk5vdyB0byBzYXZlIG91ciBnaWYgd2UgY2FuIHVzZSB0aGUgYGltYWdlX3dyaXRlKClgIGZ1bmN0aW9uIG9mIHRoZSBgbWFnaWNrYCBwYWNrYWdlIGFuZCB0aGUgYGhlcmUoKWAgZnVuY3Rpb24gb2YgdGhlIGBoZXJlYCBwYWNrYWdlIHRvIGVhc2lseSBzYXZlIGl0IGluIGEgZGlyZWN0b3J5IGNhbGxlZCBgaW1nYCB3aXRoaW4gdGhlIGRpcmVjdG9yeSB0aGF0IGNvbnRhaW5zIG91ciAuUnByb2ogZmlsZS4gV2Ugd2lsbCBuYW1lIHRoZSBmaWxlIGVkdWNhdGlvbmFsLmdpZi4NCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCmltYWdlX3dyaXRlKGVkdWNhdGlvbmFsX2dpZiwNCiAgICAgIGhlcmU6OmhlcmUoImltZyIsICJlZHVjYXRpb25hbC5naWYiKSkNCmBgYA0KDQoNCjwvZGV0YWlscz4NCg0KDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJlZHVjYXRpb25hbC5naWYiKSkNCmBgYA0KDQoNCioqKg0KDQpOb3cgbGV0J3MgZ28gdGhyb3VnaCBlYWNoIHN0ZXAgdG9nZXRoZXI6DQoNCiMjIyMgMSkgSWRlbnRpZnkgbG9jYXRpb24gb2YgZGF0YSB0aGF0IHdpbGwgYmUgc2NyYXBlZA0KDQpGaXJzdCwgbGV0J3MgZ28gdG8gdGhlIFt3ZWIgcGFnZV0oaHR0cHM6Ly93d3cuc2FtaHNhLmdvdi9kYXRhL3NpdGVzL2RlZmF1bHQvZmlsZXMvY2Joc3EtcmVwb3J0cy9OU0RVSERldGFpbGVkVGFiczIwMThSMi9OU0RVSERldFRhYnNTZWN0MTFwZTIwMTguaHRtKXt0YXJnZXQ9Il9ibGFuayJ9IHdpdGggYWxsIHRoZSB0YWJsZXMgd2UgYXJlIGludGVyZXN0ZWQgaW4gc2NyYXBpbmcNCg0KYGBge3IsIHN0ZXAxLCBlY2hvPUZBTFNFfQ0Kc3RlcDENCmBgYA0KDQpPbmNlIG9uIHRoZSB3ZWJwYWdlLCB0aGVyZSBhcmUgbm90IGFueSB2aXNpYmxlIG9wdGlvbnMgdG8gZG93bmxvYWQgdGhlIGRhdGEuIA0KDQpSaWdodC1jbGljayBhbmQgc2VsZWN0ICJJbnNwZWN0Ii4NCg0KYGBge3IsIHN0ZXAyLCBlY2hvPUZBTFNFfQ0Kc3RlcDINCmBgYA0KDQpBIHdpbmRvdyBvcGVucy4gDQoNClRoaXMgd2luZG93IGFsbG93cyB1cyB0byBnbGFuY2UgYXQgdGhlIGludGVybmFsIG1lY2hhbmljcyBvZiB0aGUgd2VicGFnZS4gVG8gc2NyYXBlIHRoZSBkYXRhIGZyb20gdGhlIHdlYnBhZ2UsIHdlIG5lZWQgdG8gZmlyc3QgbGVhcm4gYSBsaXR0bGUgYml0IGFib3V0IHRoZSBjb21wb25lbnRzIHRoYXQgbWFrZSBpdCB0aGUgd2ViIHBhZ2UgaXQgaXMuIA0KDQpIb3ZlcmluZyBvdXIgbW91c2Ugb3ZlciB0aGUgZWxlbWVudHMgb2YgdGhlIHdlYnBhZ2UgaGlnaGxpZ2h0cyB0aGUgcmVzcGVjdGl2ZSBzZWN0aW9uIG9mIHRoZSB3ZWJwYWdlIGl0IHJlcHJlc2VudHMuDQpCeSBob3ZlcmluZyBvdmVyIHNldmVyYWwgZWxlbWVudHPigJRhbmQgY2xpY2tpbmcgb24gdGhlIGVsZW1lbnRzIG9uIHRoZSByaWdodCBzaWRlIG9mIHRoZSBzY3JlZW7igJR3ZSBjYW4gaWRlbnRpZnkgdGhlIGVsZW1lbnQgdGhhdCBjb250YWlucyB0aGUgZGF0YSB3ZSBhcmUgbG9va2luZyBmb3IuIA0KQW5vdGhlciBvcHRpb24gZm9yIGlkZW50aWZ5aW5nIFhQYXRocyBpcyB0byB1c2UgdGhlIFtzZWxlY3RvcmdhZGdldCB0b29sXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcnZlc3QvdmlnbmV0dGVzL3NlbGVjdG9yZ2FkZ2V0Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uICANCg0KYGBge3Isc3RlcDMsIGVjaG89RkFMU0V9DQpzdGVwMyANCmBgYA0KDQpSaWdodCBjbGljayBvbiB0aGUgZWxlbWVudCBhbmQgY29weSB0aGUgWFBhdGguIFdlIHdpbGwgbmVlZCB0aGlzIFhQYXRoIGZvciB0aGUgbmV4dCBzdGVwLg0KDQpgYGB7ciwgc3RlcDQsIGVjaG89RkFMU0V9DQpzdGVwNA0KYGBgDQoNCk5vdyB3ZSBjYW4gcmV0dXJuIHRvIHRoZSBgUmAgcHJvZ3JhbW1pbmcgZW52aXJvbm1lbnQuDQoNCmBgYHtyLCBzdGVwNSwgZWNobz1GQUxTRX0NCnN0ZXA1DQpgYGANCg0KKioqDQoNCiMjIyMgMikgU2F2ZSB3ZWJwYWdlIGVsZW1lbnQgdG8gYW4gb2JqZWN0IGluIFIgDQoNCkZvciB0aGUgZmlyc3QgdGFibGUgd2Ugd2FudCB0byBzY3JhcGUsIHRoZSBYUGF0aCBpcyBgL2h0bWwvYm9keS9kaXZbNF0vZGl2WzFdL3RhYmxlYC4gV2UgdXNlIHRoaXMgWFBhdGggd2l0aCBmdW5jdGlvbnMgZnJvbSB0aGUgYHJ2ZXN0YCBwYWNrYWdlIHRvIHNjcmFwZSB0aGUgZGF0YSBmcm9tIHRoaXMgdGFibGUuDQoNCg0KYGBge3Isc3RlcDVfem9vbSwgZWNobz1GQUxTRX0NCnN0ZXA1X3pvb20NCmBgYA0KDQoNCkxldCdzIGV4cGxvcmUgdGhpcyBzdGVwIGluIGdyZWF0ZXIgZGV0YWlsOg0KDQpXZSBuZWVkIHRvOg0KDQorIGltcG9ydCBodG1sIGNvZGUgZm9yIHRoZSB3ZWJwYWdlDQorIGV4dHJhY3QgcGllY2VzICh0YWJsZSkgb3V0IG9mIEhUTUwgZG9jdW1lbnRzICh3ZWJwYWdlKSB1c2luZyBYUGF0aA0KKyBwYXJzZSB0aGUgaHRtbCB0YWJsZSBpbnRvIGEgZGF0YSBmcmFtZQ0KDQpUbyBkbyB0aGlzOg0KDQorIFdlIGltcG9ydCB0aGUgaHRtbCBjb2RlIHVzaW5nIHRoZSBgcmVhZF9odG1sKClgIGZ1bmN0aW9uIG9mIHRoZSBgcnZlc3RgIHBhY2thZ2UNCisgV2UgZXh0cmFjdCBzcGVjaWZpYyBjb21wb25lbnRzIG9mIHRoZSB3ZWJwYWdlIHVzaW5nIHRoZSBgaHRtbF9ub2RlcygpYCBmdW5jdGlvbiBvZiB0aGUgYHJ2ZXN0YCBwYWNrYWdlDQorIFdlIGNvbnZlcnQgdGhpcyBodG1sIHRhYmxlIGludG8gYSBkYXRhZnJhbWUgdXNpbmcgdGhlIGBodG1sX3RhYmxlKClgZnVuY3Rpb24gb2YgdGhlIGBydmVzdGAgcGFja2FnZQ0KDQoqKlRoZSBgcnZlc3RgIHBhY2thZ2UgcHJvdmlkZXMgd3JhcHBlcnMgZm9yIHRoZSBgeG1sMmAgYW5kIGBodHRyYCBwYWNrYWdlcywgdGh1cyB3ZSBjYW4ganVzdCBpbnN0YWxsIGFuZCBsb2FkIHRoZSBgcnZlc3RgIHBhY2thZ2UgYW5kIGl0IHdpbGwgaW5zdGFsbCBhbmQgbG9hZCBkZXBlbmRlbmN5IHBhY2thZ2VzIGxpa2UgYHhtbDJgIGFuZCBgaHR0cmAgYW5kIGFsbG93IHVzIHRvIHVzZSBmdW5jdGlvbnMgZnJvbSAgYm90aCBvZiB0aGVzZSBwYWNrYWdlcy4qKg0KDQpJbiBmYWN0LCB3aGVuIHdlIGxvYWQgYHJ2ZXN0YCB0aGUgZmlyc3QgdGltZSB3ZSBzZWU6DQoNCmBgYHtyLCBvdXQud2lkdGg9ICI2MCUiLCBlY2hvPUZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInJ2ZXN0LnBuZyIpKQ0KYGBgDQoNCkluIHRoaXMgY2FzZSwgd2UgYXJlIHNjcmFwaW5nIFRhYmxlIDExLjFBIGZyb20gdGhlIHdlYnNpdGUuIA0KRmlyc3QsIHdlIGFzc2lnbiB0aGUgVVJMIHRvIGEgY2hhcmFjdGVyIHN0cmluZyB0byB1c2Ugd2l0aGluIHRoZSBgcmVhZF9odG1sKClgIGZ1bmN0aW9uIGluIHRoZSBgeG1sMmAgcGFja2FnZS4gDQoNCmBgYHtyfQ0KTlNEVUhfdXJsIDwtICJodHRwczovL3d3dy5zYW1oc2EuZ292L2RhdGEvc2l0ZXMvZGVmYXVsdC9maWxlcy9jYmhzcS1yZXBvcnRzL05TRFVIRGV0YWlsZWRUYWJzMjAxOFIyL05TRFVIRGV0VGFic1NlY3QxMXBlMjAxOC5odG0iDQpgYGANCg0KV2UgaGF2ZSBhbHNvIHNhdmVkIHRoZSBkYXRhIGFzIGl0IHdhcyBvbiB0aGlzIHdlYnNpdGUgdG8gb3VyIG93biB3ZWJzaXRlIHRvIGVuc3VyZSB0aGF0IG91ciBjYXNlIHN0dWR5IHdpbGwgcmVtYWluIHN0YWJsZSBkZXNwaXRlIHBvc3NpYmxlIGNoYW5nZXMgdG8gdGhpcyB3ZWJzaXRlLg0KDQpUaHVzIHdlIHdpbGwgcHJvY2VlZCB3aXRoIHRoaXMgVVJMOg0KDQpgYGB7cn0NCk5TRFVIX3VybCA8LSAiaHR0cHM6Ly93d3cub3BlbmNhc2VzdHVkaWVzLm9yZy9vY3MtYnAteW91dGgtbWVudGFsLWhlYWx0aC9kYXRhL3Jhdy9zYW1oc2EuZ292XzIwMjBfdGFibGVzLmh0bSINCmBgYA0KDQpPbmUgY291bGQgYWxzbyBkaXJlY3RseSB1c2UgdGhlIFVSTCBidXQgdGhpcyBpcyBsZXNzIGNvbnZlbmllbnQgZm9yIHBpcGluZy4gIA0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT5DbGljayBoZXJlIGlmIHlvdSBhcmUgdW5mYW1pbGlhciB3aXRoIHBpcGluZyBpbiBSLCB3aGljaCB1c2VzIHRoaXMgYCU+JWAgb3BlcmF0b3I8L3N1bW1hcnk+ICANCg0KDQpCeSBbcGlwaW5nXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gd2UgbWVhbiB1c2luZyB0aGUgYCU+JWAgcGlwZSBvcGVyYXRvciB3aGljaCBpcyBhY2Nlc3NpYmxlIGFmdGVyIGxvYWRpbmcgdGhlIGB0aWR5dmVyc2VgIG9yIHNldmVyYWwgb2YgdGhlIHBhY2thZ2VzIHdpdGhpbiB0aGUgdGlkeXZlcnNlIGxpa2UgYGRwbHlyYCBiZWNhdXNlIHRoZXkgbG9hZCB0aGUgW2BtYWdyaXR0cmAgcGFja2FnZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LiANClRoaXMgYWxsb3dzIHVzIHRvIHBlcmZvcm0gbXVsdGlwbGUgc2VxdWVudGlhbCBzdGVwcyBvbiBvbmUgZGF0YSBpbnB1dC4gDQoNCg0KPC9kZXRhaWxzPiANCg0KDQoqKioNCiAgDQpUaGVuLCB0aGUgYHJlYWRfaHRtbCgpYCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gc2F2ZSB0aGUgaHRtbCBkb2N1bWVudCBmb3IgdGhlIHdlYnBhZ2UgaW5zaWRlIFIuIA0KDQpgYGB7cn0NCndlYnBhZ2UgPC0gTlNEVUhfdXJsICU+JQ0KICB4bWwyOjpyZWFkX2h0bWwoKSANCndlYnBhZ2UNCmBgYA0KDQpUaGVuLCB3ZSB1c2UgdGhlIGBodG1sX25vZGVzKClgIGZ1bmN0aW9uIG9mIHRoZSBgcnZlc3RgIHBhY2thZ2UgdG8gc2VsZWN0IGp1c3QgdGhlIFRhYmxlIDExLjFBIGVsZW1lbnQgb2YgdGhlIHdlYnBhZ2UuDQoNClNlZSB0aGlzIFt0dXRvcmlhbF0oaHR0cDovL2ZsdWtlb3V0LmdpdGh1Yi5pby8jKXt0YXJnZXQ9Il9ibGFuayJ9IChhbmQgdGhlIFthbnN3ZXJzXShodHRwczovL2dpc3QuZ2l0aHViLmNvbS9jaHJpc21hbi9mY2IwYTg4NDU5Y2Q5ODIzOWRiZTZkMmQyMDBiMDJkMSl7dGFyZ2V0PSJfYmxhbmsifSBpbiBjYXNlIHlvdSBnZXQgc3R1Y2spIG9uIENTUyBzZWxlY3RvcnMgdG8gdW5kZXJzdGFuZCBtb3JlIGFib3V0IGhvdyB0aGlzIGZ1bmN0aW9uIHdvcmtzIHRvIHVzZSB0aGUgYHhwYXRoYCB0byBzZWxlY3QgdGhlIGVsZW1lbnRzIG9mIGludGVyZXN0IGZyb20gdGhlIHdlYnBhZ2UuDQoNCmBgYHtyfQ0Kd2VicGFnZV9lbGVtZW50IDwtIHdlYnBhZ2UgJT4lDQogIHJ2ZXN0OjpodG1sX25vZGVzKHhwYXRoPScvaHRtbC9ib2R5L2Rpdls0XS9kaXZbMV0vdGFibGUnKQ0Kd2VicGFnZV9lbGVtZW50IA0KYGBgDQoNCkZpbmFsbHksIHRoZSBgaHRtbF90YWJsZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHJ2ZXN0YCBwYWNrYWdlIHBhcnNlcyB0aGUgaHRtbCBvYmplY3QgaW50byBhIGRhdGEgZnJhbWUuIFdlIGNhbiB1c2UgdGhlIGBnbGltcHNlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gdGFrZSBhIGxvb2sgYXQgdGhlIGRhdGEuIFRoaXMgZnVuY3Rpb24gc2hvd3MgZGF0YSBmcmFtZXMgc2lkZXdheXMgd2l0aCB0aGUgY29sdW1ucyBsaXN0ZWQgb24gdGhlIGZhciBsZWZ0LiANCg0KYGBge3J9DQp0YWJsZTExLjFhIDwtIHdlYnBhZ2VfZWxlbWVudCAlPiUNCiAgcnZlc3Q6Omh0bWxfdGFibGUoKQ0KDQpwcmludCh0YWJsZTExLjFhLCBtYXggPSAyKQ0KZ2xpbXBzZSh0YWJsZTExLjFhKQ0KYGBgDQoNCldlIGNhbiBzZWUgdGhhdCB0aGUgb3V0cHV0IGlzIGEgbGlzdCB3aXRoIG9uZSBlbGVtZW50LCB0byBleHRyYWN0IHRoZSBkYXRhIGZyb20gdGhlIGxpc3Qgd2Ugd2lsbCB1c2UgYnJhY2tldHMgYFtbXV1gIHRvIHNlbGVjdCB0aGUgZmlyc3QgZWxlbWVudCBvZiB0aGUgbGlzdC4NCg0KYGBge3J9DQp0YWJsZTExLjFhIDwtIHRhYmxlMTEuMWFbWzFdXQ0KYGBgDQoNCg0KUHV0dGluZyB0aGlzIGFsbCBvZiB0aGlzIHRvZ2V0aGVyIHdlIGNhbiBkbyB0aGUgZW50aXJlIHByb2Nlc3MgbGlrZSB0aGlzIHdpdGggb3VyIHBpcGUgb3BlcmF0b3IgYCU+JWAuDQoNCmBgYHtyfQ0KdGFibGUxMS4xYSA8LSBOU0RVSF91cmwgJT4lDQogIHhtbDI6OnJlYWRfaHRtbCgpICU+JQ0KICBydmVzdDo6aHRtbF9ub2Rlcyh4cGF0aCA9ICcvaHRtbC9ib2R5L2Rpdls0XS9kaXZbMV0vdGFibGUnKSAlPiUNCiAgcnZlc3Q6Omh0bWxfdGFibGUoKQ0KdGFibGUxMS4xYSA8LSB0YWJsZTExLjFhW1sxXV0NCmBgYA0KDQoNCk5vdywgd2UgbmVlZCB0byByZXBlYXQgdGhlIGFib3ZlIHByb2Nlc3MgZm9yIHRoZSBvdGhlciB0YWJsZXMgd2UgYXJlIGludGVyZXN0ZWQgaW4uIA0KDQojIyMgKipXcml0aW5nIGEgZnVuY3Rpb24gdG8gc2NyYXBlIG11bHRpcGxlIHRhYmxlcyoqDQoqKioNCg0KT25lIG9wdGlvbiBpcyB0byBjb3B5IGFuZCBwYXN0ZSBjb2RlIHdlIHdyb3RlIGFib3ZlLiANCkhvd2V2ZXIsIHRoaXMgaXMgbm90IHZlcnkgZWZmaWNpZW50IGFuZCBpcyBlcnJvciBwcm9uZS4NCkFsdGVybmF0aXZlbHksIHdlIGNhbiBjcmVhdGUgYW4gUiBmdW5jdGlvbiB0byBhY2NvbXBsaXNoIHRoaXMgc3VjY2luY3RseS4gDQpGdW5jdGlvbnMgYWxsb3cgdXMgdG8gcGVyZm9ybSB0aGUgc2FtZSBwcm9jZXNzIG9uIG11bHRpcGxlIGRhdGEgaW5wdXRzLiANClNlZSBbdGhpcyBvdGhlciBjYXNlIHN0dWR5XShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8vb2NzLWJwLXZhcGluZy1jYXNlLXN0dWR5Lyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBkZXRhaWxzIGFib3V0IGhvdyB0byB3cml0ZSBhIGZ1bmN0aW9uLg0KDQpJbiBnZW5lcmFsLCB0aGUgcHJvY2VzcyBvZiB3cml0aW5nIGZ1bmN0aW9ucyBpbnZvbHZlcyBmaXJzdCBzcGVjaWZ5aW5nIGFuIGlucHV0IHRoYXQgaXMgdXNlZCB3aXRoaW4gdGhlIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhbiBvdXRwdXQuIEluIHRoaXMgY2FzZSwgYFhQQVRIYCB3aWxsIGJlIHVzZWQgYXMgYW4gImlucHV0IGFyZ3VtZW50IiB0byB0aGUgZnVuY3Rpb24sIHdoaWNoIHdpbGwgYmUgcmVwbGFjZWQgYnkgYW4gYWN0dWFsIFhQYXRoIGFuZCB0aGVuIHVzZWQgaW4gdGhlIHN1YnNlcXVlbnQgc3RlcHMgdG8gc2NyYXBlIHRoZSBkYXRhIGZyb20gZWFjaCB0YWJsZSB0aGF0IGFuIFhQYXRoIGlzIHN1cHBsaWVkIGZvci4NCg0KV2Ugd2lsbCBjYWxsIHRoaXMgZnVuY3Rpb24gYHNjcmFwZXJgLg0KDQpgYGB7cn0NCnNjcmFwZXIgPC0gZnVuY3Rpb24oWFBBVEgpew0KICBOU0RVSF91cmwgPC0gImh0dHBzOi8vd3d3Lm9wZW5jYXNlc3R1ZGllcy5vcmcvb2NzLWJwLXlvdXRoLW1lbnRhbC1oZWFsdGgvZGF0YS9yYXcvc2FtaHNhLmdvdl8yMDIwX3RhYmxlcy5odG0iDQogIHRhYmxlIDwtIE5TRFVIX3VybCAlPiUNCiAgICByZWFkX2h0bWwoKSAlPiUNCiAgICBodG1sX25vZGVzKHhwYXRoID0gWFBBVEgpICU+JQ0KICAgIGh0bWxfdGFibGUoKQ0KICBvdXRwdXQgPC0gdGFibGVbWzFdXQ0KICBvdXRwdXQNCn0NCmBgYA0KDQpOb3cgd2UgY2FuIGFwcGx5IHRoZSBmdW5jdGlvbiB3ZSBjcmVhdGVkIHRvIGVhY2ggb2YgdGhlIFhQYXRocyBmb3IgZWFjaCBvZiB0aGUgdGFibGVzIG9uIHRoZSB3ZWJzaXRlIHRoYXQgd2Ugd291bGQgbGlrZSB0byB1c2UgaW4gb3VyIGRhdGEgYW5hbHlzaXMuDQoNCmBgYHtyfQ0KdGFibGUxMS4xYiA8LSBzY3JhcGVyKFhQQVRIID0gIi9odG1sL2JvZHkvZGl2WzRdL2RpdlsyXS90YWJsZSIpDQp0YWJsZTExLjJhIDwtIHNjcmFwZXIoWFBBVEggPSAnL2h0bWwvYm9keS9kaXZbNF0vZGl2WzNdL3RhYmxlJykNCnRhYmxlMTEuMmIgPC0gc2NyYXBlcihYUEFUSCA9ICcvaHRtbC9ib2R5L2Rpdls0XS9kaXZbNF0vdGFibGUnKQ0KdGFibGUxMS4zYSA8LSBzY3JhcGVyKFhQQVRIID0gJy9odG1sL2JvZHkvZGl2WzRdL2Rpdls1XS90YWJsZScpDQp0YWJsZTExLjNiIDwtIHNjcmFwZXIoWFBBVEggPSAnL2h0bWwvYm9keS9kaXZbNF0vZGl2WzZdL3RhYmxlJykNCnRhYmxlMTEuNGEgPC0gc2NyYXBlcihYUEFUSCA9ICcvaHRtbC9ib2R5L2Rpdls0XS9kaXZbN10vdGFibGUnKQ0KdGFibGUxMS40YiA8LSBzY3JhcGVyKFhQQVRIID0gJy9odG1sL2JvZHkvZGl2WzRdL2Rpdls4XS90YWJsZScpDQpgYGANCg0KDQpHcmVhdCEgV2UgaGF2ZSBzdWNjZXNzZnVsbHkgc2NyYXBlZCB0aGUgZGF0YSBmcm9tIHRoZSB3ZWIgaW50byBSIQ0KDQpOZXh0LCB3ZSBuZWVkIHRvIHdyYW5nbGUgdGhlIGRhdGEuDQoNCldlIHdpbGwgc2F2ZSB0aGUgaW1wb3J0ZWQgZGF0YSBub3cuIFRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGJhc2UgYHNhdmUoKWAgZnVuY3Rpb24uIFdlIHdpbGwgc2F2ZSBpdCB3aXRoaW4gYSBkaXJlY3RvcnkgY2FsbGVkICJpbXBvcnRlZCIgb2Ygb3VyICJkYXRhIiBkaXJlY3RvcnkuIE1ha2Ugc3VyZSB5b3UgbWFrZSB0aGlzIGRpcmVjdG9yeSBmaXJzdC4NCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCnNhdmUodGFibGUxMS4xYSwgdGFibGUxMS4xYiwgdGFibGUxMS4yYSwgdGFibGUxMS4yYiwgDQogICAgIHRhYmxlMTEuM2EsIHRhYmxlMTEuM2IsIHRhYmxlMTEuNGEsIHRhYmxlMTEuNGIsIA0KICAgICBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJpbXBvcnRlZCIsICJpbXBvcnRlZF9kYXRhLnJkYSIpKQ0KYGBgDQoNCg0KIyMgKipEYXRhIFdyYW5nbGluZyoqDQoqKiogDQpJZiB5b3UgaGF2ZSBiZWVuIGZvbGxvd2luZyBhbG9uZyBidXQgc3RvcHBlZCwgd2UgY291bGQgbG9hZCBvdXIgaW1wb3J0ZWQgZGF0YSBmcm9tIHRoZSAiZGF0YSIgZGlyZWN0b3J5IGxpa2Ugc286DQoNCmBgYHtyfQ0KbG9hZChmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJpbXBvcnRlZCIsICJpbXBvcnRlZF9kYXRhLnJkYSIpKQ0KYGBgDQoNCg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBJZiB5b3Ugc2tpcHBlZCB0aGUgZGF0YSBpbXBvcnQgc2VjdGlvbiBjbGljayBoZXJlLiA8L3N1bW1hcnk+DQoNCkZpcnN0IHlvdSBuZWVkIHRvIGluc3RhbGwgYW5kIGxvYWQgdGhlIGBPQ1NkYXRhYCBwYWNrYWdlOg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmluc3RhbGwucGFja2FnZXMoIk9DU2RhdGEiKQ0KbGlicmFyeShPQ1NkYXRhKQ0KYGBgDQoNClRoZW4sIHlvdSBtYXkgbG9hZCB0aGUgaW1wb3J0ZWQgZGF0YSB1c2luZyB0aGUgZm9sbG93aW5nIGNvZGU6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KaW1wb3J0ZWRfZGF0YSgib2NzLWJwLXlvdXRoLW1lbnRhbC1oZWFsdGgiLCBvdXRwYXRoID0gZ2V0d2QoKSkNCmxvYWQoaGVyZTo6aGVyZSgiT0NTZGF0YSIsICJkYXRhIiwgImltcG9ydGVkIiwgImltcG9ydGVkX2RhdGEucmRhIikpDQpgYGANCg0KSWYgdGhlIHBhY2thZ2UgZG9lcyBub3Qgd29yayBmb3IgeW91LCBhbHRlcm5hdGl2ZWx5LCBhbiBSREEgZmlsZSAoc3RhbmRzIGZvciBSIGRhdGEpIG9mIHRoZSBkYXRhIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tLy9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLXlvdXRoLW1lbnRhbC1oZWFsdGgvdHJlZS9tYXN0ZXIvZGF0YS9pbXBvcnRlZCkgb3Igc2xpZ2h0bHkgbW9yZSBkaXJlY3RseSBbaGVyZV0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAteW91dGgtbWVudGFsLWhlYWx0aC9tYXN0ZXIvZGF0YS9pbXBvcnRlZC9pbXBvcnRlZF9kYXRhLnJkYSkuIERvd25sb2FkIHRoaXMgZmlsZSBhbmQgdGhlbiBwbGFjZSBpdCBpbiB5b3VyIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnkgd2l0aGluIGEgc3ViZGlyZWN0b3J5IGNhbGxlZCAiaW1wb3J0ZWQiIHdpdGhpbiBhIHN1YmRpcmVjdG9yeSBjYWxsZWQgImRhdGEiIHRvIGNvcHkgYW5kIHBhc3RlIG91ciBjb2RlLiBXZSB1c2VkIGFuIFJTdHVkaW8gcHJvamVjdCBhbmQgdGhlIFtgaGVyZWAgcGFja2FnZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSB0byBuYXZpZ2F0ZSB0byB0aGUgZmlsZSBtb3JlIGVhc2lseS4gDQoNCmBgYHtyfQ0KbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgImltcG9ydGVkIiwgImltcG9ydGVkX2RhdGEucmRhIikpDQpgYGANCg0KKioqDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIG1vcmUgYWJvdXQgY3JlYXRpbmcgbmV3IHByb2plY3RzIGluIFJTdHVkaW8uIDwvc3VtbWFyeT4NCg0KWW91IGNhbiBjcmVhdGUgYSBwcm9qZWN0IGJ5IGdvaW5nIHRvIHRoZSBGaWxlIG1lbnUgb2YgUlN0dWRpbyBsaWtlIHNvOg0KDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJOZXdfcHJvamVjdC5wbmciKSkNCmBgYA0KDQpZb3UgY2FuIGFsc28gZG8gc28gYnkgY2xpY2tpbmcgdGhlIHByb2plY3QgYnV0dG9uOg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAicHJvamVjdF9idXR0b24ucG5nIikpDQpgYGANCg0KU2VlIFtoZXJlXShodHRwczovL3N1cHBvcnQucnN0dWRpby5jb20vaGMvZW4tdXMvYXJ0aWNsZXMvMjAwNTI2MjA3LVVzaW5nLVByb2plY3RzKSB0byBsZWFybiBtb3JlIGFib3V0IHVzaW5nIFJTdHVkaW8gcHJvamVjdHMgYW5kIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdGhlIGBoZXJlYCBwYWNrYWdlLg0KDQo8L2RldGFpbHM+DQoqKioNCjwvZGV0YWlscz4NCioqKg0KDQoNCk5vdyB0aGF0IHdlIGhhdmUgaW1wb3J0ZWQgdGhlIGRhdGEsIGxldCdzIHNlZSBpZiB3ZSBjYW4gd3JhbmdsZSBhIHRhYmxlLiANCg0KV2hhdCBkbyB3ZSBtZWFuIGJ5ICJ3cmFuZ2xlIj8gV2UgbWVhbiB0aGF0IHdlIGludGVuZCB0byBnZXQgdGhlIGRhdGEgaW50byB3aGF0IGlzIGNhbGxlZCAidGlkeSIgZm9ybWF0LiANCg0KVGhpcyBtZWFucyB0aGF0IHRoZSBkYXRhOiAgDQoxKSBoYXMgZWFjaCBvYnNlcnZhdGlvbiBpbiBzaW5nbGUgcm93ICANCjIpIGhhcyBhIHNpbmdsZSBhc3BlY3QgYWJvdXQgZWFjaCBvYnNlcnZhdGlvbiBhcyBhIHNpbmdsZSBjb2x1bW4gIA0KMykgaXMgcmVjdGFuZ3VsYXIgKG1lYW5pbmcgdGhlcmUgYXJlIG5vIGVtcHR5IGNlbGxzKSAgDQo0KSB0aGUgdmFsdWVzIHdpdGhpbiB0aGUgY2VsbHMgYXJlIGluIGEgZm9ybWF0IHRoYXQgaXMgdXNlZnVsIGZvciBtYWtpbmcgdmlzdWFsaXphdGlvbnMgYW5kIGZvciBhbmFseXNpcyAgDQoNCkNoZWNrIG91dCB0aGlzIFtwYXBlcl0oaHR0cHM6Ly92aXRhLmhhZC5jby5uei9wYXBlcnMvdGlkeS1kYXRhLnBkZikgZm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGlkeSBkYXRhLg0KDQpTaW5jZSB0aGUgZGF0YSBhcHBlYXIgdG8gYmUgZm9ybWF0dGVkIGluIGEgc2ltaWxhciB3YXkgaW4gZWFjaCBvZiB0aGUgdGFibGVzLCBpdCBpcyBsaWtlbHkgdGhhdCB3aGF0ZXZlciBzdGVwcyB3ZSB0YWtlIHRvIHdyYW5nbGUgdGhpcyBmaXJzdCB0YWJsZSB3aWxsIGFsc28gYmUgbmVjZXNzYXJ5IGluIHRoZSB3cmFuZ2xpbmcgb2Ygc3Vic2VxdWVudCB0YWJsZXMuIA0KVGhpcyBpcyBiZWNhdXNlIHdlbGwtbWFpbnRhaW5lZCBkYXRhIHNvdXJjZXMgb2Z0ZW4gZm9ybWF0IGRpZmZlcmVudCBkYXRhc2V0cyBzaW1pbGFybHkuIA0KV2UgY2FuIHRha2UgYWR2YW50YWdlIG9mIHRoaXMgc2ltaWxhcml0eSB0byBzcGVlZCB1cCB0aGUgd3JhbmdsaW5nIHByb2Nlc3MuIA0KDQoNCiMjIyAqKlRhYmxlMTEuMWEqKg0KKioqDQoNCkxldCdzIHRha2UgYSBsb29rIGF0IG91ciB0YWJsZSBvbiB0aGUgd2Vic2l0ZSB0byBzZWUgd2hhdCBpdCBuZWVkcyB0byBnZXQgaXQgaW50byAidGlkeSIgZm9ybWF0Lg0KDQpGaXJzdCwgd2UgY2FuIHNlZSB0aGF0IHdlIHdhbnQgdG8gcmVtb3ZlIHRoZSBsZWdlbmQgb2Ygb3VyIHRhYmxlLg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInRhYmxlMTEuMWEucG5nIikpDQpgYGANCg0KV2UgY2FuIHRha2UgYSBsb29rIGF0IHRoZSBsYXN0IHJvdyB1c2luZyB0aGUgYHRhaWxgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFdlIGNhbiBzcGVjaWZ5IHRoYXQgd2Ugb25seSB3YW50IHRvIHNlZSB0aGUgbGFzdCByb3cgYnkgdXNpbmcgdGhlIGBuID0gMWAgYXJndW1lbnQuIFRvIHVzZSB0aGUgYGRwbHlyYCBmdW5jdGlvbnMgd2UgbmVlZCB0byBmaXJzdCBtYWtlIHRoaXMgdGFibGUgaW50byBhIHRpYmJsZSwgd2hpY2ggaXMgdGhlIGB0aWR5dmVyc2VgIHZlcnNpb24gb2YgYSBkYXRhZnJhbWUuDQoNCkN1cnJlbnRseSB0YWJsZTExLjFhIGlzIGEgdHlwaWNhbCBkYXRhZnJhbWUsIHdoaWNoIHdlIGNhbiBzZWUgdXNpbmcgdGhlIGBjbGFzc2AgZnVuY3Rpb24gd2hpY2ggZGVzY3JpYmVzIHRoZSB0eXBlcyBvZiBkYXRhIG9iamVjdHMgaW4gUi4NCmBgYHtyfQ0KY2xhc3ModGFibGUxMS4xYSkNCmBgYA0KDQpXZSBjYW4gdXNlIHRoZSBgYXNfdGliYmxlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gY29udmVydCBgdGFibGUxMS4xYWAgaW50byBhIHRpYmJsZS4NCg0KYGBge3J9DQp0YWJsZTExLjFhICU+JQ0KICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lDQogIHRhaWwobiA9IDEpDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoZSBsZWdlbmQgaXMgcmVwZWF0ZWQgZm9yIGV2ZXJ5IGNvbHVtbi4gDQpOb3csIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSB5ZWFyIDIwMDQgY29sdW1uLg0KYGBge3J9DQp0YWJsZTExLjFhICU+JQ0KICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lICANCiAgZHBseXI6OnNlbGVjdChgMjAwNGApICU+JQ0KICB0YWlsKG4gPSAxKQ0KYGBgDQoNCkxldCdzIHNhdmUgdGhpcyB0byBhbiBvYmplY3QgY2FsbGVkIGBsZWdlbmRgIHNvIHRoYXQgd2UgY2FuIHJlZmVyIGJhY2sgdG8gaXQgbGF0ZXI6DQpgYGB7cn0NCmxlZ2VuZCA8LSB0YWJsZTExLjFhICU+JQ0KICBhc190aWJibGUoKSAlPiUgIA0KICBzZWxlY3QoYDIwMDRgKSAlPiUNCiAgdGFpbChuID0gMSkNCmBgYA0KDQpBbm90aGVyIHdheSB0byBsb29rIGF0IHRoZSBsYXN0IHJvdyBpcyB0byB1c2UgdGhlIGBuKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIA0KVGhpcyBmdW5jdGlvbiBjYW4gYmUgdXNlZCBpbnNpZGUgb3RoZXIgYGRwbHlyYCBmdW5jdGlvbnMgYW5kIGl0IGNvdW50cyB0aGUgdG90YWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBvZiBhIGdyb3VwLiANCldpdGhpbiB0aGUgW2BzbGljZSgpYCBmdW5jdGlvbl0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9zbGljZS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IG9mIHRoZSBgZHBseXJgIHBhY2thZ2UsIGl0IGFsbG93cyB5b3UgdG8gcmVmZXIgdGhlIGZ1bGwgbGVuZ3RoIG9mIHRoZSBvYmplY3QuDQoNCmBgYHtyfQ0KdGFibGUxMS4xYSAlPiUNCiAgZHBseXI6OmFzX3RpYmJsZSgpICU+JQ0KICBkcGx5cjo6c2xpY2UobigpKSANCmBgYA0KDQpXZSBjYW4gdXNlIHRoZSBgc2xpY2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byByZW1vdmUgdGhpcyByb3csIGJ5IHVzaW5nIHRoZSBgc2xpY2VgZnVuY3Rpb24gdG8gc2VsZWN0IGZyb20gdGhlIGZpcnN0IHJvdyB1c2luZyBgMTpgIHRvIHRoZSBzZWNvbmQgdG8gbGFzdCByb3cgdXNpbmcgYG4oKS0xYC4NCg0KV2UgYXJlIGFsc28gZ29pbmcgdG8gdXNlIGEgc3BlY2lhbCBwaXBlIG9wZXJhdG9yIGZyb20gdGhlIFtgbWFncml0dHJgIHBhY2thZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBjYWxsZWQgdGhlIGNvbXBvdW5kIGFzc2lnbm1lbnQgcGlwZS1vcGVyYXRvciBvciBzb21ldGltZXMgdGhlIGRvdWJsZSBwaXBlIG9wZXJhdG9yLiANClRoaXMgYWxsb3dzIHVzIHRvIHVzZSB0aGUgYHRhYmxlMTEuMWFgIGFzIG91ciBpbnB1dCBhbmQgcmVhc3NpZ24gaXQgYXQgdGhlIGVuZCBhZnRlciBhbGwgdGhlIHN0ZXBzIGhhdmUgYmVlbiBwZXJmb3JtZWQuDQoNCldlIHdpbGwgYWxzbyBmaXJzdCBjaGFuZ2UgdGhlIGRhdGEgdG8gYmUgYSBbdGliYmxlXShodHRwczovL3RpYmJsZS50aWR5dmVyc2Uub3JnLyM6fjp0ZXh0PUElMjB0aWJibGUlMkMlMjBvciUyMHRibF9kZiUyMCUyQyUyMGlzLG1vZGVybiUyMHJlaW1hZ2luaW5nJTIwb2YlMjB0aGUlMjBkYXRhLiZ0ZXh0PVRpYmJsZXMlMjBhcmUlMjBkYXRhLixhJTIwdmFyaWFibGUlMjBkb2VzJTIwbm90JTIwZXhpc3QpLCB3aGljaCBpcyB0aGUgYHRpZHl2ZXJzZWAgdmVyc2lvbiBvZiBhIGRhdGEgZnJhbWUgdXNpbmcgdGhlIGBhc190aWJibGUoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSBhbmQgdGhlIGB0aWJibGVgIHBhY2thZ2UuDQoNCmBgYHtyfQ0KdGFibGUxMS4xYSAlPD4lDQogIGRwbHlyOjphc190aWJibGUoKSAlPiUNCiAgc2xpY2UoMToobigpLTEpKQ0KYGBgDQoNCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgZGF0YToNCmBgYHtyfQ0Kc2xpY2VfaGVhZCh0YWJsZTExLjFhLCBuID0gKGxlbmd0aChwdWxsKHRhYmxlMTEuMWEsIGAyMDAyYCkpKSkNCmBgYA0KDQpHcmVhdCEgV2UgY2FuIHNlZSB0aGUgdGhlIGxlZ2VuZCBpcyBubyBsb25nZXIgcGFydCBvZiB0aGUgZGF0YS4NCg0KTm93IGxldCdzIHVzZSB0aGUgbGVnZW5kIHRvIHJlY29kZSB0aGUgZGF0YS4gDQpUaGVyZSBhcmUgbWFueSBkaWZmZXJlbnQgdmFsdWVzIGZvciBtaXNzaW5nIGRhdGEsIHRoYXQgd2Ugd291bGQgbGlrZSB0byByZXBsYWNlIHdpdGggYE5BYCBpbnN0ZWFkLg0KV2UgY2FuIHVzZSB0aGUgYHB1bGwoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byB0YWtlIGEgbG9vayBhdCB0aGUgbGVnZW5kIGRhdGE6DQoNCmBgYHtyfQ0KZHBseXI6OnB1bGwobGVnZW5kLCBgMjAwNGApDQpgYGANCg0KTG9va3MgbGlrZSB3ZSB3YW50IHRvIHJlcGxhY2UgdmFsdWVzIHRoYXQgYXJlOiBgKmAsIGAtLWAsIGBkYWAsIGBuY2AsIGFuZCBgbnJgLiANCg0KDQpXZSBjYW4gdXNlIHRoZSBgbmFfaWYoKWAgZnVuY3Rpb24gdG8gcmVjb2RlIHRoZXNlIHZhbHVlcyB0byBgTkFgLg0KDQoNCmBgYHtyfQ0KdGFibGUxMS4xYSAlPD4lDQogIGRwbHlyOjpuYV9pZigibmMiKSAlPiUNCiAgZHBseXI6Om5hX2lmKCItLSIpICU+JQ0KICBkcGx5cjo6bmFfaWYoIiIpICU+JQ0KICBkcGx5cjo6bmFfaWYoIioiKQ0KDQpoZWFkKHRhYmxlMTEuMWEpDQpgYGANCg0KDQpMZXQncyBsb29rIGF0IHRoZSBjb2x1bW4gbmFtZXMgaW4gb3VyIHRhYmxlOiANCmBgYHtyfQ0KY29sbmFtZXModGFibGUxMS4xYSkNCmBgYA0KDQpMZXQncyByZW5hbWUgdGhlIGZpcnN0IGNvbHVtbiB1c2luZyB0aGUgYHJlbmFtZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiANClRoaXMgcmVxdWlyZXMgbGlzdGluZyB0aGUgbmV3IG5hbWUgZmlyc3QgbGlrZSBzbzogYG5ld19uYW1lID0gb2xkX25hbWVgLg0KDQpgYGB7cn0NCnRhYmxlMTEuMWEgJTw+JQ0KICBkcGx5cjo6cmVuYW1lKE1IU19zZXR0aW5nID0gYFNldHRpbmcgV2hlcmUgTWVudGFsIEhlYWx0aCBTZXJ2aWNlV2FzIFJlY2VpdmVkYCkNCg0KaGVhZCh0YWJsZTExLjFhKQ0KYGBgDQoNCk5pY2UhDQoNCk5vdyB5b3UgbWF5IG5vdGljZSB0aGF0IHRoZSBpbmRpdmlkdWFsIHZhbHVlcyBmb3IgdGhlIHllYXIgY29sdW1ucyBoYXZlIGFuIGAiYSJgIGFmdGVyIHRoZSBudW1lcmljIHZhbHVlLg0KDQpBY2NvcmRpbmcgdG8gdGhlIGxlZ2VuZCB0aGlzIGluZGljYXRlcyBpZiAidGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGlzIGVzdGltYXRlIGFuZCB0aGUgMjAxOCBlc3RpbWF0ZSBpcyBzaWduaWZpY2FudCBhdCB0aGUgJFxhbHBoYSQ9LjA1IGxldmVsLiINCg0KV2hpbGUgdGhpcyBpcyB1c2VmdWwgaW5mb3JtYXRpb24sIGl0IG1ha2VzIGl0IGRpZmZpY3VsdCB0byB3b3JrIHdpdGggb3VyIG51bWVyaWMgdmFsdWVzLCBzbyB3ZSB3YW50IHRvIHJlbW92ZSB0aGVtLg0KDQoNClNpbmNlIGxvd2VyIGNhc2UgYCJhImAgdmFsdWVzIG9jY3VyIGluIHRoZSB2YWx1ZXMgb2YgdGhlIGBNSFNfc2V0dGluZ2AgY29sdW1uIChsaWtlIG91dHAqKmEqKnRpZW50KSwgd2Ugd2FudCB0byBtYWtlIHN1cmUgdGhhdCB3ZSBkb24ndCBqdXN0IHJlbW92ZSBhbGwgYCJhImAgdmFsdWVzIGZyb20gdGhlIHRhYmxlLCBqdXN0IHRob3NlIGluIHRoZSBzdWJzZXF1ZW50IGNvbHVtbnMuIA0KDQoNClNvIGhvdyBjYW4gd2UgZG8gdGhpcz8gV2UgY2FuIHVzZSB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgdG8gbW9kaWZ5IGNoYXJhY3RlciBzdHJpbmdzLiANCkFsc28sIHdlIGNhbiB1c2UgdGhlIGBkcGx5cmAgZnVuY3Rpb25zIGBtdXRhdGUoKWAsIGBzZWxlY3QoKWAgYW5kIGBhY3Jvc3MoKWAgdG8gc3BlY2lmeSB3YW50IGNvbHVtbnMgd2Ugd2FudCB0byBjaGFuZ2UuDQoNCkN1cnJlbnRseSBhbGwgb2Ygb3VyIGRhdGEgYXJlIGNoYXJhY3RlciBzdHJpbmdzIGFzIGluZGljYXRlZCBieSB0aGUgYDxjaHI+YCB1bmRlciB0aGUgY29sdW1uIG5hbWVzLiANCg0KKioqDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSBmb3IgYW4gZXhwbGFuYXRpb24gYWJvdXQgZGF0YSBjbGFzc2VzIGluIFIgYW5kIGFib3V0IGNoYXJhY3RlciBzdHJpbmdzLiA8L3N1bW1hcnk+DQoNCg0KVGhlcmUgYXJlIHNldmVyYWwgW2NsYXNzZXMgb2YgZGF0YSBpbiBSIHByb2dyYW1taW5nXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9SXyhwcm9ncmFtbWluZ19sYW5ndWFnZSkpLCBtZWFuaW5nIHRoYXQgY2VydGFpbiBvYmplY3RzIHdpbGwgYmUgdHJlYXRlZCBvciBpbnRlcnByZXRlZCBkaWZmZXJlbnRseS4gDQpDaGFyYWN0ZXIgaXMgb25lIG9mIHRoZXNlIGNsYXNzZXMuIA0KQSBjaGFyYWN0ZXIgc3RyaW5nIGlzIGFuIGluZGl2aWR1YWwgZGF0YSB2YWx1ZSBtYWRlIHVwIG9mIGNoYXJhY3RlcnMuIA0KVGhpcyBjYW4gYmUgYSBwYXJhZ3JhcGgsIGxpa2UgdGhlIGxlZ2VuZCBmb3IgdGhlIHRhYmxlLCBvciBpdCBjYW4gYmUgYSBzaW5nbGUgbGV0dGVyIG9yIG51bWJlciBsaWtlIHRoZSBsZXR0ZXIgYCJhImAgb3IgdGhlIG51bWJlciBgIjMiYC4gDQpJZiBkYXRhIGFyZSBvZiBjbGFzcyBjaGFyYWN0ZXIsIHRoYW4gdGhlIG51bWVyaWMgdmFsdWVzIHdpbGwgbm90IGJlIHByb2Nlc3NlZCBsaWtlIGEgbnVtZXJpYyB2YWx1ZSBpbiBhIG1hdGhlbWF0aWNhbCBzZW5zZS4gDQpJZiB5b3Ugd2FudCB5b3VyIG51bWVyaWMgdmFsdWVzIHRvIGJlIGludGVycHJldGVkIHRoYXQgd2F5LCB0aGV5IG5lZWQgdG8gYmUgY29udmVydGVkIHRvIGEgbnVtZXJpYyBjbGFzcy4gDQpUaGUgb3B0aW9ucyB0eXBpY2FsbHkgdXNlZCBhcmUgaW50ZWdlciAod2hpY2ggaGFzIG5vIGRlY2ltYWwgcGxhY2UpIGFuZCBkb3VibGUgcHJlY2lzaW9uICh3aGljaCBoYXMgYSBkZWNpbWFsIHBsYWNlKS4gDQoNCjwvZGV0YWlscz4NCg0KDQoqKioNCiAgDQpUaGUgYHN0cmluZ3JgIHBhY2thZ2UgaGFzIGZ1bmN0aW9ucyB0aGF0IGFsbG93IHVzIHRvIHJlcGxhY2UgKHVzaW5nIHRoZSBgc3RyX3JlcGxhY2UoKWAgZnVuY3Rpb24pIG9yIHJlbW92ZSAodXNpbmcgdGhlIGBzdHJfcmVtb3ZlKClgIGZ1bmN0aW9uKSBjaGFyYWN0ZXJzLiANCg0KVG8gdXNlIHRoZXNlLCB3ZSBuZWVkIHRvIGJlIGFibGUgdG8gc3BlY2lmeSB3aGF0IHdlIHdhbnQgdG8gcmVtb3ZlIGFuZCByZXBsYWNlLiANCg0KSGVyZSBpcyBhIHBhcnQgb2YgYSBbY2hlYXRzaGVldF0oaHR0cHM6Ly9yc3R1ZGlvLmNvbS9yZXNvdXJjZXMvY2hlYXRzaGVldHMvKXt0YXJnZXQ9Il9ibGFuayJ9IGFib3V0IHN0cmluZyBtYW5pcHVsYXRpb24gZnJvbSBSU3R1ZGlvLg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJyZWdleC5wbmciKSkNCmBgYA0KDQpXZSBjYW4gc2VlIHRoYXQgd2UgY2FuIHJlZmVyIHRvIGFueSBkaWdpdCAoc3VjaCBhcyAxLCAyLCAzIGV0Yy4pIGFzIGBbOmRpZ2l0Ol1gLg0KV2UgY2FuIGFsc28gc2VlIHRoYXQgd2UgY2FuIHJlZmVyIHRvIGFueSBwdW5jdHVhdGlvbiBtYXJrIGFzIGBbOnB1bmN0Ol1gLg0KRmluYWxseSwgd2Ugc2VlIHRoYXQgc3BhY2VzIGFuZCB0YWJzIGNhbiBiZSByZWZlcnJlZCB0byBhcyBgWzpibGFuazpdYC4NCg0KSWYgd2UgdGFrZSBhIGNsb3NlciBsb29rIGF0IGp1c3QgdGhlIGZpcnN0IGNvbHVtbiBvZiBvdXIgdGFibGUgKHVzaW5nIHRoZSBgcHVsbCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlKSwgd2UgIHNlZSB0aGF0IHRoZXJlIGFyZSBhbHNvIHNvbWUgbGFyZ2Ugd2hpdGUgc3BhY2VzLCBzb21lIG51bWVyaWMgdmFsdWVzLCBpbnN0YW5jZXMgb2YgYCJcclxuImAsIGFzIHdlbGwgYXMgc29tZSBjb21tYXMgYW5kIG90aGVyIHB1bmN0dWF0aW9uIG1hcmtzIHRoYXQgd2Ugd291bGQgbGlrZSB0byByZW1vdmUgZm9ybSB0aGlzIGNvbHVtbi4gDQoNCmBgYHtyfQ0KdGFibGUxMS4xYSAlPiUgDQogIHB1bGwoTUhTX3NldHRpbmcpDQpgYGANCg0KDQpXZSBjYW4gdXNlIHRoZSBgc3RyX3JlbW92ZV9hbGwoKWAgZnVuY3Rpb24gdG8gcmVtb3ZlIHRoZXNlIHVud2FudGVkIGNoYXJhY3RlcnMgZnJvbSB0aGlzIGNvbHVtbiBzcGVjaWZpY2FsbHkuDQoNClRoZSBgc3RyX3JlbW92ZV9hbGwoKWAgZnVuY3Rpb24gaXMgYSB2YXJpYW50IG9mIHRoZSBgc3RyX3JlbW92ZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIEl0IGFsbG93cyB1cyB0byByZW1vdmUgYWxsIG9jY3VycmVuY2VzIG9mIHNwZWNpZmllZCBjaGFyYWN0ZXJzIGluIGVhY2ggcm93IHJhdGhlciB0aGFuIGp1c3QgdGhlIGZpcnN0IG9jY3VycmVuY2UgKHdoaWNoIGlzIHdoYXQgYHN0cl9yZW1vdmUoKWAgZG9lcykuDQoNCg0KVXNpbmcgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24sIHdlIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRvIGNoYW5nZSB0aGlzIHBhcnRpY3VsYXIgY29sdW1uIGFuZCByZXBsYWNlIGl0IHdpdGggYSB2ZXJzaW9uIG9mIHRoaXMgY29sdW1uIHRoYXQgZG9lcyBub3QgY29udGFpbiBjaGFyYWN0ZXJzIHRoYXQgYXJlIGRpZ2l0cywgdGhlIGByXG5gIHN0cmluZyB0aGF0IHdlIHNhdywgb3IgcHVuY3R1YXRpb24gbWFya3MuDQoNCldlIG5lZWQgdG8gc3BlY2lmeSB0aGF0IHRoZSBjaGFyYWN0ZXIgc3RyaW5ncyB0aGF0IHNob3VsZCBiZSB1c2VkIGNhbiBiZSBmb3VuZCBpbiB0aGUgYE1IU19zZXR0aW5nYCBjb2x1bW4gYnkgdXNpbmcgdGhlIGBzdHJpbmcgPWAgYXJndW1lbnQgYW5kIHRoZSBwYXR0ZXJucyB0byBmaW5kIGFuZCByZW1vdmUgYXJlIHNwZWNpZmllZCB1c2luZyB0aGUgYHBhdHRlcm4gPWAgYXJndW1lbnQuDQoNClRvIGFsbG93IHVzIHRvIGxvb2sgZm9yIGFsbCB0aHJlZSBvZiB0aGVzZSBwYXR0ZXJucyBhdCB0aGUgc2FtZSB0aW1lLCB3ZSBjYW4gdXNlIHRoZSBgfGAgc3ltYm9sIGJldHdlZW4gZWFjaCBwYXR0ZXJuLg0KDQpgYGB7cn0NCnRhYmxlMTEuMWEgJTw+JQ0KbXV0YXRlKE1IU19zZXR0aW5nID0gDQogICAgICAgICBzdHJfcmVtb3ZlX2FsbChzdHJpbmcgPSBNSFNfc2V0dGluZywgDQogICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIls6ZGlnaXQ6XXxcclxufFs6cHVuY3Q6XXwiKSkNCg0KaGVhZCh0YWJsZTExLjFhKQ0KYGBgDQoNCldlIGFsc28gd2FudCB0byByZXBsYWNlIHRoZSBzcGFjZXMgd2l0aCBhIHNpbmdsZSBzcGFjZS4gDQpXZSBjYW4gc2VlIHRoYXQgc29tZXRpbWVzIHRoZXJlIGFwcGVhcnMgdG8gYmUgbW9yZSB0aGFuIG9uZSBzcGFjZS4gDQpXZSBjYW4gc3BlY2lmeSB0aGF0IHdlIHdhbnQgYW55IG9jY3VycmVuY2Ugb2YgMSBvciBtb3JlIHRvIGJlIHJlcGxhY2VkIGJ5IHVzaW5nIHRoZSBgezEsfWAgbm90YXRpb24uDQoNClNlZSBoZXJlIGZvciBhbiBleHBsYW5hdGlvbiBvZiB0aGlzIG9uIHRoZSBjaGVhdCBzaGVldDoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAicXVhbnRpZmllcnMucG5nIikpDQpgYGANCg0KU28sIHdlIHdpbGwgdXNlIHRoZSBgc3RyX3JlcGxhY2VfYWxsKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZS4NCkluIHRoaXMgY2FzZSwgd2UgYWxzbyBuZWVkIHRvIHNwZWNpZnkgYSByZXBsYWNlbWVudCB3aXRoIHRoZSBgcmVwbGFjZW1lbnQgPSBgIGFyZ3VtZW50LiBXZSB3aWxsIHVzZSB0aGlzIHRvIHNwZWNpZnkgb25lIHNwYWNlLg0KDQpgYGB7cn0gDQp0YWJsZTExLjFhICU8PiUNCm11dGF0ZShNSFNfc2V0dGluZyA9IA0KICAgICAgICAgc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9IE1IU19zZXR0aW5nLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiWzpibGFuazpdezEsfSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIiAiKSkNCg0KaGVhZCh0YWJsZTExLjFhKQ0KYGBgDQoNCk5leHQsIHdlIHdpbGwgcmVtb3ZlIHRoZSBgImEiYCB2YWx1ZXMgYW5kIHRoZSBjb21tYXMgZnJvbSB0aGUgYm9keSBvZiB0aGUgdGFibGUgdXNpbmcgdGhlIGBzdHJfcmVtb3ZlX2FsbCgpYCBmdW5jdGlvbiB5ZXQgYWdhaW4uDQoNCkhvd2V2ZXIsIHRoaXMgdGltZSB0byBzcGVjaWZ5IHRoYXQgd2Ugd2FudCBhbGwgY29sdW1ucyBleGNlcHQgdGhlIGZpcnN0IGNvbHVtbiBjYWxsZWQgYE1IU19zZXR0aW5nYCwgd2UgY2FuIHVzZSB0aGUgYGFjcm9zcygpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiANCg0KVGhpcyBhbGxvd3MgdXMgdG8gc3BlY2lmeSB3aGF0IGNvbHVtbnMgd2Ugd2FudCB0byBtdXRhdGUgYnkgdXNpbmcgdGhlIGAuY29scyA9IGAgYXJndW1lbnQuIA0KV2UgY2FuIHNlbGVjdCBhbGwgY29sdW1ucyBleGNlcHQgdGhlIGZpcnN0IGNvbHVtbiBjYWxsZWQgYE1IU19zZXR0aW5nYCBieSB1c2luZyBhIG1pbnVzIHNpZ24gYC1gIGluIGZyb250IG9mIHRoZSBjb2x1bW4gbmFtZS4NCg0KYGBge3J9DQp0YWJsZTExLjFhICU8PiUNCiAgbXV0YXRlKGRwbHlyOjphY3Jvc3MoLmNvbHMgPSAtTUhTX3NldHRpbmcsDQogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3I6OnN0cl9yZW1vdmVfYWxsLCAiYXwsIikpDQoNCmhlYWQodGFibGUxMS4xYSkNCmBgYA0KDQpPdXIgdGFibGUgaXMgbG9va2luZyBtdWNoIGJldHRlciENCg0KV2UgYWxzbyB3YW50IHRvIGNoYW5nZSBvdXIgdmFsdWVzIHRvIGJlIG51bWVyaWMgYXMgb3Bwb3NlZCB0byBjaGFyYWN0ZXIgc28gdGhhdCB3ZSBjYW4gdXNlIHRoZW0gaW4gbWF0aGVtYXRpY2FsIGZ1bmN0aW9ucy4gDQpXZSBjYW4gdXNlIHRoZSBiYXNlIGBhcy5udW1lcmljKClgIGZ1bmN0aW9uLiANCkFnYWluIHdlIHdpbGwgdXNlIHRoZSBgYWNyb3NzKClgIGZ1bmN0aW9uIHRvIGluZGljYXRlIHdoYXQgdmFyaWFibGVzIHdlIHdpc2ggdG8gbXV0YXRlLg0KDQpgYGB7cn0NCnRhYmxlMTEuMWEgJTw+JQ0KICBtdXRhdGUoYWNyb3NzKC5jb2xzID0tTUhTX3NldHRpbmcsIGFzLm51bWVyaWMpKQ0KDQpoZWFkKHRhYmxlMTEuMWEpDQpgYGANCg0KV2Ugd291bGQgYWxzbyBsaWtlIHRvIGFkZCBhIGB0eXBlYCBhbmQgYHN1YnR5cGVgIHZhcmlhYmxlLCB0aGF0IHNwZWNpZmllcyB0aGUgZ2VuZXJhbCBjYXRlZ29yaWVzIG9mIHNldHRpbmdzIHdoZXJlIHNlcnZpY2VzIHdlcmUgcmVjZWl2ZWQsIGFzIHdlbGwgYXMgcmVtb3ZlIGEgY291cGxlIG9mIHJvd3MgdGhhdCBhcmUgY29tcGxldGVseSBlbXB0eS4gDQpUaGVzZSBhcmUgdGhlIHJvd3Mgd2hlcmUgdGhlIGZpcnN0IGNvbHVtbiB2YWx1ZXMgYXJlIGBHZW5lcmFsIE1lZGljaW5lYCBhbmQgYEp1dmVuaWxlIEp1c3RpY2VgLCBhbmQgYENoaWxkIFdlbGZhcmVgLiBJZiB3ZSBsb29rIGF0IHRoZSB3ZWJzaXRlLCB3ZSBjYW4gc2VlIHRoYXQgdGhlc2Ugd2VyZSBsZWFkaW5nIGxpbmVzIHdpdGggbm8gZGF0YS4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAidGFibGUxMS4xYS5wbmciKSkNCmBgYA0KDQpGaXJzdCwgd2Ugd2lsbCBhZGQgdGhlIGB0eXBlYCBhbmQgYHN1YnR5cGVgIHZhcmlhYmxlcyB1c2luZyB0aGUgYG11dGF0ZWAgZnVuY3Rpb24uDQoNCmBgYHtyfQ0KdGFibGUxMS4xYSAlPD4lDQogIG11dGF0ZSh0eXBlID0gYyhyZXAoIlNwZWNpYWx0eSIsIDkpLCANCiAgICAgICAgICAgICAgICAgIHJlcCgiTm9uc3BlY2lhbHR5IiwgMTEpKSkgJT4lDQogIG11dGF0ZShzdWJ0eXBlID0gYygiU3BlY2lhbHR5X3RvdGFsIiwgDQogICAgICAgICAgICAgICAgICAgICByZXAoIk91dHBhdGllbnQiLCA1KSwgDQogICAgICAgICAgICAgICAgICAgICByZXAoIklucGF0aWVudCIsIDMpLCANCiAgICAgICAgICAgICAgICAgICAgICJOb25zcGVjaWFsdHlfdG90YWwiLCANCiAgICAgICAgICAgICAgICAgICAgIHJlcCgiRWR1Y2F0aW9uIiwgMyksIA0KICAgICAgICAgICAgICAgICAgICAgcmVwKCJHZW5lcmFsX21lZGljaW5lIiwgMiksDQogICAgICAgICAgICAgICAgICAgICByZXAoIkp1dmVuaWxlX0p1c3RpY2UiLCAyKSwgDQogICAgICAgICAgICAgICAgICAgICByZXAoIkNoaWxkX1dlbGZhcmUiLCAyKSwgDQogICAgICAgICAgICAgICAgICAgICAiY29tYmluYXRpb24iKSkNCmBgYA0KDQpXZSBhbHNvIHdhbnQgdG8gYWRkIGEgdmFyaWFibGUgd2l0aCBzaG9ydGVyIG5hbWVzIGZvciBsYWJlbHMgaW4gcGxvdHMgYW5kIHN0YXRpc3RpY2FsIG91dHB1dC4NCg0KYGBge3J9DQp0YWJsZTExLjFhICU8PiUNCiAgbXV0YXRlKHNob3J0X2xhYmVsID0gYygiU3BlY2lhbHR5IHRvdGFsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIk91dHBhdGllbnQgdG90YWwiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAiVGhlcmFwaXN0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIkNsaW5pYyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICJEYXkgcHJvZ3JhbSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIkluLWhvbWUgVGhlcmFwaXN0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIklucGF0aWVudCB0b3RhbCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICJIb3NwaXRhbCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICJSZXNpZGVudGlhbCBDZW50ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJOb25zcGVjaWFsdHkgdG90YWwiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAiU2Nob29sIHRvdGFsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIlNjaG9vbCBUaGVyYXBpc3QiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAiU2Nob29sIFByb2dyYW0iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAiR2VuZXJhbCBNZWRpY2luZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIkZhbWlseSBEciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIkp1c3RpY2UgU3lzdGVtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiSnVzdGljZSBTeXN0ZW0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJXZWxmYXJlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIkZvc3RlcmNhcmUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAiU3BlY2lhbHR5IENvbWJpbmF0aW9uIikpDQpgYGANCg0KV2UgY2FuIHJlbW92ZSB0aGUgZW1wdHkgcm93cyB1c2luZyB0aGUgYGZpbHRlcigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiANCldlIGNhbiBzcGVjaWZ5IHRoYXQgd2UgZG9uJ3Qgd2FudCB0byBrZWVwIHRoZXNlIHJvd3MgYnkgdXNpbmcgdGhlIGAhPWAgbm90IGVxdWFsIHRvIG9wZXJhdG9yLiANCg0KYGBge3J9DQp0YWJsZTExLjFhICU8PiUNCiAgZHBseXI6OmZpbHRlcihNSFNfc2V0dGluZyAhPSAiR2VuZXJhbF9NZWRpY2luZSIpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKE1IU19zZXR0aW5nICE9ICJKdXZlbmlsZV9KdXN0aWNlIikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoTUhTX3NldHRpbmcgIT0gIkNoaWxkX1dlbGZhcmUiKQ0KDQpoZWFkKHRhYmxlMTEuMWEpDQpgYGANCg0KRmluYWxseSwgd2Ugd291bGQgbGlrZSB0byBjaGFuZ2UgdGhlIHNoYXBlIG9mIG91ciB0YWJsZSBzbyB0aGF0IHdlIGhhdmUgYSBuZXcgY29sdW1uIHRoYXQgcmVwcmVzZW50cyB0aGUgeWVhciBhbmQgYSBuZXcgY29sdW1uIHRoYXQgcmVwcmVzZW50cyB0aGUgdmFsdWUgZm9yIHRoYXQgeWVhci4gDQpUbyBkbyBzbyB3ZSB3aWxsIGJlIG1ha2luZyBvdXIgdGFibGUgImxvbmdlciIsIG1lYW5pbmcgdGhhdCBpdCB3aWxsIGhhdmUgZmV3ZXIgY29sdW1ucyBhbmQgbW9yZSByb3dzLiANClNlZSBbaGVyZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvV2lkZV9hbmRfbmFycm93X2RhdGEpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgZGlmZmVyZW50IHRhYmxlIGZvcm1hdHMsIHR5cGljYWxseSByZWZlcnJlZCB0byBhcyB3aWRlIGFuZCBsb25nIG9yIHNvbWV0aW1lcyBuYXJyb3cuDQoNCldlIHdpbGwgdXNlIHRoZSBgcGl2b3RfbG9uZ2VyKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGlkeXJgIHBhY2thZ2UgdG8gY2hhbmdlIHRoZSBzaGFwZSBvZiBvdXIgdGFibGUuIA0KDQpUaGVyZSBhcmUgMyBtYWluIGFyZ3VtZW50cyBpbiB0aGlzIGZ1bmN0aW9uOiAgIA0KDQoxLiBgY29sc2AgLSB3aGljaCBzcGVjaWZpZXMgd2hhdCBjb2x1bW5zIHRvIGNvbGxhcHNlICANCjIuIGBuYW1lc190b2AgLSB3aGljaCBzcGVjaWZpZXMgdGhlIG5hbWUgb2YgdGhlIG5ldyBjb2x1bW4gdGhhdCB3aWxsIGJlIGNyZWF0ZWQgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIGNvbHVtbiBuYW1lcyBvZiB0aGUgY29sdW1ucyB5b3UgYXJlIGNvbGxhcHNpbmcgIA0KMy4gYHZhbHVlc190b2AgLSB3aGljaCBzcGVjaWZpZXMgdGhlIG5hbWUgb2YgdGhlIG5ldyBjb2x1bW4gdGhhdCB3aWxsIGJlIGNyZWF0ZWQgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIHZhbHVlcyBmcm9tIHRoZSBjb2x1bW5zIHlvdSBhcmUgY29sbGFwc2luZyANCg0KVG8gc3BlY2lmeSB0aGF0IHdlIHdhbnQgdG8gY29sbGFwc2UgYWxsIHRoZSBjb2x1bW5zIHRoYXQgaGF2ZSB5ZWFyIHZhbHVlcywgd2UgY2FuIGNob3NlIHRob3NlIHRoYXQgY29udGFpbiB0aGUgc3RyaW5nIGAiMjAiYCB1c2luZyB0aGUgYGNvbnRhaW5zKClgIGZ1bmN0aW9uIG9mIGBkcGx5cmAuIA0KDQpGaW5hbGx5LCB3ZSB3aWxsIG1ha2UgdGhlIGBZZWFyYCB2YXJpYWJsZSBudW1lcmljIGFzIHdlbGwuDQoNCldlIHdpbGwgZmlyc3QgdXNlIHRoZSBiYXNlIGBkaW0oKWAgZnVuY3Rpb24gdG8gc2VlIHRoZSBkaW1lbnNpb25zIG9mIG91ciB0YWJsZSBiZWZvcmUgYW5kIGFmdGVyIHVzaW5nIGBwaXZvdF9sb25nZXIoKWAuDQoNCmBgYHtyfQ0KZGltKHRhYmxlMTEuMWEpDQp0YWJsZTExLjFhICU8PiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoIjIwIiksIA0KICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlllYXIiLA0KICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJOdW1iZXIiKSAlPiUNCiAgbXV0YXRlKFllYXIgPSBhcy5udW1lcmljKFllYXIpKQ0KDQpkaW0odGFibGUxMS4xYSkNCmhlYWQodGFibGUxMS4xYSkNCmBgYA0KDQpXZSBjYW4gc2VlIHRoYXQgb3VyIHRhYmxlIGlzIG5vdyBtdWNoIGxvbmdlciAtIGFzIHdlIGhhdmUgYHIgZGltKHRhYmxlMTEuMWEpWzFdYCByb3dzIQ0KDQojIyMjIHsucXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KV2h5IGRvIHdlIGhhdmUgYHIgZGltKHRhYmxlMTEuMWEpWzFdYCByb3dzIG5vdz8NCg0KIyMjIw0KDQpOb3csIHdlIHNlZSB0aGF0IHRoZSBgWWVhcmAgYW5kIGBOdW1iZXJgIHZhcmlhYmxlcyBhcmUgb2YgY2xhc3MgZG91YmxlIGJlY2F1c2Ugb2YgdGhlIGA8ZGJsPmAgdW5kZXIgdGhlIGNvbHVtbiBuYW1lLg0KDQpMZXQncyByZW1pbmQgb3Vyc2VsdmVzIHdoYXQgdGhlIHJlc3Qgb2YgdGhlIHRhYmxlcyBjb250YWluOg0KDQoNClRhYmxlICAgfCBEZXRhaWxzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KLS0tfC0tLS0tLS0tLS0tLS0NClRhYmxlIDExLjFBICAgICAgIHwgU2V0dGluZ3MgV2hlcmUgTWVudGFsIEhlYWx0aCBTZXJ2aWNlcyBXZXJlIFJlY2VpdmVkIGluIFBhc3QgWWVhciBhbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTc6IE51bWJlcnMgaW4gVGhvdXNhbmRzLCAyMDAyLTIwMTggICANClRhYmxlIDExLjFCICAgICAgIHwgU2V0dGluZ3MgV2hlcmUgTWVudGFsIEhlYWx0aCBTZXJ2aWNlcyBXZXJlIFJlY2VpdmVkIGluIFBhc3QgWWVhciBhbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTc6IFBlcmNlbnRhZ2VzLCAyMDAyLTIwMTggIA0KVGFibGUgMTEuMkEgICAgICAgfCAgTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlIGluIFBhc3QgWWVhciBhbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTcsIGJ5IERlbW9ncmFwaGljIENoYXJhY3RlcmlzdGljczogTnVtYmVycyBpbiBUaG91c2FuZHMsIDIwMDQtMjAxOA0KVGFibGUgMTEuMkIgICAgICAgfCBNYWpvciBEZXByZXNzaXZlIEVwaXNvZGUgaW4gUGFzdCBZZWFyIGFtb25nIFBlcnNvbnMgQWdlZCAxMiB0byAxNywgYnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzOiBQZXJjZW50YWdlcywgMjAwNC0yMDE4DQpUYWJsZSAxMS4zQSAgICAgICB8IE1ham9yIERlcHJlc3NpdmUgRXBpc29kZSB3aXRoIFNldmVyZSBJbXBhaXJtZW50IGluIFBhc3QgWWVhciBhbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTcsIGJ5IERlbW9ncmFwaGljIENoYXJhY3RlcmlzdGljczogTnVtYmVycyBpbiBUaG91c2FuZHMsIDIwMDYtMjAxOA0KVGFibGUgMTEuM0IgICAgICAgfCBNYWpvciBEZXByZXNzaXZlIEVwaXNvZGUgd2l0aCBTZXZlcmUgSW1wYWlybWVudCBpbiBQYXN0IFllYXIgYW1vbmcgUGVyc29ucyBBZ2VkIDEyIHRvIDE3LCBieSBEZW1vZ3JhcGhpYyBDaGFyYWN0ZXJpc3RpY3M6IFBlcmNlbnRhZ2VzLCAyMDA2LTIwMTgNClRhYmxlIDExLjRBICAgICAgIHwgUmVjZWlwdCBvZiBUcmVhdG1lbnQgZm9yIERlcHJlc3Npb24gaW4gUGFzdCBZZWFyIGFtb25nIFBlcnNvbnMgQWdlZCAxMiB0byAxNyB3aXRoIE1ham9yIERlcHJlc3NpdmUgRXBpc29kZSBpbiBQYXN0IFllYXIsIGJ5IERlbW9ncmFwaGljIENoYXJhY3RlcmlzdGljczogTnVtYmVycyBpbiBUaG91c2FuZHMsIDIwMDQtMjAxOA0KVGFibGUgMTEuNEIgICAgICAgfCBSZWNlaXB0IG9mIFRyZWF0bWVudCBmb3IgRGVwcmVzc2lvbiBpbiBQYXN0IFllYXIgYW1vbmcgUGVyc29ucyBBZ2VkIDEyIHRvIDE3IHdpdGggTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlIGluIFBhc3QgWWVhciwgYnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzOiBQZXJjZW50YWdlcywgMjAwNC0yMDE4DQoNCk9LLCBzbyB0aGUgbmV4dCB0YWJsZSAoVGFibGUxMS4xQikgaXMgdmVyeSBzaW1pbGFyIHRvIFRhYmxlMTEuMUEsIHdoaWxlIHRoZSByZW1haW5pbmcgdGFibGVzIGhhdmUgaW5mb3JtYXRpb24gYWJvdXQgZGVtb2dyYXBoaWNzLg0KDQpBcyBhIHJlbWluZGVyIGhlcmUgYXJlIGFsbCBvZiB0aGUgc3RlcHMgdGhhdCB3ZSBwZXJmb3JtZWQgdG8gd3JhbmdsZSBgdGFibGUxMS4xYWA6DQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQp0YWJsZTExLjFhICU8PiUNCiMgbWFrZSB0aGUgdGFibGUgaW50byBhIHRpYmJsZQ0KICBkcGx5cjo6YXNfdGliYmxlKCkgJT4lDQojIHJlbW92ZSB0aGUgbGFzdCByb3cgYnkgb25seSBrZWVwaW5nIHRoZSBmaXJzdCB0aHJvdWdoIHRoZSBzZWNvbmQgdG8gbGFzdA0KICBzbGljZSgxOihuKCkgLSAxKSkgJT4lDQojIG1ha2UgdGhlICJuYyIgdmFsdWVzICJOQSIgaW5zdGVhZA0KICBkcGx5cjo6bmFfaWYoIm5jIikgJT4lDQogIGRwbHlyOjpuYV9pZigiLS0iKSAlPiUNCiAgZHBseXI6Om5hX2lmKCIiKSAlPiUNCiAgZHBseXI6Om5hX2lmKCIqIikgJT4lIA0KIyByZW5hbWUgdGhlIGNvbHVtbiB0byB0aGUgc2hvcnRlciBNSFNfc2V0dGluZyBuYW1lDQogIGRwbHlyOjpyZW5hbWUoTUhTX3NldHRpbmcgPSANCiAgICAgICAgICAgICAgICAgIGBTZXR0aW5nIFdoZXJlIE1lbnRhbCBIZWFsdGggU2VydmljZVdhcyBSZWNlaXZlZGApICU+JQ0KIyByZW1vdmUgbnVtYmVycywgY2FycmlhZ2UgcmV0dXJuLCBuZXcgbGluZXMsIGFuZCBwdW5jdHVhdGlvbiBtYXJrcyBmcm9tIHRoZSB2YWx1ZXMgZm9yIHRoZSBNSFNfc2V0dGluZyBjb2x1bW4NCiAgbXV0YXRlKE1IU19zZXR0aW5nID0gDQogICAgICAgICBzdHJfcmVtb3ZlX2FsbChzdHJpbmcgPSBNSFNfc2V0dGluZywgDQogICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiWzpkaWdpdDpdfFxyXG58WzpwdW5jdDpdfCIpKSAlPiUNCiMgcmVwbGFjZSB0aGUgd2hpdGUgc3BhY2VzIHdpdGggYSBzaW5nbGUgc3BhY2UNCiAgbXV0YXRlKE1IU19zZXR0aW5nID0gDQogICAgICAgICBzdHJfcmVwbGFjZV9hbGwoc3RyaW5nID0gTUhTX3NldHRpbmcsDQogICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIls6Ymxhbms6XXsxLH0iLCANCiAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiICIpKSAlPiUNCiMgcmVtb3ZlICJhIiBhbmQgY29tbWFzIGZyb20gdGhlIHZhbHVlcyBpbiB0aGUgY29sdW1ucyBleGNlcHQgdGhlIGNvbHVtbiBjYWxsZWQgTUhTX3NldHRpbmcNCiAgbXV0YXRlKGRwbHlyOjphY3Jvc3MoLmNvbHMgPSAtTUhTX3NldHRpbmcsDQogICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwsICJhfCwiKSkgJT4lDQojIG1ha2UgdGhvc2UgY29sdW1ucyBudW1lcmljDQogIG11dGF0ZShhY3Jvc3MoLU1IU19zZXR0aW5nLCBhcy5udW1lcmljKSkgJT4lDQojIGNyZWF0ZSBhIG5ldyB0eXBlIGNvbHVtbiB3aXRoIHRoZSB2YWx1ZXM6ICJTcGVjaWFsdHkgcmVwZWF0ZWQgOSB0aW1lcyBmb2xsb3dlZCBieSAiTm9uc3BlY2lhbHR5IiByZXBlYXRlZCAxMSB0aW1lcw0KICBtdXRhdGUodHlwZSA9IGMocmVwKCJTcGVjaWFsdHkiLCA5KSwgcmVwKCJOb25zcGVjaWFsdHkiLCAxMSkpKSAlPiUNCiMgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBzdWJ0eXBlIA0KICBtdXRhdGUoc3VidHlwZSA9YygiU3BlY2lhbHR5X3RvdGFsIiwgDQogICAgICAgICAgICAgICAgICAgIHJlcCgiT3V0cGF0aWVudCIsIDUpLCANCiAgICAgICAgICAgICAgICAgICAgcmVwKCJJbnBhdGllbnQiLCAzKSwgDQogICAgICAgICAgICAgICAgICAgICJOb25zcGVjaWFsdHlfdG90YWwiLCANCiAgICAgICAgICAgICAgICAgICAgcmVwKCJFZHVjYXRpb24iLCAzKSwgDQogICAgICAgICAgICAgICAgICAgIHJlcCgiR2VuZXJhbF9tZWRpY2luZSIsIDIpLA0KICAgICAgICAgICAgICAgICAgICByZXAoIkp1dmVuaWxlX0p1c3RpY2UiLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgcmVwKCJDaGlsZF9XZWxmYXJlIiwgMiksIA0KICAgICAgICAgICAgICAgICAgICAiY29tYmluYXRpb24iKSkgJT4lDQojIGNyZWF0ZSBhIG5ldyB2YXJpYWJlbCBjYWxsZWQgc2hvcnRfbGFiZWwNCiAgbXV0YXRlKHNob3J0X2xhYmVsID0gYygiU3BlY2lhbHR5IHRvdGFsIiwgIk91dHBhdGllbnQgdG90YWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJUaGVyYXBpc3QiLCAiQ2xpbmljIiwgIkRheSBwcm9ncmFtIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIkluLWhvbWUgVGhlcmFwaXN0IiwgIklucGF0aWVudCB0b3RhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIkhvc3BpdGFsIiwgIlJlc2lkZW50aWFsIENlbnRlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIk5vbnNwZWNpYWx0eSB0b3RhbCIsICJTY2hvb2wgdG90YWwiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAiU2Nob29sIFRoZXJhcGlzdCIsICJTY2hvb2wgUHJvZ3JhbSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICJHZW5lcmFsIE1lZGljaW5lIiwgIkZhbWlseSBEciIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICJKdXN0aWNlIFN5c3RlbSIsICJKdXN0aWNlIFN5c3RlbSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIldlbGZhcmUiLCAiRm9zdGVyY2FyZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICJTcGVjaWFsdHkgQ29tYmluYXRpb24iKSkgJT4lDQojIHJlbW92ZSByb3dzIHdpdGggR2VuZXJhbF9NZWRpY2luZSBhcyB0aGUgdmFsdWUgaW4gdGhlIE1IU19zZXR0aW5nIGNvbHVtbiBiZWNhdXNlIGl0IGlzIGVtcHR5DQogIGRwbHlyOjpmaWx0ZXIoTUhTX3NldHRpbmcgIT0gIkdlbmVyYWxfTWVkaWNpbmUiKSAlPiUNCiMgcmVtb3ZlIHJvd3Mgd2l0aCBKdXZlbmlsZV9KdXN0aWNlIGFzIHRoZSB2YWx1ZSBpbiB0aGUgTUhTX3NldHRpbmcgY29sdW1uIGJlY2F1c2UgaXQgaXMgZW1wdHkNCiAgZHBseXI6OmZpbHRlcihNSFNfc2V0dGluZyAhPSAiSnV2ZW5pbGVfSnVzdGljZSIpICU+JQ0KIyByZW1vdmUgcm93cyB3aXRoIENoaWxkX1dlbGZhcmUgYXMgdGhlIHZhbHVlIGluIHRoZSBNSFNfc2V0dGluZyBjb2x1bW4gYmVjYXVzZSBpdCBpcyBlbXB0eQ0KICBkcGx5cjo6ZmlsdGVyKE1IU19zZXR0aW5nICE9ICJDaGlsZF9XZWxmYXJlIikgJT4lDQojIG1ha2UgdGhlIHRhYmxlIGluIGxvbmcgZm9ybWF0DQogICAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoIjIwIiksDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJOdW1iZXIiKSAlPiUNCiMgbWFrZSB0aGUgbmV3IFllYXIgdmFyaWFibGUgdG8gYmUgbnVtZXJpYw0KICAgbXV0YXRlKFllYXIgPSBhcy5udW1lcmljKFllYXIpKQ0KYGBgDQoNCk5vdyB3ZSB3YW50IHRvIHdyYW5nbGUgdGFibGUxMS4xQiB3aGljaCBpcyBmb3JtYXR0ZWQgdGhlIG1vc3Qgc2ltaWxhcmx5LiBUbyBkbyBzbyB3ZSBjYW4gc2ltcGx5IHJ1biB0aGVzZSBzdGVwcyBvbiB0aGUgdXNpbmcgdGhlIGB0YWJsZTExLjFCYCBhcyB0aGUgaW5wdXQuIEZvciB0aGUgc2FrZSBvZiBlZHVjYXRpb24sIGhvd2V2ZXIsIHdlIHdpbGwgc2hvdyB5b3UgaG93IHlvdSBjb3VsZCBtYWtlIGEgZnVuY3Rpb24gaWYgd2UgaGFkIHNldmVyYWwgbW9yZSBzaW1pbGFyIHRhYmxlcyB0byB3cmFuZ2xlLiBUaGlzIHdpbGwgYWxzbyBtYWtlIGl0IGVhc2llciB0byB3cml0ZSBhIGZ1bmN0aW9uIHRvIHdyYW5nbGUgdGhlIG90aGVyIGRlbW9ncmFwaGljIHRhYmxlcy4NCg0KTGFzdCB0aW1lIHdlIHdyb3RlIGEgZnVuY3Rpb24gaW4gdGhpcyBjYXNlIHN0dWR5LCB3ZSBvbmx5IGhhZCBvbmUgaW5wdXQgaW4gb3VyIGZ1bmN0aW9uLiBUaGlzIHRpbWUgd2Ugd2lsbCBoYXZlIHNldmVyYWwgaW5wdXRzLiBXZSB3aWxsIGhhdmUgdGhlIHRhYmxlIHRoYXQgd2Ugd2FudCB0byB3cmFuZ2xlIGFzIGBUQUJMRWAsIGEgbmV3IG5hbWUgZm9yIHRoZSBmaXJzdCBjb2x1bW4gY2FsbGVkIGBuZXdfY29sYCwgYW5kIGFuIGlucHV0IGNhbGxlZCBgcGl2b3RfY29sYCwgd2hpY2ggd2lsbCBiZSB0aGUgbmFtZSBvZiB0aGUgY29sdW1uIHRoYXQgd2lsbCBiZSBjcmVhdGVkIGFmdGVyIHBpdm90aW5nIHRoYXQgd2lsbCB0YWtlIHRoZSB2YWx1ZXMgZnJvbSBlYWNoIG9mIHRoZSB5ZWFycy4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpmdW5jdGlvbihUQUJMRSwgbmV3X2NvbCwgcGl2b3RfY29sKXsNCiAgICA8YWRkIGNvZGUgaGVyZT4gDQogIH0NCmBgYA0KDQpXZSB3YW50IHRvIG1ha2Ugb3VyIGZ1bmN0aW9uIGZsZXhpYmxlIHNvIHRoYXQgaXQgY2FuIHRha2UgYW55IHZhbHVlIGZvciB0aGUgbmFtZSBvZiB0aGUgZmlyc3QgY29sdW1uLiBUbyBzZWxlY3QgdGhlIGZpcnN0IGNvbHVtbiB3ZSB3aWxsIHVzZSB0aGlzIGZvbGxvd2luZyBjb2RlLCB3aGVyZSB0aGUgYmFzZSBgbmFtZXMoKWAgZnVuY3Rpb24gZ2V0cyB0aGUgY29sdW1uIG5hbWVzIG9mIHRoZSBgVEFCTEVgIGlucHV0ICwgd2hpY2ggaXMgaW5kaWNhdGVkIGJ5IHRoZSBgLmAgYW5kIHRoZW4gdG8gZ2V0IGp1c3QgdGhlIGZpcnN0IG5hbWUgdGhlIGBbMV1gIGlzIHVzZWQuDQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQpmdW5jdGlvbihUQUJMRSwgbmV3X2NvbCwgcGl2b3RfY29sKXsNCiAgZHBseXI6OmFzX3RpYmJsZShUQUJMRSkgJT4lDQogICNhZGRpdGlvbmFsIHN0ZXBzDQogIG5hbWVzKC4pWzFdDQogICNhZGRpdGlvbmFsIHN0ZXBzDQp9DQpgYGANCg0KQW5kIHRvIHJlbmFtZSB0aGUgd2l0aCB0aGUgYG5ld19jb2xgIGlucHV0IHRvIHRoZSBmdW5jdGlvbiB3ZSBjYW4gZG8gdGhpczoNCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCmZ1bmN0aW9uKFRBQkxFLCBuZXdfY29sLCBwaXZvdF9jb2wpew0KICBkcGx5cjo6YXNfdGliYmxlKFRBQkxFKSAlPiUNCiAgI2FkZGl0aW9uYWwgc3RlcHMNCiAgcmVuYW1lKHt7bmV3X2NvbH19IDo9IG5hbWVzKC4pWzFdKQ0KICAjYWRkaXRpb25hbCBzdGVwcw0KfQ0KYGBgDQoNClRoZSBkb3VibGUgY3VybHkgYnJhY2tldHMgYHt7fX1gIGFsbG93IHVzIHRvIHVzZSB0aGUgaW5wdXQgdG8gdGhlIGZ1bmN0aW9uIGNhbGxlZCBgbmV3X2NvbGAgd2l0aGluIHRoZSBmdW5jdGlvbi4NCg0KU2VlIFtoZXJlXShodHRwczovL2Fkdi1yLmhhZGxleS5uei9xdWFzaXF1b3RhdGlvbi5odG1sI3RpZHktZG90cyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGA6PWAgY29sb24tZXF1YWxzIG9wZXJhdG9yLiANClRoaXMgb3BlcmF0b3IgaXMgbW9yZSBmbGV4aWJsZSB0aGFuIHRoZSBub3JtYWwgYD1gLiBJdCBhbGxvd3MgZXhwcmVzc2lvbnMgb24gYm90aCBzaWRlcywgdGh1cyBpdCBhbGxvd3MgdXMgdG8gdXNlIGFuIGV4cHJlc3Npb24gKHRoZSB2YWx1ZXMgZm9yIGBuZXdfY29sYCkgYXMgdGhlIGlucHV0IHZhbHVlIHRvIHRoZSBleHByZXNzaW9ucyB0aGF0IGZvbGxvdyB0aGUgYDo9YCBvcGVyYXRvci4NCg0KV2Ugd2lsbCBhbHNvIGFkZCBjb2RlIHRvIHJlbW92ZSBhbGwgcm93cyB0aGF0IGhhdmUgb25seSBgTkFgIHZhbHVlcyBpbiBhIG1vcmUgZmxleGlibGUgd2F5LCBzbyB0aGF0IHdlIGRvbid0IG5lZWQgdG8ga25vdyB3aGF0IHJvd3MgYWhlYWQgb2YgdGltZS4NCg0KVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYGZpbHRlcigpYCBhbmQgYHNlbGVjdCgpYCBmdW5jdGlvbnMgb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gDQoNCldlIHdpbGwgY2FsY3VsYXRlIGEgc3VtIG9mIHRoZSBjb3VudCBvZiBgTkFgIHZhbHVlcyBhY3Jvc3MgdGhlIHJvd3MgZm9yIHRoZSBjb2x1bW5zIGZvciBlYWNoIHllYXIgdXNpbmcgdGhlIGJhc2UgYHJvd1N1bXMoKWAgZnVuY3Rpb24gbGlrZSBzbzoNCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCnJvd1N1bXMoaXMubmEoLikpDQpgYGANCg0KSG93ZXZlciB0byBkbyB0aGlzIHdlIGZpcnN0IG5lZWQgdG8gc2VsZWN0IG9ubHkgdGhlIGNvbHVtbnMgdGhhdCBhcmUgbnVtZXJpYyB1c2luZzogYHNlbGVjdCguLCBpcy5udW1lcmljKWAsIHdoZXJlIHRoZSBgLmAgcmVmZXJzIHRvIHRoZSB0YWJsZSBhZnRlciBhbGwgdGhlIHByZXZpb3VzIHdyYW5nbGluZyBzdGVwcyBpbiBvdXIgZnVuY3Rpb24uIEltcG9ydGFudGx5IG9mIGNvdXJzZSwgdGhpcyBhbGwgbmVlZHMgdG8gaGFwcGVuIGFmdGVyIHdlIGNvbnZlcnQgdGhlIHZhbHVlcyBmb3IgZWFjaCB5ZWFyIHRvIG51bWVyaWMuDQoNCkFueXdheSwgYWx0b2dldGhlciB0aGlzIGxvb2tzIGxpa2UgdGhpczogDQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQpyb3dTdW1zKGlzLm5hKHNlbGVjdCguLCBpcy5udW1lcmljKSkpYC4NCmBgYA0KDQpGaW5hbGx5LCB3ZSBjb21wYXJlIHRoaXMgdG8gdGhlIG51bWJlciBvZiBjb2x1bW5zIHRoYXQgYXJlIG51bWVyaWMgYnkgdXNpbmc6IGBsZW5ndGgoc2VsZWN0KC4sIGlzLm51bWVyaWMpKSlgLCB3aXRoIHRoZSBpZGVhIHRoYXQgaWYgdGhlIG51bWJlciBvZiBgTkFgIHZhbHVlcyBpcyBsZXNzIHRoYW4gdGhlIG51bWJlciBvZiBjb2x1bW5zIHRoYXQgY291bGQgaGF2ZSBgTkFgIHZhbHVlcywgdGhlbiB3ZSBrbm93IGl0IGlzIG5vdCBhbiBlbXB0eSByb3cuDQoNCk92ZXJhbGwsIHRoaXMgd291bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzIGFmdGVyIHdlIHBlcmZvcm0gYSBzdGVwIHRvIGNvbnZlcnQgdGhlIGNvbHVtbnMgdG8gYmUgbnVtZXJpYyBsaWtlIHdlIGRpZCBiZWZvcmU6DQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQpmdW5jdGlvbihUQUJMRSwgbmV3X2NvbCwgcGl2b3RfY29sKXsNCiAgIyBwcmV2aW91cyBzaW1pbGFyIHN0ZXBzIHRvIG1vZGlmeSBhbmQgbWFrZSB0YWJsZSB2YWx1ZXMgbnVtZXJpYw0KICAgIGZpbHRlcihyb3dTdW1zKGlzLm5hKHNlbGVjdCguLCBpcy5udW1lcmljKSkpIDwgDQogICAgICAgICAgICAgbGVuZ3RoKHNlbGVjdCguLCBpcy5udW1lcmljKSkpIA0KICB9DQogIA0KYGBgDQoNCk5vdGUgdGhhdCBpZiB3ZSB3ZXJlIHVzaW5nIHRoZSBgc3VtbWFyaXplKClgIG9yIGBtdXRhdGUoKWAgZnVuY3Rpb24gb3IgdGhlIGBkcGx5cmAgcGFja2FnZSwgdGhlbiB3ZSBjb3VsZCB1c2UgdGhlIGBhY3Jvc3MoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBzZWxlY3Qgd2hhdCBjb2x1bW5zIHdlIHdhbnRlZCB0byB1c2UgaW4gb3VyIGNhbGN1bGF0aW9uLg0KDQoNCk9LLCBzbyBwdXR0aW5nIGV2ZXJ5dGhpbmcgdG9nZXRoZXIgZnJvbSB3aGF0IHdlIGRpZCBwcmV2aW91c2x5IGZvciBgdGFibGUxMS4xYWAgYW5kIHRoZXNlIG5ldyBmbGV4aWJsZSBzdGVwcyB3ZSBjYW4gY3JlYXRlIHRoaXMgZnVuY3Rpb246DQoNCmBgYHtyfQ0KZGF0YV9wcmVwX3NldHRpbmdzIDwtIGZ1bmN0aW9uKFRBQkxFLCBuZXdfY29sLCBwaXZvdF9jb2wpew0KIyBtYWtlIHRoZSB0YWJsZSBhIHRpYmJsZQ0KICBkcGx5cjo6YXNfdGliYmxlKFRBQkxFKSAlPiUNCiMgcmVtb3ZlIHRoZSBsYXN0IHJvdw0KICAgIHNsaWNlKDE6KG4oKSAtIDEpKSAlPiUNCiMgbWFrZSAibmMiIHZhbHVlcyBOQSBldGMuDQogICAgbmFfaWYoIm5jIikgJT4lDQogICAgbmFfaWYoIi0tIikgJT4lDQogICAgbmFfaWYoIiIpICU+JQ0KICAgIG5hX2lmKCIqIikgJT4lIA0KIyByZW5hbWUgdGhlIGZpcnN0IGNvbHVtbiAobmFtZXMoLilbMV0pIHRvIGJlIHdoYXQgd2FzIHNwZWNpZmllZCB3aXRoIHRoZSBuZXdfY29sIGFyZ3VtZW50DQogICAgcmVuYW1lKHt7bmV3X2NvbH19IDo9IG5hbWVzKC4pWzFdKSAlPiUNCiMgcmVtb3ZlIHRoZSBudW1iZXJzIGFuZCBwdW5jdHVhdGlvbiBtYXJrcyBhbmQgY2FycmlhZ2UgcmV0dXJucyAoXHIpIGFuZCBuZXcgbGluZXMgKFxuKSBmcm9tIHRoZSBmaXJzdCBjb2x1bW4NCiAgICBtdXRhdGUoe3tuZXdfY29sfX0gOj0gDQogICAgICAgIHN0cl9yZW1vdmVfYWxsKHN0cmluZyA9IHB1bGwoLiwge3tuZXdfY29sfX0pLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiWzpkaWdpdDpdfFxyXG58WzpwdW5jdDpdfCIpKSAlPiUNCiMgcmVwbGFjZSB3aGl0ZSBzcGFjZXMgd2l0aCBhIHNpbmdsZSBzcGFjZQ0KICAgIG11dGF0ZSh7e25ld19jb2x9fSA6PSANCiAgICAgICAgc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9cHVsbCguLCB7e25ld19jb2x9fSksDQogICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJbOmJsYW5rOl17MSx9IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiICIpKSAlPiUNCiMgcmVtb3ZlICJhIiBhbmQgLCBmcm9tIHRoZSB2YWx1ZXMgZm9yIHRoZSBjb2x1bW5zIHRoYXQgYXJlIG5vdCB0aGUgZmlyc3QgY29sdW1uIChjYWxsZWQgbmV3X2NvbCkNCiAgICBtdXRhdGUoZHBseXI6OmFjcm9zcyguY29scyA9IC17e25ld19jb2x9fSwNCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwsICJhfCwiKSkgJT4lDQojIG1ha2UgdGhlc2UgY29sdW1ucyBudW1lcmljICAoYWxsIHRoZSBjb2x1bW5zIGJ1dCB0aGUgZmlyc3QgY29sdW1uKQ0KICAgIG11dGF0ZShhY3Jvc3MoLXt7bmV3X2NvbH19LCBhcy5udW1lcmljKSkgJT4lDQojIG1ha2UgYSBuZXcgdmFyaWFibGUgY2FsbGVkIHR5cGUgd2l0aCA5IHZhbHVlcyB0aGF0IGFyZSBTcGVjaWFsdHkgZm9sbG93ZWQgYnkgMTEgdmFsdWVzIG9mIE5vbnNwZWNpYWx0eQ0KICAgIG11dGF0ZSh0eXBlID0gYyhyZXAoIlNwZWNpYWx0eSIsIDkpLCByZXAoIk5vbnNwZWNpYWx0eSIsIDExKSkpICU+JQ0KIyBtYWtlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBzdWJ0eXBlIHdpdGggdGhlIGZvbGxvd2luZyB2YWx1ZXMgcmVwZWF0ZWQgdmFyaW91cyB0aW1lcw0KICAgIG11dGF0ZShzdWJ0eXBlID0gYygiU3BlY2lhbHR5X3RvdGFsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJPdXRwYXRpZW50IiwgNSksDQogICAgICAgICAgICAgICAgICAgICAgIHJlcCgiSW5wYXRpZW50IiwgMyksDQogICAgICAgICAgICAgICAgICAgICAgICJOb25zcGVjaWFsdHlfdG90YWwiLA0KICAgICAgICAgICAgICAgICAgICAgICByZXAoIkVkdWNhdGlvbiIsIDMpLA0KICAgICAgICAgICAgICAgICAgICAgICByZXAoIkdlbmVyYWxfbWVkaWNpbmUiLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJKdXZlbmlsZV9KdXN0aWNlIiwgMiksDQogICAgICAgICAgICAgICAgICAgICAgIHJlcCgiQ2hpbGRfV2VsZmFyZSIsIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAiY29tYmluYXRpb24iKSkgJT4lIA0KIyBtYWtlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBzaG9ydF9sYWJlbCB0byB1c2UgYXMgbGFiZWxzIGZvciBwbG90cyBmb3IgdGhlIGRhdGENCiAgICBtdXRhdGUoc2hvcnRfbGFiZWwgPSBjKCJTcGVjaWFsdHkgdG90YWwiLCAiT3V0cGF0aWVudCB0b3RhbCIsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJUaGVyYXBpc3QiLCAiQ2xpbmljIiwgIkRheSBwcm9ncmFtIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiSW4taG9tZSBUaGVyYXBpc3QiLCAiSW5wYXRpZW50IHRvdGFsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJIb3NwaXRhbCIsICJSZXNpZGVudGlhbCBDZW50ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbnNwZWNpYWx0eSB0b3RhbCIsICJTY2hvb2wgdG90YWwiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTY2hvb2wgVGhlcmFwaXN0IiwgIlNjaG9vbCBQcm9ncmFtIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiR2VuZXJhbCBNZWRpY2luZSIsICJGYW1pbHkgRHIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJKdXN0aWNlIFN5c3RlbSIsICJKdXN0aWNlIFN5c3RlbSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlbGZhcmUiLCAiRm9zdGVyY2FyZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNwZWNpYWx0eSBDb21iaW5hdGlvbiIpKSAlPiUNCiMgcmVtb3ZlIHJvd3Mgd2VyZSBhbGwgdGhlIHZhbHVlcyBhcmUgTkEgLSANCiMgdGhlIG51bWJlciBvZiBgTkFgIHZhbHVlcyBmb3IgYSByb3cgc2hvdWxkIGJlIGxlc3MgdGhhbiB0aGUgbnVtYmVyIG9mIGNvbHVtbnMgdGhhdCBjb3VsZCBoYXZlIGBOQWAgdmFsdWVzDQogIGZpbHRlcihyb3dTdW1zKGlzLm5hKHNlbGVjdCguLCBpcy5udW1lcmljKSkpIDwNCiAgICAgICAgICAgbGVuZ3RoKHNlbGVjdCguLCBpcy5udW1lcmljKSkpICU+JQ0KIyBtYWtlIHRoZSB0YWJsZSBpbnRvIGxvbmcgZm9ybWF0IHNvIHRoYXQgdGhlIHllYXIgY29sdW1ucyBhcmUgY29sbGFwc2VkIHRvZ2V0aGVyIA0KIyB0aGUgbmV3IHZhbHVlIGNvbHVtbiBpcyBjYWxsZWQgd2hhdCB3YXMgc3BlY2lmaWVkIHdpdGggdGhlICJwaXZvdF9jb2wiIGFyZ3VtZW50DQogIHBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoIjIwIiksDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwgDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSBwaXZvdF9jb2wpJT4lDQojIG1ha2UgdGhlIG5ldyAiWWVhciIgdmFyaWFibGUgbnVtZXJpYw0KICBtdXRhdGUoWWVhciA9IGFzLm51bWVyaWMoWWVhcikpDQp9DQpgYGANCg0KTm93IHdlIGNhbiBhcHBseSB0aGUgZnVuY3Rpb24gdG8gYHRhYmxlMTEuMWJgLg0KDQojIyMgKipUYWJsZTExLjFiKioNCioqKg0KDQpgYGB7cn0NCnRhYmxlMTEuMWIgPC0gDQogIGRhdGFfcHJlcF9zZXR0aW5ncyhUQUJMRSA9IHRhYmxlMTEuMWIsIA0KICAgICAgICAgICAgICAgICAgICAgbmV3X2NvbCA9ICJNSFNfc2V0dGluZyIsDQogICAgICAgICAgICAgICAgICAgICBwaXZvdF9jb2wgPSAiUGVyY2VudCIpDQoNCmhlYWQodGFibGUxMS4xYikNCmBgYA0KDQpOb3cgd2UgaGF2ZSB0aWR5IGRhdGEgYWJvdXQgdGhlIGNvdW50cyBhbmQgcGVyY2VudGFnZXMgb2Ygd2hlcmUgeW91dGhzLCB3aG8gZXhwZXJpZW5jZWQgYSBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGUsIHJlY2VpdmVkIHRyZWF0bWVudCBmb3IgZGVwcmVzc2lvbi4NCg0KV2hhdCBhYm91dCB0aGUgc3Vic2VxdWVudCB0YWJsZXM/DQoNCg0KIyMjICoqRGVtb2dyYXBoaWMgVGFibGVzKioNCioqKg0KDQpBbGwgb2YgdGhlIHJlc3Qgb2YgdGhlIHRhYmxlcyBoYXZlIGRlbW9ncmFwaGljIGluZm9ybWF0aW9uIGFuZCBoYXZlIHRoaXMgZ2VuZXJhbCBzdHJ1Y3R1cmU6DQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImRlbV90YWJsZS5wbmciKSkNCmBgYA0KDQpJbiB0aGVzZSB0YWJsZXMsIHdlIGhhdmUgYWdlIGdyb3VwcyBpbiBvdXIgZmlyc3QgY29sdW1uIHNvIHdlIGRvbid0IHdhbnQgdG8gcmVtb3ZlIGRpZ2l0cyBvciBwdW5jdHVhdGlvbiBtYXJrcyBhbnltb3JlIHNvIHdlIG5lZWQgdG8gbW9kaWZ5IG91ciBmdW5jdGlvbiBhIGJpdCB0byByZW1vdmUgdGhhdCBzdGVwLiANCg0KV2UgYWxzbyB3YW50IHRvIGFkZCB0aGUgd29yZCBgQWdlYCBhbmQgYW4gdW5kZXJzY29yZSBpbiBmcm9udCBvZiB0aGUgYWdlIGdyb3VwIGxpc3RlZCBpbiB0aGUgdGFibGVzLg0KV2UgY2FuIHVzZSB0aGUgYHN0cl9yZXBsYWNlKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZSwgYmVjYXVzZSBub3cgd2Ugd2FudCB0byBvbmx5IHJlcGxhY2UgdGhlIGZpcnN0IGluc3RhbmNlIG9mIGAxYCB3aXRoIGBBZ2U6IDFgLg0KDQpXZSB3aWxsIHJlcGxhY2UgdGhlIGZpcnN0IGNvbHVtbiBuYW1lIHdpdGggYERlbW9ncmFwaGljYCBmb3IgYWxsIG9mIHRoZSB0YWJsZXMuDQoNCldlIHdpbGwgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIHRoYXQgbGlzdCB0aGUgc3ViZ3JvdXBzLg0KDQpXZSB3aWxsIGFsc28gd2FudCB0byBvbmx5IHdyYW5nbGUgdGhlIGRhdGEgdXAgdG8gdGhlIHBvaW50IHRoYXQgd2UgY2hhbmdlIHRoZSBzaGFwZSBvZiB0aGUgZGF0YSwgc28gdGhhdCB3ZSBjYW4gY2hlY2sgaG93IHRoZSBkYXRhIGxvb2tzIGZpcnN0Lg0KDQpPSyBsZXQncyBwdXQgdGhpcyBhbGwgdG9nZXRoZXIgaW50byBhIGBkYXRhX2RlbV9zZXR0aW5ncygpYCBmdW5jdGlvbjogDQoNCmBgYHtyfQ0KZGF0YV9kZW1fc2V0dGluZ3MgPC0gZnVuY3Rpb24oVEFCTEUpew0KICAjIG1ha2UgdGhlIHRhYmxlIGEgdGliYmxlDQogIGRwbHlyOjphc190aWJibGUoVEFCTEUpICU+JQ0KICAjIFJlbW92ZSB0aGUgbGFzdCByb3cgLSBrZWVwIG9ubHkgdGhlIDFzdCB0aHJvdWdoIDJuZCB0byBsYXN0IHJvd3MNCiAgc2xpY2UoMToobigpLTEpKSAlPiUNCiAgIyBjaGFuZ2UgdGhlIHZhbHVlcyBmcm9tICJuYywgLS0iIGV0YyB0byBOQQ0KICBuYV9pZigibmMiKSAlPiUNCiAgbmFfaWYoIi0tIikgJT4lDQogIG5hX2lmKCIiKSAlPiUNCiAgbmFfaWYoIioiKSAlPiUNCiAgIyByZW5hbWUgdGhlIGZpcnN0IGNvbHVtbiB0byBiZSAiRGVtb2dyYXBoaWMiDQogIHJlbmFtZShEZW1vZ3JhcGhpYyA6PSBuYW1lcyguKVsxXSkgJT4lDQogICMgcmVwbGFjZSB3aGl0ZSBzcGFjZXMgZm9ybSB0aGUgdmFsdWVzIG9mIHRoZSAiRGVtb2dyYXBoaWMiIHZhcmlhYmxlIHdpdGggYSBzaW5nbGUgc3BhY2UNCiAgbXV0YXRlKERlbW9ncmFwaGljIDo9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBwdWxsKC4sIERlbW9ncmFwaGljKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIls6Ymxhbms6XXsxLH0iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIgIikpICU+JQ0KICAjIHJlcGxhY2UgdmFsdWVzIHdoZXJlIHRoZXJlIGlzIGEgIjEiIGluIHRoZSAiRGVtb2dyYXBoaWMiIHZhcmlhYmxlIHRvIGJlICJBZ2U6IDEiDQogIG11dGF0ZShEZW1vZ3JhcGhpYyA9IHN0cl9yZXBsYWNlKHN0cmluZyA9IERlbW9ncmFwaGljLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIkFnZTogMSIpKSAlPiUNCiAgIyBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIHN1Ymdyb3VwDQogIG11dGF0ZShzdWJncm91cCA9IGMoIlRvdGFsIiwgcmVwKCJBZ2UiLCA0KSwgDQogICAgICAgICAgICAgICAgICAgIHJlcCgiR2VuZGVyIiwgMyksIHJlcCgiUmFjZS9FdGhuaWNpdHkiLCA5KSkpICU+JQ0KICAjIHJlbW92ZSAiYSIgYW5kIGNvbW1hcyBmcm9tIHRoZSB2YXJpYWJsZXMgdGhhdCBoYXZlIGNvbHVtbiBuYW1lcyB3aXRoICIyMCIgaW4gdGhlbQ0KICBtdXRhdGUoZHBseXI6OmFjcm9zcyguY29scyA9IGNvbnRhaW5zKCIyMCIpLA0KICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbCwgImF8LCIpKSAlPiUNCiAgIyBtYWtlIHRoZSB2YXJpYWJsZXMgd2l0aCAiMjAiIGluIHRoZSBuYW1lcyAodGhlIHllYXIgdmFyaWFibGVzKSB0byBiZSBudW1lcmljDQogIG11dGF0ZShhY3Jvc3MoY29udGFpbnMoIjIwIiksIGFzLm51bWVyaWMpKSAlPiUNCiAgIyByZW1vdmUgZW1wdHkgcm93cyAtIHJvd3Mgd2VyZSB0aGUgbnVtYmVyIG9mIE5BIHZhbHVlcyBpcyBlcXVhbCB0byB0aGUgbnVtYmVyIG9mIG51bWVyaWMgY29sdW1ucw0KICBmaWx0ZXIocm93U3Vtcyhpcy5uYShzZWxlY3QoLiwgaXMubnVtZXJpYykpKSA8IGxlbmd0aChzZWxlY3QoLiwgaXMubnVtZXJpYykpKQ0KICB9DQpgYGANCg0KDQpOb3csIHdlIHVzZSB0aGUgYGRhdGFfZGVtX3NldHRpbmdzKClgIGZ1bmN0aW9uIHRvIHdyYW5nbGUgdGhlIG5leHQgc2V0IG9mIHRhYmxlcy4gDQpXZSB3aWxsIGFsc28gYWRkIGEgY29sdW1uIHRvIGRlc2NyaWJlIHdoYXQgdGhlIGRhdGEgYXJlIGFib3V0IHdoaWNoIHdpbGwgYmUgaGVscGZ1bCBmb3IgbWVyZ2luZyB0aGUgZGF0YSBsYXRlci4NCg0KYGBge3J9DQp0YWJsZTExLjJhIDwtIGRhdGFfZGVtX3NldHRpbmdzKFRBQkxFID0gdGFibGUxMS4yYSkNCnRhYmxlMTEuMmEgJTw+JSBtdXRhdGUoZGF0YV90eXBlID0gIk1ham9yX0RlcHJlc3NpdmVfRXBpc29kZSIpDQpoZWFkKHRhYmxlMTEuMmEpDQoNCnRhYmxlMTEuMmIgPC0gZGF0YV9kZW1fc2V0dGluZ3MoVEFCTEUgPSB0YWJsZTExLjJiKQ0KdGFibGUxMS4yYiAlPD4lIG11dGF0ZShkYXRhX3R5cGUgPSAiTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlIikNCmhlYWQodGFibGUxMS4yYikNCg0KdGFibGUxMS4zYSA8LSBkYXRhX2RlbV9zZXR0aW5ncyhUQUJMRSA9IHRhYmxlMTEuM2EpDQp0YWJsZTExLjNhICU8PiUgbXV0YXRlKGRhdGFfdHlwZSA9ICJTZXZlcmVfTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlIikNCmhlYWQodGFibGUxMS4zYSkNCg0KdGFibGUxMS4zYiA8LSBkYXRhX2RlbV9zZXR0aW5ncyhUQUJMRSA9IHRhYmxlMTEuM2IpDQp0YWJsZTExLjNiICU8PiUgbXV0YXRlKGRhdGFfdHlwZSA9ICJTZXZlcmVfTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlIikNCmhlYWQodGFibGUxMS4zYikNCg0KdGFibGUxMS40YSA8LSBkYXRhX2RlbV9zZXR0aW5ncyhUQUJMRSA9IHRhYmxlMTEuNGEpDQp0YWJsZTExLjRhICU8PiUgbXV0YXRlKGRhdGFfdHlwZSA9ICJUcmVhdG1lbnQiKQ0KaGVhZCh0YWJsZTExLjRhKQ0KDQp0YWJsZTExLjRiIDwtIGRhdGFfZGVtX3NldHRpbmdzKFRBQkxFID0gdGFibGUxMS40YikNCnRhYmxlMTEuNGIgJTw+JSBtdXRhdGUoZGF0YV90eXBlID0gIlRyZWF0bWVudCIpDQpoZWFkKHRhYmxlMTEuNGIpDQpgYGANCg0KR3JlYXQhIEFsbCBvZiB0aGUgZGVtb2dyYXBoaWMgdGFibGVzIGxvb2sgZ29vZC4NCg0KDQpJdCdzIGEgZ29vZCBpZGVhIHRvIHJlZ3VsYXJseSBjaGVjayB5b3VyIGRhdGEgdG8gbWFrZSBzdXJlIGl0IGlzIGFzIHlvdSBleHBlY3QuIA0KDQpOb3cgbGV0J3MgbWFrZSBhIGZ1bmN0aW9uIHRvIGNoZWNrIHRoYXQgb3VyIGRhdGEgaXMgYXMgd2UgZXhwZWN0LiBXZSBoYXZlIHF1aXRlIGEgZmV3IHRhYmxlcyB3aGljaCBjb3VsZCBtYWtlIHRoaXMgYSBiaXQgY2hhbGxlbmdpbmcsIGJ1dCB5b3UgbWlnaHQgZmluZCB5b3Vyc2VsZiBpbiBmdXR1cmUgaW4gYSBzaXR1YXRpb24gd2hlcmUgeW91IGhhdmUgbG90cyBvZiBkYXRhLCBhbmQgY2hlY2tpbmcgYnkgbG9va2luZyBhdCB0aGUgZGF0YSB3b3VsZCBub3QgYmUgZmVhc2libGUuICANCg0KRmlyc3QgbGV0J3MgbWFrZSBzdXJlIG91ciB0YWJsZXMgYXJlIHRpYmJsZXMgYnkgdXNpbmcgdGhlIGBpc190aWJibGUoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWJibGVgIHBhY2thZ2UuIFdlIGNhbiB1c2UgdGhlIGBjYXNlX3doZW4oKWAgZnVuY3Rpb24gdG8gZ2l2ZSB1cyBhIG1lc3NhZ2UgaWYgdGhlIHZhbHVlIGZvciB0aGUgYGlzX3RpYmJsZSgpYCBmdW5jdGlvbiBpcyBgVFJVRWAgLSB0aGlzIGlzIHRoZSBtZXNzYWdlIGFmdGVyIHRoZSBmaXJzdCBgfmAgYW5kIGEgZGlmZmVyZW50IG1lc3NhZ2UgZm9yIGFsbCBvdGhlciBjYXNlcyB1c2luZyBgVFJVRWAgZm9sbG93ZWQgYWdhaW4gYnkgYH5gIGFuZCBhIGhlbHBmdWwgbWVzc2FnZSBhYm91dCB0aGUgZGF0YS4gDQoNCmBgYHtyfQ0KZGF0YV9kZW1fY2hlY2sgPC0gZnVuY3Rpb24oVEFCTEUpew0KICAjIGNoZWNrIHRoYXQgdGhlIGRhdGEgaXMgYSB0aWJibGUNCiAgY2FzZV93aGVuKGlzX3RpYmJsZShUQUJMRSkgfiAiR29vZCEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJOb3QgYSB0aWJibGUiKQ0KfQ0KYGBgDQoNCk5vdyB3ZSB3aWxsIHRyeSB0aGlzIG9uIHNvbWUgZGF0YSB3ZSBrbm93IGlzIGZvciBzdXJlIGEgdGliYmxlICh0YWJsZTExLjFhKSBhbmQgZGF0YSB0aGF0IHdlIGtub3cgZm9yIHN1cmUgaXMgbm90Lg0KDQpgYGB7cn0NCnRlc3RfdGhhdF9zaG91bGRfZmFpbCA8LSBjKDEsMiwzKQ0KY2xhc3ModGVzdF90aGF0X3Nob3VsZF9mYWlsKQ0KY2xhc3ModGFibGUxMS4xYSkNCg0KZGF0YV9kZW1fY2hlY2sodGVzdF90aGF0X3Nob3VsZF9mYWlsKQ0KZGF0YV9kZW1fY2hlY2sodGFibGUxMS4xYSkNCmBgYA0KR3JlYXQhIGl0IGxvb2tzIGxpa2UgaXQncyB3b3JraW5nISBOb3cgd2Ugd2lsbCBjcmVhdGUgbW9yZSBmdW5jdGlvbnMgdG8gZG8gYWRkaXRpb25hbCBjaGVja3Mgb24gdGhlIGRhdGEuIA0KDQoqKioNCjxkZXRhaWxzPjxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggb2YgdGhlIGNoZWNrIGZ1bmN0aW9ucy4gPC9zdW1tYXJ5Pg0KDQpOZXh0IHdlIHdpbGwgY2hlY2sgdGhhdCB0aGUgbGVnZW5kIGhhcyBiZWVuIHJlbW92ZWQuIFRvIGRvIHRoaXMgd2Ugd2lsbCBtYWtlIHN1cmUgdGhhdCB0aGVyZSBhcmUgbm8gYC0tID0gbm90IGF2YWlsYWJsZWAgKGFzIHRoaXMgd2FzIHBhcnQgb2YgdGhlIGxlZ2VuZCkgaW4gdGhlIGxhc3Qgcm93IGJ5IHVzaW5nIGBzdHJfZGV0ZWN0KClgIHRvIGxvb2sgZm9yIGAtLT1gIGFuZCBgc2xpY2UobigpKWAgdG8gbG9vayBhdCB0aGUgbGFzdCByb3cgc3BlY2lmaWNhbGx5LiANCg0KRmlyc3QgbGV0J3MgdGFrZSBhIGxvb2sgYWdhaW4gYXQgd2hhdCB0aGUgbGVnZW5kIGxvb2tlZCBsaWtlOg0KDQpgYGB7cn0NCmxlZ2VuZA0KYGBgDQoNCmBgYHtyfQ0KDQpkYXRhX2RlbV9jaGVjayA8LSBmdW5jdGlvbihUQUJMRSl7DQogICMgY2hlY2sgdGhhdCB0aGUgbGFzdCByb3cgZG9lcyBub3QgY29udGFpbiAiLS0iIGJ5Li4NCiAgICNmaXJzdCBncmFiYmluZyBvbmx5IHRoZSBsYXN0IHJvdw0KICAgI3B1bGxpbmcgb25lIG9mIHRoZSB5ZWFycw0KICBjYXNlX3doZW4oVEFCTEUgJT4lIHNsaWNlKG4oKSkgJT4lIHB1bGwoYDIwMThgKSAlPiUNCiAgIyBpZiBpdCBpcyBkZXRlY3RlZCBwcmludCANCiAgICAgICAgICAgIHN0cl9kZXRlY3QocGF0dGVybiA9ICItLSA9IG5vdCBhdmFpbGFibGUiKSAgfiAiTGVnZW5kIG1pZ2h0IHN0aWxsIGJlIHRoZXJlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiR29vZCEiKQ0KfQ0KDQpkYXRhX2RlbV9jaGVjayh0YWJsZTExLjRhKQ0KYGBgDQoNCg0KTm93IHdlIHdpbGwgcHV0IHRoZXNlIHRvZ2V0aGVyIGluIGEgbmV3IHRpYmJsZToNCmBgYHtyfQ0KDQpkYXRhX2RlbV9jaGVjayA8LSBmdW5jdGlvbihUQUJMRSl7DQp0aWJibGUodGliYmxlX2NoZWNrID0gY2FzZV93aGVuKGlzX3RpYmJsZSh0YWJsZTExLjRhKSB+ICJHb29kISIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJOb3QgYSB0aWJibGUiKSwNCiAgICAgICBsZWdlbmRfY2hlY2sgPSBjYXNlX3doZW4odGFibGUxMS40YSAlPiUgc2xpY2UobigpKSAlPiVwdWxsKGAyMDA0YCkgJT4lDQogICAjIGlmIGl0IGlzIGRldGVjdGVkIHByaW50IA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KHBhdHRlcm4gPSAiLS0iKSAgfiAiTGVnZW5kIG1pZ2h0IHN0aWxsIGJlIHRoZXJlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkdvb2QhIikpDQp9DQoNCmRhdGFfZGVtX2NoZWNrKHRhYmxlMTEuNGEpDQpgYGANCg0KTm90ZSBoZXJlIHRoYXQgd2Ugd2lsbCBtYWtlIGFsbCBvZiB0aGUgcG9zaXRpdmUgY2hlY2tzIGhhdmUgdGhlIHNhbWUgdmFsdWUgb2YgYEdvb2QhYC4gVGhpcyB3aWxsIGFsbG93IHVzIHRvIG1ha2UgYW4gb3ZlcmFsbCBjaGVjayBsYXRlciB0aGF0IGFsbCBvZiB0aGUgY2hlY2tzIHBhc3NlZC4gDQoNCk5vdyB3ZSB3aWxsIHdyaXRlIGEgZnVuY3Rpb24gdG8gY2hlY2sgaWYgYW55IG9mIHRoZSB2YWx1ZXMgdGhhdCB3ZXJlIGBuY2AsYCpgLCBgLS1gICwgb3IgdGhleSBnb3QgY29udmVydGVkIHRvIGBOQWAuIFdlIGNhbiBjaGVjayBmb3IgdGhlIHByZXNlbmNlIG9mIGEgdmFsdWUgaW4gZW50aXJlIHRpYmJsZSB1c2luZyB0aGUgYmFzZSBgYW55KClgIGZ1bmN0aW9uLg0KDQpgYGB7cn0NCmRhdGFfZGVtX2NoZWNrIDwtIGZ1bmN0aW9uKFRBQkxFKXsNCiAgY2FzZV93aGVuKGFueShzdHJfZGV0ZWN0KFRBQkxFLCBwYXR0ZXJuID0gIm5jfFxcKnwtLSIpKSANCiAgIyBpZiBpdCBpcyBkZXRlY3RlZCwgcHJpbnQgdGhpczoNCiAgICAgICAgIH4gIk5BIG5vdCBmaXhlZCIsDQogICMgaWYgbm90IGRldGVjdGVkLCBwcmludCB0aGlzOg0KICAgIFRSVUUgfiAiR29vZCEiKQ0KfQ0KDQoNCmRhdGFfZGVtX2NoZWNrKHRhYmxlMTEuNGEpDQpgYGANCg0KDQpOb3cgd2Ugd2lsbCBjaGVjayB0aGF0IHRoZSBmaXJzdCB2YXJpYWJsZSBpcyBjYWxsZWQgIkRlbW9ncmFwaGljIi4NCg0KYGBge3J9DQpkYXRhX2RlbV9jaGVjayA8LSBmdW5jdGlvbihUQUJMRSl7DQogIGNhc2Vfd2hlbihuYW1lcyhUQUJMRSlbMV0gPT0gIkRlbW9ncmFwaGljIiB+ICJHb29kISIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJjaGVjayBmaXJzdCBjb2x1bW4iKQ0KICB9DQoNCmRhdGFfZGVtX2NoZWNrKHRhYmxlMTEuNGEpDQpgYGANCg0KTm93IGxldCdzIGNoZWNrIHRoYXQgdGhlcmUgYXJlIG5vIHdoaXRlIHNwYWNlcyBsYXJnZXIgdGhhbiBvbmUgc3BhY2UuIFdlIGNhbiB1c2UgYFs6Ymxhbms6XXsyLH1gIHRvIGluZGljYXRlIHR3byBvciBtb3JlIHdoaXRlIHNwYWNlcy4gDQoNCmBgYHtyfQ0KZGF0YV9kZW1fY2hlY2sgPC0gZnVuY3Rpb24oVEFCTEUpew0KICBjYXNlX3doZW4oYW55KHN0cl9kZXRlY3QoVEFCTEUsIHBhdHRlcm4gPSAiWzpibGFuazpdezIsfSIpKSANCiAgICAgICAgIH4gIndoaXRlIHNwYWNlcyBub3QgZml4ZWQiLA0KICAgIFRSVUUgfiAiR29vZCEiKQ0KfQ0KDQoNCmRhdGFfZGVtX2NoZWNrKHRhYmxlMTEuNGEpDQoNCmBgYA0KDQoNCk5vdyBsZXQncyBjaGVjayB0aGF0IGFsbCB0aGUgYWdlIHZhbHVlcyBzdGFydCB3aXRoIGBBZ2U6IGAgZm9yIHRoZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZS4gV2UgY2FuIHVzZSBgXmAgdG8gbG9vayBhdCB0aGUgYmVnaW5uaW5nIG9mIGVhY2ggY2hhcmFjdGVyIHN0cmluZyBpbiB0aGUgYERlbW9ncmFwaGljYCB2YXJpYWJsZS4gTm9uZSBzaG91bGQgc3RhcnQgd2l0aCBgMWAgYW55bW9yZS4gVGh1cyB3ZSBjYW4gdXNlIGBeMWAgdG8gY2hlY2sgaWYgYW55IHN0cmluZ3MgZG8gc3RhcnQgd2l0aCBhIGAxYC4NCg0KYGBge3J9DQpkYXRhX2RlbV9jaGVjayA8LSBmdW5jdGlvbihUQUJMRSl7DQogIGNhc2Vfd2hlbihhbnkoc3RyX2RldGVjdChwdWxsKFRBQkxFLERlbW9ncmFwaGljKSwgcGF0dGVybiA9ICJeMSIpKQ0KICAjIGlmIGl0IGlzIGRldGVjdGVkIHByaW50IA0KICAgICAgICAgfiAiQWdlIGRhdGEgbm90IGZpeGVkISIsDQogICAgVFJVRSB+ICJHb29kISIpDQp9DQoNCg0KZGF0YV9kZW1fY2hlY2sodGFibGUxMS40YSkNCg0KDQpgYGANCg0KDQpOb3cgd2Ugd2lsbCBjaGVjayB0aGF0IHdlIGhhdmUgYSB2YXJpYWJsZSBjYWxsZWQgc3ViZ3JvdXANCmBgYHtyfQ0KZGF0YV9kZW1fY2hlY2sgPC0gZnVuY3Rpb24oVEFCTEUpew0KICBjYXNlX3doZW4oYW55KG5hbWVzKFRBQkxFKSA9PSAic3ViZ3JvdXAiKQ0KICAjIGlmIGl0IGlzIGRldGVjdGVkIHByaW50IA0KICAgICAgICAgfiAiR29vZCIsDQogICAgVFJVRSB+ICJObyBzdWJncm91cCB2YXJpYWJsZSEiKQ0KfQ0KDQpkYXRhX2RlbV9jaGVjayh0YWJsZTExLjRhKQ0KYGBgDQoNCk5leHQgd2Ugd2lsbCBjaGVjayB0aGF0IHRoZSB5ZWFyIHZhcmlhYmxlcyBkbyBub3QgY29udGFpbiAiYSIgb3IgIiwiLiBUbyBkbyBzbyBpbnN0ZWFkIG9mIHNlbGVjdGluZyB0aGUgY29sdW1ucyB3aXRoIG5hbWVzIHRoYXQgYXJlIHllYXJzLCB3ZSB3aWxsIG5vdCBpbmNsdWRlIHRoZSBjb2x1bW5zIHRoYXQgYXJlIG5vdCB5ZWFycy4gV2Ugd2lsbCBhbHNvIHVzZSB0aGVgbWFwX2RmYCBmdW5jdGlvbiBvZiB0aGUgYHB1cnJyYCBwYWNrYWdlIHRvIGNoZWNrIGZvciBkZXRlY3RpbmcgY29tbWFzIGFuZCAiYSJzIGZvciBlYWNoIGNvbHVtbiBzZXBhcmF0ZWx5LiBUeXBpY2FsbHkgdGhpcyB3b3VsZCBub3QgYmUgbmVjZXNzYXJ5IGJlY2F1c2UgYXMgbG9uZyBhcyB3ZSBhcmVuJ3QgY2hlY2tpbmcgZm9yIGNvbW1hcyBpdCBzaG91bGQgd29yay4gSG93ZXZlciwgYHN0cl9kZXRlY3QoKWAgd2lsbCBjb2VyY2UgdGhlIGRhdGEgdG8gYmUgdmVjdG9yaXplZCBhbmQgdG8gZG8gc28gaXQgd2lsbCBhZGQgY29tbWFzIHRvIG91ciBkYXRhISBTaW5jZSB3ZSBhcmUgbG9va2luZyBmb3IgY29tbWFzIHRoaXMgd291bGQgbGVhZCB1cyB0byBkZXRlY3QgY29tbWFzIHJlZ2FyZGxlc3Mgb2YgaWYgdGhleSB3ZXJlIHByZXNlbnQgaW4gb3VyIGRhdGEuIFRoZSBgbWFwYCBmdW5jdGlvbnMgb2YgdGhlIGBwdXJycmAgcGFja2FnZSBhbGxvd3MgdXMgdG8gcGVyZm9ybSBmdW5jdGlvbnMgYWNyb3NzIG11bHRpcGxlIGNvbHVtbnMgb2YgdGliYmxlcy4gVGhlIGBtYXBfZGYoKWAgZnVuY3Rpb24gcHJlc2VydmVzIHRoZSBkYXRhIGZyYW1lIHN0cnVjdHVyZSwgb3RoZXJ3aXNlIHdlIGFyZSBsZWZ0IHdpdGggYSBsaXN0LCB3aGljaCB3b3VsZCBiZSBzbGlnaHRseSBoYXJkZXIgdG8gd29yayB3aXRoLiAgVGhpcyB3aWxsIGNyZWF0ZSBhIGRhdGEgZnJhbWUgb2YgYFRSVUVgIGFuZCBgRkFMU0VgIHZhbHVlcy4gV2UgY2FuIHRoZW4gc3VtIGVhY2ggcm93IGFzIGBGQUxTRWAgaXMgZXZhbHVhdGVkIGFzIGEgemVybyBhbmQgYFRSVUVgIGlzIGV2YWx1YXRlZCBhcyBhIG9uZS4gVGhlbiB0byBnZXQgYSBzaW5nbGUgdmFsdWUgZm9yIG91ciBgY2FzZV93aGVuKClgIGZ1bmN0aW9uLCB3ZSB3aWxsIHN1bSB0aGUgc3VtcyBvZiB0aGUgcm93cy4gV2Ugc2hvdWxkIGhhdmUgbm8gdmFsdWVzIHdpdGggZWl0aGVyICJhIiBvciAiLCIgdGh1cyB3aGVuIHdlIHJ1biB0aGlzIGNoZWNrLCB0aGUgc3VtIHNob3VsZCBiZSBlcXVhbCB0byB6ZXJvLiBUbyBwaXBlIHRoZSBkYXRhIGludG8gdGhlIGBtYXBfZGYoKWAgZnVuY3Rpb24gYW5kIHRoZW4gaW50byBgc3RyX2RldGVjdCgpYCwgd2UgbmVlZCB0byB1c2UgdGhlIGB+YCBhbmQgYC54YCBub3RhdGlvbi4gVGh1cyB0aGUgYC5YYCBpcyB0aGUgY29sdW1ucyB3aXRoaW4gdGhlIHNlbGVjdGVkIGNvbHVtbnMgb2YgdGhlIHRhYmxlIHRoYXQgd2lsbCBiZSBwaXBlZCBpbnRvIGBzdHJfZGV0ZWN0YC4gVGhlIGB+YCBpbmRpY2F0ZXMgdGhlIGZ1bmN0aW9uIHdlIHdpbGwgYmUgdXNpbmcgb24gZWFjaCBjb2x1bW4uIA0KDQpgYGB7cn0NCmRhdGFfZGVtX2NoZWNrIDwtIGZ1bmN0aW9uKFRBQkxFKXsNCiAgY2FzZV93aGVuKA0KICAgVEFCTEUlPiUgc2VsZWN0KC1EZW1vZ3JhcGhpYywgLXN1Ymdyb3VwLCAtZGF0YV90eXBlKSAlPiUgDQogICAgIG1hcF9kZih+c3RyX2RldGVjdCgueCwgcGF0dGVybiA9ImF8LCIpKSAlPiUNCiAgICAgcm93U3VtcyhuYS5ybSA9IFRSVUUpICU+JSANCiAgICAgc3VtKCkgPT0gMA0KICAgICAgICAgfiAiR29vZCEiLA0KICAgIFRSVUUgfiAiVGhlcmUgbWF5IGJlIGNvbW1hcyBvciB0aGUgbGV0dGVyIGEgaW4gdGhlIHllYXIgY29sdW1ucyEiKQ0KfQ0KDQoNCmRhdGFfZGVtX2NoZWNrKHRhYmxlMTEuNGEpDQpgYGANCg0KDQpOb3cgd2Ugd2lsbCBjaGVjayB0aGF0IHRoZSB5ZWFyIHZhcmlhYmxlcyBhcmUgbnVtZXJpYy4NCg0KYGBge3J9DQoNCmRhdGFfZGVtX2NoZWNrIDwtIGZ1bmN0aW9uKFRBQkxFKXsNCiAgY2FzZV93aGVuKHN1bShtYXBfZGJsKFRBQkxFLCBpcy5udW1lcmljKSk9PSBzdW0oc3RyX2NvdW50KG5hbWVzKFRBQkxFKSwgIjIwIikpDQogICMgaWYgaXQgaXMgZGV0ZWN0ZWQgcHJpbnQgDQogICAgICAgICB+ICJHb29kISIsDQogICAgVFJVRSB+ICJWYXJpYWJsZXMgYXJlIG5vdCBudW1lcmljISIpDQp9DQoNCmRhdGFfZGVtX2NoZWNrKHRhYmxlMTEuNGEpDQpgYGANCg0KRmluYWxseSB3ZSB3aWxsIG1ha2Ugc3VyZSB0aGF0IHRoZXJlIGFyZSBubyByb3dzIHdoZXJlIGFsbCB0aGUgeWVhciBjb2x1bW5zIGhhdmUgYE5BYCB2YWx1ZXMuDQoNCmBgYHtyfQ0KZGF0YV9kZW1fY2hlY2sgPC0gZnVuY3Rpb24oVEFCTEUpew0KICBjYXNlX3doZW4obnJvdyhUQUJMRSAlPiVmaWx0ZXIocm93U3Vtcyhpcy5uYShzZWxlY3QoLiwgaXMubnVtZXJpYykpKSA+IGxlbmd0aChzZWxlY3QoLiwgaXMubnVtZXJpYykpKSkNCiA+MCANCiAgIyBpZiBpdCBpcyBkZXRlY3RlZCBwcmludCANCiAgICAgICAgIH4gIlRoZXJlIGFyZSBlbXB0eSByb3dzICIsDQogICAgVFJVRSB+ICJHb29kISIpDQp9DQoNCmRhdGFfZGVtX2NoZWNrKHRhYmxlMTEuNGEpDQpgYGANCg0KPC9kZXRhaWxzPg0KDQoqKioNCg0KTm93IGxldCdzIHB1dCBhbGwgb3VyIGNoZWNrIGZ1bmN0aW9ucyB0b2dldGhlciBpbnRvIG9uZSBsYXJnZSBkYXRhIGNoZWNraW5nIGZ1bmN0aW9uLiBOb3RpY2UgdGhhdCBpZiB0aGUgcmVzdWx0IGlzIGdvb2QgZm9yIGVhY2ggY2hlY2sgaXQgcmVzdWx0cyBpbiBhIHZhbHVlIG9mICJHb29kISIuIFdlIGNhbiB0aGVuIHVzZSB0aGUgYmFzZSBgYWxsKClgIGZ1bmN0aW9uIHRvIGNoZWNrIHRoYXQgYWxsIHRoZSB2YWx1ZXMgaW4gdGhlIGByZXN1bHRzYCB0aWJibGUgdGhhdCBnZXRzIGNyZWF0ZWQgZHVyaW5nIG91ciBvdmVyYWxsIGZ1bmN0aW9uIHlpZWxkcyBhIHZhbHVlIG9mICJHb29kISIuDQoNCldlIGNhbiB1c2UgdGhlIGBpZmVsc2VgIGJhc2UgZnVuY3Rpb24gdG8gZ2l2ZSBvdXIgcmVzdWx0IHNpbWlsYXIgdG8gaG93IHdlIGhhdmUgdXNlZCBgY2FzZV93aGVuKClgLiAqKklmKiogYWxsIHZhbHVlcyBmb3IgZWFjaCBjaGVjayBhcmUgIkdvb2QhIiB0aGVuIHdlIHdpbGwgZ2V0ICJEYXRhIGxvb2tzIGdvb2QhIiwgb3RoZXJ3aXNlIG9yICoqZWxzZSoqIHdlIHdpbGwgc2VlIGFsbCBvZiB0aGUgY2hlY2sgcmVzdWx0cy4gVGhlcmUgaXMgYW4gYGlmX2Vsc2UoKWAgZnVuY3Rpb24gaW4gYGRwbHlyYCBidXQgaXQgb25seSBvdXRwdXRzIGNoYXJhY3RlciBzdHJpbmdzLCBzbyB0aGlzIHdvdWxkIG5vdCB3b3JrIHRvIHNob3cgd2hhdCBjaGVja3MgZmFpbGVkIHdoZW4gbm90IGFsbCB2YWx1ZXMgd2VyZSAiR29vZCEiLg0KDQpgYGB7cn0NCg0KZGF0YV9kZW1fY2hlY2sgPC0gZnVuY3Rpb24oVEFCTEUpew0KcmVzdWx0cyA8LXRpYmJsZSh0aWJibGVfY2hlY2sgPSBjYXNlX3doZW4oaXNfdGliYmxlKFRBQkxFKSB+ICJHb29kISIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJOb3QgYSB0aWJibGUiKSwNCiAgICAgICBsZWdlbmRfY2hlY2sgPSBjYXNlX3doZW4oVEFCTEUgJT4lIHNsaWNlKG4oKSkgJT4lcHVsbChgMjAxOGApICU+JQ0KICAgIyBpZiBpdCBpcyBkZXRlY3RlZCBwcmludCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChwYXR0ZXJuID0gIi0tIikgIH4gIkxlZ2VuZCBtaWdodCBzdGlsbCBiZSB0aGVyZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJHb29kISIpLA0KICAgICAgIE5Bc19jaGVjayA9IGNhc2Vfd2hlbihhbnkoc3RyX2RldGVjdChUQUJMRSwgcGF0dGVybiA9ICJuYyIpKSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gIk5BIG5vdCBmaXhlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJHb29kISIpLA0KICBmaXJzdGNvbF9jaGVjayA9IGNhc2Vfd2hlbihuYW1lcyhUQUJMRSlbMV0gPT0gIkRlbW9ncmFwaGljIiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gIkdvb2QhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gImNoZWNrIGZpcnN0IGNvbHVtbiIpLA0KICB3aGl0ZV9zcGFjZV9jaGVjayA9IGNhc2Vfd2hlbihhbnkoc3RyX2RldGVjdChUQUJMRSwgcGF0dGVybiA9ICJbOmJsYW5rOl17Mix9IikpIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAid2hpdGUgc3BhY2VzIG5vdCBmaXhlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJHb29kISIpLA0KICBhZ2VfZGF0YV9jaGVjayA9IGNhc2Vfd2hlbihhbnkoc3RyX2RldGVjdChwdWxsKFRBQkxFLERlbW9ncmFwaGljKSwgcGF0dGVybiA9ICJeMSIpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAiQWdlIGRhdGEgbm90IGZpeGVkISIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJHb29kISIpLA0KICBzdWJncm91cF9jaGVjayA9IGNhc2Vfd2hlbihhbnkobmFtZXMoVEFCTEUpID09ICJzdWJncm91cCIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+ICJHb29kISIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJObyBzdWJncm91cCB2YXJpYWJsZSEiKSwNCiAgICBhX2NvbW1hX2NoZWNrID0gY2FzZV93aGVuKFRBQkxFJT4lIHNlbGVjdCgtRGVtb2dyYXBoaWMsIC1zdWJncm91cCwgLWRhdGFfdHlwZSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBfZGYofihzdHJfZGV0ZWN0KC54LCBwYXR0ZXJuID0iYXwsIikpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dTdW1zKG5hLnJtID0gVFJVRSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtKCkgPT0gMA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gIkdvb2QhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJUaGVyZSBtYXkgYmUgY29tbWFzIG9yIHRoZSBsZXR0ZXIgYSBpbiB0aGUgeWVhciBjb2x1bW5zISIpLA0KbnVtZXJpY19jaGVjayA9IGNhc2Vfd2hlbihzdW0obWFwX2RibChUQUJMRSwgaXMubnVtZXJpYykpPT0gc3VtKHN0cl9jb3VudChuYW1lcyhUQUJMRSksICIyMCIpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+ICJHb29kISIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIlZhcmlhYmxlcyBhcmUgbm90IG51bWVyaWMhIiksDQogIGVtcHR5X3Jvd19jaGVjayA9IGNhc2Vfd2hlbihucm93KFRBQkxFICU+JWZpbHRlcihyb3dTdW1zKGlzLm5hKHNlbGVjdCguLCBpcy5udW1lcmljKSkpID4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aChzZWxlY3QoLiwgaXMubnVtZXJpYykpKSkgPjAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gIlRoZXJlIGFyZSBlbXB0eSByb3dzICIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIkdvb2QhIikpDQoNCmlmZWxzZShhbGwocmVzdWx0cyA9PSAiR29vZCEiKSwNCiAgICAgICAiRGF0YSBsb29rcyBnb29kISIsIGdsaW1wc2UocmVzdWx0cykpDQp9DQoNCmRhdGFfZGVtX2NoZWNrKHRhYmxlMTEuNGEpDQpgYGANCg0KR3JlYXQhIG5vdyBsZXQncyBjaGVjayBhbGwgb2Ygb3VyIHdyYW5nbGVkIGRlbW9ncmFwaGljIHRpYmJsZXMuIFdlIGNhbiB1c2UgdGhlIGdlbmVyYWwgYG1hcCgpYCBmdW5jdGlvbiBvZiB0aGUgYHB1cnJyYCBwYWNrYWdlIHRvIGNoZWNrIGFsbCBvZiBvdXIgZGVtb2dyYXBoaWMgdGFibGVzIGVmZmljaWVudGx5LiBXZSB3aWxsIGNyZWF0ZSBhIGxpc3Qgb2YgdGhlIG5hbWVzIG9mIHRoZSB0aWJibGVzIGFuZCB0aGVuIGFwcGx5IHRoZSBgZGF0YV9kZW1fY2hlY2soKWAgZnVuY3Rpb24gdGhhdCB3ZSB3cm90ZSB0byBlYWNoIHRpYmJsZSBieSB1c2luZyBgbWFwKClgLg0KDQpgYGB7cn0NCnRhYmxlc190b2NoZWNrIDwtbGlzdCh0YWJsZTExLjJhLCB0YWJsZTExLjJiLCB0YWJsZTExLjNhLCB0YWJsZTExLjNiLCB0YWJsZTExLjRhLCB0YWJsZTExLjRiKQ0KdGFibGVzX3RvY2hlY2sgJT4lIG1hcChkYXRhX2RlbV9jaGVjaykNCg0KYGBgDQoNCkdyZWF0ISBOb3cgdGhhdCB3ZSBoYXZlIGNoZWNrZWQgb3VyIGRhdGEsIGxldCdzIHB1dCBpdCB0b2dldGhlci4NCg0KTGV0J3MgY29tYmluZSB0aGUgY291bnQgZGF0YSAodGhlICJhIiB0YWJsZXMpIGFuZCB0aGUgcGVyY2VudCBkYXRhICh0aGUgImIiIHRhYmxlcykgdXNpbmcgdGhlIGBiaW5kX3Jvd3MoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSwgd2hpY2ggd2lsbCBhcHBlbmQgZWFjaCBvZiB0aGUgc3Vic2VxdWVudCB0YWJsZXMgdG9nZXRoZXIuDQoNCldlIGNhbiB1c2UgdGhlIGBkaXN0aW5jdCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGNoZWNrIHRoYXQgd2UgaW5kZWVkIGhhdmUgYWxsIHRoZSBkYXRhIHR5cGVzIG5vdyBpbiB0aGVzZSBsYXJnZXIgdGliYmxlcy4NCg0KYGBge3J9DQpjb3VudHMgPC0gZHBseXI6OmJpbmRfcm93cyh0YWJsZTExLjJhLCB0YWJsZTExLjNhLCB0YWJsZTExLjRhKQ0KcGVyY2VudHMgPC0gYmluZF9yb3dzKHRhYmxlMTEuMmIsIHRhYmxlMTEuM2IsIHRhYmxlMTEuNGIpDQoNCmNvdW50cyAlPiUgZHBseXI6OmRpc3RpbmN0KGRhdGFfdHlwZSkNCnBlcmNlbnRzICU+JSBkaXN0aW5jdChkYXRhX3R5cGUpDQpgYGANCkdyZWF0IQ0KDQpOb3cgd2Ugd2lsbCByZWZvcm1hdCBib3RoIHRoZSBgY291bnRzYCBhbmQgYHBlcmNlbnRzYCBkYXRhIHRvIGJlIGluIHRoZSBsb25nIGZvcm1hdCB1c2luZyBgcGl2b3RfbG9uZ2VyKClgIG9uY2UgYWdhaW4uDQoNCmBgYHtyfQ0KY291bnRzICU8PiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb250YWlucygiMjAiKSwgDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwgDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiTnVtYmVyIikgJT4lDQogIG11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhZZWFyKSkNCg0KcGVyY2VudHMgJTw+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGNvbnRhaW5zKCIyMCIpLCANCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlllYXIiLCANCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQZXJjZW50IikgJT4lDQogIG11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhZZWFyKSkNCg0KZ2xpbXBzZShjb3VudHMpDQpnbGltcHNlKHBlcmNlbnRzKQ0KYGBgDQoNCk5vdGljZSBhbHNvIHRoYXQgc29tZSBvZiB0aGUgZ3JvdXBzIGFyZSBhYmJyZXZpYXRlZCBhcyBBSUFOIGFuZCBOSE9QSS4NCg0KYGBge3J9DQpwZXJjZW50cyAlPiUgDQogIGRpc3RpbmN0KERlbW9ncmFwaGljKSU+JQ0KICBwdWxsKERlbW9ncmFwaGljKQ0KYGBgDQoNClVzaW5nIHRoZSBkZWZpbml0aW9ucyBmcm9tIHRoZSBbQ2Vuc3VzIEJ1cmVhdV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL2Nwcy9kYXRhL2RhdGEtdG9vbHMvY3BzLXRhYmxlLWNyZWF0b3ItaGVscC9yYWNlLWRlZmluaXRpb25zLmh0bWwjOn46dGV4dD1OSE9QSSUyMEFsb25lJTIwJUUyJTgwJTkzJTIwTkhPUEklMjBhbG9uZSUyMHJlZmVycyxub3QlMjByZXBvcnQlMjBhbnklMjBvdGhlciUyMHJhY2UuKXt0YXJnZXQ9Il9ibGFuayJ9OiANCg0KMS4gKipBSUFOKiogc3RhbmRzIGZvciBBbWVyaWNhbiBJbmRpYW4gYW5kIEFsYXNrYSBOYXRpdmUgIA0KMi4gKipOSE9QSSoqIHN0YW5kcyBmb3IgTmF0aXZlIEhhd2FpaWFuIG9yIE90aGVyIFBhY2lmaWMgSXNsYW5kZXIgIA0KDQpMZXQncyB1cGRhdGUgb3VyIGRhdGEgdG8gcmVmbGVjdCB0aGVzZSBkZWZpbml0aW9ucy4gDQoNCkhvd2V2ZXIsIHdlIHdvdWxkIGxpa2UgdG8gbm90ZSB0aGF0IHRoZXJlIGlzIFtjb250cm92ZXJzeV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTmF0aXZlX0FtZXJpY2FuX25hbWVfY29udHJvdmVyc3kpIGFib3V0IHRoZSBiZXN0IHRlcm0gaWYgYW55IHRvIGlkZW50aWZ5IHRoZSB2YXJpb3VzIGdyb3VwcyBvZiBwZW9wbGUgdGhhdCBtYXkgaGF2ZSBzZWxmLXJlcG9ydGVkIGFzIG9uZSBvZiB0aGVzZSBjYXRlZ29yaWVzIGFtb25nIHRoZSBvcHRpb25zIHByb3ZpZGVkIGluIHRoZSBzdXJ2ZXkgd2hlcmUgdGhlIGRhdGEgY2FtZSBmcm9tLiAgSXQgaXMgYSBsaW1pdGF0aW9uIG9mIHRoZSBkYXRhIHRoYXQgbW9yZSBzcGVjaWZpYyByYWNpYWwgYW5kIGV0aG5pYyBpbmZvcm1hdGlvbiBpcyBub3QgYXZhaWxhYmxlLiBXZSB3aWxsIHN0aWNrIHdpdGggdGhlIGFiYnJldmlhdGlvbiBkZWZpbml0aW9ucyBwcm92aWRlZCBpbiB0aGUgdGFibGVzIHNpbXBseSB0byByZW1haW4gY29uc2lzdGVudCB3aXRoIHRoZSBvcmlnaW5hbCBkYXRhLg0KDQoNClRvIGRvIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGBzdHJfcmVwbGFjZSgpYCBmdW5jdGlvbi4NCg0KYGBge3J9DQpwZXJjZW50cyAlPD4lIG11dGF0ZShEZW1vZ3JhcGhpYyA9IHN0cl9yZXBsYWNlKHN0cmluZyA9IERlbW9ncmFwaGljLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiQUlBTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIkFtZXJpY2FuIEluZGlhbiBhbmQgQWxhc2thIE5hdGl2ZSIpKQ0KDQpwZXJjZW50cyAlPD4lIG11dGF0ZShEZW1vZ3JhcGhpYyA9ICBzdHJfcmVwbGFjZShzdHJpbmcgPSBEZW1vZ3JhcGhpYywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIk5IT1BJIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiTmF0aXZlIEhhd2FpaWFuIG9yIE90aGVyIFBhY2lmaWMgSXNsYW5kZXIiKSkNCg0KY291bnRzICU8PiUgbXV0YXRlKERlbW9ncmFwaGljID0gc3RyX3JlcGxhY2Uoc3RyaW5nID0gRGVtb2dyYXBoaWMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJBSUFOIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiQW1lcmljYW4gSW5kaWFuIGFuZCBBbGFza2EgTmF0aXZlIikpDQoNCmNvdW50cyAlPD4lIG11dGF0ZShEZW1vZ3JhcGhpYyA9ICBzdHJfcmVwbGFjZShzdHJpbmcgPSBEZW1vZ3JhcGhpYywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIk5IT1BJIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiTmF0aXZlIEhhd2FpaWFuIG9yIE90aGVyIFBhY2lmaWMgSXNsYW5kZXIiKSkNCg0KYGBgDQoNCkxldCdzIGNoZWNrIHRoYXQgdGhpcyB3b3JrZWQuDQoNCmBgYHtyfQ0KcGVyY2VudHMgJT4lIA0KICBkaXN0aW5jdChEZW1vZ3JhcGhpYyklPiUNCiAgcHVsbChEZW1vZ3JhcGhpYykNCg0KY291bnRzICU+JSANCiAgZGlzdGluY3QoRGVtb2dyYXBoaWMpJT4lDQogIHB1bGwoRGVtb2dyYXBoaWMpDQpgYGANCg0KTG9va3MgZ29vZCENCg0KDQpXZSBmaW5pc2hlZCB3cmFuZ2xpbmcgdGhlIGRhdGEgYW5kIHdlIGFyZSByZWFkeSB0byBwcm9jZWVkIHdpdGggb3VyIGFuYWx5c2lzLiANCkxldCdzIHNhdmUgb3VyIGRhdGEgZmlyc3QuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBjb21lIGJhY2sgd2l0aG91dCBydW5uaW5nIG91ciBwcmV2aW91cyBjb2RlLiBXZSB3aWxsIHNhdmUgaXQgYXMgYW4gcmRhIGZpbGUgYW5kIGFzIGEgY3N2IGZpbGUgYXMgdGhpcyBpcyB1c2VmdWwgdG8gZ2l2ZSB0byBjb2xsYWJvcmF0b3JzLiBXZSB3aWxsIHNhdmUgdGhpcyBpbiBhIGRpcmVjdG9yeSBjYWxsZWQgIndyYW5nbGVkIiB3aXRoaW4gb3VyICJkYXRhIiBkaXJlY3Rvcnkgb2Ygb3VyIHByb2plY3QuIFdlIHdpbGwgdXNlIHRoZSBgd3JpdGVfY3N2KClgIGZ1bmN0aW9uIGZyb20gdGhlIGByZWFkcmAgcGFja2FnZSB0byBkbyB0aGlzLiBXZSBuZWVkIHRvIGRvIHRoaXMgZm9yIGVhY2ggdGliYmxlIHNlcGFyYXRlbHkuIA0KDQpgYGB7cn0NCnNhdmUocGVyY2VudHMsIGNvdW50cywgdGFibGUxMS4xYSwgdGFibGUxMS4xYiwgDQogICAgIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX2RhdGEucmRhIikpDQpyZWFkcjo6d3JpdGVfY3N2KHBlcmNlbnRzLCBwYXRoID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJwZXJjZW50cy5jc3YiKSkNCnJlYWRyOjp3cml0ZV9jc3YoY291bnRzLCBwYXRoID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJjb3VudHMuY3N2IikpDQpyZWFkcjo6d3JpdGVfY3N2KHRhYmxlMTEuMWEsIHBhdGggPSBoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgInRhYmxlMTEuMWEuY3N2IikpDQpyZWFkcjo6d3JpdGVfY3N2KHRhYmxlMTEuMWIsIHBhdGggPSBoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgInRhYmxlMTEuMWIuY3N2IikpDQpgYGANCg0KDQojIyAqKkRhdGEgVmlzdWFsaXphdGlvbioqDQoqKiogDQoNCklmIHlvdSBoYXZlIGJlZW4gZm9sbG93aW5nIGFsb25nIGJ1dCBzdG9wcGVkLCB5b3UgY2FuIGxvYWQgeW91ciBkYXRhIGxpa2Ugc286DQpgYGB7cn0NCmxvYWQoZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWQiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkNCmBgYA0KDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gSWYgeW91IHNraXBwZWQgdGhlIGRhdGEgd3JhbmdsaW5nIHNlY3Rpb24gY2xpY2sgaGVyZS4gPC9zdW1tYXJ5Pg0KDQpGaXJzdCB5b3UgbmVlZCB0byBpbnN0YWxsIGFuZCBsb2FkIHRoZSBgT0NTZGF0YWAgcGFja2FnZToNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQppbnN0YWxsLnBhY2thZ2VzKCJPQ1NkYXRhIikNCmxpYnJhcnkoT0NTZGF0YSkNCmBgYA0KDQpUaGVuLCB5b3UgbWF5IGxvYWQgdGhlIHdyYW5nbGVkIGRhdGEgdXNpbmcgdGhlIGZvbGxvd2luZyBjb2RlOg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCndyYW5nbGVkX3JkYSgib2NzLWJwLXlvdXRoLW1lbnRhbC1oZWFsdGgiLCBvdXRwYXRoID0gZ2V0d2QoKSkNCmxvYWQoaGVyZTo6aGVyZSgiT0NTZGF0YSIsICJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX2RhdGEucmRhIikpDQpgYGANCg0KSWYgdGhlIHBhY2thZ2UgZG9lcyBub3Qgd29yayBmb3IgeW91LCBhbHRlcm5hdGl2ZWx5LCBhbiBSREEgZmlsZSAoc3RhbmRzIGZvciBSIGRhdGEpIG9mIHRoZSBkYXRhIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tLy9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLXlvdXRoLW1lbnRhbC1oZWFsdGgvdHJlZS9tYXN0ZXIvZGF0YS93cmFuZ2xlZCkgb3Igc2xpZ2h0bHkgbW9yZSBkaXJlY3RseSBbaGVyZV0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAteW91dGgtbWVudGFsLWhlYWx0aC9tYXN0ZXIvZGF0YS93cmFuZ2xlZC93cmFuZ2xlZF9kYXRhLnJkYSkuIERvd25sb2FkIHRoaXMgZmlsZSBhbmQgdGhlbiBwbGFjZSBpdCBpbiB5b3VyIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnkgd2l0aGluIGEgc3ViZGlyZWN0b3J5IGNhbGxlZCAid3JhbmdsZWQiIHdpdGhpbiBhIHN1YmRpcmVjdG9yeSBjYWxsZWQgImRhdGEiIHRvIGNvcHkgYW5kIHBhc3RlIG91ciBjb2RlLiBXZSB1c2VkIGFuIFJTdHVkaW8gcHJvamVjdCBhbmQgdGhlIFtgaGVyZWAgcGFja2FnZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSB0byBuYXZpZ2F0ZSB0byB0aGUgZmlsZSBtb3JlIGVhc2lseS4gDQoNCmBgYHtyfQ0KbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX2RhdGEucmRhIikpDQpgYGANCg0KDQoqKioNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgbW9yZSBhYm91dCBjcmVhdGluZyBuZXcgcHJvamVjdHMgaW4gUlN0dWRpby4gPC9zdW1tYXJ5Pg0KDQpZb3UgY2FuIGNyZWF0ZSBhIHByb2plY3QgYnkgZ29pbmcgdG8gdGhlIEZpbGUgbWVudSBvZiBSU3R1ZGlvIGxpa2Ugc286DQoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIk5ld19wcm9qZWN0LnBuZyIpKQ0KYGBgDQoNCllvdSBjYW4gYWxzbyBkbyBzbyBieSBjbGlja2luZyB0aGUgcHJvamVjdCBidXR0b246DQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJwcm9qZWN0X2J1dHRvbi5wbmciKSkNCmBgYA0KDQpTZWUgW2hlcmVdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdXNpbmcgUlN0dWRpbyBwcm9qZWN0cyBhbmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgYGhlcmVgIHBhY2thZ2UuDQoNCjwvZGV0YWlscz4NCioqKg0KPC9kZXRhaWxzPg0KKioqDQoNCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCBjcmVhdGUgc29tZSBkYXRhIHZpc3VhbGl6YXRpb25zIHRvIGV4cGxvcmUgb3VyIGRhdGEgYW5kIHF1ZXN0aW9ucyBvZiBpbnRlcmVzdDogDQoNCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQ0KPGI+PHU+IE91ciBtYWluIHF1ZXN0aW9uczogPC91PjwvYj4NCg0KMS4gSG93IGhhdmUgZGVwcmVzc2lvbiByYXRlcyBpbiBBbWVyaWNhbiB5b3V0aCBjaGFuZ2VkIHNpbmNlIDIwMDQsIGFjY29yZGluZyB0byB0aGUgTlNEVUggZGF0YT8gIEhvdyBoYXZlIHJhdGVzIGRpZmZlcmVkIGJldHdlZW4gZGlmZmVyZW50IHlvdXRoIHN1Ymdyb3VwcyAoYWdlLCBnZW5kZXIsIGV0aG5pY2l0eSk/DQoyLiBEbyBtZW50YWwgaGVhbHRoIHNlcnZpY2VzIGFwcGVhciB0byBiZSByZWFjaGluZyBtb3JlIHlvdXRocz8gQWdhaW4sIGhvdyBoYXZlIHJhdGVzIGRpZmZlcmVkIGJldHdlZW4gZGlmZmVyZW50IHlvdXRoIHN1Ymdyb3VwcyAoYWdlLCBnZW5kZXIsIGV0aG5pY2l0eSk/DQoNCiMjIyMNCg0KV2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgYGdncGxvdDJgIHBhY2thZ2UgdG8gY3JlYXRlIG91ciBwbG90cy4NCg0KKioqDQo8ZGV0YWlscz48c3VtbWFyeT4gQ2xpY2sgaGVyZSBmb3IgYW4gaW50cm9kdWN0aW9uIGFib3V0IHRoaXMgcGFja2FnZSBpZiB5b3UgYXJlICBuZXcgdG8gdXNpbmcgYGdncGxvdDJgIDwvc3VtbWFyeT4NCg0KVGhlIFtnZ3Bsb3QyIHBhY2thZ2VdKGh0dHA6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcpIGlzIGEgZ3JlYXQgcGxhY2UgdG8gc3RhcnQgZm9yIGJlZ2lubmVycyBiZWNhdXNlIGl0IGlzIGJhc2VkIG9uIGEgIFtncmFtbWFyIG9mIGdyYXBoaWNzXShodHRwOi8vdml0YS5oYWQuY28ubnovcGFwZXJzL2xheWVyZWQtZ3JhbW1hci5odG1sKSAsIHdoaWNoIGlzIHdoYXQgdGhlIGBnZ2Agc3RhbmRzIGZvciBpbiBgZ2dwbG90MmAuIA0KDQpUaGUgaWRlYSBpcyB0aGF0IHRoZXJlIGFyZSBzcGVjaWZpYyBmdW5jdGlvbnMgYW5kIGFyZ3VtZW50cyAob3Ig4oCcd29yZHPigJ0pIHRoYXQgd2Ugd2lsbCBuZWVkIHRvIGxlYXJuIHRoYXQgY2FuIGJlIHVzZWQgaW4gbWFueSBkaWZmZXJlbnQgY29tYmluYXRpb25zIHRvIGNyZWF0ZSAob3Ig4oCcd3JpdGXigJ0pIGh1bmRyZWRzIG9mIGRpZmZlcmVudCBwbG90cy4NCg0KVGhlIGNyaXRpY2FsIHBhcnQgdG8gbWFraW5nIGdyYXBoaWNzIHVzaW5nIGBnZ3Bsb3QyYCBpcyB0aGUgZGF0YSBuZWVkcyB0byBiZSBpbiBhIF90aWR5XyBmb3JtYXQuIA0KR2l2ZW4gdGhhdCB3ZSBoYXZlIGp1c3Qgc3BlbnQgdGltZSBwdXR0aW5nIG91ciBkYXRhIGluIF90aWR5XyBmb3JtYXQsIHdlIGFyZSBwcmltZWQgdG8gdGFrZSBhZHZhbnRhZ2Ugb2YgYWxsIHRoYXQgYGdncGxvdDJgIGhhcyB0byBvZmZlciEgDQoNCldlIHdpbGwgc2hvdyBob3cgaXQgaXMgZWFzeSB0byBwaXBlIF90aWR5XyBkYXRhIChvdXRwdXQpIGFzIGlucHV0IHRvIG90aGVyIGZ1bmN0aW9ucyB0aGF0IGNyZWF0ZSBwbG90cy4gDQpUaGlzIGFsbCB3b3JrcyBiZWNhdXNlIHdlIGFyZSB3b3JraW5nIA0Kd2l0aGluIHRoZSBfdGlkeXZlcnNlXy4gDQoNCioqV2hhdCBpcyB0aGUgYGdncGxvdCgpYCBmdW5jdGlvbj8qKiANCkFzIGV4cGxhaW5lZCBieSBIYWRsZXkgV2lja2hhbToNCg0KPiBUaGUgZ3JhbW1hciB0ZWxscyB1cyB0aGF0IGEgc3RhdGlzdGljYWwgZ3JhcGhpYyBpcyBhIG1hcHBpbmcgZnJvbSBkYXRhIHRvIGFlc3RoZXRpYyBhdHRyaWJ1dGVzIChjb2xvdXIsIHNoYXBlLCBzaXplKSBvZiBnZW9tZXRyaWMgb2JqZWN0cyAocG9pbnRzLCBsaW5lcywgYmFycykuIFRoZSBwbG90IG1heSBhbHNvIGNvbnRhaW4gc3RhdGlzdGljYWwgdHJhbnNmb3JtYXRpb25zIG9mIHRoZSBkYXRhIGFuZCBpcyBkcmF3biBvbiBhIHNwZWNpZmljIGNvb3JkaW5hdGVzIHN5c3RlbS4NCg0KYGdncGxvdDJgIFRlcm1pbm9sb2d5OiANCg0KLSAqKmdncGxvdCoqIC0gdGhlIG1haW4gZnVuY3Rpb24gd2hlcmUgeW91IHNwZWNpZnkgdGhlIGRhdGFzZXQgYW5kIHZhcmlhYmxlcyB0byBwbG90ICh0aGlzIGlzIHdoZXJlIHdlIGRlZmluZSB0aGUgYHhgIGFuZA0KYHlgIHZhcmlhYmxlIG5hbWVzKQ0KLSAqKmdlb21zKiogLSBnZW9tZXRyaWMgb2JqZWN0cw0KICAgIC0gZS5nLiBgZ2VvbV9wb2ludCgpYCwgYGdlb21fYmFyKClgLCBgZ2VvbV9saW5lKClgLCBgZ2VvbV9oaXN0b2dyYW0oKWANCi0gKiphZXMqKiAtIGFlc3RoZXRpY3MNCiAgICAtIHNoYXBlLCB0cmFuc3BhcmVuY3ksIGNvbG9yLCBmaWxsLCBsaW5lIHR5cGVzDQotICoqc2NhbGVzKiogLSBkZWZpbmUgaG93IHlvdXIgZGF0YSB3aWxsIGJlIHBsb3R0ZWQNCiAgICAtIGNvbnRpbnVvdXMsIGRpc2NyZXRlLCBsb2csIGV0Yw0KDQpUaGUgZnVuY3Rpb24gYGFlcygpYCBpcyBhbiBhZXN0aGV0aWMgbWFwcGluZyBmdW5jdGlvbiBpbnNpZGUgdGhlIGBnZ3Bsb3QoKWAgb2JqZWN0LiANCldlIHVzZSB0aGlzIGZ1bmN0aW9uIHRvIHNwZWNpZnkgcGxvdCBhdHRyaWJ1dGVzIChlLmcuIGB4YCBhbmQgYHlgIHZhcmlhYmxlIG5hbWVzKSB0aGF0IHdpbGwgbm90IGNoYW5nZSBhcyB3ZSBhZGQgbW9yZSBsYXllcnMuICANCg0KQW55dGhpbmcgdGhhdCBnb2VzIGluIHRoZSBgZ2dwbG90KClgIG9iamVjdCBiZWNvbWVzIGEgZ2xvYmFsIHNldHRpbmcuIA0KRnJvbSB0aGVyZSwgd2UgdXNlIHRoZSBgZ2VvbWAgb2JqZWN0cyB0byBhZGQgbW9yZSBsYXllcnMgdG8gdGhlIGJhc2UgYGdncGxvdCgpYCBvYmplY3QuIA0KVGhlc2Ugd2lsbCBkZWZpbmUgd2hhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBpbGx1c3RyYXRpbmcgdXNpbmcgdGhlIGRhdGEuDQoNCjwvZGV0YWlscz4NCg0KKioqDQoNCiMjIyAqKk1ERSBBY3Jvc3MgVGltZSoqDQoqKioNCg0KV2Ugd2lsbCBzdGFydCBieSB0YWtpbmcgYSBsb29rIGF0IHRoZSByYXRlIG9mIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZXMgKE1ERSkgYW1vbmcgeW91dGhzIGFjcm9zcyB0aW1lIGluIHZhcmlvdXMgZGVtb2dyYXBoaWMgZ3JvdXBzLg0KRm9yIHRoaXMgd2Ugd2lsbCB1c2UgdGhlIGBwZXJjZW50c2AgZGF0YXNldCB0aGF0IHdlIHdyYW5nbGVkIGluIHRoZSBzZWN0aW9uIGFib3ZlLg0KDQpPSywgd2Ugd2lsbCBzdGFydCBvdXQgYnkgdXNpbmcgdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24gdG8gc3BlY2lmeSB3aGF0IGRhdGEgd2Ugd291bGQgbGlrZSB0byBwbG90IG9uIGVhY2ggYXhpcy4gDQpXZSB3aWxsIGFsc28gaW5kaWNhdGUgdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIHVzZSB0aGUgYERlbW9ncmFwaGljYCB2YXJpYWJsZSBpbiBvdXIgZGF0YXNldCB0byBncm91cCBvdXIgZGF0YSBhbmQgdG8gY29sb3Igb3VyIGRhdGEuDQpUaGlzIGlzIG91ciBmaXJzdCBsYXllciBvZiB0aGUgcGxvdCwgdGh1cyBmb3Igc3Vic2VxdWVudCBsYXllcnMgd2UgbmVlZCB0byB1c2UgYSBwbHVzIHNpZ24gYCtgLiANCg0KTmV4dCwgd2Ugd2lsbCB1c2UgdGhlIGBnZW9tX2xpbmUoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIHRvIHNwZWNpZnkgdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIGNyZWF0ZSBhIGxpbmUgcGxvdC4gDQoNClRoZW4sIHdlIHdpbGwgYWRkIGxhYmVscyBmb3IgdGhlIHRpdGxlIGFuZCBzdWJ0aXRsZSB1c2luZyB0aGUgYGxhYnMoKWAgZnVuY3Rpb24gb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLiANCg0KRmluYWxseSwgd2Ugd2lsbCBtb3ZlIG91ciBsZWdlbmQgdG8gdGhlIGJvdHRvbSBvZiB0aGUgcGxvdCB1c2luZyB0aGUgYHRoZW1lKClgIGZ1bmN0aW9uIHdoaWNoIGhlbHBzIHVzIGNvbnRyb2wgdmFyaW91cyBkZXRhaWxzIGFib3V0IG91ciBwbG90LiANCg0KYGBge3J9DQpwZXJjZW50cyAlPiUNCiAgZmlsdGVyKGRhdGFfdHlwZSA9PSAiTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlIikgJT4lDQogIGdncGxvdDI6OmdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCANCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IERlbW9ncmFwaGljKSkgKw0KICAgICAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogICAgICBsYWJzKHRpdGxlID0gIk1ham9yIERlcHJlc3NpdmUgRXBpc29kZSBhbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgICBzdWJ0aXRsZSA9ICJCeSBEZW1vZ3JhcGhpYyBDaGFyYWN0ZXJpc3RpY3MsIFBlcmNlbnRhZ2VzLCAyMDA0LTIwMTgiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KYGBgDQoNClRoaXMgcGxvdCBpcyB2ZXJ5IGRpZmZpY3VsdCB0byByZWFkIGJlY2F1c2UgdGhlcmUgYXJlIHNvIG1hbnkgZ3JvdXBzLiANCg0KTm93IGxldCdzIGxvb2sgYXQganVzdCB0aGUgdG90YWwgYWNyb3NzIHRpbWUuIA0KV2UgY2FuIGRvIHNvIGJ5IGZpcnN0IGZpbHRlcmluZyBvdXIgZGF0YSBmb3IgYFRPVEFMYCB2YWx1ZXMuIA0KDQpJdCB3b3VsZCBhbHNvIGJlIG5pY2UgdG8gaW5jbHVkZSBldmVyeSB5ZWFyIGluIHRoZSB4LWF4aXMuIA0KV2UgY2FuIGRvIHNvIGJ5IHVzaW5nIHRoZSBgc2NhbGVfeF9jb250aW51b3VzKClgIGZ1bmN0aW9uIHdoaWNoIGdpdmVzIHVzIGdyZWF0ZXIgY29udHJvbCBhYm91dCBob3cgdGhlIHgtYXhpcyBpcyBkaXNwbGF5ZWQuDQoNCkZpbmFsbHksIHdlIHdpbGwgZHJvcCB0aGUgbGVnZW5kIHNpbmNlIHdlIHdpbGwgb25seSBoYXZlIG9uZSBncm91cCB1c2luZyBgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiYCBhbmQgd2UgY2FuIGNoYW5nZSB0aGUgYW5nbGUgb2YgdGhlIHgtYXhpcyB0ZXh0IHVzaW5nIGBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKWAgd2l0aGluIHRoZSBgdGhlbWUoKWAgZnVuY3Rpb24uDQoNCldlIHdpbGwgYWxzbyBtYWtlIHRoZSBsaW5lIHRoaWNrZXIgdXNpbmcgdGhlIGBzaXplID1gIGFyZ3VtZW50IGZvciB0aGUgYGdlb21fbGluZSgpYCBmdW5jdGlvbi4NCg0KVGhlIGB0aGVtZV9jbGFzc2ljKClgIGZ1bmN0aW9uIGNoYW5nZXMgdGhlIGFlc3RoZXRpY3Mgb2YgdGhlIHBsb3QuIFNlZSBbaGVyZV0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dndGhlbWUuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgYSBsaXN0IG9mIG9wdGlvbnMuDQoNCmBgYHtyfQ0KTURFX3RvdGFsIDwtIHBlcmNlbnRzICU+JQ0KICBmaWx0ZXIoZGF0YV90eXBlID09ICJNYWpvcl9EZXByZXNzaXZlX0VwaXNvZGUiLCANCiAgICAgICAgIERlbW9ncmFwaGljID09ICJUT1RBTCIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUGVyY2VudCwgY29sb3IgPSBEZW1vZ3JhcGhpYykpICsNCiAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IERlbW9ncmFwaGljKSwgc2l6ZSA9IDEuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDQsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNCwgMjAxOCkpICsNCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50IG9mIFBlcnNvbnMgQWdlZCAxMiB0byAxNyBSZXBvcnRpbmcgSGF2aW5nIGEgXG4gTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlIGluIHRoZSBQYXN0IFllYXIgIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSANCg0KTURFX3RvdGFsDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGlzIGEgc3RlZXAgaW5jcmVhc2UgYWZ0ZXIgYXJvdW5kIDIwMTEhIA0KDQpMZXQncyBhZGQgYSBkaWZmZXJlbnQgYmFja2dyb3VuZCBjb2xvciB0byBoaWdobGlnaHQgdGhlIHllYXJzIHNpbmNlIDIwMTEuDQpXZSBjYW4gZG8gc28gYnkgYWRkaW5nIGEgYGdlb21fcmVjdCgpYCBsYXllciBiZWZvcmUgd2UgcGxvdCB0aGUgbGluZS4NCldlIGp1c3QgbmVlZCB0byBzcGVjaWZ5IHRoZSBsb2NhdGlvbiBvZiB0aGUgcmVjdGFuZ2xlIG9uIG91ciBwbG90Lg0KDQpXZSB3aWxsIGFkZCBhIGZhY2V0IHVzaW5nIHRoZSBgZmFjZXRfd3JhcCgpYCBmdW5jdGlvbiB0byBhZGQgc3RyaXAgb2YgdGV4dCB0byB0aGUgdG9wIG9mIHRoZSBwbG90IHRvIHRlbGwgbW9yZSBhYm91dCB3aGF0IGlzIGNvbnRhaW5lZCB3aXRoaW4gdGhlIHBsb3QuIFRoaXMgZnVuY3Rpb24gaXMgdHlwaWNhbGx5IHVzZWQgdG8gY3JlYXRlIHN1YnBsb3RzIHdoaWNoIHdlIHdpbGwgZGVtb25zdHJhdGUgbmV4dC4NCg0KV2Ugd2lsbCB1c2UgdGhlIGBzdHJpcC5iYWNrZ3JvdW5kYCBhbmQgYHN0cmlwLnRleHRgIG9mIHRoZSBgdGhlbWUoKWAgZnVuY3Rpb24gdG8gc3BlY2lmeSBob3cgdGhlIHRleHQgYXQgdGhlIHRvcCBvZiB0aGUgcGxvdCB3aWxsIGxvb2suDQoNCldlIHdhbnQgdG8gY2hhbmdlIHRoZSB2YWx1ZSBgVE9UQUxgIG9mIHRoZSBgRGVtb2dyYXBoaWMgdmFyaWFibGVgIHRvIGAiUGVyY2VudCBvZiByZXNwb25kYW50cyB3aXRoIE1ERSJgIHNvIHRoYXQgdGhlIHRleHQgaW4gdGhlIHN0cmlwIGFib3ZlIHRoZSBwbG90IHNob3dzIHRoaXMgaW5zdGVhZC4gV2UgY2FuIGRvIHNvIGJ5IHVzaW5nIHRoZSBgcmVjb2RlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIA0KDQpXZSB3aWxsIGFsc28gY2hhbmdlIHRoZSBjb2xvciBvZiB0aGUgbGluZSB1c2luZyB0aGUgYHNjYWxlX2NvbG9yX21hbnVhbCgpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuDQoNCmBgYHtyfQ0KDQpNREVfdG90YWwgPC0gcGVyY2VudHMgJT4lDQogIGZpbHRlcihkYXRhX3R5cGUgPT0gIk1ham9yX0RlcHJlc3NpdmVfRXBpc29kZSIsIA0KICAgICAgICAgRGVtb2dyYXBoaWMgPT0gIlRPVEFMIikgJT4lDQogIG11dGF0ZShEZW1vZ3JhcGhpYyA9IHJlY29kZShEZW1vZ3JhcGhpYywgDQogICAgICAgICAgICAgIlRPVEFMIiA9ICJQZXJjZW50IG9mIHJlc3BvbmRlbnRzIHdpdGggTURFIikpJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBncm91cCA9IERlbW9ncmFwaGljKSkgKw0KICAgIGZhY2V0X3dyYXAoIH4gRGVtb2dyYXBoaWMpKw0KICAgIGdlb21fcmVjdCh4bWluID0gMjAxMSwgeG1heCA9IEluZiwgIA0KICAgICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiwgIA0KICAgICAgICAgICAgICBmaWxsID0gImxpZ2h0IGdyYXkiKSArDQogICAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IERlbW9ncmFwaGljKSwgc2l6ZSA9IDEuNSkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDIwMDQsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNCwgMjAxOCkpICsNCiAgICBsYWJzKHRpdGxlID0gIlRoZSBSYXRlIG9mIFlvdXRocyBBZ2VkIDEyIHRvIDE3IFJlcG9ydGluZyBIYXZpbmcgYSBcbiBNYWpvciBEZXByZXNzaXZlIEVwaXNvZGUgKE1ERSkgaXMgSW5jcmVhc2luZyIpKw0KICAgIHRoZW1lX2NsYXNzaWMoKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ImJsYWNrIiksDQogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxNCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIpKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiKSkNCg0KTURFX3RvdGFsDQpgYGANCg0KTmljZSEgDQoNCk5vdyBsZXQncyBzYXkgd2Ugd2FudGVkIHRvIHNhdmUgdGhpcyBwbG90Lg0KDQpXZSBjb3VsZCBkbyBzbyB1c2luZyB0aGUgdXNpbmcgdGhlICBgc2F2ZSgpYCBmdW5jdGlvbiB0byBzYXZlIHRoaXMgdG8gYSAicGxvdHMiIGRpcmVjdG9yeSBpbiBvdXIgd29ya2luZyBkaXJlY3RvcnkgYXMgYW4gcmRhIGZpbGUgYW5kIHdlIGNhbiB1c2UgdGhlIGBwbmcoKWAgZnVuY3Rpb24gdG8gc2F2ZSBhIHBuZyBmb3IgY29sbGFib3JhdG9ycy4gV2UgbmVlZCB0byB1c2UgYGRldi5vZmYoKWAgZnVuY3Rpb24gdG8gY2xvc2UgdGhlIGdyYXBoaWNhbCBkZXZpY2UgdGhhdCB3ZSB3aWxsIHVzZSB0byBjcmVhdGUgdGhlIHBuZyB2ZXJzaW9uIG9mIHRoZSBwbG90IHNvIHRoYXQgd2UgYXJlIHJlYWR5IHRvIG1ha2UgYW5vdGhlciBwbG90IGxpa2UgdGhpcy4NCg0KYGBge3J9DQpzYXZlKE1ERV90b3RhbCwgZmlsZSA9aGVyZTo6aGVyZSgicGxvdHMiLCAiTURFX3RvdGFsLnJkYSIpKQ0KcG5nKGhlcmU6OmhlcmUoInBsb3RzIiwgIk1ERV90b3RhbC5wbmciKSkNCk1ERV90b3RhbA0KZGV2Lm9mZigpDQpgYGANCg0KDQoNCiMjIyMgey5xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpXaGF0IGRvIHlvdSBleHBlY3Qgd2lsbCBoYXBwZW4gd2hlbiBpZiB3ZSBoYWQgdXNlZCB0aGUgYCtgIHN5bWJvbCB0byBhZGQgdGhlIGBnZW9tX3JlY3QoKWAgZnVuY3Rpb24gd2l0aCBgTURFX3RvdGFsYCBsaWtlIHNvPyANCklzIHRoYXQgd2hhdCB5b3UgYW50aWNpcGF0ZWQ/IFdoeSBvciB3aHkgbm90PyANCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpNREVfdG90YWwgKyANCiAgZ2VvbV9yZWN0KHhtaW4gPSAyMDExLCB4bWF4ID0gSW5mLCAgDQogICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiwgIA0KICAgICAgICAgICAgZmlsbCA9ICJsaWdodCBncmF5IikNCmBgYA0KDQoNCg0KIyMjIw0KDQpXZSBjYW4gY3JlYXRlIGEgdGhlbWUgZm9yIG91ciBmdXR1cmUgc2ltaWxhciBnZ3Bsb3RzIGxpa2Ugc286DQoNCmBgYHtyfQ0Kb2NzX3RoZW1lIDwtIGZ1bmN0aW9uKCkgew0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImJsYWNrIiksDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiKSkNCiAgfQ0KYGBgDQoNCllvdSB3aWxsIG5vdGljZSB0aGF0IHdlIGRpZG4ndCB1c2UgYGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lImAgc28gdGhhdCB0aGlzIHRoZW1lIGlzIGZsZXhpYmxlIGZvciBwbG90cyB0aGF0IHdlIGRvIHdhbnQgdG8gcGxvdCBhIGxlZ2VuZC4NCg0KTm93IGxldCdzIGxvb2sgYXQgZ3JvdXAgZGlmZmVyZW5jZXMuICANCg0KVG8gbWFrZSBzdXJlIG91ciBwbG90IGlzIG5vdCB0b28gb3ZlcndoZWxtaW5nLCBsZXQncyBsaW1pdCB0byBvbmx5IGFnZSBhbmQgZ2VuZGVyIHN1Ymdyb3Vwcy4gDQpUaHVzLCB3ZSB3aWxsIGZpbHRlciBvdXQgdGhlIGRhdGEgYWJvdXQgdG90YWxzIGFuZCBkaWZmZXJlbnQgcmFjaWFsL2V0aG5pYyBncm91cHMgZm9yIG5vdy4gDQpXZSB3aWxsIGFsc28gdXNlIHRoZSBgZmFjZXRfd3JhcCgpYCBmdW5jdGlvbiB0byBtYWtlIHN1YnBsb3RzIGJhc2VkIG9uIHRoZSBkZW1vZ3JhcGhpYyBjYXRlZ29yaWVzLCB3aGljaCB3ZSBwdXQgaW4gYSB2YXJpYWJsZSBjYWxsZWQgYHN1Ymdyb3Vwc2AgZWFybGllciB3aGVuIHdlIHdyYW5nbGVkIHRoZSBkYXRhLg0KDQpgYGB7cn0NCg0KTURFX2FnZV9nZW5kZXIgPC1wZXJjZW50cyAlPiUNCiAgZmlsdGVyKGRhdGFfdHlwZSA9PSAiTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlIiwgDQogICAgICAgICBzdWJncm91cCAhPSAiUmFjZS9FdGhuaWNpdHkiLCANCiAgICAgICAgIERlbW9ncmFwaGljICE9ICJUT1RBTCIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUGVyY2VudCwgY29sb3IgPSBEZW1vZ3JhcGhpYykpICsNCiAgICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gRGVtb2dyYXBoaWMpLCBzaXplID0gMSkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDIwMDQsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNCwgMjAxOCkpICsNCiAgICBsYWJzKHRpdGxlID0gIk1ham9yIERlcHJlc3NpdmUgRXBpc29kZSBhbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiQnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzLCBQZXJjZW50YWdlcywgMjAwNC0yMDE4IikgKw0KICAgIGZhY2V0X3dyYXAofiBzdWJncm91cCkgKw0KICAgIG9jc190aGVtZSgpDQoNCk1ERV9hZ2VfZ2VuZGVyDQpgYGANCg0KTmljZSEgTm93IGl0IGlzIG11Y2ggZWFzaWVyIHRvIHRlbGwgaG93IGVhY2ggZ3JvdXAgaGFzIGNoYW5nZWQgb3ZlciB0aW1lLg0KDQpXZSBjYW4gYWxzbyBhZGQgbGFiZWxzIGRpcmVjdGx5IHRvIHRoZSBsaW5lcyB1c2luZyB0aGUgYGRpcmVjdGxhYmVsc2AgcGFja2FnZS4gDQpUaGVyZSBhcmUgc2V2ZXJhbCBtZXRob2RzIHRvIGRvIHNvLiANClNlZSBbaGVyZV0oaHR0cDovL2RpcmVjdGxhYmVscy5yLWZvcmdlLnItcHJvamVjdC5vcmcvZG9jcy9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBvcHRpb25zIGZvciBhZGRpbmcgbGFiZWxzIHdpdGggdGhpcyBwYWNrYWdlLiAgDQpXZSB1c2UgdGhlIGAiZmFyLmZyb20ub3RoZXJzLmJvcmRlcnMiYCBtZXRob2Qgc28gdGhhdCBvdXIgbGFiZWxzIGRvIG5vdCBvdmVybGFwIG9uZSBhbm90aGVyLiANCldlIGFsc28gdXNlIGBkbC50cmFucygpYCBvZiB0aGUgYGRpcmVjdGxhYmVsc2AgcGFja2FnZSB0byBtb3ZlIHRoZSBsYWJlbHMgc2xpZ2h0bHkgdXB3YXJkIChgeSA9IHkgKzAuMzVgKSBhbmQgdG8gdGhlIGxlZnQgKGB4ID0geCAtMC4xYCkuIA0KVGhlIGBkbC5tb3ZlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZGlyZWN0bGFiZWxzYCBwYWNrYWdlIGlzIHVzZWQgdG8gbW92ZSBvbmUgb2YgdGhlIGxhYmVscyB0byBhIHBhcnRpY3VsYXIgbG9jYXRpb24uIA0KDQpOb3RlOiB0aGUgYGRsLm1vdmVgIGZ1bmN0aW9ucyBhcmUgc2V0IHVwIGZvciB0aGUgcmVuZGVyaW5nIHRoZSBSIE1hcmtkb3duIC0gc28gaWYgeW91IGFyZSB2aWV3aW5nIHRoZSBjYXNlIHN0dWR5IGZyb20gUlN0dWRpbyB0aGUgbGFiZWxzIHdpbGwgb3ZlcmxhcC4NCg0KV2UgY2FuIG1vZGlmeSB0aGUgc2l6ZSBvZiB0aGUgbGFiZWxzIHdpdGggdGhlIGBjZXhgIGFyZ3VtZW50IGFuZCB0aGUgc3R5bGUgb2YgdGhlIGZvbnQgd2l0aCB0aGUgYGZvbnRmYWNlYCBhcmd1bWVudC4gDQoNCmBgYHtyfQ0KTURFX2FnZV9nZW5kZXIgPC0gZGlyZWN0bGFiZWxzOjpkaXJlY3QubGFiZWwoDQogIE1ERV9hZ2VfZ2VuZGVyLCANCiAgbGlzdChkbC50cmFucyh5ID0geSArIDAuMzgsIHggPSB4IC0wLjEpLCANCiAgICAgICAiZmFyLmZyb20ub3RoZXJzLmJvcmRlcnMiLA0KICAgICAgIGNleCA9IC44LCANCiAgICAgICBmb250ZmFjZT1jKCJib2xkIiksIA0KICAgICAgIGRsLm1vdmUoIkFnZTogMTQtMTUiLCB4ID0gMjAwNywgeSA9IDkuNykpDQogICkNCg0KTURFX2FnZV9nZW5kZXIgDQpgYGANCg0KRmluYWxseSwgbGV0J3MgY29sb3IgdGhlIGRpZmZlcmVudCBhZ2UgZ3JvdXBzIGluIG9yZGVyIG9mIGFnZSBieSBpbnRlbnNpdHkgb2YgY29sb3Igc2hhZGUuDQoNCkxldCdzIGFsc28gZ2V0IHRoZSBjb2xvcnMgdGhhdCB3ZSBwcmV2aW91c2x5IHVzZWQgc28gdGhhdCB3ZSBjYW4gY29sb3IgdGhlIGBNYWxlYCBhbmQgYEZlbWFsZWAgZ3JvdXBzIGluIGEgY29uc2lzdGVudCB3YXkgYWNyb3NzIG91ciB2YXJpb3VzIGZ1dHVyZSBwbG90cy4gVGhpcyB0aW1lIHdlIGNhbiB1c2UgdGhlIGBzaG93X2NvbCgpYCBmdW5jdGlvbiBhbmQgdGhlIGBodWVfcGFsKClgIGZ1bmN0aW9ucyBvZiB0aGUgYHNjYWxlc2AgcGFja2FnZSB0byBzZWUgd2hhdCB0aGUgW2hleGFkZWNpbWFsIGNvZGUgKGNhbGxlZCBoZXgpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XZWJfY29sb3JzKSBmb3IgdGhlc2UgY29sb3JzLg0KDQpJdCB3b3VsZCBiZSBuaWNlIHRvIHN3aXRjaCB0aGUgY29sb3JzIGZvciBtYWxlcyBhbmQgZmVtYWxlcyBzbyB0aGF0IHRoZXkgbWlnaHQgZml0IHdoYXQgcGVvcGxlIHdvdWxkIGV4cGVjdCB0byBhdm9pZCBjb25mdXNpb24gYW5kIGFpZCBpbiBpbnRlcnByZXRhdGlvbi4NCg0KYGBge3J9DQpzY2FsZXM6OnNob3dfY29sKHNjYWxlczo6aHVlX3BhbCgpKDYpKQ0KYGBgDQoNCkxldCdzIG1ha2UgdGhlIGFnZSBncm91cHMgZGlmZmVyZW50IHNoYWRlcyBvZiBncmVlbi4gDQoNCldlIGNhbiBnZXQgYWRkaXRpb25hbCBzaGFkZXMgdXNpbmcgdGhlIHNhbWUgZnVuY3Rpb24gYnV0IHNwZWNpZnlpbmcgbW9yZSBjb2xvcnMgdG8gZGVjaWRlIGlmIHdlIHdhbnQgYSBkaWZmZXJlbnQgY29sb3IuDQoNCmBgYHtyfQ0KDQpzY2FsZXM6OnNob3dfY29sKHNjYWxlczo6aHVlX3BhbCgpKDMwKSkNCg0KYGBgDQpXZSBjYW4gc2F2ZSBhIGZldyBkaWZmZXJlbnQgc2hhZGVzIG9mIGNvbG9ycyBmYWRpbmcgZnJvbSBnb2xkIHRvIGdyZWVuIGZvciB0aGUgZGlmZmVyZW50IGFnZSBncm91cHMuDQoNCmBgYHtyfQ0KYWdlX2NvbF9saWdodCA8LSBjKCIjQjc5RjAwIikNCmFnZV9jb2w8LSBjKCIjNkJCMTAwIikNCmFnZV9jb2xfZGFyazwtIGMoIiMwMEJENUYiKQ0KYGBgDQoNCldlIGNhbiBhbHNvIHNhdmUgdGhlIG1hbGUgYW5kIGZlbWFsZSBjb2xvcnMgYXMgbW9yZSBlYXNpbHkgcmVjb2duaXphYmxlIG9iamVjdHMgdG8gdXNlIGxhdGVyLg0KDQpgYGB7cn0NCkZlbWFsZV9jb2wgPC1jKCIjRjU2NEUzIikNCk1hbGVfY29sIDwtIGMoIiM2MTlDRkYiKQ0KYGBgDQoNCg0KTm93IHdlIGNhbiBjaGFuZ2UgdGhlIGNvbG9ycyB1c2luZyB0aGUgYHNjYWxlX2NvbG9yX21hbnVhbCgpYCBmdW5jdGlvbiBhbmQgbGlzdGluZyB0aGUgY29sb3JzIGluIG9yZGVyIGFzIHRoZXkgYXBwZWFyIGluIHRoZSBkYXRhLg0KDQpgYGB7cn0NCk1ERV9hZ2VfZ2VuZGVyIDwtIE1ERV9hZ2VfZ2VuZGVyICArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKGFnZV9jb2xfbGlnaHQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2VfY29sLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlX2NvbF9kYXJrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRmVtYWxlX2NvbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hbGVfY29sKSkNCg0KTURFX2FnZV9nZW5kZXINCg0KYGBgDQoNCg0KVGhpcyBsb29rcyB2ZXJ5IGNsZWFyIG5vdyENCg0KV2UgY2FuIHNlZSB0aGF0IHRoZSBtYWpvcml0eSBvZiBpbmRpdmlkdWFscyB0aGF0IHJlcG9ydGVkIGV4cGVyaWVuY2luZyBhIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZSBpbiB0aGUgcGFzdCB5ZWFyIHdlcmUgaW4gYW4gb2xkZXIgYWdlIGJyYWNrZXQgKDE2LTE3IGNvbXBhcmVkIHRvIDEyLTEzKS4gDQpXZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGUgdHJlbmQgaGFzIGJlZW4gaW5jcmVhc2luZyBmb3IgYWxsIHRocmVlIGFnZSBicmFja2V0cyBzaW5jZSByb3VnaGx5IDIwMTEuDQoNCldlIGNhbiBhbHNvIHNlZSBhbiBpbmNyZWFzZSBmb3IgYm90aCBnZW5kZXJzIHNpbmNlIGFib3V0IDIwMTEsIGJ1dCB0aGVyZSBpcyBhIHN0ZWVwZXIgaW5jcmVhc2UgZm9yIGZlbWFsZXMuIA0KRnVydGhlcm1vcmUsIGZlbWFsZXMgaGF2ZSBhIG11Y2ggaGlnaGVyIHBlcmNlbnRhZ2UgdGhhbiBtYWxlcyBhY3Jvc3MgYWxsIHllYXJzLg0KDQpMZXQncyBtYWtlIHRoZSBzYW1lIHBsb3Qgd2l0aCBhIGRpZmZlcmVudCBzaGFkZWQgYmFja2dyb3VuZCBmb3IgdGhlIHllYXJzIG9mIHRoZSBpbmNyZWFzZSBsaWtlIHdlIGRpZCBmb3IgdGhlIHRvdGFsIHBsb3QuDQoNCiMjIyMgey5xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpUcnkgdG8gY29tZSB1cCB3aXRoIHRoZSBjb2RlIGZvciB0aGlzIHBsb3Qgb24geW91ciBvd24gYmVmb3JlIHlvdSByZXZlYWwgaXQuDQoNCiMjIyMNCg0KKioqDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQoNCmBgYHtyfQ0KTURFX2FnZV9nZW5kZXIgPC0NCiAgcGVyY2VudHMgJT4lDQogIGZpbHRlcihkYXRhX3R5cGUgPT0gIk1ham9yX0RlcHJlc3NpdmVfRXBpc29kZSIsIA0KICAgICAgICAgc3ViZ3JvdXAgIT0gIlJhY2UvRXRobmljaXR5IiwgDQogICAgICAgICBEZW1vZ3JhcGhpYyAhPSAiVE9UQUwiKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQsIGdyb3VwID0gRGVtb2dyYXBoaWMpKSArDQogICAgZ2VvbV9yZWN0KHhtaW4gPSAyMDExLCB4bWF4ID0gSW5mLCAgDQogICAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCAgDQogICAgICAgICAgICAgIGZpbGwgPSAibGlnaHQgZ3JheSIpICsNCiAgICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gRGVtb2dyYXBoaWMpLCBzaXplID0xKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA0LCAyMDE4LCBieT0xKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDIwMDQsIDIwMTgsIGJ5PTEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDIwMDQsIDIwMTgpKSArDQogICAgbGFicyh0aXRsZSA9ICJNYWpvciBEZXByZXNzaXZlIEVwaXNvZGVcbmFtb25nIFBlcnNvbnMgQWdlZCAxMiB0byAxNyIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJCeSBEZW1vZ3JhcGhpYyBDaGFyYWN0ZXJpc3RpY3MsIFBlcmNlbnRhZ2VzLCAyMDA0LTIwMTgiKSArDQogICAgZmFjZXRfd3JhcCh+IHN1Ymdyb3VwKSArDQogICAgb2NzX3RoZW1lKCkNCg0KTURFX2FnZV9nZW5kZXIgPC0gZGlyZWN0LmxhYmVsKA0KICBNREVfYWdlX2dlbmRlciwgDQogIGxpc3QoZGwudHJhbnMoeSA9IHkgKzAuMzgsIHggPSB4IC0wLjIpLCANCiAgICAgICAiZmFyLmZyb20ub3RoZXJzLmJvcmRlcnMiLCANCiAgICAgICBjZXggPSAuOCwNCiAgICAgICBmb250ZmFjZSA9ICJib2xkIiwNCiAgICAgICBkbC5tb3ZlKCJBZ2U6IDE0LTE1IiwgeCA9IDIwMDgsIHkgPTEwKSkNCiAgKSArIA0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhhZ2VfY29sX2xpZ2h0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlX2NvbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZV9jb2xfZGFyaywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZlbWFsZV9jb2wsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNYWxlX2NvbCkpDQpgYGANCg0KPC9kZXRhaWxzPg0KDQoqKioNCg0KDQoNCmBgYHtyfQ0KTURFX2FnZV9nZW5kZXINCmBgYA0KDQoNCkxldCdzIHNhdmUgdGhpcyBwbG90IGFzIHdlbGw6DQpgYGB7cn0NCnNhdmUoTURFX2FnZV9nZW5kZXIsIGZpbGUgPWhlcmU6OmhlcmUoInBsb3RzIiwgIk1ERV9hZ2VfZ2VuZGVyLnJkYSIpKQ0KcG5nKGhlcmU6OmhlcmUoInBsb3RzIiwgIk1ERV9hZ2VfZ2VuZGVyLnBuZyIpKQ0KTURFX2FnZV9nZW5kZXINCmRldi5vZmYoKQ0KYGBgDQoNCk5pY2UhDQoNCkluIHRoZSBuZXh0IHNlY3Rpb24sIHdlIHdpbGwgZm9ybWFsbHkgdGVzdCB3aGV0aGVyIGBHZW5kZXJgIGlzIGluZGVwZW5kZW50IG9mIHRoZSBkaWZmZXJlbmNlcyBpbiByYXRlcyBvZiBNREUgYWNyb3NzIHRpbWUuIA0KDQpUbyBkbyB0aGlzLCB3ZSB3aWxsIHRlc3Qgd2hldGhlciB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBleHBlY3RlZCBmcmVxdWVuY2llcyBhbmQgdGhlIG9ic2VydmVkIGZyZXF1ZW5jaWVzIGluIG9uZSBvciBtb3JlIGNhdGVnb3JpZXMgb2YgYSBjb250aW5nZW5jeSB0YWJsZS4NCg0KV2hpbGUsIGl0IGlzIHZlcnkgaW50cmlndWluZyB0aGF0IHRoZXJlIGlzIGFuIGluY3JlYXNlIGFyb3VuZCAyMDExLCB3ZSBkbyBub3QgZ28gaW50byBkZXRhaWxzIGhlcmUgYXMgdG8gd2h5IHRoYXQgbWlnaHQgYmUgaGFwcGVuaW5nLiANCg0KSG93ZXZlciwgd2Ugc3VtbWFyaXplIGEgZmV3IGFydGljbGVzIHRoYXQgZGlkIGludmVzdGlnYXRlIGluY3JlYXNlZCBkZXByZXNzaW9uIHJhdGVzLiANCg0KKioqDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSBmb3IgYSBzdW1tYXJ5IG9uIGEgZmV3IGFydGljbGVzIGludmVzdGlnYXRpbmcgaW5jcmVhc2VkIGRlcHJlc3Npb24gcmF0ZXMuIDwvc3VtbWFyeT4NCg0KDQpUaGlzIGNyb3NzLWN1bHR1cmFsIFtyZXZpZXcgYXJ0aWNsZV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DMzMzMDE2MS8pe3RhcmdldD0iX2JsYW5rIn0gcHVibGlzaGVkIGluIDIwMTIgc3VnZ2VzdHMgdGhhdCBhc3BlY3RzIHJlbGF0ZWQgdG8gbGlmZS1zdHlsZSBkdWUgdG8gbW9kZXJuaXR5IG1heSBiZSBjYXVzaW5nIGluY3JlYXNlZCBkZXByZXNzaW9uIHJhdGVzOiANCg0KPiBNb2Rlcm4gcG9wdWxhdGlvbnMgYXJlIGluY3JlYXNpbmdseSBvdmVyZmVkLCBtYWxub3VyaXNoZWQsIHNlZGVudGFyeSwgc3VubGlnaHQtZGVmaWNpZW50LCBzbGVlcC1kZXByaXZlZCwgYW5kIHNvY2lhbGx5LWlzb2xhdGVkLiBUaGVzZSBjaGFuZ2VzIGluIGxpZmVzdHlsZSBlYWNoIGNvbnRyaWJ1dGUgdG8gcG9vciBwaHlzaWNhbCBoZWFsdGggYW5kIGFmZmVjdCB0aGUgaW5jaWRlbmNlIGFuZCB0cmVhdG1lbnQgb2YgZGVwcmVzc2lvbi4NCg0KQW5kIGFsdGhvdWdoIHRoaXMgbWF5IGJlIHRydWUgZ2xvYmFsbHksIHRoZSBVUyBoYXMgYmVlbiBhcmd1YWJseSBleHBlcmllbmNpbmcgdGhlc2UgbW9kZXJuIGxpZmVzdHlsZSBjaGFuZ2VzIGZvciB5ZWFycyBwcmlvciB0byB0aGlzIHN0ZWVwIGluY3JlYXNlIGluIDIwMTEuDQoNClNvIHdoYXQgbWlnaHQgaGF2ZSBoYXBwZW5lZCBpbiB0aGUgVVMgYXJvdW5kIHRoaXMgdGltZT8NCg0KVGhlcmUgaXMgbGFyZ2UgYW1vdW50IG9mIGxpdGVyYXR1cmUgYWJvdXQgaG93IHRoZSB1c2Ugb2Ygc21hcnQgcGhvbmUgYW5kIHNvY2lhbCBtZWRpYSBtYXkgaGF2ZSBsZWFkIHRvIGluY3JlYXNlZCBkZXByZXNzaW9uIHJhdGVzLiBTZWUgdGhpcyBbYXJ0aWNsZV0oaHR0cHM6Ly9jaGlsZG1pbmQub3JnL2FydGljbGUvaXMtc29jaWFsLW1lZGlhLXVzZS1jYXVzaW5nLWRlcHJlc3Npb24vKXt0YXJnZXQ9Il9ibGFuayJ9IHdoaWNoIGxpbmtzIHRvIG1hbnkgc2NpZW50aWZpYyBhcnRpY2xlcyBvbiB0aGUgc3ViamVjdC4gDQoNClRoaXMgaGFzIGJlZW4gYSBjb250cm92ZXJzaWFsIHRvcGljIGR1ZSB0byBjb25mbGljdGluZyBmaW5kaW5ncywgbGlrZWx5IGR1ZSB0byBmb2N1cyBvbiBkaWZmZXJlbnQgc2l0ZXMgYW5kIGFzcGVjdHMgb2Ygc29jaWFsIG1lZGlhIGFjcm9zcyBkaWZmZXJlbnQgc3R1ZGllcy4gDQoNClRoZSBhcnRpY2xlIHBvaW50cyBvdXQgdGhhdCB0aGUgdHJ1ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBzb2NpYWwgbWVkaWEgdXNlIGFuZCBkZXByZXNzaW9uIG1heSBiZSBudWFuY2VkLiBTb21lIGluZGl2aWR1YWxzIHdobyBoYXZlIGhpZ2ggZmFjZS10by1mYWNlIGxldmVscyBvZiBpbnRlcmFjdGlvbiBvciBsYWNrIG9mIHRoZSBvcHBvcnR1bml0eSB0byBpbnRlcmFjdCB3aXRoIG90aGVycyBmYWNlLXRvLWZhY2UgKGR1ZSB0byB2YXJpb3VzIGJhcnJpZXJzIGxpa2UgZ2VvZ3JhcGh5KSwgbWF5IGFjdHVhbGx5IGV4cGVyaWVuY2UgbG93ZXIgcmlzayBmb3IgZGVwcmVzc2lvbiB3aXRoIG1vcmUgc29jaWFsIG1lZGlhIHVzZS4gDQoNCkZ1cnRoZXJtb3JlLCBkaWZmZXJlbnQgc29jaWFsIG1lZGlhIHBsYXRmb3JtcyBtYXkgdmFyeSBmb3IgdGhlaXIgaW5mbHVlbmNlIG9uIGRlcHJlc3Npb24uDQoNCkluc3RhZ3JhbSB3YXMgcmVsZWFzZWQgaW4gMjAxMCAod2hpY2ggaXMgYXJvdW5kIHdoZW4gb3VyIHBsb3Qgc3RhcnRzIHRvIHNob3cgdGhlIHVwd2FyZCBpbmNyZWFzZSBpbiBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGVzLCBwYXJ0aWN1bGFybHkgaW4gZmVtYWxlcykgYW5kIGFjY29yZGluZyB0byB0aGUgYXJ0aWNsZToNCg0KPiBJbWFnZS1kcml2ZW4gSW5zdGFncmFtIHNob3dzIHVwIGluIHN1cnZleXMgYXMgdGhlIHBsYXRmb3JtIHRoYXQgbW9zdCBsZWFkcyB5b3VuZyBwZW9wbGUgdG8gcmVwb3J0IGZlZWxpbmcgYW54aWV0eSwgZGVwcmVzc2lvbiBhbmQgd29ycmllcyBhYm91dCBib2R5IGltYWdlLg0KDQpGdXJ0aGVybW9yZSwgaXQgbWF5IGJlIHNlY29uZGFyeSBlZmZlY3RzIG9mIHNvY2lhbCBtZWRpYSB1c2UsIGxpa2UgbGVzcyBwaHlzaWNhbCBhY3Rpdml0eSBvciBsZXNzIHNsZWVwIHRoYXQgbWF5IGluY3JlYXNlIHRoZSByaXNrIGZvciBkZXByZXNzaW9uLiANCg0KPC9kZXRhaWxzPg0KDQoqKioNCg0KTmV4dCwgbGV0J3MgdGFrZSBhIGxvb2sgYXQgaG93IHRoZSByYXRlIG9mIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZXMgaGFzIGNoYW5nZWQgYWNyb3NzIHRpbWUgZm9yIGRpZmZlcmVudCByYWNpYWwvZXRobmljIGdyb3Vwcy4NCg0KU2luY2Ugd2UgaGF2ZSBzbyBtYW55IGdyb3Vwcywgd2UgcHJvYmFibHkgZG9uJ3Qgd2FudCB0byBkaXJlY3RseSBsYWJlbCB0aGUgbGluZXMgdGhpcyB0aW1lLiANCkluc3RlYWQsIHdlIHdpbGwgcmVseSBvbiB0aGUgbGVnZW5kIHRoYXQgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQuDQoNCldlIHdpbGwgdXNlIHRoZSB0aGUgYGZjdF9yZW9yZGVyKClgIGZ1bmN0aW9uIG9mIHRoZSBgZm9yY2F0c2AgcGFja2FnZSB0byBvcmRlciB0aGUgcmFjaWFsL2V0aG5pYyBncm91cHMgaW4gdGhlIGxlZ2VuZCBiYXNlZCBvbiB0aGUgbGFzdCB2YWx1ZSAodXNpbmcgYHRhaWwoKWApIG9mIHRoZSBgUGVyY2VudGAgdmFyaWFibGUuDQoNCldlIHdpbGwgYWxzbyBtYW51YWxseSBjb2xvciBvdXIgbGluZXMgYmFzZWQgb24gYSBjb2xvciBwYWxldHRlIGNhbGxlZCBbdmlyaWRpc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3ZpcmlkaXMvdmlnbmV0dGVzL2ludHJvLXRvLXZpcmlkaXMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSwgd2hpY2ggaXMgbW9yZSBkaXNjZXJuaWJsZSBmb3IgaW5kaXZpZHVhbHMgd2l0aCBjb2xvci1ibGluZG5lc3MuIFRvIGRvIHNvIHdlIHdpbGwgdXNlIHRoZSBgc2NhbGVfY29sb3JfdmlyaWRpc19kKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZSwgd2hpY2ggaXMgaW50ZW5kZWQgZm9yIGNvbG9yaW5nIGRpc2NyZXRlIHZhbHVlcy4NCg0KYGBge3J9DQpNREVfcmFjZSA8LSBwZXJjZW50cyAlPiUNCiAgZmlsdGVyKGRhdGFfdHlwZSA9PSAiTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlIiwgDQogICAgICAgICBzdWJncm91cCA9PSAiUmFjZS9FdGhuaWNpdHkiKSAlPiUNCiAgbXV0YXRlKERlbW9ncmFwaGljID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoRGVtb2dyYXBoaWMsIFBlcmNlbnQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhaWwsIG4gPSAxLCAuZGVzYyA9IFRSVUUpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQsIGdyb3VwID0gRGVtb2dyYXBoaWMpKSArDQogICAgZ2VvbV9yZWN0KHhtaW4gPSAyMDExLCB4bWF4ID0gSW5mLCAgIA0KICAgICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiwgICANCiAgICAgICAgICAgICAgZmlsbCA9ICJsaWdodCBncmF5IikgKw0KICAgIGdlb21fbGluZShhZXMoY29sb3IgPSBEZW1vZ3JhcGhpYyksIHNpemUgPSAxKSArDQogICAgZmFjZXRfd3JhcCggfiBzdWJncm91cCkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDIwMDQsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNCwgMjAxOCkpICsNCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArDQogICAgbGFicyh0aXRsZSA9ICJNYWpvciBEZXByZXNzaXZlIEVwaXNvZGVcbmFtb25nIFBlcnNvbnMgQWdlZCAxMiB0byAxNyIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJCeSBEZW1vZ3JhcGhpYyBDaGFyYWN0ZXJpc3RpY3MsIFBlcmNlbnRhZ2VzLCAyMDA0LTIwMTgiKSArDQogICAgb2NzX3RoZW1lKCkNCg0KTURFX3JhY2UNCmBgYA0KDQoNClVuZm9ydHVuYXRlbHksIHRoZXJlIGlzIG9ubHkgb25lIHZhbHVlIGZvciB0aGUgYE5hdGl2ZSBIYXdhaWlhbiBvciBPdGhlciBQYWNpZmljIElzbGFuZGVyYCBncm91cCwgdGh1cyBzaW5jZSB0aGlzIGlzIGEgbGluZSBwbG90LCB3ZSBkbyBub3QgaGF2ZSBlbm91Z2ggcG9pbnRzICgyIGF0IG1pbmltdW0pIHRvIGNyZWF0ZSBhIGxpbmUsIHNvIGxldHMgcmVtb3ZlIHRoaXMgZ3JvdXAgZnJvbSB0aGUgcGxvdCB0byByZW1vdmUgdGhlIGdyb3VwIGZyb20gdGhlIGxlZ2VuZC4NCg0KIyMjIyB7LnF1ZXN0aW9uX2Jsb2NrfQ0KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+DQoNCkhvdyBtaWdodCB3ZSByZW1vdmUgdGhlIGBOYXRpdmUgSGF3YWlpYW4gb3IgT3RoZXIgUGFjaWZpYyBJc2xhbmRlcmAgZ3JvdXAgZnJvbSB0aGUgbGVnZW5kPw0KDQojIyMjDQoNCg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHJldmVhbCB0aGUgY29kZS4gPC9zdW1tYXJ5Pg0KDQpgYGB7cn0NCk1ERV9yYWNlIDwtIHBlcmNlbnRzICU+JQ0KICBmaWx0ZXIoZGF0YV90eXBlID09ICJNYWpvcl9EZXByZXNzaXZlX0VwaXNvZGUiLCANCiAgICAgICAgIHN1Ymdyb3VwID09ICJSYWNlL0V0aG5pY2l0eSIsIA0KICAgICAgICAgRGVtb2dyYXBoaWMgIT0gIk5hdGl2ZSBIYXdhaWlhbiBvciBPdGhlciBQYWNpZmljIElzbGFuZGVyIikgJT4lDQogIG11dGF0ZShEZW1vZ3JhcGhpYyA9IGZjdF9yZW9yZGVyKERlbW9ncmFwaGljLCBQZXJjZW50LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWlsLCBuID0gMSwgLmRlc2MgPSBUUlVFKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBncm91cCA9IERlbW9ncmFwaGljKSkgKw0KICAgIGdlb21fcmVjdCh4bWluID0gMjAxMSwgeG1heCA9IEluZiwgICANCiAgICAgICAgICAgICAgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYsICAgDQogICAgICAgICAgICAgIGZpbGwgPSAibGlnaHQgZ3JheSIpICsNCiAgICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gRGVtb2dyYXBoaWMpLCBzaXplID0gMSkgKw0KICAgIGZhY2V0X3dyYXAoIH4gc3ViZ3JvdXApICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDQsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgyMDA0LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDIwMDQsIDIwMTgpKSArDQogICAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKw0KICAgIGxhYnModGl0bGUgPSAiTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlXG5hbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiQnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzLCBQZXJjZW50YWdlcywgMjAwNC0yMDE4IikgKw0KICAgIG9jc190aGVtZSgpDQpgYGANCjwvZGV0YWlscz4NCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCk1ERV9yYWNlDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoZSBncm91cCBvZiBpbmRpdmlkdWFscyB3aG8gcmVwb3J0ZWQgYXMgYmVpbmcgdHdvIG9yIG1vcmUgcmFjZXMsIGhhZCB0aGUgaGlnaGVzdCBwZXJjZW50YWdlcyBvZiBoYXZpbmcgYSBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGUgaW4gdGhlIHBhc3QgeWVhci4gDQpUaG9zZSBncm91cCB3aG8gcmVwb3J0ZWQgYXMgQmxhY2sgb3IgQWZyaWNhbiBBbWVyaWNhbiBoYWQgdGhlIGxvd2VzdCBwZXJjZW50YWdlcy4gDQpIb3dldmVyLCB3ZSBjYW4gc2VlIHRoYXQgbW9zdCBvZiB0aGUgcmFjaWFsL2V0aG5pYyBncm91cHMgYXJlIGZhaXJseSBzaW1pbGFyIGFuZCB3ZSBzZWUgYW4gaW5jcmVhc2luZyBmb3IgbW9zdCBncm91cHMgc2luY2UgYXJvdW5kIDIwMTEuIA0KS2VlcCBpbiBtaW5kIHRoZSBsaW1pdGF0aW9ucyBsaXN0ZWQgaW4gdGhlIFsqKkxpbWl0YXRpb25zKipdIHNlY3Rpb24gYXMgeW91IHZpZXcgdGhlc2UgZmluZGluZ3MuIA0KSXQgaXMgcG9zc2libGUgdGhhdCB0aGlzIGdyb3VwIG1heSBiZSBsZXNzIGxpa2VseSB0byByZXBvcnQgZXhwZXJpZW5jaW5nIHN5bXB0b21zIG9mIGRlcHJlc3Npb24uDQoNCg0KTGV0J3Mgc2F2ZSB0aGlzIHBsb3QgdG9vOg0KYGBge3J9DQpzYXZlKE1ERV9yYWNlLCBmaWxlID1oZXJlOjpoZXJlKCJwbG90cyIsICJNREVfcmFjZS5yZGEiKSkNCnBuZyhoZXJlOjpoZXJlKCJwbG90cyIsICJNREVfcmFjZS5wbmciKSkNCk1ERV9yYWNlDQpkZXYub2ZmKCkNCmBgYA0KDQoNCiMjIyAqKk1ERSB3aXRoIFNldmVyZSBJbXBhaXJtZW50KioNCioqKg0KDQpOb3cgbGV0J3MgdGFrZSBhIGxvb2sgYXQgaG93IHRoZSBvdmVyYWxsIHJhdGUgb2YgeW91dGhzIHJlcG9ydGluZyBoYXZpbmcgYSBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGUgKE1ERSkgKip3aXRoIHNldmVyZSBpbXBhaXJtZW50KiogaGFzIGNoYW5nZWQgb3ZlciB0aW1lLiBTZWUgdGhlIFsqKldoYXQgYXJlIHRoZSBkYXRhPyoqXSBzZWN0aW9uIGFib3V0IGhvdyBzZXZlcmUgaW1wYWlybWVudCB3YXMgZGVmaW5lZC4gDQoNCiMjIyMgey5xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpUcnkgdG8gY29tZSB1cCB3aXRoIHRoZSBjb2RlIGZvciB0aGUgZm9sbG93aW5nIHR3byBwbG90cyBvbiB5b3VyIG93biBiZWZvcmUgeW91IHJldmVhbCBpdC4gVGhpcyB0aW1lIHdlIHdpbGwgcmVtb3ZlIHRoZSBsZWdlbmQgdXNpbmcgdGhlIGB0aGVtZSgpYCBmdW5jdGlvbi4NCg0KIyMjIw0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQpgYGB7cn0NCk1ERVNfdG90YWwgPC0gcGVyY2VudHMgJT4lDQogIGZpbHRlcihkYXRhX3R5cGUgPT0gIlNldmVyZV9NYWpvcl9EZXByZXNzaXZlX0VwaXNvZGUiLA0KICAgICAgICAgRGVtb2dyYXBoaWMgPT0gIlRPVEFMIikgJT4lIA0KICBtdXRhdGUoRGVtb2dyYXBoaWMgPSByZWNvZGUoRGVtb2dyYXBoaWMsIA0KICAgICAgICAgICAgICJUT1RBTCIgPSAiUGVyY2VudCBvZiByZXNwb25kZW50cyB3aXRoIFNldmVyZSBNREUiKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBncm91cCA9IERlbW9ncmFwaGljKSkgKw0KICAgIGdlb21fcmVjdCh4bWluID0gMjAxMSwgeG1heCA9IEluZiwgIA0KICAgICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiwgIA0KICAgICAgICAgICAgICBmaWxsID0gImxpZ2h0IGdyYXkiKSArDQogICAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IERlbW9ncmFwaGljKSwgc2l6ZSA9IDEpICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDYsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwNiwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNiwgMjAxOCkpICsNCiAgICBsYWJzKHRpdGxlID0gIk1ham9yIERlcHJlc3NpdmUgRXBpc29kZSB3aXRoIFNldmVyZSBJbXBhaXJtZW50XG5hbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiQnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzLCBQZXJjZW50YWdlcywgMjAwNC0yMDE4IikgKw0KICAgIGZhY2V0X3dyYXAoIH4gRGVtb2dyYXBoaWMpICsNCiAgICBvY3NfdGhlbWUoKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiKSkNCmBgYA0KDQo8L2RldGFpbHM+DQoNCg0KYGBge3J9DQpNREVTX3RvdGFsDQpgYGANCg0KTmV4dCBsZXQncyBsb29rIGF0IGFnZSBncm91cHMgYW5kIGdlbmRlciBkaWZmZXJlbmNlczoNCg0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQpgYGB7cn0NCk1ERVNfYWdlX2dlbmRlciA8LQ0KICBwZXJjZW50cyAlPiUNCiAgZmlsdGVyKGRhdGFfdHlwZSA9PSAiU2V2ZXJlX01ham9yX0RlcHJlc3NpdmVfRXBpc29kZSIsIA0KICAgICAgICAgc3ViZ3JvdXAgIT0gIlJhY2UvRXRobmljaXR5IiwgDQogICAgICAgICBEZW1vZ3JhcGhpYyAhPSAiVE9UQUwiKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQsIGdyb3VwID0gRGVtb2dyYXBoaWMpKSArDQogICAgZ2VvbV9yZWN0KHhtaW4gPSAyMDExLCB4bWF4ID0gSW5mLCAgDQogICAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCAgDQogICAgICAgICAgICAgIGZpbGwgPSAibGlnaHQgZ3JheSIpICsNCiAgICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gRGVtb2dyYXBoaWMpLCBzaXplID0gMSkrDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA2LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgyMDA2LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDIwMDYsIDIwMTgpKSArDQogICAgbGFicyh0aXRsZSA9ICJNYWpvciBEZXByZXNzaXZlIEVwaXNvZGUgd2l0aCBTZXZlcmUgSW1wYWlybWVudFxuYW1vbmcgUGVyc29ucyBBZ2VkIDEyIHRvIDE3IiwNCiAgICAgICAgIHN1YnRpdGxlID0gIkJ5IERlbW9ncmFwaGljIENoYXJhY3RlcmlzdGljcywgUGVyY2VudGFnZXMsIDIwMDQtMjAxOCIpICsNCiAgICBmYWNldF93cmFwKCB+IHN1Ymdyb3VwKSArDQogICAgb2NzX3RoZW1lKCkNCg0KTURFU19hZ2VfZ2VuZGVyICA8LSBkaXJlY3QubGFiZWwoDQogIE1ERVNfYWdlX2dlbmRlciwgDQogIGxpc3QoZGwudHJhbnMoeSA9IHkgKzAuMzksIHggPSB4IC0wLjEpLCANCiAgICAgICAiZmFyLmZyb20ub3RoZXJzLmJvcmRlcnMiLA0KICAgICAgIGNleCA9IC44LCANCiAgICAgICBmb250ZmFjZSA9ICJib2xkIiwNCiAgICAgICBkbC5tb3ZlKCJBZ2U6IDE0LTE1IiwgeD0gMjAxNi41LCB5ID0gMTEpKQ0KICApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoYWdlX2NvbF9saWdodCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZV9jb2wsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2VfY29sX2RhcmssIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGZW1hbGVfY29sLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWFsZV9jb2wpKQ0KYGBgDQoNCjwvZGV0YWlscz4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQpNREVTX2FnZV9nZW5kZXINCmBgYA0KDQpXZSBjYW4gc2VlIHRoYXQgdGhlIG1ham9yaXR5IG9mIGluZGl2aWR1YWxzIHRoYXQgcmVwb3J0ZWQgZXhwZXJpZW5jaW5nIGEgbWFqb3IgZGVwcmVzc2l2ZSBlcGlzb2RlIHdpdGggc2V2ZXJlIGltcGFpcm1lbnQgd2VyZSBpbiBhbiBvbGRlciBhZ2UgYnJhY2tldC4gDQpIb3dldmVyLCB0aGVyZSBhcHBlYXJzIHRvIGJlIGEgbW9yZSBkcmFtYXRpYyBjaGFuZ2UgaW4gdGhlIG1pZGRsZSBhZ2UgZ3JvdXAgZnJvbSAyMDExLTIwMTIuIA0KV2UgY2FuIHNlZSBhIHZlcnkgc3RlZXAgaW5jcmVhc2UgaW4gdGhlIGRhdGEgZm9yIHRoZSBmZW1hbGVzIGFmdGVyIDIwMTEsIGFnYWluIHRoaXMgaXMgbXVjaCBtb3JlIHN0ZWVwIHRoYW4gdGhlIGluY3JlYXNlIHNlZW4gZm9yIG1hbGVzIG92ZXIgdGltZS4NCg0KTm93IGxldCdzIGxvb2sgYXQgZGlmZmVyZW50IHJhY2lhbC9ldGhuaWMgZ3JvdXBzLg0KDQojIyMjIHsucXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KVHJ5IHRvIGNvbWUgdXAgd2l0aCB0aGUgY29kZSBmb3IgdGhpcyBwbG90IG9uIHlvdXIgb3duIGJlZm9yZSB5b3UgcmV2ZWFsIGl0Lg0KDQojIyMjDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCg0KYGBge3J9DQpSYWNlX01ERVMgPC0gcGVyY2VudHMgJT4lDQogIGZpbHRlcihkYXRhX3R5cGUgPT0gIlNldmVyZV9NYWpvcl9EZXByZXNzaXZlX0VwaXNvZGUiLCANCiAgICAgICAgIHN1Ymdyb3VwID09ICJSYWNlL0V0aG5pY2l0eSIpICU+JQ0KICBtdXRhdGUoRGVtb2dyYXBoaWMgPSANCiAgICAgICAgICAgZmN0X3Jlb3JkZXIoRGVtb2dyYXBoaWMsIFBlcmNlbnQsIA0KICAgICAgICAgICAgICAgICAgICAgICB0YWlsLCBuID0gMSwgLmRlc2MgPSBUUlVFKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBncm91cCA9IERlbW9ncmFwaGljKSkgKw0KICAgIGdlb21fcmVjdCh4bWluID0gMjAxMSwgeG1heCA9IEluZiwgIA0KICAgICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiwgIA0KICAgICAgICAgICAgICBmaWxsID0gImxpZ2h0IGdyYXkiKSArDQogICAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IERlbW9ncmFwaGljKSwgc2l6ZSA9MSkgKw0KICAgIGZhY2V0X3dyYXAofiBzdWJncm91cCkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNiwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDIwMDYsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNiwgMjAxOCkpICsNCiAgICBsYWJzKHRpdGxlID0gIk1ham9yIERlcHJlc3NpdmUgRXBpc29kZSB3aXRoIFNldmVyZSBJbXBhaXJtZW50XG5hbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiQnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzOiBQZXJjZW50YWdlcywgMjAwNi0yMDE4IikgKw0KICAgIG9jc190aGVtZSgpICsNCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKQ0KYGBgDQo8L2RldGFpbHM+DQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KUmFjZV9NREVTDQpgYGANCg0KV2Ugc2VlIHNpbWlsYXIgdHJlbmRzIGFzIHdlIHNhdyBmb3IgdGhlIHByZXZpb3VzIHJhY2lhbC9ldGhuaWMgZ3JvdXAgcGxvdC4gDQpUaGUgcmF0ZSBpcyBoaWdoZXN0IGZvciB0aG9zZSB3aG8gYXJlIHR3byBhcmUgbW9yZSByYWNlcyBhbmQgbG93ZXN0IGZvciB0aG9zZSB3aG8gYXJlIEJsYWNrIG9yIEFmcmljYW4gQW1lcmljYW4uIA0KVGhlIGRhdGEgZm9yIHRoZSBgQW1lcmljYW4gSW5kaWFuIGFuZCBBbGFza2EgTmF0aXZlYCBncm91cCBpcyBzcGFyc2UsIHNvIGl0IGlzIHVuY2xlYXIgaWYgdGhlaXIgbGV2ZWxzIHdvdWxkIGJlIGxvd2VzdCBvbiB0aGUgbGFzdCB5ZWFyLg0KDQojIyMgKipNREUgVHJlYXRtZW50KioNCioqKg0KDQpOb3cgd2Ugd2lsbCB0YWtlIGEgbG9vayBhdCB0aG9zZSB3aG8gcmVwb3J0ZWQgaGF2aW5nIGEgTURFIGFuZCByZWNlaXZlZCB0cmVhdG1lbnQgZm9yIGRlcHJlc3Npb24uDQoNCkZpcnN0LCBsZXQncyBsb29rIG92ZXJhbGwgdXNpbmcgdGhlIGBEZW1vZ3JhcGhpYyA9PSAiVE9UQUwiYCBncm91cC4gV2Ugd2lsbCByZW1vdmUgdGhlIGxlZ2VuZCBmb3IgdGhpcyBwbG90Lg0KDQoNCiMjIyMgey5xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpUcnkgdG8gY29tZSB1cCB3aXRoIHRoZSBjb2RlIGZvciB0aGlzIHBsb3Qgb24geW91ciBvd24gYmVmb3JlIHlvdSByZXZlYWwgaXQuDQoNCiMjIyMNCg0KKioqDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQoNCmBgYHtyfQ0KVHJlYXRfdG90YWwgPC0gcGVyY2VudHMgJT4lDQogIGZpbHRlcihkYXRhX3R5cGUgPT0gIlRyZWF0bWVudCIsIA0KICAgICAgICAgRGVtb2dyYXBoaWMgPT0gIlRPVEFMIikgJT4lDQogIG11dGF0ZShEZW1vZ3JhcGhpYyA9IHJlY29kZShEZW1vZ3JhcGhpYywgDQogICAgICAgICAgICAgIlRPVEFMIiA9ICJQZXJjZW50IG9mIE1ERSByZXNwb25kZW50cyB3aXRoIHRyZWF0bWVudCIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQsIGdyb3VwID0gRGVtb2dyYXBoaWMpKSArDQogICAgZ2VvbV9yZWN0KHhtaW4gPSAyMDExLCB4bWF4ID0gSW5mLCAgDQogICAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCAgIA0KICAgICAgICAgICAgICBmaWxsID0gImxpZ2h0IGdyYXkiKSArDQogICAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IERlbW9ncmFwaGljKSwgc2l6ZSA9IDEuNSkgKw0KICAgIGZhY2V0X3dyYXAofkRlbW9ncmFwaGljKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA0LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDA0LCAyMDE4KSkgKw0KICAgIGxhYnModGl0bGUgPSAiVGhlIFJhdGUgb2YgWW91dGhzIEFnZWQgMTIgdG8gMTcgUmVjZWl2aW5nIFRyZWF0bWVudCBhZnRlclxuUmVwb3J0aW5nIEhhdmluZyBhIE1ham9yIERlcHJlc3NpdmUgRXBpc29kZSBpcyBJbmNyZWFzaW5nIikgKw0KICAgIG9jc190aGVtZSgpICsNCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmx1ZSIpKQ0KYGBgDQoNCjwvZGV0YWlscz4NCioqKg0KDQpgYGB7cn0NClRyZWF0X3RvdGFsDQpgYGANCg0KT3ZlcmFsbCwgcm91Z2hseSA0MCBwZXJjZW50IG9mIHlvdXRocyB3aG8gc2VsZi1yZXBvcnRlZCBleHBlcmllbmNpbmcgYSBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGUsIGFsc28gcmVjZWl2ZWQgdHJlYXRtZW50IGZvciBkZXByZXNzaW9uLiBUaHVzIHRoZSBtYWpvcml0eSBvZiB5b3V0aHMgcmVwb3J0aW5nIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZSBzeW1wdG9tcyBhcmUgbm90IHJlY2VpdmluZyB0cmVhdG1lbnQuIA0KDQpUaGlzIHNob3dzIGFuIG92ZXJhbGwgaW5jcmVhc2UgaW4gdGhlIHJhdGUgaW4gd2hpY2ggeW91dGhzIGFyZSByZWNlaXZpbmcgdHJlYXRtZW50IHNpbmNlIDIwMTEsIGxpa2UgdGhlIHRyZW5kIHNlZW4gZm9yIHRoZSBudW1iZXIgb2YgeW91dGhzIHJlcG9ydGluZyBoYXZpbmcgaGFkIGEgbWFqb3IgZGVwcmVzc2l2ZSBlcGlzb2RlLCB5ZXQgdGhlIGRhdGEgZm9yIHRyZWF0bWVudCBhcmUgbXVjaCBtb3JlIHZhcmlhYmxlIGZyb20gb25lIHllYXIgdG8gdGhlIG5leHQuIA0KDQpOZXh0LCB3ZSBjb25zaWRlciBkaWZmZXJlbmNlcyBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzIGFuZCBkaWZmZXJlbnQgYWdlIGdyb3Vwcy4gDQoNCkZpcnN0IGxldCdzIHNhdmUgdGhpcyBwbG90Og0KYGBge3J9DQpzYXZlKFRyZWF0X3RvdGFsLCBmaWxlID1oZXJlOjpoZXJlKCJwbG90cyIsICJUcmVhdF90b3RhbC5yZGEiKSkNCnBuZyhoZXJlOjpoZXJlKCJwbG90cyIsICJUcmVhdF90b3RhbC5wbmciKSkNClRyZWF0X3RvdGFsDQpkZXYub2ZmKCkNCmBgYA0KDQojIyMjIHsucXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KVHJ5IHRvIGNvbWUgdXAgd2l0aCB0aGUgY29kZSBmb3IgdGhpcyBwbG90IG9uIHlvdXIgb3duIGJlZm9yZSB5b3UgcmV2ZWFsIGl0Lg0KDQojIyMjDQoNCioqKg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHJldmVhbCB0aGUgY29kZS4gPC9zdW1tYXJ5Pg0KDQpgYGB7cn0NCnRyZWF0IDwtIHBlcmNlbnRzICU+JQ0KICBmaWx0ZXIoZGF0YV90eXBlID09ICJUcmVhdG1lbnQiLCANCiAgICAgICAgIHN1Ymdyb3VwICE9ICJSYWNlL0V0aG5pY2l0eSIsIA0KICAgICAgICAgc3ViZ3JvdXAgIT0gIlRvdGFsIikgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBjb2xvciA9IERlbW9ncmFwaGljKSkgKw0KICAgIGdlb21fbGluZShzaXplID0gMSkgKw0KICAgIGZhY2V0X3dyYXAoIH4gc3ViZ3JvdXApICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDQsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgyMDA0LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDIwMDQsIDIwMTgpKSArIA0KICAgIGxhYnModGl0bGUgPSAiUmVjZWlwdCBvZiBUcmVhdG1lbnQgZm9yIERlcHJlc3Npb24gYW1vbmdcblBlcnNvbnMgQWdlZCAxMiB0byAxNyB3aXRoIE1ham9yIERlcHJlc3NpdmUgRXBpc29kZSIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJCeSBEZW1vZ3JhcGhpYyBDaGFyYWN0ZXJpc3RpY3M6IFBlcmNlbnRhZ2VzLCAyMDA0LTIwMTgiKSArDQogICAgb2NzX3RoZW1lKCkNCg0KdHJlYXQgPC0gZGlyZWN0LmxhYmVsKA0KICB0cmVhdCwgDQogIGxpc3QoZGwudHJhbnMoeSA9IHkgLTEuNSwgeCA9IHggLTAuNCksDQogICAgICAgImZhci5mcm9tLm90aGVycy5ib3JkZXJzIiwgDQogICAgICAgY2V4ID0gLjgsIA0KICAgICAgIGZvbnRmYWNlID0gImJvbGQiLA0KICAgICAgIGRsLm1vdmUoIkFnZTogMTYtMTciLCB4ID0gMjAxMCwgeSA9IDQyKSwNCiAgICAgICBkbC5tb3ZlKCJBZ2U6IDE0LTE1IiwgeCA9IDIwMTUsIHkgPSAzOCkpDQogICkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhhZ2VfY29sX2xpZ2h0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlX2NvbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZV9jb2xfZGFyaywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZlbWFsZV9jb2wsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNYWxlX2NvbCkpDQpgYGANCg0KPC9kZXRhaWxzPg0KDQoqKioNCg0KYGBge3J9DQp0cmVhdA0KYGBgDQoNClRoZXJlIHNlZW1zIHRvIGJlIGFuIHVwd2FyZCB0cmVuZCwgYnV0IGl0IGlzbid0IG5lYXJseSBhcyBtdWNoIGFzIHRoZSB0cmVuZCB3ZSBzYXcgZm9yIHRoZSBpbmNyZWFzZSBvZiBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGVzLiBJbiBnZW5lcmFsLCB0aGUgZGF0YSBzZWVtcyB0byB2YXJ5IG11Y2ggbW9yZSBhcyB3ZWxsLg0KDQoNCiMjIyMgey5xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpDcmVhdGUgYSBzaW1pbGFyIHBsb3Qgb24geW91ciBvd24gZm9yIHRoZSBkaWZmZXJlbnQgcmFjZSAvIGV0aG5pYyBncm91cHMuIA0KDQojIyMjDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCg0KYGBge3J9DQpSYWNlX3RyZWF0IDwtIHBlcmNlbnRzICU+JQ0KICBmaWx0ZXIoZGF0YV90eXBlID09ICJUcmVhdG1lbnQiKSAlPiUNCiAgZmlsdGVyKHN1Ymdyb3VwID09ICJSYWNlL0V0aG5pY2l0eSIpICU+JQ0KICBtdXRhdGUoRGVtb2dyYXBoaWMgPSANCiAgICAgICAgICAgZmN0X3Jlb3JkZXIoRGVtb2dyYXBoaWMsIFBlcmNlbnQsIA0KICAgICAgICAgICAgICAgICAgICAgICB0YWlsLCBuID0gMSwgLmRlc2MgPSBUUlVFKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBjb2xvciA9IERlbW9ncmFwaGljKSkgKw0KICAgIGdlb21fbGluZShzaXplID0gMSkgKw0KICAgIGZhY2V0X3dyYXAoIH4gc3ViZ3JvdXApICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDksIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgyMDA5LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDIwMDksIDIwMTgpKSArDQogICAgbGFicyh0aXRsZSA9ICJSZWNlaXB0IG9mIFRyZWF0bWVudCBmb3IgRGVwcmVzc2lvbiBhbW9uZ1xuUGVyc29ucyBBZ2VkIDEyIHRvIDE3IHdpdGggTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlIiwNCiAgICAgICAgIHN1YnRpdGxlID0gIkJ5IERlbW9ncmFwaGljIENoYXJhY3RlcmlzdGljczogUGVyY2VudGFnZXMsIDIwMDQtMjAxOCIpICsNCiAgICBvY3NfdGhlbWUoKSArDQogICAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkNCmBgYA0KPC9kZXRhaWxzPg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NClJhY2VfdHJlYXQNCmBgYA0KDQpJdCBsb29rcyBhcyB0aG91Z2ggeW91dGhzIHdobyByZXBvcnQgYXMgYmVpbmcgd2hpdGUgcmVjZWl2ZWQgdGhlIG1vc3QgY2FyZSBmcm9tIG1lbnRhbCBoZWFsdGggc2VydmljZXMuDQoNCg0KIyMjICoqTWVudGFsIEhlYWx0aCBTZXJ2aWNlcyoqDQoqKioNCg0KV2Ugd2lsbCBhbHNvIHRha2UgYSBsb29rIGF0IHdoZXJlIHlvdXRocyBhcmUgcmVjZWl2aW5nIHRyZWF0bWVudCBieSB1c2luZyB2YWx1ZXMgZnJvbSBgdGFibGUxMS4xYmAgd2hpY2ggaGFzIHRoZSBwZXJjZW50YWdlIHZhbHVlcyBmb3IgY291bnRzIHByZXNlbnRlZCBpbiBgdGFibGUxMS4xYWAuDQoNCldlIGNhbiB1c2UgdGhlIGBzdHJfZGV0ZWN0KClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZSB0byBmaWx0ZXIgZm9yIHRoZSB2YWx1ZXMgb2YgdGhlIGBzaG9ydF9sYWJlbGAgdmFyaWFibGUgdGhhdCBoYXMgdGhlIHdvcmQgYHRvdGFsYCBpbiBpdC4gDQoNCmBgYHtyfQ0KcGxvdE1IUyA8LSB0YWJsZTExLjFiICU+JQ0KICBmaWx0ZXIoc3RyaW5ncjo6c3RyX2RldGVjdChzaG9ydF9sYWJlbCwgInRvdGFsIikgKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQsIA0KICAgICAgICAgICAgIGdyb3VwID0gTUhTX3NldHRpbmcsIGNvbG9yID0gc2hvcnRfbGFiZWwpKSArDQogICAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogICAgZmFjZXRfd3JhcCggfiB0eXBlKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA5LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwOSwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDA5LCAyMDE4KSkgKw0KICAgIGxhYnModGl0bGUgPSAiU2V0dGluZ3MgV2hlcmUgTWVudGFsIEhlYWx0aCBTZXJ2aWNlcyBXZXJlIFJlY2VpdmVkXG5hbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiUGVyY2VudGFnZXMsIDIwMDItMjAxOCIpICsNCiAgICBvY3NfdGhlbWUoKQ0KDQpwbG90TUhTIDwtIGRpcmVjdC5sYWJlbCgNCiAgcGxvdE1IUywgDQogIGxpc3QoZGwudHJhbnMoeSA9IHkgKzAuMzUsIHggPSB4IC0wLjEpLA0KICAgICAgICJmYXIuZnJvbS5vdGhlcnMuYm9yZGVycyIsIA0KICAgICAgIGNleCA9IC44LCANCiAgICAgICBkbC5tb3ZlKCJPdXRwYXRpZW50IHRvdGFsIiwgeCA9IDIwMTUsIHkgPTExKSkNCiAgKQ0KDQpwbG90TUhTDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHlvdXRocyBhcHBlYXIgdG8gYmUgcmVjZWl2aW5nIGNhcmUgaW4gbm9uc3BlY2lhbHR5IGZhY2lsaXRpZXMgYXQgYSBzbGlnaHRseSBoaWdoZXIgcmF0ZSB0aGFuIHRoYXQgb2Ygc3BlY2lhbHR5IGZhY2lsaXRpZXMuIFNlZSBbaGVyZV0oaHR0cHM6Ly93d3cubm9ydGh0ZXhhc2hlbHAuY29tL21lbnRhbC1oZWFsdGgtdHJlYXRtZW50LXNldHRpbmdzLmh0bWwpIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHRoZXNlIGRpZmZlcmVudCB0eXBlcyBvZiBtZW50YWwgaGVhbHRoIHNlcnZpY2VzLiBBIG5vbnNwZWNpYWx0eSBmYWNpbGl0eSBwcm92aWRlcyBnZW5lcmFsIGhlYWx0aCB0cmVhdG1lbnQgYW5kIG90aGVyIHNlcnZpY2VzLCBzdWNoIGFzIGEgdHlwaWNhbCBob3NwaXRhbCBvciBhIHNjaG9vbC4gQSBzcGVjaWFsdHkgZmFjaWxpdHksIGluIGNvbnRyYXN0LCBmb2N1c2VzIG9uIHRoZSB0cmVhdG1lbnQgb2YgbWVudGFsIGhlYWx0aC4gT3V0cGF0aWVudCBzZXJ2aWNlcyBhcmUgdGhvc2UgaW4gd2hpY2ggdGhlIHBhdGllbnQgZG9lcyBub3Qgc3RheSBvdmVybmlnaHQgZm9yIGV2ZW4gb25lIG5pZ2h0IGF0IHRoZSBob3NwaXRhbCBvciB0cmVhdG1lbnQgZmFjaWxpdHksIHdoaWxlIGlucGF0aWVudCBzZXJ2aWNlcyBhcmUgdGhvc2UgaW4gd2hpY2ggdGhlIHBhdGllbnQgc3RheXMgb3Zlcm5pZ2h0IGZvciBhdCBsZWFzdCBvbmUgbmlnaHQgYXQgdGhlIGNhcmUgZmFjaWxpdHkuDQoNCkhvd2V2ZXIsIHRoZSByYXRlcyBhcHBlYXIgdG8gYmUgdmVyeSBzaW1pbGFyIGFuZCB0aGUgcmVsYXRpdmUgZGlmZmVyZW5jZXMgYXBwZWFyIHRvIGJlIGNvbnNpc3RlbnQgYWNyb3NzIHRpbWUuDQoNCkxldCdzIHRha2UgYSBsb29rIGF0IHN1YmNhdGVnb3JpZXMgb2YgbWVudGFsIGhlYWx0aCBzZXJ2aWNlcy4NClRvIGRvIHRoaXMsIHdlIHdpbGwgZmlsdGVyIGZvciB2YWx1ZXMgd2l0aGluIHRoZSBgc2hvcnRfbGFiZWxgIHZhcmlhYmxlIHRoYXQgZG8gbm90IGNvbnRhaW4gdGhlIHdvcmQgInRvdGFsIiBieSB1c2luZyBhIGAhYCBpbiBmcm9udCBvZiB0aGUgYHN0cl9kZWN0ZWN0YCBzdGF0ZW1lbnQuDQoNCmBgYHtyfQ0KcGxvdE1IU1MgPC0gdGFibGUxMS4xYiAlPiUNCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHNob3J0X2xhYmVsLCAidG90YWwiKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCANCiAgICAgICAgIGdyb3VwID0gTUhTX3NldHRpbmcsIGNvbG9yID0gc2hvcnRfbGFiZWwpKSArDQogICAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogICAgZmFjZXRfd3JhcCggfiB0eXBlKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDAyLCAyMDE5LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwMiwgMjAxOSwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDAyLCAyMDE5KSkgKw0KICAgIGxhYnModGl0bGUgPSAiU2V0dGluZ3MgV2hlcmUgTWVudGFsIEhlYWx0aCBTZXJ2aWNlcyBXZXJlIFJlY2VpdmVkXG5hbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiUGVyY2VudGFnZXMsIDIwMDItMjAxOCIpICsNCiAgICBvY3NfdGhlbWUoKSANCg0KcGxvdE1IU1MgPC0gZGlyZWN0LmxhYmVsKA0KICBwbG90TUhTUywgDQogIGxpc3QoZGwudHJhbnMoeSA9IHkgKzAuMyksDQogICAgICAgImZhci5mcm9tLm90aGVycy5ib3JkZXJzIiwgDQogICAgICAgZGwubW92ZSgiU2Nob29sIFRoZXJhcGlzdCIsIDIwMTAsIDEwKSwgDQogICAgICAgZGwubW92ZSgiRm9zdGVyY2FyZSIsIDIwMTAsIDEpLCANCiAgICAgICBkbC5tb3ZlKCJUaGVyYXBpc3QiLCB4PTIwMDksIHkgPSAxMC41KSkNCiAgKQ0KDQpwbG90TUhTUw0KYGBgDQpJdCBsb29rcyBsaWtlIG1vc3QgeW91dGhzIGFyZSByZWNlaXZpbmcgY2FyZSBmcm9tIGVpdGhlciBhIHRoZXJhcGlzdCBvciBhIHNjaG9vbCB0aGVyYXBpc3QuDQoNCk9LLCBzbyBub3cgd2Uga25vdyBob3cgdGhlIHJhdGVzIG9mIGRpZmZlcmVudCBzdWJncm91cHMgY29tcGFyZSBmb3IgaGF2aW5nIGEgTURFIGluIHRoZSBwYXN0IHllYXIsIGhhdmluZyBhIE1ERSB3aXRoIHNldmVyZSBpbXBhaXJtZW50LCBhbmQgcmVjZWl2aW5nIHRyZWF0bWVudCBhZnRlciBhIE1ERS4gDQpXZSBhbHNvIGtub3cgd2hlcmUgeW91dGhzIGFyZSB0eXBpY2FsbHkgZ2V0dGluZyB0cmVhdG1lbnQuIA0KQnV0LCBob3cgZG8gdGhlIHJhdGVzIG9mIGhhdmluZyBhIE1ERSBpbiB0aGUgcGFzdCB5ZWFyLCBoYXZpbmcgYSBNREUgd2l0aCBzZXZlcmUgaW1wYWlybWVudCwgYW5kIHJlY2VpdmluZyB0cmVhdG1lbnQgY29tcGFyZSB3aXRoaW4gZWFjaCBzdWJncm91cCAoZS5nLiBqdXN0IGZlbWFsZXMpPw0KDQpUaGlzIGlzIHdoYXQgd2UgdGFja2xlIGluIHRoZSBuZXh0IHNlY3Rpb24uIA0KDQojIyMgKipPdmVyYWxsIE91dGNvbWVzIGJ5IEdyb3VwKioNCioqKg0KDQpJbiB0aGUgbmV4dCBwbG90LCB3ZSBmaXJzdCBmaWx0ZXIgZm9yIGBNYWxlYCwgYEZlbWFsZWAgYW5kIGBUb3RhbGAgYW5kIHRoZW4gZmFjZXQgYnkgdGhlIGBEZW1vZ3JhcGhpY2AgdmFyaWFibGUuIFdlIHdpbGwgdXNlIGRpZmZlcmVudCB0eXBlcyBvZiBsaW5lcyB0byBpbmRpY2F0ZSB0aGUgZGlmZmVyZW50IG91dGNvbWUgdmFsdWVzIGJ5IHVzaW5nIHRoZSBgc2NhbGVfbGluZXR5cGVfbWFudWFsKClgIGZ1bmN0aW9uLiBXZSBjYW4gdXNlIHRoZSBgZ2d0aGVtZXNgIHBhY2thZ2UgYW5kIHRoZSBgc2NhbGVzYCBwYWNrYWdlIGluIG9yZGVyIHRvIHNlZSBhbGwgdGhlIGN1cnJlbnQgb3B0aW9ucyBmb3IgZGlmZmVyZW50IGxpbmV0eXBlcy4NCg0KYGBge3J9DQpnZ3RoZW1lczo6c2hvd19saW5ldHlwZXMoc2NhbGVzOjpsaW5ldHlwZV9wYWwoKSgxMiksIGxhYmVscyA9IFRSVUUpDQpgYGANCg0KV2UgY2FuIG5vdyB1c2UgdGhlIGxhYmVscyBmb3IgdGhlIGRpZmZlcmVudCB0eXBlcyBvZiBsaW5lcyBpbiB0aGUgYHNjYWxlX2xpbmV0eXBlX21hbnVhbCgpYCBmdW5jdGlvbiB0byBzcGVjaWZ5IHNwZWNpZmljIGxpbmV0eXBlcy4NCg0KDQpXZSB3aWxsIGFsc28gdXNlIHRoZSBgZ3VpZGVzKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZSB0byByZW1vdmUgdGhlIGxlZ2VuZCBzcGVjaWZpY2FsbHkgZm9yIHRoZSBjb2xvciwgbm90IGZvciB0aGUgbGluZXR5cGUgYnkgdXNpbmcgYGd1aWRlcyhjb2xvciA9IEZBTFNFKS4NCg0KYGBge3J9DQpnZW5kZXJfb3V0Y29tZXMgPC0gDQogIHBlcmNlbnRzICU+JQ0KICBmaWx0ZXIoRGVtb2dyYXBoaWMgJWluJSBjKCJNYWxlIiwgIkZlbWFsZSIsICJUT1RBTCIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IFBlcmNlbnQsIGNvbG9yID0gRGVtb2dyYXBoaWMpKSArDQogICAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZSA9IGRhdGFfdHlwZSksIHNpemUgPSAxKSArDQogICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoInNvbGlkIiwgIjIyNjIiLCAiMTMiKSkgKw0KICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKEZlbWFsZV9jb2wsIE1hbGVfY29sLCAiYmxhY2siKSkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDIwMDQsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNCwgMjAxOCkpICsNCiAgICBsYWJzKHRpdGxlID0gIk1ham9yIERlcHJlc3NpdmUgRXBpc29kZXMgYW5kIFRyZWF0bWVudCBBbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiQnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzLCBQZXJjZW50YWdlcywgMjAwNC0yMDE4IikgKw0KICAgIGZhY2V0X3dyYXAoIH4gRGVtb2dyYXBoaWMsIHN0cmlwLnBvc2l0aW9uID0gInRvcCIpICsNCiAgb2NzX3RoZW1lKCkgKw0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogICAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpDQoNCmdlbmRlcl9vdXRjb21lcyANCmBgYA0KDQpXZSBjYW4gc2VlIHRoYXQgYSBsYXJnZSBwb3J0aW9uIG9mIGluZGl2aWR1YWxzIGV4cGVyaWVuY2luZyBhIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZSBoYXZlIGFuIGVwaXNvZGUgd2l0aCBzZXZlcmUgaW1wYWlybWVudCBmb3IgZWFjaCBncm91cC4gDQpGZW1hbGVzIGhhdmUgYSBoaWdoZXIgcmF0ZSBvZiBib3RoIHR5cGVzIG9mIGVwaXNvZGUgYW5kIG9mIHRyZWF0bWVudC4gDQpBbHRob3VnaCBmZW1hbGVzIGhhdmUgbW9yZSB0aGFuIGRvdWJsZSB0aGUgcmF0ZSBvZiByZXBvcnRlZCBlcGlzb2RlcywgdGhleSByZWNlaXZlIGEgcmVsYXRpdmVseSBzaW1pbGFyIHJhdGUgb2YgdHJlYXRtZW50IGFzIG1hbGVzIGZvciBkZXByZXNzaW9uLiANClRoaXMgc3VnZ2VzdHMgdGhhdCBmZW1hbGVzIGFyZSBlaXRoZXIgbW9yZSBsaWtlbHkgdGhhbiBtYWxlcyB0byBzZWxmLXJlcG9ydCBkZXByZXNzaW9uIHN5bXB0b21zIGluIHN1cnZleXMsIG9yIGZlbWFsZXMgbWF5IG5vdCBiZSByZWNlaXZpbmcgYXMgbXVjaCBjYXJlIGRlc3BpdGUgdGhlIGxhcmdlciBuZWVkLiANCg0KIyMjIyB7LnF1ZXN0aW9uX2Jsb2NrfQ0KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+DQoNCkNyZWF0ZSBhIHNpbWlsYXIgcGxvdCBvbiB5b3VyIG93biBmb3IgZGlmZmVyZW50IGFnZSBncm91cHMuIA0KDQojIyMjDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCg0KDQpgYGB7cn0NCmFnZV9vdXRjb21lcyA8LXBlcmNlbnRzICU+JQ0KICBmaWx0ZXIoc3ViZ3JvdXAgPT0gIkFnZSIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUGVyY2VudCwgY29sb3IgPSBEZW1vZ3JhcGhpYykpICsNCiAgICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlPSBkYXRhX3R5cGUpLCBzaXplID0gMSkgKw0KICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJzb2xpZCIsICIyMjYyIiwgIjEzIikpICsNCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhhZ2VfY29sX2xpZ2h0LCBhZ2VfY29sLCBhZ2VfY29sX2RhcmspKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA0LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDA0LCAyMDE4KSkgKw0KICAgIGxhYnModGl0bGUgPSAiTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlXG5hbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiQnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzLCBQZXJjZW50YWdlcywgMjAwNC0yMDE4IikgKw0KICAgIGZhY2V0X3dyYXAoIH4gRGVtb2dyYXBoaWMsIHN0cmlwLnBvc2l0aW9uID0gInRvcCIpKw0KICBvY3NfdGhlbWUoKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgICBndWlkZXMoY29sb3IgPSBGQUxTRSkNCmBgYA0KDQo8L2RldGFpbHM+IA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmFnZV9vdXRjb21lcw0KYGBgDQoNCkFsbCBhZ2UgZ3JvdXBzIHNob3cgYSBzaW1pbGFyIHJhdGlvIG9mIHNldmVyZSBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGVzIGZvciB0aG9zZSB0aGF0IGV4cGVyaWVuY2VkIGFuIGVwaXNvZGUuIA0KDQojIyMjIHsucXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KQ3JlYXRlIGEgc2ltaWxhciBwbG90IG9uIHlvdXIgb3duIGZvciB0aGUgZGlmZmVyZW50IHJhY2UgLyBldGhuaWMgZ3JvdXBzLiANCg0KIyMjIw0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQoNCmBgYHtyfQ0KcmFjZV9vdXRjb21lcyA8LSBwZXJjZW50cyAlPiUNCiAgZmlsdGVyKHN1Ymdyb3VwID09ICJSYWNlL0V0aG5pY2l0eSIsIA0KICAgICAgICAgRGVtb2dyYXBoaWMgIT0gIk5hdGl2ZSBIYXdhaWlhbiBvciBPdGhlciBQYWNpZmljIElzbGFuZGVyIikgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBjb2xvciA9IERlbW9ncmFwaGljKSkgKw0KICAgIGdlb21fbGluZShhZXMobGluZXR5cGUgPSBkYXRhX3R5cGUpLCBzaXplPTEpICsNCiAgICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygic29saWQiLCAiMjI2MiIsICIxMyIpKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA0LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDA0LCAyMDE4KSkgKw0KICAgIGxhYnModGl0bGUgPSAiTWFqb3IgRGVwcmVzc2l2ZSBFcGlzb2RlXG5hbW9uZyBQZXJzb25zIEFnZWQgMTIgdG8gMTciLA0KICAgICAgICAgc3VidGl0bGUgPSAiQnkgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzLCBQZXJjZW50YWdlcywgMjAwNC0yMDE4IikgKw0KICAgIGZhY2V0X3dyYXAoIH4gRGVtb2dyYXBoaWMsIHN0cmlwLnBvc2l0aW9uID0gInRvcCIsIG5yb3cgPSA0KSArDQogIG9jc190aGVtZSgpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICAgIGd1aWRlcyhjb2xvciA9IEZBTFNFKQ0KYGBgDQo8L2RldGFpbHM+DQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTEwfQ0KcmFjZV9vdXRjb21lcw0KYGBgDQoNCkFsbCByYWNpYWwgYW5kIGV0aG5pYyBncm91cHMgYWxzbyBzaG93IGEgc2ltaWxhciByYXRlIG9mIHNldmVyZSBlcGlzb2RlcyByZWxhdGl2ZSB0byBnZW5lcmFsIGVwaXNvZGUgcmF0ZS4gDQpUaGUgcmF0ZSBvZiByZWNlaXZpbmcgdHJlYXRtZW50IGlzIGZhaXJseSBzaW1pbGFyIHJlbGF0aXZlIHRvIHRoZSBwZXJjZW50YWdlIG9mIHlvdXRocyB0aGF0IHJlcG9ydGVkIGhhdmluZyBzeW1wdG9tcyBmb3IgZWFjaCBncm91cC4NCg0KDQojIyAqKkRhdGEgQW5hbHlzaXMqKg0KKioqIA0KDQpJZiB5b3UgaGF2ZSBiZWVuIGZvbGxvd2luZyBhbG9uZyBidXQgc3RvcHBlZCwgeW91IGNhbiBsb2FkIHlvdXIgZGF0YSBsaWtlIHNvOg0KYGBge3J9DQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX2RhdGEucmRhIikpDQpgYGANCg0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IElmIHlvdSBza2lwcGVkIHRoZSBwcmV2aW91cyBzZWN0aW9ucyBjbGljayBoZXJlLiA8L3N1bW1hcnk+DQoNCkZpcnN0IHlvdSBuZWVkIHRvIGluc3RhbGwgYW5kIGxvYWQgdGhlIGBPQ1NkYXRhYCBwYWNrYWdlOg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmluc3RhbGwucGFja2FnZXMoIk9DU2RhdGEiKQ0KbGlicmFyeShPQ1NkYXRhKQ0KYGBgDQoNClRoZW4sIHlvdSBtYXkgbG9hZCB0aGUgd3JhbmdsZWQgZGF0YSB1c2luZyB0aGUgZm9sbG93aW5nIGNvZGU6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0Kd3JhbmdsZWRfcmRhKCJvY3MtYnAteW91dGgtbWVudGFsLWhlYWx0aCIsIG91dHBhdGggPSBnZXR3ZCgpKQ0KbG9hZChoZXJlOjpoZXJlKCJPQ1NkYXRhIiwgImRhdGEiLCAid3JhbmdsZWQiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkNCmBgYA0KDQpJZiB0aGUgcGFja2FnZSBkb2VzIG5vdCB3b3JrIGZvciB5b3UsIGFsdGVybmF0aXZlbHksIGFuIFJEQSBmaWxlIChzdGFuZHMgZm9yIFIgZGF0YSkgb2YgdGhlIGRhdGEgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAteW91dGgtbWVudGFsLWhlYWx0aC90cmVlL21hc3Rlci9kYXRhL3dyYW5nbGVkKSBvciBzbGlnaHRseSBtb3JlIGRpcmVjdGx5IFtoZXJlXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy1icC15b3V0aC1tZW50YWwtaGVhbHRoL21hc3Rlci9kYXRhL3dyYW5nbGVkL3dyYW5nbGVkX2RhdGEucmRhKS4gRG93bmxvYWQgdGhpcyBmaWxlIGFuZCB0aGVuIHBsYWNlIGl0IGluIHlvdXIgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSB3aXRoaW4gYSBzdWJkaXJlY3RvcnkgY2FsbGVkICJ3cmFuZ2xlZCIgd2l0aGluIGEgc3ViZGlyZWN0b3J5IGNhbGxlZCAiZGF0YSIgdG8gY29weSBhbmQgcGFzdGUgb3VyIGNvZGUuIFdlIHVzZWQgYW4gUlN0dWRpbyBwcm9qZWN0IGFuZCB0aGUgW2BoZXJlYCBwYWNrYWdlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpIHRvIG5hdmlnYXRlIHRvIHRoZSBmaWxlIG1vcmUgZWFzaWx5LiANCg0KYGBge3J9DQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWQiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkNCmBgYA0KDQoNCioqKg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBtb3JlIGFib3V0IGNyZWF0aW5nIG5ldyBwcm9qZWN0cyBpbiBSU3R1ZGlvLiA8L3N1bW1hcnk+DQoNCllvdSBjYW4gY3JlYXRlIGEgcHJvamVjdCBieSBnb2luZyB0byB0aGUgRmlsZSBtZW51IG9mIFJTdHVkaW8gbGlrZSBzbzoNCg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAiTmV3X3Byb2plY3QucG5nIikpDQpgYGANCg0KWW91IGNhbiBhbHNvIGRvIHNvIGJ5IGNsaWNraW5nIHRoZSBwcm9qZWN0IGJ1dHRvbjoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInByb2plY3RfYnV0dG9uLnBuZyIpKQ0KYGBgDQoNClNlZSBbaGVyZV0oaHR0cHM6Ly9zdXBwb3J0LnJzdHVkaW8uY29tL2hjL2VuLXVzL2FydGljbGVzLzIwMDUyNjIwNy1Vc2luZy1Qcm9qZWN0cykgdG8gbGVhcm4gbW9yZSBhYm91dCB1c2luZyBSU3R1ZGlvIHByb2plY3RzIGFuZCBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSB0byBsZWFybiBtb3JlIGFib3V0IHRoZSBgaGVyZWAgcGFja2FnZS4NCg0KPC9kZXRhaWxzPg0KKioqDQo8L2RldGFpbHM+DQoqKioNCg0KUmVjYWxsIHdoYXQgb3VyIG1haW4gcXVlc3Rpb25zIHdlcmU6DQoNCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQ0KPGI+PHU+IE91ciBtYWluIHF1ZXN0aW9uczogPC91PjwvYj4NCg0KMS4gSG93IGhhdmUgZGVwcmVzc2lvbiByYXRlcyBpbiBBbWVyaWNhbiB5b3V0aCBjaGFuZ2VkIHNpbmNlIDIwMDQsIGFjY29yZGluZyB0byB0aGUgTlNEVUggZGF0YT8gIEhvdyBoYXZlIHJhdGVzIGRpZmZlcmVkIGJldHdlZW4gZGlmZmVyZW50IHlvdXRoIHN1Ymdyb3VwcyAoYWdlLCBnZW5kZXIsIGV0aG5pY2l0eSk/DQoyLiBEbyBtZW50YWwgaGVhbHRoIHNlcnZpY2VzIGFwcGVhciB0byBiZSByZWFjaGluZyBtb3JlIHlvdXRocz8gQWdhaW4sIGhvdyBoYXZlIHJhdGVzIGRpZmZlcmVkIGJldHdlZW4gZGlmZmVyZW50IHlvdXRoIHN1Ymdyb3VwcyAoYWdlLCBnZW5kZXIsIGV0aG5pY2l0eSk/DQoNCiMjIyMNCg0KV2UgYXJlIHNwZWNpZmljYWxseSBpbnRlcmVzdGVkIGluIGhvdyB0aGUgZnJlcXVlbmN5IG9mIHJlY2VudCBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGVzIGFtb25nIHlvdXRocyBkaWZmZXIgY29tcGFyZWQgdG8gdGhvc2UgaW4gMjAwNC4gDQpXZSBhcmUgYWxzbyBpbnRlcmVzdGVkIGhvdyBkaWZmZXJlbnQgc3ViZ3JvdXBzIGRpZmZlci4gDQpXZSB3aWxsIHN0YXJ0IHdpdGggZXhhbWluaW5nIGhvdyBtYWxlIGFuZCBmZW1hbGVzIGRpZmZlciBhY3Jvc3MgdGltZS4NCg0KIyMjICoqQ2hpLVNxdWFyZWQgVGVzdCoqDQoqKioNCg0KT3VyIGZpcnN0IHF1ZXN0aW9uIGlzOiBfSXMgdGhlIHJhdGUgb2YgcmVwb3J0ZWQgbWFqb3IgZGVwcmVzc2l2ZSBlcGlzb2RlcyBhY3Jvc3MgdGhlIHR3byB5ZWFycyBhc3NvY2lhdGVkIHdpdGggZ2VuZGVyP18gIA0KDQpTaW5jZSB3ZSBoYXZlIGNvdW50cyBmb3IgdGhlIHR3byBnZW5kZXJzOiBtYWxlcyBhbmQgZmVtYWxlcywgYW5kIGZvciB0aGUgdHdvIHllYXJzIG9mIGludGVyZXN0LCAyMDA0IGFuZCAyMDE4LCB3ZSBjYW4gY29uZHVjdCBhIFtQZWFyc29uJ3MgY2hpLXNxdWFyZWQgdGVzdF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUGVhcnNvbiUyN3NfY2hpLXNxdWFyZWRfdGVzdCM6fjp0ZXh0PVBlYXJzb24ncyUyMGNoaSUyRHNxdWFyZWQlMjB0ZXN0JTIwaXMsZGlmZmVycyUyMGZyb20lMjBhJTIwdGhlb3JldGljYWwlMjBkaXN0cmlidXRpb24uKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciAqKmluZGVwZW5kZW5jZSoqLCB3aGljaCBpcyBhbHNvIHdyaXR0ZW4gbGlrZSB0aGlzOiAke1xjaGl9XjIkLiANCg0KVGhpcyB3aWxsIGFsbG93IHVzIHRvIGNvbXBhcmUgaWYgdGhlIHJlbGF0aXZlIGZyZXF1ZW5jaWVzIG9mIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZXMgZGlmZmVycyBmcm9tIHdoYXQgd2Ugd291bGQgZXhwZWN0IGJ5IGNoYW5jZSBpZiB0aGUgdmFyaWFibGVzIHllYXJzIGFuZCBnZW5kZXIgd2VyZSBpbmRlcGVuZGVudC4NCg0KDQpBY2NvcmRpbmcgdG8gW3dpa2lwZWRpYV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ2hpLXNxdWFyZWRfdGVzdD9vbGRmb3JtYXQ9dHJ1ZSl7dGFyZ2V0PSJfYmxhbmsifTogDQoNCj4gUGVhcnNvbidzIGNoaS1zcXVhcmVkIHRlc3QgaXMgdXNlZCB0byBkZXRlcm1pbmUgd2hldGhlciB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSAqKmV4cGVjdGVkIGZyZXF1ZW5jaWVzKiogYW5kIHRoZSAqKm9ic2VydmVkIGZyZXF1ZW5jaWVzKiogaW4gb25lIG9yIG1vcmUgKipjYXRlZ29yaWVzKiogb2YgYSBbY29udGluZ2VuY3kgdGFibGVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NvbnRpbmdlbmN5X3RhYmxlKXt0YXJnZXQ9Il9ibGFuayJ9Lg0KDQpUaGUgbnVsbCBoeXBvdGhlc2lzIGlzIHRoYXQgdGhlIHZhcmlhYmxlcyBhcmUgaW5kZWVkIGluZGVwZW5kZW50LCBvciB0aGF0IHRoZSBkaWZmZXJlbmNlIGluIHRoZSBwcm9wb3J0aW9uIG9mIG9ic2VydmVkIHRvIGV4cGVjdGVkIGZyZXF1ZW5jaWVzIGlzIGVxdWFsIHRvIHplcm8uIA0KDQpUaHVzLCB0byBjb25kdWN0IHRoaXMgc3RhdGlzdGljYWwgdGVzdCwgd2UgZmlyc3QgbmVlZCB0byBjcmVhdGUgYSBbY29udGluZ2VuY3kgdGFibGVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NvbnRpbmdlbmN5X3RhYmxlKXt0YXJnZXQ9Il9ibGFuayJ9LCB3aGljaCBpbiB0aGlzIGNhc2UgY291bGQgYWxzbyBiZSBjYWxsZWQgYSAyeDIgdGFibGUsIHdoaWNoIGlzIHRoZSBzaW1wbGVzdCBraW5kIG9mIGNvbnRpbmdlbmN5IHRhYmxlIChvbmx5IHR3byBsZXZlbHMgZm9yIHR3byB2YXJpYWJsZXMpLg0KDQpCZWZvcmUgd2UgY3JlYXRlIGEgY29udGluZ2VuY3kgdGFibGUgZm9yIG91ciBkYXRhIGFuZCB1c2UgdGhlIGNoaS1zcXVhcmVkIHRlc3QsIGxldCdzIHByYWN0aWNlIHRoaXMgd2l0aCBhIGRpZmZlcmVudCBleGFtcGxlLiANCg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciBhbiBleGFtcGxlIGFuZCBtb3JlIGV4cGxhbmF0aW9uIG9mIHRoZSBQZWFyc29uJ3MgY2hpLXNxdWFyZWQgdGVzdC4gPC9zdW1tYXJ5Pg0KDQoNCg0KQ29uc2lkZXIgYSBoeXBvdGhldGljYWwgc2NlbmFyaW8gd2hlcmUgd2Ugc2FtcGxlIDEwMCBpbmRpdmlkdWFscyBhbmQgcmVwb3J0IGEgY29udGluZ2VuY3kgdGFibGUgcmVwcmVzZW50aW5nIHRoZSBudW1iZXIgb2YgaHlwb3RoZXRpY2FsIGluZGl2aWR1YWxzIHRoYXQgd2Ugb2JzZXJ2ZWQgd2hvIGFyZSBsZWZ0IGFuZCByaWdodCBoYW5kZWQsIHN0cmF0aWZpZWQgYnkgbWFsZXMgYW5kIGZlbWFsZXMgKGFzc3VtaW5nIGFsbCBpbmRpdmlkdWFscyBoYWQgYmluYXJ5IGdlbmRlcikuDQoNCg0KYGBge3J9DQpvYnNlcnZlZCA8LSB0aWJibGUoR2VuZGVyID0gYygiTWFsZSIsICJGZW1hbGUiLCAiVG90YWwiKSwgDQogICAgICAgICAgICAgICAgICAgUmlnaHRoYW5kZWQgPSBjKDQxLDQ3LDg4KSwgDQogICAgICAgICAgICAgICAgICAgTGVmdGhhbmRlZCA9IGMoOSwzLCAxMiksIA0KICAgICAgICAgICAgICAgICAgIFRvdGFsID0gYyg1MCw1MCwxMDApKQ0KDQpvYnNlcnZlZA0KYGBgDQoNCldlIGNhbiBzZWUgdGhhdCB0aGVyZSBhcmUgdHdvIHZhcmlhYmxlczogYEdlbmRlcmAgYW5kIGBIYW5kZWRuZXNzYCBhbmQgZWFjaCBoYXZlIHR3byBsZXZlbHMgKGBNYWxlYCBhbmQgYEZlbWFsZWAgZm9yIGBHZW5kZXJgIGFuZCBgUmlnaHRoYW5kZWRgIGFuZCBgTGVmdGhhbmRlZGAgZm9yIGBIYW5kZWRuZXNzYCkuIA0KDQpUaGUgdGFibGUgYWxzbyBpbmNsdWRlcyB0b3RhbHMgb2YgZWFjaCBvZiB0aGUgNCBwb3NzaWJsZSBncm91cHMgYXMgd2VsbCBhcyB0aGUgb3ZlcmFsbCB0b3RhbC4NCg0KTmV4dCwgd2UgY3JlYXRlIGEgdGFibGUgb2Ygd2hhdCB3ZSAqKmV4cGVjdCoqIGFzc3VtaW5nIGBHZW5kZXJgIGFuZCBgSGFuZGVkbmVzc2AgYXJlIGluZGVwZW5kZW50LiANCg0KLSBUaGUgdG90YWwgbnVtYmVyIG9mIGluZGl2aWR1YWxzIHdobyBhcmUgcmlnaHQtaGFuZGVkIGlzIDg4IG91dCBvZiAxMDAgd2hpY2ggaXMgZXF1YWwgdG8gODglLg0KLSBUaGUgdG90YWwgbnVtYmVyIG9mIGluZGl2aWR1YWxzIHdobyBhcmUgbGVmdC1oYW5kZWQgaXMgMTIgb3V0IG9mIDEwMCB3aGljaCBpcyBlcXVhbCB0byAxMiUuDQoNClRodXMsIGlmIGVhY2ggYm90aCBgTWFsZWAgYW5kIGBGZW1hbGVzYCBoYWQgdGhlIHNhbWUgYW1vdW50IG9mIHJpZ2h0LWhhbmRlZG5lc3MgYW5kIGxlZnQtaGFuZGVkbmVzcywgd2Ugd291bGQgZXhwZWN0IDg4JSBvZiB0aGUgbWFsZXMgdG8gYmUgcmlnaHQtaGFuZGVkIGFuZCAxMiUgdG8gYmUgbGVmdC1oYW5kZWQ7IGFuZA0Kd2Ugd291bGQgZXhwZWN0IHRoZSBleGFjdCBzYW1lIHByb3BvcnRpb25zIG9mIDg4JSByaWdodC1oYW5kZWQgYW5kIDEyJSBsZWZ0LWhhbmRlZCBmb3IgdGhlIGZlbWFsZXMuDQoNClNpbmNlIHdlIGhhdmUgNTAgbWFsZXMgYW5kIDUwIGZlbWFsZXMgYW5kIDEyJSBvZiA1MCBpcyA2IGFuZCA4OCUgb2YgNTAgaXMgNDQsIHdlIHdvdWxkIHRodXMgaGF2ZSB0aGUgZm9sbG93aW5nIHRhYmxlIG9mIGV4cGVjdGVkIGZyZXF1ZW5jaWVzOg0KDQpgYGB7cn0NCg0KZXhwZWN0ZWQgPC0gdGliYmxlKEdlbmRlciA9IGMoIk1hbGUiLCAiRmVtYWxlIiwgIlRvdGFsIiksIA0KICAgICAgICAgICAgICAgICAgIFJpZ2h0aGFuZGVkID0gYyg0NCw0NCw4OCksIA0KICAgICAgICAgICAgICAgICAgIExlZnRoYW5kZWQgPSBjKDYsNiwgMTIpLCANCiAgICAgICAgICAgICAgICAgICBUb3RhbCA9IGMoNTAsNTAsMTAwKSkNCg0KZXhwZWN0ZWQNCmBgYA0KDQpUaGUgJHtcY2hpfV4yJCB0ZXN0IHN0YXRpc3RpY3MgaXMgY2FsY3VsYXRlZCB1c2luZyB0aGUgYG9ic2VydmVkYCAoTykgYW5kIGBleHBlY3RlZGAgKEUpIGZyZXF1ZW5jaWVzIHdlIGp1c3QgY2FsY3VsYXRlZCBhYm92ZSB1c2luZyB0aGUgZm9sbG93aW5nIGZvcm11bGE6DQoNCiQke1xjaGl9XjI9XHN1bV97aj0xfV57bX0gXGZyYWN7KE9faiAtIEVfaileMn17RV9qfSQkDQoNCndoZXJlICRPX2ogPSBqXnt0aH0kIG9ic2VydmVkIGNvdW50IGFuZCAkRV9qID0gal57dGh9JCBleHBlY3RlZCBjb3VudCBmb3INCnRoZSAkal57dGh9JCBjZWxsIG9mIGEgY29udGluZ2VuY3kgdGFibGUgd2l0aCAkbSQgY2VsbHMuDQoNClRoZSBbZGVncmVlcyBvZiBmcmVlZG9tXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EZWdyZWVzX29mX2ZyZWVkb21fKHN0YXRpc3RpY3MpKSAoJGRmJCkgaXMgY2FsY3VsYXRlZCBsaWtlIHNvOiAkZGY9IChyLTEpKGMtMSkkLiBOb3RlIHRoYXQgYXMgYWNjb3JkaW5nIHRvIFdpa2lwZWRpYTogImRlZ3JlZXMgb2YgZnJlZWRvbSBpcyB0aGUgbnVtYmVyIG9mIHZhbHVlcyBpbiB0aGUgZmluYWwgY2FsY3VsYXRpb24gb2YgYSBzdGF0aXN0aWMgdGhhdCBhcmUgZnJlZSB0byB2YXJ5IiBvciAidGhlIG51bWJlciBvZiBpbmRlcGVuZGVudCBwaWVjZXMgb2YgaW5mb3JtYXRpb24gdGhhdCBnbyBpbnRvIHRoZSBlc3RpbWF0ZSBvZiBhIHBhcmFtZXRlciIuDQoNCldoZXJlICRyJCA9ICMgb2Ygcm93cyBhbmQgJGMkID0gdGhlICMgb2YgY29sdW1ucy4NCg0KU28gdG8gY2FsY3VsYXRlIHRoZSAke1xjaGl9XjIkIHRlc3Qgc3RhdGlzdGljcyBmb3IgaGFuZGVkbmVzcyBhbmQgZ2VuZGVyIG1hbnVhbGx5LCB3ZSBjYW4gZG8gdGhlIGZvbGxvd2luZyBmb3IgZWFjaCBvZiB0aGUgZm91ciB2YWx1ZXMgaW4gdGhlIHRhYmxlIChpZ25vcmluZyB0aGUgYFRvdGFsc2ApIGxpa2UgdGhpczoNCg0KJCR7XGNoaX1eMiA9ICBcZnJhY3soNDEtNDQpXjJ9ezQ0fSArIFxmcmFjeyg5LTYpXjJ9ezZ9KyBcZnJhY3soNDctNDQpXjJ9ezQ0fSsgXGZyYWN7KDMtNileMn17Nn0kJA0KDQpXaGVyZSB3ZSBjYWxjdWxhdGUgdGhlIGZyYWN0aW9uIG9mIHRoZSBzcXVhcmUgZGlmZmVyZW5jZSBvZiB0aGUgb2JzZXJ2ZWQgbWludXMgdGhlIGV4cGVjdGVkLCBkaXZpZGVkIGJ5IGV4cGVjdGVkIGZvcjogDQoNCjEuIHJpZ2h0LWhhbmRlZCBtYWxlcw0KMi4gbGVmdC1oYW5kZWQgbWFsZXMNCjMuIHJpZ2h0LWhhbmRlZCBmZW1hbGVzDQo0LiBsZWZ0LWhhbmRlZCBmZW1hbGVzDQoNCkFmdGVyIHN1bW1pbmcgdGhlc2UgaW5kaXZpZHVhbCB0ZXJtcyB0b2dldGhlciwgdGhpcyBpcyBlcXVhbCB0bw0KDQoke1xjaGl9XjIkID0gYHIgKCg0MS00NCleMikvNDQgKygoOS02KV4yKS82ICsgKCg0Ny00NCleMikvNDQgKyAoMy02KV4yLzZgDQoNCldoZXJlIHRoZSBkZWdyZWVzIG9mIGZyZWVkb20gID0gJGRmID0gKDkyLTEpKDItMSkgPSAxJA0KDQoNCldoYXQgZG9lcyB0aGlzIG1lYW4/IFdlIG5lZWQgdG8gY29uc3VsdCBhIGNoaS1zcXVhcmVkIGRpc3RyaWJ1dGlvbiB0byBkZXRlcm1pbmUgd2hhdCB0aGUgJHAkLXZhbHVlIGlzIGFuZCBpZiB0aGlzIGlzIHNpZ25pZmljYW50Lg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIkNoaS1zcXVhcmVfZGlzdHJpYnV0aW9uQ0RGLUVuZ2xpc2gucG5nIikpDQpgYGANCg0KW1tzb3VyY2VdXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DaGktc3F1YXJlZF90ZXN0Iy9tZWRpYS9GaWxlOkNoaS1zcXVhcmVfZGlzdHJpYnV0aW9uQ0RGLUVuZ2xpc2gucG5nKXt0YXJnZXQ9Il9ibGFuayJ9DQoNClRoaXMgW3dlYnNpdGVdKGh0dHA6Ly9ob21lcGFnZS5kaXZtcy51aW93YS5lZHUvfm1ib2duYXIvYXBwbGV0cy9jaGlzcS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IGhhcyBhIHNpbXBsZSB3YXkgdG8gY2hlY2sgdGhpcywgd2l0aG91dCByZXF1aXJpbmcgeW91IHRvIGdldCBvdXQgYSBydWxlciBhbmQgY29uc3VsdCB0aGlzIHBsb3QuIChOb3RlIG9uIHRoaXMgd2Vic2l0ZSB0aGUgbm90YXRpb24gZm9yICRkZiQgaXMgJHtcbnV9JC4pDQoNClBsdWdnaW5nIGluIDMuNDA5MDkxIGFzICR7XGNoaX1eMiQgYW5kIDEgYXMgJHtcbnV9JCwgd2UgZ2V0IGEgJHAkLXZhbHVlIG9mIDAuMDY0ODQuDQoNClRodXMsIHdlIGRvIG5vdCBoYXZlIGVub3VnaCBldmlkZW5jZSB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4NCg0KVGhlcmVmb3JlLCBvdXIgZGF0YSBkbyBub3QgcHJvdmlkZSBldmlkZW5jZSB0byBzdWdnZXN0IHRoYXQgZ2VuZGVyIGFuZCBoYW5kZWRuZXNzIGFyZSByZWxhdGVkLiANCg0KU2VlIGhlcmUgZm9yIGEgbW9yZSB0aG9yb3VnaCBleHBsYW5hdGlvbiBvZiB0aGUgW2NoaS1zcXVhcmVkIHRlc3RdKGh0dHBzOi8vd3d3LmxpbmcudXBlbm4uZWR1L35jbGlnaHQvY2hpc3F1YXJlZC5odG0pe3RhcmdldD0iX2JsYW5rIn0uDQoNCg0KDQo8L2RldGFpbHM+IA0KDQoNCiMjIyAqKkdlbmRlciBhbmQgTURFIEFuYWx5c2lzKioNCioqKg0KDQpOb3cgbGV0J3MgY3JlYXRlIGEgY29udGluZ2VuY3kgdGFibGUgd2l0aCBvdXIgb3duIGRhdGEgYW5kIHNlZSBob3cgd2UgY2FuIGltcGxlbWVudCB0aGlzIHRlc3QgaW4gUi4NCg0KSXQgaXMgY3JpdGljYWwgdGhhdCB3ZSB1c2UgdGhlIGNvdW50cyBkYXRhLCBhbmQgbm90IHRoZSBwZXJjZW50YWdlIGRhdGEgZm9yIG91ciBhbmFseXNpcywgYXMgdGhlICR7XGNoaX1eMiQgdGVzdCAqKnJlcXVpcmVzKiogY291bnRzLiANCg0KV2Ugd2lsbCBmaWx0ZXIgdGhlIGNvdW50IGRhdGEgZm9yIHRoZSBgTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlYCBkYXRhLCBhcyB3ZWxsIGFzIGZvciB0aGUgYE1hbGVgIGFuZCBgRmVtYWxlYCBkYXRhIGZyb20gYDIwMDRgIGFuZCBgMjAxOGAuDQoNClRoZSBmb2xsb3dpbmcgY29kZSBzdWJzZXRzIHRoZSBkYXRhIHdlIG5lZWQgYW5kIG1ha2VzIHRoZSBuZWNlc3NhcnkgbWFuaXB1bGF0aW9ucyBzbyB0aGF0IHRoZSB1bml0cyBvZiBvYnNlcnZhdGlvbiBhcmUgYXBwcm9wcmlhdGUuIA0KSWYgd2UgdGFrZSBhIGxvb2sgYXQgdGhlIHRpdGxlIG9mIHRoZSB0YWJsZSB3ZSBjYW4gc2VlIHRoYXQgdGhlIG51bWJlcnMgaW4gdGhlIHRhYmxlIHJlcHJlc2VudCBpbmRpdmlkdWFscyBieSB0aGUgdGhvdXNhbmRzLg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJkZW1fdGFibGUucG5nIikpDQpgYGANCg0KYGBge3J9DQpjaGlfc3F1YXJlZF8xMS4yYSA8LSBjb3VudHMgJT4lDQogIGZpbHRlcihkYXRhX3R5cGUgPT0gIk1ham9yX0RlcHJlc3NpdmVfRXBpc29kZSIpICU+JQ0KICBmaWx0ZXIoWWVhciAlaW4lIGMoMjAwNCwgMjAxOCkpICU+JQ0KICBmaWx0ZXIoRGVtb2dyYXBoaWMgJWluJSBjKCJNYWxlIiwgIkZlbWFsZSIpKSAlPiUNCiAgbXV0YXRlKE51bWJlciA9IE51bWJlciAqIDEwMDApICMgYmVjdWFzZSB0aGUgbnVtYmVycyBhcmUgaW4gdGhvdXNhbmRzDQpgYGANCg0KVGhlIHJlc3VsdGluZyBvYmplY3QgY29udGFpbnMgYWxsIHRoZSB2YWx1ZXMgd2UgbmVlZCBmb3Igb3V0IGNvbnRpbmdlbmN5IHRhYmxlLiANCg0KYGBge3J9DQpjaGlfc3F1YXJlZF8xMS4yYQ0KYGBgDQoNCkEgY29udGluZ2VuY3kgdGFibGUgY2FuIG5vdyBiZSBwcm9kdWNlZCBmcm9tIHRoaXMgZGF0YSAod2hpY2ggY3VycmVudGx5IGlzIGluIGxvbmcgZm9ybWF0KSBieSB0cmFuc2Zvcm1pbmcgdGhlIGRhdGEgdG8gd2lkZSBmb3JtYXQgYW5kIHJlLXB1cnBvc2luZyBzb21lIHZhbHVlcyBhcyByb3cgbmFtZXMuIA0KVG8gcmVmb3JtYXQgdGhlIGRhdGEgdG8gd2lkZSBmb3JtYXQsIHdlIGNhbiB1c2UgdGhlIGBwaXZvdF93aWRlcigpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlLg0KDQpGb3IgdGhpcyBmdW5jdGlvbiB0aGVyZSBhcmUgc2V2ZXJhbCBpbXBvcnRhbnQgYXJndW1lbnRzOiAgDQoNCjEuIGBuYW1lc19mcm9tYCAtIHRoaXMgaXMgdGhlIHZhcmlhYmxlIHdoZXJlIHRoZSBuYW1lcyBvZiBuZXcgY29sdW1ucyB3aWxsIGNvbWUgZnJvbQ0KMi4gYHZhbHVlc19mcm9tYCAtIHRoaXMgaXMgdGhlIHZhcmlhYmxlIHdoZXJlIHRoZSB2YWx1ZXMgZm9yIHRoZSBuZXcgY29sdW1ucyB3aWxsIGNvbWUgZnJvbQ0KMy4gYG5hbWVzX3ByZWZpeGAgLSBpZiB3ZSB3YW50IHRvIGFkZCBhIHByZWZpeCB0byB0aGUgbmV3IGNvbHVtbnMgd2UgY2FuIGRvIHNvIHVzaW5nIHRoaXMgYXJndW1lbnQNCg0KSW4gb3VyIGNhc2UsIHdlIHdhbnQgdG8gc3ByZWFkIG91dCB0aGUgeWVhciBkYXRhIGludG8gdHdvIGNvbHVtbnMgdGh1cyB0aGUgbmFtZXMgd2lsbCBjb21lIGZyb20gdGhlIGBZZWFyYCB2YXJpYWJsZSBhbmQgdGhlIHZhbHVlcyB3aWxsIGNvbWUgZnJvbSB0aGUgYE51bWJlcmAgdmFyaWFibGUuIA0KV2Ugd2FudCB0byBhZGQgdGhlIHdvcmQgYFllYXJgIHRvIHRoZSBuZXcgY29sdW1ucy4gDQpXZSBhbHNvIHdhbnQgdGhlIHJlbW92ZSB0aGUgYHN1Ymdyb3VwYCBhbmQgYGRhdGFfdHlwZWAgdmFyaWFibGVzIGFuZCBvbmx5IGtlZXAgdGhlIGBEZW1vZ3JhcGhpY2AsIGBZZWFyYCwgYW5kIGBOdW1iZXJgIHZhcmlhYmxlcy4gDQpUbyBkbyBzbyB3ZSBjYW4gdXNlIHRoZSBgc2VsZWN0KClgIGZ1bmN0aW9uLg0KDQojIyMjIHsucXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KVXNpbmcgd2hhdCB5b3UganVzdCBsZWFybmVkIGFib3V0IGBwaXZvdF93aWRlcigpYCBhbmQgYHNlbGVjdCgpYCBhbmQgd2l0aG91dCBzY3JvbGxpbmcgdXAsIHRyeSB0byBjb21lIHVwIHdpdGggdGhlIGNvZGUgdG8gZG8gdGhlIHdyYW5nbGluZyBmb3IgdGhpcyBkYXRhLg0KDQojIyMjDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCg0KYGBge3J9DQpjaGlfc3F1YXJlZF8xMS4yYSAlPD4lDQogIHNlbGVjdChEZW1vZ3JhcGhpYywgWWVhciwgTnVtYmVyKSAlPiUNCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgbmFtZXNfcHJlZml4ID0gIlllYXIiLCANCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gTnVtYmVyKQ0KY2hpX3NxdWFyZWRfMTEuMmENCmBgYA0KDQo8L2RldGFpbHM+DQoNCkF0IHRoaXMgcG9pbnQgd2UgaGF2ZSB0aHJlZSBjb2x1bW5zLCBidXQgdGhlIGZpcnN0IGNvbHVtbiB3ZSBvbmx5IG5lZWQgdGhlIGBNYWxlYCBhbmQgYEZlbWFsZWAgbGFiZWxzIGFuZCB3YW50IHRvIHRyZWF0IGl0IGFzIHJvdyBuYW1lcy4gDQpUbyBjb252ZXJ0IGEgY29sdW1uIHRvIHRoZSBuYW1lcyBvZiByb3dzLCB5b3UgY2FuIHVzZSB0aGUgYGNvbHVtbl90b19yb3duYW1lcygpYCBmdW5jdGlvbiBvZiB0aGUgYHRpYmJsZWAgcGFja2FnZSB0byBtYWtlIHRoZSBgRGVtb2dyYXBoaWNgIHZhcmlhYmxlIGxldmVscyBmb3IgdGhlIHJvdyBuYW1lcy4gDQpPdGhlcndpc2UsIHdlIHdvdWxkIG5lZWQgdG8gc2VsZWN0IHRoZSBudW1lcmljIGNvbHVtbnMgdG8gcGVyZm9ybSB0aGUgc3RhdHMgdGVzdC4NCg0KYGBge3J9DQpjaGlfc3F1YXJlZF8xMS4yYSAlPD4lDQogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJEZW1vZ3JhcGhpYyIpDQoNCmNoaV9zcXVhcmVkXzExLjJhDQpgYGANCg0KKipOb3RlKio6IGEgY29udGluZ2VuY3kgdGFibGUgd291bGQgdXN1YWxseSBhbHNvIGhhdmUgdG90YWxzIGZvciBhbGwgZ3JvdXBzIGFzIHdlbGwsIGJ1dCB0aGlzIGlzIG5vdCBuZWNlc3NhcnkgZm9yIHRoZSBgc3RhdHM6OmNoaXNxLnRlc3QoKWAgZnVuY3Rpb24uDQoNClRoZSBjaGktc3F1YXJlZCB0ZXN0IGZvciBpbmRlcGVuZGVuY2UgY2FuIGJlIGNvbmR1Y3RlZCB1c2luZyB0aGUgYHN0YXRzOjpjaGlzcS50ZXN0KClgIGZ1bmN0aW9uLiANCg0KYGBge3J9DQpzdGF0czo6Y2hpc3EudGVzdChjaGlfc3F1YXJlZF8xMS4yYSkNCmBgYA0KDQpXZSBzZWUgdGhhdCB0aGUgJHAkLXZhbHVlIGlzIHZlcnkgc21hbGwsIHdoaWNoIHN1Z2dlc3RzIHRoZXJlIGlzIGFuIGFzc29jaWF0aW9uIGJldHdlZW4gYEdlbmRlcmAgYW5kIHRoZSBudW1iZXIgb2YgbWFqb3IgZGVwcmVzc2l2ZSBlcGlzb2RlcyBhY3Jvc3MgdGltZSAoMjAwNCBjb21wYXJlZCB0byAyMDE4KS4gDQoNCg0KDQoNCiMjIyMgey5xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpVc2luZyB3aGF0IHlvdSBsZWFybmVkIGFib3V0IHRoZSBDaGktc3F1YXJlZCB0ZXN0LCBkZXNjcmliZSB0aGUgcmVzdWx0cyBpbiByZWZlcmVuY2UgdG8gdGhlIG51bGwgaHlwb3RoZXNpcy4NCg0KIyMjIw0KDQoNCk5vdyB0aGF0IHdlIHNlZSB0aGF0IHRoZXJlIGlzIGxpa2VseSBhbiBhc3NvY2lhdGlvbiwgd2Ugd2FudCB0byAgZGVzY3JpYmUgdGhlICoqc2l6ZSoqIG9mIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMuDQoNCldlIGNhbiB1c2UgdGhlIHByb3BfdGVzdCgpIGZ1bmN0aW9uIG9mIHRoZSBgcnN0YXRpeGAgcGFja2FnZSB0byB0ZXN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgcHJvcG9ydGlvbiBvZiB0aGUgcmVwb3J0ZWQgZXBpc29kZXMgZ2l2ZW4gYnkgbWFsZXMgaXMgdGhlIHNhbWUgZm9yIGVhY2ggeWVhci4gVGhpcyBpcyBlcXVpdmFsZW50IHRvIHRoZSBjaGktc3F1YXJlZCB0ZXN0IHdl4oCZdmUgYWxyZWFkeSBkb25lISAgUmVtZW1iZXIgdGhhdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGZvciB0aGUgY2hpLXNxdWFyZXMgdGVzdCBpcyB0aGF0IHRoZSB2YXJpYWJsZXMgYXJlIGluZGVwZW5kZW50LiBJbiB0aGlzIGNhc2UsIHRoZSBudWxsIGh5cG90aGVzaXMgaXMgdGhhdCB5ZWFyIGFuZCBnZW5kZXIgYXJlIGluZGVwZW5kZW50LiAgSWYgeWVhciBhbmQgZ2VuZGVyIGFyZSBpbmRlcGVuZGVudCwgdGhlbiB3ZeKAmWQgZXhwZWN0IG1hbGVzIHRvIGhhdmUgdGhlIHNhbWUgcHJvcG9ydGlvbiBvZiBlcGlzb2RlcyBpbiBlYWNoIG9mIHRoZSB0d28geWVhcnMg4oCTIHdoaWNoIGlzIGV4YWN0bHkgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBhIHRlc3QgY29tcGFyaW5nIHR3byBwcm9wb3J0aW9ucy4gVGhpbmtpbmcgb2Ygb3VyIHRlc3QgYXMgY29tcGFyaW5nIHR3byBwcm9wb3J0aW9ucyBpcyBoZWxwZnVsLCBiZWNhdXNlIHRoaXMgY2FuIGdpdmUgdXMgYSBbY29uZmlkZW5jZSBpbnRlcnZhbF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29uZmlkZW5jZV9pbnRlcnZhbCkgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgZGlmZmVyZW5jZXMgaW4gdGhlIHByb3BvcnRpb25zLiBTZWUgW2hlcmVdKGh0dHBzOi8vcnBrZ3MuZGF0YW5vdmlhLmNvbS9yc3RhdGl4L3JlZmVyZW5jZS9wcm9wX3Rlc3QuaHRtbCkgZm9yIG1vcmUgaW5mb3JtYXRpb24uDQoNCmBgYHtyfQ0KcHJvcF90ZXN0KGNoaV9zcXVhcmVkXzExLjJhLCBkZXRhaWxlZCA9IFRSVUUsIGNvcnJlY3QgPSBUUlVFKSAlPiUNCmdsaW1wc2UoKQ0KYGBgDQoNCkhlcmUgJG4kIGlzIHRoZSB0b3RhbCBmb3IgYm90aCBtYWxlcyBhbmQgZmVtYWxlcyBvZiBib3RoIHllYXJzLiAgDQpUaGUgJG4xJCBpcyB0aGUgdG90YWwgbiBmb3IgbWFsZXMgYWNyb3NzIGJvdGggeWVhcnMuICANClRoZSAkbjIkIGlzIHRoZSB0b3RhbCBuIGZvciBmZW1hbGVzIGFjcm9zcyBib3RoIHllYXJzLiAgDQpXZSBjYW4gc2VlIHRoYXQgdGhlIHN0YXRpc3RpYyBpcyBlcXVpdmFsZW50IHRvIHRoZSBDaGktc3F1YXJlZCBzdGF0aXN0aWMgdGhhdCB3ZSBzYXcgcHJldmlvdXNseS4gIA0KRXN0aW1hdGUgMSBpcyB0aGUgcHJvcG9ydGlvbiBvZiB0aGUgbWFsZSByZXBvcnRzIGdpdmVuIGluIDIwMDQgKG91dCBvZiB0aGUgdG90YWwgbnVtYmVyIG9mIG1hbGVzIHJlcG9ydGluZyBhbiBlcGlzb2RlIGluIDIwMDQgYW5kIDIwMTgpIGFuZCBlc3RpbWF0ZSAyIHRvIGlzIHRoZSBlcXVpdmFsZW50IGZvciBmZW1hbGVzLiAgDQoNClRodXMgZXN0aW1hdGUgMSBmb3IgbWFsZXMgaXM6IA0KJCRcdGV4dHtNYWxlc18yMDA0L01hbGVzX2JvdGhZZWFyc30gPSAoNjM3MDAwLyggNjM3MDAwICsgOTQ2MDAwKSkgPSAoNjM3MDAwLzE1ODMwMDApID0gKDYzNzAwMC9uMSkgPSAuNDAkJA0KICANCiAgDQpUaHVzIGVzdGltYXRlIDIgZm9yIGZlbWFsZXMgaXM6DQokJFx0ZXh0e0ZlbWFsZXNfMjAwNC9GZW1hbGVzX2JvdGhZZWFyc30gPSgxNTg4MDAwLygyNTM3MDAwICsgMTU4ODAwMCkpID0gKDE1ODgwMDAvKDQxMjUwMDApKSA9ICgxNTg4MDAwL24yKSA9IC4zOCQkDQogIA0KU28gb2YgYWxsIHRoZSByZXBvcnRzIGdpdmVuIGJ5IG1hbGVzIGluIHRoZXNlIHR3byB5ZWFycywgNDAlIGNhbWUgaW4gMjAwNC4gIEZvciBmZW1hbGVzLCAzOCUgb2YgdGhlIHJlcG9ydHMgY2FtZSBpbiAyMDA0LiAgVGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZ2l2ZXMgYSByYW5nZSBvZiBwbGF1c2libGUgdmFsdWVzIGZvciB0aGUgdHJ1ZSBkaWZmZXJlbmNlIGluIHRoZXNlIHByb3BvcnRpb25zIGluIHRoZSBwb3B1bGF0aW9uLiAgSXQgZ2l2ZXMgdXMgYSBzZW5zZSBvZiB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgcHJvcG9ydGlvbiBvZiByZXBvcnRzIHRoYXQgY2FtZSBpbiAyMDA0IGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXMuICANCg0KQWNjb3JkaW5nIHRvIG91ciBjb25maWRlbmNlIGludGVydmFsLCB3ZSBhcmUgOTUlIGNvbmZpZGVudCB0aGF0IHRoZSB0cnVlIGRpZmZlcmVuY2UgaW4gdGhlIHByb3BvcnRpb24gb2YgcmVwb3J0cyB0aGF0IGNhbWUgaW4gMjAwNCBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzIChvdXQgb2YgdGhlIHRvdGFsIGZvciBlYWNoKSBpcyBiZXR3ZWVuIDEuNjUlIGFuZCAxLjgzJS4gT0ssIHNvIHRoaXMgaXNuJ3QgYSBzdXBlciBsYXJnZSBjaGFuZ2UuIEJ1dCB3ZSBkbyBub3RpY2UgdGhhdCAwIGlzIG5vdCBpbiB0aGlzIGNvbmZpZGVuY2UgaW50ZXJ2YWwuICBUaGlzIG1lYW5zIHdlIGFyZSBjb25maWRlbnQgdGhhdCB0aGUgZGlmZmVyZW5jZSBpc27igJl0IDAsIHdoaWNoIHN1Z2dlc3RzIHRoYXQgdGhlcmUgaXMgaW5kZWVkIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBwcm9wb3J0aW9ucyAodGhpcyBpcyBhIHNpbWlsYXIgdG8gY2hlY2tpbmcgaWYgdGhlIHAgdmFsdWUgaXMgbGVzcyB0aGFuIDAuMDUpLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gY29uZmlkZW5jZSBpbnRlcnZhbHMgYW5kIHAtdmFsdWVzLCBzZWUgW3RoaXMgcGFwZXJdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzQxMTEwMjAvKS4gDQoNCg0KWW91IG1pZ2h0IG5vdGljZSB0aGF0IHRoZSBwcm9wb3J0aW9ucyBlc3RpbWF0ZWQgYnkgcHJvcF90ZXN0KCkgZG9u4oCZdCBxdWl0ZSBtYXRjaCB0aGUgbnVsbCBoeXBvdGhlc2lzIHdlIHN0YXRlZCBlYXJsaWVyLCB3aGljaCBzYWlkIHRoZSBwcm9wb3J0aW9uIG9mIHJlcG9ydGVkIGVwaXNvZGVzIGJ5IG1hbGVzIGlzIHRoZSBzYW1lIGluIGVhY2ggeWVhci4gIEluc3RlYWQsIHdlIHdlcmUgY29tcGFyaW5nIHRoZSBwcm9wb3J0aW9uIG9mIHJlcG9ydGVkIGVwaXNvZGVzIGluIDIwMDQgYmV0d2VlbiBtYWxlcyBhbmQgZmVtYWxlcy4gIFdlIGNhbiBnZXQgcHJvcG9ydGlvbnMgdGhhdCBtYXRjaCBvdXIgcHJldmlvdXNseSBzdGF0ZWQgbnVsbCBoeXBvdGhlc2lzIGJ5IHRyYW5zcG9zaW5nIHRoZSBjb250aW5nZW5jeSB0YWJsZSB3ZSB1c2UgdG8gaGF2ZSBNYWxlL0ZlbWFsZSBpbiB0aGUgY29sdW1ucyBhbmQgdGhlIE1hbGUvRmVtYWxlIGluIHRoZSBjb2x1bW5zIGFuZCB0aGUgeWVhcnMgaW4gdGhlIHJvd3MuIFdoZW4gd2UgZG8gdGhpcywgb3VyIHRlc3QgcmVzdWx0IHdpbGwgYmUgdGhlIHNhbWUsIHNpbmNlIGl04oCZcyB0ZXN0aW5nIGZvciBpbmRlcGVuZGVuY2Ugb2YgeWVhciBhbmQgZ2VuZGVyLCBidXQgdGhlIHByb3BvcnRpb25zIGVzdGltYXRlZCB3aWxsIGJlIHRoZSBwcm9wb3J0aW9uIG9mIG1hbGVzIChvdXQgb2YgbWFsZXMgKyBmZW1hbGVzKSBpbiAyMDA0IGFuZCB0aGUgcHJvcG9ydGlvbiBvZiBtYWxlcyAob3V0IG9mIG1hbGVzICsgZmVtYWxlcykgaW4gMjAxOC4gIA0KDQpXZSBjYW4gdXNlIHRoZSBiYXNlIGB0KClgIGZ1bmN0aW9uIHRvIHRyYW5zcG9zZSBvdXIgY29udGluZ2VuY3kgdGFibGUuIA0KDQpgYGB7cn0NCnQoY2hpX3NxdWFyZWRfMTEuMmEpIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KdChjaGlfc3F1YXJlZF8xMS4yYSkgJT4lIA0KICBwcm9wX3Rlc3QoIGRldGFpbGVkID0gVFJVRSwgY29ycmVjdCA9IFRSVUUpICU+JQ0KICBnbGltcHNlKCkNCg0KYGBgDQoNCkhlcmUgJG4kIGlzIGFnYWluIHRoZSB0b3RhbCBmb3IgYm90aCBtYWxlcyBhbmQgZmVtYWxlcyBvZiBib3RoIHllYXJzLiAgDQpOb3cgJG4xJCBpcyB0aGUgdG90YWwgbiBmb3IgbWFsZXMgYW5kIGZlbWFsZXMgaW4gMjAwNC4gIA0KVGhlICRuMiQgaXMgdGhlIHRvdGFsIG4gZm9yIG1hbGVzIGFuZCBmZW1hbGVzIGluIDIwMTguICANCldlIGNhbiBnYWluIHNlZSB0aGF0IHRoZSBzdGF0aXN0aWMgaXMgZXF1aXZhbGVudCB0byB0aGUgQ2hpLXNxdWFyZWQgc3RhdGlzdGljIHRoYXQgd2Ugc2F3IHByZXZpb3VzbHkuICANCkVzdGltYXRlIDEgaXMgdGhlIHByb3BvcnRpb24gb2YgdGhlIG1hbGUgcmVwb3J0cyBnaXZlbiBpbiAyMDA0IChvdXQgb2YgdGhlIHRvdGFsIG51bWJlciBvZiBtYWxlcyBhbmQgZmVtYWxlcyByZXBvcnRpbmcgYW4gZXBpc29kZSBpbiAyMDA0KSBhbmQgZXN0aW1hdGUgMiB0byBpcyB0aGUgZXF1aXZhbGVudCBmb3IgMjAxOC4gDQoNClRodXMgZXN0aW1hdGUgMSBpczogDQokJFx0ZXh0e01hbGVzXzIwMDQvTWFsZXNfYW5kX0ZlbWFsZXNfMjAwNH0gPSAoNjM3MDAwLyg2MzcwMDAgKyAxNTg4MDAwKSkgPSAoNjM3MDAwLzIyMjUwMDApID0gKDYzNzAwMC9uMSkgPSAuMjkkJCAgDQogIA0KVGh1cyBlc3RpbWF0ZSAyIGlzOiAgDQokJFx0ZXh0e01hbGVzXzIwMTgvTWFsZXNfYW5kX0ZlbWFsZXNfMjAxOH0gPSAoOTQ2MDAwLyg5NDYwMDAgKyAyNTM3MDAwKSkgPSAoOTQ2MDAwLzM0ODMwMDApID0gKDYzNzAwMC9uMSkgPSAuMjckJCAgDQogIA0KDQpOb3cgd2UgY2FuIGludGVycHJldCBvdXIgY29uZmlkZW5jZSBpbnRlcnZhbCBsaWtlIHNvOiB3ZSBhcmUgOTUlIGNvbmZpZGVudCB0aGF0IHRoZSBkaWZmZXJlbmNlIGluIHRoZSBwcm9wb3J0aW9uIG9mIG1hbGVzIHJlcG9ydGluZyBvdmVyIHRoZSB0d28geWVhcnMgaXMgYmV0d2VlbiAxLjM5JSBhbmQgMS41NCUuIFdlIHNlZSBhcm91bmQgMS41JSBtb3JlIG1hbGVzIHJlcG9ydGluZyBpbiAyMDA0IG91dCBvZiB0aGUgdG90YWwgcmVwb3J0cyB0aGFuIHdlIGRvIGluIDIwMTguDQoNCldlIGNhbiBhbHNvIHRha2UgYSBsb29rIGF0IG91ciBwbG90IHRvIGFzc2lzdCB3aXRoIGludGVycHJldGF0aW9uLg0KDQpUaGlzIHRpbWUgd2Ugd2lsbCBzaG93IHRoZSBzYW1lIHBsb3QgYXMgd2UgZGlkIGJlZm9yZSBidXQgZm9yIGNvdW50cyBpbnN0ZWFkIG9mIHBlcmNlbnRhZ2UuDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCg0KYGBge3J9DQoNCk1ERV9hZ2VfZ2VuZGVyX2NvdW50cyA8LQ0KICBjb3VudHMgJT4lDQogIGZpbHRlcihkYXRhX3R5cGUgPT0gIk1ham9yX0RlcHJlc3NpdmVfRXBpc29kZSIsIA0KICAgICAgICAgc3ViZ3JvdXAgIT0gIlJhY2UvRXRobmljaXR5IiwgDQogICAgICAgICBEZW1vZ3JhcGhpYyAhPSAiVE9UQUwiKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IE51bWJlciwgZ3JvdXAgPSBEZW1vZ3JhcGhpYykpICsNCiAgICBnZW9tX3JlY3QoeG1pbiA9IDIwMTEsIHhtYXggPSBJbmYsICANCiAgICAgICAgICAgICAgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYsICANCiAgICAgICAgICAgICAgZmlsbCA9ICJsaWdodCBncmF5IikgKw0KICAgIGdlb21fbGluZShhZXMoY29sb3IgPSBEZW1vZ3JhcGhpYyksIHNpemUgPTEpICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDQsIDIwMTgsIGJ5PTEpLA0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwNCwgMjAxOCwgYnk9MSksDQogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNCwgMjAxOCkpICsNCiAgICBsYWJzKHRpdGxlID0gIk1ham9yIERlcHJlc3NpdmUgRXBpc29kZVxuYW1vbmcgUGVyc29ucyBBZ2VkIDEyIHRvIDE3IiwNCiAgICAgICAgIHN1YnRpdGxlID0gIkJ5IERlbW9ncmFwaGljIENoYXJhY3RlcmlzdGljcywgUGVyY2VudGFnZXMsIDIwMDQtMjAxOCIpICsNCiAgICBmYWNldF93cmFwKH4gc3ViZ3JvdXApICsNCiAgICBvY3NfdGhlbWUoKQ0KDQpNREVfYWdlX2dlbmRlcl9jb3VudHMgPC0gZGlyZWN0LmxhYmVsKA0KICBNREVfYWdlX2dlbmRlcl9jb3VudHMsIA0KICBsaXN0KGRsLnRyYW5zKHkgPSB5ICswLjM4LCB4ID0geCAtMC4yKSwgDQogICAgICAgImZhci5mcm9tLm90aGVycy5ib3JkZXJzIiwgDQogICAgICAgY2V4ID0gLjgsDQogICAgICAgZm9udGZhY2UgPSAiYm9sZCIsDQogICAgICAgZGwubW92ZSgiQWdlOiAxNC0xNSIsIHggPSAyMDA4LCB5ID0xMCkpDQogICkgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoYWdlX2NvbF9saWdodCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZV9jb2wsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2VfY29sX2RhcmssIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGZW1hbGVfY29sLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWFsZV9jb2wpKQ0KDQpgYGANCg0KPC9kZXRhaWxzPg0KDQoNCmBgYHtyfQ0KTURFX2FnZV9nZW5kZXJfY291bnRzIA0KYGBgDQoNCg0KV2UgY2FuIHNlZSB0aGF0IHRoZSBibHVlIGxpbmUgcmVsYXRpdmUgdG8gdGhlIHN1bSBvZiB0aGUgcGluayBhbmQgYmx1ZSBsaW5lcyBpbiAyMDA0IChhYm91dCAyOSUpIGlzIGZhaXJseSBzaW1pbGFyIHRvIHRoYXQgb2YgMjAxOCAoYWJvdXQgMjclKS4gSXQgY2FuIGJlIGRpZmZpY3VsdCB0byBzZWUgcHJvcG9ydGlvbnMgYW5kIGVzcGVjaWFsbHkgYSBwcm9wb3J0aW9uYWwgZGlmZmVyZW5jZSBvZiB+ICAxLjUlIQ0KDQoNCkhvdyBhYm91dCBmb3Igc2V2ZXJlIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZXM/DQoNCiMjIyAqKkdlbmRlciBhbmQgU2V2ZXJlIE1ERSBBbmFseXNpcyoqDQoqKioNCg0KYGBge3J9DQpjaGlfc3F1YXJlZF8xMS4zYSA8LSBjb3VudHMgJT4lDQogIGZpbHRlcihkYXRhX3R5cGUgPT0gIlNldmVyZV9NYWpvcl9EZXByZXNzaXZlX0VwaXNvZGUiLCANCiAgICAgICAgIFllYXIgJWluJSBjKDIwMDYsIDIwMTgpLCANCiAgICAgICAgIERlbW9ncmFwaGljICVpbiUgYygiTWFsZSIsIkZlbWFsZSIpKSAlPiUNCiAgbXV0YXRlKE51bWJlciA9IE51bWJlciAqIDEwMDApICU+JQ0KICBzZWxlY3QoLWRhdGFfdHlwZSwgLXN1Ymdyb3VwKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFllYXIsDQogICAgICAgICAgICAgIG5hbWVzX3ByZWZpeCA9ICJZZWFyIiwgDQogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gTnVtYmVyKSAlPiUNCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJEZW1vZ3JhcGhpYyIpDQoNCmNoaV9zcXVhcmVkXzExLjNhDQpgYGANCg0KYGBge3J9DQpjaGlzcS50ZXN0KGNoaV9zcXVhcmVkXzExLjNhKQ0KYGBgDQoNClRoZXJlIGFsc28gYXBwZWFycyB0byBiZSBhbiBpbmZsdWVuY2Ugb2YgZ2VuZGVyIG9uIHRoZSByYXRlIG9mIHNldmVyZSBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGVzIGFjcm9zcyB0aGUgeWVhcnMuDQoNCg0KYGBge3J9DQp0KGNoaV9zcXVhcmVkXzExLjNhKSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCnQoY2hpX3NxdWFyZWRfMTEuM2EpICU+JSANCiAgcHJvcF90ZXN0KCBkZXRhaWxlZCA9IFRSVUUsIGNvcnJlY3QgPSBUUlVFKSAlPiUNCiAgZ2xpbXBzZSgpDQoNCmBgYA0KDQoNClRoZSBkaWZmZXJlbmNlIGluIHRoZSBwcm9wb3J0aW9ucyBvZiB0aGUgdHdvIHllYXJzIGlzIHBvc3NpYmx5IGJldHdlZW4gMC4wMTMgdG8gMC4wMTIgb3IgLTEuMyUgYW5kIC0xLjIlLiBUaGlzIHRpbWUgdGhlIHByb3BvcnRpb24gb2YgbWFsZXMgcmVwb3J0aW5nIG91dCBvZiB0aGUgdG90YWwgcmVwb3J0cyBlYWNoIHllYXIgd2FzIGxhcmdlciBpbiAyMDE4IChlc3RpbWF0ZTIgPSAyNiUpIHRoYW4gaW4gMjAwNiAoZXN0aW1hdGUxID0gMjQuNyUpLiBBZ2FpbiB0aGUgZGlmZmVyZW5jZSB3YXMgcXVpdGUgc21hbGwgYW5kIHRoZSByYW5nZSBkb2VzIG5vdCBpbmNsdWRlIDAsIHRodXMgc3VnZ2VzdGluZyB0aGF0IHRoZXJlIGlzIGluZGVlZCBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIGdlbmRlciBhbmQgYW5kIHRoZSBudW1iZXIgb2Ygc2V2ZXJlIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZXMgYWNyb3NzIHRpbWUgKDIwMDYgY29tcGFyZWQgdG8gMjAxOCkuIA0KDQoNCkhvdyBhYm91dCB0cmVhdG1lbnQ/DQoNCg0KIyMjICoqR2VuZGVyIGFuZCBUcmVhdG1lbnQgQW5hbHlzaXMqKg0KKioqDQoNCiMjIyMgey5xdWVzdGlvbl9ibG9ja30NCjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPg0KDQpUcnkgcGVyZm9ybWluZyB0aGUgc2FtZSB3cmFuZ2xpbmcgYXMgd2UgZGlkIGZvciB0aGUgcGVyY2VudGFnZSBvZiBlYWNoIGRlbW9ncmFwaGljIHRoYXQgcmVwb3J0ZWQgaGF2aW5nIGEgbWFqb3IgZGVwcmVzc2l2ZSBlcGlzb2RlIGZvciB0aGUgZGF0YSBhYm91dCB0cmVhdG1lbnQuDQoNCiMjIyMNCg0KPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHJldmVhbCB0aGUgY29kZS4gPC9zdW1tYXJ5Pg0KDQpgYGB7cn0NCmNoaV9zcXVhcmVkXzExLjRhIDwtIGNvdW50cyAlPiUNCiAgZmlsdGVyKGRhdGFfdHlwZSA9PSAiVHJlYXRtZW50IiwgDQogICAgICAgICBZZWFyICVpbiUgYygyMDA0LCAyMDE4KSwgDQogICAgICAgICBEZW1vZ3JhcGhpYyAlaW4lIGMoIk1hbGUiLCJGZW1hbGUiKSkgJT4lDQogIG11dGF0ZShOdW1iZXIgPSBOdW1iZXIgKiAxMDAwKSAlPiUNCiAgc2VsZWN0KC1kYXRhX3R5cGUsIC1zdWJncm91cCkgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZZWFyLA0KICAgICAgICAgICAgICBuYW1lc19wcmVmaXggPSAiWWVhciIsIA0KICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IE51bWJlcikgJT4lDQogIGNvbHVtbl90b19yb3duYW1lcygiRGVtb2dyYXBoaWMiKQ0KDQpjaGlfc3F1YXJlZF8xMS40YQ0KYGBgDQo8L2RldGFpbHM+DQoNCg0KYGBge3J9DQpjaGlzcS50ZXN0KGNoaV9zcXVhcmVkXzExLjRhKQ0KYGBgDQoNClRoZXJlIGFsc28gYXBwZWFycyB0byBiZSBhbiBpbmZsdWVuY2Ugb2YgZ2VuZGVyIG9uIHRoZSByYXRlIGF0IHdoaWNoIHlvdXRocyByZWNlaXZlZCB0cmVhdG1lbnQgYWNyb3NzIHRoZSB0d28geWVhcnMuDQoNCmBgYHtyfQ0KdChjaGlfc3F1YXJlZF8xMS40YSkgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQp0KGNoaV9zcXVhcmVkXzExLjRhKSAlPiUgDQogIHByb3BfdGVzdCggZGV0YWlsZWQgPSBUUlVFLCBjb3JyZWN0ID0gVFJVRSkgJT4lDQogIGdsaW1wc2UoKQ0KDQpgYGANCg0KQWdhaW4gdGhlIHZhbHVlcyBvZiBvdXIgY29uZmlkZW5jZSBpbnRlcnZhbCBzdWdnZXN0cyB0aGF0IHRoZXJlIGlzIGEgc21hbGwgZGlmZmVyZW5jZSAocm91Z2hseSAyJSBkaWZmZXJlbmNlIGluIHRoZSBwcm9wb3J0aW9uIG9mIG1hbGVzIGFjcm9zcyB0aGUgdHdvIHllYXJzIHJlY2VpdmluZyB0cmVhdG1lbnQpIGFuZCBhZ2FpbiB0aGUgcmFuZ2UgZG9lcyBub3QgY3Jvc3MgMCwgc3VnZ2VzdGluZyB0aGF0IHRoZXJlIGlzIGluZGVlZCBhIGRpZmZlcmVuY2UgaW4gdGhlIHByb3BvcnRpb25zLiANCg0KSW4gdGhpcyBjYXNlIHdlIGZpbmQgdGhhdCB0aGUgbWFsZXMgaW4gMjAwNCBtYWRlIHVwIDI3JSBvZiBhbGwgeW91dGhzIHJlcG9ydGluZyByZWNlaXZpbmcgdHJlYXRtZW50IGZvciBkZXByZXNzaW9uIHRoYXQgeWVhciwgYW5kIG1hbGVzIG1hZGUgdXAgb25seSAyNSUgb2YgdGhlIHlvdXRocyByZXBvcnRpbmcgcmVjZWl2aW5nIHRyZWF0bWVudCBpbiAyMDE4Lg0KDQoNCg0KIyMgKipTdW1tYXJ5KioNCioqKiANCg0KIyMjICoqU3VtbWFyeSBQbG90KioNCioqKg0KDQpMZXQncyBtYWtlIGEgcGxvdCB0aGF0IHN1bW1hcml6ZXMgb3VyIG1ham9yIGZpbmRpbmdzLg0KDQpXZSB3aWxsIHVzZSB0aGUgYGdnZHJhdygpYCBmdW5jdGlvbiBpbiB0aGUgYGNvd3Bsb3RgIHBhY2thZ2UuDQpUaGlzIGFsbG93cyB5b3UgdG8gYWRkIGxhYmVscyBhbmQgb3RoZXIgcGxvdCBhc3BlY3RzIG9uIHRvcCBvZiBleGlzdGluZyBwbG90cy4gDQpUaHVzIGlmIHdlIHdhbnQgdG8gYWRkIGEgdGl0bGUgZWxlbWVudCB0byBvdXIgb3ZlcmFsbCBwbG90IHRoYXQgd2Ugd2lsbCBhZGQgdG8gYSBjb21iaW5lZCBwbG90IG9mIG91ciBleGlzdGluZyBwbG90cyB3ZSBjYW4gdXNlIGBnZ2RyYXcoKWAgdG8gc3RhcnQgYW5kIHRoZW4gdGhlIGBkcmF3X2xhYmVsKClgIGZ1bmN0aW9uIHRvIGFkZCB0ZXh0LiANCg0KYGBge3J9DQp0aXRsZV9wbG90cyA8LQ0KICBnZ2RyYXcoKSArDQogIGRyYXdfbGFiZWwoDQogICAgIlNlbGYtUmVwb3J0ZWQgRGVwcmVzc2lvbiBBbW9uZyBBbWVyaWNhbiBZb3V0aHMiLA0KICAgIGZvbnRmYWNlID0gJ2JvbGQnLA0KICAgIHNpemUgPSAxOCwNCiAgICB4ID0gMCwNCiAgICBoanVzdCA9IC0wLjAxDQogICkNCmBgYA0KVGhlIGB4ID0gMGAgYXJndW1lbnQgcGxhY2VzIHRoZSB0aXRsZSBvbiB0aGUgZmFyIGxlZnQgZWRnZSBvZiB0aGUgcGxvdCBhcmVhLiANClRodXMsIGlmIHdlIHVzZSBhIHZhbHVlIG9mIC0wLjAxIGl0IHdpbGwgbW92ZSB0aGUgdGl0bGUganVzdCBhIGJpdCBhd2F5IGZyb20gdGhlIGxlZnQgZWRnZSBvZiB0aGUgcGxvdCBhcmVhLg0KDQojIyMjIHsucXVlc3Rpb25fYmxvY2t9DQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4NCg0KV2hhdCBoYXBwZW5zIGlmIHdlIG1vZGlmeSB0aGUgYGhqdXN0YCB2YWx1ZT8NCg0KDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGFuc3dlci4gPC9zdW1tYXJ5Pg0KDQpUaGUgYGhqdXN0YCBhcmd1bWVudCBtb3ZlcyB0aGUgbGFiZWwgaW4gdGhlIGhvcml6b250YWwgZGlyZWN0aW9uLiANCg0KPC9kZXRhaWxzPiANCg0KIyMjIw0KDQpXZSBjYW4gYWxzbyBtYWtlIGEgc3VidGl0bGUgaW4gdGhlIHNhbWUgd2F5LiBIZXJlLCB3ZSBjcmVhdGUgYSBzdWJ0aXRsZSBjYWxsZWQgYGZvcndhcmRgLCB3aGljaCB3ZSB3aWxsIHVzZSBsYXRlciBvbi4gDQoNCmBgYHtyfQ0KZm9yd2FyZCA8LSBnZ2RyYXcoKSArIA0KICBkcmF3X2xhYmVsKA0KICAgICJUaGUgcGVyY2VudGFnZSBvZiB5b3V0aHMgKGFnZSAxMi0xNykgZXhwZXJpZW5jaW5nIG1ham9yIGRlcHJlc3NpdmUgZXBpc29kZXMgKE1ERSkgaGFzXG5pbmNyZWFzZWQgc2luY2UgMjAxMS4gT2YgdGhlc2UgeW91dGhzLCB0aGUgcGVyY2VudGFnZSByZWNlaXZpbmcgdHJlYXRtZW50IGZvciBkZXByZXNzaW9uIGhhcyBhbHNvXG4gaW5jcmVhc2VkIGJ1dCByZW1haW5zIGxpbWl0ZWQgdG8gbGVzcyB0aGFuIDQyJS4iLA0KICAgIHNpemUgPSAxNiwNCiAgICB4ID0gMCwNCiAgICBoanVzdCA9IC0wLjAxDQogICkNCmBgYA0KDQpOZXh0LCB3ZSB3aWxsIG1vZGlmeSBzb21lIG9mIG91ciBleGlzdGluZyBwbG90cyB1c2luZyB0aGUgYHRoZW1lKClgIGZ1bmN0aW9uIGFzIHdlIGRpZCBiZWZvcmUgdG8gcmVtb3ZlIHRoZSB4LWF4aXMgdGl0bGUsIHRvIGNoYW5nZSB0aGUgY29sb3Igb2YgdGhlIGF4aXMgdGV4dCBhbmQgdGhlIHRpdGxlIHNpemUgYW5kIGNvbG9yLCBhcyB3ZWxsIGFzIGNoYW5nZSB0aGUgdGl0bGVzIG9mIHRoZSBwbG90cy4gDQoNCkZpcnN0IGxldCdzIGxvYWQgdGhlIHBsb3RzIHdlIGludGVuZCB0byB1c2U6DQpgYGB7cn0NCmxvYWQoZmlsZSA9IGhlcmU6OmhlcmUoInBsb3RzIiwgIk1ERV90b3RhbC5yZGEiKSkNCmxvYWQoZmlsZSA9IGhlcmU6OmhlcmUoInBsb3RzIiwgIlRyZWF0X3RvdGFsLnJkYSIpKQ0KbG9hZChmaWxlID0gaGVyZTo6aGVyZSgicGxvdHMiLCAiTURFX2FnZV9nZW5kZXIucmRhIikpDQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJwbG90cyIsICJNREVfcmFjZS5yZGEiKSkNCmBgYA0KDQpVc2luZyBvdXIgYE1ERV90b3RhbGAgcGxvdDogDQpgYGB7cn0NCg0KTURFX3RvdGFsX2Zvcl9tcCA8LSBNREVfdG90YWwgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSkNCmBgYA0KDQpVc2luZyBvdXIgYFRyZWF0X3RvdGFsYCBwbG90Og0KYGBge3J9DQoNCnRyZWF0X2Zvcl9tcCA8LSANCiAgVHJlYXRfdG90YWwgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSkNCg0KYGBgDQoNCg0KVXNpbmcgb3VyIGBNREVfYWdlX2dlbmRlcmAgcGxvdDoNCmBgYHtyfQ0KDQpNREVfYWdlX2dlbmRlcl9mb3JfbXAgPC0gDQogIE1ERV9hZ2VfZ2VuZGVyICsNCiAgdGhlbWUocGxvdC50aXRsZT0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIikpICsNCiAgbGFicyh0aXRsZSA9ICJPbGRlciB5b3V0aHMgYW5kIGZlbWFsZXMgcmVwb3J0IE1ERSBhdCB0aGUgaGlnaGVzdCByYXRlc1xuYW5kIHNob3cgdGhlIHN0ZWVwZXN0IGluY3JlYXNlIikgDQpgYGANCg0KRm9yIHRoaXMgbGFzdCBwbG90LCB3ZSBhbHNvIHdhbnQgdG8gZ2V0IHRoZSBsZWdlbmQgYW5kIHNhdmUgaXQgYXMgYSBzZXBhcmF0ZSBvYmplY3Qgc28gdGhhdCB3ZSBjYW4gYWRkIGl0IHRvIG91ciBwbG90IGdyaWQgaW4gYSB3YXkgdGhhdCBkb2VzIG5vdCBzaHJpbmsgdGhlIHNpemUgb2Ygb3VyIHBsb3QgdG8gYWNjb21tb2RhdGUgdGhlIGxlZ2VuZC4gDQpXZSBjYW4gdXNlIHRoZSBgZ2V0X2xlZ2VuZCgpYCBmdW5jdGlvbiBvZiB0aGUgYGNvd3Bsb3RgIHBhY2thZ2UgdG8gZG8gdGhpcy4NCldlIGNhbiBhbHNvIHNwZWNpZnkgaG93IGl0IHNob3VsZCBiZSBqdXN0aWZpZWQgdXNpbmcgYHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0pYCB0aGlzIHRha2VzIGEgbnVtYmVyIG9mIG9wdGlvbnMgaW5jbHVkaW5nIGAiY2VudGVyImAsIGAibGVmdCJgLCBhbmQgYCJyaWdodCJgLg0KDQpIb3dldmVyLCBiZWZvcmVoYW5kLCB3ZSBhbHNvIHdhbnQgdG8gY2hhbmdlIHRoZSB3YXkgdGhlIGxlZ2VuZCBpcyBkaXNwbGF5ZWQuIA0KV2UgY2FuIHVzZSB0aGUgYGd1aWRlcygpYCBmdW5jdGlvbiBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UgdG8gbW9kaWZ5IHRoZSBsZWdlbmQgdG8gc3BlY2lmeSB0aGF0IHdlIHdhbnQgdGhlIGxlZ2VuZCB0byBiZSBkaXNwbGF5ZWQgaW4gMiBjb2x1bW5zIGxpa2Ugc28gYGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChuY29sID0gMikpYC4gV2UgbmVlZCB0byBzcGVjaWZ5IHRoYXQgd2UgYXJlIG1vZGlmeWluZyB0aGUgbGVnZW5kIGZvciBjb2xvci4NCg0KYGBge3J9DQpNREVfcmFjZV9mb3JfbXBfbGVnIDwtIE1ERV9yYWNlICsNCiAgdGhlbWUocGxvdC50aXRsZT0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpICsNCiAgbGFicyh0aXRsZSA9ICJBbGwgcmFjaWFsL2V0aG5pYyBncm91cHMgc2hvdyBzaW1pbGFyXG5pbmNyZWFzZXMgc2luY2UgMjAxMSIpICsNCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAyKSkNCg0KbGVnZW5kIDwtIGdldF9sZWdlbmQoTURFX3JhY2VfZm9yX21wX2xlZyArDQogICAgICAgICAgdGhlbWUobGVnZW5kLmp1c3RpZmljYXRpb24gPSAicmlnaHQiKSkNCmBgYA0KDQpOb3csIHdlIHdpbGwgcmVtb3ZlIHRoZSBsZWdlbmQgZm9yIHRoaXMgcGxvdC4NCg0KIyMjIyB7LnF1ZXN0aW9uX2Jsb2NrfQ0KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+DQoNCkRvIHlvdSByZWNhbGwgaG93IHRvIGRvIHRoaXM/IFdpdGhvdXQgc2Nyb2xsaW5nIHVwLCBzZWUgaWYgeW91IGNhbiBmaWd1cmUgb3V0IGhvdy4NCg0KIyMjIw0KDQo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+DQoNCmBgYHtyfQ0KTURFX3JhY2VfZm9yX21wIDwtIE1ERV9yYWNlX2Zvcl9tcF9sZWcgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpgYGANCjwvZGV0YWlscz4NCg0KT0ssIG5vdyB3ZSBhcmUgcmVhZHkgdG8gc3RhcnQgcHV0dGluZyBvdXIgcGxvdHMgdG9nZXRoZXIgdXNpbmcgdGhlIGBwbG90X2dyaWQoKWAgZnVuY3Rpb24gb2YgdGhlIGBjb3dwbG90YCBwYWNrYWdlLiANCg0KSXQgaXMgaGVscGZ1bCB0byBmaXJzdCBtYWtlIHJvd3MgYnkgY29tYmluaW5nIHRoZSBwbG90cyB0aGF0IHdlIHdhbnQgdG8gYmUgZGlzcGxheWVkIG5leHQgdG8gZWFjaCBvdGhlciBhbmQgdGhlbiBjb21iaW5pbmcgdGhlc2Ugd2l0aCB0aGUgdGl0bGUgYW5kIHN1YnRpdGxlLCBjYWxsZWQgYGZvcndhcmRgLiANCg0KV2UgY2FuIHVzZSB0aGUgYHJlbF93aWR0aHNgIChyZWxhdGl2ZSBjb2x1bW4gd2lkdGgpIGFyZ3VtZW50IHRvIG1vZGlmeSBob3cgd2lkZSBlYWNoIHBsb3QgaXMgZGlzcGxheWVkLg0KRm9yIGV4YW1wbGUsIGluIGEgdHdvLWNvbHVtbiBncmlkLCBgcmVsX3dpZHRocyA9IGMoMiwgMSlgIHdvdWxkIG1ha2UgdGhlIGZpcnN0IGNvbHVtbiB0d2ljZSBhcyB3aWRlIGFzIHRoZSBzZWNvbmQgY29sdW1uLg0KDQpgYGB7cn0NCnJvd18xIDwtIHBsb3RfZ3JpZChNREVfdG90YWxfZm9yX21wLA0KICAgICAgICAgICAgICAgICAgIHRyZWF0X2Zvcl9tcCwNCiAgICAgICAgICAgICAgICAgICBucm93ID0gMSkNCg0Kcm93XzIgPC0gcGxvdF9ncmlkKE1ERV9hZ2VfZ2VuZGVyX2Zvcl9tcCwNCiAgICAgICAgICAgICAgICAgICBNREVfcmFjZV9mb3JfbXAsDQogICAgICAgICAgICAgICAgICAgbnJvdyA9IDEsIA0KICAgICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEsIDAuNikpDQpgYGANCg0KDQpOb3cgd2UgY2FuIGNvbWJpbmUgZXZlcnl0aGluZyB0b2dldGhlciB1c2luZyBgcGxvdF9ncmlkKClgIHlldCBhZ2Fpbi4gDQpOb3cgdGhhdCB3ZSBoYXZlIHJvd3MsIHdlIGNhbiBjb21iaW5lIGV2ZXJ5dGhpbmcgYXMgYSBzaW5nbGUgY29sdW1uIGFuZCBlYXNpbHkgbW9kaWZ5IHRoZSByZWxhdGl2ZSBoZWlnaHRzIHVzaW5nIHRoZSBgcmVsX2hlaWdodHMoKWAgZnVuY3Rpb24gc28gdGhhdCBvdXIgdGl0bGUsIHN1YnRpdGxlIGFuZCBsZWdlbmQgYXJlIGFsbCByZWxhdGl2ZSBzaG9ydCByZWxhdGl2ZSB0byB0aGUgcGxvdHMuIA0KV2Ugd2lsbCBtYWtlIHRoZSBmaXJzdCByb3cgaGFsZiB0aGUgaGVpZ2h0IG9mIHRoZSBzZWNvbmQgcm93LiANCg0KRmluYWxseSwgd2Ugd2lsbCB1c2UgdGhlIGBwbmcoKWAgZnVuY3Rpb24gb2YgdGhlIGBnckRldmljZXNgIHBhY2thZ2Ugd2hpY2ggaXMgYXV0b21hdGljYWxseSBsb2FkZWQgaW4gUlN0dWRpbyBzZXNzaW9ucyB0byBzYXZlIHRoZSBwbG90LiANCldlIHdpbGwgdXNlIHRoZSBgaGVyZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGhlcmVgIHBhY2thZ2UsIHRvIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRvIHNhdmUgaXQgaW4gdGhlIGBpbWdgIGRpcmVjdG9yeSBhbmQgY2FsbCBpdCBgbWFpbnBsb3QucG5nYC4NCldlIGNhbiBhbHNvIHVzZSB0aGlzIGZ1bmN0aW9uIHRvIHNwZWNpZnkgdGhlIHJlc29sdXRpb24gd2l0aCBgcmVzYCBhbmQgaW4gZG9pbmcgc28sIHdlIG5lZWQgdG8gc2F2ZSB0aGUgaW1hZ2Ugd2l0aCBzaXplIHNwZWNpZmljYXRpb25zIHRvIG1ha2UgaXQgbGFyZ2VyLiANCg0KYGBge3IsIGV2YWwgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQ0KcG5nKGZpbGVuYW1lID0gaGVyZTo6aGVyZSgiaW1nIiwgIm1haW5wbG90X29yaWcucG5nIiksIA0KICAgICAgICAgcmVzID0gMzAwLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiaW4iKQ0KcGxvdF9ncmlkKHRpdGxlX3Bsb3RzLCANCiAgICAgICAgICBmb3J3YXJkLA0KICAgICAgICAgIHJvd18xLA0KICAgICAgICAgIHJvd18yLA0KICAgICAgICAgIGxlZ2VuZCwNCiAgICAgICAgICBuY29sID0gMSwgDQogICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDAuMSwwLjIsLjgsIDEsIDAuMykpDQpkZXYub2ZmKCkNCmBgYA0KDQpUaGUgYGRldi5vZmYoKWAgZnVuY3Rpb24gaXMgbmVjZXNzYXJ5IHRvIGNsb3NlIHRoZSBncmFwaGljcyBkZXZpY2UuIFRoaXMgaXMgZ29vZCBwcmFjdGljZSB0byBhbGxvdyB5b3UgdG8gY3JlYXRlIGFub3RoZXIgcGxvdCBhZ2FpbiBsYXRlci4NCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJtYWlucGxvdF9vcmlnLnBuZyIpKQ0KYGBgDQoNCg0KT0ssIHRoaXMgbG9va3MgcHJldHR5IGdvb2QhIEJ1dCBpdCBpcyBhIGJpdCBidXN5LCBzbyB3ZSBhcmUgbm93IGdvaW5nIHRvIHJlbW92ZSB0aGUgUmFjZS9ldGhuaWNpdHkgcGxvdCBzbyBhcyB0byBzaW1wbGlmeSBvdXIgcGxvdC4NCg0KVGhpcyB0aW1lIHdlIG5lZWQgdG8gcmVjcmVhdGUgb3VyIGBNREVfYWdlX2dlbmRlcmAgcGxvdCBhZ2FpbiBiZWNhdXNlIHdlIHdhbnQgdG8gc2VwYXJhdGUgb3VyIHBsb3RzIHNvIHRoZXkgbG9vayBtb3JlIHNpbWlsYXIgdG8gdGhlIHRvdGFsIE1ERSBhbmQgdHJlYXRtZW50IHBsb3RzLiBTbyB3ZSB3aWxsIGFjdHVhbGx5IG1ha2UgdHdvIHNlcGFyYXRlIHBsb3RzLiANCg0KV2UgYWxzbyB3YW50IHRvIHJlY29kZSB0aGUgdGV4dCBmb3IgdGhlIHN0cmlwIGFib3ZlIHRoZSBwbG90IGFuZCBjaGFuZ2UgdGhlIHBsb3Qgc28gdGhhdCB0aGVyZSBhcmUgbm8gZ3JpZCBsaW5lcyBsaWtlIHRoZSBmaXJzdCByb3cgb2YgcGxvdHMuDQoNCg0KIyMjIyB7LnF1ZXN0aW9uX2Jsb2NrfQ0KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+DQoNClRyeSB0byBjb21lIHVwIHdpdGggdGhlIGNvZGUgZm9yIHRoZXNlIHBsb3RzIG9uIHlvdXIgb3duIGJlZm9yZSB5b3UgcmV2ZWFsIGl0LiBXZSBjYW4gdXNlIG91ciBgb2NzX3RoZW1lKClgIGZvciB0aGVzZSBwbG90cyB0byBtYWtlIGFsbCB0aGUgcGxvdHMgbG9vayBzaW1pbGFyLg0KDQojIyMjDQoNCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4NCg0KYGBge3J9DQoNCk1ERV9nZW5kZXIgPC1wZXJjZW50cyAlPiUNCiAgZmlsdGVyKGRhdGFfdHlwZSA9PSAiTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlIiwgDQogICAgICAgICAgc3ViZ3JvdXAgPT0gIkdlbmRlciIpICU+JQ0KICBtdXRhdGUoc3ViZ3JvdXAgPSByZWNvZGUoc3ViZ3JvdXAsICJHZW5kZXIiID0gDQogICAgICAgICAiUGVyY2VudCBvZiBlYWNoIGdlbmRlciByZXBvcnRpbmcgTURFIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gUGVyY2VudCwgZ3JvdXAgPSBEZW1vZ3JhcGhpYykpICsNCiAgZ2VvbV9yZWN0KHhtaW4gPSAyMDExLCB4bWF4ID0gSW5mLCAgDQogICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiwgIA0KICAgICAgICAgICAgZmlsbCA9ICJsaWdodCBncmF5IikgKw0KICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gRGVtb2dyYXBoaWMpLCBzaXplID0gMS41KSArDQogIGZhY2V0X3dyYXAofnN1Ymdyb3VwKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDIzKSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgyMDA0LCAyMDE4LCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygyMDA0LCAyMDE4KSkgKw0KIG9jc190aGVtZSgpICsNCiBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhGZW1hbGVfY29sLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hbGVfY29sKSkNCg0KDQoNCk1ERV9nZW5kZXI8LSBkaXJlY3QubGFiZWwoDQogIE1ERV9nZW5kZXIsIA0KICBsaXN0KGRsLnRyYW5zKHkgPSB5ICswLjM4LCB4ID0geCAtMC4yKSwgDQogICAgICAgImZhci5mcm9tLm90aGVycy5ib3JkZXJzIiwgDQogICAgICAgY2V4ID0gMSwNCiAgICAgICBmb250ZmFjZT1jKCJib2xkIikpDQogICkNCiAgICAgICANCg0KTURFX2FnZSA8LSBwZXJjZW50cyAlPiUNCiAgZmlsdGVyKGRhdGFfdHlwZSA9PSAiTWFqb3JfRGVwcmVzc2l2ZV9FcGlzb2RlIiwgDQogICAgICAgICAgc3ViZ3JvdXAgPT0gIkFnZSIpICU+JQ0KICBtdXRhdGUoc3ViZ3JvdXAgPSByZWNvZGUoc3ViZ3JvdXAsICJBZ2UiID0gDQogICAgICAgICJQZXJjZW50IG9mIGVhY2ggYWdlIGdyb3VwIHJlcG9ydGluZyBNREUiKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBQZXJjZW50LCBncm91cCA9IERlbW9ncmFwaGljKSkgKw0KICBnZW9tX3JlY3QoeG1pbiA9IDIwMTEsIHhtYXggPSBJbmYsICANCiAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCAgDQogICAgICAgICAgICBmaWxsID0gImxpZ2h0IGdyYXkiKSArDQogIGdlb21fbGluZShhZXMoY29sb3IgPSBEZW1vZ3JhcGhpYyksIHNpemUgPSAxLjUpICsNCiAgZmFjZXRfd3JhcCh+c3ViZ3JvdXApKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyMykpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDQsIDIwMTgsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzZXEoMjAwNCwgMjAxOCwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMjAwNCwgMjAxOCkpICsNCiAgb2NzX3RoZW1lKCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhhZ2VfY29sX2xpZ2h0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2VfY29sLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2VfY29sX2RhcmspKQ0KDQpNREVfYWdlIDwtIGRpcmVjdC5sYWJlbCgNCiAgTURFX2FnZSwgDQogIGxpc3QoZGwudHJhbnMoeSA9IHkgKyAwLjM4LCB4ID0geCAtMC4yKSwgDQogICAgICAgImZhci5mcm9tLm90aGVycy5ib3JkZXJzIiwgDQogICAgICAgY2V4ID0gMSwgDQogICAgICAgZm9udGZhY2U9YygiYm9sZCIpLA0KICAgICAgIGRsLm1vdmUoIkFnZTogMTItMTMiLCB4ID0gMjAxNSwgeSA9IDkpKQ0KICApDQpgYGANCg0KPC9kZXRhaWxzPg0KDQpXZSB3aWxsIGFsc28gbWFrZSBhbm90aGVyIHN1YnRpdGxlIGZvciB0aGUgZ2VuZGVyIGFuZCByYWNlIHBsb3RzLiBUaGlzIHRpbWUgd2Ugd2lsbCBhZGQgYm9sZCB0ZXh0IHRvIG91ciB0ZXh0IHVzaW5nIHRoZSBiYXNlIGBleHByZXNzaW9uKClgIGZ1bmN0aW9uIGFuZCB0aGUgYmFzZSBgcGFzdGUoKWAgZnVuY3Rpb24gd2hpY2ggYWxsb3dzIHlvdSB0byBjb21iaW5lIGNoYXJhY3RlciBzdHJpbmdzIHRvZ2V0aGVyLiBXZSBjYW4gc3BlY2lmeSB0aGF0IHdlIGRvbid0IHdhbnQgYW55IHNwYWNlcyBvciBjaGFyYWN0ZXIgZm9yIG91ciBzZXBhcmF0b3IuDQoNCmBgYHtyfQ0KbGFiZWwgPC0gZXhwcmVzc2lvbihwYXN0ZSgNCiAgICBib2xkKCJPbGRlciAiKSwNCiAgICAieW91dGhzIGFuZCAiLA0KICAgIGJvbGQoImZlbWFsZXMgIiksDQogICAgInJlcG9ydCBNREUgYXQgdGhlIGhpZ2hlc3QgcmF0ZSBhbmQgYWxzbyBzaG93IHRoZSBzdGVlcGVzdCBpbmNyZWFzZS4iKSwgc2VwID0gIiIpDQoNCmZvcndhcmQyIDwtIGdnZHJhdygpICsgDQogIGRyYXdfbGFiZWwobGFiZWwsDQogICAgc2l6ZSA9IDE2LA0KICAgIHggPSAwLA0KICAgIGhqdXN0ID0gLTAuMDENCiAgKQ0KYGBgDQoNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0NCg0Kcm93XzIgPC0gcGxvdF9ncmlkKE1ERV9hZ2UsIE1ERV9nZW5kZXIsDQogICAgICAgICAgICAgICAgICAgbnJvdyA9IDEpDQoNCnBuZyhmaWxlbmFtZSA9IGhlcmU6OmhlcmUoImltZyIsICJtYWlucGxvdC5wbmciKSwgDQogICAgICAgICByZXMgPSAzMDAsIHdpZHRoID0gMTAsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJpbiIpDQpwbG90X2dyaWQodGl0bGVfcGxvdHMsIA0KICAgICAgICAgIGZvcndhcmQsDQogICAgICAgICAgcm93XzEsDQogICAgICAgICAgZm9yd2FyZDIsDQogICAgICAgICAgcm93XzIsDQogICAgICAgICAgbmNvbCA9IDEsIA0KICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjEsIDAuMiwgMSwgMC4xLCAxKSkNCmRldi5vZmYoKQ0KYGBgDQoNCg0KYGBge3IsZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIm1haW5wbG90LnBuZyIpKQ0KYGBgDQoNCiMjIyAqKlN5bm9wc2lzKioNCioqKg0KDQpJbiB0aGlzIGNhc2Ugc3R1ZHkgd2UgZXZhbHVhdGVkIHNlbGYtcmVwb3J0ZWQgbWVhc3VyZXMgb2YgZGVwcmVzc2lvbiBzeW1wdG9tcyBhbW9uZyB5b3V0aHMgYWdlIDEyLTE3IGluIHRoZSBVbml0ZWQgU3RhdGVzLCBhcyB3ZWxsIGFzIHRoZSByYXRlIG9mIHlvdXRocyByZWNlaXZpbmcgdHJlYXRtZW50IGZvciBkZXByZXNzaW9uLiANCldlIGxlYXJuZWQgaG93IHRvIHNjcmFwZSBkYXRhIGRpcmVjdGx5IGZyb20gdGhlIHdlYiB1c2luZyB0aGUgYHJ2ZXN0YCBwYWNrYWdlIGFuZCB3ZSBsZWFybmVkIGhvdyB0byBwZXJmb3JtIGFuZCBpbnRlcnByZXQgYSBjaGktc3F1YXJlIHRlc3QgdXNpbmcgdGhlIGBjaGlzcS50ZXN0KClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RhdHNgIHBhY2thZ2UuDQoNCkJ5IGFuYWx5emluZyBhbmQgcGxvdHRpbmcgb3VyIGRhdGEsIGl0IGlzIGNsZWFyIHRoYXQgZGVwcmVzc2lvbiByYXRlcyBhcHBlYXIgdG8gYmUgaW5jcmVhc2luZywgcGFydGljdWxhcmx5IHNpbmNlIDIwMTEuIA0KSG93ZXZlciwgaXQgaXMgcG9zc2libGUgdGhhdCByZXNwb25kZW50cyBoYWQgc2ltaWxhciByYXRlcyBpbiBwcmV2aW91cyB5ZWFycywgYnV0IG5vdyBmZWVsIGxlc3Mgc3RpZ21hIGFib3V0IHJlc3BvbmRpbmcgYWJvdXQgZGVwcmVzc2lvbiBzeW1wdG9tcyB3aGVuIGZpbGxpbmcgb3V0IHRoZSBzdXJ2ZXkuIA0KVGhlIHN1cnZleSBoYXMgYWx3YXlzIGJlZW4gYW5vbnltb3VzLCBidXQgW3JlcG9ydGluZyBiaWFzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TZWxmLXJlcG9ydF9zdHVkeSM6fjp0ZXh0PVNlbGYlMkRyZXBvcnQlMjBzdHVkaWVzJTIwYXJlJTIwaW5oZXJlbnRseSxhbnN3ZXJzJTIwd2lsbCUyMGJlJTIwbW9yZSUyMHBvc2l0aXZlLil7dGFyZ2V0PSJfYmxhbmsifSBjYW4gc29tZXRpbWVzIGNhdXNlIGluZGl2aWR1YWxzIHRvIGV4YWdnZXJhdGUgb3IgbWluaW1pemUgdGhlaXIgc3ltcHRvbXMgYmVjYXVzZSBvZiB3aGF0IHRoZXkgdGhpbmsgcmVzZWFyY2hlcnMgd2FudCB0aGVpciByZXNwb25zZSB0byBiZSBvciBvdXQgb2Ygc2hhbWUgb3IgZW1iYXJyYXNzbWVudCwgYW1vbmcgb3RoZXIgcmVhc29ucy4gDQpIb3dldmVyLCB0aGUgZGF0YSBzdWdnZXN0cyB0aGF0IHlvdXRocyBtYXkgYmUgZXhwZXJpZW5jaW5nIG1vcmUgc3ltcHRvbXMgb2YgZGVwcmVzc2lvbiBhbmQgdGhhdCB0aGUgcmF0ZSBvZiBpbmNyZWFzZSBpcyBxdWl0ZSBoaWdoLiANCg0KTmVhcmx5IGEgcXVhcnRlciBvZiBhbGwgaW5kaXZpZHVhbHMgdGhhdCB3ZXJlIGZlbWFsZSBhbmQgb2YgYWdlIDEyLTE3IHJlcG9ydGVkIGV4cGVyaWVuY2luZyBzeW1wdG9tcyBvZiBkZXByZXNzaW9uLiANClRoaXMgd2FycmFudHMgZnVydGhlciBpbnZlc3RpZ2F0aW9uIHRvIHNlZSBpZiB0aGlzIGlzIGEgcHJvZHVjdCBvZiBtb3JlIHJlcG9ydGluZyBvciBpZiBpbmRlZWQgQW1lcmljYW4gZmVtYWxlcyBhcmUgdHJ1bHkgbW9yZSBkZXByZXNzZWQuIA0KRnVydGhlcm1vcmUsIGlmIHRoZXkgYXJlIGluZGVlZCBtb3JlIGRlcHJlc3NlZCwgaW52ZXN0aWdhdGlvbiBhYm91dCB3aHkgeW91bmcgZmVtYWxlcyBhcmUgbW9yZSBkZXByZXNzZWQgaXMgYWxzbyBvZiBjcml0aWNhbCBpbXBvcnRhbmNlLiANCk9uZSBpbXBvcnRhbnQgbGltaXRhdGlvbiBpcyB0aGF0IHRoZSBkYXRhIGRvZXMgbm90IGluY2x1ZGUgc3ViZ3JvdXAgaW50ZXJzZWN0aW9ucywgc3VjaCBhcyByYXRlcyBvZiBtYWpvciBkZXByZXNzaXZlIGVwaXNvZGVzIGFtb25nIGZlbWFsZXMgb2YgdmFyaW91cyBldGhuaWMgYmFja2dyb3VuZHMuIA0KDQpDb25zaWRlcmluZyB0aGUgdmVyeSBzdGVlcCBpbmNyZWFzZSBpbiBmZW1hbGVzLCB0aGlzIHdhcnJhbnRzIGZ1cnRoZXIgaW52ZXN0aWdhdGlvbiBhYm91dCB3aGljaCBmZW1hbGVzIGFyZSBwYXJ0aWN1bGFybHkgdnVsbmVyYWJsZSBhbmQgd2h5LiANCg0KDQojIyAqKkhvbWV3b3JrKioNCioqKiANCg0KQXNrIHN0dWRlbnRzIHRvIHNjcmFwZSBUYWJsZXMgMTEuNUEgYW5kIDExLjVCIGZyb20gdGhlIHdlYnNpdGUsIHdoaWNoIGNvbnRhaW4gZGF0YSBhYm91dCB0aGUgcmVjZWlwdCBvZiB0cmVhdG1lbnQgYW1vbmcgeW91dGhzIHdobyByZXBvcnRlZCBoYXZpbmcgYSBzZXZlcmUgZXBpc29kZS4gQXNrIHN0dWRlbnRzIHRvIGNyZWF0ZSBwbG90cyBhbmQgcGVyZm9ybSBDaGktc3F1YXJlIHRlc3RzIHRvIGV2YWx1YXRlIGhvdyBncm91cHMgY29tcGFyZSBvdmVyIHRpbWUuDQoNCg0KIyMgKipBZGRpdGlvbmFsIEluZm9ybWF0aW9uKioNCioqKg0KDQojIyMgKipIZWxwZnVsIExpbmtzKioNCioqKg0KDQpbUlN0dWRpb10oaHR0cHM6Ly9yc3R1ZGlvLmNvbS9wcm9kdWN0cy9yc3R1ZGlvL2ZlYXR1cmVzLyl7dGFyZ2V0PSJfYmxhbmsifSAgDQpbQ2hlYXRzaGVldCBvbiBSU3R1aWRvIElERV0oaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vY2hlYXRzaGVldHMvcmF3L21hc3Rlci9yc3R1ZGlvLWlkZS5wZGYpe3RhcmdldD0iX2JsYW5rIn0gIA0KW090aGVyIFJTdHVkaW8gY2hlYXRzaGVldHNdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLyl7dGFyZ2V0PSJfYmxhbmsifSAgIA0KW1RpZHl2ZXJzZV0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICANCltTZWxlY3Rpb24gYmlhc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2VsZWN0aW9uX2JpYXM/b2xkZm9ybWF0PXRydWUpe3RhcmdldD0iX2JsYW5rIn0gIA0KW1NhbXBsaW5nIG1ldGhvZHNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NhbXBsaW5nXyhzdGF0aXN0aWNzKT9vbGRmb3JtYXQ9dHJ1ZSl7dGFyZ2V0PSJfYmxhbmsifSAgIA0KW1NhbXBsaW5nIGZyYW1lXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TYW1wbGluZ19mcmFtZT9vbGRmb3JtYXQ9dHJ1ZSl7dGFyZ2V0PSJfYmxhbmsifSAgDQpbRFNNIDVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0RTTS01KXt0YXJnZXQ9Il9ibGFuayJ9PC9zdW1tYXJ5PiAgICANCltOYXRpb25hbCBTdXJ2ZXkgb24gRHJ1ZyBVc2UgYW5kIEhlYWx0aCAoTlNEVUgpXShodHRwczovL25zZHVod2ViLnJ0aS5vcmcvcmVzcHdlYi9ob21lcGFnZS5jZm0pe3RhcmdldD0iX2JsYW5rIn0gICANCltTdWJzdGFuY2UgQWJ1c2UgYW5kIE1lbnRhbCBIZWFsdGggU2VydmljZXMgQWRtaW5pc3RyYXRpb24gKFNBTUhTQSldKGh0dHBzOi8vd3d3LnNhbWhzYS5nb3YvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgDQpbVS5TLiBEZXBhcnRtZW50IG9mIEhlYWx0aCBhbmQgSHVtYW4gU2VydmljZXMgKERISFMpXShodHRwczovL3d3dy5oaHMuZ292Lyl7dGFyZ2V0PSJfYmxhbmsifSAgIA0KW05TRFVIIFN1cnZleSBSZXN1bHRzIFdlYnNpdGVdKGh0dHBzOi8vd3d3LnNhbWhzYS5nb3YvZGF0YS9zaXRlcy9kZWZhdWx0L2ZpbGVzL2NiaHNxLXJlcG9ydHMvTlNEVUhEZXRhaWxlZFRhYnMyMDE4UjIvTlNEVUhEZXRUYWJzU2VjdDExcGUyMDE4Lmh0bSl7dGFyZ2V0PSJfYmxhbmsifSAod2hlcmUgd2UgZ290IHRoZSBkYXRhIGZvciB0aGlzIGNhc2Ugc3R1ZHkpICAgIA0KW0RldGFpbHMgYWJvdXQgdGhlIFN1cnZleV0oaHR0cHM6Ly9uc2R1aHdlYi5ydGkub3JnL3Jlc3B3ZWIvYWJvdXRfbnNkdWguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgDQpbUmVwb3J0IGFib3V0IHRoZSAyMDE4IE5TRFVIIFN1cnZleV0oaHR0cHM6Ly93d3cuc2FtaHNhLmdvdi9kYXRhL3NpdGVzL2RlZmF1bHQvZmlsZXMvY2Joc3EtcmVwb3J0cy9OU0RVSERldGFpbGVkVGFiczIwMThSMi9OU0RVSERldGFpbGVkVGFiczIwMTgucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICANCltXZWIgc2NyYXBpbmddKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1dlYl9zY3JhcGluZz9vbGRmb3JtYXQ9dHJ1ZSl7dGFyZ2V0PSJfYmxhbmsifSAgDQpbU2VsZWN0b3JnYWRnZXQgVG9vbF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3J2ZXN0L3ZpZ25ldHRlcy9zZWxlY3RvcmdhZGdldC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICANClNlZSB0aGlzIFtibG9nIHBvc3RdKGh0dHA6Ly9yZXNlYXJjaC5saWJkLm9yZy9yc3RhdHNjbHViL3Bvc3QvaW50cm9kdWN0aW9uLXRvLXNjcmFwaW5nLWFuZC13cmFuZ2luZy10YWJsZXMtZnJvbS1yZXNlYXJjaC1hcnRpY2xlcy8jLlh3ODc4Wk5LaFFKKXt0YXJnZXQ9Il9ibGFuayJ9LCB0aGlzIFtibG9nIHBvc3RdKGh0dHA6Ly9ibG9nLmNvcnluaXNzZW4uY29tLzIwMTUvMDEvdXNpbmctcnZlc3QtdG8tc2NyYXBlLWh0bWwtdGFibGUuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSwgYW5kIHRoaXMgW3ZpZ25ldHRlXShodHRwczovL3JzdHVkaW8tcHVicy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS8yNjY0MzBfZjNmZDQ2NjBiMjc0NDc1MWFiMTQ0YWExMzA3NjhhMDYuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB3ZWIgc2NyYXBpbmcgIA0KW0NTUyBzZWxlY3RvcnMgdHV0b3JpYWxdKGh0dHA6Ly9mbHVrZW91dC5naXRodWIuaW8vIyl7dGFyZ2V0PSJfYmxhbmsifSAoYW5kIHRoZSBbYW5zd2Vyc10oaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vY2hyaXNtYW4vZmNiMGE4ODQ1OWNkOTgyMzlkYmU2ZDJkMjAwYjAyZDEpe3RhcmdldD0iX2JsYW5rIn0pICAgICANCltQaXBpbmcgaW4gUl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgDQpbV3JpdGluZyBmdW5jdGlvbnNdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZnVuY3Rpb25zLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0NCkFsc28gc2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtdmFwaW5nLWNhc2Utc3R1ZHkvKXt0YXJnZXQ9Il9ibGFuayJ9ICBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB3cml0aW5nIGZ1bmN0aW9ucy4gICANCltTdHJpbmcgbWFuaXB1bGF0aW9uIGNoZWF0c2hlZXRdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLyl7dGFyZ2V0PSJfYmxhbmsifSAgDQpbVGFibGUgZm9ybWF0c10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvV2lkZV9hbmRfbmFycm93X2RhdGEpe3RhcmdldD0iX2JsYW5rIn0NCltQZWFyc29uJ3MgY2hpLXNxdWFyZWQgdGVzdF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUGVhcnNvbiUyN3NfY2hpLXNxdWFyZWRfdGVzdCM6fjp0ZXh0PVBlYXJzb24ncyUyMGNoaSUyRHNxdWFyZWQlMjB0ZXN0JTIwaXMsZGlmZmVycyUyMGZyb20lMjBhJTIwdGhlb3JldGljYWwlMjBkaXN0cmlidXRpb24uKXt0YXJnZXQ9Il9ibGFuayJ9ICANCltjb250aW5nZW5jeSB0YWJsZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29udGluZ2VuY3lfdGFibGUpe3RhcmdldD0iX2JsYW5rIn0gIA0KW0NoaS1zcXVhcmVkIGRpc3RyaWJ1dGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ2hpLXNxdWFyZWRfdGVzdCMvbWVkaWEvRmlsZTpDaGktc3F1YXJlX2Rpc3RyaWJ1dGlvbkNERi1FbmdsaXNoLnBuZyl7dGFyZ2V0PSJfYmxhbmsifSAgDQpbY2hpLXNxdWFyZSBkaXN0cmlidXRpb24gYXBwbGV0XShodHRwOi8vaG9tZXBhZ2UuZGl2bXMudWlvd2EuZWR1L35tYm9nbmFyL2FwcGxldHMvY2hpc3EuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgDQpTZWUgaGVyZSBmb3IgYSBtb3JlIHRob3JvdWdoIGV4cGxhbmF0aW9uIG9mIHRoZSBbY2hpLXNxdWFyZSB0ZXN0XShodHRwczovL3d3dy5saW5nLnVwZW5uLmVkdS9+Y2xpZ2h0L2NoaXNxdWFyZWQuaHRtKXt0YXJnZXQ9Il9ibGFuayJ9ICAgDQpbYGdncGxvdDJgIHBhY2thZ2VdKGh0dHA6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcpe3RhcmdldD0iX2JsYW5rIn0gICAgDQpQbGVhc2Ugc2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9vY3MtYnAtY28yLWVtaXNzaW9ucy8pe3RhcmdldD0iX2JsYW5rIn0gIGZvciBtb3JlIGRldGFpbHMgb24gdXNpbmcgYGdncGxvdDJgLiANCltncmFtbWFyIG9mIGdyYXBoaWNzXShodHRwOi8vdml0YS5oYWQuY28ubnovcGFwZXJzL2xheWVyZWQtZ3JhbW1hci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICANCltgZ2dwbG90MmAgdGhlbWVzXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2d0aGVtZS5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgDQpbYGRpcmVjdGxhYmVsc2AgcGFja2FnZSBtZXRob2RzXShodHRwOi8vZGlyZWN0bGFiZWxzLnItZm9yZ2Uuci1wcm9qZWN0Lm9yZy9kb2NzL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gIA0KW1ZpcmlkaXMgcGFsZXR0ZSBmb3IgY29sb3JibGluZCBmcmllbmRseSBwbG90c10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3ZpcmlkaXMvdmlnbmV0dGVzL2ludHJvLXRvLXZpcmlkaXMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgDQpbTW90aXZhdGluZyBhcnRpY2xlIGZvciB0aGlzIGNhc2Ugc3R1ZHkgYWJvdXQgZGVwcmVzc2lvbiByYXRlc10oaHR0cHM6Ly9wdWJtZWQubmNiaS5ubG0ubmloLmdvdi8zMDg2OTkyNy8pe3RhcmdldD0iX2JsYW5rIn0gKEFjY2VzcyBpcyBwb3NzaWJsZSBmb3IgdGhvc2UgYXQgSG9wa2lucyBieSB1c2luZyB0aGVpciBlbWFpbCBhZGRyZXNzKSAgICANCg0KW01vdGl2YXRpbmcgYXJ0aWNsZSBhYm91dCB0aGUgcmF0ZSBvZiB5b3V0aHMgc2Vla2luZyBtZW50YWwgaGVhbHRoIHNlcnZpY2VzXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzI0Mjg1MzgyLyl7dGFyZ2V0PSJfYmxhbmsifSAgICANCg0KW0Nyb3NzLWN1bHR1cmFsIHJldmlldyBhcnRpY2xlIGFib3V0IHBvc3NpYmxlIGNhdXNlcyBmb3IgaW5jcmVhc2VkIGRlcHJlc3Npb25dKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzMzMzAxNjEvKXt0YXJnZXQ9Il9ibGFuayJ9DQoNCltSZXZpZXcgYXJ0aWNsZSBhYm91dCBzb2NpYWwgbWVkaWEgYW5kIGRlcHJlc3Npb25dKGh0dHBzOi8vY2hpbGRtaW5kLm9yZy9hcnRpY2xlL2lzLXNvY2lhbC1tZWRpYS11c2UtY2F1c2luZy1kZXByZXNzaW9uLyl7dGFyZ2V0PSJfYmxhbmsifQ0KDQoNCjx1PioqUGFja2FnZXMgdXNlZCBpbiB0aGlzIGNhc2Ugc3R1ZHk6KiogPC91Pg0KDQogUGFja2FnZSAgIHwgVXNlIGluIHRoaXMgY2FzZSBzdHVkeSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tDQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YSAgDQpbcnZlc3RdKGh0dHBzOi8vZ2l0aHViLmNvbS90aWR5dmVyc2UvcnZlc3Qpe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHNjcmFwZSB3ZWIgcGFnZXMgIA0KW2RwbHlyXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBzdWJzZXQgYW5kIGZpbHRlciB0aGUgZGF0YSBmb3Igc3BlY2lmaWMgZ3JvdXBzLCB0byByZXBsYWNlIHNwZWNpZmljIHZhbHVlcyB3aXRoIGBOQWAsIHJlbmFtZSB2YXJpYWJsZXMsICBhbmQgcGVyZm9ybSBmdW5jdGlvbnMgb24gbXVsdGlwbGUgdmFyaWFibGVzICAgICANClttYWdpY2tdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdpY2svdmlnbmV0dGVzL2ludHJvLmh0bWwjS2VybmVsX2NvbnZvbHV0aW9uKSAgICAgIHwgdG8gY3JlYXRlIGEgZ2lmICAgDQpbbWFncml0dHJdKGh0dHBzOi8vbWFncml0dHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHVzZSBhbmQgcmVhc3NpZ24gZGF0YSBvYmplY3RzIHVzaW5nIHRoZSAlPD4lcGlwZSBvcGVyYXRvciAgDQpbc3RyaW5ncl0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBtYW5pcHVsYXRlIHN0cmluZ3MgIA0KW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBjaGFuZ2UgdGhlIHNoYXBlIG9yIGZvcm1hdCBvZiB0aWJibGVzIHRvIHdpZGUgYW5kIGxvbmcgIA0KW3RpYmJsZV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGNyZWF0ZSB0aWJibGVzIGFuZCBjb252ZXJ0IHZhbHVlcyBvZiBhIGNvbHVtbiB0byByb3cgbmFtZXMgIA0KW3B1cnJyXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gYXBwbHkgYSBmdW5jdGlvbiB0byBlYWNoIGNvbHVtbiBvZiBhIHRpYmJsZSBvciBlYWNoIHRpYmJsZSBpbiBhIGxpc3QgICAgIA0KW2dncGxvdDJdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gY3JlYXRlIHBsb3RzICANCltkaXJlY3RsYWJlbHNdKGh0dHA6Ly9kaXJlY3RsYWJlbHMuci1mb3JnZS5yLXByb2plY3Qub3JnL2RvY3MvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gYWRkIGxhYmVscyBkaXJlY3RseSB0byBsaW5lcyBpbiBwbG90cyAgDQpbc2NhbGVzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc2NhbGVzL3NjYWxlcy5wZGYpICB8IHRvIGdldCB0aGUgY3VycmVudCBsaW5ldHlwZSBvcHRpb25zICANCltmb3JjYXRzXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHJlb3JkZXIgZmFjdG9yIGZvciBwbG90DQpbZ2d0aGVtZXNdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3RoZW1lcy9nZ3RoZW1lcy5wZGYpIHwgdG8gY3JlYXRlIGEgcGxvdCB0byBzZWUgd2hhdCB0aGUgZGlmZmVyZW50IGxpbmV0eXBlcyBsb29rIGxpa2UgIA0KW3JzdGF0aXhdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yc3RhdGl4L3JzdGF0aXgucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gcHJlZm9ybSBwcm9wb3J0aW9uIHRlc3QgICANCltjb3dwbG90XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvY293cGxvdC92aWduZXR0ZXMvaW50cm9kdWN0aW9uLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGNvbWJpbmUgcGxvdHMgdG9nZXRoZXIgDQoNCiMjIyMgey5lbXBoYXNpc19ibG9ja30NCklmIHlvdSBhcmUgaW4gY3Jpc2lzIGFuZCBuZWVkIGhlbHAsIGNhbGwgdGhpcyB0b2xsLWZyZWUgbnVtYmVyIGZvciB0aGUgKipOYXRpb25hbCBTdWljaWRlIFByZXZlbnRpb24gTGlmZWxpbmUgKE5TUEwpKiosIGF2YWlsYWJsZSAyNCBob3VycyBhIGRheSwgZXZlcnkgZGF5OiAqKjEtODAwLTI3My1UQUxLICg4MjU1KSoqLiBUaGUgc2VydmljZSBpcyBhdmFpbGFibGUgdG8gZXZlcnlvbmUuIFRoZSBkZWFmIGFuZCBoYXJkIG9mIGhlYXJpbmcgY2FuIGNvbnRhY3QgdGhlIExpZmVsaW5lIHZpYSBUVFkgYXQgMS04MDAtNzk5LTQ4ODkuIEFsbCBjYWxscyBhcmUgY29uZmlkZW50aWFsLiBZb3UgY2FuIGFsc28gdmlzaXQgdGhlIExpZmVsaW5l4oCZcyB3ZWJzaXRlIGF0IFt3d3cuc3VpY2lkZXByZXZlbnRpb25saWZlbGluZS5vcmddKHd3dy5zdWljaWRlcHJldmVudGlvbmxpZmVsaW5lLm9yZyl7dGFyZ2V0PSJfYmxhbmsifS4NCg0KVGhlICoqQ3Jpc2lzIFRleHQgTGluZSoqIGlzIGFub3RoZXIgZnJlZSwgY29uZmlkZW50aWFsIHJlc291cmNlIGF2YWlsYWJsZSAyNCBob3VycyBhIGRheSwgc2V2ZW4gZGF5cyBhIHdlZWsuIFRleHQg4oCcSE9NReKAnSB0byAqKjc0MTc0MSoqIGFuZCBhIHRyYWluZWQgY3Jpc2lzIGNvdW5zZWxvciB3aWxsIHJlc3BvbmQgdG8geW91IHdpdGggc3VwcG9ydCBhbmQgaW5mb3JtYXRpb24gb3ZlciB0ZXh0IG1lc3NhZ2UuIFZpc2l0IFt3d3cuY3Jpc2lzdGV4dGxpbmUub3JnXSh3d3cuY3Jpc2lzdGV4dGxpbmUub3JnKXt0YXJnZXQ9Il9ibGFuayJ9Lg0KDQojIyMjDQoNCkFsc28gc2VlIFtoZXJlXShodHRwczovL3d3dy5taGFuYXRpb25hbC5vcmcvZGVwcmVzc2lvbi10ZWVucy0wKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGhvdyB0byByZWNvZ25pemUgYW5kIGhlbHAgeW91dGhzIGV4cGVyaWVuY2luZyBzeW1wdG9tcyBvZiBkZXByZXNzaW9uDQoNCiMjIyAqKlNlc3Npb24gaW5mbyoqDQoqKioNCg0KYGBge3J9DQpzZXNzaW9uSW5mbygpDQpgYGANCg0KKipFc3RpbWF0ZSBvZiBSTWFya2Rvd24gQ29tcGlsYXRpb24gVGltZTogKioNCg0KYGBge3IsIGVjaG89RkFMU0V9DQpybWFya2Rvd246OjpwZXJmX3RpbWVyX3N0b3AoInJlbmRlciIpDQpwdHMgPSBybWFya2Rvd246OjpwZXJmX3RpbWVyX3N1bW1hcnkoKQ0KY2F0KCJBYm91dCIsIHJvdW5kKHB0cyR0aW1lWzFdLzEwMDAgKyA1KSwgIi0iLCByb3VuZChwdHMkdGltZVsxXS8xMDAwICsgMTUpLCJzZWNvbmRzIikNCmBgYA0KDQpUaGlzIGNvbXBpbGF0aW9uIHRpbWUgd2FzIG1lYXN1cmVkIG9uIGEgUEMgbWFjaGluZSBvcGVyYXRpbmcgb24gV2luZG93cyAxMC4gVGhpcyByYW5nZSBzaG91bGQgb25seSBiZSB1c2VkIGFzIGFuIGVzdGltYXRlIGFzIGNvbXBpbGF0aW9uIHRpbWUgd2lsbCB2YXJ5IHdpdGggZGlmZmVyZW50IG1hY2hpbmVzIGFuZCBvcGVyYXRpbmcgc3lzdGVtcy4gDQoNCiMjIyAqKkFja25vd2xlZGdtZW50cyoqDQoqKioNCg0KV2Ugd291bGQgbGlrZSB0byBhY2tub3dsZWRnZSBbVGFtYXIgTWVuZGVsc29uXShodHRwczovL3d3dy5qaHNwaC5lZHUvZmFjdWx0eS9kaXJlY3RvcnkvcHJvZmlsZS8xNzcwL3RhbWFyLW1lbmRlbHNvbil7dGFyZ2V0PSJfYmxhbmsifSBmb3IgYXNzaXN0aW5nIGluIGZyYW1pbmcgdGhlIG1ham9yIGRpcmVjdGlvbiBvZiB0aGUgY2FzZSBzdHVkeS4NCg0KV2Ugd291bGQgbGlrZSB0byBhY2tub3dsZWRnZSBbUWllciBNZW5nXShodHRwczovL3d3dy5vcGVuY2FzZXN0dWRpZXMub3JnL2F1dGhvcnMvcW1lbmcvKSBhbmQgW01pY2hhZWwgQnJlc2hvY2tdKGh0dHBzOi8vbWJyZXNob2NrLmdpdGh1Yi5pby8pIGZvciB0aGVpciBjb250cmlidXRpb25zIHRvIHRoaXMgY2FzZSBzdHVkeS4gDQoNCldlIHdvdWxkIGFsc28gbGlrZSB0byBhY2tub3dsZWRnZSB0aGUgW0Jsb29tYmVyZyBBbWVyaWNhbiBIZWFsdGggSW5pdGlhdGl2ZV0oaHR0cHM6Ly9hbWVyaWNhbmhlYWx0aC5qaHUuZWR1Lyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgZnVuZGluZyB0aGlzIHdvcmsuIA0KDQoNCjxzY3JpcHQgdHlwZT0ndGV4dC9qYXZhc2NyaXB0JyBpZD0nY2x1c3RybWFwcycgc3JjPScvL2Nkbi5jbHVzdHJtYXBzLmNvbS9tYXBfdjIuanM/Y2w9MDgwODA4Jnc9YSZ0PXR0JmQ9VjFRWkxWWWhkUEtrSkFMcHQ4enA2OEh4czFxT1hTRVZnRXlsTDlnRnM5ZyZjbz1mZmZmZmYmY21vPTNhY2MzYSZjbW49ZmY1MzUzJmN0PTgwODA4MCc+PC9zY3JpcHQ+DQoNCg==