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_at("cholLog",
list(mean=~mean(.,na.rm=TRUE),
sd=~sd(.,na.rm=TRUE),
n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
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_at("cholLog",
list(mean=~mean(.,na.rm=TRUE),
sd=~sd(.,na.rm=TRUE),
n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
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_at("cholLog",
list(mean=~mean(.,na.rm=TRUE),
sd=~sd(.,na.rm=TRUE),
n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
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_at("cholLog",
list(mean=~mean(.,na.rm=TRUE),
sd=~sd(.,na.rm=TRUE),
n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
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?
LS0tCnRpdGxlOiAiMS4gSW50cm9kdWN0aW9uOiBXaHkgZG8gd2UgbmVlZCBzdGF0aXN0aWNzIiAKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCm91dHB1dDoKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgICAgCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICB0b2M6IHRydWUKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgojIE1vdGl2YXRpb24gCjxhIHJlbD0ibGljZW5zZSIgaHJlZj0iaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMCI+PGltZyBhbHQ9IkNyZWF0aXZlIENvbW1vbnMgTGljZW5zZSIgc3R5bGU9ImJvcmRlci13aWR0aDowIiBzcmM9Imh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnktbmMtc2EvNC4wLzg4eDMxLnBuZyIgLz48L2E+CgohW10oaHR0cHM6Ly9pbWFnZXMubWFydGVjaGFkdmlzb3IuY29tL2ltYWdlcy91cGxvYWRzL2NvbnRlbnRfaW1hZ2VzL3dheXNfdG9fY2FwdHVyZV9iMmJfY3VzdG9tZXJfZGF0YV81YmFjZDJkYmUxYTA5LnBuZykKCiFbXSguL2ZpZ3VyZXMvd3BHcmFwaC5qcGVnKQoKLSBXZSBsaXZlIGluIGEgYmlnIGRhdGEgZXJhCi0gRGF0YSBvbiBsb2NhdGlvbiwgY2xpY2tzLCBlLWNvbW1lcmNlLCBzb2NpYWwgbWVkaWEgLi4uCi0gTGlmZSBTY2llbmNlczogbWVhc3VyZSBleHByZXNzaW9uIG9mIHRob3VzYW5kcyBvZiBnZW5lcywgcHJvdGVpbnMsIC4uLiBmb3IgZWFjaCBzdWJqZWN0IG9yIGV2ZW4gaW5kaXZpZHVhbCBjZWxscyAKLSBEYXRhIGRyaXZlbiBqb3VybmFsaXNtCi0gLi4uCgpTdGF0aXN0aWNzIGlzIHRoZSBzY2llbmNlIHRvIGxlYXJuIGZyb20gZW1waXJpY2FsIGRhdGEuIAoKU3RhdGlzdGljYWwgbGl0ZXJhY3kgaXMga2V5IHRvIGludGVycHJldCByZXN1bHRzIGZyb20gc2NpZW50aWZpYyBwdWJsaWNhdGlvbnMuCgoKCiMjIFRoZXJlIGFyZSB0aHJlZSB0eXBlcyBvZiBsaWVzOiBsaWVzLCBkYW1uIGxpZXMgYW5kIHN0YXRpc3RpY3Mgey19CgotLS0KCiMjIFRoZXJlIGFyZSB0aHJlZSB0eXBlcyBvZiBsaWVzOiBsaWVzLCBkYW1uIGxpZXMgYW5kIGJhZCBzdGF0aXN0aWNzIHstfQoKLS0tCgpodHRwczovL3d3dy5tZWRyeGl2Lm9yZy9jb250ZW50LzEwLjExMDEvMjAyMC4wNy4xNy4yMDE1NTg0NnYxCgohW10oaHR0cHM6Ly9naXRodWIuY29tL3N0YXRPbWljcy9zYmMyMC9yYXcvbWFzdGVyL2ZpZ3VyZXMvRm9uc2VjYTIwMjBDb3ZpZFZlZ2V0YWJsZXMucG5nKQoKLS0tCgohW10oaHR0cHM6Ly9naXRodWIuY29tL3N0YXRPbWljcy9zYmMyMC9yYXcvbWFzdGVyL2ZpZ3VyZXMvY292aWRWZWdldGFibGVzNi5wbmcpe3dpZHRoPTcwJX0KCgotLS0KCiFbXShodHRwczovL2dpdGh1Yi5jb20vc3RhdE9taWNzL3NiYzIwL3Jhdy9tYXN0ZXIvZmlndXJlcy9jb3ZpZFZlZ2V0YWJsZXMucG5nKXt3aWR0aD03MCV9CgoiVGhlIGF1dGhvcnMgc3RhdGU6IFRoZSBuZWdhdGl2ZSBlY29sb2dpY2FsIGFzc29jaWF0aW9uIGJldHdlZW4gQ09WSUQtMTkgbW9ydGFsaXR5IGFuZCB0aGUgY29uc3VtcHRpb24gb2YgY2FiYmFnZSBhbmQgY3VjdW1iZXIgc3VwcG9ydHMgdGhlIGEgcHJpb3JpIGh5cG90aGVzaXMgcHJldmlvdXNseSByZXBvcnRlZC4KSW4gdGhpcyBoeXBvdGhlc2lzLCB3ZSBwcm9wb3NlZCB0aGF0IHZlZ2V0YWJsZXMgc3VjaCBhcyBCcmFzc2ljYSAtIHdpdGggYW4gYW50aW94aWRhbnQgYWN0aXZpdHkgcmVkdWNpbmcgaW5zdWxpbiByZXNpc3RhbmNlIC0gbWF5IGFsc28gYmUgYXNzb2NpYXRlZCB3aXRoIGxvdyBDT1ZJRC0xOSBtb3J0YWxpdHkgaW4gY291bnRyaWVzLgoiCgoiClRob3VnaCBvdXIgcmVzdWx0cyBkbyBub3QgYWxsb3cgdG8gaW5mZXIgY2F1c2FsaXR5LCB0aGV5IGRvIHJlaW5mb3JjZSBvdXIgYSBwcmlvcnkgaHlwb3RoZXNpcyB0aGF0IHRoZSBpbmdlc3Rpb24gb2YgYW50aS1veGlkYW50IGZvb2RzIGFjdGluZyBvbiBpbnN1bGluIGludG9sZXJhbmNlIG1heSBoYXZlIHJlZHVjZWQgdGhlIHNldmVyaXR5IG9mIENPVklELTE5LgoiCgotLS0KCiFbXShodHRwczovL2dpdGh1Yi5jb20vc3RhdE9taWNzL3NiYzIwL3Jhdy9tYXN0ZXIvZmlndXJlcy9jb3ZpZFZlZ2V0YWJsZXM0LnBuZykKCi0tLQoKIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9zdGF0T21pY3Mvc2JjMjAvcmF3L21hc3Rlci9maWd1cmVzL2NvdmlkVmVnZXRhYmxlczMucG5nKQoKLSBNYW55IGh5cG90aGVzZXMgYXJlIGFzc2Vzc2VkID8hCi0gQ2F1c2FsaXR5ID8hCi0gRXhwZXJpbWVudGFsIGRlc2lnbjogT2JzZXJ2YXRpb25hbCBzdHVkeQotIEJhc2VkIG9uIHRoZSBkYXRhIHdlIGNhbm5vdCBwcm92aWRlIHJlY29tbWVuZGF0aW9ucyBhdCB0aGUgc3ViamVjdCBsZXZlbAoKLS0tCgohW10oaHR0cHM6Ly9naXRodWIuY29tL3N0YXRPbWljcy9zYmMyMC9yYXcvbWFzdGVyL2ZpZ3VyZXMvY292aWRWZWdldGFibGVzMi5wbmcpe3dpZHRoPTcwJX0KCi0gSW1wb3J0YW5jZSBvZiBEYXRhIEV4cGxvcmF0aW9uIQotIERhdGEgZG9lcyBub3QgZXhoaWJpdCB0aGUgdHJlbmQKLSBEYXRhIHNob3dzIGV2aWRlbmNlIGZvciB0d28gY2x1c3RlcnM6IGFib3ZlIGFuZCBiZWxvdyAyMDAgZGVhdGhzL21pbGxpb24KLSBNb2RlbCBmb3IgY3VjdW1iZXIgZG9lcyBub3QgbW9kZWwgdGhlIGRhdGEgY29ycmVjdGx5OiBPdmVyZXN0aW1hdGlvbiBvZiBkZWF0aCByYXRlIGZvciBtYW55IGNvdW50cmllcyBlLmcuIFBvcnR1Z2FsLCBIdW5nYXJ5LCAuLi4KCi0tLQoKYGBge3IgZWNobz1GQUxTRSxvdXQud2lkdGg9IjEwJSIsb3V0LmV4dHJhPSdzdHlsZT0iZmxvYXQ6cmlnaHQ7IHBhZGRpbmc6MTBweCInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiLi9maWd1cmVzL2ZlYXIucG5nIikKYGBgCgpQYXBlcnMgYXJlIG1lcmdlZCwgcHVibGlzaGVkLCBhbmQgMzkgdGltZXMgY2l0ZWQgCgpCb3VzcXVldCBldCBhbC4gKDIwMjEpLiBDYWJiYWdlIGFuZCBmZXJtZW50ZWQgdmVnZXRhYmxlczogRnJvbSBkZWF0aCByYXRlIGhldGVyb2dlbmVpdHkgaW4gY291bnRyaWVzIHRvIGNhbmRpZGF0ZXMgZm9yIG1pdGlnYXRpb24gc3RyYXRlZ2llcyBvZiBzZXZlcmUgQ09WSUQtMTkuIEFsbGVyZ3kgNzY6NzM14oCTNzUwLgoKLS0tCgpJbiB0aGUgZXhhbXBsZSB3ZSBjb3ZlcmVkIGlzc3VlcyB3aXRoIHRocmVlIGltcG9ydGFudCBicmFuY2hlcyBpbiBzdGF0aXN0aWNzCgoxLiBTdGF0aXN0aWNhbCBpbmZlcmVuY2UKCiAgLSBJcyB0aGVyZSBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuICBDT1ZJRC0xOSBtb3J0YWxpdHkgYW5kIGZvb2QgY29uc3VtcHRpb24/CiAgLSBJc3N1ZSBpbiBzdHVkeToKICAgICAgLSBkYXRhIGRyZWRnaW5nLCBwLWhhY2tpbmcsIC4uLjogd2hlbiB5b3UgYXNzZXNzIG1hbnkgaHlwb3RoZXNlcyB5b3Ugd2lsbCBhbGx3YXlzIGZpbmQgc3Ryb25nIHBhdHRlcm5zIGJ5IHJhbmRvbSBjaGFuZ2UgJFxyaWdodGFycm93JCBjb3JyZWN0IGZvciBtdWx0aXBsZSB0ZXN0aW5nISAKICAgICAgLSBBc3N1bXB0aW9ucyBvZiB0aGUgbW9kZWxzIGRvIG5vdCBob2xkCiAgICAgIC0gQ29uZm91bmRpbmcKCjIuIEV4cGVyaW1lbnRhbCBkZXNpZ24KCiAgICAtIENvbmZvdW5kaW5nOiBjb3VudHJpZXMgZG8gbm90IG9ubHkgZGlmZmVyIGluIGNvbnN1bXB0aW9uIG9mIGEgdmVnZXRhYmxlIGJ1dCBhbHNvIGluIG1heSBvdGhlciB2YXJpYWJsZXMgKGRlbW9ncmFwaGljYWwsIENPVklEIG1lYXN1cmVzLCBoZWFsdHkgY2FyZSwgLi4uKSB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggQ09WSUQgbW9ydGFsaXR5LiAKCiAgICAtIERpZmZpY3VsdCB0byBkcmF3IGNhdXNhbCBjb25jbHVzaW9ucyBmcm9tIG9ic2VydmF0aW9uYWwgc3R1ZGllcy4gCiAgICAKICAgIC0gSW4gZXhwZXJpbWVudGFsIHN0dWRpZXM6IHJhbmRvbWlzYXRpb24hICRccmlnaHRhcnJvdyQgc28gdGhhdCAgdGhlIGdyb3VwcyBvbmx5IGRpZmZlciBpbiB0aGUgdHJlYXRtZW50LiAKICAgIAogICAgLSBFeHBlcmltZW50YWwgc3R1ZGllcyBhcmUgdGhlcmVmb3JlIHRoZSBnb2xkZW4gc3RhbmRhcmQKCjMuIERhdGEgZXhwbG9yYXRpb24gYW5kIHZpc3VhbGlzYXRpb24KCiAgICAtIENydWNpYWwgdG8gZ2V0IGluc2lnaHQgaW4gdGhlIGRhdGEhCiAgICAtIEFzc2VzcyBtb2RlbCBhc3N1bXB0aW9ucwoKLS0tCgojIFNtZWxseSBhcm1waXQgZXhhbXBsZQoKLSBTbWVsbHkgYXJtcGl0cyBhcmUgbm90IGNhdXNlZCBieSBzd2VhdCBpdHNlbGYuIFRoZSBzbWVsbCBpcyBjYXVzZWQgYnkgc3BlY2lmaWMgbWljcm8tb3JnYW5pc21zIGJlbG9uZ2luZyB0byB0aGUgZ3JvdXAgb2YgKkNvcnluZWJhY3Rlcml1bSBzcHAuKiB0aGF0IG1ldGFib2xpc2Ugc3dlYXQuCkFub3RoZXIgZ3JvdXAgb2YgYWJ1bmRhbnQgYmFjdGVyaWEgYXJlIHRoZSAqU3RhcGh5bG9jb2NjdXMgc3BwLiosIHRoZXNlIGJhY3RlcmlhIGRvIG5vdCBtZXRhYm9saXNlIHN3ZWF0IGluIHNtZWxseSBjb21wb3VuZHMuCgotIFRoZSBDTUVULWdyb2VwIGF0IEdoZW50IFVuaXZlcnNpdHkgZG9lcyByZXNlYXJjaCBvbiB0cmFuc3BsYW50aW5nIHRoZSBhcm1waXQgbWljcm9iaW9tZSB0byBzYXZlIHBlb3BsZSB3aXRoIHNtZWxseSBhcm1waXRzLgoKLSBQcm9wb3NlZCBUaGVyYXB5OgogIAkxLiBSZW1vdmUgYXJtcGl0LW1pY3JvYmlvbWUgd2l0aCBhbnRpYmlvdGljcwogICAgMi4gSW5mbHVlbmNlIGFybXBpdCBtaWNyb2Jpb21lIHdpdGggbWljcm9iaWFsICB0cmFuc3BsYW50IChodHRwczovL3lvdXR1LmJlLzlSSUZ5cUxYZFZ3KQoKCmBgYHtyIG91dC53aWR0aD0nODAlJyxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIlaW4lbHMoKSkgcm0oInBpIikKa29wdm9ldGVyPC1mdW5jdGlvbih4LHksYW5nbGU9MCxsPS4yLGNleC5kb3Q9LjUscGNoPTE5LGNvbD0iYmxhY2siKQp7CmFuZ2xlPWFuZ2xlLzE4MCpwaQpwb2ludHMoeCx5LGNleD1jZXguZG90LHBjaD1wY2gsY29sPWNvbCkKbGluZXMoYyh4LHgrbCpjb3MoLXBpLzIrYW5nbGUpKSxjKHkseStsKnNpbigtcGkvMithbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MoYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKGFuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhwaSthbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4ocGkrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzIrcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMitwaS80K2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yLXBpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzItcGkvNCthbmdsZSkpLGNvbD1jb2wpCn0KCnBhcihtYXI9YygwLDAsMCwwKSxtYWk9YygwLDAsMCwwKSkKcGxvdCgwLDAseGxhYj0iIix5bGFiPSIiLHhsaW09YygwLDEwKSx5bGltPWMoMCwxMCksY29sPTAseGF4dD0ibm9uZSIseWF4dD0ibm9uZSIsYXhlcz1GQUxTRSkKcmVjdCgwLDYsMTAsMTAsYm9yZGVyPSJyZWQiLGx3ZD0yKQp0ZXh0KC41LDgsInBvcHVsYXRpb24iLHNydD05MCxjb2w9InJlZCIsY2V4PTIpCnN5bWJvbHMgKDMsIDgsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9InJlZCIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpzZXQuc2VlZCgzMzApCmdyaWQ9c2VxKDAsMS4zLC4wMSkKCmZvciAoaSBpbiAxOjUwKQp7CglhbmdsZTE9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglhbmdsZTI9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglyYWRpdXM9c2FtcGxlKGdyaWQscHJvYj1ncmlkXjIqcGkvc3VtKGdyaWReMipwaSksc2l6ZT0xKQoJa29wdm9ldGVyKDMrcmFkaXVzKmNvcyhhbmdsZTEvMTgwKnBpKSw4K3JhZGl1cypzaW4oYW5nbGUxLzE4MCpwaSksYW5nbGU9YW5nbGUyKQp9CnRleHQoNy41LDgsIk1pY3JvYmlvbWUgaW4gcG9wdWxhdGlvbiIsY29sPSJyZWQiLGNleD0xLjIpCgpyZWN0KDAsMCwxMCw0LGJvcmRlcj0iYmx1ZSIsbHdkPTIpCnRleHQoLjUsMiwic2FtcGxlIixzcnQ9OTAsY29sPSJibHVlIixjZXg9MikKc3ltYm9scyAoMywgMiwgY2lyY2xlcz0xLjUsIGNvbD0icmVkIixhZGQ9VFJVRSxmZz0iYmx1ZSIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpmb3IgKGkgaW4gMDoxKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjEraS8yLGNvbD0icHVycGxlIikKfQpmb3IgKGkgaW4gMjozKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjYraS8yLGNvbD0ib3JhbmdlIikKfQp0ZXh0KDcuNSwyLCJNaWNyb2Jpb21lIGluIHNhbXBsZSIsY29sPSJibHVlIixjZXg9MS4yKQoKYXJyb3dzKDMsNS45LDMsNC4xLGNvbD0iYmxhY2siLGx3ZD0zKQp0ZXh0KDEuNSw1LCJFWFAuIERFU0lHTiAoMSkiLGNvbD0iYmxhY2siLGNleD0xLjIpCnRleHQoNy41LC41LCJEQVRBIEVYUExPUkFUSU9OICZcbkRFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgKDIpIixjb2w9ImJsYWNrIixjZXg9MS4yKQphcnJvd3MoNyw0LjEsNyw1LjksY29sPSJibGFjayIsbHdkPTMpCnRleHQoOC41LDUsIkVTVElNQVRJT04gJlxuSU5GRVJFTkNFICgzKSIsY29sPSJibGFjayIsY2V4PTEuMikKYGBgCgoKLSBFeHBlcmltZW50OgoKICAgIC0gMjAgc3ViamVjdHMgd2l0aCBzbWVsbHkgYXJtcGl0cyBhcmUgYXR0cmlidXRlZCB0byBvbmUgb2YgdHdvIHRyZWF0bWVudCBncm91cHMKICAgIC0gcGxhY2VibyAob25seSBhbnRpYmlvdGljcykKICAgIC0gdHJhbnNwbGFudCAoYW50aWJpb3RpY3MgZm9sbG93ZWQgYnkgbWljcm9iaWFsIHRyYW5zcGxhbnQpLgogICAgLSBUaGUgbWljcm9iaW9tZSBpcyBzYW1wbGVkIDYgd2Vla3MgdXBvbiB0aGUgdHJlYXRtZW50LgogICAgLSBUaGUgcmVsYXRpdmUgYWJ1bmRhbmNlIG9mICpTdGFwaHlsb2NvY2N1cyBzcHAuKiBvbiAqQ29yeW5lYmFjdGVyaXVtIHNwcC4qICsgKlN0YXBoeWxvY29jY3VzIHNwcC4qIGluIHRoZSBtaWNyb2Jpb21lIGlzIG1lYXN1cmVkIHZpYSBER0dFICgqRGVuYXR1cmluZyBHcmFkaWVudCBHZWwgRWxlY3Ryb3Bob3Jlc2lzKikuCgotLS0KCiMjIEltcG9ydCB0aGUgZGF0YQpgYGB7cn0KcmVhZF9saW5lcygiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL2FybXBpdC5jc3YiKQpgYGAKClRoZSBmaWxlIGlzIGNvbW1hIHNlcGFyYXRlZCBhbmQgaW4gdGlkeSBmb3JtYXQKCmBgYHtyfQphcDwtcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HVFBCL1BTTFMyMC9tYXN0ZXIvZGF0YS9hcm1waXQuY3N2IikKYXAKYGBgCgotLS0KCiMjIERhdGEgRXhwbG9yYXRpb24gYW5kIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MKCi0gRGF0YSBleHBsb3JhdGlvbiBpcyBleHRyZW1lbHkgaW1wb3J0YW50IHRvIGdldCBpbnNpZ2h0IGluIHRoZSBkYXRhLiAKLSBJdCBpcyBvZnRlbiB1bmRlcnJhdGVkIGFuZCBvdmVybG9va2VkLiAKCiMjIyBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzCgpXZSBmaXJzdCBzdW1tYXJpemUgdGhlIGRhdGEgYW5kIGNhbGN1bGF0ZSB0aGUgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uLCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGFuZCBzdGFuZGFyZCBlcnJvciBhbmQgc3RvcmUgdGhlIHJlc3VsdCBpbiBhbiBvYmplY3QgYXBSZWxTdW0gdmlhICdhcFJlbFN1bTwtYAoKMS4gV2UgcGlwZSB0aGUgYGFwYCBkYXRhZnJhbWUgdG8gdGhlIGdyb3VwX2J5IGZ1bmN0aW9uIHRvIGdyb3VwIHRoZSBkYXRhIGJ5IHRyZWF0bWVudCB0cnQgYGdyb3VwX2J5KHRydClgCjIuIFdlIHBpcGUgdGhlIHJlc3VsdCB0byB0aGUgYHN1bW1hcml6ZV9hdGAgZnVuY3Rpb24gdG8gc3VtbWFyaXplIHRoZSAicmVsIiB2YXJpYWJsZSBhbmQgY2FsY3VsYXRlIHRoZSBtZWFuLCBzdGFuZGFyZCBkZXZpYXRpb24gYW5kIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIAozLiBXZSBwaXBlIHRoZSByZXN1bHQgdG8gdGhlIGBtdXRhdGVgIGZ1bmN0aW9uIHRvIG1ha2UgYSBuZXcgdmFyaWFibGUgaW4gdGhlIGRhdGEgZnJhbWUgYHNlYCBmb3Igd2hpY2ggd2UgY2FsY3VsYXRlIHRoZSBzdGFuZGFyZCBlcnJvciAKCgpgYGB7cn0KYXBSZWxTdW08LWFwJT4lCiAgZ3JvdXBfYnkodHJ0KSU+JQogIHN1bW1hcml6ZV9hdCgicmVsIiwKICAgICAgICAgICAgICAgbGlzdChtZWFuPX5tZWFuKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgc2Q9fnNkKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgbj1mdW5jdGlvbih4KSB4JT4laXMubmElPiVgIWAlPiVzdW0pKSAlPiUKICBtdXRhdGUoc2U9c2Qvc3FydChuKSkKCmFwUmVsU3VtCmBgYAoKLS0tCgojIyMgUGxvdHMKV2Ugd2lsbCB1c2UgZ2dwbG90MiB0byBtYWtlIG91ciBwbG90cy4gCldpdGggdGhlIGdncGxvdDIgbGlicmFyeSB3ZSBjYW4gZWFzaWx5IGJ1aWxkIHBsb3RzIGJ5IGFkZGluZyBsYXllcnMuCgojIyMjIGJhcnBsb3QKCjEuIFdlIHBpcGUgb3VyIHN1bW1hcml6ZWQgZGF0YSB0byB0aGUgYGdncGxvdGAgZnVuY3Rpb24gYW5kIHdlIHNlbGVjdCB0aGUgdHJlYXRtZW50IHZhcmlhYmxlIHRydCBhbmQgdGhlIHZhcmlhYmxlIG1lYW4gZm9yIHBsb3R0aW5nIGBhZXMoeD10cnQseT1tZWFuKWAKCjIuIFdlIG1ha2UgYSBiYXJwbG90IGJhc2VkIG9uIHRoaXMgZGF0YSB1c2luZyB0aGUgYGdlb21fYmFyYCBmdW5jdGlvbi4gVGhlIHN0YXRpc3RpYyBpcyBgc3RhdD0iaWRlbnRpdHkiYCBiZWNhdXNlIHRoZSBiYXIgaGVpZ2h0IHNob3VsZCBiZSBlcXVhbCB0aGUgdmFsdWUgZm9yIHRoZSBtZWFuIG9mIHRoZSByZWxhdGl2ZSBhYnVuZGFuY2UuCgpgYGB7cn0KYXBSZWxTdW0lPiUgCiAgZ2dwbG90KGFlcyh4PXRydCx5PW1lYW4pKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSAKYGBgCgotIElzIHRoaXMgcGxvdCBpbmZvcm1hdGl2ZT8/CgotLS0KCldlIHdpbGwgbm93IGFkZCBzdGFuZGFyZCBlcnJvcnMgdG8gdGhlIHBsb3QKdXNpbmcgYGdlb21fZXJyb3JiYXJgIGZ1bmN0aW9uIGFuZCBzcGVjaWZ5IHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHZhbHVlIGZvciBvZiB0aGUgZXJyb3IgYmFyLCB0aGUgd2lkdGggY29tbWFuZCBpcyB1c2VkIHRvIHNldCB0aGUgd2lkdGggb2YgdGhlIGVycm9yIGJhciBzbWFsbGVyIHRoYW4gdGhlIHdpZHRoIG9mIHRoZSBiYXIuIAoKYGBge3J9CmFwUmVsU3VtJT4lIAogIGdncGxvdChhZXMoeD10cnQseT1tZWFuKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKyAKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2UseW1heD1tZWFuK3NlKSx3aWR0aD0uMikKYGBgCgotIElzIHRoaXMgcGxvdCBpbmZvcm1hdGl2ZT8/CgotLS0KCiMjIyMgYm94cGxvdHMKCkkgY29uc2lkZXIgYmFycGxvdHMgdG8gYmUgYmFkIHBsb3RzCgotIFRoZXkgYXJlIG5vdCBpbmZvcm1hdGl2ZQotIFRoZXkganVzdCB2aXN1YWxpemUgYSB0d28gcG9pbnQgc3VtbWFyeSBvZiB0aGUgZGF0YS4gSXQgaXMgYmV0dGVyIHRvIGRvIHRoaXMgaW4gYSB0YWJsZQotIFRoZXkgdXNlIGEgbG90IG9mIHNwYWNlIChlLmcuIGZyb20gemVybyB1cCB0byB0aGUgbWluaW11bSByZWxhdGl2ZSBhYnVuZGFuY2UpIHdoZXJlIG5vIGRhdGEgYXJlIHByZXNlbnQuIAoKSXQgaXMgYmV0dGVyIHRvIGdldCBhIHZpZXcgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YS4gV2UgY2FuIHVzZSBhIGJveHBsb3QgZm9yIHRoaXMgcHVycG9zZS4KV2UgZmlyc3QgZXhwbGFpbiB3aGF0IGEgYm94cGxvdC4gCgotLS0KCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpmZW0gPC0gTkhBTkVTOjpOSEFORVMgJT4lIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiICYgIWlzLm5hKERpcmVjdENob2wpKSAlPiUgc2VsZWN0KERpcmVjdENob2wpCmJveHBsb3QoZmVtJERpcmVjdENob2wsIHlsYWI9IkRpcmVjdCBjaG9sZXN0ZXJvbCIsY2V4LmxhYj0xLjUsY2V4LmF4aXM9MS41LGNleC5tYWluPTEuNSkKcmFuZ2VDbDwtcXVhbnRpbGUoZmVtJERpcmVjdENob2wsYyguMjUsLjc1KSkrYygtMSwxKSpkaWZmKHF1YW50aWxlKGZlbSREaXJlY3RDaG9sLGMoLjI1LC43NSkpKSoxLjUKYm94WXM8LWMocmFuZ2UoZmVtJERpcmVjdENob2xbZmVtJERpcmVjdENob2w8PXJhbmdlQ2xbMl0mZmVtJERpcmVjdENob2w+PXJhbmdlQ2xbMV1dKSxxdWFudGlsZShmZW0kRGlyZWN0Q2hvbCxjKC4yNSwuNSwuNzUpKSxyYW5nZUNsWzJdKyhtYXgoZmVtJERpcmVjdENob2wpLXJhbmdlQ2xbMl0pLzIpCnRleHQoMS4zLGJveFlzLGxhYmVscz1jKCJ3aXNrZXIiLCJ3aXNrZXIiLCJ4MjUiLCJtZWRpYWFuIiwieDc1Iiwib3V0bGllcnMiKSxwb3M9NCxjZXg9MS4zKQpsaW5lcyhjKDEuMSwxLjMsMS4zLDEuMSksYyhyYW5nZUNsWzJdLHJhbmdlQ2xbMl0rKG1heChmZW0kRGlyZWN0Q2hvbCktcmFuZ2VDbFsyXSkvMixyYW5nZUNsWzJdKyhtYXgoZmVtJERpcmVjdENob2wpLXJhbmdlQ2xbMl0pLzIsbWF4KGZlbSREaXJlY3RDaG9sKSksbHR5PTIpCmBgYAoKLS0tCgpXZSB3aWxsIG5vdyBtYWtlIGEgYm94cGxvdCBmb3IgdGhlIGFwIGRhdGEKCjEuIFdlIHBpcGUgdGhlIGBhcGAgZGF0YWZyYW1lIHRvIHRoZSBnZ3Bsb3QgY29tbWFuZAoyLiBXZSBzZWxlY3QgdGhlIGRhdGEgd2l0aCB0aGUgY29tbWFuZCBgZ2dwbG90KGFlcyh4PXRydCx5PXJlbCkpYAozLiBXZSBhZGQgYSBib3hwbG90IHdpdGggdGhlIGNvbW1hbmQgYGdlb21fYm94cGxvdCgpYAogICAgCmBgYHtyfQphcCAlPiUgIAogIGdncGxvdChhZXMoeD10cnQseT1yZWwpKSArIAogIGdlb21fYm94cGxvdCgpCmBgYAoKLS0tCgotIE5vdGUsIHRoYXQgd2UgZG8gbm90IGhhdmUgc28gbWFueSBvYnNlcnZhdGlvbnMuCgotIEl0IGlzIGFsd2F5cyBiZXR0ZXIgdG8gc2hvdyB0aGUgZGF0YSBhcyByYXcgYXMgcG9zc2libGUhCgpXZSB3aWxsIG5vdyBhZGQgdGhlIHJhdyBkYXRhIHRvIHRoZSBwbG90LgoKLSBOb3RlIHRoYXQgd2Ugc2V0IHRoZSBvdXRsaWVyLnNoYXBlPU5BIGluIHRoZSBnZW9tX2JveHBsb3QgZnVuY3Rpb24gYmVjYXVzZSBiZWNhdXNlIHdlIHdpbGwgYWRkIGFsbCByYXcgZGF0YSBhbnl3YXkuCi0gV2UgYWRkIHRoZSByYXcgZGF0YSB1c2luZyBgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIilgLCB3aXRoIHRoZSBhcmd1bWVudCBwb3NpdGlvbj0naml0dGVyJyB3ZSB3aWxsIGFkZCBzb21lIHJhbmRvbSBub2lzZSB0byB0aGUgeCBjb29yZGluYXRlIHNvIHRoYXQgd2UgY2FuIHNlZSBhbGwgZGF0YS4KCmBgYHtyfQphcCAlPiUgIAogIGdncGxvdChhZXMoeD10cnQseT1yZWwpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGU9TkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKQpgYGAKClRoaXMgaXMgYW4gaW5mb3JtYXRpdmUgcGxvdCEKCi0tLQoKLSBXZSBvYnNlcnZlZCBhbiBlZmZlY3Qgb2YgdGhlIHRyYW5zcGxhbnRhdGlvbiBvbiB0aGUgcmVsYXRpZXZlIGFidW5kYW50aWUgb2YgU3RhcGh5bG9jb2NjdXMuCgotIElzIHRoYXQgZWZmZWN0IGxhcmdlIGVub3VnaCB0byBjb25jbHVkZSB0aGF0IHRoZSB0cmVhdG1lbnQgd29ya3M/IAoKLS0tCgojIyBFc3RpbWF0aW9uIGFuZCBzdGF0aXN0aWNhbCBpbmZlcmVuY2UgCgotIEluZHVjdGlvbjogV2l0aCBzdGF0aXN0aWNhbCBpbmZlcmVuY2Ugd2UgY2FuIGdlbmVyYWxpemUgd2hhdCB3ZSBvYnNlcnZlIGluIHRoZSBzYW1wbGUgdG93YXJkcyB0aGUgcG9wdWxhdGlvbi4gCgotIFRoZSBwcmljZSB0aGF0IHdlIGhhdmUgdG8gcGF5OiB1bmNlcnRhaW50eSBvbiBvdXIgY29uY2x1c2lvbnMhIAoKLS0tCgotIFdpdGggZGF0YSB3ZSBjYW5ub3QgcHJvdmUgdGhhdCB0aGUgdHJlYXRtZW50IHdvcmtzCgotIEZhbHNpZmljYXRpb24gcHJpbmNpcGxlIG9mIFBvcHBlcjogV2l0aCBkYXRhIHdlIGNhbiBvbmx5ICByZWplY3QgYSBoeXBvdGhlc2lzIG9yIHRoZW9yeS4gCgotIFdpdGggc3RhdHMgd2UgY2FuIHRodXMgbm90IHByb3ZlIHRoYXQgdGhlIHRyZWF0bWVudCB3b3Jrcy4gCgotIEJ1dCBzdGF0cyB3aWxsIGFsbG93IHVzIHRvIGZhbGNpZnkgdGhlIG9wcG9zaXRlIGh5cG90aGVzaXM6IGhvdyBtdWNoIGV2aWRlbmNlIGlzIHRoZXJlIGluIHRoZSBkYXRhIGFnYWluc3QgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGVyZSBpcyBubyBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudD8KCi0gV2l0aCBzdGF0cyB3ZSBjYW4gY2FsY3VsYXRlIGhvdyBsaWtlbHkgaXQgaXMgdG8gZHJhdyBhIHJhbmRvbSBzYW1wbGUgKHdoZW4geW91IHdvdWxkIHJlcGVhdCB0aGUgZXhwZXJpbWVudCkgd2l0aCBhIG1lYW4gZGlmZmVyZW5jZSBpbiByZWxhdGl2ZSBhYnVuZGFuY2UgYmV0d2VlbiB0cmFuc3BsYW50IGFuZCBwbGFjZWJvIGdyb3VwIHRoYXQgaXMgYXQgbGVhc3QgYXMgbGFyZ2UgYXMgd2hhdCB3ZSBvYnNlcnZlZCBpbiBvdXIgc2FtcGxlIHdoZW4gdGhlcmUgd291bGQgYmUgbm8gZWZmZWN0IG9mIHRoZSB0cmVhdG1lbnQuIAoKLSBUaGlzIHByb2JhYmlsaXR5IGlzIGNhbGxlZCBhIHAtdmFsdWUuCgotIElmIHAgaXMgdmVyeSBzbWFsbCwgaXQgaXMgdmVyeSB1bmxpa2VseSB0byBvYnNlcnZlIGEgc2FtcGxlIGxpa2Ugb3VycyBieSByYW5kb20gY2hhbmdlIHdoZW4gdGhlcmUgd291bGQgYmUgbm8gZWZmZWN0IG9mIHRoZSB0cmVhdG1lbnQuIAoKLSBXZSB0eXBpY2FsbHkgY29tcGFyZSBwIHdpdGggNSUuIElmIHRoZXJlIGlzIG5vIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50IHdlIHdpbGwgdGh1cyB0b2xlcmF0ZSBhIHByb2JhYmlsaXR5IG9mIDUlIG9uIGEgZmFsc2UgcG9zaXRpdmUgY29uY2x1c2lvbi4gCgotIFRvIGNhbGN1bGF0ZSBwIHdlIHdpbGwgaGF2ZSB0byBtb2RlbCB0aGUgZGF0YSB1c2luZyAgc3RhdGlzdGljYWwgbW9kZWxzLgoKLS0tCgpJbiBjaGFwdGVyIDUgd2Ugd2lsbCBsZWFybiB0aGF0IHdlIGNhbiB1c2UgYSB0d28tc2FtcGxlIHQtdGVzdCB0byBnZW5lcmFsaXNlIHdoYXQgd2Ugb2JzZXJ2ZSBpbiB0aGUgbWljcm9iaW9tZSBkYXRhc2V0IHRvd2FyZHMgdGhlIHBvcHVsYXRpb24uIAoKYGBge3J9CnQudGVzdChyZWx+dHJ0LGRhdGE9YXApCmBgYAoKQ29uY2x1c2lvbjoKCldlIGNhbiBjb25jbHVkZSB0aGF0IHRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgU3RhcGh5bG9jb2NjdXMgaW4gdGhlIG1pY3JvYmlvbWUgb2YgaW5kaXZpZHVhbHMgd2l0aCBzbWVsbHkgYXJtcGl0cyAgaXMgYHIgZm9ybWF0KGFwUmVsU3VtJG1lYW5bMl0tYXBSZWxTdW0kbWVhblsxXSxkaWdpdHM9MylgJSBoaWdoZXIgdXBvbiB0aGUgdHJhbnNwbGFudCB0aGFuIHVwb24gdGhlIHBsYWNlYm8gdHJlYXRtZW50IChwIDwgMC4wMDEpLiAKCi0tLQoKIyMgU29tZSBjb25jZXB0cwoKV2hhdCBhcmUgdGhlIGNvbnNlcXVlbmNlcyBvZiB1c2luZyBhIHNhbXBsZSBhbmQgcmFuZG9taXNhdGlvbj8KCi0gUmFuZG9tIHNhbXBsaW5nIGlzIGNsb3NlbHkgcmVsYXRlZCB0byB0aGUgY29uY2VwdCBvZiB0aGUgcG9wdWxhdGlvbiBvciB0aGUgc2NvcGUgb2YgdGhlIHN0dWR5LgoKLSBCYXNlZCBvbiBhIHNhbXBsZSBvZiBzdWJqZWN0cywgdGhlIHJlc2VhcmNoZXJzIHdhbnQgdG8gY29tZSB0byBjb25jbHVzaW9ucyB0aGF0IGhvbGQgZm9yCgogICAgLSBhbGwga2luZHMgb2YgcGVvcGxlCiAgICAtIG9ubHkgbWFsZSBzdHVkZW50cwoKLSBTY29wZSBvZiB0aGUgc3R1ZHkgc2hvdWxkIGJlIHdlbGwgc3BlY2lmaWVkIGJlZm9yZSB0aGUgc3RhcnQgb2YgdGhlIHN0dWR5LgoKLSBGb3IgdGhlIHN0YXRpc3RpY2FsIGFuYWx5c2lzIHRvIGJlIHZhbGlkLCBpdCBpcyByZXF1aXJlZCB0aGF0IHRoZSBzdWJqZWN0cyBhcmUgc2VsZWN0ZWQgY29tcGxldGVseSBhdCByYW5kb20gZnJvbSB0aGUgcG9wdWxhdGlvbiB0byB3aGljaCB3ZSB3YW50IHRvIGdlbmVyYWxpemUgb3VyIGNvbmNsdXNpb25zLgoKLSBTZWxlY3RpbmcgY29tcGxldGVseSBhdCByYW5kb20gZnJvbSBhIHBvcHVsYXRpb24gaW1wbGllczoKICAgIC0gYWxsIHN1YmplY3RzIGluIHRoZSBwb3B1bGF0aW9uIHNob3VsZCBoYXZlIHRoZSBzYW1lIHByb2JhYmlsaXR5IG9mIGJlaW5nIHNlbGVjdGVkIGluIHRoZSBzYW1wbGUsCiAgICAtIHRoZSBzZWxlY3Rpb24gb2YgYSBzdWJqZWN0IGluIHRoZSBzYW1wbGUgc2hvdWxkIGJlIGluZGVwZW5kZW50IGZyb20gdGhlIHNlbGVjdGlvbiBvZiB0aGUgb3RoZXIgc3ViamVjdHMgaW4gdGhlIHNhbXBsZS4KCi0gVGhlIHNhbXBsZSBpcyB0aHVzIHN1cHBvc2VkIHRvIGJlIHJlcHJlc2VudGF0aXZlIGZvciB0aGUgcG9wdWxhdGlvbiwgYnV0IHN0aWxsIGl0IGlzIHJhbmRvbS4KCi0gV2hhdCBkb2VzIHRoaXMgaW1wbHk/CgotLS0KCiMgU2FtcGxlIHRvIHNhbXBsZSB2YXJpYWJpbGl0eQoKTmF0aW9uYWwgSGVhbHRoIE5IYW5lcyBzdHVkeQoKICAtIFNpbmNlIDE5NjAgaW5kaXZpZHVhbHMgb2YgYWxsIGFnZXMgYXJlIGludGVydmlld2VkIGluIHRoZWlyIGhvbWVzIGV2ZXJ5IHllYXIKICAtIFRoZSBoZWFsdGggZXhhbWluYXRpb24gY29tcG9uZW50IG9mIHRoZSBzdXJ2ZXkgaXMgY29uZHVjdGVkIGluIGEgbW9iaWxlIGV4YW1pbmF0aW9uIGNlbnRyZSAoTUVDKS4KICAtIFdlIHdpbGwgdXNlIHRoaXMgbGFyZ2Ugc3R1ZHkgdG8gc2VsZWN0IHJhbmRvbSBzdWJqZWN0cyBmcm9tIHRoZSBBbWVyaWNhbiBwb3B1bGF0aW9uLgogIC0gVGhpcyB3aWxsIGhlbHAgdXMgdG8gdW5kZXJzdGFuZCBob3cgdGhlIHJlc3VsdHMgb2YgYW4gYW5hbHlzaXMgYW5kIHRoZSBjb25jbHVzaW9ucyB2YXJ5IGZyb20gc2FtcGxlIHRvIHNhbXBsZS4KCi0tLQoKYGBge3J9CmxpYnJhcnkoTkhBTkVTKQpoZWFkKE5IQU5FUykKZ2xpbXBzZShOSEFORVMpCmBgYAoKLS0tCgojIyBEYXRhIGV4cGxvcmF0aW9uCgoKU3VwcG9zZSB0aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluIGFzc2Vzc2luZyB0aGUgZGlmZmVyZW5jZSBpbiBkaXJlY3QgY2hvbGVzdGVyb2wgbGV2ZWxzIGJldHdlZW4gbWFsZXMgYW5kIGZlbWFsZXMgb2xkZXIgdGhhbiAyNSB5ZWFycy4KCjEuIFdlIHBpcGUgdGhlIGRhdGFzZXQgdG8gdGhlIGZ1bmN0aW9uIGBmaWx0ZXJgIHRvIGZpbHRlciB0aGUgZGF0YSBhY2NvcmRpbmcgdG8gYWdlLiAKMi4gV2UgcGxvdCB0aGUgZGlyZWN0IGNob2xlc3Rlcm9sIGxldmVscy4KICAgIC0gV2Ugc2VsZWN0IHRoZSBkYXRhIHdpdGggdGhlIGNvbW1hbmQgYGdncGxvdChhZXMoeD1EaXJlY3RDaG9sKSlgCiAgICAtIFdlIGFkZCBhIGhpc3RvZ3JhbSB3aXRoIHRoZSBjb21tYW5kIGBnZW9tX2hpc3RvZ3JhbSgpYAogICAgLSBXZSBtYWtlIHRvIHZlcnRpY2FsIHBhbmVscyB1c2luZyB0aGUgY29tbWFuZCBgZmFjZXRfZ3JpZChHZW5kZXJ+LilgCiAgICAtIFdlIGN1c3RvbWl6ZSB0aGUgbGFiZWwgb2YgdGhlIHgtYXhpcyB3aXRoIHRoZSBgeGxhYmAgY29tbWFuZC4KCmBgYHtyfQpOSEFORVMlPiVmaWx0ZXIoQWdlPjI1KSU+JQogIGdncGxvdChhZXMoeD1EaXJlY3RDaG9sKSkrCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZmFjZXRfZ3JpZChHZW5kZXJ+LikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobWcvZGwpIikKYGBgCgotLS0KCi0gQ2hvbGVzdGVyb2wgbGV2ZWxzIGFuZCBjb25jZW50cmF0aW9uIG1lYXN1cmVtZW50cyBhcmUgb2Z0ZW4gc2tld2VkLgotIENvbmNlbnRyYXRpb25zIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuCi0gVGhleSBhcmUgb2Z0ZW4gbG9nIHRyYW5zZm9ybWVkLgoKYGBge3J9Ck5IQU5FUyU+JQogIGZpbHRlcihBZ2U+MjUpJT4lCiAgZ2dwbG90KGFlcyh4PURpcmVjdENob2wlPiVsb2cyKSkrCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZmFjZXRfZ3JpZChHZW5kZXJ+LikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKQpgYGAKCldlIHNlZSB0aGF0IHRoZSBkYXRhIGFyZSBtb3JlIG9yIGxlc3MgYmVsbCBzaGFwZWQgdXBvbiBsb2cgdHJhbnNmb3JtYXRpb24uCgotLS0KCldlIHdpbGwgbm93IGNyZWF0ZSBhIHN1YnNldCBvZiB0aGUgZGF0YSB0aGF0IHdlIHdpbGwgdXNlIHRvIHNhbXBsZSBmcm9tIGluIHRoZSBuZXh0IHNlY3Rpb25zLgoKICAxLiBXZSBmaWx0ZXIgb24gYWdlIGFuZCByZW1vdmUgc3ViamVjdHMgd2l0aCBtaXNzaW5nIHZhbHVlcyAoTkEpLgogIDIuIFdlIG9ubHkgc2VsZWN0IHRoZSB2YXJpYWJsZXMgR2VuZGVyIGFuZCBEaXJlY3RDaG9sIGZyb20gdGhlIGRhdGFzZXQgdG8gYXZvaWQgdW5uZWNlc3NhcnkgdmFyaWFibGVzLgogIDMuIFdpdGggdGhlIG11dGF0ZSBmdW5jdGlvbiB3ZSBjYW4gYWRkIGEgbmV3IHZhcmlhYmxlIGxvZ0Nob2wgd2l0aCBsb2cgdHJhbnNmb3JtZWQgZGlyZWN0IGNob2xlc3Rlcm9sIGxldmVscy4KCmBgYHtyfQpuaGFuZXNTdWI8LSBOSEFORVMlPiUKICBmaWx0ZXIoQWdlPjI1JiFpcy5uYShEaXJlY3RDaG9sKSkgJT4lCiAgc2VsZWN0KGMoIkdlbmRlciIsIkRpcmVjdENob2wiKSkgJT4lCiAgbXV0YXRlKGNob2xMb2c9bG9nMihEaXJlY3RDaG9sKSkKYGBgCgotLS0KCldlIHdpbGwgY2FsY3VsYXRlIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSBjaG9sTG9nIHZhcmlhYmxlIGZvciBtYWxlcyBhbmQgZmVtYWxlcyBpbiB0aGUgbGFyZ2UgZGF0YXNldC4gClNvIHdlIGdyb3VwIGJ5IEdlbmRlcgoKYGBge3J9CmNob2xMb2dTdW08LSBuaGFuZXNTdWIgJT4lIAogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgIHN1bW1hcml6ZV9hdCgiY2hvbExvZyIsCiAgICAgICAgICAgICAgIGxpc3QobWVhbj1+bWVhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIHNkPX5zZCguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG49ZnVuY3Rpb24oeCkgeCU+JWlzLm5hJT4lYCFgJT4lc3VtKSkgJT4lCiAgbXV0YXRlKHNlPXNkL3NxcnQobikpCgpjaG9sTG9nU3VtCmBgYAoKLS0tCgojIyBFeHBlcmltZW50CgotIFN1cHBvc2UgdGhhdCB3ZSBoYXZlIG5vIGFjY2VzcyB0byBjaG9sZXN0ZXJvbCBsZXZlbHMgb2YgdGhlIEFtZXJpY2FuIHBvcHVsYXRpb24sCi0gd2Ugd2lsbCBoYXZlIHRvIHNldHVwIGFuIGV4cGVyaW1lbnQuCi0gU3VwcG9zZSB3ZSBoYXZlIGEgYnVkZ2V0IGZvciBhc3Nlc3NpbmcgMTAgZmVtYWxlcyBhbmQgMTAgbWFsZXMsCi0gd2Ugd2lsbCBzdWJzZXQgMTAgZmVtYWxlcyBhbmQgMTAgbWFsZXMgYXQgcmFuZG9tIGZyb20gdGhlIEFtZXJpY2FuIHBvcHVsYXRpb24gYW5kIG1lYXN1cmUgdGhlaXIgZGlyZWN0IGNob2xlc3Rlcm9sIGxldmVscy4KCmBgYHtyfQpmZW08LW5oYW5lc1N1YiU+JWZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKSU+JXNhbXBsZV9uKHNpemU9MTApCm1hbDwtbmhhbmVzU3ViJT4lZmlsdGVyKEdlbmRlcj09Im1hbGUiKSU+JXNhbXBsZV9uKHNpemU9MTApCgpzYW1wPC1yYmluZChmZW0sbWFsKQpzYW1wCmBgYAoKLS0tCgpXZSB3aWxsIG5vdyBwbG90IHRoZSBkYXRhIHdpdGggYSBoaXN0b2dyYW0gYW5kIGJveHBsb3RzCgpgYGB7cn0Kc2FtcCAlPiUKICBnZ3Bsb3QoYWVzKHg9Y2hvbExvZykpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjEpICsKICBmYWNldF9ncmlkKEdlbmRlcn4uKSArCiAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIChsb2cyKSIpCgpzYW1wJT4lIAogIGdncGxvdChhZXMoeD1HZW5kZXIseT1jaG9sTG9nKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikKYGBgCgotLS0KCldlIHN1bW1hcml6ZSB0aGUgZGF0YQpgYGB7cn0Kc2FtcCAlPiUgCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICAgc3VtbWFyaXplX2F0KCJjaG9sTG9nIiwKICAgICAgICAgICAgICAgbGlzdChtZWFuPX5tZWFuKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgc2Q9fnNkKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgbj1mdW5jdGlvbih4KSB4JT4laXMubmElPiVgIWAlPiVzdW0pKSAlPiUKICBtdXRhdGUoc2U9c2Qvc3FydChuKSkKYGBgCgpOb3RlIHRoYXQgdGhlIHNhbXBsZSBtZWFuIGlzIGRpZmZlcmVudCBmcm9tIHRoYXQgb2YgdGhlIGxhcmdlIGV4cGVyaW1lbnQgKCJwb3B1bGF0aW9uIikgd2Ugc2FtcGxlZCBmcm9tLiAKCldlIHRlc3QgZm9yIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gTWFsZXMgYW5kIGZlbWFsZXMKCmBgYHtyfQp0LnRlc3QoY2hvbExvZ35HZW5kZXIsc2FtcCx2YXIuZXF1YWw9VFJVRSkKYGBgCgotLS0KCiMjIFJlcGVhdCB0aGUgZXhwZXJpbWVudAoKSWYgd2UgZG8gdGhlIGV4cGVyaW1lbnQgYWdhaW4gd2Ugc2VsZWN0IG90aGVyIHBlb3BsZSBhbmQgd2Ugb2J0YWluIGRpZmZlcmVudCByZXN1bHRzLgoKCmBgYHtyfQpmZW08LW5oYW5lc1N1YiU+JWZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKSU+JXNhbXBsZV9uKHNpemU9MTApCm1hbDwtbmhhbmVzU3ViJT4lZmlsdGVyKEdlbmRlcj09Im1hbGUiKSU+JXNhbXBsZV9uKHNpemU9MTApCgpzYW1wMjwtcmJpbmQoZmVtLG1hbCkKc2FtcDIlPiUKICBnZ3Bsb3QoYWVzKHg9RGlyZWN0Q2hvbCU+JWxvZykpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjEpICsKICBmYWNldF9ncmlkKEdlbmRlcn4uKSArCiAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIChsb2cpIikKCnNhbXAyJT4lIAogIGdncGxvdChhZXMoeD1HZW5kZXIseT1jaG9sTG9nKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikKCnNhbXAyICU+JSAKICBncm91cF9ieShHZW5kZXIpICU+JQogICBzdW1tYXJpemVfYXQoImNob2xMb2ciLAogICAgICAgICAgICAgICBsaXN0KG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKQoKdC50ZXN0KGNob2xMb2d+R2VuZGVyLHNhbXAyLHZhci5lcXVhbD1UUlVFKQpgYGAKCi0tLQoKIyMgQW5kIGFnYWluCgpgYGB7cn0Kc2V0LnNlZWQoMTI4NTcpCmZlbTwtbmhhbmVzU3ViJT4lZmlsdGVyKEdlbmRlcj09ImZlbWFsZSIpJT4lc2FtcGxlX24oc2l6ZT0xMCkKbWFsPC1uaGFuZXNTdWIlPiVmaWx0ZXIoR2VuZGVyPT0ibWFsZSIpJT4lc2FtcGxlX24oc2l6ZT0xMCkKCnNhbXAzPC1yYmluZChmZW0sbWFsKQpzYW1wMyU+JQogIGdncGxvdChhZXMoeD1EaXJlY3RDaG9sJT4lbG9nKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAuMSkgKwogIGZhY2V0X2dyaWQoR2VuZGVyfi4pICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKGxvZykiKQoKc2FtcDMlPiUgCiAgZ2dwbG90KGFlcyh4PUdlbmRlcix5PWNob2xMb2cpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGU9TkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKQoKCnNhbXAzICU+JSAKICBncm91cF9ieShHZW5kZXIpICU+JQogICBzdW1tYXJpemVfYXQoImNob2xMb2ciLAogICAgICAgICAgICAgICBsaXN0KG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKQoKdC50ZXN0KGNob2xMb2d+R2VuZGVyLHNhbXAzLHZhci5lcXVhbD1UUlVFKQpgYGAKCi0tLQoKIyMgU3VtbWFyeQoKLSBCZWNhdXNlIHdlIHNhbXBsZWQgb3RoZXIgc3ViamVjdHMgaW4gZWFjaCBzYW1wbGUsIHdlIG9idGFpbiBkaWZmZXJlbnQgY2hvbGVzdGVyb2wgbGV2ZWxzLgotIEhvd2V2ZXIsIG5vdCBvbmx5IHRoZSBjaG9sZXN0ZXJvbCBsZXZlbHMgZGlmZmVyIGZyb20gc2FtcGxlIHRvIHNhbXBsZSBidXQgYWxzbyB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzOiBtZWFucywgc3RhbmRhcmQgZGV2aWF0aW9ucyBhbmQgc3RhbmRhcmQgZXJyb3JzLgotIE5vdGUsIHRoYXQgaW4gdGhlIGxhc3Qgc2FtcGxlIHRoZSBsb2cgY2hvbGVzdGVyb2wgbGV2ZWxzIGFyZSBvbiBhdmVyYWdlIGxvd2VyIGZvciBmZW1hbGVzIHRoYW4gZm9yIG1hbGVzOyBiYXNlZCBvbiB0aGlzIHNhbXBsZSB3ZSBldmVuIHdvdWxkIHdyb25nbHkgY29uY2x1ZGUgdGhhdCB0aGUgY2hvbGVzdGVyb2wgbGV2ZWxzIGZvciBmZW1hbGVzIGFyZSBvbiBhdmVyYWdlIGxhcmdlciB0aGFuIHRob3NlIG9mIG1hbGVzLgoKLSBUaGlzIGltcGxpZXMgdGhhdCBvdXIgY29uY2x1c2lvbnMgYXJlIGFsc28gc3ViamVjdGVkIHRvIHVuY2VydGFpbnR5IGFuZCBtaWdodCBjaGFuZ2UgZnJvbSBzYW1wbGUgdG8gc2FtcGxlLgoKLSBTYW1wbGVzIGFzIHRoZSBvbmUgd2hlcmUgdGhlIGVmZmVjdCBzd2FwcyBhbmQgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgaG93ZXZlciwgYXJlIHZlcnkgcmFyZS4KLSBUaGlzIGlzIGlsbHVzdHJhdGVkIHdpdGggdGhlIGNvZGUgYmVsb3csIHdoZXJlIHdlIHdpbGwgZHJhdyAyMDAwMCByZXBlYXRlZCBzYW1wbGVzIHdpdGggc2FtcGxlIHNpemUgMTAgZm9yIGZlbWFsZXMgYW5kIG1hbGVzIGZyb20gdGhlIE5IYW5lcyBzdHVkeS4KCmBgYHtyfQpuc2ltPC0yMDAwMApuU2FtcDwtMTAKcmVzPC1tYXRyaXgoMCxucm93PW5zaW0sbmNvbD0yKQpmZW08LW5oYW5lc1N1YiU+JWZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKQptYWw8LW5oYW5lc1N1YiU+JWZpbHRlcihHZW5kZXI9PSJtYWxlIikKCmZvciAoaSBpbiAxOm5zaW0pCnsKIGZlbVNhbXA8LXNhbXBsZShmZW0kY2hvbExvZyxuU2FtcCkKIG1hbFNhbXA8LXNhbXBsZShtYWwkY2hvbExvZyxuU2FtcCkKCm1lYW5GZW08LW1lYW4oZmVtU2FtcCkKIG1lYW5NYWw8LW1lYW4obWFsU2FtcCkKIGRlbHRhPC1tZWFuRmVtLW1lYW5NYWwKIHNkRmVtPC1zZChmZW1TYW1wKQogc2RNYWw8LXNkKG1hbFNhbXApCiBzZUZlbTwtc2RGZW0vc3FydChuU2FtcCkKIHNlRmVtPC1zZEZlbS9zcXJ0KG5TYW1wKQogc2RQb29sPC1zcXJ0KChzZEZlbV4yKihuU2FtcC0xKSArIHNkTWFsXjIqKG5TYW1wLTEpKS8oMipuU2FtcC0yKSkKdHZhbHVlPC0oZGVsdGEpLyhzZFBvb2wqc3FydCgxL25TYW1wKzEvblNhbXApKQpwdmFsdWU8LXB0KGFicyh0dmFsdWUpLGxvd2VyLnRhaWwgPSBGQUxTRSxkZj0yKm5TYW1wLTIpKjIKIHJlc1tpLF08LWMoZGVsdGEscHZhbHVlKQp9CnN1bShyZXNbLDJdPDAuMDUmcmVzWywxXT4wKQpzdW0ocmVzWywyXT4wLjA1KQpzdW0ocmVzWywyXTwwLjA1JnJlc1ssMV08MCkKCnJlczwtcmVzICU+JSBhcy5kYXRhLmZyYW1lCm5hbWVzKHJlcykgPC0gYygiZGVsdGEiLCJwdmFsdWUiKQpyZXMgJT4lIAogIGdncGxvdChhZXMoeD1kZWx0YSx5PS1sb2cxMChwdmFsdWUpLGNvbG9yPXB2YWx1ZTwwLjA1KSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICB4bGFiKCJBdmVyYWdlIGNob2xlc3Rlcm9sIGRpZmZlcmVuY2UiKSArCiAgeWxhYigiLSBsb2cxMChwdmFsdWUpIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiYmxhY2siLCJyZWQiKSkKCnJlcyAlPiUgCiAgZ2dwbG90KGFlcyh5PWRlbHRhKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4PTAseT1jKG1lYW4oZmVtJGNob2xMb2cpLW1lYW4obWFsJGNob2xMb2cpKSxjb2xvcj0icG9wLiBkaWZmIikpICsKICB4bGFiKCIiKQpgYGAKCk9ubHkgaW4gYHIgc3VtKHJlc1ssMl08MC4wNSZyZXNbLDFdPDApYCBvdXQgb2YgMjAwMDAgc2FtcGxlcyB3ZSBjb25jbHVkZSB0aGF0IHRoZSBtZWFuIGNob2xlc3Rlcm9sIGxldmVsIG9mIG1hbGVzIGlzIHNpZ25pZmljYW50bHkgbG93ZXIgdGhhbiBmb3IgZmVtYWxlcy4gRm9yIHRoZSByZW1haW5pbmcgc2FtcGxlcyB0aGUgY2hvbGVzdGVyb2wgbGV2ZWxzIGZvciBtYWxlcyB3ZXJlIG9uIGF2ZXJhZ2Ugc2lnbmlmaWNhbnRseSBsb3dlciB0aGFuIGZvciBmZW1hbGVzIChgciBzdW0ocmVzWywyXTwwLjA1JnJlc1ssMV0+MClgIHNhbXBsZXMpIG9yIHRoZSBhdmVyYWdlIGRpZmZlcmVuY2UgaW4gY2hvbGVzdGVyb2wgbGV2ZWxzIHdlcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKGByIHN1bShyZXNbLDJdPjAuMDUpYCBzYW1wbGVzKS4gVGhlIGxhdHRlciBpcyBiZWNhdXNlIHRoZSBwb3dlciBpcyByYXRoZXIgbG93IHRvIGRldGVjdCB0aGUgZGlmZmVyZW5jZSB3aXRoIDEwIHNhbXBsZXMgaW4gZWFjaCBncm91cC4KCi0tLQoKIyMgQXNzaWdubWVudAoKMS4gQ29weSB0aGUgY29kZSBjaHVuayB3aXRoIHRoZSBzaW11bGF0aW9uIHN0dWR5CjIuIEFkZCBpdCBoZXJlIGJlbG93CjMuIE1vZGlmeSB0aGUgc2FtcGxlIHNpemUgdG8gNTAuCjQuIFdoYXQgZG8geW91IG9ic2VydmU/CgoKLS0tCgojIyBDb250cm9sIG9mIGZhbHNlIHBvc2l0aXZlcwoKV2F0IGhhcHBlbnMgd2hlbiB0aGVyZSBpcyBubyBkaWZmZXJlbmNlIGJldHdlZW4gYm90aCBncm91cHM/IAoKLSBXZSB3aWxsIGhhdmUgdG8gc2ltdWxhdGUgZXhwZXJpbWVudHMgZm9yIHdoaWNoIHRoZSBjaG9sZXN0b3JvbCBsZXZlbHMgYXJlIHRoZSBzYW1lIGZvciBib3RoIGdyb3Vwcy4gCgoKLSBXZSBjYW4gZG8gdGhpcyBieSBzYW1wbGluZyBkYXRhIGZvciBib3RoIGdyb3VwcyBmcm9tIHRoZSBzdWJzZXQgb2Ygd29tZW4gaW4gdGhlIHN0dWR5LiAKCi0gV2UgZG8gdGhpcyBhZ2FpbiBmb3IgMTAgc3ViamVjdHMgcGVyIGdyb3VwCgoKYGBge3J9Cm5zaW08LTIwMDAwCm5TYW1wPC0xMApyZXM8LW1hdHJpeCgwLG5yb3c9bnNpbSxuY29sPTIpCmZlbTwtbmhhbmVzU3ViJT4lZmlsdGVyKEdlbmRlcj09ImZlbWFsZSIpCm1hbDwtbmhhbmVzU3ViJT4lZmlsdGVyKEdlbmRlcj09Im1hbGUiKQoKZm9yIChpIGluIDE6bnNpbSkKewogZmVtU2FtcDwtc2FtcGxlKGZlbSRjaG9sTG9nLG5TYW1wKQogZmVtMlNhbXA8LXNhbXBsZShmZW0kY2hvbExvZyxuU2FtcCkKCm1lYW5GZW08LW1lYW4oZmVtU2FtcCkKIG1lYW5GZW0yPC1tZWFuKGZlbTJTYW1wKQogZGVsdGE8LW1lYW5GZW0tbWVhbkZlbTIKIHNkRmVtPC1zZChmZW1TYW1wKQogc2RGZW0yPC1zZChmZW0yU2FtcCkKIHNlRmVtPC1zZEZlbS9zcXJ0KG5TYW1wKQogc2VGZW08LXNkRmVtMi9zcXJ0KG5TYW1wKQogc2RQb29sPC1zcXJ0KChzZEZlbV4yKihuU2FtcC0xKSArIHNkRmVtMl4yKihuU2FtcC0xKSkvKDIqblNhbXAtMikpCnR2YWx1ZTwtKGRlbHRhKS8oc2RQb29sKnNxcnQoMS9uU2FtcCsxL25TYW1wKSkKcHZhbHVlPC1wdChhYnModHZhbHVlKSxsb3dlci50YWlsID0gRkFMU0UsZGY9MipuU2FtcC0yKSoyCiByZXNbaSxdPC1jKGRlbHRhLHB2YWx1ZSkKfQpzdW0ocmVzWywyXTwwLjA1JnJlc1ssMV0+MCkKc3VtKHJlc1ssMl0+PTAuMDUpCnN1bShyZXNbLDJdPDAuMDUmcmVzWywxXTwwKQoKcmVzPC1yZXMgJT4lIGFzLmRhdGEuZnJhbWUKbmFtZXMocmVzKSA8LSBjKCJkZWx0YSIsInB2YWx1ZSIpCnJlcyAlPiUgCiAgZ2dwbG90KGFlcyh4PWRlbHRhLHk9LWxvZzEwKHB2YWx1ZSksY29sb3I9cHZhbHVlPDAuMDUpKSArIAogIGdlb21fcG9pbnQoKSArIAogIHhsYWIoIkF2ZXJhZ2UgY2hvbGVzdGVyb2wgZGlmZmVyZW5jZSIpICsKICB5bGFiKCItIGxvZzEwKHB2YWx1ZSkiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsInJlZCIpKQoKcmVzICU+JSAKICBnZ3Bsb3QoYWVzKHk9ZGVsdGEpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHg9MCx5PTAsY29sb3I9InBvcC4gZGlmZiIpKSArCiAgeGxhYigiIikKYGBgCgpOb3RlLCB0aGF0IHRoZSBudW1iZXIgb2YgZmFsc2UgcG9zaXRpdmVzIGFyZSBvbiBgciBzdW0ocmVzWywyXTwwLjA1KWAgb24gYHIgZm9ybWF0KG5zaW0sZGlnaXRzPTUpYCBleHBlcmltZW50cyBhbmQgYXJlIG5pY2VseSBjb250cm9sbGVkIGF0IHRoZSA1JSBsZXZlbC4KCldoYXQgaGFwcGVucyBpZiB3ZSBpbmNyZWFzZSB0aGUgc2FtcGxlIHNpemUgdG8gNTAgc3ViamVjdHMgcGVyIGdyb3VwPyAgCgoKLS0tCgojIFNhbGsgU3R1ZHkKCi0gSW4gMTkxNiwgdGhlIFVTIGV4cGVyaWVuY2VkIHRoZSBmaXJzdCBsYXJnZSBlcGlkZW1pYyBvZiBwb2xpby4KLSBKb2huIFNhbGsgZGV2ZWxvcGVkIGEgdmFjY2luZSB3aXRoIHByb21pc2luZyByZXN1bHRzIGluIHRoZSBsYWIgaW4gdGhlIGVhcmx5IGZpZnRpZXMuCi0gSW4gMTk1NCwgdGhlIE5hdGlvbmFsIEZvdW5kYXRpb24KZm9yIEluZmFudGlsZSBQYXJhbHlzaXMgKE5GSVApIGhhcyBzZXR1cCBhIGxhcmdlIHN0dWR5IHRvIGFzc2VzcyB0aGUgZWZmZWN0aXZlbmVzcyBvZiB0aGUgU2FsayB2YWNjaW5lLgotIFN1cHBvc2UgdGhhdCB0aGUgTkZJUCB3b3VsZCBoYXZlIHZhY2NpbmF0ZWQgYSBsYXJnZSBudW1iZXIgb2YgY2hpbGRyZW4gaW4gMTk1NCBhbmQgd291bGQgaGF2ZSBvYnNlcnZlZCB0aGF0IHRoZSBwb2xpbyBpbmNpZGVuY2UgaW4gMTk1NCB3YXMgbG93ZXIgdGhhbiBpbiAxOTUzLiBDb3VsZCB0aGV5IGhhdmUgY29uY2x1ZGVkIHRoYXQgdGhlIHZhY2NpbmUgd2FzIGVmZmVjdGl2ZT8KCi0tLQoKIyMgTkZJUCBTdHVkeQojIyMgRGVzaWduCgotIExhcmdlIHNpbXVsdGFuZW91cyBzdHVkeSB3aXRoIGNhc2VzLCB2YWNjaW5hdGVkIGNoaWxkcmVuLCBhbmQgY29udHJvbHMsICBub24tdmFjY2luYXRlZCBjaGlsZHJlbi4KLSBBbGwgc2Nob29scyBpbiBkaXN0cmljdHMgd2l0aCBoaWdoIHBvbGlvIGluY2lkZW5jZQotIENhc2VzOiBjaGlsZHJlbiB3aXRoIGNvbnNlbnQgZm9yIHZhY2NpbmF0aW9uIGZyb20gc2Vjb25kIGdyYWRlIG9mIHByaW1hcnkgc2Nob29sLgotIENvbnRyb2xzOiBjaGlsZHJlbiBmcm9tICBmaXJzdCBhbmQgdGhpcmQgZ3JhZGUuCgojIyMgRGF0YQpgYGB7cn0KbmZpcDwtZGF0YS5mcmFtZShncm91cD1jKCJjYXNlcyIsImNvbnRyb2wiLCJub0NvbmNlbnQiKSxncmFkZT1jKCJnMiIsImcxZzMiLCJnMiIpLHZhY2Npbj1jKCJ5ZXMiLCJubyIsIm5vIiksdG90YWw9YygyMjE5OTgsNzI1MTczLDEyMzYwNSkscG9saW89Yyg1NCwzOTEsNTYpKQpuZmlwJG5vUG9saW88LW5maXAkdG90YWwtbmZpcCRwb2xpbwprbml0cjo6a2FibGUobmZpcCkKYGBgCgpDb21wYXJlIHBvbGlvIGluY2lkZW5jZT8KCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpuZmlwJGluY2lkZW5jZVBNPC1yb3VuZChuZmlwJHBvbGlvL25maXAkdG90YWwqMWU2LDApCmtuaXRyOjprYWJsZShuZmlwKQpgYGAKCldoYXQgY2FuIHdlIGNvbmNsdWRlPwoKLS0tCgojIyBDb25mb3VuZGluZwoKCmBgYHtyLGVjaG89RkFMU0UsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLG91dC53aWR0aCA9ICc1MCUnfQpwbG90KGMoMCwwLDEpLGMoLTIsMiwwKSxwY2g9YygiUyIsIlYiLCJQIikseGF4dD0ibm9uZSIseWF4dD0ibm9uZSIsYXhlcz1GQUxTRSx4bGFiPSIiLHlsYWI9IiIsY2V4PTQseWxpbT1jKC0yLjIsMi4yKSkKYXJyb3dzKHgwPTAuMSx4MT0uOSx5MD0xLjgseTE9MC4xLGx3ZD00KQphcnJvd3MoeDA9MC4xLHgxPS45LHkwPS0xLjgseTE9LTAuMixsd2Q9NCkKYXJyb3dzKHgwPTAseDE9MCx5MD0tMS40LHkxPTEuNCxsd2Q9NCkKYGBgCgoKLSBXZSBvYnNlcnZlIGEgbG93ZXIgcG9saW8gKFApIGluY2lkZW5jZSBmb3IgY2hpbGRyZW4gZm9yIHdobyBubyBjb25zZW50IHdhcyBnaXZlbiB0aGFuIGZvciB0aGUgY2hpbGRyZW4gaW4gdGhlIGNvbnRyb2wgZ3JvdXAuCgotIENvbnNlbnQgZm9yIHZhY2NpbmF0aW9uIChWKSB3YXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBzb2Npby1lY29ub21pYyBzdGF0dXMgKFMpLgoKLSBDaGlsZHJlbiBvZiBsb3dlciBzb2Npby1lY29ub21pYyBzdGF0dXMgd2VyZSBtb3JlIHJlc2lzdGFudCB0byB0aGUgZGlzZWFzZS4KCi0gVGhlIGdyb3VwcyBvZiBjYXNlcyBhbmQgY29udHJvbHMgYXJlIG5vdCBjb21wYXJhYmxlOgogICAgLSBkaWZmZXJlbmNlIGluIGFnZSwKICAgIC0gZGlmZmVyZW5jZSBpbiBzb2Npby1lY29ub21pYyBzdGF0dXMgYW5kCiAgICAtIGRpZmZlcmVuY2UgaW4gc3VzY2VwdGlibGUgZm9yIGRpc2Vhc2UuCgotLS0KCiMjIFNhbGsgU3R1ZHkKCiMjIyBEZXNpZ24KQSBuZXcgc3R1ZHkgd2FzIGNvbmR1Y3RlZDogUmFuZG9taXplZCBkb3VibGUgYmxpbmQgc3R1ZHkKCiAgLSBDaGlsZHJlbiBhcmUgYXNzaWduZWQgYXQgcmFuZG9tIHRvIHRoZSBjb250cm9sIG9yIGNhc2UgdHJlYXRtZW50IGFybSBhZnRlciBjb25zZW50IHdhcyBnaXZlbiBieSB0aGUgcGFyZW50cy4KICAtIENvbnRyb2w6IHZhY2NpbmF0aW9uIHdpdGggcGxhY2VibwogIC0gVHJlYXRtZW50OiB2YWNjaW5hdGlvbiB3aXRoIHZhY2NpbmUKICAtIGRvdWJsZSBibGluZGluZzoKICAgIC0gcGFyZW50cyBkaWQgbm90IGtub3cgaWYgdGhlaXIgY2hpbGQgd2FzIHZhY2NpbmF0ZWQgb3IgcmVjZWl2ZWQgdGhlIHBsYWNlYm8KICAgIC0gY2FyZS1naXZlci9yZXNlYXJjaGVycyBkaWQgbm90IGtub3cgaWYgdGhlIGNoaWxkIHdhcyB2YWNjaW5hdGVkICBvciByZWNlaXZlZCBwbGFjZWJvCgotLS0KCiMjIyBEYXRhCgpgYGB7cn0Kc2FsazwtZGF0YS5mcmFtZShncm91cD1jKCJjYXNlcyIsImNvbnRyb2wiLCJub0NvbmNlbnQiKSx0cmVhdG1lbnQ9YygidmFjY2luZSIsInBsYWNlYm8iLCJub25lIiksdG90YWw9YygyMDA3NDUsCjIwMTIyOSwgMzM4Nzc4KSxwb2xpbz1jKDU3LDE0MiwxNTcpKQpzYWxrJG5vUG9saW88LXNhbGskdG90YWwtc2FsayRwb2xpbwpzYWxrJGluY2lkZW5jZVBNPC1yb3VuZChzYWxrJHBvbGlvL3NhbGskdG90YWwqMWU2LDApCmtuaXRyOjprYWJsZShzYWxrKQpgYGAKCi0gV2Ugb2JzZXJ2ZSBhIG11Y2ggbGFyZ2VyIGVmZmVjdCBub3cgdGhhdCB0aGUgY2FzZXMgYW5kIHRoZSBjb250cm9scyBhcmUgY29tcGFyYWJsZSwgaW5jaWRlbmNlIG9mIGByIHNhbGskaW5jaWRlbmNlUE1bMV1gICBhbmQgYHIgc2FsayRpbmNpZGVuY2VQTVsyXWAgcGVyIG1pbGxpb24sIHJlc3BlY3RpdmVseS4KCi0gVGhlIHBvbGlvIGluY2lkZW5jZSBmb3IgY2hpbGRyZW4gd2l0aCBubyBjb25zZW50IHJlbWFpbnMgc2ltaWxhciwgYHIgbmZpcCRpbmNpZGVuY2VQTVszXWAgYW5kIGByIHNhbGskaW5jaWRlbmNlUE1bM11gIHBlciBtaWxsaW9uIGluIHRoZSBORklQIGFuZCBTYWxrIHN0dWR5LCByZXNwZWN0aXZlbHkuCgotLS0KCiMgUm9sZSBvZiBTdGF0aXN0aWNzIGluIHRoZSBMaWZlIFNjaWVuY2VzCgotIFdlIGhhdmUgc2VlbiB0aGF0CiAgICAtIGl0IGlzIGltcG9ydGFudCB0byBjYXJlZnVsbHkgc3BlY2lmeSB0aGUgc2NvcGUgb2YgdGhlIHN0dWR5IGJlZm9yZSB0aGUgZXhwZXJpbWVudCwKICAgIC0gdGhlIHNhbXBsZSBzaXplIG1hdHRlcnMsCiAgICAtIHdlIHNob3VsZCBiZSBhd2FyZSBvZiBjb25mb3VuZGluZywgYW5kIAogICAgLSBhIHByb3BlciBjb250cm9sIGlzIHJlcXVpcmVkLgoKJFxyaWdodGFycm93JCBHb29kIGV4cGVyaW1lbnRhbCBkZXNpZ24gaXMgY3J1Y2lhbCEKCi0gV2UgYWxzbyBvYnNlcnZlZCB0aGF0IHRoZXJlIGlzIHZhcmlhYmlsaXR5IGluIHRoZSBwb3B1bGF0aW9uIGFuZCBiZWNhdXNlIHdlIGNhbiBvbmx5IHNhbXBsZSBhIHNtYWxsIHBhcnQgb2YgdGhlIHBvcHVsYXRpb24gb3VyIHJlc3VsdHMgYW5kIGNvbmNsdXNpb25zIGFyZSBzdWJqZWN0ZWQgdG8gdW5jZXJ0YWludHkuCgoKCgotIFN0YXRpc3RpY3MgaXMgdGhlIHNjaWVuY2Ugb24KICAgIDEuIGNvbGxlY3RpbmcgKGV4cGVyaW1lbnRhbCBkZXNpZ24pLAogICAgMi4gZXhwbG9yaW5nIChkYXRhIGV4cGxvcmF0aW9uKSBhbmQKICAgIDMuIGxlYXJuaW5nIGZyb20gZGF0YSBhbmQgdG8gZ2VuZXJhbGl6ZSB3aGF0IHdlIG9ic2VydmUgaW4gdGhlIHNhbXBsZSB0b3dhcmRzIHRoZSBwb3B1bGF0aW9uIHdoaWxlIHF1YW50aWZ5aW5nLCBjb250cm9sbGluZyBhbmQgcmVwb3J0aW5nIHZhcmlhYmlsaXR5IGFuZCB1bmNlcnRhaW50eSAoc3RhdGlzdGljYWwgbW9kZWxsaW5nIGFuZCBzdGF0aXN0aWNhbCBpbmZlcmVuY2UpLgoKLSBUaGVyZWZvcmUsIHN0YXRpc3RpY3MgcGxheXMgYW4gaW1wb3J0YW50IHJvbGUgaW4gYWxtb3N0IGFsbCBzY2llbmNlcyAoZS5nLiBjb2x1bW4gInBvaW50cyBvZiBzaWduaWZpY2FuY2UiIGluIE5hdHVyZSBNZXRob2RzLiBodHRwOi8vYmxvZ3MubmF0dXJlLmNvbS9tZXRoYWdvcmEvMjAxMy8wOC9naXZpbmdfc3RhdGlzdGljc190aGVfYXR0ZW50aW9uX2l0X2Rlc2VydmVzLmh0bWwpCgotLS0KCmBgYHtyIHBvcDJTYW1wMlBvcCwgb3V0LndpZHRoPSc4MCUnLGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQppZiAoInBpIiVpbiVscygpKSBybSgicGkiKQprb3B2b2V0ZXI8LWZ1bmN0aW9uKHgseSxhbmdsZT0wLGw9LjIsY2V4LmRvdD0uNSxwY2g9MTksY29sPSJibGFjayIpCnsKYW5nbGU9YW5nbGUvMTgwKnBpCnBvaW50cyh4LHksY2V4PWNleC5kb3QscGNoPXBjaCxjb2w9Y29sKQpsaW5lcyhjKHgseCtsKmNvcygtcGkvMithbmdsZSkpLGMoeSx5K2wqc2luKC1waS8yK2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhhbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4oYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbC8yKmNvcygtcGkvMithbmdsZSkseCtsLzIqY29zKC1waS8yK2FuZ2xlKStsLzQqY29zKHBpK2FuZ2xlKSksYyh5K2wvMipzaW4oLXBpLzIrYW5nbGUpLHkrbC8yKnNpbigtcGkvMithbmdsZSkrbC80KnNpbihwaSthbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsKmNvcygtcGkvMithbmdsZSkseCtsKmNvcygtcGkvMithbmdsZSkrbC8yKmNvcygtcGkvMitwaS80K2FuZ2xlKSksYyh5K2wqc2luKC1waS8yK2FuZ2xlKSx5K2wqc2luKC1waS8yK2FuZ2xlKStsLzIqc2luKC1waS8yK3BpLzQrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzItcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMi1waS80K2FuZ2xlKSksY29sPWNvbCkKfQoKcGFyKG1hcj1jKDAsMCwwLDApLG1haT1jKDAsMCwwLDApKQpwbG90KDAsMCx4bGFiPSIiLHlsYWI9IiIseGxpbT1jKDAsMTApLHlsaW09YygwLDEwKSxjb2w9MCx4YXh0PSJub25lIix5YXh0PSJub25lIixheGVzPUZBTFNFKQpyZWN0KDAsNiwxMCwxMCxib3JkZXI9InJlZCIsbHdkPTIpCnRleHQoLjUsOCwicG9wdWxhdGlvbiIsc3J0PTkwLGNvbD0icmVkIixjZXg9MikKc3ltYm9scyAoMywgOCwgY2lyY2xlcz0xLjUsIGNvbD0icmVkIixhZGQ9VFJVRSxmZz0icmVkIixpbmNoZXM9RkFMU0UsbHdkPTIpCnNldC5zZWVkKDMzMCkKZ3JpZD1zZXEoMCwxLjMsLjAxKQoKZm9yIChpIGluIDE6NTApCnsKCWFuZ2xlMT1ydW5pZihuPTEsbWluPTAsbWF4PTM2MCkKCWFuZ2xlMj1ydW5pZihuPTEsbWluPTAsbWF4PTM2MCkKCXJhZGl1cz1zYW1wbGUoZ3JpZCxwcm9iPWdyaWReMipwaS9zdW0oZ3JpZF4yKnBpKSxzaXplPTEpCglrb3B2b2V0ZXIoMytyYWRpdXMqY29zKGFuZ2xlMS8xODAqcGkpLDgrcmFkaXVzKnNpbihhbmdsZTEvMTgwKnBpKSxhbmdsZT1hbmdsZTIpCn0KdGV4dCg3LjUsOCwiY2hvbGVzdGVyb2wgaW4gcG9wdWxhdGlvbiIsY29sPSJyZWQiLGNleD0xLjIpCgpyZWN0KDAsMCwxMCw0LGJvcmRlcj0iYmx1ZSIsbHdkPTIpCnRleHQoLjUsMiwic2FtcGxlIixzcnQ9OTAsY29sPSJibHVlIixjZXg9MikKc3ltYm9scyAoMywgMiwgY2lyY2xlcz0xLjUsIGNvbD0icmVkIixhZGQ9VFJVRSxmZz0iYmx1ZSIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpmb3IgKGkgaW4gMDoyKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjEraSkKfQp0ZXh0KDcuNSwyLCJjaG9sZXN0ZXJvbCBpbiBzYW1wbGUiLGNvbD0iYmx1ZSIsY2V4PTEuMikKCmFycm93cygzLDUuOSwzLDQuMSxjb2w9ImJsYWNrIixsd2Q9MykKYXJyb3dzKDcsNC4xLDcsNS45LGNvbD0iYmxhY2siLGx3ZD0zKQp0ZXh0KDEuNSw1LCJFWFAuIERFU0lHTiAoMSkiLGNvbD0iYmxhY2siLGNleD0xLjIpCnRleHQoOC41LDUsIkVTVElNQVRJT04gJlxuSU5GRVJFTkNFICgzKSIsY29sPSJibGFjayIsY2V4PTEuMikKdGV4dCg3LjUsLjUsIkRBVEEgRVhQTE9SQVRJT04gJlxuREVTQ1JJUFRJVkUgU1RBVElTVElDUyAoMikiLGNvbD0iYmxhY2siLGNleD0xLjIpCmBgYAoKCg==