library(ggplot2)
library(xtable)
library(dplyr)
library(plotROC)
library(ROCR)
library(MASS)

Do戼㸳戼㸹czanie pakietu: 㤼㸱MASS㤼㸲

Nast攼㹡puj戼㸹cy obiekt zosta戼㸳 zakryty z 㤼㸱package:dplyr㤼㸲:

    select

Rozkład wielomianowy

Estymatory NW parametrów modelu

Statystyka \(X^2\) Pearsona

\[ \begin{array}{rcl} H_0 & = & \pi_j=\pi_j^0 \: (j=1,2,\dots,I)\\ H_1 & = & \neg H_0\\ \end{array} \]

Niech \(\mu_j=n\pi_j^0\). Statystyka \(X^2\) Pearsona: \[ X^2=\sum_{j=1}^{I}\frac{\left( n_j-\mu_j\right)^2}{\mu_j} \]

Gdy \(n\to\infty\) to \(X^2\to \chi^2_{I-1}\)

Uzasadnienie Fishera

Statystyka Youle’a

\[ \phi^2 = \sum_{j=1}^{I}\pi_j^0 \left( 1-\frac{\widehat{\pi_j}}{\pi_j^0} \right)^2 \]

\[ \phi=\sqrt{\frac{X^2}{n}} \] Dowód

Test \(\chi^2\) dla dużych \(n\) często odrzuca \(H_0\) !!

Przykład

Test ilorazu wiarygodności

\[ H_0:\pi_j=\pi_j^0 \]

\[ \log(l_0)=\sum_j n_j \log \left( \pi_j^0 \right) \]

\[ \log(l_1)=\sum_j n_j \log \left( \widehat{\pi_j} \right) \]

\[ G^2=2\log\left( \frac{l_1}{l_0}\right)=2\sum_j n_j \log \left(\frac{\widehat{\pi_j}}{ \pi_j^0} \right) \]

\(G^2\) ma asymptotycznie rozkład \(\chi^2\) z \(I-1\) stopniami swobody. Rozmiar przestrzeni \(H_0\) jest 0 (punkt) rozmiar \(H_1\) jest \(I-1\) bo \(\sum_{j=1}^{I}\pi_j=1\)
Statystyki \(G^2\) i \(X^2\) są asympttotycznie równe (różnica zbiega według prawdopodobieństwa do 0). \(X^2\) szybciej zbiega do \(\chi^2\) niż \(G^2\).
Przykład

W 60 rzutach kością było 15 jedynek i po 9 dwójek, trójek itd. Oblicz statystyki \(X^2\) i \(G^2\) dla hipotezy, że kość nie jest symetryczna .

\(\mu_j=10\)

\[ X^2=\frac{(15-10)^2}{10}+5\frac{(9-10)^2}{10}=2.5+0.5=3 \]

\(\widehat{\pi_1}=0.25\), \(\widehat{\pi_j}=0.15\) dla \(j=2,...,6\)

\[ G^2=2*\left( 15\log(0.25*6)+5*9*\log(0.15*6) \right) = 2.6815 \]

Wartość krytyczna testu \(\chi^2\) z 5 stopniami swobody wynosi

qchisq(0.05,5,lower.tail = FALSE)
[1] 11.0705

Testowanie gdy \(\mu_j\) są estymowane

Gdy \(\pi_j^0=h_j(\theta)\) to estymator największej wiarygodności \(\widehat{\pi_j^0}=h_j(\widehat{\theta})\) gdzie \(\widehat{\theta}\) jest estymatorem NW parametru \(\theta\).
Zamieniając \(\mu_j\) w statystyce \(X^2\) przez \(\widehat{\mu_j}=n \widehat{\pi_j^0}\) zmieniamy rozkład \(X^2\). Ma on asymptotycznie rozkład \(\chi^2\) z \(I-1-p\) stopniami swobody, gdzie \(p=\dim(\theta)\).

Przykład

Reszty Pearsona dla parametru jednowymiarowego

Reszty Pearsona niestandaryzowane
\[ e_j=\frac{n_j-\widehat{\mu_j}}{\sqrt{\widehat{\mu_j}}} \]

e <- function(n,m){
  ln <- length(n)
  ew <- vector(length = ln)
  for (i in 1:ln) ew[i] <- (n[i]-m[i])/sqrt(m[i])
  chi <- sum(ew^2)
  fi <- sqrt(chi/sum(n))
  list(r=ew,chi=chi,fi=fi)
}
nn <- c(30,63,63)
mm <- c(38.1,39,78.9)
pp <- e(nn,mm)
pp$r
[1] -1.312268  3.843076 -1.790023
pp$chi
[1] 19.69546
pchisq(pp$chi,df = 1,lower.tail = FALSE)
[1] 9.081684e-06
pp$fi
[1] 0.3553209

Reszty Pearsona standaryzowane
\[ \widehat{\pi_j} = \pi_j(\widehat{\theta})\\ g_j=\frac{\partial}{\partial \theta}\left( \pi_j(\theta) \right) |_{\theta=\widehat{\theta}}\\ aa = \sum_j \frac{g_j^2}{\widehat{\pi_j}} \\ h_j=\widehat{\pi_j}+\frac{g_j^2}{aa*\widehat{\pi_j}}\\ r_j = \frac{e_j}{\sqrt{1-h_j}} \]

th <- 0.494
(pi <- c(th^2,th-th^2,1-th))
[1] 0.244036 0.249964 0.506000
(gpi <- c(2*th,1-2*th,-1))
[1]  0.988  0.012 -1.000
(aa <- 4+(1-2*th)^2/th/(1-th)+1/(1-th))
[1] 5.976861
h <- vector(length = 3)
for (i in 1:3) h[i] <- pi[i]+gpi[i]^2/pi[i]/aa
h
[1] 0.9132837 0.2500604 0.8366560
rst <- vector(length = 3)
for(i in 1:3) rst[i] <- pp$r[i]/sqrt(1-h[i])
rst
[1] -4.456276  4.437780 -4.429013

Tablice kontyngencji

Przykład 1 Physicians Health Study (choroba wieńcowa serca)

silny zwykły brak razem
placebo 18 171 10845 11034
aspiryna 5 99 10933 11037

Przykład 2 Palenie i płeć

Wylosowano 100 osób. Każdej z nich zadano dwa pytania: płeć i palenie

pali nie pali razem
kobieta 5 43 48
mężczyzna 8 44 52

Przykład 3 Rak i palenie

rak <- matrix(c(688,650,21,59),nrow=2,ncol=2,byrow=TRUE,
                dimnames=list(c("pali T","pali N"),(c("rak +","rak-"))))
#knitr::kable(rak, caption = "Rak i palenia")
# print(xtable(rak, digits=0),
#  type = "html", html.table.attributes = "border=2")
rak+ rak-
pali T 688 650
pali N 21 59

Modele dla tablic kontyngencji

Oznaczenia \[ \pi_{ij}=P\left( X=x_i,Y=y_j \right) \\ \pi_{i+} = P\left( X=x_i \right) = \sum_{j=1}^J \pi_{ij} \\ \pi_{+j} = P\left( Y=y_j \right) = \sum_{i=1}^I \pi_{ij} \\ \pi_{j|i} = P\left( Y=y_j | X=x_i\right) = \frac{\pi_{ij}}{\pi_{i+}} \] Są dwa możliwe sposoby zbierania informacji

  • Wartości zmiennej \(X\) są wybierane losowo (Przykład 2)
  • Wartości zmiennej \(X\) są wybierane deterministycznie (Przykład 1 i 3)

Niezależność i jednorodność

Gdy zmienna \(X\) jest wybierana deterministycznie mamy do czynienia z jednorodnością, która oznacza, że w każdym wierszu rozkład (warunkowy) zmiennej \(Y\) jest taki sam. Oznacza to, że dla kazdego \(j\): \[ \pi_{j|1} = \pi_{j|2} = \dots = \pi_{j|I} \]

Z tego wynika, że dla każdego \(i,j\)

\[ \pi_{j|i} = \pi_{+j} \\ \pi_{ij} = \pi_{i+}\pi_{+j} \]

Dowód: \[ q_j=\pi_{j|1} = \pi_{j|2} = \dots = \pi_{j|I}\\ q_j = \frac{\pi_{ij}}{\pi_{i+}}\\ \pi_{ij} = q_j\pi_{i+} \\ \pi_{+j}= \sum_{i=1}^I \pi_{ij} = \sum_{i=1}^I q_j\pi_{i+}= q_j=\pi_{j|i} \]

Gdy zmienna \(X\) jest wybierana losowo mamy do czynienia z niezależnością, która oznacza, że Zmienne \(X\) i \(Y\) są niezależne (w sensie rachunku prawdopodobieństwa)

Z tego wynika, że dla każdego \(i,j\)

\[ \pi_{ij} = \pi_{i+}\pi_{+j} \]

Rozkłady prawdopodobieństwa w tablicach kontyngencji

Niech \(N_{ij}\) oznacza niezależne zmienne losowe, określające \(\#\{X=x_i,Y=y_j\}\) w próbie o \(n\) elementach (\(\sum_{ij}N_{ij}=n\)). Niech \(EN_{ij}=\mu_{ij}\). Rozważane są dwa rozkłady:
Poissona: \[ P\left(N_{ij} = n_{ij} \right)= e^{-\mu_{ij}}\frac{\mu_{ij}^{n_{ij}}}{n_{ij}!} \] Wielomianowy, gdy zmienna \(X\) ma wartości wybierane losowo: \[ P\left(N_{11} = n_{11},N_{12} = n_{12},\dots,N_{IJ} = n_{IJ} \right)= n!\prod_{ij}\frac{\pi_{ij}^{n_{ij}}}{n_{ij}!},\\ \pi_{ij} = \frac{\mu_{ij}}{n} \]

Wielomianowy, gdy zmienna \(X\) ma wartości wybierane deterministycznie: \[ P\left(N_{i1} = n_{i1},N_{i2} = n_{i2},\dots,N_{iJ} = n_{iJ} \right)= n_{i+}!\prod_{j}\frac{\pi_{j|i}^{n_{ij}}}{n_{ij}!},\\ \pi_{j|i} = \frac{\mu_{ij}}{\mu_{i+}} \]

Badania biomedyczne

http://www.authorstream.com/Presentation/panstudio-1176382-rodzaje-i-metodyka-bada-klinicznych/

Jak to się zaczęło?: JPo II Wojnie Światowej w czasopiśmie British Medical Journal ukazuje się publikacja opisująca wyniki z pierwszego badania klinicznego z losowym doborem pacjentów do grup. Jest to zarazem zwiastun nowoczesnej antybiotykoterapii, bowiem badanie dotyczy skuteczności streptomycyny w leczeniu gruźlicy. Oxman AD, Sackett DL, Guyatt GH . Users’ guides to the medical literature. I. How to get started. The Evidence-Based Medicine Working Group . JAMA ( 1993 ); 270: 2093-5 .

Badania obserwacyjne: tego rodzaju badania przeprowadza się głównie w celu oceny szkodliwości i analizy czynników rokowniczych; badania takie robi się z braku możliwości wykonania badań eksperymentalnych z powodów etycznych; dla wiarygodności tych wyników badań, podobnie jak w przypadku badań eksperymentalnych, zasadnicze znaczenie ma właściwe dobranie grupy kontrolnej, tak aby grupy różniły się tylko ocenianą ekspozycją; w badaniach obserwacyjnych łatwiej popełnić błąd systematyczny.

Badania prospektywne (kohortowe, cohort study): ocenia się prospektywnie wystąpienie określonego punktu końcowego w grupach (kohortach) osób narażonych i nienarażonych na dany czynnik lub interwencję, np.: Badanie umieralności związanej z paleniem tytoniu – 50-letnie obserwacje lekarzy brytyjskich BMJ. 2004 ; 328: 1519
Przykład 1

Badania retrospektywne (badanie kliniczno-kontrolne, case-control study): porównanie grupy osób u których punkt końcowy już wystąpił (np. nowotwór), z grupą kontrolną (osoby zdrowe), a następnie sprawdzamy częstość występowania jakiegoś czynnika w obu grupach (karta choroby, badanie cech genetycznych, etc.), np.: Używanie telefonu komórkowego a ryzyko nowotworów mózgu
Przykład 3

Badania przekrojowe (cross-sectional study) : W badaniach tych ocenia się chorobowość np. liczba chorych na gruźlicę w Polsce w danym momencie. Badanie to daje dużą niepewność co do związków przyczyno-skutkowych między ekspozycją-ocenianym czynnikiem, np.: Ryzyko choroby zakrzepowo-zatorowej oraz jej profilaktyka w warunkach opieki szpitalnej.
Przykład 2

Przykład, że badanie retrospektywne nie pozwala ocenić związków prospektywnych

ggplot(data.frame(x=c(0, 1)), aes(x)) + stat_function(fun=function(x) 688*x/(688*x+650*(1-x))) +
  geom_abline(slope = 1,intercept = 0,col="blue",linetype=2) +
  labs(title="Prawdopodobieństwo raka, gdy pacjent pali",x="Prawdopodobieństwo raka w populacji",y="Prawdopodobieństwo raka dla palących")

Tablice binarne

Parametry opisujące związki w tablicach binarnych

\[ \pi_1=\pi_{1|1}=\frac{\pi_{11}}{\pi_{1+}} \\ \pi_2=\pi_{1|2}=\frac{\pi_{12}}{\pi_{2+}} \\ \]

  • Różnica
  • Ryzyko względne
  • Stosunek szans
  • Iloraz krzyżowy

Różnica

Różnica i estymator różnicy w próbach o liczności \(n_1\) i \(n_2\) i liczbami sukcesóW \(n_{11}\) i \(n_{12}\) \[ \pi_1 - \pi_2 \\ \widehat{\pi_1}=\frac{n_{11}}{n_1}, \quad \widehat{\pi_2}=\frac{n_{12}}{n_2} \] Odchylenie standardowe różnicy \[ \sigma\left( \widehat{\pi_1} - \widehat{\pi_2} \right) = \sqrt { \frac{\pi_1(1-\pi_1)}{n_1} + \frac{\pi_2(1-\pi_2)}{n_2}} \]

Ryzyko wzgledne

\[ r = \frac{\widehat{\pi_1}}{\widehat{\pi_2}} \\ \sigma(\log(r)) = \sqrt{\frac{1-\pi_1}{\pi_1n_1}+\frac{1-\pi_2}{\pi_2n_2}} \]

Iloraz krzyżowy

Iloraz krzyżowy=1 \(\iff\) jednorodność.
Iloraz krzyżowy=1 \(\iff\) niezależność.

Estymator ilorazu krzyżowego

Iloraz krzyżowy dla doświadczeń typy case-control

Przykład. Rak i palenie

rak+ rak-
pali T 688 650
pali N 21 59
pi1 <- round(688/(688+650),digits=4)
pi2 <- round(21/(21+59),digits=4)
cat("\n",
    "ryzyko raka wśród palących         ",pi1,"\n",
    "ryzyko raka wśród niepalących      ",pi2,"\n",
    "różnica ryzyk dla palących         ",pi1-pi2,"\n",
    "ryzyko względne                    ",round(pi1/pi2,digits=4),"\n",
    "stosunek szans raka dla palących   ",round(pi1/(1-pi1),digits=4),"\n",
    "stosunek szans raka dla niepalących",round(pi2/(1-pi2),digits=4),"\n",
    "iloraz krzyżowy                    ", round(pi1*(1-pi2)/pi2/(1-pi1),digits=4), "\n"
    )

 ryzyko raka wśród palących          0.5142 
 ryzyko raka wśród niepalących       0.2625 
 różnica ryzyk dla palących          0.2517 
 ryzyko względne                     1.9589 
 stosunek szans raka dla palących    1.0585 
 stosunek szans raka dla niepalących 0.3559 
 iloraz krzyżowy                     2.9738 

Przykład

a1 <- 0.410; a2 <- 0.401
b1 <- 0.010; b2 <- 0.001
c(a1-a2,b1-b2)
[1] 0.009 0.009
c(a1/a2,b1/b2)
[1]  1.022444 10.000000

Stosunek szans dla palenia występowanie raka \[ \frac {P(X_1|Y_1)}{P(X_2|Y_1)}=\frac{\frac{\pi_{11}}{\pi_{+1}}}{\frac{\pi_{21}}{\pi_{+1}}}=\frac{\pi_{11}}{\pi_{21}} \]

Stosunek szans dla palenia niewystępowanie raka \[ \frac {P(X_1|Y_2)}{P(X_2|Y_2)}=\frac{\frac{\pi_{12}}{\pi_{+2}}}{\frac{\pi_{22}}{\pi_{+2}}}=\frac{\pi_{12}}{\pi_{22}} \]

Niepotrzebna jest znajomość \(\pi_{+1}\) - prawdopodobieństwa zachorowania na raka!

Estymatory ilorazów szans

c(688/21,650/59)
[1] 32.76190 11.01695

Gdybyśmy mieli w próbie pięciokrotnie mniejszą grupę z osób nie mających raka (z zachowanymi proporcjami)

rak+ rak-
pali T 688 130
pali N 21 12

Estymatory ilorazów szans

c(688/21,130/12)
[1] 32.76190 10.83333

Ilorazy krzyżowe w obu przypadkach.

688*59/(650*21)
[1] 2.973773
688*12/(130*21)
[1] 3.024176

Można dowolnie sterować liczbą osób w próbie.
Jeżeli jest reprezentatywna, a więc zachowały się proporcje, to stosunki szans i iloczyny krzyżowe nie zmienią się.

Przedziały ufności dla ilorazu krzyżowego

\[ OR=\frac{n_{11}*n_{22}}{n_{12}*n_{21}} \\ OR= \frac{(n_{11}+0.5)*(n_{22}+0.5)}{(n_{12}+0.5)*(n_{21}+0.5)} \\ \sigma(\log(OR)) = \sqrt{\frac{1}{n_{11}}+\frac{1}{n_{12}}+\frac{1}{n_{21}}+\frac{1}{n_{22}}} \]

oddsratioWald.proc <- function(n00, n01, n10, n11, alpha = 0.05){
  #
  #  Compute the odds ratio between two binary variables, x and y,
  #  as defined by the four numbers nij:
  #
  #    n00 = number of cases where x = 0 and y = 0
  #    n01 = number of cases where x = 0 and y = 1
  #    n10 = number of cases where x = 1 and y = 0
  #    n11 = number of cases where x = 1 and y = 1
  #
  OR <- (n00 * n11)/(n01 * n10)
  #
  #  Compute the Wald confidence intervals:
  #
  siglog <- sqrt((1/n00) + (1/n01) + (1/n10) + (1/n11))
  zalph <- qnorm(1 - alpha/2)
  logOR <- log(OR)
  loglo <- logOR - zalph * siglog
  loghi <- logOR + zalph * siglog
  #
  ORlo <- exp(loglo)
  ORhi <- exp(loghi)
  #
  oframe <- data.frame(LowerCI = ORlo, OR = OR, UpperCI = ORhi, alpha = alpha)
  oframe
}

Przykład rak i palenie

oddsratioWald.proc(688,650,21,59)

Przykład 1 Physicians Health Study (choroba wieńcowa serca)

silny zwykły brak razem
placebo 18 171 10845 11034
aspiryna 5 99 10933 11037

Po połączeniu dwóch kolumn otrzymamy tabelę binarną

choroba brak razem
placebo 189 10845 11034
aspiryna 104 10933 11037
pi1 <- round(189/(189+10845),digits=4)
pi2 <- round(104/(104+10933),digits=4)
cat("\n",
    "ryzyko choroby wśród placebo       ",pi1,"\n",
    "ryzyko choroby wśród aspiryna      ",pi2,"\n",
    "różnica ryzyk dla placebo          ",pi1-pi2,"\n",
    "ryzyko względne                    ",round(pi1/pi2,digits=4),"\n",
    "stosunek szans choroby dla placebo ",round(pi1/(1-pi1),digits=4),"\n",
    "stosunek szans choroby dla aspiryny",round(pi2/(1-pi2),digits=4),"\n",
    "iloraz krzyżowy                    ", round(pi1*(1-pi2)/pi2/(1-pi1),digits=4), "\n"
    )

 ryzyko choroby wśród placebo        0.0171 
 ryzyko choroby wśród aspiryna       0.0094 
 różnica ryzyk dla placebo           0.0077 
 ryzyko względne                     1.8191 
 stosunek szans choroby dla placebo  0.0174 
 stosunek szans choroby dla aspiryny 0.0095 
 iloraz krzyżowy                     1.8334 

Gdy ryzyko zdarzenia małe (w obu przypadkach) to ryzyko względne = iloraz krzyżowy

Przedziały ufności dla różnych statystyk

Przykład 1 Physicians Health Study

n1 <- 189+10845
n2 <- 104+10933
roznica <- pi1-pi2  + c(-1,1)*1.96*sqrt(pi1*(1-pi1)/n1 + pi2*(1-pi2)/n2)
stosunek <- log(pi1/pi2) + c(-1,1)*1.96*sqrt((1-pi1)/pi1/n1+(1-pi2)/pi2/n2)
stosunek <- exp(stosunek)
OR <- oddsratioWald.proc(189,10845,104,10933)
ORpu <- c(OR$LowerCI,OR$UpperCI)
cat("\n",
    "różnica ryzyk dla placebo          ",round(roznica,digits=4),"\n",
    "ryzyko względne                    ",round(stosunek,digits=4),"\n",
    "iloraz krzyżowy                    ",round(ORpu,digits=4), "\n"
    )

 różnica ryzyk dla placebo           0.0047 0.0107 
 ryzyko względne                     1.4337 2.3082 
 iloraz krzyżowy                     1.44 2.3308 

Reszty Pearsona dla tablic kontyngencji

\[ \chi^2_{(I-1)(J-1)} \\ V = \sqrt{\frac{\chi^2}{n(\min(I,J)-1)}} \\ p_{i+} = \frac{n_{i+}}{n} \quad p_{+j} = \frac{n_{+j}}{n} \\ \widehat{\mu_{ij}}=\frac{n_{i+} n_{+j}}{n} \\ e_{ij}=\frac{n_{ij}-\widehat{\mu_{ij}}}{\sqrt{\widehat{\mu_{ij}}}} \\ r_{ij} = \frac{e_{ij}}{\sqrt{(1-p_{i+})(1-p_{+j})}} \]

Przykład 1 Physicians Health Study

silny zwykły brak razem
placebo 18 171 10845 11034
aspiryna 5 99 10933 11037
razem 23 270 21778 22071
phs <- matrix(c(18,171,10845,5,99,10933),nrow = 2,ncol = 3,byrow = TRUE,
              dimnames=list(c("placebo","aspiryna"),c("silny","zwykły","brak")))
ct <- chisq.test(phs)
ct$statistic
X-squared 
 26.90301 
cat("\n","V = ",sqrt(ct$statistic/22071),"\n",
"p-value = ",ct$p.value,"\n")

 V =  0.03491318 
 p-value =  1.439084e-06 
# mij#
ct$expected
            silny   zwykły     brak
placebo  11.49844 134.9817 10887.52
aspiryna 11.50156 135.0183 10890.48
# eij
ct$residuals
             silny    zwykły       brak
placebo   1.917337  3.100177 -0.4075003
aspiryna -1.917076 -3.099755  0.4074449
# rij
ct$stdres
             silny    zwykły      brak
placebo   2.712753  4.411078 -5.001388
aspiryna -2.712753 -4.411078  5.001388

Diagnozy medyczne. Krzywa ROC

Przykład pylica

FEV1 % normalnej pojemnosci płuc skorygowanej dla wieku i wzrostu pylica - “+” występuje, “-” brak
[Dane: Pylica u górników, Campbell, Machin, Medical Statistics, str.44]

FEV1 <- c(40,43,47,49,50,50,53,57,58,58,58,62,65,69,71,73,74,75,75,77,78,79,80,87,90,100,105,60,67,73,75,79,80,83,87,89,100,105,109,115)
pylica <- c(rep("+",27),rep("-",13))
pylica <- data.frame(FEV1=FEV1,pylica=pylica)
pylica
qplot(pylica, FEV1, data = pylica, geom = "violin", fill = pylica)

qplot(pylica, FEV1, data = pylica, 
      geom= "boxplot", fill = pylica)

Diagnoza na podstawie FEV1: od kiedy uznawać wystąpienie pylicy? Wprowadźmy dwa typy diagnozy:
D80: FEV1<=80 i D90: FEV1<=90

pylica$D80 <- case_when(
  FEV1<=80 ~ "+",
  TRUE ~ "-"
)
pylica$D80 <- as.factor(pylica$D80)
pylica$D90 <- case_when(
  FEV1<=90 ~ "+",
  TRUE ~ "-"
)
pylica$D90 <- as.factor(pylica$D90)
pylica$pylica <- factor(pylica$pylica, levels=rev(levels(pylica$pylica)))
pylica$D80 <- factor(pylica$D80, levels=rev(levels(pylica$D80)))
pylica$D90 <- factor(pylica$D90, levels=rev(levels(pylica$D90)))

Tabele kontyngencji

t80 <- table(pylica$D80,pylica$pylica,dnn=list("diagnoza","choroba"))
t80
        choroba
diagnoza  +  -
       + 23  6
       -  4  7
t90 <- table(pylica$D90,pylica$pylica,dnn=list("diagnoza","choroba"))
t90
        choroba
diagnoza  +  -
       + 25  9
       -  2  4

Ocena tabeli diagnostycznej

choroba + choroba -
diagnoza + TP FP DP
diagnoza - FN TN DN
CP CN S

Wskaźniki oceny tablicy diagnostycznej \[ \text{czułość:}\quad TPR=\frac{TP}{CP}\\ \text{specyficzność:}\quad TNR=\frac{TN}{CN}\\ FPR=\frac{FP}{CN}=1-TNR \]

Dla diagnozy D80 i D90

parD <- data.frame(TPR=c(23/27,25/27),TNR=c(7/13,4/13),FPR=c(6/13,9/13))
rownames(parD) <- c("D80","D90")
round(parD,digits=3)

Globalne oceny tablicy diagnostycznej \[ \text{dokładność:}\quad ACC=\frac{TP+TN}{S} \\ \text{informatywność:} \quad INF=TPR-FPR \\ \text{korelacja Matthewsa} \quad MCC = \phi=\frac{TP*TN-FP*FN}{\sqrt{DP*DN*CP*CN}} \]

Niech \(X=1\) gdy diagnoza jest “+” i \(X=0\) gdy diagnoza jest “-”. Podobnie, niech \(Y=1\) gdy choroba jest “+” i \(Y=0\) gdy choroba jest “-”. Wtedy współczynnik \(\phi\) jest współczynnikiem korelacji między \(X\) i \(Y\). Ponadto \(|\phi|\) jest równe statystyce \(V\) Cramera dla testowania zależności między \(X\) i \(Y\).

Dla diagnozy D80 i D90

gloD <- data.frame(ACC=c((23+7)/40,(25+4)/40),INF=parD$TPR-parD$FPR,
                   MCC=c((23*7-6*4)/sqrt(11*29*13*27),(4*25-4*9)/sqrt(6*34*13*27))
)
rownames(gloD) <- c("D80","D90")
round(gloD,digits=3)

Jak wybrać najlepszy próg diagnostyczny?

pylica$pylica1 <- 2-as.numeric(pylica$pylica)
ggroc <- ggplot(pylica, aes(m =-FEV1, d = pylica1)) + geom_roc()+style_roc()
ggroc

round(calc_auc(ggroc),digits=2)
pred <- prediction(-pylica$FEV1,2-as.numeric(pylica$pylica))
perf <- performance(pred,measure="tpr", x.measure="fpr")
prfdf <- data.frame(cutoff=unlist(perf@alpha.values),fpr=unlist(perf@x.values),tpr=unlist(perf@y.values))
prfdf <- cbind(prfdf,inf=prfdf$tpr-prfdf$fpr)
prfdf

Najlepszy punkt podziału: 78

pylica$D78 <- case_when(
  pylica$FEV1<=78 ~ "+",
  TRUE ~ "-"
)
pylica$D78 <- as.factor(pylica$D78)
pylica$D78 <- factor(pylica$D78, levels=rev(levels(pylica$D78)))
t78 <- table(pylica$D78,pylica$pylica,dnn=list("diagnoza","choroba"))
t78
        choroba
diagnoza  +  -
       + 21  4
       -  6  9
parD <- data.frame(TPR=c(23/27,25/27,21/27),TNR=c(7/13,4/13,9/13),FPR=c(6/13,9/13,4/13))
rownames(parD) <- c("D80","D90","D78")
round(parD,digits=3)
gloD <- data.frame(ACC=c((23+7)/40,(25+4)/40,(21+9)/40),INF=parD$TPR-parD$FPR,
                   MCC=c((23*7-6*4)/sqrt(11*29*13*27),(4*25-4*9)/sqrt(6*34*13*27),
                         (9*21-4*6)/sqrt(25*15*13*27))
)
rownames(gloD) <- c("D80","D90","D78")
round(gloD,digits=3)

Dokładny test Fishera

W ankiecie wzięło udział 5 kobiet i 10 mężczyzn. Na pytanie o poparcie partii XX 3 kobiety i 5 mężczyzn odpowiedziały TAK. Czy poparcie partii XX jest większe u kobiet?

Tablica kontyngencji

tfis <- matrix(c(3,2,5,5,5,10,8,7,15),nrow=3,ncol=3,byrow = TRUE,dimnames=list(c("K","M","suma"),c("T","N","suma")))
tfis
     T N suma
K    3 2    5
M    5 5   10
suma 8 7   15

Pytanie to można wyrazić w języku testowania: \[ H_0: \theta=1 \\ H_1: \theta>1 \]

Liczności w tablicy są tak małe, że poprzednie testy, jako asymptotyczne, są nieadekwatne.
Pomysł FIshera

Gdy \(H_0\) jest prawdziwa to prawdopodobieństwo wyprodukowania tablicy kontyngencji

\(y_1\) \(y_2\)
\(x_1\) \(n_{11}\) \(n_{12}\)
\(x_2\) \(n_{21}\) \(n_{22}\)

o ustalonych wartościach brzegowych \(n_{1+}\), \(n_{2+}\), \(n_{+1}\), \(n_{+2}\) wynosi \[ \frac{\binom{n_{+1}}{n_{11}}\binom{n_{+2}}{n_{12}}}{\binom{n_{++}}{n_{+1}}} = \frac{n_{+1}!\,n_{+2}!\,n_{1+}!\,n_{2+}!}{n_{11}!\,n_{12}!\,n_{21}!\,n_{22}!\,n!} \]

ffisher <- function(n11,n12,n21,n22,cyfr=4) {
  n <- n11+n12+n21+n22
  fff <- factorial(n11+n12)*factorial(n21+n22)* factorial(n11+n21)*factorial(n22+n12)/(
    factorial(n11)*factorial(n12)* factorial(n21)*factorial(n22)*factorial(n) 
  )
   round(fff,digits=cyfr)
}
ffisher(3,2,5,5)
[1] 0.3916

Warunek \(\theta>1\) jest równoważny warunkowi: \[ n_{11}>\widehat{n_{11}}=\frac{n_{1+}n_{+1}}{n} \] Warunek ten w naszym przykładzie ma postać

\[ n_{11}>\frac{5*8}{15}=\frac{8}{3}\\ n_{11} \geq 3 \]

Prawdopodobieństwo, że \(n_{11} \geq 3\) jest równe sumie prawdopodobieństw dla \(n_{11} = 3,4,5\) i wynosi

ffisher(3,2,5,5)
[1] 0.3916
ffisher(4,1,4,6)
[1] 0.1632
ffisher(5,0,3,7)
[1] 0.0186
ffisher(3,2,5,5) + ffisher(4,1,4,6) + ffisher(5,0,3,7)
[1] 0.5734
fisher.test(tfis[1:2,1:2],alternative = "greater")

    Fisher's Exact Test for Count Data

data:  tfis[1:2, 1:2]
p-value = 0.5734
alternative hypothesis: true odds ratio is greater than 1
95 percent confidence interval:
 0.1543702       Inf
sample estimates:
odds ratio 
  1.460011 

Podział tablicy kontyngencji

https://rstudio-pubs-static.s3.amazonaws.com/65435_a8b26773b5d64138b6411a5aa306a5b9.html https://css.ncifcrf.gov/services/alvord/R_Tutorial_Partition_LR_Chi-Square_IxJ_Contingency_Table.pdf

Dane [1996 (USA) General Social Survey, National Opinion Research Center.]
wiersze: wykształcenie“podstawowe”,“średnie”,“wyższe”
kolumny: stosunek do religii “fundamentalista”,“umiarkowany”,“liberalny”

rel.dat <- as.table(matrix(c(178,138,108,570,648,442,138,252,252),nrow=3,ncol=3,byrow=TRUE,dimnames = list(edu=c("P","S","W"),rel=c("F","U","L"))))
addmargins(rel.dat)
     rel
edu      F    U    L  Sum
  P    178  138  108  424
  S    570  648  442 1660
  W    138  252  252  642
  Sum  886 1038  802 2726

Zadanie polega na wybraniu jednorodnych podmacierzy.
Twierdzenie o sumowaniu
Warunki dobrego podziału

t1 <- loglm( ~ edu + rel,data = rel.dat) 
t1
Call:
loglm(formula = ~edu + rel, data = rel.dat)

Statistics:
                      X^2 df     P(> X^2)
Likelihood Ratio 69.81162  4 2.486900e-14
Pearson          69.15676  4 3.419487e-14
chisq.test(rel.dat)$stdres
   rel
edu          F          U          L
  P  4.5349181 -2.5521511 -1.9417050
  S  2.5532682  1.2859224 -3.9946969
  W -6.8097502  0.7009713  6.2525467
t2 <- as.table(rel.dat[c(1,2),c(2,3)])
t2
   rel
edu   U   L
  P 138 108
  S 648 442
t2m <- loglm( ~ edu + rel,data = t2) 
t2m
Call:
loglm(formula = ~edu + rel, data = t2)

Statistics:
                       X^2 df  P(> X^2)
Likelihood Ratio 0.9267211  1 0.3357164
Pearson          0.9310773  1 0.3345831
chisq.test(t2)$stdres
   rel
edu          U          L
  P -0.9649235  0.9649235
  S  0.9649235 -0.9649235
apply(t2,1,sum)
   P    S 
 246 1090 
t3 <- as.table(matrix(c(246,1090,c(178,570)),nrow=2,ncol=2,dimnames = list(edu=c("P","S"),rel=c("U+L","F"))))
t3
   rel
edu  U+L    F
  P  246  178
  S 1090  570
t3m <- loglm( ~ edu + rel,data = t3) 
t3m
Call:
loglm(formula = ~edu + rel, data = t3)

Statistics:
                      X^2 df    P(> X^2)
Likelihood Ratio 8.440411  1 0.003669733
Pearson          8.575911  1 0.003406395
chisq.test(t3)$stdres
   rel
edu       U+L         F
  P -2.928466  2.928466
  S  2.928466 -2.928466
apply(t2,2,sum)
  U   L 
786 550 
t4 <- as.table(matrix(c(786,252,c(550,252)),nrow=2,ncol=2,dimnames = list(edu=c("P+S","W"),rel=c("U","L"))))
t4
     rel
edu     U   L
  P+S 786 550
  W   252 252
t4m <- loglm( ~ edu + rel,data = t4) 
t4m
Call:
loglm(formula = ~edu + rel, data = t4)

Statistics:
                      X^2 df     P(> X^2)
Likelihood Ratio 11.55507  1 0.0006756460
Pearson          11.61005  1 0.0006559629
chisq.test(t4)$stdres
     rel
edu           U         L
  P+S  3.407353 -3.407353
  W   -3.407353  3.407353
sum(t2)
[1] 1336
t5 <- as.table(matrix(c(1336,252+252,c(178+570,138)),nrow=2,ncol=2,dimnames = list(edu=c("P+S","W"),rel=c("U+L","F"))))
t5
     rel
edu    U+L    F
  P+S 1336  748
  W    504  138
t5m <- loglm( ~ edu + rel,data = t5) 
t5m
Call:
loglm(formula = ~edu + rel, data = t5)

Statistics:
                      X^2 df     P(> X^2)
Likelihood Ratio 48.88941  1 2.708056e-12
Pearson          46.37270  1 9.776846e-12
chisq.test(t5)$stdres
     rel
edu        U+L        F
  P+S -6.80975  6.80975
  W    6.80975 -6.80975
LS0tDQp0aXRsZTogIkFuYWxpemEgZGFueWNoIGpha2/Fm2Npb3d5Y2ggQiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyIGxpYnJhcnl9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHh0YWJsZSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBsb3RST0MpDQpsaWJyYXJ5KFJPQ1IpDQpsaWJyYXJ5KE1BU1MpDQpgYGANCg0KIyNSb3prxYJhZCB3aWVsb21pYW5vd3kgIA0KKkVzdHltYXRvcnkgTlcgcGFyYW1ldHLDs3cgbW9kZWx1Kg0KDQoNCiMjIyNTdGF0eXN0eWthICRYXjIkIFBlYXJzb25hDQokJA0KXGJlZ2lue2FycmF5fXtyY2x9DQogIEhfMCAmID0gJiBccGlfaj1ccGlfal4wIFw6IChqPTEsMixcZG90cyxJKVxcDQogIEhfMSAmID0gJiBcbmVnIEhfMFxcDQpcZW5ke2FycmF5fQ0KJCQNCg0KTmllY2ggJFxtdV9qPW5ccGlfal4wJC4gU3RhdHlzdHlrYSAkWF4yJCBQZWFyc29uYToNCiQkDQpYXjI9XHN1bV97aj0xfV57SX1cZnJhY3tcbGVmdCggbl9qLVxtdV9qXHJpZ2h0KV4yfXtcbXVfan0NCiQkDQoNCj4gR2R5ICRuXHRvXGluZnR5JCB0byAkWF4yXHRvIFxjaGleMl97SS0xfSQNCg0KKlV6YXNhZG5pZW5pZSBGaXNoZXJhKg0KDQoqKlN0YXR5c3R5a2EgWW91bGUnYSoqDQoNCg0KJCQNClxwaGleMiA9IFxzdW1fe2o9MX1ee0l9XHBpX2peMCBcbGVmdCgNCjEtXGZyYWN7XHdpZGVoYXR7XHBpX2p9fXtccGlfal4wfQ0KXHJpZ2h0KV4yDQokJA0KDQokJA0KXHBoaT1cc3FydHtcZnJhY3tYXjJ9e259fQ0KJCQNCipEb3fDs2QqDQoNCj4gVGVzdCAkXGNoaV4yJCBkbGEgZHXFvHljaCAkbiQgY3rEmXN0byBvZHJ6dWNhICRIXzAkICEhDQoNCipQcnp5a8WCYWQqDQoNCiMjI1Rlc3QgaWxvcmF6dSB3aWFyeWdvZG5vxZtjaQ0KDQokJA0KSF8wOlxwaV9qPVxwaV9qXjANCiQkDQoNCiQkDQpcbG9nKGxfMCk9XHN1bV9qIG5faiBcbG9nDQpcbGVmdCgNCiAgXHBpX2peMA0KXHJpZ2h0KQ0KJCQNCg0KJCQNClxsb2cobF8xKT1cc3VtX2ogbl9qIFxsb2cNClxsZWZ0KA0KICBcd2lkZWhhdHtccGlfan0NClxyaWdodCkNCiQkDQoNCiQkDQpHXjI9Mlxsb2dcbGVmdCggXGZyYWN7bF8xfXtsXzB9XHJpZ2h0KT0yXHN1bV9qIG5faiBcbG9nIFxsZWZ0KFxmcmFje1x3aWRlaGF0e1xwaV9qfX17IFxwaV9qXjB9IFxyaWdodCkNCiQkDQoNCiRHXjIkIG1hIGFzeW1wdG90eWN6bmllIHJvemvFgmFkICRcY2hpXjIkIHogJEktMSQgc3RvcG5pYW1pIHN3b2JvZHkuIFJvem1pYXIgcHJ6ZXN0cnplbmkgJEhfMCQgamVzdCAwIChwdW5rdCkgcm96bWlhciAkSF8xJCBqZXN0ICRJLTEkIGJvICRcc3VtX3tqPTF9XntJfVxwaV9qPTEkICANClN0YXR5c3R5a2kgJEdeMiQgaSAkWF4yJCBzxIUgYXN5bXB0dG90eWN6bmllIHLDs3duZSAocsOzxbxuaWNhIHpiaWVnYSB3ZWTFgnVnIHByYXdkb3BvZG9iaWXFhHN0d2EgZG8gMCkuICRYXjIkIHN6eWJjaWVqIHpiaWVnYSBkbyAkXGNoaV4yJCBuacW8ICRHXjIkLiAgDQoqKlByenlrxYJhZCoqICANCg0KPlcgNjAgcnp1dGFjaCBrb8WbY2nEhSBiecWCbyAxNSBqZWR5bmVrIGkgcG8gOSBkd8OzamVrLCB0csOzamVrIGl0ZC4gT2JsaWN6IHN0YXR5c3R5a2kgJFheMiQgaSAkR14yJCBkbGEgaGlwb3RlenksIMW8ZSBrb8WbxIcgbmllIGplc3Qgc3ltZXRyeWN6bmEgIC4NCg0KJFxtdV9qPTEwJA0KDQokJA0KWF4yPVxmcmFjeygxNS0xMCleMn17MTB9KzVcZnJhY3soOS0xMCleMn17MTB9PTIuNSswLjU9Mw0KJCQNCg0KJFx3aWRlaGF0e1xwaV8xfT0wLjI1JCwgJFx3aWRlaGF0e1xwaV9qfT0wLjE1JCBkbGEgJGo9MiwuLi4sNiQNCg0KJCQNCkdeMj0yKlxsZWZ0KA0KICAxNVxsb2coMC4yNSo2KSs1KjkqXGxvZygwLjE1KjYpIA0KICBccmlnaHQpID0gMi42ODE1DQokJA0KDQpXYXJ0b8WbxIcga3J5dHljem5hIHRlc3R1ICRcY2hpXjIkIHogNSBzdG9wbmlhbWkgc3dvYm9keSB3eW5vc2kNCmBgYHtyfQ0KcWNoaXNxKDAuMDUsNSxsb3dlci50YWlsID0gRkFMU0UpDQpgYGANCg0KIyMjI1Rlc3Rvd2FuaWUgZ2R5ICRcbXVfaiQgc8SFIGVzdHltb3dhbmUNCg0KR2R5ICRccGlfal4wPWhfaihcdGhldGEpJCB0byBlc3R5bWF0b3IgbmFqd2nEmWtzemVqIHdpYXJ5Z29kbm/Fm2NpICRcd2lkZWhhdHtccGlfal4wfT1oX2ooXHdpZGVoYXR7XHRoZXRhfSkkICBnZHppZSAkXHdpZGVoYXR7XHRoZXRhfSQgamVzdCBlc3R5bWF0b3JlbSBOVyBwYXJhbWV0cnUgJFx0aGV0YSQuICANClphbWllbmlhasSFYyAkXG11X2okIHcgc3RhdHlzdHljZSAkWF4yJCBwcnpleiAkXHdpZGVoYXR7XG11X2p9PW4gXHdpZGVoYXR7XHBpX2peMH0kIHptaWVuaWFteSByb3prxYJhZCAkWF4yJC4gTWEgb24gYXN5bXB0b3R5Y3puaWUgcm96a8WCYWQgJFxjaGleMiQgeiAkSS0xLXAkIHN0b3BuaWFtaSBzd29ib2R5LCBnZHppZSAkcD1cZGltKFx0aGV0YSkkLg0KDQoNCipQcnp5a8WCYWQqDQoNCiMjIyNSZXN6dHkgUGVhcnNvbmEgZGxhIHBhcmFtZXRydSBqZWRub3d5bWlhcm93ZWdvICANCioqUmVzenR5IFBlYXJzb25hIG5pZXN0YW5kYXJ5em93YW5lKiogIA0KJCQNCmVfaj1cZnJhY3tuX2otXHdpZGVoYXR7XG11X2p9fXtcc3FydHtcd2lkZWhhdHtcbXVfan19fQ0KJCQNCg0KYGBge3IgcmVzenR5IHp3eWvFgmV9DQplIDwtIGZ1bmN0aW9uKG4sbSl7DQogIGxuIDwtIGxlbmd0aChuKQ0KICBldyA8LSB2ZWN0b3IobGVuZ3RoID0gbG4pDQogIGZvciAoaSBpbiAxOmxuKSBld1tpXSA8LSAobltpXS1tW2ldKS9zcXJ0KG1baV0pDQogIGNoaSA8LSBzdW0oZXdeMikNCiAgZmkgPC0gc3FydChjaGkvc3VtKG4pKQ0KICBsaXN0KHI9ZXcsY2hpPWNoaSxmaT1maSkNCn0NCg0KYGBgDQoNCmBgYHtyfQ0Kbm4gPC0gYygzMCw2Myw2MykNCm1tIDwtIGMoMzguMSwzOSw3OC45KQ0KcHAgPC0gZShubixtbSkNCnBwJHINCnBwJGNoaQ0KcGNoaXNxKHBwJGNoaSxkZiA9IDEsbG93ZXIudGFpbCA9IEZBTFNFKQ0KcHAkZmkNCmBgYA0KDQoqKlJlc3p0eSBQZWFyc29uYSBzdGFuZGFyeXpvd2FuZSoqICANCiQkDQpcd2lkZWhhdHtccGlfan0gPSBccGlfaihcd2lkZWhhdHtcdGhldGF9KVxcDQpnX2o9XGZyYWN7XHBhcnRpYWx9e1xwYXJ0aWFsIFx0aGV0YX1cbGVmdCggXHBpX2ooXHRoZXRhKSBccmlnaHQpIHxfe1x0aGV0YT1cd2lkZWhhdHtcdGhldGF9fVxcDQphYSA9IFxzdW1faiBcZnJhY3tnX2peMn17XHdpZGVoYXR7XHBpX2p9fSBcXA0KaF9qPVx3aWRlaGF0e1xwaV9qfStcZnJhY3tnX2peMn17YWEqXHdpZGVoYXR7XHBpX2p9fVxcDQpyX2ogPSBcZnJhY3tlX2p9e1xzcXJ0ezEtaF9qfX0NCiQkDQoNCmBgYHtyfQ0KdGggPC0gMC40OTQNCihwaSA8LSBjKHRoXjIsdGgtdGheMiwxLXRoKSkNCihncGkgPC0gYygyKnRoLDEtMip0aCwtMSkpDQooYWEgPC0gNCsoMS0yKnRoKV4yL3RoLygxLXRoKSsxLygxLXRoKSkNCmggPC0gdmVjdG9yKGxlbmd0aCA9IDMpDQpmb3IgKGkgaW4gMTozKSBoW2ldIDwtIHBpW2ldK2dwaVtpXV4yL3BpW2ldL2FhDQpoDQpyc3QgPC0gdmVjdG9yKGxlbmd0aCA9IDMpDQpmb3IoaSBpbiAxOjMpIHJzdFtpXSA8LSBwcCRyW2ldL3NxcnQoMS1oW2ldKQ0KcnN0DQpgYGANCg0KIyNUYWJsaWNlIGtvbnR5bmdlbmNqaQ0KDQoNCioqUHJ6eWvFgmFkIDEqKiBfUGh5c2ljaWFucyBIZWFsdGggU3R1ZHlfIChjaG9yb2JhIHdpZcWEY293YSBzZXJjYSkgIA0KDQp8ICAgICAgICB8c2lsbnl8end5a8WCeXxicmFrfHJhemVtfA0KfDotLS0tLS06fC0tLS06fC0tLS0tOnwtLS0tOnwtLS0tOnwNCnwgcGxhY2Vib3wgICAxOHwgICAxNzF8MTA4NDV8MTEwMzR8DQp8YXNwaXJ5bmF8ICAgIDV8ICAgIDk5fDEwOTMzfDExMDM3fA0KDQoqKlByenlrxYJhZCAyKiogX1BhbGVuaWUgaSBwxYJlxIdfICAgDQoNCj5XeWxvc293YW5vIDEwMCBvc8OzYi4gS2HFvGRlaiB6IG5pY2ggemFkYW5vIGR3YSBweXRhbmlhOiBwxYJlxIcgaSBwYWxlbmllDQoNCg0KfCAgICAgICAgIHxwYWxpfG5pZSBwYWxpfHJhemVtfA0KfDotLS0tLS0tOnwtLS06fC0tLS0tLS06fC0tOnwNCnwgIGtvYmlldGF8ICAgNXwgICAgICA0M3wgNDh8DQp8bcSZxbxjenl6bmF8ICAgOHwgICAgICA0NHwgNTJ8DQoNCg0KKipQcnp5a8WCYWQgMyoqIF9SYWsgaSBwYWxlbmllXyANCg0KYGBge3IgfQ0KcmFrIDwtIG1hdHJpeChjKDY4OCw2NTAsMjEsNTkpLG5yb3c9MixuY29sPTIsYnlyb3c9VFJVRSwNCiAgICAgICAgICAgICAgICBkaW1uYW1lcz1saXN0KGMoInBhbGkgVCIsInBhbGkgTiIpLChjKCJyYWsgKyIsInJhay0iKSkpKQ0KYGBgDQoNCmBgYHtyIHJlc3VsdHM9ICJhc2lzIn0NCiNrbml0cjo6a2FibGUocmFrLCBjYXB0aW9uID0gIlJhayBpIHBhbGVuaWEiKQ0KYGBgDQoNCmBgYHtyIHJlc3VsdHM9ImFzaXMifQ0KDQojIHByaW50KHh0YWJsZShyYWssIGRpZ2l0cz0wKSwNCiMgIHR5cGUgPSAiaHRtbCIsIGh0bWwudGFibGUuYXR0cmlidXRlcyA9ICJib3JkZXI9MiIpDQoNCmBgYA0KDQp8ICAgICAgfHJhaysgfHJhay18DQp8Oi0tLS06fC0tLS06fC0tLTp8DQp8cGFsaSBUfDY4OCAgfDY1MCB8DQp8cGFsaSBOfDIxICAgfDU5ICB8DQoNCiMjI01vZGVsZSBkbGEgdGFibGljIGtvbnR5bmdlbmNqaSAgDQoqKk96bmFjemVuaWEqKg0KJCQNClxwaV97aWp9PVBcbGVmdCggWD14X2ksWT15X2ogXHJpZ2h0KSBcXA0KXHBpX3tpK30gPSBQXGxlZnQoIFg9eF9pIFxyaWdodCkgPSBcc3VtX3tqPTF9XkogXHBpX3tpan0gXFwNClxwaV97K2p9ID0gUFxsZWZ0KCBZPXlfaiBccmlnaHQpID0gXHN1bV97aT0xfV5JIFxwaV97aWp9IFxcDQpccGlfe2p8aX0gPSBQXGxlZnQoIFk9eV9qIHwgWD14X2lccmlnaHQpID0gXGZyYWN7XHBpX3tpan19e1xwaV97aSt9fQ0KJCQNClPEhSBkd2EgbW/FvGxpd2Ugc3Bvc29ieSB6YmllcmFuaWEgaW5mb3JtYWNqaQ0KDQoqIFdhcnRvxZtjaSB6bWllbm5laiAkWCQgc8SFIHd5YmllcmFuZSBsb3Nvd28gKFByenlrxYJhZCAyKQ0KKiBXYXJ0b8WbY2kgem1pZW5uZWogJFgkIHPEhSB3eWJpZXJhbmUgZGV0ZXJtaW5pc3R5Y3puaWUgKFByenlrxYJhZCAxIGkgMykNCg0KDQojIyMjTmllemFsZcW8bm/Fm8SHIGkgamVkbm9yb2Rub8WbxIcgIA0KR2R5IHptaWVubmEgJFgkIGplc3Qgd3liaWVyYW5hIGRldGVybWluaXN0eWN6bmllIG1hbXkgZG8gY3p5bmllbmlhIHogKipqZWRub3JvZG5vxZtjacSFKiosIGt0w7NyYSBvem5hY3phLCDFvGUgdyBrYcW8ZHltIHdpZXJzenUgcm96a8WCYWQgKHdhcnVua293eSkgem1pZW5uZWogJFkkIGplc3QgdGFraSBzYW0uDQpPem5hY3phIHRvLCDFvGUgZGxhIGthemRlZ28gJGokOg0KJCQNClxwaV97anwxfSA9IFxwaV97anwyfSA9IFxkb3RzID0gXHBpX3tqfEl9DQokJA0KDQpaIHRlZ28gd3luaWthLCDFvGUgZGxhIGthxbxkZWdvICRpLGokICANCg0KJCQNClxwaV97anxpfSA9IFxwaV97K2p9IFxcDQpccGlfe2lqfSA9IFxwaV97aSt9XHBpX3sran0NCiQkICANCg0KRG93w7NkOg0KJCQNCnFfaj1ccGlfe2p8MX0gPSBccGlfe2p8Mn0gPSBcZG90cyA9IFxwaV97anxJfVxcDQpxX2ogPSBcZnJhY3tccGlfe2lqfX17XHBpX3tpK319XFwNClxwaV97aWp9ID0gcV9qXHBpX3tpK30gXFwNClxwaV97K2p9PSBcc3VtX3tpPTF9XkkgXHBpX3tpan0gPSBcc3VtX3tpPTF9XkkgcV9qXHBpX3tpK309IHFfaj1ccGlfe2p8aX0NCiQkDQoNCkdkeSB6bWllbm5hICRYJCBqZXN0IHd5YmllcmFuYSBsb3Nvd28gbWFteSBkbyBjenluaWVuaWEgeiAqKm5pZXphbGXFvG5vxZtjacSFKiosIGt0w7NyYSBvem5hY3phLCDFvGUgWm1pZW5uZSAkWCQgaSAkWSQgc8SFIG5pZXphbGXFvG5lICh3IHNlbnNpZSByYWNodW5rdSBwcmF3ZG9wb2RvYmllxYRzdHdhKQ0KDQpaIHRlZ28gd3luaWthLCDFvGUgZGxhIGthxbxkZWdvICRpLGokICANCg0KJCQNClxwaV97aWp9ID0gXHBpX3tpK31ccGlfeytqfQ0KJCQgIA0KDQojIyMjUm96a8WCYWR5IHByYXdkb3BvZG9iaWXFhHN0d2EgdyB0YWJsaWNhY2gga29udHluZ2VuY2ppDQoNCk5pZWNoICROX3tpan0kIG96bmFjemEgbmllemFsZcW8bmUgem1pZW5uZSBsb3Nvd2UsIG9rcmXFm2xhasSFY2UgJFwjXHtYPXhfaSxZPXlfalx9JCB3IHByw7NiaWUgbyAkbiQgZWxlbWVudGFjaCAoJFxzdW1fe2lqfU5fe2lqfT1uJCkuIE5pZWNoICRFTl97aWp9PVxtdV97aWp9JC4gUm96d2HFvGFuZSBzxIUgZHdhIHJvemvFgmFkeTogIA0KUG9pc3NvbmE6DQokJA0KUFxsZWZ0KE5fe2lqfSA9IG5fe2lqfSBccmlnaHQpPSBlXnstXG11X3tpan19XGZyYWN7XG11X3tpan1ee25fe2lqfX19e25fe2lqfSF9DQokJA0KV2llbG9taWFub3d5LCBnZHkgem1pZW5uYSAkWCQgbWEgd2FydG/Fm2NpIHd5YmllcmFuZSBsb3Nvd286DQokJA0KUFxsZWZ0KE5fezExfSA9IG5fezExfSxOX3sxMn0gPSBuX3sxMn0sXGRvdHMsTl97SUp9ID0gbl97SUp9IFxyaWdodCk9IG4hXHByb2Rfe2lqfVxmcmFje1xwaV97aWp9XntuX3tpan19fXtuX3tpan0hfSxcXA0KXHBpX3tpan0gPSBcZnJhY3tcbXVfe2lqfX17bn0NCiQkDQoNCldpZWxvbWlhbm93eSwgZ2R5IHptaWVubmEgJFgkIG1hIHdhcnRvxZtjaSB3eWJpZXJhbmUgZGV0ZXJtaW5pc3R5Y3puaWU6DQokJA0KUFxsZWZ0KE5fe2kxfSA9IG5fe2kxfSxOX3tpMn0gPSBuX3tpMn0sXGRvdHMsTl97aUp9ID0gbl97aUp9IFxyaWdodCk9IG5fe2krfSFccHJvZF97an1cZnJhY3tccGlfe2p8aX1ee25fe2lqfX19e25fe2lqfSF9LFxcDQpccGlfe2p8aX0gPSBcZnJhY3tcbXVfe2lqfX17XG11X3tpK319DQokJA0KDQojIyNCYWRhbmlhIGJpb21lZHljem5lDQo8aHR0cDovL3d3dy5hdXRob3JzdHJlYW0uY29tL1ByZXNlbnRhdGlvbi9wYW5zdHVkaW8tMTE3NjM4Mi1yb2R6YWplLWktbWV0b2R5a2EtYmFkYS1rbGluaWN6bnljaC8+DQoNCj5KYWsgdG8gc2nEmSB6YWN6xJnFgm8/OiBKUG8gSUkgV29qbmllIMWad2lhdG93ZWogdyBjemFzb3BpxZttaWUgQnJpdGlzaCBNZWRpY2FsIEpvdXJuYWwgdWthenVqZSBzacSZIHB1Ymxpa2FjamEgb3Bpc3VqxIVjYSB3eW5pa2kgeiBwaWVyd3N6ZWdvIGJhZGFuaWEga2xpbmljem5lZ28geiBsb3Nvd3ltIGRvYm9yZW0gcGFjamVudMOzdyBkbyBncnVwLiBKZXN0IHRvIHphcmF6ZW0gendpYXN0dW4gbm93b2N6ZXNuZWogYW50eWJpb3R5a290ZXJhcGlpLCBib3dpZW0gYmFkYW5pZSBkb3R5Y3p5IHNrdXRlY3pub8WbY2kgc3RyZXB0b215Y3lueSB3IGxlY3plbml1IGdydcW6bGljeS4gT3htYW4gQUQsIFNhY2tldHQgREwsIEd1eWF0dCBHSCAuIFVzZXJzJyBndWlkZXMgdG8gdGhlIG1lZGljYWwgbGl0ZXJhdHVyZS4gSS4gSG93IHRvIGdldCBzdGFydGVkLiBUaGUgRXZpZGVuY2UtQmFzZWQgTWVkaWNpbmUgV29ya2luZyBHcm91cCAuIEpBTUEgKCAxOTkzICk7IDI3MDogMjA5My01IC4NCg0KDQo+KipCYWRhbmlhIG9ic2Vyd2FjeWpuZSoqOiB0ZWdvIHJvZHphanUgYmFkYW5pYSBwcnplcHJvd2FkemEgc2nEmSBnxYLDs3duaWUgdyBjZWx1IG9jZW55IHN6a29kbGl3b8WbY2kgaSBhbmFsaXp5IGN6eW5uaWvDs3cgcm9rb3duaWN6eWNoOyBiYWRhbmlhIHRha2llIHJvYmkgc2nEmSB6IGJyYWt1IG1vxbxsaXdvxZtjaSB3eWtvbmFuaWEgYmFkYcWEIGVrc3BlcnltZW50YWxueWNoIHogcG93b2TDs3cgZXR5Y3pueWNoOyBkbGEgd2lhcnlnb2Rub8WbY2kgdHljaCB3eW5pa8OzdyBiYWRhxYQsIHBvZG9ibmllIGphayB3IHByenlwYWRrdSBiYWRhxYQgZWtzcGVyeW1lbnRhbG55Y2gsIHphc2FkbmljemUgem5hY3plbmllIG1hIHfFgmHFm2Npd2UgZG9icmFuaWUgZ3J1cHkga29udHJvbG5laiwgdGFrIGFieSBncnVweSByw7PFvG5pxYJ5IHNpxJkgdHlsa28gb2NlbmlhbsSFIGVrc3BvenljasSFOyB3IGJhZGFuaWFjaCBvYnNlcndhY3lqbnljaCDFgmF0d2llaiBwb3BlxYJuacSHIGLFgsSFZCBzeXN0ZW1hdHljem55Lg0KDQo+KipCYWRhbmlhIHByb3NwZWt0eXduZSAoa29ob3J0b3dlLCBjb2hvcnQgc3R1ZHkpKio6IG9jZW5pYSBzacSZIHByb3NwZWt0eXduaWUgd3lzdMSFcGllbmllIG9rcmXFm2xvbmVnbyBwdW5rdHUga2/FhGNvd2VnbyB3IGdydXBhY2ggKGtvaG9ydGFjaCkgb3PDs2IgbmFyYcW8b255Y2ggaSBuaWVuYXJhxbxvbnljaCBuYSBkYW55IGN6eW5uaWsgbHViIGludGVyd2VuY2rEmSwgbnAuOiBCYWRhbmllIHVtaWVyYWxub8WbY2kgendpxIV6YW5laiB6IHBhbGVuaWVtIHR5dG9uaXUg4oCTIDUwLWxldG5pZSBvYnNlcndhY2plIGxla2FyenkgYnJ5dHlqc2tpY2ggQk1KLiAyMDA0IDsgMzI4OiAxNTE5ICAgDQpQcnp5a8WCYWQgMQ0KDQohWyBdKGJhZGFuaWVfa29ob3J0b3dlLnBuZykNCg0KPioqQmFkYW5pYSByZXRyb3NwZWt0eXduZSAoYmFkYW5pZSBrbGluaWN6bm8ta29udHJvbG5lLCBjYXNlLWNvbnRyb2wgc3R1ZHkpKio6ICBwb3LDs3duYW5pZSBncnVweSBvc8OzYiB1IGt0w7NyeWNoIHB1bmt0IGtvxYRjb3d5IGp1xbwgd3lzdMSFcGnFgiAobnAuIG5vd290d8OzciksIHogZ3J1cMSFIGtvbnRyb2xuxIUgKG9zb2J5IHpkcm93ZSksIGEgbmFzdMSZcG5pZSBzcHJhd2R6YW15IGN6xJlzdG/Fm8SHIHd5c3TEmXBvd2FuaWEgamFraWVnb8WbIGN6eW5uaWthIHcgb2J1IGdydXBhY2ggKGthcnRhIGNob3JvYnksIGJhZGFuaWUgY2VjaCBnZW5ldHljem55Y2gsIGV0Yy4pLCBucC46IFXFvHl3YW5pZSB0ZWxlZm9udSBrb23Ds3Jrb3dlZ28gYSByeXp5a28gbm93b3R3b3LDs3cgbcOzemd1ICANClByenlrxYJhZCAzICANCg0KIVtdKGNhc2VfY29udHJvbC5wbmcpDQoNCj4qKkJhZGFuaWEgcHJ6ZWtyb2pvd2UgKGNyb3NzLXNlY3Rpb25hbCBzdHVkeSkqKiA6ICBXIGJhZGFuaWFjaCB0eWNoIG9jZW5pYSBzacSZIGNob3JvYm93b8WbxIcgbnAuIGxpY3piYSBjaG9yeWNoIG5hIGdydcW6bGljxJkgdyBQb2xzY2UgdyBkYW55bSBtb21lbmNpZS4gQmFkYW5pZSB0byBkYWplIGR1xbzEhSBuaWVwZXdub8WbxIcgY28gZG8gendpxIV6a8OzdyBwcnp5Y3p5bm8tc2t1dGtvd3ljaCBtacSZZHp5IGVrc3BvenljasSFLW9jZW5pYW55bSBjenlubmlraWVtLCBucC46IFJ5enlrbyBjaG9yb2J5IHpha3J6ZXBvd28temF0b3Jvd2VqIG9yYXogamVqIHByb2ZpbGFrdHlrYSB3IHdhcnVua2FjaCBvcGlla2kgc3pwaXRhbG5lai4gIA0KUHJ6eWvFgmFkIDINCg0KIVtdKHByemVrcm9qb3dlLnBuZykNCg0KIyMjI1ByenlrxYJhZCwgxbxlIGJhZGFuaWUgcmV0cm9zcGVrdHl3bmUgbmllIHBvendhbGEgb2NlbmnEhyB6d2nEhXprw7N3IHByb3NwZWt0eXdueWNoDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEuZnJhbWUoeD1jKDAsIDEpKSwgYWVzKHgpKSArIHN0YXRfZnVuY3Rpb24oZnVuPWZ1bmN0aW9uKHgpIDY4OCp4Lyg2ODgqeCs2NTAqKDEteCkpKSArDQogIGdlb21fYWJsaW5lKHNsb3BlID0gMSxpbnRlcmNlcHQgPSAwLGNvbD0iYmx1ZSIsbGluZXR5cGU9MikgKw0KICBsYWJzKHRpdGxlPSJQcmF3ZG9wb2RvYmllxYRzdHdvIHJha2EsIGdkeSBwYWNqZW50IHBhbGkiLHg9IlByYXdkb3BvZG9iaWXFhHN0d28gcmFrYSB3IHBvcHVsYWNqaSIseT0iUHJhd2RvcG9kb2JpZcWEc3R3byByYWthIGRsYSBwYWzEhWN5Y2giKQ0KYGBgDQoNCg0KIyMjI1RhYmxpY2UgYmluYXJuZQ0KDQojIyMjI1BhcmFtZXRyeSBvcGlzdWrEhWNlIHp3acSFemtpIHcgdGFibGljYWNoIGJpbmFybnljaA0KDQoNCiQkDQpccGlfMT1ccGlfezF8MX09XGZyYWN7XHBpX3sxMX19e1xwaV97MSt9fSBcXA0KXHBpXzI9XHBpX3sxfDJ9PVxmcmFje1xwaV97MTJ9fXtccGlfezIrfX0gXFwNCiQkDQoNCiogUsOzxbxuaWNhDQoqIFJ5enlrbyB3emdsxJlkbmUNCiogU3Rvc3VuZWsgc3phbnMNCiogSWxvcmF6IGtyennFvG93eSAgDQoNCiMjIyNSw7PFvG5pY2EgIA0KDQpSw7PFvG5pY2EgaSBlc3R5bWF0b3IgcsOzxbxuaWN5IHcgcHLDs2JhY2ggbyBsaWN6bm/Fm2NpICRuXzEkIGkgJG5fMiQgaSBsaWN6YmFtaSBzdWtjZXPDs1cgJG5fezExfSQgaSAkbl97MTJ9JA0KJCQNClxwaV8xIC0gXHBpXzIgXFwNClx3aWRlaGF0e1xwaV8xfT1cZnJhY3tuX3sxMX19e25fMX0sIFxxdWFkIFx3aWRlaGF0e1xwaV8yfT1cZnJhY3tuX3sxMn19e25fMn0gDQokJA0KT2RjaHlsZW5pZSBzdGFuZGFyZG93ZSByw7PFvG5pY3kNCiQkDQpcc2lnbWFcbGVmdCggXHdpZGVoYXR7XHBpXzF9IC0gXHdpZGVoYXR7XHBpXzJ9IFxyaWdodCkgPSANClxzcXJ0IHsgXGZyYWN7XHBpXzEoMS1ccGlfMSl9e25fMX0gKyBcZnJhY3tccGlfMigxLVxwaV8yKX17bl8yfX0NCiQkDQoNCiMjIyNSeXp5a28gd3pnbGVkbmUgIA0KDQokJA0KciA9IFxmcmFje1x3aWRlaGF0e1xwaV8xfX17XHdpZGVoYXR7XHBpXzJ9fSBcXA0KXHNpZ21hKFxsb2cocikpID0gXHNxcnR7XGZyYWN7MS1ccGlfMX17XHBpXzFuXzF9K1xmcmFjezEtXHBpXzJ9e1xwaV8ybl8yfX0NCiQkDQoNCiMjIyNJbG9yYXoga3J6ecW8b3d5DQoNCj4gSWxvcmF6IGtyennFvG93eT0xICRcaWZmJCBqZWRub3JvZG5vxZvEhy4gIA0KSWxvcmF6IGtyennFvG93eT0xICRcaWZmJCBuaWV6YWxlxbxub8WbxIcuDQoNCkVzdHltYXRvciBpbG9yYXp1IGtyennFvG93ZWdvICANCg0KSWxvcmF6IGtyennFvG93eSBkbGEgZG/Fm3dpYWRjemXFhCB0eXB5IF9jYXNlLWNvbnRyb2xfDQoNCioqUHJ6eWvFgmFkLiBfUmFrIGkgcGFsZW5pZV8qKg0KDQoNCnwgICAgICB8cmFrKyB8cmFrLXwNCnw6LS0tLTp8LS0tLTp8LS0tOnwNCnxwYWxpIFR8Njg4ICB8NjUwIHwNCnxwYWxpIE58MjEgICB8NTkgIHwNCg0KYGBge3IgdGFiZWxlIHBhcmFtZXRyb3d9DQpwaTEgPC0gcm91bmQoNjg4Lyg2ODgrNjUwKSxkaWdpdHM9NCkNCnBpMiA8LSByb3VuZCgyMS8oMjErNTkpLGRpZ2l0cz00KQ0KY2F0KCJcbiIsDQogICAgInJ5enlrbyByYWthIHfFm3LDs2QgcGFsxIVjeWNoICAgICAgICAgIixwaTEsIlxuIiwNCiAgICAicnl6eWtvIHJha2Egd8WbcsOzZCBuaWVwYWzEhWN5Y2ggICAgICAiLHBpMiwiXG4iLA0KICAgICJyw7PFvG5pY2Egcnl6eWsgZGxhIHBhbMSFY3ljaCAgICAgICAgICIscGkxLXBpMiwiXG4iLA0KICAgICJyeXp5a28gd3pnbMSZZG5lICAgICAgICAgICAgICAgICAgICAiLHJvdW5kKHBpMS9waTIsZGlnaXRzPTQpLCJcbiIsDQogICAgInN0b3N1bmVrIHN6YW5zIHJha2EgZGxhIHBhbMSFY3ljaCAgICIscm91bmQocGkxLygxLXBpMSksZGlnaXRzPTQpLCJcbiIsDQogICAgInN0b3N1bmVrIHN6YW5zIHJha2EgZGxhIG5pZXBhbMSFY3ljaCIscm91bmQocGkyLygxLXBpMiksZGlnaXRzPTQpLCJcbiIsDQogICAgImlsb3JheiBrcnp5xbxvd3kgICAgICAgICAgICAgICAgICAgICIsIHJvdW5kKHBpMSooMS1waTIpL3BpMi8oMS1waTEpLGRpZ2l0cz00KSwgIlxuIg0KICAgICkNCmBgYA0KDQoqKlByenlrxYJhZCoqDQpgYGB7ciByeXp5a28gd3pnbGVkbmV9DQphMSA8LSAwLjQxMDsgYTIgPC0gMC40MDENCmIxIDwtIDAuMDEwOyBiMiA8LSAwLjAwMQ0KYyhhMS1hMixiMS1iMikNCmMoYTEvYTIsYjEvYjIpDQoNCmBgYA0KDQpTdG9zdW5layBzemFucyBkbGEgcGFsZW5pYSBfd3lzdMSZcG93YW5pZSByYWthXw0KJCQgDQpcZnJhYyB7UChYXzF8WV8xKX17UChYXzJ8WV8xKX09XGZyYWN7XGZyYWN7XHBpX3sxMX19e1xwaV97KzF9fX17XGZyYWN7XHBpX3syMX19e1xwaV97KzF9fX09XGZyYWN7XHBpX3sxMX19e1xwaV97MjF9fQ0KJCQNCg0KU3Rvc3VuZWsgc3phbnMgZGxhIHBhbGVuaWEgX25pZXd5c3TEmXBvd2FuaWUgcmFrYV8NCiQkIA0KXGZyYWMge1AoWF8xfFlfMil9e1AoWF8yfFlfMil9PVxmcmFje1xmcmFje1xwaV97MTJ9fXtccGlfeysyfX19e1xmcmFje1xwaV97MjJ9fXtccGlfeysyfX19PVxmcmFje1xwaV97MTJ9fXtccGlfezIyfX0NCiQkDQoNCj4gTmllcG90cnplYm5hIGplc3Qgem5ham9tb8WbxIcgJFxwaV97KzF9JCAtIHByYXdkb3BvZG9iaWXFhHN0d2EgemFjaG9yb3dhbmlhIG5hIHJha2EhDQoNCkVzdHltYXRvcnkgaWxvcmF6w7N3IHN6YW5zIA0KYGBge3IgaWxvcmF6eSBzemFucyByYWsgaSBwYWxlbmllfQ0KYyg2ODgvMjEsNjUwLzU5KQ0KYGBgDQoNCkdkeWJ5xZtteSBtaWVsaSB3IHByw7NiaWUgcGnEmWNpb2tyb3RuaWUgbW5pZWpzesSFIGdydXDEmSB6IG9zw7NiIG5pZSBtYWrEhWN5Y2ggcmFrYSAoeiB6YWNob3dhbnltaSBwcm9wb3JjamFtaSkNCg0KDQp8ICAgICAgfHJhaysgfHJhay18DQp8Oi0tLS06fC0tLS06fC0tLTp8DQp8cGFsaSBUfDY4OCAgfDEzMCB8DQp8cGFsaSBOfDIxICAgfDEyICB8DQoNCg0KRXN0eW1hdG9yeSBpbG9yYXrDs3cgc3phbnMgDQpgYGB7ciBpbG9yYXp5IHN6YW5zIHJhayBpIHBhbGVuaWUgMn0NCmMoNjg4LzIxLDEzMC8xMikNCmBgYA0KSWxvcmF6eSBrcnp5xbxvd2UgdyBvYnUgcHJ6eXBhZGthY2guDQpgYGB7ciBpbG9yYXoga3J6ecW8b3d5IHJhayBpIHBhbGVuaWV9DQo2ODgqNTkvKDY1MCoyMSkNCjY4OCoxMi8oMTMwKjIxKQ0KDQpgYGANCg0KPiBNb8W8bmEgZG93b2xuaWUgc3Rlcm93YcSHIGxpY3pixIUgb3PDs2IgdyBwcsOzYmllLiAgIA0KSmXFvGVsaSBqZXN0IHJlcHJlemVudGF0eXduYSwgYSB3acSZYyB6YWNob3dhxYJ5IHNpxJkgcHJvcG9yY2plLCB0byBzdG9zdW5raSBzemFucyBpIGlsb2N6eW55IGtyennFvG93ZSBuaWUgem1pZW5pxIUgc2nEmS4NCg0KKipQcnplZHppYcWCeSB1Zm5vxZtjaSBkbGEgaWxvcmF6dSBrcnp5xbxvd2VnbyoqDQoNCiQkDQpPUj1cZnJhY3tuX3sxMX0qbl97MjJ9fXtuX3sxMn0qbl97MjF9fSBcXA0KT1I9IFxmcmFjeyhuX3sxMX0rMC41KSoobl97MjJ9KzAuNSl9eyhuX3sxMn0rMC41KSoobl97MjF9KzAuNSl9IFxcDQpcc2lnbWEoXGxvZyhPUikpID0gDQpcc3FydHtcZnJhY3sxfXtuX3sxMX19K1xmcmFjezF9e25fezEyfX0rXGZyYWN7MX17bl97MjF9fStcZnJhY3sxfXtuX3syMn19fQ0KJCQNCg0KYGBge3IgT1IgcHJ6ZWR6aWFsIHVmbm9zY2l9DQpvZGRzcmF0aW9XYWxkLnByb2MgPC0gZnVuY3Rpb24objAwLCBuMDEsIG4xMCwgbjExLCBhbHBoYSA9IDAuMDUpew0KICAjDQogICMgIENvbXB1dGUgdGhlIG9kZHMgcmF0aW8gYmV0d2VlbiB0d28gYmluYXJ5IHZhcmlhYmxlcywgeCBhbmQgeSwNCiAgIyAgYXMgZGVmaW5lZCBieSB0aGUgZm91ciBudW1iZXJzIG5pajoNCiAgIw0KICAjICAgIG4wMCA9IG51bWJlciBvZiBjYXNlcyB3aGVyZSB4ID0gMCBhbmQgeSA9IDANCiAgIyAgICBuMDEgPSBudW1iZXIgb2YgY2FzZXMgd2hlcmUgeCA9IDAgYW5kIHkgPSAxDQogICMgICAgbjEwID0gbnVtYmVyIG9mIGNhc2VzIHdoZXJlIHggPSAxIGFuZCB5ID0gMA0KICAjICAgIG4xMSA9IG51bWJlciBvZiBjYXNlcyB3aGVyZSB4ID0gMSBhbmQgeSA9IDENCiAgIw0KICBPUiA8LSAobjAwICogbjExKS8objAxICogbjEwKQ0KICAjDQogICMgIENvbXB1dGUgdGhlIFdhbGQgY29uZmlkZW5jZSBpbnRlcnZhbHM6DQogICMNCiAgc2lnbG9nIDwtIHNxcnQoKDEvbjAwKSArICgxL24wMSkgKyAoMS9uMTApICsgKDEvbjExKSkNCiAgemFscGggPC0gcW5vcm0oMSAtIGFscGhhLzIpDQogIGxvZ09SIDwtIGxvZyhPUikNCiAgbG9nbG8gPC0gbG9nT1IgLSB6YWxwaCAqIHNpZ2xvZw0KICBsb2doaSA8LSBsb2dPUiArIHphbHBoICogc2lnbG9nDQogICMNCiAgT1JsbyA8LSBleHAobG9nbG8pDQogIE9SaGkgPC0gZXhwKGxvZ2hpKQ0KICAjDQogIG9mcmFtZSA8LSBkYXRhLmZyYW1lKExvd2VyQ0kgPSBPUmxvLCBPUiA9IE9SLCBVcHBlckNJID0gT1JoaSwgYWxwaGEgPSBhbHBoYSkNCiAgb2ZyYW1lDQp9DQpgYGANCg0KUHJ6eWvFgmFkIHJhayBpIHBhbGVuaWUNCmBgYHtyIHB1IGRsYSBwYWxlbmlhfQ0Kb2Rkc3JhdGlvV2FsZC5wcm9jKDY4OCw2NTAsMjEsNTkpDQpgYGANCg0KKipQcnp5a8WCYWQgMSoqIF9QaHlzaWNpYW5zIEhlYWx0aCBTdHVkeV8gKGNob3JvYmEgd2llxYRjb3dhIHNlcmNhKSAgDQoNCnwgICAgICAgIHxzaWxueXx6d3lrxYJ5fGJyYWt8cmF6ZW18DQp8Oi0tLS0tLTp8LS0tLTp8LS0tLS06fC0tLS06fC0tLS06fA0KfCBwbGFjZWJvfCAgIDE4fCAgIDE3MXwxMDg0NXwxMTAzNHwNCnxhc3BpcnluYXwgICAgNXwgICAgOTl8MTA5MzN8MTEwMzd8DQoNClBvIHBvxYLEhWN6ZW5pdSBkd8OzY2gga29sdW1uIG90cnp5bWFteSB0YWJlbMSZIGJpbmFybsSFICANCg0KDQp8ICAgICAgICB8Y2hvcm9iYXwgYnJha3xyYXplbXwNCnw6LS0tLS0tOnwtLS0tLS06fC0tLS06fC0tLS06fA0KfCBwbGFjZWJvfCAgICAxODl8MTA4NDV8MTEwMzR8DQp8YXNwaXJ5bmF8ICAgIDEwNHwxMDkzM3wxMTAzN3wNCg0KYGBge3IgdGFiZWxlIHBhcmFtZXRyb3cgYXNwaXJ5bmF9DQpwaTEgPC0gcm91bmQoMTg5LygxODkrMTA4NDUpLGRpZ2l0cz00KQ0KcGkyIDwtIHJvdW5kKDEwNC8oMTA0KzEwOTMzKSxkaWdpdHM9NCkNCmNhdCgiXG4iLA0KICAgICJyeXp5a28gY2hvcm9ieSB3xZtyw7NkIHBsYWNlYm8gICAgICAgIixwaTEsIlxuIiwNCiAgICAicnl6eWtvIGNob3JvYnkgd8WbcsOzZCBhc3BpcnluYSAgICAgICIscGkyLCJcbiIsDQogICAgInLDs8W8bmljYSByeXp5ayBkbGEgcGxhY2VibyAgICAgICAgICAiLHBpMS1waTIsIlxuIiwNCiAgICAicnl6eWtvIHd6Z2zEmWRuZSAgICAgICAgICAgICAgICAgICAgIixyb3VuZChwaTEvcGkyLGRpZ2l0cz00KSwiXG4iLA0KICAgICJzdG9zdW5layBzemFucyBjaG9yb2J5IGRsYSBwbGFjZWJvICIscm91bmQocGkxLygxLXBpMSksZGlnaXRzPTQpLCJcbiIsDQogICAgInN0b3N1bmVrIHN6YW5zIGNob3JvYnkgZGxhIGFzcGlyeW55Iixyb3VuZChwaTIvKDEtcGkyKSxkaWdpdHM9NCksIlxuIiwNCiAgICAiaWxvcmF6IGtyennFvG93eSAgICAgICAgICAgICAgICAgICAgIiwgcm91bmQocGkxKigxLXBpMikvcGkyLygxLXBpMSksZGlnaXRzPTQpLCAiXG4iDQogICAgKQ0KYGBgDQoNCj4gR2R5IHJ5enlrbyB6ZGFyemVuaWEgbWHFgmUgKHcgb2J1IHByenlwYWRrYWNoKSB0byByeXp5a28gd3pnbMSZZG5lID0gaWxvcmF6IGtyennFvG93eQ0KDQojIyMjUHJ6ZWR6aWHFgnkgdWZub8WbY2kgZGxhIHLDs8W8bnljaCBzdGF0eXN0eWsNCg0KKipQcnp5a8WCYWQgMSoqIF9QaHlzaWNpYW5zIEhlYWx0aCBTdHVkeV8gDQoNCmBgYHtyIHByemVkemlhxYJ5IHVmbm/Fm2NpIGRsYSBzdGF0eXN0eWsgdyB0YWJsaWN6YWNoIGJpbmFybnljaH0NCm4xIDwtIDE4OSsxMDg0NQ0KbjIgPC0gMTA0KzEwOTMzDQpyb3puaWNhIDwtIHBpMS1waTIgICsgYygtMSwxKSoxLjk2KnNxcnQocGkxKigxLXBpMSkvbjEgKyBwaTIqKDEtcGkyKS9uMikNCnN0b3N1bmVrIDwtIGxvZyhwaTEvcGkyKSArIGMoLTEsMSkqMS45NipzcXJ0KCgxLXBpMSkvcGkxL24xKygxLXBpMikvcGkyL24yKQ0Kc3Rvc3VuZWsgPC0gZXhwKHN0b3N1bmVrKQ0KT1IgPC0gb2Rkc3JhdGlvV2FsZC5wcm9jKDE4OSwxMDg0NSwxMDQsMTA5MzMpDQpPUnB1IDwtIGMoT1IkTG93ZXJDSSxPUiRVcHBlckNJKQ0KY2F0KCJcbiIsDQogICAgInLDs8W8bmljYSByeXp5ayBkbGEgcGxhY2VibyAgICAgICAgICAiLHJvdW5kKHJvem5pY2EsZGlnaXRzPTQpLCJcbiIsDQogICAgInJ5enlrbyB3emdsxJlkbmUgICAgICAgICAgICAgICAgICAgICIscm91bmQoc3Rvc3VuZWssZGlnaXRzPTQpLCJcbiIsDQogICAgImlsb3JheiBrcnp5xbxvd3kgICAgICAgICAgICAgICAgICAgICIscm91bmQoT1JwdSxkaWdpdHM9NCksICJcbiINCiAgICApDQpgYGANCg0KIyMjI1Jlc3p0eSBQZWFyc29uYSBkbGEgdGFibGljIGtvbnR5bmdlbmNqaQ0KDQokJA0KXGNoaV4yX3soSS0xKShKLTEpfSBcXA0KViA9IFxzcXJ0e1xmcmFje1xjaGleMn17bihcbWluKEksSiktMSl9fSBcXA0KcF97aSt9ID0gXGZyYWN7bl97aSt9fXtufSBccXVhZCBwX3sran0gPSBcZnJhY3tuX3sran19e259IFxcDQpcd2lkZWhhdHtcbXVfe2lqfX09XGZyYWN7bl97aSt9IG5feytqfX17bn0gXFwNCmVfe2lqfT1cZnJhY3tuX3tpan0tXHdpZGVoYXR7XG11X3tpan19fXtcc3FydHtcd2lkZWhhdHtcbXVfe2lqfX19fSBcXA0Kcl97aWp9ID0gXGZyYWN7ZV97aWp9fXtcc3FydHsoMS1wX3tpK30pKDEtcF97K2p9KX19IA0KJCQNCg0KKipQcnp5a8WCYWQgMSoqIF9QaHlzaWNpYW5zIEhlYWx0aCBTdHVkeV8gDQoNCg0KfCAgICAgICAgfHNpbG55fHp3eWvFgnl8YnJha3xyYXplbXwNCnw6LS0tLS0tOnwtLS0tOnwtLS0tLTp8LS0tLTp8LS0tLTp8DQp8IHBsYWNlYm98ICAgMTh8ICAgMTcxfDEwODQ1fCoqMTEwMzQqKnwNCnxhc3BpcnluYXwgICAgNXwgICAgOTl8MTA5MzN8KioxMTAzNyoqfA0KfCAgKipyYXplbSoqfCAgICoqMjMqKnwgICAqKjI3MCoqfCoqMjE3NzgqKnwqKjIyMDcxKip8DQoNCmBgYHtyIHRlc3QgY2hpfQ0KcGhzIDwtIG1hdHJpeChjKDE4LDE3MSwxMDg0NSw1LDk5LDEwOTMzKSxucm93ID0gMixuY29sID0gMyxieXJvdyA9IFRSVUUsDQogICAgICAgICAgICAgIGRpbW5hbWVzPWxpc3QoYygicGxhY2VibyIsImFzcGlyeW5hIiksYygic2lsbnkiLCJ6d3lrxYJ5IiwiYnJhayIpKSkNCmN0IDwtIGNoaXNxLnRlc3QocGhzKQ0KY3Qkc3RhdGlzdGljDQpjYXQoIlxuIiwiViA9ICIsc3FydChjdCRzdGF0aXN0aWMvMjIwNzEpLCJcbiIsDQoicC12YWx1ZSA9ICIsY3QkcC52YWx1ZSwiXG4iKQ0KIyBtaWojDQpjdCRleHBlY3RlZA0KIyBlaWoNCmN0JHJlc2lkdWFscw0KIyByaWoNCmN0JHN0ZHJlcw0KDQpgYGANCg0KIyNEaWFnbm96eSBtZWR5Y3puZS4gS3J6eXdhIFJPQw0KDQojIyMjUHJ6eWvFgmFkIF9weWxpY2FfICANCkZFVjEgJSBub3JtYWxuZWogcG9qZW1ub3NjaSBwxYJ1YyBza29yeWdvd2FuZWogZGxhIHdpZWt1IGkgd3pyb3N0dQ0KcHlsaWNhIC0gIisiIHd5c3TEmXB1amUsICItICIgYnJhayAgDQpbRGFuZTogUHlsaWNhIHUgZ8Ozcm5pa8OzdywgQ2FtcGJlbGwsIE1hY2hpbiwgX01lZGljYWwgU3RhdGlzdGljc18sIHN0ci40NF0NCmBgYHtyIGRhbmUgfQ0KRkVWMSA8LSBjKDQwLDQzLDQ3LDQ5LDUwLDUwLDUzLDU3LDU4LDU4LDU4LDYyLDY1LDY5LDcxLDczLDc0LDc1LDc1LDc3LDc4LDc5LDgwLDg3LDkwLDEwMCwxMDUsNjAsNjcsNzMsNzUsNzksODAsODMsODcsODksMTAwLDEwNSwxMDksMTE1KQ0KcHlsaWNhIDwtIGMocmVwKCIrIiwyNykscmVwKCItIiwxMykpDQpweWxpY2EgPC0gZGF0YS5mcmFtZShGRVYxPUZFVjEscHlsaWNhPXB5bGljYSkNCnB5bGljYQ0KYGBgDQoNCmBgYHtyIHZpb2xpbiBwbG90fQ0KcXBsb3QocHlsaWNhLCBGRVYxLCBkYXRhID0gcHlsaWNhLCBnZW9tID0gInZpb2xpbiIsIGZpbGwgPSBweWxpY2EpDQpxcGxvdChweWxpY2EsIEZFVjEsIGRhdGEgPSBweWxpY2EsIA0KICAgICAgZ2VvbT0gImJveHBsb3QiLCBmaWxsID0gcHlsaWNhKQ0KYGBgDQoNCkRpYWdub3phIG5hIHBvZHN0YXdpZSBGRVYxOiBvZCBraWVkeSB1em5hd2HEhyB3eXN0xIVwaWVuaWUgcHlsaWN5Pw0KV3Byb3dhZMW6bXkgZHdhIHR5cHkgZGlhZ25venk6ICANCkQ4MDogRkVWMTw9ODAgaSBEOTA6IEZFVjE8PTkwDQpgYGB7ciBkaWFnbm96eX0NCnB5bGljYSREODAgPC0gY2FzZV93aGVuKA0KICBGRVYxPD04MCB+ICIrIiwNCiAgVFJVRSB+ICItIg0KKQ0KcHlsaWNhJEQ4MCA8LSBhcy5mYWN0b3IocHlsaWNhJEQ4MCkNCnB5bGljYSREOTAgPC0gY2FzZV93aGVuKA0KICBGRVYxPD05MCB+ICIrIiwNCiAgVFJVRSB+ICItIg0KKQ0KcHlsaWNhJEQ5MCA8LSBhcy5mYWN0b3IocHlsaWNhJEQ5MCkNCnB5bGljYSRweWxpY2EgPC0gZmFjdG9yKHB5bGljYSRweWxpY2EsIGxldmVscz1yZXYobGV2ZWxzKHB5bGljYSRweWxpY2EpKSkNCnB5bGljYSREODAgPC0gZmFjdG9yKHB5bGljYSREODAsIGxldmVscz1yZXYobGV2ZWxzKHB5bGljYSREODApKSkNCnB5bGljYSREOTAgPC0gZmFjdG9yKHB5bGljYSREOTAsIGxldmVscz1yZXYobGV2ZWxzKHB5bGljYSREOTApKSkNCmBgYA0KVGFiZWxlIGtvbnR5bmdlbmNqaSANCmBgYHtyIEQ4MCBEOTB9DQp0ODAgPC0gdGFibGUocHlsaWNhJEQ4MCxweWxpY2EkcHlsaWNhLGRubj1saXN0KCJkaWFnbm96YSIsImNob3JvYmEiKSkNCnQ4MA0KdDkwIDwtIHRhYmxlKHB5bGljYSREOTAscHlsaWNhJHB5bGljYSxkbm49bGlzdCgiZGlhZ25vemEiLCJjaG9yb2JhIikpDQp0OTANCmBgYA0KDQojIyMjT2NlbmEgdGFiZWxpIGRpYWdub3N0eWN6bmVqDQoNCnwgfGNob3JvYmEgK3xjaG9yb2JhIC18IHwNCnw6LS06fDotLTp8Oi0tOnw6LS06fA0KfCoqZGlhZ25vemEgKyoqfFRQfEZQfERQfA0KfCoqZGlhZ25vemEgLSoqfEZOfFROfEROfA0KfCB8Q1B8Q058U3wNCg0KKipXc2thxbpuaWtpIG9jZW55IHRhYmxpY3kgZGlhZ25vc3R5Y3puZWoqKg0KJCQNClx0ZXh0e2N6dcWCb8WbxIc6fVxxdWFkIFRQUj1cZnJhY3tUUH17Q1B9XFwNClx0ZXh0e3NwZWN5Zmljem5vxZvEhzp9XHF1YWQgVE5SPVxmcmFje1ROfXtDTn1cXA0KRlBSPVxmcmFje0ZQfXtDTn09MS1UTlINCiQkDQoNCkRsYSBkaWFnbm96eSBEODAgaSBEOTANCmBgYHtyIHdza2F6bmlraX0NCnBhckQgPC0gZGF0YS5mcmFtZShUUFI9YygyMy8yNywyNS8yNyksVE5SPWMoNy8xMyw0LzEzKSxGUFI9Yyg2LzEzLDkvMTMpKQ0Kcm93bmFtZXMocGFyRCkgPC0gYygiRDgwIiwiRDkwIikNCnJvdW5kKHBhckQsZGlnaXRzPTMpDQpgYGANCg0KKipHbG9iYWxuZSBvY2VueSB0YWJsaWN5IGRpYWdub3N0eWN6bmVqKioNCiQkDQpcdGV4dHtkb2vFgmFkbm/Fm8SHOn1ccXVhZCBBQ0M9XGZyYWN7VFArVE59e1N9ICAgXFwNClx0ZXh0e2luZm9ybWF0eXdub8WbxIc6fSBccXVhZCBJTkY9VFBSLUZQUiAgXFwNClx0ZXh0e2tvcmVsYWNqYSBNYXR0aGV3c2F9IFxxdWFkIE1DQyA9IFxwaGk9XGZyYWN7VFAqVE4tRlAqRk59e1xzcXJ0e0RQKkROKkNQKkNOfX0NCiQkDQoNCj4gTmllY2ggJFg9MSQgZ2R5IGRpYWdub3phIGplc3QgIisiIGkgJFg9MCQgZ2R5IGRpYWdub3phIGplc3QgIi0iLiBQb2RvYm5pZSwgbmllY2ggJFk9MSQgZ2R5IGNob3JvYmEgamVzdCAiKyIgaSAkWT0wJCBnZHkgY2hvcm9iYSBqZXN0ICItIi4gV3RlZHkgd3Nww7PFgmN6eW5uaWsgJFxwaGkkIGplc3Qgd3Nww7PFgmN6eW5uaWtpZW0ga29yZWxhY2ppIG1pxJlkenkgJFgkIGkgJFkkLiBQb25hZHRvICR8XHBoaXwkIGplc3QgcsOzd25lIHN0YXR5c3R5Y2UgJFYkIENyYW1lcmEgZGxhIHRlc3Rvd2FuaWEgemFsZcW8bm/Fm2NpIG1pxJlkenkgJFgkIGkgJFkkLg0KDQpEbGEgZGlhZ25venkgRDgwIGkgRDkwDQpgYGB7ciBnbG9iYWxuZX0NCmdsb0QgPC0gZGF0YS5mcmFtZShBQ0M9YygoMjMrNykvNDAsKDI1KzQpLzQwKSxJTkY9cGFyRCRUUFItcGFyRCRGUFIsDQogICAgICAgICAgICAgICAgICAgTUNDPWMoKDIzKjctNio0KS9zcXJ0KDExKjI5KjEzKjI3KSwoNCoyNS00KjkpL3NxcnQoNiozNCoxMyoyNykpDQopDQpyb3duYW1lcyhnbG9EKSA8LSBjKCJEODAiLCJEOTAiKQ0Kcm91bmQoZ2xvRCxkaWdpdHM9MykNCmBgYA0KDQpKYWsgd3licmHEhyBuYWpsZXBzenkgcHLDs2cgZGlhZ25vc3R5Y3pueT8NCg0KYGBge3IgUk9DfQ0KcHlsaWNhJHB5bGljYTEgPC0gMi1hcy5udW1lcmljKHB5bGljYSRweWxpY2EpDQpnZ3JvYyA8LSBnZ3Bsb3QocHlsaWNhLCBhZXMobSA9LUZFVjEsIGQgPSBweWxpY2ExKSkgKyBnZW9tX3JvYygpK3N0eWxlX3JvYygpDQpnZ3JvYw0Kcm91bmQoY2FsY19hdWMoZ2dyb2MpLGRpZ2l0cz0yKQ0KcHJlZCA8LSBwcmVkaWN0aW9uKC1weWxpY2EkRkVWMSwyLWFzLm51bWVyaWMocHlsaWNhJHB5bGljYSkpDQpwZXJmIDwtIHBlcmZvcm1hbmNlKHByZWQsbWVhc3VyZT0idHByIiwgeC5tZWFzdXJlPSJmcHIiKQ0KcHJmZGYgPC0gZGF0YS5mcmFtZShjdXRvZmY9dW5saXN0KHBlcmZAYWxwaGEudmFsdWVzKSxmcHI9dW5saXN0KHBlcmZAeC52YWx1ZXMpLHRwcj11bmxpc3QocGVyZkB5LnZhbHVlcykpDQpwcmZkZiA8LSBjYmluZChwcmZkZixpbmY9cHJmZGYkdHByLXByZmRmJGZwcikNCnByZmRmDQpgYGANCg0KPiBOYWpsZXBzenkgcHVua3QgcG9kemlhxYJ1OiA3OA0KDQpgYGB7ciBkaWFnbm96YSA3OH0NCnB5bGljYSRENzggPC0gY2FzZV93aGVuKA0KICBweWxpY2EkRkVWMTw9NzggfiAiKyIsDQogIFRSVUUgfiAiLSINCikNCnB5bGljYSRENzggPC0gYXMuZmFjdG9yKHB5bGljYSRENzgpDQpweWxpY2EkRDc4IDwtIGZhY3RvcihweWxpY2EkRDc4LCBsZXZlbHM9cmV2KGxldmVscyhweWxpY2EkRDc4KSkpDQp0NzggPC0gdGFibGUocHlsaWNhJEQ3OCxweWxpY2EkcHlsaWNhLGRubj1saXN0KCJkaWFnbm96YSIsImNob3JvYmEiKSkNCnQ3OA0KYGBgDQoNCmBgYHtyIHd5bmlraSBuYWpsZXBzemVqIGRpYWdub3p5fQ0KcGFyRCA8LSBkYXRhLmZyYW1lKFRQUj1jKDIzLzI3LDI1LzI3LDIxLzI3KSxUTlI9Yyg3LzEzLDQvMTMsOS8xMyksRlBSPWMoNi8xMyw5LzEzLDQvMTMpKQ0Kcm93bmFtZXMocGFyRCkgPC0gYygiRDgwIiwiRDkwIiwiRDc4IikNCnJvdW5kKHBhckQsZGlnaXRzPTMpDQpnbG9EIDwtIGRhdGEuZnJhbWUoQUNDPWMoKDIzKzcpLzQwLCgyNSs0KS80MCwoMjErOSkvNDApLElORj1wYXJEJFRQUi1wYXJEJEZQUiwNCiAgICAgICAgICAgICAgICAgICBNQ0M9YygoMjMqNy02KjQpL3NxcnQoMTEqMjkqMTMqMjcpLCg0KjI1LTQqOSkvc3FydCg2KjM0KjEzKjI3KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAoOSoyMS00KjYpL3NxcnQoMjUqMTUqMTMqMjcpKQ0KKQ0Kcm93bmFtZXMoZ2xvRCkgPC0gYygiRDgwIiwiRDkwIiwiRDc4IikNCnJvdW5kKGdsb0QsZGlnaXRzPTMpDQpgYGANCg0KIyMjIERva8WCYWRueSB0ZXN0IEZpc2hlcmENCg0KPiBXIGFua2llY2llIHd6acSZxYJvIHVkemlhxYIgNSBrb2JpZXQgaSAxMCBtxJnFvGN6eXpuLiBOYSBweXRhbmllIG8gcG9wYXJjaWUgcGFydGlpIFhYIDMga29iaWV0eSBpIDUgbcSZxbxjenl6biBvZHBvd2llZHppYcWCeSBUQUsuIEN6eSBwb3BhcmNpZSBwYXJ0aWkgWFggamVzdCB3acSZa3N6ZSB1IGtvYmlldD8NCg0KVGFibGljYSBrb250eW5nZW5jamkNCmBgYHtyIHRrb250IEZpc2hlcn0NCnRmaXMgPC0gbWF0cml4KGMoMywyLDUsNSw1LDEwLDgsNywxNSksbnJvdz0zLG5jb2w9MyxieXJvdyA9IFRSVUUsZGltbmFtZXM9bGlzdChjKCJLIiwiTSIsInN1bWEiKSxjKCJUIiwiTiIsInN1bWEiKSkpDQp0ZmlzDQpgYGANClB5dGFuaWUgdG8gbW/FvG5hIHd5cmF6acSHIHcgasSZenlrdSB0ZXN0b3dhbmlhOg0KJCQNCkhfMDogXHRoZXRhPTEgIFxcDQpIXzE6IFx0aGV0YT4xDQokJA0KDQpMaWN6bm/Fm2NpIHcgdGFibGljeSBzxIUgdGFrIG1hxYJlLCDFvGUgcG9wcnplZG5pZSB0ZXN0eSwgamFrbyBhc3ltcHRvdHljem5lLCBzxIUgbmllYWRla3dhdG5lLiAgDQoqKlBvbXlzxYIgRklzaGVyYSoqDQoNCkdkeSAkSF8wJCBqZXN0IHByYXdkeml3YSB0byBwcmF3ZG9wb2RvYmllxYRzdHdvIHd5cHJvZHVrb3dhbmlhIHRhYmxpY3kga29udHluZ2VuY2ppDQoNCnwgICAgIHwgICAkeV8xJHwgICAkeV8yJHwNCnw6LS0tOnwtLS0tLS0tOnwtLS0tLS0tOnwNCnwkeF8xJHwkbl97MTF9JHwkbl97MTJ9JHwNCnwkeF8yJHwkbl97MjF9JHwkbl97MjJ9JHwNCg0KbyB1c3RhbG9ueWNoIHdhcnRvxZtjaWFjaCBicnplZ293eWNoICRuX3sxK30kLCAkbl97Mit9JCwgJG5feysxfSQsICRuX3srMn0kIHd5bm9zaQ0KJCQNClxmcmFje1xiaW5vbXtuX3srMX19e25fezExfX1cYmlub217bl97KzJ9fXtuX3sxMn19fXtcYmlub217bl97Kyt9fXtuX3srMX19fSA9IA0KXGZyYWN7bl97KzF9IVwsbl97KzJ9IVwsbl97MSt9IVwsbl97Mit9IX17bl97MTF9IVwsbl97MTJ9IVwsbl97MjF9IVwsbl97MjJ9IVwsbiF9DQokJA0KDQpgYGB7ciBmdW5rY2phIEZpc2hlcn0NCmZmaXNoZXIgPC0gZnVuY3Rpb24objExLG4xMixuMjEsbjIyLGN5ZnI9NCkgew0KICBuIDwtIG4xMStuMTIrbjIxK24yMg0KICBmZmYgPC0gZmFjdG9yaWFsKG4xMStuMTIpKmZhY3RvcmlhbChuMjErbjIyKSogZmFjdG9yaWFsKG4xMStuMjEpKmZhY3RvcmlhbChuMjIrbjEyKS8oDQogICAgZmFjdG9yaWFsKG4xMSkqZmFjdG9yaWFsKG4xMikqIGZhY3RvcmlhbChuMjEpKmZhY3RvcmlhbChuMjIpKmZhY3RvcmlhbChuKSANCiAgKQ0KICAgcm91bmQoZmZmLGRpZ2l0cz1jeWZyKQ0KfQ0KZmZpc2hlcigzLDIsNSw1KQ0KYGBgDQoNCldhcnVuZWsgJFx0aGV0YT4xJCBqZXN0IHLDs3dub3dhxbxueSB3YXJ1bmtvd2k6DQokJA0Kbl97MTF9Plx3aWRlaGF0e25fezExfX09XGZyYWN7bl97MSt9bl97KzF9fXtufQ0KJCQNCldhcnVuZWsgdGVuIHcgbmFzenltIHByenlrxYJhZHppZSBtYSBwb3N0YcSHDQoNCiQkDQpuX3sxMX0+XGZyYWN7NSo4fXsxNX09XGZyYWN7OH17M31cXA0Kbl97MTF9IFxnZXEgIDMNCiQkDQoNClByYXdkb3BvZG9iaWXFhHN0d28sIMW8ZSAkbl97MTF9IFxnZXEgMyQgamVzdCByw7N3bmUgc3VtaWUgcHJhd2RvcG9kb2JpZcWEc3R3IGRsYSAkbl97MTF9ID0gMyw0LDUkIGkgd3lub3NpDQpgYGB7ciBGaXNoZXIgcHZhbHVlfQ0KZmZpc2hlcigzLDIsNSw1KQ0KZmZpc2hlcig0LDEsNCw2KQ0KZmZpc2hlcig1LDAsMyw3KQ0KZmZpc2hlcigzLDIsNSw1KSArIGZmaXNoZXIoNCwxLDQsNikgKyBmZmlzaGVyKDUsMCwzLDcpDQpgYGANCg0KYGBge3J9DQpmaXNoZXIudGVzdCh0ZmlzWzE6MiwxOjJdLGFsdGVybmF0aXZlID0gImdyZWF0ZXIiKQ0KYGBgDQoNCiMjI1BvZHppYcWCIHRhYmxpY3kga29udHluZ2VuY2ppDQo8aHR0cHM6Ly9yc3R1ZGlvLXB1YnMtc3RhdGljLnMzLmFtYXpvbmF3cy5jb20vNjU0MzVfYThiMjY3NzNiNWQ2NDEzOGI2NDExYTVhYTMwNmE1YjkuaHRtbD4NCjxodHRwczovL2Nzcy5uY2lmY3JmLmdvdi9zZXJ2aWNlcy9hbHZvcmQvUl9UdXRvcmlhbF9QYXJ0aXRpb25fTFJfQ2hpLVNxdWFyZV9JeEpfQ29udGluZ2VuY3lfVGFibGUucGRmPg0KDQoqKkRhbmUqKg0KWzE5OTYgKFVTQSkgR2VuZXJhbCBTb2NpYWwgU3VydmV5LCBOYXRpb25hbCBPcGluaW9uIFJlc2VhcmNoIENlbnRlci5dICANCndpZXJzemU6IHd5a3N6dGHFgmNlbmllInBvZHN0YXdvd2UiLCLFm3JlZG5pZSIsInd5xbxzemUiICANCmtvbHVtbnk6IHN0b3N1bmVrIGRvIHJlbGlnaWkgImZ1bmRhbWVudGFsaXN0YSIsInVtaWFya293YW55IiwibGliZXJhbG55Ig0KYGBge3IgcmVsaWdpYSBkYW5lfQ0KcmVsLmRhdCA8LSBhcy50YWJsZShtYXRyaXgoYygxNzgsMTM4LDEwOCw1NzAsNjQ4LDQ0MiwxMzgsMjUyLDI1MiksbnJvdz0zLG5jb2w9MyxieXJvdz1UUlVFLGRpbW5hbWVzID0gbGlzdChlZHU9YygiUCIsIlMiLCJXIikscmVsPWMoIkYiLCJVIiwiTCIpKSkpDQphZGRtYXJnaW5zKHJlbC5kYXQpDQpgYGANCg0KWmFkYW5pZSBwb2xlZ2EgbmEgd3licmFuaXUgamVkbm9yb2RueWNoIHBvZG1hY2llcnp5LiAgDQpUd2llcmR6ZW5pZSBvIHN1bW93YW5pdSAgDQpXYXJ1bmtpIGRvYnJlZ28gcG9kemlhxYJ1ICANCg0KYGBge3IgcmVsaWdpYSB0ZXN0MX0NCnQxIDwtIGxvZ2xtKCB+IGVkdSArIHJlbCxkYXRhID0gcmVsLmRhdCkgDQp0MQ0KY2hpc3EudGVzdChyZWwuZGF0KSRzdGRyZXMNCmBgYA0KDQoNCmBgYHtyIHQyfQ0KdDIgPC0gYXMudGFibGUocmVsLmRhdFtjKDEsMiksYygyLDMpXSkNCnQyDQp0Mm0gPC0gbG9nbG0oIH4gZWR1ICsgcmVsLGRhdGEgPSB0MikgDQp0Mm0NCmNoaXNxLnRlc3QodDIpJHN0ZHJlcw0KYGBgDQoNCmBgYHtyIHQzfQ0KYXBwbHkodDIsMSxzdW0pDQp0MyA8LSBhcy50YWJsZShtYXRyaXgoYygyNDYsMTA5MCxjKDE3OCw1NzApKSxucm93PTIsbmNvbD0yLGRpbW5hbWVzID0gbGlzdChlZHU9YygiUCIsIlMiKSxyZWw9YygiVStMIiwiRiIpKSkpDQp0Mw0KdDNtIDwtIGxvZ2xtKCB+IGVkdSArIHJlbCxkYXRhID0gdDMpIA0KdDNtDQpjaGlzcS50ZXN0KHQzKSRzdGRyZXMNCmBgYA0KDQpgYGB7ciB0NH0NCmFwcGx5KHQyLDIsc3VtKQ0KdDQgPC0gYXMudGFibGUobWF0cml4KGMoNzg2LDI1MixjKDU1MCwyNTIpKSxucm93PTIsbmNvbD0yLGRpbW5hbWVzID0gbGlzdChlZHU9YygiUCtTIiwiVyIpLHJlbD1jKCJVIiwiTCIpKSkpDQp0NA0KdDRtIDwtIGxvZ2xtKCB+IGVkdSArIHJlbCxkYXRhID0gdDQpIA0KdDRtDQpjaGlzcS50ZXN0KHQ0KSRzdGRyZXMNCmBgYA0KDQpgYGB7ciB0NX0NCnN1bSh0MikNCnQ1IDwtIGFzLnRhYmxlKG1hdHJpeChjKDEzMzYsMjUyKzI1MixjKDE3OCs1NzAsMTM4KSksbnJvdz0yLG5jb2w9MixkaW1uYW1lcyA9IGxpc3QoZWR1PWMoIlArUyIsIlciKSxyZWw9YygiVStMIiwiRiIpKSkpDQp0NQ0KdDVtIDwtIGxvZ2xtKCB+IGVkdSArIHJlbCxkYXRhID0gdDUpIA0KdDVtDQpjaGlzcS50ZXN0KHQ1KSRzdGRyZXMNCmBgYA0K