Speaker: NCS. Nguyễn Thanh Nga - Học viện Ngân Hàng
1. Mô tả dữ liệu
Tập tin marketing.csv dùng để phân tích ảnh hưởng của các hình thức quảng cáo lên doanh thu. Dữ liệu bao gồm 4 biến:
- \(youtube\), \(facebook\) và \(newspaper\) là số tiền chi cho quảng cáo (Đơn vị: triệu đồng)
- \(sales\) là biến doanh thu. Bộ số liệu có \(200\) quan sát, thu thập tại 200 cửa hàng.
marketing <- read.csv("marketing.csv")
head(marketing)
## X youtube facebook newspaper sales
## 1 1 200.92 142.17 145.41 943.0419
## 2 2 156.26 129.85 62.70 856.2597
## 3 3 124.38 187.57 140.04 964.9689
## 4 4 157.69 187.48 143.94 1017.4412
## 5 5 158.23 222.41 116.04 1115.2990
## 6 6 132.48 181.55 119.84 932.3739
## 'data.frame': 200 obs. of 5 variables:
## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ youtube : num 201 156 124 158 158 ...
## $ facebook : num 142 130 188 187 222 ...
## $ newspaper: num 145.4 62.7 140 143.9 116 ...
## $ sales : num 943 856 965 1017 1115 ...
2. Phân tích tương quan
vẽ đồ thị phân tán giữa các cặp biến
op <- par(mfrow = c(1,3))
plot(youtube ~ sales, data = marketing, pch = 16, col = 'blue', main = "Youtube vs Sales")
plot(facebook ~ sales, data = marketing, pch = 16, col = 'blue', main = "Facebook vs Sales")
plot(marketing$newspaper, marketing$sales, pch = 16, col = 'blue', main = "Newspaper vs Sales")

Từ các đồ thị phân tán, ta có thể nhận xét rằng các biến \(youtube\) và \(facebook\) có mối quan hệ tuyến tính với biến \(sales\) trong khi biến \(newspaper\) không có. Mặt khác, mối quan hệ giữa \(Newspaper\) và \(sales\), nói một cách chính xác hơn là phi tuyến tính hơn là tuyến tính.
Hệ số tương quan tuyến tính (Correlation coefficient)
Hệ số tương quan đo lường mức độ quan hệ tuyến tính giữa hai biến, không phân biệt biến này phụ thuộc vào biến kia
Các phương pháp tính tương quan: * Hệ số tương quan Pearson * Hệ số tương quan spearman * Hệ số tương quan kendall
2.1. Hệ số tương quan Pearson
- Công thức tính hệ số tương quan Pearson trên R: cor(df, method = “pearson”)
cor(marketing, method = "pearson")
## X youtube facebook newspaper sales
## X 1.00000000 -0.04977015 -0.03918551 -0.177473371 -0.047532656
## youtube -0.04977015 1.00000000 0.08401121 0.047806059 0.487083735
## facebook -0.03918551 0.08401121 1.00000000 -0.039579633 0.903092760
## newspaper -0.17747337 0.04780606 -0.03957963 1.000000000 -0.002900308
## sales -0.04753266 0.48708374 0.90309276 -0.002900308 1.000000000
# Cor cho hai bien
cor(marketing$facebook,marketing$sales)
## [1] 0.9030928
2.2. Hệ số tương quan spearman
Đánh giá mức độ tương quan của 2 hạng của 2 biến (rank-ordered variables), sử dụng khi phân phối của tổng thể được giả sử không phải là phân phối chuẩn hoặc trong trường hợp có các giá trị quan sát bất thường (lớn quá hoặc nhỏ quá)
Công thức tính trên R: cor(df, method = “spearman”)
cor(marketing, method = "spearman")
## X youtube facebook newspaper sales
## X 1.000000000 -0.007446197 -0.06512643 -0.1753965822 -0.0706097652
## youtube -0.007446197 1.000000000 0.06036389 0.0620604644 0.4422117186
## facebook -0.065126427 0.060363895 1.00000000 -0.0332461435 0.8994231601
## newspaper -0.175396582 0.062060464 -0.03324614 1.0000000000 -0.0004522618
## sales -0.070609765 0.442211719 0.89942316 -0.0004522618 1.0000000000
# Cor cho hai bien
cor(marketing$youtube, marketing$sales, method = "spearman")
## [1] 0.4422117
2.3. Hệ số tương quan kendall
Hệ số kendall ít dùng hơn so với 2 hệ số tương quan trên
Công thức tính trên R: cor(df, method = “kendall”)
cor(marketing, method = "kendall")
## X youtube facebook newspaper sales
## X 1.000000000 -0.005025631 -0.04532891 -0.11734553 -0.04874372
## youtube -0.005025631 1.000000000 0.03789516 0.04829995 0.30324656
## facebook -0.045328911 0.037895160 1.00000000 -0.02326925 0.72656918
## newspaper -0.117345529 0.048299952 -0.02326925 1.00000000 -0.00587984
## sales -0.048743719 0.303246559 0.72656918 -0.00587984 1.00000000
# Cor cho hai bien
cor(marketing$youtube, marketing$sales, method = "kendall")
## [1] 0.3032466
2.4. Kiểm định tương quan
Cũng như phương pháp tính, kiểm định cũng có 3 method: Pearson, Spearman, Kendall
Giả thiết kiểm định:
- H0: Không có tương quan (hệ số tương quan = 0)
- H1: Có tương quan
Ví dụ: Sử dụng hàm cor.test
cor.test(marketing$youtube, marketing$sales)
##
## Pearson's product-moment correlation
##
## data: marketing$youtube and marketing$sales
## t = 7.8478, df = 198, p-value = 2.597e-13
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.3735893 0.5862096
## sample estimates:
## cor
## 0.4870837
cor.test(marketing$facebook,marketing$sales)
##
## Pearson's product-moment correlation
##
## data: marketing$facebook and marketing$sales
## t = 29.591, df = 198, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.8738405 0.9258309
## sample estimates:
## cor
## 0.9030928
cor.test(marketing$newspaper, marketing$sales)
##
## Pearson's product-moment correlation
##
## data: marketing$newspaper and marketing$sales
## t = -0.040811, df = 198, p-value = 0.9675
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.1415844 0.1358954
## sample estimates:
## cor
## -0.002900308
2.5.Một số đồ thị trong phân tích tương quan
- corrplot (package: corrplot)
raqMatrix <- cor(marketing %>% select(youtube, facebook,
newspaper, sales))
corrplot(raqMatrix, method = "circle")

- biểu đồ tương quan giữa các biến, hàm pairs.panels() trong gói psych

3. Hồi quy tuyến tính đa biến
Mô hình hồi quy bội có dạng: \[Y = \beta_{1} + \beta_{2}X_{2} + \beta_{3}X_{3} +..+ \beta_{k}X_{k} + u \]
Yêu cầu: xây dựng mô hình hồi quy bội (multiple regression) để phân tích tác động của các hình thức quảng cáo lên doanh thu và diễn giải kết quả. cụ thể:
- Biến phụ thuộc: doanh thu \(sales\)
- Biến độc lập: \(youtube\), \(facebook\), \(newspaper\) lần lượt là số tiền chi cho quảng cáo trên Youtube, Facebook và trên báo chí
3.1.Ước lượng mô hình
Sử dụng lệnh lm():
model.marketing <- lm(sales ~ youtube + facebook + newspaper, data = marketing)
summary(model.marketing)
##
## Call:
## lm(formula = sales ~ youtube + facebook + newspaper, data = marketing)
##
## Residuals:
## Min 1Q Median 3Q Max
## -37.571 -9.826 0.581 9.575 40.175
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 202.19448 7.93632 25.477 <2e-16 ***
## youtube 1.86693 0.03832 48.714 <2e-16 ***
## facebook 2.73133 0.02668 102.382 <2e-16 ***
## newspaper 0.04969 0.03590 1.384 0.168
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 14.62 on 196 degrees of freedom
## Multiple R-squared: 0.986, Adjusted R-squared: 0.9858
## F-statistic: 4605 on 3 and 196 DF, p-value: < 2.2e-16
Vì biến \(newspaper\) không có ý nghĩa trong mô hình hồi quy bội được xây dựng, ta có thể loại bỏ biến này và xây dựng lại mô hình hồi quy bội chỉ với hai biến \(youtube\) và \(facebook\):
model2.marketing <- lm(sales ~ youtube + facebook, data = marketing)
summary(model2.marketing)
##
## Call:
## lm(formula = sales ~ youtube + facebook, data = marketing)
##
## Residuals:
## Min 1Q Median 3Q Max
## -38.589 -9.631 0.468 9.658 38.351
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 207.06397 7.13046 29.04 <2e-16 ***
## youtube 1.86966 0.03836 48.74 <2e-16 ***
## facebook 2.72971 0.02671 102.18 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 14.65 on 197 degrees of freedom
## Multiple R-squared: 0.9859, Adjusted R-squared: 0.9857
## F-statistic: 6875 on 2 and 197 DF, p-value: < 2.2e-16
Hệ số \(R^2\) hiệu chỉnh bằng \(0.9857\) nghĩa là \(98.57\%\) sự biến thiên trong doanh thu \(sales\) được giải thích bởi các biến \(youtube\) và \(facebook\) tức là chi phí chi cho việc quảng cáo trên Facebook và Youtube.
3.2. Tìm khoảng tin cậy cho các hệ số hồi quy
Sử dụng hàm confint():
confint(model2.marketing) # do tin cay = 95%
## 2.5 % 97.5 %
## (Intercept) 193.002136 221.125806
## youtube 1.794002 1.945312
## facebook 2.677027 2.782391
confint(model2.marketing, level = 0.99) # do tin cay = 99%
## 0.5 % 99.5 %
## (Intercept) 188.517527 225.610415
## youtube 1.769874 1.969440
## facebook 2.660225 2.799193
3.3. Kiểm định và lựa chọn mô hình
Nhắc lại một số giả thiết của mô hình hồi quy
- Tính tuyến tính của dữ liệu
- Phần dư có phân phối chuẩn
- Phần dư có trung bình bằng 0
- Phương sai của phần dư là không đổi
3.3.1 Dựa vào đồ thị phần dư
par(mfrow = c(2, 2))
plot(model2.marketing)

- Đồ thị thứ 1 (Residuals vs Fitted) Dùng để kiểm tra giả thiết tuyến tính của dữ liệu và giả thiết phần dư có trung bình bằng 0
Trục tung biểu thị giá trị của phần dư, trục hoành biểu thị giá trị tiên lượng (\(\hat y_i\)) của biến phụ thuộc. Nếu như giả thiết về tính tuyến tính của dữ liệu KHÔNG thỏa, ta sẽ quan sát thấy rằng đường màu đỏ trên đồ thị sẽ phân bố theo một hình mẫu (pattern) đặc trưng nào đó (ví dụ parabol). Nếu đường màu đỏ trên đồ thị phân tán là đường thẳng nằm ngang mà không phải là đường cong, thì giả thiết tính tuyến tính của dữ liệu được thỏa mãn. Giả thiết phần dư có trung bình bằng 0 thỏa mãn nếu đường màu đỏ gần với đường nằm ngang (ứng với phần dư =0).
- Đồ thị thứ 2 (Normal Q-Q) Dùng để kiểm tra giả thiết phần dư có phân phối chuẩn
Nếu các điểm thặng dư nằm trên cùng 1 đường thẳng thì điều kiện về phân phối chuẩn được thỏa.
- Đồ thị thứ 3 (Scale - Location) Dùng để kiểm định giả thiết phương sai của phần dư là không đổi
Trục tung là căn bậc hai của giá trị của phần dư (đã được chuẩn hóa), trục hoành là giá trị tiên lượng (\(\hat y_i\)) của biến phụ thuộc từ mô hình. Nếu như đường màu đỏ trên đồ thị là đường thẳng nằm ngang và các điểm thặng dư phân tán đều xung quanh đường thẳng này thì giả thiết thứ 4 được thỏa. Nếu như đường màu đỏ có độ dốc (hoặc cong) hoặc các điểm thặng dư phân tán không đều xung quanh đường thẳng này, thì giả thiết này bị vi phạm.
- Đồ thị thứ 4 (Residuals vs Leverage) cho phép xác định những điểm có ảnh hưởng cao (influential observations), nếu chúng có hiện diện trong bộ dữ liệu. Những điểm có ảnh hưởng cao này có thể là các điểm outliers, là những điểm có thể gây nhiều ảnh hưởng nhất khi phân tích dữ liệu. Nếu như ta quan sát thấy một đường thẳng màu đỏ đứt nét (Cook’s distance), và có một số điểm vượt qua đường thẳng khoảng cách này, nghĩa là các điểm đó là các điểm có ảnh hưởng cao. Nếu như ta chỉ quan sát thấy đường thẳng khoảng cách Cook ở góc của đồ thị và không có điểm nào vượt qua nó, nghĩa không có điểm nào thực sự có ảnh hưởng cao.
Nhận xét:
- Đồ thị thứ 1 (Residuals vs Fitted) cho thấy giả thiết về tính tuyến tính của dữ liệu hơi bị vi phạm. Tuy nhiên giả thiết trung bình của phần dư có thể coi là thỏa mãn
- Đồ thị Normal Q-Q cho thấy giả thiết phần dư có phân phối chuẩn được thỏa mãn.
- Đồ thị (Scale - Location) cho ta thấy rằng giả thiết về tính đồng nhất của phương sai cũng thỏa mãn.
- Đồ thị thứ tư chỉ ra có các quan trắc thứ 42, 124 và 143 có thể là các điểm có ảnh hưởng cao trong bộ dữ liệu.
Để vẽ từng đồ thị, ta dùng các lệnh sau:
plot(model2.marketing, 1)

plot(model2.marketing, 2)

plot(model2.marketing, 3)

plot(model2.marketing, 5)

3.3.2 Dựa vào các kiểm định
re <- resid(model2.marketing)
Giả thiết 1: Sai số ngẫu nhiên có phân phối chuẩn
Giả thiết kiểm định:
- H0: Dữ liệu có phân phối chuẩn
- H1: Dữ liệu không có phân phối chuẩn
##
## Shapiro-Wilk normality test
##
## data: re
## W = 0.9945, p-value = 0.676
p-value =0.676 nên phần dư có phân phối chuẩn
Giả thiết 2: Kỳ vọng của sai số ngẫu nhiên tại mỗi giá trị bằng 0
##
## One Sample t-test
##
## data: re
## t = -6.9193e-16, df = 199, p-value = 1
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## -2.032987 2.032987
## sample estimates:
## mean of x
## -7.133487e-16
p-value = 1, do do mô hình thỏa mãn giả thiết 2
Giả thiết 3: Phương sai của sai số ngẫu nhiên không đổi
H0: phương sai sai số không đổi
H1: Phương sai sai số thay đổi
ncvTest(model2.marketing)
## Non-constant Variance Score Test
## Variance formula: ~ fitted.values
## Chisquare = 0.2402166, Df = 1, p = 0.62405
p-value = 0.624, có thể kết luận phương sai sai số là không đổi.
Giả thiết 4: Giữa các biến độc lập không có mối quan hệ đa cộng tuyến hoàn hảo
\(VIF_j = \frac {1} {1-R_j^2}\)
\(R_j^2\) là hệ số xác định của mô hình hồi qui tuyến tính phụ của biến độc lập \(X_j\) theo các biến độc lập còn lại của mô hình.
## youtube facebook
## 1.007108 1.007108
vif < 10 cho thấy các biến độc lập không có đa cộng tuyến
3.4. Dự báo
youtube <- c(57, 60, 55.5, 117, 98, 69, 100, 150, 200, 125, 170, 195, 270, 198)
facebook <- c(10, 15.7, 50, 76, 24.8, 200, 198, 150, 99.8, 76.5, 45.4, 187, 78.3, 200)
new <- data.frame(youtube, facebook)
Dự báo giá trị trung bình
predict(model2.marketing , newdata = new, interval = "confidence")
## fit lwr upr
## 1 340.9315 330.1266 351.7365
## 2 362.0998 351.6488 372.5509
## 3 447.3154 437.8850 456.7458
## 4 633.2717 627.4215 639.1219
## 5 457.9871 449.3153 466.6590
## 6 882.0121 875.3312 888.6930
## 7 934.5121 929.9632 939.0609
## 8 896.9689 894.5891 899.3486
## 9 853.4203 847.4027 859.4380
## 10 649.5938 643.9473 655.2404
## 11 648.8345 641.5132 656.1557
## 12 1082.1027 1078.0787 1086.1267
## 13 925.6076 914.6529 936.5623
## 14 1123.1979 1118.8581 1127.5377
Dự báo giá trị cá biệt
predict(model2.marketing , newdata = new, interval = "prediction")
## fit lwr upr
## 1 340.9315 310.0795 371.7836
## 2 362.0998 331.3699 392.8297
## 3 447.3154 416.9174 477.7133
## 4 633.2717 603.7874 662.7561
## 5 457.9871 427.8159 488.1584
## 6 882.0121 852.3517 911.6725
## 7 934.5121 905.2581 963.7660
## 8 896.9689 867.9729 925.9648
## 9 853.4203 823.9023 882.9384
## 10 649.5938 620.1492 679.0385
## 11 648.8345 619.0233 678.6456
## 12 1082.1027 1052.9257 1111.2797
## 13 925.6076 894.7028 956.5124
## 14 1123.1979 1093.9757 1152.4201
3.5. Xuất kết quả hệ số hồi quy
Xuất bảng hồi quy dạng tex, cho báo cáo file Word
stargazer(model2.marketing, type = "text")
##
## ===============================================
## Dependent variable:
## ---------------------------
## sales
## -----------------------------------------------
## youtube 1.870***
## (0.038)
##
## facebook 2.730***
## (0.027)
##
## Constant 207.064***
## (7.130)
##
## -----------------------------------------------
## Observations 200
## R2 0.986
## Adjusted R2 0.986
## Residual Std. Error 14.654 (df = 197)
## F Statistic 6,875.092*** (df = 2; 197)
## ===============================================
## Note: *p<0.1; **p<0.05; ***p<0.01
Xuất bảng hồi quy dạng tex, cho báo cáo file latex.
stargazer(model2.marketing, type = "latex")
##
## % Table created by stargazer v.5.2.2 by Marek Hlavac, Harvard University. E-mail: hlavac at fas.harvard.edu
## % Date and time: Tue, Sep 21, 2021 - 10:19:08 PM
## \begin{table}[!htbp] \centering
## \caption{}
## \label{}
## \begin{tabular}{@{\extracolsep{5pt}}lc}
## \\[-1.8ex]\hline
## \hline \\[-1.8ex]
## & \multicolumn{1}{c}{\textit{Dependent variable:}} \\
## \cline{2-2}
## \\[-1.8ex] & sales \\
## \hline \\[-1.8ex]
## youtube & 1.870$^{***}$ \\
## & (0.038) \\
## & \\
## facebook & 2.730$^{***}$ \\
## & (0.027) \\
## & \\
## Constant & 207.064$^{***}$ \\
## & (7.130) \\
## & \\
## \hline \\[-1.8ex]
## Observations & 200 \\
## R$^{2}$ & 0.986 \\
## Adjusted R$^{2}$ & 0.986 \\
## Residual Std. Error & 14.654 (df = 197) \\
## F Statistic & 6,875.092$^{***}$ (df = 2; 197) \\
## \hline
## \hline \\[-1.8ex]
## \textit{Note:} & \multicolumn{1}{r}{$^{*}$p$<$0.1; $^{**}$p$<$0.05; $^{***}$p$<$0.01} \\
## \end{tabular}
## \end{table}
TRÂN TRỌNG MỜI ĐẠI BIỂU THAM DỰ VÀ TRÂN TRỌNG CẢM ƠN!
LS0tDQp0aXRsZTogIk3DtCBIw6xuaCBI4buTaSBRdXkgQuG7mWkiDQphdXRob3I6ICJOZ3V54buFbiBUaGFuaCBOZ2EgLSBI4buNYyB2aeG7h24gTmfDom4gSMOgbmciDQpkYXRlOiAiOS8yMi8yMDIxIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDogDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICAjIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6ICJmbGF0bHkiDQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KDQpUw6BpIGxp4buHdSBideG7lWkgdGjhu7FjIGjDoG5oIHNlbWluYXIgVEtVRCBbVEtVRDE5XSAyMi85LzIwMjE6IE3DtCBow6xuaCBo4buTaSBxdXkgYuG7mWkNCg0KU3BlYWtlcjogTkNTLiBOZ3V54buFbiBUaGFuaCBOZ2EgLSBI4buNYyB2aeG7h24gTmfDom4gSMOgbmcNCg0KQ2hpIHRp4bq/dCB04bqhaTogaHR0cHM6Ly9zaXRlcy5nb29nbGUuY29tL3ZpZXcvdGt1ZC9ob21lP2F1dGh1c2VyPTEgDQoNClTDoGkgbGnhu4d1IHRo4buxYyBow6BuaCBjw7MgdGjhu4MgZG93bmxvYWQgW3ThuqFpIMSRw6J5XShodHRwczovL2RyaXZlLmdvb2dsZS5jb20vZHJpdmUvZm9sZGVycy8xbWFOVUFXeUNjalhyVTBtNmhNZ1pOaGpFSTBqVUk5R3U/dXNwPXNoYXJpbmcpLg0KDQooQ2jhu41uIGNodeG7mXQgcGjhuqNpIHThuqFpIGNo4buvICJ04bqhaSDEkcOieSIsIGNo4buNbiBvcGVuIG5ldyB0YWIpDQoNCkhv4bq3YyBjb3B5IGxpbmsgbsOgeTogaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2RyaXZlL2ZvbGRlcnMvMW1hTlVBV3lDY2pYclUwbTZoTWdaTmhqRUkwalVJOUd1P3VzcD1zaGFyaW5nIA0KDQoNCmBgYHtyIH0NCiNzZXR3ZCgiQzpcXFVzZXJzXFxndGVjaFxcRGVza3RvcFxcTUhIUVRUX05nYSIpDQpzZXR3ZCgiRDovVGFwIGh1YW4gVklBU00vQ2h1b2kgU2VtaW5hci9UOV8yMDIxL1RoYW5oIE5nYSIpDQpsaWJyYXJ5KGNhcikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShjb3JycGxvdCkgIyBWZSBoaW5oIHR1b25nIHF1YW4NCmxpYnJhcnkocHN5Y2gpIyBWZSBoaW5oIHR1b25nIHF1YW4NCnJlcXVpcmUoc3RhcmdhemVyKSAjIFh1YXQga2V0IHF1YSBob2kgcXV5DQpgYGANCg0KIyMgMS4gTcO0IHThuqMgZOG7ryBsaeG7h3UgDQpU4bqtcCB0aW4gKm1hcmtldGluZy5jc3YqIGTDuW5nIMSR4buDIHBow6JuIHTDrWNoIOG6o25oIGjGsOG7n25nIGPhu6dhIGPDoWMgaMOsbmggdGjhu6ljIHF14bqjbmcgY8OhbyBsw6puIGRvYW5oIHRodS4gROG7ryBsaeG7h3UgYmFvIGfhu5NtIDQgYmnhur9uOiANCg0KKiAkeW91dHViZSQsICRmYWNlYm9vayQgdsOgICRuZXdzcGFwZXIkIGzDoCBz4buRIHRp4buBbiBjaGkgY2hvIHF14bqjbmcgY8OhbyAoxJDGoW4gduG7izogdHJp4buHdSDEkeG7k25nKQ0KKiAkc2FsZXMkIGzDoCBiaeG6v24gZG9hbmggdGh1LiANCkLhu5kgc+G7kSBsaeG7h3UgY8OzICQyMDAkIHF1YW4gc8OhdCwgdGh1IHRo4bqtcCB04bqhaSAyMDAgY+G7rWEgaMOgbmcuIA0KDQpgYGB7cn0NCm1hcmtldGluZyA8LSByZWFkLmNzdigibWFya2V0aW5nLmNzdiIpDQpoZWFkKG1hcmtldGluZykNCnN0cihtYXJrZXRpbmcpDQpgYGANCg0KIyMgMi4gUGjDom4gdMOtY2ggdMawxqFuZyBxdWFuDQoNCnbhur0gxJHhu5MgdGjhu4sgcGjDom4gdMOhbiBnaeG7r2EgY8OhYyBj4bq3cCBiaeG6v24NCg0KYGBge3J9DQpvcCA8LSBwYXIobWZyb3cgPSBjKDEsMykpDQpwbG90KHlvdXR1YmUgfiBzYWxlcywgZGF0YSA9IG1hcmtldGluZywgcGNoID0gMTYsIGNvbCA9ICdibHVlJywgbWFpbiA9ICJZb3V0dWJlIHZzIFNhbGVzIikNCnBsb3QoZmFjZWJvb2sgfiBzYWxlcywgZGF0YSA9IG1hcmtldGluZywgcGNoID0gMTYsIGNvbCA9ICdibHVlJywgbWFpbiA9ICJGYWNlYm9vayB2cyBTYWxlcyIpDQpwbG90KG1hcmtldGluZyRuZXdzcGFwZXIsIG1hcmtldGluZyRzYWxlcywgcGNoID0gMTYsIGNvbCA9ICdibHVlJywgbWFpbiA9ICJOZXdzcGFwZXIgdnMgU2FsZXMiKQ0KcGFyKG9wKQ0KYGBgDQoNClThu6sgY8OhYyDEkeG7kyB0aOG7iyBwaMOibiB0w6FuLCB0YSBjw7MgdGjhu4Mgbmjhuq1uIHjDqXQgcuG6sW5nIGPDoWMgYmnhur9uICR5b3V0dWJlJCB2w6AgJGZhY2Vib29rJCBjw7MgbeG7kWkgcXVhbiBo4buHIHR1eeG6v24gdMOtbmggduG7m2kgYmnhur9uICRzYWxlcyQgdHJvbmcga2hpIGJp4bq/biAkbmV3c3BhcGVyJCBraMO0bmcgY8OzLiBN4bq3dCBraMOhYywgbeG7kWkgcXVhbiBo4buHIGdp4buvYSAkTmV3c3BhcGVyJCB2w6AgJHNhbGVzJCwgbsOzaSBt4buZdCBjw6FjaCBjaMOtbmggeMOhYyBoxqFuIGzDoCBwaGkgdHV54bq/biB0w61uaCBoxqFuIGzDoCB0dXnhur9uIHTDrW5oLiANCg0KIyMjIEjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gdHV54bq/biB0w61uaCAoQ29ycmVsYXRpb24gY29lZmZpY2llbnQpDQoNCkjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gxJFvIGzGsOG7nW5nIG3hu6ljIMSR4buZIHF1YW4gaOG7hyB0dXnhur9uIHTDrW5oIGdp4buvYSBoYWkgYmnhur9uLCBraMO0bmcgcGjDom4gYmnhu4d0IGJp4bq/biBuw6B5IHBo4bulIHRodeG7mWMgdsOgbyBiaeG6v24ga2lhDQoNCkPDoWMgcGjGsMahbmcgcGjDoXAgdMOtbmggdMawxqFuZyBxdWFuOg0KKiBI4buHIHPhu5EgdMawxqFuZyBxdWFuIFBlYXJzb24NCiogSOG7hyBz4buRIHTGsMahbmcgcXVhbiBzcGVhcm1hbg0KKiBI4buHIHPhu5EgdMawxqFuZyBxdWFuIGtlbmRhbGwNCg0KIyMjIDIuMS4gSOG7hyBz4buRIHTGsMahbmcgcXVhbiBQZWFyc29uDQoNCiAgLSBDw7RuZyB0aOG7qWMgdMOtbmggaOG7hyBz4buRIHTGsMahbmcgcXVhbiBQZWFyc29uIHRyw6puIFI6IGNvcihkZiwgbWV0aG9kID0gInBlYXJzb24iKQ0KDQpgYGB7ciB9DQpjb3IobWFya2V0aW5nLCBtZXRob2QgPSAicGVhcnNvbiIpDQojIENvciBjaG8gaGFpIGJpZW4NCmNvcihtYXJrZXRpbmckZmFjZWJvb2ssbWFya2V0aW5nJHNhbGVzKQ0KYGBgDQoNCiAgICANCiMjIyAyLjIuIEjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gc3BlYXJtYW4NCiAgLSDEkMOhbmggZ2nDoSBt4bupYyDEkeG7mSB0xrDGoW5nIHF1YW4gY+G7p2EgMiBo4bqhbmcgY+G7p2EgMiBiaeG6v24gKHJhbmstb3JkZXJlZCB2YXJpYWJsZXMpLCBz4butIGThu6VuZyAga2hpIHBow6JuIHBo4buRaSBj4bunYSB04buVbmcgdGjhu4MgxJHGsOG7o2MgZ2nhuqMgc+G7rSBraMO0bmcgcGjhuqNpIGzDoCBwaMOibiBwaOG7kWkgY2h14bqpbiBob+G6t2MgdHJvbmcgdHLGsOG7nW5nIGjhu6NwIGPDsyBjw6FjIGdpw6EgdHLhu4sgcXVhbiBzw6F0IGLhuqV0IHRoxrDhu51uZyAobOG7m24gcXXDoSBob+G6t2Mgbmjhu48gcXXDoSkgDQogIA0KICANCiAgLSBDw7RuZyB0aOG7qWMgdMOtbmggdHLDqm4gUjogY29yKGRmLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KICANCiAgDQpgYGB7cn0NCmNvcihtYXJrZXRpbmcsIG1ldGhvZCA9ICJzcGVhcm1hbiIpDQojIENvciBjaG8gaGFpIGJpZW4NCmNvcihtYXJrZXRpbmckeW91dHViZSwgbWFya2V0aW5nJHNhbGVzLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KYGBgDQogICANCiMjIyAyLjMuIEjhu4cgc+G7kSB0xrDGoW5nIHF1YW4ga2VuZGFsbA0KICANCiAgLSBI4buHIHPhu5Ega2VuZGFsbCDDrXQgZMO5bmcgaMahbiBzbyB24bubaSAyIGjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gdHLDqm4NCg0KICAtIEPDtG5nIHRo4bupYyB0w61uaCB0csOqbiBSOiBjb3IoZGYsIG1ldGhvZCA9ICJrZW5kYWxsIikgIA0KICANCmBgYHtyfQ0KY29yKG1hcmtldGluZywgbWV0aG9kID0gImtlbmRhbGwiKQ0KIyBDb3IgY2hvIGhhaSBiaWVuDQpjb3IobWFya2V0aW5nJHlvdXR1YmUsIG1hcmtldGluZyRzYWxlcywgbWV0aG9kID0gImtlbmRhbGwiKQ0KYGBgDQogIA0KIyMjIDIuNC4gS2nhu4NtIMSR4buLbmggdMawxqFuZyBxdWFuDQoNCiAgKiAgQ8WpbmcgbmjGsCBwaMawxqFuZyBwaMOhcCB0w61uaCwga2nhu4NtIMSR4buLbmggY8WpbmcgY8OzIDMgbWV0aG9kOiBQZWFyc29uLCBTcGVhcm1hbiwgS2VuZGFsbA0KICANCiAgKiBHaeG6oyB0aGnhur90IGtp4buDbSDEkeG7i25oOg0KICANCiAgICAgLSBIMDogS2jDtG5nIGPDsyB0xrDGoW5nIHF1YW4gKGjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gPSAwKQ0KICAgICAtIEgxOiBDw7MgdMawxqFuZyBxdWFuDQoNCiAgKiBWw60gZOG7pTogU+G7rSBk4bulbmcgaMOgbSBjb3IudGVzdCANCiAgDQpgYGB7cn0NCmNvci50ZXN0KG1hcmtldGluZyR5b3V0dWJlLCBtYXJrZXRpbmckc2FsZXMpDQpjb3IudGVzdChtYXJrZXRpbmckZmFjZWJvb2ssbWFya2V0aW5nJHNhbGVzKQ0KY29yLnRlc3QobWFya2V0aW5nJG5ld3NwYXBlciwgbWFya2V0aW5nJHNhbGVzKQ0KYGBgDQoNCg0KIyMjIDIuNS5N4buZdCBz4buRIMSR4buTIHRo4buLIHRyb25nIHBow6JuIHTDrWNoIHTGsMahbmcgcXVhbg0KDQogIC0gY29ycnBsb3QgKHBhY2thZ2U6IGNvcnJwbG90KQ0KICANCmBgYHtyfQ0KcmFxTWF0cml4IDwtIGNvcihtYXJrZXRpbmcgJT4lIHNlbGVjdCh5b3V0dWJlLCBmYWNlYm9vaywgDQogICAgICAgICAgICAgICAgIG5ld3NwYXBlciwgc2FsZXMpKQ0KY29ycnBsb3QocmFxTWF0cml4LCBtZXRob2QgPSAiY2lyY2xlIikNCmBgYA0KDQogIC0gYmnhu4N1IMSR4buTIHTGsMahbmcgcXVhbiBnaeG7r2EgY8OhYyBiaeG6v24sIGjDoG0gcGFpcnMucGFuZWxzKCkNCiB0cm9uZyBnw7NpICpwc3ljaCoNCiANCmBgYHtyfQ0KDQpwYWlycy5wYW5lbHMobWFya2V0aW5nKQ0KDQpgYGANCg0KDQojIyAzLiBI4buTaSBxdXkgdHV54bq/biB0w61uaCDEkWEgYmnhur9uDQoNCk3DtCBow6xuaCBo4buTaSBxdXkgYuG7mWkgY8OzIGThuqFuZzogXFtZID0gXGJldGFfezF9ICsgXGJldGFfezJ9WF97Mn0gKyBcYmV0YV97M31YX3szfSArLi4rIFxiZXRhX3trfVhfe2t9ICsgdSBcXQ0KDQoqKlnDqnUgY+G6p3U6KiogeMOieSBk4buxbmcgbcO0IGjDrG5oIGjhu5NpIHF1eSBi4buZaSAobXVsdGlwbGUgcmVncmVzc2lvbikgxJHhu4MgcGjDom4gdMOtY2ggdMOhYyDEkeG7mW5nIGPhu6dhIGPDoWMgaMOsbmggdGjhu6ljIHF14bqjbmcgY8OhbyBsw6puIGRvYW5oIHRodSB2w6AgZGnhu4VuIGdp4bqjaSBr4bq/dCBxdeG6oy4gY+G7pSB0aOG7gzoNCg0KICArIEJp4bq/biBwaOG7pSB0aHXhu5ljOiBkb2FuaCB0aHUgJHNhbGVzJCANCiAgKyBCaeG6v24gxJHhu5ljIGzhuq1wOiAkeW91dHViZSQsICRmYWNlYm9vayQsICRuZXdzcGFwZXIkIGzhuqduIGzGsOG7o3QgbMOgIHPhu5EgdGnhu4FuIGNoaSBjaG8gcXXhuqNuZyBjw6FvIHRyw6puIFlvdXR1YmUsIEZhY2Vib29rIHbDoCB0csOqbiBiw6FvIGNow60gDQoNCiMjIyAzLjEuxq/hu5tjIGzGsOG7o25nIG3DtCBow6xuaCAgDQoNClPhu60gZOG7pW5nIGzhu4duaCAqKmxtKCkqKjoNCg0KYGBge3J9DQptb2RlbC5tYXJrZXRpbmcgPC0gbG0oc2FsZXMgfiB5b3V0dWJlICsgZmFjZWJvb2sgKyBuZXdzcGFwZXIsIGRhdGEgPSBtYXJrZXRpbmcpDQpzdW1tYXJ5KG1vZGVsLm1hcmtldGluZykNCmBgYA0KDQpWw6wgYmnhur9uICRuZXdzcGFwZXIkIGtow7RuZyBjw7Mgw70gbmdoxKlhIHRyb25nIG3DtCBow6xuaCBo4buTaSBxdXkgYuG7mWkgxJHGsOG7o2MgeMOieSBk4buxbmcsIHRhIGPDsyB0aOG7gyBsb+G6oWkgYuG7jyBiaeG6v24gbsOgeSB2w6AgeMOieSBk4buxbmcgbOG6oWkgbcO0IGjDrG5oIGjhu5NpIHF1eSBi4buZaSBjaOG7iSB24bubaSBoYWkgYmnhur9uICR5b3V0dWJlJCB2w6AgJGZhY2Vib29rJDogDQpgYGB7cn0NCm1vZGVsMi5tYXJrZXRpbmcgPC0gbG0oc2FsZXMgfiB5b3V0dWJlICsgZmFjZWJvb2ssIGRhdGEgPSBtYXJrZXRpbmcpDQpzdW1tYXJ5KG1vZGVsMi5tYXJrZXRpbmcpIA0KYGBgDQoNCkjhu4cgc+G7kSAkUl4yJCBoaeG7h3UgY2jhu4luaCBi4bqxbmcgJDAuOTg1NyQgbmdoxKlhIGzDoCAkOTguNTdcJSQgc+G7sSBiaeG6v24gdGhpw6puIHRyb25nIGRvYW5oIHRodSAkc2FsZXMkIMSRxrDhu6NjIGdp4bqjaSB0aMOtY2ggYuG7n2kgY8OhYyBiaeG6v24gJHlvdXR1YmUkIHbDoCAkZmFjZWJvb2skIHThu6ljIGzDoCBjaGkgcGjDrSBjaGkgY2hvIHZp4buHYyBxdeG6o25nIGPDoW8gdHLDqm4gRmFjZWJvb2sgdsOgIFlvdXR1YmUuIA0KDQojIyMgMy4yLiBUw6xtIGtob+G6o25nIHRpbiBj4bqteSBjaG8gY8OhYyBo4buHIHPhu5EgaOG7k2kgcXV5DQoNClPhu60gZOG7pW5nIGjDoG0gKipjb25maW50KCkqKjoNCg0KYGBge3J9DQpjb25maW50KG1vZGVsMi5tYXJrZXRpbmcpICMgZG8gdGluIGNheSA9IDk1JQ0KY29uZmludChtb2RlbDIubWFya2V0aW5nLCBsZXZlbCA9IDAuOTkpICMgZG8gdGluIGNheSA9IDk5JQ0KYGBgDQoNCg0KIyMjIDMuMy4gS2nhu4NtIMSR4buLbmggdsOgIGzhu7FhIGNo4buNbiBtw7QgaMOsbmgNCg0KTmjhuq9jIGzhuqFpIG3hu5l0IHPhu5EgZ2nhuqMgdGhp4bq/dCBj4bunYSBtw7QgaMOsbmggaOG7k2kgcXV5DQoNCiAgMSkgKipUw61uaCB0dXnhur9uIHTDrW5oIGPhu6dhIGThu68gbGnhu4d1KioNCiAgMikgKipQaOG6p24gZMawIGPDsyBwaMOibiBwaOG7kWkgY2h14bqpbioqIA0KICAzKSAqKlBo4bqnbiBkxrAgY8OzIHRydW5nIGLDrG5oIGLhurFuZyAwKioNCiAgNCkgKipQaMawxqFuZyBzYWkgY+G7p2EgcGjhuqduIGTGsCBsw6Aga2jDtG5nIMSR4buVaSoqICANCiAgDQogIA0KDQojIyMgMy4zLjEgROG7sWEgdsOgbyDEkeG7kyB0aOG7iyBwaOG6p24gZMawDQoNCmBgYHtyfQ0KcGFyKG1mcm93ID0gYygyLCAyKSkNCnBsb3QobW9kZWwyLm1hcmtldGluZykNCnBhcihvcCkNCg0KYGBgDQorIMSQ4buTIHRo4buLIHRo4bupIDEgKCpSZXNpZHVhbHMgdnMgRml0dGVkKikgRMO5bmcgxJHhu4Mga2nhu4NtIHRyYSBnaeG6oyB0aGnhur90IHR1eeG6v24gdMOtbmggY+G7p2EgZOG7ryBsaeG7h3UgdsOgIGdp4bqjIHRoaeG6v3QgcGjhuqduIGTGsCBjw7MgdHJ1bmcgYsOsbmggYuG6sW5nIDANCg0KVHLhu6VjIHR1bmcgYmnhu4N1IHRo4buLIGdpw6EgdHLhu4sgY+G7p2EgcGjhuqduIGTGsCwgdHLhu6VjIGhvw6BuaCBiaeG7g3UgdGjhu4sgZ2nDoSB0cuG7iyB0acOqbiBsxrDhu6NuZyAoJFxoYXQgeV9pJCkgY+G7p2EgYmnhur9uIHBo4bulIHRodeG7mWMuIE7hur91IG5oxrAgZ2nhuqMgdGhp4bq/dCB24buBIHTDrW5oIHR1eeG6v24gdMOtbmggY+G7p2EgZOG7ryBsaeG7h3UgKipLSMOUTkcqKiB0aOG7j2EsIHRhIHPhur0gcXVhbiBzw6F0IHRo4bqleSBy4bqxbmcgxJHGsOG7nW5nIG3DoHUgxJHhu48gdHLDqm4gxJHhu5MgdGjhu4sgc+G6vSBwaMOibiBi4buRIHRoZW8gbeG7mXQgaMOsbmggbeG6q3UgKHBhdHRlcm4pIMSR4bq3YyB0csawbmcgbsOgbyDEkcOzICh2w60gZOG7pSBwYXJhYm9sKS4gTuG6v3UgxJHGsOG7nW5nIG3DoHUgxJHhu48gdHLDqm4gxJHhu5MgdGjhu4sgcGjDom4gdMOhbiBsw6AgxJHGsOG7nW5nIHRo4bqzbmcgbuG6sW0gbmdhbmcgbcOgIGtow7RuZyBwaOG6o2kgbMOgIMSRxrDhu51uZyBjb25nLCB0aMOsIGdp4bqjIHRoaeG6v3QgdMOtbmggdHV54bq/biB0w61uaCBj4bunYSBk4buvIGxp4buHdSDEkcaw4bujYyB0aOG7j2EgbcOjbi4gR2nhuqMgdGhp4bq/dCBwaOG6p24gZMawIGPDsyB0cnVuZyBiw6xuaCBi4bqxbmcgMCB0aOG7j2EgbcOjbiBu4bq/dSDEkcaw4budbmcgbcOgdSDEkeG7jyBn4bqnbiB24bubaSDEkcaw4budbmcgbuG6sW0gbmdhbmcgKOG7qW5nIHbhu5tpIHBo4bqnbiBkxrAgPTApLg0KDQorIMSQ4buTIHRo4buLIHRo4bupIDIgKCpOb3JtYWwgUS1RKikgRMO5bmcgxJHhu4Mga2nhu4NtIHRyYSBnaeG6oyB0aGnhur90IHBo4bqnbiBkxrAgY8OzIHBow6JuIHBo4buRaSBjaHXhuqluDQoNCk7hur91IGPDoWMgxJFp4buDbSB0aOG6t25nIGTGsCBu4bqxbSB0csOqbiBjw7luZyAxIMSRxrDhu51uZyB0aOG6s25nIHRow6wgxJFp4buBdSBraeG7h24gduG7gSBwaMOibiBwaOG7kWkgY2h14bqpbiDEkcaw4bujYyB0aOG7j2EuIA0KDQorIMSQ4buTIHRo4buLIHRo4bupIDMgKCpTY2FsZSAtIExvY2F0aW9uKikgRMO5bmcgxJHhu4Mga2nhu4NtIMSR4buLbmggZ2nhuqMgdGhp4bq/dCBwaMawxqFuZyBzYWkgY+G7p2EgcGjhuqduIGTGsCBsw6Aga2jDtG5nIMSR4buVaQ0KDQpUcuG7pWMgdHVuZyBsw6AgY8SDbiBi4bqtYyBoYWkgY+G7p2EgZ2nDoSB0cuG7iyBj4bunYSBwaOG6p24gZMawICjEkcOjIMSRxrDhu6NjIGNodeG6qW4gaMOzYSksIHRy4bulYyBob8OgbmggbMOgIGdpw6EgdHLhu4sgdGnDqm4gbMaw4bujbmcgKCRcaGF0IHlfaSQpIGPhu6dhIGJp4bq/biBwaOG7pSB0aHXhu5ljIHThu6sgbcO0IGjDrG5oLiBO4bq/dSBuaMawIMSRxrDhu51uZyBtw6B1IMSR4buPIHRyw6puIMSR4buTIHRo4buLIGzDoCDEkcaw4budbmcgdGjhurNuZyBu4bqxbSBuZ2FuZyB2w6AgY8OhYyDEkWnhu4NtIHRo4bq3bmcgZMawIHBow6JuIHTDoW4gxJHhu4F1IHh1bmcgcXVhbmggxJHGsOG7nW5nIHRo4bqzbmcgbsOgeSB0aMOsIGdp4bqjIHRoaeG6v3QgdGjhu6kgNCDEkcaw4bujYyB0aOG7j2EuIE7hur91IG5oxrAgxJHGsOG7nW5nIG3DoHUgxJHhu48gY8OzIMSR4buZIGThu5FjIChob+G6t2MgY29uZykgaG/hurdjIGPDoWMgxJFp4buDbSB0aOG6t25nIGTGsCBwaMOibiB0w6FuIGtow7RuZyDEkeG7gXUgeHVuZyBxdWFuaCDEkcaw4budbmcgdGjhurNuZyBuw6B5LCB0aMOsIGdp4bqjIHRoaeG6v3QgbsOgeSBi4buLIHZpIHBo4bqhbS4gDQoNCisgxJDhu5MgdGjhu4sgdGjhu6kgNCAoKlJlc2lkdWFscyB2cyBMZXZlcmFnZSopIGNobyBwaMOpcCB4w6FjIMSR4buLbmggbmjhu69uZyDEkWnhu4NtIGPDsyDhuqNuaCBoxrDhu59uZyBjYW8gKCppbmZsdWVudGlhbCBvYnNlcnZhdGlvbnMqKSwgbuG6v3UgY2jDum5nIGPDsyBoaeG7h24gZGnhu4duIHRyb25nIGLhu5kgZOG7ryBsaeG7h3UuIE5o4buvbmcgxJFp4buDbSBjw7Mg4bqjbmggaMaw4bufbmcgY2FvIG7DoHkgY8OzIHRo4buDIGzDoCBjw6FjIMSRaeG7g20gb3V0bGllcnMsIGzDoCBuaOG7r25nIMSRaeG7g20gY8OzIHRo4buDIGfDonkgbmhp4buBdSDhuqNuaCBoxrDhu59uZyBuaOG6pXQga2hpIHBow6JuIHTDrWNoIGThu68gbGnhu4d1LiBO4bq/dSBuaMawIHRhIHF1YW4gc8OhdCB0aOG6pXkgbeG7mXQgxJHGsOG7nW5nIHRo4bqzbmcgbcOgdSDEkeG7jyDEkeG7qXQgbsOpdCAoW0Nvb2sncyBkaXN0YW5jZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29vayUyN3NfZGlzdGFuY2UpKSwgdsOgIGPDsyBt4buZdCBz4buRIMSRaeG7g20gdsaw4bujdCBxdWEgxJHGsOG7nW5nIHRo4bqzbmcga2hv4bqjbmcgY8OhY2ggbsOgeSwgbmdoxKlhIGzDoCBjw6FjIMSRaeG7g20gxJHDsyBsw6AgY8OhYyDEkWnhu4NtIGPDsyDhuqNuaCBoxrDhu59uZyBjYW8uIE7hur91IG5oxrAgdGEgY2jhu4kgcXVhbiBzw6F0IHRo4bqleSDEkcaw4budbmcgdGjhurNuZyBraG/huqNuZyBjw6FjaCBDb29rIOG7nyBnw7NjIGPhu6dhIMSR4buTIHRo4buLIHbDoCBraMO0bmcgY8OzIMSRaeG7g20gbsOgbyB2xrDhu6N0IHF1YSBuw7MsIG5naMSpYSBraMO0bmcgY8OzIMSRaeG7g20gbsOgbyB0aOG7sWMgc+G7sSBjw7Mg4bqjbmggaMaw4bufbmcgY2FvLg0KDQoqKk5o4bqtbiB4w6l0OioqDQoNCiAgKyDEkOG7kyB0aOG7iyB0aOG7qSAxICgqUmVzaWR1YWxzIHZzIEZpdHRlZCopIGNobyB0aOG6pXkgZ2nhuqMgdGhp4bq/dCB24buBIHTDrW5oIHR1eeG6v24gdMOtbmggY+G7p2EgZOG7ryBsaeG7h3UgaMahaSBi4buLIHZpIHBo4bqhbS4gVHV5IG5oacOqbiBnaeG6oyB0aGnhur90IHRydW5nIGLDrG5oIGPhu6dhIHBo4bqnbiBkxrAgY8OzIHRo4buDIGNvaSBsw6AgdGjhu49hIG3Do24NCiAgKyDEkOG7kyB0aOG7iyAqTm9ybWFsIFEtUSogY2hvIHRo4bqleSBnaeG6oyB0aGnhur90IHBo4bqnbiBkxrAgY8OzIHBow6JuIHBo4buRaSBjaHXhuqluIMSRxrDhu6NjIHRo4buPYSBtw6NuLiANCiAgKyDEkOG7kyB0aOG7iyAoKlNjYWxlIC0gTG9jYXRpb24qKSBjaG8gdGEgdGjhuqV5IHLhurFuZyBnaeG6oyB0aGnhur90IHbhu4EgdMOtbmggxJHhu5NuZyBuaOG6pXQgY+G7p2EgcGjGsMahbmcgc2FpIGPFqW5nIHRo4buPYSBtw6NuLiANCiAgKyDEkOG7kyB0aOG7iyB0aOG7qSB0xrAgY2jhu4kgcmEgY8OzIGPDoWMgcXVhbiB0cuG6r2MgdGjhu6kgNDIsIDEyNCB2w6AgMTQzIGPDsyB0aOG7gyBsw6AgY8OhYyDEkWnhu4NtIGPDsyDhuqNuaCBoxrDhu59uZyBjYW8gdHJvbmcgYuG7mSBk4buvIGxp4buHdS4gDQogIA0KDQrEkOG7gyB24bq9IHThu6tuZyDEkeG7kyB0aOG7iywgdGEgZMO5bmcgY8OhYyBs4buHbmggc2F1Og0KDQpgYGB7cn0NCnBsb3QobW9kZWwyLm1hcmtldGluZywgMSkNCmBgYA0KDQpgYGB7cn0NCnBsb3QobW9kZWwyLm1hcmtldGluZywgMikNCmBgYA0KDQpgYGB7cn0NCnBsb3QobW9kZWwyLm1hcmtldGluZywgMykNCmBgYA0KDQpgYGB7cn0NCnBsb3QobW9kZWwyLm1hcmtldGluZywgNSkNCmBgYA0KICANCg0KIyMjIDMuMy4yIEThu7FhIHbDoG8gY8OhYyBraeG7g20gxJHhu4tuaA0KDQpgYGB7cn0NCnJlIDwtIHJlc2lkKG1vZGVsMi5tYXJrZXRpbmcpDQpgYGANCg0KIyMjIEdp4bqjIHRoaeG6v3QgMTogU2FpIHPhu5Egbmfhuqt1IG5oacOqbiBjw7MgcGjDom4gcGjhu5FpIGNodeG6qW4NCg0KR2nhuqMgdGhp4bq/dCBraeG7g20gxJHhu4tuaDoNCiAgDQogICAgIC0gSDA6IEThu68gbGnhu4d1IGPDsyBwaMOibiBwaOG7kWkgY2h14bqpbg0KICAgICAtIEgxOiBE4buvIGxp4buHdSBraMO0bmcgY8OzIHBow6JuIHBo4buRaSBjaHXhuqluDQoNCmBgYHtyfQ0Kc2hhcGlyby50ZXN0KHJlKQ0KYGBgDQoNCnAtdmFsdWUgPTAuNjc2IG7Dqm4gcGjhuqduIGTGsCBjw7MgcGjDom4gcGjhu5FpIGNodeG6qW4NCg0KIyMjIEdp4bqjIHRoaeG6v3QgMjogS+G7syB24buNbmcgY+G7p2Egc2FpIHPhu5Egbmfhuqt1IG5oacOqbiB04bqhaSBt4buXaSBnacOhIHRy4buLIGLhurFuZyAwDQoNCmBgYHtyfQ0KDQp0LnRlc3QocmUsIG11ID0gMCkNCmBgYA0KDQpwLXZhbHVlID0gMSwgZG8gZG8gbcO0IGjDrG5oIHRo4buPYSBtw6NuIGdp4bqjIHRoaeG6v3QgMg0KDQojIyMgR2nhuqMgdGhp4bq/dCAzOiBQaMawxqFuZyBzYWkgY+G7p2Egc2FpIHPhu5Egbmfhuqt1IG5oacOqbiBraMO0bmcgxJHhu5VpIA0KSDA6IHBoxrDGoW5nIHNhaSBzYWkgc+G7kSBraMO0bmcgxJHhu5VpDQoNCkgxOiBQaMawxqFuZyBzYWkgc2FpIHPhu5EgdGhheSDEkeG7lWkNCg0KYGBge3J9DQpuY3ZUZXN0KG1vZGVsMi5tYXJrZXRpbmcpDQpgYGANCg0KcC12YWx1ZSA9IDAuNjI0LCBjw7MgdGjhu4Mga+G6v3QgbHXhuq1uIHBoxrDGoW5nIHNhaSBzYWkgc+G7kSBsw6Aga2jDtG5nIMSR4buVaS4NCg0KIyMjIEdp4bqjIHRoaeG6v3QgNDogR2nhu69hIGPDoWMgYmnhur9uIMSR4buZYyBs4bqtcCBraMO0bmcgY8OzIG3hu5FpIHF1YW4gaOG7hyDEkWEgY+G7mW5nIHR1eeG6v24gaG/DoG4gaOG6o28NCg0KJFZJRl9qID0gIFxmcmFjIHsxfSB7MS1SX2peMn0kDQoNCiRSX2peMiQgbMOgIGjhu4cgc+G7kSB4w6FjIMSR4buLbmggY+G7p2EgbcO0IGjDrG5oIGjhu5NpIHF1aSB0dXnhur9uIHTDrW5oIHBo4bulIGPhu6dhIGJp4bq/biDEkeG7mWMgbOG6rXAgJFhfaiQgdGhlbyBjw6FjIGJp4bq/biDEkeG7mWMgbOG6rXAgY8OybiBs4bqhaSBj4bunYSBtw7QgaMOsbmguDQoNCmBgYHtyfQ0KdmlmKG1vZGVsMi5tYXJrZXRpbmcpDQpgYGANCg0KdmlmIDwgMTAgY2hvIHRo4bqleSBjw6FjIGJp4bq/biDEkeG7mWMgbOG6rXAga2jDtG5nIGPDsyDEkWEgY+G7mW5nIHR1eeG6v24NCg0KIyMjIDMuNC4gROG7sSBiw6FvDQoNCmBgYHtyfQ0KeW91dHViZSA8LSBjKDU3LCA2MCwgNTUuNSwgMTE3LCA5OCwgNjksIDEwMCwgMTUwLCAyMDAsIDEyNSwgMTcwLCAxOTUsIDI3MCwgMTk4KQ0KZmFjZWJvb2sgPC0gYygxMCwgMTUuNywgNTAsIDc2LCAyNC44LCAyMDAsIDE5OCwgMTUwLCA5OS44LCA3Ni41LCA0NS40LCAxODcsIDc4LjMsIDIwMCkNCm5ldyA8LSBkYXRhLmZyYW1lKHlvdXR1YmUsIGZhY2Vib29rKQ0KYGBgDQoNCkThu7EgYsOhbyBnacOhIHRy4buLIHRydW5nIGLDrG5oDQoNCmBgYHtyfQ0KDQpwcmVkaWN0KG1vZGVsMi5tYXJrZXRpbmcgLCBuZXdkYXRhID0gbmV3LCBpbnRlcnZhbCA9ICJjb25maWRlbmNlIikNCmBgYA0KDQpE4buxIGLDoW8gZ2nDoSB0cuG7iyBjw6EgYmnhu4d0DQoNCmBgYHtyfQ0KcHJlZGljdChtb2RlbDIubWFya2V0aW5nICwgbmV3ZGF0YSA9IG5ldywgaW50ZXJ2YWwgPSAicHJlZGljdGlvbiIpDQpgYGANCg0KIyMjIDMuNS4gWHXhuqV0IGvhur90IHF14bqjIGjhu4cgc+G7kSBo4buTaSBxdXkNCg0KWHXhuqV0IGLhuqNuZyBo4buTaSBxdXkgZOG6oW5nIHRleCwgY2hvIGLDoW8gY8OhbyBmaWxlIFdvcmQNCmBgYHtyfQ0Kc3RhcmdhemVyKG1vZGVsMi5tYXJrZXRpbmcsIHR5cGUgPSAidGV4dCIpDQpgYGANCg0KDQpYdeG6pXQgYuG6o25nIGjhu5NpIHF1eSBk4bqhbmcgdGV4LCBjaG8gYsOhbyBjw6FvIGZpbGUgbGF0ZXguDQpgYGB7cn0NCnN0YXJnYXplcihtb2RlbDIubWFya2V0aW5nLCB0eXBlID0gImxhdGV4IikNCmBgYA0KDQoNCg0KDQpUUsOCTiBUUuG7jE5HIE3hu5xJIMSQ4bqgSSBCSeG7glUgVEhBTSBE4buwIFbDgCBUUsOCTiBUUuG7jE5HIEPhuqJNIMagTiENCg0K