Giới thiệu


1. Nhiệm vụ

Yêu cầu: Vẽ ít nhất 30 đồ thị dạng bar chart cho bộ dữ liệu Diamonds - một bộ dữ thuộc gói package ggplot2.

2. Bộ dữ liệu Diamonds

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.0     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2     
## ── 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
data(package = 'ggplot2')
a <- diamonds #gán bộ dữ liệu vào a

dim(a)
## [1] 53940    10
names(a)
##  [1] "carat"   "cut"     "color"   "clarity" "depth"   "table"   "price"  
##  [8] "x"       "y"       "z"

Bộ dữ liệu Diamonds cho ta biết một số thông tin và thuộc tính của 53.940 viên kim cương (hàng) ứng với 10 biến (cột) bao gồm:

  • carat (trọng lượng): Đơn vị dùng để đo khối lượng của kim cương (1 carat = 0.2gram).

  • cut (giác cắt): Mô tả cách viên kim cương được cắt và xếp chồng.

  • color (màu sắc): Đánh giá mức độ màu sắc của kim cương, các viên kim cương không có màu sắc (D) được coi là cao cấp.

  • clarity (độ tinh khiết): Đo lường sự trong suốt của kim cương và xác định có hay không có các tạp chất/vết nứt.

  • depth (độ sâu): Đo lường tỷ lệ giữa chiều sâu và đường kính của viên kim cương.

  • table (bề mặt): Mặt được đánh bóng lớn nhất của viên kim Cương.

  • price (giá cả): Giá cả của một viên kim cương.

  • x,y,z (kích thước): Kích thước chiều dài, chiều rộng và chiều sâu của viên kim cương (mm).

Phân tích bộ dữ liệu theo biến lẻ


1. Theo biến carat (trọng lượng)

1.1. Số lượng viên kim cương theo 2 nhóm carat lớn/nhỏ

Đối với một viên kim lượng, trọng lượng carat càng lớn tức giá trị của một viên kim cương càng cao và ngược lại. Để dễ hình dung, ta chia trọng lượng carat thành 2 phần, trọng lượng carat nhỏtrọng lượng carat lớn với:

  • Trọng lượng carat nhỏ: viên kim cương có carat < 1

  • Trọng lượng carat lớn: viên kim cương có carat > 1

library(ggplot2)

a$c1 <- case_when(a$carat<=0.99 ~ 'Nhỏ', a$carat>=1 ~ 'Lớn')

b <- a %>% mutate(c1 = cut(price,2, label = c('Nhỏ', 'Lớn')))
b %>% ggplot(aes(x = c1)) +
  geom_bar(fill = 'skyblue') +
  labs(title = "Hình 1: Số lượng viên kim cương theo 2 nhóm carat", x = 'Trọng lượng', y = 'Số lượng')

=> Kết quả trả về cho chúng ta biết (Hình 1), số lượng viên kim cương có trọng lượng carat nhỏ chiếm đông đảo (gần 90%) trong tổng số 53.940 viên. Cho thấy sự hiếm hoi trong việc tìm kiếm những viên kim cương có trọng lượng carat lớn.

1.2. Số lượng viên kim cương theo 5 nhóm carat

Ta cũng có thể chia số lượng viên kim cương thành 5 nhóm khác nhau là: Rất nhỏ, Nhỏ, Trung bình, Lớn, Rất lớn để dễ so sánh giữa các loại kim cương với nhau như (Hình 2) dưới đây.

c <- a %>% mutate(carat_C = cut(carat,5, label = c('Rất nhỏ', 'Nhỏ','Trung bình','Lớn','Rất lớn'))) #gán dữ liệu vào c

c %>% ggplot(aes(x = carat_C)) +
  geom_bar(fill = 'skyblue') +
  labs(title = "Hình 2: Số lượng viên kim cương theo 5 nhóm carat", x = 'Trọng lượng', y = 'Số lượng')

2. Theo biến cut (giác cắt)

Thông thường, người mua kim cương sẽ quan tâm đến giác cắt vì nó ảnh hưởng lớn đến sự lấp lánh và độ chói của viên kim cương. Các viên kim cương có giác cắt tốt thường có khả năng phản xạ ánh sáng tốt, tạo ra hiệu ứng lấp lánh và sự chói lọi.

2.1. Số lượng kim cương theo biến cut

a %>% ggplot(aes(x = cut)) +
  geom_bar(fill = 'maroon') +
  labs(title = 'Hình 3: Số lượng kim cương theo biến giác cắt (cut)', x = "Loại", y = "Số lượng")

=> Trong (Hình 3), có 5 loại giác cắt khác nhau bao gồm: Fair (Khá tốt), Good (Tốt), Very good (Rất tốt), Premium (Cao cấp) và Ideal (Lý tưởng).

Số lượng kim cương phân bố cho mỗi loại giác cắt tăng dần, với loại Ideal chiếm số lượng lớn nhất, với hơn 20.000 viên. Điều này cho thấy sự tập trung của các nhà sản xuất kim cương vào việc tạo ra các giá trị tốt nhất cho các viên kim cương. Mặc dù loại Fair vẫn tồn tại, nhưng không phân bố nhiều. Người dùng có thể chọn loại kim cương phù hợp với nhu cầu của họ tùy thuộc vào mục đích sử dụng cụ thể.

2.2. Biểu đồ xoay trục số lượng kim cương theo giác cắt (cut)

Trong một số trường hợp, để phục vụ mục đích nghiên cứu, ta cũng có thể lựa chọn biểu dổ xoay trục để thuận tiện cho việc quan sát và phân tích như (Hình 4).

a %>% ggplot(aes(x = cut)) +
    geom_bar(fill = 'maroon') +
    labs(title = 'Hình 4: Biểu đồ xoay trục của số lượng kim cương theo biến giác cắt cut ', x = 'Loại', y = 'Số lượng') +
    coord_flip()

2.3. Biểu đồ tổng số lượng kim cương theo biến giác cắt cut

Nếu (Hình 3)(Hình 4) chỉ cho tao một cái nhìn tổng quát về số lượng kim cương thì với (Hình 5) sẽ cho ta một cái nhìn chi tiết hơn về số lượng kim cương theo từng loại giác cắt.

a %>% group_by(cut) %>% summarise(n = n()) %>%
  ggplot(aes(cut,n)) +
    geom_col(fill='maroon') +
    geom_text(aes(label = n),vjust = 2, color = 'white') +
    labs(title = 'Hình 5: Biểu đồ tổng số lượng kim cương theo biến giác cắt cut', x = 'Loại', y = 'Số lượng')

Cụ thể, ta thấy theo (Hình 5):

  • 1610 viên kim cương thuộc loại giác cắt Fair (Khá tốt).

  • 4906 viên kim cương thuộc loại giác cắt Good (Tốt).

  • 12082 viên kim cương thuộc loại giác cắt Very good (Rất tốt).

  • 13791 viên kim cương thuộc loại giác cắt Premium (Cao cấp).

  • 21551 viên kim cương thuộc loại giác cắt Ideal (Lý tưởng).

2.4. Biểu đồ số lượng kim cương theo biến giác cắt cut (thể hiện %)

Tương tự (Hình 5) ta cũng có thể quan sát bộ dữ liệu dưới dạng thể hiện là % như kết quả ở (Hình 6).

library(scales) 
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
a %>% group_by(cut) %>% summarise(n = n()) %>%
  ggplot(aes(cut,n)) +
  geom_col(fill='maroon') +
  geom_text(aes(label = percent(n/length(a$carat))),vjust = 2, color = 'white') +
  labs(title= 'Hình 6: Biểu đồ số lượng kim cương theo biến giác cắt cut (thể hiện %)', x = 'Loại', y = 'Số lượng')

=> Theo (Hình 6):

  • Số lượng kim cương theo giác cắt Fair chiếm: 3.0%

  • Số lượng kim cương theo giác cắt Good chiếm: 9.1%

  • Số lượng kim cương theo giác cắt Very good chiếm: 22.4%

  • Số lượng kim cương theo giác cắt Premium chiếm: 25.6%

  • Số lượng kim cương theo giác cắt Ideal chiếm: 40.0%

Qua phân tích, ta nhận thấy rằng loại kim cương Ideal chiếm tỷ lệ lớn nhất, gần bằng tổng tỷ lệ của hai loại Very Good và Premium kết hợp. Chỉ ra sự ưu tiên cao về chất lượng giác cắt Ideal so với các loại khác trong tập dữ liệu. Điều này có thể thể hiện sự đánh giá cao về mặt chất lượng và sự tinh tế trong quá trình chế tạo kim cương.

3. Theo biến color (màu sắc)

Màu sắc (color) của kim cương đề cập đến mức độ màu sắc tự nhiên của viên kim cương. Kim cương thường được đánh giá dựa trên thang đo màu sắc, và mức độ không màu được coi là lý tưởng.

Trong hệ thống GIA, màu sắc được đánh giá từ D đến Z, với:

  • D, E, F: Vô màu (Colorless)

  • G, H, I, J: Gần vô màu (Near Colorless)

  • K, L, M: Màu rất nhẹ (Faint)

  • N, O, P, Q, R: Màu nhẹ (Very Light)

  • S, T, U, V, W, X, Y, Z: Màu nhẹ đến màu rõ (Light to Fancy)

Mà trong bộ dữ liệu này, ta sẽ chỉ phân tích 2 nhóm màu bao gồm:

  • Vô màu: D, E, F

  • Gần vô màu: G, H, I, J

Số lượng kim cương theo biến color

a %>% group_by(color) %>% summarise(n = n()) %>%
  ggplot(aes(color,n)) +
  geom_col(fill='khaki') +
  geom_text(aes(label = percent(n/length(a$color))),vjust = 2, color = 'black') +
  labs(title= 'Hình 7: Biểu đồ số lượng kim cương theo biến color (màu sắc)', x = 'Loại', y = 'Số lượng')

Biểu đồ cung cấp cái nhìn tổng quan về sự phổ biến của các mức độ màu sắc trong bộ dữ liệu Diamonds và thể hiện sự đa dạng của các màu sắc trong thị trường kim cương.

=> Ở đây, chúng ta có thể nhận thấy mức độ phổ biến nhất là màu G, chiếm tỷ lệ 20.93%. Màu sắc tiếp theo là màu E với tỷ lệ 18.16%, và màu ít phổ biến nhất là màu J, chỉ chiếm tỷ lệ 5.21%. Tuy nhiên, từ khía cạnh khách quan, chênh lệch giữa các màu sắc không quá lớn, cho thấy thị trường kim cương có sự đa dạng trong màu sắc và không có một màu sắc nào chiếm ưu thế quá áp đảo. Điều này có thể cho thấy sự đa dạng và sự lựa chọn rộng rãi khi mua kim cương.

4. Theo biến clarity (độ trong suốt)

Clarity (Độ trong suốt) đo lường mức độ và sự xuất hiện của các tạp chất và khuyết điểm bên trong hay bề mặt của viên kim cương bao gồm các phân loại (chỉ tính theo bộ dữ liệu Diamonds):

  • IF - Trong suốt bên trong: Kim cương không có bất kỳ khuyết điểm nào nhìn thấy được bằng kính hiển vi 10x, nhưng có thể có một số tạp chất nhỏ bên ngoài.

  • VVS1 và VVS2 - Rất, rất ít tạp chất: Tạp chất rất nhỏ và khó nhận biết bằng kính hiển vi 10x.

  • VS1 và VS2 - Rất ít tạp chất: Tạp chất nhỏ và khó nhận biết bằng kính hiển vi 10x.

  • SI1 và SI2 - Có tạp chất: Tạp chất nhỏ và có thể nhận biết bằng kính hiển vi 10x.

  • I1 - Có nhiều tạp chất: Tạp chất lớn và rõ ràng thậm chí khi không sử dụng kính hiển vi.

Kim cương có độ trong suốt cao thường có giá trị cao hơn.

a %>% group_by(clarity) %>% summarise(n = n()) %>%
  ggplot(aes(clarity,n)) +
    geom_col(fill='forestgreen') +
    geom_text(aes(label = n),vjust = 0, color = 'navy') +
    labs(title = 'Hình 8: Biểu đồ tổng số lượng kim cương theo biến clarity', x = 'Độ trong suốt', y = 'Số lượng') + 
    coord_flip()

Thông qua (Hình 8), có thể nhận thấy rằng việc loại bỏ hoàn toàn tạp chất trong kim cương là một thách thức, do loại SI1 (có tạp chất) và loại VS2 (rất ít tạp chất) chiếm đa số với hơn 12.000 viên cho mỗi loại. Trong khi đó, kim cương IF (không có tạp chất) chỉ chiếm một lượng rất nhỏ với 1790 viên.

Mặc dù số lượng kim cương không có tạp chất là ít, nhưng những viên này thường được đánh giá cao về chất lượng. Điều này có thể là do các nhà điều tác kim cương tập trung vào việc tôn vinh giá trị và chất lượng cao của kim cương, và họ đã đạt được thành công trong việc giảm số lượng kim cương I1 (có nhiều tạp chất) xuống còn 741 viên.

5. Số lượng kim cương theo biến depth (độ sâu)

Depth (độ sâu) đo lường tỉ lệ giữa chiều cao của viên kim cương và chiều ngang của viên kim cương (đường kính). Depth thường được tính toán theo công thức:

\[ \text{Depth %} = \left( \frac{\text{Chiều cao}}{\text{Đường kính}} \right) \times 100 \]

Khi chọn kim cương, người tiêu dùng thường quan tâm đến sự cân bằng giữa depth và các yếu tố khác như màu sắc, độ trong suốt và giác cắt. Sự cân nhắc này giúp đảm bảo kim cương không chỉ đẹp về mặt màu sắc và trong suốt mà còn có khả năng phản xạ ánh sáng tối ưu.

d <- a %>% mutate(độ.sâu = cut(price,4, label = c('Khá tốt', 'Tốt','Cao cấp','Lý tưởng'))) #gán dữ liệu vào d

d %>% ggplot(aes(x = độ.sâu)) +
  geom_bar(fill = 'seagreen') +
  labs(title = "Hình 9: Số lượng viên kim cương theo biến depth (độ sâu)", x = 'Độ sâu', y = 'Số lượng')

= > Sau khi chia cột biến Depth thành 4 nhóm để phân tích, ta nhận thấy rằng nhóm ‘Khá tốt’ có số lượng kim cương phân bố cao nhất, áp đảo cả 3 nhóm còn lại. Điều này cho thấy rằng việc điều tác và tạo ra kim cương thuộc 3 nhóm còn lại (Tốt, Cao cấp, Lý tưởng) có thể là một thách thức, đặt ra yêu cầu cao về kỹ thuật và chất lượng của quá trình sản xuất kim cương.

6. Số lượng kim cương theo biến price (giá cả)

Trong ngành công nghiệp kim cương, giá cả của một viên kim cương được ảnh hưởng bởi nhiều yếu tố khác nhau, trong đó có các yếu tố chính như carat (trọng lượng), color (màu sắc), clarity (độ trong suốt), và cut (cắt). Yếu tố này được thường được biểu diễn dưới dạng giá trị tiền tệ, ví dụ như VNĐ.

Với bộ dữ liệu Diamonds, ta chia cột price thành 5 nhóm tương ứng:

  • Dưới 500 đơn vị tiền: Rất rẻ

  • Từ 501 đến 1000 đơn vị tiền: Rẻ

  • Từ 1001 đến 1500 đơn vị tiền: Vừa phải

  • Từ 1501 đến 2000 đơn vị tiền: Mắc

  • Trên 2001 đơn vị tiền: Rất mắc

a$giá.cả <- case_when(a$price<= 500 ~ 'Rất rẻ', a$price>=501 & a$price<=1000 ~ 'Rẻ', a$price>=1001 & a$price<=1500 ~ 'Vừa phải', a$price>=1501 & a$price<=2000 ~ 'Mắc', a$price>=2001 ~ 'Rất mắc')

e <- a %>% mutate(giá.cả = cut(price,5, label = c('Rất rẻ', 'Rẻ','Vừa phải','Mắc','Rất mắc')))
e %>% ggplot(aes(x = giá.cả)) +
  geom_bar(fill = 'sandybrown') +
  labs(title = 'Hình 10: Số lượng kim cương theo biến price (giá cả)', x = 'Giá cả', y = 'Số lượng')

=> Kết quả trả về từ (Hình 10) cho thấy một phân phối đáng chú ý về số lượng kim cương dựa trên mức giá. Cụ thể, số lượng kim cương ở mức giá ‘rất rẻ’ và ‘rẻ’ chiếm tỉ lệ vô cùng lớn, với hơn 30.000 viên kim cương. Ngược lại, số lượng kim cương ở mức giá ‘mắc’ và ‘rất mắc’ lại rất ít ỏi.

Dựa vào phân phối này, có thể suy luận rằng nhóm đối tượng chủ yếu của các viên kim cương thuộc mức giá thấp là tầng lớp khách hàng có thu nhập trung bình hoặc thấp. Trong khi đó, những viên kim cương ở mức giá ‘mắc’ và ‘rất mắc’ có thể là sản phẩm dành cho tầng lớp khách hàng giàu có hoặc mong muốn các viên kim cương có chất lượng và đặc tính cao hơn.

Phân tích bộ dữ liệu theo nhóm


1. Phân tích theo trung bình của biến carat (trọng lượng)

Để tiếp cận thông tin chi tiết về trung bình carat cho từng loại giác cắt của viên kim cương, chúng ta có thể dựa vào biểu đồ thống kê chi tiết được minh họa trong (Hình 11).

a %>% group_by(cut) %>% summarise(m= mean(carat)) %>%
  ggplot(aes(x = cut,y = m)) +
    geom_col(fill = 'gold') +
    geom_text(aes(label = round(m,2)), vjust = 2, color = 'red') +
    labs(title = 'Hình 11: Giác cắt theo trung bình biến carat', x = 'Màu', y = 'Trung bình carat')

Dựa vào (Hình 11), chúng ta có thể rút ra các nhận xét quan trọng như sau:

  • Kim cương loại Fair thể hiện trung bình theo biến carat là 1.05, đồng thời có sự phân bố cao nhất trong tất cả các loại giác cắt.

  • Các loại kim cương Good, Very Good, và Premium có trung bình theo biến carat lần lượt là 0.85, 0.81 và 0.89. Điều này cho thấy sự chênh lệch không lớn giữa ba loại này, và chúng đều giữ sự phân bố cao ở mức thứ hai.

  • Kim cương loại Ideal có trung bình theo biến carat thấp nhất là 0.1, và đồng thời thể hiện sự phân bố thấp nhất trong số các loại giác cắt.

2. Phân tích theo biến cut (giác cắt)

2.1. Số lượng viên kim cương có trọng lượng carat < 1 theo biến cut

Chúng ta cũng có thể tiến hành phân tích chi tiết hơn về dòng kim cương có trọng lượng carat nhỏ, tập trung vào yếu tố giác cắt (cut), nhằm đánh giá mức độ hiếm có của các kim cương trong mỗi loại giác cắt khác nhau.

b1 <- diamonds %>% filter(carat < 1) 
b1 %>% ggplot(aes(x=cut)) +
    geom_bar(fill = 'navy') +
    labs(title = 'Hình 12: Số lượng kim cương có trọng lượng carat nhỏ theo giác cắt (cut)', x = 'Giác cắt', y = 'Số lượng') +
    coord_flip()

=> Kết quả phân tích trả về cho biết (Hình 12) kim cương loại lý tưởng (Ideal) chiếm tỷ lệ lớn nhất trong tập dữ liệu, đồng thời kim cương loại khá tốt (Fair) chiếm tỷ lệ thấp nhất. Điều này cho thấy sự rộng lớn và đa dạng của dòng kim cương lý tưởng, với hơn 15,000 viên kim cương trong tập dữ liệu, mặc dù chúng có giác cắt tốt nhưng không hiếm.

2.2. Số lượng viên kim cương có trọng lượng carat > 1 theo biến cut

Tương tự, ta cũng có thể dễ dàng phân tích với các viên kim cương có trọng lượng carat lớn.

b2 <- diamonds %>% filter(carat > 1)
b2 %>% ggplot(aes(x=cut)) +
    geom_bar(fill = 'navy') +
    labs(title = 'Hình 13: Số lượng kim cương có trọng lượng carat lớn theo giác cắt (cut)', x = 'Loại', y = 'Số lượng') +
    coord_flip()

=> Kết quả trả về, như thể hiện trong (Hình 13), thể hiện sự đối ngược giữa kim cương có trọng lượng carat nhỏ và kim cương có trọng lượng carat lớn. Trong trường hợp của kim cương lớn, chúng phân bố rộng rãi đặc biệt trong các loại giác cắt cao cấp (Premium) và lý tưởng (Ideal), đặc biệt là trong loại cao cấp. Tuy nhiên, đối với giác cắt loại khá tốt (Fair), kim cương có trọng lượng carat lớn vẫn duy trì mức độ phân bố thấp.

2.3. Số lượng viên kim cương có độ trong suốt là IF và I1 theo biến cut

Ta xem kim cương loại IF (trong suốt bên trong) là màu xanh lá nhạt, kim cương loại I1 (nhiều tạp chất) là màu xanh lá đậm.

Khi ta muốn xem độ chênh lệch sự phân bố giữa kim cương loại trong suốt và kim cương có nhiều tạp chất, ta có thể quan sát biểu đồ bên dưới.

f <- a %>% group_by(cut, clarity) %>% summarise(n = n())
## `summarise()` has grouped output by 'cut'. You can override using the `.groups`
## argument.
f %>% ggplot(aes(x = cut, y = n)) +
  geom_col(data = f %>% filter(clarity == 'IF'), fill = 'darkseagreen') +
  geom_col(data = f %>% filter(clarity == 'I1'), fill = 'darkolivegreen') +
  labs(title = 'Hình 14: Số lượng viên kim cương có độ trong suốt là IF và I1 theo biến cut', x = 'Giác cắt', y = 'Số lượng')

=> Kết quả trả về (Hình 14) cho chúng ta thấy, mặc dù điều chế được những viên kim cương trong suốt bên trong là một thử thách như kim cương có giác cắt loại FairGood hoàn toàn không có độ trong suốt, chứa rất nhiều tạp chất. Tuy vậy các nhà điều chế kim cương vẫn cố gắng điều chế được loại kim cương này, nhằm tôn vinh những giá trị đẹp đẽ nhất của kim cương.

Như kim cương có giác cắt loại Ideal, một dòng kim cương lý tưởng nhưng sự phân bố của dòng kim cương trong suốt đã chiếm đông đảo.

2.4. Số lượng kim cương theo giác cắt của từng độ trong suốt

Với chức năng hỗ trợ của R, ta có thể thấy tùy vào mục đích nhu cầu nghiên cứu và phân tích mà chúng ta có thể chọn sử dụng 1 trong 3 biểu đồ bên dưới.

(Hình 15) cho chúng ta một cái nhìn tổng quát về số lượng kim cương theo giác cắt của từng độ trong suốt. Trong khi đó (Hình 16)(Hình 17) lại cho chúng ta một cái nhìn chi tiết hơn về số lượng kim cương.

a %>% group_by(cut,clarity) %>% summarise(n=n()) %>%
  ggplot(aes(x = cut,y = n)) +
    geom_col(fill = 'mediumslateblue') +
    facet_wrap(~clarity) +
    labs(title = 'Hình 15: Số lượng kim cương theo giác cắt của từng độ trong suốt', x = 'Độ trong suốt', y = 'Số lượng')
## `summarise()` has grouped output by 'cut'. You can override using the `.groups`
## argument.

a %>% group_by(cut,color) %>% summarise(n=n()) %>%
  ggplot(aes(x = cut,y = n)) +
    geom_col(fill = 'mediumslateblue') +
    facet_wrap(~color) +
    geom_text(aes(label = n),vjust = 0, color = 'mediumblue') +
    labs(title = 'Hình 16: Số lượng kim cương theo giác cắt của từng loại màu', x = 'Loại', y = 'Số lượng')
## `summarise()` has grouped output by 'cut'. You can override using the `.groups`
## argument.

ggplot(diamonds, aes(x = cut, fill = clarity)) +
  geom_bar(position = 'dodge') +
  facet_wrap(~clarity) +
  labs(title = 'Hình 17: Số lượng kim cương theo giác cắt của từng độ trong suốt (đa màu)', x = 'Giác Cắt', y = 'Số lượng')

Nhưng nhìn chung, chúng ta có thể nhận xét rằng:

  • Kim cương có giác cắt loại Fair có số lượng ít hơn những loại giác cắt khác, chúng chủ yếu tập trung ở những màu F, G, H với lần lượt là 312, 314, 303 viên.

  • Kim cương có giác cắt loại Good phân bố chủ yếu ở màu E, F với số lượng lần lượt là 933, 909.

  • Kim cương có giác cắt loại Very goodPremium có số lượng phân bố không quá chênh lệch nhau cao, chúng tập trung chủ yếu ở màu E, G lần lượt với số lượng là 2400, 23372299, 2924.

  • Kim cương có giác cắt loại Ideal, cấp độ lý tưởng, mặc dù không phân bố nhiều ở màu J chỉ có 896 màu nhưng chúng lại phân bố nhiều ở màu G với 4884.

2.5. Độ lệch chuẩn giá kim cương theo giác cắt

ggplot(diamonds, aes(x = cut, y = sd(price))) +
  geom_bar(fill = 'chartreuse', stat = 'identity') +
  labs(title = 'Hình 18: Độ lệch chuẩn giá kim cương theo giác cắt', x = 'Giác cắt', y = 'Độ lệch chuẩn giá')

=> Mỗi cột biểu diễn một mức độ độ lệch chuẩn tương ứng với loại giác cắt, và màu sắc của cột được chọn là chartreuse để tạo sự nổi bật. Độ lệch chuẩn tương ứng với 5 màu cũng biến thiên theo từng loại giác cắt. Càng là loại giác cắt có mức độ cao như Premium hay Ideal thì độ lệnh chuẩn giá càng lớn và ngược lại, độ lệch chuẩn giá thấp nhất là loại Fair.

2.6. Độ lệch chuẩn giá kim cương theo màu

ggplot(diamonds, aes(x = color, y = sd(price))) +
  geom_bar(fill = 'chartreuse', stat = 'identity') +
  labs(title = 'Hình 19: Độ lệch chuẩn giá kim cương theo màu', x = 'Màu', y = 'Độ lệch chuẩn giá')

Với 7 màu sắc D, E, F, G, H, I, K, ta thấy:

  • Màu G là màu có độ lệch chuẩn giá cao nhất.

  • Mức độ lệch chuẩn giá trung bình là màu Dmàu H.

  • Mức độ lệch chuẩn giá thấp nhất là màu J.

2.7. Độ lệch chuẩn giá kim cương theo độ trong suốt

ggplot(diamonds, aes(x = clarity, y = sd(price))) +
  geom_bar(fill = 'chartreuse', stat = 'identity') +
  labs(title = 'Hình 20: Độ lệch chuẩn mức độ màu của kim cương theo giác cắt', x = 'Giác cắt', y = 'Độ lệch chuẩn mức độ màu')

Với 8 mức độ trong suốt lần lượt là I1, SI2, SI1, VS2, VS1, VVS2, VVS1, IF ta thấy:

  • SI1 là mức có độ lệch chuẩn giá cao nhất.

  • Mức độ lệch chuẩn giá trung bình là độ trong suốt loại SI2VS1.

  • Mức độ lệch chuẩn giá thấp nhất là độ trong suốt loại ÌF.

3. Phân tích theo biến color (màu sắc)

3.1. Số lượng kim cương có giác cắt loại Premium và Good theo biến color

Ta xem kim cương có loại giác cắt là Premium là màu hồng nhạt và kim cương có loại giác cắt là Good có màu hồng đậm.

f <- a %>% group_by(color, cut) %>% summarise(n = n())
## `summarise()` has grouped output by 'color'. You can override using the
## `.groups` argument.
f %>% ggplot(aes(x = color, y = n)) +
  geom_col(data = f %>% filter(cut == 'Premium'), fill = 'lightpink') +
  geom_col(data = f %>% filter(cut == 'Good'), fill = 'brown') +
  labs(title = 'Hình 21: Số lượng kim cương có giác cắt loại Premium và Good theo biến color', x = 'Màu sắc', y = 'Số lượng')

So sánh số lượng kim cương có giác cắt loại Premium và Good theo màu sắc, ta thấy giữa các màu 2 loại kim cường phân bố khá đều nhau.

  • Với kim cương loại Premium chúng tập trung số lượng nhiều ở 3 màu E, F, G và tập trung ít nhất ở màu J.

  • Với kim cương loại Good chúng tập trung nhiều ở màu G và tập trung ít nhất ở màu J (tương tự như loại Premium).

3.2. Số lượng viên kim cương theo biến color của từng loại giác cắt

Ngoài 2 loại kim cương nói trên (giác cắt Premium và Good) ta cũng có thể so sánh cụ thể với từng loại kim cương theo màu sắc với biểu đồ (Hình 22). Hoặc ta có thể xem biểu đồ ở (Hình 23) thể hiện chi tiết tổng số viên kim cương theo biến color của từng loại giác cắt.

a %>% group_by(color,cut) %>% summarise(n=n()) %>%
  ggplot(aes(x = color,y = n)) +
    geom_col(fill = 'red') +
    facet_wrap(~cut) +
    labs(title = 'Hình 22: Số lượng viên kim cương theo biến color của từng loại giác cắt', x = 'Loại', y = 'Số lượng')
## `summarise()` has grouped output by 'color'. You can override using the
## `.groups` argument.

a %>% group_by(color,cut) %>% summarise(n=n()) %>%
  ggplot(aes(x = color,y = n)) +
    geom_col(fill = 'red') +
    facet_wrap(~ cut) +
    geom_text(aes(label = n),vjust = 0, color = 'mediumblue') +
    labs(title = 'Hình 23: Tổng số lượng viên kim cương theo biến color của từng loại giác cắt', x = 'Loại', y = 'Số lượng')
## `summarise()` has grouped output by 'color'. You can override using the
## `.groups` argument.

3.3. Số lượng kim cương theo tổng giá trị biến color của từng loại giác cắt

# Tính tổng giá trị kim cương theo "cut" và "color"
g <- diamonds %>%
  group_by(color, cut) %>%
  summarise(total_price = sum(price))
## `summarise()` has grouped output by 'color'. You can override using the
## `.groups` argument.
# Vẽ biểu đồ bar chart
ggplot(g, aes(x = color, y = total_price, fill = cut)) +
  geom_bar(stat = 'identity') +
  labs(title = 'Hình 24: Số lượng kim cương theo tổng giá trị biến color của từng loại giác cắt', x = 'Màu sắc', y = 'Tổng Giá trị') +
  scale_fill_brewer(palette = 'Set2')  # Sử dụng màu từ bảng màu Brewer

Biểu đồ (Hình 24) tương tự như biểu đồ (Hình 23)(Hình 22), tuy nhiên ưu điểm của loại này là chỉ có một biểu đồ có các cột chồng lên nhau thay vì chia nhỏ ra thành nhiều biểu đồ. Thuận tiện cho việc quan sát và so sánh.

3.4. Tổng giá trị theo phân loại và màu sắc

ggplot(diamonds, aes(x = color, fill = clarity)) +
  geom_bar(position = 'stack') +
  labs(title = 'Hình 25: Tổng giá trị theo phân loại và màu sắc', x = 'Loại', y = 'Tổng giá trị')

Với (Hình 25) ta nhận xét rằng:

  • Độ trong suốt là IF (trong suốt) vì rất khó điều chế nên mức độ phân bố của chúng vô cùng ít, với màu Dmàu J gần như là không có, tập trung phân bố cao ở màu G.

  • Độ trong suốt là SI1, SI2, VS1, VS2 rải rác ở các màu có độ phân bố gần như là đều nhau.

  • Độ trong suốt là VVS1, VVS2 cũng rải rác ở các màu có độ phân bố gần như là đều nhau.

4. Phân tích theo biến clarity (độ trong suốt)

Số lượng viên kim cương theo độ trong suốt của từng loại màu

a %>% group_by(cut,color) %>% summarise(m = mean(price)) %>%
  ggplot(aes(x = cut,y = m)) +
    geom_col(fill = 'gold') +
    facet_wrap(~color) +
    geom_text(aes(label = round(m)), vjust = 2, color = 'red') +
    labs(title = 'Hình 26: Số lượng viên kim cương theo độ trong suốt của từng loại màu', x = 'Loại', y = 'Số lượng')
## `summarise()` has grouped output by 'cut'. You can override using the `.groups`
## argument.

Các nhóm màu sắc được biểu diễn dưới dạng các nhóm con, và trên mỗi cột, có nhãn hiển thị giá trị trung bình giá làm tròn. Biểu đồ này giúp thấy rõ sự phân bố của giá trị trung bình giá của kim cương trong các nhóm độ trong suốt và màu sắc khác nhau.

5. Phân tích theo biến price (giá cả)

5.1. Trung bình mức giá của từng loại màu theo độ trong suốt

a %>% group_by(clarity,color) %>% summarise(m = mean(price)) %>%
  ggplot(aes(x = clarity,y = m)) +
    geom_col(fill = 'yellowgreen') +
    facet_wrap(~color) +
    labs(title = 'Hình 27: Trung bình mức giá của từng loại màu theo độ trong suốt', x = 'Giác cắt', y = 'Trung bình giá')
## `summarise()` has grouped output by 'clarity'. You can override using the
## `.groups` argument.

Với (Hình 27) ta thấy rằng;

  • Độ trong suốt IF không tạp chất ở màu D có trung bình giá cao vượt trội, áp đảo hơn những loại kim cương khác.

  • Hầu hết từng độ trong suốt ở các màu của viên kim cương đều có trung bình giá xêm xêm nhau, không chệnh lệch quá nhiều.

5.2. Giá trung bình của từng loại giác cắt

ggplot(diamonds, aes(x = cut, y = price)) +
  geom_bar(stat = 'summary', fun = 'mean', fill = 'orange') +
  labs(title = 'Hình 28: Giá trung bình của từng loại giác cắt', x = 'Giác cắt', y = 'Giá trung bình')

Kết quả trả về cho chúng ta thấy,

  • Loại Premium có trung bình giá cao nhất với giá trị trung bình hơn 4500.

  • Loại Fair có trung bình giá cao thứ 2 với giá trị trung bình xấp xĩ gần bằng 4500.

  • Loại Goodvery good có trung bình giá trị cao thứ 3, đều có giá trị trung bình xấp xĩ bằng 4000.

  • Loại Ideal có trung bình giá trị thấp nhát, giá trị trung bình bằng 3500.

ggplot(diamonds, aes(x = cut, fill = cut, y = price)) +                                  
  geom_bar(stat = 'summary', fun = 'mean', position = 'dodge') +
  labs(title = 'Hình 29: Giá trung bình của từng loại giác cắt (đa màu sắc)', x = 'Giác cắt', y = 'Giá trung bình')      

Biểu đồ (Hình 28)(Hình 29) có cùng một cấu trúc cơ bản, nhưng biểu đồ (Hình 29) được thiết kế với một góc thẩm mỹ cao hơn, nhấn mạnh vào sự trực quan và dễ hiểu. Sự chú ý đặc biệt được đặt vào việc tạo điểm nhấn và sự đồng nhất trong màu sắc, giúp biểu đồ trở nên hấp dẫn và dễ theo dõi.

5.3. So sánh giá kim cương giữa các loại màu sắc và giác cắt

ggplot(diamonds, aes(x = cut, fill = color, y = price)) +
  geom_bar(stat = 'summary', fun = 'mean', position = 'dodge') +
  labs(title = 'Hình 30: So sánh giá kim cương giữa các loại màu sắc và giác cắt', x = 'Loại', y = 'Giá') +
  scale_fill_brewer(palette = 'Set4') 
## Warning: Unknown palette: "Set4"

=> Biểu đồ cột so sánh giá kim cương giữa các loại màu sắc và giác cắt. Mỗi cột biểu diễn giá trung bình của kim cương trong từng loại màu sắc, được phân chia theo giác cắt, với màu sắc của cột được đặc trưng bởi loại màu sắc.

LS0tDQp0aXRsZTogIk5oaeG7h20gduG7pSA0Ig0KYXV0aG9yOiAiTmd1eeG7hW4gUGjhuqFtIFRow7p5IEFuIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIG51bWJlciBzZWN0aW9uOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUg6JU06JVMsICVkIC0gJW0gLSAlWScpYCINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojICoqR2nhu5tpIHRoaeG7h3UgKioNCioqKg0KIyMgKioxLiBOaGnhu4dtIHbhu6UqKg0KDQpZw6p1IGPhuqd1OiBW4bq9IMOtdCBuaOG6pXQgKiozMCDEkeG7kyB0aOG7iyBk4bqhbmcgYmFyIGNoYXJ0KiogY2hvIGLhu5kgZOG7ryBsaeG7h3UgKipEaWFtb25kcyoqIC0gbeG7mXQgYuG7mSBk4buvIHRodeG7mWMgZ8OzaSBwYWNrYWdlICpnZ3Bsb3QyKi4NCg0KIyMgKioyLiBC4buZIGThu68gbGnhu4d1IERpYW1vbmRzKioNCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmRhdGEocGFja2FnZSA9ICdnZ3Bsb3QyJykNCmEgPC0gZGlhbW9uZHMgI2fDoW4gYuG7mSBk4buvIGxp4buHdSB2w6BvIGENCg0KZGltKGEpDQpuYW1lcyhhKQ0KYGBgDQoNCkLhu5kgZOG7ryBsaeG7h3UgRGlhbW9uZHMgY2hvIHRhIGJp4bq/dCBt4buZdCBz4buRIHRow7RuZyB0aW4gdsOgIHRodeG7mWMgdMOtbmggY+G7p2EgKio1My45NDAgdmnDqm4ga2ltIGPGsMahbmcqKiAoaMOgbmcpIOG7qW5nIHbhu5tpICoqMTAgYmnhur9uKiogKGPhu5l0KSBiYW8gZ+G7k206DQoNCiogKipjYXJhdCAodHLhu41uZyBsxrDhu6NuZykqKjogxJDGoW4gduG7iyBkw7luZyDEkeG7gyDEkW8ga2jhu5FpIGzGsOG7o25nIGPhu6dhIGtpbSBjxrDGoW5nICgxIGNhcmF0ID0gMC4yZ3JhbSkuDQoNCiogKipjdXQgKGdpw6FjIGPhuq90KSoqOiBNw7QgdOG6oyBjw6FjaCB2acOqbiBraW0gY8awxqFuZyDEkcaw4bujYyBj4bqvdCB2w6AgeOG6v3AgY2jhu5NuZy4NCg0KKiAqKmNvbG9yIChtw6B1IHPhuq9jKSoqOiDEkMOhbmggZ2nDoSBt4bupYyDEkeG7mSBtw6B1IHPhuq9jIGPhu6dhIGtpbSBjxrDGoW5nLCBjw6FjIHZpw6puIGtpbSBjxrDGoW5nIGtow7RuZyBjw7MgbcOgdSBz4bqvYyAoRCkgxJHGsOG7o2MgY29pIGzDoCBjYW8gY+G6pXAuDQoNCiogKipjbGFyaXR5ICjEkeG7mSB0aW5oIGtoaeG6v3QpKio6IMSQbyBsxrDhu51uZyBz4buxIHRyb25nIHN14buRdCBj4bunYSBraW0gY8awxqFuZyB2w6AgeMOhYyDEkeG7i25oIGPDsyBoYXkga2jDtG5nIGPDsyBjw6FjIHThuqFwIGNo4bqldC924bq/dCBu4bupdC4NCg0KKiAqKmRlcHRoICjEkeG7mSBzw6J1KSoqOiDEkG8gbMaw4budbmcgdOG7tyBs4buHIGdp4buvYSBjaGnhu4F1IHPDonUgdsOgIMSRxrDhu51uZyBrw61uaCBj4bunYSB2acOqbiBraW0gY8awxqFuZy4NCg0KKiAqKnRhYmxlIChi4buBIG3hurd0KSoqOiAgTeG6t3QgxJHGsOG7o2MgxJHDoW5oIGLDs25nIGzhu5tuIG5o4bqldCBj4bunYSB2acOqbiBraW0gQ8awxqFuZy4NCg0KKiAqKnByaWNlIChnacOhIGPhuqMpKio6IEdpw6EgY+G6oyBj4bunYSBt4buZdCB2acOqbiBraW0gY8awxqFuZy4NCg0KKiAqKngseSx6IChrw61jaCB0aMaw4bubYykqKjogS8OtY2ggdGjGsOG7m2MgY2hp4buBdSBkw6BpLCBjaGnhu4F1IHLhu5luZyB2w6AgY2hp4buBdSBzw6J1IGPhu6dhIHZpw6puIGtpbSBjxrDGoW5nIChtbSkuDQoNCiMgKipQaMOibiB0w61jaCBi4buZIGThu68gbGnhu4d1IHRoZW8gYmnhur9uIGzhursqKg0KKioqDQojIyAqKjEuIFRoZW8gYmnhur9uIGNhcmF0ICh0cuG7jW5nIGzGsOG7o25nKSoqDQoNCiMjIyAqKjEuMS4gU+G7kSBsxrDhu6NuZyB2acOqbiBraW0gY8awxqFuZyB0aGVvIDIgbmjDs20gY2FyYXQgbOG7m24vbmjhu48qKg0KDQrEkOG7kWkgduG7m2kgbeG7mXQgdmnDqm4ga2ltIGzGsOG7o25nLCB0cuG7jW5nIGzGsOG7o25nIGNhcmF0IGPDoG5nIGzhu5tuIHThu6ljIGdpw6EgdHLhu4sgY+G7p2EgbeG7mXQgdmnDqm4ga2ltIGPGsMahbmcgY8OgbmcgY2FvIHbDoCBuZ8aw4bujYyBs4bqhaS4gxJDhu4MgZOG7hSBow6xuaCBkdW5nLCB0YSBjaGlhIHRy4buNbmcgbMaw4bujbmcgY2FyYXQgdGjDoG5oIDIgcGjhuqduLCAqKnRy4buNbmcgbMaw4bujbmcgY2FyYXQgbmjhu48qKiB2w6AgKip0cuG7jW5nIGzGsOG7o25nIGNhcmF0IGzhu5tuKiogduG7m2k6DQoNCiogKipUcuG7jW5nIGzGsOG7o25nIGNhcmF0IG5o4buPKio6IHZpw6puIGtpbSBjxrDGoW5nIGPDsyBjYXJhdCA8IDENCg0KKiAqKlRy4buNbmcgbMaw4bujbmcgY2FyYXQgbOG7m24qKjogdmnDqm4ga2ltIGPGsMahbmcgY8OzIGNhcmF0ID4gMQ0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KYSRjMSA8LSBjYXNlX3doZW4oYSRjYXJhdDw9MC45OSB+ICdOaOG7jycsIGEkY2FyYXQ+PTEgfiAnTOG7m24nKQ0KDQpiIDwtIGEgJT4lIG11dGF0ZShjMSA9IGN1dChwcmljZSwyLCBsYWJlbCA9IGMoJ05o4buPJywgJ0zhu5tuJykpKQ0KYiAlPiUgZ2dwbG90KGFlcyh4ID0gYzEpKSArDQogIGdlb21fYmFyKGZpbGwgPSAnc2t5Ymx1ZScpICsNCiAgbGFicyh0aXRsZSA9ICJIw6xuaCAxOiBT4buRIGzGsOG7o25nIHZpw6puIGtpbSBjxrDGoW5nIHRoZW8gMiBuaMOzbSBjYXJhdCIsIHggPSAnVHLhu41uZyBsxrDhu6NuZycsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KPT4gS+G6v3QgcXXhuqMgdHLhuqMgduG7gSBjaG8gY2jDum5nIHRhIGJp4bq/dCAqKEjDrG5oIDEpKiwgc+G7kSBsxrDhu6NuZyB2acOqbiBraW0gY8awxqFuZyBjw7MgdHLhu41uZyBsxrDhu6NuZyBjYXJhdCBuaOG7jyBjaGnhur9tIMSRw7RuZyDEkeG6o28gKGfhuqduIDkwJSkgdHJvbmcgdOG7lW5nIHPhu5EgNTMuOTQwIHZpw6puLiBDaG8gdGjhuqV5IHPhu7EgaGnhur9tIGhvaSB0cm9uZyB2aeG7h2MgdMOsbSBraeG6v20gbmjhu69uZyB2acOqbiBraW0gY8awxqFuZyBjw7MgdHLhu41uZyBsxrDhu6NuZyBjYXJhdCBs4bubbi4NCg0KIyMjICoqMS4yLiBT4buRIGzGsOG7o25nIHZpw6puIGtpbSBjxrDGoW5nIHRoZW8gNSBuaMOzbSBjYXJhdCoqDQoNClRhIGPFqW5nIGPDsyB0aOG7gyBjaGlhIHPhu5EgbMaw4bujbmcgdmnDqm4ga2ltIGPGsMahbmcgdGjDoG5oIDUgbmjDs20ga2jDoWMgbmhhdSBsw6A6IFLhuqV0IG5o4buPLCBOaOG7jywgVHJ1bmcgYsOsbmgsIEzhu5tuLCBS4bqldCBs4bubbiDEkeG7gyBk4buFIHNvIHPDoW5oIGdp4buvYSBjw6FjIGxv4bqhaSBraW0gY8awxqFuZyB24bubaSBuaGF1IG5oxrAgKihIw6xuaCAyKSogZMaw4bubaSDEkcOieS4NCg0KYGBge3J9DQpjIDwtIGEgJT4lIG11dGF0ZShjYXJhdF9DID0gY3V0KGNhcmF0LDUsIGxhYmVsID0gYygnUuG6pXQgbmjhu48nLCAnTmjhu48nLCdUcnVuZyBiw6xuaCcsJ0zhu5tuJywnUuG6pXQgbOG7m24nKSkpICNnw6FuIGThu68gbGnhu4d1IHbDoG8gYw0KDQpjICU+JSBnZ3Bsb3QoYWVzKHggPSBjYXJhdF9DKSkgKw0KICBnZW9tX2JhcihmaWxsID0gJ3NreWJsdWUnKSArDQogIGxhYnModGl0bGUgPSAiSMOsbmggMjogU+G7kSBsxrDhu6NuZyB2acOqbiBraW0gY8awxqFuZyB0aGVvIDUgbmjDs20gY2FyYXQiLCB4ID0gJ1Ry4buNbmcgbMaw4bujbmcnLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCiMjICoqMi4gVGhlbyBiaeG6v24gY3V0IChnacOhYyBj4bqvdCkqKg0KDQpUaMO0bmcgdGjGsOG7nW5nLCBuZ8aw4budaSBtdWEga2ltIGPGsMahbmcgc+G6vSBxdWFuIHTDom0gxJHhur9uIGdpw6FjIGPhuq90IHbDrCBuw7Mg4bqjbmggaMaw4bufbmcgbOG7m24gxJHhur9uIHPhu7EgbOG6pXAgbMOhbmggdsOgIMSR4buZIGNow7NpIGPhu6dhIHZpw6puIGtpbSBjxrDGoW5nLiBDw6FjIHZpw6puIGtpbSBjxrDGoW5nIGPDsyBnacOhYyBj4bqvdCB04buRdCB0aMaw4budbmcgY8OzIGto4bqjIG7Eg25nIHBo4bqjbiB44bqhIMOhbmggc8OhbmcgdOG7kXQsIHThuqFvIHJhIGhp4buHdSDhu6luZyBs4bqlcCBsw6FuaCB2w6Agc+G7sSBjaMOzaSBs4buNaS4gDQoNCiMjIyAqKjIuMS4gU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGJp4bq/biBjdXQqKg0KDQpgYGB7cn0NCmEgJT4lIGdncGxvdChhZXMoeCA9IGN1dCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICdtYXJvb24nKSArDQogIGxhYnModGl0bGUgPSAnSMOsbmggMzogU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGJp4bq/biBnacOhYyBj4bqvdCAoY3V0KScsIHggPSAiTG/huqFpIiwgeSA9ICJT4buRIGzGsOG7o25nIikNCmBgYA0KDQo9PiBUcm9uZyAqKEjDrG5oIDMpKiwgY8OzIDUgbG/huqFpIGdpw6FjIGPhuq90IGtow6FjIG5oYXUgYmFvIGfhu5NtOiAqKkZhaXIqKiAoS2jDoSB04buRdCksICoqR29vZCoqIChU4buRdCksICoqVmVyeSBnb29kKiogKFLhuqV0IHThu5F0KSwgKipQcmVtaXVtKiogKENhbyBj4bqlcCkgdsOgICoqSWRlYWwqKiAoTMO9IHTGsOG7n25nKS4gDQoNClPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgcGjDom4gYuG7kSBjaG8gbeG7l2kgbG/huqFpIGdpw6FjIGPhuq90IHTEg25nIGThuqduLCB24bubaSBsb+G6oWkgSWRlYWwgY2hp4bq/bSBz4buRIGzGsOG7o25nIGzhu5tuIG5o4bqldCwgduG7m2kgaMahbiAyMC4wMDAgdmnDqm4uIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IHPhu7EgdOG6rXAgdHJ1bmcgY+G7p2EgY8OhYyBuaMOgIHPhuqNuIHh14bqldCBraW0gY8awxqFuZyB2w6BvIHZp4buHYyB04bqhbyByYSBjw6FjIGdpw6EgdHLhu4sgdOG7kXQgbmjhuqV0IGNobyBjw6FjIHZpw6puIGtpbSBjxrDGoW5nLiBN4bq3YyBkw7kgbG/huqFpIEZhaXIgduG6q24gdOG7k24gdOG6oWksIG5oxrBuZyBraMO0bmcgcGjDom4gYuG7kSBuaGnhu4F1LiBOZ8aw4budaSBkw7luZyBjw7MgdGjhu4MgY2jhu41uIGxv4bqhaSBraW0gY8awxqFuZyBwaMO5IGjhu6NwIHbhu5tpIG5odSBj4bqndSBj4bunYSBo4buNIHTDuXkgdGh14buZYyB2w6BvIG3hu6VjIMSRw61jaCBz4butIGThu6VuZyBj4bulIHRo4buDLg0KDQojIyMgKioyLjIuIEJp4buDdSDEkeG7kyB4b2F5IHRy4bulYyBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8gZ2nDoWMgY+G6r3QgKGN1dCkqKiANCg0KVHJvbmcgbeG7mXQgc+G7kSB0csaw4budbmcgaOG7o3AsIMSR4buDIHBo4bulYyB24bulIG3hu6VjIMSRw61jaCBuZ2hpw6puIGPhu6l1LCB0YSBjxaluZyBjw7MgdGjhu4MgbOG7sWEgY2jhu41uIGJp4buDdSBk4buVIHhvYXkgdHLhu6VjIMSR4buDIHRodeG6rW4gdGnhu4duIGNobyB2aeG7h2MgcXVhbiBzw6F0IHbDoCBwaMOibiB0w61jaCBuaMawICooSMOsbmggNCkqLg0KDQpgYGB7cn0NCmEgJT4lIGdncGxvdChhZXMoeCA9IGN1dCkpICsNCiAgICBnZW9tX2JhcihmaWxsID0gJ21hcm9vbicpICsNCiAgICBsYWJzKHRpdGxlID0gJ0jDrG5oIDQ6IEJp4buDdSDEkeG7kyB4b2F5IHRy4bulYyBj4bunYSBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8gYmnhur9uIGdpw6FjIGPhuq90IGN1dCAnLCB4ID0gJ0xv4bqhaScsIHkgPSAnU+G7kSBsxrDhu6NuZycpICsNCiAgICBjb29yZF9mbGlwKCkNCmBgYA0KDQojIyMgKioyLjMuIEJp4buDdSDEkeG7kyB04buVbmcgc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGJp4bq/biBnacOhYyBj4bqvdCBjdXQqKg0KDQpO4bq/dSAqKEjDrG5oIDMpKiB2w6AgKihIw6xuaCA0KSogY2jhu4kgY2hvIHRhbyBt4buZdCBjw6FpIG5ow6xuIHThu5VuZyBxdcOhdCB24buBIHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGjDrCB24bubaSAqKEjDrG5oIDUpKiBz4bq9IGNobyB0YSBt4buZdCBjw6FpIG5ow6xuIGNoaSB0aeG6v3QgaMahbiB24buBIHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyB04burbmcgbG/huqFpIGdpw6FjIGPhuq90Lg0KDQpgYGB7cn0NCmEgJT4lIGdyb3VwX2J5KGN1dCkgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyhjdXQsbikpICsNCiAgICBnZW9tX2NvbChmaWxsPSdtYXJvb24nKSArDQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLHZqdXN0ID0gMiwgY29sb3IgPSAnd2hpdGUnKSArDQogICAgbGFicyh0aXRsZSA9ICdIw6xuaCA1OiBCaeG7g3UgxJHhu5MgdOG7lW5nIHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBiaeG6v24gZ2nDoWMgY+G6r3QgY3V0JywgeCA9ICdMb+G6oWknLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCkPhu6UgdGjhu4MsIHRhIHRo4bqleSB0aGVvICooSMOsbmggNSkqOg0KDQoqIEPDsyAqKjE2MTAqKiB2acOqbiBraW0gY8awxqFuZyB0aHXhu5ljIGxv4bqhaSBnacOhYyBj4bqvdCAqKkZhaXIqKiAoS2jDoSB04buRdCkuDQoNCiogQ8OzICoqNDkwNioqIHZpw6puIGtpbSBjxrDGoW5nIHRodeG7mWMgbG/huqFpIGdpw6FjIGPhuq90ICoqR29vZCoqIChU4buRdCkuDQoNCiogQ8OzICoqMTIwODIqKiB2acOqbiBraW0gY8awxqFuZyB0aHXhu5ljIGxv4bqhaSBnacOhYyBj4bqvdCAqKlZlcnkgZ29vZCoqIChS4bqldCB04buRdCkuDQoNCiogQ8OzICoqMTM3OTEqKiB2acOqbiBraW0gY8awxqFuZyB0aHXhu5ljIGxv4bqhaSBnacOhYyBj4bqvdCAqKlByZW1pdW0qKiAoQ2FvIGPhuqVwKS4NCg0KKiBDw7MgKioyMTU1MSoqIHZpw6puIGtpbSBjxrDGoW5nIHRodeG7mWMgbG/huqFpIGdpw6FjIGPhuq90ICoqSWRlYWwqKiAoTMO9IHTGsOG7n25nKS4NCg0KIyMjICoqMi40LiBCaeG7g3UgxJHhu5Mgc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGJp4bq/biBnacOhYyBj4bqvdCBjdXQgKHRo4buDIGhp4buHbiAlKSoqDQoNClTGsMahbmcgdOG7sSAqKEjDrG5oIDUpKiB0YSBjxaluZyBjw7MgdGjhu4MgcXVhbiBzw6F0IGLhu5kgZOG7ryBsaeG7h3UgZMaw4bubaSBk4bqhbmcgdGjhu4MgaGnhu4duIGzDoCAlIG5oxrAga+G6v3QgcXXhuqMg4bufICooSMOsbmggNikqLg0KDQpgYGB7cn0NCmxpYnJhcnkoc2NhbGVzKSANCg0KYSAlPiUgZ3JvdXBfYnkoY3V0KSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKGN1dCxuKSkgKw0KICBnZW9tX2NvbChmaWxsPSdtYXJvb24nKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KG4vbGVuZ3RoKGEkY2FyYXQpKSksdmp1c3QgPSAyLCBjb2xvciA9ICd3aGl0ZScpICsNCiAgbGFicyh0aXRsZT0gJ0jDrG5oIDY6IEJp4buDdSDEkeG7kyBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8gYmnhur9uIGdpw6FjIGPhuq90IGN1dCAodGjhu4MgaGnhu4duICUpJywgeCA9ICdMb+G6oWknLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCj0+IFRoZW8gKihIw6xuaCA2KSo6DQoNCiogU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGdpw6FjIGPhuq90ICoqRmFpcioqIGNoaeG6v206ICoqMy4wJSoqDQoNCiogU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGdpw6FjIGPhuq90ICoqR29vZCoqIGNoaeG6v206ICoqOS4xJSoqDQoNCiogU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGdpw6FjIGPhuq90ICoqVmVyeSBnb29kKiogY2hp4bq/bTogKioyMi40JSoqDQoNCiogU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGdpw6FjIGPhuq90ICoqUHJlbWl1bSoqIGNoaeG6v206ICoqMjUuNiUqKg0KDQoqIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBnacOhYyBj4bqvdCAqKklkZWFsKiogY2hp4bq/bTogKio0MC4wJSoqDQoNClF1YSBwaMOibiB0w61jaCwgdGEgbmjhuq1uIHRo4bqleSBy4bqxbmcgbG/huqFpIGtpbSBjxrDGoW5nIElkZWFsIGNoaeG6v20gdOG7tyBs4buHIGzhu5tuIG5o4bqldCwgZ+G6p24gYuG6sW5nIHThu5VuZyB04bu3IGzhu4cgY+G7p2EgaGFpIGxv4bqhaSBWZXJ5IEdvb2QgdsOgIFByZW1pdW0ga+G6v3QgaOG7o3AuIENo4buJIHJhIHPhu7EgxrB1IHRpw6puIGNhbyB24buBIGNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCBJZGVhbCBzbyB24bubaSBjw6FjIGxv4bqhaSBraMOhYyB0cm9uZyB04bqtcCBk4buvIGxp4buHdS4gxJBp4buBdSBuw6B5IGPDsyB0aOG7gyB0aOG7gyBoaeG7h24gc+G7sSDEkcOhbmggZ2nDoSBjYW8gduG7gSBt4bq3dCBjaOG6pXQgbMaw4bujbmcgdsOgIHPhu7EgdGluaCB04bq/IHRyb25nIHF1w6EgdHLDrG5oIGNo4bq/IHThuqFvIGtpbSBjxrDGoW5nLg0KDQojIyAqKjMuIFRoZW8gYmnhur9uIGNvbG9yIChtw6B1IHPhuq9jKSoqDQoNCk3DoHUgc+G6r2MgKGNvbG9yKSBj4bunYSBraW0gY8awxqFuZyDEkeG7gSBj4bqtcCDEkeG6v24gbeG7qWMgxJHhu5kgbcOgdSBz4bqvYyB04buxIG5oacOqbiBj4bunYSB2acOqbiBraW0gY8awxqFuZy4gS2ltIGPGsMahbmcgdGjGsOG7nW5nIMSRxrDhu6NjIMSRw6FuaCBnacOhIGThu7FhIHRyw6puIHRoYW5nIMSRbyBtw6B1IHPhuq9jLCB2w6AgbeG7qWMgxJHhu5kga2jDtG5nIG3DoHUgxJHGsOG7o2MgY29pIGzDoCBsw70gdMaw4bufbmcuICANCg0KVHJvbmcgaOG7hyB0aOG7kW5nIEdJQSwgbcOgdSBz4bqvYyDEkcaw4bujYyDEkcOhbmggZ2nDoSB04burIEQgxJHhur9uIFosIHbhu5tpOg0KDQoqICoqRCwgRSwgRioqOiBWw7QgbcOgdSAoQ29sb3JsZXNzKQ0KDQoqICoqRywgSCwgSSwgSioqOiBH4bqnbiB2w7QgbcOgdSAoTmVhciBDb2xvcmxlc3MpDQoNCiogKipLLCBMLCBNKio6IE3DoHUgcuG6pXQgbmjhurkgKEZhaW50KQ0KDQoqICoqTiwgTywgUCwgUSwgUioqOiBNw6B1IG5o4bq5IChWZXJ5IExpZ2h0KQ0KDQoqICoqUywgVCwgVSwgViwgVywgWCwgWSwgWioqOiBNw6B1IG5o4bq5IMSR4bq/biBtw6B1IHLDtSAoTGlnaHQgdG8gRmFuY3kpDQoNCk3DoCB0cm9uZyBi4buZIGThu68gbGnhu4d1IG7DoHksIHRhIHPhur0gY2jhu4kgcGjDom4gdMOtY2ggMiBuaMOzbSBtw6B1IGJhbyBn4buTbToNCg0KKiAqKlbDtCBtw6B1Kio6IEQsIEUsIEYNCg0KKiAqKkfhuqduIHbDtCBtw6B1Kio6IEcsIEgsIEksIEoNCg0KIyMjICoqU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGJp4bq/biBjb2xvcioqDQoNCmBgYHtyfQ0KYSAlPiUgZ3JvdXBfYnkoY29sb3IpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoY29sb3IsbikpICsNCiAgZ2VvbV9jb2woZmlsbD0na2hha2knKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KG4vbGVuZ3RoKGEkY29sb3IpKSksdmp1c3QgPSAyLCBjb2xvciA9ICdibGFjaycpICsNCiAgbGFicyh0aXRsZT0gJ0jDrG5oIDc6IEJp4buDdSDEkeG7kyBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8gYmnhur9uIGNvbG9yIChtw6B1IHPhuq9jKScsIHggPSAnTG/huqFpJywgeSA9ICdT4buRIGzGsOG7o25nJykNCmBgYA0KDQpCaeG7g3UgxJHhu5MgY3VuZyBj4bqlcCBjw6FpIG5ow6xuIHThu5VuZyBxdWFuIHbhu4Egc+G7sSBwaOG7lSBiaeG6v24gY+G7p2EgY8OhYyBt4bupYyDEkeG7mSBtw6B1IHPhuq9jIHRyb25nIGLhu5kgZOG7ryBsaeG7h3UgRGlhbW9uZHMgdsOgIHRo4buDIGhp4buHbiBz4buxIMSRYSBk4bqhbmcgY+G7p2EgY8OhYyBtw6B1IHPhuq9jIHRyb25nIHRo4buLIHRyxrDhu51uZyBraW0gY8awxqFuZy4NCg0KPT4g4bueIMSRw6J5LCBjaMO6bmcgdGEgY8OzIHRo4buDIG5o4bqtbiB0aOG6pXkgbeG7qWMgxJHhu5kgcGjhu5UgYmnhur9uIG5o4bqldCBsw6AgKiptw6B1IEcqKiwgY2hp4bq/bSB04bu3IGzhu4cgKioyMC45MyUqKi4gTcOgdSBz4bqvYyB0aeG6v3AgdGhlbyBsw6AgKiptw6B1IEUqKiB24bubaSB04bu3IGzhu4cgKioxOC4xNiUqKiwgdsOgIG3DoHUgw610IHBo4buVIGJp4bq/biBuaOG6pXQgbMOgICoqbcOgdSBKKiosIGNo4buJIGNoaeG6v20gdOG7tyBs4buHICoqNS4yMSUqKi4gVHV5IG5oacOqbiwgdOG7qyBraMOtYSBj4bqhbmgga2jDoWNoIHF1YW4sIGNow6puaCBs4buHY2ggZ2nhu69hIGPDoWMgbcOgdSBz4bqvYyBraMO0bmcgcXXDoSBs4bubbiwgY2hvIHRo4bqleSB0aOG7iyB0csaw4budbmcga2ltIGPGsMahbmcgY8OzIHPhu7EgxJFhIGThuqFuZyB0cm9uZyBtw6B1IHPhuq9jIHbDoCBraMO0bmcgY8OzIG3hu5l0IG3DoHUgc+G6r2MgbsOgbyBjaGnhur9tIMawdSB0aOG6vyBxdcOhIMOhcCDEkeG6o28uIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgY2hvIHRo4bqleSBz4buxIMSRYSBk4bqhbmcgdsOgIHPhu7EgbOG7sWEgY2jhu41uIHLhu5luZyByw6NpIGtoaSBtdWEga2ltIGPGsMahbmcuDQoNCiMjICoqNC4gVGhlbyBiaeG6v24gY2xhcml0eSAoxJHhu5kgdHJvbmcgc3Xhu5F0KSoqDQoNCkNsYXJpdHkgKMSQ4buZIHRyb25nIHN14buRdCkgxJFvIGzGsOG7nW5nIG3hu6ljIMSR4buZIHbDoCBz4buxIHh14bqldCBoaeG7h24gY+G7p2EgY8OhYyB04bqhcCBjaOG6pXQgdsOgIGtodXnhur90IMSRaeG7g20gYsOqbiB0cm9uZyBoYXkgYuG7gSBt4bq3dCBj4bunYSB2acOqbiBraW0gY8awxqFuZyBiYW8gZ+G7k20gY8OhYyBwaMOibiBsb+G6oWkgKGNo4buJIHTDrW5oIHRoZW8gYuG7mSBk4buvIGxp4buHdSBEaWFtb25kcyk6DQoNCiogKipJRiAtIFRyb25nIHN14buRdCBiw6puIHRyb25nKio6IEtpbSBjxrDGoW5nIGtow7RuZyBjw7MgYuG6pXQga+G7syBraHV54bq/dCDEkWnhu4NtIG7DoG8gbmjDrG4gdGjhuqV5IMSRxrDhu6NjIGLhurFuZyBrw61uaCBoaeG7g24gdmkgMTB4LCBuaMawbmcgY8OzIHRo4buDIGPDsyBt4buZdCBz4buRIHThuqFwIGNo4bqldCBuaOG7jyBiw6puIG5nb8OgaS4NCg0KKiAqKlZWUzEgdsOgIFZWUzIgLSBS4bqldCwgcuG6pXQgw610IHThuqFwIGNo4bqldCoqOiBU4bqhcCBjaOG6pXQgcuG6pXQgbmjhu48gdsOgIGtow7Mgbmjhuq1uIGJp4bq/dCBi4bqxbmcga8OtbmggaGnhu4NuIHZpIDEweC4NCg0KKiAqKlZTMSB2w6AgVlMyIC0gUuG6pXQgw610IHThuqFwIGNo4bqldDoqKiBU4bqhcCBjaOG6pXQgbmjhu48gdsOgIGtow7Mgbmjhuq1uIGJp4bq/dCBi4bqxbmcga8OtbmggaGnhu4NuIHZpIDEweC4NCg0KKiAqKlNJMSB2w6AgU0kyIC0gQ8OzIHThuqFwIGNo4bqldDoqKiBU4bqhcCBjaOG6pXQgbmjhu48gdsOgIGPDsyB0aOG7gyBuaOG6rW4gYmnhur90IGLhurFuZyBrw61uaCBoaeG7g24gdmkgMTB4Lg0KDQoqICoqSTEgLSBDw7Mgbmhp4buBdSB04bqhcCBjaOG6pXQ6KiogVOG6oXAgY2jhuqV0IGzhu5tuIHbDoCByw7UgcsOgbmcgdGjhuq1tIGNow60ga2hpIGtow7RuZyBz4butIGThu6VuZyBrw61uaCBoaeG7g24gdmkuDQoNCktpbSBjxrDGoW5nIGPDsyDEkeG7mSB0cm9uZyBzdeG7kXQgY2FvIHRoxrDhu51uZyBjw7MgZ2nDoSB0cuG7iyBjYW8gaMahbi4NCg0KYGBge3J9DQphICU+JSBncm91cF9ieShjbGFyaXR5KSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKGNsYXJpdHksbikpICsNCiAgICBnZW9tX2NvbChmaWxsPSdmb3Jlc3RncmVlbicpICsNCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksdmp1c3QgPSAwLCBjb2xvciA9ICduYXZ5JykgKw0KICAgIGxhYnModGl0bGUgPSAnSMOsbmggODogQmnhu4N1IMSR4buTIHThu5VuZyBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHRoZW8gYmnhur9uIGNsYXJpdHknLCB4ID0gJ8SQ4buZIHRyb25nIHN14buRdCcsIHkgPSAnU+G7kSBsxrDhu6NuZycpICsgDQogICAgY29vcmRfZmxpcCgpDQpgYGANCg0KVGjDtG5nIHF1YSAqKEjDrG5oIDgpKiwgY8OzIHRo4buDIG5o4bqtbiB0aOG6pXkgcuG6sW5nIHZp4buHYyBsb+G6oWkgYuG7jyBob8OgbiB0b8OgbiB04bqhcCBjaOG6pXQgdHJvbmcga2ltIGPGsMahbmcgbMOgIG3hu5l0IHRow6FjaCB0aOG7qWMsIGRvIGxv4bqhaSAqKlNJMSoqIChjw7MgdOG6oXAgY2jhuqV0KSB2w6AgbG/huqFpICoqVlMyKiogKHLhuqV0IMOtdCB04bqhcCBjaOG6pXQpIGNoaeG6v20gxJFhIHPhu5EgduG7m2kgaMahbiAxMi4wMDAgdmnDqm4gY2hvIG3hu5dpIGxv4bqhaS4gVHJvbmcga2hpIMSRw7MsIGtpbSBjxrDGoW5nICoqSUYqKiAoa2jDtG5nIGPDsyB04bqhcCBjaOG6pXQpIGNo4buJIGNoaeG6v20gbeG7mXQgbMaw4bujbmcgcuG6pXQgbmjhu48gduG7m2kgMTc5MCB2acOqbi4NCg0KTeG6t2MgZMO5IHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcga2jDtG5nIGPDsyB04bqhcCBjaOG6pXQgbMOgIMOtdCwgbmjGsG5nIG5o4buvbmcgdmnDqm4gbsOgeSB0aMaw4budbmcgxJHGsOG7o2MgxJHDoW5oIGdpw6EgY2FvIHbhu4EgY2jhuqV0IGzGsOG7o25nLiDEkGnhu4F1IG7DoHkgY8OzIHRo4buDIGzDoCBkbyBjw6FjIG5ow6AgxJFp4buBdSB0w6FjIGtpbSBjxrDGoW5nIHThuq1wIHRydW5nIHbDoG8gdmnhu4djIHTDtG4gdmluaCBnacOhIHRy4buLIHbDoCBjaOG6pXQgbMaw4bujbmcgY2FvIGPhu6dhIGtpbSBjxrDGoW5nLCB2w6AgaOG7jSDEkcOjIMSR4bqhdCDEkcaw4bujYyB0aMOgbmggY8O0bmcgdHJvbmcgdmnhu4djIGdp4bqjbSBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nICoqSTEqKiAoY8OzIG5oaeG7gXUgdOG6oXAgY2jhuqV0KSB4deG7kW5nIGPDsm4gNzQxIHZpw6puLg0KDQojIyAqKjUuIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBiaeG6v24gZGVwdGggKMSR4buZIHPDonUpKioNCg0KRGVwdGggKMSR4buZIHPDonUpIMSRbyBsxrDhu51uZyB04buJIGzhu4cgZ2nhu69hIGNoaeG7gXUgY2FvIGPhu6dhIHZpw6puIGtpbSBjxrDGoW5nIHbDoCBjaGnhu4F1IG5nYW5nIGPhu6dhIHZpw6puIGtpbSBjxrDGoW5nICjEkcaw4budbmcga8OtbmgpLiBEZXB0aCB0aMaw4budbmcgxJHGsOG7o2MgdMOtbmggdG/DoW4gdGhlbyBjw7RuZyB0aOG7qWM6IA0KDQpcWyBcdGV4dHtEZXB0aCAlfSA9IFxsZWZ0KCBcZnJhY3tcdGV4dHtDaGnhu4F1IGNhb319e1x0ZXh0e8SQxrDhu51uZyBrw61uaH19IFxyaWdodCkgXHRpbWVzIDEwMCBcXQ0KDQpLaGkgY2jhu41uIGtpbSBjxrDGoW5nLCBuZ8aw4budaSB0acOqdSBkw7luZyB0aMaw4budbmcgcXVhbiB0w6JtIMSR4bq/biBz4buxIGPDom4gYuG6sW5nIGdp4buvYSBkZXB0aCB2w6AgY8OhYyB54bq/dSB04buRIGtow6FjIG5oxrAgbcOgdSBz4bqvYywgxJHhu5kgdHJvbmcgc3Xhu5F0IHbDoCBnacOhYyBj4bqvdC4gU+G7sSBjw6JuIG5o4bqvYyBuw6B5IGdpw7pwIMSR4bqjbSBi4bqjbyBraW0gY8awxqFuZyBraMO0bmcgY2jhu4kgxJHhurlwIHbhu4EgbeG6t3QgbcOgdSBz4bqvYyB2w6AgdHJvbmcgc3Xhu5F0IG3DoCBjw7JuIGPDsyBraOG6oyBuxINuZyBwaOG6o24geOG6oSDDoW5oIHPDoW5nIHThu5FpIMawdS4NCg0KYGBge3J9DQpkIDwtIGEgJT4lIG11dGF0ZSjEkeG7mS5zw6J1ID0gY3V0KHByaWNlLDQsIGxhYmVsID0gYygnS2jDoSB04buRdCcsICdU4buRdCcsJ0NhbyBj4bqlcCcsJ0zDvSB0xrDhu59uZycpKSkgI2fDoW4gZOG7ryBsaeG7h3UgdsOgbyBkDQoNCmQgJT4lIGdncGxvdChhZXMoeCA9IMSR4buZLnPDonUpKSArDQogIGdlb21fYmFyKGZpbGwgPSAnc2VhZ3JlZW4nKSArDQogIGxhYnModGl0bGUgPSAiSMOsbmggOTogU+G7kSBsxrDhu6NuZyB2acOqbiBraW0gY8awxqFuZyB0aGVvIGJp4bq/biBkZXB0aCAoxJHhu5kgc8OidSkiLCB4ID0gJ8SQ4buZIHPDonUnLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCj0gPiBTYXUga2hpIGNoaWEgY+G7mXQgYmnhur9uIERlcHRoIHRow6BuaCA0IG5ow7NtIMSR4buDIHBow6JuIHTDrWNoLCB0YSBuaOG6rW4gdGjhuqV5IHLhurFuZyBuaMOzbSAqKidLaMOhIHThu5F0JyoqIGPDsyBz4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIHBow6JuIGLhu5EgY2FvIG5o4bqldCwgw6FwIMSR4bqjbyBj4bqjIDMgbmjDs20gY8OybiBs4bqhaS4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgcuG6sW5nIHZp4buHYyDEkWnhu4F1IHTDoWMgdsOgIHThuqFvIHJhIGtpbSBjxrDGoW5nIHRodeG7mWMgMyBuaMOzbSBjw7JuIGzhuqFpICooVOG7kXQsIENhbyBj4bqlcCwgTMO9IHTGsOG7n25nKSogY8OzIHRo4buDIGzDoCBt4buZdCB0aMOhY2ggdGjhu6ljLCDEkeG6t3QgcmEgecOqdSBj4bqndSBjYW8gduG7gSBr4bu5IHRodeG6rXQgdsOgIGNo4bqldCBsxrDhu6NuZyBj4bunYSBxdcOhIHRyw6xuaCBz4bqjbiB4deG6pXQga2ltIGPGsMahbmcuDQoNCiMjICoqNi4gU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGJp4bq/biBwcmljZSAoZ2nDoSBj4bqjKSoqDQoNClRyb25nIG5nw6BuaCBjw7RuZyBuZ2hp4buHcCBraW0gY8awxqFuZywgZ2nDoSBj4bqjIGPhu6dhIG3hu5l0IHZpw6puIGtpbSBjxrDGoW5nIMSRxrDhu6NjIOG6o25oIGjGsOG7n25nIGLhu59pIG5oaeG7gXUgeeG6v3UgdOG7kSBraMOhYyBuaGF1LCB0cm9uZyDEkcOzIGPDsyBjw6FjIHnhur91IHThu5EgY2jDrW5oIG5oxrAgKipjYXJhdCoqICh0cuG7jW5nIGzGsOG7o25nKSwgKipjb2xvcioqIChtw6B1IHPhuq9jKSwgKipjbGFyaXR5KiogKMSR4buZIHRyb25nIHN14buRdCksIHbDoCAqKmN1dCoqIChj4bqvdCkuIFnhur91IHThu5EgbsOgeSDEkcaw4bujYyB0aMaw4budbmcgxJHGsOG7o2MgYmnhu4N1IGRp4buFbiBkxrDhu5tpIGThuqFuZyBnacOhIHRy4buLIHRp4buBbiB04buHLCB2w60gZOG7pSBuaMawIFZOxJAuDQoNClbhu5tpIGLhu5kgZOG7ryBsaeG7h3UgRGlhbW9uZHMsIHRhIGNoaWEgY+G7mXQgcHJpY2UgdGjDoG5oIDUgbmjDs20gdMawxqFuZyDhu6luZzoNCg0KKiBExrDhu5tpIDUwMCDEkcahbiB24buLIHRp4buBbjogKipS4bqldCBy4bq7KioNCg0KKiBU4burIDUwMSDEkeG6v24gMTAwMCDEkcahbiB24buLIHRp4buBbjogKipS4bq7KioNCg0KKiBU4burIDEwMDEgxJHhur9uIDE1MDAgxJHGoW4gduG7iyB0aeG7gW46ICoqVuG7q2EgcGjhuqNpKioNCg0KKiBU4burIDE1MDEgxJHhur9uIDIwMDAgxJHGoW4gduG7iyB0aeG7gW46ICoqTeG6r2MqKg0KDQoqIFRyw6puIDIwMDEgxJHGoW4gduG7iyB0aeG7gW46ICoqUuG6pXQgbeG6r2MqKg0KDQpgYGB7cn0NCmEkZ2nDoS5j4bqjIDwtIGNhc2Vfd2hlbihhJHByaWNlPD0gNTAwIH4gJ1LhuqV0IHLhursnLCBhJHByaWNlPj01MDEgJiBhJHByaWNlPD0xMDAwIH4gJ1LhursnLCBhJHByaWNlPj0xMDAxICYgYSRwcmljZTw9MTUwMCB+ICdW4burYSBwaOG6o2knLCBhJHByaWNlPj0xNTAxICYgYSRwcmljZTw9MjAwMCB+ICdN4bqvYycsIGEkcHJpY2U+PTIwMDEgfiAnUuG6pXQgbeG6r2MnKQ0KDQplIDwtIGEgJT4lIG11dGF0ZShnacOhLmPhuqMgPSBjdXQocHJpY2UsNSwgbGFiZWwgPSBjKCdS4bqldCBy4bq7JywgJ1LhursnLCdW4burYSBwaOG6o2knLCdN4bqvYycsJ1LhuqV0IG3huq9jJykpKQ0KZSAlPiUgZ2dwbG90KGFlcyh4ID0gZ2nDoS5j4bqjKSkgKw0KICBnZW9tX2JhcihmaWxsID0gJ3NhbmR5YnJvd24nKSArDQogIGxhYnModGl0bGUgPSAnSMOsbmggMTA6IFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBiaeG6v24gcHJpY2UgKGdpw6EgY+G6oyknLCB4ID0gJ0dpw6EgY+G6oycsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KPT4gS+G6v3QgcXXhuqMgdHLhuqMgduG7gSB04burICooSMOsbmggMTApKiBjaG8gdGjhuqV5IG3hu5l0IHBow6JuIHBo4buRaSDEkcOhbmcgY2jDuiDDvSB24buBIHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgZOG7sWEgdHLDqm4gbeG7qWMgZ2nDoS4gQ+G7pSB0aOG7gywgc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyDhu58gbeG7qWMgZ2nDoSAncuG6pXQgcuG6uycgdsOgICdy4bq7JyBjaGnhur9tIHThu4kgbOG7hyB2w7QgY8O5bmcgbOG7m24sIHbhu5tpIGjGoW4gMzAuMDAwIHZpw6puIGtpbSBjxrDGoW5nLiBOZ8aw4bujYyBs4bqhaSwgc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyDhu58gbeG7qWMgZ2nDoSAnbeG6r2MnIHbDoCAncuG6pXQgbeG6r2MnIGzhuqFpIHLhuqV0IMOtdCDhu49pLg0KDQpE4buxYSB2w6BvIHBow6JuIHBo4buRaSBuw6B5LCBjw7MgdGjhu4Mgc3V5IGx14bqtbiBy4bqxbmcgbmjDs20gxJHhu5FpIHTGsOG7o25nIGNo4bunIHnhur91IGPhu6dhIGPDoWMgdmnDqm4ga2ltIGPGsMahbmcgdGh14buZYyBt4bupYyBnacOhIHRo4bqlcCBsw6AgdOG6p25nIGzhu5twIGtow6FjaCBow6BuZyBjw7MgdGh1IG5o4bqtcCB0cnVuZyBiw6xuaCBob+G6t2MgdGjhuqVwLiBUcm9uZyBraGkgxJHDsywgbmjhu69uZyB2acOqbiBraW0gY8awxqFuZyDhu58gbeG7qWMgZ2nDoSAnbeG6r2MnIHbDoCAncuG6pXQgbeG6r2MnIGPDsyB0aOG7gyBsw6Agc+G6o24gcGjhuqltIGTDoG5oIGNobyB04bqnbmcgbOG7m3Aga2jDoWNoIGjDoG5nIGdpw6B1IGPDsyBob+G6t2MgbW9uZyBtdeG7kW4gY8OhYyB2acOqbiBraW0gY8awxqFuZyBjw7MgY2jhuqV0IGzGsOG7o25nIHbDoCDEkeG6t2MgdMOtbmggY2FvIGjGoW4uDQoNCiMgKipQaMOibiB0w61jaCBi4buZIGThu68gbGnhu4d1IHRoZW8gbmjDs20qKg0KKioqDQojIyAqKjEuIFBow6JuIHTDrWNoIHRoZW8gdHJ1bmcgYsOsbmggY+G7p2EgYmnhur9uIGNhcmF0ICh0cuG7jW5nIGzGsOG7o25nKSoqDQoNCsSQ4buDIHRp4bq/cCBj4bqtbiB0aMO0bmcgdGluIGNoaSB0aeG6v3QgduG7gSB0cnVuZyBiw6xuaCBjYXJhdCBjaG8gdOG7q25nIGxv4bqhaSBnacOhYyBj4bqvdCBj4bunYSB2acOqbiBraW0gY8awxqFuZywgY2jDum5nIHRhIGPDsyB0aOG7gyBk4buxYSB2w6BvIGJp4buDdSDEkeG7kyB0aOG7kW5nIGvDqiBjaGkgdGnhur90IMSRxrDhu6NjIG1pbmggaOG7jWEgdHJvbmcgKihIw6xuaCAxMSkqLg0KDQpgYGB7cn0NCmEgJT4lIGdyb3VwX2J5KGN1dCkgJT4lIHN1bW1hcmlzZShtPSBtZWFuKGNhcmF0KSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGN1dCx5ID0gbSkpICsNCiAgICBnZW9tX2NvbChmaWxsID0gJ2dvbGQnKSArDQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKG0sMikpLCB2anVzdCA9IDIsIGNvbG9yID0gJ3JlZCcpICsNCiAgICBsYWJzKHRpdGxlID0gJ0jDrG5oIDExOiBHacOhYyBj4bqvdCB0aGVvIHRydW5nIGLDrG5oIGJp4bq/biBjYXJhdCcsIHggPSAnTcOgdScsIHkgPSAnVHJ1bmcgYsOsbmggY2FyYXQnKQ0KYGBgDQpE4buxYSB2w6BvICooSMOsbmggMTEpKiwgY2jDum5nIHRhIGPDsyB0aOG7gyByw7p0IHJhIGPDoWMgbmjhuq1uIHjDqXQgcXVhbiB0cuG7jW5nIG5oxrAgc2F1Og0KDQoqIEtpbSBjxrDGoW5nIGxv4bqhaSAqKkZhaXIqKiB0aOG7gyBoaeG7h24gdHJ1bmcgYsOsbmggdGhlbyBiaeG6v24gY2FyYXQgbMOgIDEuMDUsIMSR4buTbmcgdGjhu51pIGPDsyBz4buxIHBow6JuIGLhu5EgY2FvIG5o4bqldCB0cm9uZyB04bqldCBj4bqjIGPDoWMgbG/huqFpIGdpw6FjIGPhuq90Lg0KDQoqIEPDoWMgbG/huqFpIGtpbSBjxrDGoW5nICoqR29vZCoqLCAqKlZlcnkgR29vZCoqLCB2w6AgKipQcmVtaXVtKiogY8OzIHRydW5nIGLDrG5oIHRoZW8gYmnhur9uIGNhcmF0IGzhuqduIGzGsOG7o3QgbMOgIDAuODUsIDAuODEgdsOgIDAuODkuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IHPhu7EgY2jDqm5oIGzhu4djaCBraMO0bmcgbOG7m24gZ2nhu69hIGJhIGxv4bqhaSBuw6B5LCB2w6AgY2jDum5nIMSR4buBdSBnaeG7ryBz4buxIHBow6JuIGLhu5EgY2FvIOG7nyBt4bupYyB0aOG7qSBoYWkuDQoNCiogS2ltIGPGsMahbmcgbG/huqFpICoqSWRlYWwqKiBjw7MgdHJ1bmcgYsOsbmggdGhlbyBiaeG6v24gY2FyYXQgdGjhuqVwIG5o4bqldCBsw6AgMC4xLCB2w6AgxJHhu5NuZyB0aOG7nWkgdGjhu4MgaGnhu4duIHPhu7EgcGjDom4gYuG7kSB0aOG6pXAgbmjhuqV0IHRyb25nIHPhu5EgY8OhYyBsb+G6oWkgZ2nDoWMgY+G6r3QuDQoNCiMjICoqMi4gUGjDom4gdMOtY2ggdGhlbyBiaeG6v24gY3V0IChnacOhYyBj4bqvdCkqKg0KDQojIyMgKioyLjEuIFPhu5EgbMaw4bujbmcgdmnDqm4ga2ltIGPGsMahbmcgY8OzIHRy4buNbmcgbMaw4bujbmcgY2FyYXQgPCAxIHRoZW8gYmnhur9uIGN1dCoqDQoNCkNow7puZyB0YSBjxaluZyBjw7MgdGjhu4MgdGnhur9uIGjDoG5oIHBow6JuIHTDrWNoIGNoaSB0aeG6v3QgaMahbiB24buBIGTDsm5nIGtpbSBjxrDGoW5nIGPDsyB0cuG7jW5nIGzGsOG7o25nIGNhcmF0IG5o4buPLCB04bqtcCB0cnVuZyB2w6BvIHnhur91IHThu5EgZ2nDoWMgY+G6r3QgKGN1dCksIG5o4bqxbSDEkcOhbmggZ2nDoSBt4bupYyDEkeG7mSBoaeG6v20gY8OzIGPhu6dhIGPDoWMga2ltIGPGsMahbmcgdHJvbmcgbeG7l2kgbG/huqFpIGdpw6FjIGPhuq90IGtow6FjIG5oYXUuIA0KDQpgYGB7cn0NCmIxIDwtIGRpYW1vbmRzICU+JSBmaWx0ZXIoY2FyYXQgPCAxKSANCmIxICU+JSBnZ3Bsb3QoYWVzKHg9Y3V0KSkgKw0KICAgIGdlb21fYmFyKGZpbGwgPSAnbmF2eScpICsNCiAgICBsYWJzKHRpdGxlID0gJ0jDrG5oIDEyOiBT4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIGPDsyB0cuG7jW5nIGzGsOG7o25nIGNhcmF0IG5o4buPIHRoZW8gZ2nDoWMgY+G6r3QgKGN1dCknLCB4ID0gJ0dpw6FjIGPhuq90JywgeSA9ICdT4buRIGzGsOG7o25nJykgKw0KICAgIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCj0+IEvhur90IHF14bqjIHBow6JuIHTDrWNoIHRy4bqjIHbhu4EgY2hvIGJp4bq/dCAqKEjDrG5oIDEyKSoga2ltIGPGsMahbmcgbG/huqFpIGzDvSB0xrDhu59uZyAoSWRlYWwpIGNoaeG6v20gdOG7tyBs4buHIGzhu5tuIG5o4bqldCB0cm9uZyB04bqtcCBk4buvIGxp4buHdSwgxJHhu5NuZyB0aOG7nWkga2ltIGPGsMahbmcgbG/huqFpIGtow6EgdOG7kXQgKEZhaXIpIGNoaeG6v20gdOG7tyBs4buHIHRo4bqlcCBuaOG6pXQuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IHPhu7EgcuG7mW5nIGzhu5tuIHbDoCDEkWEgZOG6oW5nIGPhu6dhIGTDsm5nIGtpbSBjxrDGoW5nIGzDvSB0xrDhu59uZywgduG7m2kgaMahbiAxNSwwMDAgdmnDqm4ga2ltIGPGsMahbmcgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UsIG3hurdjIGTDuSBjaMO6bmcgY8OzIGdpw6FjIGPhuq90IHThu5F0IG5oxrBuZyBraMO0bmcgaGnhur9tLg0KDQojIyMgKioyLjIuIFPhu5EgbMaw4bujbmcgdmnDqm4ga2ltIGPGsMahbmcgY8OzIHRy4buNbmcgbMaw4bujbmcgY2FyYXQgPiAxIHRoZW8gYmnhur9uIGN1dCoqDQoNClTGsMahbmcgdOG7sSwgdGEgY8WpbmcgY8OzIHRo4buDIGThu4UgZMOgbmcgcGjDom4gdMOtY2ggduG7m2kgY8OhYyB2acOqbiBraW0gY8awxqFuZyBjw7MgdHLhu41uZyBsxrDhu6NuZyBjYXJhdCBs4bubbi4NCg0KYGBge3J9DQpiMiA8LSBkaWFtb25kcyAlPiUgZmlsdGVyKGNhcmF0ID4gMSkNCmIyICU+JSBnZ3Bsb3QoYWVzKHg9Y3V0KSkgKw0KICAgIGdlb21fYmFyKGZpbGwgPSAnbmF2eScpICsNCiAgICBsYWJzKHRpdGxlID0gJ0jDrG5oIDEzOiBT4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIGPDsyB0cuG7jW5nIGzGsOG7o25nIGNhcmF0IGzhu5tuIHRoZW8gZ2nDoWMgY+G6r3QgKGN1dCknLCB4ID0gJ0xv4bqhaScsIHkgPSAnU+G7kSBsxrDhu6NuZycpICsNCiAgICBjb29yZF9mbGlwKCkNCmBgYA0KDQo9PiBL4bq/dCBxdeG6oyB0cuG6oyB24buBLCBuaMawIHRo4buDIGhp4buHbiB0cm9uZyAqKEjDrG5oIDEzKSosIHRo4buDIGhp4buHbiBz4buxIMSR4buRaSBuZ8aw4bujYyBnaeG7r2Ega2ltIGPGsMahbmcgY8OzIHRy4buNbmcgbMaw4bujbmcgY2FyYXQgbmjhu48gdsOgIGtpbSBjxrDGoW5nIGPDsyB0cuG7jW5nIGzGsOG7o25nIGNhcmF0IGzhu5tuLiBUcm9uZyB0csaw4budbmcgaOG7o3AgY+G7p2Ega2ltIGPGsMahbmcgbOG7m24sIGNow7puZyBwaMOibiBi4buRIHLhu5luZyByw6NpIMSR4bq3YyBiaeG7h3QgdHJvbmcgY8OhYyBsb+G6oWkgZ2nDoWMgY+G6r3QgY2FvIGPhuqVwIChQcmVtaXVtKSB2w6AgbMO9IHTGsOG7n25nIChJZGVhbCksIMSR4bq3YyBiaeG7h3QgbMOgIHRyb25nIGxv4bqhaSBjYW8gY+G6pXAuIFR1eSBuaGnDqm4sIMSR4buRaSB24bubaSBnacOhYyBj4bqvdCBsb+G6oWkga2jDoSB04buRdCAoRmFpciksIGtpbSBjxrDGoW5nIGPDsyB0cuG7jW5nIGzGsOG7o25nIGNhcmF0IGzhu5tuIHbhuqtuIGR1eSB0csOsIG3hu6ljIMSR4buZIHBow6JuIGLhu5EgdGjhuqVwLg0KDQojIyMgKioyLjMuIFPhu5EgbMaw4bujbmcgdmnDqm4ga2ltIGPGsMahbmcgY8OzIMSR4buZIHRyb25nIHN14buRdCBsw6AgSUYgdsOgIEkxIHRoZW8gYmnhur9uIGN1dCoqDQoNClRhIHhlbSBraW0gY8awxqFuZyBsb+G6oWkgKipJRioqICh0cm9uZyBzdeG7kXQgYsOqbiB0cm9uZykgbMOgIG3DoHUgeGFuaCBsw6EgbmjhuqF0LCBraW0gY8awxqFuZyBsb+G6oWkgKipJMSoqIChuaGnhu4F1IHThuqFwIGNo4bqldCkgbMOgIG3DoHUgeGFuaCBsw6EgxJHhuq1tLg0KDQpLaGkgdGEgbXXhu5FuIHhlbSDEkeG7mSBjaMOqbmggbOG7h2NoIHPhu7EgcGjDom4gYuG7kSBnaeG7r2Ega2ltIGPGsMahbmcgbG/huqFpIHRyb25nIHN14buRdCB2w6Aga2ltIGPGsMahbmcgY8OzIG5oaeG7gXUgdOG6oXAgY2jhuqV0LCB0YSBjw7MgdGjhu4MgcXVhbiBzw6F0IGJp4buDdSDEkeG7kyBiw6puIGTGsOG7m2kuDQoNCmBgYHtyfQ0KZiA8LSBhICU+JSBncm91cF9ieShjdXQsIGNsYXJpdHkpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkNCmYgJT4lIGdncGxvdChhZXMoeCA9IGN1dCwgeSA9IG4pKSArDQogIGdlb21fY29sKGRhdGEgPSBmICU+JSBmaWx0ZXIoY2xhcml0eSA9PSAnSUYnKSwgZmlsbCA9ICdkYXJrc2VhZ3JlZW4nKSArDQogIGdlb21fY29sKGRhdGEgPSBmICU+JSBmaWx0ZXIoY2xhcml0eSA9PSAnSTEnKSwgZmlsbCA9ICdkYXJrb2xpdmVncmVlbicpICsNCiAgbGFicyh0aXRsZSA9ICdIw6xuaCAxNDogU+G7kSBsxrDhu6NuZyB2acOqbiBraW0gY8awxqFuZyBjw7MgxJHhu5kgdHJvbmcgc3Xhu5F0IGzDoCBJRiB2w6AgSTEgdGhlbyBiaeG6v24gY3V0JywgeCA9ICdHacOhYyBj4bqvdCcsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KPT4gS+G6v3QgcXXhuqMgdHLhuqMgduG7gSAqKEjDrG5oIDE0KSogY2hvIGNow7puZyB0YSB0aOG6pXksIG3hurdjIGTDuSDEkWnhu4F1IGNo4bq/IMSRxrDhu6NjIG5o4buvbmcgdmnDqm4ga2ltIGPGsMahbmcgdHJvbmcgc3Xhu5F0IGLDqm4gdHJvbmcgbMOgIG3hu5l0IHRo4butIHRow6FjaCBuaMawIGtpbSBjxrDGoW5nIGPDsyBnacOhYyBj4bqvdCBsb+G6oWkgKipGYWlyKiogdsOgICoqR29vZCoqIGhvw6BuIHRvw6BuIGtow7RuZyBjw7MgxJHhu5kgdHJvbmcgc3Xhu5F0LCBjaOG7qWEgcuG6pXQgbmhp4buBdSB04bqhcCBjaOG6pXQuIFR1eSB24bqteSBjw6FjIG5ow6AgxJFp4buBdSBjaOG6vyBraW0gY8awxqFuZyB24bqrbiBj4buRIGfhuq9uZyDEkWnhu4F1IGNo4bq/IMSRxrDhu6NjIGxv4bqhaSBraW0gY8awxqFuZyBuw6B5LCBuaOG6sW0gdMO0biB2aW5oIG5o4buvbmcgZ2nDoSB0cuG7iyDEkeG6uXAgxJHhur0gbmjhuqV0IGPhu6dhIGtpbSBjxrDGoW5nLg0KDQpOaMawIGtpbSBjxrDGoW5nIGPDsyBnacOhYyBj4bqvdCBsb+G6oWkgKipJZGVhbCoqLCBt4buZdCBkw7JuZyBraW0gY8awxqFuZyBsw70gdMaw4bufbmcgbmjGsG5nIHPhu7EgcGjDom4gYuG7kSBj4bunYSBkw7JuZyBraW0gY8awxqFuZyB0cm9uZyBzdeG7kXQgxJHDoyBjaGnhur9tIMSRw7RuZyDEkeG6o28uIA0KDQojIyMgKioyLjQuIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBnacOhYyBj4bqvdCBj4bunYSB04burbmcgxJHhu5kgdHJvbmcgc3Xhu5F0KioNCg0KVuG7m2kgY2jhu6ljIG7Eg25nIGjhu5cgdHLhu6MgY+G7p2EgUiwgdGEgY8OzIHRo4buDIHRo4bqleSB0w7l5IHbDoG8gbeG7pWMgxJHDrWNoIG5odSBj4bqndSBuZ2hpw6puIGPhu6l1IHbDoCBwaMOibiB0w61jaCBtw6AgY2jDum5nIHRhIGPDsyB0aOG7gyBjaOG7jW4gc+G7rSBk4bulbmcgMSB0cm9uZyAzIGJp4buDdSDEkeG7kyBiw6puIGTGsOG7m2kuIA0KDQoqKEjDrG5oIDE1KSogY2hvIGNow7puZyB0YSBt4buZdCBjw6FpIG5ow6xuIHThu5VuZyBxdcOhdCB24buBIHPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBnacOhYyBj4bqvdCBj4bunYSB04burbmcgxJHhu5kgdHJvbmcgc3Xhu5F0LiBUcm9uZyBraGkgxJHDsyAqKEjDrG5oIDE2KSogdsOgICooSMOsbmggMTcpKiBs4bqhaSBjaG8gY2jDum5nIHRhIG3hu5l0IGPDoWkgbmjDrG4gY2hpIHRp4bq/dCBoxqFuIHbhu4Egc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZy4NCg0KYGBge3J9DQphICU+JSBncm91cF9ieShjdXQsY2xhcml0eSkgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGN1dCx5ID0gbikpICsNCiAgICBnZW9tX2NvbChmaWxsID0gJ21lZGl1bXNsYXRlYmx1ZScpICsNCiAgICBmYWNldF93cmFwKH5jbGFyaXR5KSArDQogICAgbGFicyh0aXRsZSA9ICdIw6xuaCAxNTogU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGdpw6FjIGPhuq90IGPhu6dhIHThu6tuZyDEkeG7mSB0cm9uZyBzdeG7kXQnLCB4ID0gJ8SQ4buZIHRyb25nIHN14buRdCcsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KYGBge3J9DQphICU+JSBncm91cF9ieShjdXQsY29sb3IpICU+JSBzdW1tYXJpc2Uobj1uKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjdXQseSA9IG4pKSArDQogICAgZ2VvbV9jb2woZmlsbCA9ICdtZWRpdW1zbGF0ZWJsdWUnKSArDQogICAgZmFjZXRfd3JhcCh+Y29sb3IpICsNCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksdmp1c3QgPSAwLCBjb2xvciA9ICdtZWRpdW1ibHVlJykgKw0KICAgIGxhYnModGl0bGUgPSAnSMOsbmggMTY6IFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgdGhlbyBnacOhYyBj4bqvdCBj4bunYSB04burbmcgbG/huqFpIG3DoHUnLCB4ID0gJ0xv4bqhaScsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY3V0LCBmaWxsID0gY2xhcml0eSkpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAnZG9kZ2UnKSArDQogIGZhY2V0X3dyYXAofmNsYXJpdHkpICsNCiAgbGFicyh0aXRsZSA9ICdIw6xuaCAxNzogU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIGdpw6FjIGPhuq90IGPhu6dhIHThu6tuZyDEkeG7mSB0cm9uZyBzdeG7kXQgKMSRYSBtw6B1KScsIHggPSAnR2nDoWMgQ+G6r3QnLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCk5oxrBuZyBuaMOsbiBjaHVuZywgY2jDum5nIHRhIGPDsyB0aOG7gyBuaOG6rW4geMOpdCBy4bqxbmc6DQoNCiogS2ltIGPGsMahbmcgY8OzIGdpw6FjIGPhuq90IGxv4bqhaSAqKkZhaXIqKiBjw7Mgc+G7kSBsxrDhu6NuZyDDrXQgaMahbiBuaOG7r25nIGxv4bqhaSBnacOhYyBj4bqvdCBraMOhYywgY2jDum5nIGNo4bunIHnhur91IHThuq1wIHRydW5nIOG7nyBuaOG7r25nIG3DoHUgKipGLCBHLCBIKiogduG7m2kgbOG6p24gbMaw4bujdCBsw6AgKiozMTIsIDMxNCwgMzAzKiogdmnDqm4uDQoNCiogS2ltIGPGsMahbmcgY8OzIGdpw6FjIGPhuq90IGxv4bqhaSAqKkdvb2QqKiBwaMOibiBi4buRIGNo4bunIHnhur91IOG7nyBtw6B1ICoqRSwgRioqIHbhu5tpIHPhu5EgbMaw4bujbmcgbOG6p24gbMaw4bujdCBsw6AgKio5MzMsIDkwOSoqLg0KDQoqIEtpbSBjxrDGoW5nIGPDsyBnacOhYyBj4bqvdCBsb+G6oWkgKipWZXJ5IGdvb2QqKiB2w6AgKipQcmVtaXVtKiogY8OzIHPhu5EgbMaw4bujbmcgcGjDom4gYuG7kSBraMO0bmcgcXXDoSBjaMOqbmggbOG7h2NoIG5oYXUgY2FvLCBjaMO6bmcgdOG6rXAgdHJ1bmcgY2jhu6cgeeG6v3Ug4bufIG3DoHUgKipFLCBHKiogbOG6p24gbMaw4bujdCB24bubaSBz4buRIGzGsOG7o25nIGzDoCAqKjI0MDAsIDIzMzcqKiB2w6AgKioyMjk5LCAyOTI0KiouDQoNCiogS2ltIGPGsMahbmcgY8OzIGdpw6FjIGPhuq90IGxv4bqhaSAqKklkZWFsKiosIGPhuqVwIMSR4buZIGzDvSB0xrDhu59uZywgbeG6t2MgZMO5IGtow7RuZyBwaMOibiBi4buRIG5oaeG7gXUg4bufIG3DoHUgKipKKiogY2jhu4kgY8OzIDg5NiBtw6B1IG5oxrBuZyBjaMO6bmcgbOG6oWkgcGjDom4gYuG7kSBuaGnhu4F1IOG7nyBtw6B1ICoqRyoqIHbhu5tpIDQ4ODQuDQoNCiMjIyAqKjIuNS4gxJDhu5kgbOG7h2NoIGNodeG6qW4gZ2nDoSBraW0gY8awxqFuZyB0aGVvIGdpw6FjIGPhuq90KioNCg0KYGBge3J9DQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY3V0LCB5ID0gc2QocHJpY2UpKSkgKw0KICBnZW9tX2JhcihmaWxsID0gJ2NoYXJ0cmV1c2UnLCBzdGF0ID0gJ2lkZW50aXR5JykgKw0KICBsYWJzKHRpdGxlID0gJ0jDrG5oIDE4OiDEkOG7mSBs4buHY2ggY2h14bqpbiBnacOhIGtpbSBjxrDGoW5nIHRoZW8gZ2nDoWMgY+G6r3QnLCB4ID0gJ0dpw6FjIGPhuq90JywgeSA9ICfEkOG7mSBs4buHY2ggY2h14bqpbiBnacOhJykNCmBgYA0KDQo9PiBN4buXaSBj4buZdCBiaeG7g3UgZGnhu4VuIG3hu5l0IG3hu6ljIMSR4buZIMSR4buZIGzhu4djaCBjaHXhuqluIHTGsMahbmcg4bupbmcgduG7m2kgbG/huqFpIGdpw6FjIGPhuq90LCB2w6AgbcOgdSBz4bqvYyBj4bunYSBj4buZdCDEkcaw4bujYyBjaOG7jW4gbMOgIGNoYXJ0cmV1c2UgxJHhu4MgdOG6oW8gc+G7sSBu4buVaSBi4bqtdC4gxJDhu5kgbOG7h2NoIGNodeG6qW4gdMawxqFuZyDhu6luZyB24bubaSA1IG3DoHUgY8WpbmcgYmnhur9uIHRoacOqbiB0aGVvIHThu6tuZyBsb+G6oWkgZ2nDoWMgY+G6r3QuIEPDoG5nIGzDoCBsb+G6oWkgZ2nDoWMgY+G6r3QgY8OzIG3hu6ljIMSR4buZIGNhbyBuaMawICoqUHJlbWl1bSoqIGhheSAqKklkZWFsKiogdGjDrCDEkeG7mSBs4buHbmggY2h14bqpbiBnacOhIGPDoG5nIGzhu5tuIHbDoCBuZ8aw4bujYyBs4bqhaSwgxJHhu5kgbOG7h2NoIGNodeG6qW4gZ2nDoSB0aOG6pXAgbmjhuqV0IGzDoCBsb+G6oWkgKipGYWlyKiouDQoNCiMjIyAqKjIuNi4gxJDhu5kgbOG7h2NoIGNodeG6qW4gZ2nDoSBraW0gY8awxqFuZyB0aGVvIG3DoHUqKg0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjb2xvciwgeSA9IHNkKHByaWNlKSkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICdjaGFydHJldXNlJywgc3RhdCA9ICdpZGVudGl0eScpICsNCiAgbGFicyh0aXRsZSA9ICdIw6xuaCAxOTogxJDhu5kgbOG7h2NoIGNodeG6qW4gZ2nDoSBraW0gY8awxqFuZyB0aGVvIG3DoHUnLCB4ID0gJ03DoHUnLCB5ID0gJ8SQ4buZIGzhu4djaCBjaHXhuqluIGdpw6EnKQ0KYGBgDQoNClbhu5tpIDcgbcOgdSBz4bqvYyBELCBFLCBGLCBHLCBILCBJLCBLLCB0YSB0aOG6pXk6DQoNCiogKipNw6B1IEcqKiBsw6AgbcOgdSBjw7MgxJHhu5kgbOG7h2NoIGNodeG6qW4gZ2nDoSBjYW8gbmjhuqV0Lg0KDQoqIE3hu6ljIMSR4buZIGzhu4djaCBjaHXhuqluIGdpw6EgdHJ1bmcgYsOsbmggbMOgICoqbcOgdSBEKiogdsOgICoqbcOgdSBIKiouDQoNCiogTeG7qWMgxJHhu5kgbOG7h2NoIGNodeG6qW4gZ2nDoSB0aOG6pXAgbmjhuqV0IGzDoCAqKm3DoHUgSioqLg0KDQojIyMgKioyLjcuIMSQ4buZIGzhu4djaCBjaHXhuqluIGdpw6Ega2ltIGPGsMahbmcgdGhlbyDEkeG7mSB0cm9uZyBzdeG7kXQqKg0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjbGFyaXR5LCB5ID0gc2QocHJpY2UpKSkgKw0KICBnZW9tX2JhcihmaWxsID0gJ2NoYXJ0cmV1c2UnLCBzdGF0ID0gJ2lkZW50aXR5JykgKw0KICBsYWJzKHRpdGxlID0gJ0jDrG5oIDIwOiDEkOG7mSBs4buHY2ggY2h14bqpbiBt4bupYyDEkeG7mSBtw6B1IGPhu6dhIGtpbSBjxrDGoW5nIHRoZW8gZ2nDoWMgY+G6r3QnLCB4ID0gJ0dpw6FjIGPhuq90JywgeSA9ICfEkOG7mSBs4buHY2ggY2h14bqpbiBt4bupYyDEkeG7mSBtw6B1JykNCmBgYA0KVuG7m2kgOCBt4bupYyDEkeG7mSB0cm9uZyBzdeG7kXQgbOG6p24gbMaw4bujdCBsw6AgSTEsIFNJMiwgU0kxLCBWUzIsIFZTMSwgVlZTMiwgVlZTMSwgSUYgdGEgdGjhuqV5Og0KDQoqICoqU0kxKiogbMOgIG3hu6ljIGPDsyDEkeG7mSBs4buHY2ggY2h14bqpbiBnacOhIGNhbyBuaOG6pXQuDQoNCiogTeG7qWMgxJHhu5kgbOG7h2NoIGNodeG6qW4gZ2nDoSB0cnVuZyBiw6xuaCBsw6AgxJHhu5kgdHJvbmcgc3Xhu5F0IGxv4bqhaSAqKlNJMioqIHbDoCAqKlZTMSoqLg0KDQoqIE3hu6ljIMSR4buZIGzhu4djaCBjaHXhuqluIGdpw6EgdGjhuqVwIG5o4bqldCBsw6AgxJHhu5kgdHJvbmcgc3Xhu5F0IGxv4bqhaSAqKsOMRioqLg0KDQojIyAqKjMuIFBow6JuIHTDrWNoIHRoZW8gYmnhur9uIGNvbG9yIChtw6B1IHPhuq9jKSoqDQoNCiMjIyAqKjMuMS4gU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyBjw7MgZ2nDoWMgY+G6r3QgbG/huqFpIFByZW1pdW0gdsOgIEdvb2QgdGhlbyBiaeG6v24gY29sb3IqKg0KDQpUYSB4ZW0ga2ltIGPGsMahbmcgY8OzIGxv4bqhaSBnacOhYyBj4bqvdCBsw6AgKipQcmVtaXVtKiogbMOgIG3DoHUgaOG7k25nIG5o4bqhdCB2w6Aga2ltIGPGsMahbmcgY8OzIGxv4bqhaSBnacOhYyBj4bqvdCBsw6AgKipHb29kKiogY8OzIG3DoHUgaOG7k25nIMSR4bqtbS4gDQoNCmBgYHtyfQ0KZiA8LSBhICU+JSBncm91cF9ieShjb2xvciwgY3V0KSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpDQpmICU+JSBnZ3Bsb3QoYWVzKHggPSBjb2xvciwgeSA9IG4pKSArDQogIGdlb21fY29sKGRhdGEgPSBmICU+JSBmaWx0ZXIoY3V0ID09ICdQcmVtaXVtJyksIGZpbGwgPSAnbGlnaHRwaW5rJykgKw0KICBnZW9tX2NvbChkYXRhID0gZiAlPiUgZmlsdGVyKGN1dCA9PSAnR29vZCcpLCBmaWxsID0gJ2Jyb3duJykgKw0KICBsYWJzKHRpdGxlID0gJ0jDrG5oIDIxOiBT4buRIGzGsOG7o25nIGtpbSBjxrDGoW5nIGPDsyBnacOhYyBj4bqvdCBsb+G6oWkgUHJlbWl1bSB2w6AgR29vZCB0aGVvIGJp4bq/biBjb2xvcicsIHggPSAnTcOgdSBz4bqvYycsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KU28gc8Ohbmggc+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyBjw7MgZ2nDoWMgY+G6r3QgbG/huqFpIFByZW1pdW0gdsOgIEdvb2QgdGhlbyBtw6B1IHPhuq9jLCB0YSB0aOG6pXkgZ2nhu69hIGPDoWMgbcOgdSAyIGxv4bqhaSBraW0gY8aw4budbmcgcGjDom4gYuG7kSBraMOhIMSR4buBdSBuaGF1Lg0KDQoqIFbhu5tpIGtpbSBjxrDGoW5nIGxv4bqhaSAqKlByZW1pdW0qKiBjaMO6bmcgdOG6rXAgdHJ1bmcgc+G7kSBsxrDhu6NuZyBuaGnhu4F1IOG7nyAzIG3DoHUgKipFLCBGLCBHKiogdsOgIHThuq1wIHRydW5nIMOtdCBuaOG6pXQg4bufIG3DoHUgSi4NCg0KKiBW4bubaSBraW0gY8awxqFuZyBsb+G6oWkgKipHb29kKiogY2jDum5nIHThuq1wIHRydW5nIG5oaeG7gXUg4bufIG3DoHUgKipHKiogdsOgIHThuq1wIHRydW5nIMOtdCBuaOG6pXQg4bufIG3DoHUgKipKKiogKHTGsMahbmcgdOG7sSBuaMawIGxv4bqhaSBQcmVtaXVtKS4NCg0KIyMjICoqMy4yLiBT4buRIGzGsOG7o25nIHZpw6puIGtpbSBjxrDGoW5nIHRoZW8gYmnhur9uIGNvbG9yIGPhu6dhIHThu6tuZyBsb+G6oWkgZ2nDoWMgY+G6r3QqKg0KDQpOZ2/DoGkgMiBsb+G6oWkga2ltIGPGsMahbmcgbsOzaSB0csOqbiAoZ2nDoWMgY+G6r3QgUHJlbWl1bSB2w6AgR29vZCkgdGEgY8WpbmcgY8OzIHRo4buDIHNvIHPDoW5oIGPhu6UgdGjhu4MgduG7m2kgdOG7q25nIGxv4bqhaSBraW0gY8awxqFuZyB0aGVvIG3DoHUgc+G6r2MgduG7m2kgYmnhu4N1IMSR4buTICooSMOsbmggMjIpKi4gSG/hurdjIHRhIGPDsyB0aOG7gyB4ZW0gYmnhu4N1IMSR4buTIOG7nyAqKEjDrG5oIDIzKSogdGjhu4MgaGnhu4duIGNoaSB0aeG6v3QgdOG7lW5nIHPhu5EgdmnDqm4ga2ltIGPGsMahbmcgdGhlbyBiaeG6v24gY29sb3IgY+G7p2EgdOG7q25nIGxv4bqhaSBnacOhYyBj4bqvdC4NCg0KYGBge3J9DQphICU+JSBncm91cF9ieShjb2xvcixjdXQpICU+JSBzdW1tYXJpc2Uobj1uKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2xvcix5ID0gbikpICsNCiAgICBnZW9tX2NvbChmaWxsID0gJ3JlZCcpICsNCiAgICBmYWNldF93cmFwKH5jdXQpICsNCiAgICBsYWJzKHRpdGxlID0gJ0jDrG5oIDIyOiBT4buRIGzGsOG7o25nIHZpw6puIGtpbSBjxrDGoW5nIHRoZW8gYmnhur9uIGNvbG9yIGPhu6dhIHThu6tuZyBsb+G6oWkgZ2nDoWMgY+G6r3QnLCB4ID0gJ0xv4bqhaScsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KYGBge3J9DQphICU+JSBncm91cF9ieShjb2xvcixjdXQpICU+JSBzdW1tYXJpc2Uobj1uKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjb2xvcix5ID0gbikpICsNCiAgICBnZW9tX2NvbChmaWxsID0gJ3JlZCcpICsNCiAgICBmYWNldF93cmFwKH4gY3V0KSArDQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLHZqdXN0ID0gMCwgY29sb3IgPSAnbWVkaXVtYmx1ZScpICsNCiAgICBsYWJzKHRpdGxlID0gJ0jDrG5oIDIzOiBU4buVbmcgc+G7kSBsxrDhu6NuZyB2acOqbiBraW0gY8awxqFuZyB0aGVvIGJp4bq/biBjb2xvciBj4bunYSB04burbmcgbG/huqFpIGdpw6FjIGPhuq90JywgeCA9ICdMb+G6oWknLCB5ID0gJ1Phu5EgbMaw4bujbmcnKQ0KYGBgDQoNCiMjIyAqKjMuMy4gU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIHThu5VuZyBnacOhIHRy4buLIGJp4bq/biBjb2xvciBj4bunYSB04burbmcgbG/huqFpIGdpw6FjIGPhuq90KioNCg0KYGBge3J9DQojIFTDrW5oIHThu5VuZyBnacOhIHRy4buLIGtpbSBjxrDGoW5nIHRoZW8gImN1dCIgdsOgICJjb2xvciINCmcgPC0gZGlhbW9uZHMgJT4lDQogIGdyb3VwX2J5KGNvbG9yLCBjdXQpICU+JQ0KICBzdW1tYXJpc2UodG90YWxfcHJpY2UgPSBzdW0ocHJpY2UpKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIGJhciBjaGFydA0KZ2dwbG90KGcsIGFlcyh4ID0gY29sb3IsIHkgPSB0b3RhbF9wcmljZSwgZmlsbCA9IGN1dCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScpICsNCiAgbGFicyh0aXRsZSA9ICdIw6xuaCAyNDogU+G7kSBsxrDhu6NuZyBraW0gY8awxqFuZyB0aGVvIHThu5VuZyBnacOhIHRy4buLIGJp4bq/biBjb2xvciBj4bunYSB04burbmcgbG/huqFpIGdpw6FjIGPhuq90JywgeCA9ICdNw6B1IHPhuq9jJywgeSA9ICdU4buVbmcgR2nDoSB0cuG7iycpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICdTZXQyJykgICMgU+G7rSBk4bulbmcgbcOgdSB04burIGLhuqNuZyBtw6B1IEJyZXdlcg0KDQpgYGANCg0KQmnhu4N1IMSR4buTICooSMOsbmggMjQpKiB0xrDGoW5nIHThu7EgbmjGsCBiaeG7g3UgxJHhu5MgKihIw6xuaCAyMykqIHbDoCAqKEjDrG5oIDIyKSosIHR1eSBuaGnDqm4gxrB1IMSRaeG7g20gY+G7p2EgbG/huqFpIG7DoHkgbMOgIGNo4buJIGPDsyBt4buZdCBiaeG7g3UgxJHhu5MgY8OzIGPDoWMgY+G7mXQgY2jhu5NuZyBsw6puIG5oYXUgdGhheSB2w6wgY2hpYSBuaOG7jyByYSB0aMOgbmggbmhp4buBdSBiaeG7g3UgxJHhu5MuIFRodeG6rW4gdGnhu4duIGNobyB2aeG7h2MgcXVhbiBzw6F0IHbDoCBzbyBzw6FuaC4NCg0KIyMjICoqMy40LiBU4buVbmcgZ2nDoSB0cuG7iyB0aGVvIHBow6JuIGxv4bqhaSB2w6AgbcOgdSBz4bqvYyoqIA0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjb2xvciwgZmlsbCA9IGNsYXJpdHkpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gJ3N0YWNrJykgKw0KICBsYWJzKHRpdGxlID0gJ0jDrG5oIDI1OiBU4buVbmcgZ2nDoSB0cuG7iyB0aGVvIHBow6JuIGxv4bqhaSB2w6AgbcOgdSBz4bqvYycsIHggPSAnTG/huqFpJywgeSA9ICdU4buVbmcgZ2nDoSB0cuG7iycpDQpgYGANClbhu5tpICooSMOsbmggMjUpKiB0YSBuaOG6rW4geMOpdCBy4bqxbmc6DQoNCiogxJDhu5kgdHJvbmcgc3Xhu5F0IGzDoCAqKklGKiogKHRyb25nIHN14buRdCkgdsOsIHLhuqV0IGtow7MgxJFp4buBdSBjaOG6vyBuw6puIG3hu6ljIMSR4buZIHBow6JuIGLhu5EgY+G7p2EgY2jDum5nIHbDtCBjw7luZyDDrXQsIHbhu5tpICoqbcOgdSBEKiogdsOgICoqbcOgdSBKKiogZ+G6p24gbmjGsCBsw6Aga2jDtG5nIGPDsywgdOG6rXAgdHJ1bmcgcGjDom4gYuG7kSBjYW8g4bufICoqbcOgdSBHKiouDQoNCiogxJDhu5kgdHJvbmcgc3Xhu5F0IGzDoCAqKlNJMSwgU0kyLCBWUzEsIFZTMioqIHLhuqNpIHLDoWMg4bufIGPDoWMgbcOgdSBjw7MgxJHhu5kgcGjDom4gYuG7kSBn4bqnbiBuaMawIGzDoCDEkeG7gXUgbmhhdS4NCg0KKiDEkOG7mSB0cm9uZyBzdeG7kXQgbMOgICoqVlZTMSwgVlZTMioqIGPFqW5nIHLhuqNpIHLDoWMg4bufIGPDoWMgbcOgdSBjw7MgxJHhu5kgcGjDom4gYuG7kSBn4bqnbiBuaMawIGzDoCDEkeG7gXUgbmhhdS4NCg0KIyMgKio0LiBQaMOibiB0w61jaCB0aGVvIGJp4bq/biBjbGFyaXR5ICjEkeG7mSB0cm9uZyBzdeG7kXQpKioNCg0KIyMjICoqU+G7kSBsxrDhu6NuZyB2acOqbiBraW0gY8awxqFuZyB0aGVvIMSR4buZIHRyb25nIHN14buRdCBj4bunYSB04burbmcgbG/huqFpIG3DoHUqKg0KDQpgYGB7cn0NCmEgJT4lIGdyb3VwX2J5KGN1dCxjb2xvcikgJT4lIHN1bW1hcmlzZShtID0gbWVhbihwcmljZSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjdXQseSA9IG0pKSArDQogICAgZ2VvbV9jb2woZmlsbCA9ICdnb2xkJykgKw0KICAgIGZhY2V0X3dyYXAofmNvbG9yKSArDQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKG0pKSwgdmp1c3QgPSAyLCBjb2xvciA9ICdyZWQnKSArDQogICAgbGFicyh0aXRsZSA9ICdIw6xuaCAyNjogU+G7kSBsxrDhu6NuZyB2acOqbiBraW0gY8awxqFuZyB0aGVvIMSR4buZIHRyb25nIHN14buRdCBj4bunYSB04burbmcgbG/huqFpIG3DoHUnLCB4ID0gJ0xv4bqhaScsIHkgPSAnU+G7kSBsxrDhu6NuZycpDQpgYGANCg0KQ8OhYyBuaMOzbSBtw6B1IHPhuq9jIMSRxrDhu6NjIGJp4buDdSBkaeG7hW4gZMaw4bubaSBk4bqhbmcgY8OhYyBuaMOzbSBjb24sIHbDoCB0csOqbiBt4buXaSBj4buZdCwgY8OzIG5ow6NuIGhp4buDbiB0aOG7iyBnacOhIHRy4buLIHRydW5nIGLDrG5oIGdpw6EgbMOgbSB0csOybi4gQmnhu4N1IMSR4buTIG7DoHkgZ2nDunAgdGjhuqV5IHLDtSBz4buxIHBow6JuIGLhu5EgY+G7p2EgZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBnacOhIGPhu6dhIGtpbSBjxrDGoW5nIHRyb25nIGPDoWMgbmjDs20gxJHhu5kgdHJvbmcgc3Xhu5F0IHbDoCBtw6B1IHPhuq9jIGtow6FjIG5oYXUuDQoNCg0KIyMgKio1LiBQaMOibiB0w61jaCB0aGVvIGJp4bq/biBwcmljZSAoZ2nDoSBj4bqjKSoqDQoNCiMjIyAqKjUuMS4gVHJ1bmcgYsOsbmggbeG7qWMgZ2nDoSBj4bunYSB04burbmcgbG/huqFpIG3DoHUgdGhlbyDEkeG7mSB0cm9uZyBzdeG7kXQqKg0KDQpgYGB7cn0NCmEgJT4lIGdyb3VwX2J5KGNsYXJpdHksY29sb3IpICU+JSBzdW1tYXJpc2UobSA9IG1lYW4ocHJpY2UpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY2xhcml0eSx5ID0gbSkpICsNCiAgICBnZW9tX2NvbChmaWxsID0gJ3llbGxvd2dyZWVuJykgKw0KICAgIGZhY2V0X3dyYXAofmNvbG9yKSArDQogICAgbGFicyh0aXRsZSA9ICdIw6xuaCAyNzogVHJ1bmcgYsOsbmggbeG7qWMgZ2nDoSBj4bunYSB04burbmcgbG/huqFpIG3DoHUgdGhlbyDEkeG7mSB0cm9uZyBzdeG7kXQnLCB4ID0gJ0dpw6FjIGPhuq90JywgeSA9ICdUcnVuZyBiw6xuaCBnacOhJykNCmBgYA0KDQpW4bubaSAqKEjDrG5oIDI3KSogdGEgdGjhuqV5IHLhurFuZzsNCg0KKiDEkOG7mSB0cm9uZyBzdeG7kXQgKipJRioqIGtow7RuZyB04bqhcCBjaOG6pXQg4bufICoqbcOgdSBEKiogY8OzIHRydW5nIGLDrG5oIGdpw6EgY2FvIHbGsOG7o3QgdHLhu5lpLCDDoXAgxJHhuqNvIGjGoW4gbmjhu69uZyBsb+G6oWkga2ltIGPGsMahbmcga2jDoWMuDQoNCiogSOG6p3UgaOG6v3QgdOG7q25nIMSR4buZIHRyb25nIHN14buRdCDhu58gY8OhYyBtw6B1IGPhu6dhIHZpw6puIGtpbSBjxrDGoW5nIMSR4buBdSBjw7MgdHJ1bmcgYsOsbmggZ2nDoSB4w6ptIHjDqm0gbmhhdSwga2jDtG5nIGNo4buHbmggbOG7h2NoIHF1w6Egbmhp4buBdS4NCg0KIyMjICoqNS4yLiBHacOhIHRydW5nIGLDrG5oIGPhu6dhIHThu6tuZyBsb+G6oWkgZ2nDoWMgY+G6r3QqKg0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjdXQsIHkgPSBwcmljZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICdzdW1tYXJ5JywgZnVuID0gJ21lYW4nLCBmaWxsID0gJ29yYW5nZScpICsNCiAgbGFicyh0aXRsZSA9ICdIw6xuaCAyODogR2nDoSB0cnVuZyBiw6xuaCBj4bunYSB04burbmcgbG/huqFpIGdpw6FjIGPhuq90JywgeCA9ICdHacOhYyBj4bqvdCcsIHkgPSAnR2nDoSB0cnVuZyBiw6xuaCcpDQpgYGANCg0KS+G6v3QgcXXhuqMgdHLhuqMgduG7gSBjaG8gY2jDum5nIHRhIHRo4bqleSwNCg0KKiBMb+G6oWkgKipQcmVtaXVtKiogY8OzIHRydW5nIGLDrG5oIGdpw6EgY2FvIG5o4bqldCB24bubaSBnacOhIHRy4buLIHRydW5nIGLDrG5oIGjGoW4gNDUwMC4NCg0KKiBMb+G6oWkgKipGYWlyKiogY8OzIHRydW5nIGLDrG5oIGdpw6EgY2FvIHRo4bupIDIgduG7m2kgZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCB44bqlcCB4xKkgZ+G6p24gYuG6sW5nIDQ1MDAuDQoNCiogTG/huqFpICoqR29vZCoqIHbDoCAqKnZlcnkgZ29vZCoqIGPDsyB0cnVuZyBiw6xuaCBnacOhIHRy4buLIGNhbyB0aOG7qSAzLCDEkeG7gXUgY8OzIGdpw6EgdHLhu4sgdHJ1bmcgYsOsbmggeOG6pXAgeMSpIGLhurFuZyA0MDAwLg0KDQoqIExv4bqhaSAqKklkZWFsKiogY8OzIHRydW5nIGLDrG5oIGdpw6EgdHLhu4sgdGjhuqVwIG5ow6F0LCBnacOhIHRy4buLIHRydW5nIGLDrG5oIGLhurFuZyAzNTAwLg0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjdXQsIGZpbGwgPSBjdXQsIHkgPSBwcmljZSkpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGdlb21fYmFyKHN0YXQgPSAnc3VtbWFyeScsIGZ1biA9ICdtZWFuJywgcG9zaXRpb24gPSAnZG9kZ2UnKSArDQogIGxhYnModGl0bGUgPSAnSMOsbmggMjk6IEdpw6EgdHJ1bmcgYsOsbmggY+G7p2EgdOG7q25nIGxv4bqhaSBnacOhYyBj4bqvdCAoxJFhIG3DoHUgc+G6r2MpJywgeCA9ICdHacOhYyBj4bqvdCcsIHkgPSAnR2nDoSB0cnVuZyBiw6xuaCcpICAgICAgDQpgYGANCg0KQmnhu4N1IMSR4buTICooSMOsbmggMjgpKiB2w6AgKihIw6xuaCAyOSkqIGPDsyBjw7luZyBt4buZdCBj4bqldSB0csO6YyBjxqEgYuG6o24sIG5oxrBuZyBiaeG7g3UgxJHhu5MgKihIw6xuaCAyOSkqIMSRxrDhu6NjIHRoaeG6v3Qga+G6vyB24bubaSBt4buZdCBnw7NjIHRo4bqpbSBt4bu5IGNhbyBoxqFuLCBuaOG6pW4gbeG6oW5oIHbDoG8gc+G7sSB0cuG7sWMgcXVhbiB2w6AgZOG7hSBoaeG7g3UuIFPhu7EgY2jDuiDDvSDEkeG6t2MgYmnhu4d0IMSRxrDhu6NjIMSR4bq3dCB2w6BvIHZp4buHYyB04bqhbyDEkWnhu4NtIG5o4bqlbiB2w6Agc+G7sSDEkeG7k25nIG5o4bqldCB0cm9uZyBtw6B1IHPhuq9jLCBnacO6cCBiaeG7g3UgxJHhu5MgdHLhu58gbsOqbiBo4bqlcCBk4bqrbiB2w6AgZOG7hSB0aGVvIGTDtWkuDQoNCiMjIyAqKjUuMy4gU28gc8OhbmggZ2nDoSBraW0gY8awxqFuZyBnaeG7r2EgY8OhYyBsb+G6oWkgbcOgdSBz4bqvYyB2w6AgZ2nDoWMgY+G6r3QqKg0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjdXQsIGZpbGwgPSBjb2xvciwgeSA9IHByaWNlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gJ3N1bW1hcnknLCBmdW4gPSAnbWVhbicsIHBvc2l0aW9uID0gJ2RvZGdlJykgKw0KICBsYWJzKHRpdGxlID0gJ0jDrG5oIDMwOiBTbyBzw6FuaCBnacOhIGtpbSBjxrDGoW5nIGdp4buvYSBjw6FjIGxv4bqhaSBtw6B1IHPhuq9jIHbDoCBnacOhYyBj4bqvdCcsIHggPSAnTG/huqFpJywgeSA9ICdHacOhJykgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gJ1NldDQnKSANCmBgYA0KDQo9PiBCaeG7g3UgxJHhu5MgY+G7mXQgc28gc8OhbmggZ2nDoSBraW0gY8awxqFuZyBnaeG7r2EgY8OhYyBsb+G6oWkgbcOgdSBz4bqvYyB2w6AgZ2nDoWMgY+G6r3QuIE3hu5dpIGPhu5l0IGJp4buDdSBkaeG7hW4gZ2nDoSB0cnVuZyBiw6xuaCBj4bunYSBraW0gY8awxqFuZyB0cm9uZyB04burbmcgbG/huqFpIG3DoHUgc+G6r2MsIMSRxrDhu6NjIHBow6JuIGNoaWEgdGhlbyBnacOhYyBj4bqvdCwgduG7m2kgbcOgdSBz4bqvYyBj4bunYSBj4buZdCDEkcaw4bujYyDEkeG6t2MgdHLGsG5nIGLhu59pIGxv4bqhaSBtw6B1IHPhuq9jLg0KDQoNCg0KDQoNCg0KDQoNCg0K