BÀI TẬP 1: TÓM TẮT CUỐN SÁCH “Generalized Linear Models With Examples in R (2019)”

Dưới đây là bản tóm tắt cuốn sách “Generalized Linear Models With Examples in R” (2019) của Peter K. Dunn và Gordon K. Smyth, một tài liệu rất có giá trị cho những người học hoặc ứng dụng Generalized Linear Models (GLM), đặc biệt là với ngôn ngữ R.

CHƯƠNG 1: MÔ HÌNH THỐNG KÊ (STATISTICAL MODELS)

1.1 Giới thiệu

Mô hình thống kê được hiểu là công cụ để mô tả và lý giải dữ liệu. GLMs là một lớp con của mô hình hồi quy, cho phép mô hình hóa nhiều dạng phân phối khác nhau ngoài chuẩn.

1.2 Cách mô tả dữ liệu

Ví dụ 1.1: Dữ liệu dung tích phổi của thanh thiếu niên

  • Dữ liệu từ 654 thanh thiếu niên ở Boston;

  • Biến: tuổi, dung tích phổi (FEV), chiều cao, giới tính, tình trạng hút thuốc.

Mã R: library(GLMsData) data(lungcap) head(lungcap)

Kết quả: dữ liệu gồm các biến Age, FEV, Ht, Gender, Smoke.

1.3 Vẽ đồ thị

  • Việc vẽ đồ thị giúp khám phá đặc điểm của dữ liệu.

  • Dùng R để biểu diễn mối quan hệ giữa biến độc lập và biến phản hồi.

Ví dụ mã R: plot(FEV ~ Age, data=lungcap)

1.4 Mã hóa biến phân loại

  • Biến phân loại như Gender cần mã hóa (dùng dummy variables) để đưa vào mô hình.

  • R sử dụng treatment coding làm mặc định.

lungcap$Gender <- factor(lungcap$Gender) contrasts(lungcap$Gender)

1.5 Thành phần của mô hình thống kê

  • Thành phần hệ thống (systematic component): biến giải thích, kết hợp tuyến tính.

  • Thành phần ngẫu nhiên (random component): mô tả sự biến đổi không giải thích được.

1.6 Giới thiệu mô hình hồi quy

  • Mô hình hồi quy tuyến tính là trường hợp đặc biệt: $$Y_i = \beta_0 + \beta_1 X_i + \epsilon_i$$

  • Tất cả các mô hình trong sách đều là mô hình hồi quy.

1.7 Giải thích mô hình hồi quy

  • Cần hiểu ý nghĩa thống kê và thực nghiệm của các tham số trong mô hình.

1.8 – 1.12 Các chủ đề triết lý và thực hành

  • “Tất cả mô hình đều sai, nhưng một số thì hữu ích” (Box & Draper);

  • Mục đích của mô hình: hiểu dữ liệu hoặc dự đoán;

  • Đánh giá mô hình dựa trên tính chính xác (accuracy) và sự đơn giản (parsimony);

  • So sánh dữ liệu quan sát và dữ liệu thực nghiệm;

  • Tổng quát hóa kết quả từ mẫu đến quần thể.

1.13: Giới thiệu về sử dụng R

  • R là công cụ chính để xây dựng mô hình thống kê;

  • Các chức năng như lm(), plot(), summary() được sử dụng xuyên suốt.

BÀI TẬP & MÃ R THỰC HÀNH

Ví dụ với dữ liệu crabs: library(GLMsData) data(hcrabs) summary(hcrabs) plot(y ~ weight, data = hcrabs)

  • Yêu cầu xác định loại biến, xử lý biến phân loại, kiểm tra tính phù hợp của hồi quy tuyến tính vs. GLM.

Kết luận chương 1

Chương 1 đóng vai trò định hướng tri thức nền tảng về mô hình hóa thống kê, nhấn mạnh tư duy phân tích dữ liệu, hiểu đặc tính dữ liệu và chuẩn bị cho các chương về GLMs.

CHƯƠNG 2: MÔ HÌNH HỒI QUY TUYẾN TÍNH (LINEAR REGRESSION MODELS)

2.1 Giới thiệu tổng quan

  • Hồi quy tuyến tính là mô hình phổ biến nhất trong thống kê.

  • Mô hình hồi quy tuyến tính là trường hợp đặc biệt của GLM với phân phối chuẩn và hàm liên kết là hàm đồng nhất.

2.2 Định nghĩa mô hình hồi quy tuyến tính

Mô hình hồi quy tuyến tính có hai thành phần:

  • Ngẫu nhiên: $$\operatorname{Var}(y_i) = \frac{\sigma^2}{w_i}$$ với \(w_i\) là trọng số.

  • Hệ thống: $$\mu_i = \beta_0 + \sum_{j=1}^{p} \beta_j x_{ij}$$

  • Biểu diễn tổng quát: $$\begin{cases}\operatorname{Var}(y_i) = \frac{\sigma^2}{w_i} \\\mu_i = \beta_0 + \beta_1 x_{i1} + \cdots + \beta_p x_{ip}\end{cases}$$

2.3 Ước lượng bình phương tối thiểu (OLS) – hồi quy đơn

  • Giải pháp cổ điển để ước lượng các hệ số hồi quy;

  • Dễ tính toán, giải tích rõ ràng;

  • Tối thiểu hóa tổng bình phương sai số.

Ví dụ mã R: model <- lm(FEV ~ Age, data = lungcap) summary(model)

2.4 & 2.5 Hồi quy tuyến tính bội

  • Mở rộng từ hồi quy đơn sang nhiều biến giải thích.

  • Có thể bao gồm biến định tính thông qua biến giả (dummy).

  • Khuyến nghị kiểm tra tương quan, đa cộng tuyến.

Ví dụ mã R: model2 <- lm(FEV ~ Age + Ht + Gender + Smoke, data = lungcap) summary(model2)

2.6 Sử dụng R để ước lượng mô hình

  • Hàm lm() để ước lượng;

  • Các hàm plot(), residuals(), fitted(), anova() để kiểm tra chẩn đoán.

Mã ví dụ: plot(residuals(model) ~ fitted(model))

2.7 Giải thích mô hình hồi quy

  • Mỗi hệ số \(βj​\) thể hiện thay đổi kỳ vọng của \(y\) ứng với một đơn vị thay đổi của \(x_j\) , giữ nguyên các biến khác.

  • Quan trọng trong việc suy luận thực nghiệm từ kết quả thống kê.

2.8 Suy luận thống kê

  • Kiểm định giả thuyết: \(H_0:βj=0\)

  • Khoảng tin cậy cho từng hệ số.

Mã R: confint(model)

2.9 Phân tích phương sai (ANOVA)

  • Kiểm tra tổng quát xem mô hình có ý nghĩa thống kê không.

  • Bảng ANOVA giúp kiểm tra ảnh hưởng của từng nhóm biến giải thích.

2.10 So sánh mô hình lồng nhau

  • Dùng kiểm định F hoặc kiểm định Deviance để so sánh mô hình tổng quát và mô hình con.

2.11 So sánh mô hình không lồng nhau

  • Sử dụng tiêu chí lựa chọn mô hình: AIC và BIC.

2.12 Lựa chọn mô hình

  • Các chiến lược như lựa chọn tiến, lùi, hoặc từng bước.

  • R hỗ trợ hàm step() để tự động hóa.

Mã R: step(model2)

Tổng kết chương

Chương này xây dựng nền tảng toán học và lập trình cho hồi quy tuyến tính, từ đó mở đường cho việc học và ứng dụng GLMs. Nó cũng chỉ ra rõ:

  • Sức mạnh mô hình tuyến tính;

  • Các giới hạn về giả định phân phối chuẩn và phương sai không đổi;

Cách dùng R để mô hình hóa thực tế và kiểm tra mô hình.

CHƯƠNG 3: PHÂN TÍCH PHƯƠNG SAI (ANOVA)

3.1 Giới thiệu

  • ANOVA (Analysis of Variance) được trình bày như một trường hợp đặc biệt của mô hình hồi quy tuyến tính.

  • ANOVA dùng để kiểm tra xem trung bình của nhiều nhóm có khác biệt thống kê hay không.

3.2 Mô hình ANOVA một yếu tố

  • Mô hình hóa ảnh hưởng của một yếu tố phân loại (categorical factor) đến biến phản hồi.

  • Ví dụ: So sánh trung bình điểm thi của các lớp học khác nhau.

  • Biểu thức mô hình:

\[ Y_{ij} = \mu + \alpha_i + \epsilon_{ij}, \quad \epsilon_{ij} \sim \mathcal{N}(0, \sigma^2) \]

Mã R: mô hình hóa ANOVA một chiều

model1 <- lm(FEV ~ Group, data = lungcap) anova(model1)

3.3 Mã hóa biến phân loại

  • Mặc định trong R là treatment coding: nhóm đầu tiên là tham chiếu (reference group).

  • Có thể thay đổi cách mã hóa bằng contrasts().

Ví dụ kiểm tra mã hóa: contrasts(lungcap$Group)

3.4 ANOVA nhiều yếu tố

  • Mở rộng mô hình để xét đồng thời nhiều yếu tố.

  • Bao gồm mô hình tương tác nếu giả thuyết về ảnh hưởng độc lập không đúng.

Mã R: model2 <- lm(FEV ~ Gender * Smoke, data = lungcap) anova(model2)

3.5 Phân tích bảng ANOVA

  • Phân tích phương sai chia tổng phương sai thành các thành phần:

    • Giữa nhóm (between-group),

    • Trong nhóm (within-group / residual),

    • Kiểm định bằng F-test.

Bảng ANOVA mẫu: anova(model2) summary(model2)

3.6 Hiệu ứng chính và tương tác

  • Tương tác cho biết ảnh hưởng của một yếu tố thay đổi theo cấp độ của yếu tố khác.

  • Quan sát thông qua biểu đồ hoặc kiểm định mô hình có tương tác.

3.7 So sánh nhiều nhóm

  • Sau khi phát hiện sự khác biệt toàn cục bằng ANOVA, dùng các kiểm định so sánh từng cặp (post-hoc tests), ví dụ:

    • Tukey’s HSD.

    • Bonferroni.

Mã R ví dụ: Tukey HSD

TukeyHSD(aov(model1))

3.8 Kết nối giữa ANOVA và hồi quy

  • ANOVA là một trường hợp của mô hình hồi quy tuyến tính với biến phân loại.

  • Các hệ số hồi quy biểu diễn sự khác biệt giữa nhóm với nhóm tham chiếu.

Tổng kết chương

  • ANOVA được khái quát thành mô hình hồi quy, tạo cơ sở để hiểu GLMs.

  • Quan trọng trong phân tích thiết kế thí nghiệm.

R cung cấp công cụ mạnh mẽ để xây dựng và giải thích mô hình ANOVA với lm()aov().

CHƯƠNG 4: ƯỚC LƯỢNG HỢP LÝ CỰC ĐẠI (MAXIMUM LIKELIHOOD ESTIMATION - MLE)

4.1 Giới thiệu

  • Trình bày phương pháp ước lượng hợp lý cực đại (MLE) như là nền tảng thống kê hiện đại để ước lượng các tham số mô hình.

  • MLE là phương pháp chủ yếu dùng trong GLMs để ước lượng các tham số β và các tham số phương sai/phân tán (φ).

4.2–4.4 Tổng quát hóa mô hình hồi quy tuyến tính

  • Từ mô hình hồi quy tuyến tính (OLS), tổng quát hóa bằng cách thay giả định phân phối chuẩn sang bất kỳ phân phối nào trong họ hàm mũ.

  • Dẫn nhập khái niệm hàm hợp lý (likelihood) và vai trò trong thống kê suy luận.

4.5 Ước lượng một tham số bằng MLE

  • Thiết lập phương trình điểm (score equations): đạo hàm log-likelihood theo tham số.

  • Ma trận thông tin Fisher: đo độ chính xác của ước lượng.

  • Ước lượng sai số chuẩn dựa trên ma trận thông tin.

Mã R đơn giản:

# Mô phỏng likelihood cho phân phối Bernoulli theta <- seq(0.01, 0.99, length=100) lik <- dbinom(7, size=10, prob=theta) plot(theta, lik, type="l", main="Likelihood function")

4.6 Ước lượng nhiều tham số

  • Xử lý mô hình với nhiều tham số bằng cách sử dụng đạo hàm riêngtối ưu hóa hàm log-likelihood đa biến.

4.7 MLE bằng đại số ma trận

  • Biểu diễn phương trình điểm và ma trận thông tin bằng đại số ma trận để dễ tổng quát và triển khai trên máy tính.

  • Chuẩn bị cho thuật toán Fisher scoring trong GLMs.

4.8 Fisher Scoring để tính MLE

  • Thuật toán lặp để tìm nghiệm phương trình điểm.

  • Dễ cài đặt trong phần mềm thống kê và chính là nền tảng của hàm glm() trong R.

4.9 Tính chất của MLE

  • Không chệch tiệm cận, hiệu quả, phân phối chuẩn hóa khi mẫu lớn.

  • Giải thích rõ vai trò của số lượng mẫu lớn (asymptotics) trong thống kê hiện đại.

4.10 Kiểm định giả thuyết

  • Giới thiệu ba loại kiểm định thống kê từ MLE:

    • Wald test

    • Likelihood Ratio test (LRT)

    • Score test

  • Mỗi loại có ưu/nhược điểm khác nhau tùy vào bài toán.

4.11 Khoảng tin cậy

  • Xây dựng khoảng tin cậy cho từng tham số dựa vào phân phối xấp xỉ chuẩn và ma trận thông tin.

4.12 So sánh mô hình không lồng nhau

  • Giới thiệu tiêu chí:

    • AIC (Akaike Information Criterion)

    • BIC (Bayesian Information Criterion)

  • Phù hợp để lựa chọn mô hình trong GLMs.

4.13 Phụ lục: Mã R áp dụng cho dữ liệu mưa Quilpie

Ví dụ mã R:

MakeMu <- function(x, beta){ eta <- x %*% beta return(1 / (1 + exp(-eta))) } MakeScore <- function(x, y, beta){ mu <- MakeMu(x, beta) return(t(x) %*% (y - mu)) }

  • Mã R tự xây dựng lại toàn bộ thuật toán MLE cho logistic regression.

  • Minh họa cho quá trình thủ công tính toán MLE, chuẩn bị cho việc dùng hàm glm() ở các chương sau.

Kết luận chương

  • MLE là cơ sở cho tất cả các mô hình GLM: mô hình hóa tổng quát, kiểm định, và chọn mô hình đều dựa vào nguyên lý hợp lý cực đại.

  • Chương 4 là bước chuyển từ hồi quy tuyến tính cổ điển sang các phương pháp hiện đại và khái quát hơn của GLMs.

  • Được hỗ trợ mạnh mẽ bằng các hàm và gói R, đặc biệt là glm().

CHƯƠNG 5: CẤU TRÚC CỦA MÔ HÌNH TUYẾN TÍNH TỔNG QUÁT (GLMs: STRUCTURE)

5.1 Giới thiệu

  • Chuyển tiếp từ hồi quy tuyến tính (giả định phương sai hằng số) sang GLM cho phép xử lý dữ liệu phi chuẩn và phương sai thay đổi.

  • GLM được xây dựng từ hai thành phần chính:

    • Thành phần ngẫu nhiên (random component);

    • Thành phần hệ thống (systematic component).

5.2 Hai thành phần chính của GLM

  1. Ngẫu nhiên: Chọn phân phối xác suất phù hợp (thường thuộc họ Exponential Dispersion Models - EDMs).

  2. Hệ thống: Sử dụng kết hợp tuyến tính với hàm liên kết g(μ)=ηg() = (μ)=η, trong đó η=Xβ= X=Xβ.

5.3 Thành phần ngẫu nhiên: EDMs

  • GLM giả định yi∼EDM(μi,ϕ/wi)y_i (_i, /w_i)yi​∼EDM(μi​,ϕ/wi​).

  • EDM bao gồm: Phân phối chuẩn, Poisson, nhị thức, gamma, inverse Gaussian, negative binomial,…

  • Hàm xác suất có dạng:

    Biểu thức phân phối thuộc họ hàm mũ:

    \[ P(y; \theta, \phi) = a(y, \phi)\exp\left\{\frac{y\theta - \kappa(\theta)}{\phi}\right\} \]

  • Hàm tạo khoảnh khắc, hàm tích lũy (cumulant), và hàm phương sai đóng vai trò quan trọng để suy luận.

5.4 Dạng phân tán của EDM

  • Trình bày cách viết lại EDM để dễ tính toán deviance.

  • Giới thiệu unit deviance:

    Ví dụ với phân phối Poisson, hàm deviance có dạng:

    \[ d(y, \mu) = 2\left[ \frac{y - \mu}{\mu} + \log\left( \frac{\mu}{y} \right) \right] \]

  • Saddlepoint approximation được dùng để gần đúng phân phối của deviance.

5.5 Thành phần hệ thống

  • Bao gồm:

    • Linear predictor: η=β0+β1x1+⋯+βpxp= _0 + _1x_1 + + _px_pη=β0​+β1​x1​+⋯+βp​xp​;

    • Hàm liên kết (link function): nối kết μ=E[y]= E[y]μ=E[y] với η.

  • Ngoài ra còn có thể thêm offsets (biến cố định trong mô hình).

5.6 Định nghĩa chính thức GLM

  • Một GLM đầy đủ:

    Biểu diễn tổng quát của mô hình:

    \[ \begin{cases} y_i \sim \text{EDM}(\mu_i, \phi/w_i) \\ g(\mu_i) = o_i + \beta_0 + \beta_1 x_{i1} + \cdots + \beta_p x_{ip} \end{cases} \]

  • Mô hình được ký hiệu như: glm(Poisson; log) hoặc glm(binomial; logit) trong R.

5.7 Deviance tổng quát

  • Tổng deviance:

    Độ lệch tổng (Deviance) trong mô hình GLM được tính bởi:

    \[ D(y, \mu) = \sum_{i=1}^n w_i \, d(y_i, \mu_i) \]

  • Scaled deviance:

    Độ lệch chuẩn hóa (standardized deviance) được tính bởi:

    \[ D^*(y, \mu) = \frac{D(y, \mu)}{\phi} \]

  • Khi saddlepoint approximation đúng, scaled deviance xấp xỉ phân phối chi bình phương.

5.8 Hồi quy biến đổi vs. GLMs

  • So sánh GLMs với hồi quy tuyến tính dùng biến đổi \(y\).

  • Nhấn mạnh: GLM giúp mô hình hóa \(y\) trực tiếp thay vì biến đổi nó, làm cho giải thích thống kê rõ ràng hơn.

Kết luận chương

  • Chương 5 xây dựng cấu trúc lý thuyết cốt lõi của GLMs dựa trên hai thành phần: phân phối xác suất (EDMs) và liên kết tuyến tính (hàm liên kết).

  • GLM cho phép linh hoạt trong mô hình hóa dữ liệu không tuân chuẩn, có phương sai biến đổi, hoặc là số đếm, tỷ lệ, v.v.

  • Cơ sở cho việc ước lượng, suy luận và kiểm định được trình bày trong các chương tiếp theo (6–8).

CHƯƠNG 6: ƯỚC LƯỢNG TRONG GLM (GENERALIZED LINEAR MODELS: ESTIMATION)

6.1 Giới thiệu

  • Trình bày các kỹ thuật để ước lượng tham số trong GLM: hệ số hồi quy \(β\) và tham số phân tán \(ϕ\) (nếu có).

  • Sử dụng phương pháp ước lượng hợp lý cực đại (MLE) làm cơ sở.

6.2 Ước lượng xác suất hợp lý cho β

  • Phương trình điểm (score equations)ma trận thông tin được xây dựng từ đạo hàm log-likelihood.

  • Từ biểu thức xác suất dạng EDM, thu được:

    \[ \frac{\partial \log P(y;\mu,\phi/w)}{\partial \mu} = \frac{w(y - \mu)}{\phi V(\mu)} \]

  • Từ đó, suy ra đạo hàm theo từng hệ số \(βj\)​ và ma trận thông tin Fisher một cách cụ thể.

6.3 Tính toán ước lượng β

  • Áp dụng thuật toán lặp Newton–Raphson hoặc Fisher Scoring để tìm ước lượng.

  • Biểu diễn quy trình lặp: từ giá trị ban đầu → tính working values → cập nhật \(β\).

Mã R (ví dụ Poisson GLM):

library(GLMsData) data(nminer) model <- glm(Minerab ~ Eucs, data=nminer, family=poisson(link="log")) summary(model)

R sử dụng nội bộ thuật toán Fisher scoring để ước lượng.

6.4 Deviance còn lại (residual deviance)

  • Là thước đo độ phù hợp của mô hình:

    \[ D(y, \hat{\mu}) = 2 \sum w_i \left[ y_i \log \frac{y_i}{\hat{\mu}_i} - (y_i - \hat{\mu}_i) \right] \]

  • Scaled deviance được dùng để kiểm định mô hình thông qua phân phối \(χ2\).

6.5 Sai số chuẩn của β

  • Ước lượng từ nghịch đảo của ma trận thông tin:

    \[ \text{Var}(\hat{\beta}) = I^{-1}(\hat{\beta}) \]

6.6 Dạng ma trận của phương trình ước lượng

  • Mô tả GLMs tương tự hồi quy tuyến tính thông qua:

    \[ \hat{\beta} = (X^T W X)^{-1} X^T W z \]

  • Với:

    • \(w\): ma trận trọng số (working weights)

    • \(z\): biến phụ (working response)

6.7 So sánh với hồi quy tuyến tính

  • Quá trình ước lượng trong GLMs xấp xỉ tuyến tính tại mỗi bước lặp;

  • Nhấn mạnh sự tương đồng về mặt hình thức giữa GLMs và mô hình OLS.

6.8 Ước lượng tham số phân tán \(ϕ\)

Bao gồm 4 phương pháp:

  1. MLE (với hàm log-likelihood profile);

  2. Deviance trung bình:

    \[ \hat{\phi} = \frac{D(y, \mu)}{\text{df}_{\text{res}}} \]

  3. Pearson: \[ \hat{\phi} = \sum \frac{(y - \mu)^2}{\phi V(\mu)} \]

  4. Lựa chọn tối ưu tùy thuộc vào phân phối cụ thể.

Ví dụ mã R: summary(model)$dispersion # Pearson estimator deviance(model) / df.residual(model) # Mean deviance estimator

6.9 Sử dụng R để khớp GLMs

  • Hàm chính: glm(), với các đối số:

    • formula: công thức mô hình;

    • family: chỉ định phân phối và hàm liên kết.

Ví dụ: glm(y ~ x1 + x2, family = poisson(link = "log"), data = df) glm(y ~ x1 + x2, family = binomial, data = df)

R hỗ trợ các family phổ biến: gaussian(), poisson(), binomial(), Gamma(), inverse.gaussian(), quasi(),…

6.10 Tổng kết chương

  • Chương 6 củng cố cơ sở toán học và thuật toán để ước lượng tham số trong GLM.

  • Là cầu nối giữa lý thuyết xác suất hàm mũ và thực hành phân tích dữ liệu với R.

CHƯƠNG 7: SUY LUẬN TRONG MÔ HÌNH TUYẾN TÍNH TỔNG QUÁT (INFERENCE IN GLMs)

7.1 Giới thiệu

  • Chương này trình bày các phương pháp suy luận thống kê cho các hệ số trong GLMs.

  • Dựa trên ước lượng hợp lý cực đại (MLE), sử dụng 3 loại kiểm định:

    • Wald test

    • Likelihood Ratio Test (LRT)

    • Score test

  • Áp dụng cho cả trường hợp tham số phân tán \(ϕ\) được biết hoặc không biết.

7.2 Khi tham số phân tán φ đã biết

Wald test

  • Dựa trên giả định phân phối chuẩn tiệm cận của \(\hat{\beta}_j​:\) \[ Z = \frac{\hat{\beta}_j - \beta_j^0}{\text{se}(\hat{\beta}_j)} \sim N(0,1) \]

  • Phổ biến vì đơn giản và có sẵn trong summary(glm_object).

Mã R: summary(glm(FEV ~ Age, family=gaussian, data=lungcap))

Khoảng tin cậy (Confidence intervals)

  • Xây dựng từ Wald test:

    \[ \hat{\beta}_j \pm z_{\alpha/2} \cdot \text{se}(\hat{\beta}_j) \]

  • R dùng confint() hoặc trực tiếp từ summary()

Mã R: confint(model)

Likelihood Ratio Test (LRT)

  • So sánh mô hình con và mô hình đầy đủ:

    \[ \frac{D_{\text{reduced}} - D_{\text{full}}}{\phi} \sim \chi^2_{df} \]

  • Có thể dùng anova(model1, model2, test="Chisq").

Mã R: model.full <- glm(Y ~ X1 + X2, family=poisson, data=df) model.reduced <- glm(Y ~ X1, family=poisson, data=df) anova(model.reduced, model.full, test="Chisq")

Score test

  • Đánh giá hiệu quả của việc thêm biến vào mô hình.

  • Dùng khi chưa ước lượng mô hình đầy đủ.

7.3 – 7.4 Kiểm định độ phù hợp (Goodness-of-Fit)

  • Deviance test: Dựa vào scaled deviance.

  • Pearson test: Dựa vào tổng phần dư Pearson bình phương.

  • Có thể kiểm tra bằng deviance(model)residuals(model, type="pearson").

Mã R: deviance(model) sum(residuals(model, type="pearson")^2)

7.6 Khi φ chưa biết

  • Ước lượng \(ϕ\) từ phần dư (Pearson hoặc deviance).

  • Thay phân phối chuẩn bằng phân phối t:

    \[ T = \frac{\hat{\beta}_j - \beta_j^0}{\text{se}(\hat{\beta}_j)} \sim t_{n - p'} \]

  • Khoảng tin cậy dùng phân phối t thay vì z.

7.7 So sánh 3 loại kiểm định

Kiểm định Ưu điểm Nhược điểm
Wald Có sẵn trong output R Nhạy cảm khi \(\hat{\beta}\) gần 0
LRT Chính xác, phù hợp với mô hình lồng nhau Cần ước lượng mô hình đầy đủ
Score Không cần mô hình đầy đủ Thiếu sẵn có trong R

7.8 So sánh mô hình không lồng nhau

  • Dùng AICBIC:

    \[ \text{AIC} = -2\log L + 2k; \quad \text{BIC} = -2\log L + k \log n \]

Mã R: AIC(model1, model2) BIC(model1, model2)

7.9 Tự động chọn mô hình

  • Sử dụng hàm step() (theo AIC):

step(glm(FEV ~ Age + Ht + Gender + Smoke, family=gaussian, data=lungcap))

Tổng kết chương

  • Chương này thiết lập hệ thống công cụ suy luận cho GLMs:

    • Kiểm định ý nghĩa thống kê của hệ số;

    • Đánh giá sự cải thiện mô hình;

    • Chọn mô hình tối ưu hóa giữa độ phù hợp và đơn giản.

Các phương pháp này nền tảng cho chẩn đoán mô hình (Chương 8) và diễn giải kết quả trong thực hành thống kê hiện đại.

CHƯƠNG 8: CHẨN ĐOÁN MÔ HÌNH TUYẾN TÍNH TỔNG QUÁT (DIAGNOSTICS)

8.1 Giới thiệu

Chương này trình bày các công cụ để:

  • Xác định vi phạm giả định của GLM;

  • Giải thích các loại phần dư (residuals);

  • Phát hiện điểm dữ liệu bất thường hoặc ảnh hưởng lớn;

  • Đề xuất các hướng điều chỉnh mô hình.

8.2 Giả định của GLM

Các giả định chính:

  1. Không có outliers ảnh hưởng lớn;

  2. Hàm liên kết \(g(μ)\) là đúng;

  3. Tuyến tính hóa các biến giải thích là đúng;

  4. Hàm phương sai \(V(μ)\) là phù hợp;

  5. Tham số phân tán \(ϕ\) là hằng số;

  6. Các quan sát độc lập;

  7. Dữ liệu đến từ phân phối EDM xác định.

8.3 Residuals trong GLM

Ba loại residuals chính:

  • Pearson residuals: Residual Pearson được tính bởi \(\displaystyle r_P = \frac{y - \mu}{\sqrt{\phi\,V(\mu)/w}}\).

  • Deviance residuals:\[ r_D = \text{sign}(y - \mu) \cdot \sqrt{2w\,d(y, \mu)} \]

  • Quantile residuals: dùng để vẽ Q–Q plot, đặc biệt hữu ích cho dữ liệu rời rạc (discrete).

8.4 Leverages và ma trận “hat”

  • Leverage \(h_i\)​: mức độ ảnh hưởng của mỗi quan sát lên ước lượng \(\hat{\mu}_i\) ;

  • Được tính qua ma trận “hat”:

\[ H = W^{1/2} X (X^T W X)^{-1} X^T W^{1/2} \]

8.5 Phần dư chuẩn hóa (Standardized residuals)

  • Chuẩn hóa giúp phần dư có phương sai ổn định.

  • Ví dụ:

    \[ r'_P = \frac{r_P}{\sqrt{1 - h}}, \quad r'_D = \frac{r_D}{\sqrt{1 - h}}, \quad r'_Q = \frac{r_Q}{\sqrt{1 - h}} \]

  • rstandard()rstudent() dùng để lấy phần dư chuẩn hóa và Studentized.

8.6 Khi nào dùng loại residual nào

  • Quantile residuals: khuyên dùng với dữ liệu đếm hoặc nhị phân;

  • Deviance residuals: thường dùng nhất;

  • Pearson residuals: dùng để ước lượng \(ϕ\), ít dùng cho đồ thị.

8.7 Kiểm tra giả định mô hình

Các đồ thị chẩn đoán:

  • Residuals vs. fitted values: tìm xu hướng không tuyến tính hoặc phương sai không đều.

  • Q–Q plot của residuals: phát hiện outliers.

  • Residuals vs. explanatory variables: kiểm tra tuyến tính của từng biến.

  • Partial residual plots (termplot()): xác định mối quan hệ đúng giữa biến và phản hồi.

8.8 Phát hiện quan sát ngoại lệ và ảnh hưởng lớn

  • Sử dụng:

    • Standardized residuals

    • Studentized residuals

    • Cook’s distance, dfbetas, dffits, covratio từ influence.measures() trong R.

  • Một quan sát được gọi là ảnh hưởng nếu khi loại bỏ nó sẽ làm thay đổi đáng kể mô hình.

8.9 Giải quyết vấn đề mô hình

  • Biến đổi biến (log, sqrt);

  • Sử dụng spline (ns(), bs() từ package splines);

  • Loại bỏ hoặc tách riêng các outliers có lý do rõ ràng.

8.10 Mô hình quasi-likelihood

  • Dùng khi phân phối không phù hợp hoàn toàn;

  • Ví dụ: quasipoisson(), quasibinomial() cho dữ liệu overdispersion;

  • AIC không định nghĩa cho quasi-models, nhưng summary()anova() vẫn dùng được.

8.11 Vấn đề đa cộng tuyến (Collinearity)

  • Dấu hiệu: hệ số hồi quy không ổn định, phương sai lớn;

  • Giải pháp: loại biến, kết hợp biến, dùng PCA.

8.12 Tổng kết

  • Chẩn đoán là bước bắt buộc sau khi khớp GLM;

  • Dựa vào phần dư, leverage, ảnh hưởng để đánh giá chất lượng mô hình;

  • Đề xuất cách cải thiện mô hình nếu có vi phạm giả định

CHƯƠNG 9: MÔ HÌNH NHỊ THỨC (BINOMIAL GLMs)

9.1 Giới thiệu

  • Chương 9 áp dụng lý thuyết GLM đã phát triển ở các chương trước cho trường hợp phân phối nhị thức, dùng để mô hình hóa tỷ lệ (proportions).

  • Đặc biệt hữu ích trong các nghiên cứu như: tỷ lệ tử vong, kết quả điều trị, tỷ lệ bỏ phiếu, v.v..

9.2 Mô hình hóa tỷ lệ (Proportion Models)

  • Dữ liệu nhị thức được mô hình hóa theo:

    Giả sử biến quan sát \(y_i\) tuân theo phân phối nhị thức:

    \[ y_i \sim \text{Binomial}(m_i, \mu_i), \quad \text{với } 0 < \mu_i < 1 \]

    Trong đó: - \(m_i\): số lần thử (số trials) - \(\mu_i\): xác suất thành công trong mỗi lần thử

  • Phương sai là: \(\text{var}(y_i) = \frac{\mu_i(1 - \mu_i)}{m_i}\).​

  • Trọng số tiên nghiệm: \(w_i = m_i\)

9.4 Diễn giải theo ngưỡng (Threshold interpretation)

  • Các hàm liên kết có thể được hiểu là kết quả của mô hình ngưỡng (threshold models): mỗi đối tượng có một mức dung sai (tolerance).

  • Dẫn đến diễn giải xác suất dựa trên phân phối của ngưỡng dung sai.

9.5 Odds và Odds Ratio

  • Sử dụng logit cho phép diễn giải mô hình như log(odds).

    • Tỷ số odds (odds ratio) là quan hệ giữa xác suất xảy ra và không xảy ra:

      Tỷ số cược (odds) và hàm logit được định nghĩa như sau:

      \[ \text{odds} = \frac{\mu}{1 - \mu}, \quad \text{logit}(\mu) = \log(\text{odds}) = \log\left(\frac{\mu}{1 - \mu}\right) \]

      Trong đó: \(\mu\): xác suất thành công; logit(\(\mu\)): hàm liên kết trong mô hình hồi quy logistic

  • Giải thích hệ số hồi quy dễ dàng hơn thông qua thay đổi tỷ số odds.

9.6 ED50 (Liều hiệu quả trung bình)

  • Được định nghĩa là giá trị liều lượng ddd sao cho μ=0.5= 0.5μ=0.5

  • Với liên kết logit: Giá trị ED\(_{50}\) được tính bằng $_{50} = -_0 / _1$.

  • Công cụ dose.p() trong R (gói MASS) được dùng để tính toán ED(ρ).

Ví dụ R: library(MASS) dose.p(fit, c(1, 2)) # ước lượng ED50

9.7 Complementary Log-Log trong phân tích sinh học

  • Phù hợp với bài toán dilution assay, như xác định xác suất có tế bào gốc trong mẫu mô.

  • Xây dựng trên giả định phân phối Poisson của số tế bào và mô hình log-log-link.

9.8 Overdispersion trong mô hình nhị thức

  • Overdispersion: Phương sai lớn hơn dự kiến.

  • Nguyên nhân:

    • \(u_i\) thay đổi giữa các nhóm;

    • Các thử nghiệm \(m_i\)​ không độc lập;

  • Dẫn đến phương sai hiệu dụng:

    \[ \text{var}(y_i) = \phi \frac{\mu_i(1 - \mu_i)}{m_i}, \quad \phi > 1 \]

  • Giải pháp: Dùng quasi-binomial models hoặc beta-binomial models.

9.9 Lỗi ước lượng do separation

  • Khi biến giải thích hoàn toàn phân biệt giữa các nhóm, gây ra hiện tượng separation.

  • Gây ra ước lượng hệ số hồi quy vô hạn → R sẽ cảnh báo.

9.10 Goodness-of-fit với dữ liệu nhị phân

  • Các kiểm định như deviance test không phù hợp với dữ liệu nhị phân (mỗi dòng là một cá thể);

  • Phân phối deviance không còn tiệm cận theo chi bình phương;

  • Giải pháp: xem phần dư chuẩn hóa, hoặc dùng bootstrap nếu cần kiểm định.

9.12 Sử dụng R cho mô hình nhị thức

Ba cách nhập dữ liệu:

  1. Tỷ lệ thành công + weights = m;

  2. cbind(success, failure) ~ x;

  3. Nhị phân từng cá thể: dùng biến logic hoặc factor.

Mã mẫu: glm(y ~ x, weights=m, family=binomial) glm(cbind(success, failure) ~ x, family=binomial) glm(success ~ x, family=binomial) # nhị phân

Tổng kết chương

  • Chương 9 áp dụng GLMs vào mô hình tỷ lệ với phân phối nhị thức;

  • Trình bày rõ ràng hàm liên kết, cách tính ED50, xử lý overdispersion, và diễn giải logit;

  • Đặc biệt hữu ích trong các bài toán logistic regression, dose-response và sinh học phân tử.

CHƯƠNG 10: MÔ HÌNH ĐẾM – POISSON VÀ NEGATIVE BINOMIAL GLMs

10.1 Giới thiệu

  • Mô hình hóa dữ liệu đếm là một ứng dụng phổ biến trong GLMs.

  • Dữ liệu đếm xuất hiện khi:

    • Các sự kiện xảy ra độc lập;

    • Không có giới hạn trên rõ ràng cho số lượng sự kiện;

  • Mô hình hóa sử dụng:

    • Phân phối Poisson (chính);

    • Poisson GLMs cho dữ liệu đếm theo biến giải thích;

    • Mô hình tỷ lệ (rates);

    • Bảng phân loại (contingency tables).

10.2 Poisson GLMs

Phân phối Poisson

  • Hàm xác suất:

\[ P(y; \mu) = \frac{e^{-\mu} \mu^y}{y!} \]

  • Kỳ vọng:

\[ E[y] = \mu, \quad \text{phương sai:} \quad Var(y) = \mu \]

  • Đơn vị deviance:

\[ d(y, \mu) = 2 \left( y \log \frac{y}{\mu} - (y - \mu) \right) \]

Hàm liên kết

  • Log-link (hàm liên kết chuẩn):

\[ \log(\mu) = \beta_0 + \sum_j \beta_j x_j \]

  • Diễn giải: tác động của \(x_j\) là nhân với \(\mu\) theo \(\exp(\beta_j)\).

10.3 Mô hình hóa tỷ lệ (Rates)

  • Khi số lượng đếm phụ thuộc vào quy mô dân số hoặc mức độ phơi nhiễm (exposure);

  • Sử dụng offset trong công thức GLM để điều chỉnh cho quy mô:

    glm(y ~ x + offset(log(population)), family=poisson)

10.4 Bảng phân loại (Contingency Tables)

  • Khi biến giải thích là định tính → mô hình Poisson trở thành log-linear model;

  • Dữ liệu 2 chiều, 3 chiều có thể được mô hình hóa thông qua các tương tác;

  • Cẩn trọng với zero counts:

    • Sampling zeros: xảy ra ngẫu nhiên;

    • Structural zeros: không thể xảy ra – cần loại bỏ khỏi mô hình

10.5 Overdispersion – Quá phân tán

Overdispersion trong Poisson GLMs

  • Khi phương sai thực tế lớn hơn μ;

  • Ảnh hưởng:

    • Sai số chuẩn bị đánh giá thấp;

    • Test thống kê cho thấy kết quả quá “đáng kể”;

  • Phát hiện qua: Deviance test, Pearson goodness-of-fit.

Negative Binomial GLMs

  • Giải pháp mô hình hóa overdispersion:

    • Giả định \(\mu_i\) có phân phối Gamma →

\[ y_i \sim \text{NB}(\mu, k) \]

  • Phương sai:

\[ \text{Var}(y) = \mu + \frac{\mu^2}{k} \]

  • Ước lượng đồng thời \(\beta\)\(k\) bằng glm.nb() trong R:

    library(MASS) glm.nb(Count ~ log2(Dilution), data=pock)

Quasi-Poisson GLMs

  • Không mô hình hóa phân phối xác suất, chỉ sử dụng phương sai:

\[ \text{Var}(y) = \phi \mu \]

  • Ước lượng ổn định, phù hợp khi chỉ quan tâm đến suy luận thống kê (inference), không dùng AIC.
  • Dùng trong R với: glm(..., family=quasipoisson())

10.6 Ví dụ: Poisson và Negative Binomial so sánh

  • Dữ liệu pock:

    • Poisson GLM không phù hợp do overdispersion;

    • Negative Binomial và Quasi-Poisson phù hợp hơn;

    • So sánh confidence interval và sai số chuẩn giữa các mô hình.

10.7 Mã R sử dụng GLMs cho đếm

  • Poisson GLM:

    glm(y ~ x, family=poisson)

  • Quasi-Poisson: glm(y ~ x, family=quasipoisson)

  • Negative Binomial: glm.nb(y ~ x)

10.8 Tổng kết chương

  • Poisson GLM là mô hình nền tảng cho dữ liệu đếm;

  • Khi có overdispersion:

    • Dùng Negative Binomial GLM nếu cần mô hình xác suất;

    • Dùng Quasi-Poisson GLM nếu cần inference đơn giản;

  • Đánh giá cần kết hợp deviance, phần dư, và lựa chọn mô hình phù hợp

CHƯƠNG 11: DỮ LIỆU DƯƠNG LIÊN TỤC – MÔ HÌNH GAMMA VÀ INVERSE GAUSSIAN GLMs

11.1 Giới thiệu

  • Chương này tập trung vào GLMs cho dữ liệu dương và liên tục – thường là các đại lượng đo lường như thời gian, chi phí, năng suất,…

  • Hai phân phối chính được sử dụng:

    • Phân phối Gamma (V(μ) = μ²)

    • Phân phối Inverse Gaussian (V(μ) = μ³)

  • Mục tiêu là mô hình hóa quan hệ bất đối xứng giữa biến phản hồi và biến giải thích.

11.2 Mô hình hóa dữ liệu dương liên tục

  • Dữ liệu thường lệch phải, không thể có giá trị âm.

  • Phương sai thường tăng theo giá trị trung bình.

  • Các hàm phương sai tăng nhanh như μ² và μ³ thường xuất hiện ⇒ phù hợp với Gamma và Inverse Gaussian GLMs.

11.3 Phân phối Gamma

  • Dùng để mô tả thời gian giữa các sự kiện Poisson.

  • Định nghĩa đơn vị deviance:

    \[ d(y, \mu) = 2\left( -\log \frac{y}{\mu} + \frac{y - \mu}{\mu} \right) \]

  • Phân phối Deviance xấp xỉ phân phối chi bình phương khi \(\phi \leq \frac{1}{3}\):

    \[ \text{Deviance} \sim \chi^2_{n - p'} \]

  • Liên kết chuẩn (canonical link) trong phân phối Poisson là hàm nghịch đảo:

    \[ \eta = \frac{1}{\mu} \]

  • Trong thực hành, thường dùng log-link để đảm bảo \(μ>0\) và dễ diễn giải.

11.4 Phân phối Inverse Gaussian

  • Dùng cho dữ liệu lệch mạnh hơn Gamma.

  • Có liên hệ với thời gian chạm ngưỡng trong chuyển động Brown (Brownian motion).

  • Hàm phương sai: \(V(\mu) = \mu^3\)

  • Liên kết chuẩn: \(\eta = 1/\mu^2\), nhưng thường dùng log-link hơn để đảm bảo \(μ> 0\).

11.6 Ước lượng tham số phân tán φ

  • Cả hai mô hình đều cần ước lượng \(ϕ\)

  • Gamma GLM:

    • Ước lượng Pearson và deviance khác nhau nhưng gần nhau;

    • LRT dựa trên phân phối F nếu φ được ước lượng.

  • Inverse Gaussian GLM:

    • Ước lượng MLE của $ϕ$ là chính xác.

    • Deviance tuân theo phân phối \(χ^2\) đúng (không chỉ xấp xỉ).

11.7 Nghiên cứu tình huống

  • Case study 1 (permeability):

    • Dữ liệu đo độ thấm của vật liệu xây dựng;

    • Phù hợp với mô hình inverse Gaussian + log-link:

    glm(Perm ~ Mach * Day, family=inverse.gaussian(link="log"), data=perm)

  • Case study 2 (onion yield):

    • Mô hình Gamma cho sản lượng hành theo mật độ trồng và giống.

11.8 Sử dụng R để khớp mô hình

  • Cú pháp cho Gamma GLM:

    glm(formula, family=Gamma(link="log"))

  • Cú pháp cho Inverse Gaussian GLM: glm(formula, family=inverse.gaussian(link="log"))

  • Có thể sử dụng các liên kết "log", "inverse", "identity" cho cả hai; riêng Inverse Gaussian còn thêm "1/mu^2".

11.9 Tổng kết chương

  • Mô hình Gamma và Inverse Gaussian rất thích hợp cho dữ liệu liên tục và dương với phương sai tăng theo trung bình.

  • Việc chọn đúng hàm liên kết và phân phối rất quan trọng để mô hình phản ánh chính xác bản chất dữ liệu.

  • R cung cấp công cụ linh hoạt để khớp, chẩn đoán, và kiểm định các mô hình này

CHƯƠNG 12: MÔ HÌNH TWEEDIE TRONG GLMs

12.1 Giới thiệu

  • Chương này mở rộng phạm vi GLMs đến một lớp phân phối đặc biệt gọi là Tweedie distributions, giúp xử lý:

    • Dữ liệu có cấu trúc liên tục + đếm (semicontinuous);

    • Dữ liệu không âm, lệch phải, có giá trị 0 với xác suất dương;

  • Mô hình Tweedie đặc biệt thích hợp cho mô hình hóa bảo hiểm, tài chính, và môi trường.

12.2 Họ phân phối Tweedie

  • Là một nhánh của Exponential Dispersion Models (EDMs), xác định bởi:

    \[ \text{Var}(Y) = \phi \mu^p \]

    Với:

    • \(μ\): kỳ vọng;

    • \(ϕ\): tham số phân tán;

    • \(p\): tham số chỉ số (index parameter) đặc trưng cho dạng phân phối

Giá trị \(p\) Loại phân phối tương ứng
0 Normal
1 Poisson
(1,2) Compound Poisson-Gamma
2 Gamma
3 Inverse Gaussian

12.3 Mô hình hóa dữ liệu semicontinuous

  • Trong nhiều trường hợp thực tế, dữ liệu có phân phối với phần tử:

    • Giá trị 0 với xác suất lớn (tương ứng với đếm hoặc không xảy ra sự kiện),

    • Giá trị dương liên tục (ví dụ chi phí, tổn thất,…).

  • Phân phối Tweedie với \(1 < p < 2\) mô hình hóa rất tốt kiểu dữ liệu này.

12.4 Ước lượng trong mô hình Tweedie

  • Không có dạng xác suất đóng – cần sử dụng:

    • Phương pháp xấp xỉ (quasi-likelihood);

    • Phương pháp lập trình tối ưu hóa (profile likelihood);

    • Dựng GLM bằng cách ước lượng đồng thời \(β\), \(ϕ\)\(p\).

12.5 Sử dụng R để khớp mô hình Tweedie

  • Cần gói statmod, tweedie, hoặc mgcv:

  • library(statmod) library(tweedie) glm(TotalCost ~ Age + Sex, family=tweedie(var.power=1.5, link.power=0), data=df)

  • Có thể dùng hàm tweedie.profile() để chọn giá trị tối ưu cho ppp.

12.6 Ứng dụng thực tế

  • Bảo hiểm: dự đoán chi phí y tế, tổn thất;

  • Sinh thái học: mật độ loài + vùng không quan sát được;

  • Năng lượng: dữ liệu tiêu thụ có nhiều số 0 và phân bố lệch.

Tổng kết chương

  • Mô hình Tweedie mở rộng GLMs sang các tình huống dữ liệu phức tạp:

    • Dữ liệu bán liên tục;

    • Phân phối lệch và không chuẩn;

    • Nhiều giá trị 0 có tính hệ thống;

  • Tuy tính toán phức tạp hơn, nhưng Tweedie GLMs là công cụ cực kỳ linh hoạt và mạnh mẽ trong mô hình hóa thực nghiệm hiện đại.

CHƯƠNG 13: MỞ RỘNG MÔ HÌNH HÓA TRONG GLMs

13.1 Giới thiệu

Chương này trình bày các kỹ thuật mở rộng để:

  • Vượt qua các giới hạn của GLMs cổ điển;

  • Cải thiện độ linh hoạt trong mô hình hóa phi tuyến, phân tán thay đổi,…;

  • Áp dụng kỹ thuật như spline, smoothers, quasi-likelihood và mô hình phân tán thay đổi (heteroscedastic GLMs).

13.2 Mô hình hóa hiệu ứng phi tuyến (Nonlinear Effects)

  • Trong GLM cổ điển, mối quan hệ giữa biến giải thích và biến phản hồi là tuyến tính sau hàm liên kết.

  • Khi điều này không đúng, có thể dùng:

    • Hàm spline (splines::ns(), bs());

    • Smoothers (mgcv::gam()).

Ví dụ R: library(splines) glm(y ~ ns(x, df=4), family=poisson, data=df)

13.3 Spline và hàm trơn hóa (Smoothing)

  • Natural splines: tránh hiện tượng dao động ở biên;

  • B-splines: kiểm soát tốt hơn mức độ trơn;

  • GAM (Generalized Additive Models): mở rộng GLM với thành phần trơn hóa:

    library(mgcv) gam(y ~ s(x1) + s(x2), family=poisson, data=df)

13.4 Biến phân tán (Varying dispersion)

  • Trong nhiều ứng dụng, tham số phân tán \(ϕ\) không hằng số;

  • Có thể mô hình hóa \(ϕ\) như một hàm số của biến giải thích:

    • Dùng quasi-likelihood;

    • Dùng mô hình lồng (hierarchical/multilevel GLMs);

    • Hoặc mô hình hai phần (double GLM).

13.5 Phân tích bán tham số (Semiparametric methods)

  • Dùng khi chưa xác định được chính xác dạng liên kết;

  • GAM, spline và kernel regression giúp duy trì tính linh hoạt nhưng vẫn dễ giải thích.

13.6 Mô hình hóa tác động ngẫu nhiên (Random effects and mixed models)

  • Kết hợp GLM với các thành phần ngẫu nhiên:

    • Dữ liệu phân cấp, lồng ghép (ví dụ: học sinh trong lớp, bệnh nhân trong bệnh viện);

    • Sử dụng glmer() trong lme4:

      library(lme4) glmer(y ~ x + (1 | group), family=poisson, data=df)

13.7 Lựa chọn mô hình mở rộng

  • Ngoài AIC/BIC còn có:

    • GCV (Generalized Cross-Validation);

    • Deviance explained;

    • Adjusted R² cho GAMs.

Tổng kết chương

  • GLMs cổ điển mạnh nhưng có giới hạn trong:

    • Biến hiệu ứng phi tuyến;

    • Phân tán thay đổi;

    • Cấu trúc dữ liệu lồng;

    Chương 13 trình bày cách kết hợp các kỹ thuật hiện đại (spline, GAM, mô hình hỗn hợp) để mở rộng tính linh hoạt và khả năng mô hình hóa dữ liệu thực tế.

BÀI TẬP 2: THỐNG KÊ MÔ TẢ “Supermarket Transactions.csv”

# Tải các thư viện cần thiết
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(summarytools)
## Warning: package 'summarytools' was built under R version 4.4.3
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.4.1
## Warning: package 'tidyr' was built under R version 4.4.1
## Warning: package 'readr' was built under R version 4.4.1
## Warning: package 'purrr' was built under R version 4.4.1
## Warning: package 'forcats' was built under R version 4.4.1
## Warning: package 'lubridate' was built under R version 4.4.1
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ lubridate 1.9.3     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     ✔ tidyr     1.3.1
## ✔ readr     2.1.5
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ✖ tibble::view()  masks summarytools::view()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(lubridate)
library(scales) 
## Warning: package 'scales' was built under R version 4.4.1
## 
## Attaching package: 'scales'
## 
## The following object is masked from 'package:purrr':
## 
##     discard
## 
## The following object is masked from 'package:readr':
## 
##     col_factor

1. Đọc dữ liệu

# Đọc file CSV
data <- read.csv("D:/PTDLDT/Supermarket Transactions.csv")

# Kiểm tra cấu trúc dữ liệu
str(data)
## 'data.frame':    14059 obs. of  16 variables:
##  $ X                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ PurchaseDate     : chr  "2007-12-18" "2007-12-20" "2007-12-21" "2007-12-21" ...
##  $ CustomerID       : int  7223 7841 8374 9619 1900 6696 9673 354 1293 7938 ...
##  $ Gender           : chr  "F" "M" "F" "M" ...
##  $ MaritalStatus    : chr  "S" "M" "M" "M" ...
##  $ Homeowner        : chr  "Y" "Y" "N" "Y" ...
##  $ Children         : int  2 5 2 3 3 3 2 2 3 1 ...
##  $ AnnualIncome     : chr  "$30K - $50K" "$70K - $90K" "$50K - $70K" "$30K - $50K" ...
##  $ City             : chr  "Los Angeles" "Los Angeles" "Bremerton" "Portland" ...
##  $ StateorProvince  : chr  "CA" "CA" "WA" "OR" ...
##  $ Country          : chr  "USA" "USA" "USA" "USA" ...
##  $ ProductFamily    : chr  "Food" "Food" "Food" "Food" ...
##  $ ProductDepartment: chr  "Snack Foods" "Produce" "Snack Foods" "Snacks" ...
##  $ ProductCategory  : chr  "Snack Foods" "Vegetables" "Snack Foods" "Candy" ...
##  $ UnitsSold        : int  5 5 3 4 4 3 4 6 1 2 ...
##  $ Revenue          : num  27.38 14.9 5.52 4.44 14 ...

2. Tổng quan dữ liệu

# Tóm tắt toàn bộ dữ liệu
summary(data)
##        X         PurchaseDate         CustomerID       Gender         
##  Min.   :    1   Length:14059       Min.   :    3   Length:14059      
##  1st Qu.: 3516   Class :character   1st Qu.: 2549   Class :character  
##  Median : 7030   Mode  :character   Median : 5060   Mode  :character  
##  Mean   : 7030                      Mean   : 5117                     
##  3rd Qu.:10544                      3rd Qu.: 7633                     
##  Max.   :14059                      Max.   :10280                     
##  MaritalStatus       Homeowner            Children    AnnualIncome      
##  Length:14059       Length:14059       Min.   :0.00   Length:14059      
##  Class :character   Class :character   1st Qu.:1.00   Class :character  
##  Mode  :character   Mode  :character   Median :3.00   Mode  :character  
##                                        Mean   :2.53                     
##                                        3rd Qu.:4.00                     
##                                        Max.   :5.00                     
##      City           StateorProvince      Country          ProductFamily     
##  Length:14059       Length:14059       Length:14059       Length:14059      
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  ProductDepartment  ProductCategory      UnitsSold        Revenue     
##  Length:14059       Length:14059       Min.   :1.000   Min.   : 0.53  
##  Class :character   Class :character   1st Qu.:3.000   1st Qu.: 6.84  
##  Mode  :character   Mode  :character   Median :4.000   Median :11.25  
##                                        Mean   :4.081   Mean   :13.00  
##                                        3rd Qu.:5.000   3rd Qu.:17.37  
##                                        Max.   :8.000   Max.   :56.70

Bảng kết quả cho thấy tập dữ liệu gồm 14.059 dòng với nhiều biến thông tin về khách hàng, sản phẩm và giao dịch. Bao gồm biến định lượng và biến định tính.

3. Thống kê mô tả các biến định lượng

# Chọn các biến định lượng
numeric_vars <- data %>% 
  select(AnnualIncome, Children, UnitsSold, Revenue)

# Tóm tắt mô tả chi tiết
summary(numeric_vars)
##  AnnualIncome          Children      UnitsSold        Revenue     
##  Length:14059       Min.   :0.00   Min.   :1.000   Min.   : 0.53  
##  Class :character   1st Qu.:1.00   1st Qu.:3.000   1st Qu.: 6.84  
##  Mode  :character   Median :3.00   Median :4.000   Median :11.25  
##                     Mean   :2.53   Mean   :4.081   Mean   :13.00  
##                     3rd Qu.:4.00   3rd Qu.:5.000   3rd Qu.:17.37  
##                     Max.   :5.00   Max.   :8.000   Max.   :56.70

Các biến định lượng có phân bố hợp lý. Children trung bình khoảng 2.5, UnitsSold phổ biến từ 3–5 sản phẩm, và Revenue trung bình 13 đơn vị tiền, cho thấy sự đa dạng về giá trị đơn hàng.

4. Thống kê mô tả các biến định tính

categorical_vars <- c("Gender", "MaritalStatus", "Homeowner", "City", "StateorProvince", 
                      "Country", "ProductFamily", "ProductDepartment", "ProductCategory")

# Tạo bảng tần suất và tần suất tương đối
for (var in categorical_vars) {
  cat("\n\n==>", var, "\n")
  print(prop.table(table(data[[var]])) * 100)
}
## 
## 
## ==> Gender 
## 
##        F        M 
## 50.99936 49.00064 
## 
## 
## ==> MaritalStatus 
## 
##        M        S 
## 48.83704 51.16296 
## 
## 
## ==> Homeowner 
## 
##        N        Y 
## 39.93883 60.06117 
## 
## 
## ==> City 
## 
##      Acapulco    Bellingham Beverly Hills     Bremerton       Camacho 
##     2.7242336     1.0171420     5.7685468     5.9321431     3.2150224 
##   Guadalajara       Hidalgo   Los Angeles        Merida   Mexico City 
##     0.5334661     6.0103848     6.5865282     4.6518245     1.3798990 
##       Orizaba      Portland         Salem    San Andres     San Diego 
##     3.3003770     6.2308841     9.8584537     4.4170994     6.1597553 
## San Francisco       Seattle       Spokane        Tacoma     Vancouver 
##     0.9246746     6.5580767     6.2237712     8.9408920     4.5024539 
##      Victoria   Walla Walla        Yakima 
##     1.2518671     1.1380610     2.6744434 
## 
## 
## ==> StateorProvince 
## 
##         BC         CA         DF   Guerrero    Jalisco         OR   Veracruz 
##  5.7543211 19.4395049  5.7969984  2.7242336  0.5334661 16.0893378  3.3003770 
##         WA    Yucatan  Zacatecas 
## 32.4845295  4.6518245  9.2254072 
## 
## 
## ==> Country 
## 
##    Canada    Mexico       USA 
##  5.754321 26.232307 68.013372 
## 
## 
## ==> ProductFamily 
## 
##          Drink           Food Non-Consumable 
##       8.891102      72.217085      18.891813 
## 
## 
## ==> ProductDepartment 
## 
## Alcoholic Beverages         Baked Goods        Baking Goods           Beverages 
##           2.5321858           3.0229746           7.6250089           4.8367594 
##     Breakfast Foods        Canned Foods     Canned Products            Carousel 
##           1.3372217           6.9492852           0.7753041           0.4196600 
##            Checkout               Dairy                Deli                Eggs 
##           0.5832563           6.4229319           4.9719041           1.4083505 
##        Frozen Foods  Health and Hygiene           Household                Meat 
##           9.8300021           6.3518031          10.1002916           0.6330464 
##         Periodicals             Produce             Seafood         Snack Foods 
##           1.4368020          14.1830856           0.7255139          11.3806103 
##              Snacks       Starchy Foods 
##           2.5037343           1.9702682 
## 
## 
## ==> ProductCategory 
## 
##         Baking Goods    Bathroom Products        Beer and Wine 
##            3.4426346            2.5962017            2.5321858 
##                Bread      Breakfast Foods              Candles 
##            3.0229746            2.9660716            0.3200797 
##                Candy     Canned Anchovies         Canned Clams 
##            2.5037343            0.3129668            0.3769827 
##       Canned Oysters      Canned Sardines        Canned Shrimp 
##            0.2489508            0.2845153            0.2702895 
##          Canned Soup          Canned Tuna Carbonated Beverages 
##            2.8736041            0.6188207            1.0953837 
##    Cleaning Supplies        Cold Remedies                Dairy 
##            1.3443346            0.6614980            6.4229319 
##        Decongestants               Drinks                 Eggs 
##            0.6045949            0.9602390            1.4083505 
##           Electrical      Frozen Desserts       Frozen Entrees 
##            2.5250729            2.2974607            0.8393200 
##                Fruit             Hardware        Hot Beverages 
##            5.4413543            0.9175617            1.6075112 
##              Hygiene     Jams and Jellies     Kitchen Products 
##            1.4012376            4.1823743            1.5434953 
##            Magazines                 Meat        Miscellaneous 
##            1.4368020            5.4129028            0.2987410 
##  Packaged Vegetables       Pain Relievers       Paper Products 
##            0.3414183            1.3656732            2.4539441 
##                Pizza     Plastic Products Pure Juice Beverages 
##            1.3798990            1.0029163            1.1736254 
##              Seafood          Side Dishes          Snack Foods 
##            0.7255139            1.0882709           11.3806103 
##            Specialty        Starchy Foods           Vegetables 
##            2.0556227            1.9702682           12.2910591
  • Giới tính: Phân bố gần như đồng đều (Nữ 51%, Nam 49%).

  • Tình trạng hôn nhân: Khách hàng độc thân chiếm đa số (51%).

  • Sở hữu nhà: 60% khách hàng có nhà riêng.

  • Khu vực: Tập trung chủ yếu tại Mỹ (68%), đặc biệt ở bang Washington, California, Oregon.

  • Sản phẩm: Thực phẩm chiếm ưu thế lớn (72%), đặc biệt là rau củ và đồ ăn nhẹ.

  • Thành phố nổi bật: Salem, Tacoma, Los Angeles.

→ Nhìn chung, khách hàng chủ yếu là người Mỹ, có nhà, tiêu dùng mạnh vào thực phẩm, đặc biệt là rau và snack.

4.1. Thông tin nhân khẩu học khách hàng

Giới tính (Gender)

# Tần suất và biểu đồ giới tính
gender_freq <- data %>% count(Gender)
gender_freq
##   Gender    n
## 1      F 7170
## 2      M 6889
# Biểu đồ
ggplot(gender_freq, aes(x = Gender, y = n, fill = Gender)) +
  geom_col() +
  labs(title = "Phân phối giới tính", x = "Giới tính", y = "Số lượng") +
  theme_minimal()

Biểu đồ cho thấy sự phân bố giới tính của khách hàng gần như cân bằng:

  • Nữ chiếm khoảng 51%, nhỉnh hơn một chút so với nam.

  • Nam chiếm khoảng 49%.

Kết luận: Không có sự chênh lệch lớn về giới tính trong tập khách hàng, cho thấy nhóm khách hàng của siêu thị được phân bố đồng đều giữa nam và nữ. Điều này có thể giúp doanh nghiệp thiết kế sản phẩm, chương trình khuyến mãi phù hợp cho cả hai giới.

Tình trạng hôn nhân (Marital Status)

marital_freq <- data %>% count(MaritalStatus)
marital_freq
##   MaritalStatus    n
## 1             M 6866
## 2             S 7193
ggplot(marital_freq, aes(x = MaritalStatus, y = n, fill = MaritalStatus)) +
  geom_col() +
  labs(title = "Tình trạng hôn nhân", x = "Tình trạng", y = "Số lượng") +
  theme_minimal()

  • Biểu đồ cho thấy số khách hàng độc thân (S) nhỉnh hơn một chút so với số khách hàng đã kết hôn (M).

  • Sự chênh lệch không quá lớn, cho thấy nhóm khách hàng khá cân bằng giữa hai tình trạng hôn nhân.

Kết luận: Khách hàng trong dữ liệu có sự phân bố tương đối đồng đều giữa độc thânđã kết hôn, giúp phân tích nhu cầu và hành vi tiêu dùng theo từng nhóm dễ dàng hơn.

Tình trạng sở hữu nhà (Homeowner)

homeowner_freq <- data %>% count(Homeowner)
homeowner_freq
##   Homeowner    n
## 1         N 5615
## 2         Y 8444
ggplot(homeowner_freq, aes(x = Homeowner, y = n, fill = Homeowner)) +
  geom_col() +
  labs(title = "Khách hàng có sở hữu nhà không?", x = "Homeowner", y = "Số lượng") +
  theme_minimal()

  • Số lượng khách hàng sở hữu nhà (Y) cao hơn đáng kể so với số không sở hữu nhà (N).

  • Ước tính tỷ lệ: Khoảng 60% khách hàng sở hữu nhà, còn lại 40% không sở hữu.

Kết luận: Đa số khách hàng trong tập dữ liệu đã sở hữu nhà. Điều này có thể liên quan đến mức độ ổn định tài chính cao hơn, và là yếu tố hữu ích trong việc phân tích khả năng chi tiêu, đầu tư hoặc tín dụng.

4.2. Thông tin địa lý

Thành phố (City)

top_city <- data %>% count(City, sort = TRUE) %>% slice(1:10)
top_city
##             City    n
## 1          Salem 1386
## 2         Tacoma 1257
## 3    Los Angeles  926
## 4        Seattle  922
## 5       Portland  876
## 6        Spokane  875
## 7      San Diego  866
## 8        Hidalgo  845
## 9      Bremerton  834
## 10 Beverly Hills  811
ggplot(top_city, aes(x = reorder(City, n), y = n)) +
  geom_col(fill = "skyblue") +
  coord_flip() +
  labs(title = "Top 10 thành phố có khách hàng nhiều nhất", x = "Thành phố", y = "Số lượng") +
  theme_minimal()

Biểu đồ cho thấy Salem có số lượng khách hàng cao nhất, theo sau là TacomaLos Angeles. Top 10 tập trung chủ yếu ở các thành phố phía Tây nước Mỹ. Sự chênh lệch rõ rệt giữa các thành phố đầu và cuối danh sách.

Bang hoặc tỉnh (State or Province) 

state_freq <- data %>% count(StateorProvince, sort = TRUE) %>% slice(1:10)
state_freq
##    StateorProvince    n
## 1               WA 4567
## 2               CA 2733
## 3               OR 2262
## 4        Zacatecas 1297
## 5               DF  815
## 6               BC  809
## 7          Yucatan  654
## 8         Veracruz  464
## 9         Guerrero  383
## 10         Jalisco   75
ggplot(state_freq, aes(x = reorder(StateorProvince, n), y = n)) +
  geom_col(fill = "seagreen") +
  coord_flip() +
  labs(title = "Top 10 bang có khách hàng nhiều nhất", x = "Bang", y = "Số lượng") +
  theme_minimal()

Biểu đồ cho thấy bang Washington (WA) có số lượng khách hàng cao nhất, theo sau là California (CA)Oregon (OR). Ngoài các bang của Mỹ, dữ liệu còn ghi nhận khách hàng từ một số bang của Mexico như ZacatecasDistrito Federal. Sự chênh lệch lớn giữa các bang cho thấy khách hàng tập trung chủ yếu ở khu vực Tây Bắc nước Mỹ.

Quốc gia (Country)

country_freq <- data %>% count(Country, sort = TRUE)
country_freq
##   Country    n
## 1     USA 9562
## 2  Mexico 3688
## 3  Canada  809
ggplot(country_freq, aes(x = reorder(Country, n), y = n)) +
  geom_col(fill = "purple") +
  coord_flip() +
  labs(title = "Phân phối khách hàng theo quốc gia", x = "Quốc gia", y = "Số lượng") +
  theme_minimal()

Biểu đồ cho thấy khách hàng tập trung chủ yếu tại Hoa Kỳ (USA), chiếm phần lớn so với các quốc gia còn lại. Mexico là quốc gia có số lượng khách hàng nhiều thứ hai, tuy nhiên cách biệt khá lớn. Điều này cho thấy thị trường chính của siêu thị là tại Mỹ. Biểu đồ trực quan, dễ hiểu với màu sắc nổi bật.

4.3. Thông tin sản phẩm

Nhóm sản phẩm (Product Family)

family_freq <- data %>% count(ProductFamily, sort = TRUE)
family_freq
##    ProductFamily     n
## 1           Food 10153
## 2 Non-Consumable  2656
## 3          Drink  1250
ggplot(family_freq, aes(x = reorder(ProductFamily, n), y = n)) +
  geom_col(fill = "coral") +
  coord_flip() +
  labs(title = "Phân phối theo nhóm sản phẩm", x = "Nhóm sản phẩm", y = "Số lượng") +
  theme_minimal()

Biểu đồ cho thấy nhóm sản phẩm Food (Thực phẩm) chiếm số lượng giao dịch cao nhất, vượt trội so với các nhóm còn lại như Drink (Đồ uống)Non-Consumable (Hàng không tiêu dùng). Điều này phản ánh nhu cầu tiêu dùng thực phẩm là chủ yếu tại siêu thị. Biểu đồ rõ ràng, dễ đọc và trực quan.

Bộ phận sản phẩm (Product Department)

dept_freq <- data %>% count(ProductDepartment, sort = TRUE)
dept_freq
##      ProductDepartment    n
## 1              Produce 1994
## 2          Snack Foods 1600
## 3            Household 1420
## 4         Frozen Foods 1382
## 5         Baking Goods 1072
## 6         Canned Foods  977
## 7                Dairy  903
## 8   Health and Hygiene  893
## 9                 Deli  699
## 10           Beverages  680
## 11         Baked Goods  425
## 12 Alcoholic Beverages  356
## 13              Snacks  352
## 14       Starchy Foods  277
## 15         Periodicals  202
## 16                Eggs  198
## 17     Breakfast Foods  188
## 18     Canned Products  109
## 19             Seafood  102
## 20                Meat   89
## 21            Checkout   82
## 22            Carousel   59
ggplot(dept_freq, aes(x = reorder(ProductDepartment, n), y = n)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(title = "Phân phối theo phòng ban sản phẩm", x = "Phòng ban", y = "Số lượng") +
  theme_minimal()

Biểu đồ cho thấy các phòng ban như Snacks, BeveragesDairy có số lượng giao dịch cao nhất. Điều này phản ánh thói quen tiêu dùng phổ biến là các sản phẩm ăn uống nhanh. Phân phối giữa các phòng ban khá đa dạng, biểu đồ trình bày rõ ràng và dễ hiểu.

Loại sản phẩm (Product Category)

cat_freq <- data %>% count(ProductCategory, sort = TRUE) %>% slice(1:15)
cat_freq
##      ProductCategory    n
## 1         Vegetables 1728
## 2        Snack Foods 1600
## 3              Dairy  903
## 4              Fruit  765
## 5               Meat  761
## 6   Jams and Jellies  588
## 7       Baking Goods  484
## 8              Bread  425
## 9    Breakfast Foods  417
## 10       Canned Soup  404
## 11 Bathroom Products  365
## 12     Beer and Wine  356
## 13        Electrical  355
## 14             Candy  352
## 15    Paper Products  345
ggplot(cat_freq, aes(x = reorder(ProductCategory, n), y = n)) +
  geom_col(fill = "darkorange") +
  coord_flip() +
  labs(title = "Top 15 loại sản phẩm phổ biến", x = "Loại sản phẩm", y = "Số lượng") +
  theme_minimal()

Biểu đồ hiển thị 15 loại sản phẩm phổ biến nhất.

  1. Hàng đầu: “Vegetables” (Rau củ) dẫn đầu về số lượng, cho thấy nhu cầu cao về thực phẩm tươi.

  2. Xu hướng: “Snack Foods” và “Dairy” cũng phổ biến, phản ánh thói quen ăn uống đa dạng.

  3. Tiện lợi: Các sản phẩm như “Bread” và “Canned Soup” cho thấy sự ưa chuộng thực phẩm tiện lợi.

Tổng quan, nhu cầu cao đối với thực phẩm tươi sống và tiện lợi.

4.4 Kết luận cho phần định tính

  • Các biến định tính giúp hiểu sâu hơn về đặc điểm tập khách hàng như giới tính, hôn nhân, nơi sống.

  • Các đặc tính sản phẩm và phân phối địa lý cung cấp bức tranh tổng thể giúp định vị thị trường tiềm năng hoặc điều chỉnh danh mục sản phẩm phù hợp với từng khu vực.

5. Kết luận

Thông qua thống kê mô tả chi tiết:

  • Các biến định lượng phản ánh sự phân tán lớn giữa các nhóm khách hàng và sản phẩm.

  • Các biến định tính cho thấy sự đa dạng trong tập khách hàng và danh mục hàng hóa.

  • Doanh thu tập trung ở một số bang, thành phốnhóm sản phẩm nhất định, mở ra cơ hội tối ưu hóa chiến lược kinh doanh.

Thống kê mô tả là bước nền tảng không thể thiếu trước khi tiến hành các kỹ thuật phân tích dữ liệu nâng cao như clustering, phân tích RFM, hoặc mô hình hóa hành vi tiêu dùng.

LS0tDQp0aXRsZTogIk5oaeG7h20gduG7pSB0deG6p24gMSINCmF1dGhvcjogIkzDom0gVMOibSBOaMawIg0KZGF0ZTogIjIwMjUtMDUtMTkiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2M6IHRydWUNCiAgcGRmX2RvY3VtZW50Og0KICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleA0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCmBgYHs9aHRtbH0NCjxzdHlsZT4NCmJvZHkgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIHNhbnMtc2VyaWY7DQogIGZvbnQtc2l6ZTogMTZweDsNCiAgdGV4dC1hbGlnbjoganVzdGlmeTsNCiAgbGluZS1oZWlnaHQ6IDEuNTsNCn0NCmgyIHsNCiAgY29sb3I6IHJlZDsNCn0NCmgzIHsNCiAgY29sb3I6IGRhcmtibHVlOw0KfQ0KPC9zdHlsZT4NCmBgYA0KIyAqKkLDgEkgVOG6rFAgMTogVMOTTSBU4bquVCBDVeG7kE4gU8OBQ0ggIkdlbmVyYWxpemVkIExpbmVhciBNb2RlbHMgV2l0aCBFeGFtcGxlcyBpbiBSICgyMDE5KSIqKg0KDQpExrDhu5tpIMSRw6J5IGzDoCBi4bqjbiAqKnTDs20gdOG6r3QgY3Xhu5FuIHPDoWNoICoiR2VuZXJhbGl6ZWQgTGluZWFyIE1vZGVscyBXaXRoIEV4YW1wbGVzIGluIFIiKiAoMjAxOSkqKiBj4bunYSAqKlBldGVyIEsuIER1bm4gdsOgIEdvcmRvbiBLLiBTbXl0aCoqLCBt4buZdCB0w6BpIGxp4buHdSBy4bqldCBjw7MgZ2nDoSB0cuG7iyBjaG8gbmjhu69uZyBuZ8aw4budaSBo4buNYyBob+G6t2Mg4bupbmcgZOG7pW5nICoqR2VuZXJhbGl6ZWQgTGluZWFyIE1vZGVscyAoR0xNKSoqLCDEkeG6t2MgYmnhu4d0IGzDoCB24bubaSBuZ8O0biBuZ+G7ryAqKlIqKi4NCg0KIyMgKipDSMavxqBORyAxOiBNw5QgSMOMTkggVEjhu5BORyBLw4ogKFNUQVRJU1RJQ0FMIE1PREVMUykqKg0KDQojIyMgKioxLjEgR2nhu5tpIHRoaeG7h3UqKg0KDQpNw7QgaMOsbmggdGjhu5FuZyBrw6ogxJHGsOG7o2MgaGnhu4N1IGzDoCBjw7RuZyBj4bulIMSR4buDIG3DtCB04bqjIHbDoCBsw70gZ2nhuqNpIGThu68gbGnhu4d1LiBHTE1zIGzDoCBt4buZdCBs4bubcCBjb24gY+G7p2EgbcO0IGjDrG5oIGjhu5NpIHF1eSwgY2hvIHBow6lwIG3DtCBow6xuaCBow7NhIG5oaeG7gXUgZOG6oW5nIHBow6JuIHBo4buRaSBraMOhYyBuaGF1IG5nb8OgaSBjaHXhuqluLg0KDQojIyMgKioxLjIgQ8OhY2ggbcO0IHThuqMgZOG7ryBsaeG7h3UqKg0KDQoqKlbDrSBk4bulIDEuMTogROG7ryBsaeG7h3UgZHVuZyB0w61jaCBwaOG7lWkgY+G7p2EgdGhhbmggdGhp4bq/dSBuacOqbioqDQoNCi0gICBE4buvIGxp4buHdSB04burIDY1NCB0aGFuaCB0aGnhur91IG5pw6puIOG7nyBCb3N0b247DQoNCi0gICBCaeG6v246IHR14buVaSwgZHVuZyB0w61jaCBwaOG7lWkgKEZFViksIGNoaeG7gXUgY2FvLCBnaeG7m2kgdMOtbmgsIHTDrG5oIHRy4bqhbmcgaMO6dCB0aHXhu5FjLg0KDQoqKk3DoyBSOioqIGBsaWJyYXJ5KEdMTXNEYXRhKSBkYXRhKGx1bmdjYXApIGhlYWQobHVuZ2NhcClgDQoNCioqS+G6v3QgcXXhuqM6KiogZOG7ryBsaeG7h3UgZ+G7k20gY8OhYyBiaeG6v24gYEFnZWAsIGBGRVZgLCBgSHRgLCBgR2VuZGVyYCwgYFNtb2tlYC4NCg0KIyMjICoqMS4zIFbhur0gxJHhu5MgdGjhu4sqKg0KDQotICAgVmnhu4djIHbhur0gxJHhu5MgdGjhu4sgZ2nDunAga2jDoW0gcGjDoSDEkeG6t2MgxJFp4buDbSBj4bunYSBk4buvIGxp4buHdS4NCg0KLSAgIETDuW5nIFIgxJHhu4MgYmnhu4N1IGRp4buFbiBt4buRaSBxdWFuIGjhu4cgZ2nhu69hIGJp4bq/biDEkeG7mWMgbOG6rXAgdsOgIGJp4bq/biBwaOG6o24gaOG7k2kuDQoNCioqVsOtIGThu6UgbcOjIFI6KiogYHBsb3QoRkVWIH4gQWdlLCBkYXRhPWx1bmdjYXApYA0KDQojIyMgKioxLjQgTcOjIGjDs2EgYmnhur9uIHBow6JuIGxv4bqhaSoqDQoNCi0gICBCaeG6v24gcGjDom4gbG/huqFpIG5oxrAgYEdlbmRlcmAgY+G6p24gbcOjIGjDs2EgKGTDuW5nIGR1bW15IHZhcmlhYmxlcykgxJHhu4MgxJHGsGEgdsOgbyBtw7QgaMOsbmguDQoNCi0gICBSIHPhu60gZOG7pW5nICoqdHJlYXRtZW50IGNvZGluZyoqIGzDoG0gbeG6t2MgxJHhu4tuaC4NCg0KYGx1bmdjYXAkR2VuZGVyIDwtIGZhY3RvcihsdW5nY2FwJEdlbmRlcikgY29udHJhc3RzKGx1bmdjYXAkR2VuZGVyKWANCg0KIyMjICoqMS41IFRow6BuaCBwaOG6p24gY+G7p2EgbcO0IGjDrG5oIHRo4buRbmcga8OqKioNCg0KLSAgICoqVGjDoG5oIHBo4bqnbiBo4buHIHRo4buRbmcgKHN5c3RlbWF0aWMgY29tcG9uZW50KSoqOiBiaeG6v24gZ2nhuqNpIHRow61jaCwga+G6v3QgaOG7o3AgdHV54bq/biB0w61uaC4NCg0KLSAgICoqVGjDoG5oIHBo4bqnbiBuZ+G6q3Ugbmhpw6puIChyYW5kb20gY29tcG9uZW50KSoqOiBtw7QgdOG6oyBz4buxIGJp4bq/biDEkeG7lWkga2jDtG5nIGdp4bqjaSB0aMOtY2ggxJHGsOG7o2MuDQoNCiMjIyAqKjEuNiBHaeG7m2kgdGhp4buHdSBtw7QgaMOsbmggaOG7k2kgcXV5KioNCg0KLSAgIE3DtCBow6xuaCBo4buTaSBxdXkgdHV54bq/biB0w61uaCBsw6AgdHLGsOG7nW5nIGjhu6NwIMSR4bq3YyBiaeG7h3Q6IFwkXCRZX2kgPSBcXGJldGFfMCArIFxcYmV0YV8xIFhfaSArIFxcZXBzaWxvbl9pXCRcJA0KDQotICAgVOG6pXQgY+G6oyBjw6FjIG3DtCBow6xuaCB0cm9uZyBzw6FjaCDEkeG7gXUgbMOgIG3DtCBow6xuaCBo4buTaSBxdXkuDQoNCiMjIyAqKjEuNyBHaeG6o2kgdGjDrWNoIG3DtCBow6xuaCBo4buTaSBxdXkqKg0KDQotICAgQ+G6p24gaGnhu4N1IMO9IG5naMSpYSB0aOG7kW5nIGvDqiB2w6AgdGjhu7FjIG5naGnhu4dtIGPhu6dhIGPDoWMgdGhhbSBz4buRIHRyb25nIG3DtCBow6xuaC4NCg0KIyMjICoqMS44IOKAkyAxLjEyIEPDoWMgY2jhu6cgxJHhu4EgdHJp4bq/dCBsw70gdsOgIHRo4buxYyBow6BuaCoqDQoNCi0gICDigJxU4bqldCBj4bqjIG3DtCBow6xuaCDEkeG7gXUgc2FpLCBuaMawbmcgbeG7mXQgc+G7kSB0aMOsIGjhu691IMOtY2jigJ0gKEJveCAmIERyYXBlcik7DQoNCi0gICBN4bulYyDEkcOtY2ggY+G7p2EgbcO0IGjDrG5oOiBoaeG7g3UgZOG7ryBsaeG7h3UgaG/hurdjIGThu7EgxJFvw6FuOw0KDQotICAgxJDDoW5oIGdpw6EgbcO0IGjDrG5oIGThu7FhIHRyw6puICoqdMOtbmggY2jDrW5oIHjDoWMqKiAoYWNjdXJhY3kpIHbDoCAqKnPhu7EgxJHGoW4gZ2nhuqNuKiogKHBhcnNpbW9ueSk7DQoNCi0gICBTbyBzw6FuaCBk4buvIGxp4buHdSBxdWFuIHPDoXQgdsOgIGThu68gbGnhu4d1IHRo4buxYyBuZ2hp4buHbTsNCg0KLSAgIFThu5VuZyBxdcOhdCBow7NhIGvhur90IHF14bqjIHThu6sgbeG6q3UgxJHhur9uIHF14bqnbiB0aOG7gy4NCg0KIyMjICoqMS4xMzogR2nhu5tpIHRoaeG7h3UgduG7gSBz4butIGThu6VuZyBSKioNCg0KLSAgIFIgbMOgIGPDtG5nIGPhu6UgY2jDrW5oIMSR4buDIHjDonkgZOG7sW5nIG3DtCBow6xuaCB0aOG7kW5nIGvDqjsNCg0KLSAgIEPDoWMgY2jhu6ljIG7Eg25nIG5oxrAgYGxtKClgLCBgcGxvdCgpYCwgYHN1bW1hcnkoKWAgxJHGsOG7o2Mgc+G7rSBk4bulbmcgeHV5w6puIHN14buRdC4NCg0KKipCw4BJIFThuqxQICYgTcODIFIgVEjhu7BDIEjDgE5IKioNCg0KKipWw60gZOG7pSB24bubaSBk4buvIGxp4buHdSBjcmFiczoqKiBgbGlicmFyeShHTE1zRGF0YSkgZGF0YShoY3JhYnMpIHN1bW1hcnkoaGNyYWJzKSBwbG90KHkgfiB3ZWlnaHQsIGRhdGEgPSBoY3JhYnMpYA0KDQotICAgWcOqdSBj4bqndSB4w6FjIMSR4buLbmggbG/huqFpIGJp4bq/biwgeOG7rSBsw70gYmnhur9uIHBow6JuIGxv4bqhaSwga2nhu4NtIHRyYSB0w61uaCBwaMO5IGjhu6NwIGPhu6dhIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIHZzLiBHTE0uDQoNCioqS+G6v3QgbHXhuq1uIGNoxrDGoW5nIDEqKg0KDQpDaMawxqFuZyAxIMSRw7NuZyB2YWkgdHLDsiDEkeG7i25oIGjGsOG7m25nIHRyaSB0aOG7qWMgbuG7gW4gdOG6o25nIHbhu4EgbcO0IGjDrG5oIGjDs2EgdGjhu5FuZyBrw6osIG5o4bqlbiBt4bqhbmggdMawIGR1eSBwaMOibiB0w61jaCBk4buvIGxp4buHdSwgaGnhu4N1IMSR4bq3YyB0w61uaCBk4buvIGxp4buHdSB2w6AgY2h14bqpbiBi4buLIGNobyBjw6FjIGNoxrDGoW5nIHbhu4EgR0xNcy4NCg0KIyMgKipDSMavxqBORyAyOiBNw5QgSMOMTkggSOG7kkkgUVVZIFRVWeG6vk4gVMONTkggKExJTkVBUiBSRUdSRVNTSU9OIE1PREVMUykqKg0KDQojIyMgKioyLjEgR2nhu5tpIHRoaeG7h3UgdOG7lW5nIHF1YW4qKg0KDQotICAgSOG7k2kgcXV5IHR1eeG6v24gdMOtbmggbMOgIG3DtCBow6xuaCBwaOG7lSBiaeG6v24gbmjhuqV0IHRyb25nIHRo4buRbmcga8OqLg0KDQotICAgTcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIGzDoCAqKnRyxrDhu51uZyBo4bujcCDEkeG6t2MgYmnhu4d0IGPhu6dhIEdMTSoqIHbhu5tpIHBow6JuIHBo4buRaSBjaHXhuqluIHbDoCBow6BtIGxpw6puIGvhur90IGzDoCBow6BtIMSR4buTbmcgbmjhuqV0Lg0KDQojIyMgKioyLjIgxJDhu4tuaCBuZ2jEqWEgbcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oKioNCg0KTcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIGPDsyBoYWkgdGjDoG5oIHBo4bqnbjoNCg0KLSAgIE5n4bqrdSBuaGnDqm46IFwkXCRcXG9wZXJhdG9ybmFtZXtWYXJ9KHlfaSkgPSBcXGZyYWN7XFxzaWdtYVxeMn17d19pfVwkXCQgduG7m2kgJHdfaSQgbMOgIHRy4buNbmcgc+G7kS4NCg0KLSAgIEjhu4cgdGjhu5FuZzogXCRcJFxcbXVfaSA9IFxcYmV0YV8wICsgXFxzdW1cX3tqPTF9XF57cH0gXFxiZXRhX2ogeFxfe2lqfVwkXCQNCg0KLSAgIEJp4buDdSBkaeG7hW4gdOG7lW5nIHF1w6F0OiBcJFwkXFxiZWdpbntjYXNlc31cXG9wZXJhdG9ybmFtZXtWYXJ9KHlfaSkgPSBcXGZyYWN7XFxzaWdtYVxeMn17d19pfSBcXFxcXFxtdV9pID0gXFxiZXRhXzAgKyBcXGJldGFfMSB4XF97aTF9ICsgXFxjZG90cyArIFxcYmV0YV9wIHhcX3tpcH1cXGVuZHtjYXNlc31cJFwkDQoNCiMjIyAqKjIuMyDGr+G7m2MgbMaw4bujbmcgYsOsbmggcGjGsMahbmcgdOG7kWkgdGhp4buDdSAoT0xTKSDigJMgaOG7k2kgcXV5IMSRxqFuKioNCg0KLSAgIEdp4bqjaSBwaMOhcCBj4buVIMSRaeG7g24gxJHhu4MgxrDhu5tjIGzGsOG7o25nIGPDoWMgaOG7hyBz4buRIGjhu5NpIHF1eTsNCg0KLSAgIEThu4UgdMOtbmggdG/DoW4sIGdp4bqjaSB0w61jaCByw7UgcsOgbmc7DQoNCi0gICBU4buRaSB0aGnhu4N1IGjDs2EgdOG7lW5nIGLDrG5oIHBoxrDGoW5nIHNhaSBz4buRLg0KDQoqKlbDrSBk4bulIG3DoyBSOioqIGBtb2RlbCA8LSBsbShGRVYgfiBBZ2UsIGRhdGEgPSBsdW5nY2FwKSBzdW1tYXJ5KG1vZGVsKWANCg0KIyMjICoqMi40ICYgMi41IEjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIGLhu5lpKioNCg0KLSAgIE3hu58gcuG7mW5nIHThu6sgaOG7k2kgcXV5IMSRxqFuIHNhbmcgbmhp4buBdSBiaeG6v24gZ2nhuqNpIHRow61jaC4NCg0KLSAgIEPDsyB0aOG7gyBiYW8gZ+G7k20gYmnhur9uIMSR4buLbmggdMOtbmggdGjDtG5nIHF1YSBiaeG6v24gZ2nhuqMgKGR1bW15KS4NCg0KLSAgIEtodXnhur9uIG5naOG7iyBraeG7g20gdHJhIHTGsMahbmcgcXVhbiwgxJFhIGPhu5luZyB0dXnhur9uLg0KDQoqKlbDrSBk4bulIG3DoyBSOioqIGBtb2RlbDIgPC0gbG0oRkVWIH4gQWdlICsgSHQgKyBHZW5kZXIgKyBTbW9rZSwgZGF0YSA9IGx1bmdjYXApIHN1bW1hcnkobW9kZWwyKWANCg0KIyMjICoqMi42IFPhu60gZOG7pW5nIFIgxJHhu4MgxrDhu5tjIGzGsOG7o25nIG3DtCBow6xuaCoqDQoNCi0gICBIw6BtIGBsbSgpYCDEkeG7gyDGsOG7m2MgbMaw4bujbmc7DQoNCi0gICBDw6FjIGjDoG0gYHBsb3QoKWAsIGByZXNpZHVhbHMoKWAsIGBmaXR0ZWQoKWAsIGBhbm92YSgpYCDEkeG7gyBraeG7g20gdHJhIGNo4bqpbiDEkW/DoW4uDQoNCioqTcOjIHbDrSBk4bulOioqIGBwbG90KHJlc2lkdWFscyhtb2RlbCkgfiBmaXR0ZWQobW9kZWwpKWANCg0KIyMjICoqMi43IEdp4bqjaSB0aMOtY2ggbcO0IGjDrG5oIGjhu5NpIHF1eSoqDQoNCi0gICBN4buXaSBo4buHIHPhu5EgJM6yauKAiyQgdGjhu4MgaGnhu4duIHRoYXkgxJHhu5VpIGvhu7MgduG7jW5nIGPhu6dhICR5JCDhu6luZyB24bubaSBt4buZdCDEkcahbiB24buLIHRoYXkgxJHhu5VpIGPhu6dhICR4X2okICwgZ2nhu68gbmd1ecOqbiBjw6FjIGJp4bq/biBraMOhYy4NCg0KLSAgIFF1YW4gdHLhu41uZyB0cm9uZyB2aeG7h2Mgc3V5IGx14bqtbiB0aOG7sWMgbmdoaeG7h20gdOG7qyBr4bq/dCBxdeG6oyB0aOG7kW5nIGvDqi4NCg0KIyMjICoqMi44IFN1eSBsdeG6rW4gdGjhu5FuZyBrw6oqKg0KDQotICAgS2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3Q6ICRIXzA6zrJqPTAkDQoNCi0gICBLaG/huqNuZyB0aW4gY+G6rXkgY2hvIHThu6tuZyBo4buHIHPhu5EuDQoNCioqTcOjIFI6KiogYGNvbmZpbnQobW9kZWwpYA0KDQojIyMgKioyLjkgUGjDom4gdMOtY2ggcGjGsMahbmcgc2FpIChBTk9WQSkqKg0KDQotICAgS2nhu4NtIHRyYSB04buVbmcgcXXDoXQgeGVtIG3DtCBow6xuaCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIGtow7RuZy4NCg0KLSAgIELhuqNuZyBBTk9WQSBnacO6cCBraeG7g20gdHJhIOG6o25oIGjGsOG7n25nIGPhu6dhIHThu6tuZyBuaMOzbSBiaeG6v24gZ2nhuqNpIHRow61jaC4NCg0KIyMjICoqMi4xMCBTbyBzw6FuaCBtw7QgaMOsbmggbOG7k25nIG5oYXUqKg0KDQotICAgRMO5bmcga2nhu4NtIMSR4buLbmggRiBob+G6t2Mga2nhu4NtIMSR4buLbmggRGV2aWFuY2UgxJHhu4Mgc28gc8OhbmggbcO0IGjDrG5oIHThu5VuZyBxdcOhdCB2w6AgbcO0IGjDrG5oIGNvbi4NCg0KIyMjICoqMi4xMSBTbyBzw6FuaCBtw7QgaMOsbmgga2jDtG5nIGzhu5NuZyBuaGF1KioNCg0KLSAgIFPhu60gZOG7pW5nIHRpw6p1IGNow60gbOG7sWEgY2jhu41uIG3DtCBow6xuaDogQUlDIHbDoCBCSUMuDQoNCiMjIyAqKjIuMTIgTOG7sWEgY2jhu41uIG3DtCBow6xuaCoqDQoNCi0gICBDw6FjIGNoaeG6v24gbMaw4bujYyBuaMawIGzhu7FhIGNo4buNbiB0aeG6v24sIGzDuWksIGhv4bq3YyB04burbmcgYsaw4bubYy4NCg0KLSAgIFIgaOG7lyB0cuG7oyBow6BtIGBzdGVwKClgIMSR4buDIHThu7EgxJHhu5luZyBow7NhLg0KDQoqKk3DoyBSOioqIGBzdGVwKG1vZGVsMilgDQoNCioqVOG7lW5nIGvhur90IGNoxrDGoW5nKioNCg0KQ2jGsMahbmcgbsOgeSB4w6J5IGThu7FuZyBu4buBbiB04bqjbmcgdG/DoW4gaOG7jWMgdsOgIGzhuq1wIHRyw6xuaCBjaG8gaOG7k2kgcXV5IHR1eeG6v24gdMOtbmgsIHThu6sgxJHDsyBt4bufIMSRxrDhu51uZyBjaG8gdmnhu4djIGjhu41jIHbDoCDhu6luZyBk4bulbmcgR0xNcy4gTsOzIGPFqW5nIGNo4buJIHJhIHLDtToNCg0KLSAgIFPhu6ljIG3huqFuaCBtw7QgaMOsbmggdHV54bq/biB0w61uaDsNCg0KLSAgIEPDoWMgZ2nhu5tpIGjhuqFuIHbhu4EgZ2nhuqMgxJHhu4tuaCBwaMOibiBwaOG7kWkgY2h14bqpbiB2w6AgcGjGsMahbmcgc2FpIGtow7RuZyDEkeG7lWk7DQoNCkPDoWNoIGTDuW5nIFIgxJHhu4MgbcO0IGjDrG5oIGjDs2EgdGjhu7FjIHThur8gdsOgIGtp4buDbSB0cmEgbcO0IGjDrG5oLg0KDQojIyAqKkNIxq/GoE5HIDM6IFBIw4JOIFTDjUNIIFBIxq/GoE5HIFNBSSAoQU5PVkEpKioNCg0KIyMjICoqMy4xIEdp4bubaSB0aGnhu4d1KioNCg0KLSAgICoqQU5PVkEgKEFuYWx5c2lzIG9mIFZhcmlhbmNlKSoqIMSRxrDhu6NjIHRyw6xuaCBiw6B5IG5oxrAgbeG7mXQgdHLGsOG7nW5nIGjhu6NwIMSR4bq3YyBiaeG7h3QgY+G7p2EgbcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oLg0KDQotICAgQU5PVkEgZMO5bmcgxJHhu4Mga2nhu4NtIHRyYSB4ZW0gdHJ1bmcgYsOsbmggY+G7p2Egbmhp4buBdSBuaMOzbSBjw7Mga2jDoWMgYmnhu4d0IHRo4buRbmcga8OqIGhheSBraMO0bmcuDQoNCiMjIyAqKjMuMiBNw7QgaMOsbmggQU5PVkEgbeG7mXQgeeG6v3UgdOG7kSoqDQoNCi0gICBNw7QgaMOsbmggaMOzYSDhuqNuaCBoxrDhu59uZyBj4bunYSBt4buZdCB54bq/dSB04buRIHBow6JuIGxv4bqhaSAoY2F0ZWdvcmljYWwgZmFjdG9yKSDEkeG6v24gYmnhur9uIHBo4bqjbiBo4buTaS4NCg0KLSAgIFbDrSBk4bulOiBTbyBzw6FuaCB0cnVuZyBiw6xuaCDEkWnhu4NtIHRoaSBj4bunYSBjw6FjIGzhu5twIGjhu41jIGtow6FjIG5oYXUuDQoNCi0gICBCaeG7g3UgdGjhu6ljIG3DtCBow6xuaDoNCg0KJCQNCllfe2lqfSA9IFxtdSArIFxhbHBoYV9pICsgXGVwc2lsb25fe2lqfSwgXHF1YWQgXGVwc2lsb25fe2lqfSBcc2ltIFxtYXRoY2Fse059KDAsIFxzaWdtYV4yKQ0KJCQNCg0KKipNw6MgUjogbcO0IGjDrG5oIGjDs2EgQU5PVkEgbeG7mXQgY2hp4buBdSoqDQoNCmBtb2RlbDEgPC0gbG0oRkVWIH4gR3JvdXAsIGRhdGEgPSBsdW5nY2FwKSBhbm92YShtb2RlbDEpYA0KDQojIyMgKiozLjMgTcOjIGjDs2EgYmnhur9uIHBow6JuIGxv4bqhaSoqDQoNCi0gICBN4bq3YyDEkeG7i25oIHRyb25nIFIgbMOgICoqdHJlYXRtZW50IGNvZGluZyoqOiBuaMOzbSDEkeG6p3UgdGnDqm4gbMOgIHRoYW0gY2hp4bq/dSAocmVmZXJlbmNlIGdyb3VwKS4NCg0KLSAgIEPDsyB0aOG7gyB0aGF5IMSR4buVaSBjw6FjaCBtw6MgaMOzYSBi4bqxbmcgYGNvbnRyYXN0cygpYC4NCg0KKipWw60gZOG7pSBraeG7g20gdHJhIG3DoyBow7NhOioqIGBjb250cmFzdHMobHVuZ2NhcCRHcm91cClgDQoNCiMjIyAqKjMuNCBBTk9WQSBuaGnhu4F1IHnhur91IHThu5EqKg0KDQotICAgTeG7nyBy4buZbmcgbcO0IGjDrG5oIMSR4buDIHjDqXQgxJHhu5NuZyB0aOG7nWkgbmhp4buBdSB54bq/dSB04buRLg0KDQotICAgQmFvIGfhu5NtICoqbcO0IGjDrG5oIHTGsMahbmcgdMOhYyoqIG7hur91IGdp4bqjIHRodXnhur90IHbhu4Eg4bqjbmggaMaw4bufbmcgxJHhu5ljIGzhuq1wIGtow7RuZyDEkcO6bmcuDQoNCioqTcOjIFI6KiogYG1vZGVsMiA8LSBsbShGRVYgfiBHZW5kZXIgKiBTbW9rZSwgZGF0YSA9IGx1bmdjYXApIGFub3ZhKG1vZGVsMilgDQoNCiMjIyAqKjMuNSBQaMOibiB0w61jaCBi4bqjbmcgQU5PVkEqKg0KDQotICAgUGjDom4gdMOtY2ggcGjGsMahbmcgc2FpIGNoaWEgdOG7lW5nIHBoxrDGoW5nIHNhaSB0aMOgbmggY8OhYyB0aMOgbmggcGjhuqduOg0KDQogICAgLSAgICoqR2nhu69hIG5ow7NtKiogKGJldHdlZW4tZ3JvdXApLA0KDQogICAgLSAgICoqVHJvbmcgbmjDs20qKiAod2l0aGluLWdyb3VwIC8gcmVzaWR1YWwpLA0KDQogICAgLSAgIEtp4buDbSDEkeG7i25oIGLhurFuZyAqKkYtdGVzdCoqLg0KDQoqKkLhuqNuZyBBTk9WQSBt4bqrdToqKiBgYW5vdmEobW9kZWwyKSBzdW1tYXJ5KG1vZGVsMilgDQoNCiMjIyAqKjMuNiBIaeG7h3Ug4bupbmcgY2jDrW5oIHbDoCB0xrDGoW5nIHTDoWMqKg0KDQotICAgVMawxqFuZyB0w6FjIGNobyBiaeG6v3Qg4bqjbmggaMaw4bufbmcgY+G7p2EgbeG7mXQgeeG6v3UgdOG7kSB0aGF5IMSR4buVaSB0aGVvIGPhuqVwIMSR4buZIGPhu6dhIHnhur91IHThu5Ega2jDoWMuDQoNCi0gICBRdWFuIHPDoXQgdGjDtG5nIHF1YSBiaeG7g3UgxJHhu5MgaG/hurdjIGtp4buDbSDEkeG7i25oIG3DtCBow6xuaCBjw7MgdMawxqFuZyB0w6FjLg0KDQojIyMgKiozLjcgU28gc8Ohbmggbmhp4buBdSBuaMOzbSoqDQoNCi0gICBTYXUga2hpIHBow6F0IGhp4buHbiBz4buxIGtow6FjIGJp4buHdCB0b8OgbiBj4bulYyBi4bqxbmcgQU5PVkEsIGTDuW5nIGPDoWMga2nhu4NtIMSR4buLbmggKipzbyBzw6FuaCB04burbmcgY+G6t3AqKiAocG9zdC1ob2MgdGVzdHMpLCB2w60gZOG7pToNCg0KICAgIC0gICBUdWtleSdzIEhTRC4NCg0KICAgIC0gICBCb25mZXJyb25pLg0KDQoqKk3DoyBSIHbDrSBk4bulOiBUdWtleSBIU0QqKg0KDQpgVHVrZXlIU0QoYW92KG1vZGVsMSkpYA0KDQojIyMgKiozLjggS+G6v3QgbuG7kWkgZ2nhu69hIEFOT1ZBIHbDoCBo4buTaSBxdXkqKg0KDQotICAgQU5PVkEgbMOgIG3hu5l0IHRyxrDhu51uZyBo4bujcCBj4bunYSBtw7QgaMOsbmggaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggduG7m2kgYmnhur9uIHBow6JuIGxv4bqhaS4NCg0KLSAgIEPDoWMgaOG7hyBz4buRIGjhu5NpIHF1eSBiaeG7g3UgZGnhu4VuIHPhu7Ega2jDoWMgYmnhu4d0IGdp4buvYSBuaMOzbSB24bubaSBuaMOzbSB0aGFtIGNoaeG6v3UuDQoNCioqVOG7lW5nIGvhur90IGNoxrDGoW5nKioNCg0KLSAgICoqQU5PVkEqKiDEkcaw4bujYyBraMOhaSBxdcOhdCB0aMOgbmggbcO0IGjDrG5oIGjhu5NpIHF1eSwgdOG6oW8gY8ahIHPhu58gxJHhu4MgaGnhu4N1IEdMTXMuDQoNCi0gICBRdWFuIHRy4buNbmcgdHJvbmcgcGjDom4gdMOtY2ggdGhp4bq/dCBr4bq/IHRow60gbmdoaeG7h20uDQoNClIgY3VuZyBj4bqlcCBjw7RuZyBj4bulIG3huqFuaCBt4bq9IMSR4buDIHjDonkgZOG7sW5nIHbDoCBnaeG6o2kgdGjDrWNoIG3DtCBow6xuaCBBTk9WQSB24bubaSBgbG0oKWAgdsOgIGBhb3YoKWAuXA0KDQojIyAqKkNIxq/GoE5HIDQ6IMav4buaQyBMxq/hu6JORyBI4buiUCBMw50gQ+G7sEMgxJDhuqBJIChNQVhJTVVNIExJS0VMSUhPT0QgRVNUSU1BVElPTiAtIE1MRSkqKg0KDQojIyMgKio0LjEgR2nhu5tpIHRoaeG7h3UqKg0KDQotICAgVHLDrG5oIGLDoHkgcGjGsMahbmcgcGjDoXAgKirGsOG7m2MgbMaw4bujbmcgaOG7o3AgbMO9IGPhu7FjIMSR4bqhaSAoTUxFKSoqIG5oxrAgbMOgIG7hu4FuIHThuqNuZyB0aOG7kW5nIGvDqiBoaeG7h24gxJHhuqFpIMSR4buDIMaw4bubYyBsxrDhu6NuZyBjw6FjIHRoYW0gc+G7kSBtw7QgaMOsbmguDQoNCi0gICBNTEUgbMOgIHBoxrDGoW5nIHBow6FwIGNo4bunIHnhur91IGTDuW5nIHRyb25nIEdMTXMgxJHhu4MgxrDhu5tjIGzGsOG7o25nIGPDoWMgdGhhbSBz4buRIM6yIHbDoCBjw6FjIHRoYW0gc+G7kSBwaMawxqFuZyBzYWkvcGjDom4gdMOhbiAoz4YpLg0KDQojIyMgKio0LjLigJM0LjQgVOG7lW5nIHF1w6F0IGjDs2EgbcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oKioNCg0KLSAgIFThu6sgbcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIChPTFMpLCB04buVbmcgcXXDoXQgaMOzYSBi4bqxbmcgY8OhY2ggdGhheSBnaeG6oyDEkeG7i25oIHBow6JuIHBo4buRaSBjaHXhuqluIHNhbmcgYuG6pXQga+G7syBwaMOibiBwaOG7kWkgbsOgbyB0cm9uZyBo4buNIGjDoG0gbcWpLg0KDQotICAgROG6q24gbmjhuq1wIGtow6FpIG5p4buHbSAqKmjDoG0gaOG7o3AgbMO9IChsaWtlbGlob29kKSoqIHbDoCB2YWkgdHLDsiB0cm9uZyB0aOG7kW5nIGvDqiBzdXkgbHXhuq1uLg0KDQojIyMgKio0LjUgxq/hu5tjIGzGsOG7o25nIG3hu5l0IHRoYW0gc+G7kSBi4bqxbmcgTUxFKioNCg0KLSAgIFRoaeG6v3QgbOG6rXAgKipwaMawxqFuZyB0csOsbmggxJFp4buDbSAoc2NvcmUgZXF1YXRpb25zKSoqOiDEkeG6oW8gaMOgbSBsb2ctbGlrZWxpaG9vZCB0aGVvIHRoYW0gc+G7kS4NCg0KLSAgICoqTWEgdHLhuq1uIHRow7RuZyB0aW4gRmlzaGVyKio6IMSRbyDEkeG7mSBjaMOtbmggeMOhYyBj4bunYSDGsOG7m2MgbMaw4bujbmcuDQoNCi0gICDGr+G7m2MgbMaw4bujbmcgc2FpIHPhu5EgY2h14bqpbiBk4buxYSB0csOqbiBtYSB0cuG6rW4gdGjDtG5nIHRpbi4NCg0KKipNw6MgUiDEkcahbiBnaeG6o246KioNCg0KYCMgTcO0IHBo4buPbmcgbGlrZWxpaG9vZCBjaG8gcGjDom4gcGjhu5FpIEJlcm5vdWxsaSB0aGV0YSA8LSBzZXEoMC4wMSwgMC45OSwgbGVuZ3RoPTEwMCkgbGlrIDwtIGRiaW5vbSg3LCBzaXplPTEwLCBwcm9iPXRoZXRhKSBwbG90KHRoZXRhLCBsaWssIHR5cGU9ImwiLCBtYWluPSJMaWtlbGlob29kIGZ1bmN0aW9uIilgDQoNCiMjIyAqKjQuNiDGr+G7m2MgbMaw4bujbmcgbmhp4buBdSB0aGFtIHPhu5EqKg0KDQotICAgWOG7rSBsw70gbcO0IGjDrG5oIHbhu5tpIG5oaeG7gXUgdGhhbSBz4buRIGLhurFuZyBjw6FjaCBz4butIGThu6VuZyAqKsSR4bqhbyBow6BtIHJpw6puZyoqIHbDoCAqKnThu5FpIMawdSBow7NhIGjDoG0gbG9nLWxpa2VsaWhvb2QgxJFhIGJp4bq/bioqLg0KDQojIyMgKio0LjcgTUxFIGLhurFuZyDEkeG6oWkgc+G7kSBtYSB0cuG6rW4qKg0KDQotICAgQmnhu4N1IGRp4buFbiBwaMawxqFuZyB0csOsbmggxJFp4buDbSB2w6AgbWEgdHLhuq1uIHRow7RuZyB0aW4gYuG6sW5nIMSR4bqhaSBz4buRIG1hIHRy4bqtbiDEkeG7gyBk4buFIHThu5VuZyBxdcOhdCB2w6AgdHJp4buDbiBraGFpIHRyw6puIG3DoXkgdMOtbmguDQoNCi0gICBDaHXhuqluIGLhu4sgY2hvIHRodeG6rXQgdG/DoW4gKipGaXNoZXIgc2NvcmluZyoqIHRyb25nIEdMTXMuDQoNCiMjIyAqKjQuOCBGaXNoZXIgU2NvcmluZyDEkeG7gyB0w61uaCBNTEUqKg0KDQotICAgVGh14bqtdCB0b8OhbiBs4bq3cCDEkeG7gyB0w6xtIG5naGnhu4dtIHBoxrDGoW5nIHRyw6xuaCDEkWnhu4NtLg0KDQotICAgROG7hSBjw6BpIMSR4bq3dCB0cm9uZyBwaOG6p24gbeG7gW0gdGjhu5FuZyBrw6ogdsOgIGNow61uaCBsw6AgbuG7gW4gdOG6o25nIGPhu6dhIGjDoG0gYGdsbSgpYCB0cm9uZyBSLg0KDQojIyMgKio0LjkgVMOtbmggY2jhuqV0IGPhu6dhIE1MRSoqDQoNCi0gICAqKktow7RuZyBjaOG7h2NoIHRp4buHbSBj4bqtbioqLCBoaeG7h3UgcXXhuqMsIHBow6JuIHBo4buRaSBjaHXhuqluIGjDs2Ega2hpIG3huqt1IGzhu5tuLg0KDQotICAgR2nhuqNpIHRow61jaCByw7UgdmFpIHRyw7IgY+G7p2EgKipz4buRIGzGsOG7o25nIG3huqt1IGzhu5tuIChhc3ltcHRvdGljcykqKiB0cm9uZyB0aOG7kW5nIGvDqiBoaeG7h24gxJHhuqFpLg0KDQojIyMgKio0LjEwIEtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90KioNCg0KLSAgIEdp4bubaSB0aGnhu4d1IGJhIGxv4bqhaSBraeG7g20gxJHhu4tuaCB0aOG7kW5nIGvDqiB04burIE1MRToNCg0KICAgIC0gICAqKldhbGQgdGVzdCoqDQoNCiAgICAtICAgKipMaWtlbGlob29kIFJhdGlvIHRlc3QgKExSVCkqKg0KDQogICAgLSAgICoqU2NvcmUgdGVzdCoqDQoNCi0gICBN4buXaSBsb+G6oWkgY8OzIMawdS9uaMaw4bujYyDEkWnhu4NtIGtow6FjIG5oYXUgdMO5eSB2w6BvIGLDoGkgdG/DoW4uDQoNCiMjIyAqKjQuMTEgS2hv4bqjbmcgdGluIGPhuq15KioNCg0KLSAgIFjDonkgZOG7sW5nICoqa2hv4bqjbmcgdGluIGPhuq15IGNobyB04burbmcgdGhhbSBz4buRKiogZOG7sWEgdsOgbyBwaMOibiBwaOG7kWkgeOG6pXAgeOG7iSBjaHXhuqluIHbDoCBtYSB0cuG6rW4gdGjDtG5nIHRpbi4NCg0KIyMjICoqNC4xMiBTbyBzw6FuaCBtw7QgaMOsbmgga2jDtG5nIGzhu5NuZyBuaGF1KioNCg0KLSAgIEdp4bubaSB0aGnhu4d1IHRpw6p1IGNow606DQoNCiAgICAtICAgKipBSUMgKEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24pKioNCg0KICAgIC0gICAqKkJJQyAoQmF5ZXNpYW4gSW5mb3JtYXRpb24gQ3JpdGVyaW9uKSoqDQoNCi0gICBQaMO5IGjhu6NwIMSR4buDIGzhu7FhIGNo4buNbiBtw7QgaMOsbmggdHJvbmcgR0xNcy4NCg0KIyMjICoqNC4xMyBQaOG7pSBs4bulYzogTcOjIFIgw6FwIGThu6VuZyBjaG8gZOG7ryBsaeG7h3UgbcawYSBRdWlscGllKioNCg0KKipWw60gZOG7pSBtw6MgUjoqKg0KDQpgTWFrZU11IDwtIGZ1bmN0aW9uKHgsIGJldGEpeyAgIGV0YSA8LSB4ICUqJSBiZXRhICAgcmV0dXJuKDEgLyAoMSArIGV4cCgtZXRhKSkpIH0gIE1ha2VTY29yZSA8LSBmdW5jdGlvbih4LCB5LCBiZXRhKXsgICBtdSA8LSBNYWtlTXUoeCwgYmV0YSkgICByZXR1cm4odCh4KSAlKiUgKHkgLSBtdSkpIH1gDQoNCi0gICBNw6MgUiB04buxIHjDonkgZOG7sW5nIGzhuqFpIHRvw6BuIGLhu5kgdGh14bqtdCB0b8OhbiBNTEUgY2hvIGxvZ2lzdGljIHJlZ3Jlc3Npb24uDQoNCi0gICBNaW5oIGjhu41hIGNobyBxdcOhIHRyw6xuaCB0aOG7pyBjw7RuZyB0w61uaCB0b8OhbiBNTEUsIGNodeG6qW4gYuG7iyBjaG8gdmnhu4djIGTDuW5nIGjDoG0gYGdsbSgpYCDhu58gY8OhYyBjaMawxqFuZyBzYXUuDQoNCioqS+G6v3QgbHXhuq1uIGNoxrDGoW5nKioNCg0KLSAgICoqTUxFIGzDoCBjxqEgc+G7nyBjaG8gdOG6pXQgY+G6oyBjw6FjIG3DtCBow6xuaCBHTE0qKjogbcO0IGjDrG5oIGjDs2EgdOG7lW5nIHF1w6F0LCBraeG7g20gxJHhu4tuaCwgdsOgIGNo4buNbiBtw7QgaMOsbmggxJHhu4F1IGThu7FhIHbDoG8gbmd1ecOqbiBsw70gaOG7o3AgbMO9IGPhu7FjIMSR4bqhaS4NCg0KLSAgIENoxrDGoW5nIDQgbMOgIGLGsOG7m2MgY2h1eeG7g24gdOG7qyBo4buTaSBxdXkgdHV54bq/biB0w61uaCBj4buVIMSRaeG7g24gc2FuZyBjw6FjIHBoxrDGoW5nIHBow6FwIGhp4buHbiDEkeG6oWkgdsOgIGtow6FpIHF1w6F0IGjGoW4gY+G7p2EgR0xNcy4NCg0KLSAgIMSQxrDhu6NjIGjhu5cgdHLhu6MgbeG6oW5oIG3hur0gYuG6sW5nIGPDoWMgaMOgbSB2w6AgZ8OzaSBSLCDEkeG6t2MgYmnhu4d0IGzDoCBgZ2xtKClgLg0KDQojIyAqKkNIxq/GoE5HIDU6IEPhuqRVIFRSw5pDIEPhu6ZBIE3DlCBIw4xOSCBUVVnhur5OIFTDjU5IIFThu5RORyBRVcOBVCAoR0xNczogU1RSVUNUVVJFKSoqDQoNCiMjIyAqKjUuMSBHaeG7m2kgdGhp4buHdSoqDQoNCi0gICBDaHV54buDbiB0aeG6v3AgdOG7qyBo4buTaSBxdXkgdHV54bq/biB0w61uaCAoZ2nhuqMgxJHhu4tuaCBwaMawxqFuZyBzYWkgaOG6sW5nIHPhu5EpIHNhbmcgR0xNIGNobyBwaMOpcCB44butIGzDvSBk4buvIGxp4buHdSBwaGkgY2h14bqpbiB2w6AgcGjGsMahbmcgc2FpIHRoYXkgxJHhu5VpLg0KDQotICAgR0xNIMSRxrDhu6NjIHjDonkgZOG7sW5nIHThu6sgaGFpIHRow6BuaCBwaOG6p24gY2jDrW5oOg0KDQogICAgLSAgICoqVGjDoG5oIHBo4bqnbiBuZ+G6q3Ugbmhpw6puKiogKHJhbmRvbSBjb21wb25lbnQpOw0KDQogICAgLSAgICoqVGjDoG5oIHBo4bqnbiBo4buHIHRo4buRbmcqKiAoc3lzdGVtYXRpYyBjb21wb25lbnQpLg0KDQojIyMgKio1LjIgSGFpIHRow6BuaCBwaOG6p24gY2jDrW5oIGPhu6dhIEdMTSoqDQoNCjEuICAqKk5n4bqrdSBuaGnDqm4qKjogQ2jhu41uIHBow6JuIHBo4buRaSB4w6FjIHN14bqldCBwaMO5IGjhu6NwICh0aMaw4budbmcgdGh14buZYyBo4buNICoqRXhwb25lbnRpYWwgRGlzcGVyc2lvbiBNb2RlbHMgLSBFRE1zKiopLg0KDQoyLiAgKipI4buHIHRo4buRbmcqKjogU+G7rSBk4bulbmcga+G6v3QgaOG7o3AgdHV54bq/biB0w61uaCB24bubaSBow6BtIGxpw6puIGvhur90IGcozrwpPc63ZyhcbXUpID0gXGV0YWcozrwpPc63LCB0cm9uZyDEkcOzIM63PVjOslxldGEgPSBYXGJldGHOtz1YzrIuDQoNCiMjIyAqKjUuMyBUaMOgbmggcGjhuqduIG5n4bqrdSBuaGnDqm46IEVETXMqKg0KDQotICAgR0xNIGdp4bqjIMSR4buLbmggeWniiLxFRE0ozrxpLM+VL3dpKXlfaSBcc2ltIFx0ZXh0e0VETX0oXG11XF9pLCBccGhpL3dfaSl5aeKAi+KIvEVETSjOvGnigIssz5Uvd2nigIspLg0KDQotICAgRURNIGJhbyBn4buTbTogUGjDom4gcGjhu5FpIGNodeG6qW4sIFBvaXNzb24sIG5o4buLIHRo4bupYywgZ2FtbWEsIGludmVyc2UgR2F1c3NpYW4sIG5lZ2F0aXZlIGJpbm9taWFsLC4uLg0KDQotICAgSMOgbSB4w6FjIHN14bqldCBjw7MgZOG6oW5nOg0KDQogICAgQmnhu4N1IHRo4bupYyBwaMOibiBwaOG7kWkgdGh14buZYyBo4buNIGjDoG0gbcWpOg0KDQogICAgJCQNCiAgICBQKHk7IFx0aGV0YSwgXHBoaSkgPSBhKHksIFxwaGkpXGV4cFxsZWZ0XHtcZnJhY3t5XHRoZXRhIC0gXGthcHBhKFx0aGV0YSl9e1xwaGl9XHJpZ2h0XH0NCiAgICAkJA0KDQotICAgSMOgbSB04bqhbyBraG/huqNuaCBraOG6r2MsIGjDoG0gdMOtY2ggbMWpeSAoY3VtdWxhbnQpLCB2w6AgaMOgbSBwaMawxqFuZyBzYWkgxJHDs25nIHZhaSB0csOyIHF1YW4gdHLhu41uZyDEkeG7gyBzdXkgbHXhuq1uLg0KDQojIyMgKio1LjQgROG6oW5nIHBow6JuIHTDoW4gY+G7p2EgRURNKioNCg0KLSAgIFRyw6xuaCBiw6B5IGPDoWNoIHZp4bq/dCBs4bqhaSBFRE0gxJHhu4MgZOG7hSB0w61uaCB0b8OhbiBkZXZpYW5jZS4NCg0KLSAgIEdp4bubaSB0aGnhu4d1ICoqdW5pdCBkZXZpYW5jZSoqOg0KDQogICAgVsOtIGThu6UgduG7m2kgcGjDom4gcGjhu5FpIFBvaXNzb24sIGjDoG0gZGV2aWFuY2UgY8OzIGThuqFuZzoNCg0KICAgICQkDQogICAgZCh5LCBcbXUpID0gMlxsZWZ0WyBcZnJhY3t5IC0gXG11fXtcbXV9ICsgXGxvZ1xsZWZ0KCBcZnJhY3tcbXV9e3l9IFxyaWdodCkgXHJpZ2h0XQ0KICAgICQkDQoNCi0gICAqKlNhZGRsZXBvaW50IGFwcHJveGltYXRpb24qKiDEkcaw4bujYyBkw7luZyDEkeG7gyBn4bqnbiDEkcO6bmcgcGjDom4gcGjhu5FpIGPhu6dhIGRldmlhbmNlLg0KDQojIyMgKio1LjUgVGjDoG5oIHBo4bqnbiBo4buHIHRo4buRbmcqKg0KDQotICAgQmFvIGfhu5NtOg0KDQogICAgLSAgICoqTGluZWFyIHByZWRpY3RvcioqOiDOtz3OsjArzrIxeDEr4ouvK86ycHhwXGV0YSA9IFxiZXRhXF8wICsgXGJldGFcXzF4XzEgKyBcY2RvdHMgKyBcYmV0YVxfcHhfcM63Pc6yMOKAiyvOsjHigIt4MeKAiyvii68rzrJw4oCLeHDigIs7DQoNCiAgICAtICAgKipIw6BtIGxpw6puIGvhur90IChsaW5rIGZ1bmN0aW9uKSoqOiBu4buRaSBr4bq/dCDOvD1FW3ldXG11ID0gRVt5Xc68PUVbeV0gduG7m2kgzrdcZXRhzrcuDQoNCi0gICBOZ2/DoGkgcmEgY8OybiBjw7MgdGjhu4MgdGjDqm0gKipvZmZzZXRzKiogKGJp4bq/biBj4buRIMSR4buLbmggdHJvbmcgbcO0IGjDrG5oKS4NCg0KIyMjICoqNS42IMSQ4buLbmggbmdoxKlhIGNow61uaCB0aOG7qWMgR0xNKioNCg0KLSAgIE3hu5l0IEdMTSDEkeG6p3kgxJHhu6c6DQoNCiAgICBCaeG7g3UgZGnhu4VuIHThu5VuZyBxdcOhdCBj4bunYSBtw7QgaMOsbmg6DQoNCiAgICAkJA0KICAgIFxiZWdpbntjYXNlc30NCiAgICB5X2kgXHNpbSBcdGV4dHtFRE19KFxtdV9pLCBccGhpL3dfaSkgXFwNCiAgICBnKFxtdV9pKSA9IG9faSArIFxiZXRhXzAgKyBcYmV0YV8xIHhfe2kxfSArIFxjZG90cyArIFxiZXRhX3AgeF97aXB9DQogICAgXGVuZHtjYXNlc30NCiAgICAkJA0KDQotICAgTcO0IGjDrG5oIMSRxrDhu6NjIGvDvSBoaeG7h3UgbmjGsDogYGdsbShQb2lzc29uOyBsb2cpYCBob+G6t2MgYGdsbShiaW5vbWlhbDsgbG9naXQpYCB0cm9uZyBSLg0KDQojIyMgKio1LjcgRGV2aWFuY2UgdOG7lW5nIHF1w6F0KioNCg0KLSAgICoqVOG7lW5nIGRldmlhbmNlKio6DQoNCiAgICDEkOG7mSBs4buHY2ggdOG7lW5nIChEZXZpYW5jZSkgdHJvbmcgbcO0IGjDrG5oIEdMTSDEkcaw4bujYyB0w61uaCBi4bufaToNCg0KICAgICQkDQogICAgRCh5LCBcbXUpID0gXHN1bV97aT0xfV5uIHdfaSBcLCBkKHlfaSwgXG11X2kpDQogICAgJCQNCg0KLSAgICoqU2NhbGVkIGRldmlhbmNlKio6DQoNCiAgICDEkOG7mSBs4buHY2ggY2h14bqpbiBow7NhIChzdGFuZGFyZGl6ZWQgZGV2aWFuY2UpIMSRxrDhu6NjIHTDrW5oIGLhu59pOg0KDQogICAgJCQNCiAgICBEXiooeSwgXG11KSA9IFxmcmFje0QoeSwgXG11KX17XHBoaX0NCiAgICAkJA0KDQotICAgS2hpIHNhZGRsZXBvaW50IGFwcHJveGltYXRpb24gxJHDum5nLCBzY2FsZWQgZGV2aWFuY2UgeOG6pXAgeOG7iSBwaMOibiBwaOG7kWkgY2hpIGLDrG5oIHBoxrDGoW5nLg0KDQojIyMgKio1LjggSOG7k2kgcXV5IGJp4bq/biDEkeG7lWkgdnMuIEdMTXMqKg0KDQotICAgU28gc8OhbmggR0xNcyB24bubaSBo4buTaSBxdXkgdHV54bq/biB0w61uaCBkw7luZyBiaeG6v24gxJHhu5VpICR5JC4NCg0KLSAgIE5o4bqlbiBt4bqhbmg6IEdMTSBnacO6cCBtw7QgaMOsbmggaMOzYSAkeSQgdHLhu7FjIHRp4bq/cCB0aGF5IHbDrCBiaeG6v24gxJHhu5VpIG7DsywgbMOgbSBjaG8gZ2nhuqNpIHRow61jaCB0aOG7kW5nIGvDqiByw7UgcsOgbmcgaMahbi4NCg0KKipL4bq/dCBsdeG6rW4gY2jGsMahbmcqKg0KDQotICAgQ2jGsMahbmcgNSB4w6J5IGThu7FuZyBj4bqldSB0csO6YyBsw70gdGh1eeG6v3QgY+G7kXQgbMO1aSBj4bunYSBHTE1zIGThu7FhIHRyw6puIGhhaSB0aMOgbmggcGjhuqduOiAqKnBow6JuIHBo4buRaSB4w6FjIHN14bqldCoqIChFRE1zKSB2w6AgKipsacOqbiBr4bq/dCB0dXnhur9uIHTDrW5oKiogKGjDoG0gbGnDqm4ga+G6v3QpLg0KDQotICAgR0xNIGNobyBwaMOpcCBsaW5oIGhv4bqhdCB0cm9uZyBtw7QgaMOsbmggaMOzYSBk4buvIGxp4buHdSBraMO0bmcgdHXDom4gY2h14bqpbiwgY8OzIHBoxrDGoW5nIHNhaSBiaeG6v24gxJHhu5VpLCBob+G6t2MgbMOgIHPhu5EgxJHhur9tLCB04bu3IGzhu4csIHYudi4NCg0KLSAgIEPGoSBz4bufIGNobyB2aeG7h2MgxrDhu5tjIGzGsOG7o25nLCBzdXkgbHXhuq1uIHbDoCBraeG7g20gxJHhu4tuaCDEkcaw4bujYyB0csOsbmggYsOgeSB0cm9uZyBjw6FjIGNoxrDGoW5nIHRp4bq/cCB0aGVvICg24oCTOCkuDQoNCiMjICoqQ0jGr8agTkcgNjogxq/hu5pDIEzGr+G7ok5HIFRST05HIEdMTSAoR0VORVJBTElaRUQgTElORUFSIE1PREVMUzogRVNUSU1BVElPTikqKg0KDQojIyMgKio2LjEgR2nhu5tpIHRoaeG7h3UqKg0KDQotICAgVHLDrG5oIGLDoHkgY8OhYyBr4bu5IHRodeG6rXQgxJHhu4MgxrDhu5tjIGzGsOG7o25nIHRoYW0gc+G7kSB0cm9uZyBHTE06IGjhu4cgc+G7kSBo4buTaSBxdXkgJM6yJCB2w6AgdGhhbSBz4buRIHBow6JuIHTDoW4gJM+VJCAobuG6v3UgY8OzKS4NCg0KLSAgIFPhu60gZOG7pW5nIHBoxrDGoW5nIHBow6FwICoqxrDhu5tjIGzGsOG7o25nIGjhu6NwIGzDvSBj4buxYyDEkeG6oWkgKE1MRSkqKiBsw6BtIGPGoSBz4bufLg0KDQojIyMgKio2LjIgxq/hu5tjIGzGsOG7o25nIHjDoWMgc3XhuqV0IGjhu6NwIGzDvSBjaG8gzrIqKg0KDQotICAgKipQaMawxqFuZyB0csOsbmggxJFp4buDbSAoc2NvcmUgZXF1YXRpb25zKSoqIHbDoCAqKm1hIHRy4bqtbiB0aMO0bmcgdGluKiogxJHGsOG7o2MgeMOieSBk4buxbmcgdOG7qyDEkeG6oW8gaMOgbSBsb2ctbGlrZWxpaG9vZC4NCg0KLSAgIFThu6sgYmnhu4N1IHRo4bupYyB4w6FjIHN14bqldCBk4bqhbmcgRURNLCB0aHUgxJHGsOG7o2M6DQoNCiAgICAkJA0KICAgIFxmcmFje1xwYXJ0aWFsIFxsb2cgUCh5O1xtdSxccGhpL3cpfXtccGFydGlhbCBcbXV9ID0gXGZyYWN7dyh5IC0gXG11KX17XHBoaSBWKFxtdSl9DQogICAgJCQNCg0KLSAgIFThu6sgxJHDsywgc3V5IHJhIMSR4bqhbyBow6BtIHRoZW8gdOG7q25nIGjhu4cgc+G7kSAkzrJqJOKAiyB2w6AgbWEgdHLhuq1uIHRow7RuZyB0aW4gRmlzaGVyIG3hu5l0IGPDoWNoIGPhu6UgdGjhu4MuDQoNCiMjIyAqKjYuMyBUw61uaCB0b8OhbiDGsOG7m2MgbMaw4bujbmcgzrIqKg0KDQotICAgw4FwIGThu6VuZyAqKnRodeG6rXQgdG/DoW4gbOG6t3AgTmV3dG9u4oCTUmFwaHNvbiBob+G6t2MgRmlzaGVyIFNjb3JpbmcqKiDEkeG7gyB0w6xtIMaw4bubYyBsxrDhu6NuZy4NCg0KLSAgIEJp4buDdSBkaeG7hW4gcXV5IHRyw6xuaCBs4bq3cDogdOG7qyBnacOhIHRy4buLIGJhbiDEkeG6p3Ug4oaSIHTDrW5oIHdvcmtpbmcgdmFsdWVzIOKGkiBj4bqtcCBuaOG6rXQgJM6yJC4NCg0KKipNw6MgUiAodsOtIGThu6UgUG9pc3NvbiBHTE0pOioqDQoNCmBsaWJyYXJ5KEdMTXNEYXRhKSBkYXRhKG5taW5lcikgbW9kZWwgPC0gZ2xtKE1pbmVyYWIgfiBFdWNzLCBkYXRhPW5taW5lciwgZmFtaWx5PXBvaXNzb24obGluaz0ibG9nIikpIHN1bW1hcnkobW9kZWwpYA0KDQo+IFIgc+G7rSBk4bulbmcgbuG7mWkgYuG7mSB0aHXhuq10IHRvw6FuIEZpc2hlciBzY29yaW5nIMSR4buDIMaw4bubYyBsxrDhu6NuZy4NCg0KIyMjICoqNi40IERldmlhbmNlIGPDsm4gbOG6oWkgKHJlc2lkdWFsIGRldmlhbmNlKSoqDQoNCi0gICBMw6AgdGjGsOG7m2MgxJFvIMSR4buZIHBow7kgaOG7o3AgY+G7p2EgbcO0IGjDrG5oOg0KDQogICAgJCQNCiAgICBEKHksIFxoYXR7XG11fSkgPSAyIFxzdW0gd19pIFxsZWZ0WyB5X2kgXGxvZyBcZnJhY3t5X2l9e1xoYXR7XG11fV9pfSAtICh5X2kgLSBcaGF0e1xtdX1faSkgXHJpZ2h0XQ0KICAgICQkDQoNCi0gICAqKlNjYWxlZCBkZXZpYW5jZSoqIMSRxrDhu6NjIGTDuW5nIMSR4buDIGtp4buDbSDEkeG7i25oIG3DtCBow6xuaCB0aMO0bmcgcXVhIHBow6JuIHBo4buRaSAkz4cyJC4NCg0KIyMjICoqNi41IFNhaSBz4buRIGNodeG6qW4gY+G7p2EgzrIqKg0KDQotICAgxq/hu5tjIGzGsOG7o25nIHThu6sgbmdo4buLY2ggxJHhuqNvIGPhu6dhIG1hIHRy4bqtbiB0aMO0bmcgdGluOg0KDQogICAgJCQNCiAgICBcdGV4dHtWYXJ9KFxoYXR7XGJldGF9KSA9IEleey0xfShcaGF0e1xiZXRhfSkNCiAgICAkJA0KDQojIyMgKio2LjYgROG6oW5nIG1hIHRy4bqtbiBj4bunYSBwaMawxqFuZyB0csOsbmggxrDhu5tjIGzGsOG7o25nKioNCg0KLSAgIE3DtCB04bqjIEdMTXMgdMawxqFuZyB04buxIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIHRow7RuZyBxdWE6DQoNCiAgICAkJA0KICAgIFxoYXR7XGJldGF9ID0gKFheVCBXIFgpXnstMX0gWF5UIFcgeg0KICAgICQkDQoNCi0gICBW4bubaToNCg0KICAgIC0gICAkdyQ6IG1hIHRy4bqtbiB0cuG7jW5nIHPhu5EgKHdvcmtpbmcgd2VpZ2h0cykNCg0KICAgIC0gICAkeiQ6IGJp4bq/biBwaOG7pSAod29ya2luZyByZXNwb25zZSkNCg0KIyMjICoqNi43IFNvIHPDoW5oIHbhu5tpIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oKioNCg0KLSAgIFF1w6EgdHLDrG5oIMaw4bubYyBsxrDhu6NuZyB0cm9uZyBHTE1zICoqeOG6pXAgeOG7iSB0dXnhur9uIHTDrW5oKiogdOG6oWkgbeG7l2kgYsaw4bubYyBs4bq3cDsNCg0KLSAgIE5o4bqlbiBt4bqhbmggc+G7sSB0xrDGoW5nIMSR4buTbmcgduG7gSBt4bq3dCBow6xuaCB0aOG7qWMgZ2nhu69hIEdMTXMgdsOgIG3DtCBow6xuaCBPTFMuDQoNCiMjIyAqKjYuOCDGr+G7m2MgbMaw4bujbmcgdGhhbSBz4buRIHBow6JuIHTDoW4qKiAkz5UkDQoNCkJhbyBn4buTbSA0IHBoxrDGoW5nIHBow6FwOg0KDQoxLiAgKipNTEUqKiAoduG7m2kgaMOgbSBsb2ctbGlrZWxpaG9vZCBwcm9maWxlKTsNCg0KMi4gICoqRGV2aWFuY2UgdHJ1bmcgYsOsbmgqKjoNCg0KICAgICQkDQogICAgXGhhdHtccGhpfSA9IFxmcmFje0QoeSwgXG11KX17XHRleHR7ZGZ9X3tcdGV4dHtyZXN9fX0NCiAgICAkJA0KDQozLiAgKipQZWFyc29uKio6ICQkDQogICAgXGhhdHtccGhpfSA9IFxzdW0gXGZyYWN7KHkgLSBcbXUpXjJ9e1xwaGkgVihcbXUpfQ0KICAgICQkDQoNCjQuICAqKkzhu7FhIGNo4buNbiB04buRaSDGsHUqKiB0w7l5IHRodeG7mWMgdsOgbyBwaMOibiBwaOG7kWkgY+G7pSB0aOG7gy4NCg0KKipWw60gZOG7pSBtw6MgUjoqKiBgc3VtbWFyeShtb2RlbCkkZGlzcGVyc2lvbiAgIyBQZWFyc29uIGVzdGltYXRvciBkZXZpYW5jZShtb2RlbCkgLyBkZi5yZXNpZHVhbChtb2RlbCkgICMgTWVhbiBkZXZpYW5jZSBlc3RpbWF0b3JgDQoNCiMjIyAqKjYuOSBT4butIGThu6VuZyBSIMSR4buDIGto4bubcCBHTE1zKioNCg0KLSAgIEjDoG0gY2jDrW5oOiBgZ2xtKClgLCB24bubaSBjw6FjIMSR4buRaSBz4buROg0KDQogICAgLSAgIGBmb3JtdWxhYDogY8O0bmcgdGjhu6ljIG3DtCBow6xuaDsNCg0KICAgIC0gICBgZmFtaWx5YDogY2jhu4kgxJHhu4tuaCBwaMOibiBwaOG7kWkgdsOgIGjDoG0gbGnDqm4ga+G6v3QuDQoNCioqVsOtIGThu6U6KiogYGdsbSh5IH4geDEgKyB4MiwgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpLCBkYXRhID0gZGYpIGdsbSh5IH4geDEgKyB4MiwgZmFtaWx5ID0gYmlub21pYWwsIGRhdGEgPSBkZilgDQoNClIgaOG7lyB0cuG7oyBjw6FjIGBmYW1pbHlgIHBo4buVIGJp4bq/bjogYGdhdXNzaWFuKClgLCBgcG9pc3NvbigpYCwgYGJpbm9taWFsKClgLCBgR2FtbWEoKWAsIGBpbnZlcnNlLmdhdXNzaWFuKClgLCBgcXVhc2koKWAsLi4uDQoNCiMjIyAqKjYuMTAgVOG7lW5nIGvhur90IGNoxrDGoW5nKioNCg0KLSAgIENoxrDGoW5nIDYgY+G7p25nIGPhu5EgY8ahIHPhu58gdG/DoW4gaOG7jWMgdsOgIHRodeG6rXQgdG/DoW4gxJHhu4MgxrDhu5tjIGzGsOG7o25nIHRoYW0gc+G7kSB0cm9uZyBHTE0uDQoNCi0gICBMw6AgY+G6p3UgbuG7kWkgZ2nhu69hIGzDvSB0aHV54bq/dCB4w6FjIHN14bqldCBow6BtIG3FqSB2w6AgdGjhu7FjIGjDoG5oIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IHbhu5tpIFIuDQoNCiMjICoqQ0jGr8agTkcgNzogU1VZIExV4bqsTiBUUk9ORyBNw5QgSMOMTkggVFVZ4bq+TiBUw41OSCBU4buUTkcgUVXDgVQgKElORkVSRU5DRSBJTiBHTE1zKSoqDQoNCiMjIyAqKjcuMSBHaeG7m2kgdGhp4buHdSoqDQoNCi0gICBDaMawxqFuZyBuw6B5IHRyw6xuaCBiw6B5IGPDoWMgcGjGsMahbmcgcGjDoXAgKipzdXkgbHXhuq1uIHRo4buRbmcga8OqKiogY2hvIGPDoWMgaOG7hyBz4buRIHRyb25nIEdMTXMuDQoNCi0gICBE4buxYSB0csOqbiDGsOG7m2MgbMaw4bujbmcgaOG7o3AgbMO9IGPhu7FjIMSR4bqhaSAoTUxFKSwgc+G7rSBk4bulbmcgMyBsb+G6oWkga2nhu4NtIMSR4buLbmg6DQoNCiAgICAtICAgKipXYWxkIHRlc3QqKg0KDQogICAgLSAgICoqTGlrZWxpaG9vZCBSYXRpbyBUZXN0IChMUlQpKioNCg0KICAgIC0gICAqKlNjb3JlIHRlc3QqKg0KDQotICAgw4FwIGThu6VuZyBjaG8gY+G6oyB0csaw4budbmcgaOG7o3AgdGhhbSBz4buRIHBow6JuIHTDoW4gJM+VJCDEkcaw4bujYyBiaeG6v3QgaG/hurdjIGtow7RuZyBiaeG6v3QuDQoNCiMjIyAqKjcuMiBLaGkgdGhhbSBz4buRIHBow6JuIHTDoW4gz4YgxJHDoyBiaeG6v3QqKg0KDQoqKldhbGQgdGVzdCoqDQoNCi0gICBE4buxYSB0csOqbiBnaeG6oyDEkeG7i25oIHBow6JuIHBo4buRaSBjaHXhuqluIHRp4buHbSBj4bqtbiBj4bunYSAkXGhhdHtcYmV0YX1fauKAizokICQkDQogICAgWiA9IFxmcmFje1xoYXR7XGJldGF9X2ogLSBcYmV0YV9qXjB9e1x0ZXh0e3NlfShcaGF0e1xiZXRhfV9qKX0gXHNpbSBOKDAsMSkNCiAgICAkJA0KDQotICAgUGjhu5UgYmnhur9uIHbDrCDEkcahbiBnaeG6o24gdsOgIGPDsyBz4bq1biB0cm9uZyBgc3VtbWFyeShnbG1fb2JqZWN0KWAuDQoNCioqTcOjIFI6KiogYHN1bW1hcnkoZ2xtKEZFViB+IEFnZSwgZmFtaWx5PWdhdXNzaWFuLCBkYXRhPWx1bmdjYXApKWANCg0KKipLaG/huqNuZyB0aW4gY+G6rXkgKENvbmZpZGVuY2UgaW50ZXJ2YWxzKSoqDQoNCi0gICBYw6J5IGThu7FuZyB04burIFdhbGQgdGVzdDoNCg0KICAgICQkDQogICAgXGhhdHtcYmV0YX1faiBccG0gel97XGFscGhhLzJ9IFxjZG90IFx0ZXh0e3NlfShcaGF0e1xiZXRhfV9qKQ0KICAgICQkDQoNCi0gICBSIGTDuW5nIGBjb25maW50KClgIGhv4bq3YyB0cuG7sWMgdGnhur9wIHThu6sgYHN1bW1hcnkoKWANCg0KKipNw6MgUjoqKiBgY29uZmludChtb2RlbClgDQoNCioqTGlrZWxpaG9vZCBSYXRpbyBUZXN0IChMUlQpKioNCg0KLSAgIFNvIHPDoW5oIG3DtCBow6xuaCBjb24gdsOgIG3DtCBow6xuaCDEkeG6p3kgxJHhu6c6DQoNCiAgICAkJA0KICAgIFxmcmFje0Rfe1x0ZXh0e3JlZHVjZWR9fSAtIERfe1x0ZXh0e2Z1bGx9fX17XHBoaX0gXHNpbSBcY2hpXjJfe2RmfQ0KICAgICQkDQoNCi0gICBDw7MgdGjhu4MgZMO5bmcgYGFub3ZhKG1vZGVsMSwgbW9kZWwyLCB0ZXN0PSJDaGlzcSIpYC4NCg0KKipNw6MgUjoqKiBgbW9kZWwuZnVsbCA8LSBnbG0oWSB+IFgxICsgWDIsIGZhbWlseT1wb2lzc29uLCBkYXRhPWRmKSBtb2RlbC5yZWR1Y2VkIDwtIGdsbShZIH4gWDEsIGZhbWlseT1wb2lzc29uLCBkYXRhPWRmKSBhbm92YShtb2RlbC5yZWR1Y2VkLCBtb2RlbC5mdWxsLCB0ZXN0PSJDaGlzcSIpYA0KDQoqKlNjb3JlIHRlc3QqKg0KDQotICAgxJDDoW5oIGdpw6EgaGnhu4d1IHF14bqjIGPhu6dhIHZp4buHYyB0aMOqbSBiaeG6v24gdsOgbyBtw7QgaMOsbmguDQoNCi0gICBEw7luZyBraGkgY2jGsGEgxrDhu5tjIGzGsOG7o25nIG3DtCBow6xuaCDEkeG6p3kgxJHhu6cuDQoNCiMjIyAqKjcuMyDigJMgNy40IEtp4buDbSDEkeG7i25oIMSR4buZIHBow7kgaOG7o3AgKEdvb2RuZXNzLW9mLUZpdCkqKg0KDQotICAgKipEZXZpYW5jZSB0ZXN0Kio6IEThu7FhIHbDoG8gc2NhbGVkIGRldmlhbmNlLg0KDQotICAgKipQZWFyc29uIHRlc3QqKjogROG7sWEgdsOgbyB04buVbmcgcGjhuqduIGTGsCBQZWFyc29uIGLDrG5oIHBoxrDGoW5nLg0KDQotICAgQ8OzIHRo4buDIGtp4buDbSB0cmEgYuG6sW5nIGBkZXZpYW5jZShtb2RlbClgIHbDoCBgcmVzaWR1YWxzKG1vZGVsLCB0eXBlPSJwZWFyc29uIilgLg0KDQoqKk3DoyBSOioqIGBkZXZpYW5jZShtb2RlbCkgc3VtKHJlc2lkdWFscyhtb2RlbCwgdHlwZT0icGVhcnNvbiIpXjIpYA0KDQojIyMgKio3LjYgS2hpIM+GIGNoxrBhIGJp4bq/dCoqDQoNCi0gICDGr+G7m2MgbMaw4bujbmcgJM+VJCB04burIHBo4bqnbiBkxrAgKFBlYXJzb24gaG/hurdjIGRldmlhbmNlKS4NCg0KLSAgIFRoYXkgcGjDom4gcGjhu5FpIGNodeG6qW4gYuG6sW5nIHBow6JuIHBo4buRaSB0Og0KDQogICAgJCQNCiAgICBUID0gXGZyYWN7XGhhdHtcYmV0YX1faiAtIFxiZXRhX2peMH17XHRleHR7c2V9KFxoYXR7XGJldGF9X2opfSBcc2ltIHRfe24gLSBwJ30NCiAgICAkJA0KDQotICAgS2hv4bqjbmcgdGluIGPhuq15IGTDuW5nIHBow6JuIHBo4buRaSB0IHRoYXkgdsOsIHouDQoNCiMjIyAqKjcuNyBTbyBzw6FuaCAzIGxv4bqhaSBraeG7g20gxJHhu4tuaCoqDQoNCnwgS2nhu4NtIMSR4buLbmggfCDGr3UgxJFp4buDbSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IE5oxrDhu6NjIMSRaeG7g20gICAgICAgICAgICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgKipXYWxkKiogIHwgQ8OzIHPhurVuIHRyb25nIG91dHB1dCBSICAgICAgICAgICAgICAgICAgICB8IE5o4bqheSBj4bqjbSBraGkgJFxoYXR7XGJldGF9JCBn4bqnbiAwIHwNCnwgKipMUlQqKiAgIHwgQ2jDrW5oIHjDoWMsIHBow7kgaOG7o3AgduG7m2kgbcO0IGjDrG5oIGzhu5NuZyBuaGF1IHwgQ+G6p24gxrDhu5tjIGzGsOG7o25nIG3DtCBow6xuaCDEkeG6p3kgxJHhu6cgICAgIHwNCnwgKipTY29yZSoqIHwgS2jDtG5nIGPhuqduIG3DtCBow6xuaCDEkeG6p3kgxJHhu6cgICAgICAgICAgICAgICAgIHwgVGhp4bq/dSBz4bq1biBjw7MgdHJvbmcgUiAgICAgICAgICAgICB8DQoNCiMjIyAqKjcuOCBTbyBzw6FuaCBtw7QgaMOsbmgga2jDtG5nIGzhu5NuZyBuaGF1KioNCg0KLSAgIETDuW5nICoqQUlDKiogdsOgICoqQklDKio6DQoNCiAgICAkJA0KICAgIFx0ZXh0e0FJQ30gPSAtMlxsb2cgTCArIDJrOyBccXVhZCBcdGV4dHtCSUN9ID0gLTJcbG9nIEwgKyBrIFxsb2cgbg0KICAgICQkDQoNCioqTcOjIFI6KiogYEFJQyhtb2RlbDEsIG1vZGVsMikgQklDKG1vZGVsMSwgbW9kZWwyKWANCg0KIyMjICoqNy45IFThu7EgxJHhu5luZyBjaOG7jW4gbcO0IGjDrG5oKioNCg0KLSAgIFPhu60gZOG7pW5nIGjDoG0gYHN0ZXAoKWAgKHRoZW8gQUlDKToNCg0KYHN0ZXAoZ2xtKEZFViB+IEFnZSArIEh0ICsgR2VuZGVyICsgU21va2UsIGZhbWlseT1nYXVzc2lhbiwgZGF0YT1sdW5nY2FwKSlgDQoNCioqVOG7lW5nIGvhur90IGNoxrDGoW5nKioNCg0KLSAgIENoxrDGoW5nIG7DoHkgdGhp4bq/dCBs4bqtcCBo4buHIHRo4buRbmcgY8O0bmcgY+G7pSBzdXkgbHXhuq1uIGNobyBHTE1zOg0KDQogICAgLSAgIEtp4buDbSDEkeG7i25oIMO9IG5naMSpYSB0aOG7kW5nIGvDqiBj4bunYSBo4buHIHPhu5E7DQoNCiAgICAtICAgxJDDoW5oIGdpw6Egc+G7sSBj4bqjaSB0aGnhu4duIG3DtCBow6xuaDsNCg0KICAgIC0gICBDaOG7jW4gbcO0IGjDrG5oIHThu5FpIMawdSBow7NhIGdp4buvYSDEkeG7mSBwaMO5IGjhu6NwIHbDoCDEkcahbiBnaeG6o24uDQoNCkPDoWMgcGjGsMahbmcgcGjDoXAgbsOgeSBu4buBbiB04bqjbmcgY2hvICoqY2jhuqluIMSRb8OhbiBtw7QgaMOsbmgqKiAoQ2jGsMahbmcgOCkgdsOgICoqZGnhu4VuIGdp4bqjaSBr4bq/dCBxdeG6oyoqIHRyb25nIHRo4buxYyBow6BuaCB0aOG7kW5nIGvDqiBoaeG7h24gxJHhuqFpLg0KDQojIyAqKkNIxq/GoE5HIDg6IENI4bqoTiDEkE/DgU4gTcOUIEjDjE5IIFRVWeG6vk4gVMONTkggVOG7lE5HIFFVw4FUIChESUFHTk9TVElDUykqKg0KDQojIyMgKio4LjEgR2nhu5tpIHRoaeG7h3UqKg0KDQpDaMawxqFuZyBuw6B5IHRyw6xuaCBiw6B5IGPDoWMgY8O0bmcgY+G7pSDEkeG7gzoNCg0KLSAgIFjDoWMgxJHhu4tuaCB2aSBwaOG6oW0gZ2nhuqMgxJHhu4tuaCBj4bunYSBHTE07DQoNCi0gICBHaeG6o2kgdGjDrWNoIGPDoWMgbG/huqFpIHBo4bqnbiBkxrAgKHJlc2lkdWFscyk7DQoNCi0gICBQaMOhdCBoaeG7h24gxJFp4buDbSBk4buvIGxp4buHdSBi4bqldCB0aMaw4budbmcgaG/hurdjIOG6o25oIGjGsOG7n25nIGzhu5tuOw0KDQotICAgxJDhu4EgeHXhuqV0IGPDoWMgaMaw4bubbmcgxJFp4buBdSBjaOG7iW5oIG3DtCBow6xuaC4NCg0KIyMjICoqOC4yIEdp4bqjIMSR4buLbmggY+G7p2EgR0xNKioNCg0KQ8OhYyBnaeG6oyDEkeG7i25oIGNow61uaDoNCg0KMS4gIEtow7RuZyBjw7Mgb3V0bGllcnMg4bqjbmggaMaw4bufbmcgbOG7m247DQoNCjIuICBIw6BtIGxpw6puIGvhur90ICRnKM68KSQgbMOgIMSRw7puZzsNCg0KMy4gIFR1eeG6v24gdMOtbmggaMOzYSBjw6FjIGJp4bq/biBnaeG6o2kgdGjDrWNoIGzDoCDEkcO6bmc7DQoNCjQuICBIw6BtIHBoxrDGoW5nIHNhaSAkVijOvCkkIGzDoCBwaMO5IGjhu6NwOw0KDQo1LiAgVGhhbSBz4buRIHBow6JuIHTDoW4gJM+VJCBsw6AgaOG6sW5nIHPhu5E7DQoNCjYuICBDw6FjIHF1YW4gc8OhdCDEkeG7mWMgbOG6rXA7DQoNCjcuICBE4buvIGxp4buHdSDEkeG6v24gdOG7qyBwaMOibiBwaOG7kWkgRURNIHjDoWMgxJHhu4tuaC4NCg0KIyMjICoqOC4zIFJlc2lkdWFscyB0cm9uZyBHTE0qKg0KDQpCYSBsb+G6oWkgcmVzaWR1YWxzIGNow61uaDoNCg0KLSAgICoqUGVhcnNvbiByZXNpZHVhbHM6KiogUmVzaWR1YWwgUGVhcnNvbiDEkcaw4bujYyB0w61uaCBi4bufaSAkXGRpc3BsYXlzdHlsZSByX1AgPSBcZnJhY3t5IC0gXG11fXtcc3FydHtccGhpXCxWKFxtdSkvd319JC4NCg0KLSAgICoqRGV2aWFuY2UgcmVzaWR1YWxzKio6JCQNCiAgICByX0QgPSBcdGV4dHtzaWdufSh5IC0gXG11KSBcY2RvdCBcc3FydHsyd1wsZCh5LCBcbXUpfQ0KICAgICQkDQoNCi0gICAqKlF1YW50aWxlIHJlc2lkdWFscyoqOiBkw7luZyDEkeG7gyB24bq9IFHigJNRIHBsb3QsIMSR4bq3YyBiaeG7h3QgaOG7r3Ugw61jaCBjaG8gZOG7ryBsaeG7h3UgcuG7nWkgcuG6oWMgKGRpc2NyZXRlKS4NCg0KIyMjICoqOC40IExldmVyYWdlcyB2w6AgbWEgdHLhuq1uICJoYXQiKioNCg0KLSAgIExldmVyYWdlICRoX2kk4oCLOiBt4bupYyDEkeG7mSDhuqNuaCBoxrDhu59uZyBj4bunYSBt4buXaSBxdWFuIHPDoXQgbMOqbiDGsOG7m2MgbMaw4bujbmcgJFxoYXR7XG11fV9pJCA7DQoNCi0gICDEkMaw4bujYyB0w61uaCBxdWEgbWEgdHLhuq1uICJoYXQiOg0KDQokJA0KSCA9IFdeezEvMn0gWCAoWF5UIFcgWCleey0xfSBYXlQgV157MS8yfQ0KJCQNCg0KIyMjICoqOC41IFBo4bqnbiBkxrAgY2h14bqpbiBow7NhIChTdGFuZGFyZGl6ZWQgcmVzaWR1YWxzKSoqDQoNCi0gICBDaHXhuqluIGjDs2EgZ2nDunAgcGjhuqduIGTGsCBjw7MgcGjGsMahbmcgc2FpIOG7lW4gxJHhu4tuaC4NCg0KLSAgIFbDrSBk4bulOg0KDQogICAgJCQNCiAgICByJ19QID0gXGZyYWN7cl9QfXtcc3FydHsxIC0gaH19LCBccXVhZCANCiAgICByJ19EID0gXGZyYWN7cl9EfXtcc3FydHsxIC0gaH19LCBccXVhZCANCiAgICByJ19RID0gXGZyYWN7cl9RfXtcc3FydHsxIC0gaH19DQogICAgJCQNCg0KLSAgIGByc3RhbmRhcmQoKWAgdsOgIGByc3R1ZGVudCgpYCBkw7luZyDEkeG7gyBs4bqleSBwaOG6p24gZMawIGNodeG6qW4gaMOzYSB2w6AgU3R1ZGVudGl6ZWQuDQoNCiMjIyAqKjguNiBLaGkgbsOgbyBkw7luZyBsb+G6oWkgcmVzaWR1YWwgbsOgbyoqDQoNCi0gICAqKlF1YW50aWxlIHJlc2lkdWFscyoqOiBraHV5w6puIGTDuW5nIHbhu5tpIGThu68gbGnhu4d1IMSR4bq/bSBob+G6t2Mgbmjhu4sgcGjDom47DQoNCi0gICAqKkRldmlhbmNlIHJlc2lkdWFscyoqOiB0aMaw4budbmcgZMO5bmcgbmjhuqV0Ow0KDQotICAgKipQZWFyc29uIHJlc2lkdWFscyoqOiBkw7luZyDEkeG7gyDGsOG7m2MgbMaw4bujbmcgJM+VJCwgw610IGTDuW5nIGNobyDEkeG7kyB0aOG7iy4NCg0KIyMjICoqOC43IEtp4buDbSB0cmEgZ2nhuqMgxJHhu4tuaCBtw7QgaMOsbmgqKg0KDQpDw6FjIMSR4buTIHRo4buLIGNo4bqpbiDEkW/DoW46DQoNCi0gICBSZXNpZHVhbHMgdnMuIGZpdHRlZCB2YWx1ZXM6IHTDrG0geHUgaMaw4bubbmcga2jDtG5nIHR1eeG6v24gdMOtbmggaG/hurdjIHBoxrDGoW5nIHNhaSBraMO0bmcgxJHhu4F1Lg0KDQotICAgUeKAk1EgcGxvdCBj4bunYSByZXNpZHVhbHM6IHBow6F0IGhp4buHbiBvdXRsaWVycy4NCg0KLSAgIFJlc2lkdWFscyB2cy4gZXhwbGFuYXRvcnkgdmFyaWFibGVzOiBraeG7g20gdHJhIHR1eeG6v24gdMOtbmggY+G7p2EgdOG7q25nIGJp4bq/bi4NCg0KLSAgIFBhcnRpYWwgcmVzaWR1YWwgcGxvdHMgKGB0ZXJtcGxvdCgpYCk6IHjDoWMgxJHhu4tuaCBt4buRaSBxdWFuIGjhu4cgxJHDum5nIGdp4buvYSBiaeG6v24gdsOgIHBo4bqjbiBo4buTaS4NCg0KIyMjICoqOC44IFBow6F0IGhp4buHbiBxdWFuIHPDoXQgbmdv4bqhaSBs4buHIHbDoCDhuqNuaCBoxrDhu59uZyBs4bubbioqDQoNCi0gICBT4butIGThu6VuZzoNCg0KICAgIC0gICAqKlN0YW5kYXJkaXplZCByZXNpZHVhbHMqKg0KDQogICAgLSAgICoqU3R1ZGVudGl6ZWQgcmVzaWR1YWxzKioNCg0KICAgIC0gICAqKkNvb2sncyBkaXN0YW5jZSoqLCAqKmRmYmV0YXMqKiwgKipkZmZpdHMqKiwgKipjb3ZyYXRpbyoqIHThu6sgYGluZmx1ZW5jZS5tZWFzdXJlcygpYCB0cm9uZyBSLg0KDQotICAgTeG7mXQgcXVhbiBzw6F0IMSRxrDhu6NjIGfhu41pIGzDoCDhuqNuaCBoxrDhu59uZyBu4bq/dSBraGkgbG/huqFpIGLhu48gbsOzIHPhur0gbMOgbSB0aGF5IMSR4buVaSDEkcOhbmcga+G7gyBtw7QgaMOsbmguDQoNCiMjIyAqKjguOSBHaeG6o2kgcXV54bq/dCB24bqlbiDEkeG7gSBtw7QgaMOsbmgqKg0KDQotICAgQmnhur9uIMSR4buVaSBiaeG6v24gKGxvZywgc3FydCk7DQoNCi0gICBT4butIGThu6VuZyBzcGxpbmUgKGBucygpYCwgYGJzKClgIHThu6sgcGFja2FnZSBgc3BsaW5lc2ApOw0KDQotICAgTG/huqFpIGLhu48gaG/hurdjIHTDoWNoIHJpw6puZyBjw6FjIG91dGxpZXJzIGPDsyBsw70gZG8gcsO1IHLDoG5nLg0KDQojIyMgKio4LjEwIE3DtCBow6xuaCBxdWFzaS1saWtlbGlob29kKioNCg0KLSAgIETDuW5nIGtoaSBwaMOibiBwaOG7kWkga2jDtG5nIHBow7kgaOG7o3AgaG/DoG4gdG/DoG47DQoNCi0gICBWw60gZOG7pTogYHF1YXNpcG9pc3NvbigpYCwgYHF1YXNpYmlub21pYWwoKWAgY2hvIGThu68gbGnhu4d1IG92ZXJkaXNwZXJzaW9uOw0KDQotICAgQUlDIGtow7RuZyDEkeG7i25oIG5naMSpYSBjaG8gcXVhc2ktbW9kZWxzLCBuaMawbmcgYHN1bW1hcnkoKWAgdsOgIGBhbm92YSgpYCB24bqrbiBkw7luZyDEkcaw4bujYy4NCg0KIyMjICoqOC4xMSBW4bqlbiDEkeG7gSDEkWEgY+G7mW5nIHR1eeG6v24gKENvbGxpbmVhcml0eSkqKg0KDQotICAgROG6pXUgaGnhu4d1OiBo4buHIHPhu5EgaOG7k2kgcXV5IGtow7RuZyDhu5VuIMSR4buLbmgsIHBoxrDGoW5nIHNhaSBs4bubbjsNCg0KLSAgIEdp4bqjaSBwaMOhcDogbG/huqFpIGJp4bq/biwga+G6v3QgaOG7o3AgYmnhur9uLCBkw7luZyBQQ0EuDQoNCiMjIyAqKjguMTIgVOG7lW5nIGvhur90KioNCg0KLSAgIENo4bqpbiDEkW/DoW4gbMOgICoqYsaw4bubYyBi4bqvdCBideG7mWMqKiBzYXUga2hpIGto4bubcCBHTE07DQoNCi0gICBE4buxYSB2w6BvIHBo4bqnbiBkxrAsIGxldmVyYWdlLCDhuqNuaCBoxrDhu59uZyDEkeG7gyDEkcOhbmggZ2nDoSBjaOG6pXQgbMaw4bujbmcgbcO0IGjDrG5oOw0KDQotICAgxJDhu4EgeHXhuqV0IGPDoWNoIGPhuqNpIHRoaeG7h24gbcO0IGjDrG5oIG7hur91IGPDsyB2aSBwaOG6oW0gZ2nhuqMgxJHhu4tuaA0KDQojIyAqKkNIxq/GoE5HIDk6IE3DlCBIw4xOSCBOSOG7iiBUSOG7qEMgKEJJTk9NSUFMIEdMTXMpKioNCg0KIyMjICoqOS4xIEdp4bubaSB0aGnhu4d1KioNCg0KLSAgIENoxrDGoW5nIDkgw6FwIGThu6VuZyBsw70gdGh1eeG6v3QgR0xNIMSRw6MgcGjDoXQgdHJp4buDbiDhu58gY8OhYyBjaMawxqFuZyB0csaw4bubYyBjaG8gdHLGsOG7nW5nIGjhu6NwICoqcGjDom4gcGjhu5FpIG5o4buLIHRo4bupYyoqLCBkw7luZyDEkeG7gyBtw7QgaMOsbmggaMOzYSAqKnThu7cgbOG7hyAocHJvcG9ydGlvbnMpKiouDQoNCi0gICDEkOG6t2MgYmnhu4d0IGjhu691IMOtY2ggdHJvbmcgY8OhYyBuZ2hpw6puIGPhu6l1IG5oxrA6IHThu7cgbOG7hyB04butIHZvbmcsIGvhur90IHF14bqjIMSRaeG7gXUgdHLhu4ssIHThu7cgbOG7hyBi4buPIHBoaeG6v3UsIHYudi4uDQoNCiMjIyAqKjkuMiBNw7QgaMOsbmggaMOzYSB04bu3IGzhu4cgKFByb3BvcnRpb24gTW9kZWxzKSoqDQoNCi0gICBE4buvIGxp4buHdSBuaOG7iyB0aOG7qWMgxJHGsOG7o2MgbcO0IGjDrG5oIGjDs2EgdGhlbzoNCg0KICAgIEdp4bqjIHPhu60gYmnhur9uIHF1YW4gc8OhdCAkeV9pJCB0dcOibiB0aGVvIHBow6JuIHBo4buRaSBuaOG7iyB0aOG7qWM6DQoNCiAgICAkJA0KICAgIHlfaSBcc2ltIFx0ZXh0e0Jpbm9taWFsfShtX2ksIFxtdV9pKSwgXHF1YWQgXHRleHR7duG7m2kgfSAwIDwgXG11X2kgPCAxDQogICAgJCQNCg0KICAgIFRyb25nIMSRw7M6IC0gJG1faSQ6IHPhu5EgbOG6p24gdGjhu60gKHPhu5EgdHJpYWxzKSAtICRcbXVfaSQ6IHjDoWMgc3XhuqV0IHRow6BuaCBjw7RuZyB0cm9uZyBt4buXaSBs4bqnbiB0aOG7rQ0KDQotICAgUGjGsMahbmcgc2FpIGzDoDogJFx0ZXh0e3Zhcn0oeV9pKSA9IFxmcmFje1xtdV9pKDEgLSBcbXVfaSl9e21faX0kLuKAiw0KDQotICAgVHLhu41uZyBz4buRIHRpw6puIG5naGnhu4dtOiAkd19pID0gbV9pJA0KDQojIyMgKio5LjMgSMOgbSBsacOqbiBr4bq/dCAoTGluayBGdW5jdGlvbnMpKioNCg0KQmEgaMOgbSBsacOqbiBr4bq/dCBwaOG7lSBiaeG6v246DQoNCjEuICAqKkxvZ2l0Kio6ICQkDQogICAgXGV0YSA9IFxsb2dcbGVmdChcZnJhY3tcbXV9ezEgLSBcbXV9XHJpZ2h0KQ0KICAgICQkDQoNCjIuICAqKlByb2JpdCoqOiBMacOqbiBr4bq/dCB0cm9uZyBtw7QgaMOsbmggUHJvYml0IGzDoCAkXGV0YSA9IFxQaGleey0xfShcbXUpJCwgdHJvbmcgxJHDsyAkXFBoaV57LTF9JCBsw6AgaMOgbSBwaMOibiBwaOG7kWkgY2h14bqpbiBuZ8aw4bujYy4NCg0KMy4gICoqQ29tcGxlbWVudGFyeSBsb2ctbG9nKio6IEjDoG0gbGnDqm4ga+G6v3QgY2xvZ2xvZyBsw6AgXCQgXFxldGEgPSBcXGxvZ1xcey1cXGxvZygxIC0gXFxtdSlcXH0gXCQgLCB0aMaw4budbmcgxJHGsOG7o2MgZMO5bmcga2hpIHjDoWMgc3XhuqV0IHRow6BuaCBjw7RuZyBn4bqnbiAwIGhv4bq3YyBn4bqnbiAxIGtow7RuZyDEkeG7kWkgeOG7qW5nLg0KDQo0LiAgTmdvw6BpIHJhIGPDsm4gY8OzOiBgImxvZyJgICh04bu3IHN14bqldCBy4bunaSBybykgdsOgIGAiY2F1Y2hpdCJgIChwaMOibiBwaOG7kWkgQ2F1Y2h5KS4NCg0KIyMjICoqOS40IERp4buFbiBnaeG6o2kgdGhlbyBuZ8aw4buhbmcgKFRocmVzaG9sZCBpbnRlcnByZXRhdGlvbikqKg0KDQotICAgQ8OhYyBow6BtIGxpw6puIGvhur90IGPDsyB0aOG7gyDEkcaw4bujYyBoaeG7g3UgbMOgIGvhur90IHF14bqjIGPhu6dhIG3DtCBow6xuaCAqKm5nxrDhu6FuZyAodGhyZXNob2xkIG1vZGVscykqKjogbeG7l2kgxJHhu5FpIHTGsOG7o25nIGPDsyBt4buZdCBt4bupYyBkdW5nIHNhaSAodG9sZXJhbmNlKS4NCg0KLSAgIEThuqtuIMSR4bq/biBkaeG7hW4gZ2nhuqNpIHjDoWMgc3XhuqV0IGThu7FhIHRyw6puIHBow6JuIHBo4buRaSBj4bunYSBuZ8aw4buhbmcgZHVuZyBzYWkuDQoNCiMjIyAqKjkuNSBPZGRzIHbDoCBPZGRzIFJhdGlvKioNCg0KLSAgIFPhu60gZOG7pW5nIGxvZ2l0IGNobyBwaMOpcCBkaeG7hW4gZ2nhuqNpIG3DtCBow6xuaCBuaMawIGxvZyhvZGRzKS4NCg0KICAgIC0gICBU4bu3IHPhu5Egb2RkcyAob2RkcyByYXRpbykgbMOgIHF1YW4gaOG7hyBnaeG7r2EgeMOhYyBzdeG6pXQgeOG6o3kgcmEgdsOgIGtow7RuZyB44bqjeSByYToNCg0KICAgICAgICBU4bu3IHPhu5EgY8aw4bujYyAob2RkcykgdsOgIGjDoG0gbG9naXQgxJHGsOG7o2MgxJHhu4tuaCBuZ2jEqWEgbmjGsCBzYXU6DQoNCiAgICAgICAgJCQNCiAgICAgICAgXHRleHR7b2Rkc30gPSBcZnJhY3tcbXV9ezEgLSBcbXV9LCBccXVhZCBcdGV4dHtsb2dpdH0oXG11KSA9IFxsb2coXHRleHR7b2Rkc30pID0gXGxvZ1xsZWZ0KFxmcmFje1xtdX17MSAtIFxtdX1ccmlnaHQpDQogICAgICAgICQkDQoNCiAgICAgICAgVHJvbmcgxJHDszogJFxtdSQ6IHjDoWMgc3XhuqV0IHRow6BuaCBjw7RuZzsgbG9naXQoJFxtdSQpOiBow6BtIGxpw6puIGvhur90IHRyb25nIG3DtCBow6xuaCBo4buTaSBxdXkgbG9naXN0aWMNCg0KLSAgIEdp4bqjaSB0aMOtY2ggaOG7hyBz4buRIGjhu5NpIHF1eSBk4buFIGTDoG5nIGjGoW4gdGjDtG5nIHF1YSB0aGF5IMSR4buVaSB04bu3IHPhu5Egb2Rkcy4NCg0KIyMjICoqOS42IEVENTAgKExp4buBdSBoaeG7h3UgcXXhuqMgdHJ1bmcgYsOsbmgpKioNCg0KLSAgIMSQxrDhu6NjIMSR4buLbmggbmdoxKlhIGzDoCBnacOhIHRy4buLIGxp4buBdSBsxrDhu6NuZyBkZGQgc2FvIGNobyDOvD0wLjVcbXUgPSAwLjXOvD0wLjUNCg0KLSAgIFbhu5tpIGxpw6puIGvhur90IGxvZ2l0OiBHacOhIHRy4buLIEVEJF97NTB9JCDEkcaw4bujYyB0w61uaCBi4bqxbmcgXCRcdGV4dHtFRH1cX3s1MH0gPSAtXGJldGFcXzAgLyBcYmV0YVxfMVwkLg0KDQotICAgQ8O0bmcgY+G7pSBgZG9zZS5wKClgIHRyb25nIFIgKGfDs2kgKipNQVNTKiopIMSRxrDhu6NjIGTDuW5nIMSR4buDIHTDrW5oIHRvw6FuIEVEKM+BKS4NCg0KKipWw60gZOG7pSBSOioqIGBsaWJyYXJ5KE1BU1MpIGRvc2UucChmaXQsIGMoMSwgMikpICAjIMaw4bubYyBsxrDhu6NuZyBFRDUwYA0KDQojIyMgKio5LjcgQ29tcGxlbWVudGFyeSBMb2ctTG9nIHRyb25nIHBow6JuIHTDrWNoIHNpbmggaOG7jWMqKg0KDQotICAgUGjDuSBo4bujcCB24bubaSBiw6BpIHRvw6FuICoqZGlsdXRpb24gYXNzYXkqKiwgbmjGsCB4w6FjIMSR4buLbmggeMOhYyBzdeG6pXQgY8OzIHThur8gYsOgbyBn4buRYyB0cm9uZyBt4bqrdSBtw7QuDQoNCi0gICBYw6J5IGThu7FuZyB0csOqbiBnaeG6oyDEkeG7i25oIHBow6JuIHBo4buRaSBQb2lzc29uIGPhu6dhIHPhu5EgdOG6vyBiw6BvIHbDoCBtw7QgaMOsbmggbG9nLWxvZy1saW5rLg0KDQojIyMgKio5LjggT3ZlcmRpc3BlcnNpb24gdHJvbmcgbcO0IGjDrG5oIG5o4buLIHRo4bupYyoqDQoNCi0gICAqKk92ZXJkaXNwZXJzaW9uKio6IFBoxrDGoW5nIHNhaSBs4bubbiBoxqFuIGThu7Ega2nhur9uLg0KDQotICAgTmd1ecOqbiBuaMOibjoNCg0KICAgIC0gICAkdV9pJCB0aGF5IMSR4buVaSBnaeG7r2EgY8OhYyBuaMOzbTsNCg0KICAgIC0gICBDw6FjIHRo4butIG5naGnhu4dtICRtX2kk4oCLIGtow7RuZyDEkeG7mWMgbOG6rXA7DQoNCi0gICBE4bqrbiDEkeG6v24gKipwaMawxqFuZyBzYWkgaGnhu4d1IGThu6VuZyoqOg0KDQogICAgJCQNCiAgICBcdGV4dHt2YXJ9KHlfaSkgPSBccGhpIFxmcmFje1xtdV9pKDEgLSBcbXVfaSl9e21faX0sIFxxdWFkIFxwaGkgPiAxDQogICAgJCQNCg0KLSAgIEdp4bqjaSBwaMOhcDogRMO5bmcgKipxdWFzaS1iaW5vbWlhbCBtb2RlbHMqKiBob+G6t2MgKipiZXRhLWJpbm9taWFsIG1vZGVscyoqLg0KDQojIyMgKio5LjkgTOG7l2kgxrDhu5tjIGzGsOG7o25nIGRvIHNlcGFyYXRpb24qKg0KDQotICAgS2hpIGJp4bq/biBnaeG6o2kgdGjDrWNoIGhvw6BuIHRvw6BuIHBow6JuIGJp4buHdCBnaeG7r2EgY8OhYyBuaMOzbSwgZ8OieSByYSBoaeG7h24gdMaw4bujbmcgKipzZXBhcmF0aW9uKiouDQoNCi0gICBHw6J5IHJhIMaw4bubYyBsxrDhu6NuZyBo4buHIHPhu5EgaOG7k2kgcXV5IHbDtCBo4bqhbiDihpIgUiBz4bq9IGPhuqNuaCBiw6FvLg0KDQojIyMgKio5LjEwIEdvb2RuZXNzLW9mLWZpdCB24bubaSBk4buvIGxp4buHdSBuaOG7iyBwaMOibioqDQoNCi0gICBDw6FjIGtp4buDbSDEkeG7i25oIG5oxrAgZGV2aWFuY2UgdGVzdCBraMO0bmcgcGjDuSBo4bujcCB24bubaSBk4buvIGxp4buHdSBuaOG7iyBwaMOibiAobeG7l2kgZMOybmcgbMOgIG3hu5l0IGPDoSB0aOG7gyk7DQoNCi0gICBQaMOibiBwaOG7kWkgZGV2aWFuY2Uga2jDtG5nIGPDsm4gdGnhu4dtIGPhuq1uIHRoZW8gY2hpIGLDrG5oIHBoxrDGoW5nOw0KDQotICAgR2nhuqNpIHBow6FwOiB4ZW0gcGjhuqduIGTGsCBjaHXhuqluIGjDs2EsIGhv4bq3YyBkw7luZyAqKmJvb3RzdHJhcCoqIG7hur91IGPhuqduIGtp4buDbSDEkeG7i25oLg0KDQojIyMgKio5LjEyIFPhu60gZOG7pW5nIFIgY2hvIG3DtCBow6xuaCBuaOG7iyB0aOG7qWMqKg0KDQpCYSBjw6FjaCBuaOG6rXAgZOG7ryBsaeG7h3U6DQoNCjEuICBU4bu3IGzhu4cgdGjDoG5oIGPDtG5nICsgYHdlaWdodHMgPSBtYDsNCg0KMi4gIGBjYmluZChzdWNjZXNzLCBmYWlsdXJlKSB+IHhgOw0KDQozLiAgTmjhu4sgcGjDom4gdOG7q25nIGPDoSB0aOG7gzogZMO5bmcgYmnhur9uIGxvZ2ljIGhv4bq3YyBmYWN0b3IuDQoNCioqTcOjIG3huqt1OioqIGBnbG0oeSB+IHgsIHdlaWdodHM9bSwgZmFtaWx5PWJpbm9taWFsKSBnbG0oY2JpbmQoc3VjY2VzcywgZmFpbHVyZSkgfiB4LCBmYW1pbHk9Ymlub21pYWwpIGdsbShzdWNjZXNzIH4geCwgZmFtaWx5PWJpbm9taWFsKSAgIyBuaOG7iyBwaMOibmANCg0KKipU4buVbmcga+G6v3QgY2jGsMahbmcqKg0KDQotICAgQ2jGsMahbmcgOSDDoXAgZOG7pW5nIEdMTXMgdsOgbyBtw7QgaMOsbmggdOG7tyBs4buHIHbhu5tpIHBow6JuIHBo4buRaSBuaOG7iyB0aOG7qWM7DQoNCi0gICBUcsOsbmggYsOgeSByw7UgcsOgbmcgaMOgbSBsacOqbiBr4bq/dCwgY8OhY2ggdMOtbmggRUQ1MCwgeOG7rSBsw70gb3ZlcmRpc3BlcnNpb24sIHbDoCBkaeG7hW4gZ2nhuqNpIGxvZ2l0Ow0KDQotICAgxJDhurdjIGJp4buHdCBo4buvdSDDrWNoIHRyb25nIGPDoWMgYsOgaSB0b8OhbiBsb2dpc3RpYyByZWdyZXNzaW9uLCBkb3NlLXJlc3BvbnNlIHbDoCBzaW5oIGjhu41jIHBow6JuIHThu60uDQoNCiMjICoqQ0jGr8agTkcgMTA6IE3DlCBIw4xOSCDEkOG6vk0g4oCTIFBPSVNTT04gVsOAIE5FR0FUSVZFIEJJTk9NSUFMIEdMTXMqKg0KDQojIyMgKioxMC4xIEdp4bubaSB0aGnhu4d1KioNCg0KLSAgIE3DtCBow6xuaCBow7NhIGThu68gbGnhu4d1IMSR4bq/bSBsw6AgbeG7mXQg4bupbmcgZOG7pW5nIHBo4buVIGJp4bq/biB0cm9uZyBHTE1zLg0KDQotICAgROG7ryBsaeG7h3UgxJHhur9tIHh14bqldCBoaeG7h24ga2hpOg0KDQogICAgLSAgIEPDoWMgc+G7sSBraeG7h24geOG6o3kgcmEgxJHhu5ljIGzhuq1wOw0KDQogICAgLSAgIEtow7RuZyBjw7MgZ2nhu5tpIGjhuqFuIHRyw6puIHLDtSByw6BuZyBjaG8gc+G7kSBsxrDhu6NuZyBz4buxIGtp4buHbjsNCg0KLSAgIE3DtCBow6xuaCBow7NhIHPhu60gZOG7pW5nOg0KDQogICAgLSAgIFBow6JuIHBo4buRaSBQb2lzc29uIChjaMOtbmgpOw0KDQogICAgLSAgIFBvaXNzb24gR0xNcyBjaG8gZOG7ryBsaeG7h3UgxJHhur9tIHRoZW8gYmnhur9uIGdp4bqjaSB0aMOtY2g7DQoNCiAgICAtICAgTcO0IGjDrG5oIHThu7cgbOG7hyAocmF0ZXMpOw0KDQogICAgLSAgIELhuqNuZyBwaMOibiBsb+G6oWkgKGNvbnRpbmdlbmN5IHRhYmxlcykuDQoNCiMjIyAqKjEwLjIgUG9pc3NvbiBHTE1zKioNCg0K4pyFICoqUGjDom4gcGjhu5FpIFBvaXNzb24qKg0KDQotICAgSMOgbSB4w6FjIHN14bqldDoNCg0KJCQNClAoeTsgXG11KSA9IFxmcmFje2Veey1cbXV9IFxtdV55fXt5IX0NCiQkDQoNCi0gICBL4buzIHbhu41uZzoNCg0KJCQNCkVbeV0gPSBcbXUsIFxxdWFkIFx0ZXh0e3BoxrDGoW5nIHNhaTp9IFxxdWFkIFZhcih5KSA9IFxtdQ0KJCQNCg0KLSAgIMSQxqFuIHbhu4sgZGV2aWFuY2U6DQoNCiQkDQpkKHksIFxtdSkgPSAyIFxsZWZ0KCB5IFxsb2cgXGZyYWN7eX17XG11fSAtICh5IC0gXG11KSBccmlnaHQpDQokJA0KDQrinIUgKipIw6BtIGxpw6puIGvhur90KioNCg0KLSAgIExvZy1saW5rIChow6BtIGxpw6puIGvhur90IGNodeG6qW4pOg0KDQokJA0KXGxvZyhcbXUpID0gXGJldGFfMCArIFxzdW1faiBcYmV0YV9qIHhfag0KJCQNCg0KLSAgIERp4buFbiBnaeG6o2k6IHTDoWMgxJHhu5luZyBj4bunYSAkeF9qJCBsw6AgbmjDom4gduG7m2kgJFxtdSQgdGhlbyAkXGV4cChcYmV0YV9qKSQuDQoNCiMjIyAqKjEwLjMgTcO0IGjDrG5oIGjDs2EgdOG7tyBs4buHIChSYXRlcykqKg0KDQotICAgS2hpIHPhu5EgbMaw4bujbmcgxJHhur9tIHBo4bulIHRodeG7mWMgdsOgbyBxdXkgbcO0IGTDom4gc+G7kSBob+G6t2MgbeG7qWMgxJHhu5kgcGjGoWkgbmhp4buFbSAoZXhwb3N1cmUpOw0KDQotICAgU+G7rSBk4bulbmcgKipvZmZzZXQqKiB0cm9uZyBjw7RuZyB0aOG7qWMgR0xNIMSR4buDIMSRaeG7gXUgY2jhu4luaCBjaG8gcXV5IG3DtDoNCg0KICAgIGBnbG0oeSB+IHggKyBvZmZzZXQobG9nKHBvcHVsYXRpb24pKSwgZmFtaWx5PXBvaXNzb24pYA0KDQojIyMgKioxMC40IELhuqNuZyBwaMOibiBsb+G6oWkgKENvbnRpbmdlbmN5IFRhYmxlcykqKg0KDQotICAgS2hpIGJp4bq/biBnaeG6o2kgdGjDrWNoIGzDoCDEkeG7i25oIHTDrW5oIOKGkiBtw7QgaMOsbmggUG9pc3NvbiB0cuG7nyB0aMOgbmggKipsb2ctbGluZWFyIG1vZGVsKio7DQoNCi0gICBE4buvIGxp4buHdSAyIGNoaeG7gXUsIDMgY2hp4buBdSBjw7MgdGjhu4MgxJHGsOG7o2MgbcO0IGjDrG5oIGjDs2EgdGjDtG5nIHF1YSBjw6FjIHTGsMahbmcgdMOhYzsNCg0KLSAgIEPhuqluIHRy4buNbmcgduG7m2kgKip6ZXJvIGNvdW50cyoqOg0KDQogICAgLSAgICoqU2FtcGxpbmcgemVyb3MqKjogeOG6o3kgcmEgbmfhuqt1IG5oacOqbjsNCg0KICAgIC0gICAqKlN0cnVjdHVyYWwgemVyb3MqKjoga2jDtG5nIHRo4buDIHjhuqN5IHJhIOKAkyBj4bqnbiBsb+G6oWkgYuG7jyBraOG7j2kgbcO0IGjDrG5oDQoNCiMjIyAqKjEwLjUgT3ZlcmRpc3BlcnNpb24g4oCTIFF1w6EgcGjDom4gdMOhbioqDQoNCioqT3ZlcmRpc3BlcnNpb24gdHJvbmcgUG9pc3NvbiBHTE1zKioNCg0KLSAgIEtoaSBwaMawxqFuZyBzYWkgdGjhu7FjIHThur8gbOG7m24gaMahbiDOvFxtdc68Ow0KDQotICAg4bqibmggaMaw4bufbmc6DQoNCiAgICAtICAgU2FpIHPhu5EgY2h14bqpbiBi4buLIMSRw6FuaCBnacOhIHRo4bqlcDsNCg0KICAgIC0gICBUZXN0IHRo4buRbmcga8OqIGNobyB0aOG6pXkga+G6v3QgcXXhuqMgcXXDoSDigJzEkcOhbmcga+G7g+KAnTsNCg0KLSAgIFBow6F0IGhp4buHbiBxdWE6ICoqRGV2aWFuY2UgdGVzdCoqLCAqKlBlYXJzb24gZ29vZG5lc3Mtb2YtZml0LioqDQoNCioqTmVnYXRpdmUgQmlub21pYWwgR0xNcyoqDQoNCi0gICBHaeG6o2kgcGjDoXAgbcO0IGjDrG5oIGjDs2Egb3ZlcmRpc3BlcnNpb246DQoNCiAgICAtICAgR2nhuqMgxJHhu4tuaCAkXG11X2kkIGPDsyBwaMOibiBwaOG7kWkgR2FtbWEg4oaSDQoNCiQkDQp5X2kgXHNpbSBcdGV4dHtOQn0oXG11LCBrKQ0KJCQNCg0KLSAgIFBoxrDGoW5nIHNhaToNCg0KJCQNClx0ZXh0e1Zhcn0oeSkgPSBcbXUgKyBcZnJhY3tcbXVeMn17a30NCiQkDQoNCi0gICDGr+G7m2MgbMaw4bujbmcgxJHhu5NuZyB0aOG7nWkgJFxiZXRhJCB2w6AgJGskIGLhurFuZyBgZ2xtLm5iKClgIHRyb25nIFI6DQoNCiAgICBgbGlicmFyeShNQVNTKSBnbG0ubmIoQ291bnQgfiBsb2cyKERpbHV0aW9uKSwgZGF0YT1wb2NrKWANCg0KKipRdWFzaS1Qb2lzc29uIEdMTXMqKg0KDQotICAgS2jDtG5nIG3DtCBow6xuaCBow7NhIHBow6JuIHBo4buRaSB4w6FjIHN14bqldCwgY2jhu4kgc+G7rSBk4bulbmcgcGjGsMahbmcgc2FpOg0KDQokJA0KXHRleHR7VmFyfSh5KSA9IFxwaGkgXG11DQokJA0KDQotICAgxq/hu5tjIGzGsOG7o25nIOG7lW4gxJHhu4tuaCwgcGjDuSBo4bujcCBraGkgY2jhu4kgcXVhbiB0w6JtIMSR4bq/biAqKnN1eSBsdeG6rW4gdGjhu5FuZyBrw6oqKiAoaW5mZXJlbmNlKSwgKipraMO0bmcgZMO5bmcgQUlDKiouDQotICAgRMO5bmcgdHJvbmcgUiB24bubaTogYGdsbSguLi4sIGZhbWlseT1xdWFzaXBvaXNzb24oKSlgDQoNCiMjIyAqKjEwLjYgVsOtIGThu6U6IFBvaXNzb24gdsOgIE5lZ2F0aXZlIEJpbm9taWFsIHNvIHPDoW5oKioNCg0KLSAgICoqROG7ryBsaeG7h3UgcG9jayoqOg0KDQogICAgLSAgIFBvaXNzb24gR0xNIGtow7RuZyBwaMO5IGjhu6NwIGRvIG92ZXJkaXNwZXJzaW9uOw0KDQogICAgLSAgIE5lZ2F0aXZlIEJpbm9taWFsIHbDoCBRdWFzaS1Qb2lzc29uIHBow7kgaOG7o3AgaMahbjsNCg0KICAgIC0gICBTbyBzw6FuaCBjb25maWRlbmNlIGludGVydmFsIHbDoCBzYWkgc+G7kSBjaHXhuqluIGdp4buvYSBjw6FjIG3DtCBow6xuaC4NCg0KIyMjICoqMTAuNyBNw6MgUiBz4butIGThu6VuZyBHTE1zIGNobyDEkeG6v20qKg0KDQotICAgKipQb2lzc29uIEdMTSoqOg0KDQogICAgYGdsbSh5IH4geCwgZmFtaWx5PXBvaXNzb24pYA0KDQotICAgKipRdWFzaS1Qb2lzc29uKio6IGBnbG0oeSB+IHgsIGZhbWlseT1xdWFzaXBvaXNzb24pYA0KDQotICAgKipOZWdhdGl2ZSBCaW5vbWlhbCoqOiBgZ2xtLm5iKHkgfiB4KWANCg0KIyMjICoqMTAuOCBU4buVbmcga+G6v3QgY2jGsMahbmcqKg0KDQotICAgUG9pc3NvbiBHTE0gbMOgIG3DtCBow6xuaCBu4buBbiB04bqjbmcgY2hvIGThu68gbGnhu4d1IMSR4bq/bTsNCg0KLSAgIEtoaSBjw7Mgb3ZlcmRpc3BlcnNpb246DQoNCiAgICAtICAgRMO5bmcgTmVnYXRpdmUgQmlub21pYWwgR0xNIG7hur91IGPhuqduIG3DtCBow6xuaCB4w6FjIHN14bqldDsNCg0KICAgIC0gICBEw7luZyBRdWFzaS1Qb2lzc29uIEdMTSBu4bq/dSBj4bqnbiBpbmZlcmVuY2UgxJHGoW4gZ2nhuqNuOw0KDQotICAgxJDDoW5oIGdpw6EgY+G6p24ga+G6v3QgaOG7o3AgZGV2aWFuY2UsIHBo4bqnbiBkxrAsIHbDoCBs4buxYSBjaOG7jW4gbcO0IGjDrG5oIHBow7kgaOG7o3ANCg0KIyMgKipDSMavxqBORyAxMTogROG7riBMSeG7hlUgRMavxqBORyBMScOKTiBU4bukQyDigJMgTcOUIEjDjE5IIEdBTU1BIFbDgCBJTlZFUlNFIEdBVVNTSUFOIEdMTXMqKg0KDQojIyMgKioxMS4xIEdp4bubaSB0aGnhu4d1KioNCg0KLSAgIENoxrDGoW5nIG7DoHkgdOG6rXAgdHJ1bmcgdsOgbyAqKkdMTXMgY2hvIGThu68gbGnhu4d1IGTGsMahbmcgdsOgIGxpw6puIHThu6VjKiog4oCTIHRoxrDhu51uZyBsw6AgY8OhYyDEkeG6oWkgbMaw4bujbmcgxJFvIGzGsOG7nW5nIG5oxrAgdGjhu51pIGdpYW4sIGNoaSBwaMOtLCBuxINuZyBzdeG6pXQsLi4uDQoNCi0gICBIYWkgcGjDom4gcGjhu5FpIGNow61uaCDEkcaw4bujYyBz4butIGThu6VuZzoNCg0KICAgIC0gICAqKlBow6JuIHBo4buRaSBHYW1tYSoqIChWKM68KSA9IM68wrIpDQoNCiAgICAtICAgKipQaMOibiBwaOG7kWkgSW52ZXJzZSBHYXVzc2lhbioqIChWKM68KSA9IM68wrMpDQoNCi0gICBN4bulYyB0acOqdSBsw6AgKiptw7QgaMOsbmggaMOzYSBxdWFuIGjhu4cgYuG6pXQgxJHhu5FpIHjhu6luZyoqIGdp4buvYSBiaeG6v24gcGjhuqNuIGjhu5NpIHbDoCBiaeG6v24gZ2nhuqNpIHRow61jaC4NCg0KIyMjICoqMTEuMiBNw7QgaMOsbmggaMOzYSBk4buvIGxp4buHdSBkxrDGoW5nIGxpw6puIHThu6VjKioNCg0KLSAgIEThu68gbGnhu4d1IHRoxrDhu51uZyAqKmzhu4djaCBwaOG6o2kqKiwga2jDtG5nIHRo4buDIGPDsyBnacOhIHRy4buLIMOibS4NCg0KLSAgIFBoxrDGoW5nIHNhaSB0aMaw4budbmcgdMSDbmcgdGhlbyBnacOhIHRy4buLIHRydW5nIGLDrG5oLg0KDQotICAgQ8OhYyBow6BtIHBoxrDGoW5nIHNhaSB0xINuZyBuaGFuaCBuaMawIM68wrIgdsOgIM68wrMgdGjGsOG7nW5nIHh14bqldCBoaeG7h24g4oeSIHBow7kgaOG7o3AgduG7m2kgR2FtbWEgdsOgIEludmVyc2UgR2F1c3NpYW4gR0xNcy4NCg0KIyMjICoqMTEuMyBQaMOibiBwaOG7kWkgR2FtbWEqKg0KDQotICAgRMO5bmcgxJHhu4MgbcO0IHThuqMgKip0aOG7nWkgZ2lhbiBnaeG7r2EgY8OhYyBz4buxIGtp4buHbiBQb2lzc29uKiouDQoNCi0gICDEkOG7i25oIG5naMSpYSDEkcahbiB24buLIGRldmlhbmNlOg0KDQogICAgJCQNCiAgICBkKHksIFxtdSkgPSAyXGxlZnQoIC1cbG9nIFxmcmFje3l9e1xtdX0gKyBcZnJhY3t5IC0gXG11fXtcbXV9IFxyaWdodCkNCiAgICAkJA0KDQotICAgUGjDom4gcGjhu5FpIERldmlhbmNlIHjhuqVwIHjhu4kgcGjDom4gcGjhu5FpIGNoaSBiw6xuaCBwaMawxqFuZyBraGkgJFxwaGkgXGxlcSBcZnJhY3sxfXszfSQ6DQoNCiAgICAkJA0KICAgIFx0ZXh0e0RldmlhbmNlfSBcc2ltIFxjaGleMl97biAtIHAnfQ0KICAgICQkDQoNCi0gICBMacOqbiBr4bq/dCBjaHXhuqluIChjYW5vbmljYWwgbGluaykgdHJvbmcgcGjDom4gcGjhu5FpIFBvaXNzb24gbMOgIGjDoG0gbmdo4buLY2ggxJHhuqNvOg0KDQogICAgJCQNCiAgICBcZXRhID0gXGZyYWN7MX17XG11fQ0KICAgICQkDQoNCi0gICBUcm9uZyB0aOG7sWMgaMOgbmgsIHRoxrDhu51uZyBkw7luZyAqKmxvZy1saW5rKiogxJHhu4MgxJHhuqNtIGLhuqNvICTOvD4wJCB2w6AgZOG7hSBkaeG7hW4gZ2nhuqNpLg0KDQojIyMgKioxMS40IFBow6JuIHBo4buRaSBJbnZlcnNlIEdhdXNzaWFuKioNCg0KLSAgIETDuW5nIGNobyBk4buvIGxp4buHdSAqKmzhu4djaCBt4bqhbmggaMahbioqIEdhbW1hLg0KDQotICAgQ8OzIGxpw6puIGjhu4cgduG7m2kgKip0aOG7nWkgZ2lhbiBjaOG6oW0gbmfGsOG7oW5nIHRyb25nIGNodXnhu4NuIMSR4buZbmcgQnJvd24gKEJyb3duaWFuIG1vdGlvbikqKi4NCg0KLSAgIEjDoG0gcGjGsMahbmcgc2FpOiAkVihcbXUpID0gXG11XjMkDQoNCi0gICBMacOqbiBr4bq/dCBjaHXhuqluOiAkXGV0YSA9IDEvXG11XjIkLCBuaMawbmcgdGjGsOG7nW5nIGTDuW5nIGxvZy1saW5rIGjGoW4gxJHhu4MgxJHhuqNtIGLhuqNvICTOvD4gMCQuDQoNCiMjIyAqKjExLjUgQ8OhYyBow6BtIGxpw6puIGvhur90IChMaW5rIGZ1bmN0aW9ucykqKg0KDQotICAgRMO5bmcgxJHGsOG7o2MgY2hvIGPhuqMgR2FtbWEgdsOgIEludmVyc2UgR2F1c3NpYW46DQoNCiAgICAtICAgYCJsb2ciYCDigJMgcGjhu5UgYmnhur9uIG5o4bqldCwgxJHhuqNtIGLhuqNvICTOvCA+IDAkOw0KDQogICAgLSAgIGAiaWRlbnRpdHkiYCDigJMgZMO5bmcga2hpIG3hu5FpIHF1YW4gaOG7hyB0dXnhur9uIHTDrW5oOw0KDQogICAgLSAgIGAiaW52ZXJzZSJgIOKAkyBsacOqbiBr4bq/dCBjaHXhuqluIGPhu6dhIEdhbW1hOw0KDQogICAgLSAgIGAiMS9tdV4yImAg4oCTIGxpw6puIGvhur90IGNodeG6qW4gY+G7p2EgSW52ZXJzZSBHYXVzc2lhbi4NCg0KIyMjICoqMTEuNiDGr+G7m2MgbMaw4bujbmcgdGhhbSBz4buRIHBow6JuIHTDoW4gz4YqKg0KDQotICAgQ+G6oyBoYWkgbcO0IGjDrG5oIMSR4buBdSBj4bqnbiDGsOG7m2MgbMaw4bujbmcgJM+VJA0KDQotICAgKipHYW1tYSBHTE0qKjoNCg0KICAgIC0gICDGr+G7m2MgbMaw4bujbmcgUGVhcnNvbiB2w6AgZGV2aWFuY2Uga2jDoWMgbmhhdSBuaMawbmcgZ+G6p24gbmhhdTsNCg0KICAgIC0gICBMUlQgZOG7sWEgdHLDqm4gcGjDom4gcGjhu5FpIEYgbuG6v3Ugz4YgxJHGsOG7o2MgxrDhu5tjIGzGsOG7o25nLg0KDQotICAgKipJbnZlcnNlIEdhdXNzaWFuIEdMTSoqOg0KDQogICAgLSAgIMav4bubYyBsxrDhu6NuZyBNTEUgY+G7p2EgXCTPlVwkIGzDoCBjaMOtbmggeMOhYy4NCg0KICAgIC0gICBEZXZpYW5jZSB0dcOibiB0aGVvIHBow6JuIHBo4buRaSAkz4deMiQgxJHDum5nIChraMO0bmcgY2jhu4kgeOG6pXAgeOG7iSkuDQoNCiMjIyAqKjExLjcgTmdoacOqbiBj4bupdSB0w6xuaCBodeG7kW5nKioNCg0KLSAgICoqQ2FzZSBzdHVkeSAxIChwZXJtZWFiaWxpdHkpKio6DQoNCiAgICAtICAgROG7ryBsaeG7h3UgxJFvIMSR4buZIHRo4bqlbSBj4bunYSB24bqtdCBsaeG7h3UgeMOieSBk4buxbmc7DQoNCiAgICAtICAgUGjDuSBo4bujcCB24bubaSBtw7QgaMOsbmggKippbnZlcnNlIEdhdXNzaWFuKiogKyBsb2ctbGluazoNCg0KICAgIGBnbG0oUGVybSB+IE1hY2ggKiBEYXksIGZhbWlseT1pbnZlcnNlLmdhdXNzaWFuKGxpbms9ImxvZyIpLCBkYXRhPXBlcm0pYA0KDQotICAgKipDYXNlIHN0dWR5IDIgKG9uaW9uIHlpZWxkKSoqOg0KDQogICAgLSAgIE3DtCBow6xuaCBHYW1tYSBjaG8gc+G6o24gbMaw4bujbmcgaMOgbmggdGhlbyBt4bqtdCDEkeG7mSB0cuG7k25nIHbDoCBnaeG7kW5nLg0KDQojIyMgKioxMS44IFPhu60gZOG7pW5nIFIgxJHhu4Mga2jhu5twIG3DtCBow6xuaCoqDQoNCi0gICBDw7ogcGjDoXAgY2hvICoqR2FtbWEgR0xNKio6DQoNCiAgICBgZ2xtKGZvcm11bGEsIGZhbWlseT1HYW1tYShsaW5rPSJsb2ciKSlgDQoNCi0gICBDw7ogcGjDoXAgY2hvICoqSW52ZXJzZSBHYXVzc2lhbiBHTE0qKjogYGdsbShmb3JtdWxhLCBmYW1pbHk9aW52ZXJzZS5nYXVzc2lhbihsaW5rPSJsb2ciKSlgDQoNCi0gICBDw7MgdGjhu4Mgc+G7rSBk4bulbmcgY8OhYyBsacOqbiBr4bq/dCBgImxvZyJgLCBgImludmVyc2UiYCwgYCJpZGVudGl0eSJgIGNobyBj4bqjIGhhaTsgcmnDqm5nIEludmVyc2UgR2F1c3NpYW4gY8OybiB0aMOqbSBgIjEvbXVeMiJgLg0KDQojIyMgKioxMS45IFThu5VuZyBr4bq/dCBjaMawxqFuZyoqDQoNCi0gICBNw7QgaMOsbmggR2FtbWEgdsOgIEludmVyc2UgR2F1c3NpYW4gcuG6pXQgdGjDrWNoIGjhu6NwIGNobyBk4buvIGxp4buHdSAqKmxpw6puIHThu6VjIHbDoCBkxrDGoW5nKiogduG7m2kgcGjGsMahbmcgc2FpIHTEg25nIHRoZW8gdHJ1bmcgYsOsbmguDQoNCi0gICBWaeG7h2MgY2jhu41uIMSRw7puZyBow6BtIGxpw6puIGvhur90IHbDoCBwaMOibiBwaOG7kWkgcuG6pXQgcXVhbiB0cuG7jW5nIMSR4buDIG3DtCBow6xuaCBwaOG6o24gw6FuaCBjaMOtbmggeMOhYyBi4bqjbiBjaOG6pXQgZOG7ryBsaeG7h3UuDQoNCi0gICBSIGN1bmcgY+G6pXAgY8O0bmcgY+G7pSBsaW5oIGhv4bqhdCDEkeG7gyBraOG7m3AsIGNo4bqpbiDEkW/DoW4sIHbDoCBraeG7g20gxJHhu4tuaCBjw6FjIG3DtCBow6xuaCBuw6B5DQoNCiMjICoqQ0jGr8agTkcgMTI6IE3DlCBIw4xOSCBUV0VFRElFIFRST05HIEdMTXMqKg0KDQojIyMgKioxMi4xIEdp4bubaSB0aGnhu4d1KioNCg0KLSAgIENoxrDGoW5nIG7DoHkgbeG7nyBy4buZbmcgcGjhuqFtIHZpIEdMTXMgxJHhur9uIG3hu5l0IGzhu5twIHBow6JuIHBo4buRaSDEkeG6t2MgYmnhu4d0IGfhu41pIGzDoCAqKlR3ZWVkaWUgZGlzdHJpYnV0aW9ucyoqLCBnacO6cCB44butIGzDvToNCg0KICAgIC0gICBE4buvIGxp4buHdSBjw7MgY+G6pXUgdHLDumMgKipsacOqbiB04bulYyArIMSR4bq/bSAoc2VtaWNvbnRpbnVvdXMpKio7DQoNCiAgICAtICAgROG7ryBsaeG7h3UgKipraMO0bmcgw6JtLCBs4buHY2ggcGjhuqNpKiosIGPDsyBnacOhIHRy4buLIDAgduG7m2kgeMOhYyBzdeG6pXQgZMawxqFuZzsNCg0KLSAgIE3DtCBow6xuaCBUd2VlZGllIMSR4bq3YyBiaeG7h3QgdGjDrWNoIGjhu6NwIGNobyAqKm3DtCBow6xuaCBow7NhIGLhuqNvIGhp4buDbSwgdMOgaSBjaMOtbmgsIHbDoCBtw7RpIHRyxrDhu51uZyoqLg0KDQojIyMgKioxMi4yIEjhu40gcGjDom4gcGjhu5FpIFR3ZWVkaWUqKg0KDQotICAgTMOgIG3hu5l0IG5ow6FuaCBj4bunYSAqKkV4cG9uZW50aWFsIERpc3BlcnNpb24gTW9kZWxzIChFRE1zKSoqLCB4w6FjIMSR4buLbmggYuG7n2k6DQoNCiAgICAkJA0KICAgIFx0ZXh0e1Zhcn0oWSkgPSBccGhpIFxtdV5wDQogICAgJCQNCg0KICAgIFbhu5tpOg0KDQogICAgLSAgICTOvCQ6IGvhu7MgduG7jW5nOw0KDQogICAgLSAgICTPlSQ6IHRoYW0gc+G7kSBwaMOibiB0w6FuOw0KDQogICAgLSAgICRwJDogdGhhbSBz4buRIGNo4buJIHPhu5EgKGluZGV4IHBhcmFtZXRlcikgxJHhurdjIHRyxrBuZyBjaG8gZOG6oW5nIHBow6JuIHBo4buRaQ0KDQp8IEdpw6EgdHLhu4sgJHAkIHwgTG/huqFpIHBow6JuIHBo4buRaSB0xrDGoW5nIOG7qW5nIHwNCnwtLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCAwICAgICAgICAgICB8IE5vcm1hbCAgICAgICAgICAgICAgICAgICB8DQp8IDEgICAgICAgICAgIHwgUG9pc3NvbiAgICAgICAgICAgICAgICAgIHwNCnwgKDEsMikgICAgICAgfCBDb21wb3VuZCBQb2lzc29uLUdhbW1hICAgfA0KfCAyICAgICAgICAgICB8IEdhbW1hICAgICAgICAgICAgICAgICAgICB8DQp8IDMgICAgICAgICAgIHwgSW52ZXJzZSBHYXVzc2lhbiAgICAgICAgIHwNCg0KIyMjICoqMTIuMyBNw7QgaMOsbmggaMOzYSBk4buvIGxp4buHdSBzZW1pY29udGludW91cyoqDQoNCi0gICBUcm9uZyBuaGnhu4F1IHRyxrDhu51uZyBo4bujcCB0aOG7sWMgdOG6vywgZOG7ryBsaeG7h3UgY8OzIHBow6JuIHBo4buRaSB24bubaSBwaOG6p24gdOG7rToNCg0KICAgIC0gICBHacOhIHRy4buLIDAgduG7m2kgeMOhYyBzdeG6pXQgbOG7m24gKHTGsMahbmcg4bupbmcgduG7m2kgKirEkeG6v20qKiBob+G6t2Mga2jDtG5nIHjhuqN5IHJhIHPhu7Ega2nhu4duKSwNCg0KICAgIC0gICBHacOhIHRy4buLIGTGsMahbmcgbGnDqm4gdOG7pWMgKHbDrSBk4bulICoqY2hpIHBow60qKiwgKip04buVbiB0aOG6pXQqKiwuLi4pLg0KDQotICAgUGjDom4gcGjhu5FpIFR3ZWVkaWUgduG7m2kgJDEgPCBwIDwgMiQgbcO0IGjDrG5oIGjDs2EgcuG6pXQgdOG7kXQga2nhu4N1IGThu68gbGnhu4d1IG7DoHkuDQoNCiMjIyAqKjEyLjQgxq/hu5tjIGzGsOG7o25nIHRyb25nIG3DtCBow6xuaCBUd2VlZGllKioNCg0KLSAgIEtow7RuZyBjw7MgZOG6oW5nIHjDoWMgc3XhuqV0IMSRw7NuZyDigJMgY+G6p24gc+G7rSBk4bulbmc6DQoNCiAgICAtICAgKipQaMawxqFuZyBwaMOhcCB44bqlcCB44buJIChxdWFzaS1saWtlbGlob29kKSoqOw0KDQogICAgLSAgICoqUGjGsMahbmcgcGjDoXAgbOG6rXAgdHLDrG5oIHThu5FpIMawdSBow7NhKiogKHByb2ZpbGUgbGlrZWxpaG9vZCk7DQoNCiAgICAtICAgROG7sW5nIEdMTSBi4bqxbmcgY8OhY2ggxrDhu5tjIGzGsOG7o25nIMSR4buTbmcgdGjhu51pICTOsiQsICTPlSQgdsOgICRwJC4NCg0KIyMjICoqMTIuNSBT4butIGThu6VuZyBSIMSR4buDIGto4bubcCBtw7QgaMOsbmggVHdlZWRpZSoqDQoNCi0gICBD4bqnbiBnw7NpIGBzdGF0bW9kYCwgYHR3ZWVkaWVgLCBob+G6t2MgYG1nY3ZgOg0KDQotICAgYGxpYnJhcnkoc3RhdG1vZCkgbGlicmFyeSh0d2VlZGllKSBnbG0oVG90YWxDb3N0IH4gQWdlICsgU2V4LCBmYW1pbHk9dHdlZWRpZSh2YXIucG93ZXI9MS41LCBsaW5rLnBvd2VyPTApLCBkYXRhPWRmKWANCg0KLSAgIEPDsyB0aOG7gyBkw7luZyBow6BtIGB0d2VlZGllLnByb2ZpbGUoKWAgxJHhu4MgY2jhu41uIGdpw6EgdHLhu4sgdOG7kWkgxrB1IGNobyBwcHAuDQoNCiMjIyAqKjEyLjYg4buobmcgZOG7pW5nIHRo4buxYyB04bq/KioNCg0KLSAgICoqQuG6o28gaGnhu4NtKio6IGThu7EgxJFvw6FuIGNoaSBwaMOtIHkgdOG6vywgdOG7lW4gdGjhuqV0Ow0KDQotICAgKipTaW5oIHRow6FpIGjhu41jKio6IG3huq10IMSR4buZIGxvw6BpICsgdsO5bmcga2jDtG5nIHF1YW4gc8OhdCDEkcaw4bujYzsNCg0KLSAgICoqTsSDbmcgbMaw4bujbmcqKjogZOG7ryBsaeG7h3UgdGnDqnUgdGjhu6UgY8OzIG5oaeG7gXUgc+G7kSAwIHbDoCBwaMOibiBi4buRIGzhu4djaC4NCg0KKipU4buVbmcga+G6v3QgY2jGsMahbmcqKg0KDQotICAgTcO0IGjDrG5oIFR3ZWVkaWUgbeG7nyBy4buZbmcgR0xNcyBzYW5nIGPDoWMgdMOsbmggaHXhu5FuZyBk4buvIGxp4buHdSBwaOG7qWMgdOG6oXA6DQoNCiAgICAtICAgROG7ryBsaeG7h3UgYsOhbiBsacOqbiB04bulYzsNCg0KICAgIC0gICBQaMOibiBwaOG7kWkgbOG7h2NoIHbDoCBraMO0bmcgY2h14bqpbjsNCg0KICAgIC0gICBOaGnhu4F1IGdpw6EgdHLhu4sgMCBjw7MgdMOtbmggaOG7hyB0aOG7kW5nOw0KDQotICAgVHV5IHTDrW5oIHRvw6FuIHBo4bupYyB04bqhcCBoxqFuLCBuaMawbmcgVHdlZWRpZSBHTE1zIGzDoCBjw7RuZyBj4bulIGPhu7FjIGvhu7MgbGluaCBob+G6oXQgdsOgIG3huqFuaCBt4bq9IHRyb25nIG3DtCBow6xuaCBow7NhIHRo4buxYyBuZ2hp4buHbSBoaeG7h24gxJHhuqFpLg0KDQojIyAqKkNIxq/GoE5HIDEzOiBN4bueIFLhu5hORyBNw5QgSMOMTkggSMOTQSBUUk9ORyBHTE1zKioNCg0KIyMjICoqMTMuMSBHaeG7m2kgdGhp4buHdSoqDQoNCkNoxrDGoW5nIG7DoHkgdHLDrG5oIGLDoHkgY8OhYyBr4bu5IHRodeG6rXQgbeG7nyBy4buZbmcgxJHhu4M6DQoNCi0gICBWxrDhu6N0IHF1YSBjw6FjIGdp4bubaSBo4bqhbiBj4bunYSBHTE1zIGPhu5UgxJFp4buDbjsNCg0KLSAgIEPhuqNpIHRoaeG7h24gxJHhu5kgbGluaCBob+G6oXQgdHJvbmcgbcO0IGjDrG5oIGjDs2EgcGhpIHR1eeG6v24sIHBow6JuIHTDoW4gdGhheSDEkeG7lWksLi4uOw0KDQotICAgw4FwIGThu6VuZyBr4bu5IHRodeG6rXQgbmjGsCBzcGxpbmUsIHNtb290aGVycywgcXVhc2ktbGlrZWxpaG9vZCB2w6AgbcO0IGjDrG5oIHBow6JuIHTDoW4gdGhheSDEkeG7lWkgKGhldGVyb3NjZWRhc3RpYyBHTE1zKS4NCg0KIyMjICoqMTMuMiBNw7QgaMOsbmggaMOzYSBoaeG7h3Ug4bupbmcgcGhpIHR1eeG6v24gKE5vbmxpbmVhciBFZmZlY3RzKSoqDQoNCi0gICBUcm9uZyBHTE0gY+G7lSDEkWnhu4NuLCBt4buRaSBxdWFuIGjhu4cgZ2nhu69hIGJp4bq/biBnaeG6o2kgdGjDrWNoIHbDoCBiaeG6v24gcGjhuqNuIGjhu5NpIGzDoCAqKnR1eeG6v24gdMOtbmggc2F1IGjDoG0gbGnDqm4ga+G6v3QqKi4NCg0KLSAgIEtoaSDEkWnhu4F1IG7DoHkga2jDtG5nIMSRw7puZywgY8OzIHRo4buDIGTDuW5nOg0KDQogICAgLSAgICoqSMOgbSBzcGxpbmUqKiAoYHNwbGluZXM6Om5zKClgLCBgYnMoKWApOw0KDQogICAgLSAgICoqU21vb3RoZXJzKiogKGBtZ2N2OjpnYW0oKWApLg0KDQoqKlbDrSBk4bulIFI6KiogYGxpYnJhcnkoc3BsaW5lcykgZ2xtKHkgfiBucyh4LCBkZj00KSwgZmFtaWx5PXBvaXNzb24sIGRhdGE9ZGYpYA0KDQojIyMgKioxMy4zIFNwbGluZSB2w6AgaMOgbSB0csahbiBow7NhIChTbW9vdGhpbmcpKioNCg0KLSAgICoqTmF0dXJhbCBzcGxpbmVzKio6IHRyw6FuaCBoaeG7h24gdMaw4bujbmcgZGFvIMSR4buZbmcg4bufIGJpw6puOw0KDQotICAgKipCLXNwbGluZXMqKjoga2nhu4NtIHNvw6F0IHThu5F0IGjGoW4gbeG7qWMgxJHhu5kgdHLGoW47DQoNCi0gICAqKkdBTSAoR2VuZXJhbGl6ZWQgQWRkaXRpdmUgTW9kZWxzKSoqOiBt4bufIHLhu5luZyBHTE0gduG7m2kgdGjDoG5oIHBo4bqnbiB0csahbiBow7NhOg0KDQogICAgYGxpYnJhcnkobWdjdikgZ2FtKHkgfiBzKHgxKSArIHMoeDIpLCBmYW1pbHk9cG9pc3NvbiwgZGF0YT1kZilgDQoNCiMjIyAqKjEzLjQgQmnhur9uIHBow6JuIHTDoW4gKFZhcnlpbmcgZGlzcGVyc2lvbikqKg0KDQotICAgVHJvbmcgbmhp4buBdSDhu6luZyBk4bulbmcsIHRoYW0gc+G7kSBwaMOibiB0w6FuICTPlSQga2jDtG5nIGjhurFuZyBz4buROw0KDQotICAgQ8OzIHRo4buDIG3DtCBow6xuaCBow7NhICTPlSQgbmjGsCBt4buZdCBow6BtIHPhu5EgY+G7p2EgYmnhur9uIGdp4bqjaSB0aMOtY2g6DQoNCiAgICAtICAgRMO5bmcgcXVhc2ktbGlrZWxpaG9vZDsNCg0KICAgIC0gICBEw7luZyBtw7QgaMOsbmggbOG7k25nIChoaWVyYXJjaGljYWwvbXVsdGlsZXZlbCBHTE1zKTsNCg0KICAgIC0gICBIb+G6t2MgbcO0IGjDrG5oIGhhaSBwaOG6p24gKGRvdWJsZSBHTE0pLg0KDQojIyMgKioxMy41IFBow6JuIHTDrWNoIGLDoW4gdGhhbSBz4buRIChTZW1pcGFyYW1ldHJpYyBtZXRob2RzKSoqDQoNCi0gICBEw7luZyBraGkgY2jGsGEgeMOhYyDEkeG7i25oIMSRxrDhu6NjIGNow61uaCB4w6FjIGThuqFuZyBsacOqbiBr4bq/dDsNCg0KLSAgIEdBTSwgc3BsaW5lIHbDoCBrZXJuZWwgcmVncmVzc2lvbiBnacO6cCBkdXkgdHLDrCB0w61uaCBsaW5oIGhv4bqhdCBuaMawbmcgduG6q24gZOG7hSBnaeG6o2kgdGjDrWNoLg0KDQojIyMgKioxMy42IE3DtCBow6xuaCBow7NhIHTDoWMgxJHhu5luZyBuZ+G6q3Ugbmhpw6puIChSYW5kb20gZWZmZWN0cyBhbmQgbWl4ZWQgbW9kZWxzKSoqDQoNCi0gICBL4bq/dCBo4bujcCBHTE0gduG7m2kgKipjw6FjIHRow6BuaCBwaOG6p24gbmfhuqt1IG5oacOqbioqOg0KDQogICAgLSAgIEThu68gbGnhu4d1IHBow6JuIGPhuqVwLCBs4buTbmcgZ2jDqXAgKHbDrSBk4bulOiBo4buNYyBzaW5oIHRyb25nIGzhu5twLCBi4buHbmggbmjDom4gdHJvbmcgYuG7h25oIHZp4buHbik7DQoNCiAgICAtICAgU+G7rSBk4bulbmcgYGdsbWVyKClgIHRyb25nIGBsbWU0YDoNCg0KICAgICAgICBgbGlicmFyeShsbWU0KSBnbG1lcih5IH4geCArICgxIHwgZ3JvdXApLCBmYW1pbHk9cG9pc3NvbiwgZGF0YT1kZilgDQoNCiMjIyAqKjEzLjcgTOG7sWEgY2jhu41uIG3DtCBow6xuaCBt4bufIHLhu5luZyoqDQoNCi0gICBOZ2/DoGkgQUlDL0JJQyBjw7JuIGPDszoNCg0KICAgIC0gICAqKkdDVioqIChHZW5lcmFsaXplZCBDcm9zcy1WYWxpZGF0aW9uKTsNCg0KICAgIC0gICAqKkRldmlhbmNlIGV4cGxhaW5lZCoqOw0KDQogICAgLSAgICoqQWRqdXN0ZWQgUsKyKiogY2hvIEdBTXMuDQoNCioqVOG7lW5nIGvhur90IGNoxrDGoW5nKioNCg0KLSAgIEdMTXMgY+G7lSDEkWnhu4NuIG3huqFuaCBuaMawbmcgY8OzIGdp4bubaSBo4bqhbiB0cm9uZzoNCg0KICAgIC0gICBCaeG6v24gaGnhu4d1IOG7qW5nIHBoaSB0dXnhur9uOw0KDQogICAgLSAgIFBow6JuIHTDoW4gdGhheSDEkeG7lWk7DQoNCiAgICAtICAgQ+G6pXUgdHLDumMgZOG7ryBsaeG7h3UgbOG7k25nOw0KDQogICAgQ2jGsMahbmcgMTMgdHLDrG5oIGLDoHkgY8OhY2ggKipr4bq/dCBo4bujcCBjw6FjIGvhu7kgdGh14bqtdCBoaeG7h24gxJHhuqFpIChzcGxpbmUsIEdBTSwgbcO0IGjDrG5oIGjhu5duIGjhu6NwKSoqIMSR4buDIG3hu58gcuG7mW5nIHTDrW5oIGxpbmggaG/huqF0IHbDoCBraOG6oyBuxINuZyBtw7QgaMOsbmggaMOzYSBk4buvIGxp4buHdSB0aOG7sWMgdOG6vy4NCg0KIyAqKkLDgEkgVOG6rFAgMjogVEjhu5BORyBLw4ogTcOUIFThuqIgIlN1cGVybWFya2V0IFRyYW5zYWN0aW9ucy5jc3YiKioNCg0KYGBge3J9DQojIFThuqNpIGPDoWMgdGjGsCB2aeG7h24gY+G6p24gdGhp4bq/dA0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc3VtbWFyeXRvb2xzKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoc2NhbGVzKSANCmBgYA0KDQojIyAqKjEuIMSQ4buNYyBk4buvIGxp4buHdSoqDQoNCmBgYHtyfQ0KIyDEkOG7jWMgZmlsZSBDU1YNCmRhdGEgPC0gcmVhZC5jc3YoIkQ6L1BURExEVC9TdXBlcm1hcmtldCBUcmFuc2FjdGlvbnMuY3N2IikNCg0KIyBLaeG7g20gdHJhIGPhuqV1IHRyw7pjIGThu68gbGnhu4d1DQpzdHIoZGF0YSkNCmBgYA0KDQojIyAqKjIuIFThu5VuZyBxdWFuIGThu68gbGnhu4d1KioNCg0KYGBge3J9DQojIFTDs20gdOG6r3QgdG/DoG4gYuG7mSBk4buvIGxp4buHdQ0Kc3VtbWFyeShkYXRhKQ0KYGBgDQoNCkLhuqNuZyBr4bq/dCBxdeG6oyBjaG8gdGjhuqV5IHThuq1wIGThu68gbGnhu4d1IGfhu5NtIDE0LjA1OSBkw7JuZyB24bubaSBuaGnhu4F1IGJp4bq/biB0aMO0bmcgdGluIHbhu4Ega2jDoWNoIGjDoG5nLCBz4bqjbiBwaOG6qW0gdsOgIGdpYW8gZOG7i2NoLiBCYW8gZ+G7k20gYmnhur9uIMSR4buLbmggbMaw4bujbmcgdsOgIGJp4bq/biDEkeG7i25oIHTDrW5oLg0KDQojIyAqKjMuIFRo4buRbmcga8OqIG3DtCB04bqjIGPDoWMgYmnhur9uIMSR4buLbmggbMaw4bujbmcqKg0KDQpgYGB7cn0NCiMgQ2jhu41uIGPDoWMgYmnhur9uIMSR4buLbmggbMaw4bujbmcNCm51bWVyaWNfdmFycyA8LSBkYXRhICU+JSANCiAgc2VsZWN0KEFubnVhbEluY29tZSwgQ2hpbGRyZW4sIFVuaXRzU29sZCwgUmV2ZW51ZSkNCg0KIyBUw7NtIHThuq90IG3DtCB04bqjIGNoaSB0aeG6v3QNCnN1bW1hcnkobnVtZXJpY192YXJzKQ0KYGBgDQoNCkPDoWMgYmnhur9uIMSR4buLbmggbMaw4bujbmcgY8OzIHBow6JuIGLhu5EgaOG7o3AgbMO9LiBgQ2hpbGRyZW5gIHRydW5nIGLDrG5oIGtob+G6o25nIDIuNSwgYFVuaXRzU29sZGAgcGjhu5UgYmnhur9uIHThu6sgM+KAkzUgc+G6o24gcGjhuqltLCB2w6AgYFJldmVudWVgIHRydW5nIGLDrG5oIDEzIMSRxqFuIHbhu4sgdGnhu4FuLCBjaG8gdGjhuqV5IHPhu7EgxJFhIGThuqFuZyB24buBIGdpw6EgdHLhu4sgxJHGoW4gaMOgbmcuDQoNCiMjICoqNC4gVGjhu5FuZyBrw6ogbcO0IHThuqMgY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCoqDQoNCmBgYHtyfQ0KY2F0ZWdvcmljYWxfdmFycyA8LSBjKCJHZW5kZXIiLCAiTWFyaXRhbFN0YXR1cyIsICJIb21lb3duZXIiLCAiQ2l0eSIsICJTdGF0ZW9yUHJvdmluY2UiLCANCiAgICAgICAgICAgICAgICAgICAgICAiQ291bnRyeSIsICJQcm9kdWN0RmFtaWx5IiwgIlByb2R1Y3REZXBhcnRtZW50IiwgIlByb2R1Y3RDYXRlZ29yeSIpDQoNCiMgVOG6oW8gYuG6o25nIHThuqduIHN14bqldCB2w6AgdOG6p24gc3XhuqV0IHTGsMahbmcgxJHhu5FpDQpmb3IgKHZhciBpbiBjYXRlZ29yaWNhbF92YXJzKSB7DQogIGNhdCgiXG5cbj09PiIsIHZhciwgIlxuIikNCiAgcHJpbnQocHJvcC50YWJsZSh0YWJsZShkYXRhW1t2YXJdXSkpICogMTAwKQ0KfQ0KYGBgDQoNCi0gICAqKkdp4bubaSB0w61uaCoqOiBQaMOibiBi4buRIGfhuqduIG5oxrAgxJHhu5NuZyDEkeG7gXUgKE7hu68gNTElLCBOYW0gNDklKS4NCg0KLSAgICoqVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuKio6IEtow6FjaCBow6BuZyDEkeG7mWMgdGjDom4gY2hp4bq/bSDEkWEgc+G7kSAoNTElKS4NCg0KLSAgICoqU+G7nyBo4buvdSBuaMOgKio6IDYwJSBraMOhY2ggaMOgbmcgY8OzIG5ow6AgcmnDqm5nLg0KDQotICAgKipLaHUgduG7sWMqKjogVOG6rXAgdHJ1bmcgY2jhu6cgeeG6v3UgdOG6oWkgTeG7uSAoNjglKSwgxJHhurdjIGJp4buHdCDhu58gYmFuZyBXYXNoaW5ndG9uLCBDYWxpZm9ybmlhLCBPcmVnb24uDQoNCi0gICAqKlPhuqNuIHBo4bqpbSoqOiBUaOG7sWMgcGjhuqltIGNoaeG6v20gxrB1IHRo4bq/IGzhu5tuICg3MiUpLCDEkeG6t2MgYmnhu4d0IGzDoCByYXUgY+G7pyB2w6AgxJHhu5MgxINuIG5o4bq5Lg0KDQotICAgKipUaMOgbmggcGjhu5EgbuG7lWkgYuG6rXQqKjogU2FsZW0sIFRhY29tYSwgTG9zIEFuZ2VsZXMuDQoNCuKGkiBOaMOsbiBjaHVuZywga2jDoWNoIGjDoG5nIGNo4bunIHnhur91IGzDoCBuZ8aw4budaSBN4bu5LCBjw7MgbmjDoCwgdGnDqnUgZMO5bmcgbeG6oW5oIHbDoG8gdGjhu7FjIHBo4bqpbSwgxJHhurdjIGJp4buHdCBsw6AgcmF1IHbDoCBzbmFjay4NCg0KIyMjICoqNC4xLiBUaMO0bmcgdGluIG5ow6JuIGto4bqpdSBo4buNYyBraMOhY2ggaMOgbmcqKg0KDQoqKkdp4bubaSB0w61uaCAoR2VuZGVyKSoqDQoNCmBgYHtyfQ0KIyBU4bqnbiBzdeG6pXQgdsOgIGJp4buDdSDEkeG7kyBnaeG7m2kgdMOtbmgNCmdlbmRlcl9mcmVxIDwtIGRhdGEgJT4lIGNvdW50KEdlbmRlcikNCmdlbmRlcl9mcmVxDQoNCiMgQmnhu4N1IMSR4buTDQpnZ3Bsb3QoZ2VuZGVyX2ZyZXEsIGFlcyh4ID0gR2VuZGVyLCB5ID0gbiwgZmlsbCA9IEdlbmRlcikpICsNCiAgZ2VvbV9jb2woKSArDQogIGxhYnModGl0bGUgPSAiUGjDom4gcGjhu5FpIGdp4bubaSB0w61uaCIsIHggPSAiR2nhu5tpIHTDrW5oIiwgeSA9ICJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpCaeG7g3UgxJHhu5MgY2hvIHRo4bqleSBz4buxIHBow6JuIGLhu5EgZ2nhu5tpIHTDrW5oIGPhu6dhIGtow6FjaCBow6BuZyBn4bqnbiBuaMawICoqY8OibiBi4bqxbmcqKjoNCg0KLSAgICoqTuG7ryBjaGnhur9tIGtob+G6o25nIDUxJSoqLCBuaOG7iW5oIGjGoW4gbeG7mXQgY2jDunQgc28gduG7m2kgbmFtLg0KDQotICAgKipOYW0gY2hp4bq/bSBraG/huqNuZyA0OSUqKi4NCg0KKipL4bq/dCBsdeG6rW4qKjogS2jDtG5nIGPDsyBz4buxIGNow6puaCBs4buHY2ggbOG7m24gduG7gSBnaeG7m2kgdMOtbmggdHJvbmcgdOG6rXAga2jDoWNoIGjDoG5nLCBjaG8gdGjhuqV5IG5ow7NtIGtow6FjaCBow6BuZyBj4bunYSBzacOqdSB0aOG7iyDEkcaw4bujYyBwaMOibiBi4buRIMSR4buTbmcgxJHhu4F1IGdp4buvYSBuYW0gdsOgIG7hu68uIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgZ2nDunAgZG9hbmggbmdoaeG7h3AgKip0aGnhur90IGvhur8gc+G6o24gcGjhuqltLCBjaMawxqFuZyB0csOsbmgga2h1eeG6v24gbcOjaSBwaMO5IGjhu6NwIGNobyBj4bqjIGhhaSBnaeG7m2kqKi4NCg0KKipUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gKE1hcml0YWwgU3RhdHVzKSoqDQoNCmBgYHtyfQ0KbWFyaXRhbF9mcmVxIDwtIGRhdGEgJT4lIGNvdW50KE1hcml0YWxTdGF0dXMpDQptYXJpdGFsX2ZyZXENCg0KZ2dwbG90KG1hcml0YWxfZnJlcSwgYWVzKHggPSBNYXJpdGFsU3RhdHVzLCB5ID0gbiwgZmlsbCA9IE1hcml0YWxTdGF0dXMpKSArDQogIGdlb21fY29sKCkgKw0KICBsYWJzKHRpdGxlID0gIlTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiIsIHggPSAiVMOsbmggdHLhuqFuZyIsIHkgPSAiU+G7kSBsxrDhu6NuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQotICAgQmnhu4N1IMSR4buTIGNobyB0aOG6pXkgc+G7kSAqKmtow6FjaCBow6BuZyDEkeG7mWMgdGjDom4gKFMpKiogKipuaOG7iW5oIGjGoW4gbeG7mXQgY2jDunQqKiBzbyB24bubaSBz4buRICoqa2jDoWNoIGjDoG5nIMSRw6Mga+G6v3QgaMO0biAoTSkqKi4NCg0KLSAgIFPhu7EgY2jDqm5oIGzhu4djaCBraMO0bmcgcXXDoSBs4bubbiwgY2hvIHRo4bqleSBuaMOzbSBraMOhY2ggaMOgbmcga2jDoSBjw6JuIGLhurFuZyBnaeG7r2EgaGFpIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibi4NCg0KKipL4bq/dCBsdeG6rW4qKjogS2jDoWNoIGjDoG5nIHRyb25nIGThu68gbGnhu4d1IGPDsyBz4buxIHBow6JuIGLhu5EgdMawxqFuZyDEkeG7kWkgxJHhu5NuZyDEkeG7gXUgZ2nhu69hICoqxJHhu5ljIHRow6JuKiogdsOgICoqxJHDoyBr4bq/dCBow7RuKiosIGdpw7pwIHBow6JuIHTDrWNoIG5odSBj4bqndSB2w6AgaMOgbmggdmkgdGnDqnUgZMO5bmcgdGhlbyB04burbmcgbmjDs20gZOG7hSBkw6BuZyBoxqFuLg0KDQoqKlTDrG5oIHRy4bqhbmcgc+G7nyBo4buvdSBuaMOgIChIb21lb3duZXIpKioNCg0KYGBge3J9DQpob21lb3duZXJfZnJlcSA8LSBkYXRhICU+JSBjb3VudChIb21lb3duZXIpDQpob21lb3duZXJfZnJlcQ0KDQpnZ3Bsb3QoaG9tZW93bmVyX2ZyZXEsIGFlcyh4ID0gSG9tZW93bmVyLCB5ID0gbiwgZmlsbCA9IEhvbWVvd25lcikpICsNCiAgZ2VvbV9jb2woKSArDQogIGxhYnModGl0bGUgPSAiS2jDoWNoIGjDoG5nIGPDsyBz4bufIGjhu691IG5ow6Aga2jDtG5nPyIsIHggPSAiSG9tZW93bmVyIiwgeSA9ICJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCi0gICBT4buRIGzGsOG7o25nICoqa2jDoWNoIGjDoG5nIHPhu58gaOG7r3UgbmjDoCAoWSkqKiAqKmNhbyBoxqFuIMSRw6FuZyBr4buDKiogc28gduG7m2kgc+G7kSAqKmtow7RuZyBz4bufIGjhu691IG5ow6AgKE4pKiouDQoNCi0gICAqKsav4bubYyB0w61uaCB04bu3IGzhu4cqKjogS2hv4bqjbmcgKio2MCUga2jDoWNoIGjDoG5nIHPhu58gaOG7r3UgbmjDoCoqLCBjw7JuIGzhuqFpICoqNDAlIGtow7RuZyBz4bufIGjhu691KiouDQoNCioqS+G6v3QgbHXhuq1uKio6IMSQYSBz4buRIGtow6FjaCBow6BuZyB0cm9uZyB04bqtcCBk4buvIGxp4buHdSAqKsSRw6Mgc+G7nyBo4buvdSBuaMOgKiouIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgbGnDqm4gcXVhbiDEkeG6v24gbeG7qWMgxJHhu5kg4buVbiDEkeG7i25oIHTDoGkgY2jDrW5oIGNhbyBoxqFuLCB2w6AgbMOgIHnhur91IHThu5EgaOG7r3Ugw61jaCB0cm9uZyB2aeG7h2MgcGjDom4gdMOtY2gga2jhuqMgbsSDbmcgY2hpIHRpw6p1LCDEkeG6p3UgdMawIGhv4bq3YyB0w61uIGThu6VuZy4NCg0KIyMjICoqNC4yLiBUaMO0bmcgdGluIMSR4buLYSBsw70qKg0KDQoqKlRow6BuaCBwaOG7kSAoQ2l0eSkqKg0KDQpgYGB7cn0NCnRvcF9jaXR5IDwtIGRhdGEgJT4lIGNvdW50KENpdHksIHNvcnQgPSBUUlVFKSAlPiUgc2xpY2UoMToxMCkNCnRvcF9jaXR5DQoNCmdncGxvdCh0b3BfY2l0eSwgYWVzKHggPSByZW9yZGVyKENpdHksIG4pLCB5ID0gbikpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICJza3libHVlIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIlRvcCAxMCB0aMOgbmggcGjhu5EgY8OzIGtow6FjaCBow6BuZyBuaGnhu4F1IG5o4bqldCIsIHggPSAiVGjDoG5oIHBo4buRIiwgeSA9ICJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCkJp4buDdSDEkeG7kyBjaG8gdGjhuqV5ICoqU2FsZW0qKiBjw7Mgc+G7kSBsxrDhu6NuZyBraMOhY2ggaMOgbmcgY2FvIG5o4bqldCwgdGhlbyBzYXUgbMOgICoqVGFjb21hKiogdsOgICoqTG9zIEFuZ2VsZXMqKi4gVG9wIDEwIHThuq1wIHRydW5nIGNo4bunIHnhur91IOG7nyBjw6FjIHRow6BuaCBwaOG7kSBwaMOtYSBUw6J5IG7GsOG7m2MgTeG7uS4gU+G7sSBjaMOqbmggbOG7h2NoIHLDtSBy4buHdCBnaeG7r2EgY8OhYyB0aMOgbmggcGjhu5EgxJHhuqd1IHbDoCBjdeG7kWkgZGFuaCBzw6FjaC4NCg0KKipCYW5nIGhv4bq3YyB04buJbmggKFN0YXRlIG9yIFByb3ZpbmNlKSoqwqANCg0KYGBge3J9DQpzdGF0ZV9mcmVxIDwtIGRhdGEgJT4lIGNvdW50KFN0YXRlb3JQcm92aW5jZSwgc29ydCA9IFRSVUUpICU+JSBzbGljZSgxOjEwKQ0Kc3RhdGVfZnJlcQ0KDQpnZ3Bsb3Qoc3RhdGVfZnJlcSwgYWVzKHggPSByZW9yZGVyKFN0YXRlb3JQcm92aW5jZSwgbiksIHkgPSBuKSkgKw0KICBnZW9tX2NvbChmaWxsID0gInNlYWdyZWVuIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIlRvcCAxMCBiYW5nIGPDsyBraMOhY2ggaMOgbmcgbmhp4buBdSBuaOG6pXQiLCB4ID0gIkJhbmciLCB5ID0gIlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KQmnhu4N1IMSR4buTIGNobyB0aOG6pXkgYmFuZyAqKldhc2hpbmd0b24gKFdBKSoqIGPDsyBz4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyBjYW8gbmjhuqV0LCB0aGVvIHNhdSBsw6AgKipDYWxpZm9ybmlhIChDQSkqKiB2w6AgKipPcmVnb24gKE9SKSoqLiBOZ2/DoGkgY8OhYyBiYW5nIGPhu6dhIE3hu7ksIGThu68gbGnhu4d1IGPDsm4gZ2hpIG5o4bqtbiBraMOhY2ggaMOgbmcgdOG7qyBt4buZdCBz4buRIGJhbmcgY+G7p2EgTWV4aWNvIG5oxrAgKipaYWNhdGVjYXMqKiB2w6AgKipEaXN0cml0byBGZWRlcmFsKiouIFPhu7EgY2jDqm5oIGzhu4djaCBs4bubbiBnaeG7r2EgY8OhYyBiYW5nIGNobyB0aOG6pXkga2jDoWNoIGjDoG5nIHThuq1wIHRydW5nIGNo4bunIHnhur91IOG7nyBraHUgduG7sWMgVMOieSBC4bqvYyBuxrDhu5tjIE3hu7kuDQoNCioqUXXhu5FjIGdpYSAoQ291bnRyeSkqKg0KDQpgYGB7cn0NCmNvdW50cnlfZnJlcSA8LSBkYXRhICU+JSBjb3VudChDb3VudHJ5LCBzb3J0ID0gVFJVRSkNCmNvdW50cnlfZnJlcQ0KDQpnZ3Bsb3QoY291bnRyeV9mcmVxLCBhZXMoeCA9IHJlb3JkZXIoQ291bnRyeSwgbiksIHkgPSBuKSkgKw0KICBnZW9tX2NvbChmaWxsID0gInB1cnBsZSIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBwaOG7kWkga2jDoWNoIGjDoG5nIHRoZW8gcXXhu5FjIGdpYSIsIHggPSAiUXXhu5FjIGdpYSIsIHkgPSAiU+G7kSBsxrDhu6NuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KQmnhu4N1IMSR4buTIGNobyB0aOG6pXkga2jDoWNoIGjDoG5nIHThuq1wIHRydW5nIGNo4bunIHnhur91IHThuqFpICoqSG9hIEvhu7MgKFVTQSkqKiwgY2hp4bq/bSBwaOG6p24gbOG7m24gc28gduG7m2kgY8OhYyBxdeG7kWMgZ2lhIGPDsm4gbOG6oWkuICoqTWV4aWNvKiogbMOgIHF14buRYyBnaWEgY8OzIHPhu5EgbMaw4bujbmcga2jDoWNoIGjDoG5nIG5oaeG7gXUgdGjhu6kgaGFpLCB0dXkgbmhpw6puIGPDoWNoIGJp4buHdCBraMOhIGzhu5tuLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSB0aOG7iyB0csaw4budbmcgY2jDrW5oIGPhu6dhIHNpw6p1IHRo4buLIGzDoCB04bqhaSBN4bu5LiBCaeG7g3UgxJHhu5MgdHLhu7FjIHF1YW4sIGThu4UgaGnhu4N1IHbhu5tpIG3DoHUgc+G6r2MgbuG7lWkgYuG6rXQuDQoNCiMjIyAqKjQuMy4qKiAqKlRow7RuZyB0aW4gc+G6o24gcGjhuqltKioNCg0KKipOaMOzbSBz4bqjbiBwaOG6qW0gKFByb2R1Y3QgRmFtaWx5KSoqDQoNCmBgYHtyfQ0KZmFtaWx5X2ZyZXEgPC0gZGF0YSAlPiUgY291bnQoUHJvZHVjdEZhbWlseSwgc29ydCA9IFRSVUUpDQpmYW1pbHlfZnJlcQ0KDQpnZ3Bsb3QoZmFtaWx5X2ZyZXEsIGFlcyh4ID0gcmVvcmRlcihQcm9kdWN0RmFtaWx5LCBuKSwgeSA9IG4pKSArDQogIGdlb21fY29sKGZpbGwgPSAiY29yYWwiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnModGl0bGUgPSAiUGjDom4gcGjhu5FpIHRoZW8gbmjDs20gc+G6o24gcGjhuqltIiwgeCA9ICJOaMOzbSBz4bqjbiBwaOG6qW0iLCB5ID0gIlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KQmnhu4N1IMSR4buTIGNobyB0aOG6pXkgbmjDs20gc+G6o24gcGjhuqltICoqRm9vZCAoVGjhu7FjIHBo4bqpbSkqKiBjaGnhur9tIHPhu5EgbMaw4bujbmcgZ2lhbyBk4buLY2ggY2FvIG5o4bqldCwgdsaw4bujdCB0cuG7mWkgc28gduG7m2kgY8OhYyBuaMOzbSBjw7JuIGzhuqFpIG5oxrAgKipEcmluayAoxJDhu5MgdeG7kW5nKSoqIHbDoCAqKk5vbi1Db25zdW1hYmxlIChIw6BuZyBraMO0bmcgdGnDqnUgZMO5bmcpKiouIMSQaeG7gXUgbsOgeSBwaOG6o24gw6FuaCBuaHUgY+G6p3UgdGnDqnUgZMO5bmcgdGjhu7FjIHBo4bqpbSBsw6AgY2jhu6cgeeG6v3UgdOG6oWkgc2nDqnUgdGjhu4suIEJp4buDdSDEkeG7kyByw7UgcsOgbmcsIGThu4UgxJHhu41jIHbDoCB0cuG7sWMgcXVhbi4NCg0KKipC4buZIHBo4bqtbiBz4bqjbiBwaOG6qW0gKFByb2R1Y3QgRGVwYXJ0bWVudCkqKg0KDQpgYGB7cn0NCmRlcHRfZnJlcSA8LSBkYXRhICU+JSBjb3VudChQcm9kdWN0RGVwYXJ0bWVudCwgc29ydCA9IFRSVUUpDQpkZXB0X2ZyZXENCg0KZ2dwbG90KGRlcHRfZnJlcSwgYWVzKHggPSByZW9yZGVyKFByb2R1Y3REZXBhcnRtZW50LCBuKSwgeSA9IG4pKSArDQogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIHBo4buRaSB0aGVvIHBow7JuZyBiYW4gc+G6o24gcGjhuqltIiwgeCA9ICJQaMOybmcgYmFuIiwgeSA9ICJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCkJp4buDdSDEkeG7kyBjaG8gdGjhuqV5IGPDoWMgcGjDsm5nIGJhbiBuaMawICoqU25hY2tzKiosICoqQmV2ZXJhZ2VzKiogdsOgICoqRGFpcnkqKiBjw7Mgc+G7kSBsxrDhu6NuZyBnaWFvIGThu4tjaCBjYW8gbmjhuqV0LiDEkGnhu4F1IG7DoHkgcGjhuqNuIMOhbmggdGjDs2kgcXVlbiB0acOqdSBkw7luZyBwaOG7lSBiaeG6v24gbMOgIGPDoWMgc+G6o24gcGjhuqltIMSDbiB14buRbmcgbmhhbmguIFBow6JuIHBo4buRaSBnaeG7r2EgY8OhYyBwaMOybmcgYmFuIGtow6EgxJFhIGThuqFuZywgYmnhu4N1IMSR4buTIHRyw6xuaCBiw6B5IHLDtSByw6BuZyB2w6AgZOG7hSBoaeG7g3UuDQoNCioqTG/huqFpIHPhuqNuIHBo4bqpbSAoUHJvZHVjdCBDYXRlZ29yeSkqKg0KDQpgYGB7cn0NCmNhdF9mcmVxIDwtIGRhdGEgJT4lIGNvdW50KFByb2R1Y3RDYXRlZ29yeSwgc29ydCA9IFRSVUUpICU+JSBzbGljZSgxOjE1KQ0KY2F0X2ZyZXENCg0KZ2dwbG90KGNhdF9mcmVxLCBhZXMoeCA9IHJlb3JkZXIoUHJvZHVjdENhdGVnb3J5LCBuKSwgeSA9IG4pKSArDQogIGdlb21fY29sKGZpbGwgPSAiZGFya29yYW5nZSIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJUb3AgMTUgbG/huqFpIHPhuqNuIHBo4bqpbSBwaOG7lSBiaeG6v24iLCB4ID0gIkxv4bqhaSBz4bqjbiBwaOG6qW0iLCB5ID0gIlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KQmnhu4N1IMSR4buTIGhp4buDbiB0aOG7iyAxNSBsb+G6oWkgc+G6o24gcGjhuqltIHBo4buVIGJp4bq/biBuaOG6pXQuDQoNCjEuICBIw6BuZyDEkeG6p3U6ICJWZWdldGFibGVzIiAoUmF1IGPhu6cpIGThuqtuIMSR4bqndSB24buBIHPhu5EgbMaw4bujbmcsIGNobyB0aOG6pXkgbmh1IGPhuqd1IGNhbyB24buBIHRo4buxYyBwaOG6qW0gdMawxqFpLg0KDQoyLiAgWHUgaMaw4bubbmc6ICJTbmFjayBGb29kcyIgdsOgICJEYWlyeSIgY8WpbmcgcGjhu5UgYmnhur9uLCBwaOG6o24gw6FuaCB0aMOzaSBxdWVuIMSDbiB14buRbmcgxJFhIGThuqFuZy4NCg0KMy4gIFRp4buHbiBs4bujaTogQ8OhYyBz4bqjbiBwaOG6qW0gbmjGsCAiQnJlYWQiIHbDoCAiQ2FubmVkIFNvdXAiIGNobyB0aOG6pXkgc+G7sSDGsGEgY2h14buZbmcgdGjhu7FjIHBo4bqpbSB0aeG7h24gbOG7o2kuDQoNClThu5VuZyBxdWFuLCBuaHUgY+G6p3UgY2FvIMSR4buRaSB24bubaSB0aOG7sWMgcGjhuqltIHTGsMahaSBz4buRbmcgdsOgIHRp4buHbiBs4bujaS4NCg0KIyMjICoqNC40KiogKipL4bq/dCBsdeG6rW4gY2hvIHBo4bqnbiDEkeG7i25oIHTDrW5oKioNCg0KLSAgIEPDoWMgYmnhur9uIMSR4buLbmggdMOtbmggZ2nDunAgKipoaeG7g3Ugc8OidSBoxqFuIHbhu4EgxJHhurdjIMSRaeG7g20gdOG6rXAga2jDoWNoIGjDoG5nKiogbmjGsCBnaeG7m2kgdMOtbmgsIGjDtG4gbmjDom4sIG7GoWkgc+G7kW5nLg0KDQotICAgQ8OhYyDEkeG6t2MgdMOtbmggc+G6o24gcGjhuqltIHbDoCBwaMOibiBwaOG7kWkgxJHhu4thIGzDvSBjdW5nIGPhuqVwIGLhu6ljIHRyYW5oIHThu5VuZyB0aOG7gyBnacO6cCAqKsSR4buLbmggduG7iyB0aOG7iyB0csaw4budbmcgdGnhu4FtIG7Eg25nKiogaG/hurdjICoqxJFp4buBdSBjaOG7iW5oIGRhbmggbeG7pWMgc+G6o24gcGjhuqltKiogcGjDuSBo4bujcCB24bubaSB04burbmcga2h1IHbhu7FjLg0KDQojIyAqKjUuIEvhur90IGx14bqtbioqDQoNClRow7RuZyBxdWEgdGjhu5FuZyBrw6ogbcO0IHThuqMgY2hpIHRp4bq/dDoNCg0KLSAgIEPDoWMgKipiaeG6v24gxJHhu4tuaCBsxrDhu6NuZyoqIHBo4bqjbiDDoW5oIHPhu7EgcGjDom4gdMOhbiBs4bubbiBnaeG7r2EgY8OhYyBuaMOzbSBraMOhY2ggaMOgbmcgdsOgIHPhuqNuIHBo4bqpbS4NCg0KLSAgIEPDoWMgKipiaeG6v24gxJHhu4tuaCB0w61uaCoqIGNobyB0aOG6pXkgc+G7sSDEkWEgZOG6oW5nIHRyb25nIHThuq1wIGtow6FjaCBow6BuZyB2w6AgZGFuaCBt4bulYyBow6BuZyBow7NhLg0KDQotICAgRG9hbmggdGh1IHThuq1wIHRydW5nIOG7nyBt4buZdCBz4buRICoqYmFuZyoqLCAqKnRow6BuaCBwaOG7kSoqIHbDoCAqKm5ow7NtIHPhuqNuIHBo4bqpbSoqIG5o4bqldCDEkeG7i25oLCBt4bufIHJhIGPGoSBo4buZaSB04buRaSDGsHUgaMOzYSBjaGnhur9uIGzGsOG7o2Mga2luaCBkb2FuaC4NCg0KVGjhu5FuZyBrw6ogbcO0IHThuqMgbMOgIGLGsOG7m2MgbuG7gW4gdOG6o25nIGtow7RuZyB0aOG7gyB0aGnhur91IHRyxrDhu5tjIGtoaSB0aeG6v24gaMOgbmggY8OhYyBr4bu5IHRodeG6rXQgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgbsOibmcgY2FvIG5oxrAgY2x1c3RlcmluZywgcGjDom4gdMOtY2ggUkZNLCBob+G6t2MgbcO0IGjDrG5oIGjDs2EgaMOgbmggdmkgdGnDqnUgZMO5bmcuDQo=