Sample to sample variability
National Health NHanes study
- Since 1960 individuals of all ages are interviewed in their homes every year
- The health examination component of the survey is conducted in a mobile examination centre (MEC).
- We will use this large study to select random subjects from the American population.
- This will help us to understand how the results of an analysis and the conclusions vary from sample to sample.
library(NHANES)
head(NHANES)
Rows: 10,000
Columns: 76
$ ID <int> 51624, 51624, 51624, 51625, 51630, 51638, 51646, 5164…
$ SurveyYr <fct> 2009_10, 2009_10, 2009_10, 2009_10, 2009_10, 2009_10,…
$ Gender <fct> male, male, male, male, female, male, male, female, f…
$ Age <int> 34, 34, 34, 4, 49, 9, 8, 45, 45, 45, 66, 58, 54, 10, …
$ AgeDecade <fct> 30-39, 30-39, 30-39, 0-9, 40-49, 0-9, 0-9, 40…
$ AgeMonths <int> 409, 409, 409, 49, 596, 115, 101, 541, 541, 541, 795,…
$ Race1 <fct> White, White, White, Other, White, White, White, Whit…
$ Race3 <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Education <fct> High School, High School, High School, NA, Some Colle…
$ MaritalStatus <fct> Married, Married, Married, NA, LivePartner, NA, NA, M…
$ HHIncome <fct> 25000-34999, 25000-34999, 25000-34999, 20000-24999, 3…
$ HHIncomeMid <int> 30000, 30000, 30000, 22500, 40000, 87500, 60000, 8750…
$ Poverty <dbl> 1.36, 1.36, 1.36, 1.07, 1.91, 1.84, 2.33, 5.00, 5.00,…
$ HomeRooms <int> 6, 6, 6, 9, 5, 6, 7, 6, 6, 6, 5, 10, 6, 10, 10, 4, 3,…
$ HomeOwn <fct> Own, Own, Own, Own, Rent, Rent, Own, Own, Own, Own, O…
$ Work <fct> NotWorking, NotWorking, NotWorking, NA, NotWorking, N…
$ Weight <dbl> 87.4, 87.4, 87.4, 17.0, 86.7, 29.8, 35.2, 75.7, 75.7,…
$ Length <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ HeadCirc <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Height <dbl> 164.7, 164.7, 164.7, 105.4, 168.4, 133.1, 130.6, 166.…
$ BMI <dbl> 32.22, 32.22, 32.22, 15.30, 30.57, 16.82, 20.64, 27.2…
$ BMICatUnder20yrs <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ BMI_WHO <fct> 30.0_plus, 30.0_plus, 30.0_plus, 12.0_18.5, 30.0_plus…
$ Pulse <int> 70, 70, 70, NA, 86, 82, 72, 62, 62, 62, 60, 62, 76, 8…
$ BPSysAve <int> 113, 113, 113, NA, 112, 86, 107, 118, 118, 118, 111, …
$ BPDiaAve <int> 85, 85, 85, NA, 75, 47, 37, 64, 64, 64, 63, 74, 85, 6…
$ BPSys1 <int> 114, 114, 114, NA, 118, 84, 114, 106, 106, 106, 124, …
$ BPDia1 <int> 88, 88, 88, NA, 82, 50, 46, 62, 62, 62, 64, 76, 86, 6…
$ BPSys2 <int> 114, 114, 114, NA, 108, 84, 108, 118, 118, 118, 108, …
$ BPDia2 <int> 88, 88, 88, NA, 74, 50, 36, 68, 68, 68, 62, 72, 88, 6…
$ BPSys3 <int> 112, 112, 112, NA, 116, 88, 106, 118, 118, 118, 114, …
$ BPDia3 <int> 82, 82, 82, NA, 76, 44, 38, 60, 60, 60, 64, 76, 82, 7…
$ Testosterone <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ DirectChol <dbl> 1.29, 1.29, 1.29, NA, 1.16, 1.34, 1.55, 2.12, 2.12, 2…
$ TotChol <dbl> 3.49, 3.49, 3.49, NA, 6.70, 4.86, 4.09, 5.82, 5.82, 5…
$ UrineVol1 <int> 352, 352, 352, NA, 77, 123, 238, 106, 106, 106, 113, …
$ UrineFlow1 <dbl> NA, NA, NA, NA, 0.094, 1.538, 1.322, 1.116, 1.116, 1.…
$ UrineVol2 <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ UrineFlow2 <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Diabetes <fct> No, No, No, No, No, No, No, No, No, No, No, No, No, N…
$ DiabetesAge <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ HealthGen <fct> Good, Good, Good, NA, Good, NA, NA, Vgood, Vgood, Vgo…
$ DaysPhysHlthBad <int> 0, 0, 0, NA, 0, NA, NA, 0, 0, 0, 10, 0, 4, NA, NA, 0,…
$ DaysMentHlthBad <int> 15, 15, 15, NA, 10, NA, NA, 3, 3, 3, 0, 0, 0, NA, NA,…
$ LittleInterest <fct> Most, Most, Most, NA, Several, NA, NA, None, None, No…
$ Depressed <fct> Several, Several, Several, NA, Several, NA, NA, None,…
$ nPregnancies <int> NA, NA, NA, NA, 2, NA, NA, 1, 1, 1, NA, NA, NA, NA, N…
$ nBabies <int> NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Age1stBaby <int> NA, NA, NA, NA, 27, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ SleepHrsNight <int> 4, 4, 4, NA, 8, NA, NA, 8, 8, 8, 7, 5, 4, NA, 5, 7, N…
$ SleepTrouble <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, No, No, Y…
$ PhysActive <fct> No, No, No, NA, No, NA, NA, Yes, Yes, Yes, Yes, Yes, …
$ PhysActiveDays <int> NA, NA, NA, NA, NA, NA, NA, 5, 5, 5, 7, 5, 1, NA, 2, …
$ TVHrsDay <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ CompHrsDay <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ TVHrsDayChild <int> NA, NA, NA, 4, NA, 5, 1, NA, NA, NA, NA, NA, NA, 4, N…
$ CompHrsDayChild <int> NA, NA, NA, 1, NA, 0, 6, NA, NA, NA, NA, NA, NA, 3, N…
$ Alcohol12PlusYr <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, Yes, Y…
$ AlcoholDay <int> NA, NA, NA, NA, 2, NA, NA, 3, 3, 3, 1, 2, 6, NA, NA, …
$ AlcoholYear <int> 0, 0, 0, NA, 20, NA, NA, 52, 52, 52, 100, 104, 364, N…
$ SmokeNow <fct> No, No, No, NA, Yes, NA, NA, NA, NA, NA, No, NA, NA, …
$ Smoke100 <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, Yes, No, …
$ Smoke100n <fct> Smoker, Smoker, Smoker, NA, Smoker, NA, NA, Non-Smoke…
$ SmokeAge <int> 18, 18, 18, NA, 38, NA, NA, NA, NA, NA, 13, NA, NA, N…
$ Marijuana <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, NA, Ye…
$ AgeFirstMarij <int> 17, 17, 17, NA, 18, NA, NA, 13, 13, 13, NA, 19, 15, N…
$ RegularMarij <fct> No, No, No, NA, No, NA, NA, No, No, No, NA, Yes, Yes,…
$ AgeRegMarij <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 20, 15, N…
$ HardDrugs <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, No, Yes, …
$ SexEver <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, Yes, Y…
$ SexAge <int> 16, 16, 16, NA, 12, NA, NA, 13, 13, 13, 17, 22, 12, N…
$ SexNumPartnLife <int> 8, 8, 8, NA, 10, NA, NA, 20, 20, 20, 15, 7, 100, NA, …
$ SexNumPartYear <int> 1, 1, 1, NA, 1, NA, NA, 0, 0, 0, NA, 1, 1, NA, NA, 1,…
$ SameSex <fct> No, No, No, NA, Yes, NA, NA, Yes, Yes, Yes, No, No, N…
$ SexOrientation <fct> Heterosexual, Heterosexual, Heterosexual, NA, Heteros…
$ PregnantNow <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
Data exploration
Suppose that we are interested in assessing the difference in direct cholesterol levels between males and females older than 25 years.
- We pipe the dataset to the function
filter
to filter the data according to age.
- We plot the direct cholesterol levels.
- We select the data with the command
ggplot(aes(x=DirectChol))
- We add a histogram with the command
geom_histogram()
- We make to vertical panels using the command
facet_grid(Gender~.)
- We customize the label of the x-axis with the
xlab
command.
NHANES %>%
filter(Age > 25) %>%
ggplot(aes(x = DirectChol)) +
geom_histogram() +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (mg/dl)")

- Cholesterol levels and concentration measurements are often skewed.
- Concentrations cannot be lower than 0.
- They are often log transformed.
NHANES %>%
filter(Age > 25) %>%
ggplot(aes(x = DirectChol %>% log2())) +
geom_histogram() +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (log2)")

We see that the data are more or less bell shaped upon log transformation.
We will now create a subset of the data that we will use to sample from in the next sections.
- We filter on age and remove subjects with missing values (NA).
- We only select the variables Gender and DirectChol from the dataset to avoid unnecessary variables.
- With the mutate function we can add a new variable logChol with log transformed direct cholesterol levels.
nhanesSub <- NHANES %>%
filter(Age > 25 & !is.na(DirectChol)) %>%
select(c("Gender", "DirectChol")) %>%
mutate(cholLog = log2(DirectChol))
We will calculate the summary statistics for the cholLog variable for males and females in the large dataset.
So we group by Gender
cholLogSum <- nhanesSub %>%
group_by(Gender) %>%
summarize(
mean = mean(cholLog, na.rm = TRUE),
sd = sd(cholLog, na.rm = TRUE),
n = n()
) %>%
mutate(se = sd / sqrt(n))
cholLogSum
Experiment
- Suppose that we have no access to cholesterol levels of the American population,
- we will have to setup an experiment.
- Suppose we have a budget for assessing 10 females and 10 males,
- we will subset 10 females and 10 males at random from the American population and measure their direct cholesterol levels.
fem <- nhanesSub %>%
filter(Gender == "female") %>%
sample_n(size = 10)
mal <- nhanesSub %>%
filter(Gender == "male") %>%
sample_n(size = 10)
samp <- rbind(fem, mal)
samp
We will now plot the data with a histogram and boxplots
samp %>%
ggplot(aes(x = cholLog)) +
geom_histogram(binwidth = .1) +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (log2)")

samp %>%
ggplot(aes(x = Gender, y = cholLog)) +
geom_boxplot(outlier.shape = NA) +
geom_point(position = "jitter")

We summarize the data
samp %>%
group_by(Gender) %>%
summarize(
mean = mean(cholLog, na.rm = TRUE),
sd = sd(cholLog, na.rm = TRUE),
n = n()
) %>%
mutate(se = sd / sqrt(n))
Note that the sample mean is different from that of the large experiment (“population”) we sampled from.
We test for the difference between Males and females
t.test(cholLog ~ Gender, samp, var.equal = TRUE)
Two Sample t-test
data: cholLog by Gender
t = 1.8919, df = 18, p-value = 0.0747
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
-0.03588746 0.68570738
sample estimates:
mean in group female mean in group male
0.34776170 0.02285174
Repeat the experiment
If we do the experiment again we select other people and we obtain different results.
fem <- nhanesSub %>%
filter(Gender == "female") %>%
sample_n(size = 10)
mal <- nhanesSub %>%
filter(Gender == "male") %>%
sample_n(size = 10)
samp2 <- rbind(fem, mal)
samp2 %>%
ggplot(aes(x = DirectChol %>% log())) +
geom_histogram(binwidth = .1) +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (log)")

samp2 %>%
ggplot(aes(x = Gender, y = cholLog)) +
geom_boxplot(outlier.shape = NA) +
geom_point(position = "jitter")

samp2 %>%
group_by(Gender) %>%
summarize(
mean = mean(cholLog, na.rm = TRUE),
sd = sd(cholLog, na.rm = TRUE),
n = n()
) %>%
mutate(se = sd / sqrt(n))
t.test(cholLog ~ Gender, samp2, var.equal = TRUE)
Two Sample t-test
data: cholLog by Gender
t = 1.7522, df = 18, p-value = 0.09675
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
-0.07604904 0.84039821
sample estimates:
mean in group female mean in group male
0.6420087 0.2598341
And again
set.seed(12857)
fem <- nhanesSub %>%
filter(Gender == "female") %>%
sample_n(size = 10)
mal <- nhanesSub %>%
filter(Gender == "male") %>%
sample_n(size = 10)
samp3 <- rbind(fem, mal)
samp3 %>%
ggplot(aes(x = DirectChol %>% log())) +
geom_histogram(binwidth = .1) +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (log)")

samp3 %>%
ggplot(aes(x = Gender, y = cholLog)) +
geom_boxplot(outlier.shape = NA) +
geom_point(position = "jitter")

samp3 %>%
group_by(Gender) %>%
summarize(
mean = mean(cholLog, na.rm = TRUE),
sd = sd(cholLog, na.rm = TRUE),
n = n()
) %>%
mutate(se = sd / sqrt(n))
t.test(cholLog ~ Gender, samp3, var.equal = TRUE)
Two Sample t-test
data: cholLog by Gender
t = -2.4449, df = 18, p-value = 0.02501
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
-0.7049891 -0.0533427
sample estimates:
mean in group female mean in group male
0.2585913 0.6377572
Summary
Because we sampled other subjects in each sample, we obtain different cholesterol levels.
However, not only the cholesterol levels differ from sample to sample but also the summary statistics: means, standard deviations and standard errors.
Note, that in the last sample the log cholesterol levels are on average lower for females than for males; based on this sample we even would wrongly conclude that the cholesterol levels for females are on average larger than those of males.
This implies that our conclusions are also subjected to uncertainty and might change from sample to sample.
Samples as the one where the effect swaps and is statistically significant, however, are very rare.
This is illustrated with the code below, where we will draw 20000 repeated samples with sample size 10 for females and males from the NHanes study.
nsim <- 20000
nSamp <- 10
res <- matrix(0, nrow = nsim, ncol = 2)
fem <- nhanesSub %>% filter(Gender == "female")
mal <- nhanesSub %>% filter(Gender == "male")
for (i in 1:nsim)
{
femSamp <- sample(fem$cholLog, nSamp)
malSamp <- sample(mal$cholLog, nSamp)
meanFem <- mean(femSamp)
meanMal <- mean(malSamp)
delta <- meanFem - meanMal
sdFem <- sd(femSamp)
sdMal <- sd(malSamp)
seFem <- sdFem / sqrt(nSamp)
seFem <- sdFem / sqrt(nSamp)
sdPool <- sqrt((sdFem^2 * (nSamp - 1) + sdMal^2 * (nSamp - 1)) / (2 * nSamp - 2))
tvalue <- (delta) / (sdPool * sqrt(1 / nSamp + 1 / nSamp))
pvalue <- pt(abs(tvalue), lower.tail = FALSE, df = 2 * nSamp - 2) * 2
res[i, ] <- c(delta, pvalue)
}
sum(res[, 2] < 0.05 & res[, 1] > 0)
[1] 7785
[1] 12212
sum(res[, 2] < 0.05 & res[, 1] < 0)
[1] 3
res <- res %>% as.data.frame()
names(res) <- c("delta", "pvalue")
res %>%
ggplot(aes(x = delta, y = -log10(pvalue), color = pvalue < 0.05)) +
geom_point() +
xlab("Average cholesterol difference") +
ylab("- log10(pvalue)") +
scale_color_manual(values = c("black", "red"))

res %>%
ggplot(aes(y = delta)) +
geom_boxplot() +
geom_point(aes(x = 0, y = c(mean(fem$cholLog) - mean(mal$cholLog)), color = "pop. diff")) +
xlab("")

Only in 3 out of 20000 samples we conclude that the mean cholesterol level of males is significantly lower than for females. For the remaining samples the cholesterol levels for males were on average significantly lower than for females (7785 samples) or the average difference in cholesterol levels were not statistically significant (12212 samples). The latter is because the power is rather low to detect the difference with 10 samples in each group.
Assignment
- Copy the code chunk with the simulation study
- Add it here below
- Modify the sample size to 50.
- What do you observe?
Control of false positives
Wat happens when there is no difference between both groups?
We will have to simulate experiments for which the cholestorol levels are the same for both groups.
We can do this by sampling data for both groups from the subset of women in the study.
We do this again for 10 subjects per group
nsim <- 20000
nSamp <- 10
res <- matrix(0, nrow = nsim, ncol = 2)
fem <- nhanesSub %>% filter(Gender == "female")
mal <- nhanesSub %>% filter(Gender == "male")
for (i in 1:nsim)
{
femSamp <- sample(fem$cholLog, nSamp)
fem2Samp <- sample(fem$cholLog, nSamp)
meanFem <- mean(femSamp)
meanFem2 <- mean(fem2Samp)
delta <- meanFem - meanFem2
sdFem <- sd(femSamp)
sdFem2 <- sd(fem2Samp)
seFem <- sdFem / sqrt(nSamp)
seFem <- sdFem2 / sqrt(nSamp)
sdPool <- sqrt((sdFem^2 * (nSamp - 1) + sdFem2^2 * (nSamp - 1)) / (2 * nSamp - 2))
tvalue <- (delta) / (sdPool * sqrt(1 / nSamp + 1 / nSamp))
pvalue <- pt(abs(tvalue), lower.tail = FALSE, df = 2 * nSamp - 2) * 2
res[i, ] <- c(delta, pvalue)
}
sum(res[, 2] < 0.05 & res[, 1] > 0)
[1] 480
[1] 18960
sum(res[, 2] < 0.05 & res[, 1] < 0)
[1] 560
res <- res %>% as.data.frame()
names(res) <- c("delta", "pvalue")
res %>%
ggplot(aes(x = delta, y = -log10(pvalue), color = pvalue < 0.05)) +
geom_point() +
xlab("Average cholesterol difference") +
ylab("- log10(pvalue)") +
scale_color_manual(values = c("black", "red"))

res %>%
ggplot(aes(y = delta)) +
geom_boxplot() +
geom_point(aes(x = 0, y = 0, color = "pop. diff")) +
xlab("")

Note, that the number of false positives are on 1040 on 20000 experiments and are nicely controlled at the 5% level.
What happens if we increase the sample size to 50 subjects per group?
LS0tCnRpdGxlOiAnMS4gSW50cm9kdWN0aW9uOiBXaHkgZG8gd2UgbmVlZCBzdGF0aXN0aWNzJwphdXRob3I6ICJMaWV2ZW4gQ2xlbWVudCIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKb3V0cHV0OgogIGJvb2tkb3duOjpwZGZfZG9jdW1lbnQyOgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleAphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCBjYWNoZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjYWNoZSA9IFRSVUUKKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgojIE1vdGl2YXRpb24KPGEgcmVsPSJsaWNlbnNlIiBocmVmPSJodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktbmMtc2EvNC4wIj48aW1nIGFsdD0iQ3JlYXRpdmUgQ29tbW9ucyBMaWNlbnNlIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjAiIHNyYz0iaHR0cHM6Ly9pLmNyZWF0aXZlY29tbW9ucy5vcmcvbC9ieS1uYy1zYS80LjAvODh4MzEucG5nIiAvPjwvYT4KCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvU0N3NjVqamFYUHc/c2k9bTJ3X05xRGdqZ0M5a2JmOSIgdGl0bGU9IllvdVR1YmUgdmlkZW8gcGxheWVyIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImFjY2VsZXJvbWV0ZXI7IGF1dG9wbGF5OyBjbGlwYm9hcmQtd3JpdGU7IGVuY3J5cHRlZC1tZWRpYTsgZ3lyb3Njb3BlOyBwaWN0dXJlLWluLXBpY3R1cmU7IHdlYi1zaGFyZSIgcmVmZXJyZXJwb2xpY3k9InN0cmljdC1vcmlnaW4td2hlbi1jcm9zcy1vcmlnaW4iIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4KCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvUEFKTDIwNzhPMjA/c2k9Wk8yQm5FaGJvWDZGNTN4NSIgdGl0bGU9IllvdVR1YmUgdmlkZW8gcGxheWVyIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImFjY2VsZXJvbWV0ZXI7IGF1dG9wbGF5OyBjbGlwYm9hcmQtd3JpdGU7IGVuY3J5cHRlZC1tZWRpYTsgZ3lyb3Njb3BlOyBwaWN0dXJlLWluLXBpY3R1cmU7IHdlYi1zaGFyZSIgcmVmZXJyZXJwb2xpY3k9InN0cmljdC1vcmlnaW4td2hlbi1jcm9zcy1vcmlnaW4iIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4KCiFbXSguL2ZpZ3VyZXMvd3BHcmFwaC5qcGVnKQoKLSBXZSBsaXZlIGluIGEgYmlnIGRhdGEgZXJhCi0gRGF0YSBvbiBsb2NhdGlvbiwgY2xpY2tzLCBlLWNvbW1lcmNlLCBzb2NpYWwgbWVkaWEgLi4uCi0gTGlmZSBTY2llbmNlczogbWVhc3VyZSBleHByZXNzaW9uIG9mIHRob3VzYW5kcyBvZiBnZW5lcywgcHJvdGVpbnMsIC4uLiBmb3IgZWFjaCBzdWJqZWN0IG9yIGV2ZW4gaW5kaXZpZHVhbCBjZWxscwotIERhdGEgZHJpdmVuIGpvdXJuYWxpc20KLSAuLi4KClN0YXRpc3RpY3MgaXMgdGhlIHNjaWVuY2UgdG8gbGVhcm4gZnJvbSBlbXBpcmljYWwgZGF0YS4KClN0YXRpc3RpY2FsIGxpdGVyYWN5IGlzIGtleSB0byBpbnRlcnByZXQgcmVzdWx0cyBmcm9tIHNjaWVudGlmaWMgcHVibGljYXRpb25zLgoKIyBMZWFybmluZyBvYmplY3RpdmVzIAoKMS4gSW4gdGhpcyBpbnRyb2R1Y3Rpb24geW91IHdpbGwgZmFtaWxpYXJpemUgeW91cnNlbGYgd2l0aCB0aHJlZSBpbXBvcnRhbnQgdGFza3Mgb2Ygc3RhdGlzdGljcyAKCiAgLSBFeHBlcmltZW50YWwgZGVzaWduCiAgLSBEYXRhIEV4cGxvcmF0aW9uCiAgLSBFc3RpbWF0aW9uIGFuZCBzdGF0aXN0aWNhbCBpbmZlcmVuY2UgCgoyLiBZb3UgdW5kZXJzdGFuZCBob3cgdGhlIGRhdGEsIHRoZSBlc3RpbWF0ZWQgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uIGFuZCBjb25jbHVzaW9ucyBvZiBhIHN0YXRpc3RpY2FsIGRhdGEgYW5hbHlzaXMgY2FuIGNoYW5nZSBmcm9tIGV4cGVyaW1lbnQgdG8gZXhwZXJpbWVudCAKCjMuIFlvdSBoYXZlIG5vdGljZSBvbiBob3cgCgogIC0gc3RhdGlzdGljYWwgdGVzdHMgY2FuIGNvbnRyb2wgZm9yIGZhbHNlIHBvc2l0aXZlcyAKICAtIHRoZSBwb3dlciB0byBwaWNrIHVwIGFuIGVmZmVjdCBkZXBlbmRzIG9uIHRoZSBzYW1wbGUgc2l6ZSAKCjQuIFlvdSBjYW4gZXhwbGFpbiB0aGUgaW1wb3J0YW5jZSBvZiB1c2luZyBhIGdvb2QgY29udHJvbCAKCjUuIFlvdSBjYW4gZXhwbGFpbiB3aGF0IGNvbmZvdW5kaW5nIGlzCgojIFNtZWxseSBhcm1waXQgZXhhbXBsZQoKLSBTbWVsbHkgYXJtcGl0cyBhcmUgbm90IGNhdXNlZCBieSBzd2VhdCBpdHNlbGYuIFRoZSBzbWVsbCBpcyBjYXVzZWQgYnkgc3BlY2lmaWMgbWljcm8tb3JnYW5pc21zIGJlbG9uZ2luZyB0byB0aGUgZ3JvdXAgb2YgKkNvcnluZWJhY3Rlcml1bSBzcHAuKiB0aGF0IG1ldGFib2xpc2Ugc3dlYXQuCkFub3RoZXIgZ3JvdXAgb2YgYWJ1bmRhbnQgYmFjdGVyaWEgYXJlIHRoZSAqU3RhcGh5bG9jb2NjdXMgc3BwLiosIHRoZXNlIGJhY3RlcmlhIGRvIG5vdCBtZXRhYm9saXNlIHN3ZWF0IGluIHNtZWxseSBjb21wb3VuZHMuCgotIFRoZSBDTUVULWdyb2VwIGF0IEdoZW50IFVuaXZlcnNpdHkgZG9lcyByZXNlYXJjaCBvbiB0cmFuc3BsYW50aW5nIHRoZSBhcm1waXQgbWljcm9iaW9tZSB0byBzYXZlIHBlb3BsZSB3aXRoIHNtZWxseSBhcm1waXRzLgoKLSBQcm9wb3NlZCBUaGVyYXB5OgogIAkxLiBSZW1vdmUgYXJtcGl0LW1pY3JvYmlvbWUgd2l0aCBhbnRpYmlvdGljcwogICAgMi4gSW5mbHVlbmNlIGFybXBpdCBtaWNyb2Jpb21lIHdpdGggbWljcm9iaWFsICB0cmFuc3BsYW50IChodHRwczovL3lvdXR1LmJlLzlSSUZ5cUxYZFZ3KQoKCmBgYHtyIG91dC53aWR0aD0nODAlJyxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIgJWluJSBscygpKSBybSgicGkiKQprb3B2b2V0ZXIgPC0gZnVuY3Rpb24oeCwgeSwgYW5nbGUgPSAwLCBsID0gLjIsIGNleC5kb3QgPSAuNSwgcGNoID0gMTksIGNvbCA9ICJibGFjayIpIHsKICBhbmdsZSA8LSBhbmdsZSAvIDE4MCAqIHBpCiAgcG9pbnRzKHgsIHksIGNleCA9IGNleC5kb3QsIHBjaCA9IHBjaCwgY29sID0gY29sKQogIGxpbmVzKGMoeCwgeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSksIGMoeSwgeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSksIGNvbCA9IGNvbCkKICBsaW5lcyhjKHggKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgYW5nbGUpLCB4ICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSArIGwgLyA0ICogY29zKGFuZ2xlKSksIGMoeSArIGwgLyAyICogc2luKC1waSAvIDIgKyBhbmdsZSksIHkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgYW5nbGUpICsgbCAvIDQgKiBzaW4oYW5nbGUpKSwgY29sID0gY29sKQogIGxpbmVzKGMoeCArIGwgLyAyICogY29zKC1waSAvIDIgKyBhbmdsZSksIHggKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgYW5nbGUpICsgbCAvIDQgKiBjb3MocGkgKyBhbmdsZSkpLCBjKHkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgYW5nbGUpLCB5ICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSArIGwgLyA0ICogc2luKHBpICsgYW5nbGUpKSwgY29sID0gY29sKQogIGxpbmVzKGMoeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSwgeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSArIGwgLyAyICogY29zKC1waSAvIDIgKyBwaSAvIDQgKyBhbmdsZSkpLCBjKHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSksIHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgcGkgLyA0ICsgYW5nbGUpKSwgY29sID0gY29sKQogIGxpbmVzKGMoeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSwgeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSArIGwgLyAyICogY29zKC1waSAvIDIgLSBwaSAvIDQgKyBhbmdsZSkpLCBjKHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSksIHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gMiAqIHNpbigtcGkgLyAyIC0gcGkgLyA0ICsgYW5nbGUpKSwgY29sID0gY29sKQp9CgpwYXIobWFyID0gYygwLCAwLCAwLCAwKSwgbWFpID0gYygwLCAwLCAwLCAwKSkKcGxvdCgwLCAwLCB4bGFiID0gIiIsIHlsYWIgPSAiIiwgeGxpbSA9IGMoMCwgMTApLCB5bGltID0gYygwLCAxMCksIGNvbCA9IDAsIHhheHQgPSAibm9uZSIsIHlheHQgPSAibm9uZSIsIGF4ZXMgPSBGQUxTRSkKcmVjdCgwLCA2LCAxMCwgMTAsIGJvcmRlciA9ICJyZWQiLCBsd2QgPSAyKQp0ZXh0KC41LCA4LCAicG9wdWxhdGlvbiIsIHNydCA9IDkwLCBjb2wgPSAicmVkIiwgY2V4ID0gMikKc3ltYm9scygzLCA4LCBjaXJjbGVzID0gMS41LCBjb2wgPSAicmVkIiwgYWRkID0gVFJVRSwgZmcgPSAicmVkIiwgaW5jaGVzID0gRkFMU0UsIGx3ZCA9IDIpCnNldC5zZWVkKDMzMCkKZ3JpZCA8LSBzZXEoMCwgMS4zLCAuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewogIGFuZ2xlMSA8LSBydW5pZihuID0gMSwgbWluID0gMCwgbWF4ID0gMzYwKQogIGFuZ2xlMiA8LSBydW5pZihuID0gMSwgbWluID0gMCwgbWF4ID0gMzYwKQogIHJhZGl1cyA8LSBzYW1wbGUoZ3JpZCwgcHJvYiA9IGdyaWReMiAqIHBpIC8gc3VtKGdyaWReMiAqIHBpKSwgc2l6ZSA9IDEpCiAga29wdm9ldGVyKDMgKyByYWRpdXMgKiBjb3MoYW5nbGUxIC8gMTgwICogcGkpLCA4ICsgcmFkaXVzICogc2luKGFuZ2xlMSAvIDE4MCAqIHBpKSwgYW5nbGUgPSBhbmdsZTIpCn0KdGV4dCg3LjUsIDgsICJNaWNyb2Jpb21lIGluIHBvcHVsYXRpb24iLCBjb2wgPSAicmVkIiwgY2V4ID0gMS4yKQoKcmVjdCgwLCAwLCAxMCwgNCwgYm9yZGVyID0gImJsdWUiLCBsd2QgPSAyKQp0ZXh0KC41LCAyLCAic2FtcGxlIiwgc3J0ID0gOTAsIGNvbCA9ICJibHVlIiwgY2V4ID0gMikKc3ltYm9scygzLCAyLCBjaXJjbGVzID0gMS41LCBjb2wgPSAicmVkIiwgYWRkID0gVFJVRSwgZmcgPSAiYmx1ZSIsIGluY2hlcyA9IEZBTFNFLCBsd2QgPSAyKQpmb3IgKGkgaW4gMDoxKSB7CiAgZm9yIChqIGluIDA6NCkKICB7CiAgICBrb3B2b2V0ZXIoMi4xICsgaiAqICgzLjkgLSAyLjEpIC8gNCwgMS4xICsgaSAvIDIsIGNvbCA9ICJwdXJwbGUiKQogIH0KfQpmb3IgKGkgaW4gMjozKSB7CiAgZm9yIChqIGluIDA6NCkKICB7CiAgICBrb3B2b2V0ZXIoMi4xICsgaiAqICgzLjkgLSAyLjEpIC8gNCwgMS42ICsgaSAvIDIsIGNvbCA9ICJvcmFuZ2UiKQogIH0KfQp0ZXh0KDcuNSwgMiwgIk1pY3JvYmlvbWUgaW4gc2FtcGxlIiwgY29sID0gImJsdWUiLCBjZXggPSAxLjIpCgphcnJvd3MoMywgNS45LCAzLCA0LjEsIGNvbCA9ICJibGFjayIsIGx3ZCA9IDMpCnRleHQoMS41LCA1LCAiRVhQLiBERVNJR04gKDEpIiwgY29sID0gImJsYWNrIiwgY2V4ID0gMS4yKQp0ZXh0KDcuNSwgLjUsICJEQVRBIEVYUExPUkFUSU9OICZcbkRFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgKDIpIiwgY29sID0gImJsYWNrIiwgY2V4ID0gMS4yKQphcnJvd3MoNywgNC4xLCA3LCA1LjksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDMpCnRleHQoOC41LCA1LCAiRVNUSU1BVElPTiAmXG5JTkZFUkVOQ0UgKDMpIiwgY29sID0gImJsYWNrIiwgY2V4ID0gMS4yKQpgYGAKCgotIEV4cGVyaW1lbnQ6CgogICAgLSAyMCBzdWJqZWN0cyB3aXRoIHNtZWxseSBhcm1waXRzIGFyZSBhdHRyaWJ1dGVkIHRvIG9uZSBvZiB0d28gdHJlYXRtZW50IGdyb3VwcwogICAgLSBwbGFjZWJvIChvbmx5IGFudGliaW90aWNzKQogICAgLSB0cmFuc3BsYW50IChhbnRpYmlvdGljcyBmb2xsb3dlZCBieSBtaWNyb2JpYWwgdHJhbnNwbGFudCkuCiAgICAtIFRoZSBtaWNyb2Jpb21lIGlzIHNhbXBsZWQgNiB3ZWVrcyB1cG9uIHRoZSB0cmVhdG1lbnQuCiAgICAtIFRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgKlN0YXBoeWxvY29jY3VzIHNwcC4qIG9uICpDb3J5bmViYWN0ZXJpdW0gc3BwLiogKyAqU3RhcGh5bG9jb2NjdXMgc3BwLiogaW4gdGhlIG1pY3JvYmlvbWUgaXMgbWVhc3VyZWQgdmlhIERHR0UgKCpEZW5hdHVyaW5nIEdyYWRpZW50IEdlbCBFbGVjdHJvcGhvcmVzaXMqKS4KCi0tLQoKIyMgSW1wb3J0IHRoZSBkYXRhCmBgYHtyfQpyZWFkX2xpbmVzKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvYXJtcGl0LmNzdiIpCmBgYAoKVGhlIGZpbGUgaXMgY29tbWEgc2VwYXJhdGVkIGFuZCBpbiB0aWR5IGZvcm1hdAoKYGBge3J9CmFwIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvYXJtcGl0LmNzdiIpCmFwCmBgYAoKLS0tCgojIyBEYXRhIEV4cGxvcmF0aW9uIGFuZCBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzCgotIERhdGEgZXhwbG9yYXRpb24gaXMgZXh0cmVtZWx5IGltcG9ydGFudCB0byBnZXQgaW5zaWdodCBpbiB0aGUgZGF0YS4KLSBJdCBpcyBvZnRlbiB1bmRlcnJhdGVkIGFuZCBvdmVybG9va2VkLgoKIyMjIERlc2NyaXB0aXZlIHN0YXRpc3RpY3MKCldlIGZpcnN0IHN1bW1hcml6ZSB0aGUgZGF0YSBhbmQgY2FsY3VsYXRlIHRoZSBtZWFuLCBzdGFuZGFyZCBkZXZpYXRpb24sIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgYW5kIHN0YW5kYXJkIGVycm9yIGFuZCBzdG9yZSB0aGUgcmVzdWx0IGluIGFuIG9iamVjdCBhcFJlbFN1bSB2aWEgYGFwUmVsU3VtPC1gCgoxLiBXZSBwaXBlIHRoZSBgYXBgIGRhdGFmcmFtZSB0byB0aGUgZ3JvdXBfYnkgZnVuY3Rpb24gdG8gZ3JvdXAgdGhlIGRhdGEgYnkgdHJlYXRtZW50IHRydCBgZ3JvdXBfYnkodHJ0KWAKMi4gV2UgcGlwZSB0aGUgcmVzdWx0IHRvIHRoZSBgc3VtbWFyaXplYCBmdW5jdGlvbiB0byBzdW1tYXJpemUgdGhlICJyZWwiIHZhcmlhYmxlIGFuZCBjYWxjdWxhdGUgdGhlIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiBhbmQgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMKMy4gV2UgcGlwZSB0aGUgcmVzdWx0IHRvIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiB0byBtYWtlIGEgbmV3IHZhcmlhYmxlIGluIHRoZSBkYXRhIGZyYW1lIGBzZWAgZm9yIHdoaWNoIHdlIGNhbGN1bGF0ZSB0aGUgc3RhbmRhcmQgZXJyb3IKCgpgYGB7cn0KYXBSZWxTdW0gPC0gYXAgJT4lCiAgZ3JvdXBfYnkodHJ0KSAlPiUKICBzdW1tYXJpemUoCiAgICBtZWFuID0gbWVhbihyZWwsIG5hLnJtID0gVFJVRSksCiAgICBzZCA9IHNkKHJlbCwgbmEucm0gPSBUUlVFKSwKICAgIG4gPSBuKCkKICApICU+JQogIG11dGF0ZShzZSA9IHNkIC8gc3FydChuKSkKCmFwUmVsU3VtCmBgYAoKLS0tCgojIyMgUGxvdHMKCldlIHdpbGwgdXNlIGdncGxvdDIgdG8gbWFrZSBvdXIgcGxvdHMuCldpdGggdGhlIGdncGxvdDIgbGlicmFyeSB3ZSBjYW4gZWFzaWx5IGJ1aWxkIHBsb3RzIGJ5IGFkZGluZyBsYXllcnMuCgojIyMjIGJhcnBsb3QKCjEuIFdlIHBpcGUgb3VyIHN1bW1hcml6ZWQgZGF0YSB0byB0aGUgYGdncGxvdGAgZnVuY3Rpb24gYW5kIHdlIHNlbGVjdCB0aGUgdHJlYXRtZW50IHZhcmlhYmxlIHRydCBhbmQgdGhlIHZhcmlhYmxlIG1lYW4gZm9yIHBsb3R0aW5nIGBhZXMoeD10cnQseT1tZWFuKWAKCjIuIFdlIG1ha2UgYSBiYXJwbG90IGJhc2VkIG9uIHRoaXMgZGF0YSB1c2luZyB0aGUgYGdlb21fYmFyYCBmdW5jdGlvbi4gVGhlIHN0YXRpc3RpYyBpcyBgc3RhdD0iaWRlbnRpdHkiYCBiZWNhdXNlIHRoZSBiYXIgaGVpZ2h0IHNob3VsZCBiZSBlcXVhbCB0aGUgdmFsdWUgZm9yIHRoZSBtZWFuIG9mIHRoZSByZWxhdGl2ZSBhYnVuZGFuY2UuCgpgYGB7cn0KYXBSZWxTdW0gJT4lCiAgZ2dwbG90KGFlcyh4ID0gdHJ0LCB5ID0gbWVhbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikKYGBgCgotIElzIHRoaXMgcGxvdCBpbmZvcm1hdGl2ZT8/CgotLS0KCldlIHdpbGwgbm93IGFkZCBzdGFuZGFyZCBlcnJvcnMgdG8gdGhlIHBsb3QKdXNpbmcgYGdlb21fZXJyb3JiYXJgIGZ1bmN0aW9uIGFuZCBzcGVjaWZ5IHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHZhbHVlIGZvciBvZiB0aGUgZXJyb3IgYmFyLCB0aGUgd2lkdGggY29tbWFuZCBpcyB1c2VkIHRvIHNldCB0aGUgd2lkdGggb2YgdGhlIGVycm9yIGJhciBzbWFsbGVyIHRoYW4gdGhlIHdpZHRoIG9mIHRoZSBiYXIuCgpgYGB7cn0KYXBSZWxTdW0gJT4lCiAgZ2dwbG90KGFlcyh4ID0gdHJ0LCB5ID0gbWVhbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBtZWFuIC0gc2UsIHltYXggPSBtZWFuICsgc2UpLCB3aWR0aCA9IC4yKQpgYGAKCi0gSXMgdGhpcyBwbG90IGluZm9ybWF0aXZlPz8KCi0tLQoKIyMjIyBib3hwbG90cwoKSSBjb25zaWRlciBiYXJwbG90cyB0byBiZSBiYWQgcGxvdHMKCi0gVGhleSBhcmUgbm90IGluZm9ybWF0aXZlCi0gVGhleSBqdXN0IHZpc3VhbGl6ZSBhIHR3byBwb2ludCBzdW1tYXJ5IG9mIHRoZSBkYXRhLiBJdCBpcyBiZXR0ZXIgdG8gZG8gdGhpcyBpbiBhIHRhYmxlCi0gVGhleSB1c2UgYSBsb3Qgb2Ygc3BhY2UgKGUuZy4gZnJvbSB6ZXJvIHVwIHRvIHRoZSBtaW5pbXVtIHJlbGF0aXZlIGFidW5kYW5jZSkgd2hlcmUgbm8gZGF0YSBhcmUgcHJlc2VudC4KCkl0IGlzIGJldHRlciB0byBnZXQgYSB2aWV3IG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGRhdGEuIFdlIGNhbiB1c2UgYSBib3hwbG90IGZvciB0aGlzIHB1cnBvc2UuCldlIGZpcnN0IGV4cGxhaW4gd2hhdCBhIGJveHBsb3QuCgotLS0KCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpmZW0gPC0gTkhBTkVTOjpOSEFORVMgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiZmVtYWxlIiAmICFpcy5uYShEaXJlY3RDaG9sKSkgJT4lCiAgc2VsZWN0KERpcmVjdENob2wpCmJveHBsb3QoZmVtJERpcmVjdENob2wsIHlsYWIgPSAiRGlyZWN0IGNob2xlc3Rlcm9sIiwgY2V4LmxhYiA9IDEuNSwgY2V4LmF4aXMgPSAxLjUsIGNleC5tYWluID0gMS41KQpyYW5nZUNsIDwtIHF1YW50aWxlKGZlbSREaXJlY3RDaG9sLCBjKC4yNSwgLjc1KSkgKyBjKC0xLCAxKSAqIGRpZmYocXVhbnRpbGUoZmVtJERpcmVjdENob2wsIGMoLjI1LCAuNzUpKSkgKiAxLjUKYm94WXMgPC0gYyhyYW5nZShmZW0kRGlyZWN0Q2hvbFtmZW0kRGlyZWN0Q2hvbCA8PSByYW5nZUNsWzJdICYgZmVtJERpcmVjdENob2wgPj0gcmFuZ2VDbFsxXV0pLCBxdWFudGlsZShmZW0kRGlyZWN0Q2hvbCwgYyguMjUsIC41LCAuNzUpKSwgcmFuZ2VDbFsyXSArIChtYXgoZmVtJERpcmVjdENob2wpIC0gcmFuZ2VDbFsyXSkgLyAyKQp0ZXh0KDEuMywgYm94WXMsIGxhYmVscyA9IGMoIndpc2tlciIsICJ3aXNrZXIiLCAieDI1IiwgIm1lZGlhbiIsICJ4NzUiLCAib3V0bGllcnMiKSwgcG9zID0gNCwgY2V4ID0gMS4zKQpsaW5lcyhjKDEuMSwgMS4zLCAxLjMsIDEuMSksIGMocmFuZ2VDbFsyXSwgcmFuZ2VDbFsyXSArIChtYXgoZmVtJERpcmVjdENob2wpIC0gcmFuZ2VDbFsyXSkgLyAyLCByYW5nZUNsWzJdICsgKG1heChmZW0kRGlyZWN0Q2hvbCkgLSByYW5nZUNsWzJdKSAvIDIsIG1heChmZW0kRGlyZWN0Q2hvbCkpLCBsdHkgPSAyKQpgYGAKCi0tLQoKV2Ugd2lsbCBub3cgbWFrZSBhIGJveHBsb3QgZm9yIHRoZSBhcCBkYXRhCgoxLiBXZSBwaXBlIHRoZSBgYXBgIGRhdGFmcmFtZSB0byB0aGUgZ2dwbG90IGNvbW1hbmQKMi4gV2Ugc2VsZWN0IHRoZSBkYXRhIHdpdGggdGhlIGNvbW1hbmQgYGdncGxvdChhZXMoeD10cnQseT1yZWwpKWAKMy4gV2UgYWRkIGEgYm94cGxvdCB3aXRoIHRoZSBjb21tYW5kIGBnZW9tX2JveHBsb3QoKWAKCmBgYHtyfQphcCAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0cnQsIHkgPSByZWwpKSArCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgotLS0KCi0gTm90ZSwgdGhhdCB3ZSBkbyBub3QgaGF2ZSBzbyBtYW55IG9ic2VydmF0aW9ucy4KCi0gSXQgaXMgYWx3YXlzIGJldHRlciB0byBzaG93IHRoZSBkYXRhIGFzIHJhdyBhcyBwb3NzaWJsZSEKCldlIHdpbGwgbm93IGFkZCB0aGUgcmF3IGRhdGEgdG8gdGhlIHBsb3QuCgotIE5vdGUgdGhhdCB3ZSBzZXQgdGhlIG91dGxpZXIuc2hhcGU9TkEgaW4gdGhlIGdlb21fYm94cGxvdCBmdW5jdGlvbiBiZWNhdXNlIGJlY2F1c2Ugd2Ugd2lsbCBhZGQgYWxsIHJhdyBkYXRhIGFueXdheS4KLSBXZSBhZGQgdGhlIHJhdyBkYXRhIHVzaW5nIGBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKWAsIHdpdGggdGhlIGFyZ3VtZW50IHBvc2l0aW9uPSdqaXR0ZXInIHdlIHdpbGwgYWRkIHNvbWUgcmFuZG9tIG5vaXNlIHRvIHRoZSB4IGNvb3JkaW5hdGUgc28gdGhhdCB3ZSBjYW4gc2VlIGFsbCBkYXRhLgoKYGBge3J9CmFwICU+JQogIGdncGxvdChhZXMoeCA9IHRydCwgeSA9IHJlbCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9ICJqaXR0ZXIiKQpgYGAKClRoaXMgaXMgYW4gaW5mb3JtYXRpdmUgcGxvdCEKCi0tLQoKLSBXZSBvYnNlcnZlZCBhbiBlZmZlY3Qgb2YgdGhlIHRyYW5zcGxhbnRhdGlvbiBvbiB0aGUgcmVsYXRpZXZlIGFidW5kYW50aWUgb2YgU3RhcGh5bG9jb2NjdXMuCgotIElzIHRoYXQgZWZmZWN0IGxhcmdlIGVub3VnaCB0byBjb25jbHVkZSB0aGF0IHRoZSB0cmVhdG1lbnQgd29ya3M/CgotLS0KCiMjIEVzdGltYXRpb24gYW5kIHN0YXRpc3RpY2FsIGluZmVyZW5jZQoKLSBJbmR1Y3Rpb246IFdpdGggc3RhdGlzdGljYWwgaW5mZXJlbmNlIHdlIGNhbiBnZW5lcmFsaXplIHdoYXQgd2Ugb2JzZXJ2ZSBpbiB0aGUgc2FtcGxlIHRvd2FyZHMgdGhlIHBvcHVsYXRpb24uCgotIFRoZSBwcmljZSB0aGF0IHdlIGhhdmUgdG8gcGF5OiB1bmNlcnRhaW50eSBvbiBvdXIgY29uY2x1c2lvbnMhCgotLS0KCi0gV2l0aCBkYXRhIHdlIGNhbm5vdCBwcm92ZSB0aGF0IHRoZSB0cmVhdG1lbnQgd29ya3MKCi0gRmFsc2lmaWNhdGlvbiBwcmluY2lwbGUgb2YgUG9wcGVyOiBXaXRoIGRhdGEgd2UgY2FuIG9ubHkgIHJlamVjdCBhIGh5cG90aGVzaXMgb3IgdGhlb3J5LgoKLSBXaXRoIHN0YXRzIHdlIGNhbiB0aHVzIG5vdCBwcm92ZSB0aGF0IHRoZSB0cmVhdG1lbnQgd29ya3MuCgotIEJ1dCBzdGF0cyB3aWxsIGFsbG93IHVzIHRvIGZhbGNpZnkgdGhlIG9wcG9zaXRlIGh5cG90aGVzaXM6IGhvdyBtdWNoIGV2aWRlbmNlIGlzIHRoZXJlIGluIHRoZSBkYXRhIGFnYWluc3QgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGVyZSBpcyBubyBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudD8KCi0gV2l0aCBzdGF0cyB3ZSBjYW4gY2FsY3VsYXRlIGhvdyBsaWtlbHkgaXQgaXMgdG8gZHJhdyBhIHJhbmRvbSBzYW1wbGUgKHdoZW4geW91IHdvdWxkIHJlcGVhdCB0aGUgZXhwZXJpbWVudCkgd2l0aCBhIG1lYW4gZGlmZmVyZW5jZSBpbiByZWxhdGl2ZSBhYnVuZGFuY2UgYmV0d2VlbiB0cmFuc3BsYW50IGFuZCBwbGFjZWJvIGdyb3VwIHRoYXQgaXMgYXQgbGVhc3QgYXMgbGFyZ2UgYXMgd2hhdCB3ZSBvYnNlcnZlZCBpbiBvdXIgc2FtcGxlIHdoZW4gdGhlcmUgd291bGQgYmUgbm8gZWZmZWN0IG9mIHRoZSB0cmVhdG1lbnQuCgotIFRoaXMgcHJvYmFiaWxpdHkgaXMgY2FsbGVkIGEgcC12YWx1ZS4KCi0gSWYgcCBpcyB2ZXJ5IHNtYWxsLCBpdCBpcyB2ZXJ5IHVubGlrZWx5IHRvIG9ic2VydmUgYSBzYW1wbGUgbGlrZSBvdXJzIGJ5IHJhbmRvbSBjaGFuZ2Ugd2hlbiB0aGVyZSB3b3VsZCBiZSBubyBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudC4KCi0gV2UgdHlwaWNhbGx5IGNvbXBhcmUgcCB3aXRoIDUlLiBJZiB0aGVyZSBpcyBubyBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudCB3ZSB3aWxsIHRodXMgdG9sZXJhdGUgYSBwcm9iYWJpbGl0eSBvZiA1JSBvbiBhIGZhbHNlIHBvc2l0aXZlIGNvbmNsdXNpb24uCgotIFRvIGNhbGN1bGF0ZSBwIHdlIHdpbGwgaGF2ZSB0byBtb2RlbCB0aGUgZGF0YSB1c2luZyAgc3RhdGlzdGljYWwgbW9kZWxzLgoKLS0tCgpJbiBjaGFwdGVyIDUgd2Ugd2lsbCBsZWFybiB0aGF0IHdlIGNhbiB1c2UgYSB0d28tc2FtcGxlIHQtdGVzdCB0byBnZW5lcmFsaXNlIHdoYXQgd2Ugb2JzZXJ2ZSBpbiB0aGUgbWljcm9iaW9tZSBkYXRhc2V0IHRvd2FyZHMgdGhlIHBvcHVsYXRpb24uCgpgYGB7cn0KdC50ZXN0KHJlbCB+IHRydCwgZGF0YSA9IGFwKQpgYGAKCkNvbmNsdXNpb246CgpXZSBjYW4gY29uY2x1ZGUgdGhhdCB0aGUgcmVsYXRpdmUgYWJ1bmRhbmNlIG9mIFN0YXBoeWxvY29jY3VzIGluIHRoZSBtaWNyb2Jpb21lIG9mIGluZGl2aWR1YWxzIHdpdGggc21lbGx5IGFybXBpdHMgIGlzIGByIGZvcm1hdChhcFJlbFN1bSRtZWFuWzJdLWFwUmVsU3VtJG1lYW5bMV0sZGlnaXRzPTMpYCUgaGlnaGVyIHVwb24gdGhlIHRyYW5zcGxhbnQgdGhhbiB1cG9uIHRoZSBwbGFjZWJvIHRyZWF0bWVudCAocCA8IDAuMDAxKS4KCi0tLQoKIyMgU29tZSBjb25jZXB0cwoKV2hhdCBhcmUgdGhlIGNvbnNlcXVlbmNlcyBvZiB1c2luZyBhIHNhbXBsZSBhbmQgcmFuZG9taXNhdGlvbj8KCi0gUmFuZG9tIHNhbXBsaW5nIGlzIGNsb3NlbHkgcmVsYXRlZCB0byB0aGUgY29uY2VwdCBvZiB0aGUgcG9wdWxhdGlvbiBvciB0aGUgc2NvcGUgb2YgdGhlIHN0dWR5LgoKLSBCYXNlZCBvbiBhIHNhbXBsZSBvZiBzdWJqZWN0cywgdGhlIHJlc2VhcmNoZXJzIHdhbnQgdG8gY29tZSB0byBjb25jbHVzaW9ucyB0aGF0IGhvbGQgZm9yCgogICAgLSBhbGwga2luZHMgb2YgcGVvcGxlCiAgICAtIG9ubHkgbWFsZSBzdHVkZW50cwoKLSBTY29wZSBvZiB0aGUgc3R1ZHkgc2hvdWxkIGJlIHdlbGwgc3BlY2lmaWVkIGJlZm9yZSB0aGUgc3RhcnQgb2YgdGhlIHN0dWR5LgoKLSBGb3IgdGhlIHN0YXRpc3RpY2FsIGFuYWx5c2lzIHRvIGJlIHZhbGlkLCBpdCBpcyByZXF1aXJlZCB0aGF0IHRoZSBzdWJqZWN0cyBhcmUgc2VsZWN0ZWQgY29tcGxldGVseSBhdCByYW5kb20gZnJvbSB0aGUgcG9wdWxhdGlvbiB0byB3aGljaCB3ZSB3YW50IHRvIGdlbmVyYWxpemUgb3VyIGNvbmNsdXNpb25zLgoKLSBTZWxlY3RpbmcgY29tcGxldGVseSBhdCByYW5kb20gZnJvbSBhIHBvcHVsYXRpb24gaW1wbGllczoKICAgIC0gYWxsIHN1YmplY3RzIGluIHRoZSBwb3B1bGF0aW9uIHNob3VsZCBoYXZlIHRoZSBzYW1lIHByb2JhYmlsaXR5IG9mIGJlaW5nIHNlbGVjdGVkIGluIHRoZSBzYW1wbGUsCiAgICAtIHRoZSBzZWxlY3Rpb24gb2YgYSBzdWJqZWN0IGluIHRoZSBzYW1wbGUgc2hvdWxkIGJlIGluZGVwZW5kZW50IGZyb20gdGhlIHNlbGVjdGlvbiBvZiB0aGUgb3RoZXIgc3ViamVjdHMgaW4gdGhlIHNhbXBsZS4KCi0gVGhlIHNhbXBsZSBpcyB0aHVzIHN1cHBvc2VkIHRvIGJlIHJlcHJlc2VudGF0aXZlIGZvciB0aGUgcG9wdWxhdGlvbiwgYnV0IHN0aWxsIGl0IGlzIHJhbmRvbS4KCi0gV2hhdCBkb2VzIHRoaXMgaW1wbHk/CgotLS0KCiMgU2FtcGxlIHRvIHNhbXBsZSB2YXJpYWJpbGl0eQoKTmF0aW9uYWwgSGVhbHRoIE5IYW5lcyBzdHVkeQoKICAtIFNpbmNlIDE5NjAgaW5kaXZpZHVhbHMgb2YgYWxsIGFnZXMgYXJlIGludGVydmlld2VkIGluIHRoZWlyIGhvbWVzIGV2ZXJ5IHllYXIKICAtIFRoZSBoZWFsdGggZXhhbWluYXRpb24gY29tcG9uZW50IG9mIHRoZSBzdXJ2ZXkgaXMgY29uZHVjdGVkIGluIGEgbW9iaWxlIGV4YW1pbmF0aW9uIGNlbnRyZSAoTUVDKS4KICAtIFdlIHdpbGwgdXNlIHRoaXMgbGFyZ2Ugc3R1ZHkgdG8gc2VsZWN0IHJhbmRvbSBzdWJqZWN0cyBmcm9tIHRoZSBBbWVyaWNhbiBwb3B1bGF0aW9uLgogIC0gVGhpcyB3aWxsIGhlbHAgdXMgdG8gdW5kZXJzdGFuZCBob3cgdGhlIHJlc3VsdHMgb2YgYW4gYW5hbHlzaXMgYW5kIHRoZSBjb25jbHVzaW9ucyB2YXJ5IGZyb20gc2FtcGxlIHRvIHNhbXBsZS4KCi0tLQoKYGBge3J9CmxpYnJhcnkoTkhBTkVTKQpoZWFkKE5IQU5FUykKZ2xpbXBzZShOSEFORVMpCmBgYAoKLS0tCgojIyBEYXRhIGV4cGxvcmF0aW9uCgoKU3VwcG9zZSB0aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluIGFzc2Vzc2luZyB0aGUgZGlmZmVyZW5jZSBpbiBkaXJlY3QgY2hvbGVzdGVyb2wgbGV2ZWxzIGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXMgb2xkZXIgdGhhbiAyNSB5ZWFycy4KCjEuIFdlIHBpcGUgdGhlIGRhdGFzZXQgdG8gdGhlIGZ1bmN0aW9uIGBmaWx0ZXJgIHRvIGZpbHRlciB0aGUgZGF0YSBhY2NvcmRpbmcgdG8gYWdlLgoyLiBXZSBwbG90IHRoZSBkaXJlY3QgY2hvbGVzdGVyb2wgbGV2ZWxzLgogICAgLSBXZSBzZWxlY3QgdGhlIGRhdGEgd2l0aCB0aGUgY29tbWFuZCBgZ2dwbG90KGFlcyh4PURpcmVjdENob2wpKWAKICAgIC0gV2UgYWRkIGEgaGlzdG9ncmFtIHdpdGggdGhlIGNvbW1hbmQgYGdlb21faGlzdG9ncmFtKClgCiAgICAtIFdlIG1ha2UgdG8gdmVydGljYWwgcGFuZWxzIHVzaW5nIHRoZSBjb21tYW5kIGBmYWNldF9ncmlkKEdlbmRlcn4uKWAKICAgIC0gV2UgY3VzdG9taXplIHRoZSBsYWJlbCBvZiB0aGUgeC1heGlzIHdpdGggdGhlIGB4bGFiYCBjb21tYW5kLgoKYGBge3J9Ck5IQU5FUyAlPiUKICBmaWx0ZXIoQWdlID4gMjUpICU+JQogIGdncGxvdChhZXMoeCA9IERpcmVjdENob2wpKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZmFjZXRfZ3JpZChHZW5kZXIgfiAuKSArCiAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIChtZy9kbCkiKQpgYGAKCi0tLQoKLSBDaG9sZXN0ZXJvbCBsZXZlbHMgYW5kIGNvbmNlbnRyYXRpb24gbWVhc3VyZW1lbnRzIGFyZSBvZnRlbiBza2V3ZWQuCi0gQ29uY2VudHJhdGlvbnMgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4KLSBUaGV5IGFyZSBvZnRlbiBsb2cgdHJhbnNmb3JtZWQuCgpgYGB7cn0KTkhBTkVTICU+JQogIGZpbHRlcihBZ2UgPiAyNSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGlyZWN0Q2hvbCAlPiUgbG9nMigpKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGZhY2V0X2dyaWQoR2VuZGVyIH4gLikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKQpgYGAKCldlIHNlZSB0aGF0IHRoZSBkYXRhIGFyZSBtb3JlIG9yIGxlc3MgYmVsbCBzaGFwZWQgdXBvbiBsb2cgdHJhbnNmb3JtYXRpb24uCgotLS0KCldlIHdpbGwgbm93IGNyZWF0ZSBhIHN1YnNldCBvZiB0aGUgZGF0YSB0aGF0IHdlIHdpbGwgdXNlIHRvIHNhbXBsZSBmcm9tIGluIHRoZSBuZXh0IHNlY3Rpb25zLgoKICAxLiBXZSBmaWx0ZXIgb24gYWdlIGFuZCByZW1vdmUgc3ViamVjdHMgd2l0aCBtaXNzaW5nIHZhbHVlcyAoTkEpLgogIDIuIFdlIG9ubHkgc2VsZWN0IHRoZSB2YXJpYWJsZXMgR2VuZGVyIGFuZCBEaXJlY3RDaG9sIGZyb20gdGhlIGRhdGFzZXQgdG8gYXZvaWQgdW5uZWNlc3NhcnkgdmFyaWFibGVzLgogIDMuIFdpdGggdGhlIG11dGF0ZSBmdW5jdGlvbiB3ZSBjYW4gYWRkIGEgbmV3IHZhcmlhYmxlIGxvZ0Nob2wgd2l0aCBsb2cgdHJhbnNmb3JtZWQgZGlyZWN0IGNob2xlc3Rlcm9sIGxldmVscy4KCmBgYHtyfQpuaGFuZXNTdWIgPC0gTkhBTkVTICU+JQogIGZpbHRlcihBZ2UgPiAyNSAmICFpcy5uYShEaXJlY3RDaG9sKSkgJT4lCiAgc2VsZWN0KGMoIkdlbmRlciIsICJEaXJlY3RDaG9sIikpICU+JQogIG11dGF0ZShjaG9sTG9nID0gbG9nMihEaXJlY3RDaG9sKSkKYGBgCgotLS0KCldlIHdpbGwgY2FsY3VsYXRlIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSBjaG9sTG9nIHZhcmlhYmxlIGZvciBtYWxlcyBhbmQgZmVtYWxlcyBpbiB0aGUgbGFyZ2UgZGF0YXNldC4KU28gd2UgZ3JvdXAgYnkgR2VuZGVyCgpgYGB7cn0KY2hvbExvZ1N1bSA8LSBuaGFuZXNTdWIgJT4lCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBzdW1tYXJpemUoCiAgICBtZWFuID0gbWVhbihjaG9sTG9nLCBuYS5ybSA9IFRSVUUpLAogICAgc2QgPSBzZChjaG9sTG9nLCBuYS5ybSA9IFRSVUUpLAogICAgbiA9IG4oKQogICkgJT4lCiAgbXV0YXRlKHNlID0gc2QgLyBzcXJ0KG4pKQoKY2hvbExvZ1N1bQpgYGAKCi0tLQoKIyMgRXhwZXJpbWVudAoKLSBTdXBwb3NlIHRoYXQgd2UgaGF2ZSBubyBhY2Nlc3MgdG8gY2hvbGVzdGVyb2wgbGV2ZWxzIG9mIHRoZSBBbWVyaWNhbiBwb3B1bGF0aW9uLAotIHdlIHdpbGwgaGF2ZSB0byBzZXR1cCBhbiBleHBlcmltZW50LgotIFN1cHBvc2Ugd2UgaGF2ZSBhIGJ1ZGdldCBmb3IgYXNzZXNzaW5nIDEwIGZlbWFsZXMgYW5kIDEwIG1hbGVzLAotIHdlIHdpbGwgc3Vic2V0IDEwIGZlbWFsZXMgYW5kIDEwIG1hbGVzIGF0IHJhbmRvbSBmcm9tIHRoZSBBbWVyaWNhbiBwb3B1bGF0aW9uIGFuZCBtZWFzdXJlIHRoZWlyIGRpcmVjdCBjaG9sZXN0ZXJvbCBsZXZlbHMuCgpgYGB7cn0KZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplID0gMTApCm1hbCA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAibWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemUgPSAxMCkKCnNhbXAgPC0gcmJpbmQoZmVtLCBtYWwpCnNhbXAKYGBgCgotLS0KCldlIHdpbGwgbm93IHBsb3QgdGhlIGRhdGEgd2l0aCBhIGhpc3RvZ3JhbSBhbmQgYm94cGxvdHMKCmBgYHtyfQpzYW1wICU+JQogIGdncGxvdChhZXMoeCA9IGNob2xMb2cpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAuMSkgKwogIGZhY2V0X2dyaWQoR2VuZGVyIH4gLikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKQoKc2FtcCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBHZW5kZXIsIHkgPSBjaG9sTG9nKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIpCmBgYAoKLS0tCgpXZSBzdW1tYXJpemUgdGhlIGRhdGEKYGBge3J9CnNhbXAgJT4lCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBzdW1tYXJpemUoCiAgICBtZWFuID0gbWVhbihjaG9sTG9nLCBuYS5ybSA9IFRSVUUpLAogICAgc2QgPSBzZChjaG9sTG9nLCBuYS5ybSA9IFRSVUUpLAogICAgbiA9IG4oKQogICkgJT4lCiAgbXV0YXRlKHNlID0gc2QgLyBzcXJ0KG4pKQpgYGAKCk5vdGUgdGhhdCB0aGUgc2FtcGxlIG1lYW4gaXMgZGlmZmVyZW50IGZyb20gdGhhdCBvZiB0aGUgbGFyZ2UgZXhwZXJpbWVudCAoInBvcHVsYXRpb24iKSB3ZSBzYW1wbGVkIGZyb20uCgpXZSB0ZXN0IGZvciB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIE1hbGVzIGFuZCBmZW1hbGVzCgpgYGB7cn0KdC50ZXN0KGNob2xMb2cgfiBHZW5kZXIsIHNhbXAsIHZhci5lcXVhbCA9IFRSVUUpCmBgYAoKLS0tCgojIyBSZXBlYXQgdGhlIGV4cGVyaW1lbnQKCklmIHdlIGRvIHRoZSBleHBlcmltZW50IGFnYWluIHdlIHNlbGVjdCBvdGhlciBwZW9wbGUgYW5kIHdlIG9idGFpbiBkaWZmZXJlbnQgcmVzdWx0cy4KCgpgYGB7cn0KZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplID0gMTApCm1hbCA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAibWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemUgPSAxMCkKCnNhbXAyIDwtIHJiaW5kKGZlbSwgbWFsKQpzYW1wMiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBEaXJlY3RDaG9sICU+JSBsb2coKSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IC4xKSArCiAgZmFjZXRfZ3JpZChHZW5kZXIgfiAuKSArCiAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIChsb2cpIikKCnNhbXAyICU+JQogIGdncGxvdChhZXMoeCA9IEdlbmRlciwgeSA9IGNob2xMb2cpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikKCnNhbXAyICU+JQogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgc3VtbWFyaXplKAogICAgbWVhbiA9IG1lYW4oY2hvbExvZywgbmEucm0gPSBUUlVFKSwKICAgIHNkID0gc2QoY2hvbExvZywgbmEucm0gPSBUUlVFKSwKICAgIG4gPSBuKCkKICApICU+JQogIG11dGF0ZShzZSA9IHNkIC8gc3FydChuKSkKCnQudGVzdChjaG9sTG9nIH4gR2VuZGVyLCBzYW1wMiwgdmFyLmVxdWFsID0gVFJVRSkKYGBgCgotLS0KCiMjIEFuZCBhZ2FpbgoKYGBge3J9CnNldC5zZWVkKDEyODU3KQpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemUgPSAxMCkKbWFsIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZSA9IDEwKQoKc2FtcDMgPC0gcmJpbmQoZmVtLCBtYWwpCnNhbXAzICU+JQogIGdncGxvdChhZXMoeCA9IERpcmVjdENob2wgJT4lIGxvZygpKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjEpICsKICBmYWNldF9ncmlkKEdlbmRlciB+IC4pICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKGxvZykiKQoKc2FtcDMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gR2VuZGVyLCB5ID0gY2hvbExvZykpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9ICJqaXR0ZXIiKQoKCnNhbXAzICU+JQogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgc3VtbWFyaXplKAogICAgbWVhbiA9IG1lYW4oY2hvbExvZywgbmEucm0gPSBUUlVFKSwKICAgIHNkID0gc2QoY2hvbExvZywgbmEucm0gPSBUUlVFKSwKICAgIG4gPSBuKCkKICApICU+JQogIG11dGF0ZShzZSA9IHNkIC8gc3FydChuKSkKCnQudGVzdChjaG9sTG9nIH4gR2VuZGVyLCBzYW1wMywgdmFyLmVxdWFsID0gVFJVRSkKYGBgCgotLS0KCiMjIFN1bW1hcnkKCi0gQmVjYXVzZSB3ZSBzYW1wbGVkIG90aGVyIHN1YmplY3RzIGluIGVhY2ggc2FtcGxlLCB3ZSBvYnRhaW4gZGlmZmVyZW50IGNob2xlc3Rlcm9sIGxldmVscy4KLSBIb3dldmVyLCBub3Qgb25seSB0aGUgY2hvbGVzdGVyb2wgbGV2ZWxzIGRpZmZlciBmcm9tIHNhbXBsZSB0byBzYW1wbGUgYnV0IGFsc28gdGhlIHN1bW1hcnkgc3RhdGlzdGljczogbWVhbnMsIHN0YW5kYXJkIGRldmlhdGlvbnMgYW5kIHN0YW5kYXJkIGVycm9ycy4KLSBOb3RlLCB0aGF0IGluIHRoZSBsYXN0IHNhbXBsZSB0aGUgbG9nIGNob2xlc3Rlcm9sIGxldmVscyBhcmUgb24gYXZlcmFnZSBsb3dlciBmb3IgZmVtYWxlcyB0aGFuIGZvciBtYWxlczsgYmFzZWQgb24gdGhpcyBzYW1wbGUgd2UgZXZlbiB3b3VsZCB3cm9uZ2x5IGNvbmNsdWRlIHRoYXQgdGhlIGNob2xlc3Rlcm9sIGxldmVscyBmb3IgZmVtYWxlcyBhcmUgb24gYXZlcmFnZSBsYXJnZXIgdGhhbiB0aG9zZSBvZiBtYWxlcy4KCi0gVGhpcyBpbXBsaWVzIHRoYXQgb3VyIGNvbmNsdXNpb25zIGFyZSBhbHNvIHN1YmplY3RlZCB0byB1bmNlcnRhaW50eSBhbmQgbWlnaHQgY2hhbmdlIGZyb20gc2FtcGxlIHRvIHNhbXBsZS4KCi0gU2FtcGxlcyBhcyB0aGUgb25lIHdoZXJlIHRoZSBlZmZlY3Qgc3dhcHMgYW5kIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIGhvd2V2ZXIsIGFyZSB2ZXJ5IHJhcmUuCi0gVGhpcyBpcyBpbGx1c3RyYXRlZCB3aXRoIHRoZSBjb2RlIGJlbG93LCB3aGVyZSB3ZSB3aWxsIGRyYXcgMjAwMDAgcmVwZWF0ZWQgc2FtcGxlcyB3aXRoIHNhbXBsZSBzaXplIDEwIGZvciBmZW1hbGVzIGFuZCBtYWxlcyBmcm9tIHRoZSBOSGFuZXMgc3R1ZHkuCgpgYGB7cn0KbnNpbSA8LSAyMDAwMApuU2FtcCA8LSAxMApyZXMgPC0gbWF0cml4KDAsIG5yb3cgPSBuc2ltLCBuY29sID0gMikKZmVtIDwtIG5oYW5lc1N1YiAlPiUgZmlsdGVyKEdlbmRlciA9PSAiZmVtYWxlIikKbWFsIDwtIG5oYW5lc1N1YiAlPiUgZmlsdGVyKEdlbmRlciA9PSAibWFsZSIpCgpmb3IgKGkgaW4gMTpuc2ltKQp7CiAgZmVtU2FtcCA8LSBzYW1wbGUoZmVtJGNob2xMb2csIG5TYW1wKQogIG1hbFNhbXAgPC0gc2FtcGxlKG1hbCRjaG9sTG9nLCBuU2FtcCkKCiAgbWVhbkZlbSA8LSBtZWFuKGZlbVNhbXApCiAgbWVhbk1hbCA8LSBtZWFuKG1hbFNhbXApCiAgZGVsdGEgPC0gbWVhbkZlbSAtIG1lYW5NYWwKICBzZEZlbSA8LSBzZChmZW1TYW1wKQogIHNkTWFsIDwtIHNkKG1hbFNhbXApCiAgc2VGZW0gPC0gc2RGZW0gLyBzcXJ0KG5TYW1wKQogIHNlRmVtIDwtIHNkRmVtIC8gc3FydChuU2FtcCkKICBzZFBvb2wgPC0gc3FydCgoc2RGZW1eMiAqIChuU2FtcCAtIDEpICsgc2RNYWxeMiAqIChuU2FtcCAtIDEpKSAvICgyICogblNhbXAgLSAyKSkKICB0dmFsdWUgPC0gKGRlbHRhKSAvIChzZFBvb2wgKiBzcXJ0KDEgLyBuU2FtcCArIDEgLyBuU2FtcCkpCiAgcHZhbHVlIDwtIHB0KGFicyh0dmFsdWUpLCBsb3dlci50YWlsID0gRkFMU0UsIGRmID0gMiAqIG5TYW1wIC0gMikgKiAyCiAgcmVzW2ksIF0gPC0gYyhkZWx0YSwgcHZhbHVlKQp9CnN1bShyZXNbLCAyXSA8IDAuMDUgJiByZXNbLCAxXSA+IDApCnN1bShyZXNbLCAyXSA+IDAuMDUpCnN1bShyZXNbLCAyXSA8IDAuMDUgJiByZXNbLCAxXSA8IDApCgpyZXMgPC0gcmVzICU+JSBhcy5kYXRhLmZyYW1lKCkKbmFtZXMocmVzKSA8LSBjKCJkZWx0YSIsICJwdmFsdWUiKQpyZXMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGVsdGEsIHkgPSAtbG9nMTAocHZhbHVlKSwgY29sb3IgPSBwdmFsdWUgPCAwLjA1KSkgKwogIGdlb21fcG9pbnQoKSArCiAgeGxhYigiQXZlcmFnZSBjaG9sZXN0ZXJvbCBkaWZmZXJlbmNlIikgKwogIHlsYWIoIi0gbG9nMTAocHZhbHVlKSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCAicmVkIikpCgpyZXMgJT4lCiAgZ2dwbG90KGFlcyh5ID0gZGVsdGEpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHggPSAwLCB5ID0gYyhtZWFuKGZlbSRjaG9sTG9nKSAtIG1lYW4obWFsJGNob2xMb2cpKSwgY29sb3IgPSAicG9wLiBkaWZmIikpICsKICB4bGFiKCIiKQpgYGAKCk9ubHkgaW4gYHIgc3VtKHJlc1ssMl08MC4wNSZyZXNbLDFdPDApYCBvdXQgb2YgMjAwMDAgc2FtcGxlcyB3ZSBjb25jbHVkZSB0aGF0IHRoZSBtZWFuIGNob2xlc3Rlcm9sIGxldmVsIG9mIG1hbGVzIGlzIHNpZ25pZmljYW50bHkgbG93ZXIgdGhhbiBmb3IgZmVtYWxlcy4gRm9yIHRoZSByZW1haW5pbmcgc2FtcGxlcyB0aGUgY2hvbGVzdGVyb2wgbGV2ZWxzIGZvciBtYWxlcyB3ZXJlIG9uIGF2ZXJhZ2Ugc2lnbmlmaWNhbnRseSBsb3dlciB0aGFuIGZvciBmZW1hbGVzIChgciBzdW0ocmVzWywyXTwwLjA1JnJlc1ssMV0+MClgIHNhbXBsZXMpIG9yIHRoZSBhdmVyYWdlIGRpZmZlcmVuY2UgaW4gY2hvbGVzdGVyb2wgbGV2ZWxzIHdlcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKGByIHN1bShyZXNbLDJdPjAuMDUpYCBzYW1wbGVzKS4gVGhlIGxhdHRlciBpcyBiZWNhdXNlIHRoZSBwb3dlciBpcyByYXRoZXIgbG93IHRvIGRldGVjdCB0aGUgZGlmZmVyZW5jZSB3aXRoIDEwIHNhbXBsZXMgaW4gZWFjaCBncm91cC4KCi0tLQoKIyMgQXNzaWdubWVudAoKMS4gQ29weSB0aGUgY29kZSBjaHVuayB3aXRoIHRoZSBzaW11bGF0aW9uIHN0dWR5CjIuIEFkZCBpdCBoZXJlIGJlbG93CjMuIE1vZGlmeSB0aGUgc2FtcGxlIHNpemUgdG8gNTAuCjQuIFdoYXQgZG8geW91IG9ic2VydmU/CgoKLS0tCgojIyBDb250cm9sIG9mIGZhbHNlIHBvc2l0aXZlcwoKV2F0IGhhcHBlbnMgd2hlbiB0aGVyZSBpcyBubyBkaWZmZXJlbmNlIGJldHdlZW4gYm90aCBncm91cHM/CgotIFdlIHdpbGwgaGF2ZSB0byBzaW11bGF0ZSBleHBlcmltZW50cyBmb3Igd2hpY2ggdGhlIGNob2xlc3Rvcm9sIGxldmVscyBhcmUgdGhlIHNhbWUgZm9yIGJvdGggZ3JvdXBzLgoKCi0gV2UgY2FuIGRvIHRoaXMgYnkgc2FtcGxpbmcgZGF0YSBmb3IgYm90aCBncm91cHMgZnJvbSB0aGUgc3Vic2V0IG9mIHdvbWVuIGluIHRoZSBzdHVkeS4KCi0gV2UgZG8gdGhpcyBhZ2FpbiBmb3IgMTAgc3ViamVjdHMgcGVyIGdyb3VwCgoKYGBge3J9Cm5zaW0gPC0gMjAwMDAKblNhbXAgPC0gMTAKcmVzIDwtIG1hdHJpeCgwLCBucm93ID0gbnNpbSwgbmNvbCA9IDIpCmZlbSA8LSBuaGFuZXNTdWIgJT4lIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIpCm1hbCA8LSBuaGFuZXNTdWIgJT4lIGZpbHRlcihHZW5kZXIgPT0gIm1hbGUiKQoKZm9yIChpIGluIDE6bnNpbSkKewogIGZlbVNhbXAgPC0gc2FtcGxlKGZlbSRjaG9sTG9nLCBuU2FtcCkKICBmZW0yU2FtcCA8LSBzYW1wbGUoZmVtJGNob2xMb2csIG5TYW1wKQoKICBtZWFuRmVtIDwtIG1lYW4oZmVtU2FtcCkKICBtZWFuRmVtMiA8LSBtZWFuKGZlbTJTYW1wKQogIGRlbHRhIDwtIG1lYW5GZW0gLSBtZWFuRmVtMgogIHNkRmVtIDwtIHNkKGZlbVNhbXApCiAgc2RGZW0yIDwtIHNkKGZlbTJTYW1wKQogIHNlRmVtIDwtIHNkRmVtIC8gc3FydChuU2FtcCkKICBzZUZlbSA8LSBzZEZlbTIgLyBzcXJ0KG5TYW1wKQogIHNkUG9vbCA8LSBzcXJ0KChzZEZlbV4yICogKG5TYW1wIC0gMSkgKyBzZEZlbTJeMiAqIChuU2FtcCAtIDEpKSAvICgyICogblNhbXAgLSAyKSkKICB0dmFsdWUgPC0gKGRlbHRhKSAvIChzZFBvb2wgKiBzcXJ0KDEgLyBuU2FtcCArIDEgLyBuU2FtcCkpCiAgcHZhbHVlIDwtIHB0KGFicyh0dmFsdWUpLCBsb3dlci50YWlsID0gRkFMU0UsIGRmID0gMiAqIG5TYW1wIC0gMikgKiAyCiAgcmVzW2ksIF0gPC0gYyhkZWx0YSwgcHZhbHVlKQp9CnN1bShyZXNbLCAyXSA8IDAuMDUgJiByZXNbLCAxXSA+IDApCnN1bShyZXNbLCAyXSA+PSAwLjA1KQpzdW0ocmVzWywgMl0gPCAwLjA1ICYgcmVzWywgMV0gPCAwKQoKcmVzIDwtIHJlcyAlPiUgYXMuZGF0YS5mcmFtZSgpCm5hbWVzKHJlcykgPC0gYygiZGVsdGEiLCAicHZhbHVlIikKcmVzICU+JQogIGdncGxvdChhZXMoeCA9IGRlbHRhLCB5ID0gLWxvZzEwKHB2YWx1ZSksIGNvbG9yID0gcHZhbHVlIDwgMC4wNSkpICsKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkF2ZXJhZ2UgY2hvbGVzdGVyb2wgZGlmZmVyZW5jZSIpICsKICB5bGFiKCItIGxvZzEwKHB2YWx1ZSkiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgInJlZCIpKQoKcmVzICU+JQogIGdncGxvdChhZXMoeSA9IGRlbHRhKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gMCwgeSA9IDAsIGNvbG9yID0gInBvcC4gZGlmZiIpKSArCiAgeGxhYigiIikKYGBgCgpOb3RlLCB0aGF0IHRoZSBudW1iZXIgb2YgZmFsc2UgcG9zaXRpdmVzIGFyZSBvbiBgciBzdW0ocmVzWywyXTwwLjA1KWAgb24gYHIgZm9ybWF0KG5zaW0sZGlnaXRzPTUpYCBleHBlcmltZW50cyBhbmQgYXJlIG5pY2VseSBjb250cm9sbGVkIGF0IHRoZSA1JSBsZXZlbC4KCldoYXQgaGFwcGVucyBpZiB3ZSBpbmNyZWFzZSB0aGUgc2FtcGxlIHNpemUgdG8gNTAgc3ViamVjdHMgcGVyIGdyb3VwPwoKCi0tLQoKIyBTYWxrIFN0dWR5CgotIEluIDE5MTYsIHRoZSBVUyBleHBlcmllbmNlZCB0aGUgZmlyc3QgbGFyZ2UgZXBpZGVtaWMgb2YgcG9saW8uCi0gSm9obiBTYWxrIGRldmVsb3BlZCBhIHZhY2NpbmUgd2l0aCBwcm9taXNpbmcgcmVzdWx0cyBpbiB0aGUgbGFiIGluIHRoZSBlYXJseSBmaWZ0aWVzLgotIEluIDE5NTQsIHRoZSBOYXRpb25hbCBGb3VuZGF0aW9uCmZvciBJbmZhbnRpbGUgUGFyYWx5c2lzIChORklQKSBoYXMgc2V0dXAgYSBsYXJnZSBzdHVkeSB0byBhc3Nlc3MgdGhlIGVmZmVjdGl2ZW5lc3Mgb2YgdGhlIFNhbGsgdmFjY2luZS4KLSBTdXBwb3NlIHRoYXQgdGhlIE5GSVAgd291bGQgaGF2ZSB2YWNjaW5hdGVkIGEgbGFyZ2UgbnVtYmVyIG9mIGNoaWxkcmVuIGluIDE5NTQgYW5kIHdvdWxkIGhhdmUgb2JzZXJ2ZWQgdGhhdCB0aGUgcG9saW8gaW5jaWRlbmNlIGluIDE5NTQgd2FzIGxvd2VyIHRoYW4gaW4gMTk1My4gQ291bGQgdGhleSBoYXZlIGNvbmNsdWRlZCB0aGF0IHRoZSB2YWNjaW5lIHdhcyBlZmZlY3RpdmU/CgotLS0KCiMjIE5GSVAgU3R1ZHkKCiMjIyBEZXNpZ24KCi0gTGFyZ2Ugc2ltdWx0YW5lb3VzIHN0dWR5IHdpdGggY2FzZXMsIHZhY2NpbmF0ZWQgY2hpbGRyZW4sIGFuZCBjb250cm9scywgIG5vbi12YWNjaW5hdGVkIGNoaWxkcmVuLgotIEFsbCBzY2hvb2xzIGluIGRpc3RyaWN0cyB3aXRoIGhpZ2ggcG9saW8gaW5jaWRlbmNlCi0gQ2FzZXM6IGNoaWxkcmVuIHdpdGggY29uc2VudCBmb3IgdmFjY2luYXRpb24gZnJvbSBzZWNvbmQgZ3JhZGUgb2YgcHJpbWFyeSBzY2hvb2wuCi0gQ29udHJvbHM6IGNoaWxkcmVuIGZyb20gIGZpcnN0IGFuZCB0aGlyZCBncmFkZS4KCiMjIyBEYXRhCgpgYGB7cn0KbmZpcCA8LSBkYXRhLmZyYW1lKGdyb3VwID0gYygiY2FzZXMiLCAiY29udHJvbCIsICJub0NvbmNlbnQiKSwgZ3JhZGUgPSBjKCJnMiIsICJnMWczIiwgImcyIiksIHZhY2NpbiA9IGMoInllcyIsICJubyIsICJubyIpLCB0b3RhbCA9IGMoMjIxOTk4LCA3MjUxNzMsIDEyMzYwNSksIHBvbGlvID0gYyg1NCwgMzkxLCA1NikpCm5maXAkbm9Qb2xpbyA8LSBuZmlwJHRvdGFsIC0gbmZpcCRwb2xpbwprbml0cjo6a2FibGUobmZpcCkKYGBgCgpDb21wYXJlIHBvbGlvIGluY2lkZW5jZT8KCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpuZmlwJGluY2lkZW5jZVBNIDwtIHJvdW5kKG5maXAkcG9saW8gLyBuZmlwJHRvdGFsICogMWU2LCAwKQprbml0cjo6a2FibGUobmZpcCkKYGBgCgpXaGF0IGNhbiB3ZSBjb25jbHVkZT8KCi0tLQoKIyMgQ29uZm91bmRpbmcKCmBgYHtyLGVjaG89RkFMU0UsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLG91dC53aWR0aCA9ICc1MCUnfQpwbG90KGMoMCwgMCwgMSksIGMoLTIsIDIsIDApLCBwY2ggPSBjKCJTIiwgIlYiLCAiUCIpLCB4YXh0ID0gIm5vbmUiLCB5YXh0ID0gIm5vbmUiLCBheGVzID0gRkFMU0UsIHhsYWIgPSAiIiwgeWxhYiA9ICIiLCBjZXggPSA0LCB5bGltID0gYygtMi4yLCAyLjIpKQphcnJvd3MoeDAgPSAwLjEsIHgxID0gLjksIHkwID0gMS44LCB5MSA9IDAuMSwgbHdkID0gNCkKYXJyb3dzKHgwID0gMC4xLCB4MSA9IC45LCB5MCA9IC0xLjgsIHkxID0gLTAuMiwgbHdkID0gNCkKYXJyb3dzKHgwID0gMCwgeDEgPSAwLCB5MCA9IC0xLjQsIHkxID0gMS40LCBsd2QgPSA0KQpgYGAKCgotIFdlIG9ic2VydmUgYSBsb3dlciBwb2xpbyAoUCkgaW5jaWRlbmNlIGZvciBjaGlsZHJlbiBmb3Igd2hvIG5vIGNvbnNlbnQgd2FzIGdpdmVuIHRoYW4gZm9yIHRoZSBjaGlsZHJlbiBpbiB0aGUgY29udHJvbCBncm91cC4KCi0gQ29uc2VudCBmb3IgdmFjY2luYXRpb24gKFYpIHdhcyBhc3NvY2lhdGVkIHdpdGggdGhlIHNvY2lvLWVjb25vbWljIHN0YXR1cyAoUykuCgotIENoaWxkcmVuIG9mIGxvd2VyIHNvY2lvLWVjb25vbWljIHN0YXR1cyB3ZXJlIG1vcmUgcmVzaXN0YW50IHRvIHRoZSBkaXNlYXNlLgoKLSBUaGUgZ3JvdXBzIG9mIGNhc2VzIGFuZCBjb250cm9scyBhcmUgbm90IGNvbXBhcmFibGU6CiAgICAtIGRpZmZlcmVuY2UgaW4gYWdlLAogICAgLSBkaWZmZXJlbmNlIGluIHNvY2lvLWVjb25vbWljIHN0YXR1cyBhbmQKICAgIC0gZGlmZmVyZW5jZSBpbiBzdXNjZXB0aWJsZSBmb3IgZGlzZWFzZS4KCi0tLQoKIyMgU2FsayBTdHVkeQoKIyMjIERlc2lnbgoKQSBuZXcgc3R1ZHkgd2FzIGNvbmR1Y3RlZDogUmFuZG9taXplZCBkb3VibGUgYmxpbmQgc3R1ZHkKCiAgLSBDaGlsZHJlbiBhcmUgYXNzaWduZWQgYXQgcmFuZG9tIHRvIHRoZSBjb250cm9sIG9yIGNhc2UgdHJlYXRtZW50IGFybSBhZnRlciBjb25zZW50IHdhcyBnaXZlbiBieSB0aGUgcGFyZW50cy4KICAtIENvbnRyb2w6IHZhY2NpbmF0aW9uIHdpdGggcGxhY2VibwogIC0gVHJlYXRtZW50OiB2YWNjaW5hdGlvbiB3aXRoIHZhY2NpbmUKICAtIGRvdWJsZSBibGluZGluZzoKICAgIC0gcGFyZW50cyBkaWQgbm90IGtub3cgaWYgdGhlaXIgY2hpbGQgd2FzIHZhY2NpbmF0ZWQgb3IgcmVjZWl2ZWQgdGhlIHBsYWNlYm8KICAgIC0gY2FyZS1naXZlci9yZXNlYXJjaGVycyBkaWQgbm90IGtub3cgaWYgdGhlIGNoaWxkIHdhcyB2YWNjaW5hdGVkICBvciByZWNlaXZlZCBwbGFjZWJvCgotLS0KCiMjIyBEYXRhCgpgYGB7cn0Kc2FsayA8LSBkYXRhLmZyYW1lKGdyb3VwID0gYygiY2FzZXMiLCAiY29udHJvbCIsICJub0NvbmNlbnQiKSwgdHJlYXRtZW50ID0gYygidmFjY2luZSIsICJwbGFjZWJvIiwgIm5vbmUiKSwgdG90YWwgPSBjKAogIDIwMDc0NSwKICAyMDEyMjksIDMzODc3OAopLCBwb2xpbyA9IGMoNTcsIDE0MiwgMTU3KSkKc2FsayRub1BvbGlvIDwtIHNhbGskdG90YWwgLSBzYWxrJHBvbGlvCnNhbGskaW5jaWRlbmNlUE0gPC0gcm91bmQoc2FsayRwb2xpbyAvIHNhbGskdG90YWwgKiAxZTYsIDApCmtuaXRyOjprYWJsZShzYWxrKQpgYGAKCi0gV2Ugb2JzZXJ2ZSBhIG11Y2ggbGFyZ2VyIGVmZmVjdCBub3cgdGhhdCB0aGUgY2FzZXMgYW5kIHRoZSBjb250cm9scyBhcmUgY29tcGFyYWJsZSwgaW5jaWRlbmNlIG9mIGByIHNhbGskaW5jaWRlbmNlUE1bMV1gICBhbmQgYHIgc2FsayRpbmNpZGVuY2VQTVsyXWAgcGVyIG1pbGxpb24sIHJlc3BlY3RpdmVseS4KCi0gVGhlIHBvbGlvIGluY2lkZW5jZSBmb3IgY2hpbGRyZW4gd2l0aCBubyBjb25zZW50IHJlbWFpbnMgc2ltaWxhciwgYHIgbmZpcCRpbmNpZGVuY2VQTVszXWAgYW5kIGByIHNhbGskaW5jaWRlbmNlUE1bM11gIHBlciBtaWxsaW9uIGluIHRoZSBORklQIGFuZCBTYWxrIHN0dWR5LCByZXNwZWN0aXZlbHkuCgotLS0KCiMgUm9sZSBvZiBTdGF0aXN0aWNzIGluIHRoZSBMaWZlIFNjaWVuY2VzCgotIFdlIGhhdmUgc2VlbiB0aGF0CiAgICAtIGl0IGlzIGltcG9ydGFudCB0byBjYXJlZnVsbHkgc3BlY2lmeSB0aGUgc2NvcGUgb2YgdGhlIHN0dWR5IGJlZm9yZSB0aGUgZXhwZXJpbWVudCwKICAgIC0gdGhlIHNhbXBsZSBzaXplIG1hdHRlcnMsCiAgICAtIHdlIHNob3VsZCBiZSBhd2FyZSBvZiBjb25mb3VuZGluZywgYW5kCiAgICAtIGEgcHJvcGVyIGNvbnRyb2wgaXMgcmVxdWlyZWQuCgokXHJpZ2h0YXJyb3ckIEdvb2QgZXhwZXJpbWVudGFsIGRlc2lnbiBpcyBjcnVjaWFsIQoKLSBXZSBhbHNvIG9ic2VydmVkIHRoYXQgdGhlcmUgaXMgdmFyaWFiaWxpdHkgaW4gdGhlIHBvcHVsYXRpb24gYW5kIGJlY2F1c2Ugd2UgY2FuIG9ubHkgc2FtcGxlIGEgc21hbGwgcGFydCBvZiB0aGUgcG9wdWxhdGlvbiBvdXIgcmVzdWx0cyBhbmQgY29uY2x1c2lvbnMgYXJlIHN1YmplY3RlZCB0byB1bmNlcnRhaW50eS4KCi0gU3RhdGlzdGljcyBpcyB0aGUgc2NpZW5jZSBvbgogICAgMS4gY29sbGVjdGluZyAoZXhwZXJpbWVudGFsIGRlc2lnbiksCiAgICAyLiBleHBsb3JpbmcgKGRhdGEgZXhwbG9yYXRpb24pIGFuZAogICAgMy4gbGVhcm5pbmcgZnJvbSBkYXRhIGFuZCB0byBnZW5lcmFsaXplIHdoYXQgd2Ugb2JzZXJ2ZSBpbiB0aGUgc2FtcGxlIHRvd2FyZHMgdGhlIHBvcHVsYXRpb24gd2hpbGUgcXVhbnRpZnlpbmcsIGNvbnRyb2xsaW5nIGFuZCByZXBvcnRpbmcgdmFyaWFiaWxpdHkgYW5kIHVuY2VydGFpbnR5IChzdGF0aXN0aWNhbCBtb2RlbGxpbmcgYW5kIHN0YXRpc3RpY2FsIGluZmVyZW5jZSkuCgotIFRoZXJlZm9yZSwgc3RhdGlzdGljcyBwbGF5cyBhbiBpbXBvcnRhbnQgcm9sZSBpbiBhbG1vc3QgYWxsIHNjaWVuY2VzIChlLmcuIGNvbHVtbiAicG9pbnRzIG9mIHNpZ25pZmljYW5jZSIgaW4gTmF0dXJlIE1ldGhvZHMuIGh0dHA6Ly9ibG9ncy5uYXR1cmUuY29tL21ldGhhZ29yYS8yMDEzLzA4L2dpdmluZ19zdGF0aXN0aWNzX3RoZV9hdHRlbnRpb25faXRfZGVzZXJ2ZXMuaHRtbCkKCi0tLQoKYGBge3IgcG9wMlNhbXAyUG9wLCBvdXQud2lkdGg9JzgwJScsZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmlmICgicGkiICVpbiUgbHMoKSkgcm0oInBpIikKa29wdm9ldGVyIDwtIGZ1bmN0aW9uKHgsIHksIGFuZ2xlID0gMCwgbCA9IC4yLCBjZXguZG90ID0gLjUsIHBjaCA9IDE5LCBjb2wgPSAiYmxhY2siKSB7CiAgYW5nbGUgPC0gYW5nbGUgLyAxODAgKiBwaQogIHBvaW50cyh4LCB5LCBjZXggPSBjZXguZG90LCBwY2ggPSBwY2gsIGNvbCA9IGNvbCkKICBsaW5lcyhjKHgsIHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSkpLCBjKHksIHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSkpLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4ICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSwgeCArIGwgLyAyICogY29zKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gNCAqIGNvcyhhbmdsZSkpLCBjKHkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgYW5nbGUpLCB5ICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSArIGwgLyA0ICogc2luKGFuZ2xlKSksIGNvbCA9IGNvbCkKICBsaW5lcyhjKHggKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgYW5nbGUpLCB4ICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSArIGwgLyA0ICogY29zKHBpICsgYW5nbGUpKSwgYyh5ICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSwgeSArIGwgLyAyICogc2luKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gNCAqIHNpbihwaSArIGFuZ2xlKSksIGNvbCA9IGNvbCkKICBsaW5lcyhjKHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSksIHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgcGkgLyA0ICsgYW5nbGUpKSwgYyh5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpLCB5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIHBpIC8gNCArIGFuZ2xlKSksIGNvbCA9IGNvbCkKICBsaW5lcyhjKHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSksIHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gMiAqIGNvcygtcGkgLyAyIC0gcGkgLyA0ICsgYW5nbGUpKSwgYyh5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpLCB5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpICsgbCAvIDIgKiBzaW4oLXBpIC8gMiAtIHBpIC8gNCArIGFuZ2xlKSksIGNvbCA9IGNvbCkKfQoKcGFyKG1hciA9IGMoMCwgMCwgMCwgMCksIG1haSA9IGMoMCwgMCwgMCwgMCkpCnBsb3QoMCwgMCwgeGxhYiA9ICIiLCB5bGFiID0gIiIsIHhsaW0gPSBjKDAsIDEwKSwgeWxpbSA9IGMoMCwgMTApLCBjb2wgPSAwLCB4YXh0ID0gIm5vbmUiLCB5YXh0ID0gIm5vbmUiLCBheGVzID0gRkFMU0UpCnJlY3QoMCwgNiwgMTAsIDEwLCBib3JkZXIgPSAicmVkIiwgbHdkID0gMikKdGV4dCguNSwgOCwgInBvcHVsYXRpb24iLCBzcnQgPSA5MCwgY29sID0gInJlZCIsIGNleCA9IDIpCnN5bWJvbHMoMywgOCwgY2lyY2xlcyA9IDEuNSwgY29sID0gInJlZCIsIGFkZCA9IFRSVUUsIGZnID0gInJlZCIsIGluY2hlcyA9IEZBTFNFLCBsd2QgPSAyKQpzZXQuc2VlZCgzMzApCmdyaWQgPC0gc2VxKDAsIDEuMywgLjAxKQoKZm9yIChpIGluIDE6NTApCnsKICBhbmdsZTEgPC0gcnVuaWYobiA9IDEsIG1pbiA9IDAsIG1heCA9IDM2MCkKICBhbmdsZTIgPC0gcnVuaWYobiA9IDEsIG1pbiA9IDAsIG1heCA9IDM2MCkKICByYWRpdXMgPC0gc2FtcGxlKGdyaWQsIHByb2IgPSBncmlkXjIgKiBwaSAvIHN1bShncmlkXjIgKiBwaSksIHNpemUgPSAxKQogIGtvcHZvZXRlcigzICsgcmFkaXVzICogY29zKGFuZ2xlMSAvIDE4MCAqIHBpKSwgOCArIHJhZGl1cyAqIHNpbihhbmdsZTEgLyAxODAgKiBwaSksIGFuZ2xlID0gYW5nbGUyKQp9CnRleHQoNy41LCA4LCAiY2hvbGVzdGVyb2wgaW4gcG9wdWxhdGlvbiIsIGNvbCA9ICJyZWQiLCBjZXggPSAxLjIpCgpyZWN0KDAsIDAsIDEwLCA0LCBib3JkZXIgPSAiYmx1ZSIsIGx3ZCA9IDIpCnRleHQoLjUsIDIsICJzYW1wbGUiLCBzcnQgPSA5MCwgY29sID0gImJsdWUiLCBjZXggPSAyKQpzeW1ib2xzKDMsIDIsIGNpcmNsZXMgPSAxLjUsIGNvbCA9ICJyZWQiLCBhZGQgPSBUUlVFLCBmZyA9ICJibHVlIiwgaW5jaGVzID0gRkFMU0UsIGx3ZCA9IDIpCmZvciAoaSBpbiAwOjIpIHsKICBmb3IgKGogaW4gMDo0KQogIHsKICAgIGtvcHZvZXRlcigyLjEgKyBqICogKDMuOSAtIDIuMSkgLyA0LCAxLjEgKyBpKQogIH0KfQp0ZXh0KDcuNSwgMiwgImNob2xlc3Rlcm9sIGluIHNhbXBsZSIsIGNvbCA9ICJibHVlIiwgY2V4ID0gMS4yKQoKYXJyb3dzKDMsIDUuOSwgMywgNC4xLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAzKQphcnJvd3MoNywgNC4xLCA3LCA1LjksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDMpCnRleHQoMS41LCA1LCAiRVhQLiBERVNJR04gKDEpIiwgY29sID0gImJsYWNrIiwgY2V4ID0gMS4yKQp0ZXh0KDguNSwgNSwgIkVTVElNQVRJT04gJlxuSU5GRVJFTkNFICgzKSIsIGNvbCA9ICJibGFjayIsIGNleCA9IDEuMikKdGV4dCg3LjUsIC41LCAiREFUQSBFWFBMT1JBVElPTiAmXG5ERVNDUklQVElWRSBTVEFUSVNUSUNTICgyKSIsIGNvbCA9ICJibGFjayIsIGNleCA9IDEuMikKYGBgCg==