1 Introductie

In deze sectie illustreren we hoe experimenten met een factoriële proefopzet geanalyseerd kunnen worden met het algemeen lineair model.

We focussen hierbij op een two-way anova design waarbij we een continue response modelleren in functie van twee categorische predictor variabelen (factoren).

2 Data

48 ratten werden at random toegewezen aan

  • 3 giffen (I,II,III) and
  • 4 behandelingen (A,B,C,D),

en,

  • de overlevingstijd werd opgemeten (eenheid: 10 h)

We transformeren de data eerst naar uren

library(faraway)
data(rats)

rats <- rats %>% 
  mutate(time=time * 10)

library(GGally)
rats %>% 
  ggpairs()

De data exploratie suggereert een effect van beide factoren.

rats %>%
  ggplot(aes(x=treat,y=time)) + 
  geom_boxplot(outlier.shape=NA) + 
  geom_jitter() +
  facet_wrap(~poison) +
  ylab("time (h)")

  • Er zou een interactie kunnen zijn tussen behandeling en gif, het effect van het gif op de overlevingstijd hangt dan af van de behandeling en vice versa.
  • De boxplots geven ook aan dat de data heteroscedastisch zijn.

3 Model

We modelleren de data met een hoofdeffect voor gif en behandeling en een gif \(\times\) behandeling interactie.

\[ \begin{array}{lcl} y_i &=& \beta_0 + \\ &&\beta_{II} x_{iII} + \beta_{III} x_{iIII} + \\ && \beta_{B} x_{iB} + \beta_{C} x_{iC} + \beta_{D} x_{iD} + \\ &&\beta_{II:B}x_{iII}x_{iB} + \beta_{II:C}x_{iII}x_{iC} + \beta_{II:D}x_{iII}x_{iD} + \\ &&\beta_{III:B}x_{iIII}x_{iB} + \beta_{III:C}x_{iIII}x_{iC} + \beta_{III:D}x_{iIII}x_{iD} + \epsilon_i \end{array} \]

met \(i = 1, \ldots, n\), \(n=48\), en, \(x_{iII}\), \(x_{iIII}\), \(x_{iB}\), \(x_{iC}\) en \(x_{iD}\) dummy variabelen voor respectievelijk gif II, III, behandeling B, C, en D.

rats1 <- lm(time~poison*treat, rats)
summary(rats1)

Call:
lm(formula = time ~ poison * treat, data = rats)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.2500 -0.4875  0.0500  0.4312  4.2500 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)        4.1250     0.7457   5.532 2.94e-06 ***
poisonII          -0.9250     1.0546  -0.877   0.3862    
poisonIII         -2.0250     1.0546  -1.920   0.0628 .  
treatB             4.6750     1.0546   4.433 8.37e-05 ***
treatC             1.5500     1.0546   1.470   0.1503    
treatD             1.9750     1.0546   1.873   0.0692 .  
poisonII:treatB    0.2750     1.4914   0.184   0.8547    
poisonIII:treatB  -3.4250     1.4914  -2.297   0.0276 *  
poisonII:treatC   -1.0000     1.4914  -0.671   0.5068    
poisonIII:treatC  -1.3000     1.4914  -0.872   0.3892    
poisonII:treatD    1.5000     1.4914   1.006   0.3212    
poisonIII:treatD  -0.8250     1.4914  -0.553   0.5836    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.491 on 36 degrees of freedom
Multiple R-squared:  0.7335,    Adjusted R-squared:  0.6521 
F-statistic:  9.01 on 11 and 36 DF,  p-value: 1.986e-07
plot(rats1)

De errors zijn heteroscedastisch. De residu plot suggereert een relatie tussen gemiddelde en variantie. De QQ-plot suggereert dat de verdeling mogelijks bredere staarten heeft dan de normale verdeling.

3.1 Transformaties

3.1.1 Logaritmische transformatie

rats %>%
  ggplot(aes(x=treat,y=log2(time))) + 
  geom_boxplot(outlier.shape=NA) + 
  geom_jitter() +
  facet_wrap(~poison)

rats2 <- lm(time %>% log2~poison*treat, rats)
plot(rats2)

Log transformatie verwijdert heteroscedasticiteit niet volledig.

3.1.2 Reciproke transformatie

rats %>%
  ggplot(aes(x=treat,y=1/time)) + 
  geom_boxplot(outlier.shape=NA) + 
  geom_jitter() +
  facet_wrap(~poison) + 
  ylab ("rate of dying (1/h)")

rats3 <- lm(1/time~poison*treat, rats)
plot(rats3) 

De reciproke transformatie lijkt beter. Transformaties bemoeilijken soms de interpretatie. Hier kan de reciproke transformatie echter worden geïnterpreteerd als de “snelheid van sterven” (rate of dying).

4 Inferentie

Er zijn meerdere interactie termen in het model. We kunnen deze eerst samen testen a.d.h.v. van de resultaten uit de anova tabel.

library(car)
Anova(rats3, type="III")

4.1 Verwijderen van niet-significante interactie.

De interactie tussen gif en behandeling is niet significant op het 5% niveau.

Een veelgebruikte methode is om de niet-significante interactie te verwijderen uit het model.

We verkrijgen dan een additief model wat toelaat om de effecten van de twee factoren afzonderlijk te bestuderen.

rats4 <- lm(1/time~poison + treat, rats)
plot(rats4)

We zien wel iets meer afwijkingen in de residu plot.

Anova(rats4, type="III")

De anova tabel toont dat het effect van gif en behandeling beiden extreem siginficant zijn (beide \(p<< 0.001\)).

Het additieve model laat toe om de effecten van het type gif en de behandeling afzonderlijke te bestuderen via een post-hoc analyse.

library(multcomp)
comparisons <- glht(rats4, linfct = mcp(poison = "Tukey", treat="Tukey"))
summary(comparisons)

     Simultaneous Tests for General Linear Hypotheses

Multiple Comparisons of Means: Tukey Contrasts


Fit: lm(formula = 1/time ~ poison + treat, data = rats)

Linear Hypotheses:
                      Estimate Std. Error t value Pr(>|t|)    
poison: II - I == 0    0.04686    0.01744   2.688  0.07353 .  
poison: III - I == 0   0.19964    0.01744  11.451  < 0.001 ***
poison: III - II == 0  0.15278    0.01744   8.763  < 0.001 ***
treat: B - A == 0     -0.16574    0.02013  -8.233  < 0.001 ***
treat: C - A == 0     -0.05721    0.02013  -2.842  0.05097 .  
treat: D - A == 0     -0.13583    0.02013  -6.747  < 0.001 ***
treat: C - B == 0      0.10853    0.02013   5.391  < 0.001 ***
treat: D - B == 0      0.02991    0.02013   1.485  0.61545    
treat: D - C == 0     -0.07862    0.02013  -3.905  0.00275 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Adjusted p values reported -- single-step method)
confint(comparisons)

     Simultaneous Confidence Intervals

Multiple Comparisons of Means: Tukey Contrasts


Fit: lm(formula = 1/time ~ poison + treat, data = rats)

Quantile = 2.8494
95% family-wise confidence level
 

Linear Hypotheses:
                      Estimate   lwr        upr       
poison: II - I == 0    0.0468641 -0.0028153  0.0965435
poison: III - I == 0   0.1996425  0.1499631  0.2493219
poison: III - II == 0  0.1527784  0.1030990  0.2024578
treat: B - A == 0     -0.1657402 -0.2231051 -0.1083754
treat: C - A == 0     -0.0572135 -0.1145784  0.0001513
treat: D - A == 0     -0.1358338 -0.1931987 -0.0784690
treat: C - B == 0      0.1085267  0.0511619  0.1658915
treat: D - B == 0      0.0299064 -0.0274584  0.0872712
treat: D - C == 0     -0.0786203 -0.1359851 -0.0212555
plot(comparisons,yaxt="none")
contrastNames <- c("II-I","III-I","III-II","B-A","C-A","D-A","C-B","D-B","D-C")
axis(2,at=c(length(contrastNames):1), labels=contrastNames,las=2)

4.2 Niet-significante interactie term in het model weerhouden

Het aanvaarden van de null hypothese dat er geen interactie is, is een zwakke conclusie. Het zou immers kunnen dat de power van het experiment te klein is om de interactie op te pikken. We kunnen er ook voor kiezen om de niet significante interactie term in het model te laten.

Als de interactie significant zou zijn geweest, betekent dit dat het effect van het gif op de snelheid van sterven afhangt van de behandeling en vice versa. Dan kunnen we het effect van het type gif en de behandeling op de overlevingstijd niet afzonderlijk bestuderen.

ExploreModelMatrix::VisualizeDesign(rats,~poison*treat)$plot
[[1]]

We zouden dan het effect van het type gif afzonderlijk moeten bestuderen voor elke behandeling:

  1. Voor behandeling A moeten we dan volgende nulhypotheses toetsen:
  • II-I: \(H_0: \beta_{II}=0\)
  • III-I: \(H_0: \beta_{III}=0\)
  • III-II: \(H_0: \beta_{III}-\beta_{II}=0\)
  1. Voor behandeling B:
  • II-I: \(H_0: \beta_{II}+\beta_{II:B}=0\)
  • III-I: \(H_0: \beta_{III}+\beta_{III:B}=0\)
  • III-II: \(H_0: \beta_{III}+\beta_{III:B}-\beta_{II}-\beta_{II:B}=0\)
  1. Voor behandeling C:
  • II-I: \(H_0: \beta_{II}+\beta_{II:C}=0\)
  • III-I: \(H_0: \beta_{III}+\beta_{III:C}=0\)
  • III-II: \(H_0: \beta_{III}+\beta_{III:C}-\beta_{II}-\beta_{II:C}=0\)
  1. Voor behandeling D:
  • II-I: \(H_0: \beta_{II}+\beta_{II:D}=0\)
  • III-I: \(H_0: \beta_{III}+\beta_{III:D}=0\)
  • III-II: \(H_0: \beta_{III}+\beta_{III:D}-\beta_{II}-\beta_{II:D}=0\)

Het zelfde geldt wanneer we het effect van de behandeling bestuderen:

  1. Voor gif I toetsen we dan nulhypothese
  • B-A: \(H_0: \beta_{B}=0\)
  • C-A: \(H_0: \beta_{C}=0\)
  • D-A: \(H_0: \beta_{D}=0\)
  • C-B: \(H_0: \beta_{C}-\beta_{B}=0\)
  • D-B: \(H_0: \beta_{D}-\beta_{B}=0\)
  • D-C: \(H_0: \beta_{D}-\beta_{C}=0\)
  1. Gif II
  • B-A: \(H_0: \beta_{B}+\beta_{II:B}=0\)
  • C-A: \(H_0: \beta_{C}+\beta_{II:C}=0\)
  • D-A: \(H_0: \beta_{D}+\beta_{II:D}=0\)
  • C-B: \(H_0: \beta_{C}+\beta_{II:C}-\beta_{B}-\beta_{II:B}=0\)
  • D-B: \(H_0: \beta_{D}+\beta_{II:D}-\beta_{B}-\beta_{II:B}=0\)
  • D-C: \(H_0: \beta_{D}+\beta_{II:D}-\beta_{C}-\beta_{II:C}=0\)
  1. Gif III
  • B-A: \(H_0: \beta_{B}+\beta_{III:B}=0\)
  • C-A: \(H_0: \beta_{C}+\beta_{III:C}=0\)
  • D-A: \(H_0: \beta_{D}+\beta_{II:D}=0\)
  • C-B: \(H_0: \beta_{C}+\beta_{III:C}-\beta_{B}-\beta_{III:B}=0\)
  • D-B: \(H_0: \beta_{D}+\beta_{III:D}-\beta_{B}-\beta_{III:B}=0\)
  • D-C: \(H_0: \beta_{D}+\beta_{III:D}-\beta_{C}-\beta_{III:C}=0\)
comparisonsInt <- glht(rats3, linfct = c(
  "poisonII = 0",
  "poisonIII = 0",
  "poisonIII - poisonII = 0",
  "poisonII + poisonII:treatB = 0",
  "poisonIII + poisonIII:treatB = 0",
  "poisonIII + poisonIII:treatB - poisonII- poisonII:treatB = 0",  
  "poisonII + poisonII:treatC = 0",
  "poisonIII + poisonIII:treatC = 0",
  "poisonIII + poisonIII:treatC - poisonII- poisonII:treatC = 0",  
  "poisonII + poisonII:treatD = 0",
  "poisonIII + poisonIII:treatD = 0",
  "poisonIII + poisonIII:treatD - poisonII- poisonII:treatD = 0",  
  "treatB = 0",
  "treatC = 0",
  "treatD = 0",
  "treatC - treatB = 0",
  "treatD - treatB = 0",
  "treatD - treatC = 0",
  "treatB + poisonII:treatB = 0",
  "treatC + poisonII:treatC = 0",
  "treatD + poisonII:treatD = 0",
  "treatC + poisonII:treatC - treatB - poisonII:treatB = 0",
  "treatD + poisonII:treatD - treatB - poisonII:treatB = 0",
  "treatD + poisonII:treatD - treatC - poisonII:treatC = 0",
  "treatB + poisonIII:treatB = 0",
  "treatC + poisonIII:treatC = 0",
  "treatD + poisonIII:treatD = 0",
  "treatC + poisonIII:treatC - treatB - poisonIII:treatB = 0",
  "treatD + poisonIII:treatD - treatB - poisonIII:treatB = 0",
  "treatD + poisonIII:treatD - treatC - poisonIII:treatC = 0")
)

contrastNames<-
  c(paste(rep(LETTERS[1:4],each=3),rep(apply(combn(c("I","II","III"),2)[2:1,],2,paste,collapse="-") ,4),sep=": "),
    paste(rep(c("I","II","III"),each=6),rep(apply(combn(c(LETTERS[1:4]),2)[2:1,],2,paste,collapse="-") ,3),sep=": "))

plot(comparisonsInt,yaxt="none")
axis(2,at=c(length(contrastNames):1), labels=contrastNames,las=2)

In onze studie was de interactie echter niet significant. Het effect van het gif (II-I, III-I en III- II) verandert dus niet significant volgens de behandeling (A, B, C, en D) en vice versa. Voor onze dataset lijkt het dus zinvol om

  1. de effectgrootte voor de pairsgewijze vergelijkingen tussen de verschillende giffen (II-I, III-I en III- II) te schatten door ze uit te middelen over alle behandelingen (A, B, C, en D), en,
  2. de effectgrootte voor de pairsgewijze vergelijkingen tussen de verschillende behandelingen (B-A, C-A, D-A, C-B, D-B en D-C) te schatten door ze uit te middelen over alle giffen (I, II, III).

Dat zou ons gelijkaardige schattingen van de effectgroottes moeten geven als deze voor het additieve model waarbij we de interactie term uit het model hadden geweerd.

B.v. voor gif III vs gif II zou dat in volgende contrast resulteren:

  • III-II: \[H_0: \begin{array}{l} \frac{\beta_{III}-\beta_{II}}{4} + \\ \quad \frac{\beta_{III} + \beta_{III:B}-\beta_{II} - \beta_{II:B}}{4} + \\ \quad \quad \frac{\beta_{III} + \beta_{III:C}-\beta_{II} - \beta_{II:C}}{4} + \\ \quad \quad \quad \frac{\beta_{III} + \beta_{III:D}-\beta_{II} - \beta_{II:D}}{4}=0 \end{array} \] \[ H_0:\beta_{III} + \frac{1}{4} \times \beta_{III:B} + \frac{1}{4} \times\beta_{III:C} + \frac{1}{4} \times\beta_{III:D} -\beta_{II} - \frac{1}{4} \times\beta_{II:B} - \frac{1}{4} \times\beta_{II:C} - \frac{1}{4} \times\beta_{II:D}=0 \]

We schatten met onderstaande code alle gemiddelde contrasten a.d.h.v. het model met interactie.

contrasts <- c(
  "poisonII + 1/4*poisonII:treatB + 1/4*poisonII:treatC + 1/4*poisonII:treatD = 0",
  "poisonIII + 1/4*poisonIII:treatB + 1/4*poisonIII:treatC + 1/4*poisonIII:treatD= 0",
  "poisonIII + 1/4*poisonIII:treatB + 1/4*poisonIII:treatC + 1/4*poisonIII:treatD - poisonII - 1/4*poisonII:treatB - 1/4*poisonII:treatC - 1/4*poisonII:treatD = 0",
  "treatB + 1/3*poisonII:treatB + 1/3*poisonIII:treatB = 0",
  "treatC + 1/3*poisonII:treatC + 1/3*poisonIII:treatC = 0",
  "treatD + 1/3*poisonII:treatD + 1/3*poisonIII:treatD = 0",
  "treatC + 1/3*poisonII:treatC + 1/3*poisonIII:treatC - treatB - 1/3*poisonII:treatB - 1/3*poisonIII:treatB = 0",
  "treatD + 1/3*poisonII:treatD + 1/3*poisonIII:treatD  - treatB - 1/3*poisonII:treatB - 1/3*poisonIII:treatB = 0",
  "treatD + 1/3*poisonII:treatD + 1/3*poisonIII:treatD  - treatC - 1/3*poisonII:treatC - 1/3*poisonIII:treatC = 0") 


comparisonsInt2 <- glht(rats3, linfct = contrasts
)
plot(comparisonsInt2,yaxt="none")
contrastNames <- c("II-I","III-I","III-II","B-A","C-A","D-A","C-B","D-B","D-C")
axis(2,at=c(length(contrastNames):1), labels=contrastNames,las=2)

De geschatte effectgroottes zijn inderdaad exact gelijk als bij het model zonder interactie omdat het experiment gebalanceerd is.

De standaard errors verschillen wel lichtjes. Dat is het gevolg van de errors die verschillen tussen beiden modellen alsook het aantal vrijheidsgraden van de errors (n-p).

data.frame(Additive_coef=summary(comparisons)$test$coef,Additive_se=summary(comparisons)$test$sigma,Int_coef=summary(comparisonsInt2)$test$coef,int_se=summary(comparisonsInt2)$test$sigma) %>% round(3)

5 Conclusie

Er is een extreem significant effect van het type gif en de behandeling op de snelheid van sterven bij ratten (p << 0.001).

De interactie tussen gif en behandeling is niet significant (p = 0.387).

De snelheid van sterven is gemiddeld 0.2h\(^{-1}\) en 0.15h\(^{-1}\) hoger voor ratten die blootgesteld worden aan gif III dan aan respectievelijk gif I en II (beide p << 0.001, 95% BI III-I: [0.15, 0.25]h\(^{-1}\), 95% BI III-II: [0.1, 0.2]h\(^{-1}\)) De gemiddelde snelheid van sterven was niet significant verschillend tussen ratten die werden blootgesteld aan gif I en gif II (p=0.074).

De snelheid van sterven is gemiddeld 0.17h\(^{-1}\) en 0.14h\(^{-1}\) hoger na behandeling A dan na behandeling B en D (p << 0.001, 95% BI B-A: [-0.22, -0.11]h\(^{-1}\), 95% BI D-A: [-0.19, -0.08]h\(^{-1}\)). De snelheid van sterven is gemiddeld 0.11h\(^{-1}\) en 0.08h\(^{-1}\) hoger na behandeling C dan respectievelijk na behandeling B en D (C-B: p << 0.001, 95% CI [0.05, 0.17]h\(^{-1}\) , D-C: p = 0.003, 95% CI [-0.14, -0.02]h\(^{-1}\)). De gemiddelde snelheid van sterven is niet significant verschillend tussen ratten behandeld met behandeling C vs A, en D vs B (p- waarden respectievelijk p = 0.051 en p = 0.61).

Alle p-waarden werden gecorrigeerd voor meervoudig testen.

LS0tCnRpdGxlOiAiMTAuIEFsZ2VtZWVuIExpbmVhaXIgTW9kZWwgLSBGYWN0b3Jpw6tsZSBEZXNpZ25zIgphdXRob3I6ICJMaWV2ZW4gQ2xlbWVudCIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgIAogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleAoKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCiMgSW50cm9kdWN0aWUKCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvVjFRQXYyX29ZQnMKIiBmcmFtZWJvcmRlcj0iMCIgc3R5bGU9ImRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87IiBhbGxvdz0iYXV0b3BsYXk7IGVuY3J5cHRlZC1tZWRpYSIgYWxsb3dmdWxsc2NyZWVuPjwvaWZyYW1lPgoKCgpJbiBkZXplIHNlY3RpZSBpbGx1c3RyZXJlbiB3ZSBob2UgZXhwZXJpbWVudGVuIG1ldCBlZW4gZmFjdG9yacOrbGUgcHJvZWZvcHpldCBnZWFuYWx5c2VlcmQga3VubmVuIHdvcmRlbiBtZXQgaGV0IGFsZ2VtZWVuIGxpbmVhaXIgbW9kZWwuIAoKV2UgZm9jdXNzZW4gaGllcmJpaiBvcCBlZW4gdHdvLXdheSBhbm92YSBkZXNpZ24gd2FhcmJpaiB3ZSBlZW4gY29udGludWUgcmVzcG9uc2UgbW9kZWxsZXJlbiBpbiBmdW5jdGllIHZhbiB0d2VlIGNhdGVnb3Jpc2NoZSBwcmVkaWN0b3IgdmFyaWFiZWxlbiAoZmFjdG9yZW4pLiAKCgojIERhdGEgCgoKNDggcmF0dGVuIHdlcmRlbiBhdCByYW5kb20gdG9lZ2V3ZXplbiBhYW4KCi0gMyBnaWZmZW4gKEksSUksSUlJKSBhbmQgCi0gNCBiZWhhbmRlbGluZ2VuIChBLEIsQyxEKSwgCgplbiwgCgotIGRlIG92ZXJsZXZpbmdzdGlqZCB3ZXJkIG9wZ2VtZXRlbiAoZWVuaGVpZDogMTAgaCkKCldlIHRyYW5zZm9ybWVyZW4gZGUgZGF0YSBlZXJzdCBuYWFyIHVyZW4KCmBgYHtyfQpsaWJyYXJ5KGZhcmF3YXkpCmRhdGEocmF0cykKCnJhdHMgPC0gcmF0cyAlPiUgCiAgbXV0YXRlKHRpbWU9dGltZSAqIDEwKQoKbGlicmFyeShHR2FsbHkpCnJhdHMgJT4lIAogIGdncGFpcnMoKQpgYGAKCkRlIGRhdGEgZXhwbG9yYXRpZSBzdWdnZXJlZXJ0IGVlbiBlZmZlY3QgdmFuIGJlaWRlIGZhY3RvcmVuLiAKCmBgYHtyfQpyYXRzICU+JQogIGdncGxvdChhZXMoeD10cmVhdCx5PXRpbWUpKSArIAogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArIAogIGdlb21faml0dGVyKCkgKwogIGZhY2V0X3dyYXAofnBvaXNvbikgKwogIHlsYWIoInRpbWUgKGgpIikKYGBgCgotIEVyIHpvdSBlZW4gaW50ZXJhY3RpZSBrdW5uZW4gemlqbiB0dXNzZW4gYmVoYW5kZWxpbmcgZW4gZ2lmLCBoZXQgZWZmZWN0IHZhbiBoZXQgZ2lmIG9wIGRlIG92ZXJsZXZpbmdzdGlqZCBoYW5ndCBkYW4gYWYgdmFuIGRlIGJlaGFuZGVsaW5nIGVuIHZpY2UgdmVyc2EuIAotIERlIGJveHBsb3RzIGdldmVuIG9vayBhYW4gZGF0IGRlIGRhdGEgaGV0ZXJvc2NlZGFzdGlzY2ggemlqbi4gCgojIE1vZGVsIAoKPGlmcmFtZSB3aWR0aD0iNTYwIiBoZWlnaHQ9IjMxNSIgc3JjPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9lbWJlZC9VeEhLRjBmZ3drWQoiIGZyYW1lYm9yZGVyPSIwIiBzdHlsZT0iZGlzcGxheTogYmxvY2s7IG1hcmdpbjogYXV0bzsiIGFsbG93PSJhdXRvcGxheTsgZW5jcnlwdGVkLW1lZGlhIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+CgoKV2UgbW9kZWxsZXJlbiBkZSBkYXRhIG1ldCBlZW4gaG9vZmRlZmZlY3Qgdm9vciBnaWYgZW4gYmVoYW5kZWxpbmcgZW4gZWVuIGdpZiAkXHRpbWVzJCBiZWhhbmRlbGluZyBpbnRlcmFjdGllLiAKCiQkClxiZWdpbnthcnJheX17bGNsfQp5X2kgJj0mIFxiZXRhXzAgICsgXFwKJiZcYmV0YV97SUl9IHhfe2lJSX0gKyBcYmV0YV97SUlJfSB4X3tpSUlJfSArIFxcCiYmIFxiZXRhX3tCfSB4X3tpQn0gICsgXGJldGFfe0N9IHhfe2lDfSArIFxiZXRhX3tEfSB4X3tpRH0gKyBcXAomJlxiZXRhX3tJSTpCfXhfe2lJSX14X3tpQn0gKyBcYmV0YV97SUk6Q314X3tpSUl9eF97aUN9ICArIFxiZXRhX3tJSTpEfXhfe2lJSX14X3tpRH0gKyBcXAomJlxiZXRhX3tJSUk6Qn14X3tpSUlJfXhfe2lCfSArIFxiZXRhX3tJSUk6Q314X3tpSUlJfXhfe2lDfSAgKyBcYmV0YV97SUlJOkR9eF97aUlJSX14X3tpRH0gKwpcZXBzaWxvbl9pClxlbmR7YXJyYXl9CiQkCgptZXQgJGkgPSAxLCBcbGRvdHMsIG4kLCAkbj00OCQsIGVuLCAkeF97aUlJfSQsICR4X3tpSUlJfSQsICR4X3tpQn0kLCAkeF97aUN9JCBlbiAkeF97aUR9JCBkdW1teSB2YXJpYWJlbGVuIHZvb3IgcmVzcGVjdGlldmVsaWprIGdpZiBJSSwgSUlJLCBiZWhhbmRlbGluZyBCLCBDLCBlbiBELgoKYGBge3J9CnJhdHMxIDwtIGxtKHRpbWV+cG9pc29uKnRyZWF0LCByYXRzKQpzdW1tYXJ5KHJhdHMxKQpwbG90KHJhdHMxKQpgYGAKCkRlIGVycm9ycyB6aWpuIGhldGVyb3NjZWRhc3Rpc2NoLiBEZSByZXNpZHUgcGxvdCBzdWdnZXJlZXJ0IGVlbiByZWxhdGllIHR1c3NlbiBnZW1pZGRlbGRlIGVuIHZhcmlhbnRpZS4gRGUgUVEtcGxvdCBzdWdnZXJlZXJ0IGRhdCBkZSB2ZXJkZWxpbmcgbW9nZWxpamtzIGJyZWRlcmUgc3RhYXJ0ZW4gaGVlZnQgZGFuIGRlIG5vcm1hbGUgdmVyZGVsaW5nLiAKCgojIyBUcmFuc2Zvcm1hdGllcyAKCiMjIyBMb2dhcml0bWlzY2hlIHRyYW5zZm9ybWF0aWUgCgpgYGB7cn0KcmF0cyAlPiUKICBnZ3Bsb3QoYWVzKHg9dHJlYXQseT1sb2cyKHRpbWUpKSkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKyAKICBnZW9tX2ppdHRlcigpICsKICBmYWNldF93cmFwKH5wb2lzb24pCgpyYXRzMiA8LSBsbSh0aW1lICU+JSBsb2cyfnBvaXNvbip0cmVhdCwgcmF0cykKcGxvdChyYXRzMikKYGBgCgpMb2cgdHJhbnNmb3JtYXRpZSB2ZXJ3aWpkZXJ0IGhldGVyb3NjZWRhc3RpY2l0ZWl0IG5pZXQgdm9sbGVkaWcuIAoKIyMjIFJlY2lwcm9rZSB0cmFuc2Zvcm1hdGllCgpgYGB7cn0KcmF0cyAlPiUKICBnZ3Bsb3QoYWVzKHg9dHJlYXQseT0xL3RpbWUpKSArIAogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArIAogIGdlb21faml0dGVyKCkgKwogIGZhY2V0X3dyYXAofnBvaXNvbikgKyAKICB5bGFiICgicmF0ZSBvZiBkeWluZyAoMS9oKSIpCgpyYXRzMyA8LSBsbSgxL3RpbWV+cG9pc29uKnRyZWF0LCByYXRzKQpwbG90KHJhdHMzKSAKYGBgCgpEZSByZWNpcHJva2UgdHJhbnNmb3JtYXRpZSBsaWprdCBiZXRlci4gClRyYW5zZm9ybWF0aWVzIGJlbW9laWxpamtlbiBzb21zIGRlIGludGVycHJldGF0aWUuIApIaWVyIGthbiBkZSByZWNpcHJva2UgdHJhbnNmb3JtYXRpZSBlY2h0ZXIgd29yZGVuIGdlw69udGVycHJldGVlcmQgYWxzIGRlICJzbmVsaGVpZCB2YW4gc3RlcnZlbiIgKHJhdGUgb2YgZHlpbmcpLiAKCiMgSW5mZXJlbnRpZSAKCgo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL0R5M1N5eWFtbEhnCiIgZnJhbWVib3JkZXI9IjAiIHN0eWxlPSJkaXNwbGF5OiBibG9jazsgbWFyZ2luOiBhdXRvOyIgYWxsb3c9ImF1dG9wbGF5OyBlbmNyeXB0ZWQtbWVkaWEiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4KCgo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL0d0R0tBY3R6WlQwCiIgZnJhbWVib3JkZXI9IjAiIHN0eWxlPSJkaXNwbGF5OiBibG9jazsgbWFyZ2luOiBhdXRvOyIgYWxsb3c9ImF1dG9wbGF5OyBlbmNyeXB0ZWQtbWVkaWEiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4KCkVyIHppam4gbWVlcmRlcmUgaW50ZXJhY3RpZSB0ZXJtZW4gaW4gaGV0IG1vZGVsLiAKV2Uga3VubmVuIGRlemUgZWVyc3Qgc2FtZW4gdGVzdGVuIGEuZC5oLnYuIHZhbiBkZSByZXN1bHRhdGVuIHVpdCBkZSBhbm92YSB0YWJlbC4gCgpgYGB7cn0KbGlicmFyeShjYXIpCkFub3ZhKHJhdHMzLCB0eXBlPSJJSUkiKQpgYGAKCiMjIFZlcndpamRlcmVuIHZhbiBuaWV0LXNpZ25pZmljYW50ZSBpbnRlcmFjdGllLiAKCkRlIGludGVyYWN0aWUgdHVzc2VuIGdpZiBlbiBiZWhhbmRlbGluZyBpcyBuaWV0IHNpZ25pZmljYW50IG9wIGhldCA1JSBuaXZlYXUuIAoKRWVuIHZlZWxnZWJydWlrdGUgbWV0aG9kZSBpcyBvbSBkZSBuaWV0LXNpZ25pZmljYW50ZSBpbnRlcmFjdGllIHRlIHZlcndpamRlcmVuIHVpdCBoZXQgbW9kZWwuIAoKV2UgdmVya3JpamdlbiBkYW4gZWVuIGFkZGl0aWVmIG1vZGVsIHdhdCB0b2VsYWF0IG9tIGRlIGVmZmVjdGVuIHZhbiBkZSB0d2VlIGZhY3RvcmVuIGFmem9uZGVybGlqayB0ZSBiZXN0dWRlcmVuLiAKCmBgYHtyfQpyYXRzNCA8LSBsbSgxL3RpbWV+cG9pc29uICsgdHJlYXQsIHJhdHMpCnBsb3QocmF0czQpCmBgYAoKV2UgemllbiB3ZWwgaWV0cyBtZWVyIGFmd2lqa2luZ2VuIGluIGRlIHJlc2lkdSBwbG90LgoKYGBge3J9CkFub3ZhKHJhdHM0LCB0eXBlPSJJSUkiKQpgYGAKCkRlIGFub3ZhIHRhYmVsIHRvb250IGRhdCBoZXQgZWZmZWN0IHZhbiBnaWYgZW4gYmVoYW5kZWxpbmcgYmVpZGVuIGV4dHJlZW0gc2lnaW5maWNhbnQgemlqbiAoYmVpZGUgJHA8PCAwLjAwMSQpLgoKSGV0IGFkZGl0aWV2ZSBtb2RlbCBsYWF0IHRvZSBvbSBkZSBlZmZlY3RlbiB2YW4gaGV0IHR5cGUgZ2lmIGVuIGRlIGJlaGFuZGVsaW5nIGFmem9uZGVybGlqa2UgdGUgYmVzdHVkZXJlbiB2aWEgZWVuIHBvc3QtaG9jIGFuYWx5c2UuIAoKYGBge3J9CmxpYnJhcnkobXVsdGNvbXApCmNvbXBhcmlzb25zIDwtIGdsaHQocmF0czQsIGxpbmZjdCA9IG1jcChwb2lzb24gPSAiVHVrZXkiLCB0cmVhdD0iVHVrZXkiKSkKc3VtbWFyeShjb21wYXJpc29ucykKY29uZmludChjb21wYXJpc29ucykKcGxvdChjb21wYXJpc29ucyx5YXh0PSJub25lIikKY29udHJhc3ROYW1lcyA8LSBjKCJJSS1JIiwiSUlJLUkiLCJJSUktSUkiLCJCLUEiLCJDLUEiLCJELUEiLCJDLUIiLCJELUIiLCJELUMiKQpheGlzKDIsYXQ9YyhsZW5ndGgoY29udHJhc3ROYW1lcyk6MSksIGxhYmVscz1jb250cmFzdE5hbWVzLGxhcz0yKQpgYGAKCiMjIE5pZXQtc2lnbmlmaWNhbnRlIGludGVyYWN0aWUgdGVybSBpbiBoZXQgbW9kZWwgd2VlcmhvdWRlbgoKSGV0IGFhbnZhYXJkZW4gdmFuIGRlIG51bGwgaHlwb3RoZXNlIGRhdCBlciBnZWVuIGludGVyYWN0aWUgaXMsIGlzIGVlbiB6d2Fra2UgY29uY2x1c2llLiAKSGV0IHpvdSBpbW1lcnMga3VubmVuIGRhdCBkZSBwb3dlciB2YW4gaGV0IGV4cGVyaW1lbnQgdGUga2xlaW4gaXMgb20gZGUgaW50ZXJhY3RpZSBvcCB0ZSBwaWtrZW4uCldlIGt1bm5lbiBlciBvb2sgdm9vciBraWV6ZW4gb20gZGUgbmlldCBzaWduaWZpY2FudGUgaW50ZXJhY3RpZSB0ZXJtIGluIGhldCBtb2RlbCB0ZSBsYXRlbi4gCgpBbHMgZGUgaW50ZXJhY3RpZSBzaWduaWZpY2FudCB6b3UgemlqbiBnZXdlZXN0LCBiZXRla2VudCBkaXQgZGF0IGhldCBlZmZlY3QgdmFuIGhldCBnaWYgb3AgZGUgc25lbGhlaWQgdmFuIHN0ZXJ2ZW4gYWZoYW5ndCB2YW4gZGUgYmVoYW5kZWxpbmcgZW4gdmljZSB2ZXJzYS4gCkRhbiBrdW5uZW4gd2UgaGV0IGVmZmVjdCB2YW4gaGV0IHR5cGUgZ2lmIGVuIGRlIGJlaGFuZGVsaW5nIG9wIGRlIG92ZXJsZXZpbmdzdGlqZCBuaWV0IGFmem9uZGVybGlqayBiZXN0dWRlcmVuLiAKCmBgYHtyfSAKRXhwbG9yZU1vZGVsTWF0cml4OjpWaXN1YWxpemVEZXNpZ24ocmF0cyx+cG9pc29uKnRyZWF0KSRwbG90CmBgYAoKV2Ugem91ZGVuIGRhbiBoZXQgZWZmZWN0IHZhbiBoZXQgdHlwZSBnaWYgYWZ6b25kZXJsaWprIG1vZXRlbiBiZXN0dWRlcmVuIHZvb3IgZWxrZSBiZWhhbmRlbGluZzogCgoxLiBWb29yIGJlaGFuZGVsaW5nIEEgbW9ldGVuIHdlIGRhbiB2b2xnZW5kZSBudWxoeXBvdGhlc2VzIHRvZXRzZW46CgotIElJLUk6ICRIXzA6IFxiZXRhX3tJSX09MCQKLSBJSUktSTogJEhfMDogXGJldGFfe0lJSX09MCQKLSBJSUktSUk6ICRIXzA6IFxiZXRhX3tJSUl9LVxiZXRhX3tJSX09MCQKCjIuIFZvb3IgYmVoYW5kZWxpbmcgQjoKCi0gSUktSTogJEhfMDogXGJldGFfe0lJfStcYmV0YV97SUk6Qn09MCQKLSBJSUktSTogJEhfMDogXGJldGFfe0lJSX0rXGJldGFfe0lJSTpCfT0wJAotIElJSS1JSTogJEhfMDogXGJldGFfe0lJSX0rXGJldGFfe0lJSTpCfS1cYmV0YV97SUl9LVxiZXRhX3tJSTpCfT0wJAoKMy4gVm9vciBiZWhhbmRlbGluZyBDOgoKLSBJSS1JOiAkSF8wOiBcYmV0YV97SUl9K1xiZXRhX3tJSTpDfT0wJAotIElJSS1JOiAkSF8wOiBcYmV0YV97SUlJfStcYmV0YV97SUlJOkN9PTAkCi0gSUlJLUlJOiAkSF8wOiBcYmV0YV97SUlJfStcYmV0YV97SUlJOkN9LVxiZXRhX3tJSX0tXGJldGFfe0lJOkN9PTAkCgo0LiBWb29yIGJlaGFuZGVsaW5nIEQ6CgotIElJLUk6ICRIXzA6IFxiZXRhX3tJSX0rXGJldGFfe0lJOkR9PTAkCi0gSUlJLUk6ICRIXzA6IFxiZXRhX3tJSUl9K1xiZXRhX3tJSUk6RH09MCQKLSBJSUktSUk6ICRIXzA6IFxiZXRhX3tJSUl9K1xiZXRhX3tJSUk6RH0tXGJldGFfe0lJfS1cYmV0YV97SUk6RH09MCQKCkhldCB6ZWxmZGUgZ2VsZHQgd2FubmVlciB3ZSBoZXQgZWZmZWN0IHZhbiBkZSBiZWhhbmRlbGluZyBiZXN0dWRlcmVuOiAKCjEuIFZvb3IgZ2lmIEkgdG9ldHNlbiB3ZSBkYW4gbnVsaHlwb3RoZXNlCgotIEItQTogJEhfMDogXGJldGFfe0J9PTAkCi0gQy1BOiAkSF8wOiBcYmV0YV97Q309MCQKLSBELUE6ICRIXzA6IFxiZXRhX3tEfT0wJAotIEMtQjogJEhfMDogXGJldGFfe0N9LVxiZXRhX3tCfT0wJAotIEQtQjogJEhfMDogXGJldGFfe0R9LVxiZXRhX3tCfT0wJAotIEQtQzogJEhfMDogXGJldGFfe0R9LVxiZXRhX3tDfT0wJAoKMi4gR2lmIElJCgotIEItQTogJEhfMDogXGJldGFfe0J9K1xiZXRhX3tJSTpCfT0wJAotIEMtQTogJEhfMDogXGJldGFfe0N9K1xiZXRhX3tJSTpDfT0wJAotIEQtQTogJEhfMDogXGJldGFfe0R9K1xiZXRhX3tJSTpEfT0wJAotIEMtQjogJEhfMDogXGJldGFfe0N9K1xiZXRhX3tJSTpDfS1cYmV0YV97Qn0tXGJldGFfe0lJOkJ9PTAkCi0gRC1COiAkSF8wOiBcYmV0YV97RH0rXGJldGFfe0lJOkR9LVxiZXRhX3tCfS1cYmV0YV97SUk6Qn09MCQKLSBELUM6ICRIXzA6IFxiZXRhX3tEfStcYmV0YV97SUk6RH0tXGJldGFfe0N9LVxiZXRhX3tJSTpDfT0wJAoKMy4gR2lmIElJSQoKLSBCLUE6ICRIXzA6IFxiZXRhX3tCfStcYmV0YV97SUlJOkJ9PTAkCi0gQy1BOiAkSF8wOiBcYmV0YV97Q30rXGJldGFfe0lJSTpDfT0wJAotIEQtQTogJEhfMDogXGJldGFfe0R9K1xiZXRhX3tJSTpEfT0wJAotIEMtQjogJEhfMDogXGJldGFfe0N9K1xiZXRhX3tJSUk6Q30tXGJldGFfe0J9LVxiZXRhX3tJSUk6Qn09MCQKLSBELUI6ICRIXzA6IFxiZXRhX3tEfStcYmV0YV97SUlJOkR9LVxiZXRhX3tCfS1cYmV0YV97SUlJOkJ9PTAkCi0gRC1DOiAkSF8wOiBcYmV0YV97RH0rXGJldGFfe0lJSTpEfS1cYmV0YV97Q30tXGJldGFfe0lJSTpDfT0wJAoKYGBge3IgZmlnLmhlaWdodD0xMH0KY29tcGFyaXNvbnNJbnQgPC0gZ2xodChyYXRzMywgbGluZmN0ID0gYygKICAicG9pc29uSUkgPSAwIiwKICAicG9pc29uSUlJID0gMCIsCiAgInBvaXNvbklJSSAtIHBvaXNvbklJID0gMCIsCiAgInBvaXNvbklJICsgcG9pc29uSUk6dHJlYXRCID0gMCIsCiAgInBvaXNvbklJSSArIHBvaXNvbklJSTp0cmVhdEIgPSAwIiwKICAicG9pc29uSUlJICsgcG9pc29uSUlJOnRyZWF0QiAtIHBvaXNvbklJLSBwb2lzb25JSTp0cmVhdEIgPSAwIiwgIAogICJwb2lzb25JSSArIHBvaXNvbklJOnRyZWF0QyA9IDAiLAogICJwb2lzb25JSUkgKyBwb2lzb25JSUk6dHJlYXRDID0gMCIsCiAgInBvaXNvbklJSSArIHBvaXNvbklJSTp0cmVhdEMgLSBwb2lzb25JSS0gcG9pc29uSUk6dHJlYXRDID0gMCIsICAKICAicG9pc29uSUkgKyBwb2lzb25JSTp0cmVhdEQgPSAwIiwKICAicG9pc29uSUlJICsgcG9pc29uSUlJOnRyZWF0RCA9IDAiLAogICJwb2lzb25JSUkgKyBwb2lzb25JSUk6dHJlYXREIC0gcG9pc29uSUktIHBvaXNvbklJOnRyZWF0RCA9IDAiLCAgCiAgInRyZWF0QiA9IDAiLAogICJ0cmVhdEMgPSAwIiwKICAidHJlYXREID0gMCIsCiAgInRyZWF0QyAtIHRyZWF0QiA9IDAiLAogICJ0cmVhdEQgLSB0cmVhdEIgPSAwIiwKICAidHJlYXREIC0gdHJlYXRDID0gMCIsCiAgInRyZWF0QiArIHBvaXNvbklJOnRyZWF0QiA9IDAiLAogICJ0cmVhdEMgKyBwb2lzb25JSTp0cmVhdEMgPSAwIiwKICAidHJlYXREICsgcG9pc29uSUk6dHJlYXREID0gMCIsCiAgInRyZWF0QyArIHBvaXNvbklJOnRyZWF0QyAtIHRyZWF0QiAtIHBvaXNvbklJOnRyZWF0QiA9IDAiLAogICJ0cmVhdEQgKyBwb2lzb25JSTp0cmVhdEQgLSB0cmVhdEIgLSBwb2lzb25JSTp0cmVhdEIgPSAwIiwKICAidHJlYXREICsgcG9pc29uSUk6dHJlYXREIC0gdHJlYXRDIC0gcG9pc29uSUk6dHJlYXRDID0gMCIsCiAgInRyZWF0QiArIHBvaXNvbklJSTp0cmVhdEIgPSAwIiwKICAidHJlYXRDICsgcG9pc29uSUlJOnRyZWF0QyA9IDAiLAogICJ0cmVhdEQgKyBwb2lzb25JSUk6dHJlYXREID0gMCIsCiAgInRyZWF0QyArIHBvaXNvbklJSTp0cmVhdEMgLSB0cmVhdEIgLSBwb2lzb25JSUk6dHJlYXRCID0gMCIsCiAgInRyZWF0RCArIHBvaXNvbklJSTp0cmVhdEQgLSB0cmVhdEIgLSBwb2lzb25JSUk6dHJlYXRCID0gMCIsCiAgInRyZWF0RCArIHBvaXNvbklJSTp0cmVhdEQgLSB0cmVhdEMgLSBwb2lzb25JSUk6dHJlYXRDID0gMCIpCikKCmNvbnRyYXN0TmFtZXM8LQogIGMocGFzdGUocmVwKExFVFRFUlNbMTo0XSxlYWNoPTMpLHJlcChhcHBseShjb21ibihjKCJJIiwiSUkiLCJJSUkiKSwyKVsyOjEsXSwyLHBhc3RlLGNvbGxhcHNlPSItIikgLDQpLHNlcD0iOiAiKSwKICAgIHBhc3RlKHJlcChjKCJJIiwiSUkiLCJJSUkiKSxlYWNoPTYpLHJlcChhcHBseShjb21ibihjKExFVFRFUlNbMTo0XSksMilbMjoxLF0sMixwYXN0ZSxjb2xsYXBzZT0iLSIpICwzKSxzZXA9IjogIikpCgpwbG90KGNvbXBhcmlzb25zSW50LHlheHQ9Im5vbmUiKQpheGlzKDIsYXQ9YyhsZW5ndGgoY29udHJhc3ROYW1lcyk6MSksIGxhYmVscz1jb250cmFzdE5hbWVzLGxhcz0yKQpgYGAKCkluIG9uemUgc3R1ZGllIHdhcyBkZSBpbnRlcmFjdGllIGVjaHRlciBuaWV0IHNpZ25pZmljYW50LiBIZXQgZWZmZWN0IHZhbiBoZXQgZ2lmIChJSS1JLCBJSUktSSBlbiBJSUktIElJKSB2ZXJhbmRlcnQgZHVzIG5pZXQgc2lnbmlmaWNhbnQgdm9sZ2VucyBkZSBiZWhhbmRlbGluZyAoQSwgQiwgQywgZW4gRCkgZW4gdmljZSB2ZXJzYS4gVm9vciBvbnplIGRhdGFzZXQgbGlqa3QgaGV0IGR1cyB6aW52b2wgb20gCgoxLiBkZSBlZmZlY3Rncm9vdHRlIHZvb3IgZGUgcGFpcnNnZXdpanplIHZlcmdlbGlqa2luZ2VuIHR1c3NlbiBkZSB2ZXJzY2hpbGxlbmRlIGdpZmZlbiAoSUktSSwgSUlJLUkgZW4gSUlJLSBJSSkgdGUgc2NoYXR0ZW4gZG9vciB6ZSB1aXQgdGUgbWlkZGVsZW4gb3ZlciBhbGxlIGJlaGFuZGVsaW5nZW4gKEEsIEIsIEMsIGVuIEQpLCBlbiwgCjIuICBkZSBlZmZlY3Rncm9vdHRlIHZvb3IgZGUgcGFpcnNnZXdpanplIHZlcmdlbGlqa2luZ2VuIHR1c3NlbiBkZSB2ZXJzY2hpbGxlbmRlIGJlaGFuZGVsaW5nZW4gKEItQSwgQy1BLCBELUEsIEMtQiwgRC1CIGVuIEQtQykgdGUgc2NoYXR0ZW4gZG9vciB6ZSB1aXQgdGUgbWlkZGVsZW4gb3ZlciBhbGxlIGdpZmZlbiAoSSwgSUksIElJSSkuIAoKRGF0IHpvdSBvbnMgZ2VsaWprYWFyZGlnZSBzY2hhdHRpbmdlbiB2YW4gZGUgZWZmZWN0Z3Jvb3R0ZXMgbW9ldGVuIGdldmVuIGFscyBkZXplIHZvb3IgaGV0IGFkZGl0aWV2ZSBtb2RlbCB3YWFyYmlqIHdlIGRlIGludGVyYWN0aWUgdGVybSB1aXQgaGV0IG1vZGVsIGhhZGRlbiBnZXdlZXJkLiAKCgpCLnYuIHZvb3IgZ2lmIElJSSB2cyBnaWYgSUkgem91IGRhdCBpbiB2b2xnZW5kZSBjb250cmFzdCByZXN1bHRlcmVuOiAKCi0gSUlJLUlJOiAKJCRIXzA6IApcYmVnaW57YXJyYXl9e2x9ClxmcmFje1xiZXRhX3tJSUl9LVxiZXRhX3tJSX19ezR9ICsgXFwKXHF1YWQgXGZyYWN7XGJldGFfe0lJSX0gKyBcYmV0YV97SUlJOkJ9LVxiZXRhX3tJSX0gLSBcYmV0YV97SUk6Qn19ezR9ICsgXFwKXHF1YWQgXHF1YWQgXGZyYWN7XGJldGFfe0lJSX0gKyBcYmV0YV97SUlJOkN9LVxiZXRhX3tJSX0gLSBcYmV0YV97SUk6Q319ezR9ICsgXFwKXHF1YWQgXHF1YWQgXHF1YWQgXGZyYWN7XGJldGFfe0lJSX0gKyBcYmV0YV97SUlJOkR9LVxiZXRhX3tJSX0gLSBcYmV0YV97SUk6RH19ezR9PTAKXGVuZHthcnJheX0KJCQKJCQKSF8wOlxiZXRhX3tJSUl9ICsgXGZyYWN7MX17NH0gXHRpbWVzIFxiZXRhX3tJSUk6Qn0gKyAgXGZyYWN7MX17NH0gXHRpbWVzXGJldGFfe0lJSTpDfSArICBcZnJhY3sxfXs0fSBcdGltZXNcYmV0YV97SUlJOkR9Ci1cYmV0YV97SUl9IC0gXGZyYWN7MX17NH0gXHRpbWVzXGJldGFfe0lJOkJ9IC0gIFxmcmFjezF9ezR9IFx0aW1lc1xiZXRhX3tJSTpDfSAgLSBcZnJhY3sxfXs0fSBcdGltZXNcYmV0YV97SUk6RH09MAokJAoKV2Ugc2NoYXR0ZW4gbWV0IG9uZGVyc3RhYW5kZSBjb2RlIGFsbGUgZ2VtaWRkZWxkZSBjb250cmFzdGVuIGEuZC5oLnYuIGhldCBtb2RlbCBtZXQgaW50ZXJhY3RpZS4KCmBgYHtyfQpjb250cmFzdHMgPC0gYygKICAicG9pc29uSUkgKyAxLzQqcG9pc29uSUk6dHJlYXRCICsgMS80KnBvaXNvbklJOnRyZWF0QyArIDEvNCpwb2lzb25JSTp0cmVhdEQgPSAwIiwKICAicG9pc29uSUlJICsgMS80KnBvaXNvbklJSTp0cmVhdEIgKyAxLzQqcG9pc29uSUlJOnRyZWF0QyArIDEvNCpwb2lzb25JSUk6dHJlYXREPSAwIiwKICAicG9pc29uSUlJICsgMS80KnBvaXNvbklJSTp0cmVhdEIgKyAxLzQqcG9pc29uSUlJOnRyZWF0QyArIDEvNCpwb2lzb25JSUk6dHJlYXREIC0gcG9pc29uSUkgLSAxLzQqcG9pc29uSUk6dHJlYXRCIC0gMS80KnBvaXNvbklJOnRyZWF0QyAtIDEvNCpwb2lzb25JSTp0cmVhdEQgPSAwIiwKICAidHJlYXRCICsgMS8zKnBvaXNvbklJOnRyZWF0QiArIDEvMypwb2lzb25JSUk6dHJlYXRCID0gMCIsCiAgInRyZWF0QyArIDEvMypwb2lzb25JSTp0cmVhdEMgKyAxLzMqcG9pc29uSUlJOnRyZWF0QyA9IDAiLAogICJ0cmVhdEQgKyAxLzMqcG9pc29uSUk6dHJlYXREICsgMS8zKnBvaXNvbklJSTp0cmVhdEQgPSAwIiwKICAidHJlYXRDICsgMS8zKnBvaXNvbklJOnRyZWF0QyArIDEvMypwb2lzb25JSUk6dHJlYXRDIC0gdHJlYXRCIC0gMS8zKnBvaXNvbklJOnRyZWF0QiAtIDEvMypwb2lzb25JSUk6dHJlYXRCID0gMCIsCiAgInRyZWF0RCArIDEvMypwb2lzb25JSTp0cmVhdEQgKyAxLzMqcG9pc29uSUlJOnRyZWF0RCAgLSB0cmVhdEIgLSAxLzMqcG9pc29uSUk6dHJlYXRCIC0gMS8zKnBvaXNvbklJSTp0cmVhdEIgPSAwIiwKICAidHJlYXREICsgMS8zKnBvaXNvbklJOnRyZWF0RCArIDEvMypwb2lzb25JSUk6dHJlYXREICAtIHRyZWF0QyAtIDEvMypwb2lzb25JSTp0cmVhdEMgLSAxLzMqcG9pc29uSUlJOnRyZWF0QyA9IDAiKSAKCgpjb21wYXJpc29uc0ludDIgPC0gZ2xodChyYXRzMywgbGluZmN0ID0gY29udHJhc3RzCikKcGxvdChjb21wYXJpc29uc0ludDIseWF4dD0ibm9uZSIpCmNvbnRyYXN0TmFtZXMgPC0gYygiSUktSSIsIklJSS1JIiwiSUlJLUlJIiwiQi1BIiwiQy1BIiwiRC1BIiwiQy1CIiwiRC1CIiwiRC1DIikKYXhpcygyLGF0PWMobGVuZ3RoKGNvbnRyYXN0TmFtZXMpOjEpLCBsYWJlbHM9Y29udHJhc3ROYW1lcyxsYXM9MikKYGBgCgpEZSBnZXNjaGF0dGUgZWZmZWN0Z3Jvb3R0ZXMgemlqbiBpbmRlcmRhYWQgZXhhY3QgZ2VsaWprIGFscyBiaWogaGV0IG1vZGVsIHpvbmRlciBpbnRlcmFjdGllIG9tZGF0IGhldCBleHBlcmltZW50IGdlYmFsYW5jZWVyZCBpcy4gCgpEZSBzdGFuZGFhcmQgZXJyb3JzIHZlcnNjaGlsbGVuIHdlbCBsaWNodGplcy4gCkRhdCBpcyBoZXQgZ2V2b2xnIHZhbiBkZSBlcnJvcnMgZGllIHZlcnNjaGlsbGVuIHR1c3NlbiBiZWlkZW4gbW9kZWxsZW4gYWxzb29rIGhldCBhYW50YWwgdnJpamhlaWRzZ3JhZGVuIHZhbiBkZSBlcnJvcnMgKG4tcCkuIAoKYGBge3J9CmRhdGEuZnJhbWUoQWRkaXRpdmVfY29lZj1zdW1tYXJ5KGNvbXBhcmlzb25zKSR0ZXN0JGNvZWYsQWRkaXRpdmVfc2U9c3VtbWFyeShjb21wYXJpc29ucykkdGVzdCRzaWdtYSxJbnRfY29lZj1zdW1tYXJ5KGNvbXBhcmlzb25zSW50MikkdGVzdCRjb2VmLGludF9zZT1zdW1tYXJ5KGNvbXBhcmlzb25zSW50MikkdGVzdCRzaWdtYSkgJT4lIHJvdW5kKDMpCmBgYAoKIyBDb25jbHVzaWUKCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvOTVEdnpMRmUzeWsKIiBmcmFtZWJvcmRlcj0iMCIgc3R5bGU9ImRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87IiBhbGxvdz0iYXV0b3BsYXk7IGVuY3J5cHRlZC1tZWRpYSIgYWxsb3dmdWxsc2NyZWVuPjwvaWZyYW1lPgoKRXIgaXMgZWVuIGV4dHJlZW0gc2lnbmlmaWNhbnQgZWZmZWN0IHZhbiBoZXQgdHlwZSBnaWYgZW4gZGUgYmVoYW5kZWxpbmcgb3AgZGUgc25lbGhlaWQgdmFuIHN0ZXJ2ZW4gYmlqIHJhdHRlbiAocCA8PCAwLjAwMSkuCgpEZSBpbnRlcmFjdGllIHR1c3NlbiBnaWYgZW4gYmVoYW5kZWxpbmcgaXMgbmlldCBzaWduaWZpY2FudCAocCA9IGByICBBbm92YShyYXRzMyx0eXBlPSJJSUkiKVsicG9pc29uOnRyZWF0IiwiUHIoPkYpIl0gJT4lIHJvdW5kKDMpYCkuIAoKRGUgc25lbGhlaWQgdmFuIHN0ZXJ2ZW4gaXMgZ2VtaWRkZWxkIGByIGNvbmZpbnQoY29tcGFyaXNvbnNJbnQyKSRjb25maW50W2NvbnRyYXN0TmFtZXM9PSJJSUktSSIsMV0gJT4lIHJvdW5kKDIpYGgkXnstMX0kICBlbiBgciBjb25maW50KGNvbXBhcmlzb25zSW50MikkY29uZmludFtjb250cmFzdE5hbWVzPT0iSUlJLUlJIiwxXSAlPiUgcm91bmQoMilgaCReey0xfSQgaG9nZXIgdm9vciByYXR0ZW4gZGllIGJsb290Z2VzdGVsZCB3b3JkZW4gYWFuIGdpZiBJSUkgZGFuIGFhbiByZXNwZWN0aWV2ZWxpamsgZ2lmIEkgZW4gSUkgKGJlaWRlIHAgPDwgMC4wMDEsIDk1JSBCSSBJSUktSTogW2ByIHBhc3RlKHJvdW5kKGNvbmZpbnQoY29tcGFyaXNvbnNJbnQyKSRjb25maW50W2NvbnRyYXN0TmFtZXM9PSJJSUktSSIsLTFdLDIpLGNvbGxhcHNlPSIsICIpYF1oJF57LTF9JCwgOTUlIEJJIElJSS1JSTogW2ByIHBhc3RlKHJvdW5kKGNvbmZpbnQoY29tcGFyaXNvbnNJbnQyKSRjb25maW50W2NvbnRyYXN0TmFtZXM9PSJJSUktSUkiLC0xXSwyKSxjb2xsYXBzZT0iLCAiKWBdaCReey0xfSQpCkRlIGdlbWlkZGVsZGUgc25lbGhlaWQgdmFuIHN0ZXJ2ZW4gd2FzIG5pZXQgc2lnbmlmaWNhbnQgdmVyc2NoaWxsZW5kIHR1c3NlbiByYXR0ZW4gZGllIHdlcmRlbiBibG9vdGdlc3RlbGQgYWFuIGdpZiBJIGVuIGdpZiBJSSAocD1gciByb3VuZChzdW1tYXJ5KGNvbXBhcmlzb25zSW50MikkdGVzdCRwdmFsdWVzW2NvbnRyYXN0TmFtZXM9PSJJSS1JIl0sMylgKS4KCkRlIHNuZWxoZWlkIHZhbiBzdGVydmVuIGlzIGdlbWlkZGVsZCBgciBjb25maW50KGNvbXBhcmlzb25zSW50MikkY29uZmludFtjb250cmFzdE5hbWVzPT0iQi1BIiwxXSAlPiUgcm91bmQoMikgJT4lIGFic2BoJF57LTF9JCBlbiBgciBjb25maW50KGNvbXBhcmlzb25zSW50MikkY29uZmludFtjb250cmFzdE5hbWVzPT0iRC1BIiwxXSAlPiUgcm91bmQoMiklPiUgYWJzYGgkXnstMX0kIGhvZ2VyIG5hIGJlaGFuZGVsaW5nIEEgZGFuIG5hIGJlaGFuZGVsaW5nIEIgZW4gRCAocCA8PCAwLjAwMSwgOTUlIEJJIEItQTogW2ByIHBhc3RlKHJvdW5kKGNvbmZpbnQoY29tcGFyaXNvbnNJbnQyKSRjb25maW50W2NvbnRyYXN0TmFtZXM9PSJCLUEiLC0xXSwyKSxjb2xsYXBzZT0iLCAiKWBdaCReey0xfSQsIDk1JSBCSSBELUE6IFtgciBwYXN0ZShyb3VuZChjb25maW50KGNvbXBhcmlzb25zSW50MikkY29uZmludFtjb250cmFzdE5hbWVzPT0iRC1BIiwtMV0sMiksY29sbGFwc2U9IiwgIilgXWgkXnstMX0kKS4gCkRlIHNuZWxoZWlkIHZhbiBzdGVydmVuIGlzIGdlbWlkZGVsZCBgciBjb25maW50KGNvbXBhcmlzb25zSW50MikkY29uZmludFtjb250cmFzdE5hbWVzPT0iQy1CIiwxXSAlPiUgcm91bmQoMilgaCReey0xfSQgZW4gYHIgY29uZmludChjb21wYXJpc29uc0ludDIpJGNvbmZpbnRbY29udHJhc3ROYW1lcz09IkQtQyIsMV0gJT4lIHJvdW5kKDIpICU+JSBhYnNgaCReey0xfSQgaG9nZXIgbmEgYmVoYW5kZWxpbmcgQyBkYW4gcmVzcGVjdGlldmVsaWprIG5hIGJlaGFuZGVsaW5nIEIgZW4gRCAoQy1COiBwIDw8IDAuMDAxLCA5NSUgQ0kgW2ByIHBhc3RlKHJvdW5kKGNvbmZpbnQoY29tcGFyaXNvbnNJbnQyKSRjb25maW50W2NvbnRyYXN0TmFtZXM9PSJDLUIiLC0xXSwyKSxjb2xsYXBzZT0iLCAiKWBdaCReey0xfSQgLCBELUM6IHAgPSBgciBzdW1tYXJ5KGNvbXBhcmlzb25zSW50MikkdGVzdCRwdmFsdWVzW2NvbnRyYXN0TmFtZXM9PSJELUMiXSAlPiUgcm91bmQoMylgLCA5NSUgQ0kgW2ByIHBhc3RlKHJvdW5kKGNvbmZpbnQoY29tcGFyaXNvbnNJbnQyKSRjb25maW50W2NvbnRyYXN0TmFtZXM9PSJELUMiLC0xXSwyKSxjb2xsYXBzZT0iLCAiKWBdaCReey0xfSQpLiAKRGUgZ2VtaWRkZWxkZSBzbmVsaGVpZCB2YW4gc3RlcnZlbiBpcyBuaWV0IHNpZ25pZmljYW50IHZlcnNjaGlsbGVuZCB0dXNzZW4gcmF0dGVuIGJlaGFuZGVsZCBtZXQgYmVoYW5kZWxpbmcgQyB2cyBBLCBlbiBEIHZzIEIgKHAtIHdhYXJkZW4gcmVzcGVjdGlldmVsaWprIHAgPSBgciBzdW1tYXJ5KGNvbXBhcmlzb25zSW50MikkdGVzdCRwdmFsdWVzW2NvbnRyYXN0TmFtZXM9PSJDLUEiXSAlPiUgcm91bmQoMylgIGVuIHAgPSBgciBzdW1tYXJ5KGNvbXBhcmlzb25zSW50MikkdGVzdCRwdmFsdWVzW2NvbnRyYXN0TmFtZXM9PSJELUIiXSAlPiUgcm91bmQoMylgKS4KCkFsbGUgcC13YWFyZGVuIHdlcmRlbiBnZWNvcnJpZ2VlcmQgdm9vciBtZWVydm91ZGlnIHRlc3Rlbi4g