Observations of trends in Electronic Health Record Data Among Patients Who Have Undergone a Stroke Evaluation

Preliminary information

Because patients who are monitored for stroke status during hospital visits are often watched closely and put through a myriad of tests, they may have exceptionally rich EHR data and be useful clinical research subjects. The purpose of this study is to highlight four interesting research questions and answer them using EHR data pulled from patients who had been evaluated for stroke.

1 Setup and Data Ingest

1.1 Initial R setup

The packages and parameters used in this code chunk are present in order to generate a legible report.

library(knitr)
library(rmdformats)
library(rmarkdown)

options(max.print="100")
knitr::opts_chunk$set(echo = TRUE)
knitr::opts_chunk$set(comment = NA)
options(width = 70)

1.2 Loading Necessary R Packages

Each of the following packages were necessary for the analysis and/or graphical display of information used in this project.

setwd(dirname(getwd()))
source("Love-boost.R")
library(janitor)
library(Epi)
library(kableExtra)
library(GGally)
library(ggforce)
library(ggdist)
library(gghalves)
library(ggmosaic)
library(car)
library(tidyr)
library(magrittr)
library(mosaic)
library(equatiomatic)
library(simputation) 
library(patchwork)
library(broom)
library(naniar)
library(tidyverse)



theme_set(theme_bw())

1.3 Data ingest

The following code is present for the purpose of ingesting the the raw data from the STROKEDATA.csv file. Additionally, this code converts certain character variables used in this study into factors. Specifically, all of the categorical variables were converted into factors. The data for bmi, which is a quantitative variable, was kept in the numeric category alongside avg_glucose_level and age. The id variable is maintained as a character variable here, as it is only present for the purpose of displaying a unique number alongside each observation.

stroke_raw <- read.csv("STROKEDATA.csv") |> 
   mutate(across(where(is.character), as.factor)) |>
  mutate(id = as.character(id))  |> 
  mutate(across(where(is.integer), as.factor)) |> 
  mutate(bmi = as.character(bmi)) |>
  mutate(bmi = as.numeric(bmi)) 

Standardizing the “unknown” variables for the raw dataset

It appears that missing values are noted as “unknown” in only the smoking_status variable. The following code is meant to change it to “N/A” so that it matches all other variables. A quick count of the smoking status factors is provided to show that the name was properly changed.

stroke_raw$smoking_status <- recode_factor(stroke_raw$smoking_status, 
                                             "Unknown" = "N/A")

stroke_raw |> count(smoking_status)
   smoking_status    n
1             N/A 1544
2 formerly smoked  885
3    never smoked 1892
4          smokes  789

2 Cleaning the Data

Using the code below, a new data frame called stroke_complete_cases was created, including only the patients in stroke_raw with information on all of the variables collected. For enhanced legibility, binary categorical variables with factors of 0 and 1 were renamed such that the factors reflected the actual clinical observation. For example, instead of “0” and “1” being used in the hypertension variable, “No Hypertension” and “Hypertension” were used respectively. Finally, a glimpse of the stroke_complete_cases tibble is provided.

Because the research question for analysis E, which is explained later, only involves employed persons, the two categories for unemployed people (children and never_worked) were omitted from the work_type variable.

stroke_complete_cases <- stroke_raw |>
 filter(complete.cases(id, age, gender, 
                       hypertension, heart_disease, 
                       ever_married, work_type,
                       Residence_type, 
                       avg_glucose_level, bmi, 
                       smoking_status, stroke),  
        bmi != "N/A", smoking_status != "N/A", gender != "Other") |> 
  mutate(gender = fct_collapse(factor(gender) , 
                               "Male" = "Male", 
                               "Female" = c("Female"))) |> 
  filter(
    work_type == "Govt_job" | 
      work_type == "Private" | 
      work_type == "Self-employed") |> droplevels()


stroke_complete_cases$work_type <- recode_factor(stroke_complete_cases$work_type, 
                                             "Govt_job" = "Government Job",
                                             "Private" = "Private Sector",
                                             "Self-employed" = "Self-Employed")

#renaming the factors
stroke_complete_cases$hypertension <- recode_factor(stroke_complete_cases$hypertension, 
                                             "0" = "No Hypertension",
                                             "1" = "Hypertension")


stroke_complete_cases$heart_disease <- recode_factor(stroke_complete_cases$heart_disease, 
                                             "0" = "No Heart Disease",
                                             "1" = "Heart Disease" )

stroke_complete_cases$stroke <- recode_factor(stroke_complete_cases$stroke, 
                                       "0" = "No Stroke",
                                             "1" = "Stroke")


stroke_complete_cases <- stroke_complete_cases |> 
  mutate(smoking_status = fct_relevel(smoking_status, "never smoked",
                                      "formerly smoked", "smokes"))|> 
  droplevels()
  

stroke_complete_cases <- stroke_complete_cases |> as_tibble(stroke_complete_cases)

# Reviewing the data set

glimpse(stroke_complete_cases)
Rows: 3,343
Columns: 12
$ id                <chr> "9046", "31112", "60182", "1665", "56669",…
$ gender            <fct> Male, Male, Female, Female, Male, Male, Fe…
$ age               <dbl> 67, 80, 49, 79, 81, 74, 69, 81, 61, 54, 79…
$ hypertension      <fct> No Hypertension, No Hypertension, No Hyper…
$ heart_disease     <fct> Heart Disease, Heart Disease, No Heart Dis…
$ ever_married      <fct> Yes, Yes, Yes, Yes, Yes, Yes, No, Yes, Yes…
$ work_type         <fct> Private Sector, Private Sector, Private Se…
$ Residence_type    <fct> Urban, Rural, Urban, Rural, Urban, Rural, …
$ avg_glucose_level <dbl> 228.69, 105.92, 171.23, 174.12, 186.21, 70…
$ bmi               <dbl> 36.6, 32.5, 34.4, 24.0, 29.0, 27.4, 22.8, …
$ smoking_status    <fct> formerly smoked, never smoked, smokes, nev…
$ stroke            <fct> Stroke, Stroke, Stroke, Stroke, Stroke, St…

Checking to make sure that none of the values for bmi are unrealistically high:

The following code is present for the purpose of displaying the number of bmi observations above 50 (10 points above the clinical level of morbid obesity as per the CDC) and below 10 (8 points below the clinically underweight cutoff point as per the CDC). This allows for any abnormally large or small values in the data set to be noted so that they can be omitted.

sum(stroke_complete_cases$bmi > 50) 
[1] 58
sum(stroke_complete_cases$bmi < 10)
[1] 0

Although the lowest bmi value in the stroke_complete_cases data frame appears to be in a reasonable area for a low BMI per CDC guidance, there are a total of 58 recorded BMI values over 50, which is considerably above the widely accepted cutoff value for morbid obesity of 40 (as per CDC guidance). For this reason values of bmi over 50 will be removed from the data frame, as they are either serious anomalies or possibly improperly measured/reported values.

Removing impossibly high values

The following code is present for the purpose of removing bmi values in the stroke_complete_cases data frame above 50.

stroke_complete_cases <- stroke_complete_cases[which(stroke_complete_cases$bmi < 50),]

2.1 Creating a data set containing only the variables to be used in this study

Because this project will only use five of the variables included in stroke_complete_cases there is no reason to include information on the other variables in the analytic data frame that will be used in this project. The following code is present to only select the necessary variables for this study and omit the remaining variables.

A1_stroke_complete_cases <- stroke_complete_cases |> 
  select(id, gender, stroke, bmi, 
         hypertension, smoking_status, work_type)


glimpse(A1_stroke_complete_cases) 
Rows: 3,285
Columns: 7
$ id             <chr> "9046", "31112", "60182", "1665", "56669", "5…
$ gender         <fct> Male, Male, Female, Female, Male, Male, Femal…
$ stroke         <fct> Stroke, Stroke, Stroke, Stroke, Stroke, Strok…
$ bmi            <dbl> 36.6, 32.5, 34.4, 24.0, 29.0, 27.4, 22.8, 29.…
$ hypertension   <fct> No Hypertension, No Hypertension, No Hyperten…
$ smoking_status <fct> formerly smoked, never smoked, smokes, never …
$ work_type      <fct> Private Sector, Private Sector, Private Secto…

2.2 Checking for missing data on each of the selected variables

Checking the quantitative variable

The following code is present for the purpose of searching for any extraneous missing data in the quantitative variables. Although missing cases were previously omitted from the data set, it is important to check before proceeding with the analyses of this study. A brief numeric summary is also provided in order to ensure that no impossible values are included for the bmi variable.

A1_stroke_complete_cases |> select(bmi) |>
    miss_var_summary() 
# A tibble: 1 × 3
  variable n_miss pct_miss
  <chr>     <int>    <dbl>
1 bmi           0        0
A1_stroke_complete_cases |> 
  select(bmi) |>
  mosaic::inspect() 

quantitative variables:  
  name   class  min   Q1 median   Q3  max    mean       sd    n
1  bmi numeric 11.5 25.3   29.1 33.9 49.9 29.9972 6.377575 3285
  missing
1       0

It can be seen above that, as expected, there are no missing bmi observations in our analytic tibble. Additionally, it appears that no bmi values above 50 are included, as intended.

Checking binary categorical variables

The following code is present for the purpose of searching for any extraneous missing data in the binary categorical variables. Also included is a table from the inspect function of the mosaic package, which displays the name, class, levels, n, number missing, and distribution of factors for each variable.

A1_stroke_complete_cases |> 
  select(stroke, gender) |>
    miss_var_summary() 
# A tibble: 2 × 3
  variable n_miss pct_miss
  <chr>     <int>    <dbl>
1 stroke        0        0
2 gender        0        0
A1_stroke_complete_cases |> 
  select(stroke, gender) |> 
  mosaic::inspect() 

categorical variables:  
    name  class levels    n missing
1 stroke factor      2 3285       0
2 gender factor      2 3285       0
                                   distribution
1 No Stroke (94.6%), Stroke (5.4%)             
2 Female (60.9%), Male (39.1%)                 

It can be seen above that, as expected, there are no missing stroke, or gender observations in our analytic tibble. Both variables were properly classified as factors with two understandably named levels.

Checking multicategorical variables

The following code is present for the purpose of searching for any extraneous missing data in the multicategorical variables. Also included is a report from the inspect function of the mosaic package, which displays the name, class, levels, n, number missing, and distribution of factors for each variable.

A1_stroke_complete_cases |> 
  select(smoking_status, work_type) |>
    miss_var_summary() 
# A tibble: 2 × 3
  variable       n_miss pct_miss
  <chr>           <int>    <dbl>
1 smoking_status      0        0
2 work_type           0        0
A1_stroke_complete_cases |>
  select(smoking_status, work_type) |> 
  mosaic::inspect() 

categorical variables:  
            name  class levels    n missing
1 smoking_status factor      3 3285       0
2      work_type factor      3 3285       0
                                   distribution
1 never smoked (53.3%) ...                     
2 Private Sector (65.7%) ...                   

It can be seen above that, as expected, there are no missing smoking_status, or work_type observations in our analytic tibble. Both are classified as factors with the intended number of levels present.

2.3 Printing The analytic tibble

The following code is present for the purpose of renaming the data set containing all of the six variables and printing it to show the final analytic tibble that will be used in all subsequent analyses.

Stroke_data <- A1_stroke_complete_cases

Stroke_data
# A tibble: 3,285 × 7
   id    gender stroke   bmi hypertension    smoking_status  work_type
   <chr> <fct>  <fct>  <dbl> <fct>           <fct>           <fct>    
 1 9046  Male   Stroke  36.6 No Hypertension formerly smoked Private …
 2 31112 Male   Stroke  32.5 No Hypertension never smoked    Private …
 3 60182 Female Stroke  34.4 No Hypertension smokes          Private …
 4 1665  Female Stroke  24   Hypertension    never smoked    Self-Emp…
 5 56669 Male   Stroke  29   No Hypertension formerly smoked Private …
 6 53882 Male   Stroke  27.4 Hypertension    never smoked    Private …
 7 10434 Female Stroke  22.8 No Hypertension never smoked    Private …
 8 12109 Female Stroke  29.7 Hypertension    never smoked    Private …
 9 12095 Female Stroke  36.8 No Hypertension smokes          Governme…
10 12175 Female Stroke  27.3 No Hypertension smokes          Private …
# … with 3,275 more rows

List of missing values

The following code provides one final count of missing variables to ensure that subsequent analyses include only complete cases. It should be noted that in this study, all missing data is considered to be missing completely at random (MCAR).

miss_var_summary(Stroke_data)
# A tibble: 7 × 3
  variable       n_miss pct_miss
  <chr>           <int>    <dbl>
1 id                  0        0
2 gender              0        0
3 stroke              0        0
4 bmi                 0        0
5 hypertension        0        0
6 smoking_status      0        0
7 work_type           0        0

3 Codebook and Data Description

Description of the subjects of this study

The data used for this study was taken from the electronic health records (EHRs) of 3285 persons aged 10-82 who, within their EHR, had explicitly been noted as either having suffered a stroke in their life or having not suffered a stroke in their life. All EHR data used in this study was de-identified and made public by McKinsey and Company, a consulting firm with oversight over a number of US hospital EHRs. All subjects had complete data for each of the variables listed below.

3.1 Codebook

Description of Variables

The following table contains the name of each variable in the Stroke_data data set used for this analysis, the type of variable it is, and a brief description of the levels for each variable. The variable types are denoted as such:

  • ID = Identification number

  • Quant = Quantitative variables

  • Binary = Two-category variables

  • X-cat = Multicategorical variables) where X indicates the number of levels in the variable.

Variable Type Description / Levels
id ID A unique identification number assigned to each participant
gender Binary The gender of the subject based on recording in the patient’s EHR. “Male” indicates that the subject was male, “Female” indicates that they were female.
stroke Binary Whether or not electronic health records indicated that the individual had suffered a stroke at some point in their life. “Stroke” indicates that they suffered a stroke, “No Stroke” indicates that they did not.
bmi Quant Current body mass index of the patient as indicated by that patient’s EHR. Body mass index is calculated by dividing weight in pounds (lb) by height in inches (in) squared and multiplying that value by a conversion factor of 703.
smoking_status 3-Cat The smoking status of the patient as indicated by that patient’s EHR. “never smoked” indicates that the patient has no history of smoking, “formerly smoked” indicates that they have, but no longer smoke, and “smokes” indicates that the patient currently smokes.
work_type 5-Cat The category of work of the patient as indicated by that patient’s EHR. “Govt_job” indicates that the patient works for the government (public sector), “Private” indicates that the patient is employed and works for a private company (private sector), “Self-employed” indicates that the patient is self employed.
hypertension Binary The hypertensive status of the patient as indicated by that patient’s EHR. “No Hypertension” indicates that the patient does not have hypertension (high blood pressure) and “Hypertension” indicates that the patient has hypertension (high blood pressure).

3.2 Analytic Tibble

The following code is present for the purpose of printing the analytic tibble in order to show that it is, in fact, a tibble.

Stroke_data
# A tibble: 3,285 × 7
   id    gender stroke   bmi hypertension    smoking_status  work_type
   <chr> <fct>  <fct>  <dbl> <fct>           <fct>           <fct>    
 1 9046  Male   Stroke  36.6 No Hypertension formerly smoked Private …
 2 31112 Male   Stroke  32.5 No Hypertension never smoked    Private …
 3 60182 Female Stroke  34.4 No Hypertension smokes          Private …
 4 1665  Female Stroke  24   Hypertension    never smoked    Self-Emp…
 5 56669 Male   Stroke  29   No Hypertension formerly smoked Private …
 6 53882 Male   Stroke  27.4 Hypertension    never smoked    Private …
 7 10434 Female Stroke  22.8 No Hypertension never smoked    Private …
 8 12109 Female Stroke  29.7 Hypertension    never smoked    Private …
 9 12095 Female Stroke  36.8 No Hypertension smokes          Governme…
10 12175 Female Stroke  27.3 No Hypertension smokes          Private …
# … with 3,275 more rows

3.3 Data summary

The following code is present for the purpose of creating a descriptive summary of each of the variables used in the tibble for this study.

Hmisc::describe(Stroke_data)
Stroke_data 

 7  Variables      3285  Observations
----------------------------------------------------------------------
id 
       n  missing distinct 
    3285        0     3285 

lowest : 10056 10119 10133 10138 10139, highest: 9730  9752  9923  9926  9955 
----------------------------------------------------------------------
gender 
       n  missing distinct 
    3285        0        2 
                        
Value      Female   Male
Frequency    2000   1285
Proportion  0.609  0.391
----------------------------------------------------------------------
stroke 
       n  missing distinct 
    3285        0        2 
                              
Value      No Stroke    Stroke
Frequency       3106       179
Proportion     0.946     0.054
----------------------------------------------------------------------
bmi 
       n  missing distinct     Info     Mean      Gmd      .05 
    3285        0      318        1       30    7.144    21.00 
     .10      .25      .50      .75      .90      .95 
   22.40    25.30    29.10    33.90    39.06    42.20 

lowest : 11.5 14.1 15.0 15.7 16.0, highest: 49.3 49.4 49.5 49.8 49.9
----------------------------------------------------------------------
hypertension 
       n  missing distinct 
    3285        0        2 
                                          
Value      No Hypertension    Hypertension
Frequency             2892             393
Proportion            0.88            0.12
----------------------------------------------------------------------
smoking_status 
       n  missing distinct 
    3285        0        3 
                                                          
Value         never smoked formerly smoked          smokes
Frequency             1751             811             723
Proportion           0.533           0.247           0.220
----------------------------------------------------------------------
work_type 
       n  missing distinct 
    3285        0        3 
                                                       
Value      Government Job Private Sector  Self-Employed
Frequency             505           2159            621
Proportion          0.154          0.657          0.189
----------------------------------------------------------------------

4 Analysis B: Comparing Two Population Means with Independent Samples

4.1 Research Question

In this analysis, the bmi values in the Stroke_data tibble will be compared to the stroke status of the patients included in the study, with the objective of identifying if there is any meaningful difference in bmi for patients who were recorded as having a stroke vs those who were not recorded as having a stroke. This information may be a useful hypothesis generator for researchers looking to investigate the possible clinical appearances of patients more likely to suffer a stroke. For this study, a 90% confidence interval will be used in all analyses. The research question is as follows:

Is there a meaningful difference in mean BMI between patients that have been noted as having suffered a stroke in their electronic medical history and those who have not been noted as having suffered a stroke in their electronic medical history?

4.2 Describing the Data

In this analysis, two variables will be examined. One is stroke status, which is a binary categorical variable named stroke with the levels “No Stroke” and “Stroke”, representing whether or not electronic medical records indicated that the individual had suffered a stroke at some point in their life. “Stroke” indicates that they suffered a stroke, “No Stroke” indicates that they did not.

The second variable is BMI, which is a quantitative variable describing the current body mass index of the patient as indicated by that patient’s EHR.

Numerical summary

The following code is present for the purpose of displaying a brief numerical summary of the bmi data between patients that have suffered a stroke and patients who have not.

mosaic::favstats(bmi ~ stroke, data = Stroke_data) |> 
  kbl(caption = "Numerical summary of BMI by stroke status", 
      digits = 2) |> 
  kable_styling(font_size = 20) |>
  kable_paper("hover", full_width = F)
Numerical summary of BMI by stroke status
stroke min Q1 median Q3 max mean sd n missing
No Stroke 11.5 25.3 29.0 33.9 49.9 29.97 6.40 3106 0
Stroke 16.9 26.6 29.7 33.9 48.9 30.51 6.02 179 0

It can be seen in the table above that the two stroke classified groups have very similar values for max, mean, median, and interquartile range. However the minimum value for the “No Stroke” group was considerably lower than that of the “Stroke” group. It should also be noted that there are many more patients within the “No Stroke” group than the “Stroke” group.

Graphical assessment of Symmetry and Normality

In order to visualize the overall distribution of data in terms of BMI, a histogram was constructed comprising the entire range for bmi of the Stroke_data data set, with portions of the histogram highlighted to show the distribution of the two stroke groups.

ggplot(Stroke_data, aes(x = bmi, fill = stroke, color = 2)) +
    geom_histogram(bins = 75) + 
    guides(color = "none") +
    labs(title = "Histogram of BMI Values For All Patients Assessed for Stroke",
         x = "Body Mass Index (BMI)") + theme(
  panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) + 
  theme(plot.background = element_rect(fill = "azure2"))

The above plot reveals a distribution that appears to be fairly normal with some right skew. It can be seen that the normal distribution is present in both categories of stroke, but that the “No Stroke” category was more pronounced. This was expected, as in the numerical summary it was demonstrated that the “No Stroke” category had almost 3000 more observations than the “Stroke” category.

A box and violin plot juxtaposed with normal QQ plots for bmi in each stroke category is also useful for visualizing the distribution of values in this data. The following code displays such a plot:

p1 <- ggplot(Stroke_data, aes(x = stroke, y = bmi, fill = stroke)) + 
  geom_violin(alpha = 0.3) +
  geom_boxplot(width = 0.3, notch = TRUE) +
  guides(fill = "none") +
  labs(title = "BMI by Stroke Status",
       x = "EHR indication of a stroke", 
       y = "Body Mass Index (BMI)") + 
  theme(plot.background = element_rect(fill = "azure2"))

p2 <- ggplot(Stroke_data, aes(sample = bmi, col = stroke)) +
  geom_qq() + geom_qq_line() +
  facet_wrap(~ stroke, labeller = "label_both") +
  guides(col = "none") +
  theme_bw() +
  labs(y = "Body Mass Index (BMI)",
       title = "Normal QQ plot for BMI") + 
  theme(plot.background = element_rect(fill = "azure2"))

p1 + theme(
  panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) + 
  p2  + 
  theme(plot.background = element_rect(fill = "azure2")) + 
  theme(panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) 

The two violin plots demonstrate a relatively normal distribution and few outliers for both of the stroke categories. The normal QQ plots help to visualize the degree of skew seen in the data, which, as suggested by the histogram is to the right, slightly.

In order to better visualize the distribution of bmi for each stroke category and specifically to visualize the highest density areas of population for each `bmi, a rain cloud plot ma be useful. The following code is present for the purpose of displaying a rain cloud plot.

ggplot(Stroke_data, aes(stroke, bmi)) + 
  ggdist::stat_halfeye(adjust = .5, width = .3, 
                       .width = 0, justification = -.3, 
                       point_colour = NA, fill = "darkturquoise") + 
  geom_boxplot(width = .1, outlier.shape = NA, fill = "tomato1" , 
               outlier.color = "black") + 
  stat_summary(fun = "mean", geom = "point", 
               shape = 23, size = 3, fill = "white") +
  
  theme(
  panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) +
 labs(
    title = "BMI by stroke status", 
    subtitle = 
      "For Patients Who Have Stroke Evaluation Information in Their EHR",
    y = "Body Mass Index (BMI)", 
    x="Stroke Status") + 
  theme(plot.background = element_rect(fill = "azure2"))

It can be seen in the rain cloud plot above, similarly to the violin plot depicted above, that the mean and median values of bmi are very close for both stroke categories. It can also be seen that the greatest number of people in each group have bmi values slightly above 30, which the CDC would consider to be overweight.

Numerical Assessment of Skew

In order to determine the type of test used to figure out if there is a statistically meaningful difference between the bmi values of patients who had a stroke and those who did not, the normality of the distribution of bmi values must be assessed. While the visualizations are useful in determining obvious skew, it is also useful to ensure that the data is normal using a nonparametric skew analysis. In this analysis, nonparametric skew is calculated by taking the difference between the mean and the median, and dividing it by the standard deviation. This particular type of skew is based off of Pearson’s notion of median skewness, with values falling between -1 and +1 for any distribution. Generally, when this measure of skew is used, values greater than + 0.2 indicate fairly substantial right skew, while values below -0.2 indicate fairly substantial left skew. If the skewness value for bmi is between -0.2 and +0.2, the data will be considered to be normally distributed.

Stroke_data|> group_by(stroke) |>
  summarize(skew = round_half_up((mean(bmi) - median(bmi))/sd(bmi), 3)) |> 
  kbl(caption = "Assessment of Skew by Stroke Status", digits = 5) |> 
  kable_styling(font_size = 20) |> 
  kable_paper("hover", full_width = F)
Assessment of Skew by Stroke Status
stroke skew
No Stroke 0.151
Stroke 0.134

Above, it can be seen that there is no substantial skew in either of the stroke categories for bmi, only some mild right skew. For this reason the data will be considered to be normally distributed.

Assessment of population variance

The population variance is also an important measure to consider when deciding which method to utilize to compare the means of two independent samples. The following code is present for the purpose of displaying the population variance in bmi for each stroke category.

Stroke_data |> group_by(stroke) |>
  summarize(n = n(), mean = mean(bmi), variance = var(bmi)) |> 
  kbl(caption = "Assessment of Population Variance", digits = 5) |> 
  kable_styling(font_size = 20) |> 
  kable_paper("hover", full_width = F)
Assessment of Population Variance
stroke n mean variance
No Stroke 3106 29.96784 40.92328
Stroke 179 30.50670 36.26804

Although the “Stroke” and “Not Stroke” categories have similar variances, they are still nearly 5 bmi points away, and for this reason they cannot be considered to be equal.

Overall Assessment of Plots and Numeric Summaries

The plots and numeric summaries depicted above were all in agreement that the data was reasonably normally distributed with some mild, but unsubstantial right skew in both stroke categories. Additionally, it was observed that there was not similar variance in BMI values between the two stroke status categories.

Sample information

It can be deduced from the above numerical summaries and plots that the bmi data for the Stroke_data set is normally distributed among both stroke categories. Only a small amount amount of right skew was observed in the distribution, which was determined by a nonparametric skew analysis to be unimportant. The presence of a normal distribution allows the means of these independent samples to being compared accurately using an approach based on a t-distribution. With the presence of a normal distribution, a bootstrap re-sampling approach is not necessary to compare the bmi means in the two stroke categories. Additionally, because the objective of the research question was to compare the samples based on their mean values, they are not best compared using a rank-based approach like that seen in a Wilcoxon-Mann-Whitney rank-sum test. This is because this category of tests does not generate a CI based on the means of the samples, but for calculated pseudo-medians, which are not analogous to the means of the samples if the samples are not symmetrically distributed.

Given that equal population variance was not able to be established for the two independent samples, a pooled t-test may not be used here. Instead, a t-test will be completed with Welch’s approach, which does not assume equal variance. Welch’s approach has two additional conditions, that the samples in each group are drawn independently of each other and that the samples in each group represent a random sample of the population of interest. Our two groups that we are comparing means for are independent samples, with no matching or pairing present and both are drawn from wide ranging de-identified EHR data, which is widely used around the United States in hospitals that evaluate patients for strokes. Thus, these samples can be considered to be random samples.

4.3 Main Analysis

The following code is present for the purpose of comparing the means of the two stroke categories using a t-test . A Welch’s t-test approach will be used because equal variance could not be established. It is important to note that Welch’s t-test carries two additional assumptions to the normality assumption: that the samples in each group are drawn independently of each other and that the samples in each group represent a random sample of the population of interest. Both of those can be considered to be true in this case for reasons mentioned above. A summary of the 90% confidence interval for the difference (No stroke - Stroke) of the population means is included as well.

wtt <- t.test(bmi ~ stroke, data = Stroke_data, conf.level = 0.90) 

wtt

    Welch Two Sample t-test

data:  bmi by stroke
t = -1.16, df = 201.85, p-value = 0.2474
alternative hypothesis: true difference in means between group No Stroke and group Stroke is not equal to 0
90 percent confidence interval:
 -1.3064782  0.2287433
sample estimates:
mean in group No Stroke    mean in group Stroke 
               29.96784                30.50670 
wtt |>
  tidy() |>
  select(estimate, conf.low, conf.high) |> 
  kbl(caption = "Welch's T-test", digits = 5) |>
  kable_styling(font_size = 20) |> 
  kable_paper("hover", full_width = F)
Welch’s T-test
estimate conf.low conf.high
-0.53887 -1.30648 0.22874

4.4 Conclusions

From the above analysis, which uses a Welch’s T-test approach to compare the mean bmi values for the two categories of the stroke variable in the Stroke_data data set, two point estimates were able to be obtained. The point estimate for the mean BMI in the “No Stroke” group was 29.96784 and the point estimate for the mean BMI in the “Stroke” group was 30.50670. The 90% confidence interval for the difference (No stroke - Stroke) of the population means was found to be from -1.3064782 to 0.2287433. Because the t-tests’ resulting 90% confidence interval includes zero in its range, it can be concluded that the true potential difference in mean BMI values between the “No Stroke” and “Stroke” groups could be positive, negative, or zero. Thus we can conclude that, with an alpha level of 0.10 and the sample size used, there is not a meaningful difference in mean BMI between patients that have been noted as having suffered a stroke in their electronic medical history and those who have not been noted as having suffered a stroke in their electronic medical history using the Stroke_data set.

Although this particular study was not able to establish a difference in mean bmi values among the two stroke categories, there are a number of potential limitations to this particular study. One of these limitations is that the type of stroke that a patient suffered was not mentioned. Because strokes can be caused by ischemia or hemorrhage in a multitude of different areas of the brain and can have a wide range of etiologies, treating all strokes as the same when considering the BMI of a patient may not accurately describe the true relationship between stroke and BMI. Also, the number of strokes that a patient suffered and the length of time since that patient’s last stroke were not mentioned, each of which may have different effects on BMI.

Future studies looking to determine whether or not there is a difference in mean bmi values based on stroke status may opt to dig deeper into the electronic health records and create a data set that includes information on the type of stroke a patient suffered, the number of strokes they had, and how recently their most recent stroke was. Information on how medical staff intervened with the patient’s stroke may also be useful in determining whether or not BMI values differ based on stroke status.

5 Analysis C: Comparing Three Means with Independent Samples

5.1 Research Question

In this analysis, the mean bmi values in the Stroke_data tibble will be compared by the smoking_status of the patients included in the study, with the objective of identifying if there is any meaningful difference in bmi for patients who were recorded in their EHR as being either a smoker, former smoker, or person who has never smoked. The three smoking_status categories are all independent of one another and none of the results are paired or matched. This information may be a useful hypothesis generator for researchers looking to further investigate the physiological changes among smokers, non-smokers and former smokers. The research question is as follows:

Is there a meaningful difference in mean BMI values between patients who smoke currently, those who have smoked in the past, and those who do not smoke, among patients who have a stroke evaluation in their electronic health record?

5.2 Describing the Data

In this analysis, two variables will be examined. One is smoking status, which is a three level categorical variable named smoking_status with the levels “never smoked”, “former smoker”, and “smokes”, representing the smoking status of the patient as indicated by that patient’s EHR. “never smoked” indicates that the patient has no history of smoking, “formerly smoked” indicates that they have, but no longer smoke, and “smokes” indicates that the patient currently smokes.

The second variable is BMI, which is a quantitative variable describing the current body mass index of the patient as indicated by that patient’s EHR.

Numeric summary

The following code is present for the purpose of displaying a brief numerical summary of the bmi data between patients in each of the three smoking_status categories.

mosaic::favstats(bmi ~ smoking_status, data = Stroke_data) |>
  kable(caption = "BMI Numerical Summary by Smoking Category", 
        digits = 2) |> kable_styling(font_size = 20) |>  
  kable_paper("hover", full_width = F)
BMI Numerical Summary by Smoking Category
smoking_status min Q1 median Q3 max mean sd n missing
never smoked 11.5 25.0 28.7 33.40 49.8 29.69 6.41 1751 0
formerly smoked 15.0 26.1 29.8 34.35 49.8 30.55 6.32 811 0
smokes 15.7 25.4 29.0 34.25 49.9 30.13 6.32 723 0

It can be seen in the table above that the three smoking_status categories have very similar values for max, mean, median, and interquartile range. It can also be seen that the “formerly smoked” and “smokes” categories each have less than half of the number of observations as the “never smoked” category.

Graphical assessment

In order to visualize the overall distribution of data in terms of BMI, a histogram was constructed comprising the entire range for bmi of the Stroke_data data set, with portions of the histogram highlighted to show the distribution of the three smoking_status categories. To better individually highlight the distributions of the three categories, an additional three histograms were made.

p3 <- ggplot(Stroke_data, aes(x = bmi, fill = smoking_status, color = 2)) +
    geom_histogram(bins = 75)  + 
  guides(color = "none") +
    labs(title = "Histogram of BMI results For All Smoking Statuses",
         x = "BMI") + 
  theme(panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) + 
  theme(plot.background = element_rect(fill = "azure2"))

p4 <- ggplot(Stroke_data, aes(x = bmi)) +
  geom_histogram(aes(fill = smoking_status), bins = 30, col = "white") +
  theme_bw() +
  facet_wrap(~ smoking_status) + guides(fill = "none") +
  labs(title = "Individual histograms of BMI by smoking status",
       y = "count",
       x = "Smoking Status") + 
  theme(panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) + 
  theme(plot.background = element_rect(fill = "azure2"))

p3/p4

It can be seen above that each of the three smoking_status categories appear to have a normal distribution with some slight right skew. All three categories appear to have the greatest number of people at a BMI value around 30, which is consistent with the numeric summary.

In order to better visualize the distribution of bmi for each smoking_status category and specifically to visualize the highest density areas of population for each, a rain cloud plot may be useful. The following code is present for the purpose of displaying a rain cloud plot.

ggplot(Stroke_data, aes(smoking_status, bmi)) + 
  ggdist::stat_halfeye(adjust = .5, width = .3,
                       .width = 0, justification = -.3,
                       point_colour = NA, fill = "darkturquoise") + 
  geom_boxplot(width = .1, outlier.shape = NA, fill = "tomato1" , 
               outlier.color = "black", notch = TRUE) + 
  stat_summary(fun = "mean", geom = "point", 
               shape = 23, size = 3, fill = "white") +
  
  theme(
  panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) +
 labs(
    title = "BMI by Smoking Status", 
    subtitle = 
      "For Patients Who Have Stroke Evaluation Information in Their EHR",
    y = "Body Mass Index (BMI)", 
    x="Smoking Status") + 
  theme(plot.background = element_rect(fill = "azure2"))

It can be seen in the above rain cloud plot that the mean and median values of bmi are very close for all three of the smoking_status categories. It can also be seen that the greatest number of people in each group have bmi values slightly below 30, which the CDC would consider to be in a healthy range (meaning neither overweight or underweight). The data also appear to have relatively similar variance in each smoking_status category.

The distribution of data can be further investigated using a box and violin plot juxtaposed with normal QQ plots for bmi in each smoking_status category. The following code allows for that.

p1 <- ggplot(Stroke_data, 
             aes(x = smoking_status, y = bmi, fill = smoking_status)) + 
  geom_violin(alpha = 0.3) +
  geom_boxplot(width = 0.3, notch = TRUE) +
  guides(fill = FALSE) +
  labs(title = "BMI by Smoking Status",
       x = "Smoking Status", y = "Body Mass Index") + 
  theme(plot.background = element_rect(fill = "azure2"))

p2 <- ggplot(Stroke_data, aes(sample = bmi, col = smoking_status)) +
  geom_qq() + geom_qq_line() +
  facet_wrap(~ smoking_status) +
  guides(col = "none") +
  theme_bw() +
  labs(y = "Observed BMI values",
       title = "Normal QQ Plot") + 
  theme(plot.background = element_rect(fill = "azure2"))

(p1 + theme(
  panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) ) + (p2  +
    plot_annotation(title = "Overall title") + theme(
  panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) ) 

The three violin plots demonstrate a relatively normal distribution and few outliers for each of the smoking_status categories. The normal QQ plots help to visualize the degree of skew seen in the data, which, as suggested by the histogram is to the right, slightly for all three smoking_status categories.

Numerical Assessment of Skew

A nonparametric skewness assessment was done to help establish whether or not the data was normally distributed. In this analysis, nonparametric skew is calculated by taking the difference between the mean and the median, and dividing it by the standard deviation. This particular type of skew is based off of Pearson’s notion of median skewness, with values falling between -1 and +1 for any distribution. Generally, when this measure of skew is used, values greater than + 0.2 indicate fairly substantial right skew, while values below -0.2 indicate fairly substantial left skew. If the skewness value for bmi is between -0.2 and +0.2, the data will be considered to be normally distributed.

Stroke_data|> group_by(smoking_status) |>
  summarize(skew = round_half_up((mean(bmi) - median(bmi))/sd(bmi), 3)) |> 
  kbl(caption = "Assessment of Skew", digits = 2) |> 
  kable_styling(font_size = 20) |> 
  kable_paper("hover", full_width = F)
Assessment of Skew
smoking_status skew
never smoked 0.15
formerly smoked 0.12
smokes 0.18

It can be seen in the table above that the “smokes” category of the smoking_status variable demonstrated the greatest amount of right skew of all of the three categories. However, none were above 0.2, indicating that there was no substantial skew, only some mild right skew. For this reason, the data will be considered to be normally distributed.

5.3 Main Analysis

The assessment of skewness, histograms, box plots, and QQ diagrams of bmi data for each of the three smoking_status categories suggested that they all have a fairly normal distribution. In addition to normality, the samples in each of the smoking_status categories were independently sampled and, as mentioned in analysis B, the data used in this study is reflective of a random sample of the population of interest. Moreover, equal variance is seen across all three smoking_status categories. Given this information, an ANOVA (analysis of variance) test, which is based on a pooled t-test, will be used to compare the mean BMI for each of the smoking_status categories.

Stroke_data_m1 <- lm(bmi ~ smoking_status, data = Stroke_data)

anova(Stroke_data_m1) |> 
  kbl(caption= "Analysis of Variance to Compare Mean BMI by Smoking Status", 
      digits = 2) |> 
  kable_styling(font_size = 20) |> 
  kable_paper("hover", full_width = F)
Analysis of Variance to Compare Mean BMI by Smoking Status
Df Sum Sq Mean Sq F value Pr(>F)
smoking_status 2 423.77 211.88 5.22 0.01
Residuals 3282 133147.87 40.57 NA NA

From the above analysis of variance (ANOVA), it appears that the null hypothesis, which was that there was no difference in mean BMI values between patients who smoke currently, those who have smoked in the past, and those who do not smoke is not consistent with our data for bmi among smoking_status categories. The eta squared value is calculated as follows:

(423.77)/(423.77 + 133147.87) = 0.0032

The value for eta squared shows that smoking_status accounts for around 0.32% of the variation in bmi.

Tukey multiple comparisons of means

Although the ANOVA was able to elucidate whether or not the three bmi means across the smoking_status categories are different, it does not explain where the differences lie. To explore the potential differences further, Tukey’s Honestly Significant Differences approach to pairwise comparisons of means was used. The following code uses this technique to create 90% confidence intervals for the differences in mean BMI for each of the possible smoking_status pairs.

TukeyHSD(aov(Stroke_data$bmi ~ Stroke_data$smoking_status), conf.level = 0.90) 
  Tukey multiple comparisons of means
    90% family-wise confidence level

Fit: aov(formula = Stroke_data$bmi ~ Stroke_data$smoking_status)

$`Stroke_data$smoking_status`
                                   diff        lwr      upr     p adj
formerly smoked-never smoked  0.8576613  0.3022364 1.413086 0.0043846
smokes-never smoked           0.4401911 -0.1378742 1.018256 0.2617963
smokes-formerly smoked       -0.4174702 -1.0863104 0.251370 0.4057613

The 90% confidence intervals derived from the Tukey’s HSD analysis show that there is likely a considerable difference between the “formerly smoked” and “never smoked” groups, but not between any of the other possible pairs.

Plot of Tukey multiple comparisons of means

The following code is present for the purpose of plotting the 90% confidence intervals associated with the above Tukey’s HSD analysis.

For the below plot, the following shorthand was used

Abbreviation Category of smoking_status
S smokes
NS never smoked
FS formerly smoked
par(bg = "azure2")

Stroke_data$smk.new <- 
    fct_recode(Stroke_data$smoking_status, 
               "S" = "smokes", "NS" = "never smoked",
               "FS" = "formerly smoked")

mar.default <- c(5,6,4,2) + 0.1
par(mar = mar.default + c(0, 4, 0, 0))
plot(TukeyHSD(aov(Stroke_data$bmi ~ Stroke_data$smk.new), 
              conf.level = 0.90, las = 1)) 

It can be seen above that the 90% confidence intervals derived from the Tukey’s HSD analysis of mean bmi by smoking status group show that there is a statistically meaningful difference between the “formerly smoked” and “never smoked” groups, but not between any of the other possible pairs. Given that the difference between the “formerly smoked” and “never smoked” groups is positive, it can be concluded that the mean bmi value for the “formerly smoked” group is greater than that of the “never smoked group. There is no evidence that there is a meaningful difference between mean bmi values for any of the other pairs, and it cannot explicitly concluded with the current sample size and an alpha level of 0.10 that any of the other means are meaningfully different from each other.

5.4 Conclusions

The research question that guided the design of this analysis was “Is there a meaningful difference in mean BMI values between patients who smoke currently, those who have smoked in the past, and those who do not smoke, among patients who have a stroke evaluation in their electronic health record?”. From the ANOVA test and analysis of Tukey’s HSD for the mean BMI values of each of the categories of smoking_status, it was able to be seen that there was only a meaningful difference in BMI values between patients who have formerly smoked and those who have never smoked. When the differences between other pairs of smoking_status categories were calculated, 90% confidence intervals were not able to establish an explicitly positive or negative value and were thus considered to not be meaningful, as it was not able to be determined which category had a larger or smaller true mean BMI value.

Although this particular study was not able to establish a difference in mean bmi values among all of the smoking_status categories, there are a number of potential limitations to this particular study. One of these limitations is that the data used to report the smoking status of a patient did not specify the type of smoking that the patient partakes in. It may be possible that while a tobacco smoker does not have an appreciable difference in mean BMI values based on their smoking status, that a marijuana smoker does. Furthermore, the status of each patient as a heavy, mild and light smoker was not specified, which may also be a modulator of the patient’s BMI value based on their smoking status.

Future studies looking to determine whether or not there is a difference in mean BMI values among the three smoking status categories may seek to adjust for the type of smoking a person partakes in and/or their status as a heavy, mild, or light smoker. This would, however, require additional data to be collected that is not included in the data set used in this analysis.

6 Analysis D: Analyzing a 2x2 table

6.1 Research Question

For this analysis, the focus will be on the gender and stroke variables, which are each two level categorical variables. Particularly, this analysis will be considering whether or not the gender of a patient that has been evaluated for a stroke has an impact on whether or not they did have a stroke. In this analysis, a 90% confidence level will be used and a Bayesian augmentation of +2 success and +2 failures will be used. The research question is as follows:

Is there a relationship between the gender of a person (male or female) and whether or not that person has had a stroke among patients who have a stroke evaluation in their electronic health record?

6.2 Describing the Data

For this analysis two variables in the Stroke_data data set are considered: gender and stroke. Both of these are binary categorical variables. Gender refers to the gender of the subject based on recording in the patient’s EHR. “Male” indicates that the subject was male, “Female” indicates that they were female. Stroke refers to whether or not electronic health records indicated that a patient had suffered a stroke at some point in their life. “Stroke” indicates that they suffered a stroke, “No Stroke” indicates that they did not.

The following code is present for the purpose of creating a two by two table to analyze the potential relationship between the two chosen variables. In this table, which is displayed in standard epidemiological format, the `gender status “Male” is considered to be the exposure of interest. The purpose of this table is to visualize the distribution of patients, and for this reason, a Bayesian augmentation was withheld. However, it will be added during the main analysis.

# Re-leveling the factors so that the tabyl will be in standard epidemiological format:

Stroke_data_analysisD <- Stroke_data |> 
    mutate(stroke = fct_relevel(stroke, "Stroke", "No Stroke")) |>
  mutate(gender = fct_relevel(gender, "Male", "Female"))

Stroke_data_analysisD |> tabyl(gender, stroke) |> 
    adorn_percentages(denom = "row") |>
    adorn_pct_formatting(digits = 1) |>
    adorn_ns(position = "front") |> 
    adorn_title(col_name = "Stroke status by gender", 
                row_name = "Gender") |> 
  kbl(caption = "Stroke Status by Gender", digits = 2) |> 
  kable_styling(font_size = 20) |> 
  kable_paper("hover", full_width = F)
Stroke Status by Gender
Stroke status by gender
Gender Stroke No Stroke
Male 75 (5.8%) 1210 (94.2%)
Female 104 (5.2%) 1896 (94.8%)

6.3 Main Analysis

The following code is present for the purpose of creating a two-by-two table analysis, displaying the a point estimate and 90% confidence interval for the probability of having a specific stroke status between the two gender categories, a relative risk of stroke given that the gender is male (vs female), and the odds ratio describing the odds of stroke use given that the gender is Male (vs female).

A Bayesian augmentation was added to the analysis table, adding two successes and two failures in accordance with Alan Agresti’s suggestion of using (x +2)/(n +4) as a success rate estimate for categorical data analysis rather than (x))/(n)

twobytwo(75+2, 1249+2, 104+2, 1939+2,
         "Male", "Female", "Stroke", "No Stroke",
         conf.level = 0.90)
2 by 2 table analysis: 
------------------------------------------------------ 
Outcome   : Stroke 
Comparing : Male vs. Female 

       Stroke No Stroke    P(Stroke) 90% conf. interval
Male       77      1251       0.0580    0.0483   0.0695
Female    106      1941       0.0518    0.0443   0.0605

                                   90% conf. interval
             Relative Risk: 1.1197    0.8813   1.4225
         Sample Odds Ratio: 1.1271    0.8748   1.4521
Conditional MLE Odds Ratio: 1.1270    0.8635   1.4677
    Probability difference: 0.0062   -0.0068   0.0199

             Exact P-value: 0.4377 
        Asymptotic P-value: 0.4375 
------------------------------------------------------

It can be elucidated from the above table that the individual probability of being a male with a positive stroke status was around 0.058 and that the individual probability of being a female with a positive stroke status was around 0.0518, each with confidence intervals from around 0.04 to 0.06.

It can also be seen that the relative risk of having suffered a stroke given being male vs. having suffered a stroke given being male, is estimated to be 1.1197. While the point estimate indicates that there is a greater risk of suffering a stroke for males than females, the 90% confidence interval for this relative risk value is 0.8813 - 1.4225, which is not detectably different from 1 at an alpha level of 0.10. This indicates that there is not evidence to suggest that being male is either a risk factor or a protecting factor for stroke in this data set.

Additionally, an odds ratio describing the odds of having suffered a stroke given a patient is male vs. female was found to be 1.1271 with a 90% confidence interval of 0.8748 - 1.4521. Although the odds ratio suggests that males have a greater odds of having suffered a stroke than females, the confidence interval suggests that the odds ratio is not detectably different from 1 at an alpha level of 0.10. This indicates that a larger sample size would likely be required in order to suggest that the odds of suffering a stroke are higher or lower for males when compared to females in the Stroke_data data set.

Finally, the difference in probability of having suffered a stroke given a patient is male vs. female was estimated to be 0.0062.The 90% confidence interval for this relative risk value is -0.0068 - 0.0199, which at an alpha level of 0.10, is not detectably different from zero. This indicates that there is not enough evidence to suggest that there is a difference in the probability of having suffered a stroke greater than, less than, or equal to zero between the two gender categories in the Stroke_data` data set.

6.4 Conclusions

The research question that helped guide the design of this analysis was “Is there a relationship between the gender of a person (male or female) and whether or not that person has had a stroke among patients who have a stroke evaluation in their electronic health record?”. Although point estimates suggested that being male was associated with a greater risk of suffering a stroke (based on the calculated risk ratio) and greater odds of suffering a stroke (based on the calculated odds ratio), the confidence intervals for all of the estimates included both positive and negative values, demonstrating that at the current sample size, a relationship between the gender of a person (male or female) and whether or not that person has had a stroke among patients who have a stroke evaluation in their electronic health record could not be determined with 90% confidence.

This analysis had a number of limitations associated with it, largely based on the quality of information provided for the stroke status of the patient. In the data analyzed, the only information about the stroke status of the patient was whether or not that patient had suffered a stroke. There is no mention of the type of stroke or care received after stroke which may be affected by the gender of the patient. Future analyses looking to find if there is a relationship between the gender of a person and whether or not that person has had a stroke may take information about the specific type of stroke and care given into account to establish a more realistic view of any relationship or lack thereof.

7 Analysis E: Analyzing a 2x3 table

7.1 Research Question

For this analysis, the focus will be on the hypertension and work_type variables, which are each categorical variables. Particularly, this analysis will be considering whether or not the type of employment of a patient that has recorded in their EHR has an impact on whether or not they also have hypertension recorded in their EHR. In this analysis, a 90% confidence level will be used. The research question is as follows:

Is there a relationship between the type of employer a person has and whether or not that person also has hypertension among patients who have a stroke evaluation in their electronic health record?

For this analysis, only persons who are employed will be considered. The reason for this is that there is immense variability among the types of circumstances that could cause somebody to be unemployed. For this reason, only three work_type categories are used (“Govt_job”, “Private”, and “Self-employed”).

7.2 Describing the Data

In this analysis, two variables are observed: the hypertension status of a patient, a binary categorical variable titled hypertension, and the category of employment of a patient, a categorical variable with three levels titled work_type. In this study, hypertension represents the hypertensive status of the patient as indicated by that patient’s EHR. “No Hypertension” indicates that the patient does not have hypertension (high blood pressure) and “Hypertension” indicates that the patient has hypertension (high blood pressure).work_type represents the category of work of the patient as indicated by that patient’s EHR. “Govt_job” indicates that the patient works for the government (public sector), “Private” indicates that the patient is employed and works for a private company (private sector), “Self-employed” indicates that the patient is self employed.

The following code is present for the purpose of organizing a table displaying the distribution of hypertension status among the three categories of work_type.

Stroke_data_analysisE <- Stroke_data |> 
  as_tabyl() |> 
  filter(complete.cases(hypertension, work_type)) 

Stroke_data_analysisE$work_type <- recode_factor(Stroke_data_analysisE$work_type, 
                                             "Govt_job" = "Government Job",
                                             "Private" = "Private Sector",
                                             "Self-employed" = "Self-Employed")


Analysis_E_table <- Stroke_data_analysisE |> 
  tabyl(hypertension, work_type) 

Stroke_data_analysisE |> 
  tabyl(hypertension, work_type) |>
  adorn_totals(where = c("row", "col")) |>
    adorn_title( col_name = "Employer") |>
  kbl( caption = "Hypertension status by Employment Type", digits = 2) |>
  kable_styling(font_size = 20) |> 
  kable_paper("hover", full_width = F)
Hypertension status by Employment Type
Employer
hypertension Government Job Private Sector Self-Employed Total
No Hypertension 444 1936 512 2892
Hypertension 61 223 109 393
Total 505 2159 621 3285

It can be seen in the above table that greatest proportion of hypertensive individuals is seen in the “Self-Employed” work_type category, with nearly double the proportion of hypertensive individuals than the “Government job” category and a more than 50% greater proportion of hypertensive individuals than the “Private Sector” category.

To further visualize the information in the above table, a bar chart was constructed, displaying the distribution of work_type among the two levels of hypertension.

ggplot(Stroke_data_analysisE, aes(x = hypertension, fill = work_type)) + 
  geom_bar(position = "fill") + 
  scale_fill_manual(values=c("chartreuse4", "salmon2", "steelblue1")) +
  
  theme(
  panel.background = element_rect(fill = "lemonchiffon1",
                                colour = "lemonchiffon1",
                                size = 0.5, linetype = "solid")) +
 labs(
    title = "Hypertension by Employment Type", 
    subtitle = "Based on EHR data of patients evaluated for stroke",
    y = "Proportion of study population", 
    x="Hypertension status") + 
  theme(plot.background = element_rect(fill = "azure2"))

7.3 Main Analysis

It can be seen in the two by three table above that none of the cells contain zero observations and all cells have at least five observations, as expected. For this reason, each of the Cochran conditions can be considered to have been met and a Pearson chi-square test is appropriate for assessing homogeneity .

A chi-square test for the data in the above table will help to elucidate whether or not there is a relationship between the employment category of a person and their hypertensive status by determining whether or not the two variables are independent of one another. The chi-square test of independence for this analysis is a hypothesis test with the following conditions:

Null hypothesis: The employment category of a person and their hypertensive status are independent of one another.

Alternative hypothesis: There is a relationship between the employment category of a person and their hypertensive status.

The following code is present for the purpose of running a chi-square test of independence.

chisq.test(Analysis_E_table)

    Pearson's Chi-squared test

data:  Analysis_E_table
X-squared = 23.901, df = 2, p-value = 6.457e-06

It can be seen above that the chi-square test statistic is 23.901 on two degrees of freedom. The chi-square test of independence yielded a p-value of 6.457e-06. This information suggests that the difference in hypertension status among the three employment categories of the work_type variable is less likely to be due to chance and more likely to be attributed to a relationship between hypertension status and employment type. It is important to note that additional testing must be done to determine the true presence of a relationship, as a small p-value can only suggest that there is a small probability that the observed difference is due to chance, not that there is a relationship between the two variables. Nonetheless, the results of this chi-square test of independence encourage the null hypothesis to be rejected.

7.4 Conclusions

The research question that guided the design of this analysis was “Is there a relationship between the type of employer a person has and whether or not that person also has hypertension among patients who have a stroke evaluation in their electronic health record?” The chi-square test of independence was able to determine that there is a high probability that there is a relationship between the type of employer a person has and whether or not that person also has hypertension based on information from the hypertension and work_type variables in the Stroke_data data set. It was not, however, able to determine the true nature of the relationship between hypertension and work type, only that there is likely to be a relationship present.

Future studies looking to investigate a possible relationship between the type of employer a person has and whether or not that person also has hypertension may consider utilizing a data set that includes a continuous quantitative variable to determine hypertension, such as the blood pressure in mmHg. The presence of hypertension as a binary categorical variable is a key limitation to this analysis as it prevents a detailed understanding of the relationship of hypertension and employment type from being visualized. A continuous quantitative variable may better be able to suggest the type of relationship that is present between the employment type and hypertension status of a patient and answer the research question in more detail.

Session Information

sessioninfo::session_info()
─ Session info ─────────────────────────────────────────────────────
 setting  value
 version  R version 4.2.1 (2022-06-23)
 os       macOS Big Sur ... 10.16
 system   x86_64, darwin17.0
 ui       X11
 language (EN)
 collate  en_US.UTF-8
 ctype    en_US.UTF-8
 tz       America/New_York
 date     2022-12-19
 pandoc   2.19.2 @ /Applications/RStudio.app/Contents/MacOS/quarto/bin/tools/ (via rmarkdown)

─ Packages ─────────────────────────────────────────────────────────
 package        * version    date (UTC) lib source
 abind            1.4-5      2016-07-21 [1] CRAN (R 4.2.0)
 assertthat       0.2.1      2019-03-21 [1] CRAN (R 4.2.0)
 backports        1.4.1      2021-12-13 [1] CRAN (R 4.2.0)
 base64enc        0.1-3      2015-07-28 [1] CRAN (R 4.2.0)
 bookdown         0.30       2022-11-09 [1] CRAN (R 4.2.0)
 broom          * 1.0.1      2022-08-29 [1] CRAN (R 4.2.0)
 bslib            0.4.1      2022-11-02 [1] CRAN (R 4.2.0)
 cachem           1.0.6      2021-08-19 [1] CRAN (R 4.2.0)
 car            * 3.1-1      2022-10-19 [1] CRAN (R 4.2.0)
 carData        * 3.0-5      2022-01-06 [1] CRAN (R 4.2.0)
 cellranger       1.1.0      2016-07-27 [1] CRAN (R 4.2.0)
 checkmate        2.1.0      2022-04-21 [1] CRAN (R 4.2.0)
 cli              3.4.1      2022-09-23 [1] CRAN (R 4.2.0)
 cluster          2.1.4      2022-08-22 [1] CRAN (R 4.2.0)
 cmprsk           2.2-11     2022-01-06 [1] CRAN (R 4.2.0)
 colorspace       2.0-3      2022-02-21 [1] CRAN (R 4.2.0)
 crayon           1.5.2      2022-09-29 [1] CRAN (R 4.2.0)
 data.table       1.14.6     2022-11-16 [1] CRAN (R 4.2.0)
 DBI              1.1.3      2022-06-18 [1] CRAN (R 4.2.0)
 dbplyr           2.2.1      2022-06-27 [1] CRAN (R 4.2.0)
 deldir           1.0-6      2021-10-23 [1] CRAN (R 4.2.0)
 digest           0.6.31     2022-12-11 [1] CRAN (R 4.2.1)
 distributional   0.3.1      2022-09-02 [1] CRAN (R 4.2.0)
 dplyr          * 1.0.10     2022-09-01 [1] CRAN (R 4.2.0)
 ellipsis         0.3.2      2021-04-29 [1] CRAN (R 4.2.0)
 Epi            * 2.47       2022-06-26 [1] CRAN (R 4.2.0)
 equatiomatic   * 0.3.1      2022-01-30 [1] CRAN (R 4.2.0)
 etm              1.1.1      2020-09-08 [1] CRAN (R 4.2.0)
 evaluate         0.18       2022-11-07 [1] CRAN (R 4.2.0)
 fansi            1.0.3      2022-03-24 [1] CRAN (R 4.2.0)
 farver           2.1.1      2022-07-06 [1] CRAN (R 4.2.0)
 fastmap          1.1.0      2021-01-25 [1] CRAN (R 4.2.0)
 forcats        * 0.5.2      2022-08-19 [1] CRAN (R 4.2.0)
 foreign          0.8-83     2022-09-28 [1] CRAN (R 4.2.0)
 Formula          1.2-4      2020-10-16 [1] CRAN (R 4.2.0)
 fs               1.5.2      2021-12-08 [1] CRAN (R 4.2.0)
 gargle           1.2.1      2022-09-08 [1] CRAN (R 4.2.0)
 generics         0.1.3      2022-07-05 [1] CRAN (R 4.2.0)
 GGally         * 2.1.2      2021-06-21 [1] CRAN (R 4.2.0)
 ggdist         * 3.2.0      2022-07-19 [1] CRAN (R 4.2.0)
 ggforce        * 0.4.1      2022-10-04 [1] CRAN (R 4.2.0)
 ggformula      * 0.10.2     2022-09-01 [1] CRAN (R 4.2.0)
 gghalves       * 0.1.4      2022-11-20 [1] CRAN (R 4.2.0)
 ggmosaic       * 0.3.4      2022-12-10 [1] Github (haleyjeppson/ggmosaic@fb42e7b)
 ggplot2        * 3.4.0      2022-11-04 [1] CRAN (R 4.2.0)
 ggrepel          0.9.2      2022-11-06 [1] CRAN (R 4.2.0)
 ggridges         0.5.4      2022-09-26 [1] CRAN (R 4.2.0)
 ggstance         0.3.5      2020-12-17 [1] CRAN (R 4.2.0)
 glue             1.6.2      2022-02-24 [1] CRAN (R 4.2.0)
 googledrive      2.0.0      2021-07-08 [1] CRAN (R 4.2.0)
 googlesheets4    1.0.1      2022-08-13 [1] CRAN (R 4.2.0)
 gower            1.0.0      2022-02-03 [1] CRAN (R 4.2.0)
 gridExtra        2.3        2017-09-09 [1] CRAN (R 4.2.0)
 gtable           0.3.1      2022-09-01 [1] CRAN (R 4.2.0)
 haven            2.5.1      2022-08-22 [1] CRAN (R 4.2.0)
 highr            0.9        2021-04-16 [1] CRAN (R 4.2.0)
 Hmisc            4.7-1      2022-08-15 [1] CRAN (R 4.2.0)
 hms              1.1.2      2022-08-19 [1] CRAN (R 4.2.0)
 htmlTable        2.4.1      2022-07-07 [1] CRAN (R 4.2.0)
 htmltools        0.5.4      2022-12-07 [1] CRAN (R 4.2.0)
 htmlwidgets      1.5.4      2021-09-08 [1] CRAN (R 4.2.0)
 httpuv           1.6.6      2022-09-08 [1] CRAN (R 4.2.0)
 httr             1.4.4      2022-08-17 [1] CRAN (R 4.2.0)
 interp           1.1-3      2022-07-13 [1] CRAN (R 4.2.0)
 janitor        * 2.1.0      2021-01-05 [1] CRAN (R 4.2.0)
 jpeg             0.1-9      2021-07-24 [1] CRAN (R 4.2.0)
 jquerylib        0.1.4      2021-04-26 [1] CRAN (R 4.2.0)
 jsonlite         1.8.4      2022-12-06 [1] CRAN (R 4.2.0)
 kableExtra     * 1.3.4      2021-02-20 [1] CRAN (R 4.2.0)
 knitr          * 1.41       2022-11-18 [1] CRAN (R 4.2.0)
 labeling         0.4.2      2020-10-20 [1] CRAN (R 4.2.0)
 labelled         2.10.0     2022-09-14 [1] CRAN (R 4.2.0)
 later            1.3.0      2021-08-18 [1] CRAN (R 4.2.0)
 lattice        * 0.20-45    2021-09-22 [1] CRAN (R 4.2.1)
 latticeExtra     0.6-30     2022-07-04 [1] CRAN (R 4.2.0)
 lazyeval         0.2.2      2019-03-15 [1] CRAN (R 4.2.0)
 lifecycle        1.0.3      2022-10-07 [1] CRAN (R 4.2.0)
 lubridate        1.9.0      2022-11-06 [1] CRAN (R 4.2.0)
 magrittr       * 2.0.3      2022-03-30 [1] CRAN (R 4.2.0)
 MASS             7.3-58.1   2022-08-03 [1] CRAN (R 4.2.0)
 Matrix         * 1.4-1      2022-03-23 [1] CRAN (R 4.2.1)
 mgcv             1.8-41     2022-10-21 [1] CRAN (R 4.2.0)
 mime             0.12       2021-09-28 [1] CRAN (R 4.2.0)
 modelr           0.1.10     2022-11-11 [1] CRAN (R 4.2.1)
 mosaic         * 1.8.4.2    2022-09-20 [1] CRAN (R 4.2.0)
 mosaicCore       0.9.2.1    2022-09-22 [1] CRAN (R 4.2.0)
 mosaicData     * 0.20.3     2022-09-01 [1] CRAN (R 4.2.0)
 munsell          0.5.0      2018-06-12 [1] CRAN (R 4.2.0)
 naniar         * 0.6.1      2021-05-14 [1] CRAN (R 4.2.0)
 nlme             3.1-160    2022-10-10 [1] CRAN (R 4.2.0)
 nnet             7.3-18     2022-09-28 [1] CRAN (R 4.2.0)
 numDeriv         2016.8-1.1 2019-06-06 [1] CRAN (R 4.2.0)
 patchwork      * 1.1.2      2022-08-19 [1] CRAN (R 4.2.0)
 pillar           1.8.1      2022-08-19 [1] CRAN (R 4.2.0)
 pkgconfig        2.0.3      2019-09-22 [1] CRAN (R 4.2.0)
 plotly           4.10.1     2022-11-07 [1] CRAN (R 4.2.0)
 plyr             1.8.8      2022-11-11 [1] CRAN (R 4.2.1)
 png              0.1-7      2013-12-03 [1] CRAN (R 4.2.0)
 polyclip         1.10-4     2022-10-20 [1] CRAN (R 4.2.0)
 productplots     0.1.1      2016-07-02 [1] CRAN (R 4.2.0)
 promises         1.2.0.1    2021-02-11 [1] CRAN (R 4.2.0)
 purrr          * 0.3.5      2022-10-06 [1] CRAN (R 4.2.0)
 R6               2.5.1      2021-08-19 [1] CRAN (R 4.2.0)
 RColorBrewer     1.1-3      2022-04-03 [1] CRAN (R 4.2.0)
 Rcpp             1.0.9      2022-07-08 [1] CRAN (R 4.2.0)
 readr          * 2.1.3      2022-10-01 [1] CRAN (R 4.2.0)
 readxl           1.4.1      2022-08-17 [1] CRAN (R 4.2.0)
 reprex           2.0.2      2022-08-17 [1] CRAN (R 4.2.0)
 reshape          0.8.9      2022-04-12 [1] CRAN (R 4.2.0)
 rlang            1.0.6      2022-09-24 [1] CRAN (R 4.2.0)
 rmarkdown      * 2.18       2022-11-09 [1] CRAN (R 4.2.0)
 rmdformats     * 1.0.4      2022-05-17 [1] CRAN (R 4.2.0)
 rpart            4.1.19     2022-10-21 [1] CRAN (R 4.2.0)
 rstudioapi       0.14       2022-08-22 [1] CRAN (R 4.2.0)
 rvest            1.0.3      2022-08-19 [1] CRAN (R 4.2.0)
 sass             0.4.2      2022-07-16 [1] CRAN (R 4.2.0)
 scales           1.2.1      2022-08-20 [1] CRAN (R 4.2.0)
 sessioninfo      1.2.2      2021-12-06 [1] CRAN (R 4.2.0)
 shiny            1.7.3      2022-10-25 [1] CRAN (R 4.2.0)
 simputation    * 0.2.8      2022-06-16 [1] CRAN (R 4.2.0)
 snakecase        0.11.0     2019-05-25 [1] CRAN (R 4.2.0)
 stringi          1.7.8      2022-07-11 [1] CRAN (R 4.2.0)
 stringr        * 1.5.0      2022-12-02 [1] CRAN (R 4.2.0)
 survival         3.4-0      2022-08-09 [1] CRAN (R 4.2.0)
 svglite          2.1.0      2022-02-03 [1] CRAN (R 4.2.0)
 systemfonts      1.0.4      2022-02-11 [1] CRAN (R 4.2.0)
 tibble         * 3.1.8      2022-07-22 [1] CRAN (R 4.2.0)
 tidyr          * 1.2.1      2022-09-08 [1] CRAN (R 4.2.0)
 tidyselect       1.2.0      2022-10-10 [1] CRAN (R 4.2.0)
 tidyverse      * 1.3.2      2022-07-18 [1] CRAN (R 4.2.0)
 timechange       0.1.1      2022-11-04 [1] CRAN (R 4.2.0)
 tweenr           2.0.2      2022-09-06 [1] CRAN (R 4.2.0)
 tzdb             0.3.0      2022-03-28 [1] CRAN (R 4.2.0)
 utf8             1.2.2      2021-07-24 [1] CRAN (R 4.2.0)
 vctrs            0.5.1      2022-11-16 [1] CRAN (R 4.2.0)
 viridisLite      0.4.1      2022-08-22 [1] CRAN (R 4.2.0)
 visdat           0.5.3      2019-02-15 [1] CRAN (R 4.2.0)
 webshot          0.5.4      2022-09-26 [1] CRAN (R 4.2.0)
 withr            2.5.0      2022-03-03 [1] CRAN (R 4.2.0)
 xfun             0.35       2022-11-16 [1] CRAN (R 4.2.0)
 xml2             1.3.3      2021-11-30 [1] CRAN (R 4.2.0)
 xtable           1.8-4      2019-04-21 [1] CRAN (R 4.2.0)
 yaml             2.3.6      2022-10-18 [1] CRAN (R 4.2.0)
 zoo              1.8-11     2022-09-17 [1] CRAN (R 4.2.0)

 [1] /Library/Frameworks/R.framework/Versions/4.2/Resources/library

────────────────────────────────────────────────────────────────────
LS0tCnRpdGxlOiAiT2JzZXJ2YXRpb25zIG9mIHRyZW5kcyBpbiBFbGVjdHJvbmljIEhlYWx0aCBSZWNvcmQgRGF0YSBBbW9uZyBQYXRpZW50cyBXaG8gSGF2ZSBVbmRlcmdvbmUgYSBTdHJva2UgRXZhbHVhdGlvbiIKYXV0aG9yOiAiQmVuamFtaW4gSGVpZmV0eiIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IAogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOgogICAgaGlnaGxpZ2h0OiBrYXRlCiAgICBudW1iZXJfc2VjdGlvbnM6IFRSVUUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogVFJVRQotLS0KCiMjIFByZWxpbWluYXJ5IGluZm9ybWF0aW9uIHsudW5udW1iZXJlZH0KCkJlY2F1c2UgcGF0aWVudHMgd2hvIGFyZSBtb25pdG9yZWQgZm9yIHN0cm9rZSBzdGF0dXMgZHVyaW5nIGhvc3BpdGFsIHZpc2l0cyBhcmUgb2Z0ZW4gd2F0Y2hlZCBjbG9zZWx5IGFuZCBwdXQgdGhyb3VnaCBhIG15cmlhZCBvZiB0ZXN0cywgdGhleSBtYXkgaGF2ZSBleGNlcHRpb25hbGx5IHJpY2ggRUhSIGRhdGEgYW5kIGJlIHVzZWZ1bCBjbGluaWNhbCByZXNlYXJjaCBzdWJqZWN0cy4gVGhlIHB1cnBvc2Ugb2YgdGhpcyBzdHVkeSBpcyB0byBoaWdobGlnaHQgZm91ciBpbnRlcmVzdGluZyByZXNlYXJjaCBxdWVzdGlvbnMgYW5kIGFuc3dlciB0aGVtIHVzaW5nIEVIUiBkYXRhIHB1bGxlZCBmcm9tIHBhdGllbnRzIHdobyBoYWQgYmVlbiBldmFsdWF0ZWQgZm9yIHN0cm9rZS4KCiMgU2V0dXAgYW5kIERhdGEgSW5nZXN0CgojIyBJbml0aWFsIFIgc2V0dXAKClRoZSBwYWNrYWdlcyBhbmQgcGFyYW1ldGVycyB1c2VkIGluIHRoaXMgY29kZSBjaHVuayBhcmUgcHJlc2VudCBpbiBvcmRlciB0byBnZW5lcmF0ZSBhIGxlZ2libGUgcmVwb3J0LgoKYGBge3Igc2V0dXB9CgpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHJtZGZvcm1hdHMpCmxpYnJhcnkocm1hcmtkb3duKQoKb3B0aW9ucyhtYXgucHJpbnQ9IjEwMCIpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGNvbW1lbnQgPSBOQSkKb3B0aW9ucyh3aWR0aCA9IDcwKQpgYGAKCiMjIExvYWRpbmcgTmVjZXNzYXJ5IFIgUGFja2FnZXMKCkVhY2ggb2YgdGhlIGZvbGxvd2luZyBwYWNrYWdlcyB3ZXJlIG5lY2Vzc2FyeSBmb3IgdGhlIGFuYWx5c2lzIGFuZC9vciBncmFwaGljYWwgZGlzcGxheSBvZiBpbmZvcm1hdGlvbiB1c2VkIGluIHRoaXMgcHJvamVjdC4KCmBgYHtyIGxvYWRfcGFja2FnZXMsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQpzZXR3ZChkaXJuYW1lKGdldHdkKCkpKQpzb3VyY2UoIkxvdmUtYm9vc3QuUiIpCmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShFcGkpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShHR2FsbHkpCmxpYnJhcnkoZ2dmb3JjZSkKbGlicmFyeShnZ2Rpc3QpCmxpYnJhcnkoZ2doYWx2ZXMpCmxpYnJhcnkoZ2dtb3NhaWMpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KG1vc2FpYykKbGlicmFyeShlcXVhdGlvbWF0aWMpCmxpYnJhcnkoc2ltcHV0YXRpb24pIApsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShicm9vbSkKbGlicmFyeShuYW5pYXIpCmxpYnJhcnkodGlkeXZlcnNlKQoKCgp0aGVtZV9zZXQodGhlbWVfYncoKSkKCgpgYGAKCiMjIERhdGEgaW5nZXN0CgpUaGUgZm9sbG93aW5nIGNvZGUgaXMgcHJlc2VudCBmb3IgdGhlIHB1cnBvc2Ugb2YgaW5nZXN0aW5nIHRoZSB0aGUgcmF3IGRhdGEgZnJvbSB0aGUgYFNUUk9LRURBVEEuY3N2YCBmaWxlLiBBZGRpdGlvbmFsbHksIHRoaXMgY29kZSBjb252ZXJ0cyBjZXJ0YWluIGNoYXJhY3RlciB2YXJpYWJsZXMgdXNlZCBpbiB0aGlzIHN0dWR5IGludG8gZmFjdG9ycy4gU3BlY2lmaWNhbGx5LCBhbGwgb2YgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3ZXJlIGNvbnZlcnRlZCBpbnRvIGZhY3RvcnMuIFRoZSBkYXRhIGZvciBgYm1pYCwgd2hpY2ggaXMgYSBxdWFudGl0YXRpdmUgdmFyaWFibGUsIHdhcyBrZXB0IGluIHRoZSBudW1lcmljIGNhdGVnb3J5IGFsb25nc2lkZSBgYXZnX2dsdWNvc2VfbGV2ZWxgIGFuZCBgYWdlYC4gVGhlIGBpZGAgdmFyaWFibGUgaXMgbWFpbnRhaW5lZCBhcyBhIGNoYXJhY3RlciB2YXJpYWJsZSBoZXJlLCBhcyBpdCBpcyBvbmx5IHByZXNlbnQgZm9yIHRoZSBwdXJwb3NlIG9mIGRpc3BsYXlpbmcgYSB1bmlxdWUgbnVtYmVyIGFsb25nc2lkZSBlYWNoIG9ic2VydmF0aW9uLgoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CnN0cm9rZV9yYXcgPC0gcmVhZC5jc3YoIlNUUk9LRURBVEEuY3N2IikgfD4gCiAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuY2hhcmFjdGVyKSwgYXMuZmFjdG9yKSkgfD4KICBtdXRhdGUoaWQgPSBhcy5jaGFyYWN0ZXIoaWQpKSAgfD4gCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5pbnRlZ2VyKSwgYXMuZmFjdG9yKSkgfD4gCiAgbXV0YXRlKGJtaSA9IGFzLmNoYXJhY3RlcihibWkpKSB8PgogIG11dGF0ZShibWkgPSBhcy5udW1lcmljKGJtaSkpIAoKIApgYGAKCiMjIyBTdGFuZGFyZGl6aW5nIHRoZSAidW5rbm93biIgdmFyaWFibGVzIGZvciB0aGUgcmF3IGRhdGFzZXQgey51bm51bWJlcmVkfQoKSXQgYXBwZWFycyB0aGF0IG1pc3NpbmcgdmFsdWVzIGFyZSBub3RlZCBhcyAidW5rbm93biIgaW4gb25seSB0aGUgYHNtb2tpbmdfc3RhdHVzYCB2YXJpYWJsZS4gVGhlIGZvbGxvd2luZyBjb2RlIGlzIG1lYW50IHRvIGNoYW5nZSBpdCB0byAiTi9BIiBzbyB0aGF0IGl0IG1hdGNoZXMgYWxsIG90aGVyIHZhcmlhYmxlcy4gQSBxdWljayBjb3VudCBvZiB0aGUgc21va2luZyBzdGF0dXMgZmFjdG9ycyBpcyBwcm92aWRlZCB0byBzaG93IHRoYXQgdGhlIG5hbWUgd2FzIHByb3Blcmx5IGNoYW5nZWQuCgpgYGB7cn0KCnN0cm9rZV9yYXckc21va2luZ19zdGF0dXMgPC0gcmVjb2RlX2ZhY3RvcihzdHJva2VfcmF3JHNtb2tpbmdfc3RhdHVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVua25vd24iID0gIk4vQSIpCgpzdHJva2VfcmF3IHw+IGNvdW50KHNtb2tpbmdfc3RhdHVzKQpgYGAKCiMgQ2xlYW5pbmcgdGhlIERhdGEKClVzaW5nIHRoZSBjb2RlIGJlbG93LCBhIG5ldyBkYXRhIGZyYW1lIGNhbGxlZCBgc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzYCB3YXMgY3JlYXRlZCwgaW5jbHVkaW5nIG9ubHkgdGhlIHBhdGllbnRzIGluIGBzdHJva2VfcmF3YCB3aXRoIGluZm9ybWF0aW9uIG9uIGFsbCBvZiB0aGUgdmFyaWFibGVzIGNvbGxlY3RlZC4gRm9yIGVuaGFuY2VkIGxlZ2liaWxpdHksIGJpbmFyeSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgd2l0aCBmYWN0b3JzIG9mIDAgYW5kIDEgd2VyZSByZW5hbWVkIHN1Y2ggdGhhdCB0aGUgZmFjdG9ycyByZWZsZWN0ZWQgdGhlIGFjdHVhbCBjbGluaWNhbCBvYnNlcnZhdGlvbi4gRm9yIGV4YW1wbGUsIGluc3RlYWQgb2YgIjAiIGFuZCAiMSIgYmVpbmcgdXNlZCBpbiB0aGUgYGh5cGVydGVuc2lvbmAgdmFyaWFibGUsICJObyBIeXBlcnRlbnNpb24iIGFuZCAiSHlwZXJ0ZW5zaW9uIiB3ZXJlIHVzZWQgcmVzcGVjdGl2ZWx5LiBGaW5hbGx5LCBhIGdsaW1wc2Ugb2YgdGhlIGBzdHJva2VfY29tcGxldGVfY2FzZXNgIHRpYmJsZSBpcyBwcm92aWRlZC4KCkJlY2F1c2UgdGhlIHJlc2VhcmNoIHF1ZXN0aW9uIGZvciBhbmFseXNpcyBFLCB3aGljaCBpcyBleHBsYWluZWQgbGF0ZXIsIG9ubHkgaW52b2x2ZXMgZW1wbG95ZWQgcGVyc29ucywgdGhlIHR3byBjYXRlZ29yaWVzIGZvciB1bmVtcGxveWVkIHBlb3BsZSAoYGNoaWxkcmVuYCBhbmQgYG5ldmVyX3dvcmtlZGApIHdlcmUgb21pdHRlZCBmcm9tIHRoZSBgd29ya190eXBlYCB2YXJpYWJsZS4KCmBgYHtyfQpzdHJva2VfY29tcGxldGVfY2FzZXMgPC0gc3Ryb2tlX3JhdyB8PgogZmlsdGVyKGNvbXBsZXRlLmNhc2VzKGlkLCBhZ2UsIGdlbmRlciwgCiAgICAgICAgICAgICAgICAgICAgICAgaHlwZXJ0ZW5zaW9uLCBoZWFydF9kaXNlYXNlLCAKICAgICAgICAgICAgICAgICAgICAgICBldmVyX21hcnJpZWQsIHdvcmtfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICBSZXNpZGVuY2VfdHlwZSwgCiAgICAgICAgICAgICAgICAgICAgICAgYXZnX2dsdWNvc2VfbGV2ZWwsIGJtaSwgCiAgICAgICAgICAgICAgICAgICAgICAgc21va2luZ19zdGF0dXMsIHN0cm9rZSksICAKICAgICAgICBibWkgIT0gIk4vQSIsIHNtb2tpbmdfc3RhdHVzICE9ICJOL0EiLCBnZW5kZXIgIT0gIk90aGVyIikgfD4gCiAgbXV0YXRlKGdlbmRlciA9IGZjdF9jb2xsYXBzZShmYWN0b3IoZ2VuZGVyKSAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hbGUiID0gIk1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGZW1hbGUiID0gYygiRmVtYWxlIikpKSB8PiAKICBmaWx0ZXIoCiAgICB3b3JrX3R5cGUgPT0gIkdvdnRfam9iIiB8IAogICAgICB3b3JrX3R5cGUgPT0gIlByaXZhdGUiIHwgCiAgICAgIHdvcmtfdHlwZSA9PSAiU2VsZi1lbXBsb3llZCIpIHw+IGRyb3BsZXZlbHMoKQoKCnN0cm9rZV9jb21wbGV0ZV9jYXNlcyR3b3JrX3R5cGUgPC0gcmVjb2RlX2ZhY3RvcihzdHJva2VfY29tcGxldGVfY2FzZXMkd29ya190eXBlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdvdnRfam9iIiA9ICJHb3Zlcm5tZW50IEpvYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQcml2YXRlIiA9ICJQcml2YXRlIFNlY3RvciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWxmLWVtcGxveWVkIiA9ICJTZWxmLUVtcGxveWVkIikKCiNyZW5hbWluZyB0aGUgZmFjdG9ycwpzdHJva2VfY29tcGxldGVfY2FzZXMkaHlwZXJ0ZW5zaW9uIDwtIHJlY29kZV9mYWN0b3Ioc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzJGh5cGVydGVuc2lvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwIiA9ICJObyBIeXBlcnRlbnNpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMSIgPSAiSHlwZXJ0ZW5zaW9uIikKCgpzdHJva2VfY29tcGxldGVfY2FzZXMkaGVhcnRfZGlzZWFzZSA8LSByZWNvZGVfZmFjdG9yKHN0cm9rZV9jb21wbGV0ZV9jYXNlcyRoZWFydF9kaXNlYXNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAiID0gIk5vIEhlYXJ0IERpc2Vhc2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMSIgPSAiSGVhcnQgRGlzZWFzZSIgKQoKc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzJHN0cm9rZSA8LSByZWNvZGVfZmFjdG9yKHN0cm9rZV9jb21wbGV0ZV9jYXNlcyRzdHJva2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMCIgPSAiTm8gU3Ryb2tlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEiID0gIlN0cm9rZSIpCgoKc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzIDwtIHN0cm9rZV9jb21wbGV0ZV9jYXNlcyB8PiAKICBtdXRhdGUoc21va2luZ19zdGF0dXMgPSBmY3RfcmVsZXZlbChzbW9raW5nX3N0YXR1cywgIm5ldmVyIHNtb2tlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImZvcm1lcmx5IHNtb2tlZCIsICJzbW9rZXMiKSl8PiAKICBkcm9wbGV2ZWxzKCkKICAKCnN0cm9rZV9jb21wbGV0ZV9jYXNlcyA8LSBzdHJva2VfY29tcGxldGVfY2FzZXMgfD4gYXNfdGliYmxlKHN0cm9rZV9jb21wbGV0ZV9jYXNlcykKCiMgUmV2aWV3aW5nIHRoZSBkYXRhIHNldAoKZ2xpbXBzZShzdHJva2VfY29tcGxldGVfY2FzZXMpCgpgYGAKCiMjIyBDaGVja2luZyB0byBtYWtlIHN1cmUgdGhhdCBub25lIG9mIHRoZSB2YWx1ZXMgZm9yIGBibWlgIGFyZSB1bnJlYWxpc3RpY2FsbHkgaGlnaDogey51bm51bWJlcmVkfQoKVGhlIGZvbGxvd2luZyBjb2RlIGlzIHByZXNlbnQgZm9yIHRoZSBwdXJwb3NlIG9mIGRpc3BsYXlpbmcgdGhlIG51bWJlciBvZiBgYm1pYCBvYnNlcnZhdGlvbnMgYWJvdmUgNTAgKDEwIHBvaW50cyBhYm92ZSB0aGUgY2xpbmljYWwgbGV2ZWwgb2YgKm1vcmJpZCogb2Jlc2l0eSBhcyBwZXIgdGhlIENEQykgYW5kIGJlbG93IDEwICg4IHBvaW50cyBiZWxvdyB0aGUgY2xpbmljYWxseSAqdW5kZXJ3ZWlnaHQqIGN1dG9mZiBwb2ludCBhcyBwZXIgdGhlIENEQykuIFRoaXMgYWxsb3dzIGZvciBhbnkgYWJub3JtYWxseSBsYXJnZSBvciBzbWFsbCB2YWx1ZXMgaW4gdGhlIGRhdGEgc2V0IHRvIGJlIG5vdGVkIHNvIHRoYXQgdGhleSBjYW4gYmUgb21pdHRlZC4KCmBgYHtyfQoKc3VtKHN0cm9rZV9jb21wbGV0ZV9jYXNlcyRibWkgPiA1MCkgCnN1bShzdHJva2VfY29tcGxldGVfY2FzZXMkYm1pIDwgMTApCgpgYGAKCkFsdGhvdWdoIHRoZSBsb3dlc3QgYGJtaWAgdmFsdWUgaW4gdGhlIGBzdHJva2VfY29tcGxldGVfY2FzZXNgIGRhdGEgZnJhbWUgYXBwZWFycyB0byBiZSBpbiBhIHJlYXNvbmFibGUgYXJlYSBmb3IgYSBsb3cgQk1JIHBlciBDREMgZ3VpZGFuY2UsIHRoZXJlIGFyZSBhIHRvdGFsIG9mIDU4IHJlY29yZGVkIEJNSSB2YWx1ZXMgb3ZlciA1MCwgd2hpY2ggaXMgY29uc2lkZXJhYmx5IGFib3ZlIHRoZSB3aWRlbHkgYWNjZXB0ZWQgY3V0b2ZmIHZhbHVlIGZvciBtb3JiaWQgb2Jlc2l0eSBvZiA0MCAoYXMgcGVyIENEQyBndWlkYW5jZSkuIEZvciB0aGlzIHJlYXNvbiB2YWx1ZXMgb2YgYGJtaWAgb3ZlciA1MCB3aWxsIGJlIHJlbW92ZWQgZnJvbSB0aGUgZGF0YSBmcmFtZSwgYXMgdGhleSBhcmUgZWl0aGVyIHNlcmlvdXMgYW5vbWFsaWVzIG9yIHBvc3NpYmx5IGltcHJvcGVybHkgbWVhc3VyZWQvcmVwb3J0ZWQgdmFsdWVzLgoKIyMjIFJlbW92aW5nIGltcG9zc2libHkgaGlnaCB2YWx1ZXMgey51bm51bWJlcmVkfQoKVGhlIGZvbGxvd2luZyBjb2RlIGlzIHByZXNlbnQgZm9yIHRoZSBwdXJwb3NlIG9mIHJlbW92aW5nIGBibWlgIHZhbHVlcyBpbiB0aGUgYHN0cm9rZV9jb21wbGV0ZV9jYXNlc2AgZGF0YSBmcmFtZSBhYm92ZSA1MC4KCmBgYHtyfQoKc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzIDwtIHN0cm9rZV9jb21wbGV0ZV9jYXNlc1t3aGljaChzdHJva2VfY29tcGxldGVfY2FzZXMkYm1pIDwgNTApLF0KYGBgCgojIyBDcmVhdGluZyBhIGRhdGEgc2V0IGNvbnRhaW5pbmcgb25seSB0aGUgdmFyaWFibGVzIHRvIGJlIHVzZWQgaW4gdGhpcyBzdHVkeQoKQmVjYXVzZSB0aGlzIHByb2plY3Qgd2lsbCBvbmx5IHVzZSBmaXZlIG9mIHRoZSB2YXJpYWJsZXMgaW5jbHVkZWQgaW4gYHN0cm9rZV9jb21wbGV0ZV9jYXNlc2AgdGhlcmUgaXMgbm8gcmVhc29uIHRvIGluY2x1ZGUgaW5mb3JtYXRpb24gb24gdGhlIG90aGVyIHZhcmlhYmxlcyBpbiB0aGUgYW5hbHl0aWMgZGF0YSBmcmFtZSB0aGF0IHdpbGwgYmUgdXNlZCBpbiB0aGlzIHByb2plY3QuIFRoZSBmb2xsb3dpbmcgY29kZSBpcyBwcmVzZW50IHRvIG9ubHkgc2VsZWN0IHRoZSBuZWNlc3NhcnkgdmFyaWFibGVzIGZvciB0aGlzIHN0dWR5IGFuZCBvbWl0IHRoZSByZW1haW5pbmcgdmFyaWFibGVzLgoKYGBge3J9CgoKQTFfc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzIDwtIHN0cm9rZV9jb21wbGV0ZV9jYXNlcyB8PiAKICBzZWxlY3QoaWQsIGdlbmRlciwgc3Ryb2tlLCBibWksIAogICAgICAgICBoeXBlcnRlbnNpb24sIHNtb2tpbmdfc3RhdHVzLCB3b3JrX3R5cGUpCgoKZ2xpbXBzZShBMV9zdHJva2VfY29tcGxldGVfY2FzZXMpIAoKYGBgCgojIyBDaGVja2luZyBmb3IgbWlzc2luZyBkYXRhIG9uIGVhY2ggb2YgdGhlIHNlbGVjdGVkIHZhcmlhYmxlcwoKIyMjIENoZWNraW5nIHRoZSBxdWFudGl0YXRpdmUgdmFyaWFibGUgey51bm51bWJlcmVkfQoKVGhlIGZvbGxvd2luZyBjb2RlIGlzIHByZXNlbnQgZm9yIHRoZSBwdXJwb3NlIG9mIHNlYXJjaGluZyBmb3IgYW55IGV4dHJhbmVvdXMgbWlzc2luZyBkYXRhIGluIHRoZSBxdWFudGl0YXRpdmUgdmFyaWFibGVzLiBBbHRob3VnaCBtaXNzaW5nIGNhc2VzIHdlcmUgcHJldmlvdXNseSBvbWl0dGVkIGZyb20gdGhlIGRhdGEgc2V0LCBpdCBpcyBpbXBvcnRhbnQgdG8gY2hlY2sgYmVmb3JlIHByb2NlZWRpbmcgd2l0aCB0aGUgYW5hbHlzZXMgb2YgdGhpcyBzdHVkeS4gQSBicmllZiBudW1lcmljIHN1bW1hcnkgaXMgYWxzbyBwcm92aWRlZCBpbiBvcmRlciB0byBlbnN1cmUgdGhhdCBubyBpbXBvc3NpYmxlIHZhbHVlcyBhcmUgaW5jbHVkZWQgZm9yIHRoZSBgYm1pYCB2YXJpYWJsZS4KCmBgYHtyfQoKQTFfc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzIHw+IHNlbGVjdChibWkpIHw+CiAgICBtaXNzX3Zhcl9zdW1tYXJ5KCkgCgpBMV9zdHJva2VfY29tcGxldGVfY2FzZXMgfD4gCiAgc2VsZWN0KGJtaSkgfD4KICBtb3NhaWM6Omluc3BlY3QoKSAKCmBgYAoKSXQgY2FuIGJlIHNlZW4gYWJvdmUgdGhhdCwgYXMgZXhwZWN0ZWQsIHRoZXJlIGFyZSBubyBtaXNzaW5nIGBibWlgIG9ic2VydmF0aW9ucyBpbiBvdXIgYW5hbHl0aWMgdGliYmxlLiBBZGRpdGlvbmFsbHksIGl0IGFwcGVhcnMgdGhhdCBubyBgYm1pYCB2YWx1ZXMgYWJvdmUgNTAgYXJlIGluY2x1ZGVkLCBhcyBpbnRlbmRlZC4KCiMjIyBDaGVja2luZyBiaW5hcnkgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHsudW5udW1iZXJlZH0KClRoZSBmb2xsb3dpbmcgY29kZSBpcyBwcmVzZW50IGZvciB0aGUgcHVycG9zZSBvZiBzZWFyY2hpbmcgZm9yIGFueSBleHRyYW5lb3VzIG1pc3NpbmcgZGF0YSBpbiB0aGUgYmluYXJ5IGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gQWxzbyBpbmNsdWRlZCBpcyBhIHRhYmxlIGZyb20gdGhlIGBpbnNwZWN0YCBmdW5jdGlvbiBvZiB0aGUgYG1vc2FpY2AgcGFja2FnZSwgd2hpY2ggZGlzcGxheXMgdGhlIG5hbWUsIGNsYXNzLCBsZXZlbHMsIG4sIG51bWJlciBtaXNzaW5nLCBhbmQgZGlzdHJpYnV0aW9uIG9mIGZhY3RvcnMgZm9yIGVhY2ggdmFyaWFibGUuCgpgYGB7cn0KCkExX3N0cm9rZV9jb21wbGV0ZV9jYXNlcyB8PiAKICBzZWxlY3Qoc3Ryb2tlLCBnZW5kZXIpIHw+CiAgICBtaXNzX3Zhcl9zdW1tYXJ5KCkgCgpBMV9zdHJva2VfY29tcGxldGVfY2FzZXMgfD4gCiAgc2VsZWN0KHN0cm9rZSwgZ2VuZGVyKSB8PiAKICBtb3NhaWM6Omluc3BlY3QoKSAKCmBgYAoKSXQgY2FuIGJlIHNlZW4gYWJvdmUgdGhhdCwgYXMgZXhwZWN0ZWQsIHRoZXJlIGFyZSBubyBtaXNzaW5nIGBzdHJva2VgLCBvciBgZ2VuZGVyYCBvYnNlcnZhdGlvbnMgaW4gb3VyIGFuYWx5dGljIHRpYmJsZS4gQm90aCB2YXJpYWJsZXMgd2VyZSBwcm9wZXJseSBjbGFzc2lmaWVkIGFzIGZhY3RvcnMgd2l0aCB0d28gdW5kZXJzdGFuZGFibHkgbmFtZWQgbGV2ZWxzLgoKIyMjIENoZWNraW5nIG11bHRpY2F0ZWdvcmljYWwgdmFyaWFibGVzIHsudW5udW1iZXJlZH0KClRoZSBmb2xsb3dpbmcgY29kZSBpcyBwcmVzZW50IGZvciB0aGUgcHVycG9zZSBvZiBzZWFyY2hpbmcgZm9yIGFueSBleHRyYW5lb3VzIG1pc3NpbmcgZGF0YSBpbiB0aGUgbXVsdGljYXRlZ29yaWNhbCB2YXJpYWJsZXMuIEFsc28gaW5jbHVkZWQgaXMgYSByZXBvcnQgZnJvbSB0aGUgYGluc3BlY3RgIGZ1bmN0aW9uIG9mIHRoZSBgbW9zYWljYCBwYWNrYWdlLCB3aGljaCBkaXNwbGF5cyB0aGUgbmFtZSwgY2xhc3MsIGxldmVscywgbiwgbnVtYmVyIG1pc3NpbmcsIGFuZCBkaXN0cmlidXRpb24gb2YgZmFjdG9ycyBmb3IgZWFjaCB2YXJpYWJsZS4KCmBgYHtyfQoKQTFfc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzIHw+IAogIHNlbGVjdChzbW9raW5nX3N0YXR1cywgd29ya190eXBlKSB8PgogICAgbWlzc192YXJfc3VtbWFyeSgpIAoKQTFfc3Ryb2tlX2NvbXBsZXRlX2Nhc2VzIHw+CiAgc2VsZWN0KHNtb2tpbmdfc3RhdHVzLCB3b3JrX3R5cGUpIHw+IAogIG1vc2FpYzo6aW5zcGVjdCgpIAoKYGBgCgpJdCBjYW4gYmUgc2VlbiBhYm92ZSB0aGF0LCBhcyBleHBlY3RlZCwgdGhlcmUgYXJlIG5vIG1pc3NpbmcgYHNtb2tpbmdfc3RhdHVzYCwgb3IgYHdvcmtfdHlwZWAgb2JzZXJ2YXRpb25zIGluIG91ciBhbmFseXRpYyB0aWJibGUuIEJvdGggYXJlIGNsYXNzaWZpZWQgYXMgZmFjdG9ycyB3aXRoIHRoZSBpbnRlbmRlZCBudW1iZXIgb2YgbGV2ZWxzIHByZXNlbnQuCgojIyBQcmludGluZyBUaGUgYW5hbHl0aWMgdGliYmxlCgpUaGUgZm9sbG93aW5nIGNvZGUgaXMgcHJlc2VudCBmb3IgdGhlIHB1cnBvc2Ugb2YgcmVuYW1pbmcgdGhlIGRhdGEgc2V0IGNvbnRhaW5pbmcgYWxsIG9mIHRoZSBzaXggdmFyaWFibGVzIGFuZCBwcmludGluZyBpdCB0byBzaG93IHRoZSBmaW5hbCBhbmFseXRpYyB0aWJibGUgdGhhdCB3aWxsIGJlIHVzZWQgaW4gYWxsIHN1YnNlcXVlbnQgYW5hbHlzZXMuCgpgYGB7cn0KClN0cm9rZV9kYXRhIDwtIEExX3N0cm9rZV9jb21wbGV0ZV9jYXNlcwoKU3Ryb2tlX2RhdGEKCmBgYAoKIyMjIExpc3Qgb2YgbWlzc2luZyB2YWx1ZXMgey51bm51bWJlcmVkfQoKVGhlIGZvbGxvd2luZyBjb2RlIHByb3ZpZGVzIG9uZSBmaW5hbCBjb3VudCBvZiBtaXNzaW5nIHZhcmlhYmxlcyB0byBlbnN1cmUgdGhhdCBzdWJzZXF1ZW50IGFuYWx5c2VzIGluY2x1ZGUgb25seSBjb21wbGV0ZSBjYXNlcy4gSXQgc2hvdWxkIGJlIG5vdGVkIHRoYXQgaW4gdGhpcyBzdHVkeSwgYWxsIG1pc3NpbmcgZGF0YSBpcyBjb25zaWRlcmVkIHRvIGJlIG1pc3NpbmcgY29tcGxldGVseSBhdCByYW5kb20gKE1DQVIpLiAgCgpgYGB7cn0KbWlzc192YXJfc3VtbWFyeShTdHJva2VfZGF0YSkKYGBgCgojIENvZGVib29rIGFuZCBEYXRhIERlc2NyaXB0aW9uCgojIyMgRGVzY3JpcHRpb24gb2YgdGhlIHN1YmplY3RzIG9mIHRoaXMgc3R1ZHkgey19CgpUaGUgZGF0YSB1c2VkIGZvciB0aGlzIHN0dWR5IHdhcyB0YWtlbiBmcm9tIHRoZSBlbGVjdHJvbmljIGhlYWx0aCByZWNvcmRzIChFSFJzKSBvZiAzMjg1IHBlcnNvbnMgYWdlZCAxMC04MiB3aG8sIHdpdGhpbiB0aGVpciBFSFIsIGhhZCBleHBsaWNpdGx5IGJlZW4gbm90ZWQgYXMgZWl0aGVyIGhhdmluZyBzdWZmZXJlZCBhIHN0cm9rZSBpbiB0aGVpciBsaWZlIG9yIGhhdmluZyBub3Qgc3VmZmVyZWQgYSBzdHJva2UgaW4gdGhlaXIgbGlmZS4gQWxsIEVIUiBkYXRhIHVzZWQgaW4gdGhpcyBzdHVkeSB3YXMgZGUtaWRlbnRpZmllZCBhbmQgbWFkZSBwdWJsaWMgYnkgTWNLaW5zZXkgYW5kIENvbXBhbnksIGEgY29uc3VsdGluZyBmaXJtIHdpdGggb3ZlcnNpZ2h0IG92ZXIgYSBudW1iZXIgb2YgVVMgaG9zcGl0YWwgRUhScy4gQWxsIHN1YmplY3RzIGhhZCBjb21wbGV0ZSBkYXRhIGZvciBlYWNoIG9mIHRoZSB2YXJpYWJsZXMgbGlzdGVkIGJlbG93LgoKIyMgQ29kZWJvb2sKCioqRGVzY3JpcHRpb24gb2YgVmFyaWFibGVzKioKClRoZSBmb2xsb3dpbmcgdGFibGUgY29udGFpbnMgdGhlIG5hbWUgb2YgZWFjaCB2YXJpYWJsZSBpbiB0aGUgYFN0cm9rZV9kYXRhYCBkYXRhIHNldCB1c2VkIGZvciB0aGlzIGFuYWx5c2lzLCB0aGUgdHlwZSBvZiB2YXJpYWJsZSBpdCBpcywgYW5kIGEgYnJpZWYgZGVzY3JpcHRpb24gb2YgdGhlIGxldmVscyBmb3IgZWFjaCB2YXJpYWJsZS4gVGhlIHZhcmlhYmxlIHR5cGVzIGFyZSBkZW5vdGVkIGFzIHN1Y2g6CgotICAgKklEID0gSWRlbnRpZmljYXRpb24gbnVtYmVyKgoKLSAgICpRdWFudCA9IFF1YW50aXRhdGl2ZSB2YXJpYWJsZXMqCgotICAgKkJpbmFyeSA9IFR3by1jYXRlZ29yeSB2YXJpYWJsZXMqCgotICAgKlgtY2F0ID0gTXVsdGljYXRlZ29yaWNhbCB2YXJpYWJsZXMpIHdoZXJlIFggaW5kaWNhdGVzIHRoZSBudW1iZXIgb2YgbGV2ZWxzIGluIHRoZSB2YXJpYWJsZS4qCgp8IFZhcmlhYmxlICAgICAgICAgfCAgVHlwZSAgfCBEZXNjcmlwdGlvbiAvIExldmVscyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tOnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgYGlkYCAgICAgICAgICAgICB8ICAgSUQgICB8IEEgdW5pcXVlIGlkZW50aWZpY2F0aW9uIG51bWJlciBhc3NpZ25lZCB0byBlYWNoIHBhcnRpY2lwYW50ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgZ2VuZGVyYCAgICAgICAgIHwgQmluYXJ5IHwgVGhlIGdlbmRlciBvZiB0aGUgc3ViamVjdCBiYXNlZCBvbiByZWNvcmRpbmcgaW4gdGhlIHBhdGllbnQncyBFSFIuICoqIk1hbGUiKiogaW5kaWNhdGVzIHRoYXQgdGhlIHN1YmplY3Qgd2FzIG1hbGUsICoqIkZlbWFsZSIqKiBpbmRpY2F0ZXMgdGhhdCB0aGV5IHdlcmUgZmVtYWxlLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBzdHJva2VgICAgICAgICAgfCBCaW5hcnkgfCBXaGV0aGVyIG9yIG5vdCBlbGVjdHJvbmljIGhlYWx0aCByZWNvcmRzIGluZGljYXRlZCB0aGF0IHRoZSBpbmRpdmlkdWFsIGhhZCBzdWZmZXJlZCBhIHN0cm9rZSBhdCBzb21lIHBvaW50IGluIHRoZWlyIGxpZmUuICoqIlN0cm9rZSIqKiBpbmRpY2F0ZXMgdGhhdCB0aGV5IHN1ZmZlcmVkIGEgc3Ryb2tlLCAqKiJObyBTdHJva2UiKiogaW5kaWNhdGVzIHRoYXQgdGhleSBkaWQgbm90LiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYGJtaWAgICAgICAgICAgICB8IFF1YW50ICB8IEN1cnJlbnQgYm9keSBtYXNzIGluZGV4IG9mIHRoZSBwYXRpZW50IGFzIGluZGljYXRlZCBieSB0aGF0IHBhdGllbnQncyBFSFIuIEJvZHkgbWFzcyBpbmRleCBpcyBjYWxjdWxhdGVkIGJ5IGRpdmlkaW5nIHdlaWdodCBpbiBwb3VuZHMgKGxiKSBieSBoZWlnaHQgaW4gaW5jaGVzIChpbikgc3F1YXJlZCBhbmQgbXVsdGlwbHlpbmcgdGhhdCB2YWx1ZSBieSBhIGNvbnZlcnNpb24gZmFjdG9yIG9mIDcwMy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgc21va2luZ19zdGF0dXNgIHwgMy1DYXQgIHwgVGhlIHNtb2tpbmcgc3RhdHVzIG9mIHRoZSBwYXRpZW50IGFzIGluZGljYXRlZCBieSB0aGF0IHBhdGllbnQncyBFSFIuICoqIm5ldmVyIHNtb2tlZCIqKiBpbmRpY2F0ZXMgdGhhdCB0aGUgcGF0aWVudCBoYXMgbm8gaGlzdG9yeSBvZiBzbW9raW5nLCAqKiJmb3JtZXJseSBzbW9rZWQiKiogaW5kaWNhdGVzIHRoYXQgdGhleSBoYXZlLCBidXQgbm8gbG9uZ2VyIHNtb2tlLCBhbmQgKioic21va2VzIioqIGluZGljYXRlcyB0aGF0IHRoZSBwYXRpZW50IGN1cnJlbnRseSBzbW9rZXMuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgd29ya190eXBlYCAgICAgIHwgNS1DYXQgIHwgVGhlIGNhdGVnb3J5IG9mIHdvcmsgb2YgdGhlIHBhdGllbnQgYXMgaW5kaWNhdGVkIGJ5IHRoYXQgcGF0aWVudCdzIEVIUi4gKioiR292dF9qb2IiKiogaW5kaWNhdGVzIHRoYXQgdGhlIHBhdGllbnQgd29ya3MgZm9yIHRoZSBnb3Zlcm5tZW50IChwdWJsaWMgc2VjdG9yKSwgKioiUHJpdmF0ZSIqKiBpbmRpY2F0ZXMgdGhhdCB0aGUgcGF0aWVudCBpcyBlbXBsb3llZCBhbmQgd29ya3MgZm9yIGEgcHJpdmF0ZSBjb21wYW55IChwcml2YXRlIHNlY3RvciksICoqIlNlbGYtZW1wbG95ZWQiKiogaW5kaWNhdGVzIHRoYXQgdGhlIHBhdGllbnQgaXMgc2VsZiBlbXBsb3llZC4gfAp8IGBoeXBlcnRlbnNpb25gICAgfCBCaW5hcnkgfCBUaGUgaHlwZXJ0ZW5zaXZlIHN0YXR1cyBvZiB0aGUgcGF0aWVudCBhcyBpbmRpY2F0ZWQgYnkgdGhhdCBwYXRpZW50J3MgRUhSLiAqKiJObyBIeXBlcnRlbnNpb24iKiogaW5kaWNhdGVzIHRoYXQgdGhlIHBhdGllbnQgZG9lcyBub3QgaGF2ZSBoeXBlcnRlbnNpb24gKGhpZ2ggYmxvb2QgcHJlc3N1cmUpIGFuZCAqKiJIeXBlcnRlbnNpb24iKiogaW5kaWNhdGVzIHRoYXQgdGhlIHBhdGllbnQgaGFzIGh5cGVydGVuc2lvbiAoaGlnaCBibG9vZCBwcmVzc3VyZSkuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CgojIyBBbmFseXRpYyBUaWJibGUKClRoZSBmb2xsb3dpbmcgY29kZSBpcyBwcmVzZW50IGZvciB0aGUgcHVycG9zZSBvZiBwcmludGluZyB0aGUgYW5hbHl0aWMgdGliYmxlIGluIG9yZGVyIHRvIHNob3cgdGhhdCBpdCBpcywgaW4gZmFjdCwgYSB0aWJibGUuCgpgYGB7cn0KClN0cm9rZV9kYXRhCgpgYGAKCiMjIERhdGEgc3VtbWFyeQoKVGhlIGZvbGxvd2luZyBjb2RlIGlzIHByZXNlbnQgZm9yIHRoZSBwdXJwb3NlIG9mIGNyZWF0aW5nIGEgZGVzY3JpcHRpdmUgc3VtbWFyeSBvZiBlYWNoIG9mIHRoZSB2YXJpYWJsZXMgdXNlZCBpbiB0aGUgdGliYmxlIGZvciB0aGlzIHN0dWR5LgoKYGBge3J9CgpIbWlzYzo6ZGVzY3JpYmUoU3Ryb2tlX2RhdGEpCgpgYGAKCiMgQW5hbHlzaXMgQjogQ29tcGFyaW5nIFR3byBQb3B1bGF0aW9uIE1lYW5zIHdpdGggSW5kZXBlbmRlbnQgU2FtcGxlcwoKIyMgUmVzZWFyY2ggUXVlc3Rpb24KCkluIHRoaXMgYW5hbHlzaXMsIHRoZSBgYm1pYCB2YWx1ZXMgaW4gdGhlIGBTdHJva2VfZGF0YWAgdGliYmxlIHdpbGwgYmUgY29tcGFyZWQgdG8gdGhlIGBzdHJva2VgIHN0YXR1cyBvZiB0aGUgcGF0aWVudHMgaW5jbHVkZWQgaW4gdGhlIHN0dWR5LCB3aXRoIHRoZSBvYmplY3RpdmUgb2YgaWRlbnRpZnlpbmcgaWYgdGhlcmUgaXMgYW55IG1lYW5pbmdmdWwgZGlmZmVyZW5jZSBpbiBgYm1pYCBmb3IgcGF0aWVudHMgd2hvIHdlcmUgcmVjb3JkZWQgYXMgaGF2aW5nIGEgc3Ryb2tlIHZzIHRob3NlIHdobyB3ZXJlIG5vdCByZWNvcmRlZCBhcyBoYXZpbmcgYSBzdHJva2UuIFRoaXMgaW5mb3JtYXRpb24gbWF5IGJlIGEgdXNlZnVsIGh5cG90aGVzaXMgZ2VuZXJhdG9yIGZvciByZXNlYXJjaGVycyBsb29raW5nIHRvIGludmVzdGlnYXRlIHRoZSBwb3NzaWJsZSBjbGluaWNhbCBhcHBlYXJhbmNlcyBvZiBwYXRpZW50cyBtb3JlIGxpa2VseSB0byBzdWZmZXIgYSBzdHJva2UuIEZvciB0aGlzIHN0dWR5LCBhIDkwJSBjb25maWRlbmNlIGludGVydmFsIHdpbGwgYmUgdXNlZCBpbiBhbGwgYW5hbHlzZXMuIFRoZSByZXNlYXJjaCBxdWVzdGlvbiBpcyBhcyBmb2xsb3dzOgoKKipJcyB0aGVyZSBhIG1lYW5pbmdmdWwgZGlmZmVyZW5jZSBpbiBtZWFuIEJNSSBiZXR3ZWVuIHBhdGllbnRzIHRoYXQgaGF2ZSBiZWVuIG5vdGVkIGFzIGhhdmluZyBzdWZmZXJlZCBhIHN0cm9rZSBpbiB0aGVpciBlbGVjdHJvbmljIG1lZGljYWwgaGlzdG9yeSBhbmQgdGhvc2Ugd2hvIGhhdmUgbm90IGJlZW4gbm90ZWQgYXMgaGF2aW5nIHN1ZmZlcmVkIGEgc3Ryb2tlIGluIHRoZWlyIGVsZWN0cm9uaWMgbWVkaWNhbCBoaXN0b3J5PyoqCgojIyBEZXNjcmliaW5nIHRoZSBEYXRhCgpJbiB0aGlzIGFuYWx5c2lzLCB0d28gdmFyaWFibGVzIHdpbGwgYmUgZXhhbWluZWQuIE9uZSBpcyBzdHJva2Ugc3RhdHVzLCB3aGljaCBpcyBhIGJpbmFyeSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBuYW1lZCBgc3Ryb2tlYCB3aXRoIHRoZSBsZXZlbHMgIk5vIFN0cm9rZSIgYW5kICJTdHJva2UiLCByZXByZXNlbnRpbmcgd2hldGhlciBvciBub3QgZWxlY3Ryb25pYyBtZWRpY2FsIHJlY29yZHMgaW5kaWNhdGVkIHRoYXQgdGhlIGluZGl2aWR1YWwgaGFkIHN1ZmZlcmVkIGEgc3Ryb2tlIGF0IHNvbWUgcG9pbnQgaW4gdGhlaXIgbGlmZS4gIlN0cm9rZSIgaW5kaWNhdGVzIHRoYXQgdGhleSBzdWZmZXJlZCBhIHN0cm9rZSwgIk5vIFN0cm9rZSIgaW5kaWNhdGVzIHRoYXQgdGhleSBkaWQgbm90LgoKVGhlIHNlY29uZCB2YXJpYWJsZSBpcyBCTUksIHdoaWNoIGlzIGEgcXVhbnRpdGF0aXZlIHZhcmlhYmxlIGRlc2NyaWJpbmcgdGhlIGN1cnJlbnQgYm9keSBtYXNzIGluZGV4IG9mIHRoZSBwYXRpZW50IGFzIGluZGljYXRlZCBieSB0aGF0IHBhdGllbnQncyBFSFIuCgojIyMgTnVtZXJpY2FsIHN1bW1hcnkgey51bm51bWJlcmVkfQoKVGhlIGZvbGxvd2luZyBjb2RlIGlzIHByZXNlbnQgZm9yIHRoZSBwdXJwb3NlIG9mIGRpc3BsYXlpbmcgYSBicmllZiBudW1lcmljYWwgc3VtbWFyeSBvZiB0aGUgYGJtaWAgZGF0YSBiZXR3ZWVuIHBhdGllbnRzIHRoYXQgaGF2ZSBzdWZmZXJlZCBhIHN0cm9rZSBhbmQgcGF0aWVudHMgd2hvIGhhdmUgbm90LgoKYGBge3J9Cgptb3NhaWM6OmZhdnN0YXRzKGJtaSB+IHN0cm9rZSwgZGF0YSA9IFN0cm9rZV9kYXRhKSB8PiAKICBrYmwoY2FwdGlvbiA9ICJOdW1lcmljYWwgc3VtbWFyeSBvZiBCTUkgYnkgc3Ryb2tlIHN0YXR1cyIsIAogICAgICBkaWdpdHMgPSAyKSB8PiAKICBrYWJsZV9zdHlsaW5nKGZvbnRfc2l6ZSA9IDIwKSB8PgogIGthYmxlX3BhcGVyKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKQoKYGBgCgpJdCBjYW4gYmUgc2VlbiBpbiB0aGUgdGFibGUgYWJvdmUgdGhhdCB0aGUgdHdvIGBzdHJva2VgIGNsYXNzaWZpZWQgZ3JvdXBzIGhhdmUgdmVyeSBzaW1pbGFyIHZhbHVlcyBmb3IgbWF4LCBtZWFuLCBtZWRpYW4sIGFuZCBpbnRlcnF1YXJ0aWxlIHJhbmdlLiBIb3dldmVyIHRoZSBtaW5pbXVtIHZhbHVlIGZvciB0aGUgIk5vIFN0cm9rZSIgZ3JvdXAgd2FzIGNvbnNpZGVyYWJseSBsb3dlciB0aGFuIHRoYXQgb2YgdGhlICJTdHJva2UiIGdyb3VwLiBJdCBzaG91bGQgYWxzbyBiZSBub3RlZCB0aGF0IHRoZXJlIGFyZSBtYW55IG1vcmUgcGF0aWVudHMgd2l0aGluIHRoZSAiTm8gU3Ryb2tlIiBncm91cCB0aGFuIHRoZSAiU3Ryb2tlIiBncm91cC4KCiMjIyBHcmFwaGljYWwgYXNzZXNzbWVudCBvZiBTeW1tZXRyeSBhbmQgTm9ybWFsaXR5IHsudW5udW1iZXJlZH0KCkluIG9yZGVyIHRvIHZpc3VhbGl6ZSB0aGUgb3ZlcmFsbCBkaXN0cmlidXRpb24gb2YgZGF0YSBpbiB0ZXJtcyBvZiBCTUksIGEgaGlzdG9ncmFtIHdhcyBjb25zdHJ1Y3RlZCBjb21wcmlzaW5nIHRoZSBlbnRpcmUgcmFuZ2UgZm9yIGBibWlgIG9mIHRoZSBgU3Ryb2tlX2RhdGFgIGRhdGEgc2V0LCB3aXRoIHBvcnRpb25zIG9mIHRoZSBoaXN0b2dyYW0gaGlnaGxpZ2h0ZWQgdG8gc2hvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB0d28gYHN0cm9rZWAgZ3JvdXBzLgoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChTdHJva2VfZGF0YSwgYWVzKHggPSBibWksIGZpbGwgPSBzdHJva2UsIGNvbG9yID0gMikpICsKICAgIGdlb21faGlzdG9ncmFtKGJpbnMgPSA3NSkgKyAKICAgIGd1aWRlcyhjb2xvciA9ICJub25lIikgKwogICAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgQk1JIFZhbHVlcyBGb3IgQWxsIFBhdGllbnRzIEFzc2Vzc2VkIGZvciBTdHJva2UiLAogICAgICAgICB4ID0gIkJvZHkgTWFzcyBJbmRleCAoQk1JKSIpICsgdGhlbWUoCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImxlbW9uY2hpZmZvbjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC41LCBsaW5ldHlwZSA9ICJzb2xpZCIpKSArIAogIHRoZW1lKHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImF6dXJlMiIpKQoKYGBgCgpUaGUgYWJvdmUgcGxvdCByZXZlYWxzIGEgZGlzdHJpYnV0aW9uIHRoYXQgYXBwZWFycyB0byBiZSBmYWlybHkgbm9ybWFsIHdpdGggc29tZSByaWdodCBza2V3LiBJdCBjYW4gYmUgc2VlbiB0aGF0IHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGlzIHByZXNlbnQgaW4gYm90aCBjYXRlZ29yaWVzIG9mIGBzdHJva2VgLCBidXQgdGhhdCB0aGUgIk5vIFN0cm9rZSIgY2F0ZWdvcnkgd2FzIG1vcmUgcHJvbm91bmNlZC4gVGhpcyB3YXMgZXhwZWN0ZWQsIGFzIGluIHRoZSBudW1lcmljYWwgc3VtbWFyeSBpdCB3YXMgZGVtb25zdHJhdGVkIHRoYXQgdGhlICJObyBTdHJva2UiIGNhdGVnb3J5IGhhZCBhbG1vc3QgMzAwMCBtb3JlIG9ic2VydmF0aW9ucyB0aGFuIHRoZSAiU3Ryb2tlIiBjYXRlZ29yeS4KCkEgYm94IGFuZCB2aW9saW4gcGxvdCBqdXh0YXBvc2VkIHdpdGggbm9ybWFsIFFRIHBsb3RzIGZvciBgYm1pYCBpbiBlYWNoIGBzdHJva2VgIGNhdGVnb3J5IGlzIGFsc28gdXNlZnVsIGZvciB2aXN1YWxpemluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHZhbHVlcyBpbiB0aGlzIGRhdGEuIFRoZSBmb2xsb3dpbmcgY29kZSBkaXNwbGF5cyBzdWNoIGEgcGxvdDoKCmBgYHtyLCB3YXJuaW5nPSBGQUxTRX0KCnAxIDwtIGdncGxvdChTdHJva2VfZGF0YSwgYWVzKHggPSBzdHJva2UsIHkgPSBibWksIGZpbGwgPSBzdHJva2UpKSArIAogIGdlb21fdmlvbGluKGFscGhhID0gMC4zKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4zLCBub3RjaCA9IFRSVUUpICsKICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiQk1JIGJ5IFN0cm9rZSBTdGF0dXMiLAogICAgICAgeCA9ICJFSFIgaW5kaWNhdGlvbiBvZiBhIHN0cm9rZSIsIAogICAgICAgeSA9ICJCb2R5IE1hc3MgSW5kZXggKEJNSSkiKSArIAogIHRoZW1lKHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImF6dXJlMiIpKQoKcDIgPC0gZ2dwbG90KFN0cm9rZV9kYXRhLCBhZXMoc2FtcGxlID0gYm1pLCBjb2wgPSBzdHJva2UpKSArCiAgZ2VvbV9xcSgpICsgZ2VvbV9xcV9saW5lKCkgKwogIGZhY2V0X3dyYXAofiBzdHJva2UsIGxhYmVsbGVyID0gImxhYmVsX2JvdGgiKSArCiAgZ3VpZGVzKGNvbCA9ICJub25lIikgKwogIHRoZW1lX2J3KCkgKwogIGxhYnMoeSA9ICJCb2R5IE1hc3MgSW5kZXggKEJNSSkiLAogICAgICAgdGl0bGUgPSAiTm9ybWFsIFFRIHBsb3QgZm9yIEJNSSIpICsgCiAgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiYXp1cmUyIikpCgpwMSArIHRoZW1lKAogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuNSwgbGluZXR5cGUgPSAic29saWQiKSkgKyAKICBwMiAgKyAKICB0aGVtZShwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhenVyZTIiKSkgKyAKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImxlbW9uY2hpZmZvbjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjUsIGxpbmV0eXBlID0gInNvbGlkIikpIAoKCgpgYGAKClRoZSB0d28gdmlvbGluIHBsb3RzIGRlbW9uc3RyYXRlIGEgcmVsYXRpdmVseSBub3JtYWwgZGlzdHJpYnV0aW9uIGFuZCBmZXcgb3V0bGllcnMgZm9yIGJvdGggb2YgdGhlIGBzdHJva2VgIGNhdGVnb3JpZXMuIFRoZSBub3JtYWwgUVEgcGxvdHMgaGVscCB0byB2aXN1YWxpemUgdGhlIGRlZ3JlZSBvZiBza2V3IHNlZW4gaW4gdGhlIGRhdGEsIHdoaWNoLCBhcyBzdWdnZXN0ZWQgYnkgdGhlIGhpc3RvZ3JhbSBpcyB0byB0aGUgcmlnaHQsIHNsaWdodGx5LgoKSW4gb3JkZXIgdG8gYmV0dGVyIHZpc3VhbGl6ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIGBibWlgIGZvciBlYWNoIGBzdHJva2VgIGNhdGVnb3J5IGFuZCBzcGVjaWZpY2FsbHkgdG8gdmlzdWFsaXplIHRoZSBoaWdoZXN0IGRlbnNpdHkgYXJlYXMgb2YgcG9wdWxhdGlvbiBmb3IgZWFjaCBcYGJtaSwgYSByYWluIGNsb3VkIHBsb3QgbWEgYmUgdXNlZnVsLiBUaGUgZm9sbG93aW5nIGNvZGUgaXMgcHJlc2VudCBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzcGxheWluZyBhIHJhaW4gY2xvdWQgcGxvdC4KCmBgYHtyLCB3YXJuaW5nPSBGQUxTRX0KCmdncGxvdChTdHJva2VfZGF0YSwgYWVzKHN0cm9rZSwgYm1pKSkgKyAKICBnZ2Rpc3Q6OnN0YXRfaGFsZmV5ZShhZGp1c3QgPSAuNSwgd2lkdGggPSAuMywgCiAgICAgICAgICAgICAgICAgICAgICAgLndpZHRoID0gMCwganVzdGlmaWNhdGlvbiA9IC0uMywgCiAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRfY29sb3VyID0gTkEsIGZpbGwgPSAiZGFya3R1cnF1b2lzZSIpICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gLjEsIG91dGxpZXIuc2hhcGUgPSBOQSwgZmlsbCA9ICJ0b21hdG8xIiAsIAogICAgICAgICAgICAgICBvdXRsaWVyLmNvbG9yID0gImJsYWNrIikgKyAKICBzdGF0X3N1bW1hcnkoZnVuID0gIm1lYW4iLCBnZW9tID0gInBvaW50IiwgCiAgICAgICAgICAgICAgIHNoYXBlID0gMjMsIHNpemUgPSAzLCBmaWxsID0gIndoaXRlIikgKwogIAogIHRoZW1lKAogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuNSwgbGluZXR5cGUgPSAic29saWQiKSkgKwogbGFicygKICAgIHRpdGxlID0gIkJNSSBieSBzdHJva2Ugc3RhdHVzIiwgCiAgICBzdWJ0aXRsZSA9IAogICAgICAiRm9yIFBhdGllbnRzIFdobyBIYXZlIFN0cm9rZSBFdmFsdWF0aW9uIEluZm9ybWF0aW9uIGluIFRoZWlyIEVIUiIsCiAgICB5ID0gIkJvZHkgTWFzcyBJbmRleCAoQk1JKSIsIAogICAgeD0iU3Ryb2tlIFN0YXR1cyIpICsgCiAgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiYXp1cmUyIikpCgpgYGAKCkl0IGNhbiBiZSBzZWVuIGluIHRoZSByYWluIGNsb3VkIHBsb3QgYWJvdmUsIHNpbWlsYXJseSB0byB0aGUgdmlvbGluIHBsb3QgZGVwaWN0ZWQgYWJvdmUsIHRoYXQgdGhlIG1lYW4gYW5kIG1lZGlhbiB2YWx1ZXMgb2YgYGJtaWAgYXJlIHZlcnkgY2xvc2UgZm9yIGJvdGggYHN0cm9rZWAgY2F0ZWdvcmllcy4gSXQgY2FuIGFsc28gYmUgc2VlbiB0aGF0IHRoZSBncmVhdGVzdCBudW1iZXIgb2YgcGVvcGxlIGluIGVhY2ggZ3JvdXAgaGF2ZSBgYm1pYCB2YWx1ZXMgc2xpZ2h0bHkgYWJvdmUgMzAsIHdoaWNoIHRoZSBDREMgd291bGQgY29uc2lkZXIgdG8gYmUgb3ZlcndlaWdodC4KCiMjIyBOdW1lcmljYWwgQXNzZXNzbWVudCBvZiBTa2V3IHsudW5udW1iZXJlZH0KCkluIG9yZGVyIHRvIGRldGVybWluZSB0aGUgdHlwZSBvZiB0ZXN0IHVzZWQgdG8gZmlndXJlIG91dCBpZiB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgbWVhbmluZ2Z1bCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGBibWlgIHZhbHVlcyBvZiBwYXRpZW50cyB3aG8gaGFkIGEgc3Ryb2tlIGFuZCB0aG9zZSB3aG8gZGlkIG5vdCwgdGhlIG5vcm1hbGl0eSBvZiB0aGUgZGlzdHJpYnV0aW9uIG9mIGBibWlgIHZhbHVlcyBtdXN0IGJlIGFzc2Vzc2VkLiBXaGlsZSB0aGUgdmlzdWFsaXphdGlvbnMgYXJlIHVzZWZ1bCBpbiBkZXRlcm1pbmluZyBvYnZpb3VzIHNrZXcsIGl0IGlzIGFsc28gdXNlZnVsIHRvIGVuc3VyZSB0aGF0IHRoZSBkYXRhIGlzIG5vcm1hbCB1c2luZyBhIG5vbnBhcmFtZXRyaWMgc2tldyBhbmFseXNpcy4gSW4gdGhpcyBhbmFseXNpcywgbm9ucGFyYW1ldHJpYyBza2V3IGlzIGNhbGN1bGF0ZWQgYnkgdGFraW5nIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1lYW4gYW5kIHRoZSBtZWRpYW4sIGFuZCBkaXZpZGluZyBpdCBieSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uLiBUaGlzIHBhcnRpY3VsYXIgdHlwZSBvZiBza2V3IGlzIGJhc2VkIG9mZiBvZiBQZWFyc29uJ3Mgbm90aW9uIG9mIG1lZGlhbiBza2V3bmVzcywgd2l0aCB2YWx1ZXMgZmFsbGluZyBiZXR3ZWVuIC0xIGFuZCArMSBmb3IgYW55IGRpc3RyaWJ1dGlvbi4gR2VuZXJhbGx5LCB3aGVuIHRoaXMgbWVhc3VyZSBvZiBza2V3IGlzIHVzZWQsIHZhbHVlcyBncmVhdGVyIHRoYW4gKyAwLjIgaW5kaWNhdGUgZmFpcmx5IHN1YnN0YW50aWFsIHJpZ2h0IHNrZXcsIHdoaWxlIHZhbHVlcyBiZWxvdyAtMC4yIGluZGljYXRlIGZhaXJseSBzdWJzdGFudGlhbCBsZWZ0IHNrZXcuIElmIHRoZSBza2V3bmVzcyB2YWx1ZSBmb3IgYGJtaWAgaXMgYmV0d2VlbiAtMC4yIGFuZCArMC4yLCB0aGUgZGF0YSB3aWxsIGJlIGNvbnNpZGVyZWQgdG8gYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCgpgYGB7cn0KU3Ryb2tlX2RhdGF8PiBncm91cF9ieShzdHJva2UpIHw+CiAgc3VtbWFyaXplKHNrZXcgPSByb3VuZF9oYWxmX3VwKChtZWFuKGJtaSkgLSBtZWRpYW4oYm1pKSkvc2QoYm1pKSwgMykpIHw+IAogIGtibChjYXB0aW9uID0gIkFzc2Vzc21lbnQgb2YgU2tldyBieSBTdHJva2UgU3RhdHVzIiwgZGlnaXRzID0gNSkgfD4gCiAga2FibGVfc3R5bGluZyhmb250X3NpemUgPSAyMCkgfD4gCiAga2FibGVfcGFwZXIoImhvdmVyIiwgZnVsbF93aWR0aCA9IEYpCgpgYGAKCkFib3ZlLCBpdCBjYW4gYmUgc2VlbiB0aGF0IHRoZXJlIGlzIG5vIHN1YnN0YW50aWFsIHNrZXcgaW4gZWl0aGVyIG9mIHRoZSBgc3Ryb2tlYCBjYXRlZ29yaWVzIGZvciBgYm1pYCwgb25seSBzb21lIG1pbGQgcmlnaHQgc2tldy4gRm9yIHRoaXMgcmVhc29uIHRoZSBkYXRhIHdpbGwgYmUgY29uc2lkZXJlZCB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZC4KCiMjIyBBc3Nlc3NtZW50IG9mIHBvcHVsYXRpb24gdmFyaWFuY2Ugey51bm51bWJlcmVkfQoKVGhlIHBvcHVsYXRpb24gdmFyaWFuY2UgaXMgYWxzbyBhbiBpbXBvcnRhbnQgbWVhc3VyZSB0byBjb25zaWRlciB3aGVuIGRlY2lkaW5nIHdoaWNoIG1ldGhvZCB0byB1dGlsaXplIHRvIGNvbXBhcmUgdGhlIG1lYW5zIG9mIHR3byBpbmRlcGVuZGVudCBzYW1wbGVzLiBUaGUgZm9sbG93aW5nIGNvZGUgaXMgcHJlc2VudCBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzcGxheWluZyB0aGUgcG9wdWxhdGlvbiB2YXJpYW5jZSBpbiBgYm1pYCBmb3IgZWFjaCBgc3Ryb2tlYCBjYXRlZ29yeS4KCmBgYHtyfQpTdHJva2VfZGF0YSB8PiBncm91cF9ieShzdHJva2UpIHw+CiAgc3VtbWFyaXplKG4gPSBuKCksIG1lYW4gPSBtZWFuKGJtaSksIHZhcmlhbmNlID0gdmFyKGJtaSkpIHw+IAogIGtibChjYXB0aW9uID0gIkFzc2Vzc21lbnQgb2YgUG9wdWxhdGlvbiBWYXJpYW5jZSIsIGRpZ2l0cyA9IDUpIHw+IAogIGthYmxlX3N0eWxpbmcoZm9udF9zaXplID0gMjApIHw+IAogIGthYmxlX3BhcGVyKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKQpgYGAKCkFsdGhvdWdoIHRoZSAiU3Ryb2tlIiBhbmQgIk5vdCBTdHJva2UiIGNhdGVnb3JpZXMgaGF2ZSBzaW1pbGFyIHZhcmlhbmNlcywgdGhleSBhcmUgc3RpbGwgbmVhcmx5IDUgYGJtaWAgcG9pbnRzIGF3YXksIGFuZCBmb3IgdGhpcyByZWFzb24gdGhleSBjYW5ub3QgYmUgY29uc2lkZXJlZCB0byBiZSBlcXVhbC4KCiMjIyBPdmVyYWxsIEFzc2Vzc21lbnQgb2YgUGxvdHMgYW5kIE51bWVyaWMgU3VtbWFyaWVzIHsudW5udW1iZXJlZH0KCioqVGhlIHBsb3RzIGFuZCBudW1lcmljIHN1bW1hcmllcyBkZXBpY3RlZCBhYm92ZSB3ZXJlIGFsbCBpbiBhZ3JlZW1lbnQgdGhhdCB0aGUgZGF0YSB3YXMgcmVhc29uYWJseSBub3JtYWxseSBkaXN0cmlidXRlZCB3aXRoIHNvbWUgbWlsZCwgYnV0IHVuc3Vic3RhbnRpYWwgcmlnaHQgc2tldyBpbiBib3RoIGBzdHJva2VgIGNhdGVnb3JpZXMuIEFkZGl0aW9uYWxseSwgaXQgd2FzIG9ic2VydmVkIHRoYXQgdGhlcmUgd2FzIG5vdCBzaW1pbGFyIHZhcmlhbmNlIGluIEJNSSB2YWx1ZXMgYmV0d2VlbiB0aGUgdHdvIHN0cm9rZSBzdGF0dXMgY2F0ZWdvcmllcy4qKgoKIyMjIFNhbXBsZSBpbmZvcm1hdGlvbiB7LnVubnVtYmVyZWR9CgpJdCBjYW4gYmUgZGVkdWNlZCBmcm9tIHRoZSBhYm92ZSBudW1lcmljYWwgc3VtbWFyaWVzIGFuZCBwbG90cyB0aGF0IHRoZSBgYm1pYCBkYXRhIGZvciB0aGUgYFN0cm9rZV9kYXRhYCBzZXQgKmlzKiBub3JtYWxseSBkaXN0cmlidXRlZCBhbW9uZyBib3RoIGBzdHJva2VgIGNhdGVnb3JpZXMuIE9ubHkgYSBzbWFsbCBhbW91bnQgYW1vdW50IG9mIHJpZ2h0IHNrZXcgd2FzIG9ic2VydmVkIGluIHRoZSBkaXN0cmlidXRpb24sIHdoaWNoIHdhcyBkZXRlcm1pbmVkIGJ5IGEgbm9ucGFyYW1ldHJpYyBza2V3IGFuYWx5c2lzIHRvIGJlIHVuaW1wb3J0YW50LiBUaGUgcHJlc2VuY2Ugb2YgYSBub3JtYWwgZGlzdHJpYnV0aW9uIGFsbG93cyB0aGUgbWVhbnMgb2YgdGhlc2UgaW5kZXBlbmRlbnQgc2FtcGxlcyB0byBiZWluZyBjb21wYXJlZCBhY2N1cmF0ZWx5IHVzaW5nIGFuIGFwcHJvYWNoIGJhc2VkIG9uIGEgdC1kaXN0cmlidXRpb24uIFdpdGggdGhlIHByZXNlbmNlIG9mIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgYSBib290c3RyYXAgcmUtc2FtcGxpbmcgYXBwcm9hY2ggaXMgbm90IG5lY2Vzc2FyeSB0byBjb21wYXJlIHRoZSBgYm1pYCBtZWFucyBpbiB0aGUgdHdvIGBzdHJva2VgIGNhdGVnb3JpZXMuIEFkZGl0aW9uYWxseSwgYmVjYXVzZSB0aGUgb2JqZWN0aXZlIG9mIHRoZSByZXNlYXJjaCBxdWVzdGlvbiB3YXMgdG8gY29tcGFyZSB0aGUgc2FtcGxlcyBiYXNlZCBvbiB0aGVpciBtZWFuIHZhbHVlcywgdGhleSBhcmUgbm90IGJlc3QgY29tcGFyZWQgdXNpbmcgYSByYW5rLWJhc2VkIGFwcHJvYWNoIGxpa2UgdGhhdCBzZWVuIGluIGEgV2lsY294b24tTWFubi1XaGl0bmV5IHJhbmstc3VtIHRlc3QuIFRoaXMgaXMgYmVjYXVzZSB0aGlzIGNhdGVnb3J5IG9mIHRlc3RzIGRvZXMgbm90IGdlbmVyYXRlIGEgQ0kgYmFzZWQgb24gdGhlIG1lYW5zIG9mIHRoZSBzYW1wbGVzLCBidXQgZm9yIGNhbGN1bGF0ZWQgcHNldWRvLW1lZGlhbnMsIHdoaWNoIGFyZSBub3QgYW5hbG9nb3VzIHRvIHRoZSBtZWFucyBvZiB0aGUgc2FtcGxlcyBpZiB0aGUgc2FtcGxlcyBhcmUgbm90IHN5bW1ldHJpY2FsbHkgZGlzdHJpYnV0ZWQuCgpHaXZlbiB0aGF0IGVxdWFsIHBvcHVsYXRpb24gdmFyaWFuY2Ugd2FzIG5vdCBhYmxlIHRvIGJlIGVzdGFibGlzaGVkIGZvciB0aGUgdHdvIGluZGVwZW5kZW50IHNhbXBsZXMsIGEgcG9vbGVkIHQtdGVzdCBtYXkgbm90IGJlIHVzZWQgaGVyZS4gSW5zdGVhZCwgYSB0LXRlc3Qgd2lsbCBiZSBjb21wbGV0ZWQgd2l0aCBXZWxjaCdzIGFwcHJvYWNoLCB3aGljaCBkb2VzIG5vdCBhc3N1bWUgZXF1YWwgdmFyaWFuY2UuIFdlbGNoJ3MgYXBwcm9hY2ggaGFzIHR3byBhZGRpdGlvbmFsIGNvbmRpdGlvbnMsIHRoYXQgdGhlIHNhbXBsZXMgaW4gZWFjaCBncm91cCBhcmUgZHJhd24gaW5kZXBlbmRlbnRseSBvZiBlYWNoIG90aGVyIGFuZCB0aGF0IHRoZSBzYW1wbGVzIGluIGVhY2ggZ3JvdXAgcmVwcmVzZW50IGEgcmFuZG9tIHNhbXBsZSBvZiB0aGUgcG9wdWxhdGlvbiBvZiBpbnRlcmVzdC4gT3VyIHR3byBncm91cHMgdGhhdCB3ZSBhcmUgY29tcGFyaW5nIG1lYW5zIGZvciBhcmUgaW5kZXBlbmRlbnQgc2FtcGxlcywgd2l0aCBubyBtYXRjaGluZyBvciBwYWlyaW5nIHByZXNlbnQgYW5kIGJvdGggYXJlIGRyYXduIGZyb20gd2lkZSByYW5naW5nIGRlLWlkZW50aWZpZWQgRUhSIGRhdGEsIHdoaWNoIGlzIHdpZGVseSB1c2VkIGFyb3VuZCB0aGUgVW5pdGVkIFN0YXRlcyBpbiBob3NwaXRhbHMgdGhhdCBldmFsdWF0ZSBwYXRpZW50cyBmb3Igc3Ryb2tlcy4gVGh1cywgdGhlc2Ugc2FtcGxlcyBjYW4gYmUgY29uc2lkZXJlZCB0byBiZSByYW5kb20gc2FtcGxlcy4KCiMjIE1haW4gQW5hbHlzaXMKClRoZSBmb2xsb3dpbmcgY29kZSBpcyBwcmVzZW50IGZvciB0aGUgcHVycG9zZSBvZiBjb21wYXJpbmcgdGhlIG1lYW5zIG9mIHRoZSB0d28gYHN0cm9rZWAgY2F0ZWdvcmllcyB1c2luZyBhICoqdC10ZXN0KiogLiBBIFdlbGNoJ3MgdC10ZXN0IGFwcHJvYWNoIHdpbGwgYmUgdXNlZCBiZWNhdXNlIGVxdWFsIHZhcmlhbmNlIGNvdWxkIG5vdCBiZSBlc3RhYmxpc2hlZC4gSXQgaXMgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCBXZWxjaCdzIHQtdGVzdCBjYXJyaWVzIHR3byBhZGRpdGlvbmFsIGFzc3VtcHRpb25zIHRvIHRoZSBub3JtYWxpdHkgYXNzdW1wdGlvbjogdGhhdCB0aGUgc2FtcGxlcyBpbiBlYWNoIGdyb3VwIGFyZSBkcmF3biBpbmRlcGVuZGVudGx5IG9mIGVhY2ggb3RoZXIgYW5kIHRoYXQgdGhlIHNhbXBsZXMgaW4gZWFjaCBncm91cCByZXByZXNlbnQgYSByYW5kb20gc2FtcGxlIG9mIHRoZSBwb3B1bGF0aW9uIG9mIGludGVyZXN0LiBCb3RoIG9mIHRob3NlIGNhbiBiZSBjb25zaWRlcmVkIHRvIGJlIHRydWUgaW4gdGhpcyBjYXNlIGZvciByZWFzb25zIG1lbnRpb25lZCBhYm92ZS4gQSBzdW1tYXJ5IG9mIHRoZSA5MCUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIGRpZmZlcmVuY2UgKE5vIHN0cm9rZSAtIFN0cm9rZSkgb2YgdGhlIHBvcHVsYXRpb24gbWVhbnMgaXMgaW5jbHVkZWQgYXMgd2VsbC4KCmBgYHtyfQoKd3R0IDwtIHQudGVzdChibWkgfiBzdHJva2UsIGRhdGEgPSBTdHJva2VfZGF0YSwgY29uZi5sZXZlbCA9IDAuOTApIAoKd3R0Cgp3dHQgfD4KICB0aWR5KCkgfD4KICBzZWxlY3QoZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpIHw+IAogIGtibChjYXB0aW9uID0gIldlbGNoJ3MgVC10ZXN0IiwgZGlnaXRzID0gNSkgfD4KICBrYWJsZV9zdHlsaW5nKGZvbnRfc2l6ZSA9IDIwKSB8PiAKICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikKCmBgYAoKIyMgQ29uY2x1c2lvbnMKCkZyb20gdGhlIGFib3ZlIGFuYWx5c2lzLCB3aGljaCB1c2VzIGEgV2VsY2gncyBULXRlc3QgYXBwcm9hY2ggdG8gY29tcGFyZSB0aGUgbWVhbiBgYm1pYCB2YWx1ZXMgZm9yIHRoZSB0d28gY2F0ZWdvcmllcyBvZiB0aGUgYHN0cm9rZWAgdmFyaWFibGUgaW4gdGhlIGBTdHJva2VfZGF0YWAgZGF0YSBzZXQsIHR3byBwb2ludCBlc3RpbWF0ZXMgd2VyZSBhYmxlIHRvIGJlIG9idGFpbmVkLiBUaGUgcG9pbnQgZXN0aW1hdGUgZm9yIHRoZSBtZWFuIEJNSSBpbiB0aGUgIk5vIFN0cm9rZSIgZ3JvdXAgd2FzIDI5Ljk2Nzg0IGFuZCB0aGUgcG9pbnQgZXN0aW1hdGUgZm9yIHRoZSBtZWFuIEJNSSBpbiB0aGUgIlN0cm9rZSIgZ3JvdXAgd2FzIDMwLjUwNjcwLiBUaGUgOTAlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIHRoZSBkaWZmZXJlbmNlIChObyBzdHJva2UgLSBTdHJva2UpIG9mIHRoZSBwb3B1bGF0aW9uIG1lYW5zIHdhcyBmb3VuZCB0byBiZSBmcm9tIC0xLjMwNjQ3ODIgdG8gMC4yMjg3NDMzLiBCZWNhdXNlIHRoZSB0LXRlc3RzJyByZXN1bHRpbmcgOTAlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaW5jbHVkZXMgemVybyBpbiBpdHMgcmFuZ2UsIGl0IGNhbiBiZSBjb25jbHVkZWQgdGhhdCB0aGUgdHJ1ZSBwb3RlbnRpYWwgZGlmZmVyZW5jZSBpbiBtZWFuIEJNSSB2YWx1ZXMgYmV0d2VlbiB0aGUgIk5vIFN0cm9rZSIgYW5kICJTdHJva2UiIGdyb3VwcyBjb3VsZCBiZSBwb3NpdGl2ZSwgbmVnYXRpdmUsIG9yIHplcm8uIFRodXMgd2UgY2FuIGNvbmNsdWRlIHRoYXQsIHdpdGggYW4gYWxwaGEgbGV2ZWwgb2YgMC4xMCBhbmQgdGhlIHNhbXBsZSBzaXplIHVzZWQsIHRoZXJlIGlzIG5vdCBhIG1lYW5pbmdmdWwgZGlmZmVyZW5jZSBpbiBtZWFuIEJNSSBiZXR3ZWVuIHBhdGllbnRzIHRoYXQgaGF2ZSBiZWVuIG5vdGVkIGFzIGhhdmluZyBzdWZmZXJlZCBhIHN0cm9rZSBpbiB0aGVpciBlbGVjdHJvbmljIG1lZGljYWwgaGlzdG9yeSBhbmQgdGhvc2Ugd2hvIGhhdmUgbm90IGJlZW4gbm90ZWQgYXMgaGF2aW5nIHN1ZmZlcmVkIGEgc3Ryb2tlIGluIHRoZWlyIGVsZWN0cm9uaWMgbWVkaWNhbCBoaXN0b3J5IHVzaW5nIHRoZSBgU3Ryb2tlX2RhdGFgIHNldC4KCkFsdGhvdWdoIHRoaXMgcGFydGljdWxhciBzdHVkeSB3YXMgbm90IGFibGUgdG8gZXN0YWJsaXNoIGEgZGlmZmVyZW5jZSBpbiBtZWFuIGBibWlgIHZhbHVlcyBhbW9uZyB0aGUgdHdvIGBzdHJva2VgIGNhdGVnb3JpZXMsIHRoZXJlIGFyZSBhIG51bWJlciBvZiBwb3RlbnRpYWwgbGltaXRhdGlvbnMgdG8gdGhpcyBwYXJ0aWN1bGFyIHN0dWR5LiBPbmUgb2YgdGhlc2UgbGltaXRhdGlvbnMgaXMgdGhhdCB0aGUgdHlwZSBvZiBzdHJva2UgdGhhdCBhIHBhdGllbnQgc3VmZmVyZWQgd2FzIG5vdCBtZW50aW9uZWQuIEJlY2F1c2Ugc3Ryb2tlcyBjYW4gYmUgY2F1c2VkIGJ5IGlzY2hlbWlhIG9yIGhlbW9ycmhhZ2UgaW4gYSBtdWx0aXR1ZGUgb2YgZGlmZmVyZW50IGFyZWFzIG9mIHRoZSBicmFpbiBhbmQgY2FuIGhhdmUgYSB3aWRlIHJhbmdlIG9mIGV0aW9sb2dpZXMsIHRyZWF0aW5nIGFsbCBzdHJva2VzIGFzIHRoZSBzYW1lIHdoZW4gY29uc2lkZXJpbmcgdGhlIEJNSSBvZiBhIHBhdGllbnQgbWF5IG5vdCBhY2N1cmF0ZWx5IGRlc2NyaWJlIHRoZSB0cnVlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHN0cm9rZSBhbmQgQk1JLiBBbHNvLCB0aGUgbnVtYmVyIG9mIHN0cm9rZXMgdGhhdCBhIHBhdGllbnQgc3VmZmVyZWQgYW5kIHRoZSBsZW5ndGggb2YgdGltZSBzaW5jZSB0aGF0IHBhdGllbnQncyBsYXN0IHN0cm9rZSB3ZXJlIG5vdCBtZW50aW9uZWQsIGVhY2ggb2Ygd2hpY2ggbWF5IGhhdmUgZGlmZmVyZW50IGVmZmVjdHMgb24gQk1JLgoKRnV0dXJlIHN0dWRpZXMgbG9va2luZyB0byBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGluIG1lYW4gYGJtaWAgdmFsdWVzIGJhc2VkIG9uIHN0cm9rZSBzdGF0dXMgbWF5IG9wdCB0byBkaWcgZGVlcGVyIGludG8gdGhlIGVsZWN0cm9uaWMgaGVhbHRoIHJlY29yZHMgYW5kIGNyZWF0ZSBhIGRhdGEgc2V0IHRoYXQgaW5jbHVkZXMgaW5mb3JtYXRpb24gb24gdGhlIHR5cGUgb2Ygc3Ryb2tlIGEgcGF0aWVudCBzdWZmZXJlZCwgdGhlIG51bWJlciBvZiBzdHJva2VzIHRoZXkgaGFkLCBhbmQgaG93IHJlY2VudGx5IHRoZWlyIG1vc3QgcmVjZW50IHN0cm9rZSB3YXMuIEluZm9ybWF0aW9uIG9uIGhvdyBtZWRpY2FsIHN0YWZmIGludGVydmVuZWQgd2l0aCB0aGUgcGF0aWVudCdzIHN0cm9rZSBtYXkgYWxzbyBiZSB1c2VmdWwgaW4gZGV0ZXJtaW5pbmcgd2hldGhlciBvciBub3QgQk1JIHZhbHVlcyBkaWZmZXIgYmFzZWQgb24gc3Ryb2tlIHN0YXR1cy4KCiMgQW5hbHlzaXMgQzogQ29tcGFyaW5nIFRocmVlIE1lYW5zIHdpdGggSW5kZXBlbmRlbnQgU2FtcGxlcwoKIyMgUmVzZWFyY2ggUXVlc3Rpb24KCkluIHRoaXMgYW5hbHlzaXMsIHRoZSBtZWFuIGBibWlgIHZhbHVlcyBpbiB0aGUgYFN0cm9rZV9kYXRhYCB0aWJibGUgd2lsbCBiZSBjb21wYXJlZCBieSB0aGUgYHNtb2tpbmdfc3RhdHVzYCBvZiB0aGUgcGF0aWVudHMgaW5jbHVkZWQgaW4gdGhlIHN0dWR5LCB3aXRoIHRoZSBvYmplY3RpdmUgb2YgaWRlbnRpZnlpbmcgaWYgdGhlcmUgaXMgYW55IG1lYW5pbmdmdWwgZGlmZmVyZW5jZSBpbiBgYm1pYCBmb3IgcGF0aWVudHMgd2hvIHdlcmUgcmVjb3JkZWQgaW4gdGhlaXIgRUhSIGFzIGJlaW5nIGVpdGhlciBhIHNtb2tlciwgZm9ybWVyIHNtb2tlciwgb3IgcGVyc29uIHdobyBoYXMgbmV2ZXIgc21va2VkLiBUaGUgdGhyZWUgYHNtb2tpbmdfc3RhdHVzYCBjYXRlZ29yaWVzIGFyZSBhbGwgaW5kZXBlbmRlbnQgb2Ygb25lIGFub3RoZXIgYW5kIG5vbmUgb2YgdGhlIHJlc3VsdHMgYXJlIHBhaXJlZCBvciBtYXRjaGVkLiBUaGlzIGluZm9ybWF0aW9uIG1heSBiZSBhIHVzZWZ1bCBoeXBvdGhlc2lzIGdlbmVyYXRvciBmb3IgcmVzZWFyY2hlcnMgbG9va2luZyB0byBmdXJ0aGVyIGludmVzdGlnYXRlIHRoZSBwaHlzaW9sb2dpY2FsIGNoYW5nZXMgYW1vbmcgc21va2Vycywgbm9uLXNtb2tlcnMgYW5kIGZvcm1lciBzbW9rZXJzLiBUaGUgcmVzZWFyY2ggcXVlc3Rpb24gaXMgYXMgZm9sbG93czoKCioqSXMgdGhlcmUgYSBtZWFuaW5nZnVsIGRpZmZlcmVuY2UgaW4gbWVhbiBCTUkgdmFsdWVzIGJldHdlZW4gcGF0aWVudHMgd2hvIHNtb2tlIGN1cnJlbnRseSwgdGhvc2Ugd2hvIGhhdmUgc21va2VkIGluIHRoZSBwYXN0LCBhbmQgdGhvc2Ugd2hvIGRvIG5vdCBzbW9rZSwgYW1vbmcgcGF0aWVudHMgd2hvIGhhdmUgYSBzdHJva2UgZXZhbHVhdGlvbiBpbiB0aGVpciBlbGVjdHJvbmljIGhlYWx0aCByZWNvcmQ/KioKCiMjIERlc2NyaWJpbmcgdGhlIERhdGEKCkluIHRoaXMgYW5hbHlzaXMsIHR3byB2YXJpYWJsZXMgd2lsbCBiZSBleGFtaW5lZC4gT25lIGlzIHNtb2tpbmcgc3RhdHVzLCB3aGljaCBpcyBhIHRocmVlIGxldmVsIGNhdGVnb3JpY2FsIHZhcmlhYmxlIG5hbWVkIGBzbW9raW5nX3N0YXR1c2Agd2l0aCB0aGUgbGV2ZWxzICJuZXZlciBzbW9rZWQiLCAiZm9ybWVyIHNtb2tlciIsIGFuZCAic21va2VzIiwgcmVwcmVzZW50aW5nIHRoZSBzbW9raW5nIHN0YXR1cyBvZiB0aGUgcGF0aWVudCBhcyBpbmRpY2F0ZWQgYnkgdGhhdCBwYXRpZW50J3MgRUhSLiAibmV2ZXIgc21va2VkIiBpbmRpY2F0ZXMgdGhhdCB0aGUgcGF0aWVudCBoYXMgbm8gaGlzdG9yeSBvZiBzbW9raW5nLCAiZm9ybWVybHkgc21va2VkIiBpbmRpY2F0ZXMgdGhhdCB0aGV5IGhhdmUsIGJ1dCBubyBsb25nZXIgc21va2UsIGFuZCAic21va2VzIiBpbmRpY2F0ZXMgdGhhdCB0aGUgcGF0aWVudCBjdXJyZW50bHkgc21va2VzLgoKVGhlIHNlY29uZCB2YXJpYWJsZSBpcyBCTUksIHdoaWNoIGlzIGEgcXVhbnRpdGF0aXZlIHZhcmlhYmxlIGRlc2NyaWJpbmcgdGhlIGN1cnJlbnQgYm9keSBtYXNzIGluZGV4IG9mIHRoZSBwYXRpZW50IGFzIGluZGljYXRlZCBieSB0aGF0IHBhdGllbnQncyBFSFIuCgojIyMgTnVtZXJpYyBzdW1tYXJ5IHsudW5udW1iZXJlZH0KClRoZSBmb2xsb3dpbmcgY29kZSBpcyBwcmVzZW50IGZvciB0aGUgcHVycG9zZSBvZiBkaXNwbGF5aW5nIGEgYnJpZWYgbnVtZXJpY2FsIHN1bW1hcnkgb2YgdGhlIGBibWlgIGRhdGEgYmV0d2VlbiBwYXRpZW50cyBpbiBlYWNoIG9mIHRoZSB0aHJlZSBgc21va2luZ19zdGF0dXNgIGNhdGVnb3JpZXMuCgpgYGB7cn0KCm1vc2FpYzo6ZmF2c3RhdHMoYm1pIH4gc21va2luZ19zdGF0dXMsIGRhdGEgPSBTdHJva2VfZGF0YSkgfD4KICBrYWJsZShjYXB0aW9uID0gIkJNSSBOdW1lcmljYWwgU3VtbWFyeSBieSBTbW9raW5nIENhdGVnb3J5IiwgCiAgICAgICAgZGlnaXRzID0gMikgfD4ga2FibGVfc3R5bGluZyhmb250X3NpemUgPSAyMCkgfD4gIAogIGthYmxlX3BhcGVyKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKQoKYGBgCgpJdCBjYW4gYmUgc2VlbiBpbiB0aGUgdGFibGUgYWJvdmUgdGhhdCB0aGUgdGhyZWUgYHNtb2tpbmdfc3RhdHVzYCBjYXRlZ29yaWVzIGhhdmUgdmVyeSBzaW1pbGFyIHZhbHVlcyBmb3IgbWF4LCBtZWFuLCBtZWRpYW4sIGFuZCBpbnRlcnF1YXJ0aWxlIHJhbmdlLiBJdCBjYW4gYWxzbyBiZSBzZWVuIHRoYXQgdGhlICJmb3JtZXJseSBzbW9rZWQiIGFuZCAic21va2VzIiBjYXRlZ29yaWVzIGVhY2ggaGF2ZSBsZXNzIHRoYW4gaGFsZiBvZiB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhcyB0aGUgIm5ldmVyIHNtb2tlZCIgY2F0ZWdvcnkuCgojIyMgR3JhcGhpY2FsIGFzc2Vzc21lbnQgey51bm51bWJlcmVkfQoKSW4gb3JkZXIgdG8gdmlzdWFsaXplIHRoZSBvdmVyYWxsIGRpc3RyaWJ1dGlvbiBvZiBkYXRhIGluIHRlcm1zIG9mIEJNSSwgYSBoaXN0b2dyYW0gd2FzIGNvbnN0cnVjdGVkIGNvbXByaXNpbmcgdGhlIGVudGlyZSByYW5nZSBmb3IgYGJtaWAgb2YgdGhlIGBTdHJva2VfZGF0YWAgZGF0YSBzZXQsIHdpdGggcG9ydGlvbnMgb2YgdGhlIGhpc3RvZ3JhbSBoaWdobGlnaHRlZCB0byBzaG93IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHRocmVlIGBzbW9raW5nX3N0YXR1c2AgY2F0ZWdvcmllcy4gVG8gYmV0dGVyIGluZGl2aWR1YWxseSBoaWdobGlnaHQgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIHRocmVlIGNhdGVnb3JpZXMsIGFuIGFkZGl0aW9uYWwgdGhyZWUgaGlzdG9ncmFtcyB3ZXJlIG1hZGUuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KCnAzIDwtIGdncGxvdChTdHJva2VfZGF0YSwgYWVzKHggPSBibWksIGZpbGwgPSBzbW9raW5nX3N0YXR1cywgY29sb3IgPSAyKSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDc1KSAgKyAKICBndWlkZXMoY29sb3IgPSAibm9uZSIpICsKICAgIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIG9mIEJNSSByZXN1bHRzIEZvciBBbGwgU21va2luZyBTdGF0dXNlcyIsCiAgICAgICAgIHggPSAiQk1JIikgKyAKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImxlbW9uY2hpZmZvbjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjUsIGxpbmV0eXBlID0gInNvbGlkIikpICsgCiAgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiYXp1cmUyIikpCgpwNCA8LSBnZ3Bsb3QoU3Ryb2tlX2RhdGEsIGFlcyh4ID0gYm1pKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyhmaWxsID0gc21va2luZ19zdGF0dXMpLCBiaW5zID0gMzAsIGNvbCA9ICJ3aGl0ZSIpICsKICB0aGVtZV9idygpICsKICBmYWNldF93cmFwKH4gc21va2luZ19zdGF0dXMpICsgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIkluZGl2aWR1YWwgaGlzdG9ncmFtcyBvZiBCTUkgYnkgc21va2luZyBzdGF0dXMiLAogICAgICAgeSA9ICJjb3VudCIsCiAgICAgICB4ID0gIlNtb2tpbmcgU3RhdHVzIikgKyAKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImxlbW9uY2hpZmZvbjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjUsIGxpbmV0eXBlID0gInNvbGlkIikpICsgCiAgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiYXp1cmUyIikpCgpwMy9wNAoKYGBgCgpJdCBjYW4gYmUgc2VlbiBhYm92ZSB0aGF0IGVhY2ggb2YgdGhlIHRocmVlIGBzbW9raW5nX3N0YXR1c2AgY2F0ZWdvcmllcyBhcHBlYXIgdG8gaGF2ZSBhIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBzb21lIHNsaWdodCByaWdodCBza2V3LiBBbGwgdGhyZWUgY2F0ZWdvcmllcyBhcHBlYXIgdG8gaGF2ZSB0aGUgZ3JlYXRlc3QgbnVtYmVyIG9mIHBlb3BsZSBhdCBhIEJNSSB2YWx1ZSBhcm91bmQgMzAsIHdoaWNoIGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgbnVtZXJpYyBzdW1tYXJ5LgoKSW4gb3JkZXIgdG8gYmV0dGVyIHZpc3VhbGl6ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIGBibWlgIGZvciBlYWNoIGBzbW9raW5nX3N0YXR1c2AgY2F0ZWdvcnkgYW5kIHNwZWNpZmljYWxseSB0byB2aXN1YWxpemUgdGhlIGhpZ2hlc3QgZGVuc2l0eSBhcmVhcyBvZiBwb3B1bGF0aW9uIGZvciBlYWNoLCBhIHJhaW4gY2xvdWQgcGxvdCBtYXkgYmUgdXNlZnVsLiBUaGUgZm9sbG93aW5nIGNvZGUgaXMgcHJlc2VudCBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzcGxheWluZyBhIHJhaW4gY2xvdWQgcGxvdC4KCmBgYHtyfQpnZ3Bsb3QoU3Ryb2tlX2RhdGEsIGFlcyhzbW9raW5nX3N0YXR1cywgYm1pKSkgKyAKICBnZ2Rpc3Q6OnN0YXRfaGFsZmV5ZShhZGp1c3QgPSAuNSwgd2lkdGggPSAuMywKICAgICAgICAgICAgICAgICAgICAgICAud2lkdGggPSAwLCBqdXN0aWZpY2F0aW9uID0gLS4zLAogICAgICAgICAgICAgICAgICAgICAgIHBvaW50X2NvbG91ciA9IE5BLCBmaWxsID0gImRhcmt0dXJxdW9pc2UiKSArIAogIGdlb21fYm94cGxvdCh3aWR0aCA9IC4xLCBvdXRsaWVyLnNoYXBlID0gTkEsIGZpbGwgPSAidG9tYXRvMSIgLCAKICAgICAgICAgICAgICAgb3V0bGllci5jb2xvciA9ICJibGFjayIsIG5vdGNoID0gVFJVRSkgKyAKICBzdGF0X3N1bW1hcnkoZnVuID0gIm1lYW4iLCBnZW9tID0gInBvaW50IiwgCiAgICAgICAgICAgICAgIHNoYXBlID0gMjMsIHNpemUgPSAzLCBmaWxsID0gIndoaXRlIikgKwogIAogIHRoZW1lKAogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuNSwgbGluZXR5cGUgPSAic29saWQiKSkgKwogbGFicygKICAgIHRpdGxlID0gIkJNSSBieSBTbW9raW5nIFN0YXR1cyIsIAogICAgc3VidGl0bGUgPSAKICAgICAgIkZvciBQYXRpZW50cyBXaG8gSGF2ZSBTdHJva2UgRXZhbHVhdGlvbiBJbmZvcm1hdGlvbiBpbiBUaGVpciBFSFIiLAogICAgeSA9ICJCb2R5IE1hc3MgSW5kZXggKEJNSSkiLCAKICAgIHg9IlNtb2tpbmcgU3RhdHVzIikgKyAKICB0aGVtZShwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhenVyZTIiKSkKYGBgCgpJdCBjYW4gYmUgc2VlbiBpbiB0aGUgYWJvdmUgcmFpbiBjbG91ZCBwbG90IHRoYXQgdGhlIG1lYW4gYW5kIG1lZGlhbiB2YWx1ZXMgb2YgYGJtaWAgYXJlIHZlcnkgY2xvc2UgZm9yIGFsbCB0aHJlZSBvZiB0aGUgYHNtb2tpbmdfc3RhdHVzYCBjYXRlZ29yaWVzLiBJdCBjYW4gYWxzbyBiZSBzZWVuIHRoYXQgdGhlIGdyZWF0ZXN0IG51bWJlciBvZiBwZW9wbGUgaW4gZWFjaCBncm91cCBoYXZlIGBibWlgIHZhbHVlcyBzbGlnaHRseSBiZWxvdyAzMCwgd2hpY2ggdGhlIENEQyB3b3VsZCBjb25zaWRlciB0byBiZSBpbiBhIGhlYWx0aHkgcmFuZ2UgKG1lYW5pbmcgbmVpdGhlciBvdmVyd2VpZ2h0IG9yIHVuZGVyd2VpZ2h0KS4gVGhlIGRhdGEgYWxzbyBhcHBlYXIgdG8gaGF2ZSByZWxhdGl2ZWx5IHNpbWlsYXIgdmFyaWFuY2UgaW4gZWFjaCBgc21va2luZ19zdGF0dXNgIGNhdGVnb3J5LgoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBkYXRhIGNhbiBiZSBmdXJ0aGVyIGludmVzdGlnYXRlZCB1c2luZyBhIGJveCBhbmQgdmlvbGluIHBsb3QganV4dGFwb3NlZCB3aXRoIG5vcm1hbCBRUSBwbG90cyBmb3IgYGJtaWAgaW4gZWFjaCBgc21va2luZ19zdGF0dXNgIGNhdGVnb3J5LiBUaGUgZm9sbG93aW5nIGNvZGUgYWxsb3dzIGZvciB0aGF0LgoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CgpwMSA8LSBnZ3Bsb3QoU3Ryb2tlX2RhdGEsIAogICAgICAgICAgICAgYWVzKHggPSBzbW9raW5nX3N0YXR1cywgeSA9IGJtaSwgZmlsbCA9IHNtb2tpbmdfc3RhdHVzKSkgKyAKICBnZW9tX3Zpb2xpbihhbHBoYSA9IDAuMykgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMywgbm90Y2ggPSBUUlVFKSArCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKwogIGxhYnModGl0bGUgPSAiQk1JIGJ5IFNtb2tpbmcgU3RhdHVzIiwKICAgICAgIHggPSAiU21va2luZyBTdGF0dXMiLCB5ID0gIkJvZHkgTWFzcyBJbmRleCIpICsgCiAgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiYXp1cmUyIikpCgpwMiA8LSBnZ3Bsb3QoU3Ryb2tlX2RhdGEsIGFlcyhzYW1wbGUgPSBibWksIGNvbCA9IHNtb2tpbmdfc3RhdHVzKSkgKwogIGdlb21fcXEoKSArIGdlb21fcXFfbGluZSgpICsKICBmYWNldF93cmFwKH4gc21va2luZ19zdGF0dXMpICsKICBndWlkZXMoY29sID0gIm5vbmUiKSArCiAgdGhlbWVfYncoKSArCiAgbGFicyh5ID0gIk9ic2VydmVkIEJNSSB2YWx1ZXMiLAogICAgICAgdGl0bGUgPSAiTm9ybWFsIFFRIFBsb3QiKSArIAogIHRoZW1lKHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImF6dXJlMiIpKQoKKHAxICsgdGhlbWUoCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImxlbW9uY2hpZmZvbjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC41LCBsaW5ldHlwZSA9ICJzb2xpZCIpKSApICsgKHAyICArCiAgICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiT3ZlcmFsbCB0aXRsZSIpICsgdGhlbWUoCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImxlbW9uY2hpZmZvbjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC41LCBsaW5ldHlwZSA9ICJzb2xpZCIpKSApIAoKYGBgCgpUaGUgdGhyZWUgdmlvbGluIHBsb3RzIGRlbW9uc3RyYXRlIGEgcmVsYXRpdmVseSBub3JtYWwgZGlzdHJpYnV0aW9uIGFuZCBmZXcgb3V0bGllcnMgZm9yIGVhY2ggb2YgdGhlIGBzbW9raW5nX3N0YXR1c2AgY2F0ZWdvcmllcy4gVGhlIG5vcm1hbCBRUSBwbG90cyBoZWxwIHRvIHZpc3VhbGl6ZSB0aGUgZGVncmVlIG9mIHNrZXcgc2VlbiBpbiB0aGUgZGF0YSwgd2hpY2gsIGFzIHN1Z2dlc3RlZCBieSB0aGUgaGlzdG9ncmFtIGlzIHRvIHRoZSByaWdodCwgc2xpZ2h0bHkgZm9yIGFsbCB0aHJlZSBgc21va2luZ19zdGF0dXNgIGNhdGVnb3JpZXMuCgojIyMgTnVtZXJpY2FsIEFzc2Vzc21lbnQgb2YgU2tldyB7LnVubnVtYmVyZWR9CgpBIG5vbnBhcmFtZXRyaWMgc2tld25lc3MgYXNzZXNzbWVudCB3YXMgZG9uZSB0byBoZWxwIGVzdGFibGlzaCB3aGV0aGVyIG9yIG5vdCB0aGUgZGF0YSB3YXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIEluIHRoaXMgYW5hbHlzaXMsIG5vbnBhcmFtZXRyaWMgc2tldyBpcyBjYWxjdWxhdGVkIGJ5IHRha2luZyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBtZWFuIGFuZCB0aGUgbWVkaWFuLCBhbmQgZGl2aWRpbmcgaXQgYnkgdGhlIHN0YW5kYXJkIGRldmlhdGlvbi4gVGhpcyBwYXJ0aWN1bGFyIHR5cGUgb2Ygc2tldyBpcyBiYXNlZCBvZmYgb2YgUGVhcnNvbidzIG5vdGlvbiBvZiBtZWRpYW4gc2tld25lc3MsIHdpdGggdmFsdWVzIGZhbGxpbmcgYmV0d2VlbiAtMSBhbmQgKzEgZm9yIGFueSBkaXN0cmlidXRpb24uIEdlbmVyYWxseSwgd2hlbiB0aGlzIG1lYXN1cmUgb2Ygc2tldyBpcyB1c2VkLCB2YWx1ZXMgZ3JlYXRlciB0aGFuICsgMC4yIGluZGljYXRlIGZhaXJseSBzdWJzdGFudGlhbCByaWdodCBza2V3LCB3aGlsZSB2YWx1ZXMgYmVsb3cgLTAuMiBpbmRpY2F0ZSBmYWlybHkgc3Vic3RhbnRpYWwgbGVmdCBza2V3LiBJZiB0aGUgc2tld25lc3MgdmFsdWUgZm9yIGBibWlgIGlzIGJldHdlZW4gLTAuMiBhbmQgKzAuMiwgdGhlIGRhdGEgd2lsbCBiZSBjb25zaWRlcmVkIHRvIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKYGBge3J9CgpTdHJva2VfZGF0YXw+IGdyb3VwX2J5KHNtb2tpbmdfc3RhdHVzKSB8PgogIHN1bW1hcml6ZShza2V3ID0gcm91bmRfaGFsZl91cCgobWVhbihibWkpIC0gbWVkaWFuKGJtaSkpL3NkKGJtaSksIDMpKSB8PiAKICBrYmwoY2FwdGlvbiA9ICJBc3Nlc3NtZW50IG9mIFNrZXciLCBkaWdpdHMgPSAyKSB8PiAKICBrYWJsZV9zdHlsaW5nKGZvbnRfc2l6ZSA9IDIwKSB8PiAKICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikKYGBgCgpJdCBjYW4gYmUgc2VlbiBpbiB0aGUgdGFibGUgYWJvdmUgdGhhdCB0aGUgInNtb2tlcyIgY2F0ZWdvcnkgb2YgdGhlIGBzbW9raW5nX3N0YXR1c2AgdmFyaWFibGUgZGVtb25zdHJhdGVkIHRoZSBncmVhdGVzdCBhbW91bnQgb2YgcmlnaHQgc2tldyBvZiBhbGwgb2YgdGhlIHRocmVlIGNhdGVnb3JpZXMuIEhvd2V2ZXIsIG5vbmUgd2VyZSBhYm92ZSAwLjIsIGluZGljYXRpbmcgdGhhdCB0aGVyZSB3YXMgbm8gc3Vic3RhbnRpYWwgc2tldywgb25seSBzb21lIG1pbGQgcmlnaHQgc2tldy4gRm9yIHRoaXMgcmVhc29uLCB0aGUgZGF0YSB3aWxsIGJlIGNvbnNpZGVyZWQgdG8gYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCgojIyBNYWluIEFuYWx5c2lzCgpUaGUgYXNzZXNzbWVudCBvZiBza2V3bmVzcywgaGlzdG9ncmFtcywgYm94IHBsb3RzLCBhbmQgUVEgZGlhZ3JhbXMgb2YgYGJtaWAgZGF0YSBmb3IgZWFjaCBvZiB0aGUgdGhyZWUgYHNtb2tpbmdfc3RhdHVzYCBjYXRlZ29yaWVzIHN1Z2dlc3RlZCB0aGF0IHRoZXkgYWxsIGhhdmUgYSBmYWlybHkgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gSW4gYWRkaXRpb24gdG8gbm9ybWFsaXR5LCB0aGUgc2FtcGxlcyBpbiBlYWNoIG9mIHRoZSBgc21va2luZ19zdGF0dXNgIGNhdGVnb3JpZXMgd2VyZSBpbmRlcGVuZGVudGx5IHNhbXBsZWQgYW5kLCBhcyBtZW50aW9uZWQgaW4gYW5hbHlzaXMgQiwgdGhlIGRhdGEgdXNlZCBpbiB0aGlzIHN0dWR5IGlzIHJlZmxlY3RpdmUgb2YgYSByYW5kb20gc2FtcGxlIG9mIHRoZSBwb3B1bGF0aW9uIG9mIGludGVyZXN0LiBNb3Jlb3ZlciwgZXF1YWwgdmFyaWFuY2UgaXMgc2VlbiBhY3Jvc3MgYWxsIHRocmVlIGBzbW9raW5nX3N0YXR1c2AgY2F0ZWdvcmllcy4gR2l2ZW4gdGhpcyBpbmZvcm1hdGlvbiwgYW4gQU5PVkEgKGFuYWx5c2lzIG9mIHZhcmlhbmNlKSB0ZXN0LCB3aGljaCBpcyBiYXNlZCBvbiBhIHBvb2xlZCB0LXRlc3QsIHdpbGwgYmUgdXNlZCB0byBjb21wYXJlIHRoZSBtZWFuIEJNSSBmb3IgZWFjaCBvZiB0aGUgYHNtb2tpbmdfc3RhdHVzYCBjYXRlZ29yaWVzLgoKYGBge3J9ClN0cm9rZV9kYXRhX20xIDwtIGxtKGJtaSB+IHNtb2tpbmdfc3RhdHVzLCBkYXRhID0gU3Ryb2tlX2RhdGEpCgphbm92YShTdHJva2VfZGF0YV9tMSkgfD4gCiAga2JsKGNhcHRpb249ICJBbmFseXNpcyBvZiBWYXJpYW5jZSB0byBDb21wYXJlIE1lYW4gQk1JIGJ5IFNtb2tpbmcgU3RhdHVzIiwgCiAgICAgIGRpZ2l0cyA9IDIpIHw+IAogIGthYmxlX3N0eWxpbmcoZm9udF9zaXplID0gMjApIHw+IAogIGthYmxlX3BhcGVyKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKQogIApgYGAKCkZyb20gdGhlIGFib3ZlIGFuYWx5c2lzIG9mIHZhcmlhbmNlIChBTk9WQSksIGl0IGFwcGVhcnMgdGhhdCB0aGUgbnVsbCBoeXBvdGhlc2lzLCB3aGljaCB3YXMgdGhhdCB0aGVyZSB3YXMgbm8gZGlmZmVyZW5jZSBpbiBtZWFuIEJNSSB2YWx1ZXMgYmV0d2VlbiBwYXRpZW50cyB3aG8gc21va2UgY3VycmVudGx5LCB0aG9zZSB3aG8gaGF2ZSBzbW9rZWQgaW4gdGhlIHBhc3QsIGFuZCB0aG9zZSB3aG8gZG8gbm90IHNtb2tlIGlzIG5vdCBjb25zaXN0ZW50IHdpdGggb3VyIGRhdGEgZm9yIGBibWlgIGFtb25nIGBzbW9raW5nX3N0YXR1c2AgY2F0ZWdvcmllcy4gVGhlIGV0YSBzcXVhcmVkIHZhbHVlIGlzIGNhbGN1bGF0ZWQgYXMgZm9sbG93czoKCig0MjMuNzcpLyg0MjMuNzcgKyAxMzMxNDcuODcpID0gKiowLjAwMzIqKgoKVGhlIHZhbHVlIGZvciBldGEgc3F1YXJlZCBzaG93cyB0aGF0IGBzbW9raW5nX3N0YXR1c2AgYWNjb3VudHMgZm9yIGFyb3VuZCAwLjMyJSBvZiB0aGUgdmFyaWF0aW9uIGluIGBibWlgLgoKIyMjIFR1a2V5IG11bHRpcGxlIGNvbXBhcmlzb25zIG9mIG1lYW5zIHsudW5udW1iZXJlZH0KCkFsdGhvdWdoIHRoZSBBTk9WQSB3YXMgYWJsZSB0byBlbHVjaWRhdGUgd2hldGhlciBvciBub3QgdGhlIHRocmVlIGBibWlgIG1lYW5zIGFjcm9zcyB0aGUgYHNtb2tpbmdfc3RhdHVzYCBjYXRlZ29yaWVzIGFyZSBkaWZmZXJlbnQsIGl0IGRvZXMgbm90IGV4cGxhaW4gd2hlcmUgdGhlIGRpZmZlcmVuY2VzIGxpZS4gVG8gZXhwbG9yZSB0aGUgcG90ZW50aWFsIGRpZmZlcmVuY2VzIGZ1cnRoZXIsIFR1a2V5J3MgSG9uZXN0bHkgU2lnbmlmaWNhbnQgRGlmZmVyZW5jZXMgYXBwcm9hY2ggdG8gcGFpcndpc2UgY29tcGFyaXNvbnMgb2YgbWVhbnMgd2FzIHVzZWQuIFRoZSBmb2xsb3dpbmcgY29kZSB1c2VzIHRoaXMgdGVjaG5pcXVlIHRvIGNyZWF0ZSA5MCUgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIHRoZSBkaWZmZXJlbmNlcyBpbiBtZWFuIEJNSSBmb3IgZWFjaCBvZiB0aGUgcG9zc2libGUgYHNtb2tpbmdfc3RhdHVzYCBwYWlycy4KCmBgYHtyfQpUdWtleUhTRChhb3YoU3Ryb2tlX2RhdGEkYm1pIH4gU3Ryb2tlX2RhdGEkc21va2luZ19zdGF0dXMpLCBjb25mLmxldmVsID0gMC45MCkgCiAgCmBgYAoKVGhlIDkwJSBjb25maWRlbmNlIGludGVydmFscyBkZXJpdmVkIGZyb20gdGhlIFR1a2V5J3MgSFNEIGFuYWx5c2lzIHNob3cgdGhhdCB0aGVyZSBpcyBsaWtlbHkgYSBjb25zaWRlcmFibGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSAiZm9ybWVybHkgc21va2VkIiBhbmQgIm5ldmVyIHNtb2tlZCIgZ3JvdXBzLCBidXQgbm90IGJldHdlZW4gYW55IG9mIHRoZSBvdGhlciBwb3NzaWJsZSBwYWlycy4KCiMjIyBQbG90IG9mIFR1a2V5IG11bHRpcGxlIGNvbXBhcmlzb25zIG9mIG1lYW5zIHsudW5udW1iZXJlZH0KClRoZSBmb2xsb3dpbmcgY29kZSBpcyBwcmVzZW50IGZvciB0aGUgcHVycG9zZSBvZiBwbG90dGluZyB0aGUgOTAlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFzc29jaWF0ZWQgd2l0aCB0aGUgYWJvdmUgVHVrZXkncyBIU0QgYW5hbHlzaXMuCgoqRm9yIHRoZSBiZWxvdyBwbG90LCB0aGUgZm9sbG93aW5nIHNob3J0aGFuZCB3YXMgdXNlZCoKCnwgKipBYmJyZXZpYXRpb24qKiB8IENhdGVnb3J5IG9mIGBzbW9raW5nX3N0YXR1c2AgfAp8LS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCAqKlMqKiAgICAgICAgICAgIHwgc21va2VzICAgICAgICAgICAgICAgICAgICAgICB8CnwgKipOUyoqICAgICAgICAgICB8IG5ldmVyIHNtb2tlZCAgICAgICAgICAgICAgICAgfAp8ICoqRlMqKiAgICAgICAgICAgfCBmb3JtZXJseSBzbW9rZWQgICAgICAgICAgICAgIHwKCmBgYHtyfQpwYXIoYmcgPSAiYXp1cmUyIikKClN0cm9rZV9kYXRhJHNtay5uZXcgPC0gCiAgICBmY3RfcmVjb2RlKFN0cm9rZV9kYXRhJHNtb2tpbmdfc3RhdHVzLCAKICAgICAgICAgICAgICAgIlMiID0gInNtb2tlcyIsICJOUyIgPSAibmV2ZXIgc21va2VkIiwKICAgICAgICAgICAgICAgIkZTIiA9ICJmb3JtZXJseSBzbW9rZWQiKQoKbWFyLmRlZmF1bHQgPC0gYyg1LDYsNCwyKSArIDAuMQpwYXIobWFyID0gbWFyLmRlZmF1bHQgKyBjKDAsIDQsIDAsIDApKQpwbG90KFR1a2V5SFNEKGFvdihTdHJva2VfZGF0YSRibWkgfiBTdHJva2VfZGF0YSRzbWsubmV3KSwgCiAgICAgICAgICAgICAgY29uZi5sZXZlbCA9IDAuOTAsIGxhcyA9IDEpKSAKYGBgCgpJdCBjYW4gYmUgc2VlbiBhYm92ZSB0aGF0IHRoZSA5MCUgY29uZmlkZW5jZSBpbnRlcnZhbHMgZGVyaXZlZCBmcm9tIHRoZSBUdWtleSdzIEhTRCBhbmFseXNpcyBvZiBtZWFuIGBibWlgIGJ5IHNtb2tpbmcgc3RhdHVzIGdyb3VwIHNob3cgdGhhdCB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgbWVhbmluZ2Z1bCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlICJmb3JtZXJseSBzbW9rZWQiIGFuZCAibmV2ZXIgc21va2VkIiBncm91cHMsIGJ1dCBub3QgYmV0d2VlbiBhbnkgb2YgdGhlIG90aGVyIHBvc3NpYmxlIHBhaXJzLiBHaXZlbiB0aGF0IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlICJmb3JtZXJseSBzbW9rZWQiIGFuZCAibmV2ZXIgc21va2VkIiBncm91cHMgaXMgcG9zaXRpdmUsIGl0IGNhbiBiZSBjb25jbHVkZWQgdGhhdCB0aGUgbWVhbiBgYm1pYCB2YWx1ZSBmb3IgdGhlICJmb3JtZXJseSBzbW9rZWQiIGdyb3VwIGlzIGdyZWF0ZXIgdGhhbiB0aGF0IG9mIHRoZSAibmV2ZXIgc21va2VkIGdyb3VwLiBUaGVyZSBpcyBubyBldmlkZW5jZSB0aGF0IHRoZXJlIGlzIGEgbWVhbmluZ2Z1bCBkaWZmZXJlbmNlIGJldHdlZW4gbWVhbiBgYm1pYCB2YWx1ZXMgZm9yIGFueSBvZiB0aGUgb3RoZXIgcGFpcnMsIGFuZCBpdCBjYW5ub3QgZXhwbGljaXRseSBjb25jbHVkZWQgd2l0aCB0aGUgY3VycmVudCBzYW1wbGUgc2l6ZSBhbmQgYW4gYWxwaGEgbGV2ZWwgb2YgMC4xMCB0aGF0IGFueSBvZiB0aGUgb3RoZXIgbWVhbnMgYXJlIG1lYW5pbmdmdWxseSBkaWZmZXJlbnQgZnJvbSBlYWNoIG90aGVyLgoKIyMgQ29uY2x1c2lvbnMKClRoZSByZXNlYXJjaCBxdWVzdGlvbiB0aGF0IGd1aWRlZCB0aGUgZGVzaWduIG9mIHRoaXMgYW5hbHlzaXMgd2FzICJJcyB0aGVyZSBhIG1lYW5pbmdmdWwgZGlmZmVyZW5jZSBpbiBtZWFuIEJNSSB2YWx1ZXMgYmV0d2VlbiBwYXRpZW50cyB3aG8gc21va2UgY3VycmVudGx5LCB0aG9zZSB3aG8gaGF2ZSBzbW9rZWQgaW4gdGhlIHBhc3QsIGFuZCB0aG9zZSB3aG8gZG8gbm90IHNtb2tlLCBhbW9uZyBwYXRpZW50cyB3aG8gaGF2ZSBhIHN0cm9rZSBldmFsdWF0aW9uIGluIHRoZWlyIGVsZWN0cm9uaWMgaGVhbHRoIHJlY29yZD8iLiBGcm9tIHRoZSBBTk9WQSB0ZXN0IGFuZCBhbmFseXNpcyBvZiBUdWtleSdzIEhTRCBmb3IgdGhlIG1lYW4gQk1JIHZhbHVlcyBvZiBlYWNoIG9mIHRoZSBjYXRlZ29yaWVzIG9mIGBzbW9raW5nX3N0YXR1c2AsIGl0IHdhcyBhYmxlIHRvIGJlIHNlZW4gdGhhdCB0aGVyZSB3YXMgb25seSBhIG1lYW5pbmdmdWwgZGlmZmVyZW5jZSBpbiBCTUkgdmFsdWVzIGJldHdlZW4gcGF0aWVudHMgd2hvIGhhdmUgZm9ybWVybHkgc21va2VkIGFuZCB0aG9zZSB3aG8gaGF2ZSBuZXZlciBzbW9rZWQuIFdoZW4gdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gb3RoZXIgcGFpcnMgb2YgYHNtb2tpbmdfc3RhdHVzYCBjYXRlZ29yaWVzIHdlcmUgY2FsY3VsYXRlZCwgOTAlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHdlcmUgbm90IGFibGUgdG8gZXN0YWJsaXNoIGFuIGV4cGxpY2l0bHkgcG9zaXRpdmUgb3IgbmVnYXRpdmUgdmFsdWUgYW5kIHdlcmUgdGh1cyBjb25zaWRlcmVkIHRvIG5vdCBiZSBtZWFuaW5nZnVsLCBhcyBpdCB3YXMgbm90IGFibGUgdG8gYmUgZGV0ZXJtaW5lZCB3aGljaCBjYXRlZ29yeSBoYWQgYSBsYXJnZXIgb3Igc21hbGxlciB0cnVlIG1lYW4gQk1JIHZhbHVlLgoKQWx0aG91Z2ggdGhpcyBwYXJ0aWN1bGFyIHN0dWR5IHdhcyBub3QgYWJsZSB0byBlc3RhYmxpc2ggYSBkaWZmZXJlbmNlIGluIG1lYW4gYGJtaWAgdmFsdWVzIGFtb25nIGFsbCBvZiB0aGUgYHNtb2tpbmdfc3RhdHVzYCBjYXRlZ29yaWVzLCB0aGVyZSBhcmUgYSBudW1iZXIgb2YgcG90ZW50aWFsIGxpbWl0YXRpb25zIHRvIHRoaXMgcGFydGljdWxhciBzdHVkeS4gT25lIG9mIHRoZXNlIGxpbWl0YXRpb25zIGlzIHRoYXQgdGhlIGRhdGEgdXNlZCB0byByZXBvcnQgdGhlIHNtb2tpbmcgc3RhdHVzIG9mIGEgcGF0aWVudCBkaWQgbm90IHNwZWNpZnkgdGhlIHR5cGUgb2Ygc21va2luZyB0aGF0IHRoZSBwYXRpZW50IHBhcnRha2VzIGluLiBJdCBtYXkgYmUgcG9zc2libGUgdGhhdCB3aGlsZSBhIHRvYmFjY28gc21va2VyIGRvZXMgbm90IGhhdmUgYW4gYXBwcmVjaWFibGUgZGlmZmVyZW5jZSBpbiBtZWFuIEJNSSB2YWx1ZXMgYmFzZWQgb24gdGhlaXIgc21va2luZyBzdGF0dXMsIHRoYXQgYSBtYXJpanVhbmEgc21va2VyIGRvZXMuIEZ1cnRoZXJtb3JlLCB0aGUgc3RhdHVzIG9mIGVhY2ggcGF0aWVudCBhcyBhIGhlYXZ5LCBtaWxkIGFuZCBsaWdodCBzbW9rZXIgd2FzIG5vdCBzcGVjaWZpZWQsIHdoaWNoIG1heSBhbHNvIGJlIGEgbW9kdWxhdG9yIG9mIHRoZSBwYXRpZW50J3MgQk1JIHZhbHVlIGJhc2VkIG9uIHRoZWlyIHNtb2tpbmcgc3RhdHVzLgoKRnV0dXJlIHN0dWRpZXMgbG9va2luZyB0byBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGluIG1lYW4gQk1JIHZhbHVlcyBhbW9uZyB0aGUgdGhyZWUgc21va2luZyBzdGF0dXMgY2F0ZWdvcmllcyBtYXkgc2VlayB0byBhZGp1c3QgZm9yIHRoZSB0eXBlIG9mIHNtb2tpbmcgYSBwZXJzb24gcGFydGFrZXMgaW4gYW5kL29yIHRoZWlyIHN0YXR1cyBhcyBhIGhlYXZ5LCBtaWxkLCBvciBsaWdodCBzbW9rZXIuIFRoaXMgd291bGQsIGhvd2V2ZXIsIHJlcXVpcmUgYWRkaXRpb25hbCBkYXRhIHRvIGJlIGNvbGxlY3RlZCB0aGF0IGlzIG5vdCBpbmNsdWRlZCBpbiB0aGUgZGF0YSBzZXQgdXNlZCBpbiB0aGlzIGFuYWx5c2lzLgoKIyBBbmFseXNpcyBEOiBBbmFseXppbmcgYSAyeDIgdGFibGUKCiMjIFJlc2VhcmNoIFF1ZXN0aW9uCgpGb3IgdGhpcyBhbmFseXNpcywgdGhlIGZvY3VzIHdpbGwgYmUgb24gdGhlIGBnZW5kZXJgIGFuZCBgc3Ryb2tlYCB2YXJpYWJsZXMsIHdoaWNoIGFyZSBlYWNoIHR3byBsZXZlbCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuIFBhcnRpY3VsYXJseSwgdGhpcyBhbmFseXNpcyB3aWxsIGJlIGNvbnNpZGVyaW5nIHdoZXRoZXIgb3Igbm90IHRoZSBnZW5kZXIgb2YgYSBwYXRpZW50IHRoYXQgaGFzIGJlZW4gZXZhbHVhdGVkIGZvciBhIHN0cm9rZSBoYXMgYW4gaW1wYWN0IG9uIHdoZXRoZXIgb3Igbm90IHRoZXkgZGlkIGhhdmUgYSBzdHJva2UuIEluIHRoaXMgYW5hbHlzaXMsIGEgOTAlIGNvbmZpZGVuY2UgbGV2ZWwgd2lsbCBiZSB1c2VkIGFuZCBhIEJheWVzaWFuIGF1Z21lbnRhdGlvbiBvZiArMiBzdWNjZXNzIGFuZCArMiBmYWlsdXJlcyB3aWxsIGJlIHVzZWQuIFRoZSByZXNlYXJjaCBxdWVzdGlvbiBpcyBhcyBmb2xsb3dzOgoKKipJcyB0aGVyZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBnZW5kZXIgb2YgYSBwZXJzb24gKG1hbGUgb3IgZmVtYWxlKSBhbmQgd2hldGhlciBvciBub3QgdGhhdCBwZXJzb24gaGFzIGhhZCBhIHN0cm9rZSBhbW9uZyBwYXRpZW50cyB3aG8gaGF2ZSBhIHN0cm9rZSBldmFsdWF0aW9uIGluIHRoZWlyIGVsZWN0cm9uaWMgaGVhbHRoIHJlY29yZD8qKgoKIyMgRGVzY3JpYmluZyB0aGUgRGF0YQoKRm9yIHRoaXMgYW5hbHlzaXMgdHdvIHZhcmlhYmxlcyBpbiB0aGUgYFN0cm9rZV9kYXRhYCBkYXRhIHNldCBhcmUgY29uc2lkZXJlZDogYGdlbmRlcmAgYW5kIGBzdHJva2VgLiBCb3RoIG9mIHRoZXNlIGFyZSBiaW5hcnkgY2F0ZWdvcmljYWwgdmFyaWFibGVzLiBHZW5kZXIgcmVmZXJzIHRvIHRoZSBnZW5kZXIgb2YgdGhlIHN1YmplY3QgYmFzZWQgb24gcmVjb3JkaW5nIGluIHRoZSBwYXRpZW50J3MgRUhSLiAiTWFsZSIgaW5kaWNhdGVzIHRoYXQgdGhlIHN1YmplY3Qgd2FzIG1hbGUsICJGZW1hbGUiIGluZGljYXRlcyB0aGF0IHRoZXkgd2VyZSBmZW1hbGUuIFN0cm9rZSByZWZlcnMgdG8gd2hldGhlciBvciBub3QgZWxlY3Ryb25pYyBoZWFsdGggcmVjb3JkcyBpbmRpY2F0ZWQgdGhhdCBhIHBhdGllbnQgaGFkIHN1ZmZlcmVkIGEgc3Ryb2tlIGF0IHNvbWUgcG9pbnQgaW4gdGhlaXIgbGlmZS4gIlN0cm9rZSIgaW5kaWNhdGVzIHRoYXQgdGhleSBzdWZmZXJlZCBhIHN0cm9rZSwgIk5vIFN0cm9rZSIgaW5kaWNhdGVzIHRoYXQgdGhleSBkaWQgbm90LgoKVGhlIGZvbGxvd2luZyBjb2RlIGlzIHByZXNlbnQgZm9yIHRoZSBwdXJwb3NlIG9mIGNyZWF0aW5nIGEgdHdvIGJ5IHR3byB0YWJsZSB0byBhbmFseXplIHRoZSBwb3RlbnRpYWwgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHR3byBjaG9zZW4gdmFyaWFibGVzLiBJbiB0aGlzIHRhYmxlLCB3aGljaCBpcyBkaXNwbGF5ZWQgaW4gc3RhbmRhcmQgZXBpZGVtaW9sb2dpY2FsIGZvcm1hdCwgdGhlIFxgZ2VuZGVyIHN0YXR1cyAiTWFsZSIgaXMgY29uc2lkZXJlZCB0byBiZSB0aGUgZXhwb3N1cmUgb2YgaW50ZXJlc3QuIFRoZSBwdXJwb3NlIG9mIHRoaXMgdGFibGUgaXMgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgcGF0aWVudHMsIGFuZCBmb3IgdGhpcyByZWFzb24sIGEgQmF5ZXNpYW4gYXVnbWVudGF0aW9uIHdhcyB3aXRoaGVsZC4gSG93ZXZlciwgaXQgd2lsbCBiZSBhZGRlZCBkdXJpbmcgdGhlIG1haW4gYW5hbHlzaXMuCgpgYGB7cn0KCiMgUmUtbGV2ZWxpbmcgdGhlIGZhY3RvcnMgc28gdGhhdCB0aGUgdGFieWwgd2lsbCBiZSBpbiBzdGFuZGFyZCBlcGlkZW1pb2xvZ2ljYWwgZm9ybWF0OgoKU3Ryb2tlX2RhdGFfYW5hbHlzaXNEIDwtIFN0cm9rZV9kYXRhIHw+IAogICAgbXV0YXRlKHN0cm9rZSA9IGZjdF9yZWxldmVsKHN0cm9rZSwgIlN0cm9rZSIsICJObyBTdHJva2UiKSkgfD4KICBtdXRhdGUoZ2VuZGVyID0gZmN0X3JlbGV2ZWwoZ2VuZGVyLCAiTWFsZSIsICJGZW1hbGUiKSkKClN0cm9rZV9kYXRhX2FuYWx5c2lzRCB8PiB0YWJ5bChnZW5kZXIsIHN0cm9rZSkgfD4gCiAgICBhZG9ybl9wZXJjZW50YWdlcyhkZW5vbSA9ICJyb3ciKSB8PgogICAgYWRvcm5fcGN0X2Zvcm1hdHRpbmcoZGlnaXRzID0gMSkgfD4KICAgIGFkb3JuX25zKHBvc2l0aW9uID0gImZyb250IikgfD4gCiAgICBhZG9ybl90aXRsZShjb2xfbmFtZSA9ICJTdHJva2Ugc3RhdHVzIGJ5IGdlbmRlciIsIAogICAgICAgICAgICAgICAgcm93X25hbWUgPSAiR2VuZGVyIikgfD4gCiAga2JsKGNhcHRpb24gPSAiU3Ryb2tlIFN0YXR1cyBieSBHZW5kZXIiLCBkaWdpdHMgPSAyKSB8PiAKICBrYWJsZV9zdHlsaW5nKGZvbnRfc2l6ZSA9IDIwKSB8PiAKICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikKCgoKYGBgCgojIyBNYWluIEFuYWx5c2lzCgpUaGUgZm9sbG93aW5nIGNvZGUgaXMgcHJlc2VudCBmb3IgdGhlIHB1cnBvc2Ugb2YgY3JlYXRpbmcgYSB0d28tYnktdHdvIHRhYmxlIGFuYWx5c2lzLCBkaXNwbGF5aW5nIHRoZSBhIHBvaW50IGVzdGltYXRlIGFuZCA5MCUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIHByb2JhYmlsaXR5IG9mIGhhdmluZyBhIHNwZWNpZmljIGBzdHJva2VgIHN0YXR1cyBiZXR3ZWVuIHRoZSB0d28gYGdlbmRlcmAgY2F0ZWdvcmllcywgYSByZWxhdGl2ZSByaXNrIG9mIHN0cm9rZSBnaXZlbiB0aGF0IHRoZSBnZW5kZXIgaXMgbWFsZSAodnMgZmVtYWxlKSwgYW5kIHRoZSBvZGRzIHJhdGlvIGRlc2NyaWJpbmcgdGhlIG9kZHMgb2Ygc3Ryb2tlIHVzZSBnaXZlbiB0aGF0IHRoZSBnZW5kZXIgaXMgTWFsZSAodnMgZmVtYWxlKS4KCipBIEJheWVzaWFuIGF1Z21lbnRhdGlvbiB3YXMgYWRkZWQgdG8gdGhlIGFuYWx5c2lzIHRhYmxlLCBhZGRpbmcgdHdvIHN1Y2Nlc3NlcyBhbmQgdHdvIGZhaWx1cmVzIGluIGFjY29yZGFuY2Ugd2l0aCBBbGFuIEFncmVzdGkncyBzdWdnZXN0aW9uIG9mIHVzaW5nICh4ICsyKS8obiArNCkgYXMgYSBzdWNjZXNzIHJhdGUgZXN0aW1hdGUgZm9yIGNhdGVnb3JpY2FsIGRhdGEgYW5hbHlzaXMgcmF0aGVyIHRoYW4gKHgpKS8obikqCgpgYGB7cn0KCnR3b2J5dHdvKDc1KzIsIDEyNDkrMiwgMTA0KzIsIDE5MzkrMiwKICAgICAgICAgIk1hbGUiLCAiRmVtYWxlIiwgIlN0cm9rZSIsICJObyBTdHJva2UiLAogICAgICAgICBjb25mLmxldmVsID0gMC45MCkKCmBgYAoKSXQgY2FuIGJlIGVsdWNpZGF0ZWQgZnJvbSB0aGUgYWJvdmUgdGFibGUgdGhhdCB0aGUgaW5kaXZpZHVhbCBwcm9iYWJpbGl0eSBvZiBiZWluZyBhIG1hbGUgd2l0aCBhIHBvc2l0aXZlIHN0cm9rZSBzdGF0dXMgd2FzIGFyb3VuZCAwLjA1OCBhbmQgdGhhdCB0aGUgaW5kaXZpZHVhbCBwcm9iYWJpbGl0eSBvZiBiZWluZyBhIGZlbWFsZSB3aXRoIGEgcG9zaXRpdmUgc3Ryb2tlIHN0YXR1cyB3YXMgYXJvdW5kIDAuMDUxOCwgZWFjaCB3aXRoIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGZyb20gYXJvdW5kIDAuMDQgdG8gMC4wNi4KCkl0IGNhbiBhbHNvIGJlIHNlZW4gdGhhdCB0aGUgcmVsYXRpdmUgcmlzayBvZiBoYXZpbmcgc3VmZmVyZWQgYSBzdHJva2UgZ2l2ZW4gYmVpbmcgbWFsZSB2cy4gaGF2aW5nIHN1ZmZlcmVkIGEgc3Ryb2tlIGdpdmVuIGJlaW5nIG1hbGUsIGlzIGVzdGltYXRlZCB0byBiZSAxLjExOTcuIFdoaWxlIHRoZSBwb2ludCBlc3RpbWF0ZSBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBhIGdyZWF0ZXIgcmlzayBvZiBzdWZmZXJpbmcgYSBzdHJva2UgZm9yIG1hbGVzIHRoYW4gZmVtYWxlcywgdGhlIDkwJSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGlzIHJlbGF0aXZlIHJpc2sgdmFsdWUgaXMgMC44ODEzIC0gMS40MjI1LCB3aGljaCBpcyBub3QgZGV0ZWN0YWJseSBkaWZmZXJlbnQgZnJvbSAxIGF0IGFuIGFscGhhIGxldmVsIG9mIDAuMTAuIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlcmUgaXMgbm90IGV2aWRlbmNlIHRvIHN1Z2dlc3QgdGhhdCBiZWluZyBtYWxlIGlzIGVpdGhlciBhIHJpc2sgZmFjdG9yIG9yIGEgcHJvdGVjdGluZyBmYWN0b3IgZm9yIHN0cm9rZSBpbiB0aGlzIGRhdGEgc2V0LgoKQWRkaXRpb25hbGx5LCBhbiBvZGRzIHJhdGlvIGRlc2NyaWJpbmcgdGhlIG9kZHMgb2YgaGF2aW5nIHN1ZmZlcmVkIGEgc3Ryb2tlIGdpdmVuIGEgcGF0aWVudCBpcyBtYWxlIHZzLiBmZW1hbGUgd2FzIGZvdW5kIHRvIGJlIDEuMTI3MSB3aXRoIGEgOTAlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgb2YgMC44NzQ4IC0gMS40NTIxLiBBbHRob3VnaCB0aGUgb2RkcyByYXRpbyBzdWdnZXN0cyB0aGF0IG1hbGVzIGhhdmUgYSBncmVhdGVyIG9kZHMgb2YgaGF2aW5nIHN1ZmZlcmVkIGEgc3Ryb2tlIHRoYW4gZmVtYWxlcywgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgc3VnZ2VzdHMgdGhhdCB0aGUgb2RkcyByYXRpbyBpcyBub3QgZGV0ZWN0YWJseSBkaWZmZXJlbnQgZnJvbSAxIGF0IGFuIGFscGhhIGxldmVsIG9mIDAuMTAuIFRoaXMgaW5kaWNhdGVzIHRoYXQgYSBsYXJnZXIgc2FtcGxlIHNpemUgd291bGQgbGlrZWx5IGJlIHJlcXVpcmVkIGluIG9yZGVyIHRvIHN1Z2dlc3QgdGhhdCB0aGUgb2RkcyBvZiBzdWZmZXJpbmcgYSBzdHJva2UgYXJlIGhpZ2hlciBvciBsb3dlciBmb3IgbWFsZXMgd2hlbiBjb21wYXJlZCB0byBmZW1hbGVzIGluIHRoZSBgU3Ryb2tlX2RhdGFgIGRhdGEgc2V0LgoKRmluYWxseSwgdGhlIGRpZmZlcmVuY2UgaW4gcHJvYmFiaWxpdHkgb2YgaGF2aW5nIHN1ZmZlcmVkIGEgc3Ryb2tlIGdpdmVuIGEgcGF0aWVudCBpcyBtYWxlIHZzLiBmZW1hbGUgd2FzIGVzdGltYXRlZCB0byBiZSAwLjAwNjIuVGhlIDkwJSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGlzIHJlbGF0aXZlIHJpc2sgdmFsdWUgaXMgLTAuMDA2OCAtIDAuMDE5OSwgd2hpY2ggYXQgYW4gYWxwaGEgbGV2ZWwgb2YgMC4xMCwgaXMgbm90IGRldGVjdGFibHkgZGlmZmVyZW50IGZyb20gemVyby4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBub3QgZW5vdWdoIGV2aWRlbmNlIHRvIHN1Z2dlc3QgdGhhdCB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgaW4gdGhlIHByb2JhYmlsaXR5IG9mIGhhdmluZyBzdWZmZXJlZCBhIHN0cm9rZSBncmVhdGVyIHRoYW4sIGxlc3MgdGhhbiwgb3IgZXF1YWwgdG8gemVybyBiZXR3ZWVuIHRoZSB0d28gYGdlbmRlcmAgY2F0ZWdvcmllcyBpbiB0aGUgU3Ryb2tlX2RhdGFcYCBkYXRhIHNldC4KCiMjIENvbmNsdXNpb25zCgpUaGUgcmVzZWFyY2ggcXVlc3Rpb24gdGhhdCBoZWxwZWQgZ3VpZGUgdGhlIGRlc2lnbiBvZiB0aGlzIGFuYWx5c2lzIHdhcyAiSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgZ2VuZGVyIG9mIGEgcGVyc29uIChtYWxlIG9yIGZlbWFsZSkgYW5kIHdoZXRoZXIgb3Igbm90IHRoYXQgcGVyc29uIGhhcyBoYWQgYSBzdHJva2UgYW1vbmcgcGF0aWVudHMgd2hvIGhhdmUgYSBzdHJva2UgZXZhbHVhdGlvbiBpbiB0aGVpciBlbGVjdHJvbmljIGhlYWx0aCByZWNvcmQ/Ii4gQWx0aG91Z2ggcG9pbnQgZXN0aW1hdGVzIHN1Z2dlc3RlZCB0aGF0IGJlaW5nIG1hbGUgd2FzIGFzc29jaWF0ZWQgd2l0aCBhIGdyZWF0ZXIgcmlzayBvZiBzdWZmZXJpbmcgYSBzdHJva2UgKGJhc2VkIG9uIHRoZSBjYWxjdWxhdGVkIHJpc2sgcmF0aW8pIGFuZCBncmVhdGVyIG9kZHMgb2Ygc3VmZmVyaW5nIGEgc3Ryb2tlIChiYXNlZCBvbiB0aGUgY2FsY3VsYXRlZCBvZGRzIHJhdGlvKSwgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGZvciBhbGwgb2YgdGhlIGVzdGltYXRlcyBpbmNsdWRlZCBib3RoIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSB2YWx1ZXMsIGRlbW9uc3RyYXRpbmcgdGhhdCBhdCB0aGUgY3VycmVudCBzYW1wbGUgc2l6ZSwgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgZ2VuZGVyIG9mIGEgcGVyc29uIChtYWxlIG9yIGZlbWFsZSkgYW5kIHdoZXRoZXIgb3Igbm90IHRoYXQgcGVyc29uIGhhcyBoYWQgYSBzdHJva2UgYW1vbmcgcGF0aWVudHMgd2hvIGhhdmUgYSBzdHJva2UgZXZhbHVhdGlvbiBpbiB0aGVpciBlbGVjdHJvbmljIGhlYWx0aCByZWNvcmQgY291bGQgbm90IGJlIGRldGVybWluZWQgd2l0aCA5MCUgY29uZmlkZW5jZS4KClRoaXMgYW5hbHlzaXMgaGFkIGEgbnVtYmVyIG9mIGxpbWl0YXRpb25zIGFzc29jaWF0ZWQgd2l0aCBpdCwgbGFyZ2VseSBiYXNlZCBvbiB0aGUgcXVhbGl0eSBvZiBpbmZvcm1hdGlvbiBwcm92aWRlZCBmb3IgdGhlIHN0cm9rZSBzdGF0dXMgb2YgdGhlIHBhdGllbnQuIEluIHRoZSBkYXRhIGFuYWx5emVkLCB0aGUgb25seSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgc3Ryb2tlIHN0YXR1cyBvZiB0aGUgcGF0aWVudCB3YXMgd2hldGhlciBvciBub3QgdGhhdCBwYXRpZW50IGhhZCBzdWZmZXJlZCBhIHN0cm9rZS4gVGhlcmUgaXMgbm8gbWVudGlvbiBvZiB0aGUgdHlwZSBvZiBzdHJva2Ugb3IgY2FyZSByZWNlaXZlZCBhZnRlciBzdHJva2Ugd2hpY2ggbWF5IGJlIGFmZmVjdGVkIGJ5IHRoZSBnZW5kZXIgb2YgdGhlIHBhdGllbnQuIEZ1dHVyZSBhbmFseXNlcyBsb29raW5nIHRvIGZpbmQgaWYgdGhlcmUgaXMgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgZ2VuZGVyIG9mIGEgcGVyc29uIGFuZCB3aGV0aGVyIG9yIG5vdCB0aGF0IHBlcnNvbiBoYXMgaGFkIGEgc3Ryb2tlIG1heSB0YWtlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzcGVjaWZpYyB0eXBlIG9mIHN0cm9rZSBhbmQgY2FyZSBnaXZlbiBpbnRvIGFjY291bnQgdG8gZXN0YWJsaXNoIGEgbW9yZSByZWFsaXN0aWMgdmlldyBvZiBhbnkgcmVsYXRpb25zaGlwIG9yIGxhY2sgdGhlcmVvZi4KCiMgQW5hbHlzaXMgRTogQW5hbHl6aW5nIGEgMngzIHRhYmxlCgojIyBSZXNlYXJjaCBRdWVzdGlvbgoKRm9yIHRoaXMgYW5hbHlzaXMsIHRoZSBmb2N1cyB3aWxsIGJlIG9uIHRoZSBgaHlwZXJ0ZW5zaW9uYCBhbmQgYHdvcmtfdHlwZWAgdmFyaWFibGVzLCB3aGljaCBhcmUgZWFjaCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuIFBhcnRpY3VsYXJseSwgdGhpcyBhbmFseXNpcyB3aWxsIGJlIGNvbnNpZGVyaW5nIHdoZXRoZXIgb3Igbm90IHRoZSB0eXBlIG9mIGVtcGxveW1lbnQgb2YgYSBwYXRpZW50IHRoYXQgaGFzIHJlY29yZGVkIGluIHRoZWlyIEVIUiBoYXMgYW4gaW1wYWN0IG9uIHdoZXRoZXIgb3Igbm90IHRoZXkgYWxzbyBoYXZlIGh5cGVydGVuc2lvbiByZWNvcmRlZCBpbiB0aGVpciBFSFIuIEluIHRoaXMgYW5hbHlzaXMsIGEgOTAlIGNvbmZpZGVuY2UgbGV2ZWwgd2lsbCBiZSB1c2VkLiBUaGUgcmVzZWFyY2ggcXVlc3Rpb24gaXMgYXMgZm9sbG93czoKCioqSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHlwZSBvZiBlbXBsb3llciBhIHBlcnNvbiBoYXMgYW5kIHdoZXRoZXIgb3Igbm90IHRoYXQgcGVyc29uIGFsc28gaGFzIGh5cGVydGVuc2lvbiBhbW9uZyBwYXRpZW50cyB3aG8gaGF2ZSBhIHN0cm9rZSBldmFsdWF0aW9uIGluIHRoZWlyIGVsZWN0cm9uaWMgaGVhbHRoIHJlY29yZD8qKgoKRm9yIHRoaXMgYW5hbHlzaXMsIG9ubHkgcGVyc29ucyB3aG8gYXJlIGVtcGxveWVkIHdpbGwgYmUgY29uc2lkZXJlZC4gVGhlIHJlYXNvbiBmb3IgdGhpcyBpcyB0aGF0IHRoZXJlIGlzIGltbWVuc2UgdmFyaWFiaWxpdHkgYW1vbmcgdGhlIHR5cGVzIG9mIGNpcmN1bXN0YW5jZXMgdGhhdCBjb3VsZCBjYXVzZSBzb21lYm9keSB0byBiZSB1bmVtcGxveWVkLiBGb3IgdGhpcyByZWFzb24sIG9ubHkgdGhyZWUgYHdvcmtfdHlwZWAgY2F0ZWdvcmllcyBhcmUgdXNlZCAoIkdvdnRfam9iIiwgIlByaXZhdGUiLCBhbmQgIlNlbGYtZW1wbG95ZWQiKS4KCiMjIERlc2NyaWJpbmcgdGhlIERhdGEKCkluIHRoaXMgYW5hbHlzaXMsIHR3byB2YXJpYWJsZXMgYXJlIG9ic2VydmVkOiB0aGUgaHlwZXJ0ZW5zaW9uIHN0YXR1cyBvZiBhIHBhdGllbnQsIGEgYmluYXJ5IGNhdGVnb3JpY2FsIHZhcmlhYmxlIHRpdGxlZCBgaHlwZXJ0ZW5zaW9uYCwgYW5kIHRoZSBjYXRlZ29yeSBvZiBlbXBsb3ltZW50IG9mIGEgcGF0aWVudCwgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB3aXRoIHRocmVlIGxldmVscyB0aXRsZWQgYHdvcmtfdHlwZWAuIEluIHRoaXMgc3R1ZHksIGBoeXBlcnRlbnNpb25gIHJlcHJlc2VudHMgdGhlIGh5cGVydGVuc2l2ZSBzdGF0dXMgb2YgdGhlIHBhdGllbnQgYXMgaW5kaWNhdGVkIGJ5IHRoYXQgcGF0aWVudCdzIEVIUi4gIk5vIEh5cGVydGVuc2lvbiIgaW5kaWNhdGVzIHRoYXQgdGhlIHBhdGllbnQgZG9lcyBub3QgaGF2ZSBoeXBlcnRlbnNpb24gKGhpZ2ggYmxvb2QgcHJlc3N1cmUpIGFuZCAiSHlwZXJ0ZW5zaW9uIiBpbmRpY2F0ZXMgdGhhdCB0aGUgcGF0aWVudCBoYXMgaHlwZXJ0ZW5zaW9uIChoaWdoIGJsb29kIHByZXNzdXJlKS5gd29ya190eXBlYCByZXByZXNlbnRzIHRoZSBjYXRlZ29yeSBvZiB3b3JrIG9mIHRoZSBwYXRpZW50IGFzIGluZGljYXRlZCBieSB0aGF0IHBhdGllbnTigJlzIEVIUi4g4oCcR292dF9qb2LigJ0gaW5kaWNhdGVzIHRoYXQgdGhlIHBhdGllbnQgd29ya3MgZm9yIHRoZSBnb3Zlcm5tZW50IChwdWJsaWMgc2VjdG9yKSwg4oCcUHJpdmF0ZeKAnSBpbmRpY2F0ZXMgdGhhdCB0aGUgcGF0aWVudCBpcyBlbXBsb3llZCBhbmQgd29ya3MgZm9yIGEgcHJpdmF0ZSBjb21wYW55IChwcml2YXRlIHNlY3RvciksIOKAnFNlbGYtZW1wbG95ZWTigJ0gaW5kaWNhdGVzIHRoYXQgdGhlIHBhdGllbnQgaXMgc2VsZiBlbXBsb3llZC4KClRoZSBmb2xsb3dpbmcgY29kZSBpcyBwcmVzZW50IGZvciB0aGUgcHVycG9zZSBvZiBvcmdhbml6aW5nIGEgdGFibGUgZGlzcGxheWluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGh5cGVydGVuc2lvbiBzdGF0dXMgYW1vbmcgdGhlIHRocmVlIGNhdGVnb3JpZXMgb2YgYHdvcmtfdHlwZWAuICAKCmBgYHtyfQpTdHJva2VfZGF0YV9hbmFseXNpc0UgPC0gU3Ryb2tlX2RhdGEgfD4gCiAgYXNfdGFieWwoKSB8PiAKICBmaWx0ZXIoY29tcGxldGUuY2FzZXMoaHlwZXJ0ZW5zaW9uLCB3b3JrX3R5cGUpKSAKClN0cm9rZV9kYXRhX2FuYWx5c2lzRSR3b3JrX3R5cGUgPC0gcmVjb2RlX2ZhY3RvcihTdHJva2VfZGF0YV9hbmFseXNpc0Ukd29ya190eXBlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdvdnRfam9iIiA9ICJHb3Zlcm5tZW50IEpvYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQcml2YXRlIiA9ICJQcml2YXRlIFNlY3RvciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWxmLWVtcGxveWVkIiA9ICJTZWxmLUVtcGxveWVkIikKCgpBbmFseXNpc19FX3RhYmxlIDwtIFN0cm9rZV9kYXRhX2FuYWx5c2lzRSB8PiAKICB0YWJ5bChoeXBlcnRlbnNpb24sIHdvcmtfdHlwZSkgCgpTdHJva2VfZGF0YV9hbmFseXNpc0UgfD4gCiAgdGFieWwoaHlwZXJ0ZW5zaW9uLCB3b3JrX3R5cGUpIHw+CiAgYWRvcm5fdG90YWxzKHdoZXJlID0gYygicm93IiwgImNvbCIpKSB8PgogICAgYWRvcm5fdGl0bGUoIGNvbF9uYW1lID0gIkVtcGxveWVyIikgfD4KICBrYmwoIGNhcHRpb24gPSAiSHlwZXJ0ZW5zaW9uIHN0YXR1cyBieSBFbXBsb3ltZW50IFR5cGUiLCBkaWdpdHMgPSAyKSB8PgogIGthYmxlX3N0eWxpbmcoZm9udF9zaXplID0gMjApIHw+IAogIGthYmxlX3BhcGVyKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKQoKYGBgCgpJdCBjYW4gYmUgc2VlbiBpbiB0aGUgYWJvdmUgdGFibGUgdGhhdCBncmVhdGVzdCBwcm9wb3J0aW9uIG9mIGh5cGVydGVuc2l2ZSBpbmRpdmlkdWFscyBpcyBzZWVuIGluIHRoZSAiU2VsZi1FbXBsb3llZCIgYHdvcmtfdHlwZWAgY2F0ZWdvcnksIHdpdGggbmVhcmx5IGRvdWJsZSB0aGUgcHJvcG9ydGlvbiBvZiBoeXBlcnRlbnNpdmUgaW5kaXZpZHVhbHMgdGhhbiB0aGUgIkdvdmVybm1lbnQgam9iIiBjYXRlZ29yeSBhbmQgYSBtb3JlIHRoYW4gNTAlIGdyZWF0ZXIgcHJvcG9ydGlvbiBvZiBoeXBlcnRlbnNpdmUgaW5kaXZpZHVhbHMgdGhhbiB0aGUgIlByaXZhdGUgU2VjdG9yIiBjYXRlZ29yeS4gCgoKVG8gZnVydGhlciB2aXN1YWxpemUgdGhlIGluZm9ybWF0aW9uIGluIHRoZSBhYm92ZSB0YWJsZSwgYSBiYXIgY2hhcnQgd2FzIGNvbnN0cnVjdGVkLCBkaXNwbGF5aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgYHdvcmtfdHlwZWAgYW1vbmcgdGhlIHR3byBsZXZlbHMgb2YgYGh5cGVydGVuc2lvbmAuIAoKYGBge3J9CmdncGxvdChTdHJva2VfZGF0YV9hbmFseXNpc0UsIGFlcyh4ID0gaHlwZXJ0ZW5zaW9uLCBmaWxsID0gd29ya190eXBlKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiY2hhcnRyZXVzZTQiLCAic2FsbW9uMiIsICJzdGVlbGJsdWUxIikpICsKICAKICB0aGVtZSgKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImxlbW9uY2hpZmZvbjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjUsIGxpbmV0eXBlID0gInNvbGlkIikpICsKIGxhYnMoCiAgICB0aXRsZSA9ICJIeXBlcnRlbnNpb24gYnkgRW1wbG95bWVudCBUeXBlIiwgCiAgICBzdWJ0aXRsZSA9ICJCYXNlZCBvbiBFSFIgZGF0YSBvZiBwYXRpZW50cyBldmFsdWF0ZWQgZm9yIHN0cm9rZSIsCiAgICB5ID0gIlByb3BvcnRpb24gb2Ygc3R1ZHkgcG9wdWxhdGlvbiIsIAogICAgeD0iSHlwZXJ0ZW5zaW9uIHN0YXR1cyIpICsgCiAgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiYXp1cmUyIikpCmBgYAoKIyMgTWFpbiBBbmFseXNpcwoKSXQgY2FuIGJlIHNlZW4gaW4gdGhlIHR3byBieSB0aHJlZSB0YWJsZSBhYm92ZSB0aGF0IG5vbmUgb2YgdGhlIGNlbGxzIGNvbnRhaW4gemVybyBvYnNlcnZhdGlvbnMgYW5kIGFsbCBjZWxscyBoYXZlIGF0IGxlYXN0IGZpdmUgb2JzZXJ2YXRpb25zLCBhcyBleHBlY3RlZC4gRm9yIHRoaXMgcmVhc29uLCBlYWNoIG9mIHRoZSBDb2NocmFuIGNvbmRpdGlvbnMgY2FuIGJlIGNvbnNpZGVyZWQgdG8gaGF2ZSBiZWVuIG1ldCBhbmQgYSBQZWFyc29uIGNoaS1zcXVhcmUgdGVzdCBpcyBhcHByb3ByaWF0ZSBmb3IgYXNzZXNzaW5nIGhvbW9nZW5laXR5IC4KCkEgY2hpLXNxdWFyZSB0ZXN0IGZvciB0aGUgZGF0YSBpbiB0aGUgYWJvdmUgdGFibGUgd2lsbCBoZWxwIHRvIGVsdWNpZGF0ZSB3aGV0aGVyIG9yIG5vdCB0aGVyZSBpcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBlbXBsb3ltZW50IGNhdGVnb3J5IG9mIGEgcGVyc29uIGFuZCB0aGVpciBoeXBlcnRlbnNpdmUgc3RhdHVzIGJ5IGRldGVybWluaW5nIHdoZXRoZXIgb3Igbm90IHRoZSB0d28gdmFyaWFibGVzIGFyZSBpbmRlcGVuZGVudCBvZiBvbmUgYW5vdGhlci4gVGhlIGNoaS1zcXVhcmUgdGVzdCBvZiBpbmRlcGVuZGVuY2UgZm9yIHRoaXMgYW5hbHlzaXMgaXMgYSBoeXBvdGhlc2lzIHRlc3Qgd2l0aCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgoqKk51bGwgaHlwb3RoZXNpcyoqOiAqVGhlIGVtcGxveW1lbnQgY2F0ZWdvcnkgb2YgYSBwZXJzb24gYW5kIHRoZWlyIGh5cGVydGVuc2l2ZSBzdGF0dXMgYXJlIGluZGVwZW5kZW50IG9mIG9uZSBhbm90aGVyLiogCgoqKkFsdGVybmF0aXZlIGh5cG90aGVzaXMqKjogKlRoZXJlIGlzIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGVtcGxveW1lbnQgY2F0ZWdvcnkgb2YgYSBwZXJzb24gYW5kIHRoZWlyIGh5cGVydGVuc2l2ZSBzdGF0dXMuKgoKVGhlIGZvbGxvd2luZyBjb2RlIGlzIHByZXNlbnQgZm9yIHRoZSBwdXJwb3NlIG9mIHJ1bm5pbmcgYSBjaGktc3F1YXJlIHRlc3Qgb2YgaW5kZXBlbmRlbmNlLgoKYGBge3J9CgpjaGlzcS50ZXN0KEFuYWx5c2lzX0VfdGFibGUpCgpgYGAKCkl0IGNhbiBiZSBzZWVuIGFib3ZlIHRoYXQgdGhlIGNoaS1zcXVhcmUgdGVzdCBzdGF0aXN0aWMgaXMgMjMuOTAxIG9uIHR3byBkZWdyZWVzIG9mIGZyZWVkb20uIFRoZSBjaGktc3F1YXJlIHRlc3Qgb2YgaW5kZXBlbmRlbmNlIHlpZWxkZWQgYSBwLXZhbHVlIG9mIDYuNDU3ZS0wNi4gVGhpcyBpbmZvcm1hdGlvbiBzdWdnZXN0cyB0aGF0IHRoZSBkaWZmZXJlbmNlIGluIGh5cGVydGVuc2lvbiBzdGF0dXMgYW1vbmcgdGhlIHRocmVlIGVtcGxveW1lbnQgY2F0ZWdvcmllcyBvZiB0aGUgYHdvcmtfdHlwZWAgdmFyaWFibGUgaXMgbGVzcyBsaWtlbHkgdG8gYmUgZHVlIHRvIGNoYW5jZSBhbmQgbW9yZSBsaWtlbHkgdG8gYmUgYXR0cmlidXRlZCB0byBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGh5cGVydGVuc2lvbiBzdGF0dXMgYW5kIGVtcGxveW1lbnQgdHlwZS4gSXQgaXMgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCBhZGRpdGlvbmFsIHRlc3RpbmcgbXVzdCBiZSBkb25lIHRvIGRldGVybWluZSB0aGUgdHJ1ZSBwcmVzZW5jZSBvZiBhIHJlbGF0aW9uc2hpcCwgYXMgYSBzbWFsbCBwLXZhbHVlIGNhbiBvbmx5IHN1Z2dlc3QgdGhhdCB0aGVyZSBpcyBhIHNtYWxsIHByb2JhYmlsaXR5IHRoYXQgdGhlIG9ic2VydmVkIGRpZmZlcmVuY2UgaXMgZHVlIHRvIGNoYW5jZSwgbm90IHRoYXQgdGhlcmUgaXMgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcy4gTm9uZXRoZWxlc3MsIHRoZSByZXN1bHRzIG9mIHRoaXMgY2hpLXNxdWFyZSB0ZXN0IG9mIGluZGVwZW5kZW5jZSBlbmNvdXJhZ2UgdGhlIG51bGwgaHlwb3RoZXNpcyB0byBiZSByZWplY3RlZC4gCgojIyBDb25jbHVzaW9ucwoKVGhlIHJlc2VhcmNoIHF1ZXN0aW9uIHRoYXQgZ3VpZGVkIHRoZSBkZXNpZ24gb2YgdGhpcyBhbmFseXNpcyB3YXMgIklzIHRoZXJlIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHR5cGUgb2YgZW1wbG95ZXIgYSBwZXJzb24gaGFzIGFuZCB3aGV0aGVyIG9yIG5vdCB0aGF0IHBlcnNvbiBhbHNvIGhhcyBoeXBlcnRlbnNpb24gYW1vbmcgcGF0aWVudHMgd2hvIGhhdmUgYSBzdHJva2UgZXZhbHVhdGlvbiBpbiB0aGVpciBlbGVjdHJvbmljIGhlYWx0aCByZWNvcmQ/IiBUaGUgY2hpLXNxdWFyZSB0ZXN0IG9mIGluZGVwZW5kZW5jZSB3YXMgYWJsZSB0byBkZXRlcm1pbmUgdGhhdCB0aGVyZSBpcyBhIGhpZ2ggcHJvYmFiaWxpdHkgdGhhdCB0aGVyZSBpcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0eXBlIG9mIGVtcGxveWVyIGEgcGVyc29uIGhhcyBhbmQgd2hldGhlciBvciBub3QgdGhhdCBwZXJzb24gYWxzbyBoYXMgaHlwZXJ0ZW5zaW9uIGJhc2VkIG9uIGluZm9ybWF0aW9uIGZyb20gdGhlIGBoeXBlcnRlbnNpb25gIGFuZCBgd29ya190eXBlYCB2YXJpYWJsZXMgaW4gdGhlIGBTdHJva2VfZGF0YWAgZGF0YSBzZXQuIEl0IHdhcyBub3QsIGhvd2V2ZXIsIGFibGUgdG8gZGV0ZXJtaW5lIHRoZSB0cnVlIG5hdHVyZSBvZiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gaHlwZXJ0ZW5zaW9uIGFuZCB3b3JrIHR5cGUsIG9ubHkgdGhhdCB0aGVyZSBpcyBsaWtlbHkgdG8gYmUgYSByZWxhdGlvbnNoaXAgcHJlc2VudC4gCgpGdXR1cmUgc3R1ZGllcyBsb29raW5nIHRvIGludmVzdGlnYXRlIGEgcG9zc2libGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHR5cGUgb2YgZW1wbG95ZXIgYSBwZXJzb24gaGFzIGFuZCB3aGV0aGVyIG9yIG5vdCB0aGF0IHBlcnNvbiBhbHNvIGhhcyBoeXBlcnRlbnNpb24gbWF5IGNvbnNpZGVyIHV0aWxpemluZyBhIGRhdGEgc2V0IHRoYXQgaW5jbHVkZXMgYSBjb250aW51b3VzIHF1YW50aXRhdGl2ZSB2YXJpYWJsZSB0byBkZXRlcm1pbmUgaHlwZXJ0ZW5zaW9uLCBzdWNoIGFzIHRoZSBibG9vZCBwcmVzc3VyZSBpbiBtbUhnLiBUaGUgcHJlc2VuY2Ugb2YgaHlwZXJ0ZW5zaW9uIGFzIGEgYmluYXJ5IGNhdGVnb3JpY2FsIHZhcmlhYmxlIGlzIGEga2V5IGxpbWl0YXRpb24gdG8gdGhpcyBhbmFseXNpcyBhcyBpdCBwcmV2ZW50cyBhIGRldGFpbGVkIHVuZGVyc3RhbmRpbmcgb2YgdGhlIHJlbGF0aW9uc2hpcCBvZiBoeXBlcnRlbnNpb24gYW5kIGVtcGxveW1lbnQgdHlwZSBmcm9tIGJlaW5nIHZpc3VhbGl6ZWQuIEEgY29udGludW91cyBxdWFudGl0YXRpdmUgdmFyaWFibGUgbWF5IGJldHRlciBiZSBhYmxlIHRvIHN1Z2dlc3QgdGhlIHR5cGUgb2YgcmVsYXRpb25zaGlwIHRoYXQgaXMgcHJlc2VudCBiZXR3ZWVuIHRoZSBlbXBsb3ltZW50IHR5cGUgYW5kIGh5cGVydGVuc2lvbiBzdGF0dXMgb2YgYSBwYXRpZW50IGFuZCBhbnN3ZXIgdGhlIHJlc2VhcmNoIHF1ZXN0aW9uIGluIG1vcmUgZGV0YWlsLiAKCgojIFNlc3Npb24gSW5mb3JtYXRpb24gey51bm51bWJlcmVkfQoKYGBge3J9CgpzZXNzaW9uaW5mbzo6c2Vzc2lvbl9pbmZvKCkKCmBgYAo=