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

Đọc và Làm quen Dữ liệu:

td <- read.csv(file = "C:/Users/Admin/Downloads/Supermarket Transactions.csv", header = T)
str(td) 
## 'data.frame':    14059 obs. of  16 variables:
##  $ X                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ PurchaseDate     : chr  "2007-12-18" "2007-12-20" "2007-12-21" "2007-12-21" ...
##  $ CustomerID       : int  7223 7841 8374 9619 1900 6696 9673 354 1293 7938 ...
##  $ Gender           : chr  "F" "M" "F" "M" ...
##  $ MaritalStatus    : chr  "S" "M" "M" "M" ...
##  $ Homeowner        : chr  "Y" "Y" "N" "Y" ...
##  $ Children         : int  2 5 2 3 3 3 2 2 3 1 ...
##  $ AnnualIncome     : chr  "$30K - $50K" "$70K - $90K" "$50K - $70K" "$30K - $50K" ...
##  $ City             : chr  "Los Angeles" "Los Angeles" "Bremerton" "Portland" ...
##  $ StateorProvince  : chr  "CA" "CA" "WA" "OR" ...
##  $ Country          : chr  "USA" "USA" "USA" "USA" ...
##  $ ProductFamily    : chr  "Food" "Food" "Food" "Food" ...
##  $ ProductDepartment: chr  "Snack Foods" "Produce" "Snack Foods" "Snacks" ...
##  $ ProductCategory  : chr  "Snack Foods" "Vegetables" "Snack Foods" "Candy" ...
##  $ UnitsSold        : int  5 5 3 4 4 3 4 6 1 2 ...
##  $ Revenue          : num  27.38 14.9 5.52 4.44 14 ...
head(td, 6)
##   X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children
## 1 1   2007-12-18       7223      F             S         Y        2
## 2 2   2007-12-20       7841      M             M         Y        5
## 3 3   2007-12-21       8374      F             M         N        2
## 4 4   2007-12-21       9619      M             M         Y        3
## 5 5   2007-12-22       1900      F             S         Y        3
## 6 6   2007-12-22       6696      F             M         Y        3
##    AnnualIncome          City StateorProvince Country ProductFamily
## 1   $30K - $50K   Los Angeles              CA     USA          Food
## 2   $70K - $90K   Los Angeles              CA     USA          Food
## 3   $50K - $70K     Bremerton              WA     USA          Food
## 4   $30K - $50K      Portland              OR     USA          Food
## 5 $130K - $150K Beverly Hills              CA     USA         Drink
## 6   $10K - $30K Beverly Hills              CA     USA          Food
##   ProductDepartment      ProductCategory UnitsSold Revenue
## 1       Snack Foods          Snack Foods         5   27.38
## 2           Produce           Vegetables         5   14.90
## 3       Snack Foods          Snack Foods         3    5.52
## 4            Snacks                Candy         4    4.44
## 5         Beverages Carbonated Beverages         4   14.00
## 6              Deli          Side Dishes         3    4.37
tail(td, 6)
##           X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children
## 14054 14054   2009-12-29       2032      F             M         N        3
## 14055 14055   2009-12-29       9102      F             M         Y        2
## 14056 14056   2009-12-29       4822      F             M         Y        3
## 14057 14057   2009-12-31        250      M             S         Y        1
## 14058 14058   2009-12-31       6153      F             S         N        4
## 14059 14059   2009-12-31       3656      M             S         N        3
##       AnnualIncome        City StateorProvince Country  ProductFamily
## 14054  $10K - $30K      Yakima              WA     USA Non-Consumable
## 14055  $10K - $30K   Bremerton              WA     USA           Food
## 14056  $10K - $30K Walla Walla              WA     USA           Food
## 14057  $30K - $50K    Portland              OR     USA          Drink
## 14058  $50K - $70K     Spokane              WA     USA          Drink
## 14059  $50K - $70K    Portland              OR     USA Non-Consumable
##       ProductDepartment      ProductCategory UnitsSold Revenue
## 14054         Household       Paper Products         5   14.50
## 14055      Baking Goods         Baking Goods         3    9.64
## 14056      Frozen Foods           Vegetables         3    7.45
## 14057         Beverages Pure Juice Beverages         4    3.24
## 14058             Dairy                Dairy         2    4.00
## 14059         Household           Electrical         5   25.53

Tổng quan:

Tập dữ liệu gồm 14,059 quan sát và 16 biến. Dựa trên kết quả str() của tập dữ liệu, dưới đây là phân loại các biến theo kiểu dữ liệu:

Kiểu int (integer - số nguyên):

  • X: Chỉ số hoặc ID quan sát (1, 2, 3, …).

  • CustomerID: Mã định danh khách hàng (7223, 7841, …).

  • Children: Số con (2, 5, 3, …).

  • UnitsSold: Số đơn vị bán (5, 3, 4, …).

  • Kiểu chr (character - chuỗi ký tự):

  • PurchaseDate: Ngày mua hàng (“2007-12-18”, …).

  • Gender: Giới tính (“F”, “M”).

  • MaritalStatus: Tình trạng hôn nhân (“S”, “M”).

  • Homeowner: Sở hữu nhà (“Y”, “N”).

  • AnnualIncome: Khoảng thu nhập (“$30K - $50K”, …).

  • City: Thành phố (“Los Angeles”, “Bremerton”, …).

  • StateorProvince: Bang/tỉnh (“CA”, “WA”, …).

  • Country: Quốc gia (“USA”, …).

  • ProductFamily: Nhóm sản phẩm (“Food”, …).

  • ProductDepartment: Bộ phận sản phẩm (“Snack Foods”, “Produce”, …).

  • ProductCategory: Danh mục sản phẩm (“Snack Foods”, “Vegetables”, …).

Kiểu num (numeric - số thực):

  • Revenue: Doanh thu (27.38, 14.90, …)
qual_cols <- c('Gender', 'MaritalStatus', 'Homeowner', 'AnnualIncome', 'City', 'StateorProvince', 'Country', 'ProductFamily', 'ProductDepartment', 'ProductCategory')
sapply(td[qual_cols], function(x) sum(is.na(x))) 
##            Gender     MaritalStatus         Homeowner      AnnualIncome 
##                 0                 0                 0                 0 
##              City   StateorProvince           Country     ProductFamily 
##                 0                 0                 0                 0 
## ProductDepartment   ProductCategory 
##                 0                 0

Kết quả cho thấy không có giá trị thiếu (NA) nào trong các cột định tính của tập dữ liệu.

Kết quả xử lý dữ liệu sang factofactor

#kiểm tra các biến định tính có phải là factor hay chưa
for (i in 1:ncol(td)) {
  a <- is.factor(td[,i])
  cat(colnames(td)[i],":",a,"\n")
}
## X : FALSE 
## PurchaseDate : FALSE 
## CustomerID : FALSE 
## Gender : FALSE 
## MaritalStatus : FALSE 
## Homeowner : FALSE 
## Children : FALSE 
## AnnualIncome : FALSE 
## City : FALSE 
## StateorProvince : FALSE 
## Country : FALSE 
## ProductFamily : FALSE 
## ProductDepartment : FALSE 
## ProductCategory : FALSE 
## UnitsSold : FALSE 
## Revenue : FALSE
# Chuyển về dạng factor 

for (i in 1:ncol(td)) {
  td[,i] <- as.factor(td[,i])
}

# Kiểm tra lại 
for (i in 1:ncol(td)) {
  a <- is.factor(td[,i])
  cat(colnames(td)[i],":",a,"\n")
}
## X : TRUE 
## PurchaseDate : TRUE 
## CustomerID : TRUE 
## Gender : TRUE 
## MaritalStatus : TRUE 
## Homeowner : TRUE 
## Children : TRUE 
## AnnualIncome : TRUE 
## City : TRUE 
## StateorProvince : TRUE 
## Country : TRUE 
## ProductFamily : TRUE 
## ProductDepartment : TRUE 
## ProductCategory : TRUE 
## UnitsSold : TRUE 
## Revenue : TRUE

Sau khi kiểm tra kiểu dữ liệu ban đầu, các biến phân loại như Gender, MaritalStatus, Homeowner, AnnualIncome, City, StateorProvince, Country, ProductFamily, ProductDepartment, ProductCategory đã được chuyển từ kiểu character sang factor. Tổng cộng có 10 biến đã được chuyển đổi thành công.

Tất cả các biến trên đều là biến phân loại (categorical), tức là chỉ gồm một tập giá trị hữu hạn như “Nam”/“Nữ”,“Độc thân”/“Kết hôn”,… hoặc tên các thành phố, nhóm sản phẩm,… Việc chuyển đổi sang kiểu factor hỗ trợ xử lý dữ liệu tốt hơn, giúp R hiểu rõ bản chất của các cột dữ liệu và tiết kiệm được bộ nhớ.

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

1. Gender(giới tính)

Biến Gender là một biến định tính phân loại nhị phân, phản ánh giới tính của khách hàng trong tập dữ liệu.

library(ggplot2)
# Tạo bảng tần số cho Gender
gender_freq <- table(td$Gender)
gender_df <- as.data.frame(gender_freq)
colnames(gender_df) <- c("Gender", "Count")

# Vẽ biểu đồ cột
ggplot(gender_df, aes(x = Gender, y = Count, fill = Gender)) +
  geom_bar(stat = "identity", width = 0.6) +
  scale_fill_manual(values = c("lightgreen", "lightpink")) +
  labs(title = "Biểu đồ số lượng theo Giới tính", x = "Giới tính", y = "Số lượng") +
  theme_minimal()

Phân tích mô tả cho thấy cơ cấu giới tính trong bộ dữ liệu khá đồng đều, với tỷ lệ nữ là 51% và nam chiếm 49%. Sự phân bố gần như tương đương này phản ánh sự cân bằng giới, góp phần nâng cao độ tin cậy của các kết quả phân tích sau này. Nhờ vào việc không có sự thiên lệch đáng kể giữa hai nhóm giới tính, nguy cơ sai lệch do chọn mẫu được giảm thiểu. Đồng thời, sự đồng đều này cũng hỗ trợ tốt cho việc xây dựng và kiểm định các mô hình thống kê có yếu tố phân tích theo giới.

2. MaritalStatus (tình trạng hôn nhân)

Biến MaritalStatus phản ánh trạng thái hôn nhân của người tiêu dùng, với ký hiệu ‘S’ tương ứng với nhóm độc thân và ‘M’ cho nhóm đã lập gia đình. Đây là một biến định tính thuộc dạng phân đôi, thường được khai thác trong các nghiên cứu hành vi để phân biệt sự khác nhau trong thói quen chi tiêu giữa các đối tượng khách hàng. Chẳng hạn, những người chưa kết hôn có xu hướng chi tiêu cho nhu cầu cá nhân, trong khi những người đã kết hôn thường ưu tiên mua sắm cho hộ gia đình hoặc cân nhắc kỹ lưỡng về mặt tài chính. Việc đưa biến này vào quá trình phân tích không chỉ giúp nhận diện rõ hơn đặc điểm nhân khẩu học mà còn hỗ trợ doanh nghiệp trong việc thiết kế chiến lược tiếp thị, dự đoán hành vi và phân chia thị trường mục tiêu một cách chính xác hơn.

library(ggplot2)

# Tạo bảng tần số cho MaritalStatus
marital_freq <- table(td$MaritalStatus)
marital_df <- as.data.frame(marital_freq)
colnames(marital_df) <- c("MaritalStatus", "Count")

# Tính phần trăm và nhãn
marital_df$Percentage <- round(marital_df$Count / sum(marital_df$Count) * 100, 1)
marital_df$Label <- paste0(marital_df$Percentage, "%")

# Vẽ biểu đồ tròn với nhãn %
ggplot(marital_df, aes(x = "", y = Count, fill = MaritalStatus)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = Label), 
            position = position_stack(vjust = 0.5), 
            color = "white", size = 4.5) +
  scale_fill_manual(values = c("lightblue", "lightcoral")) +
  labs(title = "Biểu đồ tròn tình trạng hôn nhân", fill = "Tình trạng") +
  theme_void()

Dữ liệu thống kê cho thấy nhóm khách hàng độc thân chiếm tỷ lệ khoảng 51,2%, trong khi nhóm đã kết hôn chiếm 48,8%. Tỷ lệ này cho thấy sự phân bổ giữa hai trạng thái hôn nhân khá cân bằng, phản ánh tính đại diện xã hội tương đối tốt của tập dữ liệu. Việc nhóm độc thân chiếm ưu thế nhẹ có thể là dấu hiệu cho thấy phần lớn khách hàng có xu hướng sống một mình, từ đó gợi mở nhu cầu tiêu dùng thiên về cá nhân hóa và linh hoạt hơn. Thông tin này có thể là cơ sở hữu ích cho việc điều chỉnh chiến lược tiếp thị hoặc thiết kế sản phẩm phù hợp với đặc điểm của nhóm khách hàng chủ đạo.

3. Homeowner

Biến Homeowner thể hiện thông tin về quyền sở hữu nhà ở của khách hàng, trong đó ký hiệu ‘Y’ đại diện cho những người có nhà riêng và ‘N’ dành cho những người chưa sở hữu nhà. Đây là một biến phân loại nhị phân, thường được sử dụng trong phân tích để đánh giá năng lực tài chính hoặc mức độ ổn định kinh tế của đối tượng nghiên cứu. Việc sở hữu nhà không chỉ phản ánh phần nào thu nhập và tài sản tích lũy của khách hàng, mà còn có thể ảnh hưởng đến hành vi chi tiêu cũng như nhu cầu về các sản phẩm và dịch vụ nhất định – đặc biệt trong các lĩnh vực như ngân hàng, bảo hiểm hoặc tiêu dùng bền vững.

library(ggplot2)

# Tạo bảng tần số và phần trăm cho biến Homeowner
home_freq <- table(td$Homeowner)
home_df <- as.data.frame(home_freq)
colnames(home_df) <- c("Homeowner", "Count")

# Tính phần trăm
home_df$Percentage <- round(home_df$Count / sum(home_df$Count) * 100, 1)
home_df$Label <- paste0(home_df$Percentage, "%")

# Vẽ biểu đồ cột với nhãn phần trăm
ggplot(home_df, aes(x = Homeowner, y = Count, fill = Homeowner)) +
  geom_bar(stat = "identity", width = 0.6) +
  geom_text(aes(label = Label), vjust = -0.5, size = 4.5) +
  scale_fill_manual(values = c("blue", "yellow")) +
  labs(title = "Biểu đồ thể hiện tình trạng sở hữu nhà",
       x = "Sở hữu nhà",
       y = "Số lượng") +
  theme_minimal()

Tỷ lệ khách hàng sở hữu nhà trong tập dữ liệu đạt 60,1%, cao hơn so với 39,9% còn lại không có nhà ở. Sự phân bố này phản ánh mức độ ổn định tài chính nhất định của phần lớn khách hàng, đồng thời cho thấy sự khác biệt tiềm năng về hành vi tiêu dùng giữa hai nhóm. Trong khi nhóm có nhà có xu hướng hướng đến các lựa chọn đầu tư dài hạn, thì nhóm không sở hữu nhà có thể ưu tiên các giải pháp tiêu dùng linh hoạt hơn. Do đó, đặc điểm này đóng vai trò quan trọng trong việc phân tích nhân khẩu học và hoạch định chiến lược tiếp cận phù hợp.

4. AnnualIncome

Biến AnnualIncome mô tả thu nhập hàng năm của khách hàng, được chia thành các nhóm theo từng khoảng mức tăng dần. Đây là một biến phân loại có thứ tự (ordinal), phản ánh sự khác biệt về khả năng tài chính giữa các nhóm khách hàng. Thứ tự sắp xếp các mức thu nhập cho phép khai thác sâu hơn trong phân tích nhân khẩu học và phân tầng tiêu dùng.

library(knitr)

# Thống kê tần suất
table_income <- table(td$AnnualIncome)
prop_income <- prop.table(table_income) * 100  # Tỷ lệ phần trăm

income_freq <- data.frame(
  AnnualIncome = names(table_income),
  Frequency = as.vector(table_income),
  Percentage = round(as.vector(prop_income), 2)
)

kable(income_freq, col.names = c("Khoảng thu nhập", "Tần suất", "Tỷ lệ (%)"),
      caption = "Bảng phân phối thu nhập")
Bảng phân phối thu nhập
Khoảng thu nhập Tần suất Tỷ lệ (%)
$10K - $30K 3090 21.98
$110K - $130K 643 4.57
$130K - $150K 760 5.41
$150K + 273 1.94
$30K - $50K 4601 32.73
$50K - $70K 2370 16.86
$70K - $90K 1709 12.16
$90K - $110K 613 4.36
library(ggplot2)

# Sắp xếp theo Percentage giảm dần
income_freq <- income_freq[order(income_freq$Percentage, decreasing = TRUE), ]

# Vẽ biểu đồ cột ngang
ggplot(income_freq, aes(x = reorder(AnnualIncome, Percentage), y = Percentage, fill = AnnualIncome)) +
  geom_col(width = 0.7, show.legend = FALSE) +
  coord_flip() +
  labs(title = "Tỷ lệ phần trăm thu nhập hàng năm của khách hàng",
       x = "Khoảng thu nhập",
       y = "Tỷ lệ (%)") +
  scale_fill_brewer(palette = "Set3") +
  theme_minimal()

Phân bố thu nhập của khách hàng cho thấy nhóm có số lượng đông đảo nhất thuộc vào khoảng thu nhập từ 30.000 đến 50.000 đô la, với hơn 4.600 cá nhân. Nhóm thu nhập thấp, nằm trong khoảng 10.000 đến 30.000 đô la, cũng chiếm tỷ lệ đáng kể với gần 3.100 khách hàng. Các phân khúc thu nhập trung bình như 50.000 đến 70.000 đô la và 70.000 đến 90.000 đô la lần lượt có khoảng 2.370 và 1.700 khách hàng. Ngược lại, số lượng khách hàng thuộc các nhóm thu nhập cao hơn, từ 90.000 đến trên 150.000 đô la, tương đối khiêm tốn, dao động trong khoảng từ 270 đến 760 cá nhân. Những con số này cho thấy đa phần khách hàng trong bộ dữ liệu tập trung chủ yếu ở các nhóm thu nhập thấp đến trung bình, trong khi nhóm thu nhập cao có quy mô hạn chế hơn đáng kể.

5. City

Biến City trong tập dữ liệu thể hiện địa điểm thành phố nơi giao dịch mua sắm diễn ra. Đây là một biến phân loại (qualitative variable) với các giá trị đa dạng như Los Angeles, Bremerton, Portland, Salem, Tacoma, và nhiều thành phố khác. Biến này hỗ trợ việc phân tích sự phân bố giao dịch theo khu vực địa lý, giúp khám phá hành vi mua sắm theo vùng, nhận diện các thị trường quan trọng hoặc phát hiện xu hướng tiêu dùng theo từng địa phương.

library(knitr)

# Thống kê tần suất
table_city <- table(td$City)
prop_city <- prop.table(table_city) * 100  # Tỷ lệ phần trăm

# Kết hợp thành data frame 
city_freq <- data.frame(
  City = names(table_city),
  Frequency = as.vector(table_city),
  Percentage = round(as.vector(prop_city), 2)
)

# Hiển thị bảng rõ ràng bằng kable
kable(city_freq, align = "lrr", caption = "Bảng tần suất và tỷ lệ phần trăm theo thành phố")
Bảng tần suất và tỷ lệ phần trăm theo thành phố
City Frequency Percentage
Acapulco 383 2.72
Bellingham 143 1.02
Beverly Hills 811 5.77
Bremerton 834 5.93
Camacho 452 3.22
Guadalajara 75 0.53
Hidalgo 845 6.01
Los Angeles 926 6.59
Merida 654 4.65
Mexico City 194 1.38
Orizaba 464 3.30
Portland 876 6.23
Salem 1386 9.86
San Andres 621 4.42
San Diego 866 6.16
San Francisco 130 0.92
Seattle 922 6.56
Spokane 875 6.22
Tacoma 1257 8.94
Vancouver 633 4.50
Victoria 176 1.25
Walla Walla 160 1.14
Yakima 376 2.67
library(ggplot2)
library(tidyr)


# Chuyển dữ liệu sang định dạng long
city_long <- city_freq %>%
  pivot_longer(cols = c(Frequency, Percentage),
               names_to = "Metric", values_to = "Value")

# Vẽ biểu đồ với facet
ggplot(city_long, aes(x = reorder(City, -Value), y = Value, fill = Metric)) +
  geom_bar(stat = "identity", position = "dodge") +
  facet_wrap(~Metric, scales = "free_y") +
  labs(title = "Số lượng và Tỷ lệ phần trăm khách hàng theo Thành phố",
       x = "Thành phố", y = "") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        legend.position = "none")

Dữ liệu cho thấy khách hàng phân bố tại nhiều thành phố khác nhau, trong đó một số địa phương nổi bật với số lượng khách hàng lớn. Salem dẫn đầu với 1.386 khách, chiếm khoảng 10% tổng số quan sát. Tiếp theo là Tacoma với 1.257 khách và Seattle với 922 khách, phản ánh sự tập trung khách hàng tại các vùng đô thị này. Ngược lại, các thành phố như Guadalajara (75 khách), San Francisco (130 khách) và Bellingham (143 khách) ghi nhận số lượng khách hàng tương đối thấp, cho thấy sự phân bố không đồng đều trong tập dữ liệu. Một số thành phố khác như Portland (876 khách), Spokane (875 khách) và San Diego (866 khách) có lượng khách hàng gần tương đương, nằm trong nhóm có số lượng cao nhưng không có sự khác biệt đáng kể.Tổng thể, kết quả minh họa xu hướng tập trung khách hàng chủ yếu tại các thành phố lớn hoặc trung tâm kinh tế, trong khi các khu vực nhỏ hơn có mức độ tham gia thị trường thấp hơn.

6.StateorProvince

Biến StateorProvince đại diện cho các khu vực hành chính như bang hoặc tỉnh nơi khách hàng cư trú hoặc thực hiện giao dịch. Bộ giá trị bao gồm nhiều khu vực đa dạng như BC, CA, DF, Guerrero, Jalisco, OR, Veracruz, WA, Yucatan và Zacatecas, phản ánh phạm vi địa lý rộng lớn của dữ liệu. Việc phân tích phân bố khách hàng theo các bang hoặc tỉnh cung cấp cái nhìn sâu sắc về đặc điểm vùng miền và thói quen tiêu dùng, qua đó hỗ trợ doanh nghiệp xây dựng các chiến lược tiếp thị hiệu quả cũng như quản lý kho vận hợp lý. Do đây là biến định danh, phân tích chủ yếu tập trung vào tần suất và tỷ lệ phần trăm của từng khu vực, thay vì sử dụng các thống kê mô tả như trung bình hay độ lệch chuẩn.

# Thống kê tần suất
table_state <- table(td$StateorProvince)
prop_state <- prop.table(table_state) * 100  # Tỷ lệ phần trăm

# Kết hợp thành data frame 
state_freq <- data.frame(
  StateOrProvince = names(table_state),
  Frequency = as.vector(table_state),
  Percentage = round(as.vector(prop_state), 2))

print(state_freq)
##    StateOrProvince Frequency Percentage
## 1               BC       809       5.75
## 2               CA      2733      19.44
## 3               DF       815       5.80
## 4         Guerrero       383       2.72
## 5          Jalisco        75       0.53
## 6               OR      2262      16.09
## 7         Veracruz       464       3.30
## 8               WA      4567      32.48
## 9          Yucatan       654       4.65
## 10       Zacatecas      1297       9.23
library(ggplot2)
state_long <- state_freq %>%
  pivot_longer(cols = c(Frequency, Percentage),
               names_to = "Metric", values_to = "Value")

ggplot(state_freq, aes(x = reorder(StateOrProvince, -Frequency), y = Frequency)) +
  geom_bar(stat = "identity", fill = "pink") +
  labs(title = "Lượng khách hàng đến từ các bang/tỉnh",
       x = "State or Province",
       y = "Lượng khách hàng ") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Phân bố khách hàng theo bang hoặc tỉnh cho thấy Washington (WA) dẫn đầu với 4.567 khách hàng, tiếp theo là California (CA) với 2.733 và Oregon (OR) với 2.262 khách hàng, thể hiện mức độ tập trung cao tại các khu vực này. Các bang như Zacatecas, British Columbia (BC) và Distrito Federal (DF) cũng ghi nhận số lượng khách hàng đáng kể, lần lượt là 1.297, 809 và 815. Ngược lại, các bang như Jalisco và Guerrero có lượng khách hàng thấp hơn nhiều, chỉ đạt 75 và 383. Như vậy, phân bố khách hàng theo bang/tỉnh không đồng đều, với sự tập trung rõ rệt tại một số khu vực trọng điểm, trong khi các vùng khác có số lượng khách hàng tương đối hạn chế.

7.Country

Biến Country biểu thị quốc gia nơi khách hàng tiến hành giao dịch, bao gồm ba quốc gia chính: Mỹ (USA), Mexico và Canada. Điều này cho thấy phạm vi hoạt động của siêu thị mở rộng trên toàn bộ khu vực Bắc Mỹ.

  • Về khía cạnh địa lý, dữ liệu phản ánh chiến lược kinh doanh đa quốc gia, tập trung khai thác thị trường tiêu dùng tại ba quốc gia này.

  • Sự đa dạng quốc gia trong dữ liệu cũng tạo điều kiện phân tích sự khác biệt về thói quen tiêu dùng, doanh thu và các sản phẩm ưa chuộng theo từng vùng lãnh thổ.

# Thống kê tần suất
table_cou <- table(td$Country)
prop_cou <- prop.table(table_cou) * 100  # Tỷ lệ phần trăm

# Kết hợp thành data frame 
cou_freq <- data.frame(
 cou = names(table_cou),
  Frequency = as.vector(table_cou),
  Percentage = round(as.vector(prop_cou), 2))

print(cou_freq)
##      cou Frequency Percentage
## 1 Canada       809       5.75
## 2 Mexico      3688      26.23
## 3    USA      9562      68.01
library(ggplot2)
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
# Giả sử cou_freq là bảng gồm 2 cột: Quốc gia (cou) và Tần suất (Frequency)
cou_freq <- cou_freq %>%
  mutate(Percentage = round(Frequency / sum(Frequency) * 100, 1),
         Label = paste0(cou, " (", Percentage, "%)"))

# Vẽ biểu đồ tròn
ggplot(cou_freq, aes(x = "", y = Frequency, fill = cou)) +
  geom_col(width = 1, color = "white") +
  coord_polar(theta = "y") +
  labs(title = "Tỷ lệ khách hàng theo quốc gia") +
  theme_void() +
  theme(legend.title = element_blank()) +
  geom_text(aes(label = paste0(Percentage, "%")), 
            position = position_stack(vjust = 0.5), size = 4)

Biến Country trong bộ dữ liệu chỉ chứa duy nhất giá trị “USA”, cho thấy toàn bộ thông tin đều đến từ khách hàng cư trú tại Hoa Kỳ. Điều này cho thấy phạm vi địa lý của dữ liệu khá hạn chế và không phản ánh được sự đa dạng về quốc gia.

Vì biến này không có sự biến đổi nào khác ngoài “USA”, nó không có giá trị trong việc phân loại hay giải thích trong phân tích mô tả. Do đó, trong các bước phân tích tiếp theo như xây dựng mô hình hồi quy hoặc phân đoạn thị trường, biến Country có thể được loại bỏ nếu mục tiêu nghiên cứu không bao gồm mở rộng sang các quốc gia khác.

8.ProductFamily

# Thống kê tần suất
table_fam <- table(td$ProductFamily)
prop_fam <- prop.table(table_fam) * 100  # Tỷ lệ phần trăm

# Kết hợp thành data frame 
fam_freq <- data.frame(
 fam = names(table_fam),
  Frequency = as.vector(table_fam),
  Percentage = round(as.vector(prop_fam), 2))

print(fam_freq)
##              fam Frequency Percentage
## 1          Drink      1250       8.89
## 2           Food     10153      72.22
## 3 Non-Consumable      2656      18.89
library(ggplot2)
ggplot(fam_freq, aes(x = reorder(fam, -Frequency), y = Frequency)) +
  geom_bar(stat = "identity", fill = "blue") +
  labs(title = "Số lượng khách hàng đến từ các nước",
       x = "Country",
       y = "Lượng ") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Kết quả phân tích dữ liệu về nhóm sản phẩm (ProductFamily) trong tập dữ liệu:

  • Drink: 1,250 giao dịch, chiếm 8.89%.

  • Food: 10,153 giao dịch, chiếm 72.22%.

  • Non-Consumable: 2,656 giao dịch, chiếm 18.89%.

    Nhận xét: Nhóm “Food” chiếm tỷ lệ cao nhất (72.22%), cho thấy sản phẩm thực phẩm là mặt hàng chủ đạo trong các giao dịch, trong khi “Drink” và “Non-Consumable” có tỷ lệ thấp hơn đáng kể.

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 sau:

1. Gender - Nữ (F)

# Lưu tổng số dòng trong dataframe
n_total <- nrow(td)
# tổng số quan sát (observation) trong tập dữ liệu.
n_female <- sum(td$Gender == "Female")
# Thực hiện kiểm định tỷ lệ một mẫu (1-sample proportion test).
prop.test(n_female, n_total, p = 0.5, correct = TRUE)
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_female out of n_total, null probability 0.5
## X-squared = 14057, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.0000000000 0.0003405602
## sample estimates:
## p 
## 0

Kiểm định tỷ lệ một mẫu cho biến Gender

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

  • (H₀): Tỷ lệ nữ trong tổng số khách hàng bằng 50%, tức p=0.5.

  • (H₁): Tỷ lệ nữ khác 50%, tức 𝑝≠0.5

    Kết quả kiểm định:

    Kiểm định tỷ lệ một mẫu (1-sample proportion test with continuity correction) được thực hiện với tỷ lệ giả định là 0.5. Kết quả cho thấy:

  • Giá trị thống kê Chi-bình phương: 𝜒2=14057

  • Bậc tự do: 1

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

Khoảng tin cậy 95% cho tỷ lệ nữ: [0.0000000000, 0.0003405602]

Tỷ lệ mẫu ước lượng: 𝑝^=0

Kết luận: Với p-value rất nhỏ (nhỏ hơn 0.05), chúng ta bác bỏ giả thiết không ở mức ý nghĩa 5%. Điều này cho thấy tỷ lệ nữ trong mẫu dữ liệu khác biệt có ý nghĩa thống kê so với 50%.

Cụ thể, tỷ lệ ước lượng bằng 0 và khoảng tin cậy không bao gồm 0.5 cho thấy gần như không có khách hàng nữ trong dữ liệu, phản ánh sự mất cân bằng nghiêm trọng về giới tính trong tập khách hàng được khảo sát.

2. Homeowner – Hạng mục quan tâm: “Yes” (Y)

n_total_home <- nrow(td)
n_homeowner <- sum(td$Homeowner == "Y")
prop.test(n_homeowner, n_total_home, p = 0.6, correct = TRUE)
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_homeowner out of n_total_home, null probability 0.6
## X-squared = 0.019445, df = 1, p-value = 0.8891
## alternative hypothesis: true p is not equal to 0.6
## 95 percent confidence interval:
##  0.5924537 0.6087145
## sample estimates:
##         p 
## 0.6006117
  • Tỷ lệ mẫu: 60.06%

  • Khoảng tin cậy 95%: [59.25%; 60.87%]

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

    H₀: Tỷ lệ chủ nhà = 0.6

    H₁: Tỷ lệ chủ nhà ≠ 0.6

    Giá trị p ≈ 0.89 → Không bác bỏ H₀, ttức là không có đủ bằng chứng để kết luận rằng tỷ lệ chủ nhà khác 60% trong tổng thể.(Khoảng tin cậy chứa giá trị 0.6 nên phù hợp với giả thuyết ban đầu)

    Nhận xét:

    Tỷ lệ khách hàng sở hữu nhà trong tập dữ liệu đạt 60.06%, với khoảng tin cậy 95% nằm trong khoảng [59.25%; 60.87%]. Kiểm định giả thuyết cho thấy không có sự khác biệt có ý nghĩa thống kê so với tỷ lệ giả định là 60% (p = 0.8891). Điều này cho thấy sự phân bố của biến này khá ổn định và đáng tin cậy. Việc hơn 60% khách hàng sở hữu nhà cho thấy một mức độ ổn định tài chính nhất định, phản ánh tiềm năng cho các hành vi tiêu dùng dài hạn hơn ở nhóm này. Ngược lại, nhóm không sở hữu nhà có thể ưu tiên các lựa chọn ngắn hạn và linh hoạt hơn, giúp cung cấp góc nhìn đa dạng trong việc phân tích phân khúc khách hàng.

3.ProductFamily – Hạng mục quan tâm: “Food”

n_total_prod <- nrow(td)
n_food <- sum(td$ProductFamily == "Food")
prop.test(n_food, n_total_prod, p = 0.7, alternative = "less", correct = TRUE)
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_food out of n_total_prod, null probability 0.7
## X-squared = 32.802, df = 1, p-value = 1
## alternative hypothesis: true p is less than 0.7
## 95 percent confidence interval:
##  0.0000000 0.7283768
## sample estimates:
##         p 
## 0.7221709
  • Tỷ lệ mẫu: 72.22%

  • Khoảng tin cậy 95%: [0.00%; 72.84%] (do lựa chọn kiểm định một phía nên cận dưới là 0)

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

    H₀: Tỷ lệ Food ≥ 0.7

    H₁: Tỷ lệ Food < 0.7

Giá trị p từ kiểm định H₀: p ≥ 0.7 (dạng một phía): 1

Kết luận: Vì p-value > 0.05 → không bác bỏ H₀, tức là không có đủ bằng chứng để kết luận rằng tỷ lệ sản phẩm Food nhỏ hơn 70%.

Tuy nhiên, vì tỷ lệ mẫu thực tế là 72.22%, kết hợp khoảng tin cậy khá rộng, có thể cân nhắc kiểm định hai phía để đánh giá sát hơn.

Nhận xét:

Nhóm sản phẩm “Food” chiếm tỷ lệ cao nhất với 72.22%, cho thấy đây là mặt hàng chủ lực trong các giao dịch. Mặc dù kết quả kiểm định giả thuyết một phía không bác bỏ giả thuyết tỷ lệ ≥ 70% (p = 1), nhưng tỷ lệ thực tế vượt mức giả định, đồng thời chiếm đa số rõ rệt so với các nhóm còn lại như “Drink” hay “Non-Consumable”. Điều này cho thấy nhu cầu lớn về thực phẩm trong tập khách hàng và là căn cứ vững chắc để doanh nghiệp tập trung chiến lược kinh doanh vào nhóm sản phẩm này.

Phần 4. Phân tích Mối quan hệ hai biến định tính

Ta chọn 3 cặp biến sau đây:

  • StateorProvince và ProductFamily:

  • MaritalStatus và Homeowner

  • AnnualIncome và ProductCategory

4.1 MaritalStatus và Homeowner:

Bảng tần số chéo

table_marital_home <- table(td$MaritalStatus, td$Homeowner)

percent_row <- prop.table(table_marital_home, margin = 1) * 100

print(table_marital_home)
##    
##        N    Y
##   M 1719 5147
##   S 3896 3297

Trực quan hóa

library(ggplot2)
library(dplyr)

# Ví dụ với MaritalStatus và Homeowner
td %>%
  group_by(MaritalStatus, Homeowner) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = MaritalStatus, y = count, fill = Homeowner)) +
  geom_bar(stat = "identity", position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Tỷ lệ sở hữu nhà theo tình trạng hôn nhân",
       y = "Tỷ lệ phần trăm", x = "Tình trạng hôn nhân") +
  theme_minimal()
## `summarise()` has grouped output by 'MaritalStatus'. You can override using the
## `.groups` argument.

Nhận xét

Biểu đồ “Tỷ lệ sở hữu nhà theo tình trạng hôn nhân” cho thấy có sự khác biệt rõ rệt giữa hai nhóm MaritalStatus. Cụ thể, trong nhóm đã kết hôn (Married), tỷ lệ sở hữu nhà (Homeowner = Y) cao hơn đáng kể so với tỷ lệ không sở hữu nhà. Ngược lại, ở nhóm độc thân (Single), tỷ lệ không sở hữu nhà lại chiếm ưu thế. Xu hướng này cho thấy khả năng có mối liên hệ giữa tình trạng hôn nhân và việc sở hữu nhà ở: những người đã kết hôn thường có xu hướng sở hữu nhà cao hơn, có thể do nhu cầu ổn định chỗ ở, khả năng tài chính kết hợp từ hai người hoặc kế hoạch dài hạn cho gia đình. Trong khi đó, nhóm độc thân có thể ưu tiên sự linh hoạt về chỗ ở hoặc chưa đủ điều kiện để sở hữu nhà. Mối quan sát này cho thấy sự khác biệt đáng chú ý về hành vi sở hữu tài sản giữa các nhóm hôn nhân.

4.2 AnnualIncome và ProductCategory

Bảng tần số chéo

table_income_cat <- table(td$AnnualIncome, td$ProductCategory)
percent_income_cat <- prop.table(table_income_cat, margin = 1) * 100

print(table_income_cat)
##                
##                 Baking Goods Bathroom Products Beer and Wine Bread
##   $10K - $30K            119                85            80   108
##   $110K - $130K           18                16            14    23
##   $130K - $150K           22                19            15    24
##   $150K +                 11                 8             3    10
##   $30K - $50K            151               116           121   134
##   $50K - $70K             86                50            61    63
##   $70K - $90K             59                51            39    50
##   $90K - $110K            18                20            23    13
##                
##                 Breakfast Foods Candles Candy Canned Anchovies Canned Clams
##   $10K - $30K               111       6    76               10           12
##   $110K - $130K               7       1    16                2            1
##   $130K - $150K              28       2    19                1            3
##   $150K +                     7       1     8                1            1
##   $30K - $50K               143      21   127               14           20
##   $50K - $70K                62       7    60                8            6
##   $70K - $90K                42       7    29                6            7
##   $90K - $110K               17       0    17                2            3
##                
##                 Canned Oysters Canned Sardines Canned Shrimp Canned Soup
##   $10K - $30K                5               8             9          98
##   $110K - $130K              4               2             0          19
##   $130K - $150K              3               1             2          17
##   $150K +                    1               1             0           8
##   $30K - $50K               10              18            16         137
##   $50K - $70K                5               5             7          67
##   $70K - $90K                5               3             2          50
##   $90K - $110K               2               2             2           8
##                
##                 Canned Tuna Carbonated Beverages Cleaning Supplies
##   $10K - $30K            13                   36                47
##   $110K - $130K           3                    6                 8
##   $130K - $150K           5                    3                 7
##   $150K +                 3                    6                 4
##   $30K - $50K            28                   51                51
##   $50K - $70K            19                   20                35
##   $70K - $90K            10                   23                25
##   $90K - $110K            6                    9                12
##                
##                 Cold Remedies Dairy Decongestants Drinks Eggs Electrical
##   $10K - $30K              23   174            22     30   37         74
##   $110K - $130K             2    38             4      9    9         20
##   $130K - $150K             6    49             5      8   15         21
##   $150K +                   3    17             0      4    4          8
##   $30K - $50K              32   299            31     46   67        114
##   $50K - $70K              12   160             8     19   36         57
##   $70K - $90K              10   126            10     16   20         47
##   $90K - $110K              5    40             5      3   10         14
##                
##                 Frozen Desserts Frozen Entrees Fruit Hardware Hot Beverages
##   $10K - $30K                75             20   150       31            48
##   $110K - $130K              17             10    29        3            11
##   $130K - $150K              17              5    48       10             9
##   $150K +                     8              2    10        1             5
##   $30K - $50K               112             35   252       41            79
##   $50K - $70K                44             21   136       25            33
##   $70K - $90K                36             18   104       13            26
##   $90K - $110K               14              7    36        5            15
##                
##                 Hygiene Jams and Jellies Kitchen Products Magazines Meat
##   $10K - $30K        36              137               47        49  156
##   $110K - $130K       6               31                5        17   41
##   $130K - $150K      14               32               14         9   52
##   $150K +             4                8                3         1   14
##   $30K - $50K        62              185               74        65  253
##   $50K - $70K        37              103               51        36  115
##   $70K - $90K        29               71               20        18  100
##   $90K - $110K        9               21                3         7   30
##                
##                 Miscellaneous Packaged Vegetables Pain Relievers Paper Products
##   $10K - $30K              10                   9             42             70
##   $110K - $130K             1                   1              7             19
##   $130K - $150K             6                   1              8             17
##   $150K +                   0                   2              5              8
##   $30K - $50K               8                  20             61            101
##   $50K - $70K              14                   8             34             67
##   $70K - $90K               2                   7             30             46
##   $90K - $110K              1                   0              5             17
##                
##                 Pizza Plastic Products Pure Juice Beverages Seafood Side Dishes
##   $10K - $30K      50               41                   34      17          36
##   $110K - $130K    13                6                    9       3           2
##   $130K - $150K    12                7                    5       8           8
##   $150K +           1                2                    5       5           3
##   $30K - $50K      59               33                   52      44          53
##   $50K - $70K      31               31                   25      11          23
##   $70K - $90K      15               17                   26      12          23
##   $90K - $110K     13                4                    9       2           5
##                
##                 Snack Foods Specialty Starchy Foods Vegetables
##   $10K - $30K           329        65            70        385
##   $110K - $130K          85        13            18         74
##   $130K - $150K          83        18            15         87
##   $150K +                35         5             5         32
##   $30K - $50K           533        96            85        551
##   $50K - $70K           274        50            48        300
##   $70K - $90K           184        32            28        215
##   $90K - $110K           77        10             8         84
print(round(percent_income_cat, 2))
##                
##                 Baking Goods Bathroom Products Beer and Wine Bread
##   $10K - $30K           3.85              2.75          2.59  3.50
##   $110K - $130K         2.80              2.49          2.18  3.58
##   $130K - $150K         2.89              2.50          1.97  3.16
##   $150K +               4.03              2.93          1.10  3.66
##   $30K - $50K           3.28              2.52          2.63  2.91
##   $50K - $70K           3.63              2.11          2.57  2.66
##   $70K - $90K           3.45              2.98          2.28  2.93
##   $90K - $110K          2.94              3.26          3.75  2.12
##                
##                 Breakfast Foods Candles Candy Canned Anchovies Canned Clams
##   $10K - $30K              3.59    0.19  2.46             0.32         0.39
##   $110K - $130K            1.09    0.16  2.49             0.31         0.16
##   $130K - $150K            3.68    0.26  2.50             0.13         0.39
##   $150K +                  2.56    0.37  2.93             0.37         0.37
##   $30K - $50K              3.11    0.46  2.76             0.30         0.43
##   $50K - $70K              2.62    0.30  2.53             0.34         0.25
##   $70K - $90K              2.46    0.41  1.70             0.35         0.41
##   $90K - $110K             2.77    0.00  2.77             0.33         0.49
##                
##                 Canned Oysters Canned Sardines Canned Shrimp Canned Soup
##   $10K - $30K             0.16            0.26          0.29        3.17
##   $110K - $130K           0.62            0.31          0.00        2.95
##   $130K - $150K           0.39            0.13          0.26        2.24
##   $150K +                 0.37            0.37          0.00        2.93
##   $30K - $50K             0.22            0.39          0.35        2.98
##   $50K - $70K             0.21            0.21          0.30        2.83
##   $70K - $90K             0.29            0.18          0.12        2.93
##   $90K - $110K            0.33            0.33          0.33        1.31
##                
##                 Canned Tuna Carbonated Beverages Cleaning Supplies
##   $10K - $30K          0.42                 1.17              1.52
##   $110K - $130K        0.47                 0.93              1.24
##   $130K - $150K        0.66                 0.39              0.92
##   $150K +              1.10                 2.20              1.47
##   $30K - $50K          0.61                 1.11              1.11
##   $50K - $70K          0.80                 0.84              1.48
##   $70K - $90K          0.59                 1.35              1.46
##   $90K - $110K         0.98                 1.47              1.96
##                
##                 Cold Remedies Dairy Decongestants Drinks  Eggs Electrical
##   $10K - $30K            0.74  5.63          0.71   0.97  1.20       2.39
##   $110K - $130K          0.31  5.91          0.62   1.40  1.40       3.11
##   $130K - $150K          0.79  6.45          0.66   1.05  1.97       2.76
##   $150K +                1.10  6.23          0.00   1.47  1.47       2.93
##   $30K - $50K            0.70  6.50          0.67   1.00  1.46       2.48
##   $50K - $70K            0.51  6.75          0.34   0.80  1.52       2.41
##   $70K - $90K            0.59  7.37          0.59   0.94  1.17       2.75
##   $90K - $110K           0.82  6.53          0.82   0.49  1.63       2.28
##                
##                 Frozen Desserts Frozen Entrees Fruit Hardware Hot Beverages
##   $10K - $30K              2.43           0.65  4.85     1.00          1.55
##   $110K - $130K            2.64           1.56  4.51     0.47          1.71
##   $130K - $150K            2.24           0.66  6.32     1.32          1.18
##   $150K +                  2.93           0.73  3.66     0.37          1.83
##   $30K - $50K              2.43           0.76  5.48     0.89          1.72
##   $50K - $70K              1.86           0.89  5.74     1.05          1.39
##   $70K - $90K              2.11           1.05  6.09     0.76          1.52
##   $90K - $110K             2.28           1.14  5.87     0.82          2.45
##                
##                 Hygiene Jams and Jellies Kitchen Products Magazines  Meat
##   $10K - $30K      1.17             4.43             1.52      1.59  5.05
##   $110K - $130K    0.93             4.82             0.78      2.64  6.38
##   $130K - $150K    1.84             4.21             1.84      1.18  6.84
##   $150K +          1.47             2.93             1.10      0.37  5.13
##   $30K - $50K      1.35             4.02             1.61      1.41  5.50
##   $50K - $70K      1.56             4.35             2.15      1.52  4.85
##   $70K - $90K      1.70             4.15             1.17      1.05  5.85
##   $90K - $110K     1.47             3.43             0.49      1.14  4.89
##                
##                 Miscellaneous Packaged Vegetables Pain Relievers Paper Products
##   $10K - $30K            0.32                0.29           1.36           2.27
##   $110K - $130K          0.16                0.16           1.09           2.95
##   $130K - $150K          0.79                0.13           1.05           2.24
##   $150K +                0.00                0.73           1.83           2.93
##   $30K - $50K            0.17                0.43           1.33           2.20
##   $50K - $70K            0.59                0.34           1.43           2.83
##   $70K - $90K            0.12                0.41           1.76           2.69
##   $90K - $110K           0.16                0.00           0.82           2.77
##                
##                 Pizza Plastic Products Pure Juice Beverages Seafood Side Dishes
##   $10K - $30K    1.62             1.33                 1.10    0.55        1.17
##   $110K - $130K  2.02             0.93                 1.40    0.47        0.31
##   $130K - $150K  1.58             0.92                 0.66    1.05        1.05
##   $150K +        0.37             0.73                 1.83    1.83        1.10
##   $30K - $50K    1.28             0.72                 1.13    0.96        1.15
##   $50K - $70K    1.31             1.31                 1.05    0.46        0.97
##   $70K - $90K    0.88             0.99                 1.52    0.70        1.35
##   $90K - $110K   2.12             0.65                 1.47    0.33        0.82
##                
##                 Snack Foods Specialty Starchy Foods Vegetables
##   $10K - $30K         10.65      2.10          2.27      12.46
##   $110K - $130K       13.22      2.02          2.80      11.51
##   $130K - $150K       10.92      2.37          1.97      11.45
##   $150K +             12.82      1.83          1.83      11.72
##   $30K - $50K         11.58      2.09          1.85      11.98
##   $50K - $70K         11.56      2.11          2.03      12.66
##   $70K - $90K         10.77      1.87          1.64      12.58
##   $90K - $110K        12.56      1.63          1.31      13.70

Trực quan hóa đồ thị

library(ggplot2)
library(dplyr)

# Trực quan hóa AnnualIncome và ProductCategory
td %>%
  group_by(AnnualIncome, ProductCategory) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = AnnualIncome, y = count, fill = ProductCategory)) +
  geom_bar(stat = "identity", position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Tỷ lệ danh mục sản phẩm theo thu nhập hàng năm",
       x = "Thu nhập hàng năm", y = "Tỷ lệ phần trăm") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
## `summarise()` has grouped output by 'AnnualIncome'. You can override using the
## `.groups` argument.

Nhận xét: Biểu đồ “Tỷ lệ danh mục sản phẩm theo thu nhập hằng năm” cho thấy sự phân bố đa dạng của các nhóm sản phẩm mà khách hàng lựa chọn dựa trên mức thu nhập. Nhìn chung, các cột thu nhập có chiều cao màu sắc khá đồng đều, cho thấy không có sự thay đổi quá lớn trong tỷ lệ tiêu dùng từng danh mục sản phẩm giữa các nhóm thu nhập. Tuy nhiên, một số danh mục như “Snack Foods”, “Baking Goods” hay “Canned Vegetables” vẫn chiếm tỷ lệ đáng kể ở hầu hết các mức thu nhập. Điều này cho thấy các sản phẩm này có thể là nhu yếu phẩm phổ biến, phù hợp với nhiều đối tượng khách hàng. Mặc dù không có sự khác biệt nổi bật, nhưng xu hướng tiêu dùng nhất định có thể được phát hiện rõ hơn khi phân tích cụ thể từng nhóm sản phẩm theo thu nhập. Biểu đồ này hỗ trợ doanh nghiệp trong việc định vị và xây dựng chiến lược sản phẩm phù hợp cho từng phân khúc khách hàng theo mức thu nhập.

4.3 StateorProvince và ProductFamily

Bảng tần số chéo

table_state_prod <- table(td$StateorProvince, td$ProductFamily)
percent_state_prod <- prop.table(table_state_prod, margin = 1) * 100

print(table_state_prod)
##            
##             Drink Food Non-Consumable
##   BC           69  580            160
##   CA          258 1974            501
##   DF           65  598            152
##   Guerrero     41  272             70
##   Jalisco       5   57             13
##   OR          199 1629            434
##   Veracruz     44  322             98
##   WA          399 3287            881
##   Yucatan      48  494            112
##   Zacatecas   122  940            235
print(round(percent_state_prod, 2))
##            
##             Drink  Food Non-Consumable
##   BC         8.53 71.69          19.78
##   CA         9.44 72.23          18.33
##   DF         7.98 73.37          18.65
##   Guerrero  10.70 71.02          18.28
##   Jalisco    6.67 76.00          17.33
##   OR         8.80 72.02          19.19
##   Veracruz   9.48 69.40          21.12
##   WA         8.74 71.97          19.29
##   Yucatan    7.34 75.54          17.13
##   Zacatecas  9.41 72.47          18.12

Trực quan hóa đồ thị

# Trực quan hóa StateorProvince và ProductFamily
td %>%
  group_by(StateorProvince, ProductFamily) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = StateorProvince, y = count, fill = ProductFamily)) +
  geom_bar(stat = "identity", position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Tỷ lệ nhóm sản phẩm theo tỉnh/bang",
       x = "Tỉnh/Bang", y = "Tỷ lệ phần trăm") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
## `summarise()` has grouped output by 'StateorProvince'. You can override using
## the `.groups` argument.

Nhận xét

Bảng “Tỷ lệ nhóm sản phẩm theo bang” thể hiện sự phân bố tiêu dùng của ba nhóm sản phẩm chính là Drink, Food và Non-Consumable ở các bang khác nhau. Qua bảng này, ta có thể thấy rằng mặc dù ba nhóm sản phẩm đều được tiêu dùng tại tất cả các bang, nhưng tỷ trọng giữa chúng có sự khác biệt rõ rệt. Ví dụ, bang Veracruz và Yucatan có tỷ lệ tiêu dùng nhóm sản phẩm Food rất cao, chiếm lần lượt khoảng 81% và 74%, trong khi tỷ lệ này ở Guerrero và Jalisco lại thấp hơn đáng kể. Ngược lại, nhóm Drink chiếm tỷ lệ cao hơn tại các bang như Guerrero (khoảng 17.6%) hay Jalisco (18.3%). Nhóm Non-Consumable nhìn chung có tỷ lệ thấp hơn so với hai nhóm còn lại, dao động chủ yếu từ 17% đến 20%. Những sự khác biệt này có thể phản ánh điều kiện sống, sở thích tiêu dùng hoặc mức độ phát triển thương mại khác nhau giữa các bang. Kết quả này hữu ích cho việc thiết kế chiến lược phân phối và tiếp thị theo khu vực địa lý.

4.4 Kiểm định chi bình phương

MaritalStatus và Homeowner

# Tạo bảng tần số chéo
tab <- table(td$MaritalStatus, td$Homeowner)



# Kiểm định Chi-bình phương
result <- chisq.test(tab)

# In kết quả
print(result)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tab
## X-squared = 1241.2, df = 1, p-value < 2.2e-16

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

H₀ (Giả thuyết không.

H₁ (Giả thuyết đối).

Kết quả kiểm định:

Giá trị thống kê: 𝜒2=1241.2

Bậc tự do: d𝑓=1

Giá trị p-value rất nhỏ (< 2.2e-16)

Kết luận: Vì p-value rất nhỏ (nhỏ hơn mức ý nghĩa thông thường 0.05), nên bác bỏ giả thiết không. Điều này cho thấy có mối liên hệ thống kê có ý nghĩa giữa hai biến

AnnualIncome và ProductCategory

tab2 <- table(td$AnnualIncome, td$ProductCategory)
result2 <- chisq.test(tab2)
## Warning in chisq.test(tab2): Chi-squared approximation may be incorrect

Vì một số ô trong bảng tần số có giá trị nhỏ (thường dưới 5), khiến kiểm định Chi-bình phương không đáng tin cậy.

StateorProvince và ProductFamily

tab3 <- table(td$StateorProvince, td$ProductFamily)

result3 <- chisq.test(tab3)

print(result3)
## 
##  Pearson's Chi-squared test
## 
## data:  tab3
## X-squared = 12.3, df = 18, p-value = 0.8314

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

H₀: không có mối liên hệ hay phụ thuộc lẫn nhau.

H₁: tồn tại mối liên hệ giữa khu vực địa lý và nhóm sản phẩm.

Kết quả kiểm định:

Giá trị thống kê: 𝜒2 = 12.3

Bậc tự do: d𝑓 = 18

Giá trị p-value = 0.8314.

Kết luận:Vì giá trị p-value lớn hơn mức ý nghĩa phổ biến 0.05, chúng ta không đủ cơ sở để bác bỏ giả thiết không. Điều này cho thấy không có mối liên hệ thống kê đáng kể giữa khu vực địa lý (StateorProvince) và nhóm sản phẩm (ProductFamily) trong dữ liệu phân tích.

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

Dựa trên các phân tích về các biến định tính, nghiên cứu đã làm rõ một số đặc điểm quan trọng của khách hàng và hành vi mua sắm của họ. Cụ thể, mối quan hệ có ý nghĩa thống kê giữa tình trạng hôn nhân (MaritalStatus) và việc sở hữu nhà (Homeowner) phản ánh sự liên kết giữa các yếu tố xã hội và kinh tế trong phân khúc khách hàng. Đồng thời, phân tích các biến về thu nhập hàng năm (AnnualIncome) và loại sản phẩm (ProductCategory) cũng cho thấy sự phân bố không đồng đều, chỉ ra rằng nhóm khách hàng khác nhau có xu hướng lựa chọn sản phẩm phù hợp với mức thu nhập. Cuối cùng, mối quan hệ giữa khu vực địa lý (StateorProvince) và nhóm sản phẩm (ProductFamily) hé lộ sự khác biệt trong hành vi tiêu dùng tùy theo vùng miền, góp phần định hướng phân phối và tiếp thị hiệu quả hơn.

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

Phân tích trong bài tập này tập trung chủ yếu vào các biến định tính, do đó còn tồn tại một số hạn chế nhất định. Trước hết, các biến định tính trong bộ dữ liệu có một số giá trị thiếu (NA) ở những cột quan trọng, gây khó khăn trong việc xử lý và có thể ảnh hưởng đến kết quả phân tích nếu không được xử lý hợp lý. Mặc dù đã thực hiện các bước thay thế hoặc loại bỏ giá trị thiếu, nhưng việc này có thể làm mất đi một phần thông tin khách hàng đáng giá.

Thứ hai, một số nhóm con trong các biến phân loại có kích thước mẫu khá nhỏ, dẫn đến khó khăn trong việc áp dụng các kiểm định thống kê chuẩn như kiểm định Chi-bình phương, vì có thể vi phạm giả định về tần số kỳ vọng trong bảng tần số. Điều này hạn chế khả năng đánh giá chính xác mối quan hệ giữa các biến định tính trong những nhóm nhỏ.

Ngoài ra, việc chỉ phân tích các biến định tính mà không kết hợp với các biến định lượng (ví dụ: mức chi tiêu, số lần mua) làm hạn chế góc nhìn toàn diện về hành vi khách hàng, cũng như khả năng phát hiện các mẫu phức tạp hơn trong dữ liệu. Cuối cùng, dữ liệu thu thập được có thể chịu ảnh hưởng bởi các yếu tố bên ngoài như sai sót trong nhập liệu hoặc sự không đồng nhất trong cách phân loại, tạo ra những khó khăn khi chạy các phân tích thống kê.

5.3 Đề xuất

Dựa trên các kết quả phân tích và những hạn chế đã nêu, chúng tôi đề xuất một số hướng đi cụ thể nhằm khai thác sâu hơn dữ liệu và nâng cao hiệu quả trong việc hiểu và phục vụ khách hàng:

Mở rộng phân tích định tính kết hợp với định lượng

  • Bổ sung các biến định lượng liên quan đến hành vi mua sắm như tổng chi tiêu, tần suất mua hàng để kết hợp cùng các biến định tính đã phân tích.

  • Áp dụng các mô hình phân tích đa biến hoặc hồi quy logistic để dự báo hành vi khách hàng theo từng nhóm đặc trưng như tình trạng hôn nhân, thu nhập, sở hữu nhà.

    Phân khúc khách hàng dựa trên đặc điểm đa chiều

  • Sử dụng kỹ thuật phân cụm (clustering) kết hợp các biến định tính (tình trạng hôn nhân, địa lý, thu nhập) nhằm phân nhóm khách hàng theo hành vi và nhu cầu tiêu dùng thực tế.

  • Từ đó thiết kế các chiến lược marketing cá nhân hóa, nhắm đúng mục tiêu với từng phân khúc cụ thể, ví dụ ưu tiên nhóm có thu nhập cao hoặc nhóm độc thân có xu hướng tiêu dùng linh hoạt hơn.

    Kết hợp dữ liệu bên ngoài và mở rộng thu thập

  • Tích hợp dữ liệu về đặc điểm dân cư khu vực, xu hướng tiêu dùng theo vùng để có cái nhìn toàn diện hơn về thị trường.

  • Bổ sung dữ liệu về thời gian mua hàng, kênh phân phối để phân tích xu hướng theo mùa, ngày trong tuần, giúp tối ưu hóa kế hoạch tiếp thị và tồn kho.

    Gợi ý chiến lược kinh doanh

  • Tập trung phát triển các sản phẩm phù hợp với từng nhóm thu nhập và tình trạng hôn nhân, ví dụ sản phẩm tiện lợi cho nhóm độc thân, sản phẩm gia đình cho nhóm đã kết hôn và sở hữu nhà.

  • Đẩy mạnh chiến dịch tiếp thị theo vùng miền dựa trên sự khác biệt về sản phẩm ưa chuộng và thói quen tiêu dùng đã được phân tích.

  • Thiết kế các chương trình khuyến mãi riêng biệt cho từng phân khúc để tăng sự tương tác và mức độ trung thành của khách hàng.

LS0tDQp0aXRsZTogIkLDgEkgVOG6rFA6IFRV4bqmTiAxIg0KYXV0aG9yOiAixJDhurduZyBUaMO5eSBEdW5nIg0KZGF0ZTogIjIwMjUtMDUtMTkiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgbnVtYmVyIHNlY3Rpb246IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUgICANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICBmaWdfd2lkdGg6IDYgDQogICAgZmlnX2hlaWdodDogNCANCmtuaXRyOg0KICBvcHRzX2NodW5rOiANCiAgICBlY2hvOiBmYWxzZQ0KICAgIG1lc3NhZ2U6IGZhbHNlDQogICAgd2FybmluZzogZmFsc2UNCi0tLQ0KDQoNCiMjICoqUGjhuqduIDE6IFTDrG0gaGnhu4N1IHbDoCBDaHXhuqluIGLhu4sgROG7ryBsaeG7h3UqKg0KDQojIyMgKirEkOG7jWMgdsOgIEzDoG0gcXVlbiBE4buvIGxp4buHdToqKg0KDQpgYGB7cn0NCnRkIDwtIHJlYWQuY3N2KGZpbGUgPSAiQzovVXNlcnMvQWRtaW4vRG93bmxvYWRzL1N1cGVybWFya2V0IFRyYW5zYWN0aW9ucy5jc3YiLCBoZWFkZXIgPSBUKQ0Kc3RyKHRkKSANCmhlYWQodGQsIDYpDQp0YWlsKHRkLCA2KQ0KYGBgDQojIyMjICoqVOG7lW5nIHF1YW46KioNCiAgVOG6rXAgZOG7ryBsaeG7h3UgZ+G7k20gMTQsMDU5IHF1YW4gc8OhdCB2w6AgMTYgYmnhur9uLiBE4buxYSB0csOqbiBr4bq/dCBxdeG6oyBzdHIoKSBj4bunYSB04bqtcCBk4buvIGxp4buHdSwgZMaw4bubaSDEkcOieSBsw6AgcGjDom4gbG/huqFpIGPDoWMgYmnhur9uIHRoZW8ga2nhu4N1IGThu68gbGnhu4d1Og0KICANCiAgS2nhu4N1IGludCAoaW50ZWdlciAtIHPhu5Egbmd1ecOqbik6DQoNCiogWDogQ2jhu4kgc+G7kSBob+G6t2MgSUQgcXVhbiBzw6F0ICgxLCAyLCAzLCAuLi4pLg0KDQoqIEN1c3RvbWVySUQ6IE3DoyDEkeG7i25oIGRhbmgga2jDoWNoIGjDoG5nICg3MjIzLCA3ODQxLCAuLi4pLg0KDQoqIENoaWxkcmVuOiBT4buRIGNvbiAoMiwgNSwgMywgLi4uKS4NCg0KKiBVbml0c1NvbGQ6IFPhu5EgxJHGoW4gduG7iyBiw6FuICg1LCAzLCA0LCAuLi4pLg0KDQoqIEtp4buDdSBjaHIgKGNoYXJhY3RlciAtIGNodeG7l2kga8O9IHThu7EpOg0KDQoqIFB1cmNoYXNlRGF0ZTogTmfDoHkgbXVhIGjDoG5nICgiMjAwNy0xMi0xOCIsIC4uLikuDQoNCiogR2VuZGVyOiBHaeG7m2kgdMOtbmggKCJGIiwgIk0iKS4NCg0KKiBNYXJpdGFsU3RhdHVzOiBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gKCJTIiwgIk0iKS4NCg0KKiBIb21lb3duZXI6IFPhu58gaOG7r3UgbmjDoCAoIlkiLCAiTiIpLg0KDQoqIEFubnVhbEluY29tZTogS2hv4bqjbmcgdGh1IG5o4bqtcCAoIiQzMEsgLSAkNTBLIiwgLi4uKS4NCg0KKiBDaXR5OiBUaMOgbmggcGjhu5EgKCJMb3MgQW5nZWxlcyIsICJCcmVtZXJ0b24iLCAuLi4pLg0KDQoqIFN0YXRlb3JQcm92aW5jZTogQmFuZy904buJbmggKCJDQSIsICJXQSIsIC4uLikuDQoNCiogQ291bnRyeTogUXXhu5FjIGdpYSAoIlVTQSIsIC4uLikuDQoNCiogUHJvZHVjdEZhbWlseTogTmjDs20gc+G6o24gcGjhuqltICgiRm9vZCIsIC4uLikuDQoNCiogUHJvZHVjdERlcGFydG1lbnQ6IELhu5kgcGjhuq1uIHPhuqNuIHBo4bqpbSAoIlNuYWNrIEZvb2RzIiwgIlByb2R1Y2UiLCAuLi4pLg0KDQoqIFByb2R1Y3RDYXRlZ29yeTogRGFuaCBt4bulYyBz4bqjbiBwaOG6qW0gKCJTbmFjayBGb29kcyIsICJWZWdldGFibGVzIiwgLi4uKS4NCiANCiBLaeG7g3UgbnVtIChudW1lcmljIC0gc+G7kSB0aOG7sWMpOg0KDQoqIFJldmVudWU6IERvYW5oIHRodSAoMjcuMzgsIDE0LjkwLCAuLi4pDQoNCmBgYHtyfQ0KcXVhbF9jb2xzIDwtIGMoJ0dlbmRlcicsICdNYXJpdGFsU3RhdHVzJywgJ0hvbWVvd25lcicsICdBbm51YWxJbmNvbWUnLCAnQ2l0eScsICdTdGF0ZW9yUHJvdmluY2UnLCAnQ291bnRyeScsICdQcm9kdWN0RmFtaWx5JywgJ1Byb2R1Y3REZXBhcnRtZW50JywgJ1Byb2R1Y3RDYXRlZ29yeScpDQpzYXBwbHkodGRbcXVhbF9jb2xzXSwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkgDQoNCmBgYA0KICBL4bq/dCBxdeG6oyBjaG8gdGjhuqV5IGtow7RuZyBjw7MgZ2nDoSB0cuG7iyB0aGnhur91IChOQSkgbsOgbyB0cm9uZyBjw6FjIGPhu5l0IMSR4buLbmggdMOtbmggY+G7p2EgdOG6rXAgZOG7ryBsaeG7h3UuDQoNCiMjIyMgKipL4bq/dCBxdeG6oyB44butIGzDvSBk4buvIGxp4buHdSBzYW5nIGZhY3RvZmFjdG9yKioNCmBgYHtyfQ0KI2tp4buDbSB0cmEgY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCBjw7MgcGjhuqNpIGzDoCBmYWN0b3IgaGF5IGNoxrBhDQpmb3IgKGkgaW4gMTpuY29sKHRkKSkgew0KICBhIDwtIGlzLmZhY3Rvcih0ZFssaV0pDQogIGNhdChjb2xuYW1lcyh0ZClbaV0sIjoiLGEsIlxuIikNCn0NCmBgYA0KDQpgYGB7cn0NCiMgQ2h1eeG7g24gduG7gSBk4bqhbmcgZmFjdG9yIA0KDQpmb3IgKGkgaW4gMTpuY29sKHRkKSkgew0KICB0ZFssaV0gPC0gYXMuZmFjdG9yKHRkWyxpXSkNCn0NCg0KIyBLaeG7g20gdHJhIGzhuqFpIA0KZm9yIChpIGluIDE6bmNvbCh0ZCkpIHsNCiAgYSA8LSBpcy5mYWN0b3IodGRbLGldKQ0KICBjYXQoY29sbmFtZXModGQpW2ldLCI6IixhLCJcbiIpDQp9DQoNCmBgYA0KDQoNCiAgU2F1IGtoaSBraeG7g20gdHJhIGtp4buDdSBk4buvIGxp4buHdSBiYW4gxJHhuqd1LCBjw6FjIGJp4bq/biBwaMOibiBsb+G6oWkgbmjGsCBHZW5kZXIsIE1hcml0YWxTdGF0dXMsIEhvbWVvd25lciwgQW5udWFsSW5jb21lLCBDaXR5LCBTdGF0ZW9yUHJvdmluY2UsIENvdW50cnksIFByb2R1Y3RGYW1pbHksIFByb2R1Y3REZXBhcnRtZW50LCBQcm9kdWN0Q2F0ZWdvcnkgxJHDoyDEkcaw4bujYyBjaHV54buDbiB04burIGtp4buDdSBjaGFyYWN0ZXIgc2FuZyBmYWN0b3IuIFThu5VuZyBj4buZbmcgY8OzIDEwIGJp4bq/biDEkcOjIMSRxrDhu6NjIGNodXnhu4NuIMSR4buVaSB0aMOgbmggY8O0bmcuDQogIA0KICBU4bqldCBj4bqjIGPDoWMgYmnhur9uIHRyw6puIMSR4buBdSBsw6AgYmnhur9uIHBow6JuIGxv4bqhaSAoY2F0ZWdvcmljYWwpLCB04bupYyBsw6AgY2jhu4kgZ+G7k20gbeG7mXQgdOG6rXAgZ2nDoSB0cuG7iyBo4buvdSBo4bqhbiBuaMawICJOYW0iLyJO4buvIiwixJDhu5ljIHRow6JuIi8iS+G6v3QgaMO0biIsLi4uIGhv4bq3YyB0w6puIGPDoWMgdGjDoG5oIHBo4buRLCBuaMOzbSBz4bqjbiBwaOG6qW0sLi4uIFZp4buHYyBjaHV54buDbiDEkeG7lWkgc2FuZyBraeG7g3UgZmFjdG9yIGjhu5cgdHLhu6MgeOG7rSBsw70gZOG7ryBsaeG7h3UgdOG7kXQgaMahbiwgZ2nDunAgUiBoaeG7g3UgcsO1IGLhuqNuIGNo4bqldCBj4bunYSBjw6FjIGPhu5l0IGThu68gbGnhu4d1IHbDoCB0aeG6v3Qga2nhu4dtIMSRxrDhu6NjIGLhu5kgbmjhu5suDQoNCiMjICoqUGjhuqduIDI6IFBow6JuIHTDrWNoIE3DtCB04bqjIE3hu5l0IGJp4bq/biDEkOG7i25oIHTDrW5oIChVbml2YXJpYXRlIERlc2NyaXB0aXZlIEFuYWx5c2lzKSoqDQoNCiMjIyAqKjEuIEdlbmRlcihnaeG7m2kgdMOtbmgpKioNCg0KICBCaeG6v24gR2VuZGVyIGzDoCBt4buZdCBiaeG6v24gxJHhu4tuaCB0w61uaCBwaMOibiBsb+G6oWkgbmjhu4sgcGjDom4sIHBo4bqjbiDDoW5oIGdp4bubaSB0w61uaCBj4bunYSBraMOhY2ggaMOgbmcgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UuDQogIA0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQojIFThuqFvIGLhuqNuZyB04bqnbiBz4buRIGNobyBHZW5kZXINCmdlbmRlcl9mcmVxIDwtIHRhYmxlKHRkJEdlbmRlcikNCmdlbmRlcl9kZiA8LSBhcy5kYXRhLmZyYW1lKGdlbmRlcl9mcmVxKQ0KY29sbmFtZXMoZ2VuZGVyX2RmKSA8LSBjKCJHZW5kZXIiLCAiQ291bnQiKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIGPhu5l0DQpnZ3Bsb3QoZ2VuZGVyX2RmLCBhZXMoeCA9IEdlbmRlciwgeSA9IENvdW50LCBmaWxsID0gR2VuZGVyKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjYpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibGlnaHRncmVlbiIsICJsaWdodHBpbmsiKSkgKw0KICBsYWJzKHRpdGxlID0gIkJp4buDdSDEkeG7kyBz4buRIGzGsOG7o25nIHRoZW8gR2nhu5tpIHTDrW5oIiwgeCA9ICJHaeG7m2kgdMOtbmgiLCB5ID0gIlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCiAgUGjDom4gdMOtY2ggbcO0IHThuqMgY2hvIHRo4bqleSBjxqEgY+G6pXUgZ2nhu5tpIHTDrW5oIHRyb25nIGLhu5kgZOG7ryBsaeG7h3Uga2jDoSDEkeG7k25nIMSR4buBdSwgduG7m2kgdOG7tyBs4buHIG7hu68gbMOgIDUxJSB2w6AgbmFtIGNoaeG6v20gNDklLiBT4buxIHBow6JuIGLhu5EgZ+G6p24gbmjGsCB0xrDGoW5nIMSRxrDGoW5nIG7DoHkgcGjhuqNuIMOhbmggc+G7sSBjw6JuIGLhurFuZyBnaeG7m2ksIGfDs3AgcGjhuqduIG7Dom5nIGNhbyDEkeG7mSB0aW4gY+G6rXkgY+G7p2EgY8OhYyBr4bq/dCBxdeG6oyBwaMOibiB0w61jaCBzYXUgbsOgeS4gTmjhu50gdsOgbyB2aeG7h2Mga2jDtG5nIGPDsyBz4buxIHRoacOqbiBs4buHY2ggxJHDoW5nIGvhu4MgZ2nhu69hIGhhaSBuaMOzbSBnaeG7m2kgdMOtbmgsIG5ndXkgY8ahIHNhaSBs4buHY2ggZG8gY2jhu41uIG3huqt1IMSRxrDhu6NjIGdp4bqjbSB0aGnhu4N1LiDEkOG7k25nIHRo4budaSwgc+G7sSDEkeG7k25nIMSR4buBdSBuw6B5IGPFqW5nIGjhu5cgdHLhu6MgdOG7kXQgY2hvIHZp4buHYyB4w6J5IGThu7FuZyB2w6Aga2nhu4NtIMSR4buLbmggY8OhYyBtw7QgaMOsbmggdGjhu5FuZyBrw6ogY8OzIHnhur91IHThu5EgcGjDom4gdMOtY2ggdGhlbyBnaeG7m2kuDQogIA0KIyMjICoqMi4gTWFyaXRhbFN0YXR1cyAodMOsbmggdHLhuqFuZyBow7RuIG5ow6JuKSoqDQoNCiAgQmnhur9uIE1hcml0YWxTdGF0dXMgcGjhuqNuIMOhbmggdHLhuqFuZyB0aMOhaSBow7RuIG5ow6JuIGPhu6dhIG5nxrDhu51pIHRpw6p1IGTDuW5nLCB24bubaSBrw70gaGnhu4d1IOKAmFPigJkgdMawxqFuZyDhu6luZyB24bubaSBuaMOzbSDEkeG7mWMgdGjDom4gdsOgIOKAmE3igJkgY2hvIG5ow7NtIMSRw6MgbOG6rXAgZ2lhIMSRw6xuaC4gxJDDonkgbMOgIG3hu5l0IGJp4bq/biDEkeG7i25oIHTDrW5oIHRodeG7mWMgZOG6oW5nIHBow6JuIMSRw7RpLCB0aMaw4budbmcgxJHGsOG7o2Mga2hhaSB0aMOhYyB0cm9uZyBjw6FjIG5naGnDqm4gY+G7qXUgaMOgbmggdmkgxJHhu4MgcGjDom4gYmnhu4d0IHPhu7Ega2jDoWMgbmhhdSB0cm9uZyB0aMOzaSBxdWVuIGNoaSB0acOqdSBnaeG7r2EgY8OhYyDEkeG7kWkgdMaw4bujbmcga2jDoWNoIGjDoG5nLiBDaOG6s25nIGjhuqFuLCBuaOG7r25nIG5nxrDhu51pIGNoxrBhIGvhur90IGjDtG4gY8OzIHh1IGjGsOG7m25nIGNoaSB0acOqdSBjaG8gbmh1IGPhuqd1IGPDoSBuaMOibiwgdHJvbmcga2hpIG5o4buvbmcgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIHRoxrDhu51uZyDGsHUgdGnDqm4gbXVhIHPhuq9tIGNobyBo4buZIGdpYSDEkcOsbmggaG/hurdjIGPDom4gbmjhuq9jIGvhu7kgbMaw4buhbmcgduG7gSBt4bq3dCB0w6BpIGNow61uaC4gVmnhu4djIMSRxrBhIGJp4bq/biBuw6B5IHbDoG8gcXXDoSB0csOsbmggcGjDom4gdMOtY2gga2jDtG5nIGNo4buJIGdpw7pwIG5o4bqtbiBkaeG7h24gcsO1IGjGoW4gxJHhurdjIMSRaeG7g20gbmjDom4ga2jhuql1IGjhu41jIG3DoCBjw7JuIGjhu5cgdHLhu6MgZG9hbmggbmdoaeG7h3AgdHJvbmcgdmnhu4djIHRoaeG6v3Qga+G6vyBjaGnhur9uIGzGsOG7o2MgdGnhur9wIHRo4buLLCBk4buxIMSRb8OhbiBow6BuaCB2aSB2w6AgcGjDom4gY2hpYSB0aOG7iyB0csaw4budbmcgbeG7pWMgdGnDqnUgbeG7mXQgY8OhY2ggY2jDrW5oIHjDoWMgaMahbi4NCiAgDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBU4bqhbyBi4bqjbmcgdOG6p24gc+G7kSBjaG8gTWFyaXRhbFN0YXR1cw0KbWFyaXRhbF9mcmVxIDwtIHRhYmxlKHRkJE1hcml0YWxTdGF0dXMpDQptYXJpdGFsX2RmIDwtIGFzLmRhdGEuZnJhbWUobWFyaXRhbF9mcmVxKQ0KY29sbmFtZXMobWFyaXRhbF9kZikgPC0gYygiTWFyaXRhbFN0YXR1cyIsICJDb3VudCIpDQoNCiMgVMOtbmggcGjhuqduIHRyxINtIHbDoCBuaMOjbg0KbWFyaXRhbF9kZiRQZXJjZW50YWdlIDwtIHJvdW5kKG1hcml0YWxfZGYkQ291bnQgLyBzdW0obWFyaXRhbF9kZiRDb3VudCkgKiAxMDAsIDEpDQptYXJpdGFsX2RmJExhYmVsIDwtIHBhc3RlMChtYXJpdGFsX2RmJFBlcmNlbnRhZ2UsICIlIikNCg0KIyBW4bq9IGJp4buDdSDEkeG7kyB0csOybiB24bubaSBuaMOjbiAlDQpnZ3Bsb3QobWFyaXRhbF9kZiwgYWVzKHggPSAiIiwgeSA9IENvdW50LCBmaWxsID0gTWFyaXRhbFN0YXR1cykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTGFiZWwpLCANCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLCANCiAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDQuNSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJsaWdodGJsdWUiLCAibGlnaHRjb3JhbCIpKSArDQogIGxhYnModGl0bGUgPSAiQmnhu4N1IMSR4buTIHRyw7JuIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiIsIGZpbGwgPSAiVMOsbmggdHLhuqFuZyIpICsNCiAgdGhlbWVfdm9pZCgpDQoNCmBgYA0KDQogIEThu68gbGnhu4d1IHRo4buRbmcga8OqIGNobyB0aOG6pXkgbmjDs20ga2jDoWNoIGjDoG5nIMSR4buZYyB0aMOibiBjaGnhur9tIHThu7cgbOG7hyBraG/huqNuZyA1MSwyJSwgdHJvbmcga2hpIG5ow7NtIMSRw6Mga+G6v3QgaMO0biBjaGnhur9tIDQ4LDglLiBU4bu3IGzhu4cgbsOgeSBjaG8gdGjhuqV5IHPhu7EgcGjDom4gYuG7lSBnaeG7r2EgaGFpIHRy4bqhbmcgdGjDoWkgaMO0biBuaMOibiBraMOhIGPDom4gYuG6sW5nLCBwaOG6o24gw6FuaCB0w61uaCDEkeG6oWkgZGnhu4duIHjDoyBo4buZaSB0xrDGoW5nIMSR4buRaSB04buRdCBj4bunYSB04bqtcCBk4buvIGxp4buHdS4gVmnhu4djIG5ow7NtIMSR4buZYyB0aMOibiBjaGnhur9tIMawdSB0aOG6vyBuaOG6uSBjw7MgdGjhu4MgbMOgIGThuqV1IGhp4buHdSBjaG8gdGjhuqV5IHBo4bqnbiBs4bubbiBraMOhY2ggaMOgbmcgY8OzIHh1IGjGsOG7m25nIHPhu5FuZyBt4buZdCBtw6xuaCwgdOG7qyDEkcOzIGfhu6NpIG3hu58gbmh1IGPhuqd1IHRpw6p1IGTDuW5nIHRoacOqbiB24buBIGPDoSBuaMOibiBow7NhIHbDoCBsaW5oIGhv4bqhdCBoxqFuLiBUaMO0bmcgdGluIG7DoHkgY8OzIHRo4buDIGzDoCBjxqEgc+G7nyBo4buvdSDDrWNoIGNobyB2aeG7h2MgxJFp4buBdSBjaOG7iW5oIGNoaeG6v24gbMaw4bujYyB0aeG6v3AgdGjhu4sgaG/hurdjIHRoaeG6v3Qga+G6vyBz4bqjbiBwaOG6qW0gcGjDuSBo4bujcCB24bubaSDEkeG6t2MgxJFp4buDbSBj4bunYSBuaMOzbSBraMOhY2ggaMOgbmcgY2jhu6cgxJHhuqFvLg0KDQojIyMgKiozLiBIb21lb3duZXIqKg0KDQogIEJp4bq/biBIb21lb3duZXIgdGjhu4MgaGnhu4duIHRow7RuZyB0aW4gduG7gSBxdXnhu4FuIHPhu58gaOG7r3UgbmjDoCDhu58gY+G7p2Ega2jDoWNoIGjDoG5nLCB0cm9uZyDEkcOzIGvDvSBoaeG7h3Ug4oCYWeKAmSDEkeG6oWkgZGnhu4duIGNobyBuaOG7r25nIG5nxrDhu51pIGPDsyBuaMOgIHJpw6puZyB2w6Ag4oCYTuKAmSBkw6BuaCBjaG8gbmjhu69uZyBuZ8aw4budaSBjaMawYSBz4bufIGjhu691IG5ow6AuIMSQw6J5IGzDoCBt4buZdCBiaeG6v24gcGjDom4gbG/huqFpIG5o4buLIHBow6JuLCB0aMaw4budbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcgdHJvbmcgcGjDom4gdMOtY2ggxJHhu4MgxJHDoW5oIGdpw6EgbsSDbmcgbOG7sWMgdMOgaSBjaMOtbmggaG/hurdjIG3hu6ljIMSR4buZIOG7lW4gxJHhu4tuaCBraW5oIHThur8gY+G7p2EgxJHhu5FpIHTGsOG7o25nIG5naGnDqm4gY+G7qXUuIFZp4buHYyBz4bufIGjhu691IG5ow6Aga2jDtG5nIGNo4buJIHBo4bqjbiDDoW5oIHBo4bqnbiBuw6BvIHRodSBuaOG6rXAgdsOgIHTDoGkgc+G6o24gdMOtY2ggbMWpeSBj4bunYSBraMOhY2ggaMOgbmcsIG3DoCBjw7JuIGPDsyB0aOG7gyDhuqNuaCBoxrDhu59uZyDEkeG6v24gaMOgbmggdmkgY2hpIHRpw6p1IGPFqW5nIG5oxrAgbmh1IGPhuqd1IHbhu4EgY8OhYyBz4bqjbiBwaOG6qW0gdsOgIGThu4tjaCB24bulIG5o4bqldCDEkeG7i25oIOKAkyDEkeG6t2MgYmnhu4d0IHRyb25nIGPDoWMgbMSpbmggduG7sWMgbmjGsCBuZ8OibiBow6BuZywgYuG6o28gaGnhu4NtIGhv4bq3YyB0acOqdSBkw7luZyBi4buBbiB24buvbmcuDQogIA0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgVOG6oW8gYuG6o25nIHThuqduIHPhu5EgdsOgIHBo4bqnbiB0csSDbSBjaG8gYmnhur9uIEhvbWVvd25lcg0KaG9tZV9mcmVxIDwtIHRhYmxlKHRkJEhvbWVvd25lcikNCmhvbWVfZGYgPC0gYXMuZGF0YS5mcmFtZShob21lX2ZyZXEpDQpjb2xuYW1lcyhob21lX2RmKSA8LSBjKCJIb21lb3duZXIiLCAiQ291bnQiKQ0KDQojIFTDrW5oIHBo4bqnbiB0csSDbQ0KaG9tZV9kZiRQZXJjZW50YWdlIDwtIHJvdW5kKGhvbWVfZGYkQ291bnQgLyBzdW0oaG9tZV9kZiRDb3VudCkgKiAxMDAsIDEpDQpob21lX2RmJExhYmVsIDwtIHBhc3RlMChob21lX2RmJFBlcmNlbnRhZ2UsICIlIikNCg0KIyBW4bq9IGJp4buDdSDEkeG7kyBj4buZdCB24bubaSBuaMOjbiBwaOG6p24gdHLEg20NCmdncGxvdChob21lX2RmLCBhZXMoeCA9IEhvbWVvd25lciwgeSA9IENvdW50LCBmaWxsID0gSG9tZW93bmVyKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjYpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IExhYmVsKSwgdmp1c3QgPSAtMC41LCBzaXplID0gNC41KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiLCAieWVsbG93IikpICsNCiAgbGFicyh0aXRsZSA9ICJCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIHTDrG5oIHRy4bqhbmcgc+G7nyBo4buvdSBuaMOgIiwNCiAgICAgICB4ID0gIlPhu58gaOG7r3UgbmjDoCIsDQogICAgICAgeSA9ICJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCiAgVOG7tyBs4buHIGtow6FjaCBow6BuZyBz4bufIGjhu691IG5ow6AgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UgxJHhuqF0IDYwLDElLCBjYW8gaMahbiBzbyB24bubaSAzOSw5JSBjw7JuIGzhuqFpIGtow7RuZyBjw7MgbmjDoCDhu58uIFPhu7EgcGjDom4gYuG7kSBuw6B5IHBo4bqjbiDDoW5oIG3hu6ljIMSR4buZIOG7lW4gxJHhu4tuaCB0w6BpIGNow61uaCBuaOG6pXQgxJHhu4tuaCBj4bunYSBwaOG6p24gbOG7m24ga2jDoWNoIGjDoG5nLCDEkeG7k25nIHRo4budaSBjaG8gdGjhuqV5IHPhu7Ega2jDoWMgYmnhu4d0IHRp4buBbSBuxINuZyB24buBIGjDoG5oIHZpIHRpw6p1IGTDuW5nIGdp4buvYSBoYWkgbmjDs20uIFRyb25nIGtoaSBuaMOzbSBjw7MgbmjDoCBjw7MgeHUgaMaw4bubbmcgaMaw4bubbmcgxJHhur9uIGPDoWMgbOG7sWEgY2jhu41uIMSR4bqndSB0xrAgZMOgaSBo4bqhbiwgdGjDrCBuaMOzbSBraMO0bmcgc+G7nyBo4buvdSBuaMOgIGPDsyB0aOG7gyDGsHUgdGnDqm4gY8OhYyBnaeG6o2kgcGjDoXAgdGnDqnUgZMO5bmcgbGluaCBob+G6oXQgaMahbi4gRG8gxJHDsywgxJHhurdjIMSRaeG7g20gbsOgeSDEkcOzbmcgdmFpIHRyw7IgcXVhbiB0cuG7jW5nIHRyb25nIHZp4buHYyBwaMOibiB0w61jaCBuaMOibiBraOG6qXUgaOG7jWMgdsOgIGhv4bqhY2ggxJHhu4tuaCBjaGnhur9uIGzGsOG7o2MgdGnhur9wIGPhuq1uIHBow7kgaOG7o3AuDQogIA0KIyMjICoqNC4gQW5udWFsSW5jb21lKioNCg0KICBCaeG6v24gQW5udWFsSW5jb21lIG3DtCB04bqjIHRodSBuaOG6rXAgaMOgbmcgbsSDbSBj4bunYSBraMOhY2ggaMOgbmcsIMSRxrDhu6NjIGNoaWEgdGjDoG5oIGPDoWMgbmjDs20gdGhlbyB04burbmcga2hv4bqjbmcgbeG7qWMgdMSDbmcgZOG6p24uIMSQw6J5IGzDoCBt4buZdCBiaeG6v24gcGjDom4gbG/huqFpIGPDsyB0aOG7qSB04buxIChvcmRpbmFsKSwgcGjhuqNuIMOhbmggc+G7sSBraMOhYyBiaeG7h3QgduG7gSBraOG6oyBuxINuZyB0w6BpIGNow61uaCBnaeG7r2EgY8OhYyBuaMOzbSBraMOhY2ggaMOgbmcuIFRo4bupIHThu7Egc+G6r3AgeOG6v3AgY8OhYyBt4bupYyB0aHUgbmjhuq1wIGNobyBwaMOpcCBraGFpIHRow6FjIHPDonUgaMahbiB0cm9uZyBwaMOibiB0w61jaCBuaMOibiBraOG6qXUgaOG7jWMgdsOgIHBow6JuIHThuqduZyB0acOqdSBkw7luZy4NCiAgDQpgYGB7cn0NCmxpYnJhcnkoa25pdHIpDQoNCiMgVGjhu5FuZyBrw6ogdOG6p24gc3XhuqV0DQp0YWJsZV9pbmNvbWUgPC0gdGFibGUodGQkQW5udWFsSW5jb21lKQ0KcHJvcF9pbmNvbWUgPC0gcHJvcC50YWJsZSh0YWJsZV9pbmNvbWUpICogMTAwICAjIFThu7cgbOG7hyBwaOG6p24gdHLEg20NCg0KaW5jb21lX2ZyZXEgPC0gZGF0YS5mcmFtZSgNCiAgQW5udWFsSW5jb21lID0gbmFtZXModGFibGVfaW5jb21lKSwNCiAgRnJlcXVlbmN5ID0gYXMudmVjdG9yKHRhYmxlX2luY29tZSksDQogIFBlcmNlbnRhZ2UgPSByb3VuZChhcy52ZWN0b3IocHJvcF9pbmNvbWUpLCAyKQ0KKQ0KDQprYWJsZShpbmNvbWVfZnJlcSwgY29sLm5hbWVzID0gYygiS2hv4bqjbmcgdGh1IG5o4bqtcCIsICJU4bqnbiBzdeG6pXQiLCAiVOG7tyBs4buHICglKSIpLA0KICAgICAgY2FwdGlvbiA9ICJC4bqjbmcgcGjDom4gcGjhu5FpIHRodSBuaOG6rXAiKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBT4bqvcCB44bq/cCB0aGVvIFBlcmNlbnRhZ2UgZ2nhuqNtIGThuqduDQppbmNvbWVfZnJlcSA8LSBpbmNvbWVfZnJlcVtvcmRlcihpbmNvbWVfZnJlcSRQZXJjZW50YWdlLCBkZWNyZWFzaW5nID0gVFJVRSksIF0NCg0KIyBW4bq9IGJp4buDdSDEkeG7kyBj4buZdCBuZ2FuZw0KZ2dwbG90KGluY29tZV9mcmVxLCBhZXMoeCA9IHJlb3JkZXIoQW5udWFsSW5jb21lLCBQZXJjZW50YWdlKSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBBbm51YWxJbmNvbWUpKSArDQogIGdlb21fY29sKHdpZHRoID0gMC43LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnModGl0bGUgPSAiVOG7tyBs4buHIHBo4bqnbiB0csSDbSB0aHUgbmjhuq1wIGjDoG5nIG7Eg20gY+G7p2Ega2jDoWNoIGjDoG5nIiwNCiAgICAgICB4ID0gIktob+G6o25nIHRodSBuaOG6rXAiLA0KICAgICAgIHkgPSAiVOG7tyBs4buHICglKSIpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCiAgUGjDom4gYuG7kSB0aHUgbmjhuq1wIGPhu6dhIGtow6FjaCBow6BuZyBjaG8gdGjhuqV5IG5ow7NtIGPDsyBz4buRIGzGsOG7o25nIMSRw7RuZyDEkeG6o28gbmjhuqV0IHRodeG7mWMgdsOgbyBraG/huqNuZyB0aHUgbmjhuq1wIHThu6sgMzAuMDAwIMSR4bq/biA1MC4wMDAgxJHDtCBsYSwgduG7m2kgaMahbiA0LjYwMCBjw6EgbmjDom4uIE5ow7NtIHRodSBuaOG6rXAgdGjhuqVwLCBu4bqxbSB0cm9uZyBraG/huqNuZyAxMC4wMDAgxJHhur9uIDMwLjAwMCDEkcO0IGxhLCBjxaluZyBjaGnhur9tIHThu7cgbOG7hyDEkcOhbmcga+G7gyB24bubaSBn4bqnbiAzLjEwMCBraMOhY2ggaMOgbmcuIEPDoWMgcGjDom4ga2jDumMgdGh1IG5o4bqtcCB0cnVuZyBiw6xuaCBuaMawIDUwLjAwMCDEkeG6v24gNzAuMDAwIMSRw7QgbGEgdsOgIDcwLjAwMCDEkeG6v24gOTAuMDAwIMSRw7QgbGEgbOG6p24gbMaw4bujdCBjw7Mga2hv4bqjbmcgMi4zNzAgdsOgIDEuNzAwIGtow6FjaCBow6BuZy4gTmfGsOG7o2MgbOG6oWksIHPhu5EgbMaw4bujbmcga2jDoWNoIGjDoG5nIHRodeG7mWMgY8OhYyBuaMOzbSB0aHUgbmjhuq1wIGNhbyBoxqFuLCB04burIDkwLjAwMCDEkeG6v24gdHLDqm4gMTUwLjAwMCDEkcO0IGxhLCB0xrDGoW5nIMSR4buRaSBraGnDqm0gdOG7kW4sIGRhbyDEkeG7mW5nIHRyb25nIGtob+G6o25nIHThu6sgMjcwIMSR4bq/biA3NjAgY8OhIG5ow6JuLiBOaOG7r25nIGNvbiBz4buRIG7DoHkgY2hvIHRo4bqleSDEkWEgcGjhuqduIGtow6FjaCBow6BuZyB0cm9uZyBi4buZIGThu68gbGnhu4d1IHThuq1wIHRydW5nIGNo4bunIHnhur91IOG7nyBjw6FjIG5ow7NtIHRodSBuaOG6rXAgdGjhuqVwIMSR4bq/biB0cnVuZyBiw6xuaCwgdHJvbmcga2hpIG5ow7NtIHRodSBuaOG6rXAgY2FvIGPDsyBxdXkgbcO0IGjhuqFuIGNo4bq/IGjGoW4gxJHDoW5nIGvhu4MuDQogIA0KIyMjICoqNS4gQ2l0eSoqDQoNCiAgQmnhur9uIENpdHkgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UgdGjhu4MgaGnhu4duIMSR4buLYSDEkWnhu4NtIHRow6BuaCBwaOG7kSBuxqFpIGdpYW8gZOG7i2NoIG11YSBz4bqvbSBkaeG7hW4gcmEuIMSQw6J5IGzDoCBt4buZdCBiaeG6v24gcGjDom4gbG/huqFpIChxdWFsaXRhdGl2ZSB2YXJpYWJsZSkgduG7m2kgY8OhYyBnacOhIHRy4buLIMSRYSBk4bqhbmcgbmjGsCBMb3MgQW5nZWxlcywgQnJlbWVydG9uLCBQb3J0bGFuZCwgU2FsZW0sIFRhY29tYSwgdsOgIG5oaeG7gXUgdGjDoG5oIHBo4buRIGtow6FjLiBCaeG6v24gbsOgeSBo4buXIHRy4bujIHZp4buHYyBwaMOibiB0w61jaCBz4buxIHBow6JuIGLhu5EgZ2lhbyBk4buLY2ggdGhlbyBraHUgduG7sWMgxJHhu4thIGzDvSwgZ2nDunAga2jDoW0gcGjDoSBow6BuaCB2aSBtdWEgc+G6r20gdGhlbyB2w7luZywgbmjhuq1uIGRp4buHbiBjw6FjIHRo4buLIHRyxrDhu51uZyBxdWFuIHRy4buNbmcgaG/hurdjIHBow6F0IGhp4buHbiB4dSBoxrDhu5tuZyB0acOqdSBkw7luZyB0aGVvIHThu6tuZyDEkeG7i2EgcGjGsMahbmcuDQogIA0KYGBge3J9DQpsaWJyYXJ5KGtuaXRyKQ0KDQojIFRo4buRbmcga8OqIHThuqduIHN14bqldA0KdGFibGVfY2l0eSA8LSB0YWJsZSh0ZCRDaXR5KQ0KcHJvcF9jaXR5IDwtIHByb3AudGFibGUodGFibGVfY2l0eSkgKiAxMDAgICMgVOG7tyBs4buHIHBo4bqnbiB0csSDbQ0KDQojIEvhur90IGjhu6NwIHRow6BuaCBkYXRhIGZyYW1lIA0KY2l0eV9mcmVxIDwtIGRhdGEuZnJhbWUoDQogIENpdHkgPSBuYW1lcyh0YWJsZV9jaXR5KSwNCiAgRnJlcXVlbmN5ID0gYXMudmVjdG9yKHRhYmxlX2NpdHkpLA0KICBQZXJjZW50YWdlID0gcm91bmQoYXMudmVjdG9yKHByb3BfY2l0eSksIDIpDQopDQoNCiMgSGnhu4NuIHRo4buLIGLhuqNuZyByw7UgcsOgbmcgYuG6sW5nIGthYmxlDQprYWJsZShjaXR5X2ZyZXEsIGFsaWduID0gImxyciIsIGNhcHRpb24gPSAiQuG6o25nIHThuqduIHN14bqldCB2w6AgdOG7tyBs4buHIHBo4bqnbiB0csSDbSB0aGVvIHRow6BuaCBwaOG7kSIpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5cikNCg0KDQojIENodXnhu4NuIGThu68gbGnhu4d1IHNhbmcgxJHhu4tuaCBk4bqhbmcgbG9uZw0KY2l0eV9sb25nIDwtIGNpdHlfZnJlcSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKEZyZXF1ZW5jeSwgUGVyY2VudGFnZSksDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJNZXRyaWMiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIHbhu5tpIGZhY2V0DQpnZ3Bsb3QoY2l0eV9sb25nLCBhZXMoeCA9IHJlb3JkZXIoQ2l0eSwgLVZhbHVlKSwgeSA9IFZhbHVlLCBmaWxsID0gTWV0cmljKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGZhY2V0X3dyYXAofk1ldHJpYywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicyh0aXRsZSA9ICJT4buRIGzGsOG7o25nIHbDoCBU4bu3IGzhu4cgcGjhuqduIHRyxINtIGtow6FjaCBow6BuZyB0aGVvIFRow6BuaCBwaOG7kSIsDQogICAgICAgeCA9ICJUaMOgbmggcGjhu5EiLCB5ID0gIiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQoNCmBgYA0KDQogIEThu68gbGnhu4d1IGNobyB0aOG6pXkga2jDoWNoIGjDoG5nIHBow6JuIGLhu5EgdOG6oWkgbmhp4buBdSB0aMOgbmggcGjhu5Ega2jDoWMgbmhhdSwgdHJvbmcgxJHDsyBt4buZdCBz4buRIMSR4buLYSBwaMawxqFuZyBu4buVaSBi4bqtdCB24bubaSBz4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyBs4bubbi4gU2FsZW0gZOG6q24gxJHhuqd1IHbhu5tpIDEuMzg2IGtow6FjaCwgY2hp4bq/bSBraG/huqNuZyAxMCUgdOG7lW5nIHPhu5EgcXVhbiBzw6F0LiBUaeG6v3AgdGhlbyBsw6AgVGFjb21hIHbhu5tpIDEuMjU3IGtow6FjaCB2w6AgU2VhdHRsZSB24bubaSA5MjIga2jDoWNoLCBwaOG6o24gw6FuaCBz4buxIHThuq1wIHRydW5nIGtow6FjaCBow6BuZyB04bqhaSBjw6FjIHbDuW5nIMSRw7QgdGjhu4sgbsOgeS4gTmfGsOG7o2MgbOG6oWksIGPDoWMgdGjDoG5oIHBo4buRIG5oxrAgR3VhZGFsYWphcmEgKDc1IGtow6FjaCksIFNhbiBGcmFuY2lzY28gKDEzMCBraMOhY2gpIHbDoCBCZWxsaW5naGFtICgxNDMga2jDoWNoKSBnaGkgbmjhuq1uIHPhu5EgbMaw4bujbmcga2jDoWNoIGjDoG5nIHTGsMahbmcgxJHhu5FpIHRo4bqlcCwgY2hvIHRo4bqleSBz4buxIHBow6JuIGLhu5Ega2jDtG5nIMSR4buTbmcgxJHhu4F1IHRyb25nIHThuq1wIGThu68gbGnhu4d1LiBN4buZdCBz4buRIHRow6BuaCBwaOG7kSBraMOhYyBuaMawIFBvcnRsYW5kICg4NzYga2jDoWNoKSwgU3Bva2FuZSAoODc1IGtow6FjaCkgdsOgIFNhbiBEaWVnbyAoODY2IGtow6FjaCkgY8OzIGzGsOG7o25nIGtow6FjaCBow6BuZyBn4bqnbiB0xrDGoW5nIMSRxrDGoW5nLCBu4bqxbSB0cm9uZyBuaMOzbSBjw7Mgc+G7kSBsxrDhu6NuZyBjYW8gbmjGsG5nIGtow7RuZyBjw7Mgc+G7sSBraMOhYyBiaeG7h3QgxJHDoW5nIGvhu4MuVOG7lW5nIHRo4buDLCBr4bq/dCBxdeG6oyBtaW5oIGjhu41hIHh1IGjGsOG7m25nIHThuq1wIHRydW5nIGtow6FjaCBow6BuZyBjaOG7pyB54bq/dSB04bqhaSBjw6FjIHRow6BuaCBwaOG7kSBs4bubbiBob+G6t2MgdHJ1bmcgdMOibSBraW5oIHThur8sIHRyb25nIGtoaSBjw6FjIGtodSB24buxYyBuaOG7jyBoxqFuIGPDsyBt4bupYyDEkeG7mSB0aGFtIGdpYSB0aOG7iyB0csaw4budbmcgdGjhuqVwIGjGoW4uDQoNCiMjIyAqKjYuU3RhdGVvclByb3ZpbmNlKioNCg0KICBCaeG6v24gU3RhdGVvclByb3ZpbmNlIMSR4bqhaSBkaeG7h24gY2hvIGPDoWMga2h1IHbhu7FjIGjDoG5oIGNow61uaCBuaMawIGJhbmcgaG/hurdjIHThu4luaCBuxqFpIGtow6FjaCBow6BuZyBjxrAgdHLDuiBob+G6t2MgdGjhu7FjIGhp4buHbiBnaWFvIGThu4tjaC4gQuG7mSBnacOhIHRy4buLIGJhbyBn4buTbSBuaGnhu4F1IGtodSB24buxYyDEkWEgZOG6oW5nIG5oxrAgQkMsIENBLCBERiwgR3VlcnJlcm8sIEphbGlzY28sIE9SLCBWZXJhY3J1eiwgV0EsIFl1Y2F0YW4gdsOgIFphY2F0ZWNhcywgcGjhuqNuIMOhbmggcGjhuqFtIHZpIMSR4buLYSBsw70gcuG7mW5nIGzhu5tuIGPhu6dhIGThu68gbGnhu4d1LiBWaeG7h2MgcGjDom4gdMOtY2ggcGjDom4gYuG7kSBraMOhY2ggaMOgbmcgdGhlbyBjw6FjIGJhbmcgaG/hurdjIHThu4luaCBjdW5nIGPhuqVwIGPDoWkgbmjDrG4gc8OidSBz4bqvYyB24buBIMSR4bq3YyDEkWnhu4NtIHbDuW5nIG1p4buBbiB2w6AgdGjDs2kgcXVlbiB0acOqdSBkw7luZywgcXVhIMSRw7MgaOG7lyB0cuG7oyBkb2FuaCBuZ2hp4buHcCB4w6J5IGThu7FuZyBjw6FjIGNoaeG6v24gbMaw4bujYyB0aeG6v3AgdGjhu4sgaGnhu4d1IHF14bqjIGPFqW5nIG5oxrAgcXXhuqNuIGzDvSBraG8gduG6rW4gaOG7o3AgbMO9LiBEbyDEkcOieSBsw6AgYmnhur9uIMSR4buLbmggZGFuaCwgcGjDom4gdMOtY2ggY2jhu6cgeeG6v3UgdOG6rXAgdHJ1bmcgdsOgbyB04bqnbiBzdeG6pXQgdsOgIHThu7cgbOG7hyBwaOG6p24gdHLEg20gY+G7p2EgdOG7q25nIGtodSB24buxYywgdGhheSB2w6wgc+G7rSBk4bulbmcgY8OhYyB0aOG7kW5nIGvDqiBtw7QgdOG6oyBuaMawIHRydW5nIGLDrG5oIGhheSDEkeG7mSBs4buHY2ggY2h14bqpbi4NCiAgDQpgYGB7cn0NCiMgVGjhu5FuZyBrw6ogdOG6p24gc3XhuqV0DQp0YWJsZV9zdGF0ZSA8LSB0YWJsZSh0ZCRTdGF0ZW9yUHJvdmluY2UpDQpwcm9wX3N0YXRlIDwtIHByb3AudGFibGUodGFibGVfc3RhdGUpICogMTAwICAjIFThu7cgbOG7hyBwaOG6p24gdHLEg20NCg0KIyBL4bq/dCBo4bujcCB0aMOgbmggZGF0YSBmcmFtZSANCnN0YXRlX2ZyZXEgPC0gZGF0YS5mcmFtZSgNCiAgU3RhdGVPclByb3ZpbmNlID0gbmFtZXModGFibGVfc3RhdGUpLA0KICBGcmVxdWVuY3kgPSBhcy52ZWN0b3IodGFibGVfc3RhdGUpLA0KICBQZXJjZW50YWdlID0gcm91bmQoYXMudmVjdG9yKHByb3Bfc3RhdGUpLCAyKSkNCg0KcHJpbnQoc3RhdGVfZnJlcSkNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpzdGF0ZV9sb25nIDwtIHN0YXRlX2ZyZXEgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhGcmVxdWVuY3ksIFBlcmNlbnRhZ2UpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiTWV0cmljIiwgdmFsdWVzX3RvID0gIlZhbHVlIikNCg0KZ2dwbG90KHN0YXRlX2ZyZXEsIGFlcyh4ID0gcmVvcmRlcihTdGF0ZU9yUHJvdmluY2UsIC1GcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJwaW5rIikgKw0KICBsYWJzKHRpdGxlID0gIkzGsOG7o25nIGtow6FjaCBow6BuZyDEkeG6v24gdOG7qyBjw6FjIGJhbmcvdOG7iW5oIiwNCiAgICAgICB4ID0gIlN0YXRlIG9yIFByb3ZpbmNlIiwNCiAgICAgICB5ID0gIkzGsOG7o25nIGtow6FjaCBow6BuZyAiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCiAgDQogIFBow6JuIGLhu5Ega2jDoWNoIGjDoG5nIHRoZW8gYmFuZyBob+G6t2MgdOG7iW5oIGNobyB0aOG6pXkgV2FzaGluZ3RvbiAoV0EpIGThuqtuIMSR4bqndSB24bubaSA0LjU2NyBraMOhY2ggaMOgbmcsIHRp4bq/cCB0aGVvIGzDoCBDYWxpZm9ybmlhIChDQSkgduG7m2kgMi43MzMgdsOgIE9yZWdvbiAoT1IpIHbhu5tpIDIuMjYyIGtow6FjaCBow6BuZywgdGjhu4MgaGnhu4duIG3hu6ljIMSR4buZIHThuq1wIHRydW5nIGNhbyB04bqhaSBjw6FjIGtodSB24buxYyBuw6B5LiBDw6FjIGJhbmcgbmjGsCBaYWNhdGVjYXMsIEJyaXRpc2ggQ29sdW1iaWEgKEJDKSB2w6AgRGlzdHJpdG8gRmVkZXJhbCAoREYpIGPFqW5nIGdoaSBuaOG6rW4gc+G7kSBsxrDhu6NuZyBraMOhY2ggaMOgbmcgxJHDoW5nIGvhu4MsIGzhuqduIGzGsOG7o3QgbMOgIDEuMjk3LCA4MDkgdsOgIDgxNS4gTmfGsOG7o2MgbOG6oWksIGPDoWMgYmFuZyBuaMawIEphbGlzY28gdsOgIEd1ZXJyZXJvIGPDsyBsxrDhu6NuZyBraMOhY2ggaMOgbmcgdGjhuqVwIGjGoW4gbmhp4buBdSwgY2jhu4kgxJHhuqF0IDc1IHbDoCAzODMuIE5oxrAgduG6rXksIHBow6JuIGLhu5Ega2jDoWNoIGjDoG5nIHRoZW8gYmFuZy904buJbmgga2jDtG5nIMSR4buTbmcgxJHhu4F1LCB24bubaSBz4buxIHThuq1wIHRydW5nIHLDtSBy4buHdCB04bqhaSBt4buZdCBz4buRIGtodSB24buxYyB0cuG7jW5nIMSRaeG7g20sIHRyb25nIGtoaSBjw6FjIHbDuW5nIGtow6FjIGPDsyBz4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyB0xrDGoW5nIMSR4buRaSBo4bqhbiBjaOG6vy4NCiAgDQojIyMgKio3LkNvdW50cnkqKg0KDQogIEJp4bq/biBDb3VudHJ5IGJp4buDdSB0aOG7iyBxdeG7kWMgZ2lhIG7GoWkga2jDoWNoIGjDoG5nIHRp4bq/biBow6BuaCBnaWFvIGThu4tjaCwgYmFvIGfhu5NtIGJhIHF14buRYyBnaWEgY2jDrW5oOiBN4bu5IChVU0EpLCBNZXhpY28gdsOgIENhbmFkYS4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgcGjhuqFtIHZpIGhv4bqhdCDEkeG7mW5nIGPhu6dhIHNpw6p1IHRo4buLIG3hu58gcuG7mW5nIHRyw6puIHRvw6BuIGLhu5kga2h1IHbhu7FjIELhuq9jIE3hu7kuDQoNCiogVuG7gSBraMOtYSBj4bqhbmggxJHhu4thIGzDvSwgZOG7ryBsaeG7h3UgcGjhuqNuIMOhbmggY2hp4bq/biBsxrDhu6NjIGtpbmggZG9hbmggxJFhIHF14buRYyBnaWEsIHThuq1wIHRydW5nIGtoYWkgdGjDoWMgdGjhu4sgdHLGsOG7nW5nIHRpw6p1IGTDuW5nIHThuqFpIGJhIHF14buRYyBnaWEgbsOgeS4NCg0KKiBT4buxIMSRYSBk4bqhbmcgcXXhu5FjIGdpYSB0cm9uZyBk4buvIGxp4buHdSBjxaluZyB04bqhbyDEkWnhu4F1IGtp4buHbiBwaMOibiB0w61jaCBz4buxIGtow6FjIGJp4buHdCB24buBIHRow7NpIHF1ZW4gdGnDqnUgZMO5bmcsIGRvYW5oIHRodSB2w6AgY8OhYyBz4bqjbiBwaOG6qW0gxrBhIGNodeG7mW5nIHRoZW8gdOG7q25nIHbDuW5nIGzDo25oIHRo4buVLg0KDQpgYGB7cn0NCiMgVGjhu5FuZyBrw6ogdOG6p24gc3XhuqV0DQp0YWJsZV9jb3UgPC0gdGFibGUodGQkQ291bnRyeSkNCnByb3BfY291IDwtIHByb3AudGFibGUodGFibGVfY291KSAqIDEwMCAgIyBU4bu3IGzhu4cgcGjhuqduIHRyxINtDQoNCiMgS+G6v3QgaOG7o3AgdGjDoG5oIGRhdGEgZnJhbWUgDQpjb3VfZnJlcSA8LSBkYXRhLmZyYW1lKA0KIGNvdSA9IG5hbWVzKHRhYmxlX2NvdSksDQogIEZyZXF1ZW5jeSA9IGFzLnZlY3Rvcih0YWJsZV9jb3UpLA0KICBQZXJjZW50YWdlID0gcm91bmQoYXMudmVjdG9yKHByb3BfY291KSwgMikpDQoNCnByaW50KGNvdV9mcmVxKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCg0KIyBHaeG6oyBz4butIGNvdV9mcmVxIGzDoCBi4bqjbmcgZ+G7k20gMiBj4buZdDogUXXhu5FjIGdpYSAoY291KSB2w6AgVOG6p24gc3XhuqV0IChGcmVxdWVuY3kpDQpjb3VfZnJlcSA8LSBjb3VfZnJlcSAlPiUNCiAgbXV0YXRlKFBlcmNlbnRhZ2UgPSByb3VuZChGcmVxdWVuY3kgLyBzdW0oRnJlcXVlbmN5KSAqIDEwMCwgMSksDQogICAgICAgICBMYWJlbCA9IHBhc3RlMChjb3UsICIgKCIsIFBlcmNlbnRhZ2UsICIlKSIpKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIHRyw7JuDQpnZ3Bsb3QoY291X2ZyZXEsIGFlcyh4ID0gIiIsIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBjb3UpKSArDQogIGdlb21fY29sKHdpZHRoID0gMSwgY29sb3IgPSAid2hpdGUiKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiVOG7tyBs4buHIGtow6FjaCBow6BuZyB0aGVvIHF14buRYyBnaWEiKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKFBlcmNlbnRhZ2UsICIlIikpLCANCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLCBzaXplID0gNCkNCg0KYGBgDQoNCiAgQmnhur9uIENvdW50cnkgdHJvbmcgYuG7mSBk4buvIGxp4buHdSBjaOG7iSBjaOG7qWEgZHV5IG5o4bqldCBnacOhIHRy4buLIOKAnFVTQeKAnSwgY2hvIHRo4bqleSB0b8OgbiBi4buZIHRow7RuZyB0aW4gxJHhu4F1IMSR4bq/biB04burIGtow6FjaCBow6BuZyBjxrAgdHLDuiB04bqhaSBIb2EgS+G7sy4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgcGjhuqFtIHZpIMSR4buLYSBsw70gY+G7p2EgZOG7ryBsaeG7h3Uga2jDoSBo4bqhbiBjaOG6vyB2w6Aga2jDtG5nIHBo4bqjbiDDoW5oIMSRxrDhu6NjIHPhu7EgxJFhIGThuqFuZyB24buBIHF14buRYyBnaWEuDQogIA0KICBWw6wgYmnhur9uIG7DoHkga2jDtG5nIGPDsyBz4buxIGJp4bq/biDEkeG7lWkgbsOgbyBraMOhYyBuZ2/DoGkg4oCcVVNB4oCdLCBuw7Mga2jDtG5nIGPDsyBnacOhIHRy4buLIHRyb25nIHZp4buHYyBwaMOibiBsb+G6oWkgaGF5IGdp4bqjaSB0aMOtY2ggdHJvbmcgcGjDom4gdMOtY2ggbcO0IHThuqMuIERvIMSRw7MsIHRyb25nIGPDoWMgYsaw4bubYyBwaMOibiB0w61jaCB0aeG6v3AgdGhlbyBuaMawIHjDonkgZOG7sW5nIG3DtCBow6xuaCBo4buTaSBxdXkgaG/hurdjIHBow6JuIMSRb+G6oW4gdGjhu4sgdHLGsOG7nW5nLCBiaeG6v24gQ291bnRyeSBjw7MgdGjhu4MgxJHGsOG7o2MgbG/huqFpIGLhu48gbuG6v3UgbeG7pWMgdGnDqnUgbmdoacOqbiBj4bupdSBraMO0bmcgYmFvIGfhu5NtIG3hu58gcuG7mW5nIHNhbmcgY8OhYyBxdeG7kWMgZ2lhIGtow6FjLg0KICANCiMjIyAqKjguUHJvZHVjdEZhbWlseSoqDQoNCmBgYHtyfQ0KIyBUaOG7kW5nIGvDqiB04bqnbiBzdeG6pXQNCnRhYmxlX2ZhbSA8LSB0YWJsZSh0ZCRQcm9kdWN0RmFtaWx5KQ0KcHJvcF9mYW0gPC0gcHJvcC50YWJsZSh0YWJsZV9mYW0pICogMTAwICAjIFThu7cgbOG7hyBwaOG6p24gdHLEg20NCg0KIyBL4bq/dCBo4bujcCB0aMOgbmggZGF0YSBmcmFtZSANCmZhbV9mcmVxIDwtIGRhdGEuZnJhbWUoDQogZmFtID0gbmFtZXModGFibGVfZmFtKSwNCiAgRnJlcXVlbmN5ID0gYXMudmVjdG9yKHRhYmxlX2ZhbSksDQogIFBlcmNlbnRhZ2UgPSByb3VuZChhcy52ZWN0b3IocHJvcF9mYW0pLCAyKSkNCg0KcHJpbnQoZmFtX2ZyZXEpDQpgYGANCiAgDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChmYW1fZnJlcSwgYWVzKHggPSByZW9yZGVyKGZhbSwgLUZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3kpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImJsdWUiKSArDQogIGxhYnModGl0bGUgPSAiU+G7kSBsxrDhu6NuZyBraMOhY2ggaMOgbmcgxJHhur9uIHThu6sgY8OhYyBuxrDhu5tjIiwNCiAgICAgICB4ID0gIkNvdW50cnkiLA0KICAgICAgIHkgPSAiTMaw4bujbmcgIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQpgYGANCg0KICBL4bq/dCBxdeG6oyBwaMOibiB0w61jaCBk4buvIGxp4buHdSB24buBIG5ow7NtIHPhuqNuIHBo4bqpbSAoUHJvZHVjdEZhbWlseSkgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3U6DQoNCiogRHJpbms6IDEsMjUwIGdpYW8gZOG7i2NoLCBjaGnhur9tIDguODklLg0KDQoqIEZvb2Q6IDEwLDE1MyBnaWFvIGThu4tjaCwgY2hp4bq/bSA3Mi4yMiUuDQoNCiogTm9uLUNvbnN1bWFibGU6IDIsNjU2IGdpYW8gZOG7i2NoLCBjaGnhur9tIDE4Ljg5JS4NCg0KICAqKk5o4bqtbiB4w6l0OioqIE5ow7NtICJGb29kIiBjaGnhur9tIHThu7cgbOG7hyBjYW8gbmjhuqV0ICg3Mi4yMiUpLCBjaG8gdGjhuqV5IHPhuqNuIHBo4bqpbSB0aOG7sWMgcGjhuqltIGzDoCBt4bq3dCBow6BuZyBjaOG7pyDEkeG6oW8gdHJvbmcgY8OhYyBnaWFvIGThu4tjaCwgdHJvbmcga2hpICJEcmluayIgdsOgICJOb24tQ29uc3VtYWJsZSIgY8OzIHThu7cgbOG7hyB0aOG6pXAgaMahbiDEkcOhbmcga+G7gy4NCiAgDQojIyAqKlBo4bqnbiAzOiDGr+G7m2MgbMaw4bujbmcgS2hv4bqjbmcgdsOgIEtp4buDbSDEkeG7i25oIEdp4bqjIHRodXnhur90IGNobyBU4bu3IGzhu4cgKE3hu5l0IGJp4bq/bikqKg0KDQojIyMgKiozLjEgWMOhYyDEkeG7i25oIGjhuqFuZyBt4bulYyBxdWFuIHTDom0qKg0KDQogIFRhIGNo4buNbiAzIGjhuqFuZyBt4bulYyBzYXU6DQogIA0KKioxLiBHZW5kZXIgLSBO4buvIChGKSoqDQoNCmBgYHtyfQ0KDQojIEzGsHUgdOG7lW5nIHPhu5EgZMOybmcgdHJvbmcgZGF0YWZyYW1lDQpuX3RvdGFsIDwtIG5yb3codGQpDQojIHThu5VuZyBz4buRIHF1YW4gc8OhdCAob2JzZXJ2YXRpb24pIHRyb25nIHThuq1wIGThu68gbGnhu4d1Lg0Kbl9mZW1hbGUgPC0gc3VtKHRkJEdlbmRlciA9PSAiRmVtYWxlIikNCiMgVGjhu7FjIGhp4buHbiBraeG7g20gxJHhu4tuaCB04bu3IGzhu4cgbeG7mXQgbeG6q3UgKDEtc2FtcGxlIHByb3BvcnRpb24gdGVzdCkuDQpwcm9wLnRlc3Qobl9mZW1hbGUsIG5fdG90YWwsIHAgPSAwLjUsIGNvcnJlY3QgPSBUUlVFKQ0KDQoNCmBgYA0KDQpLaeG7g20gxJHhu4tuaCB04bu3IGzhu4cgbeG7mXQgbeG6q3UgY2hvIGJp4bq/biBHZW5kZXINCg0KICBHaeG6oyB0aGnhur90IGtp4buDbSDEkeG7i25oOg0KDQoqIChI4oKAKTogVOG7tyBs4buHIG7hu68gdHJvbmcgdOG7lW5nIHPhu5Ega2jDoWNoIGjDoG5nIGLhurFuZyA1MCUsIHThu6ljIHA9MC41Lg0KDQoqIChI4oKBKTogVOG7tyBs4buHIG7hu68ga2jDoWMgNTAlLCB04bupYyDwnZGd4omgMC41DQoNCiAgS+G6v3QgcXXhuqMga2nhu4NtIMSR4buLbmg6DQoNCiAgS2nhu4NtIMSR4buLbmggdOG7tyBs4buHIG3hu5l0IG3huqt1ICgxLXNhbXBsZSBwcm9wb3J0aW9uIHRlc3Qgd2l0aCBjb250aW51aXR5IGNvcnJlY3Rpb24pIMSRxrDhu6NjIHRo4buxYyBoaeG7h24gduG7m2kgdOG7tyBs4buHIGdp4bqjIMSR4buLbmggbMOgIDAuNS4gS+G6v3QgcXXhuqMgY2hvIHRo4bqleToNCg0KKiBHacOhIHRy4buLIHRo4buRbmcga8OqIENoaS1iw6xuaCBwaMawxqFuZzog8J2ckjI9MTQwNTcNCg0KKiBC4bqtYyB04buxIGRvOiAxDQoNCkdpw6EgdHLhu4sgcC12YWx1ZTogPCAyLjJlLTE2DQoNCktob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBu4buvOiBbMC4wMDAwMDAwMDAwLCAwLjAwMDM0MDU2MDJdDQoNClThu7cgbOG7hyBt4bqrdSDGsOG7m2MgbMaw4bujbmc6IPCdkZ1ePTANCg0KICAqKkvhur90IGx14bqtbjoqKg0KICBW4bubaSBwLXZhbHVlIHLhuqV0IG5o4buPIChuaOG7jyBoxqFuIDAuMDUpLCBjaMO6bmcgdGEgYsOhYyBi4buPIGdp4bqjIHRoaeG6v3Qga2jDtG5nIOG7nyBt4bupYyDDvSBuZ2jEqWEgNSUuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IHThu7cgbOG7hyBu4buvIHRyb25nIG3huqt1IGThu68gbGnhu4d1IGtow6FjIGJp4buHdCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIHNvIHbhu5tpIDUwJS4NCg0KICBD4bulIHRo4buDLCB04bu3IGzhu4cgxrDhu5tjIGzGsOG7o25nIGLhurFuZyAwIHbDoCBraG/huqNuZyB0aW4gY+G6rXkga2jDtG5nIGJhbyBn4buTbSAwLjUgY2hvIHRo4bqleSBn4bqnbiBuaMawIGtow7RuZyBjw7Mga2jDoWNoIGjDoG5nIG7hu68gdHJvbmcgZOG7ryBsaeG7h3UsIHBo4bqjbiDDoW5oIHPhu7EgbeG6pXQgY8OibiBi4bqxbmcgbmdoacOqbSB0cuG7jW5nIHbhu4EgZ2nhu5tpIHTDrW5oIHRyb25nIHThuq1wIGtow6FjaCBow6BuZyDEkcaw4bujYyBraOG6o28gc8OhdC4NCg0KDQoqKjIuIEhvbWVvd25lciDigJMgSOG6oW5nIG3hu6VjIHF1YW4gdMOibTog4oCcWWVz4oCdIChZKSoqDQoNCmBgYHtyfQ0Kbl90b3RhbF9ob21lIDwtIG5yb3codGQpDQpuX2hvbWVvd25lciA8LSBzdW0odGQkSG9tZW93bmVyID09ICJZIikNCnByb3AudGVzdChuX2hvbWVvd25lciwgbl90b3RhbF9ob21lLCBwID0gMC42LCBjb3JyZWN0ID0gVFJVRSkNCg0KYGBgDQoNCg0KKiBU4bu3IGzhu4cgbeG6q3U6IDYwLjA2JQ0KDQoqIEtob+G6o25nIHRpbiBj4bqteSA5NSU6IFs1OS4yNSU7IDYwLjg3JV0NCg0KKiBHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaDoNCg0KICBI4oKAOiBU4bu3IGzhu4cgY2jhu6cgbmjDoCA9IDAuNg0KDQogIEjigoE6IFThu7cgbOG7hyBjaOG7pyBuaMOgIOKJoCAwLjYNCg0KICBHacOhIHRy4buLIHAg4omIIDAuODkg4oaSIEtow7RuZyBiw6FjIGLhu48gSOKCgCwgdHThu6ljIGzDoCBraMO0bmcgY8OzIMSR4bunIGLhurFuZyBjaOG7qW5nIMSR4buDIGvhur90IGx14bqtbiBy4bqxbmcgdOG7tyBs4buHIGNo4bunIG5ow6Aga2jDoWMgNjAlIHRyb25nIHThu5VuZyB0aOG7gy4oS2hv4bqjbmcgdGluIGPhuq15IGNo4bupYSBnacOhIHRy4buLIDAuNiBuw6puIHBow7kgaOG7o3AgduG7m2kgZ2nhuqMgdGh1eeG6v3QgYmFuIMSR4bqndSkNCg0KICAqKk5o4bqtbiB4w6l0OioqDQoNCiAgVOG7tyBs4buHIGtow6FjaCBow6BuZyBz4bufIGjhu691IG5ow6AgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UgxJHhuqF0IDYwLjA2JSwgduG7m2kga2hv4bqjbmcgdGluIGPhuq15IDk1JSBu4bqxbSB0cm9uZyBraG/huqNuZyBbNTkuMjUlOyA2MC44NyVdLiBLaeG7g20gxJHhu4tuaCBnaeG6oyB0aHV54bq/dCBjaG8gdGjhuqV5IGtow7RuZyBjw7Mgc+G7sSBraMOhYyBiaeG7h3QgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiBzbyB24bubaSB04bu3IGzhu4cgZ2nhuqMgxJHhu4tuaCBsw6AgNjAlIChwID0gMC44ODkxKS4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgc+G7sSBwaMOibiBi4buRIGPhu6dhIGJp4bq/biBuw6B5IGtow6Eg4buVbiDEkeG7i25oIHbDoCDEkcOhbmcgdGluIGPhuq15LiBWaeG7h2MgaMahbiA2MCUga2jDoWNoIGjDoG5nIHPhu58gaOG7r3UgbmjDoCBjaG8gdGjhuqV5IG3hu5l0IG3hu6ljIMSR4buZIOG7lW4gxJHhu4tuaCB0w6BpIGNow61uaCBuaOG6pXQgxJHhu4tuaCwgcGjhuqNuIMOhbmggdGnhu4FtIG7Eg25nIGNobyBjw6FjIGjDoG5oIHZpIHRpw6p1IGTDuW5nIGTDoGkgaOG6oW4gaMahbiDhu58gbmjDs20gbsOgeS4gTmfGsOG7o2MgbOG6oWksIG5ow7NtIGtow7RuZyBz4bufIGjhu691IG5ow6AgY8OzIHRo4buDIMawdSB0acOqbiBjw6FjIGzhu7FhIGNo4buNbiBuZ+G6r24gaOG6oW4gdsOgIGxpbmggaG/huqF0IGjGoW4sIGdpw7pwIGN1bmcgY+G6pXAgZ8OzYyBuaMOsbiDEkWEgZOG6oW5nIHRyb25nIHZp4buHYyBwaMOibiB0w61jaCBwaMOibiBraMO6YyBraMOhY2ggaMOgbmcuDQoNCioqMy5Qcm9kdWN0RmFtaWx5IOKAkyBI4bqhbmcgbeG7pWMgcXVhbiB0w6JtOiDigJxGb29k4oCdKioNCg0KYGBge3J9DQpuX3RvdGFsX3Byb2QgPC0gbnJvdyh0ZCkNCm5fZm9vZCA8LSBzdW0odGQkUHJvZHVjdEZhbWlseSA9PSAiRm9vZCIpDQpwcm9wLnRlc3Qobl9mb29kLCBuX3RvdGFsX3Byb2QsIHAgPSAwLjcsIGFsdGVybmF0aXZlID0gImxlc3MiLCBjb3JyZWN0ID0gVFJVRSkNCg0KYGBgDQoNCiogVOG7tyBs4buHIG3huqt1OiA3Mi4yMiUNCg0KKiBLaG/huqNuZyB0aW4gY+G6rXkgOTUlOiBbMC4wMCU7IDcyLjg0JV0NCihkbyBs4buxYSBjaOG7jW4ga2nhu4NtIMSR4buLbmggbeG7mXQgcGjDrWEgbsOqbiBj4bqtbiBkxrDhu5tpIGzDoCAwKQ0KDQoqIEdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oOg0KDQogIEjigoA6IFThu7cgbOG7hyBGb29kIOKJpSAwLjcNCg0KICBI4oKBOiBU4bu3IGzhu4cgRm9vZCA8IDAuNw0KDQpHacOhIHRy4buLIHAgdOG7qyBraeG7g20gxJHhu4tuaCBI4oKAOiBwIOKJpSAwLjcgKGThuqFuZyBt4buZdCBwaMOtYSk6IDENCg0KICBL4bq/dCBsdeG6rW46IFbDrCBwLXZhbHVlID4gMC4wNSDihpIga2jDtG5nIGLDoWMgYuG7jyBI4oKALCB04bupYyBsw6Aga2jDtG5nIGPDsyDEkeG7pyBi4bqxbmcgY2jhu6luZyDEkeG7gyBr4bq/dCBsdeG6rW4gcuG6sW5nIHThu7cgbOG7hyBz4bqjbiBwaOG6qW0gRm9vZCBuaOG7jyBoxqFuIDcwJS4NCg0KICBUdXkgbmhpw6puLCB2w6wgdOG7tyBs4buHIG3huqt1IHRo4buxYyB04bq/IGzDoCA3Mi4yMiUsIGvhur90IGjhu6NwIGtob+G6o25nIHRpbiBj4bqteSBraMOhIHLhu5luZywgY8OzIHRo4buDIGPDom4gbmjhuq9jIGtp4buDbSDEkeG7i25oIGhhaSBwaMOtYSDEkeG7gyDEkcOhbmggZ2nDoSBzw6F0IGjGoW4uDQogIA0KICAqKk5o4bqtbiB4w6l0OioqDQogIA0KICBOaMOzbSBz4bqjbiBwaOG6qW0gIkZvb2QiIGNoaeG6v20gdOG7tyBs4buHIGNhbyBuaOG6pXQgduG7m2kgNzIuMjIlLCBjaG8gdGjhuqV5IMSRw6J5IGzDoCBt4bq3dCBow6BuZyBjaOG7pyBs4buxYyB0cm9uZyBjw6FjIGdpYW8gZOG7i2NoLiBN4bq3YyBkw7kga+G6v3QgcXXhuqMga2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3QgbeG7mXQgcGjDrWEga2jDtG5nIGLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCB04bu3IGzhu4cg4omlIDcwJSAocCA9IDEpLCBuaMawbmcgdOG7tyBs4buHIHRo4buxYyB04bq/IHbGsOG7o3QgbeG7qWMgZ2nhuqMgxJHhu4tuaCwgxJHhu5NuZyB0aOG7nWkgY2hp4bq/bSDEkWEgc+G7kSByw7UgcuG7h3Qgc28gduG7m2kgY8OhYyBuaMOzbSBjw7JuIGzhuqFpIG5oxrAg4oCcRHJpbmvigJ0gaGF5IOKAnE5vbi1Db25zdW1hYmxl4oCdLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBuaHUgY+G6p3UgbOG7m24gduG7gSB0aOG7sWMgcGjhuqltIHRyb25nIHThuq1wIGtow6FjaCBow6BuZyB2w6AgbMOgIGPEg24gY+G7qSB24buvbmcgY2jhuq9jIMSR4buDIGRvYW5oIG5naGnhu4dwIHThuq1wIHRydW5nIGNoaeG6v24gbMaw4bujYyBraW5oIGRvYW5oIHbDoG8gbmjDs20gc+G6o24gcGjhuqltIG7DoHkuDQoNCiMjICoqUGjhuqduIDQuIFBow6JuIHTDrWNoIE3hu5FpIHF1YW4gaOG7hyBoYWkgYmnhur9uIMSR4buLbmggdMOtbmgqKg0KDQogIFRhIGNo4buNbiAzIGPhurdwIGJp4bq/biBzYXUgxJHDonk6DQogIA0KKiBTdGF0ZW9yUHJvdmluY2UgdsOgIFByb2R1Y3RGYW1pbHk6DQoNCiogTWFyaXRhbFN0YXR1cyB2w6AgSG9tZW93bmVyDQoNCiogQW5udWFsSW5jb21lIHbDoCBQcm9kdWN0Q2F0ZWdvcnkNCg0KIyMjICoqNC4xIE1hcml0YWxTdGF0dXMgdsOgIEhvbWVvd25lcjoqKg0KDQogICoqQuG6o25nIHThuqduIHPhu5EgY2jDqW8qKg0KYGBge3J9DQp0YWJsZV9tYXJpdGFsX2hvbWUgPC0gdGFibGUodGQkTWFyaXRhbFN0YXR1cywgdGQkSG9tZW93bmVyKQ0KDQpwZXJjZW50X3JvdyA8LSBwcm9wLnRhYmxlKHRhYmxlX21hcml0YWxfaG9tZSwgbWFyZ2luID0gMSkgKiAxMDANCg0KcHJpbnQodGFibGVfbWFyaXRhbF9ob21lKQ0KYGBgDQogICoqVHLhu7FjIHF1YW4gaMOzYSoqDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQoNCiMgVsOtIGThu6UgduG7m2kgTWFyaXRhbFN0YXR1cyB2w6AgSG9tZW93bmVyDQp0ZCAlPiUNCiAgZ3JvdXBfYnkoTWFyaXRhbFN0YXR1cywgSG9tZW93bmVyKSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gTWFyaXRhbFN0YXR1cywgeSA9IGNvdW50LCBmaWxsID0gSG9tZW93bmVyKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICBsYWJzKHRpdGxlID0gIlThu7cgbOG7hyBz4bufIGjhu691IG5ow6AgdGhlbyB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4iLA0KICAgICAgIHkgPSAiVOG7tyBs4buHIHBo4bqnbiB0csSDbSIsIHggPSAiVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KICAqKk5o4bqtbiB4w6l0KioNCiAgDQogIEJp4buDdSDEkeG7kyDigJxU4bu3IGzhu4cgc+G7nyBo4buvdSBuaMOgIHRoZW8gdMOsbmggdHLhuqFuZyBow7RuIG5ow6Ju4oCdIGNobyB0aOG6pXkgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IHLDtSBy4buHdCBnaeG7r2EgaGFpIG5ow7NtIE1hcml0YWxTdGF0dXMuIEPhu6UgdGjhu4MsIHRyb25nIG5ow7NtIMSRw6Mga+G6v3QgaMO0biAoTWFycmllZCksIHThu7cgbOG7hyBz4bufIGjhu691IG5ow6AgKEhvbWVvd25lciA9IFkpIGNhbyBoxqFuIMSRw6FuZyBr4buDIHNvIHbhu5tpIHThu7cgbOG7hyBraMO0bmcgc+G7nyBo4buvdSBuaMOgLiBOZ8aw4bujYyBs4bqhaSwg4bufIG5ow7NtIMSR4buZYyB0aMOibiAoU2luZ2xlKSwgdOG7tyBs4buHIGtow7RuZyBz4bufIGjhu691IG5ow6AgbOG6oWkgY2hp4bq/bSDGsHUgdGjhur8uIFh1IGjGsOG7m25nIG7DoHkgY2hvIHRo4bqleSBraOG6oyBuxINuZyBjw7MgbeG7kWkgbGnDqm4gaOG7hyBnaeG7r2EgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIHbDoCB2aeG7h2Mgc+G7nyBo4buvdSBuaMOgIOG7nzogbmjhu69uZyBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gdGjGsOG7nW5nIGPDsyB4dSBoxrDhu5tuZyBz4bufIGjhu691IG5ow6AgY2FvIGjGoW4sIGPDsyB0aOG7gyBkbyBuaHUgY+G6p3Ug4buVbiDEkeG7i25oIGNo4buXIOG7nywga2jhuqMgbsSDbmcgdMOgaSBjaMOtbmgga+G6v3QgaOG7o3AgdOG7qyBoYWkgbmfGsOG7nWkgaG/hurdjIGvhur8gaG/huqFjaCBkw6BpIGjhuqFuIGNobyBnaWEgxJHDrG5oLiBUcm9uZyBraGkgxJHDsywgbmjDs20gxJHhu5ljIHRow6JuIGPDsyB0aOG7gyDGsHUgdGnDqm4gc+G7sSBsaW5oIGhv4bqhdCB24buBIGNo4buXIOG7nyBob+G6t2MgY2jGsGEgxJHhu6cgxJFp4buBdSBraeG7h24gxJHhu4Mgc+G7nyBo4buvdSBuaMOgLiBN4buRaSBxdWFuIHPDoXQgbsOgeSBjaG8gdGjhuqV5IHPhu7Ega2jDoWMgYmnhu4d0IMSRw6FuZyBjaMO6IMO9IHbhu4EgaMOgbmggdmkgc+G7nyBo4buvdSB0w6BpIHPhuqNuIGdp4buvYSBjw6FjIG5ow7NtIGjDtG4gbmjDom4uDQoNCiMjIyAqKjQuMiBBbm51YWxJbmNvbWUgdsOgIFByb2R1Y3RDYXRlZ29yeSoqDQogIA0KICAqKkLhuqNuZyB04bqnbiBz4buRIGNow6lvKioNCmBgYHtyfQ0KdGFibGVfaW5jb21lX2NhdCA8LSB0YWJsZSh0ZCRBbm51YWxJbmNvbWUsIHRkJFByb2R1Y3RDYXRlZ29yeSkNCnBlcmNlbnRfaW5jb21lX2NhdCA8LSBwcm9wLnRhYmxlKHRhYmxlX2luY29tZV9jYXQsIG1hcmdpbiA9IDEpICogMTAwDQoNCnByaW50KHRhYmxlX2luY29tZV9jYXQpDQpwcmludChyb3VuZChwZXJjZW50X2luY29tZV9jYXQsIDIpKQ0KDQpgYGANCiAgKipUcuG7sWMgcXVhbiBow7NhIMSR4buTIHRo4buLKioNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCg0KIyBUcuG7sWMgcXVhbiBow7NhIEFubnVhbEluY29tZSB2w6AgUHJvZHVjdENhdGVnb3J5DQp0ZCAlPiUNCiAgZ3JvdXBfYnkoQW5udWFsSW5jb21lLCBQcm9kdWN0Q2F0ZWdvcnkpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBBbm51YWxJbmNvbWUsIHkgPSBjb3VudCwgZmlsbCA9IFByb2R1Y3RDYXRlZ29yeSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgbGFicyh0aXRsZSA9ICJU4bu3IGzhu4cgZGFuaCBt4bulYyBz4bqjbiBwaOG6qW0gdGhlbyB0aHUgbmjhuq1wIGjDoG5nIG7Eg20iLA0KICAgICAgIHggPSAiVGh1IG5o4bqtcCBow6BuZyBuxINtIiwgeSA9ICJU4bu3IGzhu4cgcGjhuqduIHRyxINtIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KYGBgDQogICoqTmjhuq1uIHjDqXQ6KiogQmnhu4N1IMSR4buTIOKAnFThu7cgbOG7hyBkYW5oIG3hu6VjIHPhuqNuIHBo4bqpbSB0aGVvIHRodSBuaOG6rXAgaOG6sW5nIG7Eg23igJ0gY2hvIHRo4bqleSBz4buxIHBow6JuIGLhu5EgxJFhIGThuqFuZyBj4bunYSBjw6FjIG5ow7NtIHPhuqNuIHBo4bqpbSBtw6Aga2jDoWNoIGjDoG5nIGzhu7FhIGNo4buNbiBk4buxYSB0csOqbiBt4bupYyB0aHUgbmjhuq1wLiBOaMOsbiBjaHVuZywgY8OhYyBj4buZdCB0aHUgbmjhuq1wIGPDsyBjaGnhu4F1IGNhbyBtw6B1IHPhuq9jIGtow6EgxJHhu5NuZyDEkeG7gXUsIGNobyB0aOG6pXkga2jDtG5nIGPDsyBz4buxIHRoYXkgxJHhu5VpIHF1w6EgbOG7m24gdHJvbmcgdOG7tyBs4buHIHRpw6p1IGTDuW5nIHThu6tuZyBkYW5oIG3hu6VjIHPhuqNuIHBo4bqpbSBnaeG7r2EgY8OhYyBuaMOzbSB0aHUgbmjhuq1wLiBUdXkgbmhpw6puLCBt4buZdCBz4buRIGRhbmggbeG7pWMgbmjGsCDigJxTbmFjayBGb29kc+KAnSwg4oCcQmFraW5nIEdvb2Rz4oCdIGhheSDigJxDYW5uZWQgVmVnZXRhYmxlc+KAnSB24bqrbiBjaGnhur9tIHThu7cgbOG7hyDEkcOhbmcga+G7gyDhu58gaOG6p3UgaOG6v3QgY8OhYyBt4bupYyB0aHUgbmjhuq1wLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBjw6FjIHPhuqNuIHBo4bqpbSBuw6B5IGPDsyB0aOG7gyBsw6Agbmh1IHnhur91IHBo4bqpbSBwaOG7lSBiaeG6v24sIHBow7kgaOG7o3AgduG7m2kgbmhp4buBdSDEkeG7kWkgdMaw4bujbmcga2jDoWNoIGjDoG5nLiBN4bq3YyBkw7kga2jDtG5nIGPDsyBz4buxIGtow6FjIGJp4buHdCBu4buVaSBi4bqtdCwgbmjGsG5nIHh1IGjGsOG7m25nIHRpw6p1IGTDuW5nIG5o4bqldCDEkeG7i25oIGPDsyB0aOG7gyDEkcaw4bujYyBwaMOhdCBoaeG7h24gcsO1IGjGoW4ga2hpIHBow6JuIHTDrWNoIGPhu6UgdGjhu4MgdOG7q25nIG5ow7NtIHPhuqNuIHBo4bqpbSB0aGVvIHRodSBuaOG6rXAuIEJp4buDdSDEkeG7kyBuw6B5IGjhu5cgdHLhu6MgZG9hbmggbmdoaeG7h3AgdHJvbmcgdmnhu4djIMSR4buLbmggduG7iyB2w6AgeMOieSBk4buxbmcgY2hp4bq/biBsxrDhu6NjIHPhuqNuIHBo4bqpbSBwaMO5IGjhu6NwIGNobyB04burbmcgcGjDom4ga2jDumMga2jDoWNoIGjDoG5nIHRoZW8gbeG7qWMgdGh1IG5o4bqtcC4NCiAgDQojIyMgKio0LjMgU3RhdGVvclByb3ZpbmNlIHbDoCBQcm9kdWN0RmFtaWx5KioNCg0KICAqKkLhuqNuZyB04bqnbiBz4buRIGNow6lvKioNCmBgYHtyfQ0KdGFibGVfc3RhdGVfcHJvZCA8LSB0YWJsZSh0ZCRTdGF0ZW9yUHJvdmluY2UsIHRkJFByb2R1Y3RGYW1pbHkpDQpwZXJjZW50X3N0YXRlX3Byb2QgPC0gcHJvcC50YWJsZSh0YWJsZV9zdGF0ZV9wcm9kLCBtYXJnaW4gPSAxKSAqIDEwMA0KDQpwcmludCh0YWJsZV9zdGF0ZV9wcm9kKQ0KcHJpbnQocm91bmQocGVyY2VudF9zdGF0ZV9wcm9kLCAyKSkNCmBgYA0KICAqKlRy4buxYyBxdWFuIGjDs2EgxJHhu5MgdGjhu4sqKg0KICANCmBgYHtyfQ0KIyBUcuG7sWMgcXVhbiBow7NhIFN0YXRlb3JQcm92aW5jZSB2w6AgUHJvZHVjdEZhbWlseQ0KdGQgJT4lDQogIGdyb3VwX2J5KFN0YXRlb3JQcm92aW5jZSwgUHJvZHVjdEZhbWlseSkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFN0YXRlb3JQcm92aW5jZSwgeSA9IGNvdW50LCBmaWxsID0gUHJvZHVjdEZhbWlseSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgbGFicyh0aXRsZSA9ICJU4bu3IGzhu4cgbmjDs20gc+G6o24gcGjhuqltIHRoZW8gdOG7iW5oL2JhbmciLA0KICAgICAgIHggPSAiVOG7iW5oL0JhbmciLCB5ID0gIlThu7cgbOG7hyBwaOG6p24gdHLEg20iKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQoNCmBgYA0KDQogICoqTmjhuq1uIHjDqXQqKg0KICANCiAgQuG6o25nIOKAnFThu7cgbOG7hyBuaMOzbSBz4bqjbiBwaOG6qW0gdGhlbyBiYW5n4oCdIHRo4buDIGhp4buHbiBz4buxIHBow6JuIGLhu5EgdGnDqnUgZMO5bmcgY+G7p2EgYmEgbmjDs20gc+G6o24gcGjhuqltIGNow61uaCBsw6AgRHJpbmssIEZvb2QgdsOgIE5vbi1Db25zdW1hYmxlIOG7nyBjw6FjIGJhbmcga2jDoWMgbmhhdS4gUXVhIGLhuqNuZyBuw6B5LCB0YSBjw7MgdGjhu4MgdGjhuqV5IHLhurFuZyBt4bq3YyBkw7kgYmEgbmjDs20gc+G6o24gcGjhuqltIMSR4buBdSDEkcaw4bujYyB0acOqdSBkw7luZyB04bqhaSB04bqldCBj4bqjIGPDoWMgYmFuZywgbmjGsG5nIHThu7cgdHLhu41uZyBnaeG7r2EgY2jDum5nIGPDsyBz4buxIGtow6FjIGJp4buHdCByw7UgcuG7h3QuIFbDrSBk4bulLCBiYW5nIFZlcmFjcnV6IHbDoCBZdWNhdGFuIGPDsyB04bu3IGzhu4cgdGnDqnUgZMO5bmcgbmjDs20gc+G6o24gcGjhuqltIEZvb2QgcuG6pXQgY2FvLCBjaGnhur9tIGzhuqduIGzGsOG7o3Qga2hv4bqjbmcgODElIHbDoCA3NCUsIHRyb25nIGtoaSB04bu3IGzhu4cgbsOgeSDhu58gR3VlcnJlcm8gdsOgIEphbGlzY28gbOG6oWkgdGjhuqVwIGjGoW4gxJHDoW5nIGvhu4MuIE5nxrDhu6NjIGzhuqFpLCBuaMOzbSBEcmluayBjaGnhur9tIHThu7cgbOG7hyBjYW8gaMahbiB04bqhaSBjw6FjIGJhbmcgbmjGsCBHdWVycmVybyAoa2hv4bqjbmcgMTcuNiUpIGhheSBKYWxpc2NvICgxOC4zJSkuIE5ow7NtIE5vbi1Db25zdW1hYmxlIG5ow6xuIGNodW5nIGPDsyB04bu3IGzhu4cgdGjhuqVwIGjGoW4gc28gduG7m2kgaGFpIG5ow7NtIGPDsm4gbOG6oWksIGRhbyDEkeG7mW5nIGNo4bunIHnhur91IHThu6sgMTclIMSR4bq/biAyMCUuIE5o4buvbmcgc+G7sSBraMOhYyBiaeG7h3QgbsOgeSBjw7MgdGjhu4MgcGjhuqNuIMOhbmggxJFp4buBdSBraeG7h24gc+G7kW5nLCBz4bufIHRow61jaCB0acOqdSBkw7luZyBob+G6t2MgbeG7qWMgxJHhu5kgcGjDoXQgdHJp4buDbiB0aMawxqFuZyBt4bqhaSBraMOhYyBuaGF1IGdp4buvYSBjw6FjIGJhbmcuIEvhur90IHF14bqjIG7DoHkgaOG7r3Ugw61jaCBjaG8gdmnhu4djIHRoaeG6v3Qga+G6vyBjaGnhur9uIGzGsOG7o2MgcGjDom4gcGjhu5FpIHbDoCB0aeG6v3AgdGjhu4sgdGhlbyBraHUgduG7sWMgxJHhu4thIGzDvS4NCg0KIyMjICoqNC40IEtp4buDbSDEkeG7i25oIGNoaSBiw6xuaCBwaMawxqFuZyoqDQoNCiAgKipNYXJpdGFsU3RhdHVzIHbDoCBIb21lb3duZXIqKg0KYGBge3J9DQojIFThuqFvIGLhuqNuZyB04bqnbiBz4buRIGNow6lvDQp0YWIgPC0gdGFibGUodGQkTWFyaXRhbFN0YXR1cywgdGQkSG9tZW93bmVyKQ0KDQoNCg0KIyBLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcNCnJlc3VsdCA8LSBjaGlzcS50ZXN0KHRhYikNCg0KIyBJbiBr4bq/dCBxdeG6ow0KcHJpbnQocmVzdWx0KQ0KDQoNCmBgYA0KICAqKkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oOioqDQoNCkjigoAgKEdp4bqjIHRodXnhur90IGtow7RuZy4NCg0KSOKCgSAoR2nhuqMgdGh1eeG6v3QgxJHhu5FpKS4NCg0KICoqS+G6v3QgcXXhuqMga2nhu4NtIMSR4buLbmg6KioNCg0KR2nDoSB0cuG7iyB0aOG7kW5nIGvDqjog8J2ckjI9MTI0MS4yDQoNCkLhuq1jIHThu7EgZG86IGTwnZGTPTENCg0KR2nDoSB0cuG7iyBwLXZhbHVlIHLhuqV0IG5o4buPICg8IDIuMmUtMTYpDQoNCiAgS+G6v3QgbHXhuq1uOiBWw6wgcC12YWx1ZSBy4bqldCBuaOG7jyAobmjhu48gaMahbiBt4bupYyDDvSBuZ2jEqWEgdGjDtG5nIHRoxrDhu51uZyAwLjA1KSwgbsOqbiBiw6FjIGLhu48gZ2nhuqMgdGhp4bq/dCBraMO0bmcuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IGPDsyBt4buRaSBsacOqbiBo4buHIHRo4buRbmcga8OqIGPDsyDDvSBuZ2jEqWEgZ2nhu69hIGhhaSBiaeG6v24NCiAgDQogICoqQW5udWFsSW5jb21lIHbDoCBQcm9kdWN0Q2F0ZWdvcnkqKg0KICANCmBgYHtyfQ0KdGFiMiA8LSB0YWJsZSh0ZCRBbm51YWxJbmNvbWUsIHRkJFByb2R1Y3RDYXRlZ29yeSkNCnJlc3VsdDIgPC0gY2hpc3EudGVzdCh0YWIyKQ0KYGBgDQogIFbDrCBt4buZdCBz4buRIMO0IHRyb25nIGLhuqNuZyB04bqnbiBz4buRIGPDsyBnacOhIHRy4buLIG5o4buPICh0aMaw4budbmcgZMaw4bubaSA1KSwga2hp4bq/biBraeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcga2jDtG5nIMSRw6FuZyB0aW4gY+G6rXkuDQoNCiAgKipTdGF0ZW9yUHJvdmluY2UgdsOgIFByb2R1Y3RGYW1pbHkqKg0KICANCmBgYHtyfQ0KdGFiMyA8LSB0YWJsZSh0ZCRTdGF0ZW9yUHJvdmluY2UsIHRkJFByb2R1Y3RGYW1pbHkpDQoNCnJlc3VsdDMgPC0gY2hpc3EudGVzdCh0YWIzKQ0KDQpwcmludChyZXN1bHQzKQ0KDQoNCmBgYA0KICoqR2nhuqMgdGh1eeG6v3Qga2nhu4NtIMSR4buLbmg6KioNCg0KSOKCgDoga2jDtG5nIGPDsyBt4buRaSBsacOqbiBo4buHIGhheSBwaOG7pSB0aHXhu5ljIGzhuqtuIG5oYXUuDQoNCkjigoE6IHThu5NuIHThuqFpIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGtodSB24buxYyDEkeG7i2EgbMO9IHbDoCBuaMOzbSBz4bqjbiBwaOG6qW0uDQoNCiAqKkvhur90IHF14bqjIGtp4buDbSDEkeG7i25oOioqDQoNCkdpw6EgdHLhu4sgdGjhu5FuZyBrw6o6IPCdnJIyID0gMTIuMw0KDQpC4bqtYyB04buxIGRvOiBk8J2RkyA9IDE4DQoNCkdpw6EgdHLhu4sgcC12YWx1ZSA9IDAuODMxNC4NCg0KICAqKkvhur90IGx14bqtbjoqKlbDrCBnacOhIHRy4buLIHAtdmFsdWUgbOG7m24gaMahbiBt4bupYyDDvSBuZ2jEqWEgcGjhu5UgYmnhur9uIDAuMDUsIGNow7puZyB0YSBraMO0bmcgxJHhu6cgY8ahIHPhu58gxJHhu4MgYsOhYyBi4buPIGdp4bqjIHRoaeG6v3Qga2jDtG5nLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBraMO0bmcgY8OzIG3hu5FpIGxpw6puIGjhu4cgdGjhu5FuZyBrw6ogxJHDoW5nIGvhu4MgZ2nhu69hIGtodSB24buxYyDEkeG7i2EgbMO9IChTdGF0ZW9yUHJvdmluY2UpIHbDoCBuaMOzbSBz4bqjbiBwaOG6qW0gKFByb2R1Y3RGYW1pbHkpIHRyb25nIGThu68gbGnhu4d1IHBow6JuIHTDrWNoLg0KDQogIA0KIyMgKipQaOG6p24gNS4gVOG7lW5nIGvhur90IHbDoCB0aOG6o28gbHXhuq1uKioNCg0KIyMjICoqNS4xIFTDs20gdOG6r3Qgbmjhu69uZyBwaMOhdCBoaeG7h24gY2jDrW5oKioNCg0KICBE4buxYSB0csOqbiBjw6FjIHBow6JuIHTDrWNoIHbhu4EgY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCwgbmdoacOqbiBj4bupdSDEkcOjIGzDoG0gcsO1IG3hu5l0IHPhu5EgxJHhurdjIMSRaeG7g20gcXVhbiB0cuG7jW5nIGPhu6dhIGtow6FjaCBow6BuZyB2w6AgaMOgbmggdmkgbXVhIHPhuq9tIGPhu6dhIGjhu40uIEPhu6UgdGjhu4MsIG3hu5FpIHF1YW4gaOG7hyBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIGdp4buvYSB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gKE1hcml0YWxTdGF0dXMpIHbDoCB2aeG7h2Mgc+G7nyBo4buvdSBuaMOgIChIb21lb3duZXIpIHBo4bqjbiDDoW5oIHPhu7EgbGnDqm4ga+G6v3QgZ2nhu69hIGPDoWMgeeG6v3UgdOG7kSB4w6MgaOG7mWkgdsOgIGtpbmggdOG6vyB0cm9uZyBwaMOibiBraMO6YyBraMOhY2ggaMOgbmcuIMSQ4buTbmcgdGjhu51pLCBwaMOibiB0w61jaCBjw6FjIGJp4bq/biB24buBIHRodSBuaOG6rXAgaMOgbmcgbsSDbSAoQW5udWFsSW5jb21lKSB2w6AgbG/huqFpIHPhuqNuIHBo4bqpbSAoUHJvZHVjdENhdGVnb3J5KSBjxaluZyBjaG8gdGjhuqV5IHPhu7EgcGjDom4gYuG7kSBraMO0bmcgxJHhu5NuZyDEkeG7gXUsIGNo4buJIHJhIHLhurFuZyBuaMOzbSBraMOhY2ggaMOgbmcga2jDoWMgbmhhdSBjw7MgeHUgaMaw4bubbmcgbOG7sWEgY2jhu41uIHPhuqNuIHBo4bqpbSBwaMO5IGjhu6NwIHbhu5tpIG3hu6ljIHRodSBuaOG6rXAuIEN14buRaSBjw7luZywgbeG7kWkgcXVhbiBo4buHIGdp4buvYSBraHUgduG7sWMgxJHhu4thIGzDvSAoU3RhdGVvclByb3ZpbmNlKSB2w6AgbmjDs20gc+G6o24gcGjhuqltIChQcm9kdWN0RmFtaWx5KSBow6kgbOG7mSBz4buxIGtow6FjIGJp4buHdCB0cm9uZyBow6BuaCB2aSB0acOqdSBkw7luZyB0w7l5IHRoZW8gdsO5bmcgbWnhu4FuLCBnw7NwIHBo4bqnbiDEkeG7i25oIGjGsOG7m25nIHBow6JuIHBo4buRaSB2w6AgdGnhur9wIHRo4buLIGhp4buHdSBxdeG6oyBoxqFuLg0KICANCiMjIyAqKjUuMiBI4bqhbiBjaOG6vyBj4bunYSBwaMOibiB0w61jaCoqDQoNCiAgUGjDom4gdMOtY2ggdHJvbmcgYsOgaSB04bqtcCBuw6B5IHThuq1wIHRydW5nIGNo4bunIHnhur91IHbDoG8gY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCwgZG8gxJHDsyBjw7JuIHThu5NuIHThuqFpIG3hu5l0IHPhu5EgaOG6oW4gY2jhur8gbmjhuqV0IMSR4buLbmguIFRyxrDhu5tjIGjhur90LCBjw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oIHRyb25nIGLhu5kgZOG7ryBsaeG7h3UgY8OzIG3hu5l0IHPhu5EgZ2nDoSB0cuG7iyB0aGnhur91IChOQSkg4bufIG5o4buvbmcgY+G7mXQgcXVhbiB0cuG7jW5nLCBnw6J5IGtow7Mga2jEg24gdHJvbmcgdmnhu4djIHjhu60gbMO9IHbDoCBjw7MgdGjhu4Mg4bqjbmggaMaw4bufbmcgxJHhur9uIGvhur90IHF14bqjIHBow6JuIHTDrWNoIG7hur91IGtow7RuZyDEkcaw4bujYyB44butIGzDvSBo4bujcCBsw70uIE3hurdjIGTDuSDEkcOjIHRo4buxYyBoaeG7h24gY8OhYyBixrDhu5tjIHRoYXkgdGjhur8gaG/hurdjIGxv4bqhaSBi4buPIGdpw6EgdHLhu4sgdGhp4bq/dSwgbmjGsG5nIHZp4buHYyBuw6B5IGPDsyB0aOG7gyBsw6BtIG3huqV0IMSRaSBt4buZdCBwaOG6p24gdGjDtG5nIHRpbiBraMOhY2ggaMOgbmcgxJHDoW5nIGdpw6EuDQoNCiAgVGjhu6kgaGFpLCBt4buZdCBz4buRIG5ow7NtIGNvbiB0cm9uZyBjw6FjIGJp4bq/biBwaMOibiBsb+G6oWkgY8OzIGvDrWNoIHRoxrDhu5tjIG3huqt1IGtow6Egbmjhu48sIGThuqtuIMSR4bq/biBraMOzIGtoxINuIHRyb25nIHZp4buHYyDDoXAgZOG7pW5nIGPDoWMga2nhu4NtIMSR4buLbmggdGjhu5FuZyBrw6ogY2h14bqpbiBuaMawIGtp4buDbSDEkeG7i25oIENoaS1iw6xuaCBwaMawxqFuZywgdsOsIGPDsyB0aOG7gyB2aSBwaOG6oW0gZ2nhuqMgxJHhu4tuaCB24buBIHThuqduIHPhu5Ega+G7syB24buNbmcgdHJvbmcgYuG6o25nIHThuqduIHPhu5EuIMSQaeG7gXUgbsOgeSBo4bqhbiBjaOG6vyBraOG6oyBuxINuZyDEkcOhbmggZ2nDoSBjaMOtbmggeMOhYyBt4buRaSBxdWFuIGjhu4cgZ2nhu69hIGPDoWMgYmnhur9uIMSR4buLbmggdMOtbmggdHJvbmcgbmjhu69uZyBuaMOzbSBuaOG7jy4NCg0KICBOZ2/DoGkgcmEsIHZp4buHYyBjaOG7iSBwaMOibiB0w61jaCBjw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oIG3DoCBraMO0bmcga+G6v3QgaOG7o3AgduG7m2kgY8OhYyBiaeG6v24gxJHhu4tuaCBsxrDhu6NuZyAodsOtIGThu6U6IG3hu6ljIGNoaSB0acOqdSwgc+G7kSBs4bqnbiBtdWEpIGzDoG0gaOG6oW4gY2jhur8gZ8OzYyBuaMOsbiB0b8OgbiBkaeG7h24gduG7gSBow6BuaCB2aSBraMOhY2ggaMOgbmcsIGPFqW5nIG5oxrAga2jhuqMgbsSDbmcgcGjDoXQgaGnhu4duIGPDoWMgbeG6q3UgcGjhu6ljIHThuqFwIGjGoW4gdHJvbmcgZOG7ryBsaeG7h3UuIEN14buRaSBjw7luZywgZOG7ryBsaeG7h3UgdGh1IHRo4bqtcCDEkcaw4bujYyBjw7MgdGjhu4MgY2jhu4t1IOG6o25oIGjGsOG7n25nIGLhu59pIGPDoWMgeeG6v3UgdOG7kSBiw6puIG5nb8OgaSBuaMawIHNhaSBzw7N0IHRyb25nIG5o4bqtcCBsaeG7h3UgaG/hurdjIHPhu7Ega2jDtG5nIMSR4buTbmcgbmjhuqV0IHRyb25nIGPDoWNoIHBow6JuIGxv4bqhaSwgdOG6oW8gcmEgbmjhu69uZyBraMOzIGtoxINuIGtoaSBjaOG6oXkgY8OhYyBwaMOibiB0w61jaCB0aOG7kW5nIGvDqi4NCg0KIyMjICoqNS4zIMSQ4buBIHh14bqldCoqDQoNCiAgROG7sWEgdHLDqm4gY8OhYyBr4bq/dCBxdeG6oyBwaMOibiB0w61jaCB2w6Agbmjhu69uZyBo4bqhbiBjaOG6vyDEkcOjIG7DqnUsIGNow7puZyB0w7RpIMSR4buBIHh14bqldCBt4buZdCBz4buRIGjGsOG7m25nIMSRaSBj4bulIHRo4buDIG5o4bqxbSBraGFpIHRow6FjIHPDonUgaMahbiBk4buvIGxp4buHdSB2w6AgbsOibmcgY2FvIGhp4buHdSBxdeG6oyB0cm9uZyB2aeG7h2MgaGnhu4N1IHbDoCBwaOG7pWMgduG7pSBraMOhY2ggaMOgbmc6DQoNCiAgKipN4bufIHLhu5luZyBwaMOibiB0w61jaCDEkeG7i25oIHTDrW5oIGvhur90IGjhu6NwIHbhu5tpIMSR4buLbmggbMaw4bujbmcqKg0KDQoqIELhu5Ugc3VuZyBjw6FjIGJp4bq/biDEkeG7i25oIGzGsOG7o25nIGxpw6puIHF1YW4gxJHhur9uIGjDoG5oIHZpIG11YSBz4bqvbSBuaMawIHThu5VuZyBjaGkgdGnDqnUsIHThuqduIHN14bqldCBtdWEgaMOgbmcgxJHhu4Mga+G6v3QgaOG7o3AgY8O5bmcgY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCDEkcOjIHBow6JuIHTDrWNoLg0KDQoqIMOBcCBk4bulbmcgY8OhYyBtw7QgaMOsbmggcGjDom4gdMOtY2ggxJFhIGJp4bq/biBob+G6t2MgaOG7k2kgcXV5IGxvZ2lzdGljIMSR4buDIGThu7EgYsOhbyBow6BuaCB2aSBraMOhY2ggaMOgbmcgdGhlbyB04burbmcgbmjDs20gxJHhurdjIHRyxrBuZyBuaMawIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiwgdGh1IG5o4bqtcCwgc+G7nyBo4buvdSBuaMOgLg0KDQogICoqUGjDom4ga2jDumMga2jDoWNoIGjDoG5nIGThu7FhIHRyw6puIMSR4bq3YyDEkWnhu4NtIMSRYSBjaGnhu4F1KioNCg0KKiBT4butIGThu6VuZyBr4bu5IHRodeG6rXQgcGjDom4gY+G7pW0gKGNsdXN0ZXJpbmcpIGvhur90IGjhu6NwIGPDoWMgYmnhur9uIMSR4buLbmggdMOtbmggKHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiwgxJHhu4thIGzDvSwgdGh1IG5o4bqtcCkgbmjhurFtIHBow6JuIG5ow7NtIGtow6FjaCBow6BuZyB0aGVvIGjDoG5oIHZpIHbDoCBuaHUgY+G6p3UgdGnDqnUgZMO5bmcgdGjhu7FjIHThur8uDQoNCiogVOG7qyDEkcOzIHRoaeG6v3Qga+G6vyBjw6FjIGNoaeG6v24gbMaw4bujYyBtYXJrZXRpbmcgY8OhIG5ow6JuIGjDs2EsIG5o4bqvbSDEkcO6bmcgbeG7pWMgdGnDqnUgduG7m2kgdOG7q25nIHBow6JuIGtow7pjIGPhu6UgdGjhu4MsIHbDrSBk4bulIMawdSB0acOqbiBuaMOzbSBjw7MgdGh1IG5o4bqtcCBjYW8gaG/hurdjIG5ow7NtIMSR4buZYyB0aMOibiBjw7MgeHUgaMaw4bubbmcgdGnDqnUgZMO5bmcgbGluaCBob+G6oXQgaMahbi4NCg0KICAqKkvhur90IGjhu6NwIGThu68gbGnhu4d1IGLDqm4gbmdvw6BpIHbDoCBt4bufIHLhu5luZyB0aHUgdGjhuq1wKioNCg0KKiBUw61jaCBo4bujcCBk4buvIGxp4buHdSB24buBIMSR4bq3YyDEkWnhu4NtIGTDom4gY8awIGtodSB24buxYywgeHUgaMaw4bubbmcgdGnDqnUgZMO5bmcgdGhlbyB2w7luZyDEkeG7gyBjw7MgY8OhaSBuaMOsbiB0b8OgbiBkaeG7h24gaMahbiB24buBIHRo4buLIHRyxrDhu51uZy4NCg0KKiBC4buVIHN1bmcgZOG7ryBsaeG7h3UgduG7gSB0aOG7nWkgZ2lhbiBtdWEgaMOgbmcsIGvDqm5oIHBow6JuIHBo4buRaSDEkeG7gyBwaMOibiB0w61jaCB4dSBoxrDhu5tuZyB0aGVvIG3DuWEsIG5nw6B5IHRyb25nIHR14bqnbiwgZ2nDunAgdOG7kWkgxrB1IGjDs2Ega+G6vyBob+G6oWNoIHRp4bq/cCB0aOG7iyB2w6AgdOG7k24ga2hvLg0KDQogICoqR+G7o2kgw70gY2hp4bq/biBsxrDhu6NjIGtpbmggZG9hbmgqKg0KDQoqIFThuq1wIHRydW5nIHBow6F0IHRyaeG7g24gY8OhYyBz4bqjbiBwaOG6qW0gcGjDuSBo4bujcCB24bubaSB04burbmcgbmjDs20gdGh1IG5o4bqtcCB2w6AgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuLCB2w60gZOG7pSBz4bqjbiBwaOG6qW0gdGnhu4duIGzhu6NpIGNobyBuaMOzbSDEkeG7mWMgdGjDom4sIHPhuqNuIHBo4bqpbSBnaWEgxJHDrG5oIGNobyBuaMOzbSDEkcOjIGvhur90IGjDtG4gdsOgIHPhu58gaOG7r3UgbmjDoC4NCg0KKiDEkOG6qXkgbeG6oW5oIGNoaeG6v24gZOG7i2NoIHRp4bq/cCB0aOG7iyB0aGVvIHbDuW5nIG1p4buBbiBk4buxYSB0csOqbiBz4buxIGtow6FjIGJp4buHdCB24buBIHPhuqNuIHBo4bqpbSDGsGEgY2h14buZbmcgdsOgIHRow7NpIHF1ZW4gdGnDqnUgZMO5bmcgxJHDoyDEkcaw4bujYyBwaMOibiB0w61jaC4NCg0KKiBUaGnhur90IGvhur8gY8OhYyBjaMawxqFuZyB0csOsbmgga2h1eeG6v24gbcOjaSByacOqbmcgYmnhu4d0IGNobyB04burbmcgcGjDom4ga2jDumMgxJHhu4MgdMSDbmcgc+G7sSB0xrDGoW5nIHTDoWMgdsOgIG3hu6ljIMSR4buZIHRydW5nIHRow6BuaCBj4bunYSBraMOhY2ggaMOgbmcuDQoNCg==