Giới thiệu
Thân chào các bạn, đây là bài thực hành thứ ba trong dự án Bayes for Vietnam, được reboot lại từ project cùng tên năm 2016. Mục tiêu của dự án này là phổ biến phương pháp thống kê theo trường phái Bayes cho các bạn bác sĩ và sinh viên y khoa, nhằm thay thế cho những công cụ thống kê truyền thống.
Qua 2 bài trước, chắc hẳn các bạn đã được làm quen với quy trình phân tích và suy diễn thống kê theo trường phái Bayes và nhận ra những điểm khác biệt của Bayes so với quy trình cổ điển. Nguyên lý của phương pháp này dựa vào định lý Bayes, được diễn đạt bằng ngôn ngữ mô hình, xác suất điều kiện. Suy diễn thống kê theo Bayes liên kết giữa 4 phần: Dữ liệu quan sát thực tế, giả thuyết (phân phối) tiền định Prior, hàm likelihood và kết quả phân phối hậu địn h. Quy trình Bayes đòi hỏi người thực hành nhìn thấu suốt vấn đề mà họ phải đối diện đến từng chi tiết nhỏ nhất: Họ phải nhận diện ra những biến số trong bài toán, đâu là biến kết quả, đâu là tham số. Tiếp theo, người dùng phải chuyển được bài toán sang ngôn ngữ mô hình và chọn một mô hình phù hợp. Từ mô hình này, ta lại phải xác định các tham số, hàm likelihood, phân phối tiền định cho tham số. Khi đã phác thảo xong mô hình, ta viết code để đưa mô hình vào một Sampler để lấy mẫu chuỗi MCMC cho tham số và các trị số thống kê khác. Các chuỗi MCMC này chứa phân phối hậu định, cũng là kết quả của phân tích. Cuối cùng, ta suy diễn thống kê trên phân phối hậu định, bằng nhiều cách khác nhau bao gồm Bayes factor, khoảng vô nghĩa thực dụng (ROPE) hay ngưỡng so sánh (Comp.Val).
Tại một số vị trí nào đó, Bayes và thống kê cổ điển có thể giao nhau, thí dụ từ mô hình Bayes, ta có thể rút ra phân phối hậu định cho các trị số thống kê, bao gồm cả Effect-size. Như vậy khác biệt quan trọng nhất giữa Bayes và các kiểm định thống kê quy ước, đó là có sự hòa hợp giữa prior và posterior, đó là xác suất điều kiện, likelihood và mô hình thay cho những công thức và trị số thống kê mang tính đại diện và xấp xỉ (như Chi2 cho Pearson Chi2 test, t cho Student t-test, F cho ANOVA , r cho phân tích tương quan vv…). Khác biệt thứ hai nằm ở cách diễn giải kết quả. Thực ra, P_vale hoàn toàn có thể được tính dựa vào phân phối hậu định, nhưng bản thân phân phối hậu định đã chứa nhiều thông tin đến mức ta không cần phải dùng đến phản nghiệm, Null hypothesis testings và p_value nữa.
Sau khi thay thế Student-t test trong bài thứ 2, bài này Nhi sẽ hướng dẫn các bạn dùng Bayes để thay thế cho một công cụ phổ biến khác đó là Chi2 test trong phân tích tần số, tỉ lệ của bảng chéo
Phân tích bảng chéo thực ra là một bài toán xác suất rất đơn giản, đến mức sinh viên Y khoa năm thứ nhất có thể giải quyết dễ dàng; tại sao ta phải dùng đến Bayes ? Nhi hy vọng sau bài thực hành bạn sẽ có câu trả lời cho mình.
Bài toán bảng chéo và 3 cách tư duy
Bộ số liệu này có nguồn gốc từ 1 nghiên cứu thử nghiệm lâm sàng của Edwards Koch năm 1988, với mục tiêu khảo sát hiệu quả điều trị bệnh Viêm khớp của một loại thuốc (nhóm Treatment), so với nhóm sử dụng giả dược (placebo). Hiệu quả điều trị được đánh giá như một biến định danh với 3 bậc giá trị : Cải thiện rõ rệt (marked), cải thiện tương đối (Some) và không có cải thiện (None) triệu chứng của bệnh.
library(tidyverse)
df=read.csv("https://raw.github.com/vincentarelbundock/Rdatasets/master/csv/vcd/Arthritis.csv")
crosstab=xtabs(~Treatment+Improved,data=df)
crosstab
## Improved
## Treatment Marked None Some
## Placebo 7 29 7
## Treated 21 13 7
library(vcd)
mosaic(crosstab,shade=TRUE,legend=TRUE,gp = shading_max)

Như vậy bài toán này có 2 biến số (yếu tố) : Treatment và Outcome, cả 2 đều là biến định danh với 2 hoặc 3 bậc giá trị. Với dữ liệu như vậy, ta có thể phát biểu câu hỏi nghiên cứu (giả thuyết H0/H1) theo nhiều cách khác nhau; và chú ý rằng mỗi cách như vậy sẽ gợi ý cho chúng ta sử dụng một hình thức/công cụ thống kê khác nhau:
Cách thứ 1
Giả thuyết cần chứng minh là : Có mối liên hệ giữa yếu tố phân nhóm điều trị và mức độ cải thiện triệu chứng; Ghi chú: liên hệ ở đây được hiểu ngầm – là về tần số / tỉ lệ phân bố. Cách tư duy này sẽ dẫn chúng ta đến Chisquared test của Pearson với H0: 2 yếu tố Điều trị và Cải thiện triệu chứng là độc lập với nhau (không có liên hệ giữa chúng), độ tự do cho Chi2= 2. Chúng ta sẽ bàn về Chi2test trong phần tiếp theo.
Cách thứ 2
Giả thuyết cần chứng minh sẽ là: Có sự khác biệt về tỉ lệ phân bố của bệnh nhân Có cải thiện triệu chứng giữa 2 phân nhóm : Dùng thuốc và dùng Giả dược. Cách tư duy này sẽ dẫn chúng ta đến bài toán so sánh tỉ lệ điều trị thành công giữa 2 phân nhóm (Treatment vs Placebo), ghi chú là tỉ lệ này chính là tỉ số giữa số bệnh nhân có cải thiện chia cho tổng số bệnh nhân ở từng phân nhóm điều trị. Bài toán này dẫn chúng ta đến một mô hình : số bệnh nhân điều trị thành công là biến kết quả, được mô tả bằng phân phối Binomial (theta, ntrial), với ntrial = tổng số bệnh nhân ở mỗi phân nhóm điều trị, và theta là tỉ lệ điều trị thành công, tham số của mô hình. Như vậy bài toán này gần giống với bài toán so sánh trung bình giữa 2 phân nhóm (kiểm định t), chỉ thay phân phối Student t bằng phân phối binomial và tham số Mu bằng tham số Theta. Ghi chú: để thực hiện phân tích, ta phải gộp 2 phân loại: Cải thiện đáng kể và cải thiện tương đối thành một.
Cách thứ 3:
Giả thuyết được phát biểu như sau: 1 bệnh nhân bất kì nếu được điều trị bằng thuốc X sẽ có xác suất cải thiện triệu chứng cao hơn so với khi dùng placebo. Outcome của bài toán này là 1 xác suất cho 1 cá thể. Chắc các bạn cũng nhận ra, đây là 1 mô hình logistic hoặc mô hình hồi quy đa giá trị (tùy theo biến kết quả được gộp thành 1 biến nhị giá :Có/không có cải thiện hay giữ nguyên 3 bậc giá trị. Cách thứ 3 này hoàn toàn khác với 2 cách trên, và không có liên quan đến phân tích bảng chéo/ tần số, nên chúng ta sẽ không xét về nó trong bài.
Tuy cách 1 và 2 đều biểu diễn dữ liệu bằng bảng chéo, nhưng bản chất câu hỏi và cách giải quyết rất khác nhau. Như đã trình bày, kiểm định Chi2 là giải pháp cho câu hỏi chứng minh về tính độc lập/liên hệ giữa 2 yếu tố (biến định danh). Do đó, cần phải nêu rõ 1 điều ở đây: công dụng của Chisquare test không phải là để so sánh về tỉ lệ phân phối giữa các phân nhóm. Rất nhiều bạn sinh viên nhầm lẫn ở điểm này, nên các bạn thường viết trong báo cáo/luận văn như sau : tỉ lệ bệnh nhân giữa 2 phân nhóm được SO SÁNH bằng test Chi2. Đây là 1 phát biểu sai vì khi làm Chi2 test ta không so sánh cái gì cả. Mặt khác, bạn sẽ thấy rằng: ngay cả khi chúng ta trả lời thành công cho câu hỏi thứ 1 (test chi2 cho ra kết quả ý nghĩa, p<0.05), chứng minh được có mối liên hệ giữa yếu tố Nhóm điều trị và Yếu tố Cải thiện triệu chứng, ta vẫn chưa thể kết luận gì về Hiệu ứng của Thuốc so với Placebo cả ! (giả sử ta hoán chuyển tên 2 phân nhóm Placebo và điều trị, bạn vẫn sẽ có 1 kết quả test Chi2 dương tính như thường nhưng ý nghĩa lâm sàng khác hẳn !); do đó Cách đặt vấn đề thứ 2 và thứ 3 tốt hơn nhiều so với cách thứ 1, vì bạn có trong tay bằng chứng định lượng (xác suất khỏi bệnh, khác biệt tần số bệnh nhân khỏi bệnh, odss-ratio) giữa 2 phân nhóm.
Nhắc lại về Chi2 test cổ điển
Chisquared test là gì ? Đây là một kiểm định rất cổ xưa, do Karl Pearson tạo ra từ năm 1900, công dụng của nó là kiểm tra mối liên hệ giữa Hàng và Cột trong một bảng chéo.
Giả thuyết H0 của Chi2 test là: hàng và cột trong bảng chéo độc lập với nhau = không có liên hệ giữa 2 yếu tố ta đang xét. Giả thuyết H1 là: có mối liên hệ giữa hàng và cột trong bảng chéo
Chisquared test có 2 giả định, thứ nhất, mọi quan sát trong bảng chéo là độc lập với nhau (1 cá thể chỉ xuất hiện 1 lần ở hàng/cột); thứ 2, không quá 20% tần số giả định có giá trị < 5. Giả định thứ 2 này khá phiền toái, có thể hiểu là với 1 bảng 2x2, và tần số ở 1 ô nào đó <5, ta không thể dùng test Chi2 được nữa, vì khi đó đường cong mật độ phân phối của Chi2 sẽ có hình dạng bất đối xứng, không chính xác để tính xác suất cho trị số p. Giả định này có thể được kiểm tra đơn giản bằng cách xem kết quả tần số giả định trong bảng chéo.
Trị số thống kê của test có bản chất là tổng bình phương sai số (residual) giữa Tần số quan sát được trên thực tế trong bảng chéo (observed) và tần số giả định (expected) nếu giả thuyết H0 là đúng.
Nếu giả thuyết H0 đúng, trị số thống kê này tuân theo quy luật phân phối Chisquared với độ tự do =df; do đó nó được đặt tên là Chisquared. Thực ra phân phối Chi2 rất phổ biến trong kiểm định thống kê; có vài chục loại kiểm định mà trị số thống kê được mô tả bằng phân phối Chi2.
Tần số giả định:
\[expected = \frac{rowsum * colsum}{total}\]
Độ tự do df của Chi2 test được tính như sau:
\[df = (nrow - 1)(ncol - 1)\]
Pearson residual được tính như sau:
\[residual = \frac{observed - expected}{\sqrt{expected}}\]
\[\chi^2 = \sum{\frac{(observed - expected)^2}{expected}} = \sum{residuals}\]
Chisquare là một phân phối liên tục, nó có 1 tham số kiểu hình là Nu=df. Minh họa: hình dáng của phân phối Chisquared ở độ tự do từ 2 đến 15; khi df tăng dần, Chi2 trở nên đối xứng và gần với phân phối Gaussian.
# Chi2
sim=data.frame(Val=rep(NA,500),nu=rep(NA,500))
temp=sim
for (i in (2:15)){
temp$Val=rchisq(n=500,df=i)
temp$nu=i
sim=rbind(temp,sim)
}
sim$nu=as.factor(sim$nu)
sim%>%na.omit%>%ggplot(aes(x=Val,fill=nu,col=nu))+
geom_density(alpha=0.1)+
theme_bw()+ggtitle("Chisquared distribution")

Chisquared test có một số biến thể, bao gồm test Exact của Fisher, phương pháp mô phỏng Monte Carlo. Effect-size của chi2 test là V (theo Cramer). Hàm sau đây sẽ thực hiện cùng lúc cả 3 loại test và tính Cramer’s V cho 1 bảng chéo:
chisquare=function(crosstab,B,level){
test1=chisq.test(crosstab)
test2=chisq.test(crosstab,simulate.p.value = T,B=B)
test3=test3=fisher.test(crosstab)
p=Monte_Carlo_pval=test2$p.value[[1]]
print(rbind(Chisqr=test1$statistic[[1]],
df=test1$parameter[[1]],
Chi2p_val=test1$p.value[[1]],
Monte_Carlo_pval=p,
Fisher_exact_pval=test3$p.value[[1]],
Cramer_V=lsr::cramersV(crosstab)))
}
chisquare(crosstab,10000)
## [,1]
## Chisqr 13.055019853
## df 2.000000000
## Chi2p_val 0.001462643
## Monte_Carlo_pval 0.001699830
## Fisher_exact_pval 0.001393195
## Cramer_V 0.394229505
Khi dùng hàm summary cho 1 bảng chéo, R tự động làm test Chi2
crosstab%>%summary()
## Call: xtabs(formula = ~Treatment + Improved, data = df)
## Number of cases in table: 84
## Number of factors: 2
## Test for independence of all factors:
## Chisq = 13.055, df = 2, p-value = 0.001463
Hàm chisq.test cho phép làm Chi2 test và trích xuất các trị số bên trong:
test1=chisq.test(crosstab)
test1
##
## Pearson's Chi-squared test
##
## data: crosstab
## X-squared = 13.055, df = 2, p-value = 0.001463
Thí dụ: Observed values:
test1$observed
## Improved
## Treatment Marked None Some
## Placebo 7 29 7
## Treated 21 13 7
Expected values:
test1$expected
## Improved
## Treatment Marked None Some
## Placebo 14.33333 21.5 7.166667
## Treated 13.66667 20.5 6.833333
Pearson residual
test1$residuals
## Improved
## Treatment Marked None Some
## Placebo -1.93699199 1.61749160 -0.06225728
## Treated 1.98367320 -1.65647289 0.06375767
Chisquared test BAYES
Ta có thể mô phỏng Chi2 test theo phương pháp BAYES như sau:
Ta muốn xác định phân phối hậu định của trị số Chisquared và Effect-szie của nó là Cramer’s V bằng một mô hình Bayes có likelihood function ước tính Chisquared theo phân phối Chi2 với tham số là Nu. Tiền định của mô hình là thal số Nu (độ tự do của phân phối Chi2) có phân phối uniform (0.01, 100). Dữ liệu đầu vào của mô hình là 2 vector chứa tần số quan sát được (observed) và tần số giả định (expect) trong bảng chéo.
expect=test1$expected%>%as.vector()
obs=test1$observed%>%as.vector()
Đây là nội dung mô hình STAN
# Bayesian Chi2 test
library(rstan)
stanmodelcode ="
data{
int<lower=4> ncell;
vector[ncell] observed;
vector[ncell] expect;
}
transformed data {
real residual[ncell];
real chisqr;
real total;
for (i in 1:ncell) {
residual[i]=(observed[i]-expect[i])^2/expect[i];}
chisqr=sum(residual);
total = sum(observed);
}
parameters {
real nu;
}
model {
// khai bao tien dinh (prior)
nu ~ uniform(0.01,100);
// likelihood
chisqr ~ chi_square(nu);
}
generated quantities {
real cramersV;
real chi2;
chi2=chi_square_rng(nu);
cramersV=sqrt(chi2/total);
}
"
Mô tả nội dung model STAN:
Block data: cần 3 thành phần: ncell= số ô trong bảng chéo, 2 vector observed và expect.
Block transformed data: khai báo vector residual là 1 số thực, chisqr là 1 số thực, total là 1 số thực. residual được tính cho từng ô trong vector, dựa vào expect và observed vector. Có residual, ta dễ dàng tính được Chi2 = sum(residual). Total = tổng tất cả giá trị observed.
Model Bayes có likelihood chisqr ~ chi_square(nu), nu là một số thực, chỉ độ tự do của Chi2, nu có prior là phân phối uniform.
Block generated quantities: ta lấy mẫu ngẫu nhiên cho biến chi2 là 1 số thực,dựa vào phân phối hậu định của nu, rồi từ đó tính Cramer’s V là effectsize, cũng là 1 số thực.
Khi thi hành mô hình BAYES này, chúng ta sẽ có phân phối hậu định của Nu, Chi2 và Cramers’V.
data=list(ncell=6,observed=obs,expected=expect)
fit = stan(model_code=stanmodelcode, data=data, iter=1000, warmup=200, chains=1,cores=4, thin=10)
## In file included from C:/Users/Admin/Documents/R/win-library/3.4/BH/include/boost/config.hpp:39:0,
## from C:/Users/Admin/Documents/R/win-library/3.4/BH/include/boost/math/tools/config.hpp:13,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math/rev/core/var.hpp:7,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math/rev/core/gevv_vvv_vari.hpp:5,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math/rev/core.hpp:12,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math/rev/mat.hpp:4,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math.hpp:4,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/src/stan/model/model_header.hpp:4,
## from filef081bc235d1.cpp:8:
## C:/Users/Admin/Documents/R/win-library/3.4/BH/include/boost/config/compiler/gcc.hpp:186:0: warning: "BOOST_NO_CXX11_RVALUE_REFERENCES" redefined
## # define BOOST_NO_CXX11_RVALUE_REFERENCES
## ^
## <command-line>:0:0: note: this is the location of the previous definition
## cc1plus.exe: warning: unrecognized command line option "-Wno-ignored-attributes"
##
## SAMPLING FOR MODEL '16c3f04e4fe9d979aca9ed660448df9f' NOW (CHAIN 1).
## Rejecting initial value:
## Error evaluating the log probability at the initial value.
## Exception: chi_square_lpdf: Degrees of freedom parameter is -0.80088, but must be > 0! (in 'modelf0894ab16_16c3f04e4fe9d979aca9ed660448df9f' at line 35)
##
##
## Gradient evaluation took 0 seconds
## 1000 transitions using 10 leapfrog steps per transition would take 0 seconds.
## Adjust your expectations accordingly!
##
##
## Iteration: 1 / 1000 [ 0%] (Warmup)
## Iteration: 100 / 1000 [ 10%] (Warmup)
## Iteration: 200 / 1000 [ 20%] (Warmup)
## Iteration: 201 / 1000 [ 20%] (Sampling)
## Iteration: 300 / 1000 [ 30%] (Sampling)
## Iteration: 400 / 1000 [ 40%] (Sampling)
## Iteration: 500 / 1000 [ 50%] (Sampling)
## Iteration: 600 / 1000 [ 60%] (Sampling)
## Iteration: 700 / 1000 [ 70%] (Sampling)
## Iteration: 800 / 1000 [ 80%] (Sampling)
## Iteration: 900 / 1000 [ 90%] (Sampling)
## Iteration: 1000 / 1000 [100%] (Sampling)
##
## Elapsed Time: 0.01 seconds (Warm-up)
## 0.01 seconds (Sampling)
## 0.02 seconds (Total)
summary(fit)
## $summary
## mean se_mean sd 2.5% 25% 50%
## nu 15.2526184 0.68121374 5.4843252 7.5471615 11.373353 14.3500838
## cramersV 0.4071654 0.01341651 0.1105121 0.1922191 0.349046 0.4089721
## chi2 14.9388936 0.94685718 7.6189792 3.1081116 10.237335 14.0497266
## lp__ 3.4585111 0.11744526 0.8783617 0.4998120 3.376739 3.7322409
## 75% 97.5% n_eff Rhat
## nu 18.8198123 29.6969801 64.81561 1.007013
## cramersV 0.4624003 0.6452856 67.84858 1.028366
## chi2 17.9605729 34.9771457 64.74774 1.039745
## lp__ 3.9522331 3.9831383 55.93399 1.021946
##
## $c_summary
## , , chains = chain:1
##
## stats
## parameter mean sd 2.5% 25% 50% 75%
## nu 15.2526184 5.4843252 7.5471615 11.373353 14.3500838 18.8198123
## cramersV 0.4071654 0.1105121 0.1922191 0.349046 0.4089721 0.4624003
## chi2 14.9388936 7.6189792 3.1081116 10.237335 14.0497266 17.9605729
## lp__ 3.4585111 0.8783617 0.4998120 3.376739 3.7322409 3.9522331
## stats
## parameter 97.5%
## nu 29.6969801
## cramersV 0.6452856
## chi2 34.9771457
## lp__ 3.9831383
Ta có thể thấy rằng kết quả Median của Chi2 và Cramer’s V tương đương với test Chi2 frequentist
Ta có thể diễn giải kết quả trực tiếp dựa vào Cramers’V, hoặc dùng phân phối hậu định của Chi2 để ước tính một giá trị p_value nhằm kiểm tra giả thuyết H0. Giá trị p này = 0.0007, rất gần với p_value theo phương pháp mô phỏng Monte Carlomaé ta tìm ra ở trên.
chi2=extract(fit,pars="chi2")%>%.[[1]]
p=rep(NA,length(chi2))
for (i in 1:length(chi2)){
p[i]=pchisq(chi2[i],2,lower.tail=F)}
median(p)
## [1] 0.0008897486
Như vậy, cách làm này không cho ta biết thêm thông tin nào mới so với test Chi2 cổ điển.
So sánh tỉ lệ bằng mô hình Binomial BAYES
Một cách tổng quát, suy diễn Bayes dựa trên định lý Bayes như sau :
\[ p(\theta |y,x)\propto p(y|\theta ,x) p(\theta ,x) \] theo đó, phân phối hậu định của một tham số Theta (khi ta có trong tay dữ liệu biến kết quả Y và hằng số X là một matrix các predictors trong mô hình) tỉ lệ với tích của hàm likelihood (xác suất có điều kiện của y khi có theta và x) và phân phối tiền định (prior= giả thuyết về phân phối của theta).
Ta có thể biến cách tiếp cận thứ 2 (So 2 sánh tỉ lệ thành công giữa 2 phân nhóm Điều trị vs Placebo) thành một mô hình Bayes như sau:
Dữ liệu đầu vào gồm có:
1 vector Proportion có 2 giá trị là tần số điều trị thành công tương ứng cho 2 nhóm
1 vector Total với 2 giá trị tổng số bệnh nhân ở mỗi phân nhóm
Ở mỗi phân nhóm, biến kết quả của mô hình có thể xem như là số lần thành công (Proportion[i]) rút ra được sau n[i] lần thử từ một hộp kín chứa n[i] phần tử (=Total[i]).
Như vậy quy luật đằng sau thử nghiệm này chính là phân phối Binomial. Như ta biết, phân phối Binomial có 2 tham số là số lần thử (n trial) và tỉ lệ thành công (Theta). Số lần thử ở đây ta đã biết, chính là tổng số bệnh nhân ở mỗi phân nhóm, ta chỉ còn phải xác định phân phối hậu định của tham số Theta.
# Binomial
sim=data.frame(Val=rep(NA,100),theta=rep(NA,100))
temp=sim
theta=c(0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9)
for (i in (1:10)){
temp$Val=rbinom(n=100,prob=theta[i],size=41)
temp$theta=theta[i]
sim=rbind(temp,sim)
}
sim$theta=as.factor(sim$theta)
sim%>%na.omit%>%ggplot(aes(x=Val,fill=theta,col=theta))+
geom_density(alpha=0.2)+
theme_bw()+ggtitle("Binomial distribution / 41 trials")

Giả thuyết tiền định cho tham số Theta là gì ?: Do theta là 1 xác suất có giá trị từ 0.0 đến 1.0, sẽ hợp lý nếu ta giả định rằng theta được mô tả bằng phân phối Beta. Nếu bạn không có thông tin nào về prior, bạn có thể chọn giải pháp an toàn khi đặt phân phối Beta(shape1, shape2) có hình dạng “phẳng” tức gần giống 1 phân phối Uniform(0,1), bằng cách dùng 2 tham số shape bằng nhau = 1.
Ở đây Nhi dùng 1 prior do Jeffrey đề nghị là Beta (0.5, 0.5). Một prior khác bạn có thể thử là prior của Haldane : Beta (0.0001, 0.0001).
#Beta Distribution
sim=data.frame(Val=rep(NA,1000),shape=rep(NA,500))
temp=sim
para=c(0.0001,0.5,1,2,3,4)
for (i in (1:6)){
temp$Val=rbeta(n=1000,shape1=para[i],shape2=para[i])
temp$shape=para[i]
sim=rbind(temp,sim)
}
sim$shape=as.factor(sim$shape)
sim%>%na.omit%>%ggplot(aes(x=Val,fill=shape,col=shape))+
geom_density(alpha=0.2)+
theme_bw()+ggtitle("Beta distribution")

Sau đây là nội dung model STAN
# Proportional test BAYES
stanmodelcode ="
data {
int <lower=2> ng;
int proportion[ng];
int total[ng];
}
transformed data {
}
parameters {
real theta[ng];
}
model {
// khai bao tien dinh (prior)
theta ~ beta(0.5,0.5);
// likelihood
for (i in 1:ng) {
proportion[i] ~ binomial(total[i],theta[i]);
}
}
generated quantities {
int pred[ng];
for (i in 1:ng){
pred[i] = binomial_rng(total[i],theta[i]);
}
}
"
Block data gồm có 3 thành phần: ng là 1 số nguyên >2, chỉ số phân nhóm cần so sánh, trong thí dụ này ng=2; proportion là 1 vector số nguyên có độ dài ng, chứa tần số bệnh nhân có đáp ứng điều trị ở 2 phân nhóm placebo và treatment; total cũng là 1 vector số nguyên, chứa tổng số bệnh nhân ở mỗi phân nhóm placebo và treatmen
Block transformed data không cần thiết
block parameter khai báo 1 tham số theta là 1 vector số thực, có độ dài ng
Block model gồm có: prior của theta là beta(0.5, 0.5);
hàm likelihood của biến kết quả là proportion[i] ~ binomial(total[i],theta[i]);
- Block generated quantities:
Tính giá trị dự báo pred1 và pred2 theo mô hình binomial : pred[i] = binomial_rng(total[i],theta[i]);
Ta tạo 2 vector: positive = số bệnh nhân có cải thiện triệu chứng, và rowsum = tổng số bệnh nhân ở 2 phân nhóm điều trị vs placebo
marked=crosstab[,1]%>%as.vector()
some=crosstab[,3]%>%as.vector()
none=crosstab[,2]%>%as.vector()
positive=marked+some
rowsum=marked+some+none
Và ta thi hành mô hình STAN
data=list(ng=2,proportion=positive,total=rowsum)
fit = stan(model_code=stanmodelcode, data=data, iter=1000, warmup=200, chains=1,cores=4, thin=1)
## In file included from C:/Users/Admin/Documents/R/win-library/3.4/BH/include/boost/config.hpp:39:0,
## from C:/Users/Admin/Documents/R/win-library/3.4/BH/include/boost/math/tools/config.hpp:13,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math/rev/core/var.hpp:7,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math/rev/core/gevv_vvv_vari.hpp:5,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math/rev/core.hpp:12,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math/rev/mat.hpp:4,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/stan/math.hpp:4,
## from C:/Users/Admin/Documents/R/win-library/3.4/StanHeaders/include/src/stan/model/model_header.hpp:4,
## from filef081f962d39.cpp:8:
## C:/Users/Admin/Documents/R/win-library/3.4/BH/include/boost/config/compiler/gcc.hpp:186:0: warning: "BOOST_NO_CXX11_RVALUE_REFERENCES" redefined
## # define BOOST_NO_CXX11_RVALUE_REFERENCES
## ^
## <command-line>:0:0: note: this is the location of the previous definition
## cc1plus.exe: warning: unrecognized command line option "-Wno-ignored-attributes"
##
## SAMPLING FOR MODEL '04fe3b5c2c1476993474804c7e83a5a1' NOW (CHAIN 1).
##
## Gradient evaluation took 0 seconds
## 1000 transitions using 10 leapfrog steps per transition would take 0 seconds.
## Adjust your expectations accordingly!
##
##
## Iteration: 1 / 1000 [ 0%] (Warmup)
## Iteration: 100 / 1000 [ 10%] (Warmup)
## Iteration: 200 / 1000 [ 20%] (Warmup)
## Iteration: 201 / 1000 [ 20%] (Sampling)
## Iteration: 300 / 1000 [ 30%] (Sampling)
## Iteration: 400 / 1000 [ 40%] (Sampling)
## Iteration: 500 / 1000 [ 50%] (Sampling)
## Iteration: 600 / 1000 [ 60%] (Sampling)
## Iteration: 700 / 1000 [ 70%] (Sampling)
## Iteration: 800 / 1000 [ 80%] (Sampling)
## Iteration: 900 / 1000 [ 90%] (Sampling)
## Iteration: 1000 / 1000 [100%] (Sampling)
##
## Elapsed Time: 0.01 seconds (Warm-up)
## 0.02 seconds (Sampling)
## 0.03 seconds (Total)
Sau khi thi hành mô hình BAYES này trong STAN, ta sẽ có phân phối hậu định của 2 tham số Theta1, tương ứng với tỉ lệ điều trị thành công ở mỗi phân nhóm (theta quyết định đặc tính của phân phối binomial, và từ đó quyết định tần số bệnh nhân tại mỗi ô trong bảng 2x2). Theta1 cho nhóm Placebo, Theta2 cho nhóm Treatment. Ta cũng có phân phối hậu định của tần số bệnh nhân (có cải thiện triệu chứng) được ước tính : Pred1 và Pred2.
summary(fit)
## $summary
## mean se_mean sd 2.5% 25%
## theta[1] 0.3309912 0.003078324 0.06609964 0.2102120 0.2858369
## theta[2] 0.6808666 0.002788962 0.07180417 0.5412657 0.6333668
## pred[1] 14.2150000 0.173538683 4.21704925 7.0000000 11.0000000
## pred[2] 27.9112500 0.156339165 4.23713524 19.0000000 25.0000000
## lp__ -52.1387069 0.051342673 0.92616717 -54.7483711 -52.4387371
## 50% 75% 97.5% n_eff Rhat
## theta[1] 0.3305032 0.3724852 0.4772503 461.0727 0.9988131
## theta[2] 0.6833480 0.7316253 0.8138947 662.8483 0.9993492
## pred[1] 14.0000000 17.0000000 23.0000000 590.5066 0.9999734
## pred[2] 28.0000000 31.0000000 36.0000000 734.5292 1.0000668
## lp__ -51.8454698 -51.4643321 -51.2403454 325.4032 1.0001991
##
## $c_summary
## , , chains = chain:1
##
## stats
## parameter mean sd 2.5% 25% 50%
## theta[1] 0.3309912 0.06609964 0.2102120 0.2858369 0.3305032
## theta[2] 0.6808666 0.07180417 0.5412657 0.6333668 0.6833480
## pred[1] 14.2150000 4.21704925 7.0000000 11.0000000 14.0000000
## pred[2] 27.9112500 4.23713524 19.0000000 25.0000000 28.0000000
## lp__ -52.1387069 0.92616717 -54.7483711 -52.4387371 -51.8454698
## stats
## parameter 75% 97.5%
## theta[1] 0.3724852 0.4772503
## theta[2] 0.7316253 0.8138947
## pred[1] 17.0000000 23.0000000
## pred[2] 31.0000000 36.0000000
## lp__ -51.4643321 -51.2403454
Kết quả sơ bộ cho thấy tỉ lệ bệnh nhân có cải thiện triệu chứng cao hơn hẳn ở nhóm trị liệu so với nhóm placebo (theta2=0.68 so với theta1=0.328).
Từ 2 chuỗi MCMC chứa phân phối hậu định của theta1, theta2, ta có thể tạo ra một vector chứa phân phối hậu định của Khác biệt xác suất điều trị thành công giữa 2 phân nhóm: Difprop = Theta2 – Theta1. Suy diễn thống kê sẽ dựa vào vector Difprop này, sử dụng các phương pháp mà Nhi đã trình bày trong bài trước là Comp.Val, ROPE và Bayes Factor.
s=as.data.frame(fit)%>%.[,-5]
colnames(s)=c("Theta_Placebo","Theta_Treated","Pred_Placebo","Pred_Treated")
s$Difprop=s$Theta_Treated-s$Theta_Placebo
Hmisc::describe(s$Difprop)
## s$Difprop
## n missing distinct Info Mean Gmd .05 .10
## 800 0 793 1 0.3499 0.1092 0.1813 0.2184
## .25 .50 .75 .90 .95
## 0.2868 0.3536 0.4170 0.4727 0.5071
##
## lowest : 0.06469176 0.08309505 0.09891270 0.09959744 0.10642911
## highest: 0.59264643 0.59302557 0.59726109 0.62291389 0.62578527
s$pseudoGroup=factor(rep(c(1:20),e=nrow(s)/20))
s$Iter=as.numeric(rownames(s))
Phân phối hậu định của khác biệt về tỉ lệ đáp ứng điều trị là 0.173 -0.519, median khác biệt là 0.3554
Ta có thể vẽ hình phân phối hậu định cho Theta1,Theta2,Difprop như sau:
p1=s%>%ggplot(aes(x=Theta_Treated))+
geom_density(alpha=0.5,col="red4",size=1) +
geom_point(y=0, alpha=.01, size=2,col="red3") +
geom_line(aes(group=pseudoGroup, color=pseudoGroup), stat='density', alpha=.5,show.legend = F)+
scale_x_continuous("Theta_Treated")+
theme_bw()
p2=s%>%ggplot(aes(x=Theta_Placebo))+
geom_density(alpha=0.5,col="blue4",size=1) +
geom_point(y=0, alpha=.01, size=2,col="blue3") +
geom_line(aes(group=pseudoGroup, color=pseudoGroup), stat='density', alpha=.5,show.legend = F)+
scale_x_continuous("Theta_Placebo")+
theme_bw()
p3=s%>%ggplot(aes(x=Difprop))+
geom_density(alpha=0.5,col="purple",size=1) +
geom_point(y=0, alpha=.01, size=2,col="purple") +
geom_line(aes(group=pseudoGroup, color=pseudoGroup), stat='density', alpha=.5,show.legend = F)+
scale_x_continuous("Proportion Difference")+
theme_bw()
p11=s%>%ggplot(aes(x=Iter,y=Theta_Treated))+
geom_path(alpha=.7,show.legend = F,col="red")+
scale_y_continuous("Theta_Treated")+
theme_bw()
p21=s%>%ggplot(aes(x=Iter,y=Theta_Placebo))+
geom_path(alpha=.7,show.legend = F,col="blue")+
scale_y_continuous("Theta_Placebo")+
theme_bw()
p31=s%>%ggplot(aes(x=Iter,y=Theta_Placebo))+
geom_path(alpha=.7,show.legend = F,col="violet")+
scale_y_continuous("Difprop")+
theme_bw()
gridExtra::grid.arrange(p11,p1,p21,p2,p31,p3,ncol=2)

Tiếp theo, Nhi sẽ giới thiệu với các bạn cả 3 cách suy diễn thống kê theo Bayes, đó là Bayes Factor, Ngưỡng so sánh (CompVal) và khoảng vô nghĩa thực dụng (ROPE) :
Bayes Factor
Bản chất của Bayes Factor là tỉ trọng chứng cứ ủng hộ cho một giả thuyết H1 so với giả thuyết H0. Giả thuyết này được xác định bằng 1 ngưỡng giá trị đặc biệt. Bayes factor cho phép kiểm chứng (xác nhận hay loại trừ) giả thuyết H1 có liên quan tới ngưỡng giá trị này.
Ranh giới của H0 và H1 là BF=1, BF càng cao (>1), thì độ khả tín của kết luận (H1) càng lớn, và ngược lại, BF càng thấp (<1) thì chứng cứ ủng hộ cho H0 càng cao. Thông thường khi BF > 10 đã là « strong evidence », BF >30 thì tỉ trọng chứng cứ đã là rất mạnh ; còn khi BF > 100 thì có thể gần như khẳng định chắc chắn H1 là đúng.
BF có thể tính trực tiếp nhờ hàm hypothesis trong package brms, nó nhận 1 input là mô hình STAN (bất kì mô hình Bayes nào do STAN tạo ra, dù là brms, rstan hay rstanarm), và xuất kết quả là Evidence ratio chính là BF.
ROPE và CompVal
Ngoài BF, tác giả John Kruschke đề xuất diễn giải kết quả phân tích Bayes dựa vào tỉ trọng phân phối hậu nghiệm sau khi phân chia bằng 1 khoảng thực dụng (ROPE) hoặc 1 ngưỡng (CompVal). Mục tiêu là xác định mật độ (%) của phân phối hậu nghiệm nằm trong, hay ngoài (cao hơn, thấp hơn) ROPE, hoặc cao/thấp hơn ngưỡng CompVal.
Ngưỡng so sánh : CompVal có bản chất là 1 ngưỡng giá trị nhất định, cho phép chia phân phối hậu nghiệm thành 2 vùng: Cao hơn/Thấp hơn. Công dụng của nó là khẳng định 1 giả thuyết H1 hoặc loại trừ giả thuyết H0 có hàm ý so sánh với 1 ngưỡng ý nghĩa đặc biệt.
ROPE (Region of practice equivalence) có bản chất là 1 khoảng giá trị trên thang đo, giới hạn bởi 2 ngưỡng trên/dưới. ROPE cho phép chia phân phối hậu nghiệm ra 3 vùng:
Vùng trong ROPE xem như vô nghĩa
Ngoài ROPE : gồm Vùng cao / Vùng Thấp
ROPE cho phép khẳng định 1 giả thuyết H1 hoặc loại trừ 1 giả thuyết H0 liên quan tới 1,2 hoặc 3 vùng với ý nghĩa thực dụng tùy chọn. Do đó ROPE tiện ích hơn nhiều so với BF và Null hypothesis testing, vì nó cho phép trả lời cả 3 câu hỏi : kết quả cao hay thấp so với ngưỡng so sánh ? kết quả có ý nghĩa lâm sàng hay không ? Mức độ khả tín là bao nhiêu ?
Phương pháp J.Kruschke áp dụng trên output thuộc lớp MCMC và dựa vào 1 vài hàm do tác giả viết, Nhi chỉ cải biên lại đôi chút.
#Hypothesis testing
# Kruschke codes
HDIF= function( sampleVec,credMass=0.975 ) {
sortedPts = sort( sampleVec )
ciIdxInc = ceiling( credMass * length( sortedPts ) )
nCIs = length( sortedPts ) - ciIdxInc
ciWidth = rep( 0 , nCIs )
for ( i in 1:nCIs ) {
ciWidth[ i ] = sortedPts[ i + ciIdxInc ] - sortedPts[ i ]
}
HDImin = sortedPts[ which.min( ciWidth ) ]
HDImax = sortedPts[ which.min( ciWidth ) + ciIdxInc ]
HDIlim = c( HDImin , HDImax )
return( HDIlim )
}
SUMK=function(paramSampleVec,compVal=NULL , ROPE=NULL , credMass=0.975) {
meanParam = mean( paramSampleVec )
medianParam = median( paramSampleVec )
dres = density( paramSampleVec )
modeParam = dres$x[which.max(dres$y)]
hdiLim = HDIF( paramSampleVec , credMass=credMass )
if ( !is.null(compVal) ) {
pcgtCompVal = ( 100 * sum( paramSampleVec > compVal )
/ length( paramSampleVec ) )
} else {
compVal=NA
pcgtCompVal=NA
}
if ( !is.null(ROPE) ) {
pcltRope = ( 100 * sum( paramSampleVec < ROPE[1] )
/ length( paramSampleVec ) )
pcgtRope = ( 100 * sum( paramSampleVec > ROPE[2] )
/ length( paramSampleVec ) )
pcinRope = 100-(pcltRope+pcgtRope)
} else {
ROPE = c(NA,NA)
pcltRope=NA
pcgtRope=NA
pcinRope=NA
}
return( c( Mean=meanParam , Median=medianParam , Mode=modeParam ,
HDIlevel=credMass , LL=hdiLim[1] , UL=hdiLim[2] ,
CompVal=compVal , PcntGtCompVal=pcgtCompVal ,
ROPElow=ROPE[1] , ROPEhigh=ROPE[2] ,
PcntLtROPE=pcltRope , PcntInROPE=pcinRope , PcntGtROPE=pcgtRope ) )
}
summaryKruschke=function(MCMC,compVal=NULL, rope=NULL,credMass=NULL){
summaryInfo = NULL
summaryInfo = cbind(summaryInfo, "Estimated"= SUMK(MCMC,
compVal=compVal,
ROPE=rope,credMass=credMass))
return(summaryInfo)
}
summaryKruschke(MCMC = s$Difprop,compVal=0.05,rope=c(0.1,0.2),credMass=0.975)
## Estimated
## Mean 0.3498755
## Median 0.3536088
## Mode 0.3650493
## HDIlevel 0.9750000
## LL 0.1256309
## UL 0.5498100
## CompVal 0.0500000
## PcntGtCompVal 100.0000000
## ROPElow 0.1000000
## ROPEhigh 0.2000000
## PcntLtROPE 0.5000000
## PcntInROPE 5.2500000
## PcntGtROPE 94.2500000
#Bayes factor
brms::hypothesis(s,"Difprop>0.05",alpha=0.01)
## Hypothesis Tests for class :
## Estimate Est.Error l-99% CI u-99% CI Evid.Ratio Star
## (Difprop)-(0.05) > 0 0.3 0.1 0.07 Inf Inf *
## ---
## '*': The expected value under the hypothesis lies outside the 99% CI.
Trong thí dụ trên, mục tiêu diễn giải là phân phối hậu định của khác biệt tỉ lệ cải thiện triệu chứng (theta) giữa phân nhóm điều trị và placebo.
Nhi đặt ngưỡng so sánh CompVal = 0.05, như vậy nó cho phép kiểm tra giả thuyết H0: Difprop < hay = 5% và H1:Difprop > 5%; đồng thời Nhi đặt khoảng ROPE từ 10-20%, như vậy giả thuyết ở đây là: nếu khác biệt rơi vào trong khoảng 0.1 - 0.2 (ROPE), xem như không có ý nghĩa lâm sàng, và 2 giả thuyết khác là: Dif < 5% và Dif > 5%.
Kết quả cho thấy có 99.875 % mật độ phân phối hậu định của khác biệt nằm bên phải CompVal (>5%), chỉ có 1.125 % mật độ phân phối hậu định khác biệt tỉ lệ nằm ngoài và dưới ngưỡng bên trái=10% của ROPE, 6.375 % phân phối hậu định rơi vào bên trong ROPE,nhưng có đến 92.5% mật độ nằm bên ngoài và cao hơn ngưỡng trên = 20% của ROPE.
Nếu dùng BF với ngưỡng H1 là 5% khác biệt, ta sẽ có giá trị BF=799, rất lớn; cho thấy độ xác tín rất cao của khác biệt về tỉ lệ cải thiện triệu chứng giữa 2 phân nhóm.
Khi tăng dần ngưỡng H1 từ 5% lên 100%, BF giảm dần như sau:
threshold=rep(NA,20)
BayesFactor=rep(NA,20)
for(i in (1:20)){
thr=i/20
threshold[i]=thr
hyp=paste("(`theta[2]`-`theta[1]`)>",thr,sep="")
bf=brms::hypothesis(fit,hyp,alpha=0.05)
BayesFactor[i]=bf$hypothesis$Evid.Ratio
}
bfdf=cbind(threshold,BayesFactor)%>%as_tibble()
bfdf%>%ggplot(aes(x=threshold,y=BayesFactor,fill=BayesFactor))+
geom_path()+
geom_point(show.legend = F,size=5,shape=21,col="black")+
geom_text(aes(label=round(BayesFactor,2)),col="black",show.legend = F,angle = 60,nudge_y=50,nudge_x=0.05,size=4)+
theme_bw()+
geom_hline(yintercept = c(30,100),linetype=2,col="blue")+
scale_fill_gradient(low="gold",high="red")

Kết quả của phân tích Bayes có thể tóm tắt như sau: Tỉ lệ bệnh nhân có cải thiện triệu chứng được so sánh giữa 2 phân nhóm Dùng thuốc và Placebo thông qua một mô hình phân phối Binomial theo Bayes. Phân phối hậu định của khác biệt cho thấy nhóm điều trị có tỉ lệ cải thiện cao hơn nhóm placebo đến 35.5 % (khoảng mật độ lớn nhất từ 17.3% đến 51.9%).
Tổng kết
Bài thực hành đến đây là chấm dứt. Ngoài một số kỹ năng viết code cho mô hình trong STAN, Nhi đã chuyển đến cho các bạn một số thông điệp chính như sau:
Cùng một bài toán về bảng chéo và phân tích tần số; chúng ta có thể tiếp cận theo nhiều cách. Mỗi cách tương ứng với một phát biểu câu hỏi/giả thuyết khác nhau và sẽ dẫn ta đến những phương pháp thống kê khác nhau . Tuy Chi2 test là một bài toán rất đơn giản, nhưng khi giải quyết nó bằng BAYES, chúng ta học được rất nhiều điều thú vị, và điều này đúng cho mọi quy trình Bayes. Ít nhất, ta đã có khái niệm về 3 loại phân phối khi viết mô hình Bayes cho Chi2 test, đó là phân phối Chi2,phân phối binomial, và phân phối beta, ta có thể diễn đạt bảng chéo thành likelihood và model.
Chi2 test không phải là cách tiếp cận tối ưu, so với mô hình logistic, log linear và so sánh tỉ lệ bằng mô hình binomial.
Chi2 test không có công dụng so sánh tỉ lệ. Nếu bạn muốn so sánh, nên dùng binomial test.
Hẹn gặp lại các bạn vào 1 dịp khác. Nếu các bạn có hứng thú tham gia reboot cho dự án Bayes for Vietnam, xin liên lạc với nhóm chúng tôi.
Xin cảm ơn và hẹn gặp lại
LS0tDQp0aXRsZTogIkJBWUVTIHRoYXkgdGjhur8ga2nhu4NtIMSR4buLbmggQ2hpMiINCnN1YnRpdGxlOiAiU+G7rSBk4bulbmcgbmfDtG4gbmfhu68gU1RBTiINCmF1dGhvcjogIkzDqiBOZ+G7jWMgS2jhuqMgTmhpIg0KZGF0ZTogIjIxIFRow6FuZyA5IDIwMTciDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiAiZGVmYXVsdCINCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyc3RhbikNCmxpYnJhcnkoYnJtcykNCg0KYGBgDQoNCiFbXShjaGkyYmF5ZXMucG5nKQ0KDQojIEdp4bubaSB0aGnhu4d1IA0KDQpUaMOibiBjaMOgbyBjw6FjIGLhuqFuLCDEkcOieSBsw6AgYsOgaSB0aOG7sWMgaMOgbmggdGjhu6kgYmEgdHJvbmcgZOG7sSDDoW4gQmF5ZXMgZm9yIFZpZXRuYW0sIMSRxrDhu6NjIHJlYm9vdCBs4bqhaSB04burIHByb2plY3QgY8O5bmcgdMOqbiBuxINtIDIwMTYuIE3hu6VjIHRpw6p1IGPhu6dhIGThu7Egw6FuIG7DoHkgbMOgIHBo4buVIGJp4bq/biBwaMawxqFuZyBwaMOhcCB0aOG7kW5nIGvDqiB0aGVvIHRyxrDhu51uZyBwaMOhaSBCYXllcyBjaG8gY8OhYyBi4bqhbiBiw6FjIHPEqSB2w6Agc2luaCB2acOqbiB5IGtob2EsIG5o4bqxbSB0aGF5IHRo4bq/IGNobyBuaOG7r25nIGPDtG5nIGPhu6UgdGjhu5FuZyBrw6ogdHJ1eeG7gW4gdGjhu5FuZy4NCg0KUXVhIDIgYsOgaSB0csaw4bubYywgY2jhuq9jIGjhurNuIGPDoWMgYuG6oW4gxJHDoyDEkcaw4bujYyBsw6BtIHF1ZW4gduG7m2kgcXV5IHRyw6xuaCBwaMOibiB0w61jaCB2w6Agc3V5IGRp4buFbiB0aOG7kW5nIGvDqiB0aGVvIHRyxrDhu51uZyBwaMOhaSBCYXllcyB2w6Agbmjhuq1uIHJhIG5o4buvbmcgxJFp4buDbSBraMOhYyBiaeG7h3QgY+G7p2EgQmF5ZXMgc28gduG7m2kgcXV5IHRyw6xuaCBj4buVIMSRaeG7g24uIE5ndXnDqm4gbMO9IGPhu6dhIHBoxrDGoW5nIHBow6FwIG7DoHkgZOG7sWEgdsOgbyDEkeG7i25oIGzDvSBCYXllcywgxJHGsOG7o2MgZGnhu4VuIMSR4bqhdCBi4bqxbmcgbmfDtG4gbmfhu68gbcO0IGjDrG5oLCB4w6FjIHN14bqldCDEkWnhu4F1IGtp4buHbi4gU3V5IGRp4buFbiB0aOG7kW5nIGvDqiB0aGVvIEJheWVzIGxpw6puIGvhur90IGdp4buvYSA0IHBo4bqnbjogROG7ryBsaeG7h3UgcXVhbiBzw6F0IHRo4buxYyB04bq/LCBnaeG6oyB0aHV54bq/dCAocGjDom4gcGjhu5FpKSB0aeG7gW4gxJHhu4tuaCBQcmlvciwgaMOgbSBsaWtlbGlob29kIHbDoCBr4bq/dCBxdeG6oyBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuDQpoLg0KUXV5IHRyw6xuaCBCYXllcyDEkcOyaSBo4buPaSBuZ8aw4budaSB0aOG7sWMgaMOgbmggbmjDrG4gdGjhuqV1IHN14buRdCB24bqlbiDEkeG7gSBtw6AgaOG7jSBwaOG6o2kgxJHhu5FpIGRp4buHbiDEkeG6v24gdOG7q25nIGNoaSB0aeG6v3Qgbmjhu48gbmjhuqV0OiBI4buNIHBo4bqjaSBuaOG6rW4gZGnhu4duIHJhIG5o4buvbmcgYmnhur9uIHPhu5EgdHJvbmcgYsOgaSB0b8OhbiwgxJHDonUgbMOgIGJp4bq/biBr4bq/dCBxdeG6oywgxJHDonUgbMOgIHRoYW0gc+G7kS4gVGnhur9wIHRoZW8sIG5nxrDhu51pIGTDuW5nIHBo4bqjaSBjaHV54buDbiDEkcaw4bujYyBiw6BpIHRvw6FuIHNhbmcgbmfDtG4gbmfhu68gbcO0IGjDrG5oIHbDoCBjaOG7jW4gbeG7mXQgbcO0IGjDrG5oIHBow7kgaOG7o3AuIFThu6sgbcO0IGjDrG5oIG7DoHksIHRhIGzhuqFpIHBo4bqjaSB4w6FjIMSR4buLbmggY8OhYyB0aGFtIHPhu5EsIGjDoG0gbGlrZWxpaG9vZCwgcGjDom4gcGjhu5FpIHRp4buBbiDEkeG7i25oIGNobyB0aGFtIHPhu5EuIEtoaSDEkcOjIHBow6FjIHRo4bqjbyB4b25nIG3DtCBow6xuaCwgdGEgdmnhur90IGNvZGUgxJHhu4MgxJHGsGEgbcO0IGjDrG5oIHbDoG8gbeG7mXQgU2FtcGxlciDEkeG7gyBs4bqleSBt4bqrdSBjaHXhu5dpIE1DTUMgY2hvIHRoYW0gc+G7kSB2w6AgY8OhYyB0cuG7iyBz4buRIHRo4buRbmcga8OqIGtow6FjLiBDw6FjIGNodeG7l2kgTUNNQyBuw6B5IGNo4bupYSBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCwgY8WpbmcgbMOgIGvhur90IHF14bqjIGPhu6dhIHBow6JuIHTDrWNoLiBDdeG7kWkgY8O5bmcsIHRhIHN1eSBkaeG7hW4gdGjhu5FuZyBrw6ogdHLDqm4gcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmgsIGLhurFuZyBuaGnhu4F1IGPDoWNoIGtow6FjIG5oYXUgYmFvIGfhu5NtIEJheWVzIGZhY3Rvciwga2hv4bqjbmcgdsO0IG5naMSpYSB0aOG7sWMgZOG7pW5nIChST1BFKSBoYXkgbmfGsOG7oW5nIHNvIHPDoW5oIChDb21wLlZhbCkuDQoNClThuqFpIG3hu5l0IHPhu5EgduG7iyB0csOtIG7DoG8gxJHDsywgQmF5ZXMgdsOgIHRo4buRbmcga8OqIGPhu5UgxJFp4buDbiBjw7MgdGjhu4MgZ2lhbyBuaGF1LCB0aMOtIGThu6UgdOG7qyBtw7QgaMOsbmggQmF5ZXMsIHRhIGPDsyB0aOG7gyByw7p0IHJhIHBow6JuIHBo4buRaSBo4bqtdSDEkeG7i25oIGNobyBjw6FjIHRy4buLIHPhu5EgdGjhu5FuZyBrw6osIGJhbyBn4buTbSBj4bqjIEVmZmVjdC1zaXplLiBOaMawIHbhuq15IGtow6FjIGJp4buHdCBxdWFuIHRy4buNbmcgbmjhuqV0IGdp4buvYSBCYXllcyB2w6AgY8OhYyBraeG7g20gxJHhu4tuaCB0aOG7kW5nIGvDqiBxdXkgxrDhu5tjLCDEkcOzIGzDoCBjw7Mgc+G7sSBow7JhIGjhu6NwIGdp4buvYSBwcmlvciB2w6AgcG9zdGVyaW9yLCDEkcOzIGzDoCB4w6FjIHN14bqldCDEkWnhu4F1IGtp4buHbiwgbGlrZWxpaG9vZCB2w6AgbcO0IGjDrG5oIHRoYXkgY2hvIG5o4buvbmcgY8O0bmcgdGjhu6ljIHbDoCB0cuG7iyBz4buRIHRo4buRbmcga8OqIG1hbmcgdMOtbmggxJHhuqFpIGRp4buHbiB2w6AgeOG6pXAgeOG7iSAobmjGsCBDaGkyIGNobyBQZWFyc29uIENoaTIgdGVzdCwgdCBjaG8gU3R1ZGVudCB0LXRlc3QsIEYgY2hvIEFOT1ZBICwgciBjaG8gcGjDom4gdMOtY2ggdMawxqFuZyBxdWFuIHZ24oCmKS4gS2jDoWMgYmnhu4d0IHRo4bupIGhhaSBu4bqxbSDhu58gY8OhY2ggZGnhu4VuIGdp4bqjaSBr4bq/dCBxdeG6oy4gVGjhu7FjIHJhLCBQX3ZhbGUgaG/DoG4gdG/DoG4gY8OzIHRo4buDIMSRxrDhu6NjIHTDrW5oIGThu7FhIHbDoG8gcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmgsIG5oxrBuZyBi4bqjbiB0aMOibiBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCDEkcOjIGNo4bupYSBuaGnhu4F1IHRow7RuZyB0aW4gxJHhur9uIG3hu6ljIHRhIGtow7RuZyBj4bqnbiBwaOG6o2kgZMO5bmcgxJHhur9uIHBo4bqjbiBuZ2hp4buHbSwgTnVsbCBoeXBvdGhlc2lzIHRlc3RpbmdzIHbDoCBwX3ZhbHVlIG7hu69hLiANCg0KU2F1IGtoaSB0aGF5IHRo4bq/IFN0dWRlbnQtdCB0ZXN0IHRyb25nIGLDoGkgdGjhu6kgMiwgYsOgaSBuw6B5IE5oaSBz4bq9IGjGsOG7m25nIGThuqtuIGPDoWMgYuG6oW4gZMO5bmcgQmF5ZXMgxJHhu4MgdGhheSB0aOG6vyBjaG8gbeG7mXQgY8O0bmcgY+G7pSBwaOG7lSBiaeG6v24ga2jDoWMgxJHDsyBsw6AgQ2hpMiB0ZXN0IHRyb25nIHBow6JuIHTDrWNoIHThuqduIHPhu5EsIHThu4kgbOG7hyBj4bunYSBi4bqjbmcgY2jDqW8NCg0KUGjDom4gdMOtY2ggYuG6o25nIGNow6lvIHRo4buxYyByYSBsw6AgbeG7mXQgYsOgaSB0b8OhbiB4w6FjIHN14bqldCBy4bqldCDEkcahbiBnaeG6o24sIMSR4bq/biBt4bupYyBzaW5oIHZpw6puIFkga2hvYSBuxINtIHRo4bupIG5o4bqldCBjw7MgdGjhu4MgZ2nhuqNpIHF1eeG6v3QgZOG7hSBkw6BuZzsgdOG6oWkgc2FvIHRhIHBo4bqjaSBkw7luZyDEkeG6v24gQmF5ZXMgPyBOaGkgaHkgduG7jW5nIHNhdSBiw6BpIHRo4buxYyBow6BuaCBi4bqhbiBz4bq9IGPDsyBjw6J1IHRy4bqjIGzhu51pIGNobyBtw6xuaC4NCg0KIyBCw6BpIHRvw6FuIGLhuqNuZyBjaMOpbyB2w6AgMyBjw6FjaCB0xrAgZHV5DQoNCkLhu5kgc+G7kSBsaeG7h3UgbsOgeSBjw7Mgbmd14buTbiBn4buRYyB04burIDEgbmdoacOqbiBj4bupdSB0aOG7rSBuZ2hp4buHbSBsw6JtIHPDoG5nIGPhu6dhIEVkd2FyZHMgS29jaCBuxINtIDE5ODgsIHbhu5tpIG3hu6VjIHRpw6p1IGto4bqjbyBzw6F0IGhp4buHdSBxdeG6oyDEkWnhu4F1IHRy4buLIGLhu4duaCBWacOqbSBraOG7m3AgY+G7p2EgbeG7mXQgbG/huqFpIHRodeG7kWMgKG5ow7NtIFRyZWF0bWVudCksIHNvIHbhu5tpIG5ow7NtIHPhu60gZOG7pW5nIGdp4bqjIGTGsOG7o2MgKHBsYWNlYm8pLiBIaeG7h3UgcXXhuqMgxJFp4buBdSB0cuG7iyDEkcaw4bujYyDEkcOhbmggZ2nDoSBuaMawIG3hu5l0IGJp4bq/biDEkeG7i25oIGRhbmggduG7m2kgMyBi4bqtYyBnacOhIHRy4buLIDogQ+G6o2kgdGhp4buHbiByw7UgcuG7h3QgKG1hcmtlZCksIGPhuqNpIHRoaeG7h24gdMawxqFuZyDEkeG7kWkgKFNvbWUpIHbDoCBraMO0bmcgY8OzIGPhuqNpIHRoaeG7h24gKE5vbmUpIHRyaeG7h3UgY2jhu6luZyBj4bunYSBi4buHbmguIA0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQpkZj1yZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHViLmNvbS92aW5jZW50YXJlbGJ1bmRvY2svUmRhdGFzZXRzL21hc3Rlci9jc3YvdmNkL0FydGhyaXRpcy5jc3YiKQ0KDQpjcm9zc3RhYj14dGFicyh+VHJlYXRtZW50K0ltcHJvdmVkLGRhdGE9ZGYpDQoNCmNyb3NzdGFiDQpgYGANCg0KYGBge3IsbWVzc2FnZSA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHZjZCkNCg0KbW9zYWljKGNyb3NzdGFiLHNoYWRlPVRSVUUsbGVnZW5kPVRSVUUsZ3AgPSBzaGFkaW5nX21heCkNCg0KYGBgDQoNCk5oxrAgduG6rXkgYsOgaSB0b8OhbiBuw6B5IGPDsyAyIGJp4bq/biBz4buRICh54bq/dSB04buRKSA6IFRyZWF0bWVudCB2w6AgT3V0Y29tZSwgY+G6oyAyIMSR4buBdSBsw6AgYmnhur9uIMSR4buLbmggZGFuaCB24bubaSAyIGhv4bq3YyAzIGLhuq1jIGdpw6EgdHLhu4suIFbhu5tpIGThu68gbGnhu4d1IG5oxrAgduG6rXksIHRhIGPDsyB0aOG7gyBwaMOhdCBiaeG7g3UgY8OidSBo4buPaSBuZ2hpw6puIGPhu6l1IChnaeG6oyB0aHV54bq/dCBIMC9IMSkgdGhlbyBuaGnhu4F1IGPDoWNoIGtow6FjIG5oYXU7IHbDoCBjaMO6IMO9IHLhurFuZyBt4buXaSBjw6FjaCBuaMawIHbhuq15IHPhur0gZ+G7o2kgw70gY2hvIGNow7puZyB0YSBz4butIGThu6VuZyBt4buZdCBow6xuaCB0aOG7qWMvY8O0bmcgY+G7pSB0aOG7kW5nIGvDqiBraMOhYyBuaGF1Og0KDQoqKkPDoWNoIHRo4bupIDEqKiANCg0KR2nhuqMgdGh1eeG6v3QgY+G6p24gY2jhu6luZyBtaW5oIGzDoCA6IEPDsyBt4buRaSBsacOqbiBo4buHIGdp4buvYSB54bq/dSB04buRIHBow6JuIG5ow7NtIMSRaeG7gXUgdHLhu4sgdsOgIG3hu6ljIMSR4buZIGPhuqNpIHRoaeG7h24gdHJp4buHdSBjaOG7qW5nOyBHaGkgY2jDujogbGnDqm4gaOG7hyDhu58gxJHDonkgxJHGsOG7o2MgaGnhu4N1IG5n4bqnbSDigJMgbMOgIHbhu4EgdOG6p24gc+G7kSAvIHThu4kgbOG7hyBwaMOibiBi4buRLiBDw6FjaCB0xrAgZHV5IG7DoHkgc+G6vSBk4bqrbiBjaMO6bmcgdGEgxJHhur9uIENoaXNxdWFyZWQgdGVzdCBj4bunYSBQZWFyc29uIHbhu5tpIEgwOiAyIHnhur91IHThu5EgxJBp4buBdSB0cuG7iyB2w6AgQ+G6o2kgdGhp4buHbiB0cmnhu4d1IGNo4bupbmcgbMOgIMSR4buZYyBs4bqtcCB24bubaSBuaGF1IChraMO0bmcgY8OzIGxpw6puIGjhu4cgZ2nhu69hIGNow7puZyksIMSR4buZIHThu7EgZG8gY2hvIENoaTI9IDIuIENow7puZyB0YSBz4bq9IGLDoG4gduG7gSBDaGkydGVzdCB0cm9uZyBwaOG6p24gdGnhur9wIHRoZW8uDQoNCioqQ8OhY2ggdGjhu6kgMioqDQoNCkdp4bqjIHRodXnhur90IGPhuqduIGNo4bupbmcgbWluaCBz4bq9IGzDoDogQ8OzIHPhu7Ega2jDoWMgYmnhu4d0IHbhu4EgdOG7iSBs4buHIHBow6JuIGLhu5EgY+G7p2EgYuG7h25oIG5ow6JuIEPDsyBj4bqjaSB0aGnhu4duIHRyaeG7h3UgY2jhu6luZyBnaeG7r2EgMiBwaMOibiBuaMOzbSA6IETDuW5nIHRodeG7kWMgdsOgIGTDuW5nIEdp4bqjIGTGsOG7o2MuIEPDoWNoIHTGsCBkdXkgbsOgeSBz4bq9IGThuqtuIGNow7puZyB0YSDEkeG6v24gYsOgaSB0b8OhbiBzbyBzw6FuaCB04buJIGzhu4cgxJFp4buBdSB0cuG7iyB0aMOgbmggY8O0bmcgZ2nhu69hIDIgcGjDom4gbmjDs20gKFRyZWF0bWVudCB2cyBQbGFjZWJvKSwgZ2hpIGNow7ogbMOgIHThu4kgbOG7hyBuw6B5IGNow61uaCBsw6AgdOG7iSBz4buRIGdp4buvYSBz4buRIGLhu4duaCBuaMOibiBjw7MgY+G6o2kgdGhp4buHbiBjaGlhIGNobyB04buVbmcgc+G7kSBi4buHbmggbmjDom4g4bufIHThu6tuZyBwaMOibiBuaMOzbSDEkWnhu4F1IHRy4buLLiBCw6BpIHRvw6FuIG7DoHkgZOG6q24gY2jDum5nIHRhIMSR4bq/biBt4buZdCBtw7QgaMOsbmggOiBz4buRIGLhu4duaCBuaMOibiDEkWnhu4F1IHRy4buLIHRow6BuaCBjw7RuZyBsw6AgYmnhur9uIGvhur90IHF14bqjLCDEkcaw4bujYyBtw7QgdOG6oyBi4bqxbmcgcGjDom4gcGjhu5FpIEJpbm9taWFsICh0aGV0YSwgbnRyaWFsKSwgduG7m2kgbnRyaWFsID0gdOG7lW5nIHPhu5EgYuG7h25oIG5ow6JuIOG7nyBt4buXaSBwaMOibiBuaMOzbSDEkWnhu4F1IHRy4buLLCB2w6AgdGhldGEgbMOgIHThu4kgbOG7hyDEkWnhu4F1IHRy4buLIHRow6BuaCBjw7RuZywgdGhhbSBz4buRIGPhu6dhIG3DtCBow6xuaC4gTmjGsCB24bqteSBiw6BpIHRvw6FuIG7DoHkgZ+G6p24gZ2nhu5FuZyB24bubaSBiw6BpIHRvw6FuIHNvIHPDoW5oIHRydW5nIGLDrG5oIGdp4buvYSAyIHBow6JuIG5ow7NtIChraeG7g20gxJHhu4tuaCB0KSwgY2jhu4kgdGhheSBwaMOibiBwaOG7kWkgU3R1ZGVudCB0IGLhurFuZyBwaMOibiBwaOG7kWkgYmlub21pYWwgdsOgIHRoYW0gc+G7kSBNdSBi4bqxbmcgdGhhbSBz4buRIFRoZXRhLiBHaGkgY2jDujogxJHhu4MgdGjhu7FjIGhp4buHbiBwaMOibiB0w61jaCwgdGEgcGjhuqNpIGfhu5lwIDIgcGjDom4gbG/huqFpOiBD4bqjaSB0aGnhu4duIMSRw6FuZyBr4buDIHbDoCBj4bqjaSB0aGnhu4duIHTGsMahbmcgxJHhu5FpIHRow6BuaCBt4buZdC4gDQoNCioqQ8OhY2ggdGjhu6kgMyoqOiANCg0KR2nhuqMgdGh1eeG6v3QgxJHGsOG7o2MgcGjDoXQgYmnhu4N1IG5oxrAgc2F1OiAxIGLhu4duaCBuaMOibiBi4bqldCBrw6wgbuG6v3UgxJHGsOG7o2MgxJFp4buBdSB0cuG7iyBi4bqxbmcgdGh14buRYyBYIHPhur0gY8OzIHjDoWMgc3XhuqV0IGPhuqNpIHRoaeG7h24gdHJp4buHdSBjaOG7qW5nIGNhbyBoxqFuIHNvIHbhu5tpIGtoaSBkw7luZyBwbGFjZWJvLiBPdXRjb21lIGPhu6dhIGLDoGkgdG/DoW4gbsOgeSBsw6AgMSB4w6FjIHN14bqldCBjaG8gMSBjw6EgdGjhu4MuIENo4bqvYyBjw6FjIGLhuqFuIGPFqW5nIG5o4bqtbiByYSwgxJHDonkgbMOgIDEgbcO0IGjDrG5oIGxvZ2lzdGljIGhv4bq3YyBtw7QgaMOsbmggaOG7k2kgcXV5IMSRYSBnacOhIHRy4buLICh0w7l5IHRoZW8gYmnhur9uIGvhur90IHF14bqjIMSRxrDhu6NjIGfhu5lwIHRow6BuaCAxIGJp4bq/biBuaOG7iyBnacOhIDpDw7Mva2jDtG5nIGPDsyBj4bqjaSB0aGnhu4duIGhheSBnaeG7ryBuZ3V5w6puIDMgYuG6rWMgZ2nDoSB0cuG7iy4gQ8OhY2ggdGjhu6kgMyBuw6B5IGhvw6BuIHRvw6BuIGtow6FjIHbhu5tpIDIgY8OhY2ggdHLDqm4sIHbDoCBraMO0bmcgY8OzIGxpw6puIHF1YW4gxJHhur9uIHBow6JuIHTDrWNoIGLhuqNuZyBjaMOpby8gdOG6p24gc+G7kSwgbsOqbiBjaMO6bmcgdGEgc+G6vSBraMO0bmcgeMOpdCB24buBIG7DsyB0cm9uZyBiw6BpLg0KDQpUdXkgY8OhY2ggMSB2w6AgMiDEkeG7gXUgYmnhu4N1IGRp4buFbiBk4buvIGxp4buHdSBi4bqxbmcgYuG6o25nIGNow6lvLCBuaMawbmcgYuG6o24gY2jhuqV0IGPDonUgaOG7j2kgdsOgIGPDoWNoIGdp4bqjaSBxdXnhur90IHLhuqV0IGtow6FjIG5oYXUuIE5oxrAgxJHDoyB0csOsbmggYsOgeSwga2nhu4NtIMSR4buLbmggQ2hpMiBsw6AgZ2nhuqNpIHBow6FwIGNobyBjw6J1IGjhu49pIGNo4bupbmcgbWluaCB24buBIHTDrW5oIMSR4buZYyBs4bqtcC9sacOqbiBo4buHIGdp4buvYSAyIHnhur91IHThu5EgKGJp4bq/biDEkeG7i25oIGRhbmgpLiBEbyDEkcOzLCBj4bqnbiBwaOG6o2kgbsOqdSByw7UgMSDEkWnhu4F1IOG7nyDEkcOieTogY8O0bmcgZOG7pW5nIGPhu6dhIENoaXNxdWFyZSB0ZXN0IGtow7RuZyBwaOG6o2kgbMOgIMSR4buDIHNvIHPDoW5oIHbhu4EgdOG7iSBs4buHIHBow6JuIHBo4buRaSBnaeG7r2EgY8OhYyBwaMOibiBuaMOzbS4gUuG6pXQgbmhp4buBdSBi4bqhbiBzaW5oIHZpw6puIG5o4bqnbSBs4bqrbiDhu58gxJFp4buDbSBuw6B5LCBuw6puIGPDoWMgYuG6oW4gdGjGsOG7nW5nIHZp4bq/dCB0cm9uZyBiw6FvIGPDoW8vbHXhuq1uIHbEg24gbmjGsCBzYXUgOiB04buJIGzhu4cgYuG7h25oIG5ow6JuIGdp4buvYSAyIHBow6JuIG5ow7NtIMSRxrDhu6NjIFNPIFPDgU5IIGLhurFuZyB0ZXN0IENoaTIuIMSQw6J5IGzDoCAxIHBow6F0IGJp4buDdSBzYWkgdsOsIGtoaSBsw6BtIENoaTIgdGVzdCB0YSBraMO0bmcgc28gc8OhbmggY8OhaSBnw6wgY+G6oy4gTeG6t3Qga2jDoWMsIGLhuqFuIHPhur0gdGjhuqV5IHLhurFuZzogbmdheSBj4bqjIGtoaSBjaMO6bmcgdGEgdHLhuqMgbOG7nWkgdGjDoG5oIGPDtG5nIGNobyBjw6J1IGjhu49pIHRo4bupIDEgKHRlc3QgY2hpMiBjaG8gcmEga+G6v3QgcXXhuqMgw70gbmdoxKlhLCBwPDAuMDUpLCBjaOG7qW5nIG1pbmggxJHGsOG7o2MgY8OzIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIHnhur91IHThu5EgTmjDs20gxJFp4buBdSB0cuG7iyB2w6AgWeG6v3UgdOG7kSBD4bqjaSB0aGnhu4duIHRyaeG7h3UgY2jhu6luZywgdGEgduG6q24gY2jGsGEgdGjhu4Mga+G6v3QgbHXhuq1uIGfDrCB24buBIEhp4buHdSDhu6luZyBj4bunYSBUaHXhu5FjIHNvIHbhu5tpIFBsYWNlYm8gY+G6oyAhIChnaeG6oyBz4butIHRhIGhvw6FuIGNodXnhu4NuIHTDqm4gMiBwaMOibiBuaMOzbSBQbGFjZWJvIHbDoCDEkWnhu4F1IHRy4buLLCBi4bqhbiB24bqrbiBz4bq9IGPDsyAxIGvhur90IHF14bqjIHRlc3QgQ2hpMiBkxrDGoW5nIHTDrW5oIG5oxrAgdGjGsOG7nW5nIG5oxrBuZyDDvSBuZ2jEqWEgbMOibSBzw6BuZyBraMOhYyBo4bqzbiAhKTsgZG8gxJHDsyBDw6FjaCDEkeG6t3QgduG6pW4gxJHhu4EgdGjhu6kgMiB2w6AgdGjhu6kgMyB04buRdCBoxqFuIG5oaeG7gXUgc28gduG7m2kgY8OhY2ggdGjhu6kgMSwgdsOsIGLhuqFuIGPDsyB0cm9uZyB0YXkgYuG6sW5nIGNo4bupbmcgxJHhu4tuaCBsxrDhu6NuZyAoeMOhYyBzdeG6pXQga2jhu49pIGLhu4duaCwga2jDoWMgYmnhu4d0IHThuqduIHPhu5EgYuG7h25oIG5ow6JuIGto4buPaSBi4buHbmgsIG9kc3MtcmF0aW8pIGdp4buvYSAyIHBow6JuIG5ow7NtLiANCg0KIyBOaOG6r2MgbOG6oWkgduG7gSBDaGkyIHRlc3QgY+G7lSDEkWnhu4NuDQoNCkNoaXNxdWFyZWQgdGVzdCBsw6AgZ8OsID8gxJDDonkgbMOgIG3hu5l0IGtp4buDbSDEkeG7i25oIHLhuqV0IGPhu5UgeMawYSwgZG8gS2FybCBQZWFyc29uIHThuqFvIHJhIHThu6sgbsSDbSAxOTAwLCBjw7RuZyBk4bulbmcgY+G7p2EgbsOzIGzDoCBraeG7g20gdHJhIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIEjDoG5nIHbDoCBD4buZdCB0cm9uZyBt4buZdCBi4bqjbmcgY2jDqW8uIA0KDQpHaeG6oyB0aHV54bq/dCBIMCBj4bunYSBDaGkyIHRlc3QgbMOgOiBow6BuZyB2w6AgY+G7mXQgdHJvbmcgYuG6o25nIGNow6lvIMSR4buZYyBs4bqtcCB24bubaSBuaGF1ID0ga2jDtG5nIGPDsyBsacOqbiBo4buHIGdp4buvYSAyIHnhur91IHThu5EgdGEgxJFhbmcgeMOpdC4NCkdp4bqjIHRodXnhur90IEgxIGzDoDogY8OzIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGjDoG5nIHbDoCBj4buZdCB0cm9uZyBi4bqjbmcgY2jDqW8gDQoNCkNoaXNxdWFyZWQgdGVzdCBjw7MgMiBnaeG6oyDEkeG7i25oLCB0aOG7qSBuaOG6pXQsIG3hu41pIHF1YW4gc8OhdCB0cm9uZyBi4bqjbmcgY2jDqW8gbMOgIMSR4buZYyBs4bqtcCB24bubaSBuaGF1ICgxIGPDoSB0aOG7gyBjaOG7iSB4deG6pXQgaGnhu4duIDEgbOG6p24g4bufIGjDoG5nL2Phu5l0KTsgdGjhu6kgMiwga2jDtG5nIHF1w6EgMjAlIHThuqduIHPhu5EgZ2nhuqMgxJHhu4tuaCBjw7MgZ2nDoSB0cuG7iyA8IDUuIEdp4bqjIMSR4buLbmggdGjhu6kgMiBuw6B5IGtow6EgcGhp4buBbiB0b8OhaSwgY8OzIHRo4buDIGhp4buDdSBsw6AgduG7m2kgMSBi4bqjbmcgMngyLCB2w6AgdOG6p24gc+G7kSDhu58gMSDDtCBuw6BvIMSRw7MgPDUsIHRhIGtow7RuZyB0aOG7gyBkw7luZyB0ZXN0IENoaTIgxJHGsOG7o2MgbuG7r2EsIHbDrCBraGkgxJHDsyDEkcaw4budbmcgY29uZyBt4bqtdCDEkeG7mSBwaMOibiBwaOG7kWkgY+G7p2EgQ2hpMiBz4bq9IGPDsyBow6xuaCBk4bqhbmcgYuG6pXQgxJHhu5FpIHjhu6luZywga2jDtG5nIGNow61uaCB4w6FjIMSR4buDIHTDrW5oIHjDoWMgc3XhuqV0IGNobyB0cuG7iyBz4buRIHAuIEdp4bqjIMSR4buLbmggbsOgeSBjw7MgdGjhu4MgxJHGsOG7o2Mga2nhu4NtIHRyYSDEkcahbiBnaeG6o24gYuG6sW5nIGPDoWNoIHhlbSBr4bq/dCBxdeG6oyB04bqnbiBz4buRIGdp4bqjIMSR4buLbmggdHJvbmcgYuG6o25nIGNow6lvLg0KDQpUcuG7iyBz4buRIHRo4buRbmcga8OqIGPhu6dhIHRlc3QgY8OzIGLhuqNuIGNo4bqldCBsw6AgdOG7lW5nIGLDrG5oIHBoxrDGoW5nIHNhaSBz4buRIChyZXNpZHVhbCkgZ2nhu69hIFThuqduIHPhu5EgcXVhbiBzw6F0IMSRxrDhu6NjIHRyw6puIHRo4buxYyB04bq/IHRyb25nIGLhuqNuZyBjaMOpbyAob2JzZXJ2ZWQpIHbDoCB04bqnbiBz4buRIGdp4bqjIMSR4buLbmggKGV4cGVjdGVkKSBu4bq/dSBnaeG6oyB0aHV54bq/dCBIMCBsw6AgxJHDum5nLg0KDQpO4bq/dSBnaeG6oyB0aHV54bq/dCBIMCDEkcO6bmcsIHRy4buLIHPhu5EgdGjhu5FuZyBrw6ogbsOgeSB0dcOibiB0aGVvIHF1eSBsdeG6rXQgcGjDom4gcGjhu5FpIENoaXNxdWFyZWQgduG7m2kgxJHhu5kgdOG7sSBkbyA9ZGY7IGRvIMSRw7MgbsOzIMSRxrDhu6NjIMSR4bq3dCB0w6puIGzDoCBDaGlzcXVhcmVkLiBUaOG7sWMgcmEgcGjDom4gcGjhu5FpIENoaTIgcuG6pXQgcGjhu5UgYmnhur9uIHRyb25nIGtp4buDbSDEkeG7i25oIHRo4buRbmcga8OqOyBjw7MgdsOgaSBjaOG7pWMgbG/huqFpIGtp4buDbSDEkeG7i25oIG3DoCB0cuG7iyBz4buRIHRo4buRbmcga8OqIMSRxrDhu6NjIG3DtCB04bqjIGLhurFuZyBwaMOibiBwaOG7kWkgQ2hpMi4NCg0KVOG6p24gc+G7kSBnaeG6oyDEkeG7i25oOg0KDQokJGV4cGVjdGVkID0gXGZyYWN7cm93c3VtICogY29sc3VtfXt0b3RhbH0kJA0KDQrEkOG7mSB04buxIGRvIGRmIGPhu6dhIENoaTIgdGVzdCDEkcaw4bujYyB0w61uaCBuaMawIHNhdToNCg0KJCRkZiA9IChucm93IC0gMSkobmNvbCAtIDEpJCQNCg0KUGVhcnNvbiByZXNpZHVhbCDEkcaw4bujYyB0w61uaCBuaMawIHNhdToNCg0KJCRyZXNpZHVhbCA9IFxmcmFje29ic2VydmVkIC0gZXhwZWN0ZWR9e1xzcXJ0e2V4cGVjdGVkfX0kJA0KDQokJFxjaGleMiA9IFxzdW17XGZyYWN7KG9ic2VydmVkIC0gZXhwZWN0ZWQpXjJ9e2V4cGVjdGVkfX0gPSBcc3Vte3Jlc2lkdWFsc30kJA0KDQpDaGlzcXVhcmUgbMOgIG3hu5l0IHBow6JuIHBo4buRaSBsacOqbiB04bulYywgbsOzIGPDsyAxIHRoYW0gc+G7kSBraeG7g3UgaMOsbmggbMOgIE51PWRmLiBNaW5oIGjhu41hOiBow6xuaCBkw6FuZyBj4bunYSBwaMOibiBwaOG7kWkgQ2hpc3F1YXJlZCDhu58gxJHhu5kgdOG7sSBkbyB04burIDIgxJHhur9uIDE1OyBraGkgZGYgdMSDbmcgZOG6p24sIENoaTIgdHLhu58gbsOqbiDEkeG7kWkgeOG7qW5nIHbDoCBn4bqnbiB24bubaSBwaMOibiBwaOG7kWkgR2F1c3NpYW4uDQoNCmBgYHtyfQ0KIyBDaGkyIA0KDQpzaW09ZGF0YS5mcmFtZShWYWw9cmVwKE5BLDUwMCksbnU9cmVwKE5BLDUwMCkpDQp0ZW1wPXNpbQ0KDQpmb3IgKGkgaW4gKDI6MTUpKXsNCiAgdGVtcCRWYWw9cmNoaXNxKG49NTAwLGRmPWkpDQogIHRlbXAkbnU9aQ0KICBzaW09cmJpbmQodGVtcCxzaW0pDQp9DQoNCnNpbSRudT1hcy5mYWN0b3Ioc2ltJG51KQ0KDQpzaW0lPiVuYS5vbWl0JT4lZ2dwbG90KGFlcyh4PVZhbCxmaWxsPW51LGNvbD1udSkpKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4xKSsNCiAgdGhlbWVfYncoKStnZ3RpdGxlKCJDaGlzcXVhcmVkIGRpc3RyaWJ1dGlvbiIpDQpgYGANCg0KQ2hpc3F1YXJlZCB0ZXN0IGPDsyBt4buZdCBz4buRIGJp4bq/biB0aOG7gywgYmFvIGfhu5NtIHRlc3QgRXhhY3QgY+G7p2EgRmlzaGVyLCBwaMawxqFuZyBwaMOhcCBtw7QgcGjhu49uZyBNb250ZSBDYXJsby4gRWZmZWN0LXNpemUgY+G7p2EgY2hpMiB0ZXN0IGzDoCBWICh0aGVvIENyYW1lcikuIEjDoG0gc2F1IMSRw6J5IHPhur0gdGjhu7FjIGhp4buHbiBjw7luZyBsw7pjIGPhuqMgMyBsb+G6oWkgdGVzdCB2w6AgdMOtbmggQ3JhbWVyJ3MgViBjaG8gMSBi4bqjbmcgY2jDqW86DQoNCmBgYHtyfQ0KY2hpc3F1YXJlPWZ1bmN0aW9uKGNyb3NzdGFiLEIsbGV2ZWwpew0KICB0ZXN0MT1jaGlzcS50ZXN0KGNyb3NzdGFiKQ0KICB0ZXN0Mj1jaGlzcS50ZXN0KGNyb3NzdGFiLHNpbXVsYXRlLnAudmFsdWUgPSBULEI9QikNCiAgdGVzdDM9dGVzdDM9ZmlzaGVyLnRlc3QoY3Jvc3N0YWIpDQogIHA9TW9udGVfQ2FybG9fcHZhbD10ZXN0MiRwLnZhbHVlW1sxXV0NCiAgcHJpbnQocmJpbmQoQ2hpc3FyPXRlc3QxJHN0YXRpc3RpY1tbMV1dLA0KICAgICAgICAgICAgICBkZj10ZXN0MSRwYXJhbWV0ZXJbWzFdXSwNCiAgICAgICAgICAgICAgQ2hpMnBfdmFsPXRlc3QxJHAudmFsdWVbWzFdXSwNCiAgICAgICAgICAgICAgTW9udGVfQ2FybG9fcHZhbD1wLA0KICAgICAgICAgICAgICBGaXNoZXJfZXhhY3RfcHZhbD10ZXN0MyRwLnZhbHVlW1sxXV0sDQogICAgICAgICAgICAgIENyYW1lcl9WPWxzcjo6Y3JhbWVyc1YoY3Jvc3N0YWIpKSkNCiAgICAgICAgfQ0KDQpjaGlzcXVhcmUoY3Jvc3N0YWIsMTAwMDApDQpgYGANCg0KS2hpIGTDuW5nIGjDoG0gc3VtbWFyeSBjaG8gMSBi4bqjbmcgY2jDqW8sIFIgdOG7sSDEkeG7mW5nIGzDoG0gdGVzdCBDaGkyDQoNCmBgYHtyfQ0KY3Jvc3N0YWIlPiVzdW1tYXJ5KCkNCmBgYA0KDQpIw6BtIGNoaXNxLnRlc3QgY2hvIHBow6lwIGzDoG0gQ2hpMiB0ZXN0IHbDoCB0csOtY2ggeHXhuqV0IGPDoWMgdHLhu4sgc+G7kSBiw6puIHRyb25nOg0KDQpgYGB7cn0NCnRlc3QxPWNoaXNxLnRlc3QoY3Jvc3N0YWIpDQoNCnRlc3QxDQpgYGANCg0KVGjDrSBk4bulOiBPYnNlcnZlZCB2YWx1ZXM6DQoNCmBgYHtyfQ0KdGVzdDEkb2JzZXJ2ZWQNCmBgYA0KRXhwZWN0ZWQgdmFsdWVzOg0KDQpgYGB7cn0NCg0KdGVzdDEkZXhwZWN0ZWQNCg0KYGBgDQoNClBlYXJzb24gcmVzaWR1YWwNCg0KYGBge3J9DQp0ZXN0MSRyZXNpZHVhbHMNCg0KYGBgDQoNCiMgQ2hpc3F1YXJlZCB0ZXN0IEJBWUVTDQoNClRhIGPDsyB0aOG7gyBtw7QgcGjhu49uZyBDaGkyIHRlc3QgdGhlbyBwaMawxqFuZyBwaMOhcCBCQVlFUyBuaMawIHNhdToNCg0KVGEgbXXhu5FuIHjDoWMgxJHhu4tuaCBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBj4bunYSB0cuG7iyBz4buRIENoaXNxdWFyZWQgdsOgIEVmZmVjdC1zemllIGPhu6dhIG7DsyBsw6AgQ3JhbWVy4oCZcyBWIGLhurFuZyBt4buZdCBtw7QgaMOsbmggQmF5ZXMgY8OzIGxpa2VsaWhvb2QgZnVuY3Rpb24gxrDhu5tjIHTDrW5oIENoaXNxdWFyZWQgdGhlbyBwaMOibiBwaOG7kWkgQ2hpMiB24bubaSB0aGFtIHPhu5EgbMOgIE51LiBUaeG7gW4gxJHhu4tuaCBj4bunYSBtw7QgaMOsbmggbMOgIHRoYWwgc+G7kSBOdSAoxJHhu5kgdOG7sSBkbyBj4bunYSBwaMOibiBwaOG7kWkgQ2hpMikgY8OzIHBow6JuIHBo4buRaSB1bmlmb3JtICgwLjAxLCAxMDApLiBE4buvIGxp4buHdSDEkeG6p3UgdsOgbyBj4bunYSBtw7QgaMOsbmggbMOgIDIgdmVjdG9yIGNo4bupYSB04bqnbiBz4buRIHF1YW4gc8OhdCDEkcaw4bujYyAob2JzZXJ2ZWQpIHbDoCB04bqnbiBz4buRIGdp4bqjIMSR4buLbmggKGV4cGVjdCkgdHJvbmcgYuG6o25nIGNow6lvLg0KDQpgYGB7cn0NCmV4cGVjdD10ZXN0MSRleHBlY3RlZCU+JWFzLnZlY3RvcigpDQpvYnM9dGVzdDEkb2JzZXJ2ZWQlPiVhcy52ZWN0b3IoKQ0KYGBgDQoNCsSQw6J5IGzDoCBu4buZaSBkdW5nIG3DtCBow6xuaCBTVEFODQoNCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQ0KIyBCYXllc2lhbiBDaGkyIHRlc3QNCg0KbGlicmFyeShyc3RhbikNCg0Kc3Rhbm1vZGVsY29kZSA9Ig0KDQpkYXRhew0KaW50PGxvd2VyPTQ+IG5jZWxsOw0KdmVjdG9yW25jZWxsXSBvYnNlcnZlZDsNCnZlY3RvcltuY2VsbF0gZXhwZWN0Ow0KfQ0KDQp0cmFuc2Zvcm1lZCBkYXRhIHsNCg0KcmVhbCByZXNpZHVhbFtuY2VsbF07DQpyZWFsIGNoaXNxcjsNCnJlYWwgdG90YWw7DQoNCmZvciAoaSBpbiAxOm5jZWxsKSB7DQpyZXNpZHVhbFtpXT0ob2JzZXJ2ZWRbaV0tZXhwZWN0W2ldKV4yL2V4cGVjdFtpXTt9DQoNCmNoaXNxcj1zdW0ocmVzaWR1YWwpOw0KdG90YWwgPSBzdW0ob2JzZXJ2ZWQpOw0KDQp9DQoNCnBhcmFtZXRlcnMgew0KcmVhbCBudTsNCn0NCg0KbW9kZWwgew0KDQovLyBraGFpIGJhbyB0aWVuIGRpbmggKHByaW9yKQ0KDQpudSB+IHVuaWZvcm0oMC4wMSwxMDApOw0KDQovLyBsaWtlbGlob29kDQoNCmNoaXNxciB+IGNoaV9zcXVhcmUobnUpOw0KDQp9DQoNCmdlbmVyYXRlZCBxdWFudGl0aWVzIHsNCnJlYWwgY3JhbWVyc1Y7DQpyZWFsIGNoaTI7DQoNCmNoaTI9Y2hpX3NxdWFyZV9ybmcobnUpOw0KY3JhbWVyc1Y9c3FydChjaGkyL3RvdGFsKTsNCn0NCiINCmBgYA0KDQpNw7QgdOG6oyBu4buZaSBkdW5nIG1vZGVsIFNUQU46DQoNCjEpIEJsb2NrIGRhdGE6IGPhuqduIDMgdGjDoG5oIHBo4bqnbjogbmNlbGw9IHPhu5Egw7QgdHJvbmcgYuG6o25nIGNow6lvLCAyIHZlY3RvciBvYnNlcnZlZCB2w6AgZXhwZWN0Lg0KDQoyKSBCbG9jayB0cmFuc2Zvcm1lZCBkYXRhOiBraGFpIGLDoW8gdmVjdG9yIHJlc2lkdWFsIGzDoCAxIHPhu5EgdGjhu7FjLCBjaGlzcXIgbMOgIDEgc+G7kSB0aOG7sWMsIHRvdGFsIGzDoCAxIHPhu5EgdGjhu7FjLiANCnJlc2lkdWFsIMSRxrDhu6NjIHTDrW5oIGNobyB04burbmcgw7QgdHJvbmcgdmVjdG9yLCBk4buxYSB2w6BvIGV4cGVjdCB2w6Agb2JzZXJ2ZWQgdmVjdG9yLiBDw7MgcmVzaWR1YWwsIHRhIGThu4UgZMOgbmcgdMOtbmggxJHGsOG7o2MgQ2hpMiA9IHN1bShyZXNpZHVhbCkuIFRvdGFsID0gdOG7lW5nIHThuqV0IGPhuqMgZ2nDoSB0cuG7iyBvYnNlcnZlZC4NCg0KMykgTW9kZWwgQmF5ZXMgY8OzIGxpa2VsaWhvb2QgY2hpc3FyIH4gY2hpX3NxdWFyZShudSksIG51IGzDoCBt4buZdCBz4buRIHRo4buxYywgY2jhu4kgxJHhu5kgdOG7sSBkbyBj4bunYSBDaGkyLCBudSBjw7MgcHJpb3IgbMOgIHBow6JuIHBo4buRaSB1bmlmb3JtLg0KDQo0KSBCbG9jayBnZW5lcmF0ZWQgcXVhbnRpdGllczogdGEgbOG6pXkgbeG6q3Ugbmfhuqt1IG5oacOqbiBjaG8gYmnhur9uIGNoaTIgbMOgIDEgc+G7kSB0aOG7sWMsZOG7sWEgdsOgbyBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBj4bunYSBudSwgcuG7k2kgdOG7qyDEkcOzIHTDrW5oIENyYW1lcidzIFYgbMOgIGVmZmVjdHNpemUsIGPFqW5nIGzDoCAxIHPhu5EgdGjhu7FjLg0KDQpLaGkgdGhpIGjDoG5oIG3DtCBow6xuaCBCQVlFUyBuw6B5LCBjaMO6bmcgdGEgc+G6vSBjw7MgcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2EgTnUsIENoaTIgdsOgIENyYW1lcnPigJlWLiANCg0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCmRhdGE9bGlzdChuY2VsbD02LG9ic2VydmVkPW9icyxleHBlY3RlZD1leHBlY3QpDQoNCmZpdCA9IHN0YW4obW9kZWxfY29kZT1zdGFubW9kZWxjb2RlLCBkYXRhPWRhdGEsIGl0ZXI9MTAwMCwgd2FybXVwPTIwMCwgY2hhaW5zPTEsY29yZXM9NCwgdGhpbj0xMCkNCg0Kc3VtbWFyeShmaXQpDQoNCmBgYA0KDQpUYSBjw7MgdGjhu4MgdGjhuqV5IHLhurFuZyBr4bq/dCBxdeG6oyBNZWRpYW4gY+G7p2EgQ2hpMiB2w6AgQ3JhbWVyJ3MgViB0xrDGoW5nIMSRxrDGoW5nIHbhu5tpIHRlc3QgQ2hpMiBmcmVxdWVudGlzdA0KDQpUYSBjw7MgdGjhu4MgZGnhu4VuIGdp4bqjaSBr4bq/dCBxdeG6oyB0cuG7sWMgdGnhur9wIGThu7FhIHbDoG8gQ3JhbWVyc+KAmVYsIGhv4bq3YyBkw7luZyBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBj4bunYSBDaGkyIMSR4buDIMaw4bubYyB0w61uaCBt4buZdCBnacOhIHRy4buLIHBfdmFsdWUgbmjhurFtIGtp4buDbSB0cmEgZ2nhuqMgdGh1eeG6v3QgSDAuIEdpw6EgdHLhu4sgcCBuw6B5ID0gMC4wMDA3LCBy4bqldCBn4bqnbiB24bubaSBwX3ZhbHVlIHRoZW8gcGjGsMahbmcgcGjDoXAgbcO0IHBo4buPbmcgTW9udGUgQ2FybG9tYcOpIHRhIHTDrG0gcmEg4bufIHRyw6puLg0KDQpgYGB7cn0NCmNoaTI9ZXh0cmFjdChmaXQscGFycz0iY2hpMiIpJT4lLltbMV1dDQoNCnA9cmVwKE5BLGxlbmd0aChjaGkyKSkNCg0KZm9yIChpIGluIDE6bGVuZ3RoKGNoaTIpKXsNCiAgcFtpXT1wY2hpc3EoY2hpMltpXSwyLGxvd2VyLnRhaWw9Ril9DQoNCm1lZGlhbihwKQ0KDQpgYGANCg0KTmjGsCB24bqteSwgY8OhY2ggbMOgbSBuw6B5IGtow7RuZyBjaG8gdGEgYmnhur90IHRow6ptIHRow7RuZyB0aW4gbsOgbyBt4bubaSBzbyB24bubaSB0ZXN0IENoaTIgY+G7lSDEkWnhu4NuLg0KDQojIFNvIHPDoW5oIHThu4kgbOG7hyBi4bqxbmcgbcO0IGjDrG5oIEJpbm9taWFsIEJBWUVTDQoNCk3hu5l0IGPDoWNoIHThu5VuZyBxdcOhdCwgc3V5IGRp4buFbiBCYXllcyBk4buxYSB0csOqbiDEkeG7i25oIGzDvSBCYXllcyBuaMawIHNhdSA6DQoNCiQkIHAoXHRoZXRhIHx5LHgpXHByb3B0byBwKHl8XHRoZXRhICx4KSBwKFx0aGV0YSAseCkgJCQNCnRoZW8gxJHDsywgcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2EgbeG7mXQgdGhhbSBz4buRIFRoZXRhIChraGkgdGEgY8OzIHRyb25nIHRheSBk4buvIGxp4buHdSBiaeG6v24ga+G6v3QgcXXhuqMgWSB2w6AgaOG6sW5nIHPhu5EgWCBsw6AgbeG7mXQgbWF0cml4IGPDoWMgcHJlZGljdG9ycyB0cm9uZyBtw7QgaMOsbmgpIHThu4kgbOG7hyB24bubaSB0w61jaCBj4bunYSBow6BtIGxpa2VsaWhvb2QgKHjDoWMgc3XhuqV0IGPDsyDEkWnhu4F1IGtp4buHbiBj4bunYSB5IGtoaSBjw7MgdGhldGEgdsOgIHgpIHbDoCBwaMOibiBwaOG7kWkgdGnhu4FuIMSR4buLbmggKHByaW9yPSBnaeG6oyB0aHV54bq/dCB24buBIHBow6JuIHBo4buRaSBj4bunYSB0aGV0YSkuDQoNClRhIGPDsyB0aOG7gyBiaeG6v24gY8OhY2ggdGnhur9wIGPhuq1uIHRo4bupIDIgKFNvIDIgc8OhbmggdOG7iSBs4buHIHRow6BuaCBjw7RuZyBnaeG7r2EgMiBwaMOibiBuaMOzbSDEkGnhu4F1IHRy4buLIHZzIFBsYWNlYm8pIHRow6BuaCBt4buZdCBtw7QgaMOsbmggQmF5ZXMgbmjGsCBzYXU6DQoNCkThu68gbGnhu4d1IMSR4bqndSB2w6BvIGfhu5NtIGPDszoNCg0KMSB2ZWN0b3IgUHJvcG9ydGlvbiBjw7MgMiBnacOhIHRy4buLIGzDoCB04bqnbiBz4buRIMSRaeG7gXUgdHLhu4sgdGjDoG5oIGPDtG5nIHTGsMahbmcg4bupbmcgY2hvIDIgbmjDs20NCg0KMSB2ZWN0b3IgVG90YWwgduG7m2kgMiBnacOhIHRy4buLIHThu5VuZyBz4buRIGLhu4duaCBuaMOibiDhu58gbeG7l2kgcGjDom4gbmjDs20NCg0K4bueIG3hu5dpIHBow6JuIG5ow7NtLCBiaeG6v24ga+G6v3QgcXXhuqMgY+G7p2EgbcO0IGjDrG5oIGPDsyB0aOG7gyB4ZW0gbmjGsCBsw6Agc+G7kSBs4bqnbiB0aMOgbmggY8O0bmcgKFByb3BvcnRpb25baV0pIHLDunQgcmEgxJHGsOG7o2Mgc2F1IG5baV0gbOG6p24gdGjhu60gdOG7qyBt4buZdCBo4buZcCBrw61uIGNo4bupYSBuW2ldIHBo4bqnbiB04butICg9VG90YWxbaV0pLiANCg0KTmjGsCB24bqteSBxdXkgbHXhuq10IMSR4bqxbmcgc2F1IHRo4butIG5naGnhu4dtIG7DoHkgY2jDrW5oIGzDoCBwaMOibiBwaOG7kWkgQmlub21pYWwuIE5oxrAgdGEgYmnhur90LCBwaMOibiBwaOG7kWkgQmlub21pYWwgY8OzIDIgdGhhbSBz4buRIGzDoCBz4buRIGzhuqduIHRo4butIChuIHRyaWFsKSB2w6AgdOG7iSBs4buHIHRow6BuaCBjw7RuZyAoVGhldGEpLiBT4buRIGzhuqduIHRo4butIOG7nyDEkcOieSB0YSDEkcOjIGJp4bq/dCwgY2jDrW5oIGzDoCB04buVbmcgc+G7kSBi4buHbmggbmjDom4g4bufIG3hu5dpIHBow6JuIG5ow7NtLCB0YSBjaOG7iSBjw7JuIHBo4bqjaSB4w6FjIMSR4buLbmggcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2EgdGhhbSBz4buRIFRoZXRhLg0KDQoNCmBgYHtyfQ0KIyBCaW5vbWlhbA0KDQpzaW09ZGF0YS5mcmFtZShWYWw9cmVwKE5BLDEwMCksdGhldGE9cmVwKE5BLDEwMCkpDQp0ZW1wPXNpbQ0KdGhldGE9YygwLjA1LDAuMSwwLjIsMC4zLDAuNCwwLjUsMC42LDAuNywwLjgsMC45KQ0KDQpmb3IgKGkgaW4gKDE6MTApKXsNCiAgdGVtcCRWYWw9cmJpbm9tKG49MTAwLHByb2I9dGhldGFbaV0sc2l6ZT00MSkNCiAgdGVtcCR0aGV0YT10aGV0YVtpXQ0KICBzaW09cmJpbmQodGVtcCxzaW0pDQp9DQoNCnNpbSR0aGV0YT1hcy5mYWN0b3Ioc2ltJHRoZXRhKQ0KDQpzaW0lPiVuYS5vbWl0JT4lZ2dwbG90KGFlcyh4PVZhbCxmaWxsPXRoZXRhLGNvbD10aGV0YSkpKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4yKSsNCiAgdGhlbWVfYncoKStnZ3RpdGxlKCJCaW5vbWlhbCBkaXN0cmlidXRpb24gLyA0MSB0cmlhbHMiKQ0KYGBgDQoNCg0KR2nhuqMgdGh1eeG6v3QgdGnhu4FuIMSR4buLbmggY2hvIHRoYW0gc+G7kSBUaGV0YSBsw6AgZ8OsID86IERvIHRoZXRhIGzDoCAxIHjDoWMgc3XhuqV0IGPDsyBnacOhIHRy4buLIHThu6sgMC4wIMSR4bq/biAxLjAsIHPhur0gaOG7o3AgbMO9IG7hur91IHRhIGdp4bqjIMSR4buLbmggcuG6sW5nIHRoZXRhIMSRxrDhu6NjIG3DtCB04bqjIGLhurFuZyBwaMOibiBwaOG7kWkgQmV0YS4gTuG6v3UgYuG6oW4ga2jDtG5nIGPDsyB0aMO0bmcgdGluIG7DoG8gduG7gSBwcmlvciwgYuG6oW4gY8OzIHRo4buDIGNo4buNbiBnaeG6o2kgcGjDoXAgYW4gdG/DoG4ga2hpIMSR4bq3dCBwaMOibiBwaOG7kWkgQmV0YShzaGFwZTEsIHNoYXBlMikgY8OzIGjDrG5oIGThuqFuZyDigJxwaOG6s25n4oCdIHThu6ljIGfhuqduIGdp4buRbmcgMSBwaMOibiBwaOG7kWkgVW5pZm9ybSgwLDEpLCBi4bqxbmcgY8OhY2ggZMO5bmcgMiB0aGFtIHPhu5Egc2hhcGUgYuG6sW5nIG5oYXUgPSAxLiANCg0K4bueIMSRw6J5IE5oaSBkw7luZyAxIHByaW9yIGRvIEplZmZyZXkgxJHhu4Egbmdo4buLIGzDoCBCZXRhICgwLjUsIDAuNSkuIE3hu5l0IHByaW9yIGtow6FjIGLhuqFuIGPDsyB0aOG7gyB0aOG7rSBsw6AgcHJpb3IgY+G7p2EgSGFsZGFuZSA6IEJldGEgKDAuMDAwMSwgMC4wMDAxKS4NCg0KYGBge3J9DQojQmV0YSBEaXN0cmlidXRpb24NCg0Kc2ltPWRhdGEuZnJhbWUoVmFsPXJlcChOQSwxMDAwKSxzaGFwZT1yZXAoTkEsNTAwKSkNCnRlbXA9c2ltDQpwYXJhPWMoMC4wMDAxLDAuNSwxLDIsMyw0KQ0KDQpmb3IgKGkgaW4gKDE6Nikpew0KICB0ZW1wJFZhbD1yYmV0YShuPTEwMDAsc2hhcGUxPXBhcmFbaV0sc2hhcGUyPXBhcmFbaV0pDQogIHRlbXAkc2hhcGU9cGFyYVtpXQ0KICBzaW09cmJpbmQodGVtcCxzaW0pDQp9DQoNCnNpbSRzaGFwZT1hcy5mYWN0b3Ioc2ltJHNoYXBlKQ0KDQpzaW0lPiVuYS5vbWl0JT4lZ2dwbG90KGFlcyh4PVZhbCxmaWxsPXNoYXBlLGNvbD1zaGFwZSkpKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4yKSsNCiAgdGhlbWVfYncoKStnZ3RpdGxlKCJCZXRhIGRpc3RyaWJ1dGlvbiIpDQpgYGANCg0KIVtdKHByb3BvcnRpb250ZXN0QmF5ZXMucG5nKQ0KDQpTYXUgxJHDonkgbMOgIG7hu5lpIGR1bmcgbW9kZWwgU1RBTg0KDQpgYGB7cn0NCiMgUHJvcG9ydGlvbmFsIHRlc3QgQkFZRVMNCg0KDQpzdGFubW9kZWxjb2RlID0iDQpkYXRhIHsNCmludCA8bG93ZXI9Mj4gbmc7DQppbnQgcHJvcG9ydGlvbltuZ107DQppbnQgdG90YWxbbmddOw0KfQ0KDQp0cmFuc2Zvcm1lZCBkYXRhIHsNCn0NCg0KcGFyYW1ldGVycyB7DQpyZWFsIHRoZXRhW25nXTsNCn0NCg0KbW9kZWwgew0KDQovLyBraGFpIGJhbyB0aWVuIGRpbmggKHByaW9yKQ0KDQp0aGV0YSB+IGJldGEoMC41LDAuNSk7DQoNCi8vIGxpa2VsaWhvb2QNCmZvciAoaSBpbiAxOm5nKSB7DQpwcm9wb3J0aW9uW2ldIH4gYmlub21pYWwodG90YWxbaV0sdGhldGFbaV0pOw0KfQ0KDQp9DQoNCmdlbmVyYXRlZCBxdWFudGl0aWVzIHsNCg0KaW50IHByZWRbbmddOw0KDQpmb3IgKGkgaW4gMTpuZyl7DQpwcmVkW2ldID0gYmlub21pYWxfcm5nKHRvdGFsW2ldLHRoZXRhW2ldKTsNCn0NCg0KDQoNCn0NCg0KIg0KYGBgDQoNCjEpIEJsb2NrIGRhdGEgZ+G7k20gY8OzIDMgdGjDoG5oIHBo4bqnbjogbmcgbMOgIDEgc+G7kSBuZ3V5w6puID4yLCBjaOG7iSBz4buRIHBow6JuIG5ow7NtIGPhuqduIHNvIHPDoW5oLCB0cm9uZyB0aMOtIGThu6UgbsOgeSBuZz0yOyBwcm9wb3J0aW9uIGzDoCAxIHZlY3RvciBz4buRIG5ndXnDqm4gY8OzIMSR4buZIGTDoGkgbmcsIGNo4bupYSB04bqnbiBz4buRIGLhu4duaCBuaMOibiBjw7MgxJHDoXAg4bupbmcgxJFp4buBdSB0cuG7iyDhu58gMiBwaMOibiBuaMOzbSBwbGFjZWJvIHbDoCB0cmVhdG1lbnQ7IHRvdGFsIGPFqW5nIGzDoCAxIHZlY3RvciBz4buRIG5ndXnDqm4sIGNo4bupYSB04buVbmcgc+G7kSBi4buHbmggbmjDom4g4bufIG3hu5dpIHBow6JuIG5ow7NtICBwbGFjZWJvIHbDoCB0cmVhdG1lbg0KDQoyKSBCbG9jayB0cmFuc2Zvcm1lZCBkYXRhIGtow7RuZyBj4bqnbiB0aGnhur90DQoNCjMpIGJsb2NrIHBhcmFtZXRlciBraGFpIGLDoW8gMSB0aGFtIHPhu5EgdGhldGEgbMOgIDEgdmVjdG9yIHPhu5EgdGjhu7FjLCBjw7MgxJHhu5kgZMOgaSBuZw0KDQo0KSBCbG9jayBtb2RlbCBn4buTbSBjw7M6IHByaW9yIGPhu6dhIHRoZXRhIGzDoCBiZXRhKDAuNSwgMC41KTsNCg0KaMOgbSBsaWtlbGlob29kIGPhu6dhIGJp4bq/biBr4bq/dCBxdeG6oyBsw6AgcHJvcG9ydGlvbltpXSB+IGJpbm9taWFsKHRvdGFsW2ldLHRoZXRhW2ldKTsNCg0KNSkgQmxvY2sgZ2VuZXJhdGVkIHF1YW50aXRpZXM6DQoNClTDrW5oIGdpw6EgdHLhu4sgZOG7sSBiw6FvIHByZWQxIHbDoCBwcmVkMiB0aGVvIG3DtCBow6xuaCBiaW5vbWlhbCA6IHByZWRbaV0gPSBiaW5vbWlhbF9ybmcodG90YWxbaV0sdGhldGFbaV0pOw0KDQpUYSB04bqhbyAyIHZlY3RvcjogcG9zaXRpdmUgPSBz4buRIGLhu4duaCBuaMOibiBjw7MgY+G6o2kgdGhp4buHbiB0cmnhu4d1IGNo4bupbmcsIHbDoCByb3dzdW0gPSB04buVbmcgc+G7kSBi4buHbmggbmjDom4g4bufIDIgcGjDom4gbmjDs20gxJFp4buBdSB0cuG7iyB2cyBwbGFjZWJvDQoNCmBgYHtyfQ0KbWFya2VkPWNyb3NzdGFiWywxXSU+JWFzLnZlY3RvcigpDQpzb21lPWNyb3NzdGFiWywzXSU+JWFzLnZlY3RvcigpDQpub25lPWNyb3NzdGFiWywyXSU+JWFzLnZlY3RvcigpDQoNCnBvc2l0aXZlPW1hcmtlZCtzb21lDQpyb3dzdW09bWFya2VkK3NvbWUrbm9uZQ0KYGBgDQoNClbDoCB0YSB0aGkgaMOgbmggbcO0IGjDrG5oIFNUQU4NCg0KYGBge3IsbWVzc2FnZSA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9DQpkYXRhPWxpc3Qobmc9Mixwcm9wb3J0aW9uPXBvc2l0aXZlLHRvdGFsPXJvd3N1bSkNCg0KZml0ID0gc3Rhbihtb2RlbF9jb2RlPXN0YW5tb2RlbGNvZGUsIGRhdGE9ZGF0YSwgaXRlcj0xMDAwLCB3YXJtdXA9MjAwLCBjaGFpbnM9MSxjb3Jlcz00LCB0aGluPTEpDQpgYGANCg0KU2F1IGtoaSB0aGkgaMOgbmggbcO0IGjDrG5oIEJBWUVTIG7DoHkgdHJvbmcgU1RBTiwgdGEgc+G6vSBjw7MgcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2EgMiB0aGFtIHPhu5EgVGhldGExLCB0xrDGoW5nIOG7qW5nIHbhu5tpIHThu4kgbOG7hyDEkWnhu4F1IHRy4buLIHRow6BuaCBjw7RuZyDhu58gbeG7l2kgcGjDom4gbmjDs20gKHRoZXRhIHF1eeG6v3QgxJHhu4tuaCDEkeG6t2MgdMOtbmggY+G7p2EgcGjDom4gcGjhu5FpIGJpbm9taWFsLCB2w6AgdOG7qyDEkcOzIHF1eeG6v3QgxJHhu4tuaCB04bqnbiBz4buRIGLhu4duaCBuaMOibiB04bqhaSBt4buXaSDDtCB0cm9uZyBi4bqjbmcgMngyKS4gVGhldGExIGNobyBuaMOzbSBQbGFjZWJvLCBUaGV0YTIgY2hvIG5ow7NtIFRyZWF0bWVudC4gVGEgY8WpbmcgY8OzIHBow6JuIHBo4buRaSBo4bqtdSDEkeG7i25oIGPhu6dhIHThuqduIHPhu5EgYuG7h25oIG5ow6JuIChjw7MgY+G6o2kgdGhp4buHbiB0cmnhu4d1IGNo4bupbmcpIMSRxrDhu6NjIMaw4bubYyB0w61uaCA6IFByZWQxIHbDoCBQcmVkMi4NCg0KYGBge3J9DQpzdW1tYXJ5KGZpdCkNCmBgYA0KDQpL4bq/dCBxdeG6oyBzxqEgYuG7mSBjaG8gdGjhuqV5IHThu4kgbOG7hyBi4buHbmggbmjDom4gY8OzIGPhuqNpIHRoaeG7h24gdHJp4buHdSBjaOG7qW5nIGNhbyBoxqFuIGjhurNuIOG7nyBuaMOzbSB0cuG7iyBsaeG7h3Ugc28gduG7m2kgbmjDs20gcGxhY2VibyAodGhldGEyPTAuNjggc28gduG7m2kgdGhldGExPTAuMzI4KS4NCg0KVOG7qyAyIGNodeG7l2kgTUNNQyBjaOG7qWEgcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2EgdGhldGExLCB0aGV0YTIsIHRhIGPDsyB0aOG7gyB04bqhbyByYSBt4buZdCB2ZWN0b3IgY2jhu6lhIHBow6JuIHBo4buRaSBo4bqtdSDEkeG7i25oIGPhu6dhIEtow6FjIGJp4buHdCB4w6FjIHN14bqldCDEkWnhu4F1IHRy4buLIHRow6BuaCBjw7RuZyBnaeG7r2EgMiBwaMOibiBuaMOzbTogRGlmcHJvcCA9IFRoZXRhMiDigJMgVGhldGExLiBTdXkgZGnhu4VuIHRo4buRbmcga8OqIHPhur0gZOG7sWEgdsOgbyB2ZWN0b3IgRGlmcHJvcCBuw6B5LCBz4butIGThu6VuZyBjw6FjIHBoxrDGoW5nIHBow6FwIG3DoCBOaGkgxJHDoyB0csOsbmggYsOgeSB0cm9uZyBiw6BpIHRyxrDhu5tjIGzDoCBDb21wLlZhbCwgUk9QRSB2w6AgQmF5ZXMgRmFjdG9yLg0KDQpgYGB7cn0NCnM9YXMuZGF0YS5mcmFtZShmaXQpJT4lLlssLTVdDQoNCmNvbG5hbWVzKHMpPWMoIlRoZXRhX1BsYWNlYm8iLCJUaGV0YV9UcmVhdGVkIiwiUHJlZF9QbGFjZWJvIiwiUHJlZF9UcmVhdGVkIikNCg0KcyREaWZwcm9wPXMkVGhldGFfVHJlYXRlZC1zJFRoZXRhX1BsYWNlYm8NCg0KSG1pc2M6OmRlc2NyaWJlKHMkRGlmcHJvcCkNCg0KcyRwc2V1ZG9Hcm91cD1mYWN0b3IocmVwKGMoMToyMCksZT1ucm93KHMpLzIwKSkNCnMkSXRlcj1hcy5udW1lcmljKHJvd25hbWVzKHMpKQ0KYGBgDQoNClBow6JuIHBo4buRaSBo4bqtdSDEkeG7i25oIGPhu6dhIGtow6FjIGJp4buHdCB24buBIHThu4kgbOG7hyDEkcOhcCDhu6luZyDEkWnhu4F1IHRy4buLIGzDoCAwLjE3MyAtMC41MTksIG1lZGlhbiBraMOhYyBiaeG7h3QgbMOgIDAuMzU1NA0KDQpUYSBjw7MgdGjhu4MgduG6vSBow6xuaCBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBjaG8gVGhldGExLFRoZXRhMixEaWZwcm9wIG5oxrAgc2F1Og0KDQpgYGB7cn0NCnAxPXMlPiVnZ3Bsb3QoYWVzKHg9VGhldGFfVHJlYXRlZCkpKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC41LGNvbD0icmVkNCIsc2l6ZT0xKSArDQogIGdlb21fcG9pbnQoeT0wLCBhbHBoYT0uMDEsIHNpemU9Mixjb2w9InJlZDMiKSArDQogIGdlb21fbGluZShhZXMoZ3JvdXA9cHNldWRvR3JvdXAsIGNvbG9yPXBzZXVkb0dyb3VwKSwgc3RhdD0nZGVuc2l0eScsIGFscGhhPS41LHNob3cubGVnZW5kID0gRikrDQogIHNjYWxlX3hfY29udGludW91cygiVGhldGFfVHJlYXRlZCIpKw0KICB0aGVtZV9idygpDQoNCg0KcDI9cyU+JWdncGxvdChhZXMoeD1UaGV0YV9QbGFjZWJvKSkrDQogIGdlb21fZGVuc2l0eShhbHBoYT0wLjUsY29sPSJibHVlNCIsc2l6ZT0xKSArDQogIGdlb21fcG9pbnQoeT0wLCBhbHBoYT0uMDEsIHNpemU9Mixjb2w9ImJsdWUzIikgKw0KICBnZW9tX2xpbmUoYWVzKGdyb3VwPXBzZXVkb0dyb3VwLCBjb2xvcj1wc2V1ZG9Hcm91cCksIHN0YXQ9J2RlbnNpdHknLCBhbHBoYT0uNSxzaG93LmxlZ2VuZCA9IEYpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlRoZXRhX1BsYWNlYm8iKSsNCiAgdGhlbWVfYncoKQ0KDQpwMz1zJT4lZ2dwbG90KGFlcyh4PURpZnByb3ApKSsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhPTAuNSxjb2w9InB1cnBsZSIsc2l6ZT0xKSArDQogIGdlb21fcG9pbnQoeT0wLCBhbHBoYT0uMDEsIHNpemU9Mixjb2w9InB1cnBsZSIpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cD1wc2V1ZG9Hcm91cCwgY29sb3I9cHNldWRvR3JvdXApLCBzdGF0PSdkZW5zaXR5JywgYWxwaGE9LjUsc2hvdy5sZWdlbmQgPSBGKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKCJQcm9wb3J0aW9uIERpZmZlcmVuY2UiKSsNCiAgdGhlbWVfYncoKQ0KDQpwMTE9cyU+JWdncGxvdChhZXMoeD1JdGVyLHk9VGhldGFfVHJlYXRlZCkpKw0KICBnZW9tX3BhdGgoYWxwaGE9Ljcsc2hvdy5sZWdlbmQgPSBGLGNvbD0icmVkIikrDQogIHNjYWxlX3lfY29udGludW91cygiVGhldGFfVHJlYXRlZCIpKw0KICB0aGVtZV9idygpDQoNCnAyMT1zJT4lZ2dwbG90KGFlcyh4PUl0ZXIseT1UaGV0YV9QbGFjZWJvKSkrDQogIGdlb21fcGF0aChhbHBoYT0uNyxzaG93LmxlZ2VuZCA9IEYsY29sPSJibHVlIikrDQogIHNjYWxlX3lfY29udGludW91cygiVGhldGFfUGxhY2VibyIpKw0KICB0aGVtZV9idygpDQoNCnAzMT1zJT4lZ2dwbG90KGFlcyh4PUl0ZXIseT1UaGV0YV9QbGFjZWJvKSkrDQogIGdlb21fcGF0aChhbHBoYT0uNyxzaG93LmxlZ2VuZCA9IEYsY29sPSJ2aW9sZXQiKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJEaWZwcm9wIikrDQogIHRoZW1lX2J3KCkNCg0KZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocDExLHAxLHAyMSxwMixwMzEscDMsbmNvbD0yKQ0KYGBgDQoNClRp4bq/cCB0aGVvLCBOaGkgc+G6vSBnaeG7m2kgdGhp4buHdSB24bubaSBjw6FjIGLhuqFuIGPhuqMgMyBjw6FjaCBzdXkgZGnhu4VuIHRo4buRbmcga8OqIHRoZW8gQmF5ZXMsIMSRw7MgbMOgIEJheWVzIEZhY3RvciwgTmfGsOG7oW5nIHNvIHPDoW5oIChDb21wVmFsKSB2w6Aga2hv4bqjbmcgdsO0IG5naMSpYSB0aOG7sWMgZOG7pW5nIChST1BFKSA6DQoNCiFbXShCYXllc2lhbmluZmVyZW5jZS5wbmcpDQoNCiMgQmF5ZXMgRmFjdG9yDQoNCkLhuqNuIGNo4bqldCBj4bunYSBCYXllcyBGYWN0b3IgbMOgIHThu4kgdHLhu41uZyBjaOG7qW5nIGPhu6kg4bunbmcgaOG7mSBjaG8gbeG7mXQgZ2nhuqMgdGh1eeG6v3QgSDEgc28gduG7m2kgZ2nhuqMgdGh1eeG6v3QgSDAuIEdp4bqjIHRodXnhur90IG7DoHkgxJHGsOG7o2MgeMOhYyDEkeG7i25oIGLhurFuZyAxIG5nxrDhu6FuZyBnacOhIHRy4buLIMSR4bq3YyBiaeG7h3QuIEJheWVzIGZhY3RvciBjaG8gcGjDqXAga2nhu4NtIGNo4bupbmcgKHjDoWMgbmjhuq1uIGhheSBsb+G6oWkgdHLhu6spIGdp4bqjIHRodXnhur90IEgxIGPDsyBsacOqbiBxdWFuIHThu5tpIG5nxrDhu6FuZyBnacOhIHRy4buLIG7DoHkuIA0KDQpSYW5oIGdp4bubaSBj4bunYSBIMCB2w6AgSDEgbMOgIEJGPTEsIEJGIGPDoG5nIGNhbyAoPjEpLCB0aMOsIMSR4buZIGto4bqjIHTDrW4gY+G7p2Ega+G6v3QgbHXhuq1uIChIMSkgY8OgbmcgbOG7m24sIHbDoCBuZ8aw4bujYyBs4bqhaSwgQkYgY8OgbmcgdGjhuqVwICg8MSkgdGjDrCBjaOG7qW5nIGPhu6kg4bunbmcgaOG7mSBjaG8gSDAgY8OgbmcgY2FvLiBUaMO0bmcgdGjGsOG7nW5nIGtoaSBCRiA+IDEwIMSRw6MgbMOgIMKrIHN0cm9uZyBldmlkZW5jZSDCuywgQkYgPjMwIHRow6wgdOG7iSB0cuG7jW5nIGNo4bupbmcgY+G7qSDEkcOjIGzDoCBy4bqldCBt4bqhbmggOyBjw7JuIGtoaSBCRiA+IDEwMCB0aMOsIGPDsyB0aOG7gyBn4bqnbiBuaMawIGto4bqzbmcgxJHhu4tuaCBjaOG6r2MgY2jhuq9uIEgxIGzDoCDEkcO6bmcuDQoNCkJGIGPDsyB0aOG7gyB0w61uaCB0cuG7sWMgdGnhur9wIG5o4budIGjDoG0gaHlwb3RoZXNpcyB0cm9uZyBwYWNrYWdlIGJybXMsIG7DsyBuaOG6rW4gMSBpbnB1dCBsw6AgbcO0IGjDrG5oIFNUQU4gKGLhuqV0IGvDrCBtw7QgaMOsbmggQmF5ZXMgbsOgbyBkbyBTVEFOIHThuqFvIHJhLCBkw7kgbMOgIGJybXMsIHJzdGFuIGhheSByc3RhbmFybSksIHbDoCB4deG6pXQga+G6v3QgcXXhuqMgbMOgIEV2aWRlbmNlIHJhdGlvIGNow61uaCBsw6AgQkYuDQoNCiMgUk9QRSB2w6AgQ29tcFZhbA0KDQpOZ2/DoGkgQkYsIHTDoWMgZ2nhuqMgSm9obiBLcnVzY2hrZSDEkeG7gSB4deG6pXQgZGnhu4VuIGdp4bqjaSBr4bq/dCBxdeG6oyBwaMOibiB0w61jaCBCYXllcyBk4buxYSB2w6BvIHThu4kgdHLhu41uZyBwaMOibiBwaOG7kWkgaOG6rXUgbmdoaeG7h20gc2F1IGtoaSBwaMOibiBjaGlhIGLhurFuZyAxIGtob+G6o25nIHRo4buxYyBk4bulbmcgKFJPUEUpIGhv4bq3YyAxIG5nxrDhu6FuZyAoQ29tcFZhbCkuIE3hu6VjIHRpw6p1IGzDoCB4w6FjIMSR4buLbmggbeG6rXQgxJHhu5kgKCUpIGPhu6dhIHBow6JuIHBo4buRaSBo4bqtdSBuZ2hp4buHbSBu4bqxbSB0cm9uZywgaGF5IG5nb8OgaSAoY2FvIGjGoW4sIHRo4bqlcCBoxqFuKSBST1BFLCBob+G6t2MgY2FvL3Ro4bqlcCBoxqFuIG5nxrDhu6FuZyBDb21wVmFsLg0KDQpOZ8aw4buhbmcgc28gc8OhbmggOiBDb21wVmFsIGPDsyBi4bqjbiBjaOG6pXQgbMOgIDEgbmfGsOG7oW5nIGdpw6EgdHLhu4sgbmjhuqV0IMSR4buLbmgsIGNobyBwaMOpcCBjaGlhIHBow6JuIHBo4buRaSBo4bqtdSBuZ2hp4buHbSB0aMOgbmggMiB2w7luZzogQ2FvIGjGoW4vVGjhuqVwIGjGoW4uIEPDtG5nIGThu6VuZyBj4bunYSBuw7MgbMOgIGto4bqzbmcgxJHhu4tuaCAxIGdp4bqjIHRodXnhur90IEgxIGhv4bq3YyBsb+G6oWkgdHLhu6sgZ2nhuqMgdGh1eeG6v3QgSDAgY8OzIGjDoG0gw70gc28gc8OhbmggduG7m2kgMSBuZ8aw4buhbmcgw70gbmdoxKlhIMSR4bq3YyBiaeG7h3QuIA0KDQpST1BFIChSZWdpb24gb2YgcHJhY3RpY2UgZXF1aXZhbGVuY2UpIGPDsyBi4bqjbiBjaOG6pXQgbMOgIDEga2hv4bqjbmcgZ2nDoSB0cuG7iyB0csOqbiB0aGFuZyDEkW8sIGdp4bubaSBo4bqhbiBi4bufaSAyIG5nxrDhu6FuZyB0csOqbi9kxrDhu5tpLiBST1BFIGNobyBwaMOpcCBjaGlhIHBow6JuIHBo4buRaSBo4bqtdSBuZ2hp4buHbSByYSAzIHbDuW5nOg0KDQpWw7luZyB0cm9uZyBST1BFIHhlbSBuaMawIHbDtCBuZ2jEqWEgDQoNCk5nb8OgaSBST1BFIDogZ+G7k20gVsO5bmcgY2FvIC8gVsO5bmcgVGjhuqVwDQoNClJPUEUgY2hvIHBow6lwIGto4bqzbmcgxJHhu4tuaCAxIGdp4bqjIHRodXnhur90IEgxIGhv4bq3YyBsb+G6oWkgdHLhu6sgMSBnaeG6oyB0aHV54bq/dCBIMCBsacOqbiBxdWFuIHThu5tpIDEsMiBob+G6t2MgMyB2w7luZyB24bubaSDDvSBuZ2jEqWEgdGjhu7FjIGThu6VuZyB0w7l5IGNo4buNbi4gRG8gxJHDsyBST1BFIHRp4buHbiDDrWNoIGjGoW4gbmhp4buBdSBzbyB24bubaSBCRiB2w6AgTnVsbCBoeXBvdGhlc2lzIHRlc3RpbmcsIHbDrCBuw7MgY2hvIHBow6lwIHRy4bqjIGzhu51pIGPhuqMgMyBjw6J1IGjhu49pIDoga+G6v3QgcXXhuqMgY2FvIGhheSB0aOG6pXAgc28gduG7m2kgbmfGsOG7oW5nIHNvIHPDoW5oID8ga+G6v3QgcXXhuqMgY8OzIMO9IG5naMSpYSBsw6JtIHPDoG5nIGhheSBraMO0bmcgPyBN4bupYyDEkeG7mSBraOG6oyB0w61uIGzDoCBiYW8gbmhpw6p1ID8NCg0KUGjGsMahbmcgcGjDoXAgSi5LcnVzY2hrZSDDoXAgZOG7pW5nIHRyw6puIG91dHB1dCB0aHXhu5ljIGzhu5twIE1DTUMgdsOgIGThu7FhIHbDoG8gMSB2w6BpIGjDoG0gZG8gdMOhYyBnaeG6oyB2aeG6v3QsIE5oaSBjaOG7iSBj4bqjaSBiacOqbiBs4bqhaSDEkcO0aSBjaMO6dC4NCg0KYGBge3J9DQojSHlwb3RoZXNpcyB0ZXN0aW5nDQoNCiMgS3J1c2Noa2UgY29kZXMNCg0KSERJRj0gZnVuY3Rpb24oIHNhbXBsZVZlYyxjcmVkTWFzcz0wLjk3NSApIHsNCiAgc29ydGVkUHRzID0gc29ydCggc2FtcGxlVmVjICkNCiAgY2lJZHhJbmMgPSBjZWlsaW5nKCBjcmVkTWFzcyAqIGxlbmd0aCggc29ydGVkUHRzICkgKQ0KICBuQ0lzID0gbGVuZ3RoKCBzb3J0ZWRQdHMgKSAtIGNpSWR4SW5jDQogIGNpV2lkdGggPSByZXAoIDAgLCBuQ0lzICkNCiAgZm9yICggaSBpbiAxOm5DSXMgKSB7DQogICAgY2lXaWR0aFsgaSBdID0gc29ydGVkUHRzWyBpICsgY2lJZHhJbmMgXSAtIHNvcnRlZFB0c1sgaSBdDQogIH0NCiAgSERJbWluID0gc29ydGVkUHRzWyB3aGljaC5taW4oIGNpV2lkdGggKSBdDQogIEhESW1heCA9IHNvcnRlZFB0c1sgd2hpY2gubWluKCBjaVdpZHRoICkgKyBjaUlkeEluYyBdDQogIEhESWxpbSA9IGMoIEhESW1pbiAsIEhESW1heCApDQogIHJldHVybiggSERJbGltICkNCn0NCg0KU1VNSz1mdW5jdGlvbihwYXJhbVNhbXBsZVZlYyxjb21wVmFsPU5VTEwgLCBST1BFPU5VTEwgLCBjcmVkTWFzcz0wLjk3NSkgew0KICBtZWFuUGFyYW0gPSBtZWFuKCBwYXJhbVNhbXBsZVZlYyApDQogIG1lZGlhblBhcmFtID0gbWVkaWFuKCBwYXJhbVNhbXBsZVZlYyApDQogIGRyZXMgPSBkZW5zaXR5KCBwYXJhbVNhbXBsZVZlYyApDQogIG1vZGVQYXJhbSA9IGRyZXMkeFt3aGljaC5tYXgoZHJlcyR5KV0NCiAgaGRpTGltID0gSERJRiggcGFyYW1TYW1wbGVWZWMgLCBjcmVkTWFzcz1jcmVkTWFzcyApDQogIGlmICggIWlzLm51bGwoY29tcFZhbCkgKSB7DQogICAgcGNndENvbXBWYWwgPSAoIDEwMCAqIHN1bSggcGFyYW1TYW1wbGVWZWMgPiBjb21wVmFsICkgDQogICAgICAgICAgICAgICAgICAgIC8gbGVuZ3RoKCBwYXJhbVNhbXBsZVZlYyApICkNCiAgfSBlbHNlIHsNCiAgICBjb21wVmFsPU5BDQogICAgcGNndENvbXBWYWw9TkENCiAgfQ0KICBpZiAoICFpcy5udWxsKFJPUEUpICkgew0KICAgIHBjbHRSb3BlID0gKCAxMDAgKiBzdW0oIHBhcmFtU2FtcGxlVmVjIDwgUk9QRVsxXSApIA0KICAgICAgICAgICAgICAgICAvIGxlbmd0aCggcGFyYW1TYW1wbGVWZWMgKSApDQogICAgcGNndFJvcGUgPSAoIDEwMCAqIHN1bSggcGFyYW1TYW1wbGVWZWMgPiBST1BFWzJdICkgDQogICAgICAgICAgICAgICAgIC8gbGVuZ3RoKCBwYXJhbVNhbXBsZVZlYyApICkNCiAgICBwY2luUm9wZSA9IDEwMC0ocGNsdFJvcGUrcGNndFJvcGUpDQogIH0gZWxzZSB7IA0KICAgIFJPUEUgPSBjKE5BLE5BKQ0KICAgIHBjbHRSb3BlPU5BIA0KICAgIHBjZ3RSb3BlPU5BIA0KICAgIHBjaW5Sb3BlPU5BIA0KICB9ICANCiAgcmV0dXJuKCBjKCBNZWFuPW1lYW5QYXJhbSAsIE1lZGlhbj1tZWRpYW5QYXJhbSAsIE1vZGU9bW9kZVBhcmFtICwgDQogICAgICAgICAgICAgSERJbGV2ZWw9Y3JlZE1hc3MgLCBMTD1oZGlMaW1bMV0gLCBVTD1oZGlMaW1bMl0gLCANCiAgICAgICAgICAgICBDb21wVmFsPWNvbXBWYWwgLCBQY250R3RDb21wVmFsPXBjZ3RDb21wVmFsICwgDQogICAgICAgICAgICAgUk9QRWxvdz1ST1BFWzFdICwgUk9QRWhpZ2g9Uk9QRVsyXSAsDQogICAgICAgICAgICAgUGNudEx0Uk9QRT1wY2x0Um9wZSAsIFBjbnRJblJPUEU9cGNpblJvcGUgLCBQY250R3RST1BFPXBjZ3RSb3BlICkgKQ0KfQ0KDQpzdW1tYXJ5S3J1c2Noa2U9ZnVuY3Rpb24oTUNNQyxjb21wVmFsPU5VTEwsIHJvcGU9TlVMTCxjcmVkTWFzcz1OVUxMKXsNCiAgc3VtbWFyeUluZm8gPSBOVUxMDQogIHN1bW1hcnlJbmZvID0gY2JpbmQoc3VtbWFyeUluZm8sICJFc3RpbWF0ZWQiPSBTVU1LKE1DTUMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBWYWw9Y29tcFZhbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUk9QRT1yb3BlLGNyZWRNYXNzPWNyZWRNYXNzKSkNCiAgcmV0dXJuKHN1bW1hcnlJbmZvKQ0KfQ0KDQpzdW1tYXJ5S3J1c2Noa2UoTUNNQyA9IHMkRGlmcHJvcCxjb21wVmFsPTAuMDUscm9wZT1jKDAuMSwwLjIpLGNyZWRNYXNzPTAuOTc1KQ0KDQojQmF5ZXMgZmFjdG9yDQoNCmJybXM6Omh5cG90aGVzaXMocywiRGlmcHJvcD4wLjA1IixhbHBoYT0wLjAxKQ0KDQpgYGANCg0KVHJvbmcgdGjDrSBk4bulIHRyw6puLCBt4bulYyB0acOqdSBkaeG7hW4gZ2nhuqNpIGzDoCBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBj4bunYSBraMOhYyBiaeG7h3QgdOG7iSBs4buHIGPhuqNpIHRoaeG7h24gdHJp4buHdSBjaOG7qW5nICh0aGV0YSkgZ2nhu69hIHBow6JuIG5ow7NtIMSRaeG7gXUgdHLhu4sgdsOgIHBsYWNlYm8uIA0KDQpOaGkgxJHhurd0IG5nxrDhu6FuZyBzbyBzw6FuaCBDb21wVmFsID0gMC4wNSwgbmjGsCB24bqteSBuw7MgY2hvIHBow6lwIGtp4buDbSB0cmEgZ2nhuqMgdGh1eeG6v3QgSDA6IERpZnByb3AgPCBoYXkgPSA1JSB2w6AgSDE6RGlmcHJvcCA+IDUlOyDEkeG7k25nIHRo4budaSBOaGkgxJHhurd0IGtob+G6o25nIFJPUEUgdOG7qyAxMC0yMCUsIG5oxrAgduG6rXkgZ2nhuqMgdGh1eeG6v3Qg4bufIMSRw6J5IGzDoDogbuG6v3Uga2jDoWMgYmnhu4d0IHLGoWkgdsOgbyB0cm9uZyBraG/huqNuZyAwLjEgLSAwLjIgKFJPUEUpLCB4ZW0gbmjGsCBraMO0bmcgY8OzIMO9IG5naMSpYSBsw6JtIHPDoG5nLCB2w6AgMiBnaeG6oyB0aHV54bq/dCBraMOhYyBsw6A6IERpZiA8IDUlIHbDoCBEaWYgPiA1JS4NCg0KS+G6v3QgcXXhuqMgY2hvIHRo4bqleSBjw7MgOTkuODc1ICUgbeG6rXQgxJHhu5kgcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2Ega2jDoWMgYmnhu4d0IG7hurFtIGLDqm4gcGjhuqNpIENvbXBWYWwgKD41JSksIGNo4buJIGPDsyAxLjEyNSAlIG3huq10IMSR4buZIHBow6JuIHBo4buRaSBo4bqtdSDEkeG7i25oIGtow6FjIGJp4buHdCB04buJIGzhu4cgbuG6sW0gbmdvw6BpIHbDoCBkxrDhu5tpIG5nxrDhu6FuZyBiw6puIHRyw6FpPTEwJSBj4bunYSBST1BFLCA2LjM3NSAlIHBow6JuIHBo4buRaSBo4bqtdSDEkeG7i25oIHLGoWkgdsOgbyBiw6puIHRyb25nIFJPUEUsbmjGsG5nIGPDsyDEkeG6v24gOTIuNSUgbeG6rXQgxJHhu5kgbuG6sW0gYsOqbiBuZ2/DoGkgdsOgIGNhbyBoxqFuIG5nxrDhu6FuZyB0csOqbiA9IDIwJSBj4bunYSBST1BFLg0KDQpO4bq/dSBkw7luZyBCRiB24bubaSBuZ8aw4buhbmcgSDEgbMOgIDUlIGtow6FjIGJp4buHdCwgdGEgc+G6vSBjw7MgZ2nDoSB0cuG7iyBCRj03OTksIHLhuqV0IGzhu5tuOyBjaG8gdGjhuqV5IMSR4buZIHjDoWMgdMOtbiBy4bqldCBjYW8gY+G7p2Ega2jDoWMgYmnhu4d0IHbhu4EgdOG7iSBs4buHIGPhuqNpIHRoaeG7h24gdHJp4buHdSBjaOG7qW5nIGdp4buvYSAyIHBow6JuIG5ow7NtLiANCg0KS2hpIHTEg25nIGThuqduIG5nxrDhu6FuZyBIMSB04burIDUlIGzDqm4gMTAwJSwgQkYgZ2nhuqNtIGThuqduIG5oxrAgc2F1Og0KDQpgYGB7cn0NCnRocmVzaG9sZD1yZXAoTkEsMjApDQpCYXllc0ZhY3Rvcj1yZXAoTkEsMjApDQoNCmZvcihpIGluICgxOjIwKSl7DQogIHRocj1pLzIwDQogIHRocmVzaG9sZFtpXT10aHINCiAgaHlwPXBhc3RlKCIoYHRoZXRhWzJdYC1gdGhldGFbMV1gKT4iLHRocixzZXA9IiIpDQogIGJmPWJybXM6Omh5cG90aGVzaXMoZml0LGh5cCxhbHBoYT0wLjA1KQ0KICBCYXllc0ZhY3RvcltpXT1iZiRoeXBvdGhlc2lzJEV2aWQuUmF0aW8NCn0NCg0KYmZkZj1jYmluZCh0aHJlc2hvbGQsQmF5ZXNGYWN0b3IpJT4lYXNfdGliYmxlKCkNCg0KYmZkZiU+JWdncGxvdChhZXMoeD10aHJlc2hvbGQseT1CYXllc0ZhY3RvcixmaWxsPUJheWVzRmFjdG9yKSkrDQogIGdlb21fcGF0aCgpKw0KICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRixzaXplPTUsc2hhcGU9MjEsY29sPSJibGFjayIpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPXJvdW5kKEJheWVzRmFjdG9yLDIpKSxjb2w9ImJsYWNrIixzaG93LmxlZ2VuZCA9IEYsYW5nbGUgPSA2MCxudWRnZV95PTUwLG51ZGdlX3g9MC4wNSxzaXplPTQpKw0KICB0aGVtZV9idygpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKDMwLDEwMCksbGluZXR5cGU9Mixjb2w9ImJsdWUiKSsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9ImdvbGQiLGhpZ2g9InJlZCIpDQpgYGANCg0KS+G6v3QgcXXhuqMgY+G7p2EgcGjDom4gdMOtY2ggQmF5ZXMgY8OzIHRo4buDIHTDs20gdOG6r3QgbmjGsCBzYXU6DQpU4buJIGzhu4cgYuG7h25oIG5ow6JuIGPDsyBj4bqjaSB0aGnhu4duIHRyaeG7h3UgY2jhu6luZyDEkcaw4bujYyBzbyBzw6FuaCBnaeG7r2EgMiBwaMOibiBuaMOzbSBEw7luZyB0aHXhu5FjIHbDoCBQbGFjZWJvIHRow7RuZyBxdWEgbeG7mXQgbcO0IGjDrG5oIHBow6JuIHBo4buRaSBCaW5vbWlhbCB0aGVvIEJheWVzLiBQaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBj4bunYSBraMOhYyBiaeG7h3QgY2hvIHRo4bqleSBuaMOzbSDEkWnhu4F1IHRy4buLIGPDsyB04buJIGzhu4cgY+G6o2kgdGhp4buHbiBjYW8gaMahbiBuaMOzbSBwbGFjZWJvIMSR4bq/biAzNS41ICUgKGtob+G6o25nIG3huq10IMSR4buZIGzhu5tuIG5o4bqldCB04burIDE3LjMlIMSR4bq/biA1MS45JSkuDQoNCiMgVOG7lW5nIGvhur90DQoNCkLDoGkgdGjhu7FjIGjDoG5oIMSR4bq/biDEkcOieSBsw6AgY2jhuqVtIGThu6l0LiBOZ2/DoGkgbeG7mXQgc+G7kSBr4bu5IG7Eg25nIHZp4bq/dCBjb2RlIGNobyBtw7QgaMOsbmggdHJvbmcgU1RBTiwgTmhpIMSRw6MgY2h1eeG7g24gxJHhur9uIGNobyBjw6FjIGLhuqFuIG3hu5l0IHPhu5EgdGjDtG5nIMSRaeG7h3AgY2jDrW5oIG5oxrAgc2F1Og0KDQpDw7luZyBt4buZdCBiw6BpIHRvw6FuIHbhu4EgYuG6o25nIGNow6lvIHbDoCBwaMOibiB0w61jaCB04bqnbiBz4buROyBjaMO6bmcgdGEgY8OzIHRo4buDIHRp4bq/cCBj4bqtbiB0aGVvIG5oaeG7gXUgY8OhY2guIE3hu5dpIGPDoWNoIHTGsMahbmcg4bupbmcgduG7m2kgbeG7mXQgcGjDoXQgYmnhu4N1IGPDonUgaOG7j2kvZ2nhuqMgdGh1eeG6v3Qga2jDoWMgbmhhdSB2w6Agc+G6vSBk4bqrbiB0YSDEkeG6v24gbmjhu69uZyBwaMawxqFuZyBwaMOhcCB0aOG7kW5nIGvDqiBraMOhYyBuaGF1DQouIA0KVHV5IENoaTIgdGVzdCBsw6AgbeG7mXQgYsOgaSB0b8OhbiBy4bqldCDEkcahbiBnaeG6o24sIG5oxrBuZyBraGkgZ2nhuqNpIHF1eeG6v3QgbsOzIGLhurFuZyBCQVlFUywgY2jDum5nIHRhIGjhu41jIMSRxrDhu6NjIHLhuqV0IG5oaeG7gXUgxJFp4buBdSB0aMO6IHbhu4ssIHbDoCDEkWnhu4F1IG7DoHkgxJHDum5nIGNobyBt4buNaSBxdXkgdHLDrG5oIEJheWVzLiDDjXQgbmjhuqV0LCB0YSDEkcOjIGPDsyBraMOhaSBuaeG7h20gduG7gSAzIGxv4bqhaSBwaMOibiBwaOG7kWkga2hpIHZp4bq/dCBtw7QgaMOsbmggQmF5ZXMgY2hvIENoaTIgdGVzdCwgxJHDsyBsw6AgcGjDom4gcGjhu5FpIENoaTIscGjDom4gcGjhu5FpIGJpbm9taWFsLCB2w6AgcGjDom4gcGjhu5FpIGJldGEsIHRhIGPDsyB0aOG7gyBkaeG7hW4gxJHhuqF0IGLhuqNuZyBjaMOpbyB0aMOgbmggbGlrZWxpaG9vZCB2w6AgbW9kZWwuDQoNCkNoaTIgdGVzdCBraMO0bmcgcGjhuqNpIGzDoCBjw6FjaCB0aeG6v3AgY+G6rW4gdOG7kWkgxrB1LCBzbyB24bubaSBtw7QgaMOsbmggbG9naXN0aWMsIGxvZyBsaW5lYXIgdsOgIHNvIHPDoW5oIHThu4kgbOG7hyBi4bqxbmcgbcO0IGjDrG5oIGJpbm9taWFsLiANCg0KQ2hpMiB0ZXN0IGtow7RuZyBjw7MgY8O0bmcgZOG7pW5nIHNvIHPDoW5oIHThu4kgbOG7hy4gTuG6v3UgYuG6oW4gbXXhu5FuIHNvIHPDoW5oLCBuw6puIGTDuW5nIGJpbm9taWFsIHRlc3QuDQogDQpI4bq5biBn4bq3cCBs4bqhaSBjw6FjIGLhuqFuIHbDoG8gMSBk4buLcCBraMOhYy4NCk7hur91IGPDoWMgYuG6oW4gY8OzIGjhu6luZyB0aMO6IHRoYW0gZ2lhIHJlYm9vdCBjaG8gZOG7sSDDoW4gQmF5ZXMgZm9yIFZpZXRuYW0sIHhpbiBsacOqbiBs4bqhYyB24bubaSBuaMOzbSBjaMO6bmcgdMO0aS4gDQoNCipYaW4gY+G6o20gxqFuIHbDoCBo4bq5biBn4bq3cCBs4bqhaSo=