Phần 1: Tìm hiểu và Chuẩn bị Dữ liệu

1.1 Đọc bộ dữ liệu

library(csv)
data <- read.csv("D:/UFM/2025- Kì 2/Phân tích dữ liệu định tính - Trần Mạnh Tường/Supermarket Transactions.csv", header = T)

Bộ dữ liệu “Supermarket Transactions” ghi nhận thông tin chi tiết về các giao dịch mua hàng tại một siêu thị trong một khoảng thời gian nhất định. Mỗi dòng dữ liệu đại diện cho một giao dịch, bao gồm nhiều thông tin liên quan đến khách hàng (giới tính, loại thành viên, chi nhánh mua hàng), thông tin sản phẩm (loại sản phẩm, kênh thanh toán), và các biến liên quan đến hành vi mua sắm (thời gian mua hàng, mức độ hài lòng, tổng giá trị đơn hàng,…).

  • Supermarket Transactions là file csv ,nên ta đọc từ file csv.

  • Thao tác thực hiện: Ta gán bộ dữ liệu Supermarket Transactions với tên là data.

1.2 Cấu trúc dữ liệu

Để có thể kiểm tra cấu trúc tổng quát của dữ liệu, ta sử dụng lệnh str()

Lệnh str() là viết tắt của structure – dùng để:

  • Kiểm tra cấu trúc tổng quát của một đối tượng, thường là một data frame.

  • Giúp ta nhận biết được:

    • Số lượng dòng, số lượng cột.

    • Tên cụ thể của các biến.

    • Kiểu dữ liệu của từng biến.

    • Một vài giá trị mẫu đầu tiên của từng biến.

str(data)
## 'data.frame':    14059 obs. of  16 variables:
##  $ X                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ PurchaseDate     : chr  "2007-12-18" "2007-12-20" "2007-12-21" "2007-12-21" ...
##  $ CustomerID       : int  7223 7841 8374 9619 1900 6696 9673 354 1293 7938 ...
##  $ Gender           : chr  "F" "M" "F" "M" ...
##  $ MaritalStatus    : chr  "S" "M" "M" "M" ...
##  $ Homeowner        : chr  "Y" "Y" "N" "Y" ...
##  $ Children         : int  2 5 2 3 3 3 2 2 3 1 ...
##  $ AnnualIncome     : chr  "$30K - $50K" "$70K - $90K" "$50K - $70K" "$30K - $50K" ...
##  $ City             : chr  "Los Angeles" "Los Angeles" "Bremerton" "Portland" ...
##  $ StateorProvince  : chr  "CA" "CA" "WA" "OR" ...
##  $ Country          : chr  "USA" "USA" "USA" "USA" ...
##  $ ProductFamily    : chr  "Food" "Food" "Food" "Food" ...
##  $ ProductDepartment: chr  "Snack Foods" "Produce" "Snack Foods" "Snacks" ...
##  $ ProductCategory  : chr  "Snack Foods" "Vegetables" "Snack Foods" "Candy" ...
##  $ UnitsSold        : int  5 5 3 4 4 3 4 6 1 2 ...
##  $ Revenue          : num  27.38 14.9 5.52 4.44 14 ...

Từ kết quả hiển thị, ta thấy:

  • Dữ liệu bao gồm: 14,059 dòng (obs)16 biến (variables).

  • Tên cụ thể của từng biến, kiểu dữ liệumột số giá trị mẫu.

Mục tiêu của phân tích này là áp dụng các kỹ thuật thống kê mô tả và thống kê suy diễn để khám phá các đặc điểm của khách hàng và hành vi mua sắm của họ, với trọng tâm là các biến định tính (categorical variables). bao gồm:

  • Gender: Giới tính (F - Nữ, M - Nam)

  • MaritalStatus: Tình trạng hôn nhân (S - Độc thân, M - Đã kết hôn)

  • Homeowner: Có sở hữu nhà hay không (Y – Có, N – Không)

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

  • City, StateorProvince, Country: Thông tin địa lý

  • ProductFamily, ProductDepartment, ProductCategory: Phân loại sản phẩm

1.3 Một vài dòng đầu và cuối của dữ liệu

Trong R, 2 hàm thường được sử dụng cho mục đích kiểm tra một cách trực quan các dòng đầu và cuối của bộ dữ liệu là head()tail().

Hai câu lệnh này giúp khi phân tích:

  • Nhanh chóng xác nhận dữ liệu đã được nhập đúng định dạng (kiểu ngày tháng, ký tự, số, v.v.).

  • Kiểm tra tính đầy đủ, nhất quán của dữ liệu từ đầu đến cuối.

  • Phát hiện sớm các lỗi phổ biến như: dữ liệu bị cắt xén, dòng trống, dữ liệu sai vị trí…

head(data,5)
X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children AnnualIncome City StateorProvince Country ProductFamily ProductDepartment ProductCategory UnitsSold Revenue
1 2007-12-18 7223 F S Y 2 $30K - $50K Los Angeles CA USA Food Snack Foods Snack Foods 5 27.38
2 2007-12-20 7841 M M Y 5 $70K - $90K Los Angeles CA USA Food Produce Vegetables 5 14.90
3 2007-12-21 8374 F M N 2 $50K - $70K Bremerton WA USA Food Snack Foods Snack Foods 3 5.52
4 2007-12-21 9619 M M Y 3 $30K - $50K Portland OR USA Food Snacks Candy 4 4.44
5 2007-12-22 1900 F S Y 3 $130K - $150K Beverly Hills CA USA Drink Beverages Carbonated Beverages 4 14.00

Câu lệnh head(data,5) giúp hiển thị 5 dòng đầu tiên, mặc định sẽ hiển thị từ dòng 1 đến dòng 5. Nếu muốn thay đổi số dòng hiển thị thì chỉ cần điền một con số khác trong câu lệnh là được.

Mục đích của câu lệnh:

  • Xem cấu trúc dữ liệu ban đầu, định dạng biến, kiểu dữ liệu.

  • Kiểm tra nhập liệu đầu dòng có hợp lý không.

  • Phù hợp để xác định xem dữ liệu có được đọc đúng cách (ví dụ: ngày, ký tự, số…).

tail(data,5)
X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children AnnualIncome City StateorProvince Country ProductFamily ProductDepartment ProductCategory UnitsSold Revenue
14055 14055 2009-12-29 9102 F M Y 2 $10K - $30K Bremerton WA USA Food Baking Goods Baking Goods 3 9.64
14056 14056 2009-12-29 4822 F M Y 3 $10K - $30K Walla Walla WA USA Food Frozen Foods Vegetables 3 7.45
14057 14057 2009-12-31 250 M S Y 1 $30K - $50K Portland OR USA Drink Beverages Pure Juice Beverages 4 3.24
14058 14058 2009-12-31 6153 F S N 4 $50K - $70K Spokane WA USA Drink Dairy Dairy 2 4.00
14059 14059 2009-12-31 3656 M S N 3 $50K - $70K Portland OR USA Non-Consumable Household Electrical 5 25.53

Ngược lại với head là tail, câu lệnh tail(data,5) giúp hiển thị 5 dòng cuối cùng của dữ liệu. Nếu muốn thay đổi số dòng hiển thị thì cũng chỉ cần điền một con số khác trong câu lệnh.

Mục đích của câu lệnh:

  • Kiểm tra kết thúc tập dữ liệu, xem dữ liệu có bị thiếu hoặc lỗi định dạng ở cuối không.

  • Kiểm tra tính đồng nhất và nhất quán đến cuối tập dữ liệu.

1.4 Kiểm tra giá trị thiếu NA

Để kiểm tra tính hoàn chỉnh của dữ liệu, cụ thể là phát hiện giá trị bị thiếu (NA) trong bộ dữ liệu, ta dùng các câu lệnh sau:

sum(is.na(data))
## [1] 0
  • is,na() là câu lệnh giúp đánh dấu dữ liệu đang bị thiếu.

    • Kết quả sẽ là TRUE nếu trong dữ liệu có giá trị thiếu NA.

    • Kết quả sẽ là FALSE nếu không thiếu.

  • sum(is,na()) sẽ giúp ta tính tổng giá trị bị thiếu (nếu có).

    • TRUE được tính là 1, FALSE là 0 nên tổng của các TRUE sẽ là số lượng phần tử bị thiếu.

    • Mục đích câu lệnh giúp nhanh chóng biết được toàn bộ dataset có bao nhiêu giá trị bị thiếu.

which(is.na(data))
## integer(0)

which(is.na(data)) đang tìm vị trí các phần tử bị thiếu trong toàn bộ data.

  • Kết quả integer(0) có nghĩa là không có bất kỳ giá trị nào bị thiếu trong toàn bộ dữ liệu.

Nếu có giá trị bị thiếu xuất hiện trong bộ dữ liệu, ta có thể dùng lệnh na.omit() để loại bỏ tất cả các hàng trong data có chứa ít nhất một giá trị bị thiếu.


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

2.1 Biến Gender

2.1.1 Tần số và tấn suất

Bảng thống kê tần số của biến Gender - giới tính như sau:

table(data$Gender)
## 
##    F    M 
## 7170 6889
  • Lệnh table() giúp tạo ra một bảng tần số đếm số lần xuất hiện của từng giá trị trong biến của data

  • Nhận xét: Dựa trên bảng tần số, dữ liệu có tổng cộng 14.059 quan sát, trong đó có 7.170 người thuộc giới tính nữ (F - Female) và 6.889 người thuộc giới tính nam (M - Male), cho thấy số lượng nữ chiếm ưu thế nhẹ so với nam.

table(data$Gender)/sum(nrow(data))
## 
##         F         M 
## 0.5099936 0.4900064
  • Ta giải thích các lệnh thực hiện ra bảng kết quả tần suất như sau:

    • Lệnh table(data$Gender) trả về số lượng từng nhóm như đã giải thích bên trên

    • Lệnh nrow(data) hiển thị tổng số quan sát trong dataframe

    • Ta lấy số lượng từng nhóm chia cho tổng số quan sát của nhóm đó sẽ ra tuần suất

  • Nhận xét: Dựa trên bảng tần suất, tỷ lệ Nữ - F chiếm khoảng 50,99%, còn tỷ lệ Nam - M cũng có tỷ gần 49%. Sự chênh lệch giữa 2 giới tính là không quá đáng kể

2.1.2 Trực quan hóa

Sau khi thấy bảng tấn số và tần suất về giới tính, ta tiến hành trực quan hóa bằng biểu đồ tròn dưới đây:

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)

data %>% group_by(Gender) %>% summarise(n = n()) %>%
  ggplot(aes(x = '', y = n,fill = Gender)) +
    geom_col(color = 'black') +
    coord_polar('y') +
    geom_text(aes(x = 1.3, label = n),position = position_stack(vjust = .5)) +
    labs(caption = "Biểu đồ tròn về tần số giới tính") +
    theme_void()

  • Giải thích các câu lệnh như sau:

    • data: là dataframe gốc chứa dữ liệu.

    • %>%: toán tử pipe dùng để truyền kết quả bước trước sang bước sau.

    • group_by(Gender): nhóm dữ liệu theo biến giới tính.

    • summarise(n = n()): đếm số lượng người trong từng nhóm giới tính và gán vào biến mới là n.

    • ggplot(): hàm tạo biểu đồ với khung dữ liệu đầu vào.

    • x = '': trục x rỗng vì không cần thiết trong biểu đồ tròn.

    • y = n: giá trị số lượng dùng để chia tỷ lệ các phần.

    • fill = Gender: tô màu khác nhau cho từng giới tính.

    • geom_col(color = ''): tô viền ngoài cho từng phần.

    • coord_polar('y'): Chuyển hệ trục từ Cartesian sang Polar tạo ra biểu đồ tròn và xoay theo trục y để chuyển từ cột thành vòng tròn.

    • geom_text(aes(x = 1.3, label = n), position = position_stack(vjust = 0.5)): Hiển thị các con số thống kê cụ thể bên trong các phần của biểu đồ, x = 1.3 là vị trí các nhãn lệch ra một chút khỏi tâm, position_stack(vjust): căn giữa các nhãn theo chiều dọc trong từng phần tròn.

    • labs(caption = " "): Thêm dòng chú thích phía dưới biểu đồ.

    • theme_void(): Dùng xóa toàn bộ trục, lưới, nhãn, để biểu đồ tròn hiển thị gọn gàng và tập trung vào nội dung chính.

  • Nhận xét: Biểu đồ tròn trên thể hiện tần số phân bố giới tính trong bộ dữ liệu. Có thể thấy, phần màu đỏ đại diện cho giới tính nữ (F) chiếm tỷ lệ lớn hơn một chút so với phần màu xanh dương đại diện cho giới tính nam (M). Mặc dù sự khác biệt không lớn, nhưng biểu đồ cho thấy giới tính nữ có xu hướng chiếm ưu thế nhẹ so với giới tính nam trong tập dữ liệu này. Biểu đồ trực quan này giúp dễ dàng so sánh và nhận diện sự chênh lệch nhỏ giữa hai nhóm giới tính.

2.2 Biến MaritalStatus

2.2.1 Tần số và tấn suất

Bảng thống kê tần số của biến MaritalStatus - tình trạng hôn nhân như sau:

table(data$MaritalStatus)
## 
##    M    S 
## 6866 7193
  • Nhận xét: Dựa trên bảng kết quả, có 6,866 người đã kết hôn (M - Married) và 7,193 người còn độc thân (S - Single), cho thấy số lượng những người đã kết hôn ít hơn người còn độc thân.
table(data$MaritalStatus)/sum(nrow(data))
## 
##         M         S 
## 0.4883704 0.5116296
  • Nhận xét: Khi xét về tần suất, những người còn độc thân chiếm khoảng 51,16% trong toàn bộ dữ liệu, trong khi những người đã kết hôn chiếm khoảng 48,83%. Mức chênh lệch giữa 2 mức tình trạng hôn nhân là khoảng 3%.

2.2.2 Trực quan hóa

data %>%
  group_by(MaritalStatus) %>% summarise(n = n()) %>%
  mutate(perc = round(n / sum(n) * 100, 1)) %>%
  ggplot(aes(x = "", y = perc, fill = MaritalStatus)) +
    geom_col(color = 'black') +
    coord_polar("y") +
    geom_text(aes(x = 1.3, label = paste0(perc, "%")), 
              position = position_stack(vjust = 0.5)) +
    labs(caption = "Biểu đồ tròn về tần suất tình trạng hôn nhân") +
    theme_void()

  • Giải thích các câu lệnh sẽ tương tự như biểu đồ trên, bên cạnh đó cũng có các câu lệnh mới như sau:

    • mutate(perc = round(n / sum(n) * 100, 1)): tính phần trăm và làm tròn 1 chữ số thập phân.

    • y = perc: biểu đồ dựa trên tần suất % thay vì số lượng.

    • label = paste0(perc, "%"): hiển thị phần trăm trong biểu đồ.

  • Nhận xét: Biểu đồ tròn trên thể hiện tần suất về tình trạng hôn nhân, ta thấy phần màu xanh trên biểu đồ chiếm % nhiều hơn so với màu đó. Điều đó đồng nghĩa những người còn độc thân chiếm số lượng nhiều hơn đã kết hôn.

2.3 Biến Homeowner

2.3.1 Tần số và tấn suất

Kết quả thống kê tần số và tấn suất của biến Homeowner - sở hữu nhà hay không như sau:

table(data$Homeowner)
## 
##    N    Y 
## 5615 8444
table(data$Homeowner)/sum(nrow(data))
## 
##         N         Y 
## 0.3993883 0.6006117

Nhận xét: Dựa vào bảng tần số và tần suất của biến Homeowner – sở hữu nhà hay không, có thể thấy trong tổng số dữ liệu, có 8.444 người sở hữu nhà (ký hiệu Y) và 5.615 người không sở hữu nhà (ký hiệu N). Tính theo tỷ lệ, khoảng 60,06% số người trong tập dữ liệu là chủ sở hữu nhà, trong khi khoảng 39,94% còn lại không có nhà.

2.3.2 Trực quan hóa

data %>% group_by(Homeowner) %>% summarise(n = n()) %>%
  ggplot(aes(x = '', y = n,fill = Homeowner)) +
    geom_col(color = 'black') +
    coord_polar('y') +
    geom_text(aes(x = 1.3, label = n),position = position_stack(vjust = .5)) +
    labs(caption = "Biểu đồ tròn về tỷ lệ sở hữu nhà") +
    theme_void()

2.4 Biến AnnualIncome

2.4.1 Tần số và tấn suất

Kết quả thống kê tần số và tấn suất của biến AnnualIncome - Thu nhập hàng năm (được biểu thị dưới dạng các khoảng) như sau:

table(data$AnnualIncome)
## 
##   $10K - $30K $110K - $130K $130K - $150K       $150K +   $30K - $50K 
##          3090           643           760           273          4601 
##   $50K - $70K   $70K - $90K  $90K - $110K 
##          2370          1709           613
table(data$AnnualIncome)/sum(nrow(data))
## 
##   $10K - $30K $110K - $130K $130K - $150K       $150K +   $30K - $50K 
##    0.21978804    0.04573583    0.05405790    0.01941817    0.32726367 
##   $50K - $70K   $70K - $90K  $90K - $110K 
##    0.16857529    0.12155914    0.04360196

2.4.2 Trực quan hóa

data %>% group_by(AnnualIncome) %>% summarise(n = n()) %>%
  ggplot(aes(x = n, y = AnnualIncome))+
  geom_col(fill='lightblue')+
  labs(y = "Các mức thu nhập hằng năm", x="tần số")+
  labs(caption = "Biểu đồ tần số mức thu nhập hằng năm")+
  geom_text(aes(label =n), vjust=0, color = 'black')

Nhận xét: Nhìn chung, phần lớn thu nhập trong bộ dữ liệu khoảng từ 30.000 đến 50.000 USD/năm, với 4.601 người, chiếm tỷ lệ cao nhất trong tất cả các nhóm. Theo sau đó là nhóm thu nhập từ 10.000 đến 30.000 USD với 3.090 người và nhóm 50.000 đến 70.000 USD với 2.370 người. Nhóm thu nhập từ 70.000 đến 90.000 USD và 90.000 đến 110.000 USD có số lượng lần lượt là 1.709 và 613 người. Trong khi đó, các nhóm thu nhập cao hơn như 130.000–150.000 USD và trên 150.000 USD có tần số thấp hơn đáng kể, với lần lượt 760 và 273 người, cho thấy số người có thu nhập rất cao chiếm tỷ lệ nhỏ. Biểu đồ này phản ánh xu hướng phổ biến là phần lớn người lao động có mức thu nhập trung bình, trong khi số người có thu nhập rất cao hoặc rất thấp tương đối ít.

2.5 Biến City

2.5.1 Tần số và tấn suất

Kết quả thống kê tần số và tấn suất của biến City - Thành phố của các khách hàng có trong bộ dữ liệu như sau:

table(data$City)
## 
##      Acapulco    Bellingham Beverly Hills     Bremerton       Camacho 
##           383           143           811           834           452 
##   Guadalajara       Hidalgo   Los Angeles        Merida   Mexico City 
##            75           845           926           654           194 
##       Orizaba      Portland         Salem    San Andres     San Diego 
##           464           876          1386           621           866 
## San Francisco       Seattle       Spokane        Tacoma     Vancouver 
##           130           922           875          1257           633 
##      Victoria   Walla Walla        Yakima 
##           176           160           376
table(data$City)/sum(nrow(data))
## 
##      Acapulco    Bellingham Beverly Hills     Bremerton       Camacho 
##   0.027242336   0.010171420   0.057685468   0.059321431   0.032150224 
##   Guadalajara       Hidalgo   Los Angeles        Merida   Mexico City 
##   0.005334661   0.060103848   0.065865282   0.046518245   0.013798990 
##       Orizaba      Portland         Salem    San Andres     San Diego 
##   0.033003770   0.062308841   0.098584537   0.044170994   0.061597553 
## San Francisco       Seattle       Spokane        Tacoma     Vancouver 
##   0.009246746   0.065580767   0.062237712   0.089408920   0.045024539 
##      Victoria   Walla Walla        Yakima 
##   0.012518671   0.011380610   0.026744434

2.5.2 Trực quan hóa

data %>% group_by(City) %>% summarise(n = n()) %>%
  ggplot(aes(x = n, y = City))+
  geom_col(fill='pink')+
  labs(x="tần số", y = "Thông tin thành phố mà các khách hàng đang sống")+
  labs(caption = "Biểu đồ tần số các thành phố mà các khách hàng đang sống")+
  geom_text(aes(label =n), vjust=0.5, color = 'black')

Nhận xét: Biểu đồ cho thấy tần số khách hàng theo các thành phố nơi họ đang sinh sống. Thành phố có số lượng khách hàng cao nhất là San Andres với 1.386 người, tiếp theo là Seattle (1.257) và Los Angeles (926). Một số thành phố khác như Spokane, San Francisco, Merida cũng có lượng khách hàng đáng kể (trên 800 người). Ngược lại, các thành phố như Guadalajara (75), San Francisco (130) và Walla Walla (160) có số lượng khách hàng thấp nhất. Điều này cho thấy sự phân bố khách hàng không đồng đều, tập trung nhiều ở các thành phố lớn.

2.6 Biến StateorProvince

2.6.1 Tần số và tấn suất

Kết quả thống kê tần số và tấn suất của biến StateorProvince - Tiểu bang của các khách hàng đang sinh sống có trong bộ dữ liệu như sau:

table(data$StateorProvince)
## 
##        BC        CA        DF  Guerrero   Jalisco        OR  Veracruz        WA 
##       809      2733       815       383        75      2262       464      4567 
##   Yucatan Zacatecas 
##       654      1297
table(data$StateorProvince)/sum(nrow(data))
## 
##          BC          CA          DF    Guerrero     Jalisco          OR 
## 0.057543211 0.194395049 0.057969984 0.027242336 0.005334661 0.160893378 
##    Veracruz          WA     Yucatan   Zacatecas 
## 0.033003770 0.324845295 0.046518245 0.092254072

2.6.2 Trực quan hóa

library(scales)
data %>% group_by(StateorProvince) %>% summarise(n = n()) %>%
  mutate(percent = n / sum(n)) %>%
  ggplot(aes(x = percent, y = reorder(StateorProvince, percent))) +
  geom_col(fill = 'yellow') +
  scale_x_continuous(labels = percent_format(accuracy = 0.01)) +
  geom_text(aes(label = paste0(round(percent * 100, 2), "%")),
            hjust = -0.1, color = 'black') +
  labs(x = "Tỷ lệ (%)", y = "Tiểu bang", caption = "Biểu đồ tỷ lệ (%) các khách hàng theo tiểu bang") +
  theme_minimal()

  • mutate(percent = n / sum(n)): tính tỷ lệ phần trăm của từng tiểu bang so với tổng và sau đó lưu vào cột percent.

  • ggplot(aes(x = percent, y = reorder(StateorProvince, percent))):

    • Tạo biểu đồ với trục hoành là percent và trục tung là tên tiểu bang

    • reorder(StateorProvince, percent): sắp xếp tiểu bang theo thứ tự phần trăm tăng dần.

  • Tùy chỉnh trụ x scale_x_continuous(labels = percent_format(accuracy = 0.01)):

    • Hiển thị theo định dạng phần trăm %.

    • accuracy = 0.01: làm tròn đến 2 chữ số sau dấu phẩy.

  • geom_text(aes(label = paste0(round(percent * 100, 2), "%")), hjust = -0.1, color = 'black'):

    • Thêm nhãn phần trăm phía ngoài cột.

    • round(percent * 100, 2): làm tròn tỷ lệ phần trăm 2 chữ số.

    • hjust = -0.1: chỉnh vị trí nhãn ra phía ngoài cột.

    • color = 'black': màu chữ là đen.

2.7 Biến Country

2.7.1 Tần số và tấn suất

Kết quả thống kê tần số và tấn suất của biến Country - Quốc gia của các khách hàng đang sống có trong bộ dữ liệu như sau:

table(data$Country)
## 
## Canada Mexico    USA 
##    809   3688   9562
table(data$Country)/sum(nrow(data))
## 
##     Canada     Mexico        USA 
## 0.05754321 0.26232307 0.68013372

2.7.2 Trực quan hóa

data %>% group_by(Country) %>% summarise(n = n()) %>%
  ggplot(aes(x = Country, y = n))+
  geom_col(fill='darkorange')+
  labs(x = "Quốc gia", y="tần số")+
  labs(caption = "Biểu đồ tần số quốc gia")+
  geom_text(aes(label =n), vjust=2, color = 'black')

2.8 Biến ProductFamily

2.8.1 Tần số và tấn suất

Kết quả thống kê tần số và tấn suất của biến ProductFamily - Sản phẩm tiêu dùng gia đình như sau:

table(data$ProductFamily)
## 
##          Drink           Food Non-Consumable 
##           1250          10153           2656
table(data$ProductFamily)/sum(nrow(data))
## 
##          Drink           Food Non-Consumable 
##     0.08891102     0.72217085     0.18891813

2.8.2 Trực quan hóa

data %>% group_by(ProductFamily) %>% summarise(n = n()) %>%
  ggplot(aes(x = ProductFamily, y = n))+
  geom_col(fill='forestgreen')+
  labs(x = "Sản phẩm tiêu dùng gia đình", y="tần số")+
  labs(caption = "Biểu đồ tần suất giới tính")+
  geom_text(aes(label = paste0(round(table(data$ProductFamily)/sum(nrow(data)), 3), "%")),hjust = 0.3,vjust=2, color = 'black')

2.9 Biến ProductDepartment

2.9.1 Tần số và tấn suất

Kết quả thống kê tần số và tấn suất của biến ProductDepartment - Bộ phận sản phẩm

table(data$ProductDepartment)
## 
## Alcoholic Beverages         Baked Goods        Baking Goods           Beverages 
##                 356                 425                1072                 680 
##     Breakfast Foods        Canned Foods     Canned Products            Carousel 
##                 188                 977                 109                  59 
##            Checkout               Dairy                Deli                Eggs 
##                  82                 903                 699                 198 
##        Frozen Foods  Health and Hygiene           Household                Meat 
##                1382                 893                1420                  89 
##         Periodicals             Produce             Seafood         Snack Foods 
##                 202                1994                 102                1600 
##              Snacks       Starchy Foods 
##                 352                 277
table(data$ProductDepartment)/sum(nrow(data))
## 
## Alcoholic Beverages         Baked Goods        Baking Goods           Beverages 
##         0.025321858         0.030229746         0.076250089         0.048367594 
##     Breakfast Foods        Canned Foods     Canned Products            Carousel 
##         0.013372217         0.069492852         0.007753041         0.004196600 
##            Checkout               Dairy                Deli                Eggs 
##         0.005832563         0.064229319         0.049719041         0.014083505 
##        Frozen Foods  Health and Hygiene           Household                Meat 
##         0.098300021         0.063518031         0.101002916         0.006330464 
##         Periodicals             Produce             Seafood         Snack Foods 
##         0.014368020         0.141830856         0.007255139         0.113806103 
##              Snacks       Starchy Foods 
##         0.025037343         0.019702682

2.9.2 Trực quan hóa

data %>% group_by(ProductDepartment) %>% summarise(n = n()) %>%
  ggplot(aes(x = n, y = ProductDepartment))+
  geom_col(fill='orchid')+
  labs(x="tần số", y = "Thông tin về bộ phận sản phẩm")+
  labs(caption = "Biểu đồ tần số bộ phận sản phẩm")+
  geom_text(aes(label =n), vjust=0.5, color = 'black')

2.10 Biến ProductCategory

2.10.1 Tần số và tấn suất

Kết quả thống kê tần số và tấn suất của biến ProductCategory - Danh mục sản phẩm

table(data$ProductCategory)
## 
##         Baking Goods    Bathroom Products        Beer and Wine 
##                  484                  365                  356 
##                Bread      Breakfast Foods              Candles 
##                  425                  417                   45 
##                Candy     Canned Anchovies         Canned Clams 
##                  352                   44                   53 
##       Canned Oysters      Canned Sardines        Canned Shrimp 
##                   35                   40                   38 
##          Canned Soup          Canned Tuna Carbonated Beverages 
##                  404                   87                  154 
##    Cleaning Supplies        Cold Remedies                Dairy 
##                  189                   93                  903 
##        Decongestants               Drinks                 Eggs 
##                   85                  135                  198 
##           Electrical      Frozen Desserts       Frozen Entrees 
##                  355                  323                  118 
##                Fruit             Hardware        Hot Beverages 
##                  765                  129                  226 
##              Hygiene     Jams and Jellies     Kitchen Products 
##                  197                  588                  217 
##            Magazines                 Meat        Miscellaneous 
##                  202                  761                   42 
##  Packaged Vegetables       Pain Relievers       Paper Products 
##                   48                  192                  345 
##                Pizza     Plastic Products Pure Juice Beverages 
##                  194                  141                  165 
##              Seafood          Side Dishes          Snack Foods 
##                  102                  153                 1600 
##            Specialty        Starchy Foods           Vegetables 
##                  289                  277                 1728
table(data$ProductCategory)/sum(nrow(data))
## 
##         Baking Goods    Bathroom Products        Beer and Wine 
##          0.034426346          0.025962017          0.025321858 
##                Bread      Breakfast Foods              Candles 
##          0.030229746          0.029660716          0.003200797 
##                Candy     Canned Anchovies         Canned Clams 
##          0.025037343          0.003129668          0.003769827 
##       Canned Oysters      Canned Sardines        Canned Shrimp 
##          0.002489508          0.002845153          0.002702895 
##          Canned Soup          Canned Tuna Carbonated Beverages 
##          0.028736041          0.006188207          0.010953837 
##    Cleaning Supplies        Cold Remedies                Dairy 
##          0.013443346          0.006614980          0.064229319 
##        Decongestants               Drinks                 Eggs 
##          0.006045949          0.009602390          0.014083505 
##           Electrical      Frozen Desserts       Frozen Entrees 
##          0.025250729          0.022974607          0.008393200 
##                Fruit             Hardware        Hot Beverages 
##          0.054413543          0.009175617          0.016075112 
##              Hygiene     Jams and Jellies     Kitchen Products 
##          0.014012376          0.041823743          0.015434953 
##            Magazines                 Meat        Miscellaneous 
##          0.014368020          0.054129028          0.002987410 
##  Packaged Vegetables       Pain Relievers       Paper Products 
##          0.003414183          0.013656732          0.024539441 
##                Pizza     Plastic Products Pure Juice Beverages 
##          0.013798990          0.010029163          0.011736254 
##              Seafood          Side Dishes          Snack Foods 
##          0.007255139          0.010882709          0.113806103 
##            Specialty        Starchy Foods           Vegetables 
##          0.020556227          0.019702682          0.122910591

2.10.2 Trực quan hóa

data %>% group_by(ProductCategory) %>% summarise(n = n()) %>%
  ggplot(aes(x = n, y = ProductCategory))+
  geom_col(fill='gray')+
  labs(x="tần số", y = "Thông tin về các sản phẩm cụ thể")+
  labs(caption = "Biểu đồ tần số các sản phẩm")+
  geom_text(aes(label =n), vjust=0.5, color = 'black')


Phần 3: Ước lượng Khoảng và Kiểm định Giả thuyết cho Tỷ lệ (Một biến)

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

Ta chọn 3 hạng mục từ 3 biến của danh sách các biến định tính trên, bao gồm:

  • Hạng mục “F” của biến Gender - giới tính

  • Hạng mục “S” của biến MaritalStatus - tình trạng hôn nhân

  • Hạng mục “USA” của biến Country - quốc gia

3.2 Ước lượng Khoảng Tin cậy

3.2.1 Hạng mục “F” của biến Gender

Ước lượng Khoảng Tin cậy:

Ta muốn ước lượng khoảng tin cậy 95% cho tỷ lệ nữ (Gender = “F”)

# Số người là nữ
n_female <- sum(data$Gender == "F")

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

# Ước lượng khoảng tin cậy 95% cho tỷ lệ nữ
prop.test(n_female, n_total, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_female out of n_total, null probability 0.5
## X-squared = 5.5765, df = 1, p-value = 0.0182
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5016931 0.5182886
## sample estimates:
##         p 
## 0.5099936
  • Tỷ lệ khách hàng là nữ ước lượng được là: 0.5099 hay 50.99%

  • Khoảng tin cậy 95% cho tỷ lệ này: [50.17%, 51.82%]

  • Nhận xét: Từ các quan sát cho thấy tỷ lệ khách hàng nữ được ước lượng là khoảng 51.0%. Khoảng tin cậy 95% cho tỷ lệ này là từ 50.2% đến 51.8%, không bao gồm 50%. Với p-value = 0.0182 < 0.05, ta bác bỏ giả thuyết rằng tỷ lệ nữ bằng 50%. Điều này cho thấy có bằng chứng thống kê rằng tỷ lệ khách hàng nữ khác 50%, và cao hơn một chút so với giả thuyết.

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

Ta đặt bài toán giả thiết:

  • Giả thuyết H0: Tỷ lệ nữ trong tổng thể = 0.5

  • Giả thuyết H1: Tỷ lệ nữ ≠ 0.5

Kết quả thu được:

  • Nếu p-value < 0.05bác bỏ H0 ⇒ tỷ lệ nữ ≠ 50%, có ý nghĩa thống kê.

  • Nếu p-value ≥ 0.05không bác bỏ H0, không đủ bằng chứng để nói tỷ lệ nữ khác 50%.

→ Vì p-value = 0.0182 < 0.05, bác bỏ giả thuyết H0 ở mức ý nghĩa 5%.

Kết quả kiểm định giả thuyết cho thấy tỷ lệ khách hàng nữ trong mẫu khác 50% với độ tin cậy 95% (p-value = 0.0182 < 0.05). Do đó, có thể kết luận rằng tỷ lệ khách hàng nữ trong tổng thể không phải là 50%, mà là cao hơn một chút (~51%).

Trong toàn bộ dữ liệu khách mua hàng tại siêu thị, tỷ lệ khách hàng là nữ là khoảng 51%. Kết quả kiểm định cho thấy có bằng chứng thống kê rõ ràng rằng tỷ lệ này khác 50% — tức là không hoàn toàn cân bằng giữa nam và nữ. Mặc dù chênh lệch chỉ khoảng 1%, nhưng vì dữ liệu lớn, sự khác biệt nhỏ này cũng có ý nghĩa.

3.3.2 Hạng mục “S” của biến Gender

Ước lượng Khoảng Tin cậy:

Ta muốn ước lượng khoảng tin cậy 95% cho tỷ lệ độc thân (MaritalStatus = “S”)

# Số người độc thân
n_single <- sum(data$MaritalStatus == "S")

# Ước lượng khoảng tin cậy 95% cho tỷ lệ độc thân
prop.test(n_single, n_total, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_single out of n_total, null probability 0.5
## X-squared = 7.5593, df = 1, p-value = 0.00597
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5033292 0.5199235
## sample estimates:
##         p 
## 0.5116296
  • Tỷ lệ khách hàng độc thân ước lượng được là: 0.5116 hay 51.16%

  • Khoảng tin cậy 95% cho tỷ lệ này: [50.33%, 51.99%]

  • Nhận xét: Ta tin tưởng 95% rằng tỷ lệ khách hàng độc thân trong tổng thể nằm trong khoảng từ 50.33% đến 51.99%. Mặc dù khoảng này khá hẹp (chênh lệch chỉ ~1.6%), nó cho thấy khách độc thân chiếm tỉ lệ nhỉnh hơn một chút so với khách đã kết hôn hoặc ở trạng thái khác.

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

Ta đặt bài toán giả thiết:

  • Giả thuyết H0: Tỷ lệ khách độc thân = 50%

  • Giả thuyết H1: Tỷ lệ khách độc thân ≠ 50%

Kết quả giá trị p-value = 0.00597 < 0.05Bác bỏ giả thuyết H0

Có bằng chứng thống kê cho thấy tỷ lệ khách hàng độc thân KHÁC 50%, Tỷ lệ thực tế cao hơn một chút (~51.16%).

3.3.3 Hạng mục “USA” của biến Country

Ước lượng Khoảng Tin cậy:

# Số người sống ở USA
n_USA <- sum(data$Country == "USA")

# Ước lượng khoảng tin cậy 95% cho tỷ lệ sống ở USA
prop.test(n_USA, n_total, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_USA out of n_total, null probability 0.5
## X-squared = 1824, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.6723397 0.6878289
## sample estimates:
##         p 
## 0.6801337
  • Tỷ lệ khách hàng sống tại USA ước lượng được là: 0.6801337 hay 68.01%

  • Khoảng tin cậy 95% cho tỷ lệ này là: [67.23%, 68.79%]

  • Nhận xét: Ta có thể tin tưởng 95% rằng tỷ lệ khách hàng sống tại Hoa Kỳ (USA) trong tổng thể là từ 67.23% đến 68.79%. Tức là gần 7 trong 10 khách hàng trong dữ liệu là người sống tại Mỹ.

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

Ta đặt bài toán giả thiết:

  • Giả thuyết H0: Tỷ lệ khách hàng sống ở USA = 50%

  • Giả thuyết H1: Tỷ lệ khách hàng sống ở USA ≠ 50%

Kết quả giá trị p-value < 2.2e-16 (rất nhỏ, gần như bằng 0) ⇒ Bác bỏ giả thuyết H0 ở mức ý nghĩa 5%

Có bằng chứng thống kê rất mạnh cho thấy tỷ lệ khách hàng sống ở Mỹ KHÁC 50% — và thực tế là cao hơn rất nhiều (68%).


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

Ta chọn 3 cặp biến định tính như sau:

  • Gender và Homeowner

  • MaritalStatus và Homeowner

  • Country và ProductFamily

4.1 Cặp biến Gender và Homeowner

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

Ta tạo bảng tần suất chéo (contingency table) cho hai biến Gender và Homeowner như sau:

# Bảng tần suất chéo
table_gender_home <- table(data$Gender, data$Homeowner)
table_gender_home
##    
##        N    Y
##   F 2826 4344
##   M 2789 4100

Kết quả của bảng tần suất này có ý nghĩa như sau:

  • 2826 nữ không sở hữu nhà.

  • 4344 nữ sở hữu nhà.

  • 2789 nam không sở hữu nhà.

  • 4100 nam sở hữu nhà.

# Hiển thị bảng tần suất chéo theo tỷ lệ hàng
prop.table(table_gender_home, margin = 1)
##    
##             N         Y
##   F 0.3941423 0.6058577
##   M 0.4048483 0.5951517

Lệnh prop.table(..., margin = 1) có ý nghĩa như sau:

  • Tính tỷ lệ phần trăm (proportion) theo hàng trong bảng table_gender_home.

  • margin = 1: tỷ lệ theo từng giới tính (F và M).

  • Tổng mỗi hàng sẽ bằng 1.0 (100%).

Diễn giải kết quả:

  • Trong số nữ sẽ có ~39.41% không sở hữu nhà~60.59% sở hữu nhà.

  • Trong số nam sẽ có ~40.48% không sở hữu nhà~59.52% sở hữu nhà.

Nhận xét: Dựa trên kết quả bảng tần suất và tỷ lệ, ta có thể rút ra một số nhận định rằng trong 7170 nữ giới (2826 không sở hữu nhà và 4344 sở hữu nhà), và 6889 nam giới (2789 không sở hữu nhà và 4100 sở hữu nhà). Tỷ lệ sở hữu nhà giữa nam và nữ khá tương đồng, nhưng nữ có xu hướng sở hữu nhà cao hơn một chút (60.59% so với 59.52%).

4.1.2 Trực quan hóa

Ta trực quan hóa bảng tần suất thành biểu đồ cột chồng như sau:

# Trực quan hóa bằng biểu đồ cột chồng
ggplot(data, aes(x = Gender, fill = Homeowner)) +
  geom_bar(position = "fill") +
  labs(title = "Tỷ lệ sở hữu nhà theo giới tính", y = "Tỷ lệ", x = "Giới tính") +
  scale_y_continuous(labels = scales::percent)

Nhận xét: Biểu đồ thể hiện tỷ lệ sở hữu nhà theo giới tính cho thấy sự phân bố tương đối đồng đều giữa nam và nữ. Cụ thể, cả hai giới đều có khoảng 60% người sở hữu nhà và khoảng 40% không sở hữu nhà. Điều này cho thấy rằng giới tính không phải là một yếu tố ảnh hưởng rõ rệt đến khả năng sở hữu nhà trong tập dữ liệu này. Mặc dù tỷ lệ phụ nữ sở hữu nhà có phần nhỉnh hơn so với nam giới, nhưng mức chênh lệch là rất nhỏ và không thể hiện một xu hướng rõ ràng.

4.1.3 Kiểm định Thống kê - Kiểm định Chi-bình phương

Ta thực hiện kiểm định Chi-squared như sau:

chisq.test(table_gender_home)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  table_gender_home
## X-squared = 1.6344, df = 1, p-value = 0.2011

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

  • Giả thuyết không H0: Hai biến Gender và Homeowner là độc lập với nhau (tức giới tính không ảnh hưởng đến khả năng sở hữu nhà).

  • Giả thuyết đối H1: Hai biến có mối liên hệ với nhau (tức giới tính có ảnh hưởng đến khả năng sở hữu nhà).

Kết quả kiểm định Chi-bình phương:

  • Giá trị Chi-squared (X²): 1.6344

  • Bậc tự do df: 1

  • Giá trị p-value: 0.2011

Kết luận thống kê:p = 0.2011 > 0.05, ta chấp nhận giả thuyết không. Điều này có nghĩa là không có bằng chứng thống kê đủ mạnh để kết luận rằng tồn tại mối liên hệ giữa giới tính và tình trạng sở hữu nhà.

Thảo luận thêm: Kết quả kiểm định thống kê phù hợp với những gì biểu đồ trực quan cho thấy: tỷ lệ sở hữu nhà giữa nam và nữ khá tương đồng (khoảng 60% ở cả hai giới). Mặc dù phụ nữ có vẻ nhỉnh hơn một chút về tỷ lệ sở hữu nhà, nhưng sự khác biệt đó là nhỏ và không mang ý nghĩa thống kê.

4.2 Cặp biến MaritalStatus và Homeowner

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

Cặp biến tiếp theo là Tình trạng hôn nhân và Sở hữu nhà, liệu có bao nhiêu người độc thân sở hữu nhà và bao nhiêu người đã kết hôn sở hữu nhà?

Ta xem kết quả bảng tần suất chéo như sau:

# Bảng tần suất chéo
table_marital_home <- table(data$MaritalStatus, data$Homeowner)
table_marital_home
##    
##        N    Y
##   M 1719 5147
##   S 3896 3297

Kết quả của bảng tần suất này có ý nghĩa như sau:

  • 1719 người đã kết hôn không sở hữu nhà.

  • 5147 người đã kết hôn sở hữu nhà.

  • 3896 người độc thân không sở hữu nhà.

  • 3297 người độc thân sở hữu nhà.

# Hiển thị bảng tần suất chéo theo tỷ lệ hàng
prop.table(table_marital_home, margin = 1)
##    
##             N         Y
##   M 0.2503641 0.7496359
##   S 0.5416377 0.4583623

Nhận xét: Phân tích bảng tần suất cho thấy có sự khác biệt rõ rệt trong việc sở hữu nhà giữa những người đã kết hôn và người độc thân. Cụ thể, trong tổng số 6866 người đã kết hôn, có đến 5147 người (tương đương 75%) sở hữu nhà, trong khi chỉ 1719 người (khoảng 25%) không sở hữu nhà. Ngược lại, trong nhóm 7193 người độc thân, tỷ lệ sở hữu nhà chỉ là 45.8% (3297 người), còn lại 54.2% (3896 người) không sở hữu nhà.

Những con số này cho thấy rằng người đã kết hôn có khả năng sở hữu nhà cao hơn đáng kể so với người độc thân. Điều này có thể phản ánh sự ổn định về mặt tài chính, sự chia sẻ chi phí sinh hoạt hoặc khả năng tiếp cận tín dụng tốt hơn ở những người đã kết hôn. Từ đó, có thể bước đầu nhận định rằng tình trạng hôn nhân có liên quan đến khả năng sở hữu nhà trong tập dữ liệu này.

4.2.2 Trực quan hóa

# Trực quan hóa
data_summary <- data %>% group_by(MaritalStatus, Homeowner) %>% summarise(count = n()) %>% ungroup()
## `summarise()` has grouped output by 'MaritalStatus'. You can override using the
## `.groups` argument.
ggplot(data_summary, aes(x = MaritalStatus, y = count, fill = Homeowner)) +
  geom_col(position = position_dodge()) +
  geom_text(aes(label = count), position = position_dodge(width = 0.9), vjust = -0.5) +
  labs(title = "Số lượng sở hữu nhà theo tình trạng hôn nhân", y = "Số lượng", x = "Tình trạng hôn nhân")

Giải thích câu lệnh:

  • group_by(MaritalStatus, Homeowner): Nhóm dữ liệu theo tình trạng hôn nhân và tình trạng sở hữu nhà. Mỗi tổ hợp (ví dụ: Độc thân + Có nhà, Kết hôn + Không nhà) sẽ thành 1 nhóm.

  • summarise(count = n()): Tính số lượng bản ghi trong mỗi nhóm và đặt tên cột là count.

  • ungroup(): Bỏ grouping để kết quả không còn ràng buộc bởi các nhóm nữa (tránh lỗi khi xử lý tiếp sau này).

  • Kết quả là một bảng tóm tắt (data_summary) gồm 3 cột: MaritalStatus, Homeowner, và count.

  • ggplot(data_summary, aes(...)): Tạo biểu đồ từ bảng data_summary, trong đó:

    • x = MaritalStatus: trục hoành là tình trạng hôn nhân (M, S).

    • y = count: chiều cao cột là số lượng.

    • fill = Homeowner: màu sắc cột thay đổi theo tình trạng sở hữu nhà (Y, N).

  • geom_col(position = position_dodge()): Vẽ biểu đồ cột (column chart) với các cột đặt cạnh nhau (thay vì chồng lên nhau) theo từng nhóm Homeowner.

  • geom_text(...): Thêm nhãn số lượng trên mỗi cột:

    • label = count: hiện số lượng.

    • position_dodge(width = 0.9): căn chỉnh vị trí chữ trùng khớp với vị trí các cột.

    • vjust = -0.5: dịch chữ lên phía trên một chút.

  • labs(...): Đặt tiêu đề và tên trục:

    • title: tiêu đề biểu đồ.

    • x: tên trục hoành là “Tình trạng hôn nhân”.

    • y: tên trục tung là “Số lượng”.

Nhận xét: Biểu đồ cho thấy người đã kết hôn có xu hướng sở hữu nhà cao hơn so với người độc thân. Cụ thể, số người đã kết hôn sở hữu nhà là 5.147, gần gấp ba lần so với nhóm không sở hữu nhà. Ngược lại, trong nhóm độc thân, số người không sở hữu nhà (3.896) lại cao hơn so với người có nhà (3.297). Điều này cho thấy tình trạng hôn nhân có ảnh hưởng rõ rệt đến khả năng sở hữu nhà, có thể do người đã kết hôn thường có tài chính ổn định hơn và nhu cầu mua nhà để ổn định cuộc sống gia đình.

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

Ta thực hiện kiểm định Chi-squared như sau:

chisq.test(table_marital_home)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  table_marital_home
## X-squared = 1241.2, df = 1, p-value < 2.2e-16

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

  • Giả thuyết không H0: Tình trạng hôn nhân và quyền sở hữu nhà là độc lập (không liên quan đến nhau).

  • Giả thuyết đối H1: Tình trạng hôn nhân và quyền sở hữu nhà có mối liên hệ (không độc lập).

Kết quả kiểm định Chi-bình phương:

  • Giá trị Chi-squared (X²): 1241.2

  • Bậc tự do df: 1

  • Giá trị p-value: < 2.2e-16

Kết luận thống kê: Vì giá trị p cực kỳ nhỏ (p < 2.2e-16), rất nhỏ hơn nhiều so với 0.05, ta bác bỏ giả thuyết không. Kết quả kiểm định cho thấy rằng có mối liên hệ có ý nghĩa thống kê mạnh mẽ giữa tình trạng hôn nhân và việc sở hữu nhà. Nói cách khác, khả năng một người sở hữu nhà có liên quan chặt chẽ đến việc họ có đang kết hôn hay không.

Thảo luận thêm: Tình trạng hôn nhân không chỉ là một đặc điểm xã hội, mà còn có ảnh hưởng rõ ràng đến kết quả kinh tế, cụ thể là khả năng sở hữu nhà. Sự khác biệt lớn về tỷ lệ và kết quả kiểm định thống kê cùng chỉ ra rằng người đã kết hôn có nhiều khả năng sở hữu nhà hơn người độc thân, có thể do yếu tố thu nhập kép, ổn định tài chính, hoặc kế hoạch cuộc sống dài hạn hơn.

4.3 Cặp biến Country và ProductFamily

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

Cặp biến cuối cùng là cặp biến Quốc gia và Nhóm sản phẩm chính

# Bảng tần suất chéo
table_country_product <- table(data$Country, data$ProductFamily)
table_country_product
##         
##          Drink Food Non-Consumable
##   Canada    69  580            160
##   Mexico   325 2683            680
##   USA      856 6890           1816

Nhận xét:

  • Mỹ là quốc gia có số lượng cao nhất ở tất cả các nhóm sản phẩm, đặc biệt là nhóm Food (6890).

  • Mexico đứng thứ hai, với Food là nhóm chiếm nhiều nhất.

  • Canada có số lượng thấp nhất ở tất cả các nhóm, đặc biệt Drink chỉ có 69.

# Hiển thị bảng tần suất chéo theo tỷ lệ hàng
prop.table(table_country_product, margin = 1)
##         
##               Drink       Food Non-Consumable
##   Canada 0.08529048 0.71693449     0.19777503
##   Mexico 0.08812364 0.72749458     0.18438178
##   USA    0.08952102 0.72056055     0.18991843

Nhận xét: Dù số lượng tuyệt đối khác nhau, tỷ lệ phân bổ sản phẩm theo từng quốc gia lại khá giống nhau.

  • Cả ba quốc gia đều có:

    • Trên 70% sản phẩm là Food (chiếm tỷ lệ cao nhất).

    • Drink và Non-Consumable chiếm tỷ lệ thấp và gần tương đương nhau.

  • Canada có tỷ lệ sản phẩm Non-Consumable cao hơn một chút (19.8%) so với Mexico và USA.

  • USA có tỷ lệ sản phẩm Drink cao nhất (8.95%), nhưng chênh lệch là không đáng kể.

4.3.2 Trực quan hóa

# Trực quan hóa
data_summary2 <- data %>% group_by(Country, ProductFamily) %>% summarise(count = n()) %>% mutate(total = sum(count), pct = count / total) %>% ungroup()
## `summarise()` has grouped output by 'Country'. You can override using the
## `.groups` argument.
ggplot(data_summary2, aes(x = Country, y = pct, fill = ProductFamily)) +
  geom_col(position = position_dodge()) +
  geom_text(aes(label = scales::percent(pct, accuracy = 0.1)),
            position = position_dodge(width = 0.9), vjust = -0.3, size = 3) +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(title = "Tỷ lệ nhóm sản phẩm theo quốc gia",
       y = "Tỷ lệ",
       x = "Quốc gia")

Giải thích câu lệnh:

  • group_by(Country, ProductFamily): Nhóm dữ liệu theo Quốc gia và Nhóm sản phẩm

  • summarise(count = n()): Tính số lượng từng nhóm (count)

  • mutate(total = sum(count): Tính tổng số sản phẩm theo mỗi Quốc gia

  • pct = count / total): Tính tỷ lệ phần trăm cho từng nhóm

  • ungroup(): Bỏ nhóm để tránh ảnh hưởng khi vẽ biểu đồ

  • ggplot(): vẽ biểu đồ cột theo tỷ lệ quốc gia

  • geom_col(position = position_dodge()): Vẽ các cột với các nhóm (ProductFamily) đặt cạnh nhau thay vì chồng lên nhau.

  • geom_text(aes(label = scales::percent(pct, accuracy = 0.1)), position = position_dodge(width = 0.9), vjust = -0.3, size = 3)

    • Gán nhãn văn bản là phần trăm, ví dụ “72.1%” thay vì số thập phân.

    • accuracy = 0.1 → hiển thị chính xác đến 1 chữ số thập phân.

    • vjust = -0.3 → căn vị trí nhãn nằm phía trên đầu cột.

    • size = 3 → chỉnh kích cỡ chữ.

  • scale_y_continuous(labels = scales::percent_format()): Biến trục y thành định dạng phần trăm

Nhận xét: Nhóm sản phẩm “Food” chiếm tỷ lệ cao nhất ở cả 3 quốc gia, % tỷ lệ là cao hơn hẳn 2 nhóm còn lại.”Drink” và “Non-Consumable” có tỷ lệ thấp hơn và khá tương đồng giữa các quốc gia. Biểu đồ cho thấy cơ cấu nhóm sản phẩm gần như không thay đổi theo quốc gia, cho thấy tính đồng nhất trong danh mục sản phẩm hoặc hành vi tiêu dùng ở các thị trường này.

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

Ta thực hiện kiểm định Chi-squared như sau:

chisq.test(table_country_product)
## 
##  Pearson's Chi-squared test
## 
## data:  table_country_product
## X-squared = 1.1831, df = 4, p-value = 0.8809

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

  • Giả thuyết không H0: 2 biến Quốc gia và Nhóm sản phẩm chính là độc lập (không liên quan đến nhau).

  • Giả thuyết đối H1: 2 biến Quốc gia và Nhóm sản phẩm chính có mối liên hệ (không độc lập).

Kết quả kiểm định Chi-bình phương:

  • Giá trị Chi-squared (X²): 1.1831

  • Bậc tự do df: 4

  • Giá trị p-value: 0.8809

Kết luận thống kê: Vì giá trị p-value = 0.8809, tức rất lớn hơn mức ý nghĩa, do đó không đủ bằng chứng thống kê để bác bỏ giả thuyết H0. Không có mối liên hệ giữa các quốc gia và nhóm sản phẩm.


Phần 5:Tổng kết và Thảo luận

5.1 Tóm tắt những phát hiện chính

  • Giới tính: Cả nam và nữ đều là nhóm khách hàng chính, nhưng chưa có dấu hiệu khác biệt rõ rệt về hành vi mua sắm chỉ dựa vào giới tính.

  • Tình trạng hôn nhân & sở hữu nhà: Người đã kết hôn có tỷ lệ sở hữu nhà cao hơn đáng kể so với người độc thân. Điều này gợi ý rằng nhóm khách hàng đã lập gia đình có thể có tài chính ổn định và tiềm năng mua sắm cao hơn.

  • Quốc gia & nhóm sản phẩm chính: Ở cả 3 quốc gia (Canada, Mexico, USA), thực phẩm (Food) là nhóm sản phẩm chủ đạo, chiếm hơn 70% tổng lượng sản phẩm bán ra. Các nhóm Drink và Non-Consumable chiếm tỷ trọng thấp hơn, tương đối đồng đều giữa các nước.

  • Kiểm định thống kê: Kiểm định Chi-bình phương cho thấy không có sự khác biệt có ý nghĩa thống kê về cơ cấu nhóm sản phẩm giữa các quốc gia (p-value ≈ 0.88).

5.2 Hạn chế của phân tích

  • Giới hạn trong biến định tính: Phân tích chỉ dựa trên các biến định tính, chưa xem xét yếu tố định lượng như thu nhập, doanh thu, hoặc số lượng bán chi tiết theo thời gian.

  • Dữ liệu chưa chuẩn hóa hoàn toàn: Một số biến (ví dụ: thu nhập) vẫn ở dạng text, cần xử lý thêm để phục vụ phân tích sâu hơn.

  • Không có yếu tố thời gian rõ ràng: Mặc dù có ngày mua hàng, nhưng chưa phân tích theo xu hướng thời gian (ví dụ theo quý hoặc năm).

5.3 Đề xuất

  • Chiến lược sản phẩm: Tập trung tiếp thị nhóm thực phẩm (Food) vì chiếm ưu thế trong cả ba thị trường. Tuy nhiên, cũng cần nghiên cứu thêm để tăng tỷ lệ tiêu thụ các nhóm sản phẩm còn lại.

  • Nhắm mục tiêu khách hàng: Ưu tiên nhóm khách hàng đã kết hôn và sở hữu nhà, vì có thể đây là đối tượng có sức mua cao và ổn định hơn.

  • Chiến dịch cá nhân hóa theo khu vực: Dù chưa có sự khác biệt đáng kể giữa các quốc gia, doanh nghiệp vẫn nên phân tích thêm theo thành phố hoặc tỉnh bang để điều chỉnh chiến lược cụ thể hơn.

5.4 Câu hỏi mở/Hướng nghiên cứu tiếp theo

  • Liệu có sự khác biệt đáng kể trong hành vi mua sắm giữa các nhóm thu nhập không?

  • Mức chi tiêu trung bình theo giới tính và tình trạng hôn nhân là bao nhiêu?

  • Có xu hướng theo mùa vụ nào trong hành vi mua sắm không?

  • Nên phân tích thêm tương quan giữa nhóm sản phẩm và doanh thu để tối ưu danh mục sản phẩm.

LS0tDQp0aXRsZTogIkJUIFR14bqnbiAyIg0KYXV0aG9yOiAiVsWpIFF14buzbmggVHLDumMgVnkiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclSDolTTolUywgJWQgLSAlbSAtICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2M6IHRydWUNCiAgICBkZl9wcmludDoga2FibGUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojICoqUGjhuqduIDE6IFTDrG0gaGnhu4N1IHbDoCBDaHXhuqluIGLhu4sgROG7ryBsaeG7h3UqKg0KDQojIyAqKjEuMSDEkOG7jWMgYuG7mSBk4buvIGxp4buHdSoqDQoNCmBgYHtyfQ0KbGlicmFyeShjc3YpDQpkYXRhIDwtIHJlYWQuY3N2KCJEOi9VRk0vMjAyNS0gS8OsIDIvUGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgxJHhu4tuaCB0w61uaCAtIFRy4bqnbiBN4bqhbmggVMaw4budbmcvU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zLmNzdiIsIGhlYWRlciA9IFQpDQpgYGANCg0KKipC4buZIGThu68gbGnhu4d1ICJTdXBlcm1hcmtldCBUcmFuc2FjdGlvbnMiKiogZ2hpIG5o4bqtbiB0aMO0bmcgdGluIGNoaSB0aeG6v3QgduG7gSBjw6FjIGdpYW8gZOG7i2NoIG11YSBow6BuZyB04bqhaSBt4buZdCBzacOqdSB0aOG7iyB0cm9uZyBt4buZdCBraG/huqNuZyB0aOG7nWkgZ2lhbiBuaOG6pXQgxJHhu4tuaC4gTeG7l2kgZMOybmcgZOG7ryBsaeG7h3UgxJHhuqFpIGRp4buHbiBjaG8gbeG7mXQgZ2lhbyBk4buLY2gsIGJhbyBn4buTbSBuaGnhu4F1IHRow7RuZyB0aW4gbGnDqm4gcXVhbiDEkeG6v24ga2jDoWNoIGjDoG5nIChnaeG7m2kgdMOtbmgsIGxv4bqhaSB0aMOgbmggdmnDqm4sIGNoaSBuaMOhbmggbXVhIGjDoG5nKSwgdGjDtG5nIHRpbiBz4bqjbiBwaOG6qW0gKGxv4bqhaSBz4bqjbiBwaOG6qW0sIGvDqm5oIHRoYW5oIHRvw6FuKSwgdsOgIGPDoWMgYmnhur9uIGxpw6puIHF1YW4gxJHhur9uIGjDoG5oIHZpIG11YSBz4bqvbSAodGjhu51pIGdpYW4gbXVhIGjDoG5nLCBt4bupYyDEkeG7mSBow6BpIGzDsm5nLCB04buVbmcgZ2nDoSB0cuG7iyDEkcahbiBow6BuZywuLi4pLg0KDQotICoqU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zKiogbMOgIGZpbGUgKipjc3YqKiAsbsOqbiB0YSDEkeG7jWMgdOG7qyBmaWxlIGNzdi4NCg0KLSAqKlRoYW8gdMOhYyB0aOG7sWMgaGnhu4duOioqIFRhIGfDoW4gYuG7mSBk4buvIGxp4buHdSAqKipTdXBlcm1hcmtldCBUcmFuc2FjdGlvbnMqKiogduG7m2kgdMOqbiBsw6AgKipkYXRhKiouDQoNCiMjICoqMS4yIEPhuqV1IHRyw7pjIGThu68gbGnhu4d1KioNCg0KxJDhu4MgY8OzIHRo4buDIGtp4buDbSB0cmEgY+G6pXUgdHLDumMgdOG7lW5nIHF1w6F0IGPhu6dhIGThu68gbGnhu4d1LCB0YSBz4butIGThu6VuZyBs4buHbmggYHN0cigpYA0KDQpM4buHbmggYHN0cigpYCBsw6Agdmnhur90IHThuq90IGPhu6dhIHN0cnVjdHVyZSDigJMgZMO5bmcgxJHhu4M6DQoNCi0gS2nhu4NtIHRyYSAqKmPhuqV1IHRyw7pjIHThu5VuZyBxdcOhdCoqIGPhu6dhIG3hu5l0IMSR4buRaSB0xrDhu6NuZywgdGjGsOG7nW5nIGzDoCBt4buZdCBkYXRhIGZyYW1lLg0KDQotIEdpw7pwIHRhIG5o4bqtbiBiaeG6v3QgxJHGsOG7o2M6DQoNCiAgIC0gU+G7kSBsxrDhu6NuZyBkw7JuZywgc+G7kSBsxrDhu6NuZyBj4buZdC4NCg0KICAgLSBUw6puIGPhu6UgdGjhu4MgY+G7p2EgY8OhYyBiaeG6v24uDQoNCiAgIC0gS2nhu4N1IGThu68gbGnhu4d1IGPhu6dhIHThu6tuZyBiaeG6v24uDQoNCiAgIC0gTeG7mXQgdsOgaSBnacOhIHRy4buLIG3huqt1IMSR4bqndSB0acOqbiBj4bunYSB04burbmcgYmnhur9uLg0KDQoNCmBgYHtyfQ0Kc3RyKGRhdGEpDQpgYGANCg0KVOG7qyBr4bq/dCBxdeG6oyBoaeG7g24gdGjhu4ssIHRhIHRo4bqleToNCg0KLSBE4buvIGxp4buHdSBiYW8gZ+G7k206ICoqMTQsMDU5IGTDsm5nIChvYnMpKiogdsOgICoqMTYgYmnhur9uICh2YXJpYWJsZXMpKiouDQoNCi0gKipUw6puIGPhu6UgdGjhu4MqKiBj4bunYSB04burbmcgYmnhur9uLCAqKmtp4buDdSBk4buvIGxp4buHdSoqIHbDoCAqKm3hu5l0IHPhu5EgZ2nDoSB0cuG7iyBt4bqrdSoqLg0KDQpN4bulYyB0acOqdSBj4bunYSBwaMOibiB0w61jaCBuw6B5IGzDoCDDoXAgZOG7pW5nIGPDoWMga+G7uSB0aHXhuq10IHRo4buRbmcga8OqIG3DtCB04bqjIHbDoCB0aOG7kW5nIGvDqiBzdXkgZGnhu4VuIMSR4buDIGtow6FtIHBow6EgY8OhYyDEkeG6t2MgxJFp4buDbSBj4bunYSBraMOhY2ggaMOgbmcgdsOgIGjDoG5oIHZpIG11YSBz4bqvbSBj4bunYSBo4buNLCB24bubaSB0cuG7jW5nIHTDom0gbMOgICoqY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCAoY2F0ZWdvcmljYWwgdmFyaWFibGVzKS4qKiBiYW8gZ+G7k206DQoNCi0gYEdlbmRlcmA6IEdp4bubaSB0w61uaCAoRiAtIE7hu68sIE0gLSBOYW0pIA0KDQotIGBNYXJpdGFsU3RhdHVzYDogVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIChTIC0gxJDhu5ljIHRow6JuLCBNIC0gxJDDoyBr4bq/dCBow7RuKQ0KDQotIGBIb21lb3duZXJgOiBDw7Mgc+G7nyBo4buvdSBuaMOgIGhheSBraMO0bmcgKFkg4oCTIEPDsywgTiDigJMgS2jDtG5nKSAgDQoNCi0gYEFubnVhbEluY29tZWA6IFRodSBuaOG6rXAgaMOgbmcgbsSDbSAoxJHGsOG7o2MgYmnhu4N1IHRo4buLIGTGsOG7m2kgZOG6oW5nIGPDoWMga2hv4bqjbmcpICANCg0KLSBgQ2l0eWAsIGBTdGF0ZW9yUHJvdmluY2VgLCBgQ291bnRyeWA6IFRow7RuZyB0aW4gxJHhu4thIGzDvSAgDQoNCi0gYFByb2R1Y3RGYW1pbHlgLCBgUHJvZHVjdERlcGFydG1lbnRgLCBgUHJvZHVjdENhdGVnb3J5YDogUGjDom4gbG/huqFpIHPhuqNuIHBo4bqpbSAgDQoNCg0KIyMgKioxLjMgTeG7mXQgdsOgaSBkw7JuZyDEkeG6p3UgdsOgIGN14buRaSBj4bunYSBk4buvIGxp4buHdSoqDQoNClRyb25nIFIsIDIgaMOgbSB0aMaw4budbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcgY2hvIG3hu6VjIMSRw61jaCBraeG7g20gdHJhIG3hu5l0IGPDoWNoIHRy4buxYyBxdWFuIGPDoWMgZMOybmcgxJHhuqd1IHbDoCBjdeG7kWkgY+G7p2EgYuG7mSBk4buvIGxp4buHdSBsw6AgYGhlYWQoKWAgdsOgIGB0YWlsKClgLg0KDQpIYWkgY8OidSBs4buHbmggbsOgeSBnacO6cCBraGkgcGjDom4gdMOtY2g6DQoNCi0gTmhhbmggY2jDs25nIHjDoWMgbmjhuq1uICoqZOG7ryBsaeG7h3UgxJHDoyDEkcaw4bujYyBuaOG6rXAgxJHDum5nIMSR4buLbmggZOG6oW5nKiogKGtp4buDdSBuZ8OgeSB0aMOhbmcsIGvDvSB04buxLCBz4buRLCB2LnYuKS4NCg0KLSAqKktp4buDbSB0cmEgdMOtbmggxJHhuqd5IMSR4bunLCBuaOG6pXQgcXXDoW4qKiBj4bunYSBk4buvIGxp4buHdSB04burIMSR4bqndSDEkeG6v24gY3Xhu5FpLg0KDQotICoqUGjDoXQgaGnhu4duIHPhu5ttIGPDoWMgbOG7l2kgcGjhu5UgYmnhur9uKiogbmjGsDogZOG7ryBsaeG7h3UgYuG7iyBj4bqvdCB4w6luLCBkw7JuZyB0cuG7kW5nLCBk4buvIGxp4buHdSBzYWkgduG7iyB0csOtLi4uDQoNCg0KYGBge3J9DQpoZWFkKGRhdGEsNSkNCmBgYA0KDQpDw6J1IGzhu4duaCBgaGVhZChkYXRhLDUpYCBnacO6cCBoaeG7g24gdGjhu4sgNSBkw7JuZyDEkeG6p3UgdGnDqm4sIG3hurdjIMSR4buLbmggc+G6vSBoaeG7g24gdGjhu4sgdOG7qyBkw7JuZyAxIMSR4bq/biBkw7JuZyA1LiBO4bq/dSBtdeG7kW4gdGhheSDEkeG7lWkgc+G7kSBkw7JuZyBoaeG7g24gdGjhu4sgdGjDrCBjaOG7iSBj4bqnbiDEkWnhu4FuIG3hu5l0IGNvbiBz4buRIGtow6FjIHRyb25nIGPDonUgbOG7h25oIGzDoCDEkcaw4bujYy4NCg0KKipN4bulYyDEkcOtY2gqKiBj4bunYSBjw6J1IGzhu4duaDogDQoNCi0gWGVtIGPhuqV1IHRyw7pjIGThu68gbGnhu4d1IGJhbiDEkeG6p3UsIMSR4buLbmggZOG6oW5nIGJp4bq/biwga2nhu4N1IGThu68gbGnhu4d1Lg0KDQotIEtp4buDbSB0cmEgbmjhuq1wIGxp4buHdSDEkeG6p3UgZMOybmcgY8OzIGjhu6NwIGzDvSBraMO0bmcuDQoNCi0gUGjDuSBo4bujcCDEkeG7gyB4w6FjIMSR4buLbmggeGVtIGThu68gbGnhu4d1IGPDsyDEkcaw4bujYyDEkeG7jWMgxJHDum5nIGPDoWNoICh2w60gZOG7pTogbmfDoHksIGvDvSB04buxLCBz4buRLi4uKS4NCg0KDQpgYGB7cn0NCnRhaWwoZGF0YSw1KQ0KYGBgDQoNCk5nxrDhu6NjIGzhuqFpIHbhu5tpIGhlYWQgbMOgIHRhaWwsIGPDonUgbOG7h25oIGB0YWlsKGRhdGEsNSlgIGdpw7pwIGhp4buDbiB0aOG7iyA1IGTDsm5nIGN14buRaSBjw7luZyBj4bunYSBk4buvIGxp4buHdS4gTuG6v3UgbXXhu5FuIHRoYXkgxJHhu5VpIHPhu5EgZMOybmcgaGnhu4NuIHRo4buLIHRow6wgY8WpbmcgY2jhu4kgY+G6p24gxJFp4buBbiBt4buZdCBjb24gc+G7kSBraMOhYyB0cm9uZyBjw6J1IGzhu4duaC4NCg0KKipN4bulYyDEkcOtY2gqKiBj4bunYSBjw6J1IGzhu4duaDogDQoNCi0gS2nhu4NtIHRyYSBr4bq/dCB0aMO6YyB04bqtcCBk4buvIGxp4buHdSwgeGVtIGThu68gbGnhu4d1IGPDsyBi4buLIHRoaeG6v3UgaG/hurdjIGzhu5dpIMSR4buLbmggZOG6oW5nIOG7nyBjdeG7kWkga2jDtG5nLg0KDQotIEtp4buDbSB0cmEgdMOtbmggxJHhu5NuZyBuaOG6pXQgdsOgIG5o4bqldCBxdcOhbiDEkeG6v24gY3Xhu5FpIHThuq1wIGThu68gbGnhu4d1Lg0KDQojIyAqKjEuNCBLaeG7g20gdHJhIGdpw6EgdHLhu4sgdGhp4bq/dSBOQSoqDQoNCsSQ4buDIGtp4buDbSB0cmEgdMOtbmggaG/DoG4gY2jhu4luaCBj4bunYSBk4buvIGxp4buHdSwgY+G7pSB0aOG7gyBsw6AgcGjDoXQgaGnhu4duIGdpw6EgdHLhu4sgYuG7iyB0aGnhur91IChOQSkgdHJvbmcgYuG7mSBk4buvIGxp4buHdSwgdGEgZMO5bmcgY8OhYyBjw6J1IGzhu4duaCBzYXU6DQoNCmBgYHtyfQ0Kc3VtKGlzLm5hKGRhdGEpKQ0KYGBgDQotIGBpcyxuYSgpYCBsw6AgY8OidSBs4buHbmggZ2nDunAgxJHDoW5oIGThuqV1IGThu68gbGnhu4d1IMSRYW5nIGLhu4sgdGhp4bq/dS4NCg0KICAgLSBL4bq/dCBxdeG6oyBz4bq9IGzDoCBgVFJVRWAgbuG6v3UgdHJvbmcgZOG7ryBsaeG7h3UgY8OzIGdpw6EgdHLhu4sgdGhp4bq/dSBOQS4NCiAgIA0KICAgLSBL4bq/dCBxdeG6oyBz4bq9IGzDoCBgRkFMU0VgIG7hur91IGtow7RuZyB0aGnhur91Lg0KICAgDQotIGBzdW0oaXMsbmEoKSlgIHPhur0gZ2nDunAgdGEgdMOtbmggdOG7lW5nIGdpw6EgdHLhu4sgYuG7iyB0aGnhur91IChu4bq/dSBjw7MpLg0KDQogICAtIFbDrCBgVFJVRWAgxJHGsOG7o2MgdMOtbmggbMOgIDEsIGBGQUxTRWAgbMOgIDAgbsOqbiB04buVbmcgY+G7p2EgY8OhYyBUUlVFIHPhur0gbMOgIHPhu5EgbMaw4bujbmcgcGjhuqduIHThu60gYuG7iyB0aGnhur91Lg0KICAgDQogICAtIE3hu6VjIMSRw61jaCBjw6J1IGzhu4duaCBnacO6cCBuaGFuaCBjaMOzbmcgYmnhur90IMSRxrDhu6NjIHRvw6BuIGLhu5kgZGF0YXNldCBjw7MgYmFvIG5oacOqdSBnacOhIHRy4buLIGLhu4sgdGhp4bq/dS4NCg0KDQpgYGB7cn0NCndoaWNoKGlzLm5hKGRhdGEpKQ0KYGBgDQoNCmB3aGljaChpcy5uYShkYXRhKSlgIMSRYW5nIHTDrG0gduG7iyB0csOtIGPDoWMgcGjhuqduIHThu60gYuG7iyB0aGnhur91IHRyb25nIHRvw6BuIGLhu5kgZGF0YS4NCg0KLSBL4bq/dCBxdeG6oyBgaW50ZWdlcigwKWAgY8OzIG5naMSpYSBsw6Aga2jDtG5nIGPDsyBi4bqldCBr4buzIGdpw6EgdHLhu4sgbsOgbyBi4buLIHRoaeG6v3UgdHJvbmcgdG/DoG4gYuG7mSBk4buvIGxp4buHdS4NCg0KTuG6v3UgY8OzIGdpw6EgdHLhu4sgYuG7iyB0aGnhur91IHh14bqldCBoaeG7h24gdHJvbmcgYuG7mSBk4buvIGxp4buHdSwgdGEgY8OzIHRo4buDIGTDuW5nIGzhu4duaCBgbmEub21pdCgpYCDEkeG7gyBsb+G6oWkgYuG7jyB04bqldCBj4bqjIGPDoWMgaMOgbmcgdHJvbmcgZGF0YSBjw7MgY2jhu6lhIMOtdCBuaOG6pXQgbeG7mXQgZ2nDoSB0cuG7iyBi4buLIHRoaeG6v3UuDQoNCi0tLQ0KDQojICoqUGjhuqduIDI6IFBow6JuIHTDrWNoIE3DtCB04bqjIE3hu5l0IGJp4bq/biDEkOG7i25oIHTDrW5oIChVbml2YXJpYXRlIERlc2NyaXB0aXZlIEFuYWx5c2lzKSoqDQoNCiMjICoqMi4xIEJp4bq/biBHZW5kZXIqKg0KDQojIyMgKioyLjEuMSBU4bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQqKg0KDQpC4bqjbmcgdGjhu5FuZyBrw6ogdOG6p24gc+G7kSBj4bunYSBiaeG6v24gKipHZW5kZXIgLSBnaeG7m2kgdMOtbmgqKiBuaMawIHNhdToNCg0KYGBge3J9DQp0YWJsZShkYXRhJEdlbmRlcikNCmBgYA0KLSBM4buHbmggYHRhYmxlKClgIGdpw7pwIHThuqFvIHJhIG3hu5l0IGLhuqNuZyB04bqnbiBz4buRIMSR4bq/bSBz4buRIGzhuqduIHh14bqldCBoaeG7h24gY+G7p2EgdOG7q25nIGdpw6EgdHLhu4sgdHJvbmcgYmnhur9uIGPhu6dhIGRhdGENCg0KLSAqKk5o4bqtbiB4w6l0OioqIEThu7FhIHRyw6puIGLhuqNuZyB04bqnbiBz4buRLCBk4buvIGxp4buHdSBjw7MgdOG7lW5nIGPhu5luZyAxNC4wNTkgcXVhbiBzw6F0LCB0cm9uZyDEkcOzIGPDsyA3LjE3MCBuZ8aw4budaSB0aHXhu5ljIGdp4bubaSB0w61uaCBu4buvIChGIC0gRmVtYWxlKSB2w6AgNi44ODkgbmfGsOG7nWkgdGh14buZYyBnaeG7m2kgdMOtbmggbmFtIChNIC0gTWFsZSksIGNobyB0aOG6pXkgc+G7kSBsxrDhu6NuZyBu4buvIGNoaeG6v20gxrB1IHRo4bq/IG5o4bq5IHNvIHbhu5tpIG5hbS4NCg0KDQpgYGB7cn0NCnRhYmxlKGRhdGEkR2VuZGVyKS9zdW0obnJvdyhkYXRhKSkNCmBgYA0KLSBUYSBnaeG6o2kgdGjDrWNoIGPDoWMgbOG7h25oIHRo4buxYyBoaeG7h24gcmEgYuG6o25nIGvhur90IHF14bqjIHThuqduIHN14bqldCBuaMawIHNhdToNCg0KICAgLSBM4buHbmggdGFibGUoZGF0YSRHZW5kZXIpIHRy4bqjIHbhu4Egc+G7kSBsxrDhu6NuZyB04burbmcgbmjDs20gbmjGsCDEkcOjIGdp4bqjaSB0aMOtY2ggYsOqbiB0csOqbg0KDQogICAtIEzhu4duaCBucm93KGRhdGEpIGhp4buDbiB0aOG7iyB04buVbmcgc+G7kSBxdWFuIHPDoXQgdHJvbmcgZGF0YWZyYW1lDQoNCiAgIC0gVGEgbOG6pXkgc+G7kSBsxrDhu6NuZyB04burbmcgbmjDs20gY2hpYSBjaG8gdOG7lW5nIHPhu5EgcXVhbiBzw6F0IGPhu6dhIG5ow7NtIMSRw7Mgc+G6vSByYSB0deG6p24gc3XhuqV0DQoNCi0gKipOaOG6rW4geMOpdDoqKiBE4buxYSB0csOqbiBi4bqjbmcgdOG6p24gc3XhuqV0LCB04bu3IGzhu4cgTuG7ryAtIEYgY2hp4bq/bSBraG/huqNuZyA1MCw5OSUsIGPDsm4gdOG7tyBs4buHIE5hbSAtIE0gY8WpbmcgY8OzIHThu7cgZ+G6p24gNDklLiBT4buxIGNow6puaCBs4buHY2ggZ2nhu69hIDIgZ2nhu5tpIHTDrW5oIGzDoCBraMO0bmcgcXXDoSDEkcOhbmcga+G7gw0KDQojIyMgKioyLjEuMiBUcuG7sWMgcXVhbiBow7NhKioNCg0KU2F1IGtoaSB0aOG6pXkgYuG6o25nIHThuqVuIHPhu5EgdsOgIHThuqduIHN14bqldCB24buBIGdp4bubaSB0w61uaCwgdGEgdGnhur9uIGjDoG5oIHRy4buxYyBxdWFuIGjDs2EgYuG6sW5nIGJp4buDdSDEkeG7kyB0csOybiBkxrDhu5tpIMSRw6J5Og0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmRhdGEgJT4lIGdyb3VwX2J5KEdlbmRlcikgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gJycsIHkgPSBuLGZpbGwgPSBHZW5kZXIpKSArDQogICAgZ2VvbV9jb2woY29sb3IgPSAnYmxhY2snKSArDQogICAgY29vcmRfcG9sYXIoJ3knKSArDQogICAgZ2VvbV90ZXh0KGFlcyh4ID0gMS4zLCBsYWJlbCA9IG4pLHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAuNSkpICsNCiAgICBsYWJzKGNhcHRpb24gPSAiQmnhu4N1IMSR4buTIHRyw7JuIHbhu4EgdOG6p24gc+G7kSBnaeG7m2kgdMOtbmgiKSArDQogICAgdGhlbWVfdm9pZCgpDQpgYGANCg0KLSAqKkdp4bqjaSB0aMOtY2ggY8OhYyBjw6J1IGzhu4duaCoqIG5oxrAgc2F1Og0KDQogICAtIGBkYXRhYDogbMOgIGRhdGFmcmFtZSBn4buRYyBjaOG7qWEgZOG7ryBsaeG7h3UuDQoNCiAgIC0gYCU+JWA6IHRvw6FuIHThu60gcGlwZSBkw7luZyDEkeG7gyB0cnV54buBbiBr4bq/dCBxdeG6oyBixrDhu5tjIHRyxrDhu5tjIHNhbmcgYsaw4bubYyBzYXUuDQoNCiAgIC0gYGdyb3VwX2J5KEdlbmRlcilgOiBuaMOzbSBk4buvIGxp4buHdSB0aGVvIGJp4bq/biBnaeG7m2kgdMOtbmguDQoNCiAgIC0gYHN1bW1hcmlzZShuID0gbigpKWA6IMSR4bq/bSBz4buRIGzGsOG7o25nIG5nxrDhu51pIHRyb25nIHThu6tuZyBuaMOzbSBnaeG7m2kgdMOtbmggdsOgIGfDoW4gdsOgbyBiaeG6v24gbeG7m2kgbMOgIG4uDQoNCiAgIC0gYGdncGxvdCgpYDogaMOgbSB04bqhbyBiaeG7g3UgxJHhu5MgduG7m2kga2h1bmcgZOG7ryBsaeG7h3UgxJHhuqd1IHbDoG8uDQoNCiAgIC0gYHggPSAnJ2A6IHRy4bulYyB4IHLhu5duZyB2w6wga2jDtG5nIGPhuqduIHRoaeG6v3QgdHJvbmcgYmnhu4N1IMSR4buTIHRyw7JuLg0KDQogICAtIGB5ID0gbmA6IGdpw6EgdHLhu4sgc+G7kSBsxrDhu6NuZyBkw7luZyDEkeG7gyBjaGlhIHThu7cgbOG7hyBjw6FjIHBo4bqnbi4NCg0KICAgLSBgZmlsbCA9IEdlbmRlcmA6IHTDtCBtw6B1IGtow6FjIG5oYXUgY2hvIHThu6tuZyBnaeG7m2kgdMOtbmguDQogICANCiAgIC0gYGdlb21fY29sKGNvbG9yID0gJycpYDogdMO0IHZp4buBbiBuZ2/DoGkgY2hvIHThu6tuZyBwaOG6p24uDQogICANCiAgIC0gYGNvb3JkX3BvbGFyKCd5JylgOiBDaHV54buDbiBo4buHIHRy4bulYyB04burIENhcnRlc2lhbiBzYW5nIFBvbGFyIHThuqFvIHJhIGJp4buDdSDEkeG7kyB0csOybiB2w6AgeG9heSB0aGVvIHRy4bulYyB5IMSR4buDIGNodXnhu4NuIHThu6sgY+G7mXQgdGjDoG5oIHbDsm5nIHRyw7JuLg0KICAgDQogICAtIGBnZW9tX3RleHQoYWVzKHggPSAxLjMsIGxhYmVsID0gbiksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKWA6IEhp4buDbiB0aOG7iyBjw6FjIGNvbiBz4buRIHRo4buRbmcga8OqIGPhu6UgdGjhu4MgYsOqbiB0cm9uZyBjw6FjIHBo4bqnbiBj4bunYSBiaeG7g3UgxJHhu5MsIHggPSAxLjMgbMOgIHbhu4sgdHLDrSBjw6FjIG5ow6NuIGzhu4djaCByYSBt4buZdCBjaMO6dCBraOG7j2kgdMOibSwgcG9zaXRpb25fc3RhY2sodmp1c3QpOiBjxINuIGdp4buvYSBjw6FjIG5ow6NuIHRoZW8gY2hp4buBdSBk4buNYyB0cm9uZyB04burbmcgcGjhuqduIHRyw7JuLg0KICAgDQogICAtIGBsYWJzKGNhcHRpb24gPSAiICIpYDogVGjDqm0gZMOybmcgY2jDuiB0aMOtY2ggcGjDrWEgZMaw4bubaSBiaeG7g3UgxJHhu5MuDQogICANCiAgIC0gYHRoZW1lX3ZvaWQoKWA6IETDuW5nIHjDs2EgdG/DoG4gYuG7mSB0cuG7pWMsIGzGsOG7m2ksIG5ow6NuLCDEkeG7gyBiaeG7g3UgxJHhu5MgdHLDsm4gaGnhu4NuIHRo4buLIGfhu41uIGfDoG5nIHbDoCB04bqtcCB0cnVuZyB2w6BvIG7hu5lpIGR1bmcgY2jDrW5oLg0KDQoNCg0KLSAqKk5o4bqtbiB4w6l0OioqIEJp4buDdSDEkeG7kyB0csOybiB0csOqbiB0aOG7gyBoaeG7h24gdOG6p24gc+G7kSBwaMOibiBi4buRIGdp4bubaSB0w61uaCB0cm9uZyBi4buZIGThu68gbGnhu4d1LiBDw7MgdGjhu4MgdGjhuqV5LCBwaOG6p24gbcOgdSDEkeG7jyDEkeG6oWkgZGnhu4duIGNobyBnaeG7m2kgdMOtbmggbuG7ryAoRikgY2hp4bq/bSB04bu3IGzhu4cgbOG7m24gaMahbiBt4buZdCBjaMO6dCBzbyB24bubaSBwaOG6p24gbcOgdSB4YW5oIGTGsMahbmcgxJHhuqFpIGRp4buHbiBjaG8gZ2nhu5tpIHTDrW5oIG5hbSAoTSkuIE3hurdjIGTDuSBz4buxIGtow6FjIGJp4buHdCBraMO0bmcgbOG7m24sIG5oxrBuZyBiaeG7g3UgxJHhu5MgY2hvIHRo4bqleSBnaeG7m2kgdMOtbmggbuG7ryBjw7MgeHUgaMaw4bubbmcgY2hp4bq/bSDGsHUgdGjhur8gbmjhurkgc28gduG7m2kgZ2nhu5tpIHTDrW5oIG5hbSB0cm9uZyB04bqtcCBk4buvIGxp4buHdSBuw6B5LiBCaeG7g3UgxJHhu5MgdHLhu7FjIHF1YW4gbsOgeSBnacO6cCBk4buFIGTDoG5nIHNvIHPDoW5oIHbDoCBuaOG6rW4gZGnhu4duIHPhu7EgY2jDqm5oIGzhu4djaCBuaOG7jyBnaeG7r2EgaGFpIG5ow7NtIGdp4bubaSB0w61uaC4NCg0KIyMgKioyLjIgQmnhur9uIE1hcml0YWxTdGF0dXMqKg0KDQojIyMgKioyLjIuMSBU4bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQqKg0KDQpC4bqjbmcgdGjhu5FuZyBrw6ogdOG6p24gc+G7kSBj4bunYSBiaeG6v24gKipNYXJpdGFsU3RhdHVzIC0gdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuKiogbmjGsCBzYXU6DQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRNYXJpdGFsU3RhdHVzKQ0KYGBgDQoNCi0gKipOaOG6rW4geMOpdDoqKiBE4buxYSB0csOqbiBi4bqjbmcga+G6v3QgcXXhuqMsIGPDsyA2LDg2NiBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gKE0gLSBNYXJyaWVkKSB2w6AgNywxOTMgIG5nxrDhu51pIGPDsm4gxJHhu5ljIHRow6JuIChTIC0gU2luZ2xlKSwgY2hvIHRo4bqleSBz4buRIGzGsOG7o25nIG5o4buvbmcgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIMOtdCBoxqFuIG5nxrDhu51pIGPDsm4gxJHhu5ljIHRow6JuLg0KDQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRNYXJpdGFsU3RhdHVzKS9zdW0obnJvdyhkYXRhKSkNCmBgYA0KDQotICoqTmjhuq1uIHjDqXQ6KiogS2hpIHjDqXQgduG7gSB04bqnbiBzdeG6pXQsIG5o4buvbmcgbmfGsOG7nWkgY8OybiDEkeG7mWMgdGjDom4gY2hp4bq/bSBraG/huqNuZyA1MSwxNiUgdHJvbmcgdG/DoG4gYuG7mSBk4buvIGxp4buHdSwgdHJvbmcga2hpIG5o4buvbmcgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIGNoaeG6v20ga2hv4bqjbmcgNDgsODMlLiBN4bupYyBjaMOqbmggbOG7h2NoIGdp4buvYSAyIG3hu6ljIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiBsw6Aga2hv4bqjbmcgMyUuDQoNCg0KIyMjICoqMi4yLjIgVHLhu7FjIHF1YW4gaMOzYSoqDQoNCmBgYHtyfQ0KZGF0YSAlPiUNCiAgZ3JvdXBfYnkoTWFyaXRhbFN0YXR1cykgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgbXV0YXRlKHBlcmMgPSByb3VuZChuIC8gc3VtKG4pICogMTAwLCAxKSkgJT4lDQogIGdncGxvdChhZXMoeCA9ICIiLCB5ID0gcGVyYywgZmlsbCA9IE1hcml0YWxTdGF0dXMpKSArDQogICAgZ2VvbV9jb2woY29sb3IgPSAnYmxhY2snKSArDQogICAgY29vcmRfcG9sYXIoInkiKSArDQogICAgZ2VvbV90ZXh0KGFlcyh4ID0gMS4zLCBsYWJlbCA9IHBhc3RlMChwZXJjLCAiJSIpKSwgDQogICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogICAgbGFicyhjYXB0aW9uID0gIkJp4buDdSDEkeG7kyB0csOybiB24buBIHThuqduIHN14bqldCB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4iKSArDQogICAgdGhlbWVfdm9pZCgpDQpgYGANCg0KLSAqKkdp4bqjaSB0aMOtY2ggY8OhYyBjw6J1IGzhu4duaCoqIHPhur0gdMawxqFuZyB04buxIG5oxrAgYmnhu4N1IMSR4buTIHRyw6puLCBiw6puIGPhuqFuaCDEkcOzIGPFqW5nIGPDsyBjw6FjIGPDonUgbOG7h25oIG3hu5tpIG5oxrAgc2F1Og0KDQogICAtIGBtdXRhdGUocGVyYyA9IHJvdW5kKG4gLyBzdW0obikgKiAxMDAsIDEpKWA6IHTDrW5oIHBo4bqnbiB0csSDbSB2w6AgbMOgbSB0csOybiAxIGNo4buvIHPhu5EgdGjhuq1wIHBow6JuLg0KICAgDQogICAtIGB5ID0gcGVyY2A6IGJp4buDdSDEkeG7kyBk4buxYSB0csOqbiB04bqnbiBzdeG6pXQgJSB0aGF5IHbDrCBz4buRIGzGsOG7o25nLg0KICAgDQogICAtIGBsYWJlbCA9IHBhc3RlMChwZXJjLCAiJSIpYDogaGnhu4NuIHRo4buLIHBo4bqnbiB0csSDbSB0cm9uZyBiaeG7g3UgxJHhu5MuDQoNCg0KLSAqKk5o4bqtbiB4w6l0OioqIEJp4buDdSDEkeG7kyB0csOybiB0csOqbiB0aOG7gyBoaeG7h24gdOG6p24gc3XhuqV0IHbhu4EgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuLCB0YSB0aOG6pXkgcGjhuqduIG3DoHUgeGFuaCB0csOqbiBiaeG7g3UgxJHhu5MgY2hp4bq/bSAlIG5oaeG7gXUgaMahbiBzbyB24bubaSBtw6B1IMSRw7MuIMSQaeG7gXUgxJHDsyDEkeG7k25nIG5naMSpYSBuaOG7r25nIG5nxrDhu51pIGPDsm4gxJHhu5ljIHRow6JuIGNoaeG6v20gc+G7kSBsxrDhu6NuZyBuaGnhu4F1IGjGoW4gxJHDoyBr4bq/dCBow7RuLg0KDQojIyAqKjIuMyBCaeG6v24gSG9tZW93bmVyKioNCg0KIyMjICoqMi4zLjEgVOG6p24gc+G7kSB2w6AgdOG6pW4gc3XhuqV0KioNCg0KS+G6v3QgcXXhuqMgdGjhu5FuZyBrw6ogdOG6p24gc+G7kSB2w6AgdOG6pW4gc3XhuqV0IGPhu6dhIGJp4bq/biAqKkhvbWVvd25lciAtIHPhu58gaOG7r3UgbmjDoCBoYXkga2jDtG5nKiogbmjGsCBzYXU6DQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRIb21lb3duZXIpDQpgYGANCg0KYGBge3J9DQp0YWJsZShkYXRhJEhvbWVvd25lcikvc3VtKG5yb3coZGF0YSkpDQpgYGANCiAqKk5o4bqtbiB4w6l0OioqIEThu7FhIHbDoG8gYuG6o25nIHThuqduIHPhu5EgdsOgIHThuqduIHN14bqldCBj4bunYSBiaeG6v24gSG9tZW93bmVyIOKAkyBz4bufIGjhu691IG5ow6AgaGF5IGtow7RuZywgY8OzIHRo4buDIHRo4bqleSB0cm9uZyB04buVbmcgc+G7kSBk4buvIGxp4buHdSwgY8OzIDguNDQ0IG5nxrDhu51pIHPhu58gaOG7r3UgbmjDoCAoa8O9IGhp4buHdSBZKSB2w6AgNS42MTUgbmfGsOG7nWkga2jDtG5nIHPhu58gaOG7r3UgbmjDoCAoa8O9IGhp4buHdSBOKS4gVMOtbmggdGhlbyB04bu3IGzhu4csIGtob+G6o25nIDYwLDA2JSBz4buRIG5nxrDhu51pIHRyb25nIHThuq1wIGThu68gbGnhu4d1IGzDoCBjaOG7pyBz4bufIGjhu691IG5ow6AsIHRyb25nIGtoaSBraG/huqNuZyAzOSw5NCUgY8OybiBs4bqhaSBraMO0bmcgY8OzIG5ow6AuIA0KDQojIyMgKioyLjMuMiBUcuG7sWMgcXVhbiBow7NhKioNCg0KYGBge3J9DQpkYXRhICU+JSBncm91cF9ieShIb21lb3duZXIpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9ICcnLCB5ID0gbixmaWxsID0gSG9tZW93bmVyKSkgKw0KICAgIGdlb21fY29sKGNvbG9yID0gJ2JsYWNrJykgKw0KICAgIGNvb3JkX3BvbGFyKCd5JykgKw0KICAgIGdlb21fdGV4dChhZXMoeCA9IDEuMywgbGFiZWwgPSBuKSxwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gLjUpKSArDQogICAgbGFicyhjYXB0aW9uID0gIkJp4buDdSDEkeG7kyB0csOybiB24buBIHThu7cgbOG7hyBz4bufIGjhu691IG5ow6AiKSArDQogICAgdGhlbWVfdm9pZCgpDQpgYGANCg0KDQojIyAqKjIuNCBCaeG6v24gQW5udWFsSW5jb21lKioNCg0KIyMjICoqMi40LjEgVOG6p24gc+G7kSB2w6AgdOG6pW4gc3XhuqV0KioNCg0KS+G6v3QgcXXhuqMgdGjhu5FuZyBrw6ogdOG6p24gc+G7kSB2w6AgdOG6pW4gc3XhuqV0IGPhu6dhIGJp4bq/biAqKkFubnVhbEluY29tZSAtIFRodSBuaOG6rXAgaMOgbmcgbsSDbSoqICjEkcaw4bujYyBiaeG7g3UgdGjhu4sgZMaw4bubaSBk4bqhbmcgY8OhYyBraG/huqNuZykgbmjGsCBzYXU6DQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRBbm51YWxJbmNvbWUpDQpgYGANCg0KYGBge3J9DQp0YWJsZShkYXRhJEFubnVhbEluY29tZSkvc3VtKG5yb3coZGF0YSkpDQpgYGANCg0KIyMjICoqMi40LjIgVHLhu7FjIHF1YW4gaMOzYSoqDQoNCmBgYHtyfQ0KZGF0YSAlPiUgZ3JvdXBfYnkoQW5udWFsSW5jb21lKSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gQW5udWFsSW5jb21lKSkrDQogIGdlb21fY29sKGZpbGw9J2xpZ2h0Ymx1ZScpKw0KICBsYWJzKHkgPSAiQ8OhYyBt4bupYyB0aHUgbmjhuq1wIGjhurFuZyBuxINtIiwgeD0idOG6p24gc+G7kSIpKw0KICBsYWJzKGNhcHRpb24gPSAiQmnhu4N1IMSR4buTIHThuqduIHPhu5EgbeG7qWMgdGh1IG5o4bqtcCBo4bqxbmcgbsSDbSIpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID1uKSwgdmp1c3Q9MCwgY29sb3IgPSAnYmxhY2snKQ0KYGBgDQoNCg0KKipOaOG6rW4geMOpdDoqKiBOaMOsbiBjaHVuZywgcGjhuqduIGzhu5tuIHRodSBuaOG6rXAgdHJvbmcgYuG7mSBk4buvIGxp4buHdSBraG/huqNuZyB04burIDMwLjAwMCDEkeG6v24gNTAuMDAwIFVTRC9uxINtLCB24bubaSA0LjYwMSBuZ8aw4budaSwgY2hp4bq/bSB04bu3IGzhu4cgY2FvIG5o4bqldCB0cm9uZyB04bqldCBj4bqjIGPDoWMgbmjDs20uIFRoZW8gc2F1IMSRw7MgbMOgIG5ow7NtIHRodSBuaOG6rXAgdOG7qyAxMC4wMDAgxJHhur9uIDMwLjAwMCBVU0QgduG7m2kgMy4wOTAgbmfGsOG7nWkgdsOgIG5ow7NtIDUwLjAwMCDEkeG6v24gNzAuMDAwIFVTRCB24bubaSAyLjM3MCBuZ8aw4budaS4gTmjDs20gdGh1IG5o4bqtcCB04burIDcwLjAwMCDEkeG6v24gOTAuMDAwIFVTRCB2w6AgOTAuMDAwIMSR4bq/biAxMTAuMDAwIFVTRCBjw7Mgc+G7kSBsxrDhu6NuZyBs4bqnbiBsxrDhu6N0IGzDoCAxLjcwOSB2w6AgNjEzIG5nxrDhu51pLiBUcm9uZyBraGkgxJHDsywgY8OhYyBuaMOzbSB0aHUgbmjhuq1wIGNhbyBoxqFuIG5oxrAgMTMwLjAwMOKAkzE1MC4wMDAgVVNEIHbDoCB0csOqbiAxNTAuMDAwIFVTRCBjw7MgdOG6p24gc+G7kSB0aOG6pXAgaMahbiDEkcOhbmcga+G7gywgduG7m2kgbOG6p24gbMaw4bujdCA3NjAgdsOgIDI3MyBuZ8aw4budaSwgY2hvIHRo4bqleSBz4buRIG5nxrDhu51pIGPDsyB0aHUgbmjhuq1wIHLhuqV0IGNhbyBjaGnhur9tIHThu7cgbOG7hyBuaOG7jy4gQmnhu4N1IMSR4buTIG7DoHkgcGjhuqNuIMOhbmggeHUgaMaw4bubbmcgcGjhu5UgYmnhur9uIGzDoCBwaOG6p24gbOG7m24gbmfGsOG7nWkgbGFvIMSR4buZbmcgY8OzIG3hu6ljIHRodSBuaOG6rXAgdHJ1bmcgYsOsbmgsIHRyb25nIGtoaSBz4buRIG5nxrDhu51pIGPDsyB0aHUgbmjhuq1wIHLhuqV0IGNhbyBob+G6t2MgcuG6pXQgdGjhuqVwIHTGsMahbmcgxJHhu5FpIMOtdC4NCg0KIyMgKioyLjUgQmnhur9uIENpdHkqKg0KDQojIyMgKioyLjUuMSBU4bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQqKg0KDQpL4bq/dCBxdeG6oyB0aOG7kW5nIGvDqiB04bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQgY+G7p2EgYmnhur9uICoqQ2l0eSAtIFRow6BuaCBwaOG7kSoqIGPhu6dhIGPDoWMga2jDoWNoIGjDoG5nIGPDsyB0cm9uZyBi4buZIGThu68gbGnhu4d1IG5oxrAgc2F1Og0KDQpgYGB7cn0NCnRhYmxlKGRhdGEkQ2l0eSkNCmBgYA0KDQpgYGB7cn0NCnRhYmxlKGRhdGEkQ2l0eSkvc3VtKG5yb3coZGF0YSkpDQpgYGANCg0KIyMjICoqMi41LjIgVHLhu7FjIHF1YW4gaMOzYSoqDQoNCmBgYHtyfQ0KZGF0YSAlPiUgZ3JvdXBfYnkoQ2l0eSkgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IENpdHkpKSsNCiAgZ2VvbV9jb2woZmlsbD0ncGluaycpKw0KICBsYWJzKHg9InThuqduIHPhu5EiLCB5ID0gIlRow7RuZyB0aW4gdGjDoG5oIHBo4buRIG3DoCBjw6FjIGtow6FjaCBow6BuZyDEkWFuZyBz4buRbmciKSsNCiAgbGFicyhjYXB0aW9uID0gIkJp4buDdSDEkeG7kyB04bqnbiBz4buRIGPDoWMgdGjDoG5oIHBo4buRIG3DoCBjw6FjIGtow6FjaCBow6BuZyDEkWFuZyBz4buRbmciKSsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9biksIHZqdXN0PTAuNSwgY29sb3IgPSAnYmxhY2snKQ0KYGBgDQoNCg0KKipOaOG6rW4geMOpdDoqKiBCaeG7g3UgxJHhu5MgY2hvIHRo4bqleSB04bqnbiBz4buRIGtow6FjaCBow6BuZyB0aGVvIGPDoWMgdGjDoG5oIHBo4buRIG7GoWkgaOG7jSDEkWFuZyBzaW5oIHPhu5FuZy4gVGjDoG5oIHBo4buRIGPDsyBz4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyBjYW8gbmjhuqV0IGzDoCBTYW4gQW5kcmVzIHbhu5tpIDEuMzg2IG5nxrDhu51pLCB0aeG6v3AgdGhlbyBsw6AgU2VhdHRsZSAoMS4yNTcpIHbDoCBMb3MgQW5nZWxlcyAoOTI2KS4gTeG7mXQgc+G7kSB0aMOgbmggcGjhu5Ega2jDoWMgbmjGsCBTcG9rYW5lLCBTYW4gRnJhbmNpc2NvLCBNZXJpZGEgY8WpbmcgY8OzIGzGsOG7o25nIGtow6FjaCBow6BuZyDEkcOhbmcga+G7gyAodHLDqm4gODAwIG5nxrDhu51pKS4gTmfGsOG7o2MgbOG6oWksIGPDoWMgdGjDoG5oIHBo4buRIG5oxrAgR3VhZGFsYWphcmEgKDc1KSwgU2FuIEZyYW5jaXNjbyAoMTMwKSB2w6AgV2FsbGEgV2FsbGEgKDE2MCkgY8OzIHPhu5EgbMaw4bujbmcga2jDoWNoIGjDoG5nIHRo4bqlcCBuaOG6pXQuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IHPhu7EgcGjDom4gYuG7kSBraMOhY2ggaMOgbmcga2jDtG5nIMSR4buTbmcgxJHhu4F1LCB04bqtcCB0cnVuZyBuaGnhu4F1IOG7nyBjw6FjIHRow6BuaCBwaOG7kSBs4bubbi4NCg0KIyMgKioyLjYgQmnhur9uIFN0YXRlb3JQcm92aW5jZSoqDQoNCiMjIyAqKjIuNi4xIFThuqduIHPhu5EgdsOgIHThuqVuIHN14bqldCoqDQoNCkvhur90IHF14bqjIHRo4buRbmcga8OqIHThuqduIHPhu5EgdsOgIHThuqVuIHN14bqldCBj4bunYSBiaeG6v24gKipTdGF0ZW9yUHJvdmluY2UgLSBUaeG7g3UgYmFuZyoqIGPhu6dhIGPDoWMga2jDoWNoIGjDoG5nIMSRYW5nIHNpbmggc+G7kW5nIGPDsyB0cm9uZyBi4buZIGThu68gbGnhu4d1IG5oxrAgc2F1Og0KDQpgYGB7cn0NCnRhYmxlKGRhdGEkU3RhdGVvclByb3ZpbmNlKQ0KYGBgDQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRTdGF0ZW9yUHJvdmluY2UpL3N1bShucm93KGRhdGEpKQ0KYGBgDQoNCiMjIyAqKjIuNi4yIFRy4buxYyBxdWFuIGjDs2EqKg0KDQoNCmBgYHtyfQ0KbGlicmFyeShzY2FsZXMpDQpkYXRhICU+JSBncm91cF9ieShTdGF0ZW9yUHJvdmluY2UpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIG11dGF0ZShwZXJjZW50ID0gbiAvIHN1bShuKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IHBlcmNlbnQsIHkgPSByZW9yZGVyKFN0YXRlb3JQcm92aW5jZSwgcGVyY2VudCkpKSArDQogIGdlb21fY29sKGZpbGwgPSAneWVsbG93JykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKHBlcmNlbnQgKiAxMDAsIDIpLCAiJSIpKSwNCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwgY29sb3IgPSAnYmxhY2snKSArDQogIGxhYnMoeCA9ICJU4bu3IGzhu4cgKCUpIiwgeSA9ICJUaeG7g3UgYmFuZyIsIGNhcHRpb24gPSAiQmnhu4N1IMSR4buTIHThu7cgbOG7hyAoJSkgY8OhYyBraMOhY2ggaMOgbmcgdGhlbyB0aeG7g3UgYmFuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KLSBgbXV0YXRlKHBlcmNlbnQgPSBuIC8gc3VtKG4pKTpgIHTDrW5oIHThu7cgbOG7hyBwaOG6p24gdHLEg20gY+G7p2EgdOG7q25nIHRp4buDdSBiYW5nIHNvIHbhu5tpIHThu5VuZyB2w6Agc2F1IMSRw7MgbMawdSB2w6BvIGPhu5l0IHBlcmNlbnQuDQoNCi0gYGdncGxvdChhZXMoeCA9IHBlcmNlbnQsIHkgPSByZW9yZGVyKFN0YXRlb3JQcm92aW5jZSwgcGVyY2VudCkpKWA6DQoNCiAgIC0gVOG6oW8gYmnhu4N1IMSR4buTIHbhu5tpIHRy4bulYyBob8OgbmggbMOgIGBwZXJjZW50YCB2w6AgdHLhu6VjIHR1bmcgbMOgIHTDqm4gdGnhu4N1IGJhbmcNCiAgIA0KICAgLSBgcmVvcmRlcihTdGF0ZW9yUHJvdmluY2UsIHBlcmNlbnQpYDogc+G6r3AgeOG6v3AgdGnhu4N1IGJhbmcgdGhlbyB0aOG7qSB04buxIHBo4bqnbiB0csSDbSB0xINuZyBk4bqnbi4NCiAgDQotIFTDuXkgY2jhu4luaCB0cuG7pSB4IGBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSlgOg0KDQogICAtIEhp4buDbiB0aOG7iyB0aGVvIMSR4buLbmggZOG6oW5nIHBo4bqnbiB0csSDbSAlLg0KICANCiAgIC0gYGFjY3VyYWN5ID0gMC4wMWA6IGzDoG0gdHLDsm4gxJHhur9uIDIgY2jhu68gc+G7kSBzYXUgZOG6pXUgcGjhuql5Lg0KDQotIGBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKHBlcmNlbnQgKiAxMDAsIDIpLCAiJSIpKSwgaGp1c3QgPSAtMC4xLCBjb2xvciA9ICdibGFjaycpOmANCg0KICAgLSBUaMOqbSBuaMOjbiBwaOG6p24gdHLEg20gcGjDrWEgbmdvw6BpIGPhu5l0Lg0KICAgDQogICAtIGByb3VuZChwZXJjZW50ICogMTAwLCAyKWA6IGzDoG0gdHLDsm4gdOG7tyBs4buHIHBo4bqnbiB0csSDbSAyIGNo4buvIHPhu5EuDQogICANCiAgIC0gYGhqdXN0ID0gLTAuMWA6IGNo4buJbmggduG7iyB0csOtIG5ow6NuIHJhIHBow61hIG5nb8OgaSBj4buZdC4NCiAgIA0KICAgLSBgY29sb3IgPSAnYmxhY2snYDogbcOgdSBjaOG7ryBsw6AgxJFlbi4NCg0KIyMgKioyLjcgQmnhur9uIENvdW50cnkqKg0KDQojIyMgKioyLjcuMSBU4bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQqKg0KDQpL4bq/dCBxdeG6oyB0aOG7kW5nIGvDqiB04bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQgY+G7p2EgYmnhur9uICoqQ291bnRyeSAtIFF14buRYyBnaWEqKiBj4bunYSBjw6FjIGtow6FjaCBow6BuZyDEkWFuZyBz4buRbmcgY8OzIHRyb25nIGLhu5kgZOG7ryBsaeG7h3UgbmjGsCBzYXU6DQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRDb3VudHJ5KQ0KYGBgDQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRDb3VudHJ5KS9zdW0obnJvdyhkYXRhKSkNCmBgYA0KDQojIyMgKioyLjcuMiBUcuG7sWMgcXVhbiBow7NhKioNCg0KDQpgYGB7cn0NCmRhdGEgJT4lIGdyb3VwX2J5KENvdW50cnkpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IENvdW50cnksIHkgPSBuKSkrDQogIGdlb21fY29sKGZpbGw9J2RhcmtvcmFuZ2UnKSsNCiAgbGFicyh4ID0gIlF14buRYyBnaWEiLCB5PSJ04bqnbiBz4buRIikrDQogIGxhYnMoY2FwdGlvbiA9ICJCaeG7g3UgxJHhu5MgdOG6p24gc+G7kSBxdeG7kWMgZ2lhIikrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPW4pLCB2anVzdD0yLCBjb2xvciA9ICdibGFjaycpDQpgYGANCg0KIyMgKioyLjggQmnhur9uIFByb2R1Y3RGYW1pbHkqKg0KDQojIyMgKioyLjguMSBU4bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQqKg0KDQpL4bq/dCBxdeG6oyB0aOG7kW5nIGvDqiB04bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQgY+G7p2EgYmnhur9uICoqUHJvZHVjdEZhbWlseSAtIFPhuqNuIHBo4bqpbSB0acOqdSBkw7luZyBnaWEgxJHDrG5oKiogbmjGsCBzYXU6DQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRQcm9kdWN0RmFtaWx5KQ0KYGBgDQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRQcm9kdWN0RmFtaWx5KS9zdW0obnJvdyhkYXRhKSkNCmBgYA0KDQojIyMgKioyLjguMiBUcuG7sWMgcXVhbiBow7NhKioNCg0KDQpgYGB7cn0NCmRhdGEgJT4lIGdyb3VwX2J5KFByb2R1Y3RGYW1pbHkpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFByb2R1Y3RGYW1pbHksIHkgPSBuKSkrDQogIGdlb21fY29sKGZpbGw9J2ZvcmVzdGdyZWVuJykrDQogIGxhYnMoeCA9ICJT4bqjbiBwaOG6qW0gdGnDqnUgZMO5bmcgZ2lhIMSRw6xuaCIsIHk9InThuqduIHPhu5EiKSsNCiAgbGFicyhjYXB0aW9uID0gIkJp4buDdSDEkeG7kyB04bqnbiBzdeG6pXQgZ2nhu5tpIHTDrW5oIikrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQodGFibGUoZGF0YSRQcm9kdWN0RmFtaWx5KS9zdW0obnJvdyhkYXRhKSksIDMpLCAiJSIpKSxoanVzdCA9IDAuMyx2anVzdD0yLCBjb2xvciA9ICdibGFjaycpDQpgYGANCg0KDQojIyAqKjIuOSBCaeG6v24gUHJvZHVjdERlcGFydG1lbnQqKg0KDQojIyMgKioyLjkuMSBU4bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQqKg0KDQpL4bq/dCBxdeG6oyB0aOG7kW5nIGvDqiB04bqnbiBz4buRIHbDoCB04bqlbiBzdeG6pXQgY+G7p2EgYmnhur9uICoqUHJvZHVjdERlcGFydG1lbnQgLSBC4buZIHBo4bqtbiBz4bqjbiBwaOG6qW0qKg0KDQpgYGB7cn0NCnRhYmxlKGRhdGEkUHJvZHVjdERlcGFydG1lbnQpDQpgYGANCg0KYGBge3J9DQp0YWJsZShkYXRhJFByb2R1Y3REZXBhcnRtZW50KS9zdW0obnJvdyhkYXRhKSkNCmBgYA0KDQojIyMgKioyLjkuMiBUcuG7sWMgcXVhbiBow7NhKioNCg0KDQpgYGB7cn0NCmRhdGEgJT4lIGdyb3VwX2J5KFByb2R1Y3REZXBhcnRtZW50KSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gUHJvZHVjdERlcGFydG1lbnQpKSsNCiAgZ2VvbV9jb2woZmlsbD0nb3JjaGlkJykrDQogIGxhYnMoeD0idOG6p24gc+G7kSIsIHkgPSAiVGjDtG5nIHRpbiB24buBIGLhu5kgcGjhuq1uIHPhuqNuIHBo4bqpbSIpKw0KICBsYWJzKGNhcHRpb24gPSAiQmnhu4N1IMSR4buTIHThuqduIHPhu5EgYuG7mSBwaOG6rW4gc+G6o24gcGjhuqltIikrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPW4pLCB2anVzdD0wLjUsIGNvbG9yID0gJ2JsYWNrJykNCmBgYA0KDQoNCiMjICoqMi4xMCBCaeG6v24gUHJvZHVjdENhdGVnb3J5KioNCg0KIyMjICoqMi4xMC4xIFThuqduIHPhu5EgdsOgIHThuqVuIHN14bqldCoqDQoNCkvhur90IHF14bqjIHRo4buRbmcga8OqIHThuqduIHPhu5EgdsOgIHThuqVuIHN14bqldCBj4bunYSBiaeG6v24gKipQcm9kdWN0Q2F0ZWdvcnkgLSBEYW5oIG3hu6VjIHPhuqNuIHBo4bqpbSoqDQoNCmBgYHtyfQ0KdGFibGUoZGF0YSRQcm9kdWN0Q2F0ZWdvcnkpDQpgYGANCg0KYGBge3J9DQp0YWJsZShkYXRhJFByb2R1Y3RDYXRlZ29yeSkvc3VtKG5yb3coZGF0YSkpDQpgYGANCg0KIyMjICoqMi4xMC4yIFRy4buxYyBxdWFuIGjDs2EqKg0KDQpgYGB7cn0NCmRhdGEgJT4lIGdyb3VwX2J5KFByb2R1Y3RDYXRlZ29yeSkgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IFByb2R1Y3RDYXRlZ29yeSkpKw0KICBnZW9tX2NvbChmaWxsPSdncmF5JykrDQogIGxhYnMoeD0idOG6p24gc+G7kSIsIHkgPSAiVGjDtG5nIHRpbiB24buBIGPDoWMgc+G6o24gcGjhuqltIGPhu6UgdGjhu4MiKSsNCiAgbGFicyhjYXB0aW9uID0gIkJp4buDdSDEkeG7kyB04bqnbiBz4buRIGPDoWMgc+G6o24gcGjhuqltIikrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPW4pLCB2anVzdD0wLjUsIGNvbG9yID0gJ2JsYWNrJykNCmBgYA0KDQotLS0NCg0KIyAqKlBo4bqnbiAzOiDGr+G7m2MgbMaw4bujbmcgS2hv4bqjbmcgdsOgIEtp4buDbSDEkeG7i25oIEdp4bqjIHRodXnhur90IGNobyBU4bu3IGzhu4cgKE3hu5l0IGJp4bq/bikqKg0KDQojIyAqKjMuMSBYw6FjIMSR4buLbmggaOG6oW5nIG3hu6VjIFF1YW4gdMOibSoqDQoNClRhIGNo4buNbiAzIGjhuqFuZyBt4bulYyB04burIDMgYmnhur9uIGPhu6dhIGRhbmggc8OhY2ggY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCB0csOqbiwgYmFvIGfhu5NtOg0KDQotICoqSOG6oW5nIG3hu6VjICJGIioqIGPhu6dhICoqYmnhur9uIEdlbmRlcioqIC0gZ2nhu5tpIHTDrW5oDQoNCi0gKipI4bqhbmcgbeG7pWMgIlMiKiogY+G7p2EgKipiaeG6v24gTWFyaXRhbFN0YXR1cyoqIC0gdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuDQoNCi0gKipI4bqhbmcgbeG7pWMgIlVTQSIqKiBj4bunYSAqKmJp4bq/biBDb3VudHJ5KiogLSBxdeG7kWMgZ2lhDQoNCiMjICoqMy4yIMav4bubYyBsxrDhu6NuZyBLaG/huqNuZyBUaW4gY+G6rXkqKg0KDQojIyMgKiozLjIuMSBI4bqhbmcgbeG7pWMgIkYiIGPhu6dhIGJp4bq/biBHZW5kZXIqKg0KDQojIyMjICoqxq/hu5tjIGzGsOG7o25nIEtob+G6o25nIFRpbiBj4bqteToqKg0KDQpUYSBtdeG7kW4gxrDhu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBu4buvIChHZW5kZXIgPSAiRiIpDQoNCmBgYHtyfQ0KIyBT4buRIG5nxrDhu51pIGzDoCBu4buvDQpuX2ZlbWFsZSA8LSBzdW0oZGF0YSRHZW5kZXIgPT0gIkYiKQ0KDQojIFThu5VuZyBz4buRIHF1YW4gc8OhdA0Kbl90b3RhbCA8LSBucm93KGRhdGEpDQoNCiMgxq/hu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBu4buvDQpwcm9wLnRlc3Qobl9mZW1hbGUsIG5fdG90YWwsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KYGBgDQoNCg0KLSBU4bu3IGzhu4cgKipraMOhY2ggaMOgbmcgbMOgIG7hu68gxrDhu5tjIGzGsOG7o25nKiogxJHGsOG7o2MgbMOgOiAqKjAuNTA5OSBoYXkgNTAuOTklKioNCg0KLSBLaG/huqNuZyB0aW4gY+G6rXkgOTUlIGNobyB04bu3IGzhu4cgbsOgeTogKipbNTAuMTclLCA1MS44MiVdKioNCg0KLSAqKk5o4bqtbiB4w6l0Kio6IFThu6sgY8OhYyBxdWFuIHPDoXQgY2hvIHRo4bqleSB04bu3IGzhu4cga2jDoWNoIGjDoG5nIG7hu68gxJHGsOG7o2MgxrDhu5tjIGzGsOG7o25nIGzDoCBraG/huqNuZyA1MS4wJS4gS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIG7DoHkgbMOgIHThu6sgNTAuMiUgxJHhur9uIDUxLjglLCBraMO0bmcgYmFvIGfhu5NtIDUwJS4gVuG7m2kgcC12YWx1ZSA9IDAuMDE4MiA8IDAuMDUsIHRhIGLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCBy4bqxbmcgdOG7tyBs4buHIG7hu68gYuG6sW5nIDUwJS4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgY8OzIGLhurFuZyBjaOG7qW5nIHRo4buRbmcga8OqIHLhurFuZyB04bu3IGzhu4cga2jDoWNoIGjDoG5nIG7hu68ga2jDoWMgNTAlLCB2w6AgY2FvIGjGoW4gbeG7mXQgY2jDunQgc28gduG7m2kgZ2nhuqMgdGh1eeG6v3QuDQoNCiMjIyMgKipLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dDoqKg0KDQpUYSDEkeG6t3QgYsOgaSB0b8OhbiBnaeG6oyB0aGnhur90Og0KDQotICoqR2nhuqMgdGh1eeG6v3QgSDAqKjogVOG7tyBs4buHIG7hu68gdHJvbmcgdOG7lW5nIHRo4buDID0gMC41DQoNCi0gKipHaeG6oyB0aHV54bq/dCBIMSoqOiBU4bu3IGzhu4cgbuG7ryDiiaAgMC41DQoNCkvhur90IHF14bqjIHRodSDEkcaw4bujYzogDQoNCi0gTuG6v3UgKipwLXZhbHVlIDwgMC4wNSoqIOKHkiAqKmLDoWMgYuG7jyBIMCoqIOKHkiB04bu3IGzhu4cgbuG7ryDiiaAgNTAlLCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqLg0KDQotIE7hur91ICoqcC12YWx1ZSDiiaUgMC4wNSoqIOKHkiAqKmtow7RuZyBiw6FjIGLhu48gSDAqKiwga2jDtG5nIMSR4bunIGLhurFuZyBjaOG7qW5nIMSR4buDIG7Ds2kgdOG7tyBs4buHIG7hu68ga2jDoWMgNTAlLg0KDQrihpIgVsOsICoqcC12YWx1ZSA9IDAuMDE4MiA8IDAuMDUqKiwgYsOhYyBi4buPIGdp4bqjIHRodXnhur90IEgwIOG7nyBt4bupYyDDvSBuZ2jEqWEgNSUuDQoNCkvhur90IHF14bqjIGtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IGNobyB0aOG6pXkgdOG7tyBs4buHIGtow6FjaCBow6BuZyBu4buvIHRyb25nIG3huqt1IGtow6FjIDUwJSB24bubaSDEkeG7mSB0aW4gY+G6rXkgOTUlIChwLXZhbHVlID0gMC4wMTgyIDwgMC4wNSkuIERvIMSRw7MsIGPDsyB0aOG7gyBr4bq/dCBsdeG6rW4gcuG6sW5nICoqdOG7tyBs4buHIGtow6FjaCBow6BuZyBu4buvIHRyb25nIHThu5VuZyB0aOG7gyBraMO0bmcgcGjhuqNpIGzDoCA1MCUsIG3DoCBsw6AgY2FvIGjGoW4gbeG7mXQgY2jDunQgKH41MSUpKiouDQoNClRyb25nIHRvw6BuIGLhu5kgZOG7ryBsaeG7h3Uga2jDoWNoIG11YSBow6BuZyB04bqhaSBzacOqdSB0aOG7iywgdOG7tyBs4buHIGtow6FjaCBow6BuZyBsw6AgbuG7ryBsw6Aga2hv4bqjbmcgNTElLiBL4bq/dCBxdeG6oyBraeG7g20gxJHhu4tuaCBjaG8gdGjhuqV5IGPDsyBi4bqxbmcgY2jhu6luZyB0aOG7kW5nIGvDqiByw7UgcsOgbmcgcuG6sW5nIHThu7cgbOG7hyBuw6B5IGtow6FjIDUwJSDigJQgdOG7qWMgbMOgIGtow7RuZyBob8OgbiB0b8OgbiBjw6JuIGLhurFuZyBnaeG7r2EgbmFtIHbDoCBu4buvLiBN4bq3YyBkw7kgY2jDqm5oIGzhu4djaCBjaOG7iSBraG/huqNuZyAxJSwgbmjGsG5nIHbDrCBk4buvIGxp4buHdSBs4bubbiwgc+G7sSBraMOhYyBiaeG7h3Qgbmjhu48gbsOgeSBjxaluZyBjw7Mgw70gbmdoxKlhLg0KDQoNCiMjIyAqKjMuMy4yIEjhuqFuZyBt4bulYyAiUyIgY+G7p2EgYmnhur9uIEdlbmRlcioqDQoNCiMjIyMgKirGr+G7m2MgbMaw4bujbmcgS2hv4bqjbmcgVGluIGPhuq15OioqDQoNClRhIG114buRbiDGsOG7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIMSR4buZYyB0aMOibiAoTWFyaXRhbFN0YXR1cyA9ICJTIikNCg0KYGBge3J9DQojIFPhu5EgbmfGsOG7nWkgxJHhu5ljIHRow6JuDQpuX3NpbmdsZSA8LSBzdW0oZGF0YSRNYXJpdGFsU3RhdHVzID09ICJTIikNCg0KIyDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIMSR4buZYyB0aMOibg0KcHJvcC50ZXN0KG5fc2luZ2xlLCBuX3RvdGFsLCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQotIFThu7cgbOG7hyAqKmtow6FjaCBow6BuZyDEkeG7mWMgdGjDom4gxrDhu5tjIGzGsOG7o25nKiogxJHGsOG7o2MgbMOgOiAqKjAuNTExNiBoYXkgNTEuMTYlKioNCg0KLSBLaG/huqNuZyB0aW4gY+G6rXkgOTUlIGNobyB04bu3IGzhu4cgbsOgeTogKipbNTAuMzMlLCA1MS45OSVdKioNCg0KLSAqKk5o4bqtbiB4w6l0Kio6IFRhIHRpbiB0xrDhu59uZyA5NSUgcuG6sW5nIHThu7cgbOG7hyBraMOhY2ggaMOgbmcgxJHhu5ljIHRow6JuIHRyb25nIHThu5VuZyB0aOG7gyBu4bqxbSB0cm9uZyBraG/huqNuZyB04burIDUwLjMzJSDEkeG6v24gNTEuOTklLiBN4bq3YyBkw7kga2hv4bqjbmcgbsOgeSBraMOhIGjhurlwIChjaMOqbmggbOG7h2NoIGNo4buJIH4xLjYlKSwgbsOzIGNobyB0aOG6pXkga2jDoWNoIMSR4buZYyB0aMOibiBjaGnhur9tIHThu4kgbOG7hyBuaOG7iW5oIGjGoW4gbeG7mXQgY2jDunQgc28gduG7m2kga2jDoWNoIMSRw6Mga+G6v3QgaMO0biBob+G6t2Mg4bufIHRy4bqhbmcgdGjDoWkga2jDoWMuDQoNCiMjIyMgKipLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dDoqKg0KDQpUYSDEkeG6t3QgYsOgaSB0b8OhbiBnaeG6oyB0aGnhur90Og0KDQotICoqR2nhuqMgdGh1eeG6v3QgSDAqKjogVOG7tyBs4buHIGtow6FjaCDEkeG7mWMgdGjDom4gPSA1MCUNCg0KLSAqKkdp4bqjIHRodXnhur90IEgxKio6IFThu7cgbOG7hyBraMOhY2ggxJHhu5ljIHRow6JuIOKJoCA1MCUNCg0KKipL4bq/dCBxdeG6oyoqIGdpw6EgdHLhu4sgKipwLXZhbHVlID0gMC4wMDU5NyA8IDAuMDUqKiDih5IgKipCw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3QgSDAqKiANCg0KQ8OzIGLhurFuZyBjaOG7qW5nIHRo4buRbmcga8OqIGNobyB0aOG6pXkgKip04bu3IGzhu4cga2jDoWNoIGjDoG5nIMSR4buZYyB0aMOibiBLSMOBQyA1MCUqKiwgVOG7tyBs4buHIHRo4buxYyB04bq/IGNhbyBoxqFuIG3hu5l0IGNow7p0ICh+NTEuMTYlKS4NCg0KDQojIyMgKiozLjMuMyBI4bqhbmcgbeG7pWMgIlVTQSIgY+G7p2EgYmnhur9uIENvdW50cnkqKg0KDQojIyMjICoqxq/hu5tjIGzGsOG7o25nIEtob+G6o25nIFRpbiBj4bqteToqKg0KDQpgYGB7cn0NCiMgU+G7kSBuZ8aw4budaSBz4buRbmcg4bufIFVTQQ0Kbl9VU0EgPC0gc3VtKGRhdGEkQ291bnRyeSA9PSAiVVNBIikNCg0KIyDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIHPhu5FuZyDhu58gVVNBDQpwcm9wLnRlc3Qobl9VU0EsIG5fdG90YWwsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KYGBgDQoNCg0KLSBU4bu3IGzhu4cgKipraMOhY2ggaMOgbmcgc+G7kW5nIHThuqFpIFVTQSoqIMaw4bubYyBsxrDhu6NuZyDEkcaw4bujYyBsw6A6ICoqMC42ODAxMzM3IGhheSA2OC4wMSUqKg0KDQotICoqS2hv4bqjbmcgdGluIGPhuq15IDk1JSoqIGNobyB04bu3IGzhu4cgbsOgeSBsw6A6ICoqWzY3LjIzJSwgNjguNzklXSoqDQoNCi0gKipOaOG6rW4geMOpdCoqOiBUYSBjw7MgdGjhu4MgdGluIHTGsOG7n25nIDk1JSBy4bqxbmcgdOG7tyBs4buHIGtow6FjaCBow6BuZyBz4buRbmcgdOG6oWkgSG9hIEvhu7MgKFVTQSkgdHJvbmcgdOG7lW5nIHRo4buDIGzDoCB04burIDY3LjIzJSDEkeG6v24gNjguNzklLiBU4bupYyBsw6AgZ+G6p24gNyB0cm9uZyAxMCBraMOhY2ggaMOgbmcgdHJvbmcgZOG7ryBsaeG7h3UgbMOgIG5nxrDhu51pIHPhu5FuZyB04bqhaSBN4bu5Lg0KDQoNCiMjIyMgKipLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dDoqKg0KDQpUYSDEkeG6t3QgYsOgaSB0b8OhbiBnaeG6oyB0aGnhur90Og0KDQotICoqR2nhuqMgdGh1eeG6v3QgSDAqKjogVOG7tyBs4buHIGtow6FjaCBow6BuZyBz4buRbmcg4bufIFVTQSA9IDUwJQ0KDQotICoqR2nhuqMgdGh1eeG6v3QgSDEqKjogVOG7tyBs4buHIGtow6FjaCBow6BuZyBz4buRbmcg4bufIFVTQSDiiaAgNTAlDQoNCioqS+G6v3QgcXXhuqMqKiBnacOhIHRy4buLICoqcC12YWx1ZSA8IDIuMmUtMTYqKiAocuG6pXQgbmjhu48sIGfhuqduIG5oxrAgYuG6sW5nIDApIOKHkiAqKkLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCBIMCoqIOG7nyBt4bupYyDDvSBuZ2jEqWEgNSUNCg0KQ8OzIGLhurFuZyBjaOG7qW5nIHRo4buRbmcga8OqIHLhuqV0IG3huqFuaCBjaG8gdGjhuqV5IHThu7cgbOG7hyBraMOhY2ggaMOgbmcgc+G7kW5nIOG7nyBN4bu5IEtIw4FDIDUwJSDigJQgdsOgIHRo4buxYyB04bq/IGzDoCBjYW8gaMahbiBy4bqldCBuaGnhu4F1ICg2OCUpLg0KDQotLS0NCg0KIyAqKlBo4bqnbiA0OiBQaMOibiB0w61jaCBN4buRaSBxdWFuIGjhu4cgZ2nhu69hIEhhaSBiaeG6v24gxJDhu4tuaCB0w61uaCAoQml2YXJpYXRlIEFuYWx5c2lzKSoqDQoNClRhIGNo4buNbiAzIGPhurdwIGJp4bq/biDEkeG7i25oIHTDrW5oIG5oxrAgc2F1Og0KDQotIEdlbmRlciB2w6AgSG9tZW93bmVyDQoNCi0gTWFyaXRhbFN0YXR1cyB2w6AgSG9tZW93bmVyDQoNCi0gQ291bnRyeSB2w6AgUHJvZHVjdEZhbWlseQ0KDQojIyAqKjQuMSBD4bq3cCBiaeG6v24gR2VuZGVyIHbDoCBIb21lb3duZXIqKg0KDQojIyMgKio0LjEuMSBC4bqjbmcgdOG6p24gc3XhuqV0IGNow6lvKioNCg0KVGEgdOG6oW8gYuG6o25nIHThuqduIHN14bqldCBjaMOpbyAoY29udGluZ2VuY3kgdGFibGUpIGNobyBoYWkgYmnhur9uIEdlbmRlciB2w6AgSG9tZW93bmVyIG5oxrAgc2F1Og0KDQpgYGB7cn0NCiMgQuG6o25nIHThuqduIHN14bqldCBjaMOpbw0KdGFibGVfZ2VuZGVyX2hvbWUgPC0gdGFibGUoZGF0YSRHZW5kZXIsIGRhdGEkSG9tZW93bmVyKQ0KdGFibGVfZ2VuZGVyX2hvbWUNCmBgYA0KDQpL4bq/dCBxdeG6oyBj4bunYSBi4bqjbmcgdOG6p24gc3XhuqV0IG7DoHkgY8OzIMO9IG5naMSpYSBuaMawIHNhdToNCg0KLSBDw7MgKioyODI2IG7hu68qKiBraMO0bmcgc+G7nyBo4buvdSBuaMOgLg0KDQotIEPDsyAqKjQzNDQgbuG7ryoqIHPhu58gaOG7r3UgbmjDoC4NCg0KLSBDw7MgKioyNzg5IG5hbSoqIGtow7RuZyBz4bufIGjhu691IG5ow6AuDQoNCi0gQ8OzICoqNDEwMCBuYW0qKiBz4bufIGjhu691IG5ow6AuDQoNCg0KYGBge3J9DQojIEhp4buDbiB0aOG7iyBi4bqjbmcgdOG6p24gc3XhuqV0IGNow6lvIHRoZW8gdOG7tyBs4buHIGjDoG5nDQpwcm9wLnRhYmxlKHRhYmxlX2dlbmRlcl9ob21lLCBtYXJnaW4gPSAxKQ0KYGBgDQoNCkzhu4duaCBgcHJvcC50YWJsZSguLi4sIG1hcmdpbiA9IDEpYCBjw7Mgw70gbmdoxKlhIG5oxrAgc2F1Og0KDQotIFTDrW5oIHThu7cgbOG7hyBwaOG6p24gdHLEg20gKHByb3BvcnRpb24pIHRoZW8gaMOgbmcgdHJvbmcgYuG6o25nIHRhYmxlX2dlbmRlcl9ob21lLg0KDQotIG1hcmdpbiA9IDE6IHThu7cgbOG7hyB0aGVvIHThu6tuZyBnaeG7m2kgdMOtbmggKEYgdsOgIE0pLg0KDQotIFThu5VuZyBt4buXaSBow6BuZyBz4bq9IGLhurFuZyAxLjAgKDEwMCUpLg0KDQpEaeG7hW4gZ2nhuqNpIGvhur90IHF14bqjOg0KDQotIFRyb25nIHPhu5EgKipu4buvKiogc+G6vSBjw7MgKip+MzkuNDElIGtow7RuZyBz4bufIGjhu691IG5ow6AqKiB2w6AgKip+NjAuNTklIHPhu58gaOG7r3UgbmjDoCoqLg0KDQotIFRyb25nIHPhu5EgKipuYW0qKiBz4bq9IGPDsyAqKn40MC40OCUga2jDtG5nIHPhu58gaOG7r3UgbmjDoCoqIHbDoCAqKn41OS41MiUgc+G7nyBo4buvdSBuaMOgKiouDQoNCg0KKipOaOG6rW4geMOpdCoqOiBE4buxYSB0csOqbiBr4bq/dCBxdeG6oyBi4bqjbmcgdOG6p24gc3XhuqV0IHbDoCB04bu3IGzhu4csIHRhIGPDsyB0aOG7gyByw7p0IHJhIG3hu5l0IHPhu5Egbmjhuq1uIMSR4buLbmggcuG6sW5nIHRyb25nICoqNzE3MCBu4buvIGdp4bubaSoqICgyODI2IGtow7RuZyBz4bufIGjhu691IG5ow6AgdsOgIDQzNDQgc+G7nyBo4buvdSBuaMOgKSwgdsOgICoqNjg4OSBuYW0gZ2nhu5tpKiogKDI3ODkga2jDtG5nIHPhu58gaOG7r3UgbmjDoCB2w6AgNDEwMCBz4bufIGjhu691IG5ow6ApLiBU4bu3IGzhu4cgc+G7nyBo4buvdSBuaMOgIGdp4buvYSBuYW0gdsOgIG7hu68ga2jDoSB0xrDGoW5nIMSR4buTbmcsIG5oxrBuZyAqKm7hu68gY8OzIHh1IGjGsOG7m25nIHPhu58gaOG7r3UgbmjDoCBjYW8gaMahbiBt4buZdCBjaMO6dCoqICg2MC41OSUgc28gduG7m2kgNTkuNTIlKS4NCg0KDQojIyMgKio0LjEuMiBUcuG7sWMgcXVhbiBow7NhKioNCg0KVGEgdHLhu7FjIHF1YW4gaMOzYSBi4bqjbmcgdOG6p24gc3XhuqV0IHRow6BuaCBiaeG7g3UgxJHhu5MgY+G7mXQgY2jhu5NuZyBuaMawIHNhdToNCg0KYGBge3J9DQojIFRy4buxYyBxdWFuIGjDs2EgYuG6sW5nIGJp4buDdSDEkeG7kyBj4buZdCBjaOG7k25nDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBHZW5kZXIsIGZpbGwgPSBIb21lb3duZXIpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArDQogIGxhYnModGl0bGUgPSAiVOG7tyBs4buHIHPhu58gaOG7r3UgbmjDoCB0aGVvIGdp4bubaSB0w61uaCIsIHkgPSAiVOG7tyBs4buHIiwgeCA9ICJHaeG7m2kgdMOtbmgiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHThu7cgbOG7hyBz4bufIGjhu691IG5ow6AgdGhlbyBnaeG7m2kgdMOtbmggY2hvIHRo4bqleSBz4buxIHBow6JuIGLhu5EgdMawxqFuZyDEkeG7kWkgxJHhu5NuZyDEkeG7gXUgZ2nhu69hIG5hbSB2w6AgbuG7ry4gQ+G7pSB0aOG7gywgY+G6oyBoYWkgZ2nhu5tpIMSR4buBdSBjw7Mga2hv4bqjbmcgNjAlIG5nxrDhu51pIHPhu58gaOG7r3UgbmjDoCB2w6Aga2hv4bqjbmcgNDAlIGtow7RuZyBz4bufIGjhu691IG5ow6AuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IHLhurFuZyBnaeG7m2kgdMOtbmgga2jDtG5nIHBo4bqjaSBsw6AgbeG7mXQgeeG6v3UgdOG7kSDhuqNuaCBoxrDhu59uZyByw7UgcuG7h3QgxJHhur9uIGto4bqjIG7Eg25nIHPhu58gaOG7r3UgbmjDoCB0cm9uZyB04bqtcCBk4buvIGxp4buHdSBuw6B5LiBN4bq3YyBkw7kgdOG7tyBs4buHIHBo4bulIG7hu68gc+G7nyBo4buvdSBuaMOgIGPDsyBwaOG6p24gbmjhu4luaCBoxqFuIHNvIHbhu5tpIG5hbSBnaeG7m2ksIG5oxrBuZyBt4bupYyBjaMOqbmggbOG7h2NoIGzDoCBy4bqldCBuaOG7jyB2w6Aga2jDtG5nIHRo4buDIGhp4buHbiBt4buZdCB4dSBoxrDhu5tuZyByw7UgcsOgbmcuDQoNCg0KIyMjICoqNC4xLjMgS2nhu4NtIMSR4buLbmggVGjhu5FuZyBrw6ogLSBLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcqKg0KDQpUYSB0aOG7sWMgaGnhu4duIGtp4buDbSDEkeG7i25oIENoaS1zcXVhcmVkIG5oxrAgc2F1Og0KDQpgYGB7cn0NCmNoaXNxLnRlc3QodGFibGVfZ2VuZGVyX2hvbWUpDQpgYGANCg0KKipHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaDoqKg0KDQotICoqR2nhuqMgdGh1eeG6v3Qga2jDtG5nIEgwKio6IEhhaSBiaeG6v24gR2VuZGVyIHbDoCBIb21lb3duZXIgbMOgICoqxJHhu5ljIGzhuq1wKiogduG7m2kgbmhhdSAodOG7qWMgZ2nhu5tpIHTDrW5oIGtow7RuZyDhuqNuaCBoxrDhu59uZyDEkeG6v24ga2jhuqMgbsSDbmcgc+G7nyBo4buvdSBuaMOgKS4NCg0KLSAqKkdp4bqjIHRodXnhur90IMSR4buRaSBIMSoqOiBIYWkgYmnhur9uICoqY8OzIG3hu5FpIGxpw6puIGjhu4cqKiB24bubaSBuaGF1ICh04bupYyBnaeG7m2kgdMOtbmggY8OzIOG6o25oIGjGsOG7n25nIMSR4bq/biBraOG6oyBuxINuZyBz4bufIGjhu691IG5ow6ApLg0KDQoqKkvhur90IHF14bqjIGtp4buDbSDEkeG7i25oKiogQ2hpLWLDrG5oIHBoxrDGoW5nOg0KDQotIEdpw6EgdHLhu4sgQ2hpLXNxdWFyZWQgKiooWMKyKTogMS42MzQ0KioNCg0KLSBC4bqtYyB04buxIGRvICoqZGY6IDEqKg0KDQotIEdpw6EgdHLhu4sgKipwLXZhbHVlOiAwLjIwMTEqKg0KDQoqKkvhur90IGx14bqtbiB0aOG7kW5nIGvDqjoqKiBWw6wgKipwID0gMC4yMDExID4gMC4wNSoqLCB0YSBjaOG6pXAgbmjhuq1uIGdp4bqjIHRodXnhur90IGtow7RuZy4gxJBp4buBdSBuw6B5IGPDsyBuZ2jEqWEgbMOgICoqa2jDtG5nIGPDsyBi4bqxbmcgY2jhu6luZyB0aOG7kW5nIGvDqiDEkeG7pyBt4bqhbmgqKiDEkeG7gyBr4bq/dCBsdeG6rW4gcuG6sW5nICoqdOG7k24gdOG6oWkgbeG7kWkgbGnDqm4gaOG7hyBnaeG7r2EgZ2nhu5tpIHTDrW5oIHbDoCB0w6xuaCB0cuG6oW5nIHPhu58gaOG7r3UgbmjDoCoqLg0KDQoqKlRo4bqjbyBsdeG6rW4gdGjDqm06KiogS+G6v3QgcXXhuqMga2nhu4NtIMSR4buLbmggdGjhu5FuZyBrw6ogcGjDuSBo4bujcCB24bubaSBuaOG7r25nIGfDrCBiaeG7g3UgxJHhu5MgdHLhu7FjIHF1YW4gY2hvIHRo4bqleTogdOG7tyBs4buHIHPhu58gaOG7r3UgbmjDoCBnaeG7r2EgbmFtIHbDoCBu4buvIGtow6EgdMawxqFuZyDEkeG7k25nIChraG/huqNuZyA2MCUg4bufIGPhuqMgaGFpIGdp4bubaSkuIE3hurdjIGTDuSBwaOG7pSBu4buvIGPDsyB24bq7IG5o4buJbmggaMahbiBt4buZdCBjaMO6dCB24buBIHThu7cgbOG7hyBz4bufIGjhu691IG5ow6AsIG5oxrBuZyBz4buxIGtow6FjIGJp4buHdCDEkcOzIGzDoCBuaOG7jyB2w6Aga2jDtG5nIG1hbmcgw70gbmdoxKlhIHRo4buRbmcga8OqLg0KDQoNCiMjICoqNC4yIEPhurdwIGJp4bq/biBNYXJpdGFsU3RhdHVzIHbDoCBIb21lb3duZXIqKg0KDQojIyMgKio0LjIuMSBC4bqjbmcgdOG6p24gc3XhuqV0IGNow6lvKioNCg0KQ+G6t3AgYmnhur9uIHRp4bq/cCB0aGVvIGzDoCBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gdsOgIFPhu58gaOG7r3UgbmjDoCwgbGnhu4d1IGPDsyBiYW8gbmhpw6p1IG5nxrDhu51pIMSR4buZYyB0aMOibiBz4bufIGjhu691IG5ow6AgdsOgIGJhbyBuaGnDqnUgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIHPhu58gaOG7r3UgbmjDoD8NCg0KVGEgeGVtIGvhur90IHF14bqjIGLhuqNuZyB04bqnbiBzdeG6pXQgY2jDqW8gbmjGsCBzYXU6DQoNCmBgYHtyfQ0KIyBC4bqjbmcgdOG6p24gc3XhuqV0IGNow6lvDQp0YWJsZV9tYXJpdGFsX2hvbWUgPC0gdGFibGUoZGF0YSRNYXJpdGFsU3RhdHVzLCBkYXRhJEhvbWVvd25lcikNCnRhYmxlX21hcml0YWxfaG9tZQ0KYGBgDQoNCkvhur90IHF14bqjIGPhu6dhIGLhuqNuZyB04bqnbiBzdeG6pXQgbsOgeSBjw7Mgw70gbmdoxKlhIG5oxrAgc2F1Og0KDQotIEPDsyAqKjE3MTkgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuKioga2jDtG5nIHPhu58gaOG7r3UgbmjDoC4NCg0KLSBDw7MgKio1MTQ3IG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0bioqIHPhu58gaOG7r3UgbmjDoC4NCg0KLSBDw7MgKiozODk2IG5nxrDhu51pIMSR4buZYyB0aMOibioqIGtow7RuZyBz4bufIGjhu691IG5ow6AuDQoNCi0gQ8OzICoqMzI5NyBuZ8aw4budaSDEkeG7mWMgdGjDom4qKiBz4bufIGjhu691IG5ow6AuDQoNCg0KYGBge3J9DQojIEhp4buDbiB0aOG7iyBi4bqjbmcgdOG6p24gc3XhuqV0IGNow6lvIHRoZW8gdOG7tyBs4buHIGjDoG5nDQpwcm9wLnRhYmxlKHRhYmxlX21hcml0YWxfaG9tZSwgbWFyZ2luID0gMSkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqIFBow6JuIHTDrWNoIGLhuqNuZyB04bqnbiBzdeG6pXQgY2hvIHRo4bqleSBjw7Mgc+G7sSBraMOhYyBiaeG7h3QgcsO1IHLhu4d0IHRyb25nIHZp4buHYyBz4bufIGjhu691IG5ow6AgZ2nhu69hIG5o4buvbmcgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIHbDoCBuZ8aw4budaSDEkeG7mWMgdGjDom4uIEPhu6UgdGjhu4MsIHRyb25nIHThu5VuZyBz4buRICoqNjg2NiBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4sIGPDsyDEkeG6v24gNTE0NyBuZ8aw4budaSoqICh0xrDGoW5nIMSRxrDGoW5nIDc1JSkgc+G7nyBo4buvdSBuaMOgLCB0cm9uZyBraGkgKipjaOG7iSAxNzE5IG5nxrDhu51pIChraG/huqNuZyAyNSUpIGtow7RuZyBz4bufIGjhu691IG5ow6AqKi4gTmfGsOG7o2MgbOG6oWksIHRyb25nIG5ow7NtIDcxOTMgbmfGsOG7nWkgxJHhu5ljIHRow6JuLCB04bu3IGzhu4cgc+G7nyBo4buvdSBuaMOgIGNo4buJIGzDoCA0NS44JSAoMzI5NyBuZ8aw4budaSksIGPDsm4gbOG6oWkgNTQuMiUgKDM4OTYgbmfGsOG7nWkpIGtow7RuZyBz4bufIGjhu691IG5ow6AuIA0KDQpOaOG7r25nIGNvbiBz4buRIG7DoHkgY2hvIHRo4bqleSBy4bqxbmcgKipuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gY8OzIGto4bqjIG7Eg25nIHPhu58gaOG7r3UgbmjDoCBjYW8gaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBuZ8aw4budaSDEkeG7mWMgdGjDom4qKi4gxJBp4buBdSBuw6B5IGPDsyB0aOG7gyBwaOG6o24gw6FuaCBz4buxIOG7lW4gxJHhu4tuaCB24buBIG3hurd0IHTDoGkgY2jDrW5oLCBz4buxIGNoaWEgc+G6uyBjaGkgcGjDrSBzaW5oIGhv4bqhdCBob+G6t2Mga2jhuqMgbsSDbmcgdGnhur9wIGPhuq1uIHTDrW4gZOG7pW5nIHThu5F0IGjGoW4g4bufIG5o4buvbmcgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuLiBU4burIMSRw7MsIGPDsyB0aOG7gyBixrDhu5tjIMSR4bqndSBuaOG6rW4gxJHhu4tuaCBy4bqxbmcgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIGPDsyBsacOqbiBxdWFuIMSR4bq/biBraOG6oyBuxINuZyBz4bufIGjhu691IG5ow6AgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UgbsOgeS4gDQoNCiMjIyAqKjQuMi4yIFRy4buxYyBxdWFuIGjDs2EqKg0KDQpgYGB7cn0NCiMgVHLhu7FjIHF1YW4gaMOzYQ0KZGF0YV9zdW1tYXJ5IDwtIGRhdGEgJT4lIGdyb3VwX2J5KE1hcml0YWxTdGF0dXMsIEhvbWVvd25lcikgJT4lIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIHVuZ3JvdXAoKQ0KDQpnZ3Bsb3QoZGF0YV9zdW1tYXJ5LCBhZXMoeCA9IE1hcml0YWxTdGF0dXMsIHkgPSBjb3VudCwgZmlsbCA9IEhvbWVvd25lcikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBjb3VudCksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCB2anVzdCA9IC0wLjUpICsNCiAgbGFicyh0aXRsZSA9ICJT4buRIGzGsOG7o25nIHPhu58gaOG7r3UgbmjDoCB0aGVvIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiIsIHkgPSAiU+G7kSBsxrDhu6NuZyIsIHggPSAiVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIikNCmBgYA0KDQpHaeG6o2kgdGjDrWNoIGPDonUgbOG7h25oOg0KDQotIGBncm91cF9ieShNYXJpdGFsU3RhdHVzLCBIb21lb3duZXIpYDogTmjDs20gZOG7ryBsaeG7h3UgdGhlbyB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gdsOgIHTDrG5oIHRy4bqhbmcgc+G7nyBo4buvdSBuaMOgLiBN4buXaSB04buVIGjhu6NwICh2w60gZOG7pTogxJDhu5ljIHRow6JuICsgQ8OzIG5ow6AsIEvhur90IGjDtG4gKyBLaMO0bmcgbmjDoCkgc+G6vSB0aMOgbmggMSBuaMOzbS4NCg0KLSBgc3VtbWFyaXNlKGNvdW50ID0gbigpKWA6IFTDrW5oIHPhu5EgbMaw4bujbmcgYuG6o24gZ2hpIHRyb25nIG3hu5dpIG5ow7NtIHbDoCDEkeG6t3QgdMOqbiBj4buZdCBsw6AgY291bnQuDQoNCi0gYHVuZ3JvdXAoKWA6IELhu48gZ3JvdXBpbmcgxJHhu4Mga+G6v3QgcXXhuqMga2jDtG5nIGPDsm4gcsOgbmcgYnXhu5ljIGLhu59pIGPDoWMgbmjDs20gbuG7r2EgKHRyw6FuaCBs4buXaSBraGkgeOG7rSBsw70gdGnhur9wIHNhdSBuw6B5KS4NCg0KLSBL4bq/dCBxdeG6oyBsw6AgbeG7mXQgYuG6o25nIHTDs20gdOG6r3QgYChkYXRhX3N1bW1hcnkpYCBn4buTbSAzIGPhu5l0OiBNYXJpdGFsU3RhdHVzLCBIb21lb3duZXIsIHbDoCBjb3VudC4NCg0KLSBgZ2dwbG90KGRhdGFfc3VtbWFyeSwgYWVzKC4uLikpYDogVOG6oW8gYmnhu4N1IMSR4buTIHThu6sgYuG6o25nIGRhdGFfc3VtbWFyeSwgdHJvbmcgxJHDszoNCg0KICAgLSBgeCA9IE1hcml0YWxTdGF0dXNgOiB0cuG7pWMgaG/DoG5oIGzDoCB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gKE0sIFMpLg0KDQogICAtIGB5ID0gY291bnRgOiBjaGnhu4F1IGNhbyBj4buZdCBsw6Agc+G7kSBsxrDhu6NuZy4NCg0KICAgLSBgZmlsbCA9IEhvbWVvd25lcmA6IG3DoHUgc+G6r2MgY+G7mXQgdGhheSDEkeG7lWkgdGhlbyB0w6xuaCB0cuG6oW5nIHPhu58gaOG7r3UgbmjDoCAoWSwgTikuDQoNCi0gYGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSlgOiBW4bq9IGJp4buDdSDEkeG7kyBj4buZdCAoY29sdW1uIGNoYXJ0KSB24bubaSBjw6FjIGPhu5l0IMSR4bq3dCBj4bqhbmggbmhhdSAodGhheSB2w6wgY2jhu5NuZyBsw6puIG5oYXUpIHRoZW8gdOG7q25nIG5ow7NtIEhvbWVvd25lci4NCg0KLSBgZ2VvbV90ZXh0KC4uLilgOiBUaMOqbSBuaMOjbiBz4buRIGzGsOG7o25nIHRyw6puIG3hu5dpIGPhu5l0Og0KDQogICAtIGBsYWJlbCA9IGNvdW50YDogaGnhu4duIHPhu5EgbMaw4bujbmcuDQoNCiAgIC0gYHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KWA6IGPEg24gY2jhu4luaCB24buLIHRyw60gY2jhu68gdHLDuW5nIGto4bubcCB24bubaSB24buLIHRyw60gY8OhYyBj4buZdC4NCg0KICAgLSBgdmp1c3QgPSAtMC41YDogZOG7i2NoIGNo4buvIGzDqm4gcGjDrWEgdHLDqm4gbeG7mXQgY2jDunQuDQoNCi0gYGxhYnMoLi4uKWA6IMSQ4bq3dCB0acOqdSDEkeG7gSB2w6AgdMOqbiB0cuG7pWM6DQoNCiAgIC0gYHRpdGxlYDogdGnDqnUgxJHhu4EgYmnhu4N1IMSR4buTLg0KICAgDQogICAtIGB4YDogdMOqbiB0cuG7pWMgaG/DoG5oIGzDoCAiVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIi4NCg0KICAgLSBgeWA6IHTDqm4gdHLhu6VjIHR1bmcgbMOgICJT4buRIGzGsOG7o25nIi4NCg0KDQoqKk5o4bqtbiB4w6l0OioqIEJp4buDdSDEkeG7kyBjaG8gdGjhuqV5IG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biBjw7MgeHUgaMaw4bubbmcgc+G7nyBo4buvdSBuaMOgIGNhbyBoxqFuIHNvIHbhu5tpIG5nxrDhu51pIMSR4buZYyB0aMOibi4gQ+G7pSB0aOG7gywgc+G7kSBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gc+G7nyBo4buvdSBuaMOgIGzDoCA1LjE0NywgZ+G6p24gZ+G6pXAgYmEgbOG6p24gc28gduG7m2kgbmjDs20ga2jDtG5nIHPhu58gaOG7r3UgbmjDoC4gTmfGsOG7o2MgbOG6oWksIHRyb25nIG5ow7NtIMSR4buZYyB0aMOibiwgc+G7kSBuZ8aw4budaSBraMO0bmcgc+G7nyBo4buvdSBuaMOgICgzLjg5NikgbOG6oWkgY2FvIGjGoW4gc28gduG7m2kgbmfGsOG7nWkgY8OzIG5ow6AgKDMuMjk3KS4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIGPDsyDhuqNuaCBoxrDhu59uZyByw7UgcuG7h3QgxJHhur9uIGto4bqjIG7Eg25nIHPhu58gaOG7r3UgbmjDoCwgY8OzIHRo4buDIGRvIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biB0aMaw4budbmcgY8OzIHTDoGkgY2jDrW5oIOG7lW4gxJHhu4tuaCBoxqFuIHbDoCBuaHUgY+G6p3UgbXVhIG5ow6AgxJHhu4Mg4buVbiDEkeG7i25oIGN14buZYyBz4buRbmcgZ2lhIMSRw6xuaC4NCg0KDQojIyMgKio0LjIuMyBLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcqKg0KDQpUYSB0aOG7sWMgaGnhu4duIGtp4buDbSDEkeG7i25oIENoaS1zcXVhcmVkIG5oxrAgc2F1Og0KDQpgYGB7cn0NCmNoaXNxLnRlc3QodGFibGVfbWFyaXRhbF9ob21lKQ0KYGBgDQoNCioqR2nhuqMgdGh1eeG6v3Qga2nhu4NtIMSR4buLbmg6KioNCg0KLSAqKkdp4bqjIHRodXnhur90IGtow7RuZyBIMCoqOiBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gdsOgIHF1eeG7gW4gc+G7nyBo4buvdSBuaMOgIGzDoCAqKsSR4buZYyBs4bqtcCoqIChraMO0bmcgbGnDqm4gcXVhbiDEkeG6v24gbmhhdSkuDQoNCi0gKipHaeG6oyB0aHV54bq/dCDEkeG7kWkgSDEqKjogVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIHbDoCBxdXnhu4FuIHPhu58gaOG7r3UgbmjDoCAqKmPDsyBt4buRaSBsacOqbiBo4buHKiogKGtow7RuZyDEkeG7mWMgbOG6rXApLg0KDQoqKkvhur90IHF14bqjIGtp4buDbSDEkeG7i25oKiogQ2hpLWLDrG5oIHBoxrDGoW5nOg0KDQotIEdpw6EgdHLhu4sgQ2hpLXNxdWFyZWQgKiooWMKyKTogMTI0MS4yKioNCg0KLSBC4bqtYyB04buxIGRvICoqZGY6IDEqKg0KDQotIEdpw6EgdHLhu4sgKipwLXZhbHVlOiA8IDIuMmUtMTYqKg0KDQoqKkvhur90IGx14bqtbiB0aOG7kW5nIGvDqjoqKiBWw6wgZ2nDoSB0cuG7iyAqKnAgY+G7sWMga+G7syBuaOG7jyAocCA8IDIuMmUtMTYpKiosIHLhuqV0IG5o4buPIGjGoW4gbmhp4buBdSBzbyB24bubaSAwLjA1LCB0YSBiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3Qga2jDtG5nLiBL4bq/dCBxdeG6oyBraeG7g20gxJHhu4tuaCBjaG8gdGjhuqV5IHLhurFuZyAqKmPDsyBt4buRaSBsacOqbiBo4buHIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogbeG6oW5oIG3hur0gZ2nhu69hIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiB2w6Agdmnhu4djIHPhu58gaOG7r3UgbmjDoCoqLiBOw7NpIGPDoWNoIGtow6FjLCBraOG6oyBuxINuZyBt4buZdCBuZ8aw4budaSBz4bufIGjhu691IG5ow6AgY8OzIGxpw6puIHF1YW4gY2jhurd0IGNo4bq9IMSR4bq/biB2aeG7h2MgaOG7jSBjw7MgxJFhbmcga+G6v3QgaMO0biBoYXkga2jDtG5nLg0KDQoqKlRo4bqjbyBsdeG6rW4gdGjDqm06KiogVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIGtow7RuZyBjaOG7iSBsw6AgbeG7mXQgxJHhurdjIMSRaeG7g20geMOjIGjhu5lpLCBtw6AgY8OybiBjw7Mg4bqjbmggaMaw4bufbmcgcsO1IHLDoG5nIMSR4bq/biBr4bq/dCBxdeG6oyBraW5oIHThur8sIGPhu6UgdGjhu4MgbMOgIGto4bqjIG7Eg25nIHPhu58gaOG7r3UgbmjDoC4gU+G7sSBraMOhYyBiaeG7h3QgbOG7m24gduG7gSB04bu3IGzhu4cgdsOgIGvhur90IHF14bqjIGtp4buDbSDEkeG7i25oIHRo4buRbmcga8OqIGPDuW5nIGNo4buJIHJhIHLhurFuZyBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gY8OzIG5oaeG7gXUga2jhuqMgbsSDbmcgc+G7nyBo4buvdSBuaMOgIGjGoW4gbmfGsOG7nWkgxJHhu5ljIHRow6JuLCBjw7MgdGjhu4MgZG8geeG6v3UgdOG7kSB0aHUgbmjhuq1wIGvDqXAsIOG7lW4gxJHhu4tuaCB0w6BpIGNow61uaCwgaG/hurdjIGvhur8gaG/huqFjaCBjdeG7mWMgc+G7kW5nIGTDoGkgaOG6oW4gaMahbi4NCg0KDQojIyAqKjQuMyBD4bq3cCBiaeG6v24gQ291bnRyeSB2w6AgUHJvZHVjdEZhbWlseSoqDQoNCiMjIyAqKjQuMy4xIELhuqNuZyB04bqnbiBzdeG6pXQgY2jDqW8qKg0KDQpD4bq3cCBiaeG6v24gY3Xhu5FpIGPDuW5nIGzDoCBj4bq3cCBiaeG6v24gUXXhu5FjIGdpYSB2w6AgTmjDs20gc+G6o24gcGjhuqltIGNow61uaA0KDQpgYGB7cn0NCiMgQuG6o25nIHThuqduIHN14bqldCBjaMOpbw0KdGFibGVfY291bnRyeV9wcm9kdWN0IDwtIHRhYmxlKGRhdGEkQ291bnRyeSwgZGF0YSRQcm9kdWN0RmFtaWx5KQ0KdGFibGVfY291bnRyeV9wcm9kdWN0DQpgYGANCioqTmjhuq1uIHjDqXQ6KioNCg0KLSAqKk3hu7kgbMOgIHF14buRYyBnaWEgY8OzIHPhu5EgbMaw4bujbmcgY2FvIG5o4bqldCoqIOG7nyB04bqldCBj4bqjIGPDoWMgbmjDs20gc+G6o24gcGjhuqltLCDEkeG6t2MgYmnhu4d0IGzDoCBuaMOzbSBGb29kICg2ODkwKS4NCg0KLSAqKk1leGljbyDEkeG7qW5nIHRo4bupIGhhaSoqLCB24bubaSBGb29kIGzDoCBuaMOzbSBjaGnhur9tIG5oaeG7gXUgbmjhuqV0Lg0KDQotICoqQ2FuYWRhIGPDsyBz4buRIGzGsOG7o25nIHRo4bqlcCBuaOG6pXQqKiDhu58gdOG6pXQgY+G6oyBjw6FjIG5ow7NtLCDEkeG6t2MgYmnhu4d0IERyaW5rIGNo4buJIGPDsyA2OS4NCg0KDQpgYGB7cn0NCiMgSGnhu4NuIHRo4buLIGLhuqNuZyB04bqnbiBzdeG6pXQgY2jDqW8gdGhlbyB04bu3IGzhu4cgaMOgbmcNCnByb3AudGFibGUodGFibGVfY291bnRyeV9wcm9kdWN0LCBtYXJnaW4gPSAxKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KiogRMO5IHPhu5EgbMaw4bujbmcgdHV54buHdCDEkeG7kWkga2jDoWMgbmhhdSwgdOG7tyBs4buHIHBow6JuIGLhu5Ugc+G6o24gcGjhuqltIHRoZW8gdOG7q25nIHF14buRYyBnaWEgbOG6oWkga2jDoSBnaeG7kW5nIG5oYXUuDQoNCi0gQ+G6oyBiYSBxdeG7kWMgZ2lhIMSR4buBdSBjw7M6DQoNCiAgIC0gKipUcsOqbiA3MCUgc+G6o24gcGjhuqltIGzDoCBGb29kKiogKGNoaeG6v20gdOG7tyBs4buHIGNhbyBuaOG6pXQpLg0KDQogICAtICoqRHJpbmsgdsOgIE5vbi1Db25zdW1hYmxlIGNoaeG6v20gdOG7tyBs4buHIHRo4bqlcCoqIHbDoCBn4bqnbiAqKnTGsMahbmcgxJHGsMahbmcgbmhhdSoqLg0KDQotIENhbmFkYSBjw7MgdOG7tyBs4buHIHPhuqNuIHBo4bqpbSBOb24tQ29uc3VtYWJsZSBjYW8gaMahbiBt4buZdCBjaMO6dCAoMTkuOCUpIHNvIHbhu5tpIE1leGljbyB2w6AgVVNBLg0KDQotIFVTQSBjw7MgdOG7tyBs4buHIHPhuqNuIHBo4bqpbSBEcmluayBjYW8gbmjhuqV0ICg4Ljk1JSksIG5oxrBuZyBjaMOqbmggbOG7h2NoIGzDoCBraMO0bmcgxJHDoW5nIGvhu4MuDQoNCiMjIyAqKjQuMy4yIFRy4buxYyBxdWFuIGjDs2EqKg0KDQpgYGB7cn0NCiMgVHLhu7FjIHF1YW4gaMOzYQ0KZGF0YV9zdW1tYXJ5MiA8LSBkYXRhICU+JSBncm91cF9ieShDb3VudHJ5LCBQcm9kdWN0RmFtaWx5KSAlPiUgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgbXV0YXRlKHRvdGFsID0gc3VtKGNvdW50KSwgcGN0ID0gY291bnQgLyB0b3RhbCkgJT4lIHVuZ3JvdXAoKQ0KDQpnZ3Bsb3QoZGF0YV9zdW1tYXJ5MiwgYWVzKHggPSBDb3VudHJ5LCB5ID0gcGN0LCBmaWxsID0gUHJvZHVjdEZhbWlseSkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQocGN0LCBhY2N1cmFjeSA9IDAuMSkpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSkgKw0KICBsYWJzKHRpdGxlID0gIlThu7cgbOG7hyBuaMOzbSBz4bqjbiBwaOG6qW0gdGhlbyBxdeG7kWMgZ2lhIiwNCiAgICAgICB5ID0gIlThu7cgbOG7hyIsDQogICAgICAgeCA9ICJRdeG7kWMgZ2lhIikNCmBgYA0KDQpHaeG6o2kgdGjDrWNoIGPDonUgbOG7h25oOg0KDQotIGBncm91cF9ieShDb3VudHJ5LCBQcm9kdWN0RmFtaWx5KWA6IE5ow7NtIGThu68gbGnhu4d1IHRoZW8gUXXhu5FjIGdpYSB2w6AgTmjDs20gc+G6o24gcGjhuqltDQoNCi0gYHN1bW1hcmlzZShjb3VudCA9IG4oKSlgOiBUw61uaCBz4buRIGzGsOG7o25nIHThu6tuZyBuaMOzbSAoY291bnQpDQoNCi0gYG11dGF0ZSh0b3RhbCA9IHN1bShjb3VudClgOiBUw61uaCB04buVbmcgc+G7kSBz4bqjbiBwaOG6qW0gdGhlbyBt4buXaSBRdeG7kWMgZ2lhDQoNCi0gYHBjdCA9IGNvdW50IC8gdG90YWwpYDogVMOtbmggdOG7tyBs4buHIHBo4bqnbiB0csSDbSBjaG8gdOG7q25nIG5ow7NtDQoNCi0gYHVuZ3JvdXAoKWA6IELhu48gbmjDs20gxJHhu4MgdHLDoW5oIOG6o25oIGjGsOG7n25nIGtoaSB24bq9IGJp4buDdSDEkeG7kw0KDQotIGBnZ3Bsb3QoKWA6IHbhur0gYmnhu4N1IMSR4buTIGPhu5l0IHRoZW8gdOG7tyBs4buHIHF14buRYyBnaWENCg0KLSBgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKWA6IFbhur0gY8OhYyBj4buZdCB24bubaSBjw6FjIG5ow7NtIChQcm9kdWN0RmFtaWx5KSDEkeG6t3QgY+G6oW5oIG5oYXUgdGhheSB2w6wgY2jhu5NuZyBsw6puIG5oYXUuDQoNCi0gYGdlb21fdGV4dChhZXMobGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQocGN0LCBhY2N1cmFjeSA9IDAuMSkpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMylgDQoNCiAgIC0gR8OhbiBuaMOjbiB2xINuIGLhuqNuIGzDoCBwaOG6p24gdHLEg20sIHbDrSBk4bulICI3Mi4xJSIgdGhheSB2w6wgc+G7kSB0aOG6rXAgcGjDom4uDQoNCiAgIC0gYGFjY3VyYWN5ID0gMC4xYCDihpIgaGnhu4NuIHRo4buLIGNow61uaCB4w6FjIMSR4bq/biAxIGNo4buvIHPhu5EgdGjhuq1wIHBow6JuLg0KDQogICAtIGB2anVzdCA9IC0wLjNgIOKGkiBjxINuIHbhu4sgdHLDrSBuaMOjbiBu4bqxbSBwaMOtYSB0csOqbiDEkeG6p3UgY+G7mXQuDQoNCiAgIC0gYHNpemUgPSAzYCDihpIgY2jhu4luaCBrw61jaCBj4buhIGNo4buvLg0KICAgDQotIGBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpKWA6IEJp4bq/biB0cuG7pWMgeSB0aMOgbmggxJHhu4tuaCBk4bqhbmcgcGjhuqduIHRyxINtDQoNCioqTmjhuq1uIHjDqXQ6KiogTmjDs20gc+G6o24gcGjhuqltICJGb29kIiBjaGnhur9tIHThu7cgbOG7hyBjYW8gbmjhuqV0IOG7nyBj4bqjIDMgcXXhu5FjIGdpYSwgJSB04bu3IGzhu4cgbMOgIGNhbyBoxqFuIGjhurNuIDIgbmjDs20gY8OybiBs4bqhaS4iRHJpbmsiIHbDoCAiTm9uLUNvbnN1bWFibGUiIGPDsyB04bu3IGzhu4cgdGjhuqVwIGjGoW4gdsOgIGtow6EgdMawxqFuZyDEkeG7k25nIGdp4buvYSBjw6FjIHF14buRYyBnaWEuIEJp4buDdSDEkeG7kyBjaG8gdGjhuqV5IGPGoSBj4bqldSBuaMOzbSBz4bqjbiBwaOG6qW0gZ+G6p24gbmjGsCBraMO0bmcgdGhheSDEkeG7lWkgdGhlbyBxdeG7kWMgZ2lhLCBjaG8gdGjhuqV5IHTDrW5oIMSR4buTbmcgbmjhuqV0IHRyb25nIGRhbmggbeG7pWMgc+G6o24gcGjhuqltIGhv4bq3YyBow6BuaCB2aSB0acOqdSBkw7luZyDhu58gY8OhYyB0aOG7iyB0csaw4budbmcgbsOgeS4NCg0KDQojIyMgKio0LjMuMyBLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcqKg0KDQpUYSB0aOG7sWMgaGnhu4duIGtp4buDbSDEkeG7i25oIENoaS1zcXVhcmVkIG5oxrAgc2F1Og0KDQpgYGB7cn0NCmNoaXNxLnRlc3QodGFibGVfY291bnRyeV9wcm9kdWN0KQ0KYGBgDQoNCioqR2nhuqMgdGh1eeG6v3Qga2nhu4NtIMSR4buLbmg6KioNCg0KLSAqKkdp4bqjIHRodXnhur90IGtow7RuZyBIMCoqOiAyIGJp4bq/biBRdeG7kWMgZ2lhIHbDoCBOaMOzbSBz4bqjbiBwaOG6qW0gY2jDrW5oIGzDoCAqKsSR4buZYyBs4bqtcCoqIChraMO0bmcgbGnDqm4gcXVhbiDEkeG6v24gbmhhdSkuDQoNCi0gKipHaeG6oyB0aHV54bq/dCDEkeG7kWkgSDEqKjogMiBiaeG6v24gUXXhu5FjIGdpYSB2w6AgTmjDs20gc+G6o24gcGjhuqltIGNow61uaCAqKmPDsyBt4buRaSBsacOqbiBo4buHKiogKGtow7RuZyDEkeG7mWMgbOG6rXApLg0KDQoqKkvhur90IHF14bqjIGtp4buDbSDEkeG7i25oKiogQ2hpLWLDrG5oIHBoxrDGoW5nOg0KDQotIEdpw6EgdHLhu4sgQ2hpLXNxdWFyZWQgKiooWMKyKTogMS4xODMxKioNCg0KLSBC4bqtYyB04buxIGRvICoqZGY6IDQqKg0KDQotIEdpw6EgdHLhu4sgKipwLXZhbHVlOiAwLjg4MDkqKg0KDQoqKkvhur90IGx14bqtbiB0aOG7kW5nIGvDqjoqKiBWw6wgZ2nDoSB0cuG7iyBwLXZhbHVlID0gMC44ODA5LCB04bupYyBy4bqldCBs4bubbiBoxqFuIG3hu6ljIMO9IG5naMSpYSwgZG8gxJHDsyBraMO0bmcgxJHhu6cgYuG6sW5nIGNo4bupbmcgdGjhu5FuZyBrw6ogxJHhu4MgYsOhYyBi4buPIGdp4bqjIHRodXnhur90IEgwLiBLaMO0bmcgY8OzIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGPDoWMgcXXhu5FjIGdpYSB2w6AgbmjDs20gc+G6o24gcGjhuqltLg0KDQotLS0NCg0KIyAqKlBo4bqnbiA1OlThu5VuZyBr4bq/dCB2w6AgVGjhuqNvIGx14bqtbioqDQoNCiMjICoqNS4xIFTDs20gdOG6r3Qgbmjhu69uZyBwaMOhdCBoaeG7h24gY2jDrW5oKioNCg0KLSAqKkdp4bubaSB0w61uaDoqKiBD4bqjIG5hbSB2w6AgbuG7ryDEkeG7gXUgbMOgIG5ow7NtIGtow6FjaCBow6BuZyBjaMOtbmgsIG5oxrBuZyBjaMawYSBjw7MgZOG6pXUgaGnhu4d1IGtow6FjIGJp4buHdCByw7UgcuG7h3QgduG7gSBow6BuaCB2aSBtdWEgc+G6r20gY2jhu4kgZOG7sWEgdsOgbyBnaeG7m2kgdMOtbmguDQoNCi0gKipUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gJiBz4bufIGjhu691IG5ow6A6KiogTmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIGPDsyB04bu3IGzhu4cgc+G7nyBo4buvdSBuaMOgIGNhbyBoxqFuIMSRw6FuZyBr4buDIHNvIHbhu5tpIG5nxrDhu51pIMSR4buZYyB0aMOibi4gxJBp4buBdSBuw6B5IGfhu6NpIMO9IHLhurFuZyBuaMOzbSBraMOhY2ggaMOgbmcgxJHDoyBs4bqtcCBnaWEgxJHDrG5oIGPDsyB0aOG7gyBjw7MgdMOgaSBjaMOtbmgg4buVbiDEkeG7i25oIHbDoCB0aeG7gW0gbsSDbmcgbXVhIHPhuq9tIGNhbyBoxqFuLg0KDQotICoqUXXhu5FjIGdpYSAmIG5ow7NtIHPhuqNuIHBo4bqpbSBjaMOtbmg6Kiog4bueIGPhuqMgMyBxdeG7kWMgZ2lhIChDYW5hZGEsIE1leGljbywgVVNBKSwgdGjhu7FjIHBo4bqpbSAoRm9vZCkgbMOgIG5ow7NtIHPhuqNuIHBo4bqpbSBjaOG7pyDEkeG6oW8sIGNoaeG6v20gaMahbiA3MCUgdOG7lW5nIGzGsOG7o25nIHPhuqNuIHBo4bqpbSBiw6FuIHJhLiBDw6FjIG5ow7NtIERyaW5rIHbDoCBOb24tQ29uc3VtYWJsZSBjaGnhur9tIHThu7cgdHLhu41uZyB0aOG6pXAgaMahbiwgdMawxqFuZyDEkeG7kWkgxJHhu5NuZyDEkeG7gXUgZ2nhu69hIGPDoWMgbsaw4bubYy4NCg0KLSAqKktp4buDbSDEkeG7i25oIHRo4buRbmcga8OqOioqIEtp4buDbSDEkeG7i25oIENoaS1iw6xuaCBwaMawxqFuZyBjaG8gdGjhuqV5IGtow7RuZyBjw7Mgc+G7sSBraMOhYyBiaeG7h3QgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiB24buBIGPGoSBj4bqldSBuaMOzbSBz4bqjbiBwaOG6qW0gZ2nhu69hIGPDoWMgcXXhu5FjIGdpYSAocC12YWx1ZSDiiYggMC44OCkuDQoNCiMjICoqNS4yIEjhuqFuIGNo4bq/IGPhu6dhIHBow6JuIHTDrWNoKioNCg0KLSAqKkdp4bubaSBo4bqhbiB0cm9uZyBiaeG6v24gxJHhu4tuaCB0w61uaDoqKiBQaMOibiB0w61jaCBjaOG7iSBk4buxYSB0csOqbiBjw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oLCBjaMawYSB4ZW0geMOpdCB54bq/dSB04buRIMSR4buLbmggbMaw4bujbmcgbmjGsCB0aHUgbmjhuq1wLCBkb2FuaCB0aHUsIGhv4bq3YyBz4buRIGzGsOG7o25nIGLDoW4gY2hpIHRp4bq/dCB0aGVvIHRo4budaSBnaWFuLg0KDQotICoqROG7ryBsaeG7h3UgY2jGsGEgY2h14bqpbiBow7NhIGhvw6BuIHRvw6BuOioqIE3hu5l0IHPhu5EgYmnhur9uICh2w60gZOG7pTogdGh1IG5o4bqtcCkgduG6q24g4bufIGThuqFuZyB0ZXh0LCBj4bqnbiB44butIGzDvSB0aMOqbSDEkeG7gyBwaOG7pWMgduG7pSBwaMOibiB0w61jaCBzw6J1IGjGoW4uDQoNCi0gKipLaMO0bmcgY8OzIHnhur91IHThu5EgdGjhu51pIGdpYW4gcsO1IHLDoG5nOioqIE3hurdjIGTDuSBjw7MgbmfDoHkgbXVhIGjDoG5nLCBuaMawbmcgY2jGsGEgcGjDom4gdMOtY2ggdGhlbyB4dSBoxrDhu5tuZyB0aOG7nWkgZ2lhbiAodsOtIGThu6UgdGhlbyBxdcO9IGhv4bq3YyBuxINtKS4NCg0KIyMgKio1LjMgxJDhu4EgeHXhuqV0KioNCg0KLSAqKkNoaeG6v24gbMaw4bujYyBz4bqjbiBwaOG6qW06KiogVOG6rXAgdHJ1bmcgdGnhur9wIHRo4buLIG5ow7NtIHRo4buxYyBwaOG6qW0gKEZvb2QpIHbDrCBjaGnhur9tIMawdSB0aOG6vyB0cm9uZyBj4bqjIGJhIHRo4buLIHRyxrDhu51uZy4gVHV5IG5oacOqbiwgY8WpbmcgY+G6p24gbmdoacOqbiBj4bupdSB0aMOqbSDEkeG7gyB0xINuZyB04bu3IGzhu4cgdGnDqnUgdGjhu6UgY8OhYyBuaMOzbSBz4bqjbiBwaOG6qW0gY8OybiBs4bqhaS4NCg0KLSAqKk5o4bqvbSBt4bulYyB0acOqdSBraMOhY2ggaMOgbmc6Kiogxq91IHRpw6puIG5ow7NtIGtow6FjaCBow6BuZyDEkcOjIGvhur90IGjDtG4gdsOgIHPhu58gaOG7r3UgbmjDoCwgdsOsIGPDsyB0aOG7gyDEkcOieSBsw6AgxJHhu5FpIHTGsOG7o25nIGPDsyBz4bupYyBtdWEgY2FvIHbDoCDhu5VuIMSR4buLbmggaMahbi4NCg0KLSAqKkNoaeG6v24gZOG7i2NoIGPDoSBuaMOibiBow7NhIHRoZW8ga2h1IHbhu7FjOioqIETDuSBjaMawYSBjw7Mgc+G7sSBraMOhYyBiaeG7h3QgxJHDoW5nIGvhu4MgZ2nhu69hIGPDoWMgcXXhu5FjIGdpYSwgZG9hbmggbmdoaeG7h3AgduG6q24gbsOqbiBwaMOibiB0w61jaCB0aMOqbSB0aGVvIHRow6BuaCBwaOG7kSBob+G6t2MgdOG7iW5oIGJhbmcgxJHhu4MgxJFp4buBdSBjaOG7iW5oIGNoaeG6v24gbMaw4bujYyBj4bulIHRo4buDIGjGoW4uDQoNCiMjICoqNS40IEPDonUgaOG7j2kgbeG7ny9IxrDhu5tuZyBuZ2hpw6puIGPhu6l1IHRp4bq/cCB0aGVvKioNCg0KLSBMaeG7h3UgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IMSRw6FuZyBr4buDIHRyb25nIGjDoG5oIHZpIG11YSBz4bqvbSBnaeG7r2EgY8OhYyBuaMOzbSB0aHUgbmjhuq1wIGtow7RuZz8NCg0KLSBN4bupYyBjaGkgdGnDqnUgdHJ1bmcgYsOsbmggdGhlbyBnaeG7m2kgdMOtbmggdsOgIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiBsw6AgYmFvIG5oacOqdT8NCg0KLSBDw7MgeHUgaMaw4bubbmcgdGhlbyBtw7lhIHbhu6UgbsOgbyB0cm9uZyBow6BuaCB2aSBtdWEgc+G6r20ga2jDtG5nPw0KDQotIE7Dqm4gcGjDom4gdMOtY2ggdGjDqm0gdMawxqFuZyBxdWFuIGdp4buvYSBuaMOzbSBz4bqjbiBwaOG6qW0gdsOgIGRvYW5oIHRodSDEkeG7gyB04buRaSDGsHUgZGFuaCBt4bulYyBz4bqjbiBwaOG6qW0uDQoNCg==