Contesto Aziendale

Azienda: Neonatal Health Solutions Obiettivo: Creare un modello statistico in grado di prevedere con precisione il peso dei neonati alla nascita, basandosi su variabili cliniche raccolte da tre ospedali. Il progetto mira a migliorare la gestione delle gravidanze ad alto rischio, ottimizzare le risorse ospedaliere e garantire migliori risultati per la salute neonatale.

Il progetto si inserisce all’interno di un contesto di crescente attenzione verso la prevenzione delle complicazioni neonatali. La possibilità di prevedere il peso alla nascita dei neonati rappresenta un’opportunità fondamentale per migliorare la pianificazione clinica e ridurre i rischi associati a nascite problematiche, come parti prematuri o neonati con basso peso. Di seguito, i principali benefici che questo progetto porterà all’azienda e al settore sanitario:

1.Miglioramento delle previsioni cliniche:

2.Ottimizzazione delle risorse ospedaliere:

3.Prevenzione e identificazione dei fattori di rischio:

4.Valutazione delle pratiche ospedaliere:

5.Supporto alla pianificazione strategica:



1 - Raccolta dei Dati e Struttura del Dataset

Per costruire il modello predittivo, sono stati raccolti dati su 2500 neonati provenienti da tre ospedali. Le variabili raccolte includono:

L’obiettivo principale è identificare quali di queste variabili sono più predittive del peso alla nascita, con un focus particolare sull’impatto del fumo materno e delle settimane di gestazione, che potrebbero indicare nascite premature.


Esplorazione dati

Tabella- Indici di posizione, variabilità e asimmetria per variabili quantitative
Variabile Media Deviazione_Standard Coeff_Variazione Minimo Massimo Skewness Kurtosis
Anni.madre 28.16 5.27 0.19 0 46 0.04 3.38
N.gravidanze 0.98 1.28 1.31 0 12 2.51 13.99
Fumatrici 0.04 0.20 4.80 0 1 4.59 22.08
Gestazione 38.98 1.87 0.05 25 43 -2.07 11.26
Peso 3284.08 525.04 0.16 830 4930 -0.65 5.03
Lunghezza 494.69 26.32 0.05 310 565 -1.51 9.49
Cranio 340.03 16.43 0.05 235 390 -0.79 5.95


Analisi distribuzione delle variabili quantitative:

Anni.madre

N.gravidanze

Fumatrici

Gestazione

Peso

Lunghezza

Cranio

Sintesi



Ipotesi 1

in alcuni ospedali si fanno più parti cesarei

Step 1: Analizziamo prima la distribuzione dei tipi di parto tra parto naturale e parto cesareo

Step 2: Calcoliamo distribuzione dei tipi di parto tra parto naturale e parto cesareo tra ospedali

table(dati$Tipo.parto, dati$Ospedale)
     
      osp1 osp2 osp3
  Ces  242  254  232
  Nat  574  595  603

Step 3 Visualizziamo graficamente

Step 4 effettuiamo il test

# Parti cesarei per ospedale
chisq.test(table(dati$Tipo.parto, dati$Ospedale))

    Pearson's Chi-squared test

data:  table(dati$Tipo.parto, dati$Ospedale)
X-squared = 1.0972, df = 2, p-value = 0.5778

Commenti:

Il p-value è maggiore di 0.05, quindi non ci sono differenze statisticamente significative nella distribuzione dei tipi di parto tra gli ospedali. La scelta tra parto naturale e cesareo non sembra dipendere dall’ospedale in cui avviene l’evento per cui si rifiuta l’ipotesi.


Ipotesi 2

La media del peso e della lunghezza di questo campione di neonati sono significativamente uguali a quelle della popolazione

Step 1: Analizziamo la distribuzione delle variabili peso e lunghezza

Step 2: Effettuiamo un test di confronto delle variabili con le medie di riferimento della popolazione (con mu Peso=3300g e mu lunghezza=500cm)

# Test t per il peso
t.test(dati$Peso, mu = 3300)

    One Sample t-test

data:  dati$Peso
t = -1.516, df = 2499, p-value = 0.1296
alternative hypothesis: true mean is not equal to 3300
95 percent confidence interval:
 3263.490 3304.672
sample estimates:
mean of x 
 3284.081 
# Test t per la lunghezza con valore di riferimento (es. 500cm)
t.test(dati$Lunghezza, mu = 500)

    One Sample t-test

data:  dati$Lunghezza
t = -10.084, df = 2499, p-value < 2.2e-16
alternative hypothesis: true mean is not equal to 500
95 percent confidence interval:
 493.6598 495.7242
sample estimates:
mean of x 
  494.692 

Commenti:


Ipotesi 3

Le misure antropometriche sono significativamente diverse tra i due sessi

Step 1: Analizziamo la distribuzione M/F

Il grafico mostra una distribuzione delle osservazioni tra maschi e femmine quasi perfettamente bilanciata

Step 2: Analizziamo la distribuzione delle variabili peso e lunghezza

Step 3: Effettuiamo il test condizionato

# Peso
t.test(Peso ~ Sesso, data = dati)

    Welch Two Sample t-test

data:  Peso by Sesso
t = -12.106, df = 2490.7, p-value < 2.2e-16
alternative hypothesis: true difference in means between group F and group M is not equal to 0
95 percent confidence interval:
 -287.1051 -207.0615
sample estimates:
mean in group F mean in group M 
       3161.132        3408.215 
# Lunghezza
t.test(Lunghezza ~ Sesso, data = dati)

    Welch Two Sample t-test

data:  Lunghezza by Sesso
t = -9.582, df = 2459.3, p-value < 2.2e-16
alternative hypothesis: true difference in means between group F and group M is not equal to 0
95 percent confidence interval:
 -11.929470  -7.876273
sample estimates:
mean in group F mean in group M 
       489.7643        499.6672 
# Cranio
t.test(Cranio ~ Sesso, data = dati)

    Welch Two Sample t-test

data:  Cranio by Sesso
t = -7.4102, df = 2491.4, p-value = 1.718e-13
alternative hypothesis: true difference in means between group F and group M is not equal to 0
95 percent confidence interval:
 -6.089912 -3.541270
sample estimates:
mean in group F mean in group M 
       337.6330        342.4486 

Commenti:


Focus particolare sull’impatto del fumo materno sul peso e sulle settimane di gestazione, che potrebbero indicare nascite premature

L’obiettivo di questa analisi è verificare un eventuale correlazione e impatto tra il fumo e la nascita prematura dei neonati ed il relativo peso alla nascita.

t.test(Peso~ Fumatrici)

    Welch Two Sample t-test

data:  Peso by Fumatrici
t = 1.034, df = 114.1, p-value = 0.3033
alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
95 percent confidence interval:
 -45.61354 145.22674
sample estimates:
mean in group 0 mean in group 1 
       3286.153        3236.346 

Commenti:


2 - Creazione del Modello di Regressione


Step 1 Analisi delle correlazioni tra le variabili quantitative

round(cor(variabili),2)
             Anni.madre N.gravidanze Fumatrici Gestazione  Peso Lunghezza Cranio
Anni.madre         1.00         0.38      0.01      -0.14 -0.02     -0.06   0.02
N.gravidanze       0.38         1.00      0.05      -0.10  0.00     -0.06   0.04
Fumatrici          0.01         0.05      1.00       0.03 -0.02     -0.02  -0.01
Gestazione        -0.14        -0.10      0.03       1.00  0.59      0.62   0.46
Peso              -0.02         0.00     -0.02       0.59  1.00      0.80   0.70
Lunghezza         -0.06        -0.06     -0.02       0.62  0.80      1.00   0.60
Cranio             0.02         0.04     -0.01       0.46  0.70      0.60   1.00

Matrice di correlazione tra tutte le variabili

Osservazioni sulla matrice

  • Correlazioni forti:
    • Peso vs Sesso:: i neaonati maschi pesano mediamente di più delle femmine
    • Peso Vs Gestazione: 0.59 la durata della gravidanza incide significativamente sul peso alla nascita
    • Peso vs Lunghezza: 0.80 → fortissima correlazione positiva. Più lungo è il neonato, maggiore è il peso
    • Peso vs Cranio::0.70 anche la circonferenza cranica è fortemente associata al peso
    • Gestazione vs Lunghezza:: 0.62 più lunga è la gestazione, maggiore è la lunghezza del neonato
  • Correlazioni deboli o nulle:
    • Fumatrici vs tutte le altre: valori vicini a 0 (es. −0.02, 0.03) → il fumo materno non mostra una correlazione forte con le variabili neonatali in questo dataset
  • Correlazioni negative:
    • Anni.madre vs Gestazione: leggerissima tendenza: madri più anziane potrebbero avere gestazioni leggermente più brevi
    • Gestazione vs N.gravidanze: più gravidanze sembrano associate a gestazioni leggermente più brevi

Creazione del primo modello di regressione lineare multipla con tutte le variabili (Mod1)

# Mod1= Modello completo
mod1 <- lm(Peso ~ ., data = dati)

summary(mod1)

Call:
lm(formula = Peso ~ ., data = dati)

Residuals:
     Min       1Q   Median       3Q      Max 
-1124.40  -181.66   -14.42   160.91  2611.89 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)   -6738.4762   141.3087 -47.686  < 2e-16 ***
Anni.madre        0.8921     1.1323   0.788   0.4308    
N.gravidanze     11.2665     4.6608   2.417   0.0157 *  
Fumatrici       -30.1631    27.5386  -1.095   0.2735    
Gestazione       32.5696     3.8187   8.529  < 2e-16 ***
Lunghezza        10.2945     0.3007  34.236  < 2e-16 ***
Cranio           10.4707     0.4260  24.578  < 2e-16 ***
Tipo.partoNat    29.5254    12.0844   2.443   0.0146 *  
Ospedaleosp2    -11.2095    13.4379  -0.834   0.4043    
Ospedaleosp3     28.0958    13.4957   2.082   0.0375 *  
SessoM           77.5409    11.1776   6.937 5.08e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 273.9 on 2489 degrees of freedom
Multiple R-squared:  0.7289,    Adjusted R-squared:  0.7278 
F-statistic: 669.2 on 10 and 2489 DF,  p-value: < 2.2e-16

Creazione di un secondo modello ottimizzato di regressione lineare multipla con le variabili escludendo le variabili poco significative come Fumatrici e Ospedale (Mod2)

# Mod2= Modello ottimizzato
mod2 <- update(mod1,~ .- Ospedale - Fumatrici)
summary(mod2)

Call:
lm(formula = Peso ~ Anni.madre + N.gravidanze + Gestazione + 
    Lunghezza + Cranio + Tipo.parto + Sesso, data = dati)

Residuals:
     Min       1Q   Median       3Q      Max 
-1140.63  -181.17   -15.31   160.36  2633.22 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)   -6740.2053   141.4004 -47.668  < 2e-16 ***
Anni.madre        0.9637     1.1336   0.850   0.3953    
N.gravidanze     11.3062     4.6600   2.426   0.0153 *  
Gestazione       32.6164     3.8160   8.547  < 2e-16 ***
Lunghezza        10.2865     0.3007  34.205  < 2e-16 ***
Cranio           10.4874     0.4266  24.583  < 2e-16 ***
Tipo.partoNat    30.0205    12.0976   2.482   0.0131 *  
SessoM           77.8423    11.1916   6.955 4.48e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 274.3 on 2492 degrees of freedom
Multiple R-squared:  0.7278,    Adjusted R-squared:  0.727 
F-statistic: 951.6 on 7 and 2492 DF,  p-value: < 2.2e-16

Creazione di un terzo modello ancora più parsimonioso, con il principio del Rasoio di Occam, di regressione lineare multipla escludendo un ulteriorie variabili come il tipo parto (Mod3)

mod3 <- update(mod2,~ .- Tipo.parto)
summary(mod3)

Call:
lm(formula = Peso ~ Anni.madre + N.gravidanze + Gestazione + 
    Lunghezza + Cranio + Sesso, data = dati)

Residuals:
     Min       1Q   Median       3Q      Max 
-1160.80  -181.84   -14.91   164.28  2634.06 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -6714.1927   141.1571 -47.565  < 2e-16 ***
Anni.madre       0.9674     1.1347   0.853   0.3940    
N.gravidanze    11.0199     4.6634   2.363   0.0182 *  
Gestazione      32.6784     3.8198   8.555  < 2e-16 ***
Lunghezza       10.2486     0.3006  34.088  < 2e-16 ***
Cranio          10.5218     0.4268  24.652  < 2e-16 ***
SessoM          77.9061    11.2032   6.954 4.52e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 274.6 on 2493 degrees of freedom
Multiple R-squared:  0.7271,    Adjusted R-squared:  0.7264 
F-statistic:  1107 on 6 and 2493 DF,  p-value: < 2.2e-16

3 - Selezione del Modello di Regressione migliore


Per selezionare il modello migliore vengono messi a confronto i tre modelli con la tecnica di Bayes (BIC), applicando ANOVA e VIF

anova(mod3,mod1)
Analysis of Variance Table

Model 1: Peso ~ Anni.madre + N.gravidanze + Gestazione + Lunghezza + Cranio + 
    Sesso
Model 2: Peso ~ Anni.madre + N.gravidanze + Fumatrici + Gestazione + Lunghezza + 
    Cranio + Tipo.parto + Ospedale + Sesso
  Res.Df       RSS Df Sum of Sq      F   Pr(>F)   
1   2493 188010731                                
2   2489 186762521  4   1248209 4.1587 0.002325 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

vif<5

vif(mod3)
  Anni.madre N.gravidanze   Gestazione    Lunghezza       Cranio        Sesso 
    1.186622     1.181758     1.688288     2.074689     1.628621     1.040140 

Commenti:

mod3 risulta il modello ottimale secondo il BIC: più semplice (7 parametri) e con il miglior equilibrio tra complessità e adattamento.

In termini di selezione di variabili, significa che togliere ulteriori predittori rispetto a mod2 ha reso il modello ancora più parsimonioso senza peggiorare la capacità di spiegare i dati.



4- Analisi della qualità del Modello di Regressione selezionato


Analisi dei residui

shapiro.test(residuals(mod3))

    Shapiro-Wilk normality test

data:  residuals(mod3)
W = 0.97413, p-value < 2.2e-16

#leverage
lev<-hatvalues(mod3)
plot(lev)
p<-sum(lev)
n<-length(lev)
soglia=2*p/n
abline(h=soglia,col=2)
lev[lev>soglia]
         13          15          34          61          67          70          89          96         101         106 
0.005684347 0.007060519 0.006747369 0.005664249 0.005895931 0.005612823 0.012966743 0.006042837 0.007745118 0.015033667 
        131         134         151         155         161         189         190         204         205         206 
0.007338390 0.007583673 0.011289124 0.007304937 0.020643649 0.005798343 0.005740905 0.015669489 0.008732982 0.010786029 
        220         230         260         294         304         305         310         312         335         378 
0.007859452 0.006505071 0.006048045 0.005915388 0.006144441 0.006963312 0.029108905 0.013381509 0.006554957 0.016026324 
        408         411         442         445         446         486         492         516         582         587 
0.006110755 0.005792516 0.007732411 0.007533035 0.005739232 0.005824264 0.008433653 0.013092597 0.012822336 0.011877860 
        592         638         656         684         697         748         750         757         765         805 
0.006385723 0.006854179 0.006954864 0.008833096 0.006154282 0.009502586 0.007088886 0.008923975 0.006294047 0.014420805 
        828         855         928         946         947         951         956         985        1014        1067 
0.007398786 0.006178106 0.023008513 0.006910812 0.008432363 0.006175882 0.007786248 0.008445882 0.010011594 0.009364299 
       1072        1075        1091        1096        1106        1130        1152        1166        1181        1188 
0.005805811 0.006181114 0.008945797 0.006116493 0.007866262 0.033179618 0.014053872 0.006026149 0.005677759 0.006901542 
       1194        1200        1219        1238        1248        1273        1291        1293        1311        1321 
0.005895406 0.005870628 0.031495526 0.007417126 0.014903156 0.007179160 0.006450744 0.006168427 0.009802029 0.009293849 
       1323        1357        1380        1385        1400        1411        1428        1429        1450        1505 
0.007113784 0.007677691 0.013304831 0.012869661 0.006544304 0.008339480 0.008241753 0.024434421 0.015169586 0.014596639 
       1551        1553        1556        1560        1593        1610        1619        1686        1692        1701 
0.049353528 0.008845028 0.008277042 0.006092914 0.007010111 0.009082760 0.015189307 0.009416569 0.007069515 0.011563400 
       1712        1718        1727        1735        1780        1781        1806        1809        1827        1962 
0.007069180 0.007092916 0.013525504 0.007569348 0.026634410 0.017423335 0.006322689 0.009556466 0.006147505 0.005965789 
       1967        1977        2026        2037        2040        2086        2089        2098        2114        2115 
0.005994098 0.007252882 0.006354152 0.006435075 0.011554118 0.015940304 0.006389663 0.006593767 0.014361960 0.012189225 
       2120        2140        2146        2148        2149        2157        2175        2200        2216        2220 
0.018762407 0.006256453 0.005838802 0.008144160 0.014148145 0.006125118 0.032750743 0.011932710 0.008943401 0.006252941 
       2221        2224        2244        2257        2307        2317        2318        2359        2408        2422 
0.022368287 0.007961185 0.006944292 0.008765853 0.014264552 0.009747025 0.006030803 0.012649781 0.010185054 0.022811910 
       2437        2452        2458        2471        2478 
0.024108318 0.023876497 0.008593048 0.022057423 0.005844481 


# R² e RMSE

pred <- predict(mod3)
rmse(dati$Peso, pred)

Commenti sulla qualità del modello:

  • Il modello mod3 presenta residui quasi normali, con qualche deviazione alle code.

  • La violazione della normalità è confermata dal test, ma non così grave mostrate nei grafici.

  • La eteroscedasticità è lieve.

  • Alcuni outlier/influential points meritano attenzione, ma non invalidano il modello

  • Il modello mod3 sbaglia di circa 275 g rispetto al peso reale dei neonati (RMSE: 274.234)

Considerando che il peso medio è intorno ai 3200–3400 g, l’errore è circa l’8% del valore medio → un livello di accuratezza piuttosto buono per dati biologici, che hanno sempre variabilità naturale.


5- Previsioni dei risultati


Testiamo il modello per effettuare delle previsioni

Previsione test: Proviamo a stimare il peso di una neonata considerando una madre alla terza gravidanza che partorirà alla 39esima settimana.

# Esempio: madre alla terza gravidanza, 39 settimane, non fumatrice
nuovo <- data.frame(
  Anni.madre = 30,
  Gestazione = 39,
  N.gravidanze= 3,
  Lunghezza = 500,
  Cranio = 340,
  Sesso = factor("F", levels = levels(dati$Sesso))
)

predict(mod3, nuovo, interval = "prediction")
       fit      lwr      upr
1 3324.071 2785.035 3863.107

Commenti:

Il modello di regressione multipla mostra una buona capacità predittiva, con un RMSE di circa 275 g. Questo significa che, in media, la stima del peso neonatale differisce di meno di 300 g dal valore osservato, un margine accettabile considerando la variabilità naturale dei dati antropometrici.


6- Conclusioni finali


In questo lavoro sono state analizzate le misure antropometriche neonatali con l’obiettivo di comprendere relazioni tra le diverse variabili e di costruire un modello predittivo del peso alla nascita.

I risultati dei test statistici hanno mostrato chiaramente che i neonati maschi tendono ad avere valori medi più elevati rispetto alle femmine in tutte le variabili considerate: peso, lunghezza e circonferenza cranica.

Queste differenze non sono casuali, ma statisticamente significative, e confermano quanto già osservato in letteratura.

Successivamente, è stato costruito un modello di regressione multipla per stimare il peso neonatale in funzione di variabili come lunghezza, cranio, sesso, numero di gravidanze e settimana di gestazione

Il modello ha mostrato una buona capacità esplicativa: le variabili antropometriche e ostetriche contribuiscono in modo significativo alla previsione del peso, e l’errore medio di stima (RMSE) è risultato di circa 275 grammi. Questo valore, se confrontato con il peso medio dei neonati del campione (circa 3200–3400 g), rappresenta un margine di errore contenuto e accettabile

Infine, abbiamo applicato il modello a un caso pratico: una neonata, figlia di una madre alla terza gravidanza, partorita alla 39ª settimana. La previsione ha stimato un peso di circa 3300 g, con un intervallo di predizione compreso tra 2785 e 3863 g.

LS0tDQp0aXRsZTogIk1vZGVsbG8gU3RhdGlzdGljbyBwZXIgbGEgUHJldmlzaW9uZSBkZWwgUGVzbyBOZW9uYXRhbGUiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCkNvbnRlc3RvIEF6aWVuZGFsZVxicg0KDQpBemllbmRhOiBOZW9uYXRhbCBIZWFsdGggU29sdXRpb25zDQpPYmlldHRpdm86IENyZWFyZSB1biBtb2RlbGxvIHN0YXRpc3RpY28gaW4gZ3JhZG8gZGkgcHJldmVkZXJlIGNvbiBwcmVjaXNpb25lIGlsIHBlc28gZGVpIG5lb25hdGkgYWxsYSBuYXNjaXRhLCBiYXNhbmRvc2kgc3UgdmFyaWFiaWxpIGNsaW5pY2hlIHJhY2NvbHRlIGRhIHRyZSBvc3BlZGFsaS4gSWwgcHJvZ2V0dG8gbWlyYSBhIG1pZ2xpb3JhcmUgbGEgZ2VzdGlvbmUgZGVsbGUgZ3JhdmlkYW56ZSBhZCBhbHRvIHJpc2NoaW8sIG90dGltaXp6YXJlIGxlIHJpc29yc2Ugb3NwZWRhbGllcmUgZSBnYXJhbnRpcmUgbWlnbGlvcmkgcmlzdWx0YXRpIHBlciBsYSBzYWx1dGUgbmVvbmF0YWxlLg0KDQpJbCBwcm9nZXR0byBzaSBpbnNlcmlzY2UgYWxsJ2ludGVybm8gZGkgdW4gY29udGVzdG8gZGkgY3Jlc2NlbnRlIGF0dGVuemlvbmUgdmVyc28gbGEgcHJldmVuemlvbmUgZGVsbGUgY29tcGxpY2F6aW9uaSBuZW9uYXRhbGkuIExhIHBvc3NpYmlsaXTDoCBkaSBwcmV2ZWRlcmUgaWwgcGVzbyBhbGxhIG5hc2NpdGEgZGVpIG5lb25hdGkgcmFwcHJlc2VudGEgdW4nb3Bwb3J0dW5pdMOgIGZvbmRhbWVudGFsZSBwZXIgbWlnbGlvcmFyZSBsYSBwaWFuaWZpY2F6aW9uZSBjbGluaWNhIGUgcmlkdXJyZSBpIHJpc2NoaSBhc3NvY2lhdGkgYSBuYXNjaXRlIHByb2JsZW1hdGljaGUsIGNvbWUgcGFydGkgcHJlbWF0dXJpIG8gbmVvbmF0aSBjb24gYmFzc28gcGVzby4gRGkgc2VndWl0bywgaSBwcmluY2lwYWxpIGJlbmVmaWNpIGNoZSBxdWVzdG8gcHJvZ2V0dG8gcG9ydGVyw6AgYWxs4oCZYXppZW5kYSBlIGFsIHNldHRvcmUgc2FuaXRhcmlvOlxicg0KDQoNCjEuKipNaWdsaW9yYW1lbnRvIGRlbGxlIHByZXZpc2lvbmkgY2xpbmljaGUqKjpcYnINCg0KDQotIElsIHBlc28gZGVsIG5lb25hdG8gw6ggdW4gaW5kaWNhdG9yZSBjaGlhdmUgZGVsbGEgc3VhIHNhbHV0ZS4gQXZlcmUgdW4gbW9kZWxsbyBwcmVkaXR0aXZvIGFjY3VyYXRvIGNvbnNlbnRlIGFsIHBlcnNvbmFsZSBtZWRpY28gZGkgaW50ZXJ2ZW5pcmUgdGVtcGVzdGl2YW1lbnRlIGluIGNhc28gZGkgYW5vbWFsaWUsIHJpZHVjZW5kbyBsZSBjb21wbGljYXppb25pIHBlcmluYXRhbGkgY29tZSBsZSBkaWZmaWNvbHTDoCByZXNwaXJhdG9yaWUgbyBs4oCZaXBvZ2xpY2VtaWEuXEJSDQoNCjIuKipPdHRpbWl6emF6aW9uZSBkZWxsZSByaXNvcnNlIG9zcGVkYWxpZXJlKio6DQoNCi0gU2FwZXJlIGluIGFudGljaXBvIHF1YWxpIG5lb25hdGkgcG90cmViYmVybyBhdmVyZSBiaXNvZ25vIGRpIGN1cmUgaW50ZW5zaXZlIGFpdXRhIGEgb3JnYW5penphcmUgbGUgcmlzb3JzZSB1bWFuZSBlIHRlY25vbG9naWNoZSBkZWdsaSBvc3BlZGFsaSBpbiBtb2RvIGVmZmljaWVudGUuIFF1ZXN0byBzaSB0cmFkdWNlIGluIHVuYSByaWR1emlvbmUgZGVpIGNvc3RpIG9wZXJhdGl2aSBlIHVuYSBtaWdsaW9yZSBwaWFuaWZpY2F6aW9uZSBkZWxs4oCZdXRpbGl6em8gZGVsbGUgdW5pdMOgIGRpIHRlcmFwaWEgaW50ZW5zaXZhIG5lb25hdGFsZSAoVElOKS5cQlINCg0KMy4qKlByZXZlbnppb25lIGUgaWRlbnRpZmljYXppb25lIGRlaSBmYXR0b3JpIGRpIHJpc2NoaW8qKjoNCg0KLSBJbCBtb2RlbGxvIHBvdHLDoCBldmlkZW56aWFyZSBpIGZhdHRvcmkgY2hlIG1hZ2dpb3JtZW50ZSBpbmZsdWVuemFubyBuZWdhdGl2YW1lbnRlIGlsIHBlc28gZGVsIG5lb25hdG8gKGNvbWUgaWwgZnVtbyBtYXRlcm5vLCBncmF2aWRhbnplIG11bHRpcGxlIG8gZXTDoCBhdmFuemF0YSBkZWxsYSBtYWRyZSkuIFF1ZXN0ZSBpbmZvcm1hemlvbmkgc29ubyBwcmV6aW9zZSBwZXIgbGEgcHJldmVuemlvbmUgZSBsYSBnZXN0aW9uZSBwZXJzb25hbGl6emF0YSBkZWxsZSBncmF2aWRhbnplLCBwZXJtZXR0ZW5kbyBpbnRlcnZlbnRpIHByb2F0dGl2aSBpbiBjYXNvIGRpIHJpc2NoaW8gZWxldmF0by5cQlINCg0KNC4qKlZhbHV0YXppb25lIGRlbGxlIHByYXRpY2hlIG9zcGVkYWxpZXJlKio6DQoNCi0gQXR0cmF2ZXJzbyB1buKAmWFuYWxpc2kgY29tcGFyYXRpdmEgdHJhIGkgdHJlIG9zcGVkYWxpIGNvaW52b2x0aSwgbOKAmWF6aWVuZGEgcG90csOgIGlkZW50aWZpY2FyZSBldmVudHVhbGkgZGlmZmVyZW56ZSBuZWkgcmlzdWx0YXRpIGNsaW5pY2ksIGNvbWUgdW5hIG1hZ2dpb3JlIGluY2lkZW56YSBkaSBwYXJ0aSBjZXNhcmVpIGluIHVuYSBkZXRlcm1pbmF0YSBzdHJ1dHR1cmEuIENpw7IgY29uc2VudGUgZGkgbW9uaXRvcmFyZSBsYSBxdWFsaXTDoCBkZWxsZSBwcmF0aWNoZSBlIGFybW9uaXp6YXJlIGkgcHJvdG9jb2xsaSB0cmEgaSBkaXZlcnNpIGNlbnRyaSBvc3BlZGFsaWVyaSwgbWlnbGlvcmFuZG8gbGEgY29lcmVuemEgZGVsbGUgY3VyZS5cQlINCg0KNS4qKlN1cHBvcnRvIGFsbGEgcGlhbmlmaWNhemlvbmUgc3RyYXRlZ2ljYSoqOg0KDQotIEzigJlhbmFsaXNpIGRlaSBkYXRpIGUgbGUgcHJldmlzaW9uaSBwb3Nzb25vIGVzc2VyZSB1dGlsaXp6YXRlIHBlciBwcmVuZGVyZSBkZWNpc2lvbmkgaW5mb3JtYXRlIG5vbiBzb2xvIGEgbGl2ZWxsbyBjbGluaWNvIG1hIGFuY2hlIHN0cmF0ZWdpY28uIEwnYXppZW5kYSBwb3Ryw6Agc2ZydXR0YXJlIHF1ZXN0ZSBpbmZvcm1hemlvbmkgcGVyIGltcGxlbWVudGFyZSBudW92ZSBwb2xpdGljaGUgZGkgc2FsdXRlIHB1YmJsaWNhLCBnYXJhbnRlbmRvIHVuIGltcGF0dG8gcG9zaXRpdm8gc3VpIHRhc3NpIGRpIG1vcnRhbGl0w6AgZSBtb3JiaWxpdMOgIG5lb25hdGFsZS4NCg0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KZ2V0d2QoKQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpkYXRpIDwtIHJlYWQuY3N2KCJuZW9uYXRpLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUKQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQphdHRhY2goZGF0aSkNCmBgYA0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpuPC0gbnJvdyhkYXRpKQ0KYGBgDQoNCg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0Kc2hhcGlyby50ZXN0KFBlc28pDQpgYGANCg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KaW5zdGFsbC5wYWNrYWdlcygiY2FyIikNCmluc3RhbGwucGFja2FnZXMoImJyb29tIikNCmluc3RhbGwucGFja2FnZXMoIk1ldHJpY3MiKQ0KaW5zdGFsbC5wYWNrYWdlcygicmdsIikNCmluc3RhbGwucGFja2FnZXMoInBhdGNod29yayIpDQoNCmBgYA0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQojIPCfk5ogQ2FyaWNhbWVudG8gZGVsbGUgbGlicmVyaWUgbmVjZXNzYXJpZQ0KDQpsaWJyYXJ5KGRwbHlyKSAgICAgICAgIyBNYW5pcG9sYXppb25lIGRlaSBkYXRpDQpsaWJyYXJ5KGdncGxvdDIpICAgICAgIyBHcmFmaWNpIHN0YXRpY2kNCmxpYnJhcnkocGxvdGx5KSAgICAgICAjIEdyYWZpY2kgaW50ZXJhdHRpdmkNCmxpYnJhcnkoY3Jvc3N0YWxrKSAgICAjIEZpbHRyaSBpbnRlcmF0dGl2aSBjb25kaXZpc2kNCmxpYnJhcnkoYnNwbHVzKSAgICAgICAjIExheW91dCBpbnRlcmF0dGl2byBjb24gYnNjb2xzKCkNCmxpYnJhcnkoc2NhbGVzKSAgICAgICAjIEZvcm1hdHRhemlvbmUgbnVtZXJpY2EgKGV0aWNoZXR0ZSwgYXNzaSkNCmxpYnJhcnkocmVhZHIpICAgICAgICAjIExldHR1cmEgZmlsZSBDU1YgKHNlIHVzYXRvKQ0KIyBPcHppb25hbGkNCmxpYnJhcnkoRFQpICAgICAgICAgICAjIFRhYmVsbGUgaW50ZXJhdHRpdmUNCmxpYnJhcnkoa2FibGVFeHRyYSkgICAjIFRhYmVsbGUgc3RhdGljaGUgZWxlZ2FudGkNCmxpYnJhcnkodGlkeXIpICAgICAgICAjIFJpc3RydXR0dXJhemlvbmUgZGF0aQ0KbGlicmFyeShsdWJyaWRhdGUpICAgICMgR2VzdGlvbmUgZGF0ZQ0KbGlicmFyeShlMTA3MSkNCmxpYnJhcnkobW9tZW50cykNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KbGlicmFyeShNZXRyaWNzKQ0KbGlicmFyeShjYXIpDQoNCmBgYA0KDQoNCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KIyMjICoqMSAtIFJhY2NvbHRhIGRlaSBEYXRpIGUgU3RydXR0dXJhIGRlbCBEYXRhc2V0KioNCg0KDQpQZXIgY29zdHJ1aXJlIGlsIG1vZGVsbG8gcHJlZGl0dGl2bywgc29ubyBzdGF0aSByYWNjb2x0aSBkYXRpIHN1IDI1MDAgbmVvbmF0aSBwcm92ZW5pZW50aSBkYSB0cmUgb3NwZWRhbGkuIExlIHZhcmlhYmlsaSByYWNjb2x0ZSBpbmNsdWRvbm86DQoNCi0gKipFdMOgIGRlbGxhIG1hZHJlKio6IE1pc3VyYSBkZWxsJ2V0w6AgaW4gYW5uaS4NCi0gKipOdW1lcm8gZGkgZ3JhdmlkYW56ZSoqOiBRdWFudGUgZ3JhdmlkYW56ZSBoYSBhdnV0byBsYSBtYWRyZS4NCi0gKipGdW1vIG1hdGVybm8qKjogVW4gaW5kaWNhdG9yZSBiaW5hcmlvICgwPW5vbiBmdW1hdHJpY2UsIDE9ZnVtYXRyaWNlKS4NCi0gKipEdXJhdGEgZGVsbGEgZ3JhdmlkYW56YSoqOiBOdW1lcm8gZGkgc2V0dGltYW5lIGRpIGdlc3RhemlvbmUuDQotICoqUGVzbyBkZWwgbmVvbmF0byoqOiBQZXNvIGFsbGEgbmFzY2l0YSBpbiBncmFtbWkuDQotICoqTHVuZ2hlenphIGUgZGlhbWV0cm8gZGVsIGNyYW5pbyoqOiBMdW5naGV6emEgZGVsIG5lb25hdG8gZSBkaWFtZXRybyBjcmFuaWFsZSwgbWlzdXJhYmlsaSBhbmNoZSBkdXJhbnRlIGxhIGdyYXZpZGFuemEgdHJhbWl0ZSBlY29ncmFmaWUuDQotICoqVGlwbyBkaSBwYXJ0byoqOiBOYXR1cmFsZSBvIGNlc2FyZW8uDQotICoqT3NwZWRhbGUgZGkgbmFzY2l0YSoqOiBPc3BlZGFsZSAxLCAyIG8gMy4NCi0gKipTZXNzbyBkZWwgbmVvbmF0byoqOiBNYXNjaGlvIChNKSBvIGZlbW1pbmEgKEYpLlxicg0KDQpM4oCZb2JpZXR0aXZvIHByaW5jaXBhbGUgw6ggaWRlbnRpZmljYXJlIHF1YWxpIGRpIHF1ZXN0ZSB2YXJpYWJpbGkgc29ubyBwacO5IHByZWRpdHRpdmUgZGVsIHBlc28gYWxsYSBuYXNjaXRhLCBjb24gdW4gZm9jdXMgcGFydGljb2xhcmUgc3VsbOKAmWltcGF0dG8gZGVsIGZ1bW8gbWF0ZXJubyBlIGRlbGxlIHNldHRpbWFuZSBkaSBnZXN0YXppb25lLCBjaGUgcG90cmViYmVybyBpbmRpY2FyZSBuYXNjaXRlIHByZW1hdHVyZS4NCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KIyMjIEVzcGxvcmF6aW9uZSBkYXRpDQoNCg0KYGBge3IgZWNobz1GQUxTRX0NCiMgU2VsZXppb25hIGxlIHZhcmlhYmlsaQ0KdmFyaWFiaWxpIDwtIGRhdGkgJT4lDQogIHNlbGVjdChBbm5pLm1hZHJlLCBOLmdyYXZpZGFuemUsIEZ1bWF0cmljaSwgR2VzdGF6aW9uZSwgUGVzbywgTHVuZ2hlenphLCBDcmFuaW8pDQoNCiMgQ2FsY29sYSBnbGkgaW5kaWNpDQp0YWJlbGxhX3ZhciA8LSB0aWJibGUoDQogIFZhcmlhYmlsZSA9IGMoIkFubmkubWFkcmUiLCAiTi5ncmF2aWRhbnplIiwiRnVtYXRyaWNpIiwiR2VzdGF6aW9uZSIsICJQZXNvIiwgIkx1bmdoZXp6YSIsICJDcmFuaW8iKSwNCiAgTWVkaWEgPSBzYXBwbHkodmFyaWFiaWxpLCBtZWFuKSwNCiAgRGV2aWF6aW9uZV9TdGFuZGFyZCA9IHNhcHBseSh2YXJpYWJpbGksIHNkKSwNCiAgQ29lZmZfVmFyaWF6aW9uZSA9IHNhcHBseSh2YXJpYWJpbGksIHNkKSAvIHNhcHBseSh2YXJpYWJpbGksIG1lYW4pLA0KICBNaW5pbW8gPSBzYXBwbHkodmFyaWFiaWxpLCBtaW4pLA0KICBNYXNzaW1vID0gc2FwcGx5KHZhcmlhYmlsaSwgbWF4KSwNCiAgU2tld25lc3MgPSBzYXBwbHkodmFyaWFiaWxpLCBza2V3bmVzcyksDQogIEt1cnRvc2lzID0gc2FwcGx5KHZhcmlhYmlsaSwga3VydG9zaXMpDQopICU+JQ0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+cm91bmQoLngsIDIpKSkNCg0KIyBWaXN1YWxpenphIGxhIHRhYmVsbGENCnRhYmVsbGFfdmFyICU+JQ0KICBrYWJsZShjYXB0aW9uID0gIlRhYmVsbGEtIEluZGljaSBkaSBwb3NpemlvbmUsIHZhcmlhYmlsaXTDoCBlIGFzaW1tZXRyaWEgcGVyIHZhcmlhYmlsaSBxdWFudGl0YXRpdmUiKSAlPiUNCiAga2FibGVfc3R5bGluZygNCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSwNCiAgICBmdWxsX3dpZHRoID0gRkFMU0UsDQogICAgcG9zaXRpb24gPSAibGVmdCINCiAgKQ0KYGBgDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3J9DQojIFByZXBhcmEgaSBkYXRpIGluIGZvcm1hdG8gbHVuZ28NCmRhdGlfbG9uZyA8LSBkYXRpICU+JQ0KICBzZWxlY3QoUGVzbywgTHVuZ2hlenphLCBDcmFuaW8sIEdlc3RhemlvbmUsIEFubmkubWFkcmUsIE4uZ3JhdmlkYW56ZSkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJWYXJpYWJpbGUiLCB2YWx1ZXNfdG8gPSAiVmFsb3JlIikNCg0KIyBDYWxjb2xhIGxhIG1lZGlhIHBlciBvZ25pIHZhcmlhYmlsZQ0KbWVkaWUgPC0gZGF0aV9sb25nICU+JQ0KICBncm91cF9ieShWYXJpYWJpbGUpICU+JQ0KICBzdW1tYXJpc2UoTWVkaWEgPSBtZWFuKFZhbG9yZSkpDQoNCiMgQ3JlYSBpbCBncmFmaWNvIGNvbiBjb2xvcmUgdW5pY28NCmdncGxvdChkYXRpX2xvbmcsIGFlcyh4ID0gVmFsb3JlKSkgKw0KICBnZW9tX2RlbnNpdHkoZmlsbCA9ICJncmV5NjAiLCBhbHBoYSA9IDAuNiwgY29sb3IgPSAiZ3JleTMwIiwgbGluZXdpZHRoID0gMSkgKw0KICBnZW9tX3ZsaW5lKGRhdGEgPSBtZWRpZSwgYWVzKHhpbnRlcmNlcHQgPSBNZWRpYSksDQogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjgpICsNCiAgZmFjZXRfd3JhcCh+VmFyaWFiaWxlLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSAyKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBOVUxMKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiR3JhZmljbyBkaXN0cmlidXppb25lIGRlbGxlIHZhcmlhYmlsaSBxdWFudGl0YXRpdmUiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gTlVMTA0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpDQogICkNCmBgYA0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCiMjIyBBbmFsaXNpIGRpc3RyaWJ1emlvbmUgZGVsbGUgdmFyaWFiaWxpIHF1YW50aXRhdGl2ZTpcYnINCg0KKipBbm5pLm1hZHJlKipcYnINCg0KLSBNZWRpYTogMjguMTYgYW5uaSDihpIgZXTDoCBtZWRpYSBkZWxsZSBtYWRyaSByZWxhdGl2YW1lbnRlIGdpb3ZhbmVcYnINCi0gU2tld25lc3Mg4omIIDAg4oaSIGRpc3RyaWJ1emlvbmUgc2ltbWV0cmljYVxicg0KLSBLdXJ0b3NpcyAzLjM4IOKGkiB2aWNpbmEgYWxsYSBub3JtYWxlLCBxdWluZGkgc2VuemEgY29kZSBlY2Nlc3NpdmVcYnINCi0gUHJlc2VuemEgZGkgb3V0bGllciBwcm9iYWJpbG1lbnRlIGRvdnV0aSBhZCBlcnJvcmkgKDIgY2FzaSBzb3R0byBpIDEzIGFubmkpXGJyDQoNCioqTi5ncmF2aWRhbnplKipcYnINCg0KLSBNZWRpYTogMC45OCDihpIgaW4gbWVkaWEgdW5hIGdyYXZpZGFuemEgcGVyIG1hZHJlLlxicg0KLSBDb2VmZi4gdmFyaWF6aW9uZSA9IDEuMzEg4oaSIGFsdGlzc2ltYSB2YXJpYWJpbGl0w6AgcmVsYXRpdmFcYnINCi0gU2tld25lc3MgMi41MSDihpIgZGlzdHJpYnV6aW9uZSBtb2x0byBhc2ltbWV0cmljYSBhIGRlc3RyYSAoYWxjdW5lIG1hZHJpIGNvbiBtb2x0ZSBncmF2aWRhbnplKVxicg0KDQoqKkZ1bWF0cmljaSoqXGJyDQoNCi0gTWVkaWE6IDAuMDQg4oaSIHNvbG8gaWwgNCUgZGVsbGUgbWFkcmkgZnVtYVxicg0KLSBTa2V3bmVzcyA0LjU5IOKGkiBmb3J0ZW1lbnRlIGFzaW1tZXRyaWNhIChxdWFzaSB0dXR0ZSBsZSBnZXN0YW50aSBub24gZnVtYW5vKVxicg0KDQoqKkdlc3RhemlvbmUqKlxicg0KDQotIE1lZGlhOiAzOC45OCBzZXR0aW1hbmUg4oaSIHZpY2luYSBhbCB0ZXJtaW5lIGZpc2lvbG9naWNvICjiiYggMzkpLlxicg0KLSBNaW5pbW86IDI1IHNldHRpbWFuZSDihpIgcHJlc2VuemEgZGkgcHJlbWF0dXJpIGVzdHJlbWlcYnINCi0gS3VydG9zaXMgMTEuMjYg4oaSIGRpc3RyaWJ1emlvbmUgY29uIGNvZGUgcGVzYW50aSwgb3V0bGllciBpbXBvcnRhbnRpXGJyDQoNCioqUGVzbyoqXGJyDQoNCi0gTWVkaWE6IDMyODQgZyDihpIgaW4gbGluZWEgY29uIHZhbG9yaSBhdHRlc2lcYnINCi0gTWluaW1vOiA4MzAgZyDihpIgbmVvbmF0aSBtb2x0byBwaWNjb2xpIChwcmVtYXR1cmkpXGJyDQotIEt1cnRvc2lzIDUuMDMg4oaSIGNvZGUgcGVzYW50aSwgcHJlc2VuemEgZGkgdmFsb3JpIGVzdHJlbWlcYnINCg0KDQoqKkx1bmdoZXp6YSoqXGJyDQoNCi0gTWVkaWE6IDQ5NC42OSBtbSAo4omIIDQ5LjUgY20pXGJyDQotIFNrZXduZXNzIC0xLjUxIOKGkiBkaXN0cmlidXppb25lIGFzaW1tZXRyaWNhIGEgc2luaXN0cmEgKGFsY3VuaSBuZW9uYXRpIG1vbHRvIHBpY2NvbGkpXGJyDQotIEt1cnRvc2lzIDkuNDkg4oaSIGNvZGUgcGVzYW50aSwgb3V0bGllclxicg0KDQoqKkNyYW5pbyoqXGJyDQoNCi0gTWVkaWE6IDM0MCBtbVxicg0KLSBTa2V3bmVzcyAtMC43OSDihpIgbGVnZ2VyYSBhc2ltbWV0cmlhIGEgc2luaXN0cmFcYnINCi0gS3VydG9zaXMgNS45NSDihpIgZGlzdHJpYnV6aW9uZSBsZXB0b2N1cnRpY2EsIGNvZGUgcGVzYW50aVxicg0KDQoqKlNpbnRlc2kqKlxicg0KDQotIEFubmkubWFkcmUgw6ggbGEgdmFyaWFiaWxlIHBpw7kg4oCccmVnb2xhcmXigJ0sIGNvbiBkaXN0cmlidXppb25lIHZpY2luYSBhbGxhIG5vcm1hbGVcYnINCi0gVmFyaWFiaWxpIGNvbWUgTi5ncmF2aWRhbnplLCBGdW1hdHJpY2kgZSBHZXN0YXppb25lIG1vc3RyYW5vIGRpc3RyaWJ1emlvbmkgbW9sdG8gYXNpbW1ldHJpY2hlIGUgY29uIG91dGxpZXIg4oaSIHJpY2hpZWRvbm8gYXR0ZW56aW9uZSBuZWkgdGVzdCBzdGF0aXN0aWNpXGJyDQotIFZhcmlhYmlsaSBhbnRyb3BvbWV0cmljaGUgKFBlc28sIEx1bmdoZXp6YSwgQ3JhbmlvKSBoYW5ubyBtZWRpZSBwbGF1c2liaWxpLCBtYSBjb2RlIHBlc2FudGkg4oaSIGNvbmZlcm1hIGxhIHByZXNlbnphIGRpIG5lb25hdGkgcHJlbWF0dXJpIG8gbWFjcm9zb21pY2lcYnINCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNCiMjIElwb3Rlc2kgMQ0KDQppbiBhbGN1bmkgb3NwZWRhbGkgc2kgZmFubm8gcGnDuSBwYXJ0aSBjZXNhcmVpXGJyDQoNCg0KU3RlcCAxOiBBbmFsaXp6aWFtbyBwcmltYSBsYSBkaXN0cmlidXppb25lIGRlaSB0aXBpIGRpIHBhcnRvIHRyYSBwYXJ0byBuYXR1cmFsZSBlIHBhcnRvIGNlc2FyZW8NCg0KYGBge3J9DQojIENhbGNvbGEgbGUgZnJlcXVlbnplDQpwYXJ0aSA8LSB0YWJsZShkYXRpJFRpcG8ucGFydG8pDQoNCiMgQ3JlYSBpbCBncmFmaWNvIGEgdG9ydGENCnBpZShwYXJ0aSwNCiAgICBsYWJlbHMgPSBwYXN0ZShuYW1lcyhwYXJ0aSksICJcbiIsIHJvdW5kKDEwMCAqIHBhcnRpIC8gc3VtKHBhcnRpKSwgMSksICIlIiksDQogICAgY29sID0gYygiZ3JleSIsICJncmV5OTAiKSwNCiAgICBtYWluID0gIkRpc3RyaWJ1emlvbmUgZGVpIHRpcGkgZGkgcGFydG8iKQ0KDQpgYGANCg0KDQpTdGVwIDI6IENhbGNvbGlhbW8gZGlzdHJpYnV6aW9uZSBkZWkgdGlwaSBkaSBwYXJ0byB0cmEgcGFydG8gbmF0dXJhbGUgZSBwYXJ0byBjZXNhcmVvIHRyYSBvc3BlZGFsaQ0KDQoNCg0KYGBge3J9DQp0YWJsZShkYXRpJFRpcG8ucGFydG8sIGRhdGkkT3NwZWRhbGUpDQoNCmBgYA0KU3RlcCAzIFZpc3VhbGl6emlhbW8gZ3JhZmljYW1lbnRlDQpgYGB7cn0NCiMgRnJlcXVlbnplIHBlciBjaWFzY3VuIG9zcGVkYWxlDQpwYXJ0aV9vc3BlZGFsaSA8LSB0YWJsZShkYXRpJFRpcG8ucGFydG8sIGRhdGkkT3NwZWRhbGUpDQoNCiMgR3JhZmljbyBhIHRvcnRhIHBlciBvZ25pIG9zcGVkYWxlDQpwYXIobWZyb3cgPSBjKDEsIDMpKSAgIyAzIGdyYWZpY2kgYWZmaWFuY2F0aQ0KDQpmb3IgKG9zcCBpbiBjb2xuYW1lcyhwYXJ0aV9vc3BlZGFsaSkpIHsNCiAgcGllKHBhcnRpX29zcGVkYWxpWywgb3NwXSwNCiAgICAgIGxhYmVscyA9IHBhc3RlKHJvd25hbWVzKHBhcnRpX29zcGVkYWxpKSwgIlxuIiwgcm91bmQoMTAwICogcGFydGlfb3NwZWRhbGlbLCBvc3BdIC8gc3VtKHBhcnRpX29zcGVkYWxpWywgb3NwXSksIDEpLCAiJSIpLA0KICAgICAgY29sID0gYygiZ3JleSIsICJncmV5OTAiKSwNCiAgICAgIG1haW4gPSBwYXN0ZSgiUGFydGkgaW4iLCBvc3ApKQ0KfQ0KDQpgYGANCg0KU3RlcCA0IGVmZmV0dHVpYW1vIGlsIHRlc3QNCmBgYHtyfQ0KIyBQYXJ0aSBjZXNhcmVpIHBlciBvc3BlZGFsZQ0KY2hpc3EudGVzdCh0YWJsZShkYXRpJFRpcG8ucGFydG8sIGRhdGkkT3NwZWRhbGUpKQ0KYGBgDQoNCkNvbW1lbnRpOlxicg0KDQpJbCBwLXZhbHVlIMOoIG1hZ2dpb3JlIGRpIDAuMDUsIHF1aW5kaSBub24gY2kgc29ubyBkaWZmZXJlbnplIHN0YXRpc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZlIG5lbGxhIGRpc3RyaWJ1emlvbmUgZGVpIHRpcGkgZGkgcGFydG8gdHJhIGdsaSBvc3BlZGFsaS4NCkxhIHNjZWx0YSB0cmEgcGFydG8gbmF0dXJhbGUgZSBjZXNhcmVvIG5vbiBzZW1icmEgZGlwZW5kZXJlIGRhbGzigJlvc3BlZGFsZSBpbiBjdWkgYXZ2aWVuZSBsJ2V2ZW50byBwZXIgY3VpIHNpIHJpZml1dGEgbCdpcG90ZXNpLg0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQojIyBJcG90ZXNpIDINCg0KTGEgbWVkaWEgZGVsIHBlc28gZSBkZWxsYSBsdW5naGV6emEgZGkgcXVlc3RvIGNhbXBpb25lIGRpIG5lb25hdGkgc29ubyBzaWduaWZpY2F0aXZhbWVudGUgdWd1YWxpIGEgcXVlbGxlIGRlbGxhIHBvcG9sYXppb25lXGJyDQoNCg0KU3RlcCAxOiBBbmFsaXp6aWFtbyBsYSBkaXN0cmlidXppb25lIGRlbGxlIHZhcmlhYmlsaSBwZXNvIGUgbHVuZ2hlenphXGJyDQoNCmBgYHtyfQ0KDQoNCiMgQm94IHBsb3QgZGVsIFBlc28NCmJveF9wZXNvIDwtIGdncGxvdChkYXRpLCBhZXMoeSA9IFBlc28pKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gImdyZXkiLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMzMwMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkJveCBwbG90IFBlc28iLCB5ID0gIlBlc28gKGcpIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBCb3ggcGxvdCBkZWxsYSBMdW5naGV6emENCmJveF9sdW5naGV6emEgPC0gZ2dwbG90KGRhdGksIGFlcyh5ID0gTHVuZ2hlenphKSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICJncmV5IiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDUwMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkJveCBwbG90IEx1bmdoZXp6YSIsIHkgPSAiTHVuZ2hlenphIChtbSkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYm94X3Blc28gKyBib3hfbHVuZ2hlenphDQoNCg0KYGBgDQpTdGVwIDI6IEVmZmV0dHVpYW1vIHVuIHRlc3QgZGkgY29uZnJvbnRvIGRlbGxlIHZhcmlhYmlsaSBjb24gbGUgbWVkaWUgZGkgcmlmZXJpbWVudG8gZGVsbGEgcG9wb2xhemlvbmUgKGNvbiBtdSBQZXNvPTMzMDBnIGUgbXUgbHVuZ2hlenphPTUwMGNtKSBcYnINCg0KDQoNCmBgYHtyfQ0KDQojIFRlc3QgdCBwZXIgaWwgcGVzbw0KdC50ZXN0KGRhdGkkUGVzbywgbXUgPSAzMzAwKQ0KDQojIFRlc3QgdCBwZXIgbGEgbHVuZ2hlenphIGNvbiB2YWxvcmUgZGkgcmlmZXJpbWVudG8gKGVzLiA1MDBjbSkNCnQudGVzdChkYXRpJEx1bmdoZXp6YSwgbXUgPSA1MDApDQoNCg0KYGBgDQpDb21tZW50aToNCg0KLSAqKlBlc28qKjogIElsIHAtdmFsdWUgw6ggbWFnZ2lvcmUgZGkgMC4wNSwgcXVpbmRpIG5vbiBj4oCZw6ggZXZpZGVuemEgc3RhdGlzdGljYSBjaGUgbGEgbWVkaWEgZGVsIHBlc28gc2lhIGRpdmVyc2EgZGEgcXVlbGxhIGRlbGxhIHBvcG9sYXppb25lLiBMYSBtZWRpYSBkZWwgY2FtcGlvbmUgw6ggY29tcGF0aWJpbGUgY29uIDMzMDAgZ1xicg0KDQoNCi0gKipsdW5naGV6emEqKjogSWwgcC12YWx1ZSDDqCBtb2x0byBpbmZlcmlvcmUgYSAwLjA1LCBxdWluZGkgbGEgbWVkaWEgZGVsbGEgbHVuZ2hlenphIMOoIHNpZ25pZmljYXRpdmFtZW50ZSBkaXZlcnNhIGRhIHF1ZWxsYSBkZWxsYSBwb3BvbGF6aW9uZS4gSWwgY2FtcGlvbmUgbW9zdHJhIHVuYSBsdW5naGV6emEgbWVkaWEgaW5mZXJpb3JlIHJpc3BldHRvIGFsIHZhbG9yZSBhdHRlc28NCg0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQojIyBJcG90ZXNpIDMNCg0KTGUgbWlzdXJlIGFudHJvcG9tZXRyaWNoZSBzb25vIHNpZ25pZmljYXRpdmFtZW50ZSBkaXZlcnNlIHRyYSBpIGR1ZSBzZXNzaVxicg0KDQoNClN0ZXAgMTogQW5hbGl6emlhbW8gbGEgZGlzdHJpYnV6aW9uZSBNL0ZcYnINCg0KSWwgZ3JhZmljbyBtb3N0cmEgdW5hIGRpc3RyaWJ1emlvbmUgZGVsbGUgb3NzZXJ2YXppb25pIHRyYSBtYXNjaGkgZSBmZW1taW5lIHF1YXNpIHBlcmZldHRhbWVudGUgYmlsYW5jaWF0YQ0KDQoNCmBgYHtyfQ0KIyBDYWxjb2xhIGxlIGZyZXF1ZW56ZQ0KcGFydGkgPC0gdGFibGUoZGF0aSRTZXNzbykNCg0KIyBDcmVhIGlsIGdyYWZpY28gYSB0b3J0YQ0KcGllKHBhcnRpLA0KICAgIGxhYmVscyA9IHBhc3RlKG5hbWVzKHBhcnRpKSwgIlxuIiwgcm91bmQoMTAwICogcGFydGkgLyBzdW0ocGFydGkpLCAxKSwgIiUiKSwNCiAgICBjb2wgPSBjKCJncmV5IiwgImdyZXk5MCIpLA0KICAgIG1haW4gPSAiRGlzdHJpYnV6aW9uZSBzZXNzbyBkZWkgbmVvbmF0aSIpDQpgYGANCg0KDQpTdGVwIDI6IEFuYWxpenppYW1vIGxhIGRpc3RyaWJ1emlvbmUgZGVsbGUgdmFyaWFiaWxpIHBlc28gZSBsdW5naGV6emFcYnINCg0KDQpgYGB7cn0NCiMgQm94IHBsb3QgZGVsIFBlc28gcGVyIHNlc3NvDQpib3hfcGVzbyA8LSBnZ3Bsb3QoZGF0aSwgYWVzKHggPSBTZXNzbywgeSA9IFBlc28pKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gImdyZXk3MCIsIGNvbG9yID0gImJsYWNrIiwgb3V0bGllci5jb2xvciA9ICJibGFjayIpICsNCiAgbGFicyh0aXRsZSA9ICJCb3ggcGxvdCBQZXNvIiwgeSA9ICJQZXNvIChnKSIsIHggPSAiIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBCb3ggcGxvdCBkZWxsYSBMdW5naGV6emEgcGVyIHNlc3NvDQpib3hfbHVuZ2hlenphIDwtIGdncGxvdChkYXRpLCBhZXMoeCA9IFNlc3NvLCB5ID0gTHVuZ2hlenphKSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICJncmV5NzAiLCBjb2xvciA9ICJibGFjayIsIG91dGxpZXIuY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnModGl0bGUgPSAiQm94IHBsb3QgTHVuZ2hlenphIiwgeSA9ICJMdW5naGV6emEgKG1tKSIsIHggPSAiIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBCb3ggcGxvdCBkZWwgQ3JhbmlvIHBlciBzZXNzbw0KYm94X2NyYW5pbyA8LSBnZ3Bsb3QoZGF0aSwgYWVzKHggPSBTZXNzbywgeSA9IENyYW5pbykpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAiZ3JleTcwIiwgY29sb3IgPSAiYmxhY2siLCBvdXRsaWVyLmNvbG9yID0gImJsYWNrIikgKw0KICBsYWJzKHRpdGxlID0gIkJveCBwbG90IENyYW5pbyIsIHkgPSAiQ2lyY29uZmVyZW56YSBjcmFuaWNhIChtbSkiLCB4ID0gIiIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgQWZmaWFuY2EgaSB0cmUgZ3JhZmljaQ0KYm94X3Blc28gKyBib3hfbHVuZ2hlenphICsgYm94X2NyYW5pbw0KYGBgDQoNClN0ZXAgMzogRWZmZXR0dWlhbW8gaWwgdGVzdCBjb25kaXppb25hdG9cYnINCg0KYGBge3J9DQojIFBlc28NCnQudGVzdChQZXNvIH4gU2Vzc28sIGRhdGEgPSBkYXRpKQ0KDQojIEx1bmdoZXp6YQ0KdC50ZXN0KEx1bmdoZXp6YSB+IFNlc3NvLCBkYXRhID0gZGF0aSkNCg0KIyBDcmFuaW8NCnQudGVzdChDcmFuaW8gfiBTZXNzbywgZGF0YSA9IGRhdGkpDQpgYGANCkNvbW1lbnRpOg0KDQotIFR1dHRlIGxlIHZhcmlhYmlsaSBtb3N0cmFubyBkaWZmZXJlbnplIHN0YXRpc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZlIHRyYSBpIHNlc3NpDQotIEkgbWFzY2hpIGhhbm5vIGluIG1lZGlhOg0KICAtIFBlc28gbWFnZ2lvcmUgZGkgY2lyY2EgMjQ3IGcNCiAgLSBMdW5naGV6emEgbWFnZ2lvcmUgZGkgY2lyY2EgMTAgbW0NCiAgLSBDaXJjb25mZXJlbnphIGNyYW5pY2EgbWFnZ2lvcmUgZGkgY2lyY2EgNSBtbQ0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQpGb2N1cyBwYXJ0aWNvbGFyZSBzdWxs4oCZaW1wYXR0byBkZWwgZnVtbyBtYXRlcm5vIHN1bCBwZXNvIGUgc3VsbGUgc2V0dGltYW5lIGRpIGdlc3RhemlvbmUsIGNoZSBwb3RyZWJiZXJvIGluZGljYXJlIG5hc2NpdGUgcHJlbWF0dXJlXGJyDQoNCkwnb2JpZXR0aXZvIGRpIHF1ZXN0YSBhbmFsaXNpIMOoIHZlcmlmaWNhcmUgdW4gZXZlbnR1YWxlIGNvcnJlbGF6aW9uZSBlIGltcGF0dG8gdHJhIGlsIGZ1bW8gZSBsYSBuYXNjaXRhIHByZW1hdHVyYSBkZWkgbmVvbmF0aSBlZCBpbCByZWxhdGl2byBwZXNvIGFsbGEgbmFzY2l0YS5cYnINCg0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpkYXRpJFByZW1hdHVybyA8LSBpZmVsc2UoZGF0aSRHZXN0YXppb25lIDwgMzcsIDEsIDApDQoNCmBgYA0KDQoNCmBgYHtyfQ0KdGFiIDwtIGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZSh0YWJsZShkYXRpJEZ1bWF0cmljaSwgZGF0aSRQcmVtYXR1cm8pLCBtYXJnaW4gPSAxKSkNCmNvbG5hbWVzKHRhYikgPC0gYygiRnVtYXRyaWNpIiwgIlByZW1hdHVybyIsICJQcm9wb3J6aW9uZSIpDQoNCmdncGxvdCh0YWIsIGFlcyh4ID0gRnVtYXRyaWNpLCB5ID0gUHJvcG9yemlvbmUsIGZpbGwgPSBmYWN0b3IoUHJlbWF0dXJvKSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5IiwgImJsYWNrIiksDQogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk5hc2NpdGEgbm9uIHByZW1hdHVyYSIsICJOYXNjaXRhIHByZW1hdHVyYSIpKSArDQogIGxhYnMoeSA9ICJQZXJjZW50dWFsZSIsIGZpbGwgPSAiRXNpdG8gcGFydG8iKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpDQoNCmBgYA0KDQpgYGB7cn0NCmJveHBsb3QoUGVzb34gRnVtYXRyaWNpKQ0KYGBgDQoNCmBgYHtyfQ0KdC50ZXN0KFBlc29+IEZ1bWF0cmljaSkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGksIGFlcyh4ID0gR2VzdGF6aW9uZSwgeSA9IFBlc28sIGNvbG9yID0gZmFjdG9yKEZ1bWF0cmljaSkpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBUUlVFKSArDQogIGxhYnMoeCA9ICJTZXR0aW1hbmUgZGkgZ2VzdGF6aW9uZSIsIHkgPSAiUGVzbyAoZykiLCBjb2xvciA9ICJGdW1vIG1hdGVybm8iKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJzdGVlbGJsdWUiLCAidG9tYXRvIiksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJOb24gZnVtYXRyaWNlIiwgIkZ1bWF0cmljZSIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KDQoNCg0KDQpDb21tZW50aToNCg0KLSBMZSBzZXR0aW1hbmUgZGkgZ2VzdGF6aW9uZSBzb25vIGZvcnRlbWVudGUgY29ycmVsbGF0ZSBhbCBwZXNvLCBjb21lIG1vc3RyYXRvIGRhbCBncmFmaWNvDQotIE5lbCBjYW1waW9uZSwgbGUgZnVtYXRyaWNpIHNlbWJyYW5vIGF2ZXJlIG1lbm8gcGFydGkgcHJlbWF0dXJpIHJpc3BldHRvIGFsbGUgbm9uIGZ1bWF0cmljaVxicg0KLSBub24gY2kgc29ubyBldmlkZW56ZSBzdGF0aXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2ZSBjaGUgaWwgcGVzbyBkaWZmZXJpc2NhIHRyYSBpIGR1ZSBncnVwcGkgKGZ1bWF0cmljaSB2cyBub24gZnVtYXRyaWNpKVxicg0KLSBRdWVzdG8gcmlzdWx0YXRvIMOoIGNvbnRyb2ludHVpdGl2byByaXNwZXR0byBhbGxhIGxldHRlcmF0dXJhIG1lZGljYVxicg0KTm90YTpDb24gY29zw6wgcG9jaGkgY2FzaSwgbOKAmWVmZmV0dG8gc3RhdGlzdGljbyBwdcOyIGVzc2VyZSBpbnN0YWJpbGUgZSBub24gcmFwcHJlc2VudGF0aXZvIGUgaW5vbHRyZSBwb3RyZWJiZXJvIGVzc2VyY2kgdmFyaWFiaWxpIGNvbmZvbmRlbnRpIGNoZSBpbmZsdWVuemFubyBpbCByaXN1bHRhdG8NCg0KDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KIyMjICoqMiAtIENyZWF6aW9uZSBkZWwgTW9kZWxsbyBkaSBSZWdyZXNzaW9uZSoqDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KU3RlcCAxIEFuYWxpc2kgZGVsbGUgY29ycmVsYXppb25pIHRyYSBsZSB2YXJpYWJpbGkgcXVhbnRpdGF0aXZlDQoNCg0KYGBge3J9DQpyb3VuZChjb3IodmFyaWFiaWxpKSwyKQ0KYGBgDQpNYXRyaWNlIGRpIGNvcnJlbGF6aW9uZSB0cmEgdHV0dGUgbGUgdmFyaWFiaWxpDQogDQoNCmBgYHtyfQ0KcGFuZWwuY29yIDwtIGZ1bmN0aW9uKHgsIHksIGRpZ2l0cyA9IDIsIHByZWZpeCA9ICIiLCBjZXguY29yLCAuLi4pDQp7DQogIHVzciA8LSBwYXIoInVzciIpOyBvbi5leGl0KHBhcih1c3IpKQ0KICBwYXIodXNyID0gYygwLCAxLCAwLCAxKSkNCiAgciA8LSAoY29yKHgsIHkpKQ0KICB0eHQgPC0gZm9ybWF0KGMociwgMSksIGRpZ2l0cyA9IGRpZ2l0cylbMV0NCiAgdHh0IDwtIHBhc3RlMChwcmVmaXgsIHR4dCkNCiAgaWYobWlzc2luZyhjZXguY29yKSkgY2V4LmNvciA8LSAwLjgvc3Ryd2lkdGgodHh0KQ0KICB0ZXh0KDAuNSwgMC41LCB0eHQsIGNleCA9IDEuNSkNCn0NCiNjb3JyZWxhemlvbmkNCnBhaXJzKGRhdGksbG93ZXIucGFuZWw9cGFuZWwuY29yLCB1cHBlci5wYW5lbD1wYW5lbC5zbW9vdGgpDQpgYGANCg0KDQoqKk9zc2VydmF6aW9uaSBzdWxsYSBtYXRyaWNlKioNCg0KLSAqKkNvcnJlbGF6aW9uaSBmb3J0aSoqOg0KICAtICoqUGVzbyB2cyBTZXNzbzoqKjogaSBuZWFvbmF0aSBtYXNjaGkgcGVzYW5vIG1lZGlhbWVudGUgZGkgcGnDuSBkZWxsZSBmZW1taW5lDQogIC0gKipQZXNvIFZzIEdlc3RhemlvbmUqKjogMC41OSBsYSBkdXJhdGEgZGVsbGEgZ3JhdmlkYW56YSBpbmNpZGUgc2lnbmlmaWNhdGl2YW1lbnRlIHN1bCBwZXNvIGFsbGEgbmFzY2l0YQ0KICAtICoqUGVzbyB2cyBMdW5naGV6emEqKjogMC44MCDihpIgZm9ydGlzc2ltYSBjb3JyZWxhemlvbmUgcG9zaXRpdmEuIFBpw7kgbHVuZ28gw6ggaWwgbmVvbmF0bywgbWFnZ2lvcmUgw6ggaWwgcGVzbw0KICAtICoqUGVzbyB2cyBDcmFuaW86Kio6MC43MCBhbmNoZSBsYSBjaXJjb25mZXJlbnphIGNyYW5pY2Egw6ggZm9ydGVtZW50ZSBhc3NvY2lhdGEgYWwgcGVzbw0KICAtICoqR2VzdGF6aW9uZSB2cyBMdW5naGV6emE6Kio6IDAuNjIgcGnDuSBsdW5nYSDDqCBsYSBnZXN0YXppb25lLCBtYWdnaW9yZSDDqCBsYSBsdW5naGV6emEgZGVsIG5lb25hdG8NCiANCiAgDQogIA0KLSAqKkNvcnJlbGF6aW9uaSBkZWJvbGkgbyBudWxsZSoqOg0KICAtICoqRnVtYXRyaWNpIHZzIHR1dHRlIGxlIGFsdHJlKio6IHZhbG9yaSB2aWNpbmkgYSAwIChlcy4g4oiSMC4wMiwgMC4wMykg4oaSIGlsIGZ1bW8gbWF0ZXJubyBub24gbW9zdHJhIHVuYSBjb3JyZWxhemlvbmUgZm9ydGUgY29uIGxlIHZhcmlhYmlsaSBuZW9uYXRhbGkgaW4gcXVlc3RvIGRhdGFzZXQNCiAgDQotICoqQ29ycmVsYXppb25pIG5lZ2F0aXZlKio6DQogIC0gKipBbm5pLm1hZHJlIHZzIEdlc3RhemlvbmUqKjogbGVnZ2VyaXNzaW1hIHRlbmRlbnphOiBtYWRyaSBwacO5IGFuemlhbmUgcG90cmViYmVybyBhdmVyZSBnZXN0YXppb25pIGxlZ2dlcm1lbnRlIHBpw7kgYnJldmkNCiAgLSAqKkdlc3RhemlvbmUgdnMgTi5ncmF2aWRhbnplKio6IHBpw7kgZ3JhdmlkYW56ZSBzZW1icmFubyBhc3NvY2lhdGUgYSBnZXN0YXppb25pIGxlZ2dlcm1lbnRlIHBpw7kgYnJldmkNCiAgDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNCiMjIyBDcmVhemlvbmUgZGVsIHByaW1vIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgbGluZWFyZSBtdWx0aXBsYSBjb24gdHV0dGUgbGUgdmFyaWFiaWxpIChNb2QxKQ0KDQoNCmBgYHtyfQ0KDQojIE1vZDE9IE1vZGVsbG8gY29tcGxldG8NCm1vZDEgPC0gbG0oUGVzbyB+IC4sIGRhdGEgPSBkYXRpKQ0KDQpzdW1tYXJ5KG1vZDEpDQoNCmBgYA0KDQojIyMgQ3JlYXppb25lIGRpIHVuIHNlY29uZG8gbW9kZWxsbyBvdHRpbWl6emF0byAgZGkgcmVncmVzc2lvbmUgbGluZWFyZSBtdWx0aXBsYSBjb24gbGUgdmFyaWFiaWxpIGVzY2x1ZGVuZG8gbGUgdmFyaWFiaWxpIHBvY28gc2lnbmlmaWNhdGl2ZSBjb21lIEZ1bWF0cmljaSBlIE9zcGVkYWxlIChNb2QyKQ0KDQoNCmBgYHtyfQ0KIyBNb2QyPSBNb2RlbGxvIG90dGltaXp6YXRvDQptb2QyIDwtIHVwZGF0ZShtb2QxLH4gLi0gT3NwZWRhbGUgLSBGdW1hdHJpY2kpDQpzdW1tYXJ5KG1vZDIpDQoNCmBgYA0KDQojIyMgQ3JlYXppb25lIGRpIHVuIHRlcnpvIG1vZGVsbG8gYW5jb3JhIHBpw7kgcGFyc2ltb25pb3NvLCBjb24gaWwgcHJpbmNpcGlvIGRlbCBSYXNvaW8gZGkgT2NjYW0sICBkaSByZWdyZXNzaW9uZSBsaW5lYXJlIG11bHRpcGxhIGVzY2x1ZGVuZG8gdW4gdWx0ZXJpb3JpZSB2YXJpYWJpbGkgY29tZSBpbCB0aXBvIHBhcnRvIChNb2QzKQ0KDQoNCg0KYGBge3J9DQojIE1vZDI9IE1vZGVsbG8gcGnDuSBwYXJzaW1vbmlvc28NCm1vZDMgPC0gdXBkYXRlKG1vZDIsfiAuLSBUaXBvLnBhcnRvKQ0Kc3VtbWFyeShtb2QzKQ0KDQpgYGANCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQojIyMgKiozIC0gU2VsZXppb25lIGRlbCBNb2RlbGxvIGRpIFJlZ3Jlc3Npb25lIG1pZ2xpb3JlKioNCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQoNClBlciBzZWxlemlvbmFyZSBpbCBtb2RlbGxvIG1pZ2xpb3JlIHZlbmdvbm8gbWVzc2kgYSBjb25mcm9udG8gaSB0cmUgbW9kZWxsaSBjb24gbGEgdGVjbmljYSBkaSBCYXllcyAoQklDKSwgYXBwbGljYW5kbyBBTk9WQSBlIFZJRg0KDQpgYGB7cn0NCkJJQyhtb2QxLG1vZDIsbW9kMykNCmBgYA0KDQoNCmBgYHtyfQ0KYW5vdmEobW9kMyxtb2QxKQ0KYGBgDQoNCnZpZjw1DQoNCmBgYHtyfQ0KdmlmKG1vZDMpDQpgYGANCg0KDQpDb21tZW50aTpcYnINCg0KKiptb2QzKiogcmlzdWx0YSBpbCBtb2RlbGxvIG90dGltYWxlIHNlY29uZG8gaWwgQklDOiBwacO5IHNlbXBsaWNlICg3IHBhcmFtZXRyaSkgZSBjb24gaWwgbWlnbGlvciBlcXVpbGlicmlvIHRyYSBjb21wbGVzc2l0w6AgZSBhZGF0dGFtZW50by4NCg0KSW4gdGVybWluaSBkaSBzZWxlemlvbmUgZGkgdmFyaWFiaWxpLCBzaWduaWZpY2EgY2hlIHRvZ2xpZXJlIHVsdGVyaW9yaSBwcmVkaXR0b3JpIHJpc3BldHRvIGEgbW9kMiBoYSByZXNvIGlsIG1vZGVsbG8gYW5jb3JhIHBpw7kgcGFyc2ltb25pb3NvIHNlbnphIHBlZ2dpb3JhcmUgbGEgY2FwYWNpdMOgIGRpIHNwaWVnYXJlIGkgZGF0aS4NCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNCiMjIyAqKjQtIEFuYWxpc2kgZGVsbGEgcXVhbGl0w6AgZGVsIE1vZGVsbG8gZGkgUmVncmVzc2lvbmUgc2VsZXppb25hdG8qKg0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNCg0KIyMjIEFuYWxpc2kgZGVpIHJlc2lkdWkNCg0KDQoNCmBgYHtyfQ0KIyBBbmFsaXNpIGRlaSByZXNpZHVpDQoNCnBhcihtZnJvdz1jKDIsMikpDQoNCnBsb3QobW9kMykNCg0KYGBgDQoNCmBgYHtyfQ0Kc2hhcGlyby50ZXN0KHJlc2lkdWFscyhtb2QzKSkNCmBgYA0KDQoNCmBgYHtyfQ0KI2xldmVyYWdlDQpsZXY8LWhhdHZhbHVlcyhtb2QzKQ0KcGxvdChsZXYpDQpwPC1zdW0obGV2KQ0KbjwtbGVuZ3RoKGxldikNCnNvZ2xpYT0yKnAvbg0KYWJsaW5lKGg9c29nbGlhLGNvbD0yKQ0KbGV2W2xldj5zb2dsaWFdDQpgYGANCg0KDQpgYGB7cn0NCiNvdXRsaWVycw0KcGxvdChyc3R1ZGVudChtb2QzKSkNCmFibGluZShoPWMoLTIsMikpDQpjYXI6Om91dGxpZXJUZXN0KG1vZDMpDQpgYGANCg0KDQpgYGB7cn0NCiNkaXN0YW56YSBkaSBjb29rDQpjb29rPC1jb29rcy5kaXN0YW5jZShtb2QzKQ0KcGxvdChjb29rLHlsaW0gPSBjKDAsMSkpIA0KDQpgYGANCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNCmBgYHtyfQ0KIyBSwrIgZSBSTVNFDQoNCnByZWQgPC0gcHJlZGljdChtb2QzKQ0Kcm1zZShkYXRpJFBlc28sIHByZWQpDQoNCg0KYGBgDQoNCg0KDQoNCg0KDQpDb21tZW50aSBzdWxsYSBxdWFsaXTDoCBkZWwgbW9kZWxsbzoNCg0KDQotIElsIG1vZGVsbG8gbW9kMyBwcmVzZW50YSByZXNpZHVpIHF1YXNpIG5vcm1hbGksIGNvbiBxdWFsY2hlIGRldmlhemlvbmUgYWxsZSBjb2RlLg0KDQotIExhIHZpb2xhemlvbmUgZGVsbGEgbm9ybWFsaXTDoCDDqCBjb25mZXJtYXRhIGRhbCB0ZXN0LCBtYSBub24gY29zw6wgZ3JhdmUgbW9zdHJhdGUgbmVpIGdyYWZpY2kuDQoNCi0gTGEgZXRlcm9zY2VkYXN0aWNpdMOgIMOoIGxpZXZlLg0KDQotIEFsY3VuaSBvdXRsaWVyL2luZmx1ZW50aWFsIHBvaW50cyBtZXJpdGFubyBhdHRlbnppb25lLCBtYSBub24gaW52YWxpZGFubyBpbCBtb2RlbGxvDQoNCg0KLSBJbCBtb2RlbGxvIG1vZDMgc2JhZ2xpYSBkaSBjaXJjYSAyNzUgZyByaXNwZXR0byBhbCBwZXNvIHJlYWxlIGRlaSBuZW9uYXRpIChSTVNFOiAyNzQuMjM0KQ0KDQoqKkNvbnNpZGVyYW5kbyBjaGUgaWwgcGVzbyBtZWRpbyDDqCBpbnRvcm5vIGFpIDMyMDDigJMzNDAwIGcsIGzigJllcnJvcmUgw6ggY2lyY2EgbOKAmTglIGRlbCB2YWxvcmUgbWVkaW8g4oaSIHVuIGxpdmVsbG8gZGkgYWNjdXJhdGV6emEgcGl1dHRvc3RvIGJ1b25vIHBlciBkYXRpIGJpb2xvZ2ljaSwgY2hlIGhhbm5vIHNlbXByZSB2YXJpYWJpbGl0w6AgbmF0dXJhbGUuKioNCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQojIyMgKio1LSBQcmV2aXNpb25pIGRlaSByaXN1bHRhdGkqKg0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNCg0KVGVzdGlhbW8gaWwgbW9kZWxsbyBwZXIgZWZmZXR0dWFyZSBkZWxsZSBwcmV2aXNpb25pDQoNCg0KUHJldmlzaW9uZSB0ZXN0Olxicg0KUHJvdmlhbW8gYSBzdGltYXJlIGlsIHBlc28gZGkgdW5hIG5lb25hdGEgY29uc2lkZXJhbmRvIHVuYSBtYWRyZSBhbGxhIHRlcnphIGdyYXZpZGFuemEgY2hlIHBhcnRvcmlyw6AgYWxsYSAzOWVzaW1hIHNldHRpbWFuYS4NCg0KDQpgYGB7cn0NCiMgRXNlbXBpbzogbWFkcmUgYWxsYSB0ZXJ6YSBncmF2aWRhbnphLCAzOSBzZXR0aW1hbmUsIG5vbiBmdW1hdHJpY2UNCm51b3ZvIDwtIGRhdGEuZnJhbWUoDQogIEFubmkubWFkcmUgPSAzMCwNCiAgR2VzdGF6aW9uZSA9IDM5LA0KICBOLmdyYXZpZGFuemU9IDMsDQogIEx1bmdoZXp6YSA9IDUwMCwNCiAgQ3JhbmlvID0gMzQwLA0KICBTZXNzbyA9IGZhY3RvcigiRiIsIGxldmVscyA9IGxldmVscyhkYXRpJFNlc3NvKSkNCikNCg0KcHJlZGljdChtb2QzLCBudW92bywgaW50ZXJ2YWwgPSAicHJlZGljdGlvbiIpDQoNCmBgYA0KDQpDb21tZW50aTpcYnINCg0KSWwgbW9kZWxsbyBkaSByZWdyZXNzaW9uZSBtdWx0aXBsYSBtb3N0cmEgdW5hIGJ1b25hIGNhcGFjaXTDoCBwcmVkaXR0aXZhLCBjb24gdW4gUk1TRSBkaSBjaXJjYSAyNzUgZy4gUXVlc3RvIHNpZ25pZmljYSBjaGUsIGluIG1lZGlhLCBsYSBzdGltYSBkZWwgcGVzbyBuZW9uYXRhbGUgZGlmZmVyaXNjZSBkaSBtZW5vIGRpIDMwMCBnIGRhbCB2YWxvcmUgb3NzZXJ2YXRvLCB1biBtYXJnaW5lIGFjY2V0dGFiaWxlIGNvbnNpZGVyYW5kbyBsYSB2YXJpYWJpbGl0w6AgbmF0dXJhbGUgZGVpIGRhdGkgYW50cm9wb21ldHJpY2kuDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KIyMjICoqNi0gQ29uY2x1c2lvbmkgZmluYWxpKioNCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQoNCkluIHF1ZXN0byBsYXZvcm8gc29ubyBzdGF0ZSBhbmFsaXp6YXRlIGxlIG1pc3VyZSBhbnRyb3BvbWV0cmljaGUgbmVvbmF0YWxpIGNvbiBs4oCZb2JpZXR0aXZvIGRpIGNvbXByZW5kZXJlIHJlbGF6aW9uaSB0cmEgbGUgZGl2ZXJzZSB2YXJpYWJpbGkgZSBkaSBjb3N0cnVpcmUgdW4gbW9kZWxsbyBwcmVkaXR0aXZvIGRlbCBwZXNvIGFsbGEgbmFzY2l0YS4NCg0KSSByaXN1bHRhdGkgZGVpIHRlc3Qgc3RhdGlzdGljaSBoYW5ubyBtb3N0cmF0byBjaGlhcmFtZW50ZSBjaGUgaSBuZW9uYXRpIG1hc2NoaSB0ZW5kb25vIGFkIGF2ZXJlIHZhbG9yaSBtZWRpIHBpw7kgZWxldmF0aSByaXNwZXR0byBhbGxlIGZlbW1pbmUgaW4gdHV0dGUgbGUgdmFyaWFiaWxpIGNvbnNpZGVyYXRlOiBwZXNvLCBsdW5naGV6emEgZSBjaXJjb25mZXJlbnphIGNyYW5pY2EuXGJyDQoNClF1ZXN0ZSBkaWZmZXJlbnplIG5vbiBzb25vIGNhc3VhbGksIG1hIHN0YXRpc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZlLCBlIGNvbmZlcm1hbm8gcXVhbnRvIGdpw6Agb3NzZXJ2YXRvIGluIGxldHRlcmF0dXJhLlxicg0KDQoNClN1Y2Nlc3NpdmFtZW50ZSwgw6ggc3RhdG8gY29zdHJ1aXRvIHVuIG1vZGVsbG8gZGkgcmVncmVzc2lvbmUgbXVsdGlwbGEgcGVyIHN0aW1hcmUgaWwgcGVzbyBuZW9uYXRhbGUgaW4gZnVuemlvbmUgZGkgdmFyaWFiaWxpIGNvbWUgbHVuZ2hlenphLCBjcmFuaW8sIHNlc3NvLCBudW1lcm8gZGkgZ3JhdmlkYW56ZSBlIHNldHRpbWFuYSBkaSBnZXN0YXppb25lXGJyDQoNCklsIG1vZGVsbG8gaGEgbW9zdHJhdG8gdW5hICoqYnVvbmEgY2FwYWNpdMOgIGVzcGxpY2F0aXZhKio6IGxlIHZhcmlhYmlsaSBhbnRyb3BvbWV0cmljaGUgZSBvc3RldHJpY2hlIGNvbnRyaWJ1aXNjb25vIGluIG1vZG8gc2lnbmlmaWNhdGl2byBhbGxhIHByZXZpc2lvbmUgZGVsIHBlc28sIGUgbOKAmWVycm9yZSBtZWRpbyBkaSBzdGltYSAoUk1TRSkgw6ggcmlzdWx0YXRvIGRpIGNpcmNhIDI3NSBncmFtbWkuIFF1ZXN0byB2YWxvcmUsIHNlIGNvbmZyb250YXRvIGNvbiBpbCBwZXNvIG1lZGlvIGRlaSBuZW9uYXRpIGRlbCBjYW1waW9uZSAoY2lyY2EgMzIwMOKAkzM0MDAgZyksIHJhcHByZXNlbnRhIHVuIG1hcmdpbmUgZGkgZXJyb3JlIGNvbnRlbnV0byBlIGFjY2V0dGFiaWxlDQoNCkluZmluZSwgYWJiaWFtbyBhcHBsaWNhdG8gaWwgbW9kZWxsbyBhIHVuIGNhc28gcHJhdGljbzogdW5hIG5lb25hdGEsIGZpZ2xpYSBkaSB1bmEgbWFkcmUgYWxsYSB0ZXJ6YSBncmF2aWRhbnphLCBwYXJ0b3JpdGEgYWxsYSAzOcKqIHNldHRpbWFuYS4gTGEgcHJldmlzaW9uZSBoYSBzdGltYXRvIHVuIHBlc28gZGkgY2lyY2EgMzMwMCBnLCBjb24gdW4gaW50ZXJ2YWxsbyBkaSBwcmVkaXppb25lIGNvbXByZXNvIHRyYSAqKjI3ODUgZSAzODYzIGcqKi4NCg==