6.3 Cross Validation
Dalam bagian ini, kita akan mempelajari caranya:
Membandingkan dan membedakan validasi silang dengan teknik
simulasi dan metode bootstrap.
Menggunakan teknik validasi silang untuk pemilihan model
Menjelaskan metode jackknife sebagai kasus khusus validasi silang
dan menghitung estimasi bias dan kesalahan standar jackknife
Validasi silang, yang diperkenalkan secara singkat pada Bagian 4.2.4,
adalah teknik yang didasarkan pada hasil simulasi. Sekarang kita akan
membandingkan dan membedakan validasi silang dengan teknik simulasi lain
yang telah diperkenalkan dalam bab ini.”
Simulasi, atau Monte-Carlo, yang diperkenalkan pada Bagian 6.1,
memungkinkan kita untuk menghitung nilai ekspektasi dan rangkuman
distribusi statistik lainnya, seperti nilai-p, dengan mudah.
Bootstrap, dan metode resampling lainnya yang diperkenalkan pada
Bagian 6.2, menyediakan estimator presisi, atau variabilitas,
statistik.
Validasi silang penting ketika menilai seberapa akurat model
prediktif akan bekerja dalam praktiknya.
Tumpang tindih memang ada, namun tetap saja akan sangat membantu
untuk memikirkan tujuan luas yang terkait dengan setiap metode
statistik.
Untuk membahas validasi silang, mari kita ingat kembali dari Bagian
4.2 beberapa ide kunci dari validasi model. Ketika menilai, atau
memvalidasi, sebuah model, kita melihat kinerja yang diukur pada data
baru, atau setidaknya bukan data yang digunakan untuk mencocokkan model.
Pendekatan klasik, yang dijelaskan di Bagian 4.2.3, adalah membagi
sampel menjadi dua: satu bagian (dataset pelatihan) digunakan untuk
menyesuaikan model dan bagian lainnya (dataset pengujian) digunakan
untuk memvalidasi. Namun, keterbatasan dari pendekatan ini adalah bahwa
hasilnya bergantung pada pembagian; meskipun keseluruhan sampel tetap,
pembagian antara sub-sampel pelatihan dan pengujian bervariasi secara
acak. Sampel pelatihan yang berbeda berarti parameter estimasi model
akan berbeda. Parameter model yang berbeda dan sampel uji yang berbeda
berarti statistik validasi akan berbeda. Dua orang analis dapat
menggunakan data yang sama dan model yang sama, namun mencapai
kesimpulan yang berbeda tentang kelayakan suatu model (berdasarkan
pembagian acak yang berbeda), sebuah situasi yang membuat frustasi.
6.3.1 k-Fold Cross-Validation
Untuk mengurangi kesulitan ini, biasanya digunakan pendekatan
validasi silang seperti yang diperkenalkan di Bagian 4.2.4. Ide utamanya
adalah meniru pendekatan pengujian/pelatihan dasar untuk validasi model
dengan mengulanginya berkali-kali melalui rata-rata dari beberapa bagian
data yang berbeda. Keuntungan utamanya adalah bahwa statistik validasi
tidak terikat pada model parametrik (atau nonparametrik) tertentu -
seseorang dapat menggunakan statistik nonparametrik atau statistik yang
memiliki interpretasi ekonomi - sehingga dapat digunakan untuk
membandingkan model yang tidak bersarang (tidak seperti prosedur rasio
kemungkinan).
Contoh 6.3.1. Dana Properti Wisconsin. Untuk data
dana properti 2010 yang diperkenalkan pada Bagian 1.3, kami mencocokkan
distribusi gamma dan Pareto dengan 1.377 data klaim. Untuk rincian
kecocokan terkait, lihat Lampiran Bagian 15.4.4. Sekarang kita
mempertimbangkan statistik Kolmogorov-Smirnov yang diperkenalkan di
Bagian 4.1.2.2. Ketika seluruh dataset telah sesuai, statistik kecocokan
Kolmogorov-Smirnov untuk distribusi gamma adalah 0,2639 dan untuk
distribusi Pareto adalah 0,0478. Nilai yang lebih rendah untuk
distribusi Pareto menunjukkan bahwa distribusi ini lebih cocok daripada
gamma.
Untuk melihat bagaimana validasi silang k-lipatan bekerja, kami
membagi data secara acak menjadi \(k=8\) kelompok, atau lipatan, yang
masing-masing memiliki sekitar \(1377/8≈172\) pengamatan. Kemudian, kami
mencocokkan model gamma dan Pareto pada set data dengan tujuh lipatan
pertama (sekitar $172⋅7 = 120$4 pengamatan), menentukan estimasi
parameter, dan kemudian menggunakan model-model yang cocok dengan data
yang ditahan untuk menentukan statistik Kolmogorov-Smirnov.
## Loading required package: stats4
## Loading required package: splines
library(MASS)
claim_lev <- read.csv("CLAIMLEVEL.csv", header = TRUE)
claim_data <- subset(claim_lev, Year == 2010);
# Randomly re-order the data - "shuffle it"
n <- nrow(claim_data)
set.seed(12347)
cvdata <- claim_data[sample(n), ]
# Number of folds
k <- 8
cvalvec <- matrix(0,2,k)
for (i in 1:k) {
indices <- (((i-1) * round((1/k)*nrow(cvdata))) + 1):((i*round((1/k) * nrow(cvdata))))
# Pareto
fit.pareto <- vglm(Claim ~ 1, paretoII, loc = 0, data = cvdata[-indices,])
ksResultPareto <- ks.test(cvdata[indices,]$Claim, "pparetoII", loc = 0, shape = exp(coef(fit.pareto)[2]),
scale = exp(coef(fit.pareto)[1]))
cvalvec[1,i] <- ksResultPareto$statistic
# Gamma
fit.gamma <- glm(Claim ~ 1, data = cvdata[-indices,], family = Gamma(link = log))
gamma_theta <- exp(coef(fit.gamma)) * gamma.dispersion(fit.gamma)
alpha <- 1 / gamma.dispersion(fit.gamma)
ksResultGamma <- ks.test(cvdata[indices,]$Claim, "pgamma", shape = alpha, scale = gamma_theta)
cvalvec[2,i] <- ksResultGamma$statistic
}
KScv <- rowSums(cvalvec)/k
Hasilnya tampak pada Gambar 6.12 di mana sumbu horizontal adalah
Fold=1. Proses ini diulangi untuk tujuh lipatan lainnya. Hasil yang
dirangkum dalam Gambar 6.12 menunjukkan bahwa Pareto secara konsisten
memberikan distribusi prediktif yang lebih dapat diandalkan daripada
gamma.
# Plot the statistics
matplot(1:k,t(cvalvec),type="b", col=c(1,3), lty=1:2,
ylim=c(0,0.4), pch = 0, xlab="Fold", ylab="KS Statistic")
legend("left", c("Pareto", "Gamma"), col=c(1,3),lty=1:2, bty="n")
“Figure 6.2:” Statistik Kolmogorov-Smirnov (KS) yang telah
divalidasi silang untuk Data Klaim Dana Asuransi. Garis hitam
solid untuk distribusi Pareto, garis putus-putus hijau untuk distribusi
gamma. Statistik KS mengukur deviasi terbesar antara distribusi yang
sesuai dengan distribusi empiris untuk masing-masing dari 8 kelompok,
atau lipatan, data yang dipilih secara acak.
6.3.2 Leave-One-Out Cross-Validation
Kasus khusus di mana \(k=n\) dikenal
sebagai validasi silang tinggalkan-satu-keluar. Kasus ini secara
historis sangat menonjol dan terkait erat dengan jackknifestatistik yang
merupakan pendahulu dari teknik bootstrap.
Meskipun kita menyajikannya sebagai kasus khusus validasi silang,
akan sangat membantu jika kami memberikan definisi eksplisit.
Pertimbangkan sebuah statistik umum \(θˆ =
t(x)\) yang merupakan penaksir untuk sebuah parameter yang
diminati \(θ\). Ide dari jackknife
adalah menghitung n nilai \(θˆ_{-i} =
t(x-i)\), di mana \(x-i\) adalah
subsampel dari \(x\) dengan nilai \(ke-i\) dihilangkan. Rata-rata dari
nilai-nilai ini dilambangkan sebagai
\[\overline{\widehat{\theta}}_{(\cdot)}=\frac{1}{n}\sum_{i=1}^n
\widehat{\theta}_{-i} .\]
Nilai-nilai ini dapat digunakan untuk membuat estimasi bias dari
statistik \(\hatθ\)
\[\begin{equation}
Bias_{jack} = (n-1) \left(\overline{\widehat{\theta}}_{(\cdot)} -
\widehat{\theta}\right)
\tag{6.3}
\end{equation}\]
serta estimasi standar deviasi
\[\begin{equation}
s_{jack} =\sqrt{\frac{n-1}{n}\sum_{i=1}^n \left(\widehat{\theta}_{-i}
-\overline{\widehat{\theta}}_{(\cdot)}\right)^2} ~.
\tag{6.4}
\end{equation}\]
Contoh 6.3.2. Koefisien Variasi. Sebagai ilustrasi,
pertimbangkan sebuah sampel fiktif kecil \(x =
{x_1,...,x_n}\) dengan realisasi
sample_x <- c(2.46,2.80,3.28,3.86,2.85,3.67,3.37,3.40,
5.22,2.55,2.79,4.50,3.37,2.88,1.44,2.56,2.00,2.07,2.19,1.77)
Misalkan kita tertarik dengan \(\theta = CV
= \sqrt{\mathrm{Var~}[X]}/\mathrm{E~}[X]\)
Dengan dataset ini, estimator koefisien variasi menjadi 0,31196.
Namun, seberapa handalkah estimasi tersebut? Untuk menjawab pertanyaan
ini, kita dapat menghitung estimator pisau lipat dari bias dan deviasi
standarnya. Kode berikut ini menunjukkan bahwa penaksir jackknife untuk
bias adalah \(Bias_{jack} = -0,00627\)
dan standar deviasi jackknife adalah \(s_{jack} = 0,01293\).
CVar <- function(x) sqrt(var(x))/mean(x)
JackCVar <- function(i) sqrt(var(sample_x[-i]))/mean(sample_x[-i])
JackTheta <- Vectorize(JackCVar)(1:length(sample_x))
BiasJack <- (length(sample_x)-1)*(mean(JackTheta) - CVar(sample_x))
sd(JackTheta)
## [1] 0.01293001
Contoh 6.3.3. Klaim Cidera Badan dan Rasio Eliminasi
Kerugian. Pada Contoh 6.2.1, kita telah menunjukkan bagaimana
menghitung estimasi bootstrap dari bias dan deviasi standar untuk rasio
eliminasi kerugian dengan menggunakan data klaim cedera badan pada
Contoh 4.1.11. Sekarang kita menindaklanjuti dengan memberikan jumlah
yang sebanding dengan menggunakan statistik jackknife.
Tabel 6.7 merangkum hasil estimasi jackknife. Tabel ini menunjukkan
bahwa estimasi jackknife terhadap bias dan deviasi standar dari rasio
eliminasi kerugian \(E [min (X, d)]/E
[X]\) sebagian besar konsisten dengan metodologi bootstrap.
Selain itu, kita dapat menggunakan standar deviasi untuk membangun
interval kepercayaan berbasis normal, yang berpusat di sekitar penaksir
yang dikoreksi bias. Sebagai contoh, pada \(d
= 14000\), kita melihat pada Contoh 4.1.11 bahwa estimasi
nonparametrik dari \(LER\) adalah
0.97678. Estimasi ini memiliki bias sebesar 0,00010, sehingga
menghasilkan estimator terkoreksi-bias sebesar 0,97688. Interval
kepercayaan 95% dihasilkan dengan membuat interval dua kali panjang 1,96
deviasi standar jackknife, yang berpusat pada estimator terkoreksi bias
(1,96 adalah perkiraan kuantil ke-97,5 dari distribusi normal
standar).
##
## Attaching package: 'boot'
## The following objects are masked from 'package:VGAM':
##
## logit, simplex
# Example from Derrig et al
BIData <- read.csv("DerrigResampling.csv", header =T)
BIData$Censored <- 1*(BIData$AmountPaid >= BIData$PolicyLimit)
BIDataUncensored <- subset(BIData, Censored == 0)
LER.boot <- function(ded, data, indices){
resample.data <- data[indices,]
sumClaims <- sum(resample.data$AmountPaid)
sumClaims_d <- sum(pmin(resample.data$AmountPaid,ded))
LER <- sumClaims_d/sumClaims
return(LER)
}
x <- BIDataUncensored$AmountPaid
LER.jack<- function(ded,i){
LER <- sum(pmin(x[-i],ded))/sum(x[-i])
return(LER)
}
LER <- function(ded) sum(pmin(x,ded))/sum(x)
##Derrig et al
set.seed(2019)
dVec2 <- c(4000, 5000, 10500, 11500, 14000, 18500)
OutJack <- matrix(0,length(dVec2),8)
for (j in 1:length(dVec2)) {
OutJack[j,1] <- dVec2[j]
results <- boot(data=BIDataUncensored, statistic=LER.boot, R=1000, ded=dVec2[j])
OutJack[j,2] <- results$t0
biasboot <- mean(results$t)-results$t0 -> OutJack[j,3]
sdboot <- sd(results$t) -> OutJack[j,4]
temp <- boot.ci(results)
LER.jack.ded<- function(i) LER.jack(ded=dVec2[j],i)
JackTheta.ded <- Vectorize(LER.jack.ded)(1:length(x))
OutJack[j,5] <- BiasJack.ded <- (length(x)-1)*(mean(JackTheta.ded) - LER(ded=dVec2[j]))
OutJack[j,6] <- sd(JackTheta.ded)
OutJack[j,7:8] <- mean(JackTheta.ded)+qt(c(0.025,0.975),length(x)-1)*OutJack[j,6]
}
Table 6.7. Estimasi Jackknife dari LER pada Deductible yang
Dipilih
|
d
|
NP Estimate
|
Bootstrap Bias
|
Bootstrap SD
|
Jackknife Bias
|
Jackknife SD
|
Lower Jackknife 95% CI
|
Upper Jackknife 95% CI
|
|
4000
|
0.54113
|
0.00011
|
0.01237
|
0.00031
|
0.00061
|
0.53993
|
0.54233
|
|
5000
|
0.64960
|
0.00027
|
0.01412
|
0.00033
|
0.00068
|
0.64825
|
0.65094
|
|
10500
|
0.93563
|
0.00004
|
0.01017
|
0.00019
|
0.00053
|
0.93460
|
0.93667
|
|
11500
|
0.95281
|
-0.00003
|
0.00941
|
0.00016
|
0.00047
|
0.95189
|
0.95373
|
|
14000
|
0.97678
|
0.00016
|
0.00687
|
0.00010
|
0.00034
|
0.97612
|
0.97745
|
|
18500
|
0.99382
|
0.00014
|
0.00331
|
0.00003
|
0.00017
|
0.99350
|
0.99415
|
Diskusi. Salah satu dari banyak hal menarik tentang kasus khusus
leave-one-out adalah kemampuan untuk mereplikasi estimasi dengan tepat.
Artinya, ketika ukuran lipatan hanya satu, maka tidak ada ketidakpastian
tambahan yang disebabkan oleh validasi silang. Ini berarti bahwa para
analis dapat mereplikasi pekerjaan satu sama lain dengan tepat, sebuah
pertimbangan yang penting.
Statistik Jackknife dikembangkan untuk memahami ketepatan estimator,
menghasilkan estimator bias dan deviasi standar pada persamaan (6.3) dan
(6.4). Hal ini sesuai dengan tujuan yang telah kita kaitkan dengan
teknik bootstrap, bukan metode validasi silang. Hal ini menunjukkan
bagaimana teknik statistik dapat digunakan untuk mencapai tujuan yang
berbeda.
6.3.3 Cross-Validation and Bootstrap
Bootstrap berguna untuk memberikan estimator presisi, atau
variabilitas, dari statistik. Hal ini juga berguna untuk validasi model.
Pendekatan bootstrap untuk validasi model mirip dengan prosedur validasi
leave-one-out dan k-fold:
Buat sampel bootstrap dengan mengambil sampel ulang (dengan
penggantian) \(n\) indeks dalam \({1, ⋯, n}\). Ini akan menjadi sampel
pelatihan kita. Perkirakan model yang sedang dipertimbangkan berdasarkan
sampel ini.
Uji, atau sampel validasi, terdiri dari
pengamatan yang tidak dipilih untuk pelatihan. Mengevaluasi model yang
cocok (berdasarkan data pelatihan) dengan menggunakan data uji.
Ulangi proses ini beberapa kali (katakanlah \(B\)). Ambil rata-rata dari hasil-hasilnya
dan pilih model berdasarkan statistik evaluasi rata-rata.
Contoh 6.3.4. Dana Properti Wisconsin. Kembali ke
Contoh 6.3.1 di mana kita menyelidiki kecocokan distribusi gamma dan
Pareto pada data dana properti. Kita kembali membandingkan kinerja
prediksi menggunakan statistik Kolmogorov-Smirnov (KS), namun kali ini
menggunakan prosedur bootstrap untuk membagi data antara sampel
pelatihan dan pengujian. Berikut ini adalah kode ilustrasinya.
library(goftest)
n <- nrow(claim_data)
set.seed(12347)
indices <- 1:n
# Number of Bootstrap Samples
B <- 100
cvalvec <- matrix(0,2,B)
for (i in 1:B) {
bootindex <- unique(sample(indices, size=n, replace= TRUE))
traindata <- claim_data[bootindex,]
testdata <- claim_data[-bootindex,]
# Pareto
fit.pareto <- vglm(Claim ~ 1, paretoII, loc = 0, data = traindata)
ksResultPareto <- ks.test(testdata$Claim, "pparetoII", loc = 0, shape = exp(coef(fit.pareto)[2]),
scale = exp(coef(fit.pareto)[1]))
cvalvec[1,i] <- ksResultPareto$statistic
# Gamma
fit.gamma <- glm(Claim ~ 1, data = traindata, family = Gamma(link = log))
gamma_theta <- exp(coef(fit.gamma)) * gamma.dispersion(fit.gamma)
alpha <- 1 / gamma.dispersion(fit.gamma)
ksResultGamma <- ks.test(testdata$Claim, "pgamma", shape = alpha, scale = gamma_theta)
cvalvec[2,i] <- ksResultGamma$statistic
}
KSBoot <- rowSums(cvalvec)/B
Kami melakukan pengambilan sampel dengan menggunakan B= 100 ulangan.
Statistik KS rata-rata untuk distribusi Pareto adalah 0,058 dibandingkan
dengan rata-rata untuk distribusi gamma, 0,262. Hal ini konsisten dengan
hasil sebelumnya dan memberikan bukti lain bahwa Pareto adalah model
yang lebih baik untuk data ini dibandingkan dengan gamma.
6.4 Importance Sampling
Bagian 6.1 memperkenalkan teknik Monte Carlo dengan menggunakan
teknik inversi: untuk membangkitkan sebuah variabel acak \(X\) dengan distribusi \(F\), terapkan \(F^{-1}\) pada pemanggilan sebuah generator
acak (seragam pada interval satuan). Bagaimana jika kita ingin
menggambar sesuai dengan \(X\), dengan
syarat \(X∈[a,b]\)?
Seseorang dapat menggunakan mekanisme terima-tolak: menarik \(x\) dari distribusi \(F\)
jika \(x\in[a,b]\): simpan
(“terima”)
jika \(x\notin[a,b]\): gambar
yang lain (“tolak”)
Amati bahwa dari n nilai yang awalnya dihasilkan, kita simpan di sini
hanya \([F(b)-F(a)] ⋅ n\) hasil imbang,
rata-rata.
Contoh 6.4.1. Penarikan dari Distribusi Normal.
Misalkan kita menggambar dari distribusi normal dengan rata-rata 2,5 dan
varians 1, \(N(2,5,1)\), tetapi hanya
tertarik pada gambar yang lebih besar dari \(a≥2\) dan kurang dari \(b≤4\). Artinya, kita hanya dapat
menggunakan \(F(4)-F(2)=Φ(4-2.5)-Φ(2-2.5) =
0.9332 - 0.3085 = 0.6247\) proporsi undian. Gambar 6.13
menunjukkan bahwa beberapa hasil undian berada di dalam interval \((2,4)\) dan beberapa di luarnya.
mu = 2.5
sigma = 1
a = 2
b = 4
Fa = pnorm(a,mu,sigma)
Fb = pnorm(b,mu,sigma)
pic_ani = function(){
u=seq(0,5,by=.01)
plot(u,pnorm(u,mu,sigma),col="white",ylab="",xlab="")
rect(-1,-1,6,2,col=rgb(1,0,0,.2),border=NA)
rect(a,Fa,b,Fb,col="white",border=NA)
lines(u,pnorm(u,mu,sigma),lwd=2)
abline(v=c(a,b),lty=2,col="red")
ru <- runif(1)
clr <- "red"
if((qnorm(ru,mu,sigma)>=a)&(qnorm(ru,mu,sigma)<=b)) clr <- "blue"
segments(-1,ru,qnorm(ru,mu,sigma),ru,col=clr,lwd=2)
arrows(qnorm(ru,mu,sigma),ru,qnorm(ru,mu,sigma),0,col=clr,lwd=2,length = .1)
}
for (i in 1:numAnimation) {pic_ani()}

Sebagai gantinya, seseorang dapat menggambar menurut distribusi
bersyarat \(F^⋆\) yang didefinisikan
sebagai
\[F^{\star}(x) = \Pr(X \le x | a < X
\le b) =\frac{F(x)-F(a)}{F(b)-F(a)}, \ \ \ \text{for } a < x \le b
.\] Dengan menggunakan metode inverse transform pada Bagian
6.1.2, kita mendapatkan hasil imbang
\[X^\star=F^{\star-1}\left( U \right) =
F^{-1}\left(F(a)+U\cdot[F(b)-F(a)]\right)\]
memiliki distribusi \(F⋆^\).
Dinyatakan dengan cara lain, definisikan
\[\tilde{U} = (1-U)\cdot F(a)+U\cdot
F(b)\]
dan kemudian gunakan \(F^{-1}(\tilde{U})\). Dengan pendekatan ini,
setiap undian dihitung.
Hal ini dapat dikaitkan dengan mekanisme pengambilan sampel
kepentingan: kita menarik lebih sering di wilayah yang kita harapkan
memiliki kuantitas yang memiliki kepentingan. Transformasi ini dapat
dianggap sebagai “perubahan ukuran.”
pic_ani = function(){
u=seq(0,5,by=.01)
plot(u,pnorm(u,mu,sigma),col="white",ylab="",xlab="")
rect(-1,-1,6,2,col=rgb(1,0,0,.2),border=NA)
rect(a,Fa,b,Fb,col="white",border=NA)
lines(u,pnorm(u,mu,sigma),lwd=2)
abline(h=pnorm(c(a,b),mu,sigma),lty=2,col="red")
ru <- runif(1)
rutilde <- (1-ru)*Fa+ru*Fb
segments(-1,rutilde,qnorm(rutilde,mu,sigma),rutilde,col="blue",lwd=2)
arrows(qnorm(rutilde,mu,sigma),rutilde,qnorm(rutilde,mu,sigma),0,col="blue",lwd=2,length = .1)
}
for (i in 1:numAnimation) {pic_ani()}

Pada Contoh 6.4.1., kebalikan dari distribusi normal sudah tersedia
(dalam R, fungsinya adalah qnorm). Namun,
untuk aplikasi lain, hal ini tidak terjadi. Kemudian, kita cukup
menggunakan metode numerik untuk menentukan \(X^⋆\) sebagai solusi dari persamaan \(F(X^\star) =\tilde{U}\) di mana \(\tilde{U}=(1-U)\cdot F(a)+U\cdot F(b)\)).
Lihat kode ilustrasi berikut ini.
pic_ani = function(){
u=seq(0,5,by=.01)
plot(u,pnorm(u,mu,sigma),col="white",ylab="",xlab="")
rect(-1,-1,6,2,col=rgb(1,0,0,.2),border=NA)
rect(2,-1,4,2,col="white",border=NA)
lines(u,pnorm(u,mu,sigma),lty=2)
pnormstar <- Vectorize(function(x){
y=(pnorm(x,mu,sigma)-Fa)/(Fb-Fa)
if(x<=a) y <- 0
if(x>=b) y <- 1
return(y)
})
qnormstar <- function(u) as.numeric(uniroot((function (x) pnormstar(x) - u), lower = 2, upper = 4)[1])
lines(u,pnormstar(u),lwd=2)
abline(v=c(2,4),lty=2,col="red")
ru <- runif(1)
segments(-1,ru,qnormstar(ru),ru,col="blue",lwd=2)
arrows(qnormstar(ru),ru,qnormstar(ru),0,col="blue",lwd=2,length = .1)
}
for (i in 1:numAnimation) {pic_ani()}

LS0tDQp0aXRsZTogIlRlb3JpIFJpc2lrbyINCnN1YnRpdGxlOiAiU2ltdWxhdGlvbiBhbmQgUmVzYW1wbGluZyINCmF1dGhvcjogIllvc2lhIg0KZGF0ZTogICIxMy8wMy8yMDIzIg0Kb3V0cHV0Og0KICBybWRmb3JtYXRzOjpyb2JvYm9vazogICAjIGh0dHBzOi8vZ2l0aHViLmNvbS9qdWJhL3JtZGZvcm1hdHMNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICB0aGVtZTogc2FuZHN0b25lDQogICAgdGh1bWJuYWlsczogdHJ1ZQ0KICAgIGxpZ2h0Ym94OiB0cnVlDQogICAgZ2FsbGVyeTogdHJ1ZQ0KICAgIGxpYl9kaXI6IGxpYnMNCiAgICBkZl9wcmludDogInBhZ2VkIg0KICAgIGNvZGVfZm9sZGluZzogInNob3ciDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY3NzOiAic3R5bGUuY3NzIg0KDQotLS0NCg0KPEJPRFkgew0KIHVzZXItc2VsZWN0Om5vbmU7DQogLW1vei11c2VyLXNlbGVjdDpub25lOw0KIC1tcy11c2VyLXNlbGVjdDpub25lOw0KIC1raHRtbC11c2VyLXNlbGVjdDpub25lOw0KIC13ZWJraXQtdXNlci1zZWxlY3Q6bm9uZQ0KfS8+DQoNCjxicj4NCg0KPGltZyBzdHlsZT0iZmxvYXQ6IHJpZ2h0OyBtYXJnaW46IC01MHB4IDUwcHggMHB4IDUwcHg7IHdpZHRoOjMwJSIgc3JjPSJkb3dubG9hZC5wbmciLz4gDQoNCnwNCjotLS0tIHw6LS0tLQ0KKipLb250YWsqKnwgKio6ICRcZG93bmFycm93JCoqDQpFbWFpbHwgeW9zaWEueW9zaWFAc3R1ZGVudC5tYXRhbmF1bml2ZXJzaXR5LmFjLmlkDQpJbnN0YWdyYW0gfCBbeXlvc2lhXShodHRwczovL3d3dy5pbnN0YWdyYW0uY29tL3l5b3NpYS8pIA0KUlB1YnMgIHwgaHR0cHM6Ly9ycHVicy5jb20veW9zaWEvDQoNCioqKg0KDQojIDYuMyBDcm9zcyBWYWxpZGF0aW9uICAgIA0KDQpEYWxhbSBiYWdpYW4gaW5pLCBraXRhIGFrYW4gbWVtcGVsYWphcmkgY2FyYW55YToNCg0KKiBNZW1iYW5kaW5na2FuIGRhbiBtZW1iZWRha2FuIHZhbGlkYXNpIHNpbGFuZyBkZW5nYW4gdGVrbmlrIHNpbXVsYXNpIGRhbiBtZXRvZGUgYm9vdHN0cmFwLg0KDQoqCU1lbmdndW5ha2FuIHRla25payB2YWxpZGFzaSBzaWxhbmcgdW50dWsgcGVtaWxpaGFuIG1vZGVsDQoNCioJTWVuamVsYXNrYW4gbWV0b2RlIGphY2trbmlmZSBzZWJhZ2FpIGthc3VzIGtodXN1cyB2YWxpZGFzaSBzaWxhbmcgZGFuIG1lbmdoaXR1bmcgZXN0aW1hc2kgYmlhcyBkYW4ga2VzYWxhaGFuIHN0YW5kYXIgamFja2tuaWZlDQoNClZhbGlkYXNpIHNpbGFuZywgeWFuZyBkaXBlcmtlbmFsa2FuIHNlY2FyYSBzaW5na2F0IHBhZGEgQmFnaWFuIDQuMi40LCBhZGFsYWggdGVrbmlrIHlhbmcgZGlkYXNhcmthbiBwYWRhIGhhc2lsIHNpbXVsYXNpLiBTZWthcmFuZyBraXRhIGFrYW4gbWVtYmFuZGluZ2thbiBkYW4gbWVtYmVkYWthbiB2YWxpZGFzaSBzaWxhbmcgZGVuZ2FuIHRla25payBzaW11bGFzaSBsYWluIHlhbmcgdGVsYWggZGlwZXJrZW5hbGthbiBkYWxhbSBiYWIgaW5pLiINCg0KKglTaW11bGFzaSwgYXRhdSBNb250ZS1DYXJsbywgeWFuZyBkaXBlcmtlbmFsa2FuIHBhZGEgQmFnaWFuIDYuMSwgbWVtdW5na2lua2FuIGtpdGEgdW50dWsgbWVuZ2hpdHVuZyBuaWxhaSBla3NwZWt0YXNpIGRhbiByYW5na3VtYW4gZGlzdHJpYnVzaSBzdGF0aXN0aWsgbGFpbm55YSwgc2VwZXJ0aSBuaWxhaS1wLCBkZW5nYW4gbXVkYWguDQoNCiogQm9vdHN0cmFwLCBkYW4gbWV0b2RlIHJlc2FtcGxpbmcgbGFpbm55YSB5YW5nIGRpcGVya2VuYWxrYW4gcGFkYSBCYWdpYW4gNi4yLCBtZW55ZWRpYWthbiBlc3RpbWF0b3IgcHJlc2lzaSwgYXRhdSB2YXJpYWJpbGl0YXMsIHN0YXRpc3Rpay4NCg0KKglWYWxpZGFzaSBzaWxhbmcgcGVudGluZyBrZXRpa2EgbWVuaWxhaSBzZWJlcmFwYSBha3VyYXQgbW9kZWwgcHJlZGlrdGlmIGFrYW4gYmVrZXJqYSBkYWxhbSBwcmFrdGlrbnlhLg0KDQpUdW1wYW5nIHRpbmRpaCBtZW1hbmcgYWRhLCBuYW11biB0ZXRhcCBzYWphIGFrYW4gc2FuZ2F0IG1lbWJhbnR1IHVudHVrIG1lbWlraXJrYW4gdHVqdWFuIGx1YXMgeWFuZyB0ZXJrYWl0IGRlbmdhbiBzZXRpYXAgbWV0b2RlIHN0YXRpc3Rpay4NCiAgICANClVudHVrIG1lbWJhaGFzIHZhbGlkYXNpIHNpbGFuZywgbWFyaSBraXRhIGluZ2F0IGtlbWJhbGkgZGFyaSBCYWdpYW4gNC4yIGJlYmVyYXBhIGlkZSBrdW5jaSBkYXJpIHZhbGlkYXNpIG1vZGVsLiBLZXRpa2EgbWVuaWxhaSwgYXRhdSBtZW12YWxpZGFzaSwgc2VidWFoIG1vZGVsLCBraXRhIG1lbGloYXQga2luZXJqYSB5YW5nIGRpdWt1ciBwYWRhIGRhdGEgYmFydSwgYXRhdSBzZXRpZGFrbnlhIGJ1a2FuIGRhdGEgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuY29jb2trYW4gbW9kZWwuIFBlbmRla2F0YW4ga2xhc2lrLCB5YW5nIGRpamVsYXNrYW4gZGkgQmFnaWFuIDQuMi4zLCBhZGFsYWggbWVtYmFnaSBzYW1wZWwgbWVuamFkaSBkdWE6IHNhdHUgYmFnaWFuIChkYXRhc2V0IHBlbGF0aWhhbikgZGlndW5ha2FuIHVudHVrIG1lbnllc3VhaWthbiBtb2RlbCBkYW4gYmFnaWFuIGxhaW5ueWEgKGRhdGFzZXQgcGVuZ3VqaWFuKSBkaWd1bmFrYW4gdW50dWsgbWVtdmFsaWRhc2kuIE5hbXVuLCBrZXRlcmJhdGFzYW4gZGFyaSBwZW5kZWthdGFuIGluaSBhZGFsYWggYmFod2EgaGFzaWxueWEgYmVyZ2FudHVuZyBwYWRhIHBlbWJhZ2lhbjsgbWVza2lwdW4ga2VzZWx1cnVoYW4gc2FtcGVsIHRldGFwLCBwZW1iYWdpYW4gYW50YXJhIHN1Yi1zYW1wZWwgcGVsYXRpaGFuIGRhbiBwZW5ndWppYW4gYmVydmFyaWFzaSBzZWNhcmEgYWNhay4gU2FtcGVsIHBlbGF0aWhhbiB5YW5nIGJlcmJlZGEgYmVyYXJ0aSBwYXJhbWV0ZXIgZXN0aW1hc2kgbW9kZWwgYWthbiBiZXJiZWRhLiBQYXJhbWV0ZXIgbW9kZWwgeWFuZyBiZXJiZWRhIGRhbiBzYW1wZWwgdWppIHlhbmcgYmVyYmVkYSBiZXJhcnRpIHN0YXRpc3RpayB2YWxpZGFzaSBha2FuIGJlcmJlZGEuIER1YSBvcmFuZyBhbmFsaXMgZGFwYXQgbWVuZ2d1bmFrYW4gZGF0YSB5YW5nIHNhbWEgZGFuIG1vZGVsIHlhbmcgc2FtYSwgbmFtdW4gbWVuY2FwYWkga2VzaW1wdWxhbiB5YW5nIGJlcmJlZGEgdGVudGFuZyBrZWxheWFrYW4gc3VhdHUgbW9kZWwgKGJlcmRhc2Fya2FuIHBlbWJhZ2lhbiBhY2FrIHlhbmcgYmVyYmVkYSksIHNlYnVhaCBzaXR1YXNpIHlhbmcgbWVtYnVhdCBmcnVzdGFzaS4NCg0KIyMgNi4zLjEgay1Gb2xkIENyb3NzLVZhbGlkYXRpb24NCg0KVW50dWsgbWVuZ3VyYW5naSBrZXN1bGl0YW4gaW5pLCBiaWFzYW55YSBkaWd1bmFrYW4gcGVuZGVrYXRhbiB2YWxpZGFzaSBzaWxhbmcgc2VwZXJ0aSB5YW5nIGRpcGVya2VuYWxrYW4gZGkgQmFnaWFuIDQuMi40LiBJZGUgdXRhbWFueWEgYWRhbGFoIG1lbmlydSBwZW5kZWthdGFuIHBlbmd1amlhbi9wZWxhdGloYW4gZGFzYXIgdW50dWsgdmFsaWRhc2kgbW9kZWwgZGVuZ2FuIG1lbmd1bGFuZ2lueWEgYmVya2FsaS1rYWxpIG1lbGFsdWkgcmF0YS1yYXRhIGRhcmkgYmViZXJhcGEgYmFnaWFuIGRhdGEgeWFuZyBiZXJiZWRhLiBLZXVudHVuZ2FuIHV0YW1hbnlhIGFkYWxhaCBiYWh3YSBzdGF0aXN0aWsgdmFsaWRhc2kgdGlkYWsgdGVyaWthdCBwYWRhIG1vZGVsIHBhcmFtZXRyaWsgKGF0YXUgbm9ucGFyYW1ldHJpaykgdGVydGVudHUgLSBzZXNlb3JhbmcgZGFwYXQgbWVuZ2d1bmFrYW4gc3RhdGlzdGlrIG5vbnBhcmFtZXRyaWsgYXRhdSBzdGF0aXN0aWsgeWFuZyBtZW1pbGlraSBpbnRlcnByZXRhc2kgZWtvbm9taSAtIHNlaGluZ2dhIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW1iYW5kaW5na2FuIG1vZGVsIHlhbmcgdGlkYWsgYmVyc2FyYW5nICh0aWRhayBzZXBlcnRpIHByb3NlZHVyIHJhc2lvIGtlbXVuZ2tpbmFuKS4NCg0KKipDb250b2ggNi4zLjEuIERhbmEgUHJvcGVydGkgV2lzY29uc2luLioqIFVudHVrIGRhdGEgZGFuYSBwcm9wZXJ0aSAyMDEwIHlhbmcgZGlwZXJrZW5hbGthbiBwYWRhIEJhZ2lhbiAxLjMsIGthbWkgbWVuY29jb2trYW4gZGlzdHJpYnVzaSBnYW1tYSBkYW4gUGFyZXRvIGRlbmdhbiAxLjM3NyBkYXRhIGtsYWltLiBVbnR1ayByaW5jaWFuIGtlY29jb2thbiB0ZXJrYWl0LCBsaWhhdCBMYW1waXJhbiBCYWdpYW4gMTUuNC40LiBTZWthcmFuZyBraXRhIG1lbXBlcnRpbWJhbmdrYW4gc3RhdGlzdGlrIEtvbG1vZ29yb3YtU21pcm5vdiB5YW5nIGRpcGVya2VuYWxrYW4gZGkgQmFnaWFuIDQuMS4yLjIuIEtldGlrYSBzZWx1cnVoIGRhdGFzZXQgdGVsYWggc2VzdWFpLCBzdGF0aXN0aWsga2Vjb2Nva2FuIEtvbG1vZ29yb3YtU21pcm5vdiB1bnR1ayBkaXN0cmlidXNpIGdhbW1hIGFkYWxhaCAwLDI2MzkgZGFuIHVudHVrIGRpc3RyaWJ1c2kgUGFyZXRvIGFkYWxhaCAwLDA0NzguIE5pbGFpIHlhbmcgbGViaWggcmVuZGFoIHVudHVrIGRpc3RyaWJ1c2kgUGFyZXRvIG1lbnVuanVra2FuIGJhaHdhIGRpc3RyaWJ1c2kgaW5pIGxlYmloIGNvY29rIGRhcmlwYWRhIGdhbW1hLg0KDQpVbnR1ayBtZWxpaGF0IGJhZ2FpbWFuYSB2YWxpZGFzaSBzaWxhbmcgay1saXBhdGFuIGJla2VyamEsIGthbWkgbWVtYmFnaSBkYXRhIHNlY2FyYSBhY2FrIG1lbmphZGkgJGs9OCQga2Vsb21wb2ssIGF0YXUgbGlwYXRhbiwgeWFuZyBtYXNpbmctbWFzaW5nIG1lbWlsaWtpIHNla2l0YXIgJDEzNzcvOOKJiDE3MiQgcGVuZ2FtYXRhbi4gS2VtdWRpYW4sIGthbWkgbWVuY29jb2trYW4gbW9kZWwgZ2FtbWEgZGFuIFBhcmV0byBwYWRhIHNldCBkYXRhIGRlbmdhbiB0dWp1aCBsaXBhdGFuIHBlcnRhbWEgKHNla2l0YXIgJDE3MuKLhTcgPSAxMjAkNCBwZW5nYW1hdGFuKSwgbWVuZW50dWthbiBlc3RpbWFzaSBwYXJhbWV0ZXIsIGRhbiBrZW11ZGlhbiBtZW5nZ3VuYWthbiBtb2RlbC1tb2RlbCB5YW5nIGNvY29rIGRlbmdhbiBkYXRhIHlhbmcgZGl0YWhhbiB1bnR1ayBtZW5lbnR1a2FuIHN0YXRpc3RpayBLb2xtb2dvcm92LVNtaXJub3YuDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShWR0FNKQ0KbGlicmFyeShNQVNTKQ0KY2xhaW1fbGV2IDwtIHJlYWQuY3N2KCJDTEFJTUxFVkVMLmNzdiIsIGhlYWRlciA9IFRSVUUpIA0KY2xhaW1fZGF0YSA8LSBzdWJzZXQoY2xhaW1fbGV2LCBZZWFyID09IDIwMTApOyANCg0KIyBSYW5kb21seSByZS1vcmRlciB0aGUgZGF0YSAtICJzaHVmZmxlIGl0Ig0KbiA8LSBucm93KGNsYWltX2RhdGEpDQpzZXQuc2VlZCgxMjM0NykNCmN2ZGF0YSA8LSBjbGFpbV9kYXRhW3NhbXBsZShuKSwgXQ0KIyBOdW1iZXIgb2YgZm9sZHMNCmsgPC0gOA0KY3ZhbHZlYyA8LSBtYXRyaXgoMCwyLGspDQpmb3IgKGkgaW4gMTprKSB7DQogIGluZGljZXMgPC0gKCgoaS0xKSAqIHJvdW5kKCgxL2spKm5yb3coY3ZkYXRhKSkpICsgMSk6KChpKnJvdW5kKCgxL2spICogbnJvdyhjdmRhdGEpKSkpDQojIFBhcmV0bw0KICBmaXQucGFyZXRvIDwtIHZnbG0oQ2xhaW0gfiAxLCBwYXJldG9JSSwgbG9jID0gMCwgZGF0YSA9IGN2ZGF0YVstaW5kaWNlcyxdKQ0KICBrc1Jlc3VsdFBhcmV0byA8LSBrcy50ZXN0KGN2ZGF0YVtpbmRpY2VzLF0kQ2xhaW0sICJwcGFyZXRvSUkiLCBsb2MgPSAwLCBzaGFwZSA9IGV4cChjb2VmKGZpdC5wYXJldG8pWzJdKSwgDQogICAgICAgIHNjYWxlID0gZXhwKGNvZWYoZml0LnBhcmV0bylbMV0pKQ0KICBjdmFsdmVjWzEsaV0gPC0ga3NSZXN1bHRQYXJldG8kc3RhdGlzdGljDQojIEdhbW1hDQogIGZpdC5nYW1tYSA8LSBnbG0oQ2xhaW0gfiAxLCBkYXRhID0gY3ZkYXRhWy1pbmRpY2VzLF0sIGZhbWlseSA9IEdhbW1hKGxpbmsgPSBsb2cpKSANCiAgZ2FtbWFfdGhldGEgPC0gZXhwKGNvZWYoZml0LmdhbW1hKSkgKiBnYW1tYS5kaXNwZXJzaW9uKGZpdC5nYW1tYSkgIA0KICBhbHBoYSA8LSAxIC8gZ2FtbWEuZGlzcGVyc2lvbihmaXQuZ2FtbWEpDQogIGtzUmVzdWx0R2FtbWEgPC0ga3MudGVzdChjdmRhdGFbaW5kaWNlcyxdJENsYWltLCAicGdhbW1hIiwgc2hhcGUgPSBhbHBoYSwgc2NhbGUgPSBnYW1tYV90aGV0YSkNCiAgY3ZhbHZlY1syLGldIDwtIGtzUmVzdWx0R2FtbWEkc3RhdGlzdGljDQp9DQpLU2N2IDwtIHJvd1N1bXMoY3ZhbHZlYykvaw0KYGBgDQoNCkhhc2lsbnlhIHRhbXBhayBwYWRhIEdhbWJhciA2LjEyIGRpIG1hbmEgc3VtYnUgaG9yaXpvbnRhbCBhZGFsYWggRm9sZD0xLiBQcm9zZXMgaW5pIGRpdWxhbmdpIHVudHVrIHR1anVoIGxpcGF0YW4gbGFpbm55YS4gSGFzaWwgeWFuZyBkaXJhbmdrdW0gZGFsYW0gR2FtYmFyIDYuMTIgbWVudW5qdWtrYW4gYmFod2EgUGFyZXRvIHNlY2FyYSBrb25zaXN0ZW4gbWVtYmVyaWthbiBkaXN0cmlidXNpIHByZWRpa3RpZiB5YW5nIGxlYmloIGRhcGF0IGRpYW5kYWxrYW4gZGFyaXBhZGEgZ2FtbWEuDQoNCmBgYHtyfQ0KIyBQbG90IHRoZSBzdGF0aXN0aWNzDQptYXRwbG90KDE6ayx0KGN2YWx2ZWMpLHR5cGU9ImIiLCBjb2w9YygxLDMpLCBsdHk9MToyLCANCiAgICAgICAgeWxpbT1jKDAsMC40KSwgcGNoID0gMCwgeGxhYj0iRm9sZCIsIHlsYWI9IktTIFN0YXRpc3RpYyIpDQpsZWdlbmQoImxlZnQiLCBjKCJQYXJldG8iLCAiR2FtbWEiKSwgY29sPWMoMSwzKSxsdHk9MToyLCBidHk9Im4iKQ0KYGBgDQo8cCBjbGFzcz0iY2FwdGlvbiI+DQogICJGaWd1cmUgNi4yOiAiDQo8c3Ryb25nPiANCiAgU3RhdGlzdGlrIEtvbG1vZ29yb3YtU21pcm5vdiAoS1MpIHlhbmcgdGVsYWggZGl2YWxpZGFzaSBzaWxhbmcgdW50dWsgRGF0YSBLbGFpbSBEYW5hIEFzdXJhbnNpLiANCjwvc3Ryb25nPg0KICBHYXJpcyBoaXRhbSBzb2xpZCB1bnR1ayBkaXN0cmlidXNpIFBhcmV0bywgZ2FyaXMgcHV0dXMtcHV0dXMgaGlqYXUgdW50dWsgZGlzdHJpYnVzaSBnYW1tYS4gU3RhdGlzdGlrIEtTIG1lbmd1a3VyIGRldmlhc2kgdGVyYmVzYXIgYW50YXJhIGRpc3RyaWJ1c2kgeWFuZyBzZXN1YWkgZGVuZ2FuIGRpc3RyaWJ1c2kgZW1waXJpcyB1bnR1ayBtYXNpbmctbWFzaW5nIGRhcmkgOCBrZWxvbXBvaywgYXRhdSBsaXBhdGFuLCBkYXRhIHlhbmcgZGlwaWxpaCBzZWNhcmEgYWNhay4gDQo8L3A+DQoNCiMjIDYuMy4yIExlYXZlLU9uZS1PdXQgQ3Jvc3MtVmFsaWRhdGlvbg0KDQoNCkthc3VzIGtodXN1cyBkaSBtYW5hICRrPW4kIGRpa2VuYWwgc2ViYWdhaSB2YWxpZGFzaSBzaWxhbmcgdGluZ2dhbGthbi1zYXR1LWtlbHVhci4gS2FzdXMgaW5pIHNlY2FyYSBoaXN0b3JpcyBzYW5nYXQgbWVub25qb2wgZGFuIHRlcmthaXQgZXJhdCBkZW5nYW4gamFja2tuaWZlc3RhdGlzdGlrIHlhbmcgbWVydXBha2FuIHBlbmRhaHVsdSBkYXJpIHRla25payBib290c3RyYXAuDQoNCk1lc2tpcHVuIGtpdGEgbWVueWFqaWthbm55YSBzZWJhZ2FpIGthc3VzIGtodXN1cyB2YWxpZGFzaSBzaWxhbmcsIGFrYW4gc2FuZ2F0IG1lbWJhbnR1IGppa2Ega2FtaSBtZW1iZXJpa2FuIGRlZmluaXNpIGVrc3BsaXNpdC4gUGVydGltYmFuZ2thbiBzZWJ1YWggc3RhdGlzdGlrIHVtdW0gJM64y4YgPSB0KHgpJCB5YW5nIG1lcnVwYWthbiBwZW5ha3NpciB1bnR1ayBzZWJ1YWggcGFyYW1ldGVyIHlhbmcgZGltaW5hdGkgJM64JC4gSWRlIGRhcmkgamFja2tuaWZlIGFkYWxhaCBtZW5naGl0dW5nIG4gbmlsYWkgJM64y4Zfey1pfSA9IHQoeC1pKSQsIGRpIG1hbmEgJHgtaSQgYWRhbGFoIHN1YnNhbXBlbCBkYXJpICR4JCBkZW5nYW4gbmlsYWkgJGtlLWkkIGRpaGlsYW5na2FuLiBSYXRhLXJhdGEgZGFyaSBuaWxhaS1uaWxhaSBpbmkgZGlsYW1iYW5na2FuIHNlYmFnYWkNCg0KJCRcb3ZlcmxpbmV7XHdpZGVoYXR7XHRoZXRhfX1feyhcY2RvdCl9PVxmcmFjezF9e259XHN1bV97aT0xfV5uIFx3aWRlaGF0e1x0aGV0YX1fey1pfSAuJCQNCg0KTmlsYWktbmlsYWkgaW5pIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW1idWF0IGVzdGltYXNpIGJpYXMgZGFyaSBzdGF0aXN0aWsgJFxoYXTOuCQNCg0KJCRcYmVnaW57ZXF1YXRpb259DQpCaWFzX3tqYWNrfSA9IChuLTEpIFxsZWZ0KFxvdmVybGluZXtcd2lkZWhhdHtcdGhldGF9fV97KFxjZG90KX0gLSBcd2lkZWhhdHtcdGhldGF9XHJpZ2h0KQ0KXHRhZ3s2LjN9DQpcZW5ke2VxdWF0aW9ufSQkDQoNCnNlcnRhIGVzdGltYXNpIHN0YW5kYXIgZGV2aWFzaQ0KDQokJFxiZWdpbntlcXVhdGlvbn0NCnNfe2phY2t9ID1cc3FydHtcZnJhY3tuLTF9e259XHN1bV97aT0xfV5uIFxsZWZ0KFx3aWRlaGF0e1x0aGV0YX1fey1pfSAtXG92ZXJsaW5le1x3aWRlaGF0e1x0aGV0YX19X3soXGNkb3QpfVxyaWdodCleMn0gfi4NClx0YWd7Ni40fQ0KXGVuZHtlcXVhdGlvbn0kJA0KDQoqKkNvbnRvaCA2LjMuMi4gS29lZmlzaWVuIFZhcmlhc2kuKiogU2ViYWdhaSBpbHVzdHJhc2ksIHBlcnRpbWJhbmdrYW4gc2VidWFoIHNhbXBlbCBmaWt0aWYga2VjaWwgJHggPSB7eF8xLC4uLix4X259JCBkZW5nYW4gcmVhbGlzYXNpDQoNCmBgYHtyfQ0Kc2FtcGxlX3ggPC0gYygyLjQ2LDIuODAsMy4yOCwzLjg2LDIuODUsMy42NywzLjM3LDMuNDAsDQogICAgICAgICAgICAgIDUuMjIsMi41NSwyLjc5LDQuNTAsMy4zNywyLjg4LDEuNDQsMi41NiwyLjAwLDIuMDcsMi4xOSwxLjc3KQ0KYGBgDQoNCk1pc2Fsa2FuIGtpdGEgdGVydGFyaWsgZGVuZ2FuICRcdGhldGEgPSBDViA9IFxzcXJ0e1xtYXRocm17VmFyfn1bWF19L1xtYXRocm17RX59W1hdJA0KDQpEZW5nYW4gZGF0YXNldCBpbmksIGVzdGltYXRvciBrb2VmaXNpZW4gdmFyaWFzaSBtZW5qYWRpIDAsMzExOTYuIE5hbXVuLCBzZWJlcmFwYSBoYW5kYWxrYWggZXN0aW1hc2kgdGVyc2VidXQ/IFVudHVrIG1lbmphd2FiIHBlcnRhbnlhYW4gaW5pLCBraXRhIGRhcGF0IG1lbmdoaXR1bmcgZXN0aW1hdG9yIHBpc2F1IGxpcGF0IGRhcmkgYmlhcyBkYW4gZGV2aWFzaSBzdGFuZGFybnlhLiBLb2RlIGJlcmlrdXQgaW5pIG1lbnVuanVra2FuIGJhaHdhIHBlbmFrc2lyIGphY2trbmlmZSB1bnR1ayBiaWFzIGFkYWxhaCAkQmlhc197amFja30gPSAtMCwwMDYyNyQgZGFuIHN0YW5kYXIgZGV2aWFzaSBqYWNra25pZmUgYWRhbGFoICRzX3tqYWNrfSA9IDAsMDEyOTMkLg0KDQpgYGB7cn0NCkNWYXIgPC0gZnVuY3Rpb24oeCkgc3FydCh2YXIoeCkpL21lYW4oeCkNCkphY2tDVmFyIDwtIGZ1bmN0aW9uKGkpIHNxcnQodmFyKHNhbXBsZV94Wy1pXSkpL21lYW4oc2FtcGxlX3hbLWldKQ0KSmFja1RoZXRhIDwtIFZlY3Rvcml6ZShKYWNrQ1ZhcikoMTpsZW5ndGgoc2FtcGxlX3gpKQ0KQmlhc0phY2sgPC0gKGxlbmd0aChzYW1wbGVfeCktMSkqKG1lYW4oSmFja1RoZXRhKSAtIENWYXIoc2FtcGxlX3gpKQ0Kc2QoSmFja1RoZXRhKQ0KYGBgDQoNCioqQ29udG9oIDYuMy4zLiBLbGFpbSBDaWRlcmEgQmFkYW4gZGFuIFJhc2lvIEVsaW1pbmFzaSBLZXJ1Z2lhbi4qKiBQYWRhIENvbnRvaCA2LjIuMSwga2l0YSB0ZWxhaCBtZW51bmp1a2thbiBiYWdhaW1hbmEgbWVuZ2hpdHVuZyBlc3RpbWFzaSBib290c3RyYXAgZGFyaSBiaWFzIGRhbiBkZXZpYXNpIHN0YW5kYXIgdW50dWsgcmFzaW8gZWxpbWluYXNpIGtlcnVnaWFuIGRlbmdhbiBtZW5nZ3VuYWthbiBkYXRhIGtsYWltIGNlZGVyYSBiYWRhbiBwYWRhIENvbnRvaCA0LjEuMTEuIFNla2FyYW5nIGtpdGEgbWVuaW5kYWtsYW5qdXRpIGRlbmdhbiBtZW1iZXJpa2FuIGp1bWxhaCB5YW5nIHNlYmFuZGluZyBkZW5nYW4gbWVuZ2d1bmFrYW4gc3RhdGlzdGlrIGphY2trbmlmZS4NCg0KVGFiZWwgNi43IG1lcmFuZ2t1bSBoYXNpbCBlc3RpbWFzaSBqYWNra25pZmUuIFRhYmVsIGluaSBtZW51bmp1a2thbiBiYWh3YSBlc3RpbWFzaSBqYWNra25pZmUgdGVyaGFkYXAgYmlhcyBkYW4gZGV2aWFzaSBzdGFuZGFyIGRhcmkgcmFzaW8gZWxpbWluYXNpIGtlcnVnaWFuICRFIFttaW4gKFgsIGQpXS9FIFtYXSQgc2ViYWdpYW4gYmVzYXIga29uc2lzdGVuIGRlbmdhbiBtZXRvZG9sb2dpIGJvb3RzdHJhcC4gU2VsYWluIGl0dSwga2l0YSBkYXBhdCBtZW5nZ3VuYWthbiBzdGFuZGFyIGRldmlhc2kgdW50dWsgbWVtYmFuZ3VuIGludGVydmFsIGtlcGVyY2F5YWFuIGJlcmJhc2lzIG5vcm1hbCwgeWFuZyBiZXJwdXNhdCBkaSBzZWtpdGFyIHBlbmFrc2lyIHlhbmcgZGlrb3Jla3NpIGJpYXMuIFNlYmFnYWkgY29udG9oLCBwYWRhICRkID0gMTQwMDAkLCBraXRhIG1lbGloYXQgcGFkYSBDb250b2ggNC4xLjExIGJhaHdhIGVzdGltYXNpIG5vbnBhcmFtZXRyaWsgZGFyaSAkTEVSJCBhZGFsYWggMC45NzY3OC4gRXN0aW1hc2kgaW5pIG1lbWlsaWtpIGJpYXMgc2ViZXNhciAwLDAwMDEwLCBzZWhpbmdnYSBtZW5naGFzaWxrYW4gZXN0aW1hdG9yIHRlcmtvcmVrc2ktYmlhcyBzZWJlc2FyIDAsOTc2ODguIEludGVydmFsIGtlcGVyY2F5YWFuIDk1JSBkaWhhc2lsa2FuIGRlbmdhbiBtZW1idWF0IGludGVydmFsIGR1YSBrYWxpIHBhbmphbmcgMSw5NiBkZXZpYXNpIHN0YW5kYXIgamFja2tuaWZlLCB5YW5nIGJlcnB1c2F0IHBhZGEgZXN0aW1hdG9yIHRlcmtvcmVrc2kgYmlhcyAoMSw5NiBhZGFsYWggcGVya2lyYWFuIGt1YW50aWwga2UtOTcsNSBkYXJpIGRpc3RyaWJ1c2kgbm9ybWFsIHN0YW5kYXIpLg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoYm9vdCkNCiMgRXhhbXBsZSBmcm9tIERlcnJpZyBldCBhbA0KQklEYXRhIDwtIHJlYWQuY3N2KCJEZXJyaWdSZXNhbXBsaW5nLmNzdiIsIGhlYWRlciA9VCkNCkJJRGF0YSRDZW5zb3JlZCA8LSAxKihCSURhdGEkQW1vdW50UGFpZCA+PSBCSURhdGEkUG9saWN5TGltaXQpDQpCSURhdGFVbmNlbnNvcmVkIDwtIHN1YnNldChCSURhdGEsIENlbnNvcmVkID09IDApDQpMRVIuYm9vdCA8LSBmdW5jdGlvbihkZWQsIGRhdGEsIGluZGljZXMpew0KICByZXNhbXBsZS5kYXRhIDwtIGRhdGFbaW5kaWNlcyxdDQogIHN1bUNsYWltcyA8LSBzdW0ocmVzYW1wbGUuZGF0YSRBbW91bnRQYWlkKQ0KICBzdW1DbGFpbXNfZCA8LSBzdW0ocG1pbihyZXNhbXBsZS5kYXRhJEFtb3VudFBhaWQsZGVkKSkNCiAgTEVSIDwtICAgc3VtQ2xhaW1zX2Qvc3VtQ2xhaW1zDQogIHJldHVybihMRVIpICANCn0NCg0KeCA8LSBCSURhdGFVbmNlbnNvcmVkJEFtb3VudFBhaWQNCkxFUi5qYWNrPC0gZnVuY3Rpb24oZGVkLGkpew0KICBMRVIgPC0gICBzdW0ocG1pbih4Wy1pXSxkZWQpKS9zdW0oeFstaV0pDQogIHJldHVybihMRVIpICANCn0NCkxFUiA8LSBmdW5jdGlvbihkZWQpIHN1bShwbWluKHgsZGVkKSkvc3VtKHgpDQojI0RlcnJpZyBldCBhbA0Kc2V0LnNlZWQoMjAxOSkNCmRWZWMyIDwtIGMoNDAwMCwgNTAwMCwgMTA1MDAsIDExNTAwLCAxNDAwMCwgMTg1MDApDQpPdXRKYWNrIDwtIG1hdHJpeCgwLGxlbmd0aChkVmVjMiksOCkNCiAgZm9yIChqIGluIDE6bGVuZ3RoKGRWZWMyKSkgew0KT3V0SmFja1tqLDFdIDwtIGRWZWMyW2pdDQpyZXN1bHRzIDwtIGJvb3QoZGF0YT1CSURhdGFVbmNlbnNvcmVkLCBzdGF0aXN0aWM9TEVSLmJvb3QsIFI9MTAwMCwgZGVkPWRWZWMyW2pdKQ0KT3V0SmFja1tqLDJdIDwtIHJlc3VsdHMkdDANCmJpYXNib290IDwtIG1lYW4ocmVzdWx0cyR0KS1yZXN1bHRzJHQwIC0+IE91dEphY2tbaiwzXQ0Kc2Rib290IDwtIHNkKHJlc3VsdHMkdCkgLT4gT3V0SmFja1tqLDRdDQp0ZW1wIDwtIGJvb3QuY2kocmVzdWx0cykNCg0KTEVSLmphY2suZGVkPC0gZnVuY3Rpb24oaSkgTEVSLmphY2soZGVkPWRWZWMyW2pdLGkpDQpKYWNrVGhldGEuZGVkIDwtIFZlY3Rvcml6ZShMRVIuamFjay5kZWQpKDE6bGVuZ3RoKHgpKQ0KT3V0SmFja1tqLDVdIDwtIEJpYXNKYWNrLmRlZCA8LSAobGVuZ3RoKHgpLTEpKihtZWFuKEphY2tUaGV0YS5kZWQpIC0gTEVSKGRlZD1kVmVjMltqXSkpDQpPdXRKYWNrW2osNl0gPC0gc2QoSmFja1RoZXRhLmRlZCkNCk91dEphY2tbaiw3OjhdIDwtIG1lYW4oSmFja1RoZXRhLmRlZCkrcXQoYygwLjAyNSwwLjk3NSksbGVuZ3RoKHgpLTEpKk91dEphY2tbaiw2XQ0KICB9DQpgYGANCg0KW1RhYmxlIDYuN106XCN0YWI6NjcNCg0KPGEgaWQ9dGFiOjY3PjwvYT4NCg0KVGFibGUgNi43LiAqKkVzdGltYXNpIEphY2trbmlmZSBkYXJpIExFUiBwYWRhIERlZHVjdGlibGUgeWFuZyBEaXBpbGloKioNCg0KYGBge3IgY29tbWVudD0iIiwgZWNobz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShtYWdyaXR0cikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpPdXRKYWNrLmxhdGV4IDwtIE91dEphY2sNCmNvbG5hbWVzKE91dEphY2spIDwtIGMoImQiLCJOUCBFc3RpbWF0ZSIsIkJvb3RzdHJhcCBCaWFzIiwgIkJvb3RzdHJhcCBTRCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAiSmFja2tuaWZlIEJpYXMiLCAiSmFja2tuaWZlIFNEIiwiTG93ZXIgSmFja2tuaWZlIDk1JSBDSSIsICJVcHBlciBKYWNra25pZmUgOTUlIENJIikNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkge2tuaXRyOjprYWJsZShPdXRKYWNrLCAiaHRtbCIsZGlnaXRzPTUpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpLA0KICAgICAgICAgIGZvbnRfc2l6ZSA9IDEwKQ0KfQ0KaWYgKGtuaXRyOjppc19sYXRleF9vdXRwdXQoKSkge2tuaXRyOjprYWJsZShPdXRKYWNrLmxhdGV4LCAibGF0ZXgiLCBib29rdGFicyA9IFQsIGRpZ2l0cz01KSAlPiUNCiAga2FibGVfc3R5bGluZyhsYXRleF9vcHRpb25zPSJzY2FsZV9kb3duIikgJT4lDQogICAgYWRkX2hlYWRlcl9hYm92ZShjKCIiLCJFc3RpbWF0ZSIsIkJpYXMiLCAiU0QiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIkJpYXMiLCAiU0QiLCI5NSUgQ0kiLCAiOTUlIENJIikpICU+JQ0KICAgICAgYWRkX2hlYWRlcl9hYm92ZShjKCJkIiwiTlAiLCJCb290c3RyYXAiLCAiQm9vdHN0cmFwIiwgDQogICAgICAgICAgICAgICAgICAgICAgICJKYWNra25pZmUiLCAiSmFja2tuaWZlIiwiTG93ZXIgSmFja2tuaWZlIiwgIlVwcGVyIEphY2trbmlmZSIpKQ0KfQ0KYGBgDQoNCkRpc2t1c2kuIFNhbGFoIHNhdHUgZGFyaSBiYW55YWsgaGFsIG1lbmFyaWsgdGVudGFuZyBrYXN1cyBraHVzdXMgbGVhdmUtb25lLW91dCBhZGFsYWgga2VtYW1wdWFuIHVudHVrIG1lcmVwbGlrYXNpIGVzdGltYXNpIGRlbmdhbiB0ZXBhdC4gQXJ0aW55YSwga2V0aWthIHVrdXJhbiBsaXBhdGFuIGhhbnlhIHNhdHUsIG1ha2EgdGlkYWsgYWRhIGtldGlkYWtwYXN0aWFuIHRhbWJhaGFuIHlhbmcgZGlzZWJhYmthbiBvbGVoIHZhbGlkYXNpIHNpbGFuZy4gSW5pIGJlcmFydGkgYmFod2EgcGFyYSBhbmFsaXMgZGFwYXQgbWVyZXBsaWthc2kgcGVrZXJqYWFuIHNhdHUgc2FtYSBsYWluIGRlbmdhbiB0ZXBhdCwgc2VidWFoIHBlcnRpbWJhbmdhbiB5YW5nIHBlbnRpbmcuDQoNClN0YXRpc3RpayBKYWNra25pZmUgZGlrZW1iYW5na2FuIHVudHVrIG1lbWFoYW1pIGtldGVwYXRhbiBlc3RpbWF0b3IsIG1lbmdoYXNpbGthbiBlc3RpbWF0b3IgYmlhcyBkYW4gZGV2aWFzaSBzdGFuZGFyIHBhZGEgcGVyc2FtYWFuICg2LjMpIGRhbiAoNi40KS4gSGFsIGluaSBzZXN1YWkgZGVuZ2FuIHR1anVhbiB5YW5nIHRlbGFoIGtpdGEga2FpdGthbiBkZW5nYW4gdGVrbmlrIGJvb3RzdHJhcCwgYnVrYW4gbWV0b2RlIHZhbGlkYXNpIHNpbGFuZy4gSGFsIGluaSBtZW51bmp1a2thbiBiYWdhaW1hbmEgdGVrbmlrIHN0YXRpc3RpayBkYXBhdCBkaWd1bmFrYW4gdW50dWsgbWVuY2FwYWkgdHVqdWFuIHlhbmcgYmVyYmVkYS4NCg0KIyMgNi4zLjMgQ3Jvc3MtVmFsaWRhdGlvbiBhbmQgQm9vdHN0cmFwDQoNCkJvb3RzdHJhcCBiZXJndW5hIHVudHVrIG1lbWJlcmlrYW4gZXN0aW1hdG9yIHByZXNpc2ksIGF0YXUgdmFyaWFiaWxpdGFzLCBkYXJpIHN0YXRpc3Rpay4gSGFsIGluaSBqdWdhIGJlcmd1bmEgdW50dWsgdmFsaWRhc2kgbW9kZWwuIFBlbmRla2F0YW4gYm9vdHN0cmFwIHVudHVrIHZhbGlkYXNpIG1vZGVsIG1pcmlwIGRlbmdhbiBwcm9zZWR1ciB2YWxpZGFzaSBsZWF2ZS1vbmUtb3V0IGRhbiAqayotZm9sZDoNCg0KKiBCdWF0IHNhbXBlbCBib290c3RyYXAgZGVuZ2FuIG1lbmdhbWJpbCBzYW1wZWwgdWxhbmcgKGRlbmdhbiBwZW5nZ2FudGlhbikgJG4kIGluZGVrcyBkYWxhbSAkezEsIOKLrywgbn0kLiBJbmkgYWthbiBtZW5qYWRpIHNhbXBlbCBwZWxhdGloYW4ga2l0YS4gUGVya2lyYWthbiBtb2RlbCB5YW5nIHNlZGFuZyBkaXBlcnRpbWJhbmdrYW4gYmVyZGFzYXJrYW4gc2FtcGVsIGluaS4NCg0KKiAqVWppKiwgYXRhdSAqc2FtcGVsIHZhbGlkYXNpKiwgdGVyZGlyaSBkYXJpIHBlbmdhbWF0YW4geWFuZyB0aWRhayBkaXBpbGloIHVudHVrIHBlbGF0aWhhbi4gTWVuZ2V2YWx1YXNpIG1vZGVsIHlhbmcgY29jb2sgKGJlcmRhc2Fya2FuIGRhdGEgcGVsYXRpaGFuKSBkZW5nYW4gbWVuZ2d1bmFrYW4gZGF0YSB1amkuDQoNClVsYW5naSBwcm9zZXMgaW5pIGJlYmVyYXBhIGthbGkgKGthdGFrYW5sYWggJEIkKS4gQW1iaWwgcmF0YS1yYXRhIGRhcmkgaGFzaWwtaGFzaWxueWEgZGFuIHBpbGloIG1vZGVsIGJlcmRhc2Fya2FuIHN0YXRpc3RpayBldmFsdWFzaSByYXRhLXJhdGEuDQoNCioqQ29udG9oIDYuMy40LiBEYW5hIFByb3BlcnRpIFdpc2NvbnNpbioqLiBLZW1iYWxpIGtlIENvbnRvaCA2LjMuMSBkaSBtYW5hIGtpdGEgbWVueWVsaWRpa2kga2Vjb2Nva2FuIGRpc3RyaWJ1c2kgZ2FtbWEgZGFuIFBhcmV0byBwYWRhIGRhdGEgZGFuYSBwcm9wZXJ0aS4gS2l0YSBrZW1iYWxpIG1lbWJhbmRpbmdrYW4ga2luZXJqYSBwcmVkaWtzaSBtZW5nZ3VuYWthbiBzdGF0aXN0aWsgS29sbW9nb3Jvdi1TbWlybm92IChLUyksIG5hbXVuIGthbGkgaW5pIG1lbmdndW5ha2FuIHByb3NlZHVyIGJvb3RzdHJhcCB1bnR1ayBtZW1iYWdpIGRhdGEgYW50YXJhIHNhbXBlbCBwZWxhdGloYW4gZGFuIHBlbmd1amlhbi4gQmVyaWt1dCBpbmkgYWRhbGFoIGtvZGUgaWx1c3RyYXNpbnlhLg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZ29mdGVzdCkNCm4gPC0gbnJvdyhjbGFpbV9kYXRhKQ0Kc2V0LnNlZWQoMTIzNDcpDQppbmRpY2VzIDwtIDE6bg0KIyBOdW1iZXIgb2YgQm9vdHN0cmFwIFNhbXBsZXMNCkIgPC0gMTAwDQpjdmFsdmVjIDwtIG1hdHJpeCgwLDIsQikNCmZvciAoaSBpbiAxOkIpIHsNCiAgYm9vdGluZGV4IDwtIHVuaXF1ZShzYW1wbGUoaW5kaWNlcywgc2l6ZT1uLCByZXBsYWNlPSBUUlVFKSkNCiAgdHJhaW5kYXRhIDwtIGNsYWltX2RhdGFbYm9vdGluZGV4LF0NCiAgdGVzdGRhdGEgIDwtIGNsYWltX2RhdGFbLWJvb3RpbmRleCxdDQojIFBhcmV0bw0KICBmaXQucGFyZXRvIDwtIHZnbG0oQ2xhaW0gfiAxLCBwYXJldG9JSSwgbG9jID0gMCwgZGF0YSA9IHRyYWluZGF0YSkNCiAga3NSZXN1bHRQYXJldG8gPC0ga3MudGVzdCh0ZXN0ZGF0YSRDbGFpbSwgInBwYXJldG9JSSIsIGxvYyA9IDAsIHNoYXBlID0gZXhwKGNvZWYoZml0LnBhcmV0bylbMl0pLCANCiAgICAgICAgc2NhbGUgPSBleHAoY29lZihmaXQucGFyZXRvKVsxXSkpDQogIGN2YWx2ZWNbMSxpXSA8LSBrc1Jlc3VsdFBhcmV0byRzdGF0aXN0aWMNCiMgR2FtbWENCiAgZml0LmdhbW1hIDwtIGdsbShDbGFpbSB+IDEsIGRhdGEgPSB0cmFpbmRhdGEsIGZhbWlseSA9IEdhbW1hKGxpbmsgPSBsb2cpKSANCiAgZ2FtbWFfdGhldGEgPC0gZXhwKGNvZWYoZml0LmdhbW1hKSkgKiBnYW1tYS5kaXNwZXJzaW9uKGZpdC5nYW1tYSkgIA0KICBhbHBoYSA8LSAxIC8gZ2FtbWEuZGlzcGVyc2lvbihmaXQuZ2FtbWEpDQogIGtzUmVzdWx0R2FtbWEgPC0ga3MudGVzdCh0ZXN0ZGF0YSRDbGFpbSwgInBnYW1tYSIsIHNoYXBlID0gYWxwaGEsIHNjYWxlID0gZ2FtbWFfdGhldGEpDQogIGN2YWx2ZWNbMixpXSA8LSBrc1Jlc3VsdEdhbW1hJHN0YXRpc3RpYw0KfQ0KS1NCb290IDwtIHJvd1N1bXMoY3ZhbHZlYykvQg0KYGBgDQoNCkthbWkgbWVsYWt1a2FuIHBlbmdhbWJpbGFuIHNhbXBlbCBkZW5nYW4gbWVuZ2d1bmFrYW4gQj0gMTAwIHVsYW5nYW4uIFN0YXRpc3RpayBLUyByYXRhLXJhdGEgdW50dWsgZGlzdHJpYnVzaSBQYXJldG8gYWRhbGFoIDAsMDU4IGRpYmFuZGluZ2thbiBkZW5nYW4gcmF0YS1yYXRhIHVudHVrIGRpc3RyaWJ1c2kgZ2FtbWEsIDAsMjYyLiBIYWwgaW5pIGtvbnNpc3RlbiBkZW5nYW4gaGFzaWwgc2ViZWx1bW55YSBkYW4gbWVtYmVyaWthbiBidWt0aSBsYWluIGJhaHdhIFBhcmV0byBhZGFsYWggbW9kZWwgeWFuZyBsZWJpaCBiYWlrIHVudHVrIGRhdGEgaW5pIGRpYmFuZGluZ2thbiBkZW5nYW4gZ2FtbWEuDQoNCiMgNi40IEltcG9ydGFuY2UgU2FtcGxpbmcNCg0KQmFnaWFuIDYuMSBtZW1wZXJrZW5hbGthbiB0ZWtuaWsgTW9udGUgQ2FybG8gZGVuZ2FuIG1lbmdndW5ha2FuIHRla25payBpbnZlcnNpOiB1bnR1ayBtZW1iYW5na2l0a2FuIHNlYnVhaCB2YXJpYWJlbCBhY2FrICRYJCBkZW5nYW4gZGlzdHJpYnVzaSAkRiQsIHRlcmFwa2FuICRGXnstMX0kIHBhZGEgcGVtYW5nZ2lsYW4gc2VidWFoIGdlbmVyYXRvciBhY2FrIChzZXJhZ2FtIHBhZGEgaW50ZXJ2YWwgc2F0dWFuKS4gQmFnYWltYW5hIGppa2Ega2l0YSBpbmdpbiBtZW5nZ2FtYmFyIHNlc3VhaSBkZW5nYW4gJFgkLCBkZW5nYW4gc3lhcmF0ICRY4oiIW2EsYl0kPw0KDQpTZXNlb3JhbmcgZGFwYXQgbWVuZ2d1bmFrYW4gbWVrYW5pc21lIHRlcmltYS10b2xhazogbWVuYXJpayAkeCQgZGFyaSBkaXN0cmlidXNpICRGJA0KDQoqIGppa2EgJHhcaW5bYSxiXSQ6IHNpbXBhbiAoInRlcmltYSIpDQoNCiogamlrYSAkeFxub3RpblthLGJdJDogZ2FtYmFyIHlhbmcgbGFpbiAoInRvbGFrIikNCg0KQW1hdGkgYmFod2EgZGFyaSBuIG5pbGFpIHlhbmcgYXdhbG55YSBkaWhhc2lsa2FuLCBraXRhIHNpbXBhbiBkaSBzaW5pIGhhbnlhICRbRihiKS1GKGEpXSDii4UgbiQgaGFzaWwgaW1iYW5nLCByYXRhLXJhdGEuDQoNCioqQ29udG9oIDYuNC4xLiBQZW5hcmlrYW4gZGFyaSBEaXN0cmlidXNpIE5vcm1hbC4qKiBNaXNhbGthbiBraXRhIG1lbmdnYW1iYXIgZGFyaSBkaXN0cmlidXNpIG5vcm1hbCBkZW5nYW4gcmF0YS1yYXRhIDIsNSBkYW4gdmFyaWFucyAxLCAkTigyLDUsMSkkLCB0ZXRhcGkgaGFueWEgdGVydGFyaWsgcGFkYSBnYW1iYXIgeWFuZyBsZWJpaCBiZXNhciBkYXJpICRh4omlMiQgZGFuIGt1cmFuZyBkYXJpICRi4omkNCQuIEFydGlueWEsIGtpdGEgaGFueWEgZGFwYXQgbWVuZ2d1bmFrYW4gJEYoNCktRigyKT3Opig0LTIuNSktzqYoMi0yLjUpID0gMC45MzMyIC0gMC4zMDg1ID0gMC42MjQ3JCBwcm9wb3JzaSB1bmRpYW4uIEdhbWJhciA2LjEzIG1lbnVuanVra2FuIGJhaHdhIGJlYmVyYXBhIGhhc2lsIHVuZGlhbiBiZXJhZGEgZGkgZGFsYW0gaW50ZXJ2YWwgJCgyLDQpJCBkYW4gYmViZXJhcGEgZGkgbHVhcm55YS4NCg0KYGBge3J9DQptdSA9IDIuNQ0Kc2lnbWEgPSAxDQphID0gMg0KYiA9IDQNCkZhID0gcG5vcm0oYSxtdSxzaWdtYSkNCkZiID0gcG5vcm0oYixtdSxzaWdtYSkNCnBpY19hbmkgPSBmdW5jdGlvbigpew0KICB1PXNlcSgwLDUsYnk9LjAxKQ0KICBwbG90KHUscG5vcm0odSxtdSxzaWdtYSksY29sPSJ3aGl0ZSIseWxhYj0iIix4bGFiPSIiKQ0KICByZWN0KC0xLC0xLDYsMixjb2w9cmdiKDEsMCwwLC4yKSxib3JkZXI9TkEpDQogIHJlY3QoYSxGYSxiLEZiLGNvbD0id2hpdGUiLGJvcmRlcj1OQSkNCiAgbGluZXModSxwbm9ybSh1LG11LHNpZ21hKSxsd2Q9MikNCiAgYWJsaW5lKHY9YyhhLGIpLGx0eT0yLGNvbD0icmVkIikNCiAgcnUgPC0gcnVuaWYoMSkNCiAgY2xyIDwtICJyZWQiDQogIGlmKChxbm9ybShydSxtdSxzaWdtYSk+PWEpJihxbm9ybShydSxtdSxzaWdtYSk8PWIpKSBjbHIgPC0gImJsdWUiDQogIHNlZ21lbnRzKC0xLHJ1LHFub3JtKHJ1LG11LHNpZ21hKSxydSxjb2w9Y2xyLGx3ZD0yKQ0KICBhcnJvd3MocW5vcm0ocnUsbXUsc2lnbWEpLHJ1LHFub3JtKHJ1LG11LHNpZ21hKSwwLGNvbD1jbHIsbHdkPTIsbGVuZ3RoID0gLjEpDQp9DQpgYGANCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCmZvciAoaSBpbiAxOm51bUFuaW1hdGlvbikge3BpY19hbmkoKX0NCmBgYA0KDQo8YnI+DQoNCjxpbWcgc3JjPSJzYW1wbGVhbmkxLS5naWYiIGFsdD0iIiB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgYWxpZ249Im1pZGRsZSI+DQoNClNlYmFnYWkgZ2FudGlueWEsIHNlc2VvcmFuZyBkYXBhdCBtZW5nZ2FtYmFyIG1lbnVydXQgZGlzdHJpYnVzaSBiZXJzeWFyYXQgJEZe4ouGJCB5YW5nIGRpZGVmaW5pc2lrYW4gc2ViYWdhaQ0KDQokJEZee1xzdGFyfSh4KSA9IFxQcihYIFxsZSB4IHwgYSA8IFggXGxlIGIpID1cZnJhY3tGKHgpLUYoYSl9e0YoYiktRihhKX0sIFwgXCAgXCBcdGV4dHtmb3IgfSBhIDwgeCBcbGUgYiAuJCQNCkRlbmdhbiBtZW5nZ3VuYWthbiBtZXRvZGUgaW52ZXJzZSB0cmFuc2Zvcm0gcGFkYSBCYWdpYW4gNi4xLjIsIGtpdGEgbWVuZGFwYXRrYW4gaGFzaWwgaW1iYW5nDQoNCiQkWF5cc3Rhcj1GXntcc3Rhci0xfVxsZWZ0KCBVIFxyaWdodCkgPSBGXnstMX1cbGVmdChGKGEpK1VcY2RvdFtGKGIpLUYoYSldXHJpZ2h0KSQkDQoNCm1lbWlsaWtpIGRpc3RyaWJ1c2kgJEbii4ZeJC4gRGlueWF0YWthbiBkZW5nYW4gY2FyYSBsYWluLCBkZWZpbmlzaWthbg0KDQokJFx0aWxkZXtVfSA9ICgxLVUpXGNkb3QgRihhKStVXGNkb3QgRihiKSQkDQoNCmRhbiBrZW11ZGlhbiBndW5ha2FuICRGXnstMX0oXHRpbGRle1V9KSQuIERlbmdhbiBwZW5kZWthdGFuIGluaSwgc2V0aWFwIHVuZGlhbiBkaWhpdHVuZy4NCg0KSGFsIGluaSBkYXBhdCBkaWthaXRrYW4gZGVuZ2FuIG1la2FuaXNtZSBwZW5nYW1iaWxhbiBzYW1wZWwga2VwZW50aW5nYW46IGtpdGEgbWVuYXJpayBsZWJpaCBzZXJpbmcgZGkgd2lsYXlhaCB5YW5nIGtpdGEgaGFyYXBrYW4gbWVtaWxpa2kga3VhbnRpdGFzIHlhbmcgbWVtaWxpa2kga2VwZW50aW5nYW4uIFRyYW5zZm9ybWFzaSBpbmkgZGFwYXQgZGlhbmdnYXAgc2ViYWdhaSAicGVydWJhaGFuIHVrdXJhbi4iDQoNCmBgYHtyfQ0KcGljX2FuaSA9IGZ1bmN0aW9uKCl7DQogIHU9c2VxKDAsNSxieT0uMDEpDQogIHBsb3QodSxwbm9ybSh1LG11LHNpZ21hKSxjb2w9IndoaXRlIix5bGFiPSIiLHhsYWI9IiIpDQogIHJlY3QoLTEsLTEsNiwyLGNvbD1yZ2IoMSwwLDAsLjIpLGJvcmRlcj1OQSkNCiAgcmVjdChhLEZhLGIsRmIsY29sPSJ3aGl0ZSIsYm9yZGVyPU5BKQ0KICBsaW5lcyh1LHBub3JtKHUsbXUsc2lnbWEpLGx3ZD0yKQ0KICBhYmxpbmUoaD1wbm9ybShjKGEsYiksbXUsc2lnbWEpLGx0eT0yLGNvbD0icmVkIikNCiAgcnUgPC0gcnVuaWYoMSkNCiAgcnV0aWxkZSA8LSAoMS1ydSkqRmErcnUqRmINCiAgc2VnbWVudHMoLTEscnV0aWxkZSxxbm9ybShydXRpbGRlLG11LHNpZ21hKSxydXRpbGRlLGNvbD0iYmx1ZSIsbHdkPTIpDQogIGFycm93cyhxbm9ybShydXRpbGRlLG11LHNpZ21hKSxydXRpbGRlLHFub3JtKHJ1dGlsZGUsbXUsc2lnbWEpLDAsY29sPSJibHVlIixsd2Q9MixsZW5ndGggPSAuMSkNCn0NCmBgYA0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0KZm9yIChpIGluIDE6bnVtQW5pbWF0aW9uKSB7cGljX2FuaSgpfQ0KYGBgDQoNCjxicj4NCg0KPGltZyBzcmM9InNhbXBsZWFuaV9JU18yLS5naWYiIGFsdD0iIiB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgYWxpZ249Im1pZGRsZSI+DQoNClBhZGEgQ29udG9oIDYuNC4xLiwga2ViYWxpa2FuIGRhcmkgZGlzdHJpYnVzaSBub3JtYWwgc3VkYWggdGVyc2VkaWEgKGRhbGFtIGBSYCwgZnVuZ3NpbnlhIGFkYWxhaCBgcW5vcm1gKS4gTmFtdW4sIHVudHVrIGFwbGlrYXNpIGxhaW4sIGhhbCBpbmkgdGlkYWsgdGVyamFkaS4gS2VtdWRpYW4sIGtpdGEgY3VrdXAgbWVuZ2d1bmFrYW4gbWV0b2RlIG51bWVyaWsgdW50dWsgbWVuZW50dWthbiAkWF7ii4YkIHNlYmFnYWkgc29sdXNpIGRhcmkgcGVyc2FtYWFuICRGKFheXHN0YXIpID1cdGlsZGV7VX0kIGRpIG1hbmEgJFx0aWxkZXtVfT0oMS1VKVxjZG90IEYoYSkrVVxjZG90IEYoYikkKS4gTGloYXQga29kZSBpbHVzdHJhc2kgYmVyaWt1dCBpbmkuDQoNCmBgYHtyfQ0KcGljX2FuaSA9IGZ1bmN0aW9uKCl7DQogIHU9c2VxKDAsNSxieT0uMDEpDQogIHBsb3QodSxwbm9ybSh1LG11LHNpZ21hKSxjb2w9IndoaXRlIix5bGFiPSIiLHhsYWI9IiIpDQogIHJlY3QoLTEsLTEsNiwyLGNvbD1yZ2IoMSwwLDAsLjIpLGJvcmRlcj1OQSkNCiAgcmVjdCgyLC0xLDQsMixjb2w9IndoaXRlIixib3JkZXI9TkEpDQogIGxpbmVzKHUscG5vcm0odSxtdSxzaWdtYSksbHR5PTIpDQogIHBub3Jtc3RhciA8LSBWZWN0b3JpemUoZnVuY3Rpb24oeCl7DQogICAgeT0ocG5vcm0oeCxtdSxzaWdtYSktRmEpLyhGYi1GYSkNCiAgICBpZih4PD1hKSB5IDwtIDANCiAgICBpZih4Pj1iKSB5IDwtIDENCiAgICByZXR1cm4oeSkNCiAgICB9KQ0KICBxbm9ybXN0YXIgPC0gZnVuY3Rpb24odSkgYXMubnVtZXJpYyh1bmlyb290KChmdW5jdGlvbiAoeCkgcG5vcm1zdGFyKHgpIC0gdSksIGxvd2VyID0gMiwgdXBwZXIgPSA0KVsxXSkNCiAgbGluZXModSxwbm9ybXN0YXIodSksbHdkPTIpDQogIGFibGluZSh2PWMoMiw0KSxsdHk9Mixjb2w9InJlZCIpDQogIHJ1IDwtIHJ1bmlmKDEpDQogIHNlZ21lbnRzKC0xLHJ1LHFub3Jtc3RhcihydSkscnUsY29sPSJibHVlIixsd2Q9MikNCiAgYXJyb3dzKHFub3Jtc3RhcihydSkscnUscW5vcm1zdGFyKHJ1KSwwLGNvbD0iYmx1ZSIsbHdkPTIsbGVuZ3RoID0gLjEpDQp9DQpgYGANCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCmZvciAoaSBpbiAxOm51bUFuaW1hdGlvbikge3BpY19hbmkoKX0NCmBgYA0KPGJyPg0KPGltZyBzcmM9InNhbXBsZWFuaV9JU18xLS5naWYiIGFsdD0iIiB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgYWxpZ249Im1pZGRsZSI+DQo=