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\)\(\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\)\(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\)\(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 sexspecies

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