Required packages

library(readr) # Useful for reading data
library(car) # Useful to qqplot
library(dplyr)  # Useful for data maipulation
library(tidyr) # Useful for tidying data
library(Hmisc) # Useful for utility operation
library(ggplot2) # Useful for creating plots
library(outliers) # Useful to handle outliers
library(knitr) # Useful for creating nice tables
library(lubridate) # Useful for date/time
library(forecast) # Userful for analysing time series data
library(naniar) # Userful for Handling data 
rm(list=ls()) # Cleaning environment
# getwd()
setwd("D:/Studies/MS/Sem1/Data Preprocessing (MATH2349)/Assignment/Assignment3") # Set userdirectory

Executive Summary

Aim of the assignment is, collecting two different datasets, merging, understanding and analysiing dataset, perform data processing concepts like correct datatype conversion. Further checking tidy principles on dataset and coverting data into tidy form using various method if it doesn’t satisfy. Next is to scan and handle missing values and outliers, And exclude or replace with appropriate values if it is necessary to do which helps to nearly accurate analysis. After applying tidy principle and handling inapproriate values, check for normality of data and applying any trasnformation to convert into normalized form. These task will help us to prepare data for any statisitcal analysis or reporting.

Data

We are using demographic and population health data(around 3141 US counties) to perform data preprocessing task.But we will focus on county data to perform task.

Datasource: https://data.world/data-society/health-status-indicators https://catalog.data.gov/dataset/community-health-status-indicators-chsi-to-combat-obesity-heart-disease-and-cancer#sec-dates

Dataset1: Demographic contains county/population count by age group and total Dataset2: Vulnerable population data by various category like unemployed, depression, Drug user for particular time span(2001-2003, 1999-2003, 1994-2003)

Both dataset has State_FIPS_Code, Country_FIPS_Code which helps to identify state and county developed by National Bureau of Standards. Some measure column contains any of these values -9999, -2222, -222, -2 which represent NA/Not available/ No details. All measures are calculated based on average.

dataset1 <- read.csv("demographic.csv",stringsAsFactors = FALSE)
dataset2 <- read.csv("vulnerablepopulation.csv",stringsAsFactors = FALSE)

Understand

Dataset1 (Dempographic Population by Age) :

  • Snapshot and data strcture of demographic data
# Data Structure of dataset1
dataset_1 <- dataset1 %>%  select(-c("CHSI_State_Name", "Strata_ID_Number"))
head(dataset_1)
str(dataset_1)
'data.frame':   3141 obs. of  8 variables:
 $ State_FIPS_Code : int  1 1 1 1 1 1 1 1 1 1 ...
 $ County_FIPS_Code: int  1 3 5 7 9 11 13 15 17 19 ...
 $ CHSI_County_Name: chr  "Autauga" "Baldwin" "Barbour" "Bibb" ...
 $ CHSI_State_Abbr : chr  "AL" "AL" "AL" "AL" ...
 $ Age_19_Under    : num  26.9 23.5 24.3 24.6 24.5 24.7 25.6 24.1 24.8 21.9 ...
 $ Age_19_64       : num  62.3 60.3 62.5 63.3 62.1 63.2 58.5 61.6 59.5 61.4 ...
 $ Age_65_84       : num  9.8 14.5 11.6 10.9 12.1 10 13.6 12.7 13.5 15.2 ...
 $ Age_85_and_Over : num  0.9 1.8 1.6 1.2 1.3 2.2 2.4 1.5 2.2 1.4 ...
  • Total Observations: 3141, TOtal Variables: 8
  • State_FIPS_Code : int(2) State Code
  • County_FIPS_Code : int(2) County Code
  • CHSI_County_Name : chr Country Name
  • CHSI_State_Abbr : chr County Abbreviation
  • Age_19_Under : num population count with age < 19
  • Age_19_64 : num population count with age >= 19 and <=64
  • Age_65_84 : num population count with age >= 65 and <=84
  • Age_85_and_Over : num population count with age >= 85

Dataset2 (Vulnerable Population) :

  • Snapshot and data structure of demographic data
# Data Structure of dataset1
dataset_2 <- dataset2 %>%  select(-c("CHSI_State_Name", "Strata_ID_Number"))
head(dataset_2)
str(dataset_2)
'data.frame':   3141 obs. of  10 variables:
 $ State_FIPS_Code  : int  1 1 1 1 1 1 1 1 1 1 ...
 $ County_FIPS_Code : int  1 3 5 7 9 11 13 15 17 19 ...
 $ CHSI_County_Name : chr  "Autauga" "Baldwin" "Barbour" "Bibb" ...
 $ CHSI_State_Abbr  : chr  "AL" "AL" "AL" "AL" ...
 $ No_HS_Diploma    : int  6690 20254 6729 5355 11181 2848 4363 19546 8718 6398 ...
 $ Unemployed       : int  774 2533 569 358 819 327 537 2182 849 464 ...
 $ Sev_Work_Disabled: int  1727 4933 1302 900 2217 448 976 5722 1470 1154 ...
 $ Major_Depression : int  2680 9354 1618 1218 3164 626 1164 6400 2005 1436 ...
 $ Recent_Drug_Use  : int  2394 7753 1403 1034 2675 565 1029 5545 1647 1140 ...
 $ EH_Time_Span     : chr  "1999-2003" "2001-2003" "1999-2003" "1994-2003" ...
  • Total Observations: 3141, TOtal Variables: 10
  • State_FIPS_Code : int(2) State Code
  • County_FIPS_Code : int(2) County Code
  • CHSI_County_Name : chr Country Name
  • CHSI_State_Abbr : chr County Abbreviation
  • No_HS_Diploma : int No high school diploma
  • Unemployed : int unemployed count
  • Sev_Work_Disabled : int severely work disabled
  • Major_Depression : int major depression
  • Recent_Drug_Use : int recent drug users(last month)
  • EH_Time_Span : chr time span

Joining datasets

  • Merging both dataset by State_FIPS_Code, County_FIPS_Code and create combine dataset
  • Snapshot of new dataset
# Joining dataset1 with dataset2 based in State_FIPS_Code
dataset <- left_join(dataset1, dataset2,by=c("State_FIPS_Code","County_FIPS_Code"))
head(dataset)
  • data strcture of new dataset
str(dataset)
'data.frame':   3141 obs. of  20 variables:
 $ State_FIPS_Code   : int  1 1 1 1 1 1 1 1 1 1 ...
 $ County_FIPS_Code  : int  1 3 5 7 9 11 13 15 17 19 ...
 $ CHSI_County_Name.x: chr  "Autauga" "Baldwin" "Barbour" "Bibb" ...
 $ CHSI_State_Name.x : chr  "Alabama" "Alabama" "Alabama" "Alabama" ...
 $ CHSI_State_Abbr.x : chr  "AL" "AL" "AL" "AL" ...
 $ Strata_ID_Number.x: int  29 16 51 42 28 75 76 6 50 64 ...
 $ Age_19_Under      : num  26.9 23.5 24.3 24.6 24.5 24.7 25.6 24.1 24.8 21.9 ...
 $ Age_19_64         : num  62.3 60.3 62.5 63.3 62.1 63.2 58.5 61.6 59.5 61.4 ...
 $ Age_65_84         : num  9.8 14.5 11.6 10.9 12.1 10 13.6 12.7 13.5 15.2 ...
 $ Age_85_and_Over   : num  0.9 1.8 1.6 1.2 1.3 2.2 2.4 1.5 2.2 1.4 ...
 $ CHSI_County_Name.y: chr  "Autauga" "Baldwin" "Barbour" "Bibb" ...
 $ CHSI_State_Name.y : chr  "Alabama" "Alabama" "Alabama" "Alabama" ...
 $ CHSI_State_Abbr.y : chr  "AL" "AL" "AL" "AL" ...
 $ Strata_ID_Number.y: int  29 16 51 42 28 75 76 6 50 64 ...
 $ No_HS_Diploma     : int  6690 20254 6729 5355 11181 2848 4363 19546 8718 6398 ...
 $ Unemployed        : int  774 2533 569 358 819 327 537 2182 849 464 ...
 $ Sev_Work_Disabled : int  1727 4933 1302 900 2217 448 976 5722 1470 1154 ...
 $ Major_Depression  : int  2680 9354 1618 1218 3164 626 1164 6400 2005 1436 ...
 $ Recent_Drug_Use   : int  2394 7753 1403 1034 2675 565 1029 5545 1647 1140 ...
 $ EH_Time_Span      : chr  "1999-2003" "2001-2003" "1999-2003" "1994-2003" ...
  • Variable suffix with .x belongs to dataset1 and with .y belongs to dataset2.

Tidy & Manipulate Data I

# reshape age category
dataset_t1 <- dataset %>% gather(c("Age_19_Under","Age_19_64","Age_65_84","Age_85_and_Over"),key="Age",value="Age_Population")
# reshape Vulnerable Category
dataset_t2 <- dataset_t1 %>%  gather(c("No_HS_Diploma","Unemployed","Sev_Work_Disabled","Major_Depression","Recent_Drug_Use"),key="Vulnerable_Category", value="Vulnerable_Population") 
str(dataset_t2)
'data.frame':   62820 obs. of  15 variables:
 $ State_FIPS_Code      : int  1 1 1 1 1 1 1 1 1 1 ...
 $ County_FIPS_Code     : int  1 3 5 7 9 11 13 15 17 19 ...
 $ CHSI_County_Name.x   : chr  "Autauga" "Baldwin" "Barbour" "Bibb" ...
 $ CHSI_State_Name.x    : chr  "Alabama" "Alabama" "Alabama" "Alabama" ...
 $ CHSI_State_Abbr.x    : chr  "AL" "AL" "AL" "AL" ...
 $ Strata_ID_Number.x   : int  29 16 51 42 28 75 76 6 50 64 ...
 $ CHSI_County_Name.y   : chr  "Autauga" "Baldwin" "Barbour" "Bibb" ...
 $ CHSI_State_Name.y    : chr  "Alabama" "Alabama" "Alabama" "Alabama" ...
 $ CHSI_State_Abbr.y    : chr  "AL" "AL" "AL" "AL" ...
 $ Strata_ID_Number.y   : int  29 16 51 42 28 75 76 6 50 64 ...
 $ EH_Time_Span         : chr  "1999-2003" "2001-2003" "1999-2003" "1994-2003" ...
 $ Age                  : chr  "Age_19_Under" "Age_19_Under" "Age_19_Under" "Age_19_Under" ...
 $ Age_Population       : num  26.9 23.5 24.3 24.6 24.5 24.7 25.6 24.1 24.8 21.9 ...
 $ Vulnerable_Category  : chr  "No_HS_Diploma" "No_HS_Diploma" "No_HS_Diploma" "No_HS_Diploma" ...
 $ Vulnerable_Population: int  6690 20254 6729 5355 11181 2848 4363 19546 8718 6398 ...
# Factoring Age and Vulnerable Category
Age_cat <- c("Age_19_Under","Age_19_64","Age_65_84","Age_85_and_Over")
Age_Cat_labels <- c("<19","19-64","65-84","85+")
vulnerable_cat <- c("No_HS_Diploma","Unemployed","Sev_Work_Disabled","Major_Depression","Recent_Drug_Use")

dataset_t2 <- mutate(dataset_t2 
                        ,Age_Cat=factor(Age,levels=Age_cat, labels=Age_Cat_labels,ordered = TRUE)
                        ,Vulnerable_Cat=factor(Vulnerable_Category,levels=vulnerable_cat)
                       ) %>% select(-c("Age","Vulnerable_Category"))
summary(dataset_t2$Age_Population)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.100   5.175  19.600  25.000  47.300  83.300 
summary(dataset_t2$Vulnerable_Population)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
      1     500    1298    5646    3881 1872316     148 

Tidy & Manipulate Data II

dataset_t3 <- dataset_t2 %>% separate(EH_Time_Span, into=c("Start_Year","End_Year"),sep="-")
str(dataset_t3)
'data.frame':   62820 obs. of  16 variables:
 $ State_FIPS_Code      : int  1 1 1 1 1 1 1 1 1 1 ...
 $ County_FIPS_Code     : int  1 3 5 7 9 11 13 15 17 19 ...
 $ CHSI_County_Name.x   : chr  "Autauga" "Baldwin" "Barbour" "Bibb" ...
 $ CHSI_State_Name.x    : chr  "Alabama" "Alabama" "Alabama" "Alabama" ...
 $ CHSI_State_Abbr.x    : chr  "AL" "AL" "AL" "AL" ...
 $ Strata_ID_Number.x   : int  29 16 51 42 28 75 76 6 50 64 ...
 $ CHSI_County_Name.y   : chr  "Autauga" "Baldwin" "Barbour" "Bibb" ...
 $ CHSI_State_Name.y    : chr  "Alabama" "Alabama" "Alabama" "Alabama" ...
 $ CHSI_State_Abbr.y    : chr  "AL" "AL" "AL" "AL" ...
 $ Strata_ID_Number.y   : int  29 16 51 42 28 75 76 6 50 64 ...
 $ Start_Year           : chr  "1999" "2001" "1999" "1994" ...
 $ End_Year             : chr  "2003" "2003" "2003" "2003" ...
 $ Age_Population       : num  26.9 23.5 24.3 24.6 24.5 24.7 25.6 24.1 24.8 21.9 ...
 $ Vulnerable_Population: int  6690 20254 6729 5355 11181 2848 4363 19546 8718 6398 ...
 $ Age_Cat              : Ord.factor w/ 4 levels "<19"<"19-64"<..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Vulnerable_Cat       : Factor w/ 5 levels "No_HS_Diploma",..: 1 1 1 1 1 1 1 1 1 1 ...

Scan I

# Finding Missing values
colSums(is.na(dataset_t3))
      State_FIPS_Code      County_FIPS_Code    CHSI_County_Name.x     CHSI_State_Name.x 
                    0                     0                     0                     0 
    CHSI_State_Abbr.x    Strata_ID_Number.x    CHSI_County_Name.y     CHSI_State_Name.y 
                    0                     0                     0                     0 
    CHSI_State_Abbr.y    Strata_ID_Number.y            Start_Year              End_Year 
                    0                     0                     0                     0 
       Age_Population Vulnerable_Population               Age_Cat        Vulnerable_Cat 
                    0                   148                     0                     0 
# total missing values
sum(is.na(dataset_t3))
[1] 148
# Omitting missing values
dataset_t4 <- na.omit(dataset_t3)
sum(is.na(dataset_t4))
[1] 0
# Total NaN values in Age_Population
sum(is.nan(dataset_t4$Age_Population))
[1] 0
# Total Inf/-Inf values in Age_Population
sum(is.infinite(dataset_t4$Age_Population))
[1] 0
# Total NaN values in Vulnerable_Population
sum(is.nan(dataset_t4$Vulnerable_Population))
[1] 0
# Total Inf/-Inf values in Vulnerable_Population
sum(is.infinite(dataset_t4$Vulnerable_Population))
[1] 0

Scan II

# Z-Score for Age Population
z.scores_age <- dataset_t4$Age_Population %>% scores(type="z")
length (which( abs(z.scores_age) >3 ))
[1] 0
# Boxplot for Age Population
boxplot(dataset_t4$Age_Population, main = "BoxPlot of Age Population", ylab = "Population")

# Z-Score for Vulnerable Population
z.scores_vul <- dataset_t4$Vulnerable_Population %>% scores(type="z")
length (which( abs(z.scores_vul) >3 ))
[1] 448
# Boxplot for Vulnerable Population
boxplot(dataset_t4$Vulnerable_Population, main = "BoxPlot of Vulnerable Population", ylab = "Population")

# Capping function to replace the outlier value with 1st and 3rd Quantilies.
cap <- function(x){quantiles <- quantile(x,c(0.05,0.25,0.75,0.95))
  x[x < quantiles[2] - 1.5*IQR(x)] <- quantiles[1]
  x[x > quantiles[3] + 1.5*IQR(x)] <- quantiles[4]
  x
}
# Replace Outlier values using capping function
dataset_t4$Vulnerable_Population[is.na(dataset_t4$Vulnerable_Population) != TRUE] <-
dataset_t4$Vulnerable_Population[is.na(dataset_t4$Vulnerable_Population) != TRUE] %>% cap()
# After capping boxplot
boxplot(dataset_t4$Vulnerable_Population, main = "BoxPlot of Vulnerable Population", ylab = "Population")

# Z-Score for Vulnerable Population
z.scores_vul <- dataset_t4$Vulnerable_Population %>% scores(type="z")
length (which( abs(z.scores_vul) >3 ))
[1] 0

Transform

hist(dataset_t4$Age_Population, main="Histogram for Age Population", xlab="Mean of Age population")
abline(v = mean(dataset_t4$Age_Population), col="red", lwd=3, lty=2)

# Apply boxcox with lamda Auto to normalize the data
dataset_t4$Age_Population_Box <- BoxCox(dataset_t4$Age_Population, lambda = "auto")
dataset_t4$Age_Population_Box<-scale(dataset_t4$Age_Population_Box,center=TRUE,scale=TRUE)
hist(dataset_t4$Age_Population_Box, main="After transformation, Histogram for Age Population", xlab="Mean of Age population")
abline(v = mean(dataset_t4$Age_Population_Box), col="red", lwd=3, lty=2)

hist(dataset_t4$Vulnerable_Population, main="Histogram for Vulnerable Population", xlab="Mean of Vulnerable population")
abline(v = mean(dataset_t4$Vulnerable_Population), col="red", lwd=3, lty=2)

# Apply boxcox with lamda Auto to normalize the data
dataset_t4$Vulnerable_Population_Box_1 <- BoxCox(dataset_t4$Vulnerable_Population, lambda = "auto")
dataset_t4$Vulnerable_Population_Box <- BoxCox(dataset_t4$Vulnerable_Population_Box_1, lambda = "auto")
hist(dataset_t4$Vulnerable_Population_Box, main="After transformation, Histogram for Vulnerable Population", xlab="Mean of Vulnerable population")
abline(v = mean(dataset_t4$Vulnerable_Population_Box), col="red", lwd=3, lty=2)



LS0tDQp0aXRsZTogIk1BVEgyMzQ5IFNlbWVzdGVyIDIsIDIwMTkiDQphdXRob3I6IFJhdmlrdW1hciBCYWxhciAoUzM3OTgwOTgpIHwgRHJhc2h0aSBNYW5peWEgKFMzNzQ4OTQ0KSB8IEFqYXlrdW1hciBLb3RoaXlhIChTMzc5MzY2MSkNCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMw0KLS0tDQoNCiMjIFJlcXVpcmVkIHBhY2thZ2VzIA0KDQpgYGB7ciwgZWNobz1UUlVFLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkocmVhZHIpICMgVXNlZnVsIGZvciByZWFkaW5nIGRhdGENCmxpYnJhcnkoY2FyKSAjIFVzZWZ1bCB0byBxcXBsb3QNCmxpYnJhcnkoZHBseXIpICAjIFVzZWZ1bCBmb3IgZGF0YSBtYWlwdWxhdGlvbg0KbGlicmFyeSh0aWR5cikgIyBVc2VmdWwgZm9yIHRpZHlpbmcgZGF0YQ0KbGlicmFyeShIbWlzYykgIyBVc2VmdWwgZm9yIHV0aWxpdHkgb3BlcmF0aW9uDQpsaWJyYXJ5KGdncGxvdDIpICMgVXNlZnVsIGZvciBjcmVhdGluZyBwbG90cw0KbGlicmFyeShvdXRsaWVycykgIyBVc2VmdWwgdG8gaGFuZGxlIG91dGxpZXJzDQpsaWJyYXJ5KGtuaXRyKSAjIFVzZWZ1bCBmb3IgY3JlYXRpbmcgbmljZSB0YWJsZXMNCmxpYnJhcnkobHVicmlkYXRlKSAjIFVzZWZ1bCBmb3IgZGF0ZS90aW1lDQpsaWJyYXJ5KGZvcmVjYXN0KSAjIFVzZXJmdWwgZm9yIGFuYWx5c2luZyB0aW1lIHNlcmllcyBkYXRhDQpsaWJyYXJ5KG5hbmlhcikgIyBVc2VyZnVsIGZvciBIYW5kbGluZyBkYXRhIA0Kcm0obGlzdD1scygpKSAjIENsZWFuaW5nIGVudmlyb25tZW50DQojIGdldHdkKCkNCnNldHdkKCJEOi9TdHVkaWVzL01TL1NlbTEvRGF0YSBQcmVwcm9jZXNzaW5nIChNQVRIMjM0OSkvQXNzaWdubWVudC9Bc3NpZ25tZW50MyIpICMgU2V0IHVzZXJkaXJlY3RvcnkNCmBgYA0KDQoNCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IA0KDQpBaW0gb2YgdGhlIGFzc2lnbm1lbnQgaXMsIGNvbGxlY3RpbmcgdHdvIGRpZmZlcmVudCBkYXRhc2V0cywgbWVyZ2luZywgdW5kZXJzdGFuZGluZyBhbmQgYW5hbHlzaWluZyBkYXRhc2V0LCBwZXJmb3JtIGRhdGEgcHJvY2Vzc2luZyBjb25jZXB0cyBsaWtlIGNvcnJlY3QgZGF0YXR5cGUgY29udmVyc2lvbi4gRnVydGhlciBjaGVja2luZyB0aWR5IHByaW5jaXBsZXMgb24gZGF0YXNldCBhbmQgY292ZXJ0aW5nIGRhdGEgaW50byB0aWR5IGZvcm0gdXNpbmcgdmFyaW91cyBtZXRob2QgaWYgaXQgZG9lc24ndCBzYXRpc2Z5LiBOZXh0IGlzIHRvIHNjYW4gYW5kIGhhbmRsZSBtaXNzaW5nIHZhbHVlcyBhbmQgb3V0bGllcnMsIEFuZCBleGNsdWRlIG9yIHJlcGxhY2Ugd2l0aCBhcHByb3ByaWF0ZSB2YWx1ZXMgaWYgaXQgaXMgbmVjZXNzYXJ5IHRvIGRvIHdoaWNoIGhlbHBzIHRvIG5lYXJseSBhY2N1cmF0ZSBhbmFseXNpcy4gQWZ0ZXIgYXBwbHlpbmcgdGlkeSBwcmluY2lwbGUgYW5kIGhhbmRsaW5nIGluYXBwcm9yaWF0ZSB2YWx1ZXMsIGNoZWNrIGZvciBub3JtYWxpdHkgb2YgZGF0YSBhbmQgYXBwbHlpbmcgYW55IHRyYXNuZm9ybWF0aW9uIHRvIGNvbnZlcnQgaW50byBub3JtYWxpemVkIGZvcm0uIFRoZXNlIHRhc2sgd2lsbCBoZWxwIHVzIHRvIHByZXBhcmUgZGF0YSBmb3IgYW55IHN0YXRpc2l0Y2FsIGFuYWx5c2lzIG9yIHJlcG9ydGluZy4NCg0KIyMgRGF0YSANCg0KV2UgYXJlIHVzaW5nIGRlbW9ncmFwaGljIGFuZCBwb3B1bGF0aW9uIGhlYWx0aCBkYXRhKGFyb3VuZCAzMTQxIFVTIGNvdW50aWVzKSB0byBwZXJmb3JtIGRhdGEgcHJlcHJvY2Vzc2luZyB0YXNrLkJ1dCB3ZSB3aWxsIGZvY3VzIG9uIGNvdW50eSBkYXRhIHRvIHBlcmZvcm0gdGFzay4NCg0KRGF0YXNvdXJjZTogaHR0cHM6Ly9kYXRhLndvcmxkL2RhdGEtc29jaWV0eS9oZWFsdGgtc3RhdHVzLWluZGljYXRvcnMNCmh0dHBzOi8vY2F0YWxvZy5kYXRhLmdvdi9kYXRhc2V0L2NvbW11bml0eS1oZWFsdGgtc3RhdHVzLWluZGljYXRvcnMtY2hzaS10by1jb21iYXQtb2Jlc2l0eS1oZWFydC1kaXNlYXNlLWFuZC1jYW5jZXIjc2VjLWRhdGVzDQoNCkRhdGFzZXQxOiBEZW1vZ3JhcGhpYyBjb250YWlucyBjb3VudHkvcG9wdWxhdGlvbiBjb3VudCBieSBhZ2UgZ3JvdXAgYW5kIHRvdGFsDQpEYXRhc2V0MjogVnVsbmVyYWJsZSBwb3B1bGF0aW9uIGRhdGEgYnkgdmFyaW91cyBjYXRlZ29yeSBsaWtlIHVuZW1wbG95ZWQsIGRlcHJlc3Npb24sIERydWcgdXNlciBmb3IgcGFydGljdWxhciB0aW1lIHNwYW4oMjAwMS0yMDAzLCAxOTk5LTIwMDMsIDE5OTQtMjAwMykNCg0KQm90aCBkYXRhc2V0IGhhcyBTdGF0ZV9GSVBTX0NvZGUsIENvdW50cnlfRklQU19Db2RlIHdoaWNoIGhlbHBzIHRvIGlkZW50aWZ5IHN0YXRlIGFuZCBjb3VudHkgZGV2ZWxvcGVkIGJ5IE5hdGlvbmFsIEJ1cmVhdSBvZiBTdGFuZGFyZHMuDQpTb21lIG1lYXN1cmUgY29sdW1uIGNvbnRhaW5zIGFueSBvZiB0aGVzZSB2YWx1ZXMgLTk5OTksIC0yMjIyLCAtMjIyLCAtMiB3aGljaCByZXByZXNlbnQgTkEvTm90IGF2YWlsYWJsZS8gTm8gZGV0YWlscy4gQWxsIG1lYXN1cmVzIGFyZSBjYWxjdWxhdGVkIGJhc2VkIG9uIGF2ZXJhZ2UuDQpgYGB7cn0NCmRhdGFzZXQxIDwtIHJlYWQuY3N2KCJkZW1vZ3JhcGhpYy5jc3YiLHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCmRhdGFzZXQyIDwtIHJlYWQuY3N2KCJ2dWxuZXJhYmxlcG9wdWxhdGlvbi5jc3YiLHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCmBgYA0KDQojIyBVbmRlcnN0YW5kIA0KDQojIyMgRGF0YXNldDEgKERlbXBvZ3JhcGhpYyBQb3B1bGF0aW9uIGJ5IEFnZSkgOg0KDQotIFNuYXBzaG90IGFuZCBkYXRhIHN0cmN0dXJlIG9mIGRlbW9ncmFwaGljIGRhdGENCmBgYHtyfQ0KIyBEYXRhIFN0cnVjdHVyZSBvZiBkYXRhc2V0MQ0KZGF0YXNldF8xIDwtIGRhdGFzZXQxICU+JSAgc2VsZWN0KC1jKCJDSFNJX1N0YXRlX05hbWUiLCAiU3RyYXRhX0lEX051bWJlciIpKQ0KaGVhZChkYXRhc2V0XzEpDQpgYGANCg0KYGBge3J9DQpzdHIoZGF0YXNldF8xKQ0KYGBgDQoNCi0gKlRvdGFsIE9ic2VydmF0aW9ucyo6IDMxNDEsIFRPdGFsIFZhcmlhYmxlczogOA0KLSAqU3RhdGVfRklQU19Db2RlKiAgIDogaW50KDIpIFN0YXRlIENvZGUNCi0gKkNvdW50eV9GSVBTX0NvZGUqICA6IGludCgyKSBDb3VudHkgQ29kZSANCi0gKkNIU0lfQ291bnR5X05hbWUqICA6IGNociBDb3VudHJ5IE5hbWUNCi0gKkNIU0lfU3RhdGVfQWJiciogICA6IGNociBDb3VudHkgQWJicmV2aWF0aW9uDQotICpBZ2VfMTlfVW5kZXIqICAgICAgOiBudW0gcG9wdWxhdGlvbiBjb3VudCB3aXRoIGFnZSA8IDE5DQotICpBZ2VfMTlfNjQqICAgICAgICAgOiBudW0gcG9wdWxhdGlvbiBjb3VudCB3aXRoIGFnZSA+PSAxOSBhbmQgPD02NA0KLSAqQWdlXzY1Xzg0KiAgICAgICAgIDogbnVtIHBvcHVsYXRpb24gY291bnQgd2l0aCBhZ2UgPj0gNjUgYW5kIDw9ODQgIA0KLSAqQWdlXzg1X2FuZF9PdmVyKiAgIDogbnVtIHBvcHVsYXRpb24gY291bnQgd2l0aCBhZ2UgPj0gODUNCg0KIyMjIERhdGFzZXQyIChWdWxuZXJhYmxlIFBvcHVsYXRpb24pIDoNCg0KLSBTbmFwc2hvdCBhbmQgZGF0YSBzdHJ1Y3R1cmUgb2YgZGVtb2dyYXBoaWMgZGF0YQ0KYGBge3J9DQojIERhdGEgU3RydWN0dXJlIG9mIGRhdGFzZXQxDQpkYXRhc2V0XzIgPC0gZGF0YXNldDIgJT4lICBzZWxlY3QoLWMoIkNIU0lfU3RhdGVfTmFtZSIsICJTdHJhdGFfSURfTnVtYmVyIikpDQpoZWFkKGRhdGFzZXRfMikNCmBgYA0KDQpgYGB7cn0NCnN0cihkYXRhc2V0XzIpDQpgYGANCg0KLSAqVG90YWwgT2JzZXJ2YXRpb25zKjogMzE0MSwgVE90YWwgVmFyaWFibGVzOiAxMA0KLSAqU3RhdGVfRklQU19Db2RlKiAgIDogaW50KDIpIFN0YXRlIENvZGUNCi0gKkNvdW50eV9GSVBTX0NvZGUqICA6IGludCgyKSBDb3VudHkgQ29kZSANCi0gKkNIU0lfQ291bnR5X05hbWUqICA6IGNociBDb3VudHJ5IE5hbWUNCi0gKkNIU0lfU3RhdGVfQWJiciogICA6IGNociBDb3VudHkgQWJicmV2aWF0aW9uDQotICpOb19IU19EaXBsb21hKiAgICAgOiBpbnQgTm8gaGlnaCBzY2hvb2wgZGlwbG9tYQ0KLSAqVW5lbXBsb3llZCogICAgICAgIDogaW50IHVuZW1wbG95ZWQgY291bnQNCi0gKlNldl9Xb3JrX0Rpc2FibGVkKiA6IGludCBzZXZlcmVseSB3b3JrIGRpc2FibGVkDQotICpNYWpvcl9EZXByZXNzaW9uKiAgOiBpbnQgbWFqb3IgZGVwcmVzc2lvbg0KLSAqUmVjZW50X0RydWdfVXNlKiAgIDogaW50IHJlY2VudCBkcnVnIHVzZXJzKGxhc3QgbW9udGgpDQotICpFSF9UaW1lX1NwYW4qICAgICAgOiBjaHIgdGltZSBzcGFuDQoNCiMjIyBKb2luaW5nIGRhdGFzZXRzDQoNCi0gTWVyZ2luZyBib3RoIGRhdGFzZXQgYnkgU3RhdGVfRklQU19Db2RlLCBDb3VudHlfRklQU19Db2RlIGFuZCBjcmVhdGUgY29tYmluZSBkYXRhc2V0DQotIFNuYXBzaG90IG9mIG5ldyBkYXRhc2V0DQpgYGB7cn0NCiMgSm9pbmluZyBkYXRhc2V0MSB3aXRoIGRhdGFzZXQyIGJhc2VkIGluIFN0YXRlX0ZJUFNfQ29kZQ0KZGF0YXNldCA8LSBsZWZ0X2pvaW4oZGF0YXNldDEsIGRhdGFzZXQyLGJ5PWMoIlN0YXRlX0ZJUFNfQ29kZSIsIkNvdW50eV9GSVBTX0NvZGUiKSkNCmhlYWQoZGF0YXNldCkNCmBgYA0KDQotIGRhdGEgc3RyY3R1cmUgb2YgbmV3IGRhdGFzZXQNCmBgYHtyfQ0Kc3RyKGRhdGFzZXQpDQpgYGANCg0KLSBWYXJpYWJsZSBzdWZmaXggd2l0aCAueCBiZWxvbmdzIHRvIGRhdGFzZXQxIGFuZCB3aXRoIC55IGJlbG9uZ3MgdG8gZGF0YXNldDIuDQoNCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSSANCg0KLSBDdXJyZW50IGRhdGFzZXQgY29udGFpbnMgQWdlIGNhdGVnb3J5IGFzIHZhcmlhYmxlcyB3aGljaCB3ZSBuZWVkIHRvIHJlc2hhcGUuDQotIEFsc28gVnVsbmVyYWJsZSBDYXRlZ29yeSBhcyB2YXJpYWJsZXMgd2hpY2ggYWxzbyBuZWVkcyB0byBiZSByZXNoYXBlDQpgYGB7cn0NCiMgcmVzaGFwZSBhZ2UgY2F0ZWdvcnkNCmRhdGFzZXRfdDEgPC0gZGF0YXNldCAlPiUgZ2F0aGVyKGMoIkFnZV8xOV9VbmRlciIsIkFnZV8xOV82NCIsIkFnZV82NV84NCIsIkFnZV84NV9hbmRfT3ZlciIpLGtleT0iQWdlIix2YWx1ZT0iQWdlX1BvcHVsYXRpb24iKQ0KIyByZXNoYXBlIFZ1bG5lcmFibGUgQ2F0ZWdvcnkNCmRhdGFzZXRfdDIgPC0gZGF0YXNldF90MSAlPiUgIGdhdGhlcihjKCJOb19IU19EaXBsb21hIiwiVW5lbXBsb3llZCIsIlNldl9Xb3JrX0Rpc2FibGVkIiwiTWFqb3JfRGVwcmVzc2lvbiIsIlJlY2VudF9EcnVnX1VzZSIpLGtleT0iVnVsbmVyYWJsZV9DYXRlZ29yeSIsIHZhbHVlPSJWdWxuZXJhYmxlX1BvcHVsYXRpb24iKSANCnN0cihkYXRhc2V0X3QyKQ0KYGBgDQoNCi0gRmFjdG9yaW5nIEFnZSBhbmQgVnVsbmVyYWJsZSBjYXRlZ29yeSANCmBgYHtyfQ0KIyBGYWN0b3JpbmcgQWdlIGFuZCBWdWxuZXJhYmxlIENhdGVnb3J5DQpBZ2VfY2F0IDwtIGMoIkFnZV8xOV9VbmRlciIsIkFnZV8xOV82NCIsIkFnZV82NV84NCIsIkFnZV84NV9hbmRfT3ZlciIpDQpBZ2VfQ2F0X2xhYmVscyA8LSBjKCI8MTkiLCIxOS02NCIsIjY1LTg0IiwiODUrIikNCnZ1bG5lcmFibGVfY2F0IDwtIGMoIk5vX0hTX0RpcGxvbWEiLCJVbmVtcGxveWVkIiwiU2V2X1dvcmtfRGlzYWJsZWQiLCJNYWpvcl9EZXByZXNzaW9uIiwiUmVjZW50X0RydWdfVXNlIikNCmRhdGFzZXRfdDIgPC0gbXV0YXRlKGRhdGFzZXRfdDIgDQogICAgICAgICAgICAgICAgICAgICAgICAsQWdlX0NhdD1mYWN0b3IoQWdlLGxldmVscz1BZ2VfY2F0LCBsYWJlbHM9QWdlX0NhdF9sYWJlbHMsb3JkZXJlZCA9IFRSVUUpDQogICAgICAgICAgICAgICAgICAgICAgICAsVnVsbmVyYWJsZV9DYXQ9ZmFjdG9yKFZ1bG5lcmFibGVfQ2F0ZWdvcnksbGV2ZWxzPXZ1bG5lcmFibGVfY2F0KQ0KICAgICAgICAgICAgICAgICAgICAgICApICU+JSBzZWxlY3QoLWMoIkFnZSIsIlZ1bG5lcmFibGVfQ2F0ZWdvcnkiKSkNCnN0cihkYXRhc2V0X3QyKQ0KYGBgDQoNCi0gU3VtbWFyeSBvZiBBZ2UgQ2F0ZWdvcnl3aXNlIFBvcHVsYXRpb24NCmBgYHtyfQ0Kc3VtbWFyeShkYXRhc2V0X3QyJEFnZV9Qb3B1bGF0aW9uKQ0KYGBgDQoNCi0gU3VtbWFyeSBvZiBWdWxuZXJhYmxlIFBvcHVsYXRpb24NCmBgYHtyfQ0Kc3VtbWFyeShkYXRhc2V0X3QyJFZ1bG5lcmFibGVfUG9wdWxhdGlvbikNCmBgYA0KDQojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIElJIA0KDQotIERhdGFzZXQgaGFzIEVIX1RpbWVfU3BhbiB3aGljaCBjb250YWlucyAyIHllYXJzKHNlcGFyYXRlZCBieSAiLSIpIHN0YXJ0IGFuZCBlbmQgeWVhciBvZiByZXBvcnRpbmcgZGF0YS4gU28sIHNlcGFyYXRlIHdpbGwgY3JlYXRlIHR3byBuZXcgdmFyaWFibGUoIlN0YXJ0X1llYXIiLCJFbmRfWWVhciIpLg0KYGBge3J9DQpkYXRhc2V0X3QzIDwtIGRhdGFzZXRfdDIgJT4lIHNlcGFyYXRlKEVIX1RpbWVfU3BhbiwgaW50bz1jKCJTdGFydF9ZZWFyIiwiRW5kX1llYXIiKSxzZXA9Ii0iKQ0Kc3RyKGRhdGFzZXRfdDMpDQpgYGANCg0KIyMJU2NhbiBJIA0KDQotIERhdGEgY29udGFpbnMgdmFsdWVzIGxpa2UgLTk5OTksIC0yMjIyLCAtMjIyLCAtMiB3aGljaCByZXByZXNlbnQgTkEvTm90IGF2YWlsYWJsZS8gTm8gZGV0YWlscy4NCi0gRmlyc3Qgc3RlcCwgZmluZCBtaXNzaW5nIHZhbHVlcyBieSB2YXJpYWJsZXMNCmBgYHtyfQ0KIyBGaW5kaW5nIE1pc3NpbmcgdmFsdWVzDQpjb2xTdW1zKGlzLm5hKGRhdGFzZXRfdDMpKQ0KYGBgDQoNCmBgYHtyfQ0KIyB0b3RhbCBtaXNzaW5nIHZhbHVlcw0Kc3VtKGlzLm5hKGRhdGFzZXRfdDMpKQ0KYGBgDQoNCi0gTWlzc2luZyBkYXRhIGlzIHZlcnkgbGVzcyBjb21wYXJlIHRvIHRvdGFsIG5vIG9mIG9ic2VydmF0aW9uLCBzbyB3ZSBjYW4gb21pdCB0aGVtLiBBbmQgT3RoZXIgcmVhc29uIGlzLCBJZiB3ZSByZXBsYWNlIHRoZSB3aXRoIG1lYW4gb3IgbWVkaWFuIG9mIGluZGl2aWR1YWwgdmFyaWFibGUsIGl0IGNhbiBsZWFkIHRvIHdyb25nIHJlc3VsdC4NCmBgYHtyfQ0KIyBPbWl0dGluZyBtaXNzaW5nIHZhbHVlcw0KZGF0YXNldF90NCA8LSBuYS5vbWl0KGRhdGFzZXRfdDMpDQpzdW0oaXMubmEoZGF0YXNldF90NCkpDQpgYGANCg0KLSBDaGVjayBmb3Igc3BlY2lhbCB2YWx1ZXMgSW5mLC1JbmYsIE5hTiBpbiBBZ2VfUG9wdWxhdGlvbg0KYGBge3IsIGVjaG89VFJVRX0NCiMgVG90YWwgTmFOIHZhbHVlcyBpbiBBZ2VfUG9wdWxhdGlvbg0Kc3VtKGlzLm5hbihkYXRhc2V0X3Q0JEFnZV9Qb3B1bGF0aW9uKSkNCiMgVG90YWwgSW5mLy1JbmYgdmFsdWVzIGluIEFnZV9Qb3B1bGF0aW9uDQpzdW0oaXMuaW5maW5pdGUoZGF0YXNldF90NCRBZ2VfUG9wdWxhdGlvbikpDQpgYGANCg0KLSBDaGVjayBmb3Igc3BlY2lhbCB2YWx1ZXMgSW5mLC1JbmYsIE5hTiBpbiBWdWxuZXJhYmxlX1BvcHVsYXRpb24NCmBgYHtyLCBlY2hvPVRSVUV9DQojIFRvdGFsIE5hTiB2YWx1ZXMgaW4gVnVsbmVyYWJsZV9Qb3B1bGF0aW9uDQpzdW0oaXMubmFuKGRhdGFzZXRfdDQkVnVsbmVyYWJsZV9Qb3B1bGF0aW9uKSkNCiMgVG90YWwgSW5mLy1JbmYgdmFsdWVzIGluIFZ1bG5lcmFibGVfUG9wdWxhdGlvbg0Kc3VtKGlzLmluZmluaXRlKGRhdGFzZXRfdDQkVnVsbmVyYWJsZV9Qb3B1bGF0aW9uKSkNCmBgYA0KDQojIwlTY2FuIElJDQoNCi0gU2Nhbm5pbmcgb3V0bGllcnMgZm9yIEFnZV9Qb3B1bGF0aW9uIGFuZCBWdWxuZXJhYmxlX1BvcHVsYXRpb24gdXNpbmcgei1zY29yZT4zIGFuZCBib3hwbG90IG1ldGhvZC4NCmBgYHtyfQ0KIyBaLVNjb3JlIGZvciBBZ2UgUG9wdWxhdGlvbg0Kei5zY29yZXNfYWdlIDwtIGRhdGFzZXRfdDQkQWdlX1BvcHVsYXRpb24gJT4lIHNjb3Jlcyh0eXBlPSJ6IikNCmxlbmd0aCAod2hpY2goIGFicyh6LnNjb3Jlc19hZ2UpID4zICkpDQpgYGANCg0KLSBBZ2UgUG9wdWxhdGlvbiBoYXMgbm8gdmFsdWUgd2hpY2ggaGFzIHouc2NvcmU+My4gSXQgbWVhbnMgQWdlIHBvcHVsYXRpb24gaGFzIG5vIG91dGxpZXJzLg0KYGBge3J9DQojIEJveHBsb3QgZm9yIEFnZSBQb3B1bGF0aW9uDQpib3hwbG90KGRhdGFzZXRfdDQkQWdlX1BvcHVsYXRpb24sIG1haW4gPSAiQm94UGxvdCBvZiBBZ2UgUG9wdWxhdGlvbiIsIHlsYWIgPSAiUG9wdWxhdGlvbiIpDQpgYGANCg0KLSBCeSBzdHVkeWluZyB6LnNjb3JlIGFuZCBib3hwbG90LCB3ZSBjYW4gY29uY3VsZGUgQWdlX1BvcHVsYXRpb24gaGFzIG5vIG91dGxpZXJzLg0KYGBge3J9DQojIFotU2NvcmUgZm9yIFZ1bG5lcmFibGUgUG9wdWxhdGlvbg0Kei5zY29yZXNfdnVsIDwtIGRhdGFzZXRfdDQkVnVsbmVyYWJsZV9Qb3B1bGF0aW9uICU+JSBzY29yZXModHlwZT0ieiIpDQpsZW5ndGggKHdoaWNoKCBhYnMoei5zY29yZXNfdnVsKSA+MyApKQ0KYGBgDQoNCi0gSWRlbnRpZnkgb3V0bGllcnMgYnkgYm94cGxvdA0KYGBge3J9DQojIEJveHBsb3QgZm9yIFZ1bG5lcmFibGUgUG9wdWxhdGlvbg0KYm94cGxvdChkYXRhc2V0X3Q0JFZ1bG5lcmFibGVfUG9wdWxhdGlvbiwgbWFpbiA9ICJCb3hQbG90IG9mIFZ1bG5lcmFibGUgUG9wdWxhdGlvbiIsIHlsYWIgPSAiUG9wdWxhdGlvbiIpDQpgYGANCg0KLSBBcyBwZXIgei5zY29yZSBhbmQgYm94cGxvdCwgVnVsbmVyYWJsZSBQb3B1bGF0aW9uIGhhcyB+NDQ4IG91dGxpZXIuIFdlIGNhbiBoYW5kbGUgdGhvc2UgdXNpbmcgY2FwcGluZyBmdW5jdGlvbiBhbmQgcmVzdWx0IHdpbGwgbm90IGhhdmUgbXVjaCBhZmZlY3QuDQpgYGB7cn0NCiMgQ2FwcGluZyBmdW5jdGlvbiB0byByZXBsYWNlIHRoZSBvdXRsaWVyIHZhbHVlIHdpdGggMXN0IGFuZCAzcmQgUXVhbnRpbGllcy4NCmNhcCA8LSBmdW5jdGlvbih4KXtxdWFudGlsZXMgPC0gcXVhbnRpbGUoeCxjKDAuMDUsMC4yNSwwLjc1LDAuOTUpKQ0KICB4W3ggPCBxdWFudGlsZXNbMl0gLSAxLjUqSVFSKHgpXSA8LSBxdWFudGlsZXNbMV0NCiAgeFt4ID4gcXVhbnRpbGVzWzNdICsgMS41KklRUih4KV0gPC0gcXVhbnRpbGVzWzRdDQogIHgNCn0NCiMgUmVwbGFjZSBPdXRsaWVyIHZhbHVlcyB1c2luZyBjYXBwaW5nIGZ1bmN0aW9uDQpkYXRhc2V0X3Q0JFZ1bG5lcmFibGVfUG9wdWxhdGlvbltpcy5uYShkYXRhc2V0X3Q0JFZ1bG5lcmFibGVfUG9wdWxhdGlvbikgIT0gVFJVRV0gPC0NCmRhdGFzZXRfdDQkVnVsbmVyYWJsZV9Qb3B1bGF0aW9uW2lzLm5hKGRhdGFzZXRfdDQkVnVsbmVyYWJsZV9Qb3B1bGF0aW9uKSAhPSBUUlVFXSAlPiUgY2FwKCkNCiMgQWZ0ZXIgY2FwcGluZyBib3hwbG90DQpib3hwbG90KGRhdGFzZXRfdDQkVnVsbmVyYWJsZV9Qb3B1bGF0aW9uLCBtYWluID0gIkJveFBsb3Qgb2YgVnVsbmVyYWJsZSBQb3B1bGF0aW9uIiwgeWxhYiA9ICJQb3B1bGF0aW9uIikNCmBgYA0KDQotIEFmdGVyIGNhcHBpbmcgb2Ygb3V0bGllciwgei5zY29yZSBjaGVjayBmb3IgVnVsbmVyYWJsZV9Qb3B1bGF0aW9uIGFuZCBjb3VudCBaLlNjb3JlPjMgaXMgemVyby4gaXQgbWVhbnMgVnVsbmVyYWJsZV9Qb3B1bGF0aW9uIGhhcyBubyBvdXRsaWVycy4NCmBgYHtyfQ0KIyBaLVNjb3JlIGZvciBWdWxuZXJhYmxlIFBvcHVsYXRpb24NCnouc2NvcmVzX3Z1bCA8LSBkYXRhc2V0X3Q0JFZ1bG5lcmFibGVfUG9wdWxhdGlvbiAlPiUgc2NvcmVzKHR5cGU9InoiKQ0KbGVuZ3RoICh3aGljaCggYWJzKHouc2NvcmVzX3Z1bCkgPjMgKSkNCmBgYA0KDQojIwlUcmFuc2Zvcm0gDQoNCi0gVHJhbnNmb3JtaW5nIEFnZSBQb3B1bGF0aW9uIGRhdGENCmBgYHtyfQ0KaGlzdChkYXRhc2V0X3Q0JEFnZV9Qb3B1bGF0aW9uLCBtYWluPSJIaXN0b2dyYW0gZm9yIEFnZSBQb3B1bGF0aW9uIiwgeGxhYj0iTWVhbiBvZiBBZ2UgcG9wdWxhdGlvbiIpDQphYmxpbmUodiA9IG1lYW4oZGF0YXNldF90NCRBZ2VfUG9wdWxhdGlvbiksIGNvbD0icmVkIiwgbHdkPTMsIGx0eT0yKQ0KYGBgDQoNCi0gSGlzdG9ncmFtIG9mIEFnZSBQb3B1bGF0aW9uIHNob3csIGl0IGlzIG5vdCBub3JtYWxpemUgZGF0YS4gQnV0IEFnZSBncm91cCBpcyBtdWx0aSB2YXJpYXRlIHZhcmlhYmxlIHNvIGl0IGNhbid0IGJlIGNvbnZlcnRlZCBpbnRvIG5vcm1hbGl6ZSBkYXRhLiBFdmVuIGlmIHdlIGFwcGx5IG5vcm1hbGl6ZSB0ZWNobmlxdWUsIHJlc3VsdCBtaWdodCBiZSBhcyBiZWxvdy4NCmBgYHtyfQ0KIyBBcHBseSBib3hjb3ggd2l0aCBsYW1kYSBBdXRvIHRvIG5vcm1hbGl6ZSB0aGUgZGF0YQ0KZGF0YXNldF90NCRBZ2VfUG9wdWxhdGlvbl9Cb3ggPC0gQm94Q294KGRhdGFzZXRfdDQkQWdlX1BvcHVsYXRpb24sIGxhbWJkYSA9ICJhdXRvIikNCmRhdGFzZXRfdDQkQWdlX1BvcHVsYXRpb25fQm94PC1zY2FsZShkYXRhc2V0X3Q0JEFnZV9Qb3B1bGF0aW9uX0JveCxjZW50ZXI9VFJVRSxzY2FsZT1UUlVFKQ0KaGlzdChkYXRhc2V0X3Q0JEFnZV9Qb3B1bGF0aW9uX0JveCwgbWFpbj0iQWZ0ZXIgdHJhbnNmb3JtYXRpb24sIEhpc3RvZ3JhbSBmb3IgQWdlIFBvcHVsYXRpb24iLCB4bGFiPSJNZWFuIG9mIEFnZSBwb3B1bGF0aW9uIikNCmFibGluZSh2ID0gbWVhbihkYXRhc2V0X3Q0JEFnZV9Qb3B1bGF0aW9uX0JveCksIGNvbD0icmVkIiwgbHdkPTMsIGx0eT0yKQ0KYGBgDQoNCi0gVHJhbnNmb3JtaW5nIFZ1bG5lcmFibGUgUG9wdWxhdGlvbiBkYXRhDQpgYGB7cn0NCmhpc3QoZGF0YXNldF90NCRWdWxuZXJhYmxlX1BvcHVsYXRpb24sIG1haW49Ikhpc3RvZ3JhbSBmb3IgVnVsbmVyYWJsZSBQb3B1bGF0aW9uIiwgeGxhYj0iTWVhbiBvZiBWdWxuZXJhYmxlIHBvcHVsYXRpb24iKQ0KYWJsaW5lKHYgPSBtZWFuKGRhdGFzZXRfdDQkVnVsbmVyYWJsZV9Qb3B1bGF0aW9uKSwgY29sPSJyZWQiLCBsd2Q9MywgbHR5PTIpDQpgYGANCg0KLSBIaXN0b2dyYW0gb2YgVnVsbmVyYWJsZSBQb3B1bGF0aW9uIHNob3csIGl0IGlzIG5vdCBub3JtYWxpemUgZGF0YS4gV2UgY2FuIGNvbnZlcnQgaXQgYnkgYXBwbHlpbmcgYm94Y294IG1ldGhvZCB3aXRoIG9uZSBvdXRsaWVyIHdoaWNoIHdlIGNhbiBpZ25vcmUuDQpgYGB7cn0NCiMgQXBwbHkgYm94Y294IHdpdGggbGFtZGEgQXV0byB0byBub3JtYWxpemUgdGhlIGRhdGENCmRhdGFzZXRfdDQkVnVsbmVyYWJsZV9Qb3B1bGF0aW9uX0JveF8xIDwtIEJveENveChkYXRhc2V0X3Q0JFZ1bG5lcmFibGVfUG9wdWxhdGlvbiwgbGFtYmRhID0gImF1dG8iKQ0KZGF0YXNldF90NCRWdWxuZXJhYmxlX1BvcHVsYXRpb25fQm94IDwtIEJveENveChkYXRhc2V0X3Q0JFZ1bG5lcmFibGVfUG9wdWxhdGlvbl9Cb3hfMSwgbGFtYmRhID0gImF1dG8iKQ0KaGlzdChkYXRhc2V0X3Q0JFZ1bG5lcmFibGVfUG9wdWxhdGlvbl9Cb3gsIG1haW49IkFmdGVyIHRyYW5zZm9ybWF0aW9uLCBIaXN0b2dyYW0gZm9yIFZ1bG5lcmFibGUgUG9wdWxhdGlvbiIsIHhsYWI9Ik1lYW4gb2YgVnVsbmVyYWJsZSBwb3B1bGF0aW9uIikNCmFibGluZSh2ID0gbWVhbihkYXRhc2V0X3Q0JFZ1bG5lcmFibGVfUG9wdWxhdGlvbl9Cb3gpLCBjb2w9InJlZCIsIGx3ZD0zLCBsdHk9MikNCmBgYA0KDQoNCjxicj4NCjxicj4NCg==