Abstract Summary

Coronavirus Disease 2019 (COVID-19) has become a major health problem causing severe acute respiratory illness in humans. It has spread rapidly around the globe since its outbreak.The incidence of COVID-19 continues to increase with millions confirmed cases and deaths worldwide. In this assignment I have tried to analyze the impact of covid19 in US using R programming language.Data collected from Kaggle websites.Datasets provides information about covid19 related counts and related hospitals and beds availability over different parts of US.Both the datasets are very large dataset .I tried to implements all key concepts of Data Wrangling like tidying the messy data ,creating new variables using mutate ,scanning missing values ,outliers ,applying transformations and visualization.

Required packages

# This is the R chunk for the required packages

library(readr)
library(Hmisc)
library(readxl)
library(dplyr)
library(tidyr)
library(Hmisc)
library(outliers)
library(forecast)
library(gdata)
library(rvest)
library(ggplot2)
library(knitr)
library(car)
library(lubridate)
library(magrittr)

Executive Summary

This report has been prepared by analyzing Novel CoronaVirus cases for country US.I have used datasets from Kaggle. First dataset is the covid daily cases of US and Second dataset is details of avalability of hospitals beds and related data in US .Merging two dataset , and selecting some of the important columns ,I have applied all wrangling techniques.As the data has been collected from different sources,in various shapes and forms,therefore it is necessary to apply relevant methods to prepare the collection of data by using pre-processing techniques before analyzing and visualizing it.

First dataset ‘us_states_covid19_daily.csv’ contains missing values whereas second dataset ‘hospital_beds_USA_v1.csv’ does not contain any missing values. The following steps has been implemented for this entire assignment:

-> Download datasets into RMarkdown

-> Merging two datasets.

-> Selecting the columns from the merged dataset which are required to carry out further assignment.

-> Data type conversions like converting characters to factors.

-> Tidying up data:

  1. Reshaping the data to yield proper format.
  2. Mutate to yield two new coulmn - percentage of positive covid cases and percentage of negative covid cases

-> Scanning:

  1. missing values and handling them.
  2. special values
  3. inconsistencies or obvious errors
  4. Outliers using Boxplot and other appropriate R function handle it.

-> Transformation using appropriate R function

Data

First dataset ‘us_states_covid19_daily.csv’ contains state wise and date wise daily covid cases counts,confirmed deaths,positive cases and other coulmns which gives a comprehensive details of covid cases in USA for all states.It consists of 54 coulmns .Some of the columns contains missing values and is untidy dataset. Second dataset ‘hospital_beds_USA_v1.csv’ contains details of types of beds ,number of beds ,population and others important variables with state wise details of hospitals in US. This dataset contains 12 coulmns .There are no missing data in this dataset. Both the datasets has been merged using left join by state.Please find the links of two dataset below.

https://www.kaggle.com/sudalairajkumar/covid19-in-usa?select=us_states_covid19_daily.csv

https://www.kaggle.com/ikiulian/global-hospital-beds-capacity-for-covid19?select=hospital_beds_USA_v1.csv


# First dataset

US_covid_data <- read_csv("us_states_covid19_daily.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  state = col_character(),
  dataQualityGrade = col_character(),
  lastUpdateEt = col_character(),
  dateModified = col_datetime(format = ""),
  checkTimeEt = col_character(),
  dateChecked = col_datetime(format = ""),
  fips = col_character(),
  totalTestResultsSource = col_character(),
  hash = col_character(),
  grade = col_logical()
)
See spec(...) for full column specifications.
head(US_covid_data)
# second dataset

hospital_beds_USA_v1 <- read_csv("hospital_beds_USA_v1.csv")
Parsed with column specification:
cols(
  country = col_character(),
  state = col_character(),
  county = col_character(),
  lat = col_double(),
  lng = col_double(),
  type = col_character(),
  measure = col_character(),
  beds = col_double(),
  population = col_double(),
  year = col_double(),
  source = col_character(),
  source_url = col_character()
)
head(hospital_beds_USA_v1)

Understand

First I merged two above dataset using left join by state.The next steps I took is to select the columns with which I want to work from the merged dataset.Therefore I have filtered out the required columns using select function which is a part of dplyr package.Total 18 columns have been selected.Also the dataset seems to have very large number of observations ,so I have decided to work with 75000 observations.

After selection of required columns, I have checked data types of columns. Dataset have various datatypes like character,numeric. I found some columns are in characters which needs to be converted into factor. Therefore I converted them into factors by providing labels and levels. The structure of filtered merged dataset after selecting required columns have been studied using str().

# This is the R chunk for the Understand Section

#MERGE

merged <- left_join( hospital_beds_USA_v1 , US_covid_data , by ="state" )
# SELECT ONLY REQUIRED COLUMNS FROM MERGED DATASET


filtered_merged <-merged %>% select(country,state,type,measure,beds,population,year,date ,positive ,negative,totalTestResults,
                                    hospitalizedCurrently,inIcuCurrently,
                                    onVentilatorCurrently, recovered,death ,hospitalized,
                                    deathConfirmed )

# take 75000 observation fron large dataset

filtered_merged <- filtered_merged [1:75000 ,]


str(filtered_merged)
tibble [75,000 x 18] (S3: tbl_df/tbl/data.frame)
 $ country              : chr [1:75000] "US" "US" "US" "US" ...
 $ state                : chr [1:75000] "AK" "AK" "AK" "AK" ...
 $ type                 : chr [1:75000] "ICU" "ICU" "ICU" "ICU" ...
 $ measure              : chr [1:75000] "1000HAB" "1000HAB" "1000HAB" "1000HAB" ...
 $ beds                 : num [1:75000] 0 0 0 0 0 0 0 0 0 0 ...
 $ population           : num [1:75000] 3338 3338 3338 3338 3338 ...
 $ year                 : num [1:75000] 2019 2019 2019 2019 2019 ...
 $ date                 : num [1:75000] 20200927 20200926 20200925 20200924 20200923 ...
 $ positive             : num [1:75000] 8431 8315 8202 7941 7941 ...
 $ negative             : num [1:75000] 434554 434554 433130 425257 425257 ...
 $ totalTestResults     : num [1:75000] 442869 442869 441332 433198 433198 ...
 $ hospitalizedCurrently: num [1:75000] 43 43 43 43 43 43 47 43 41 36 ...
 $ inIcuCurrently       : num [1:75000] NA NA NA NA NA NA NA NA NA NA ...
 $ onVentilatorCurrently: num [1:75000] 14 14 14 14 14 14 13 13 13 13 ...
 $ recovered            : num [1:75000] 3502 3267 3042 2731 2731 ...
 $ death                : num [1:75000] 56 52 51 45 45 45 45 45 45 45 ...
 $ hospitalized         : num [1:75000] NA NA NA NA NA NA NA NA NA NA ...
 $ deathConfirmed       : num [1:75000] 56 52 51 45 45 45 45 45 45 45 ...
#DATA TYPE CONVERSION

filtered_merged$type <-factor(filtered_merged$type, levels= c("ACUTE" , "ICU" ,"OTHER" ,"PSYCHIATRIC") ,labels=c("ACUTE" , "ICU" ,"OTHER" ,"PSYCHIATRIC") ,ordered=TRUE)
levels(filtered_merged$type)
[1] "ACUTE"       "ICU"         "OTHER"       "PSYCHIATRIC"
filtered_merged$state <- as.factor(filtered_merged$state)
levels(filtered_merged$state)
[1] "AK" "AL" "AR" "AZ" "CA"
filtered_merged$measure <- as.factor(filtered_merged$measure)
levels(filtered_merged$measure)
[1] "1000HAB"
filtered_merged$country <- as.factor(filtered_merged$country)
levels(filtered_merged$country)
[1] "US"

Tidy & Manipulate Data I

Dataset ‘filtered_merged’ which was formed after merging two dataset and selection required columns was found to be in improper format and have many missing values.Secondly I aim to find out covid cases details along with hospital beds details for each states.I have found multiple variables like hospital bed types have been stored in rows .These types needs to be converted into columns so that we can know the counts of each type of bed.That is why I have used spread() function to wide format by generating new columns from ‘type’ column .The columns so formed after reshaping are ‘ACUTE’ ,‘ICU’,‘OTHER’,‘PSYCHIATRIC’. This reshaped columns will give the counts of different types of beds available in different states of US .

# This is the R chunk for the Tidy & Manipulate Data I 

#RESHAPE

reshape_covid_data <-spread(filtered_merged ,key =type  ,value =beds)
head(reshape_covid_data)
NA

Tidy & Manipulate Data II

I have created two new columns using mutate() function which is a part of dplyr package.

-The first new column is the percentage of positive covid cases which has been calculated using formula : (positive tested cases / total tested cases) *100 .

-The second new column is the percentage of negative covid cases which uses the formula : (negative tested cases / total tested cases) *100 .

# This is the R chunk for the Tidy & Manipulate Data II 

#MUTATE

# create new column with percentage of positive covid case = (negative /totalTestResults)*100

reshape_covid_data <-reshape_covid_data %>% mutate(Positive_case_percentage = (positive /totalTestResults)*100 )


# create new column with percentage of negative covid case = (negative /totalTestResults)*100

reshape_covid_data <-reshape_covid_data %>% mutate(Negative_case_percentage = (negative /totalTestResults)*100 )

# After mutate

head(reshape_covid_data)
NA

Scan I

First phase of scanning involves Scan of the data for missing values, special values and obvious errors (i.e. inconsistencies).

1.First I checked for missing values from original two datasets and then merged filtered dataset. We found some columns with missing values.

2.Imputing some of the columns like ACUTE ,ICU,OTHER ,PSYCHIATRIC with mean value using impute() which is a part of Hmisc package.Assuming as numbers of missing is high so imputing with mean value would ensure consistency and will reduce overall variance. For other missing columns, I have replaced the missing values with mean of that column with mean() so as to retain overall consistent data.

3.Next step was to check for special values like infinite values ,nan values or numeric values. None of the columns has been found with special values.

4.Finally I checked for any inconsistencies and error such as negative values in columns. No such columns has been found with such criteria.

# This is the R chunk for the Scan I


#Scanning for missing values


any(is.na(reshape_covid_data))
[1] TRUE
colSums(is.na(reshape_covid_data))
                 country                    state                  measure               population                     year                     date 
                       0                        0                        0                        0                        0                        0 
                positive                 negative         totalTestResults    hospitalizedCurrently           inIcuCurrently    onVentilatorCurrently 
                       0                      375                        0                     6893                    55260                    35597 
               recovered                    death             hospitalized           deathConfirmed                    ACUTE                      ICU 
                   17784                     3196                    16488                    37043                    40770                    25120 
                   OTHER              PSYCHIATRIC Positive_case_percentage Negative_case_percentage 
                   60326                    59868                      500                      500 

# Action on missing values on refined merged data


reshape_covid_data$ACUTE <- impute(reshape_covid_data$ACUTE, fun = mean) 

reshape_covid_data$ICU <- impute(reshape_covid_data$ICU, fun = mean) 

reshape_covid_data$OTHER <- impute(reshape_covid_data$OTHER, fun = mean) 

reshape_covid_data$PSYCHIATRIC <- impute(reshape_covid_data$PSYCHIATRIC, fun = mean) 

reshape_covid_data$negative[is.na(reshape_covid_data$negative)] <- mean(reshape_covid_data$negative ,na.rm = TRUE)

reshape_covid_data$hospitalizedCurrently[is.na(reshape_covid_data$hospitalizedCurrently)] <- mean(reshape_covid_data$hospitalizedCurrently ,na.rm = TRUE)

reshape_covid_data$inIcuCurrently[is.na(reshape_covid_data$inIcuCurrently)] <- mean(reshape_covid_data$inIcuCurrently ,na.rm = TRUE)

reshape_covid_data$onVentilatorCurrently[is.na(reshape_covid_data$onVentilatorCurrently)] <-mean(reshape_covid_data$onVentilatorCurrently ,na.rm = TRUE)

reshape_covid_data$recovered[is.na(reshape_covid_data$recovered)] <- mean(reshape_covid_data$recovered ,na.rm = TRUE)

reshape_covid_data$hospitalized[is.na(reshape_covid_data$hospitalized)] <- mean(reshape_covid_data$hospitalized,na.rm = TRUE)

reshape_covid_data$death[is.na(reshape_covid_data$death)] <-mean(reshape_covid_data$death ,na.rm = TRUE)

reshape_covid_data$deathConfirmed[is.na(reshape_covid_data$deathConfirmed)] <- mean(reshape_covid_data$deathConfirmed ,na.rm = TRUE)

reshape_covid_data$Negative_case_percentage[is.na(reshape_covid_data$Negative_case_percentage)] <-mean(reshape_covid_data$Negative_case_percentage,na.rm = TRUE)

reshape_covid_data$Positive_case_percentage[is.na(reshape_covid_data$Positive_case_percentage)] <-mean(reshape_covid_data$Positive_case_percentage,na.rm = TRUE)

colSums(is.na(reshape_covid_data))
                 country                    state                  measure               population                     year                     date 
                       0                        0                        0                        0                        0                        0 
                positive                 negative         totalTestResults    hospitalizedCurrently           inIcuCurrently    onVentilatorCurrently 
                       0                        0                        0                        0                        0                        0 
               recovered                    death             hospitalized           deathConfirmed                    ACUTE                      ICU 
                       0                        0                        0                        0                        0                        0 
                   OTHER              PSYCHIATRIC Positive_case_percentage Negative_case_percentage 
                       0                        0                        0                        0 

#Check  for special values

#Define function 
special_values <- function(x){
  if (is.numeric(x)) (is.infinite(x) | is.nan(x))
}

sp_value<-sapply(reshape_covid_data, FUN = special_values)

sapply(reshape_covid_data, function(x){if (is.numeric(x)) sum(special_values(x))})
$country
NULL

$state
NULL

$measure
NULL

$population
[1] 0

$year
[1] 0

$date
[1] 0

$positive
[1] 0

$negative
[1] 0

$totalTestResults
[1] 0

$hospitalizedCurrently
[1] 0

$inIcuCurrently
[1] 0

$onVentilatorCurrently
[1] 0

$recovered
[1] 0

$death
[1] 0

$hospitalized
[1] 0

$deathConfirmed
[1] 0

$ACUTE
[1] 0

$ICU
[1] 0

$OTHER
[1] 0

$PSYCHIATRIC
[1] 0

$Positive_case_percentage
[1] 0

$Negative_case_percentage
[1] 0
##Check  for inconsistencies or obvious errors for numerical columns

nonnegative<- function(x){x<0}

nonnegative_values<-sapply(reshape_covid_data[,7:22], FUN = nonnegative)

colSums(nonnegative_values)
                positive                 negative         totalTestResults    hospitalizedCurrently           inIcuCurrently    onVentilatorCurrently 
                       0                        0                        0                        0                        0                        0 
               recovered                    death             hospitalized           deathConfirmed                    ACUTE                      ICU 
                       0                        0                        0                        0                        0                        0 
                   OTHER              PSYCHIATRIC Positive_case_percentage Negative_case_percentage 
                       0                        0                        0                        0 

Scan II

Next phase of scanning involves detecting outliers and how to handle them. As the dataset is very large ,therefore there are possibilities of large number of outliers.

  1. First I have taken subsets from above dataset by taking some of the numerical columns to do a better visual inspection of outliers and later transformations.

  2. Then I checked for outliers using boxplot.I found columns ‘recovered’,‘positive,’death’ and ‘hospitalizedCurrently’ have few outliers in it.

  3. Capping or winsorising involves replacing the outliers with the nearest neighbours that are not outliers instead of removing outliers.Since it is not always necessary that outliers are generated because of errors .Sometimes outliers can be legitimate observations.For example positive or death have outlier might mean that positive covid cases or covid death cases are high. Therefore I decided to use cap() instead of removing outliers.

  4. I created cap() function to replace those data points lying outside the lower limit and above the upper limit with the value of 5th percentile and 95th percentile.

  5. Summary of the subset data has been computed before and after capping .

Scan Outliers

#subset numerical columns into dataset

covid_subset<- reshape_covid_data %>% select( positive ,negative ,totalTestResults,hospitalizedCurrently ,recovered ,Positive_case_percentage ,death)


#CHECK OUTLIERS USING BOXPLOTS

# boxplot for finding outliers


par(mfrow=c(1,2))

boxplot(covid_subset$recovered ,main ="recovered cases")
grid(col = "grey")

boxplot(covid_subset$positive ,main ="positive cases")
grid(col = "grey")


boxplot(covid_subset$hospitalizedCurrently ,main ="hospitalizedCurrently cases")
grid(col = "grey")

boxplot(covid_subset$death ,main ="death cases")
grid(col = "grey")

NA
NA
#CAPPING


cap <- function(x){
  quantiles <- quantile( x, c(.05, 0.25, 0.75, .95 ) )
  x[ x < quantiles[2] - 1.5*IQR(x) ] <- quantiles[1]
  x[ x > quantiles[3] + 1.5*IQR(x) ] <- quantiles[4]
  x
}

#Descriptive statistics of the subset

summary(covid_subset)
    positive         negative        totalTestResults   hospitalizedCurrently   recovered     Positive_case_percentage     death      
 Min.   :     0   Min.   :       0   Min.   :       0   Min.   :   7.0        Min.   :   11   Min.   : 0.000           Min.   :    0  
 1st Qu.:  3006   1st Qu.:   45124   1st Qu.:   47398   1st Qu.: 224.0        1st Qu.: 7116   1st Qu.: 6.490           1st Qu.:   85  
 Median : 16957   Median :  254491   Median :  264492   Median : 509.0        Median :22820   Median : 8.498           Median :  517  
 Mean   : 53391   Mean   :  568349   Mean   :  617287   Mean   : 846.8        Mean   :22820   Mean   : 9.650           Mean   : 1106  
 3rd Qu.: 66757   3rd Qu.:  602939   3rd Qu.:  673704   3rd Qu.: 846.8        3rd Qu.:30682   3rd Qu.:12.303           3rd Qu.: 1181  
 Max.   :802308   Max.   :13531190   Max.   :14333498   Max.   :8820.0        Max.   :72602   Max.   :81.579           Max.   :15587  
#Applying cap() to the numeric variables

positive_capped <- covid_subset$positive %>%cap()

recovered_capped<- covid_subset$recovered %>% cap()

hospitalized_capped <- covid_subset$hospitalizedCurrently %>%cap()

positivePercent_cap<- covid_subset$Positive_case_percentage %>% cap()

totalTestResults_capped <- covid_subset$totalTestResults %>%cap()

death_capped <- covid_subset$death %>%cap()

Covid_capped <- sapply(covid_subset, FUN = cap)

#Descriptive statistics of the capped dataset

summary(Covid_capped)
    positive         negative       totalTestResults  hospitalizedCurrently   recovered     Positive_case_percentage     death       
 Min.   :     0   Min.   :      0   Min.   :      0   Min.   :   7.0        Min.   :   11   Min.   : 0.000           Min.   :   0.0  
 1st Qu.:  3006   1st Qu.:  45124   1st Qu.:  47398   1st Qu.: 224.0        1st Qu.: 7116   1st Qu.: 6.490           1st Qu.:  85.0  
 Median : 16957   Median : 254491   Median : 264492   Median : 509.0        Median :22820   Median : 8.498           Median : 517.0  
 Mean   : 43113   Mean   : 350384   Mean   : 389790   Mean   : 763.3        Mean   :22701   Mean   : 8.952           Mean   : 947.8  
 3rd Qu.: 66757   3rd Qu.: 602939   3rd Qu.: 673704   3rd Qu.: 846.8        3rd Qu.:30682   3rd Qu.:12.303           3rd Qu.:1181.0  
 Max.   :185053   Max.   :1424675   Max.   :1582745   Max.   :3454.0        Max.   :66003   Max.   :20.091           Max.   :4626.0  

Transform

Transformation is required in Data wrangling for scaling,standardizing,normalizing ,reducing skewness of distribution.I have applied different types of transformation like log , log10 ,Box-Cox transformation to the capped data which I got from above steps after capping outliers .After experimenting with different transformation types,I found the best types suitable for each of the variables.

Below are the observations after applying transformation.

  1. hospitalized_capped was right skewed .This variable does not have any negative values .So applying log10 transformation, graph produce more symmetric distribution.

  2. positive_capped was shown as extremely right skewed. This variable also does not have any negative values Applying log transformation ,distribution look approximately more symmetrical.

  3. positivePercent_cap was unevenly distributed and not was symmetric .Here I applied Box-Cox transformation rather than log transformation which produced more symmetric distribution.

  4. death_capped was rightly skewed.Applying Box-Cox transformation produced the best result than other transformation and resulted in approximately symmetrical distribution.


par(mfrow=c(1,2))

hist(hospitalized_capped ,main = " Covid Hospitalized ", xlab = "Covid Hospitalized ")
grid(col = "grey")

# It is highly right skewed

# Applying log10 transformation

log_hospitalized <- log10(hospitalized_capped)


# Histogram after transformation

hist(log_hospitalized ,main = "Log10 transformation", xlab = "Covid Hospitalized " ,col = "bisque" )

grid(col = "grey")


par(mfrow=c(1,2))

hist(positive_capped,main = "Number of covid positive cases ", xlab = "covid_positive_cases")

grid(col = "grey")
# It is highly right skewed

# Applying log transformation

log_positive <- log(positive_capped)

# Histogram after transformation

hist(log_positive ,main = "Log transformation ", xlab = "covid_positive_cases" ,col = "bisque")
grid(col = "grey")

NA
NA

par(mfrow=c(1,2))

hist(positivePercent_cap ,main ="Percentage of positive cases", xlab = "positive case percentage")
grid(col = "grey")

# Applying Box-Cox transformation

boxcox_positive<- BoxCox(positivePercent_cap,lambda = "auto")

hist(boxcox_positive ,main ="Box-Cox transformation", xlab = "positive case perecentage" ,col = "bisque")
grid(col = "grey")

NA
NA

par(mfrow=c(1,2))

hist(death_capped ,main = "Number of Covid deaths ", xlab = "number of Covid deaths ")
grid(col = "grey")
# It is highly right skewed

# Applying boxcox transformation


boxcox_death<- BoxCox(death_capped,lambda = "auto")

# Histogram after transformation

hist(boxcox_death ,main = "BoxCox transformation ", xlab = "number of Covid deaths " ,col = "bisque")
grid(col = "grey")

NA
NA

Conclusion

-From the above assignment,we can see how large messy data sets and be pre-processed using Data Wrangling techniques in R.

-Tidying up data ensures variable have its own columns and observations have its own rows.

-Scanning missing data,special values and outliers is necessary before any statistical analysis so that clean data can be used as input into a variety of other functions that may transform, model, or visualize the data.

-Also we can see that it is not always good idea to eliminate missing data or outliers as it can remove important data from the dataset. Techniques like Imputation ,capping are some of the methods which can be applied to make data more efficent for further use.

-To make better-organized and properly formatted data, transformation is necessary.Not always same transformation type is applicable to all data variables .Each variable can be experiment by applying different transformation method and the best one can be found which ensure maximum possible symmetry and normality.

-Overall this assignment helped me to gain insights into practical aspects of Data Wrangling and understand real world problems.

LS0tDQp0aXRsZTogIk1BVEgyMzQ5IERhdGEgV3JhbmdsaW5nIg0KYXV0aG9yOiAiQXBhcnVwYSBNaXRyYSAoczM4MzE3MjQpIg0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMiA6Q09WSUQgQU5BTFlTSVMgVVNJTkcgUg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCiMjIEFic3RyYWN0IFN1bW1hcnkgDQoNCkNvcm9uYXZpcnVzIERpc2Vhc2UgMjAxOSAoQ09WSUQtMTkpIGhhcyBiZWNvbWUgYSBtYWpvciBoZWFsdGggcHJvYmxlbSBjYXVzaW5nIHNldmVyZSBhY3V0ZSByZXNwaXJhdG9yeSBpbGxuZXNzIGluIGh1bWFucy4gSXQgaGFzIHNwcmVhZCByYXBpZGx5IGFyb3VuZCB0aGUgZ2xvYmUgc2luY2UgaXRzIG91dGJyZWFrLlRoZSBpbmNpZGVuY2Ugb2YgQ09WSUQtMTkgY29udGludWVzIHRvIGluY3JlYXNlIHdpdGggIG1pbGxpb25zIGNvbmZpcm1lZCBjYXNlcyBhbmQgZGVhdGhzIHdvcmxkd2lkZS4gSW4gdGhpcyBhc3NpZ25tZW50IEkgaGF2ZSB0cmllZCB0byBhbmFseXplIHRoZSBpbXBhY3Qgb2YgY292aWQxOSBpbiBVUyB1c2luZyBSIHByb2dyYW1taW5nIGxhbmd1YWdlLkRhdGEgY29sbGVjdGVkIGZyb20gS2FnZ2xlIHdlYnNpdGVzLkRhdGFzZXRzIHByb3ZpZGVzIGluZm9ybWF0aW9uIGFib3V0IGNvdmlkMTkgcmVsYXRlZCBjb3VudHMgYW5kIHJlbGF0ZWQgaG9zcGl0YWxzIGFuZCBiZWRzIGF2YWlsYWJpbGl0eSBvdmVyIGRpZmZlcmVudCBwYXJ0cyBvZiBVUy5Cb3RoIHRoZSBkYXRhc2V0cyBhcmUgdmVyeSBsYXJnZSBkYXRhc2V0IC5JIHRyaWVkIHRvIGltcGxlbWVudHMgYWxsIGtleSBjb25jZXB0cyBvZiBEYXRhIFdyYW5nbGluZyBsaWtlIHRpZHlpbmcgdGhlIG1lc3N5IGRhdGEgLGNyZWF0aW5nIG5ldyB2YXJpYWJsZXMgdXNpbmcgbXV0YXRlICxzY2FubmluZyBtaXNzaW5nIHZhbHVlcyAsb3V0bGllcnMgLGFwcGx5aW5nIHRyYW5zZm9ybWF0aW9ucyBhbmQgdmlzdWFsaXphdGlvbi4NCg0KDQojIyBSZXF1aXJlZCBwYWNrYWdlcyANCg0KDQpgYGB7cn0NCiMgVGhpcyBpcyB0aGUgUiBjaHVuayBmb3IgdGhlIHJlcXVpcmVkIHBhY2thZ2VzDQoNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KEhtaXNjKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoSG1pc2MpDQpsaWJyYXJ5KG91dGxpZXJzKQ0KbGlicmFyeShmb3JlY2FzdCkNCmxpYnJhcnkoZ2RhdGEpDQpsaWJyYXJ5KHJ2ZXN0KQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoY2FyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KDQpgYGANCg0KIyMgRXhlY3V0aXZlIFN1bW1hcnkgDQoNClRoaXMgcmVwb3J0IGhhcyBiZWVuIHByZXBhcmVkIGJ5IGFuYWx5emluZyBOb3ZlbCBDb3JvbmFWaXJ1cyBjYXNlcyBmb3IgY291bnRyeSBVUy5JIGhhdmUgdXNlZCBkYXRhc2V0cyBmcm9tIEthZ2dsZS4gRmlyc3QgZGF0YXNldCBpcyB0aGUgY292aWQgZGFpbHkgY2FzZXMgb2YgVVMgYW5kIFNlY29uZCBkYXRhc2V0IGlzIGRldGFpbHMgb2YgYXZhbGFiaWxpdHkgb2YgaG9zcGl0YWxzIGJlZHMgYW5kIHJlbGF0ZWQgZGF0YSBpbiBVUyAuTWVyZ2luZyB0d28gZGF0YXNldCAsIGFuZCBzZWxlY3Rpbmcgc29tZSBvZiB0aGUgaW1wb3J0YW50IGNvbHVtbnMgLEkgaGF2ZSBhcHBsaWVkIGFsbCB3cmFuZ2xpbmcgdGVjaG5pcXVlcy5BcyB0aGUgZGF0YSBoYXMgYmVlbiBjb2xsZWN0ZWQgZnJvbSBkaWZmZXJlbnQgc291cmNlcyxpbiB2YXJpb3VzIHNoYXBlcyBhbmQgZm9ybXMsdGhlcmVmb3JlIGl0IGlzIG5lY2Vzc2FyeSB0byBhcHBseSByZWxldmFudCBtZXRob2RzIHRvIHByZXBhcmUgdGhlIGNvbGxlY3Rpb24gb2YgZGF0YSBieSB1c2luZyBwcmUtcHJvY2Vzc2luZyB0ZWNobmlxdWVzIGJlZm9yZSBhbmFseXppbmcgYW5kIHZpc3VhbGl6aW5nIGl0Lg0KDQpGaXJzdCBkYXRhc2V0ICd1c19zdGF0ZXNfY292aWQxOV9kYWlseS5jc3YnIGNvbnRhaW5zIG1pc3NpbmcgdmFsdWVzIHdoZXJlYXMgc2Vjb25kIGRhdGFzZXQgJ2hvc3BpdGFsX2JlZHNfVVNBX3YxLmNzdicgZG9lcyBub3QgY29udGFpbiBhbnkgbWlzc2luZyB2YWx1ZXMuDQpUaGUgZm9sbG93aW5nIHN0ZXBzIGhhcyBiZWVuIGltcGxlbWVudGVkIGZvciB0aGlzIGVudGlyZSBhc3NpZ25tZW50Og0KDQotPiBEb3dubG9hZCBkYXRhc2V0cyBpbnRvIFJNYXJrZG93bg0KDQotPiBNZXJnaW5nIHR3byBkYXRhc2V0cy4NCg0KLT4gU2VsZWN0aW5nIHRoZSBjb2x1bW5zIGZyb20gdGhlIG1lcmdlZCBkYXRhc2V0IHdoaWNoIGFyZSByZXF1aXJlZCB0byBjYXJyeSBvdXQgZnVydGhlciBhc3NpZ25tZW50Lg0KDQotPiBEYXRhIHR5cGUgY29udmVyc2lvbnMgbGlrZSBjb252ZXJ0aW5nIGNoYXJhY3RlcnMgdG8gZmFjdG9ycy4NCg0KLT4gVGlkeWluZyB1cCBkYXRhOg0KDQoxLiBSZXNoYXBpbmcgdGhlIGRhdGEgdG8geWllbGQgcHJvcGVyIGZvcm1hdC4NCjIuIE11dGF0ZSB0byB5aWVsZCB0d28gbmV3IGNvdWxtbiAtIHBlcmNlbnRhZ2Ugb2YgcG9zaXRpdmUgY292aWQgY2FzZXMgYW5kIHBlcmNlbnRhZ2Ugb2YgbmVnYXRpdmUgY292aWQgY2FzZXMNCg0KLT4gU2Nhbm5pbmc6IA0KDQoxLiBtaXNzaW5nIHZhbHVlcyBhbmQgaGFuZGxpbmcgdGhlbS4NCjIuIHNwZWNpYWwgdmFsdWVzDQozLiBpbmNvbnNpc3RlbmNpZXMgb3Igb2J2aW91cyBlcnJvcnMgDQo0LiBPdXRsaWVycyB1c2luZyBCb3hwbG90IGFuZCBvdGhlciBhcHByb3ByaWF0ZSBSIGZ1bmN0aW9uIGhhbmRsZSBpdC4gDQoNCi0+IFRyYW5zZm9ybWF0aW9uIHVzaW5nIGFwcHJvcHJpYXRlIFIgZnVuY3Rpb24NCg0KIyMgRGF0YSANCg0KDQpGaXJzdCBkYXRhc2V0ICd1c19zdGF0ZXNfY292aWQxOV9kYWlseS5jc3YnIGNvbnRhaW5zIHN0YXRlIHdpc2UgYW5kIGRhdGUgd2lzZSAgZGFpbHkgY292aWQgY2FzZXMgY291bnRzLGNvbmZpcm1lZCBkZWF0aHMscG9zaXRpdmUgY2FzZXMgYW5kIG90aGVyIGNvdWxtbnMgd2hpY2ggZ2l2ZXMgYSBjb21wcmVoZW5zaXZlIGRldGFpbHMgb2YgY292aWQgY2FzZXMgaW4gVVNBIGZvciBhbGwgc3RhdGVzLkl0IGNvbnNpc3RzIG9mIDU0IGNvdWxtbnMgLlNvbWUgb2YgdGhlIGNvbHVtbnMgY29udGFpbnMgbWlzc2luZyB2YWx1ZXMgYW5kIGlzIHVudGlkeSBkYXRhc2V0LiANClNlY29uZCBkYXRhc2V0ICdob3NwaXRhbF9iZWRzX1VTQV92MS5jc3YnIGNvbnRhaW5zIGRldGFpbHMgb2YgdHlwZXMgb2YgYmVkcyAsbnVtYmVyIG9mIGJlZHMgLHBvcHVsYXRpb24gYW5kIG90aGVycyAgaW1wb3J0YW50IHZhcmlhYmxlcyB3aXRoIHN0YXRlIHdpc2UgZGV0YWlscyBvZiBob3NwaXRhbHMgaW4gVVMuIFRoaXMgZGF0YXNldCBjb250YWlucyAxMiBjb3VsbW5zIC5UaGVyZSBhcmUgbm8gbWlzc2luZyBkYXRhIGluIHRoaXMgZGF0YXNldC4NCkJvdGggdGhlIGRhdGFzZXRzIGhhcyBiZWVuIG1lcmdlZCB1c2luZyBsZWZ0IGpvaW4gYnkgc3RhdGUuUGxlYXNlIGZpbmQgdGhlIGxpbmtzIG9mIHR3byBkYXRhc2V0IGJlbG93Lg0KDQogaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9zdWRhbGFpcmFqa3VtYXIvY292aWQxOS1pbi11c2E/c2VsZWN0PXVzX3N0YXRlc19jb3ZpZDE5X2RhaWx5LmNzdiANCg0KIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vaWtpdWxpYW4vZ2xvYmFsLWhvc3BpdGFsLWJlZHMtY2FwYWNpdHktZm9yLWNvdmlkMTk/c2VsZWN0PWhvc3BpdGFsX2JlZHNfVVNBX3YxLmNzdg0KDQoNCmBgYHtyfQ0KDQojIEZpcnN0IGRhdGFzZXQNCg0KVVNfY292aWRfZGF0YSA8LSByZWFkX2NzdigidXNfc3RhdGVzX2NvdmlkMTlfZGFpbHkuY3N2IikNCmhlYWQoVVNfY292aWRfZGF0YSkNCmBgYA0KDQoNCmBgYHtyfQ0KIyBzZWNvbmQgZGF0YXNldA0KDQpob3NwaXRhbF9iZWRzX1VTQV92MSA8LSByZWFkX2NzdigiaG9zcGl0YWxfYmVkc19VU0FfdjEuY3N2IikNCmhlYWQoaG9zcGl0YWxfYmVkc19VU0FfdjEpDQpgYGANCg0KIyMgVW5kZXJzdGFuZCANCg0KRmlyc3QgSSBtZXJnZWQgdHdvIGFib3ZlIGRhdGFzZXQgdXNpbmcgbGVmdCBqb2luIGJ5IHN0YXRlLlRoZSBuZXh0IHN0ZXBzIEkgdG9vayBpcyB0byBzZWxlY3QgdGhlIGNvbHVtbnMgd2l0aCB3aGljaCBJIHdhbnQgdG8gd29yayBmcm9tIHRoZSBtZXJnZWQgZGF0YXNldC5UaGVyZWZvcmUgSSBoYXZlIGZpbHRlcmVkIG91dCB0aGUgcmVxdWlyZWQgY29sdW1ucyB1c2luZyBzZWxlY3QgZnVuY3Rpb24gd2hpY2ggaXMgYSBwYXJ0IG9mIGRwbHlyIHBhY2thZ2UuVG90YWwgMTggY29sdW1ucyBoYXZlIGJlZW4gc2VsZWN0ZWQuQWxzbyB0aGUgZGF0YXNldCBzZWVtcyB0byBoYXZlIHZlcnkgbGFyZ2UgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyAsc28gSSBoYXZlIGRlY2lkZWQgdG8gd29yayB3aXRoIDc1MDAwIG9ic2VydmF0aW9ucy4NCg0KQWZ0ZXIgc2VsZWN0aW9uIG9mIHJlcXVpcmVkIGNvbHVtbnMsIEkgaGF2ZSBjaGVja2VkIGRhdGEgdHlwZXMgb2YgY29sdW1ucy4gRGF0YXNldCBoYXZlIHZhcmlvdXMgZGF0YXR5cGVzIGxpa2UgY2hhcmFjdGVyLG51bWVyaWMuIEkgZm91bmQgc29tZSBjb2x1bW5zIGFyZSBpbiBjaGFyYWN0ZXJzIHdoaWNoIG5lZWRzIHRvIGJlIGNvbnZlcnRlZCBpbnRvIGZhY3Rvci4gVGhlcmVmb3JlIEkgY29udmVydGVkIHRoZW0gaW50byBmYWN0b3JzIGJ5IHByb3ZpZGluZyBsYWJlbHMgYW5kIGxldmVscy4NClRoZSBzdHJ1Y3R1cmUgb2YgZmlsdGVyZWQgbWVyZ2VkIGRhdGFzZXQgYWZ0ZXIgc2VsZWN0aW5nIHJlcXVpcmVkIGNvbHVtbnMgaGF2ZSBiZWVuIHN0dWRpZWQgdXNpbmcgc3RyKCkuDQoNCg0KYGBge3J9DQojIFRoaXMgaXMgdGhlIFIgY2h1bmsgZm9yIHRoZSBVbmRlcnN0YW5kIFNlY3Rpb24NCg0KI01FUkdFDQoNCm1lcmdlZCA8LSBsZWZ0X2pvaW4oIGhvc3BpdGFsX2JlZHNfVVNBX3YxICwgVVNfY292aWRfZGF0YSAsIGJ5ID0ic3RhdGUiICkNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCiMgU0VMRUNUIE9OTFkgUkVRVUlSRUQgQ09MVU1OUyBGUk9NIE1FUkdFRCBEQVRBU0VUDQoNCg0KZmlsdGVyZWRfbWVyZ2VkIDwtbWVyZ2VkICU+JSBzZWxlY3QoY291bnRyeSxzdGF0ZSx0eXBlLG1lYXN1cmUsYmVkcyxwb3B1bGF0aW9uLHllYXIsZGF0ZSAscG9zaXRpdmUgLG5lZ2F0aXZlLHRvdGFsVGVzdFJlc3VsdHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3NwaXRhbGl6ZWRDdXJyZW50bHksaW5JY3VDdXJyZW50bHksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvblZlbnRpbGF0b3JDdXJyZW50bHksIHJlY292ZXJlZCxkZWF0aCAsaG9zcGl0YWxpemVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGhDb25maXJtZWQgKQ0KDQojIHRha2UgNzUwMDAgb2JzZXJ2YXRpb24gZnJvbiBsYXJnZSBkYXRhc2V0DQoNCmZpbHRlcmVkX21lcmdlZCA8LSBmaWx0ZXJlZF9tZXJnZWQgWzE6NzUwMDAgLF0NCg0KDQpzdHIoZmlsdGVyZWRfbWVyZ2VkKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiNEQVRBIFRZUEUgQ09OVkVSU0lPTg0KDQpmaWx0ZXJlZF9tZXJnZWQkdHlwZSA8LWZhY3RvcihmaWx0ZXJlZF9tZXJnZWQkdHlwZSwgbGV2ZWxzPSBjKCJBQ1VURSIgLCAiSUNVIiAsIk9USEVSIiAsIlBTWUNISUFUUklDIikgLGxhYmVscz1jKCJBQ1VURSIgLCAiSUNVIiAsIk9USEVSIiAsIlBTWUNISUFUUklDIikgLG9yZGVyZWQ9VFJVRSkNCmxldmVscyhmaWx0ZXJlZF9tZXJnZWQkdHlwZSkNCg0KDQpmaWx0ZXJlZF9tZXJnZWQkc3RhdGUgPC0gYXMuZmFjdG9yKGZpbHRlcmVkX21lcmdlZCRzdGF0ZSkNCmxldmVscyhmaWx0ZXJlZF9tZXJnZWQkc3RhdGUpDQoNCg0KZmlsdGVyZWRfbWVyZ2VkJG1lYXN1cmUgPC0gYXMuZmFjdG9yKGZpbHRlcmVkX21lcmdlZCRtZWFzdXJlKQ0KbGV2ZWxzKGZpbHRlcmVkX21lcmdlZCRtZWFzdXJlKQ0KDQpmaWx0ZXJlZF9tZXJnZWQkY291bnRyeSA8LSBhcy5mYWN0b3IoZmlsdGVyZWRfbWVyZ2VkJGNvdW50cnkpDQpsZXZlbHMoZmlsdGVyZWRfbWVyZ2VkJGNvdW50cnkpDQoNCg0KYGBgDQoNCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIA0KDQoNCkRhdGFzZXQgJ2ZpbHRlcmVkX21lcmdlZCcgd2hpY2ggd2FzIGZvcm1lZCBhZnRlciBtZXJnaW5nIHR3byBkYXRhc2V0IGFuZCBzZWxlY3Rpb24gcmVxdWlyZWQgY29sdW1ucyB3YXMgZm91bmQgdG8gYmUgaW4gaW1wcm9wZXIgZm9ybWF0IGFuZCBoYXZlIG1hbnkgbWlzc2luZyB2YWx1ZXMuU2Vjb25kbHkgSSBhaW0gdG8gZmluZCBvdXQgY292aWQgY2FzZXMgZGV0YWlscyBhbG9uZyB3aXRoIGhvc3BpdGFsIGJlZHMgZGV0YWlscyBmb3IgZWFjaCBzdGF0ZXMuSSBoYXZlIGZvdW5kIG11bHRpcGxlIHZhcmlhYmxlcyBsaWtlIGhvc3BpdGFsIGJlZCB0eXBlcyBoYXZlIGJlZW4gc3RvcmVkIGluIHJvd3MgLlRoZXNlIHR5cGVzIG5lZWRzIHRvIGJlIGNvbnZlcnRlZCBpbnRvIGNvbHVtbnMgc28gdGhhdCB3ZSBjYW4ga25vdyB0aGUgY291bnRzIG9mIGVhY2ggdHlwZSBvZiBiZWQuVGhhdCBpcyB3aHkgSSBoYXZlIHVzZWQgc3ByZWFkKCkgZnVuY3Rpb24gdG8gd2lkZSBmb3JtYXQgYnkgZ2VuZXJhdGluZyBuZXcgY29sdW1ucyBmcm9tICd0eXBlJyBjb2x1bW4gLlRoZSBjb2x1bW5zIHNvIGZvcm1lZCBhZnRlciByZXNoYXBpbmcgYXJlICdBQ1VURScgLCdJQ1UnLCdPVEhFUicsJ1BTWUNISUFUUklDJy4gVGhpcyByZXNoYXBlZCBjb2x1bW5zICB3aWxsIGdpdmUgdGhlIGNvdW50cyBvZiBkaWZmZXJlbnQgdHlwZXMgb2YgYmVkcyBhdmFpbGFibGUgaW4gZGlmZmVyZW50IHN0YXRlcyBvZiBVUyAuIA0KDQoNCmBgYHtyfQ0KIyBUaGlzIGlzIHRoZSBSIGNodW5rIGZvciB0aGUgVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIA0KDQojUkVTSEFQRQ0KDQpyZXNoYXBlX2NvdmlkX2RhdGEgPC1zcHJlYWQoZmlsdGVyZWRfbWVyZ2VkICxrZXkgPXR5cGUgICx2YWx1ZSA9YmVkcykNCmhlYWQocmVzaGFwZV9jb3ZpZF9kYXRhKQ0KDQpgYGANCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJSSANCg0KDQpJIGhhdmUgY3JlYXRlZCB0d28gbmV3IGNvbHVtbnMgdXNpbmcgbXV0YXRlKCkgZnVuY3Rpb24gd2hpY2ggaXMgYSBwYXJ0IG9mIGRwbHlyIHBhY2thZ2UuDQoNCi1UaGUgZmlyc3QgbmV3IGNvbHVtbiBpcyB0aGUgcGVyY2VudGFnZSBvZiBwb3NpdGl2ZSBjb3ZpZCBjYXNlcyB3aGljaCBoYXMgYmVlbiBjYWxjdWxhdGVkIHVzaW5nIGZvcm11bGEgOiAocG9zaXRpdmUgdGVzdGVkIGNhc2VzIC8gdG90YWwgdGVzdGVkIGNhc2VzKSAqMTAwIC4NCg0KLVRoZSBzZWNvbmQgbmV3IGNvbHVtbiBpcyB0aGUgcGVyY2VudGFnZSBvZiBuZWdhdGl2ZSBjb3ZpZCBjYXNlcyB3aGljaCB1c2VzIHRoZSBmb3JtdWxhIDogKG5lZ2F0aXZlIHRlc3RlZCBjYXNlcyAvIHRvdGFsIHRlc3RlZCBjYXNlcykgKjEwMCAuDQoNCmBgYHtyfQ0KIyBUaGlzIGlzIHRoZSBSIGNodW5rIGZvciB0aGUgVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJSSANCg0KI01VVEFURQ0KDQojIGNyZWF0ZSBuZXcgY29sdW1uIHdpdGggcGVyY2VudGFnZSBvZiBwb3NpdGl2ZSBjb3ZpZCBjYXNlID0gKG5lZ2F0aXZlIC90b3RhbFRlc3RSZXN1bHRzKSoxMDANCg0KcmVzaGFwZV9jb3ZpZF9kYXRhIDwtcmVzaGFwZV9jb3ZpZF9kYXRhICU+JSBtdXRhdGUoUG9zaXRpdmVfY2FzZV9wZXJjZW50YWdlID0gKHBvc2l0aXZlIC90b3RhbFRlc3RSZXN1bHRzKSoxMDAgKQ0KDQoNCiMgY3JlYXRlIG5ldyBjb2x1bW4gd2l0aCBwZXJjZW50YWdlIG9mIG5lZ2F0aXZlIGNvdmlkIGNhc2UgPSAobmVnYXRpdmUgL3RvdGFsVGVzdFJlc3VsdHMpKjEwMA0KDQpyZXNoYXBlX2NvdmlkX2RhdGEgPC1yZXNoYXBlX2NvdmlkX2RhdGEgJT4lIG11dGF0ZShOZWdhdGl2ZV9jYXNlX3BlcmNlbnRhZ2UgPSAobmVnYXRpdmUgL3RvdGFsVGVzdFJlc3VsdHMpKjEwMCApDQoNCiMgQWZ0ZXIgbXV0YXRlDQoNCmhlYWQocmVzaGFwZV9jb3ZpZF9kYXRhKQ0KDQpgYGANCg0KDQoNCiMjCVNjYW4gSSANCg0KRmlyc3QgcGhhc2Ugb2Ygc2Nhbm5pbmcgaW52b2x2ZXMgU2NhbiBvZiB0aGUgZGF0YSBmb3IgbWlzc2luZyB2YWx1ZXMsIHNwZWNpYWwgdmFsdWVzIGFuZCBvYnZpb3VzIGVycm9ycyAoaS5lLiBpbmNvbnNpc3RlbmNpZXMpLiANCg0KMS5GaXJzdCBJIGNoZWNrZWQgZm9yIG1pc3NpbmcgdmFsdWVzIGZyb20gb3JpZ2luYWwgdHdvIGRhdGFzZXRzIGFuZCB0aGVuIG1lcmdlZCBmaWx0ZXJlZCBkYXRhc2V0LiBXZSBmb3VuZCBzb21lIGNvbHVtbnMgd2l0aCBtaXNzaW5nIHZhbHVlcy4NCg0KMi5JbXB1dGluZyBzb21lIG9mIHRoZSBjb2x1bW5zIGxpa2UgQUNVVEUgLElDVSxPVEhFUiAsUFNZQ0hJQVRSSUMgd2l0aCBtZWFuIHZhbHVlIHVzaW5nIGltcHV0ZSgpIHdoaWNoIGlzIGEgcGFydCBvZiBIbWlzYyBwYWNrYWdlLkFzc3VtaW5nIGFzIG51bWJlcnMgb2YgbWlzc2luZyBpcyBoaWdoIHNvIGltcHV0aW5nIHdpdGggbWVhbiB2YWx1ZSB3b3VsZCBlbnN1cmUgY29uc2lzdGVuY3kgYW5kIHdpbGwgcmVkdWNlIG92ZXJhbGwgdmFyaWFuY2UuDQpGb3Igb3RoZXIgbWlzc2luZyBjb2x1bW5zLCBJIGhhdmUgcmVwbGFjZWQgdGhlIG1pc3NpbmcgdmFsdWVzIHdpdGggbWVhbiBvZiB0aGF0IGNvbHVtbiB3aXRoIG1lYW4oKSBzbyBhcyB0byByZXRhaW4gb3ZlcmFsbCBjb25zaXN0ZW50IGRhdGEuDQoNCjMuTmV4dCBzdGVwIHdhcyB0byBjaGVjayBmb3Igc3BlY2lhbCB2YWx1ZXMgbGlrZSBpbmZpbml0ZSB2YWx1ZXMgLG5hbiB2YWx1ZXMgb3IgbnVtZXJpYyB2YWx1ZXMuIE5vbmUgb2YgdGhlIGNvbHVtbnMgaGFzIGJlZW4gZm91bmQgd2l0aCBzcGVjaWFsIHZhbHVlcy4NCg0KNC5GaW5hbGx5IEkgY2hlY2tlZCBmb3IgYW55IGluY29uc2lzdGVuY2llcyBhbmQgZXJyb3Igc3VjaCBhcyBuZWdhdGl2ZSB2YWx1ZXMgaW4gY29sdW1ucy4gTm8gc3VjaCBjb2x1bW5zIGhhcyBiZWVuIGZvdW5kIHdpdGggc3VjaCBjcml0ZXJpYS4NCg0KDQpgYGB7cn0NCiMgVGhpcyBpcyB0aGUgUiBjaHVuayBmb3IgdGhlIFNjYW4gSQ0KDQoNCiNTY2FubmluZyBmb3IgbWlzc2luZyB2YWx1ZXMNCg0KDQphbnkoaXMubmEocmVzaGFwZV9jb3ZpZF9kYXRhKSkNCg0KY29sU3Vtcyhpcy5uYShyZXNoYXBlX2NvdmlkX2RhdGEpKQ0KDQpgYGANCg0KYGBge3J9DQoNCiMgQWN0aW9uIG9uIG1pc3NpbmcgdmFsdWVzIG9uIHJlZmluZWQgbWVyZ2VkIGRhdGENCg0KDQpyZXNoYXBlX2NvdmlkX2RhdGEkQUNVVEUgPC0gaW1wdXRlKHJlc2hhcGVfY292aWRfZGF0YSRBQ1VURSwgZnVuID0gbWVhbikgDQoNCnJlc2hhcGVfY292aWRfZGF0YSRJQ1UgPC0gaW1wdXRlKHJlc2hhcGVfY292aWRfZGF0YSRJQ1UsIGZ1biA9IG1lYW4pIA0KDQpyZXNoYXBlX2NvdmlkX2RhdGEkT1RIRVIgPC0gaW1wdXRlKHJlc2hhcGVfY292aWRfZGF0YSRPVEhFUiwgZnVuID0gbWVhbikgDQoNCnJlc2hhcGVfY292aWRfZGF0YSRQU1lDSElBVFJJQyA8LSBpbXB1dGUocmVzaGFwZV9jb3ZpZF9kYXRhJFBTWUNISUFUUklDLCBmdW4gPSBtZWFuKSANCg0KcmVzaGFwZV9jb3ZpZF9kYXRhJG5lZ2F0aXZlW2lzLm5hKHJlc2hhcGVfY292aWRfZGF0YSRuZWdhdGl2ZSldIDwtIG1lYW4ocmVzaGFwZV9jb3ZpZF9kYXRhJG5lZ2F0aXZlICxuYS5ybSA9IFRSVUUpDQoNCnJlc2hhcGVfY292aWRfZGF0YSRob3NwaXRhbGl6ZWRDdXJyZW50bHlbaXMubmEocmVzaGFwZV9jb3ZpZF9kYXRhJGhvc3BpdGFsaXplZEN1cnJlbnRseSldIDwtIG1lYW4ocmVzaGFwZV9jb3ZpZF9kYXRhJGhvc3BpdGFsaXplZEN1cnJlbnRseSAsbmEucm0gPSBUUlVFKQ0KDQpyZXNoYXBlX2NvdmlkX2RhdGEkaW5JY3VDdXJyZW50bHlbaXMubmEocmVzaGFwZV9jb3ZpZF9kYXRhJGluSWN1Q3VycmVudGx5KV0gPC0gbWVhbihyZXNoYXBlX2NvdmlkX2RhdGEkaW5JY3VDdXJyZW50bHkgLG5hLnJtID0gVFJVRSkNCg0KcmVzaGFwZV9jb3ZpZF9kYXRhJG9uVmVudGlsYXRvckN1cnJlbnRseVtpcy5uYShyZXNoYXBlX2NvdmlkX2RhdGEkb25WZW50aWxhdG9yQ3VycmVudGx5KV0gPC1tZWFuKHJlc2hhcGVfY292aWRfZGF0YSRvblZlbnRpbGF0b3JDdXJyZW50bHkgLG5hLnJtID0gVFJVRSkNCg0KcmVzaGFwZV9jb3ZpZF9kYXRhJHJlY292ZXJlZFtpcy5uYShyZXNoYXBlX2NvdmlkX2RhdGEkcmVjb3ZlcmVkKV0gPC0gbWVhbihyZXNoYXBlX2NvdmlkX2RhdGEkcmVjb3ZlcmVkICxuYS5ybSA9IFRSVUUpDQoNCnJlc2hhcGVfY292aWRfZGF0YSRob3NwaXRhbGl6ZWRbaXMubmEocmVzaGFwZV9jb3ZpZF9kYXRhJGhvc3BpdGFsaXplZCldIDwtIG1lYW4ocmVzaGFwZV9jb3ZpZF9kYXRhJGhvc3BpdGFsaXplZCxuYS5ybSA9IFRSVUUpDQoNCnJlc2hhcGVfY292aWRfZGF0YSRkZWF0aFtpcy5uYShyZXNoYXBlX2NvdmlkX2RhdGEkZGVhdGgpXSA8LW1lYW4ocmVzaGFwZV9jb3ZpZF9kYXRhJGRlYXRoICxuYS5ybSA9IFRSVUUpDQoNCnJlc2hhcGVfY292aWRfZGF0YSRkZWF0aENvbmZpcm1lZFtpcy5uYShyZXNoYXBlX2NvdmlkX2RhdGEkZGVhdGhDb25maXJtZWQpXSA8LSBtZWFuKHJlc2hhcGVfY292aWRfZGF0YSRkZWF0aENvbmZpcm1lZCAsbmEucm0gPSBUUlVFKQ0KDQpyZXNoYXBlX2NvdmlkX2RhdGEkTmVnYXRpdmVfY2FzZV9wZXJjZW50YWdlW2lzLm5hKHJlc2hhcGVfY292aWRfZGF0YSROZWdhdGl2ZV9jYXNlX3BlcmNlbnRhZ2UpXSA8LW1lYW4ocmVzaGFwZV9jb3ZpZF9kYXRhJE5lZ2F0aXZlX2Nhc2VfcGVyY2VudGFnZSxuYS5ybSA9IFRSVUUpDQoNCnJlc2hhcGVfY292aWRfZGF0YSRQb3NpdGl2ZV9jYXNlX3BlcmNlbnRhZ2VbaXMubmEocmVzaGFwZV9jb3ZpZF9kYXRhJFBvc2l0aXZlX2Nhc2VfcGVyY2VudGFnZSldIDwtbWVhbihyZXNoYXBlX2NvdmlkX2RhdGEkUG9zaXRpdmVfY2FzZV9wZXJjZW50YWdlLG5hLnJtID0gVFJVRSkNCg0KY29sU3Vtcyhpcy5uYShyZXNoYXBlX2NvdmlkX2RhdGEpKQ0KDQpgYGANCmBgYHtyfQ0KDQojQ2hlY2sgIGZvciBzcGVjaWFsIHZhbHVlcw0KDQojRGVmaW5lIGZ1bmN0aW9uIA0Kc3BlY2lhbF92YWx1ZXMgPC0gZnVuY3Rpb24oeCl7DQogIGlmIChpcy5udW1lcmljKHgpKSAoaXMuaW5maW5pdGUoeCkgfCBpcy5uYW4oeCkpDQp9DQoNCnNwX3ZhbHVlPC1zYXBwbHkocmVzaGFwZV9jb3ZpZF9kYXRhLCBGVU4gPSBzcGVjaWFsX3ZhbHVlcykNCg0Kc2FwcGx5KHJlc2hhcGVfY292aWRfZGF0YSwgZnVuY3Rpb24oeCl7aWYgKGlzLm51bWVyaWMoeCkpIHN1bShzcGVjaWFsX3ZhbHVlcyh4KSl9KQ0KDQpgYGANCmBgYHtyfQ0KIyNDaGVjayAgZm9yIGluY29uc2lzdGVuY2llcyBvciBvYnZpb3VzIGVycm9ycyBmb3IgbnVtZXJpY2FsIGNvbHVtbnMNCg0Kbm9ubmVnYXRpdmU8LSBmdW5jdGlvbih4KXt4PDB9DQoNCm5vbm5lZ2F0aXZlX3ZhbHVlczwtc2FwcGx5KHJlc2hhcGVfY292aWRfZGF0YVssNzoyMl0sIEZVTiA9IG5vbm5lZ2F0aXZlKQ0KDQpjb2xTdW1zKG5vbm5lZ2F0aXZlX3ZhbHVlcykNCg0KYGBgDQoNCiMJU2NhbiBJSQ0KDQpOZXh0IHBoYXNlIG9mIHNjYW5uaW5nIGludm9sdmVzIGRldGVjdGluZyBvdXRsaWVycyBhbmQgaG93IHRvIGhhbmRsZSB0aGVtLiBBcyB0aGUgZGF0YXNldCBpcyB2ZXJ5IGxhcmdlICx0aGVyZWZvcmUgdGhlcmUgYXJlIHBvc3NpYmlsaXRpZXMgb2YgbGFyZ2UgbnVtYmVyIG9mIG91dGxpZXJzLg0KDQoxLiBGaXJzdCBJIGhhdmUgdGFrZW4gc3Vic2V0cyBmcm9tIGFib3ZlIGRhdGFzZXQgYnkgdGFraW5nIHNvbWUgb2YgdGhlIG51bWVyaWNhbCBjb2x1bW5zIHRvIGRvIGEgYmV0dGVyIHZpc3VhbCBpbnNwZWN0aW9uIG9mIG91dGxpZXJzIGFuZCBsYXRlciB0cmFuc2Zvcm1hdGlvbnMuDQoNCjIuIFRoZW4gSSBjaGVja2VkIGZvciBvdXRsaWVycyB1c2luZyBib3hwbG90LkkgZm91bmQgY29sdW1ucyAncmVjb3ZlcmVkJywncG9zaXRpdmUsJ2RlYXRoJyBhbmQgJ2hvc3BpdGFsaXplZEN1cnJlbnRseScgaGF2ZSBmZXcgb3V0bGllcnMgaW4gaXQuDQoNCjMuICBDYXBwaW5nIG9yIHdpbnNvcmlzaW5nIGludm9sdmVzIHJlcGxhY2luZyB0aGUgb3V0bGllcnMgd2l0aCB0aGUgbmVhcmVzdCBuZWlnaGJvdXJzIHRoYXQgYXJlIG5vdCBvdXRsaWVycyBpbnN0ZWFkIG9mIHJlbW92aW5nIG91dGxpZXJzLlNpbmNlIGl0IGlzIG5vdCBhbHdheXMgbmVjZXNzYXJ5IHRoYXQgb3V0bGllcnMgYXJlIGdlbmVyYXRlZCBiZWNhdXNlIG9mIGVycm9ycyAuU29tZXRpbWVzIG91dGxpZXJzIGNhbiBiZSBsZWdpdGltYXRlIG9ic2VydmF0aW9ucy5Gb3IgZXhhbXBsZSBwb3NpdGl2ZSBvciBkZWF0aCBoYXZlIG91dGxpZXIgbWlnaHQgbWVhbiB0aGF0IHBvc2l0aXZlIGNvdmlkIGNhc2VzIG9yIGNvdmlkIGRlYXRoIGNhc2VzIGFyZSBoaWdoLiBUaGVyZWZvcmUgSSBkZWNpZGVkIHRvIHVzZSBjYXAoKSBpbnN0ZWFkIG9mIHJlbW92aW5nIG91dGxpZXJzLg0KDQo0LiBJIGNyZWF0ZWQgY2FwKCkgZnVuY3Rpb24gdG8gcmVwbGFjZSB0aG9zZSBkYXRhIHBvaW50cyBseWluZyBvdXRzaWRlIHRoZSBsb3dlciBsaW1pdCBhbmQgYWJvdmUgdGhlIHVwcGVyIGxpbWl0IHdpdGggdGhlIHZhbHVlIG9mIDV0aCBwZXJjZW50aWxlIGFuZCA5NXRoIHBlcmNlbnRpbGUuDQoNCjUuIFN1bW1hcnkgb2YgdGhlIHN1YnNldCBkYXRhIGhhcyBiZWVuIGNvbXB1dGVkIGJlZm9yZSBhbmQgYWZ0ZXIgY2FwcGluZyAuDQoNCg0KIyMJU2NhbiBPdXRsaWVycw0KYGBge3J9DQojc3Vic2V0IG51bWVyaWNhbCBjb2x1bW5zIGludG8gZGF0YXNldA0KDQpjb3ZpZF9zdWJzZXQ8LSByZXNoYXBlX2NvdmlkX2RhdGEgJT4lIHNlbGVjdCggcG9zaXRpdmUgLG5lZ2F0aXZlICx0b3RhbFRlc3RSZXN1bHRzLGhvc3BpdGFsaXplZEN1cnJlbnRseSAscmVjb3ZlcmVkICxQb3NpdGl2ZV9jYXNlX3BlcmNlbnRhZ2UgLGRlYXRoKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQoNCiNDSEVDSyBPVVRMSUVSUyBVU0lORyBCT1hQTE9UUw0KDQojIGJveHBsb3QgZm9yIGZpbmRpbmcgb3V0bGllcnMNCg0KDQpwYXIobWZyb3c9YygxLDIpKQ0KDQpib3hwbG90KGNvdmlkX3N1YnNldCRyZWNvdmVyZWQgLG1haW4gPSJyZWNvdmVyZWQgY2FzZXMiKQ0KZ3JpZChjb2wgPSAiZ3JleSIpDQoNCmJveHBsb3QoY292aWRfc3Vic2V0JHBvc2l0aXZlICxtYWluID0icG9zaXRpdmUgY2FzZXMiKQ0KZ3JpZChjb2wgPSAiZ3JleSIpDQoNCmJveHBsb3QoY292aWRfc3Vic2V0JGhvc3BpdGFsaXplZEN1cnJlbnRseSAsbWFpbiA9Imhvc3BpdGFsaXplZEN1cnJlbnRseSBjYXNlcyIpDQpncmlkKGNvbCA9ICJncmV5IikNCg0KYm94cGxvdChjb3ZpZF9zdWJzZXQkZGVhdGggLG1haW4gPSJkZWF0aCBjYXNlcyIpDQpncmlkKGNvbCA9ICJncmV5IikNCg0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQojQ0FQUElORw0KDQoNCmNhcCA8LSBmdW5jdGlvbih4KXsNCiAgcXVhbnRpbGVzIDwtIHF1YW50aWxlKCB4LCBjKC4wNSwgMC4yNSwgMC43NSwgLjk1ICkgKQ0KICB4WyB4IDwgcXVhbnRpbGVzWzJdIC0gMS41KklRUih4KSBdIDwtIHF1YW50aWxlc1sxXQ0KICB4WyB4ID4gcXVhbnRpbGVzWzNdICsgMS41KklRUih4KSBdIDwtIHF1YW50aWxlc1s0XQ0KICB4DQp9DQoNCiNEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIG9mIHRoZSBzdWJzZXQNCg0Kc3VtbWFyeShjb3ZpZF9zdWJzZXQpDQoNCg0KI0FwcGx5aW5nIGNhcCgpIHRvIHRoZSBudW1lcmljIHZhcmlhYmxlcw0KDQpwb3NpdGl2ZV9jYXBwZWQgPC0gY292aWRfc3Vic2V0JHBvc2l0aXZlICU+JWNhcCgpDQoNCnJlY292ZXJlZF9jYXBwZWQ8LSBjb3ZpZF9zdWJzZXQkcmVjb3ZlcmVkICU+JSBjYXAoKQ0KDQpob3NwaXRhbGl6ZWRfY2FwcGVkIDwtIGNvdmlkX3N1YnNldCRob3NwaXRhbGl6ZWRDdXJyZW50bHkgJT4lY2FwKCkNCg0KcG9zaXRpdmVQZXJjZW50X2NhcDwtIGNvdmlkX3N1YnNldCRQb3NpdGl2ZV9jYXNlX3BlcmNlbnRhZ2UgJT4lIGNhcCgpDQoNCnRvdGFsVGVzdFJlc3VsdHNfY2FwcGVkIDwtIGNvdmlkX3N1YnNldCR0b3RhbFRlc3RSZXN1bHRzICU+JWNhcCgpDQoNCmRlYXRoX2NhcHBlZCA8LSBjb3ZpZF9zdWJzZXQkZGVhdGggJT4lY2FwKCkNCg0KQ292aWRfY2FwcGVkIDwtIHNhcHBseShjb3ZpZF9zdWJzZXQsIEZVTiA9IGNhcCkNCg0KI0Rlc2NyaXB0aXZlIHN0YXRpc3RpY3Mgb2YgdGhlIGNhcHBlZCBkYXRhc2V0DQoNCnN1bW1hcnkoQ292aWRfY2FwcGVkKQ0KYGBgDQoNCg0KDQojIwlUcmFuc2Zvcm0gDQoNClRyYW5zZm9ybWF0aW9uIGlzIHJlcXVpcmVkIGluIERhdGEgd3JhbmdsaW5nIGZvciBzY2FsaW5nLHN0YW5kYXJkaXppbmcsbm9ybWFsaXppbmcgLHJlZHVjaW5nIHNrZXduZXNzIG9mIGRpc3RyaWJ1dGlvbi5JIGhhdmUgYXBwbGllZCBkaWZmZXJlbnQgdHlwZXMgb2YgdHJhbnNmb3JtYXRpb24gbGlrZSBsb2cgLCBsb2cxMCAsQm94LUNveCB0cmFuc2Zvcm1hdGlvbiB0byB0aGUgY2FwcGVkIGRhdGEgd2hpY2ggSSBnb3QgZnJvbSBhYm92ZSBzdGVwcyBhZnRlciBjYXBwaW5nIG91dGxpZXJzIC5BZnRlciBleHBlcmltZW50aW5nIHdpdGggZGlmZmVyZW50IHRyYW5zZm9ybWF0aW9uIHR5cGVzLEkgZm91bmQgdGhlIGJlc3QgdHlwZXMgc3VpdGFibGUgZm9yIGVhY2ggb2YgdGhlIHZhcmlhYmxlcy4NCg0KQmVsb3cgYXJlIHRoZSBvYnNlcnZhdGlvbnMgYWZ0ZXIgYXBwbHlpbmcgdHJhbnNmb3JtYXRpb24uDQoNCjEuIGhvc3BpdGFsaXplZF9jYXBwZWQgIHdhcyByaWdodCBza2V3ZWQgLlRoaXMgdmFyaWFibGUgZG9lcyBub3QgaGF2ZSBhbnkgbmVnYXRpdmUgdmFsdWVzIC5TbyBhcHBseWluZyBsb2cxMCB0cmFuc2Zvcm1hdGlvbiwgZ3JhcGggcHJvZHVjZSBtb3JlIHN5bW1ldHJpYyBkaXN0cmlidXRpb24uDQoNCjIuIHBvc2l0aXZlX2NhcHBlZCB3YXMgc2hvd24gYXMgZXh0cmVtZWx5IHJpZ2h0IHNrZXdlZC4gVGhpcyB2YXJpYWJsZSBhbHNvIGRvZXMgbm90IGhhdmUgYW55IG5lZ2F0aXZlIHZhbHVlcyBBcHBseWluZyBsb2cgdHJhbnNmb3JtYXRpb24gLGRpc3RyaWJ1dGlvbiBsb29rIGFwcHJveGltYXRlbHkgbW9yZSBzeW1tZXRyaWNhbC4NCg0KMy4gcG9zaXRpdmVQZXJjZW50X2NhcCAgd2FzIHVuZXZlbmx5IGRpc3RyaWJ1dGVkIGFuZCBub3Qgd2FzIHN5bW1ldHJpYyAuSGVyZSBJIGFwcGxpZWQgQm94LUNveCB0cmFuc2Zvcm1hdGlvbiByYXRoZXIgdGhhbiBsb2cgdHJhbnNmb3JtYXRpb24gd2hpY2ggcHJvZHVjZWQgbW9yZSBzeW1tZXRyaWMgZGlzdHJpYnV0aW9uLg0KDQo0LiBkZWF0aF9jYXBwZWQgd2FzIHJpZ2h0bHkgc2tld2VkLkFwcGx5aW5nIEJveC1Db3ggdHJhbnNmb3JtYXRpb24gcHJvZHVjZWQgdGhlIGJlc3QgcmVzdWx0IHRoYW4gb3RoZXIgdHJhbnNmb3JtYXRpb24gYW5kIHJlc3VsdGVkIGluIGFwcHJveGltYXRlbHkgc3ltbWV0cmljYWwgZGlzdHJpYnV0aW9uLg0KDQpgYGB7cn0NCg0KcGFyKG1mcm93PWMoMSwyKSkNCg0KaGlzdChob3NwaXRhbGl6ZWRfY2FwcGVkICxtYWluID0gIiBDb3ZpZCBIb3NwaXRhbGl6ZWQgIiwgeGxhYiA9ICJDb3ZpZCBIb3NwaXRhbGl6ZWQgIikNCmdyaWQoY29sID0gImdyZXkiKQ0KDQojIEl0IGlzIGhpZ2hseSByaWdodCBza2V3ZWQNCg0KIyBBcHBseWluZyBsb2cxMCB0cmFuc2Zvcm1hdGlvbg0KDQpsb2dfaG9zcGl0YWxpemVkIDwtIGxvZzEwKGhvc3BpdGFsaXplZF9jYXBwZWQpDQoNCg0KIyBIaXN0b2dyYW0gYWZ0ZXIgdHJhbnNmb3JtYXRpb24NCg0KaGlzdChsb2dfaG9zcGl0YWxpemVkICxtYWluID0gIkxvZzEwIHRyYW5zZm9ybWF0aW9uIiwgeGxhYiA9ICJDb3ZpZCBIb3NwaXRhbGl6ZWQgIiAsY29sID0gImJpc3F1ZSIgKQ0KDQpncmlkKGNvbCA9ICJncmV5IikNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCg0KcGFyKG1mcm93PWMoMSwyKSkNCg0KaGlzdChwb3NpdGl2ZV9jYXBwZWQsbWFpbiA9ICJOdW1iZXIgb2YgY292aWQgcG9zaXRpdmUgY2FzZXMgIiwgeGxhYiA9ICJjb3ZpZF9wb3NpdGl2ZV9jYXNlcyIpDQoNCmdyaWQoY29sID0gImdyZXkiKQ0KIyBJdCBpcyBoaWdobHkgcmlnaHQgc2tld2VkDQoNCiMgQXBwbHlpbmcgbG9nIHRyYW5zZm9ybWF0aW9uDQoNCmxvZ19wb3NpdGl2ZSA8LSBsb2cocG9zaXRpdmVfY2FwcGVkKQ0KDQojIEhpc3RvZ3JhbSBhZnRlciB0cmFuc2Zvcm1hdGlvbg0KDQpoaXN0KGxvZ19wb3NpdGl2ZSAsbWFpbiA9ICJMb2cgdHJhbnNmb3JtYXRpb24gIiwgeGxhYiA9ICJjb3ZpZF9wb3NpdGl2ZV9jYXNlcyIgLGNvbCA9ICJiaXNxdWUiKQ0KZ3JpZChjb2wgPSAiZ3JleSIpDQoNCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KDQpwYXIobWZyb3c9YygxLDIpKQ0KDQpoaXN0KHBvc2l0aXZlUGVyY2VudF9jYXAgLG1haW4gPSJQZXJjZW50YWdlIG9mIHBvc2l0aXZlIGNhc2VzIiwgeGxhYiA9ICJwb3NpdGl2ZSBjYXNlIHBlcmNlbnRhZ2UiKQ0KZ3JpZChjb2wgPSAiZ3JleSIpDQoNCiMgQXBwbHlpbmcgQm94LUNveCB0cmFuc2Zvcm1hdGlvbg0KDQpib3hjb3hfcG9zaXRpdmU8LSBCb3hDb3gocG9zaXRpdmVQZXJjZW50X2NhcCxsYW1iZGEgPSAiYXV0byIpDQoNCmhpc3QoYm94Y294X3Bvc2l0aXZlICxtYWluID0iQm94LUNveCB0cmFuc2Zvcm1hdGlvbiIsIHhsYWIgPSAicG9zaXRpdmUgY2FzZSBwZXJlY2VudGFnZSIgLGNvbCA9ICJiaXNxdWUiKQ0KZ3JpZChjb2wgPSAiZ3JleSIpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KDQpwYXIobWZyb3c9YygxLDIpKQ0KDQpoaXN0KGRlYXRoX2NhcHBlZCAsbWFpbiA9ICJOdW1iZXIgb2YgQ292aWQgZGVhdGhzICIsIHhsYWIgPSAibnVtYmVyIG9mIENvdmlkIGRlYXRocyAiKQ0KZ3JpZChjb2wgPSAiZ3JleSIpDQojIEl0IGlzIGhpZ2hseSByaWdodCBza2V3ZWQNCg0KIyBBcHBseWluZyBib3hjb3ggdHJhbnNmb3JtYXRpb24NCg0KDQpib3hjb3hfZGVhdGg8LSBCb3hDb3goZGVhdGhfY2FwcGVkLGxhbWJkYSA9ICJhdXRvIikNCg0KIyBIaXN0b2dyYW0gYWZ0ZXIgdHJhbnNmb3JtYXRpb24NCg0KaGlzdChib3hjb3hfZGVhdGggLG1haW4gPSAiQm94Q294IHRyYW5zZm9ybWF0aW9uICIsIHhsYWIgPSAibnVtYmVyIG9mIENvdmlkIGRlYXRocyAiICxjb2wgPSAiYmlzcXVlIikNCmdyaWQoY29sID0gImdyZXkiKQ0KDQoNCmBgYA0KDQojIwlDb25jbHVzaW9uIA0KDQotRnJvbSB0aGUgYWJvdmUgYXNzaWdubWVudCx3ZSBjYW4gc2VlIGhvdyBsYXJnZSBtZXNzeSBkYXRhIHNldHMgYW5kIGJlIHByZS1wcm9jZXNzZWQgdXNpbmcgRGF0YSBXcmFuZ2xpbmcgdGVjaG5pcXVlcyBpbiBSLg0KDQotVGlkeWluZyB1cCBkYXRhIGVuc3VyZXMgdmFyaWFibGUgaGF2ZSBpdHMgb3duIGNvbHVtbnMgYW5kIG9ic2VydmF0aW9ucyBoYXZlIGl0cyBvd24gcm93cy4NCg0KLVNjYW5uaW5nIG1pc3NpbmcgZGF0YSxzcGVjaWFsIHZhbHVlcyBhbmQgb3V0bGllcnMgaXMgbmVjZXNzYXJ5IGJlZm9yZSBhbnkgc3RhdGlzdGljYWwgYW5hbHlzaXMgc28gdGhhdCBjbGVhbiBkYXRhIGNhbiBiZSB1c2VkIGFzIGlucHV0IGludG8gYSB2YXJpZXR5IG9mIG90aGVyIGZ1bmN0aW9ucyB0aGF0IG1heSB0cmFuc2Zvcm0sIG1vZGVsLCBvciB2aXN1YWxpemUgdGhlIGRhdGEuDQoNCi1BbHNvIHdlIGNhbiBzZWUgdGhhdCBpdCBpcyBub3QgYWx3YXlzIGdvb2QgaWRlYSB0byBlbGltaW5hdGUgbWlzc2luZyBkYXRhIG9yIG91dGxpZXJzIGFzIGl0IGNhbiByZW1vdmUgaW1wb3J0YW50IGRhdGEgZnJvbSB0aGUgZGF0YXNldC4gVGVjaG5pcXVlcyBsaWtlIEltcHV0YXRpb24gLGNhcHBpbmcgYXJlIHNvbWUgb2YgdGhlIG1ldGhvZHMgd2hpY2ggY2FuIGJlIGFwcGxpZWQgdG8gbWFrZSBkYXRhIG1vcmUgZWZmaWNlbnQgZm9yIGZ1cnRoZXIgdXNlLg0KDQotVG8gbWFrZSBiZXR0ZXItb3JnYW5pemVkIGFuZCBwcm9wZXJseSBmb3JtYXR0ZWQgZGF0YSwgdHJhbnNmb3JtYXRpb24gaXMgbmVjZXNzYXJ5Lk5vdCBhbHdheXMgc2FtZSB0cmFuc2Zvcm1hdGlvbiB0eXBlIGlzIGFwcGxpY2FibGUgdG8gYWxsIGRhdGEgdmFyaWFibGVzIC5FYWNoIHZhcmlhYmxlIGNhbiBiZSBleHBlcmltZW50IGJ5IGFwcGx5aW5nIGRpZmZlcmVudCB0cmFuc2Zvcm1hdGlvbiBtZXRob2QgYW5kIHRoZSBiZXN0IG9uZSBjYW4gYmUgZm91bmQgd2hpY2ggZW5zdXJlIG1heGltdW0gcG9zc2libGUgc3ltbWV0cnkgYW5kIG5vcm1hbGl0eS4NCg0KLU92ZXJhbGwgdGhpcyBhc3NpZ25tZW50IGhlbHBlZCBtZSB0byBnYWluIGluc2lnaHRzIGludG8gcHJhY3RpY2FsIGFzcGVjdHMgb2YgRGF0YSBXcmFuZ2xpbmcgYW5kIHVuZGVyc3RhbmQgcmVhbCB3b3JsZCBwcm9ibGVtcy4NCg0KDQojIwlSZWZlcmVuY2UNCg0KaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9zdWRhbGFpcmFqa3VtYXIvY292aWQxOS1pbi11c2E/c2VsZWN0PXVzX3N0YXRlc19jb3ZpZDE5X2RhaWx5LmNzdg0KDQpodHRwczovL3d3dy5rYWdnbGUuY29tL2lraXVsaWFuL2dsb2JhbC1ob3NwaXRhbC1iZWRzLWNhcGFjaXR5LWZvci1jb3ZpZDE5P3NlbGVjdD1ob3NwaXRhbF9iZWRzX1VTQV92MS5jc3YNCiAgICAgICAgICAgDQpodHRwOi8vcmFyZS1waG9lbml4LTE2MTYxMC5hcHBzcG90LmNvbS9zZWN1cmVkL2luZGV4Lmh0bWwNCg0KDQoNCg0KYGBgDQoNCg0KDQo=