1 Smelly armpit example

  • Smelly armpits are not caused by sweat itself. The smell is caused by specific micro-organisms belonging to the group of Corynebacterium spp. that metabolise sweat. Another group of abundant bacteria are the Staphylococcus spp., these bacteria do not metabolise sweat in smelly compounds.

  • The CMET-groep at Ghent University does research on transplanting the armpit microbiome to save people with smelly armpits.

  • Proposed Therapy:
    1. Remove armpit-microbiome with antibiotics
    2. Influence armpit microbiome with microbial transplant (https://youtu.be/9RIFyqLXdVw)
  • Experiment:

    • 20 subjects with smelly armpits are attributed to one of two treatment groups
    • placebo (only antibiotics)
    • transplant (antibiotics followed by microbial transplant).
    • The microbiome is sampled 6 weeks upon the treatment.
    • The relative abundance of Staphylococcus spp. on Corynebacterium spp. + Staphylococcus spp. in the microbiome is measured via DGGE (Denaturing Gradient Gel Electrophoresis).

1.1 Import the data

read_lines("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/armpit.csv")
 [1] "trt,rel"                       "placebo,54.99207606973059"    
 [3] "placebo,31.84466019417476"     "placebo,41.09947643979057"    
 [5] "placebo,59.52063914780293"     "placebo,63.573407202216075"   
 [7] "placebo,41.48648648648649"     "placebo,30.44041450777202"    
 [9] "placebo,42.95676429567643"     "placebo,41.7391304347826"     
[11] "placebo,33.896515311510036"    "transplant,57.218124341412015"
[13] "transplant,72.50900360144058"  "transplant,61.89258312020461" 
[15] "transplant,56.690140845070424" "transplant,76"                
[17] "transplant,71.7357910906298"   "transplant,57.757296466973884"
[19] "transplant,65.1219512195122"   "transplant,67.53424657534246" 
[21] "transplant,77.55359394703657" 

The file is comma separated and in tidy format

ap<-read_csv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/armpit.csv")
ap
# A tibble: 20 x 2
   trt          rel
   <chr>      <dbl>
 1 placebo     55.0
 2 placebo     31.8
 3 placebo     41.1
 4 placebo     59.5
 5 placebo     63.6
 6 placebo     41.5
 7 placebo     30.4
 8 placebo     43.0
 9 placebo     41.7
10 placebo     33.9
11 transplant  57.2
12 transplant  72.5
13 transplant  61.9
14 transplant  56.7
15 transplant  76  
16 transplant  71.7
17 transplant  57.8
18 transplant  65.1
19 transplant  67.5
20 transplant  77.6

1.2 Data Exploration and Descriptive Statistics

  • Data exploration is extremely important to get insight in the data.
  • It is often underrated and overlooked.

1.2.1 Descriptive statistics

We first summarize the data and calculate the mean, standard deviation, number of observations and standard error and store the result in an object apRelSum via ’apRelSum<-`

  1. We pipe the ap dataframe to the group_by function to group the data by treatment trt group_by(trt)
  2. We pipe the result to the summarize_at function to summarize the “rel” variable and calculate the mean, standard deviation and the number of observations
  3. We pipe the result to the mutate function to make a new variable in the data frame se for which we calculate the standard error
apRelSum<-ap%>%
  group_by(trt)%>%
  summarize_at("rel",
               list(mean=~mean(.,na.rm=TRUE),
                    sd=~sd(.,na.rm=TRUE),
                    n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
  mutate(se=sd/sqrt(n))

apRelSum
# A tibble: 2 x 5
  trt         mean    sd     n    se
  <chr>      <dbl> <dbl> <int> <dbl>
1 placebo     44.2 11.5     10  3.65
2 transplant  66.4  7.88    10  2.49

1.2.2 Plots

We will use ggplot2 to make our plots. With the ggplot2 library we can easily build plots by adding layers.

1.2.2.1 barplot

  1. We pipe our summarized data to the ggplot function and we select the treatment variable trt and the variable mean for plotting aes(x=trt,y=mean)

  2. We make a barplot based on this data using the geom_bar function. The statistic is stat="identity" because the bar height should be equal the value for the mean of the relative abundance.

apRelSum%>% 
  ggplot(aes(x=trt,y=mean)) +
  geom_bar(stat="identity") 

  • Is this plot informative??

We will now add standard errors to the plot using geom_errorbar function and specify the minimum and maximum value for of the error bar, the width command is used to set the width of the error bar smaller than the width of the bar.

apRelSum%>% 
  ggplot(aes(x=trt,y=mean)) +
  geom_bar(stat="identity") + 
  geom_errorbar(aes(ymin=mean-se,ymax=mean+se),width=.2)

  • Is this plot informative??

1.2.2.2 boxplots

I consider barplots to be bad plots

  • They are not informative
  • They just visualize a two point summary of the data. It is better to do this in a table
  • They use a lot of space (e.g. from zero up to the minimum relative abundance) where no data are present.

It is better to get a view on the distribution of the data. We can use a boxplot for this purpose. We first explain what a boxplot.



We will now make a boxplot for the ap data

  1. We pipe the ap dataframe to the ggplot command
  2. We select the data with the command ggplot(aes(x=trt,y=rel))
  3. We add a boxplot with the command geom_boxplot()
ap %>%  
  ggplot(aes(x=trt,y=rel)) + 
  geom_boxplot()


  • Note, that we do not have so many observations.

  • It is always better to show the data as raw as possible!

We will now add the raw data to the plot.

  • Note that we set the outlier.shape=NA in the geom_boxplot function because because we will add all raw data anyway.
  • We add the raw data using geom_point(position="jitter"), with the argument position=‘jitter’ we will add some random noise to the x coordinate so that we can see all data.
ap %>%  
  ggplot(aes(x=trt,y=rel)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter")

This is an informative plot!


1.3 Some concepts

  • Why do we need more than one student per group?

  • What are the meaning and the consequences of the term “randomly”?

  • Consider two designs:

  1. A research assistant selects 20 male students with smelly armpits from his faculty.

  2. A research assistant selects 20 random people with smelly armpits from the Belgian population.


ap %>%  
  ggplot(aes(x=trt,y=rel)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter") + 
  ylim(0,100)

ap2 %>%  
  ggplot(aes(x=trt,y=rel)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter") + 
  ylim(0,100)


  • Design 1: smaller variability

  • Design 2: larger variability and lower relative abundance of Staphylococcus

  • What is the best design?


  • Random sampling is closely related to the concept of the population or the scope of the study.

  • Based on a sample of subjects, the researchers want to come to conclusions that hold for

    • all kinds of people
    • only male students
  • Scope of the study should be well specified before the start of the study.

  • For the statistical analysis to be valid, it is required that the subjects are selected completely at random from the population to which we want to generalize our conclusions.

  • Selecting completely at random from a population implies:
    • all subjects in the population should have the same probability of being selected in the sample,
    • the selection of a subject in the sample should be independent from the selection of the other subjects in the sample.
  • The sample is thus supposed to be representative for the population, but still it is random.

  • What does this imply?


2 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)
# A tibble: 6 x 76
     ID SurveyYr Gender   Age AgeDecade AgeMonths Race1 Race3 Education
  <int> <fct>    <fct>  <int> <fct>         <int> <fct> <fct> <fct>    
1 51624 2009_10  male      34 " 30-39"        409 White <NA>  High Sch~
2 51624 2009_10  male      34 " 30-39"        409 White <NA>  High Sch~
3 51624 2009_10  male      34 " 30-39"        409 White <NA>  High Sch~
4 51625 2009_10  male       4 " 0-9"           49 Other <NA>  <NA>     
5 51630 2009_10  female    49 " 40-49"        596 White <NA>  Some Col~
6 51638 2009_10  male       9 " 0-9"          115 White <NA>  <NA>     
# ... with 67 more variables: MaritalStatus <fct>, HHIncome <fct>,
#   HHIncomeMid <int>, Poverty <dbl>, HomeRooms <int>, HomeOwn <fct>,
#   Work <fct>, Weight <dbl>, Length <dbl>, HeadCirc <dbl>, Height <dbl>,
#   BMI <dbl>, BMICatUnder20yrs <fct>, BMI_WHO <fct>, Pulse <int>,
#   BPSysAve <int>, BPDiaAve <int>, BPSys1 <int>, BPDia1 <int>,
#   BPSys2 <int>, BPDia2 <int>, BPSys3 <int>, BPDia3 <int>,
#   Testosterone <dbl>, DirectChol <dbl>, TotChol <dbl>, UrineVol1 <int>,
#   UrineFlow1 <dbl>, UrineVol2 <int>, UrineFlow2 <dbl>, Diabetes <fct>,
#   DiabetesAge <int>, HealthGen <fct>, DaysPhysHlthBad <int>,
#   DaysMentHlthBad <int>, LittleInterest <fct>, Depressed <fct>,
#   nPregnancies <int>, nBabies <int>, Age1stBaby <int>,
#   SleepHrsNight <int>, SleepTrouble <fct>, PhysActive <fct>,
#   PhysActiveDays <int>, TVHrsDay <fct>, CompHrsDay <fct>,
#   TVHrsDayChild <int>, CompHrsDayChild <int>, Alcohol12PlusYr <fct>,
#   AlcoholDay <int>, AlcoholYear <int>, SmokeNow <fct>, Smoke100 <fct>,
#   Smoke100n <fct>, SmokeAge <int>, Marijuana <fct>, AgeFirstMarij <int>,
#   RegularMarij <fct>, AgeRegMarij <int>, HardDrugs <fct>, SexEver <fct>,
#   SexAge <int>, SexNumPartnLife <int>, SexNumPartYear <int>,
#   SameSex <fct>, SexOrientation <fct>, PregnantNow <fct>
glimpse(NHANES)
Observations: 10,000
Variables: 76
$ ID               <int> 51624, 51624, 51624, 51625, 51630, 51638, 516...
$ SurveyYr         <fct> 2009_10, 2009_10, 2009_10, 2009_10, 2009_10, ...
$ Gender           <fct> male, male, male, male, female, male, male, f...
$ 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, 5...
$ Race1            <fct> White, White, White, Other, White, White, Whi...
$ Race3            <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
$ Education        <fct> High School, High School, High School, NA, So...
$ MaritalStatus    <fct> Married, Married, Married, NA, LivePartner, N...
$ HHIncome         <fct> 25000-34999, 25000-34999, 25000-34999, 20000-...
$ HHIncomeMid      <int> 30000, 30000, 30000, 22500, 40000, 87500, 600...
$ Poverty          <dbl> 1.36, 1.36, 1.36, 1.07, 1.91, 1.84, 2.33, 5.0...
$ HomeRooms        <int> 6, 6, 6, 9, 5, 6, 7, 6, 6, 6, 5, 10, 6, 10, 1...
$ HomeOwn          <fct> Own, Own, Own, Own, Rent, Rent, Own, Own, Own...
$ Work             <fct> NotWorking, NotWorking, NotWorking, NA, NotWo...
$ Weight           <dbl> 87.4, 87.4, 87.4, 17.0, 86.7, 29.8, 35.2, 75....
$ Length           <dbl> 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, N...
$ Height           <dbl> 164.7, 164.7, 164.7, 105.4, 168.4, 133.1, 130...
$ BMI              <dbl> 32.22, 32.22, 32.22, 15.30, 30.57, 16.82, 20....
$ BMICatUnder20yrs <fct> 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, 3...
$ Pulse            <int> 70, 70, 70, NA, 86, 82, 72, 62, 62, 62, 60, 6...
$ BPSysAve         <int> 113, 113, 113, NA, 112, 86, 107, 118, 118, 11...
$ BPDiaAve         <int> 85, 85, 85, NA, 75, 47, 37, 64, 64, 64, 63, 7...
$ BPSys1           <int> 114, 114, 114, NA, 118, 84, 114, 106, 106, 10...
$ BPDia1           <int> 88, 88, 88, NA, 82, 50, 46, 62, 62, 62, 64, 7...
$ BPSys2           <int> 114, 114, 114, NA, 108, 84, 108, 118, 118, 11...
$ BPDia2           <int> 88, 88, 88, NA, 74, 50, 36, 68, 68, 68, 62, 7...
$ BPSys3           <int> 112, 112, 112, NA, 116, 88, 106, 118, 118, 11...
$ BPDia3           <int> 82, 82, 82, NA, 76, 44, 38, 60, 60, 60, 64, 7...
$ Testosterone     <dbl> 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,...
$ TotChol          <dbl> 3.49, 3.49, 3.49, NA, 6.70, 4.86, 4.09, 5.82,...
$ UrineVol1        <int> 352, 352, 352, NA, 77, 123, 238, 106, 106, 10...
$ UrineFlow1       <dbl> NA, NA, NA, NA, 0.094, 1.538, 1.322, 1.116, 1...
$ UrineVol2        <int> 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, N...
$ Diabetes         <fct> 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, N...
$ HealthGen        <fct> Good, Good, Good, NA, Good, NA, NA, Vgood, Vg...
$ DaysPhysHlthBad  <int> 0, 0, 0, NA, 0, NA, NA, 0, 0, 0, 10, 0, 4, NA...
$ DaysMentHlthBad  <int> 15, 15, 15, NA, 10, NA, NA, 3, 3, 3, 0, 0, 0,...
$ LittleInterest   <fct> Most, Most, Most, NA, Several, NA, NA, None, ...
$ Depressed        <fct> Several, Several, Several, NA, Several, NA, N...
$ nPregnancies     <int> NA, NA, NA, NA, 2, NA, NA, 1, 1, 1, NA, NA, N...
$ nBabies          <int> NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, NA...
$ Age1stBaby       <int> NA, NA, NA, NA, 27, NA, NA, NA, NA, NA, NA, N...
$ SleepHrsNight    <int> 4, 4, 4, NA, 8, NA, NA, 8, 8, 8, 7, 5, 4, NA,...
$ SleepTrouble     <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, N...
$ PhysActive       <fct> No, No, No, NA, No, NA, NA, Yes, Yes, Yes, Ye...
$ PhysActiveDays   <int> NA, NA, NA, NA, NA, NA, NA, 5, 5, 5, 7, 5, 1,...
$ TVHrsDay         <fct> 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, N...
$ 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, Yes...
$ 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, 104...
$ 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, Y...
$ Smoke100n        <fct> Smoker, Smoker, Smoker, NA, Smoker, NA, NA, N...
$ SmokeAge         <int> 18, 18, 18, NA, 38, NA, NA, NA, NA, NA, 13, N...
$ Marijuana        <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes...
$ AgeFirstMarij    <int> 17, 17, 17, NA, 18, NA, NA, 13, 13, 13, NA, 1...
$ RegularMarij     <fct> No, No, No, NA, No, NA, NA, No, No, No, NA, Y...
$ AgeRegMarij      <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 2...
$ HardDrugs        <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, N...
$ SexEver          <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes...
$ SexAge           <int> 16, 16, 16, NA, 12, NA, NA, 13, 13, 13, 17, 2...
$ SexNumPartnLife  <int> 8, 8, 8, NA, 10, NA, NA, 20, 20, 20, 15, 7, 1...
$ SexNumPartYear   <int> 1, 1, 1, NA, 1, NA, NA, 0, 0, 0, NA, 1, 1, NA...
$ SameSex          <fct> No, No, No, NA, Yes, NA, NA, Yes, Yes, Yes, N...
$ SexOrientation   <fct> Heterosexual, Heterosexual, Heterosexual, NA,...
$ PregnantNow      <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...

2.1 Data exploration

Suppose that we are interested in assessing the difference in direct cholesterol levels between males and females older than 25 years.

  1. We pipe the dataset to the function filter to filter the data according to age.
  2. 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.

  1. We filter on age and remove subjects with missing values (NA).
  2. We only select the variables Gender and DirectChol from the dataset to avoid unnecessary variables.
  3. 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
# A tibble: 2 x 5
  Gender  mean    sd     n      se
  <fct>  <dbl> <dbl> <int>   <dbl>
1 female 0.553 0.408  3099 0.00733
2 male   0.238 0.400  3025 0.00727

2.2 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
# A tibble: 20 x 3
   Gender DirectChol cholLog
   <fct>       <dbl>   <dbl>
 1 female       1.6   0.678 
 2 female       1.4   0.485 
 3 female       1.68  0.748 
 4 female       1.4   0.485 
 5 female       1.32  0.401 
 6 female       1.16  0.214 
 7 female       1.94  0.956 
 8 female       1.55  0.632 
 9 female       1.58  0.660 
10 female       1.29  0.367 
11 male         0.72 -0.474 
12 male         1.89  0.918 
13 male         2.48  1.31  
14 male         2.38  1.25  
15 male         0.98 -0.0291
16 male         0.88 -0.184 
17 male         0.91 -0.136 
18 male         1.73  0.791 
19 male         1.22  0.287 
20 male         1.22  0.287 

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))
# A tibble: 2 x 5
  Gender  mean    sd     n     se
  <fct>  <dbl> <dbl> <int>  <dbl>
1 female 0.563 0.215    10 0.0679
2 male   0.402 0.630    10 0.199 

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 = 0.76309, df = 18, p-value = 0.4553
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.2817359  0.6031382
sample estimates:
mean in group female   mean in group male 
           0.5627670            0.4020659 

2.3 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))
# A tibble: 2 x 5
  Gender  mean    sd     n    se
  <fct>  <dbl> <dbl> <int> <dbl>
1 female 0.457 0.584    10 0.185
2 male   0.359 0.502    10 0.159
t.test(cholLog~Gender,samp2,var.equal=TRUE)

    Two Sample t-test

data:  cholLog by Gender
t = 0.40094, df = 18, p-value = 0.6932
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.4139006  0.6091374
sample estimates:
mean in group female   mean in group male 
           0.4566768            0.3590584 

2.4 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))
# A tibble: 2 x 5
  Gender  mean    sd     n    se
  <fct>  <dbl> <dbl> <int> <dbl>
1 female 0.259 0.328    10 0.104
2 male   0.638 0.365    10 0.115
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 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 

2.5 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] 7783
sum(res[,2]>0.05)
[1] 12214
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 (7783 samples) or the average difference in cholesterol levels were not statistically significant (12214 samples). The latter is because the power is rather low to detect the difference with 10 samples in each group.


2.6 Assignment

  1. Copy the code chunk with the simulation study
  2. Add it here below
  3. Modify the sample size to 50.
  4. What do you observe?

3 Salk Study

  • In 1916, the US experienced the first large epidemic of polio.
  • John Salk developed a vaccine with promising results in the lab in the early fifties.
  • In 1954, the National Foundation for Infantile Paralysis (NFIP) has setup a large study to assess the effectiveness of the Salk vaccine.
  • Suppose that the NFIP would have vaccinated a large number of children in 1954 and would have observed that the polio incidence in 1954 was lower than in 1953. Could they have concluded that the vaccine was effective?

3.1 NFIP Study

3.1.1 Design

  • Large simultaneous study with cases, vaccinated children, and controls, non-vaccinated children.
  • All schools in districts with high polio incidence
  • Cases: children with consent for vaccination from second grade of primary school.
  • Controls: children from first and third grade.

3.1.2 Data

nfip<-data.frame(group=c("cases","control","noConcent"),grade=c("g2","g1g3","g2"),vaccin=c("yes","no","no"),total=c(221998,725173,123605),polio=c(54,391,56))
nfip$noPolio<-nfip$total-nfip$polio
knitr::kable(nfip)
group grade vaccin total polio noPolio
cases g2 yes 221998 54 221944
control g1g3 no 725173 391 724782
noConcent g2 no 123605 56 123549

Compare polio incidence?

What can we conclude?


3.2 Confounding

  • We observe a lower polio (P) incidence for children for who no consent was given than for the children in the control group.

  • Consent for vaccination (V) was associated with the socio-economic status (S).

  • Children of lower socio-economic status were more resistant to the disease.

  • The groups of cases and controls are not comparable:
    • difference in age,
    • difference in socio-economic status and
    • difference in susceptible for disease.

3.3 Salk Study

3.3.1 Design

A new study was conducted: Randomized double blind study

  • Children are assigned at random to the control or case treatment arm after consent was given by the parents.
  • Control: vaccination with placebo
  • Treatment: vaccination with vaccine
  • double blinding:
    • parents did not know if their child was vaccinated or received the placebo
    • care-giver/researchers did not know if the child was vaccinated or received placebo

3.3.2 Data

salk<-data.frame(group=c("cases","control","noConcent"),treatment=c("vaccine","placebo","none"),total=c(200745,
201229, 338778),polio=c(57,142,157))
salk$noPolio<-salk$total-salk$polio
salk$incidencePM<-round(salk$polio/salk$total*1e6,0)
knitr::kable(salk)
group treatment total polio noPolio incidencePM
cases vaccine 200745 57 200688 284
control placebo 201229 142 201087 706
noConcent none 338778 157 338621 463
  • We observe a much larger effect now that the cases and the controls are comparable, incidence of 284 and 706 per million, respectively.

  • The polio incidence for children with no consent remains similar, and 463 per million in the NFIP and Salk study, respectively.


4 Scientific Method

  • Empirical data is key in the life sciences.
  • Research is largely driven by data.

  • Nature: biological process which we study

  • Deduction: deduce logical consequences of the theory/hypothesis that can be experimentally validated.

  • Experiment: collect data on the process. The data are a manifestation of the real process. The experiment has to be representative and reproducible and should challenge the theory. Experimental Design!

  • Statistical inference: Bridge to confront the model/hypothesis to the data \(\rightarrow\) Cornerstone of the scientific method.

  • Falsification principle: Data cannot be used to prove a model/hypothesis, only to reject it.

  • Data-exploration and analysis is typically used to refine the theory and to generate new hypotheses.


5 Role of Statistics in the Life Sciences

  • We have seen that
    • it is important to carefully specify the scope of the study before the experiment,
    • the sample size matters,
    • we should be aware of confounding, and
    • a proper control is required.

\(\rightarrow\) Good experimental design is crucial!

  • We also observed that there is variability in the population and because we can only sample a small part of the population our results and conclusions are subjected to uncertainty.

  • Statistics is the science on
    1. collecting (experimental design),
    2. exploring (data exploration) and
    3. learning from data and to generalize what we observe in the sample towards the population while quantifying, controlling and reporting variability and uncertainty (statistical modelling and statistical inference).
  • Therefore, statistics plays an important role in almost all sciences (e.g. column “points of significance” in Nature Methods. http://blogs.nature.com/methagora/2013/08/giving_statistics_the_attention_it_deserves.html)



LS0tCnRpdGxlOiAiMS4gSW50cm9kdWN0aW9uOiBXaHkgZG8gd2UgbmVlZCBzdGF0aXN0aWNzIiAKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCm91dHB1dDoKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgICAgCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICB0b2M6IHRydWUKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgojU21lbGx5IGFybXBpdCBleGFtcGxlCgotIFNtZWxseSBhcm1waXRzIGFyZSBub3QgY2F1c2VkIGJ5IHN3ZWF0IGl0c2VsZi4gVGhlIHNtZWxsIGlzIGNhdXNlZCBieSBzcGVjaWZpYyBtaWNyby1vcmdhbmlzbXMgYmVsb25naW5nIHRvIHRoZSBncm91cCBvZiAqQ29yeW5lYmFjdGVyaXVtIHNwcC4qIHRoYXQgbWV0YWJvbGlzZSBzd2VhdC4KQW5vdGhlciBncm91cCBvZiBhYnVuZGFudCBiYWN0ZXJpYSBhcmUgdGhlICpTdGFwaHlsb2NvY2N1cyBzcHAuKiwgdGhlc2UgYmFjdGVyaWEgZG8gbm90IG1ldGFib2xpc2Ugc3dlYXQgaW4gc21lbGx5IGNvbXBvdW5kcy4KCi0gVGhlIENNRVQtZ3JvZXAgYXQgR2hlbnQgVW5pdmVyc2l0eSBkb2VzIHJlc2VhcmNoIG9uIHRyYW5zcGxhbnRpbmcgdGhlIGFybXBpdCBtaWNyb2Jpb21lIHRvIHNhdmUgcGVvcGxlIHdpdGggc21lbGx5IGFybXBpdHMuCgotIFByb3Bvc2VkIFRoZXJhcHk6CiAgCTEuIFJlbW92ZSBhcm1waXQtbWljcm9iaW9tZSB3aXRoIGFudGliaW90aWNzCiAgICAyLiBJbmZsdWVuY2UgYXJtcGl0IG1pY3JvYmlvbWUgd2l0aCBtaWNyb2JpYWwgIHRyYW5zcGxhbnQgKGh0dHBzOi8veW91dHUuYmUvOVJJRnlxTFhkVncpCgotIEV4cGVyaW1lbnQ6CgogICAgLSAyMCBzdWJqZWN0cyB3aXRoIHNtZWxseSBhcm1waXRzIGFyZSBhdHRyaWJ1dGVkIHRvIG9uZSBvZiB0d28gdHJlYXRtZW50IGdyb3VwcwogICAgLSBwbGFjZWJvIChvbmx5IGFudGliaW90aWNzKQogICAgLSB0cmFuc3BsYW50IChhbnRpYmlvdGljcyBmb2xsb3dlZCBieSBtaWNyb2JpYWwgdHJhbnNwbGFudCkuCiAgICAtIFRoZSBtaWNyb2Jpb21lIGlzIHNhbXBsZWQgNiB3ZWVrcyB1cG9uIHRoZSB0cmVhdG1lbnQuCiAgICAtIFRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgKlN0YXBoeWxvY29jY3VzIHNwcC4qIG9uICpDb3J5bmViYWN0ZXJpdW0gc3BwLiogKyAqU3RhcGh5bG9jb2NjdXMgc3BwLiogaW4gdGhlIG1pY3JvYmlvbWUgaXMgbWVhc3VyZWQgdmlhIERHR0UgKCpEZW5hdHVyaW5nIEdyYWRpZW50IEdlbCBFbGVjdHJvcGhvcmVzaXMqKS4KCi0tLQoKIyMgSW1wb3J0IHRoZSBkYXRhCmBgYHtyfQpyZWFkX2xpbmVzKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvYXJtcGl0LmNzdiIpCmBgYAoKVGhlIGZpbGUgaXMgY29tbWEgc2VwYXJhdGVkIGFuZCBpbiB0aWR5IGZvcm1hdAoKYGBge3J9CmFwPC1yZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL2FybXBpdC5jc3YiKQphcApgYGAKCi0tLQoKIyMgRGF0YSBFeHBsb3JhdGlvbiBhbmQgRGVzY3JpcHRpdmUgU3RhdGlzdGljcwoKLSBEYXRhIGV4cGxvcmF0aW9uIGlzIGV4dHJlbWVseSBpbXBvcnRhbnQgdG8gZ2V0IGluc2lnaHQgaW4gdGhlIGRhdGEuIAotIEl0IGlzIG9mdGVuIHVuZGVycmF0ZWQgYW5kIG92ZXJsb29rZWQuIAoKIyMjIERlc2NyaXB0aXZlIHN0YXRpc3RpY3MKV2UgZmlyc3Qgc3VtbWFyaXplIHRoZSBkYXRhIGFuZCBjYWxjdWxhdGUgdGhlIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhbmQgc3RhbmRhcmQgZXJyb3IgYW5kIHN0b3JlIHRoZSByZXN1bHQgaW4gYW4gb2JqZWN0IGFwUmVsU3VtIHZpYSAnYXBSZWxTdW08LWAKCjEuIFdlIHBpcGUgdGhlIGBhcGAgZGF0YWZyYW1lIHRvIHRoZSBncm91cF9ieSBmdW5jdGlvbiB0byBncm91cCB0aGUgZGF0YSBieSB0cmVhdG1lbnQgdHJ0IGBncm91cF9ieSh0cnQpYAoyLiBXZSBwaXBlIHRoZSByZXN1bHQgdG8gdGhlIGBzdW1tYXJpemVfYXRgIGZ1bmN0aW9uIHRvIHN1bW1hcml6ZSB0aGUgInJlbCIgdmFyaWFibGUgYW5kIGNhbGN1bGF0ZSB0aGUgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uIGFuZCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyAKMy4gV2UgcGlwZSB0aGUgcmVzdWx0IHRvIHRoZSBgbXV0YXRlYCBmdW5jdGlvbiB0byBtYWtlIGEgbmV3IHZhcmlhYmxlIGluIHRoZSBkYXRhIGZyYW1lIGBzZWAgZm9yIHdoaWNoIHdlIGNhbGN1bGF0ZSB0aGUgc3RhbmRhcmQgZXJyb3IgCgoKYGBge3J9CmFwUmVsU3VtPC1hcCU+JQogIGdyb3VwX2J5KHRydCklPiUKICBzdW1tYXJpemVfYXQoInJlbCIsCiAgICAgICAgICAgICAgIGxpc3QobWVhbj1+bWVhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIHNkPX5zZCguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG49ZnVuY3Rpb24oeCkgeCU+JWlzLm5hJT4lYCFgJT4lc3VtKSkgJT4lCiAgbXV0YXRlKHNlPXNkL3NxcnQobikpCgphcFJlbFN1bQpgYGAKCi0tLQoKIyMjIFBsb3RzCldlIHdpbGwgdXNlIGdncGxvdDIgdG8gbWFrZSBvdXIgcGxvdHMuIApXaXRoIHRoZSBnZ3Bsb3QyIGxpYnJhcnkgd2UgY2FuIGVhc2lseSBidWlsZCBwbG90cyBieSBhZGRpbmcgbGF5ZXJzLgoKIyMjIyBiYXJwbG90CgoxLiBXZSBwaXBlIG91ciBzdW1tYXJpemVkIGRhdGEgdG8gdGhlIGBnZ3Bsb3RgIGZ1bmN0aW9uIGFuZCB3ZSBzZWxlY3QgdGhlIHRyZWF0bWVudCB2YXJpYWJsZSB0cnQgYW5kIHRoZSB2YXJpYWJsZSBtZWFuIGZvciBwbG90dGluZyBgYWVzKHg9dHJ0LHk9bWVhbilgCgoyLiBXZSBtYWtlIGEgYmFycGxvdCBiYXNlZCBvbiB0aGlzIGRhdGEgdXNpbmcgdGhlIGBnZW9tX2JhcmAgZnVuY3Rpb24uIFRoZSBzdGF0aXN0aWMgaXMgYHN0YXQ9ImlkZW50aXR5ImAgYmVjYXVzZSB0aGUgYmFyIGhlaWdodCBzaG91bGQgYmUgZXF1YWwgdGhlIHZhbHVlIGZvciB0aGUgbWVhbiBvZiB0aGUgcmVsYXRpdmUgYWJ1bmRhbmNlLgoKYGBge3J9CmFwUmVsU3VtJT4lIAogIGdncGxvdChhZXMoeD10cnQseT1tZWFuKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgCmBgYAoKLSBJcyB0aGlzIHBsb3QgaW5mb3JtYXRpdmU/PwoKLS0tCgpXZSB3aWxsIG5vdyBhZGQgc3RhbmRhcmQgZXJyb3JzIHRvIHRoZSBwbG90CnVzaW5nIGBnZW9tX2Vycm9yYmFyYCBmdW5jdGlvbiBhbmQgc3BlY2lmeSB0aGUgbWluaW11bSBhbmQgbWF4aW11bSB2YWx1ZSBmb3Igb2YgdGhlIGVycm9yIGJhciwgdGhlIHdpZHRoIGNvbW1hbmQgaXMgdXNlZCB0byBzZXQgdGhlIHdpZHRoIG9mIHRoZSBlcnJvciBiYXIgc21hbGxlciB0aGFuIHRoZSB3aWR0aCBvZiB0aGUgYmFyLiAKCmBgYHtyfQphcFJlbFN1bSU+JSAKICBnZ3Bsb3QoYWVzKHg9dHJ0LHk9bWVhbikpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNlLHltYXg9bWVhbitzZSksd2lkdGg9LjIpCmBgYAoKLSBJcyB0aGlzIHBsb3QgaW5mb3JtYXRpdmU/PwoKLS0tCgojIyMjIGJveHBsb3RzCgpJIGNvbnNpZGVyIGJhcnBsb3RzIHRvIGJlIGJhZCBwbG90cwoKLSBUaGV5IGFyZSBub3QgaW5mb3JtYXRpdmUKLSBUaGV5IGp1c3QgdmlzdWFsaXplIGEgdHdvIHBvaW50IHN1bW1hcnkgb2YgdGhlIGRhdGEuIEl0IGlzIGJldHRlciB0byBkbyB0aGlzIGluIGEgdGFibGUKLSBUaGV5IHVzZSBhIGxvdCBvZiBzcGFjZSAoZS5nLiBmcm9tIHplcm8gdXAgdG8gdGhlIG1pbmltdW0gcmVsYXRpdmUgYWJ1bmRhbmNlKSB3aGVyZSBubyBkYXRhIGFyZSBwcmVzZW50LiAKCkl0IGlzIGJldHRlciB0byBnZXQgYSB2aWV3IG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGRhdGEuIFdlIGNhbiB1c2UgYSBib3hwbG90IGZvciB0aGlzIHB1cnBvc2UuCldlIGZpcnN0IGV4cGxhaW4gd2hhdCBhIGJveHBsb3QuIAoKLS0tCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KZmVtIDwtIE5IQU5FUzo6TkhBTkVTICU+JSBmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIiAmICFpcy5uYShEaXJlY3RDaG9sKSkgJT4lIHNlbGVjdChEaXJlY3RDaG9sKQpib3hwbG90KGZlbSREaXJlY3RDaG9sLCB5bGFiPSJEaXJlY3QgY2hvbGVzdGVyb2wiLGNleC5sYWI9MS41LGNleC5heGlzPTEuNSxjZXgubWFpbj0xLjUpCnJhbmdlQ2w8LXF1YW50aWxlKGZlbSREaXJlY3RDaG9sLGMoLjI1LC43NSkpK2MoLTEsMSkqZGlmZihxdWFudGlsZShmZW0kRGlyZWN0Q2hvbCxjKC4yNSwuNzUpKSkqMS41CmJveFlzPC1jKHJhbmdlKGZlbSREaXJlY3RDaG9sW2ZlbSREaXJlY3RDaG9sPD1yYW5nZUNsWzJdJmZlbSREaXJlY3RDaG9sPj1yYW5nZUNsWzFdXSkscXVhbnRpbGUoZmVtJERpcmVjdENob2wsYyguMjUsLjUsLjc1KSkscmFuZ2VDbFsyXSsobWF4KGZlbSREaXJlY3RDaG9sKS1yYW5nZUNsWzJdKS8yKQp0ZXh0KDEuMyxib3hZcyxsYWJlbHM9Yygid2lza2VyIiwid2lza2VyIiwieDI1IiwibWVkaWFhbiIsIng3NSIsIm91dGxpZXJzIikscG9zPTQsY2V4PTEuMykKbGluZXMoYygxLjEsMS4zLDEuMywxLjEpLGMocmFuZ2VDbFsyXSxyYW5nZUNsWzJdKyhtYXgoZmVtJERpcmVjdENob2wpLXJhbmdlQ2xbMl0pLzIscmFuZ2VDbFsyXSsobWF4KGZlbSREaXJlY3RDaG9sKS1yYW5nZUNsWzJdKS8yLG1heChmZW0kRGlyZWN0Q2hvbCkpLGx0eT0yKQpgYGAKCi0tLQoKV2Ugd2lsbCBub3cgbWFrZSBhIGJveHBsb3QgZm9yIHRoZSBhcCBkYXRhCgoxLiBXZSBwaXBlIHRoZSBgYXBgIGRhdGFmcmFtZSB0byB0aGUgZ2dwbG90IGNvbW1hbmQKMi4gV2Ugc2VsZWN0IHRoZSBkYXRhIHdpdGggdGhlIGNvbW1hbmQgYGdncGxvdChhZXMoeD10cnQseT1yZWwpKWAKMy4gV2UgYWRkIGEgYm94cGxvdCB3aXRoIHRoZSBjb21tYW5kIGBnZW9tX2JveHBsb3QoKWAKICAgIApgYGB7cn0KYXAgJT4lICAKICBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsKSkgKyAKICBnZW9tX2JveHBsb3QoKQpgYGAKCi0tLQoKLSBOb3RlLCB0aGF0IHdlIGRvIG5vdCBoYXZlIHNvIG1hbnkgb2JzZXJ2YXRpb25zLgoKLSBJdCBpcyBhbHdheXMgYmV0dGVyIHRvIHNob3cgdGhlIGRhdGEgYXMgcmF3IGFzIHBvc3NpYmxlIQoKV2Ugd2lsbCBub3cgYWRkIHRoZSByYXcgZGF0YSB0byB0aGUgcGxvdC4KCi0gTm90ZSB0aGF0IHdlIHNldCB0aGUgb3V0bGllci5zaGFwZT1OQSBpbiB0aGUgZ2VvbV9ib3hwbG90IGZ1bmN0aW9uIGJlY2F1c2UgYmVjYXVzZSB3ZSB3aWxsIGFkZCBhbGwgcmF3IGRhdGEgYW55d2F5LgotIFdlIGFkZCB0aGUgcmF3IGRhdGEgdXNpbmcgYGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpYCwgd2l0aCB0aGUgYXJndW1lbnQgcG9zaXRpb249J2ppdHRlcicgd2Ugd2lsbCBhZGQgc29tZSByYW5kb20gbm9pc2UgdG8gdGhlIHggY29vcmRpbmF0ZSBzbyB0aGF0IHdlIGNhbiBzZWUgYWxsIGRhdGEuCgpgYGB7cn0KYXAgJT4lICAKICBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikKYGBgCgpUaGlzIGlzIGFuIGluZm9ybWF0aXZlIHBsb3QhCgotLS0KCiMjIFNvbWUgY29uY2VwdHMKCi0gV2h5IGRvIHdlIG5lZWQgbW9yZSB0aGFuIG9uZSBzdHVkZW50IHBlciBncm91cD8KCi0gV2hhdCBhcmUgdGhlIG1lYW5pbmcgYW5kIHRoZSBjb25zZXF1ZW5jZXMgb2YgdGhlIHRlcm0gInJhbmRvbWx5Ij8KCi0gQ29uc2lkZXIgdHdvIGRlc2lnbnM6CgoxLiBBIHJlc2VhcmNoIGFzc2lzdGFudCBzZWxlY3RzIDIwIG1hbGUgc3R1ZGVudHMgd2l0aCBzbWVsbHkgYXJtcGl0cyBmcm9tIGhpcyBmYWN1bHR5LgoKMi4gQSByZXNlYXJjaCBhc3Npc3RhbnQgc2VsZWN0cyAyMCByYW5kb20gcGVvcGxlIHdpdGggc21lbGx5IGFybXBpdHMgZnJvbSB0aGUgQmVsZ2lhbiBwb3B1bGF0aW9uLgoKLS0tCgpgYGB7ciBlY2hvPUZBTFNFfQphcDI8LWFwCmhscDwtbG0ocmVsfnRydCxhcCkKYXAyJHJlbDwtcm5vcm0oMjAsbWVhbj1obHAkZml0LTIwLHNkPXNpZ21hKGhscCkqMikKYGBgCgoKYGBge3J9CmFwICU+JSAgCiAgZ2dwbG90KGFlcyh4PXRydCx5PXJlbCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpICsgCiAgeWxpbSgwLDEwMCkKCmFwMiAlPiUgIAogIGdncGxvdChhZXMoeD10cnQseT1yZWwpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGU9TkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKSArIAogIHlsaW0oMCwxMDApCmBgYAoKLS0tCgotIERlc2lnbiAxOiBzbWFsbGVyIHZhcmlhYmlsaXR5CgotIERlc2lnbiAyOiBsYXJnZXIgdmFyaWFiaWxpdHkgYW5kIGxvd2VyIHJlbGF0aXZlIGFidW5kYW5jZSBvZiAqU3RhcGh5bG9jb2NjdXMqCgotIFdoYXQgaXMgdGhlIGJlc3QgZGVzaWduPwoKLS0tCgotIFJhbmRvbSBzYW1wbGluZyBpcyBjbG9zZWx5IHJlbGF0ZWQgdG8gdGhlIGNvbmNlcHQgb2YgdGhlIHBvcHVsYXRpb24gb3IgdGhlIHNjb3BlIG9mIHRoZSBzdHVkeS4KCi0gQmFzZWQgb24gYSBzYW1wbGUgb2Ygc3ViamVjdHMsIHRoZSByZXNlYXJjaGVycyB3YW50IHRvIGNvbWUgdG8gY29uY2x1c2lvbnMgdGhhdCBob2xkIGZvcgoKICAgIC0gYWxsIGtpbmRzIG9mIHBlb3BsZQogICAgLSBvbmx5IG1hbGUgc3R1ZGVudHMKCi0gU2NvcGUgb2YgdGhlIHN0dWR5IHNob3VsZCBiZSB3ZWxsIHNwZWNpZmllZCBiZWZvcmUgdGhlIHN0YXJ0IG9mIHRoZSBzdHVkeS4KCi0gRm9yIHRoZSBzdGF0aXN0aWNhbCBhbmFseXNpcyB0byBiZSB2YWxpZCwgaXQgaXMgcmVxdWlyZWQgdGhhdCB0aGUgc3ViamVjdHMgYXJlIHNlbGVjdGVkIGNvbXBsZXRlbHkgYXQgcmFuZG9tIGZyb20gdGhlIHBvcHVsYXRpb24gdG8gd2hpY2ggd2Ugd2FudCB0byBnZW5lcmFsaXplIG91ciBjb25jbHVzaW9ucy4KCi0gU2VsZWN0aW5nIGNvbXBsZXRlbHkgYXQgcmFuZG9tIGZyb20gYSBwb3B1bGF0aW9uIGltcGxpZXM6CiAgICAtIGFsbCBzdWJqZWN0cyBpbiB0aGUgcG9wdWxhdGlvbiBzaG91bGQgaGF2ZSB0aGUgc2FtZSBwcm9iYWJpbGl0eSBvZiBiZWluZyBzZWxlY3RlZCBpbiB0aGUgc2FtcGxlLAogICAgLSB0aGUgc2VsZWN0aW9uIG9mIGEgc3ViamVjdCBpbiB0aGUgc2FtcGxlIHNob3VsZCBiZSBpbmRlcGVuZGVudCBmcm9tIHRoZSBzZWxlY3Rpb24gb2YgdGhlIG90aGVyIHN1YmplY3RzIGluIHRoZSBzYW1wbGUuCgotIFRoZSBzYW1wbGUgaXMgdGh1cyBzdXBwb3NlZCB0byBiZSByZXByZXNlbnRhdGl2ZSBmb3IgdGhlIHBvcHVsYXRpb24sIGJ1dCBzdGlsbCBpdCBpcyByYW5kb20uCgotIFdoYXQgZG9lcyB0aGlzIGltcGx5PwoKLS0tCgojIFNhbXBsZSB0byBzYW1wbGUgdmFyaWFiaWxpdHkKCk5hdGlvbmFsIEhlYWx0aCBOSGFuZXMgc3R1ZHkKCiAgLSBTaW5jZSAxOTYwIGluZGl2aWR1YWxzIG9mIGFsbCBhZ2VzIGFyZSBpbnRlcnZpZXdlZCBpbiB0aGVpciBob21lcyBldmVyeSB5ZWFyCiAgLSBUaGUgaGVhbHRoIGV4YW1pbmF0aW9uIGNvbXBvbmVudCBvZiB0aGUgc3VydmV5IGlzIGNvbmR1Y3RlZCBpbiBhIG1vYmlsZSBleGFtaW5hdGlvbiBjZW50cmUgKE1FQykuCiAgLSBXZSB3aWxsIHVzZSB0aGlzIGxhcmdlIHN0dWR5IHRvIHNlbGVjdCByYW5kb20gc3ViamVjdHMgZnJvbSB0aGUgQW1lcmljYW4gcG9wdWxhdGlvbi4KICAtIFRoaXMgd2lsbCBoZWxwIHVzIHRvIHVuZGVyc3RhbmQgaG93IHRoZSByZXN1bHRzIG9mIGFuIGFuYWx5c2lzIGFuZCB0aGUgY29uY2x1c2lvbnMgdmFyeSBmcm9tIHNhbXBsZSB0byBzYW1wbGUuCgotLS0KCmBgYHtyfQpsaWJyYXJ5KE5IQU5FUykKaGVhZChOSEFORVMpCmdsaW1wc2UoTkhBTkVTKQpgYGAKCi0tLQoKIyMgRGF0YSBleHBsb3JhdGlvbgoKClN1cHBvc2UgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBhc3Nlc3NpbmcgdGhlIGRpZmZlcmVuY2UgaW4gZGlyZWN0IGNob2xlc3Rlcm9sIGxldmVscyBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzIG9sZGVyIHRoYW4gMjUgeWVhcnMuCgoxLiBXZSBwaXBlIHRoZSBkYXRhc2V0IHRvIHRoZSBmdW5jdGlvbiBgZmlsdGVyYCB0byBmaWx0ZXIgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIGFnZS4gCjIuIFdlIHBsb3QgdGhlIGRpcmVjdCBjaG9sZXN0ZXJvbCBsZXZlbHMuCiAgICAtIFdlIHNlbGVjdCB0aGUgZGF0YSB3aXRoIHRoZSBjb21tYW5kIGBnZ3Bsb3QoYWVzKHg9RGlyZWN0Q2hvbCkpYAogICAgLSBXZSBhZGQgYSBoaXN0b2dyYW0gd2l0aCB0aGUgY29tbWFuZCBgZ2VvbV9oaXN0b2dyYW0oKWAKICAgIC0gV2UgbWFrZSB0byB2ZXJ0aWNhbCBwYW5lbHMgdXNpbmcgdGhlIGNvbW1hbmQgYGZhY2V0X2dyaWQoR2VuZGVyfi4pYAogICAgLSBXZSBjdXN0b21pemUgdGhlIGxhYmVsIG9mIHRoZSB4LWF4aXMgd2l0aCB0aGUgYHhsYWJgIGNvbW1hbmQuCgpgYGB7cn0KTkhBTkVTJT4lZmlsdGVyKEFnZT4yNSklPiUKICBnZ3Bsb3QoYWVzKHg9RGlyZWN0Q2hvbCkpKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGZhY2V0X2dyaWQoR2VuZGVyfi4pICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKG1nL2RsKSIpCmBgYAoKLS0tCgotIENob2xlc3Rlcm9sIGxldmVscyBhbmQgY29uY2VudHJhdGlvbiBtZWFzdXJlbWVudHMgYXJlIG9mdGVuIHNrZXdlZC4KLSBDb25jZW50cmF0aW9ucyBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLgotIFRoZXkgYXJlIG9mdGVuIGxvZyB0cmFuc2Zvcm1lZC4KCmBgYHtyfQpOSEFORVMlPiUKICBmaWx0ZXIoQWdlPjI1KSU+JQogIGdncGxvdChhZXMoeD1EaXJlY3RDaG9sJT4lbG9nMikpKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGZhY2V0X2dyaWQoR2VuZGVyfi4pICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKGxvZzIpIikKYGBgCgpXZSBzZWUgdGhhdCB0aGUgZGF0YSBhcmUgbW9yZSBvciBsZXNzIGJlbGwgc2hhcGVkIHVwb24gbG9nIHRyYW5zZm9ybWF0aW9uLgoKLS0tCgpXZSB3aWxsIG5vdyBjcmVhdGUgYSBzdWJzZXQgb2YgdGhlIGRhdGEgdGhhdCB3ZSB3aWxsIHVzZSB0byBzYW1wbGUgZnJvbSBpbiB0aGUgbmV4dCBzZWN0aW9ucy4KCiAgMS4gV2UgZmlsdGVyIG9uIGFnZSBhbmQgcmVtb3ZlIHN1YmplY3RzIHdpdGggbWlzc2luZyB2YWx1ZXMgKE5BKS4KICAyLiBXZSBvbmx5IHNlbGVjdCB0aGUgdmFyaWFibGVzIEdlbmRlciBhbmQgRGlyZWN0Q2hvbCBmcm9tIHRoZSBkYXRhc2V0IHRvIGF2b2lkIHVubmVjZXNzYXJ5IHZhcmlhYmxlcy4KICAzLiBXaXRoIHRoZSBtdXRhdGUgZnVuY3Rpb24gd2UgY2FuIGFkZCBhIG5ldyB2YXJpYWJsZSBsb2dDaG9sIHdpdGggbG9nIHRyYW5zZm9ybWVkIGRpcmVjdCBjaG9sZXN0ZXJvbCBsZXZlbHMuCgpgYGB7cn0KbmhhbmVzU3ViPC0gTkhBTkVTJT4lCiAgZmlsdGVyKEFnZT4yNSYhaXMubmEoRGlyZWN0Q2hvbCkpICU+JQogIHNlbGVjdChjKCJHZW5kZXIiLCJEaXJlY3RDaG9sIikpICU+JQogIG11dGF0ZShjaG9sTG9nPWxvZzIoRGlyZWN0Q2hvbCkpCmBgYAoKLS0tCgpXZSB3aWxsIGNhbGN1bGF0ZSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgY2hvbExvZyB2YXJpYWJsZSBmb3IgbWFsZXMgYW5kIGZlbWFsZXMgaW4gdGhlIGxhcmdlIGRhdGFzZXQuIApTbyB3ZSBncm91cCBieSBHZW5kZXIKCmBgYHtyfQpjaG9sTG9nU3VtPC0gbmhhbmVzU3ViICU+JSAKICBncm91cF9ieShHZW5kZXIpICU+JQogICBzdW1tYXJpemVfYXQoImNob2xMb2ciLAogICAgICAgICAgICAgICBsaXN0KG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKQoKY2hvbExvZ1N1bQpgYGAKCi0tLQoKIyMgRXhwZXJpbWVudAoKLSBTdXBwb3NlIHRoYXQgd2UgaGF2ZSBubyBhY2Nlc3MgdG8gY2hvbGVzdGVyb2wgbGV2ZWxzIG9mIHRoZSBBbWVyaWNhbiBwb3B1bGF0aW9uLAotIHdlIHdpbGwgaGF2ZSB0byBzZXR1cCBhbiBleHBlcmltZW50LgotIFN1cHBvc2Ugd2UgaGF2ZSBhIGJ1ZGdldCBmb3IgYXNzZXNzaW5nIDEwIGZlbWFsZXMgYW5kIDEwIG1hbGVzLAotIHdlIHdpbGwgc3Vic2V0IDEwIGZlbWFsZXMgYW5kIDEwIG1hbGVzIGF0IHJhbmRvbSBmcm9tIHRoZSBBbWVyaWNhbiBwb3B1bGF0aW9uIGFuZCBtZWFzdXJlIHRoZWlyIGRpcmVjdCBjaG9sZXN0ZXJvbCBsZXZlbHMuCgpgYGB7cn0KZmVtPC1uaGFuZXNTdWIlPiVmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIiklPiVzYW1wbGVfbihzaXplPTEwKQptYWw8LW5oYW5lc1N1YiU+JWZpbHRlcihHZW5kZXI9PSJtYWxlIiklPiVzYW1wbGVfbihzaXplPTEwKQoKc2FtcDwtcmJpbmQoZmVtLG1hbCkKc2FtcApgYGAKCi0tLQoKV2Ugd2lsbCBub3cgcGxvdCB0aGUgZGF0YSB3aXRoIGEgaGlzdG9ncmFtIGFuZCBib3hwbG90cwoKYGBge3J9CnNhbXAgJT4lCiAgZ2dwbG90KGFlcyh4PWNob2xMb2cpKSsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IC4xKSArCiAgZmFjZXRfZ3JpZChHZW5kZXJ+LikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKQoKc2FtcCU+JSAKICBnZ3Bsb3QoYWVzKHg9R2VuZGVyLHk9Y2hvbExvZykpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpCmBgYAoKLS0tCgpXZSBzdW1tYXJpemUgdGhlIGRhdGEKYGBge3J9CnNhbXAgJT4lIAogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgIHN1bW1hcml6ZV9hdCgiY2hvbExvZyIsCiAgICAgICAgICAgICAgIGxpc3QobWVhbj1+bWVhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIHNkPX5zZCguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG49ZnVuY3Rpb24oeCkgeCU+JWlzLm5hJT4lYCFgJT4lc3VtKSkgJT4lCiAgbXV0YXRlKHNlPXNkL3NxcnQobikpCmBgYAoKTm90ZSB0aGF0IHRoZSBzYW1wbGUgbWVhbiBpcyBkaWZmZXJlbnQgZnJvbSB0aGF0IG9mIHRoZSBsYXJnZSBleHBlcmltZW50ICgicG9wdWxhdGlvbiIpIHdlIHNhbXBsZWQgZnJvbS4gCgpXZSB0ZXN0IGZvciB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIE1hbGVzIGFuZCBmZW1hbGVzCgpgYGB7cn0KdC50ZXN0KGNob2xMb2d+R2VuZGVyLHNhbXAsdmFyLmVxdWFsPVRSVUUpCmBgYAoKLS0tCgojIyBSZXBlYXQgdGhlIGV4cGVyaW1lbnQKCklmIHdlIGRvIHRoZSBleHBlcmltZW50IGFnYWluIHdlIHNlbGVjdCBvdGhlciBwZW9wbGUgYW5kIHdlIG9idGFpbiBkaWZmZXJlbnQgcmVzdWx0cy4KCgpgYGB7cn0KZmVtPC1uaGFuZXNTdWIlPiVmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIiklPiVzYW1wbGVfbihzaXplPTEwKQptYWw8LW5oYW5lc1N1YiU+JWZpbHRlcihHZW5kZXI9PSJtYWxlIiklPiVzYW1wbGVfbihzaXplPTEwKQoKc2FtcDI8LXJiaW5kKGZlbSxtYWwpCnNhbXAyJT4lCiAgZ2dwbG90KGFlcyh4PURpcmVjdENob2wlPiVsb2cpKSsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IC4xKSArCiAgZmFjZXRfZ3JpZChHZW5kZXJ+LikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nKSIpCgpzYW1wMiU+JSAKICBnZ3Bsb3QoYWVzKHg9R2VuZGVyLHk9Y2hvbExvZykpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpCgpzYW1wMiAlPiUgCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICAgc3VtbWFyaXplX2F0KCJjaG9sTG9nIiwKICAgICAgICAgICAgICAgbGlzdChtZWFuPX5tZWFuKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgc2Q9fnNkKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgbj1mdW5jdGlvbih4KSB4JT4laXMubmElPiVgIWAlPiVzdW0pKSAlPiUKICBtdXRhdGUoc2U9c2Qvc3FydChuKSkKCnQudGVzdChjaG9sTG9nfkdlbmRlcixzYW1wMix2YXIuZXF1YWw9VFJVRSkKYGBgCgotLS0KCiMjIEFuZCBhZ2FpbgoKYGBge3J9CnNldC5zZWVkKDEyODU3KQpmZW08LW5oYW5lc1N1YiU+JWZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKSU+JXNhbXBsZV9uKHNpemU9MTApCm1hbDwtbmhhbmVzU3ViJT4lZmlsdGVyKEdlbmRlcj09Im1hbGUiKSU+JXNhbXBsZV9uKHNpemU9MTApCgpzYW1wMzwtcmJpbmQoZmVtLG1hbCkKc2FtcDMlPiUKICBnZ3Bsb3QoYWVzKHg9RGlyZWN0Q2hvbCU+JWxvZykpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjEpICsKICBmYWNldF9ncmlkKEdlbmRlcn4uKSArCiAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIChsb2cpIikKCnNhbXAzJT4lIAogIGdncGxvdChhZXMoeD1HZW5kZXIseT1jaG9sTG9nKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikKCgpzYW1wMyAlPiUgCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICAgc3VtbWFyaXplX2F0KCJjaG9sTG9nIiwKICAgICAgICAgICAgICAgbGlzdChtZWFuPX5tZWFuKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgc2Q9fnNkKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgbj1mdW5jdGlvbih4KSB4JT4laXMubmElPiVgIWAlPiVzdW0pKSAlPiUKICBtdXRhdGUoc2U9c2Qvc3FydChuKSkKCnQudGVzdChjaG9sTG9nfkdlbmRlcixzYW1wMyx2YXIuZXF1YWw9VFJVRSkKYGBgCgotLS0KCiMjIFN1bW1hcnkKCi0gQmVjYXVzZSB3ZSBzYW1wbGVkIG90aGVyIHN1YmplY3RzIGluIGVhY2ggc2FtcGxlLCB3ZSBvYnRhaW4gZGlmZmVyZW50IGNob2xlc3Rlcm9sIGxldmVscy4KLSBIb3dldmVyLCBub3Qgb25seSB0aGUgY2hvbGVzdGVyb2wgbGV2ZWxzIGRpZmZlciBmcm9tIHNhbXBsZSB0byBzYW1wbGUgYnV0IGFsc28gdGhlIHN1bW1hcnkgc3RhdGlzdGljczogbWVhbnMsIHN0YW5kYXJkIGRldmlhdGlvbnMgYW5kIHN0YW5kYXJkIGVycm9ycy4KLSBOb3RlLCB0aGF0IGluIHRoZSBsYXN0IHNhbXBsZSB0aGUgbG9nIGNob2xlc3Rlcm9sIGxldmVscyBhcmUgb24gYXZlcmFnZSBsb3dlciBmb3IgZmVtYWxlcyB0aGFuIGZvciBtYWxlczsgYmFzZWQgb24gdGhpcyBzYW1wbGUgd2UgZXZlbiB3b3VsZCB3cm9uZ2x5IGNvbmNsdWRlIHRoYXQgdGhlIGNob2xlc3Rlcm9sIGxldmVscyBmb3IgZmVtYWxlcyBhcmUgb24gYXZlcmFnZSBsYXJnZXIgdGhhbiB0aG9zZSBvZiBtYWxlcy4KCi0gVGhpcyBpbXBsaWVzIHRoYXQgb3VyIGNvbmNsdXNpb25zIGFyZSBhbHNvIHN1YmplY3RlZCB0byB1bmNlcnRhaW50eSBhbmQgbWlnaHQgY2hhbmdlIGZyb20gc2FtcGxlIHRvIHNhbXBsZS4KCi0gU2FtcGxlcyBhcyB0aGUgb25lIHdoZXJlIHRoZSBlZmZlY3Qgc3dhcHMgYW5kIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIGhvd2V2ZXIsIGFyZSB2ZXJ5IHJhcmUuCi0gVGhpcyBpcyBpbGx1c3RyYXRlZCB3aXRoIHRoZSBjb2RlIGJlbG93LCB3aGVyZSB3ZSB3aWxsIGRyYXcgMjAwMDAgcmVwZWF0ZWQgc2FtcGxlcyB3aXRoIHNhbXBsZSBzaXplIDEwIGZvciBmZW1hbGVzIGFuZCBtYWxlcyBmcm9tIHRoZSBOSGFuZXMgc3R1ZHkuCgpgYGB7cn0KbnNpbTwtMjAwMDAKblNhbXA8LTEwCnJlczwtbWF0cml4KDAsbnJvdz1uc2ltLG5jb2w9MikKZmVtPC1uaGFuZXNTdWIlPiVmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIikKbWFsPC1uaGFuZXNTdWIlPiVmaWx0ZXIoR2VuZGVyPT0ibWFsZSIpCgpmb3IgKGkgaW4gMTpuc2ltKQp7CiBmZW1TYW1wPC1zYW1wbGUoZmVtJGNob2xMb2csblNhbXApCiBtYWxTYW1wPC1zYW1wbGUobWFsJGNob2xMb2csblNhbXApCgptZWFuRmVtPC1tZWFuKGZlbVNhbXApCiBtZWFuTWFsPC1tZWFuKG1hbFNhbXApCiBkZWx0YTwtbWVhbkZlbS1tZWFuTWFsCiBzZEZlbTwtc2QoZmVtU2FtcCkKIHNkTWFsPC1zZChtYWxTYW1wKQogc2VGZW08LXNkRmVtL3NxcnQoblNhbXApCiBzZUZlbTwtc2RGZW0vc3FydChuU2FtcCkKIHNkUG9vbDwtc3FydCgoc2RGZW1eMiooblNhbXAtMSkgKyBzZE1hbF4yKihuU2FtcC0xKSkvKDIqblNhbXAtMikpCnR2YWx1ZTwtKGRlbHRhKS8oc2RQb29sKnNxcnQoMS9uU2FtcCsxL25TYW1wKSkKcHZhbHVlPC1wdChhYnModHZhbHVlKSxsb3dlci50YWlsID0gRkFMU0UsZGY9MipuU2FtcC0yKSoyCiByZXNbaSxdPC1jKGRlbHRhLHB2YWx1ZSkKfQpzdW0ocmVzWywyXTwwLjA1JnJlc1ssMV0+MCkKc3VtKHJlc1ssMl0+MC4wNSkKc3VtKHJlc1ssMl08MC4wNSZyZXNbLDFdPDApCgpyZXM8LXJlcyAlPiUgYXMuZGF0YS5mcmFtZQpuYW1lcyhyZXMpIDwtIGMoImRlbHRhIiwicHZhbHVlIikKcmVzICU+JSAKICBnZ3Bsb3QoYWVzKHg9ZGVsdGEseT0tbG9nMTAocHZhbHVlKSxjb2xvcj1wdmFsdWU8MC4wNSkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgeGxhYigiQXZlcmFnZSBjaG9sZXN0ZXJvbCBkaWZmZXJlbmNlIikgKwogIHlsYWIoIi0gbG9nMTAocHZhbHVlKSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwicmVkIikpCgpyZXMgJT4lIAogIGdncGxvdChhZXMoeT1kZWx0YSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeD0wLHk9YyhtZWFuKGZlbSRjaG9sTG9nKS1tZWFuKG1hbCRjaG9sTG9nKSksY29sb3I9InBvcC4gZGlmZiIpKSArCiAgeGxhYigiIikKYGBgCgpPbmx5IGluIGByIHN1bShyZXNbLDJdPDAuMDUmcmVzWywxXTwwKWAgb3V0IG9mIDIwMDAwIHNhbXBsZXMgd2UgY29uY2x1ZGUgdGhhdCB0aGUgbWVhbiBjaG9sZXN0ZXJvbCBsZXZlbCBvZiBtYWxlcyBpcyBzaWduaWZpY2FudGx5IGxvd2VyIHRoYW4gZm9yIGZlbWFsZXMuIEZvciB0aGUgcmVtYWluaW5nIHNhbXBsZXMgdGhlIGNob2xlc3Rlcm9sIGxldmVscyBmb3IgbWFsZXMgd2VyZSBvbiBhdmVyYWdlIHNpZ25pZmljYW50bHkgbG93ZXIgdGhhbiBmb3IgZmVtYWxlcyAoYHIgc3VtKHJlc1ssMl08MC4wNSZyZXNbLDFdPjApYCBzYW1wbGVzKSBvciB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGluIGNob2xlc3Rlcm9sIGxldmVscyB3ZXJlIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IChgciBzdW0ocmVzWywyXT4wLjA1KWAgc2FtcGxlcykuIFRoZSBsYXR0ZXIgaXMgYmVjYXVzZSB0aGUgcG93ZXIgaXMgcmF0aGVyIGxvdyB0byBkZXRlY3QgdGhlIGRpZmZlcmVuY2Ugd2l0aCAxMCBzYW1wbGVzIGluIGVhY2ggZ3JvdXAuCgotLS0KCiMjQXNzaWdubWVudAoKMS4gQ29weSB0aGUgY29kZSBjaHVuayB3aXRoIHRoZSBzaW11bGF0aW9uIHN0dWR5CjIuIEFkZCBpdCBoZXJlIGJlbG93CjMuIE1vZGlmeSB0aGUgc2FtcGxlIHNpemUgdG8gNTAuCjQuIFdoYXQgZG8geW91IG9ic2VydmU/CgotLS0KCiMgU2FsayBTdHVkeQoKLSBJbiAxOTE2LCB0aGUgVVMgZXhwZXJpZW5jZWQgdGhlIGZpcnN0IGxhcmdlIGVwaWRlbWljIG9mIHBvbGlvLgotIEpvaG4gU2FsayBkZXZlbG9wZWQgYSB2YWNjaW5lIHdpdGggcHJvbWlzaW5nIHJlc3VsdHMgaW4gdGhlIGxhYiBpbiB0aGUgZWFybHkgZmlmdGllcy4KLSBJbiAxOTU0LCB0aGUgTmF0aW9uYWwgRm91bmRhdGlvbgpmb3IgSW5mYW50aWxlIFBhcmFseXNpcyAoTkZJUCkgaGFzIHNldHVwIGEgbGFyZ2Ugc3R1ZHkgdG8gYXNzZXNzIHRoZSBlZmZlY3RpdmVuZXNzIG9mIHRoZSBTYWxrIHZhY2NpbmUuCi0gU3VwcG9zZSB0aGF0IHRoZSBORklQIHdvdWxkIGhhdmUgdmFjY2luYXRlZCBhIGxhcmdlIG51bWJlciBvZiBjaGlsZHJlbiBpbiAxOTU0IGFuZCB3b3VsZCBoYXZlIG9ic2VydmVkIHRoYXQgdGhlIHBvbGlvIGluY2lkZW5jZSBpbiAxOTU0IHdhcyBsb3dlciB0aGFuIGluIDE5NTMuIENvdWxkIHRoZXkgaGF2ZSBjb25jbHVkZWQgdGhhdCB0aGUgdmFjY2luZSB3YXMgZWZmZWN0aXZlPwoKLS0tCgojI05GSVAgU3R1ZHkKIyMjRGVzaWduCgotIExhcmdlIHNpbXVsdGFuZW91cyBzdHVkeSB3aXRoIGNhc2VzLCB2YWNjaW5hdGVkIGNoaWxkcmVuLCBhbmQgY29udHJvbHMsICBub24tdmFjY2luYXRlZCBjaGlsZHJlbi4KLSBBbGwgc2Nob29scyBpbiBkaXN0cmljdHMgd2l0aCBoaWdoIHBvbGlvIGluY2lkZW5jZQotIENhc2VzOiBjaGlsZHJlbiB3aXRoIGNvbnNlbnQgZm9yIHZhY2NpbmF0aW9uIGZyb20gc2Vjb25kIGdyYWRlIG9mIHByaW1hcnkgc2Nob29sLgotIENvbnRyb2xzOiBjaGlsZHJlbiBmcm9tICBmaXJzdCBhbmQgdGhpcmQgZ3JhZGUuCgojIyNEYXRhCmBgYHtyfQpuZmlwPC1kYXRhLmZyYW1lKGdyb3VwPWMoImNhc2VzIiwiY29udHJvbCIsIm5vQ29uY2VudCIpLGdyYWRlPWMoImcyIiwiZzFnMyIsImcyIiksdmFjY2luPWMoInllcyIsIm5vIiwibm8iKSx0b3RhbD1jKDIyMTk5OCw3MjUxNzMsMTIzNjA1KSxwb2xpbz1jKDU0LDM5MSw1NikpCm5maXAkbm9Qb2xpbzwtbmZpcCR0b3RhbC1uZmlwJHBvbGlvCmtuaXRyOjprYWJsZShuZmlwKQpgYGAKCkNvbXBhcmUgcG9saW8gaW5jaWRlbmNlPwoKYGBge3IsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9Cm5maXAkaW5jaWRlbmNlUE08LXJvdW5kKG5maXAkcG9saW8vbmZpcCR0b3RhbCoxZTYsMCkKa25pdHI6OmthYmxlKG5maXApCmBgYAoKV2hhdCBjYW4gd2UgY29uY2x1ZGU/CgotLS0KCiMjQ29uZm91bmRpbmcKCgpgYGB7cixlY2hvPUZBTFNFLCBmaWcuYWxpZ24gPSAiY2VudGVyIixvdXQud2lkdGggPSAnNTAlJ30KcGxvdChjKDAsMCwxKSxjKC0yLDIsMCkscGNoPWMoIlMiLCJWIiwiUCIpLHhheHQ9Im5vbmUiLHlheHQ9Im5vbmUiLGF4ZXM9RkFMU0UseGxhYj0iIix5bGFiPSIiLGNleD00LHlsaW09YygtMi4yLDIuMikpCmFycm93cyh4MD0wLjEseDE9LjkseTA9MS44LHkxPTAuMSxsd2Q9NCkKYXJyb3dzKHgwPTAuMSx4MT0uOSx5MD0tMS44LHkxPS0wLjIsbHdkPTQpCmFycm93cyh4MD0wLHgxPTAseTA9LTEuNCx5MT0xLjQsbHdkPTQpCmBgYAoKCi0gV2Ugb2JzZXJ2ZSBhIGxvd2VyIHBvbGlvIChQKSBpbmNpZGVuY2UgZm9yIGNoaWxkcmVuIGZvciB3aG8gbm8gY29uc2VudCB3YXMgZ2l2ZW4gdGhhbiBmb3IgdGhlIGNoaWxkcmVuIGluIHRoZSBjb250cm9sIGdyb3VwLgoKLSBDb25zZW50IGZvciB2YWNjaW5hdGlvbiAoVikgd2FzIGFzc29jaWF0ZWQgd2l0aCB0aGUgc29jaW8tZWNvbm9taWMgc3RhdHVzIChTKS4KCi0gQ2hpbGRyZW4gb2YgbG93ZXIgc29jaW8tZWNvbm9taWMgc3RhdHVzIHdlcmUgbW9yZSByZXNpc3RhbnQgdG8gdGhlIGRpc2Vhc2UuCgotIFRoZSBncm91cHMgb2YgY2FzZXMgYW5kIGNvbnRyb2xzIGFyZSBub3QgY29tcGFyYWJsZToKICAgIC0gZGlmZmVyZW5jZSBpbiBhZ2UsCiAgICAtIGRpZmZlcmVuY2UgaW4gc29jaW8tZWNvbm9taWMgc3RhdHVzIGFuZAogICAgLSBkaWZmZXJlbmNlIGluIHN1c2NlcHRpYmxlIGZvciBkaXNlYXNlLgoKLS0tCgojI1NhbGsgU3R1ZHkKCiMjIyBEZXNpZ24KQSBuZXcgc3R1ZHkgd2FzIGNvbmR1Y3RlZDogUmFuZG9taXplZCBkb3VibGUgYmxpbmQgc3R1ZHkKCiAgLSBDaGlsZHJlbiBhcmUgYXNzaWduZWQgYXQgcmFuZG9tIHRvIHRoZSBjb250cm9sIG9yIGNhc2UgdHJlYXRtZW50IGFybSBhZnRlciBjb25zZW50IHdhcyBnaXZlbiBieSB0aGUgcGFyZW50cy4KICAtIENvbnRyb2w6IHZhY2NpbmF0aW9uIHdpdGggcGxhY2VibwogIC0gVHJlYXRtZW50OiB2YWNjaW5hdGlvbiB3aXRoIHZhY2NpbmUKICAtIGRvdWJsZSBibGluZGluZzoKICAgIC0gcGFyZW50cyBkaWQgbm90IGtub3cgaWYgdGhlaXIgY2hpbGQgd2FzIHZhY2NpbmF0ZWQgb3IgcmVjZWl2ZWQgdGhlIHBsYWNlYm8KICAgIC0gY2FyZS1naXZlci9yZXNlYXJjaGVycyBkaWQgbm90IGtub3cgaWYgdGhlIGNoaWxkIHdhcyB2YWNjaW5hdGVkICBvciByZWNlaXZlZCBwbGFjZWJvCgotLS0KCiMjI0RhdGEKCmBgYHtyfQpzYWxrPC1kYXRhLmZyYW1lKGdyb3VwPWMoImNhc2VzIiwiY29udHJvbCIsIm5vQ29uY2VudCIpLHRyZWF0bWVudD1jKCJ2YWNjaW5lIiwicGxhY2VibyIsIm5vbmUiKSx0b3RhbD1jKDIwMDc0NSwKMjAxMjI5LCAzMzg3NzgpLHBvbGlvPWMoNTcsMTQyLDE1NykpCnNhbGskbm9Qb2xpbzwtc2FsayR0b3RhbC1zYWxrJHBvbGlvCnNhbGskaW5jaWRlbmNlUE08LXJvdW5kKHNhbGskcG9saW8vc2FsayR0b3RhbCoxZTYsMCkKa25pdHI6OmthYmxlKHNhbGspCmBgYAoKLSBXZSBvYnNlcnZlIGEgbXVjaCBsYXJnZXIgZWZmZWN0IG5vdyB0aGF0IHRoZSBjYXNlcyBhbmQgdGhlIGNvbnRyb2xzIGFyZSBjb21wYXJhYmxlLCBpbmNpZGVuY2Ugb2YgYHIgc2FsayRpbmNpZGVuY2VQTVsxXWAgIGFuZCBgciBzYWxrJGluY2lkZW5jZVBNWzJdYCBwZXIgbWlsbGlvbiwgcmVzcGVjdGl2ZWx5LgoKLSBUaGUgcG9saW8gaW5jaWRlbmNlIGZvciBjaGlsZHJlbiB3aXRoIG5vIGNvbnNlbnQgcmVtYWlucyBzaW1pbGFyLCBgciBuZmlwJGluY2lkZW5jZVBNWzNdYCBhbmQgYHIgc2FsayRpbmNpZGVuY2VQTVszXWAgcGVyIG1pbGxpb24gaW4gdGhlIE5GSVAgYW5kIFNhbGsgc3R1ZHksIHJlc3BlY3RpdmVseS4KCi0tLQoKIyBTY2llbnRpZmljIE1ldGhvZAoKLSBFbXBpcmljYWwgZGF0YSBpcyBrZXkgaW4gdGhlIGxpZmUgc2NpZW5jZXMuCi0gUmVzZWFyY2ggaXMgbGFyZ2VseSBkcml2ZW4gYnkgZGF0YS4KCmBgYHtyLGVjaG89RkFMU0UsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQpwbG90KDAsMCxjb2w9MCx4YXh0PSJub25lIix5YXh0PSJub25lIixheGVzPUZBTFNFLHhsYWI9IiIseWxhYj0iIixjZXg9NCx5bGltPWMoLS41LDEuNSkseGxpbT1jKC0uNSwxLjUpKQpsaW5lcyhjKDAsMSksYygwLDApLGx3ZD00KQpsaW5lcyhjKDAsLjUpLGMoMCwxKSxsd2Q9NCkKbGluZXMoYyguNSwxKSxjKDEsMCksbHdkPTQpCnRleHQoMC41LDEuMiwiTmF0dXJlIixjZXg9MikKdGV4dCgwLjgsLjUsIkV4cGVyaW1lbnQiLGNleD0yLHBvcz00LGNvbD0iZGFya3JlZCIpCnRleHQoMSwwLCJEYXRhIixjZXg9Mixwb3M9NCkKdGV4dCgwLjIsLjUsIlRoZW9yeSIsY2V4PTIscG9zPTIsY29sPSJkYXJrcmVkIikKdGV4dCgwLDAsIk1vZGVsIixjZXg9Mixwb3M9MikKdGV4dCgwLjUsLTAuMywiU3RhdGlzdGljYWxcbkluZmVyZW5jZSIsY2V4PTIsY29sPSJkYXJrcmVkIikKYGBgCgotICpOYXR1cmUqOiBiaW9sb2dpY2FsIHByb2Nlc3Mgd2hpY2ggd2Ugc3R1ZHkKCi0gKkRlZHVjdGlvbio6IGRlZHVjZSBsb2dpY2FsIGNvbnNlcXVlbmNlcyBvZiAgdGhlIHRoZW9yeS9oeXBvdGhlc2lzIHRoYXQgY2FuIGJlIGV4cGVyaW1lbnRhbGx5IHZhbGlkYXRlZC4KCi0gKkV4cGVyaW1lbnQqOiBjb2xsZWN0IGRhdGEgb24gdGhlIHByb2Nlc3MuIFRoZSBkYXRhIGFyZSBhIG1hbmlmZXN0YXRpb24gb2YgdGhlIHJlYWwgcHJvY2Vzcy4gVGhlIGV4cGVyaW1lbnQgaGFzIHRvIGJlICpyZXByZXNlbnRhdGl2ZSogYW5kICpyZXByb2R1Y2libGUqIGFuZCBzaG91bGQgY2hhbGxlbmdlIHRoZSB0aGVvcnkuICpFeHBlcmltZW50YWwgRGVzaWduKiEKCi0gKlN0YXRpc3RpY2FsIGluZmVyZW5jZSo6IEJyaWRnZSB0byBjb25mcm9udCB0aGUgbW9kZWwvaHlwb3RoZXNpcyB0byB0aGUgZGF0YSAkXHJpZ2h0YXJyb3ckIENvcm5lcnN0b25lIG9mIHRoZSBzY2llbnRpZmljIG1ldGhvZC4KCi0gKkZhbHNpZmljYXRpb24gcHJpbmNpcGxlKjogRGF0YSBjYW5ub3QgYmUgdXNlZCB0byBwcm92ZSBhIG1vZGVsL2h5cG90aGVzaXMsIG9ubHkgdG8gcmVqZWN0IGl0LgoKLSAqRGF0YS1leHBsb3JhdGlvbiBhbmQgYW5hbHlzaXMqIGlzIHR5cGljYWxseSB1c2VkIHRvIHJlZmluZSB0aGUgdGhlb3J5IGFuZCB0byBnZW5lcmF0ZSBuZXcgaHlwb3RoZXNlcy4KCi0tLQoKIyBSb2xlIG9mIFN0YXRpc3RpY3MgaW4gdGhlIExpZmUgU2NpZW5jZXMKCi0gV2UgaGF2ZSBzZWVuIHRoYXQKICAgIC0gaXQgaXMgaW1wb3J0YW50IHRvIGNhcmVmdWxseSBzcGVjaWZ5IHRoZSBzY29wZSBvZiB0aGUgc3R1ZHkgYmVmb3JlIHRoZSBleHBlcmltZW50LAogICAgLSB0aGUgc2FtcGxlIHNpemUgbWF0dGVycywKICAgIC0gd2Ugc2hvdWxkIGJlIGF3YXJlIG9mIGNvbmZvdW5kaW5nLCBhbmQgCiAgICAtIGEgcHJvcGVyIGNvbnRyb2wgaXMgcmVxdWlyZWQuCgokXHJpZ2h0YXJyb3ckIEdvb2QgZXhwZXJpbWVudGFsIGRlc2lnbiBpcyBjcnVjaWFsIQoKLSBXZSBhbHNvIG9ic2VydmVkIHRoYXQgdGhlcmUgaXMgdmFyaWFiaWxpdHkgaW4gdGhlIHBvcHVsYXRpb24gYW5kIGJlY2F1c2Ugd2UgY2FuIG9ubHkgc2FtcGxlIGEgc21hbGwgcGFydCBvZiB0aGUgcG9wdWxhdGlvbiBvdXIgcmVzdWx0cyBhbmQgY29uY2x1c2lvbnMgYXJlIHN1YmplY3RlZCB0byB1bmNlcnRhaW50eS4KCgoKCi0gU3RhdGlzdGljcyBpcyB0aGUgc2NpZW5jZSBvbgogICAgMS4gY29sbGVjdGluZyAoZXhwZXJpbWVudGFsIGRlc2lnbiksCiAgICAyLiBleHBsb3JpbmcgKGRhdGEgZXhwbG9yYXRpb24pIGFuZAogICAgMy4gbGVhcm5pbmcgZnJvbSBkYXRhIGFuZCB0byBnZW5lcmFsaXplIHdoYXQgd2Ugb2JzZXJ2ZSBpbiB0aGUgc2FtcGxlIHRvd2FyZHMgdGhlIHBvcHVsYXRpb24gd2hpbGUgcXVhbnRpZnlpbmcsIGNvbnRyb2xsaW5nIGFuZCByZXBvcnRpbmcgdmFyaWFiaWxpdHkgYW5kIHVuY2VydGFpbnR5IChzdGF0aXN0aWNhbCBtb2RlbGxpbmcgYW5kIHN0YXRpc3RpY2FsIGluZmVyZW5jZSkuCgotIFRoZXJlZm9yZSwgc3RhdGlzdGljcyBwbGF5cyBhbiBpbXBvcnRhbnQgcm9sZSBpbiBhbG1vc3QgYWxsIHNjaWVuY2VzIChlLmcuIGNvbHVtbiAicG9pbnRzIG9mIHNpZ25pZmljYW5jZSIgaW4gTmF0dXJlIE1ldGhvZHMuIGh0dHA6Ly9ibG9ncy5uYXR1cmUuY29tL21ldGhhZ29yYS8yMDEzLzA4L2dpdmluZ19zdGF0aXN0aWNzX3RoZV9hdHRlbnRpb25faXRfZGVzZXJ2ZXMuaHRtbCkKCi0tLQoKYGBge3IgcG9wMlNhbXAyUG9wLCBvdXQud2lkdGg9JzgwJScsZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmlmICgicGkiJWluJWxzKCkpIHJtKCJwaSIpCmtvcHZvZXRlcjwtZnVuY3Rpb24oeCx5LGFuZ2xlPTAsbD0uMixjZXguZG90PS41LHBjaD0xOSxjb2w9ImJsYWNrIikKewphbmdsZT1hbmdsZS8xODAqcGkKcG9pbnRzKHgseSxjZXg9Y2V4LmRvdCxwY2g9cGNoLGNvbD1jb2wpCmxpbmVzKGMoeCx4K2wqY29zKC1waS8yK2FuZ2xlKSksYyh5LHkrbCpzaW4oLXBpLzIrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbC8yKmNvcygtcGkvMithbmdsZSkseCtsLzIqY29zKC1waS8yK2FuZ2xlKStsLzQqY29zKGFuZ2xlKSksYyh5K2wvMipzaW4oLXBpLzIrYW5nbGUpLHkrbC8yKnNpbigtcGkvMithbmdsZSkrbC80KnNpbihhbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MocGkrYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKHBpK2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yK3BpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzIrcGkvNCthbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsKmNvcygtcGkvMithbmdsZSkseCtsKmNvcygtcGkvMithbmdsZSkrbC8yKmNvcygtcGkvMi1waS80K2FuZ2xlKSksYyh5K2wqc2luKC1waS8yK2FuZ2xlKSx5K2wqc2luKC1waS8yK2FuZ2xlKStsLzIqc2luKC1waS8yLXBpLzQrYW5nbGUpKSxjb2w9Y29sKQp9CgpwYXIobWFyPWMoMCwwLDAsMCksbWFpPWMoMCwwLDAsMCkpCnBsb3QoMCwwLHhsYWI9IiIseWxhYj0iIix4bGltPWMoMCwxMCkseWxpbT1jKDAsMTApLGNvbD0wLHhheHQ9Im5vbmUiLHlheHQ9Im5vbmUiLGF4ZXM9RkFMU0UpCnJlY3QoMCw2LDEwLDEwLGJvcmRlcj0icmVkIixsd2Q9MikKdGV4dCguNSw4LCJwb3B1bGF0aW9uIixzcnQ9OTAsY29sPSJyZWQiLGNleD0yKQpzeW1ib2xzICgzLCA4LCBjaXJjbGVzPTEuNSwgY29sPSJyZWQiLGFkZD1UUlVFLGZnPSJyZWQiLGluY2hlcz1GQUxTRSxsd2Q9MikKc2V0LnNlZWQoMzMwKQpncmlkPXNlcSgwLDEuMywuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewoJYW5nbGUxPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJYW5nbGUyPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJcmFkaXVzPXNhbXBsZShncmlkLHByb2I9Z3JpZF4yKnBpL3N1bShncmlkXjIqcGkpLHNpemU9MSkKCWtvcHZvZXRlcigzK3JhZGl1cypjb3MoYW5nbGUxLzE4MCpwaSksOCtyYWRpdXMqc2luKGFuZ2xlMS8xODAqcGkpLGFuZ2xlPWFuZ2xlMikKfQp0ZXh0KDcuNSw4LCJjaG9sZXN0ZXJvbCBpbiBwb3B1bGF0aW9uIixjb2w9InJlZCIsY2V4PTEuMikKCnJlY3QoMCwwLDEwLDQsYm9yZGVyPSJibHVlIixsd2Q9MikKdGV4dCguNSwyLCJzYW1wbGUiLHNydD05MCxjb2w9ImJsdWUiLGNleD0yKQpzeW1ib2xzICgzLCAyLCBjaXJjbGVzPTEuNSwgY29sPSJyZWQiLGFkZD1UUlVFLGZnPSJibHVlIixpbmNoZXM9RkFMU0UsbHdkPTIpCmZvciAoaSBpbiAwOjIpCglmb3IgKGogaW4gMDo0KQp7CgoJa29wdm9ldGVyKDIuMStqKigzLjktMi4xKS80LDEuMStpKQp9CnRleHQoNy41LDIsImNob2xlc3Rlcm9sIGluIHNhbXBsZSIsY29sPSJibHVlIixjZXg9MS4yKQoKYXJyb3dzKDMsNS45LDMsNC4xLGNvbD0iYmxhY2siLGx3ZD0zKQphcnJvd3MoNyw0LjEsNyw1LjksY29sPSJibGFjayIsbHdkPTMpCnRleHQoMS41LDUsIkVYUC4gREVTSUdOICgxKSIsY29sPSJibGFjayIsY2V4PTEuMikKdGV4dCg4LjUsNSwiRVNUSU1BVElPTiAmXG5JTkZFUkVOQ0UgKDMpIixjb2w9ImJsYWNrIixjZXg9MS4yKQp0ZXh0KDcuNSwuNSwiREFUQSBFWFBMT1JBVElPTiAmXG5ERVNDUklQVElWRSBTVEFUSVNUSUNTICgyKSIsY29sPSJibGFjayIsY2V4PTEuMikKYGBgCgoKLS0tCgojIFtIb21lXShodHRwczovL2d0cGIuZ2l0aHViLmlvL1BTTFMyMC8pIHstfQo=