Chuẩn hóa về thang đo bằng hàm scale trong r năm 2024

Thân chào các bạn, đây là bài thực hành thứ 4 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.

Chúng ta đã đi qua 3 chặng đường, dùng Bayes thay thế cho Student t-test, Chisquared test và phân loại bằng hồi quy Logistic. Các bạn đã bắt đầu quen với cấu trúc ngôn ngữ STAN, quy trình chuyển giả thuyết nghiên cứu thành mô hình Bayes, khai thác phân phố hậu định. Qua 2 bài gần đây nhất, ta thấy rằng: 1) Phân tích theo trường phái Bayes có cấu trúc như nhau trong mọi bài toán:

\[p(\theta |outcome, data)\propto p(outcome|\theta) p(\theta ,data)\]

theo đó, phân phối hậu định của một tham số Theta (xác suất điều kiện của theta khi có thông tin về biến kết quả outcome và matrix/vector dữ liệu) tỉ lệ với tích của hàm likelihood (xác suất có điều kiện cho phép ước tính kết quả khi có theta và dữ liệu) với phân phối tiền định (prior= một giả thuyết về phân phối của theta trước khi ta nhìn thấy dữ liệu và kết quả).

  1. Vấn đề là ta phải chuyển câu hỏi nghiên cứu và dữ liệu thành mô hình Bayes, trong đó theta (hoặc outcome) là mục tiêu cần tìm phân phối hậu định, ta phải mô tả được quy luật của hàm likelihood, và cuối cùng, phải cân nhắc trong việc chọn prior. Khi đã phác thảo được mô hình trên giấy thì việc viết code chỉ còn là vấn đề kỹ thuật.
  2. Theo nguyên tắc này, ta có thể thay thế tất cả những công cụ thống kê truyền thống dùng null hypothesis testing và p_value bằng phân tích Bayes.
  3. Sự thay thế có thể thực hiện ở 2 cấp độ (theo 2 cách): hoặc chọn trị số thống kê (thí dụ t cho Student t test, Chisquare cho Pearson’s Chi2 test, và các effect sizes) làm mục tiêu để tìm phân phối hậu định, tức là vẫn bám sát vào truyền thống; hoặc chỉ giữ lại tinh thần của giải pháp mà không chấp chước vào các trị số quy ước, thí dụ thay vì tính t / Cohen’s d thì ta dùng mô hình GLM với likelihood Student-t để khảo sát trực tiếp phân phối hậu định của trung bình khác biệt; thay vì tính Chi2 và Cramer’s V thì ta so sánh trực tiếp 2 tỉ lệ bằng mô hình Binomial Bayes hoặc tính odds-ratio bằng 1 model logistic Bayes, tức là ta bỏ hẳn công cụ đi và chỉ dùng mô hình.

Phân tích tương quan theo Pearson

Bài toán phân tích tương quan rất thường gặp trong nghiên cứu y học. Phân tích tương quan là một giải pháp thống kê rất quan trọng trong nghiên cứu khoa học, nhờ nó mà người ta khám phá ra những quy luật sinh lý bệnh mới, tạo ra thuốc chữa bệnh, liên kết được thông tin mới và cũ, thay thế phương pháp đo lường, biomarker cũ bằng phương pháp mới ưu việt hơn.

Vấn đề là ta có 2 vector X và Y là biến liên tục, và ta muốn biết giữa chúng có sự tương quan hay không. Tùy theo tình huống mà câu hỏi này có thể được diễn đạt khác nhau, thí dụ:

  1. Nếu ta chưa có giả thuyết nào về quan hệ nhân quả, đây sẽ là 1 phân tích mang ý nghĩa chung chung (vô hướng): ta có thể phát biểu giả thuyết: chứng minh X tương quan với Y, hay Y tương quan với X, hay chung chung: có sự tương quan giữa X và Y, hay: X và Y biến thiên cùng (ngược chiều), X và Y tỉ lệ thuận (nghịch)…
  2. Nếu ta có giả thuyết về quan hệ nhân quả, một trong hai biến sẽ là kết quả (Y) và biến còn lại (X) là nguyên nhân. Giả thuyết có thể là: Y phụ thuộc vào X, hay: X gây hiệu ứng lên thay đổi của Y, hay: Sự thay đổi của X gây ra sự thay đổi của Y
  3. Nếu X và Y có cùng bản chất nhưng khác nhau về phương pháp/điều kiện đo lường, hoặc nếu X và Y đều đại diện cho một hiện tượng nào đó, giả thuyết ở đây là: X và Y tương đương với nhau, X có thể thay thế cho Y, hay Y có thể được giải thích bởi X.

Nhưng trong thống kê, phân tích tương quan chỉ là việc đo lường variance của 2 biến số và khảo sát quan hệ giữa chúng, bao nhiêu phần variance của Y chung với X (có thể được giải thích bởi X).

Hệ số tương quan Pearson (kí hiệu : r, thuật ngữ đầy đủ : Pearson’s product moment correlation coefficient) là một trị số thống kê dùng để đo lường độ mạnh và chiều hướng của tương quan giữa 2 biến liên tục X và Y. Một cách tổng quát, r được xác định bằng tỉ số giữa Covariance 2 biến X,Y chia cho tích số của độ lệch chuẩn của chúng:

\[r_{X,Y}=\frac{Cov(XY)}{sd(X)*sd(Y)}\]

Hệ số r dao động trong khoảng -1 đến +1. Giá trị r=0 cho thấy không có tương quan giữa 2 biến. Giá trị r>0 biểu thị cho mối tương quan thuận (X và Y biến thiên cùng chiều), Giá trị r<0 biểu thị cho tương quan nghịch (X tăng thì Y giảm và ngược lại). Càng gần cực trị +/-1 thì tương quan càng mạnh. Giá trị r càng gần 1 cho thấy 2 biến tỉ lệ với nhau một cách hoàn hảo.

Trong trường phái tần số (frequentist), mục tiêu còn là kiểm định ý nghĩa thống kê của r. Một kiểm định t sẽ được áp dụng để phản nghiệm giả thuyết H0 là r=0, ta tính trị số t từ r và cỡ mẫu, t có phân phối Student t, độ tự do = (n-2):

\[t = r\sqrt{\frac{N-2}{1-r^2}}\]

Một hướng đi khác, tốt hơn, đó là dựng một mô hình hồi quy tuyến tính với Y là biến kết quả, X là hiệp biến số. Cách làm này cho ra kết quả phong phú hơn nhiều so với phân tích r đơn giản, vì ngoài độ mạnh, chiều hướng và ý nghĩa của tương quan, mô hình tuyến tính còn cho phép diễn giải mối tương quan theo thang đo tỉ lệ giữa Y và X, thí dụ ta có thể diễn giải : X tăng 1 đơn vị thì Y tăng beta1 đơn vị. Hệ số hồi quy beta do đó cũng có ý nghĩa tương đương với r. Beta và r cùng dấu vì chúng tỉ lệ thuận với nhau. Nếu beta=0 thì r cũng sẽ =0, do đó kiểm định t cho hệ số hồi quy beta giữa Y và X cũng chính là cho ý nghĩa thống kê của mối tương quan, chúng sẽ cho ra cùng trị số t, cùng p_value. Một mô hình tuyến tính còn cho phép đưa thêm biến số X2, X3… để xét mối tương quan riêng phần.

Một nguyên nhân khác khiến mô hình hồi quy tốt hơn Pearson’s r, đó là r nhạy hơn với việc thang đo của X bị chặn (giá trị của X trong mẫu không bao quát hết toàn bộ thang đo của nó trên thực tế), mô hình hồi quy ít bị ảnh hưởng bởi điều này.

Cuối cùng, mô hình hồi quy cho phép diễn giải kết quả với ý nghĩa nhân quả, có định hướng.

Nhược điểm của trường phái frequentist

Trường phái frequentist và null hypothesis testing (với p value) có vài nhược điểm, trong số đó nguy hiểm nhất là 2 vấn đề như sau :

Thứ nhất : Ý nghĩa thống kê hoàn toàn khác với ý nghĩa lâm sàng : Cả r và p value đều không cho phép kết luận về ý nghĩa lâm sàng :

Vấn đề này có thể được minh chứng qua thí dụ mô phỏng sau đây : Quan hệ giữa Y và X là vô cùng nhỏ bé (khoảng 1 phần triệu), tuy nhiên mô hình vẫn cho ra một giá trị p rất đẹp và 1 hệ số tương quan mạnh. Phi lý quá phải không các bạn ?

set.seed(123)  
sample=data.frame(X=c(1:50))%>%mutate(.,Y=0.000001*X+45+rnorm(50,0,0.000005))
## Warning: package 'bindrcpp' was built under R version 3.4.1
sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)
sample%>%lm(Y~X,.)%>%summary()
##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16
cor.test(sample$X,sample$Y)
##   
##  Pearson's product-moment correlation  
##   
## data:  sample$X and sample$Y  
## t = 21.673, df = 48, p-value < 2.2e-16  
## alternative hypothesis: true correlation is not equal to 0  
## 95 percent confidence interval:  
##  0.9173988 0.9729143  
## sample estimates:  
##      cor   
## 0.952516

Thứ hai : Độ lớn của r và ý nghĩa thống kê (p value) phụ thuộc vào cỡ mẫu, và chúng có thể mâu thuẫn nhau. Bản thân p value không cho biết độ mạnh tương quan và ngược lại. Ta có thể thấy điều này qua thí dụ sau :

Một mối tương quan mạnh (được mô phỏng theo công thức) nhưng cỡ mẫu quá thấp (n=5) sẽ cho ra kết quả p_value không có ý nghĩa thống kê

set.seed(123)  
sample=data.frame(X=c(1:5))%>%mutate(.,Y=X*rnorm(5,5,4)+rnorm(5,5,4))
sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red",fill="gold")+  
  geom_point(shape=21,size=5,color="black",fill="red")+  
  theme_bw()
sample%>%lm(Y~X,.)%>%summary()
##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##       1       2       3       4       5   
## -0.7218 -4.4127 10.1545 -4.1838 -0.8362   
##   
## Coefficients:  
##             Estimate Std. Error t value Pr(>|t|)  
## (Intercept)   11.265      7.198   1.565    0.216  
## X              4.075      2.170   1.877    0.157  
##   
## Residual standard error: 6.863 on 3 degrees of freedom  
## Multiple R-squared:  0.5402, Adjusted R-squared:  0.387   
## F-statistic: 3.525 on 1 and 3 DF,  p-value: 0.1571
cor.test(sample$X,sample$Y)
## Warning: package 'bindrcpp' was built under R version 3.4.1

1

Trong khi đó, chỉ cần tăng cỡ mẫu lên cực lớn,thí dụ =1000, mọi mối tương quan mạnh hay yếu đều trở nên có ý nghĩa thống kê với P_value rất đẹp:

## Warning: package 'bindrcpp' was built under R version 3.4.1

2

sample%>%lm(Y~X,.)%>%summary()
## Warning: package 'bindrcpp' was built under R version 3.4.1

4

cor.test(sample$X,sample$Y)
## Warning: package 'bindrcpp' was built under R version 3.4.1

6

Trong một thí dụ khác, X và Y được mô phỏng theo cùng 1 quy luật phân phối, nhưng cỡ mẫu càng lớn thì kết quả càng có ý nghĩa thống kê, p value càng đẹp

## Warning: package 'bindrcpp' was built under R version 3.4.1

7

Để khắc phục những nhược điểm này và đạt tới một kết quả hòa hợp giữa ý nghĩa thực tiễn, độ tin cậy, giả thuyết và dữ liệu, ta cần tìm một hướng đi khác, và đó là phương pháp Bayes.

Bài toán minh họa

Trong bài này, Nhi sẽ dùng bộ số liệu khảo sát tính tương hợp giữa 2 phương pháp đo gián tiếp cung lượng tim (cardiac output) : TCO đo bằng Thermodilution, FCO đo bằng định luật Fick trên 15 bệnh nhân. Số liệu lấy từ nghiên cứu của Avi A. Weinbroum (Journal of Clinical Monitoring and Computing (2008) 22: 361-366).

Như vậy bài toán này có 2 biến số TCO và FCO.

Do TCO và FCO có cùng ý nghĩa sinh lý, cùng đơn vị đo, đây là 1 bài toán với mục tiêu hoán đổi biến số/chứng minh sự tương hợp. Nhi giả định TCO là biến kết quả, FCO là predictor; Giả thuyết nghiên cứu được phát biểu là:

  1. Chung chung: chứng minh có tương quan thuận giữa TCO và FCO
  2. Cụ thể: chúng minh TCO tương đương với FCO, hay: FCO có thể giải thích gần như toàn bộ variance của TCO.

## Warning: package 'bindrcpp' was built under R version 3.4.1

8 TCO FCO 4.9 5.3 7.4 10.2 8.1 8.7 3.1 3.7 5.7 7.6 3.1 3.7

## Warning: package 'bindrcpp' was built under R version 3.4.1

9

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

0

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

1

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

2

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

3

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

4

Giải pháp Bayes cho phân tích tương quan

Để đi tìm hệ số r bằng phương pháp Bayes, chúng ta phải xây dựng mô hình. Mô hình này là gì ? Ta đã có câu trả lời ở trên: đó là một mô hình hồi quy tuyến tính đơn biến Y ~ X. Vì nếu truy nguyên ta sẽ thấy rằng tất cả khái niệm như hiệp phương sai (covariance), phương sai (variance), độ lệch chuẩn (sigma, là căn bậc 2 của variance), sum of square (tổng bình phương sai số), hệ số tương quan r … đều có quan hệ với nhau và chúng cùng hội tụ về mô hình hồi quy tuyến tính do Karl Pearson và Francis Galton xây dựng vào những năm 1880.

Như vậy bản chất của phân tích tương quan là dựng một mô hình tuyến tính (đường thẳng), sau đó đo lường xem các giá trị quan sát thực tế cách đường thẳng này bào xa, hay nói cách khác, liệu mô hình này có phù hợp với dữ liệu hay không.

Có hai con đường cho phép kết nối giữa hệ số r và mô hình hồi quy tuyến tính, đó là:

Thứ nhất: Hệ số hồi quy beta cho Xi trong một mô hình hồi quy Y =X tỉ lệ thuận với r và có thể được tính từ r qua công thức:

\[b_{X_{i}} =\frac{Cov(X_{i}Y)}{Var(X_{i})} = r_{X,Y}\tfrac{sdY}{sdX}\] Như vậy, trong một mô hình mà cả X và Y đều được chuẩn hóa (về đơn vị là sd), thì hệ số hồi quy beta chính là r

Thứ 2: Cho một mô hình hồi quy tuyến tính, giá trị của r chính là căn bậc hai của hệ số Rsquared.

\[Pearson's \ r(X,Y) = \sqrt{R^2}\] Ta có thể kiểm chứng như sau:

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

5

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

6

Như vậy cả 4 cách làm đều dẫn tới giá trị r như nhau.

Giải pháp Bayes thứ 1: Mô hình XY chuẩn hóa

Trong cách làm thứ nhất, ta sẽ xác định trực tiếp phân phối hậu định của r dựa vào tính chất: r chính là hệ số hồi quy beta của mô hình tuyến tính Y~X mà cả X và Y đều đã chuẩn hóa bằng hàm scale( ).

Như vậy nội dung mô hình STAN như sau:

  1. Block data : khai báo 3 thành phần: cỡ mẫu n là một số nguyên có giá trị nhỏ nhất = 3; X và Y là 2 vector chứa giá trị đã được chuẩn hóa của X và Y
  2. Block parameter : khai báo 3 tham số trong mô hình: intercept là một số thực, beta là hệ số hồi quy của X trong mô hình, nó là 1 số thực nhưng bị chặn trong khoảng -1 đến 1 (ta sẽ dùng beta như hệ số r); sigma là sd của Y trong hàm likelihood, là số thực có giá trị thấp nhất =0)
  3. Block model : khai báo tham số mu là giá trị kỳ vọng của Y trong hàm likelihood, mu là 1 vector có độ dài n;

Sau đó ta khai báo 3 priors cho intercept, beta và sigma. Do ta không có thông tin gì về intercept, nên Nhi chọn một prior vô thưởng vô phạt là phân phối normal, trung bình = 0, sd=100 ;

cho tham số beta (hay r), Nhi có 1 giả định ngay từ đầu đó là X và Y có tương quan rất mạnh (nhận xét trực quan trên đồ thị), nên Nhi dùng 1 prior cụ thể đó là beta có phân phối chuẩn, trung bình =0.95 và sd =0.25 (ta không quên là beta bị chặn ở giá trị =1 nha các bạn)

; và sigma có phân phối half Cauchy, do không có giả thuyết nào cho nó.

Hàm likelihood có nội dung : Y được mô tả bằng phân phối normal (mu,sigma) với mu được ước tính bằng mô hình tuyến tính mu = intercept+beta*X

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

7

Để thi hành mô hình này, trước tiên ta chuẩn hóa TCO và FCO, và chuyển kết quả thành 2 vector Y và X.Sau đó ta tạo data list cho mô hình

Ta sẽ xác định quy trình lấy mẫu MCMC bằng các tùy chỉnh như: số chuỗi (nchain=3), số lượt khởi động (để ổn định quy trình, phần này sẽ không được lưu lại, thinstep để rút ngắn kích thước mẫu, số lượt sẽ được sao lưu trong cả 3 chuỗi (save= 3000 cho mỗi chuỗi), như vậy iter = tổng số lượt lấy mẫu; cores=4 cho phép huy động tối đa 4 lõi vi xử lý cho quy trình lấy mẫu để tăng tốc độ converge.

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

8

sample%>%ggplot(aes(x=X,y=Y))+  
  geom_smooth(method="lm",color="red")+  
  geom_point(shape=21,size=2,color="black",fill="red")+  
  theme_bw()+ylim(44,46)

9

Sau khi thi hành mô hình STAN, ta có thể khai thác kết quả. Kết quả chính của mô hình này là phân phối hậu định cho tham số beta,cũng chính là hệ số tương quan r:

sample%>%lm(Y~X,.)%>%summary()

0

sample%>%lm(Y~X,.)%>%summary()

1

Median của beta là 0.93 (từ 0.79 đến 1), cho thấy một sự tương quan mạnh giữa X và Y

sample%>%lm(Y~X,.)%>%summary()

2

Đây là mục tiêu ta nhắm đến, nhưng chưa phải là một giải pháp tối ưu. Như đã nói ở trên, một mô hình tuyến tính là cách làm tối ưu cho phân tích tương quan. Chúng ta sẽ thực hiện nó bằng phương pháp Bayes:

Giải pháp Bayes thứ 2: Mô hình tuyến tính

Mục tiêu bây giờ đó là dựng một mô hình tuyến tính với Y là kết quả, X là predictor. Trong phương pháp Bayes, điều này có nghĩa là ta đi tìm phân phối hậu định cho các tham số beta0 (intercept) beta1 cho X, 2 tham số này cho phép ước tính Mu là trung bình dự báo của Y. Tham số thứ 3 là sigma, hay SD của phân phối chuẩn của Y.

Một thủ thuật thường dùng trong phân tích hồi quy cho biến định lượng liên tục, đó là di dời mốc thang đo của X về vị trí trung bình (centering), tức là mỗi giá trị Xi trừ cho trung bình của X. Việc di dời này cho phép diễn giải kết quả một cách chính xác hơn. Nó thay đổi intercept nhưng không làm ảnh hưởng gì đến hệ số hồi quy beta.

Centering sẽ được áp dụng trong mô hình Bayes. Ta sẽ xuất kết quả 2 giá trị Intercept, một ở thang đo nguyên thủy của X, một cho thang đo sau khi di dời.

Nội dung của mô hình STAN như sau:

  1. Block data : Khai báo 4 thành phần trong list data: cỡ mẫu n là một số nguyên có giá trị nhỏ nhất = 3, Y là 1 vector cho biến kết quả, có kích thước =n; nX là số predictor trong mô hình (trong trường hợp ta có nhiều hơn 1 predictor), nX là 1 số nguyên, nhỏ nhất =1; X là một matrix (n hàng, nX cột) đại diện cho model matrix.
  2. Block transformed data: nhằm hoán chuyển dữ liệu (ở đây là centering). Trước tiên ta khai báo Xc là một matrix X sau khi di dời thang đo của tất cả nX-1 cột bên trong ; means_X là một vector có kích thước nX-1, chứa giá trị trung bình cho mỗi predictor Xi trong matrix X. Hàm hoán chuyển (centering) là 1 vòng lặp có nội dung lấy mỗi giá trị Xi trừ cho means_X
  3. Block parameters: khai báo tham số trong mô hình, gồm: beta là vector kích thước nX-1, nó chứa hệ số hồi quy cho các predictors Xi trong matrix X (lưu ý; beta không bị ảnh hưởng bởi centering); cbeta0 là một số thực, chứa intercept (chỉ có 1 intercept) của mô hình với matrix Xc; sigma là một số thực, tham số scale cho phân phối normal của Y.
  4. Block transformed parameter không sử dụng
  5. Block model : Đầu tiên ta khai báo tham số trung gian mu, là 1 vector kích thước n, mu chỉ giá trị trung bình của phân phối Normal của Y, mu = giá trị dự báo của Y trong mô hình tuyến tính. Hàm likelihood có nội dung: Y được mô tả bằng 1 phân phối normal, với 2 tham số Mu và Sigma.

Có 3 tham số nên có 3 priors; cụ thể: flat prior được dùng cho beta và cbeta, half Cauchy được dùng cho sigma.

  1. Block transformed parameters cho phép chúng ta tính được Intercept (beta0) ở thang đo gốc từ cbeta0

sample%>%lm(Y~X,.)%>%summary()

3

Ta tạo list data gồm model matrix, vector Y, nX và n, sau đó đưa vào mô hình STAN và thi hành:

sample%>%lm(Y~X,.)%>%summary()

4

sample%>%lm(Y~X,.)%>%summary()

5

Kết quả mô hình sẽ cung cấp cho chúng ta 4 chuỗi MCMC, chứa phân phối hậu định của cbeta0, beta0, beta[1], vaé sigma.

sample%>%lm(Y~X,.)%>%summary()

0

sample%>%lm(Y~X,.)%>%summary()

7

Kiểm tra phẩm chất chuỗi MCMC

Trong bài này, Nhi sẽ giới thiệu với các bạn một bước phụ trong quy trình Bayes, đó là kiểm tra phẩm chất của các chuỗi MCMC. Bản chất của chuỗi MCMC là một quy trình rút ngẫu nhiên một mẫu khá lớn (vài ngàn giá trị) từ phân phối hậu định của tham số, để mô phỏng phân phối này.

Phẩm chất của chuỗi MCMC có thể được cảm nhận trực quan khi biễu diễn nó như 1 chuỗi giá trị theo thời gian (time series data). Chuỗi MCMC tốt có hình ảnh liên tục, đồng nhất, nếu có nhiều chuỗi thì chúng đồng dạng và chổng lắp được với nhau.

sample%>%lm(Y~X,.)%>%summary()

8

Kiểm định Raftery(package coda) là một cách để kiểm tra về tính phù hợp của kích thước chuỗi MCMC với độ tin cậy. Nó sẽ ước tính số lượt lấy mẫu tối thiểu cần thực hiện để đạt độ chính xác nhất định (thí dụ 0.5%). Nếu trên thực tế số lượt lấy mẫu của chúng ta cao hơn giá trị này thì ta có thể yên tâm.

sample%>%lm(Y~X,.)%>%summary()

9

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

0

Phân tích Autocorrelation của chuỗi MCMC: Mục tiêu là xác định giá trị lag của MCMC (như 1 time serie), giá trị lag càng gần 0 càng tốt (tiêu chuẩn là lag < 2), vì theo nguyên tắc các đoạn mẫu nối tiếp trong chuỗi phải độc lập với nhau (không tương quan lẫn nhau).

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

1

Một tiêu chí khác là giá trị R-hat, nó cho phép đo lường tính hiệu quả của quy trình lấy mẫu. Một cách đơn giản, giá trị R-hat càng gần 1 càng tốt (ngưỡng là < 1.05).

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

2

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

3

Cuối cùng, trị số ESS (effective sample size, tỉ lệ cỡ mẫu khả dụng), cho biết tỉ lệ mẫu được mô phỏng một cách hiệu quả so với tổng số lần lấy mẫu, giá trị ess càng gần 1.0 (100%) càng tốt.

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

4

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

3

Diễn giải phân phối hậu định

Bây giờ chúng ta thử kiểm tra lại 100 phiên bản mô hình tuyến tính được định dạng từ phân phối hậu định cho beta0, beta1 và so sánh với model dựng bằng mô hình theo phái REML:

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

6

Thật ngoạn mục, đó là mô hình tuyến tính theo Bayes cũng cho ra hệ số r tương đương với phương pháp tần số

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

7

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

8

Nếu tham vọng, ta có thể tạo ra phân phối hậu định cho r nữa (Thực ra ta đã có thể làm điều này trong block generated quantities của STAN code, nhưng ta không làm như vậy, vì tính toán trên vector MCMC luôn nhanh chóng hơn là cưỡng ép sampler lấy mẫu MCMC cho nhiều trị số). Những trị số có thể suy ra từ tham số trong mô hình nên được tính bên ngoài STAN, sau khi đã có MCMC của những tham số thiết yếu.

Đây là phân phối hậu định của r và Rsquared

##   
## Call:  
## lm(formula = Y ~ X, data = .)  
##   
## Residuals:  
##        Min         1Q     Median         3Q        Max   
## -1.006e-05 -3.111e-06 -4.097e-07  3.330e-06  1.080e-05   
##   
## Coefficients:  
##              Estimate Std. Error   t value Pr(>|t|)      
## (Intercept) 4.500e+01  1.343e-06 3.351e+07   <2e-16 ***  
## X           9.932e-07  4.583e-08 2.167e+01   <2e-16 ***  
## ---  
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1  
##   
## Residual standard error: 4.676e-06 on 48 degrees of freedom  
## Multiple R-squared:  0.9073, Adjusted R-squared:  0.9054   
## F-statistic: 469.7 on 1 and 48 DF,  p-value: < 2.2e-16

9

Sử dụng ROPE và CompVal (bạn xem 2 bài trước để hiểu thêm về 2 phương pháp này), ta có thể kiểm định một số giả thuyết về r:

cor.test(sample$X,sample$Y)

0

cor.test(sample$X,sample$Y)

1

Thí dụ, Nhi muốn kiểm tra 3 câu hỏi: r có cao hơn 0.9 hay không (dùng Compval ) ? Khả năng bao nhiêu % là r cao hơn 0.95 ? bao nhiêu % là r nằm trong khoảng 0.92 tới 0.95 ? (dùng ROPE).

Kết quả cho thấy Trung vị của r=0.9593; ngưỡng LL=0.932, UL=0.963; 99.8% phân phối của r lớn hơn 0.9; 2% r nhỏ hơn 0.92, 14.8% r nằm trong khoảng 0.92-0.95; 84.98% r cao hơn 0.95.

Như vậy ta có thể xác tín rằng tương quan giữa TCO và FCO là rất mạnh, gần như chắc chắn là r cao hơn 0.92

Một công cụ khác cũng rất lợi hại để kiểm tra phân phối hậu định r, đó là tỉ trọng chứng cứ hay Bayes factor. Trong thí dụ sau, Nhi khảo sát Bayes factor cho 11 giả thuyết H1/H0 với ngưỡng so sánh tăng dần từ 0.9 đến 1

cor.test(sample$X,sample$Y)

2

Kết quả cho thấy mức độ xác tín là rất cao trong khoảng 0.9 đến 0.93, và giảm dần cho đến 0.96, và gần như =0 từ 0.97 trở đi, như vậy với dữ liệu hiện thời, ta chỉ có thể xác quyết về giá trị r trong khoảng 0.90 đến 0.93.

Tổng kết

Bài thực hành của chúng ta đến đây là kết thúc. Các bạn đã có thể thay thế phăn tích tương quan cổ điển bằng phương pháp Bayes. Tất cả là nhờ mô hình tuyến tính mà tổ sư Karl Pearson truyền lại, chúng ta chỉ dựng mô hình theo một cách khác.

Một số thông điệp quan trọng có thể rút ra trong bài này, đó là:

  1. Có sự quan hệ giữa hệ số tương quan r và mô hình tuyến tính
  2. Mô hình tuyến tính là giải pháp tốt hơn so với r và t test, vì mô hình sẽ cho nhiều thông tin hơn, bao gồm cả r
  3. Chỉ dùng sampler cho những tham số thực sự thiết yếu, và tính những trị số khác sau đó từ MCMC
  4. Phương pháp frequentist và p_value có nhiều nhược điểm và bẫy nguy hiểm, ta nên thay thế cách làm cũ bằng phương pháp Bayes.

Đây chỉ mới là một khúc dạo đầu cho một chặng đường mới thú vị hơn mà ta sẽ khám phá, đó là mô hình tuyến tính tổng quát (GLM) theo BAYES. Hẹn gặp lại các bạn.

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

LS0tDQp0aXRsZTogIkJBWUVTIGNobyBwaMOibiB0w61jaCB0xrDGoW5nIHF1YW4iDQpzdWJ0aXRsZTogIlPhu60gZOG7pW5nIG5nw7RuIG5n4buvIFNUQU4iDQphdXRob3I6ICJMw6ogTmfhu41jIEto4bqjIE5oaSINCmRhdGU6ICIyNyBUaMOhbmcgOSAyMDE3Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogImRlZmF1bHQiDQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyc3RhbikNCmxpYnJhcnkoYnJtcykNCg0KYGBgDQoNCiFbXShQZWFyc29uUkJheWVzLnBuZykNCg0KIyDDlG4gbOG6oWkgaMOgbmggdHLDrG5oIMSRw6MgxJFpIHF1YSANCg0KVGjDom4gY2jDoG8gY8OhYyBi4bqhbiwgxJHDonkgbMOgIGLDoGkgdGjhu7FjIGjDoG5oIHRo4bupIDQgdHJvbmcgZOG7sSDDoW4gQmF5ZXMgZm9yIFZpZXRuYW0sIMSRxrDhu6NjIHJlYm9vdCBs4bqhaSB04burIHByb2plY3QgY8O5bmcgdMOqbiBuxINtIDIwMTYuIE3hu6VjIHRpw6p1IGPhu6dhIGThu7Egw6FuIG7DoHkgbMOgIHBo4buVIGJp4bq/biBwaMawxqFuZyBwaMOhcCB0aOG7kW5nIGvDqiB0aGVvIHRyxrDhu51uZyBwaMOhaSBCYXllcyBjaG8gY8OhYyBi4bqhbiBiw6FjIHPEqSB2w6Agc2luaCB2acOqbiB5IGtob2EsIG5o4bqxbSB0aGF5IHRo4bq/IGNobyBuaOG7r25nIGPDtG5nIGPhu6UgdGjhu5FuZyBrw6ogdHJ1eeG7gW4gdGjhu5FuZy4NCg0KQ2jDum5nIHRhIMSRw6MgxJFpIHF1YSAzIGNo4bq3bmcgxJHGsOG7nW5nLCBkw7luZyBCYXllcyB0aGF5IHRo4bq/IGNobyBTdHVkZW50IHQtdGVzdCwgQ2hpc3F1YXJlZCB0ZXN0IHbDoCBwaMOibiBsb+G6oWkgYuG6sW5nIGjhu5NpIHF1eSBMb2dpc3RpYy4gQ8OhYyBi4bqhbiDEkcOjIGLhuq90IMSR4bqndSBxdWVuIHbhu5tpIGPhuqV1IHRyw7pjIG5nw7RuIG5n4buvIFNUQU4sIHF1eSB0csOsbmggY2h1eeG7g24gZ2nhuqMgdGh1eeG6v3QgbmdoacOqbiBj4bupdSB0aMOgbmggbcO0IGjDrG5oIEJheWVzLCBraGFpIHRow6FjIHBow6JuIHBo4buRIGjhuq11IMSR4buLbmguIFF1YSAyIGLDoGkgZ+G6p24gxJHDonkgbmjhuqV0LCB0YSB0aOG6pXkgcuG6sW5nOg0KMSkJUGjDom4gdMOtY2ggdGhlbyB0csaw4budbmcgcGjDoWkgQmF5ZXMgY8OzIGPhuqV1IHRyw7pjIG5oxrAgbmhhdSB0cm9uZyBt4buNaSBiw6BpIHRvw6FuOg0KDQokJHAoXHRoZXRhIHxvdXRjb21lLCBkYXRhKVxwcm9wdG8gcChvdXRjb21lfFx0aGV0YSkgcChcdGhldGEgLGRhdGEpJCQNCg0KdGhlbyDEkcOzLCBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBj4bunYSBt4buZdCB0aGFtIHPhu5EgVGhldGEgKHjDoWMgc3XhuqV0IMSRaeG7gXUga2nhu4duIGPhu6dhIHRoZXRhIGtoaSBjw7MgdGjDtG5nIHRpbiB24buBIGJp4bq/biBr4bq/dCBxdeG6oyBvdXRjb21lIHbDoCBtYXRyaXgvdmVjdG9yIGThu68gbGnhu4d1KSB04buJIGzhu4cgduG7m2kgdMOtY2ggY+G7p2EgaMOgbSBsaWtlbGlob29kICh4w6FjIHN14bqldCBjw7MgxJFp4buBdSBraeG7h24gY2hvIHBow6lwIMaw4bubYyB0w61uaCBr4bq/dCBxdeG6oyBraGkgY8OzIHRoZXRhIHbDoCBk4buvIGxp4buHdSkgduG7m2kgcGjDom4gcGjhu5FpIHRp4buBbiDEkeG7i25oIChwcmlvcj0gbeG7mXQgZ2nhuqMgdGh1eeG6v3QgduG7gSBwaMOibiBwaOG7kWkgY+G7p2EgdGhldGEgdHLGsOG7m2Mga2hpIHRhIG5ow6xuIHRo4bqleSBk4buvIGxp4buHdSB2w6Aga+G6v3QgcXXhuqMpLg0KDQoyKQlW4bqlbiDEkeG7gSBsw6AgdGEgcGjhuqNpIGNodXnhu4NuIGPDonUgaOG7j2kgbmdoacOqbiBj4bupdSB2w6AgZOG7ryBsaeG7h3UgdGjDoG5oIG3DtCBow6xuaCBCYXllcywgdHJvbmcgxJHDsyB0aGV0YSAoaG/hurdjIG91dGNvbWUpIGzDoCBt4bulYyB0acOqdSBj4bqnbiB0w6xtIHBow6JuIHBo4buRaSBo4bqtdSDEkeG7i25oLCB0YSBwaOG6o2kgbcO0IHThuqMgxJHGsOG7o2MgcXV5IGx14bqtdCBj4bunYSBow6BtIGxpa2VsaWhvb2QsIHbDoCBjdeG7kWkgY8O5bmcsIHBo4bqjaSBjw6JuIG5o4bqvYyB0cm9uZyB2aeG7h2MgY2jhu41uIHByaW9yLiBLaGkgxJHDoyBwaMOhYyB0aOG6o28gxJHGsOG7o2MgbcO0IGjDrG5oIHRyw6puIGdp4bqleSB0aMOsIHZp4buHYyB2aeG6v3QgY29kZSBjaOG7iSBjw7JuIGzDoCB24bqlbiDEkeG7gSBr4bu5IHRodeG6rXQuDQoNCjMpCVRoZW8gbmd1ecOqbiB04bqvYyBuw6B5LCB0YSBjw7MgdGjhu4MgdGhheSB0aOG6vyB04bqldCBj4bqjIG5o4buvbmcgY8O0bmcgY+G7pSB0aOG7kW5nIGvDqiB0cnV54buBbiB0aOG7kW5nIGTDuW5nIG51bGwgaHlwb3RoZXNpcyB0ZXN0aW5nIHbDoCBwX3ZhbHVlIGLhurFuZyBwaMOibiB0w61jaCBCYXllcy4gDQoNCjQpCVPhu7EgdGhheSB0aOG6vyBjw7MgdGjhu4MgdGjhu7FjIGhp4buHbiDhu58gMiBj4bqlcCDEkeG7mSAodGhlbyAyIGPDoWNoKTogaG/hurdjIGNo4buNbiB0cuG7iyBz4buRIHRo4buRbmcga8OqICh0aMOtIGThu6UgdCBjaG8gU3R1ZGVudCB0IHRlc3QsIENoaXNxdWFyZSBjaG8gUGVhcnNvbuKAmXMgQ2hpMiB0ZXN0LCB2w6AgY8OhYyBlZmZlY3Qgc2l6ZXMpIGzDoG0gbeG7pWMgdGnDqnUgxJHhu4MgdMOsbSBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCwgdOG7qWMgbMOgIHbhuqtuIGLDoW0gc8OhdCB2w6BvIHRydXnhu4FuIHRo4buRbmc7IGhv4bq3YyBjaOG7iSBnaeG7ryBs4bqhaSB0aW5oIHRo4bqnbiBj4bunYSBnaeG6o2kgcGjDoXAgbcOgIGtow7RuZyBjaOG6pXAgY2jGsOG7m2MgdsOgbyBjw6FjIHRy4buLIHPhu5EgcXV5IMaw4bubYywgdGjDrSBk4bulIHRoYXkgdsOsIHTDrW5oIHQgLyBDb2hlbuKAmXMgZCB0aMOsIHRhIGTDuW5nIG3DtCBow6xuaCBHTE0gduG7m2kgbGlrZWxpaG9vZCBTdHVkZW50LXQgxJHhu4Mga2jhuqNvIHPDoXQgdHLhu7FjIHRp4bq/cCBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBj4bunYSB0cnVuZyBiw6xuaCBraMOhYyBiaeG7h3Q7IHRoYXkgdsOsIHTDrW5oIENoaTIgdsOgIENyYW1lcuKAmXMgViB0aMOsIHRhIHNvIHPDoW5oIHRy4buxYyB0aeG6v3AgMiB04buJIGzhu4cgYuG6sW5nIG3DtCBow6xuaCBCaW5vbWlhbCBCYXllcyBob+G6t2MgdMOtbmggb2Rkcy1yYXRpbyBi4bqxbmcgMSBtb2RlbCBsb2dpc3RpYyBCYXllcywgdOG7qWMgbMOgIHRhIGLhu48gaOG6s24gY8O0bmcgY+G7pSDEkWkgdsOgIGNo4buJIGTDuW5nIG3DtCBow6xuaC4gDQoNCiMgUGjDom4gdMOtY2ggdMawxqFuZyBxdWFuIHRoZW8gUGVhcnNvbg0KDQpCw6BpIHRvw6FuIHBow6JuIHTDrWNoIHTGsMahbmcgcXVhbiBy4bqldCB0aMaw4budbmcgZ+G6t3AgdHJvbmcgbmdoacOqbiBj4bupdSB5IGjhu41jLiBQaMOibiB0w61jaCB0xrDGoW5nIHF1YW4gbMOgIG3hu5l0IGdp4bqjaSBwaMOhcCB0aOG7kW5nIGvDqiBy4bqldCBxdWFuIHRy4buNbmcgdHJvbmcgbmdoacOqbiBj4bupdSBraG9hIGjhu41jLCBuaOG7nSBuw7MgbcOgIG5nxrDhu51pIHRhIGtow6FtIHBow6EgcmEgbmjhu69uZyBxdXkgbHXhuq10IHNpbmggbMO9IGLhu4duaCBt4bubaSwgdOG6oW8gcmEgdGh14buRYyBjaOG7r2EgYuG7h25oLCBsacOqbiBr4bq/dCDEkcaw4bujYyB0aMO0bmcgdGluIG3hu5tpIHbDoCBjxaksIHRoYXkgdGjhur8gcGjGsMahbmcgcGjDoXAgxJFvIGzGsOG7nW5nLCBiaW9tYXJrZXIgY8WpIGLhurFuZyBwaMawxqFuZyBwaMOhcCBt4bubaSDGsHUgdmnhu4d0IGjGoW4uIA0KDQpW4bqlbiDEkeG7gSBsw6AgdGEgY8OzIDIgdmVjdG9yIFggdsOgIFkgbMOgIGJp4bq/biBsacOqbiB04bulYywgdsOgIHRhIG114buRbiBiaeG6v3QgZ2nhu69hIGNow7puZyBjw7Mgc+G7sSB0xrDGoW5nIHF1YW4gaGF5IGtow7RuZy4gVMO5eSB0aGVvIHTDrG5oIGh14buRbmcgbcOgIGPDonUgaOG7j2kgbsOgeSBjw7MgdGjhu4MgxJHGsOG7o2MgZGnhu4VuIMSR4bqhdCBraMOhYyBuaGF1LCB0aMOtIGThu6U6DQoNCjEpIE7hur91IHRhIGNoxrBhIGPDsyBnaeG6oyB0aHV54bq/dCBuw6BvIHbhu4EgcXVhbiBo4buHIG5ow6JuIHF14bqjLCDEkcOieSBz4bq9IGzDoCAxIHBow6JuIHTDrWNoIG1hbmcgw70gbmdoxKlhIGNodW5nIGNodW5nICh2w7QgaMaw4bubbmcpOiB0YSBjw7MgdGjhu4MgcGjDoXQgYmnhu4N1IGdp4bqjIHRodXnhur90OiBjaOG7qW5nIG1pbmggWCB0xrDGoW5nIHF1YW4gduG7m2kgWSwgaGF5IFkgdMawxqFuZyBxdWFuIHbhu5tpIFgsIGhheSBjaHVuZyBjaHVuZzogY8OzIHPhu7EgdMawxqFuZyBxdWFuIGdp4buvYSBYIHbDoCBZLCBoYXk6IFggdsOgIFkgYmnhur9uIHRoacOqbiBjw7luZyAobmfGsOG7o2MgY2hp4buBdSksIFggdsOgIFkgdOG7iSBs4buHIHRodeG6rW4gKG5naOG7i2NoKeKApg0KDQoyKSBO4bq/dSB0YSBjw7MgZ2nhuqMgdGh1eeG6v3QgduG7gSBxdWFuIGjhu4cgbmjDom4gcXXhuqMsIG3hu5l0IHRyb25nIGhhaSBiaeG6v24gc+G6vSBsw6Aga+G6v3QgcXXhuqMgKFkpIHbDoCBiaeG6v24gY8OybiBs4bqhaSAoWCkgbMOgIG5ndXnDqm4gbmjDom4uIEdp4bqjIHRodXnhur90IGPDsyB0aOG7gyBsw6A6IFkgcGjhu6UgdGh14buZYyB2w6BvIFgsIGhheTogWCBnw6J5IGhp4buHdSDhu6luZyBsw6puIHRoYXkgxJHhu5VpIGPhu6dhIFksIGhheTogU+G7sSB0aGF5IMSR4buVaSBj4bunYSBYIGfDonkgcmEgc+G7sSB0aGF5IMSR4buVaSBj4bunYSBZDQoNCjMpIE7hur91IFggdsOgIFkgY8OzIGPDuW5nIGLhuqNuIGNo4bqldCBuaMawbmcga2jDoWMgbmhhdSB24buBIHBoxrDGoW5nIHBow6FwL8SRaeG7gXUga2nhu4duIMSRbyBsxrDhu51uZywgaG/hurdjIG7hur91IFggdsOgIFkgxJHhu4F1IMSR4bqhaSBkaeG7h24gY2hvIG3hu5l0IGhp4buHbiB0xrDhu6NuZyBuw6BvIMSRw7MsIGdp4bqjIHRodXnhur90IOG7nyDEkcOieSBsw6A6IFggdsOgIFkgdMawxqFuZyDEkcawxqFuZyB24bubaSBuaGF1LCBYIGPDsyB0aOG7gyB0aGF5IHRo4bq/IGNobyBZLCBoYXkgWSBjw7MgdGjhu4MgxJHGsOG7o2MgZ2nhuqNpIHRow61jaCBi4bufaSBYLg0KDQpOaMawbmcgdHJvbmcgdGjhu5FuZyBrw6osIHBow6JuIHTDrWNoIHTGsMahbmcgcXVhbiBjaOG7iSBsw6Agdmnhu4djIMSRbyBsxrDhu51uZyB2YXJpYW5jZSBj4bunYSAyIGJp4bq/biBz4buRIHbDoCBraOG6o28gc8OhdCBxdWFuIGjhu4cgZ2nhu69hIGNow7puZywgYmFvIG5oacOqdSBwaOG6p24gdmFyaWFuY2UgY+G7p2EgWSBjaHVuZyB24bubaSBYIChjw7MgdGjhu4MgxJHGsOG7o2MgZ2nhuqNpIHRow61jaCBi4bufaSBYKS4gDQoNCkjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gUGVhcnNvbiAoa8OtIGhp4buHdSA6IHIsIHRodeG6rXQgbmfhu68gxJHhuqd5IMSR4bunIDogUGVhcnNvbuKAmXMgcHJvZHVjdCBtb21lbnQgY29ycmVsYXRpb24gY29lZmZpY2llbnQpIGzDoCBt4buZdCB0cuG7iyBz4buRIHRo4buRbmcga8OqIGTDuW5nIMSR4buDIMSRbyBsxrDhu51uZyDEkeG7mSBt4bqhbmggdsOgIGNoaeG7gXUgaMaw4bubbmcgY+G7p2EgdMawxqFuZyBxdWFuIGdp4buvYSAyIGJp4bq/biBsacOqbiB04bulYyBYIHbDoCBZLiBN4buZdCBjw6FjaCB04buVbmcgcXXDoXQsIHIgxJHGsOG7o2MgeMOhYyDEkeG7i25oIGLhurFuZyB04buJIHPhu5EgZ2nhu69hIENvdmFyaWFuY2UgMiBiaeG6v24gWCxZIGNoaWEgY2hvIHTDrWNoIHPhu5EgY+G7p2EgxJHhu5kgbOG7h2NoIGNodeG6qW4gY+G7p2EgY2jDum5nOg0KDQokJHJfe1gsWX09XGZyYWN7Q292KFhZKX17c2QoWCkqc2QoWSl9JCQNCg0KSOG7hyBz4buRIHIgZGFvIMSR4buZbmcgdHJvbmcga2hv4bqjbmcgLTEgxJHhur9uICsxLiBHacOhIHRy4buLIHI9MCBjaG8gdGjhuqV5IGtow7RuZyBjw7MgdMawxqFuZyBxdWFuIGdp4buvYSAyIGJp4bq/bi4gR2nDoSB0cuG7iyByPjAgYmnhu4N1IHRo4buLIGNobyBt4buRaSB0xrDGoW5nIHF1YW4gdGh14bqtbiAoWCB2w6AgWSBiaeG6v24gdGhpw6puIGPDuW5nIGNoaeG7gXUpLCBHacOhIHRy4buLIHI8MCBiaeG7g3UgdGjhu4sgY2hvIHTGsMahbmcgcXVhbiBuZ2jhu4tjaCAoWCB0xINuZyB0aMOsIFkgZ2nhuqNtIHbDoCBuZ8aw4bujYyBs4bqhaSkuIEPDoG5nIGfhuqduIGPhu7FjIHRy4buLICsvLTEgdGjDrCB0xrDGoW5nIHF1YW4gY8OgbmcgbeG6oW5oLiBHacOhIHRy4buLIHIgY8OgbmcgZ+G6p24gMSBjaG8gdGjhuqV5IDIgYmnhur9uIHThu4kgbOG7hyB24bubaSBuaGF1IG3hu5l0IGPDoWNoIGhvw6BuIGjhuqNvLiANCg0KVHJvbmcgdHLGsOG7nW5nIHBow6FpIHThuqduIHPhu5EgKGZyZXF1ZW50aXN0KSwgbeG7pWMgdGnDqnUgY8OybiBsw6Aga2nhu4NtIMSR4buLbmggw70gbmdoxKlhIHRo4buRbmcga8OqIGPhu6dhIHIuIE3hu5l0IGtp4buDbSDEkeG7i25oIHQgc+G6vSDEkcaw4bujYyDDoXAgZOG7pW5nIMSR4buDIHBo4bqjbiBuZ2hp4buHbSBnaeG6oyB0aHV54bq/dCBIMCBsw6Agcj0wLCB0YSB0w61uaCB0cuG7iyBz4buRIHQgdOG7qyByIHbDoCBj4buhIG3huqt1LCB0IGPDsyBwaMOibiBwaOG7kWkgU3R1ZGVudCB0LCDEkeG7mSB04buxIGRvID0gKG4tMik6DQoNCiQkdCA9IHJcc3FydHtcZnJhY3tOLTJ9ezEtcl4yfX0kJA0KDQpN4buZdCBoxrDhu5tuZyDEkWkga2jDoWMsIHThu5F0IGjGoW4sIMSRw7MgbMOgIGThu7FuZyBt4buZdCBtw7QgaMOsbmggaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggduG7m2kgWSBsw6AgYmnhur9uIGvhur90IHF14bqjLCBYIGzDoCBoaeG7h3AgYmnhur9uIHPhu5EuIEPDoWNoIGzDoG0gbsOgeSBjaG8gcmEga+G6v3QgcXXhuqMgcGhvbmcgcGjDuiBoxqFuIG5oaeG7gXUgc28gduG7m2kgcGjDom4gdMOtY2ggciDEkcahbiBnaeG6o24sIHbDrCBuZ2/DoGkgxJHhu5kgbeG6oW5oLCBjaGnhu4F1IGjGsOG7m25nIHbDoCDDvSBuZ2jEqWEgY+G7p2EgdMawxqFuZyBxdWFuLCBtw7QgaMOsbmggdHV54bq/biB0w61uaCBjw7JuIGNobyBwaMOpcCBkaeG7hW4gZ2nhuqNpIG3hu5FpIHTGsMahbmcgcXVhbiB0aGVvIHRoYW5nIMSRbyB04buJIGzhu4cgZ2nhu69hIFkgdsOgIFgsIHRow60gZOG7pSB0YSBjw7MgdGjhu4MgZGnhu4VuIGdp4bqjaSA6IFggdMSDbmcgMSDEkcahbiB24buLIHRow6wgWSB0xINuZyBiZXRhMSDEkcahbiB24buLLiBI4buHIHPhu5EgaOG7k2kgcXV5IGJldGEgZG8gxJHDsyBjxaluZyBjw7Mgw70gbmdoxKlhIHTGsMahbmcgxJHGsMahbmcgduG7m2kgci4gQmV0YSB2w6AgciBjw7luZyBk4bqldSB2w6wgY2jDum5nIHThu4kgbOG7hyB0aHXhuq1uIHbhu5tpIG5oYXUuIE7hur91IGJldGE9MCB0aMOsIHIgY8Wpbmcgc+G6vSA9MCwgZG8gxJHDsyBraeG7g20gxJHhu4tuaCB0IGNobyBo4buHIHPhu5EgaOG7k2kgcXV5IGJldGEgZ2nhu69hIFkgdsOgIFggY8WpbmcgY2jDrW5oIGzDoCBjaG8gw70gbmdoxKlhIHRo4buRbmcga8OqIGPhu6dhIG3hu5FpIHTGsMahbmcgcXVhbiwgY2jDum5nIHPhur0gY2hvIHJhIGPDuW5nIHRy4buLIHPhu5EgdCwgY8O5bmcgcF92YWx1ZS4gTeG7mXQgbcO0IGjDrG5oIHR1eeG6v24gdMOtbmggY8OybiBjaG8gcGjDqXAgxJHGsGEgdGjDqm0gYmnhur9uIHPhu5EgWDIsIFgz4oCmIMSR4buDIHjDqXQgbeG7kWkgdMawxqFuZyBxdWFuIHJpw6puZyBwaOG6p24uDQoNCk3hu5l0IG5ndXnDqm4gbmjDom4ga2jDoWMga2hp4bq/biBtw7QgaMOsbmggaOG7k2kgcXV5IHThu5F0IGjGoW4gUGVhcnNvbidzIHIsIMSRw7MgbMOgIHIgbmjhuqF5IGjGoW4gduG7m2kgdmnhu4djIHRoYW5nIMSRbyBj4bunYSBYIGLhu4sgY2jhurduIChnacOhIHRy4buLIGPhu6dhIFggdHJvbmcgbeG6q3Uga2jDtG5nIGJhbyBxdcOhdCBo4bq/dCB0b8OgbiBi4buZIHRoYW5nIMSRbyBj4bunYSBuw7MgdHLDqm4gdGjhu7FjIHThur8pLCBtw7QgaMOsbmggaOG7k2kgcXV5IMOtdCBi4buLIOG6o25oIGjGsOG7n25nIGLhu59pIMSRaeG7gXUgbsOgeS4gDQoNCkN14buRaSBjw7luZywgbcO0IGjDrG5oIGjhu5NpIHF1eSBjaG8gcGjDqXAgZGnhu4VuIGdp4bqjaSBr4bq/dCBxdeG6oyB24bubaSDDvSBuZ2jEqWEgbmjDom4gcXXhuqMsIGPDsyDEkeG7i25oIGjGsOG7m25nLg0KDQojIE5oxrDhu6NjIMSRaeG7g20gY+G7p2EgdHLGsOG7nW5nIHBow6FpIGZyZXF1ZW50aXN0DQoNClRyxrDhu51uZyBwaMOhaSBmcmVxdWVudGlzdCB2w6AgbnVsbCBoeXBvdGhlc2lzIHRlc3RpbmcgKHbhu5tpIHAgdmFsdWUpIGPDsyB2w6BpIG5oxrDhu6NjIMSRaeG7g20sIHRyb25nIHPhu5EgxJHDsyBuZ3V5IGhp4buDbSBuaOG6pXQgbMOgIDIgduG6pW4gxJHhu4EgbmjGsCBzYXUgOg0KDQpUaOG7qSBuaOG6pXQgOiDDnSBuZ2jEqWEgdGjhu5FuZyBrw6ogaG/DoG4gdG/DoG4ga2jDoWMgduG7m2kgw70gbmdoxKlhIGzDom0gc8OgbmcgOiBD4bqjIHIgdsOgIHAgdmFsdWUgxJHhu4F1IGtow7RuZyBjaG8gcGjDqXAga+G6v3QgbHXhuq1uIHbhu4Egw70gbmdoxKlhIGzDom0gc8OgbmcgOg0KDQpW4bqlbiDEkeG7gSBuw6B5IGPDsyB0aOG7gyDEkcaw4bujYyBtaW5oIGNo4bupbmcgcXVhIHRow60gZOG7pSBtw7QgcGjhu49uZyBzYXUgxJHDonkgOiBRdWFuIGjhu4cgZ2nhu69hIFkgdsOgIFggbMOgIHbDtCBjw7luZyBuaOG7jyBiw6kgKGtob+G6o25nIDEgcGjhuqduIHRyaeG7h3UpLCB0dXkgbmhpw6puIG3DtCBow6xuaCB24bqrbiBjaG8gcmEgbeG7mXQgZ2nDoSB0cuG7iyBwIHLhuqV0IMSR4bq5cCB2w6AgMSBo4buHIHPhu5EgdMawxqFuZyBxdWFuIG3huqFuaC4gUGhpIGzDvSBxdcOhIHBo4bqjaSBraMO0bmcgY8OhYyBi4bqhbiA/DQoNCmBgYHtyfQ0KDQpzZXQuc2VlZCgxMjMpDQpzYW1wbGU9ZGF0YS5mcmFtZShYPWMoMTo1MCkpJT4lbXV0YXRlKC4sWT0wLjAwMDAwMSpYKzQ1K3Jub3JtKDUwLDAsMC4wMDAwMDUpKQ0KDQpzYW1wbGUlPiVnZ3Bsb3QoYWVzKHg9WCx5PVkpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsY29sb3I9InJlZCIpKw0KICBnZW9tX3BvaW50KHNoYXBlPTIxLHNpemU9Mixjb2xvcj0iYmxhY2siLGZpbGw9InJlZCIpKw0KICB0aGVtZV9idygpK3lsaW0oNDQsNDYpDQoNCnNhbXBsZSU+JWxtKFl+WCwuKSU+JXN1bW1hcnkoKQ0KDQpjb3IudGVzdChzYW1wbGUkWCxzYW1wbGUkWSkNCg0KYGBgDQoNClRo4bupIGhhaSA6IMSQ4buZIGzhu5tuIGPhu6dhIHIgdsOgIMO9IG5naMSpYSB0aOG7kW5nIGvDqiAocCB2YWx1ZSkgcGjhu6UgdGh14buZYyB2w6BvIGPhu6EgbeG6q3UsIHbDoCBjaMO6bmcgY8OzIHRo4buDIG3DonUgdGh14bqrbiBuaGF1LiBC4bqjbiB0aMOibiBwIHZhbHVlIGtow7RuZyBjaG8gYmnhur90IMSR4buZIG3huqFuaCB0xrDGoW5nIHF1YW4gdsOgIG5nxrDhu6NjIGzhuqFpLiBUYSBjw7MgdGjhu4MgdGjhuqV5IMSRaeG7gXUgbsOgeSBxdWEgdGjDrSBk4bulIHNhdSA6IA0KDQpN4buZdCBt4buRaSB0xrDGoW5nIHF1YW4gbeG6oW5oICjEkcaw4bujYyBtw7QgcGjhu49uZyB0aGVvIGPDtG5nIHRo4bupYykgbmjGsG5nIGPhu6EgbeG6q3UgcXXDoSB0aOG6pXAgKG49NSkgc+G6vSBjaG8gcmEga+G6v3QgcXXhuqMgcF92YWx1ZSBraMO0bmcgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCnNhbXBsZT1kYXRhLmZyYW1lKFg9YygxOjUpKSU+JW11dGF0ZSguLFk9WCpybm9ybSg1LDUsNCkrcm5vcm0oNSw1LDQpKQ0KDQpzYW1wbGUlPiVnZ3Bsb3QoYWVzKHg9WCx5PVkpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsY29sb3I9InJlZCIsZmlsbD0iZ29sZCIpKw0KICBnZW9tX3BvaW50KHNoYXBlPTIxLHNpemU9NSxjb2xvcj0iYmxhY2siLGZpbGw9InJlZCIpKw0KICB0aGVtZV9idygpDQoNCnNhbXBsZSU+JWxtKFl+WCwuKSU+JXN1bW1hcnkoKQ0KDQpjb3IudGVzdChzYW1wbGUkWCxzYW1wbGUkWSkNCmBgYA0KDQpUcm9uZyBraGkgxJHDsywgY2jhu4kgY+G6p24gdMSDbmcgY+G7oSBt4bqrdSBsw6puIGPhu7FjIGzhu5tuLHRow60gZOG7pSA9MTAwMCwgIG3hu41pIG3hu5FpIHTGsMahbmcgcXVhbiBt4bqhbmggaGF5IHnhur91IMSR4buBdSB0cuG7nyBuw6puIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogduG7m2kgUF92YWx1ZSBy4bqldCDEkeG6uXA6DQoNCmBgYHtyfQ0Kc2FtcGxlPWRhdGEuZnJhbWUoWD1ybm9ybSgxMDAwLDEwLDIuNSkpJT4lbXV0YXRlKC4sWT1YKnJub3JtKDEwMDAsNTAsMTAwKStybm9ybSgxMDAwLDEwMCw1MCkpDQoNCnNhbXBsZSU+JWdncGxvdChhZXMoeD1YLHk9WSkpKw0KICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIixjb2xvcj0iYmx1ZSIsZmlsbD0ic2t5Ymx1ZSIpKw0KICBnZW9tX3BvaW50KHNoYXBlPTIxLHNpemU9MSxjb2xvcj0iYmxhY2siLGZpbGw9ImJsdWUiLGFscGhhPTAuNSkrDQogIHRoZW1lX2J3KCkNCg0Kc2FtcGxlJT4lbG0oWX5YLC4pJT4lc3VtbWFyeSgpDQoNCmNvci50ZXN0KHNhbXBsZSRYLHNhbXBsZSRZKQ0KYGBgDQoNClRyb25nIG3hu5l0IHRow60gZOG7pSBraMOhYywgWCB2w6AgWSDEkcaw4bujYyBtw7QgcGjhu49uZyB0aGVvIGPDuW5nIDEgcXV5IGx14bqtdCBwaMOibiBwaOG7kWksIG5oxrBuZyBj4buhIG3huqt1IGPDoG5nIGzhu5tuIHRow6wga+G6v3QgcXXhuqMgY8OgbmcgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiwgcCB2YWx1ZSBjw6BuZyDEkeG6uXANCg0KYGBge3J9DQpzaXplPWMoNCw1LDYsNyw4LDksMTAsMTIsMTMsMTQsMTUsMjAsMjUpDQpyZXM9ZGF0YS5mcmFtZShzaXplPXJlcChOQSwxMyksUGVhcnNvbnI9cmVwKE5BLDEzKSxwX3ZhbHVlPXJlcChOQSwxMykpDQoNCmZvciAoaSBpbiAxOjEzKXsNCiAgc2V0LnNlZWQoMTIzKQ0KICBuPXNpemVbaV0NCiAgc2FtcGxlPWRhdGEuZnJhbWUoWD1ybm9ybShuLDUsMi41KSklPiVtdXRhdGUoLixZPVgqcm5vcm0obiwxMCwyKStybm9ybShuLDEwLDIpKQ0KICB0ZW1wPWNvci50ZXN0KHNhbXBsZSRYLHNhbXBsZSRZKQ0KICByZXMkc2l6ZVtpXT1uDQogIHJlcyRQZWFyc29ucltpXT10ZW1wJGVzdGltYXRlJT4lLltbMV1dDQogIHJlcyRwX3ZhbHVlW2ldPXRlbXAkcC52YWx1ZQ0KfQ0KDQpyZXMlPiVnZ3Bsb3QoYWVzKHg9c2l6ZSx5PXBfdmFsdWUpKSsNCiAgZ2VvbV9wYXRoKGNvbD0iZ29sZCIpKw0KICBnZW9tX3BvaW50KGNvbD0icmVkIikrDQogIHRoZW1lX2J3KCkrc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDUsMTAsMTUsMjAsMjUsMzAsNDAsNTAsNjAsNzAsODAsOTAsMTAwKSkNCg0KYGBgDQoNCsSQ4buDIGto4bqvYyBwaOG7pWMgbmjhu69uZyBuaMaw4bujYyDEkWnhu4NtIG7DoHkgdsOgIMSR4bqhdCB04bubaSBt4buZdCBr4bq/dCBxdeG6oyBow7JhIGjhu6NwIGdp4buvYSDDvSBuZ2jEqWEgdGjhu7FjIHRp4buFbiwgxJHhu5kgdGluIGPhuq15LCBnaeG6oyB0aHV54bq/dCB2w6AgZOG7ryBsaeG7h3UsIHRhIGPhuqduIHTDrG0gbeG7mXQgaMaw4bubbmcgxJFpIGtow6FjLCB2w6AgxJHDsyBsw6AgcGjGsMahbmcgcGjDoXAgQmF5ZXMuDQoNCiMgQsOgaSB0b8OhbiBtaW5oIGjhu41hDQoNClRyb25nIGLDoGkgbsOgeSwgTmhpIHPhur0gZMO5bmcgYuG7mSBz4buRIGxp4buHdSBraOG6o28gc8OhdCB0w61uaCB0xrDGoW5nIGjhu6NwIGdp4buvYSAyIHBoxrDGoW5nIHBow6FwIMSRbyBnacOhbiB0aeG6v3AgY3VuZyBsxrDhu6NuZyB0aW0gKGNhcmRpYWMgb3V0cHV0KSA6IFRDTyDEkW8gYuG6sW5nIFRoZXJtb2RpbHV0aW9uLCBGQ08gxJFvIGLhurFuZyDEkeG7i25oIGx14bqtdCBGaWNrIHRyw6puIDE1IGLhu4duaCBuaMOibi4gU+G7kSBsaeG7h3UgbOG6pXkgdOG7qyBuZ2hpw6puIGPhu6l1IGPhu6dhIEF2aSBBLiBXZWluYnJvdW0gKEpvdXJuYWwgb2YgQ2xpbmljYWwgTW9uaXRvcmluZyBhbmQgQ29tcHV0aW5nICgyMDA4KSAyMjogMzYxLTM2NikuDQoNCk5oxrAgduG6rXkgYsOgaSB0b8OhbiBuw6B5IGPDsyAyIGJp4bq/biBz4buRIFRDTyB2w6AgRkNPLiANCg0KRG8gVENPIHbDoCBGQ08gY8OzIGPDuW5nIMO9IG5naMSpYSBzaW5oIGzDvSwgY8O5bmcgxJHGoW4gduG7iyDEkW8sIMSRw6J5IGzDoCAxIGLDoGkgdG/DoW4gduG7m2kgbeG7pWMgdGnDqnUgaG/DoW4gxJHhu5VpIGJp4bq/biBz4buRL2No4bupbmcgbWluaCBz4buxIHTGsMahbmcgaOG7o3AuIE5oaSBnaeG6oyDEkeG7i25oIFRDTyBsw6AgYmnhur9uIGvhur90IHF14bqjLCBGQ08gbMOgIHByZWRpY3RvcjsgR2nhuqMgdGh1eeG6v3QgbmdoacOqbiBj4bupdSDEkcaw4bujYyBwaMOhdCBiaeG7g3UgbMOgOiANCg0KMSkJQ2h1bmcgY2h1bmc6IGNo4bupbmcgbWluaCBjw7MgdMawxqFuZyBxdWFuIHRodeG6rW4gZ2nhu69hIFRDTyB2w6AgRkNPIA0KDQoyKQlD4bulIHRo4buDOiBjaMO6bmcgbWluaCBUQ08gdMawxqFuZyDEkcawxqFuZyB24bubaSBGQ08sIGhheTogRkNPIGPDsyB0aOG7gyBnaeG6o2kgdGjDrWNoIGfhuqduIG5oxrAgdG/DoG4gYuG7mSB2YXJpYW5jZSBj4bunYSBUQ08uDQoNCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQ0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KZGF0YShDYXJkT3V0cHV0LHBhY2thZ2U9Ik1ldGhDb21wIikNCg0KZGY9Q2FyZE91dHB1dFssYyg2LDcpXSU+JWFzX3RpYmJsZSgpDQoNCmRmJT4laGVhZCgpJT4la25pdHI6OmthYmxlKCkNCmBgYA0KDQpgYGB7cn0NCmxhcHBseShkZixIbWlzYzo6ZGVzY3JpYmUpDQpgYGANCg0KIyBQaMOibiB0w61jaCB0xrDGoW5nIHF1YW4gY+G7lSDEkWnhu4NuDQoNCmBgYHtyfQ0KZGYlPiVnZ3Bsb3QoYWVzKHg9RkNPLHk9VENPKSkrZ2VvbV9wb2ludChjb2w9ImJsYWNrIixmaWxsPSJyZWQiLHNoYXBlPTIxLHNpemU9NSkrdGhlbWVfYncoKQ0KYGBgDQoNCmBgYHtyfQ0KZGYlPiVnZ3Bsb3QoYWVzKHg9RkNPLHk9VENPKSkrZ2VvbV9qaXR0ZXIoc2hhcGU9MjEsc2l6ZT0zLGNvbG9yPSJibGFjayIsZmlsbD0iZ3JleTUwIixhbHBoYT0wLjcpK2dlb21fc21vb3RoKG1ldGhvZD0ibG0iLGNvbG9yPSJyZWQ0IixmaWxsPSJyZWQyIixhbHBoYT0wLjMpK3RoZW1lX2J3KCkNCmBgYA0KDQpgYGB7cn0NCmNvci50ZXN0KGRmJFRDTyxkZiRGQ08pDQpgYGANCg0KIyBHaeG6o2kgcGjDoXAgQmF5ZXMgY2hvIHBow6JuIHTDrWNoIHTGsMahbmcgcXVhbg0KDQrEkOG7gyDEkWkgdMOsbSBo4buHIHPhu5EgciBi4bqxbmcgcGjGsMahbmcgcGjDoXAgQmF5ZXMsIGNow7puZyB0YSBwaOG6o2kgeMOieSBk4buxbmcgbcO0IGjDrG5oLiBNw7QgaMOsbmggbsOgeSBsw6AgZ8OsID8gVGEgxJHDoyBjw7MgY8OidSB0cuG6oyBs4budaSDhu58gdHLDqm46IMSRw7MgbMOgIG3hu5l0IG3DtCBow6xuaCBo4buTaSBxdXkgdHV54bq/biB0w61uaCDEkcahbiBiaeG6v24gWSB+IFguIFbDrCBu4bq/dSB0cnV5IG5ndXnDqm4gdGEgc+G6vSB0aOG6pXkgcuG6sW5nIHThuqV0IGPhuqMga2jDoWkgbmnhu4dtIG5oxrAgaGnhu4dwIHBoxrDGoW5nIHNhaSAoY292YXJpYW5jZSksIHBoxrDGoW5nIHNhaSAodmFyaWFuY2UpLCDEkeG7mSBs4buHY2ggY2h14bqpbiAoc2lnbWEsIGzDoCBjxINuIGLhuq1jIDIgY+G7p2EgdmFyaWFuY2UpLCBzdW0gb2Ygc3F1YXJlICh04buVbmcgYsOsbmggcGjGsMahbmcgc2FpIHPhu5EpLCBo4buHIHPhu5EgdMawxqFuZyBxdWFuIHIg4oCmIMSR4buBdSBjw7MgcXVhbiBo4buHIHbhu5tpIG5oYXUgdsOgIGNow7puZyBjw7luZyBo4buZaSB04bulIHbhu4EgbcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIGRvIEthcmwgUGVhcnNvbiB2w6AgRnJhbmNpcyBHYWx0b24geMOieSBk4buxbmcgdsOgbyBuaOG7r25nIG7Eg20gMTg4MC4NCg0KTmjGsCB24bqteSBi4bqjbiBjaOG6pXQgY+G7p2EgcGjDom4gdMOtY2ggdMawxqFuZyBxdWFuIGzDoCBk4buxbmcgbeG7mXQgbcO0IGjDrG5oIHR1eeG6v24gdMOtbmggKMSRxrDhu51uZyB0aOG6s25nKSwgc2F1IMSRw7MgxJFvIGzGsOG7nW5nIHhlbSBjw6FjIGdpw6EgdHLhu4sgcXVhbiBzw6F0IHRo4buxYyB04bq/IGPDoWNoIMSRxrDhu51uZyB0aOG6s25nIG7DoHkgYsOgbyB4YSwgaGF5IG7Ds2kgY8OhY2gga2jDoWMsIGxp4buHdSBtw7QgaMOsbmggbsOgeSBjw7MgcGjDuSBo4bujcCB24bubaSBk4buvIGxp4buHdSBoYXkga2jDtG5nLiANCg0KQ8OzIGhhaSBjb24gxJHGsOG7nW5nIGNobyBwaMOpcCBr4bq/dCBu4buRaSBnaeG7r2EgaOG7hyBz4buRIHIgdsOgIG3DtCBow6xuaCBo4buTaSBxdXkgdHV54bq/biB0w61uaCwgxJHDsyBsw6A6DQoNClRo4bupIG5o4bqldDogSOG7hyBz4buRIGjhu5NpIHF1eSBiZXRhIGNobyBYaSB0cm9uZyBt4buZdCBtw7QgaMOsbmggaOG7k2kgcXV5IFkgPVggdOG7iSBs4buHIHRodeG6rW4gduG7m2kgciB2w6AgY8OzIHRo4buDIMSRxrDhu6NjIHTDrW5oIHThu6sgciBxdWEgY8O0bmcgdGjhu6ljOg0KDQokJGJfe1hfe2l9fSA9XGZyYWN7Q292KFhfe2l9WSl9e1ZhcihYX3tpfSl9ID0gcl97WCxZfVx0ZnJhY3tzZFl9e3NkWH0kJA0KTmjGsCB24bqteSwgdHJvbmcgbeG7mXQgbcO0IGjDrG5oIG3DoCBj4bqjIFggdsOgIFkgxJHhu4F1IMSRxrDhu6NjIGNodeG6qW4gaMOzYSAoduG7gSDEkcahbiB24buLIGzDoCBzZCksIHRow6wgaOG7hyBz4buRIGjhu5NpIHF1eSBiZXRhIGNow61uaCBsw6Agcg0KDQpUaOG7qSAyOiBDaG8gbeG7mXQgbcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oLCBnacOhIHRy4buLIGPhu6dhIHIgY2jDrW5oIGzDoCBjxINuIGLhuq1jIGhhaSBj4bunYSBo4buHIHPhu5EgUnNxdWFyZWQuIA0KDQokJFBlYXJzb24ncyBcIHIoWCxZKSA9IFxzcXJ0e1JeMn0kJA0KVGEgY8OzIHRo4buDIGtp4buDbSBjaOG7qW5nIG5oxrAgc2F1Og0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCg0KWD1kZiRGQ08NClk9ZGYkVENPDQoNCg0KIyBQZWFyc29uJ3MgciBieSBjb3IgZnVuY3Rpb24NCmNvcl9yPWNvcihYLFkpDQoNCiMgTWFudWFsIGVzdGltYXRpb24gb2YgciBmcm9tIENvdiBhbmQgc2RzDQptYW51YWxfcj1jb3YoWCxZKS8oc2QoWCkqc2QoWSkpDQoNCiMgciBmcm9tIFIyDQptb2Q9bG0oWX5YKQ0KDQpzcXJ0X1IyPW1vZCU+JXN1bW1hcnkoKSU+JS4kci5zcXVhcmVkJT4lc3FydCgpDQoNCiMgTWFudWFsIGVzdGltYXRpb24gb2YgciBmcm9tIGIxIGluIG1vZGVsIHdpdGggc2NhbGVkIFgsWQ0KDQptb2QyPWxtKHNjYWxlKFkpfnNjYWxlKFgpKQ0KDQpiMV9zY2FsZWRYWT1tb2QyJT4lc3VtbWFyeSgpJT4lLiRjb2VmZmljaWVudHMlPiUuWzIsMV0NCg0KDQojIENvbXBpbGUNCnJiaW5kKGNvcl9yLG1hbnVhbF9yLHNxcnRfUjIsYjFfc2NhbGVkWFkpDQpgYGANCg0KTmjGsCB24bqteSBj4bqjIDQgY8OhY2ggbMOgbSDEkeG7gXUgZOG6q24gdOG7m2kgZ2nDoSB0cuG7iyByIG5oxrAgbmhhdS4gDQoNCiMgR2nhuqNpIHBow6FwIEJheWVzIHRo4bupIDE6IE3DtCBow6xuaCBYWSBjaHXhuqluIGjDs2ENCg0KVHJvbmcgY8OhY2ggbMOgbSB0aOG7qSBuaOG6pXQsIHRhIHPhur0geMOhYyDEkeG7i25oIHRy4buxYyB0aeG6v3AgcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2EgciBk4buxYSB2w6BvIHTDrW5oIGNo4bqldDogciBjaMOtbmggbMOgIGjhu4cgc+G7kSBo4buTaSBxdXkgYmV0YSBj4bunYSBtw7QgaMOsbmggdHV54bq/biB0w61uaCBZflggbcOgIGPhuqMgWCB2w6AgWSDEkeG7gXUgxJHDoyBjaHXhuqluIGjDs2EgYuG6sW5nIGjDoG0gc2NhbGUoICkuIA0KDQpOaMawIHbhuq15IG7hu5lpIGR1bmcgbcO0IGjDrG5oIFNUQU4gbmjGsCBzYXU6DQoNCjEpIEJsb2NrIGRhdGEgOiBraGFpIGLDoW8gMyB0aMOgbmggcGjhuqduOiBj4buhIG3huqt1IG4gbMOgIG3hu5l0IHPhu5Egbmd1ecOqbiBjw7MgZ2nDoSB0cuG7iyBuaOG7jyBuaOG6pXQgPSAzOyBYIHbDoCBZIGzDoCAyIHZlY3RvciBjaOG7qWEgZ2nDoSB0cuG7iyDEkcOjIMSRxrDhu6NjIGNodeG6qW4gaMOzYSBj4bunYSBYIHbDoCBZDQoNCjIpIEJsb2NrIHBhcmFtZXRlciA6IGtoYWkgYsOhbyAzIHRoYW0gc+G7kSB0cm9uZyBtw7QgaMOsbmg6IGludGVyY2VwdCBsw6AgbeG7mXQgc+G7kSB0aOG7sWMsIGJldGEgbMOgIGjhu4cgc+G7kSBo4buTaSBxdXkgY+G7p2EgWCB0cm9uZyBtw7QgaMOsbmgsIG7DsyBsw6AgMSBz4buRIHRo4buxYyBuaMawbmcgYuG7iyBjaOG6t24gdHJvbmcga2hv4bqjbmcgLTEgxJHhur9uIDEgKHRhIHPhur0gZMO5bmcgYmV0YSBuaMawIGjhu4cgc+G7kSByKTsgc2lnbWEgbMOgIHNkIGPhu6dhIFkgdHJvbmcgaMOgbSBsaWtlbGlob29kLCBsw6Agc+G7kSB0aOG7sWMgY8OzIGdpw6EgdHLhu4sgdGjhuqVwIG5o4bqldCA9MCkNCg0KMykgQmxvY2sgbW9kZWwgOiBraGFpIGLDoW8gdGhhbSBz4buRIG11IGzDoCBnacOhIHRy4buLIGvhu7MgduG7jW5nIGPhu6dhIFkgdHJvbmcgaMOgbSBsaWtlbGlob29kLCBtdSBsw6AgMSB2ZWN0b3IgY8OzIMSR4buZIGTDoGkgbjsgDQoNClNhdSDEkcOzIHRhIGtoYWkgYsOhbyAzIHByaW9ycyBjaG8gaW50ZXJjZXB0LCBiZXRhIHbDoCBzaWdtYS4gRG8gdGEga2jDtG5nIGPDsyB0aMO0bmcgdGluIGfDrCB24buBIGludGVyY2VwdCwgbsOqbiBOaGkgY2jhu41uIG3hu5l0IHByaW9yIHbDtCB0aMaw4bufbmcgdsO0IHBo4bqhdCBsw6AgcGjDom4gcGjhu5FpIG5vcm1hbCwgdHJ1bmcgYsOsbmggPSAwLCBzZD0xMDAgOyANCg0KY2hvIHRoYW0gc+G7kSBiZXRhIChoYXkgciksIE5oaSBjw7MgMSBnaeG6oyDEkeG7i25oIG5nYXkgdOG7qyDEkeG6p3UgxJHDsyBsw6AgWCB2w6AgWSBjw7MgdMawxqFuZyBxdWFuIHLhuqV0IG3huqFuaCAobmjhuq1uIHjDqXQgdHLhu7FjIHF1YW4gdHLDqm4gxJHhu5MgdGjhu4spLCBuw6puIE5oaSBkw7luZyAxIHByaW9yIGPhu6UgdGjhu4MgxJHDsyBsw6AgYmV0YSBjw7MgcGjDom4gcGjhu5FpIGNodeG6qW4sIHRydW5nIGLDrG5oID0wLjk1IHbDoCBzZCA9MC4yNSAodGEga2jDtG5nIHF1w6puIGzDoCBiZXRhIGLhu4sgY2jhurduIOG7nyBnacOhIHRy4buLID0xIG5oYSBjw6FjIGLhuqFuKSANCg0KOyB2w6Agc2lnbWEgY8OzIHBow6JuIHBo4buRaSBoYWxmIENhdWNoeSwgZG8ga2jDtG5nIGPDsyBnaeG6oyB0aHV54bq/dCBuw6BvIGNobyBuw7MuDQoNCkjDoG0gbGlrZWxpaG9vZCBjw7MgbuG7mWkgZHVuZyA6IFkgxJHGsOG7o2MgbcO0IHThuqMgYuG6sW5nIHBow6JuIHBo4buRaSBub3JtYWwgKG11LHNpZ21hKSB24bubaSBtdSDEkcaw4bujYyDGsOG7m2MgdMOtbmggYuG6sW5nIG3DtCBow6xuaCB0dXnhur9uIHTDrW5oICBtdSA9IGludGVyY2VwdCtiZXRhKlgNCg0KIVtdKFBlYXJzb25SbW9kZWwxLnBuZykNCg0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCmxpYnJhcnkocnN0YW4pDQoNCm1vZGVsU3RyaW5nID0gIg0KICBkYXRhIHsNCiAgaW50PGxvd2VyPTM+IG47DQogIHZlY3RvciBbbl0gWTsNCiAgdmVjdG9yIFtuXSBYOw0KICB9DQoNCiAgcGFyYW1ldGVycyB7DQogIHJlYWwgaW50ZXJjZXB0Ow0KICByZWFsPGxvd2VyPS0xLHVwcGVyPTE+IGJldGE7DQogIHJlYWw8bG93ZXI9MD4gc2lnbWE7DQogIH0NCg0KICBtb2RlbCB7DQogIHZlY3RvciBbbl0gbXU7DQoNCiAgaW50ZXJjZXB0IH4gbm9ybWFsKDAsMTAwKTsNCiAgYmV0YSB+IG5vcm1hbCgwLjk1LDAuMjUpOw0KICBzaWdtYSB+IGNhdWNoeSgwLDUpOw0KIA0KICBtdSA9IGludGVyY2VwdCtiZXRhKlg7DQogIA0KICBZfm5vcm1hbChtdSxzaWdtYSk7DQogIH0NCg0KZ2VuZXJhdGVkIHF1YW50aXRpZXMge30NCiAgIg0KYGBgDQoNCsSQ4buDIHRoaSBow6BuaCBtw7QgaMOsbmggbsOgeSwgdHLGsOG7m2MgdGnDqm4gdGEgY2h14bqpbiBow7NhIFRDTyB2w6AgRkNPLCB2w6AgY2h1eeG7g24ga+G6v3QgcXXhuqMgdGjDoG5oIDIgdmVjdG9yIFkgdsOgIFguU2F1IMSRw7MgdGEgdOG6oW8gZGF0YSBsaXN0IGNobyBtw7QgaMOsbmgNCg0KVGEgc+G6vSB4w6FjIMSR4buLbmggcXV5IHRyw6xuaCBs4bqleSBt4bqrdSBNQ01DIGLhurFuZyBjw6FjIHTDuXkgY2jhu4luaCBuaMawOiBz4buRIGNodeG7l2kgKG5jaGFpbj0zKSwgc+G7kSBsxrDhu6N0IGto4bufaSDEkeG7mW5nICjEkeG7gyDhu5VuIMSR4buLbmggcXV5IHRyw6xuaCwgcGjhuqduIG7DoHkgc+G6vSBraMO0bmcgxJHGsOG7o2MgbMawdSBs4bqhaSwgdGhpbnN0ZXAgxJHhu4MgcsO6dCBuZ+G6r24ga8OtY2ggdGjGsOG7m2MgbeG6q3UsIHPhu5EgbMaw4bujdCBz4bq9IMSRxrDhu6NjIHNhbyBsxrB1IHRyb25nIGPhuqMgMyBjaHXhu5dpIChzYXZlPSAzMDAwIGNobyBt4buXaSBjaHXhu5dpKSwgbmjGsCB24bqteSBpdGVyID0gdOG7lW5nIHPhu5EgbMaw4bujdCBs4bqleSBt4bqrdTsgY29yZXM9NCBjaG8gcGjDqXAgaHV5IMSR4buZbmcgdOG7kWkgxJFhIDQgbMO1aSB2aSB44butIGzDvSBjaG8gcXV5IHRyw6xuaCBs4bqleSBt4bqrdSDEkeG7gyB0xINuZyB04buRYyDEkeG7mSBjb252ZXJnZS4NCg0KYGBge3IsbWVzc2FnZSA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9DQpZPWFzLnZlY3RvcihzY2FsZShkZiRUQ08pKQ0KWD1hcy52ZWN0b3Ioc2NhbGUoZGYkRkNPKSkNCg0KZGF0YWxpc3Q9bGlzdChuPW5yb3coZGYpLFk9WSxYPVgpDQoNCiMgQ29uZmlndXJpbmcgTUNNQw0KDQpuY2hhaW4gPSAzDQpud2FybXVwID0gMTAwMA0KdGhpbnN0ZXAgPSA1DQpzYXZlID0gMyozMDAwIA0KaXRlciA9IGNlaWxpbmcobndhcm11cCArIChzYXZlICogdGhpbnN0ZXApL25jaGFpbikNCg0Kc2V0LnNlZWQoMTIzKQ0KDQpmaXQ9c3RhbihkYXRhID0gZGF0YWxpc3QsIA0KICAgICAgICAgbW9kZWxfY29kZSA9IG1vZGVsU3RyaW5nLCANCiAgICAgICAgIGNoYWlucyA9IG5jaGFpbiwgDQogICAgICAgICBpdGVyID0gaXRlciwgDQogICAgICAgICB3YXJtdXAgPSBud2FybXVwLA0KICAgICAgICAgdGhpbiA9IHRoaW5zdGVwLA0KICAgICAgICAgY29yZXM9NCkNCg0KYGBgDQoNClNhdSBraGkgdGhpIGjDoG5oIG3DtCBow6xuaCBTVEFOLCB0YSBjw7MgdGjhu4Mga2hhaSB0aMOhYyBr4bq/dCBxdeG6oy4gS+G6v3QgcXXhuqMgY2jDrW5oIGPhu6dhIG3DtCBow6xuaCBuw6B5IGzDoCBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBjaG8gdGhhbSBz4buRIGJldGEsY8WpbmcgY2jDrW5oIGzDoCBo4buHIHPhu5EgdMawxqFuZyBxdWFuIHI6DQoNCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQ0KcHJpbnQoZml0KQ0KYGBgDQoNCk1lZGlhbiBj4bunYSBiZXRhIGzDoCAwLjkzICh04burIDAuNzkgxJHhur9uIDEpLCBjaG8gdGjhuqV5IG3hu5l0IHPhu7EgdMawxqFuZyBxdWFuIG3huqFuaCBnaeG7r2EgWCB2w6AgWQ0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCmJldGE9ZXh0cmFjdChmaXQscGFycz0iYmV0YSIscGVybXV0ZWQ9RiklPiVhc190aWJibGUoKSU+JW11dGF0ZSguLEl0ZXJhdGlvbj1hcy5udW1lcmljKHJvd25hbWVzKC4pKSkNCg0KY29sbmFtZXMoYmV0YSk9YygiQ2hhaW4xIiwiQ2hhaW4yIiwiQ2hhaW4zIiwiSXRlcmF0aW9uIikNCg0KcDE9YmV0YSU+JWdhdGhlcihDaGFpbjE6Q2hhaW4zLGtleT0iQ2hhaW4iLHZhbHVlPSJCZXRhIiklPiUNCiAgZ2dwbG90KGFlcyh4PUJldGEsZmlsbD1DaGFpbikpKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4zKSsNCiAgdGhlbWVfYncoKQ0KDQpwMj1iZXRhJT4lZ2F0aGVyKENoYWluMTpDaGFpbjMsa2V5PSJDaGFpbiIsdmFsdWU9IkJldGEiKSU+JQ0KICBnZ3Bsb3QoYWVzKHg9SXRlcmF0aW9uLHk9QmV0YSxjb2w9Q2hhaW4pKSsNCiAgZ2VvbV9wYXRoKGFscGhhPTAuNSkrDQogIHRoZW1lX2J3KCkNCg0KZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocDEscDIpDQoNCmBgYA0KDQrEkMOieSBsw6AgbeG7pWMgdGnDqnUgdGEgbmjhuq9tIMSR4bq/biwgbmjGsG5nIGNoxrBhIHBo4bqjaSBsw6AgbeG7mXQgZ2nhuqNpIHBow6FwIHThu5FpIMawdS4gTmjGsCDEkcOjIG7Ds2kg4bufIHRyw6puLCBt4buZdCBtw7QgaMOsbmggdHV54bq/biB0w61uaCBsw6AgY8OhY2ggbMOgbSB04buRaSDGsHUgY2hvIHBow6JuIHTDrWNoIHTGsMahbmcgcXVhbi4gQ2jDum5nIHRhIHPhur0gdGjhu7FjIGhp4buHbiBuw7MgYuG6sW5nIHBoxrDGoW5nIHBow6FwIEJheWVzOg0KDQojIEdp4bqjaSBwaMOhcCBCYXllcyB0aOG7qSAyOiBNw7QgaMOsbmggdHV54bq/biB0w61uaA0KDQpN4bulYyB0acOqdSBiw6J5IGdp4budIMSRw7MgbMOgIGThu7FuZyBt4buZdCBtw7QgaMOsbmggdHV54bq/biB0w61uaCB24bubaSBZIGzDoCBr4bq/dCBxdeG6oywgWCBsw6AgcHJlZGljdG9yLiBUcm9uZyBwaMawxqFuZyBwaMOhcCBCYXllcywgxJFp4buBdSBuw6B5IGPDsyBuZ2jEqWEgbMOgIHRhIMSRaSB0w6xtIHBow6JuIHBo4buRaSBo4bqtdSDEkeG7i25oIGNobyBjw6FjIHRoYW0gc+G7kSBiZXRhMCAoaW50ZXJjZXB0KSBiZXRhMSBjaG8gWCwgMiB0aGFtIHPhu5EgbsOgeSBjaG8gcGjDqXAgxrDhu5tjIHTDrW5oIE11IGzDoCB0cnVuZyBiw6xuaCBk4buxIGLDoW8gY+G7p2EgWS4gVGhhbSBz4buRIHRo4bupIDMgbMOgIHNpZ21hLCBoYXkgU0QgY+G7p2EgcGjDom4gcGjhu5FpIGNodeG6qW4gIGPhu6dhIFkuDQoNCk3hu5l0IHRo4bunIHRodeG6rXQgdGjGsOG7nW5nIGTDuW5nIHRyb25nIHBow6JuIHTDrWNoIGjhu5NpIHF1eSBjaG8gYmnhur9uIMSR4buLbmggbMaw4bujbmcgbGnDqm4gdOG7pWMsIMSRw7MgbMOgIGRpIGThu51pIG3hu5FjIHRoYW5nIMSRbyBj4bunYSBYIHbhu4EgduG7iyB0csOtIHRydW5nIGLDrG5oIChjZW50ZXJpbmcpLCB04bupYyBsw6AgbeG7l2kgZ2nDoSB0cuG7iyBYaSB0cuG7qyBjaG8gdHJ1bmcgYsOsbmggY+G7p2EgWC4gVmnhu4djIGRpIGThu51pIG7DoHkgY2hvIHBow6lwIGRp4buFbiBnaeG6o2kga+G6v3QgcXXhuqMgbeG7mXQgY8OhY2ggY2jDrW5oIHjDoWMgaMahbi4gTsOzIHRoYXkgxJHhu5VpIGludGVyY2VwdCBuaMawbmcga2jDtG5nIGzDoG0g4bqjbmggaMaw4bufbmcgZ8OsIMSR4bq/biBo4buHIHPhu5EgaOG7k2kgcXV5IGJldGEuIA0KDQpDZW50ZXJpbmcgc+G6vSDEkcaw4bujYyDDoXAgZOG7pW5nIHRyb25nIG3DtCBow6xuaCBCYXllcy4gVGEgc+G6vSB4deG6pXQga+G6v3QgcXXhuqMgMiBnacOhIHRy4buLIEludGVyY2VwdCwgbeG7mXQg4bufIHRoYW5nIMSRbyBuZ3V5w6puIHRo4buneSBj4bunYSBYLCBt4buZdCBjaG8gdGhhbmcgxJFvIHNhdSBraGkgZGkgZOG7nWkuDQoNCk7hu5lpIGR1bmcgY+G7p2EgbcO0IGjDrG5oIFNUQU4gbmjGsCBzYXU6DQoNCjEpIEJsb2NrIGRhdGEgOiBLaGFpIGLDoW8gNCB0aMOgbmggcGjhuqduIHRyb25nIGxpc3QgZGF0YTogY+G7oSBt4bqrdSBuIGzDoCBt4buZdCBz4buRIG5ndXnDqm4gY8OzIGdpw6EgdHLhu4sgbmjhu48gbmjhuqV0ID0gMywgWSBsw6AgMSB2ZWN0b3IgY2hvIGJp4bq/biBr4bq/dCBxdeG6oywgY8OzIGvDrWNoIHRoxrDhu5tjID1uOyBuWCBsw6Agc+G7kSBwcmVkaWN0b3IgdHJvbmcgbcO0IGjDrG5oICh0cm9uZyB0csaw4budbmcgaOG7o3AgdGEgY8OzIG5oaeG7gXUgaMahbiAxIHByZWRpY3RvciksIG5YIGzDoCAxIHPhu5Egbmd1ecOqbiwgbmjhu48gbmjhuqV0ID0xOyBYIGzDoCBt4buZdCBtYXRyaXggKG4gaMOgbmcsIG5YIGPhu5l0KSDEkeG6oWkgZGnhu4duIGNobyBtb2RlbCBtYXRyaXguDQoNCjIpIEJsb2NrIHRyYW5zZm9ybWVkIGRhdGE6IG5o4bqxbSBob8OhbiBjaHV54buDbiBk4buvIGxp4buHdSAo4bufIMSRw6J5IGzDoCBjZW50ZXJpbmcpLiBUcsaw4bubYyB0acOqbiB0YSBraGFpIGLDoW8gWGMgbMOgIG3hu5l0IG1hdHJpeCBYIHNhdSBraGkgZGkgZOG7nWkgdGhhbmcgxJFvIGPhu6dhIHThuqV0IGPhuqMgblgtMSBj4buZdCBiw6puIHRyb25nIDsgbWVhbnNfWCBsw6AgbeG7mXQgdmVjdG9yIGPDsyBrw61jaCB0aMaw4bubYyBuWC0xLCBjaOG7qWEgZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBjaG8gbeG7l2kgcHJlZGljdG9yIFhpIHRyb25nIG1hdHJpeCBYLiBIw6BtIGhvw6FuIGNodXnhu4NuIChjZW50ZXJpbmcpIGzDoCAxIHbDsm5nIGzhurdwIGPDsyBu4buZaSBkdW5nIGzhuqV5IG3hu5dpIGdpw6EgdHLhu4sgWGkgdHLhu6sgY2hvIG1lYW5zX1gNCg0KMykgQmxvY2sgcGFyYW1ldGVyczoga2hhaSBiw6FvIHRoYW0gc+G7kSB0cm9uZyBtw7QgaMOsbmgsIGfhu5NtOiBiZXRhIGzDoCB2ZWN0b3Iga8OtY2ggdGjGsOG7m2MgblgtMSwgbsOzIGNo4bupYSBo4buHIHPhu5EgaOG7k2kgcXV5IGNobyBjw6FjIHByZWRpY3RvcnMgWGkgdHJvbmcgbWF0cml4IFggKGzGsHUgw707IGJldGEga2jDtG5nIGLhu4sg4bqjbmggaMaw4bufbmcgYuG7n2kgY2VudGVyaW5nKTsgY2JldGEwIGzDoCBt4buZdCBz4buRIHRo4buxYywgY2jhu6lhIGludGVyY2VwdCAoY2jhu4kgY8OzIDEgaW50ZXJjZXB0KSBj4bunYSBtw7QgaMOsbmggduG7m2kgbWF0cml4IFhjOyBzaWdtYSBsw6AgbeG7mXQgc+G7kSB0aOG7sWMsIHRoYW0gc+G7kSBzY2FsZSBjaG8gcGjDom4gcGjhu5FpIG5vcm1hbCBj4bunYSBZLg0KDQo0KSBCbG9jayB0cmFuc2Zvcm1lZCBwYXJhbWV0ZXIga2jDtG5nIHPhu60gZOG7pW5nDQoNCjUpIEJsb2NrIG1vZGVsIDogxJDhuqd1IHRpw6puIHRhIGtoYWkgYsOhbyB0aGFtIHPhu5EgdHJ1bmcgZ2lhbiBtdSwgbMOgIDEgdmVjdG9yIGvDrWNoIHRoxrDhu5tjIG4sIG11IGNo4buJIGdpw6EgdHLhu4sgdHJ1bmcgYsOsbmggY+G7p2EgcGjDom4gcGjhu5FpIE5vcm1hbCBj4bunYSBZLCBtdSA9IGdpw6EgdHLhu4sgZOG7sSBiw6FvIGPhu6dhIFkgdHJvbmcgbcO0IGjDrG5oIHR1eeG6v24gdMOtbmguDQpIw6BtIGxpa2VsaWhvb2QgY8OzIG7hu5lpIGR1bmc6IFkgxJHGsOG7o2MgbcO0IHThuqMgYuG6sW5nIDEgcGjDom4gcGjhu5FpIG5vcm1hbCwgduG7m2kgMiB0aGFtIHPhu5EgTXUgdsOgIFNpZ21hLg0KDQpDw7MgMyB0aGFtIHPhu5EgbsOqbiBjw7MgMyBwcmlvcnM7IGPhu6UgdGjhu4M6IGZsYXQgcHJpb3IgxJHGsOG7o2MgZMO5bmcgY2hvIGJldGEgdsOgIGNiZXRhLCBoYWxmIENhdWNoeSDEkcaw4bujYyBkw7luZyBjaG8gc2lnbWEuDQoNCjYpIEJsb2NrIHRyYW5zZm9ybWVkIHBhcmFtZXRlcnMgY2hvIHBow6lwIGNow7puZyB0YSB0w61uaCDEkcaw4bujYyBJbnRlcmNlcHQgKGJldGEwKSDhu58gdGhhbmcgxJFvIGfhu5FjIHThu6sgY2JldGEwDQoNCg0KIVtdKFBlYXJzb25SbW9kZWwyLnBuZykNCg0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCiMgTW9kZWwgU1RBTg0KDQptb2RlbFN0cmluZzI9ICAiZGF0YSB7IA0KICBpbnQ8bG93ZXI9Mz4gbjsgICAvLyBDbyBtYXUNCiAgdmVjdG9yW25dIFk7ICAgICAgLy8gQmllbiBrZXQgcXVhIFkNCiAgaW50PGxvd2VyPTE+IG5YOyAgLy8gU28gbHVvbmcgcHJlZGljdG9yDQogIG1hdHJpeFtuLCBuWF0gWDsgICAvLyBNb2RlbCBtYXRyaXgNCn0gDQoNCnRyYW5zZm9ybWVkIGRhdGEgeyANCiAgbWF0cml4W24sIG5YIC0gMV0gWGM7ICAvLyBUcnVuZyB0YW0gaG9hIG1hdHJpeCBYDQogIHZlY3RvcltuWCAtIDFdIG1lYW5zX1g7ICAvLyBUcnVuZyBiaW5oIGN1YSBYDQogIA0KICBmb3IgKGkgaW4gMjpuWCkgeyANCiAgICBtZWFuc19YW2kgLSAxXSA9IG1lYW4oWFssIGldKTsgDQogICAgWGNbLCBpIC0gMV0gPSBYWywgaV0gLSBtZWFuc19YW2kgLSAxXTsgDQogIH0gDQp9ICANCnBhcmFtZXRlcnMgeyANCiAgdmVjdG9yW25YLTFdIGJldGE7ICAvLyBUaGFtIHNvIGJldGEgPSBoaWV1IHVuZw0KICByZWFsIGNiZXRhMDsgIC8vIEludGVyY2VwdCBvIHRoYW5nIGRvIHRydW5nIHRhbSANCiAgcmVhbDxsb3dlcj0wPiBzaWdtYTsgIC8vIFJlc2lkdWFsIFNEDQp9IA0KDQp0cmFuc2Zvcm1lZCBwYXJhbWV0ZXJzIHsgDQp9IA0KDQptb2RlbCB7IA0KICB2ZWN0b3Jbbl0gbXU7DQogIG11ID0gY2JldGEwICsgWGMgKiBiZXRhIDsgDQogIC8vIEtoYWkgYmFvIHByaW9yIA0KICBiZXRhIH4gbm9ybWFsKDAsIDEwMCk7IA0KICBjYmV0YTAgfiBub3JtYWwoMCwgMTAwKTsgDQogIHNpZ21hIH4gY2F1Y2h5KDAsIDUpOyANCiAgLy8gbGlrZWxpaG9vZCAgDQogIFkgfiBub3JtYWwobXUsIHNpZ21hKTsgDQp9IA0KDQpnZW5lcmF0ZWQgcXVhbnRpdGllcyB7IA0KICByZWFsIGJldGEwOyAgLy8gSW50ZXJjZXB0IG8gdGhhbmcgZG8gZ29jIA0KICBiZXRhMCA9IGNiZXRhMCAtIGRvdF9wcm9kdWN0KG1lYW5zX1gsIGJldGEpOyANCn0NCiINCmBgYA0KDQpUYSB04bqhbyBsaXN0IGRhdGEgZ+G7k20gbW9kZWwgbWF0cml4LCB2ZWN0b3IgWSwgblggdsOgIG4sIHNhdSDEkcOzIMSRxrBhIHbDoG8gbcO0IGjDrG5oIFNUQU4gdsOgIHRoaSBow6BuaDoNCg0KYGBge3IsbWVzc2FnZSA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9DQpYbWF0PW1vZGVsLm1hdHJpeCh+RkNPLCBkYXRhID0gZGYpDQpkYXRhbGlzdD13aXRoKGRmLCBsaXN0KFkgPSBUQ08sIFggPSBYbWF0LCBuWCA9IG5jb2woWG1hdCksIG4gPSBucm93KGRmKSkpDQoNCnNldC5zZWVkKDEyMykNCg0KZml0PXN0YW4oZGF0YSA9IGRhdGFsaXN0LCANCiAgICAgICAgIG1vZGVsX2NvZGUgPSBtb2RlbFN0cmluZzIsIA0KICAgICAgICAgY2hhaW5zID0gbmNoYWluLCANCiAgICAgICAgIGl0ZXIgPSBpdGVyLCANCiAgICAgICAgIHdhcm11cCA9IG53YXJtdXAsDQogICAgICAgICB0aGluID0gdGhpbnN0ZXAsDQogICAgICAgICBjb3Jlcz00KQ0KDQpgYGANCg0KS+G6v3QgcXXhuqMgbcO0IGjDrG5oIHPhur0gY3VuZyBj4bqlcCBjaG8gY2jDum5nIHRhIDQgY2h14buXaSBNQ01DLCBjaOG7qWEgcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2EgY2JldGEwLCBiZXRhMCwgYmV0YVsxXSwgdmHDqSBzaWdtYS4NCg0KYGBge3IsbWVzc2FnZSA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9DQpwcmludChmaXQpDQoNCmBgYA0KDQojIEtp4buDbSB0cmEgcGjhuqltIGNo4bqldCBjaHXhu5dpIE1DTUMNCg0KVHJvbmcgYsOgaSBuw6B5LCBOaGkgc+G6vSBnaeG7m2kgdGhp4buHdSB24bubaSBjw6FjIGLhuqFuIG3hu5l0IGLGsOG7m2MgcGjhu6UgdHJvbmcgcXV5IHRyw6xuaCBCYXllcywgxJHDsyBsw6Aga2nhu4NtIHRyYSBwaOG6qW0gY2jhuqV0IGPhu6dhIGPDoWMgY2h14buXaSBNQ01DLiBC4bqjbiBjaOG6pXQgY+G7p2EgY2h14buXaSBNQ01DIGzDoCBt4buZdCBxdXkgdHLDrG5oIHLDunQgbmfhuqt1IG5oacOqbiBt4buZdCBt4bqrdSBraMOhIGzhu5tuICh2w6BpIG5nw6BuIGdpw6EgdHLhu4spIHThu6sgcGjDom4gcGjhu5FpIGjhuq11IMSR4buLbmggY+G7p2EgdGhhbSBz4buRLCDEkeG7gyBtw7QgcGjhu49uZyBwaMOibiBwaOG7kWkgbsOgeS4gDQoNClBo4bqpbSBjaOG6pXQgY+G7p2EgY2h14buXaSBNQ01DIGPDsyB0aOG7gyDEkcaw4bujYyBj4bqjbSBuaOG6rW4gdHLhu7FjIHF1YW4ga2hpIGJp4buFdSBkaeG7hW4gbsOzIG5oxrAgMSBjaHXhu5dpIGdpw6EgdHLhu4sgdGhlbyB0aOG7nWkgZ2lhbiAodGltZSBzZXJpZXMgZGF0YSkuIENodeG7l2kgTUNNQyB04buRdCBjw7MgaMOsbmgg4bqjbmggbGnDqm4gdOG7pWMsIMSR4buTbmcgbmjhuqV0LCBu4bq/dSBjw7Mgbmhp4buBdSBjaHXhu5dpIHRow6wgY2jDum5nIMSR4buTbmcgZOG6oW5nIHbDoCBjaOG7lW5nIGzhuq9wIMSRxrDhu6NjIHbhu5tpIG5oYXUuDQoNCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQ0KYmV0YT1leHRyYWN0KGZpdCxwYXJzPSJiZXRhIixwZXJtdXRlZD1GKSU+JWFzX3RpYmJsZSgpJT4lbXV0YXRlKC4sSXRlcmF0aW9uPWFzLm51bWVyaWMocm93bmFtZXMoLikpKQ0KDQpwb3N0ZGY9YXMuZGF0YS5mcmFtZShmaXQpJT4lYXNfdGliYmxlKCklPiVtdXRhdGUoLixJdGVyYXRpb249YXMubnVtZXJpYyhyZXAoYygxOjMwMDApLDMpKSxDaGFpbj1hcy5mYWN0b3IocmVwKGMoMTozKSxlYWNoPTMwMDApKSkNCg0KY29sbmFtZXMocG9zdGRmKT1jKCJCZXRhIiwiQ2VudF9JbnRlcmNlcHQiLCJTaWdtYSIsIkludGVyY2VwdCIsIkxfcCIsIkl0ZXJhdGlvbiIsIkNoYWluIikNCg0KcDE9cG9zdGRmJT4lDQogIGdncGxvdChhZXMoeD1CZXRhLGZpbGw9Q2hhaW4pKSsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhPTAuMykrDQogIHRoZW1lX2J3KCkNCg0KcDI9cG9zdGRmJT4lDQogIGdncGxvdChhZXMoeD1JdGVyYXRpb24seT1CZXRhLGNvbD1DaGFpbikpKw0KICBnZW9tX3BhdGgoYWxwaGE9MC41KSsNCiAgdGhlbWVfYncoKQ0KDQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShwMSxwMikNCg0KYGBgDQoNCktp4buDbSDEkeG7i25oIFJhZnRlcnkocGFja2FnZSBjb2RhKSBsw6AgbeG7mXQgY8OhY2ggxJHhu4Mga2nhu4NtIHRyYSB24buBIHTDrW5oIHBow7kgaOG7o3AgY+G7p2Ega8OtY2ggdGjGsOG7m2MgY2h14buXaSBNQ01DIHbhu5tpIMSR4buZIHRpbiBj4bqteS4gTsOzIHPhur0gxrDhu5tjIHTDrW5oIHPhu5EgbMaw4bujdCBs4bqleSBt4bqrdSB04buRaSB0aGnhu4N1IGPhuqduIHRo4buxYyBoaeG7h24gxJHhu4MgxJHhuqF0IMSR4buZIGNow61uaCB4w6FjIG5o4bqldCDEkeG7i25oICh0aMOtIGThu6UgMC41JSkuIE7hur91IHRyw6puIHRo4buxYyB04bq/IHPhu5EgbMaw4bujdCBs4bqleSBt4bqrdSBj4bunYSBjaMO6bmcgdGEgY2FvIGjGoW4gZ2nDoSB0cuG7iyBuw6B5IHRow6wgdGEgY8OzIHRo4buDIHnDqm4gdMOibS4NCg0KYGBge3J9DQpjb2RhOjpyYWZ0ZXJ5LmRpYWcoZml0KQ0KYGBgDQoNClBow6JuIHTDrWNoIEF1dG9jb3JyZWxhdGlvbiBj4bunYSBjaHXhu5dpIE1DTUM6IE3hu6VjIHRpw6p1IGzDoCB4w6FjIMSR4buLbmggZ2nDoSB0cuG7iyBsYWcgY+G7p2EgTUNNQyAobmjGsCAxIHRpbWUgc2VyaWUpLCBnacOhIHRy4buLIGxhZyBjw6BuZyBn4bqnbiAwIGPDoG5nIHThu5F0ICh0acOqdSBjaHXhuqluIGzDoCBsYWcgPCAyKSwgdsOsIHRoZW8gbmd1ecOqbiB04bqvYyBjw6FjIMSRb+G6oW4gbeG6q3UgbuG7kWkgdGnhur9wIHRyb25nIGNodeG7l2kgcGjhuqNpIMSR4buZYyBs4bqtcCB24bubaSBuaGF1IChraMO0bmcgdMawxqFuZyBxdWFuIGzhuqtuIG5oYXUpLiAgDQoNCmBgYHtyfQ0Kc3Rhbl9hYyhmaXQpDQoNCmBgYA0KDQpN4buZdCB0acOqdSBjaMOtIGtow6FjIGzDoCBnacOhIHRy4buLIFItaGF0LCBuw7MgY2hvIHBow6lwIMSRbyBsxrDhu51uZyB0w61uaCBoaeG7h3UgcXXhuqMgY+G7p2EgcXV5IHRyw6xuaCBs4bqleSBt4bqrdS4gTeG7mXQgY8OhY2ggxJHGoW4gZ2nhuqNuLCBnacOhIHRy4buLIFItaGF0IGPDoG5nIGfhuqduIDEgY8OgbmcgdOG7kXQgKG5nxrDhu6FuZyBsw6AgPCAxLjA1KS4gDQoNCmBgYHtyfQ0Kc3Rhbl9yaGF0KGZpdCkNCmBgYA0KDQpDdeG7kWkgY8O5bmcsIHRy4buLIHPhu5EgRVNTIChlZmZlY3RpdmUgc2FtcGxlIHNpemUsIHThu4kgbOG7hyBj4buhIG3huqt1IGto4bqjIGThu6VuZyksIGNobyBiaeG6v3QgdOG7iSBs4buHIG3huqt1IMSRxrDhu6NjIG3DtCBwaOG7j25nIG3hu5l0IGPDoWNoIGhp4buHdSBxdeG6oyBzbyB24bubaSB04buVbmcgc+G7kSBs4bqnbiBs4bqleSBt4bqrdSwgZ2nDoSB0cuG7iyBlc3MgY8OgbmcgZ+G6p24gMS4wICgxMDAlKSBjw6BuZyB04buRdC4gDQoNCmBgYHtyfQ0Kc3Rhbl9lc3MoZml0KQ0KYGBgDQoNCiMgRGnhu4VuIGdp4bqjaSBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaA0KDQpCw6J5IGdp4budIGNow7puZyB0YSB0aOG7rSBraeG7g20gdHJhIGzhuqFpIDEwMCBwaGnDqm4gYuG6o24gbcO0IGjDrG5oIHR1eeG6v24gdMOtbmggxJHGsOG7o2MgxJHhu4tuaCBk4bqhbmcgdOG7qyBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBjaG8gYmV0YTAsIGJldGExIHbDoCBzbyBzw6FuaCB24bubaSBtb2RlbCBk4buxbmcgYuG6sW5nIG3DtCBow6xuaCB0aGVvIHBow6FpIFJFTUw6DQoNCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQ0KDQpzYW1wbGVkZj1kYXRhLmZyYW1lKEJldGE9cmVwKE5BLDEwMCksSW50ZXJjZXB0PXJlcChOQSwxMDApKQ0KDQpwb3N0ZGYkcHNldWRvRz1yZXAoYygxOjEwMCksZWFjaD0zMDAwLzEwMCkNCg0KZm9yIChpIGluIDE6MTAwKXsNCiAgdGVtcD1zdWJzZXQocG9zdGRmLHBzZXVkb0c9PWkpDQogIHNhbXBsZWRmJEJldGFbaV09bWVkaWFuKHRlbXAkQmV0YVtpXSkNCiAgc2FtcGxlZGYkSW50ZXJjZXB0W2ldPW1lZGlhbih0ZW1wJEludGVyY2VwdCkNCn0NCg0KZ2dwbG90KCkrDQogIGdlb21fcG9pbnQoZGF0YT1kZixhZXMoeD1GQ08seT1UQ08pKSsNCiAgZ2VvbV9hYmxpbmUoZGF0YT1zYW1wbGVkZixhZXMoaW50ZXJjZXB0PUludGVyY2VwdCxzbG9wZT1CZXRhLGNvbD1yb3duYW1lcyhzYW1wbGVkZikpLGFscGhhPTAuMyxzaG93LmxlZ2VuZCA9IEYpKw0KICBnZW9tX3Ntb290aChkYXRhPWRmLGFlcyh4PUZDTyx5PVRDTyksbWV0aG9kPSJsbSIsY29sPSJyZWQ0IixzZT1ULGZpbGw9InJlZCIsYWxwaGE9MC4yKSsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNClRo4bqtdCBuZ2/huqFuIG3hu6VjLCDEkcOzIGzDoCBtw7QgaMOsbmggdHV54bq/biB0w61uaCB0aGVvIEJheWVzIGPFqW5nIGNobyByYSBo4buHIHPhu5EgciB0xrDGoW5nIMSRxrDGoW5nIHbhu5tpIHBoxrDGoW5nIHBow6FwIHThuqduIHPhu5ENCg0KYGBge3IsbWVzc2FnZSA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9DQpjb2Vmcz1hcy5tYXRyaXgoZml0KVssYygiYmV0YTAiLCAiYmV0YVsxXSIpXSU+JWFwcGx5KC4sIDIsIG1lZGlhbikNCg0KcHJlZERGPWRhdGEuZnJhbWUoeCA9IGRmJEZDTyx0cnV0aD1kZiRUQ08pDQoNCnByZWRERiRQcmVkPShjb2VmcyAlKiUgdChtb2RlbC5tYXRyaXgofngsIHByZWRERikpKSU+JWFzLnZlY3RvcigpDQoNCnByZWRERiRSZXNpZHVhbD1wcmVkREYkdHJ1dGgtcHJlZERGJFByZWQNCnByZWRERiRSTVNFPXNxcnQobWVhbihwcmVkREYkUmVzaWR1YWxeMikpDQoNClIyPTEtKHN1bSgocHJlZERGJHRydXRoLXByZWRERiRQcmVkKV4yKS9zdW0oKHByZWRERiR0cnV0aC1tZWFuKHByZWRERiR0cnV0aCkpXjIpKQ0KDQpSMiU+JXNxcnQoKQ0KDQpgYGANCg0KTuG6v3UgdGhhbSB24buNbmcsIHRhIGPDsyB0aOG7gyB04bqhbyByYSBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBjaG8gciBu4buvYSAoVGjhu7FjIHJhIHRhIMSRw6MgY8OzIHRo4buDIGzDoG0gxJFp4buBdSBuw6B5IHRyb25nIGJsb2NrIGdlbmVyYXRlZCBxdWFudGl0aWVzIGPhu6dhIFNUQU4gY29kZSwgbmjGsG5nIHRhIGtow7RuZyBsw6BtIG5oxrAgduG6rXksIHbDrCB0w61uaCB0b8OhbiB0csOqbiB2ZWN0b3IgTUNNQyBsdcO0biBuaGFuaCBjaMOzbmcgaMahbiBsw6AgY8aw4buhbmcgw6lwIHNhbXBsZXIgbOG6pXkgbeG6q3UgTUNNQyBjaG8gbmhp4buBdSB0cuG7iyBz4buRKS4gTmjhu69uZyB0cuG7iyBz4buRIGPDsyB0aOG7gyBzdXkgcmEgdOG7qyB0aGFtIHPhu5EgdHJvbmcgbcO0IGjDrG5oIG7Dqm4gxJHGsOG7o2MgdMOtbmggYsOqbiBuZ2/DoGkgU1RBTiwgc2F1IGtoaSDEkcOjIGPDsyBNQ01DIGPhu6dhIG5o4buvbmcgdGhhbSBz4buRIHRoaeG6v3QgeeG6v3UuDQoNCsSQw6J5IGzDoCBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCBj4bunYSByIHbDoCBSc3F1YXJlZA0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NClJkZj1kYXRhLmZyYW1lKFIyPXJlcChOQSw5MDAwKSxQZWFyc29ucj1yZXAoTkEsOTAwMCkpDQoNCmZvciAoaSBpbiAxOjkwMDApew0KICBjb2Vmcz1hcy5tYXRyaXgoZml0KVtpLGMoImJldGEwIiwgImJldGFbMV0iKV0NCiAgcHJlZERGPWRhdGEuZnJhbWUoeCA9IGRmJEZDTyx0cnV0aD1kZiRUQ08pDQogIHByZWRERiRQcmVkPShjb2VmcyAlKiUgdChtb2RlbC5tYXRyaXgofngsIHByZWRERikpKSU+JWFzLnZlY3RvcigpDQogIHByZWRERiRSZXNpZHVhbD1wcmVkREYkdHJ1dGgtcHJlZERGJFByZWQNCiAgcHJlZERGJFJNU0U9c3FydChtZWFuKHByZWRERiRSZXNpZHVhbF4yKSkNCiAgUjI9MS0oc3VtKChwcmVkREYkdHJ1dGgtcHJlZERGJFByZWQpXjIpL3N1bSgocHJlZERGJHRydXRoLW1lYW4ocHJlZERGJHRydXRoKSleMikpDQogIHI9c3FydChSMikNCiAgUmRmJFIyW2ldPVIyDQogIFJkZiRQZWFyc29ucltpXT1yDQogIH0NCg0KcDE9UmRmJT4lbXV0YXRlKC4sSXRlcmF0aW9uPWFzLm51bWVyaWMocmVwKGMoMTozMDAwKSwzKSksQ2hhaW49YXMuZmFjdG9yKHJlcChjKDE6MyksZWFjaD0zMDAwKSkpJT4lDQogIGdhdGhlcihSMixQZWFyc29ucixrZXk9IkNvZWZmaWNpZW50Iix2YWx1ZT0iRXN0aW1hdGVkIiklPiUNCiAgZ2dwbG90KGFlcyh4PUVzdGltYXRlZCxmaWxsPUNoYWluKSkrDQogIGdlb21fZGVuc2l0eShhbHBoYT0wLjIpKw0KICB0aGVtZV9idygpKw0KICBmYWNldF93cmFwKH5Db2VmZmljaWVudCxzY2FsZXM9ImZyZWUiLG5jb2w9MSkNCiAgDQpwMj1SZGYlPiVtdXRhdGUoLixJdGVyYXRpb249YXMubnVtZXJpYyhyZXAoYygxOjMwMDApLDMpKSxDaGFpbj1hcy5mYWN0b3IocmVwKGMoMTozKSxlYWNoPTMwMDApKSklPiUNCiAgZ2F0aGVyKFIyLFBlYXJzb25yLGtleT0iQ29lZmZpY2llbnQiLHZhbHVlPSJFc3RpbWF0ZWQiKSU+JQ0KICBnZ3Bsb3QoYWVzKHg9SXRlcmF0aW9uLHk9RXN0aW1hdGVkLGNvbD1DaGFpbikpKw0KICBnZW9tX3BhdGgoYWxwaGE9MC41LHNob3cubGVnZW5kID0gRikrDQogIHRoZW1lX2J3KCkrDQogIGZhY2V0X3dyYXAofkNvZWZmaWNpZW50LHNjYWxlcz0iZnJlZSIsbmNvbD0xKQ0KDQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShwMixwMSxuY29sPTIpDQoNCmBgYA0KDQpT4butIGThu6VuZyBST1BFIHbDoCBDb21wVmFsIChi4bqhbiB4ZW0gMiBiw6BpIHRyxrDhu5tjIMSR4buDIGhp4buDdSB0aMOqbSB24buBIDIgcGjGsMahbmcgcGjDoXAgbsOgeSksIHRhIGPDsyB0aOG7gyBraeG7g20gxJHhu4tuaCBt4buZdCBz4buRIGdp4bqjIHRodXnhur90IHbhu4EgcjoNCg0KYGBge3IsbWVzc2FnZSA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9DQpIRElGPSBmdW5jdGlvbiggc2FtcGxlVmVjLGNyZWRNYXNzPTAuOTc1ICkgew0KICBzb3J0ZWRQdHMgPSBzb3J0KCBzYW1wbGVWZWMgKQ0KICBjaUlkeEluYyA9IGNlaWxpbmcoIGNyZWRNYXNzICogbGVuZ3RoKCBzb3J0ZWRQdHMgKSApDQogIG5DSXMgPSBsZW5ndGgoIHNvcnRlZFB0cyApIC0gY2lJZHhJbmMNCiAgY2lXaWR0aCA9IHJlcCggMCAsIG5DSXMgKQ0KICBmb3IgKCBpIGluIDE6bkNJcyApIHsNCiAgICBjaVdpZHRoWyBpIF0gPSBzb3J0ZWRQdHNbIGkgKyBjaUlkeEluYyBdIC0gc29ydGVkUHRzWyBpIF0NCiAgfQ0KICBIREltaW4gPSBzb3J0ZWRQdHNbIHdoaWNoLm1pbiggY2lXaWR0aCApIF0NCiAgSERJbWF4ID0gc29ydGVkUHRzWyB3aGljaC5taW4oIGNpV2lkdGggKSArIGNpSWR4SW5jIF0NCiAgSERJbGltID0gYyggSERJbWluICwgSERJbWF4ICkNCiAgcmV0dXJuKCBIRElsaW0gKQ0KfQ0KDQpTVU1LPWZ1bmN0aW9uKHBhcmFtU2FtcGxlVmVjLGNvbXBWYWw9TlVMTCAsIFJPUEU9TlVMTCAsIGNyZWRNYXNzPTAuOTc1KSB7DQogIG1lYW5QYXJhbSA9IG1lYW4oIHBhcmFtU2FtcGxlVmVjICkNCiAgbWVkaWFuUGFyYW0gPSBtZWRpYW4oIHBhcmFtU2FtcGxlVmVjICkNCiAgZHJlcyA9IGRlbnNpdHkoIHBhcmFtU2FtcGxlVmVjICkNCiAgbW9kZVBhcmFtID0gZHJlcyR4W3doaWNoLm1heChkcmVzJHkpXQ0KICBoZGlMaW0gPSBIRElGKCBwYXJhbVNhbXBsZVZlYyAsIGNyZWRNYXNzPWNyZWRNYXNzICkNCiAgaWYgKCAhaXMubnVsbChjb21wVmFsKSApIHsNCiAgICBwY2d0Q29tcFZhbCA9ICggMTAwICogc3VtKCBwYXJhbVNhbXBsZVZlYyA+IGNvbXBWYWwgKSANCiAgICAgICAgICAgICAgICAgICAgLyBsZW5ndGgoIHBhcmFtU2FtcGxlVmVjICkgKQ0KICB9IGVsc2Ugew0KICAgIGNvbXBWYWw9TkENCiAgICBwY2d0Q29tcFZhbD1OQQ0KICB9DQogIGlmICggIWlzLm51bGwoUk9QRSkgKSB7DQogICAgcGNsdFJvcGUgPSAoIDEwMCAqIHN1bSggcGFyYW1TYW1wbGVWZWMgPCBST1BFWzFdICkgDQogICAgICAgICAgICAgICAgIC8gbGVuZ3RoKCBwYXJhbVNhbXBsZVZlYyApICkNCiAgICBwY2d0Um9wZSA9ICggMTAwICogc3VtKCBwYXJhbVNhbXBsZVZlYyA+IFJPUEVbMl0gKSANCiAgICAgICAgICAgICAgICAgLyBsZW5ndGgoIHBhcmFtU2FtcGxlVmVjICkgKQ0KICAgIHBjaW5Sb3BlID0gMTAwLShwY2x0Um9wZStwY2d0Um9wZSkNCiAgfSBlbHNlIHsgDQogICAgUk9QRSA9IGMoTkEsTkEpDQogICAgcGNsdFJvcGU9TkEgDQogICAgcGNndFJvcGU9TkEgDQogICAgcGNpblJvcGU9TkEgDQogIH0gIA0KICByZXR1cm4oIGMoIE1lYW49bWVhblBhcmFtICwgTWVkaWFuPW1lZGlhblBhcmFtICwgTW9kZT1tb2RlUGFyYW0gLCANCiAgICAgICAgICAgICBIRElsZXZlbD1jcmVkTWFzcyAsIExMPWhkaUxpbVsxXSAsIFVMPWhkaUxpbVsyXSAsIA0KICAgICAgICAgICAgIENvbXBWYWw9Y29tcFZhbCAsIFBjbnRHdENvbXBWYWw9cGNndENvbXBWYWwgLCANCiAgICAgICAgICAgICBST1BFbG93PVJPUEVbMV0gLCBST1BFaGlnaD1ST1BFWzJdICwNCiAgICAgICAgICAgICBQY250THRST1BFPXBjbHRSb3BlICwgUGNudEluUk9QRT1wY2luUm9wZSAsIFBjbnRHdFJPUEU9cGNndFJvcGUgKSApDQp9DQoNCnN1bW1hcnlLcnVzY2hrZT1mdW5jdGlvbihNQ01DLGNvbXBWYWw9TlVMTCwgcm9wZT1OVUxMLGNyZWRNYXNzPU5VTEwpew0KICBzdW1tYXJ5SW5mbyA9IE5VTEwNCiAgc3VtbWFyeUluZm8gPSBjYmluZChzdW1tYXJ5SW5mbywgIkVzdGltYXRlZCI9IFNVTUsoTUNNQywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcFZhbD1jb21wVmFsLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBST1BFPXJvcGUsY3JlZE1hc3M9Y3JlZE1hc3MpKQ0KICByZXR1cm4oc3VtbWFyeUluZm8pDQp9DQoNCnN1bW1hcnlLcnVzY2hrZShNQ01DID0gUmRmJFBlYXJzb25yLGNvbXBWYWw9MC45MCxyb3BlPWMoMC45MCwwLjk1KSxjcmVkTWFzcz0wLjk3NSkNCg0KYGBgDQoNClRow60gZOG7pSwgTmhpIG114buRbiBraeG7g20gdHJhIDMgY8OidSBo4buPaTogciBjw7MgY2FvIGjGoW4gMC45IGhheSBraMO0bmcgIChkw7luZyBDb21wdmFsICkgPyBLaOG6oyBuxINuZyBiYW8gbmhpw6p1ICUgbMOgIHIgY2FvIGjGoW4gMC45NSA/IGJhbyBuaGnDqnUgJSBsw6AgciBu4bqxbSB0cm9uZyBraG/huqNuZyAwLjkyIHThu5tpIDAuOTUgPyAoZMO5bmcgUk9QRSkuDQoNCkvhur90IHF14bqjIGNobyB0aOG6pXkgVHJ1bmcgduG7iyBj4bunYSByPTAuOTU5MzsgbmfGsOG7oW5nIExMPTAuOTMyLCBVTD0wLjk2MzsgOTkuOCUgcGjDom4gcGjhu5FpIGPhu6dhIHIgbOG7m24gaMahbiAwLjk7IDIlIHIgbmjhu48gaMahbiAwLjkyLCAxNC44JSByIG7hurFtIHRyb25nIGtob+G6o25nIDAuOTItMC45NTsgODQuOTglIHIgY2FvIGjGoW4gMC45NS4NCg0KTmjGsCB24bqteSB0YSBjw7MgdGjhu4MgeMOhYyB0w61uIHLhurFuZyB0xrDGoW5nIHF1YW4gZ2nhu69hIFRDTyB2w6AgRkNPIGzDoCBy4bqldCBt4bqhbmgsIGfhuqduIG5oxrAgY2jhuq9jIGNo4bqvbiBsw6AgciBjYW8gaMahbiAwLjkyDQoNCk3hu5l0IGPDtG5nIGPhu6Uga2jDoWMgY8WpbmcgcuG6pXQgbOG7o2kgaOG6oWkgxJHhu4Mga2nhu4NtIHRyYSBwaMOibiBwaOG7kWkgaOG6rXUgxJHhu4tuaCByLCDEkcOzIGzDoCB04buJIHRy4buNbmcgY2jhu6luZyBj4bupIGhheSBCYXllcyBmYWN0b3IuIFRyb25nIHRow60gZOG7pSBzYXUsIE5oaSBraOG6o28gc8OhdCBCYXllcyBmYWN0b3IgY2hvIDExIGdp4bqjIHRodXnhur90IEgxL0gwIHbhu5tpIG5nxrDhu6FuZyBzbyBzw6FuaCB0xINuZyBk4bqnbiB04burIDAuOSDEkeG6v24gMQ0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCnRocmVzaG9sZD1yZXAoTkEsMTEpDQpCYXllc0ZhY3Rvcj1yZXAoTkEsMTEpDQoNCnRocmVzPWMoMC45MCwwLjkxLDAuOTIsMC45MywwLjk0LDAuOTUsMC45NiwwLjk3LDAuOTgsMC45OSwxLjApDQoNCmZvcihpIGluICgxOjExKSl7DQogIHRocj10aHJlc1tpXQ0KICB0aHJlc2hvbGRbaV09dGhyDQogIGh5cD1wYXN0ZSgiUGVhcnNvbnI+Iix0aHIsc2VwPSIiKQ0KICBiZj1icm1zOjpoeXBvdGhlc2lzKFJkZixoeXAsYWxwaGE9MC4wNSkNCiAgQmF5ZXNGYWN0b3JbaV09YmYkaHlwb3RoZXNpcyRFdmlkLlJhdGlvDQp9DQoNCmJmZGY9Y2JpbmQodGhyZXNob2xkLEJheWVzRmFjdG9yKSU+JWFzX3RpYmJsZSgpDQoNCmJmZGYlPiVnZ3Bsb3QoYWVzKHg9dGhyZXNob2xkLHk9QmF5ZXNGYWN0b3IsZmlsbD1CYXllc0ZhY3RvcikpKw0KICBnZW9tX3BhdGgoKSsNCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEYsc2l6ZT01LHNoYXBlPTIxLGNvbD0iYmxhY2siKSsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1yb3VuZChCYXllc0ZhY3RvciwyKSksY29sPSJibGFjayIsc2hvdy5sZWdlbmQgPSBGLGFuZ2xlID0gNjAsbnVkZ2VfeT0yMCxudWRnZV94PTAsc2l6ZT00KSsNCiAgdGhlbWVfYncoKSsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygzMCwxMDApLGxpbmV0eXBlPTIsY29sPSJibHVlIikrDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJnb2xkIixoaWdoPSJyZWQiKQ0KYGBgDQoNCkvhur90IHF14bqjIGNobyB0aOG6pXkgbeG7qWMgxJHhu5kgeMOhYyB0w61uIGzDoCBy4bqldCBjYW8gdHJvbmcga2hv4bqjbmcgMC45IMSR4bq/biAwLjkzLCB2w6AgZ2nhuqNtIGThuqduIGNobyDEkeG6v24gMC45NiwgdsOgIGfhuqduIG5oxrAgPTAgdOG7qyAwLjk3IHRy4bufIMSRaSwgbmjGsCB24bqteSB24bubaSBk4buvIGxp4buHdSBoaeG7h24gdGjhu51pLCB0YSBjaOG7iSBjw7MgdGjhu4MgeMOhYyBxdXnhur90IHbhu4EgZ2nDoSB0cuG7iyByIHRyb25nIGtob+G6o25nIDAuOTAgxJHhur9uIDAuOTMuDQoNCiMgVOG7lW5nIGvhur90DQoNCkLDoGkgdGjhu7FjIGjDoG5oIGPhu6dhIGNow7puZyB0YSDEkeG6v24gxJHDonkgbMOgIGvhur90IHRow7pjLiBDw6FjIGLhuqFuIMSRw6MgY8OzIHRo4buDIHRoYXkgdGjhur8gcGjEg24gdMOtY2ggdMawxqFuZyBxdWFuIGPhu5UgxJFp4buDbiBi4bqxbmcgcGjGsMahbmcgcGjDoXAgQmF5ZXMuIFThuqV0IGPhuqMgbMOgIG5o4budIG3DtCBow6xuaCB0dXnhur9uIHTDrW5oIG3DoCB04buVIHPGsCBLYXJsIFBlYXJzb24gdHJ1eeG7gW4gbOG6oWksIGNow7puZyB0YSBjaOG7iSBk4buxbmcgbcO0IGjDrG5oIHRoZW8gbeG7mXQgY8OhY2gga2jDoWMuDQoNCk3hu5l0IHPhu5EgdGjDtG5nIMSRaeG7h3AgcXVhbiB0cuG7jW5nIGPDsyB0aOG7gyByw7p0IHJhIHRyb25nIGLDoGkgbsOgeSwgxJHDsyBsw6A6DQoNCjEpIEPDsyBz4buxIHF1YW4gaOG7hyBnaeG7r2EgaOG7hyBz4buRIHTGsMahbmcgcXVhbiByIHbDoCBtw7QgaMOsbmggdHV54bq/biB0w61uaA0KDQoyKSBNw7QgaMOsbmggdHV54bq/biB0w61uaCBsw6AgZ2nhuqNpIHBow6FwIHThu5F0IGjGoW4gc28gduG7m2kgciB2w6AgdCB0ZXN0LCB2w6wgbcO0IGjDrG5oIHPhur0gY2hvIG5oaeG7gXUgdGjDtG5nIHRpbiBoxqFuLCBiYW8gZ+G7k20gY+G6oyByDQoNCjMpIENo4buJIGTDuW5nIHNhbXBsZXIgY2hvIG5o4buvbmcgdGhhbSBz4buRIHRo4buxYyBz4buxIHRoaeG6v3QgeeG6v3UsIHbDoCB0w61uaCBuaOG7r25nIHRy4buLIHPhu5Ega2jDoWMgc2F1IMSRw7MgdOG7qyBNQ01DDQoNCjQpIFBoxrDGoW5nIHBow6FwIGZyZXF1ZW50aXN0IHbDoCBwX3ZhbHVlIGPDsyBuaGnhu4F1IG5oxrDhu6NjIMSRaeG7g20gdsOgIGLhuqt5IG5ndXkgaGnhu4NtLCB0YSBuw6puIHRoYXkgdGjhur8gY8OhY2ggbMOgbSBjxakgYuG6sW5nIHBoxrDGoW5nIHBow6FwIEJheWVzLg0KDQrEkMOieSBjaOG7iSBt4bubaSBsw6AgbeG7mXQga2jDumMgZOG6oW8gxJHhuqd1IGNobyBt4buZdCBjaOG6t25nIMSRxrDhu51uZyBt4bubaSB0aMO6IHbhu4sgaMahbiBtw6AgdGEgc+G6vSBraMOhbSBwaMOhLCDEkcOzIGzDoCBtw7QgaMOsbmggdHV54bq/biB0w61uaCB04buVbmcgcXXDoXQgKEdMTSkgdGhlbyBCQVlFUy4gSOG6uW4gZ+G6t3AgbOG6oWkgY8OhYyBi4bqhbi4NCg0KTuG6v3UgY8OhYyBi4bqhbiBjw7MgaOG7qW5nIHRow7ogdGhhbSBnaWEgcmVib290IGNobyBk4buxIMOhbiBCYXllcyBmb3IgVmlldG5hbSwgeGluIGxpw6puIGzhuqFjIHbhu5tpIG5ow7NtIGNow7puZyB0w7RpLiANCg0KKlhpbiBj4bqjbSDGoW4gdsOgIGjhurluIGfhurdwIGzhuqFpKg==