unlink("tuan5.knit.md")
library(tidyverse)
library(ggplot2)
library(epitools)
library(DescTools)
library(DT)
library(energy)
library(readr)

1.Về Bộ Dữ Liệu 🗂️

📄 Mô tả

Bộ dữ liệu này chứa thông tin về tỷ lệ tử vong do ung thư phổi và là một tập hợp toàn diện về thông tin của bệnh nhân, tập trung chủ yếu vào những người đã được chẩn đoán mắc ung thư. Với 800.000 cá nhân được ghi nhận, bộ dữ liệu bao gồm đầy đủ thông tin liên quan đến quá trình chẩn đoán, điều trị và kết quả điều trị ung thư phổi, được tổ chức trong 16 cột rõ ràng và có cấu trúc. Đây là một nguồn dữ liệu quy mô lớn, được thiết kế nhằm hỗ trợ các nhà nghiên cứu, nhà khoa học dữ liệu và chuyên gia y tế trong việc phân tích mô hình, xây dựng các hệ thống dự đoán, cũng như cải thiện chiến lược phát hiện sớm và điều trị bệnh.

#Đọc dữ liệu từ file CSV
data <- read.csv("C:/Users/Hoang Quyen/Downloads/dataset_med.csv")
#Hiển thị cấu trúc dữ liệu
str(data)
## 'data.frame':    890000 obs. of  17 variables:
##  $ id                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ age               : num  64 50 65 51 37 50 49 51 64 56 ...
##  $ gender            : chr  "Male" "Female" "Female" "Female" ...
##  $ country           : chr  "Sweden" "Netherlands" "Hungary" "Belgium" ...
##  $ diagnosis_date    : chr  "2016-04-05" "2023-04-20" "2023-04-05" "2016-02-05" ...
##  $ cancer_stage      : chr  "Stage I" "Stage III" "Stage III" "Stage I" ...
##  $ family_history    : chr  "Yes" "Yes" "Yes" "No" ...
##  $ smoking_status    : chr  "Passive Smoker" "Passive Smoker" "Former Smoker" "Passive Smoker" ...
##  $ bmi               : num  29.4 41.2 44 43 19.7 37.6 43.1 25.8 21.5 17.3 ...
##  $ cholesterol_level : int  199 280 268 241 178 274 259 195 236 183 ...
##  $ hypertension      : int  0 1 1 1 0 1 0 1 0 1 ...
##  $ asthma            : int  0 1 1 1 0 0 0 1 0 0 ...
##  $ cirrhosis         : int  1 0 0 0 0 0 0 0 0 0 ...
##  $ other_cancer      : int  0 0 0 0 0 0 0 0 0 1 ...
##  $ treatment_type    : chr  "Chemotherapy" "Surgery" "Combined" "Chemotherapy" ...
##  $ end_treatment_date: chr  "2017-09-10" "2024-06-17" "2024-04-09" "2017-04-23" ...
##  $ survived          : int  0 1 0 0 0 0 1 0 0 0 ...
View(data)
#Hiển thị 5 dòng đầu và cuối
head(data, 5)
##   id age gender     country diagnosis_date cancer_stage family_history
## 1  1  64   Male      Sweden     2016-04-05      Stage I            Yes
## 2  2  50 Female Netherlands     2023-04-20    Stage III            Yes
## 3  3  65 Female     Hungary     2023-04-05    Stage III            Yes
## 4  4  51 Female     Belgium     2016-02-05      Stage I             No
## 5  5  37   Male  Luxembourg     2023-11-29      Stage I             No
##   smoking_status  bmi cholesterol_level hypertension asthma cirrhosis
## 1 Passive Smoker 29.4               199            0      0         1
## 2 Passive Smoker 41.2               280            1      1         0
## 3  Former Smoker 44.0               268            1      1         0
## 4 Passive Smoker 43.0               241            1      1         0
## 5 Passive Smoker 19.7               178            0      0         0
##   other_cancer treatment_type end_treatment_date survived
## 1            0   Chemotherapy         2017-09-10        0
## 2            0        Surgery         2024-06-17        1
## 3            0       Combined         2024-04-09        0
## 4            0   Chemotherapy         2017-04-23        0
## 5            0       Combined         2025-01-08        0
tail(data, 5)
##            id age gender  country diagnosis_date cancer_stage family_history
## 889996 889996  40   Male    Malta     2022-07-01     Stage IV             No
## 889997 889997  62 Female   Cyprus     2015-09-27     Stage II            Yes
## 889998 889998  48 Female  Estonia     2016-03-27    Stage III            Yes
## 889999 889999  67 Female Slovakia     2015-12-22     Stage IV            Yes
## 890000 890000  55 Female    Malta     2021-07-26     Stage II            Yes
##        smoking_status  bmi cholesterol_level hypertension asthma cirrhosis
## 889996 Passive Smoker 44.8               243            1      1         1
## 889997  Former Smoker 21.6               240            0      0         0
## 889998   Never Smoked 38.6               242            1      0         0
## 889999  Former Smoker 18.6               194            1      1         0
## 890000 Current Smoker 42.8               250            0      0         0
##        other_cancer treatment_type end_treatment_date survived
## 889996            0      Radiation         2023-02-23        0
## 889997            0        Surgery         2017-06-19        0
## 889998            0       Combined         2017-01-23        1
## 889999            0   Chemotherapy         2017-12-12        0
## 890000            0       Combined         2022-10-19        0
# Các biến định tính dạng chuỗi cần chuyển thành factor:
cols_to_factor <- c("gender", "country", "cancer_stage",
                    "family_history", "smoking_status", "treatment_type")
# Chuyển các biến định tính dạng chuỗi thành factor
data[cols_to_factor] <- lapply(data[cols_to_factor], as.factor)
Tên biến Kiểu dữ liệu Mô tả
id Định danh Mã số định danh cho mỗi bệnh nhân. Không sử dụng trong phân tích thống kê.
age Định lượng Tuổi của bệnh nhân tại thời điểm chẩn đoán.
gender Định tính Giới tính của bệnh nhân (Nam hoặc Nữ).
country Định tính Quốc gia cư trú của bệnh nhân.
diagnosis_date Định tính (ngày) Ngày bệnh nhân được chẩn đoán ung thư.
cancer_stage Định tính Giai đoạn ung thư (từ Stage I đến Stage IV).
family_history Định tính Tiền sử ung thư trong gia đình (Yes hoặc No).
smoking_status Định tính Tình trạng hút thuốc (gồm 4 mức: Current, Former, Passive, Never).
bmi Định lượng Chỉ số khối cơ thể (Body Mass Index).
cholesterol_level Định lượng Mức cholesterol trong máu.
hypertension Định tính Có hay không bị cao huyết áp (0 = Không, 1 = Có).
asthma Định tính Có hay không mắc hen suyễn (0 = Không, 1 = Có).
cirrhosis Định tính Có hay không mắc xơ gan (0 = Không, 1 = Có).
other_cancer Định tính Có hay không mắc các loại ung thư khác (0 = Không, 1 = Có).
treatment_type Định tính Phương pháp điều trị chính (Chemotherapy, Radiation, Surgery, Combined).
end_treatment_date Định tính (ngày) Ngày kết thúc quá trình điều trị.
survived Định tính Kết cục sống sót (0 = Không sống sót, 1 = Sống sót). Biến đầu ra quan trọng trong phân tích suy diễn.

Dưới đây là phiên bản đã cập nhật đầy đủ nội dung thống kê mô tả biến gender, có hiển thị số liệu ngay trên đỉnh cột, trình bày theo dạng báo cáo học thuật chuyên nghiệp, dùng được trong chương thống kê mô tả:

2. Thống kê mô tả

2.1. Thống kê mô tả biến gender

Biến gender là một biến định tính phân loại (categorical nominal variable), phản ánh giới tính sinh học của các bệnh nhân trong tập dữ liệu, với hai mức giá trị chính: Male (Nam) và Female (Nữ). Việc phân tích biến này giúp nhận diện sự phân bố giới tính trong mẫu nghiên cứu và là cơ sở quan trọng cho các phân tích tiếp theo về mối liên hệ với yếu tố bệnh lý và di truyền.

2.1.1. Thống kê tần suất và tỷ lệ phần trăm

# Tần suất và tỷ lệ phần trăm
gender_freq <- table(data$gender)
gender_prop <- prop.table(gender_freq) * 100

# Hiển thị dưới dạng bảng
gender_summary <- data.frame(
  Gender = names(gender_freq),
  Frequency = as.vector(gender_freq),
  Percentage = round(as.vector(gender_prop), 2)
)

gender_summary
##   Gender Frequency Percentage
## 1 Female    444866      49.98
## 2   Male    445134      50.02

Kết quả phân tích cho thấy giới tính nam chiếm tỷ lệ nhỉnh hơn trong tổng thể mẫu, với 50,02% bệnh nhân là nam giới và 49,98% là nữ giới. Sự phân bố gần như cân bằng giữa hai giới giúp đảm bảo tính đại diện trong các phân tích tiếp theo, đồng thời phản ánh thực trạng dịch tễ học ung thư phổi có liên quan đến cả hai nhóm giới.

2.1.2. Biểu đồ cột thể hiện phân bố giới tính

library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
# Chuẩn bị dữ liệu tóm tắt
gender_summary <- as.data.frame(table(data$gender))
colnames(gender_summary) <- c("Gender", "Count")

# Biểu đồ có nhãn số trên cột
ggplot(gender_summary, aes(x = Gender, y = Count)) +
  geom_bar(stat = "identity", fill = "#66C2A5") +
  geom_text(aes(label = Count), vjust = -0.5, size = 4.5) +
  labs(title = "Phan bo gioi tinh cua benh nhan",
       x = "Giới tính", y = "Số lượng") +
  theme_minimal()

Biểu đồ cột thể hiện trực quan số lượng bệnh nhân theo từng giới tính. Các giá trị cụ thể được gắn nhãn ngay trên các cột giúp người đọc dễ dàng nhận biết sự phân bố mà không cần đối chiếu với bảng số liệu riêng.

2.1.3. Ước lượng và kiểm định tỷ lệ nữ

📌 Mục tiêu

Mục tiêu của phân tích là:

  • Ước lượng tỷ lệ nữ giới trong tổng thể người quan sát.
  • Kiểm định giả thuyết xem tỷ lệ nữ trong mẫu có khác biệt đáng kể so với tỷ lệ giả định là 50% hay không.

📌 Phương pháp

Ta xét một bài toán kiểm định tỷ lệ một mẫu, trong đó:

  • Biến nghiên cứu: gender
  • Giả thuyết kiểm định:

\[ H_0: p = 0.5 \quad \text{(Tỷ lệ nữ trong tổng thể là 50\%)} \\ H_1: p \neq 0.5 \quad \text{(Tỷ lệ nữ khác 50\%)} \]

# Đếm số lượng nữ và tổng số (sửa đúng tên biến: df)
female_count <- sum(data$gender == "Female", na.rm = TRUE)
total_gender <- sum(data$gender %in% c("Female", "Male"), na.rm = TRUE)

# Tính tỷ lệ nữ
p_female <- female_count / total_gender

# Kiểm định tỷ lệ nữ có bằng 0.5 không
test_gender <- prop.test(female_count, total_gender, p = 0.5, correct = TRUE)

# In kết quả
cat("Tỷ lệ nữ:", round(p_female, 4), "\n")
## Tỷ lệ nữ: 0.4998
print(test_gender)
## 
##  1-sample proportions test with continuity correction
## 
## data:  female_count out of total_gender, null probability 0.5
## X-squared = 0.0801, df = 1, p-value = 0.7772
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.4988101 0.5008888
## sample estimates:
##         p 
## 0.4998494

📌 Kết quả phân tích

Tổng số quan sát hợp lệ là 890.000 người, trong đó có:

  • Số lượng nữ giới: 444.866 người
  • Tỷ lệ nữ mẫu: 0.4998 (tương đương 49.98%)

🔍 Diễn giải kết quả

  • Khoảng tin cậy 95% cho tỷ lệ nữ: từ 49.88% đến 50.09%
  • Giá trị p (p-value) = 0.7772 > 0.05

Do giá trị p lớn hơn mức ý nghĩa 5%, ta không bác bỏ giả thuyết \(H_0\). Nói cách khác, không có đủ bằng chứng thống kê để kết luận rằng tỷ lệ nữ trong tổng thể khác biệt đáng kể so với 50%.

✅ Kết luận

Từ kết quả phân tích, ta có thể kết luận rằng tỷ lệ nữ giới trong mẫu dữ liệu là 49.98%, và không có sự khác biệt có ý nghĩa thống kê so với tỷ lệ giả định là 50%. Điều này cho thấy phân bố giới tính trong dữ liệu là khá cân bằng.

2.2. Thống kê mô tả biến family_history

Biến family_history là một biến định tính nhị phân (binary categorical variable), phản ánh việc bệnh nhân có hay không tiền sử ung thư trong gia đình. Đây là yếu tố quan trọng để đánh giá nguy cơ di truyền trong các bệnh lý ung thư, đặc biệt là ung thư phổi. Phân tích biến này giúp làm rõ mối liên hệ giữa yếu tố gia đình và tỷ lệ mắc bệnh.

2.2.1. Thống kê tần suất và tỷ lệ phần trăm

# Tần suất và tỷ lệ phần trăm
fh_freq <- table(data$family_history)
fh_prop <- prop.table(fh_freq) * 100

# Bảng tóm tắt
fh_summary <- data.frame(
  Family_History = names(fh_freq),
  Frequency = as.vector(fh_freq),
  Percentage = round(as.vector(fh_prop), 2)
)

fh_summary
##   Family_History Frequency Percentage
## 1             No    445181      50.02
## 2            Yes    444819      49.98

Có khoảng 49,98% bệnh nhân trong tập dữ liệu có tiền sử ung thư trong gia đình, trong khi 50.02% không có. Kết quả này cho thấy yếu tố di truyền có thể đóng vai trò quan trọng trong tỷ lệ mắc bệnh ung thư phổi, từ đó gợi ý hướng nghiên cứu sâu hơn về yếu tố gen và tiền sử gia đình.

2.2.2. Biểu đồ cột thể hiện phân bố tiền sử ung thư

library(ggplot2)

# Chuẩn bị dữ liệu tóm tắt
fh_summary <- as.data.frame(table(data$family_history))
colnames(fh_summary) <- c("Family_History", "Count")

# Biểu đồ với nhãn số trên cột
ggplot(fh_summary, aes(x = Family_History, y = Count)) +
  geom_bar(stat = "identity", fill = "#FC8D62") +
  geom_text(aes(label = Count), vjust = -0.5, size = 4.5) +
  labs(title = "Phân bố tiền sử ung thư trong gia đình",
       x = "Family History", y = "Số lượng") +
  theme_minimal()

Biểu đồ trực quan giúp thể hiện rõ ràng mức độ xuất hiện của yếu tố tiền sử gia đình trong mẫu nghiên cứu. Việc gắn nhãn số trên cột tăng tính dễ đọc và hỗ trợ so sánh tỷ lệ giữa hai nhóm bệnh nhân một cách nhanh chóng.

2.2.3. Ước lượng và kiểm định tỷ lệ có tiền sử gia đình

📌 Mục tiêu

Mục tiêu của phân tích là:

  • Ước lượng tỷ lệ người có tiền sử gia đình mắc bệnh (biến family_history)
  • Kiểm định giả thuyết xem tỷ lệ này có khác biệt đáng kể so với 50% hay không

📌 Phương pháp

Biến nghiên cứu là family_history với 2 giá trị: "Yes" (có tiền sử) và "No" (không có).

Giả thuyết kiểm định như sau:

\[ H_0: p = 0.5 \quad \text{(Tỷ lệ người có tiền sử gia đình là 50\%)} \\ H_1: p \ne 0.5 \quad \text{(Tỷ lệ khác 50\%)} \]

# Đếm số người có family history và tổng số
fh_yes <- sum(data$family_history == "Yes", na.rm = TRUE)
total_fh <- sum(data$family_history %in% c("Yes", "No"), na.rm = TRUE)

# Tính tỷ lệ
p_fh <- fh_yes / total_fh

# Kiểm định tỷ lệ có bằng 0.5 không
test_fh <- prop.test(fh_yes, total_fh, p = 0.5, correct = TRUE)

# In kết quả
cat("Tỷ lệ có tiền sử gia đình:", round(p_fh, 4), "\n")
## Tỷ lệ có tiền sử gia đình: 0.4998
print(test_fh)
## 
##  1-sample proportions test with continuity correction
## 
## data:  fh_yes out of total_fh, null probability 0.5
## X-squared = 0.14643, df = 1, p-value = 0.702
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.4987573 0.5008360
## sample estimates:
##         p 
## 0.4997966

📌 Kết quả phân tích

  • Tổng số quan sát hợp lệ: 890.000 người
  • Số người có tiền sử gia đình: 444.819 người
  • Tỷ lệ người có tiền sử gia đình (mẫu): 0.4998 (tức 49.98%)

🔍 Diễn giải kết quả

  • Khoảng tin cậy 95% cho tỷ lệ: từ 49.88% đến 50.08%
  • Giá trị p-value = 0.702 > 0.05

➡️ Không có bằng chứng thống kê để bác bỏ giả thuyết \(H_0\)

✅ Kết luận

Kết quả kiểm định cho thấy tỷ lệ người có tiền sử gia đình mắc bệnh là 49.98%, và không khác biệt đáng kể so với tỷ lệ giả định 50%. Với p-value cao (0.702), có thể kết luận rằng phân bố biến family_history là cân bằng trong dữ liệu, không nghiêng về phía nào.

3. Thống kê suy diễn

3.1. Phân tích mối liên hệ giữa genderasthma

Biến gender biểu thị giới tính sinh học của bệnh nhân (Male/Female), còn biến asthma phản ánh tình trạng có hoặc không có hen suyễn (0: Không, 1: Có). Cả hai là biến định tính nhị phân. Mục tiêu là kiểm tra xem giới tính có liên quan đến tình trạng hen suyễn hay không.

3.1.1. Bảng chéo tần suất

tab_gender_asthma <- table(data$gender, data$asthma)
addmargins(tab_gender_asthma)
##         
##               0      1    Sum
##   Female 236148 208718 444866
##   Male   235783 209351 445134
##   Sum    471931 418069 890000

Bảng chéo và thống kê mô tả:

Asthma = 0 Asthma = 1 Tổng cộng
Female 236,148 208,718 444,866
Male 235,783 209,351 445,134
Tổng 471,931 418,069 890,000

Tỷ lệ mắc hen suyễn trong nhóm nữ là 46.92%, trong khi ở nam là 47.03%.

3.1.2. Kiểm định Chi-squared

chisq.test(tab_gender_asthma)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tab_gender_asthma
## X-squared = 1.1555, df = 1, p-value = 0.2824

Kiểm định Chi-squared:

  • Chi-squared = 1.16, df = 1
  • p-value = 0.2824 (không có ý nghĩa thống kê ở mức 5%)

⟶ Không có bằng chứng thống kê để kết luận rằng tỷ lệ hen suyễn khác biệt giữa nam và nữ.

3.1.3. Ước lượng Odds Ratio và Relative Risk

library(epitools)
oddsratio(tab_gender_asthma, rev = "c")
## $data
##         
##               1      0  Total
##   Female 208718 236148 444866
##   Male   209351 235783 445134
##   Total  418069 471931 890000
## 
## $measure
##         odds ratio with 95% C.I.
##           estimate    lower    upper
##   Female 1.0000000       NA       NA
##   Male   0.9954394 0.987186 1.003754
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact chi.square
##   Female         NA           NA         NA
##   Male    0.2814615    0.2815653  0.2814605
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
riskratio(tab_gender_asthma, rev = "c")
## $data
##         
##               1      0  Total
##   Female 208718 236148 444866
##   Male   209351 235783 445134
##   Total  418069 471931 890000
## 
## $measure
##         risk ratio with 95% C.I.
##           estimate     lower    upper
##   Female 1.0000000        NA       NA
##   Male   0.9978532 0.9939584 1.001763
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact chi.square
##   Female         NA           NA         NA
##   Male    0.2814615    0.2815653  0.2814605
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
# Hiển thị chi tiết
epitab(tab_gender_asthma, method = "oddsratio", rev = "c")
## Warning in b0 * a1: NAs produced by integer overflow
## Warning in a0 * b1: NAs produced by integer overflow
## $tab
##         
##               1        p0      0        p1 oddsratio lower upper   p.value
##   Female 208718 0.4992429 236148 0.5003867         1    NA    NA        NA
##   Male   209351 0.5007571 235783 0.4996133        NA    NA    NA 0.2815653
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"
epitab(tab_gender_asthma, method = "riskratio", rev = "c")
## $tab
##         
##               1        p0      0        p1 riskratio     lower    upper
##   Female 208718 0.4691705 236148 0.5308295 1.0000000        NA       NA
##   Male   209351 0.4703101 235783 0.5296899 0.9978532 0.9939584 1.001763
##         
##            p.value
##   Female        NA
##   Male   0.2815653
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"
  • Ý nghĩa: OR đo lường tỷ lệ chênh lệch odds mắc hen suyễn giữa nam và nữ.
  • OR (Male vs Female): 0.9954
  • CI 95%: [0.9872 ; 1.0038]
  • p-value ≈ 0.281

Diễn giải:

  • OR = 0.9954 nghĩa là nam giới có odds mắc hen suyễn thấp hơn nữ một chút (0.995 lần), nhưng sự khác biệt rất nhỏ.

  • Khoảng tin cậy 95% (CI) chứa giá trị 1 → không có ý nghĩa thống kê.

  • p-value = 0.281 (> 0.05) → không có bằng chứng để bác bỏ giả thuyết H₀ (giới tính không ảnh hưởng đến khả năng mắc hen suyễn).

  • Ý nghĩa: RR so sánh tỷ lệ mắc hen suyễn giữa nam và nữ (risk thực tế).

  • RR (Male vs Female): 0.9979
  • CI 95%: [0.9939 ; 1.0018]

Diễn giải:

  • RR = 0.9979 → nam giới có nguy cơ mắc hen suyễn thấp hơn nữ khoảng 0.21%, tức gần như không có khác biệt.
  • Khoảng tin cậy 95% cũng chứa giá trị 1 → không có ý nghĩa thống kê.

3.2. Phân tích mối liên hệ giữa family_historycirrhosis

Biến family_history thể hiện việc bệnh nhân có hay không tiền sử ung thư trong gia đình (Yes/No), còn biến cirrhosis phản ánh tình trạng xơ gan (0: Không, 1: Có). Phân tích nhằm kiểm tra mối liên hệ giữa hai biến này.

3.2.1. Bảng chéo tần suất

tab_fh_cirrhosis <- table(data$family_history, data$cirrhosis)
addmargins(tab_fh_cirrhosis)
##      
##            0      1    Sum
##   No  345054 100127 445181
##   Yes 343845 100974 444819
##   Sum 688899 201101 890000

Bảng chéo và thống kê mô tả:

Cirrhosis = 0 Cirrhosis = 1 Tổng cộng
Không tiền sử 345,054 100,127 445,181
Có tiền sử 343,845 100,974 444,819
Tổng 688,899 201,101 890,000

Tỷ lệ xơ gan trong nhóm có tiền sử gia đình là 22.70%, cao hơn so với nhóm không có tiền sử (22.49%).

3.2.2. Kiểm định Chi-squared

chisq.test(tab_fh_cirrhosis)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tab_fh_cirrhosis
## X-squared = 5.53, df = 1, p-value = 0.01869

Kiểm định Chi-squared:

  • Chi-squared = 5.53, df = 1
  • p-value = 0.0187 (có ý nghĩa thống kê ở mức 5%)

⟶ Có sự khác biệt có ý nghĩa thống kê trong tỷ lệ xơ gan giữa nhóm có và không có tiền sử gia đình.

3.2.3. Ước lượng Odds Ratio và Relative Risk

oddsratio(tab_fh_cirrhosis, rev = "c")
## $data
##        
##              1      0  Total
##   No    100127 345054 445181
##   Yes   100974 343845 444819
##   Total 201101 688899 890000
## 
## $measure
##      odds ratio with 95% C.I.
##        estimate     lower     upper
##   No  1.0000000        NA        NA
##   Yes 0.9881129 0.9783789 0.9980165
## 
## $p.value
##      two-sided
##       midp.exact fisher.exact chi.square
##   No          NA           NA         NA
##   Yes 0.01856637     0.018667 0.01856609
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
riskratio(tab_fh_cirrhosis, rev = "c")
## $data
##        
##              1      0  Total
##   No    100127 345054 445181
##   Yes   100974 343845 444819
##   Total 201101 688899 890000
## 
## $measure
##      risk ratio with 95% C.I.
##        estimate     lower     upper
##   No  1.0000000        NA        NA
##   Yes 0.9973072 0.9950707 0.9995486
## 
## $p.value
##      two-sided
##       midp.exact fisher.exact chi.square
##   No          NA           NA         NA
##   Yes 0.01856637     0.018667 0.01856609
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
# Hiển thị chi tiết
epitab(tab_fh_cirrhosis, method = "oddsratio", rev = "c")
## Warning in b0 * a1: NAs produced by integer overflow
## Warning in a0 * b1: NAs produced by integer overflow
## $tab
##      
##            1        p0      0        p1 oddsratio lower upper  p.value
##   No  100127 0.4978941 345054 0.5008775         1    NA    NA       NA
##   Yes 100974 0.5021059 343845 0.4991225        NA    NA    NA 0.018667
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"
epitab(tab_fh_cirrhosis, method = "riskratio", rev = "c")
## $tab
##      
##            1        p0      0        p1 riskratio     lower     upper  p.value
##   No  100127 0.2249130 345054 0.7750870 1.0000000        NA        NA       NA
##   Yes 100974 0.2270002 343845 0.7729998 0.9973072 0.9950707 0.9995486 0.018667
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"

OR = 0.9881 95% CI: [0.9784 ; 0.9980] p-value = 0.0187

  • OR = 0.9881 nghĩa là bệnh nhân có tiền sử ung thư gia đình có odds mắc xơ gan thấp hơn nhóm không có tiền sử khoảng 1.19%.
  • Khoảng tin cậy 95% không chứa 1, p-value < 0.05 → khác biệt có ý nghĩa thống kê.
  • Kết luận: Có mối liên hệ nhẹ nhưng có ý nghĩa thống kê giữa tiền sử gia đình và xơ gan. Tuy nhiên, mức độ ảnh hưởng là rất nhỏ.

RR = 0.9973 95% CI: [0.9951 ; 0.9995]

Diễn giải RR:

  • RR = 0.9973 nghĩa là nguy cơ mắc xơ gan ở nhóm có tiền sử ung thư gia đình thấp hơn 0.27% so với nhóm không có tiền sử.
  • CI không chứa 1 → khác biệt nhỏ nhưng có ý nghĩa thống kê.
  • Tương tự OR, RR cho thấy ảnh hưởng nhỏ nhưng đáng kể.

Ý tưởng chung của MLE là gì?

Trong thống kê, khi bạn có dữ liệu và muốn tìm ra các tham số tốt nhất (như trung bình, phương sai…) để mô tả dữ liệu đó, thì MLE là một trong những cách phổ biến nhất để làm điều này.

Câu hỏi đặt ra: Biết dữ liệu rồi, làm sao “ngược lại” để tìm được các tham số mô tả tốt nhất cho phân phối tạo ra dữ liệu đó?

➡ Đó chính là mục tiêu của MLE: Tìm bộ tham số làm cho dữ liệu đang có là “hợp lý nhất” dưới phân phối giả định.

Hàm hợp lý (Likelihood function) là gì?

Để tìm tham số “tốt nhất”, ta cần một công cụ đo lường – đó là hàm hợp lý.

Giả sử bạn có:

  • Một bộ dữ liệu gồm \(n\) quan sát: \(x_1, x_2, ..., x_n\)
  • Biết dữ liệu tuân theo một phân phối nào đó, ví dụ: phân phối chuẩn hoặc phân phối Poisson, với một số tham số chưa biết, ký hiệu là \(\theta\)

Hàm hợp lý \(L(\theta)\) là tích của tất cả các xác suất (hoặc mật độ xác suất) của từng điểm dữ liệu \(x_i\) dưới tham số \(\theta\). Nếu dữ liệu là độc lập và phân phối giống nhau (i.i.d), thì:

\[ L(\theta) = P(x_1, x_2, ..., x_n | \theta) = \prod_{i=1}^{n} f(x_i|\theta) \]

✅ Mục tiêu là: Tìm giá trị của \(\theta\) sao cho hàm \(L(\theta)\)lớn nhất.

Vì sao dùng log-likelihood?

Tích của nhiều xác suất nhỏ sẽ ra một số rất bé, dễ gây sai số tính toán. Để đơn giản hơn, ta lấy log cả hai vế (log của tích thành tổng):

\[ \log L(\theta) = \sum_{i=1}^{n} \log f(x_i|\theta) \]

Hàm mới này gọi là log-likelihood, ký hiệu \(\ell(\theta)\), và có cùng điểm cực đại với \(L(\theta)\).

✅ Bài toán trở thành: Tìm \(\theta\) sao cho \(\ell(\theta)\) là lớn nhất

Ví dụ cụ thể: Ước lượng trung bình cân nặng người trưởng thành

Giả sử:

  • Cân nặng người trưởng thành tuân theo phân phối chuẩn \(N(\mu, \sigma^2)\)
  • Ta đo được một mẫu gồm \(n\) người với cân nặng \(x_1, x_2, ..., x_n\)

Bước 1: Viết hàm mật độ xác suất

\[ f(x_i|\mu, \sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x_i - \mu)^2}{2\sigma^2}\right) \]

Bước 2: Viết hàm hợp lý

\[ L(\mu, \sigma^2) = \prod_{i=1}^{n} f(x_i|\mu, \sigma^2) \]

Bước 3: Lấy log và đơn giản hoá

\[ \log L(\mu, \sigma^2) = -\frac{n}{2} \log(2\pi) - \frac{n}{2} \log(\sigma^2) - \frac{1}{2\sigma^2} \sum_{i=1}^{n}(x_i - \mu)^2 \]

Bước 4: Tính đạo hàm và giải phương trình đạo hàm = 0

Giải phương trình đạo hàm theo \(\mu\), ta sẽ thu được:

\[ \hat{\mu} = \frac{1}{n} \sum_{i=1}^{n} x_i \quad \text{(trung bình mẫu)} \]

Giải tiếp theo \(\sigma^2\), ta có:

\[ \hat{\sigma}^2 = \frac{1}{n} \sum_{i=1}^{n}(x_i - \hat{\mu})^2 \quad \text{(phương sai mẫu không điều chỉnh)} \]

✅ Kết luận: Ước lượng hợp lý tối đa cho trung bình và phương sai chính là trung bình và phương sai mẫu!

Tổng kết ngắn gọn

Nội dung Giải thích ngắn
MLE là gì? Là phương pháp tìm tham số để làm cho dữ liệu đã quan sát là “hợp lý nhất” dưới một phân phối giả định.
Hàm hợp lý Xác suất (hoặc mật độ) của toàn bộ dữ liệu, biểu diễn theo tham số cần ước lượng.
Log-likelihood Log của hàm hợp lý, giúp đơn giản hóa quá trình tính toán.
Ước lượng MLE Là nghiệm của bài toán cực trị (tối đa hóa log-likelihood).
Ứng dụng Dùng để ước lượng trung bình, phương sai, tỷ lệ,… trong nhiều mô hình phân phối khác nhau.

4: Lý thuyết về hồi quy logistic

4.1. Hồi quy logistic là gì?

Hồi quy logistic là một phương pháp thống kê được dùng để dự đoán khả năng xảy ra của một sự kiện khi biến kết quả là nhị phân (tức là chỉ có 2 giá trị: ví dụ như Sống hay Chết, Có bệnh hay Không bệnh, Đậu hay Rớt…).

Ví dụ

Giả sử bạn muốn dự đoán xem một người có sống sót (survived = 1) hay không (survived = 0), dựa vào tình trạng hút thuốc (smoking status).

4.2. Tại sao không dùng hồi quy tuyến tính?

  • Hồi quy tuyến tính cho kết quả đầu ra là một con số bất kỳ, có thể lớn hơn 1 hoặc nhỏ hơn 0.
  • Nhưng trong bài toán kiểu “Có” hoặc “Không”, ta cần đầu ra là xác suất (0 đến 1).

Do đó, hồi quy logistic dùng hàm logistic để biến đầu ra luôn nằm trong khoảng (0, 1), biểu diễn xác suất xảy ra sự kiện.

4.3. Mô hình hồi quy logistic cơ bản (đơn biến)

Mô hình:

logit(p) = ln(p / (1 - p)) = β₀ + β₁ × X

Trong đó:

  • p là xác suất sự kiện xảy ra (ví dụ: sống sót)
  • X là biến độc lập (ví dụ: tình trạng hút thuốc)
  • β₀β₁ là hệ số hồi quy
  • logit(p) là log-odds (log của tỷ số giữa xác suất xảy ra và không xảy ra)

4.4. Diễn giải kết quả

Khi bạn ước lượng mô hình, bạn sẽ nhận được hệ số β₁:

  • Nếu β₁ > 0 → biến X tăng xác suất xảy ra sự kiện
  • Nếu β₁ < 0 → biến X giảm xác suất
  • Nếu p-value < 0.05 → quan hệ này là có ý nghĩa thống kê

5: Phân tích mô hình hồi quy logistic với dữ liệu dataset_med.csv

5.1. Phân tích mô hình hồi quy logistic đơn biến

# Chuyển đổi biến
data$gender <- factor(data$gender)
data$smoking_status <- factor(data$smoking_status)
data$cancer_stage <- factor(data$cancer_stage, ordered = TRUE, levels = c("I", "II", "III", "IV"))
data$treatment_type <- factor(data$treatment_type)
data$survived <- factor(data$survived)  # Yếu tố nhị phân
# Hồi quy đơn biến: tuổi
model_age <- glm(survived ~ age, data = data, family = binomial)
summary(model_age)
## 
## Call:
## glm(formula = survived ~ age, family = binomial, data = data)
## 
## Coefficients:
##               Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -1.2807145  0.0143127 -89.481   <2e-16 ***
## age          0.0002978  0.0002559   1.164    0.245    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 938412  on 889999  degrees of freedom
## Residual deviance: 938411  on 889998  degrees of freedom
## AIC: 938415
## 
## Number of Fisher Scoring iterations: 4
  • Hệ số dương (0.0002978) cho thấy tuổi tăng nhẹ thì xác suất sống sót tăng, nhưng không có ý nghĩa thống kê (p-value = 0.245 > 0.05).
  • Do đó, tuổi không ảnh hưởng đáng kể đến khả năng sống sót trong mô hình đơn biến.
# Hồi quy đơn biến: giới tính
model_gender <- glm(survived ~ gender, data = data, family = binomial)
summary(model_gender)
## 
## Call:
## glm(formula = survived ~ gender, family = binomial, data = data)
## 
## Coefficients:
##              Estimate Std. Error  z value Pr(>|z|)    
## (Intercept) -1.266171   0.003620 -349.788   <2e-16 ***
## genderMale   0.003677   0.005116    0.719    0.472    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 938412  on 889999  degrees of freedom
## Residual deviance: 938412  on 889998  degrees of freedom
## AIC: 938416
## 
## Number of Fisher Scoring iterations: 4
  • Hệ số dương, nhưng p-value lớn ⇒ giới tính không ảnh hưởng đáng kể đến khả năng sống sót.
  • Nhóm tham chiếu là “Nữ”, nên hệ số của “Male” đại diện cho sự khác biệt giữa nam và nữ, nhưng không đủ bằng chứng để khẳng định có khác biệt.
# Hồi quy đơn biến: tình trạng hút thuốc
model_smoke <- glm(survived ~ smoking_status, data = data, family = binomial)
summary(model_smoke)
## 
## Call:
## glm(formula = survived ~ smoking_status, family = binomial, data = data)
## 
## Coefficients:
##                               Estimate Std. Error  z value Pr(>|z|)    
## (Intercept)                  -1.263686   0.005122 -246.726   <2e-16 ***
## smoking_statusFormer Smoker  -0.004075   0.007245   -0.562    0.574    
## smoking_statusNever Smoked    0.003317   0.007233    0.459    0.647    
## smoking_statusPassive Smoker -0.001834   0.007235   -0.253    0.800    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 938412  on 889999  degrees of freedom
## Residual deviance: 938411  on 889996  degrees of freedom
## AIC: 938419
## 
## Number of Fisher Scoring iterations: 4
  • Nhóm tham chiếu là "Current Smoker".
  • Các nhóm khác không có hệ số mang ý nghĩa thống kê ⇒ tình trạng hút thuốc không ảnh hưởng rõ ràng đến khả năng sống sót trong phân tích đơn biến.

5.2. Hồi quy logistic đa biến

model_full <- glm(survived ~ age + gender + smoking_status ,
                  data = data, family = binomial)
summary(model_full)
## 
## Call:
## glm(formula = survived ~ age + gender + smoking_status, family = binomial, 
##     data = data)
## 
## Coefficients:
##                                Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                  -1.2819274  0.0152057 -84.306   <2e-16 ***
## age                           0.0002979  0.0002559   1.164    0.244    
## genderMale                    0.0036853  0.0051158   0.720    0.471    
## smoking_statusFormer Smoker  -0.0040668  0.0072452  -0.561    0.575    
## smoking_statusNever Smoked    0.0033270  0.0072331   0.460    0.646    
## smoking_statusPassive Smoker -0.0018308  0.0072349  -0.253    0.800    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 938412  on 889999  degrees of freedom
## Residual deviance: 938409  on 889994  degrees of freedom
## AIC: 938421
## 
## Number of Fisher Scoring iterations: 4

Ngay cả khi kết hợp nhiều biến lại, không có biến nào có ảnh hưởng đáng kể (p < 0.05) đến khả năng sống sót.

#Chuyển hệ số sang Odds Ratio để dễ hiểu hơn

exp(cbind(OddsRatio = coef(model_full), confint(model_full)))
## Waiting for profiling to be done...
##                              OddsRatio     2.5 %    97.5 %
## (Intercept)                  0.2775019 0.2693517 0.2858946
## age                          1.0002980 0.9997963 1.0007999
## genderMale                   1.0036921 0.9936785 1.0138066
## smoking_statusFormer Smoker  0.9959415 0.9818987 1.0101851
## smoking_statusNever Smoked   1.0033325 0.9892091 1.0176577
## smoking_statusPassive Smoker 0.9981709 0.9841166 1.0124259
Biến Odds Ratio 95% CI
age ~1.0003 (0.99996, 1.0008)
genderMale ~1.0037 (0.993, 1.014)
smoking_statusNever ~1.0033 (0.989, 1.0177)

Diễn giải:

  • Các Odds Ratio đều xấp xỉ 1, và khoảng tin cậy đều chứa 1 ⇒ không có biến nào có ảnh hưởng đáng kể đến odds sống sót.
# Đánh giá mô hình (tùy chọn)
# AIC
AIC(model_full)
## [1] 938421.3
# Biểu đồ ROC
library(pROC)
## Warning: package 'pROC' was built under R version 4.4.3
## Type 'citation("pROC")' for a citation.
## 
## Attaching package: 'pROC'
## The following objects are masked from 'package:stats':
## 
##     cov, smooth, var
prob <- predict(model_full, type = "response")
roc_obj <- roc(data$survived, prob)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
plot(roc_obj)

auc(roc_obj)
## Area under the curve: 0.5016

AUC= 0.5016 (AUC < 0.6) thì mô hình không có khả năng phân biệt tốt giữa sống và không sống.

KẾT LUẬN TỔNG THỂ:

  • Cả 3 yếu tố: tuổi, giới tính, và tình trạng hút thuốc đều không có ảnh hưởng đáng kể đến khả năng sống sót theo hồi quy logistic (đơn biến và đa biến).
  • Các hệ số đều nhỏ, p-value > 0.05, Odds Ratio gần 1, khoảng tin cậy chứa 1.
LS0tIA0KdGl0bGU6ICJUdeG6p24gNiINCmF1dGhvcjogIkhvw6BuZyBRdXnDqm4iDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UgIA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogdHJ1ZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KLS0tIA0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCg0KYGBgIHtjc3MsIGVjaG8gPSBGQUxTRX0NCmgxIHsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGZvbnQtc2l6ZTogMzJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIH0NCg0KaDIgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgZm9udC1zaXplOiAyOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiANCn0NCg0KaDMgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgZm9udC1zaXplOiAyNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zdHlsZTogaXRhbGljOw0KfQ0KDQpoNCB7Zm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGZvbnQtc2l6ZTogMjBweDsNCiAgZm9udC1zdHlsZTogaXRhbGljOw0KICB9DQoNCmJvZHkgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgZm9udC1zaXplOiAxOHB4Ow0KICANCn0NCnA6bm90KGgxKTpub3QoaDIpOm5vdChoMyk6bm90KGg0KTpub3QoaDUpIHsNCiAgdGV4dC1pbmRlbnQ6IDJlbTt9DQpwIHsNCiAgdGV4dC1hbGlnbjoganVzdGlmeTsNCiAgfQ0KLnRvY2lmeS1oZWFkZXIgew0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KYGBgICAgDQoNCmBgYHtyfQ0KdW5saW5rKCJ0dWFuNS5rbml0Lm1kIikNCmBgYA0KDQoNCmBgYHtyIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShlcGl0b29scykNCmxpYnJhcnkoRGVzY1Rvb2xzKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkoZW5lcmd5KQ0KbGlicmFyeShyZWFkcikNCmBgYA0KDQoNCiMgMS4qKlbhu4EgQuG7mSBE4buvIExp4buHdSoqIPCfl4LvuI8NCg0KKirwn5OEIE3DtCB04bqjKioNCg0KQuG7mSBk4buvIGxp4buHdSBuw6B5IGNo4bupYSB0aMO0bmcgdGluIHbhu4EgdOG7tyBs4buHIHThu60gdm9uZyBkbyB1bmcgdGjGsCBwaOG7lWkgdsOgIGzDoCBt4buZdCB04bqtcCBo4bujcCB0b8OgbiBkaeG7h24gduG7gSB0aMO0bmcgdGluIGPhu6dhIGLhu4duaCBuaMOibiwgdOG6rXAgdHJ1bmcgY2jhu6cgeeG6v3UgdsOgbyBuaOG7r25nIG5nxrDhu51pIMSRw6MgxJHGsOG7o2MgY2jhuqluIMSRb8OhbiBt4bqvYyB1bmcgdGjGsC4gVuG7m2kgODAwLjAwMCBjw6EgbmjDom4gxJHGsOG7o2MgZ2hpIG5o4bqtbiwgYuG7mSBk4buvIGxp4buHdSBiYW8gZ+G7k20gxJHhuqd5IMSR4bunIHRow7RuZyB0aW4gbGnDqm4gcXVhbiDEkeG6v24gcXXDoSB0csOsbmggY2jhuqluIMSRb8OhbiwgxJFp4buBdSB0cuG7iyB2w6Aga+G6v3QgcXXhuqMgxJFp4buBdSB0cuG7iyB1bmcgdGjGsCBwaOG7lWksIMSRxrDhu6NjIHThu5UgY2jhu6ljIHRyb25nIDE2IGPhu5l0IHLDtSByw6BuZyB2w6AgY8OzIGPhuqV1IHRyw7pjLiDEkMOieSBsw6AgbeG7mXQgbmd14buTbiBk4buvIGxp4buHdSBxdXkgbcO0IGzhu5tuLCDEkcaw4bujYyB0aGnhur90IGvhur8gbmjhurFtIGjhu5cgdHLhu6MgY8OhYyBuaMOgIG5naGnDqm4gY+G7qXUsIG5ow6Aga2hvYSBo4buNYyBk4buvIGxp4buHdSB2w6AgY2h1ecOqbiBnaWEgeSB04bq/IHRyb25nIHZp4buHYyBwaMOibiB0w61jaCBtw7QgaMOsbmgsIHjDonkgZOG7sW5nIGPDoWMgaOG7hyB0aOG7kW5nIGThu7EgxJFvw6FuLCBjxaluZyBuaMawIGPhuqNpIHRoaeG7h24gY2hp4bq/biBsxrDhu6NjIHBow6F0IGhp4buHbiBz4bubbSB2w6AgxJFp4buBdSB0cuG7iyBi4buHbmguDQoNCg0KYGBge3J9DQojxJDhu41jIGThu68gbGnhu4d1IHThu6sgZmlsZSBDU1YNCmRhdGEgPC0gcmVhZC5jc3YoIkM6L1VzZXJzL0hvYW5nIFF1eWVuL0Rvd25sb2Fkcy9kYXRhc2V0X21lZC5jc3YiKQ0KI0hp4buDbiB0aOG7iyBj4bqldSB0csO6YyBk4buvIGxp4buHdQ0Kc3RyKGRhdGEpDQpWaWV3KGRhdGEpDQpgYGANCg0KYGBge3J9DQojSGnhu4NuIHRo4buLIDUgZMOybmcgxJHhuqd1IHbDoCBjdeG7kWkNCmhlYWQoZGF0YSwgNSkNCnRhaWwoZGF0YSwgNSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBDw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oIGThuqFuZyBjaHXhu5dpIGPhuqduIGNodXnhu4NuIHRow6BuaCBmYWN0b3I6DQpjb2xzX3RvX2ZhY3RvciA8LSBjKCJnZW5kZXIiLCAiY291bnRyeSIsICJjYW5jZXJfc3RhZ2UiLA0KICAgICAgICAgICAgICAgICAgICAiZmFtaWx5X2hpc3RvcnkiLCAic21va2luZ19zdGF0dXMiLCAidHJlYXRtZW50X3R5cGUiKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCiMgQ2h1eeG7g24gY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCBk4bqhbmcgY2h14buXaSB0aMOgbmggZmFjdG9yDQpkYXRhW2NvbHNfdG9fZmFjdG9yXSA8LSBsYXBwbHkoZGF0YVtjb2xzX3RvX2ZhY3Rvcl0sIGFzLmZhY3RvcikNCg0KYGBgDQoNCg0KfCBUw6puIGJp4bq/biAgICAgICAgICAgICAgICAgfCBLaeG7g3UgZOG7ryBsaeG7h3UgICAgIHwgTcO0IHThuqMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfA0KfCAqKmlkKiogICAgICAgICAgICAgICAgICAgfCDEkOG7i25oIGRhbmggICAgICAgIHwgTcOjIHPhu5EgxJHhu4tuaCBkYW5oIGNobyBt4buXaSBi4buHbmggbmjDom4uIEtow7RuZyBz4butIGThu6VuZyB0cm9uZyBwaMOibiB0w61jaCB0aOG7kW5nIGvDqi4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmFnZSoqICAgICAgICAgICAgICAgICAgfCDEkOG7i25oIGzGsOG7o25nICAgICAgIHwgVHXhu5VpIGPhu6dhIGLhu4duaCBuaMOibiB04bqhaSB0aOG7nWkgxJFp4buDbSBjaOG6qW4gxJFvw6FuLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmdlbmRlcioqICAgICAgICAgICAgICAgfCDEkOG7i25oIHTDrW5oICAgICAgICB8IEdp4bubaSB0w61uaCBj4bunYSBi4buHbmggbmjDom4gKCpOYW0qIGhv4bq3YyAqTuG7ryopLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipjb3VudHJ5KiogICAgICAgICAgICAgIHwgxJDhu4tuaCB0w61uaCAgICAgICAgfCBRdeG7kWMgZ2lhIGPGsCB0csO6IGPhu6dhIGLhu4duaCBuaMOibi4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqZGlhZ25vc2lzXF9kYXRlKiogICAgICB8IMSQ4buLbmggdMOtbmggKG5nw6B5KSB8IE5nw6B5IGLhu4duaCBuaMOibiDEkcaw4bujYyBjaOG6qW4gxJFvw6FuIHVuZyB0aMawLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqY2FuY2VyXF9zdGFnZSoqICAgICAgICB8IMSQ4buLbmggdMOtbmggICAgICAgIHwgR2lhaSDEkW/huqFuIHVuZyB0aMawICh04burIFN0YWdlIEkgxJHhur9uIFN0YWdlIElWKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmZhbWlseVxfaGlzdG9yeSoqICAgICAgfCDEkOG7i25oIHTDrW5oICAgICAgICB8IFRp4buBbiBz4butIHVuZyB0aMawIHRyb25nIGdpYSDEkcOsbmggKCpZZXMqIGhv4bq3YyAqTm8qKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipzbW9raW5nXF9zdGF0dXMqKiAgICAgIHwgxJDhu4tuaCB0w61uaCAgICAgICAgfCBUw6xuaCB0cuG6oW5nIGjDunQgdGh14buRYyAoZ+G7k20gNCBt4bupYzogKkN1cnJlbnQqLCAqRm9ybWVyKiwgKlBhc3NpdmUqLCAqTmV2ZXIqKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmJtaSoqICAgICAgICAgICAgICAgICAgfCDEkOG7i25oIGzGsOG7o25nICAgICAgIHwgQ2jhu4kgc+G7kSBraOG7kWkgY8ahIHRo4buDIChCb2R5IE1hc3MgSW5kZXgpLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmNob2xlc3Rlcm9sXF9sZXZlbCoqICAgfCDEkOG7i25oIGzGsOG7o25nICAgICAgIHwgTeG7qWMgY2hvbGVzdGVyb2wgdHJvbmcgbcOhdS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmh5cGVydGVuc2lvbioqICAgICAgICAgfCDEkOG7i25oIHTDrW5oICAgICAgICB8IEPDsyBoYXkga2jDtG5nIGLhu4sgY2FvIGh1eeG6v3Qgw6FwICgwID0gS2jDtG5nLCAxID0gQ8OzKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKiphc3RobWEqKiAgICAgICAgICAgICAgIHwgxJDhu4tuaCB0w61uaCAgICAgICAgfCBDw7MgaGF5IGtow7RuZyBt4bqvYyBoZW4gc3V54buFbiAoMCA9IEtow7RuZywgMSA9IEPDsykuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipjaXJyaG9zaXMqKiAgICAgICAgICAgIHwgxJDhu4tuaCB0w61uaCAgICAgICAgfCBDw7MgaGF5IGtow7RuZyBt4bqvYyB4xqEgZ2FuICgwID0gS2jDtG5nLCAxID0gQ8OzKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKm90aGVyXF9jYW5jZXIqKiAgICAgICAgfCDEkOG7i25oIHTDrW5oICAgICAgICB8IEPDsyBoYXkga2jDtG5nIG3huq9jIGPDoWMgbG/huqFpIHVuZyB0aMawIGtow6FjICgwID0gS2jDtG5nLCAxID0gQ8OzKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKnRyZWF0bWVudFxfdHlwZSoqICAgICAgfCDEkOG7i25oIHTDrW5oICAgICAgICB8IFBoxrDGoW5nIHBow6FwIMSRaeG7gXUgdHLhu4sgY2jDrW5oICgqQ2hlbW90aGVyYXB5KiwgKlJhZGlhdGlvbiosICpTdXJnZXJ5KiwgKkNvbWJpbmVkKikuICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKiplbmRcX3RyZWF0bWVudFxfZGF0ZSoqIHwgxJDhu4tuaCB0w61uaCAobmfDoHkpIHwgTmfDoHkga+G6v3QgdGjDumMgcXXDoSB0csOsbmggxJFp4buBdSB0cuG7iy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqc3Vydml2ZWQqKiAgICAgICAgICAgICB8IMSQ4buLbmggdMOtbmggICAgICAgIHwgS+G6v3QgY+G7pWMgc+G7kW5nIHPDs3QgKDAgPSBLaMO0bmcgc+G7kW5nIHPDs3QsIDEgPSBT4buRbmcgc8OzdCkuIEJp4bq/biDEkeG6p3UgcmEgcXVhbiB0cuG7jW5nIHRyb25nIHBow6JuIHTDrWNoIHN1eSBkaeG7hW4uIHwNCg0KDQpExrDhu5tpIMSRw6J5IGzDoCBwaGnDqm4gYuG6o24gxJHDoyBj4bqtcCBuaOG6rXQgxJHhuqd5IMSR4bunIG7hu5lpIGR1bmcgdGjhu5FuZyBrw6ogbcO0IHThuqMgYmnhur9uICoqYGdlbmRlcmAqKiwgY8OzICoqaGnhu4NuIHRo4buLIHPhu5EgbGnhu4d1IG5nYXkgdHLDqm4gxJHhu4luaCBj4buZdCoqLCB0csOsbmggYsOgeSB0aGVvICoqZOG6oW5nIGLDoW8gY8OhbyBo4buNYyB0aHXhuq10IGNodXnDqm4gbmdoaeG7h3AqKiwgZMO5bmcgxJHGsOG7o2MgdHJvbmcgY2jGsMahbmcgdGjhu5FuZyBrw6ogbcO0IHThuqM6DQoNCiMgKioyLiBUaOG7kW5nIGvDqiBtw7QgdOG6oyoqDQoNCiMjICoqMi4xLiBUaOG7kW5nIGvDqiBtw7QgdOG6oyBiaeG6v24gYGdlbmRlcmAqKg0KDQpCaeG6v24gYGdlbmRlcmAgbMOgIG3hu5l0IGJp4bq/biDEkeG7i25oIHTDrW5oIHBow6JuIGxv4bqhaSAoY2F0ZWdvcmljYWwgbm9taW5hbCB2YXJpYWJsZSksIHBo4bqjbiDDoW5oIGdp4bubaSB0w61uaCBzaW5oIGjhu41jIGPhu6dhIGPDoWMgYuG7h25oIG5ow6JuIHRyb25nIHThuq1wIGThu68gbGnhu4d1LCB24bubaSBoYWkgbeG7qWMgZ2nDoSB0cuG7iyBjaMOtbmg6ICpNYWxlKiAoTmFtKSB2w6AgKkZlbWFsZSogKE7hu68pLiBWaeG7h2MgcGjDom4gdMOtY2ggYmnhur9uIG7DoHkgZ2nDunAgbmjhuq1uIGRp4buHbiBz4buxIHBow6JuIGLhu5EgZ2nhu5tpIHTDrW5oIHRyb25nIG3huqt1IG5naGnDqm4gY+G7qXUgdsOgIGzDoCBjxqEgc+G7nyBxdWFuIHRy4buNbmcgY2hvIGPDoWMgcGjDom4gdMOtY2ggdGnhur9wIHRoZW8gduG7gSBt4buRaSBsacOqbiBo4buHIHbhu5tpIHnhur91IHThu5EgYuG7h25oIGzDvSB2w6AgZGkgdHJ1eeG7gW4uDQoNCg0KIyMjICoqMi4xLjEuIFRo4buRbmcga8OqIHThuqduIHN14bqldCB2w6AgdOG7tyBs4buHIHBo4bqnbiB0csSDbSoqDQoNCmBgYHtyfQ0KIyBU4bqnbiBzdeG6pXQgdsOgIHThu7cgbOG7hyBwaOG6p24gdHLEg20NCmdlbmRlcl9mcmVxIDwtIHRhYmxlKGRhdGEkZ2VuZGVyKQ0KZ2VuZGVyX3Byb3AgPC0gcHJvcC50YWJsZShnZW5kZXJfZnJlcSkgKiAxMDANCg0KIyBIaeG7g24gdGjhu4sgZMaw4bubaSBk4bqhbmcgYuG6o25nDQpnZW5kZXJfc3VtbWFyeSA8LSBkYXRhLmZyYW1lKA0KICBHZW5kZXIgPSBuYW1lcyhnZW5kZXJfZnJlcSksDQogIEZyZXF1ZW5jeSA9IGFzLnZlY3RvcihnZW5kZXJfZnJlcSksDQogIFBlcmNlbnRhZ2UgPSByb3VuZChhcy52ZWN0b3IoZ2VuZGVyX3Byb3ApLCAyKQ0KKQ0KDQpnZW5kZXJfc3VtbWFyeQ0KYGBgDQoNCg0KPiBL4bq/dCBxdeG6oyBwaMOibiB0w61jaCBjaG8gdGjhuqV5IGdp4bubaSB0w61uaCBuYW0gY2hp4bq/bSB04bu3IGzhu4cgbmjhu4luaCBoxqFuIHRyb25nIHThu5VuZyB0aOG7gyBt4bqrdSwgduG7m2kgNTAsMDIlIGLhu4duaCBuaMOibiBsw6AgbmFtIGdp4bubaSB2w6AgNDksOTglIGzDoCBu4buvIGdp4bubaS4gU+G7sSBwaMOibiBi4buRIGfhuqduIG5oxrAgY8OibiBi4bqxbmcgZ2nhu69hIGhhaSBnaeG7m2kgZ2nDunAgxJHhuqNtIGLhuqNvIHTDrW5oIMSR4bqhaSBkaeG7h24gdHJvbmcgY8OhYyBwaMOibiB0w61jaCB0aeG6v3AgdGhlbywgxJHhu5NuZyB0aOG7nWkgcGjhuqNuIMOhbmggdGjhu7FjIHRy4bqhbmcgZOG7i2NoIHThu4UgaOG7jWMgdW5nIHRoxrAgcGjhu5VpIGPDsyBsacOqbiBxdWFuIMSR4bq/biBj4bqjIGhhaSBuaMOzbSBnaeG7m2kuDQoNCg0KIyMjICoqMi4xLjIuIEJp4buDdSDEkeG7kyBj4buZdCB0aOG7gyBoaeG7h24gcGjDom4gYuG7kSBnaeG7m2kgdMOtbmgqKg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBDaHXhuqluIGLhu4sgZOG7ryBsaeG7h3UgdMOzbSB04bqvdA0KZ2VuZGVyX3N1bW1hcnkgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShkYXRhJGdlbmRlcikpDQpjb2xuYW1lcyhnZW5kZXJfc3VtbWFyeSkgPC0gYygiR2VuZGVyIiwgIkNvdW50IikNCg0KIyBCaeG7g3UgxJHhu5MgY8OzIG5ow6NuIHPhu5EgdHLDqm4gY+G7mXQNCmdncGxvdChnZW5kZXJfc3VtbWFyeSwgYWVzKHggPSBHZW5kZXIsIHkgPSBDb3VudCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzY2QzJBNSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IENvdW50KSwgdmp1c3QgPSAtMC41LCBzaXplID0gNC41KSArDQogIGxhYnModGl0bGUgPSAiUGhhbiBibyBnaW9pIHRpbmggY3VhIGJlbmggbmhhbiIsDQogICAgICAgeCA9ICJHaeG7m2kgdMOtbmgiLCB5ID0gIlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCj4gQmnhu4N1IMSR4buTIGPhu5l0IHRo4buDIGhp4buHbiB0cuG7sWMgcXVhbiBz4buRIGzGsOG7o25nIGLhu4duaCBuaMOibiB0aGVvIHThu6tuZyBnaeG7m2kgdMOtbmguIEPDoWMgZ2nDoSB0cuG7iyBj4bulIHRo4buDIMSRxrDhu6NjIGfhuq9uIG5ow6NuIG5nYXkgdHLDqm4gY8OhYyBj4buZdCBnacO6cCBuZ8aw4budaSDEkeG7jWMgZOG7hSBkw6BuZyBuaOG6rW4gYmnhur90IHPhu7EgcGjDom4gYuG7kSBtw6Aga2jDtG5nIGPhuqduIMSR4buRaSBjaGnhur91IHbhu5tpIGLhuqNuZyBz4buRIGxp4buHdSByacOqbmcuDQoNCg0KIyMjICoqMi4xLjMuIMav4bubYyBsxrDhu6NuZyB2w6Aga2nhu4NtIMSR4buLbmggdOG7tyBs4buHIG7hu68qKg0KDQojIyMjIPCfk4wgTeG7pWMgdGnDqnUNCg0KTeG7pWMgdGnDqnUgY+G7p2EgcGjDom4gdMOtY2ggbMOgOg0KDQoqICoqxq/hu5tjIGzGsOG7o25nIHThu7cgbOG7hyBu4buvIGdp4bubaSoqIHRyb25nIHThu5VuZyB0aOG7gyBuZ8aw4budaSBxdWFuIHPDoXQuDQoqICoqS2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3QqKiB4ZW0gdOG7tyBs4buHIG7hu68gdHJvbmcgbeG6q3UgY8OzIGtow6FjIGJp4buHdCDEkcOhbmcga+G7gyBzbyB24bubaSB04bu3IGzhu4cgZ2nhuqMgxJHhu4tuaCBsw6AgNTAlIGhheSBraMO0bmcuDQoNCg0KIyMjIyDwn5OMIFBoxrDGoW5nIHBow6FwDQoNClRhIHjDqXQgbeG7mXQgYsOgaSB0b8OhbiBraeG7g20gxJHhu4tuaCB04bu3IGzhu4cgbeG7mXQgbeG6q3UsIHRyb25nIMSRw7M6DQoNCiogQmnhur9uIG5naGnDqm4gY+G7qXU6IGBnZW5kZXJgDQoqIEdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oOg0KDQokJA0KSF8wOiBwID0gMC41IFxxdWFkIFx0ZXh0eyhU4bu3IGzhu4cgbuG7ryB0cm9uZyB04buVbmcgdGjhu4MgbMOgIDUwXCUpfSBcXA0KSF8xOiBwIFxuZXEgMC41IFxxdWFkIFx0ZXh0eyhU4bu3IGzhu4cgbuG7ryBraMOhYyA1MFwlKX0NCiQkDQoNCg0KYGBge3J9DQojIMSQ4bq/bSBz4buRIGzGsOG7o25nIG7hu68gdsOgIHThu5VuZyBz4buRIChz4butYSDEkcO6bmcgdMOqbiBiaeG6v246IGRmKQ0KZmVtYWxlX2NvdW50IDwtIHN1bShkYXRhJGdlbmRlciA9PSAiRmVtYWxlIiwgbmEucm0gPSBUUlVFKQ0KdG90YWxfZ2VuZGVyIDwtIHN1bShkYXRhJGdlbmRlciAlaW4lIGMoIkZlbWFsZSIsICJNYWxlIiksIG5hLnJtID0gVFJVRSkNCg0KIyBUw61uaCB04bu3IGzhu4cgbuG7rw0KcF9mZW1hbGUgPC0gZmVtYWxlX2NvdW50IC8gdG90YWxfZ2VuZGVyDQoNCiMgS2nhu4NtIMSR4buLbmggdOG7tyBs4buHIG7hu68gY8OzIGLhurFuZyAwLjUga2jDtG5nDQp0ZXN0X2dlbmRlciA8LSBwcm9wLnRlc3QoZmVtYWxlX2NvdW50LCB0b3RhbF9nZW5kZXIsIHAgPSAwLjUsIGNvcnJlY3QgPSBUUlVFKQ0KDQojIEluIGvhur90IHF14bqjDQpjYXQoIlThu7cgbOG7hyBu4buvOiIsIHJvdW5kKHBfZmVtYWxlLCA0KSwgIlxuIikNCnByaW50KHRlc3RfZ2VuZGVyKQ0KDQpgYGANCiMjIyMg8J+TjCBL4bq/dCBxdeG6oyBwaMOibiB0w61jaA0KDQpU4buVbmcgc+G7kSBxdWFuIHPDoXQgaOG7o3AgbOG7hyBsw6AgKio4OTAuMDAwIG5nxrDhu51pKiosIHRyb25nIMSRw7MgY8OzOg0KDQoqICoqU+G7kSBsxrDhu6NuZyBu4buvIGdp4bubaSoqOiA0NDQuODY2IG5nxrDhu51pDQoqICoqVOG7tyBs4buHIG7hu68gbeG6q3UqKjogMC40OTk4ICh0xrDGoW5nIMSRxrDGoW5nIDQ5Ljk4JSkNCg0KIyMjIyDwn5SNIERp4buFbiBnaeG6o2kga+G6v3QgcXXhuqMNCg0KKiAqKktob+G6o25nIHRpbiBj4bqteSA5NSUqKiBjaG8gdOG7tyBs4buHIG7hu686IHThu6sgKio0OS44OCUgxJHhur9uIDUwLjA5JSoqDQoqICoqR2nDoSB0cuG7iyBwIChwLXZhbHVlKSoqID0gMC43NzcyID4gMC4wNQ0KDQpEbyBnacOhIHRy4buLIHAgbOG7m24gaMahbiBt4bupYyDDvSBuZ2jEqWEgNSUsICoqdGEga2jDtG5nIGLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCAkSF8wJCoqLiBOw7NpIGPDoWNoIGtow6FjLCAqKmtow7RuZyBjw7MgxJHhu6cgYuG6sW5nIGNo4bupbmcgdGjhu5FuZyBrw6oqKiDEkeG7gyBr4bq/dCBsdeG6rW4gcuG6sW5nICoqdOG7tyBs4buHIG7hu68gdHJvbmcgdOG7lW5nIHRo4buDIGtow6FjIGJp4buHdCDEkcOhbmcga+G7gyBzbyB24bubaSA1MCUqKi4NCg0KDQojIyMjIOKchSBL4bq/dCBsdeG6rW4NCg0KVOG7qyBr4bq/dCBxdeG6oyBwaMOibiB0w61jaCwgdGEgY8OzIHRo4buDIGvhur90IGx14bqtbiBy4bqxbmcgdOG7tyBs4buHIG7hu68gZ2nhu5tpIHRyb25nIG3huqt1IGThu68gbGnhu4d1IGzDoCAqKjQ5Ljk4JSoqLCB2w6Aga2jDtG5nIGPDsyBz4buxIGtow6FjIGJp4buHdCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIHNvIHbhu5tpIHThu7cgbOG7hyBnaeG6oyDEkeG7i25oIGzDoCAqKjUwJSoqLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBwaMOibiBi4buRIGdp4bubaSB0w61uaCB0cm9uZyBk4buvIGxp4buHdSBsw6Aga2jDoSBjw6JuIGLhurFuZy4NCg0KDQojIyAqKjIuMi4gVGjhu5FuZyBrw6ogbcO0IHThuqMgYmnhur9uIGBmYW1pbHlfaGlzdG9yeWAqKg0KDQpCaeG6v24gYGZhbWlseV9oaXN0b3J5YCBsw6AgbeG7mXQgYmnhur9uIMSR4buLbmggdMOtbmggbmjhu4sgcGjDom4gKGJpbmFyeSBjYXRlZ29yaWNhbCB2YXJpYWJsZSksIHBo4bqjbiDDoW5oIHZp4buHYyBi4buHbmggbmjDom4gY8OzIGhheSBraMO0bmcgdGnhu4FuIHPhu60gdW5nIHRoxrAgdHJvbmcgZ2lhIMSRw6xuaC4gxJDDonkgbMOgIHnhur91IHThu5EgcXVhbiB0cuG7jW5nIMSR4buDIMSRw6FuaCBnacOhIG5ndXkgY8ahIGRpIHRydXnhu4FuIHRyb25nIGPDoWMgYuG7h25oIGzDvSB1bmcgdGjGsCwgxJHhurdjIGJp4buHdCBsw6AgdW5nIHRoxrAgcGjhu5VpLiBQaMOibiB0w61jaCBiaeG6v24gbsOgeSBnacO6cCBsw6BtIHLDtSBt4buRaSBsacOqbiBo4buHIGdp4buvYSB54bq/dSB04buRIGdpYSDEkcOsbmggdsOgIHThu7cgbOG7hyBt4bqvYyBi4buHbmguDQoNCg0KIyMjICoqMi4yLjEuIFRo4buRbmcga8OqIHThuqduIHN14bqldCB2w6AgdOG7tyBs4buHIHBo4bqnbiB0csSDbSoqDQoNCmBgYHtyfQ0KIyBU4bqnbiBzdeG6pXQgdsOgIHThu7cgbOG7hyBwaOG6p24gdHLEg20NCmZoX2ZyZXEgPC0gdGFibGUoZGF0YSRmYW1pbHlfaGlzdG9yeSkNCmZoX3Byb3AgPC0gcHJvcC50YWJsZShmaF9mcmVxKSAqIDEwMA0KDQojIELhuqNuZyB0w7NtIHThuq90DQpmaF9zdW1tYXJ5IDwtIGRhdGEuZnJhbWUoDQogIEZhbWlseV9IaXN0b3J5ID0gbmFtZXMoZmhfZnJlcSksDQogIEZyZXF1ZW5jeSA9IGFzLnZlY3RvcihmaF9mcmVxKSwNCiAgUGVyY2VudGFnZSA9IHJvdW5kKGFzLnZlY3RvcihmaF9wcm9wKSwgMikNCikNCg0KZmhfc3VtbWFyeQ0KYGBgDQoNCj4gQ8OzIGtob+G6o25nIDQ5LDk4JSBi4buHbmggbmjDom4gdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UgY8OzIHRp4buBbiBz4butIHVuZyB0aMawIHRyb25nIGdpYSDEkcOsbmgsIHRyb25nIGtoaSA1MC4wMiUga2jDtG5nIGPDsy4gS+G6v3QgcXXhuqMgbsOgeSBjaG8gdGjhuqV5IHnhur91IHThu5EgZGkgdHJ1eeG7gW4gY8OzIHRo4buDIMSRw7NuZyB2YWkgdHLDsiBxdWFuIHRy4buNbmcgdHJvbmcgdOG7tyBs4buHIG3huq9jIGLhu4duaCB1bmcgdGjGsCBwaOG7lWksIHThu6sgxJHDsyBn4bujaSDDvSBoxrDhu5tuZyBuZ2hpw6puIGPhu6l1IHPDonUgaMahbiB24buBIHnhur91IHThu5EgZ2VuIHbDoCB0aeG7gW4gc+G7rSBnaWEgxJHDrG5oLg0KDQoNCiMjIyAqKjIuMi4yLiBCaeG7g3UgxJHhu5MgY+G7mXQgdGjhu4MgaGnhu4duIHBow6JuIGLhu5EgdGnhu4FuIHPhu60gdW5nIHRoxrAqKg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBDaHXhuqluIGLhu4sgZOG7ryBsaeG7h3UgdMOzbSB04bqvdA0KZmhfc3VtbWFyeSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRhdGEkZmFtaWx5X2hpc3RvcnkpKQ0KY29sbmFtZXMoZmhfc3VtbWFyeSkgPC0gYygiRmFtaWx5X0hpc3RvcnkiLCAiQ291bnQiKQ0KDQojIEJp4buDdSDEkeG7kyB24bubaSBuaMOjbiBz4buRIHRyw6puIGPhu5l0DQpnZ3Bsb3QoZmhfc3VtbWFyeSwgYWVzKHggPSBGYW1pbHlfSGlzdG9yeSwgeSA9IENvdW50KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjRkM4RDYyIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gQ291bnQpLCB2anVzdCA9IC0wLjUsIHNpemUgPSA0LjUpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBi4buRIHRp4buBbiBz4butIHVuZyB0aMawIHRyb25nIGdpYSDEkcOsbmgiLA0KICAgICAgIHggPSAiRmFtaWx5IEhpc3RvcnkiLCB5ID0gIlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCj4gQmnhu4N1IMSR4buTIHRy4buxYyBxdWFuIGdpw7pwIHRo4buDIGhp4buHbiByw7UgcsOgbmcgbeG7qWMgxJHhu5kgeHXhuqV0IGhp4buHbiBj4bunYSB54bq/dSB04buRIHRp4buBbiBz4butIGdpYSDEkcOsbmggdHJvbmcgbeG6q3UgbmdoacOqbiBj4bupdS4gVmnhu4djIGfhuq9uIG5ow6NuIHPhu5EgdHLDqm4gY+G7mXQgdMSDbmcgdMOtbmggZOG7hSDEkeG7jWMgdsOgIGjhu5cgdHLhu6Mgc28gc8OhbmggdOG7tyBs4buHIGdp4buvYSBoYWkgbmjDs20gYuG7h25oIG5ow6JuIG3hu5l0IGPDoWNoIG5oYW5oIGNow7NuZy4NCg0KIyMjICoqMi4yLjMuIMav4bubYyBsxrDhu6NuZyB2w6Aga2nhu4NtIMSR4buLbmggdOG7tyBs4buHIGPDsyB0aeG7gW4gc+G7rSBnaWEgxJHDrG5oKioNCg0KIyMjIyDwn5OMIE3hu6VjIHRpw6p1DQoNCk3hu6VjIHRpw6p1IGPhu6dhIHBow6JuIHTDrWNoIGzDoDoNCg0KKiAqKsav4bubYyBsxrDhu6NuZyB04bu3IGzhu4cqKiBuZ8aw4budaSBjw7MgdGnhu4FuIHPhu60gZ2lhIMSRw6xuaCBt4bqvYyBi4buHbmggKGJp4bq/biBgZmFtaWx5X2hpc3RvcnlgKQ0KKiAqKktp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90KiogeGVtIHThu7cgbOG7hyBuw6B5IGPDsyBraMOhYyBiaeG7h3QgxJHDoW5nIGvhu4Mgc28gduG7m2kgNTAlIGhheSBraMO0bmcNCg0KDQoNCiMjIyMg8J+TjCBQaMawxqFuZyBwaMOhcA0KDQpCaeG6v24gbmdoacOqbiBj4bupdSBsw6AgYGZhbWlseV9oaXN0b3J5YCB24bubaSAyIGdpw6EgdHLhu4s6IGAiWWVzImAgKGPDsyB0aeG7gW4gc+G7rSkgdsOgIGAiTm8iYCAoa2jDtG5nIGPDsykuDQoNCkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oIG5oxrAgc2F1Og0KDQokJA0KSF8wOiBwID0gMC41IFxxdWFkIFx0ZXh0eyhU4bu3IGzhu4cgbmfGsOG7nWkgY8OzIHRp4buBbiBz4butIGdpYSDEkcOsbmggbMOgIDUwXCUpfSBcXA0KSF8xOiBwIFxuZSAwLjUgXHF1YWQgXHRleHR7KFThu7cgbOG7hyBraMOhYyA1MFwlKX0NCiQkDQoNCg0KYGBge3J9DQojIMSQ4bq/bSBz4buRIG5nxrDhu51pIGPDsyBmYW1pbHkgaGlzdG9yeSB2w6AgdOG7lW5nIHPhu5ENCmZoX3llcyA8LSBzdW0oZGF0YSRmYW1pbHlfaGlzdG9yeSA9PSAiWWVzIiwgbmEucm0gPSBUUlVFKQ0KdG90YWxfZmggPC0gc3VtKGRhdGEkZmFtaWx5X2hpc3RvcnkgJWluJSBjKCJZZXMiLCAiTm8iKSwgbmEucm0gPSBUUlVFKQ0KDQojIFTDrW5oIHThu7cgbOG7hw0KcF9maCA8LSBmaF95ZXMgLyB0b3RhbF9maA0KDQojIEtp4buDbSDEkeG7i25oIHThu7cgbOG7hyBjw7MgYuG6sW5nIDAuNSBraMO0bmcNCnRlc3RfZmggPC0gcHJvcC50ZXN0KGZoX3llcywgdG90YWxfZmgsIHAgPSAwLjUsIGNvcnJlY3QgPSBUUlVFKQ0KDQojIEluIGvhur90IHF14bqjDQpjYXQoIlThu7cgbOG7hyBjw7MgdGnhu4FuIHPhu60gZ2lhIMSRw6xuaDoiLCByb3VuZChwX2ZoLCA0KSwgIlxuIikNCnByaW50KHRlc3RfZmgpDQpgYGANCg0KIyMjIyDwn5OMIEvhur90IHF14bqjIHBow6JuIHTDrWNoDQoNCiogKipU4buVbmcgc+G7kSBxdWFuIHPDoXQgaOG7o3AgbOG7hyoqOiA4OTAuMDAwIG5nxrDhu51pDQoqICoqU+G7kSBuZ8aw4budaSBjw7MgdGnhu4FuIHPhu60gZ2lhIMSRw6xuaCoqOiA0NDQuODE5IG5nxrDhu51pDQoqICoqVOG7tyBs4buHIG5nxrDhu51pIGPDsyB0aeG7gW4gc+G7rSBnaWEgxJHDrG5oICht4bqrdSk6KiogMC40OTk4ICh04bupYyA0OS45OCUpDQoNCg0KDQoNCiMjIyMg8J+UjSBEaeG7hW4gZ2nhuqNpIGvhur90IHF14bqjDQoNCiogKipLaG/huqNuZyB0aW4gY+G6rXkgOTUlKiogY2hvIHThu7cgbOG7hzogdOG7qyAqKjQ5Ljg4JSDEkeG6v24gNTAuMDglKioNCiogKipHacOhIHRy4buLIHAtdmFsdWUqKiA9IDAuNzAyID4gMC4wNQ0KDQrinqHvuI8gS2jDtG5nIGPDsyBi4bqxbmcgY2jhu6luZyB0aOG7kW5nIGvDqiDEkeG7gyBiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3QgJEhfMCQNCg0KDQojIyMjIOKchSBL4bq/dCBsdeG6rW4NCg0KS+G6v3QgcXXhuqMga2nhu4NtIMSR4buLbmggY2hvIHRo4bqleSAqKnThu7cgbOG7hyBuZ8aw4budaSBjw7MgdGnhu4FuIHPhu60gZ2lhIMSRw6xuaCBt4bqvYyBi4buHbmggbMOgIDQ5Ljk4JSoqLCB2w6AgKipraMO0bmcga2jDoWMgYmnhu4d0IMSRw6FuZyBr4buDKiogc28gduG7m2kgdOG7tyBs4buHIGdp4bqjIMSR4buLbmggNTAlLiBW4bubaSBwLXZhbHVlIGNhbyAoMC43MDIpLCBjw7MgdGjhu4Mga+G6v3QgbHXhuq1uIHLhurFuZyAqKnBow6JuIGLhu5EgYmnhur9uIGBmYW1pbHlfaGlzdG9yeWAgbMOgIGPDom4gYuG6sW5nKiogdHJvbmcgZOG7ryBsaeG7h3UsIGtow7RuZyBuZ2hpw6puZyB24buBIHBow61hIG7DoG8uDQoNCg0KIyAqKjMuIFRo4buRbmcga8OqIHN1eSBkaeG7hW4qKg0KDQojIyAqKjMuMS4gUGjDom4gdMOtY2ggbeG7kWkgbGnDqm4gaOG7hyBnaeG7r2EgYGdlbmRlcmAgdsOgIGBhc3RobWFgKioNCg0KQmnhur9uIGBnZW5kZXJgIGJp4buDdSB0aOG7iyBnaeG7m2kgdMOtbmggc2luaCBo4buNYyBj4bunYSBi4buHbmggbmjDom4gKCpNYWxlL0ZlbWFsZSopLCBjw7JuIGJp4bq/biBgYXN0aG1hYCBwaOG6o24gw6FuaCB0w6xuaCB0cuG6oW5nIGPDsyBob+G6t2Mga2jDtG5nIGPDsyBoZW4gc3V54buFbiAoKjA6IEtow7RuZyosICoxOiBDw7MqKS4gQ+G6oyBoYWkgbMOgIGJp4bq/biDEkeG7i25oIHTDrW5oIG5o4buLIHBow6JuLiBN4bulYyB0acOqdSBsw6Aga2nhu4NtIHRyYSB4ZW0gZ2nhu5tpIHTDrW5oIGPDsyBsacOqbiBxdWFuIMSR4bq/biB0w6xuaCB0cuG6oW5nIGhlbiBzdXnhu4VuIGhheSBraMO0bmcuDQoNCiMjIyAqKjMuMS4xLiBC4bqjbmcgY2jDqW8gdOG6p24gc3XhuqV0KioNCg0KYGBge3J9DQp0YWJfZ2VuZGVyX2FzdGhtYSA8LSB0YWJsZShkYXRhJGdlbmRlciwgZGF0YSRhc3RobWEpDQphZGRtYXJnaW5zKHRhYl9nZW5kZXJfYXN0aG1hKQ0KYGBgDQoqKkLhuqNuZyBjaMOpbyB2w6AgdGjhu5FuZyBrw6ogbcO0IHThuqM6KioNCg0KfCAgICAgICAgICB8IEFzdGhtYSA9IDAgfCBBc3RobWEgPSAxIHwgVOG7lW5nIGPhu5luZyB8DQp8IC0tLS0tLS0tIHwgLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0gfCAtLS0tLS0tLS0gfA0KfCBGZW1hbGUgICB8IDIzNiwxNDggICAgfCAyMDgsNzE4ICAgIHwgNDQ0LDg2NiAgIHwNCnwgTWFsZSAgICAgfCAyMzUsNzgzICAgIHwgMjA5LDM1MSAgICB8IDQ0NSwxMzQgICB8DQp8ICoqVOG7lW5nKiogfCA0NzEsOTMxICAgIHwgNDE4LDA2OSAgICB8IDg5MCwwMDAgICB8DQoNClThu7cgbOG7hyBt4bqvYyBoZW4gc3V54buFbiB0cm9uZyBuaMOzbSBu4buvIGzDoCAqKjQ2LjkyJSoqLCB0cm9uZyBraGkg4bufIG5hbSBsw6AgKio0Ny4wMyUqKi4NCg0KDQojIyMgKiozLjEuMi4gS2nhu4NtIMSR4buLbmggQ2hpLXNxdWFyZWQqKg0KDQpgYGB7cn0NCmNoaXNxLnRlc3QodGFiX2dlbmRlcl9hc3RobWEpDQpgYGANCg0KKipLaeG7g20gxJHhu4tuaCBDaGktc3F1YXJlZDoqKg0KDQoqICoqQ2hpLXNxdWFyZWQgPSAxLjE2KiosIGRmID0gMQ0KKiAqKnAtdmFsdWUgPSAwLjI4MjQqKiAoa2jDtG5nIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6og4bufIG3hu6ljIDUlKQ0KDQrin7YgS2jDtG5nIGPDsyBi4bqxbmcgY2jhu6luZyB0aOG7kW5nIGvDqiDEkeG7gyBr4bq/dCBsdeG6rW4gcuG6sW5nIHThu7cgbOG7hyBoZW4gc3V54buFbiBraMOhYyBiaeG7h3QgZ2nhu69hIG5hbSB2w6AgbuG7ry4NCg0KDQojIyMgKiozLjEuMy4gxq/hu5tjIGzGsOG7o25nIE9kZHMgUmF0aW8gdsOgIFJlbGF0aXZlIFJpc2sqKg0KDQpgYGB7cn0NCmxpYnJhcnkoZXBpdG9vbHMpDQpvZGRzcmF0aW8odGFiX2dlbmRlcl9hc3RobWEsIHJldiA9ICJjIikNCnJpc2tyYXRpbyh0YWJfZ2VuZGVyX2FzdGhtYSwgcmV2ID0gImMiKQ0KDQojIEhp4buDbiB0aOG7iyBjaGkgdGnhur90DQplcGl0YWIodGFiX2dlbmRlcl9hc3RobWEsIG1ldGhvZCA9ICJvZGRzcmF0aW8iLCByZXYgPSAiYyIpDQplcGl0YWIodGFiX2dlbmRlcl9hc3RobWEsIG1ldGhvZCA9ICJyaXNrcmF0aW8iLCByZXYgPSAiYyIpDQpgYGANCg0KDQoqICoqw50gbmdoxKlhKio6IE9SIMSRbyBsxrDhu51uZyB04bu3IGzhu4cgY2jDqm5oIGzhu4djaCBvZGRzIG3huq9jIGhlbiBzdXnhu4VuIGdp4buvYSBuYW0gdsOgIG7hu68uDQoNCj4gLSBPUiAoTWFsZSB2cyBGZW1hbGUpOiAqKjAuOTk1NCoqDQo+IC0gQ0kgOTUlOiAqKlxbMC45ODcyIDsgMS4wMDM4XSoqDQo+IC0gcC12YWx1ZSDiiYggKiowLjI4MSoqDQoNCkRp4buFbiBnaeG6o2k6DQoNCiogT1IgPSAwLjk5NTQgbmdoxKlhIGzDoCAqKm5hbSBnaeG7m2kgY8OzIG9kZHMgbeG6r2MgaGVuIHN1eeG7hW4gdGjhuqVwIGjGoW4gbuG7ryBt4buZdCBjaMO6dCAoMC45OTUgbOG6p24pKiosIG5oxrBuZyBz4buxIGtow6FjIGJp4buHdCAqKnLhuqV0IG5o4buPKiouDQoqIEtob+G6o25nIHRpbiBj4bqteSA5NSUgKENJKSBjaOG7qWEgZ2nDoSB0cuG7iyAxIOKGkiAqKmtow7RuZyBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqKiouDQoqIHAtdmFsdWUgPSAwLjI4MSAoPiAwLjA1KSDihpIga2jDtG5nIGPDsyBi4bqxbmcgY2jhu6luZyDEkeG7gyBiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3QgSOKCgCAoZ2nhu5tpIHTDrW5oIGtow7RuZyDhuqNuaCBoxrDhu59uZyDEkeG6v24ga2jhuqMgbsSDbmcgbeG6r2MgaGVuIHN1eeG7hW4pLg0KDQoNCiogKirDnSBuZ2jEqWEqKjogUlIgc28gc8OhbmggdOG7tyBs4buHIG3huq9jIGhlbiBzdXnhu4VuIGdp4buvYSBuYW0gdsOgIG7hu68gKHJpc2sgdGjhu7FjIHThur8pLg0KDQo+IC0gUlIgKE1hbGUgdnMgRmVtYWxlKTogKiowLjk5NzkqKg0KPiAtIENJIDk1JTogKipcWzAuOTkzOSA7IDEuMDAxOF0qKg0KDQpEaeG7hW4gZ2nhuqNpOg0KDQoqIFJSID0gMC45OTc5IOKGkiAqKm5hbSBnaeG7m2kgY8OzIG5ndXkgY8ahIG3huq9jIGhlbiBzdXnhu4VuIHRo4bqlcCBoxqFuIG7hu68ga2hv4bqjbmcgMC4yMSUqKiwgdOG7qWMgZ+G6p24gbmjGsCBraMO0bmcgY8OzIGtow6FjIGJp4buHdC4NCiogS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjxaluZyBjaOG7qWEgZ2nDoSB0cuG7iyAxIOKGkiAqKmtow7RuZyBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqKiouDQoNCg0KIyMgKiozLjIuIFBow6JuIHTDrWNoIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGBmYW1pbHlfaGlzdG9yeWAgdsOgIGBjaXJyaG9zaXNgKioNCg0KQmnhur9uIGBmYW1pbHlfaGlzdG9yeWAgdGjhu4MgaGnhu4duIHZp4buHYyBi4buHbmggbmjDom4gY8OzIGhheSBraMO0bmcgdGnhu4FuIHPhu60gdW5nIHRoxrAgdHJvbmcgZ2lhIMSRw6xuaCAoKlllcy9ObyopLCBjw7JuIGJp4bq/biBgY2lycmhvc2lzYCBwaOG6o24gw6FuaCB0w6xuaCB0cuG6oW5nIHjGoSBnYW4gKCowOiBLaMO0bmcqLCAqMTogQ8OzKikuIFBow6JuIHTDrWNoIG5o4bqxbSBraeG7g20gdHJhIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGhhaSBiaeG6v24gbsOgeS4NCg0KIyMjICoqMy4yLjEuIELhuqNuZyBjaMOpbyB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCnRhYl9maF9jaXJyaG9zaXMgPC0gdGFibGUoZGF0YSRmYW1pbHlfaGlzdG9yeSwgZGF0YSRjaXJyaG9zaXMpDQphZGRtYXJnaW5zKHRhYl9maF9jaXJyaG9zaXMpDQpgYGANCg0KKipC4bqjbmcgY2jDqW8gdsOgIHRo4buRbmcga8OqIG3DtCB04bqjOioqDQoNCnwgICAgICAgICAgICAgICB8IENpcnJob3NpcyA9IDAgfCBDaXJyaG9zaXMgPSAxIHwgVOG7lW5nIGPhu5luZyB8DQp8IC0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLSB8DQp8IEtow7RuZyB0aeG7gW4gc+G7rSB8IDM0NSwwNTQgICAgICAgfCAxMDAsMTI3ICAgICAgIHwgNDQ1LDE4MSAgIHwNCnwgQ8OzIHRp4buBbiBz4butICAgIHwgMzQzLDg0NSAgICAgICB8IDEwMCw5NzQgICAgICAgfCA0NDQsODE5ICAgfA0KfCAqKlThu5VuZyoqICAgICAgfCA2ODgsODk5ICAgICAgIHwgMjAxLDEwMSAgICAgICB8IDg5MCwwMDAgICB8DQoNClThu7cgbOG7hyB4xqEgZ2FuIHRyb25nIG5ow7NtIGPDsyB0aeG7gW4gc+G7rSBnaWEgxJHDrG5oIGzDoCAqKjIyLjcwJSoqLCBjYW8gaMahbiBzbyB24bubaSBuaMOzbSBraMO0bmcgY8OzIHRp4buBbiBz4butICgqKjIyLjQ5JSoqKS4NCg0KIyMjICoqMy4yLjIuIEtp4buDbSDEkeG7i25oIENoaS1zcXVhcmVkKioNCg0KYGBge3J9DQpjaGlzcS50ZXN0KHRhYl9maF9jaXJyaG9zaXMpDQpgYGANCg0KKipLaeG7g20gxJHhu4tuaCBDaGktc3F1YXJlZDoqKg0KDQoqICoqQ2hpLXNxdWFyZWQgPSA1LjUzKiosIGRmID0gMQ0KKiAqKnAtdmFsdWUgPSAwLjAxODcqKiAoY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiDhu58gbeG7qWMgNSUpDQoNCuKftiBDw7Mgc+G7sSBraMOhYyBiaeG7h3QgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiB0cm9uZyB04bu3IGzhu4cgeMahIGdhbiBnaeG7r2EgbmjDs20gY8OzIHbDoCBraMO0bmcgY8OzIHRp4buBbiBz4butIGdpYSDEkcOsbmguDQoNCg0KIyMjICoqMy4yLjMuIMav4bubYyBsxrDhu6NuZyBPZGRzIFJhdGlvIHbDoCBSZWxhdGl2ZSBSaXNrKioNCg0KYGBge3J9DQpvZGRzcmF0aW8odGFiX2ZoX2NpcnJob3NpcywgcmV2ID0gImMiKQ0Kcmlza3JhdGlvKHRhYl9maF9jaXJyaG9zaXMsIHJldiA9ICJjIikNCg0KIyBIaeG7g24gdGjhu4sgY2hpIHRp4bq/dA0KZXBpdGFiKHRhYl9maF9jaXJyaG9zaXMsIG1ldGhvZCA9ICJvZGRzcmF0aW8iLCByZXYgPSAiYyIpDQplcGl0YWIodGFiX2ZoX2NpcnJob3NpcywgbWV0aG9kID0gInJpc2tyYXRpbyIsIHJldiA9ICJjIikNCmBgYA0KDQoNCj4gKipPUiA9IDAuOTg4MSoqDQo+ICoqOTUlIENJOiBcWzAuOTc4NCA7IDAuOTk4MF0qKg0KPiAqKnAtdmFsdWUgPSAwLjAxODcqKg0KDQoNCiogT1IgPSAqKjAuOTg4MSoqIG5naMSpYSBsw6AgKipi4buHbmggbmjDom4gY8OzIHRp4buBbiBz4butIHVuZyB0aMawIGdpYSDEkcOsbmggY8OzIG9kZHMgbeG6r2MgeMahIGdhbiB0aOG6pXAgaMahbiBuaMOzbSBraMO0bmcgY8OzIHRp4buBbiBz4butIGtob+G6o25nIDEuMTklKiouDQoqIEtob+G6o25nIHRpbiBj4bqteSA5NSUgKipraMO0bmcgY2jhu6lhIDEqKiwgcC12YWx1ZSA8IDAuMDUg4oaSICoqa2jDoWMgYmnhu4d0IGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6oqKi4NCiogKipL4bq/dCBsdeG6rW4qKjogQ8OzIG3hu5FpIGxpw6puIGjhu4cgbmjhurkgbmjGsG5nICoqY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqioqIGdp4buvYSB0aeG7gW4gc+G7rSBnaWEgxJHDrG5oIHbDoCB4xqEgZ2FuLiBUdXkgbmhpw6puLCBt4bupYyDEkeG7mSDhuqNuaCBoxrDhu59uZyBsw6AgKipy4bqldCBuaOG7jyoqLg0KDQo+ICoqUlIgPSAwLjk5NzMqKg0KPiAqKjk1JSBDSTogXFswLjk5NTEgOyAwLjk5OTVdKioNCg0KRGnhu4VuIGdp4bqjaSBSUjoNCg0KKiBSUiA9ICoqMC45OTczKiogbmdoxKlhIGzDoCAqKm5ndXkgY8ahIG3huq9jIHjGoSBnYW4g4bufIG5ow7NtIGPDsyB0aeG7gW4gc+G7rSB1bmcgdGjGsCBnaWEgxJHDrG5oIHRo4bqlcCBoxqFuIDAuMjclKiogc28gduG7m2kgbmjDs20ga2jDtG5nIGPDsyB0aeG7gW4gc+G7rS4NCiogQ0kga2jDtG5nIGNo4bupYSAxIOKGkiAqKmtow6FjIGJp4buHdCBuaOG7jyBuaMawbmcgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqioqLg0KKiBUxrDGoW5nIHThu7EgT1IsIFJSIGNobyB0aOG6pXkg4bqjbmggaMaw4bufbmcgbmjhu48gbmjGsG5nIMSRw6FuZyBr4buDLg0KDQoNCiMjIyDDnSB0xrDhu59uZyBjaHVuZyBj4bunYSBNTEUgbMOgIGfDrD8NCg0KVHJvbmcgdGjhu5FuZyBrw6osIGtoaSBi4bqhbiBjw7MgZOG7ryBsaeG7h3UgdsOgIG114buRbiAqKnTDrG0gcmEgY8OhYyB0aGFtIHPhu5EgdOG7kXQgbmjhuqV0KiogKG5oxrAgdHJ1bmcgYsOsbmgsIHBoxrDGoW5nIHNhaS4uLikgxJHhu4MgbcO0IHThuqMgZOG7ryBsaeG7h3UgxJHDsywgdGjDrCAqKk1MRSBsw6AgbeG7mXQgdHJvbmcgbmjhu69uZyBjw6FjaCBwaOG7lSBiaeG6v24gbmjhuqV0IMSR4buDIGzDoG0gxJFp4buBdSBuw6B5KiouDQoNCj4g4p2TICoqQ8OidSBo4buPaSDEkeG6t3QgcmE6KiogQmnhur90IGThu68gbGnhu4d1IHLhu5NpLCBsw6BtIHNhbyAibmfGsOG7o2MgbOG6oWkiIMSR4buDIHTDrG0gxJHGsOG7o2MgY8OhYyB0aGFtIHPhu5EgbcO0IHThuqMgdOG7kXQgbmjhuqV0IGNobyBwaMOibiBwaOG7kWkgdOG6oW8gcmEgZOG7ryBsaeG7h3UgxJHDsz8NCg0K4p6hIMSQw7MgY2jDrW5oIGzDoCBt4bulYyB0acOqdSBj4bunYSBNTEU6ICoqVMOsbSBi4buZIHRoYW0gc+G7kSBsw6BtIGNobyBk4buvIGxp4buHdSDEkWFuZyBjw7MgbMOgICJo4bujcCBsw70gbmjhuqV0IiBkxrDhu5tpIHBow6JuIHBo4buRaSBnaeG6oyDEkeG7i25oLioqDQoNCg0KDQojIyMgSMOgbSBo4bujcCBsw70gKExpa2VsaWhvb2QgZnVuY3Rpb24pIGzDoCBnw6w/DQoNCsSQ4buDIHTDrG0gdGhhbSBz4buRICJ04buRdCBuaOG6pXQiLCB0YSBj4bqnbiBt4buZdCBjw7RuZyBj4bulIMSRbyBsxrDhu51uZyDigJMgxJHDsyBsw6AgKipow6BtIGjhu6NwIGzDvSoqLg0KDQpHaeG6oyBz4butIGLhuqFuIGPDszoNCg0KKiBN4buZdCBi4buZIGThu68gbGnhu4d1IGfhu5NtICRuJCBxdWFuIHPDoXQ6ICR4XzEsIHhfMiwgLi4uLCB4X24kDQoqIEJp4bq/dCBk4buvIGxp4buHdSB0dcOibiB0aGVvIG3hu5l0IHBow6JuIHBo4buRaSBuw6BvIMSRw7MsIHbDrSBk4bulOiAqKnBow6JuIHBo4buRaSBjaHXhuqluKiogaG/hurdjICoqcGjDom4gcGjhu5FpIFBvaXNzb24qKiwgduG7m2kgbeG7mXQgc+G7kSAqKnRoYW0gc+G7kSBjaMawYSBiaeG6v3QqKiwga8O9IGhp4buHdSBsw6AgJFx0aGV0YSQNCg0KKipIw6BtIGjhu6NwIGzDvSoqICRMKFx0aGV0YSkkIGzDoCB0w61jaCBj4bunYSB04bqldCBj4bqjIGPDoWMgeMOhYyBzdeG6pXQgKGhv4bq3YyBt4bqtdCDEkeG7mSB4w6FjIHN14bqldCkgY+G7p2EgdOG7q25nIMSRaeG7g20gZOG7ryBsaeG7h3UgJHhfaSQgZMaw4bubaSB0aGFtIHPhu5EgJFx0aGV0YSQuDQpO4bq/dSBk4buvIGxp4buHdSBsw6AgxJHhu5ljIGzhuq1wIHbDoCBwaMOibiBwaOG7kWkgZ2nhu5FuZyBuaGF1IChpLmkuZCksIHRow6w6DQoNCiQkDQpMKFx0aGV0YSkgPSBQKHhfMSwgeF8yLCAuLi4sIHhfbiB8IFx0aGV0YSkgPSBccHJvZF97aT0xfV57bn0gZih4X2l8XHRoZXRhKQ0KJCQNCg0KPiDinIUgTeG7pWMgdGnDqnUgbMOgOiAqKlTDrG0gZ2nDoSB0cuG7iyBj4bunYSAkXHRoZXRhJCoqIHNhbyBjaG8gaMOgbSAkTChcdGhldGEpJCBsw6AgKips4bubbiBuaOG6pXQqKi4NCg0KDQojIyMgVsOsIHNhbyBkw7luZyBsb2ctbGlrZWxpaG9vZD8NCg0KVMOtY2ggY+G7p2Egbmhp4buBdSB4w6FjIHN14bqldCBuaOG7jyBz4bq9IHJhIG3hu5l0IHPhu5EgcuG6pXQgYsOpLCBk4buFIGfDonkgc2FpIHPhu5EgdMOtbmggdG/DoW4uIMSQ4buDIMSRxqFuIGdp4bqjbiBoxqFuLCB0YSAqKmzhuqV5IGxvZyoqIGPhuqMgaGFpIHbhur8gKGxvZyBj4bunYSB0w61jaCB0aMOgbmggdOG7lW5nKToNCg0KJCQNClxsb2cgTChcdGhldGEpID0gXHN1bV97aT0xfV57bn0gXGxvZyBmKHhfaXxcdGhldGEpDQokJA0KDQpIw6BtIG3hu5tpIG7DoHkgZ+G7jWkgbMOgICoqbG9nLWxpa2VsaWhvb2QqKiwga8O9IGhp4buHdSAkXGVsbChcdGhldGEpJCwgdsOgIGPDsyBjw7luZyDEkWnhu4NtIGPhu7FjIMSR4bqhaSB24bubaSAkTChcdGhldGEpJC4NCg0KPiDinIUgQsOgaSB0b8OhbiB0cuG7nyB0aMOgbmg6ICoqVMOsbSAkXHRoZXRhJCBzYW8gY2hvICRcZWxsKFx0aGV0YSkkIGzDoCBs4bubbiBuaOG6pXQqKg0KDQoNCiMjIyBWw60gZOG7pSBj4bulIHRo4buDOiDGr+G7m2MgbMaw4bujbmcgdHJ1bmcgYsOsbmggY8OibiBu4bq3bmcgbmfGsOG7nWkgdHLGsOG7n25nIHRow6BuaA0KDQojIyMjIEdp4bqjIHPhu606DQoNCiogQ8OibiBu4bq3bmcgbmfGsOG7nWkgdHLGsOG7n25nIHRow6BuaCB0dcOibiB0aGVvIHBow6JuIHBo4buRaSBjaHXhuqluICROKFxtdSwgXHNpZ21hXjIpJA0KKiBUYSDEkW8gxJHGsOG7o2MgbeG7mXQgbeG6q3UgZ+G7k20gJG4kIG5nxrDhu51pIHbhu5tpIGPDom4gbuG6t25nICR4XzEsIHhfMiwgLi4uLCB4X24kDQoNCiMjIyMgQsaw4bubYyAxOiBWaeG6v3QgaMOgbSBt4bqtdCDEkeG7mSB4w6FjIHN14bqldA0KDQokJA0KZih4X2l8XG11LCBcc2lnbWFeMikgPSBcZnJhY3sxfXtcc3FydHsyXHBpXHNpZ21hXjJ9fSBcZXhwXGxlZnQoLVxmcmFjeyh4X2kgLSBcbXUpXjJ9ezJcc2lnbWFeMn1ccmlnaHQpDQokJA0KDQojIyMjIELGsOG7m2MgMjogVmnhur90IGjDoG0gaOG7o3AgbMO9DQoNCiQkDQpMKFxtdSwgXHNpZ21hXjIpID0gXHByb2Rfe2k9MX1ee259IGYoeF9pfFxtdSwgXHNpZ21hXjIpDQokJA0KDQojIyMjIELGsOG7m2MgMzogTOG6pXkgbG9nIHbDoCDEkcahbiBnaeG6o24gaG/DoQ0KDQokJA0KXGxvZyBMKFxtdSwgXHNpZ21hXjIpID0gLVxmcmFje259ezJ9IFxsb2coMlxwaSkgLSBcZnJhY3tufXsyfSBcbG9nKFxzaWdtYV4yKSAtIFxmcmFjezF9ezJcc2lnbWFeMn0gXHN1bV97aT0xfV57bn0oeF9pIC0gXG11KV4yDQokJA0KDQojIyMjIELGsOG7m2MgNDogVMOtbmggxJHhuqFvIGjDoG0gdsOgIGdp4bqjaSBwaMawxqFuZyB0csOsbmggxJHhuqFvIGjDoG0gPSAwDQoNCkdp4bqjaSBwaMawxqFuZyB0csOsbmggxJHhuqFvIGjDoG0gdGhlbyAkXG11JCwgdGEgc+G6vSB0aHUgxJHGsOG7o2M6DQoNCiQkDQpcaGF0e1xtdX0gPSBcZnJhY3sxfXtufSBcc3VtX3tpPTF9XntufSB4X2kgXHF1YWQgXHRleHR7KHRydW5nIGLDrG5oIG3huqt1KX0NCiQkDQoNCkdp4bqjaSB0aeG6v3AgdGhlbyAkXHNpZ21hXjIkLCB0YSBjw7M6DQoNCiQkDQpcaGF0e1xzaWdtYX1eMiA9IFxmcmFjezF9e259IFxzdW1fe2k9MX1ee259KHhfaSAtIFxoYXR7XG11fSleMiBccXVhZCBcdGV4dHsocGjGsMahbmcgc2FpIG3huqt1IGtow7RuZyDEkWnhu4F1IGNo4buJbmgpfQ0KJCQNCg0KPiDinIUgS+G6v3QgbHXhuq1uOiAqKsav4bubYyBsxrDhu6NuZyBo4bujcCBsw70gdOG7kWkgxJFhIGNobyB0cnVuZyBiw6xuaCB2w6AgcGjGsMahbmcgc2FpIGNow61uaCBsw6AgdHJ1bmcgYsOsbmggdsOgIHBoxrDGoW5nIHNhaSBt4bqrdSEqKg0KDQoNCg0KIyMjIFThu5VuZyBr4bq/dCBuZ+G6r24gZ+G7jW4NCg0KfCBO4buZaSBkdW5nICAgICAgICAgICB8IEdp4bqjaSB0aMOtY2ggbmfhuq9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IC0tLS0tLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfA0KfCAqKk1MRSBsw6AgZ8OsPyoqICAgICB8IEzDoCBwaMawxqFuZyBwaMOhcCB0w6xtIHRoYW0gc+G7kSDEkeG7gyBsw6BtIGNobyBk4buvIGxp4buHdSDEkcOjIHF1YW4gc8OhdCBsw6AgImjhu6NwIGzDvSBuaOG6pXQiIGTGsOG7m2kgbeG7mXQgcGjDom4gcGjhu5FpIGdp4bqjIMSR4buLbmguIHwNCnwgKipIw6BtIGjhu6NwIGzDvSoqICAgICB8IFjDoWMgc3XhuqV0IChob+G6t2MgbeG6rXQgxJHhu5kpIGPhu6dhIHRvw6BuIGLhu5kgZOG7ryBsaeG7h3UsIGJp4buDdSBkaeG7hW4gdGhlbyB0aGFtIHPhu5EgY+G6p24gxrDhu5tjIGzGsOG7o25nLiAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKkxvZy1saWtlbGlob29kKiogfCBMb2cgY+G7p2EgaMOgbSBo4bujcCBsw70sIGdpw7pwIMSRxqFuIGdp4bqjbiBow7NhIHF1w6EgdHLDrG5oIHTDrW5oIHRvw6FuLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqxq/hu5tjIGzGsOG7o25nIE1MRSoqICB8IEzDoCBuZ2hp4buHbSBj4bunYSBiw6BpIHRvw6FuIGPhu7FjIHRy4buLICh04buRaSDEkWEgaMOzYSBsb2ctbGlrZWxpaG9vZCkuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKuG7qG5nIGThu6VuZyoqICAgICAgIHwgRMO5bmcgxJHhu4MgxrDhu5tjIGzGsOG7o25nIHRydW5nIGLDrG5oLCBwaMawxqFuZyBzYWksIHThu7cgbOG7hywuLi4gdHJvbmcgbmhp4buBdSBtw7QgaMOsbmggcGjDom4gcGjhu5FpIGtow6FjIG5oYXUuICAgICAgICAgICAgfA0KDQoNCiMgNDogTMO9IHRodXnhur90IHbhu4EgaOG7k2kgcXV5IGxvZ2lzdGljIA0KDQojIyAgNC4xLiBI4buTaSBxdXkgbG9naXN0aWMgbMOgIGfDrD8NCg0KKipI4buTaSBxdXkgbG9naXN0aWMqKiBsw6AgbeG7mXQgcGjGsMahbmcgcGjDoXAgdGjhu5FuZyBrw6ogxJHGsOG7o2MgZMO5bmcgxJHhu4MgKipk4buxIMSRb8OhbiBraOG6oyBuxINuZyB44bqjeSByYSBj4bunYSBt4buZdCBz4buxIGtp4buHbioqIGtoaSBiaeG6v24ga+G6v3QgcXXhuqMgbMOgICoqbmjhu4sgcGjDom4qKiAodOG7qWMgbMOgIGNo4buJIGPDsyAyIGdpw6EgdHLhu4s6IHbDrSBk4bulIG5oxrAgKipT4buRbmcgaGF5IENo4bq/dCoqLCAqKkPDsyBi4buHbmggaGF5IEtow7RuZyBi4buHbmgqKiwgKirEkOG6rXUgaGF5IFLhu5t0KiouLi4pLg0KDQpWw60gZOG7pSANCg0KR2nhuqMgc+G7rSBi4bqhbiBtdeG7kW4gZOG7sSDEkW/DoW4geGVtIG3hu5l0IG5nxrDhu51pIGPDsyBz4buRbmcgc8OzdCAoc3Vydml2ZWQgPSAxKSBoYXkga2jDtG5nIChzdXJ2aXZlZCA9IDApLCBk4buxYSB2w6BvICoqdMOsbmggdHLhuqFuZyBow7p0IHRodeG7kWMqKiAoc21va2luZyBzdGF0dXMpLg0KDQojIyA0LjIuIFThuqFpIHNhbyBraMO0bmcgZMO5bmcgaOG7k2kgcXV5IHR1eeG6v24gdMOtbmg/DQoNCiogSOG7k2kgcXV5IHR1eeG6v24gdMOtbmggY2hvIGvhur90IHF14bqjIMSR4bqndSByYSBsw6AgKipt4buZdCBjb24gc+G7kSBi4bqldCBr4buzKiosIGPDsyB0aOG7gyBs4bubbiBoxqFuIDEgaG/hurdjIG5o4buPIGjGoW4gMC4NCiogTmjGsG5nIHRyb25nIGLDoGkgdG/DoW4ga2nhu4N1ICoqIkPDsyIgaG/hurdjICJLaMO0bmciKiosIHRhIGPhuqduIMSR4bqndSByYSBsw6AgKip4w6FjIHN14bqldCAoMCDEkeG6v24gMSkqKi4NCg0KRG8gxJHDsywgaOG7k2kgcXV5IGxvZ2lzdGljIGTDuW5nIGjDoG0gKipsb2dpc3RpYyoqIMSR4buDIGJp4bq/biDEkeG6p3UgcmEgbHXDtG4gbuG6sW0gdHJvbmcga2hv4bqjbmcgKiooMCwgMSkqKiwgYmnhu4N1IGRp4buFbiAqKnjDoWMgc3XhuqV0IHjhuqN5IHJhIHPhu7Ega2nhu4duKiouDQoNCg0KIyMgNC4zLiBNw7QgaMOsbmggaOG7k2kgcXV5IGxvZ2lzdGljIGPGoSBi4bqjbiAoxJHGoW4gYmnhur9uKQ0KDQoqKk3DtCBow6xuaCoqOg0KDQpgYGBtYXRoDQpsb2dpdChwKSA9IGxuKHAgLyAoMSAtIHApKSA9IM6y4oKAICsgzrLigoEgw5cgWA0KYGBgDQoNClRyb25nIMSRw7M6DQoNCiogYHBgIGzDoCB4w6FjIHN14bqldCBz4buxIGtp4buHbiB44bqjeSByYSAodsOtIGThu6U6IHPhu5FuZyBzw7N0KQ0KKiBgWGAgbMOgIGJp4bq/biDEkeG7mWMgbOG6rXAgKHbDrSBk4bulOiB0w6xuaCB0cuG6oW5nIGjDunQgdGh14buRYykNCiogYM6y4oKAYCB2w6AgYM6y4oKBYCBsw6AgaOG7hyBz4buRIGjhu5NpIHF1eQ0KKiBgbG9naXQocClgIGzDoCBsb2ctb2RkcyAobG9nIGPhu6dhIHThu7cgc+G7kSBnaeG7r2EgeMOhYyBzdeG6pXQgeOG6o3kgcmEgdsOgIGtow7RuZyB44bqjeSByYSkNCg0KDQojIyA0LjQuIERp4buFbiBnaeG6o2kga+G6v3QgcXXhuqMNCg0KS2hpIGLhuqFuIMaw4bubYyBsxrDhu6NuZyBtw7QgaMOsbmgsIGLhuqFuIHPhur0gbmjhuq1uIMSRxrDhu6NjIGjhu4cgc+G7kSDOsuKCgToNCg0KKiBO4bq/dSDOsuKCgSA+IDAg4oaSIGJp4bq/biBYICoqdMSDbmcgeMOhYyBzdeG6pXQqKiB44bqjeSByYSBz4buxIGtp4buHbg0KKiBO4bq/dSDOsuKCgSA8IDAg4oaSIGJp4bq/biBYICoqZ2nhuqNtIHjDoWMgc3XhuqV0KioNCiogTuG6v3UgKipwLXZhbHVlIDwgMC4wNSoqIOKGkiBxdWFuIGjhu4cgbsOgeSBsw6AgKipjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqKioNCg0KDQojIDU6IFBow6JuIHTDrWNoIG3DtCBow6xuaCBo4buTaSBxdXkgbG9naXN0aWMgduG7m2kgZOG7ryBsaeG7h3UgYGRhdGFzZXRfbWVkLmNzdmANCg0KIyMgNS4xLiBQaMOibiB0w61jaCBtw7QgaMOsbmggaOG7k2kgcXV5IGxvZ2lzdGljIMSRxqFuIGJp4bq/bg0KDQpgYGB7cn0NCiMgQ2h1eeG7g24gxJHhu5VpIGJp4bq/bg0KZGF0YSRnZW5kZXIgPC0gZmFjdG9yKGRhdGEkZ2VuZGVyKQ0KZGF0YSRzbW9raW5nX3N0YXR1cyA8LSBmYWN0b3IoZGF0YSRzbW9raW5nX3N0YXR1cykNCmRhdGEkY2FuY2VyX3N0YWdlIDwtIGZhY3RvcihkYXRhJGNhbmNlcl9zdGFnZSwgb3JkZXJlZCA9IFRSVUUsIGxldmVscyA9IGMoIkkiLCAiSUkiLCAiSUlJIiwgIklWIikpDQpkYXRhJHRyZWF0bWVudF90eXBlIDwtIGZhY3RvcihkYXRhJHRyZWF0bWVudF90eXBlKQ0KZGF0YSRzdXJ2aXZlZCA8LSBmYWN0b3IoZGF0YSRzdXJ2aXZlZCkgICMgWeG6v3UgdOG7kSBuaOG7iyBwaMOibg0KDQpgYGANCg0KYGBge3J9DQojIEjhu5NpIHF1eSDEkcahbiBiaeG6v246IHR14buVaQ0KbW9kZWxfYWdlIDwtIGdsbShzdXJ2aXZlZCB+IGFnZSwgZGF0YSA9IGRhdGEsIGZhbWlseSA9IGJpbm9taWFsKQ0Kc3VtbWFyeShtb2RlbF9hZ2UpDQpgYGANCg0KKiBI4buHIHPhu5EgZMawxqFuZyAoMC4wMDAyOTc4KSBjaG8gdGjhuqV5ICoqdHXhu5VpIHTEg25nIG5o4bq5IHRow6wgeMOhYyBzdeG6pXQgc+G7kW5nIHPDs3QgdMSDbmcqKiwgbmjGsG5nICoqa2jDtG5nIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6oqKiAocC12YWx1ZSA9IDAuMjQ1ID4gMC4wNSkuDQoqIERvIMSRw7MsICoqdHXhu5VpIGtow7RuZyDhuqNuaCBoxrDhu59uZyDEkcOhbmcga+G7gyDEkeG6v24ga2jhuqMgbsSDbmcgc+G7kW5nIHPDs3QqKiB0cm9uZyBtw7QgaMOsbmggxJHGoW4gYmnhur9uLg0KDQoNCmBgYHtyfQ0KIyBI4buTaSBxdXkgxJHGoW4gYmnhur9uOiBnaeG7m2kgdMOtbmgNCm1vZGVsX2dlbmRlciA8LSBnbG0oc3Vydml2ZWQgfiBnZW5kZXIsIGRhdGEgPSBkYXRhLCBmYW1pbHkgPSBiaW5vbWlhbCkNCnN1bW1hcnkobW9kZWxfZ2VuZGVyKQ0KYGBgDQoNCiogSOG7hyBz4buRIGTGsMahbmcsIG5oxrBuZyBwLXZhbHVlIGzhu5tuIOKHkiAqKmdp4bubaSB0w61uaCBraMO0bmcg4bqjbmggaMaw4bufbmcgxJHDoW5nIGvhu4MgxJHhur9uIGto4bqjIG7Eg25nIHPhu5FuZyBzw7N0KiouDQoqIE5ow7NtIHRoYW0gY2hp4bq/dSBsw6AgIk7hu68iLCBuw6puIGjhu4cgc+G7kSBj4bunYSAiTWFsZSIgxJHhuqFpIGRp4buHbiBjaG8gc+G7sSBraMOhYyBiaeG7h3QgZ2nhu69hIG5hbSB2w6AgbuG7rywgbmjGsG5nIGtow7RuZyDEkeG7pyBi4bqxbmcgY2jhu6luZyDEkeG7gyBraOG6s25nIMSR4buLbmggY8OzIGtow6FjIGJp4buHdC4NCg0KDQpgYGB7cn0NCiMgSOG7k2kgcXV5IMSRxqFuIGJp4bq/bjogdMOsbmggdHLhuqFuZyBow7p0IHRodeG7kWMNCm1vZGVsX3Ntb2tlIDwtIGdsbShzdXJ2aXZlZCB+IHNtb2tpbmdfc3RhdHVzLCBkYXRhID0gZGF0YSwgZmFtaWx5ID0gYmlub21pYWwpDQpzdW1tYXJ5KG1vZGVsX3Ntb2tlKQ0KYGBgDQoNCiogTmjDs20gdGhhbSBjaGnhur91IGzDoCBgIkN1cnJlbnQgU21va2VyImAuDQoqIEPDoWMgbmjDs20ga2jDoWMga2jDtG5nIGPDsyBo4buHIHPhu5EgbWFuZyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6og4oeSICoqdMOsbmggdHLhuqFuZyBow7p0IHRodeG7kWMga2jDtG5nIOG6o25oIGjGsOG7n25nIHLDtSByw6BuZyDEkeG6v24ga2jhuqMgbsSDbmcgc+G7kW5nIHPDs3QgdHJvbmcgcGjDom4gdMOtY2ggxJHGoW4gYmnhur9uLioqDQoNCg0KIyMgNS4yLiBI4buTaSBxdXkgbG9naXN0aWMgxJFhIGJp4bq/bg0KDQpgYGB7cn0NCm1vZGVsX2Z1bGwgPC0gZ2xtKHN1cnZpdmVkIH4gYWdlICsgZ2VuZGVyICsgc21va2luZ19zdGF0dXMgLA0KICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhdGEsIGZhbWlseSA9IGJpbm9taWFsKQ0Kc3VtbWFyeShtb2RlbF9mdWxsKQ0KDQpgYGANCg0KTmdheSBj4bqjIGtoaSBr4bq/dCBo4bujcCBuaGnhu4F1IGJp4bq/biBs4bqhaSwgKipraMO0bmcgY8OzIGJp4bq/biBuw6BvIGPDsyDhuqNuaCBoxrDhu59uZyDEkcOhbmcga+G7gyAocCA8IDAuMDUpIMSR4bq/biBraOG6oyBuxINuZyBz4buRbmcgc8OzdC4qKg0KDQoNCmBgYHtyfQ0KI0NodXnhu4NuIGjhu4cgc+G7kSBzYW5nIE9kZHMgUmF0aW8gxJHhu4MgZOG7hSBoaeG7g3UgaMahbg0KDQpleHAoY2JpbmQoT2Rkc1JhdGlvID0gY29lZihtb2RlbF9mdWxsKSwgY29uZmludChtb2RlbF9mdWxsKSkpDQoNCmBgYA0KDQp8IEJp4bq/biAgICAgICAgICAgICAgICAgfCBPZGRzIFJhdGlvIHwgOTUlIENJICAgICAgICAgICAgfA0KfCAtLS0tLS0tLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLSB8DQp8IGFnZSAgICAgICAgICAgICAgICAgIHwgXH4xLjAwMDMgICB8ICgwLjk5OTk2LCAxLjAwMDgpIHwNCnwgZ2VuZGVyTWFsZSAgICAgICAgICAgfCBcfjEuMDAzNyAgIHwgKDAuOTkzLCAxLjAxNCkgICAgfA0KfCBzbW9raW5nXF9zdGF0dXNOZXZlciB8IFx+MS4wMDMzICAgfCAoMC45ODksIDEuMDE3NykgICB8DQoNCg0KRGnhu4VuIGdp4bqjaToNCg0KKiBDw6FjIE9kZHMgUmF0aW8gxJHhu4F1ICoqeOG6pXAgeOG7iSAxKiosIHbDoCBraG/huqNuZyB0aW4gY+G6rXkgxJHhu4F1ICoqY2jhu6lhIDEqKiDih5Iga2jDtG5nIGPDsyBiaeG6v24gbsOgbyBjw7Mg4bqjbmggaMaw4bufbmcgxJHDoW5nIGvhu4MgxJHhur9uIG9kZHMgc+G7kW5nIHPDs3QuDQoNCg0KYGBge3J9DQojIMSQw6FuaCBnacOhIG3DtCBow6xuaCAodMO5eSBjaOG7jW4pDQojIEFJQw0KQUlDKG1vZGVsX2Z1bGwpDQoNCiMgQmnhu4N1IMSR4buTIFJPQw0KbGlicmFyeShwUk9DKQ0KcHJvYiA8LSBwcmVkaWN0KG1vZGVsX2Z1bGwsIHR5cGUgPSAicmVzcG9uc2UiKQ0Kcm9jX29iaiA8LSByb2MoZGF0YSRzdXJ2aXZlZCwgcHJvYikNCnBsb3Qocm9jX29iaikNCmF1Yyhyb2Nfb2JqKQ0KDQpgYGANCg0KDQoNCkFVQz0gMC41MDE2IChBVUMgPCAwLjYpIHRow6wgbcO0IGjDrG5oIGtow7RuZyBjw7Mga2jhuqMgbsSDbmcgcGjDom4gYmnhu4d0IHThu5F0IGdp4buvYSBz4buRbmcgdsOgIGtow7RuZyBz4buRbmcuDQoNCg0KS+G6vlQgTFXhuqxOIFThu5RORyBUSOG7gjoNCg0KKiBD4bqjIDMgeeG6v3UgdOG7kTogKip0deG7lWkqKiwgKipnaeG7m2kgdMOtbmgqKiwgdsOgICoqdMOsbmggdHLhuqFuZyBow7p0IHRodeG7kWMqKiDEkeG7gXUgKipraMO0bmcgY8OzIOG6o25oIGjGsOG7n25nIMSRw6FuZyBr4buDIMSR4bq/biBraOG6oyBuxINuZyBz4buRbmcgc8OzdCoqIHRoZW8gaOG7k2kgcXV5IGxvZ2lzdGljICjEkcahbiBiaeG6v24gdsOgIMSRYSBiaeG6v24pLg0KKiBDw6FjIGjhu4cgc+G7kSDEkeG7gXUgbmjhu48sIHAtdmFsdWUgPiAwLjA1LCBPZGRzIFJhdGlvIGfhuqduIDEsIGtob+G6o25nIHRpbiBj4bqteSBjaOG7qWEgMS4NCg0K