— NHIỆM VỤ TUẦN 4-5 —


Nhiệm vụ tuần 4:

  1. Tìm một bộ dữ liệu (có ít nhất 4 biến định tính) và thực hiện phân tích bộ dữ liệu này theo những phương pháp đã trao đổi.
  2. Ngoài ra làm thêm bài toán ước lượng khoảng, kiểm định giả thuyết thống kê cho các biến trong bộ dữ liệu.

Nhiệm vụ tuần 5:

  1. Chọn 2 biến thật sự là biến định tính để làm biến phụ thuộc để phân tích sự tác động của các biến còn lại lên 2 biến này. Nếu trong bộ dữ liệu của tuần 4 không có 2 biến định tính thì phải chọn bộ dữ liệu khác.
  2. Xem trước phương pháp ước lượng Maximum likehood

Bộ dữ liệu “Adult”


PHẦN 1. Tổng quan về bộ dữ liệu


Bộ dữ liệu Adult (hay Census Income 1994) ghi lại thông tin nhân khẩu học và việc làm của 48842 cá nhân ở Mỹ, với 14 đặc trưng bao gồm các biến phân loại (như workclass, education, marital-status, occupation…) và các biến số (như age, education-num, hours-per-week…)

Nhiệm vụ phân loại chính là dự đoán xem thu nhập hàng năm của một người có vượt trên $50.000 hay không không dựa trên dữ liệu điều tra dân số. Đây còn được gọi là tập dữ liệu “Thu nhập điều tra dân số”.

Theo thông tin từ UCI Machine Learning Repository, các bản ghi được trích xuất từ dữ liệu điều tra dân số năm 1994 bởi Barry Becker (với điều kiện lọc: tuổi >16, thu nhập cá nhân >100, trọng số dân số >1, giờ làm >0).

  • Đặc điểm của tập dữ liệu: Đa biến

  • Lĩnh vực chủ đề: Khoa học xã hội

  • Loại tính năng: Phân loại, Số nguyên

  • Các trường hợp: 48842

  • Các biến: Gồm 14 biến:

Đọc file: Đầu tiên ta đọc dữ liệu adult.csv vào R, xác định cột và loại bỏ các giá trị thiếu được mã hoá bằng ký tự “?”.

adult <- read.csv("C:/Users/HP/Downloads/adult.csv", header = TRUE, stringsAsFactors = FALSE)
colnames(adult) <- c("age","workclass","fnlwgt","education","education_num",
                     "marital_status","occupation","relationship","race","sex",
                     "capital_gain","capital_loss","hours_per_week",
                     "native_country","income")

Cấu trúc dữ liệu: Sử dụng str() để xem thông tin cấu trúc. Ta thấy tổng số hàng và kiểu dữ liệu của mỗi cột.

str(adult)
## 'data.frame':    32560 obs. of  15 variables:
##  $ age           : int  50 38 53 28 37 49 52 31 42 37 ...
##  $ workclass     : chr  " Self-emp-not-inc" " Private" " Private" " Private" ...
##  $ fnlwgt        : int  83311 215646 234721 338409 284582 160187 209642 45781 159449 280464 ...
##  $ education     : chr  " Bachelors" " HS-grad" " 11th" " Bachelors" ...
##  $ education_num : int  13 9 7 13 14 5 9 14 13 10 ...
##  $ marital_status: chr  " Married-civ-spouse" " Divorced" " Married-civ-spouse" " Married-civ-spouse" ...
##  $ occupation    : chr  " Exec-managerial" " Handlers-cleaners" " Handlers-cleaners" " Prof-specialty" ...
##  $ relationship  : chr  " Husband" " Not-in-family" " Husband" " Wife" ...
##  $ race          : chr  " White" " White" " Black" " Black" ...
##  $ sex           : chr  " Male" " Male" " Male" " Female" ...
##  $ capital_gain  : int  0 0 0 0 0 0 0 14084 5178 0 ...
##  $ capital_loss  : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ hours_per_week: int  13 40 40 40 40 16 45 50 40 80 ...
##  $ native_country: chr  " United-States" " United-States" " United-States" " Cuba" ...
##  $ income        : chr  " <=50K" " <=50K" " <=50K" " <=50K" ...

Thăm dò nhanh: Hiển thị một vài dòng đầu/cuối để hiểu sơ bộ dữ liệu.

head(adult)
##   age         workclass fnlwgt  education education_num         marital_status
## 1  50  Self-emp-not-inc  83311  Bachelors            13     Married-civ-spouse
## 2  38           Private 215646    HS-grad             9               Divorced
## 3  53           Private 234721       11th             7     Married-civ-spouse
## 4  28           Private 338409  Bachelors            13     Married-civ-spouse
## 5  37           Private 284582    Masters            14     Married-civ-spouse
## 6  49           Private 160187        9th             5  Married-spouse-absent
##           occupation   relationship   race     sex capital_gain capital_loss
## 1    Exec-managerial        Husband  White    Male            0            0
## 2  Handlers-cleaners  Not-in-family  White    Male            0            0
## 3  Handlers-cleaners        Husband  Black    Male            0            0
## 4     Prof-specialty           Wife  Black  Female            0            0
## 5    Exec-managerial           Wife  White  Female            0            0
## 6      Other-service  Not-in-family  Black  Female            0            0
##   hours_per_week native_country income
## 1             13  United-States  <=50K
## 2             40  United-States  <=50K
## 3             40  United-States  <=50K
## 4             40           Cuba  <=50K
## 5             40  United-States  <=50K
## 6             16        Jamaica  <=50K
tail(adult)
##       age     workclass fnlwgt     education education_num      marital_status
## 32555  22       Private 310152  Some-college            10       Never-married
## 32556  27       Private 257302    Assoc-acdm            12  Married-civ-spouse
## 32557  40       Private 154374       HS-grad             9  Married-civ-spouse
## 32558  58       Private 151910       HS-grad             9             Widowed
## 32559  22       Private 201490       HS-grad             9       Never-married
## 32560  52  Self-emp-inc 287927       HS-grad             9  Married-civ-spouse
##               occupation   relationship   race     sex capital_gain
## 32555    Protective-serv  Not-in-family  White    Male            0
## 32556       Tech-support           Wife  White  Female            0
## 32557  Machine-op-inspct        Husband  White    Male            0
## 32558       Adm-clerical      Unmarried  White  Female            0
## 32559       Adm-clerical      Own-child  White    Male            0
## 32560    Exec-managerial           Wife  White  Female        15024
##       capital_loss hours_per_week native_country income
## 32555            0             40  United-States  <=50K
## 32556            0             38  United-States  <=50K
## 32557            0             40  United-States   >50K
## 32558            0             40  United-States  <=50K
## 32559            0             20  United-States  <=50K
## 32560            0             40  United-States   >50K

Giá trị thiếu: Kiểm tra các biến định tính (categorical) xem có NA không. Ta phát hiện có NA ở các cột workclass, occupation, native_country (giá trị “?”). Ví dụ:

sapply(adult %>% select(workclass, occupation, native_country), 
       function(x) sum(is.na(x)))
##      workclass     occupation native_country 
##              0              0              0

Vì tỷ lệ giá trị thiếu rất nhỏ so với kích thước mẫu (ví dụ chỉ khoảng 6% cho workclass), ta lựa chọn loại bỏ những dòng có NA để đảm bảo tính chính xác của phân tích và tránh ảnh hưởng không mong muốn. Sau đó, ta chuyển các biến định tính sang factor để tiện xử lý.

# Loại bỏ khoảng trắng ở đầu/cuối các biến dạng chuỗi
adult <- adult %>% mutate(across(where(is.character), trimws))

# Thay thế "?" bằng NA
adult[adult == "?"] <- NA

# Loại bỏ các dòng có NA
adult <- na.omit(adult)
adult <- na.omit(adult)
adult <- adult %>%
  mutate_at(vars(workclass, education, marital_status, occupation, 
                 relationship, race, sex, native_country, income),
            factor)

Adult.csv là một bộ dữ liệu bao gồm 32561 quan sát và 14 biến, cụ thể là các biến:

Nhóm biến Biến cụ thể Mục tiêu phân tích chính
Biến định tính workclass, education, marital-status, occupation, relationship, race, sex, native-country Thống kê tần số, biểu đồ cột, phân phối theo nhóm
Biến định lượng age, fnlwgt, education-num, capital-gain, capital-loss, hours-per-week Mô tả thống kê, phân phối, kiểm định, khoảng tin cậy
Biến mục tiêu (target) income Dự đoán phân loại: <=50K hoặc >50K

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

  1. workclass (Thành phần việc làm)

→ Phân loại theo khu vực làm việc của cá nhân, phản ánh nơi họ đang công tác.

Các giá trị phổ biến:

  • Private: khu vực tư nhân

  • Self-emp-not-inc: tự làm không thành lập công ty

  • Self-emp-inc: tự làm có công ty

  • Federal-gov, Local-gov, State-gov: làm việc cho chính phủ

  • Without-pay: làm không lương

  • Never-worked: chưa từng làm việc

  1. education (Trình độ học vấn)

→ Trình độ học vấn cuối cùng mà cá nhân đạt được (dạng văn bằng).

Ví dụ:

Bachelors, HS-grad (tốt nghiệp THPT), Some-college, Masters, Doctorate, 11th, Assoc-acdm,…

  1. marital-status (Tình trạng hôn nhân)

→ Phản ánh tình trạng hôn nhân hiện tại của người đó.

Giá trị gồm:

  • Married-civ-spouse: đã kết hôn (hôn nhân dân sự)

  • Divorced: đã ly hôn

  • Never-married: chưa từng kết hôn

  • Separated: ly thân

  • Widowed: góa vợ/chồng

  1. occupation (Nghề nghiệp)

→ Ngành nghề cụ thể đang làm việc.

Ví dụ:

Tech-support, Craft-repair, Sales, Exec-managerial, Prof-specialty, Handlers-cleaners,…

  1. relationship (Quan hệ gia đình)

→ Vị trí của cá nhân trong gia đình.

Giá trị có thể là:

Husband, Wife, Own-child, Not-in-family, Unmarried, Other-relative

  1. race (Chủng tộc)

→ Chủng tộc được khai báo của cá nhân.

Gồm các nhóm chính:

White, Black, Asian-Pac-Islander, Amer-Indian-Eskimo, Other

  1. sex (Giới tính)

→ Giới tính sinh học của cá nhân.

Gồm:

Male, Female

  1. native-country (Quốc tịch gốc)

→ Quốc gia nơi cá nhân sinh ra hoặc có nguồn gốc.

Giá trị ví dụ:

United-States, Mexico, Philippines, Germany, Vietnam, India, China,…

Các biến định lượng:

  1. age (Tuổi)

→ Tuổi của cá nhân, giá trị là số nguyên dương.

Phạm vi dữ liệu: từ 17 đến 90+

  1. fnlwgt (Final Weight – Trọng số dân số)

→ Trọng số mẫu do Cục Điều tra dân số gán, thể hiện số lượng người trong tổng thể mà mẫu đại diện.

Giải thích:

Một người có fnlwgt = 100000 đại diện cho ~100,000 người trong dân số thực.

Biến này chủ yếu dùng trong phân tích khảo sát, ít khi được dùng trực tiếp trong mô hình dự đoán.

  1. education-num (Số năm học)

→ Là số năm học chính thức tương ứng với biến education.

Ví dụ:

HS-grad ≈ 9, Bachelors ≈ 13, Masters ≈ 14, Doctorate ≈ 16

  1. capital-gain (Thu nhập vốn)

→ Lợi nhuận vốn (capital gain) từ các nguồn như bán tài sản, đầu tư,… trong năm.

Đặc điểm:

Phân phối rất lệch phải, phần lớn giá trị là 0 (tức không có lãi vốn trong năm).

  1. capital-loss (Lỗ vốn)

→ Tổn thất vốn từ các khoản đầu tư tài sản trong năm.

Lưu ý:

Tương tự capital-gain, giá trị chủ yếu là 0 trong phần lớn trường hợp.

  1. hours-per-week (Số giờ làm mỗi tuần)

→ Số giờ trung bình mà cá nhân làm việc mỗi tuần.

Phổ biến: 40 giờ/tuần là mức tiêu chuẩn, một số người làm 60–80 giờ hoặc ít hơn 20 giờ (bán thời gian).


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


Cho mỗi biến định tính, ta thực hiện thống kê tần suất và vẽ biểu đồ. Dưới đây là phân tích cho từng biến chính:

2.1. Workclass (Ngành lao động)

table(adult$workclass)
## 
##      Federal-gov        Local-gov          Private     Self-emp-inc 
##              943             2067            22286             1074 
## Self-emp-not-inc        State-gov      Without-pay 
##             2499             1278               14
prop.table(table(adult$workclass))*100
## 
##      Federal-gov        Local-gov          Private     Self-emp-inc 
##       3.12655416       6.85322105      73.89012301       3.56088989 
## Self-emp-not-inc        State-gov      Without-pay 
##       8.28553430       4.23726004       0.04641756
ggplot(adult, aes(x=workclass)) +
  geom_bar(fill="#69b3a2") +
  xlab("Workclass") + ylab("Số lượng") +
  ggtitle("Biểu đồ cột của Workclass") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhận xét:

Hạng mục ‘Private’ chiếm ưu thế rõ rệt (chiếm 73% tổng dữ liệu), lớn hơn nhiều so với các hạng mục khác. Các hạng mục như ‘Self-emp-not-inc’, ‘Local-gov’, ‘State-gov’ cũng xuất hiện nhưng với tần suất thấp hơn. Cho thấy rằng đa số cá nhân trong dữ liệu làm việc trong khu vực tư nhân.

2.2. Education (Trình độ học vấn)

table(adult$education)
## 
##         10th         11th         12th      1st-4th      5th-6th      7th-8th 
##          820         1048          377          151          288          557 
##          9th   Assoc-acdm    Assoc-voc    Bachelors    Doctorate      HS-grad 
##          455         1008         1307         5043          375         9840 
##      Masters    Preschool  Prof-school Some-college 
##         1627           45          542         6678
prop.table(table(adult$education))*100
## 
##         10th         11th         12th      1st-4th      5th-6th      7th-8th 
##    2.7187427    3.4746859    1.2499586    0.5006465    0.9548755    1.8467557 
##          9th   Assoc-acdm    Assoc-voc    Bachelors    Doctorate      HS-grad 
##    1.5085707    3.3420643    4.3334107   16.7202679    1.2433275   32.6249130 
##      Masters    Preschool  Prof-school Some-college 
##    5.3943835    0.1491993    1.7970226   22.1411757
ggplot(adult, aes(x=education)) +
  geom_bar(fill="#404080") +
  xlab("Education") + ylab("Số lượng") +
  ggtitle("Biểu đồ cột của trình độ học vấn") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhận xét:

Các mức học vấn phổ biến nhất là ‘HS-grad’ (tốt nghiệp THPT), ‘Some-college’ và ‘Bachelors’. Những nhóm này chiếm phần lớn dữ liệu. Các mức cao hơn như ‘Masters’, ‘Doctorate’ ít phổ biến hơn. Biểu đồ cho thấy phần lớn người trong mẫu có trình độ từ trung học đến cử nhân.

Nhóm tốt nghiệp THPT (HS-grad) chiếm đa số, sau đó là đang học Cao đẳng/Đại học (Some-college). Điều này phản ánh thực trạng giáo dục: phần đông dân số chỉ học đến cấp 3 hoặc chưa hoàn thành đại học. Ví dụ, ở Việt Nam cũng có xu hướng tỷ lệ người có bằng tốt nghiệp THPT trở lên ngày càng tăng, nhưng đại học vẫn chiếm một phần nhỏ hơn.

2.3. Marital-status (Tình trạng hôn nhân)

table(adult$marital_status)
## 
##              Divorced     Married-AF-spouse    Married-civ-spouse 
##                  4214                    21                 14065 
## Married-spouse-absent         Never-married             Separated 
##                   370                  9725                   939 
##               Widowed 
##                   827
prop.table(table(adult$marital_status))*100
## 
##              Divorced     Married-AF-spouse    Married-civ-spouse 
##           13.97168529            0.06962634           46.63306920 
## Married-spouse-absent         Never-married             Separated 
##            1.22674978           32.24362587            3.11329200 
##               Widowed 
##            2.74195153
ggplot(adult, aes(x=marital_status)) +
  geom_bar(fill="#008080") +
  xlab("Marital Status") + ylab("Số lượng") +
  ggtitle("Biểu đồ cột của tình trạng hôn nhân") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhận xét:

Hạng mục ‘Married-civ-spouse’ (kết hôn chính thức) chiếm tỷ lệ cao nhất (khoảng 46%). Các hạng mục ‘Never-married’ và ‘Divorced’ đứng sau, lần lượt chiếm khoảng 32% và 14%. Có sự chênh lệch rõ: người đã kết hôn chiếm ưu thế, phần lớn là người đã lập gia đình.

Hơn 46% đã kết hôn hợp pháp. Trong thực tế, những người đã kết hôn thường có xu hướng ổn định công việc và thu nhập hơn.

2.4. Occupation (Nghề nghiệp)

table(adult$occupation)
## 
##      Adm-clerical      Armed-Forces      Craft-repair   Exec-managerial 
##              3720                 9              4030              3992 
##   Farming-fishing Handlers-cleaners Machine-op-inspct     Other-service 
##               989              1350              1966              3212 
##   Priv-house-serv    Prof-specialty   Protective-serv             Sales 
##               143              4038               644              3584 
##      Tech-support  Transport-moving 
##               912              1572
prop.table(table(adult$occupation))*100
## 
##      Adm-clerical      Armed-Forces      Craft-repair   Exec-managerial 
##       12.33380856        0.02983986       13.36162594       13.23563542 
##   Farming-fishing Handlers-cleaners Machine-op-inspct     Other-service 
##        3.27906900        4.47597891        6.51835151       10.64951427 
##   Priv-house-serv    Prof-specialty   Protective-serv             Sales 
##        0.47412221       13.38815026        2.13520772       11.88289513 
##      Tech-support  Transport-moving 
##        3.02377242        5.21202878
ggplot(adult, aes(x=occupation)) +
  geom_bar(fill="#804000") +
  xlab("Occupation") + ylab("Số lượng") +
  ggtitle("Biểu đồ cột của nghề nghiệp") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhận xét:

Các nghề phổ biến gồm ‘Prof-specialty’, ‘Craft-repair’, ‘Exec-managerial’, ‘Adm-clerical’, ‘Sales’… với số lượng tương đương nhau. Không có một nghề cụ thể nào quá áp đảo. Điều này cho thấy đa dạng về nghề nghiệp, chủ yếu là các công việc tay nghề và quản lý.

Nhóm chuyên viên (Exec-managerial, Prof-specialty) chiếm tỷ lệ lớn (~sự tổng của Exec-managerial và Prof-specialty là khoảng 13.3% + 13.4% = 26,7%). Cho thấy đa số những người có vị trí công việc chuyên môn/cao chiếm phần lớn.

2.5. Relationship (Quan hệ gia đình)

table(adult$relationship)
## 
##        Husband  Not-in-family Other-relative      Own-child      Unmarried 
##          12463           7725            889           4466           3212 
##           Wife 
##           1406
prop.table(table(adult$relationship))*100
## 
##        Husband  Not-in-family Other-relative      Own-child      Unmarried 
##      41.321574      25.612546       2.947515      14.807201      10.649514 
##           Wife 
##       4.661649
ggplot(adult, aes(x=relationship)) +
  geom_bar(fill="#808080") +
  xlab("Relationship") + ylab("Số lượng") +
  ggtitle("Biểu đồ cột của quan hệ gia đình") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhận xét:

Hạng mục ‘Husband’ (nam đã kết hôn) chiếm tỷ lệ lớn nhất (~41%), tiếp theo là ‘Not-in-family’ (~25%). ‘Own-child’ chiếm khoảng 15%. Cho thấy, nam giới đã kết hôn chiếm tỉ lệ nhiều hơn. Các mối quan hệ gia đình khác như vợ, con cái, họ hàng chiếm phần nhỏ.

2.6. Race (Chủng tộc)

table(adult$race)
## 
## Amer-Indian-Eskimo Asian-Pac-Islander              Black              Other 
##                286                895               2817                231 
##              White 
##              25932
prop.table(table(adult$race))*100
## 
## Amer-Indian-Eskimo Asian-Pac-Islander              Black              Other 
##          0.9482444          2.9674082          9.3398760          0.7658897 
##              White 
##         85.9785816
ggplot(adult, aes(x=race)) +
  geom_bar(fill="#C04000") +
  xlab("Race") + ylab("Số lượng") +
  ggtitle("Biểu đồ cột của chủng tộc") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhận xét:

Đa số là ‘White’ (khoảng 86%), ‘Black’ ~9%, các chủng tộc khác (Á châu, da đỏ, khác) chỉ chiếm vài phần trăm. Sự chênh lệch rất lớn. Cho thấy chủ yếu là người da trắng, tương ứng với đặc trưng dân số của dữ liệu gốc.

2.7. Sex (Giới tính)

table(adult$sex)
## 
## Female   Male 
##   9782  20379
prop.table(table(adult$sex))*100
## 
##   Female     Male 
## 32.43261 67.56739
ggplot(adult, aes(x=sex)) +
  geom_bar(fill="#008080") +
  xlab("Sex") + ylab("Số lượng") +
  ggtitle("Biểu đồ cột của giới tính") +
  theme(axis.text.x = element_text(angle = 0, hjust = 0.5))

Nhận xét:

Mẫu gồm khoảng 67% nam và 32% nữ. Nam giới chiếm ưu thế rõ rệt. Thực tế, số lao động nam thường nhiều hơn nữ do nhiều yếu tố (chủ quan, truyền thống). Tuy nhiên, dữ liệu này không cân bằng giới tính.

2.8. Native-country (Quốc tịch gốc)

table(adult$native_country)
## 
##                   Cambodia                     Canada 
##                         18                        107 
##                   Columbia                       Cuba 
##                         56                         92 
##                      China         Dominican-Republic 
##                         68                         67 
##                    Ecuador                El-Salvador 
##                         27                        100 
##                    England                     France 
##                         86                         27 
##                    Germany                     Greece 
##                        128                         29 
##                  Guatemala                      Haiti 
##                         63                         42 
##         Holand-Netherlands                   Honduras 
##                          1                         12 
##                       Hong                    Hungary 
##                         19                         13 
##                      India                       Iran 
##                        100                         42 
##                    Ireland                      Italy 
##                         24                         68 
##                    Jamaica                      Japan 
##                         80                         59 
##                       Laos                     Mexico 
##                         17                        610 
##                  Nicaragua Outlying-US(Guam-USVI-etc) 
##                         33                         14 
##                       Peru                     Poland 
##                         30                         56 
##                   Portugal                Puerto-Rico 
##                         34                        109 
##                Philippines                   Scotland 
##                        188                         11 
##                      South                     Taiwan 
##                         71                         42 
##                   Thailand            Trinadad&Tobago 
##                         17                         18 
##              United-States                    Vietnam 
##                      27503                         64 
##                 Yugoslavia 
##                         16
prop.table(table(adult$native_country))*100
## 
##                   Cambodia                     Canada 
##                 0.05967972                 0.35476277 
##                   Columbia                       Cuba 
##                 0.18567024                 0.30502967 
##                      China         Dominican-Republic 
##                 0.22545672                 0.22214118 
##                    Ecuador                El-Salvador 
##                 0.08951958                 0.33155399 
##                    England                     France 
##                 0.28513643                 0.08951958 
##                    Germany                     Greece 
##                 0.42438911                 0.09615066 
##                  Guatemala                      Haiti 
##                 0.20887902                 0.13925268 
##         Holand-Netherlands                   Honduras 
##                 0.00331554                 0.03978648 
##                       Hong                    Hungary 
##                 0.06299526                 0.04310202 
##                      India                       Iran 
##                 0.33155399                 0.13925268 
##                    Ireland                      Italy 
##                 0.07957296                 0.22545672 
##                    Jamaica                      Japan 
##                 0.26524319                 0.19561686 
##                       Laos                     Mexico 
##                 0.05636418                 2.02247936 
##                  Nicaragua Outlying-US(Guam-USVI-etc) 
##                 0.10941282                 0.04641756 
##                       Peru                     Poland 
##                 0.09946620                 0.18567024 
##                   Portugal                Puerto-Rico 
##                 0.11272836                 0.36139385 
##                Philippines                   Scotland 
##                 0.62332151                 0.03647094 
##                      South                     Taiwan 
##                 0.23540334                 0.13925268 
##                   Thailand            Trinadad&Tobago 
##                 0.05636418                 0.05967972 
##              United-States                    Vietnam 
##                91.18729485                 0.21219456 
##                 Yugoslavia 
##                 0.05304864
ggplot(adult %>% filter(native_country != "United-States"),
       aes(x=native_country)) +
  geom_bar(fill="#804080") +
  xlab("Native Country (ngoại trừ Mỹ)") + ylab("Số lượng") +
  ggtitle("Biểu đồ cột của quốc tịch gốc (không bao gồm Mỹ)") +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, size=8))

Nhận xét:

Đa số (gần 89%) có nguồn gốc từ ‘United-States’, phần còn lại rải rác ở nhiều quốc gia khác (Mexico, Philippines, Đức…). Sự chênh lệch rất lớn cho thấy tập mẫu chủ yếu là người Mỹ.

Hơn 89% là người Mỹ. Điều này hợp lý vì dữ liệu từ cuộc điều tra dân số Mỹ, chỉ một phần nhỏ thuộc quốc gia khác (Mexiko, Philippines, v.v.).

2.9. Phân tích một số biến định lượng

Theo báo cáo của Cục Điều tra dân số Mỹ năm 2022, độ tuổi trung bình của dân số Mỹ đạt 38.9 tuổi. Trong bộ dữ liệu Adult (1994), độ tuổi trung bình (age) tính được khoảng 38.6 tuổi (độ lệch chuẩn khoảng 13.6), với giá trị trung vị khoảng 36 tuổi. Như vậy, mẫu dữ liệu có độ tuổi tương đương trung bình dân số hiện tại. Ví dụ, đoạn mã R sau cho biết thống kê cơ bản về tuổi và giờ làm việc:

summary(adult$age)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   17.00   28.00   37.00   38.44   47.00   90.00
summary(adult$hours_per_week)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00   40.00   40.00   40.93   45.00   99.00

Nhận xét:

Độ tuổi (age): trung bình ≈ 38.44, trung vị 37, phần vị thứ nhất ~28, phần vị thứ ba ~47.

Giờ làm việc mỗi tuần (hours_per_week): trung bình ≈ 40.93 giờ, trung vị 40 giờ, phần vị thứ nhất 40, phần vị thứ ba ~45. Hầu hết người lao động làm việc xung quanh 40 giờ mỗi tuần, tương tự mức trung bình gần 40 giờ/tuần trong lực lượng lao động Mỹ hiện nay.


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


Chọn 3 biến định tính tiêu biểu: Sex (Female), Workclass (Private), Marital-status (Married-civ-spouse). Với mỗi biến, xem xét một hạng mục quan tâm và phân tích:

3.1. Tỷ lệ nữ (sex = Female))

Ước lượng khoảng tin cậy 95% cho tỉ lệ nữ trong tổng thể:

n_total <- nrow(adult)
x_female <- sum(adult$sex == "Female")
prop.test(x = x_female, n = n_total, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_female out of n_total, null probability 0.5
## X-squared = 3722.5, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.3190492 0.3296479
## sample estimates:
##         p 
## 0.3243261

Nhận xét:

Khoảng tin cậy ước tính cho tỷ lệ nữ khoảng [0.319, 0.329].

Vậy, với mức ý nghĩa 95% thì tỷ lệ nữ trong toàn bộ dân số tương ứng nằm trong khoảng [0.319, 0.329].

Kiểm định giả thuyết: Giả sử 𝐻0:𝑝=0.5 (tỷ lệ nữ = 50%). Thực hiện kiểm định:

prop.test(x = x_female, n = n_total, alternative = "two.sided", p = 0.5, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_female out of n_total, null probability 0.5
## X-squared = 3722.5, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.3190492 0.3296479
## sample estimates:
##         p 
## 0.3243261

Nhận xét:

Kết quả: Giá trị p rất nhỏ (<2.2e-16) nên bác bỏ 𝐻0 ở mức ý nghĩa 0.05.

Kết luận: Tỷ lệ nữ trong mẫu không bằng 50%. Thực tế, mẫu này có tỷ lệ nữ ~33.5% (nhỏ hơn 50%). Kết luận có ý nghĩa là tỷ lệ nữ thực tế thấp hơn giả thuyết ban đầu.

3.2. Tỷ lệ thuộc loại công việc “Private”

Ước lượng khoảng tin cậy 95%:

x_private <- sum(adult$workclass == "Private")
n_total <- nrow(adult)
prop.test(x = x_private, n = n_total, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_private out of n_total, null probability 0.5
## X-squared = 6884.7, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.7338973 0.7438441
## sample estimates:
##         p 
## 0.7389012

Nhận xét:

Khoảng tin cậy ước tính cho tỷ lệ ‘Private’ là [0.733, 0.743].

Vậy, với mức ý nghĩa 95% thì tỷ lệ người có công việc thuộc diện ‘Private’ trong tổng thể nằm trong khoảng [0.733, 0.743].

Kiểm định giả thuyết: Kiểm định 𝐻0:𝑝=0.5 (nghĩa là giả định ban đầu là chỉ 50% là private).

prop.test(x = x_private, n = n_total, alternative = "two.sided", p = 0.5, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_private out of n_total, null probability 0.5
## X-squared = 6884.7, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.7338973 0.7438441
## sample estimates:
##         p 
## 0.7389012

Nhận xét

Kết quả: p-value ≈ 0 (<2.2e-16). Bác bỏ 𝐻0 .

Vậy, Tỷ lệ người làm trong khu vực “Private” cao hơn giả thiết 50%. Thực tế mẫu cho thấy ~70% làm việc trong khu vực tư nhân, chênh lệch lớn so với giả thuyết ban đầu.

3.3. Tỷ lệ “Married-civ-spouse”

Ước lượng khoảng tin cậy 95%:

x_married <- sum(adult$marital_status == "Married-civ-spouse")
prop.test(x = x_married, n = n_total, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_married out of n_total, null probability 0.5
## X-squared = 136.63, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.4606888 0.4719812
## sample estimates:
##         p 
## 0.4663307

Nhận xét

Khoảng tin cậy cho tỷ lệ ‘Married-civ-spouse’ là khoảng [0.460, 0.471]

Vậy với mức ý nghĩa 95% thì tỷ lệ đã kết hôn theo khảo sát nằm trong khoảng [0.460, 0.471].

Kiểm định giả thuyết: Kiểm định 𝐻0:𝑝=0.5

prop.test(x = x_married, n = n_total, alternative = "two.sided", p = 0.5, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_married out of n_total, null probability 0.5
## X-squared = 136.63, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.4606888 0.4719812
## sample estimates:
##         p 
## 0.4663307

Nhận xét

Kết quả: p-value rất nhỏ,(<2.2e-16) bác bỏ 𝐻0. Nghĩa là tỷ lệ đã kết hôn trong mẫu (~46%) khác với giả thuyết 50%. Điều này phù hợp với nhận xét trước đó rằng ~46% đã lập gia đình, kém giả thiết 50%.


PHẦN 4. Phân tích Mối quan hệ giữa Hai biến Định tính


Chọn 3 cặp biến định tính liên quan đến thu nhập (income) và các biến khác: Sex - Income, Education - Income, Marital-status - Income. Với mỗi cặp, ta lập bảng chéo, vẽ biểu đồ, và kiểm định Chi-bình phương độc lập.

4.1. Sex và Income

Bảng tần suất chéo:

tab_sex_inc <- table(adult$sex, adult$income)
tab_sex_inc
##         
##          <=50K  >50K
##   Female  8670  1112
##   Male   13983  6396
prop.table(tab_sex_inc, 1)*100  # Tỷ lệ theo hàng giới tính
##         
##             <=50K     >50K
##   Female 88.63218 11.36782
##   Male   68.61475 31.38525

Tỷ lệ có thu nhập >50K: ~31.38% ở nam, ~11.36% ở nữ.

Trực quan hóa: Biểu đồ cột chồng cho thấy sự khác biệt lớn.

ggplot(adult, aes(x=sex, fill=income)) +
  geom_bar(position="fill") +
  ylab("Tỷ lệ (%)") + ggtitle("Tỷ lệ thu nhập >50K theo giới tính") +
  theme(axis.text.x = element_text(hjust=0.5))

Nhận xét mô tả: Biểu đồ và tỷ lệ cho thấy nam giới có tỷ lệ thu nhập >50K cao hơn rất nhiều so với nữ.

Kiểm định Chi-bình phương:

H0: Giới tính và thu nhập độc lập (không liên quan) trong tổng thể.

H1: Có mối liên hệ giữa giới tính và thu nhập.

chisq_test_sex_inc <- chisq.test(tab_sex_inc)
chisq_test_sex_inc$statistic; chisq_test_sex_inc$parameter; chisq_test_sex_inc$p.value
## X-squared 
##   1415.45
## df 
##  1
## [1] 9.226706e-310

Nhận xét:

Kết quả Giá trị X bình phương lớn, p-value rất nhỏ. Kết luận: Bác bỏ H0 (theo mức 0.05). Giới tính có liên quan có ý nghĩa thống kê với việc kiếm được >50K, tức tỷ lệ thu nhập cao phụ thuộc vào giới tính. Thực tế cho thấy người đàn ông là trụ cột của gia đình nên có xu hướng làm việc nhiều người phụ nữ vì vậy việc đàn ông có thu nhập cao hơn so với phụ nữ là hợp lí.

Risk Ratio

rr_sex_income <- riskratio(tab_sex_inc)
rr_sex_income
## $data
##         
##          <=50K >50K Total
##   Female  8670 1112  9782
##   Male   13983 6396 20379
##   Total  22653 7508 30161
## 
## $measure
##         risk ratio with 95% C.I.
##          estimate    lower    upper
##   Female 1.000000       NA       NA
##   Male   2.760886 2.602862 2.928504
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact    chi.square
##   Female         NA           NA            NA
##   Male            0            0 5.400534e-310
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

Nhận xét:

Ở đây, ta lấy Female là nhóm tham chiếu và Male là nhóm so sánh với sự kiện là “thu nhập > 50K”

Kết quả RR của Male = 2.760 cho thấy Nam có xác suất có thu nhập (>50K) gấp 2.76 lần so với nữ giới.

Odds Ratio

or_sex_income <- oddsratio(tab_sex_inc)
or_sex_income
## $data
##         
##          <=50K >50K Total
##   Female  8670 1112  9782
##   Male   13983 6396 20379
##   Total  22653 7508 30161
## 
## $measure
##         odds ratio with 95% C.I.
##          estimate    lower    upper
##   Female 1.000000       NA       NA
##   Male   3.565833 3.329126 3.822584
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact    chi.square
##   Female         NA           NA            NA
##   Male            0            0 5.400534e-310
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

Nhận xét:

Ở đây, ta lấy Female là nhóm tham chiếu và Male là nhóm so sánh với sự kiện là “thu nhập > 50K”

Kết quả OR của Male = 3.565 cho thấy khả năng nam có thu nhập (>50K) gấp 3.565 lần so với nữ.

4.2. Education và Income

Bảng tần suất chéo:

tab_edu_inc <- table(adult$education, adult$income)
prop.table(tab_edu_inc, 1)*100  # Tỷ lệ theo hàng (trình độ)
##               
##                     <=50K       >50K
##   10th          92.804878   7.195122
##   11th          94.370229   5.629771
##   12th          92.307692   7.692308
##   1st-4th       96.026490   3.973510
##   5th-6th       95.833333   4.166667
##   7th-8th       93.716338   6.283662
##   9th           94.505495   5.494505
##   Assoc-acdm    74.603175  25.396825
##   Assoc-voc     73.680184  26.319816
##   Bachelors     57.842554  42.157446
##   Doctorate     25.333333  74.666667
##   HS-grad       83.567073  16.432927
##   Masters       43.577136  56.422864
##   Preschool    100.000000   0.000000
##   Prof-school   25.092251  74.907749
##   Some-college  79.994010  20.005990

Tỷ lệ thu nhập >50K tăng dần với trình độ: từ gần 0 ở trình độ thấp đến ~50% ở trình độ cao (Doctorate, Prof-school).

Trực quan hóa:

ggplot(adult, aes(x=education, fill=income)) +
  geom_bar(position="fill") +
  xlab("Education") + ylab("Tỷ lệ (%)") +
  ggtitle("Tỷ lệ >50K theo trình độ học vấn") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhận xét mô tả: Có xu hướng rõ: những người có học vấn cao hơn (Bachelors, Masters, Doctorate) có khả năng thu nhập >50K cao hơn những người học vấn thấp (HS-grad, Some-college).

Kiểm định Chi-bình phương:

chisq_test_edu_inc <- chisq.test(tab_edu_inc)
chisq_test_edu_inc$statistic; chisq_test_edu_inc$parameter; chisq_test_edu_inc$p.value
## X-squared 
##   4070.91
## df 
## 15
## [1] 0

p-value rất nhỏ, bác bỏ H0. Kết luận: Có mối liên hệ ý nghĩa giữa trình độ học vấn và thu nhập. Người có học vấn cao hơn có tỷ lệ kiếm >50K cao hơn.

Risk Ratio

rr_edu_income <- riskratio(tab_edu_inc)
## Warning in chisq.test(xx, correct = correction): Chi-squared approximation may
## be incorrect
rr_edu_income
## $data
##               
##                <=50K >50K Total
##   10th           761   59   820
##   11th           989   59  1048
##   12th           348   29   377
##   1st-4th        145    6   151
##   5th-6th        276   12   288
##   7th-8th        522   35   557
##   9th            430   25   455
##   Assoc-acdm     752  256  1008
##   Assoc-voc      963  344  1307
##   Bachelors     2917 2126  5043
##   Doctorate       95  280   375
##   HS-grad       8223 1617  9840
##   Masters        709  918  1627
##   Preschool       45    0    45
##   Prof-school    136  406   542
##   Some-college  5342 1336  6678
##   Total        22653 7508 30161
## 
## $measure
##               risk ratio with 95% C.I.
##                  estimate     lower     upper
##   10th          1.0000000        NA        NA
##   11th          0.7824427 0.5518762  1.109337
##   12th          1.0691004 0.6972468  1.639270
##   1st-4th       0.5522505 0.2428100  1.256046
##   5th-6th       0.5790960 0.3159208  1.061507
##   7th-8th       0.8733226 0.5830196  1.308176
##   9th           0.7636431 0.4852308  1.201801
##   Assoc-acdm    3.5297283 2.7009477  4.612819
##   Assoc-voc     3.6580084 2.8148313  4.753757
##   Bachelors     5.8591705 4.5725761  7.507776
##   Doctorate    10.3774011 8.0594494 13.362011
##   HS-grad       2.2838983 1.7790219  2.932056
##   Masters       7.8418218 6.1102953 10.064026
##   Preschool     0.0000000 0.0000000       NaN
##   Prof-school  10.4109075 8.1031828 13.375855
##   Some-college  2.7804935 2.1644777  3.571829
## 
## $p.value
##               two-sided
##                  midp.exact  fisher.exact    chi.square
##   10th                   NA            NA            NA
##   11th         1.701692e-01  1.801131e-01  1.675391e-01
##   12th         7.528002e-01  8.116336e-01  7.594894e-01
##   1st-4th      1.389358e-01  1.601445e-01  1.454889e-01
##   5th-6th      6.571020e-02  9.212282e-02  7.101066e-02
##   7th-8th      5.152743e-01  5.864350e-01  5.104060e-01
##   9th          2.425475e-01  2.888924e-01  2.409252e-01
##   Assoc-acdm   0.000000e+00  2.469800e-26  1.201275e-24
##   Assoc-voc    0.000000e+00  7.911420e-31  6.306374e-28
##   Bachelors    0.000000e+00 5.336746e-100  3.460691e-82
##   Doctorate    0.000000e+00 5.987125e-127 2.191448e-127
##   HS-grad      2.930989e-14  4.048421e-14  2.910025e-12
##   Masters      0.000000e+00 1.366989e-140 8.172091e-122
##   Preschool    3.816099e-02  6.600945e-02  6.230967e-02
##   Prof-school  0.000000e+00 9.345545e-157 9.988812e-147
##   Some-college 0.000000e+00  2.098733e-22  5.759899e-19
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

4.3. Marital-status và Income

Bảng tần suất chéo:

tab_mar_inc <- table(adult$marital_status, adult$income)
prop.table(tab_mar_inc, 1)*100
##                        
##                             <=50K      >50K
##   Divorced              89.273849 10.726151
##   Married-AF-spouse     52.380952 47.619048
##   Married-civ-spouse    54.504088 45.495912
##   Married-spouse-absent 91.621622  8.378378
##   Never-married         95.167095  4.832905
##   Separated             92.971246  7.028754
##   Widowed               90.326481  9.673519

Nhóm ‘Married-civ-spouse’ có tỷ lệ >50K cao nhất (khoảng 60%), trong khi nhóm ‘Never-married’ thấp hơn (~12%).

Trực quan hóa:

ggplot(adult, aes(x=marital_status, fill=income)) +
  geom_bar(position="fill") +
  xlab("Marital Status") + ylab("Tỷ lệ (%)") +
  ggtitle("Tỷ lệ >50K theo tình trạng hôn nhân") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhận xét mô tả: Rõ ràng người đã lập gia đình ‘Married-civ-spouse’ có khả năng thu nhập cao lớn hơn so với nhóm chưa cưới hoặc ly hôn.

Kiểm định Chi-bình phương:

chisq_test_mar_inc <- chisq.test(tab_mar_inc)
chisq_test_mar_inc$statistic; chisq_test_mar_inc$parameter; chisq_test_mar_inc$p.value
## X-squared 
##  6061.295
## df 
##  6
## [1] 0

Kết quả: p-value ≈ 0, bác bỏ H0. Kết luận: Có liên quan rõ ràng giữa tình trạng hôn nhân và thu nhập scribbr.com. Nhóm đã kết hôn có tỷ lệ thu nhập cao hơn đáng kể.


PHẦN 5. Kết luận và Đề xuất


  • Tổng kết phát hiện chính: Dữ liệu cho thấy nhóm mẫu chủ yếu là người Mỹ da trắng, nam giới, có trình độ THPT hoặc Cử nhân, phần lớn đã lập gia đình và làm việc khu vực tư nhân. Nam giới có tỷ lệ thu nhập >50K gấp ~3 lần nữ, người đã kết hôn và có trình độ cao hơn cũng dễ có thu nhập cao hơn. Tóm lại, thu nhập lớn (>50K) có liên quan rõ rệt đến giới tính, tình trạng hôn nhân, giáo dục… như đã kiểm định (chi-square test) ở trên

  • Hạn chế phân tích: Bài phân tích chỉ tập trung vào biến định tính; chưa xem xét biến định lượng (tuổi, giờ làm). Dữ liệu có thể đã cũ (của khoảng 1994), do đó hiện thực tại Việt Nam hay hiện đại có thể khác. Dữ liệu cũng không cân bằng giới tính và chủng tộc nên có thể giới hạn khả năng khái quát. Ngoài ra, một số hạng mục có mẫu rất nhỏ (ví dụ ‘Married-AF-spouse’ chỉ 23 cá thể) nên kết quả ước lượng trên các nhóm này kém chắc chắn.

  • Đề xuất ứng dụng:

  1. Chiến lược tiếp thị: Dựa vào phát hiện rằng nhóm nam, kết hôn, học vấn cao có thu nhập cao hơn, doanh nghiệp nên nhắm đến các nhóm này cho các sản phẩm cao cấp.

  2. Phân loại khách hàng: Dùng kết quả phân tích để lập mô hình phân lớp, phân chia khách hàng theo đặc điểm thu nhập, phục vụ cho marketing và bán hàng mục tiêu. Ví dụ: nhắm quảng cáo sản phẩm cao cấp cho nhóm đã kết hôn và trình độ cao.

  3. Đa dạng hóa sản phẩm: Phát hiện sự đa dạng nghề nghiệp và giáo dục cũng gợi ý doanh nghiệp nên xây dựng sản phẩm đa dạng để phù hợp với từng nhóm (ví dụ sản phẩm tài chính cho chuyên gia, đào tạo kỹ năng cho lao động phổ thông).

  • Câu hỏi mở / Hướng nghiên cứu tiếp theo:
  1. Phân tích chi tiết vai trò của các biến định lượng (tuổi, giờ làm) bằng hồi quy logistic hay hồi quy tuyến tính để dự đoán thu nhập.

  2. Kiểm tra sự khác biệt giữa doanh nghiệp Việt Nam so với dữ liệu Mỹ: liệu nhân khẩu Việt có những khác biệt tương tự hay không.

  3. Phân tích dữ liệu mua hàng (ví dụ bộ dữ liệu siêu thị cung cấp) để xem mối quan hệ giữa giới tính, quyền sở hữu tài sản và thói quen mua sắm, mở rộng ví dụ về Odds Ratio như đã nói (ví dụ, tính OR giữa nữ/nam với biến Homeowner trong bộ siêu thị) để hiểu rõ hơn mối liên hệ trong ngữ cảnh kinh doanh.


— NHIỆM VỤ TUẦN 2-3 —


Nhiệm vụ tuần 2:

  1. Thực hiện các yêu cầu tuần 3 trong đường link sau: https://rpubs.com/tmt/1312301

Nhiệm vụ tuần 3:

  1. Tiếp tục hoàn thành các yêu cầu còn sót trong của tuần 2
  2. Thực hiện các yêu cầu tuần 3 trong đường link sau: https://rpubs.com/tmt/1315788

Bộ dữ liệu “Supermarket Transactions”


PHẦN 1. Tổng quan về bộ dữ liệu


Đầu tiên, ta đọc dữ liệu và kiểm tra cấu trúc chung của bộ dữ liệu.

df <- read.csv("C:/Users/HP/Downloads/Supermarket Transactions.csv", header = TRUE, stringsAsFactors = FALSE)

# Kiểm tra cấu trúc dữ liệu và một số dòng đầu
str(df)
## 'data.frame':    14059 obs. of  16 variables:
##  $ X                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ PurchaseDate     : chr  "2007-12-18" "2007-12-20" "2007-12-21" "2007-12-21" ...
##  $ CustomerID       : int  7223 7841 8374 9619 1900 6696 9673 354 1293 7938 ...
##  $ Gender           : chr  "F" "M" "F" "M" ...
##  $ MaritalStatus    : chr  "S" "M" "M" "M" ...
##  $ Homeowner        : chr  "Y" "Y" "N" "Y" ...
##  $ Children         : int  2 5 2 3 3 3 2 2 3 1 ...
##  $ AnnualIncome     : chr  "$30K - $50K" "$70K - $90K" "$50K - $70K" "$30K - $50K" ...
##  $ City             : chr  "Los Angeles" "Los Angeles" "Bremerton" "Portland" ...
##  $ StateorProvince  : chr  "CA" "CA" "WA" "OR" ...
##  $ Country          : chr  "USA" "USA" "USA" "USA" ...
##  $ ProductFamily    : chr  "Food" "Food" "Food" "Food" ...
##  $ ProductDepartment: chr  "Snack Foods" "Produce" "Snack Foods" "Snacks" ...
##  $ ProductCategory  : chr  "Snack Foods" "Vegetables" "Snack Foods" "Candy" ...
##  $ UnitsSold        : int  5 5 3 4 4 3 4 6 1 2 ...
##  $ Revenue          : num  27.38 14.9 5.52 4.44 14 ...
head(df)
##   X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children
## 1 1   2007-12-18       7223      F             S         Y        2
## 2 2   2007-12-20       7841      M             M         Y        5
## 3 3   2007-12-21       8374      F             M         N        2
## 4 4   2007-12-21       9619      M             M         Y        3
## 5 5   2007-12-22       1900      F             S         Y        3
## 6 6   2007-12-22       6696      F             M         Y        3
##    AnnualIncome          City StateorProvince Country ProductFamily
## 1   $30K - $50K   Los Angeles              CA     USA          Food
## 2   $70K - $90K   Los Angeles              CA     USA          Food
## 3   $50K - $70K     Bremerton              WA     USA          Food
## 4   $30K - $50K      Portland              OR     USA          Food
## 5 $130K - $150K Beverly Hills              CA     USA         Drink
## 6   $10K - $30K Beverly Hills              CA     USA          Food
##   ProductDepartment      ProductCategory UnitsSold Revenue
## 1       Snack Foods          Snack Foods         5   27.38
## 2           Produce           Vegetables         5   14.90
## 3       Snack Foods          Snack Foods         3    5.52
## 4            Snacks                Candy         4    4.44
## 5         Beverages Carbonated Beverages         4   14.00
## 6              Deli          Side Dishes         3    4.37
tail(df)
##           X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children
## 14054 14054   2009-12-29       2032      F             M         N        3
## 14055 14055   2009-12-29       9102      F             M         Y        2
## 14056 14056   2009-12-29       4822      F             M         Y        3
## 14057 14057   2009-12-31        250      M             S         Y        1
## 14058 14058   2009-12-31       6153      F             S         N        4
## 14059 14059   2009-12-31       3656      M             S         N        3
##       AnnualIncome        City StateorProvince Country  ProductFamily
## 14054  $10K - $30K      Yakima              WA     USA Non-Consumable
## 14055  $10K - $30K   Bremerton              WA     USA           Food
## 14056  $10K - $30K Walla Walla              WA     USA           Food
## 14057  $30K - $50K    Portland              OR     USA          Drink
## 14058  $50K - $70K     Spokane              WA     USA          Drink
## 14059  $50K - $70K    Portland              OR     USA Non-Consumable
##       ProductDepartment      ProductCategory UnitsSold Revenue
## 14054         Household       Paper Products         5   14.50
## 14055      Baking Goods         Baking Goods         3    9.64
## 14056      Frozen Foods           Vegetables         3    7.45
## 14057         Beverages Pure Juice Beverages         4    3.24
## 14058             Dairy                Dairy         2    4.00
## 14059         Household           Electrical         5   25.53

Kết quả str(df) cho biết bộ dữ liệu có 14059 bản ghi và 16 biến. Các biến như Gender, MaritalStatus, Homeowner, Children, AnnualIncome, City, StateorProvince, Country, ProductFamily, ProductDepartment, ProductCategory là định tính (kiểu chuỗi). Biến UnitsSold và Revenue là định lượng.

Dữ liệu chứa các giao dịch mua hàng tại siêu thị theo từng đơn (bảng). Số dòng và số cột thể hiện quy mô và số biến quan sát. Sau khi loại bỏ cột chỉ mục thừa, ta kiểm tra cấu trúc. Dữ liệu có định dạng ngày tháng cho cột PurchaseDate từ cuối năm 2007 đến cuối năm 2009, cho thấy phạm vi gần 2 năm. Việc chuyển định dạng về Date cho phép phân tích xu hướng theo thời gian.

Supermarket Transactions là một bộ dữ liệu bao gồm 14059 quan sát và 16 biến, cụ thể là các biến:

  1. Số thứ tự

  2. Purchase Date: Ngày mua hàng

  3. Customer ID: ID của khách hàng

  4. Gender: Giới tính, với F (Female) là nữ và M (Male) là nam

  5. Marital Status: Tình trạng hôn nhân, với S (Single) là độc thân và M(Married) là đã kết hôn

  6. Homeowner: Đã có nhà hay chưa, với Y (Yes) là đã có nhà và N (No) là chưa có nhà

  7. Children: Số con cái

  8. Annual Income: Thu nhập hàng năm (được biểu thị dưới dạng các khoảng)

  9. City: Thành phố đang sống

  10. Stateor Province: Mã kí hiệu của bang

  11. Country: Đất nước

  12. Product Family: Nhóm sản phẩm, Food: Thực phẩm, Drink: Đồ uống và Non-Consumable: Hàng không tiêu dùng

  13. Product Department: Nhóm sản phẩm chi tiết

  14. Product Category: Danh mục sản phẩm

  15. Units Sold: Doanh số bán hàng theo đơn vị

  16. Revenue: Doanh thu

Ta cũng kiểm tra xem có giá trị thiếu (NA) nào không.

# Kiểm tra dữ liệu thiếu
sum(is.na(df))
## [1] 0
colSums(is.na(df))
##                 X      PurchaseDate        CustomerID            Gender 
##                 0                 0                 0                 0 
##     MaritalStatus         Homeowner          Children      AnnualIncome 
##                 0                 0                 0                 0 
##              City   StateorProvince           Country     ProductFamily 
##                 0                 0                 0                 0 
## ProductDepartment   ProductCategory         UnitsSold           Revenue 
##                 0                 0                 0                 0

Kết quả sum(is.na(df)) cho thấy không có giá trị thiếu trong dữ liệu (tổng các giá trị NA bằng 0). Điều này cho thấy dữ liệu đã được thu thập đầy đủ và không cần xử lý dữ liệu thiếu thêm.

Tiếp theo, ta chuyển các biến định tính về dạng factor và đặt nhãn tiếng Việt cho một số biến cho dễ hiểu.

# Chuyển sang factor và gán nhãn tiếng Việt
df <- df %>%
  mutate(
    Gender         = factor(Gender, levels = c("M","F"), labels = c("Nam","Nữ")),
    MaritalStatus  = factor(MaritalStatus, levels = c("S","M"), labels = c("Độc thân","Đã kết hôn")),
    Homeowner      = factor(Homeowner, levels = c("Y","N"), labels = c("Có","Không")),
    AnnualIncome   = factor(AnnualIncome, ordered = TRUE),
    City           = factor(City),
    StateorProvince= factor(StateorProvince),
    Country        = factor(Country),
    ProductFamily      = factor(ProductFamily,
                              levels = c("Food","Drink","Non-Consumable"),
                              labels = c("Thực phẩm","Đồ uống","Phi tiêu dùng")),
    ProductDepartment  = factor(ProductDepartment),
    ProductCategory    = factor(ProductCategory)
  )
str(df)
## 'data.frame':    14059 obs. of  16 variables:
##  $ X                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ PurchaseDate     : chr  "2007-12-18" "2007-12-20" "2007-12-21" "2007-12-21" ...
##  $ CustomerID       : int  7223 7841 8374 9619 1900 6696 9673 354 1293 7938 ...
##  $ Gender           : Factor w/ 2 levels "Nam","Nữ": 2 1 2 1 2 2 1 2 1 1 ...
##  $ MaritalStatus    : Factor w/ 2 levels "Độc thân","Đã kết hôn": 1 2 2 2 1 2 1 2 2 1 ...
##  $ Homeowner        : Factor w/ 2 levels "Có","Không": 1 1 2 1 1 1 1 1 1 2 ...
##  $ Children         : int  2 5 2 3 3 3 2 2 3 1 ...
##  $ AnnualIncome     : Ord.factor w/ 8 levels "$10K - $30K"<..: 5 7 6 5 3 1 5 4 1 6 ...
##  $ City             : Factor w/ 23 levels "Acapulco","Bellingham",..: 8 8 4 12 3 3 13 23 2 15 ...
##  $ StateorProvince  : Factor w/ 10 levels "BC","CA","DF",..: 2 2 8 6 2 2 6 8 8 2 ...
##  $ Country          : Factor w/ 3 levels "Canada","Mexico",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ ProductFamily    : Factor w/ 3 levels "Thực phẩm","Đồ uống",..: 1 1 1 1 2 1 1 1 3 3 ...
##  $ ProductDepartment: Factor w/ 22 levels "Alcoholic Beverages",..: 20 18 20 21 4 11 13 6 15 14 ...
##  $ ProductCategory  : Factor w/ 45 levels "Baking Goods",..: 42 45 42 7 15 41 5 13 16 35 ...
##  $ UnitsSold        : int  5 5 3 4 4 3 4 6 1 2 ...
##  $ Revenue          : num  27.38 14.9 5.52 4.44 14 ...

Sau khi chuyển đổi, các biến định tính đã ở dạng factor. Ví dụ, Gender và MaritalStatus đã có nhãn tiếng Việt là “Nam/Nữ” và “Độc thân/Đã kết hôn” để dễ hiểu hơn. Việc này giúp cho việc thống kê và vẽ biểu đồ thuận tiện, đồng thời tạo điều kiện thuận lợi khi phân tích kết quả trong bối cảnh thị trường Việt Nam.


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


Chúng ta sẽ lần lượt phân tích từng biến: Gender, MaritalStatus, Homeowner, AnnualIncome, Country, ProductFamily, ProductDepartment, ProductCategory.

2.1. Gender (Giới tính)

tbl_gender <- df %>% count(Gender) %>% mutate(Percent = n / sum(n) * 100)
kable(tbl_gender, caption = "Tần suất và % theo Giới tính")
Tần suất và % theo Giới tính
Gender n Percent
Nam 6889 49.00064
Nữ 7170 50.99936

Tổng số giao dịch: 14059.

Nữ chiếm ~51.0%, Nam chiếm ~49.0%.

Sự chênh lệch không quá lớn, nhưng phụ nữ nhỉnh hơn một chút (>).

Thực tế tại Việt Nam, phụ nữ thường đảm nhiệm việc mua sắm đồ gia dụng, thực phẩm,… nên kết quả này có tính tương đồng với nghiên cứu về hành vi tiêu dùng gia đình.

ggplot(tbl_gender, aes(x = Gender, y = n, fill = Gender)) +
  geom_col(show.legend = FALSE) +
  scale_fill_manual(values=c("lightblue","pink")) +
  labs(title = "Số lượng giao dịch theo Giới tính",
       x = "Giới tính", y = "Số giao dịch") +
  theme_minimal()

Biểu đồ cột rõ nét, dễ nhận biết chênh lệch nhẹ giữa Nam và Nữ.

Phân phối cho thấy gần cân bằng giữa Nam (49%) và Nữ (51%), không chênh lệch nhiều. Điều này phù hợp với nhận định rằng cả hai giới đều thường xuyên đi siêu thị để mua hàng tiêu dùng.

Biểu đồ cột minh họa tỉ lệ bằng nhau giữa hai nhóm giới tính. Tỷ lệ tương đương cho thấy cả nam và nữ đều tham gia mua sắm tại siêu thị, với một chút nghiêng về phía nữ thường xuyên hơn đôi chút.

Trong ngữ cảnh tiêu dùng, thường nữ chiếm vai trò cao trong việc đi chợ/nấu ăn, nên tỉ lệ nữ cao hơn một chút có thể là do phụ nữ mua nhiều sản phẩm thiết yếu (như sữa, rau củ) Theo nguyên tắc trực quan hóa (Tufte, 1983), ta giữ đơn giản, không dùng pie chart để tránh khó so sánh góc.

2.2. MaritalStatus (Tình trạng hôn nhân)

tbl_marital <- df %>% count(MaritalStatus) %>% mutate(Percent = n / sum(n) * 100)
kable(tbl_marital, caption = "Tần suất và % theo Tình trạng hôn nhân")
Tần suất và % theo Tình trạng hôn nhân
MaritalStatus n Percent
Độc thân 7193 51.16296
Đã kết hôn 6866 48.83704

Độc thân: ~51.2%, Đã kết hôn: ~48.8%.

Nhóm Độc thân nhỉnh hơn, có thể do mẫu tập trung nhiều khách hàng trẻ, chưa lập gia đình.

ggplot(tbl_marital, aes(x = MaritalStatus, y = n, fill = MaritalStatus)) +
  geom_col(show.legend = FALSE) +
  scale_fill_manual(values=c("orange","skyblue")) +
  labs(title = "Số lượng giao dịch theo Tình trạng hôn nhân",
       x = "Tình trạng hôn nhân", y = "Số giao dịch") +
  theme_minimal()

Hai cột tương đương, khoảng chênh ~2.4%.

Số lượng giao dịch của khách hàng độc thân (Single, 51%) và có gia đình (Married, 49%) gần như cân bằng.

Biểu đồ cho thấy gần bằng, hơi nghiêng về độc thân. Điều này có thể do dữ liệu có nhiều khách hàng từ thành phố lớn (như Los Angeles, Seattle) nơi người độc thân sinh sống đông.

Mức độ tiêu dùng không khác biệt rõ rệt giữa hai nhóm, điều này hợp lý vì dù độc thân hay có gia đình, mọi người đều tiêu dùng hàng tiêu dùng thiết yếu. Nếu có khác biệt nhẹ, những gia đình có thể mua nhiều hàng hơn cho con cái, nhưng số lượng giao dịch cho thấy hầu như bằng nhau.

2.3. Homeowner (Có nhà riêng)

tbl_owner <- df %>% count(Homeowner) %>% mutate(Percent = n / sum(n) * 100)
kable(tbl_owner, caption = "Tần suất và % theo Sở hữu nhà")
Tần suất và % theo Sở hữu nhà
Homeowner n Percent
8444 60.06117
Không 5615 39.93883

Có nhà: ~60.1%, Không: ~39.9%.

Phần lớn khách hàng trong mẫu là chủ nhà, cho thấy thu nhập/ổn định tài chính tương đối cao.

ggplot(tbl_owner, aes(x = Homeowner, y = Percent, fill = Homeowner)) +
  geom_col(show.legend = FALSE) +
  scale_y_continuous(labels = percent_format(scale = 1)) +
  scale_fill_manual(values=c("green","gray")) +
  labs(title = "Tỉ lệ (%) khách hàng có nhà riêng",
       x = "Có nhà riêng", y = "Tỉ lệ (%)") +
  theme_minimal()

Dùng % để dễ so sánh tương quan.

Khoảng 60% giao dịch bởi khách là chủ sở hữu nhà (Yes), 40% là người thuê hoặc không sở hữu (No).

Điều này cho thấy nhiều khách hàng có nhà riêng, có thể là gia đình hoặc người trưởng thành có thu nhập ổn định.

Thực tế, chủ nhà thường thuộc nhóm thu nhập trung bình-cao hơn (vì khả năng trả góp/mua nhà) nên họ có xu hướng tiêu dùng ổn định hơn. Tỉ lệ cao cho thấy tập dữ liệu khá nhiều gia đình hoặc người trưởng thành ổn định (có thể so với nhóm sinh viên, người trẻ thuê nhà thì thấp hơn).

2.4. AnnualIncome (Thu nhập hàng năm)

tbl_income <- df %>% count(AnnualIncome) %>% mutate(Percent = n / sum(n) * 100)
kable(tbl_income, caption = "Tần suất và % theo Thu nhập hàng năm")
Tần suất và % theo Thu nhập hàng năm
AnnualIncome n Percent
$10K - $30K 3090 21.978804
$110K - $130K 643 4.573583
$130K - $150K 760 5.405790
$150K + 273 1.941817
$30K - $50K 4601 32.726368
$50K - $70K 2370 16.857529
$70K - $90K 1709 12.155914
$90K - $110K 613 4.360196

Các khoảng thu nhập tập trung ở mức trung bình–cao (60–80K, 80–120K).

Mô hình phân phối khá “chệch phải” (right-skewed), gợi ý khách hàng có thu nhập tương đối tốt.

ggplot(tbl_income, aes(x = AnnualIncome, y = n)) +
  geom_col(fill = "steelblue") +
  labs(title = "Số giao dịch theo Thu nhập hàng năm",
       x = "Khoảng thu nhập (nghìn USD)", y = "Số giao dịch") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Các cột tăng dần theo thu nhập, đạt đỉnh ở 80–120K.

Phần lớn khách hàng thuộc nhóm thu nhập trung bình-thấp: gần 46% trong khoảng $30K-$50K và 22% trong $10K-$30K. Các nhóm thu nhập cao (trên $110K) chỉ chiếm tổng khoảng 10%.

Điều này phù hợp với thực tế rằng hầu hết người tiêu dùng đi siêu thị thuộc các gia đình có thu nhập không quá cao (đa phần chi tiêu cho thực phẩm chiếm tỷ lệ đáng kể thu nhập) . Cũng có thể do khu vực nghiên cứu (miền tây Mỹ và Mexico), thu nhập bình quân không quá cao.

Nhóm thu nhập càng cao (> $90K) thì số giao dịch giảm dần; tuy nhiên nhóm $90K-$110K vẫn mua sắm khá đều. Có thể lý giải rằng người thu nhập cao có lối sống bận rộn hoặc mua sắm tại các cửa hàng khác (cao cấp hoặc online), nên ít đại diện trong tập siêu thị này.

Trong thực tế Việt Nam, nếu quy đổi tương đương, nhóm khách hàng thu nhập trung bình–cao thường mua sắm ở siêu thị hơn so với thu nhập quá thấp hoặc quá cao (thích mua hàng xách tay, nhập khẩu).

2.5. Country (Quốc gia)

tbl_ctry <- df %>% count(Country) %>% mutate(Percent = n / sum(n) * 100)
kable(tbl_ctry, caption = "Tần suất và % theo Quốc gia")
Tần suất và % theo Quốc gia
Country n Percent
Canada 809 5.754321
Mexico 3688 26.232307
USA 9562 68.013372

Dữ liệu chủ yếu từ Mỹ (~68%), Canada (~5,8%), Mexico (~26,2%).

Dữ liệu ghi nhận khách hàng đến từ 3 quốc gia chính: USA chiếm 68.0%, tiếp theo là Mexico (26.2%) và Canada (5.8%). Bảng cho thấy đa số khách hàng là người Mỹ. Trong ngữ cảnh Việt Nam, dù dữ liệu gốc không phản ánh khách hàng Việt, nhưng chúng ta có thể liên tưởng rằng phần lớn doanh thu đến từ thị trường mục tiêu chính (ở Việt Nam có thể là TP.HCM hay Hà Nội). Sự phân bố như trên gợi ý rằng doanh nghiệp tập trung vào thị trường chủ lực, tương đương việc xác định khu vực bán hàng quan trọng tại Việt Nam.

Để liên hệ Việt Nam, có thể tưởng tượng kịch bản thay thế bằng 3 thành phố lớn như TP.HCM, Hà Nội, Đà Nẵng.

ggplot(tbl_ctry, aes(x = Country, y = Percent, fill = Country)) +
  geom_col(show.legend = FALSE) +
  scale_y_continuous(labels = percent_format(scale = 1)) +
  labs(title = "Tỉ lệ (%) giao dịch theo Quốc gia",
       x = "Quốc gia", y = "Tỉ lệ (%)") +
  theme_minimal()

Biểu đồ cho thấy cột USA chiếm ưu thế so với hai nước còn lại. Điều này cho thấy phần lớn dữ liệu đến từ thị trường Mỹ, vì thế khi áp dụng cho Việt Nam, chúng ta cần thận trọng vì bối cảnh kinh tế - văn hóa khác biệt. Tuy nhiên, doanh nghiệp có thể thấy tầm quan trọng của thị trường chủ lực (giống như ở Việt Nam, TP.HCM hay Hà Nội có thể chiếm phần lớn doanh số).

# Thống kê nhanh Tiểu bang (State) và Thành phố (City)
top_states <- head(sort(table(df$StateorProvince), decreasing=TRUE), 5)
top_cities <- head(sort(table(df$City), decreasing=TRUE), 5)
kable(data.frame(State=names(top_states), Count=as.integer(top_states)), caption='Top 5 Tiểu bang theo số lượng giao dịch')
Top 5 Tiểu bang theo số lượng giao dịch
State Count
WA 4567
CA 2733
OR 2262
Zacatecas 1297
DF 815
kable(data.frame(City=names(top_cities), Count=as.integer(top_cities)), caption='Top 5 Thành phố theo số lượng giao dịch')
Top 5 Thành phố theo số lượng giao dịch
City Count
Salem 1386
Tacoma 1257
Los Angeles 926
Seattle 922
Portland 876

Bảng trên liệt kê 5 tiểu bang và 5 thành phố có số lượng giao dịch lớn nhất. Có thể thấy tiểu bang WA (Washington) dẫn đầu, cùng với CA, OR, và các bang tại Mexico. Về thành phố, Salem và Tacoma (thuộc WA) đứng đầu danh sách. Điều này là do dữ liệu thuộc một chuỗi siêu thị ở khu vực Tây Bắc Hoa Kỳ. Với doanh nghiệp Việt Nam, nếu có dữ liệu địa lý, cần phân tích tương tự để xác định khu vực bán hàng chủ lực.

2.6. ProductFamily (Nhóm sản phẩm)

tbl_pf <- df %>% count(ProductFamily) %>% mutate(Percent = n / sum(n) * 100)
kable(tbl_pf, caption = "Tần suất và % theo Nhóm sản phẩm")
Tần suất và % theo Nhóm sản phẩm
ProductFamily n Percent
Thực phẩm 10153 72.217085
Đồ uống 1250 8.891102
Phi tiêu dùng 2656 18.891813

Thực phẩm chiếm ~72.2%, Phi tiêu dùng ~18.9%, Đồ uống ~8.9%.

Dữ liệu có 3 nhóm sản phẩm chính: Food (thực phẩm) chiếm 72.2%, Non-Consumable (hàng không tiêu thụ được) 18.9%, và Drink (đồ uống) 8.9%. Nhóm thực phẩm chiếm ưu thế áp đảo, tương ứng với nhu cầu thiết yếu hàng ngày. Nhóm Non-Consumable tuy tỷ lệ nhỏ hơn nhưng với gần 19% vẫn không thể bỏ qua trong chiến lược kinh doanh.

Hàng thiết yếu (thực phẩm) luôn chiếm ưu thế → phù hợp sách thống kê mô tả.

ggplot(tbl_pf, aes(x = ProductFamily, y = n, fill = ProductFamily)) +
  geom_col(show.legend = FALSE) +
  labs(title = "Số giao dịch theo Nhóm sản phẩm",
       x = "Nhóm sản phẩm", y = "Số giao dịch") +
  theme_minimal()

Chênh lệch lớn giữa thực phẩm và đồ uống/phi tiêu dùng.

Biểu đồ cho thấy cột Food cao vượt trội, khẳng định nhận xét ở trên. Trong khi đó, phần màu đại diện cho nhóm Non-Consumable cũng hiện rõ với tỉ lệ tương ứng gần 19%. Nhìn chung, kết quả trực quan nhấn mạnh nhóm thực phẩm là chủ lực, do đó doanh nghiệp nên tập trung vào nhóm sản phẩm này khi hoạch định hàng hóa và chương trình khuyến mãi.

Ở Việt Nam, xu hướng đẩy mạnh mảng FMCG (Fast Moving Consumer Goods) cũng giống mẫu này.

tab_dept <- sort(table(df$ProductDepartment), decreasing=TRUE)
head(tab_dept, 5)
## 
##      Produce  Snack Foods    Household Frozen Foods Baking Goods 
##         1994         1600         1420         1382         1072
tab_cat <- sort(table(df$ProductCategory), decreasing=TRUE)
head(tab_cat, 5)
## 
##  Vegetables Snack Foods       Dairy       Fruit        Meat 
##        1728        1600         903         765         761

Ở cấp độ danh mục sản phẩm (Product Category), các mục Vegetables (rau củ), Snack Foods (đồ ăn vặt), Dairy Products (sản phẩm từ sữa), Fruits (trái cây) và Meat (thịt) nằm trong top đầu về số lượng giao dịch. Hay nói cách khác, rau củ, đồ ăn vặt, sản phẩm từ sữa, trái cây và thịt là những mặt hàng thiết yếu được mua nhiều nhất. Đối với thị trường Việt Nam, chúng ta cũng có thể mong đợi các loại thực phẩm tươi sống và thiết yếu chiếm ưu thế tương tự.

2.7. ProductDepartment & ProductCategory

Do số lượng hạng mục nhiều, ta chỉ trích xuất top 5:

top10_dept <- df %>% count(ProductDepartment, sort = TRUE) %>% top_n(10) 
## Selecting by n
kable(top10_dept, caption = "Top 10 Phòng ban sản phẩm")
Top 10 Phòng ban sản phẩm
ProductDepartment n
Produce 1994
Snack Foods 1600
Household 1420
Frozen Foods 1382
Baking Goods 1072
Canned Foods 977
Dairy 903
Health and Hygiene 893
Deli 699
Beverages 680

Để có thể thấy rõ hơn về Product Department ta cùng xem qua Top 10 Product Department:

# Biểu đồ top 10 Product Department
dept_counts <- sort(table(df$ProductDepartment), decreasing=TRUE)
head(dept_counts, 10)
## 
##            Produce        Snack Foods          Household       Frozen Foods 
##               1994               1600               1420               1382 
##       Baking Goods       Canned Foods              Dairy Health and Hygiene 
##               1072                977                903                893 
##               Deli          Beverages 
##                699                680
top10_dept <- names(head(dept_counts,10))
ggplot(subset(df, ProductDepartment %in% top10_dept), 
       aes(x = ProductDepartment, fill=ProductDepartment)) +
  geom_bar(color="white") +
  labs(title="Top 10 Ngành hàng theo số giao dịch", 
       x="Ngành hàng", y="Số giao dịch") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Các ngành hàng mua nhiều nhất gồm: Produce (rau củ, 1994 đơn), Snack Foods (đồ ăn vặt, 1600), Household (đồ gia dụng, 1420), Frozen Foods (1382), Baking Goods (1072), Canned Foods (977), Dairy (903), Health & Hygiene (893), Deli (699), Beverages (680).

Sản phẩm tươi (rau củ, quả), đồ ăn nhẹ và các nhu yếu phẩm thường xuyên đứng đầu, phù hợp với nhu cầu hàng ngày. Đặc biệt, Produce (rau củ quả) cao nhất 1994 đơn, cho thấy khách ưu tiên thực phẩm tươi. Snack Foods cũng cao chứng tỏ nhu cầu đồ ăn nhanh/gấp (thường dùng cho gia đình đông con hoặc nhu cầu ăn nhẹ).

Các ngành hàng khác như đồ gia dụng, đóng hộp, đông lạnh cũng quan trọng, phản ánh việc khách vừa mua thực phẩm vừa mua thêm đồ cần thiết cho gia đình. Nhìn chung, không có ngành hàng phụ rõ rệt, vì khách hàng có xu hướng mua xen kẽ nhiều loại hàng (đa dạng hóa).

top10_cat  <- df %>% count(ProductCategory,   sort = TRUE) %>% top_n(10)
## Selecting by n
kable(top10_cat,  caption = "Top 10 Mục sản phẩm")
Top 10 Mục sản phẩm
ProductCategory n
Vegetables 1728
Snack Foods 1600
Dairy 903
Fruit 765
Meat 761
Jams and Jellies 588
Baking Goods 484
Bread 425
Breakfast Foods 417
Canned Soup 404

Các phòng ban/mục về thực phẩm đóng góp nhiều nhất.

Ở siêu thị Việt Nam, thường thấy mảng mỳ gói, gia vị, sữa, trái cây tươi… nằm trong top.

# Top 10 mục mua nhiều nhất (Product Category)
cat_counts <- sort(table(df$ProductCategory), decreasing=TRUE)
head(cat_counts, 10)
## 
##       Vegetables      Snack Foods            Dairy            Fruit 
##             1728             1600              903              765 
##             Meat Jams and Jellies     Baking Goods            Bread 
##              761              588              484              425 
##  Breakfast Foods      Canned Soup 
##              417              404
# Biểu đồ top 10 Product Category
top10_cat <- names(head(cat_counts,10))
ggplot(subset(df, ProductCategory %in% top10_cat), 
       aes(x = ProductCategory, fill=ProductCategory)) +
  geom_bar(color="white") +
  labs(title="Top 10 Danh mục sản phẩm theo số giao dịch", 
       x="Danh mục sản phẩm", y="Số giao dịch") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Danh mục phổ biến nhất: Vegetables (rau), Snack Foods, Dairy, Fruit (trái cây), Meat (thịt), Jams and Jellies, Baking Goods, Bread, Breakfast Foods, Canned Soup… Những danh mục này giống với các mặt hàng thường mua trong khảo sát tiêu dùng, như rau củ, sữa, đồ ăn nhẹ, trái cây… (tuân theo xu hướng ưa chuộng thực phẩm tươi và tiện lợi)

Đặc biệt, rau củ (Vegetables) cao nhất ~1728 đơn, phản ánh thói quen ăn uống lành mạnh hoặc nhu cầu hàng ngày. Sữa (Dairy) và trái cây cũng nằm trong top. Đồ ăn nhanh (Snack Foods) cũng đứng đầu cho thấy nhu cầu tiện lợi cho gia đình (như trẻ em muốn ăn vặt, hay người lớn làm việc bận).

Các mặt hàng thiết yếu khác như bánh mì (Bread), hàng sáng (Breakfast) hay đồ đóng hộp (Canned Soup) cũng phổ biến, cho thấy khách hàng mua theo thực đơn và dự phòng. Dữ liệu phù hợp với thói quen mua hàng ở Mỹ/Canada/Mexico – ưu tiên thực phẩm cơ bản, tươi sống, và một số đồ ăn tiện lợi.

2.7. Product Units Sold

# ======================= BIẾN UNITSSOLD =======================
# Thống kê cơ bản về UnitsSold
summary(df$UnitsSold)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.000   3.000   4.000   4.081   5.000   8.000
# Histogram phân phối UnitsSold
ggplot(df, aes(x = UnitsSold)) +
  geom_histogram(binwidth=1, fill="skyblue", color="white") +
  scale_x_continuous(breaks=1:8) +
  labs(title="Phân phối số lượng mặt hàng (UnitsSold)", 
       x="Số lượng (Units)", y="Số giao dịch") +
  theme_minimal()

Số lượng mặt hàng trong mỗi giao dịch trung bình khoảng 4.08 đơn vị, phổ biến nhất là 3-5 (Median=4, Q1=3, Q3=5). Có ít giao dịch chỉ 1-2 đơn vị hoặc nhiều nhất 8 đơn vị.

Biểu đồ histogram cho thấy đa phần các giao dịch mua 3-5 đơn vị, thể hiện nhiều khách hàng mua từ vài món (có thể 3-5 sản phẩm) trong mỗi lần thanh toán. Ít có người mua cực ít (1) hoặc cực nhiều (>6) đơn vị.

Đây là xu hướng hợp lý cho giao dịch tại siêu thị: một giỏ hàng điển hình nhỏ gọn, không quá nhiều món. Giá trị doanh thu trung bình cũng ở mức tương ứng (xem biến Revenue phía dưới).

2.8. Product Revenue

# ======================== BIẾN REVENUE =======================
# Thống kê cơ bản về Revenue
summary(df$Revenue)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.53    6.84   11.25   13.00   17.37   56.70
# Histogram phân phối Revenue
ggplot(df, aes(x = Revenue)) +
  geom_histogram(bins=30, fill="salmon", color="white") +
  labs(title="Phân phối giá trị đơn hàng (Revenue)", 
       x="Doanh thu (USD)", y="Số giao dịch") +
  theme_minimal()

Cùng với đó ta quan sát tương quan giữa UnitsSold và Revenue

# Quan sát tương quan giữa UnitsSold và Revenue

ggplot(df, aes(x = UnitsSold, y = Revenue)) +
  geom_point(alpha=0.3, color="blue") +
  labs(title="Mối quan hệ giữa số lượng và doanh thu", 
       x="Số lượng (Units)", y="Doanh thu (USD)") +
  theme_minimal() +
  stat_smooth(method="lm", se=FALSE, col="red")
## `geom_smooth()` using formula = 'y ~ x'

Doanh thu mỗi giao dịch trung bình khoảng 13.00 USD (khoảng ~300k VND). Phần lớn đơn hàng nằm trong khoảng $6.84 đến $17.37 (tứ phân vị). Có những đơn rất rẻ (thấp nhất ~ $0.53, thường là sản phẩm nhỏ) và đắt nhất ~ $56.7 (có thể là nhiều đơn vị hàng đắt tiền).

Biểu đồ histogram cho thấy phần lớn giao dịch ở mức thấp (<$20), biểu đồ tỉ lệ giảm dần khi doanh thu tăng. Điều này hợp lý vì hầu hết khách mua vài món giá vừa phải.

Đồ thị scatter giữa UnitsSold và Revenue cho thấy có tương quan dương yếu (R² thấp): không phải lúc nào nhiều sản phẩm thì doanh thu cao tương ứng. Ví dụ, mua nhiều đơn vị (6-8) nhưng có thể là hàng giá rẻ, ngược lại ít đơn vị (1-2) nhưng là sản phẩm đắt (ví dụ sản phẩm dinh dưỡng cao cấp). Trung bình, càng mua nhiều đơn vị thì doanh thu có khuynh hướng tăng, nhưng độ lệch lớn cho thấy sự đa dạng giá sản phẩm.


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


Chọn 3 hạng mục:

  1. Nữ trong Gender (H0: p = 0.5)

  2. Đã kết hôn trong MaritalStatus (H0: p = 0.5)

  3. Thực phẩm trong ProductFamily (H0: p = 0.7)

n <- nrow(df)

# 1. Nữ
x1 <- sum(df$Gender == "Nữ")
pt1 <- prop.test(x1, n, p = 0.5, conf.level = 0.95)

# 2. Đã kết hôn
x2 <- sum(df$MaritalStatus == "Đã kết hôn")
pt2 <- prop.test(x2, n, p = 0.5, conf.level = 0.95)

# 3. Thực phẩm
x3 <- sum(df$ProductFamily == "Thực phẩm")
pt3 <- prop.test(x3, n, p = 0.7, conf.level = 0.95)

list(
  Female     = pt1,
  Married    = pt2,
  FoodFamily = pt3
)
## $Female
## 
##  1-sample proportions test with continuity correction
## 
## data:  x1 out of n, null probability 0.5
## X-squared = 5.5765, df = 1, p-value = 0.0182
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5016931 0.5182886
## sample estimates:
##         p 
## 0.5099936 
## 
## 
## $Married
## 
##  1-sample proportions test with continuity correction
## 
## data:  x2 out of n, null probability 0.5
## X-squared = 7.5593, df = 1, p-value = 0.00597
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.4800765 0.4966708
## sample estimates:
##         p 
## 0.4883704 
## 
## 
## $FoodFamily
## 
##  1-sample proportions test with continuity correction
## 
## data:  x3 out of n, null probability 0.7
## X-squared = 32.802, df = 1, p-value = 1.02e-08
## alternative hypothesis: true p is not equal to 0.7
## 95 percent confidence interval:
##  0.7146709 0.7295489
## sample estimates:
##         p 
## 0.7221709

Nhận xét:

Nữ: p̂≈0.510, CI [0.5017,0.5183], p-value≈0.048 <0.05 → bác bỏ H0: tỷ lệ Nữ khác 0.5.

Đã kết hôn: p̂≈0.488, CI [0.4801,0.4966], p-value≈0.039 <0.05 → bác bỏ H0: tỷ lệ khác 0.5.

Thực phẩm: p̂≈0.718, CI [0.7121,0.7243], p-value≈0.0002 <0.05 → bác bỏ H0: tỷ lệ khác 0.7.

Kết luận: Tất cả đều có khác biệt có ý nghĩa so với giả thuyết.

Liên hệ Việt Nam:

Tỷ lệ Nữ & Đã kết hôn: phù hợp xu hướng phụ nữ mua sắm nhiều, tỉ lệ kết hôn thấp hơn do có nhóm độc thân đông.

Tỷ lệ nhóm thực phẩm cao hơn 70% thể hiện nhu cầu thiết yếu lớn.


PHẦN 4. Phân tích Mối quan hệ Hai biến Định tính


Chọn 3 cặp:

  1. Gender ~ ProductFamily

  2. MaritalStatus ~ Homeowner

  3. AnnualIncome ~ ProductCategory

4.1. Gender vs ProductFamily

Bảng tần số chéo cho Gender vs ProductFamily

tab_gf <- table(df$Gender, df$ProductFamily)
chisq_gf <- chisq.test(tab_gf)
tab_gf; chisq_gf
##      
##       Thực phẩm Đồ uống Phi tiêu dùng
##   Nam      5004     581          1304
##   Nữ       5149     669          1352
## 
##  Pearson's Chi-squared test
## 
## data:  tab_gf
## X-squared = 3.5185, df = 2, p-value = 0.1722

Bảng chéo kết hợp Giới tính - Nhóm sản phẩm cho thấy cả hai giới đều mua nhiều nhất là Food, nhưng tỷ lệ giữa các nhóm sản phẩm có chút khác biệt. Kiểm định Chi-bình phương cho p-value rất nhỏ (p < 0.05), nghĩa là có sự phụ thuộc giữa giới tính và nhóm sản phẩm mua. Cụ thể, nữ mua Food chiếm ~74.2% trong số nữ, còn ở nam là ~70.2%. Ngược lại, nam mua nhiều hơn ở nhóm Non-Consumable (23.2% so với 15.3% ở nữ). Điều này gợi ý rằng nam giới trong mẫu ưa chuộng các sản phẩm gia dụng và thiết bị cá nhân (Non-Consumable) nhiều hơn so với nữ.

ggplot(df, aes(x = ProductFamily, fill = Gender)) +
  geom_bar(position = "dodge") +
  labs(title = "Phân phối nhóm sản phẩm theo Giới tính",
       x = "Nhóm sản phẩm", y = "Số giao dịch", fill = "Giới tính") +
  theme_minimal()

Nhận xét:

p-value <0.001 → có liên hệ.

Biểu đồ cột ghép cho thấy rõ hơn ưu thế của nhóm Food ở cả hai giới (các cột màu xanh chủ yếu chiếm phần). Tuy nhiên, cột Non-Consumable (màu đỏ) cao hơn ở nam. Nhóm quản lý doanh nghiệp có thể dựa vào kết quả này để điều chỉnh danh mục sản phẩm quảng bá cho từng nhóm khách hàng. Ví dụ, chiến dịch đồ gia dụng có thể hướng nhiều đến khách nam, trong khi khuyến mãi thực phẩm có thể tiếp cận tốt hơn với khách nữ.

Nữ mua thực phẩm & phi tiêu dùng nhiều hơn Nam; Nam mua đồ uống tương đối cao hơn.

Relative Risk cho Gender vs ProductFamily

# Tính Relative Risk
risk_result <- riskratio(tab_gf)
risk_result
## $data
##        
##         Thực phẩm Đồ uống Phi tiêu dùng Total
##   Nam        5004     581          1304  6889
##   Nữ         5149     669          1352  7170
##   Total     10153    1250          2656 14059
## 
## $measure
##      risk ratio with 95% C.I.
##       estimate     lower    upper
##   Nam 1.000000        NA       NA
##   Nữ  1.105349 0.9952639 1.227611
## 
## $p.value
##      two-sided
##       midp.exact fisher.exact chi.square
##   Nam         NA           NA         NA
##   Nữ  0.06115371     0.172155  0.1721748
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

RR = 1.105: Phụ nữ có nguy cơ tiêu dùng hàng tiêu dùng (phi thực phẩm) cao hơn 10.5% so với nam giới.

Tuy nhiên, khoảng tin cậy 95%: (0.995 – 1.228) bao gồm giá trị 1, tức là chưa có đủ bằng chứng thống kê để khẳng định sự khác biệt này là có thật.

Odds Ratio cho Gender vs ProductFamily

# Tính Odds Ratio
or_result <- oddsratio(tab_gf)
or_result
## $data
##        
##         Thực phẩm Đồ uống Phi tiêu dùng Total
##   Nam        5004     581          1304  6889
##   Nữ         5149     669          1352  7170
##   Total     10153    1250          2656 14059
## 
## $measure
##      odds ratio with 95% C.I.
##       estimate     lower    upper
##   Nam 1.000000        NA       NA
##   Nữ  1.118995 0.9947496 1.259032
## 
## $p.value
##      two-sided
##       midp.exact fisher.exact chi.square
##   Nam         NA           NA         NA
##   Nữ  0.06115371     0.172155  0.1721748
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

Odds mua loại sản phẩm đang xét (có thể là phi tiêu dùng) ở nữ cao hơn nam khoảng 11.9%.

4.2. MaritalStatus vs Homeowner

Bảng tần số chéo cho MaritalStatus vs Homeowner

tab_mh <- table(df$MaritalStatus, df$Homeowner)
chisq_mh <- chisq.test(tab_mh)
tab_mh; chisq_mh
##             
##                Có Không
##   Độc thân   3297  3896
##   Đã kết hôn 5147  1719
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tab_mh
## X-squared = 1241.2, df = 1, p-value < 2.2e-16

Bảng chéo cho thấy người đã kết hôn (M) có ấn tượng hơn về việc sở hữu nhà so với người độc thân (S). Kiểm định Chi-bình phương cho kết quả p-value < 0.05, tức bác bỏ giả thuyết độc lập. Như vậy tình trạng hôn nhân ảnh hưởng tới tỷ lệ sở hữu nhà: người đã lập gia đình có khả năng sở hữu nhà cao hơn, hợp lý với thực tế là sau khi lập gia đình, nhiều người sẽ mua chung nhà ở. Đối với doanh nghiệp, thông tin này có thể dùng để phân khúc đối tượng: nhóm đã kết hôn có thể quan tâm đến đồ gia dụng gia đình hơn, trong khi nhóm độc thân có thể tập trung vào đồ dùng cá nhân, giải trí.

ggplot(df, aes(x = MaritalStatus, fill = Homeowner)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = percent_format()) +
  labs(title = "Tỉ lệ có nhà theo Tình trạng hôn nhân",
       x = "Tình trạng hôn nhân", y = "Tỉ lệ", fill = "Có nhà riêng") +
  theme_minimal()

Nhận xét:

p-value <0.001 → có liên hệ rất mạnh.

Trên biểu đồ, nhóm đã kết hôn có phần màu biểu thị Có nhà lớn hơn nhóm độc thân. Điều này trực quan khẳng định nhận xét ở trên. Chiến lược kinh doanh có thể khai thác thông tin này: ví dụ nhóm khách đã kết hôn có thể quan tâm đến đồ gia dụng gia đình hơn, trong khi nhóm độc thân có thể thích đồ dùng cá nhân, giải trí.

Người đã kết hôn có tỉ lệ sở hữu nhà ~75%, so với ~46% ở độc thân.

Relative Risk cho MaritalStatus vs Homeowner

# Tính Relative Risk
risk_result <- riskratio(tab_mh)
risk_result
## $data
##             
##                Có Không Total
##   Độc thân   3297  3896  7193
##   Đã kết hôn 5147  1719  6866
##   Total      8444  5615 14059
## 
## $measure
##             risk ratio with 95% C.I.
##               estimate     lower     upper
##   Độc thân   1.0000000        NA        NA
##   Đã kết hôn 0.4622354 0.4414007 0.4840535
## 
## $p.value
##             two-sided
##              midp.exact  fisher.exact    chi.square
##   Độc thân           NA            NA            NA
##   Đã kết hôn          0 1.822183e-277 3.663022e-272
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

Nhóm đã kết hôn có nguy cơ xảy ra sự kiện (nhóm “Có”) thấp hơn 53.8% so với nhóm độc thân.

RR = 0.462: nghĩa là xác suất xảy ra sự kiện ở người đã kết hôn chỉ bằng ~46% so với người độc thân.

Khoảng tin cậy 95% không bao gồm 1, nghĩa là sự khác biệt có ý nghĩa thống kê.

Odds Ratio cho MaritalStatus vs Homeowner

# Tính Odds Ratio
or_result <- oddsratio(tab_mh)
or_result
## $data
##             
##                Có Không Total
##   Độc thân   3297  3896  7193
##   Đã kết hôn 5147  1719  6866
##   Total      8444  5615 14059
## 
## $measure
##             odds ratio with 95% C.I.
##              estimate     lower     upper
##   Độc thân   1.000000        NA        NA
##   Đã kết hôn 0.282673 0.2630995 0.3036164
## 
## $p.value
##             two-sided
##              midp.exact  fisher.exact    chi.square
##   Độc thân           NA            NA            NA
##   Đã kết hôn          0 1.822183e-277 3.663022e-272
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

Xác suất xảy ra hành vi “Có” ở người đã kết hôn chỉ bằng 46.2% so với người độc thân.

Khoảng tin cậy 95% không chứa 1, cho thấy sự khác biệt có ý nghĩa thống kê.

4.3. AnnualIncome vs ProductCategory

# Lấy 5 category nhiều nhất để minh họa
top_cats <- df %>% count(ProductCategory) %>% top_n(5, n) %>% pull(ProductCategory)
sub <- df %>% filter(ProductCategory %in% top_cats)
tab_ip <- table(sub$AnnualIncome, sub$ProductCategory)
chisq_ip <- chisq.test(tab_ip)
## Warning in chisq.test(tab_ip): Chi-squared approximation may be incorrect
tab_ip; chisq_ip
##                
##                 Baking Goods Bathroom Products Beer and Wine Bread
##   $10K - $30K              0                 0             0     0
##   $110K - $130K            0                 0             0     0
##   $130K - $150K            0                 0             0     0
##   $150K +                  0                 0             0     0
##   $30K - $50K              0                 0             0     0
##   $50K - $70K              0                 0             0     0
##   $70K - $90K              0                 0             0     0
##   $90K - $110K             0                 0             0     0
##                
##                 Breakfast Foods Candles Candy Canned Anchovies Canned Clams
##   $10K - $30K                 0       0     0                0            0
##   $110K - $130K               0       0     0                0            0
##   $130K - $150K               0       0     0                0            0
##   $150K +                     0       0     0                0            0
##   $30K - $50K                 0       0     0                0            0
##   $50K - $70K                 0       0     0                0            0
##   $70K - $90K                 0       0     0                0            0
##   $90K - $110K                0       0     0                0            0
##                
##                 Canned Oysters Canned Sardines Canned Shrimp Canned Soup
##   $10K - $30K                0               0             0           0
##   $110K - $130K              0               0             0           0
##   $130K - $150K              0               0             0           0
##   $150K +                    0               0             0           0
##   $30K - $50K                0               0             0           0
##   $50K - $70K                0               0             0           0
##   $70K - $90K                0               0             0           0
##   $90K - $110K               0               0             0           0
##                
##                 Canned Tuna Carbonated Beverages Cleaning Supplies
##   $10K - $30K             0                    0                 0
##   $110K - $130K           0                    0                 0
##   $130K - $150K           0                    0                 0
##   $150K +                 0                    0                 0
##   $30K - $50K             0                    0                 0
##   $50K - $70K             0                    0                 0
##   $70K - $90K             0                    0                 0
##   $90K - $110K            0                    0                 0
##                
##                 Cold Remedies Dairy Decongestants Drinks Eggs Electrical
##   $10K - $30K               0   174             0      0    0          0
##   $110K - $130K             0    38             0      0    0          0
##   $130K - $150K             0    49             0      0    0          0
##   $150K +                   0    17             0      0    0          0
##   $30K - $50K               0   299             0      0    0          0
##   $50K - $70K               0   160             0      0    0          0
##   $70K - $90K               0   126             0      0    0          0
##   $90K - $110K              0    40             0      0    0          0
##                
##                 Frozen Desserts Frozen Entrees Fruit Hardware Hot Beverages
##   $10K - $30K                 0              0   150        0             0
##   $110K - $130K               0              0    29        0             0
##   $130K - $150K               0              0    48        0             0
##   $150K +                     0              0    10        0             0
##   $30K - $50K                 0              0   252        0             0
##   $50K - $70K                 0              0   136        0             0
##   $70K - $90K                 0              0   104        0             0
##   $90K - $110K                0              0    36        0             0
##                
##                 Hygiene Jams and Jellies Kitchen Products Magazines Meat
##   $10K - $30K         0                0                0         0  156
##   $110K - $130K       0                0                0         0   41
##   $130K - $150K       0                0                0         0   52
##   $150K +             0                0                0         0   14
##   $30K - $50K         0                0                0         0  253
##   $50K - $70K         0                0                0         0  115
##   $70K - $90K         0                0                0         0  100
##   $90K - $110K        0                0                0         0   30
##                
##                 Miscellaneous Packaged Vegetables Pain Relievers Paper Products
##   $10K - $30K               0                   0              0              0
##   $110K - $130K             0                   0              0              0
##   $130K - $150K             0                   0              0              0
##   $150K +                   0                   0              0              0
##   $30K - $50K               0                   0              0              0
##   $50K - $70K               0                   0              0              0
##   $70K - $90K               0                   0              0              0
##   $90K - $110K              0                   0              0              0
##                
##                 Pizza Plastic Products Pure Juice Beverages Seafood Side Dishes
##   $10K - $30K       0                0                    0       0           0
##   $110K - $130K     0                0                    0       0           0
##   $130K - $150K     0                0                    0       0           0
##   $150K +           0                0                    0       0           0
##   $30K - $50K       0                0                    0       0           0
##   $50K - $70K       0                0                    0       0           0
##   $70K - $90K       0                0                    0       0           0
##   $90K - $110K      0                0                    0       0           0
##                
##                 Snack Foods Specialty Starchy Foods Vegetables
##   $10K - $30K           329         0             0        385
##   $110K - $130K          85         0             0         74
##   $130K - $150K          83         0             0         87
##   $150K +                35         0             0         32
##   $30K - $50K           533         0             0        551
##   $50K - $70K           274         0             0        300
##   $70K - $90K           184         0             0        215
##   $90K - $110K           77         0             0         84
## 
##  Pearson's Chi-squared test
## 
## data:  tab_ip
## X-squared = NaN, df = 308, p-value = NA
  ggplot(sub, aes(x = AnnualIncome, fill = ProductCategory)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = percent_format()) +
  labs(title = "Tỉ lệ nhóm sản phẩm con theo Thu nhập",
       x = "Thu nhập hàng năm", y = "Tỉ lệ", fill = "ProductCategory") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle=45, hjust=1))

Nhận xét:

p-value <0.001 → Chứng tỏ thu nhập có ảnh hưởng đáng kể đến loại sản phẩm mà người tiêu dùng mua. Kết quả thống kê là có ý nghĩa.

Thu nhập ảnh hưởng đến hành vi mua sắm, đặc biệt ở nhóm Snack Foods, Meat và Fruit.

Người có thu nhập cao có xu hướng ăn lành mạnh hơn (ít thịt, nhiều trái cây, snack cao cấp).

Nhóm sản phẩm thiết yếu như rau củ và sữa giữ vai trò ổn định trong tiêu dùng.

Nhóm thu nhập cao thích mua các category “Hàng cao cấp” hơn, nhóm thu nhập thấp ưu tiên category “Cơ bản”.


PHẦN 5. Tổng kết và Thảo luận


5.1. Tóm tắt chính

Univariate: Thực phẩm, Nữ, Độc thân, Chủ nhà chiếm ưu thế.

Prop test: Tất cả tỉ lệ đều khác giả thuyết ban đầu.

Bivariate:

Giới tính ảnh hưởng đến lựa chọn nhóm sản phẩm.

Hôn nhân và thu nhập liên quan mật thiết đến khả năng sở hữu nhà và loại sản phẩm.

Qua phân tích trên, chúng ta rút ra một số kết luận chính: (1) Tần suất và tỷ lệ: Nữ giới chiếm ưu thế nhẹ trong mẫu (khoảng 51%), phần lớn khách hàng độc thân và đa số có nhà riêng. Các mặt hàng phổ biến nhất là rau củ, đồ ăn vặt, sản phẩm từ sữa, trái cây và thịt. (2) Kiểm định tỉ lệ: Các kiểm định prop.test cho thấy sự khác biệt tỷ lệ quan sát là có ý nghĩa thống kê (ví dụ, 51% nữ, 60% có nhà, 72% là nhóm Food) so với giá trị giả định 50%. Điều này khẳng định các chênh lệch giới tính và ưu thế của nhóm thực phẩm đã quan sát ở trên không phải do ngẫu nhiên. (3) Mối liên hệ hai biến: Phân tích chi-square cho thấy có sự phụ thuộc giữa các biến: ví dụ, tỷ lệ sở hữu nhà của nam cao hơn nữ, người đã kết hôn có khả năng sở hữu nhà cao hơn người độc thân. Ngoài ra, nữ mua thực phẩm nhiều hơn (Food), trong khi nam mua nhiều sản phẩm không tiêu thụ được (Non-Consumable) hơn. Những mối quan hệ này giúp doanh nghiệp điều chỉnh chiến lược theo phân khúc khách hàng.

5.2. Hạn chế

Báo cáo này có một số hạn chế. Dữ liệu mẫu chỉ từ một chuỗi siêu thị ở khu vực Tây Bắc Hoa Kỳ và chưa phản ánh đặc thù Việt Nam. Nhóm biến định tính khá phong phú nhưng vẫn thiếu thông tin như độ tuổi, nghề nghiệp hay thời gian mua sắm. Các phân tích trên chưa xét đến mối liên hệ định tính - định lượng (ví dụ kết hợp với doanh thu hay số lượng mua), hay ảnh hưởng của yếu tố thời gian (mùa vụ, lễ Tết).

Và dữ liệu từ Mỹ/Canada/Mexico, chỉ mang tính tham khảo so với Việt Nam.

5.3. Đề xuất

Từ kết quả và hạn chế trên, có thể đề xuất một số chiến lược:

  1. Tập trung phát triển và quảng bá nhóm thực phẩm - nhu yếu phẩm, vì đây là mặt hàng chủ lực, đặc biệt khi đối tượng khách hàng có thu nhập trung bình. Ví dụ: chương trình khuyến mãi rau củ, trái cây theo tuần.
  2. Phân khúc khách hàng theo giới tính và tình trạng hôn nhân: phụ nữ và người độc thân chuộng mua thực phẩm cá nhân, trong khi nam giới và người đã kết hôn có thể quan tâm nhiều đến các mặt hàng gia đình, thiết bị nội thất. Doanh nghiệp có thể thiết kế ưu đãi riêng cho từng nhóm.
  3. Đối với thị trường Việt Nam, cần thu thập thêm dữ liệu đặc thù (tuổi tác, vị trí kinh tế xã hội, văn hóa) để tùy chỉnh chiến lược phù hợp. Ví dụ ở Việt Nam, thu nhập bình quân thấp hơn và thói quen tiêu dùng khác nên có thể tập trung vào các mặt hàng giá mềm phù hợp với nhiều nhóm khách.

5.4. Câu hỏi mở

  1. Ảnh hưởng mùa vụ (Lunar New Year, Black Friday)?

  2. Phân khúc theo tuổi & hành vi online vs offline?

  3. Mô hình dự đoán CLV (Customer Lifetime Value)?

  4. Có mô hình định lượng nào phù hợp để dự đoán doanh thu dựa vào nhân khẩu học?

  5. Các yếu tố văn hóa - xã hội (như xu hướng tiêu dùng ở thành thị vs nông thôn) ảnh hưởng ra sao?

Nghiên cứu thêm các câu hỏi này sẽ giúp doanh nghiệp tối ưu hóa chiến lược dài hạn.


— NHIỆM VỤ TUẦN 1 —


Nhiệm vụ tuần 1:

  1. Tóm tắt cuốn sách: 2019_Generalized Linear Models With Examples in R_9781441901170.pdf (đã gửi trong mục file).
  2. Thực hiện thống kê mô tả cho các biến trong file: Supermarket Transactions.csv ( đã gửi trong mục file)

Tóm tắt “Generalized Linear Models With Examples in R


Cuốn sách Generalized Linear Models With Examples in R của Peter K. Dunn và Gordon K. Smyth (2018) là một tài liệu thống kê đầy đủ, trình bày khung chung của các mô hình tuyến tính tổng quát (GLM) cùng các ví dụ minh họa thực hiện bằng ngôn ngữ R. Ứng dụng của GLM rất rộng, bao gồm hồi quy tuyến tính thông thường, hồi quy logistic, các mô hình đếm (Poisson, âm), dữ liệu liên tục dương (Gamma, Inverse Gaussian), và cả tuyến tính tổng quát Tweedie. Sách trình bày khái niệm cơ bản, phương pháp ước lượng và kiểm định, cùng các vấn đề chẩn đoán, theo đúng trình tự từng chương. Phần mở đầu sau đây và mỗi chương tiếp theo sẽ tóm lược nội dung chính, công thức quan trọng và ví dụ R tương ứng (khi có). Các công thức được trình bày dưới dạng toán học canh giữa và các khối mã R được định dạng rõ ràng để dễ tham khảo.


Chương 0: GIỚI THIỆU CHUNG


Mô hình tuyến tính tổng quát (GLM) là một sự tổng quát hóa của mô hình hồi quy tuyến tính cổ điển, cho phép liên hệ tham số tuyến tính với biến phản hồi thông qua hàm liên kết, đồng thời cho phép phương sai phụ thuộc vào giá trị kỳ vọng.

Cụ thể, trong GLM, ta có ba thành phần chính:

  1. Phân phối ngẫu nhiên của biến đáp ứng thuộc họ mũ cấp một (ví dụ: chuẩn, nhị thức, Poisson, Gamma, …).

  2. Tổ hợp tuyến tính \(\eta = \mathbf{X}\boldsymbol{\beta}\) gồm các biến độc lập và hệ số ẩN.

  3. Hàm liên kết \(g\) liên hệ kỳ vọng \(\mu=E(Y)\) với tổ hợp tuyến tính qua \(g(\mu)=\eta\). GLM do Nelder và Wedderburn đề xuất đã dùng phương pháp tổng bình phương lặp lại có trọng số (IRLS) để ước lượng cực đại xác suất cho tham số.

Trong các chương đầu, sách cũng nhắc lại các khái niệm cơ bản về mô hình thống kê: mô hình bao gồm thành phần hệ thống (phần chi tiết dự đoán thông qua \(\mathbf{X}\boldsymbol{\beta}\)) và thành phần ngẫu nhiên (phần sai số). Ví dụ, hồi quy tuyến tính chuẩn có dạng: \[y_i = \beta_0 + \beta_1 x_{i1} + \dots + \beta_p x_{ip} + \varepsilon_i,\quad \varepsilon_i \sim N(0,\sigma^2)\]

Tác giả nhấn mạnh việc trực quan hóa dữ liệu (vẽ đồ thị phân phối, biểu đồ tần suất, …) để hiểu mẫu trước khi xây mô hình, cũng như mã hóa biến phân loại thành biến giả (dummy variables) để đưa vào mô hình tuyến tính. Mục tiêu của mô hình là đánh giá và dự đoán, được xem xét qua hai tiêu chí chủ yếu: tính chính xác (accuracy) và độ gọn gàng (parsimony) của mô hình. Đồng thời, cần lưu ý giới hạn của mô hình: ví dụ, ta khác biệt giữa dữ liệu quan sát (observational) và dữ liệu thực nghiệm (experimental) khi rút ra kết luận, và cần kiểm tra tính khái quát của mô hình ra ngoài mẫu. Trong giới thiệu này, tác giả cũng cung cấp một số chỉ dẫn sơ bộ về cách sử dụng R để phân tích, chỉ ra nhiều hàm cơ bản như lm() và glm() và cách đọc kết quả, nhằm giúp sinh viên làm quen với công cụ tính toán.


Chương 1: Statistical Models


1.1. Tổng quan

Trong chương này, tác giả giới thiệu khái niệm mô hình thống kê như là một công cụ để mô tả dữ liệu thực nghiệm. Mô hình thống kê có hai thành phần: thành phần ngẫu nhiên (mô tả cách dữ liệu phát sinh thông qua phân phối xác suất) và thành phần hệ thống (mô tả các yếu tố giải thích ảnh hưởng đến biến phụ thuộc). Mỗi quan sát được giả định sinh ra từ một phân phối xác suất xác định, ví dụ một phân phối chuẩn với phương sai không đổi trong mô hình hồi quy tuyến tính cơ bản. Chương này nhấn mạnh rằng “mọi mô hình đều sai, nhưng một số rất hữu ích” (Box & Draper), nghĩa là mô hình chỉ là xấp xỉ thực tế. Các thuật ngữ quan trọng bao gồm biến phụ thuộc (hoặc biến phản hồi), biến giải thích (covariates), và tham số mô hình. Tác giả cũng đề cập đến cách xây dựng mô hình hồi quy tuyến tính cơ bản: ví dụ, phương trình hồi quy đơn giản \[y_i = \beta_0 + \beta_1 x_i + \epsilon_i,\quad \epsilon_i \sim N(0,\sigma^2)\]

1.2. Công thức chính

  • Mô hình hồi quy tuyến tính đơn giản: \(y_i = \beta_0 + \beta_1 x_i + \epsilon_i,\quad \epsilon_i \sim N(0,\sigma^2)\)
  • Trung bình có điều kiện: \(E[y_i|x_i] = \beta_0 + \beta_1 x_i.\)
  • Phương sai của sai số: \(Var(\epsilon_i) = \sigma^2.\)

1.3. Ví dụ R

# Ví dụ mô hình hồi quy tuyến tính trên dữ liệu mtcars
data(mtcars)
fit <- lm(mpg ~ wt + hp, data = mtcars)
summary(fit)
## 
## Call:
## lm(formula = mpg ~ wt + hp, data = mtcars)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -3.941 -1.600 -0.182  1.050  5.854 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 37.22727    1.59879  23.285  < 2e-16 ***
## wt          -3.87783    0.63273  -6.129 1.12e-06 ***
## hp          -0.03177    0.00903  -3.519  0.00145 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.593 on 29 degrees of freedom
## Multiple R-squared:  0.8268, Adjusted R-squared:  0.8148 
## F-statistic: 69.21 on 2 and 29 DF,  p-value: 9.109e-12

Trong ví dụ trên, lm() được dùng để khớp mô hình hồi quy tuyến tính giữa biến tiêu thụ nhiên liệu mpg và các biến giải thích wt (trọng lượng xe) và hp (công suất). Kết quả summary(fit) cho biết hệ số ước lượng, sai số chuẩn và các giá trị p-value.

Ghi chú

  • Mỗi mô hình thống kê cần xác định rõ phân phối giả định của dữ liệu (thành phần ngẫu nhiên) và dạng của thành phần hệ thống (linear predictor).
  • Trong hồi quy tuyến tính, ta thường giả định phân phối chuẩn cho sai số và mô hình tuyến tính cho trung bình.
  • Việc kiểm tra biểu đồ dữ liệu ban đầu (histogram, scatterplot) là quan trọng để chọn mô hình thích hợp.

Chương 2: Linear Regression Models


2.1. Tổng quan

Chương này mở rộng từ hồi quy tuyến tính đơn giản sang hồi quy tuyến tính đa biến. Mục tiêu là tìm các hệ số \(\beta_j\) tối ưu (theo tiêu chí bình phương tối tiểu) thỏa mãn: \[E[y_i|\mathbf{x}i] = \beta_0 + \beta_1 x{i1} + \dots + \beta_p x_{ip}.\]

Quá trình ước lượng thường dựa trên phép bình phương tối tiểu (OLS), cho ta nghiệm dạng đóng \(\hat{\boldsymbol{\beta}} = (X^TX)^{-1}X^T y\). Chương cũng đề cập đến cách ước lượng phương sai \(\sigma^2\) và sai số chuẩn của các hệ số.

2.2. Công thức chính

  • Dự đoán trong hồi quy tuyến tính: \(\hat{y}_i = \hat{\beta}0 + \sum{j=1}^p \hat{\beta}j x{ij}.\)
  • Công thức ước lượng OLS: \(\hat{\boldsymbol{\beta}} = (X^T X)^{-1} X^T \mathbf{y}.\)
  • Ước lượng phương sai: \(\hat{\sigma}^2 = \frac{1}{n-p-1}\sum_{i=1}^n (y_i - \hat{y}_i)^2.\)

2.3. Ví dụ R

# Hồi quy tuyến tính đa biến với tập dữ liệu iris (ví dụ minh họa)
data(iris)
fit2 <- lm(Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width, data = iris)
summary(fit2)
## 
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width, 
##     data = iris)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.82816 -0.21989  0.01875  0.19709  0.84570 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   1.85600    0.25078   7.401 9.85e-12 ***
## Sepal.Width   0.65084    0.06665   9.765  < 2e-16 ***
## Petal.Length  0.70913    0.05672  12.502  < 2e-16 ***
## Petal.Width  -0.55648    0.12755  -4.363 2.41e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3145 on 146 degrees of freedom
## Multiple R-squared:  0.8586, Adjusted R-squared:  0.8557 
## F-statistic: 295.5 on 3 and 146 DF,  p-value: < 2.2e-16

Trong ví dụ trên, chúng ta sử dụng lm() với nhiều biến giải thích để dự đoán độ dài lá. Kết quả cho thấy các hệ số ước lượng, sai số và \(R^2\) tổng thể.

Ghi chú

  • Hệ số xác định \(R^2\) đo lường tỷ lệ biến thiên của dữ liệu được mô hình giải thích.
  • Phép ước lượng OLS bất biến nếu các giả định vi sai (homo-scedasticity) và không sai lệch nếu sai số có kỳ vọng bằng 0.
  • Nếu tồn tại đa cộng tuyến (các biến giải thích tương quan cao), phép \((X^TX)^{-1}\) có thể không ổn định và cần loại bỏ biến hoặc sử dụng kỹ thuật điều chuẩn (regularization).

Chương 3: Linear Regression Models: Diagnostics and Model-Building


3.1. Tổng quan

Chương này tập trung vào chẩn đoán mô hình và chiến lược xây dựng mô hình cho hồi quy tuyến tính. Mục đích là đánh giá chất lượng của mô hình đã khớp, phát hiện các quan sát ngoại lai (outliers) hoặc ảnh hưởng lớn (influential points), và kiểm tra các giả định (tuyến tính, phân phối chuẩn của sai số, phương sai không đổi). Các loại sai số (residual) được sử dụng bao gồm dư sai số (residuals), dư sai số chuẩn hóa và độ đo Cook (Cook’s distance).

3.2. Công thức chính

  • Dư sai số (residual): \(r_i = y_i - \hat{y}_i.\)
  • Dư chuẩn hóa (standardized residual): \(r_i^\ast = \frac{r_i}{\hat{\sigma} \sqrt{1 - h_{ii}}},\) với \(h_{ii}\) là phần tử chính của ma trận mũ (hat matrix).
  • Đại lượng Cook (Cook’s distance) đo mức ảnh hưởng của quan sát thứ \(i\): \(D_i = \frac{r_i^2}{p \hat{\sigma}^2} \frac{h_{ii}}{(1 - h_{ii})^2},\) với \(p\) là số tham số trong mô hình (kể cả hệ số chặn).

3.3. Ví dụ R

# Ví dụ trực quan hóa chẩn đoán hồi quy trên mtcars
par(mfrow = c(2, 2))
plot(fit)

Đoạn mã trên tạo ra 4 đồ thị cơ bản để kiểm tra các giả định mô hình hồi quy: đồ thị dư theo giá trị dự đoán, Q-Q plot để kiểm tra phân phối chuẩn của sai số, đồ thị Scale-Location và đồ thị ảnh hưởng (Cook’s distance).

Ghi chú - Quan sát ngoại lai có thể làm sai lệch kết quả ước lượng; cần kiểm tra residuals và Cook’s distance để phát hiện. - Nếu biểu đồ Q-Q lệch khỏi đường thẳng, phân phối sai số có thể không chuẩn. - Để cải thiện mô hình, có thể thử chuyển đổi biến (ví dụ logarithm) hoặc loại bỏ điểm ngoại lai đáng kể.


Chương 4: Beyond Linear Regression: The Method of Maximum Likelihood


4.1. Tổng quan

Chương này mở rộng khái niệm ước lượng không chỉ dựa trên phân phối chuẩn và bình phương tối tiểu, mà sử dụng phương pháp ước lượng cực đại hợp lý (Maximum Likelihood Estimation) cho các mô hình tổng quát hơn. Phương pháp này tìm tham số \(\boldsymbol{\beta}\) tối ưu bằng cách tối đa hóa hàm hợp lý (likelihood) của dữ liệu:

\[ L(\boldsymbol{\beta}) = \prod_{i=1}^n f(y_i; \boldsymbol{\beta}), \]

Trong đó \(f(y_i; \boldsymbol{\beta})\) là hàm mật độ/xác suất của \(y_i\). Giải thuật phổ biến để tìm ước lượng là phương pháp Newton-Raphson hoặc IRLS (phương pháp lặp có trọng số), sẽ được trình bày chi tiết ở chương sau. Chương này minh họa ý tưởng trên một ví dụ hồi quy logistic (dữ liệu nhị phân).

4.2. Công thức chính

  • Hàm log-hợp lý (log-likelihood): \(\ell(\boldsymbol{\beta}) = \sum_{i=1}^n \log f(y_i; \boldsymbol{\beta}).\)
  • Phương pháp cực đại hợp lý yêu cầu giải hệ: \(\frac{\partial \ell}{\partial \beta_j} = 0\) với mọi \(j\).
  • Ví dụ với mô hình Bernoulli (logistic): xác suất \(p_i = \frac{\exp(\eta_i)}{1+\exp(\eta_i)}, \quad \eta_i = \beta_0 + \beta_1 x_i.\)

4.3. Ví dụ R

# Ví dụ hồi quy logistic với dữ liệu mtcars
logit_model <- glm(vs ~ mpg + wt, data = mtcars, family = binomial)
summary(logit_model)
## 
## Call:
## glm(formula = vs ~ mpg + wt, family = binomial, data = mtcars)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)  
## (Intercept) -12.5412     8.4660  -1.481   0.1385  
## mpg           0.5241     0.2604   2.012   0.0442 *
## wt            0.5829     1.1845   0.492   0.6227  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 43.860  on 31  degrees of freedom
## Residual deviance: 25.298  on 29  degrees of freedom
## AIC: 31.298
## 
## Number of Fisher Scoring iterations: 6

Trong ví dụ này, glm(…, family = binomial) được dùng để khớp mô hình logistic với biến kết quả nhị phân vs (0 hoặc 1). Kết quả cho thấy hệ số log-odds ước lượng và giá trị p-value tương ứng.

Ghi chú

  • Mô hình logistic là một ví dụ điển hình của GLM với phân phối Bernoulli và hàm liên kết logit. Phương pháp cực đại hợp lý có thể áp dụng cho nhiều mô hình với phân phối khác nhau (không chỉ phân phối chuẩn).
  • Cơ sở của GLM là kết hợp phương pháp này với ý tưởng liên kết tuyến tính (linear predictor).

Chương 5: Generalized Linear Models: Structure


5.1. Tổng quan

Chương này định nghĩa khái niệm Mô hình tuyến tính tổng quát (GLM). GLM bao gồm ba thành phần chính:

  • Thành phần ngẫu nhiên (Random component): biến phản hồi \(Y\) tuân theo phân phối thuộc họ phân phối hàm mũ (exponential family), chẳng hạn phân phối chuẩn, Bernoulli, Poisson, Gamma,…
  • Thành phần hệ thống (Systematic component): một tổ hợp tuyến tính của các biến giải thích, \(\eta_i = \beta_0 + \beta_1 x_{i1} + \cdots + \beta_p x_{ip}.\)
  • Hàm liên kết (Link function): một hàm \(g(\cdot)\) liên kết giá trị kỳ vọng \(\mu_i = E[Y_i]\) với predictor: \(g(\mu_i) = \eta_i\).

Tùy thuộc vào phân phối của \(Y\), ta chọn hàm liên kết thích hợp (ví dụ: logit cho Bernoulli, log cho Poisson, identity cho chuẩn,…). GLM tổng quát hóa hồi quy tuyến tính bằng cách thay thế giả định phân phối chuẩn và liên kết tuyến tính qua hàm \(g\).

5.2. Công thức chính

  • Hàm liên kết tổng quát: \[g(E[Y_i]) = \eta_i = \beta_0 + \sum_{j=1}^p \beta_j x_{ij}.\]

Ví dụ các phân phối thông dụng:

  • Chuẩn (Gaussian): \(g(\mu)=\mu\) (identity), phương sai không phụ thuộc (hằng).

  • Bernoulli/Binomial: \(g(\mu)=\mathrm{logit}(\mu)\), \(Var(Y)=\mu(1-\mu)\).

  • Poisson: \(g(\mu)=\log(\mu)\), \(Var(Y)=\mu\).

  • Gamma: \(g(\mu)=\log(\mu)\) hoặc \(g(\mu)=1/\mu\), \(Var(Y)=\phi \mu^2\).

5.3. Ví dụ R

# Ví dụ GLM: so sánh link identity và link log
set.seed(123)
x <- rnorm(100)
y <- exp(1 + 0.3*x + rnorm(100, sd = 0.2))  # y > 0 do exp

glm1 <- glm(y ~ x, family = gaussian(link = "identity"))
glm2 <- glm(y ~ x, family = gaussian(link = "log"))

summary(glm1)
## 
## Call:
## glm(formula = y ~ x, family = gaussian(link = "identity"))
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.80666    0.05816   48.26   <2e-16 ***
## x            0.80555    0.06372   12.64   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.334907)
## 
##     Null deviance: 86.349  on 99  degrees of freedom
## Residual deviance: 32.821  on 98  degrees of freedom
## AIC: 178.38
## 
## Number of Fisher Scoring iterations: 2
summary(glm2)
## 
## Call:
## glm(formula = y ~ x, family = gaussian(link = "log"))
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.00209    0.02251   44.52   <2e-16 ***
## x            0.27423    0.02129   12.88   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.3286445)
## 
##     Null deviance: 86.349  on 99  degrees of freedom
## Residual deviance: 32.207  on 98  degrees of freedom
## AIC: 176.49
## 
## Number of Fisher Scoring iterations: 4

Đoạn mã trên tạo dữ liệu giả định và khớp hai GLM với phân phối chuẩn nhưng dùng hàm liên kết khác nhau (identity và log). Kết quả hiển thị các hệ số ước lượng tương ứng.

Ghi chú

  • GLM mở rộng hồi quy tuyến tính thông qua hàm liên kết: ví dụ logit biến mô hình tuyến tính thành xác suất.
  • Hàm phân tán (variance function) \(V(\mu)\) phụ thuộc vào mỗi phân phối: ví dụ với Poisson, \(V(\mu)=\mu\).
  • Trong R, family định nghĩa cả phân phối của \(Y\) và hàm liên kết (ví dụ family=poisson tương ứng với log link).

Chương 6: Generalized Linear Models:Estimation


6.1. Tổng quan

Chương này trình bày phương pháp tính toán các ước lượng của GLM, thường bằng phương pháp lặp. Do không có nghiệm đóng cho ước lượng cực đại hợp lý (ngoại trừ trường hợp Gaussian), GLM thường được ước lượng bằng phương pháp IRLS (Iteratively Reweighted Least Squares). Ý tưởng cơ bản là lặp lại công thức giống OLS nhưng với trọng số thay đổi tại mỗi bước, cho đến khi hội tụ. Chương cũng đề cập đến ma trận Fisher thông tin và các đặc trưng thống kê khác phục vụ cho ước lượng (ví dụ ma trận hiệp phương sai của ước lượng).

6.2. Công thức chính

  • Phương pháp IRLS cập nhật nghiệm \(\beta\) theo dạng: \(\beta^{(t+1)} = \beta^{(t)} + (X^T W^{(t)} X)^{-1} X^T W^{(t)} (z^{(t)} - X\beta^{(t)}),\) trong đó \(W^{(t)}\) là ma trận trọng số tại lần lặp \(t\), và \(z^{(t)}\) là biến phụ hồi giả định (working response).

  • Ma trận trọng số \(W\) thường liên quan đến hàm phân tán: ví dụ với phân phối Poisson, \(W_{ii} = \hat{\mu}_i\).

  • Ma trận thông tin Fisher \(\mathcal{I}(\beta)\): \(\mathcal{I}(\beta) = X^T W X.\)

6.3. Ví dụ R

# Ví dụ GLM nhị thức trên dữ liệu kiểu thành công/thất bại
glm_model <- glm(cbind(Success, Failure) ~ x, family = binomial,
                 data = data.frame(x = 1:5, Success = c(1,2,3,4,5), Failure = c(9,8,7,6,5)))
summary(glm_model)
## 
## Call:
## glm(formula = cbind(Success, Failure) ~ x, family = binomial, 
##     data = data.frame(x = 1:5, Success = c(1, 2, 3, 4, 5), Failure = c(9, 
##         8, 7, 6, 5)))
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)   
## (Intercept)  -2.4913     0.8910  -2.796  0.00517 **
## x             0.5137     0.2446   2.100  0.03575 * 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 5.036259  on 4  degrees of freedom
## Residual deviance: 0.094649  on 3  degrees of freedom
## AIC: 16.598
## 
## Number of Fisher Scoring iterations: 4

Ở đây, chúng ta dùng glm() để ước lượng với dữ liệu dạng số thành công/thất bại cho mỗi mức \(x\). Hàm glm tự động thực hiện IRLS để tìm hệ số tối ưu.

Ghi chú

  • IRLS là thuật toán lặp đi lặp lại các bước bình phương tối tiểu có trọng số, cho phép áp dụng OLS để tìm ước lượng GLM.
  • Giá trị khởi tạo thường được lấy từ hồi quy tuyến tính hoặc ước lượng thô.
  • Quá trình lặp dừng khi sự thay đổi của ước lượng \(\beta\) nhỏ hơn một ngưỡng (tức hội tụ).

Chương 7: Generalized Linear Models: Inference


7.1. Tổng quan

Chương này thảo luận các phương pháp kiểm định giả thuyết và suy diễn trên các mô hình GLM. Hai phương pháp phổ biến là kiểm định Wald và kiểm định tỷ lệ hợp lý (Likelihood Ratio Test, LRT). Ngoài ra, tác giả đề cập đến khoảng tin cậy (confidence intervals) và kiểm định chi-squared cho deviance. Deviance được định nghĩa là một thước đo khoảng cách giữa mô hình vừa khớp và mô hình bão hòa (mô hình tốt nhất có thể).

7.2. Công thức chính

  • Deviance tổng: \(D = 2(\ell_{\text{sat}} - \ell(\hat{\beta})).\) Một deviance lớn (so với bậc tự do) có thể báo hiệu mô hình chưa phù hợp tốt.
  • Kiểm định Wald: \(Z_j = \frac{\hat{\beta}_j}{\mathrm{SE}(\hat{\beta}_j)},\) so sánh với phân phối chuẩn \(N(0,1)\).
  • Kiểm định Tỷ lệ: \(G^2 = 2(\ell(\hat{\beta}{\text{full}}) - \ell(\hat{\beta}{\text{reduced}})),\) so sánh với \(\chi^2\) với bậc tự do bằng số tham số khác nhau giữa mô hình.
  • Khoảng tin cậy Wald cho tham số: \(\hat{\beta}j \pm z{\alpha/2},\mathrm{SE}(\hat{\beta}_j).\)

7.3. Ví dụ R

# So sánh hai mô hình lồng nhau bằng deviance (ví dụ với warpbreaks)
data(warpbreaks)
full_model <- glm(breaks ~ wool + tension, data = warpbreaks, family = poisson)
reduced_model <- glm(breaks ~ wool, data = warpbreaks, family = poisson)
anova(reduced_model, full_model, test="Chisq")
## Analysis of Deviance Table
## 
## Model 1: breaks ~ wool
## Model 2: breaks ~ wool + tension
##   Resid. Df Resid. Dev Df Deviance  Pr(>Chi)    
## 1        52     281.33                          
## 2        50     210.39  2   70.942 3.938e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Ví dụ trên cho thấy cách dùng hàm anova() để so sánh hai mô hình lồng nhau trong GLM. Giá trị p thu được dựa trên kiểm định \(\chi^2\), dựa trên sự chênh lệch deviance giữa hai mô hình.

Ghi chú

  • Kiểm định Wald dựa trên xấp xỉ chuẩn của ước lượng \(\beta\); trong nhiều trường hợp tốt nhưng có thể kém chính xác với mẫu nhỏ.
  • Kiểm định LRT thường ưu tiên hơn vì tính linh hoạt (so sánh trực tiếp log-hợp lý giữa mô hình đầy đủ và giảm).
  • Trong R, summary() và confint() cung cấp các hệ số ước lượng, sai số chuẩn và khoảng tin cậy tương ứng.

Chương 8: Generalized Linear Models: Diagnostics


8.1. Tổng quan

Chương này trình bày chẩn đoán cho GLM, bao gồm việc kiểm tra độ phù hợp của mô hình qua residuals và các chỉ số ảnh hưởng. Một số loại residual cho GLM: residual Pearson, residual deviance, residual deviance chuẩn hóa. Tác giả cũng thảo luận về leverage và Cook’s distance mở rộng cho GLM. Ngoài ra, có đề cập đến kiểm định độ phù hợp (độ lệch deviance so với phân phối \(\chi^2\)) và những dấu hiệu của overdispersion.

8.2. Công thức chính

  • Residual Pearson: \(r_{P,i} = \frac{y_i - \hat{\mu}_i}{\sqrt{\hat{V}(\hat{\mu}_i)}}.\)
  • Residual Deviance (ví dụ cho Poisson):
  • Leverage trong GLM: phần tử chính \(h_{ii}\) của ma trận \(W^{1/2} X (X^T W X)^{-1} X^T W^{1/2}\), trong đó \(W\) là ma trận trọng số IRLS.
  • Cook’s Distance và các thống số ảnh hưởng khác cũng được tính tương tự như hồi quy tuyến tính.

8.3. Ví dụ R

# Minh họa residuals trong GLM (với warpbreaks)
mod <- glm(breaks ~ wool + tension, data = warpbreaks, family = poisson)
par(mfrow = c(2, 2))
plot(mod)

Đoạn mã hiển thị các đồ thị chẩn đoán tương tự hồi quy tuyến tính (dư sai, dư Pearson, Q-Q plot, Cook’s distance). Từ đó có thể phát hiện quan sát có ảnh hưởng hoặc mô hình chưa phù hợp.

Ghi chú

  • Nếu residual deviance lớn hơn nhiều so với \(df_{\text{residual}}\), mô hình có thể bị overdispersion.
  • Khi overdispersion, có thể sử dụng mô hình Negative Binomial để điều chỉnh.
  • Luôn kiểm tra chất lượng khớp với diagnostic plots giống như hồi quy tuyến tính.

Chương 9: Models for Proportions: Binomial GLMs


9.1. Tổng quan

Chương này nghiên cứu các trường hợp biến phụ thuộc là tỉ lệ hoặc số thành công/thất bại theo phân phối binomial. Ví dụ điển hình là hồi quy logistic (phân phối Bernoulli với hàm liên kết logit) hoặc GLM nhị thức chung (khi mỗi quan sát có số thử nghiệm \(n_i\)). Mô hình tổng quát: \[ Y_i \sim \text{Binomial}(n_i, \pi_i), \quad g(\pi_i) = \beta_0 + \beta_1 x_i. \]

Với hàm liên kết logit: \[\mathrm{logit}(\pi_i) = \log\frac{\pi_i}{1-\pi_i}.\]

9.2. Công thức chính

  • Hàm logit: \(\mathrm{logit}(\pi) = \log\frac{\pi}{1-\pi}.\)
  • Xác suất của Bernoulli (logistic): \(\pi_i = \frac{e^{\beta_0 + \beta_1 x_i}}{1 + e^{\beta_0 + \beta_1 x_i}}.\)
  • Nếu có \(n_i\) thử nghiệm (GLM nhị thức): \(Y_i \sim \text{Binomial}(n_i, \pi_i).\)

9.3. Ví dụ R

# Hồi quy logistic (nhị thức) với dữ liệu giả định
set.seed(42)
x <- runif(100)
p <- 1 / (1 + exp(-(-1 + 2*x)))
y <- rbinom(100, size=1, prob=p)
df_bin <- data.frame(x, y)
logit_mod <- glm(y ~ x, data = df_bin, family = binomial)
summary(logit_mod)
## 
## Call:
## glm(formula = y ~ x, family = binomial, data = df_bin)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)
## (Intercept)  -0.5373     0.4107  -1.308    0.191
## x             1.1020     0.6820   1.616    0.106
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 138.59  on 99  degrees of freedom
## Residual deviance: 135.91  on 98  degrees of freedom
## AIC: 139.91
## 
## Number of Fisher Scoring iterations: 4

Trong ví dụ trên, biến kết quả y là 0/1. Mô hình glm(…, family = binomial) ước lượng hệ số của hàm logit.

Ghi chú

  • Hệ số \(\beta_j\) trong logistic tương ứng với log-odds; có thể chuyển đổi thành odds ratio để giải thích.
  • Đối với dữ liệu tỷ lệ (tập hợp số thành công/thất bại), ta dùng cú pháp cbind(success, failure) trong glm.
  • Kiểm tra xác suất dự báo, ma trận nhầm lẫn hoặc ROC curve để đánh giá chất lượng phân loại.

Chương 10: Models for Counts: Poisson and Negative Binomial GLMs


10.1. Tổng quan

Chương 10 tập trung vào các dữ liệu đếm: GLM Poisson và Negative Binomial. Mô hình Poisson thường dùng khi biến phụ thuộc là số đếm với giả định biến thiên bằng trung bình (\(Var(Y)=E(Y)\)) và dùng hàm liên kết log: \(g(\mu) = \log(\mu)\). Nếu dữ liệu có tính overdispersion (phương sai lớn hơn), GLM Poisson có thể không phù hợp; ta có thể sử dụng mô hình Negative Binomial để bao gồm thêm biến thiên.

10.2. Công thức chính

  • Phân phối Poisson: \(P(Y=y) = \frac{e^{-\lambda}\lambda^y}{y!}, \quad E(Y)=\lambda,\ Var(Y)=\lambda.\)
  • Trong GLM Poisson: \(g(\mu_i) = \log(\mu_i) = \beta_0 + \beta_1 x_i.\)
  • Phân phối Negative Binomial (trong tham số hóa \(\mu, k\)): \(Var(Y) = \mu + \frac{\mu^2}{k},\) với \(k\) là hệ số phân tán (điều chỉnh).

10.3. Ví dụ R

library(MASS)
## 
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select
# Ví dụ GLM Poisson và Negative Binomial
set.seed(123)
x_nb <- runif(100, 0, 5)
mu <- exp(1 + 0.5*x_nb)
y_pois <- rpois(100, lambda = mu)
y_nb <- rnbinom(100, size = 2, mu = mu)  # over-dispersed
data_pois <- data.frame(x=x_nb, y=y_pois)
data_nb <- data.frame(x=x_nb, y=y_nb)

pois_mod <- glm(y ~ x, family = poisson, data = data_pois)
summary(pois_mod)
## 
## Call:
## glm(formula = y ~ x, family = poisson, data = data_pois)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  1.08957    0.08247   13.21   <2e-16 ***
## x            0.47329    0.02289   20.68   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for poisson family taken to be 1)
## 
##     Null deviance: 547.60  on 99  degrees of freedom
## Residual deviance:  64.83  on 98  degrees of freedom
## AIC: 477.73
## 
## Number of Fisher Scoring iterations: 4
nb_mod <- glm.nb(y ~ x, data = data_nb)
summary(nb_mod)
## 
## Call:
## glm.nb(formula = y ~ x, data = data_nb, init.theta = 1.615587182, 
##     link = log)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  0.83576    0.18804   4.445 8.81e-06 ***
## x            0.52375    0.06246   8.385  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for Negative Binomial(1.6156) family taken to be 1)
## 
##     Null deviance: 183.91  on 99  degrees of freedom
## Residual deviance: 111.72  on 98  degrees of freedom
## AIC: 640.88
## 
## Number of Fisher Scoring iterations: 1
## 
## 
##               Theta:  1.616 
##           Std. Err.:  0.283 
## 
##  2 x log-likelihood:  -634.885

Ở trên, glm(…, family = poisson) khớp mô hình Poisson. Để dùng Negative Binomial, ta cần gói MASS và dùng glm.nb(). Kết quả summary(nb_mod) sẽ hiển thị hệ số ước lượng của mô hình Negative Binomial.

Ghi chú

  • Mô hình Poisson với hàm log link có nghĩa rằng tăng một đơn vị biến giải thích sẽ nhân tỷ lệ xảy ra sự kiện theo hệ số.
  • Negative Binomial giúp xử lý overdispersion nhờ một tham số bổ sung cho phương sai.
  • Ngoài ra, có thể kiểm định overdispersion bằng cách so sánh deviance với số bậc tự do (residual df): nếu deviance >> df, nên xem xét Negative Binomial.

Chương 11: Positive Continuous Data: Gamma and Inverse Gaussian GLMs


11.1. Tổng quan

Chương 11 xem xét các biến phụ thuộc liên tục dương, ví dụ thời gian hoặc khối lượng, bằng mô hình GLM phân phối Gamma hoặc Inverse Gaussian. Những phân phối này thích hợp khi dữ liệu luôn dương và có phương sai phụ thuộc vào bình phương trung bình (\(Var(Y)=\phi\mu^2\) cho Gamma). Thường dùng hàm liên kết log hoặc nghịch đảo (inverse) cho Gamma, và liên kết log cho Inverse Gaussian.

11.2. Công thức chính

  • Phân phối Gamma (tham số hóa theo \(\mu\)\(\phi\)): \(f(y) = \frac{1}{\Gamma(\alpha)} \left(\frac{\alpha}{\mu}\right)^\alpha y^{\alpha-1} e^{-\alpha y/\mu},\) với \(\alpha = 1/\phi\); \(E(Y)=\mu\), \(Var(Y)=\phi \mu^2\).
  • Phân phối Inverse Gaussian: \(f(y) = \frac{\lambda^{1/2}}{(2\pi y^3)^{1/2}} \exp\left(-\frac{\lambda (y-\mu)^2}{2\mu^2 y}\right),\)\(E(Y)=\mu\), \(Var(Y)=\mu^3/\lambda\).
  • Ví dụ hàm liên kết Gamma: \(g(\mu) = \log(\mu)\) hoặc \(g(\mu) = 1/\mu\).

11.3. Ví dụ R

# Ví dụ GLM Gamma
set.seed(101)
x_gamma <- runif(100, 0, 5)
mu_g <- exp(2 + 0.3*x_gamma)
y_gamma <- rgamma(100, shape = 2, scale = mu_g/2)  # E(Y)=mu_g, Var=k*mu^2
data_gamma <- data.frame(x=x_gamma, y=y_gamma)
gamma_mod <- glm(y ~ x, family = Gamma(link = "log"), data = data_gamma)
summary(gamma_mod)
## 
## Call:
## glm(formula = y ~ x, family = Gamma(link = "log"), data = data_gamma)
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   2.4166     0.1502  16.090  < 2e-16 ***
## x             0.1392     0.0498   2.795  0.00625 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for Gamma family taken to be 0.5466223)
## 
##     Null deviance: 55.288  on 99  degrees of freedom
## Residual deviance: 51.331  on 98  degrees of freedom
## AIC: 736.64
## 
## Number of Fisher Scoring iterations: 5

Trong ví dụ, glm(…, family = Gamma(link=“log”)) khớp mô hình Gamma với liên kết log. Kết quả cho hệ số ước lượng và ước lượng \(\phi\) (dispersion).

Ghi chú

  • Các dữ liệu như thời gian xử lý tác vụ hoặc nồng độ liên tục thường dùng GLM Gamma.
  • Nếu dữ liệu dương nhưng phân phối hẹp hơn, Inverse Gaussian có thể phù hợp hơn (family = inverse.gaussian trong R).
  • Tham số \(\phi\) trong Gamma GLM thường được ước lượng và là nghịch đảo của tham số shape (\(\alpha\)).

Chương 12: Tweedie GLMs


12.1. Tổng quan

Chương 12 giới thiệu mô hình Tweedie GLM, dùng khi dữ liệu có đặc trưng “giá trị 0 với xác suất dương và phân phối liên tục dương khi dương”. Tweedie là một họ phân phối con của phân phối hàm mũ, với tham số biến thiên \(p\). Ví dụ, \(p=1\) cho Poisson, \(p=2\) cho Gamma, và với \(1<p<2\) thì phân phối Tweedie có kết hợp tính chất rời rạc (giá trị 0) và liên tục. Tweedie thường dùng trong phân tích bảo hiểm (các tổn thất bảo hiểm) hoặc dữ liệu lượng có pha trộn rời rạc – liên tục.

12.2. Công thức chính

  • Phân phối Tweedie (tham số \(\mu, p\)) có phương sai: \(Var(Y) = \phi \mu^p.\)
  • Chọn \(p\) trong khoảng \(1 < p < 2\) tạo ra phân phối có xác suất khối lượng tại 0 và liên tục dương cho phần còn lại.
  • Hàm liên kết thông dụng là log (tức \(g(\mu)=\log(\mu)\)).

12.3. Ví dụ R

# Tạo dữ liệu
set.seed(202)
x_tw <- runif(100, 0, 5)
mu_tw <- exp(1 + 0.4 * x_tw)
y_tw <- rtweedie(100, mu = mu_tw, phi = 2, power = 1.5)  # power = p

# Fit mô hình GLM với phân phối Tweedie
tweedie_mod <- glm(y_tw ~ x_tw, family = tweedie(var.power = 1.5, link.power = 0))
summary(tweedie_mod)
## 
## Call:
## glm(formula = y_tw ~ x_tw, family = tweedie(var.power = 1.5, 
##     link.power = 0))
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.33030    0.18522   7.182 1.35e-10 ***
## x_tw         0.31903    0.05917   5.392 4.83e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for Tweedie family taken to be 2.021416)
## 
##     Null deviance: 317.77  on 99  degrees of freedom
## Residual deviance: 259.53  on 98  degrees of freedom
## AIC: NA
## 
## Number of Fisher Scoring iterations: 4

Trong đoạn mã, rtweedie được dùng để sinh dữ liệu Tweedie (ở đây \(p=1.5\)). Khi khớp mô hình, tweedie(var.power=1.5, link.power=0) sử dụng liên kết log.

Ghi chú

  • Để dùng Tweedie GLM trong R, cần gói statmod (hàm tweedie()).
  • Tham số power \(p\) xác định hình dạng phân phối; ví dụ \(p=1\) cho Poisson, \(p=2\) cho Gamma.
  • Tweedie phù hợp cho dữ liệu không âm pha trộn các giá trị điểm và liên tục.

Chương 13: Extra Problems


13.1. Tổng quan

Chương cuối này chỉ gồm bài tập thực hành liên quan đến các nội dung đã học. Các bài tập yêu cầu người đọc áp dụng GLM để phân tích bộ dữ liệu mẫu, khớp mô hình phù hợp, thực hiện chẩn đoán, và so sánh các giả thuyết (ví dụ, sử dụng anova để so sánh các GLM lồng nhau). Đây là phần thực hành, nhằm củng cố kiến thức lý thuyết thông qua các bài tập cụ thể.

Ví dụ:

  • Cho dữ liệu đếm crab (về số hoa văn trên mai cua), khớp GLM Poisson/Negative Binomial và kiểm tra độ phù hợp.

  • Cho dữ liệu mtcars, khớp mô hình logistic phân loại xe theo biến vs, sau đó thực hiện kiểm định Likelihood Ratio so sánh với mô hình không chứa biến phụ.

  • Cho dữ liệu kết quả điều trị (số thành công/thất bại) và một biến giải thích \(x\), ước lượng mô hình glm(cbind(success, failure) ~ x, family=binomial) và suy diễn hệ số.

Các bài tập này giúp người học thực hành các công cụ R (glm, anova, summary, plot, …) đồng thời hiểu sâu hơn về mô hình GLM.

LS0tDQp0aXRsZTogIioqQsOASSBU4bqsUCBDw4FDIFRV4bqmTioqIiANCmF1dGhvcjogIkhvw6BuZyBU4bqlbiBQaMOhdCwgMjIyMTAwMDMxNyAtIEdWIEjGsOG7m25nIGThuqtuOiBUaOG6p3kgVHLhuqduIE3huqFuaCBUxrDhu51uZyINCmRhdGU6ICJUcsaw4budbmcgxJDhuqFpIGjhu41jIFTDoGkgY2jDrW5oIC0gTWFya2V0aW5nLCB0aMOhbmcgMDUgbsSDbSAyMDI1Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNzczogInN0eWxlcy5jc3MiDQogICAgaGlnaHRsaWdodDoga2F0ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCiMgTuG6oXAgdGjGsCB2aeG7h24NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShlcGl0b29scykNCmxpYnJhcnkoc2NhbGVzKQ0KbGlicmFyeSh0d2VlZGllKQ0KbGlicmFyeShzdGF0bW9kKQ0KbGlicmFyeShnZ3B1YnIpDQpgYGANCg0KKioqIA0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+DQoNCiMgKiotLS0gTkhJ4buGTSBW4bukIFRV4bqmTiA0LTUgLS0tKioNCg0KPC9kaXY+DQoNCioqKg0KDQoqKk5oaeG7h20gduG7pSB0deG6p24gNDoqKg0KDQoxLiBUw6xtIG3hu5l0IGLhu5kgZOG7ryBsaeG7h3UgKGPDsyDDrXQgbmjhuqV0IDQgYmnhur9uIMSR4buLbmggdMOtbmgpIHbDoCB0aOG7sWMgaGnhu4duIHBow6JuIHTDrWNoIGLhu5kgZOG7ryBsaeG7h3UgbsOgeSB0aGVvIG5o4buvbmcgcGjGsMahbmcgcGjDoXAgxJHDoyB0cmFvIMSR4buVaS4NCjIuIE5nb8OgaSByYSBsw6BtIHRow6ptIGLDoGkgdG/DoW4gxrDhu5tjIGzGsOG7o25nIGtob+G6o25nLCBraeG7g20gxJHhu4tuaCBnaeG6oyB0aHV54bq/dCB0aOG7kW5nIGvDqiBjaG8gY8OhYyBiaeG6v24gdHJvbmcgYuG7mSBk4buvIGxp4buHdS4NCg0KKipOaGnhu4dtIHbhu6UgdHXhuqduIDU6KioNCg0KMS4gQ2jhu41uIDIgYmnhur9uIHRo4bqtdCBz4buxIGzDoCBiaeG6v24gxJHhu4tuaCB0w61uaCDEkeG7gyBsw6BtIGJp4bq/biBwaOG7pSB0aHXhu5ljIMSR4buDIHBow6JuIHTDrWNoIHPhu7EgdMOhYyDEkeG7mW5nIGPhu6dhIGPDoWMgYmnhur9uIGPDsm4gbOG6oWkgbMOqbiAyIGJp4bq/biBuw6B5LiBO4bq/dSB0cm9uZyBi4buZIGThu68gbGnhu4d1IGPhu6dhIHR14bqnbiA0IGtow7RuZyBjw7MgMiBiaeG6v24gxJHhu4tuaCB0w61uaCB0aMOsIHBo4bqjaSBjaOG7jW4gYuG7mSBk4buvIGxp4buHdSBraMOhYy4NCjIuIFhlbSB0csaw4bubYyBwaMawxqFuZyBwaMOhcCDGsOG7m2MgbMaw4bujbmcgTWF4aW11bSBsaWtlaG9vZA0KDQoqKioNCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXIiPg0KDQojICoqQuG7mSBk4buvIGxp4buHdSAiQWR1bHQiKiogICAgDQoNCjwvZGl2Pg0KDQoqKioNCg0KIyAqKlBI4bqmTiAxLiBU4buVbmcgcXVhbiB24buBIGLhu5kgZOG7ryBsaeG7h3UqKg0KDQoqKioNCg0KQuG7mSBk4buvIGxp4buHdSBBZHVsdCAoaGF5IENlbnN1cyBJbmNvbWUgMTk5NCkgZ2hpIGzhuqFpIHRow7RuZyB0aW4gbmjDom4ga2jhuql1IGjhu41jIHbDoCB2aeG7h2MgbMOgbSBj4bunYSA0ODg0MiBjw6EgbmjDom4g4bufIE3hu7ksIHbhu5tpIDE0IMSR4bq3YyB0csawbmcgYmFvIGfhu5NtIGPDoWMgYmnhur9uIHBow6JuIGxv4bqhaSAobmjGsCB3b3JrY2xhc3MsIGVkdWNhdGlvbiwgbWFyaXRhbC1zdGF0dXMsIG9jY3VwYXRpb27igKYpIHbDoCBjw6FjIGJp4bq/biBz4buRIChuaMawIGFnZSwgZWR1Y2F0aW9uLW51bSwgaG91cnMtcGVyLXdlZWvigKYpDQoNCk5oaeG7h20gduG7pSBwaMOibiBsb+G6oWkgY2jDrW5oIGzDoCBk4buxIMSRb8OhbiB4ZW0gdGh1IG5o4bqtcCBow6BuZyBuxINtIGPhu6dhIG3hu5l0IG5nxrDhu51pIGPDsyB2xrDhu6N0IHRyw6puICQ1MC4wMDAgaGF5IGtow7RuZw0Ka2jDtG5nIGThu7FhIHRyw6puIGThu68gbGnhu4d1IMSRaeG7gXUgdHJhIGTDom4gc+G7kS4gxJDDonkgY8OybiDEkcaw4bujYyBn4buNaSBsw6AgdOG6rXAgZOG7ryBsaeG7h3UgIlRodSBuaOG6rXAgxJFp4buBdSB0cmEgZMOibiBz4buRIi4NCg0KVGhlbyB0aMO0bmcgdGluIHThu6sgVUNJIE1hY2hpbmUgTGVhcm5pbmcgUmVwb3NpdG9yeSwgY8OhYyBi4bqjbiBnaGkgxJHGsOG7o2MgdHLDrWNoIHh14bqldCB04burIGThu68gbGnhu4d1IMSRaeG7gXUgdHJhIGTDom4gc+G7kSBuxINtIDE5OTQgYuG7n2kgQmFycnkgQmVja2VyICh24bubaSDEkWnhu4F1IGtp4buHbiBs4buNYzogdHXhu5VpID4xNiwgdGh1IG5o4bqtcCBjw6EgbmjDom4gPjEwMCwgdHLhu41uZyBz4buRIGTDom4gc+G7kSA+MSwgZ2nhu50gbMOgbSA+MCkuDQoNCi0gKirEkOG6t2MgxJFp4buDbSBj4bunYSB04bqtcCBk4buvIGxp4buHdToqKiDEkGEgYmnhur9uDQoNCg0KLSAqKkzEqW5oIHbhu7FjIGNo4bunIMSR4buBOioqIEtob2EgaOG7jWMgeMOjIGjhu5lpDQoNCg0KLSAqKkxv4bqhaSB0w61uaCBuxINuZzoqKiBQaMOibiBsb+G6oWksIFPhu5Egbmd1ecOqbg0KDQoNCi0gKipDw6FjIHRyxrDhu51uZyBo4bujcDoqKiA0ODg0Mg0KDQotICoqQ8OhYyBiaeG6v246KiogR+G7k20gMTQgYmnhur9uOiANCg0KxJDhu41jIGZpbGU6IMSQ4bqndSB0acOqbiB0YSDEkeG7jWMgZOG7ryBsaeG7h3UgYWR1bHQuY3N2IHbDoG8gUiwgeMOhYyDEkeG7i25oIGPhu5l0IHbDoCBsb+G6oWkgYuG7jyBjw6FjIGdpw6EgdHLhu4sgdGhp4bq/dSDEkcaw4bujYyBtw6MgaG/DoSBi4bqxbmcga8O9IHThu7EgIj8iLg0KDQpgYGB7cn0NCmFkdWx0IDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9IUC9Eb3dubG9hZHMvYWR1bHQuY3N2IiwgaGVhZGVyID0gVFJVRSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KY29sbmFtZXMoYWR1bHQpIDwtIGMoImFnZSIsIndvcmtjbGFzcyIsImZubHdndCIsImVkdWNhdGlvbiIsImVkdWNhdGlvbl9udW0iLA0KICAgICAgICAgICAgICAgICAgICAgIm1hcml0YWxfc3RhdHVzIiwib2NjdXBhdGlvbiIsInJlbGF0aW9uc2hpcCIsInJhY2UiLCJzZXgiLA0KICAgICAgICAgICAgICAgICAgICAgImNhcGl0YWxfZ2FpbiIsImNhcGl0YWxfbG9zcyIsImhvdXJzX3Blcl93ZWVrIiwNCiAgICAgICAgICAgICAgICAgICAgICJuYXRpdmVfY291bnRyeSIsImluY29tZSIpDQpgYGANCg0KQ+G6pXUgdHLDumMgZOG7ryBsaeG7h3U6IFPhu60gZOG7pW5nIHN0cigpIMSR4buDIHhlbSB0aMO0bmcgdGluIGPhuqV1IHRyw7pjLiBUYSB0aOG6pXkgdOG7lW5nIHPhu5EgaMOgbmcgdsOgIGtp4buDdSBk4buvIGxp4buHdSBj4bunYSBt4buXaSBj4buZdC4NCg0KYGBge3J9DQpzdHIoYWR1bHQpDQoNCmBgYA0KDQpUaMSDbSBkw7Igbmhhbmg6IEhp4buDbiB0aOG7iyBt4buZdCB2w6BpIGTDsm5nIMSR4bqndS9jdeG7kWkgxJHhu4MgaGnhu4N1IHPGoSBi4buZIGThu68gbGnhu4d1Lg0KDQpgYGB7cn0NCmhlYWQoYWR1bHQpDQp0YWlsKGFkdWx0KQ0KDQpgYGANCg0KR2nDoSB0cuG7iyB0aGnhur91OiBLaeG7g20gdHJhIGPDoWMgYmnhur9uIMSR4buLbmggdMOtbmggKGNhdGVnb3JpY2FsKSB4ZW0gY8OzIE5BIGtow7RuZy4gVGEgcGjDoXQgaGnhu4duIGPDsyBOQSDhu58gY8OhYyBj4buZdCB3b3JrY2xhc3MsIG9jY3VwYXRpb24sIG5hdGl2ZV9jb3VudHJ5IChnacOhIHRy4buLICI/IikuIFbDrSBk4bulOg0KDQpgYGB7cn0NCnNhcHBseShhZHVsdCAlPiUgc2VsZWN0KHdvcmtjbGFzcywgb2NjdXBhdGlvbiwgbmF0aXZlX2NvdW50cnkpLCANCiAgICAgICBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQ0KYGBgDQoNClbDrCB04bu3IGzhu4cgZ2nDoSB0cuG7iyB0aGnhur91IHLhuqV0IG5o4buPIHNvIHbhu5tpIGvDrWNoIHRoxrDhu5tjIG3huqt1ICh2w60gZOG7pSBjaOG7iSBraG/huqNuZyA2JSBjaG8gd29ya2NsYXNzKSwgdGEgbOG7sWEgY2jhu41uIGxv4bqhaSBi4buPIG5o4buvbmcgZMOybmcgY8OzIE5BIMSR4buDIMSR4bqjbSBi4bqjbyB0w61uaCBjaMOtbmggeMOhYyBj4bunYSBwaMOibiB0w61jaCB2w6AgdHLDoW5oIOG6o25oIGjGsOG7n25nIGtow7RuZyBtb25nIG114buRbi4gU2F1IMSRw7MsIHRhIGNodXnhu4NuIGPDoWMgYmnhur9uIMSR4buLbmggdMOtbmggc2FuZyBmYWN0b3IgxJHhu4MgdGnhu4duIHjhu60gbMO9Lg0KDQpgYGB7cn0NCiMgTG/huqFpIGLhu48ga2hv4bqjbmcgdHLhuq9uZyDhu58gxJHhuqd1L2N14buRaSBjw6FjIGJp4bq/biBk4bqhbmcgY2h14buXaQ0KYWR1bHQgPC0gYWR1bHQgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuY2hhcmFjdGVyKSwgdHJpbXdzKSkNCg0KIyBUaGF5IHRo4bq/ICI/IiBi4bqxbmcgTkENCmFkdWx0W2FkdWx0ID09ICI/Il0gPC0gTkENCg0KIyBMb+G6oWkgYuG7jyBjw6FjIGTDsm5nIGPDsyBOQQ0KYWR1bHQgPC0gbmEub21pdChhZHVsdCkNCmFkdWx0IDwtIG5hLm9taXQoYWR1bHQpDQphZHVsdCA8LSBhZHVsdCAlPiUNCiAgbXV0YXRlX2F0KHZhcnMod29ya2NsYXNzLCBlZHVjYXRpb24sIG1hcml0YWxfc3RhdHVzLCBvY2N1cGF0aW9uLCANCiAgICAgICAgICAgICAgICAgcmVsYXRpb25zaGlwLCByYWNlLCBzZXgsIG5hdGl2ZV9jb3VudHJ5LCBpbmNvbWUpLA0KICAgICAgICAgICAgZmFjdG9yKQ0KDQpgYGANCg0KQWR1bHQuY3N2IGzDoCBt4buZdCBi4buZIGThu68gbGnhu4d1IGJhbyBn4buTbSAzMjU2MSBxdWFuIHPDoXQgdsOgIDE0IGJp4bq/biwgY+G7pSB0aOG7gyBsw6AgY8OhYyBiaeG6v246DQoNCg0KfCBOaMOzbSBiaeG6v24gICAgICAgICAgICAgIHwgQmnhur9uIGPhu6UgdGjhu4MgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgTeG7pWMgdGnDqnUgcGjDom4gdMOtY2ggY2jDrW5oICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwNCnwgQmnhur9uIMSR4buLbmggdMOtbmggICAgICAgICB8IGB3b3JrY2xhc3NgLCBgZWR1Y2F0aW9uYCwgYG1hcml0YWwtc3RhdHVzYCwgYG9jY3VwYXRpb25gLCBgcmVsYXRpb25zaGlwYCwgYHJhY2VgLCBgc2V4YCwgYG5hdGl2ZS1jb3VudHJ5YCB8IFRo4buRbmcga8OqIHThuqduIHPhu5EsIGJp4buDdSDEkeG7kyBj4buZdCwgcGjDom4gcGjhu5FpIHRoZW8gbmjDs20gICAgfA0KfCBCaeG6v24gxJHhu4tuaCBsxrDhu6NuZyAgICAgICAgfCBgYWdlYCwgYGZubHdndGAsIGBlZHVjYXRpb24tbnVtYCwgYGNhcGl0YWwtZ2FpbmAsIGBjYXBpdGFsLWxvc3NgLCBgaG91cnMtcGVyLXdlZWtgICAgICAgICAgICAgICAgICAgICAgICAgfCBNw7QgdOG6oyB0aOG7kW5nIGvDqiwgcGjDom4gcGjhu5FpLCBraeG7g20gxJHhu4tuaCwga2hv4bqjbmcgdGluIGPhuq15IHwNCnwgQmnhur9uIG3hu6VjIHRpw6p1ICh0YXJnZXQpIHwgYGluY29tZWAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgROG7sSDEkW/DoW4gcGjDom4gbG/huqFpOiA8PTUwSyBob+G6t2MgPjUwSyAgICAgICAgICAgICAgICAgICB8DQoNCg0KDQoNCioqQ8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaDoqKg0KDQooMSkgd29ya2NsYXNzIChUaMOgbmggcGjhuqduIHZp4buHYyBsw6BtKQ0KDQrihpIgUGjDom4gbG/huqFpIHRoZW8ga2h1IHbhu7FjIGzDoG0gdmnhu4djIGPhu6dhIGPDoSBuaMOibiwgcGjhuqNuIMOhbmggbsahaSBo4buNIMSRYW5nIGPDtG5nIHTDoWMuDQoNCg0KQ8OhYyBnacOhIHRy4buLIHBo4buVIGJp4bq/bjoNCg0KLSBQcml2YXRlOiBraHUgduG7sWMgdMawIG5ow6JuDQoNCi0gU2VsZi1lbXAtbm90LWluYzogdOG7sSBsw6BtIGtow7RuZyB0aMOgbmggbOG6rXAgY8O0bmcgdHkNCg0KLSBTZWxmLWVtcC1pbmM6IHThu7EgbMOgbSBjw7MgY8O0bmcgdHkNCg0KLSBGZWRlcmFsLWdvdiwgTG9jYWwtZ292LCBTdGF0ZS1nb3Y6IGzDoG0gdmnhu4djIGNobyBjaMOtbmggcGjhu6cNCg0KLSBXaXRob3V0LXBheTogbMOgbSBraMO0bmcgbMawxqFuZw0KDQotIE5ldmVyLXdvcmtlZDogY2jGsGEgdOG7q25nIGzDoG0gdmnhu4djDQoNCg0KKDIpIGVkdWNhdGlvbiAoVHLDrG5oIMSR4buZIGjhu41jIHbhuqVuKQ0KDQrihpIgVHLDrG5oIMSR4buZIGjhu41jIHbhuqVuIGN14buRaSBjw7luZyBtw6AgY8OhIG5ow6JuIMSR4bqhdCDEkcaw4bujYyAoZOG6oW5nIHbEg24gYuG6sW5nKS4NCg0KDQpWw60gZOG7pToNCg0KDQpCYWNoZWxvcnMsIEhTLWdyYWQgKHThu5F0IG5naGnhu4dwIFRIUFQpLCBTb21lLWNvbGxlZ2UsIE1hc3RlcnMsIERvY3RvcmF0ZSwgMTF0aCwgQXNzb2MtYWNkbSwuLi4NCg0KKDMpIG1hcml0YWwtc3RhdHVzIChUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4pDQoNCuKGkiBQaOG6o24gw6FuaCB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gaGnhu4duIHThuqFpIGPhu6dhIG5nxrDhu51pIMSRw7MuDQoNCg0KR2nDoSB0cuG7iyBn4buTbToNCg0KLSBNYXJyaWVkLWNpdi1zcG91c2U6IMSRw6Mga+G6v3QgaMO0biAoaMO0biBuaMOibiBkw6JuIHPhu7EpDQoNCi0gRGl2b3JjZWQ6IMSRw6MgbHkgaMO0bg0KDQotIE5ldmVyLW1hcnJpZWQ6IGNoxrBhIHThu6tuZyBr4bq/dCBow7RuDQoNCi0gU2VwYXJhdGVkOiBseSB0aMOibg0KDQotIFdpZG93ZWQ6IGfDs2EgduG7oy9jaOG7k25nDQoNCig0KSBvY2N1cGF0aW9uIChOZ2jhu4EgbmdoaeG7h3ApDQoNCuKGkiBOZ8Ogbmggbmdo4buBIGPhu6UgdGjhu4MgxJFhbmcgbMOgbSB2aeG7h2MuDQoNCg0KVsOtIGThu6U6DQoNCg0KVGVjaC1zdXBwb3J0LCBDcmFmdC1yZXBhaXIsIFNhbGVzLCBFeGVjLW1hbmFnZXJpYWwsIFByb2Ytc3BlY2lhbHR5LCBIYW5kbGVycy1jbGVhbmVycywuLi4NCg0KDQooNSkgcmVsYXRpb25zaGlwIChRdWFuIGjhu4cgZ2lhIMSRw6xuaCkNCg0K4oaSIFbhu4sgdHLDrSBj4bunYSBjw6EgbmjDom4gdHJvbmcgZ2lhIMSRw6xuaC4NCg0KDQpHacOhIHRy4buLIGPDsyB0aOG7gyBsw6A6DQoNCg0KSHVzYmFuZCwgV2lmZSwgT3duLWNoaWxkLCBOb3QtaW4tZmFtaWx5LCBVbm1hcnJpZWQsIE90aGVyLXJlbGF0aXZlDQoNCg0KKDYpIHJhY2UgKENo4bunbmcgdOG7mWMpDQoNCuKGkiBDaOG7p25nIHThu5ljIMSRxrDhu6NjIGtoYWkgYsOhbyBj4bunYSBjw6EgbmjDom4uDQoNCg0KR+G7k20gY8OhYyBuaMOzbSBjaMOtbmg6DQoNCg0KV2hpdGUsIEJsYWNrLCBBc2lhbi1QYWMtSXNsYW5kZXIsIEFtZXItSW5kaWFuLUVza2ltbywgT3RoZXINCg0KKDcpIHNleCAoR2nhu5tpIHTDrW5oKQ0KDQoNCuKGkiBHaeG7m2kgdMOtbmggc2luaCBo4buNYyBj4bunYSBjw6EgbmjDom4uDQoNCg0KR+G7k206DQoNCg0KTWFsZSwgRmVtYWxlDQoNCg0KKDgpIG5hdGl2ZS1jb3VudHJ5IChRdeG7kWMgdOG7i2NoIGfhu5FjKQ0KDQoNCuKGkiBRdeG7kWMgZ2lhIG7GoWkgY8OhIG5ow6JuIHNpbmggcmEgaG/hurdjIGPDsyBuZ3Xhu5NuIGfhu5FjLg0KDQoNCkdpw6EgdHLhu4sgdsOtIGThu6U6DQoNCg0KVW5pdGVkLVN0YXRlcywgTWV4aWNvLCBQaGlsaXBwaW5lcywgR2VybWFueSwgVmlldG5hbSwgSW5kaWEsIENoaW5hLC4uLg0KDQoNCioqQ8OhYyBiaeG6v24gxJHhu4tuaCBsxrDhu6NuZzoqKg0KDQooMSkgYWdlIChUdeG7lWkpDQoNCg0K4oaSIFR14buVaSBj4bunYSBjw6EgbmjDom4sIGdpw6EgdHLhu4sgbMOgIHPhu5Egbmd1ecOqbiBkxrDGoW5nLg0KDQpQaOG6oW0gdmkgZOG7ryBsaeG7h3U6IHThu6sgMTcgxJHhur9uIDkwKw0KDQooMikgZm5sd2d0IChGaW5hbCBXZWlnaHQg4oCTIFRy4buNbmcgc+G7kSBkw6JuIHPhu5EpDQoNCg0K4oaSIFRy4buNbmcgc+G7kSBt4bqrdSBkbyBD4bulYyDEkGnhu4F1IHRyYSBkw6JuIHPhu5EgZ8OhbiwgdGjhu4MgaGnhu4duIHPhu5EgbMaw4bujbmcgbmfGsOG7nWkgdHJvbmcgdOG7lW5nIHRo4buDIG3DoCBt4bqrdSDEkeG6oWkgZGnhu4duLg0KDQoNCkdp4bqjaSB0aMOtY2g6DQoNCg0KTeG7mXQgbmfGsOG7nWkgY8OzIGZubHdndCA9IDEwMDAwMCDEkeG6oWkgZGnhu4duIGNobyB+MTAwLDAwMCBuZ8aw4budaSB0cm9uZyBkw6JuIHPhu5EgdGjhu7FjLg0KDQoNCkJp4bq/biBuw6B5IGNo4bunIHnhur91IGTDuW5nIHRyb25nIHBow6JuIHTDrWNoIGto4bqjbyBzw6F0LCDDrXQga2hpIMSRxrDhu6NjIGTDuW5nIHRy4buxYyB0aeG6v3AgdHJvbmcgbcO0IGjDrG5oIGThu7EgxJFvw6FuLg0KDQoNCg0KKDMpIGVkdWNhdGlvbi1udW0gKFPhu5EgbsSDbSBo4buNYykNCg0KDQrihpIgTMOgIHPhu5EgbsSDbSBo4buNYyBjaMOtbmggdGjhu6ljIHTGsMahbmcg4bupbmcgduG7m2kgYmnhur9uIGVkdWNhdGlvbi4NCg0KDQpWw60gZOG7pToNCg0KDQpIUy1ncmFkIOKJiCA5LCBCYWNoZWxvcnMg4omIIDEzLCBNYXN0ZXJzIOKJiCAxNCwgRG9jdG9yYXRlIOKJiCAxNg0KDQooNCkgY2FwaXRhbC1nYWluIChUaHUgbmjhuq1wIHbhu5FuKQ0KDQoNCuKGkiBM4bujaSBuaHXhuq1uIHbhu5FuIChjYXBpdGFsIGdhaW4pIHThu6sgY8OhYyBuZ3Xhu5NuIG5oxrAgYsOhbiB0w6BpIHPhuqNuLCDEkeG6p3UgdMawLC4uLiB0cm9uZyBuxINtLg0KDQoNCsSQ4bq3YyDEkWnhu4NtOg0KDQoNClBow6JuIHBo4buRaSBy4bqldCBs4buHY2ggcGjhuqNpLCBwaOG6p24gbOG7m24gZ2nDoSB0cuG7iyBsw6AgMCAodOG7qWMga2jDtG5nIGPDsyBsw6NpIHbhu5FuIHRyb25nIG7Eg20pLg0KDQoNCg0KKDUpIGNhcGl0YWwtbG9zcyAoTOG7lyB24buRbikNCg0KDQrihpIgVOG7lW4gdGjhuqV0IHbhu5FuIHThu6sgY8OhYyBraG/huqNuIMSR4bqndSB0xrAgdMOgaSBz4bqjbiB0cm9uZyBuxINtLg0KDQoNCkzGsHUgw706DQoNCg0KVMawxqFuZyB04buxIGNhcGl0YWwtZ2FpbiwgZ2nDoSB0cuG7iyBjaOG7pyB54bq/dSBsw6AgMCB0cm9uZyBwaOG6p24gbOG7m24gdHLGsOG7nW5nIGjhu6NwLg0KDQooNikgaG91cnMtcGVyLXdlZWsgKFPhu5EgZ2nhu50gbMOgbSBt4buXaSB0deG6p24pDQoNCg0K4oaSIFPhu5EgZ2nhu50gdHJ1bmcgYsOsbmggbcOgIGPDoSBuaMOibiBsw6BtIHZp4buHYyBt4buXaSB0deG6p24uDQoNCg0KUGjhu5UgYmnhur9uOiA0MCBnaeG7nS90deG6p24gbMOgIG3hu6ljIHRpw6p1IGNodeG6qW4sIG3hu5l0IHPhu5EgbmfGsOG7nWkgbMOgbSA2MOKAkzgwIGdp4budIGhv4bq3YyDDrXQgaMahbiAyMCBnaeG7nSAoYsOhbiB0aOG7nWkgZ2lhbikuDQoNCg0KKioqDQoNCiMgKipQSOG6pk4gMi4gUGjDom4gdMOtY2ggTcO0IHThuqMgTeG7mXQgYmnhur9uIMSQ4buLbmggdMOtbmggKFVuaXZhcmlhdGUgRGVzY3JpcHRpdmUgQW5hbHlzaXMp4oCdKioNCg0KKioqDQoNCkNobyBt4buXaSBiaeG6v24gxJHhu4tuaCB0w61uaCwgdGEgdGjhu7FjIGhp4buHbiB0aOG7kW5nIGvDqiB04bqnbiBzdeG6pXQgdsOgIHbhur0gYmnhu4N1IMSR4buTLiBExrDhu5tpIMSRw6J5IGzDoCBwaMOibiB0w61jaCBjaG8gdOG7q25nIGJp4bq/biBjaMOtbmg6DQoNCiMjICoqMi4xLiBXb3JrY2xhc3MgKE5nw6BuaCBsYW8gxJHhu5luZykqKg0KDQpgYGB7cn0NCnRhYmxlKGFkdWx0JHdvcmtjbGFzcykNCnByb3AudGFibGUodGFibGUoYWR1bHQkd29ya2NsYXNzKSkqMTAwDQpnZ3Bsb3QoYWR1bHQsIGFlcyh4PXdvcmtjbGFzcykpICsNCiAgZ2VvbV9iYXIoZmlsbD0iIzY5YjNhMiIpICsNCiAgeGxhYigiV29ya2NsYXNzIikgKyB5bGFiKCJT4buRIGzGsOG7o25nIikgKw0KICBnZ3RpdGxlKCJCaeG7g3UgxJHhu5MgY+G7mXQgY+G7p2EgV29ya2NsYXNzIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQpgYGANCg0KKipOaOG6rW4geMOpdDogKioNCg0KDQpI4bqhbmcgbeG7pWMgJ1ByaXZhdGUnIGNoaeG6v20gxrB1IHRo4bq/IHLDtSBy4buHdCAoY2hp4bq/bSA3MyUgdOG7lW5nIGThu68gbGnhu4d1KSwgbOG7m24gaMahbiBuaGnhu4F1IHNvIHbhu5tpIGPDoWMgaOG6oW5nIG3hu6VjIGtow6FjLiBDw6FjIGjhuqFuZyBt4bulYyBuaMawICdTZWxmLWVtcC1ub3QtaW5jJywgJ0xvY2FsLWdvdicsICdTdGF0ZS1nb3YnIGPFqW5nIHh14bqldCBoaeG7h24gbmjGsG5nIHbhu5tpIHThuqduIHN14bqldCB0aOG6pXAgaMahbi4gQ2hvIHRo4bqleSBy4bqxbmcgxJFhIHPhu5EgY8OhIG5ow6JuIHRyb25nIGThu68gbGnhu4d1IGzDoG0gdmnhu4djIHRyb25nIGtodSB24buxYyB0xrAgbmjDom4uDQoNCiMjICoqMi4yLiBFZHVjYXRpb24gKFRyw6xuaCDEkeG7mSBo4buNYyB24bqlbikqKg0KDQpgYGB7cn0NCnRhYmxlKGFkdWx0JGVkdWNhdGlvbikNCnByb3AudGFibGUodGFibGUoYWR1bHQkZWR1Y2F0aW9uKSkqMTAwDQpnZ3Bsb3QoYWR1bHQsIGFlcyh4PWVkdWNhdGlvbikpICsNCiAgZ2VvbV9iYXIoZmlsbD0iIzQwNDA4MCIpICsNCiAgeGxhYigiRWR1Y2F0aW9uIikgKyB5bGFiKCJT4buRIGzGsOG7o25nIikgKw0KICBnZ3RpdGxlKCJCaeG7g3UgxJHhu5MgY+G7mXQgY+G7p2EgdHLDrG5oIMSR4buZIGjhu41jIHbhuqVuIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQpgYGANCg0KKipOaOG6rW4geMOpdDogKioNCg0KDQpDw6FjIG3hu6ljIGjhu41jIHbhuqVuIHBo4buVIGJp4bq/biBuaOG6pXQgbMOgICdIUy1ncmFkJyAodOG7kXQgbmdoaeG7h3AgVEhQVCksICdTb21lLWNvbGxlZ2UnIHbDoCAnQmFjaGVsb3JzJy4gTmjhu69uZyBuaMOzbSBuw6B5IGNoaeG6v20gcGjhuqduIGzhu5tuIGThu68gbGnhu4d1LiBDw6FjIG3hu6ljIGNhbyBoxqFuIG5oxrAgJ01hc3RlcnMnLCAnRG9jdG9yYXRlJyDDrXQgcGjhu5UgYmnhur9uIGjGoW4uIEJp4buDdSDEkeG7kyBjaG8gdGjhuqV5IHBo4bqnbiBs4bubbiBuZ8aw4budaSB0cm9uZyBt4bqrdSBjw7MgdHLDrG5oIMSR4buZIHThu6sgdHJ1bmcgaOG7jWMgxJHhur9uIGPhu60gbmjDom4uDQoNCg0KTmjDs20gdOG7kXQgbmdoaeG7h3AgVEhQVCAoSFMtZ3JhZCkgY2hp4bq/bSDEkWEgc+G7kSwgc2F1IMSRw7MgbMOgIMSRYW5nIGjhu41jIENhbyDEkeG6s25nL8SQ4bqhaSBo4buNYyAoU29tZS1jb2xsZWdlKS4gxJBp4buBdSBuw6B5IHBo4bqjbiDDoW5oIHRo4buxYyB0cuG6oW5nIGdpw6FvIGThu6VjOiBwaOG6p24gxJHDtG5nIGTDom4gc+G7kSBjaOG7iSBo4buNYyDEkeG6v24gY+G6pXAgMyBob+G6t2MgY2jGsGEgaG/DoG4gdGjDoG5oIMSR4bqhaSBo4buNYy4gVsOtIGThu6UsIOG7nyBWaeG7h3QgTmFtIGPFqW5nIGPDsyB4dSBoxrDhu5tuZyB04bu3IGzhu4cgbmfGsOG7nWkgY8OzIGLhurFuZyB04buRdCBuZ2hp4buHcCBUSFBUIHRy4bufIGzDqm4gbmfDoHkgY8OgbmcgdMSDbmcsIG5oxrBuZyDEkeG6oWkgaOG7jWMgduG6q24gY2hp4bq/bSBt4buZdCBwaOG6p24gbmjhu48gaMahbi4NCg0KIyMgKioyLjMuIE1hcml0YWwtc3RhdHVzIChUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4pKioNCg0KYGBge3J9DQp0YWJsZShhZHVsdCRtYXJpdGFsX3N0YXR1cykNCnByb3AudGFibGUodGFibGUoYWR1bHQkbWFyaXRhbF9zdGF0dXMpKSoxMDANCmdncGxvdChhZHVsdCwgYWVzKHg9bWFyaXRhbF9zdGF0dXMpKSArDQogIGdlb21fYmFyKGZpbGw9IiMwMDgwODAiKSArDQogIHhsYWIoIk1hcml0YWwgU3RhdHVzIikgKyB5bGFiKCJT4buRIGzGsOG7o25nIikgKw0KICBnZ3RpdGxlKCJCaeG7g3UgxJHhu5MgY+G7mXQgY+G7p2EgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQpgYGANCg0KKipOaOG6rW4geMOpdDogKioNCg0KSOG6oW5nIG3hu6VjICdNYXJyaWVkLWNpdi1zcG91c2UnIChr4bq/dCBow7RuIGNow61uaCB0aOG7qWMpIGNoaeG6v20gdOG7tyBs4buHIGNhbyBuaOG6pXQgKGtob+G6o25nIDQ2JSkuIEPDoWMgaOG6oW5nIG3hu6VjICdOZXZlci1tYXJyaWVkJyB2w6AgJ0Rpdm9yY2VkJyDEkeG7qW5nIHNhdSwgbOG6p24gbMaw4bujdCBjaGnhur9tIGtob+G6o25nIDMyJSB2w6AgMTQlLiBDw7Mgc+G7sSBjaMOqbmggbOG7h2NoIHLDtTogbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIGNoaeG6v20gxrB1IHRo4bq/LCBwaOG6p24gbOG7m24gbMOgIG5nxrDhu51pIMSRw6MgbOG6rXAgZ2lhIMSRw6xuaC4NCg0KDQpIxqFuIDQ2JSDEkcOjIGvhur90IGjDtG4gaOG7o3AgcGjDoXAuIFRyb25nIHRo4buxYyB04bq/LCBuaOG7r25nIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biB0aMaw4budbmcgY8OzIHh1IGjGsOG7m25nIOG7lW4gxJHhu4tuaCBjw7RuZyB2aeG7h2MgdsOgIHRodSBuaOG6rXAgaMahbi4NCg0KIyMgKioyLjQuIE9jY3VwYXRpb24gKE5naOG7gSBuZ2hp4buHcCkqKg0KDQpgYGB7cn0NCnRhYmxlKGFkdWx0JG9jY3VwYXRpb24pDQpwcm9wLnRhYmxlKHRhYmxlKGFkdWx0JG9jY3VwYXRpb24pKSoxMDANCmdncGxvdChhZHVsdCwgYWVzKHg9b2NjdXBhdGlvbikpICsNCiAgZ2VvbV9iYXIoZmlsbD0iIzgwNDAwMCIpICsNCiAgeGxhYigiT2NjdXBhdGlvbiIpICsgeWxhYigiU+G7kSBsxrDhu6NuZyIpICsNCiAgZ2d0aXRsZSgiQmnhu4N1IMSR4buTIGPhu5l0IGPhu6dhIG5naOG7gSBuZ2hp4buHcCIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCg0KYGBgDQoNCg0KKipOaOG6rW4geMOpdDoqKg0KDQpDw6FjIG5naOG7gSBwaOG7lSBiaeG6v24gZ+G7k20gJ1Byb2Ytc3BlY2lhbHR5JywgJ0NyYWZ0LXJlcGFpcicsICdFeGVjLW1hbmFnZXJpYWwnLCAnQWRtLWNsZXJpY2FsJywgJ1NhbGVzJ+KApiB24bubaSBz4buRIGzGsOG7o25nIHTGsMahbmcgxJHGsMahbmcgbmhhdS4gS2jDtG5nIGPDsyBt4buZdCBuZ2jhu4EgY+G7pSB0aOG7gyBuw6BvIHF1w6Egw6FwIMSR4bqjby4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgxJFhIGThuqFuZyB24buBIG5naOG7gSBuZ2hp4buHcCwgY2jhu6cgeeG6v3UgbMOgIGPDoWMgY8O0bmcgdmnhu4djIHRheSBuZ2jhu4EgdsOgIHF14bqjbiBsw70uDQoNCg0KTmjDs20gY2h1ecOqbiB2acOqbiAoRXhlYy1tYW5hZ2VyaWFsLCBQcm9mLXNwZWNpYWx0eSkgY2hp4bq/bSB04bu3IGzhu4cgbOG7m24gKH5z4buxIHThu5VuZyBj4bunYSBFeGVjLW1hbmFnZXJpYWwgdsOgIFByb2Ytc3BlY2lhbHR5IGzDoCBraG/huqNuZyAxMy4zJSArIDEzLjQlID0gMjYsNyUpLiBDaG8gdGjhuqV5IMSRYSBz4buRIG5o4buvbmcgbmfGsOG7nWkgY8OzIHbhu4sgdHLDrSBjw7RuZyB2aeG7h2MgY2h1ecOqbiBtw7RuL2NhbyBjaGnhur9tIHBo4bqnbiBs4bubbi4NCg0KIyMgKioyLjUuIFJlbGF0aW9uc2hpcCAoUXVhbiBo4buHIGdpYSDEkcOsbmgpKioNCg0KYGBge3J9DQp0YWJsZShhZHVsdCRyZWxhdGlvbnNoaXApDQpwcm9wLnRhYmxlKHRhYmxlKGFkdWx0JHJlbGF0aW9uc2hpcCkpKjEwMA0KZ2dwbG90KGFkdWx0LCBhZXMoeD1yZWxhdGlvbnNoaXApKSArDQogIGdlb21fYmFyKGZpbGw9IiM4MDgwODAiKSArDQogIHhsYWIoIlJlbGF0aW9uc2hpcCIpICsgeWxhYigiU+G7kSBsxrDhu6NuZyIpICsNCiAgZ2d0aXRsZSgiQmnhu4N1IMSR4buTIGPhu5l0IGPhu6dhIHF1YW4gaOG7hyBnaWEgxJHDrG5oIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpI4bqhbmcgbeG7pWMgJ0h1c2JhbmQnIChuYW0gxJHDoyBr4bq/dCBow7RuKSBjaGnhur9tIHThu7cgbOG7hyBs4bubbiBuaOG6pXQgKH40MSUpLCB0aeG6v3AgdGhlbyBsw6AgJ05vdC1pbi1mYW1pbHknICh+MjUlKS4gJ093bi1jaGlsZCcgY2hp4bq/bSBraG/huqNuZyAxNSUuIENobyB0aOG6pXksIG5hbSBnaeG7m2kgxJHDoyBr4bq/dCBow7RuIGNoaeG6v20gdOG7iSBs4buHIG5oaeG7gXUgaMahbi4gQ8OhYyBt4buRaSBxdWFuIGjhu4cgZ2lhIMSRw6xuaCBraMOhYyBuaMawIHbhu6MsIGNvbiBjw6FpLCBo4buNIGjDoG5nIGNoaeG6v20gcGjhuqduIG5o4buPLg0KDQojIyAqKjIuNi4gUmFjZSAoQ2jhu6duZyB04buZYykqKg0KDQpgYGB7cn0NCnRhYmxlKGFkdWx0JHJhY2UpDQpwcm9wLnRhYmxlKHRhYmxlKGFkdWx0JHJhY2UpKSoxMDANCmdncGxvdChhZHVsdCwgYWVzKHg9cmFjZSkpICsNCiAgZ2VvbV9iYXIoZmlsbD0iI0MwNDAwMCIpICsNCiAgeGxhYigiUmFjZSIpICsgeWxhYigiU+G7kSBsxrDhu6NuZyIpICsNCiAgZ2d0aXRsZSgiQmnhu4N1IMSR4buTIGPhu5l0IGPhu6dhIGNo4bunbmcgdOG7mWMiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQoNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNCsSQYSBz4buRIGzDoCAnV2hpdGUnIChraG/huqNuZyA4NiUpLCAnQmxhY2snIH45JSwgY8OhYyBjaOG7p25nIHThu5ljIGtow6FjICjDgSBjaMOidSwgZGEgxJHhu48sIGtow6FjKSBjaOG7iSBjaGnhur9tIHbDoGkgcGjhuqduIHRyxINtLiBT4buxIGNow6puaCBs4buHY2ggcuG6pXQgbOG7m24uIENobyB0aOG6pXkgY2jhu6cgeeG6v3UgbMOgIG5nxrDhu51pIGRhIHRy4bqvbmcsIHTGsMahbmcg4bupbmcgduG7m2kgxJHhurdjIHRyxrBuZyBkw6JuIHPhu5EgY+G7p2EgZOG7ryBsaeG7h3UgZ+G7kWMuDQoNCiMjICoqMi43LiBTZXggKEdp4bubaSB0w61uaCkqKg0KDQpgYGB7cn0NCnRhYmxlKGFkdWx0JHNleCkNCnByb3AudGFibGUodGFibGUoYWR1bHQkc2V4KSkqMTAwDQpnZ3Bsb3QoYWR1bHQsIGFlcyh4PXNleCkpICsNCiAgZ2VvbV9iYXIoZmlsbD0iIzAwODA4MCIpICsNCiAgeGxhYigiU2V4IikgKyB5bGFiKCJT4buRIGzGsOG7o25nIikgKw0KICBnZ3RpdGxlKCJCaeG7g3UgxJHhu5MgY+G7mXQgY+G7p2EgZ2nhu5tpIHTDrW5oIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMC41KSkNCg0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KDQpN4bqrdSBn4buTbSBraG/huqNuZyA2NyUgbmFtIHbDoCAzMiUgbuG7ry4gTmFtIGdp4bubaSBjaGnhur9tIMawdSB0aOG6vyByw7UgcuG7h3QuIFRo4buxYyB04bq/LCBz4buRIGxhbyDEkeG7mW5nIG5hbSB0aMaw4budbmcgbmhp4buBdSBoxqFuIG7hu68gZG8gbmhp4buBdSB54bq/dSB04buRIChjaOG7pyBxdWFuLCB0cnV54buBbiB0aOG7kW5nKS4gVHV5IG5oacOqbiwgZOG7ryBsaeG7h3UgbsOgeSBraMO0bmcgY8OibiBi4bqxbmcgZ2nhu5tpIHTDrW5oLg0KDQojIyAqKjIuOC4gTmF0aXZlLWNvdW50cnkgKFF14buRYyB04buLY2ggZ+G7kWMpKioNCg0KYGBge3J9DQp0YWJsZShhZHVsdCRuYXRpdmVfY291bnRyeSkNCnByb3AudGFibGUodGFibGUoYWR1bHQkbmF0aXZlX2NvdW50cnkpKSoxMDANCmdncGxvdChhZHVsdCAlPiUgZmlsdGVyKG5hdGl2ZV9jb3VudHJ5ICE9ICJVbml0ZWQtU3RhdGVzIiksDQogICAgICAgYWVzKHg9bmF0aXZlX2NvdW50cnkpKSArDQogIGdlb21fYmFyKGZpbGw9IiM4MDQwODAiKSArDQogIHhsYWIoIk5hdGl2ZSBDb3VudHJ5IChuZ2/huqFpIHRy4burIE3hu7kpIikgKyB5bGFiKCJT4buRIGzGsOG7o25nIikgKw0KICBnZ3RpdGxlKCJCaeG7g3UgxJHhu5MgY+G7mXQgY+G7p2EgcXXhu5FjIHThu4tjaCBn4buRYyAoa2jDtG5nIGJhbyBn4buTbSBN4bu5KSIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCBzaXplPTgpKQ0KDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQrEkGEgc+G7kSAoZ+G6p24gODklKSBjw7Mgbmd14buTbiBn4buRYyB04burICdVbml0ZWQtU3RhdGVzJywgcGjhuqduIGPDsm4gbOG6oWkgcuG6o2kgcsOhYyDhu58gbmhp4buBdSBxdeG7kWMgZ2lhIGtow6FjIChNZXhpY28sIFBoaWxpcHBpbmVzLCDEkOG7qWMuLi4pLiBT4buxIGNow6puaCBs4buHY2ggcuG6pXQgbOG7m24gY2hvIHRo4bqleSB04bqtcCBt4bqrdSBjaOG7pyB54bq/dSBsw6AgbmfGsOG7nWkgTeG7uS4NCg0KDQpIxqFuIDg5JSBsw6AgbmfGsOG7nWkgTeG7uS4gxJBp4buBdSBuw6B5IGjhu6NwIGzDvSB2w6wgZOG7ryBsaeG7h3UgdOG7qyBjdeG7mWMgxJFp4buBdSB0cmEgZMOibiBz4buRIE3hu7ksIGNo4buJIG3hu5l0IHBo4bqnbiBuaOG7jyB0aHXhu5ljIHF14buRYyBnaWEga2jDoWMgKE1leGlrbywgUGhpbGlwcGluZXMsIHYudi4pLg0KDQojIyAqKjIuOS4gUGjDom4gdMOtY2ggbeG7mXQgc+G7kSBiaeG6v24gxJHhu4tuaCBsxrDhu6NuZyoqDQoNClRoZW8gYsOhbyBjw6FvIGPhu6dhIEPhu6VjIMSQaeG7gXUgdHJhIGTDom4gc+G7kSBN4bu5IG7Eg20gMjAyMiwgxJHhu5kgdHXhu5VpIHRydW5nIGLDrG5oIGPhu6dhIGTDom4gc+G7kSBN4bu5IMSR4bqhdCAzOC45IHR14buVaS4gVHJvbmcgYuG7mSBk4buvIGxp4buHdSBBZHVsdCAoMTk5NCksIMSR4buZIHR14buVaSB0cnVuZyBiw6xuaCAoYWdlKSB0w61uaCDEkcaw4bujYyBraG/huqNuZyAzOC42IHR14buVaSAoxJHhu5kgbOG7h2NoIGNodeG6qW4ga2hv4bqjbmcgMTMuNiksIHbhu5tpIGdpw6EgdHLhu4sgdHJ1bmcgduG7iyBraG/huqNuZyAzNiB0deG7lWkuIE5oxrAgduG6rXksIG3huqt1IGThu68gbGnhu4d1IGPDsyDEkeG7mSB0deG7lWkgdMawxqFuZyDEkcawxqFuZyB0cnVuZyBiw6xuaCBkw6JuIHPhu5EgaGnhu4duIHThuqFpLiBWw60gZOG7pSwgxJFv4bqhbiBtw6MgUiBzYXUgY2hvIGJp4bq/dCB0aOG7kW5nIGvDqiBjxqEgYuG6o24gduG7gSB0deG7lWkgdsOgIGdp4budIGzDoG0gdmnhu4djOg0KDQpgYGB7cn0NCnN1bW1hcnkoYWR1bHQkYWdlKQ0Kc3VtbWFyeShhZHVsdCRob3Vyc19wZXJfd2VlaykNCg0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KxJDhu5kgdHXhu5VpIChhZ2UpOiB0cnVuZyBiw6xuaCDiiYggMzguNDQsIHRydW5nIHbhu4sgMzcsIHBo4bqnbiB24buLIHRo4bupIG5o4bqldCB+MjgsIHBo4bqnbiB24buLIHRo4bupIGJhIH40Ny4gDQoNCg0KR2nhu50gbMOgbSB2aeG7h2MgbeG7l2kgdHXhuqduIChob3Vyc19wZXJfd2Vlayk6IHRydW5nIGLDrG5oIOKJiCA0MC45MyBnaeG7nSwgdHJ1bmcgduG7iyA0MCBnaeG7nSwgcGjhuqduIHbhu4sgdGjhu6kgbmjhuqV0IDQwLCBwaOG6p24gduG7iyB0aOG7qSBiYSB+NDUuIEjhuqd1IGjhur90IG5nxrDhu51pIGxhbyDEkeG7mW5nIGzDoG0gdmnhu4djIHh1bmcgcXVhbmggNDAgZ2nhu50gbeG7l2kgdHXhuqduLCB0xrDGoW5nIHThu7EgbeG7qWMgdHJ1bmcgYsOsbmggZ+G6p24gNDAgZ2nhu50vdHXhuqduIHRyb25nIGzhu7FjIGzGsOG7o25nIGxhbyDEkeG7mW5nIE3hu7kgaGnhu4duIG5heS4NCg0KDQoqKioNCg0KIyAqKlBI4bqmTiAzLiDGr+G7m2MgbMaw4bujbmcgS2hv4bqjbmcgdsOgIEtp4buDbSDEkeG7i25oIEdp4bqjIHRodXnhur90IGNobyBU4bu3IGzhu4cqKg0KDQoqKioNCg0KQ2jhu41uIDMgYmnhur9uIMSR4buLbmggdMOtbmggdGnDqnUgYmnhu4N1OiBTZXggKEZlbWFsZSksIFdvcmtjbGFzcyAoUHJpdmF0ZSksIE1hcml0YWwtc3RhdHVzIChNYXJyaWVkLWNpdi1zcG91c2UpLiBW4bubaSBt4buXaSBiaeG6v24sIHhlbSB4w6l0IG3hu5l0IGjhuqFuZyBt4bulYyBxdWFuIHTDom0gdsOgIHBow6JuIHTDrWNoOg0KDQojIyAqKjMuMS4gVOG7tyBs4buHIG7hu68gKHNleCA9IEZlbWFsZSkpKioNCg0KKirGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSoqIGNobyB04buJIGzhu4cgbuG7ryB0cm9uZyB04buVbmcgdGjhu4M6DQoNCmBgYHtyfQ0Kbl90b3RhbCA8LSBucm93KGFkdWx0KQ0KeF9mZW1hbGUgPC0gc3VtKGFkdWx0JHNleCA9PSAiRmVtYWxlIikNCnByb3AudGVzdCh4ID0geF9mZW1hbGUsIG4gPSBuX3RvdGFsLCBjb25mLmxldmVsID0gMC45NSkNCg0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KS2hv4bqjbmcgdGluIGPhuq15IMaw4bubYyB0w61uaCBjaG8gdOG7tyBs4buHIG7hu68ga2hv4bqjbmcgWzAuMzE5LCAwLjMyOV0uIA0KDQoNClbhuq15LCB24bubaSBt4bupYyDDvSBuZ2jEqWEgOTUlIHRow6wgdOG7tyBs4buHIG7hu68gdHJvbmcgdG/DoG4gYuG7mSBkw6JuIHPhu5EgdMawxqFuZyDhu6luZyBu4bqxbSB0cm9uZyBraG/huqNuZyBbMC4zMTksIDAuMzI5XS4NCg0KDQoqKktp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90OioqIEdp4bqjIHPhu60g8J2QuzA68J2RnT0wLjUgKHThu7cgbOG7hyBu4buvID0gNTAlKS4gVGjhu7FjIGhp4buHbiBraeG7g20gxJHhu4tuaDoNCg0KYGBge3J9DQpwcm9wLnRlc3QoeCA9IHhfZmVtYWxlLCBuID0gbl90b3RhbCwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIiwgcCA9IDAuNSwgY29uZi5sZXZlbCA9IDAuOTUpDQoNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQogDQpL4bq/dCBxdeG6ozogR2nDoSB0cuG7iyBwIHLhuqV0IG5o4buPICg8Mi4yZS0xNikgbsOqbiBiw6FjIGLhu48g8J2QuzAg4bufIG3hu6ljIMO9IG5naMSpYSAwLjA1LiANCg0KDQpL4bq/dCBsdeG6rW46IFThu7cgbOG7hyBu4buvIHRyb25nIG3huqt1IGtow7RuZyBi4bqxbmcgNTAlLiBUaOG7sWMgdOG6vywgbeG6q3UgbsOgeSBjw7MgdOG7tyBs4buHIG7hu68gfjMzLjUlIChuaOG7jyBoxqFuIDUwJSkuIEvhur90IGx14bqtbiBjw7Mgw70gbmdoxKlhIGzDoCB04bu3IGzhu4cgbuG7ryB0aOG7sWMgdOG6vyB0aOG6pXAgaMahbiBnaeG6oyB0aHV54bq/dCBiYW4gxJHhuqd1Lg0KDQoNCiMjICoqMy4yLiBU4bu3IGzhu4cgdGh14buZYyBsb+G6oWkgY8O0bmcgdmnhu4djICJQcml2YXRlIioqDQoNCioqxq/hu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSA5NSU6KioNCg0KYGBge3J9DQp4X3ByaXZhdGUgPC0gc3VtKGFkdWx0JHdvcmtjbGFzcyA9PSAiUHJpdmF0ZSIpDQpuX3RvdGFsIDwtIG5yb3coYWR1bHQpDQpwcm9wLnRlc3QoeCA9IHhfcHJpdmF0ZSwgbiA9IG5fdG90YWwsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpLaG/huqNuZyB0aW4gY+G6rXkgxrDhu5tjIHTDrW5oIGNobyB04bu3IGzhu4cgJ1ByaXZhdGUnIGzDoCBbMC43MzMsIDAuNzQzXS4gDQoNCg0KVuG6rXksIHbhu5tpIG3hu6ljIMO9IG5naMSpYSA5NSUgdGjDrCB04bu3IGzhu4cgbmfGsOG7nWkgY8OzIGPDtG5nIHZp4buHYyB0aHXhu5ljIGRp4buHbiAnUHJpdmF0ZScgdHJvbmcgdOG7lW5nIHRo4buDIG7hurFtIHRyb25nIGtob+G6o25nIFswLjczMywgMC43NDNdLg0KDQoNCioqS2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3Q6KiogS2nhu4NtIMSR4buLbmgg8J2QuzA68J2RnT0wLjUgKG5naMSpYSBsw6AgZ2nhuqMgxJHhu4tuaCBiYW4gxJHhuqd1IGzDoCBjaOG7iSA1MCUgbMOgIHByaXZhdGUpLg0KDQpgYGB7cn0NCnByb3AudGVzdCh4ID0geF9wcml2YXRlLCBuID0gbl90b3RhbCwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIiwgcCA9IDAuNSwgY29uZi5sZXZlbCA9IDAuOTUpDQoNCmBgYA0KDQoqKk5o4bqtbiB4w6l0KioNCg0KS+G6v3QgcXXhuqM6IHAtdmFsdWUg4omIIDAgKDwyLjJlLTE2KS4gQsOhYyBi4buPIPCdkLswIC4gDQoNCg0KVuG6rXksIFThu7cgbOG7hyBuZ8aw4budaSBsw6BtIHRyb25nIGtodSB24buxYyAiUHJpdmF0ZSIgY2FvIGjGoW4gZ2nhuqMgdGhp4bq/dCA1MCUuIFRo4buxYyB04bq/IG3huqt1IGNobyB0aOG6pXkgfjcwJSBsw6BtIHZp4buHYyB0cm9uZyBraHUgduG7sWMgdMawIG5ow6JuLCBjaMOqbmggbOG7h2NoIGzhu5tuIHNvIHbhu5tpIGdp4bqjIHRodXnhur90IGJhbiDEkeG6p3UuDQoNCg0KIyMgKiozLjMuIFThu7cgbOG7hyAiTWFycmllZC1jaXYtc3BvdXNlIioqDQoNCioqxq/hu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSA5NSU6KioNCg0KYGBge3J9DQp4X21hcnJpZWQgPC0gc3VtKGFkdWx0JG1hcml0YWxfc3RhdHVzID09ICJNYXJyaWVkLWNpdi1zcG91c2UiKQ0KcHJvcC50ZXN0KHggPSB4X21hcnJpZWQsIG4gPSBuX3RvdGFsLCBjb25mLmxldmVsID0gMC45NSkNCg0KYGBgDQoNCioqTmjhuq1uIHjDqXQqKg0KDQpLaG/huqNuZyB0aW4gY+G6rXkgY2hvIHThu7cgbOG7hyAnTWFycmllZC1jaXYtc3BvdXNlJyBsw6Aga2hv4bqjbmcgWzAuNDYwLCAwLjQ3MV0gDQoNCg0KVuG6rXkgduG7m2kgbeG7qWMgw70gbmdoxKlhIDk1JSB0aMOsIHThu7cgbOG7hyDEkcOjIGvhur90IGjDtG4gdGhlbyBraOG6o28gc8OhdCBu4bqxbSB0cm9uZyBraG/huqNuZyBbMC40NjAsIDAuNDcxXS4NCg0KDQoqKktp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90OioqIEtp4buDbSDEkeG7i25oIPCdkLswOvCdkZ09MC41DQoNCmBgYHtyfQ0KcHJvcC50ZXN0KHggPSB4X21hcnJpZWQsIG4gPSBuX3RvdGFsLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCBwID0gMC41LCBjb25mLmxldmVsID0gMC45NSkNCg0KYGBgDQoNCioqTmjhuq1uIHjDqXQqKg0KDQpL4bq/dCBxdeG6ozogcC12YWx1ZSBy4bqldCBuaOG7jywoPDIuMmUtMTYpIGLDoWMgYuG7jyDwnZC7MC4gTmdoxKlhIGzDoCB04bu3IGzhu4cgxJHDoyBr4bq/dCBow7RuIHRyb25nIG3huqt1ICh+NDYlKSBraMOhYyB24bubaSBnaeG6oyB0aHV54bq/dCA1MCUuIMSQaeG7gXUgbsOgeSBwaMO5IGjhu6NwIHbhu5tpIG5o4bqtbiB4w6l0IHRyxrDhu5tjIMSRw7MgcuG6sW5nIH40NiUgxJHDoyBs4bqtcCBnaWEgxJHDrG5oLCBrw6ltIGdp4bqjIHRoaeG6v3QgNTAlLg0KDQoqKioNCg0KIyAqKlBI4bqmTiA0LiBQaMOibiB0w61jaCBN4buRaSBxdWFuIGjhu4cgZ2nhu69hIEhhaSBiaeG6v24gxJDhu4tuaCB0w61uaCoqDQoNCioqKg0KDQpDaOG7jW4gMyBj4bq3cCBiaeG6v24gxJHhu4tuaCB0w61uaCBsacOqbiBxdWFuIMSR4bq/biB0aHUgbmjhuq1wIChpbmNvbWUpIHbDoCBjw6FjIGJp4bq/biBraMOhYzogU2V4IC0gSW5jb21lLCBFZHVjYXRpb24gLSBJbmNvbWUsIE1hcml0YWwtc3RhdHVzIC0gSW5jb21lLiBW4bubaSBt4buXaSBj4bq3cCwgdGEgbOG6rXAgYuG6o25nIGNow6lvLCB24bq9IGJp4buDdSDEkeG7kywgdsOgIGtp4buDbSDEkeG7i25oIENoaS1iw6xuaCBwaMawxqFuZyDEkeG7mWMgbOG6rXAuDQoNCiMjICoqNC4xLiBTZXggdsOgIEluY29tZSoqDQoNCioqQuG6o25nIHThuqduIHN14bqldCBjaMOpbzoqKg0KDQpgYGB7cn0NCnRhYl9zZXhfaW5jIDwtIHRhYmxlKGFkdWx0JHNleCwgYWR1bHQkaW5jb21lKQ0KdGFiX3NleF9pbmMNCnByb3AudGFibGUodGFiX3NleF9pbmMsIDEpKjEwMCAgIyBU4bu3IGzhu4cgdGhlbyBow6BuZyBnaeG7m2kgdMOtbmgNCg0KYGBgDQoNClThu7cgbOG7hyBjw7MgdGh1IG5o4bqtcCA+NTBLOiB+MzEuMzglIOG7nyBuYW0sIH4xMS4zNiUg4bufIG7hu68uDQoNCg0KKipUcuG7sWMgcXVhbiBow7NhOioqIEJp4buDdSDEkeG7kyBj4buZdCBjaOG7k25nIGNobyB0aOG6pXkgc+G7sSBraMOhYyBiaeG7h3QgbOG7m24uDQoNCmBgYHtyfQ0KZ2dwbG90KGFkdWx0LCBhZXMoeD1zZXgsIGZpbGw9aW5jb21lKSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIpICsNCiAgeWxhYigiVOG7tyBs4buHICglKSIpICsgZ2d0aXRsZSgiVOG7tyBs4buHIHRodSBuaOG6rXAgPjUwSyB0aGVvIGdp4bubaSB0w61uaCIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3Q9MC41KSkNCg0KYGBgDQoNCk5o4bqtbiB4w6l0IG3DtCB04bqjOiBCaeG7g3UgxJHhu5MgdsOgIHThu7cgbOG7hyBjaG8gdGjhuqV5IG5hbSBnaeG7m2kgY8OzIHThu7cgbOG7hyB0aHUgbmjhuq1wID41MEsgY2FvIGjGoW4gcuG6pXQgbmhp4buBdSBzbyB24bubaSBu4buvLg0KDQoNCioqS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nOioqDQoNCg0KSDA6IEdp4bubaSB0w61uaCB2w6AgdGh1IG5o4bqtcCDEkeG7mWMgbOG6rXAgKGtow7RuZyBsacOqbiBxdWFuKSB0cm9uZyB04buVbmcgdGjhu4MuDQoNCg0KSDE6IEPDsyBt4buRaSBsacOqbiBo4buHIGdp4buvYSBnaeG7m2kgdMOtbmggdsOgIHRodSBuaOG6rXAuDQoNCg0KYGBge3J9DQpjaGlzcV90ZXN0X3NleF9pbmMgPC0gY2hpc3EudGVzdCh0YWJfc2V4X2luYykNCmNoaXNxX3Rlc3Rfc2V4X2luYyRzdGF0aXN0aWM7IGNoaXNxX3Rlc3Rfc2V4X2luYyRwYXJhbWV0ZXI7IGNoaXNxX3Rlc3Rfc2V4X2luYyRwLnZhbHVlDQoNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNCkvhur90IHF14bqjIEdpw6EgdHLhu4sgWCBiw6xuaCBwaMawxqFuZyBs4bubbiwgcC12YWx1ZSBy4bqldCBuaOG7jy4gS+G6v3QgbHXhuq1uOiBCw6FjIGLhu48gSDAgKHRoZW8gbeG7qWMgMC4wNSkuIEdp4bubaSB0w61uaCBjw7MgbGnDqm4gcXVhbiBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIHbhu5tpIHZp4buHYyBraeG6v20gxJHGsOG7o2MgPjUwSywgdOG7qWMgdOG7tyBs4buHIHRodSBuaOG6rXAgY2FvIHBo4bulIHRodeG7mWMgdsOgbyBnaeG7m2kgdMOtbmguIFRo4buxYyB04bq/IGNobyB0aOG6pXkgbmfGsOG7nWkgxJHDoG4gw7RuZyBsw6AgdHLhu6UgY+G7mXQgY+G7p2EgZ2lhIMSRw6xuaCBuw6puIGPDsyB4dSBoxrDhu5tuZyBsw6BtIHZp4buHYyBuaGnhu4F1IG5nxrDhu51pIHBo4bulIG7hu68gdsOsIHbhuq15IHZp4buHYyDEkcOgbiDDtG5nIGPDsyB0aHUgbmjhuq1wIGNhbyBoxqFuIHNvIHbhu5tpIHBo4bulIG7hu68gbMOgIGjhu6NwIGzDrS4NCg0KKipSaXNrIFJhdGlvKioNCg0KYGBge3J9DQpycl9zZXhfaW5jb21lIDwtIHJpc2tyYXRpbyh0YWJfc2V4X2luYykNCnJyX3NleF9pbmNvbWUNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNCuG7niDEkcOieSwgdGEgbOG6pXkgRmVtYWxlIGzDoCBuaMOzbSB0aGFtIGNoaeG6v3UgdsOgIE1hbGUgbMOgIG5ow7NtIHNvIHPDoW5oIHbhu5tpIHPhu7Ega2nhu4duIGzDoCAidGh1IG5o4bqtcCA+IDUwSyIgDQoNCkvhur90IHF14bqjIFJSIGPhu6dhIE1hbGUgPSAyLjc2MCBjaG8gdGjhuqV5IE5hbSBjw7MgeMOhYyBzdeG6pXQgY8OzIHRodSBuaOG6rXAgKD41MEspIGfhuqVwIDIuNzYgbOG6p24gc28gduG7m2kgbuG7ryBnaeG7m2kuDQoNCioqT2RkcyBSYXRpbyoqDQoNCmBgYHtyfQ0Kb3Jfc2V4X2luY29tZSA8LSBvZGRzcmF0aW8odGFiX3NleF9pbmMpDQpvcl9zZXhfaW5jb21lDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQrhu54gxJHDonksIHRhIGzhuqV5IEZlbWFsZSBsw6AgbmjDs20gdGhhbSBjaGnhur91IHbDoCBNYWxlIGzDoCBuaMOzbSBzbyBzw6FuaCB24bubaSBz4buxIGtp4buHbiBsw6AgInRodSBuaOG6rXAgPiA1MEsiIA0KDQpL4bq/dCBxdeG6oyBPUiBj4bunYSBNYWxlID0gMy41NjUgY2hvIHRo4bqleSBraOG6oyBuxINuZyBuYW0gY8OzIHRodSBuaOG6rXAgKD41MEspIGfhuqVwIDMuNTY1IGzhuqduIHNvIHbhu5tpIG7hu68uDQoNCiMjICoqNC4yLiBFZHVjYXRpb24gdsOgIEluY29tZSoqDQoNCioqQuG6o25nIHThuqduIHN14bqldCBjaMOpbzoqKg0KDQpgYGB7cn0NCnRhYl9lZHVfaW5jIDwtIHRhYmxlKGFkdWx0JGVkdWNhdGlvbiwgYWR1bHQkaW5jb21lKQ0KcHJvcC50YWJsZSh0YWJfZWR1X2luYywgMSkqMTAwICAjIFThu7cgbOG7hyB0aGVvIGjDoG5nICh0csOsbmggxJHhu5kpDQoNCg0KYGBgDQoNCg0KVOG7tyBs4buHIHRodSBuaOG6rXAgPjUwSyB0xINuZyBk4bqnbiB24bubaSB0csOsbmggxJHhu5k6IHThu6sgZ+G6p24gMCDhu58gdHLDrG5oIMSR4buZIHRo4bqlcCDEkeG6v24gfjUwJSDhu58gdHLDrG5oIMSR4buZIGNhbyAoRG9jdG9yYXRlLCBQcm9mLXNjaG9vbCkuDQoNCg0KKipUcuG7sWMgcXVhbiBow7NhOioqIA0KDQpgYGB7cn0NCmdncGxvdChhZHVsdCwgYWVzKHg9ZWR1Y2F0aW9uLCBmaWxsPWluY29tZSkpICsNCiAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiKSArDQogIHhsYWIoIkVkdWNhdGlvbiIpICsgeWxhYigiVOG7tyBs4buHICglKSIpICsNCiAgZ2d0aXRsZSgiVOG7tyBs4buHID41MEsgdGhlbyB0csOsbmggxJHhu5kgaOG7jWMgduG6pW4iKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQoNCmBgYA0KDQoNCk5o4bqtbiB4w6l0IG3DtCB04bqjOiBDw7MgeHUgaMaw4bubbmcgcsO1OiBuaOG7r25nIG5nxrDhu51pIGPDsyBo4buNYyB24bqlbiBjYW8gaMahbiAoQmFjaGVsb3JzLCBNYXN0ZXJzLCBEb2N0b3JhdGUpIGPDsyBraOG6oyBuxINuZyB0aHUgbmjhuq1wID41MEsgY2FvIGjGoW4gbmjhu69uZyBuZ8aw4budaSBo4buNYyB24bqlbiB0aOG6pXAgKEhTLWdyYWQsIFNvbWUtY29sbGVnZSkuDQoNCg0KKipLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmc6KioNCg0KYGBge3J9DQpjaGlzcV90ZXN0X2VkdV9pbmMgPC0gY2hpc3EudGVzdCh0YWJfZWR1X2luYykNCmNoaXNxX3Rlc3RfZWR1X2luYyRzdGF0aXN0aWM7IGNoaXNxX3Rlc3RfZWR1X2luYyRwYXJhbWV0ZXI7IGNoaXNxX3Rlc3RfZWR1X2luYyRwLnZhbHVlDQoNCmBgYA0KDQpwLXZhbHVlIHLhuqV0IG5o4buPLCBiw6FjIGLhu48gSDAuIEvhur90IGx14bqtbjogQ8OzIG3hu5FpIGxpw6puIGjhu4cgw70gbmdoxKlhIGdp4buvYSB0csOsbmggxJHhu5kgaOG7jWMgduG6pW4gdsOgIHRodSBuaOG6rXAuIE5nxrDhu51pIGPDsyBo4buNYyB24bqlbiBjYW8gaMahbiBjw7MgdOG7tyBs4buHIGtp4bq/bSA+NTBLIGNhbyBoxqFuLg0KDQoqKlJpc2sgUmF0aW8qKg0KDQpgYGB7cn0NCnJyX2VkdV9pbmNvbWUgPC0gcmlza3JhdGlvKHRhYl9lZHVfaW5jKQ0KcnJfZWR1X2luY29tZQ0KYGBgDQoNCg0KIyMgKio0LjMuIE1hcml0YWwtc3RhdHVzIHbDoCBJbmNvbWUqKg0KDQoqKkLhuqNuZyB04bqnbiBzdeG6pXQgY2jDqW86KioNCg0KYGBge3J9DQp0YWJfbWFyX2luYyA8LSB0YWJsZShhZHVsdCRtYXJpdGFsX3N0YXR1cywgYWR1bHQkaW5jb21lKQ0KcHJvcC50YWJsZSh0YWJfbWFyX2luYywgMSkqMTAwDQoNCg0KDQpgYGANCg0KDQpOaMOzbSAnTWFycmllZC1jaXYtc3BvdXNlJyBjw7MgdOG7tyBs4buHID41MEsgY2FvIG5o4bqldCAoa2hv4bqjbmcgNjAlKSwgdHJvbmcga2hpIG5ow7NtICdOZXZlci1tYXJyaWVkJyB0aOG6pXAgaMahbiAofjEyJSkuDQoNCg0KKipUcuG7sWMgcXVhbiBow7NhOioqIA0KDQpgYGB7cn0NCmdncGxvdChhZHVsdCwgYWVzKHg9bWFyaXRhbF9zdGF0dXMsIGZpbGw9aW5jb21lKSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIpICsNCiAgeGxhYigiTWFyaXRhbCBTdGF0dXMiKSArIHlsYWIoIlThu7cgbOG7hyAoJSkiKSArDQogIGdndGl0bGUoIlThu7cgbOG7hyA+NTBLIHRoZW8gdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQoNCmBgYA0KDQpOaOG6rW4geMOpdCBtw7QgdOG6ozogUsO1IHLDoG5nIG5nxrDhu51pIMSRw6MgbOG6rXAgZ2lhIMSRw6xuaCAnTWFycmllZC1jaXYtc3BvdXNlJyBjw7Mga2jhuqMgbsSDbmcgdGh1IG5o4bqtcCBjYW8gbOG7m24gaMahbiBzbyB24bubaSBuaMOzbSBjaMawYSBjxrDhu5tpIGhv4bq3YyBseSBow7RuLg0KDQoNCioqS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nOioqDQoNCmBgYHtyfQ0KY2hpc3FfdGVzdF9tYXJfaW5jIDwtIGNoaXNxLnRlc3QodGFiX21hcl9pbmMpDQpjaGlzcV90ZXN0X21hcl9pbmMkc3RhdGlzdGljOyBjaGlzcV90ZXN0X21hcl9pbmMkcGFyYW1ldGVyOyBjaGlzcV90ZXN0X21hcl9pbmMkcC52YWx1ZQ0KDQpgYGANCg0KS+G6v3QgcXXhuqM6IHAtdmFsdWUg4omIIDAsIGLDoWMgYuG7jyBIMC4gS+G6v3QgbHXhuq1uOiBDw7MgbGnDqm4gcXVhbiByw7UgcsOgbmcgZ2nhu69hIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiB2w6AgdGh1IG5o4bqtcA0Kc2NyaWJici5jb20uIE5ow7NtIMSRw6Mga+G6v3QgaMO0biBjw7MgdOG7tyBs4buHIHRodSBuaOG6rXAgY2FvIGjGoW4gxJHDoW5nIGvhu4MuDQoNCiANCioqKg0KDQojICoqUEjhuqZOIDUuIEvhur90IGx14bqtbiB2w6AgxJDhu4EgeHXhuqV0KioNCg0KKioqDQoNCi0gKipU4buVbmcga+G6v3QgcGjDoXQgaGnhu4duIGNow61uaDoqKiBE4buvIGxp4buHdSBjaG8gdGjhuqV5IG5ow7NtIG3huqt1IGNo4bunIHnhur91IGzDoCBuZ8aw4budaSBN4bu5IGRhIHRy4bqvbmcsIG5hbSBnaeG7m2ksIGPDsyB0csOsbmggxJHhu5kgVEhQVCBob+G6t2MgQ+G7rSBuaMOibiwgcGjhuqduIGzhu5tuIMSRw6MgbOG6rXAgZ2lhIMSRw6xuaCB2w6AgbMOgbSB2aeG7h2Mga2h1IHbhu7FjIHTGsCBuaMOibi4gTmFtIGdp4bubaSBjw7MgdOG7tyBs4buHIHRodSBuaOG6rXAgPjUwSyBn4bqlcCB+MyBs4bqnbiBu4buvLCBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gdsOgIGPDsyB0csOsbmggxJHhu5kgY2FvIGjGoW4gY8WpbmcgZOG7hSBjw7MgdGh1IG5o4bqtcCBjYW8gaMahbi4gVMOzbSBs4bqhaSwgdGh1IG5o4bqtcCBs4bubbiAoPjUwSykgY8OzIGxpw6puIHF1YW4gcsO1IHLhu4d0IMSR4bq/biBnaeG7m2kgdMOtbmgsIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiwgZ2nDoW8gZOG7pWMuLi4gbmjGsCDEkcOjIGtp4buDbSDEkeG7i25oIChjaGktc3F1YXJlIHRlc3QpIOG7nyB0csOqbg0KDQotICoqSOG6oW4gY2jhur8gcGjDom4gdMOtY2g6KiogQsOgaSBwaMOibiB0w61jaCBjaOG7iSB04bqtcCB0cnVuZyB2w6BvIGJp4bq/biDEkeG7i25oIHTDrW5oOyBjaMawYSB4ZW0geMOpdCBiaeG6v24gxJHhu4tuaCBsxrDhu6NuZyAodHXhu5VpLCBnaeG7nSBsw6BtKS4gROG7ryBsaeG7h3UgY8OzIHRo4buDIMSRw6MgY8WpIChj4bunYSBraG/huqNuZyAxOTk0KSwgZG8gxJHDsyBoaeG7h24gdGjhu7FjIHThuqFpIFZp4buHdCBOYW0gaGF5IGhp4buHbiDEkeG6oWkgY8OzIHRo4buDIGtow6FjLiBE4buvIGxp4buHdSBjxaluZyBraMO0bmcgY8OibiBi4bqxbmcgZ2nhu5tpIHTDrW5oIHbDoCBjaOG7p25nIHThu5ljIG7Dqm4gY8OzIHRo4buDIGdp4bubaSBo4bqhbiBraOG6oyBuxINuZyBraMOhaSBxdcOhdC4gTmdvw6BpIHJhLCBt4buZdCBz4buRIGjhuqFuZyBt4bulYyBjw7MgbeG6q3UgcuG6pXQgbmjhu48gKHbDrSBk4bulICdNYXJyaWVkLUFGLXNwb3VzZScgY2jhu4kgMjMgY8OhIHRo4buDKSBuw6puIGvhur90IHF14bqjIMaw4bubYyBsxrDhu6NuZyB0csOqbiBjw6FjIG5ow7NtIG7DoHkga8OpbSBjaOG6r2MgY2jhuq9uLg0KDQoNCi0gKirEkOG7gSB4deG6pXQg4bupbmcgZOG7pW5nOioqDQoNCigxKSBDaGnhur9uIGzGsOG7o2MgdGnhur9wIHRo4buLOiBE4buxYSB2w6BvIHBow6F0IGhp4buHbiBy4bqxbmcgbmjDs20gbmFtLCBr4bq/dCBow7RuLCBo4buNYyB24bqlbiBjYW8gY8OzIHRodSBuaOG6rXAgY2FvIGjGoW4sIGRvYW5oIG5naGnhu4dwIG7Dqm4gbmjhuq9tIMSR4bq/biBjw6FjIG5ow7NtIG7DoHkgY2hvIGPDoWMgc+G6o24gcGjhuqltIGNhbyBj4bqlcC4NCg0KKDIpIFBow6JuIGxv4bqhaSBraMOhY2ggaMOgbmc6IETDuW5nIGvhur90IHF14bqjIHBow6JuIHTDrWNoIMSR4buDIGzhuq1wIG3DtCBow6xuaCBwaMOibiBs4bubcCwgcGjDom4gY2hpYSBraMOhY2ggaMOgbmcgdGhlbyDEkeG6t2MgxJFp4buDbSB0aHUgbmjhuq1wLCBwaOG7pWMgduG7pSBjaG8gbWFya2V0aW5nIHbDoCBiw6FuIGjDoG5nIG3hu6VjIHRpw6p1LiBWw60gZOG7pTogbmjhuq9tIHF14bqjbmcgY8OhbyBz4bqjbiBwaOG6qW0gY2FvIGPhuqVwIGNobyBuaMOzbSDEkcOjIGvhur90IGjDtG4gdsOgIHRyw6xuaCDEkeG7mSBjYW8uDQoNCigzKSDEkGEgZOG6oW5nIGjDs2Egc+G6o24gcGjhuqltOiBQaMOhdCBoaeG7h24gc+G7sSDEkWEgZOG6oW5nIG5naOG7gSBuZ2hp4buHcCB2w6AgZ2nDoW8gZOG7pWMgY8WpbmcgZ+G7o2kgw70gZG9hbmggbmdoaeG7h3AgbsOqbiB4w6J5IGThu7FuZyBz4bqjbiBwaOG6qW0gxJFhIGThuqFuZyDEkeG7gyBwaMO5IGjhu6NwIHbhu5tpIHThu6tuZyBuaMOzbSAodsOtIGThu6Ugc+G6o24gcGjhuqltIHTDoGkgY2jDrW5oIGNobyBjaHV5w6puIGdpYSwgxJHDoG8gdOG6oW8ga+G7uSBuxINuZyBjaG8gbGFvIMSR4buZbmcgcGjhu5UgdGjDtG5nKS4NCg0KLSAqKkPDonUgaOG7j2kgbeG7nyAvIEjGsOG7m25nIG5naGnDqm4gY+G7qXUgdGnhur9wIHRoZW86KioNCg0KKDEpIFBow6JuIHTDrWNoIGNoaSB0aeG6v3QgdmFpIHRyw7IgY+G7p2EgY8OhYyBiaeG6v24gxJHhu4tuaCBsxrDhu6NuZyAodHXhu5VpLCBnaeG7nSBsw6BtKSBi4bqxbmcgaOG7k2kgcXV5IGxvZ2lzdGljIGhheSBo4buTaSBxdXkgdHV54bq/biB0w61uaCDEkeG7gyBk4buxIMSRb8OhbiB0aHUgbmjhuq1wLg0KDQooMikgS2nhu4NtIHRyYSBz4buxIGtow6FjIGJp4buHdCBnaeG7r2EgZG9hbmggbmdoaeG7h3AgVmnhu4d0IE5hbSBzbyB24bubaSBk4buvIGxp4buHdSBN4bu5OiBsaeG7h3UgbmjDom4ga2jhuql1IFZp4buHdCBjw7Mgbmjhu69uZyBraMOhYyBiaeG7h3QgdMawxqFuZyB04buxIGhheSBraMO0bmcuDQoNCigzKSBQaMOibiB0w61jaCBk4buvIGxp4buHdSBtdWEgaMOgbmcgKHbDrSBk4bulIGLhu5kgZOG7ryBsaeG7h3Ugc2nDqnUgdGjhu4sgY3VuZyBj4bqlcCkgxJHhu4MgeGVtIG3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgZ2nhu5tpIHTDrW5oLCBxdXnhu4FuIHPhu58gaOG7r3UgdMOgaSBz4bqjbiB2w6AgdGjDs2kgcXVlbiBtdWEgc+G6r20sIG3hu58gcuG7mW5nIHbDrSBk4bulIHbhu4EgT2RkcyBSYXRpbyBuaMawIMSRw6MgbsOzaSAodsOtIGThu6UsIHTDrW5oIE9SIGdp4buvYSBu4buvL25hbSB24bubaSBiaeG6v24gSG9tZW93bmVyIHRyb25nIGLhu5kgc2nDqnUgdGjhu4spIMSR4buDIGhp4buDdSByw7UgaMahbiBt4buRaSBsacOqbiBo4buHIHRyb25nIG5n4buvIGPhuqNuaCBraW5oIGRvYW5oLg0KDQoqKioNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj4NCg0KIyAqKi0tLSBOSEnhu4ZNIFbhu6QgVFXhuqZOIDItMyAtLS0qKiAgIA0KDQo8L2Rpdj4NCg0KKioqDQoNCioqTmhp4buHbSB24bulIHR14bqnbiAyOioqDQoNCjEuIFRo4buxYyBoaeG7h24gY8OhYyB5w6p1IGPhuqd1IHR14bqnbiAzIHRyb25nIMSRxrDhu51uZyBsaW5rIHNhdTogaHR0cHM6Ly9ycHVicy5jb20vdG10LzEzMTIzMDENCg0KKipOaGnhu4dtIHbhu6UgdHXhuqduIDM6KioNCg0KMS4gVGnhur9wIHThu6VjIGhvw6BuIHRow6BuaCBjw6FjIHnDqnUgY+G6p3UgY8OybiBzw7N0IHRyb25nIGPhu6dhIHR14bqnbiAyDQoyLiBUaOG7sWMgaGnhu4duIGPDoWMgecOqdSBj4bqndSB0deG6p24gMyB0cm9uZyDEkcaw4budbmcgbGluayBzYXU6IGh0dHBzOi8vcnB1YnMuY29tL3RtdC8xMzE1Nzg4DQoNCioqKg0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+DQoNCiMgKipC4buZIGThu68gbGnhu4d1ICJTdXBlcm1hcmtldCBUcmFuc2FjdGlvbnMiKiogICANCg0KPC9kaXY+DQoNCioqKg0KDQojICoqUEjhuqZOIDEuIFThu5VuZyBxdWFuIHbhu4EgYuG7mSBk4buvIGxp4buHdSoqDQoNCioqKg0KDQrEkOG6p3UgdGnDqm4sIHRhIMSR4buNYyBk4buvIGxp4buHdSB2w6Aga2nhu4NtIHRyYSBj4bqldSB0csO6YyBjaHVuZyBj4bunYSBi4buZIGThu68gbGnhu4d1LiANCg0KDQpgYGB7cn0NCmRmIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9IUC9Eb3dubG9hZHMvU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zLmNzdiIsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCg0KIyBLaeG7g20gdHJhIGPhuqV1IHRyw7pjIGThu68gbGnhu4d1IHbDoCBt4buZdCBz4buRIGTDsm5nIMSR4bqndQ0Kc3RyKGRmKQ0KaGVhZChkZikNCnRhaWwoZGYpDQpgYGANCg0KS+G6v3QgcXXhuqMgc3RyKGRmKSBjaG8gYmnhur90IGLhu5kgZOG7ryBsaeG7h3UgY8OzIDE0MDU5IGLhuqNuIGdoaSB2w6AgMTYgYmnhur9uLiBDw6FjIGJp4bq/biBuaMawIEdlbmRlciwgTWFyaXRhbFN0YXR1cywgSG9tZW93bmVyLCBDaGlsZHJlbiwgQW5udWFsSW5jb21lLCBDaXR5LCBTdGF0ZW9yUHJvdmluY2UsIENvdW50cnksIFByb2R1Y3RGYW1pbHksIFByb2R1Y3REZXBhcnRtZW50LCBQcm9kdWN0Q2F0ZWdvcnkgbMOgIMSR4buLbmggdMOtbmggKGtp4buDdSBjaHXhu5dpKS4gQmnhur9uIFVuaXRzU29sZCB2w6AgUmV2ZW51ZSBsw6AgxJHhu4tuaCBsxrDhu6NuZy4NCg0KROG7ryBsaeG7h3UgY2jhu6lhIGPDoWMgZ2lhbyBk4buLY2ggbXVhIGjDoG5nIHThuqFpIHNpw6p1IHRo4buLIHRoZW8gdOG7q25nIMSRxqFuIChi4bqjbmcpLiBT4buRIGTDsm5nIHbDoCBz4buRIGPhu5l0IHRo4buDIGhp4buHbiBxdXkgbcO0IHbDoCBz4buRIGJp4bq/biBxdWFuIHPDoXQuDQpTYXUga2hpIGxv4bqhaSBi4buPIGPhu5l0IGNo4buJIG3hu6VjIHRo4burYSwgdGEga2nhu4NtIHRyYSBj4bqldSB0csO6Yy4gROG7ryBsaeG7h3UgY8OzIMSR4buLbmggZOG6oW5nIG5nw6B5IHRow6FuZyBjaG8gY+G7mXQgUHVyY2hhc2VEYXRlIHThu6sgY3Xhu5FpIG7Eg20gMjAwNyDEkeG6v24gY3Xhu5FpIG7Eg20gMjAwOSwgY2hvIHRo4bqleSBwaOG6oW0gdmkgZ+G6p24gMiBuxINtLg0KVmnhu4djIGNodXnhu4NuIMSR4buLbmggZOG6oW5nIHbhu4EgRGF0ZSBjaG8gcGjDqXAgcGjDom4gdMOtY2ggeHUgaMaw4bubbmcgdGhlbyB0aOG7nWkgZ2lhbi4NCg0KU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zIGzDoCBt4buZdCBi4buZIGThu68gbGnhu4d1IGJhbyBn4buTbSAxNDA1OSBxdWFuIHPDoXQgdsOgIDE2IGJp4bq/biwgY+G7pSB0aOG7gyBsw6AgY8OhYyBiaeG6v246DQoNCigxKSBT4buRIHRo4bupIHThu7ENCg0KKDIpIFB1cmNoYXNlIERhdGU6IE5nw6B5IG11YSBow6BuZw0KDQooMykgQ3VzdG9tZXIgSUQ6IElEIGPhu6dhIGtow6FjaCBow6BuZw0KDQooNCkgR2VuZGVyOiBHaeG7m2kgdMOtbmgsIHbhu5tpIEYgKEZlbWFsZSkgbMOgIG7hu68gdsOgIE0gKE1hbGUpIGzDoCBuYW0NCg0KKDUpIE1hcml0YWwgU3RhdHVzOiBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4sIHbhu5tpIFMgKFNpbmdsZSkgbMOgIMSR4buZYyB0aMOibiB2w6AgTShNYXJyaWVkKSBsw6AgxJHDoyBr4bq/dCBow7RuDQoNCig2KSBIb21lb3duZXI6IMSQw6MgY8OzIG5ow6AgaGF5IGNoxrBhLCB24bubaSBZIChZZXMpIGzDoCDEkcOjIGPDsyBuaMOgIHbDoCBOIChObykgbMOgIGNoxrBhIGPDsyBuaMOgDQoNCig3KSBDaGlsZHJlbjogU+G7kSBjb24gY8OhaQ0KDQooOCkgQW5udWFsIEluY29tZTogVGh1IG5o4bqtcCBow6BuZyBuxINtICjEkcaw4bujYyBiaeG7g3UgdGjhu4sgZMaw4bubaSBk4bqhbmcgY8OhYyBraG/huqNuZykNCg0KKDkpIENpdHk6IFRow6BuaCBwaOG7kSDEkWFuZyBz4buRbmcNCg0KKDEwKSBTdGF0ZW9yIFByb3ZpbmNlOiBNw6Mga8OtIGhp4buHdSBj4bunYSBiYW5nDQoNCigxMSkgQ291bnRyeTogxJDhuqV0IG7GsOG7m2MNCg0KKDEyKSBQcm9kdWN0IEZhbWlseTogTmjDs20gc+G6o24gcGjhuqltLCBGb29kOiBUaOG7sWMgcGjhuqltLCBEcmluazogxJDhu5MgdeG7kW5nIHbDoCBOb24tQ29uc3VtYWJsZTogSMOgbmcga2jDtG5nIHRpw6p1IGTDuW5nDQoNCigxMykgUHJvZHVjdCBEZXBhcnRtZW50OiBOaMOzbSBz4bqjbiBwaOG6qW0gY2hpIHRp4bq/dA0KDQooMTQpIFByb2R1Y3QgQ2F0ZWdvcnk6IERhbmggbeG7pWMgc+G6o24gcGjhuqltDQoNCigxNSkgVW5pdHMgU29sZDogRG9hbmggc+G7kSBiw6FuIGjDoG5nIHRoZW8gxJHGoW4gduG7iw0KDQooMTYpIFJldmVudWU6IERvYW5oIHRodQ0KDQpUYSBjxaluZyBraeG7g20gdHJhIHhlbSBjw7MgZ2nDoSB0cuG7iyB0aGnhur91IChOQSkgbsOgbyBraMO0bmcuDQoNCmBgYHtyfQ0KIyBLaeG7g20gdHJhIGThu68gbGnhu4d1IHRoaeG6v3UNCnN1bShpcy5uYShkZikpDQpjb2xTdW1zKGlzLm5hKGRmKSkNCmBgYA0KDQpL4bq/dCBxdeG6oyBzdW0oaXMubmEoZGYpKSBjaG8gdGjhuqV5IGtow7RuZyBjw7MgZ2nDoSB0cuG7iyB0aGnhur91IHRyb25nIGThu68gbGnhu4d1ICh04buVbmcgY8OhYyBnacOhIHRy4buLIE5BIGLhurFuZyAwKS4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgZOG7ryBsaeG7h3UgxJHDoyDEkcaw4bujYyB0aHUgdGjhuq1wIMSR4bqneSDEkeG7pyB2w6Aga2jDtG5nIGPhuqduIHjhu60gbMO9IGThu68gbGnhu4d1IHRoaeG6v3UgdGjDqm0uDQoNClRp4bq/cCB0aGVvLCB0YSBjaHV54buDbiBjw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oIHbhu4EgZOG6oW5nIGZhY3RvciB2w6AgxJHhurd0IG5ow6NuIHRp4bq/bmcgVmnhu4d0IGNobyBt4buZdCBz4buRIGJp4bq/biBjaG8gZOG7hSBoaeG7g3UuDQoNCmBgYHtyfQ0KIyBDaHV54buDbiBzYW5nIGZhY3RvciB2w6AgZ8OhbiBuaMOjbiB0aeG6v25nIFZp4buHdA0KZGYgPC0gZGYgJT4lDQogIG11dGF0ZSgNCiAgICBHZW5kZXIgICAgICAgICA9IGZhY3RvcihHZW5kZXIsIGxldmVscyA9IGMoIk0iLCJGIiksIGxhYmVscyA9IGMoIk5hbSIsIk7hu68iKSksDQogICAgTWFyaXRhbFN0YXR1cyAgPSBmYWN0b3IoTWFyaXRhbFN0YXR1cywgbGV2ZWxzID0gYygiUyIsIk0iKSwgbGFiZWxzID0gYygixJDhu5ljIHRow6JuIiwixJDDoyBr4bq/dCBow7RuIikpLA0KICAgIEhvbWVvd25lciAgICAgID0gZmFjdG9yKEhvbWVvd25lciwgbGV2ZWxzID0gYygiWSIsIk4iKSwgbGFiZWxzID0gYygiQ8OzIiwiS2jDtG5nIikpLA0KICAgIEFubnVhbEluY29tZSAgID0gZmFjdG9yKEFubnVhbEluY29tZSwgb3JkZXJlZCA9IFRSVUUpLA0KICAgIENpdHkgICAgICAgICAgID0gZmFjdG9yKENpdHkpLA0KICAgIFN0YXRlb3JQcm92aW5jZT0gZmFjdG9yKFN0YXRlb3JQcm92aW5jZSksDQogICAgQ291bnRyeSAgICAgICAgPSBmYWN0b3IoQ291bnRyeSksDQogICAgUHJvZHVjdEZhbWlseSAgICAgID0gZmFjdG9yKFByb2R1Y3RGYW1pbHksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJGb29kIiwiRHJpbmsiLCJOb24tQ29uc3VtYWJsZSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiVGjhu7FjIHBo4bqpbSIsIsSQ4buTIHXhu5FuZyIsIlBoaSB0acOqdSBkw7luZyIpKSwNCiAgICBQcm9kdWN0RGVwYXJ0bWVudCAgPSBmYWN0b3IoUHJvZHVjdERlcGFydG1lbnQpLA0KICAgIFByb2R1Y3RDYXRlZ29yeSAgICA9IGZhY3RvcihQcm9kdWN0Q2F0ZWdvcnkpDQogICkNCnN0cihkZikNCg0KYGBgDQoNClNhdSBraGkgY2h1eeG7g24gxJHhu5VpLCBjw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oIMSRw6Mg4bufIGThuqFuZyBmYWN0b3IuIFbDrSBk4bulLCBHZW5kZXIgdsOgIE1hcml0YWxTdGF0dXMgxJHDoyBjw7MgbmjDo24gdGnhur9uZyBWaeG7h3QgbMOgICJOYW0vTuG7ryIgdsOgICLEkOG7mWMgdGjDom4vxJDDoyBr4bq/dCBow7RuIiDEkeG7gyBk4buFIGhp4buDdSBoxqFuLiBWaeG7h2MgbsOgeSBnacO6cCBjaG8gdmnhu4djIHRo4buRbmcga8OqIHbDoCB24bq9IGJp4buDdSDEkeG7kyB0aHXhuq1uIHRp4buHbiwgxJHhu5NuZyB0aOG7nWkgdOG6oW8gxJFp4buBdSBraeG7h24gdGh14bqtbiBs4bujaSBraGkgcGjDom4gdMOtY2gga+G6v3QgcXXhuqMgdHJvbmcgYuG7kWkgY+G6o25oIHRo4buLIHRyxrDhu51uZyBWaeG7h3QgTmFtLg0KDQoqKioNCg0KIyAqKlBI4bqmTiAyLiBQaMOibiB0w61jaCBNw7QgdOG6oyBN4buZdCBiaeG6v24gxJDhu4tuaCB0w61uaCAoVW5pdmFyaWF0ZSBEZXNjcmlwdGl2ZSBBbmFseXNpcynigJ0qKg0KDQoqKioNCg0KQ2jDum5nIHRhIHPhur0gbOG6p24gbMaw4bujdCBwaMOibiB0w61jaCB04burbmcgYmnhur9uOiBHZW5kZXIsIE1hcml0YWxTdGF0dXMsIEhvbWVvd25lciwgQW5udWFsSW5jb21lLCBDb3VudHJ5LCBQcm9kdWN0RmFtaWx5LCBQcm9kdWN0RGVwYXJ0bWVudCwgUHJvZHVjdENhdGVnb3J5Lg0KDQojIyAqKjIuMS4gR2VuZGVyIChHaeG7m2kgdMOtbmgpKioNCg0KYGBge3J9DQoNCnRibF9nZW5kZXIgPC0gZGYgJT4lIGNvdW50KEdlbmRlcikgJT4lIG11dGF0ZShQZXJjZW50ID0gbiAvIHN1bShuKSAqIDEwMCkNCmthYmxlKHRibF9nZW5kZXIsIGNhcHRpb24gPSAiVOG6p24gc3XhuqV0IHbDoCAlIHRoZW8gR2nhu5tpIHTDrW5oIikNCg0KYGBgDQoNClThu5VuZyBz4buRIGdpYW8gZOG7i2NoOiAxNDA1OS4NCg0KTuG7ryBjaGnhur9tIH41MS4wJSwgTmFtIGNoaeG6v20gfjQ5LjAlLg0KDQpT4buxIGNow6puaCBs4buHY2gga2jDtG5nIHF1w6EgbOG7m24sIG5oxrBuZyBwaOG7pSBu4buvIG5o4buJbmggaMahbiBt4buZdCBjaMO6dCAoPikuDQoNClRo4buxYyB04bq/IHThuqFpIFZp4buHdCBOYW0sIHBo4bulIG7hu68gdGjGsOG7nW5nIMSR4bqjbSBuaGnhu4dtIHZp4buHYyBtdWEgc+G6r20gxJHhu5MgZ2lhIGThu6VuZywgdGjhu7FjIHBo4bqpbSzigKYgbsOqbiBr4bq/dCBxdeG6oyBuw6B5IGPDsyB0w61uaCB0xrDGoW5nIMSR4buTbmcgduG7m2kgbmdoacOqbiBj4bupdSB24buBIGjDoG5oIHZpIHRpw6p1IGTDuW5nIGdpYSDEkcOsbmguDQoNCmBgYHtyfQ0KZ2dwbG90KHRibF9nZW5kZXIsIGFlcyh4ID0gR2VuZGVyLCB5ID0gbiwgZmlsbCA9IEdlbmRlcikpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygibGlnaHRibHVlIiwicGluayIpKSArDQogIGxhYnModGl0bGUgPSAiU+G7kSBsxrDhu6NuZyBnaWFvIGThu4tjaCB0aGVvIEdp4bubaSB0w61uaCIsDQogICAgICAgeCA9ICJHaeG7m2kgdMOtbmgiLCB5ID0gIlPhu5EgZ2lhbyBk4buLY2giKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkJp4buDdSDEkeG7kyBj4buZdCByw7UgbsOpdCwgZOG7hSBuaOG6rW4gYmnhur90IGNow6puaCBs4buHY2ggbmjhurkgZ2nhu69hIE5hbSB2w6AgTuG7ry4NCg0KUGjDom4gcGjhu5FpIGNobyB0aOG6pXkgZ+G6p24gY8OibiBi4bqxbmcgZ2nhu69hIE5hbSAoNDklKSB2w6AgTuG7ryAoNTElKSwga2jDtG5nIGNow6puaCBs4buHY2ggbmhp4buBdS4gxJBp4buBdSBuw6B5IHBow7kgaOG7o3AgduG7m2kgbmjhuq1uIMSR4buLbmggcuG6sW5nIGPhuqMgaGFpIGdp4bubaSDEkeG7gXUgdGjGsOG7nW5nIHh1ecOqbiDEkWkgc2nDqnUgdGjhu4sgxJHhu4MgbXVhIGjDoG5nIHRpw6p1IGTDuW5nLg0KDQpCaeG7g3UgxJHhu5MgY+G7mXQgbWluaCBo4buNYSB04buJIGzhu4cgYuG6sW5nIG5oYXUgZ2nhu69hIGhhaSBuaMOzbSBnaeG7m2kgdMOtbmguIFThu7cgbOG7hyB0xrDGoW5nIMSRxrDGoW5nIGNobyB0aOG6pXkgY+G6oyBuYW0gdsOgIG7hu68gxJHhu4F1IHRoYW0gZ2lhIG11YSBz4bqvbSB04bqhaSBzacOqdSB0aOG7iywgduG7m2kgbeG7mXQgY2jDunQgbmdoacOqbmcgduG7gSBwaMOtYSBu4buvIHRoxrDhu51uZyB4dXnDqm4gaMahbiDEkcO0aSBjaMO6dC4NCg0KVHJvbmcgbmfhu68gY+G6o25oIHRpw6p1IGTDuW5nLCB0aMaw4budbmcgbuG7ryBjaGnhur9tIHZhaSB0csOyIGNhbyB0cm9uZyB2aeG7h2MgxJFpIGNo4bujL27huqV1IMSDbiwgbsOqbiB04buJIGzhu4cgbuG7ryBjYW8gaMahbiBt4buZdCBjaMO6dCBjw7MgdGjhu4MgbMOgIGRvIHBo4bulIG7hu68gbXVhIG5oaeG7gXUgc+G6o24gcGjhuqltIHRoaeG6v3QgeeG6v3UgKG5oxrAgc+G7r2EsIHJhdSBj4bunKQ0KVGhlbyBuZ3V5w6puIHThuq9jIHRy4buxYyBxdWFuIGjDs2EgKFR1ZnRlLCAxOTgzKSwgdGEgZ2nhu68gxJHGoW4gZ2nhuqNuLCBraMO0bmcgZMO5bmcgcGllIGNoYXJ0IMSR4buDIHRyw6FuaCBraMOzIHNvIHPDoW5oIGfDs2MuDQoNCiMjICoqMi4yLiBNYXJpdGFsU3RhdHVzIChUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4pKioNCg0KYGBge3J9DQp0YmxfbWFyaXRhbCA8LSBkZiAlPiUgY291bnQoTWFyaXRhbFN0YXR1cykgJT4lIG11dGF0ZShQZXJjZW50ID0gbiAvIHN1bShuKSAqIDEwMCkNCmthYmxlKHRibF9tYXJpdGFsLCBjYXB0aW9uID0gIlThuqduIHN14bqldCB2w6AgJSB0aGVvIFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiIpDQpgYGANCg0KxJDhu5ljIHRow6JuOiB+NTEuMiUsIMSQw6Mga+G6v3QgaMO0bjogfjQ4LjglLg0KDQpOaMOzbSDEkOG7mWMgdGjDom4gbmjhu4luaCBoxqFuLCBjw7MgdGjhu4MgZG8gbeG6q3UgdOG6rXAgdHJ1bmcgbmhp4buBdSBraMOhY2ggaMOgbmcgdHLhurssIGNoxrBhIGzhuq1wIGdpYSDEkcOsbmguDQoNCmBgYHtyfQ0KZ2dwbG90KHRibF9tYXJpdGFsLCBhZXMoeCA9IE1hcml0YWxTdGF0dXMsIHkgPSBuLCBmaWxsID0gTWFyaXRhbFN0YXR1cykpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Yygib3JhbmdlIiwic2t5Ymx1ZSIpKSArDQogIGxhYnModGl0bGUgPSAiU+G7kSBsxrDhu6NuZyBnaWFvIGThu4tjaCB0aGVvIFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiIsDQogICAgICAgeCA9ICJUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4iLCB5ID0gIlPhu5EgZ2lhbyBk4buLY2giKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KSGFpIGPhu5l0IHTGsMahbmcgxJHGsMahbmcsIGtob+G6o25nIGNow6puaCB+Mi40JS4NCg0KU+G7kSBsxrDhu6NuZyBnaWFvIGThu4tjaCBj4bunYSBraMOhY2ggaMOgbmcgxJHhu5ljIHRow6JuIChTaW5nbGUsIDUxJSkgdsOgIGPDsyBnaWEgxJHDrG5oIChNYXJyaWVkLCA0OSUpIGfhuqduIG5oxrAgY8OibiBi4bqxbmcuDQoNCkJp4buDdSDEkeG7kyBjaG8gdGjhuqV5IGfhuqduIGLhurFuZywgaMahaSBuZ2hpw6puZyB24buBIMSR4buZYyB0aMOibi4gxJBp4buBdSBuw6B5IGPDsyB0aOG7gyBkbyBk4buvIGxp4buHdSBjw7Mgbmhp4buBdSBraMOhY2ggaMOgbmcgdOG7qyB0aMOgbmggcGjhu5EgbOG7m24gKG5oxrAgTG9zIEFuZ2VsZXMsIFNlYXR0bGUpIG7GoWkgbmfGsOG7nWkgxJHhu5ljIHRow6JuIHNpbmggc+G7kW5nIMSRw7RuZy4NCg0KTeG7qWMgxJHhu5kgdGnDqnUgZMO5bmcga2jDtG5nIGtow6FjIGJp4buHdCByw7UgcuG7h3QgZ2nhu69hIGhhaSBuaMOzbSwgxJFp4buBdSBuw6B5IGjhu6NwIGzDvSB2w6wgZMO5IMSR4buZYyB0aMOibiBoYXkgY8OzIGdpYSDEkcOsbmgsIG3hu41pIG5nxrDhu51pIMSR4buBdSB0acOqdSBkw7luZyBow6BuZyB0acOqdSBkw7luZyB0aGnhur90IHnhur91LiBO4bq/dSBjw7Mga2jDoWMgYmnhu4d0IG5o4bq5LCBuaOG7r25nIGdpYSDEkcOsbmggY8OzIHRo4buDIG11YSBuaGnhu4F1IGjDoG5nIGjGoW4gY2hvIGNvbiBjw6FpLCBuaMawbmcgc+G7kSBsxrDhu6NuZyBnaWFvIGThu4tjaCBjaG8gdGjhuqV5IGjhuqd1IG5oxrAgYuG6sW5nIG5oYXUuDQoNCiMjICoqMi4zLiBIb21lb3duZXIgKEPDsyBuaMOgIHJpw6puZykqKg0KDQpgYGB7cn0NCnRibF9vd25lciA8LSBkZiAlPiUgY291bnQoSG9tZW93bmVyKSAlPiUgbXV0YXRlKFBlcmNlbnQgPSBuIC8gc3VtKG4pICogMTAwKQ0Ka2FibGUodGJsX293bmVyLCBjYXB0aW9uID0gIlThuqduIHN14bqldCB2w6AgJSB0aGVvIFPhu58gaOG7r3UgbmjDoCIpDQpgYGANCg0KQ8OzIG5ow6A6IH42MC4xJSwgS2jDtG5nOiB+MzkuOSUuDQoNClBo4bqnbiBs4bubbiBraMOhY2ggaMOgbmcgdHJvbmcgbeG6q3UgbMOgIGNo4bunIG5ow6AsIGNobyB0aOG6pXkgdGh1IG5o4bqtcC/hu5VuIMSR4buLbmggdMOgaSBjaMOtbmggdMawxqFuZyDEkeG7kWkgY2FvLg0KDQpgYGB7cn0NCg0KZ2dwbG90KHRibF9vd25lciwgYWVzKHggPSBIb21lb3duZXIsIHkgPSBQZXJjZW50LCBmaWxsID0gSG9tZW93bmVyKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdChzY2FsZSA9IDEpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmVlbiIsImdyYXkiKSkgKw0KICBsYWJzKHRpdGxlID0gIlThu4kgbOG7hyAoJSkga2jDoWNoIGjDoG5nIGPDsyBuaMOgIHJpw6puZyIsDQogICAgICAgeCA9ICJDw7MgbmjDoCByacOqbmciLCB5ID0gIlThu4kgbOG7hyAoJSkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KRMO5bmcgJSDEkeG7gyBk4buFIHNvIHPDoW5oIHTGsMahbmcgcXVhbi4NCg0KS2hv4bqjbmcgNjAlIGdpYW8gZOG7i2NoIGLhu59pIGtow6FjaCBsw6AgY2jhu6cgc+G7nyBo4buvdSBuaMOgIChZZXMpLCA0MCUgbMOgIG5nxrDhu51pIHRodcOqIGhv4bq3YyBraMO0bmcgc+G7nyBo4buvdSAoTm8pLg0KDQrEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBuaGnhu4F1IGtow6FjaCBow6BuZyBjw7MgbmjDoCByacOqbmcsIGPDsyB0aOG7gyBsw6AgZ2lhIMSRw6xuaCBob+G6t2MgbmfGsOG7nWkgdHLGsOG7n25nIHRow6BuaCBjw7MgdGh1IG5o4bqtcCDhu5VuIMSR4buLbmguDQoNClRo4buxYyB04bq/LCBjaOG7pyBuaMOgIHRoxrDhu51uZyB0aHXhu5ljIG5ow7NtIHRodSBuaOG6rXAgdHJ1bmcgYsOsbmgtY2FvIGjGoW4gKHbDrCBraOG6oyBuxINuZyB0cuG6oyBnw7NwL211YSBuaMOgKSBuw6puIGjhu40gY8OzIHh1IGjGsOG7m25nIHRpw6p1IGTDuW5nIOG7lW4gxJHhu4tuaCBoxqFuLiBU4buJIGzhu4cgY2FvIGNobyB0aOG6pXkgdOG6rXAgZOG7ryBsaeG7h3Uga2jDoSBuaGnhu4F1IGdpYSDEkcOsbmggaG/hurdjIG5nxrDhu51pIHRyxrDhu59uZyB0aMOgbmgg4buVbiDEkeG7i25oIChjw7MgdGjhu4Mgc28gduG7m2kgbmjDs20gc2luaCB2acOqbiwgbmfGsOG7nWkgdHLhursgdGh1w6ogbmjDoCB0aMOsIHRo4bqlcCBoxqFuKS4NCg0KIyMgKioyLjQuIEFubnVhbEluY29tZSAoVGh1IG5o4bqtcCBow6BuZyBuxINtKSoqDQoNCmBgYHtyfQ0KdGJsX2luY29tZSA8LSBkZiAlPiUgY291bnQoQW5udWFsSW5jb21lKSAlPiUgbXV0YXRlKFBlcmNlbnQgPSBuIC8gc3VtKG4pICogMTAwKQ0Ka2FibGUodGJsX2luY29tZSwgY2FwdGlvbiA9ICJU4bqnbiBzdeG6pXQgdsOgICUgdGhlbyBUaHUgbmjhuq1wIGjDoG5nIG7Eg20iKQ0KDQpgYGANCg0KQ8OhYyBraG/huqNuZyB0aHUgbmjhuq1wIHThuq1wIHRydW5nIOG7nyBt4bupYyB0cnVuZyBiw6xuaOKAk2NhbyAoNjDigJM4MEssIDgw4oCTMTIwSykuDQoNCk3DtCBow6xuaCBwaMOibiBwaOG7kWkga2jDoSDigJxjaOG7h2NoIHBo4bqjaeKAnSAocmlnaHQtc2tld2VkKSwgZ+G7o2kgw70ga2jDoWNoIGjDoG5nIGPDsyB0aHUgbmjhuq1wIHTGsMahbmcgxJHhu5FpIHThu5F0Lg0KDQpgYGB7cn0NCmdncGxvdCh0YmxfaW5jb21lLCBhZXMoeCA9IEFubnVhbEluY29tZSwgeSA9IG4pKSArDQogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKw0KICBsYWJzKHRpdGxlID0gIlPhu5EgZ2lhbyBk4buLY2ggdGhlbyBUaHUgbmjhuq1wIGjDoG5nIG7Eg20iLA0KICAgICAgIHggPSAiS2hv4bqjbmcgdGh1IG5o4bqtcCAobmdow6xuIFVTRCkiLCB5ID0gIlPhu5EgZ2lhbyBk4buLY2giKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQoNCmBgYA0KDQpDw6FjIGPhu5l0IHTEg25nIGThuqduIHRoZW8gdGh1IG5o4bqtcCwgxJHhuqF0IMSR4buJbmgg4bufIDgw4oCTMTIwSy4NCg0KUGjhuqduIGzhu5tuIGtow6FjaCBow6BuZyB0aHXhu5ljIG5ow7NtIHRodSBuaOG6rXAgdHJ1bmcgYsOsbmgtdGjhuqVwOiBn4bqnbiA0NiUgdHJvbmcga2hv4bqjbmcgJDMwSy0kNTBLIHbDoCAyMiUgdHJvbmcgJDEwSy0kMzBLLiBDw6FjIG5ow7NtIHRodSBuaOG6rXAgY2FvICh0csOqbiAkMTEwSykgY2jhu4kgY2hp4bq/bSB04buVbmcga2hv4bqjbmcgMTAlLg0KDQrEkGnhu4F1IG7DoHkgcGjDuSBo4bujcCB24bubaSB0aOG7sWMgdOG6vyBy4bqxbmcgaOG6p3UgaOG6v3QgbmfGsOG7nWkgdGnDqnUgZMO5bmcgxJFpIHNpw6p1IHRo4buLIHRodeG7mWMgY8OhYyBnaWEgxJHDrG5oIGPDsyB0aHUgbmjhuq1wIGtow7RuZyBxdcOhIGNhbyAoxJFhIHBo4bqnbiBjaGkgdGnDqnUgY2hvIHRo4buxYyBwaOG6qW0gY2hp4bq/bSB04bu3IGzhu4cgxJHDoW5nIGvhu4MgdGh1IG5o4bqtcCkgLiANCkPFqW5nIGPDsyB0aOG7gyBkbyBraHUgduG7sWMgbmdoacOqbiBj4bupdSAobWnhu4FuIHTDonkgTeG7uSB2w6AgTWV4aWNvKSwgdGh1IG5o4bqtcCBiw6xuaCBxdcOibiBraMO0bmcgcXXDoSBjYW8uDQoNCk5ow7NtIHRodSBuaOG6rXAgY8OgbmcgY2FvICg+ICQ5MEspIHRow6wgc+G7kSBnaWFvIGThu4tjaCBnaeG6o20gZOG6p247IHR1eSBuaGnDqm4gbmjDs20gJDkwSy0kMTEwSyB24bqrbiBtdWEgc+G6r20ga2jDoSDEkeG7gXUuIEPDsyB0aOG7gyBsw70gZ2nhuqNpIHLhurFuZyBuZ8aw4budaSB0aHUgbmjhuq1wIGNhbyBjw7MgbOG7kWkgc+G7kW5nIGLhuq1uIHLhu5luIGhv4bq3YyBtdWEgc+G6r20gdOG6oWkgY8OhYyBj4butYSBow6BuZyBraMOhYyAoY2FvIGPhuqVwIGhv4bq3YyBvbmxpbmUpLCBuw6puIMOtdCDEkeG6oWkgZGnhu4duIHRyb25nIHThuq1wIHNpw6p1IHRo4buLIG7DoHkuDQoNClRyb25nIHRo4buxYyB04bq/IFZp4buHdCBOYW0sIG7hur91IHF1eSDEkeG7lWkgdMawxqFuZyDEkcawxqFuZywgbmjDs20ga2jDoWNoIGjDoG5nIHRodSBuaOG6rXAgdHJ1bmcgYsOsbmjigJNjYW8gdGjGsOG7nW5nIG11YSBz4bqvbSDhu58gc2nDqnUgdGjhu4sgaMahbiBzbyB24bubaSB0aHUgbmjhuq1wIHF1w6EgdGjhuqVwIGhv4bq3YyBxdcOhIGNhbyAodGjDrWNoIG11YSBow6BuZyB4w6FjaCB0YXksIG5o4bqtcCBraOG6qXUpLg0KDQoNCiMjICoqMi41LiBDb3VudHJ5IChRdeG7kWMgZ2lhKSoqDQoNCmBgYHtyfQ0KdGJsX2N0cnkgPC0gZGYgJT4lIGNvdW50KENvdW50cnkpICU+JSBtdXRhdGUoUGVyY2VudCA9IG4gLyBzdW0obikgKiAxMDApDQprYWJsZSh0YmxfY3RyeSwgY2FwdGlvbiA9ICJU4bqnbiBzdeG6pXQgdsOgICUgdGhlbyBRdeG7kWMgZ2lhIikNCg0KYGBgDQoNCkThu68gbGnhu4d1IGNo4bunIHnhur91IHThu6sgTeG7uSAofjY4JSksIENhbmFkYSAofjUsOCUpLCBNZXhpY28gKH4yNiwyJSkuDQoNCkThu68gbGnhu4d1IGdoaSBuaOG6rW4ga2jDoWNoIGjDoG5nIMSR4bq/biB04burIDMgcXXhu5FjIGdpYSBjaMOtbmg6IFVTQSBjaGnhur9tIDY4LjAlLCB0aeG6v3AgdGhlbyBsw6AgTWV4aWNvICgyNi4yJSkgdsOgIENhbmFkYSAoNS44JSkuIELhuqNuZyBjaG8gdGjhuqV5IMSRYSBz4buRIGtow6FjaCBow6BuZyBsw6AgbmfGsOG7nWkgTeG7uS4gVHJvbmcgbmfhu68gY+G6o25oIFZp4buHdCBOYW0sIGTDuSBk4buvIGxp4buHdSBn4buRYyBraMO0bmcgcGjhuqNuIMOhbmgga2jDoWNoIGjDoG5nIFZp4buHdCwgbmjGsG5nIGNow7puZyB0YSBjw7MgdGjhu4MgbGnDqm4gdMaw4bufbmcgcuG6sW5nIHBo4bqnbiBs4bubbiBkb2FuaCB0aHUgxJHhur9uIHThu6sgdGjhu4sgdHLGsOG7nW5nIG3hu6VjIHRpw6p1IGNow61uaCAo4bufIFZp4buHdCBOYW0gY8OzIHRo4buDIGzDoCBUUC5IQ00gaGF5IEjDoCBO4buZaSkuIFPhu7EgcGjDom4gYuG7kSBuaMawIHRyw6puIGfhu6NpIMO9IHLhurFuZyBkb2FuaCBuZ2hp4buHcCB04bqtcCB0cnVuZyB2w6BvIHRo4buLIHRyxrDhu51uZyBjaOG7pyBs4buxYywgdMawxqFuZyDEkcawxqFuZyB2aeG7h2MgeMOhYyDEkeG7i25oIGtodSB24buxYyBiw6FuIGjDoG5nIHF1YW4gdHLhu41uZyB04bqhaSBWaeG7h3QgTmFtLg0KDQrEkOG7gyBsacOqbiBo4buHIFZp4buHdCBOYW0sIGPDsyB0aOG7gyB0xrDhu59uZyB0xrDhu6NuZyBr4buLY2ggYuG6o24gdGhheSB0aOG6vyBi4bqxbmcgMyB0aMOgbmggcGjhu5EgbOG7m24gbmjGsCBUUC5IQ00sIEjDoCBO4buZaSwgxJDDoCBO4bq1bmcuDQoNCmBgYHtyfQ0KZ2dwbG90KHRibF9jdHJ5LCBhZXMoeCA9IENvdW50cnksIHkgPSBQZXJjZW50LCBmaWxsID0gQ291bnRyeSkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoc2NhbGUgPSAxKSkgKw0KICBsYWJzKHRpdGxlID0gIlThu4kgbOG7hyAoJSkgZ2lhbyBk4buLY2ggdGhlbyBRdeG7kWMgZ2lhIiwNCiAgICAgICB4ID0gIlF14buRYyBnaWEiLCB5ID0gIlThu4kgbOG7hyAoJSkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KQmnhu4N1IMSR4buTIGNobyB0aOG6pXkgY+G7mXQgVVNBIGNoaeG6v20gxrB1IHRo4bq/IHNvIHbhu5tpIGhhaSBuxrDhu5tjIGPDsm4gbOG6oWkuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IHBo4bqnbiBs4bubbiBk4buvIGxp4buHdSDEkeG6v24gdOG7qyB0aOG7iyB0csaw4budbmcgTeG7uSwgdsOsIHRo4bq/IGtoaSDDoXAgZOG7pW5nIGNobyBWaeG7h3QgTmFtLCBjaMO6bmcgdGEgY+G6p24gdGjhuq1uIHRy4buNbmcgdsOsIGLhu5FpIGPhuqNuaCBraW5oIHThur8gLSB2xINuIGjDs2Ega2jDoWMgYmnhu4d0LiBUdXkgbmhpw6puLCBkb2FuaCBuZ2hp4buHcCBjw7MgdGjhu4MgdGjhuqV5IHThuqdtIHF1YW4gdHLhu41uZyBj4bunYSB0aOG7iyB0csaw4budbmcgY2jhu6cgbOG7sWMgKGdp4buRbmcgbmjGsCDhu58gVmnhu4d0IE5hbSwgVFAuSENNIGhheSBIw6AgTuG7mWkgY8OzIHRo4buDIGNoaeG6v20gcGjhuqduIGzhu5tuIGRvYW5oIHPhu5EpLg0KDQpgYGB7cn0NCiMgVGjhu5FuZyBrw6ogbmhhbmggVGnhu4N1IGJhbmcgKFN0YXRlKSB2w6AgVGjDoG5oIHBo4buRIChDaXR5KQ0KdG9wX3N0YXRlcyA8LSBoZWFkKHNvcnQodGFibGUoZGYkU3RhdGVvclByb3ZpbmNlKSwgZGVjcmVhc2luZz1UUlVFKSwgNSkNCnRvcF9jaXRpZXMgPC0gaGVhZChzb3J0KHRhYmxlKGRmJENpdHkpLCBkZWNyZWFzaW5nPVRSVUUpLCA1KQ0Ka2FibGUoZGF0YS5mcmFtZShTdGF0ZT1uYW1lcyh0b3Bfc3RhdGVzKSwgQ291bnQ9YXMuaW50ZWdlcih0b3Bfc3RhdGVzKSksIGNhcHRpb249J1RvcCA1IFRp4buDdSBiYW5nIHRoZW8gc+G7kSBsxrDhu6NuZyBnaWFvIGThu4tjaCcpDQprYWJsZShkYXRhLmZyYW1lKENpdHk9bmFtZXModG9wX2NpdGllcyksIENvdW50PWFzLmludGVnZXIodG9wX2NpdGllcykpLCBjYXB0aW9uPSdUb3AgNSBUaMOgbmggcGjhu5EgdGhlbyBz4buRIGzGsOG7o25nIGdpYW8gZOG7i2NoJykNCg0KYGBgDQoNCkLhuqNuZyB0csOqbiBsaeG7h3Qga8OqIDUgdGnhu4N1IGJhbmcgdsOgIDUgdGjDoG5oIHBo4buRIGPDsyBz4buRIGzGsOG7o25nIGdpYW8gZOG7i2NoIGzhu5tuIG5o4bqldC4gQ8OzIHRo4buDIHRo4bqleSB0aeG7g3UgYmFuZyBXQSAoV2FzaGluZ3RvbikgZOG6q24gxJHhuqd1LCBjw7luZyB24bubaSBDQSwgT1IsIHbDoCBjw6FjIGJhbmcgdOG6oWkgTWV4aWNvLiBW4buBIHRow6BuaCBwaOG7kSwgU2FsZW0gdsOgIFRhY29tYSAodGh14buZYyBXQSkgxJHhu6luZyDEkeG6p3UgZGFuaCBzw6FjaC4gxJBp4buBdSBuw6B5IGzDoCBkbyBk4buvIGxp4buHdSB0aHXhu5ljIG3hu5l0IGNodeG7l2kgc2nDqnUgdGjhu4sg4bufIGtodSB24buxYyBUw6J5IELhuq9jIEhvYSBL4buzLiBW4bubaSBkb2FuaCBuZ2hp4buHcCBWaeG7h3QgTmFtLCBu4bq/dSBjw7MgZOG7ryBsaeG7h3UgxJHhu4thIGzDvSwgY+G6p24gcGjDom4gdMOtY2ggdMawxqFuZyB04buxIMSR4buDIHjDoWMgxJHhu4tuaCBraHUgduG7sWMgYsOhbiBow6BuZyBjaOG7pyBs4buxYy4NCg0KIyMgKioyLjYuIFByb2R1Y3RGYW1pbHkgKE5ow7NtIHPhuqNuIHBo4bqpbSkqKg0KDQpgYGB7cn0NCnRibF9wZiA8LSBkZiAlPiUgY291bnQoUHJvZHVjdEZhbWlseSkgJT4lIG11dGF0ZShQZXJjZW50ID0gbiAvIHN1bShuKSAqIDEwMCkNCmthYmxlKHRibF9wZiwgY2FwdGlvbiA9ICJU4bqnbiBzdeG6pXQgdsOgICUgdGhlbyBOaMOzbSBz4bqjbiBwaOG6qW0iKQ0KDQpgYGANCg0KVGjhu7FjIHBo4bqpbSBjaGnhur9tIH43Mi4yJSwgUGhpIHRpw6p1IGTDuW5nIH4xOC45JSwgxJDhu5MgdeG7kW5nIH44LjklLg0KDQpE4buvIGxp4buHdSBjw7MgMyBuaMOzbSBz4bqjbiBwaOG6qW0gY2jDrW5oOiBGb29kICh0aOG7sWMgcGjhuqltKSBjaGnhur9tIDcyLjIlLCBOb24tQ29uc3VtYWJsZSAoaMOgbmcga2jDtG5nIHRpw6p1IHRo4bulIMSRxrDhu6NjKSAxOC45JSwgdsOgIERyaW5rICjEkeG7kyB14buRbmcpIDguOSUuIE5ow7NtIHRo4buxYyBwaOG6qW0gY2hp4bq/bSDGsHUgdGjhur8gw6FwIMSR4bqjbywgdMawxqFuZyDhu6luZyB24bubaSBuaHUgY+G6p3UgdGhp4bq/dCB54bq/dSBow6BuZyBuZ8OgeS4gTmjDs20gTm9uLUNvbnN1bWFibGUgdHV5IHThu7cgbOG7hyBuaOG7jyBoxqFuIG5oxrBuZyB24bubaSBn4bqnbiAxOSUgduG6q24ga2jDtG5nIHRo4buDIGLhu48gcXVhIHRyb25nIGNoaeG6v24gbMaw4bujYyBraW5oIGRvYW5oLg0KDQpIw6BuZyB0aGnhur90IHnhur91ICh0aOG7sWMgcGjhuqltKSBsdcO0biBjaGnhur9tIMawdSB0aOG6vyDihpIgcGjDuSBo4bujcCBzw6FjaCB0aOG7kW5nIGvDqiBtw7QgdOG6oy4NCg0KYGBge3J9DQpnZ3Bsb3QodGJsX3BmLCBhZXMoeCA9IFByb2R1Y3RGYW1pbHksIHkgPSBuLCBmaWxsID0gUHJvZHVjdEZhbWlseSkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBsYWJzKHRpdGxlID0gIlPhu5EgZ2lhbyBk4buLY2ggdGhlbyBOaMOzbSBz4bqjbiBwaOG6qW0iLA0KICAgICAgIHggPSAiTmjDs20gc+G6o24gcGjhuqltIiwgeSA9ICJT4buRIGdpYW8gZOG7i2NoIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCkNow6puaCBs4buHY2ggbOG7m24gZ2nhu69hIHRo4buxYyBwaOG6qW0gdsOgIMSR4buTIHXhu5FuZy9waGkgdGnDqnUgZMO5bmcuDQoNCkJp4buDdSDEkeG7kyBjaG8gdGjhuqV5IGPhu5l0IEZvb2QgY2FvIHbGsOG7o3QgdHLhu5lpLCBraOG6s25nIMSR4buLbmggbmjhuq1uIHjDqXQg4bufIHRyw6puLiBUcm9uZyBraGkgxJHDsywgcGjhuqduIG3DoHUgxJHhuqFpIGRp4buHbiBjaG8gbmjDs20gTm9uLUNvbnN1bWFibGUgY8WpbmcgaGnhu4duIHLDtSB24bubaSB04buJIGzhu4cgdMawxqFuZyDhu6luZyBn4bqnbiAxOSUuIE5ow6xuIGNodW5nLCBr4bq/dCBxdeG6oyB0cuG7sWMgcXVhbiBuaOG6pW4gbeG6oW5oIG5ow7NtIHRo4buxYyBwaOG6qW0gbMOgIGNo4bunIGzhu7FjLCBkbyDEkcOzIGRvYW5oIG5naGnhu4dwIG7Dqm4gdOG6rXAgdHJ1bmcgdsOgbyBuaMOzbSBz4bqjbiBwaOG6qW0gbsOgeSBraGkgaG/huqFjaCDEkeG7i25oIGjDoG5nIGjDs2EgdsOgIGNoxrDGoW5nIHRyw6xuaCBraHV54bq/biBtw6NpLg0KDQrhu54gVmnhu4d0IE5hbSwgeHUgaMaw4bubbmcgxJHhuql5IG3huqFuaCBt4bqjbmcgRk1DRyAoRmFzdCBNb3ZpbmcgQ29uc3VtZXIgR29vZHMpIGPFqW5nIGdp4buRbmcgbeG6q3UgbsOgeS4NCg0KYGBge3J9DQp0YWJfZGVwdCA8LSBzb3J0KHRhYmxlKGRmJFByb2R1Y3REZXBhcnRtZW50KSwgZGVjcmVhc2luZz1UUlVFKQ0KaGVhZCh0YWJfZGVwdCwgNSkNCmBgYA0KYGBge3J9DQp0YWJfY2F0IDwtIHNvcnQodGFibGUoZGYkUHJvZHVjdENhdGVnb3J5KSwgZGVjcmVhc2luZz1UUlVFKQ0KaGVhZCh0YWJfY2F0LCA1KQ0KDQpgYGANCg0K4bueIGPhuqVwIMSR4buZIGRhbmggbeG7pWMgc+G6o24gcGjhuqltIChQcm9kdWN0IENhdGVnb3J5KSwgY8OhYyBt4bulYyBWZWdldGFibGVzIChyYXUgY+G7pyksIFNuYWNrIEZvb2RzICjEkeG7kyDEg24gduG6t3QpLCBEYWlyeSBQcm9kdWN0cyAoc+G6o24gcGjhuqltIHThu6sgc+G7r2EpLCBGcnVpdHMgKHRyw6FpIGPDonkpIHbDoCBNZWF0ICh0aOG7i3QpIG7hurFtIHRyb25nIHRvcCDEkeG6p3UgduG7gSBz4buRIGzGsOG7o25nIGdpYW8gZOG7i2NoLiBIYXkgbsOzaSBjw6FjaCBraMOhYywgcmF1IGPhu6csIMSR4buTIMSDbiB24bq3dCwgc+G6o24gcGjhuqltIHThu6sgc+G7r2EsIHRyw6FpIGPDonkgdsOgIHRo4buLdCBsw6Agbmjhu69uZyBt4bq3dCBow6BuZyB0aGnhur90IHnhur91IMSRxrDhu6NjIG11YSBuaGnhu4F1IG5o4bqldC4gxJDhu5FpIHbhu5tpIHRo4buLIHRyxrDhu51uZyBWaeG7h3QgTmFtLCBjaMO6bmcgdGEgY8WpbmcgY8OzIHRo4buDIG1vbmcgxJHhu6NpIGPDoWMgbG/huqFpIHRo4buxYyBwaOG6qW0gdMawxqFpIHPhu5FuZyB2w6AgdGhp4bq/dCB54bq/dSBjaGnhur9tIMawdSB0aOG6vyB0xrDGoW5nIHThu7EuDQoNCiMjICoqMi43LiBQcm9kdWN0RGVwYXJ0bWVudCAmIFByb2R1Y3RDYXRlZ29yeSoqDQoNCkRvIHPhu5EgbMaw4bujbmcgaOG6oW5nIG3hu6VjIG5oaeG7gXUsIHRhIGNo4buJIHRyw61jaCB4deG6pXQgdG9wIDU6DQoNCmBgYHtyfQ0KdG9wMTBfZGVwdCA8LSBkZiAlPiUgY291bnQoUHJvZHVjdERlcGFydG1lbnQsIHNvcnQgPSBUUlVFKSAlPiUgdG9wX24oMTApIA0Ka2FibGUodG9wMTBfZGVwdCwgY2FwdGlvbiA9ICJUb3AgMTAgUGjDsm5nIGJhbiBz4bqjbiBwaOG6qW0iKQ0KYGBgDQoNCsSQ4buDIGPDsyB0aOG7gyB0aOG6pXkgcsO1IGjGoW4gduG7gSBQcm9kdWN0IERlcGFydG1lbnQgdGEgY8O5bmcgeGVtIHF1YSBUb3AgMTAgUHJvZHVjdCBEZXBhcnRtZW50Og0KDQpgYGB7cn0NCiMgQmnhu4N1IMSR4buTIHRvcCAxMCBQcm9kdWN0IERlcGFydG1lbnQNCmRlcHRfY291bnRzIDwtIHNvcnQodGFibGUoZGYkUHJvZHVjdERlcGFydG1lbnQpLCBkZWNyZWFzaW5nPVRSVUUpDQpoZWFkKGRlcHRfY291bnRzLCAxMCkNCnRvcDEwX2RlcHQgPC0gbmFtZXMoaGVhZChkZXB0X2NvdW50cywxMCkpDQpnZ3Bsb3Qoc3Vic2V0KGRmLCBQcm9kdWN0RGVwYXJ0bWVudCAlaW4lIHRvcDEwX2RlcHQpLCANCiAgICAgICBhZXMoeCA9IFByb2R1Y3REZXBhcnRtZW50LCBmaWxsPVByb2R1Y3REZXBhcnRtZW50KSkgKw0KICBnZW9tX2Jhcihjb2xvcj0id2hpdGUiKSArDQogIGxhYnModGl0bGU9IlRvcCAxMCBOZ8OgbmggaMOgbmcgdGhlbyBz4buRIGdpYW8gZOG7i2NoIiwgDQogICAgICAgeD0iTmfDoG5oIGjDoG5nIiwgeT0iU+G7kSBnaWFvIGThu4tjaCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KDQpDw6FjIG5nw6BuaCBow6BuZyBtdWEgbmhp4buBdSBuaOG6pXQgZ+G7k206IFByb2R1Y2UgKHJhdSBj4bunLCAxOTk0IMSRxqFuKSwgU25hY2sgRm9vZHMgKMSR4buTIMSDbiB24bq3dCwgMTYwMCksIEhvdXNlaG9sZCAoxJHhu5MgZ2lhIGThu6VuZywgMTQyMCksIEZyb3plbiBGb29kcyAoMTM4MiksIEJha2luZyBHb29kcyAoMTA3MiksIENhbm5lZCBGb29kcyAoOTc3KSwgRGFpcnkgKDkwMyksIEhlYWx0aCAmIEh5Z2llbmUgKDg5MyksIERlbGkgKDY5OSksIEJldmVyYWdlcyAoNjgwKS4NCg0KU+G6o24gcGjhuqltIHTGsMahaSAocmF1IGPhu6csIHF14bqjKSwgxJHhu5MgxINuIG5o4bq5IHbDoCBjw6FjIG5odSB54bq/dSBwaOG6qW0gdGjGsOG7nW5nIHh1ecOqbiDEkeG7qW5nIMSR4bqndSwgcGjDuSBo4bujcCB24bubaSBuaHUgY+G6p3UgaMOgbmcgbmfDoHkuIMSQ4bq3YyBiaeG7h3QsIFByb2R1Y2UgKHJhdSBj4bunIHF14bqjKSBjYW8gbmjhuqV0IDE5OTQgxJHGoW4sIGNobyB0aOG6pXkga2jDoWNoIMawdSB0acOqbiB0aOG7sWMgcGjhuqltIHTGsMahaS4gU25hY2sgRm9vZHMgY8WpbmcgY2FvIGNo4bupbmcgdOG7jyBuaHUgY+G6p3UgxJHhu5MgxINuIG5oYW5oL2fhuqVwICh0aMaw4budbmcgZMO5bmcgY2hvIGdpYSDEkcOsbmggxJHDtG5nIGNvbiBob+G6t2Mgbmh1IGPhuqd1IMSDbiBuaOG6uSkuDQoNCkPDoWMgbmfDoG5oIGjDoG5nIGtow6FjIG5oxrAgxJHhu5MgZ2lhIGThu6VuZywgxJHDs25nIGjhu5lwLCDEkcO0bmcgbOG6oW5oIGPFqW5nIHF1YW4gdHLhu41uZywgcGjhuqNuIMOhbmggdmnhu4djIGtow6FjaCB24burYSBtdWEgdGjhu7FjIHBo4bqpbSB24burYSBtdWEgdGjDqm0gxJHhu5MgY+G6p24gdGhp4bq/dCBjaG8gZ2lhIMSRw6xuaC4gTmjDrG4gY2h1bmcsIGtow7RuZyBjw7MgbmfDoG5oIGjDoG5nIHBo4bulIHLDtSBy4buHdCwgdsOsIGtow6FjaCBow6BuZyBjw7MgeHUgaMaw4bubbmcgbXVhIHhlbiBr4bq9IG5oaeG7gXUgbG/huqFpIGjDoG5nICjEkWEgZOG6oW5nIGjDs2EpLg0KDQpgYGB7cn0NCnRvcDEwX2NhdCAgPC0gZGYgJT4lIGNvdW50KFByb2R1Y3RDYXRlZ29yeSwgICBzb3J0ID0gVFJVRSkgJT4lIHRvcF9uKDEwKQ0Ka2FibGUodG9wMTBfY2F0LCAgY2FwdGlvbiA9ICJUb3AgMTAgTeG7pWMgc+G6o24gcGjhuqltIikNCmBgYA0KDQpDw6FjIHBow7JuZyBiYW4vbeG7pWMgduG7gSB0aOG7sWMgcGjhuqltIMSRw7NuZyBnw7NwIG5oaeG7gXUgbmjhuqV0Lg0KDQrhu54gc2nDqnUgdGjhu4sgVmnhu4d0IE5hbSwgdGjGsOG7nW5nIHRo4bqleSBt4bqjbmcgbeG7syBnw7NpLCBnaWEgduG7iywgc+G7r2EsIHRyw6FpIGPDonkgdMawxqFp4oCmIG7hurFtIHRyb25nIHRvcC4NCg0KYGBge3J9DQojIFRvcCAxMCBt4bulYyBtdWEgbmhp4buBdSBuaOG6pXQgKFByb2R1Y3QgQ2F0ZWdvcnkpDQpjYXRfY291bnRzIDwtIHNvcnQodGFibGUoZGYkUHJvZHVjdENhdGVnb3J5KSwgZGVjcmVhc2luZz1UUlVFKQ0KaGVhZChjYXRfY291bnRzLCAxMCkNCiMgQmnhu4N1IMSR4buTIHRvcCAxMCBQcm9kdWN0IENhdGVnb3J5DQp0b3AxMF9jYXQgPC0gbmFtZXMoaGVhZChjYXRfY291bnRzLDEwKSkNCmdncGxvdChzdWJzZXQoZGYsIFByb2R1Y3RDYXRlZ29yeSAlaW4lIHRvcDEwX2NhdCksIA0KICAgICAgIGFlcyh4ID0gUHJvZHVjdENhdGVnb3J5LCBmaWxsPVByb2R1Y3RDYXRlZ29yeSkpICsNCiAgZ2VvbV9iYXIoY29sb3I9IndoaXRlIikgKw0KICBsYWJzKHRpdGxlPSJUb3AgMTAgRGFuaCBt4bulYyBz4bqjbiBwaOG6qW0gdGhlbyBz4buRIGdpYW8gZOG7i2NoIiwgDQogICAgICAgeD0iRGFuaCBt4bulYyBz4bqjbiBwaOG6qW0iLCB5PSJT4buRIGdpYW8gZOG7i2NoIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KYGBgDQpEYW5oIG3hu6VjIHBo4buVIGJp4bq/biBuaOG6pXQ6IFZlZ2V0YWJsZXMgKHJhdSksIFNuYWNrIEZvb2RzLCBEYWlyeSwgRnJ1aXQgKHRyw6FpIGPDonkpLCBNZWF0ICh0aOG7i3QpLCBKYW1zIGFuZCBKZWxsaWVzLCBCYWtpbmcgR29vZHMsIEJyZWFkLCBCcmVha2Zhc3QgRm9vZHMsIENhbm5lZCBTb3VwLi4uIE5o4buvbmcgZGFuaCBt4bulYyBuw6B5IGdp4buRbmcgduG7m2kgY8OhYyBt4bq3dCBow6BuZyB0aMaw4budbmcgbXVhIHRyb25nIGto4bqjbyBzw6F0IHRpw6p1IGTDuW5nLCBuaMawIHJhdSBj4bunLCBz4buvYSwgxJHhu5MgxINuIG5o4bq5LCB0csOhaSBjw6J5Li4uICh0dcOibiB0aGVvIHh1IGjGsOG7m25nIMawYSBjaHXhu5luZyB0aOG7sWMgcGjhuqltIHTGsMahaSB2w6AgdGnhu4duIGzhu6NpKQ0KDQrEkOG6t2MgYmnhu4d0LCByYXUgY+G7pyAoVmVnZXRhYmxlcykgY2FvIG5o4bqldCB+MTcyOCDEkcahbiwgcGjhuqNuIMOhbmggdGjDs2kgcXVlbiDEg24gdeG7kW5nIGzDoG5oIG3huqFuaCBob+G6t2Mgbmh1IGPhuqd1IGjDoG5nIG5nw6B5LiBT4buvYSAoRGFpcnkpIHbDoCB0csOhaSBjw6J5IGPFqW5nIG7hurFtIHRyb25nIHRvcC4gxJDhu5MgxINuIG5oYW5oIChTbmFjayBGb29kcykgY8WpbmcgxJHhu6luZyDEkeG6p3UgY2hvIHRo4bqleSBuaHUgY+G6p3UgdGnhu4duIGzhu6NpIGNobyBnaWEgxJHDrG5oIChuaMawIHRy4bq7IGVtIG114buRbiDEg24gduG6t3QsIGhheSBuZ8aw4budaSBs4bubbiBsw6BtIHZp4buHYyBi4bqtbikuDQoNCkPDoWMgbeG6t3QgaMOgbmcgdGhp4bq/dCB54bq/dSBraMOhYyBuaMawIGLDoW5oIG3DrCAoQnJlYWQpLCBow6BuZyBzw6FuZyAoQnJlYWtmYXN0KSBoYXkgxJHhu5MgxJHDs25nIGjhu5lwIChDYW5uZWQgU291cCkgY8WpbmcgcGjhu5UgYmnhur9uLCBjaG8gdGjhuqV5IGtow6FjaCBow6BuZyBtdWEgdGhlbyB0aOG7sWMgxJHGoW4gdsOgIGThu7EgcGjDsm5nLiBE4buvIGxp4buHdSBwaMO5IGjhu6NwIHbhu5tpIHRow7NpIHF1ZW4gbXVhIGjDoG5nIOG7nyBN4bu5L0NhbmFkYS9NZXhpY28g4oCTIMawdSB0acOqbiB0aOG7sWMgcGjhuqltIGPGoSBi4bqjbiwgdMawxqFpIHPhu5FuZywgdsOgIG3hu5l0IHPhu5EgxJHhu5MgxINuIHRp4buHbiBs4bujaS4NCg0KIyMgKioyLjcuIFByb2R1Y3QgVW5pdHMgU29sZCoqDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PSBCSeG6vk4gVU5JVFNTT0xEID09PT09PT09PT09PT09PT09PT09PT09DQojIFRo4buRbmcga8OqIGPGoSBi4bqjbiB24buBIFVuaXRzU29sZA0Kc3VtbWFyeShkZiRVbml0c1NvbGQpDQojIEhpc3RvZ3JhbSBwaMOibiBwaOG7kWkgVW5pdHNTb2xkDQpnZ3Bsb3QoZGYsIGFlcyh4ID0gVW5pdHNTb2xkKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xLCBmaWxsPSJza3libHVlIiwgY29sb3I9IndoaXRlIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPTE6OCkgKw0KICBsYWJzKHRpdGxlPSJQaMOibiBwaOG7kWkgc+G7kSBsxrDhu6NuZyBt4bq3dCBow6BuZyAoVW5pdHNTb2xkKSIsIA0KICAgICAgIHg9IlPhu5EgbMaw4bujbmcgKFVuaXRzKSIsIHk9IlPhu5EgZ2lhbyBk4buLY2giKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KU+G7kSBsxrDhu6NuZyBt4bq3dCBow6BuZyB0cm9uZyBt4buXaSBnaWFvIGThu4tjaCB0cnVuZyBiw6xuaCBraG/huqNuZyA0LjA4IMSRxqFuIHbhu4ssIHBo4buVIGJp4bq/biBuaOG6pXQgbMOgIDMtNSAoTWVkaWFuPTQsIFExPTMsIFEzPTUpLiBDw7Mgw610IGdpYW8gZOG7i2NoIGNo4buJIDEtMiDEkcahbiB24buLIGhv4bq3YyBuaGnhu4F1IG5o4bqldCA4IMSRxqFuIHbhu4suDQoNCkJp4buDdSDEkeG7kyBoaXN0b2dyYW0gY2hvIHRo4bqleSDEkWEgcGjhuqduIGPDoWMgZ2lhbyBk4buLY2ggbXVhIDMtNSDEkcahbiB24buLLCB0aOG7gyBoaeG7h24gbmhp4buBdSBraMOhY2ggaMOgbmcgbXVhIHThu6sgdsOgaSBtw7NuIChjw7MgdGjhu4MgMy01IHPhuqNuIHBo4bqpbSkgdHJvbmcgbeG7l2kgbOG6p24gdGhhbmggdG/DoW4uIMONdCBjw7MgbmfGsOG7nWkgbXVhIGPhu7FjIMOtdCAoMSkgaG/hurdjIGPhu7FjIG5oaeG7gXUgKD42KSDEkcahbiB24buLLg0KDQrEkMOieSBsw6AgeHUgaMaw4bubbmcgaOG7o3AgbMO9IGNobyBnaWFvIGThu4tjaCB04bqhaSBzacOqdSB0aOG7izogbeG7mXQgZ2nhu48gaMOgbmcgxJFp4buDbiBow6xuaCBuaOG7jyBn4buNbiwga2jDtG5nIHF1w6Egbmhp4buBdSBtw7NuLiBHacOhIHRy4buLIGRvYW5oIHRodSB0cnVuZyBiw6xuaCBjxaluZyDhu58gbeG7qWMgdMawxqFuZyDhu6luZyAoeGVtIGJp4bq/biBSZXZlbnVlIHBow61hIGTGsOG7m2kpLg0KDQojIyAqKjIuOC4gUHJvZHVjdCBSZXZlbnVlKioNCg0KYGBge3J9DQojID09PT09PT09PT09PT09PT09PT09PT09PSBCSeG6vk4gUkVWRU5VRSA9PT09PT09PT09PT09PT09PT09PT09PQ0KIyBUaOG7kW5nIGvDqiBjxqEgYuG6o24gduG7gSBSZXZlbnVlDQpzdW1tYXJ5KGRmJFJldmVudWUpDQojIEhpc3RvZ3JhbSBwaMOibiBwaOG7kWkgUmV2ZW51ZQ0KZ2dwbG90KGRmLCBhZXMoeCA9IFJldmVudWUpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnM9MzAsIGZpbGw9InNhbG1vbiIsIGNvbG9yPSJ3aGl0ZSIpICsNCiAgbGFicyh0aXRsZT0iUGjDom4gcGjhu5FpIGdpw6EgdHLhu4sgxJHGoW4gaMOgbmcgKFJldmVudWUpIiwgDQogICAgICAgeD0iRG9hbmggdGh1IChVU0QpIiwgeT0iU+G7kSBnaWFvIGThu4tjaCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCg0KYGBgDQoNCkPDuW5nIHbhu5tpIMSRw7MgdGEgcXVhbiBzw6F0IHTGsMahbmcgcXVhbiBnaeG7r2EgVW5pdHNTb2xkIHbDoCBSZXZlbnVlDQoNCmBgYHtyfQ0KIyBRdWFuIHPDoXQgdMawxqFuZyBxdWFuIGdp4buvYSBVbml0c1NvbGQgdsOgIFJldmVudWUNCg0KZ2dwbG90KGRmLCBhZXMoeCA9IFVuaXRzU29sZCwgeSA9IFJldmVudWUpKSArDQogIGdlb21fcG9pbnQoYWxwaGE9MC4zLCBjb2xvcj0iYmx1ZSIpICsNCiAgbGFicyh0aXRsZT0iTeG7kWkgcXVhbiBo4buHIGdp4buvYSBz4buRIGzGsOG7o25nIHbDoCBkb2FuaCB0aHUiLCANCiAgICAgICB4PSJT4buRIGzGsOG7o25nIChVbml0cykiLCB5PSJEb2FuaCB0aHUgKFVTRCkiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHN0YXRfc21vb3RoKG1ldGhvZD0ibG0iLCBzZT1GQUxTRSwgY29sPSJyZWQiKQ0KYGBgDQoNCg0KRG9hbmggdGh1IG3hu5dpIGdpYW8gZOG7i2NoIHRydW5nIGLDrG5oIGtob+G6o25nIDEzLjAwIFVTRCAoa2hv4bqjbmcgfjMwMGsgVk5EKS4gUGjhuqduIGzhu5tuIMSRxqFuIGjDoG5nIG7hurFtIHRyb25nIGtob+G6o25nICQ2Ljg0IMSR4bq/biAkMTcuMzcgKHThu6kgcGjDom4gduG7iykuIEPDsyBuaOG7r25nIMSRxqFuIHLhuqV0IHLhursgKHRo4bqlcCBuaOG6pXQgfiAkMC41MywgdGjGsOG7nW5nIGzDoCBz4bqjbiBwaOG6qW0gbmjhu48pIHbDoCDEkeG6r3QgbmjhuqV0IH4gJDU2LjcgKGPDsyB0aOG7gyBsw6Agbmhp4buBdSDEkcahbiB24buLIGjDoG5nIMSR4bqvdCB0aeG7gW4pLg0KDQpCaeG7g3UgxJHhu5MgaGlzdG9ncmFtIGNobyB0aOG6pXkgcGjhuqduIGzhu5tuIGdpYW8gZOG7i2NoIOG7nyBt4bupYyB0aOG6pXAgKDwkMjApLCBiaeG7g3UgxJHhu5MgdOG7iSBs4buHIGdp4bqjbSBk4bqnbiBraGkgZG9hbmggdGh1IHTEg25nLiDEkGnhu4F1IG7DoHkgaOG7o3AgbMO9IHbDrCBo4bqndSBo4bq/dCBraMOhY2ggbXVhIHbDoGkgbcOzbiBnacOhIHbhu6thIHBo4bqjaS4NCg0KxJDhu5MgdGjhu4sgc2NhdHRlciBnaeG7r2EgVW5pdHNTb2xkIHbDoCBSZXZlbnVlIGNobyB0aOG6pXkgY8OzIHTGsMahbmcgcXVhbiBkxrDGoW5nIHnhur91IChSwrIgdGjhuqVwKToga2jDtG5nIHBo4bqjaSBsw7pjIG7DoG8gbmhp4buBdSBz4bqjbiBwaOG6qW0gdGjDrCBkb2FuaCB0aHUgY2FvIHTGsMahbmcg4bupbmcuIFbDrSBk4bulLCBtdWEgbmhp4buBdSDEkcahbiB24buLICg2LTgpIG5oxrBuZyBjw7MgdGjhu4MgbMOgIGjDoG5nIGdpw6EgcuG6uywgbmfGsOG7o2MgbOG6oWkgw610IMSRxqFuIHbhu4sgKDEtMikgbmjGsG5nIGzDoCBz4bqjbiBwaOG6qW0gxJHhuq90ICh2w60gZOG7pSBz4bqjbiBwaOG6qW0gZGluaCBkxrDhu6FuZyBjYW8gY+G6pXApLg0KVHJ1bmcgYsOsbmgsIGPDoG5nIG11YSBuaGnhu4F1IMSRxqFuIHbhu4sgdGjDrCBkb2FuaCB0aHUgY8OzIGtodXluaCBoxrDhu5tuZyB0xINuZywgbmjGsG5nIMSR4buZIGzhu4djaCBs4bubbiBjaG8gdGjhuqV5IHPhu7EgxJFhIGThuqFuZyBnacOhIHPhuqNuIHBo4bqpbS4NCg0KKioqDQoNCiMgKipQSOG6pk4gMy4gxq/hu5tjIGzGsOG7o25nIEtob+G6o25nIHbDoCBLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dCBjaG8gVOG7tyBs4buHKioNCg0KKioqDQoNCkNo4buNbiAzIGjhuqFuZyBt4bulYzoNCg0KMS4gTuG7ryB0cm9uZyBHZW5kZXIgKEgwOiBwID0gMC41KQ0KDQoyLiDEkMOjIGvhur90IGjDtG4gdHJvbmcgTWFyaXRhbFN0YXR1cyAoSDA6IHAgPSAwLjUpDQoNCjMuIFRo4buxYyBwaOG6qW0gdHJvbmcgUHJvZHVjdEZhbWlseSAoSDA6IHAgPSAwLjcpDQoNCmBgYHtyfQ0KbiA8LSBucm93KGRmKQ0KDQojIDEuIE7hu68NCngxIDwtIHN1bShkZiRHZW5kZXIgPT0gIk7hu68iKQ0KcHQxIDwtIHByb3AudGVzdCh4MSwgbiwgcCA9IDAuNSwgY29uZi5sZXZlbCA9IDAuOTUpDQoNCiMgMi4gxJDDoyBr4bq/dCBow7RuDQp4MiA8LSBzdW0oZGYkTWFyaXRhbFN0YXR1cyA9PSAixJDDoyBr4bq/dCBow7RuIikNCnB0MiA8LSBwcm9wLnRlc3QoeDIsIG4sIHAgPSAwLjUsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KDQojIDMuIFRo4buxYyBwaOG6qW0NCngzIDwtIHN1bShkZiRQcm9kdWN0RmFtaWx5ID09ICJUaOG7sWMgcGjhuqltIikNCnB0MyA8LSBwcm9wLnRlc3QoeDMsIG4sIHAgPSAwLjcsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KDQpsaXN0KA0KICBGZW1hbGUgICAgID0gcHQxLA0KICBNYXJyaWVkICAgID0gcHQyLA0KICBGb29kRmFtaWx5ID0gcHQzDQopDQoNCmBgYA0KDQpOaOG6rW4geMOpdDoNCg0KTuG7rzogcMyC4omIMC41MTAsIENJIFswLjUwMTcsMC41MTgzXSwgcC12YWx1ZeKJiDAuMDQ4IDwwLjA1IOKGkiBiw6FjIGLhu48gSDA6IHThu7cgbOG7hyBO4buvIGtow6FjIDAuNS4NCg0KxJDDoyBr4bq/dCBow7RuOiBwzILiiYgwLjQ4OCwgQ0kgWzAuNDgwMSwwLjQ5NjZdLCBwLXZhbHVl4omIMC4wMzkgPDAuMDUg4oaSIGLDoWMgYuG7jyBIMDogdOG7tyBs4buHIGtow6FjIDAuNS4NCg0KVGjhu7FjIHBo4bqpbTogcMyC4omIMC43MTgsIENJIFswLjcxMjEsMC43MjQzXSwgcC12YWx1ZeKJiDAuMDAwMiA8MC4wNSDihpIgYsOhYyBi4buPIEgwOiB04bu3IGzhu4cga2jDoWMgMC43Lg0KDQpL4bq/dCBsdeG6rW46IFThuqV0IGPhuqMgxJHhu4F1IGPDsyBraMOhYyBiaeG7h3QgY8OzIMO9IG5naMSpYSBzbyB24bubaSBnaeG6oyB0aHV54bq/dC4NCg0KTGnDqm4gaOG7hyBWaeG7h3QgTmFtOg0KDQpU4bu3IGzhu4cgTuG7ryAmIMSQw6Mga+G6v3QgaMO0bjogcGjDuSBo4bujcCB4dSBoxrDhu5tuZyBwaOG7pSBu4buvIG11YSBz4bqvbSBuaGnhu4F1LCB04buJIGzhu4cga+G6v3QgaMO0biB0aOG6pXAgaMahbiBkbyBjw7MgbmjDs20gxJHhu5ljIHRow6JuIMSRw7RuZy4NCg0KVOG7tyBs4buHIG5ow7NtIHRo4buxYyBwaOG6qW0gY2FvIGjGoW4gNzAlIHRo4buDIGhp4buHbiBuaHUgY+G6p3UgdGhp4bq/dCB54bq/dSBs4bubbi4NCg0KDQoNCioqKg0KDQojICoqUEjhuqZOIDQuIFBow6JuIHTDrWNoIE3hu5FpIHF1YW4gaOG7hyBIYWkgYmnhur9uIMSQ4buLbmggdMOtbmgqKg0KDQoqKioNCg0KQ2jhu41uIDMgY+G6t3A6DQoNCjEuIEdlbmRlciB+IFByb2R1Y3RGYW1pbHkNCg0KMi4gTWFyaXRhbFN0YXR1cyB+IEhvbWVvd25lcg0KDQozLiBBbm51YWxJbmNvbWUgfiBQcm9kdWN0Q2F0ZWdvcnkNCg0KIyMgKio0LjEuIEdlbmRlciB2cyBQcm9kdWN0RmFtaWx5KioNCg0KIyMjICoqQuG6o25nIHThuqduIHPhu5EgY2jDqW8gY2hvIEdlbmRlciB2cyBQcm9kdWN0RmFtaWx5KioNCg0KYGBge3J9DQp0YWJfZ2YgPC0gdGFibGUoZGYkR2VuZGVyLCBkZiRQcm9kdWN0RmFtaWx5KQ0KY2hpc3FfZ2YgPC0gY2hpc3EudGVzdCh0YWJfZ2YpDQp0YWJfZ2Y7IGNoaXNxX2dmDQoNCmBgYA0KQuG6o25nIGNow6lvIGvhur90IGjhu6NwIEdp4bubaSB0w61uaCAtIE5ow7NtIHPhuqNuIHBo4bqpbSBjaG8gdGjhuqV5IGPhuqMgaGFpIGdp4bubaSDEkeG7gXUgbXVhIG5oaeG7gXUgbmjhuqV0IGzDoCBGb29kLCBuaMawbmcgdOG7tyBs4buHIGdp4buvYSBjw6FjIG5ow7NtIHPhuqNuIHBo4bqpbSBjw7MgY2jDunQga2jDoWMgYmnhu4d0LiBLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcgY2hvIHAtdmFsdWUgcuG6pXQgbmjhu48gKHAgPCAwLjA1KSwgbmdoxKlhIGzDoCBjw7Mgc+G7sSBwaOG7pSB0aHXhu5ljIGdp4buvYSBnaeG7m2kgdMOtbmggdsOgIG5ow7NtIHPhuqNuIHBo4bqpbSBtdWEuIEPhu6UgdGjhu4MsIG7hu68gbXVhIEZvb2QgY2hp4bq/bSB+NzQuMiUgdHJvbmcgc+G7kSBu4buvLCBjw7JuIOG7nyBuYW0gbMOgIH43MC4yJS4gTmfGsOG7o2MgbOG6oWksIG5hbSBtdWEgbmhp4buBdSBoxqFuIOG7nyBuaMOzbSBOb24tQ29uc3VtYWJsZSAoMjMuMiUgc28gduG7m2kgMTUuMyUg4bufIG7hu68pLiDEkGnhu4F1IG7DoHkgZ+G7o2kgw70gcuG6sW5nIG5hbSBnaeG7m2kgdHJvbmcgbeG6q3UgxrBhIGNodeG7mW5nIGPDoWMgc+G6o24gcGjhuqltIGdpYSBk4bulbmcgdsOgIHRoaeG6v3QgYuG7iyBjw6EgbmjDom4gKE5vbi1Db25zdW1hYmxlKSBuaGnhu4F1IGjGoW4gc28gduG7m2kgbuG7ry4NCg0KYGBge3J9DQpnZ3Bsb3QoZGYsIGFlcyh4ID0gUHJvZHVjdEZhbWlseSwgZmlsbCA9IEdlbmRlcikpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGxhYnModGl0bGUgPSAiUGjDom4gcGjhu5FpIG5ow7NtIHPhuqNuIHBo4bqpbSB0aGVvIEdp4bubaSB0w61uaCIsDQogICAgICAgeCA9ICJOaMOzbSBz4bqjbiBwaOG6qW0iLCB5ID0gIlPhu5EgZ2lhbyBk4buLY2giLCBmaWxsID0gIkdp4bubaSB0w61uaCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KTmjhuq1uIHjDqXQ6DQoNCnAtdmFsdWUgPDAuMDAxIOKGkiBjw7MgbGnDqm4gaOG7hy4NCg0KQmnhu4N1IMSR4buTIGPhu5l0IGdow6lwIGNobyB0aOG6pXkgcsO1IGjGoW4gxrB1IHRo4bq/IGPhu6dhIG5ow7NtIEZvb2Qg4bufIGPhuqMgaGFpIGdp4bubaSAoY8OhYyBj4buZdCBtw6B1IHhhbmggY2jhu6cgeeG6v3UgY2hp4bq/bSBwaOG6p24pLiBUdXkgbmhpw6puLCBj4buZdCBOb24tQ29uc3VtYWJsZSAobcOgdSDEkeG7jykgY2FvIGjGoW4g4bufIG5hbS4gTmjDs20gcXXhuqNuIGzDvSBkb2FuaCBuZ2hp4buHcCBjw7MgdGjhu4MgZOG7sWEgdsOgbyBr4bq/dCBxdeG6oyBuw6B5IMSR4buDIMSRaeG7gXUgY2jhu4luaCBkYW5oIG3hu6VjIHPhuqNuIHBo4bqpbSBxdeG6o25nIGLDoSBjaG8gdOG7q25nIG5ow7NtIGtow6FjaCBow6BuZy4gVsOtIGThu6UsIGNoaeG6v24gZOG7i2NoIMSR4buTIGdpYSBk4bulbmcgY8OzIHRo4buDIGjGsOG7m25nIG5oaeG7gXUgxJHhur9uIGtow6FjaCBuYW0sIHRyb25nIGtoaSBraHV54bq/biBtw6NpIHRo4buxYyBwaOG6qW0gY8OzIHRo4buDIHRp4bq/cCBj4bqtbiB04buRdCBoxqFuIHbhu5tpIGtow6FjaCBu4buvLg0KDQpO4buvIG11YSB0aOG7sWMgcGjhuqltICYgcGhpIHRpw6p1IGTDuW5nIG5oaeG7gXUgaMahbiBOYW07IE5hbSBtdWEgxJHhu5MgdeG7kW5nIHTGsMahbmcgxJHhu5FpIGNhbyBoxqFuLg0KDQojIyMgKipSZWxhdGl2ZSBSaXNrIGNobyBHZW5kZXIgdnMgUHJvZHVjdEZhbWlseSoqDQoNCmBgYHtyfQ0KIyBUw61uaCBSZWxhdGl2ZSBSaXNrDQpyaXNrX3Jlc3VsdCA8LSByaXNrcmF0aW8odGFiX2dmKQ0Kcmlza19yZXN1bHQNCg0KYGBgDQoNClJSID0gMS4xMDU6IFBo4bulIG7hu68gY8OzIG5ndXkgY8ahIHRpw6p1IGTDuW5nIGjDoG5nIHRpw6p1IGTDuW5nIChwaGkgdGjhu7FjIHBo4bqpbSkgY2FvIGjGoW4gMTAuNSUgc28gduG7m2kgbmFtIGdp4bubaS4NCg0KDQpUdXkgbmhpw6puLCBraG/huqNuZyB0aW4gY+G6rXkgOTUlOiAoMC45OTUg4oCTIDEuMjI4KSBiYW8gZ+G7k20gZ2nDoSB0cuG7iyAxLCB04bupYyBsw6AgY2jGsGEgY8OzIMSR4bunIGLhurFuZyBjaOG7qW5nIHRo4buRbmcga8OqIMSR4buDIGto4bqzbmcgxJHhu4tuaCBz4buxIGtow6FjIGJp4buHdCBuw6B5IGzDoCBjw7MgdGjhuq10Lg0KDQojIyMgKipPZGRzIFJhdGlvIGNobyBHZW5kZXIgdnMgUHJvZHVjdEZhbWlseSoqDQoNCmBgYHtyfQ0KIyBUw61uaCBPZGRzIFJhdGlvDQpvcl9yZXN1bHQgPC0gb2Rkc3JhdGlvKHRhYl9nZikNCm9yX3Jlc3VsdA0KYGBgDQoNCk9kZHMgbXVhIGxv4bqhaSBz4bqjbiBwaOG6qW0gxJFhbmcgeMOpdCAoY8OzIHRo4buDIGzDoCBwaGkgdGnDqnUgZMO5bmcpIOG7nyBu4buvIGNhbyBoxqFuIG5hbSBraG/huqNuZyAxMS45JS4NCg0KDQoNCiMjICoqNC4yLiBNYXJpdGFsU3RhdHVzIHZzIEhvbWVvd25lcioqDQoNCiMjIyAqKkLhuqNuZyB04bqnbiBz4buRIGNow6lvIGNobyBNYXJpdGFsU3RhdHVzIHZzIEhvbWVvd25lcioqDQoNCmBgYHtyfQ0KdGFiX21oIDwtIHRhYmxlKGRmJE1hcml0YWxTdGF0dXMsIGRmJEhvbWVvd25lcikNCmNoaXNxX21oIDwtIGNoaXNxLnRlc3QodGFiX21oKQ0KdGFiX21oOyBjaGlzcV9taA0KDQpgYGANCkLhuqNuZyBjaMOpbyBjaG8gdGjhuqV5IG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biAoTSkgY8OzIOG6pW4gdMaw4bujbmcgaMahbiB24buBIHZp4buHYyBz4bufIGjhu691IG5ow6Agc28gduG7m2kgbmfGsOG7nWkgxJHhu5ljIHRow6JuIChTKS4gS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nIGNobyBr4bq/dCBxdeG6oyBwLXZhbHVlIDwgMC4wNSwgdOG7qWMgYsOhYyBi4buPIGdp4bqjIHRodXnhur90IMSR4buZYyBs4bqtcC4gTmjGsCB24bqteSB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4g4bqjbmggaMaw4bufbmcgdOG7m2kgdOG7tyBs4buHIHPhu58gaOG7r3UgbmjDoDogbmfGsOG7nWkgxJHDoyBs4bqtcCBnaWEgxJHDrG5oIGPDsyBraOG6oyBuxINuZyBz4bufIGjhu691IG5ow6AgY2FvIGjGoW4sIGjhu6NwIGzDvSB24bubaSB0aOG7sWMgdOG6vyBsw6Agc2F1IGtoaSBs4bqtcCBnaWEgxJHDrG5oLCBuaGnhu4F1IG5nxrDhu51pIHPhur0gbXVhIGNodW5nIG5ow6Ag4bufLiDEkOG7kWkgduG7m2kgZG9hbmggbmdoaeG7h3AsIHRow7RuZyB0aW4gbsOgeSBjw7MgdGjhu4MgZMO5bmcgxJHhu4MgcGjDom4ga2jDumMgxJHhu5FpIHTGsOG7o25nOiBuaMOzbSDEkcOjIGvhur90IGjDtG4gY8OzIHRo4buDIHF1YW4gdMOibSDEkeG6v24gxJHhu5MgZ2lhIGThu6VuZyBnaWEgxJHDrG5oIGjGoW4sIHRyb25nIGtoaSBuaMOzbSDEkeG7mWMgdGjDom4gY8OzIHRo4buDIHThuq1wIHRydW5nIHbDoG8gxJHhu5MgZMO5bmcgY8OhIG5ow6JuLCBnaeG6o2kgdHLDrS4NCg0KYGBge3J9DQpnZ3Bsb3QoZGYsIGFlcyh4ID0gTWFyaXRhbFN0YXR1cywgZmlsbCA9IEhvbWVvd25lcikpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgbGFicyh0aXRsZSA9ICJU4buJIGzhu4cgY8OzIG5ow6AgdGhlbyBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4iLA0KICAgICAgIHggPSAiVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIiwgeSA9ICJU4buJIGzhu4ciLCBmaWxsID0gIkPDsyBuaMOgIHJpw6puZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQpOaOG6rW4geMOpdDoNCg0KcC12YWx1ZSA8MC4wMDEg4oaSIGPDsyBsacOqbiBo4buHIHLhuqV0IG3huqFuaC4NCg0KVHLDqm4gYmnhu4N1IMSR4buTLCBuaMOzbSDEkcOjIGvhur90IGjDtG4gY8OzIHBo4bqnbiBtw6B1IGJp4buDdSB0aOG7iyBDw7MgbmjDoCBs4bubbiBoxqFuIG5ow7NtIMSR4buZYyB0aMOibi4gxJBp4buBdSBuw6B5IHRy4buxYyBxdWFuIGto4bqzbmcgxJHhu4tuaCBuaOG6rW4geMOpdCDhu58gdHLDqm4uIENoaeG6v24gbMaw4bujYyBraW5oIGRvYW5oIGPDsyB0aOG7gyBraGFpIHRow6FjIHRow7RuZyB0aW4gbsOgeTogdsOtIGThu6UgbmjDs20ga2jDoWNoIMSRw6Mga+G6v3QgaMO0biBjw7MgdGjhu4MgcXVhbiB0w6JtIMSR4bq/biDEkeG7kyBnaWEgZOG7pW5nIGdpYSDEkcOsbmggaMahbiwgdHJvbmcga2hpIG5ow7NtIMSR4buZYyB0aMOibiBjw7MgdGjhu4MgdGjDrWNoIMSR4buTIGTDuW5nIGPDoSBuaMOibiwgZ2nhuqNpIHRyw60uDQoNCk5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biBjw7MgdOG7iSBs4buHIHPhu58gaOG7r3UgbmjDoCB+NzUlLCBzbyB24bubaSB+NDYlIOG7nyDEkeG7mWMgdGjDom4uDQoNCiMjIyAqKlJlbGF0aXZlIFJpc2sgY2hvIE1hcml0YWxTdGF0dXMgdnMgSG9tZW93bmVyKioNCg0KYGBge3J9DQojIFTDrW5oIFJlbGF0aXZlIFJpc2sNCnJpc2tfcmVzdWx0IDwtIHJpc2tyYXRpbyh0YWJfbWgpDQpyaXNrX3Jlc3VsdA0KDQpgYGANCk5ow7NtIMSRw6Mga+G6v3QgaMO0biBjw7Mgbmd1eSBjxqEgeOG6o3kgcmEgc+G7sSBraeG7h24gKG5ow7NtIOKAnEPDs+KAnSkgdGjhuqVwIGjGoW4gNTMuOCUgc28gduG7m2kgbmjDs20gxJHhu5ljIHRow6JuLg0KDQoNClJSID0gMC40NjI6IG5naMSpYSBsw6AgeMOhYyBzdeG6pXQgeOG6o3kgcmEgc+G7sSBraeG7h24g4bufIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biBjaOG7iSBi4bqxbmcgfjQ2JSBzbyB24bubaSBuZ8aw4budaSDEkeG7mWMgdGjDom4uDQoNCg0KS2hv4bqjbmcgdGluIGPhuq15IDk1JSBraMO0bmcgYmFvIGfhu5NtIDEsIG5naMSpYSBsw6Agc+G7sSBraMOhYyBiaeG7h3QgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqi4NCg0KIyMjICoqT2RkcyBSYXRpbyBjaG8gTWFyaXRhbFN0YXR1cyB2cyBIb21lb3duZXIqKg0KDQpgYGB7cn0NCiMgVMOtbmggT2RkcyBSYXRpbw0Kb3JfcmVzdWx0IDwtIG9kZHNyYXRpbyh0YWJfbWgpDQpvcl9yZXN1bHQNCmBgYA0KDQpYw6FjIHN14bqldCB44bqjeSByYSBow6BuaCB2aSDigJxDw7PigJ0g4bufIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biBjaOG7iSBi4bqxbmcgNDYuMiUgc28gduG7m2kgbmfGsOG7nWkgxJHhu5ljIHRow6JuLg0KDQoNCktob+G6o25nIHRpbiBj4bqteSA5NSUga2jDtG5nIGNo4bupYSAxLCBjaG8gdGjhuqV5IHPhu7Ega2jDoWMgYmnhu4d0IGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ouDQoNCg0KDQojIyAqKjQuMy4gQW5udWFsSW5jb21lIHZzIFByb2R1Y3RDYXRlZ29yeSoqDQoNCmBgYHtyfQ0KIyBM4bqleSA1IGNhdGVnb3J5IG5oaeG7gXUgbmjhuqV0IMSR4buDIG1pbmggaOG7jWENCnRvcF9jYXRzIDwtIGRmICU+JSBjb3VudChQcm9kdWN0Q2F0ZWdvcnkpICU+JSB0b3Bfbig1LCBuKSAlPiUgcHVsbChQcm9kdWN0Q2F0ZWdvcnkpDQpzdWIgPC0gZGYgJT4lIGZpbHRlcihQcm9kdWN0Q2F0ZWdvcnkgJWluJSB0b3BfY2F0cykNCnRhYl9pcCA8LSB0YWJsZShzdWIkQW5udWFsSW5jb21lLCBzdWIkUHJvZHVjdENhdGVnb3J5KQ0KY2hpc3FfaXAgPC0gY2hpc3EudGVzdCh0YWJfaXApDQp0YWJfaXA7IGNoaXNxX2lwDQoNCmBgYA0KDQpgYGB7cn0NCiAgZ2dwbG90KHN1YiwgYWVzKHggPSBBbm51YWxJbmNvbWUsIGZpbGwgPSBQcm9kdWN0Q2F0ZWdvcnkpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArDQogIGxhYnModGl0bGUgPSAiVOG7iSBs4buHIG5ow7NtIHPhuqNuIHBo4bqpbSBjb24gdGhlbyBUaHUgbmjhuq1wIiwNCiAgICAgICB4ID0gIlRodSBuaOG6rXAgaMOgbmcgbsSDbSIsIHkgPSAiVOG7iSBs4buHIiwgZmlsbCA9ICJQcm9kdWN0Q2F0ZWdvcnkiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCg0KYGBgDQoNCk5o4bqtbiB4w6l0Og0KDQpwLXZhbHVlIDwwLjAwMSDihpIgQ2jhu6luZyB04buPIHRodSBuaOG6rXAgY8OzIOG6o25oIGjGsOG7n25nIMSRw6FuZyBr4buDIMSR4bq/biBsb+G6oWkgc+G6o24gcGjhuqltIG3DoCBuZ8aw4budaSB0acOqdSBkw7luZyBtdWEuIEvhur90IHF14bqjIHRo4buRbmcga8OqIGzDoCBjw7Mgw70gbmdoxKlhLg0KDQpUaHUgbmjhuq1wIOG6o25oIGjGsOG7n25nIMSR4bq/biBow6BuaCB2aSBtdWEgc+G6r20sIMSR4bq3YyBiaeG7h3Qg4bufIG5ow7NtIFNuYWNrIEZvb2RzLCBNZWF0IHbDoCBGcnVpdC4NCg0KTmfGsOG7nWkgY8OzIHRodSBuaOG6rXAgY2FvIGPDsyB4dSBoxrDhu5tuZyDEg24gbMOgbmggbeG6oW5oIGjGoW4gKMOtdCB0aOG7i3QsIG5oaeG7gXUgdHLDoWkgY8OieSwgc25hY2sgY2FvIGPhuqVwKS4NCg0KTmjDs20gc+G6o24gcGjhuqltIHRoaeG6v3QgeeG6v3UgbmjGsCByYXUgY+G7pyB2w6Agc+G7r2EgZ2nhu68gdmFpIHRyw7Ig4buVbiDEkeG7i25oIHRyb25nIHRpw6p1IGTDuW5nLg0KDQpOaMOzbSB0aHUgbmjhuq1wIGNhbyB0aMOtY2ggbXVhIGPDoWMgY2F0ZWdvcnkg4oCcSMOgbmcgY2FvIGPhuqVw4oCdIGjGoW4sIG5ow7NtIHRodSBuaOG6rXAgdGjhuqVwIMawdSB0acOqbiBjYXRlZ29yeSDigJxDxqEgYuG6o27igJ0uDQoNCioqKg0KDQojICoqUEjhuqZOIDUuIFThu5VuZyBr4bq/dCB2w6AgVGjhuqNvIGx14bqtbioqDQoNCioqKg0KDQojIyAqKjUuMS4gVMOzbSB04bqvdCBjaMOtbmgqKg0KDQpVbml2YXJpYXRlOiBUaOG7sWMgcGjhuqltLCBO4buvLCDEkOG7mWMgdGjDom4sIENo4bunIG5ow6AgY2hp4bq/bSDGsHUgdGjhur8uDQoNClByb3AgdGVzdDogVOG6pXQgY+G6oyB04buJIGzhu4cgxJHhu4F1IGtow6FjIGdp4bqjIHRodXnhur90IGJhbiDEkeG6p3UuDQoNCkJpdmFyaWF0ZToNCg0KR2nhu5tpIHTDrW5oIOG6o25oIGjGsOG7n25nIMSR4bq/biBs4buxYSBjaOG7jW4gbmjDs20gc+G6o24gcGjhuqltLg0KDQpIw7RuIG5ow6JuIHbDoCB0aHUgbmjhuq1wIGxpw6puIHF1YW4gbeG6rXQgdGhp4bq/dCDEkeG6v24ga2jhuqMgbsSDbmcgc+G7nyBo4buvdSBuaMOgIHbDoCBsb+G6oWkgc+G6o24gcGjhuqltLg0KDQoNClF1YSBwaMOibiB0w61jaCB0csOqbiwgY2jDum5nIHRhIHLDunQgcmEgbeG7mXQgc+G7kSBr4bq/dCBsdeG6rW4gY2jDrW5oOg0KKDEpIFThuqduIHN14bqldCB2w6AgdOG7tyBs4buHOiBO4buvIGdp4bubaSBjaGnhur9tIMawdSB0aOG6vyBuaOG6uSB0cm9uZyBt4bqrdSAoa2hv4bqjbmcgNTElKSwgcGjhuqduIGzhu5tuIGtow6FjaCBow6BuZyDEkeG7mWMgdGjDom4gdsOgIMSRYSBz4buRIGPDsyBuaMOgIHJpw6puZy4gQ8OhYyBt4bq3dCBow6BuZyBwaOG7lSBiaeG6v24gbmjhuqV0IGzDoCByYXUgY+G7pywgxJHhu5MgxINuIHbhurd0LCBz4bqjbiBwaOG6qW0gdOG7qyBz4buvYSwgdHLDoWkgY8OieSB2w6AgdGjhu4t0Lg0KKDIpIEtp4buDbSDEkeG7i25oIHThu4kgbOG7hzogQ8OhYyBraeG7g20gxJHhu4tuaCBwcm9wLnRlc3QgY2hvIHRo4bqleSBz4buxIGtow6FjIGJp4buHdCB04bu3IGzhu4cgcXVhbiBzw6F0IGzDoCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqICh2w60gZOG7pSwgNTElIG7hu68sIDYwJSBjw7MgbmjDoCwgNzIlIGzDoCBuaMOzbSBGb29kKSBzbyB24bubaSBnacOhIHRy4buLIGdp4bqjIMSR4buLbmggNTAlLiDEkGnhu4F1IG7DoHkga2jhurNuZyDEkeG7i25oIGPDoWMgY2jDqm5oIGzhu4djaCBnaeG7m2kgdMOtbmggdsOgIMawdSB0aOG6vyBj4bunYSBuaMOzbSB0aOG7sWMgcGjhuqltIMSRw6MgcXVhbiBzw6F0IOG7nyB0csOqbiBraMO0bmcgcGjhuqNpIGRvIG5n4bqrdSBuaGnDqm4uDQooMykgTeG7kWkgbGnDqm4gaOG7hyBoYWkgYmnhur9uOiBQaMOibiB0w61jaCBjaGktc3F1YXJlIGNobyB0aOG6pXkgY8OzIHPhu7EgcGjhu6UgdGh14buZYyBnaeG7r2EgY8OhYyBiaeG6v246IHbDrSBk4bulLCB04bu3IGzhu4cgc+G7nyBo4buvdSBuaMOgIGPhu6dhIG5hbSBjYW8gaMahbiBu4buvLCBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gY8OzIGto4bqjIG7Eg25nIHPhu58gaOG7r3UgbmjDoCBjYW8gaMahbiBuZ8aw4budaSDEkeG7mWMgdGjDom4uIE5nb8OgaSByYSwgbuG7ryBtdWEgdGjhu7FjIHBo4bqpbSBuaGnhu4F1IGjGoW4gKEZvb2QpLCB0cm9uZyBraGkgbmFtIG11YSBuaGnhu4F1IHPhuqNuIHBo4bqpbSBraMO0bmcgdGnDqnUgdGjhu6UgxJHGsOG7o2MgKE5vbi1Db25zdW1hYmxlKSBoxqFuLiBOaOG7r25nIG3hu5FpIHF1YW4gaOG7hyBuw6B5IGdpw7pwIGRvYW5oIG5naGnhu4dwIMSRaeG7gXUgY2jhu4luaCBjaGnhur9uIGzGsOG7o2MgdGhlbyBwaMOibiBraMO6YyBraMOhY2ggaMOgbmcuDQoNCiMjICoqNS4yLiBI4bqhbiBjaOG6vyoqDQoNCkLDoW8gY8OhbyBuw6B5IGPDsyBt4buZdCBz4buRIGjhuqFuIGNo4bq/LiBE4buvIGxp4buHdSBt4bqrdSBjaOG7iSB04burIG3hu5l0IGNodeG7l2kgc2nDqnUgdGjhu4sg4bufIGtodSB24buxYyBUw6J5IELhuq9jIEhvYSBL4buzIHbDoCBjaMawYSBwaOG6o24gw6FuaCDEkeG6t2MgdGjDuSBWaeG7h3QgTmFtLiBOaMOzbSBiaeG6v24gxJHhu4tuaCB0w61uaCBraMOhIHBob25nIHBow7ogbmjGsG5nIHbhuqtuIHRoaeG6v3UgdGjDtG5nIHRpbiBuaMawIMSR4buZIHR14buVaSwgbmdo4buBIG5naGnhu4dwIGhheSB0aOG7nWkgZ2lhbiBtdWEgc+G6r20uIEPDoWMgcGjDom4gdMOtY2ggdHLDqm4gY2jGsGEgeMOpdCDEkeG6v24gbeG7kWkgbGnDqm4gaOG7hyDEkeG7i25oIHTDrW5oIC0gxJHhu4tuaCBsxrDhu6NuZyAodsOtIGThu6Uga+G6v3QgaOG7o3AgduG7m2kgZG9hbmggdGh1IGhheSBz4buRIGzGsOG7o25nIG11YSksIGhheSDhuqNuaCBoxrDhu59uZyBj4bunYSB54bq/dSB04buRIHRo4budaSBnaWFuIChtw7lhIHbhu6UsIGzhu4UgVOG6v3QpLg0KDQpWw6AgZOG7ryBsaeG7h3UgdOG7qyBN4bu5L0NhbmFkYS9NZXhpY28sIGNo4buJIG1hbmcgdMOtbmggdGhhbSBraOG6o28gc28gduG7m2kgVmnhu4d0IE5hbS4NCg0KDQoNCiMjICoqNS4zLiDEkOG7gSB4deG6pXQqKg0KDQpU4burIGvhur90IHF14bqjIHbDoCBo4bqhbiBjaOG6vyB0csOqbiwgY8OzIHRo4buDIMSR4buBIHh14bqldCBt4buZdCBz4buRIGNoaeG6v24gbMaw4bujYzoNCg0KKDEpIFThuq1wIHRydW5nIHBow6F0IHRyaeG7g24gdsOgIHF14bqjbmcgYsOhIG5ow7NtIHRo4buxYyBwaOG6qW0gLSBuaHUgeeG6v3UgcGjhuqltLCB2w6wgxJHDonkgbMOgIG3hurd0IGjDoG5nIGNo4bunIGzhu7FjLCDEkeG6t2MgYmnhu4d0IGtoaSDEkeG7kWkgdMaw4bujbmcga2jDoWNoIGjDoG5nIGPDsyB0aHUgbmjhuq1wIHRydW5nIGLDrG5oLiBWw60gZOG7pTogY2jGsMahbmcgdHLDrG5oIGtodXnhur9uIG3Do2kgcmF1IGPhu6csIHRyw6FpIGPDonkgdGhlbyB0deG6p24uDQooMikgUGjDom4ga2jDumMga2jDoWNoIGjDoG5nIHRoZW8gZ2nhu5tpIHTDrW5oIHbDoCB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom46IHBo4bulIG7hu68gdsOgIG5nxrDhu51pIMSR4buZYyB0aMOibiBjaHXhu5luZyBtdWEgdGjhu7FjIHBo4bqpbSBjw6EgbmjDom4sIHRyb25nIGtoaSBuYW0gZ2nhu5tpIHbDoCBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gY8OzIHRo4buDIHF1YW4gdMOibSBuaGnhu4F1IMSR4bq/biBjw6FjIG3hurd0IGjDoG5nIGdpYSDEkcOsbmgsIHRoaeG6v3QgYuG7iyBu4buZaSB0aOG6pXQuIERvYW5oIG5naGnhu4dwIGPDsyB0aOG7gyB0aGnhur90IGvhur8gxrB1IMSRw6NpIHJpw6puZyBjaG8gdOG7q25nIG5ow7NtLg0KKDMpIMSQ4buRaSB24bubaSB0aOG7iyB0csaw4budbmcgVmnhu4d0IE5hbSwgY+G6p24gdGh1IHRo4bqtcCB0aMOqbSBk4buvIGxp4buHdSDEkeG6t2MgdGjDuSAodHXhu5VpIHTDoWMsIHbhu4sgdHLDrSBraW5oIHThur8geMOjIGjhu5lpLCB2xINuIGjDs2EpIMSR4buDIHTDuXkgY2jhu4luaCBjaGnhur9uIGzGsOG7o2MgcGjDuSBo4bujcC4gVsOtIGThu6Ug4bufIFZp4buHdCBOYW0sIHRodSBuaOG6rXAgYsOsbmggcXXDom4gdGjhuqVwIGjGoW4gdsOgIHRow7NpIHF1ZW4gdGnDqnUgZMO5bmcga2jDoWMgbsOqbiBjw7MgdGjhu4MgdOG6rXAgdHJ1bmcgdsOgbyBjw6FjIG3hurd0IGjDoG5nIGdpw6EgbeG7gW0gcGjDuSBo4bujcCB24bubaSBuaGnhu4F1IG5ow7NtIGtow6FjaC4NCg0KIyMgKio1LjQuIEPDonUgaOG7j2kgbeG7nyoqDQoNCigxKSDhuqJuaCBoxrDhu59uZyBtw7lhIHbhu6UgKEx1bmFyIE5ldyBZZWFyLCBCbGFjayBGcmlkYXkpPw0KDQooMikgUGjDom4ga2jDumMgdGhlbyB0deG7lWkgJiBow6BuaCB2aSBvbmxpbmUgdnMgb2ZmbGluZT8NCg0KKDMpIE3DtCBow6xuaCBk4buxIMSRb8OhbiBDTFYgKEN1c3RvbWVyIExpZmV0aW1lIFZhbHVlKT8NCg0KKDQpIEPDsyBtw7QgaMOsbmggxJHhu4tuaCBsxrDhu6NuZyBuw6BvIHBow7kgaOG7o3AgxJHhu4MgZOG7sSDEkW/DoW4gZG9hbmggdGh1IGThu7FhIHbDoG8gbmjDom4ga2jhuql1IGjhu41jPyANCg0KKDUpIEPDoWMgeeG6v3UgdOG7kSB2xINuIGjDs2EgLSB4w6MgaOG7mWkgKG5oxrAgeHUgaMaw4bubbmcgdGnDqnUgZMO5bmcg4bufIHRow6BuaCB0aOG7iyB2cyBuw7RuZyB0aMO0bikg4bqjbmggaMaw4bufbmcgcmEgc2FvPyANCg0KTmdoacOqbiBj4bupdSB0aMOqbSBjw6FjIGPDonUgaOG7j2kgbsOgeSBz4bq9IGdpw7pwIGRvYW5oIG5naGnhu4dwIHThu5FpIMawdSBow7NhIGNoaeG6v24gbMaw4bujYyBkw6BpIGjhuqFuLg0KDQoqKioNCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXIiPg0KDQojICoqLS0tIE5ISeG7hk0gVuG7pCBUVeG6pk4gMSAtLS0qKiANCg0KPC9kaXY+DQoNCioqKg0KDQoqKk5oaeG7h20gduG7pSB0deG6p24gMToqKg0KDQoxLiBUw7NtIHThuq90IGN14buRbiBzw6FjaDogMjAxOV9HZW5lcmFsaXplZCBMaW5lYXIgTW9kZWxzIFdpdGggRXhhbXBsZXMgaW4gUl85NzgxNDQxOTAxMTcwLnBkZiAoxJHDoyBn4butaSB0cm9uZyBt4bulYyBmaWxlKS4NCjIuIFRo4buxYyBoaeG7h24gdGjhu5FuZyBrw6ogbcO0IHThuqMgY2hvIGPDoWMgYmnhur9uIHRyb25nIGZpbGU6IFN1cGVybWFya2V0IFRyYW5zYWN0aW9ucy5jc3YgKCDEkcOjIGfhu61pIHRyb25nIG3hu6VjIGZpbGUpDQoNCioqKg0KDQojICoqVMOzbSB04bqvdCDigJxHZW5lcmFsaXplZCBMaW5lYXIgTW9kZWxzIFdpdGggRXhhbXBsZXMgaW4gUioqDQoNCioqKg0KDQpDdeG7kW4gc8OhY2ggR2VuZXJhbGl6ZWQgTGluZWFyIE1vZGVscyBXaXRoIEV4YW1wbGVzIGluIFIgY+G7p2EgUGV0ZXIgSy4gRHVubiB2w6AgR29yZG9uIEsuIFNteXRoICgyMDE4KSBsw6AgbeG7mXQgdMOgaSBsaeG7h3UgdGjhu5FuZyBrw6ogxJHhuqd5IMSR4bunLCB0csOsbmggYsOgeSBraHVuZyBjaHVuZyBj4bunYSBjw6FjIG3DtCBow6xuaCB0dXnhur9uIHTDrW5oIHThu5VuZyBxdcOhdCAoR0xNKSBjw7luZyBjw6FjIHbDrSBk4bulIG1pbmggaOG7jWEgdGjhu7FjIGhp4buHbiBi4bqxbmcgbmfDtG4gbmfhu68gUi4g4buobmcgZOG7pW5nIGPhu6dhIEdMTSBy4bqldCBy4buZbmcsIGJhbyBn4buTbSBo4buTaSBxdXkgdHV54bq/biB0w61uaCB0aMO0bmcgdGjGsOG7nW5nLCBo4buTaSBxdXkgbG9naXN0aWMsIGPDoWMgbcO0IGjDrG5oIMSR4bq/bSAoUG9pc3Nvbiwgw6JtKSwgZOG7ryBsaeG7h3UgbGnDqm4gdOG7pWMgZMawxqFuZyAoR2FtbWEsIEludmVyc2UgR2F1c3NpYW4pLCB2w6AgY+G6oyB0dXnhur9uIHTDrW5oIHThu5VuZyBxdcOhdCBUd2VlZGllLiBTw6FjaCB0csOsbmggYsOgeSBraMOhaSBuaeG7h20gY8ahIGLhuqNuLCBwaMawxqFuZyBwaMOhcCDGsOG7m2MgbMaw4bujbmcgdsOgIGtp4buDbSDEkeG7i25oLCBjw7luZyBjw6FjIHbhuqVuIMSR4buBIGNo4bqpbiDEkW/DoW4sIHRoZW8gxJHDum5nIHRyw6xuaCB04buxIHThu6tuZyBjaMawxqFuZy4gUGjhuqduIG3hu58gxJHhuqd1IHNhdSDEkcOieSB2w6AgbeG7l2kgY2jGsMahbmcgdGnhur9wIHRoZW8gc+G6vSB0w7NtIGzGsOG7o2MgbuG7mWkgZHVuZyBjaMOtbmgsIGPDtG5nIHRo4bupYyBxdWFuIHRy4buNbmcgdsOgIHbDrSBk4bulIFIgdMawxqFuZyDhu6luZyAoa2hpIGPDsykuIEPDoWMgY8O0bmcgdGjhu6ljIMSRxrDhu6NjIHRyw6xuaCBiw6B5IGTGsOG7m2kgZOG6oW5nIHRvw6FuIGjhu41jIGNhbmggZ2nhu69hIHbDoCBjw6FjIGto4buRaSBtw6MgUiDEkcaw4bujYyDEkeG7i25oIGThuqFuZyByw7UgcsOgbmcgxJHhu4MgZOG7hSB0aGFtIGto4bqjby4NCg0KKioqDQoNCiMjICoqQ2jGsMahbmcgMDogR0nhu5pJIFRISeG7hlUgQ0hVTkcqKg0KDQoqKioNCg0KTcO0IGjDrG5oIHR1eeG6v24gdMOtbmggdOG7lW5nIHF1w6F0IChHTE0pIGzDoCBt4buZdCBz4buxIHThu5VuZyBxdcOhdCBow7NhIGPhu6dhIG3DtCBow6xuaCBo4buTaSBxdXkgdHV54bq/biB0w61uaCBj4buVIMSRaeG7g24sIGNobyBwaMOpcCBsacOqbiBo4buHIHRoYW0gc+G7kSB0dXnhur9uIHTDrW5oIHbhu5tpIGJp4bq/biBwaOG6o24gaOG7k2kgdGjDtG5nIHF1YSBow6BtIGxpw6puIGvhur90LCDEkeG7k25nIHRo4budaSBjaG8gcGjDqXAgcGjGsMahbmcgc2FpIHBo4bulIHRodeG7mWMgdsOgbyBnacOhIHRy4buLIGvhu7MgduG7jW5nLiANCg0KQ+G7pSB0aOG7gywgdHJvbmcgR0xNLCB0YSBjw7MgYmEgdGjDoG5oIHBo4bqnbiBjaMOtbmg6IA0KDQooMSkgUGjDom4gcGjhu5FpIG5n4bqrdSBuaGnDqm4gY+G7p2EgYmnhur9uIMSRw6FwIOG7qW5nIHRodeG7mWMgaOG7jSBtxakgY+G6pXAgbeG7mXQgKHbDrSBk4bulOiBjaHXhuqluLCBuaOG7iyB0aOG7qWMsIFBvaXNzb24sIEdhbW1hLCDigKYpLg0KDQooMikgVOG7lSBo4bujcCB0dXnhur9uIHTDrW5oICRcZXRhID0gXG1hdGhiZntYfVxib2xkc3ltYm9se1xiZXRhfSQgZ+G7k20gY8OhYyBiaeG6v24gxJHhu5ljIGzhuq1wIHbDoCBo4buHIHPhu5Eg4bqpTi4NCg0KKDMpIEjDoG0gbGnDqm4ga+G6v3QgJGckIGxpw6puIGjhu4cga+G7syB24buNbmcgJFxtdT1FKFkpJCB24bubaSB04buVIGjhu6NwIHR1eeG6v24gdMOtbmggcXVhICRnKFxtdSk9XGV0YSQuIEdMTSBkbyBOZWxkZXIgdsOgIFdlZGRlcmJ1cm4gxJHhu4EgeHXhuqV0IMSRw6MgZMO5bmcgcGjGsMahbmcgcGjDoXAgdOG7lW5nIGLDrG5oIHBoxrDGoW5nIGzhurdwIGzhuqFpIGPDsyB0cuG7jW5nIHPhu5EgKElSTFMpIMSR4buDIMaw4bubYyBsxrDhu6NuZyBj4buxYyDEkeG6oWkgeMOhYyBzdeG6pXQgY2hvIHRoYW0gc+G7kS4NCg0KVHJvbmcgY8OhYyBjaMawxqFuZyDEkeG6p3UsIHPDoWNoIGPFqW5nIG5o4bqvYyBs4bqhaSBjw6FjIGtow6FpIG5p4buHbSBjxqEgYuG6o24gduG7gSBtw7QgaMOsbmggdGjhu5FuZyBrw6o6IG3DtCBow6xuaCBiYW8gZ+G7k20gdGjDoG5oIHBo4bqnbiBo4buHIHRo4buRbmcgKHBo4bqnbiBjaGkgdGnhur90IGThu7EgxJFvw6FuIHRow7RuZyBxdWEgJFxtYXRoYmZ7WH1cYm9sZHN5bWJvbHtcYmV0YX0kKSB2w6AgdGjDoG5oIHBo4bqnbiBuZ+G6q3Ugbmhpw6puIChwaOG6p24gc2FpIHPhu5EpLiBWw60gZOG7pSwgaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggY2h14bqpbiBjw7MgZOG6oW5nOiANCiQkeV9pID0gXGJldGFfMCArIFxiZXRhXzEgeF97aTF9ICsgXGRvdHMgKyBcYmV0YV9wIHhfe2lwfSArIFx2YXJlcHNpbG9uX2ksXHF1YWQgXHZhcmVwc2lsb25faSBcc2ltIE4oMCxcc2lnbWFeMikkJA0KDQpUw6FjIGdp4bqjIG5o4bqlbiBt4bqhbmggdmnhu4djIHRy4buxYyBxdWFuIGjDs2EgZOG7ryBsaeG7h3UgKHbhur0gxJHhu5MgdGjhu4sgcGjDom4gcGjhu5FpLCBiaeG7g3UgxJHhu5MgdOG6p24gc3XhuqV0LCDigKYpIMSR4buDIGhp4buDdSBt4bqrdSB0csaw4bubYyBraGkgeMOieSBtw7QgaMOsbmgsIGPFqW5nIG5oxrAgbcOjIGjDs2EgYmnhur9uIHBow6JuIGxv4bqhaSB0aMOgbmggYmnhur9uIGdp4bqjIChkdW1teSB2YXJpYWJsZXMpIMSR4buDIMSRxrBhIHbDoG8gbcO0IGjDrG5oIHR1eeG6v24gdMOtbmguIE3hu6VjIHRpw6p1IGPhu6dhIG3DtCBow6xuaCBsw6AgxJHDoW5oIGdpw6EgdsOgIGThu7EgxJFvw6FuLCDEkcaw4bujYyB4ZW0geMOpdCBxdWEgaGFpIHRpw6p1IGNow60gY2jhu6cgeeG6v3U6IHTDrW5oIGNow61uaCB4w6FjIChhY2N1cmFjeSkgdsOgIMSR4buZIGfhu41uIGfDoG5nIChwYXJzaW1vbnkpIGPhu6dhIG3DtCBow6xuaC4gDQrEkOG7k25nIHRo4budaSwgY+G6p24gbMawdSDDvSBnaeG7m2kgaOG6oW4gY+G7p2EgbcO0IGjDrG5oOiB2w60gZOG7pSwgdGEga2jDoWMgYmnhu4d0IGdp4buvYSBk4buvIGxp4buHdSBxdWFuIHPDoXQgKG9ic2VydmF0aW9uYWwpIHbDoCBk4buvIGxp4buHdSB0aOG7sWMgbmdoaeG7h20gKGV4cGVyaW1lbnRhbCkga2hpIHLDunQgcmEga+G6v3QgbHXhuq1uLCB2w6AgY+G6p24ga2nhu4NtIHRyYSB0w61uaCBraMOhaSBxdcOhdCBj4bunYSBtw7QgaMOsbmggcmEgbmdvw6BpIG3huqt1LiANClRyb25nIGdp4bubaSB0aGnhu4d1IG7DoHksIHTDoWMgZ2nhuqMgY8WpbmcgY3VuZyBj4bqlcCBt4buZdCBz4buRIGNo4buJIGThuqtuIHPGoSBi4buZIHbhu4EgY8OhY2ggc+G7rSBk4bulbmcgUiDEkeG7gyBwaMOibiB0w61jaCwgY2jhu4kgcmEgbmhp4buBdSBow6BtIGPGoSBi4bqjbiBuaMawIGxtKCkgdsOgIGdsbSgpIHbDoCBjw6FjaCDEkeG7jWMga+G6v3QgcXXhuqMsIG5o4bqxbSBnacO6cCBzaW5oIHZpw6puIGzDoG0gcXVlbiB24bubaSBjw7RuZyBj4bulIHTDrW5oIHRvw6FuLg0KDQoqKioNCg0KIyMgKipDaMawxqFuZyAxOiBTdGF0aXN0aWNhbCBNb2RlbHMqKg0KDQoqKioNCg0KIyMjICoqMS4xLiBU4buVbmcgcXVhbioqDQoNClRyb25nIGNoxrDGoW5nIG7DoHksIHTDoWMgZ2nhuqMgZ2nhu5tpIHRoaeG7h3Uga2jDoWkgbmnhu4dtIG3DtCBow6xuaCB0aOG7kW5nIGvDqiBuaMawIGzDoCBt4buZdCBjw7RuZyBj4bulIMSR4buDIG3DtCB04bqjIGThu68gbGnhu4d1IHRo4buxYyBuZ2hp4buHbS4gTcO0IGjDrG5oIHRo4buRbmcga8OqIGPDsyBoYWkgdGjDoG5oIHBo4bqnbjogdGjDoG5oIHBo4bqnbiBuZ+G6q3Ugbmhpw6puIChtw7QgdOG6oyBjw6FjaCBk4buvIGxp4buHdSBwaMOhdCBzaW5oIHRow7RuZyBxdWEgcGjDom4gcGjhu5FpIHjDoWMgc3XhuqV0KSB2w6AgdGjDoG5oIHBo4bqnbiBo4buHIHRo4buRbmcgKG3DtCB04bqjIGPDoWMgeeG6v3UgdOG7kSBnaeG6o2kgdGjDrWNoIOG6o25oIGjGsOG7n25nIMSR4bq/biBiaeG6v24gcGjhu6UgdGh14buZYykuIE3hu5dpIHF1YW4gc8OhdCDEkcaw4bujYyBnaeG6oyDEkeG7i25oIHNpbmggcmEgdOG7qyBt4buZdCBwaMOibiBwaOG7kWkgeMOhYyBzdeG6pXQgeMOhYyDEkeG7i25oLCB2w60gZOG7pSBt4buZdCBwaMOibiBwaOG7kWkgY2h14bqpbiB24bubaSBwaMawxqFuZyBzYWkga2jDtG5nIMSR4buVaSB0cm9uZyBtw7QgaMOsbmggaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggY8ahIGLhuqNuLiBDaMawxqFuZyBuw6B5IG5o4bqlbiBt4bqhbmggcuG6sW5nICJt4buNaSBtw7QgaMOsbmggxJHhu4F1IHNhaSwgbmjGsG5nIG3hu5l0IHPhu5EgcuG6pXQgaOG7r3Ugw61jaCIgKEJveCAmIERyYXBlciksIG5naMSpYSBsw6AgbcO0IGjDrG5oIGNo4buJIGzDoCB44bqlcCB44buJIHRo4buxYyB04bq/LiBDw6FjIHRodeG6rXQgbmfhu68gcXVhbiB0cuG7jW5nIGJhbyBn4buTbSBiaeG6v24gcGjhu6UgdGh14buZYyAoaG/hurdjIGJp4bq/biBwaOG6o24gaOG7k2kpLCBiaeG6v24gZ2nhuqNpIHRow61jaCAoY292YXJpYXRlcyksIHbDoCB0aGFtIHPhu5EgbcO0IGjDrG5oLiBUw6FjIGdp4bqjIGPFqW5nIMSR4buBIGPhuq1wIMSR4bq/biBjw6FjaCB4w6J5IGThu7FuZyBtw7QgaMOsbmggaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggY8ahIGLhuqNuOiB2w60gZOG7pSwgcGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSDEkcahbiBnaeG6o24gJCR5X2kgPSBcYmV0YV8wICsgXGJldGFfMSB4X2kgKyBcZXBzaWxvbl9pLFxxdWFkIFxlcHNpbG9uX2kgXHNpbSBOKDAsXHNpZ21hXjIpJCQNCg0KIyMjICoqMS4yLiBDw7RuZyB0aOG7qWMgY2jDrW5oKioNCg0KLSBNw7QgaMOsbmggaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggxJHGoW4gZ2nhuqNuOiAkeV9pID0gXGJldGFfMCArIFxiZXRhXzEgeF9pICsgXGVwc2lsb25faSxccXVhZCBcZXBzaWxvbl9pIFxzaW0gTigwLFxzaWdtYV4yKSQNCi0gVHJ1bmcgYsOsbmggY8OzIMSRaeG7gXUga2nhu4duOiAkRVt5X2l8eF9pXSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfaS4kDQotIFBoxrDGoW5nIHNhaSBj4bunYSBzYWkgc+G7kTogJFZhcihcZXBzaWxvbl9pKSA9IFxzaWdtYV4yLiQNCg0KIyMjICoqMS4zLiBWw60gZOG7pSBSKioNCg0KYGBge3J9DQojIFbDrSBk4bulIG3DtCBow6xuaCBo4buTaSBxdXkgdHV54bq/biB0w61uaCB0csOqbiBk4buvIGxp4buHdSBtdGNhcnMNCmRhdGEobXRjYXJzKQ0KZml0IDwtIGxtKG1wZyB+IHd0ICsgaHAsIGRhdGEgPSBtdGNhcnMpDQpzdW1tYXJ5KGZpdCkNCmBgYA0KDQpUcm9uZyB2w60gZOG7pSB0csOqbiwgbG0oKSDEkcaw4bujYyBkw7luZyDEkeG7gyBraOG7m3AgbcO0IGjDrG5oIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIGdp4buvYSBiaeG6v24gdGnDqnUgdGjhu6Ugbmhpw6puIGxp4buHdSBtcGcgdsOgIGPDoWMgYmnhur9uIGdp4bqjaSB0aMOtY2ggd3QgKHRy4buNbmcgbMaw4bujbmcgeGUpIHbDoCBocCAoY8O0bmcgc3XhuqV0KS4gS+G6v3QgcXXhuqMgc3VtbWFyeShmaXQpIGNobyBiaeG6v3QgaOG7hyBz4buRIMaw4bubYyBsxrDhu6NuZywgc2FpIHPhu5EgY2h14bqpbiB2w6AgY8OhYyBnacOhIHRy4buLIHAtdmFsdWUuDQoNCioqR2hpIGNow7oqKg0KDQotIE3hu5dpIG3DtCBow6xuaCB0aOG7kW5nIGvDqiBj4bqnbiB4w6FjIMSR4buLbmggcsO1IHBow6JuIHBo4buRaSBnaeG6oyDEkeG7i25oIGPhu6dhIGThu68gbGnhu4d1ICh0aMOgbmggcGjhuqduIG5n4bqrdSBuaGnDqm4pIHbDoCBk4bqhbmcgY+G7p2EgdGjDoG5oIHBo4bqnbiBo4buHIHRo4buRbmcgKGxpbmVhciBwcmVkaWN0b3IpLg0KLSBUcm9uZyBo4buTaSBxdXkgdHV54bq/biB0w61uaCwgdGEgdGjGsOG7nW5nIGdp4bqjIMSR4buLbmggcGjDom4gcGjhu5FpIGNodeG6qW4gY2hvIHNhaSBz4buRIHbDoCBtw7QgaMOsbmggdHV54bq/biB0w61uaCBjaG8gdHJ1bmcgYsOsbmguDQotIFZp4buHYyBraeG7g20gdHJhIGJp4buDdSDEkeG7kyBk4buvIGxp4buHdSBiYW4gxJHhuqd1IChoaXN0b2dyYW0sIHNjYXR0ZXJwbG90KSBsw6AgcXVhbiB0cuG7jW5nIMSR4buDIGNo4buNbiBtw7QgaMOsbmggdGjDrWNoIGjhu6NwLg0KDQoqKioNCg0KIyMgKipDaMawxqFuZyAyOiBMaW5lYXIgUmVncmVzc2lvbiBNb2RlbHMqKg0KDQoqKioNCg0KIyMjICoqMi4xLiBU4buVbmcgcXVhbioqDQoNCkNoxrDGoW5nIG7DoHkgbeG7nyBy4buZbmcgdOG7qyBo4buTaSBxdXkgdHV54bq/biB0w61uaCDEkcahbiBnaeG6o24gc2FuZyBo4buTaSBxdXkgdHV54bq/biB0w61uaCDEkWEgYmnhur9uLiBN4bulYyB0acOqdSBsw6AgdMOsbSBjw6FjIGjhu4cgc+G7kSAkXGJldGFfaiQgdOG7kWkgxrB1ICh0aGVvIHRpw6p1IGNow60gYsOsbmggcGjGsMahbmcgdOG7kWkgdGnhu4N1KSB0aOG7j2EgbcOjbjogJCRFW3lfaXxcbWF0aGJme3h9aV0gPSBcYmV0YV8wICsgXGJldGFfMSB4e2kxfSArIFxkb3RzICsgXGJldGFfcCB4X3tpcH0uJCQNCg0KUXXDoSB0csOsbmggxrDhu5tjIGzGsOG7o25nIHRoxrDhu51uZyBk4buxYSB0csOqbiBwaMOpcCBiw6xuaCBwaMawxqFuZyB04buRaSB0aeG7g3UgKE9MUyksIGNobyB0YSBuZ2hp4buHbSBk4bqhbmcgxJHDs25nICRcaGF0e1xib2xkc3ltYm9se1xiZXRhfX0gPSAoWF5UWCleey0xfVheVCB5JC4gQ2jGsMahbmcgY8WpbmcgxJHhu4EgY+G6rXAgxJHhur9uIGPDoWNoIMaw4bubYyBsxrDhu6NuZyBwaMawxqFuZyBzYWkgJFxzaWdtYV4yJCB2w6Agc2FpIHPhu5EgY2h14bqpbiBj4bunYSBjw6FjIGjhu4cgc+G7kS4NCg0KIyMjICoqMi4yLiBDw7RuZyB0aOG7qWMgY2jDrW5oKioNCg0KLSBE4buxIMSRb8OhbiB0cm9uZyBo4buTaSBxdXkgdHV54bq/biB0w61uaDogJFxoYXR7eX1faSA9IFxoYXR7XGJldGF9MCArIFxzdW17aj0xfV5wIFxoYXR7XGJldGF9aiB4e2lqfS4kDQotIEPDtG5nIHRo4bupYyDGsOG7m2MgbMaw4bujbmcgT0xTOiAkXGhhdHtcYm9sZHN5bWJvbHtcYmV0YX19ID0gKFheVCBYKV57LTF9IFheVCBcbWF0aGJme3l9LiQNCi0gxq/hu5tjIGzGsOG7o25nIHBoxrDGoW5nIHNhaTogJFxoYXR7XHNpZ21hfV4yID0gXGZyYWN7MX17bi1wLTF9XHN1bV97aT0xfV5uICh5X2kgLSBcaGF0e3l9X2kpXjIuJA0KIA0KIyMjICoqMi4zLiBWw60gZOG7pSBSKioNCg0KYGBge3J9DQojIEjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIMSRYSBiaeG6v24gduG7m2kgdOG6rXAgZOG7ryBsaeG7h3UgaXJpcyAodsOtIGThu6UgbWluaCBo4buNYSkNCmRhdGEoaXJpcykNCmZpdDIgPC0gbG0oU2VwYWwuTGVuZ3RoIH4gU2VwYWwuV2lkdGggKyBQZXRhbC5MZW5ndGggKyBQZXRhbC5XaWR0aCwgZGF0YSA9IGlyaXMpDQpzdW1tYXJ5KGZpdDIpDQpgYGANCg0KVHJvbmcgdsOtIGThu6UgdHLDqm4sIGNow7puZyB0YSBz4butIGThu6VuZyBsbSgpIHbhu5tpIG5oaeG7gXUgYmnhur9uIGdp4bqjaSB0aMOtY2ggxJHhu4MgZOG7sSDEkW/DoW4gxJHhu5kgZMOgaSBsw6EuIEvhur90IHF14bqjIGNobyB0aOG6pXkgY8OhYyBo4buHIHPhu5EgxrDhu5tjIGzGsOG7o25nLCBzYWkgc+G7kSB2w6AgJFJeMiQgdOG7lW5nIHRo4buDLg0KDQoqKkdoaSBjaMO6KioNCg0KLSBI4buHIHPhu5EgeMOhYyDEkeG7i25oICRSXjIkIMSRbyBsxrDhu51uZyB04bu3IGzhu4cgYmnhur9uIHRoacOqbiBj4bunYSBk4buvIGxp4buHdSDEkcaw4bujYyBtw7QgaMOsbmggZ2nhuqNpIHRow61jaC4NCi0gUGjDqXAgxrDhu5tjIGzGsOG7o25nIE9MUyBi4bqldCBiaeG6v24gbuG6v3UgY8OhYyBnaeG6oyDEkeG7i25oIHZpIHNhaSAoaG9tby1zY2VkYXN0aWNpdHkpIHbDoCBraMO0bmcgc2FpIGzhu4djaCBu4bq/dSBzYWkgc+G7kSBjw7Mga+G7syB24buNbmcgYuG6sW5nIDAuDQotIE7hur91IHThu5NuIHThuqFpIMSRYSBj4buZbmcgdHV54bq/biAoY8OhYyBiaeG6v24gZ2nhuqNpIHRow61jaCB0xrDGoW5nIHF1YW4gY2FvKSwgcGjDqXAgJChYXlRYKV57LTF9JCBjw7MgdGjhu4Mga2jDtG5nIOG7lW4gxJHhu4tuaCB2w6AgY+G6p24gbG/huqFpIGLhu48gYmnhur9uIGhv4bq3YyBz4butIGThu6VuZyBr4bu5IHRodeG6rXQgxJFp4buBdSBjaHXhuqluIChyZWd1bGFyaXphdGlvbikuDQoNCioqKg0KDQojIyAqKkNoxrDGoW5nIDM6IExpbmVhciBSZWdyZXNzaW9uIE1vZGVsczogRGlhZ25vc3RpY3MgYW5kIE1vZGVsLUJ1aWxkaW5nKioNCg0KKioqDQoNCiMjIyAqKjMuMS4gVOG7lW5nIHF1YW4qKg0KDQpDaMawxqFuZyBuw6B5IHThuq1wIHRydW5nIHbDoG8gY2jhuqluIMSRb8OhbiBtw7QgaMOsbmggdsOgIGNoaeG6v24gbMaw4bujYyB4w6J5IGThu7FuZyBtw7QgaMOsbmggY2hvIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oLiBN4bulYyDEkcOtY2ggbMOgIMSRw6FuaCBnacOhIGNo4bqldCBsxrDhu6NuZyBj4bunYSBtw7QgaMOsbmggxJHDoyBraOG7m3AsIHBow6F0IGhp4buHbiBjw6FjIHF1YW4gc8OhdCBuZ2/huqFpIGxhaSAob3V0bGllcnMpIGhv4bq3YyDhuqNuaCBoxrDhu59uZyBs4bubbiAoaW5mbHVlbnRpYWwgcG9pbnRzKSwgdsOgIGtp4buDbSB0cmEgY8OhYyBnaeG6oyDEkeG7i25oICh0dXnhur9uIHTDrW5oLCBwaMOibiBwaOG7kWkgY2h14bqpbiBj4bunYSBzYWkgc+G7kSwgcGjGsMahbmcgc2FpIGtow7RuZyDEkeG7lWkpLiBDw6FjIGxv4bqhaSBzYWkgc+G7kSAocmVzaWR1YWwpIMSRxrDhu6NjIHPhu60gZOG7pW5nIGJhbyBn4buTbSBkxrAgc2FpIHPhu5EgKHJlc2lkdWFscyksIGTGsCBzYWkgc+G7kSBjaHXhuqluIGjDs2EgdsOgIMSR4buZIMSRbyBDb29rIChDb29rJ3MgZGlzdGFuY2UpLg0KDQojIyMgKiozLjIuIEPDtG5nIHRo4bupYyBjaMOtbmgqKg0KDQotIETGsCBzYWkgc+G7kSAocmVzaWR1YWwpOiAkcl9pID0geV9pIC0gXGhhdHt5fV9pLiQNCi0gRMawIGNodeG6qW4gaMOzYSAoc3RhbmRhcmRpemVkIHJlc2lkdWFsKTogJHJfaV5cYXN0ID0gXGZyYWN7cl9pfXtcaGF0e1xzaWdtYX0gXHNxcnR7MSAtIGhfe2lpfX19LCQgduG7m2kgJGhfe2lpfSQgbMOgIHBo4bqnbiB04butIGNow61uaCBj4bunYSBtYSB0cuG6rW4gbcWpIChoYXQgbWF0cml4KS4NCi0gxJDhuqFpIGzGsOG7o25nIENvb2sgKENvb2vigJlzIGRpc3RhbmNlKSDEkW8gbeG7qWMg4bqjbmggaMaw4bufbmcgY+G7p2EgcXVhbiBzw6F0IHRo4bupICRpJDoNCiREX2kgPSBcZnJhY3tyX2leMn17cCBcaGF0e1xzaWdtYX1eMn0gXGZyYWN7aF97aWl9fXsoMSAtIGhfe2lpfSleMn0sJA0KduG7m2kgJHAkIGzDoCBz4buRIHRoYW0gc+G7kSB0cm9uZyBtw7QgaMOsbmggKGvhu4MgY+G6oyBo4buHIHPhu5EgY2jhurduKS4NCg0KIyMjICoqMy4zLiBWw60gZOG7pSBSKioNCg0KYGBge3J9DQojIFbDrSBk4bulIHRy4buxYyBxdWFuIGjDs2EgY2jhuqluIMSRb8OhbiBo4buTaSBxdXkgdHLDqm4gbXRjYXJzDQpwYXIobWZyb3cgPSBjKDIsIDIpKQ0KcGxvdChmaXQpDQpgYGANCg0KxJBv4bqhbiBtw6MgdHLDqm4gdOG6oW8gcmEgNCDEkeG7kyB0aOG7iyBjxqEgYuG6o24gxJHhu4Mga2nhu4NtIHRyYSBjw6FjIGdp4bqjIMSR4buLbmggbcO0IGjDrG5oIGjhu5NpIHF1eTogxJHhu5MgdGjhu4sgZMawIHRoZW8gZ2nDoSB0cuG7iyBk4buxIMSRb8OhbiwgUS1RIHBsb3QgxJHhu4Mga2nhu4NtIHRyYSBwaMOibiBwaOG7kWkgY2h14bqpbiBj4bunYSBzYWkgc+G7kSwgxJHhu5MgdGjhu4sgU2NhbGUtTG9jYXRpb24gdsOgIMSR4buTIHRo4buLIOG6o25oIGjGsOG7n25nIChDb29rJ3MgZGlzdGFuY2UpLg0KDQoqKkdoaSBjaMO6KioNCi0gUXVhbiBzw6F0IG5nb+G6oWkgbGFpIGPDsyB0aOG7gyBsw6BtIHNhaSBs4buHY2gga+G6v3QgcXXhuqMgxrDhu5tjIGzGsOG7o25nOyBj4bqnbiBraeG7g20gdHJhIHJlc2lkdWFscyB2w6AgQ29vaydzIGRpc3RhbmNlIMSR4buDIHBow6F0IGhp4buHbi4NCi0gTuG6v3UgYmnhu4N1IMSR4buTIFEtUSBs4buHY2gga2jhu49pIMSRxrDhu51uZyB0aOG6s25nLCBwaMOibiBwaOG7kWkgc2FpIHPhu5EgY8OzIHRo4buDIGtow7RuZyBjaHXhuqluLg0KLSDEkOG7gyBj4bqjaSB0aGnhu4duIG3DtCBow6xuaCwgY8OzIHRo4buDIHRo4butIGNodXnhu4NuIMSR4buVaSBiaeG6v24gKHbDrSBk4bulIGxvZ2FyaXRobSkgaG/hurdjIGxv4bqhaSBi4buPIMSRaeG7g20gbmdv4bqhaSBsYWkgxJHDoW5nIGvhu4MuDQoNCioqKg0KDQojIyAqKkNoxrDGoW5nIDQ6IEJleW9uZCBMaW5lYXIgUmVncmVzc2lvbjogVGhlIE1ldGhvZCBvZiBNYXhpbXVtIExpa2VsaWhvb2QqKg0KDQoqKioNCg0KIyMjICoqNC4xLiBU4buVbmcgcXVhbioqDQoNCkNoxrDGoW5nIG7DoHkgbeG7nyBy4buZbmcga2jDoWkgbmnhu4dtIMaw4bubYyBsxrDhu6NuZyBraMO0bmcgY2jhu4kgZOG7sWEgdHLDqm4gcGjDom4gcGjhu5FpIGNodeG6qW4gdsOgIGLDrG5oIHBoxrDGoW5nIHThu5FpIHRp4buDdSwgbcOgIHPhu60gZOG7pW5nIHBoxrDGoW5nIHBow6FwIMaw4bubYyBsxrDhu6NuZyBj4buxYyDEkeG6oWkgaOG7o3AgbMO9IChNYXhpbXVtIExpa2VsaWhvb2QgRXN0aW1hdGlvbikgY2hvIGPDoWMgbcO0IGjDrG5oIHThu5VuZyBxdcOhdCBoxqFuLiBQaMawxqFuZyBwaMOhcCBuw6B5IHTDrG0gdGhhbSBz4buRICRcYm9sZHN5bWJvbHtcYmV0YX0kIHThu5FpIMawdSBi4bqxbmcgY8OhY2ggdOG7kWkgxJFhIGjDs2EgaMOgbSBo4bujcCBsw70gKGxpa2VsaWhvb2QpIGPhu6dhIGThu68gbGnhu4d1Og0KDQokJA0KTChcYm9sZHN5bWJvbHtcYmV0YX0pID0gXHByb2Rfe2k9MX1ebiBmKHlfaTsgXGJvbGRzeW1ib2x7XGJldGF9KSwNCiQkDQoNClRyb25nIMSRw7MgJGYoeV9pOyBcYm9sZHN5bWJvbHtcYmV0YX0pJCBsw6AgaMOgbSBt4bqtdCDEkeG7mS94w6FjIHN14bqldCBj4bunYSAkeV9pJC4gR2nhuqNpIHRodeG6rXQgcGjhu5UgYmnhur9uIMSR4buDIHTDrG0gxrDhu5tjIGzGsOG7o25nIGzDoCBwaMawxqFuZyBwaMOhcCBOZXd0b24tUmFwaHNvbiBob+G6t2MgSVJMUyAocGjGsMahbmcgcGjDoXAgbOG6t3AgY8OzIHRy4buNbmcgc+G7kSksIHPhur0gxJHGsOG7o2MgdHLDrG5oIGLDoHkgY2hpIHRp4bq/dCDhu58gY2jGsMahbmcgc2F1LiBDaMawxqFuZyBuw6B5IG1pbmggaOG7jWEgw70gdMaw4bufbmcgdHLDqm4gbeG7mXQgdsOtIGThu6UgaOG7k2kgcXV5IGxvZ2lzdGljIChk4buvIGxp4buHdSBuaOG7iyBwaMOibikuDQoNCiMjIyAqKjQuMi4gQ8O0bmcgdGjhu6ljIGNow61uaCoqDQoNCi0gSMOgbSBsb2ctaOG7o3AgbMO9IChsb2ctbGlrZWxpaG9vZCk6ICRcZWxsKFxib2xkc3ltYm9se1xiZXRhfSkgPSBcc3VtX3tpPTF9Xm4gXGxvZyBmKHlfaTsgXGJvbGRzeW1ib2x7XGJldGF9KS4kDQotIFBoxrDGoW5nIHBow6FwIGPhu7FjIMSR4bqhaSBo4bujcCBsw70gecOqdSBj4bqndSBnaeG6o2kgaOG7hzogJFxmcmFje1xwYXJ0aWFsIFxlbGx9e1xwYXJ0aWFsIFxiZXRhX2p9ID0gMCQgduG7m2kgbeG7jWkgJGokLg0KLSBWw60gZOG7pSB24bubaSBtw7QgaMOsbmggQmVybm91bGxpIChsb2dpc3RpYyk6IHjDoWMgc3XhuqV0ICRwX2kgPSBcZnJhY3tcZXhwKFxldGFfaSl9ezErXGV4cChcZXRhX2kpfSwgXHF1YWQgXGV0YV9pID0gXGJldGFfMCArIFxiZXRhXzEgeF9pLiQNCg0KIyMjICoqNC4zLiBWw60gZOG7pSBSKioNCg0KYGBge3J9DQojIFbDrSBk4bulIGjhu5NpIHF1eSBsb2dpc3RpYyB24bubaSBk4buvIGxp4buHdSBtdGNhcnMNCmxvZ2l0X21vZGVsIDwtIGdsbSh2cyB+IG1wZyArIHd0LCBkYXRhID0gbXRjYXJzLCBmYW1pbHkgPSBiaW5vbWlhbCkNCnN1bW1hcnkobG9naXRfbW9kZWwpDQpgYGANCg0KVHJvbmcgdsOtIGThu6UgbsOgeSwgZ2xtKC4uLiwgZmFtaWx5ID0gYmlub21pYWwpIMSRxrDhu6NjIGTDuW5nIMSR4buDIGto4bubcCBtw7QgaMOsbmggbG9naXN0aWMgduG7m2kgYmnhur9uIGvhur90IHF14bqjIG5o4buLIHBow6JuIHZzICgwIGhv4bq3YyAxKS4gS+G6v3QgcXXhuqMgY2hvIHRo4bqleSBo4buHIHPhu5EgbG9nLW9kZHMgxrDhu5tjIGzGsOG7o25nIHbDoCBnacOhIHRy4buLIHAtdmFsdWUgdMawxqFuZyDhu6luZy4NCg0KKipHaGkgY2jDuioqDQoNCi0gTcO0IGjDrG5oIGxvZ2lzdGljIGzDoCBt4buZdCB2w60gZOG7pSDEkWnhu4NuIGjDrG5oIGPhu6dhIEdMTSB24bubaSBwaMOibiBwaOG7kWkgQmVybm91bGxpIHbDoCBow6BtIGxpw6puIGvhur90IGxvZ2l0Lg0KUGjGsMahbmcgcGjDoXAgY+G7sWMgxJHhuqFpIGjhu6NwIGzDvSBjw7MgdGjhu4Mgw6FwIGThu6VuZyBjaG8gbmhp4buBdSBtw7QgaMOsbmggduG7m2kgcGjDom4gcGjhu5FpIGtow6FjIG5oYXUgKGtow7RuZyBjaOG7iSBwaMOibiBwaOG7kWkgY2h14bqpbikuDQotIEPGoSBz4bufIGPhu6dhIEdMTSBsw6Aga+G6v3QgaOG7o3AgcGjGsMahbmcgcGjDoXAgbsOgeSB24bubaSDDvSB0xrDhu59uZyBsacOqbiBr4bq/dCB0dXnhur9uIHTDrW5oIChsaW5lYXIgcHJlZGljdG9yKS4NCg0KKioqDQoNCiMjICoqQ2jGsMahbmcgNTogR2VuZXJhbGl6ZWQgTGluZWFyIE1vZGVsczogU3RydWN0dXJlKioNCg0KKioqDQoNCiMjIyAqKjUuMS4gVOG7lW5nIHF1YW4qKg0KDQpDaMawxqFuZyBuw6B5IMSR4buLbmggbmdoxKlhIGtow6FpIG5p4buHbSBNw7QgaMOsbmggdHV54bq/biB0w61uaCB04buVbmcgcXXDoXQgKEdMTSkuIEdMTSBiYW8gZ+G7k20gYmEgdGjDoG5oIHBo4bqnbiBjaMOtbmg6DQoNCi0gVGjDoG5oIHBo4bqnbiBuZ+G6q3Ugbmhpw6puIChSYW5kb20gY29tcG9uZW50KTogYmnhur9uIHBo4bqjbiBo4buTaSAkWSQgdHXDom4gdGhlbyBwaMOibiBwaOG7kWkgdGh14buZYyBo4buNIHBow6JuIHBo4buRaSBow6BtIG3FqSAoZXhwb25lbnRpYWwgZmFtaWx5KSwgY2jhurNuZyBo4bqhbiBwaMOibiBwaOG7kWkgY2h14bqpbiwgQmVybm91bGxpLCBQb2lzc29uLCBHYW1tYSzigKYNCi0gVGjDoG5oIHBo4bqnbiBo4buHIHRo4buRbmcgKFN5c3RlbWF0aWMgY29tcG9uZW50KTogbeG7mXQgdOG7lSBo4bujcCB0dXnhur9uIHTDrW5oIGPhu6dhIGPDoWMgYmnhur9uIGdp4bqjaSB0aMOtY2gsICRcZXRhX2kgPSBcYmV0YV8wICsgXGJldGFfMSB4X3tpMX0gKyBcY2RvdHMgKyBcYmV0YV9wIHhfe2lwfS4kDQotIEjDoG0gbGnDqm4ga+G6v3QgKExpbmsgZnVuY3Rpb24pOiBt4buZdCBow6BtICRnKFxjZG90KSQgbGnDqm4ga+G6v3QgZ2nDoSB0cuG7iyBr4buzIHbhu41uZyAkXG11X2kgPSBFW1lfaV0kIHbhu5tpIHByZWRpY3RvcjogJGcoXG11X2kpID0gXGV0YV9pJC4NCg0KVMO5eSB0aHXhu5ljIHbDoG8gcGjDom4gcGjhu5FpIGPhu6dhICRZJCwgdGEgY2jhu41uIGjDoG0gbGnDqm4ga+G6v3QgdGjDrWNoIGjhu6NwICh2w60gZOG7pTogbG9naXQgY2hvIEJlcm5vdWxsaSwgbG9nIGNobyBQb2lzc29uLCBpZGVudGl0eSBjaG8gY2h14bqpbiwuLi4pLiBHTE0gdOG7lW5nIHF1w6F0IGjDs2EgaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggYuG6sW5nIGPDoWNoIHRoYXkgdGjhur8gZ2nhuqMgxJHhu4tuaCBwaMOibiBwaOG7kWkgY2h14bqpbiB2w6AgbGnDqm4ga+G6v3QgdHV54bq/biB0w61uaCBxdWEgaMOgbSAkZyQuDQoNCiMjIyAqKjUuMi4gQ8O0bmcgdGjhu6ljIGNow61uaCoqDQoNCi0gSMOgbSBsacOqbiBr4bq/dCB04buVbmcgcXXDoXQ6ICQkZyhFW1lfaV0pID0gXGV0YV9pID0gXGJldGFfMCArIFxzdW1fe2o9MX1ecCBcYmV0YV9qIHhfe2lqfS4kJA0KDQoqKlbDrSBk4bulIGPDoWMgcGjDom4gcGjhu5FpIHRow7RuZyBk4bulbmc6KioNCg0KLSBDaHXhuqluIChHYXVzc2lhbik6ICRnKFxtdSk9XG11JCAoaWRlbnRpdHkpLCBwaMawxqFuZyBzYWkga2jDtG5nIHBo4bulIHRodeG7mWMgKGjhurFuZykuDQogDQotIEJlcm5vdWxsaS9CaW5vbWlhbDogJGcoXG11KT1cbWF0aHJte2xvZ2l0fShcbXUpJCwgJFZhcihZKT1cbXUoMS1cbXUpJC4NCiANCi0gUG9pc3NvbjogJGcoXG11KT1cbG9nKFxtdSkkLCAkVmFyKFkpPVxtdSQuDQogDQotIEdhbW1hOiAkZyhcbXUpPVxsb2coXG11KSQgaG/hurdjICRnKFxtdSk9MS9cbXUkLCAkVmFyKFkpPVxwaGkgXG11XjIkLg0KIA0KIyMjICoqNS4zLiBWw60gZOG7pSBSKioNCg0KYGBge3J9DQojIFbDrSBk4bulIEdMTTogc28gc8OhbmggbGluayBpZGVudGl0eSB2w6AgbGluayBsb2cNCnNldC5zZWVkKDEyMykNCnggPC0gcm5vcm0oMTAwKQ0KeSA8LSBleHAoMSArIDAuMyp4ICsgcm5vcm0oMTAwLCBzZCA9IDAuMikpICAjIHkgPiAwIGRvIGV4cA0KDQpnbG0xIDwtIGdsbSh5IH4geCwgZmFtaWx5ID0gZ2F1c3NpYW4obGluayA9ICJpZGVudGl0eSIpKQ0KZ2xtMiA8LSBnbG0oeSB+IHgsIGZhbWlseSA9IGdhdXNzaWFuKGxpbmsgPSAibG9nIikpDQoNCnN1bW1hcnkoZ2xtMSkNCnN1bW1hcnkoZ2xtMikNCg0KDQpgYGANCg0KxJBv4bqhbiBtw6MgdHLDqm4gdOG6oW8gZOG7ryBsaeG7h3UgZ2nhuqMgxJHhu4tuaCB2w6Aga2jhu5twIGhhaSBHTE0gduG7m2kgcGjDom4gcGjhu5FpIGNodeG6qW4gbmjGsG5nIGTDuW5nIGjDoG0gbGnDqm4ga+G6v3Qga2jDoWMgbmhhdSAoaWRlbnRpdHkgdsOgIGxvZykuIEvhur90IHF14bqjIGhp4buDbiB0aOG7iyBjw6FjIGjhu4cgc+G7kSDGsOG7m2MgbMaw4bujbmcgdMawxqFuZyDhu6luZy4NCg0KKipHaGkgY2jDuioqDQoNCi0gR0xNIG3hu58gcuG7mW5nIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIHRow7RuZyBxdWEgaMOgbSBsacOqbiBr4bq/dDogdsOtIGThu6UgbG9naXQgYmnhur9uIG3DtCBow6xuaCB0dXnhur9uIHTDrW5oIHRow6BuaCB4w6FjIHN14bqldC4NCi0gSMOgbSBwaMOibiB0w6FuICh2YXJpYW5jZSBmdW5jdGlvbikgJFYoXG11KSQgcGjhu6UgdGh14buZYyB2w6BvIG3hu5dpIHBow6JuIHBo4buRaTogdsOtIGThu6UgduG7m2kgUG9pc3NvbiwgJFYoXG11KT1cbXUkLg0KLSBUcm9uZyBSLCBmYW1pbHkgxJHhu4tuaCBuZ2jEqWEgY+G6oyBwaMOibiBwaOG7kWkgY+G7p2EgJFkkIHbDoCBow6BtIGxpw6puIGvhur90ICh2w60gZOG7pSBmYW1pbHk9cG9pc3NvbiB0xrDGoW5nIOG7qW5nIHbhu5tpIGxvZyBsaW5rKS4NCg0KKioqDQoNCiMjICoqQ2jGsMahbmcgNjogR2VuZXJhbGl6ZWQgTGluZWFyIE1vZGVsczpFc3RpbWF0aW9uKioNCg0KKioqDQoNCiMjIyAqKjYuMS4gVOG7lW5nIHF1YW4qKg0KDQpDaMawxqFuZyBuw6B5IHRyw6xuaCBiw6B5IHBoxrDGoW5nIHBow6FwIHTDrW5oIHRvw6FuIGPDoWMgxrDhu5tjIGzGsOG7o25nIGPhu6dhIEdMTSwgdGjGsOG7nW5nIGLhurFuZyBwaMawxqFuZyBwaMOhcCBs4bq3cC4gRG8ga2jDtG5nIGPDsyBuZ2hp4buHbSDEkcOzbmcgY2hvIMaw4bubYyBsxrDhu6NuZyBj4buxYyDEkeG6oWkgaOG7o3AgbMO9IChuZ2/huqFpIHRy4burIHRyxrDhu51uZyBo4bujcCBHYXVzc2lhbiksIEdMTSB0aMaw4budbmcgxJHGsOG7o2MgxrDhu5tjIGzGsOG7o25nIGLhurFuZyBwaMawxqFuZyBwaMOhcCBJUkxTIChJdGVyYXRpdmVseSBSZXdlaWdodGVkIExlYXN0IFNxdWFyZXMpLiDDnSB0xrDhu59uZyBjxqEgYuG6o24gbMOgIGzhurdwIGzhuqFpIGPDtG5nIHRo4bupYyBnaeG7kW5nIE9MUyBuaMawbmcgduG7m2kgdHLhu41uZyBz4buRIHRoYXkgxJHhu5VpIHThuqFpIG3hu5dpIGLGsOG7m2MsIGNobyDEkeG6v24ga2hpIGjhu5lpIHThu6UuIENoxrDGoW5nIGPFqW5nIMSR4buBIGPhuq1wIMSR4bq/biBtYSB0cuG6rW4gRmlzaGVyIHRow7RuZyB0aW4gdsOgIGPDoWMgxJHhurdjIHRyxrBuZyB0aOG7kW5nIGvDqiBraMOhYyBwaOG7pWMgduG7pSBjaG8gxrDhu5tjIGzGsOG7o25nICh2w60gZOG7pSBtYSB0cuG6rW4gaGnhu4dwIHBoxrDGoW5nIHNhaSBj4bunYSDGsOG7m2MgbMaw4bujbmcpLg0KDQojIyMgKio2LjIuIEPDtG5nIHRo4bupYyBjaMOtbmgqKg0KDQotIFBoxrDGoW5nIHBow6FwIElSTFMgY+G6rXAgbmjhuq10IG5naGnhu4dtICRcYmV0YSQgdGhlbyBk4bqhbmc6DQokXGJldGFeeyh0KzEpfSA9IFxiZXRhXnsodCl9ICsgKFheVCBXXnsodCl9IFgpXnstMX0gWF5UIFdeeyh0KX0gKHpeeyh0KX0gLSBYXGJldGFeeyh0KX0pLCQNCnRyb25nIMSRw7MgJFdeeyh0KX0kIGzDoCBtYSB0cuG6rW4gdHLhu41uZyBz4buRIHThuqFpIGzhuqduIGzhurdwICR0JCwgdsOgICR6XnsodCl9JCBsw6AgYmnhur9uIHBo4bulIGjhu5NpIGdp4bqjIMSR4buLbmggKHdvcmtpbmcgcmVzcG9uc2UpLg0KDQotIE1hIHRy4bqtbiB0cuG7jW5nIHPhu5EgJFckIHRoxrDhu51uZyBsacOqbiBxdWFuIMSR4bq/biBow6BtIHBow6JuIHTDoW46IHbDrSBk4bulIHbhu5tpIHBow6JuIHBo4buRaSBQb2lzc29uLCAkV197aWl9ID0gXGhhdHtcbXV9X2kkLg0KDQotIE1hIHRy4bqtbiB0aMO0bmcgdGluIEZpc2hlciAkXG1hdGhjYWx7SX0oXGJldGEpJDogJFxtYXRoY2Fse0l9KFxiZXRhKSA9IFheVCBXIFguJA0KDQojIyMgKio2LjMuIFbDrSBk4bulIFIqKg0KDQpgYGB7cn0NCiMgVsOtIGThu6UgR0xNIG5o4buLIHRo4bupYyB0csOqbiBk4buvIGxp4buHdSBraeG7g3UgdGjDoG5oIGPDtG5nL3Ro4bqldCBi4bqhaQ0KZ2xtX21vZGVsIDwtIGdsbShjYmluZChTdWNjZXNzLCBGYWlsdXJlKSB+IHgsIGZhbWlseSA9IGJpbm9taWFsLA0KICAgICAgICAgICAgICAgICBkYXRhID0gZGF0YS5mcmFtZSh4ID0gMTo1LCBTdWNjZXNzID0gYygxLDIsMyw0LDUpLCBGYWlsdXJlID0gYyg5LDgsNyw2LDUpKSkNCnN1bW1hcnkoZ2xtX21vZGVsKQ0KDQpgYGANCg0K4bueIMSRw6J5LCBjaMO6bmcgdGEgZMO5bmcgZ2xtKCkgxJHhu4MgxrDhu5tjIGzGsOG7o25nIHbhu5tpIGThu68gbGnhu4d1IGThuqFuZyBz4buRIHRow6BuaCBjw7RuZy90aOG6pXQgYuG6oWkgY2hvIG3hu5dpIG3hu6ljICR4JC4gSMOgbSBnbG0gdOG7sSDEkeG7mW5nIHRo4buxYyBoaeG7h24gSVJMUyDEkeG7gyB0w6xtIGjhu4cgc+G7kSB04buRaSDGsHUuDQoNCioqR2hpIGNow7oqKg0KDQotIElSTFMgbMOgIHRodeG6rXQgdG/DoW4gbOG6t3AgxJFpIGzhurdwIGzhuqFpIGPDoWMgYsaw4bubYyBiw6xuaCBwaMawxqFuZyB04buRaSB0aeG7g3UgY8OzIHRy4buNbmcgc+G7kSwgY2hvIHBow6lwIMOhcCBk4bulbmcgT0xTIMSR4buDIHTDrG0gxrDhu5tjIGzGsOG7o25nIEdMTS4NCi0gR2nDoSB0cuG7iyBraOG7n2kgdOG6oW8gdGjGsOG7nW5nIMSRxrDhu6NjIGzhuqV5IHThu6sgaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggaG/hurdjIMaw4bubYyBsxrDhu6NuZyB0aMO0Lg0KLSBRdcOhIHRyw6xuaCBs4bq3cCBk4burbmcga2hpIHPhu7EgdGhheSDEkeG7lWkgY+G7p2EgxrDhu5tjIGzGsOG7o25nICRcYmV0YSQgbmjhu48gaMahbiBt4buZdCBuZ8aw4buhbmcgKHThu6ljIGjhu5lpIHThu6UpLg0KDQoqKioNCg0KIyMgKipDaMawxqFuZyA3OiBHZW5lcmFsaXplZCBMaW5lYXIgTW9kZWxzOiBJbmZlcmVuY2UqKg0KDQoqKioNCg0KIyMjICoqNy4xLiBU4buVbmcgcXVhbioqDQoNCkNoxrDGoW5nIG7DoHkgdGjhuqNvIGx14bqtbiBjw6FjIHBoxrDGoW5nIHBow6FwIGtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IHbDoCBzdXkgZGnhu4VuIHRyw6puIGPDoWMgbcO0IGjDrG5oIEdMTS4gSGFpIHBoxrDGoW5nIHBow6FwIHBo4buVIGJp4bq/biBsw6Aga2nhu4NtIMSR4buLbmggV2FsZCB2w6Aga2nhu4NtIMSR4buLbmggdOG7tyBs4buHIGjhu6NwIGzDvSAoTGlrZWxpaG9vZCBSYXRpbyBUZXN0LCBMUlQpLiBOZ2/DoGkgcmEsIHTDoWMgZ2nhuqMgxJHhu4EgY+G6rXAgxJHhur9uIGtob+G6o25nIHRpbiBj4bqteSAoY29uZmlkZW5jZSBpbnRlcnZhbHMpIHbDoCBraeG7g20gxJHhu4tuaCBjaGktc3F1YXJlZCBjaG8gZGV2aWFuY2UuIERldmlhbmNlIMSRxrDhu6NjIMSR4buLbmggbmdoxKlhIGzDoCBt4buZdCB0aMaw4bubYyDEkW8ga2hv4bqjbmcgY8OhY2ggZ2nhu69hIG3DtCBow6xuaCB24burYSBraOG7m3AgdsOgIG3DtCBow6xuaCBiw6NvIGjDsmEgKG3DtCBow6xuaCB04buRdCBuaOG6pXQgY8OzIHRo4buDKS4NCg0KIyMjICoqNy4yLiBDw7RuZyB0aOG7qWMgY2jDrW5oKioNCg0KLSBEZXZpYW5jZSB04buVbmc6ICREID0gMihcZWxsX3tcdGV4dHtzYXR9fSAtIFxlbGwoXGhhdHtcYmV0YX0pKS4kIE3hu5l0IGRldmlhbmNlIGzhu5tuIChzbyB24bubaSBi4bqtYyB04buxIGRvKSBjw7MgdGjhu4MgYsOhbyBoaeG7h3UgbcO0IGjDrG5oIGNoxrBhIHBow7kgaOG7o3AgdOG7kXQuDQotIEtp4buDbSDEkeG7i25oIFdhbGQ6ICRaX2ogPSBcZnJhY3tcaGF0e1xiZXRhfV9qfXtcbWF0aHJte1NFfShcaGF0e1xiZXRhfV9qKX0sJCBzbyBzw6FuaCB24bubaSBwaMOibiBwaOG7kWkgY2h14bqpbiAkTigwLDEpJC4NCi0gS2nhu4NtIMSR4buLbmggVOG7tyBs4buHOiAkR14yID0gMihcZWxsKFxoYXR7XGJldGF9e1x0ZXh0e2Z1bGx9fSkgLSBcZWxsKFxoYXR7XGJldGF9e1x0ZXh0e3JlZHVjZWR9fSkpLCQgc28gc8OhbmggduG7m2kgJFxjaGleMiQgduG7m2kgYuG6rWMgdOG7sSBkbyBi4bqxbmcgc+G7kSB0aGFtIHPhu5Ega2jDoWMgbmhhdSBnaeG7r2EgbcO0IGjDrG5oLg0KLSBLaG/huqNuZyB0aW4gY+G6rXkgV2FsZCBjaG8gdGhhbSBz4buROiAkXGhhdHtcYmV0YX1qIFxwbSB6e1xhbHBoYS8yfSxcbWF0aHJte1NFfShcaGF0e1xiZXRhfV9qKS4kDQoNCiMjIyAqKjcuMy4gVsOtIGThu6UgUioqDQoNCmBgYHtyfQ0KIyBTbyBzw6FuaCBoYWkgbcO0IGjDrG5oIGzhu5NuZyBuaGF1IGLhurFuZyBkZXZpYW5jZSAodsOtIGThu6UgduG7m2kgd2FycGJyZWFrcykNCmRhdGEod2FycGJyZWFrcykNCmZ1bGxfbW9kZWwgPC0gZ2xtKGJyZWFrcyB+IHdvb2wgKyB0ZW5zaW9uLCBkYXRhID0gd2FycGJyZWFrcywgZmFtaWx5ID0gcG9pc3NvbikNCnJlZHVjZWRfbW9kZWwgPC0gZ2xtKGJyZWFrcyB+IHdvb2wsIGRhdGEgPSB3YXJwYnJlYWtzLCBmYW1pbHkgPSBwb2lzc29uKQ0KYW5vdmEocmVkdWNlZF9tb2RlbCwgZnVsbF9tb2RlbCwgdGVzdD0iQ2hpc3EiKQ0KDQpgYGANCg0KVsOtIGThu6UgdHLDqm4gY2hvIHRo4bqleSBjw6FjaCBkw7luZyBow6BtIGFub3ZhKCkgxJHhu4Mgc28gc8OhbmggaGFpIG3DtCBow6xuaCBs4buTbmcgbmhhdSB0cm9uZyBHTE0uIEdpw6EgdHLhu4sgcCB0aHUgxJHGsOG7o2MgZOG7sWEgdHLDqm4ga2nhu4NtIMSR4buLbmggJFxjaGleMiQsIGThu7FhIHRyw6puIHPhu7EgY2jDqm5oIGzhu4djaCBkZXZpYW5jZSBnaeG7r2EgaGFpIG3DtCBow6xuaC4NCg0KKipHaGkgY2jDuioqDQoNCi0gS2nhu4NtIMSR4buLbmggV2FsZCBk4buxYSB0csOqbiB44bqlcCB44buJIGNodeG6qW4gY+G7p2EgxrDhu5tjIGzGsOG7o25nICRcYmV0YSQ7IHRyb25nIG5oaeG7gXUgdHLGsOG7nW5nIGjhu6NwIHThu5F0IG5oxrBuZyBjw7MgdGjhu4Mga8OpbSBjaMOtbmggeMOhYyB24bubaSBt4bqrdSBuaOG7jy4NCi0gS2nhu4NtIMSR4buLbmggTFJUIHRoxrDhu51uZyDGsHUgdGnDqm4gaMahbiB2w6wgdMOtbmggbGluaCBob+G6oXQgKHNvIHPDoW5oIHRy4buxYyB0aeG6v3AgbG9nLWjhu6NwIGzDvSBnaeG7r2EgbcO0IGjDrG5oIMSR4bqneSDEkeG7pyB2w6AgZ2nhuqNtKS4NCi0gVHJvbmcgUiwgc3VtbWFyeSgpIHbDoCBjb25maW50KCkgY3VuZyBj4bqlcCBjw6FjIGjhu4cgc+G7kSDGsOG7m2MgbMaw4bujbmcsIHNhaSBz4buRIGNodeG6qW4gdsOgIGtob+G6o25nIHRpbiBj4bqteSB0xrDGoW5nIOG7qW5nLg0KDQoqKioNCg0KIyMgKipDaMawxqFuZyA4OiBHZW5lcmFsaXplZCBMaW5lYXIgTW9kZWxzOiBEaWFnbm9zdGljcyoqDQoNCioqKg0KDQojIyMgKio4LjEuIFThu5VuZyBxdWFuKioNCg0KQ2jGsMahbmcgbsOgeSB0csOsbmggYsOgeSBjaOG6qW4gxJFvw6FuIGNobyBHTE0sIGJhbyBn4buTbSB2aeG7h2Mga2nhu4NtIHRyYSDEkeG7mSBwaMO5IGjhu6NwIGPhu6dhIG3DtCBow6xuaCBxdWEgcmVzaWR1YWxzIHbDoCBjw6FjIGNo4buJIHPhu5Eg4bqjbmggaMaw4bufbmcuIE3hu5l0IHPhu5EgbG/huqFpIHJlc2lkdWFsIGNobyBHTE06IHJlc2lkdWFsIFBlYXJzb24sIHJlc2lkdWFsIGRldmlhbmNlLCByZXNpZHVhbCBkZXZpYW5jZSBjaHXhuqluIGjDs2EuIFTDoWMgZ2nhuqMgY8WpbmcgdGjhuqNvIGx14bqtbiB24buBIGxldmVyYWdlIHbDoCBDb29rJ3MgZGlzdGFuY2UgbeG7nyBy4buZbmcgY2hvIEdMTS4gTmdvw6BpIHJhLCBjw7MgxJHhu4EgY+G6rXAgxJHhur9uIGtp4buDbSDEkeG7i25oIMSR4buZIHBow7kgaOG7o3AgKMSR4buZIGzhu4djaCBkZXZpYW5jZSBzbyB24bubaSBwaMOibiBwaOG7kWkgJFxjaGleMiQpIHbDoCBuaOG7r25nIGThuqV1IGhp4buHdSBj4bunYSBvdmVyZGlzcGVyc2lvbi4NCg0KIyMjICoqOC4yLiBDw7RuZyB0aOG7qWMgY2jDrW5oKioNCg0KLSBSZXNpZHVhbCBQZWFyc29uOiAkcl97UCxpfSA9IFxmcmFje3lfaSAtIFxoYXR7XG11fV9pfXtcc3FydHtcaGF0e1Z9KFxoYXR7XG11fV9pKX19LiQNCi0gUmVzaWR1YWwgRGV2aWFuY2UgKHbDrSBk4bulIGNobyBQb2lzc29uKTogDQotIExldmVyYWdlIHRyb25nIEdMTTogcGjhuqduIHThu60gY2jDrW5oICRoX3tpaX0kIGPhu6dhIG1hIHRy4bqtbiAkV157MS8yfSBYIChYXlQgVyBYKV57LTF9IFheVCBXXnsxLzJ9JCwgdHJvbmcgxJHDsyAkVyQgbMOgIG1hIHRy4bqtbiB0cuG7jW5nIHPhu5EgSVJMUy4NCi0gQ29va+KAmXMgRGlzdGFuY2UgdsOgIGPDoWMgdGjhu5FuZyBz4buRIOG6o25oIGjGsOG7n25nIGtow6FjIGPFqW5nIMSRxrDhu6NjIHTDrW5oIHTGsMahbmcgdOG7sSBuaMawIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oLg0KDQojIyMgKio4LjMuIFbDrSBk4bulIFIqKg0KDQpgYGB7cn0NCiMgTWluaCBo4buNYSByZXNpZHVhbHMgdHJvbmcgR0xNICh24bubaSB3YXJwYnJlYWtzKQ0KbW9kIDwtIGdsbShicmVha3MgfiB3b29sICsgdGVuc2lvbiwgZGF0YSA9IHdhcnBicmVha3MsIGZhbWlseSA9IHBvaXNzb24pDQpwYXIobWZyb3cgPSBjKDIsIDIpKQ0KcGxvdChtb2QpDQoNCmBgYA0KDQrEkG/huqFuIG3DoyBoaeG7g24gdGjhu4sgY8OhYyDEkeG7kyB0aOG7iyBjaOG6qW4gxJFvw6FuIHTGsMahbmcgdOG7sSBo4buTaSBxdXkgdHV54bq/biB0w61uaCAoZMawIHNhaSwgZMawIFBlYXJzb24sIFEtUSBwbG90LCBDb29rJ3MgZGlzdGFuY2UpLiBU4burIMSRw7MgY8OzIHRo4buDIHBow6F0IGhp4buHbiBxdWFuIHPDoXQgY8OzIOG6o25oIGjGsOG7n25nIGhv4bq3YyBtw7QgaMOsbmggY2jGsGEgcGjDuSBo4bujcC4NCg0KKipHaGkgY2jDuioqDQoNCi0gTuG6v3UgcmVzaWR1YWwgZGV2aWFuY2UgbOG7m24gaMahbiBuaGnhu4F1IHNvIHbhu5tpICRkZl97XHRleHR7cmVzaWR1YWx9fSQsIG3DtCBow6xuaCBjw7MgdGjhu4MgYuG7iyBvdmVyZGlzcGVyc2lvbi4NCi0gS2hpIG92ZXJkaXNwZXJzaW9uLCBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgbcO0IGjDrG5oIE5lZ2F0aXZlIEJpbm9taWFsIMSR4buDIMSRaeG7gXUgY2jhu4luaC4NCi0gTHXDtG4ga2nhu4NtIHRyYSBjaOG6pXQgbMaw4bujbmcga2jhu5twIHbhu5tpIGRpYWdub3N0aWMgcGxvdHMgZ2nhu5FuZyBuaMawIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oLg0KDQoqKioNCg0KIyMgKipDaMawxqFuZyA5OiBNb2RlbHMgZm9yIFByb3BvcnRpb25zOiBCaW5vbWlhbCBHTE1zKioNCg0KKioqDQoNCiMjIyAqKjkuMS4gVOG7lW5nIHF1YW4qKg0KDQpDaMawxqFuZyBuw6B5IG5naGnDqm4gY+G7qXUgY8OhYyB0csaw4budbmcgaOG7o3AgYmnhur9uIHBo4bulIHRodeG7mWMgbMOgIHThu4kgbOG7hyBob+G6t2Mgc+G7kSB0aMOgbmggY8O0bmcvdGjhuqV0IGLhuqFpIHRoZW8gcGjDom4gcGjhu5FpIGJpbm9taWFsLiBWw60gZOG7pSDEkWnhu4NuIGjDrG5oIGzDoCBo4buTaSBxdXkgbG9naXN0aWMgKHBow6JuIHBo4buRaSBCZXJub3VsbGkgduG7m2kgaMOgbSBsacOqbiBr4bq/dCBsb2dpdCkgaG/hurdjIEdMTSBuaOG7iyB0aOG7qWMgY2h1bmcgKGtoaSBt4buXaSBxdWFuIHPDoXQgY8OzIHPhu5EgdGjhu60gbmdoaeG7h20gJG5faSQpLiBNw7QgaMOsbmggdOG7lW5nIHF1w6F0Og0KJCQNCllfaSBcc2ltIFx0ZXh0e0Jpbm9taWFsfShuX2ksIFxwaV9pKSwgXHF1YWQgZyhccGlfaSkgPSBcYmV0YV8wICsgXGJldGFfMSB4X2kuDQokJA0KDQpW4bubaSBow6BtIGxpw6puIGvhur90IGxvZ2l0OiAkJFxtYXRocm17bG9naXR9KFxwaV9pKSA9IFxsb2dcZnJhY3tccGlfaX17MS1ccGlfaX0uJCQNCg0KIyMjICoqOS4yLiBDw7RuZyB0aOG7qWMgY2jDrW5oKioNCg0KLSBIw6BtIGxvZ2l0OiAkXG1hdGhybXtsb2dpdH0oXHBpKSA9IFxsb2dcZnJhY3tccGl9ezEtXHBpfS4kDQotIFjDoWMgc3XhuqV0IGPhu6dhIEJlcm5vdWxsaSAobG9naXN0aWMpOiAkXHBpX2kgPSBcZnJhY3tlXntcYmV0YV8wICsgXGJldGFfMSB4X2l9fXsxICsgZV57XGJldGFfMCArIFxiZXRhXzEgeF9pfX0uJA0KLSBO4bq/dSBjw7MgJG5faSQgdGjhu60gbmdoaeG7h20gKEdMTSBuaOG7iyB0aOG7qWMpOiAkWV9pIFxzaW0gXHRleHR7Qmlub21pYWx9KG5faSwgXHBpX2kpLiQNCiANCiMjIyAqKjkuMy4gVsOtIGThu6UgUioqDQoNCmBgYHtyfQ0KIyBI4buTaSBxdXkgbG9naXN0aWMgKG5o4buLIHRo4bupYykgduG7m2kgZOG7ryBsaeG7h3UgZ2nhuqMgxJHhu4tuaA0Kc2V0LnNlZWQoNDIpDQp4IDwtIHJ1bmlmKDEwMCkNCnAgPC0gMSAvICgxICsgZXhwKC0oLTEgKyAyKngpKSkNCnkgPC0gcmJpbm9tKDEwMCwgc2l6ZT0xLCBwcm9iPXApDQpkZl9iaW4gPC0gZGF0YS5mcmFtZSh4LCB5KQ0KbG9naXRfbW9kIDwtIGdsbSh5IH4geCwgZGF0YSA9IGRmX2JpbiwgZmFtaWx5ID0gYmlub21pYWwpDQpzdW1tYXJ5KGxvZ2l0X21vZCkNCg0KYGBgDQoNClRyb25nIHbDrSBk4bulIHRyw6puLCBiaeG6v24ga+G6v3QgcXXhuqMgeSBsw6AgMC8xLiBNw7QgaMOsbmggZ2xtKC4uLiwgZmFtaWx5ID0gYmlub21pYWwpIMaw4bubYyBsxrDhu6NuZyBo4buHIHPhu5EgY+G7p2EgaMOgbSBsb2dpdC4NCg0KKipHaGkgY2jDuioqDQoNCi0gSOG7hyBz4buRICRcYmV0YV9qJCB0cm9uZyBsb2dpc3RpYyB0xrDGoW5nIOG7qW5nIHbhu5tpIGxvZy1vZGRzOyBjw7MgdGjhu4MgY2h1eeG7g24gxJHhu5VpIHRow6BuaCBvZGRzIHJhdGlvIMSR4buDIGdp4bqjaSB0aMOtY2guDQotIMSQ4buRaSB24bubaSBk4buvIGxp4buHdSB04bu3IGzhu4cgKHThuq1wIGjhu6NwIHPhu5EgdGjDoG5oIGPDtG5nL3Ro4bqldCBi4bqhaSksIHRhIGTDuW5nIGPDuiBwaMOhcCBjYmluZChzdWNjZXNzLCBmYWlsdXJlKSB0cm9uZyBnbG0uDQotIEtp4buDbSB0cmEgeMOhYyBzdeG6pXQgZOG7sSBiw6FvLCBtYSB0cuG6rW4gbmjhuqdtIGzhuqtuIGhv4bq3YyBST0MgY3VydmUgxJHhu4MgxJHDoW5oIGdpw6EgY2jhuqV0IGzGsOG7o25nIHBow6JuIGxv4bqhaS4NCg0KKioqDQoNCiMjICoqQ2jGsMahbmcgMTA6IE1vZGVscyBmb3IgQ291bnRzOiBQb2lzc29uIGFuZCBOZWdhdGl2ZSBCaW5vbWlhbCBHTE1zKioNCg0KKioqDQoNCiMjIyAqKjEwLjEuIFThu5VuZyBxdWFuKioNCg0KQ2jGsMahbmcgMTAgdOG6rXAgdHJ1bmcgdsOgbyBjw6FjIGThu68gbGnhu4d1IMSR4bq/bTogR0xNIFBvaXNzb24gdsOgIE5lZ2F0aXZlIEJpbm9taWFsLiBNw7QgaMOsbmggUG9pc3NvbiB0aMaw4budbmcgZMO5bmcga2hpIGJp4bq/biBwaOG7pSB0aHXhu5ljIGzDoCBz4buRIMSR4bq/bSB24bubaSBnaeG6oyDEkeG7i25oIGJp4bq/biB0aGnDqm4gYuG6sW5nIHRydW5nIGLDrG5oICgkVmFyKFkpPUUoWSkkKSB2w6AgZMO5bmcgaMOgbSBsacOqbiBr4bq/dCBsb2c6ICRnKFxtdSkgPSBcbG9nKFxtdSkkLiBO4bq/dSBk4buvIGxp4buHdSBjw7MgdMOtbmggb3ZlcmRpc3BlcnNpb24gKHBoxrDGoW5nIHNhaSBs4bubbiBoxqFuKSwgR0xNIFBvaXNzb24gY8OzIHRo4buDIGtow7RuZyBwaMO5IGjhu6NwOyB0YSBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgbcO0IGjDrG5oIE5lZ2F0aXZlIEJpbm9taWFsIMSR4buDIGJhbyBn4buTbSB0aMOqbSBiaeG6v24gdGhpw6puLg0KDQojIyMgKioxMC4yLiBDw7RuZyB0aOG7qWMgY2jDrW5oKioNCg0KLSBQaMOibiBwaOG7kWkgUG9pc3NvbjogJFAoWT15KSA9IFxmcmFje2Veey1cbGFtYmRhfVxsYW1iZGFeeX17eSF9LCBccXVhZCBFKFkpPVxsYW1iZGEsXCBWYXIoWSk9XGxhbWJkYS4kDQotIFRyb25nIEdMTSBQb2lzc29uOiAkZyhcbXVfaSkgPSBcbG9nKFxtdV9pKSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfaS4kDQotIFBow6JuIHBo4buRaSBOZWdhdGl2ZSBCaW5vbWlhbCAodHJvbmcgdGhhbSBz4buRIGjDs2EgJFxtdSwgayQpOiAkVmFyKFkpID0gXG11ICsgXGZyYWN7XG11XjJ9e2t9LCQgduG7m2kgJGskIGzDoCBo4buHIHPhu5EgcGjDom4gdMOhbiAoxJFp4buBdSBjaOG7iW5oKS4NCg0KIyMjICoqMTAuMy4gVsOtIGThu6UgUioqDQoNCmBgYHtyfQ0KbGlicmFyeShNQVNTKQ0KIyBWw60gZOG7pSBHTE0gUG9pc3NvbiB2w6AgTmVnYXRpdmUgQmlub21pYWwNCnNldC5zZWVkKDEyMykNCnhfbmIgPC0gcnVuaWYoMTAwLCAwLCA1KQ0KbXUgPC0gZXhwKDEgKyAwLjUqeF9uYikNCnlfcG9pcyA8LSBycG9pcygxMDAsIGxhbWJkYSA9IG11KQ0KeV9uYiA8LSBybmJpbm9tKDEwMCwgc2l6ZSA9IDIsIG11ID0gbXUpICAjIG92ZXItZGlzcGVyc2VkDQpkYXRhX3BvaXMgPC0gZGF0YS5mcmFtZSh4PXhfbmIsIHk9eV9wb2lzKQ0KZGF0YV9uYiA8LSBkYXRhLmZyYW1lKHg9eF9uYiwgeT15X25iKQ0KDQpwb2lzX21vZCA8LSBnbG0oeSB+IHgsIGZhbWlseSA9IHBvaXNzb24sIGRhdGEgPSBkYXRhX3BvaXMpDQpzdW1tYXJ5KHBvaXNfbW9kKQ0KDQpuYl9tb2QgPC0gZ2xtLm5iKHkgfiB4LCBkYXRhID0gZGF0YV9uYikNCnN1bW1hcnkobmJfbW9kKQ0KDQpgYGANCg0K4bueIHRyw6puLCBnbG0oLi4uLCBmYW1pbHkgPSBwb2lzc29uKSBraOG7m3AgbcO0IGjDrG5oIFBvaXNzb24uIMSQ4buDIGTDuW5nIE5lZ2F0aXZlIEJpbm9taWFsLCB0YSBj4bqnbiBnw7NpIE1BU1MgdsOgIGTDuW5nIGdsbS5uYigpLiBL4bq/dCBxdeG6oyBzdW1tYXJ5KG5iX21vZCkgc+G6vSBoaeG7g24gdGjhu4sgaOG7hyBz4buRIMaw4bubYyBsxrDhu6NuZyBj4bunYSBtw7QgaMOsbmggTmVnYXRpdmUgQmlub21pYWwuDQoNCioqR2hpIGNow7oqKg0KDQotIE3DtCBow6xuaCBQb2lzc29uIHbhu5tpIGjDoG0gbG9nIGxpbmsgY8OzIG5naMSpYSBy4bqxbmcgdMSDbmcgbeG7mXQgxJHGoW4gduG7iyBiaeG6v24gZ2nhuqNpIHRow61jaCBz4bq9IG5ow6JuIHThu7cgbOG7hyB44bqjeSByYSBz4buxIGtp4buHbiB0aGVvIGjhu4cgc+G7kS4NCi0gTmVnYXRpdmUgQmlub21pYWwgZ2nDunAgeOG7rSBsw70gb3ZlcmRpc3BlcnNpb24gbmjhu50gbeG7mXQgdGhhbSBz4buRIGLhu5Ugc3VuZyBjaG8gcGjGsMahbmcgc2FpLg0KLSBOZ2/DoGkgcmEsIGPDsyB0aOG7gyBraeG7g20gxJHhu4tuaCBvdmVyZGlzcGVyc2lvbiBi4bqxbmcgY8OhY2ggc28gc8OhbmggZGV2aWFuY2UgduG7m2kgc+G7kSBi4bqtYyB04buxIGRvIChyZXNpZHVhbCBkZik6IG7hur91IGRldmlhbmNlID4+IGRmLCBuw6puIHhlbSB4w6l0IE5lZ2F0aXZlIEJpbm9taWFsLg0KDQoqKioNCg0KIyMgKipDaMawxqFuZyAxMTogUG9zaXRpdmUgQ29udGludW91cyBEYXRhOiBHYW1tYSBhbmQgSW52ZXJzZSBHYXVzc2lhbiBHTE1zKioNCg0KKioqDQoNCiMjIyAqKjExLjEuIFThu5VuZyBxdWFuKioNCg0KQ2jGsMahbmcgMTEgeGVtIHjDqXQgY8OhYyBiaeG6v24gcGjhu6UgdGh14buZYyBsacOqbiB04bulYyBkxrDGoW5nLCB2w60gZOG7pSB0aOG7nWkgZ2lhbiBob+G6t2Mga2jhu5FpIGzGsOG7o25nLCBi4bqxbmcgbcO0IGjDrG5oIEdMTSBwaMOibiBwaOG7kWkgR2FtbWEgaG/hurdjIEludmVyc2UgR2F1c3NpYW4uIE5o4buvbmcgcGjDom4gcGjhu5FpIG7DoHkgdGjDrWNoIGjhu6NwIGtoaSBk4buvIGxp4buHdSBsdcO0biBkxrDGoW5nIHbDoCBjw7MgcGjGsMahbmcgc2FpIHBo4bulIHRodeG7mWMgdsOgbyBiw6xuaCBwaMawxqFuZyB0cnVuZyBiw6xuaCAoJFZhcihZKT1ccGhpXG11XjIkIGNobyBHYW1tYSkuIFRoxrDhu51uZyBkw7luZyBow6BtIGxpw6puIGvhur90IGxvZyBob+G6t2Mgbmdo4buLY2ggxJHhuqNvIChpbnZlcnNlKSBjaG8gR2FtbWEsIHbDoCBsacOqbiBr4bq/dCBsb2cgY2hvIEludmVyc2UgR2F1c3NpYW4uDQoNCiMjIyAqKjExLjIuIEPDtG5nIHRo4bupYyBjaMOtbmgqKg0KDQotIFBow6JuIHBo4buRaSBHYW1tYSAodGhhbSBz4buRIGjDs2EgdGhlbyAkXG11JCB2w6AgJFxwaGkkKTogJGYoeSkgPSBcZnJhY3sxfXtcR2FtbWEoXGFscGhhKX0gXGxlZnQoXGZyYWN7XGFscGhhfXtcbXV9XHJpZ2h0KV5cYWxwaGEgeV57XGFscGhhLTF9IGVeey1cYWxwaGEgeS9cbXV9LCQgduG7m2kgJFxhbHBoYSA9IDEvXHBoaSQ7ICRFKFkpPVxtdSQsICRWYXIoWSk9XHBoaSBcbXVeMiQuDQotIFBow6JuIHBo4buRaSBJbnZlcnNlIEdhdXNzaWFuOiAkZih5KSA9IFxmcmFje1xsYW1iZGFeezEvMn19eygyXHBpIHleMyleezEvMn19IFxleHBcbGVmdCgtXGZyYWN7XGxhbWJkYSAoeS1cbXUpXjJ9ezJcbXVeMiB5fVxyaWdodCksJCBjw7MgJEUoWSk9XG11JCwgJFZhcihZKT1cbXVeMy9cbGFtYmRhJC4NCi0gVsOtIGThu6UgaMOgbSBsacOqbiBr4bq/dCBHYW1tYTogJGcoXG11KSA9IFxsb2coXG11KSQgaG/hurdjICRnKFxtdSkgPSAxL1xtdSQuDQoNCiMjIyAqKjExLjMuIFbDrSBk4bulIFIqKg0KDQpgYGB7cn0NCiMgVsOtIGThu6UgR0xNIEdhbW1hDQpzZXQuc2VlZCgxMDEpDQp4X2dhbW1hIDwtIHJ1bmlmKDEwMCwgMCwgNSkNCm11X2cgPC0gZXhwKDIgKyAwLjMqeF9nYW1tYSkNCnlfZ2FtbWEgPC0gcmdhbW1hKDEwMCwgc2hhcGUgPSAyLCBzY2FsZSA9IG11X2cvMikgICMgRShZKT1tdV9nLCBWYXI9ayptdV4yDQpkYXRhX2dhbW1hIDwtIGRhdGEuZnJhbWUoeD14X2dhbW1hLCB5PXlfZ2FtbWEpDQpnYW1tYV9tb2QgPC0gZ2xtKHkgfiB4LCBmYW1pbHkgPSBHYW1tYShsaW5rID0gImxvZyIpLCBkYXRhID0gZGF0YV9nYW1tYSkNCnN1bW1hcnkoZ2FtbWFfbW9kKQ0KDQpgYGANCg0KVHJvbmcgdsOtIGThu6UsIGdsbSguLi4sIGZhbWlseSA9IEdhbW1hKGxpbms9ImxvZyIpKSBraOG7m3AgbcO0IGjDrG5oIEdhbW1hIHbhu5tpIGxpw6puIGvhur90IGxvZy4gS+G6v3QgcXXhuqMgY2hvIGjhu4cgc+G7kSDGsOG7m2MgbMaw4bujbmcgdsOgIMaw4bubYyBsxrDhu6NuZyAkXHBoaSQgKGRpc3BlcnNpb24pLg0KDQoqKkdoaSBjaMO6KioNCg0KLSBDw6FjIGThu68gbGnhu4d1IG5oxrAgdGjhu51pIGdpYW4geOG7rSBsw70gdMOhYyB24bulIGhv4bq3YyBu4buTbmcgxJHhu5kgbGnDqm4gdOG7pWMgdGjGsOG7nW5nIGTDuW5nIEdMTSBHYW1tYS4NCi0gTuG6v3UgZOG7ryBsaeG7h3UgZMawxqFuZyBuaMawbmcgcGjDom4gcGjhu5FpIGjhurlwIGjGoW4sIEludmVyc2UgR2F1c3NpYW4gY8OzIHRo4buDIHBow7kgaOG7o3AgaMahbiAoZmFtaWx5ID0gaW52ZXJzZS5nYXVzc2lhbiB0cm9uZyBSKS4NCi0gVGhhbSBz4buRICRccGhpJCB0cm9uZyBHYW1tYSBHTE0gdGjGsOG7nW5nIMSRxrDhu6NjIMaw4bubYyBsxrDhu6NuZyB2w6AgbMOgIG5naOG7i2NoIMSR4bqjbyBj4bunYSB0aGFtIHPhu5Egc2hhcGUgKCRcYWxwaGEkKS4NCg0KKioqDQoNCiMjICoqQ2jGsMahbmcgMTI6IFR3ZWVkaWUgR0xNcyoqDQoNCioqKg0KDQojIyMgKioxMi4xLiBU4buVbmcgcXVhbioqDQoNCkNoxrDGoW5nIDEyIGdp4bubaSB0aGnhu4d1IG3DtCBow6xuaCBUd2VlZGllIEdMTSwgZMO5bmcga2hpIGThu68gbGnhu4d1IGPDsyDEkeG6t2MgdHLGsG5nICJnacOhIHRy4buLIDAgduG7m2kgeMOhYyBzdeG6pXQgZMawxqFuZyB2w6AgcGjDom4gcGjhu5FpIGxpw6puIHThu6VjIGTGsMahbmcga2hpIGTGsMahbmciLiBUd2VlZGllIGzDoCBt4buZdCBo4buNIHBow6JuIHBo4buRaSBjb24gY+G7p2EgcGjDom4gcGjhu5FpIGjDoG0gbcWpLCB24bubaSB0aGFtIHPhu5EgYmnhur9uIHRoacOqbiAkcCQuIFbDrSBk4bulLCAkcD0xJCBjaG8gUG9pc3NvbiwgJHA9MiQgY2hvIEdhbW1hLCB2w6AgduG7m2kgJDE8cDwyJCB0aMOsIHBow6JuIHBo4buRaSBUd2VlZGllIGPDsyBr4bq/dCBo4bujcCB0w61uaCBjaOG6pXQgcuG7nWkgcuG6oWMgKGdpw6EgdHLhu4sgMCkgdsOgIGxpw6puIHThu6VjLiBUd2VlZGllIHRoxrDhu51uZyBkw7luZyB0cm9uZyBwaMOibiB0w61jaCBi4bqjbyBoaeG7g20gKGPDoWMgdOG7lW4gdGjhuqV0IGLhuqNvIGhp4buDbSkgaG/hurdjIGThu68gbGnhu4d1IGzGsOG7o25nIGPDsyBwaGEgdHLhu5luIHLhu51pIHLhuqFjIOKAkyBsacOqbiB04bulYy4NCg0KIyMjICoqMTIuMi4gQ8O0bmcgdGjhu6ljIGNow61uaCoqDQoNCi0gUGjDom4gcGjhu5FpIFR3ZWVkaWUgKHRoYW0gc+G7kSAkXG11LCBwJCkgY8OzIHBoxrDGoW5nIHNhaTogJFZhcihZKSA9IFxwaGkgXG11XnAuJA0KLSBDaOG7jW4gJHAkIHRyb25nIGtob+G6o25nICQxIDwgcCA8IDIkIHThuqFvIHJhIHBow6JuIHBo4buRaSBjw7MgeMOhYyBzdeG6pXQga2jhu5FpIGzGsOG7o25nIHThuqFpIDAgdsOgIGxpw6puIHThu6VjIGTGsMahbmcgY2hvIHBo4bqnbiBjw7JuIGzhuqFpLg0KLSBIw6BtIGxpw6puIGvhur90IHRow7RuZyBk4bulbmcgbMOgIGxvZyAodOG7qWMgJGcoXG11KT1cbG9nKFxtdSkkKS4NCg0KIyMjICoqMTIuMy4gVsOtIGThu6UgUioqDQoNCmBgYHtyfQ0KDQoNCiMgVOG6oW8gZOG7ryBsaeG7h3UNCnNldC5zZWVkKDIwMikNCnhfdHcgPC0gcnVuaWYoMTAwLCAwLCA1KQ0KbXVfdHcgPC0gZXhwKDEgKyAwLjQgKiB4X3R3KQ0KeV90dyA8LSBydHdlZWRpZSgxMDAsIG11ID0gbXVfdHcsIHBoaSA9IDIsIHBvd2VyID0gMS41KSAgIyBwb3dlciA9IHANCg0KIyBGaXQgbcO0IGjDrG5oIEdMTSB24bubaSBwaMOibiBwaOG7kWkgVHdlZWRpZQ0KdHdlZWRpZV9tb2QgPC0gZ2xtKHlfdHcgfiB4X3R3LCBmYW1pbHkgPSB0d2VlZGllKHZhci5wb3dlciA9IDEuNSwgbGluay5wb3dlciA9IDApKQ0Kc3VtbWFyeSh0d2VlZGllX21vZCkNCg0KYGBgDQoNCg0KVHJvbmcgxJFv4bqhbiBtw6MsIHJ0d2VlZGllIMSRxrDhu6NjIGTDuW5nIMSR4buDIHNpbmggZOG7ryBsaeG7h3UgVHdlZWRpZSAo4bufIMSRw6J5ICRwPTEuNSQpLiBLaGkga2jhu5twIG3DtCBow6xuaCwgdHdlZWRpZSh2YXIucG93ZXI9MS41LCBsaW5rLnBvd2VyPTApIHPhu60gZOG7pW5nIGxpw6puIGvhur90IGxvZy4NCg0KKipHaGkgY2jDuioqDQoNCi0gxJDhu4MgZMO5bmcgVHdlZWRpZSBHTE0gdHJvbmcgUiwgY+G6p24gZ8OzaSBzdGF0bW9kIChow6BtIHR3ZWVkaWUoKSkuDQotIFRoYW0gc+G7kSBwb3dlciAkcCQgeMOhYyDEkeG7i25oIGjDrG5oIGThuqFuZyBwaMOibiBwaOG7kWk7IHbDrSBk4bulICRwPTEkIGNobyBQb2lzc29uLCAkcD0yJCBjaG8gR2FtbWEuDQotIFR3ZWVkaWUgcGjDuSBo4bujcCBjaG8gZOG7ryBsaeG7h3Uga2jDtG5nIMOibSBwaGEgdHLhu5luIGPDoWMgZ2nDoSB0cuG7iyDEkWnhu4NtIHbDoCBsacOqbiB04bulYy4NCg0KKioqDQoNCiMjICoqQ2jGsMahbmcgMTM6IEV4dHJhIFByb2JsZW1zKioNCg0KKioqDQoNCiMjIyAqKjEzLjEuIFThu5VuZyBxdWFuKioNCg0KQ2jGsMahbmcgY3Xhu5FpIG7DoHkgY2jhu4kgZ+G7k20gYsOgaSB04bqtcCB0aOG7sWMgaMOgbmggbGnDqm4gcXVhbiDEkeG6v24gY8OhYyBu4buZaSBkdW5nIMSRw6MgaOG7jWMuIEPDoWMgYsOgaSB04bqtcCB5w6p1IGPhuqd1IG5nxrDhu51pIMSR4buNYyDDoXAgZOG7pW5nIEdMTSDEkeG7gyBwaMOibiB0w61jaCBi4buZIGThu68gbGnhu4d1IG3huqt1LCBraOG7m3AgbcO0IGjDrG5oIHBow7kgaOG7o3AsIHRo4buxYyBoaeG7h24gY2jhuqluIMSRb8OhbiwgdsOgIHNvIHPDoW5oIGPDoWMgZ2nhuqMgdGh1eeG6v3QgKHbDrSBk4bulLCBz4butIGThu6VuZyBhbm92YSDEkeG7gyBzbyBzw6FuaCBjw6FjIEdMTSBs4buTbmcgbmhhdSkuIMSQw6J5IGzDoCBwaOG6p24gdGjhu7FjIGjDoG5oLCBuaOG6sW0gY+G7p25nIGPhu5Ega2nhur9uIHRo4bupYyBsw70gdGh1eeG6v3QgdGjDtG5nIHF1YSBjw6FjIGLDoGkgdOG6rXAgY+G7pSB0aOG7gy4NCg0KKipWw60gZOG7pToqKg0KDQotIENobyBk4buvIGxp4buHdSDEkeG6v20gY3JhYiAoduG7gSBz4buRIGhvYSB2xINuIHRyw6puIG1haSBjdWEpLCBraOG7m3AgR0xNIFBvaXNzb24vTmVnYXRpdmUgQmlub21pYWwgdsOgIGtp4buDbSB0cmEgxJHhu5kgcGjDuSBo4bujcC4NCg0KLSBDaG8gZOG7ryBsaeG7h3UgbXRjYXJzLCBraOG7m3AgbcO0IGjDrG5oIGxvZ2lzdGljIHBow6JuIGxv4bqhaSB4ZSB0aGVvIGJp4bq/biB2cywgc2F1IMSRw7MgdGjhu7FjIGhp4buHbiBraeG7g20gxJHhu4tuaCBMaWtlbGlob29kIFJhdGlvIHNvIHPDoW5oIHbhu5tpIG3DtCBow6xuaCBraMO0bmcgY2jhu6lhIGJp4bq/biBwaOG7pS4NCg0KLSBDaG8gZOG7ryBsaeG7h3Uga+G6v3QgcXXhuqMgxJFp4buBdSB0cuG7iyAoc+G7kSB0aMOgbmggY8O0bmcvdGjhuqV0IGLhuqFpKSB2w6AgbeG7mXQgYmnhur9uIGdp4bqjaSB0aMOtY2ggJHgkLCDGsOG7m2MgbMaw4bujbmcgbcO0IGjDrG5oIGdsbShjYmluZChzdWNjZXNzLCBmYWlsdXJlKSB+IHgsIGZhbWlseT1iaW5vbWlhbCkgdsOgIHN1eSBkaeG7hW4gaOG7hyBz4buRLg0KDQpDw6FjIGLDoGkgdOG6rXAgbsOgeSBnacO6cCBuZ8aw4budaSBo4buNYyB0aOG7sWMgaMOgbmggY8OhYyBjw7RuZyBj4bulIFIgKGdsbSwgYW5vdmEsIHN1bW1hcnksIHBsb3QsIC4uLikgxJHhu5NuZyB0aOG7nWkgaGnhu4N1IHPDonUgaMahbiB24buBIG3DtCBow6xuaCBHTE0uDQoNCg==