Giới thiệu package
Dữ liệu penguins được cung cấp bởi Tiến sĩ Kristen Gorman và Trạm
Palmer, Nam Cực. Dữ liệu thu thập các đặc điểm của các loài chim cánh
cụt sống ở Nam Cực. Dữ liệu này được tích hợp trong package
“palmerpenguins” bao gồm 8 biến:
— species: các loại chim cánh cụt
— island : hòn đảo chim cánh cụt sinh sống
— bill_length_mm: chiều dài mỏ chim cánh cụt
— bill_depth_mm: độ sâu mỏ chim cánh cụt
— body_mass_g: khối lượng cơ thể chim cánh cụt
— sex: giống (gồm đực và cái)
— flipper_length_mm: độ dài cánh của chim cánh cụt
— year: năm thu thập số liệu
library(palmerpenguins)
d <- na.omit(penguins)
d <- as.data.frame(d)
str(d)
## 'data.frame': 333 obs. of 8 variables:
## $ species : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ island : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ bill_length_mm : num 39.1 39.5 40.3 36.7 39.3 38.9 39.2 41.1 38.6 34.6 ...
## $ bill_depth_mm : num 18.7 17.4 18 19.3 20.6 17.8 19.6 17.6 21.2 21.1 ...
## $ flipper_length_mm: int 181 186 195 193 190 181 195 182 191 198 ...
## $ body_mass_g : int 3750 3800 3250 3450 3650 3625 4675 3200 3800 4400 ...
## $ sex : Factor w/ 2 levels "female","male": 2 1 1 1 2 1 2 1 2 2 ...
## $ year : int 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
## - attr(*, "na.action")= 'omit' Named int [1:11] 4 9 10 11 12 48 179 219 257 269 ...
## ..- attr(*, "names")= chr [1:11] "4" "9" "10" "11" ...
Ta thấy có 3 biến định đính là Species, Island, Sex
1.Lập bảng tần số cho các biến độc lập
Biến giới tính (sex)
table(d$sex)
##
## female male
## 165 168
table(d$sex)/sum(table(d$sex))
##
## female male
## 0.4954955 0.5045045
Ta thấy tỷ lệ con đực và con cái xêm nhau, gồm 168 con đực, chiếm
50.45%; 165 con cái chiếm 49.55%
Biến đảo sinh sống
table(d$island)
##
## Biscoe Dream Torgersen
## 163 123 47
table(d$island)/sum(table(d$island))
##
## Biscoe Dream Torgersen
## 0.4894895 0.3693694 0.1411411
Biscoe có tỷ lệ chim cánh cụt cao nhất (48.95%), điều này cho thấy
rằng đảo Biscoe có nhiều chim cánh cụt hơn so với hai đảo còn lại. Dream
có tỷ lệ chim cánh cụt trung bình (36.94%), cho thấy rằng số lượng chim
cánh cụt ở đảo Dream cũng khá cao nhưng không bằng Biscoe. Torgersen có
tỷ lệ chim cánh cụt thấp nhất (14.11%), cho thấy rằng đảo này có ít chim
cánh cụt hơn so với hai đảo còn lại.
Biến loài
table(d$species)
##
## Adelie Chinstrap Gentoo
## 146 68 119
table(d$species)/sum(table(d$species))
##
## Adelie Chinstrap Gentoo
## 0.4384384 0.2042042 0.3573574
Loài Adelie là phổ biến nhất trong dữ liệu, chiếm gần
44%.
Loài Gentoo cũng khá phổ biến, chiếm gần 36%.
Loài Chinstrap ít phổ biến nhất, chiếm khoảng 20%.
Bảng tần số giữa 2 biến
giới tính và đảo sinh sống
c <- table(d$sex,d$island)
c
##
## Biscoe Dream Torgersen
## female 80 61 24
## male 83 62 23
prop.table(c)
##
## Biscoe Dream Torgersen
## female 0.24024024 0.18318318 0.07207207
## male 0.24924925 0.18618619 0.06906907
— Nhận xet:
Biscoe có tổng số chim cánh cụt nhiều nhất (163), tiếp theo là
Dream (123), và ít nhất là Torgersen (47).
Dựa vào bảng tần suất, ta thấy Số lượng chim cánh cụt đực và cái
trên mỗi đảo khá cân bằng, không có sự chênh lệch lớn giữa hai giới
tính.
Biscoe có số lượng chim cánh cụt đực và cái đều cao nhất, cho
thấy rằng đây có thể là môi trường sống ưa thích của chim cánh cụt trong
quần đảo Palmer.
Loài và đảo sinh sống
h <- table(d$species,d$island)
h
##
## Biscoe Dream Torgersen
## Adelie 44 55 47
## Chinstrap 0 68 0
## Gentoo 119 0 0
prop.table(h)
##
## Biscoe Dream Torgersen
## Adelie 0.1321321 0.1651652 0.1411411
## Chinstrap 0.0000000 0.2042042 0.0000000
## Gentoo 0.3573574 0.0000000 0.0000000
Nhận xét:
Trên đảo Biscoe, loài Gentoo chiếm tỷ lệ cao nhất với 35.74%,
trong khi loài Adelie chiếm 13.21%, và không có loài Chinstrap
nào.
Trên đảo Dream, loài Chinstrap chiếm tỷ lệ cao nhất với 20.42%,
theo sau là loài Adelie với 16.52%, và không có loài Gentoo
nào.
Trên đảo Torgersen, chỉ có loài Adelie xuất hiện với tỷ lệ
14.11%, và không có loài Chinstrap hay Gentoo nào.
2. Vẽ đồ thị
2.1 Đồ thị cột
Vẽ đồ thị cột cho Biến loài (species)
library(ggplot2)
ggplot(d, aes(species,fill=species)) + geom_bar(position = 'dodge')

Nhìn vào biểu đồ ta thấy loài Adelie chiếm tỷ lệ nhiều nhất, kế đến
là Gentoo và cuối cùng là Chinstrap.
Chúng ta có sắp xếp lại biểu đồ theo thứ tự tăng dần và hiển thị số
cá thể trên từng loài:
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.1 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ lubridate 1.9.2 ✔ tibble 3.2.1
## ✔ purrr 1.0.1 ✔ tidyr 1.3.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
d %>%
filter(species %in% c("Adelie", "Chinstrap", "Gentoo")) %>%
group_by(species) %>%
count() %>%
ggplot(aes(reorder(species,-n), n)) +
geom_col(width = 0.7,fill="brown") +
geom_text(aes(label = n), vjust = 2, color = "white", size = 4) +
labs(x = NULL, y = "Number of Penguins",
title = "Number of Penguins by Species",
caption = "Data Source: Custom Penguins Dataset") ->> p1
# Hiển thị biểu đồ
p1

Quay ngược biểu đồ, như sau:
p1 + coord_flip()

Lúc này với biểu đồ cột ngang, các số có trên biểu đồ bị mất. Do đó
ta hiệu chỉnh như sau:
Hiệu chỉnh như sau:
penguins_count <- d %>%
group_by(species) %>%
count()
theme_set(theme_minimal())
p2 <- ggplot(penguins_count, aes(reorder(species, n), n)) +
geom_col(width = 0.7,fill="brown") +
geom_text(aes(label = n), hjust = 1.2, color = "white", size = 5) +
labs(x = NULL, y = "Number of Penguins",
title = "Number of Penguins by Species",
caption = "Data Source: Custom Penguins Dataset") +
coord_flip() +
scale_y_continuous(breaks = seq(0, max(penguins_count$n), 10))
p2

Sử dụng theme của một số tạp chí nổi tiếng:
library(ggthemes)
p2 +
theme_economist(horizontal = FALSE)+
scale_fill_economist()

library(dplyr)
d %>%
filter(species %in% c("Adelie", "Chinstrap", "Gentoo")) %>%
group_by(species) %>%
count() %>%
ggplot(aes(reorder(species, n), n, fill = species)) +
geom_col(width = 0.7, show.legend = FALSE) +
geom_text(aes(label = n), hjust = 1.2, color = "white", size = 5) +
labs(x = NULL,
y = "Số lượng",
title = "Số lượng chim cánh cụt theo loài",
caption = "Nguồn dữ liệu: https://github.com/allisonhorst/palmerpenguins") +
coord_flip() +
scale_y_continuous(breaks = seq(0, 100, 10)) -> p3
print(p3)

library(ggthemes)
p3 +
theme_economist(horizontal = FALSE) +
scale_fill_economist()

— Nhận xét: Đồ thị đã được cải tiến một cách hoàn
chỉnh và đẹp hơn. Nhìn vào biểu đồ ta thấy loài Adelie chiếm tỷ lệ nhiều
nhất, với 146 cá thể kế đến là Gentoo với 119 cá thể và cuối cùng là
Chinstrap với 68 cá thể.
3. Ước lượng tỷ lệ
— Công thức ước lượng tỉ lệ (cho 1 tổng thể):
\[
\hat{p} - Z_{\alpha/2} \sqrt{\frac{\hat{p}(1 - \hat{p})}{n}} \le P \le
\hat{p} + Z_{\alpha/2} \sqrt{\frac{\hat{p}(1 - \hat{p})}{n}}
\]
Trong đó:
- \(\hat{p}\) là tỷ lệ mẫu của mức độ
ngoại hình.
- \(P\) là tỷ lệ số lượng của từng
phân loại ngoại hình.
- \(Z_{\alpha/2}\) là giá trị
critical từ phân phối chuẩn tương ứng với mức tin cậy \(1 - \alpha\).
- \(n\) là kích thước mẫu.
Ước lượng giống cánh cụt đực, đồng thời kiểm định xem tỷ lệ % cá thể
có đạt 50% hay không (giả thuyết Ho=50%)
mal <- d[d$sex == "male",]
prop.test(length(d$sex), length(d$sex), p = 0.5)
##
## 1-sample proportions test with continuity correction
##
## data: length(d$sex) out of length(d$sex), null probability 0.5
## X-squared = 331, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
## 0.9857837 1.0000000
## sample estimates:
## p
## 1
Vì p_value = 2.2e-16 < 1%. Do đó, bác bỏ H0. Vậy tỷ lệ con đực
không đạt 50%.
Ước lượng các loài sinh sống ở Đảo Biscoe, đồng thời kiểm định xem số
cá thể sống ở Biscoe có đạt 40% hay không (Giả thuyết H0=0.4
Ade <- d[d$island == "Biscoe",]
prop.test(length(d$island), length(d$island), p = 0.4)
##
## 1-sample proportions test with continuity correction
##
## data: length(d$island) out of length(d$island), null probability 0.4
## X-squared = 497, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.4
## 95 percent confidence interval:
## 0.9857837 1.0000000
## sample estimates:
## p
## 1
Vì p_value = 2.2e-16 < 1%. Do đó, bác bỏ H0. Vậy tỷ lệ cá thể sống
ở đảo Bisoce không đạt 40%.
4.Ước lượng chênh lệch 2 tỷ lệ
Trong đó:
- \(\hat{p}_1\) và \(\hat{p}_2\) là tỷ lệ chỉ số xếp hạng ngoại
hình cao hơn 1 trong mẫu nam và nữ tương ứng.
- \(p_1\) và \(p_2\) là tỷ lệ chỉ số xếp hạng ngoại hình
cao hơn 1 trong toàn bộ tổng thể nam và nữ tương ứng.
- \(n_1\) và \(n_2\) là kích thước của mẫu nam và nữ tương
ứng.
- \(Z_{\alpha/2}\) là giá trị
critical từ phân phối chuẩn tương ứng với mức tin cậy \(1 - \alpha\).
Thực hiện bài toán kiểm định giả thuyết sự bằng nhau về tỷ lệ cá thể
đực và cái sống ở đảo Bisoce 2 tổng thể, nghĩa là chúng ta thực hiện bài
toán kiểm định H0:p1=p2
d4 <- d[d$sex == "male",]
d4f <- d[d$sex=="female",]
d4d4 <- d4[d4$island =="Biscoe",]
d4fd4 <- d4f[d4f$island == "Biscoe",]
a <- c(nrow(d4), nrow(d4f))
b <- c(nrow(d4d4), nrow(d4fd4))
prop.test(b,a)
##
## 2-sample test for equality of proportions with continuity correction
##
## data: b out of a
## X-squared = 0.0033955, df = 1, p-value = 0.9535
## alternative hypothesis: two.sided
## 95 percent confidence interval:
## -0.1041884 0.1225867
## sample estimates:
## prop 1 prop 2
## 0.4940476 0.4848485
với p_value = 0.9535, chấp nhận H0. Vậy tỷ lệ cá thể đực ở đảo Biscoe
bằng với tỷ lệ cái sống ở đảo Biscoe.
5. Tính rủi ro tương đối
— Trong phần này, tôi tiến hành tính rủi ro tương đối
h <- table(d$species,d$island)
addmargins(h)
##
## Biscoe Dream Torgersen Sum
## Adelie 44 55 47 146
## Chinstrap 0 68 0 68
## Gentoo 119 0 0 119
## Sum 163 123 47 333
Vì bảng tần số có dạng ma trận 3x3, do đó ta không thể dùng Relrisk
để tính toán rủi ro tương đối được, do đó ta tính thủ công từng cặp với
nhau như sau:
Cố định loài Adelie, ta sẽ tính rủi ro tương đối của loài Adelie so
với 3 đảo. Dưới đây là dữ liệu từ bảng tần số:
# Dữ liệu
data <- data.frame(
Species = c("Adelie", "Chinstrap", "Gentoo"),
Biscoe = c(44, 0, 119),
Dream = c(55, 68, 0),
Torgersen = c(47, 0, 0),
Sum = c(146, 68, 119)
)
data
Thực hiện tính toán, như sau:
P_Biscoe_Adelie <- data$Biscoe[1] / data$Sum[1]
P_Dream_Adelie <- data$Dream[1] / data$Sum[1]
P_Torgersen_Adelie <- data$Torgersen[1] / data$Sum[1]
P_Biscoe_Adelie
## [1] 0.3013699
P_Dream_Adelie
## [1] 0.3767123
P_Torgersen_Adelie
## [1] 0.3219178
Rủi ro tương đối cho Adelie
# Rủi ro tương đối cho Adelie
RR_1 <- P_Biscoe_Adelie / P_Dream_Adelie
RR_1
## [1] 0.8
- Kết luận: Rủi ro tương đối cho Adelie (RR_1) là
khoảng 0.80. Điều này có nghĩa là Adelie ở đảo Biscoe có nguy cơ phân bố
chỉ bằng 0.80 lần so với Adelie ở đảo Dream.
— Tương tự, ta có thể tính rủi ro tương đối của loài Adelie ở Đảo
Biscoe so với Đảo Torgersen như sau:
RR_2 <- P_Biscoe_Adelie / P_Torgersen_Adelie
RR_2
## [1] 0.9361702
- Kết luận: Rủi ro tương đối cho Adelie (RR_2) là
khoảng 0.94. Điều này có nghĩa là Adelie ở đảo Biscoe có nguy cơ phân bố
chỉ bằng 0.94 lần so với Adelie ở đảo Torgersen.
— Tương tự, ta có thể tính rủi ro tương đối của loài Adelie ở Đảo
Dream so với Đảo Torgersen như sau:
RR_3 <- P_Dream_Adelie / P_Torgersen_Adelie
RR_3
## [1] 1.170213
- Kết luận: Rủi ro tương đối cho Adelie (RR_3) là
khoảng 1.17. Điều này có nghĩa là Adelie ở đảo Dream có nguy cơ phân bố
bằng 1.17 lần so với Adelie ở đảo Dream.
6. Ước lượng odd ratio
Đầu tiên ta lập bảng tần số cho 2 biến sex và
species
odd <- table(d$species,d$sex)
addmargins(odd)
##
## female male Sum
## Adelie 73 73 146
## Chinstrap 34 34 68
## Gentoo 58 61 119
## Sum 165 168 333
Tương tự, vì đây là ma trận 3x2 do đó ta không dùng câu lệnh để tính
odd ratio được. Thay vào đó, ta làm thủ công cho từng cặp biểu hiện của
từng biến với nhau.
Làm mới lại bảng tần số để tính.
da6 <- matrix(c(73, 73, 34, 34, 58, 61), nrow = 3, byrow = TRUE,
dimnames = list(c("Adelie", "Chinstrap", "Gentoo"),
c("female", "male")))
rownames(data) <- c("Adelie", "Chinstrap", "Gentoo")
colnames(data) <- c("female", "male")
da6
## female male
## Adelie 73 73
## Chinstrap 34 34
## Gentoo 58 61
Tính Odds-ratio tỷ lệ nam nữ của loài Adelie và Chintrap xem liệu
rằng tỷ lệ nam/ nữ của 2 loài này có sự khác biệt hay không
a_adelie <- da6["Adelie", "female"]
b_adelie <- da6["Adelie", "male"]
c_chinstrap <- da6["Chinstrap", "female"]
d_chinstrap <- da6["Chinstrap", "male"]
OR_ac <- (a_adelie / b_adelie) / (c_chinstrap / d_chinstrap)
OR_ac
## [1] 1
— Nhận xét: Vậy với odds ratio =1 thì tỷ lệ nam nữ ở
cả 2 loài Adelie và Chinstrap là như nhau.
Tương tự, ta có thể tính odds ratio cho loài Chinstrap và Gentoo như
sau:
e_gentoo <- da6["Gentoo","female"]
f_gentoo <- da6["Gentoo","male"]
OR_cg <- (c_chinstrap / d_chinstrap)/(e_gentoo/f_gentoo)
OR_cg
## [1] 1.051724
— Nhận xét: Khi tính toán Odds Ratio giữa loài
Chinstrap và Gentoo và kết quả là 1.051724, điều này có nghĩa tồn tại sự
chênh lệch giữa cá thể đực và cái của cả 2 loài. Cụ thể, sự chênh lệch
đến từ việc loài Gentoo có 61 cá thể đực nhiều hơn cá thể cái (58 cá
thể).
LS0tDQp0aXRsZTogIkJ14buVaSAzIC0gUGjDom4gdMOtY2ggxJHhu4tuaCB0w61uaCINCmF1dGhvcjogIm50aHVuZyINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVIOiVNOiVTLCAlZCAtICVtIC0gJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICBwZGZfZG9jdW1lbnQ6DQogICAgZXh0cmFfZGVwZW5kZW5jaWVzOg0KICAgICAgdmlldG5hbTogdXRmOA0KICAgIHRvYzogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQpnZW9tZXRyeToNCiAgICAgIC0gaW5uZXI9M2NtDQogICAgICAtIG91dGVyPTRjbQ0KICAgICAgLSB0b3A9M2NtDQogICAgICAtIGJvdHRvbT00Y20NCiAgICAgIC0gaGVhZHNlcD0yMnB0DQogICAgICAtIGhlYWRoZWlnaHQ9MTFwdA0KICAgICAgLSBmb290c2tpcD0zM3B0DQogICAgICAtIGlnbm9yZWhlYWQNCiAgICAgIC0gaWdub3JlZm9vdA0KICAgICAgLSBoZWlnaHRyb3VuZGVkDQotLS0NCjxzdHlsZT4NCiAgYm9keSB7DQogICAgZm9udC1zaXplOiAxNnB0Ow0KICB9DQo8L3N0eWxlPg0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMgKipHaeG7m2kgdGhp4buHdSBwYWNrYWdlKioNCg0KROG7ryBsaeG7h3UgcGVuZ3VpbnMgxJHGsOG7o2MgY3VuZyBj4bqlcCBi4bufaSBUaeG6v24gc8SpIEtyaXN0ZW4gR29ybWFuIHbDoCBUcuG6oW0gUGFsbWVyLCBOYW0gQ+G7sWMuIEThu68gbGnhu4d1IHRodSB0aOG6rXAgY8OhYyDEkeG6t2MgxJFp4buDbSBj4bunYSBjw6FjIGxvw6BpIGNoaW0gY8OhbmggY+G7pXQgc+G7kW5nIOG7nyBOYW0gQ+G7sWMuIEThu68gbGnhu4d1IG7DoHkgxJHGsOG7o2MgdMOtY2ggaOG7o3AgdHJvbmcgcGFja2FnZSDigJxwYWxtZXJwZW5ndWluc+KAnSBiYW8gZ+G7k20gOCBiaeG6v246DQoNCi0tLSBzcGVjaWVzOiBjw6FjIGxv4bqhaSBjaGltIGPDoW5oIGPhu6V0DQoNCi0tLSBpc2xhbmQgOiBow7JuIMSR4bqjbyBjaGltIGPDoW5oIGPhu6V0IHNpbmggc+G7kW5nDQoNCi0tLSBiaWxsX2xlbmd0aF9tbTogY2hp4buBdSBkw6BpIG3hu48gY2hpbSBjw6FuaCBj4buldA0KDQotLS0gYmlsbF9kZXB0aF9tbTogxJHhu5kgc8OidSBt4buPIGNoaW0gY8OhbmggY+G7pXQNCg0KLS0tIGJvZHlfbWFzc19nOiBraOG7kWkgbMaw4bujbmcgY8ahIHRo4buDIGNoaW0gY8OhbmggY+G7pXQNCg0KLS0tIHNleDogZ2nhu5FuZyAoZ+G7k20gxJHhu7FjIHbDoCBjw6FpKQ0KDQotLS0gZmxpcHBlcl9sZW5ndGhfbW06IMSR4buZIGTDoGkgY8OhbmggY+G7p2EgY2hpbSBjw6FuaCBj4buldA0KDQotLS0geWVhcjogbsSDbSB0aHUgdGjhuq1wIHPhu5EgbGnhu4d1DQoNCmBgYHtyfQ0KbGlicmFyeShwYWxtZXJwZW5ndWlucykNCmQgPC0gbmEub21pdChwZW5ndWlucykNCmQgPC0gYXMuZGF0YS5mcmFtZShkKQ0Kc3RyKGQpDQpgYGANClRhIHRo4bqleSBjw7MgMyBiaeG6v24gxJHhu4tuaCDEkcOtbmggbMOgIFNwZWNpZXMsIElzbGFuZCwgU2V4DQoNCiMgKioxLkzhuq1wIGLhuqNuZyB04bqnbiBz4buRIGNobyBjw6FjIGJp4bq/biDEkeG7mWMgbOG6rXAqKg0KDQojIyBCaeG6v24gZ2nhu5tpIHTDrW5oIChzZXgpDQpgYGB7cn0NCnRhYmxlKGQkc2V4KQ0KdGFibGUoZCRzZXgpL3N1bSh0YWJsZShkJHNleCkpDQpgYGANClRhIHRo4bqleSB04bu3IGzhu4cgY29uIMSR4buxYyB2w6AgY29uIGPDoWkgeMOqbSBuaGF1LCBn4buTbSAxNjggY29uIMSR4buxYywgY2hp4bq/bSA1MC40NSU7IDE2NSBjb24gY8OhaSBjaGnhur9tIDQ5LjU1JQ0KDQojIyBCaeG6v24gxJHhuqNvIHNpbmggc+G7kW5nIA0KDQpgYGB7cn0NCnRhYmxlKGQkaXNsYW5kKQ0KdGFibGUoZCRpc2xhbmQpL3N1bSh0YWJsZShkJGlzbGFuZCkpDQpgYGANCkJpc2NvZSBjw7MgdOG7tyBs4buHIGNoaW0gY8OhbmggY+G7pXQgY2FvIG5o4bqldCAoNDguOTUlKSwgxJFp4buBdSBuw6B5IGNobyB0aOG6pXkgcuG6sW5nIMSR4bqjbyBCaXNjb2UgY8OzIG5oaeG7gXUgY2hpbSBjw6FuaCBj4buldCBoxqFuIHNvIHbhu5tpIGhhaSDEkeG6o28gY8OybiBs4bqhaS4gRHJlYW0gY8OzIHThu7cgbOG7hyBjaGltIGPDoW5oIGPhu6V0IHRydW5nIGLDrG5oICgzNi45NCUpLCBjaG8gdGjhuqV5IHLhurFuZyBz4buRIGzGsOG7o25nIGNoaW0gY8OhbmggY+G7pXQg4bufIMSR4bqjbyBEcmVhbSBjxaluZyBraMOhIGNhbyBuaMawbmcga2jDtG5nIGLhurFuZyBCaXNjb2UuDQpUb3JnZXJzZW4gY8OzIHThu7cgbOG7hyBjaGltIGPDoW5oIGPhu6V0IHRo4bqlcCBuaOG6pXQgKDE0LjExJSksIGNobyB0aOG6pXkgcuG6sW5nIMSR4bqjbyBuw6B5IGPDsyDDrXQgY2hpbSBjw6FuaCBj4buldCBoxqFuIHNvIHbhu5tpIGhhaSDEkeG6o28gY8OybiBs4bqhaS4NCiANCiMjIEJp4bq/biBsb8OgaQ0KDQpgYGB7cn0NCnRhYmxlKGQkc3BlY2llcykNCg0KdGFibGUoZCRzcGVjaWVzKS9zdW0odGFibGUoZCRzcGVjaWVzKSkNCmBgYA0KLSBMb8OgaSBBZGVsaWUgbMOgIHBo4buVIGJp4bq/biBuaOG6pXQgdHJvbmcgZOG7ryBsaeG7h3UsIGNoaeG6v20gZ+G6p24gNDQlLg0KDQotIExvw6BpIEdlbnRvbyBjxaluZyBraMOhIHBo4buVIGJp4bq/biwgY2hp4bq/bSBn4bqnbiAzNiUuDQoNCi0gTG/DoGkgQ2hpbnN0cmFwIMOtdCBwaOG7lSBiaeG6v24gbmjhuqV0LCBjaGnhur9tIGtob+G6o25nIDIwJS4NCg0KIyMgQuG6o25nIHThuqduIHPhu5EgZ2nhu69hIDIgYmnhur9uIA0KDQoqKmdp4bubaSB0w61uaCB2w6AgxJHhuqNvIHNpbmggc+G7kW5nKioNCg0KYGBge3J9DQpjIDwtIHRhYmxlKGQkc2V4LGQkaXNsYW5kKQ0KYw0KcHJvcC50YWJsZShjKQ0KYGBgDQoNCi0tLSAqKk5o4bqtbiB4ZXQqKjoNCg0KLSBCaXNjb2UgY8OzIHThu5VuZyBz4buRIGNoaW0gY8OhbmggY+G7pXQgbmhp4buBdSBuaOG6pXQgKDE2MyksIHRp4bq/cCB0aGVvIGzDoCBEcmVhbSAoMTIzKSwgdsOgIMOtdCBuaOG6pXQgbMOgIFRvcmdlcnNlbiAoNDcpLg0KDQotIEThu7FhIHbDoG8gYuG6o25nIHThuqduIHN14bqldCwgdGEgdGjhuqV5IFPhu5EgbMaw4bujbmcgY2hpbSBjw6FuaCBj4buldCDEkeG7sWMgdsOgIGPDoWkgdHLDqm4gbeG7l2kgxJHhuqNvIGtow6EgY8OibiBi4bqxbmcsIGtow7RuZyBjw7Mgc+G7sSBjaMOqbmggbOG7h2NoIGzhu5tuIGdp4buvYSBoYWkgZ2nhu5tpIHTDrW5oLg0KDQotIEJpc2NvZSBjw7Mgc+G7kSBsxrDhu6NuZyBjaGltIGPDoW5oIGPhu6V0IMSR4buxYyB2w6AgY8OhaSDEkeG7gXUgY2FvIG5o4bqldCwgY2hvIHRo4bqleSBy4bqxbmcgxJHDonkgY8OzIHRo4buDIGzDoCBtw7RpIHRyxrDhu51uZyBz4buRbmcgxrBhIHRow61jaCBj4bunYSBjaGltIGPDoW5oIGPhu6V0IHRyb25nIHF14bqnbiDEkeG6o28gUGFsbWVyLg0KDQoqKkxvw6BpIHbDoCDEkeG6o28gc2luaCBz4buRbmcqKg0KDQpgYGB7cn0NCmggPC0gdGFibGUoZCRzcGVjaWVzLGQkaXNsYW5kKQ0KaA0KcHJvcC50YWJsZShoKQ0KYGBgDQotICoqTmjhuq1uIHjDqXQqKjoNCg0KLSBUcsOqbiDEkeG6o28gQmlzY29lLCBsb8OgaSBHZW50b28gY2hp4bq/bSB04bu3IGzhu4cgY2FvIG5o4bqldCB24bubaSAzNS43NCUsIHRyb25nIGtoaSBsb8OgaSBBZGVsaWUgY2hp4bq/bSAxMy4yMSUsIHbDoCBraMO0bmcgY8OzIGxvw6BpIENoaW5zdHJhcCBuw6BvLg0KDQotIFRyw6puIMSR4bqjbyBEcmVhbSwgbG/DoGkgQ2hpbnN0cmFwIGNoaeG6v20gdOG7tyBs4buHIGNhbyBuaOG6pXQgduG7m2kgMjAuNDIlLCB0aGVvIHNhdSBsw6AgbG/DoGkgQWRlbGllIHbhu5tpIDE2LjUyJSwgdsOgIGtow7RuZyBjw7MgbG/DoGkgR2VudG9vIG7DoG8uDQoNCi0gVHLDqm4gxJHhuqNvIFRvcmdlcnNlbiwgY2jhu4kgY8OzIGxvw6BpIEFkZWxpZSB4deG6pXQgaGnhu4duIHbhu5tpIHThu7cgbOG7hyAxNC4xMSUsIHbDoCBraMO0bmcgY8OzIGxvw6BpIENoaW5zdHJhcCBoYXkgR2VudG9vIG7DoG8uDQoNCg0KIyAqKjIuIFbhur0gxJHhu5MgdGjhu4sqKg0KDQojIyAyLjEgxJDhu5MgdGjhu4sgY+G7mXQgDQpW4bq9IMSR4buTIHRo4buLIGPhu5l0IGNobyBCaeG6v24gbG/DoGkgKHNwZWNpZXMpDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChkLCBhZXMoc3BlY2llcyxmaWxsPXNwZWNpZXMpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gJ2RvZGdlJykNCmBgYA0KDQoNCk5ow6xuIHbDoG8gYmnhu4N1IMSR4buTIHRhIHRo4bqleSBsb8OgaSBBZGVsaWUgY2hp4bq/bSB04bu3IGzhu4cgbmhp4buBdSBuaOG6pXQsIGvhur8gxJHhur9uIGzDoCBHZW50b28gdsOgIGN14buRaSBjw7luZyBsw6AgQ2hpbnN0cmFwLg0KDQpDaMO6bmcgdGEgY8OzIHPhuq9wIHjhur9wIGzhuqFpIGJp4buDdSDEkeG7kyB0aGVvIHRo4bupIHThu7EgdMSDbmcgZOG6p24gdsOgIGhp4buDbiB0aOG7iyBz4buRIGPDoSB0aOG7gyB0csOqbiB04burbmcgbG/DoGk6DQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpkICU+JQ0KICBmaWx0ZXIoc3BlY2llcyAlaW4lIGMoIkFkZWxpZSIsICJDaGluc3RyYXAiLCAiR2VudG9vIikpICU+JQ0KICBncm91cF9ieShzcGVjaWVzKSAlPiUNCiAgY291bnQoKSAlPiUNCiAgZ2dwbG90KGFlcyhyZW9yZGVyKHNwZWNpZXMsLW4pLCBuKSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuNyxmaWxsPSJicm93biIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLCB2anVzdCA9IDIsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDQpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9ICJOdW1iZXIgb2YgUGVuZ3VpbnMiLA0KICAgICAgIHRpdGxlID0gIk51bWJlciBvZiBQZW5ndWlucyBieSBTcGVjaWVzIiwNCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBDdXN0b20gUGVuZ3VpbnMgRGF0YXNldCIpIC0+PiBwMQ0KDQojIEhp4buDbiB0aOG7iyBiaeG7g3UgxJHhu5MNCnAxDQpgYGANCg0KUXVheSBuZ8aw4bujYyBiaeG7g3UgxJHhu5MsIG5oxrAgc2F1Og0KDQpgYGB7cn0NCnAxICsgY29vcmRfZmxpcCgpDQpgYGANCg0KDQpMw7pjIG7DoHkgduG7m2kgYmnhu4N1IMSR4buTIGPhu5l0IG5nYW5nLCBjw6FjIHPhu5EgY8OzIHRyw6puIGJp4buDdSDEkeG7kyBi4buLIG3huqV0LiBEbyDEkcOzIHRhIGhp4buHdSBjaOG7iW5oIG5oxrAgc2F1Og0KDQpIaeG7h3UgY2jhu4luaCBuaMawIHNhdToNCg0KYGBge3J9DQpwZW5ndWluc19jb3VudCA8LSBkICU+JQ0KICBncm91cF9ieShzcGVjaWVzKSAlPiUNCiAgY291bnQoKQ0KdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSkNCnAyIDwtIGdncGxvdChwZW5ndWluc19jb3VudCwgYWVzKHJlb3JkZXIoc3BlY2llcywgbiksIG4pKSArDQogIGdlb21fY29sKHdpZHRoID0gMC43LGZpbGw9ImJyb3duIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0ID0gMS4yLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA1KSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSAiTnVtYmVyIG9mIFBlbmd1aW5zIiwNCiAgICAgICB0aXRsZSA9ICJOdW1iZXIgb2YgUGVuZ3VpbnMgYnkgU3BlY2llcyIsDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogQ3VzdG9tIFBlbmd1aW5zIERhdGFzZXQiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgbWF4KHBlbmd1aW5zX2NvdW50JG4pLCAxMCkpDQpwMg0KYGBgDQoNClPhu60gZOG7pW5nIHRoZW1lIGPhu6dhIG3hu5l0IHPhu5EgdOG6oXAgY2jDrSBu4buVaSB0aeG6v25nOg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2d0aGVtZXMpDQpwMiArIA0KICB0aGVtZV9lY29ub21pc3QoaG9yaXpvbnRhbCA9IEZBTFNFKSsNCiAgc2NhbGVfZmlsbF9lY29ub21pc3QoKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCmQgJT4lDQogIGZpbHRlcihzcGVjaWVzICVpbiUgYygiQWRlbGllIiwgIkNoaW5zdHJhcCIsICJHZW50b28iKSkgJT4lDQogIGdyb3VwX2J5KHNwZWNpZXMpICU+JQ0KICBjb3VudCgpICU+JQ0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIoc3BlY2llcywgbiksIG4sIGZpbGwgPSBzcGVjaWVzKSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuNywgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0ID0gMS4yLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA1KSArDQogIGxhYnMoeCA9IE5VTEwsDQogICAgICAgeSA9ICJT4buRIGzGsOG7o25nIiwNCiAgICAgICB0aXRsZSA9ICJT4buRIGzGsOG7o25nIGNoaW0gY8OhbmggY+G7pXQgdGhlbyBsb8OgaSIsDQogICAgICAgY2FwdGlvbiA9ICJOZ3Xhu5NuIGThu68gbGnhu4d1OiBodHRwczovL2dpdGh1Yi5jb20vYWxsaXNvbmhvcnN0L3BhbG1lcnBlbmd1aW5zIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwMCwgMTApKSAtPiBwMw0KcHJpbnQocDMpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdndGhlbWVzKQ0KcDMgKyANCiAgdGhlbWVfZWNvbm9taXN0KGhvcml6b250YWwgPSBGQUxTRSkgKyANCiAgc2NhbGVfZmlsbF9lY29ub21pc3QoKQ0KDQpgYGANCg0KLS0tICoqTmjhuq1uIHjDqXQqKjogxJDhu5MgdGjhu4sgxJHDoyDEkcaw4bujYyBj4bqjaSB0aeG6v24gbeG7mXQgY8OhY2ggaG/DoG4gY2jhu4luaCB2w6AgxJHhurlwIGjGoW4uIE5ow6xuIHbDoG8gYmnhu4N1IMSR4buTIHRhIHRo4bqleSBsb8OgaSBBZGVsaWUgY2hp4bq/bSB04bu3IGzhu4cgbmhp4buBdSBuaOG6pXQsIHbhu5tpIDE0NiBjw6EgdGjhu4Mga+G6vyDEkeG6v24gbMOgIEdlbnRvbyB24bubaSAxMTkgY8OhIHRo4buDIHbDoCBjdeG7kWkgY8O5bmcgbMOgIENoaW5zdHJhcCB24bubaSA2OCBjw6EgdGjhu4MuDQoNCg0KIyAqKjMuIMav4bubYyBsxrDhu6NuZyB04bu3IGzhu4cqKg0KDQotLS0gQ8O0bmcgdGjhu6ljIMaw4bubYyBsxrDhu6NuZyB04buJIGzhu4cgKGNobyAxIHThu5VuZyB0aOG7gyk6DQoNClxbIA0KXGhhdHtwfSAtIFpfe1xhbHBoYS8yfSBcc3FydHtcZnJhY3tcaGF0e3B9KDEgLSBcaGF0e3B9KX17bn19IFxsZSBQIFxsZSBcaGF0e3B9ICsgWl97XGFscGhhLzJ9IFxzcXJ0e1xmcmFje1xoYXR7cH0oMSAtIFxoYXR7cH0pfXtufX0NClxdDQoNClRyb25nIMSRw7M6DQoNCi0gXChcaGF0e3B9XCkgbMOgIHThu7cgbOG7hyBt4bqrdSBj4bunYSBt4bupYyDEkeG7mSBuZ2/huqFpIGjDrG5oLg0KLSBcKFBcKSBsw6AgdOG7tyBs4buHIHPhu5EgbMaw4bujbmcgY+G7p2EgdOG7q25nIHBow6JuIGxv4bqhaSBuZ2/huqFpIGjDrG5oLg0KLSBcKFpfe1xhbHBoYS8yfVwpIGzDoCBnacOhIHRy4buLIGNyaXRpY2FsIHThu6sgcGjDom4gcGjhu5FpIGNodeG6qW4gdMawxqFuZyDhu6luZyB24bubaSBt4bupYyB0aW4gY+G6rXkgXCgxIC0gXGFscGhhXCkuDQotIFwoblwpIGzDoCBrw61jaCB0aMaw4bubYyBt4bqrdS4NCg0Kxq/hu5tjIGzGsOG7o25nIGdp4buRbmcgY8OhbmggY+G7pXQgxJHhu7FjLCDEkeG7k25nIHRo4budaSBraeG7g20gxJHhu4tuaCB4ZW0gdOG7tyBs4buHICUgY8OhIHRo4buDIGPDsyDEkeG6oXQgNTAlIGhheSBraMO0bmcgKGdp4bqjIHRodXnhur90IEhvPTUwJSkNCg0KYGBge3J9DQptYWwgPC0gZFtkJHNleCA9PSAibWFsZSIsXQ0KcHJvcC50ZXN0KGxlbmd0aChkJHNleCksIGxlbmd0aChkJHNleCksIHAgPSAwLjUpDQpgYGANCg0KVsOsIHBfdmFsdWUgPSAyLjJlLTE2IDwgMSUuIERvIMSRw7MsIGLDoWMgYuG7jyBIMC4gVuG6rXkgdOG7tyBs4buHIGNvbiDEkeG7sWMga2jDtG5nIMSR4bqhdCA1MCUuDQoNCsav4bubYyBsxrDhu6NuZyBjw6FjIGxvw6BpIHNpbmggc+G7kW5nIOG7nyDEkOG6o28gQmlzY29lLCDEkeG7k25nIHRo4budaSBraeG7g20gxJHhu4tuaCB4ZW0gc+G7kSBjw6EgdGjhu4Mgc+G7kW5nIOG7nyBCaXNjb2UgY8OzIMSR4bqhdCA0MCUgaGF5IGtow7RuZyAoR2nhuqMgdGh1eeG6v3QgSDA9MC40DQoNCmBgYHtyfQ0KQWRlIDwtIGRbZCRpc2xhbmQgPT0gIkJpc2NvZSIsXQ0KcHJvcC50ZXN0KGxlbmd0aChkJGlzbGFuZCksIGxlbmd0aChkJGlzbGFuZCksIHAgPSAwLjQpDQpgYGANClbDrCBwX3ZhbHVlID0gMi4yZS0xNiA8IDElLiBEbyDEkcOzLCBiw6FjIGLhu48gSDAuIFbhuq15IHThu7cgbOG7hyBjw6EgdGjhu4Mgc+G7kW5nIOG7nyDEkeG6o28gQmlzb2NlIGtow7RuZyDEkeG6oXQgNDAlLg0KDQojICoqNC7Gr+G7m2MgbMaw4bujbmcgY2jDqm5oIGzhu4djaCAyIHThu7cgbOG7hyoqDQoNClRyb25nIMSRw7M6DQoNCi0gXChcaGF0e3B9XzFcKSB2w6AgXChcaGF0e3B9XzJcKSBsw6AgdOG7tyBs4buHIGNo4buJIHPhu5EgeOG6v3AgaOG6oW5nIG5nb+G6oWkgaMOsbmggY2FvIGjGoW4gMSB0cm9uZyBt4bqrdSBuYW0gdsOgIG7hu68gdMawxqFuZyDhu6luZy4NCi0gXChwXzFcKSB2w6AgXChwXzJcKSBsw6AgdOG7tyBs4buHIGNo4buJIHPhu5EgeOG6v3AgaOG6oW5nIG5nb+G6oWkgaMOsbmggY2FvIGjGoW4gMSB0cm9uZyB0b8OgbiBi4buZIHThu5VuZyB0aOG7gyBuYW0gdsOgIG7hu68gdMawxqFuZyDhu6luZy4NCi0gXChuXzFcKSB2w6AgXChuXzJcKSBsw6Aga8OtY2ggdGjGsOG7m2MgY+G7p2EgbeG6q3UgbmFtIHbDoCBu4buvIHTGsMahbmcg4bupbmcuDQotIFwoWl97XGFscGhhLzJ9XCkgbMOgIGdpw6EgdHLhu4sgY3JpdGljYWwgdOG7qyBwaMOibiBwaOG7kWkgY2h14bqpbiB0xrDGoW5nIOG7qW5nIHbhu5tpIG3hu6ljIHRpbiBj4bqteSBcKDEgLSBcYWxwaGFcKS4NCg0KVGjhu7FjIGhp4buHbiBiw6BpIHRvw6FuIGtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IHPhu7EgYuG6sW5nIG5oYXUgduG7gSB04bu3IGzhu4cgY8OhIHRo4buDIMSR4buxYyB2w6AgY8OhaSBz4buRbmcg4bufIMSR4bqjbyBCaXNvY2UgMiB04buVbmcgdGjhu4MsIG5naMSpYSBsw6AgY2jDum5nIHRhIHRo4buxYyBoaeG7h24gYsOgaSB0b8OhbiBraeG7g20gxJHhu4tuaCBIMDpwMT1wMg0KDQpgYGB7cn0NCmQ0IDwtIGRbZCRzZXggPT0gIm1hbGUiLF0NCmQ0ZiA8LSBkW2Qkc2V4PT0iZmVtYWxlIixdDQpkNGQ0IDwtIGQ0W2Q0JGlzbGFuZCA9PSJCaXNjb2UiLF0NCmQ0ZmQ0IDwtIGQ0ZltkNGYkaXNsYW5kID09ICJCaXNjb2UiLF0NCg0KYSA8LSBjKG5yb3coZDQpLCBucm93KGQ0ZikpDQpiIDwtIGMobnJvdyhkNGQ0KSwgbnJvdyhkNGZkNCkpDQoNCnByb3AudGVzdChiLGEpDQpgYGANCg0KduG7m2kgcF92YWx1ZSA9IDAuOTUzNSwgY2jhuqVwIG5o4bqtbiBIMC4gVuG6rXkgdOG7tyBs4buHIGPDoSB0aOG7gyDEkeG7sWMg4bufIMSR4bqjbyBCaXNjb2UgYuG6sW5nIHbhu5tpIHThu7cgbOG7hyBjw6FpIHPhu5FuZyDhu58gxJHhuqNvIEJpc2NvZS4NCg0KDQoNCiMgKio1LiBUw61uaCBy4bunaSBybyB0xrDGoW5nIMSR4buRaSoqDQoNCi0tLSBUcm9uZyBwaOG6p24gbsOgeSwgdMO0aSB0aeG6v24gaMOgbmggdMOtbmggcuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgDQpgYGB7cn0NCmggPC0gdGFibGUoZCRzcGVjaWVzLGQkaXNsYW5kKQ0KYWRkbWFyZ2lucyhoKQ0KYGBgDQoNClbDrCBi4bqjbmcgdOG6p24gc+G7kSBjw7MgZOG6oW5nIG1hIHRy4bqtbiAzeDMsIGRvIMSRw7MgdGEga2jDtG5nIHRo4buDIGTDuW5nIFJlbHJpc2sgxJHhu4MgdMOtbmggdG/DoW4gcuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgxJHGsOG7o2MsIGRvIMSRw7MgdGEgdMOtbmggdGjhu6cgY8O0bmcgdOG7q25nIGPhurdwIHbhu5tpIG5oYXUgbmjGsCBzYXU6DQoNCkPhu5EgxJHhu4tuaCBsb8OgaSBBZGVsaWUsIHRhIHPhur0gdMOtbmggcuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgY+G7p2EgbG/DoGkgQWRlbGllIHNvIHbhu5tpIDMgxJHhuqNvLiBExrDhu5tpIMSRw6J5IGzDoCBk4buvIGxp4buHdSB04burIGLhuqNuZyB04bqnbiBz4buROg0KDQpgYGB7cn0NCiMgROG7ryBsaeG7h3UNCmRhdGEgPC0gZGF0YS5mcmFtZSgNCiAgU3BlY2llcyA9IGMoIkFkZWxpZSIsICJDaGluc3RyYXAiLCAiR2VudG9vIiksDQogIEJpc2NvZSA9IGMoNDQsIDAsIDExOSksDQogIERyZWFtID0gYyg1NSwgNjgsIDApLA0KICBUb3JnZXJzZW4gPSBjKDQ3LCAwLCAwKSwNCiAgU3VtID0gYygxNDYsIDY4LCAxMTkpDQopDQpkYXRhDQpgYGANCg0KVGjhu7FjIGhp4buHbiB0w61uaCB0b8OhbiwgbmjGsCBzYXU6DQoNCg0KYGBge3J9DQpQX0Jpc2NvZV9BZGVsaWUgPC0gZGF0YSRCaXNjb2VbMV0gLyBkYXRhJFN1bVsxXQ0KUF9EcmVhbV9BZGVsaWUgPC0gZGF0YSREcmVhbVsxXSAvIGRhdGEkU3VtWzFdDQpQX1RvcmdlcnNlbl9BZGVsaWUgPC0gZGF0YSRUb3JnZXJzZW5bMV0gLyBkYXRhJFN1bVsxXQ0KUF9CaXNjb2VfQWRlbGllDQpQX0RyZWFtX0FkZWxpZQ0KUF9Ub3JnZXJzZW5fQWRlbGllDQpgYGANCg0KUuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgY2hvIEFkZWxpZQ0KDQpgYGB7cn0NCiMgUuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgY2hvIEFkZWxpZQ0KUlJfMSA8LSBQX0Jpc2NvZV9BZGVsaWUgLyBQX0RyZWFtX0FkZWxpZQ0KUlJfMQ0KYGBgDQoNCi0gKipL4bq/dCBsdeG6rW4qKjogUuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgY2hvIEFkZWxpZSAoUlJfMSkgbMOgIGtob+G6o25nIDAuODAuIMSQaeG7gXUgbsOgeSBjw7MgbmdoxKlhIGzDoCBBZGVsaWUg4bufIMSR4bqjbyBCaXNjb2UgY8OzIG5ndXkgY8ahIHBow6JuIGLhu5EgY2jhu4kgYuG6sW5nIDAuODAgbOG6p24gc28gduG7m2kgQWRlbGllIOG7nyDEkeG6o28gRHJlYW0uDQoNCi0tLSBUxrDGoW5nIHThu7EsIHRhIGPDsyB0aOG7gyB0w61uaCBy4bunaSBybyB0xrDGoW5nIMSR4buRaSBj4bunYSBsb8OgaSBBZGVsaWUg4bufIMSQ4bqjbyBCaXNjb2Ugc28gduG7m2kgxJDhuqNvIFRvcmdlcnNlbiBuaMawIHNhdToNCg0KYGBge3J9DQpSUl8yIDwtIFBfQmlzY29lX0FkZWxpZSAvIFBfVG9yZ2Vyc2VuX0FkZWxpZQ0KUlJfMg0KYGBgDQotICoqS+G6v3QgbHXhuq1uKio6IFLhu6dpIHJvIHTGsMahbmcgxJHhu5FpIGNobyBBZGVsaWUgKFJSXzIpIGzDoCBraG/huqNuZyAwLjk0LiDEkGnhu4F1IG7DoHkgY8OzIG5naMSpYSBsw6AgQWRlbGllIOG7nyDEkeG6o28gQmlzY29lIGPDsyBuZ3V5IGPGoSBwaMOibiBi4buRIGNo4buJIGLhurFuZyAwLjk0IGzhuqduIHNvIHbhu5tpIEFkZWxpZSDhu58gxJHhuqNvIFRvcmdlcnNlbi4NCg0KLS0tIFTGsMahbmcgdOG7sSwgdGEgY8OzIHRo4buDIHTDrW5oIHLhu6dpIHJvIHTGsMahbmcgxJHhu5FpIGPhu6dhIGxvw6BpIEFkZWxpZSDhu58gxJDhuqNvIERyZWFtIHNvIHbhu5tpIMSQ4bqjbyBUb3JnZXJzZW4gbmjGsCBzYXU6DQoNCmBgYHtyfQ0KUlJfMyA8LSBQX0RyZWFtX0FkZWxpZSAvIFBfVG9yZ2Vyc2VuX0FkZWxpZQ0KUlJfMw0KYGBgDQoNCi0gKipL4bq/dCBsdeG6rW4qKjogUuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgY2hvIEFkZWxpZSAoUlJfMykgbMOgIGtob+G6o25nIDEuMTcuIMSQaeG7gXUgbsOgeSBjw7MgbmdoxKlhIGzDoCBBZGVsaWUg4bufIMSR4bqjbyBEcmVhbSBjw7Mgbmd1eSBjxqEgcGjDom4gYuG7kSBi4bqxbmcgMS4xNyBs4bqnbiBzbyB24bubaSBBZGVsaWUg4bufIMSR4bqjbyBEcmVhbS4NCg0KDQoNCiMgKio2LiDGr+G7m2MgbMaw4bujbmcgb2RkIHJhdGlvKioNCg0KxJDhuqd1IHRpw6puIHRhIGzhuq1wIGLhuqNuZyB04bqnbiBz4buRIGNobyAyIGJp4bq/biBgc2V4YCB2w6AgYHNwZWNpZXNgDQoNCmBgYHtyfQ0Kb2RkIDwtIHRhYmxlKGQkc3BlY2llcyxkJHNleCkNCmFkZG1hcmdpbnMob2RkKQ0KYGBgDQoNClTGsMahbmcgdOG7sSwgdsOsIMSRw6J5IGzDoCBtYSB0cuG6rW4gM3gyIGRvIMSRw7MgdGEga2jDtG5nIGTDuW5nIGPDonUgbOG7h25oIMSR4buDIHTDrW5oIG9kZCByYXRpbyDEkcaw4bujYy4gVGhheSB2w6BvIMSRw7MsIHRhIGzDoG0gdGjhu6cgY8O0bmcgY2hvIHThu6tuZyBj4bq3cCBiaeG7g3UgaGnhu4duIGPhu6dhIHThu6tuZyBiaeG6v24gduG7m2kgbmhhdS4NCg0KTMOgbSBt4bubaSBs4bqhaSBi4bqjbmcgdOG6p24gc+G7kSDEkeG7gyB0w61uaC4NCmBgYHtyfQ0KZGE2IDwtIG1hdHJpeChjKDczLCA3MywgMzQsIDM0LCA1OCwgNjEpLCBucm93ID0gMywgYnlyb3cgPSBUUlVFLA0KICAgICAgICAgICAgICAgZGltbmFtZXMgPSBsaXN0KGMoIkFkZWxpZSIsICJDaGluc3RyYXAiLCAiR2VudG9vIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiZmVtYWxlIiwgIm1hbGUiKSkpDQpyb3duYW1lcyhkYXRhKSA8LSBjKCJBZGVsaWUiLCAiQ2hpbnN0cmFwIiwgIkdlbnRvbyIpDQpjb2xuYW1lcyhkYXRhKSA8LSBjKCJmZW1hbGUiLCAibWFsZSIpDQpkYTYNCmBgYA0KDQpUw61uaCBPZGRzLXJhdGlvIHThu7cgbOG7hyBuYW0gbuG7ryBj4bunYSBsb8OgaSBBZGVsaWUgdsOgIENoaW50cmFwIHhlbSBsaeG7h3UgcuG6sW5nIHThu7cgbOG7hyBuYW0vIG7hu68gY+G7p2EgMiBsb8OgaSBuw6B5IGPDsyBz4buxIGtow6FjIGJp4buHdCBoYXkga2jDtG5nDQoNCmBgYHtyfQ0KYV9hZGVsaWUgPC0gZGE2WyJBZGVsaWUiLCAiZmVtYWxlIl0NCmJfYWRlbGllIDwtIGRhNlsiQWRlbGllIiwgIm1hbGUiXQ0KY19jaGluc3RyYXAgPC0gZGE2WyJDaGluc3RyYXAiLCAiZmVtYWxlIl0NCmRfY2hpbnN0cmFwIDwtIGRhNlsiQ2hpbnN0cmFwIiwgIm1hbGUiXQ0KDQpPUl9hYyA8LSAoYV9hZGVsaWUgLyBiX2FkZWxpZSkgLyAoY19jaGluc3RyYXAgLyBkX2NoaW5zdHJhcCkNCk9SX2FjDQpgYGANCg0KLS0tICoqTmjhuq1uIHjDqXQqKjogVuG6rXkgduG7m2kgb2RkcyByYXRpbyA9MSB0aMOsIHThu7cgbOG7hyBuYW0gbuG7ryDhu58gY+G6oyAyIGxvw6BpIEFkZWxpZSB2w6AgQ2hpbnN0cmFwIGzDoCBuaMawIG5oYXUuDQoNClTGsMahbmcgdOG7sSwgdGEgY8OzIHRo4buDIHTDrW5oIG9kZHMgcmF0aW8gY2hvIGxvw6BpIENoaW5zdHJhcCB2w6AgR2VudG9vIG5oxrAgc2F1Og0KDQpgYGB7cn0NCmVfZ2VudG9vIDwtIGRhNlsiR2VudG9vIiwiZmVtYWxlIl0NCmZfZ2VudG9vIDwtIGRhNlsiR2VudG9vIiwibWFsZSJdDQpPUl9jZyA8LSAoY19jaGluc3RyYXAgLyBkX2NoaW5zdHJhcCkvKGVfZ2VudG9vL2ZfZ2VudG9vKQ0KT1JfY2cNCmBgYA0KLS0tICoqTmjhuq1uIHjDqXQqKjogS2hpIHTDrW5oIHRvw6FuIE9kZHMgUmF0aW8gZ2nhu69hIGxvw6BpIENoaW5zdHJhcCB2w6AgR2VudG9vIHbDoCBr4bq/dCBxdeG6oyBsw6AgMS4wNTE3MjQsIMSRaeG7gXUgbsOgeSBjw7MgbmdoxKlhIHThu5NuIHThuqFpIHPhu7EgY2jDqm5oIGzhu4djaCBnaeG7r2EgY8OhIHRo4buDIMSR4buxYyB2w6AgY8OhaSBj4bunYSBj4bqjIDIgbG/DoGkuIEPhu6UgdGjhu4MsIHPhu7EgY2jDqm5oIGzhu4djaCDEkeG6v24gdOG7qyB2aeG7h2MgbG/DoGkgR2VudG9vIGPDsyA2MSBjw6EgdGjhu4MgxJHhu7FjIG5oaeG7gXUgaMahbiBjw6EgdGjhu4MgY8OhaSAoNTggY8OhIHRo4buDKS4NCg0K