Introduction
For this project, we will be working on creating a multiple logistic
regression model. The data set for this project looks at the various
factors affecting an individual patient’s risk of developing coronary
heart disease (CHD) in a 10-year period of time. The response variable
in this data set is binary with 1 representing yes, the patient is at
risk of developing CHD within a 10-year period of time, and 0
representing no, the patient is not at risk of developing CHD within a
10-year period of time.
Our overall goal in this project is to create a model which has the
greatest predictive performance. We will create several candidate models
and compare them with each other to determine which model should be
selected as the final model for the prediction of an individual’s odds
of being at risk for developing CHD over a 10-year period of time. We
will use the cross-validation process to determine which of the
candidate models provides the best predictive power. We will also use
ROC analysis to determine which of the candidate models has the best
global goodness. This will allow us to see which of the candidate models
provides the best utility and quality for predictive modeling.
Data Description
I found this data set on kaggle.com on the following web page: https://www.kaggle.com/datasets/dileep070/heart-disease-prediction-using-logistic-regression/data
This data set takes a look at various medical and personal factors
which may have an impact on an individual’s risk of developing CHD
within the next 10 years. The binary response variable tells whether an
individual patient is at risk of developing CHD within the next 10
years, with a response value of 1 meaning yes they are at risk, and 0
meaning no they are not at risk.
Variables
There are 16 variables in this data set.
male: The gender of the patient. A categorical variable with 1
for “male”, 0 for “female”, and 2 for “other”.
age: The age of the patient in years. This is a quantitative,
continuous variable given as an integer value.
education: The education level of the patient. A categorical
variable with 1 for “less than high school”, 2 for “high school
diploma”, 3 for “college graduate”, and 4 for “post-college
graduate”.
currentSmoker: Whether or not the patient is currently a smoker.
A binary variable with 1 for “yes” and 0 for “no”.
cigsPerDay: The average number of cigarettes the patient smokes
in a day. This is a quantitative, continuous variable.
BPMeds: Whether or not the patient takes blood pressure
medication. A binary variable with 1 for “yes” and 0 for “no”.
prevalentStroke: Whether or not the patient has a history of
strokes. A binary variable with 1 for “yes” and 0 for “no”.
prevalentHyp: Whether or not the patient has a history of
hypertension. A binary variable with 1 for “yes” and 0 for
“no”.
diabetes: Whether or not the patient has a history of diabetes. A
binary variable with 1 for “yes” and 0 for “no”.
totChol: The patient’s total cholesterol level, given in mg/dL
(milligrams per deciliter). A quantitative, continuous
variable.
sysBP: The patient’s systolic blood pressure, given in mmHG
(millimeters of mercury). A quantitative, continuous variable.
diaBP: The patient’s diastolic blood pressure, given in mmHG
(millimeters of mercury). A quantitative, continuous variable.
BMI: The patient’s body mass index (BMI). A quantitative,
continuous variable.
heartRate: The patient’s heart rate, given in beats per minute. A
numeric, quantitative variable.
glucose: The patient’s glucose level, given in mg/dL (milligrams
per deciliter). A numeric, quantitative variable.
TenYearCHD (response variable): The binary response variable of
this data set which represents whether or not the patient has a 10-year
risk of developing Coronary Heart Disease (CHD). This response variable
is binary with 1 meaning yes, the patient does have a risk of developing
CHD in the next 10 years, and 0 meaning no, the patient does not have a
risk of developing CHD in the next 10 years.
Research
Questions
The key analytical question which I would like to investigate in this
project is:
- Can we create a model which has the highest predictive power in
regards to predicting a patient’s odds of being at risk for developing
coronary heart disease within a 10-year period of time based on the
predictor variables in this data set?
This question will serve as the basis for creating the candidate
multiple logistic regression models for this data set. We will
ultimately choose a final model of these potential candidate models
based upon our findings in regards to their predictive power. The
findings to this question could provide utility for both patients and
doctors to provide them with information relating to the odds and risks
for developing CHD and which factors significantly impact these
odds.
Some further questions to consider as a starting point for this
project include:
Is there a major difference in the predictive powers of the
candidate models we create?
Do the continuous independent variables in this data set follow a
normal distribution? And if not, is there a potential explanation for
why this may be the case?
How good is the predictive quality of our final model in regards
of predicting whether an individual will be at risk for developing CHD
in a 10-year period of time?
We will use these questions as a starting point for this project in
order to create a multiple logistic regression model which has the
greatest predictive power for predicting the odds of a patient being at
risk for developing CHD in a 10-year period based on the many factors
which play a role in this prediction.
Exploratory Data
Analysis
First, we will read in the data set from Github and we will call it
“heartdisease”.
heartdisease <- read.csv("https://raw.githubusercontent.com/JosieGallop/STA321/refs/heads/main/dataset/framingham.csv", header=TRUE)
str(heartdisease)
'data.frame': 4238 obs. of 16 variables:
$ male : int 1 0 1 0 0 0 0 0 1 1 ...
$ age : int 39 46 48 61 46 43 63 45 52 43 ...
$ education : int 4 2 1 3 3 2 1 2 1 1 ...
$ currentSmoker : int 0 0 1 1 1 0 0 1 0 1 ...
$ cigsPerDay : int 0 0 20 30 23 0 0 20 0 30 ...
$ BPMeds : int 0 0 0 0 0 0 0 0 0 0 ...
$ prevalentStroke: int 0 0 0 0 0 0 0 0 0 0 ...
$ prevalentHyp : int 0 0 0 1 0 1 0 0 1 1 ...
$ diabetes : int 0 0 0 0 0 0 0 0 0 0 ...
$ totChol : int 195 250 245 225 285 228 205 313 260 225 ...
$ sysBP : num 106 121 128 150 130 ...
$ diaBP : num 70 81 80 95 84 110 71 71 89 107 ...
$ BMI : num 27 28.7 25.3 28.6 23.1 ...
$ heartRate : int 80 95 75 65 85 77 60 79 76 93 ...
$ glucose : int 77 76 70 103 85 99 85 78 79 88 ...
$ TenYearCHD : int 0 0 0 1 0 0 1 0 0 0 ...
We will make a copy of the data set called “heartdisease0” which will
be the data set we will analyze and transform through the exploratory
data analysis.
heartdisease0 <- heartdisease
Fixing the Missing
Observations
When looking through the data set, I noticed that some observations
appeared to be missing from the data set, as they had values of “NA” for
certain variables. Before we can begin with the logistic regression,
this is something that we should look into.
First, let’s see how many values are missing for each of the
variables.
colSums(is.na(heartdisease0))
male age education currentSmoker cigsPerDay
0 0 105 0 29
BPMeds prevalentStroke prevalentHyp diabetes totChol
53 0 0 0 50
sysBP diaBP BMI heartRate glucose
0 0 19 1 388
TenYearCHD
0
We can see that the variables education, cigsPerDay, BPMeds, totChol,
BMI, heartRate, and glucose all have missing observations.
It is important to note that single imputation methods that could be
used to fix the missing observations of the variables could lead to
potential skew in their distributions. So, instead we will use multiple
imputation methods to fill in these missing observations with randomly
approximated values. Out of the variables with missing values, none of
the variables have the majority of their data entries missing, so it
seems suitable to fill in these missing observations with approximated
values in order to prevent these entries from coming up as NA within the
data set. However, it is important to be mindful of the fact that
filling in these missing entries could still lead to a potential skew or
inaccuracy in the distribution of these variables after filling in the
missing observations. In order to properly handle this, we will first
fix the missing values and then check the distributions of the variables
to ensure that they are normally distributed, or are practically
important enough variables to include within the final multiple logistic
regression model.
Multiple Imputation
of Missing Observations
We will use multiple imputation to fill in the missing values of the
observations. Using this multiple imputation method will use a randomly
iterated method to fill in the missing observations within the data set.
This will help ensure that the missing observations are filled in the
best way possible by handling missing values in a way that reduces the
chance of false prediction. We will use the Multiple Imputation using
Chained Equations (MICE) function to use multiple imputation to fill in
the missing observations.
We will store the results of the multiple imputation in an object
called “mice” for now.
set.seed(1)
mice <- mice(heartdisease0, method = "cart")
iter imp variable
1 1 education cigsPerDay BPMeds totChol BMI heartRate glucose
1 2 education cigsPerDay BPMeds totChol BMI heartRate glucose
1 3 education cigsPerDay BPMeds totChol BMI heartRate glucose
1 4 education cigsPerDay BPMeds totChol BMI heartRate glucose
1 5 education cigsPerDay BPMeds totChol BMI heartRate glucose
2 1 education cigsPerDay BPMeds totChol BMI heartRate glucose
2 2 education cigsPerDay BPMeds totChol BMI heartRate glucose
2 3 education cigsPerDay BPMeds totChol BMI heartRate glucose
2 4 education cigsPerDay BPMeds totChol BMI heartRate glucose
2 5 education cigsPerDay BPMeds totChol BMI heartRate glucose
3 1 education cigsPerDay BPMeds totChol BMI heartRate glucose
3 2 education cigsPerDay BPMeds totChol BMI heartRate glucose
3 3 education cigsPerDay BPMeds totChol BMI heartRate glucose
3 4 education cigsPerDay BPMeds totChol BMI heartRate glucose
3 5 education cigsPerDay BPMeds totChol BMI heartRate glucose
4 1 education cigsPerDay BPMeds totChol BMI heartRate glucose
4 2 education cigsPerDay BPMeds totChol BMI heartRate glucose
4 3 education cigsPerDay BPMeds totChol BMI heartRate glucose
4 4 education cigsPerDay BPMeds totChol BMI heartRate glucose
4 5 education cigsPerDay BPMeds totChol BMI heartRate glucose
5 1 education cigsPerDay BPMeds totChol BMI heartRate glucose
5 2 education cigsPerDay BPMeds totChol BMI heartRate glucose
5 3 education cigsPerDay BPMeds totChol BMI heartRate glucose
5 4 education cigsPerDay BPMeds totChol BMI heartRate glucose
5 5 education cigsPerDay BPMeds totChol BMI heartRate glucose
We will create a new data frame called “heartdisease1” to represent
the corrected data set that will have no missing values after multiple
imputation. We will convert the results of the multiple imputation from
a large mids object back to a regular data frame. This will be used for
the future analysis and we will call this object “heartdisease1”.
heartdisease1 <-mice::complete(mice,2)
Now that we have used the multiple imputation method to fill in all
of the missing observations, let’s double check that there are no more
missing observations. All of the variables should now have a value of
zero missing observations.
colSums(is.na(heartdisease1))
male age education currentSmoker cigsPerDay
0 0 0 0 0
BPMeds prevalentStroke prevalentHyp diabetes totChol
0 0 0 0 0
sysBP diaBP BMI heartRate glucose
0 0 0 0 0
TenYearCHD
0
As we can see, all of the variables now have zero missing
observations, so we successfully fixed all of the missing values by
filling them in with multiple imputation by the use of the mice
function. The revised data set “heartdisease1” has no missing
observations, so we will use this for further analysis and for creating
the multiple logistic regression model in the future steps of this
project.
Fixing Variable
Types
One other thing I noticed while looking through the data set is that
the variable “cigsPerDay” is given as a character variable even though
it should be a numeric variable. This variable is a measure of the
number of cigarettes a patient smokes in a day, so it should be reported
as a numeric variable since it is a continuous range of possible values
and not collected as categories. So, let’s convert cigsPerDay from a
character variable to a numeric variable. We will use the as.numeric()
function to convert cigsPerDay to a numeric variable.
heartdisease1$cigsPerDay <- as.numeric(heartdisease1$cigsPerDay)
Now, the cigsPerDay variable is correctly given as a numeric
variable.
The variable of age should also be given as a numeric value, but is
is not so we will convert this variable to a numeric as well.
heartdisease1$age <- as.numeric(heartdisease1$age)
The variable of age is now correctly given as a numeric value.
Additionally, the variable BPMeds is given as a character, however
this is a binary variable so it should be given as an integer variable
with values 0 and 1 like the other binary variables in the data set. We
will convert this variable from a character to an integer. We will use
the as.integer() function to do this conversion.
heartdisease1$BPMeds <- as.integer(heartdisease1$BPMeds)
Now, the BPMeds variable is correctly given as a binary, integer
variable.
Another issue is that the variable for education is supposed to be
categorical with each number representing a different category of
education level. However, this variable is given as an integer variable.
So, we will fix this by making education a character variable.
heartdisease1$education <- as.character(heartdisease1$education)
The education variable is now correctly given as a categorical
variable.
Now, all of the variables in the data set are given in the correct
types that they should be given as.
Checking the Variable
Distributions
Before we begin with creating and comparing the multiple logistic
regression models, we should first check the distributions of the
variables in the data set to ensure that they meet the criteria of being
approximately normally distributed, for the quantitative variables. Or,
if the variables do not appear to follow a normal distribution, we will
see if they are practically important enough to be included within the
model building process despite their lack of a normal distribution. We
will take a look at some of the variables, particuarelly some of the
quanitiative variables which had missing values that were filled in
through the multiple imputation process.
totChol
Distribution
totChol was one of the variables that had some missing observations
that were filled in during the previous steps. So, we should definetly
check the distribution of this variable.
ylimit = max(density(heartdisease1$totChol)$y)
hist(heartdisease1$totChol, probability = TRUE, main = "totChol Distribution", xlab="totChol",
col = "aliceblue", border="cornflowerblue")
lines(density(heartdisease1$totChol, adjust=2), col="darkorchid")

Overall, totChol appears to be unimodal and approximately normally
distributed. Therefore we can say that this variable is safe to include
within the multiple logistic regression model building process and that
the process of filling in the missing observations did not lead to any
severe concerns for the distribution of this variable.
BMI
Distribution
BMI is another variable that had missing observations that were
filled in during the previous steps. We will check its distribution to
make sure it appears to be approximately normally distributed.
ylimit = max(density(heartdisease1$BMI)$y)
hist(heartdisease1$BMI, probability = TRUE, main = "BMI Distribution", xlab="BMI",
col = "aliceblue", border="cornflowerblue")
lines(density(heartdisease1$BMI, adjust=2), col="darkorchid")

The distribution for BMI is unimodal and appears to be approximately
normally distributed. It appears that the majority of individuals have a
BMI somewhere in the range of 20-30, with the vast majority of the data
falling within this range. This allows us to conclude that it is safe to
include the variable of BMI within the multiple logistic regression
model building process and that the process of filling in the missing
values did not lead to any major concerns with the distribution of this
variable.
Glucose
Distribution
The variable glucose was another variable that had missing
observations which were filled in during the previous steps. We will
check its distribution to make sure that everything looks alright.
ylimit = max(density(heartdisease1$glucose)$y)
hist(heartdisease1$glucose, probability = TRUE, main = "glucose", xlab="glucose",
col = "aliceblue", border="cornflowerblue")
lines(density(heartdisease1$glucose, adjust=2), col="darkorchid")

The variable glucose is unimodal and appears to be approximately
normally distributed with the exception of a few outliers to the right.
The most common glucose value appears to be around 75, with the
histogram peaking around this value. Despite the few outliers, we will
keep this variable in the final model since a patient’s glucose level is
a medically important variable which would be helpful to know in order
to assess a patient’s odds of being at risk for developing CHD.
cigsPerDay
Distribution
cigsPerDay was another variable that had missing observations which
were filled in during the previous steps. So, we should check its
distribution to make sure things look alright.
ylimit = max(density(heartdisease1$cigsPerDay)$y)
hist(heartdisease1$cigsPerDay, probability = TRUE, main = "cigsPerDay", xlab="cigsPerDay",
col = "aliceblue", border="cornflowerblue")
lines(density(heartdisease1$cigsPerDay, adjust=2), col="darkorchid")

The variable cigsPerDay appears to be very notably skewed to the
right. This can be attributed to that this variable represents the
number of cigarettes a patient smokes per day. Many of the patients
included in the data collection were not smokers, so they would have
reported a value of 0 cigarettes smoked per day. This can explain the
skew to the right of this variable, because non-smokers would report a
value of 0 while smokers would report a value greater than 0 that
represents the number of cigarettes they smoke in a day. This is a
pratically important variable regardless of its skew, because smoking is
a major risk factor for conditions like CHD. Additionally, this is an
important piece of information, because doctors would want to know how
many cigarettes their patients smoke in a day, because this has a
significant impact on the patient’s risk factors. So, we will keep this
variable in the final model despite its skew because it is an important
variable in regards to a patient’s potential risk factors for developing
CHD. But, it is important to keep in mind that this variable is skewed
due to it being representative of both non-smokers and smokers.
heartRate
Distribution
The variable heartRate was another one which had some missing
observations that needed to be filled in during previous steps. We will
check its distribution to ensure that everything looks alright.
ylimit = max(density(heartdisease1$heartRate)$y)
hist(heartdisease1$heartRate, probability = TRUE, main = "heartRate", xlab="heartRate",
col = "aliceblue", border="cornflowerblue")
lines(density(heartdisease1$heartRate, adjust=2), col="darkorchid")

The distribution for heart rate is unimodal and approximately
normally distributed without any notable skew or outliers that are
apparent in its density plot. This allows us to conclude that this
variable is safe to include within the multiple logistic regression
model building process and that the process of filling in the missing
values did not lead to any issues in its distribution.
Overall
Findings
We have checked the distributions of the variables which had missing
observations that were filled in during the previous steps of this
project along with other important quantitative variables in this data
set. We ensured that the variables either follows a distribution that
appears to be approximately normal, or are practically important enough
to be included in the multiple logistic regression model building
process otherwise.
The only variable that did not appear to follow an approximately
normal distribution was cigsPerDay. However, the skewness seen in this
variable’s distribution can be attributed to the fact that this data was
collected amongst both smokers and non-smokers. So, non-smokers reported
values of 0 cigarettes smoked per day, while smokers reported values
that were greater than zero. This appeared to the distribution for this
variable appearing to be skewed to the right. However, this is a
variable that is practically important because the number of cigarettes
a patient smokes per day can have a significant impact on their odds of
being at risk for developing CHD. Due to the practical importance of
this variable, it must still be included within the multiple logistic
regression model building process.
Altogether, we have ensured that the variables in this data set
appear to be good enough to use within the model building process. So,
now we will begin with the process of building the candidate multiple
logistic regression models.
Data Split
We will now split the data up into training and testing data. We will
randomly split the data so that 80% of the data will be used for
training and 20% of the data will be used for testing. By splitting the
data up into the training and the testing data, this will allow us to
build the candidate models and analyze their predictive performances. We
will use the split data to conduct the cross validation process to
analysis the predictive power and performances of each of the three
candidate models we will investigate. This will allow us to eventually
determine which of these three models is the ideal choice for our final
model based upon its overall predictive power.
# Split the data into 80% training and 20% testing.
n <- dim(sd.heartdisease)[1]
train.n <- round(0.8*n)
train.id <- sample(1:n, train.n, replace = FALSE)
train <- sd.heartdisease[train.id, ]
test <- sd.heartdisease[-train.id, ]
Now, our data has been split up into a training and a testing data
set, with 80% of the data for training and the remaining 20% for
testing. The observations were split up randomly amongst these two data
sets. We will specifically use the training data for the cross
validation process. This process will allow us to identify which
multiple logistic regression model is the best model for the purpose of
prediction. This will allow us to select a model which predicts the odds
of an individual being at risk for developing CHD with the highest
quality of prediction.
Best Model
Identification
Now that our variables have been checked and standardized to ensure
their predictive performance being the best that it possibly can be, we
will begin with the model building process. We will look at three
potential, candidate models for the multiple logistic regression and
determine which one has the best predictive performance.
Descriptions of the
Three Candidate Models
We will take a look into the specifications of the three candidate
multiple logistic regression models.
Full Model
The first of the three models will be the full model, with all of the
variables included. This full model will use all of the variables in
order to create a multiple logistic regression to predict the odds of a
patient being at risk for developing CHD in a 10-year period.
The regression equation for this full model is represented as:
TenYearCHD = male + sd.age + education + currentSmoker +
sd.cigsPerDay + BPMeds + prevalentStroke + prevalentHyp + diabetes +
sd.totChol + sd.sysBP + sd.diaBP + sd.BMI + sd.heartRate +
sd.glucose
We will find the specific multiple logisitic regression equation for
this full model.
full.model = glm(TenYearCHD ~ male + sd.age + education + currentSmoker + sd.cigsPerDay + BPMeds + prevalentStroke + prevalentHyp + diabetes + sd.totChol + sd.sysBP + sd.diaBP + sd.BMI + sd.heartRate + sd.glucose,
family = binomial(link = "logit"),
data = sd.heartdisease)
kable(summary(full.model)$coef,
caption = "Full Model Summary of the Inferential Statistics")
Full Model Summary of the Inferential Statistics
(Intercept) |
-2.2024269 |
0.1240704 |
-17.7514313 |
0.0000000 |
male |
0.4852112 |
0.1013449 |
4.7877196 |
0.0000017 |
sd.age |
0.5168830 |
0.0539408 |
9.5824163 |
0.0000000 |
education2 |
-0.2356171 |
0.1154925 |
-2.0401079 |
0.0413396 |
education3 |
-0.1026466 |
0.1376433 |
-0.7457430 |
0.4558227 |
education4 |
0.0115144 |
0.1519726 |
0.0757666 |
0.9396048 |
currentSmoker |
0.0219380 |
0.1443470 |
0.1519811 |
0.8792019 |
sd.cigsPerDay |
0.2507207 |
0.0679008 |
3.6924543 |
0.0002221 |
BPMeds |
0.3270416 |
0.2170889 |
1.5064870 |
0.1319422 |
prevalentStroke |
0.9388714 |
0.4468276 |
2.1011937 |
0.0356240 |
prevalentHyp |
0.2311662 |
0.1287922 |
1.7948770 |
0.0726733 |
diabetes |
0.0912436 |
0.3005700 |
0.3035687 |
0.7614565 |
sd.totChol |
0.0803445 |
0.0457538 |
1.7560185 |
0.0790852 |
sd.sysBP |
0.3074739 |
0.0783167 |
3.9260304 |
0.0000864 |
sd.diaBP |
-0.0327142 |
0.0713895 |
-0.4582495 |
0.6467732 |
sd.BMI |
0.0071253 |
0.0482202 |
0.1477649 |
0.8825283 |
sd.heartRate |
-0.0137062 |
0.0467007 |
-0.2934898 |
0.7691478 |
sd.glucose |
0.1729621 |
0.0500142 |
3.4582600 |
0.0005437 |
The equation for the multiple logistic regression equation of the
full model is given as follows:
log p/(1-p) = -2.2024 + 0.4852 * male + 0.5169 * sd.age - 0.2356 *
education2 - 0.1026 * education3 + 0.0115 * education4 + 0.0219 *
currentSmoker+ 0.2507 * sd.cigsPerDay + 0.3270 * BPMeds + 0.9389 *
prevalentStroke + 0.2312 * prevalentHyp + 0.0912 * diabetes + 0.0803 *
sd.totChol + 0.3075 * sd.sysBP - 0.0327 * sd.diaBP + 0.0071 * sd.BMI -
0.0137 * sd.heartRate + 0.1730 * sd.glucose
Reduced Model
The second of the three models will be the reduced model. This model
will consist only of the most practically important variables within the
context of this situation, using various factors to best predict the
odds of an individual being at risk for developing CHD. The United
States National Library of Medicine of the National Institutes of Health
(NIH), the most notable risk factors for an individual being at risk of
developing CHD are cigarette smoking, blood pressure, and cholesterol
levels. In this data set, there are two variables related to smoking,
currentSmoker, whether a patient is currently a smoker or not, and
cigsPerDay which is was scaled to sd.cigsPerDay, how many cigarettes a
patient smokes in a day. There are also two variables related to blood
pressure, sysBP and diaBP, for systolic blood pressure and diastolic
blood pressure. Both of these blood pressure variables were scaled and
are now given as sd.sysBP and sd.diaBP. There is also a variable
included in the data set for a patient’s total cholesterol levels,
totChol, which was scaled and is now given as sd.totChol. These five
variables in the data set represent the key risk factors that the
medical report from the NIH stated as being the most significant in
predicting a patient’s risk for CHD. So, our reduced model will consist
only of these particular variables.
The general regression equation for this reduced model is represented
as:
TenYearCHD = currentSmoker + sd.cigsPerDay + sd.sysBP + sd.diaBP +
sd.totChol
We will find the specific multiple logistic regression equation for
this reduced model.
reduced.model = glm(TenYearCHD ~ currentSmoker + sd.cigsPerDay + sd.sysBP + sd.diaBP + sd.totChol,
family = binomial(link = "logit"),
data = sd.heartdisease)
kable(summary(reduced.model)$coef,
caption = "Reduced Model Summary of the Inferential Statistics")
Reduced Model Summary of the Inferential Statistics
(Intercept) |
-1.7675361 |
0.0822320 |
-21.494511 |
0.0000000 |
currentSmoker |
-0.1443498 |
0.1392986 |
-1.036262 |
0.3000800 |
sd.cigsPerDay |
0.2683287 |
0.0637373 |
4.209920 |
0.0000255 |
sd.sysBP |
0.6381074 |
0.0641837 |
9.941893 |
0.0000000 |
sd.diaBP |
-0.1409295 |
0.0650918 |
-2.165088 |
0.0303809 |
sd.totChol |
0.1113871 |
0.0431866 |
2.579205 |
0.0099028 |
The equation for the multiple logistic regression equation of the
reduced model is given as follows:
log p/(1-p) = -1.7675 - 0.1443 * currentSmoker + 0.2683 *
sd.cigsPerDay + 0.6381 * sd.sysBP - 0.1409 * sd.diaBP + 0.1114 *
sd.totChol
Forward Selection
Model
The third of three candidate models will be the model that was found
through the automatic variable selection process, specifically with
using forward selection. We will call this the fs.model for this project
to represent it being the model found through the use of forward
selection of the variables.
We will find the specific multiple logistic regression equation for
this forward selection model.
fs.model = stepAIC(reduced.model, scope = list(lower=formula(reduced.model), upper=formula(full.model)),
direction = "forward",
trace = 0
)
kable(summary(fs.model)$coef,
caption="Final Model Summary of the Inferential Statistics")
Final Model Summary of the Inferential Statistics
(Intercept) |
-2.2897777 |
0.1108872 |
-20.6496069 |
0.0000000 |
currentSmoker |
0.0083694 |
0.1431896 |
0.0584499 |
0.9533902 |
sd.cigsPerDay |
0.2497211 |
0.0677217 |
3.6874613 |
0.0002265 |
sd.sysBP |
0.3080000 |
0.0777695 |
3.9604228 |
0.0000748 |
sd.diaBP |
-0.0324529 |
0.0698694 |
-0.4644798 |
0.6423040 |
sd.totChol |
0.0755135 |
0.0454483 |
1.6615237 |
0.0966083 |
sd.age |
0.5363993 |
0.0527922 |
10.1605849 |
0.0000000 |
male |
0.5164091 |
0.0993494 |
5.1979103 |
0.0000002 |
sd.glucose |
0.1825977 |
0.0373944 |
4.8830291 |
0.0000010 |
prevalentStroke |
0.9413243 |
0.4425788 |
2.1269078 |
0.0334277 |
prevalentHyp |
0.2310484 |
0.1281164 |
1.8034261 |
0.0713213 |
BPMeds |
0.3233004 |
0.2160729 |
1.4962560 |
0.1345870 |
The equation for the multiple logistic regression equation of the
forward selection model is given as follows:
log p/(1-p) = -2.2898 + 0.0084 * currentSmoker + 0.2497 *
sd.cigsPerDay + 0.2497 * sd.sysBP - 0.0325 * sd.diaBP + 0.0755 *
sd.totChol + 0.5364 * sd.age + 0.5164 * male + 0.1826 * sd.glucose +
0.9413 * prevalentStroke + 0.2310 * prevalentHyp + 0.3233 * BPMeds
The variables that were kept in this model after forward selection
were currentSmoker, sd.cigsPerDay, sd.sysBP, sd.diaBP, sd.totChol,
sd,age, male, sd.glucose, prevalentStroke, prevalentHyp, and BPMeds.
Cross Validation
Now that we’ve looked into the specifications of the three potential
candidate models, we will use cross-validation to determine which of
these three models we should use. We want to see which model has the
best predictive performance. We will use a 5-fold cross validation to
conduct the process of finding the predictive errors for each of the
three candidate models. We will use this 5-fold cross validation process
to calculate the average predictive errors for each of the three
candidate models, the full model, the reduced model, and the forward
selection model. We are looking for which model has the lowest value of
average predictive errors. This model with the lowest value for the
average predictive errors will be the ideal choice, as having the lowest
predictive error value indicates a higher predictive power and more
accurate predictions than a model with higher average predictive error
would.
For our cross validation process, we will use a cut off probability
of 0.5 to define between the binary response values of 1, yes, and 0,
no. These values represent whether an individual will be stated as being
at risk for developing CHD in a 10-year period based upon the multiple
logistic regression model that was used for prediction.
We will label the full model as our first model (01), the reduced
model as our second model (02), and the forward selection model as our
third model (03) for this cross-validation process.
## 5 Fold Cross Validation
k = 5
fold.size = floor(dim(train)[1]/k)
PE1 = rep(0,5)
PE2 = rep(0,5)
PE3 = rep(0,5)
# Training and Testing Fold for the Models
for(i in 1:k){
valid.id = (fold.size*(i-1)+1):(fold.size*i)
valid = train[valid.id, ]
train.data = train[-valid.id,]
# Full Model: all variables
full.model = glm(TenYearCHD ~ male + sd.age + education + currentSmoker + sd.cigsPerDay + BPMeds + prevalentStroke + prevalentHyp + diabetes + sd.totChol + sd.sysBP + sd.diaBP + sd.BMI + sd.heartRate + sd.glucose,
family = binomial(link = "logit"),
data = train.data)
## Reduced Model: only the most practically important variables.
reduced.model = glm(TenYearCHD ~ currentSmoker + sd.cigsPerDay + sd.sysBP + sd.diaBP + sd.totChol,
family = binomial(link = "logit"),
data = train.data)
## Automatic Forward Selection (fs) Model: model found using forward selection
fs.model = stepAIC(full.model,
scope = list(lower=formula(reduced.model),
upper=formula(full.model)),
direction = "forward",
trace = 0
)
# Finding the predicted probabilities for each of the candidate models
pred.full = predict(full.model, newdata = valid, type = "response")
pred.reduced = predict(reduced.model, newdata = valid, type = "response")
pred.fs = predict(fs.model, newdata = valid, type = "response")
pre.outcome01 = ifelse(as.vector(pred.full) > 0.5, "1", "0")
pre.outcome02 = ifelse(as.vector(pred.reduced) > 0.5, "1", "0")
pre.outcome03 = ifelse(as.vector(pred.fs) > 0.5, "1", "0")
PE1[i] = sum(pre.outcome01 == valid$TenYearCHD)/length(pred.full)
PE2[i] = sum(pre.outcome02 == valid$TenYearCHD)/length(pred.reduced)
PE3[i] = sum(pre.outcome03 == valid$TenYearCHD)/length(pred.fs)
}
# Finding the average predictive errors of each candidate model
avg.pe = cbind(PE1 = mean(PE1), PE2 = mean(PE2), PE3 = mean(PE3))
kable(avg.pe, caption = "Average Predictive Errors of the Three Candidate Models")
Average Predictive Errors of the Three Candidate
Models
0.8545723 |
0.8495575 |
0.8545723 |
The average predictive errors of the three candidate models are given
as follows:
The full model, represented by PE1, had an average predictive error
of 0.8546. The reduced model, represented by PE2, had an average
predictive error of 0.8495.
The forward selection model, represented by PE3, had an average
predictive error of 0.8546.
We can see that both the full model and the forward selection model
had equal values for their average predictive errors, with both having a
value of 0.8546. However, the reduced model a lower average predictive
error value than the other two models, with a value of 0.8496. This
indicates that the reduced model is the one which we should choose as
our final model.
The cross-validation process of calculating the average predictive
errors for the three candidate models showed that the reduced model is
the ideal one to use for prediction due to it having the lowest value of
its average predictive error out of the three candidate models. This
makes the reduced model have the highest predictive power and
performance out of the three candidate models, as shown by how it has
the least amount of its average predictive errors in comparison to the
full model and the forward selection model. So, we will move forward
with the use of the reduced model as our final multiple logistic
regression model for prediction of the odds of an individual being at
risk for developing CHD.
Final Model
In the previous cross-validation step, we used a cut off probability
of 0.5 to identify between the response variable giving a positive or
negative result. In this case, a “positive” result, or an output of 1,
represents that an individual is at risk for developing CHD in a 10-year
period. And, a “negative” result, or an output of 0, represents that an
individual is not at risk for developing CHD in a 10-year period. We
used the cross-validation process with this cut off probability of 0.5
to find the values of the average predictive errors of the three
candidate models. We found that the reduced model was the one with the
best predictive performance, so we will use that as our final model.
However, in order to report the details of the final model, we must
find its actual accuracy based upon the test data. We previously split
the data up into a training and a testing data set. We will use the test
data set to find the actual accuracy of the final model, the reduced
model, in order to provide the fullest accuracy in the report of this
model.
pred.reduced = predict(reduced.model, newdata = test, type = "response")
pred.reduced.outcome = ifelse(as.vector(pred.reduced) > 0.5, "1", "0")
Accuracy = sum(pred.reduced.outcome == test$TenYearCHD)/length(pred.reduced)
kable(Accuracy, caption="Actual Accuracy of the Final Model (Reduced Model)")
Actual Accuracy of the Final Model (Reduced Model)
0.8443396 |
The actual accuracy of the final model, the reduced model, is given
as 0.8443. This value represents the accuracy rate of this final
model.
It appears that the final model has good accuracy as seen by its
accuracy rate of 0.8443. This indicates that the final model we selected
has good predictive performance for predicting the odds of an individual
being at risk for developing CHD within a 10-year period.
ROC Analysis
We will use ROC analysis to measure the global performance of the
multiple logistic regression model. This plot will illustrate the
relationship of the true positive rate (TPR), also known as the
sensitivity, against the false positive rate (FPR), also given as 1 -
specificity. We will plot the ROC curves for each of the three candidate
models to compare them against one another. We will also calculate the
area under the curve (AUC) values for each of the three candidate
models. The value of area under the curve represents the global goodness
of the model, and a higher AUC value is ideal. A higher value of the
area under the curve indicates better and more quality global goodness
of that model.
We will plot the ROC curves for the full model, the reduced model,
and the forward selection model. This will allow us to compare the area
under the curves for each of the three models. Additionally, we will
calculate the AUC values for each of the three models to compare them
with each other and determine which model indicates the best global
goodness.
TPR.FPR=function(pred){
prob.seq = seq(0, 1, length=50)
pn = length(prob.seq)
true.lab = as.vector(train$TenYearCHD)
TPR = NULL
FPR = NULL
for (i in 1:pn){
pred.lab = as.vector(ifelse(pred > prob.seq[i],"1", "0"))
TPR[i] = length(which(true.lab=="1" & pred.lab=="1"))/length(which(true.lab=="1"))
FPR[i] = length(which(true.lab=="0" & pred.lab=="1"))/length(which(true.lab=="0"))
}
cbind(FPR = FPR, TPR = TPR)
}
We will use the training data set to help find the predictive
probabilities for each of the three candidate models.
# The Full Model
full.model = glm(TenYearCHD ~male + sd.age + education + currentSmoker + sd.cigsPerDay + BPMeds + prevalentStroke + prevalentHyp + diabetes + sd.totChol + sd.sysBP + sd.diaBP + sd.BMI + sd.heartRate + sd.glucose,
family = binomial(link = "logit"),
data = train)
# The Reduced Model (final model)
reduced.model = glm(TenYearCHD ~ currentSmoker + sd.cigsPerDay + sd.sysBP + sd.diaBP + sd.totChol,
family = binomial(link = "logit"),
data = train)
# The Forward Selection (fs) Model
fs.model = stepAIC(full.model,
scope = list(lower=formula(reduced.model),
upper=formula(full.model)),
direction = "forward",
trace = 0
)
# Finding the Predicted Probabilities for Each Model
pred.full = predict.glm(full.model, newdata = train, type = "response")
pred.reduced = predict.glm(reduced.model, newdata = train, type = "response")
pred.fs = predict.glm(fs.model, newdata = train, type = "response")
Now, we will plot the ROC curves for each of the three candidate
models to compare them.
# Plotting the ROC curves
plot(TPR.FPR(pred.full)[,1], TPR.FPR(pred.full)[,2],
type="l", col = 2, lty = 1, xlim = c(0,1), ylim = c(0,1),
xlab = "FPR: 1 - Specificity",
ylab ="TPR: Sensitivity",
main = "ROC Curves for the Three Candidate Models",
cex.main = 0.8,
col.main = "navy")
lines(TPR.FPR(pred.reduced)[,1], TPR.FPR(pred.reduced)[,2], col=3, lty=2)
lines(TPR.FPR(pred.fs)[,1], TPR.FPR(pred.fs)[,2], col=4, lty=3)
category = train$TenYearCHD == "1"
ROCobj01 <- roc(category, as.vector(pred.full))
ROCobj02 <- roc(category, as.vector(pred.reduced))
ROCobj03 <- roc(category, as.vector(pred.fs))
AUC01 = round(auc(ROCobj01),4)
AUC02 = round(auc(ROCobj02),4)
AUC03 = round(auc(ROCobj03),4)
legend("bottomright", c(paste("Full model: AUC = ", AUC01),
paste("Reduced model: AUC =", AUC02),
paste("Forward Selection model: AUC =", AUC03)),
col = 2:4, lty = 1:3, cex = 0.8, bty = "n")

We can see that both the full model and the forward selection model
fall on the exact same curve, which is also evidenced by how these two
models have the same values for their area under the curve Both the full
model and the forward selection model have an area under the curve of
0.7356, and their ROC curves match up identically to each other. This
matches up with the previous finding of the full model and the forward
selection model having the exact same values for their average
predictive errors.
Something interesting found in this ROC analysis, is that the reduced
model actually has the smallest value of area under the curve with
0.6763. We found that the reduced model was the one with the lowest
average predictive errors previously, which made it the ideal model
choice for our final model. However, this model turned out to have the
lowest area under the curve out of the three, which is not ideal. A
model with a higher area under the curve has a better global goodness
than a model with a lower area under the curve.
Solely based upon area under the curve values found in the ROC
analysis, it would appear that the forward selection model provides the
best global goodness. Both the full model and the forward selection
model had the same value for their area under the curve, but the forward
selection model would be the better choice due to it having less
variables.
The ROC analysis revealed that the forward selection model may in
fact be a good alternative to use as the final model due to it having a
higher area under the curve than the reduced model, despite the reduced
model having a lower average value of predictive errors as was found
earlier. A potential reason for the forward selection model having a
higher AUC than the reduced model despite the reduced model having a
lower and more ideal average value of predictive errors could be due to
the reduced model having less variables. It could be a possibility that
the reduced model having fewer variables could have a higher likelihood
of false positivies or false negatives due to some of the variables
which may be significant not having been included in the reduced
model.
Conclusion
In this project, three candidate models were created to compare their
predictive powers and ultimately choose a final model that provides the
best significance and quality of prediction for predicting the odds of
an individual being at risk for developing CHD in a 10-year period.
These models all consisted of multiple logistic regression to predict
the binary response variable of an individual’s odds of being at risk
for developing CHD. Creating a model for the purpose of this prediction
can provide use for doctors and patients in order to predict their odds
of being at risk for developing CHD based upon various personal and
medical factors.
The three candidate models that were created included a full model
with all of the variables in the data set, a reduced model with only the
variables deemed as the most practically important, and a model created
through forward variable selection. These three models were compared by
their predictive power and quality for their potential use as a final
multiple logistic regression model for this project.
The average predictive errors of all three candidate models were
compared to assess their predictive powers through the process of
cross-validation. It was found that the full model and the forward
selection model had identical values for the average predictive errors.
However, the reduced model turned out to have the lowest value of its
average predictive errors out of the three candidate models. This
indicated that the reduced model was the ideal choice due to it having
the lowest value of average predictive errors, and therefore the highest
quality of predictive power. This indicated that the reduced model would
be a good choice for the final model due to its high quality predictive
power shown by how it had the smallest value of average predictive
errors out of all three candidate models.
Furthermore, ROC analysis was conducted to continue the analysis of
the three candidate models. It was found that the full model and the
forward selection model have identical ROC curves and area under the
curve values. This matched up with how it was previously found that the
full model and the forward selection model have the exact same average
value of their predictive errors. Between these two models, we would
choose the forward selection model over the full model due to it having
less variables. However, we also found that the reduced model in fact
had the lowest area under the curve value out of the three models. This
is interesting as it contradicts with the reduced model previously being
shown to have the lowest average value of predictive errors. It turns
out that despite the reduced model having the lowest average of
predictive errors and therefore the highest predictive power, it also
has the lowest area under the curve meaning that it has lower global
goodness out of the candidate models.
Overall, it was found that through cross-validation it turned out
that the reduced model had the lowest average value of predictive
errors, and therefore the highest predictive power. This made the
reduced model the ideal choice for the selection of our final model.
This reduced model focused on only the most practically important
variables for predicting the odds of an individual being at risk for
developing CHD. These most practically important variables included
currentSmoker, sd.cigsPerDay, sd.sysBP, sd.diaBP, and sd.totChol.
However, it was later found through ROC analysis that the reduced model
had the lowest area under the curve value, indicating a lower global
goodness. It was in fact the forward selection model that the ROC
analysis suggested as being the ideal choice based upon its global
goodness. The forward selection model included the variables of
currentSmoker, sd.cigsPerDay, sd.sysBP, sd.diaBP, sd.totChol, sd,age,
male, sd.glucose, prevalentStroke, prevalentHyp, and BPMeds.
Even though the reduced model provided the best predictive power due
to its lower value of average predictive errors, the forward selection
model was shown through ROC analysis to have the highest global
goodness. Both the reduced model and the full model are high quality
models for the prediction and estimation of the odds of an individual
being at risk for developing CHD. This discrepancy between the reduced
model having the highest predictive power yet the lowest global goodness
could in fact be due to it having the fewest variables. By having fewer
variables, this could potentially lead to higher rates of false
positives and false negatives than the other models with more variables
accounted for. So overall, the reduced model would be the ideal choice
as the final model for a model with the highest predictive power, which
is what we were looking for in this project. However, it is important to
keep in mind that this reduced model has a lower global goodness than
the forward selection model, likely due to the reduced model having
fewer variables and potentially a higher rate for false positives and
false negatives. This is important to keep in mind when creating a model
for the prediction of an individual’s odds of being at risk for
developing CHD, as high predictive power is ideal for ensuring that
patient’s health is accounted for properly, but it is also important to
be wary of the potential for false postives and false negatives in
regards of these predictions.
Recommendations
Some recommendations I would make for future projects include:
Expand the data collection to ensure the accuracy of the findings
found in this project. This could also involve reaching out to various
hospitals and doctors for a better understanding of the most serious
risk factors for CHD in order to ensure that the variables kept within
the final model indeed are representative of a patient’s odds of being
at risk for developing CHD.
Consider other variables which could be statistically significant
in predicting the odds of a patient’s risk for developing CHD. All of
the predictor variables that were included within this data set made
sense in terms of this project and were all factors which could play a
role in a patient’s odds of being at risk for developing CHD. However,
future projects could consider looking into additional variables that
may be statistically significant in predicting the odds of a patient
being at risk for developing CHD. For instance, one potential variable
that could be looked into is a patient’s income to see if the income of
a patient has an impact on their odds of being at risk for developing
CHD. A reason why I believe that this could be a significant variable
for this model is because patients with higher incomes tend to have more
options when it comes to medical care than patients with lower incomes
would. So, perhaps there could be a relationship between a patient’s
income and their odds of being at risk for developing CHD. This is just
one example of a variable that is not in this data set which may provide
use for future projects.
Consider other possible models that could provide quality
predictive power in predicting the odds of a patient being at risk for
developing CHD within a 10-year period of time. In this project, we
looked at three candidate multiple logistic regression models and chose
which one provided the best utility. These three models included a full
model with all of the predictor variables left in the model, a reduced
model with only the variables that the medical report described as most
significant risk factors for CHD, and a final model that was created
through automatic forward variable selection. We found that the reduced
model was the one which provided the lowest average value for predictive
errors out of the three models, and so we chose this to be our final
model due to it providing the strongest predictive power. However, this
is not to say that there is not any other possible model that could
potentially be better than the one we created. If further projects found
a model that provided better and more power in prediction than our final
model, this could help doctors and patients better understand their odds
of being at risk for developing CHD based on the various factors
included in the model.
Further investigate the topic of false postives and false
negatives amongst the predicted values. The topic of false postives and
false negatives was addressed as potentially being a reason for the
descrepancy between the reduced model having the greatest predictive
power, yet also having the lowest global goodness. Having fewer
varaibles could possibly lead to some factors being unaccounted for, and
potentially resulting in some false positive or negative predictions.
This is a potential topic which could be further looked into in further
experiments to fully understand the occurences of false positive or
negative predictions.
Overall, this project showed that the reduced model resulted in the
lowest average predictive errors out of the three models, meaning this
was the model with the highest predictive power. However, ROC analysis
showed that the reduced model had a lower area under the curve model,
and it was the forward selection model which had the highest global
goodness as indicated by the ROC analysis. This is something important,
because although the reduced model is an ideal choice for the final
model due to its high quality of predictive power, this lower global
goodness is an important thing to keep in mind when using this final
model for the prediction of an individual’s odds of being at risk for
developing CHD in a 10-year period.
LS0tDQp0aXRsZTogIlByZWRpY3RpbmcgYSBQYXRpZW50J3MgT2RkcyBvZiBCZWluZyBhdCBSaXNrIGZvciBEZXZlbG9waW5nIENIRC0gQmluYXJ5IFByZWRpY3RpdmUgTW9kZWxpbmciDQphdXRob3I6ICJKb3NpZSBHYWxsb3AiDQpkYXRlOiAiMjAyNC0xMC0yMSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGZpZ193aWR0aDogNg0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovDQoNCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCjwvc3R5bGU+DQpgYGANCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBEZXRlY3QsIGluc3RhbGwsIGFuZCBsb2FkIHBhY2thZ2VzIGlmIG5lZWRlZC4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgibGVhZmxldCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikNCiAgIGxpYnJhcnkobGVhZmxldCkNCn0NCmlmICghcmVxdWlyZSgiRW52U3RhdHMiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiRW52U3RhdHMiKQ0KICAgbGlicmFyeShFbnZTdGF0cykNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgIGxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgicGh5dG9vbHMiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGh5dG9vbHMiKQ0KICAgbGlicmFyeShwaHl0b29scykNCn0NCmlmKCFyZXF1aXJlKCJkcGx5ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQogICBsaWJyYXJ5KGRwbHlyKQ0KfQ0KaWYoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZighcmVxdWlyZSgiR0dhbGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIkdHYWxseSIpDQogICBsaWJyYXJ5KEdHYWxseSkNCn0NCmlmKCFyZXF1aXJlKCJ1c2RtIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInVzZG0iKQ0KICAgbGlicmFyeSh1c2RtKQ0KfQ0KaWYoIXJlcXVpcmUoImNhciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJjYXIiKQ0KICAgbGlicmFyeShjYXIpDQp9DQppZiAoIXJlcXVpcmUoImJvb3QiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiYm9vdCIpDQogICBsaWJyYXJ5KGJvb3QpDQp9DQppZighcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmKCFyZXF1aXJlKCJtaWNlIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIm1pY2UiKQ0KICAgbGlicmFyeShtaWNlKQ0KfQ0KaWYoIXJlcXVpcmUoIm1sYmVuY2giKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibWxiZW5jaCIpDQogICBsaWJyYXJ5KG1sYmVuY2gpDQp9DQppZighcmVxdWlyZSgicHN5Y2giKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQ0KICAgbGlicmFyeShwc3ljaCkNCn0NCmlmKCFyZXF1aXJlKCJicm9vbS5taXhlZCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJicm9vbS5taXhlZCIpDQogICBsaWJyYXJ5KGJyb29tLm1peGVkKQ0KfQ0KaWYoIXJlcXVpcmUoIkdHYWxseSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQ0KICAgbGlicmFyeShHR2FsbHkpDQp9DQppZighcmVxdWlyZSgiY2FyZXQiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQ0KICAgbGlicmFyeShjYXJldCkNCn0NCmlmICghcmVxdWlyZSgicFJPQyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwUk9DIikNCiAgIGxpYnJhcnkocFJPQykNCn0NCiMgU3BlY2lmaWNhdGlvbnMgb2Ygb3V0cHV0cyBvZiBjb2RlIGluIGNvZGUgY2h1bmtzDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUNCiAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAjIFNvbWV0aW1lcywgeW91ciBjb2RlIG1heSBwcm9kdWNlIGEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1lc3NhZ2VzLCB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgd2FybmluZyBtZXNzYWdlcyBpbiB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgIA0KICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQSAgICAgICMgU3VwcHJlc3MgaGFzaC10YWdzIGluIHRoZSBvdXRwdXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cy4NCiAgICAgICAgICAgICAgICAgICAgICApICAgDQpgYGANCg0KDQojIEludHJvZHVjdGlvbg0KDQpGb3IgdGhpcyBwcm9qZWN0LCB3ZSB3aWxsIGJlIHdvcmtpbmcgb24gY3JlYXRpbmcgYSBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLiBUaGUgZGF0YSBzZXQgZm9yIHRoaXMgcHJvamVjdCBsb29rcyBhdCB0aGUgdmFyaW91cyBmYWN0b3JzIGFmZmVjdGluZyBhbiBpbmRpdmlkdWFsIHBhdGllbnQncyByaXNrIG9mIGRldmVsb3BpbmcgY29yb25hcnkgaGVhcnQgZGlzZWFzZSAoQ0hEKSBpbiBhIDEwLXllYXIgcGVyaW9kIG9mIHRpbWUuIFRoZSByZXNwb25zZSB2YXJpYWJsZSBpbiB0aGlzIGRhdGEgc2V0IGlzIGJpbmFyeSB3aXRoIDEgcmVwcmVzZW50aW5nIHllcywgdGhlIHBhdGllbnQgaXMgYXQgcmlzayBvZiBkZXZlbG9waW5nIENIRCB3aXRoaW4gYSAxMC15ZWFyIHBlcmlvZCBvZiB0aW1lLCBhbmQgMCByZXByZXNlbnRpbmcgbm8sIHRoZSBwYXRpZW50IGlzIG5vdCBhdCByaXNrIG9mIGRldmVsb3BpbmcgQ0hEIHdpdGhpbiBhIDEwLXllYXIgcGVyaW9kIG9mIHRpbWUuDQoNCk91ciBvdmVyYWxsIGdvYWwgaW4gdGhpcyBwcm9qZWN0IGlzIHRvIGNyZWF0ZSBhIG1vZGVsIHdoaWNoIGhhcyB0aGUgZ3JlYXRlc3QgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZS4gV2Ugd2lsbCBjcmVhdGUgc2V2ZXJhbCBjYW5kaWRhdGUgbW9kZWxzIGFuZCBjb21wYXJlIHRoZW0gd2l0aCBlYWNoIG90aGVyIHRvIGRldGVybWluZSB3aGljaCBtb2RlbCBzaG91bGQgYmUgc2VsZWN0ZWQgYXMgdGhlIGZpbmFsIG1vZGVsIGZvciB0aGUgcHJlZGljdGlvbiBvZiBhbiBpbmRpdmlkdWFsJ3Mgb2RkcyBvZiBiZWluZyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRCBvdmVyIGEgMTAteWVhciBwZXJpb2Qgb2YgdGltZS4gV2Ugd2lsbCB1c2UgdGhlIGNyb3NzLXZhbGlkYXRpb24gcHJvY2VzcyB0byBkZXRlcm1pbmUgd2hpY2ggb2YgdGhlIGNhbmRpZGF0ZSBtb2RlbHMgcHJvdmlkZXMgdGhlIGJlc3QgcHJlZGljdGl2ZSBwb3dlci4gV2Ugd2lsbCBhbHNvIHVzZSBST0MgYW5hbHlzaXMgdG8gZGV0ZXJtaW5lIHdoaWNoIG9mIHRoZSBjYW5kaWRhdGUgbW9kZWxzIGhhcyB0aGUgYmVzdCBnbG9iYWwgZ29vZG5lc3MuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBzZWUgd2hpY2ggb2YgdGhlIGNhbmRpZGF0ZSBtb2RlbHMgcHJvdmlkZXMgdGhlIGJlc3QgdXRpbGl0eSBhbmQgcXVhbGl0eSBmb3IgcHJlZGljdGl2ZSBtb2RlbGluZy4gDQoNCg0KDQojIyBEYXRhIERlc2NyaXB0aW9uDQoNCkkgZm91bmQgdGhpcyBkYXRhIHNldCBvbiBrYWdnbGUuY29tIG9uIHRoZSBmb2xsb3dpbmcgd2ViIHBhZ2U6DQpodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL2RpbGVlcDA3MC9oZWFydC1kaXNlYXNlLXByZWRpY3Rpb24tdXNpbmctbG9naXN0aWMtcmVncmVzc2lvbi9kYXRhDQoNClRoaXMgZGF0YSBzZXQgdGFrZXMgYSBsb29rIGF0IHZhcmlvdXMgbWVkaWNhbCBhbmQgcGVyc29uYWwgZmFjdG9ycyB3aGljaCBtYXkgaGF2ZSBhbiBpbXBhY3Qgb24gYW4gaW5kaXZpZHVhbCdzIHJpc2sgb2YgZGV2ZWxvcGluZyBDSEQgd2l0aGluIHRoZSBuZXh0IDEwIHllYXJzLiBUaGUgYmluYXJ5IHJlc3BvbnNlIHZhcmlhYmxlIHRlbGxzIHdoZXRoZXIgYW4gaW5kaXZpZHVhbCBwYXRpZW50IGlzIGF0IHJpc2sgb2YgZGV2ZWxvcGluZyBDSEQgd2l0aGluIHRoZSBuZXh0IDEwIHllYXJzLCB3aXRoIGEgcmVzcG9uc2UgdmFsdWUgb2YgMSBtZWFuaW5nIHllcyB0aGV5IGFyZSBhdCByaXNrLCBhbmQgMCBtZWFuaW5nIG5vIHRoZXkgYXJlIG5vdCBhdCByaXNrLg0KDQoNCg0KIyMgVmFyaWFibGVzDQoNClRoZXJlIGFyZSAxNiB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhIHNldC4NCg0KKiBtYWxlOiBUaGUgZ2VuZGVyIG9mIHRoZSBwYXRpZW50LiBBIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHdpdGggMSBmb3IgIm1hbGUiLCAgMCBmb3IgImZlbWFsZSIsIGFuZCAyIGZvciAib3RoZXIiLiANCg0KKiBhZ2U6IFRoZSBhZ2Ugb2YgdGhlIHBhdGllbnQgaW4geWVhcnMuIFRoaXMgaXMgYSBxdWFudGl0YXRpdmUsIGNvbnRpbnVvdXMgdmFyaWFibGUgZ2l2ZW4gYXMgYW4gaW50ZWdlciB2YWx1ZS4NCg0KKiBlZHVjYXRpb246IFRoZSBlZHVjYXRpb24gbGV2ZWwgb2YgdGhlIHBhdGllbnQuIEEgY2F0ZWdvcmljYWwgdmFyaWFibGUgd2l0aCAxIGZvciAibGVzcyB0aGFuIGhpZ2ggc2Nob29sIiwgMiBmb3IgImhpZ2ggc2Nob29sIGRpcGxvbWEiLCAzIGZvciAiY29sbGVnZSBncmFkdWF0ZSIsIGFuZCA0IGZvciAicG9zdC1jb2xsZWdlIGdyYWR1YXRlIi4NCg0KKiBjdXJyZW50U21va2VyOiBXaGV0aGVyIG9yIG5vdCB0aGUgcGF0aWVudCBpcyBjdXJyZW50bHkgYSBzbW9rZXIuIEEgYmluYXJ5IHZhcmlhYmxlIHdpdGggMSBmb3IgInllcyIgYW5kIDAgZm9yICJubyIuDQoNCiogY2lnc1BlckRheTogVGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIGNpZ2FyZXR0ZXMgdGhlIHBhdGllbnQgc21va2VzIGluIGEgZGF5LiBUaGlzIGlzIGEgcXVhbnRpdGF0aXZlLCBjb250aW51b3VzIHZhcmlhYmxlLiANCg0KKiBCUE1lZHM6IFdoZXRoZXIgb3Igbm90IHRoZSBwYXRpZW50IHRha2VzIGJsb29kIHByZXNzdXJlIG1lZGljYXRpb24uIEEgYmluYXJ5IHZhcmlhYmxlIHdpdGggMSBmb3IgInllcyIgYW5kIDAgZm9yICJubyIuDQoNCiogcHJldmFsZW50U3Ryb2tlOiBXaGV0aGVyIG9yIG5vdCB0aGUgcGF0aWVudCBoYXMgYSBoaXN0b3J5IG9mIHN0cm9rZXMuIEEgYmluYXJ5IHZhcmlhYmxlIHdpdGggMSBmb3IgInllcyIgYW5kIDAgZm9yICJubyIuDQoNCiogcHJldmFsZW50SHlwOiBXaGV0aGVyIG9yIG5vdCB0aGUgcGF0aWVudCBoYXMgYSBoaXN0b3J5IG9mIGh5cGVydGVuc2lvbi4gQSBiaW5hcnkgdmFyaWFibGUgd2l0aCAxIGZvciAieWVzIiBhbmQgMCBmb3IgIm5vIi4NCg0KKiBkaWFiZXRlczogV2hldGhlciBvciBub3QgdGhlIHBhdGllbnQgaGFzIGEgaGlzdG9yeSBvZiBkaWFiZXRlcy4gQSBiaW5hcnkgdmFyaWFibGUgd2l0aCAxIGZvciAieWVzIiBhbmQgMCBmb3IgIm5vIi4NCg0KKiB0b3RDaG9sOiBUaGUgcGF0aWVudCdzIHRvdGFsIGNob2xlc3Rlcm9sIGxldmVsLCBnaXZlbiBpbiBtZy9kTCAobWlsbGlncmFtcyBwZXIgZGVjaWxpdGVyKS4gQSBxdWFudGl0YXRpdmUsIGNvbnRpbnVvdXMgdmFyaWFibGUuIA0KDQoqIHN5c0JQOiBUaGUgcGF0aWVudCdzIHN5c3RvbGljIGJsb29kIHByZXNzdXJlLCBnaXZlbiBpbiBtbUhHIChtaWxsaW1ldGVycyBvZiBtZXJjdXJ5KS4gQSBxdWFudGl0YXRpdmUsIGNvbnRpbnVvdXMgdmFyaWFibGUuIA0KDQoqIGRpYUJQOiBUaGUgcGF0aWVudCdzIGRpYXN0b2xpYyBibG9vZCBwcmVzc3VyZSwgZ2l2ZW4gaW4gbW1IRyAobWlsbGltZXRlcnMgb2YgbWVyY3VyeSkuIEEgcXVhbnRpdGF0aXZlLCBjb250aW51b3VzIHZhcmlhYmxlLiANCg0KKiBCTUk6IFRoZSBwYXRpZW50J3MgYm9keSBtYXNzIGluZGV4IChCTUkpLiBBIHF1YW50aXRhdGl2ZSwgY29udGludW91cyB2YXJpYWJsZS4gDQoNCiogaGVhcnRSYXRlOiBUaGUgcGF0aWVudCdzIGhlYXJ0IHJhdGUsIGdpdmVuIGluIGJlYXRzIHBlciBtaW51dGUuIEEgbnVtZXJpYywgcXVhbnRpdGF0aXZlIHZhcmlhYmxlLiANCg0KKiBnbHVjb3NlOiBUaGUgcGF0aWVudCdzIGdsdWNvc2UgbGV2ZWwsIGdpdmVuIGluIG1nL2RMIChtaWxsaWdyYW1zIHBlciBkZWNpbGl0ZXIpLiBBIG51bWVyaWMsIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4gDQoNCiogVGVuWWVhckNIRCAocmVzcG9uc2UgdmFyaWFibGUpOiBUaGUgYmluYXJ5IHJlc3BvbnNlIHZhcmlhYmxlIG9mIHRoaXMgZGF0YSBzZXQgd2hpY2ggcmVwcmVzZW50cyB3aGV0aGVyIG9yIG5vdCB0aGUgcGF0aWVudCBoYXMgYSAxMC15ZWFyIHJpc2sgb2YgZGV2ZWxvcGluZyBDb3JvbmFyeSBIZWFydCBEaXNlYXNlIChDSEQpLiBUaGlzIHJlc3BvbnNlIHZhcmlhYmxlIGlzIGJpbmFyeSB3aXRoIDEgbWVhbmluZyB5ZXMsIHRoZSBwYXRpZW50IGRvZXMgaGF2ZSBhIHJpc2sgb2YgZGV2ZWxvcGluZyBDSEQgaW4gdGhlIG5leHQgMTAgeWVhcnMsIGFuZCAwIG1lYW5pbmcgbm8sIHRoZSBwYXRpZW50IGRvZXMgbm90IGhhdmUgYSByaXNrIG9mIGRldmVsb3BpbmcgQ0hEIGluIHRoZSBuZXh0IDEwIHllYXJzLg0KDQoNCg0KIyMgUmVzZWFyY2ggUXVlc3Rpb25zDQoNCg0KVGhlIGtleSBhbmFseXRpY2FsIHF1ZXN0aW9uIHdoaWNoIEkgd291bGQgbGlrZSB0byBpbnZlc3RpZ2F0ZSBpbiB0aGlzIHByb2plY3QgaXM6DQoNCiogQ2FuIHdlIGNyZWF0ZSBhIG1vZGVsIHdoaWNoIGhhcyB0aGUgaGlnaGVzdCBwcmVkaWN0aXZlIHBvd2VyIGluIHJlZ2FyZHMgdG8gcHJlZGljdGluZyBhIHBhdGllbnQncyBvZGRzIG9mIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgY29yb25hcnkgaGVhcnQgZGlzZWFzZSB3aXRoaW4gYSAxMC15ZWFyIHBlcmlvZCBvZiB0aW1lIGJhc2VkIG9uIHRoZSBwcmVkaWN0b3IgdmFyaWFibGVzIGluIHRoaXMgZGF0YSBzZXQ/DQoNClRoaXMgcXVlc3Rpb24gd2lsbCBzZXJ2ZSBhcyB0aGUgYmFzaXMgZm9yIGNyZWF0aW5nIHRoZSBjYW5kaWRhdGUgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbHMgZm9yIHRoaXMgZGF0YSBzZXQuIFdlIHdpbGwgdWx0aW1hdGVseSBjaG9vc2UgYSBmaW5hbCBtb2RlbCBvZiB0aGVzZSBwb3RlbnRpYWwgY2FuZGlkYXRlIG1vZGVscyBiYXNlZCB1cG9uIG91ciBmaW5kaW5ncyBpbiByZWdhcmRzIHRvIHRoZWlyIHByZWRpY3RpdmUgcG93ZXIuIFRoZSBmaW5kaW5ncyB0byB0aGlzIHF1ZXN0aW9uIGNvdWxkIHByb3ZpZGUgdXRpbGl0eSBmb3IgYm90aCBwYXRpZW50cyBhbmQgZG9jdG9ycyB0byBwcm92aWRlIHRoZW0gd2l0aCBpbmZvcm1hdGlvbiByZWxhdGluZyB0byB0aGUgb2RkcyBhbmQgcmlza3MgZm9yIGRldmVsb3BpbmcgQ0hEIGFuZCB3aGljaCBmYWN0b3JzIHNpZ25pZmljYW50bHkgaW1wYWN0IHRoZXNlIG9kZHMuIA0KDQpTb21lIGZ1cnRoZXIgcXVlc3Rpb25zIHRvIGNvbnNpZGVyIGFzIGEgc3RhcnRpbmcgcG9pbnQgZm9yIHRoaXMgcHJvamVjdCBpbmNsdWRlOg0KDQoqIElzIHRoZXJlIGEgbWFqb3IgZGlmZmVyZW5jZSBpbiB0aGUgcHJlZGljdGl2ZSBwb3dlcnMgb2YgdGhlIGNhbmRpZGF0ZSBtb2RlbHMgd2UgY3JlYXRlPw0KDQoqIERvIHRoZSBjb250aW51b3VzIGluZGVwZW5kZW50IHZhcmlhYmxlcyBpbiB0aGlzIGRhdGEgc2V0IGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24/IEFuZCBpZiBub3QsIGlzIHRoZXJlIGEgcG90ZW50aWFsIGV4cGxhbmF0aW9uIGZvciB3aHkgdGhpcyBtYXkgYmUgdGhlIGNhc2U/DQoNCiogSG93IGdvb2QgaXMgdGhlIHByZWRpY3RpdmUgcXVhbGl0eSBvZiBvdXIgZmluYWwgbW9kZWwgaW4gcmVnYXJkcyBvZiBwcmVkaWN0aW5nIHdoZXRoZXIgYW4gaW5kaXZpZHVhbCB3aWxsIGJlIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hEIGluIGEgMTAteWVhciBwZXJpb2Qgb2YgdGltZT8NCg0KDQpXZSB3aWxsIHVzZSB0aGVzZSBxdWVzdGlvbnMgYXMgYSBzdGFydGluZyBwb2ludCBmb3IgdGhpcyBwcm9qZWN0IGluIG9yZGVyIHRvIGNyZWF0ZSBhIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgd2hpY2ggaGFzIHRoZSBncmVhdGVzdCBwcmVkaWN0aXZlIHBvd2VyIGZvciBwcmVkaWN0aW5nIHRoZSBvZGRzIG9mIGEgcGF0aWVudCBiZWluZyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRCBpbiBhIDEwLXllYXIgcGVyaW9kIGJhc2VkIG9uIHRoZSBtYW55IGZhY3RvcnMgd2hpY2ggcGxheSBhIHJvbGUgaW4gdGhpcyBwcmVkaWN0aW9uLiANCg0KDQojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMNCg0KRmlyc3QsIHdlIHdpbGwgcmVhZCBpbiB0aGUgZGF0YSBzZXQgZnJvbSBHaXRodWIgYW5kIHdlIHdpbGwgY2FsbCBpdCAiaGVhcnRkaXNlYXNlIi4gDQoNCmBgYHtyfQ0KaGVhcnRkaXNlYXNlIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vSm9zaWVHYWxsb3AvU1RBMzIxL3JlZnMvaGVhZHMvbWFpbi9kYXRhc2V0L2ZyYW1pbmdoYW0uY3N2IiwgaGVhZGVyPVRSVUUpDQoNCnN0cihoZWFydGRpc2Vhc2UpDQpgYGANCg0KDQpXZSB3aWxsIG1ha2UgYSBjb3B5IG9mIHRoZSBkYXRhIHNldCBjYWxsZWQgImhlYXJ0ZGlzZWFzZTAiIHdoaWNoIHdpbGwgYmUgdGhlIGRhdGEgc2V0IHdlIHdpbGwgYW5hbHl6ZSBhbmQgdHJhbnNmb3JtIHRocm91Z2ggdGhlIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMuIA0KDQpgYGB7cn0NCmhlYXJ0ZGlzZWFzZTAgPC0gaGVhcnRkaXNlYXNlDQpgYGANCg0KDQoNCiMjIEZpeGluZyB0aGUgTWlzc2luZyBPYnNlcnZhdGlvbnMNCg0KDQpXaGVuIGxvb2tpbmcgdGhyb3VnaCB0aGUgZGF0YSBzZXQsIEkgbm90aWNlZCB0aGF0IHNvbWUgb2JzZXJ2YXRpb25zIGFwcGVhcmVkIHRvIGJlIG1pc3NpbmcgZnJvbSB0aGUgZGF0YSBzZXQsIGFzIHRoZXkgaGFkIHZhbHVlcyBvZiAiTkEiIGZvciBjZXJ0YWluIHZhcmlhYmxlcy4gQmVmb3JlIHdlIGNhbiBiZWdpbiB3aXRoIHRoZSBsb2dpc3RpYyByZWdyZXNzaW9uLCB0aGlzIGlzIHNvbWV0aGluZyB0aGF0IHdlIHNob3VsZCBsb29rIGludG8uDQoNCkZpcnN0LCBsZXQncyBzZWUgaG93IG1hbnkgdmFsdWVzIGFyZSBtaXNzaW5nIGZvciBlYWNoIG9mIHRoZSB2YXJpYWJsZXMuDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYShoZWFydGRpc2Vhc2UwKSkNCmBgYA0KDQpXZSBjYW4gc2VlIHRoYXQgdGhlIHZhcmlhYmxlcyBlZHVjYXRpb24sIGNpZ3NQZXJEYXksIEJQTWVkcywgdG90Q2hvbCwgQk1JLCBoZWFydFJhdGUsIGFuZCBnbHVjb3NlIGFsbCBoYXZlIG1pc3Npbmcgb2JzZXJ2YXRpb25zLg0KDQpJdCBpcyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHNpbmdsZSBpbXB1dGF0aW9uIG1ldGhvZHMgdGhhdCBjb3VsZCBiZSB1c2VkIHRvIGZpeCB0aGUgbWlzc2luZyBvYnNlcnZhdGlvbnMgb2YgdGhlIHZhcmlhYmxlcyBjb3VsZCBsZWFkIHRvIHBvdGVudGlhbCBza2V3IGluIHRoZWlyIGRpc3RyaWJ1dGlvbnMuIFNvLCBpbnN0ZWFkIHdlIHdpbGwgdXNlIG11bHRpcGxlIGltcHV0YXRpb24gbWV0aG9kcyB0byBmaWxsIGluIHRoZXNlIG1pc3Npbmcgb2JzZXJ2YXRpb25zIHdpdGggcmFuZG9tbHkgYXBwcm94aW1hdGVkIHZhbHVlcy4gT3V0IG9mIHRoZSB2YXJpYWJsZXMgd2l0aCBtaXNzaW5nIHZhbHVlcywgbm9uZSBvZiB0aGUgdmFyaWFibGVzIGhhdmUgdGhlIG1ham9yaXR5IG9mIHRoZWlyIGRhdGEgZW50cmllcyBtaXNzaW5nLCBzbyBpdCBzZWVtcyBzdWl0YWJsZSB0byBmaWxsIGluIHRoZXNlIG1pc3Npbmcgb2JzZXJ2YXRpb25zIHdpdGggYXBwcm94aW1hdGVkIHZhbHVlcyBpbiBvcmRlciB0byBwcmV2ZW50IHRoZXNlIGVudHJpZXMgZnJvbSBjb21pbmcgdXAgYXMgTkEgd2l0aGluIHRoZSBkYXRhIHNldC4gSG93ZXZlciwgaXQgaXMgaW1wb3J0YW50IHRvIGJlIG1pbmRmdWwgb2YgdGhlIGZhY3QgdGhhdCBmaWxsaW5nIGluIHRoZXNlIG1pc3NpbmcgZW50cmllcyBjb3VsZCBzdGlsbCBsZWFkIHRvIGEgcG90ZW50aWFsIHNrZXcgb3IgaW5hY2N1cmFjeSBpbiB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZXNlIHZhcmlhYmxlcyBhZnRlciBmaWxsaW5nIGluIHRoZSBtaXNzaW5nIG9ic2VydmF0aW9ucy4gSW4gb3JkZXIgdG8gcHJvcGVybHkgaGFuZGxlIHRoaXMsIHdlIHdpbGwgZmlyc3QgZml4IHRoZSBtaXNzaW5nIHZhbHVlcyBhbmQgdGhlbiBjaGVjayB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgdmFyaWFibGVzIHRvIGVuc3VyZSB0aGF0IHRoZXkgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBvciBhcmUgcHJhY3RpY2FsbHkgaW1wb3J0YW50IGVub3VnaCB2YXJpYWJsZXMgdG8gaW5jbHVkZSB3aXRoaW4gdGhlIGZpbmFsIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwuDQoNCg0KIyMgTXVsdGlwbGUgSW1wdXRhdGlvbiBvZiBNaXNzaW5nIE9ic2VydmF0aW9ucw0KDQpXZSB3aWxsIHVzZSBtdWx0aXBsZSBpbXB1dGF0aW9uIHRvIGZpbGwgaW4gdGhlIG1pc3NpbmcgdmFsdWVzIG9mIHRoZSBvYnNlcnZhdGlvbnMuIFVzaW5nIHRoaXMgbXVsdGlwbGUgaW1wdXRhdGlvbiBtZXRob2Qgd2lsbCB1c2UgYSByYW5kb21seSBpdGVyYXRlZCBtZXRob2QgdG8gZmlsbCBpbiB0aGUgbWlzc2luZyBvYnNlcnZhdGlvbnMgd2l0aGluIHRoZSBkYXRhIHNldC4gVGhpcyB3aWxsIGhlbHAgZW5zdXJlIHRoYXQgdGhlIG1pc3Npbmcgb2JzZXJ2YXRpb25zIGFyZSBmaWxsZWQgaW4gdGhlIGJlc3Qgd2F5IHBvc3NpYmxlIGJ5IGhhbmRsaW5nIG1pc3NpbmcgdmFsdWVzIGluIGEgd2F5IHRoYXQgcmVkdWNlcyB0aGUgY2hhbmNlIG9mIGZhbHNlIHByZWRpY3Rpb24uIFdlIHdpbGwgdXNlIHRoZSBNdWx0aXBsZSBJbXB1dGF0aW9uIHVzaW5nIENoYWluZWQgRXF1YXRpb25zIChNSUNFKSBmdW5jdGlvbiB0byB1c2UgbXVsdGlwbGUgaW1wdXRhdGlvbiB0byBmaWxsIGluIHRoZSBtaXNzaW5nIG9ic2VydmF0aW9ucy4gDQoNCldlIHdpbGwgc3RvcmUgdGhlIHJlc3VsdHMgb2YgdGhlIG11bHRpcGxlIGltcHV0YXRpb24gaW4gYW4gb2JqZWN0IGNhbGxlZCAibWljZSIgZm9yIG5vdy4NCg0KYGBge3J9DQpzZXQuc2VlZCgxKQ0KbWljZSA8LSBtaWNlKGhlYXJ0ZGlzZWFzZTAsIG1ldGhvZCA9ICJjYXJ0IikNCmBgYA0KDQpXZSB3aWxsIGNyZWF0ZSBhIG5ldyBkYXRhIGZyYW1lIGNhbGxlZCAiaGVhcnRkaXNlYXNlMSIgdG8gcmVwcmVzZW50IHRoZSBjb3JyZWN0ZWQgZGF0YSBzZXQgdGhhdCB3aWxsIGhhdmUgbm8gbWlzc2luZyB2YWx1ZXMgYWZ0ZXIgbXVsdGlwbGUgaW1wdXRhdGlvbi4gV2Ugd2lsbCBjb252ZXJ0IHRoZSByZXN1bHRzIG9mIHRoZSBtdWx0aXBsZSBpbXB1dGF0aW9uIGZyb20gYSBsYXJnZSBtaWRzIG9iamVjdCBiYWNrIHRvIGEgcmVndWxhciBkYXRhIGZyYW1lLiBUaGlzIHdpbGwgYmUgdXNlZCBmb3IgdGhlIGZ1dHVyZSBhbmFseXNpcyBhbmQgd2Ugd2lsbCBjYWxsIHRoaXMgb2JqZWN0ICJoZWFydGRpc2Vhc2UxIi4NCg0KYGBge3J9DQpoZWFydGRpc2Vhc2UxIDwtbWljZTo6Y29tcGxldGUobWljZSwyKSANCmBgYA0KDQpOb3cgdGhhdCB3ZSBoYXZlIHVzZWQgdGhlIG11bHRpcGxlIGltcHV0YXRpb24gbWV0aG9kIHRvIGZpbGwgaW4gYWxsIG9mIHRoZSBtaXNzaW5nIG9ic2VydmF0aW9ucywgbGV0J3MgZG91YmxlIGNoZWNrIHRoYXQgdGhlcmUgYXJlIG5vIG1vcmUgbWlzc2luZyBvYnNlcnZhdGlvbnMuIEFsbCBvZiB0aGUgdmFyaWFibGVzIHNob3VsZCBub3cgaGF2ZSBhIHZhbHVlIG9mIHplcm8gbWlzc2luZyBvYnNlcnZhdGlvbnMuIA0KDQpgYGB7cn0NCmNvbFN1bXMoaXMubmEoaGVhcnRkaXNlYXNlMSkpDQpgYGANCg0KQXMgd2UgY2FuIHNlZSwgYWxsIG9mIHRoZSB2YXJpYWJsZXMgbm93IGhhdmUgemVybyBtaXNzaW5nIG9ic2VydmF0aW9ucywgc28gd2Ugc3VjY2Vzc2Z1bGx5IGZpeGVkIGFsbCBvZiB0aGUgbWlzc2luZyB2YWx1ZXMgYnkgZmlsbGluZyB0aGVtIGluIHdpdGggbXVsdGlwbGUgaW1wdXRhdGlvbiBieSB0aGUgdXNlIG9mIHRoZSBtaWNlIGZ1bmN0aW9uLiBUaGUgcmV2aXNlZCBkYXRhIHNldCAiaGVhcnRkaXNlYXNlMSIgaGFzIG5vIG1pc3Npbmcgb2JzZXJ2YXRpb25zLCBzbyB3ZSB3aWxsIHVzZSB0aGlzIGZvciBmdXJ0aGVyIGFuYWx5c2lzIGFuZCBmb3IgY3JlYXRpbmcgdGhlIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgaW4gdGhlIGZ1dHVyZSBzdGVwcyBvZiB0aGlzIHByb2plY3QuDQoNCg0KDQojIyBGaXhpbmcgVmFyaWFibGUgVHlwZXMNCg0KT25lIG90aGVyIHRoaW5nIEkgbm90aWNlZCB3aGlsZSBsb29raW5nIHRocm91Z2ggdGhlIGRhdGEgc2V0IGlzIHRoYXQgdGhlIHZhcmlhYmxlICJjaWdzUGVyRGF5IiBpcyBnaXZlbiBhcyBhIGNoYXJhY3RlciB2YXJpYWJsZSBldmVuIHRob3VnaCBpdCBzaG91bGQgYmUgYSBudW1lcmljIHZhcmlhYmxlLiBUaGlzIHZhcmlhYmxlIGlzIGEgbWVhc3VyZSBvZiB0aGUgbnVtYmVyIG9mIGNpZ2FyZXR0ZXMgYSBwYXRpZW50IHNtb2tlcyBpbiBhIGRheSwgc28gaXQgc2hvdWxkIGJlIHJlcG9ydGVkIGFzIGEgbnVtZXJpYyB2YXJpYWJsZSBzaW5jZSBpdCBpcyBhIGNvbnRpbnVvdXMgcmFuZ2Ugb2YgcG9zc2libGUgdmFsdWVzIGFuZCBub3QgY29sbGVjdGVkIGFzIGNhdGVnb3JpZXMuIFNvLCBsZXQncyBjb252ZXJ0IGNpZ3NQZXJEYXkgZnJvbSBhIGNoYXJhY3RlciB2YXJpYWJsZSB0byBhIG51bWVyaWMgdmFyaWFibGUuIFdlIHdpbGwgdXNlIHRoZSBhcy5udW1lcmljKCkgZnVuY3Rpb24gdG8gY29udmVydCBjaWdzUGVyRGF5IHRvIGEgbnVtZXJpYyB2YXJpYWJsZS4NCg0KYGBge3J9DQpoZWFydGRpc2Vhc2UxJGNpZ3NQZXJEYXkgPC0gYXMubnVtZXJpYyhoZWFydGRpc2Vhc2UxJGNpZ3NQZXJEYXkpDQpgYGANCg0KTm93LCB0aGUgY2lnc1BlckRheSB2YXJpYWJsZSBpcyBjb3JyZWN0bHkgZ2l2ZW4gYXMgYSBudW1lcmljIHZhcmlhYmxlLg0KDQpUaGUgdmFyaWFibGUgb2YgYWdlIHNob3VsZCBhbHNvIGJlIGdpdmVuIGFzIGEgbnVtZXJpYyB2YWx1ZSwgYnV0IGlzIGlzIG5vdCBzbyB3ZSB3aWxsIGNvbnZlcnQgdGhpcyB2YXJpYWJsZSB0byBhIG51bWVyaWMgYXMgd2VsbC4NCg0KYGBge3J9DQpoZWFydGRpc2Vhc2UxJGFnZSA8LSBhcy5udW1lcmljKGhlYXJ0ZGlzZWFzZTEkYWdlKQ0KYGBgDQoNClRoZSB2YXJpYWJsZSBvZiBhZ2UgaXMgbm93IGNvcnJlY3RseSBnaXZlbiBhcyBhIG51bWVyaWMgdmFsdWUuIA0KDQpBZGRpdGlvbmFsbHksIHRoZSB2YXJpYWJsZSBCUE1lZHMgaXMgZ2l2ZW4gYXMgYSBjaGFyYWN0ZXIsIGhvd2V2ZXIgdGhpcyBpcyBhIGJpbmFyeSB2YXJpYWJsZSBzbyBpdCBzaG91bGQgYmUgZ2l2ZW4gYXMgYW4gaW50ZWdlciB2YXJpYWJsZSB3aXRoIHZhbHVlcyAwIGFuZCAxIGxpa2UgdGhlIG90aGVyIGJpbmFyeSB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0LiBXZSB3aWxsIGNvbnZlcnQgdGhpcyB2YXJpYWJsZSBmcm9tIGEgY2hhcmFjdGVyIHRvIGFuIGludGVnZXIuIFdlIHdpbGwgdXNlIHRoZSBhcy5pbnRlZ2VyKCkgZnVuY3Rpb24gdG8gZG8gdGhpcyBjb252ZXJzaW9uLg0KDQpgYGB7cn0NCmhlYXJ0ZGlzZWFzZTEkQlBNZWRzIDwtIGFzLmludGVnZXIoaGVhcnRkaXNlYXNlMSRCUE1lZHMpDQpgYGANCg0KTm93LCB0aGUgQlBNZWRzIHZhcmlhYmxlIGlzIGNvcnJlY3RseSBnaXZlbiBhcyBhIGJpbmFyeSwgaW50ZWdlciB2YXJpYWJsZS4NCg0KDQpBbm90aGVyIGlzc3VlIGlzIHRoYXQgdGhlIHZhcmlhYmxlIGZvciBlZHVjYXRpb24gaXMgc3VwcG9zZWQgdG8gYmUgY2F0ZWdvcmljYWwgd2l0aCBlYWNoIG51bWJlciByZXByZXNlbnRpbmcgYSBkaWZmZXJlbnQgY2F0ZWdvcnkgb2YgZWR1Y2F0aW9uIGxldmVsLiBIb3dldmVyLCB0aGlzIHZhcmlhYmxlIGlzIGdpdmVuIGFzIGFuIGludGVnZXIgdmFyaWFibGUuIFNvLCB3ZSB3aWxsIGZpeCB0aGlzIGJ5IG1ha2luZyBlZHVjYXRpb24gYSBjaGFyYWN0ZXIgdmFyaWFibGUuDQoNCmBgYHtyfQ0KaGVhcnRkaXNlYXNlMSRlZHVjYXRpb24gPC0gYXMuY2hhcmFjdGVyKGhlYXJ0ZGlzZWFzZTEkZWR1Y2F0aW9uKQ0KYGBgDQoNClRoZSBlZHVjYXRpb24gdmFyaWFibGUgaXMgbm93IGNvcnJlY3RseSBnaXZlbiBhcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLg0KDQpOb3csIGFsbCBvZiB0aGUgdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldCBhcmUgZ2l2ZW4gaW4gdGhlIGNvcnJlY3QgdHlwZXMgdGhhdCB0aGV5IHNob3VsZCBiZSBnaXZlbiBhcy4gDQoNCg0KDQojIyBDaGVja2luZyB0aGUgVmFyaWFibGUgRGlzdHJpYnV0aW9ucw0KDQoNCkJlZm9yZSB3ZSBiZWdpbiB3aXRoIGNyZWF0aW5nIGFuZCBjb21wYXJpbmcgdGhlIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxzLCB3ZSBzaG91bGQgZmlyc3QgY2hlY2sgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBzZXQgdG8gZW5zdXJlIHRoYXQgdGhleSBtZWV0IHRoZSBjcml0ZXJpYSBvZiBiZWluZyBhcHByb3hpbWF0ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBmb3IgdGhlIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMuIE9yLCBpZiB0aGUgdmFyaWFibGVzIGRvIG5vdCBhcHBlYXIgdG8gZm9sbG93IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgd2Ugd2lsbCBzZWUgaWYgdGhleSBhcmUgcHJhY3RpY2FsbHkgaW1wb3J0YW50IGVub3VnaCB0byBiZSBpbmNsdWRlZCB3aXRoaW4gdGhlIG1vZGVsIGJ1aWxkaW5nIHByb2Nlc3MgZGVzcGl0ZSB0aGVpciBsYWNrIG9mIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gV2Ugd2lsbCB0YWtlIGEgbG9vayBhdCBzb21lIG9mIHRoZSB2YXJpYWJsZXMsIHBhcnRpY3VhcmVsbHkgc29tZSBvZiB0aGUgcXVhbml0aWF0aXZlIHZhcmlhYmxlcyB3aGljaCBoYWQgbWlzc2luZyB2YWx1ZXMgdGhhdCB3ZXJlIGZpbGxlZCBpbiB0aHJvdWdoIHRoZSBtdWx0aXBsZSBpbXB1dGF0aW9uIHByb2Nlc3MuIA0KDQoNCiMjIyB0b3RDaG9sIERpc3RyaWJ1dGlvbg0KDQp0b3RDaG9sIHdhcyBvbmUgb2YgdGhlIHZhcmlhYmxlcyB0aGF0IGhhZCBzb21lIG1pc3Npbmcgb2JzZXJ2YXRpb25zIHRoYXQgd2VyZSBmaWxsZWQgaW4gZHVyaW5nIHRoZSBwcmV2aW91cyBzdGVwcy4gU28sIHdlIHNob3VsZCBkZWZpbmV0bHkgY2hlY2sgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGlzIHZhcmlhYmxlLg0KDQpgYGB7cn0NCnlsaW1pdCA9IG1heChkZW5zaXR5KGhlYXJ0ZGlzZWFzZTEkdG90Q2hvbCkkeSkNCmhpc3QoaGVhcnRkaXNlYXNlMSR0b3RDaG9sLCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAidG90Q2hvbCBEaXN0cmlidXRpb24iLCB4bGFiPSJ0b3RDaG9sIiwgDQogICAgICAgY29sID0gImFsaWNlYmx1ZSIsIGJvcmRlcj0iY29ybmZsb3dlcmJsdWUiKQ0KICBsaW5lcyhkZW5zaXR5KGhlYXJ0ZGlzZWFzZTEkdG90Q2hvbCwgYWRqdXN0PTIpLCBjb2w9ImRhcmtvcmNoaWQiKQ0KYGBgDQoNCk92ZXJhbGwsIHRvdENob2wgYXBwZWFycyB0byBiZSB1bmltb2RhbCBhbmQgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4gVGhlcmVmb3JlIHdlIGNhbiBzYXkgdGhhdCB0aGlzIHZhcmlhYmxlIGlzIHNhZmUgdG8gaW5jbHVkZSB3aXRoaW4gdGhlIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgYnVpbGRpbmcgcHJvY2VzcyBhbmQgdGhhdCB0aGUgcHJvY2VzcyBvZiBmaWxsaW5nIGluIHRoZSBtaXNzaW5nIG9ic2VydmF0aW9ucyBkaWQgbm90IGxlYWQgdG8gYW55IHNldmVyZSBjb25jZXJucyBmb3IgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGlzIHZhcmlhYmxlLg0KDQoNCiMjIyBCTUkgRGlzdHJpYnV0aW9uDQoNCkJNSSBpcyBhbm90aGVyIHZhcmlhYmxlIHRoYXQgaGFkIG1pc3Npbmcgb2JzZXJ2YXRpb25zIHRoYXQgd2VyZSBmaWxsZWQgaW4gZHVyaW5nIHRoZSBwcmV2aW91cyBzdGVwcy4gV2Ugd2lsbCBjaGVjayBpdHMgZGlzdHJpYnV0aW9uIHRvIG1ha2Ugc3VyZSBpdCBhcHBlYXJzIHRvIGJlIGFwcHJveGltYXRlbHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIA0KDQpgYGB7cn0NCnlsaW1pdCA9IG1heChkZW5zaXR5KGhlYXJ0ZGlzZWFzZTEkQk1JKSR5KQ0KaGlzdChoZWFydGRpc2Vhc2UxJEJNSSwgcHJvYmFiaWxpdHkgPSBUUlVFLCBtYWluID0gIkJNSSBEaXN0cmlidXRpb24iLCB4bGFiPSJCTUkiLCANCiAgICAgICBjb2wgPSAiYWxpY2VibHVlIiwgYm9yZGVyPSJjb3JuZmxvd2VyYmx1ZSIpDQogIGxpbmVzKGRlbnNpdHkoaGVhcnRkaXNlYXNlMSRCTUksIGFkanVzdD0yKSwgY29sPSJkYXJrb3JjaGlkIikNCmBgYA0KDQpUaGUgZGlzdHJpYnV0aW9uIGZvciBCTUkgaXMgdW5pbW9kYWwgYW5kIGFwcGVhcnMgdG8gYmUgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4gSXQgYXBwZWFycyB0aGF0IHRoZSBtYWpvcml0eSBvZiBpbmRpdmlkdWFscyBoYXZlIGEgQk1JIHNvbWV3aGVyZSBpbiB0aGUgcmFuZ2Ugb2YgMjAtMzAsIHdpdGggdGhlIHZhc3QgbWFqb3JpdHkgb2YgdGhlIGRhdGEgZmFsbGluZyB3aXRoaW4gdGhpcyByYW5nZS4gVGhpcyBhbGxvd3MgdXMgdG8gY29uY2x1ZGUgdGhhdCBpdCBpcyBzYWZlIHRvIGluY2x1ZGUgdGhlIHZhcmlhYmxlIG9mIEJNSSB3aXRoaW4gdGhlIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgYnVpbGRpbmcgcHJvY2VzcyBhbmQgdGhhdCB0aGUgcHJvY2VzcyBvZiBmaWxsaW5nIGluIHRoZSBtaXNzaW5nIHZhbHVlcyBkaWQgbm90IGxlYWQgdG8gYW55IG1ham9yIGNvbmNlcm5zIHdpdGggdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGlzIHZhcmlhYmxlLiANCg0KDQoNCiMjIyBHbHVjb3NlIERpc3RyaWJ1dGlvbg0KDQpUaGUgdmFyaWFibGUgZ2x1Y29zZSB3YXMgYW5vdGhlciB2YXJpYWJsZSB0aGF0IGhhZCBtaXNzaW5nIG9ic2VydmF0aW9ucyB3aGljaCB3ZXJlIGZpbGxlZCBpbiBkdXJpbmcgdGhlIHByZXZpb3VzIHN0ZXBzLiBXZSB3aWxsIGNoZWNrIGl0cyBkaXN0cmlidXRpb24gdG8gbWFrZSBzdXJlIHRoYXQgZXZlcnl0aGluZyBsb29rcyBhbHJpZ2h0Lg0KDQpgYGB7cn0NCnlsaW1pdCA9IG1heChkZW5zaXR5KGhlYXJ0ZGlzZWFzZTEkZ2x1Y29zZSkkeSkNCmhpc3QoaGVhcnRkaXNlYXNlMSRnbHVjb3NlLCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAiZ2x1Y29zZSIsIHhsYWI9ImdsdWNvc2UiLCANCiAgICAgICBjb2wgPSAiYWxpY2VibHVlIiwgYm9yZGVyPSJjb3JuZmxvd2VyYmx1ZSIpDQogIGxpbmVzKGRlbnNpdHkoaGVhcnRkaXNlYXNlMSRnbHVjb3NlLCBhZGp1c3Q9MiksIGNvbD0iZGFya29yY2hpZCIpDQpgYGANCg0KVGhlIHZhcmlhYmxlIGdsdWNvc2UgaXMgdW5pbW9kYWwgYW5kIGFwcGVhcnMgdG8gYmUgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZCB3aXRoIHRoZSBleGNlcHRpb24gb2YgYSBmZXcgb3V0bGllcnMgdG8gdGhlIHJpZ2h0LiBUaGUgbW9zdCBjb21tb24gZ2x1Y29zZSB2YWx1ZSBhcHBlYXJzIHRvIGJlIGFyb3VuZCA3NSwgd2l0aCB0aGUgaGlzdG9ncmFtIHBlYWtpbmcgYXJvdW5kIHRoaXMgdmFsdWUuIERlc3BpdGUgdGhlIGZldyBvdXRsaWVycywgd2Ugd2lsbCBrZWVwIHRoaXMgdmFyaWFibGUgaW4gdGhlIGZpbmFsIG1vZGVsIHNpbmNlIGEgcGF0aWVudCdzIGdsdWNvc2UgbGV2ZWwgaXMgYSBtZWRpY2FsbHkgaW1wb3J0YW50IHZhcmlhYmxlIHdoaWNoIHdvdWxkIGJlIGhlbHBmdWwgdG8ga25vdyBpbiBvcmRlciB0byBhc3Nlc3MgYSBwYXRpZW50J3Mgb2RkcyBvZiBiZWluZyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRC4gIA0KDQoNCg0KIyMjIGNpZ3NQZXJEYXkgRGlzdHJpYnV0aW9uDQoNCmNpZ3NQZXJEYXkgd2FzIGFub3RoZXIgdmFyaWFibGUgdGhhdCBoYWQgbWlzc2luZyBvYnNlcnZhdGlvbnMgd2hpY2ggd2VyZSBmaWxsZWQgaW4gZHVyaW5nIHRoZSBwcmV2aW91cyBzdGVwcy4gU28sIHdlIHNob3VsZCBjaGVjayBpdHMgZGlzdHJpYnV0aW9uIHRvIG1ha2Ugc3VyZSB0aGluZ3MgbG9vayBhbHJpZ2h0Lg0KDQpgYGB7cn0NCnlsaW1pdCA9IG1heChkZW5zaXR5KGhlYXJ0ZGlzZWFzZTEkY2lnc1BlckRheSkkeSkNCmhpc3QoaGVhcnRkaXNlYXNlMSRjaWdzUGVyRGF5LCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAiY2lnc1BlckRheSIsIHhsYWI9ImNpZ3NQZXJEYXkiLCANCiAgICAgICBjb2wgPSAiYWxpY2VibHVlIiwgYm9yZGVyPSJjb3JuZmxvd2VyYmx1ZSIpDQogIGxpbmVzKGRlbnNpdHkoaGVhcnRkaXNlYXNlMSRjaWdzUGVyRGF5LCBhZGp1c3Q9MiksIGNvbD0iZGFya29yY2hpZCIpDQpgYGANCg0KVGhlIHZhcmlhYmxlIGNpZ3NQZXJEYXkgYXBwZWFycyB0byBiZSB2ZXJ5IG5vdGFibHkgc2tld2VkIHRvIHRoZSByaWdodC4gVGhpcyBjYW4gYmUgYXR0cmlidXRlZCB0byB0aGF0IHRoaXMgdmFyaWFibGUgcmVwcmVzZW50cyB0aGUgbnVtYmVyIG9mIGNpZ2FyZXR0ZXMgYSBwYXRpZW50IHNtb2tlcyBwZXIgZGF5LiBNYW55IG9mIHRoZSBwYXRpZW50cyBpbmNsdWRlZCBpbiB0aGUgZGF0YSBjb2xsZWN0aW9uIHdlcmUgbm90IHNtb2tlcnMsIHNvIHRoZXkgd291bGQgaGF2ZSByZXBvcnRlZCBhIHZhbHVlIG9mIDAgY2lnYXJldHRlcyBzbW9rZWQgcGVyIGRheS4gVGhpcyBjYW4gZXhwbGFpbiB0aGUgc2tldyB0byB0aGUgcmlnaHQgb2YgdGhpcyB2YXJpYWJsZSwgYmVjYXVzZSBub24tc21va2VycyB3b3VsZCByZXBvcnQgYSB2YWx1ZSBvZiAwIHdoaWxlIHNtb2tlcnMgd291bGQgcmVwb3J0IGEgdmFsdWUgZ3JlYXRlciB0aGFuIDAgdGhhdCByZXByZXNlbnRzIHRoZSBudW1iZXIgb2YgY2lnYXJldHRlcyB0aGV5IHNtb2tlIGluIGEgZGF5LiANClRoaXMgaXMgYSBwcmF0aWNhbGx5IGltcG9ydGFudCB2YXJpYWJsZSByZWdhcmRsZXNzIG9mIGl0cyBza2V3LCBiZWNhdXNlIHNtb2tpbmcgaXMgYSBtYWpvciByaXNrIGZhY3RvciBmb3IgY29uZGl0aW9ucyBsaWtlIENIRC4gQWRkaXRpb25hbGx5LCB0aGlzIGlzIGFuIGltcG9ydGFudCBwaWVjZSBvZiBpbmZvcm1hdGlvbiwgYmVjYXVzZSBkb2N0b3JzIHdvdWxkIHdhbnQgdG8ga25vdyBob3cgbWFueSBjaWdhcmV0dGVzIHRoZWlyIHBhdGllbnRzIHNtb2tlIGluIGEgZGF5LCBiZWNhdXNlIHRoaXMgaGFzIGEgc2lnbmlmaWNhbnQgaW1wYWN0IG9uIHRoZSBwYXRpZW50J3MgcmlzayBmYWN0b3JzLiBTbywgd2Ugd2lsbCBrZWVwIHRoaXMgdmFyaWFibGUgaW4gdGhlIGZpbmFsIG1vZGVsIGRlc3BpdGUgaXRzIHNrZXcgYmVjYXVzZSBpdCBpcyBhbiBpbXBvcnRhbnQgdmFyaWFibGUgaW4gcmVnYXJkcyB0byBhIHBhdGllbnQncyBwb3RlbnRpYWwgcmlzayBmYWN0b3JzIGZvciBkZXZlbG9waW5nIENIRC4gQnV0LCBpdCBpcyBpbXBvcnRhbnQgdG8ga2VlcCBpbiBtaW5kIHRoYXQgdGhpcyB2YXJpYWJsZSBpcyBza2V3ZWQgZHVlIHRvIGl0IGJlaW5nIHJlcHJlc2VudGF0aXZlIG9mIGJvdGggbm9uLXNtb2tlcnMgYW5kIHNtb2tlcnMuIA0KDQoNCiMjIyBoZWFydFJhdGUgRGlzdHJpYnV0aW9uDQoNClRoZSB2YXJpYWJsZSBoZWFydFJhdGUgd2FzIGFub3RoZXIgb25lIHdoaWNoIGhhZCBzb21lIG1pc3Npbmcgb2JzZXJ2YXRpb25zIHRoYXQgbmVlZGVkIHRvIGJlIGZpbGxlZCBpbiBkdXJpbmcgcHJldmlvdXMgc3RlcHMuIFdlIHdpbGwgY2hlY2sgaXRzIGRpc3RyaWJ1dGlvbiB0byBlbnN1cmUgdGhhdCBldmVyeXRoaW5nIGxvb2tzIGFscmlnaHQuIA0KDQpgYGB7cn0NCnlsaW1pdCA9IG1heChkZW5zaXR5KGhlYXJ0ZGlzZWFzZTEkaGVhcnRSYXRlKSR5KQ0KaGlzdChoZWFydGRpc2Vhc2UxJGhlYXJ0UmF0ZSwgcHJvYmFiaWxpdHkgPSBUUlVFLCBtYWluID0gImhlYXJ0UmF0ZSIsIHhsYWI9ImhlYXJ0UmF0ZSIsIA0KICAgICAgIGNvbCA9ICJhbGljZWJsdWUiLCBib3JkZXI9ImNvcm5mbG93ZXJibHVlIikNCiAgbGluZXMoZGVuc2l0eShoZWFydGRpc2Vhc2UxJGhlYXJ0UmF0ZSwgYWRqdXN0PTIpLCBjb2w9ImRhcmtvcmNoaWQiKQ0KYGBgDQoNClRoZSBkaXN0cmlidXRpb24gZm9yIGhlYXJ0IHJhdGUgaXMgdW5pbW9kYWwgYW5kIGFwcHJveGltYXRlbHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgd2l0aG91dCBhbnkgbm90YWJsZSBza2V3IG9yIG91dGxpZXJzIHRoYXQgYXJlIGFwcGFyZW50IGluIGl0cyBkZW5zaXR5IHBsb3QuIFRoaXMgYWxsb3dzIHVzIHRvIGNvbmNsdWRlIHRoYXQgdGhpcyB2YXJpYWJsZSBpcyBzYWZlIHRvIGluY2x1ZGUgd2l0aGluIHRoZSBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIGJ1aWxkaW5nIHByb2Nlc3MgYW5kIHRoYXQgdGhlIHByb2Nlc3Mgb2YgZmlsbGluZyBpbiB0aGUgbWlzc2luZyB2YWx1ZXMgZGlkIG5vdCBsZWFkIHRvIGFueSBpc3N1ZXMgaW4gaXRzIGRpc3RyaWJ1dGlvbi4NCg0KDQojIyMgT3ZlcmFsbCBGaW5kaW5ncw0KDQpXZSBoYXZlIGNoZWNrZWQgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIHZhcmlhYmxlcyB3aGljaCBoYWQgbWlzc2luZyBvYnNlcnZhdGlvbnMgdGhhdCB3ZXJlIGZpbGxlZCBpbiBkdXJpbmcgdGhlIHByZXZpb3VzIHN0ZXBzIG9mIHRoaXMgcHJvamVjdCBhbG9uZyB3aXRoIG90aGVyIGltcG9ydGFudCBxdWFudGl0YXRpdmUgdmFyaWFibGVzIGluIHRoaXMgZGF0YSBzZXQuIFdlIGVuc3VyZWQgdGhhdCB0aGUgdmFyaWFibGVzIGVpdGhlciBmb2xsb3dzIGEgZGlzdHJpYnV0aW9uIHRoYXQgYXBwZWFycyB0byBiZSBhcHByb3hpbWF0ZWx5IG5vcm1hbCwgb3IgYXJlIHByYWN0aWNhbGx5IGltcG9ydGFudCBlbm91Z2ggdG8gYmUgaW5jbHVkZWQgaW4gdGhlIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgYnVpbGRpbmcgcHJvY2VzcyBvdGhlcndpc2UuIA0KDQpUaGUgb25seSB2YXJpYWJsZSB0aGF0IGRpZCBub3QgYXBwZWFyIHRvIGZvbGxvdyBhbiBhcHByb3hpbWF0ZWx5IG5vcm1hbCBkaXN0cmlidXRpb24gd2FzIGNpZ3NQZXJEYXkuIEhvd2V2ZXIsIHRoZSBza2V3bmVzcyBzZWVuIGluIHRoaXMgdmFyaWFibGUncyBkaXN0cmlidXRpb24gY2FuIGJlIGF0dHJpYnV0ZWQgdG8gdGhlIGZhY3QgdGhhdCB0aGlzIGRhdGEgd2FzIGNvbGxlY3RlZCBhbW9uZ3N0IGJvdGggc21va2VycyBhbmQgbm9uLXNtb2tlcnMuIFNvLCBub24tc21va2VycyByZXBvcnRlZCB2YWx1ZXMgb2YgMCBjaWdhcmV0dGVzIHNtb2tlZCBwZXIgZGF5LCB3aGlsZSBzbW9rZXJzIHJlcG9ydGVkIHZhbHVlcyB0aGF0IHdlcmUgZ3JlYXRlciB0aGFuIHplcm8uIFRoaXMgYXBwZWFyZWQgdG8gdGhlIGRpc3RyaWJ1dGlvbiBmb3IgdGhpcyB2YXJpYWJsZSBhcHBlYXJpbmcgdG8gYmUgc2tld2VkIHRvIHRoZSByaWdodC4gSG93ZXZlciwgdGhpcyBpcyBhIHZhcmlhYmxlIHRoYXQgaXMgcHJhY3RpY2FsbHkgaW1wb3J0YW50IGJlY2F1c2UgdGhlIG51bWJlciBvZiBjaWdhcmV0dGVzIGEgcGF0aWVudCBzbW9rZXMgcGVyIGRheSBjYW4gaGF2ZSBhIHNpZ25pZmljYW50IGltcGFjdCBvbiB0aGVpciBvZGRzIG9mIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hELiBEdWUgdG8gdGhlIHByYWN0aWNhbCBpbXBvcnRhbmNlIG9mIHRoaXMgdmFyaWFibGUsIGl0IG11c3Qgc3RpbGwgYmUgaW5jbHVkZWQgd2l0aGluIHRoZSBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIGJ1aWxkaW5nIHByb2Nlc3MuDQoNCkFsdG9nZXRoZXIsIHdlIGhhdmUgZW5zdXJlZCB0aGF0IHRoZSB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhIHNldCBhcHBlYXIgdG8gYmUgZ29vZCBlbm91Z2ggdG8gdXNlIHdpdGhpbiB0aGUgbW9kZWwgYnVpbGRpbmcgcHJvY2Vzcy4gU28sIG5vdyB3ZSB3aWxsIGJlZ2luIHdpdGggdGhlIHByb2Nlc3Mgb2YgYnVpbGRpbmcgdGhlIGNhbmRpZGF0ZSBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVscy4gDQoNCg0KDQoNCiMgVmFyaWFibGUgVHJhbnNmb3JtYXRpb24tIFN0YW5kYXJkaXppbmcgdGhlIFF1YW50aXRhdGl2ZSBWYXJpYWJsZXMNCg0KDQpUaGUgbWFpbiBnb2FsIGZvciB0aGlzIHByb2plY3QgaXMgdG8gZmluZCBhIG1vZGVsIHdpdGggdGhlIGJlc3QgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZSBhbmQgcG93ZXIuIEluIG9yZGVyIHRvIGRvIHNvLCB3ZSB3aWxsIHN0YW5kYXJkaXplIHRoZSBxdWFudGl0YXRpdmUgdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldCB0byBlbnN1cmUgdGhhdCBvdXIgZGF0YSB3aWxsIGJlIGl0cyBiZXN0IGZvciBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlLiANCg0KV2Ugd2lsbCBzdGFuZGFyZGl6ZSBhbGwgb2YgdGhlIG51bWVyaWMsIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMgaW4gb3JkZXIgdG8gZ2l2ZSBvdXIgZGF0YSB0aGUgYmVzdCBwcmVkaWN0aXZlIHBvd2VyIGZvciB0aGUgZnV0dXJlIG1vZGVsIGJ1aWxkaW5nIHdlIHdpbGwgY29uZHVjdCBpbiB0aGUgZm9sbG93aW5nIHN0ZXBzLiANCg0KYGBge3J9DQojIEFnZQ0KaGVhcnRkaXNlYXNlMSRzZC5hZ2UgPSAoaGVhcnRkaXNlYXNlMSRhZ2UtbWVhbihoZWFydGRpc2Vhc2UxJGFnZSkpL3NkKGhlYXJ0ZGlzZWFzZTEkYWdlKQ0KDQojIGNpZ3NQZXJEYXkNCmhlYXJ0ZGlzZWFzZTEkc2QuY2lnc1BlckRheSA9IChoZWFydGRpc2Vhc2UxJGNpZ3NQZXJEYXktbWVhbihoZWFydGRpc2Vhc2UxJGNpZ3NQZXJEYXkpKS9zZChoZWFydGRpc2Vhc2UxJGNpZ3NQZXJEYXkpDQoNCiMgdG90Q2hvbA0KaGVhcnRkaXNlYXNlMSRzZC50b3RDaG9sID0gKGhlYXJ0ZGlzZWFzZTEkdG90Q2hvbC1tZWFuKGhlYXJ0ZGlzZWFzZTEkdG90Q2hvbCkpL3NkKGhlYXJ0ZGlzZWFzZTEkdG90Q2hvbCkNCg0KIyBzeXNCUA0KaGVhcnRkaXNlYXNlMSRzZC5zeXNCUCA9IChoZWFydGRpc2Vhc2UxJHN5c0JQLW1lYW4oaGVhcnRkaXNlYXNlMSRzeXNCUCkpL3NkKGhlYXJ0ZGlzZWFzZTEkc3lzQlApDQoNCiMgZGlhQlANCmhlYXJ0ZGlzZWFzZTEkc2QuZGlhQlAgPSAoaGVhcnRkaXNlYXNlMSRkaWFCUC1tZWFuKGhlYXJ0ZGlzZWFzZTEkZGlhQlApKS9zZChoZWFydGRpc2Vhc2UxJGRpYUJQKQ0KDQojIEJNSQ0KaGVhcnRkaXNlYXNlMSRzZC5CTUkgPSAoaGVhcnRkaXNlYXNlMSRCTUktbWVhbihoZWFydGRpc2Vhc2UxJEJNSSkpL3NkKGhlYXJ0ZGlzZWFzZTEkQk1JKQ0KDQojIGhlYXJ0UmF0ZQ0KaGVhcnRkaXNlYXNlMSRzZC5oZWFydFJhdGUgPSAoaGVhcnRkaXNlYXNlMSRoZWFydFJhdGUtbWVhbihoZWFydGRpc2Vhc2UxJGhlYXJ0UmF0ZSkpL3NkKGhlYXJ0ZGlzZWFzZTEkaGVhcnRSYXRlKQ0KDQojIGdsdWNvc2UNCmhlYXJ0ZGlzZWFzZTEkc2QuZ2x1Y29zZSA9IChoZWFydGRpc2Vhc2UxJGdsdWNvc2UtbWVhbihoZWFydGRpc2Vhc2UxJGdsdWNvc2UpKS9zZChoZWFydGRpc2Vhc2UxJGdsdWNvc2UpDQpgYGANCg0KV2Ugd2lsbCBjcmVhdGUgYSBuZXcgZGF0YSBvYmplY3QgdG8gc3RvcmUgdGhlIG5ldyBzdGFuZGFyZGl6ZWQgdmFyaWFibGVzIGFsb25nIHdpdGggYWxsIG9mIHRoZSBiaW5hcnkgYW5kIGNhdGVnb3JpY2FsIHByZWRpY3RvciB2YXJpYWJsZXMgZnJvbSB0aGUgcHJldmlvdXMgZGF0YSBzZXQuIFdlIHdpbGwgY2FsbCB0aGUgbmV3IGRhdGEgc2V0IHdpdGggYWxsIG9mIHRoZSBzdGFuZGFyZGl6ZWQgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyAic2QuaGVhcnRkaXNlYXNlIi4gDQoNCmBgYHtyfQ0KIyBOZXcgZGF0YSBzZXQgd2l0aCBvcmlnaW5hbCwgbm9uLXN0YW5kYXJkaXplZCB2YXJpYWJsZXMgZHJvcHBlZC4NCnNkLmhlYXJ0ZGlzZWFzZSA9IHNlbGVjdChoZWFydGRpc2Vhc2UxLCAtMiwtNSwtMTA6LTE1KQ0KYGBgDQoNCk5vdywgYWxsIG9mIHRoZSBxdWFudGl0YXRpdmUsIG51bWVyaWNhbCB2YXJpYWJsZXMgaW4gdGhlIG9yaWdpbmFsIGRhdGEgc2V0IGhhdmUgYmVlbiBzdGFuZGFyZGl6ZWQgaW4gb3JkZXIgdG8gZW5zdXJlIHRoYXQgb3VyIGZ1dHVyZSBtb2RlbCB3aWxsIGhhdmUgdGhlIGJlc3QgcHJlZGljdGl2ZSBwb3dlciBiZWNhdXNlIHRoZSBnb2FsIG9mIHRoaXMgcHJvamVjdCBpcyB0byBjcmVhdGUgYSBtb2RlbCB3aXRoIHRoZSBiZXN0IHByZWRpY3RpdmUgcG93ZXIgYW5kIHBlcmZvcm1hbmNlLiANCg0KDQoNCg0KIyBEYXRhIFNwbGl0DQoNCldlIHdpbGwgbm93IHNwbGl0IHRoZSBkYXRhIHVwIGludG8gdHJhaW5pbmcgYW5kIHRlc3RpbmcgZGF0YS4gV2Ugd2lsbCByYW5kb21seSBzcGxpdCB0aGUgZGF0YSBzbyB0aGF0IDgwJSBvZiB0aGUgZGF0YSB3aWxsIGJlIHVzZWQgZm9yIHRyYWluaW5nIGFuZCAyMCUgb2YgdGhlIGRhdGEgd2lsbCBiZSB1c2VkIGZvciB0ZXN0aW5nLiBCeSBzcGxpdHRpbmcgdGhlIGRhdGEgdXAgaW50byB0aGUgdHJhaW5pbmcgYW5kIHRoZSB0ZXN0aW5nIGRhdGEsIHRoaXMgd2lsbCBhbGxvdyB1cyB0byBidWlsZCB0aGUgY2FuZGlkYXRlIG1vZGVscyBhbmQgYW5hbHl6ZSB0aGVpciBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlcy4gV2Ugd2lsbCB1c2UgdGhlIHNwbGl0IGRhdGEgdG8gY29uZHVjdCB0aGUgY3Jvc3MgdmFsaWRhdGlvbiBwcm9jZXNzIHRvIGFuYWx5c2lzIHRoZSBwcmVkaWN0aXZlIHBvd2VyIGFuZCBwZXJmb3JtYW5jZXMgb2YgZWFjaCBvZiB0aGUgdGhyZWUgY2FuZGlkYXRlIG1vZGVscyB3ZSB3aWxsIGludmVzdGlnYXRlLiBUaGlzIHdpbGwgYWxsb3cgdXMgdG8gZXZlbnR1YWxseSBkZXRlcm1pbmUgd2hpY2ggb2YgdGhlc2UgdGhyZWUgbW9kZWxzIGlzIHRoZSBpZGVhbCBjaG9pY2UgZm9yIG91ciBmaW5hbCBtb2RlbCBiYXNlZCB1cG9uIGl0cyBvdmVyYWxsIHByZWRpY3RpdmUgcG93ZXIuIA0KDQpgYGB7cn0NCiMgU3BsaXQgdGhlIGRhdGEgaW50byA4MCUgdHJhaW5pbmcgYW5kIDIwJSB0ZXN0aW5nLg0KbiA8LSBkaW0oc2QuaGVhcnRkaXNlYXNlKVsxXQ0KdHJhaW4ubiA8LSByb3VuZCgwLjgqbikNCnRyYWluLmlkIDwtIHNhbXBsZSgxOm4sIHRyYWluLm4sIHJlcGxhY2UgPSBGQUxTRSkNCg0KdHJhaW4gPC0gc2QuaGVhcnRkaXNlYXNlW3RyYWluLmlkLCBdDQp0ZXN0IDwtIHNkLmhlYXJ0ZGlzZWFzZVstdHJhaW4uaWQsIF0NCmBgYA0KDQpOb3csIG91ciBkYXRhIGhhcyBiZWVuIHNwbGl0IHVwIGludG8gYSB0cmFpbmluZyBhbmQgYSB0ZXN0aW5nIGRhdGEgc2V0LCB3aXRoIDgwJSBvZiB0aGUgZGF0YSBmb3IgdHJhaW5pbmcgYW5kIHRoZSByZW1haW5pbmcgMjAlIGZvciB0ZXN0aW5nLiBUaGUgb2JzZXJ2YXRpb25zIHdlcmUgc3BsaXQgdXAgcmFuZG9tbHkgYW1vbmdzdCB0aGVzZSB0d28gZGF0YSBzZXRzLiBXZSB3aWxsIHNwZWNpZmljYWxseSB1c2UgdGhlIHRyYWluaW5nIGRhdGEgZm9yIHRoZSBjcm9zcyB2YWxpZGF0aW9uIHByb2Nlc3MuIFRoaXMgcHJvY2VzcyB3aWxsIGFsbG93IHVzIHRvIGlkZW50aWZ5IHdoaWNoIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgaXMgdGhlIGJlc3QgbW9kZWwgZm9yIHRoZSBwdXJwb3NlIG9mIHByZWRpY3Rpb24uIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBzZWxlY3QgYSBtb2RlbCB3aGljaCBwcmVkaWN0cyB0aGUgb2RkcyBvZiBhbiBpbmRpdmlkdWFsIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hEIHdpdGggdGhlIGhpZ2hlc3QgcXVhbGl0eSBvZiBwcmVkaWN0aW9uLiANCg0KDQoNCg0KIyBCZXN0IE1vZGVsIElkZW50aWZpY2F0aW9uDQoNCk5vdyB0aGF0IG91ciB2YXJpYWJsZXMgaGF2ZSBiZWVuIGNoZWNrZWQgYW5kIHN0YW5kYXJkaXplZCB0byBlbnN1cmUgdGhlaXIgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZSBiZWluZyB0aGUgYmVzdCB0aGF0IGl0IHBvc3NpYmx5IGNhbiBiZSwgd2Ugd2lsbCBiZWdpbiB3aXRoIHRoZSBtb2RlbCBidWlsZGluZyBwcm9jZXNzLiBXZSB3aWxsIGxvb2sgYXQgdGhyZWUgcG90ZW50aWFsLCBjYW5kaWRhdGUgbW9kZWxzIGZvciB0aGUgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiBhbmQgZGV0ZXJtaW5lIHdoaWNoIG9uZSBoYXMgdGhlIGJlc3QgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZS4gDQoNCiMjIERlc2NyaXB0aW9ucyBvZiB0aGUgVGhyZWUgQ2FuZGlkYXRlIE1vZGVscyANCg0KV2Ugd2lsbCB0YWtlIGEgbG9vayBpbnRvIHRoZSBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgdGhyZWUgY2FuZGlkYXRlIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxzLiANCg0KDQojIyMgRnVsbCBNb2RlbA0KDQpUaGUgZmlyc3Qgb2YgdGhlIHRocmVlIG1vZGVscyB3aWxsIGJlIHRoZSBmdWxsIG1vZGVsLCB3aXRoIGFsbCBvZiB0aGUgdmFyaWFibGVzIGluY2x1ZGVkLiBUaGlzIGZ1bGwgbW9kZWwgd2lsbCB1c2UgYWxsIG9mIHRoZSB2YXJpYWJsZXMgaW4gb3JkZXIgdG8gY3JlYXRlIGEgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiB0byBwcmVkaWN0IHRoZSBvZGRzIG9mIGEgcGF0aWVudCBiZWluZyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRCBpbiBhIDEwLXllYXIgcGVyaW9kLiANCg0KVGhlICByZWdyZXNzaW9uIGVxdWF0aW9uIGZvciB0aGlzIGZ1bGwgbW9kZWwgaXMgcmVwcmVzZW50ZWQgYXM6DQoNClRlblllYXJDSEQgPSBtYWxlICsgc2QuYWdlICsgZWR1Y2F0aW9uICsgY3VycmVudFNtb2tlciArIHNkLmNpZ3NQZXJEYXkgKyBCUE1lZHMgKyBwcmV2YWxlbnRTdHJva2UgKyBwcmV2YWxlbnRIeXAgKyBkaWFiZXRlcyArIHNkLnRvdENob2wgKyBzZC5zeXNCUCArIHNkLmRpYUJQICsgc2QuQk1JICsgc2QuaGVhcnRSYXRlICsgc2QuZ2x1Y29zZQ0KDQpXZSB3aWxsIGZpbmQgdGhlIHNwZWNpZmljIG11bHRpcGxlIGxvZ2lzaXRpYyByZWdyZXNzaW9uIGVxdWF0aW9uIGZvciB0aGlzIGZ1bGwgbW9kZWwuDQoNCmBgYHtyfQ0KZnVsbC5tb2RlbCA9IGdsbShUZW5ZZWFyQ0hEIH4gbWFsZSArIHNkLmFnZSArIGVkdWNhdGlvbiArIGN1cnJlbnRTbW9rZXIgKyBzZC5jaWdzUGVyRGF5ICsgQlBNZWRzICsgcHJldmFsZW50U3Ryb2tlICsgcHJldmFsZW50SHlwICsgZGlhYmV0ZXMgKyBzZC50b3RDaG9sICsgc2Quc3lzQlAgKyBzZC5kaWFCUCArIHNkLkJNSSArIHNkLmhlYXJ0UmF0ZSArIHNkLmdsdWNvc2UsIA0KICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgIA0KICAgICAgICAgIGRhdGEgPSBzZC5oZWFydGRpc2Vhc2UpICANCmthYmxlKHN1bW1hcnkoZnVsbC5tb2RlbCkkY29lZiwgDQogICAgICBjYXB0aW9uID0gIkZ1bGwgTW9kZWwgU3VtbWFyeSBvZiB0aGUgSW5mZXJlbnRpYWwgU3RhdGlzdGljcyIpDQpgYGANCg0KVGhlIGVxdWF0aW9uIGZvciB0aGUgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiBlcXVhdGlvbiBvZiB0aGUgZnVsbCBtb2RlbCBpcyBnaXZlbiBhcyBmb2xsb3dzOg0KDQpsb2cgcC8oMS1wKSA9IC0yLjIwMjQgKyAwLjQ4NTIgKiBtYWxlICsgMC41MTY5ICogc2QuYWdlIC0gMC4yMzU2ICogZWR1Y2F0aW9uMiAtIDAuMTAyNiAqIGVkdWNhdGlvbjMgKyAwLjAxMTUgKiBlZHVjYXRpb240ICsgMC4wMjE5ICogY3VycmVudFNtb2tlcisgMC4yNTA3ICogc2QuY2lnc1BlckRheSArIDAuMzI3MCAqIEJQTWVkcyArIDAuOTM4OSAqIHByZXZhbGVudFN0cm9rZSArIDAuMjMxMiAqIHByZXZhbGVudEh5cCArIDAuMDkxMiAqIGRpYWJldGVzICsgMC4wODAzICogc2QudG90Q2hvbCArIDAuMzA3NSAqIHNkLnN5c0JQIC0gMC4wMzI3ICogc2QuZGlhQlAgKyAwLjAwNzEgKiBzZC5CTUkgLSAwLjAxMzcgKiBzZC5oZWFydFJhdGUgKyAwLjE3MzAgKiBzZC5nbHVjb3NlDQoNCg0KIyMjIFJlZHVjZWQgTW9kZWwNCg0KVGhlIHNlY29uZCBvZiB0aGUgdGhyZWUgbW9kZWxzIHdpbGwgYmUgdGhlIHJlZHVjZWQgbW9kZWwuIFRoaXMgbW9kZWwgd2lsbCBjb25zaXN0IG9ubHkgb2YgdGhlIG1vc3QgcHJhY3RpY2FsbHkgaW1wb3J0YW50IHZhcmlhYmxlcyB3aXRoaW4gdGhlIGNvbnRleHQgb2YgdGhpcyBzaXR1YXRpb24sIHVzaW5nIHZhcmlvdXMgZmFjdG9ycyB0byBiZXN0IHByZWRpY3QgdGhlIG9kZHMgb2YgYW4gaW5kaXZpZHVhbCBiZWluZyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRC4gVGhlIFVuaXRlZCBTdGF0ZXMgTmF0aW9uYWwgTGlicmFyeSBvZiBNZWRpY2luZSBvZiB0aGUgTmF0aW9uYWwgSW5zdGl0dXRlcyBvZiBIZWFsdGggKE5JSCksIHRoZSBtb3N0IG5vdGFibGUgcmlzayBmYWN0b3JzIGZvciBhbiBpbmRpdmlkdWFsIGJlaW5nIGF0IHJpc2sgb2YgZGV2ZWxvcGluZyBDSEQgYXJlIGNpZ2FyZXR0ZSBzbW9raW5nLCBibG9vZCBwcmVzc3VyZSwgYW5kIGNob2xlc3Rlcm9sIGxldmVscy4gSW4gdGhpcyBkYXRhIHNldCwgdGhlcmUgYXJlIHR3byB2YXJpYWJsZXMgcmVsYXRlZCB0byBzbW9raW5nLCBjdXJyZW50U21va2VyLCB3aGV0aGVyIGEgcGF0aWVudCBpcyBjdXJyZW50bHkgYSBzbW9rZXIgb3Igbm90LCBhbmQgY2lnc1BlckRheSB3aGljaCBpcyB3YXMgc2NhbGVkIHRvIHNkLmNpZ3NQZXJEYXksIGhvdyBtYW55IGNpZ2FyZXR0ZXMgYSBwYXRpZW50IHNtb2tlcyBpbiBhIGRheS4gVGhlcmUgYXJlIGFsc28gdHdvIHZhcmlhYmxlcyByZWxhdGVkIHRvIGJsb29kIHByZXNzdXJlLCBzeXNCUCBhbmQgZGlhQlAsIGZvciBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBhbmQgZGlhc3RvbGljIGJsb29kIHByZXNzdXJlLiBCb3RoIG9mIHRoZXNlIGJsb29kIHByZXNzdXJlIHZhcmlhYmxlcyB3ZXJlIHNjYWxlZCBhbmQgYXJlIG5vdyBnaXZlbiBhcyBzZC5zeXNCUCBhbmQgc2QuZGlhQlAuIFRoZXJlIGlzIGFsc28gYSB2YXJpYWJsZSBpbmNsdWRlZCBpbiB0aGUgZGF0YSBzZXQgZm9yIGEgcGF0aWVudCdzIHRvdGFsIGNob2xlc3Rlcm9sIGxldmVscywgdG90Q2hvbCwgd2hpY2ggd2FzIHNjYWxlZCBhbmQgaXMgbm93IGdpdmVuIGFzIHNkLnRvdENob2wuIFRoZXNlIGZpdmUgdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldCByZXByZXNlbnQgdGhlIGtleSByaXNrIGZhY3RvcnMgdGhhdCB0aGUgbWVkaWNhbCByZXBvcnQgZnJvbSB0aGUgTklIIHN0YXRlZCBhcyBiZWluZyB0aGUgbW9zdCBzaWduaWZpY2FudCBpbiBwcmVkaWN0aW5nIGEgcGF0aWVudCdzIHJpc2sgZm9yIENIRC4gU28sIG91ciByZWR1Y2VkIG1vZGVsIHdpbGwgY29uc2lzdCBvbmx5IG9mIHRoZXNlIHBhcnRpY3VsYXIgdmFyaWFibGVzLiANCg0KVGhlIGdlbmVyYWwgcmVncmVzc2lvbiBlcXVhdGlvbiBmb3IgdGhpcyByZWR1Y2VkIG1vZGVsIGlzIHJlcHJlc2VudGVkIGFzOg0KDQpUZW5ZZWFyQ0hEID0gY3VycmVudFNtb2tlciArIHNkLmNpZ3NQZXJEYXkgKyBzZC5zeXNCUCArIHNkLmRpYUJQICsgc2QudG90Q2hvbA0KDQpXZSB3aWxsIGZpbmQgdGhlIHNwZWNpZmljIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gZXF1YXRpb24gZm9yIHRoaXMgcmVkdWNlZCBtb2RlbC4NCg0KYGBge3J9DQpyZWR1Y2VkLm1vZGVsID0gZ2xtKFRlblllYXJDSEQgfiBjdXJyZW50U21va2VyICsgc2QuY2lnc1BlckRheSArIHNkLnN5c0JQICsgc2QuZGlhQlAgKyBzZC50b3RDaG9sLCANCiAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksDQogICAgICAgICAgZGF0YSA9IHNkLmhlYXJ0ZGlzZWFzZSkgDQprYWJsZShzdW1tYXJ5KHJlZHVjZWQubW9kZWwpJGNvZWYsIA0KICAgICAgY2FwdGlvbiA9ICJSZWR1Y2VkIE1vZGVsIFN1bW1hcnkgb2YgdGhlIEluZmVyZW50aWFsIFN0YXRpc3RpY3MiKQ0KYGBgDQoNClRoZSBlcXVhdGlvbiBmb3IgdGhlIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gZXF1YXRpb24gb2YgdGhlIHJlZHVjZWQgbW9kZWwgaXMgZ2l2ZW4gYXMgZm9sbG93czoNCg0KbG9nIHAvKDEtcCkgPSAtMS43Njc1IC0gMC4xNDQzICogY3VycmVudFNtb2tlciArIDAuMjY4MyAqIHNkLmNpZ3NQZXJEYXkgKyAwLjYzODEgKiBzZC5zeXNCUCAtIDAuMTQwOSAqIHNkLmRpYUJQICsgMC4xMTE0ICogc2QudG90Q2hvbA0KDQoNCiMjIyBGb3J3YXJkIFNlbGVjdGlvbiBNb2RlbA0KDQpUaGUgdGhpcmQgb2YgdGhyZWUgY2FuZGlkYXRlIG1vZGVscyB3aWxsIGJlIHRoZSBtb2RlbCB0aGF0IHdhcyBmb3VuZCB0aHJvdWdoIHRoZSBhdXRvbWF0aWMgdmFyaWFibGUgc2VsZWN0aW9uIHByb2Nlc3MsIHNwZWNpZmljYWxseSB3aXRoIHVzaW5nIGZvcndhcmQgc2VsZWN0aW9uLiBXZSB3aWxsIGNhbGwgdGhpcyB0aGUgZnMubW9kZWwgZm9yIHRoaXMgcHJvamVjdCB0byByZXByZXNlbnQgaXQgYmVpbmcgdGhlIG1vZGVsIGZvdW5kIHRocm91Z2ggdGhlIHVzZSBvZiBmb3J3YXJkIHNlbGVjdGlvbiBvZiB0aGUgdmFyaWFibGVzLiANCg0KV2Ugd2lsbCBmaW5kIHRoZSBzcGVjaWZpYyBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIGVxdWF0aW9uIGZvciB0aGlzIGZvcndhcmQgc2VsZWN0aW9uIG1vZGVsLg0KDQpgYGB7cn0NCmZzLm1vZGVsID0gc3RlcEFJQyhyZWR1Y2VkLm1vZGVsLCBzY29wZSA9IGxpc3QobG93ZXI9Zm9ybXVsYShyZWR1Y2VkLm1vZGVsKSwgdXBwZXI9Zm9ybXVsYShmdWxsLm1vZGVsKSksDQogICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImZvcndhcmQiLCAgDQogICAgICAgICAgICAgICAgICAgICAgdHJhY2UgPSAwICAgDQogICAgICAgICAgICAgICAgICAgICAgKQ0Ka2FibGUoc3VtbWFyeShmcy5tb2RlbCkkY29lZiwgDQogICAgICBjYXB0aW9uPSJGaW5hbCBNb2RlbCBTdW1tYXJ5IG9mIHRoZSBJbmZlcmVudGlhbCBTdGF0aXN0aWNzIikNCmBgYA0KDQpUaGUgZXF1YXRpb24gZm9yIHRoZSBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIGVxdWF0aW9uIG9mIHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCBpcyBnaXZlbiBhcyBmb2xsb3dzOg0KDQpsb2cgcC8oMS1wKSA9IC0yLjI4OTggKyAwLjAwODQgKiBjdXJyZW50U21va2VyICsgMC4yNDk3ICogc2QuY2lnc1BlckRheSArIDAuMjQ5NyAqIHNkLnN5c0JQIC0gMC4wMzI1ICogc2QuZGlhQlAgKyAwLjA3NTUgKiBzZC50b3RDaG9sICsgMC41MzY0ICogc2QuYWdlICsgMC41MTY0ICogbWFsZSArIDAuMTgyNiAqIHNkLmdsdWNvc2UgKyAwLjk0MTMgKiBwcmV2YWxlbnRTdHJva2UgKyAwLjIzMTAgKiBwcmV2YWxlbnRIeXAgKyAwLjMyMzMgKiBCUE1lZHMgDQoNClRoZSB2YXJpYWJsZXMgdGhhdCB3ZXJlIGtlcHQgaW4gdGhpcyBtb2RlbCBhZnRlciBmb3J3YXJkIHNlbGVjdGlvbiB3ZXJlIGN1cnJlbnRTbW9rZXIsIHNkLmNpZ3NQZXJEYXksIHNkLnN5c0JQLCBzZC5kaWFCUCwgc2QudG90Q2hvbCwgc2QsYWdlLCBtYWxlLCBzZC5nbHVjb3NlLCBwcmV2YWxlbnRTdHJva2UsIHByZXZhbGVudEh5cCwgYW5kIEJQTWVkcy4gDQoNCg0KIyMgQ3Jvc3MgVmFsaWRhdGlvbg0KDQpOb3cgdGhhdCB3ZSd2ZSBsb29rZWQgaW50byB0aGUgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHRocmVlIHBvdGVudGlhbCBjYW5kaWRhdGUgbW9kZWxzLCB3ZSB3aWxsIHVzZSBjcm9zcy12YWxpZGF0aW9uIHRvIGRldGVybWluZSB3aGljaCBvZiB0aGVzZSB0aHJlZSBtb2RlbHMgd2Ugc2hvdWxkIHVzZS4gV2Ugd2FudCB0byBzZWUgd2hpY2ggbW9kZWwgaGFzIHRoZSBiZXN0IHByZWRpY3RpdmUgcGVyZm9ybWFuY2UuIFdlIHdpbGwgdXNlIGEgNS1mb2xkIGNyb3NzIHZhbGlkYXRpb24gdG8gY29uZHVjdCB0aGUgcHJvY2VzcyBvZiBmaW5kaW5nIHRoZSBwcmVkaWN0aXZlIGVycm9ycyBmb3IgZWFjaCBvZiB0aGUgdGhyZWUgY2FuZGlkYXRlIG1vZGVscy4gV2Ugd2lsbCB1c2UgdGhpcyA1LWZvbGQgY3Jvc3MgdmFsaWRhdGlvbiBwcm9jZXNzIHRvIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9ycyBmb3IgZWFjaCBvZiB0aGUgdGhyZWUgY2FuZGlkYXRlIG1vZGVscywgdGhlIGZ1bGwgbW9kZWwsIHRoZSByZWR1Y2VkIG1vZGVsLCBhbmQgdGhlIGZvcndhcmQgc2VsZWN0aW9uIG1vZGVsLiBXZSBhcmUgbG9va2luZyBmb3Igd2hpY2ggbW9kZWwgaGFzIHRoZSBsb3dlc3QgdmFsdWUgb2YgYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9ycy4gVGhpcyBtb2RlbCB3aXRoIHRoZSBsb3dlc3QgdmFsdWUgZm9yIHRoZSBhdmVyYWdlIHByZWRpY3RpdmUgZXJyb3JzIHdpbGwgYmUgdGhlIGlkZWFsIGNob2ljZSwgYXMgaGF2aW5nIHRoZSBsb3dlc3QgcHJlZGljdGl2ZSBlcnJvciB2YWx1ZSBpbmRpY2F0ZXMgYSBoaWdoZXIgcHJlZGljdGl2ZSBwb3dlciBhbmQgbW9yZSBhY2N1cmF0ZSBwcmVkaWN0aW9ucyB0aGFuIGEgbW9kZWwgd2l0aCBoaWdoZXIgYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9yIHdvdWxkLiANCg0KRm9yIG91ciBjcm9zcyB2YWxpZGF0aW9uIHByb2Nlc3MsIHdlIHdpbGwgdXNlIGEgY3V0IG9mZiBwcm9iYWJpbGl0eSBvZiAwLjUgdG8gZGVmaW5lIGJldHdlZW4gdGhlIGJpbmFyeSByZXNwb25zZSB2YWx1ZXMgb2YgMSwgeWVzLCBhbmQgMCwgbm8uIFRoZXNlIHZhbHVlcyByZXByZXNlbnQgd2hldGhlciBhbiBpbmRpdmlkdWFsIHdpbGwgYmUgc3RhdGVkIGFzIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hEIGluIGEgMTAteWVhciBwZXJpb2QgYmFzZWQgdXBvbiB0aGUgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB0aGF0IHdhcyB1c2VkIGZvciBwcmVkaWN0aW9uLg0KDQpXZSB3aWxsIGxhYmVsIHRoZSBmdWxsIG1vZGVsIGFzIG91ciBmaXJzdCBtb2RlbCAoMDEpLCB0aGUgcmVkdWNlZCBtb2RlbCBhcyBvdXIgc2Vjb25kIG1vZGVsICgwMiksIGFuZCB0aGUgZm9yd2FyZCBzZWxlY3Rpb24gbW9kZWwgYXMgb3VyIHRoaXJkIG1vZGVsICgwMykgZm9yIHRoaXMgY3Jvc3MtdmFsaWRhdGlvbiBwcm9jZXNzLiANCg0KYGBge3J9DQojIyA1IEZvbGQgQ3Jvc3MgVmFsaWRhdGlvbg0KayA9IDUNCmZvbGQuc2l6ZSA9IGZsb29yKGRpbSh0cmFpbilbMV0vaykNClBFMSA9IHJlcCgwLDUpDQpQRTIgPSByZXAoMCw1KQ0KUEUzID0gcmVwKDAsNSkNCg0KIyBUcmFpbmluZyBhbmQgVGVzdGluZyBGb2xkIGZvciB0aGUgTW9kZWxzDQpmb3IoaSBpbiAxOmspew0KICANCiB2YWxpZC5pZCA9IChmb2xkLnNpemUqKGktMSkrMSk6KGZvbGQuc2l6ZSppKQ0KICB2YWxpZCA9IHRyYWluW3ZhbGlkLmlkLCBdDQogIHRyYWluLmRhdGEgPSB0cmFpblstdmFsaWQuaWQsXQ0KICANCiMgRnVsbCBNb2RlbDogYWxsIHZhcmlhYmxlcw0KZnVsbC5tb2RlbCA9IGdsbShUZW5ZZWFyQ0hEIH4gbWFsZSArIHNkLmFnZSArIGVkdWNhdGlvbiArIGN1cnJlbnRTbW9rZXIgKyAgc2QuY2lnc1BlckRheSArIEJQTWVkcyArIHByZXZhbGVudFN0cm9rZSArIHByZXZhbGVudEh5cCArIGRpYWJldGVzICsgc2QudG90Q2hvbCArIHNkLnN5c0JQICsgc2QuZGlhQlAgKyBzZC5CTUkgKyBzZC5oZWFydFJhdGUgKyBzZC5nbHVjb3NlLCANCiAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksICANCiAgICAgICAgICBkYXRhID0gdHJhaW4uZGF0YSkNCg0KIyMgUmVkdWNlZCBNb2RlbDogb25seSB0aGUgbW9zdCBwcmFjdGljYWxseSBpbXBvcnRhbnQgdmFyaWFibGVzLg0KcmVkdWNlZC5tb2RlbCA9IGdsbShUZW5ZZWFyQ0hEIH4gY3VycmVudFNtb2tlciArIHNkLmNpZ3NQZXJEYXkgKyBzZC5zeXNCUCArIHNkLmRpYUJQICsgc2QudG90Q2hvbCwgDQogICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLA0KICAgICAgICAgIGRhdGEgPSB0cmFpbi5kYXRhKSANCg0KIyMgQXV0b21hdGljIEZvcndhcmQgU2VsZWN0aW9uIChmcykgTW9kZWw6IG1vZGVsIGZvdW5kIHVzaW5nIGZvcndhcmQgc2VsZWN0aW9uDQpmcy5tb2RlbCA9IHN0ZXBBSUMoZnVsbC5tb2RlbCwgDQogICAgICAgICAgICAgICAgICAgICAgc2NvcGUgPSBsaXN0KGxvd2VyPWZvcm11bGEocmVkdWNlZC5tb2RlbCksICAgDQogICAgICAgICAgICAgICAgICAgICAgdXBwZXI9Zm9ybXVsYShmdWxsLm1vZGVsKSksDQogICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImZvcndhcmQiLCAgDQogICAgICAgICAgICAgICAgICAgICAgdHJhY2UgPSAwICAgDQogICAgICAgICAgICAgICAgICAgICAgKQ0KDQojIEZpbmRpbmcgdGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIGZvciBlYWNoIG9mIHRoZSBjYW5kaWRhdGUgbW9kZWxzDQogICBwcmVkLmZ1bGwgPSBwcmVkaWN0KGZ1bGwubW9kZWwsIG5ld2RhdGEgPSB2YWxpZCwgdHlwZSA9ICJyZXNwb25zZSIpDQogICBwcmVkLnJlZHVjZWQgPSBwcmVkaWN0KHJlZHVjZWQubW9kZWwsIG5ld2RhdGEgPSB2YWxpZCwgdHlwZSA9ICJyZXNwb25zZSIpDQogICBwcmVkLmZzID0gcHJlZGljdChmcy5tb2RlbCwgbmV3ZGF0YSA9IHZhbGlkLCB0eXBlID0gInJlc3BvbnNlIikNCiAgIA0KICAgcHJlLm91dGNvbWUwMSA9IGlmZWxzZShhcy52ZWN0b3IocHJlZC5mdWxsKSA+IDAuNSwgIjEiLCAiMCIpDQogICBwcmUub3V0Y29tZTAyID0gaWZlbHNlKGFzLnZlY3RvcihwcmVkLnJlZHVjZWQpID4gMC41LCAiMSIsICIwIikNCiAgIHByZS5vdXRjb21lMDMgPSBpZmVsc2UoYXMudmVjdG9yKHByZWQuZnMpID4gMC41LCAiMSIsICIwIikNCiAgIA0KICAgUEUxW2ldID0gc3VtKHByZS5vdXRjb21lMDEgPT0gdmFsaWQkVGVuWWVhckNIRCkvbGVuZ3RoKHByZWQuZnVsbCkNCiAgIFBFMltpXSA9IHN1bShwcmUub3V0Y29tZTAyID09IHZhbGlkJFRlblllYXJDSEQpL2xlbmd0aChwcmVkLnJlZHVjZWQpDQogICBQRTNbaV0gPSBzdW0ocHJlLm91dGNvbWUwMyA9PSB2YWxpZCRUZW5ZZWFyQ0hEKS9sZW5ndGgocHJlZC5mcykNCn0NCg0KIyBGaW5kaW5nIHRoZSBhdmVyYWdlIHByZWRpY3RpdmUgZXJyb3JzIG9mIGVhY2ggY2FuZGlkYXRlIG1vZGVsICANCmF2Zy5wZSA9IGNiaW5kKFBFMSA9IG1lYW4oUEUxKSwgUEUyID0gbWVhbihQRTIpLCBQRTMgPSBtZWFuKFBFMykpDQprYWJsZShhdmcucGUsIGNhcHRpb24gPSAiQXZlcmFnZSBQcmVkaWN0aXZlIEVycm9ycyBvZiB0aGUgVGhyZWUgQ2FuZGlkYXRlIE1vZGVscyIpIA0KYGBgDQoNClRoZSBhdmVyYWdlIHByZWRpY3RpdmUgZXJyb3JzIG9mIHRoZSB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzIGFyZSBnaXZlbiBhcyBmb2xsb3dzOg0KDQpUaGUgZnVsbCBtb2RlbCwgcmVwcmVzZW50ZWQgYnkgUEUxLCBoYWQgYW4gYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9yIG9mIDAuODU0Ni4gDQpUaGUgcmVkdWNlZCBtb2RlbCwgcmVwcmVzZW50ZWQgYnkgUEUyLCBoYWQgYW4gYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9yIG9mIDAuODQ5NS4gDQoNClRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCwgcmVwcmVzZW50ZWQgYnkgUEUzLCBoYWQgYW4gYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9yIG9mIDAuODU0Ni4NCg0KV2UgY2FuIHNlZSB0aGF0IGJvdGggdGhlIGZ1bGwgbW9kZWwgYW5kIHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCBoYWQgZXF1YWwgdmFsdWVzIGZvciB0aGVpciBhdmVyYWdlIHByZWRpY3RpdmUgZXJyb3JzLCB3aXRoIGJvdGggaGF2aW5nIGEgdmFsdWUgb2YgMC44NTQ2LiBIb3dldmVyLCB0aGUgcmVkdWNlZCBtb2RlbCBhIGxvd2VyIGF2ZXJhZ2UgcHJlZGljdGl2ZSBlcnJvciB2YWx1ZSB0aGFuIHRoZSBvdGhlciB0d28gbW9kZWxzLCB3aXRoIGEgdmFsdWUgb2YgMC44NDk2LiBUaGlzIGluZGljYXRlcyB0aGF0IHRoZSByZWR1Y2VkIG1vZGVsIGlzIHRoZSBvbmUgd2hpY2ggd2Ugc2hvdWxkIGNob29zZSBhcyBvdXIgZmluYWwgbW9kZWwuDQoNClRoZSBjcm9zcy12YWxpZGF0aW9uIHByb2Nlc3Mgb2YgY2FsY3VsYXRpbmcgdGhlIGF2ZXJhZ2UgcHJlZGljdGl2ZSBlcnJvcnMgZm9yIHRoZSB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzIHNob3dlZCB0aGF0IHRoZSByZWR1Y2VkIG1vZGVsIGlzIHRoZSBpZGVhbCBvbmUgdG8gdXNlIGZvciBwcmVkaWN0aW9uIGR1ZSB0byBpdCBoYXZpbmcgdGhlIGxvd2VzdCB2YWx1ZSBvZiBpdHMgYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9yIG91dCBvZiB0aGUgdGhyZWUgY2FuZGlkYXRlIG1vZGVscy4gVGhpcyBtYWtlcyB0aGUgcmVkdWNlZCBtb2RlbCBoYXZlIHRoZSBoaWdoZXN0IHByZWRpY3RpdmUgcG93ZXIgYW5kIHBlcmZvcm1hbmNlIG91dCBvZiB0aGUgdGhyZWUgY2FuZGlkYXRlIG1vZGVscywgYXMgc2hvd24gYnkgaG93IGl0IGhhcyB0aGUgbGVhc3QgYW1vdW50IG9mIGl0cyBhdmVyYWdlIHByZWRpY3RpdmUgZXJyb3JzIGluIGNvbXBhcmlzb24gdG8gdGhlIGZ1bGwgbW9kZWwgYW5kIHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbC4gU28sIHdlIHdpbGwgbW92ZSBmb3J3YXJkIHdpdGggdGhlIHVzZSBvZiB0aGUgcmVkdWNlZCBtb2RlbCBhcyBvdXIgZmluYWwgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCBmb3IgcHJlZGljdGlvbiBvZiB0aGUgb2RkcyBvZiBhbiBpbmRpdmlkdWFsIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hELiANCg0KDQojIyBGaW5hbCBNb2RlbA0KDQpJbiB0aGUgcHJldmlvdXMgY3Jvc3MtdmFsaWRhdGlvbiBzdGVwLCB3ZSB1c2VkIGEgY3V0IG9mZiBwcm9iYWJpbGl0eSBvZiAwLjUgdG8gaWRlbnRpZnkgYmV0d2VlbiB0aGUgcmVzcG9uc2UgdmFyaWFibGUgZ2l2aW5nIGEgcG9zaXRpdmUgb3IgbmVnYXRpdmUgcmVzdWx0LiBJbiB0aGlzIGNhc2UsIGEgInBvc2l0aXZlIiByZXN1bHQsIG9yIGFuIG91dHB1dCBvZiAxLCByZXByZXNlbnRzIHRoYXQgYW4gaW5kaXZpZHVhbCBpcyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRCBpbiBhIDEwLXllYXIgcGVyaW9kLiBBbmQsIGEgIm5lZ2F0aXZlIiByZXN1bHQsIG9yIGFuIG91dHB1dCBvZiAwLCByZXByZXNlbnRzIHRoYXQgYW4gaW5kaXZpZHVhbCBpcyBub3QgYXQgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQgaW4gYSAxMC15ZWFyIHBlcmlvZC4gV2UgdXNlZCB0aGUgY3Jvc3MtdmFsaWRhdGlvbiBwcm9jZXNzIHdpdGggdGhpcyBjdXQgb2ZmIHByb2JhYmlsaXR5IG9mIDAuNSB0byBmaW5kIHRoZSB2YWx1ZXMgb2YgdGhlIGF2ZXJhZ2UgcHJlZGljdGl2ZSBlcnJvcnMgb2YgdGhlIHRocmVlIGNhbmRpZGF0ZSBtb2RlbHMuIFdlIGZvdW5kIHRoYXQgdGhlIHJlZHVjZWQgbW9kZWwgd2FzIHRoZSBvbmUgd2l0aCB0aGUgYmVzdCBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlLCBzbyB3ZSB3aWxsIHVzZSB0aGF0IGFzIG91ciBmaW5hbCBtb2RlbC4gDQoNCkhvd2V2ZXIsIGluIG9yZGVyIHRvIHJlcG9ydCB0aGUgZGV0YWlscyBvZiB0aGUgZmluYWwgbW9kZWwsIHdlIG11c3QgZmluZCBpdHMgYWN0dWFsIGFjY3VyYWN5IGJhc2VkIHVwb24gdGhlIHRlc3QgZGF0YS4gV2UgcHJldmlvdXNseSBzcGxpdCB0aGUgZGF0YSB1cCBpbnRvIGEgdHJhaW5pbmcgYW5kIGEgdGVzdGluZyBkYXRhIHNldC4gV2Ugd2lsbCB1c2UgdGhlIHRlc3QgZGF0YSBzZXQgdG8gZmluZCB0aGUgYWN0dWFsIGFjY3VyYWN5IG9mIHRoZSBmaW5hbCBtb2RlbCwgdGhlIHJlZHVjZWQgbW9kZWwsIGluIG9yZGVyIHRvIHByb3ZpZGUgdGhlIGZ1bGxlc3QgYWNjdXJhY3kgaW4gdGhlIHJlcG9ydCBvZiB0aGlzIG1vZGVsLiANCg0KYGBge3J9DQpwcmVkLnJlZHVjZWQgPSBwcmVkaWN0KHJlZHVjZWQubW9kZWwsIG5ld2RhdGEgPSB0ZXN0LCB0eXBlID0gInJlc3BvbnNlIikNCnByZWQucmVkdWNlZC5vdXRjb21lID0gaWZlbHNlKGFzLnZlY3RvcihwcmVkLnJlZHVjZWQpID4gMC41LCAiMSIsICIwIikNCg0KQWNjdXJhY3kgPSBzdW0ocHJlZC5yZWR1Y2VkLm91dGNvbWUgPT0gdGVzdCRUZW5ZZWFyQ0hEKS9sZW5ndGgocHJlZC5yZWR1Y2VkKQ0Ka2FibGUoQWNjdXJhY3ksIGNhcHRpb249IkFjdHVhbCBBY2N1cmFjeSBvZiB0aGUgRmluYWwgTW9kZWwgKFJlZHVjZWQgTW9kZWwpIikNCmBgYA0KDQpUaGUgYWN0dWFsIGFjY3VyYWN5IG9mIHRoZSBmaW5hbCBtb2RlbCwgdGhlIHJlZHVjZWQgbW9kZWwsIGlzIGdpdmVuIGFzIDAuODQ0My4gVGhpcyB2YWx1ZSByZXByZXNlbnRzIHRoZSBhY2N1cmFjeSByYXRlIG9mIHRoaXMgZmluYWwgbW9kZWwuIA0KDQpJdCBhcHBlYXJzIHRoYXQgdGhlIGZpbmFsIG1vZGVsIGhhcyBnb29kIGFjY3VyYWN5IGFzIHNlZW4gYnkgaXRzIGFjY3VyYWN5IHJhdGUgb2YgMC44NDQzLiBUaGlzIGluZGljYXRlcyB0aGF0IHRoZSBmaW5hbCBtb2RlbCB3ZSBzZWxlY3RlZCBoYXMgZ29vZCBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlIGZvciBwcmVkaWN0aW5nIHRoZSBvZGRzIG9mIGFuIGluZGl2aWR1YWwgYmVpbmcgYXQgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQgd2l0aGluIGEgMTAteWVhciBwZXJpb2QuIA0KDQoNCg0KIyBST0MgQW5hbHlzaXMNCg0KV2Ugd2lsbCB1c2UgUk9DIGFuYWx5c2lzIHRvIG1lYXN1cmUgdGhlIGdsb2JhbCBwZXJmb3JtYW5jZSBvZiB0aGUgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbC4gVGhpcyBwbG90IHdpbGwgaWxsdXN0cmF0ZSB0aGUgcmVsYXRpb25zaGlwIG9mIHRoZSB0cnVlIHBvc2l0aXZlIHJhdGUgKFRQUiksIGFsc28ga25vd24gYXMgdGhlIHNlbnNpdGl2aXR5LCBhZ2FpbnN0IHRoZSBmYWxzZSBwb3NpdGl2ZSByYXRlIChGUFIpLCBhbHNvIGdpdmVuIGFzIDEgLSBzcGVjaWZpY2l0eS4gV2Ugd2lsbCBwbG90IHRoZSBST0MgY3VydmVzIGZvciBlYWNoIG9mIHRoZSB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzIHRvIGNvbXBhcmUgdGhlbSBhZ2FpbnN0IG9uZSBhbm90aGVyLiBXZSB3aWxsIGFsc28gY2FsY3VsYXRlIHRoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSAoQVVDKSB2YWx1ZXMgZm9yIGVhY2ggb2YgdGhlIHRocmVlIGNhbmRpZGF0ZSBtb2RlbHMuIFRoZSB2YWx1ZSBvZiBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSByZXByZXNlbnRzIHRoZSBnbG9iYWwgZ29vZG5lc3Mgb2YgdGhlIG1vZGVsLCBhbmQgYSBoaWdoZXIgQVVDIHZhbHVlIGlzIGlkZWFsLiBBIGhpZ2hlciB2YWx1ZSBvZiB0aGUgYXJlYSB1bmRlciB0aGUgY3VydmUgaW5kaWNhdGVzIGJldHRlciBhbmQgbW9yZSBxdWFsaXR5IGdsb2JhbCBnb29kbmVzcyBvZiB0aGF0IG1vZGVsLiANCg0KV2Ugd2lsbCBwbG90IHRoZSBST0MgY3VydmVzIGZvciB0aGUgZnVsbCBtb2RlbCwgdGhlIHJlZHVjZWQgbW9kZWwsIGFuZCB0aGUgZm9yd2FyZCBzZWxlY3Rpb24gbW9kZWwuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBjb21wYXJlIHRoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZXMgZm9yIGVhY2ggb2YgdGhlIHRocmVlIG1vZGVscy4gQWRkaXRpb25hbGx5LCB3ZSB3aWxsIGNhbGN1bGF0ZSB0aGUgQVVDIHZhbHVlcyBmb3IgZWFjaCBvZiB0aGUgdGhyZWUgbW9kZWxzIHRvIGNvbXBhcmUgdGhlbSB3aXRoIGVhY2ggb3RoZXIgYW5kIGRldGVybWluZSB3aGljaCBtb2RlbCBpbmRpY2F0ZXMgdGhlIGJlc3QgZ2xvYmFsIGdvb2RuZXNzLiANCg0KDQpgYGB7cn0NClRQUi5GUFI9ZnVuY3Rpb24ocHJlZCl7DQogIHByb2Iuc2VxID0gc2VxKDAsIDEsIGxlbmd0aD01MCkgIA0KICBwbiA9IGxlbmd0aChwcm9iLnNlcSkNCiAgdHJ1ZS5sYWIgPSBhcy52ZWN0b3IodHJhaW4kVGVuWWVhckNIRCkNCiAgVFBSID0gTlVMTA0KICBGUFIgPSBOVUxMDQogIGZvciAoaSBpbiAxOnBuKXsNCiAgIHByZWQubGFiID0gYXMudmVjdG9yKGlmZWxzZShwcmVkID4gcHJvYi5zZXFbaV0sIjEiLCAiMCIpKQ0KICAgVFBSW2ldID0gbGVuZ3RoKHdoaWNoKHRydWUubGFiPT0iMSIgJiBwcmVkLmxhYj09IjEiKSkvbGVuZ3RoKHdoaWNoKHRydWUubGFiPT0iMSIpKQ0KICAgRlBSW2ldID0gbGVuZ3RoKHdoaWNoKHRydWUubGFiPT0iMCIgJiBwcmVkLmxhYj09IjEiKSkvbGVuZ3RoKHdoaWNoKHRydWUubGFiPT0iMCIpKQ0KICB9DQogY2JpbmQoRlBSID0gRlBSLCBUUFIgPSBUUFIpDQp9DQpgYGANCg0KV2Ugd2lsbCB1c2UgdGhlIHRyYWluaW5nIGRhdGEgc2V0IHRvIGhlbHAgZmluZCB0aGUgcHJlZGljdGl2ZSBwcm9iYWJpbGl0aWVzIGZvciBlYWNoIG9mIHRoZSB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzLiANCg0KYGBge3J9DQojIFRoZSBGdWxsIE1vZGVsDQpmdWxsLm1vZGVsID0gZ2xtKFRlblllYXJDSEQgfm1hbGUgKyBzZC5hZ2UgKyBlZHVjYXRpb24gKyBjdXJyZW50U21va2VyICsgIHNkLmNpZ3NQZXJEYXkgKyBCUE1lZHMgKyBwcmV2YWxlbnRTdHJva2UgKyBwcmV2YWxlbnRIeXAgKyBkaWFiZXRlcyArIHNkLnRvdENob2wgKyBzZC5zeXNCUCArIHNkLmRpYUJQICsgc2QuQk1JICsgc2QuaGVhcnRSYXRlICsgc2QuZ2x1Y29zZSwgDQogICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCAgDQogICAgICAgICAgZGF0YSA9IHRyYWluKQ0KDQojIFRoZSBSZWR1Y2VkIE1vZGVsIChmaW5hbCBtb2RlbCkNCnJlZHVjZWQubW9kZWwgPSBnbG0oVGVuWWVhckNIRCB+IGN1cnJlbnRTbW9rZXIgKyBzZC5jaWdzUGVyRGF5ICsgc2Quc3lzQlAgKyBzZC5kaWFCUCArIHNkLnRvdENob2wsIA0KICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwNCiAgICAgICAgICBkYXRhID0gdHJhaW4pIA0KDQojIFRoZSBGb3J3YXJkIFNlbGVjdGlvbiAoZnMpIE1vZGVsDQpmcy5tb2RlbCA9IHN0ZXBBSUMoZnVsbC5tb2RlbCwgDQogICAgICAgICAgICAgICAgICAgICAgc2NvcGUgPSBsaXN0KGxvd2VyPWZvcm11bGEocmVkdWNlZC5tb2RlbCksICAgDQogICAgICAgICAgICAgICAgICAgICAgdXBwZXI9Zm9ybXVsYShmdWxsLm1vZGVsKSksDQogICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImZvcndhcmQiLCAgDQogICAgICAgICAgICAgICAgICAgICAgdHJhY2UgPSAwICAgDQogICAgICAgICAgICAgICAgICAgICAgKQ0KDQojIEZpbmRpbmcgdGhlIFByZWRpY3RlZCBQcm9iYWJpbGl0aWVzIGZvciBFYWNoIE1vZGVsDQpwcmVkLmZ1bGwgPSBwcmVkaWN0LmdsbShmdWxsLm1vZGVsLCBuZXdkYXRhID0gdHJhaW4sIHR5cGUgPSAicmVzcG9uc2UiKSANCnByZWQucmVkdWNlZCA9IHByZWRpY3QuZ2xtKHJlZHVjZWQubW9kZWwsIG5ld2RhdGEgPSB0cmFpbiwgdHlwZSA9ICJyZXNwb25zZSIpDQpwcmVkLmZzID0gcHJlZGljdC5nbG0oZnMubW9kZWwsIG5ld2RhdGEgPSB0cmFpbiwgdHlwZSA9ICJyZXNwb25zZSIpDQpgYGANCg0KTm93LCB3ZSB3aWxsIHBsb3QgdGhlIFJPQyBjdXJ2ZXMgZm9yIGVhY2ggb2YgdGhlIHRocmVlIGNhbmRpZGF0ZSBtb2RlbHMgdG8gY29tcGFyZSB0aGVtLiANCg0KYGBge3J9DQojIFBsb3R0aW5nIHRoZSBST0MgY3VydmVzDQogcGxvdChUUFIuRlBSKHByZWQuZnVsbClbLDFdLCBUUFIuRlBSKHByZWQuZnVsbClbLDJdLCANCiAgICAgIHR5cGU9ImwiLCBjb2wgPSAyLCBsdHkgPSAxLCB4bGltID0gYygwLDEpLCB5bGltID0gYygwLDEpLA0KICAgICAgeGxhYiA9ICJGUFI6IDEgLSBTcGVjaWZpY2l0eSIsDQogICAgICB5bGFiID0iVFBSOiBTZW5zaXRpdml0eSIsDQogICAgICBtYWluID0gIlJPQyBDdXJ2ZXMgZm9yIHRoZSBUaHJlZSBDYW5kaWRhdGUgTW9kZWxzIiwNCiAgICAgIGNleC5tYWluID0gMC44LA0KICAgICAgY29sLm1haW4gPSAibmF2eSIpDQogbGluZXMoVFBSLkZQUihwcmVkLnJlZHVjZWQpWywxXSwgVFBSLkZQUihwcmVkLnJlZHVjZWQpWywyXSwgIGNvbD0zLCBsdHk9MikNCiBsaW5lcyhUUFIuRlBSKHByZWQuZnMpWywxXSwgVFBSLkZQUihwcmVkLmZzKVssMl0sICBjb2w9NCwgbHR5PTMpICAgIA0KIA0KICBjYXRlZ29yeSA9IHRyYWluJFRlblllYXJDSEQgPT0gIjEiDQogIFJPQ29iajAxIDwtIHJvYyhjYXRlZ29yeSwgYXMudmVjdG9yKHByZWQuZnVsbCkpDQogIFJPQ29iajAyIDwtIHJvYyhjYXRlZ29yeSwgYXMudmVjdG9yKHByZWQucmVkdWNlZCkpDQogIFJPQ29iajAzIDwtIHJvYyhjYXRlZ29yeSwgYXMudmVjdG9yKHByZWQuZnMpKQ0KICBBVUMwMSA9IHJvdW5kKGF1YyhST0NvYmowMSksNCkNCiAgQVVDMDIgPSByb3VuZChhdWMoUk9Db2JqMDIpLDQpDQogIEFVQzAzID0gcm91bmQoYXVjKFJPQ29iajAzKSw0KQ0KICANCiAgbGVnZW5kKCJib3R0b21yaWdodCIsIGMocGFzdGUoIkZ1bGwgbW9kZWw6IEFVQyA9ICIsIEFVQzAxKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlJlZHVjZWQgbW9kZWw6IEFVQyA9IiwgQVVDMDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJGb3J3YXJkIFNlbGVjdGlvbiBtb2RlbDogQVVDID0iLCBBVUMwMykpLA0KICAgICAgICBjb2wgPSAyOjQsIGx0eSA9IDE6MywgY2V4ID0gMC44LCBidHkgPSAibiIpDQpgYGANCg0KDQpXZSBjYW4gc2VlIHRoYXQgYm90aCB0aGUgZnVsbCBtb2RlbCBhbmQgdGhlIGZvcndhcmQgc2VsZWN0aW9uIG1vZGVsIGZhbGwgb24gdGhlIGV4YWN0IHNhbWUgY3VydmUsIHdoaWNoIGlzIGFsc28gZXZpZGVuY2VkIGJ5IGhvdyB0aGVzZSB0d28gbW9kZWxzIGhhdmUgdGhlIHNhbWUgdmFsdWVzIGZvciB0aGVpciBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSBCb3RoIHRoZSBmdWxsIG1vZGVsIGFuZCB0aGUgZm9yd2FyZCBzZWxlY3Rpb24gbW9kZWwgaGF2ZSBhbiBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSBvZiAwLjczNTYsIGFuZCB0aGVpciBST0MgY3VydmVzIG1hdGNoIHVwIGlkZW50aWNhbGx5IHRvIGVhY2ggb3RoZXIuIFRoaXMgbWF0Y2hlcyB1cCB3aXRoIHRoZSBwcmV2aW91cyBmaW5kaW5nIG9mIHRoZSBmdWxsIG1vZGVsIGFuZCB0aGUgZm9yd2FyZCBzZWxlY3Rpb24gbW9kZWwgaGF2aW5nIHRoZSBleGFjdCBzYW1lIHZhbHVlcyBmb3IgdGhlaXIgYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9ycy4gDQoNClNvbWV0aGluZyBpbnRlcmVzdGluZyBmb3VuZCBpbiB0aGlzIFJPQyBhbmFseXNpcywgaXMgdGhhdCB0aGUgcmVkdWNlZCBtb2RlbCBhY3R1YWxseSBoYXMgdGhlIHNtYWxsZXN0IHZhbHVlIG9mIGFyZWEgdW5kZXIgdGhlIGN1cnZlIHdpdGggMC42NzYzLiBXZSBmb3VuZCB0aGF0IHRoZSByZWR1Y2VkIG1vZGVsIHdhcyB0aGUgb25lIHdpdGggdGhlIGxvd2VzdCBhdmVyYWdlIHByZWRpY3RpdmUgZXJyb3JzIHByZXZpb3VzbHksIHdoaWNoIG1hZGUgaXQgdGhlIGlkZWFsIG1vZGVsIGNob2ljZSBmb3Igb3VyIGZpbmFsIG1vZGVsLiBIb3dldmVyLCB0aGlzIG1vZGVsIHR1cm5lZCBvdXQgdG8gaGF2ZSB0aGUgbG93ZXN0IGFyZWEgdW5kZXIgdGhlIGN1cnZlIG91dCBvZiB0aGUgdGhyZWUsIHdoaWNoIGlzIG5vdCBpZGVhbC4gQSBtb2RlbCB3aXRoIGEgaGlnaGVyIGFyZWEgdW5kZXIgdGhlIGN1cnZlIGhhcyBhIGJldHRlciBnbG9iYWwgZ29vZG5lc3MgdGhhbiBhIG1vZGVsIHdpdGggYSBsb3dlciBhcmVhIHVuZGVyIHRoZSBjdXJ2ZS4gDQoNClNvbGVseSBiYXNlZCB1cG9uIGFyZWEgdW5kZXIgdGhlIGN1cnZlIHZhbHVlcyBmb3VuZCBpbiB0aGUgUk9DIGFuYWx5c2lzLCBpdCB3b3VsZCBhcHBlYXIgdGhhdCB0aGUgZm9yd2FyZCBzZWxlY3Rpb24gbW9kZWwgcHJvdmlkZXMgdGhlIGJlc3QgZ2xvYmFsIGdvb2RuZXNzLiBCb3RoIHRoZSBmdWxsIG1vZGVsIGFuZCB0aGUgZm9yd2FyZCBzZWxlY3Rpb24gbW9kZWwgaGFkIHRoZSBzYW1lIHZhbHVlIGZvciB0aGVpciBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSwgYnV0IHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCB3b3VsZCBiZSB0aGUgYmV0dGVyIGNob2ljZSBkdWUgdG8gaXQgaGF2aW5nIGxlc3MgdmFyaWFibGVzLg0KDQpUaGUgUk9DIGFuYWx5c2lzIHJldmVhbGVkIHRoYXQgdGhlIGZvcndhcmQgc2VsZWN0aW9uIG1vZGVsIG1heSBpbiBmYWN0IGJlIGEgZ29vZCBhbHRlcm5hdGl2ZSB0byB1c2UgYXMgdGhlIGZpbmFsIG1vZGVsIGR1ZSB0byBpdCBoYXZpbmcgYSBoaWdoZXIgYXJlYSB1bmRlciB0aGUgY3VydmUgdGhhbiB0aGUgcmVkdWNlZCBtb2RlbCwgZGVzcGl0ZSB0aGUgcmVkdWNlZCBtb2RlbCBoYXZpbmcgYSBsb3dlciBhdmVyYWdlIHZhbHVlIG9mIHByZWRpY3RpdmUgZXJyb3JzIGFzIHdhcyBmb3VuZCBlYXJsaWVyLiBBIHBvdGVudGlhbCByZWFzb24gZm9yIHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCBoYXZpbmcgYSBoaWdoZXIgQVVDIHRoYW4gdGhlIHJlZHVjZWQgbW9kZWwgZGVzcGl0ZSB0aGUgcmVkdWNlZCBtb2RlbCBoYXZpbmcgYSBsb3dlciBhbmQgbW9yZSBpZGVhbCBhdmVyYWdlIHZhbHVlIG9mIHByZWRpY3RpdmUgZXJyb3JzIGNvdWxkIGJlIGR1ZSB0byB0aGUgcmVkdWNlZCBtb2RlbCBoYXZpbmcgbGVzcyB2YXJpYWJsZXMuIEl0IGNvdWxkIGJlIGEgcG9zc2liaWxpdHkgdGhhdCB0aGUgcmVkdWNlZCBtb2RlbCBoYXZpbmcgZmV3ZXIgdmFyaWFibGVzIGNvdWxkIGhhdmUgYSBoaWdoZXIgbGlrZWxpaG9vZCBvZiBmYWxzZSBwb3NpdGl2aWVzIG9yIGZhbHNlIG5lZ2F0aXZlcyBkdWUgdG8gc29tZSBvZiB0aGUgdmFyaWFibGVzIHdoaWNoIG1heSBiZSBzaWduaWZpY2FudCBub3QgaGF2aW5nIGJlZW4gaW5jbHVkZWQgaW4gdGhlIHJlZHVjZWQgbW9kZWwuIA0KDQoNCg0KIyBDb25jbHVzaW9uDQoNCkluIHRoaXMgcHJvamVjdCwgdGhyZWUgY2FuZGlkYXRlIG1vZGVscyB3ZXJlIGNyZWF0ZWQgdG8gY29tcGFyZSB0aGVpciBwcmVkaWN0aXZlIHBvd2VycyBhbmQgdWx0aW1hdGVseSBjaG9vc2UgYSBmaW5hbCBtb2RlbCB0aGF0IHByb3ZpZGVzIHRoZSBiZXN0IHNpZ25pZmljYW5jZSBhbmQgcXVhbGl0eSBvZiBwcmVkaWN0aW9uIGZvciBwcmVkaWN0aW5nIHRoZSBvZGRzIG9mIGFuIGluZGl2aWR1YWwgYmVpbmcgYXQgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQgaW4gYSAxMC15ZWFyIHBlcmlvZC4gVGhlc2UgbW9kZWxzIGFsbCBjb25zaXN0ZWQgb2YgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiB0byBwcmVkaWN0IHRoZSBiaW5hcnkgcmVzcG9uc2UgdmFyaWFibGUgb2YgYW4gaW5kaXZpZHVhbCdzIG9kZHMgb2YgYmVpbmcgYXQgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQuIENyZWF0aW5nIGEgbW9kZWwgZm9yIHRoZSBwdXJwb3NlIG9mIHRoaXMgcHJlZGljdGlvbiBjYW4gcHJvdmlkZSB1c2UgZm9yIGRvY3RvcnMgYW5kIHBhdGllbnRzIGluIG9yZGVyIHRvIHByZWRpY3QgdGhlaXIgb2RkcyBvZiBiZWluZyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRCBiYXNlZCB1cG9uIHZhcmlvdXMgcGVyc29uYWwgYW5kIG1lZGljYWwgZmFjdG9ycy4gDQoNClRoZSB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzIHRoYXQgd2VyZSBjcmVhdGVkIGluY2x1ZGVkIGEgZnVsbCBtb2RlbCB3aXRoIGFsbCBvZiB0aGUgdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldCwgYSByZWR1Y2VkIG1vZGVsIHdpdGggb25seSB0aGUgdmFyaWFibGVzIGRlZW1lZCBhcyB0aGUgbW9zdCBwcmFjdGljYWxseSBpbXBvcnRhbnQsIGFuZCBhIG1vZGVsIGNyZWF0ZWQgdGhyb3VnaCBmb3J3YXJkIHZhcmlhYmxlIHNlbGVjdGlvbi4gVGhlc2UgdGhyZWUgbW9kZWxzIHdlcmUgY29tcGFyZWQgYnkgdGhlaXIgcHJlZGljdGl2ZSBwb3dlciBhbmQgcXVhbGl0eSBmb3IgdGhlaXIgcG90ZW50aWFsIHVzZSBhcyBhIGZpbmFsIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIHRoaXMgcHJvamVjdC4gDQoNClRoZSBhdmVyYWdlIHByZWRpY3RpdmUgZXJyb3JzIG9mIGFsbCB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzIHdlcmUgY29tcGFyZWQgdG8gYXNzZXNzIHRoZWlyIHByZWRpY3RpdmUgcG93ZXJzIHRocm91Z2ggdGhlIHByb2Nlc3Mgb2YgY3Jvc3MtdmFsaWRhdGlvbi4gSXQgd2FzIGZvdW5kIHRoYXQgdGhlIGZ1bGwgbW9kZWwgYW5kIHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCBoYWQgaWRlbnRpY2FsIHZhbHVlcyBmb3IgdGhlIGF2ZXJhZ2UgcHJlZGljdGl2ZSBlcnJvcnMuIEhvd2V2ZXIsIHRoZSByZWR1Y2VkIG1vZGVsIHR1cm5lZCBvdXQgdG8gaGF2ZSB0aGUgbG93ZXN0IHZhbHVlIG9mIGl0cyBhdmVyYWdlIHByZWRpY3RpdmUgZXJyb3JzIG91dCBvZiB0aGUgdGhyZWUgY2FuZGlkYXRlIG1vZGVscy4gVGhpcyBpbmRpY2F0ZWQgdGhhdCB0aGUgcmVkdWNlZCBtb2RlbCB3YXMgdGhlIGlkZWFsIGNob2ljZSBkdWUgdG8gaXQgaGF2aW5nIHRoZSBsb3dlc3QgdmFsdWUgb2YgYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9ycywgYW5kIHRoZXJlZm9yZSB0aGUgaGlnaGVzdCBxdWFsaXR5IG9mIHByZWRpY3RpdmUgcG93ZXIuIFRoaXMgaW5kaWNhdGVkIHRoYXQgdGhlIHJlZHVjZWQgbW9kZWwgd291bGQgYmUgYSBnb29kIGNob2ljZSBmb3IgdGhlIGZpbmFsIG1vZGVsIGR1ZSB0byBpdHMgaGlnaCBxdWFsaXR5IHByZWRpY3RpdmUgcG93ZXIgc2hvd24gYnkgaG93IGl0IGhhZCB0aGUgc21hbGxlc3QgdmFsdWUgb2YgYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9ycyBvdXQgb2YgYWxsIHRocmVlIGNhbmRpZGF0ZSBtb2RlbHMuIA0KDQpGdXJ0aGVybW9yZSwgUk9DIGFuYWx5c2lzIHdhcyBjb25kdWN0ZWQgdG8gY29udGludWUgdGhlIGFuYWx5c2lzIG9mIHRoZSB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzLiBJdCB3YXMgZm91bmQgdGhhdCB0aGUgZnVsbCBtb2RlbCBhbmQgdGhlIGZvcndhcmQgc2VsZWN0aW9uIG1vZGVsIGhhdmUgaWRlbnRpY2FsIFJPQyBjdXJ2ZXMgYW5kIGFyZWEgdW5kZXIgdGhlIGN1cnZlIHZhbHVlcy4gVGhpcyBtYXRjaGVkIHVwIHdpdGggaG93IGl0IHdhcyBwcmV2aW91c2x5IGZvdW5kIHRoYXQgdGhlIGZ1bGwgbW9kZWwgYW5kIHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCBoYXZlIHRoZSBleGFjdCBzYW1lIGF2ZXJhZ2UgdmFsdWUgb2YgdGhlaXIgcHJlZGljdGl2ZSBlcnJvcnMuIEJldHdlZW4gdGhlc2UgdHdvIG1vZGVscywgd2Ugd291bGQgY2hvb3NlIHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCBvdmVyIHRoZSBmdWxsIG1vZGVsIGR1ZSB0byBpdCBoYXZpbmcgbGVzcyB2YXJpYWJsZXMuIEhvd2V2ZXIsIHdlIGFsc28gZm91bmQgdGhhdCB0aGUgcmVkdWNlZCBtb2RlbCBpbiBmYWN0IGhhZCB0aGUgbG93ZXN0IGFyZWEgdW5kZXIgdGhlIGN1cnZlIHZhbHVlIG91dCBvZiB0aGUgdGhyZWUgbW9kZWxzLiBUaGlzIGlzIGludGVyZXN0aW5nIGFzIGl0IGNvbnRyYWRpY3RzIHdpdGggdGhlIHJlZHVjZWQgbW9kZWwgcHJldmlvdXNseSBiZWluZyBzaG93biB0byBoYXZlIHRoZSBsb3dlc3QgYXZlcmFnZSB2YWx1ZSBvZiBwcmVkaWN0aXZlIGVycm9ycy4gSXQgdHVybnMgb3V0IHRoYXQgZGVzcGl0ZSB0aGUgcmVkdWNlZCBtb2RlbCBoYXZpbmcgdGhlIGxvd2VzdCBhdmVyYWdlIG9mIHByZWRpY3RpdmUgZXJyb3JzIGFuZCB0aGVyZWZvcmUgdGhlIGhpZ2hlc3QgcHJlZGljdGl2ZSBwb3dlciwgaXQgYWxzbyBoYXMgdGhlIGxvd2VzdCBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSBtZWFuaW5nIHRoYXQgaXQgaGFzIGxvd2VyIGdsb2JhbCBnb29kbmVzcyBvdXQgb2YgdGhlIGNhbmRpZGF0ZSBtb2RlbHMuDQoNCk92ZXJhbGwsIGl0IHdhcyBmb3VuZCB0aGF0IHRocm91Z2ggY3Jvc3MtdmFsaWRhdGlvbiBpdCB0dXJuZWQgb3V0IHRoYXQgdGhlIHJlZHVjZWQgbW9kZWwgaGFkIHRoZSBsb3dlc3QgYXZlcmFnZSB2YWx1ZSBvZiBwcmVkaWN0aXZlIGVycm9ycywgYW5kIHRoZXJlZm9yZSB0aGUgaGlnaGVzdCBwcmVkaWN0aXZlIHBvd2VyLiBUaGlzIG1hZGUgdGhlIHJlZHVjZWQgbW9kZWwgdGhlIGlkZWFsIGNob2ljZSBmb3IgdGhlIHNlbGVjdGlvbiBvZiBvdXIgZmluYWwgbW9kZWwuIFRoaXMgcmVkdWNlZCBtb2RlbCBmb2N1c2VkIG9uIG9ubHkgdGhlIG1vc3QgcHJhY3RpY2FsbHkgaW1wb3J0YW50IHZhcmlhYmxlcyBmb3IgcHJlZGljdGluZyB0aGUgb2RkcyBvZiBhbiBpbmRpdmlkdWFsIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hELiBUaGVzZSBtb3N0IHByYWN0aWNhbGx5IGltcG9ydGFudCB2YXJpYWJsZXMgaW5jbHVkZWQgY3VycmVudFNtb2tlciwgc2QuY2lnc1BlckRheSwgc2Quc3lzQlAsIHNkLmRpYUJQLCBhbmQgc2QudG90Q2hvbC4gSG93ZXZlciwgaXQgd2FzIGxhdGVyIGZvdW5kIHRocm91Z2ggUk9DIGFuYWx5c2lzIHRoYXQgdGhlIHJlZHVjZWQgbW9kZWwgaGFkIHRoZSBsb3dlc3QgYXJlYSB1bmRlciB0aGUgY3VydmUgdmFsdWUsIGluZGljYXRpbmcgYSBsb3dlciBnbG9iYWwgZ29vZG5lc3MuIEl0IHdhcyBpbiBmYWN0IHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCB0aGF0IHRoZSBST0MgYW5hbHlzaXMgc3VnZ2VzdGVkIGFzIGJlaW5nIHRoZSBpZGVhbCBjaG9pY2UgYmFzZWQgdXBvbiBpdHMgZ2xvYmFsIGdvb2RuZXNzLiBUaGUgZm9yd2FyZCBzZWxlY3Rpb24gbW9kZWwgaW5jbHVkZWQgdGhlIHZhcmlhYmxlcyBvZiBjdXJyZW50U21va2VyLCBzZC5jaWdzUGVyRGF5LCBzZC5zeXNCUCwgc2QuZGlhQlAsIHNkLnRvdENob2wsIHNkLGFnZSwgbWFsZSwgc2QuZ2x1Y29zZSwgcHJldmFsZW50U3Ryb2tlLCBwcmV2YWxlbnRIeXAsIGFuZCBCUE1lZHMuIA0KDQpFdmVuIHRob3VnaCB0aGUgcmVkdWNlZCBtb2RlbCBwcm92aWRlZCB0aGUgYmVzdCBwcmVkaWN0aXZlIHBvd2VyIGR1ZSB0byBpdHMgbG93ZXIgdmFsdWUgb2YgYXZlcmFnZSBwcmVkaWN0aXZlIGVycm9ycywgdGhlIGZvcndhcmQgc2VsZWN0aW9uIG1vZGVsIHdhcyBzaG93biB0aHJvdWdoIFJPQyBhbmFseXNpcyB0byBoYXZlIHRoZSBoaWdoZXN0IGdsb2JhbCBnb29kbmVzcy4gQm90aCB0aGUgcmVkdWNlZCBtb2RlbCBhbmQgdGhlIGZ1bGwgbW9kZWwgYXJlIGhpZ2ggcXVhbGl0eSBtb2RlbHMgZm9yIHRoZSBwcmVkaWN0aW9uIGFuZCBlc3RpbWF0aW9uIG9mIHRoZSBvZGRzIG9mIGFuIGluZGl2aWR1YWwgYmVpbmcgYXQgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQuIFRoaXMgZGlzY3JlcGFuY3kgYmV0d2VlbiB0aGUgcmVkdWNlZCBtb2RlbCBoYXZpbmcgdGhlIGhpZ2hlc3QgcHJlZGljdGl2ZSBwb3dlciB5ZXQgdGhlIGxvd2VzdCBnbG9iYWwgZ29vZG5lc3MgY291bGQgaW4gZmFjdCBiZSBkdWUgdG8gaXQgaGF2aW5nIHRoZSBmZXdlc3QgdmFyaWFibGVzLiBCeSBoYXZpbmcgZmV3ZXIgdmFyaWFibGVzLCB0aGlzIGNvdWxkIHBvdGVudGlhbGx5IGxlYWQgdG8gaGlnaGVyIHJhdGVzIG9mIGZhbHNlIHBvc2l0aXZlcyBhbmQgZmFsc2UgbmVnYXRpdmVzIHRoYW4gdGhlIG90aGVyIG1vZGVscyB3aXRoIG1vcmUgdmFyaWFibGVzIGFjY291bnRlZCBmb3IuIFNvIG92ZXJhbGwsIHRoZSByZWR1Y2VkIG1vZGVsIHdvdWxkIGJlIHRoZSBpZGVhbCBjaG9pY2UgYXMgdGhlIGZpbmFsIG1vZGVsIGZvciBhIG1vZGVsIHdpdGggdGhlIGhpZ2hlc3QgcHJlZGljdGl2ZSBwb3dlciwgd2hpY2ggaXMgd2hhdCB3ZSB3ZXJlIGxvb2tpbmcgZm9yIGluIHRoaXMgcHJvamVjdC4gSG93ZXZlciwgaXQgaXMgaW1wb3J0YW50IHRvIGtlZXAgaW4gbWluZCB0aGF0IHRoaXMgcmVkdWNlZCBtb2RlbCBoYXMgYSBsb3dlciBnbG9iYWwgZ29vZG5lc3MgdGhhbiB0aGUgZm9yd2FyZCBzZWxlY3Rpb24gbW9kZWwsIGxpa2VseSBkdWUgdG8gdGhlIHJlZHVjZWQgbW9kZWwgaGF2aW5nIGZld2VyIHZhcmlhYmxlcyBhbmQgcG90ZW50aWFsbHkgYSBoaWdoZXIgcmF0ZSBmb3IgZmFsc2UgcG9zaXRpdmVzIGFuZCBmYWxzZSBuZWdhdGl2ZXMuIFRoaXMgaXMgaW1wb3J0YW50IHRvIGtlZXAgaW4gbWluZCB3aGVuIGNyZWF0aW5nIGEgbW9kZWwgZm9yIHRoZSBwcmVkaWN0aW9uIG9mIGFuIGluZGl2aWR1YWwncyBvZGRzIG9mIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hELCBhcyBoaWdoIHByZWRpY3RpdmUgcG93ZXIgaXMgaWRlYWwgZm9yIGVuc3VyaW5nIHRoYXQgcGF0aWVudCdzIGhlYWx0aCBpcyBhY2NvdW50ZWQgZm9yIHByb3Blcmx5LCBidXQgaXQgaXMgYWxzbyBpbXBvcnRhbnQgdG8gYmUgd2FyeSBvZiB0aGUgcG90ZW50aWFsIGZvciBmYWxzZSBwb3N0aXZlcyBhbmQgZmFsc2UgbmVnYXRpdmVzIGluIHJlZ2FyZHMgb2YgdGhlc2UgcHJlZGljdGlvbnMuIA0KDQoNCg0KIyMgUmVjb21tZW5kYXRpb25zDQoNClNvbWUgcmVjb21tZW5kYXRpb25zIEkgd291bGQgbWFrZSBmb3IgZnV0dXJlIHByb2plY3RzIGluY2x1ZGU6DQoNCiogRXhwYW5kIHRoZSBkYXRhIGNvbGxlY3Rpb24gdG8gZW5zdXJlIHRoZSBhY2N1cmFjeSBvZiB0aGUgZmluZGluZ3MgZm91bmQgaW4gdGhpcyBwcm9qZWN0LiBUaGlzIGNvdWxkIGFsc28gaW52b2x2ZSByZWFjaGluZyBvdXQgdG8gdmFyaW91cyBob3NwaXRhbHMgYW5kIGRvY3RvcnMgZm9yIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIG1vc3Qgc2VyaW91cyByaXNrIGZhY3RvcnMgZm9yIENIRCBpbiBvcmRlciB0byBlbnN1cmUgdGhhdCB0aGUgdmFyaWFibGVzIGtlcHQgd2l0aGluIHRoZSBmaW5hbCBtb2RlbCBpbmRlZWQgYXJlIHJlcHJlc2VudGF0aXZlIG9mIGEgcGF0aWVudCdzIG9kZHMgb2YgYmVpbmcgYXQgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQuDQoNCiogQ29uc2lkZXIgb3RoZXIgdmFyaWFibGVzIHdoaWNoIGNvdWxkIGJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgaW4gcHJlZGljdGluZyB0aGUgb2RkcyBvZiBhIHBhdGllbnQncyByaXNrIGZvciBkZXZlbG9waW5nIENIRC4gQWxsIG9mIHRoZSBwcmVkaWN0b3IgdmFyaWFibGVzIHRoYXQgd2VyZSBpbmNsdWRlZCB3aXRoaW4gdGhpcyBkYXRhIHNldCBtYWRlIHNlbnNlIGluIHRlcm1zIG9mIHRoaXMgcHJvamVjdCBhbmQgd2VyZSBhbGwgZmFjdG9ycyB3aGljaCBjb3VsZCBwbGF5IGEgcm9sZSBpbiBhIHBhdGllbnQncyBvZGRzIG9mIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hELiBIb3dldmVyLCBmdXR1cmUgcHJvamVjdHMgY291bGQgY29uc2lkZXIgbG9va2luZyBpbnRvIGFkZGl0aW9uYWwgdmFyaWFibGVzIHRoYXQgbWF5IGJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgaW4gcHJlZGljdGluZyB0aGUgb2RkcyBvZiBhIHBhdGllbnQgYmVpbmcgYXQgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQuIEZvciBpbnN0YW5jZSwgb25lIHBvdGVudGlhbCB2YXJpYWJsZSB0aGF0IGNvdWxkIGJlIGxvb2tlZCBpbnRvIGlzIGEgcGF0aWVudCdzIGluY29tZSB0byBzZWUgaWYgdGhlIGluY29tZSBvZiBhIHBhdGllbnQgaGFzIGFuIGltcGFjdCBvbiB0aGVpciBvZGRzIG9mIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hELiBBIHJlYXNvbiB3aHkgSSBiZWxpZXZlIHRoYXQgdGhpcyBjb3VsZCBiZSBhIHNpZ25pZmljYW50IHZhcmlhYmxlIGZvciB0aGlzIG1vZGVsIGlzIGJlY2F1c2UgcGF0aWVudHMgd2l0aCBoaWdoZXIgaW5jb21lcyB0ZW5kIHRvIGhhdmUgbW9yZSBvcHRpb25zIHdoZW4gaXQgY29tZXMgdG8gbWVkaWNhbCBjYXJlIHRoYW4gcGF0aWVudHMgd2l0aCBsb3dlciBpbmNvbWVzIHdvdWxkLiBTbywgcGVyaGFwcyB0aGVyZSBjb3VsZCBiZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgcGF0aWVudCdzIGluY29tZSBhbmQgdGhlaXIgb2RkcyBvZiBiZWluZyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRC4gVGhpcyBpcyBqdXN0IG9uZSBleGFtcGxlIG9mIGEgdmFyaWFibGUgdGhhdCBpcyBub3QgaW4gdGhpcyBkYXRhIHNldCB3aGljaCBtYXkgcHJvdmlkZSB1c2UgZm9yIGZ1dHVyZSBwcm9qZWN0cy4NCg0KKiBDb25zaWRlciBvdGhlciBwb3NzaWJsZSBtb2RlbHMgdGhhdCBjb3VsZCBwcm92aWRlIHF1YWxpdHkgcHJlZGljdGl2ZSBwb3dlciBpbiBwcmVkaWN0aW5nIHRoZSBvZGRzIG9mIGEgcGF0aWVudCBiZWluZyBhdCByaXNrIGZvciBkZXZlbG9waW5nIENIRCB3aXRoaW4gYSAxMC15ZWFyIHBlcmlvZCBvZiB0aW1lLiBJbiB0aGlzIHByb2plY3QsIHdlIGxvb2tlZCBhdCB0aHJlZSBjYW5kaWRhdGUgbXVsdGlwbGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbHMgYW5kIGNob3NlIHdoaWNoIG9uZSBwcm92aWRlZCB0aGUgYmVzdCB1dGlsaXR5LiBUaGVzZSB0aHJlZSBtb2RlbHMgaW5jbHVkZWQgYSBmdWxsIG1vZGVsIHdpdGggYWxsIG9mIHRoZSBwcmVkaWN0b3IgdmFyaWFibGVzIGxlZnQgaW4gdGhlIG1vZGVsLCBhIHJlZHVjZWQgbW9kZWwgd2l0aCBvbmx5IHRoZSB2YXJpYWJsZXMgdGhhdCB0aGUgbWVkaWNhbCByZXBvcnQgZGVzY3JpYmVkIGFzIG1vc3Qgc2lnbmlmaWNhbnQgcmlzayBmYWN0b3JzIGZvciBDSEQsIGFuZCBhIGZpbmFsIG1vZGVsIHRoYXQgd2FzIGNyZWF0ZWQgdGhyb3VnaCBhdXRvbWF0aWMgZm9yd2FyZCB2YXJpYWJsZSBzZWxlY3Rpb24uIFdlIGZvdW5kIHRoYXQgdGhlIHJlZHVjZWQgbW9kZWwgd2FzIHRoZSBvbmUgd2hpY2ggcHJvdmlkZWQgdGhlIGxvd2VzdCBhdmVyYWdlIHZhbHVlIGZvciBwcmVkaWN0aXZlIGVycm9ycyBvdXQgb2YgdGhlIHRocmVlIG1vZGVscywgYW5kIHNvIHdlIGNob3NlIHRoaXMgdG8gYmUgb3VyIGZpbmFsIG1vZGVsIGR1ZSB0byBpdCBwcm92aWRpbmcgdGhlIHN0cm9uZ2VzdCBwcmVkaWN0aXZlIHBvd2VyLiBIb3dldmVyLCB0aGlzIGlzIG5vdCB0byBzYXkgdGhhdCB0aGVyZSBpcyBub3QgYW55IG90aGVyIHBvc3NpYmxlIG1vZGVsIHRoYXQgY291bGQgcG90ZW50aWFsbHkgYmUgYmV0dGVyIHRoYW4gdGhlIG9uZSB3ZSBjcmVhdGVkLiBJZiBmdXJ0aGVyIHByb2plY3RzIGZvdW5kIGEgbW9kZWwgdGhhdCBwcm92aWRlZCBiZXR0ZXIgYW5kIG1vcmUgcG93ZXIgaW4gcHJlZGljdGlvbiB0aGFuIG91ciBmaW5hbCBtb2RlbCwgdGhpcyBjb3VsZCBoZWxwIGRvY3RvcnMgYW5kIHBhdGllbnRzIGJldHRlciB1bmRlcnN0YW5kIHRoZWlyIG9kZHMgb2YgYmVpbmcgYXQgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQgYmFzZWQgb24gdGhlIHZhcmlvdXMgZmFjdG9ycyBpbmNsdWRlZCBpbiB0aGUgbW9kZWwuIA0KDQoqIEZ1cnRoZXIgaW52ZXN0aWdhdGUgdGhlIHRvcGljIG9mIGZhbHNlIHBvc3RpdmVzIGFuZCBmYWxzZSBuZWdhdGl2ZXMgYW1vbmdzdCB0aGUgcHJlZGljdGVkIHZhbHVlcy4gVGhlIHRvcGljIG9mIGZhbHNlIHBvc3RpdmVzIGFuZCBmYWxzZSBuZWdhdGl2ZXMgd2FzIGFkZHJlc3NlZCBhcyBwb3RlbnRpYWxseSBiZWluZyBhIHJlYXNvbiBmb3IgdGhlIGRlc2NyZXBhbmN5IGJldHdlZW4gdGhlIHJlZHVjZWQgbW9kZWwgaGF2aW5nIHRoZSBncmVhdGVzdCBwcmVkaWN0aXZlIHBvd2VyLCB5ZXQgYWxzbyBoYXZpbmcgdGhlIGxvd2VzdCBnbG9iYWwgZ29vZG5lc3MuIEhhdmluZyBmZXdlciB2YXJhaWJsZXMgY291bGQgcG9zc2libHkgbGVhZCB0byBzb21lIGZhY3RvcnMgYmVpbmcgdW5hY2NvdW50ZWQgZm9yLCBhbmQgcG90ZW50aWFsbHkgcmVzdWx0aW5nIGluIHNvbWUgZmFsc2UgcG9zaXRpdmUgb3IgbmVnYXRpdmUgcHJlZGljdGlvbnMuIFRoaXMgaXMgYSBwb3RlbnRpYWwgdG9waWMgd2hpY2ggY291bGQgYmUgZnVydGhlciBsb29rZWQgaW50byBpbiBmdXJ0aGVyIGV4cGVyaW1lbnRzIHRvIGZ1bGx5IHVuZGVyc3RhbmQgdGhlIG9jY3VyZW5jZXMgb2YgZmFsc2UgcG9zaXRpdmUgb3IgbmVnYXRpdmUgcHJlZGljdGlvbnMuIA0KDQoNCk92ZXJhbGwsIHRoaXMgcHJvamVjdCBzaG93ZWQgdGhhdCB0aGUgcmVkdWNlZCBtb2RlbCByZXN1bHRlZCBpbiB0aGUgbG93ZXN0IGF2ZXJhZ2UgcHJlZGljdGl2ZSBlcnJvcnMgb3V0IG9mIHRoZSB0aHJlZSBtb2RlbHMsIG1lYW5pbmcgdGhpcyB3YXMgdGhlIG1vZGVsIHdpdGggdGhlIGhpZ2hlc3QgcHJlZGljdGl2ZSBwb3dlci4gSG93ZXZlciwgUk9DIGFuYWx5c2lzIHNob3dlZCB0aGF0IHRoZSByZWR1Y2VkIG1vZGVsIGhhZCBhIGxvd2VyIGFyZWEgdW5kZXIgdGhlIGN1cnZlIG1vZGVsLCBhbmQgaXQgd2FzIHRoZSBmb3J3YXJkIHNlbGVjdGlvbiBtb2RlbCB3aGljaCBoYWQgdGhlIGhpZ2hlc3QgZ2xvYmFsIGdvb2RuZXNzIGFzIGluZGljYXRlZCBieSB0aGUgUk9DIGFuYWx5c2lzLiBUaGlzIGlzIHNvbWV0aGluZyBpbXBvcnRhbnQsIGJlY2F1c2UgYWx0aG91Z2ggdGhlIHJlZHVjZWQgbW9kZWwgaXMgYW4gaWRlYWwgY2hvaWNlIGZvciB0aGUgZmluYWwgbW9kZWwgZHVlIHRvIGl0cyBoaWdoIHF1YWxpdHkgb2YgcHJlZGljdGl2ZSBwb3dlciwgdGhpcyBsb3dlciBnbG9iYWwgZ29vZG5lc3MgaXMgYW4gaW1wb3J0YW50IHRoaW5nIHRvIGtlZXAgaW4gbWluZCB3aGVuIHVzaW5nIHRoaXMgZmluYWwgbW9kZWwgZm9yIHRoZSBwcmVkaWN0aW9uIG9mIGFuIGluZGl2aWR1YWwncyBvZGRzIG9mIGJlaW5nIGF0IHJpc2sgZm9yIGRldmVsb3BpbmcgQ0hEIGluIGEgMTAteWVhciBwZXJpb2QuIA0KDQoNCg0KDQojIFJlZmVyZW5jZXMNCg0KVGhpcyBkYXRhIHNldCB3YXMgZm91bmQgb24ga2FnZ2xlLmNvbSB1bmRlciB0aGUgY29sbGVjdGlvbiBvZiBsb2dpc3RpYyByZWdyZXNzaW9uIGRhdGEgc2V0cy4gSW5jbHVkZWQgYmVsb3cgaXMgdGhlIGNpdGF0aW9uIG9mIHRoZSB3ZWIgcGFnZSBvZiB3aGVyZSBJIGZvdW5kIHRoZSBkYXRhIHNldCBJIHVzZWQgZm9yIG15IHByb2plY3QgYWxvbmcgd2l0aCB0aGUgbWVkaWNhbCByZXBvcnQgSSBmb3VuZCB3aGljaCBkZXNjcmliZWQgd2hpY2ggZmFjdG9ycyBhcmUgdGhlIG1vc3QgbWVkaWNhbGx5IHNpZ25pZmljYW50IHdoZW4gaXQgY29tZXMgdG8gZGV0ZXJtaW5pbmcgYSBwYXRpZW50J3MgcmlzayBmb3IgZGV2ZWxvcGluZyBDSEQuDQoNCg0KRGlsZWVwLiAoMjAxOSwgSnVuZSA3KS4gTG9naXN0aWMgcmVncmVzc2lvbiB0byBwcmVkaWN0IGhlYXJ0IGRpc2Vhc2UuIEthZ2dsZS4gaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9kaWxlZXAwNzAvaGVhcnQtZGlzZWFzZS1wcmVkaWN0aW9uLXVzaW5nLWxvZ2lzdGljLXJlZ3Jlc3Npb24/cmVzb3VyY2U9ZG93bmxvYWQmc2VsZWN0PWZyYW1pbmdoYW0uY3N2IA0KDQpIYWphciwgUi4gKDIwMTcpLiBSaXNrIGZhY3RvcnMgZm9yIGNvcm9uYXJ5IGFydGVyeSBkaXNlYXNlOiBIaXN0b3JpY2FsIHBlcnNwZWN0aXZlcy4gSGVhcnQgdmlld3PigK86IHRoZSBvZmZpY2lhbCBqb3VybmFsIG9mIHRoZSBHdWxmIEhlYXJ0IEFzc29jaWF0aW9uLiBodHRwczovL3BtYy5uY2JpLm5sbS5uaWguZ292L2FydGljbGVzL1BNQzU2ODY5MzEvIA0KDQo=