Creative Commons License

1 Two-sample t-test: Plantgroei

Deze studie vergelijkt het droog gewicht van planten tussen een controle behandeling en twee verschillende behandelingen. We willen weten of het gemiddeld gewicht van planten bij behandeling twee (de data van behandeling één gaan we niet gebruiken) verschilt tegenover de controle groep.

1.1 Libraries laden

suppressPackageStartupMessages({
  library(tidyverse)
  library(ggplot2)
  library(gridExtra)
})

1.2 Data inlezen

data("PlantGrowth")

2 Data exploratie

2.1 Data structuur bekijken

#Bekijk hoe de dataset PlantGrowth eruit ziet
head(PlantGrowth)

2.2 Data filteren

We gaan eerst de data filteren zodat enkel de controle- (ctrl) en tweede behandelingsgroep (trt2) gebruikt worden.

#Filter de data zodat enkel data van de controle- (ctrl) en tweede behandelingsgroep (trt2) gebruikt worden.
PlantGrowth <- PlantGrowth %>% filter(group == "ctrl" | group == "trt2")

2.3 Boxplot van de data

We gaan de gewichten (weight) van de planten per groep (group) plotten door middel van een boxplot om te zien hoe onze distributie eruit ziet. Het lijkt dat de controlegroep een groter gewicht heeft, maar is dit verschil significant?

#Maak een boxplot voor elke groep (group) van het gewicht (weight) van de planten 
PlantGrowth %>% ggplot(aes(x=group,y=weight)) +
  geom_boxplot() +
  geom_jitter() +
  ggtitle("Gewicht van de planten voor de controle en tweede behandelingsgroep")

3 T-test

De two sample t-test kan gebruikt worden voor het gemiddelde gewicht te vergelijken tussen twee groepen. Deze heeft als test statistiek:

\[ T = \frac{\bar{Y}_1-\bar{Y}_2}{S_p\sqrt{\frac{1}{n_1}+\frac{1}{n_2}}} \]

3.1 Geef de nul- en alternatieve hypothese van de two-sample t-test:

Stel dat \(\mu_1\) het gemiddeld gewicht van plant met controle treatment voorstelt, en \(\mu_2\) het gemiddeld gewicht van een plant met treatment 2. De nul- en alternatieve hypothese voor een two-sample t-test kan men dan voorstellen als:

\(H_0\): \(\mu_1=\mu_2\)

\(H_A\): \(\mu_1 \neq \mu_2\)

De nulhypothese stelt dat er geen verschil is in gemiddeld gewicht tussen de behandelingen. De alternatieve hypothese stelt dat het gemiddelde gewicht verschilt tussen planten met de controle behandeling en planten met behandeling 2.

3.2 Geef de assumpties van de deze test en ga deze na:

Zoals beschreven in de cursus, veronderstelt t-test een locatie-shift model. Toch zijn er verschillende t-test, namelijk deze met een gepoolde variantie, de Welch t-test en daarnaast gepaarde t-test voor gepaarde data. Deze hebben verschillende assumpties:

Two-sample t-test: gepoolde variantie:

  • gelijke variantie in beide groepen
  • normaliteit van de data in elke groep
  • onafhankelijkheid van observaties

Welch t-test:

  • normaliteit van de data in elke groep
  • onafhankelijk van observaties

gepaarde t-test:

  • normaliteit van het verschil tussen de metingen van gepaarde observaties
  • onafhankelijkheid tussen de verschillende gepaarde observaties

Indien niet voldaan is aan de veronderstellingen, volgt de teststatistiek onder de nulhypothese geen t-distributie, en bijgevolg is er geen garantie dat de p-waarde en betrouwbaarheidsintervallen correct zijn. Hier werken we met een two-sample t-test met pooled variantie waardoor we moeten controleren of dat:

  • gelijke variantie in beide groepen (= homoscedasticiteit)
  • normaliteit van de data in elke groep

Onafhankelijkheid van observaties: we gaan er vanuit dat de onderzoekers hiermee rekening hebben gehouden in hun experimenteel design.

Voor het nagaan van gelijke varianties werken we met boxplots die daarnet gemaakt zijn. Deze assumptie lijkt alvast voldaan te zijn.

Het is echter niet altijd eenvoudig om te beoordelen of de varianties sterk van mekaar verschillen bij klein aantal samples (10 per treatment in dit geval). Om een beter idee te krijgen, kunnen we eens een aantal boxplots simuleren met dezelfde steekproefgrootte als in de dataset en in de veronderstelling dat de varianties gelijk zijn. Ook kan het onmogelijk zijn om deze assumptie te controleren bij zeer kleine sample size.

set.seed(52)
par(mfrow=c(3,3), mar=c(3,2,1,1))
st_dev <- PlantGrowth %>% group_by(group) %>% summarise(stdev = sd(weight))
means<- PlantGrowth %>% group_by(group) %>% summarise(m=mean(weight))
counts <- PlantGrowth %>% count(group)
sd_pooled = sqrt(((counts$n[1]-1) * st_dev$stdev[1]^2 + (counts$n[2]-1) * st_dev$stdev[2]^2) / (counts$n[1] + counts$n[2] - 2))

plots <- list()
for(i in 1:9){
  a <- rnorm(counts[1,2], mean=means$m[1], sd=sd_pooled)
  b <- rnorm(counts[2,2], mean=means$m[2], sd=sd_pooled)
  df <- data.frame("weight" = c(a,b), "group" = as.factor(c(rep(1,counts[1,2]),rep(2,counts[2,2]))))
  
  plots[[i]] <- ggplot(data=df, aes(x=group,y=weight)) + 
                geom_boxplot(outlier.shape = NA) + 
                geom_jitter(alpha=.2)
}
do.call('grid.arrange',c(plots,nrow=3, ncol = 3))

Aangezien het gebruik van een for-loop met het stapgewijs verlengen van een vector computationeel inefficiënt is in R, tonen we hier ook hoe het zou kunnen door middel van de lapply functie.

set.seed(52)
par(mfrow=c(3,3), mar=c(3,2,1,1))
plotList <- lapply(1:9, function(x,means,sd,nobs)
{
  data.frame(y = rnorm(
      sum(counts$n),
      mean=rep(means$m,times=nobs$n),
      sd=sd_pooled),
      group =  rep(nobs$group,times=counts$n)
  ) %>% 
    ggplot(aes(group,y)) +
    geom_boxplot(outlier.shape = NA) +
    geom_jitter(alpha=.2)
}, means=means,nobs=counts,sd=sd_pooled)
do.call("grid.arrange",c(plotList,nrow=3,ncol=3))

Dan moet nog de assumptie van normale distributie in elke groep nagegaan worden:

# Maak een QQplot van het gewicht van de planten voor elke treatment
PlantGrowth %>%
  ggplot(aes(sample = weight)) +
  geom_qq() +
  geom_qq_line() +
  facet_grid(.~group) +
  ylab("Relatieve abundantie")

De afwijkingen die we in onze qqplot zien lijken niet zeer uitzonderlijk te zijn. Daarom kunnen we stellen dat beide groepen een normale verdeling lijken te volgen en daarom ook aan deze assumptie voldaan is.

Ook hier kan het soms moeilijk zijn om met een beperkt aantal observaties te zien of normaliteit gevolgd worden. Hier zullen we ook op basis van een simulatiestudie bekijken hoe een steekproef van normaal verdeelde punten kan verschillen.

plotList <- lapply(1:9, function(x,means,sd,nobs)
{
  data.frame(y = rnorm(
      sum(counts$n),
      mean=rep(means$m,times=counts$n),
      sd=sd_pooled),
      group =  rep(counts$group,times=counts$n)
  ) %>% 
    ggplot(aes(sample=y)) +
    geom_qq() + # qq-punten
    geom_qq_line() + # qq-lijn
    theme_bw() + 
    facet_wrap(~group)
}, means=means,nobs=counts,sd=sd_pooled)
plotList
## [[1]]

## 
## [[2]]

## 
## [[3]]

## 
## [[4]]

## 
## [[5]]

## 
## [[6]]

## 
## [[7]]

## 
## [[8]]

## 
## [[9]]

We merken dat de natuurlijke variantie ongeveer even groot is zijn als de variatie die we in onze data zien. Dit betekent dat we verder kunnen tot het uitvoeren van de two-sample t-test.

3.3 Voer de two-sample t-test uit. Wat kan je hieruit concluderen op vlak van hypothesetest en betrouwbaarheidsinterval?

# Voer de two-sample t-test uit om de nulhypothese van gelijk gemiddeld gewicht tussen de controlebehandeling en behandeling 2 na te gaan.
model_t <- t.test(weight~group, data = PlantGrowth, var.equal=TRUE) # var.equal = FALSE is de default, wat de Welch t-test zou zijn
model_t
## 
##  Two Sample t-test
## 
## data:  weight by group
## t = -2.134, df = 18, p-value = 0.04685
## alternative hypothesis: true difference in means between group ctrl and group trt2 is not equal to 0
## 95 percent confidence interval:
##  -0.980338117 -0.007661883
## sample estimates:
## mean in group ctrl mean in group trt2 
##              5.032              5.526

We besluiten dat we de nulhypothese van gelijk gemiddeld gewicht kunnen verwerpen (p = 0.047) op het 5% significantieniveau en dat daarom het gemiddelde gewicht van de planten verschilt tussen de twee verschillende behandelingen. Daarnaast merken we op dat de effectgrootte negatief is, wat wil zeggen dat de planten gemiddeld minder wegen bij de controlebehandeling.

Het 95% betrouwbaarheidsinterval valt tussen -0.98 en -0.008. Dit wilt zeggen dat we met 95% zekerheid kunnen stellen dat het gemiddelde gewicht van een plant met de controle behandeling tussen 0.008 en 0.98 gram minder weegt dan de planten uit behandeling 2.

Onze conclusie is:

  • Er is een significant verschil in gemiddeld gewicht tussen de behandelingen (p = 0.047)

  • De controlebehandeling heeft met 95% zekerheid een gemiddeld gewicht tussen 0.008 en 0.98 gram lager dan behandeling 2.

4 Lineair model

4.2 Geef de nul- en alternatieve hypothese van deze test:

Indien we de data modelleren met een lineaire regressie dan kunnen we dezelfde hypothese (gelijkheid van gemiddelden) testen door middel van volgende hypothese:

\(H_0\): \(\beta_1 = 0\)

\(H_A\): \(\beta_1 \ne 0\)

Aangezien \(\beta_1\) het verschil tussen gemiddeld gewicht na behandeling 2 en de controlebehandeling is, betekent dit dat bij \(\beta_1 = 0\) er geen verschil in gemiddeld gewicht is.

4.3 Geef de assumpties van de deze test en ga deze na:

De assumpties van het lineair model zijn dezelfde als bij de pooled two-sample t-test. We hebben hier altijd gelijke variantie nodig, en het is hier dus niet mogelijk om met ongelijke varianties te werken.

We hebben reeds de assumpties van de pooled t-test hierboven getest.

4.4 Modelleer de data via een lineaire regressie en ga na of de nulhypothese van gelijk gemiddeld gewicht verworpen wordt. Wat kan je zeggen over de hypothesetest en de betrouwbaarheidsintervallen? Wat betekenen de verschillende parameters?

# Voer een lineare regressie toe van het gewicht in functie van de behandelingsgroep.
model_lm <- lm(weight ~ group, data = PlantGrowth)
summary <- summary(model_lm)
summary
## 
## Call:
## lm(formula = weight ~ group, data = PlantGrowth)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -0.862 -0.410 -0.006  0.280  1.078 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   5.0320     0.1637  30.742   <2e-16 ***
## grouptrt2     0.4940     0.2315   2.134   0.0469 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.5176 on 18 degrees of freedom
## Multiple R-squared:  0.2019, Adjusted R-squared:  0.1576 
## F-statistic: 4.554 on 1 and 18 DF,  p-value: 0.04685
# Geef de 95% confidence intervals van de geschatte parameters.
confint <- confint(model_lm)
confint
##                   2.5 %    97.5 %
## (Intercept) 4.688107020 5.3758930
## grouptrt2   0.007661883 0.9803381

De parameter grouptrt2 (\(\beta_1\)) heeft een p-waarde gelijk aan 0.047, waarmee we de nulhypothese van gelijk gemiddeld gewicht kunnen verwerpen. Het 95% betrouwbaarheidsinterval van parameter grouptrt2 gaat van 0 0.008 tot 0.98. Dit wil zeggen dat het gemiddeld gewicht van behandelingsgroup 2 met 95% zekerheid tussen 0.008 en 0.98 groter is dan in de controlebehandeling.

Anderzijds kunnen we met 95% zekerheid stellen dat het gemiddeld gewicht van de controlebehandeling tussen 4.688 en 5.376 ligt, wat we kunnen zien bij parameter Intercept. De p-waarde die hierbij staat (p < 2e-16), is de p-waarde voor de nulhypothese dat het intercept (\(\beta_0\)), wat overeen komt met het gemiddeld gewicht voor planten met de controlebehandeling, gelijk is aan 0 . Deze hypothese is onzinnig (anders zouden we geen plant hebben…) en heeft daarom geen interessante interpretatie.

Weer is onze conlusie:

  • Er is een significant verschil in gemiddeld gewicht tussen de behandelingen (p = 0.047)

  • De controlebehandeling heeft met 95% zekerheid een gemiddeld gewicht tussen 0.008 en 0.98 lager dan behandeling 2.

  • De controlebehandeling heeft met 95% zekerheid een gemiddeld gewicht tussen 4.688 en 5.376.

5 Conclusie:

We kunnen concluderen dat zowel de two-sample t-test analyse als de lineaire regressie dezelfde resultaten geven.

  • Er is een significant verschil in gemiddeld gewicht tussen de behandelingen (p = 0.047)

  • De controlebehandeling heeft met 95% zekerheid een gemiddeld gewicht tussen 0.008 en 0.98 lager dan behandeling 2.

  • De controlebehandeling heeft met 95% zekerheid een gemiddeld gewicht tussen 4.688 en 5.376.

LS0tCnRpdGxlOiAiUHJhY3RpY3VtIDE6IE9lZmVuaW5nIFR3by1zYW1wbGUgdC10ZXN0IgphdXRob3I6ICJBbGV4YW5kcmUgU2VnZXJzICYgTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCm91dHB1dDoKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgICAgdGhlbWU6IGNvc21vCiAgICAgIHRvYzogdHJ1ZQogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHBkZl9kb2N1bWVudDoKICAgICAgdG9jOiB0cnVlCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgICBsYXRleF9lbmdpbmU6IHhlbGF0ZXgKbGlua2NvbG9yOiBibHVlCnVybGNvbG9yOiBibHVlCmNpdGVjb2xvcjogYmx1ZQoKLS0tCgo8YSByZWw9ImxpY2Vuc2UiIGhyZWY9Imh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1zYS80LjAiPjxpbWcgYWx0PSJDcmVhdGl2ZSBDb21tb25zIExpY2Vuc2UiIHN0eWxlPSJib3JkZXItd2lkdGg6MCIgc3JjPSJodHRwczovL2kuY3JlYXRpdmVjb21tb25zLm9yZy9sL2J5LW5jLXNhLzQuMC84OHgzMS5wbmciIC8+PC9hPgoKIyBUd28tc2FtcGxlIHQtdGVzdDogUGxhbnRncm9laQpEZXplIHN0dWRpZSB2ZXJnZWxpamt0IGhldCBkcm9vZyBnZXdpY2h0IHZhbiBwbGFudGVuIHR1c3NlbiBlZW4gY29udHJvbGUgYmVoYW5kZWxpbmcgZW4gdHdlZSB2ZXJzY2hpbGxlbmRlIGJlaGFuZGVsaW5nZW4uIFdlIHdpbGxlbiB3ZXRlbiBvZiBoZXQgZ2VtaWRkZWxkIGdld2ljaHQgdmFuIHBsYW50ZW4gYmlqIGJlaGFuZGVsaW5nIHR3ZWUgKGRlIGRhdGEgdmFuIGJlaGFuZGVsaW5nIMOpw6luIGdhYW4gd2UgbmlldCBnZWJydWlrZW4pIHZlcnNjaGlsdCB0ZWdlbm92ZXIgZGUgY29udHJvbGUgZ3JvZXAuCgoKIyMgTGlicmFyaWVzIGxhZGVuCmBgYHtyfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkodGlkeXZlcnNlKQogIGxpYnJhcnkoZ2dwbG90MikKICBsaWJyYXJ5KGdyaWRFeHRyYSkKfSkKYGBgCgoKIyMgRGF0YSBpbmxlemVuCmBgYHtyfQpkYXRhKCJQbGFudEdyb3d0aCIpCmBgYAoKCiMgRGF0YSBleHBsb3JhdGllCgojIyBEYXRhIHN0cnVjdHV1ciBiZWtpamtlbgoKYGBge3J9CiNCZWtpamsgaG9lIGRlIGRhdGFzZXQgUGxhbnRHcm93dGggZXJ1aXQgemlldApoZWFkKFBsYW50R3Jvd3RoKQpgYGAKCiMjIERhdGEgZmlsdGVyZW4KV2UgZ2FhbiBlZXJzdCBkZSBkYXRhIGZpbHRlcmVuIHpvZGF0IGVua2VsIGRlIGNvbnRyb2xlLSAoY3RybCkgZW4gdHdlZWRlIGJlaGFuZGVsaW5nc2dyb2VwICh0cnQyKSBnZWJydWlrdCB3b3JkZW4uCgpgYGB7cn0KI0ZpbHRlciBkZSBkYXRhIHpvZGF0IGVua2VsIGRhdGEgdmFuIGRlIGNvbnRyb2xlLSAoY3RybCkgZW4gdHdlZWRlIGJlaGFuZGVsaW5nc2dyb2VwICh0cnQyKSBnZWJydWlrdCB3b3JkZW4uClBsYW50R3Jvd3RoIDwtIFBsYW50R3Jvd3RoICU+JSBmaWx0ZXIoZ3JvdXAgPT0gImN0cmwiIHwgZ3JvdXAgPT0gInRydDIiKQpgYGAKCiMjIEJveHBsb3QgdmFuIGRlIGRhdGEKV2UgZ2FhbiBkZSBnZXdpY2h0ZW4gKHdlaWdodCkgdmFuIGRlIHBsYW50ZW4gcGVyIGdyb2VwIChncm91cCkgcGxvdHRlbiBkb29yIG1pZGRlbCB2YW4gZWVuIGJveHBsb3Qgb20gdGUgemllbiBob2Ugb256ZSBkaXN0cmlidXRpZSBlcnVpdCB6aWV0LiBIZXQgbGlqa3QgZGF0IGRlIGNvbnRyb2xlZ3JvZXAgZWVuIGdyb3RlciBnZXdpY2h0IGhlZWZ0LCBtYWFyIGlzIGRpdCB2ZXJzY2hpbCBzaWduaWZpY2FudD8KCmBgYHtyfQojTWFhayBlZW4gYm94cGxvdCB2b29yIGVsa2UgZ3JvZXAgKGdyb3VwKSB2YW4gaGV0IGdld2ljaHQgKHdlaWdodCkgdmFuIGRlIHBsYW50ZW4gClBsYW50R3Jvd3RoICU+JSBnZ3Bsb3QoYWVzKHg9Z3JvdXAseT13ZWlnaHQpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKCkgKwogIGdndGl0bGUoIkdld2ljaHQgdmFuIGRlIHBsYW50ZW4gdm9vciBkZSBjb250cm9sZSBlbiB0d2VlZGUgYmVoYW5kZWxpbmdzZ3JvZXAiKQpgYGAKCiMgVC10ZXN0CgpEZSB0d28gc2FtcGxlIHQtdGVzdCBrYW4gZ2VicnVpa3Qgd29yZGVuIHZvb3IgaGV0IGdlbWlkZGVsZGUgZ2V3aWNodCB0ZSB2ZXJnZWxpamtlbiB0dXNzZW4gdHdlZSBncm9lcGVuLiBEZXplIGhlZWZ0IGFscyB0ZXN0IHN0YXRpc3RpZWs6CgpcWyBUID0gXGZyYWN7XGJhcntZfV8xLVxiYXJ7WX1fMn17U19wXHNxcnR7XGZyYWN7MX17bl8xfStcZnJhY3sxfXtuXzJ9fX0gXF0KCiMjIEdlZWYgZGUgbnVsLSBlbiBhbHRlcm5hdGlldmUgaHlwb3RoZXNlIHZhbiBkZSB0d28tc2FtcGxlIHQtdGVzdDoKClN0ZWwgZGF0ICRcbXVfMSQgaGV0IGdlbWlkZGVsZCBnZXdpY2h0IHZhbiBwbGFudCBtZXQgY29udHJvbGUgdHJlYXRtZW50IHZvb3JzdGVsdCwgZW4gJFxtdV8yJCBoZXQgZ2VtaWRkZWxkIGdld2ljaHQgdmFuIGVlbiBwbGFudCBtZXQgdHJlYXRtZW50IDIuCkRlIG51bC0gZW4gYWx0ZXJuYXRpZXZlIGh5cG90aGVzZSB2b29yIGVlbiB0d28tc2FtcGxlIHQtdGVzdCBrYW4gbWVuIGRhbiB2b29yc3RlbGxlbiBhbHM6CgokSF8wJDogJFxtdV8xPVxtdV8yJAoKJEhfQSQ6ICAkXG11XzEgXG5lcSBcbXVfMiQKCkRlIG51bGh5cG90aGVzZSBzdGVsdCBkYXQgZXIgZ2VlbiB2ZXJzY2hpbCBpcyBpbiBnZW1pZGRlbGQgZ2V3aWNodCB0dXNzZW4gZGUgYmVoYW5kZWxpbmdlbi4gRGUgYWx0ZXJuYXRpZXZlIGh5cG90aGVzZSBzdGVsdCBkYXQgaGV0IGdlbWlkZGVsZGUgZ2V3aWNodCB2ZXJzY2hpbHQgdHVzc2VuIHBsYW50ZW4gbWV0IGRlIGNvbnRyb2xlIGJlaGFuZGVsaW5nIGVuIHBsYW50ZW4gbWV0IGJlaGFuZGVsaW5nIDIuIAoKIyMgR2VlZiBkZSBhc3N1bXB0aWVzIHZhbiBkZSBkZXplIHRlc3QgZW4gZ2EgZGV6ZSBuYToKClpvYWxzIGJlc2NocmV2ZW4gaW4gZGUgY3Vyc3VzLCB2ZXJvbmRlcnN0ZWx0IHQtdGVzdCBlZW4gbG9jYXRpZS1zaGlmdCBtb2RlbC4gVG9jaCB6aWpuIGVyIHZlcnNjaGlsbGVuZGUgdC10ZXN0LCBuYW1lbGlqayBkZXplIG1ldCBlZW4gZ2Vwb29sZGUgdmFyaWFudGllLCBkZSBXZWxjaCB0LXRlc3QgZW4gZGFhcm5hYXN0IGdlcGFhcmRlIHQtdGVzdCB2b29yIGdlcGFhcmRlIGRhdGEuIERlemUgaGViYmVuIHZlcnNjaGlsbGVuZGUgYXNzdW1wdGllczogCgpUd28tc2FtcGxlIHQtdGVzdDogZ2Vwb29sZGUgdmFyaWFudGllOgoKLSBnZWxpamtlIHZhcmlhbnRpZSBpbiBiZWlkZSBncm9lcGVuCi0gbm9ybWFsaXRlaXQgdmFuIGRlIGRhdGEgaW4gZWxrZSBncm9lcAotIG9uYWZoYW5rZWxpamtoZWlkIHZhbiBvYnNlcnZhdGllcwoKV2VsY2ggdC10ZXN0OgoKLSBub3JtYWxpdGVpdCB2YW4gZGUgZGF0YSBpbiBlbGtlIGdyb2VwCi0gb25hZmhhbmtlbGlqayB2YW4gb2JzZXJ2YXRpZXMKCmdlcGFhcmRlIHQtdGVzdDoKCi0gbm9ybWFsaXRlaXQgdmFuIGhldCB2ZXJzY2hpbCB0dXNzZW4gZGUgbWV0aW5nZW4gdmFuIGdlcGFhcmRlIG9ic2VydmF0aWVzCi0gb25hZmhhbmtlbGlqa2hlaWQgdHVzc2VuIGRlIHZlcnNjaGlsbGVuZGUgZ2VwYWFyZGUgb2JzZXJ2YXRpZXMKCiAgCkluZGllbiBuaWV0IHZvbGRhYW4gaXMgYWFuIGRlIHZlcm9uZGVyc3RlbGxpbmdlbiwgdm9sZ3QgZGUgdGVzdHN0YXRpc3RpZWsgb25kZXIgZGUgbnVsaHlwb3RoZXNlIGdlZW4gdC1kaXN0cmlidXRpZSwgZW4gYmlqZ2V2b2xnIGlzIGVyIGdlZW4gZ2FyYW50aWUgZGF0IGRlIHAtd2FhcmRlIGVuIGJldHJvdXdiYWFyaGVpZHNpbnRlcnZhbGxlbiBjb3JyZWN0IHppam4uIEhpZXIgd2Vya2VuIHdlIG1ldCBlZW4gdHdvLXNhbXBsZSB0LXRlc3QgbWV0IHBvb2xlZCB2YXJpYW50aWUgd2FhcmRvb3Igd2UgbW9ldGVuIGNvbnRyb2xlcmVuIG9mIGRhdDoKCi0gZ2VsaWprZSB2YXJpYW50aWUgaW4gYmVpZGUgZ3JvZXBlbiAoPSBob21vc2NlZGFzdGljaXRlaXQpCi0gbm9ybWFsaXRlaXQgdmFuIGRlIGRhdGEgaW4gZWxrZSBncm9lcAoKT25hZmhhbmtlbGlqa2hlaWQgdmFuIG9ic2VydmF0aWVzOiB3ZSBnYWFuIGVyIHZhbnVpdCBkYXQgZGUgb25kZXJ6b2VrZXJzIGhpZXJtZWUgcmVrZW5pbmcgaGViYmVuIGdlaG91ZGVuIGluIGh1biBleHBlcmltZW50ZWVsIGRlc2lnbi4KClZvb3IgaGV0IG5hZ2FhbiB2YW4gZ2VsaWprZSB2YXJpYW50aWVzIHdlcmtlbiB3ZSBtZXQgYm94cGxvdHMgZGllIGRhYXJuZXQgZ2VtYWFrdCB6aWpuLiBEZXplIGFzc3VtcHRpZSBsaWprdCBhbHZhc3Qgdm9sZGFhbiB0ZSB6aWpuLgoKSGV0IGlzIGVjaHRlciBuaWV0IGFsdGlqZCBlZW52b3VkaWcgb20gdGUgYmVvb3JkZWxlbiBvZiBkZSB2YXJpYW50aWVzIHN0ZXJrIHZhbiBtZWthYXIgdmVyc2NoaWxsZW4gYmlqIGtsZWluIGFhbnRhbCBzYW1wbGVzICgxMCBwZXIgdHJlYXRtZW50IGluIGRpdCBnZXZhbCkuIE9tIGVlbiBiZXRlciBpZGVlIHRlIGtyaWpnZW4sIGt1bm5lbiB3ZSBlZW5zIGVlbiBhYW50YWwgYm94cGxvdHMgc2ltdWxlcmVuIG1ldCBkZXplbGZkZSBzdGVla3Byb2VmZ3Jvb3R0ZSBhbHMgaW4gZGUgZGF0YXNldCBlbiBpbiBkZSB2ZXJvbmRlcnN0ZWxsaW5nIGRhdCBkZSB2YXJpYW50aWVzIGdlbGlqayB6aWpuLiBPb2sga2FuIGhldCBvbm1vZ2VsaWprIHppam4gb20gZGV6ZSBhc3N1bXB0aWUgdGUgY29udHJvbGVyZW4gYmlqIHplZXIga2xlaW5lIHNhbXBsZSBzaXplLgoKCmBgYHtyfQpzZXQuc2VlZCg1MikKcGFyKG1mcm93PWMoMywzKSwgbWFyPWMoMywyLDEsMSkpCnN0X2RldiA8LSBQbGFudEdyb3d0aCAlPiUgZ3JvdXBfYnkoZ3JvdXApICU+JSBzdW1tYXJpc2Uoc3RkZXYgPSBzZCh3ZWlnaHQpKQptZWFuczwtIFBsYW50R3Jvd3RoICU+JSBncm91cF9ieShncm91cCkgJT4lIHN1bW1hcmlzZShtPW1lYW4od2VpZ2h0KSkKY291bnRzIDwtIFBsYW50R3Jvd3RoICU+JSBjb3VudChncm91cCkKc2RfcG9vbGVkID0gc3FydCgoKGNvdW50cyRuWzFdLTEpICogc3RfZGV2JHN0ZGV2WzFdXjIgKyAoY291bnRzJG5bMl0tMSkgKiBzdF9kZXYkc3RkZXZbMl1eMikgLyAoY291bnRzJG5bMV0gKyBjb3VudHMkblsyXSAtIDIpKQoKcGxvdHMgPC0gbGlzdCgpCmZvcihpIGluIDE6OSl7CiAgYSA8LSBybm9ybShjb3VudHNbMSwyXSwgbWVhbj1tZWFucyRtWzFdLCBzZD1zZF9wb29sZWQpCiAgYiA8LSBybm9ybShjb3VudHNbMiwyXSwgbWVhbj1tZWFucyRtWzJdLCBzZD1zZF9wb29sZWQpCiAgZGYgPC0gZGF0YS5mcmFtZSgid2VpZ2h0IiA9IGMoYSxiKSwgImdyb3VwIiA9IGFzLmZhY3RvcihjKHJlcCgxLGNvdW50c1sxLDJdKSxyZXAoMixjb3VudHNbMiwyXSkpKSkKICAKICBwbG90c1tbaV1dIDwtIGdncGxvdChkYXRhPWRmLCBhZXMoeD1ncm91cCx5PXdlaWdodCkpICsgCiAgICAgICAgICAgICAgICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIAogICAgICAgICAgICAgICAgZ2VvbV9qaXR0ZXIoYWxwaGE9LjIpCn0KZG8uY2FsbCgnZ3JpZC5hcnJhbmdlJyxjKHBsb3RzLG5yb3c9MywgbmNvbCA9IDMpKQpgYGAKCkFhbmdlemllbiBoZXQgZ2VicnVpayB2YW4gZWVuIGZvci1sb29wIG1ldCBoZXQgc3RhcGdld2lqcyB2ZXJsZW5nZW4gdmFuIGVlbiB2ZWN0b3IgY29tcHV0YXRpb25lZWwgaW5lZmZpY2nDq250IGlzIGluIFIsIHRvbmVuIHdlIGhpZXIgb29rIGhvZSBoZXQgem91IGt1bm5lbiBkb29yIG1pZGRlbCB2YW4gZGUgbGFwcGx5IGZ1bmN0aWUuCgpgYGB7cn0Kc2V0LnNlZWQoNTIpCnBhcihtZnJvdz1jKDMsMyksIG1hcj1jKDMsMiwxLDEpKQpwbG90TGlzdCA8LSBsYXBwbHkoMTo5LCBmdW5jdGlvbih4LG1lYW5zLHNkLG5vYnMpCnsKICBkYXRhLmZyYW1lKHkgPSBybm9ybSgKICAgICAgc3VtKGNvdW50cyRuKSwKICAgICAgbWVhbj1yZXAobWVhbnMkbSx0aW1lcz1ub2JzJG4pLAogICAgICBzZD1zZF9wb29sZWQpLAogICAgICBncm91cCA9ICByZXAobm9icyRncm91cCx0aW1lcz1jb3VudHMkbikKICApICU+JSAKICAgIGdncGxvdChhZXMoZ3JvdXAseSkpICsKICAgIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIGdlb21faml0dGVyKGFscGhhPS4yKQp9LCBtZWFucz1tZWFucyxub2JzPWNvdW50cyxzZD1zZF9wb29sZWQpCgpgYGAKYGBge3J9CmRvLmNhbGwoImdyaWQuYXJyYW5nZSIsYyhwbG90TGlzdCxucm93PTMsbmNvbD0zKSkKYGBgCgpEYW4gbW9ldCBub2cgZGUgYXNzdW1wdGllIHZhbiBub3JtYWxlIGRpc3RyaWJ1dGllIGluIGVsa2UgZ3JvZXAgbmFnZWdhYW4gd29yZGVuOgoKYGBge3J9CiMgTWFhayBlZW4gUVFwbG90IHZhbiBoZXQgZ2V3aWNodCB2YW4gZGUgcGxhbnRlbiB2b29yIGVsa2UgdHJlYXRtZW50ClBsYW50R3Jvd3RoICU+JQogIGdncGxvdChhZXMoc2FtcGxlID0gd2VpZ2h0KSkgKwogIGdlb21fcXEoKSArCiAgZ2VvbV9xcV9saW5lKCkgKwogIGZhY2V0X2dyaWQoLn5ncm91cCkgKwogIHlsYWIoIlJlbGF0aWV2ZSBhYnVuZGFudGllIikKYGBgCgpEZSBhZndpamtpbmdlbiBkaWUgd2UgaW4gb256ZSBxcXBsb3QgemllbiBsaWprZW4gbmlldCB6ZWVyIHVpdHpvbmRlcmxpamsgdGUgemlqbi4gRGFhcm9tIGt1bm5lbiB3ZSBzdGVsbGVuIGRhdCBiZWlkZSBncm9lcGVuIGVlbiBub3JtYWxlIHZlcmRlbGluZyBsaWprZW4gdGUgdm9sZ2VuIGVuIGRhYXJvbSBvb2sgYWFuIGRlemUgYXNzdW1wdGllIHZvbGRhYW4gaXMuCgpPb2sgaGllciBrYW4gaGV0IHNvbXMgbW9laWxpamsgemlqbiBvbSBtZXQgZWVuIGJlcGVya3QgYWFudGFsIG9ic2VydmF0aWVzIHRlIHppZW4gb2Ygbm9ybWFsaXRlaXQgZ2V2b2xnZCB3b3JkZW4uIEhpZXIgenVsbGVuIHdlIG9vayBvcCBiYXNpcyB2YW4gZWVuIHNpbXVsYXRpZXN0dWRpZSBiZWtpamtlbiBob2UgZWVuIHN0ZWVrcHJvZWYgdmFuIG5vcm1hYWwgdmVyZGVlbGRlIHB1bnRlbiBrYW4gdmVyc2NoaWxsZW4uCgpgYGB7cn0KcGxvdExpc3QgPC0gbGFwcGx5KDE6OSwgZnVuY3Rpb24oeCxtZWFucyxzZCxub2JzKQp7CiAgZGF0YS5mcmFtZSh5ID0gcm5vcm0oCiAgICAgIHN1bShjb3VudHMkbiksCiAgICAgIG1lYW49cmVwKG1lYW5zJG0sdGltZXM9Y291bnRzJG4pLAogICAgICBzZD1zZF9wb29sZWQpLAogICAgICBncm91cCA9ICByZXAoY291bnRzJGdyb3VwLHRpbWVzPWNvdW50cyRuKQogICkgJT4lIAogICAgZ2dwbG90KGFlcyhzYW1wbGU9eSkpICsKICAgIGdlb21fcXEoKSArICMgcXEtcHVudGVuCiAgICBnZW9tX3FxX2xpbmUoKSArICMgcXEtbGlqbgogICAgdGhlbWVfYncoKSArIAogICAgZmFjZXRfd3JhcCh+Z3JvdXApCn0sIG1lYW5zPW1lYW5zLG5vYnM9Y291bnRzLHNkPXNkX3Bvb2xlZCkKcGxvdExpc3QKYGBgCgpXZSBtZXJrZW4gZGF0IGRlIG5hdHV1cmxpamtlIHZhcmlhbnRpZSBvbmdldmVlciBldmVuIGdyb290IGlzIHppam4gYWxzIGRlIHZhcmlhdGllIGRpZSB3ZSBpbiBvbnplIGRhdGEgemllbi4gRGl0IGJldGVrZW50IGRhdCB3ZSB2ZXJkZXIga3VubmVuIHRvdCBoZXQgdWl0dm9lcmVuIHZhbiBkZSB0d28tc2FtcGxlIHQtdGVzdC4KCiMjIFZvZXIgZGUgdHdvLXNhbXBsZSB0LXRlc3QgdWl0LiBXYXQga2FuIGplIGhpZXJ1aXQgY29uY2x1ZGVyZW4gb3AgdmxhayB2YW4gaHlwb3RoZXNldGVzdCBlbiBiZXRyb3V3YmFhcmhlaWRzaW50ZXJ2YWw/CmBgYHtyfQojIFZvZXIgZGUgdHdvLXNhbXBsZSB0LXRlc3QgdWl0IG9tIGRlIG51bGh5cG90aGVzZSB2YW4gZ2VsaWprIGdlbWlkZGVsZCBnZXdpY2h0IHR1c3NlbiBkZSBjb250cm9sZWJlaGFuZGVsaW5nIGVuIGJlaGFuZGVsaW5nIDIgbmEgdGUgZ2Fhbi4KbW9kZWxfdCA8LSB0LnRlc3Qod2VpZ2h0fmdyb3VwLCBkYXRhID0gUGxhbnRHcm93dGgsIHZhci5lcXVhbD1UUlVFKSAjIHZhci5lcXVhbCA9IEZBTFNFIGlzIGRlIGRlZmF1bHQsIHdhdCBkZSBXZWxjaCB0LXRlc3Qgem91IHppam4KbW9kZWxfdAoKYGBgCgpXZSBiZXNsdWl0ZW4gZGF0IHdlIGRlIG51bGh5cG90aGVzZSB2YW4gZ2VsaWprIGdlbWlkZGVsZCBnZXdpY2h0IGt1bm5lbiB2ZXJ3ZXJwZW4gKHAgPSBgciByb3VuZChtb2RlbF90JHAudmFsdWUsMylgKSBvcCBoZXQgNSUgc2lnbmlmaWNhbnRpZW5pdmVhdSBlbiBkYXQgZGFhcm9tIGhldCBnZW1pZGRlbGRlIGdld2ljaHQgdmFuIGRlIHBsYW50ZW4gdmVyc2NoaWx0IHR1c3NlbiBkZSB0d2VlIHZlcnNjaGlsbGVuZGUgYmVoYW5kZWxpbmdlbi4gRGFhcm5hYXN0IG1lcmtlbiB3ZSBvcCBkYXQgZGUgZWZmZWN0Z3Jvb3R0ZSBuZWdhdGllZiBpcywgd2F0IHdpbCB6ZWdnZW4gZGF0IGRlIHBsYW50ZW4gZ2VtaWRkZWxkIG1pbmRlciB3ZWdlbiBiaWogZGUgY29udHJvbGViZWhhbmRlbGluZy4KCgpIZXQgOTUlIGJldHJvdXdiYWFyaGVpZHNpbnRlcnZhbCB2YWx0IHR1c3NlbiBgciByb3VuZChtb2RlbF90JGNvbmYuaW50WzFdLDMpYCBlbiBgciByb3VuZChtb2RlbF90JGNvbmYuaW50WzJdLDMpYC4gRGl0IHdpbHQgemVnZ2VuIGRhdCB3ZSBtZXQgOTUlIHpla2VyaGVpZCBrdW5uZW4gc3RlbGxlbiBkYXQgaGV0IGdlbWlkZGVsZGUgZ2V3aWNodCB2YW4gZWVuIHBsYW50IG1ldCBkZSBjb250cm9sZSBiZWhhbmRlbGluZyB0dXNzZW4gYHIgcm91bmQoLW1vZGVsX3QkY29uZi5pbnRbMl0sMylgIGVuIGByIHJvdW5kKC1tb2RlbF90JGNvbmYuaW50WzFdLDMpYCBncmFtIG1pbmRlciB3ZWVndCBkYW4gZGUgcGxhbnRlbiB1aXQgYmVoYW5kZWxpbmcgMi4KCk9uemUgY29uY2x1c2llIGlzOgoKICAtIEVyIGlzIGVlbiBzaWduaWZpY2FudCB2ZXJzY2hpbCBpbiBnZW1pZGRlbGQgZ2V3aWNodCB0dXNzZW4gZGUgYmVoYW5kZWxpbmdlbiAocCA9IGByIHJvdW5kKG1vZGVsX3QkcC52YWx1ZSwzKWApCiAgCiAgLSBEZSBjb250cm9sZWJlaGFuZGVsaW5nIGhlZWZ0IG1ldCA5NSUgemVrZXJoZWlkIGVlbiBnZW1pZGRlbGQgZ2V3aWNodCB0dXNzZW4gYHIgcm91bmQoLW1vZGVsX3QkY29uZi5pbnRbMl0sMylgIGVuIGByIHJvdW5kKC1tb2RlbF90JGNvbmYuaW50WzFdLDMpYCBncmFtIGxhZ2VyIGRhbiBiZWhhbmRlbGluZyAyLgoKCiMgTGluZWFpciBtb2RlbAoKIyMgV2F0IGlzIGRlIGxpbmsgdHVzc2VuIGRlIHR3by1zYW1wbGUgdC10ZXN0IGVuIGhldCBsaW5lYWlyIG1vZGVsPwoKV2UgaGViYmVuIHJlZWRzIGdlemllbiBkYXQgZGUgdHdvLXNhbXBsZSB0LXRlc3QgZWVuIHNwZWNpZmlla2UgdmVyc2llIGlzIHZhbiBlZW4gbGluZWFpciBtb2RlbCwgbmFtZWxpamsgdmFuIGVlbiBsaW5lYWlyIG1vZGVsIHdhYXJiaWogZGUgY292YXJpYWF0IGVlbiBkdW1teSB2YXJpYWJlbGUgJFgkIGRpZSBkZSB3YWFyZGUgMCBlbiAxIGthbiBhYW5uZW1lbi4KXFsgRVtZX2ldID0gXGJldGFfMCArIFxiZXRhXzEgWF9pIFxdCkJpanZvb3JiZWVsZCwgaW5kaWVuICRZX2kkIGRlIGxlbmd0ZSB2YW4gcGVyc29vbiAkaSQgdm9vcnN0ZWx0IGVuICRYX2kkIGhldCBnZXNsYWNodCB2YW4gZGllIHBlcnNvb24gd2FhcmJpaiAkWF9pPTAkIGluZGllbiBwZXJzb29uICRpJCBlZW4gdnJvdXcgaXMsIGVuICRYX2k9MSQgaW5kaWVuIG5pZXQuIEluIGRhdCBnZXZhbCwgc3RlbHQgJFxiZXRhXzAkIGRlIGdlbWlkZGVsZGUgbGVuZ3RlIHZvb3IgdnJvdXdlbiB2b29yLCBlbiAkXGJldGFfMSQgc3RhYXQgdm9vciBoZXQgdmVyc2NoaWwgaW4gZ2VtaWRkZWxkZSBsZW5ndGUgdHVzc2VuIHZyb3V3ZW4gZW4gbWFubmVuLiBEZSBnZW1pZGRlbGRlIGxlbmd0ZSB2b29yIGVlbiBtYW4ga2FuIG1lbiBkYW4gYmVrb21lbiBkb29yICRFW1lfe21hbGV9XSA9IFxiZXRhXzAgKyBcYmV0YV8xJC4gTWVuIGthbiBkaXQgb29rIHNjaHJpanZlbiBhbHM6ClxbIEVbWSB8IGZlbWFsZV0gPSBFW1kgfCBYID0gMF0gPSBcYmV0YV8wXF0KXFsgRVtZIHwgbWFsZV0gPSBFW1kgfCBYID0gMV0gPSBcYmV0YV8wICsgXGJldGFfMVxdCgoKIyMgR2VlZiBkZSBudWwtIGVuIGFsdGVybmF0aWV2ZSBoeXBvdGhlc2UgdmFuIGRlemUgdGVzdDoKCkluZGllbiB3ZSBkZSBkYXRhIG1vZGVsbGVyZW4gbWV0IGVlbiBsaW5lYWlyZSByZWdyZXNzaWUgZGFuIGt1bm5lbiB3ZSBkZXplbGZkZSBoeXBvdGhlc2UgKGdlbGlqa2hlaWQgdmFuIGdlbWlkZGVsZGVuKSB0ZXN0ZW4gZG9vciBtaWRkZWwgdmFuIHZvbGdlbmRlIGh5cG90aGVzZToKCiRIXzAkOiAkXGJldGFfMSA9IDAkCiAKJEhfQSQ6ICRcYmV0YV8xIFxuZSAwJCAKCkFhbmdlemllbiAkXGJldGFfMSQgaGV0IHZlcnNjaGlsIHR1c3NlbiBnZW1pZGRlbGQgZ2V3aWNodCBuYSBiZWhhbmRlbGluZyAyIGVuIGRlIGNvbnRyb2xlYmVoYW5kZWxpbmcgaXMsIGJldGVrZW50IGRpdCBkYXQgYmlqICRcYmV0YV8xID0gMCQgZXIgZ2VlbiB2ZXJzY2hpbCBpbiBnZW1pZGRlbGQgZ2V3aWNodCBpcy4KCiMjIEdlZWYgZGUgYXNzdW1wdGllcyB2YW4gZGUgZGV6ZSB0ZXN0IGVuIGdhIGRlemUgbmE6CgpEZSBhc3N1bXB0aWVzIHZhbiBoZXQgbGluZWFpciBtb2RlbCB6aWpuIGRlemVsZmRlIGFscyBiaWogZGUgcG9vbGVkIHR3by1zYW1wbGUgdC10ZXN0LiBXZSBoZWJiZW4gaGllciBhbHRpamQgZ2VsaWprZSB2YXJpYW50aWUgbm9kaWcsIGVuIGhldCBpcyBoaWVyIGR1cyBuaWV0IG1vZ2VsaWprIG9tIG1ldCBvbmdlbGlqa2UgdmFyaWFudGllcyB0ZSB3ZXJrZW4uIAoKV2UgaGViYmVuIHJlZWRzIGRlIGFzc3VtcHRpZXMgdmFuIGRlIHBvb2xlZCB0LXRlc3QgaGllcmJvdmVuIGdldGVzdC4KCiMjIE1vZGVsbGVlciBkZSBkYXRhIHZpYSBlZW4gbGluZWFpcmUgcmVncmVzc2llIGVuIGdhIG5hIG9mIGRlIG51bGh5cG90aGVzZSB2YW4gZ2VsaWprIGdlbWlkZGVsZCBnZXdpY2h0IHZlcndvcnBlbiB3b3JkdC4gV2F0IGthbiBqZSB6ZWdnZW4gb3ZlciBkZSBoeXBvdGhlc2V0ZXN0IGVuIGRlIGJldHJvdXdiYWFyaGVpZHNpbnRlcnZhbGxlbj8gV2F0IGJldGVrZW5lbiBkZSB2ZXJzY2hpbGxlbmRlIHBhcmFtZXRlcnM/CgpgYGB7cn0KIyBWb2VyIGVlbiBsaW5lYXJlIHJlZ3Jlc3NpZSB0b2UgdmFuIGhldCBnZXdpY2h0IGluIGZ1bmN0aWUgdmFuIGRlIGJlaGFuZGVsaW5nc2dyb2VwLgptb2RlbF9sbSA8LSBsbSh3ZWlnaHQgfiBncm91cCwgZGF0YSA9IFBsYW50R3Jvd3RoKQpzdW1tYXJ5IDwtIHN1bW1hcnkobW9kZWxfbG0pCnN1bW1hcnkKYGBgCmBgYHtyfQojIEdlZWYgZGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHZhbiBkZSBnZXNjaGF0dGUgcGFyYW1ldGVycy4KY29uZmludCA8LSBjb25maW50KG1vZGVsX2xtKQpjb25maW50CmBgYAoKRGUgcGFyYW1ldGVyIGdyb3VwdHJ0MiAoJFxiZXRhXzEkKSBoZWVmdCBlZW4gcC13YWFyZGUgZ2VsaWprIGFhbiBgciByb3VuZChzdW1tYXJ5JGNvZWZmaWNpZW50c1s4XSwzKWAsIHdhYXJtZWUgd2UgZGUgbnVsaHlwb3RoZXNlIHZhbiBnZWxpamsgZ2VtaWRkZWxkIGdld2ljaHQga3VubmVuIHZlcndlcnBlbi4gSGV0IDk1JSBiZXRyb3V3YmFhcmhlaWRzaW50ZXJ2YWwgdmFuIHBhcmFtZXRlciBncm91cHRydDIgZ2FhdCB2YW4gMCBgciByb3VuZChjb25maW50WzJdLDMpYCB0b3QgYHIgcm91bmQoY29uZmludFs0XSwzKWAuIERpdCB3aWwgemVnZ2VuIGRhdCBoZXQgZ2VtaWRkZWxkIGdld2ljaHQgdmFuIGJlaGFuZGVsaW5nc2dyb3VwIDIgbWV0IDk1JSB6ZWtlcmhlaWQgdHVzc2VuIGByIHJvdW5kKGNvbmZpbnRbMl0sMylgIGVuIGByIHJvdW5kKGNvbmZpbnRbNF0sMylgIGdyb3RlciBpcyBkYW4gaW4gZGUgY29udHJvbGViZWhhbmRlbGluZy4gCgpBbmRlcnppamRzIGt1bm5lbiB3ZSBtZXQgOTUlIHpla2VyaGVpZCBzdGVsbGVuIGRhdCBoZXQgZ2VtaWRkZWxkIGdld2ljaHQgdmFuIGRlIGNvbnRyb2xlYmVoYW5kZWxpbmcgdHVzc2VuIGByIHJvdW5kKGNvbmZpbnRbMV0sMylgIGVuIGByIHJvdW5kKGNvbmZpbnRbM10sMylgIGxpZ3QsIHdhdCB3ZSBrdW5uZW4gemllbiBiaWogcGFyYW1ldGVyIEludGVyY2VwdC4gRGUgcC13YWFyZGUgZGllIGhpZXJiaWogc3RhYXQgKHAgPCAyZS0xNiksIGlzIGRlIHAtd2FhcmRlIHZvb3IgZGUgbnVsaHlwb3RoZXNlIGRhdCBoZXQgaW50ZXJjZXB0ICgkXGJldGFfMCQpLCB3YXQgb3ZlcmVlbiBrb210IG1ldCBoZXQgZ2VtaWRkZWxkIGdld2ljaHQgdm9vciBwbGFudGVuIG1ldCBkZSBjb250cm9sZWJlaGFuZGVsaW5nLCAgZ2VsaWprIGlzIGFhbiAwIC4gRGV6ZSBoeXBvdGhlc2UgaXMgb256aW5uaWcgKGFuZGVycyB6b3VkZW4gd2UgZ2VlbiBwbGFudCBoZWJiZW4uLi4pIGVuIGhlZWZ0IGRhYXJvbSBnZWVuIGludGVyZXNzYW50ZSBpbnRlcnByZXRhdGllLiAKCldlZXIgaXMgb256ZSBjb25sdXNpZToKCiAgLSBFciBpcyBlZW4gc2lnbmlmaWNhbnQgdmVyc2NoaWwgaW4gZ2VtaWRkZWxkIGdld2ljaHQgdHVzc2VuIGRlIGJlaGFuZGVsaW5nZW4gKHAgPSBgciByb3VuZChzdW1tYXJ5JGNvZWZmaWNpZW50c1s4XSwzKWApCiAgCiAgLSBEZSBjb250cm9sZWJlaGFuZGVsaW5nIGhlZWZ0IG1ldCA5NSUgemVrZXJoZWlkIGVlbiBnZW1pZGRlbGQgZ2V3aWNodCB0dXNzZW4gYHIgcm91bmQoY29uZmludFsyXSwzKWAgZW4gYHIgcm91bmQoY29uZmludFs0XSwzKWAgbGFnZXIgZGFuIGJlaGFuZGVsaW5nIDIuCiAgCiAgLSBEZSBjb250cm9sZWJlaGFuZGVsaW5nIGhlZWZ0IG1ldCA5NSUgemVrZXJoZWlkIGVlbiBnZW1pZGRlbGQgZ2V3aWNodCB0dXNzZW4gYHIgcm91bmQoY29uZmludFsxXSwzKWAgZW4gYHIgcm91bmQoY29uZmludFszXSwzKWAuCgoKIyBDb25jbHVzaWU6IAoKV2Uga3VubmVuIGNvbmNsdWRlcmVuIGRhdCB6b3dlbCBkZSB0d28tc2FtcGxlIHQtdGVzdCBhbmFseXNlIGFscyBkZSBsaW5lYWlyZSByZWdyZXNzaWUgZGV6ZWxmZGUgcmVzdWx0YXRlbiBnZXZlbi4gCgogIC0gRXIgaXMgZWVuIHNpZ25pZmljYW50IHZlcnNjaGlsIGluIGdlbWlkZGVsZCBnZXdpY2h0IHR1c3NlbiBkZSBiZWhhbmRlbGluZ2VuIChwID0gYHIgcm91bmQoc3VtbWFyeSRjb2VmZmljaWVudHNbOF0sMylgKQogIAogIC0gRGUgY29udHJvbGViZWhhbmRlbGluZyBoZWVmdCBtZXQgOTUlIHpla2VyaGVpZCBlZW4gZ2VtaWRkZWxkIGdld2ljaHQgdHVzc2VuIGByIHJvdW5kKGNvbmZpbnRbMl0sMylgIGVuIGByIHJvdW5kKGNvbmZpbnRbNF0sMylgIGxhZ2VyIGRhbiBiZWhhbmRlbGluZyAyLgogIAogIC0gRGUgY29udHJvbGViZWhhbmRlbGluZyBoZWVmdCBtZXQgOTUlIHpla2VyaGVpZCBlZW4gZ2VtaWRkZWxkIGdld2ljaHQgdHVzc2VuIGByIHJvdW5kKGNvbmZpbnRbMV0sMylgIGVuIGByIHJvdW5kKGNvbmZpbnRbM10sMylgLgoKCgoKCgo=