1 Đọc và làm quen dữ liệu

  • Bộ dữ liệu Adult Income (hay còn gọi là Census Income Dataset) là một trong những tập dữ liệu kinh điển được sử dụng phổ biến trong lĩnh vực học máy và khai phá dữ liệu, đặc biệt trong các bài toán phân loại. Tập dữ liệu này được cung cấp bởi UCI Machine Learning Repository, và bao gồm các thông tin định lượng và định tính liên quan đến hơn 32.000 cá nhân trưởng thành tại Hoa Kỳ.

  • Dữ liệu được thu thập từ các cuộc khảo sát dân số (census) và phản ánh đặc điểm nhân khẩu học như tuổi tác, giới tính, chủng tộc, tình trạng hôn nhân, cùng với các yếu tố kinh tế – xã hội như trình độ học vấn, loại hình công việc, số giờ làm việc mỗi tuần, thu nhập từ vốn và quốc tịch.

  • Mục tiêu phân tích của bộ dữ liệu này là xây dựng một mô hình dự đoán xem một cá nhân có mức thu nhập hằng năm vượt ngưỡng 50.000 USD hay không, dựa trên tập hợp các biến đầu vào đã cho. Nói cách khác, đây là một bài toán phân loại nhị phân, nơi biến mục tiêu là một nhãn với hai giá trị: <=50K và >50K.

  • Với cấu trúc đơn giản nhưng giàu thông tin, bộ dữ liệu Adult thường được sử dụng như một ví dụ điển hình để thực hành các kỹ thuật tiền xử lý dữ liệu, biến đổi đặc trưng, huấn luyện mô hình học máy, và đánh giá độ chính xác của mô hình trong các khóa học và dự án nghiên cứu.

1.1 Đọc file

d <-read.csv('/Users/phamxuanhoan/Documents/Zalo Received Files/dldt.csv', header=T)

1.2 Hiển thị cấu trúc của dữ liệu

str(d)
## 'data.frame':    32561 obs. of  12 variables:
##  $ age           : int  90 82 66 54 41 34 38 74 68 41 ...
##  $ fnlwgt        : int  77053 132870 186061 140359 264663 216864 150601 88638 422013 70037 ...
##  $ education     : chr  "HS-grad" "HS-grad" "Some-college" "7th-8th" ...
##  $ education.num : int  9 9 10 4 10 9 6 16 9 10 ...
##  $ marital.status: chr  "Widowed" "Widowed" "Widowed" "Divorced" ...
##  $ relationship  : chr  "Not-in-family" "Not-in-family" "Unmarried" "Unmarried" ...
##  $ race          : chr  "White" "White" "Black" "White" ...
##  $ sex           : chr  "Female" "Female" "Female" "Female" ...
##  $ capital.loss  : int  4356 4356 4356 3900 3900 3770 3770 3683 3683 3004 ...
##  $ hours.per.week: int  40 18 40 40 40 45 40 20 40 60 ...
##  $ native.country: chr  "United-States" "United-States" "United-States" "United-States" ...
##  $ income        : chr  "<=50K" "<=50K" "<=50K" "<=50K" ...
  • str(...) là viết tắt của structure – dùng để kiểm tra nhanh thông tin về số dòng, số cột, tên biến và kiểu dữ liệu của từng biến.

  • Khi dùng str(d), bạn sẽ biết được:

  • d có bao nhiêu quan sát (rows) và biến (columns)

  • Tên của các biến

  • Kiểu dữ liệu của từng biến (vd: int, chr, factor, num…)

=> Dữ liệu bao gồm: 32561 quan sát và 12 biến, trong đó có 7 biến định tính

variable_explain <- data.frame(
  Ten_Bien = c("age", "fnlwgt", "education", "education.num", "marital.status", 
               "relationship", "race", "sex", "capital.loss", "hours.per.week", 
               "native.country", "income"),
  Y_Nghia = c(
    "Tuổi của cá nhân",
    "Trọng số mẫu dùng cho khảo sát (final weight)",
    "Trình độ học vấn (ví dụ: HS-grad, Some-college)",
    "Số năm học chính quy tương ứng với education",
    "Tình trạng hôn nhân (Divorced, Married, Widowed, v.v.)",
    "Mối quan hệ trong gia đình (Own-child, Not-in-family...)",
    "Chủng tộc (White, Black, Asian-Pac-Islander...)",
    "Giới tính (Male hoặc Female)",
    "Mức lỗ vốn từ đầu tư (capital loss)",
    "Số giờ làm việc mỗi tuần",
    "Quốc gia xuất xứ (ví dụ: United-States)",
    "Thu nhập (<=50K hoặc >50K USD/năm)"
  )
)

library(knitr)
## Warning: package 'knitr' was built under R version 4.3.3
kable(variable_explain, caption = "Giải thích các biến trong bộ dữ liệu")
Giải thích các biến trong bộ dữ liệu
Ten_Bien Y_Nghia
age Tuổi của cá nhân
fnlwgt Trọng số mẫu dùng cho khảo sát (final weight)
education Trình độ học vấn (ví dụ: HS-grad, Some-college)
education.num Số năm học chính quy tương ứng với education
marital.status Tình trạng hôn nhân (Divorced, Married, Widowed, v.v.)
relationship Mối quan hệ trong gia đình (Own-child, Not-in-family…)
race Chủng tộc (White, Black, Asian-Pac-Islander…)
sex Giới tính (Male hoặc Female)
capital.loss Mức lỗ vốn từ đầu tư (capital loss)
hours.per.week Số giờ làm việc mỗi tuần
native.country Quốc gia xuất xứ (ví dụ: United-States)
income Thu nhập (<=50K hoặc >50K USD/năm)

1.3 Kiểm tra giá trị thiếu

sum(is.na(d))
## [1] 0

=> Kết quả: Trong bộ dữ liệu không có giá trị thiếu (NA).

1.4 Chuyển đổi các biến cần thiết

# Danh sách các biến định tính (categorical variables)
cols_to_factor <- c("education", "marital.status", "relationship",
                    "race", "sex", "native.country", "income")

# Chuyển các cột đó sang factor
d[cols_to_factor] <- lapply(d[cols_to_factor], as.factor)

# Kiểm tra lại cấu trúc dữ liệu
str(d)
## 'data.frame':    32561 obs. of  12 variables:
##  $ age           : int  90 82 66 54 41 34 38 74 68 41 ...
##  $ fnlwgt        : int  77053 132870 186061 140359 264663 216864 150601 88638 422013 70037 ...
##  $ education     : Factor w/ 16 levels "10th","11th",..: 12 12 16 6 16 12 1 11 12 16 ...
##  $ education.num : int  9 9 10 4 10 9 6 16 9 10 ...
##  $ marital.status: Factor w/ 7 levels "Divorced","Married-AF-spouse",..: 7 7 7 1 6 1 6 5 1 5 ...
##  $ relationship  : Factor w/ 6 levels "Husband","Not-in-family",..: 2 2 5 5 4 5 5 3 2 5 ...
##  $ race          : Factor w/ 5 levels "Amer-Indian-Eskimo",..: 5 5 3 5 5 5 5 5 5 5 ...
##  $ sex           : Factor w/ 2 levels "Female","Male": 1 1 1 1 1 1 2 1 1 2 ...
##  $ capital.loss  : int  4356 4356 4356 3900 3900 3770 3770 3683 3683 3004 ...
##  $ hours.per.week: int  40 18 40 40 40 45 40 20 40 60 ...
##  $ native.country: Factor w/ 42 levels "?","Cambodia",..: 40 40 40 40 40 40 40 40 40 1 ...
##  $ income        : Factor w/ 2 levels "<=50K",">50K": 1 1 1 1 1 1 1 2 1 2 ...

Các biến định tính như:

  • education: có 16 mức trình độ học vấn khác nhau (ví dụ: HS-grad, Bachelors, Some-college…)

  • marital.status: gồm các mức như Married, Divorced, Widowed, Separated, Never-married

  • relationship: mô tả mối quan hệ trong gia đình, như Own-child, Not-in-family, Husband, Wife…

  • race: 5 nhóm chủng tộc

  • sex: 2 mức (Male, Female)

  • native.country: trên 30 quốc gia khác nhau (đa số là United-States)

  • income: 2 mức (<=50K, >50K)

2 Phân tích Mô tả Một biến Định tính (Univariate Descriptive Analysis)

# Danh sách biến định tính thực tế trong file
tbdt <- c("education", "marital.status", "relationship",
          "race", "sex", "native.country", "income")

# Tạo bảng con chỉ gồm các biến định tính
dq <- d[, tbdt]

# Kiểm tra
str(dq)
## 'data.frame':    32561 obs. of  7 variables:
##  $ education     : Factor w/ 16 levels "10th","11th",..: 12 12 16 6 16 12 1 11 12 16 ...
##  $ marital.status: Factor w/ 7 levels "Divorced","Married-AF-spouse",..: 7 7 7 1 6 1 6 5 1 5 ...
##  $ relationship  : Factor w/ 6 levels "Husband","Not-in-family",..: 2 2 5 5 4 5 5 3 2 5 ...
##  $ race          : Factor w/ 5 levels "Amer-Indian-Eskimo",..: 5 5 3 5 5 5 5 5 5 5 ...
##  $ sex           : Factor w/ 2 levels "Female","Male": 1 1 1 1 1 1 2 1 1 2 ...
##  $ native.country: Factor w/ 42 levels "?","Cambodia",..: 40 40 40 40 40 40 40 40 40 1 ...
##  $ income        : Factor w/ 2 levels "<=50K",">50K": 1 1 1 1 1 1 1 2 1 2 ...
  • Đây là danh sách (vector) chứa tên các cột – đều là biến định tính.

  • Lấy toàn bộ các cột trong danh sách tbdt từ bảng dữ liệu d, và tạo ra một bảng mới tên là dq.

=> Kết quả là bảng dq chỉ chứa các biến định tính.

2.1 Biến MaritalStatus

2.1.1 Giải thích biến

# Giải thích các mức của biến marital.status
marital_levels <- data.frame(
  Gia_tri = c("Divorced", "Married-AF-spouse", "Married-civ-spouse",
              "Married-spouse-absent", "Never-married", "Separated", "Widowed"),
  Y_nghia = c(
    "Ly dị",
    "Kết hôn với người trong lực lượng vũ trang",
    "Đã kết hôn hợp pháp",
    "Kết hôn nhưng sống ly thân",
    "Chưa từng kết hôn",
    "Ly thân có pháp lý",
    "Góa"
  )
)

knitr::kable(marital_levels, caption = "Giải thích các mức trong biến marital.status")
Giải thích các mức trong biến marital.status
Gia_tri Y_nghia
Divorced Ly dị
Married-AF-spouse Kết hôn với người trong lực lượng vũ trang
Married-civ-spouse Đã kết hôn hợp pháp
Married-spouse-absent Kết hôn nhưng sống ly thân
Never-married Chưa từng kết hôn
Separated Ly thân có pháp lý
Widowed Góa

2.1.2 Thống kê Tần suất

# Tạo bảng tần suất cho marital.status
ts_marital <- table(d$marital.status)

# Tạo bảng dữ liệu
ts_marital_df <- data.frame(
  Gia_tri = names(ts_marital),
  Tan_so = as.vector(ts_marital),
  Ty_le = round((as.vector(ts_marital) / sum(ts_marital)) * 100, 2)
)

# Hiển thị kết quả
ts_marital_df
##                 Gia_tri Tan_so Ty_le
## 1              Divorced   4443 13.65
## 2     Married-AF-spouse     23  0.07
## 3    Married-civ-spouse  14976 45.99
## 4 Married-spouse-absent    418  1.28
## 5         Never-married  10683 32.81
## 6             Separated   1025  3.15
## 7               Widowed    993  3.05
  • Đã ly dị (Divorced): có 4443 người (chiếm 13.65%).

  • Kết hôn với người trong quân đội (Married-AF-spouse): có 23 người (chiếm 0.07%).

  • Đã kết hôn hợp pháp (Married-civ-spouse): có 14976 người (chiếm 45.99%).

  • Ly thân (Married-spouse-absent): có 418 người (chiếm 1.28%).

  • Chưa từng kết hôn (Never-married): có 10683 người (chiếm 32.81%).

  • Ly thân có pháp lý (Separated): có 1025 người (chiếm 3.15%).

  • Góa (Widowed): có 993 người (chiếm 3.05%).

2.1.3 Trực quan hóa

library(ggplot2)
ggplot(ts_marital_df, aes(x = reorder(Gia_tri, -Tan_so), y = Tan_so, fill = Gia_tri)) +
  geom_col(width = 0.5, color = "white") +
  geom_text(aes(label = Tan_so), vjust = -0.3, size = 4, fontface = "bold") +
  labs(
    title = "Biểu đồ cột: Tình trạng hôn nhân (marital.status)",
    x = "Tình trạng hôn nhân",
    y = "Tần số"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    axis.text.x = element_text(angle = 45, hjust = 1),
    
  )

ggplot(ts_marital_df, aes(x = reorder(Gia_tri, Ty_le), y = Ty_le, fill = Gia_tri)) +
  geom_col(width = 0.6, color = "white") +
  geom_text(aes(label = paste0(Ty_le, "%")),
            hjust = -0.1, size = 4, fontface = "bold", color = "black") +
  coord_flip() +
  labs(
    title = "Biểu đồ cột ngang: Tỷ lệ tình trạng hôn nhân (marital.status)",
    x = "Tình trạng hôn nhân",
    y = "Tỷ lệ (%)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold")
  )

2.1.4 Nhận xét

  • “Married-civ-spouse” (kết hôn hợp pháp) chiếm 43.94%, cao nhất trong toàn bộ dữ liệu – cho thấy cấu trúc gia đình truyền thống vẫn chiếm ưu thế.

  • “Never-married” đạt 32.81%, là nhóm lớn thứ hai, phản ánh sự hiện diện mạnh mẽ của người độc thân.

  • Các nhóm còn lại như “Divorced” (12.29%), “Married-spouse-absent” (4.79%), “Separated” (3.13%), và “Widowed” (3.05%) góp phần tạo nên tính đa dạng trong tình trạng hôn nhân, nhưng đều chiếm tỷ lệ thấp hơn

2.2 Biến income

2.2.1 Giải thích biến

# Giải thích các mức của biến income
income_levels <- data.frame(
  Gia_tri = c("<=50K", ">50K"),
  Y_nghia = c("Thu nhập dưới hoặc bằng 50.000 USD/năm", "Thu nhập trên 50.000 USD/năm")
)

knitr::kable(income_levels, caption = "Giải thích các mức trong biến income")
Giải thích các mức trong biến income
Gia_tri Y_nghia
<=50K Thu nhập dưới hoặc bằng 50.000 USD/năm
>50K Thu nhập trên 50.000 USD/năm

2.2.2 Thống kê Tần suất

# Tạo bảng tần suất cho income
ts_income <- table(d$income)

# Tạo bảng dữ liệu
ts_income_df <- data.frame(
  Gia_tri = names(ts_income),
  Y_nghia = c("≤50K", ">50K"),
  Tan_so = as.vector(ts_income),
  Ty_le = round((as.vector(ts_income) / sum(ts_income)) * 100, 2)
)

# Hiển thị kết quả
ts_income_df
##   Gia_tri Y_nghia Tan_so Ty_le
## 1   <=50K    ≤50K  24720 75.92
## 2    >50K    >50K   7841 24.08
  • Biến income (thu nhập) có 2 mức:

    • Thu nhập dưới hoặc bằng 50K (<=50K): 24720 người (chiếm 75.92%).
  • Thu nhập trên 50K (>50K): 7841 người (chiếm 24.08%).

2.2.3 Trực quan hóa

ggplot(ts_income_df, aes(x = Gia_tri, y = Tan_so, fill = Gia_tri)) +
  geom_col(width = 0.5, color = "white") +
  geom_text(aes(label = Tan_so), vjust = -0.3, size = 4, fontface = "bold") +
  labs(
    title = "Biểu đồ cột: Thu nhập (income)",
    x = "Nhóm thu nhập",
    y = "Tần số"
  ) +
  scale_fill_manual(values = c("#6D597A", "#FFB703")) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    
  )

income_colors <- c("<=50K" = "#FDB863", ">50K" = "#5E3C99")

ggplot(ts_income_df, aes(x = "", y = Ty_le, fill = Gia_tri)) +
  geom_col(width = 1, color = "white") +
  coord_polar(theta = "y") +
  scale_fill_manual(values = income_colors) +
  labs(title = "Biểu đồ tròn: Thu nhập") +
  geom_text(aes(label = paste0(Ty_le, "%")),
            position = position_stack(vjust = 0.5),
            size = 5, color = "black") +
  theme_void() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.title = element_blank()
  )

2.2.4 Nhận xét

  • Nhóm có thu nhập <=50K chiếm 75.92%, cho thấy phần lớn người trong mẫu khảo sát có thu nhập thấp hơn ngưỡng trung bình.

  • Chỉ 24.08% thuộc nhóm thu nhập >50K, phản ánh mức thu nhập cao là thiểu số trong cộng đồng được khảo sát.

3 Ước lượng Khoảng và Kiểm định Giả thuyết cho Tỷ lệ

3.1 Xác định Hạng mục Quan tâm

  • Hạng mục “Never-married” của biến MaritalStatus – Tình trạng hôn nhân

3.2 Ước lượng Khoảng Tin cậy và Kiểm định Giả thuyết

3.2.1 Hạng mục “Never-married” của biến Tình trạng hôn nhân (marital.status)

# Số người chưa từng kết hôn
n_never_married <- sum(d$marital.status == "Never-married")

# Tổng số quan sát
n_total <- nrow(d)

# Ước lượng khoảng tin cậy 95% cho tỷ lệ người chưa từng kết hôn
prop.test(n_never_married, n_total, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_never_married out of n_total, null probability 0.5
## X-squared = 3848.3, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.3229973 0.3332271
## sample estimates:
##         p 
## 0.3280919

Phân tích kết quả

  • Phép kiểm định được sử dụng là kiểm định tỷ lệ 1 mẫu (1-sample proportions test) với chỉnh liên tục, nhằm cải thiện độ chính xác khi sử dụng phân phối xấp xỉ.

  • Dữ liệu đầu vào: đang kiểm định tỷ lệ người có tình trạng “Never-married” (n_never_married) trong tổng số quan sát (n_total), với giả thuyết gốc H₀: p = 0.5.

  • Giá trị thống kê kiểm định là X-squared = 3848.3 với df = 1, cho thấy mức độ chênh lệch lớn giữa tỷ lệ quan sát và tỷ lệ giả định.

  • Giá trị p-value < 2.2e-16, cực kỳ nhỏ, đồng nghĩa với việc kết quả là rất có ý nghĩa thống kê – xác suất xảy ra sai lầm khi bác bỏ H₀ gần như bằng 0.

  • Giả thuyết đối (H₁): Tỷ lệ thực sự khác 0.5 (kiểm định hai phía: khác lớn hơn hoặc nhỏ hơn đều được xem xét).

  • Khoảng tin cậy 95% cho tỷ lệ người chưa kết hôn nằm trong khoảng [32.30%; 33.32%], thể hiện tỷ lệ thực sự khá ổn định quanh mức 33%.

  • Tỷ lệ mẫu ước lượng là 32.81%, tức là gần 1/3 dân số trong mẫu khảo sát chưa từng kết hôn.

Bài toán kiểm định:

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

Giả thuyết không H₀: p = 0.5 (tỷ lệ người chưa từng kết hôn bằng 50%)

Giả thuyết đối H₁: p ≠ 0.5 (tỷ lệ người chưa từng kết hôn khác 50%)

Mức ý nghĩa: α = 0.05

Kết luận:

Với p-value < 2.2e-16 < 0.05, ta bác bỏ giả thuyết H₀.

Có bằng chứng thống kê mạnh cho thấy tỷ lệ người chưa từng kết hôn khác 50%, với độ tin cậy 95%.

Tỷ lệ ước lượng là 32.81%, với khoảng tin cậy nằm trong [32.30%; 33.32%]. Tỷ lệ này thấp hơn đáng kể so với mức 50%, và sự chênh lệch (~17 điểm phần trăm) là có ý nghĩa thống kê rõ rệt.

4 Phân tích Mối quan hệ giữa Hai biến Định tính (Bivariate Analysis)

Chọn cặp biến định tính :

4.1 Marital.status – Income

4.1.1 Bảng tần số chéo

# Bảng tần số chéo và tỷ lệ theo hàng giữa tình trạng hôn nhân và thu nhập
table_marital_income <- table(d$marital.status, d$income)              # Bảng tần số chéo
table_marital_income                                                   # Hiển thị bảng
##                        
##                         <=50K  >50K
##   Divorced               3980   463
##   Married-AF-spouse        13    10
##   Married-civ-spouse     8284  6692
##   Married-spouse-absent   384    34
##   Never-married         10192   491
##   Separated               959    66
##   Widowed                 908    85
prop.table(table_marital_income, margin = 1)                           # Tính tỷ lệ theo từng tình trạng hôn nhân
##                        
##                              <=50K       >50K
##   Divorced              0.89579113 0.10420887
##   Married-AF-spouse     0.56521739 0.43478261
##   Married-civ-spouse    0.55315171 0.44684829
##   Married-spouse-absent 0.91866029 0.08133971
##   Never-married         0.95403913 0.04596087
##   Separated             0.93560976 0.06439024
##   Widowed               0.91440081 0.08559919
  • Trong nhóm Married-civ-spouse: có 8,284 người thu nhập <=50K và 6,692 người thu nhập >50K → tỷ lệ >50K là 44.7%.

  • Trong nhóm Never-married: có 10,192 người thu nhập <=50K và 491 người thu nhập >50K → tỷ lệ >50K là 4.6%.

  • Trong nhóm Divorced: có 3,980 người thu nhập <=50K và 463 người thu nhập >50K → tỷ lệ >50K là 10.4%.

  • Trong nhóm Married-spouse-absent: có 384 người thu nhập <=50K và 34 người thu nhập >50K → tỷ lệ >50K là 8.1%.

  • Trong nhóm Widowed: có 908 người thu nhập <=50K và 85 người thu nhập >50K → tỷ lệ >50K là 8.6%.

  • Trong nhóm Separated: có 959 người thu nhập <=50K và 66 người thu nhập >50K → tỷ lệ >50K là 6.4%.

  • Trong nhóm Married-AF-spouse: có 13 người thu nhập <=50K và 10 người thu nhập >50K → tỷ lệ >50K là 43.5% (nhưng mẫu nhỏ).

Kết luận: → Nhóm Married-civ-spouse có tỷ lệ thu nhập >50K cao nhất trong các nhóm đông dân số, trong khi nhóm Never-married có tỷ lệ thấp nhất. → Điều này phản ánh sự chênh lệch đáng kể về thu nhập theo tình trạng hôn nhân, đặc biệt là lợi thế của người đã kết hôn hợp pháp.

4.1.2 Trực quan hóa

# Tạo bảng dữ liệu từ bảng tần suất chéo
table_marital_income <- table(d$marital.status, d$income)
df_group_marital <- as.data.frame(as.table(table_marital_income))
colnames(df_group_marital) <- c("MaritalStatus", "Income", "Freq")

# Vẽ biểu đồ cột nhóm
ggplot(df_group_marital, aes(x = MaritalStatus, y = Freq, fill = Income)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.8), width = 0.6) +
  geom_text(aes(label = Freq),
            position = position_dodge(width = 0.8),
            vjust = -0.4, size = 4, color = "black", fontface = "bold") +
  scale_fill_manual(
    values = c("<=50K" = "#FFA07A", ">50K" = "#20B2AA"),
    name = "Thu nhập"
  ) +
  labs(title = "Biểu đồ cột nhóm: MaritalStatus vs Income",
       x = "Tình trạng hôn nhân",
       y = "Tần số") +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.position = "right"
  )

# Tạo bảng dữ liệu từ bảng tần suất chéo
table_marital_income <- table(d$marital.status, d$income)
df_stack_marital <- as.data.frame(as.table(table_marital_income))
colnames(df_stack_marital) <- c("MaritalStatus", "Income", "Freq")

# Vẽ biểu đồ cột chồng 
ggplot(df_stack_marital, aes(x = MaritalStatus, y = Freq, fill = Income)) +
  geom_bar(stat = "identity", width = 0.6) +
  geom_text(
    aes(label = Freq),
    position = position_stack(vjust = 0.5),
    vjust = 0.5, size = 4, color = "black", fontface = "bold"
  ) +
  scale_fill_manual(
    values = c("<=50K" = "#FFA07A", ">50K" = "#20B2AA"),
    name = "Thu nhập"
  ) +
  labs(
    title = "Biểu đồ cột chồng: MaritalStatus vs Income",
    x = "Tình trạng hôn nhân",
    y = "Tần số"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.position = "right"
  )

4.1.3 Nhận xét mô tả

  • Biểu đồ cột nhóm cho thấy những người đã kết hôn hợp pháp (Married-civ-spouse) có số lượng vượt trội ở nhóm thu nhập >50K – thanh cột ở nhóm này cao rõ rệt.

  • Ngược lại, nhóm Never-married gần như chỉ xuất hiện ở mức thu nhập thấp. Các nhóm “Divorced” hay “Separated” cũng có tỷ lệ thu nhập cao rất thấp.

  • Biểu đồ cột chồng cho thấy cột của nhóm Married-civ-spouse có phần màu thu nhập cao chiếm gần một nửa, trong khi các nhóm khác phần màu này rất mỏng.

→ Kết luận trực quan: Tình trạng hôn nhân có liên quan chặt chẽ đến thu nhập. Biểu đồ phản ánh rõ rằng người đã kết hôn có lợi thế lớn về kinh tế so với các nhóm còn lại.

4.1.4 Kiểm định thống kê(Kiểm định Chi-bình phương)

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

H₀ (Giả thuyết không):Tình trạng hôn nhân và mức thu nhập độc lập với nha.

H₁ (Giả thuyết đối):Tình trạng hôn nhân và mức thu nhập có mối liên hệ với nhau.

chisq.test(table_marital_income)
## 
##  Pearson's Chi-squared test
## 
## data:  table_marital_income
## X-squared = 6517.7, df = 6, p-value < 2.2e-16

Kết quả kiểm định:

Chi-squared = 6517.74

Bậc tự do (df) = 6

Giá trị p-value = 0.0000

Kết luận thống kê:

Vì p < 0.05, ta bác bỏ giả thuyết H₀.

Có mối liên hệ thống kê rõ rệt giữa tình trạng hôn nhân và mức thu nhập

Thảo luận thêm về bản chất mối quan hệ:

Biểu đồ cho thấy nhóm đã kết hôn (Married-civ-spouse) có phần thu nhập >50K chiếm ưu thế tuyệt đối.

Ngược lại, nhóm độc thân (Never-married) hầu như chỉ tập trung ở mức thu nhập thấp.

Các nhóm ly hôn, ly thân, hoặc góa cũng có tỷ lệ thu nhập cao thấp đáng kể.

→ Giải thích mối liên hệ: Kiểm định cho thấy tình trạng hôn nhân không chỉ liên quan đến thu nhập, mà còn có xu hướng rõ ràng – người đã lập gia đình có nhiều khả năng đạt thu nhập cao hơn. Điều này có thể phản ánh mức độ ổn định tài chính, độ tuổi, hoặc cam kết nghề nghiệp cao hơn trong nhóm đã kết hôn.

4.1.5 Hiệu tỷ lệ

# Lập bảng tần số chéo giữa marital.status và income
table_marital_income <- table(d$marital.status, d$income)

# Thêm tổng hàng và tổng cột
table_marital_income1 <- addmargins(table_marital_income)

# Hiển thị bảng
table_marital_income1
##                        
##                         <=50K  >50K   Sum
##   Divorced               3980   463  4443
##   Married-AF-spouse        13    10    23
##   Married-civ-spouse     8284  6692 14976
##   Married-spouse-absent   384    34   418
##   Never-married         10192   491 10683
##   Separated               959    66  1025
##   Widowed                 908    85   993
##   Sum                   24720  7841 32561
  • \(p_1 = P(\text{income} = \text{">50K"} \mid \text{marital.status} = \text{"Never-married"})\) (Tỷ lệ người chưa từng kết hôn có thu nhập cao)

  • \(p_2 = P(\text{income} = \text{">50K"} \mid \text{marital.status} = \text{"Married-civ-spouse"})\) (Tỷ lệ người đang kết hôn hợp pháp có thu nhập cao)

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

  • \(H_0: p_1 - p_2 = 0\) (Không có sự khác biệt về tỷ lệ thu nhập cao giữa hai nhóm tình trạng hôn nhân)

  • \(H_1: p_1 - p_2 < 0\) (Tỷ lệ thu nhập cao ở nhóm “Never-married” thấp hơn nhóm “Married-civ-spouse”)

# Lập bảng tần số chéo giữa marital.status và income
table_marital_income <- table(d$marital.status, d$income)

# Số người có thu nhập >50K trong từng nhóm
counts_income_high <- c(table_marital_income["Never-married", ">50K"],
                        table_marital_income["Married-civ-spouse", ">50K"])

# Tổng số người trong từng nhóm
totals_income <- c(sum(table_marital_income["Never-married", ]),
                   sum(table_marital_income["Married-civ-spouse", ]))

# Kiểm định tỉ lệ một phía: p1 < p2
test_marital_income <- prop.test(counts_income_high, totals_income,
                                 alternative = "less", correct = FALSE)

# Hiển thị kết quả
test_marital_income
## 
##  2-sample test for equality of proportions without continuity correction
## 
## data:  counts_income_high out of totals_income
## X-squared = 4971.2, df = 1, p-value < 2.2e-16
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.0000000 -0.3934202
## sample estimates:
##     prop 1     prop 2 
## 0.04596087 0.44684829

Kết quả kiểm định cho thấy:

  • Tỷ lệ người chưa từng kết hôn có thu nhập >50K (prop 1) là khoảng 4.60%.

  • Tỷ lệ người đang kết hôn hợp pháp có thu nhập >50K (prop 2) là khoảng 44.65%.

Với p-value < 2.2e-16, nhỏ hơn mức ý nghĩa 0.05, chúng ta có đủ bằng chứng để bác bỏ giả thuyết H0. Điều này có nghĩa là:

–> Tỷ lệ người chưa từng kết hôn có thu nhập cao thấp hơn tỷ lệ người đang kết hôn hợp pháp một cách có ý nghĩa thống kê.

4.1.6 Relative Risk

Liệu tình trạng hôn nhân (đã kết hôn vs chưa bao giờ kết hôn) có ảnh hưởng đến nguy cơ có thu nhập cao không (>50K)?

→ Mục tiêu: So sánh nguy cơ có thu nhập cao ở người đã kết hôn với người chưa từng kết hôn.

install.packages("epitools", repos = "https://cloud.r-project.org")
## 
## The downloaded binary packages are in
##  /var/folders/8b/td0_s_sx51g4kyv_jqzgr1n80000gn/T//RtmpPbtfM7/downloaded_packages
library(epitools)
## Warning: package 'epitools' was built under R version 4.3.3
riskratio(table_marital_income)
## Warning in chisq.test(xx, correct = correction): Chi-squared approximation may
## be incorrect
## $data
##                        
##                         <=50K >50K Total
##   Divorced               3980  463  4443
##   Married-AF-spouse        13   10    23
##   Married-civ-spouse     8284 6692 14976
##   Married-spouse-absent   384   34   418
##   Never-married         10192  491 10683
##   Separated               959   66  1025
##   Widowed                 908   85   993
##   Total                 24720 7841 32561
## 
## $measure
##                        risk ratio with 95% C.I.
##                          estimate     lower     upper
##   Divorced              1.0000000        NA        NA
##   Married-AF-spouse     4.1722227 2.5975617 6.7014550
##   Married-civ-spouse    4.2880064 3.9266589 4.6826065
##   Married-spouse-absent 0.7805450 0.5591884 1.0895265
##   Never-married         0.4410457 0.3903710 0.4982986
##   Separated             0.6178960 0.4818083 0.7924220
##   Widowed               0.8214195 0.6586704 1.0243819
## 
## $p.value
##                        two-sided
##                           midp.exact fisher.exact   chi.square
##   Divorced                        NA           NA           NA
##   Married-AF-spouse     5.857500e-05 5.164112e-05 2.767102e-07
##   Married-civ-spouse    0.000000e+00 0.000000e+00 0.000000e+00
##   Married-spouse-absent 1.350522e-01 1.512784e-01 1.400969e-01
##   Never-married         0.000000e+00 7.032552e-38 4.455345e-41
##   Separated             5.197404e-05 6.379070e-05 1.013461e-04
##   Widowed               7.502949e-02 8.040431e-02 7.825486e-02
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

Nhận xét kết quả

Kết quả

  • Trong số 14,976 người đã kết hôn, có 6,692 người (44.69%) có thu nhập >50K.

  • Trong số 10,683 người chưa bao giờ kết hôn, chỉ có 491 người (4.60%) có thu nhập >50K.

  • Tỷ số nguy cơ (RR) = 9.72 → Người đã kết hôn có xác suất có thu nhập >50K cao hơn gần 10 lần so với người chưa từng kết hôn.

  • Khoảng tin cậy 95% = [8.90, 10.62] → Không bao gồm 1 → khác biệt có ý nghĩa thống kê mạnh mẽ.

  • p-value = 0.000 ở tất cả các kiểm định → xác nhận kết quả là cực kỳ có ý nghĩa thống kê.

Kết luận

  • Dựa trên kết quả phân tích, người đã kết hôn có nguy cơ có thu nhập cao vượt trội so với người chưa từng kết hôn. Tỷ số nguy cơ là 9.72, khoảng tin cậy 95% là [8.90, 10.62], và p-value bằng 0 cho thấy mối liên hệ rất mạnh mẽ và có ý nghĩa thống kê. Tình trạng hôn nhân là một yếu tố quan trọng ảnh hưởng đến khả năng đạt mức thu nhập cao trong bộ dữ liệu này.

4.1.7 Odds Ratio - OR

# Ước lượng odds ratio từng nhóm so với nhóm "Divorced"
or_result <- oddsratio(table_marital_income)
## Warning in chisq.test(xx, correct = correction): Chi-squared approximation may
## be incorrect
# In kết quả
print(or_result)
## $data
##                        
##                         <=50K >50K Total
##   Divorced               3980  463  4443
##   Married-AF-spouse        13   10    23
##   Married-civ-spouse     8284 6692 14976
##   Married-spouse-absent   384   34   418
##   Never-married         10192  491 10683
##   Separated               959   66  1025
##   Widowed                 908   85   993
##   Total                 24720 7841 32561
## 
## $measure
##                        odds ratio with 95% C.I.
##                          estimate     lower      upper
##   Divorced              1.0000000        NA         NA
##   Married-AF-spouse     6.6313682 2.7883118 15.2865405
##   Married-civ-spouse    6.9415692 6.2783544  7.6929581
##   Married-spouse-absent 0.7643062 0.5219850  1.0836587
##   Never-married         0.4141385 0.3628557  0.4727149
##   Separated             0.5928455 0.4499804  0.7690263
##   Widowed               0.8058970 0.6287078  1.0215482
## 
## $p.value
##                        two-sided
##                           midp.exact fisher.exact   chi.square
##   Divorced                        NA           NA           NA
##   Married-AF-spouse     5.857500e-05 5.164112e-05 2.767102e-07
##   Married-civ-spouse    0.000000e+00 0.000000e+00 0.000000e+00
##   Married-spouse-absent 1.350522e-01 1.512784e-01 1.400969e-01
##   Never-married         0.000000e+00 7.032552e-38 4.455345e-41
##   Separated             5.197404e-05 6.379070e-05 1.013461e-04
##   Widowed               7.502949e-02 8.040431e-02 7.825486e-02
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

Ước lượng Odds Ratio (OR) cho các nhóm tình trạng hôn nhân, tham chiếu là “Divorced” - Nhóm Married-civ-spouse có OR = 6.94 (95% CI: 6.28 – 7.69), p-value = 0.0000. –> Người đang kết hôn hợp pháp có khả năng có thu nhập >50K cao hơn gần 7 lần so với người đã ly hôn. Sự khác biệt này có ý nghĩa thống kê rất cao.

  • Nhóm Never-married có OR = 0.41 (95% CI: 0.36 – 0.47), p-value = 0.0000. –> Những người chưa từng kết hôn có khả năng đạt thu nhập cao chỉ bằng 41% so với nhóm ly hôn. Đây là sự khác biệt có ý nghĩa thống kê rõ rệt.

  • Nhóm Separated có OR = 0.59 (95% CI: 0.45 – 0.77), p-value = 0.0001. –> Những người ly thân có xác suất thu nhập cao thấp hơn đáng kể so với người ly hôn, và sự khác biệt này có ý nghĩa thống kê.

  • Nhóm Widowed có OR = 0.81 (95% CI: 0.63 – 1.02), p-value = 0.0750. –> Mặc dù có xu hướng thu nhập thấp hơn nhóm ly hôn, nhưng vì khoảng tin cậy bao gồm 1 và p-value > 0.05 nên chưa đủ bằng chứng thống kê để kết luận.

  • Nhóm Married-AF-spouse có OR = 6.63 (95% CI: 2.79 – 15.29), p-value ≈ 0.00006. –> Mặc dù nhóm này rất nhỏ (n = 23), kết quả cho thấy khả năng có thu nhập cao cũng cao hơn nhiều so với người ly hôn và có ý nghĩa thống kê.

  • Nhóm Married-spouse-absent có OR = 0.76 (95% CI: 0.52 – 1.08), p-value ≈ 0.135. –> Không có đủ bằng chứng thống kê để kết luận có sự khác biệt về thu nhập so với nhóm ly hôn.

Tóm lại:

Kết quả phân tích cho thấy tình trạng hôn nhân có mối liên hệ đáng kể với mức thu nhập. Nhóm đang sống trong hôn nhân hợp pháp (Married-civ-spouse) có xác suất đạt thu nhập cao vượt trội so với các nhóm khác, đặc biệt là người ly hôn, chưa kết hôn hay ly thân. Những khác biệt này có ý nghĩa thống kê rõ ràng, ngoại trừ một số nhóm có quy mô mẫu nhỏ hoặc khoảng tin cậy chứa 1.

LS0tCnRpdGxlOiAiTmhp4buHbSB24bulIFR14bqnbiAwNCIKYXV0aG9yOiAiUGjhuqFtIFh1w6JuIEhvYW4iCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVIOiVNOiVTLCAlZCAtICVtIC0gJVknKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDogCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogImRlZmF1bHQiCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OiB0cnVlCiAgd29yZF9kb2N1bWVudDogCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgogIHBkZl9kb2N1bWVudDogCiAgICBsYXRleF9lbmdpbmU6IHhlbGF0ZXgKLS0tCgpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CmNhdCgnPHN0eWxlPnAgeyB0ZXh0LWFsaWduOiBqdXN0aWZ5OyB9PC9zdHlsZT4nKQpgYGAKCiMgxJDhu41jIHbDoCBsw6BtIHF1ZW4gZOG7ryBsaeG7h3UKCi0gQuG7mSBk4buvIGxp4buHdSBBZHVsdCBJbmNvbWUgKGhheSBjw7JuIGfhu41pIGzDoCBDZW5zdXMgSW5jb21lIERhdGFzZXQpIGzDoCBt4buZdCB0cm9uZyBuaOG7r25nIHThuq1wIGThu68gbGnhu4d1IGtpbmggxJFp4buDbiDEkcaw4bujYyBz4butIGThu6VuZyBwaOG7lSBiaeG6v24gdHJvbmcgbMSpbmggduG7sWMgaOG7jWMgbcOheSB2w6Aga2hhaSBwaMOhIGThu68gbGnhu4d1LCDEkeG6t2MgYmnhu4d0IHRyb25nIGPDoWMgYsOgaSB0b8OhbiBwaMOibiBsb+G6oWkuIFThuq1wIGThu68gbGnhu4d1IG7DoHkgxJHGsOG7o2MgY3VuZyBj4bqlcCBi4bufaSBVQ0kgTWFjaGluZSBMZWFybmluZyBSZXBvc2l0b3J5LCB2w6AgYmFvIGfhu5NtIGPDoWMgdGjDtG5nIHRpbiDEkeG7i25oIGzGsOG7o25nIHbDoCDEkeG7i25oIHTDrW5oIGxpw6puIHF1YW4gxJHhur9uIGjGoW4gMzIuMDAwIGPDoSBuaMOibiB0csaw4bufbmcgdGjDoG5oIHThuqFpIEhvYSBL4buzLgoKLSBE4buvIGxp4buHdSDEkcaw4bujYyB0aHUgdGjhuq1wIHThu6sgY8OhYyBjdeG7mWMga2jhuqNvIHPDoXQgZMOibiBz4buRIChjZW5zdXMpIHbDoCBwaOG6o24gw6FuaCDEkeG6t2MgxJFp4buDbSBuaMOibiBraOG6qXUgaOG7jWMgbmjGsCB0deG7lWkgdMOhYywgZ2nhu5tpIHTDrW5oLCBjaOG7p25nIHThu5ljLCB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4sIGPDuW5nIHbhu5tpIGPDoWMgeeG6v3UgdOG7kSBraW5oIHThur8g4oCTIHjDoyBo4buZaSBuaMawIHRyw6xuaCDEkeG7mSBo4buNYyB24bqlbiwgbG/huqFpIGjDrG5oIGPDtG5nIHZp4buHYywgc+G7kSBnaeG7nSBsw6BtIHZp4buHYyBt4buXaSB0deG6p24sIHRodSBuaOG6rXAgdOG7qyB24buRbiB2w6AgcXXhu5FjIHThu4tjaC4KCi0gTeG7pWMgdGnDqnUgcGjDom4gdMOtY2ggY+G7p2EgYuG7mSBk4buvIGxp4buHdSBuw6B5IGzDoCB4w6J5IGThu7FuZyBt4buZdCBtw7QgaMOsbmggZOG7sSDEkW/DoW4geGVtIG3hu5l0IGPDoSBuaMOibiBjw7MgbeG7qWMgdGh1IG5o4bqtcCBo4bqxbmcgbsSDbSB2xrDhu6N0IG5nxrDhu6FuZyA1MC4wMDAgVVNEIGhheSBraMO0bmcsIGThu7FhIHRyw6puIHThuq1wIGjhu6NwIGPDoWMgYmnhur9uIMSR4bqndSB2w6BvIMSRw6MgY2hvLiBOw7NpIGPDoWNoIGtow6FjLCDEkcOieSBsw6AgbeG7mXQgYsOgaSB0b8OhbiBwaMOibiBsb+G6oWkgbmjhu4sgcGjDom4sIG7GoWkgYmnhur9uIG3hu6VjIHRpw6p1IGzDoCBt4buZdCBuaMOjbiB24bubaSBoYWkgZ2nDoSB0cuG7izogPD01MEsgdsOgID41MEsuCgotIFbhu5tpIGPhuqV1IHRyw7pjIMSRxqFuIGdp4bqjbiBuaMawbmcgZ2nDoHUgdGjDtG5nIHRpbiwgYuG7mSBk4buvIGxp4buHdSBBZHVsdCB0aMaw4budbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcgbmjGsCBt4buZdCB2w60gZOG7pSDEkWnhu4NuIGjDrG5oIMSR4buDIHRo4buxYyBow6BuaCBjw6FjIGvhu7kgdGh14bqtdCB0aeG7gW4geOG7rSBsw70gZOG7ryBsaeG7h3UsIGJp4bq/biDEkeG7lWkgxJHhurdjIHRyxrBuZywgaHXhuqVuIGx1eeG7h24gbcO0IGjDrG5oIGjhu41jIG3DoXksIHbDoCDEkcOhbmggZ2nDoSDEkeG7mSBjaMOtbmggeMOhYyBj4bunYSBtw7QgaMOsbmggdHJvbmcgY8OhYyBraMOzYSBo4buNYyB2w6AgZOG7sSDDoW4gbmdoacOqbiBj4bupdS4KCgojIyAgxJDhu41jIGZpbGUKYGBge3J9CmQgPC1yZWFkLmNzdignL1VzZXJzL3BoYW14dWFuaG9hbi9Eb2N1bWVudHMvWmFsbyBSZWNlaXZlZCBGaWxlcy9kbGR0LmNzdicsIGhlYWRlcj1UKQpgYGAKCiMjICBIaeG7g24gdGjhu4sgY+G6pXUgdHLDumMgY+G7p2EgZOG7ryBsaeG7h3UKCmBgYHtyfQpzdHIoZCkKYGBgCgotIGBzdHIoLi4uKWAgbMOgIHZp4bq/dCB04bqvdCBj4bunYSBzdHJ1Y3R1cmUg4oCTIGTDuW5nIMSR4buDIGtp4buDbSB0cmEgbmhhbmggdGjDtG5nIHRpbiB24buBIHPhu5EgZMOybmcsIHPhu5EgY+G7mXQsIHTDqm4gYmnhur9uIHbDoCBraeG7g3UgZOG7ryBsaeG7h3UgY+G7p2EgdOG7q25nIGJp4bq/bi4KCi0gS2hpIGTDuW5nIGBzdHIoZClgLCBi4bqhbiBz4bq9IGJp4bq/dCDEkcaw4bujYzoKCisgZCBjw7MgYmFvIG5oacOqdSBxdWFuIHPDoXQgKHJvd3MpIHbDoCBiaeG6v24gKGNvbHVtbnMpCgorIFTDqm4gY+G7p2EgY8OhYyBiaeG6v24KCisgS2nhu4N1IGThu68gbGnhu4d1IGPhu6dhIHThu6tuZyBiaeG6v24gKHZkOiBpbnQsIGNociwgZmFjdG9yLCBudW0uLi4pCgo9PiBE4buvIGxp4buHdSBiYW8gZ+G7k206IDMyNTYxIHF1YW4gc8OhdCB2w6AgMTIgYmnhur9uLCB0cm9uZyDEkcOzIGPDsyA3IGJp4bq/biDEkeG7i25oIHTDrW5oCgpgYGB7cn0KdmFyaWFibGVfZXhwbGFpbiA8LSBkYXRhLmZyYW1lKAogIFRlbl9CaWVuID0gYygiYWdlIiwgImZubHdndCIsICJlZHVjYXRpb24iLCAiZWR1Y2F0aW9uLm51bSIsICJtYXJpdGFsLnN0YXR1cyIsIAogICAgICAgICAgICAgICAicmVsYXRpb25zaGlwIiwgInJhY2UiLCAic2V4IiwgImNhcGl0YWwubG9zcyIsICJob3Vycy5wZXIud2VlayIsIAogICAgICAgICAgICAgICAibmF0aXZlLmNvdW50cnkiLCAiaW5jb21lIiksCiAgWV9OZ2hpYSA9IGMoCiAgICAiVHXhu5VpIGPhu6dhIGPDoSBuaMOibiIsCiAgICAiVHLhu41uZyBz4buRIG3huqt1IGTDuW5nIGNobyBraOG6o28gc8OhdCAoZmluYWwgd2VpZ2h0KSIsCiAgICAiVHLDrG5oIMSR4buZIGjhu41jIHbhuqVuICh2w60gZOG7pTogSFMtZ3JhZCwgU29tZS1jb2xsZWdlKSIsCiAgICAiU+G7kSBuxINtIGjhu41jIGNow61uaCBxdXkgdMawxqFuZyDhu6luZyB24bubaSBlZHVjYXRpb24iLAogICAgIlTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiAoRGl2b3JjZWQsIE1hcnJpZWQsIFdpZG93ZWQsIHYudi4pIiwKICAgICJN4buRaSBxdWFuIGjhu4cgdHJvbmcgZ2lhIMSRw6xuaCAoT3duLWNoaWxkLCBOb3QtaW4tZmFtaWx5Li4uKSIsCiAgICAiQ2jhu6duZyB04buZYyAoV2hpdGUsIEJsYWNrLCBBc2lhbi1QYWMtSXNsYW5kZXIuLi4pIiwKICAgICJHaeG7m2kgdMOtbmggKE1hbGUgaG/hurdjIEZlbWFsZSkiLAogICAgIk3hu6ljIGzhu5cgduG7kW4gdOG7qyDEkeG6p3UgdMawIChjYXBpdGFsIGxvc3MpIiwKICAgICJT4buRIGdp4budIGzDoG0gdmnhu4djIG3hu5dpIHR14bqnbiIsCiAgICAiUXXhu5FjIGdpYSB4deG6pXQgeOG7qSAodsOtIGThu6U6IFVuaXRlZC1TdGF0ZXMpIiwKICAgICJUaHUgbmjhuq1wICg8PTUwSyBob+G6t2MgPjUwSyBVU0QvbsSDbSkiCiAgKQopCgpsaWJyYXJ5KGtuaXRyKQprYWJsZSh2YXJpYWJsZV9leHBsYWluLCBjYXB0aW9uID0gIkdp4bqjaSB0aMOtY2ggY8OhYyBiaeG6v24gdHJvbmcgYuG7mSBk4buvIGxp4buHdSIpCgoKYGBgCgoKIyMgIEtp4buDbSB0cmEgZ2nDoSB0cuG7iyB0aGnhur91CgpgYGB7cn0Kc3VtKGlzLm5hKGQpKQoKYGBgCgo9PiBL4bq/dCBxdeG6ozogVHJvbmcgYuG7mSBk4buvIGxp4buHdSBraMO0bmcgY8OzIGdpw6EgdHLhu4sgdGhp4bq/dSAoTkEpLgoKIyMgIENodXnhu4NuIMSR4buVaSBjw6FjIGJp4bq/biBj4bqnbiB0aGnhur90CgpgYGB7cn0KCiMgRGFuaCBzw6FjaCBjw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oIChjYXRlZ29yaWNhbCB2YXJpYWJsZXMpCmNvbHNfdG9fZmFjdG9yIDwtIGMoImVkdWNhdGlvbiIsICJtYXJpdGFsLnN0YXR1cyIsICJyZWxhdGlvbnNoaXAiLAogICAgICAgICAgICAgICAgICAgICJyYWNlIiwgInNleCIsICJuYXRpdmUuY291bnRyeSIsICJpbmNvbWUiKQoKIyBDaHV54buDbiBjw6FjIGPhu5l0IMSRw7Mgc2FuZyBmYWN0b3IKZFtjb2xzX3RvX2ZhY3Rvcl0gPC0gbGFwcGx5KGRbY29sc190b19mYWN0b3JdLCBhcy5mYWN0b3IpCgojIEtp4buDbSB0cmEgbOG6oWkgY+G6pXUgdHLDumMgZOG7ryBsaeG7h3UKc3RyKGQpCgoKYGBgCgoKQ8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCBuaMawOgoKLSBlZHVjYXRpb246IGPDsyAxNiBt4bupYyB0csOsbmggxJHhu5kgaOG7jWMgduG6pW4ga2jDoWMgbmhhdSAodsOtIGThu6U6IEhTLWdyYWQsIEJhY2hlbG9ycywgU29tZS1jb2xsZWdl4oCmKQoKLSBtYXJpdGFsLnN0YXR1czogZ+G7k20gY8OhYyBt4bupYyBuaMawIE1hcnJpZWQsIERpdm9yY2VkLCBXaWRvd2VkLCBTZXBhcmF0ZWQsIE5ldmVyLW1hcnJpZWQKCi0gcmVsYXRpb25zaGlwOiBtw7QgdOG6oyBt4buRaSBxdWFuIGjhu4cgdHJvbmcgZ2lhIMSRw6xuaCwgbmjGsCBPd24tY2hpbGQsIE5vdC1pbi1mYW1pbHksIEh1c2JhbmQsIFdpZmXigKYKCi0gcmFjZTogNSBuaMOzbSBjaOG7p25nIHThu5ljCgotIHNleDogMiBt4bupYyAoTWFsZSwgRmVtYWxlKQoKLSBuYXRpdmUuY291bnRyeTogdHLDqm4gMzAgcXXhu5FjIGdpYSBraMOhYyBuaGF1ICjEkWEgc+G7kSBsw6AgVW5pdGVkLVN0YXRlcykKCi0gaW5jb21lOiAyIG3hu6ljICg8PTUwSywgPjUwSykKCiMgIFBow6JuIHTDrWNoIE3DtCB04bqjIE3hu5l0IGJp4bq/biDEkOG7i25oIHTDrW5oIChVbml2YXJpYXRlIERlc2NyaXB0aXZlIEFuYWx5c2lzKQoKCmBgYHtyfQojIERhbmggc8OhY2ggYmnhur9uIMSR4buLbmggdMOtbmggdGjhu7FjIHThur8gdHJvbmcgZmlsZQp0YmR0IDwtIGMoImVkdWNhdGlvbiIsICJtYXJpdGFsLnN0YXR1cyIsICJyZWxhdGlvbnNoaXAiLAogICAgICAgICAgInJhY2UiLCAic2V4IiwgIm5hdGl2ZS5jb3VudHJ5IiwgImluY29tZSIpCgojIFThuqFvIGLhuqNuZyBjb24gY2jhu4kgZ+G7k20gY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaApkcSA8LSBkWywgdGJkdF0KCiMgS2nhu4NtIHRyYQpzdHIoZHEpCgpgYGAKCi0gxJDDonkgbMOgIGRhbmggc8OhY2ggKHZlY3RvcikgY2jhu6lhIHTDqm4gY8OhYyBj4buZdCDigJMgxJHhu4F1IGzDoCBiaeG6v24gxJHhu4tuaCB0w61uaC4KCi0gTOG6pXkgdG/DoG4gYuG7mSBjw6FjIGPhu5l0IHRyb25nIGRhbmggc8OhY2ggdGJkdCB04burIGLhuqNuZyBk4buvIGxp4buHdSBkLCB2w6AgdOG6oW8gcmEgbeG7mXQgYuG6o25nIG3hu5tpIHTDqm4gbMOgIGRxLgoKPT4gS+G6v3QgcXXhuqMgbMOgIGLhuqNuZyBkcSBjaOG7iSBjaOG7qWEgY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaC4KCiMjICoqQmnhur9uIE1hcml0YWxTdGF0dXMqKgoKIyMjIEdp4bqjaSB0aMOtY2ggYmnhur9uCgpgYGB7cn0KIyBHaeG6o2kgdGjDrWNoIGPDoWMgbeG7qWMgY+G7p2EgYmnhur9uIG1hcml0YWwuc3RhdHVzCm1hcml0YWxfbGV2ZWxzIDwtIGRhdGEuZnJhbWUoCiAgR2lhX3RyaSA9IGMoIkRpdm9yY2VkIiwgIk1hcnJpZWQtQUYtc3BvdXNlIiwgIk1hcnJpZWQtY2l2LXNwb3VzZSIsCiAgICAgICAgICAgICAgIk1hcnJpZWQtc3BvdXNlLWFic2VudCIsICJOZXZlci1tYXJyaWVkIiwgIlNlcGFyYXRlZCIsICJXaWRvd2VkIiksCiAgWV9uZ2hpYSA9IGMoCiAgICAiTHkgZOG7iyIsCiAgICAiS+G6v3QgaMO0biB24bubaSBuZ8aw4budaSB0cm9uZyBs4buxYyBsxrDhu6NuZyB2xakgdHJhbmciLAogICAgIsSQw6Mga+G6v3QgaMO0biBo4bujcCBwaMOhcCIsCiAgICAiS+G6v3QgaMO0biBuaMawbmcgc+G7kW5nIGx5IHRow6JuIiwKICAgICJDaMawYSB04burbmcga+G6v3QgaMO0biIsCiAgICAiTHkgdGjDom4gY8OzIHBow6FwIGzDvSIsCiAgICAiR8OzYSIKICApCikKCmtuaXRyOjprYWJsZShtYXJpdGFsX2xldmVscywgY2FwdGlvbiA9ICJHaeG6o2kgdGjDrWNoIGPDoWMgbeG7qWMgdHJvbmcgYmnhur9uIG1hcml0YWwuc3RhdHVzIikKCmBgYAoKIyMjIFRo4buRbmcga8OqIFThuqduIHN14bqldApgYGB7cn0KIyBU4bqhbyBi4bqjbmcgdOG6p24gc3XhuqV0IGNobyBtYXJpdGFsLnN0YXR1cwp0c19tYXJpdGFsIDwtIHRhYmxlKGQkbWFyaXRhbC5zdGF0dXMpCgojIFThuqFvIGLhuqNuZyBk4buvIGxp4buHdQp0c19tYXJpdGFsX2RmIDwtIGRhdGEuZnJhbWUoCiAgR2lhX3RyaSA9IG5hbWVzKHRzX21hcml0YWwpLAogIFRhbl9zbyA9IGFzLnZlY3Rvcih0c19tYXJpdGFsKSwKICBUeV9sZSA9IHJvdW5kKChhcy52ZWN0b3IodHNfbWFyaXRhbCkgLyBzdW0odHNfbWFyaXRhbCkpICogMTAwLCAyKQopCgojIEhp4buDbiB0aOG7iyBr4bq/dCBxdeG6owp0c19tYXJpdGFsX2RmCgoKYGBgCgotIMSQw6MgbHkgZOG7iyAoRGl2b3JjZWQpOiBjw7MgYHIgdHNfbWFyaXRhbF9kZiRUYW5fc29bdHNfbWFyaXRhbF9kZiRHaWFfdHJpID09ICJEaXZvcmNlZCJdYCBuZ8aw4budaSAoY2hp4bq/bSBgciBwYXN0ZTAodHNfbWFyaXRhbF9kZiRUeV9sZVt0c19tYXJpdGFsX2RmJEdpYV90cmkgPT0gIkRpdm9yY2VkIl0sICIlIilgKS4KCi0gS+G6v3QgaMO0biB24bubaSBuZ8aw4budaSB0cm9uZyBxdcOibiDEkeG7mWkgKE1hcnJpZWQtQUYtc3BvdXNlKTogY8OzIGByIHRzX21hcml0YWxfZGYkVGFuX3NvW3RzX21hcml0YWxfZGYkR2lhX3RyaSA9PSAiTWFycmllZC1BRi1zcG91c2UiXWAgbmfGsOG7nWkgKGNoaeG6v20gYHIgcGFzdGUwKHRzX21hcml0YWxfZGYkVHlfbGVbdHNfbWFyaXRhbF9kZiRHaWFfdHJpID09ICJNYXJyaWVkLUFGLXNwb3VzZSJdLCAiJSIpYCkuCgotIMSQw6Mga+G6v3QgaMO0biBo4bujcCBwaMOhcCAoTWFycmllZC1jaXYtc3BvdXNlKTogY8OzIGByIHRzX21hcml0YWxfZGYkVGFuX3NvW3RzX21hcml0YWxfZGYkR2lhX3RyaSA9PSAiTWFycmllZC1jaXYtc3BvdXNlIl1gIG5nxrDhu51pIChjaGnhur9tIGByIHBhc3RlMCh0c19tYXJpdGFsX2RmJFR5X2xlW3RzX21hcml0YWxfZGYkR2lhX3RyaSA9PSAiTWFycmllZC1jaXYtc3BvdXNlIl0sICIlIilgKS4KCi0gTHkgdGjDom4gKE1hcnJpZWQtc3BvdXNlLWFic2VudCk6IGPDsyBgciB0c19tYXJpdGFsX2RmJFRhbl9zb1t0c19tYXJpdGFsX2RmJEdpYV90cmkgPT0gIk1hcnJpZWQtc3BvdXNlLWFic2VudCJdYCBuZ8aw4budaSAoY2hp4bq/bSBgciBwYXN0ZTAodHNfbWFyaXRhbF9kZiRUeV9sZVt0c19tYXJpdGFsX2RmJEdpYV90cmkgPT0gIk1hcnJpZWQtc3BvdXNlLWFic2VudCJdLCAiJSIpYCkuCgotIENoxrBhIHThu6tuZyBr4bq/dCBow7RuIChOZXZlci1tYXJyaWVkKTogY8OzIGByIHRzX21hcml0YWxfZGYkVGFuX3NvW3RzX21hcml0YWxfZGYkR2lhX3RyaSA9PSAiTmV2ZXItbWFycmllZCJdYCBuZ8aw4budaSAoY2hp4bq/bSBgciBwYXN0ZTAodHNfbWFyaXRhbF9kZiRUeV9sZVt0c19tYXJpdGFsX2RmJEdpYV90cmkgPT0gIk5ldmVyLW1hcnJpZWQiXSwgIiUiKWApLgoKLSBMeSB0aMOibiBjw7MgcGjDoXAgbMO9IChTZXBhcmF0ZWQpOiBjw7MgYHIgdHNfbWFyaXRhbF9kZiRUYW5fc29bdHNfbWFyaXRhbF9kZiRHaWFfdHJpID09ICJTZXBhcmF0ZWQiXWAgbmfGsOG7nWkgKGNoaeG6v20gYHIgcGFzdGUwKHRzX21hcml0YWxfZGYkVHlfbGVbdHNfbWFyaXRhbF9kZiRHaWFfdHJpID09ICJTZXBhcmF0ZWQiXSwgIiUiKWApLgoKLSBHw7NhIChXaWRvd2VkKTogY8OzIGByIHRzX21hcml0YWxfZGYkVGFuX3NvW3RzX21hcml0YWxfZGYkR2lhX3RyaSA9PSAiV2lkb3dlZCJdYCBuZ8aw4budaSAoY2hp4bq/bSBgciBwYXN0ZTAodHNfbWFyaXRhbF9kZiRUeV9sZVt0c19tYXJpdGFsX2RmJEdpYV90cmkgPT0gIldpZG93ZWQiXSwgIiUiKWApLgoKCiMjIyBUcuG7sWMgcXVhbiBow7NhCmBgYHtyIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02fQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdCh0c19tYXJpdGFsX2RmLCBhZXMoeCA9IHJlb3JkZXIoR2lhX3RyaSwgLVRhbl9zbyksIHkgPSBUYW5fc28sIGZpbGwgPSBHaWFfdHJpKSkgKwogIGdlb21fY29sKHdpZHRoID0gMC41LCBjb2xvciA9ICJ3aGl0ZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gVGFuX3NvKSwgdmp1c3QgPSAtMC4zLCBzaXplID0gNCwgZm9udGZhY2UgPSAiYm9sZCIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQmnhu4N1IMSR4buTIGPhu5l0OiBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gKG1hcml0YWwuc3RhdHVzKSIsCiAgICB4ID0gIlTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiIsCiAgICB5ID0gIlThuqduIHPhu5EiCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgCiAgKQoKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0KZ2dwbG90KHRzX21hcml0YWxfZGYsIGFlcyh4ID0gcmVvcmRlcihHaWFfdHJpLCBUeV9sZSksIHkgPSBUeV9sZSwgZmlsbCA9IEdpYV90cmkpKSArCiAgZ2VvbV9jb2wod2lkdGggPSAwLjYsIGNvbG9yID0gIndoaXRlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAoVHlfbGUsICIlIikpLAogICAgICAgICAgICBoanVzdCA9IC0wLjEsIHNpemUgPSA0LCBmb250ZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQmnhu4N1IMSR4buTIGPhu5l0IG5nYW5nOiBU4bu3IGzhu4cgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIChtYXJpdGFsLnN0YXR1cykiLAogICAgeCA9ICJUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4iLAogICAgeSA9ICJU4bu3IGzhu4cgKCUpIgogICkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpCiAgKQoKYGBgCgojIyMgTmjhuq1uIHjDqXQKCi0gIk1hcnJpZWQtY2l2LXNwb3VzZSIgKGvhur90IGjDtG4gaOG7o3AgcGjDoXApIGNoaeG6v20gNDMuOTQlLCBjYW8gbmjhuqV0IHRyb25nIHRvw6BuIGLhu5kgZOG7ryBsaeG7h3Ug4oCTIGNobyB0aOG6pXkgY+G6pXUgdHLDumMgZ2lhIMSRw6xuaCB0cnV54buBbiB0aOG7kW5nIHbhuqtuIGNoaeG6v20gxrB1IHRo4bq/LgoKLSAiTmV2ZXItbWFycmllZCIgxJHhuqF0IDMyLjgxJSwgbMOgIG5ow7NtIGzhu5tuIHRo4bupIGhhaSwgcGjhuqNuIMOhbmggc+G7sSBoaeG7h24gZGnhu4duIG3huqFuaCBt4bq9IGPhu6dhIG5nxrDhu51pIMSR4buZYyB0aMOibi4KCi0gQ8OhYyBuaMOzbSBjw7JuIGzhuqFpIG5oxrAgIkRpdm9yY2VkIiAoMTIuMjklKSwgIk1hcnJpZWQtc3BvdXNlLWFic2VudCIgKDQuNzklKSwgIlNlcGFyYXRlZCIgKDMuMTMlKSwgdsOgICJXaWRvd2VkIiAoMy4wNSUpIGfDs3AgcGjhuqduIHThuqFvIG7Dqm4gdMOtbmggxJFhIGThuqFuZyB0cm9uZyB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4sIG5oxrBuZyDEkeG7gXUgY2hp4bq/bSB04bu3IGzhu4cgdGjhuqVwIGjGoW4KCgoKIyMgKipCaeG6v24gaW5jb21lKioKCiMjIyBHaeG6o2kgdGjDrWNoIGJp4bq/bgoKYGBge3J9CiMgR2nhuqNpIHRow61jaCBjw6FjIG3hu6ljIGPhu6dhIGJp4bq/biBpbmNvbWUKaW5jb21lX2xldmVscyA8LSBkYXRhLmZyYW1lKAogIEdpYV90cmkgPSBjKCI8PTUwSyIsICI+NTBLIiksCiAgWV9uZ2hpYSA9IGMoIlRodSBuaOG6rXAgZMaw4bubaSBob+G6t2MgYuG6sW5nIDUwLjAwMCBVU0QvbsSDbSIsICJUaHUgbmjhuq1wIHRyw6puIDUwLjAwMCBVU0QvbsSDbSIpCikKCmtuaXRyOjprYWJsZShpbmNvbWVfbGV2ZWxzLCBjYXB0aW9uID0gIkdp4bqjaSB0aMOtY2ggY8OhYyBt4bupYyB0cm9uZyBiaeG6v24gaW5jb21lIikKYGBgCgojIyMgVGjhu5FuZyBrw6ogVOG6p24gc3XhuqV0CmBgYHtyfQojIFThuqFvIGLhuqNuZyB04bqnbiBzdeG6pXQgY2hvIGluY29tZQp0c19pbmNvbWUgPC0gdGFibGUoZCRpbmNvbWUpCgojIFThuqFvIGLhuqNuZyBk4buvIGxp4buHdQp0c19pbmNvbWVfZGYgPC0gZGF0YS5mcmFtZSgKICBHaWFfdHJpID0gbmFtZXModHNfaW5jb21lKSwKICBZX25naGlhID0gYygi4omkNTBLIiwgIj41MEsiKSwKICBUYW5fc28gPSBhcy52ZWN0b3IodHNfaW5jb21lKSwKICBUeV9sZSA9IHJvdW5kKChhcy52ZWN0b3IodHNfaW5jb21lKSAvIHN1bSh0c19pbmNvbWUpKSAqIDEwMCwgMikKKQoKIyBIaeG7g24gdGjhu4sga+G6v3QgcXXhuqMKdHNfaW5jb21lX2RmCgpgYGAKCi0gQmnhur9uIGBpbmNvbWVgICh0aHUgbmjhuq1wKSBjw7MgMiBt4bupYzoKCiAgLSAqKlRodSBuaOG6rXAgZMaw4bubaSBob+G6t2MgYuG6sW5nIDUwSyoqIChgPD01MEtgKTogYHIgdHNfaW5jb21lX2RmJFRhbl9zb1t0c19pbmNvbWVfZGYkR2lhX3RyaSA9PSAiPD01MEsiXWAgbmfGsOG7nWkgKGNoaeG6v20gYHIgcGFzdGUwKHRzX2luY29tZV9kZiRUeV9sZVt0c19pbmNvbWVfZGYkR2lhX3RyaSA9PSAiPD01MEsiXSwgIiUiKWApLgoKLSAqKlRodSBuaOG6rXAgdHLDqm4gNTBLKiogKGA+NTBLYCk6IGByIHRzX2luY29tZV9kZiRUYW5fc29bdHNfaW5jb21lX2RmJEdpYV90cmkgPT0gIj41MEsiXWAgbmfGsOG7nWkgKGNoaeG6v20gYHIgcGFzdGUwKHRzX2luY29tZV9kZiRUeV9sZVt0c19pbmNvbWVfZGYkR2lhX3RyaSA9PSAiPjUwSyJdLCAiJSIpYCkuCgoKIyMjIFRy4buxYyBxdWFuIGjDs2EKYGBge3J9CmdncGxvdCh0c19pbmNvbWVfZGYsIGFlcyh4ID0gR2lhX3RyaSwgeSA9IFRhbl9zbywgZmlsbCA9IEdpYV90cmkpKSArCiAgZ2VvbV9jb2wod2lkdGggPSAwLjUsIGNvbG9yID0gIndoaXRlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBUYW5fc28pLCB2anVzdCA9IC0wLjMsIHNpemUgPSA0LCBmb250ZmFjZSA9ICJib2xkIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJCaeG7g3UgxJHhu5MgY+G7mXQ6IFRodSBuaOG6rXAgKGluY29tZSkiLAogICAgeCA9ICJOaMOzbSB0aHUgbmjhuq1wIiwKICAgIHkgPSAiVOG6p24gc+G7kSIKICApICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjNkQ1OTdBIiwgIiNGRkI3MDMiKSkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgCiAgKQoKYGBgCgpgYGB7cn0KaW5jb21lX2NvbG9ycyA8LSBjKCI8PTUwSyIgPSAiI0ZEQjg2MyIsICI+NTBLIiA9ICIjNUUzQzk5IikKCmdncGxvdCh0c19pbmNvbWVfZGYsIGFlcyh4ID0gIiIsIHkgPSBUeV9sZSwgZmlsbCA9IEdpYV90cmkpKSArCiAgZ2VvbV9jb2wod2lkdGggPSAxLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGluY29tZV9jb2xvcnMpICsKICBsYWJzKHRpdGxlID0gIkJp4buDdSDEkeG7kyB0csOybjogVGh1IG5o4bqtcCIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKFR5X2xlLCAiJSIpKSwKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksCiAgICAgICAgICAgIHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkKICApCmBgYAoKIyMjIE5o4bqtbiB4w6l0CgotIE5ow7NtIGPDsyB0aHUgbmjhuq1wIDw9NTBLIGNoaeG6v20gNzUuOTIlLCBjaG8gdGjhuqV5IHBo4bqnbiBs4bubbiBuZ8aw4budaSB0cm9uZyBt4bqrdSBraOG6o28gc8OhdCBjw7MgdGh1IG5o4bqtcCB0aOG6pXAgaMahbiBuZ8aw4buhbmcgdHJ1bmcgYsOsbmguCgotIENo4buJIDI0LjA4JSB0aHXhu5ljIG5ow7NtIHRodSBuaOG6rXAgPjUwSywgcGjhuqNuIMOhbmggbeG7qWMgdGh1IG5o4bqtcCBjYW8gbMOgIHRoaeG7g3Ugc+G7kSB0cm9uZyBj4buZbmcgxJHhu5NuZyDEkcaw4bujYyBraOG6o28gc8OhdC4KCgojIMav4bubYyBsxrDhu6NuZyBLaG/huqNuZyB2w6AgS2nhu4NtIMSR4buLbmggR2nhuqMgdGh1eeG6v3QgY2hvIFThu7cgbOG7hwoKIyMgIFjDoWMgxJHhu4tuaCBI4bqhbmcgbeG7pWMgUXVhbiB0w6JtCgotIEjhuqFuZyBt4bulYyDigJxOZXZlci1tYXJyaWVk4oCdIGPhu6dhIGJp4bq/biBNYXJpdGFsU3RhdHVzIOKAkyBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4KCiMjICDGr+G7m2MgbMaw4bujbmcgS2hv4bqjbmcgVGluIGPhuq15IHbDoCBLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dAoKIyMjIEjhuqFuZyBt4bulYyDigJxOZXZlci1tYXJyaWVk4oCdIGPhu6dhIGJp4bq/biBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gKG1hcml0YWwuc3RhdHVzKSAKCmBgYHtyfQojIFPhu5EgbmfGsOG7nWkgY2jGsGEgdOG7q25nIGvhur90IGjDtG4Kbl9uZXZlcl9tYXJyaWVkIDwtIHN1bShkJG1hcml0YWwuc3RhdHVzID09ICJOZXZlci1tYXJyaWVkIikKCiMgVOG7lW5nIHPhu5EgcXVhbiBzw6F0Cm5fdG90YWwgPC0gbnJvdyhkKQoKIyDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIG5nxrDhu51pIGNoxrBhIHThu6tuZyBr4bq/dCBow7RuCnByb3AudGVzdChuX25ldmVyX21hcnJpZWQsIG5fdG90YWwsIGNvbmYubGV2ZWwgPSAwLjk1KQoKYGBgCipQaMOibiB0w61jaCBr4bq/dCBxdeG6oyoKCi0gUGjDqXAga2nhu4NtIMSR4buLbmggxJHGsOG7o2Mgc+G7rSBk4bulbmcgbMOgIGtp4buDbSDEkeG7i25oIHThu7cgbOG7hyAxIG3huqt1ICgxLXNhbXBsZSBwcm9wb3J0aW9ucyB0ZXN0KSB24bubaSBjaOG7iW5oIGxpw6puIHThu6VjLCBuaOG6sW0gY+G6o2kgdGhp4buHbiDEkeG7mSBjaMOtbmggeMOhYyBraGkgc+G7rSBk4bulbmcgcGjDom4gcGjhu5FpIHjhuqVwIHjhu4kuCgotIEThu68gbGnhu4d1IMSR4bqndSB2w6BvOiDEkWFuZyBraeG7g20gxJHhu4tuaCB04bu3IGzhu4cgbmfGsOG7nWkgY8OzIHTDrG5oIHRy4bqhbmcgIk5ldmVyLW1hcnJpZWQiIChuX25ldmVyX21hcnJpZWQpIHRyb25nIHThu5VuZyBz4buRIHF1YW4gc8OhdCAobl90b3RhbCksIHbhu5tpIGdp4bqjIHRodXnhur90IGfhu5FjIEjigoA6IHAgPSAwLjUuCgotIEdpw6EgdHLhu4sgdGjhu5FuZyBrw6oga2nhu4NtIMSR4buLbmggbMOgIFgtc3F1YXJlZCA9IDM4NDguMyB24bubaSBkZiA9IDEsIGNobyB0aOG6pXkgbeG7qWMgxJHhu5kgY2jDqm5oIGzhu4djaCBs4bubbiBnaeG7r2EgdOG7tyBs4buHIHF1YW4gc8OhdCB2w6AgdOG7tyBs4buHIGdp4bqjIMSR4buLbmguCgotIEdpw6EgdHLhu4sgcC12YWx1ZSA8IDIuMmUtMTYsIGPhu7FjIGvhu7Mgbmjhu48sIMSR4buTbmcgbmdoxKlhIHbhu5tpIHZp4buHYyBr4bq/dCBxdeG6oyBsw6AgcuG6pXQgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiDigJMgeMOhYyBzdeG6pXQgeOG6o3kgcmEgc2FpIGzhuqdtIGtoaSBiw6FjIGLhu48gSOKCgCBn4bqnbiBuaMawIGLhurFuZyAwLgoKLSBHaeG6oyB0aHV54bq/dCDEkeG7kWkgKEjigoEpOiBU4bu3IGzhu4cgdGjhu7FjIHPhu7Ega2jDoWMgMC41IChraeG7g20gxJHhu4tuaCBoYWkgcGjDrWE6IGtow6FjIGzhu5tuIGjGoW4gaG/hurdjIG5o4buPIGjGoW4gxJHhu4F1IMSRxrDhu6NjIHhlbSB4w6l0KS4KCi0gS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIG5nxrDhu51pIGNoxrBhIGvhur90IGjDtG4gbuG6sW0gdHJvbmcga2hv4bqjbmcgWzMyLjMwJTsgMzMuMzIlXSwgdGjhu4MgaGnhu4duIHThu7cgbOG7hyB0aOG7sWMgc+G7sSBraMOhIOG7lW4gxJHhu4tuaCBxdWFuaCBt4bupYyAzMyUuCgotIFThu7cgbOG7hyBt4bqrdSDGsOG7m2MgbMaw4bujbmcgbMOgIDMyLjgxJSwgdOG7qWMgbMOgIGfhuqduIDEvMyBkw6JuIHPhu5EgdHJvbmcgbeG6q3Uga2jhuqNvIHPDoXQgY2jGsGEgdOG7q25nIGvhur90IGjDtG4uCgoqKkLDoGkgdG/DoW4ga2nhu4NtIMSR4buLbmg6KioKCkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oOgoKR2nhuqMgdGh1eeG6v3Qga2jDtG5nIEjigoA6IHAgPSAwLjUgKHThu7cgbOG7hyBuZ8aw4budaSBjaMawYSB04burbmcga+G6v3QgaMO0biBi4bqxbmcgNTAlKQoKR2nhuqMgdGh1eeG6v3QgxJHhu5FpIEjigoE6IHAg4omgIDAuNSAodOG7tyBs4buHIG5nxrDhu51pIGNoxrBhIHThu6tuZyBr4bq/dCBow7RuIGtow6FjIDUwJSkKCk3hu6ljIMO9IG5naMSpYTogzrEgPSAwLjA1CgpL4bq/dCBsdeG6rW46CgpW4bubaSBwLXZhbHVlIDwgMi4yZS0xNiA8IDAuMDUsIHRhIGLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCBI4oKALgoKQ8OzIGLhurFuZyBjaOG7qW5nIHRo4buRbmcga8OqIG3huqFuaCBjaG8gdGjhuqV5IHThu7cgbOG7hyBuZ8aw4budaSBjaMawYSB04burbmcga+G6v3QgaMO0biBraMOhYyA1MCUsIHbhu5tpIMSR4buZIHRpbiBj4bqteSA5NSUuCgpU4bu3IGzhu4cgxrDhu5tjIGzGsOG7o25nIGzDoCAzMi44MSUsIHbhu5tpIGtob+G6o25nIHRpbiBj4bqteSBu4bqxbSB0cm9uZyBbMzIuMzAlOyAzMy4zMiVdLiBU4bu3IGzhu4cgbsOgeSB0aOG6pXAgaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBt4bupYyA1MCUsIHbDoCBz4buxIGNow6puaCBs4buHY2ggKH4xNyDEkWnhu4NtIHBo4bqnbiB0csSDbSkgbMOgIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogcsO1IHLhu4d0LgoKCgojIFBow6JuIHTDrWNoIE3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgSGFpIGJp4bq/biDEkOG7i25oIHTDrW5oIChCaXZhcmlhdGUgQW5hbHlzaXMpCgpDaOG7jW4gY+G6t3AgYmnhur9uIMSR4buLbmggdMOtbmggOgoKIyMgTWFyaXRhbC5zdGF0dXMg4oCTIEluY29tZQoKIyMjICBC4bqjbmcgdOG6p24gc+G7kSBjaMOpbwpgYGB7cn0KIyBC4bqjbmcgdOG6p24gc+G7kSBjaMOpbyB2w6AgdOG7tyBs4buHIHRoZW8gaMOgbmcgZ2nhu69hIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiB2w6AgdGh1IG5o4bqtcAp0YWJsZV9tYXJpdGFsX2luY29tZSA8LSB0YWJsZShkJG1hcml0YWwuc3RhdHVzLCBkJGluY29tZSkgICAgICAgICAgICAgICMgQuG6o25nIHThuqduIHPhu5EgY2jDqW8KdGFibGVfbWFyaXRhbF9pbmNvbWUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEhp4buDbiB0aOG7iyBi4bqjbmcKCnByb3AudGFibGUodGFibGVfbWFyaXRhbF9pbmNvbWUsIG1hcmdpbiA9IDEpICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUw61uaCB04bu3IGzhu4cgdGhlbyB04burbmcgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuCgoKYGBgCi0gVHJvbmcgbmjDs20gTWFycmllZC1jaXYtc3BvdXNlOiBjw7MgOCwyODQgbmfGsOG7nWkgdGh1IG5o4bqtcCA8PTUwSyB2w6AgNiw2OTIgbmfGsOG7nWkgdGh1IG5o4bqtcCA+NTBLIOKGkiB04bu3IGzhu4cgPjUwSyBsw6AgNDQuNyUuCgotIFRyb25nIG5ow7NtIE5ldmVyLW1hcnJpZWQ6IGPDsyAxMCwxOTIgbmfGsOG7nWkgdGh1IG5o4bqtcCA8PTUwSyB2w6AgNDkxIG5nxrDhu51pIHRodSBuaOG6rXAgPjUwSyDihpIgdOG7tyBs4buHID41MEsgbMOgIDQuNiUuCgotIFRyb25nIG5ow7NtIERpdm9yY2VkOiBjw7MgMyw5ODAgbmfGsOG7nWkgdGh1IG5o4bqtcCA8PTUwSyB2w6AgNDYzIG5nxrDhu51pIHRodSBuaOG6rXAgPjUwSyDihpIgdOG7tyBs4buHID41MEsgbMOgIDEwLjQlLgoKLSBUcm9uZyBuaMOzbSBNYXJyaWVkLXNwb3VzZS1hYnNlbnQ6IGPDsyAzODQgbmfGsOG7nWkgdGh1IG5o4bqtcCA8PTUwSyB2w6AgMzQgbmfGsOG7nWkgdGh1IG5o4bqtcCA+NTBLIOKGkiB04bu3IGzhu4cgPjUwSyBsw6AgOC4xJS4KCi0gVHJvbmcgbmjDs20gV2lkb3dlZDogY8OzIDkwOCBuZ8aw4budaSB0aHUgbmjhuq1wIDw9NTBLIHbDoCA4NSBuZ8aw4budaSB0aHUgbmjhuq1wID41MEsg4oaSIHThu7cgbOG7hyA+NTBLIGzDoCA4LjYlLgoKLSBUcm9uZyBuaMOzbSBTZXBhcmF0ZWQ6IGPDsyA5NTkgbmfGsOG7nWkgdGh1IG5o4bqtcCA8PTUwSyB2w6AgNjYgbmfGsOG7nWkgdGh1IG5o4bqtcCA+NTBLIOKGkiB04bu3IGzhu4cgPjUwSyBsw6AgNi40JS4KCi0gVHJvbmcgbmjDs20gTWFycmllZC1BRi1zcG91c2U6IGPDsyAxMyBuZ8aw4budaSB0aHUgbmjhuq1wIDw9NTBLIHbDoCAxMCBuZ8aw4budaSB0aHUgbmjhuq1wID41MEsg4oaSIHThu7cgbOG7hyA+NTBLIGzDoCA0My41JSAobmjGsG5nIG3huqt1IG5o4buPKS4KCkvhur90IGx14bqtbjoK4oaSIE5ow7NtIE1hcnJpZWQtY2l2LXNwb3VzZSBjw7MgdOG7tyBs4buHIHRodSBuaOG6rXAgPjUwSyBjYW8gbmjhuqV0IHRyb25nIGPDoWMgbmjDs20gxJHDtG5nIGTDom4gc+G7kSwgdHJvbmcga2hpIG5ow7NtIE5ldmVyLW1hcnJpZWQgY8OzIHThu7cgbOG7hyB0aOG6pXAgbmjhuqV0LgrihpIgxJBp4buBdSBuw6B5IHBo4bqjbiDDoW5oIHPhu7EgY2jDqm5oIGzhu4djaCDEkcOhbmcga+G7gyB24buBIHRodSBuaOG6rXAgdGhlbyB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4sIMSR4bq3YyBiaeG7h3QgbMOgIGzhu6NpIHRo4bq/IGPhu6dhIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biBo4bujcCBwaMOhcC4KCgojIyMgIFRy4buxYyBxdWFuIGjDs2EKYGBge3IgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CiMgVOG6oW8gYuG6o25nIGThu68gbGnhu4d1IHThu6sgYuG6o25nIHThuqduIHN14bqldCBjaMOpbwp0YWJsZV9tYXJpdGFsX2luY29tZSA8LSB0YWJsZShkJG1hcml0YWwuc3RhdHVzLCBkJGluY29tZSkKZGZfZ3JvdXBfbWFyaXRhbCA8LSBhcy5kYXRhLmZyYW1lKGFzLnRhYmxlKHRhYmxlX21hcml0YWxfaW5jb21lKSkKY29sbmFtZXMoZGZfZ3JvdXBfbWFyaXRhbCkgPC0gYygiTWFyaXRhbFN0YXR1cyIsICJJbmNvbWUiLCAiRnJlcSIpCgojIFbhur0gYmnhu4N1IMSR4buTIGPhu5l0IG5ow7NtCmdncGxvdChkZl9ncm91cF9tYXJpdGFsLCBhZXMoeCA9IE1hcml0YWxTdGF0dXMsIHkgPSBGcmVxLCBmaWxsID0gSW5jb21lKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjYpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRnJlcSksCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLAogICAgICAgICAgICB2anVzdCA9IC0wLjQsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIsIGZvbnRmYWNlID0gImJvbGQiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICB2YWx1ZXMgPSBjKCI8PTUwSyIgPSAiI0ZGQTA3QSIsICI+NTBLIiA9ICIjMjBCMkFBIiksCiAgICBuYW1lID0gIlRodSBuaOG6rXAiCiAgKSArCiAgbGFicyh0aXRsZSA9ICJCaeG7g3UgxJHhu5MgY+G7mXQgbmjDs206IE1hcml0YWxTdGF0dXMgdnMgSW5jb21lIiwKICAgICAgIHggPSAiVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIiwKICAgICAgIHkgPSAiVOG6p24gc+G7kSIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIKICApCgpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02fQojIFThuqFvIGLhuqNuZyBk4buvIGxp4buHdSB04burIGLhuqNuZyB04bqnbiBzdeG6pXQgY2jDqW8KdGFibGVfbWFyaXRhbF9pbmNvbWUgPC0gdGFibGUoZCRtYXJpdGFsLnN0YXR1cywgZCRpbmNvbWUpCmRmX3N0YWNrX21hcml0YWwgPC0gYXMuZGF0YS5mcmFtZShhcy50YWJsZSh0YWJsZV9tYXJpdGFsX2luY29tZSkpCmNvbG5hbWVzKGRmX3N0YWNrX21hcml0YWwpIDwtIGMoIk1hcml0YWxTdGF0dXMiLCAiSW5jb21lIiwgIkZyZXEiKQoKIyBW4bq9IGJp4buDdSDEkeG7kyBj4buZdCBjaOG7k25nIApnZ3Bsb3QoZGZfc3RhY2tfbWFyaXRhbCwgYWVzKHggPSBNYXJpdGFsU3RhdHVzLCB5ID0gRnJlcSwgZmlsbCA9IEluY29tZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjYpICsKICBnZW9tX3RleHQoCiAgICBhZXMobGFiZWwgPSBGcmVxKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgdmp1c3QgPSAwLjUsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIsIGZvbnRmYWNlID0gImJvbGQiCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICB2YWx1ZXMgPSBjKCI8PTUwSyIgPSAiI0ZGQTA3QSIsICI+NTBLIiA9ICIjMjBCMkFBIiksCiAgICBuYW1lID0gIlRodSBuaOG6rXAiCiAgKSArCiAgbGFicygKICAgIHRpdGxlID0gIkJp4buDdSDEkeG7kyBj4buZdCBjaOG7k25nOiBNYXJpdGFsU3RhdHVzIHZzIEluY29tZSIsCiAgICB4ID0gIlTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiIsCiAgICB5ID0gIlThuqduIHPhu5EiCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiCiAgKQoKYGBgCgojIyMgIE5o4bqtbiB4w6l0IG3DtCB04bqjCgotIEJp4buDdSDEkeG7kyBj4buZdCBuaMOzbSBjaG8gdGjhuqV5IG5o4buvbmcgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIGjhu6NwIHBow6FwIChNYXJyaWVkLWNpdi1zcG91c2UpIGPDsyBz4buRIGzGsOG7o25nIHbGsOG7o3QgdHLhu5lpIOG7nyBuaMOzbSB0aHUgbmjhuq1wID41MEsg4oCTIHRoYW5oIGPhu5l0IOG7nyBuaMOzbSBuw6B5IGNhbyByw7UgcuG7h3QuCgotIE5nxrDhu6NjIGzhuqFpLCBuaMOzbSBOZXZlci1tYXJyaWVkIGfhuqduIG5oxrAgY2jhu4kgeHXhuqV0IGhp4buHbiDhu58gbeG7qWMgdGh1IG5o4bqtcCB0aOG6pXAuIEPDoWMgbmjDs20gIkRpdm9yY2VkIiBoYXkgIlNlcGFyYXRlZCIgY8WpbmcgY8OzIHThu7cgbOG7hyB0aHUgbmjhuq1wIGNhbyBy4bqldCB0aOG6pXAuCgotIEJp4buDdSDEkeG7kyBj4buZdCBjaOG7k25nIGNobyB0aOG6pXkgY+G7mXQgY+G7p2EgbmjDs20gTWFycmllZC1jaXYtc3BvdXNlIGPDsyBwaOG6p24gbcOgdSB0aHUgbmjhuq1wIGNhbyBjaGnhur9tIGfhuqduIG3hu5l0IG7hu61hLCB0cm9uZyBraGkgY8OhYyBuaMOzbSBraMOhYyBwaOG6p24gbcOgdSBuw6B5IHLhuqV0IG3hu49uZy4KCuKGkiBL4bq/dCBsdeG6rW4gdHLhu7FjIHF1YW46IFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiBjw7MgbGnDqm4gcXVhbiBjaOG6t3QgY2jhur0gxJHhur9uIHRodSBuaOG6rXAuIEJp4buDdSDEkeG7kyBwaOG6o24gw6FuaCByw7UgcuG6sW5nIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biBjw7MgbOG7o2kgdGjhur8gbOG7m24gduG7gSBraW5oIHThur8gc28gduG7m2kgY8OhYyBuaMOzbSBjw7JuIGzhuqFpLgoKIyMjICBLaeG7g20gxJHhu4tuaCB0aOG7kW5nIGvDqihLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcpCgoqKkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oOioqCgoqKkjigoAgKEdp4bqjIHRodXnhur90IGtow7RuZykqKjpUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gdsOgIG3hu6ljIHRodSBuaOG6rXAgxJHhu5ljIGzhuq1wIHbhu5tpIG5oYS4KCioqSOKCgSAoR2nhuqMgdGh1eeG6v3QgxJHhu5FpKSoqOlTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiB2w6AgbeG7qWMgdGh1IG5o4bqtcCBjw7MgbeG7kWkgbGnDqm4gaOG7hyB24bubaSBuaGF1LgoKYGBge3J9CmNoaXNxLnRlc3QodGFibGVfbWFyaXRhbF9pbmNvbWUpCmBgYAoqKkvhur90IHF14bqjIGtp4buDbSDEkeG7i25oOioqCgpDaGktc3F1YXJlZCA9IDY1MTcuNzQKCkLhuq1jIHThu7EgZG8gKGRmKSA9IDYKCkdpw6EgdHLhu4sgcC12YWx1ZSA9IDAuMDAwMAoKKipL4bq/dCBsdeG6rW4gdGjhu5FuZyBrw6o6KioKClbDrCBwIDwgMC4wNSwgdGEgYsOhYyBi4buPIGdp4bqjIHRodXnhur90IEjigoAuCgpDw7MgbeG7kWkgbGnDqm4gaOG7hyB0aOG7kW5nIGvDqiByw7UgcuG7h3QgZ2nhu69hIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiB2w6AgbeG7qWMgdGh1IG5o4bqtcAoKKipUaOG6o28gbHXhuq1uIHRow6ptIHbhu4EgYuG6o24gY2jhuqV0IG3hu5FpIHF1YW4gaOG7hzoqKgoKQmnhu4N1IMSR4buTIGNobyB0aOG6pXkgbmjDs20gxJHDoyBr4bq/dCBow7RuIChNYXJyaWVkLWNpdi1zcG91c2UpIGPDsyBwaOG6p24gdGh1IG5o4bqtcCA+NTBLIGNoaeG6v20gxrB1IHRo4bq/IHR1eeG7h3QgxJHhu5FpLgoKTmfGsOG7o2MgbOG6oWksIG5ow7NtIMSR4buZYyB0aMOibiAoTmV2ZXItbWFycmllZCkgaOG6p3UgbmjGsCBjaOG7iSB04bqtcCB0cnVuZyDhu58gbeG7qWMgdGh1IG5o4bqtcCB0aOG6pXAuCgpDw6FjIG5ow7NtIGx5IGjDtG4sIGx5IHRow6JuLCBob+G6t2MgZ8OzYSBjxaluZyBjw7MgdOG7tyBs4buHIHRodSBuaOG6rXAgY2FvIHRo4bqlcCDEkcOhbmcga+G7gy4KCuKGkiBHaeG6o2kgdGjDrWNoIG3hu5FpIGxpw6puIGjhu4c6IEtp4buDbSDEkeG7i25oIGNobyB0aOG6pXkgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIGtow7RuZyBjaOG7iSBsacOqbiBxdWFuIMSR4bq/biB0aHUgbmjhuq1wLCBtw6AgY8OybiBjw7MgeHUgaMaw4bubbmcgcsO1IHLDoG5nIOKAkyBuZ8aw4budaSDEkcOjIGzhuq1wIGdpYSDEkcOsbmggY8OzIG5oaeG7gXUga2jhuqMgbsSDbmcgxJHhuqF0IHRodSBuaOG6rXAgY2FvIGjGoW4uIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgcGjhuqNuIMOhbmggbeG7qWMgxJHhu5kg4buVbiDEkeG7i25oIHTDoGkgY2jDrW5oLCDEkeG7mSB0deG7lWksIGhv4bq3YyBjYW0ga+G6v3Qgbmdo4buBIG5naGnhu4dwIGNhbyBoxqFuIHRyb25nIG5ow7NtIMSRw6Mga+G6v3QgaMO0bi4KCiMjIyBIaeG7h3UgdOG7tyBs4buHCgpgYGB7cn0KIyBM4bqtcCBi4bqjbmcgdOG6p24gc+G7kSBjaMOpbyBnaeG7r2EgbWFyaXRhbC5zdGF0dXMgdsOgIGluY29tZQp0YWJsZV9tYXJpdGFsX2luY29tZSA8LSB0YWJsZShkJG1hcml0YWwuc3RhdHVzLCBkJGluY29tZSkKCiMgVGjDqm0gdOG7lW5nIGjDoG5nIHbDoCB04buVbmcgY+G7mXQKdGFibGVfbWFyaXRhbF9pbmNvbWUxIDwtIGFkZG1hcmdpbnModGFibGVfbWFyaXRhbF9pbmNvbWUpCgojIEhp4buDbiB0aOG7iyBi4bqjbmcKdGFibGVfbWFyaXRhbF9pbmNvbWUxCmBgYAoKLSBcKCBwXzEgPSBQKFx0ZXh0e2luY29tZX0gPSBcdGV4dHsiPjUwSyJ9IFxtaWQgXHRleHR7bWFyaXRhbC5zdGF0dXN9ID0gXHRleHR7Ik5ldmVyLW1hcnJpZWQifSkgXCkgKFThu7cgbOG7hyBuZ8aw4budaSBjaMawYSB04burbmcga+G6v3QgaMO0biBjw7MgdGh1IG5o4bqtcCBjYW8pCgotIFwoIHBfMiA9IFAoXHRleHR7aW5jb21lfSA9IFx0ZXh0eyI+NTBLIn0gXG1pZCBcdGV4dHttYXJpdGFsLnN0YXR1c30gPSBcdGV4dHsiTWFycmllZC1jaXYtc3BvdXNlIn0pIFwpIChU4bu3IGzhu4cgbmfGsOG7nWkgxJFhbmcga+G6v3QgaMO0biBo4bujcCBwaMOhcCBjw7MgdGh1IG5o4bqtcCBjYW8pCgpHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaDoKCi0gXCggSF8wOiBwXzEgLSBwXzIgPSAwIFwpIChLaMO0bmcgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IHbhu4EgdOG7tyBs4buHIHRodSBuaOG6rXAgY2FvIGdp4buvYSBoYWkgbmjDs20gdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuKQoKLSBcKCBIXzE6IHBfMSAtIHBfMiA8IDAgXCkgKFThu7cgbOG7hyB0aHUgbmjhuq1wIGNhbyDhu58gbmjDs20gIk5ldmVyLW1hcnJpZWQiIHRo4bqlcCBoxqFuIG5ow7NtICJNYXJyaWVkLWNpdi1zcG91c2UiKQoKYGBge3J9CiMgTOG6rXAgYuG6o25nIHThuqduIHPhu5EgY2jDqW8gZ2nhu69hIG1hcml0YWwuc3RhdHVzIHbDoCBpbmNvbWUKdGFibGVfbWFyaXRhbF9pbmNvbWUgPC0gdGFibGUoZCRtYXJpdGFsLnN0YXR1cywgZCRpbmNvbWUpCgojIFPhu5EgbmfGsOG7nWkgY8OzIHRodSBuaOG6rXAgPjUwSyB0cm9uZyB04burbmcgbmjDs20KY291bnRzX2luY29tZV9oaWdoIDwtIGModGFibGVfbWFyaXRhbF9pbmNvbWVbIk5ldmVyLW1hcnJpZWQiLCAiPjUwSyJdLAogICAgICAgICAgICAgICAgICAgICAgICB0YWJsZV9tYXJpdGFsX2luY29tZVsiTWFycmllZC1jaXYtc3BvdXNlIiwgIj41MEsiXSkKCiMgVOG7lW5nIHPhu5EgbmfGsOG7nWkgdHJvbmcgdOG7q25nIG5ow7NtCnRvdGFsc19pbmNvbWUgPC0gYyhzdW0odGFibGVfbWFyaXRhbF9pbmNvbWVbIk5ldmVyLW1hcnJpZWQiLCBdKSwKICAgICAgICAgICAgICAgICAgIHN1bSh0YWJsZV9tYXJpdGFsX2luY29tZVsiTWFycmllZC1jaXYtc3BvdXNlIiwgXSkpCgojIEtp4buDbSDEkeG7i25oIHThu4kgbOG7hyBt4buZdCBwaMOtYTogcDEgPCBwMgp0ZXN0X21hcml0YWxfaW5jb21lIDwtIHByb3AudGVzdChjb3VudHNfaW5jb21lX2hpZ2gsIHRvdGFsc19pbmNvbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsdGVybmF0aXZlID0gImxlc3MiLCBjb3JyZWN0ID0gRkFMU0UpCgojIEhp4buDbiB0aOG7iyBr4bq/dCBxdeG6owp0ZXN0X21hcml0YWxfaW5jb21lCmBgYApL4bq/dCBxdeG6oyBraeG7g20gxJHhu4tuaCBjaG8gdGjhuqV5OgoKLSBU4bu3IGzhu4cgbmfGsOG7nWkgY2jGsGEgdOG7q25nIGvhur90IGjDtG4gY8OzIHRodSBuaOG6rXAgPjUwSyAocHJvcCAxKSBsw6Aga2hv4bqjbmcgNC42MCUuCgotIFThu7cgbOG7hyBuZ8aw4budaSDEkWFuZyBr4bq/dCBow7RuIGjhu6NwIHBow6FwIGPDsyB0aHUgbmjhuq1wID41MEsgKHByb3AgMikgbMOgIGtob+G6o25nIDQ0LjY1JS4KClbhu5tpIHAtdmFsdWUgPCAyLjJlLTE2LCBuaOG7jyBoxqFuIG3hu6ljIMO9IG5naMSpYSAwLjA1LCBjaMO6bmcgdGEgY8OzIMSR4bunIGLhurFuZyBjaOG7qW5nIMSR4buDIGLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCBIMC4gxJBp4buBdSBuw6B5IGPDsyBuZ2jEqWEgbMOgOgoKLS0+IFThu7cgbOG7hyBuZ8aw4budaSBjaMawYSB04burbmcga+G6v3QgaMO0biBjw7MgdGh1IG5o4bqtcCBjYW8gdGjhuqVwIGjGoW4gdOG7tyBs4buHIG5nxrDhu51pIMSRYW5nIGvhur90IGjDtG4gaOG7o3AgcGjDoXAgbeG7mXQgY8OhY2ggY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqi4KCiMjIyBSZWxhdGl2ZSBSaXNrCgoqKkxp4buHdSB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gKMSRw6Mga+G6v3QgaMO0biB2cyBjaMawYSBiYW8gZ2nhu50ga+G6v3QgaMO0bikgY8OzIOG6o25oIGjGsOG7n25nIMSR4bq/biBuZ3V5IGPGoSBjw7MgdGh1IG5o4bqtcCBjYW8ga2jDtG5nICg+NTBLKT8qKgoK4oaSIE3hu6VjIHRpw6p1OiBTbyBzw6FuaCBuZ3V5IGPGoSBjw7MgdGh1IG5o4bqtcCBjYW8g4bufIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biB24bubaSBuZ8aw4budaSBjaMawYSB04burbmcga+G6v3QgaMO0bi4KCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJlcGl0b29scyIsIHJlcG9zID0gImh0dHBzOi8vY2xvdWQuci1wcm9qZWN0Lm9yZyIpCmxpYnJhcnkoZXBpdG9vbHMpCmBgYAoKYGBge3J9CnJpc2tyYXRpbyh0YWJsZV9tYXJpdGFsX2luY29tZSkKYGBgCgoqKk5o4bqtbiB4w6l0IGvhur90IHF14bqjKioKCioqS+G6v3QgcXXhuqMqKgoKLSBUcm9uZyBz4buRIDE0LDk3NiBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4sIGPDsyA2LDY5MiBuZ8aw4budaSAoNDQuNjklKSBjw7MgdGh1IG5o4bqtcCA+NTBLLgoKLSBUcm9uZyBz4buRIDEwLDY4MyBuZ8aw4budaSBjaMawYSBiYW8gZ2nhu50ga+G6v3QgaMO0biwgY2jhu4kgY8OzIDQ5MSBuZ8aw4budaSAoNC42MCUpIGPDsyB0aHUgbmjhuq1wID41MEsuCgotIFThu7cgc+G7kSBuZ3V5IGPGoSAoUlIpID0gOS43MiDihpIgTmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIGPDsyB4w6FjIHN14bqldCBjw7MgdGh1IG5o4bqtcCA+NTBLIGNhbyBoxqFuIGfhuqduIDEwIGzhuqduIHNvIHbhu5tpIG5nxrDhu51pIGNoxrBhIHThu6tuZyBr4bq/dCBow7RuLgoKLSBLaG/huqNuZyB0aW4gY+G6rXkgOTUlID0gWzguOTAsIDEwLjYyXSDihpIgS2jDtG5nIGJhbyBn4buTbSAxIOKGkiBraMOhYyBiaeG7h3QgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiBt4bqhbmggbeG6vS4KCi0gcC12YWx1ZSA9IDAuMDAwIOG7nyB04bqldCBj4bqjIGPDoWMga2nhu4NtIMSR4buLbmgg4oaSIHjDoWMgbmjhuq1uIGvhur90IHF14bqjIGzDoCBj4buxYyBr4buzIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ouCgoqKkvhur90IGx14bqtbioqCgotIEThu7FhIHRyw6puIGvhur90IHF14bqjIHBow6JuIHTDrWNoLCBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gY8OzIG5ndXkgY8ahIGPDsyB0aHUgbmjhuq1wIGNhbyB2xrDhu6N0IHRy4buZaSBzbyB24bubaSBuZ8aw4budaSBjaMawYSB04burbmcga+G6v3QgaMO0bi4gVOG7tyBz4buRIG5ndXkgY8ahIGzDoCA5LjcyLCBraG/huqNuZyB0aW4gY+G6rXkgOTUlIGzDoCBbOC45MCwgMTAuNjJdLCB2w6AgcC12YWx1ZSBi4bqxbmcgMCBjaG8gdGjhuqV5IG3hu5FpIGxpw6puIGjhu4cgcuG6pXQgbeG6oW5oIG3hur0gdsOgIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ouIFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiBsw6AgbeG7mXQgeeG6v3UgdOG7kSBxdWFuIHRy4buNbmcg4bqjbmggaMaw4bufbmcgxJHhur9uIGto4bqjIG7Eg25nIMSR4bqhdCBt4bupYyB0aHUgbmjhuq1wIGNhbyB0cm9uZyBi4buZIGThu68gbGnhu4d1IG7DoHkuCgoKIyMjIE9kZHMgUmF0aW8gLSBPUgoKYGBge3J9CiMgxq/hu5tjIGzGsOG7o25nIG9kZHMgcmF0aW8gdOG7q25nIG5ow7NtIHNvIHbhu5tpIG5ow7NtICJEaXZvcmNlZCIKb3JfcmVzdWx0IDwtIG9kZHNyYXRpbyh0YWJsZV9tYXJpdGFsX2luY29tZSkKCiMgSW4ga+G6v3QgcXXhuqMKcHJpbnQob3JfcmVzdWx0KQpgYGAKxq/hu5tjIGzGsOG7o25nIE9kZHMgUmF0aW8gKE9SKSBjaG8gY8OhYyBuaMOzbSB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4sIHRoYW0gY2hp4bq/dSBsw6Ag4oCcRGl2b3JjZWTigJ0KLSBOaMOzbSBNYXJyaWVkLWNpdi1zcG91c2UgY8OzIE9SID0gNi45NCAoOTUlIENJOiA2LjI4IOKAkyA3LjY5KSwgcC12YWx1ZSA9IDAuMDAwMC4KLS0+IE5nxrDhu51pIMSRYW5nIGvhur90IGjDtG4gaOG7o3AgcGjDoXAgY8OzIGto4bqjIG7Eg25nIGPDsyB0aHUgbmjhuq1wID41MEsgY2FvIGjGoW4gZ+G6p24gNyBs4bqnbiBzbyB24bubaSBuZ8aw4budaSDEkcOjIGx5IGjDtG4uIFPhu7Ega2jDoWMgYmnhu4d0IG7DoHkgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiBy4bqldCBjYW8uCgotIE5ow7NtIE5ldmVyLW1hcnJpZWQgY8OzIE9SID0gMC40MSAoOTUlIENJOiAwLjM2IOKAkyAwLjQ3KSwgcC12YWx1ZSA9IDAuMDAwMC4KLS0+IE5o4buvbmcgbmfGsOG7nWkgY2jGsGEgdOG7q25nIGvhur90IGjDtG4gY8OzIGto4bqjIG7Eg25nIMSR4bqhdCB0aHUgbmjhuq1wIGNhbyBjaOG7iSBi4bqxbmcgNDElIHNvIHbhu5tpIG5ow7NtIGx5IGjDtG4uIMSQw6J5IGzDoCBz4buxIGtow6FjIGJp4buHdCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIHLDtSBy4buHdC4KCi0gTmjDs20gU2VwYXJhdGVkIGPDsyBPUiA9IDAuNTkgKDk1JSBDSTogMC40NSDigJMgMC43NyksIHAtdmFsdWUgPSAwLjAwMDEuCi0tPiBOaOG7r25nIG5nxrDhu51pIGx5IHRow6JuIGPDsyB4w6FjIHN14bqldCB0aHUgbmjhuq1wIGNhbyB0aOG6pXAgaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBuZ8aw4budaSBseSBow7RuLCB2w6Agc+G7sSBraMOhYyBiaeG7h3QgbsOgeSBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqLgoKLSBOaMOzbSBXaWRvd2VkIGPDsyBPUiA9IDAuODEgKDk1JSBDSTogMC42MyDigJMgMS4wMiksIHAtdmFsdWUgPSAwLjA3NTAuCi0tPiBN4bq3YyBkw7kgY8OzIHh1IGjGsOG7m25nIHRodSBuaOG6rXAgdGjhuqVwIGjGoW4gbmjDs20gbHkgaMO0biwgbmjGsG5nIHbDrCBraG/huqNuZyB0aW4gY+G6rXkgYmFvIGfhu5NtIDEgdsOgIHAtdmFsdWUgPiAwLjA1IG7Dqm4gY2jGsGEgxJHhu6cgYuG6sW5nIGNo4bupbmcgdGjhu5FuZyBrw6ogxJHhu4Mga+G6v3QgbHXhuq1uLgoKLSBOaMOzbSBNYXJyaWVkLUFGLXNwb3VzZSBjw7MgT1IgPSA2LjYzICg5NSUgQ0k6IDIuNzkg4oCTIDE1LjI5KSwgcC12YWx1ZSDiiYggMC4wMDAwNi4KLS0+IE3hurdjIGTDuSBuaMOzbSBuw6B5IHLhuqV0IG5o4buPIChuID0gMjMpLCBr4bq/dCBxdeG6oyBjaG8gdGjhuqV5IGto4bqjIG7Eg25nIGPDsyB0aHUgbmjhuq1wIGNhbyBjxaluZyBjYW8gaMahbiBuaGnhu4F1IHNvIHbhu5tpIG5nxrDhu51pIGx5IGjDtG4gdsOgIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ouCgotIE5ow7NtIE1hcnJpZWQtc3BvdXNlLWFic2VudCBjw7MgT1IgPSAwLjc2ICg5NSUgQ0k6IDAuNTIg4oCTIDEuMDgpLCBwLXZhbHVlIOKJiCAwLjEzNS4KLS0+IEtow7RuZyBjw7MgxJHhu6cgYuG6sW5nIGNo4bupbmcgdGjhu5FuZyBrw6ogxJHhu4Mga+G6v3QgbHXhuq1uIGPDsyBz4buxIGtow6FjIGJp4buHdCB24buBIHRodSBuaOG6rXAgc28gduG7m2kgbmjDs20gbHkgaMO0bi4KCioqVMOzbSBs4bqhaToqKgoKS+G6v3QgcXXhuqMgcGjDom4gdMOtY2ggY2hvIHRo4bqleSB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gY8OzIG3hu5FpIGxpw6puIGjhu4cgxJHDoW5nIGvhu4MgduG7m2kgbeG7qWMgdGh1IG5o4bqtcC4gTmjDs20gxJFhbmcgc+G7kW5nIHRyb25nIGjDtG4gbmjDom4gaOG7o3AgcGjDoXAgKE1hcnJpZWQtY2l2LXNwb3VzZSkgY8OzIHjDoWMgc3XhuqV0IMSR4bqhdCB0aHUgbmjhuq1wIGNhbyB2xrDhu6N0IHRy4buZaSBzbyB24bubaSBjw6FjIG5ow7NtIGtow6FjLCDEkeG6t2MgYmnhu4d0IGzDoCBuZ8aw4budaSBseSBow7RuLCBjaMawYSBr4bq/dCBow7RuIGhheSBseSB0aMOibi4gTmjhu69uZyBraMOhYyBiaeG7h3QgbsOgeSBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIHLDtSByw6BuZywgbmdv4bqhaSB0cuG7qyBt4buZdCBz4buRIG5ow7NtIGPDsyBxdXkgbcO0IG3huqt1IG5o4buPIGhv4bq3YyBraG/huqNuZyB0aW4gY+G6rXkgY2jhu6lhIDEuCgoKCgoKCgoKCgo=