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, 5…
$ SurveyYr <fct> 2009_10, 2009_10, 2009_10, 2009_10, 2009_10…
$ Gender <fct> male, male, male, male, female, male, male,…
$ Age <int> 34, 34, 34, 4, 49, 9, 8, 45, 45, 45, 66, 58…
$ AgeDecade <fct> 30-39, 30-39, 30-39, 0-9, 40-49, 0-9,…
$ AgeMonths <int> 409, 409, 409, 49, 596, 115, 101, 541, 541,…
$ Race1 <fct> White, White, White, Other, White, White, W…
$ Race3 <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ Education <fct> High School, High School, High School, NA, …
$ MaritalStatus <fct> Married, Married, Married, NA, LivePartner,…
$ HHIncome <fct> 25000-34999, 25000-34999, 25000-34999, 2000…
$ HHIncomeMid <int> 30000, 30000, 30000, 22500, 40000, 87500, 6…
$ Poverty <dbl> 1.36, 1.36, 1.36, 1.07, 1.91, 1.84, 2.33, 5…
$ HomeRooms <int> 6, 6, 6, 9, 5, 6, 7, 6, 6, 6, 5, 10, 6, 10,…
$ HomeOwn <fct> Own, Own, Own, Own, Rent, Rent, Own, Own, O…
$ Work <fct> NotWorking, NotWorking, NotWorking, NA, Not…
$ Weight <dbl> 87.4, 87.4, 87.4, 17.0, 86.7, 29.8, 35.2, 7…
$ Length <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ HeadCirc <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ Height <dbl> 164.7, 164.7, 164.7, 105.4, 168.4, 133.1, 1…
$ BMI <dbl> 32.22, 32.22, 32.22, 15.30, 30.57, 16.82, 2…
$ BMICatUnder20yrs <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ BMI_WHO <fct> 30.0_plus, 30.0_plus, 30.0_plus, 12.0_18.5,…
$ Pulse <int> 70, 70, 70, NA, 86, 82, 72, 62, 62, 62, 60,…
$ BPSysAve <int> 113, 113, 113, NA, 112, 86, 107, 118, 118, …
$ BPDiaAve <int> 85, 85, 85, NA, 75, 47, 37, 64, 64, 64, 63,…
$ BPSys1 <int> 114, 114, 114, NA, 118, 84, 114, 106, 106, …
$ BPDia1 <int> 88, 88, 88, NA, 82, 50, 46, 62, 62, 62, 64,…
$ BPSys2 <int> 114, 114, 114, NA, 108, 84, 108, 118, 118, …
$ BPDia2 <int> 88, 88, 88, NA, 74, 50, 36, 68, 68, 68, 62,…
$ BPSys3 <int> 112, 112, 112, NA, 116, 88, 106, 118, 118, …
$ BPDia3 <int> 82, 82, 82, NA, 76, 44, 38, 60, 60, 60, 64,…
$ Testosterone <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ DirectChol <dbl> 1.29, 1.29, 1.29, NA, 1.16, 1.34, 1.55, 2.1…
$ TotChol <dbl> 3.49, 3.49, 3.49, NA, 6.70, 4.86, 4.09, 5.8…
$ UrineVol1 <int> 352, 352, 352, NA, 77, 123, 238, 106, 106, …
$ UrineFlow1 <dbl> NA, NA, NA, NA, 0.094, 1.538, 1.322, 1.116,…
$ UrineVol2 <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ UrineFlow2 <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ Diabetes <fct> No, No, No, No, No, No, No, No, No, No, No,…
$ DiabetesAge <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ HealthGen <fct> Good, Good, Good, NA, Good, NA, NA, Vgood, …
$ DaysPhysHlthBad <int> 0, 0, 0, NA, 0, NA, NA, 0, 0, 0, 10, 0, 4, …
$ DaysMentHlthBad <int> 15, 15, 15, NA, 10, NA, NA, 3, 3, 3, 0, 0, …
$ LittleInterest <fct> Most, Most, Most, NA, Several, NA, NA, None…
$ Depressed <fct> Several, Several, Several, NA, Several, NA,…
$ nPregnancies <int> NA, NA, NA, NA, 2, NA, NA, 1, 1, 1, NA, NA,…
$ nBabies <int> NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, …
$ Age1stBaby <int> NA, NA, NA, NA, 27, NA, NA, NA, NA, NA, NA,…
$ SleepHrsNight <int> 4, 4, 4, NA, 8, NA, NA, 8, 8, 8, 7, 5, 4, N…
$ SleepTrouble <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No,…
$ PhysActive <fct> No, No, No, NA, No, NA, NA, Yes, Yes, Yes, …
$ PhysActiveDays <int> NA, NA, NA, NA, NA, NA, NA, 5, 5, 5, 7, 5, …
$ TVHrsDay <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ CompHrsDay <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ TVHrsDayChild <int> NA, NA, NA, 4, NA, 5, 1, NA, NA, NA, NA, NA…
$ CompHrsDayChild <int> NA, NA, NA, 1, NA, 0, 6, NA, NA, NA, NA, NA…
$ Alcohol12PlusYr <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Y…
$ AlcoholDay <int> NA, NA, NA, NA, 2, NA, NA, 3, 3, 3, 1, 2, 6…
$ AlcoholYear <int> 0, 0, 0, NA, 20, NA, NA, 52, 52, 52, 100, 1…
$ SmokeNow <fct> No, No, No, NA, Yes, NA, NA, NA, NA, NA, No…
$ Smoke100 <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No,…
$ Smoke100n <fct> Smoker, Smoker, Smoker, NA, Smoker, NA, NA,…
$ SmokeAge <int> 18, 18, 18, NA, 38, NA, NA, NA, NA, NA, 13,…
$ Marijuana <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Y…
$ AgeFirstMarij <int> 17, 17, 17, NA, 18, NA, NA, 13, 13, 13, NA,…
$ RegularMarij <fct> No, No, No, NA, No, NA, NA, No, No, No, NA,…
$ AgeRegMarij <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ HardDrugs <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No,…
$ SexEver <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Y…
$ SexAge <int> 16, 16, 16, NA, 12, NA, NA, 13, 13, 13, 17,…
$ SexNumPartnLife <int> 8, 8, 8, NA, 10, NA, NA, 20, 20, 20, 15, 7,…
$ SexNumPartYear <int> 1, 1, 1, NA, 1, NA, NA, 0, 0, 0, NA, 1, 1, …
$ SameSex <fct> No, No, No, NA, Yes, NA, NA, Yes, Yes, Yes,…
$ SexOrientation <fct> Heterosexual, Heterosexual, Heterosexual, N…
$ PregnantNow <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
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?
LS0tCnRpdGxlOiAiMS4gSW50cm9kdWN0aW9uOiBXaHkgZG8gd2UgbmVlZCBzdGF0aXN0aWNzIgphdXRob3I6ICJMaWV2ZW4gQ2xlbWVudCIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgY2FjaGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBUUlVFCikKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyBNb3RpdmF0aW9uCjxhIHJlbD0ibGljZW5zZSIgaHJlZj0iaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMCI+PGltZyBhbHQ9IkNyZWF0aXZlIENvbW1vbnMgTGljZW5zZSIgc3R5bGU9ImJvcmRlci13aWR0aDowIiBzcmM9Imh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnktbmMtc2EvNC4wLzg4eDMxLnBuZyIgLz48L2E+CgohW10oaHR0cHM6Ly9waW1hZ2VzLnRvb2xib3guY29tLzMwMHgyMTkvd3AtY29udGVudC91cGxvYWRzLzIwMjEvMTIvMTQyMzI5Mjkvd2F5c190b19jYXB0dXJlX2IyYl9jdXN0b21lcl9kYXRhXzViYWNkMmRiZTFhMDkucG5nKQoKIVtdKC4vZmlndXJlcy93cEdyYXBoLmpwZWcpCgotIFdlIGxpdmUgaW4gYSBiaWcgZGF0YSBlcmEKLSBEYXRhIG9uIGxvY2F0aW9uLCBjbGlja3MsIGUtY29tbWVyY2UsIHNvY2lhbCBtZWRpYSAuLi4KLSBMaWZlIFNjaWVuY2VzOiBtZWFzdXJlIGV4cHJlc3Npb24gb2YgdGhvdXNhbmRzIG9mIGdlbmVzLCBwcm90ZWlucywgLi4uIGZvciBlYWNoIHN1YmplY3Qgb3IgZXZlbiBpbmRpdmlkdWFsIGNlbGxzCi0gRGF0YSBkcml2ZW4gam91cm5hbGlzbQotIC4uLgoKU3RhdGlzdGljcyBpcyB0aGUgc2NpZW5jZSB0byBsZWFybiBmcm9tIGVtcGlyaWNhbCBkYXRhLgoKU3RhdGlzdGljYWwgbGl0ZXJhY3kgaXMga2V5IHRvIGludGVycHJldCByZXN1bHRzIGZyb20gc2NpZW50aWZpYyBwdWJsaWNhdGlvbnMuCgojIExlYXJuaW5nIG9iamVjdGl2ZXMgCgoxLiBJbiB0aGlzIGludHJvZHVjdGlvbiB5b3Ugd2lsbCBmYW1pbGlhcml6ZSB5b3Vyc2VsZiB3aXRoIHRocmVlIGltcG9ydGFudCB0YXNrcyBvZiBzdGF0aXN0aWNzIAoKICAtIEV4cGVyaW1lbnRhbCBkZXNpZ24KICAtIERhdGEgRXhwbG9yYXRpb24KICAtIEVzdGltYXRpb24gYW5kIHN0YXRpc3RpY2FsIGluZmVyZW5jZSAKCjIuIFlvdSB1bmRlcnN0YW5kIGhvdyB0aGUgZGF0YSwgdGhlIGVzdGltYXRlZCBtZWFuLCBzdGFuZGFyZCBkZXZpYXRpb24gYW5kIGNvbmNsdXNpb25zIG9mIGEgc3RhdGlzdGljYWwgZGF0YSBhbmFseXNpcyBjYW4gY2hhbmdlIGZyb20gZXhwZXJpbWVudCB0byBleHBlcmltZW50IAoKMy4gWW91IGhhdmUgbm90aWNlIG9uIGhvdyAKCiAgLSBzdGF0aXN0aWNhbCB0ZXN0cyBjYW4gY29udHJvbCBmb3IgZmFsc2UgcG9zaXRpdmVzIAogIC0gdGhlIHBvd2VyIHRvIHBpY2sgdXAgYW4gZWZmZWN0IGRlcGVuZHMgb24gdGhlIHNhbXBsZSBzaXplIAoKNC4gWW91IGNhbiBleHBsYWluIHRoZSBpbXBvcnRhbmNlIG9mIHVzaW5nIGEgZ29vZCBjb250cm9sIAoKNS4gWW91IGNhbiBleHBsYWluIHdoYXQgY29uZm91bmRpbmcgaXMKCiMgU21lbGx5IGFybXBpdCBleGFtcGxlCgotIFNtZWxseSBhcm1waXRzIGFyZSBub3QgY2F1c2VkIGJ5IHN3ZWF0IGl0c2VsZi4gVGhlIHNtZWxsIGlzIGNhdXNlZCBieSBzcGVjaWZpYyBtaWNyby1vcmdhbmlzbXMgYmVsb25naW5nIHRvIHRoZSBncm91cCBvZiAqQ29yeW5lYmFjdGVyaXVtIHNwcC4qIHRoYXQgbWV0YWJvbGlzZSBzd2VhdC4KQW5vdGhlciBncm91cCBvZiBhYnVuZGFudCBiYWN0ZXJpYSBhcmUgdGhlICpTdGFwaHlsb2NvY2N1cyBzcHAuKiwgdGhlc2UgYmFjdGVyaWEgZG8gbm90IG1ldGFib2xpc2Ugc3dlYXQgaW4gc21lbGx5IGNvbXBvdW5kcy4KCi0gVGhlIENNRVQtZ3JvZXAgYXQgR2hlbnQgVW5pdmVyc2l0eSBkb2VzIHJlc2VhcmNoIG9uIHRyYW5zcGxhbnRpbmcgdGhlIGFybXBpdCBtaWNyb2Jpb21lIHRvIHNhdmUgcGVvcGxlIHdpdGggc21lbGx5IGFybXBpdHMuCgotIFByb3Bvc2VkIFRoZXJhcHk6CiAgCTEuIFJlbW92ZSBhcm1waXQtbWljcm9iaW9tZSB3aXRoIGFudGliaW90aWNzCiAgICAyLiBJbmZsdWVuY2UgYXJtcGl0IG1pY3JvYmlvbWUgd2l0aCBtaWNyb2JpYWwgIHRyYW5zcGxhbnQgKGh0dHBzOi8veW91dHUuYmUvOVJJRnlxTFhkVncpCgoKYGBge3Igb3V0LndpZHRoPSc4MCUnLGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQppZiAoInBpIiAlaW4lIGxzKCkpIHJtKCJwaSIpCmtvcHZvZXRlciA8LSBmdW5jdGlvbih4LCB5LCBhbmdsZSA9IDAsIGwgPSAuMiwgY2V4LmRvdCA9IC41LCBwY2ggPSAxOSwgY29sID0gImJsYWNrIikgewogIGFuZ2xlIDwtIGFuZ2xlIC8gMTgwICogcGkKICBwb2ludHMoeCwgeSwgY2V4ID0gY2V4LmRvdCwgcGNoID0gcGNoLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4LCB4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpKSwgYyh5LCB5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpKSwgY29sID0gY29sKQogIGxpbmVzKGMoeCArIGwgLyAyICogY29zKC1waSAvIDIgKyBhbmdsZSksIHggKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgYW5nbGUpICsgbCAvIDQgKiBjb3MoYW5nbGUpKSwgYyh5ICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSwgeSArIGwgLyAyICogc2luKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gNCAqIHNpbihhbmdsZSkpLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4ICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSwgeCArIGwgLyAyICogY29zKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gNCAqIGNvcyhwaSArIGFuZ2xlKSksIGMoeSArIGwgLyAyICogc2luKC1waSAvIDIgKyBhbmdsZSksIHkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgYW5nbGUpICsgbCAvIDQgKiBzaW4ocGkgKyBhbmdsZSkpLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpLCB4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIHBpIC8gNCArIGFuZ2xlKSksIGMoeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSwgeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSArIGwgLyAyICogc2luKC1waSAvIDIgKyBwaSAvIDQgKyBhbmdsZSkpLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpLCB4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpICsgbCAvIDIgKiBjb3MoLXBpIC8gMiAtIHBpIC8gNCArIGFuZ2xlKSksIGMoeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSwgeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSArIGwgLyAyICogc2luKC1waSAvIDIgLSBwaSAvIDQgKyBhbmdsZSkpLCBjb2wgPSBjb2wpCn0KCnBhcihtYXIgPSBjKDAsIDAsIDAsIDApLCBtYWkgPSBjKDAsIDAsIDAsIDApKQpwbG90KDAsIDAsIHhsYWIgPSAiIiwgeWxhYiA9ICIiLCB4bGltID0gYygwLCAxMCksIHlsaW0gPSBjKDAsIDEwKSwgY29sID0gMCwgeGF4dCA9ICJub25lIiwgeWF4dCA9ICJub25lIiwgYXhlcyA9IEZBTFNFKQpyZWN0KDAsIDYsIDEwLCAxMCwgYm9yZGVyID0gInJlZCIsIGx3ZCA9IDIpCnRleHQoLjUsIDgsICJwb3B1bGF0aW9uIiwgc3J0ID0gOTAsIGNvbCA9ICJyZWQiLCBjZXggPSAyKQpzeW1ib2xzKDMsIDgsIGNpcmNsZXMgPSAxLjUsIGNvbCA9ICJyZWQiLCBhZGQgPSBUUlVFLCBmZyA9ICJyZWQiLCBpbmNoZXMgPSBGQUxTRSwgbHdkID0gMikKc2V0LnNlZWQoMzMwKQpncmlkIDwtIHNlcSgwLCAxLjMsIC4wMSkKCmZvciAoaSBpbiAxOjUwKQp7CiAgYW5nbGUxIDwtIHJ1bmlmKG4gPSAxLCBtaW4gPSAwLCBtYXggPSAzNjApCiAgYW5nbGUyIDwtIHJ1bmlmKG4gPSAxLCBtaW4gPSAwLCBtYXggPSAzNjApCiAgcmFkaXVzIDwtIHNhbXBsZShncmlkLCBwcm9iID0gZ3JpZF4yICogcGkgLyBzdW0oZ3JpZF4yICogcGkpLCBzaXplID0gMSkKICBrb3B2b2V0ZXIoMyArIHJhZGl1cyAqIGNvcyhhbmdsZTEgLyAxODAgKiBwaSksIDggKyByYWRpdXMgKiBzaW4oYW5nbGUxIC8gMTgwICogcGkpLCBhbmdsZSA9IGFuZ2xlMikKfQp0ZXh0KDcuNSwgOCwgIk1pY3JvYmlvbWUgaW4gcG9wdWxhdGlvbiIsIGNvbCA9ICJyZWQiLCBjZXggPSAxLjIpCgpyZWN0KDAsIDAsIDEwLCA0LCBib3JkZXIgPSAiYmx1ZSIsIGx3ZCA9IDIpCnRleHQoLjUsIDIsICJzYW1wbGUiLCBzcnQgPSA5MCwgY29sID0gImJsdWUiLCBjZXggPSAyKQpzeW1ib2xzKDMsIDIsIGNpcmNsZXMgPSAxLjUsIGNvbCA9ICJyZWQiLCBhZGQgPSBUUlVFLCBmZyA9ICJibHVlIiwgaW5jaGVzID0gRkFMU0UsIGx3ZCA9IDIpCmZvciAoaSBpbiAwOjEpIHsKICBmb3IgKGogaW4gMDo0KQogIHsKICAgIGtvcHZvZXRlcigyLjEgKyBqICogKDMuOSAtIDIuMSkgLyA0LCAxLjEgKyBpIC8gMiwgY29sID0gInB1cnBsZSIpCiAgfQp9CmZvciAoaSBpbiAyOjMpIHsKICBmb3IgKGogaW4gMDo0KQogIHsKICAgIGtvcHZvZXRlcigyLjEgKyBqICogKDMuOSAtIDIuMSkgLyA0LCAxLjYgKyBpIC8gMiwgY29sID0gIm9yYW5nZSIpCiAgfQp9CnRleHQoNy41LCAyLCAiTWljcm9iaW9tZSBpbiBzYW1wbGUiLCBjb2wgPSAiYmx1ZSIsIGNleCA9IDEuMikKCmFycm93cygzLCA1LjksIDMsIDQuMSwgY29sID0gImJsYWNrIiwgbHdkID0gMykKdGV4dCgxLjUsIDUsICJFWFAuIERFU0lHTiAoMSkiLCBjb2wgPSAiYmxhY2siLCBjZXggPSAxLjIpCnRleHQoNy41LCAuNSwgIkRBVEEgRVhQTE9SQVRJT04gJlxuREVTQ1JJUFRJVkUgU1RBVElTVElDUyAoMikiLCBjb2wgPSAiYmxhY2siLCBjZXggPSAxLjIpCmFycm93cyg3LCA0LjEsIDcsIDUuOSwgY29sID0gImJsYWNrIiwgbHdkID0gMykKdGV4dCg4LjUsIDUsICJFU1RJTUFUSU9OICZcbklORkVSRU5DRSAoMykiLCBjb2wgPSAiYmxhY2siLCBjZXggPSAxLjIpCmBgYAoKCi0gRXhwZXJpbWVudDoKCiAgICAtIDIwIHN1YmplY3RzIHdpdGggc21lbGx5IGFybXBpdHMgYXJlIGF0dHJpYnV0ZWQgdG8gb25lIG9mIHR3byB0cmVhdG1lbnQgZ3JvdXBzCiAgICAtIHBsYWNlYm8gKG9ubHkgYW50aWJpb3RpY3MpCiAgICAtIHRyYW5zcGxhbnQgKGFudGliaW90aWNzIGZvbGxvd2VkIGJ5IG1pY3JvYmlhbCB0cmFuc3BsYW50KS4KICAgIC0gVGhlIG1pY3JvYmlvbWUgaXMgc2FtcGxlZCA2IHdlZWtzIHVwb24gdGhlIHRyZWF0bWVudC4KICAgIC0gVGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiAqU3RhcGh5bG9jb2NjdXMgc3BwLiogb24gKkNvcnluZWJhY3Rlcml1bSBzcHAuKiArICpTdGFwaHlsb2NvY2N1cyBzcHAuKiBpbiB0aGUgbWljcm9iaW9tZSBpcyBtZWFzdXJlZCB2aWEgREdHRSAoKkRlbmF0dXJpbmcgR3JhZGllbnQgR2VsIEVsZWN0cm9waG9yZXNpcyopLgoKLS0tCgojIyBJbXBvcnQgdGhlIGRhdGEKYGBge3J9CnJlYWRfbGluZXMoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HVFBCL1BTTFMyMC9tYXN0ZXIvZGF0YS9hcm1waXQuY3N2IikKYGBgCgpUaGUgZmlsZSBpcyBjb21tYSBzZXBhcmF0ZWQgYW5kIGluIHRpZHkgZm9ybWF0CgpgYGB7cn0KYXAgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HVFBCL1BTTFMyMC9tYXN0ZXIvZGF0YS9hcm1waXQuY3N2IikKYXAKYGBgCgotLS0KCiMjIERhdGEgRXhwbG9yYXRpb24gYW5kIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MKCi0gRGF0YSBleHBsb3JhdGlvbiBpcyBleHRyZW1lbHkgaW1wb3J0YW50IHRvIGdldCBpbnNpZ2h0IGluIHRoZSBkYXRhLgotIEl0IGlzIG9mdGVuIHVuZGVycmF0ZWQgYW5kIG92ZXJsb29rZWQuCgojIyMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcwoKV2UgZmlyc3Qgc3VtbWFyaXplIHRoZSBkYXRhIGFuZCBjYWxjdWxhdGUgdGhlIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhbmQgc3RhbmRhcmQgZXJyb3IgYW5kIHN0b3JlIHRoZSByZXN1bHQgaW4gYW4gb2JqZWN0IGFwUmVsU3VtIHZpYSBgYXBSZWxTdW08LWAKCjEuIFdlIHBpcGUgdGhlIGBhcGAgZGF0YWZyYW1lIHRvIHRoZSBncm91cF9ieSBmdW5jdGlvbiB0byBncm91cCB0aGUgZGF0YSBieSB0cmVhdG1lbnQgdHJ0IGBncm91cF9ieSh0cnQpYAoyLiBXZSBwaXBlIHRoZSByZXN1bHQgdG8gdGhlIGBzdW1tYXJpemVgIGZ1bmN0aW9uIHRvIHN1bW1hcml6ZSB0aGUgInJlbCIgdmFyaWFibGUgYW5kIGNhbGN1bGF0ZSB0aGUgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uIGFuZCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucwozLiBXZSBwaXBlIHRoZSByZXN1bHQgdG8gdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIG1ha2UgYSBuZXcgdmFyaWFibGUgaW4gdGhlIGRhdGEgZnJhbWUgYHNlYCBmb3Igd2hpY2ggd2UgY2FsY3VsYXRlIHRoZSBzdGFuZGFyZCBlcnJvcgoKCmBgYHtyfQphcFJlbFN1bSA8LSBhcCAlPiUKICBncm91cF9ieSh0cnQpICU+JQogIHN1bW1hcml6ZSgKICAgIG1lYW4gPSBtZWFuKHJlbCwgbmEucm0gPSBUUlVFKSwKICAgIHNkID0gc2QocmVsLCBuYS5ybSA9IFRSVUUpLAogICAgbiA9IG4oKQogICkgJT4lCiAgbXV0YXRlKHNlID0gc2QgLyBzcXJ0KG4pKQoKYXBSZWxTdW0KYGBgCgotLS0KCiMjIyBQbG90cwoKV2Ugd2lsbCB1c2UgZ2dwbG90MiB0byBtYWtlIG91ciBwbG90cy4KV2l0aCB0aGUgZ2dwbG90MiBsaWJyYXJ5IHdlIGNhbiBlYXNpbHkgYnVpbGQgcGxvdHMgYnkgYWRkaW5nIGxheWVycy4KCiMjIyMgYmFycGxvdAoKMS4gV2UgcGlwZSBvdXIgc3VtbWFyaXplZCBkYXRhIHRvIHRoZSBgZ2dwbG90YCBmdW5jdGlvbiBhbmQgd2Ugc2VsZWN0IHRoZSB0cmVhdG1lbnQgdmFyaWFibGUgdHJ0IGFuZCB0aGUgdmFyaWFibGUgbWVhbiBmb3IgcGxvdHRpbmcgYGFlcyh4PXRydCx5PW1lYW4pYAoKMi4gV2UgbWFrZSBhIGJhcnBsb3QgYmFzZWQgb24gdGhpcyBkYXRhIHVzaW5nIHRoZSBgZ2VvbV9iYXJgIGZ1bmN0aW9uLiBUaGUgc3RhdGlzdGljIGlzIGBzdGF0PSJpZGVudGl0eSJgIGJlY2F1c2UgdGhlIGJhciBoZWlnaHQgc2hvdWxkIGJlIGVxdWFsIHRoZSB2YWx1ZSBmb3IgdGhlIG1lYW4gb2YgdGhlIHJlbGF0aXZlIGFidW5kYW5jZS4KCmBgYHtyfQphcFJlbFN1bSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0cnQsIHkgPSBtZWFuKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKQpgYGAKCi0gSXMgdGhpcyBwbG90IGluZm9ybWF0aXZlPz8KCi0tLQoKV2Ugd2lsbCBub3cgYWRkIHN0YW5kYXJkIGVycm9ycyB0byB0aGUgcGxvdAp1c2luZyBgZ2VvbV9lcnJvcmJhcmAgZnVuY3Rpb24gYW5kIHNwZWNpZnkgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gdmFsdWUgZm9yIG9mIHRoZSBlcnJvciBiYXIsIHRoZSB3aWR0aCBjb21tYW5kIGlzIHVzZWQgdG8gc2V0IHRoZSB3aWR0aCBvZiB0aGUgZXJyb3IgYmFyIHNtYWxsZXIgdGhhbiB0aGUgd2lkdGggb2YgdGhlIGJhci4KCmBgYHtyfQphcFJlbFN1bSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0cnQsIHkgPSBtZWFuKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IG1lYW4gLSBzZSwgeW1heCA9IG1lYW4gKyBzZSksIHdpZHRoID0gLjIpCmBgYAoKLSBJcyB0aGlzIHBsb3QgaW5mb3JtYXRpdmU/PwoKLS0tCgojIyMjIGJveHBsb3RzCgpJIGNvbnNpZGVyIGJhcnBsb3RzIHRvIGJlIGJhZCBwbG90cwoKLSBUaGV5IGFyZSBub3QgaW5mb3JtYXRpdmUKLSBUaGV5IGp1c3QgdmlzdWFsaXplIGEgdHdvIHBvaW50IHN1bW1hcnkgb2YgdGhlIGRhdGEuIEl0IGlzIGJldHRlciB0byBkbyB0aGlzIGluIGEgdGFibGUKLSBUaGV5IHVzZSBhIGxvdCBvZiBzcGFjZSAoZS5nLiBmcm9tIHplcm8gdXAgdG8gdGhlIG1pbmltdW0gcmVsYXRpdmUgYWJ1bmRhbmNlKSB3aGVyZSBubyBkYXRhIGFyZSBwcmVzZW50LgoKSXQgaXMgYmV0dGVyIHRvIGdldCBhIHZpZXcgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YS4gV2UgY2FuIHVzZSBhIGJveHBsb3QgZm9yIHRoaXMgcHVycG9zZS4KV2UgZmlyc3QgZXhwbGFpbiB3aGF0IGEgYm94cGxvdC4KCi0tLQoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmZlbSA8LSBOSEFORVM6Ok5IQU5FUyAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiICYgIWlzLm5hKERpcmVjdENob2wpKSAlPiUKICBzZWxlY3QoRGlyZWN0Q2hvbCkKYm94cGxvdChmZW0kRGlyZWN0Q2hvbCwgeWxhYiA9ICJEaXJlY3QgY2hvbGVzdGVyb2wiLCBjZXgubGFiID0gMS41LCBjZXguYXhpcyA9IDEuNSwgY2V4Lm1haW4gPSAxLjUpCnJhbmdlQ2wgPC0gcXVhbnRpbGUoZmVtJERpcmVjdENob2wsIGMoLjI1LCAuNzUpKSArIGMoLTEsIDEpICogZGlmZihxdWFudGlsZShmZW0kRGlyZWN0Q2hvbCwgYyguMjUsIC43NSkpKSAqIDEuNQpib3hZcyA8LSBjKHJhbmdlKGZlbSREaXJlY3RDaG9sW2ZlbSREaXJlY3RDaG9sIDw9IHJhbmdlQ2xbMl0gJiBmZW0kRGlyZWN0Q2hvbCA+PSByYW5nZUNsWzFdXSksIHF1YW50aWxlKGZlbSREaXJlY3RDaG9sLCBjKC4yNSwgLjUsIC43NSkpLCByYW5nZUNsWzJdICsgKG1heChmZW0kRGlyZWN0Q2hvbCkgLSByYW5nZUNsWzJdKSAvIDIpCnRleHQoMS4zLCBib3hZcywgbGFiZWxzID0gYygid2lza2VyIiwgIndpc2tlciIsICJ4MjUiLCAibWVkaWFuIiwgIng3NSIsICJvdXRsaWVycyIpLCBwb3MgPSA0LCBjZXggPSAxLjMpCmxpbmVzKGMoMS4xLCAxLjMsIDEuMywgMS4xKSwgYyhyYW5nZUNsWzJdLCByYW5nZUNsWzJdICsgKG1heChmZW0kRGlyZWN0Q2hvbCkgLSByYW5nZUNsWzJdKSAvIDIsIHJhbmdlQ2xbMl0gKyAobWF4KGZlbSREaXJlY3RDaG9sKSAtIHJhbmdlQ2xbMl0pIC8gMiwgbWF4KGZlbSREaXJlY3RDaG9sKSksIGx0eSA9IDIpCmBgYAoKLS0tCgpXZSB3aWxsIG5vdyBtYWtlIGEgYm94cGxvdCBmb3IgdGhlIGFwIGRhdGEKCjEuIFdlIHBpcGUgdGhlIGBhcGAgZGF0YWZyYW1lIHRvIHRoZSBnZ3Bsb3QgY29tbWFuZAoyLiBXZSBzZWxlY3QgdGhlIGRhdGEgd2l0aCB0aGUgY29tbWFuZCBgZ2dwbG90KGFlcyh4PXRydCx5PXJlbCkpYAozLiBXZSBhZGQgYSBib3hwbG90IHdpdGggdGhlIGNvbW1hbmQgYGdlb21fYm94cGxvdCgpYAoKYGBge3J9CmFwICU+JQogIGdncGxvdChhZXMoeCA9IHRydCwgeSA9IHJlbCkpICsKICBnZW9tX2JveHBsb3QoKQpgYGAKCi0tLQoKLSBOb3RlLCB0aGF0IHdlIGRvIG5vdCBoYXZlIHNvIG1hbnkgb2JzZXJ2YXRpb25zLgoKLSBJdCBpcyBhbHdheXMgYmV0dGVyIHRvIHNob3cgdGhlIGRhdGEgYXMgcmF3IGFzIHBvc3NpYmxlIQoKV2Ugd2lsbCBub3cgYWRkIHRoZSByYXcgZGF0YSB0byB0aGUgcGxvdC4KCi0gTm90ZSB0aGF0IHdlIHNldCB0aGUgb3V0bGllci5zaGFwZT1OQSBpbiB0aGUgZ2VvbV9ib3hwbG90IGZ1bmN0aW9uIGJlY2F1c2UgYmVjYXVzZSB3ZSB3aWxsIGFkZCBhbGwgcmF3IGRhdGEgYW55d2F5LgotIFdlIGFkZCB0aGUgcmF3IGRhdGEgdXNpbmcgYGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpYCwgd2l0aCB0aGUgYXJndW1lbnQgcG9zaXRpb249J2ppdHRlcicgd2Ugd2lsbCBhZGQgc29tZSByYW5kb20gbm9pc2UgdG8gdGhlIHggY29vcmRpbmF0ZSBzbyB0aGF0IHdlIGNhbiBzZWUgYWxsIGRhdGEuCgpgYGB7cn0KYXAgJT4lCiAgZ2dwbG90KGFlcyh4ID0gdHJ0LCB5ID0gcmVsKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIpCmBgYAoKVGhpcyBpcyBhbiBpbmZvcm1hdGl2ZSBwbG90IQoKLS0tCgotIFdlIG9ic2VydmVkIGFuIGVmZmVjdCBvZiB0aGUgdHJhbnNwbGFudGF0aW9uIG9uIHRoZSByZWxhdGlldmUgYWJ1bmRhbnRpZSBvZiBTdGFwaHlsb2NvY2N1cy4KCi0gSXMgdGhhdCBlZmZlY3QgbGFyZ2UgZW5vdWdoIHRvIGNvbmNsdWRlIHRoYXQgdGhlIHRyZWF0bWVudCB3b3Jrcz8KCi0tLQoKIyMgRXN0aW1hdGlvbiBhbmQgc3RhdGlzdGljYWwgaW5mZXJlbmNlCgotIEluZHVjdGlvbjogV2l0aCBzdGF0aXN0aWNhbCBpbmZlcmVuY2Ugd2UgY2FuIGdlbmVyYWxpemUgd2hhdCB3ZSBvYnNlcnZlIGluIHRoZSBzYW1wbGUgdG93YXJkcyB0aGUgcG9wdWxhdGlvbi4KCi0gVGhlIHByaWNlIHRoYXQgd2UgaGF2ZSB0byBwYXk6IHVuY2VydGFpbnR5IG9uIG91ciBjb25jbHVzaW9ucyEKCi0tLQoKLSBXaXRoIGRhdGEgd2UgY2Fubm90IHByb3ZlIHRoYXQgdGhlIHRyZWF0bWVudCB3b3JrcwoKLSBGYWxzaWZpY2F0aW9uIHByaW5jaXBsZSBvZiBQb3BwZXI6IFdpdGggZGF0YSB3ZSBjYW4gb25seSAgcmVqZWN0IGEgaHlwb3RoZXNpcyBvciB0aGVvcnkuCgotIFdpdGggc3RhdHMgd2UgY2FuIHRodXMgbm90IHByb3ZlIHRoYXQgdGhlIHRyZWF0bWVudCB3b3Jrcy4KCi0gQnV0IHN0YXRzIHdpbGwgYWxsb3cgdXMgdG8gZmFsY2lmeSB0aGUgb3Bwb3NpdGUgaHlwb3RoZXNpczogaG93IG11Y2ggZXZpZGVuY2UgaXMgdGhlcmUgaW4gdGhlIGRhdGEgYWdhaW5zdCB0aGUgYXNzdW1wdGlvbiB0aGF0IHRoZXJlIGlzIG5vIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50PwoKLSBXaXRoIHN0YXRzIHdlIGNhbiBjYWxjdWxhdGUgaG93IGxpa2VseSBpdCBpcyB0byBkcmF3IGEgcmFuZG9tIHNhbXBsZSAod2hlbiB5b3Ugd291bGQgcmVwZWF0IHRoZSBleHBlcmltZW50KSB3aXRoIGEgbWVhbiBkaWZmZXJlbmNlIGluIHJlbGF0aXZlIGFidW5kYW5jZSBiZXR3ZWVuIHRyYW5zcGxhbnQgYW5kIHBsYWNlYm8gZ3JvdXAgdGhhdCBpcyBhdCBsZWFzdCBhcyBsYXJnZSBhcyB3aGF0IHdlIG9ic2VydmVkIGluIG91ciBzYW1wbGUgd2hlbiB0aGVyZSB3b3VsZCBiZSBubyBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudC4KCi0gVGhpcyBwcm9iYWJpbGl0eSBpcyBjYWxsZWQgYSBwLXZhbHVlLgoKLSBJZiBwIGlzIHZlcnkgc21hbGwsIGl0IGlzIHZlcnkgdW5saWtlbHkgdG8gb2JzZXJ2ZSBhIHNhbXBsZSBsaWtlIG91cnMgYnkgcmFuZG9tIGNoYW5nZSB3aGVuIHRoZXJlIHdvdWxkIGJlIG5vIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50LgoKLSBXZSB0eXBpY2FsbHkgY29tcGFyZSBwIHdpdGggNSUuIElmIHRoZXJlIGlzIG5vIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50IHdlIHdpbGwgdGh1cyB0b2xlcmF0ZSBhIHByb2JhYmlsaXR5IG9mIDUlIG9uIGEgZmFsc2UgcG9zaXRpdmUgY29uY2x1c2lvbi4KCi0gVG8gY2FsY3VsYXRlIHAgd2Ugd2lsbCBoYXZlIHRvIG1vZGVsIHRoZSBkYXRhIHVzaW5nICBzdGF0aXN0aWNhbCBtb2RlbHMuCgotLS0KCkluIGNoYXB0ZXIgNSB3ZSB3aWxsIGxlYXJuIHRoYXQgd2UgY2FuIHVzZSBhIHR3by1zYW1wbGUgdC10ZXN0IHRvIGdlbmVyYWxpc2Ugd2hhdCB3ZSBvYnNlcnZlIGluIHRoZSBtaWNyb2Jpb21lIGRhdGFzZXQgdG93YXJkcyB0aGUgcG9wdWxhdGlvbi4KCmBgYHtyfQp0LnRlc3QocmVsIH4gdHJ0LCBkYXRhID0gYXApCmBgYAoKQ29uY2x1c2lvbjoKCldlIGNhbiBjb25jbHVkZSB0aGF0IHRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgU3RhcGh5bG9jb2NjdXMgaW4gdGhlIG1pY3JvYmlvbWUgb2YgaW5kaXZpZHVhbHMgd2l0aCBzbWVsbHkgYXJtcGl0cyAgaXMgYHIgZm9ybWF0KGFwUmVsU3VtJG1lYW5bMl0tYXBSZWxTdW0kbWVhblsxXSxkaWdpdHM9MylgJSBoaWdoZXIgdXBvbiB0aGUgdHJhbnNwbGFudCB0aGFuIHVwb24gdGhlIHBsYWNlYm8gdHJlYXRtZW50IChwIDwgMC4wMDEpLgoKLS0tCgojIyBTb21lIGNvbmNlcHRzCgpXaGF0IGFyZSB0aGUgY29uc2VxdWVuY2VzIG9mIHVzaW5nIGEgc2FtcGxlIGFuZCByYW5kb21pc2F0aW9uPwoKLSBSYW5kb20gc2FtcGxpbmcgaXMgY2xvc2VseSByZWxhdGVkIHRvIHRoZSBjb25jZXB0IG9mIHRoZSBwb3B1bGF0aW9uIG9yIHRoZSBzY29wZSBvZiB0aGUgc3R1ZHkuCgotIEJhc2VkIG9uIGEgc2FtcGxlIG9mIHN1YmplY3RzLCB0aGUgcmVzZWFyY2hlcnMgd2FudCB0byBjb21lIHRvIGNvbmNsdXNpb25zIHRoYXQgaG9sZCBmb3IKCiAgICAtIGFsbCBraW5kcyBvZiBwZW9wbGUKICAgIC0gb25seSBtYWxlIHN0dWRlbnRzCgotIFNjb3BlIG9mIHRoZSBzdHVkeSBzaG91bGQgYmUgd2VsbCBzcGVjaWZpZWQgYmVmb3JlIHRoZSBzdGFydCBvZiB0aGUgc3R1ZHkuCgotIEZvciB0aGUgc3RhdGlzdGljYWwgYW5hbHlzaXMgdG8gYmUgdmFsaWQsIGl0IGlzIHJlcXVpcmVkIHRoYXQgdGhlIHN1YmplY3RzIGFyZSBzZWxlY3RlZCBjb21wbGV0ZWx5IGF0IHJhbmRvbSBmcm9tIHRoZSBwb3B1bGF0aW9uIHRvIHdoaWNoIHdlIHdhbnQgdG8gZ2VuZXJhbGl6ZSBvdXIgY29uY2x1c2lvbnMuCgotIFNlbGVjdGluZyBjb21wbGV0ZWx5IGF0IHJhbmRvbSBmcm9tIGEgcG9wdWxhdGlvbiBpbXBsaWVzOgogICAgLSBhbGwgc3ViamVjdHMgaW4gdGhlIHBvcHVsYXRpb24gc2hvdWxkIGhhdmUgdGhlIHNhbWUgcHJvYmFiaWxpdHkgb2YgYmVpbmcgc2VsZWN0ZWQgaW4gdGhlIHNhbXBsZSwKICAgIC0gdGhlIHNlbGVjdGlvbiBvZiBhIHN1YmplY3QgaW4gdGhlIHNhbXBsZSBzaG91bGQgYmUgaW5kZXBlbmRlbnQgZnJvbSB0aGUgc2VsZWN0aW9uIG9mIHRoZSBvdGhlciBzdWJqZWN0cyBpbiB0aGUgc2FtcGxlLgoKLSBUaGUgc2FtcGxlIGlzIHRodXMgc3VwcG9zZWQgdG8gYmUgcmVwcmVzZW50YXRpdmUgZm9yIHRoZSBwb3B1bGF0aW9uLCBidXQgc3RpbGwgaXQgaXMgcmFuZG9tLgoKLSBXaGF0IGRvZXMgdGhpcyBpbXBseT8KCi0tLQoKIyBTYW1wbGUgdG8gc2FtcGxlIHZhcmlhYmlsaXR5CgpOYXRpb25hbCBIZWFsdGggTkhhbmVzIHN0dWR5CgogIC0gU2luY2UgMTk2MCBpbmRpdmlkdWFscyBvZiBhbGwgYWdlcyBhcmUgaW50ZXJ2aWV3ZWQgaW4gdGhlaXIgaG9tZXMgZXZlcnkgeWVhcgogIC0gVGhlIGhlYWx0aCBleGFtaW5hdGlvbiBjb21wb25lbnQgb2YgdGhlIHN1cnZleSBpcyBjb25kdWN0ZWQgaW4gYSBtb2JpbGUgZXhhbWluYXRpb24gY2VudHJlIChNRUMpLgogIC0gV2Ugd2lsbCB1c2UgdGhpcyBsYXJnZSBzdHVkeSB0byBzZWxlY3QgcmFuZG9tIHN1YmplY3RzIGZyb20gdGhlIEFtZXJpY2FuIHBvcHVsYXRpb24uCiAgLSBUaGlzIHdpbGwgaGVscCB1cyB0byB1bmRlcnN0YW5kIGhvdyB0aGUgcmVzdWx0cyBvZiBhbiBhbmFseXNpcyBhbmQgdGhlIGNvbmNsdXNpb25zIHZhcnkgZnJvbSBzYW1wbGUgdG8gc2FtcGxlLgoKLS0tCgpgYGB7cn0KbGlicmFyeShOSEFORVMpCmhlYWQoTkhBTkVTKQpnbGltcHNlKE5IQU5FUykKYGBgCgotLS0KCiMjIERhdGEgZXhwbG9yYXRpb24KCgpTdXBwb3NlIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gYXNzZXNzaW5nIHRoZSBkaWZmZXJlbmNlIGluIGRpcmVjdCBjaG9sZXN0ZXJvbCBsZXZlbHMgYmV0d2VlbiBtYWxlcyBhbmQgZmVtYWxlcyBvbGRlciB0aGFuIDI1IHllYXJzLgoKMS4gV2UgcGlwZSB0aGUgZGF0YXNldCB0byB0aGUgZnVuY3Rpb24gYGZpbHRlcmAgdG8gZmlsdGVyIHRoZSBkYXRhIGFjY29yZGluZyB0byBhZ2UuCjIuIFdlIHBsb3QgdGhlIGRpcmVjdCBjaG9sZXN0ZXJvbCBsZXZlbHMuCiAgICAtIFdlIHNlbGVjdCB0aGUgZGF0YSB3aXRoIHRoZSBjb21tYW5kIGBnZ3Bsb3QoYWVzKHg9RGlyZWN0Q2hvbCkpYAogICAgLSBXZSBhZGQgYSBoaXN0b2dyYW0gd2l0aCB0aGUgY29tbWFuZCBgZ2VvbV9oaXN0b2dyYW0oKWAKICAgIC0gV2UgbWFrZSB0byB2ZXJ0aWNhbCBwYW5lbHMgdXNpbmcgdGhlIGNvbW1hbmQgYGZhY2V0X2dyaWQoR2VuZGVyfi4pYAogICAgLSBXZSBjdXN0b21pemUgdGhlIGxhYmVsIG9mIHRoZSB4LWF4aXMgd2l0aCB0aGUgYHhsYWJgIGNvbW1hbmQuCgpgYGB7cn0KTkhBTkVTICU+JQogIGZpbHRlcihBZ2UgPiAyNSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGlyZWN0Q2hvbCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF9ncmlkKEdlbmRlciB+IC4pICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKG1nL2RsKSIpCmBgYAoKLS0tCgotIENob2xlc3Rlcm9sIGxldmVscyBhbmQgY29uY2VudHJhdGlvbiBtZWFzdXJlbWVudHMgYXJlIG9mdGVuIHNrZXdlZC4KLSBDb25jZW50cmF0aW9ucyBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLgotIFRoZXkgYXJlIG9mdGVuIGxvZyB0cmFuc2Zvcm1lZC4KCmBgYHtyfQpOSEFORVMgJT4lCiAgZmlsdGVyKEFnZSA+IDI1KSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBEaXJlY3RDaG9sICU+JSBsb2cyKCkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZmFjZXRfZ3JpZChHZW5kZXIgfiAuKSArCiAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIChsb2cyKSIpCmBgYAoKV2Ugc2VlIHRoYXQgdGhlIGRhdGEgYXJlIG1vcmUgb3IgbGVzcyBiZWxsIHNoYXBlZCB1cG9uIGxvZyB0cmFuc2Zvcm1hdGlvbi4KCi0tLQoKV2Ugd2lsbCBub3cgY3JlYXRlIGEgc3Vic2V0IG9mIHRoZSBkYXRhIHRoYXQgd2Ugd2lsbCB1c2UgdG8gc2FtcGxlIGZyb20gaW4gdGhlIG5leHQgc2VjdGlvbnMuCgogIDEuIFdlIGZpbHRlciBvbiBhZ2UgYW5kIHJlbW92ZSBzdWJqZWN0cyB3aXRoIG1pc3NpbmcgdmFsdWVzIChOQSkuCiAgMi4gV2Ugb25seSBzZWxlY3QgdGhlIHZhcmlhYmxlcyBHZW5kZXIgYW5kIERpcmVjdENob2wgZnJvbSB0aGUgZGF0YXNldCB0byBhdm9pZCB1bm5lY2Vzc2FyeSB2YXJpYWJsZXMuCiAgMy4gV2l0aCB0aGUgbXV0YXRlIGZ1bmN0aW9uIHdlIGNhbiBhZGQgYSBuZXcgdmFyaWFibGUgbG9nQ2hvbCB3aXRoIGxvZyB0cmFuc2Zvcm1lZCBkaXJlY3QgY2hvbGVzdGVyb2wgbGV2ZWxzLgoKYGBge3J9Cm5oYW5lc1N1YiA8LSBOSEFORVMgJT4lCiAgZmlsdGVyKEFnZSA+IDI1ICYgIWlzLm5hKERpcmVjdENob2wpKSAlPiUKICBzZWxlY3QoYygiR2VuZGVyIiwgIkRpcmVjdENob2wiKSkgJT4lCiAgbXV0YXRlKGNob2xMb2cgPSBsb2cyKERpcmVjdENob2wpKQpgYGAKCi0tLQoKV2Ugd2lsbCBjYWxjdWxhdGUgdGhlIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgdGhlIGNob2xMb2cgdmFyaWFibGUgZm9yIG1hbGVzIGFuZCBmZW1hbGVzIGluIHRoZSBsYXJnZSBkYXRhc2V0LgpTbyB3ZSBncm91cCBieSBHZW5kZXIKCmBgYHtyfQpjaG9sTG9nU3VtIDwtIG5oYW5lc1N1YiAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIHN1bW1hcml6ZSgKICAgIG1lYW4gPSBtZWFuKGNob2xMb2csIG5hLnJtID0gVFJVRSksCiAgICBzZCA9IHNkKGNob2xMb2csIG5hLnJtID0gVFJVRSksCiAgICBuID0gbigpCiAgKSAlPiUKICBtdXRhdGUoc2UgPSBzZCAvIHNxcnQobikpCgpjaG9sTG9nU3VtCmBgYAoKLS0tCgojIyBFeHBlcmltZW50CgotIFN1cHBvc2UgdGhhdCB3ZSBoYXZlIG5vIGFjY2VzcyB0byBjaG9sZXN0ZXJvbCBsZXZlbHMgb2YgdGhlIEFtZXJpY2FuIHBvcHVsYXRpb24sCi0gd2Ugd2lsbCBoYXZlIHRvIHNldHVwIGFuIGV4cGVyaW1lbnQuCi0gU3VwcG9zZSB3ZSBoYXZlIGEgYnVkZ2V0IGZvciBhc3Nlc3NpbmcgMTAgZmVtYWxlcyBhbmQgMTAgbWFsZXMsCi0gd2Ugd2lsbCBzdWJzZXQgMTAgZmVtYWxlcyBhbmQgMTAgbWFsZXMgYXQgcmFuZG9tIGZyb20gdGhlIEFtZXJpY2FuIHBvcHVsYXRpb24gYW5kIG1lYXN1cmUgdGhlaXIgZGlyZWN0IGNob2xlc3Rlcm9sIGxldmVscy4KCmBgYHtyfQpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemUgPSAxMCkKbWFsIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZSA9IDEwKQoKc2FtcCA8LSByYmluZChmZW0sIG1hbCkKc2FtcApgYGAKCi0tLQoKV2Ugd2lsbCBub3cgcGxvdCB0aGUgZGF0YSB3aXRoIGEgaGlzdG9ncmFtIGFuZCBib3hwbG90cwoKYGBge3J9CnNhbXAgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY2hvbExvZykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IC4xKSArCiAgZmFjZXRfZ3JpZChHZW5kZXIgfiAuKSArCiAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIChsb2cyKSIpCgpzYW1wICU+JQogIGdncGxvdChhZXMoeCA9IEdlbmRlciwgeSA9IGNob2xMb2cpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikKYGBgCgotLS0KCldlIHN1bW1hcml6ZSB0aGUgZGF0YQpgYGB7cn0Kc2FtcCAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIHN1bW1hcml6ZSgKICAgIG1lYW4gPSBtZWFuKGNob2xMb2csIG5hLnJtID0gVFJVRSksCiAgICBzZCA9IHNkKGNob2xMb2csIG5hLnJtID0gVFJVRSksCiAgICBuID0gbigpCiAgKSAlPiUKICBtdXRhdGUoc2UgPSBzZCAvIHNxcnQobikpCmBgYAoKTm90ZSB0aGF0IHRoZSBzYW1wbGUgbWVhbiBpcyBkaWZmZXJlbnQgZnJvbSB0aGF0IG9mIHRoZSBsYXJnZSBleHBlcmltZW50ICgicG9wdWxhdGlvbiIpIHdlIHNhbXBsZWQgZnJvbS4KCldlIHRlc3QgZm9yIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gTWFsZXMgYW5kIGZlbWFsZXMKCmBgYHtyfQp0LnRlc3QoY2hvbExvZyB+IEdlbmRlciwgc2FtcCwgdmFyLmVxdWFsID0gVFJVRSkKYGBgCgotLS0KCiMjIFJlcGVhdCB0aGUgZXhwZXJpbWVudAoKSWYgd2UgZG8gdGhlIGV4cGVyaW1lbnQgYWdhaW4gd2Ugc2VsZWN0IG90aGVyIHBlb3BsZSBhbmQgd2Ugb2J0YWluIGRpZmZlcmVudCByZXN1bHRzLgoKCmBgYHtyfQpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemUgPSAxMCkKbWFsIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZSA9IDEwKQoKc2FtcDIgPC0gcmJpbmQoZmVtLCBtYWwpCnNhbXAyICU+JQogIGdncGxvdChhZXMoeCA9IERpcmVjdENob2wgJT4lIGxvZygpKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjEpICsKICBmYWNldF9ncmlkKEdlbmRlciB+IC4pICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKGxvZykiKQoKc2FtcDIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gR2VuZGVyLCB5ID0gY2hvbExvZykpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9ICJqaXR0ZXIiKQoKc2FtcDIgJT4lCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBzdW1tYXJpemUoCiAgICBtZWFuID0gbWVhbihjaG9sTG9nLCBuYS5ybSA9IFRSVUUpLAogICAgc2QgPSBzZChjaG9sTG9nLCBuYS5ybSA9IFRSVUUpLAogICAgbiA9IG4oKQogICkgJT4lCiAgbXV0YXRlKHNlID0gc2QgLyBzcXJ0KG4pKQoKdC50ZXN0KGNob2xMb2cgfiBHZW5kZXIsIHNhbXAyLCB2YXIuZXF1YWwgPSBUUlVFKQpgYGAKCi0tLQoKIyMgQW5kIGFnYWluCgpgYGB7cn0Kc2V0LnNlZWQoMTI4NTcpCmZlbSA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiZmVtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZSA9IDEwKQptYWwgPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIm1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplID0gMTApCgpzYW1wMyA8LSByYmluZChmZW0sIG1hbCkKc2FtcDMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGlyZWN0Q2hvbCAlPiUgbG9nKCkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAuMSkgKwogIGZhY2V0X2dyaWQoR2VuZGVyIH4gLikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nKSIpCgpzYW1wMyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBHZW5kZXIsIHkgPSBjaG9sTG9nKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIpCgoKc2FtcDMgJT4lCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBzdW1tYXJpemUoCiAgICBtZWFuID0gbWVhbihjaG9sTG9nLCBuYS5ybSA9IFRSVUUpLAogICAgc2QgPSBzZChjaG9sTG9nLCBuYS5ybSA9IFRSVUUpLAogICAgbiA9IG4oKQogICkgJT4lCiAgbXV0YXRlKHNlID0gc2QgLyBzcXJ0KG4pKQoKdC50ZXN0KGNob2xMb2cgfiBHZW5kZXIsIHNhbXAzLCB2YXIuZXF1YWwgPSBUUlVFKQpgYGAKCi0tLQoKIyMgU3VtbWFyeQoKLSBCZWNhdXNlIHdlIHNhbXBsZWQgb3RoZXIgc3ViamVjdHMgaW4gZWFjaCBzYW1wbGUsIHdlIG9idGFpbiBkaWZmZXJlbnQgY2hvbGVzdGVyb2wgbGV2ZWxzLgotIEhvd2V2ZXIsIG5vdCBvbmx5IHRoZSBjaG9sZXN0ZXJvbCBsZXZlbHMgZGlmZmVyIGZyb20gc2FtcGxlIHRvIHNhbXBsZSBidXQgYWxzbyB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzOiBtZWFucywgc3RhbmRhcmQgZGV2aWF0aW9ucyBhbmQgc3RhbmRhcmQgZXJyb3JzLgotIE5vdGUsIHRoYXQgaW4gdGhlIGxhc3Qgc2FtcGxlIHRoZSBsb2cgY2hvbGVzdGVyb2wgbGV2ZWxzIGFyZSBvbiBhdmVyYWdlIGxvd2VyIGZvciBmZW1hbGVzIHRoYW4gZm9yIG1hbGVzOyBiYXNlZCBvbiB0aGlzIHNhbXBsZSB3ZSBldmVuIHdvdWxkIHdyb25nbHkgY29uY2x1ZGUgdGhhdCB0aGUgY2hvbGVzdGVyb2wgbGV2ZWxzIGZvciBmZW1hbGVzIGFyZSBvbiBhdmVyYWdlIGxhcmdlciB0aGFuIHRob3NlIG9mIG1hbGVzLgoKLSBUaGlzIGltcGxpZXMgdGhhdCBvdXIgY29uY2x1c2lvbnMgYXJlIGFsc28gc3ViamVjdGVkIHRvIHVuY2VydGFpbnR5IGFuZCBtaWdodCBjaGFuZ2UgZnJvbSBzYW1wbGUgdG8gc2FtcGxlLgoKLSBTYW1wbGVzIGFzIHRoZSBvbmUgd2hlcmUgdGhlIGVmZmVjdCBzd2FwcyBhbmQgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgaG93ZXZlciwgYXJlIHZlcnkgcmFyZS4KLSBUaGlzIGlzIGlsbHVzdHJhdGVkIHdpdGggdGhlIGNvZGUgYmVsb3csIHdoZXJlIHdlIHdpbGwgZHJhdyAyMDAwMCByZXBlYXRlZCBzYW1wbGVzIHdpdGggc2FtcGxlIHNpemUgMTAgZm9yIGZlbWFsZXMgYW5kIG1hbGVzIGZyb20gdGhlIE5IYW5lcyBzdHVkeS4KCmBgYHtyfQpuc2ltIDwtIDIwMDAwCm5TYW1wIDwtIDEwCnJlcyA8LSBtYXRyaXgoMCwgbnJvdyA9IG5zaW0sIG5jb2wgPSAyKQpmZW0gPC0gbmhhbmVzU3ViICU+JSBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKQptYWwgPC0gbmhhbmVzU3ViICU+JSBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikKCmZvciAoaSBpbiAxOm5zaW0pCnsKICBmZW1TYW1wIDwtIHNhbXBsZShmZW0kY2hvbExvZywgblNhbXApCiAgbWFsU2FtcCA8LSBzYW1wbGUobWFsJGNob2xMb2csIG5TYW1wKQoKICBtZWFuRmVtIDwtIG1lYW4oZmVtU2FtcCkKICBtZWFuTWFsIDwtIG1lYW4obWFsU2FtcCkKICBkZWx0YSA8LSBtZWFuRmVtIC0gbWVhbk1hbAogIHNkRmVtIDwtIHNkKGZlbVNhbXApCiAgc2RNYWwgPC0gc2QobWFsU2FtcCkKICBzZUZlbSA8LSBzZEZlbSAvIHNxcnQoblNhbXApCiAgc2VGZW0gPC0gc2RGZW0gLyBzcXJ0KG5TYW1wKQogIHNkUG9vbCA8LSBzcXJ0KChzZEZlbV4yICogKG5TYW1wIC0gMSkgKyBzZE1hbF4yICogKG5TYW1wIC0gMSkpIC8gKDIgKiBuU2FtcCAtIDIpKQogIHR2YWx1ZSA8LSAoZGVsdGEpIC8gKHNkUG9vbCAqIHNxcnQoMSAvIG5TYW1wICsgMSAvIG5TYW1wKSkKICBwdmFsdWUgPC0gcHQoYWJzKHR2YWx1ZSksIGxvd2VyLnRhaWwgPSBGQUxTRSwgZGYgPSAyICogblNhbXAgLSAyKSAqIDIKICByZXNbaSwgXSA8LSBjKGRlbHRhLCBwdmFsdWUpCn0Kc3VtKHJlc1ssIDJdIDwgMC4wNSAmIHJlc1ssIDFdID4gMCkKc3VtKHJlc1ssIDJdID4gMC4wNSkKc3VtKHJlc1ssIDJdIDwgMC4wNSAmIHJlc1ssIDFdIDwgMCkKCnJlcyA8LSByZXMgJT4lIGFzLmRhdGEuZnJhbWUoKQpuYW1lcyhyZXMpIDwtIGMoImRlbHRhIiwgInB2YWx1ZSIpCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkZWx0YSwgeSA9IC1sb2cxMChwdmFsdWUpLCBjb2xvciA9IHB2YWx1ZSA8IDAuMDUpKSArCiAgZ2VvbV9wb2ludCgpICsKICB4bGFiKCJBdmVyYWdlIGNob2xlc3Rlcm9sIGRpZmZlcmVuY2UiKSArCiAgeWxhYigiLSBsb2cxMChwdmFsdWUpIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJyZWQiKSkKCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBkZWx0YSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IDAsIHkgPSBjKG1lYW4oZmVtJGNob2xMb2cpIC0gbWVhbihtYWwkY2hvbExvZykpLCBjb2xvciA9ICJwb3AuIGRpZmYiKSkgKwogIHhsYWIoIiIpCmBgYAoKT25seSBpbiBgciBzdW0ocmVzWywyXTwwLjA1JnJlc1ssMV08MClgIG91dCBvZiAyMDAwMCBzYW1wbGVzIHdlIGNvbmNsdWRlIHRoYXQgdGhlIG1lYW4gY2hvbGVzdGVyb2wgbGV2ZWwgb2YgbWFsZXMgaXMgc2lnbmlmaWNhbnRseSBsb3dlciB0aGFuIGZvciBmZW1hbGVzLiBGb3IgdGhlIHJlbWFpbmluZyBzYW1wbGVzIHRoZSBjaG9sZXN0ZXJvbCBsZXZlbHMgZm9yIG1hbGVzIHdlcmUgb24gYXZlcmFnZSBzaWduaWZpY2FudGx5IGxvd2VyIHRoYW4gZm9yIGZlbWFsZXMgKGByIHN1bShyZXNbLDJdPDAuMDUmcmVzWywxXT4wKWAgc2FtcGxlcykgb3IgdGhlIGF2ZXJhZ2UgZGlmZmVyZW5jZSBpbiBjaG9sZXN0ZXJvbCBsZXZlbHMgd2VyZSBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCAoYHIgc3VtKHJlc1ssMl0+MC4wNSlgIHNhbXBsZXMpLiBUaGUgbGF0dGVyIGlzIGJlY2F1c2UgdGhlIHBvd2VyIGlzIHJhdGhlciBsb3cgdG8gZGV0ZWN0IHRoZSBkaWZmZXJlbmNlIHdpdGggMTAgc2FtcGxlcyBpbiBlYWNoIGdyb3VwLgoKLS0tCgojIyBBc3NpZ25tZW50CgoxLiBDb3B5IHRoZSBjb2RlIGNodW5rIHdpdGggdGhlIHNpbXVsYXRpb24gc3R1ZHkKMi4gQWRkIGl0IGhlcmUgYmVsb3cKMy4gTW9kaWZ5IHRoZSBzYW1wbGUgc2l6ZSB0byA1MC4KNC4gV2hhdCBkbyB5b3Ugb2JzZXJ2ZT8KCgotLS0KCiMjIENvbnRyb2wgb2YgZmFsc2UgcG9zaXRpdmVzCgpXYXQgaGFwcGVucyB3aGVuIHRoZXJlIGlzIG5vIGRpZmZlcmVuY2UgYmV0d2VlbiBib3RoIGdyb3Vwcz8KCi0gV2Ugd2lsbCBoYXZlIHRvIHNpbXVsYXRlIGV4cGVyaW1lbnRzIGZvciB3aGljaCB0aGUgY2hvbGVzdG9yb2wgbGV2ZWxzIGFyZSB0aGUgc2FtZSBmb3IgYm90aCBncm91cHMuCgoKLSBXZSBjYW4gZG8gdGhpcyBieSBzYW1wbGluZyBkYXRhIGZvciBib3RoIGdyb3VwcyBmcm9tIHRoZSBzdWJzZXQgb2Ygd29tZW4gaW4gdGhlIHN0dWR5LgoKLSBXZSBkbyB0aGlzIGFnYWluIGZvciAxMCBzdWJqZWN0cyBwZXIgZ3JvdXAKCgpgYGB7cn0KbnNpbSA8LSAyMDAwMApuU2FtcCA8LSAxMApyZXMgPC0gbWF0cml4KDAsIG5yb3cgPSBuc2ltLCBuY29sID0gMikKZmVtIDwtIG5oYW5lc1N1YiAlPiUgZmlsdGVyKEdlbmRlciA9PSAiZmVtYWxlIikKbWFsIDwtIG5oYW5lc1N1YiAlPiUgZmlsdGVyKEdlbmRlciA9PSAibWFsZSIpCgpmb3IgKGkgaW4gMTpuc2ltKQp7CiAgZmVtU2FtcCA8LSBzYW1wbGUoZmVtJGNob2xMb2csIG5TYW1wKQogIGZlbTJTYW1wIDwtIHNhbXBsZShmZW0kY2hvbExvZywgblNhbXApCgogIG1lYW5GZW0gPC0gbWVhbihmZW1TYW1wKQogIG1lYW5GZW0yIDwtIG1lYW4oZmVtMlNhbXApCiAgZGVsdGEgPC0gbWVhbkZlbSAtIG1lYW5GZW0yCiAgc2RGZW0gPC0gc2QoZmVtU2FtcCkKICBzZEZlbTIgPC0gc2QoZmVtMlNhbXApCiAgc2VGZW0gPC0gc2RGZW0gLyBzcXJ0KG5TYW1wKQogIHNlRmVtIDwtIHNkRmVtMiAvIHNxcnQoblNhbXApCiAgc2RQb29sIDwtIHNxcnQoKHNkRmVtXjIgKiAoblNhbXAgLSAxKSArIHNkRmVtMl4yICogKG5TYW1wIC0gMSkpIC8gKDIgKiBuU2FtcCAtIDIpKQogIHR2YWx1ZSA8LSAoZGVsdGEpIC8gKHNkUG9vbCAqIHNxcnQoMSAvIG5TYW1wICsgMSAvIG5TYW1wKSkKICBwdmFsdWUgPC0gcHQoYWJzKHR2YWx1ZSksIGxvd2VyLnRhaWwgPSBGQUxTRSwgZGYgPSAyICogblNhbXAgLSAyKSAqIDIKICByZXNbaSwgXSA8LSBjKGRlbHRhLCBwdmFsdWUpCn0Kc3VtKHJlc1ssIDJdIDwgMC4wNSAmIHJlc1ssIDFdID4gMCkKc3VtKHJlc1ssIDJdID49IDAuMDUpCnN1bShyZXNbLCAyXSA8IDAuMDUgJiByZXNbLCAxXSA8IDApCgpyZXMgPC0gcmVzICU+JSBhcy5kYXRhLmZyYW1lKCkKbmFtZXMocmVzKSA8LSBjKCJkZWx0YSIsICJwdmFsdWUiKQpyZXMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGVsdGEsIHkgPSAtbG9nMTAocHZhbHVlKSwgY29sb3IgPSBwdmFsdWUgPCAwLjA1KSkgKwogIGdlb21fcG9pbnQoKSArCiAgeGxhYigiQXZlcmFnZSBjaG9sZXN0ZXJvbCBkaWZmZXJlbmNlIikgKwogIHlsYWIoIi0gbG9nMTAocHZhbHVlKSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCAicmVkIikpCgpyZXMgJT4lCiAgZ2dwbG90KGFlcyh5ID0gZGVsdGEpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHggPSAwLCB5ID0gMCwgY29sb3IgPSAicG9wLiBkaWZmIikpICsKICB4bGFiKCIiKQpgYGAKCk5vdGUsIHRoYXQgdGhlIG51bWJlciBvZiBmYWxzZSBwb3NpdGl2ZXMgYXJlIG9uIGByIHN1bShyZXNbLDJdPDAuMDUpYCBvbiBgciBmb3JtYXQobnNpbSxkaWdpdHM9NSlgIGV4cGVyaW1lbnRzIGFuZCBhcmUgbmljZWx5IGNvbnRyb2xsZWQgYXQgdGhlIDUlIGxldmVsLgoKV2hhdCBoYXBwZW5zIGlmIHdlIGluY3JlYXNlIHRoZSBzYW1wbGUgc2l6ZSB0byA1MCBzdWJqZWN0cyBwZXIgZ3JvdXA/CgoKLS0tCgojIFNhbGsgU3R1ZHkKCi0gSW4gMTkxNiwgdGhlIFVTIGV4cGVyaWVuY2VkIHRoZSBmaXJzdCBsYXJnZSBlcGlkZW1pYyBvZiBwb2xpby4KLSBKb2huIFNhbGsgZGV2ZWxvcGVkIGEgdmFjY2luZSB3aXRoIHByb21pc2luZyByZXN1bHRzIGluIHRoZSBsYWIgaW4gdGhlIGVhcmx5IGZpZnRpZXMuCi0gSW4gMTk1NCwgdGhlIE5hdGlvbmFsIEZvdW5kYXRpb24KZm9yIEluZmFudGlsZSBQYXJhbHlzaXMgKE5GSVApIGhhcyBzZXR1cCBhIGxhcmdlIHN0dWR5IHRvIGFzc2VzcyB0aGUgZWZmZWN0aXZlbmVzcyBvZiB0aGUgU2FsayB2YWNjaW5lLgotIFN1cHBvc2UgdGhhdCB0aGUgTkZJUCB3b3VsZCBoYXZlIHZhY2NpbmF0ZWQgYSBsYXJnZSBudW1iZXIgb2YgY2hpbGRyZW4gaW4gMTk1NCBhbmQgd291bGQgaGF2ZSBvYnNlcnZlZCB0aGF0IHRoZSBwb2xpbyBpbmNpZGVuY2UgaW4gMTk1NCB3YXMgbG93ZXIgdGhhbiBpbiAxOTUzLiBDb3VsZCB0aGV5IGhhdmUgY29uY2x1ZGVkIHRoYXQgdGhlIHZhY2NpbmUgd2FzIGVmZmVjdGl2ZT8KCi0tLQoKIyMgTkZJUCBTdHVkeQoKIyMjIERlc2lnbgoKLSBMYXJnZSBzaW11bHRhbmVvdXMgc3R1ZHkgd2l0aCBjYXNlcywgdmFjY2luYXRlZCBjaGlsZHJlbiwgYW5kIGNvbnRyb2xzLCAgbm9uLXZhY2NpbmF0ZWQgY2hpbGRyZW4uCi0gQWxsIHNjaG9vbHMgaW4gZGlzdHJpY3RzIHdpdGggaGlnaCBwb2xpbyBpbmNpZGVuY2UKLSBDYXNlczogY2hpbGRyZW4gd2l0aCBjb25zZW50IGZvciB2YWNjaW5hdGlvbiBmcm9tIHNlY29uZCBncmFkZSBvZiBwcmltYXJ5IHNjaG9vbC4KLSBDb250cm9sczogY2hpbGRyZW4gZnJvbSAgZmlyc3QgYW5kIHRoaXJkIGdyYWRlLgoKIyMjIERhdGEKCmBgYHtyfQpuZmlwIDwtIGRhdGEuZnJhbWUoZ3JvdXAgPSBjKCJjYXNlcyIsICJjb250cm9sIiwgIm5vQ29uY2VudCIpLCBncmFkZSA9IGMoImcyIiwgImcxZzMiLCAiZzIiKSwgdmFjY2luID0gYygieWVzIiwgIm5vIiwgIm5vIiksIHRvdGFsID0gYygyMjE5OTgsIDcyNTE3MywgMTIzNjA1KSwgcG9saW8gPSBjKDU0LCAzOTEsIDU2KSkKbmZpcCRub1BvbGlvIDwtIG5maXAkdG90YWwgLSBuZmlwJHBvbGlvCmtuaXRyOjprYWJsZShuZmlwKQpgYGAKCkNvbXBhcmUgcG9saW8gaW5jaWRlbmNlPwoKYGBge3IsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9Cm5maXAkaW5jaWRlbmNlUE0gPC0gcm91bmQobmZpcCRwb2xpbyAvIG5maXAkdG90YWwgKiAxZTYsIDApCmtuaXRyOjprYWJsZShuZmlwKQpgYGAKCldoYXQgY2FuIHdlIGNvbmNsdWRlPwoKLS0tCgojIyBDb25mb3VuZGluZwoKYGBge3IsZWNobz1GQUxTRSwgZmlnLmFsaWduID0gImNlbnRlciIsb3V0LndpZHRoID0gJzUwJSd9CnBsb3QoYygwLCAwLCAxKSwgYygtMiwgMiwgMCksIHBjaCA9IGMoIlMiLCAiViIsICJQIiksIHhheHQgPSAibm9uZSIsIHlheHQgPSAibm9uZSIsIGF4ZXMgPSBGQUxTRSwgeGxhYiA9ICIiLCB5bGFiID0gIiIsIGNleCA9IDQsIHlsaW0gPSBjKC0yLjIsIDIuMikpCmFycm93cyh4MCA9IDAuMSwgeDEgPSAuOSwgeTAgPSAxLjgsIHkxID0gMC4xLCBsd2QgPSA0KQphcnJvd3MoeDAgPSAwLjEsIHgxID0gLjksIHkwID0gLTEuOCwgeTEgPSAtMC4yLCBsd2QgPSA0KQphcnJvd3MoeDAgPSAwLCB4MSA9IDAsIHkwID0gLTEuNCwgeTEgPSAxLjQsIGx3ZCA9IDQpCmBgYAoKCi0gV2Ugb2JzZXJ2ZSBhIGxvd2VyIHBvbGlvIChQKSBpbmNpZGVuY2UgZm9yIGNoaWxkcmVuIGZvciB3aG8gbm8gY29uc2VudCB3YXMgZ2l2ZW4gdGhhbiBmb3IgdGhlIGNoaWxkcmVuIGluIHRoZSBjb250cm9sIGdyb3VwLgoKLSBDb25zZW50IGZvciB2YWNjaW5hdGlvbiAoVikgd2FzIGFzc29jaWF0ZWQgd2l0aCB0aGUgc29jaW8tZWNvbm9taWMgc3RhdHVzIChTKS4KCi0gQ2hpbGRyZW4gb2YgbG93ZXIgc29jaW8tZWNvbm9taWMgc3RhdHVzIHdlcmUgbW9yZSByZXNpc3RhbnQgdG8gdGhlIGRpc2Vhc2UuCgotIFRoZSBncm91cHMgb2YgY2FzZXMgYW5kIGNvbnRyb2xzIGFyZSBub3QgY29tcGFyYWJsZToKICAgIC0gZGlmZmVyZW5jZSBpbiBhZ2UsCiAgICAtIGRpZmZlcmVuY2UgaW4gc29jaW8tZWNvbm9taWMgc3RhdHVzIGFuZAogICAgLSBkaWZmZXJlbmNlIGluIHN1c2NlcHRpYmxlIGZvciBkaXNlYXNlLgoKLS0tCgojIyBTYWxrIFN0dWR5CgojIyMgRGVzaWduCgpBIG5ldyBzdHVkeSB3YXMgY29uZHVjdGVkOiBSYW5kb21pemVkIGRvdWJsZSBibGluZCBzdHVkeQoKICAtIENoaWxkcmVuIGFyZSBhc3NpZ25lZCBhdCByYW5kb20gdG8gdGhlIGNvbnRyb2wgb3IgY2FzZSB0cmVhdG1lbnQgYXJtIGFmdGVyIGNvbnNlbnQgd2FzIGdpdmVuIGJ5IHRoZSBwYXJlbnRzLgogIC0gQ29udHJvbDogdmFjY2luYXRpb24gd2l0aCBwbGFjZWJvCiAgLSBUcmVhdG1lbnQ6IHZhY2NpbmF0aW9uIHdpdGggdmFjY2luZQogIC0gZG91YmxlIGJsaW5kaW5nOgogICAgLSBwYXJlbnRzIGRpZCBub3Qga25vdyBpZiB0aGVpciBjaGlsZCB3YXMgdmFjY2luYXRlZCBvciByZWNlaXZlZCB0aGUgcGxhY2VibwogICAgLSBjYXJlLWdpdmVyL3Jlc2VhcmNoZXJzIGRpZCBub3Qga25vdyBpZiB0aGUgY2hpbGQgd2FzIHZhY2NpbmF0ZWQgIG9yIHJlY2VpdmVkIHBsYWNlYm8KCi0tLQoKIyMjIERhdGEKCmBgYHtyfQpzYWxrIDwtIGRhdGEuZnJhbWUoZ3JvdXAgPSBjKCJjYXNlcyIsICJjb250cm9sIiwgIm5vQ29uY2VudCIpLCB0cmVhdG1lbnQgPSBjKCJ2YWNjaW5lIiwgInBsYWNlYm8iLCAibm9uZSIpLCB0b3RhbCA9IGMoCiAgMjAwNzQ1LAogIDIwMTIyOSwgMzM4Nzc4CiksIHBvbGlvID0gYyg1NywgMTQyLCAxNTcpKQpzYWxrJG5vUG9saW8gPC0gc2FsayR0b3RhbCAtIHNhbGskcG9saW8Kc2FsayRpbmNpZGVuY2VQTSA8LSByb3VuZChzYWxrJHBvbGlvIC8gc2FsayR0b3RhbCAqIDFlNiwgMCkKa25pdHI6OmthYmxlKHNhbGspCmBgYAoKLSBXZSBvYnNlcnZlIGEgbXVjaCBsYXJnZXIgZWZmZWN0IG5vdyB0aGF0IHRoZSBjYXNlcyBhbmQgdGhlIGNvbnRyb2xzIGFyZSBjb21wYXJhYmxlLCBpbmNpZGVuY2Ugb2YgYHIgc2FsayRpbmNpZGVuY2VQTVsxXWAgIGFuZCBgciBzYWxrJGluY2lkZW5jZVBNWzJdYCBwZXIgbWlsbGlvbiwgcmVzcGVjdGl2ZWx5LgoKLSBUaGUgcG9saW8gaW5jaWRlbmNlIGZvciBjaGlsZHJlbiB3aXRoIG5vIGNvbnNlbnQgcmVtYWlucyBzaW1pbGFyLCBgciBuZmlwJGluY2lkZW5jZVBNWzNdYCBhbmQgYHIgc2FsayRpbmNpZGVuY2VQTVszXWAgcGVyIG1pbGxpb24gaW4gdGhlIE5GSVAgYW5kIFNhbGsgc3R1ZHksIHJlc3BlY3RpdmVseS4KCi0tLQoKIyBSb2xlIG9mIFN0YXRpc3RpY3MgaW4gdGhlIExpZmUgU2NpZW5jZXMKCi0gV2UgaGF2ZSBzZWVuIHRoYXQKICAgIC0gaXQgaXMgaW1wb3J0YW50IHRvIGNhcmVmdWxseSBzcGVjaWZ5IHRoZSBzY29wZSBvZiB0aGUgc3R1ZHkgYmVmb3JlIHRoZSBleHBlcmltZW50LAogICAgLSB0aGUgc2FtcGxlIHNpemUgbWF0dGVycywKICAgIC0gd2Ugc2hvdWxkIGJlIGF3YXJlIG9mIGNvbmZvdW5kaW5nLCBhbmQKICAgIC0gYSBwcm9wZXIgY29udHJvbCBpcyByZXF1aXJlZC4KCiRccmlnaHRhcnJvdyQgR29vZCBleHBlcmltZW50YWwgZGVzaWduIGlzIGNydWNpYWwhCgotIFdlIGFsc28gb2JzZXJ2ZWQgdGhhdCB0aGVyZSBpcyB2YXJpYWJpbGl0eSBpbiB0aGUgcG9wdWxhdGlvbiBhbmQgYmVjYXVzZSB3ZSBjYW4gb25seSBzYW1wbGUgYSBzbWFsbCBwYXJ0IG9mIHRoZSBwb3B1bGF0aW9uIG91ciByZXN1bHRzIGFuZCBjb25jbHVzaW9ucyBhcmUgc3ViamVjdGVkIHRvIHVuY2VydGFpbnR5LgoKLSBTdGF0aXN0aWNzIGlzIHRoZSBzY2llbmNlIG9uCiAgICAxLiBjb2xsZWN0aW5nIChleHBlcmltZW50YWwgZGVzaWduKSwKICAgIDIuIGV4cGxvcmluZyAoZGF0YSBleHBsb3JhdGlvbikgYW5kCiAgICAzLiBsZWFybmluZyBmcm9tIGRhdGEgYW5kIHRvIGdlbmVyYWxpemUgd2hhdCB3ZSBvYnNlcnZlIGluIHRoZSBzYW1wbGUgdG93YXJkcyB0aGUgcG9wdWxhdGlvbiB3aGlsZSBxdWFudGlmeWluZywgY29udHJvbGxpbmcgYW5kIHJlcG9ydGluZyB2YXJpYWJpbGl0eSBhbmQgdW5jZXJ0YWludHkgKHN0YXRpc3RpY2FsIG1vZGVsbGluZyBhbmQgc3RhdGlzdGljYWwgaW5mZXJlbmNlKS4KCi0gVGhlcmVmb3JlLCBzdGF0aXN0aWNzIHBsYXlzIGFuIGltcG9ydGFudCByb2xlIGluIGFsbW9zdCBhbGwgc2NpZW5jZXMgKGUuZy4gY29sdW1uICJwb2ludHMgb2Ygc2lnbmlmaWNhbmNlIiBpbiBOYXR1cmUgTWV0aG9kcy4gaHR0cDovL2Jsb2dzLm5hdHVyZS5jb20vbWV0aGFnb3JhLzIwMTMvMDgvZ2l2aW5nX3N0YXRpc3RpY3NfdGhlX2F0dGVudGlvbl9pdF9kZXNlcnZlcy5odG1sKQoKLS0tCgpgYGB7ciBwb3AyU2FtcDJQb3AsIG91dC53aWR0aD0nODAlJyxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIgJWluJSBscygpKSBybSgicGkiKQprb3B2b2V0ZXIgPC0gZnVuY3Rpb24oeCwgeSwgYW5nbGUgPSAwLCBsID0gLjIsIGNleC5kb3QgPSAuNSwgcGNoID0gMTksIGNvbCA9ICJibGFjayIpIHsKICBhbmdsZSA8LSBhbmdsZSAvIDE4MCAqIHBpCiAgcG9pbnRzKHgsIHksIGNleCA9IGNleC5kb3QsIHBjaCA9IHBjaCwgY29sID0gY29sKQogIGxpbmVzKGMoeCwgeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSksIGMoeSwgeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSksIGNvbCA9IGNvbCkKICBsaW5lcyhjKHggKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgYW5nbGUpLCB4ICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSArIGwgLyA0ICogY29zKGFuZ2xlKSksIGMoeSArIGwgLyAyICogc2luKC1waSAvIDIgKyBhbmdsZSksIHkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgYW5nbGUpICsgbCAvIDQgKiBzaW4oYW5nbGUpKSwgY29sID0gY29sKQogIGxpbmVzKGMoeCArIGwgLyAyICogY29zKC1waSAvIDIgKyBhbmdsZSksIHggKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgYW5nbGUpICsgbCAvIDQgKiBjb3MocGkgKyBhbmdsZSkpLCBjKHkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgYW5nbGUpLCB5ICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSArIGwgLyA0ICogc2luKHBpICsgYW5nbGUpKSwgY29sID0gY29sKQogIGxpbmVzKGMoeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSwgeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSArIGwgLyAyICogY29zKC1waSAvIDIgKyBwaSAvIDQgKyBhbmdsZSkpLCBjKHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSksIHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgcGkgLyA0ICsgYW5nbGUpKSwgY29sID0gY29sKQogIGxpbmVzKGMoeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSwgeCArIGwgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSArIGwgLyAyICogY29zKC1waSAvIDIgLSBwaSAvIDQgKyBhbmdsZSkpLCBjKHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSksIHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gMiAqIHNpbigtcGkgLyAyIC0gcGkgLyA0ICsgYW5nbGUpKSwgY29sID0gY29sKQp9CgpwYXIobWFyID0gYygwLCAwLCAwLCAwKSwgbWFpID0gYygwLCAwLCAwLCAwKSkKcGxvdCgwLCAwLCB4bGFiID0gIiIsIHlsYWIgPSAiIiwgeGxpbSA9IGMoMCwgMTApLCB5bGltID0gYygwLCAxMCksIGNvbCA9IDAsIHhheHQgPSAibm9uZSIsIHlheHQgPSAibm9uZSIsIGF4ZXMgPSBGQUxTRSkKcmVjdCgwLCA2LCAxMCwgMTAsIGJvcmRlciA9ICJyZWQiLCBsd2QgPSAyKQp0ZXh0KC41LCA4LCAicG9wdWxhdGlvbiIsIHNydCA9IDkwLCBjb2wgPSAicmVkIiwgY2V4ID0gMikKc3ltYm9scygzLCA4LCBjaXJjbGVzID0gMS41LCBjb2wgPSAicmVkIiwgYWRkID0gVFJVRSwgZmcgPSAicmVkIiwgaW5jaGVzID0gRkFMU0UsIGx3ZCA9IDIpCnNldC5zZWVkKDMzMCkKZ3JpZCA8LSBzZXEoMCwgMS4zLCAuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewogIGFuZ2xlMSA8LSBydW5pZihuID0gMSwgbWluID0gMCwgbWF4ID0gMzYwKQogIGFuZ2xlMiA8LSBydW5pZihuID0gMSwgbWluID0gMCwgbWF4ID0gMzYwKQogIHJhZGl1cyA8LSBzYW1wbGUoZ3JpZCwgcHJvYiA9IGdyaWReMiAqIHBpIC8gc3VtKGdyaWReMiAqIHBpKSwgc2l6ZSA9IDEpCiAga29wdm9ldGVyKDMgKyByYWRpdXMgKiBjb3MoYW5nbGUxIC8gMTgwICogcGkpLCA4ICsgcmFkaXVzICogc2luKGFuZ2xlMSAvIDE4MCAqIHBpKSwgYW5nbGUgPSBhbmdsZTIpCn0KdGV4dCg3LjUsIDgsICJjaG9sZXN0ZXJvbCBpbiBwb3B1bGF0aW9uIiwgY29sID0gInJlZCIsIGNleCA9IDEuMikKCnJlY3QoMCwgMCwgMTAsIDQsIGJvcmRlciA9ICJibHVlIiwgbHdkID0gMikKdGV4dCguNSwgMiwgInNhbXBsZSIsIHNydCA9IDkwLCBjb2wgPSAiYmx1ZSIsIGNleCA9IDIpCnN5bWJvbHMoMywgMiwgY2lyY2xlcyA9IDEuNSwgY29sID0gInJlZCIsIGFkZCA9IFRSVUUsIGZnID0gImJsdWUiLCBpbmNoZXMgPSBGQUxTRSwgbHdkID0gMikKZm9yIChpIGluIDA6MikgewogIGZvciAoaiBpbiAwOjQpCiAgewogICAga29wdm9ldGVyKDIuMSArIGogKiAoMy45IC0gMi4xKSAvIDQsIDEuMSArIGkpCiAgfQp9CnRleHQoNy41LCAyLCAiY2hvbGVzdGVyb2wgaW4gc2FtcGxlIiwgY29sID0gImJsdWUiLCBjZXggPSAxLjIpCgphcnJvd3MoMywgNS45LCAzLCA0LjEsIGNvbCA9ICJibGFjayIsIGx3ZCA9IDMpCmFycm93cyg3LCA0LjEsIDcsIDUuOSwgY29sID0gImJsYWNrIiwgbHdkID0gMykKdGV4dCgxLjUsIDUsICJFWFAuIERFU0lHTiAoMSkiLCBjb2wgPSAiYmxhY2siLCBjZXggPSAxLjIpCnRleHQoOC41LCA1LCAiRVNUSU1BVElPTiAmXG5JTkZFUkVOQ0UgKDMpIiwgY29sID0gImJsYWNrIiwgY2V4ID0gMS4yKQp0ZXh0KDcuNSwgLjUsICJEQVRBIEVYUExPUkFUSU9OICZcbkRFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgKDIpIiwgY29sID0gImJsYWNrIiwgY2V4ID0gMS4yKQpgYGAK