library(readr)
## Warning: package 'readr' was built under R version 4.3.3
library(ggplot2)
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(skimr)
library(psych)
## Warning: package 'psych' was built under R version 4.3.3
## 
## Attaching package: 'psych'
## The following objects are masked from 'package:ggplot2':
## 
##     %+%, alpha
library(csv)
## Warning: package 'csv' was built under R version 4.3.3

1 Phần 1. TÌM HIỂU VÀ CHUẨN BỊ DỮ LIỆU

1.1 Đọc file dữ liệu

d <- read.csv("C:/Users/ASUS/Downloads/Supermarket Transactions.csv", header = T)

1.2 Danh sách các biến

names(d)
##  [1] "X"                 "PurchaseDate"      "CustomerID"       
##  [4] "Gender"            "MaritalStatus"     "Homeowner"        
##  [7] "Children"          "AnnualIncome"      "City"             
## [10] "StateorProvince"   "Country"           "ProductFamily"    
## [13] "ProductDepartment" "ProductCategory"   "UnitsSold"        
## [16] "Revenue"
Tên biến Ý nghĩa
X Ngày mua hàng (định dạng YYYY-MM-DD).
CustomerID Mã định danh duy nhất cho mỗi khách hàng.
Gender Giới tính của khách hàng (M = Male, F = Female).
MaritalStatus Tình trạng hôn nhân (S = Single, M = Married).
Homeowner Khách hàng có sở hữu nhà hay không (Y = Yes, N = No).
Children Số lượng con nhỏ trong gia đình (số nguyên).
AnnualIncome Khoảng thu nhập hàng năm (ví dụ <$25K, $25K–$50K, …).
City Thành phố sinh sống.
StateorProvince Bang hoặc tỉnh tương ứng với thành phố.
Country Quốc gia nơi giao dịch diễn ra.
ProductFamily Nhóm sản phẩm cấp cao (ví dụ Food, Drink, …).
ProductDepartment Bộ phận sản phẩm trong nhóm (ví dụ Beverages, Snack Foods, …).
ProductCategory Hạng mục sản phẩm cụ thể (ví dụ Carbonated Beverages, Candy, …).
UnitsSold Số lượng đơn vị bán ra trong mỗi giao dịch.
Revenue Doanh thu thu về từ giao dịch (đơn vị tiền tệ, ví dụ USD).

1.3 Số biến và số quan sát

dim(d)
## [1] 14059    16

1.4 Kiểm tra cấu trúc tổng quát

str(d)
## '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 ...

1.5 Chọn các biến định tính

dldt <- c("Gender", "MaritalStatus", "Homeowner","City", "StateorProvince", "Country", "ProductFamily", "ProductDepartment", "ProductCategory","AnnualIncome")
dldt
##  [1] "Gender"            "MaritalStatus"     "Homeowner"        
##  [4] "City"              "StateorProvince"   "Country"          
##  [7] "ProductFamily"     "ProductDepartment" "ProductCategory"  
## [10] "AnnualIncome"

1.6 Tạo bộ dữ liệu mới chỉ chứa các biến định tính

dt <- d[, dldt]

1.7 Cấu trúc bộ dữ liệu

str(dt)
## 'data.frame':    14059 obs. of  10 variables:
##  $ Gender           : chr  "F" "M" "F" "M" ...
##  $ MaritalStatus    : chr  "S" "M" "M" "M" ...
##  $ Homeowner        : chr  "Y" "Y" "N" "Y" ...
##  $ 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" ...
##  $ AnnualIncome     : chr  "$30K - $50K" "$70K - $90K" "$50K - $70K" "$30K - $50K" ...

1.8 Một vài dòng đầu và dòng cuối

head(dt)
##   Gender MaritalStatus Homeowner          City StateorProvince Country
## 1      F             S         Y   Los Angeles              CA     USA
## 2      M             M         Y   Los Angeles              CA     USA
## 3      F             M         N     Bremerton              WA     USA
## 4      M             M         Y      Portland              OR     USA
## 5      F             S         Y Beverly Hills              CA     USA
## 6      F             M         Y Beverly Hills              CA     USA
##   ProductFamily ProductDepartment      ProductCategory  AnnualIncome
## 1          Food       Snack Foods          Snack Foods   $30K - $50K
## 2          Food           Produce           Vegetables   $70K - $90K
## 3          Food       Snack Foods          Snack Foods   $50K - $70K
## 4          Food            Snacks                Candy   $30K - $50K
## 5         Drink         Beverages Carbonated Beverages $130K - $150K
## 6          Food              Deli          Side Dishes   $10K - $30K
tail(dt)
##       Gender MaritalStatus Homeowner        City StateorProvince Country
## 14054      F             M         N      Yakima              WA     USA
## 14055      F             M         Y   Bremerton              WA     USA
## 14056      F             M         Y Walla Walla              WA     USA
## 14057      M             S         Y    Portland              OR     USA
## 14058      F             S         N     Spokane              WA     USA
## 14059      M             S         N    Portland              OR     USA
##        ProductFamily ProductDepartment      ProductCategory AnnualIncome
## 14054 Non-Consumable         Household       Paper Products  $10K - $30K
## 14055           Food      Baking Goods         Baking Goods  $10K - $30K
## 14056           Food      Frozen Foods           Vegetables  $10K - $30K
## 14057          Drink         Beverages Pure Juice Beverages  $30K - $50K
## 14058          Drink             Dairy                Dairy  $50K - $70K
## 14059 Non-Consumable         Household           Electrical  $50K - $70K

1.9 Kiểm tra NA

any(is.na(dt))
## [1] FALSE

Vậy bộ dữ liệu không có giá trị thiếu

1.10 Kiểm tra kiểu dữ liệu và đổi về factor

dt <- data.frame(lapply(dt, as.factor))
# Kiểm tra kiểu dữ liệu của từng biến trong dldt
sapply(dt, class)
##            Gender     MaritalStatus         Homeowner              City 
##          "factor"          "factor"          "factor"          "factor" 
##   StateorProvince           Country     ProductFamily ProductDepartment 
##          "factor"          "factor"          "factor"          "factor" 
##   ProductCategory      AnnualIncome 
##          "factor"          "factor"

2 Phần 2. PHÂN TÍCH MÔ TẢ MỘT BIẾN ĐỊNH TÍNH

2.1 Biến Gender

Bảng tần số

#Lập bảng tần số biến Gender
tanso_gender <- table(dt$Gender)
tanso_gender
## 
##    F    M 
## 7170 6889

Biểu đồ

# Vẽ biểu đồ cột cho bảng tần số Gender
barplot(
  tanso_gender,
  main   = "Tần số theo giới tính",
  xlab   = "Giới tính",
  ylab   = "Số quan sát",
  las    = 1,                      
  col    = c("blue", "tomato"),  
  border = "white")

Bảng tần suất

#Lập bảng tần suất của biến Gender
tansuat_gender <- tanso_gender/sum(nrow(dt))
tansuat_gender
## 
##         F         M 
## 0.5099936 0.4900064

Biểu đồ

# Màu cho từng lát
cols <- c("pink", "green")

# Nhãn phần trăm 
nhangender <- paste0(round(tansuat_gender * 100, 1), "%")

# Vẽ pie chart không nhãn
pie(
  tansuat_gender,
  labels = NA,               # ẩn nhãn ngay trên lát
  main   = "Tần suất theo giới tính",
  col    = cols,
  border = "white"
)

# Thêm legend bên ngoài góc phải
legend(
  x      = "topright",
  legend = paste(names(tansuat_gender), nhangender),
  fill   = cols,
)

Nhận xét:

counts <- table(dt$Gender)
diff_count <- abs(counts["F"] - counts["M"])
  • Vậy trong bộ dữ liệu này có 50.9993598 % nữ và 49.0006402% nam.

  • Trong bộ dữ liệu, số lượng nữ là 7170, số lượng nam là

    1. Sự chênh lệch về số lượng giữa nữ và nam là

2.2 Biến Homeowner

Bảng tần số

#Lập bảng tần số biến Homeowner
tanso_homeowner <- table(dt$Homeowner)
tanso_homeowner
## 
##    N    Y 
## 5615 8444

Biểu đồ

barplot(
  tanso_homeowner,
  main = "tần số biến khách hàng có sở hửu nhà",
  xlab = "sỡ hữu nhà",
  ylab = "số lượng",
  las  = 1,
  col  = c("orange","purple"),
  border = "white"
)

Bảng tần suất

#Lập bảng tần suất của biến Homeowner
tansuat_homeowner <- tanso_homeowner/sum(nrow(dt))
tansuat_homeowner
## 
##         N         Y 
## 0.3993883 0.6006117

Biểu đồ

# màu cho từng lát
cols <- c("lightblue","lightpink")
# nhãn phần trăm 
nhanhomeowner <- paste0(round(tansuat_homeowner*100,1),"%")
# vẽ pie chart không nhãn
pie(
  tansuat_homeowner,
  labels = NA,
  main   = "tần số biến khách hàng có sở hửu nhà",
  col    = cols,
  border = "white")
# thêm legend bên ngoài góc phải
legend(
  x      = "topright",
  legend = paste(names(tansuat_homeowner),nhanhomeowner),
  fill   = cols
)

Nhận xét:

counts_homeowner <- table(dt$Homeowner)
diff_homeowner <- abs(counts_homeowner["Y"] - counts_homeowner["N"])
  • Vậy trong bộ dữ liệu này có 39.9388292 % không có nhà và 60.0611708% có nhà.

  • Số lượng người sở hữu nhà là 8444, số lượng người không sở hữu là 5615.

  • Sự chênh lệch về số lượng giữa hai nhóm là 2829 người, nghĩa là số người có nhà nhiều hơn khá đáng kể so với số người không có nhà.

2.3 Biến MaritalStatus

Bảng tần số

#Lập bảng tần số của biến MaritalStatus
tanso_maritalStatus <- table(dt$MaritalStatus)
tanso_maritalStatus
## 
##    M    S 
## 6866 7193

Biểu đồ

# Vẽ biểu đồ cột cho MaritalStatus
barplot(
  tanso_maritalStatus,
  main   = "Tần số biến tình trạng hôn nhân",
  xlab   = "tình trạng hôn nhân",
  ylab   = "Số quan sát",
  las    = 1,
  col    = c("yellow", "green"),
  border = "white"
)

Bảng tần suất

#Lập bảng tần suất của biến MaritalStatus
tansuat_maritalStatus <- tanso_maritalStatus/sum(nrow(dt))
tansuat_maritalStatus
## 
##         M         S 
## 0.4883704 0.5116296

Biểu đồ

# Nhãn phần trăm
nhanmaritalStatus <- paste0( round(tansuat_maritalStatus * 100, 1), "%")

# Vẽ pie chart ẩn nhãn
pie(
  tansuat_maritalStatus,
  labels = NA,
  main   = "Tần suất biến MaritalStatus",
  col    = rainbow(length(nhanmaritalStatus)),
  border = "white")

# Thêm legend bên ngoài
legend(
  x      ="topright",
  legend = paste(names(tansuat_maritalStatus),nhanmaritalStatus),
  fill   = rainbow(length(nhanmaritalStatus))
)

Nhận xét:

# Đếm số người kết hôn (M) và độc thân (S)
ms_counts <- table(dt$MaritalStatus)

# Chênh lệch về số lượng giữa hai nhóm
ms_diff <- abs(ms_counts["M"] - ms_counts["S"])
  • Vậy trong bộ dữ liệu này có 48.8370439 % đã kết hôn và 51.1629561% độc thân.

  • Trong bộ dữ liệu này có 6866 người đã kết hôn và 7193 người độc thân. Nhóm kết hôn nhiều hơn nhóm độc thân 327 người.

2.4 Biến City

Bảng tần số

# Lập bảng tần số biến City
tanso_city <- table(dt$City)

# Sắp xếp giảm dần để xem các thành phố phổ biến nhất
tanso_city <- sort(tanso_city, decreasing = TRUE)

# Hiển thị toàn bộ bảng tần số
tanso_city
## 
##         Salem        Tacoma   Los Angeles       Seattle      Portland 
##          1386          1257           926           922           876 
##       Spokane     San Diego       Hidalgo     Bremerton Beverly Hills 
##           875           866           845           834           811 
##        Merida     Vancouver    San Andres       Orizaba       Camacho 
##           654           633           621           464           452 
##      Acapulco        Yakima   Mexico City      Victoria   Walla Walla 
##           383           376           194           176           160 
##    Bellingham San Francisco   Guadalajara 
##           143           130            75

Biểu đồ

barplot(
  tanso_city,
  main   = "Tần số biến thành phố",
  cex.names = 0.4,
  xlab   = "Số quan sát",
  ylab   = "Thành phố",
  las    = 1,            # xoay nhãn trục y ngang
  col    = "steelblue",
  border = "white",
  horiz  = TRUE          # vẽ thanh ngang để đọc nhãn dễ hơn
)

Bảng tần suất

tansuat_city  <- tanso_city/sum(nrow(dt))
tansuat_city
## 
##         Salem        Tacoma   Los Angeles       Seattle      Portland 
##   0.098584537   0.089408920   0.065865282   0.065580767   0.062308841 
##       Spokane     San Diego       Hidalgo     Bremerton Beverly Hills 
##   0.062237712   0.061597553   0.060103848   0.059321431   0.057685468 
##        Merida     Vancouver    San Andres       Orizaba       Camacho 
##   0.046518245   0.045024539   0.044170994   0.033003770   0.032150224 
##      Acapulco        Yakima   Mexico City      Victoria   Walla Walla 
##   0.027242336   0.026744434   0.013798990   0.012518671   0.011380610 
##    Bellingham San Francisco   Guadalajara 
##   0.010171420   0.009246746   0.005334661

Biểu đồ

# Màu cho từng lát
cols <- rainbow(length(tansuat_city))

# Nhãn phần trăm
nhancity <- paste0( round(tansuat_city * 100, 1), "%")

# Vẽ pie chart ẩn nhãn
pie(
  tansuat_city,
  labels = NA,
  main   = "Tần suất biến city",
  col    = cols,
  border = "white")

# Thêm legend bên ngoài
legend(
  x         ="topright",
  legend    = paste(names(tansuat_city),nhancity),
  fill      = cols,
  bty       = "n",       # bỏ viền
  cex       = 0.5,       # thu nhỏ chữ
  ncol      = 2,         # chia thành 2 cột
  x.intersp = 0.5,       # giãn khoảng cách chữ–ký hiệu ngang
  y.intersp = 0.7        # giãn khoảng cách giữa các dòng
)

Nhận xét:

  • Trong bộ dữ liệu này, thành phố có tỷ lệ giao dịch cao nhất là Salem với khoảng 9.86%, tiếp theo là Tacoma (8.94%), Los Angeles (6.59%) và Seattle (6.56%).

  • Các thành phố nhỏ hơn như Hidalgo (6.01%) hoặc Guadalajara (0.53%) có tỷ lệ thấp hơn nhiều.

  • Điều này cho thấy giao dịch chủ yếu tập trung ở một số thành phố lớn với dân số hoặc hoạt động kinh tế cao hơn. Các thành phố nhỏ hơn đóng góp ít hơn vào tổng số giao dịch, có thể do quy mô thị trường nhỏ hoặc mức độ phổ biến của sản phẩm thấp.

  • Ngoài ra, việc phân bố này cũng có thể phản ánh chiến lược tiếp thị hoặc kênh phân phối mà siêu thị đang tập trung vào các khu vực đô thị lớn.

2.5 Biến StateorProvince

Bảng tần số

#Lập bảng tần số của biến StateorProvince
tanso_stateorProvince <- table(dt$StateorProvince)
tanso_stateorProvince
## 
##        BC        CA        DF  Guerrero   Jalisco        OR  Veracruz        WA 
##       809      2733       815       383        75      2262       464      4567 
##   Yucatan Zacatecas 
##       654      1297

Biểu đồ

barplot(
  tanso_stateorProvince,
  main   = "Tần số biến bang hoặc tỉnh",
  cex.names = 0.4,
  xlab   = "Số quan sát",
  ylab   = "bang hoặc tỉnh",
  las    = 1,            # xoay nhãn trục y ngang
  col    = "green",
  border = "white",
  horiz  = TRUE          # vẽ thanh ngang để đọc nhãn dễ hơn
)

Bảng tần suất

#Lập bảng tần suất của biến StateorProvince
tansuat_stateorProvince <- tanso_stateorProvince/sum(nrow(dt))
tansuat_stateorProvince
## 
##          BC          CA          DF    Guerrero     Jalisco          OR 
## 0.057543211 0.194395049 0.057969984 0.027242336 0.005334661 0.160893378 
##    Veracruz          WA     Yucatan   Zacatecas 
## 0.033003770 0.324845295 0.046518245 0.092254072

Đồ thị

# Màu cho từng lát
cols <- rainbow(length(tansuat_stateorProvince))

# Nhãn phần trăm
nhanstateorProvince <- paste0( round(tansuat_stateorProvince * 100, 1), "%")

# Vẽ pie chart ẩn nhãn
pie(
  tansuat_stateorProvince,
  labels = NA,
  main   = "Tần suất biến bang hoặc tỉnh",
  col    = cols,
  border = "white")

# Thêm legend bên ngoài
legend(
  x         ="topright",
  legend    = paste(names(tansuat_stateorProvince),nhanstateorProvince),
  fill      = cols,
  bty       = "n",       # bỏ viền
  cex       = 0.5,       # thu nhỏ chữ
  ncol      = 2,         # chia thành 2 cột
)

Nhận xét: Trong bộ dữ liệu này, bang hoặc tỉnh có tỷ lệ giao dịch lớn nhất là WA với khoảng 32.48%, tiếp theo là CA (19.44%) và OR (16.09%). Các bang như Jalisco (0.53%) và Guerrero (2.72%) chiếm tỷ lệ thấp hơn. Như vậy, dữ liệu cho thấy sự tập trung giao dịch cao ở một số bang chính.

2.6 Biến Country

Bảng tần số

#Lập bảng tần số của biến Country
tanso_country <- table(dt$Country)
tanso_country
## 
## Canada Mexico    USA 
##    809   3688   9562

Biểu đồ

barplot(
  tanso_country,
  main   = "tần số biến quốc gia",
  xlab   = "quốc gia",
  ylab   = "số lượng",
  las    = 1,
  col    = c("brown","orange","pink"),
  border = "white"
)

Bảng tần suất

#Lập bảng tần suất của biến Country
tansuat_country <- tanso_country/sum(nrow(dt))
tansuat_country
## 
##     Canada     Mexico        USA 
## 0.05754321 0.26232307 0.68013372

Biểu đồ

# Nhãn phần trăm
nhancountry <- paste0( round(tansuat_country * 100, 1), "%")
# Vẽ pie chart ẩn nhãn
pie(
  tansuat_country,
  labels = NA,
  main   = "Tần suất biến quốc gia",
  col    = rainbow(length(nhancountry)),
  border = "white")

# Thêm legend bên ngoài
legend(
  x      ="topright",
  legend = paste(names(tansuat_country),nhancountry),
  fill   = rainbow(length(nhancountry)),
  bty    ="n"
)

Nhận xét:

# Đếm số bản ghi theo quốc gia
cty_counts <- table(dt$Country)

# Chênh lệch về số lượng giữa quốc gia đông nhất và ít nhất
cty_diff <- max(cty_counts) - min(cty_counts)
  • Vậy trong bộ dữ liệu này có 5.7543211 % ở Canada, 26.2323067% ở Mexico và 68.0133722% ở USA.

  • Quốc gia đông nhất có 9562, quốc gia ít nhất có r min(cty_counts).

  • Sự chênh lệch giữa hai quốc gia này là 8753 người.

2.7 Biến ProductFamily

Bảng tần số

#Lập bảng tần số của biến ProductFamily
tanso_productFamily <- table(dt$ProductFamily)
tanso_productFamily
## 
##          Drink           Food Non-Consumable 
##           1250          10153           2656

Biểu đồ

barplot(
  tanso_productFamily,
  main   = "tần số biến nhóm sản phẩm",
  xlab   = "nhóm sản phẩm",
  ylab   = "số lượng",
  las    = 1,
  col    = c("yellow","purple","pink"),
  border = "white"
)

Bảng tần suất

#Lập bảng tần suất của biến ProductFamily
tansuat_productFamily <- tanso_productFamily/sum(nrow(dt))
tansuat_productFamily
## 
##          Drink           Food Non-Consumable 
##     0.08891102     0.72217085     0.18891813

Biểu đồ

cols <- c("lightblue","lightpink","lightgreen")
# Nhãn phần trăm
nhanproductFamily <- paste0( round(tansuat_productFamily * 100, 1), "%")
# Vẽ pie chart ẩn nhãn
pie(
  tansuat_productFamily,
  labels = NA,
  main   = "Tần suất biến nhóm sản phẩm",
  col    = cols,
  border = "white")

# Thêm legend bên ngoài
legend(
  x      ="topright",
  legend = paste(names(tansuat_productFamily),nhanproductFamily),
  fill   = cols,
  )

Nhận xét:

  • Vậy trong bộ dữ liệu này có 8.8911018 % đồ uống, 72.2170851% thức ăn và 18.8918131% không tiêu thụ được.

2.8 Biến ProductDepartment

Bảng tần số

# Lập bảng tần số
tanso_productDepartment <- table(dt$ProductDepartment)
tanso_productDepartment
## 
## Alcoholic Beverages         Baked Goods        Baking Goods           Beverages 
##                 356                 425                1072                 680 
##     Breakfast Foods        Canned Foods     Canned Products            Carousel 
##                 188                 977                 109                  59 
##            Checkout               Dairy                Deli                Eggs 
##                  82                 903                 699                 198 
##        Frozen Foods  Health and Hygiene           Household                Meat 
##                1382                 893                1420                  89 
##         Periodicals             Produce             Seafood         Snack Foods 
##                 202                1994                 102                1600 
##              Snacks       Starchy Foods 
##                 352                 277

Biểu đồ

barplot(
  tanso_productDepartment,
  main   = "Tần số biến bộ phận sản phẩm trong nhóm",
  cex.names = 0.4,
  xlab   = "Số quan sát",
  ylab   = "",
  las    = 1,            # xoay nhãn trục y ngang
  col    = "lightblue",
  border = "white",
  horiz  = TRUE          # vẽ thanh ngang để đọc nhãn dễ hơn
)

Bảng tần suất

tansuat_productDepartment <-tanso_productDepartment/sum(nrow(dt))
tansuat_productDepartment
## 
## Alcoholic Beverages         Baked Goods        Baking Goods           Beverages 
##         0.025321858         0.030229746         0.076250089         0.048367594 
##     Breakfast Foods        Canned Foods     Canned Products            Carousel 
##         0.013372217         0.069492852         0.007753041         0.004196600 
##            Checkout               Dairy                Deli                Eggs 
##         0.005832563         0.064229319         0.049719041         0.014083505 
##        Frozen Foods  Health and Hygiene           Household                Meat 
##         0.098300021         0.063518031         0.101002916         0.006330464 
##         Periodicals             Produce             Seafood         Snack Foods 
##         0.014368020         0.141830856         0.007255139         0.113806103 
##              Snacks       Starchy Foods 
##         0.025037343         0.019702682

Nhận xét:

  • Trong bộ dữ liệu, nhóm sản phẩm có tỷ lệ giao dịch cao nhất là Produce với 14.18%, tiếp theo là Snack Foods (11.38%) và Household (10.1%). Nhóm Frozen Foods cũng chiếm tỷ lệ đáng kể là 9.83%. Các nhóm như Carousel (0.42%) và Checkout (0.58%) có tỷ lệ thấp hơn nhiều.

2.9 Biến ProductCategory

Bảng tần số

tanso_productCategory <- table(dt$ProductCategory)
tanso_productCategory
## 
##         Baking Goods    Bathroom Products        Beer and Wine 
##                  484                  365                  356 
##                Bread      Breakfast Foods              Candles 
##                  425                  417                   45 
##                Candy     Canned Anchovies         Canned Clams 
##                  352                   44                   53 
##       Canned Oysters      Canned Sardines        Canned Shrimp 
##                   35                   40                   38 
##          Canned Soup          Canned Tuna Carbonated Beverages 
##                  404                   87                  154 
##    Cleaning Supplies        Cold Remedies                Dairy 
##                  189                   93                  903 
##        Decongestants               Drinks                 Eggs 
##                   85                  135                  198 
##           Electrical      Frozen Desserts       Frozen Entrees 
##                  355                  323                  118 
##                Fruit             Hardware        Hot Beverages 
##                  765                  129                  226 
##              Hygiene     Jams and Jellies     Kitchen Products 
##                  197                  588                  217 
##            Magazines                 Meat        Miscellaneous 
##                  202                  761                   42 
##  Packaged Vegetables       Pain Relievers       Paper Products 
##                   48                  192                  345 
##                Pizza     Plastic Products Pure Juice Beverages 
##                  194                  141                  165 
##              Seafood          Side Dishes          Snack Foods 
##                  102                  153                 1600 
##            Specialty        Starchy Foods           Vegetables 
##                  289                  277                 1728

Biểu đồ

barplot(
  tanso_productCategory,
  main   = "Tần số biến hạng mục sản phẩm cụ thể",
  cex.names = 0.4,
  xlab   = "Số quan sát",
  ylab   = "",
  las    = 1,            # xoay nhãn trục y ngang
  col    = "lightpink",
  border = "white",
  horiz  = TRUE          # vẽ thanh ngang để đọc nhãn dễ hơn
)

Bảng tần suất

tansuat_productCategory <- tanso_productCategory/sum(nrow(dt)) 
tansuat_productCategory
## 
##         Baking Goods    Bathroom Products        Beer and Wine 
##          0.034426346          0.025962017          0.025321858 
##                Bread      Breakfast Foods              Candles 
##          0.030229746          0.029660716          0.003200797 
##                Candy     Canned Anchovies         Canned Clams 
##          0.025037343          0.003129668          0.003769827 
##       Canned Oysters      Canned Sardines        Canned Shrimp 
##          0.002489508          0.002845153          0.002702895 
##          Canned Soup          Canned Tuna Carbonated Beverages 
##          0.028736041          0.006188207          0.010953837 
##    Cleaning Supplies        Cold Remedies                Dairy 
##          0.013443346          0.006614980          0.064229319 
##        Decongestants               Drinks                 Eggs 
##          0.006045949          0.009602390          0.014083505 
##           Electrical      Frozen Desserts       Frozen Entrees 
##          0.025250729          0.022974607          0.008393200 
##                Fruit             Hardware        Hot Beverages 
##          0.054413543          0.009175617          0.016075112 
##              Hygiene     Jams and Jellies     Kitchen Products 
##          0.014012376          0.041823743          0.015434953 
##            Magazines                 Meat        Miscellaneous 
##          0.014368020          0.054129028          0.002987410 
##  Packaged Vegetables       Pain Relievers       Paper Products 
##          0.003414183          0.013656732          0.024539441 
##                Pizza     Plastic Products Pure Juice Beverages 
##          0.013798990          0.010029163          0.011736254 
##              Seafood          Side Dishes          Snack Foods 
##          0.007255139          0.010882709          0.113806103 
##            Specialty        Starchy Foods           Vegetables 
##          0.020556227          0.019702682          0.122910591

Nhận xét:

  • Trong bộ dữ liệu, nhóm sản phẩm có tỷ lệ giao dịch cao nhất là Vegetables với 12.29%, tiếp theo là Snack Foods (11.38%) và Dairy (6.42%). Các nhóm đóng hộp như Canned Oysters (0.25%) và Canned Clams (0.38%) chiếm tỷ lệ rất nhỏ, cho thấy sự ưu tiên mua hàng tươi và đồ ăn nhẹ.

2.10 Biến AnnualIncome

Bảng tần số

# Bảng tần suất cho AnnualIncome
tanso_annualIncome <- table(dt$AnnualIncome)
tanso_annualIncome
## 
##   $10K - $30K $110K - $130K $130K - $150K       $150K +   $30K - $50K 
##          3090           643           760           273          4601 
##   $50K - $70K   $70K - $90K  $90K - $110K 
##          2370          1709           613

Biểu đồ

barplot(
  tanso_annualIncome,
  main   = "Tần số theo Thu nhập",
  cex.names = 0.4,
  xlab   = "AnnualIncome",
  ylab   = "số thu nhập",
  las    = 1,            # xoay nhãn trục y ngang
  col    = "lightblue",
  border = "white",
  horiz  = TRUE          # vẽ thanh ngang để đọc nhãn dễ hơn
)

Bảng tần suất

tansuat_annualIncome <- tanso_annualIncome/sum(nrow(dt)) 
tansuat_annualIncome
## 
##   $10K - $30K $110K - $130K $130K - $150K       $150K +   $30K - $50K 
##    0.21978804    0.04573583    0.05405790    0.01941817    0.32726367 
##   $50K - $70K   $70K - $90K  $90K - $110K 
##    0.16857529    0.12155914    0.04360196

Biểu đồ

# Màu cho từng lát
cols <- rainbow(length(tansuat_annualIncome))

# Nhãn phần trăm
nhanannualIncome <- paste0( round(tansuat_annualIncome * 100, 1), "%")

# Vẽ pie chart ẩn nhãn
pie(
  tansuat_annualIncome,
  labels = NA,
  main   = "Tần suất biến thu nhập",
  col    = cols,
  border = "white")

# Thêm legend bên ngoài
legend(
  x         ="topright",
  legend    = paste(names(tansuat_annualIncome),nhanannualIncome),
  fill      = cols,
  bty       = "n",       # bỏ viền
  cex       = 0.5,       # thu nhỏ chữ
  ncol      = 2,         # chia thành 2 cột
  x.intersp = 0.5,       # giãn khoảng cách chữ–ký hiệu ngang
  y.intersp = 0.7        # giãn khoảng cách giữa các dòng
)

Nhận xét:

  • Sự phân bố thu nhập không đều phản ánh cơ cấu khách hàng của siêu thị hoặc đơn vị khảo sát: tập trung nhiều ở các nhóm thu nhập trung bình đến trung cao, trong khi nhóm thu nhập quá thấp hoặc quá cao xuất hiện ít hơn.

  • Đây có thể là dấu hiệu để doanh nghiệp điều chỉnh chiến lược tiếp cận thị trường, như tập trung nhiều hơn vào các nhóm thu nhập đang chiếm ưu thế, hoặc mở rộng các chính sách ưu đãi để thu hút nhóm khách hàng ít phổ biến hơn.

3 Phần 3. ƯỚC LƯỢNG KHOẢNG VÀ KIỂM ĐỊNH GIẢ THUYẾT CHO TỶ LỆ (MỘT BIẾN)

# Tổng số bản ghi (n)
n <- nrow(dt)

Giả thuyết đặt ra như sau:

  • H₀: p = p₀

  • H₁: p ≠ p₀

3.1 Gender (female)

# 1) Đếm số khách nữ
count_female <- sum(dt$Gender == "F")

# 2) Đặt H₀: p_F = 0.50; H₁: p_F ≠ 0.50
p0 <- 0.5
# 3) Thực hiện prop.test
res_female <- prop.test(x         = count_female,
                        n         = n,
                        p         = p0,
                        conf.level= 0.95)
print(res_female)
## 
##  1-sample proportions test with continuity correction
## 
## data:  count_female out of n, null probability p0
## X-squared = 5.5765, df = 1, p-value = 0.0182
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5016931 0.5182886
## sample estimates:
##         p 
## 0.5099936

Nhận xét

  • Ta có p-value = 0.0182 < α = 0.05, bác H₀ (tỉ lệ nữ = 0.5) và chấp nhận H₁: tỉ lệ nữ khác 50% ở mức ý nghĩa 5%.

  • Khoảng tin cậy 95% cho tỉ lệ nữ là [0.5017, 0.5183], không chứa 0.5, củng cố rằng tỉ lệ nữ thực sự cao hơn 50%.

  • Ước tính tỉ lệ nữ trong mẫu là p̂ ≈ 0.51 (51%), nghĩa là tỉ lệ nữ vượt ngưỡng 50% khoảng 1%.

3.2 Homeowner (yes)

count_owner <- sum(dt$Homeowner == "Y")
p0_owner   <- 0.50   # Giả thuyết H₀: 50% là có sỡ hữu nhà

res_owner <- prop.test(x         = count_owner,
                       n         = n,
                       p         = p0_owner,
                       conf.level= 0.95)
print(res_owner)
## 
##  1-sample proportions test with continuity correction
## 
## data:  count_owner out of n, null probability p0_owner
## X-squared = 568.86, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5924537 0.6087145
## sample estimates:
##         p 
## 0.6006117

Nhận xét

  • Ta có p-value < 2.2e-16 < α = 0.05, nên bác bỏ H₀ (tỉ lệ sở hữu nhà = 0.5) và chấp nhận H₁: tỉ lệ chủ sở hữu khác 50% ở mức ý nghĩa 5%.

  • Khoảng tin cậy 95% cho tỉ lệ chủ sở hữu là [0.5925, 0.6087], không bao gồm 0.5, khẳng định tỉ lệ chủ sở hữu thực sự cao hơn 50%.

  • Ước tính tỉ lệ chủ sở hữu trong mẫu là p̂ ≈ 0.6006 (60.06%), nghĩa là tỉ lệ chủ sở hữu vượt 50% khoảng 10%.

3.3 ProductFamily (food)

count_food <- sum(dt$ProductFamily == "Food")
p0_food    <- 0.50   # H₀: 50% giao dịch thuộc nhóm Food

res_food <- prop.test(x         = count_food,
                      n         = n,
                      p         = p0_food,
                      conf.level= 0.95)
print(res_food)
## 
##  1-sample proportions test with continuity correction
## 
## data:  count_food out of n, null probability p0_food
## X-squared = 2774.9, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.7146709 0.7295489
## sample estimates:
##         p 
## 0.7221709

Nhận xét

  • Ta có p-value < 2.2e-16 < α = 0.05, nên bác bỏ H₀ (tỉ lệ food = 0.5) và chấp nhận H₁: tỉ lệ food khác 50% ở mức ý nghĩa 5%.

  • Khoảng tin cậy 95% cho tỉ lệ food là [0.7147, 0.7295], không bao gồm 0.5, khẳng định tỉ lệ food thực sự cao hơn 50%.

  • Ước tính tỉ lệ food trong mẫu là p̂ ≈ 0.7222 (72.22%), nghĩa là tỉ lệ food vượt ngưỡng 50% khoảng 22%—một chênh lệch đáng kể cả về thực tiễn và thống kê.

4 Phần 4. PHÂN TÍCH MỐI QUAN HỆ GIỮA HAI BIẾN ĐỊNH TÍNH

4.1 Gender và ProductFamily

4.1.1 Bảng tần số và tần suất

# Bảng chéo counts
tab_gf <- table(Gender = dt$Gender, ProductFamily = dt$ProductFamily)
tab_gf
##       ProductFamily
## Gender Drink Food Non-Consumable
##      F   669 5149           1352
##      M   581 5004           1304
# Tỉ lệ theo hàng (row‐%)
pct_gf <- round(prop.table(tab_gf, margin = 1) * 100, 1)
pct_gf
##       ProductFamily
## Gender Drink Food Non-Consumable
##      F   9.3 71.8           18.9
##      M   8.4 72.6           18.9

Nhận xét

Drink

  • Về số lượng: nữ có 669 giao dịch so với 581 của nam, nhiều hơn 88 giao dịch.

  • Về tỉ lệ: nữ chiếm 9.3% tổng giao dịch của mình, nam chiếm 8.4%, chênh +0.9%.

Vậy phụ nữ có xu hướng mua đồ uống hơi nhiều hơn nam, nhưng chênh chưa đến 1%.

Food

  • Về số lượng: nữ 5.149 giao dịch, nam 5.004, nhiều hơn 145 giao dịch.

  • Về tỉ lệ: nữ 71.8%, nam 72.6%, chênh −0.8%.

Vậy dù có nhiều giao dịch Food hơn về con số tuyệt đối, vì tổng giao dịch của nữ cũng nhiều hơn, nên tỉ lệ lại thấp hơn nam một chút.

Non-Consumable

  • Về số lượng: nữ 1.352 giao dịch, nam 1.304, nhiều hơn 48 giao dịch.

  • Về tỉ lệ: cả hai đều 18.9%, chênh 0.0%.

vậy sự khác biệt thật sự rất nhỏ, tỉ lệ ngang bằng.

4.1.2 Đồ thị

library(ggplot2)
gf_df <- as.data.frame(table(Gender = dt$Gender, ProductFamily = dt$ProductFamily))

ggplot(  gf_df, aes(x     = ProductFamily,y     = Freq, fill  = Gender, group = Gender)) +
  geom_col(position = position_dodge(width = 0.8),  width    = 0.7) +
  scale_fill_manual(
    name   = "Giới tính",
    values = c("F" = "lightgreen", "M" = "yellow"),
    labels = c("Nữ", "Nam")
  ) +
  labs(
    title = "Số giao dịch theo sản phẩm & giới tính",
    x     = "Nhóm sản phẩm",
    y     = "Số giao dịch"
  ) +
  theme_minimal()

4.1.3 Kiểm định Chi-bình phương độc lập

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

  • H₀: Giới và nhóm sản phẩmlà hai biến độc lập.

  • H₁: Giới và nhóm sản phẩm có liên quan.

test_gf <- chisq.test(tab_gf)
test_gf
## 
##  Pearson's Chi-squared test
## 
## data:  tab_gf
## X-squared = 3.5185, df = 2, p-value = 0.1722

Nhận xét

  • p-value = 0.1722 > 0.05 vậy chấp nhận H₀ nghĩa là không đủ bằng chứng để cho rằng giới tính ảnh hưởng đáng kể đến nhóm sản phẩm mua.

4.2 MaritalStatus và Homeowner

4.2.1 Bảng tần số và tần suất

tab_mo <- table(Marital = dt$MaritalStatus, Owner = dt$Homeowner)
tab_mo
##        Owner
## Marital    N    Y
##       M 1719 5147
##       S 3896 3297
pct_mo <- round(prop.table(tab_mo, margin = 1) * 100, 1)
pct_mo
##        Owner
## Marital    N    Y
##       M 25.0 75.0
##       S 54.2 45.8
# Giả sử tab_mo đã được tạo như trên
diff_owner_count     <- tab_mo["M", "Y"] - tab_mo["S", "Y"]
diff_not_owner_count <- tab_mo["S", "N"] - tab_mo["M", "N"]

Nhận xét

  • Trong bộ dữ liệu, có 3896 người độc thân không sở hữu nhà và 3297 người độc thân sở hữu nhà. Ngoài ra, có 1719 người đã kết hôn không sở hữu nhà và 5147 người đã kết hôn sở hữu nhà.

  • Số người đã kết hôn sở hữu nhà nhiều hơn người độc thân là 1850 người.

  • Người độc thân không sở hữu nhà nhiều hơn người đã kết hôn là 2177 người.

4.2.2 Đồ thi

library(ggplot2)
mo_df <- as.data.frame(table(Marital = dt$MaritalStatus, Owner   = dt$Homeowner))

ggplot(  mo_df, aes(x     = Marital,y     = Freq, fill  = Owner, group = Owner)) +
  geom_col(position = position_dodge(width = 0.8),  width    = 0.7) +
  scale_fill_manual(
    name   = "Sở hữu nhà",
    values = c("Y" = "lightblue","N" = "lightpink"),
    labels = c("Có", "Không")
  ) +
  labs(
    title = "Số khách có/không sở hữu nhà theo tình trạng hôn nhân",
    x     = "Tình trạng hôn nhân",
    y     = "Số khách hàng"
  ) +
  theme_minimal()

4.2.3 Kiểm định Chi-bình phương độc lập

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

  • H₀: Tình trạng hôn nhân và việc sở hữu nhà là hai biến độc lập.

  • H₁: Tình trạng hôn nhân và việc sở hữu nhà có liên quan.

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

Nhận xét

  • p-value < 2.2e-16 < 0.05 vậy bác bỏ H₀ nghĩa là đủ bằng chứng để cho rằng Tình trạng hôn nhân và việc sở hữu nhà có liên quan.

4.3 AnnualIncome và ProductCategory

4.3.1 Bảng tần số và tần suất

tab_ap <- table(Income = dt$AnnualIncome, Category = dt$ProductCategory)
tab_ap
##                Category
## Income          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
##                Category
## Income          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
##                Category
## Income          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
##                Category
## Income          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
##                Category
## Income          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
##                Category
## Income          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
##                Category
## Income          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
##                Category
## Income          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
##                Category
## Income          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
##                Category
## Income          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
pct_ap <- round(prop.table(tab_ap, margin = 1) * 100, 1)
pct_ap
##                Category
## Income          Baking Goods Bathroom Products Beer and Wine Bread
##   $10K - $30K            3.9               2.8           2.6   3.5
##   $110K - $130K          2.8               2.5           2.2   3.6
##   $130K - $150K          2.9               2.5           2.0   3.2
##   $150K +                4.0               2.9           1.1   3.7
##   $30K - $50K            3.3               2.5           2.6   2.9
##   $50K - $70K            3.6               2.1           2.6   2.7
##   $70K - $90K            3.5               3.0           2.3   2.9
##   $90K - $110K           2.9               3.3           3.8   2.1
##                Category
## Income          Breakfast Foods Candles Candy Canned Anchovies Canned Clams
##   $10K - $30K               3.6     0.2   2.5              0.3          0.4
##   $110K - $130K             1.1     0.2   2.5              0.3          0.2
##   $130K - $150K             3.7     0.3   2.5              0.1          0.4
##   $150K +                   2.6     0.4   2.9              0.4          0.4
##   $30K - $50K               3.1     0.5   2.8              0.3          0.4
##   $50K - $70K               2.6     0.3   2.5              0.3          0.3
##   $70K - $90K               2.5     0.4   1.7              0.4          0.4
##   $90K - $110K              2.8     0.0   2.8              0.3          0.5
##                Category
## Income          Canned Oysters Canned Sardines Canned Shrimp Canned Soup
##   $10K - $30K              0.2             0.3           0.3         3.2
##   $110K - $130K            0.6             0.3           0.0         3.0
##   $130K - $150K            0.4             0.1           0.3         2.2
##   $150K +                  0.4             0.4           0.0         2.9
##   $30K - $50K              0.2             0.4           0.3         3.0
##   $50K - $70K              0.2             0.2           0.3         2.8
##   $70K - $90K              0.3             0.2           0.1         2.9
##   $90K - $110K             0.3             0.3           0.3         1.3
##                Category
## Income          Canned Tuna Carbonated Beverages Cleaning Supplies
##   $10K - $30K           0.4                  1.2               1.5
##   $110K - $130K         0.5                  0.9               1.2
##   $130K - $150K         0.7                  0.4               0.9
##   $150K +               1.1                  2.2               1.5
##   $30K - $50K           0.6                  1.1               1.1
##   $50K - $70K           0.8                  0.8               1.5
##   $70K - $90K           0.6                  1.3               1.5
##   $90K - $110K          1.0                  1.5               2.0
##                Category
## Income          Cold Remedies Dairy Decongestants Drinks Eggs Electrical
##   $10K - $30K             0.7   5.6           0.7    1.0  1.2        2.4
##   $110K - $130K           0.3   5.9           0.6    1.4  1.4        3.1
##   $130K - $150K           0.8   6.4           0.7    1.1  2.0        2.8
##   $150K +                 1.1   6.2           0.0    1.5  1.5        2.9
##   $30K - $50K             0.7   6.5           0.7    1.0  1.5        2.5
##   $50K - $70K             0.5   6.8           0.3    0.8  1.5        2.4
##   $70K - $90K             0.6   7.4           0.6    0.9  1.2        2.8
##   $90K - $110K            0.8   6.5           0.8    0.5  1.6        2.3
##                Category
## Income          Frozen Desserts Frozen Entrees Fruit Hardware Hot Beverages
##   $10K - $30K               2.4            0.6   4.9      1.0           1.6
##   $110K - $130K             2.6            1.6   4.5      0.5           1.7
##   $130K - $150K             2.2            0.7   6.3      1.3           1.2
##   $150K +                   2.9            0.7   3.7      0.4           1.8
##   $30K - $50K               2.4            0.8   5.5      0.9           1.7
##   $50K - $70K               1.9            0.9   5.7      1.1           1.4
##   $70K - $90K               2.1            1.1   6.1      0.8           1.5
##   $90K - $110K              2.3            1.1   5.9      0.8           2.4
##                Category
## Income          Hygiene Jams and Jellies Kitchen Products Magazines Meat
##   $10K - $30K       1.2              4.4              1.5       1.6  5.0
##   $110K - $130K     0.9              4.8              0.8       2.6  6.4
##   $130K - $150K     1.8              4.2              1.8       1.2  6.8
##   $150K +           1.5              2.9              1.1       0.4  5.1
##   $30K - $50K       1.3              4.0              1.6       1.4  5.5
##   $50K - $70K       1.6              4.3              2.2       1.5  4.9
##   $70K - $90K       1.7              4.2              1.2       1.1  5.9
##   $90K - $110K      1.5              3.4              0.5       1.1  4.9
##                Category
## Income          Miscellaneous Packaged Vegetables Pain Relievers Paper Products
##   $10K - $30K             0.3                 0.3            1.4            2.3
##   $110K - $130K           0.2                 0.2            1.1            3.0
##   $130K - $150K           0.8                 0.1            1.1            2.2
##   $150K +                 0.0                 0.7            1.8            2.9
##   $30K - $50K             0.2                 0.4            1.3            2.2
##   $50K - $70K             0.6                 0.3            1.4            2.8
##   $70K - $90K             0.1                 0.4            1.8            2.7
##   $90K - $110K            0.2                 0.0            0.8            2.8
##                Category
## Income          Pizza Plastic Products Pure Juice Beverages Seafood Side Dishes
##   $10K - $30K     1.6              1.3                  1.1     0.6         1.2
##   $110K - $130K   2.0              0.9                  1.4     0.5         0.3
##   $130K - $150K   1.6              0.9                  0.7     1.1         1.1
##   $150K +         0.4              0.7                  1.8     1.8         1.1
##   $30K - $50K     1.3              0.7                  1.1     1.0         1.2
##   $50K - $70K     1.3              1.3                  1.1     0.5         1.0
##   $70K - $90K     0.9              1.0                  1.5     0.7         1.3
##   $90K - $110K    2.1              0.7                  1.5     0.3         0.8
##                Category
## Income          Snack Foods Specialty Starchy Foods Vegetables
##   $10K - $30K          10.6       2.1           2.3       12.5
##   $110K - $130K        13.2       2.0           2.8       11.5
##   $130K - $150K        10.9       2.4           2.0       11.4
##   $150K +              12.8       1.8           1.8       11.7
##   $30K - $50K          11.6       2.1           1.8       12.0
##   $50K - $70K          11.6       2.1           2.0       12.7
##   $70K - $90K          10.8       1.9           1.6       12.6
##   $90K - $110K         12.6       1.6           1.3       13.7

Nhận xét

  • Nhóm thu nhập từ "$30K - $50K" ghi nhận số giao dịch cao nhất ở hầu hết các danh mục, ví dụ:

    • Snack Foods: 533 giao dịch.
    • Vegetables: 551 giao dịch.
    • Dairy: 299 giao dịch.

    Điều này có thể là do nhóm thu nhập trung lưu có khả năng chi tiêu cao nhưng vẫn ưu tiên các mặt hàng thiết yếu.

  • Nhóm thu nhập thấp ("$10K - $30K") cũng có lượng giao dịch tương đối lớn, đặc biệt ở:

    • Vegetables: 385 giao dịch.
    • Snack Foods: 329 giao dịch.

    Điều này cho thấy nhu cầu với sản phẩm cơ bản, giá cả phải chăng vẫn rất cao.

  • Ngược lại, nhóm thu nhập cao ("$130K - $150K", "$150K +") có số giao dịch thấp hơn rõ rệt, ví dụ:

    • Snack Foods: 35 giao dịch.
    • Vegetables: 32 giao dịch.

    Có thể do số mẫu nhóm thu nhập cao ít hơn hoặc họ ưu tiên mua sắm online, sản phẩm cao cấp hơn.

4.3.2 Kiểm định Chi-bình phương độc lập

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

  • H₀: Hai biến khoảng thu nhập hằng năm và hạng mục sản phẩm là độc lập.

  • H₁: Hai biến khoảng thu nhập hằng năm và hạng mục sản phẩm có mối liên quan.

test_sp <- chisq.test(tab_ap)
## Warning in chisq.test(tab_ap): Chi-squared approximation may be incorrect
test_sp
## 
##  Pearson's Chi-squared test
## 
## data:  tab_ap
## X-squared = 295.23, df = 308, p-value = 0.6897

Nhận xét

  • p-value = 0.6897 > 0.05 vậy chấp nhận H₀ nghĩa là không đủ bằng chứng để cho rằng Hai biến khoảng thu nhập hằng năm và hạng mục sản phẩm là độc lập.

5 Phần 5: TỔNG KẾT VÀ THẢO LUẬN

5.1 Tóm tắt kết quả chính

5.1.1 Nhân khẩu học

  • Giới tính:
    • Nữ chiếm 51%, nam chiếm 49%—tương đối cân bằng.
    • Hành vi mua sắm tương đồng, chỉ khác biệt nhỏ ở một số danh mục (ví dụ: Women’s Health, Beauty).
  • Tình trạng hôn nhân & Nhà ở:
    • Người đã kết hôn (M) và độc thân (S) phân bố gần bằng nhau.
    • 60% khách hàng sở hữu nhà (Homeowner = Y).
    • Người kết hôn có tỉ lệ sở hữu nhà cao hơn (75% vs. 46%), thể hiện sự ổn định tài chính và nhu cầu mua sắm cho gia đình.

5.1.2 Thu nhập

  • Nhóm $30K–$50K chiếm đông nhất (32,7%), phản ánh tầng lớp trung lưu.
  • Nhóm thu nhập thấp ($10K–$30K) và trung bình–cao ($50K–$90K) cũng chiếm tỷ trọng lớn (~25% mỗi nhóm).
  • Nhóm > $150K chỉ ~2%, mẫu nhỏ nhưng có xu hướng tiêu dùng sản phẩm cao cấp, dịch vụ tiện lợi.

5.1.3 Phân bố địa lý

  • Quốc gia: 68% giao dịch từ Mỹ; còn lại từ Canada, Mexico.
  • Bang: WA, CA, OR chiếm phần lớn—tương ứng với các thành phố Salem, Tacoma, Los Angeles đứng đầu về số lượng giao dịch.
  • Thành phố: Salem (~10% giao dịch), Tacoma (~9%), Los Angeles (~6%).

5.1.4 Hành vi theo sản phẩm

  • ProductFamily:
    • Food (72,2%), Non-consumable (19%), Drink (9%).
  • ProductDepartment:
    • Produce (12,3%), Snack Foods (11,4%), Dairy (6,4%), Frozen Foods (9,8%).
  • ProductCategory:
    • Nhóm rau củ tươi và đồ ăn nhanh đứng đầu ở hầu hết các phân khúc thu nhập.
    • Nhóm thu nhập thấp–trung bình ưu tiên các mặt hàng thiết yếu, giá cả phải chăng; thu nhập cao mua nhiều snack, frozen và sản phẩm chăm sóc sức khỏe.

5.2 Hạn chế

  1. Thiếu biến định lượng: không phân tích sâu về tuổi, giá trị đơn hàng, tần suất mua.
  2. Mẫu không đồng đều: nhóm thu nhập rất cao và các thành phố nhỏ có ít quan sát, giảm tính đại diện.
  3. Tương quan chéo: chưa điều chỉnh mối liên hệ giữa thu nhập, nhà ở, địa lý.
  4. Giới tính & văn hóa: chưa khai thác khác biệt chi tiết giữa nam/nữ hoặc theo vùng miền.

5.3 Đề xuất chiến lược

  • Phân khúc & Marketing
    • Nhóm $30K–$70K: chú trọng combo rau củ tươi, sữa, thực phẩm đông lạnh; ưu đãi theo gói.
    • Nhóm đã kết hôn & có nhà: ưu đãi đồ gia dụng, gói giao hàng định kỳ.
  • Kênh phân phối
    • Mở rộng tại Salem, Tacoma, Los Angeles; tối ưu kệ hàng cho Produce, Snack Foods, Dairy.
    • Xem xét giảm diện tích với danh mục ít bán (ví dụ Canned Oysters, Candles).
  • Công nghệ & Cá nhân hóa
    • Dùng CRM thu thập thêm dữ liệu định lượng, phân tích hành vi theo thời gian thực; gợi ý sản phẩm tự động.

5.4 Hướng nghiên cứu tiếp theo

  1. So sánh “thu nhập cao + độc thân + có nhà” vs. “thu nhập cao + đã kết hôn” về hành vi mua sắm.
  2. Ảnh hưởng của tuổi kết hợp với hôn nhân và thu nhập đến lựa chọn sản phẩm.
  3. Sự khác biệt tiêu dùng tiện lợi (Frozen, Snack) giữa đô thị – nông thôn.
  4. Khách nào chi mạnh cho Non-consumable?
  5. Phân tích tỷ trọng chi tiêu chi tiết theo từng mức thu nhập và danh mục sản phẩm.

6 A: ĐỌC VÀ CHUẨN BỊ TRƯỚC BUỔI HỌC

6.1 Giới thiệu chung

Tuần này, chúng ta đi sâu vào suy diễn thống kê trên bảng ngẫu nhiên (Contingency Table), đặc biệt tập trung vào:

  • Kiểm định Chi-square về tính độc lập giữa hai biến phân loại.
  • Các chỉ số đo lường mối liên hệ trong bảng 2x2: Relative Risk (RR)Odds Ratio (OR).
  • Cách tính khoảng tin cậy cho Odds Ratio.
  • Ứng dụng các kiến thức trên vào một ví dụ thực tế từ bộ dữ liệu Supermarket Transactions.

Đọc dữ liệu và khám phá

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

Đầu tiên, ta sẽ sử dụng 2 biến định tính: Gender (Giới tính) và Homeowner (Có sở hữu nhà hay không) để tiến hành đưa ra ví dụ cũng như phân tích.

6.2 Bảng ngẫu nhiên

Bảng ngẫu nhiên (contingency table) là công cụ thống kê dùng để trình bày tần số của các biến phân loại. Trong trường hợp đơn giản nhất – bảng 2x2 – bảng có dạng:

Biến B = Yes Biến B = No
Biến A = Yes a b
Biến A = No c d

Trong phân tích thống kê, bảng 2x2 thường dùng để:

  • So sánh xác suất giữa hai nhóm (như Nam vs Nữ).
  • Tính toán các chỉ số đo lường mối liên hệ: Risk, Odds, Relative Risk (RR), Odds Ratio (OR).
  • Kiểm định giả thuyết về sự độc lập giữa hai biến (Chi-square test, Fisher’s Exact Test,…).

Bảng có thể sinh ra từ các phân phối như:

  • Multinomial: nếu tổng số quan sát cố định.
  • Poisson: nếu từng ô trong bảng là biến Poisson độc lập (áp dụng khi dữ liệu hiếm).

Các bước thực hiện trong R

table_gender_homeowner <- table(data$Gender, data$Homeowner)
table_gender_homeowner
##    
##        N    Y
##   F 2826 4344
##   M 2789 4100

6.3 Kiểm định Chi-square về tính độc lập

Lý thuyết: Kiểm định Chi-square

Dùng để kiểm tra xem hai biến phân loại có độc lập thống kê không.

  • Giả thuyết H₀: Hai biến độc lập.
  • Giả thuyết H₁: Hai biến có mối liên hệ.

Chỉ số kiểm định: \[ X^2 = \sum \frac{(O_{ij} - E_{ij})^2}{E_{ij}} \]

Trong đó:

  • \(O_{ij}\) là tần số quan sát
  • \(E_{ij}\) là tần số kỳ vọng.

Nếu p-value < 0.05, ta có đủ cơ sở để bác bỏ H₀ → Có bằng chứng về sự phụ thuộc giữa hai biến.

Các bước thực hiện trong R

chisq.test(table_gender_homeowner, correct = FALSE)
## 
##  Pearson's Chi-squared test
## 
## data:  table_gender_homeowner
## X-squared = 1.6788, df = 1, p-value = 0.1951

6.4 Tính Odds Ratio, Relative Risk

6.4.1 Tỷ số nguy cơ (Relative Risk - RR)

Khái niệm: Relative Risk (RR) là tỷ lệ giữa xác suất xảy ra sự kiện ở nhóm tiếp xúc so với nhóm không tiếp xúc.

Công thức:

\[ RR = \frac{\frac{a}{a+b}}{\frac{c}{c+d}} \]

Diễn giải:

  • RR = 1: Không có sự khác biệt về nguy cơ giữa hai nhóm.
  • RR > 1: Nguy cơ ở nhóm tiếp xúc cao hơn nhóm không tiếp xúc.
  • RR < 1: Nguy cơ ở nhóm tiếp xúc thấp hơn nhóm không tiếp xúc.

6.4.2 Tỷ số chênh (Odds Ratio - OR)

Khái niệm: Odds Ratio (OR) là tỷ lệ giữa odds xảy ra sự kiện ở nhóm tiếp xúc so với nhóm không tiếp xúc.

Công thức:

\[ OR = \frac{\frac{a}{b}}{\frac{c}{d}} = \frac{a \times d}{b \times c} \]

Diễn giải:

  • OR = 1: Không có sự khác biệt về odds giữa hai nhóm.
  • OR > 1: Odds xảy ra sự kiện ở nhóm tiếp xúc cao hơn nhóm không tiếp xúc.
  • OR < 1: Odds xảy ra sự kiện ở nhóm tiếp xúc thấp hơn nhóm không tiếp xúc.

Các bước thực hiện trên R

# Lấy số liệu
a <- table_gender_homeowner["F", "Y"]
b <- table_gender_homeowner["F", "N"]
c <- table_gender_homeowner["M", "Y"]
d <- table_gender_homeowner["M", "N"]

# Tính Odds
odds_female <- a / b
odds_male <- c / d

# Odds Ratio (OR)
or <- odds_female / odds_male

# Relative Risk (RR)
risk_female <- a / (a + b)
risk_male <- c / (c + d)
rr <- risk_female / risk_male

list(
  odds_female = odds_female,
  odds_male = odds_male,
  OR = or,
  RR = rr
)
## $odds_female
## [1] 1.537155
## 
## $odds_male
## [1] 1.470061
## 
## $OR
## [1] 1.04564
## 
## $RR
## [1] 1.017989

Khoảng tin cậy 95% cho Odds Ratio

Do OR không phân phối chuẩn, nên lấy log(OR) để xây dựng khoảng tin cậy:

\[ CI_{log(OR)} = \log(OR) \pm Z \cdot SE_{log(OR)} \]

Với: \[ SE = \sqrt{\frac{1}{a} + \frac{1}{b} + \frac{1}{c} + \frac{1}{d}} \]

Chuyển về thang OR bằng hàm mũ: \(e^{CI}\).

Các bước thực hiện trên R

se_log_or <- sqrt(1/a + 1/b + 1/c + 1/d)
z <- 1.96  # hệ số cho 95%
ci_lower <- exp(log(or) - z * se_log_or)
ci_upper <- exp(log(or) + z * se_log_or)
c(ci_lower, ci_upper)
## [1] 0.9773755 1.1186731

Nhận xét:

  • Nếu OR < 1, odds của việc sở hữu nhà ở nhóm Female nhỏ hơn Male.
  • Nếu RR < 1, phụ nữ có nguy cơ sở hữu nhà thấp hơn nam giới.

Kết luận cần đi kèm với kiểm định Chi-square và khoảng tin cậy, không nên chỉ nhìn vào OR/RR.

Đây là một ví dụ điển hình cho việc sử dụng Odds Ratio trong kinh tế/xã hội học để mô tả mối liên hệ giữa hai đặc điểm phân loại.

6.5 Thực hành trên bộ dữ liệu

Tạo bảng tần số

# Bảng tần số chéo giữa MaritalStatus và Homeowner
tbl <- table(data$MaritalStatus, data$Homeowner)
tbl
##    
##        N    Y
##   M 1719 5147
##   S 3896 3297

Nhận xét

  • Khách hàng đã kết hôn (M): Có tới 5147 người sở hữu nhà ở, chiếm phần lớn trong nhóm này, trong khi chỉ có 1719 người không sở hữu nhà.

  • Khách hàng độc thân (S): Ngược lại, nhóm này có xu hướng không sở hữu nhà ở cao hơn với 3896 người, trong khi số người sở hữu nhà chỉ là 3297 người.

Kiểm định Chi-square

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

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

  • Giá trị thống kê Chi-bình phương: X-squared = 1241.2

  • Bậc tự do: df = 1

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

Kết luận:

  • Vì giá trị p rất nhỏ (p < 0.05), ta bác bỏ giả thuyết không H0. Điều này cho thấy có mối liên hệ có ý nghĩa thống kê giữa tình trạng hôn nhân và tình trạng sở hữu nhà.

Tính Odds Ratio và Relative Risk

# Lọc dữ liệu: chỉ lấy Married và Single
data2 <- subset(data, MaritalStatus %in% c("M", "S"))

# Tạo bảng 2x2
tbl2 <- table(data2$MaritalStatus, data2$Homeowner)
tbl2
##    
##        N    Y
##   M 1719 5147
##   S 3896 3297
# Tính toán Odds Ratio và Relative Risk
library(epiR)
## Loading required package: survival
## Package epiR 2.0.84 is loaded
## Type help(epi.about) for summary information
## Type browseVignettes(package = 'epiR') to learn how to use epiR for applied epidemiological analyses
## 
epi_result <- epi.2by2(tbl2, method = "cohort.count", conf.level = 0.95)
epi_result
##              Outcome+    Outcome-      Total                 Inc risk *
## Exposure+        1719        5147       6866     25.04 (24.02 to 26.08)
## Exposure-        3896        3297       7193     54.16 (53.00 to 55.32)
## Total            5615        8444      14059     39.94 (39.13 to 40.75)
## 
## Point estimates and 95% CIs:
## -------------------------------------------------------------------
## Inc risk ratio                                 0.46 (0.44, 0.48)
## Inc odds ratio                                 0.28 (0.26, 0.30)
## Attrib risk in the exposed *                   -29.13 (-30.67, -27.59)
## Attrib fraction in the exposed (%)            -116.34 (-126.59, -106.62)
## Attrib risk in the population *                -14.22 (-15.63, -12.82)
## Attrib fraction in the population (%)         -35.62 (-35.74, -35.46)
## -------------------------------------------------------------------
## Uncorrected chi2 test that OR = 1: chi2(1) = 1242.432 Pr>chi2 = <0.001
## Fisher exact test that OR = 1: Pr>chi2 = <0.001
##  Wald confidence limits
##  CI: confidence interval
##  * Outcomes per 100 population units

6.6 Kết quả phân tích

Bảng chéo tần suất giữa MaritalStatus và Homeowner

Marital Status Không sở hữu nhà (N) Có sở hữu nhà (Y) Tổng cộng
Married (M) 1,719 5,147 6,866
Single (S) 3,896 3,297 7,193
Tổng cộng 5,615 8,444 14,059

Tỷ lệ hiện mắc (Incidence Risk)

  • Nhóm Married: 25.04% (CI: 24.02 – 26.08)
  • Nhóm Single: 54.16% (CI: 53.00 – 55.32)

Những người độc thân có xác suất không sở hữu nhà cao hơn gấp đôi so với người đã kết hôn.


Relative Risk (RR)

  • RR = 0.46 (95% CI: 0.44 – 0.48)

Nguy cơ không sở hữu nhà ở nhóm đã kết hôn chỉ bằng 46% so với nhóm độc thân.


Odds Ratio (OR)

  • OR = 0.28 (95% CI: 0.26 – 0.30)

Xác suất không sở hữu nhà ở nhóm đã kết hôn thấp hơn 72% so với nhóm độc thân.


Risk Difference và Attribution

  • Chênh lệch nguy cơ tuyệt đối (risk difference): -29.13 điểm phần trăm
  • Tỷ lệ quy trách trong nhóm phơi nhiễm (exposed): -116.34%
  • Tỷ lệ quy trách toàn dân (population): -35.62%

Điều này cho thấy rằng việc kết hôn có thể giúp giảm đáng kể rủi ro không sở hữu nhà ở cấp độ cá nhân lẫn dân số.


Kiểm định ý nghĩa thống kê

  • Chi-squared test: χ²(1) = 1242.43, p < 0.001
  • Fisher’s exact test: p < 0.001

Kết quả kiểm định cho thấy mối liên hệ giữa tình trạng hôn nhân và việc sở hữu nhà là rất có ý nghĩa thống kê (p < 0.001).


Kết luận:

  • Có mối liên hệ rất rõ ràng và có ý nghĩa 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 có tỷ lệ và xác suất không sở hữu nhà thấp hơn đáng kể so với người độc thân.
  • Đây là một phát hiện quan trọng có thể được sử dụng trong các nghiên cứu xã hội học hoặc chính sách nhà ở.

7 B: HOẠT ĐỘNG TRÊN LỚP

Trong hoạt động này, chúng ta sẽ sử dụng dữ liệu Supermarket Transactions để phân tích mối liên hệ giữa các biến nhị phân. Mục tiêu là:

  • Tạo bảng 2x2
  • Tính và diễn giải Hiệu hai tỷ lệ (Difference in Proportions)
  • Tính Relative Risk (RR) và Odds Ratio (OR)
  • Tính khoảng tin cậy 95% cho OR
  • Thực hiện phân tích phân tầng (stratified analysis)

7.1 Đọc và làm quen với dữ liệu

Bộ dữ liệu “Supermarket Transactions” phản ánh các giao dịch mua hàng của khách hàng tại một siêu thị trong một khoảng thời gian cụ thể. Mỗi dòng dữ liệu tương ứng với một giao dịch, bao gồm thông tin nhân khẩu học (giới tính, loại thành viên, chi nhánh), đặc điểm sản phẩm (loại sản phẩm, kênh thanh toán), và các yếu tố hành vi tiêu dùng (thời gian mua sắm, mức độ hài lòng, giá trị đơn hàng,…). Tập dữ liệu gồm 14.059 quan sát và 16 biến, cung cấp nền tảng chi tiết để phân tích hành vi khách hàng và hiệu quả kinh doanh của siêu thị.

# Đọc file
library("csv")
data <- read.csv("C:/Users/ASUS/Downloads/Supermarket Transactions.csv", header = T)

# Hiển thị cấu trúc dữ liệu
str(data)
## 'data.frame':    14059 obs. of  16 variables:
##  $ X                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ PurchaseDate     : chr  "2007-12-18" "2007-12-20" "2007-12-21" "2007-12-21" ...
##  $ CustomerID       : int  7223 7841 8374 9619 1900 6696 9673 354 1293 7938 ...
##  $ Gender           : chr  "F" "M" "F" "M" ...
##  $ MaritalStatus    : chr  "S" "M" "M" "M" ...
##  $ Homeowner        : chr  "Y" "Y" "N" "Y" ...
##  $ Children         : int  2 5 2 3 3 3 2 2 3 1 ...
##  $ AnnualIncome     : chr  "$30K - $50K" "$70K - $90K" "$50K - $70K" "$30K - $50K" ...
##  $ City             : chr  "Los Angeles" "Los Angeles" "Bremerton" "Portland" ...
##  $ StateorProvince  : chr  "CA" "CA" "WA" "OR" ...
##  $ Country          : chr  "USA" "USA" "USA" "USA" ...
##  $ ProductFamily    : chr  "Food" "Food" "Food" "Food" ...
##  $ ProductDepartment: chr  "Snack Foods" "Produce" "Snack Foods" "Snacks" ...
##  $ ProductCategory  : chr  "Snack Foods" "Vegetables" "Snack Foods" "Candy" ...
##  $ UnitsSold        : int  5 5 3 4 4 3 4 6 1 2 ...
##  $ Revenue          : num  27.38 14.9 5.52 4.44 14 ...
# Hiển thị vài dòng đầu và cuối
head(data)
##   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(data)
##           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
# Chuyển các biến định tính phù hợp sang factor
factor <- c("Gender", "MaritalStatus", "Homeowner", "AnnualIncome",
                    "City", "StateorProvince", "Country",
                    "ProductFamily", "ProductDepartment", "ProductCategory")

# Kiểm tra biến nào tồn tại trong data
factor <- intersect(factor, names(data))

# Chuyển sang factor
data[factor] <- lapply(data[factor], as.factor)

# Kiểm tra lại cấu trúc
str(data)
## 'data.frame':    14059 obs. of  16 variables:
##  $ X                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ PurchaseDate     : chr  "2007-12-18" "2007-12-20" "2007-12-21" "2007-12-21" ...
##  $ CustomerID       : int  7223 7841 8374 9619 1900 6696 9673 354 1293 7938 ...
##  $ Gender           : Factor w/ 2 levels "F","M": 1 2 1 2 1 1 2 1 2 2 ...
##  $ MaritalStatus    : Factor w/ 2 levels "M","S": 2 1 1 1 2 1 2 1 1 2 ...
##  $ Homeowner        : Factor w/ 2 levels "N","Y": 2 2 1 2 2 2 2 2 2 1 ...
##  $ Children         : int  2 5 2 3 3 3 2 2 3 1 ...
##  $ AnnualIncome     : Factor w/ 8 levels "$10K - $30K",..: 5 7 6 5 3 1 5 4 1 6 ...
##  $ City             : Factor w/ 23 levels "Acapulco","Bellingham",..: 8 8 4 12 3 3 13 23 2 15 ...
##  $ StateorProvince  : Factor w/ 10 levels "BC","CA","DF",..: 2 2 8 6 2 2 6 8 8 2 ...
##  $ Country          : Factor w/ 3 levels "Canada","Mexico",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ ProductFamily    : Factor w/ 3 levels "Drink","Food",..: 2 2 2 2 1 2 2 2 3 3 ...
##  $ ProductDepartment: Factor w/ 22 levels "Alcoholic Beverages",..: 20 18 20 21 4 11 13 6 15 14 ...
##  $ ProductCategory  : Factor w/ 45 levels "Baking Goods",..: 42 45 42 7 15 41 5 13 16 35 ...
##  $ UnitsSold        : int  5 5 3 4 4 3 4 6 1 2 ...
##  $ Revenue          : num  27.38 14.9 5.52 4.44 14 ...

Giải thích các biến

Bộ dữ liệu ghi lại thông tin về các giao dịch mua hàng của khách hàng, bao gồm thông tin nhân khẩu học, thông tin sản phẩm, số lượng bán ra và doanh thu. Dữ liệu bao gồm 14059 quan sát và 16 biến. Dưới đây là mô tả chi tiết các biến có trong bộ dữ liệu:

Tên Biến Ý Nghĩa
PurchaseDate Ngày giao dịch mua hàng diễn ra (định dạng ngày/tháng/năm).
CustomerID Mã định danh duy nhất cho mỗi khách hàng.
Gender Giới tính của khách hàng: M (Nam), F (Nữ).
MaritalStatus Tình trạng hôn nhân: S (Độc thân), M (Đã kết hôn).
Homeowner Tình trạng sở hữu nhà: Y (Có), N (Không).
Children Số lượng con cái của khách hàng.
AnnualIncome Mức thu nhập hàng năm theo khoảng (Ví dụ: $30K - $50K).
City Thành phố nơi khách hàng thực hiện giao dịch.
StateorProvince Bang hoặc tỉnh (ví dụ: CA cho California, OR cho Oregon).
Country Quốc gia.
ProductFamily Nhóm sản phẩm chính: Food (Thực phẩm), Drink (Đồ uống), Non-Consumable (Không tiêu dùng).
ProductDepartment Bộ phận sản phẩm như Snack Foods, Frozen Foods, v.v.
ProductCategory Danh mục sản phẩm cụ thể hơn, ví dụ: Candy, Beer and Wine.
UnitsSold Số lượng đơn vị sản phẩm đã bán trong giao dịch đó.
Revenue Doanh thu từ giao dịch (tính theo USD).

7.2 Phân tích mối liên hệ giữa Gender và Homeowner

7.2.1 Tạo bảng tần số chéo

table_gender_home <- table(data$Gender, data$Homeowner)
table_gender_home
##    
##        N    Y
##   F 2826 4344
##   M 2789 4100

Dựa vào bảng trên:

  • Nữ (F) có tổng cộng 7170 người, trong đó 4344 người sở hữu nhà, chiếm khoảng 60.6%.

  • Nam (M) có tổng cộng 6889 người, với 4100 người sở hữu nhà, tương ứng khoảng 59.5%.

Nhận xét:

Tỷ lệ sở hữu nhà của nữ có vẻ nhỉnh hơn một chút so với nam (khoảng 60.6% so với 59.5%), tuy nhiên sự khác biệt này là khá nhỏ.
Để đánh giá rõ ràng hơn về mức độ liên hệ giữa hai biến, ta sẽ tiếp tục tính các chỉ số định lượng như:
Hiệu hai tỷ lệ (Difference in Proportions), Relative Risk (RR), Odds Ratio (OR).


7.2.2 Tính Hiệu Hai Tỷ Lệ

prop_table <- prop.table(table_gender_home, margin = 1)
prop_table
##    
##             N         Y
##   F 0.3941423 0.6058577
##   M 0.4048483 0.5951517
diff_prop <- prop_table[1, "Y"] - prop_table[2, "N"]
diff_prop
## [1] 0.2010094

Tỷ lệ sở hữu nhà:

  • nữ là 0.6059 (tức là 60.6%)

  • nam là 0.5952 (tức là 59.5%)

Hiệu hai tỷ lệ giữa nữ và nam là 0.201, tương đương 20.1 điểm phần trăm.

Kết luận:

Tỷ lệ nữ sở hữu nhà cao hơn nam khoảng 1.00%, tuy nhiên mức chênh lệch này khá nhỏ và chưa thể kết luận có ý nghĩa thống kê nếu chưa tính khoảng tin cậy (confidence interval) hoặc thực hiện các kiểm định thống kê chính thức như kiểm định z hoặc chi bình phương.


7.2.3 Tính Relative Risk (RR)

library(epitools)
## 
## Attaching package: 'epitools'
## The following object is masked from 'package:survival':
## 
##     ratetable
rr_result <- riskratio(table_gender_home)
rr_result$measure
##    risk ratio with 95% C.I.
##      estimate     lower    upper
##   F 1.0000000        NA       NA
##   M 0.9823291 0.9561812 1.009192

Dựa vào kết quả ta thấy Relative Risk (RR) của nam so với nữ là 0.9823. Khoảng tin cậy 95% của RR nằm trong khoảng từ 0.9562 đến 1.0092.

Kết luận:
RR < 1 cho thấy nam có tỷ lệ sở hữu nhà thấp hơn nữ một chút (chỉ còn khoảng 98.23% so với nữ). Tuy nhiên, vì khoảng tin cậy 95% bao gồm giá trị 1.0, nên không có bằng chứng đủ mạnh để kết luận sự khác biệt này có ý nghĩa thống kê. Nói cách khác, tỷ lệ sở hữu nhà giữa nam và nữ có thể coi là tương đương.


7.2.4 Tính Odds Ratio (OR) và Khoảng Tin Cậy

library(epitools)
or_result <- oddsratio(table_gender_home)
or_result
## $data
##        
##            N    Y Total
##   F     2826 4344  7170
##   M     2789 4100  6889
##   Total 5615 8444 14059
## 
## $measure
##    odds ratio with 95% C.I.
##     estimate     lower    upper
##   F 1.000000        NA       NA
##   M 0.956381 0.8938974 1.023169
## 
## $p.value
##    two-sided
##     midp.exact fisher.exact chi.square
##   F         NA           NA         NA
##   M   0.195158    0.1964833  0.1950884
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
or_result$conf.int
## NULL

Phân tích bảng thì giữa hai nhóm giới tính (F và M) cho thấy:

  • Tỷ số odds (odds ratio) giữa nhóm nam (M) so với nữ (F) là 0.96, với khoảng tin cậy 95% là [0.89; 1.02].
  • Giá trị p từ các phép kiểm định hai phía:
    • Mid-p exact: p = 0.195
    • Fisher’s exact: p = 0.196
    • Chi-square: p = 0.195

Do tất cả các giá trị p đều lớn hơn mức ý nghĩa thông thường (α = 0.05), không có sự khác biệt có ý nghĩa thống kê giữa nhóm nam và nữ về biến được phân tích.

Như vậy, kết quả cho thấy không có mối liên quan rõ rệt giữa giới tính và biến, theo phân tích odds ratio và các kiểm định xác suất tương ứng.

LS0tDQp0aXRsZTogTkhJ4buGTSBW4bukIFRV4bqmTiAzDQphdXRob3I6ICJMw6JtIFRo4bqjbyBNeSINCmRhdGU6ICIyMDI1LTA2LTE1Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgdG9jX2RlcHRoOiAyDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jOiB0cnVlDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgIHRvYzogdHJ1ZQ0KICAgICB0b2NfZGVwdGg6ICcyJw0KICBwZGZfZG9jdW1lbnQ6DQogICAgbGF0ZXhfZW5naW5lOiB4ZWxhdGV4DQplZGl0b3Jfb3B0aW9uczogDQogIG1hcmtkb3duOiANCiAgICB3cmFwOiA3Mg0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCmBgYHtjc3MsZWNobyA9IEZBTFNFfQ0KaDEgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgZm9udC1zaXplOiAzMnB4Ow0KICBmb250LXdlaWdodDogYm9sZA0KICB9DQoNCmgyIHsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGZvbnQtc2l6ZTogMjhweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogDQp9DQoNCmgzIHsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc3R5bGU6IGl0YWxpYzsNCn0NCg0KaDQge2ZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtc3R5bGU6IGl0YWxpY30NCg0KYm9keSB7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBmb250LXNpemU6IDE4cHg7DQogIA0KfQ0KcDpub3QoaDEpOm5vdChoMik6bm90KGgzKTpub3QoaDQpOm5vdChoNSkgew0KICB0ZXh0LWluZGVudDogMmVtO30NCnAgew0KICB0ZXh0LWFsaWduOiBqdXN0aWZ5Ow0KICB9DQoudG9jaWZ5LWhlYWRlciB7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoc2tpbXIpDQpsaWJyYXJ5KHBzeWNoKQ0KbGlicmFyeShjc3YpDQpgYGANCg0KIyAqKlBo4bqnbiAxLiBUw4xNIEhJ4buCVSBWw4AgQ0hV4bqoTiBC4buKIEThu64gTEnhu4ZVKioNCg0KIyMgKirEkOG7jWMgZmlsZSBk4buvIGxp4buHdSoqDQoNCmBgYHtyfQ0KZCA8LSByZWFkLmNzdigiQzovVXNlcnMvQVNVUy9Eb3dubG9hZHMvU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zLmNzdiIsIGhlYWRlciA9IFQpDQpgYGANCg0KIyMgKipEYW5oIHPDoWNoIGPDoWMgYmnhur9uKioNCg0KYGBge3J9DQpuYW1lcyhkKQ0KYGBgDQoNCnwgVMOqbiBiaeG6v24gfCDDnSBuZ2jEqWEgfA0KfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8ICoqWCoqIHwgTmfDoHkgbXVhIGjDoG5nICjEkeG7i25oIGThuqFuZyBgWVlZWS1NTS1ERGApLiB8DQp8ICoqQ3VzdG9tZXJJRCoqIHwgTcOjIMSR4buLbmggZGFuaCBkdXkgbmjhuqV0IGNobyBt4buXaSBraMOhY2ggaMOgbmcuIHwNCnwgKipHZW5kZXIqKiB8IEdp4bubaSB0w61uaCBj4bunYSBraMOhY2ggaMOgbmcgKGBNYCA9IE1hbGUsIGBGYCA9IEZlbWFsZSkuIHwNCnwgKipNYXJpdGFsU3RhdHVzKiogfCBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gKGBTYCA9IFNpbmdsZSwgYE1gID0gTWFycmllZCkuIHwNCnwgKipIb21lb3duZXIqKiB8IEtow6FjaCBow6BuZyBjw7Mgc+G7nyBo4buvdSBuaMOgIGhheSBraMO0bmcgKGBZYCA9IFllcywgYE5gID0gTm8pLiB8DQp8ICoqQ2hpbGRyZW4qKiB8IFPhu5EgbMaw4bujbmcgY29uIG5o4buPIHRyb25nIGdpYSDEkcOsbmggKHPhu5Egbmd1ecOqbikuIHwNCnwgKipBbm51YWxJbmNvbWUqKiB8IEtob+G6o25nIHRodSBuaOG6rXAgaMOgbmcgbsSDbSAodsOtIGThu6UgYDwkMjVLYCwgYCQyNUvigJMkNTBLYCwg4oCmKS4gfA0KfCAqKkNpdHkqKiB8IFRow6BuaCBwaOG7kSBzaW5oIHPhu5FuZy4gfA0KfCAqKlN0YXRlb3JQcm92aW5jZSoqIHwgQmFuZyBob+G6t2MgdOG7iW5oIHTGsMahbmcg4bupbmcgduG7m2kgdGjDoG5oIHBo4buRLiB8DQp8ICoqQ291bnRyeSoqIHwgUXXhu5FjIGdpYSBuxqFpIGdpYW8gZOG7i2NoIGRp4buFbiByYS4gfA0KfCAqKlByb2R1Y3RGYW1pbHkqKiB8IE5ow7NtIHPhuqNuIHBo4bqpbSBj4bqlcCBjYW8gKHbDrSBk4bulIEZvb2QsIERyaW5rLCDigKYpLiB8DQp8ICoqUHJvZHVjdERlcGFydG1lbnQqKiB8IELhu5kgcGjhuq1uIHPhuqNuIHBo4bqpbSB0cm9uZyBuaMOzbSAodsOtIGThu6UgQmV2ZXJhZ2VzLCBTbmFjayBGb29kcywg4oCmKS4gfA0KfCAqKlByb2R1Y3RDYXRlZ29yeSoqIHwgSOG6oW5nIG3hu6VjIHPhuqNuIHBo4bqpbSBj4bulIHRo4buDICh2w60gZOG7pSBDYXJib25hdGVkIEJldmVyYWdlcywgQ2FuZHksIOKApikuIHwNCnwgKipVbml0c1NvbGQqKiB8IFPhu5EgbMaw4bujbmcgxJHGoW4gduG7iyBiw6FuIHJhIHRyb25nIG3hu5dpIGdpYW8gZOG7i2NoLiB8DQp8ICoqUmV2ZW51ZSoqIHwgRG9hbmggdGh1IHRodSB24buBIHThu6sgZ2lhbyBk4buLY2ggKMSRxqFuIHbhu4sgdGnhu4FuIHThu4csIHbDrSBk4bulIFVTRCkuIHwNCg0KIyMgKipT4buRIGJp4bq/biB2w6Agc+G7kSBxdWFuIHPDoXQqKg0KDQpgYGB7cn0NCmRpbShkKQ0KYGBgDQoNCiMjICoqS2nhu4NtIHRyYSBj4bqldSB0csO6YyB04buVbmcgcXXDoXQqKg0KDQpgYGB7cn0NCnN0cihkKQ0KYGBgDQoNCiMjICoqQ2jhu41uIGPDoWMgYmnhur9uIMSR4buLbmggdMOtbmgqKg0KDQpgYGB7cn0NCmRsZHQgPC0gYygiR2VuZGVyIiwgIk1hcml0YWxTdGF0dXMiLCAiSG9tZW93bmVyIiwiQ2l0eSIsICJTdGF0ZW9yUHJvdmluY2UiLCAiQ291bnRyeSIsICJQcm9kdWN0RmFtaWx5IiwgIlByb2R1Y3REZXBhcnRtZW50IiwgIlByb2R1Y3RDYXRlZ29yeSIsIkFubnVhbEluY29tZSIpDQpkbGR0DQpgYGANCg0KIyMgKipU4bqhbyBi4buZIGThu68gbGnhu4d1IG3hu5tpIGNo4buJIGNo4bupYSBjw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oKioNCg0KYGBge3IsIGVjaG89VFJVRX0NCmR0IDwtIGRbLCBkbGR0XQ0KYGBgDQoNCiMjICoqQ+G6pXUgdHLDumMgYuG7mSBk4buvIGxp4buHdSoqDQoNCmBgYHtyfQ0Kc3RyKGR0KQ0KYGBgDQoNCiMjICoqTeG7mXQgdsOgaSBkw7JuZyDEkeG6p3UgdsOgIGTDsm5nIGN14buRaSoqDQoNCmBgYHtyfQ0KaGVhZChkdCkNCmBgYA0KDQpgYGB7cn0NCnRhaWwoZHQpDQpgYGANCg0KIyMgKipLaeG7g20gdHJhIE5BKioNCg0KYGBge3J9DQphbnkoaXMubmEoZHQpKQ0KYGBgDQoNClbhuq15IGLhu5kgZOG7ryBsaeG7h3Uga2jDtG5nIGPDsyBnacOhIHRy4buLIHRoaeG6v3UNCg0KIyMgKipLaeG7g20gdHJhIGtp4buDdSBk4buvIGxp4buHdSB2w6AgxJHhu5VpIHbhu4EgZmFjdG9yKioNCg0KYGBge3J9DQpkdCA8LSBkYXRhLmZyYW1lKGxhcHBseShkdCwgYXMuZmFjdG9yKSkNCmBgYA0KDQpgYGB7cn0NCiMgS2nhu4NtIHRyYSBraeG7g3UgZOG7ryBsaeG7h3UgY+G7p2EgdOG7q25nIGJp4bq/biB0cm9uZyBkbGR0DQpzYXBwbHkoZHQsIGNsYXNzKQ0KYGBgDQoNCiMgKipQaOG6p24gMi4gUEjDgk4gVMONQ0ggTcOUIFThuqIgTeG7mFQgQknhur5OIMSQ4buKTkggVMONTkgqKg0KDQojIyAqKkJp4bq/biBHZW5kZXIqKg0KDQoqKkLhuqNuZyB04bqnbiBz4buRKioNCg0KYGBge3J9DQojTOG6rXAgYuG6o25nIHThuqduIHPhu5EgYmnhur9uIEdlbmRlcg0KdGFuc29fZ2VuZGVyIDwtIHRhYmxlKGR0JEdlbmRlcikNCnRhbnNvX2dlbmRlcg0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQojIFbhur0gYmnhu4N1IMSR4buTIGPhu5l0IGNobyBi4bqjbmcgdOG6p24gc+G7kSBHZW5kZXINCmJhcnBsb3QoDQogIHRhbnNvX2dlbmRlciwNCiAgbWFpbiAgID0gIlThuqduIHPhu5EgdGhlbyBnaeG7m2kgdMOtbmgiLA0KICB4bGFiICAgPSAiR2nhu5tpIHTDrW5oIiwNCiAgeWxhYiAgID0gIlPhu5EgcXVhbiBzw6F0IiwNCiAgbGFzICAgID0gMSwgICAgICAgICAgICAgICAgICAgICAgDQogIGNvbCAgICA9IGMoImJsdWUiLCAidG9tYXRvIiksICANCiAgYm9yZGVyID0gIndoaXRlIikNCmBgYA0KDQoqKkLhuqNuZyB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCiNM4bqtcCBi4bqjbmcgdOG6p24gc3XhuqV0IGPhu6dhIGJp4bq/biBHZW5kZXINCnRhbnN1YXRfZ2VuZGVyIDwtIHRhbnNvX2dlbmRlci9zdW0obnJvdyhkdCkpDQp0YW5zdWF0X2dlbmRlcg0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQojIE3DoHUgY2hvIHThu6tuZyBsw6F0DQpjb2xzIDwtIGMoInBpbmsiLCAiZ3JlZW4iKQ0KDQojIE5ow6NuIHBo4bqnbiB0csSDbSANCm5oYW5nZW5kZXIgPC0gcGFzdGUwKHJvdW5kKHRhbnN1YXRfZ2VuZGVyICogMTAwLCAxKSwgIiUiKQ0KDQojIFbhur0gcGllIGNoYXJ0IGtow7RuZyBuaMOjbg0KcGllKA0KICB0YW5zdWF0X2dlbmRlciwNCiAgbGFiZWxzID0gTkEsICAgICAgICAgICAgICAgIyDhuqluIG5ow6NuIG5nYXkgdHLDqm4gbMOhdA0KICBtYWluICAgPSAiVOG6p24gc3XhuqV0IHRoZW8gZ2nhu5tpIHTDrW5oIiwNCiAgY29sICAgID0gY29scywNCiAgYm9yZGVyID0gIndoaXRlIg0KKQ0KDQojIFRow6ptIGxlZ2VuZCBiw6puIG5nb8OgaSBnw7NjIHBo4bqjaQ0KbGVnZW5kKA0KICB4ICAgICAgPSAidG9wcmlnaHQiLA0KICBsZWdlbmQgPSBwYXN0ZShuYW1lcyh0YW5zdWF0X2dlbmRlciksIG5oYW5nZW5kZXIpLA0KICBmaWxsICAgPSBjb2xzLA0KKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KYGBge3J9DQpjb3VudHMgPC0gdGFibGUoZHQkR2VuZGVyKQ0KZGlmZl9jb3VudCA8LSBhYnMoY291bnRzWyJGIl0gLSBjb3VudHNbIk0iXSkNCmBgYA0KDQotICAgVuG6rXkgdHJvbmcgYuG7mSBk4buvIGxp4buHdSBuw6B5IGPDsw0KICAgIGByIHRhYmxlKGR0JEdlbmRlcilbMV0vc3VtKG5yb3coZHQpKSoxMDBgICUgbuG7ryB2w6ANCiAgICBgciB0YWJsZShkdCRHZW5kZXIpWzJdL3N1bShucm93KGR0KSkqMTAwYCUgbmFtLg0KDQotICAgVHJvbmcgYuG7mSBk4buvIGxp4buHdSwgc+G7kSBsxrDhu6NuZyBu4buvIGzDoCBgciBjb3VudHNbIkYiXWAsIHPhu5EgbMaw4bujbmcgbmFtIGzDoA0KICAgIGByIGNvdW50c1siTSJdYC4gU+G7sSBjaMOqbmggbOG7h2NoIHbhu4Egc+G7kSBsxrDhu6NuZyBnaeG7r2EgbuG7ryB2w6AgbmFtIGzDoA0KICAgIGByIGRpZmZfY291bnRgLg0KDQojIyAqKkJp4bq/biBIb21lb3duZXIqKg0KDQoqKkLhuqNuZyB04bqnbiBz4buRKioNCg0KYGBge3J9DQojTOG6rXAgYuG6o25nIHThuqduIHPhu5EgYmnhur9uIEhvbWVvd25lcg0KdGFuc29faG9tZW93bmVyIDwtIHRhYmxlKGR0JEhvbWVvd25lcikNCnRhbnNvX2hvbWVvd25lcg0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQpiYXJwbG90KA0KICB0YW5zb19ob21lb3duZXIsDQogIG1haW4gPSAidOG6p24gc+G7kSBiaeG6v24ga2jDoWNoIGjDoG5nIGPDsyBz4bufIGjhu611IG5ow6AiLA0KICB4bGFiID0gInPhu6EgaOG7r3UgbmjDoCIsDQogIHlsYWIgPSAic+G7kSBsxrDhu6NuZyIsDQogIGxhcyAgPSAxLA0KICBjb2wgID0gYygib3JhbmdlIiwicHVycGxlIiksDQogIGJvcmRlciA9ICJ3aGl0ZSINCikNCmBgYA0KDQoqKkLhuqNuZyB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCiNM4bqtcCBi4bqjbmcgdOG6p24gc3XhuqV0IGPhu6dhIGJp4bq/biBIb21lb3duZXINCnRhbnN1YXRfaG9tZW93bmVyIDwtIHRhbnNvX2hvbWVvd25lci9zdW0obnJvdyhkdCkpDQp0YW5zdWF0X2hvbWVvd25lcg0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQojIG3DoHUgY2hvIHThu6tuZyBsw6F0DQpjb2xzIDwtIGMoImxpZ2h0Ymx1ZSIsImxpZ2h0cGluayIpDQojIG5ow6NuIHBo4bqnbiB0csSDbSANCm5oYW5ob21lb3duZXIgPC0gcGFzdGUwKHJvdW5kKHRhbnN1YXRfaG9tZW93bmVyKjEwMCwxKSwiJSIpDQojIHbhur0gcGllIGNoYXJ0IGtow7RuZyBuaMOjbg0KcGllKA0KICB0YW5zdWF0X2hvbWVvd25lciwNCiAgbGFiZWxzID0gTkEsDQogIG1haW4gICA9ICJ04bqnbiBz4buRIGJp4bq/biBraMOhY2ggaMOgbmcgY8OzIHPhu58gaOG7rXUgbmjDoCIsDQogIGNvbCAgICA9IGNvbHMsDQogIGJvcmRlciA9ICJ3aGl0ZSIpDQojIHRow6ptIGxlZ2VuZCBiw6puIG5nb8OgaSBnw7NjIHBo4bqjaQ0KbGVnZW5kKA0KICB4ICAgICAgPSAidG9wcmlnaHQiLA0KICBsZWdlbmQgPSBwYXN0ZShuYW1lcyh0YW5zdWF0X2hvbWVvd25lciksbmhhbmhvbWVvd25lciksDQogIGZpbGwgICA9IGNvbHMNCikNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNCmBgYHtyfQ0KY291bnRzX2hvbWVvd25lciA8LSB0YWJsZShkdCRIb21lb3duZXIpDQpkaWZmX2hvbWVvd25lciA8LSBhYnMoY291bnRzX2hvbWVvd25lclsiWSJdIC0gY291bnRzX2hvbWVvd25lclsiTiJdKQ0KYGBgDQoNCi0gICBW4bqteSB0cm9uZyBi4buZIGThu68gbGnhu4d1IG7DoHkgY8OzDQogICAgYHIgdGFibGUoZHQkSG9tZW93bmVyKVsxXS9zdW0obnJvdyhkdCkpKjEwMGAgJSBraMO0bmcgY8OzIG5ow6AgdsOgDQogICAgYHIgdGFibGUoZHQkSG9tZW93bmVyKVsyXS9zdW0obnJvdyhkdCkpKjEwMGAlIGPDsyBuaMOgLg0KDQotICAgU+G7kSBsxrDhu6NuZyBuZ8aw4budaSBz4bufIGjhu691IG5ow6AgbMOgIGByIGNvdW50c19ob21lb3duZXJbIlkiXWAsIHPhu5EgbMaw4bujbmcNCiAgICBuZ8aw4budaSBraMO0bmcgc+G7nyBo4buvdSBsw6AgYHIgY291bnRzX2hvbWVvd25lclsiTiJdYC4NCg0KLSAgIFPhu7EgY2jDqm5oIGzhu4djaCB24buBIHPhu5EgbMaw4bujbmcgZ2nhu69hIGhhaSBuaMOzbSBsw6AgYHIgZGlmZl9ob21lb3duZXJgIG5nxrDhu51pLA0KICAgIG5naMSpYSBsw6Agc+G7kSBuZ8aw4budaSBjw7MgbmjDoCBuaGnhu4F1IGjGoW4ga2jDoSDEkcOhbmcga+G7gyBzbyB24bubaSBz4buRIG5nxrDhu51pIGtow7RuZw0KICAgIGPDsyBuaMOgLg0KDQojIyAqKkJp4bq/biBNYXJpdGFsU3RhdHVzKioNCg0KKipC4bqjbmcgdOG6p24gc+G7kSoqDQoNCmBgYHtyfQ0KI0zhuq1wIGLhuqNuZyB04bqnbiBz4buRIGPhu6dhIGJp4bq/biBNYXJpdGFsU3RhdHVzDQp0YW5zb19tYXJpdGFsU3RhdHVzIDwtIHRhYmxlKGR0JE1hcml0YWxTdGF0dXMpDQp0YW5zb19tYXJpdGFsU3RhdHVzDQpgYGANCg0KKipCaeG7g3UgxJHhu5MqKg0KDQpgYGB7cn0NCiMgVuG6vSBiaeG7g3UgxJHhu5MgY+G7mXQgY2hvIE1hcml0YWxTdGF0dXMNCmJhcnBsb3QoDQogIHRhbnNvX21hcml0YWxTdGF0dXMsDQogIG1haW4gICA9ICJU4bqnbiBz4buRIGJp4bq/biB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4iLA0KICB4bGFiICAgPSAidMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIiwNCiAgeWxhYiAgID0gIlPhu5EgcXVhbiBzw6F0IiwNCiAgbGFzICAgID0gMSwNCiAgY29sICAgID0gYygieWVsbG93IiwgImdyZWVuIiksDQogIGJvcmRlciA9ICJ3aGl0ZSINCikNCmBgYA0KDQoqKkLhuqNuZyB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCiNM4bqtcCBi4bqjbmcgdOG6p24gc3XhuqV0IGPhu6dhIGJp4bq/biBNYXJpdGFsU3RhdHVzDQp0YW5zdWF0X21hcml0YWxTdGF0dXMgPC0gdGFuc29fbWFyaXRhbFN0YXR1cy9zdW0obnJvdyhkdCkpDQp0YW5zdWF0X21hcml0YWxTdGF0dXMNCmBgYA0KDQoqKkJp4buDdSDEkeG7kyoqDQoNCmBgYHtyfQ0KIyBOaMOjbiBwaOG6p24gdHLEg20NCm5oYW5tYXJpdGFsU3RhdHVzIDwtIHBhc3RlMCggcm91bmQodGFuc3VhdF9tYXJpdGFsU3RhdHVzICogMTAwLCAxKSwgIiUiKQ0KDQojIFbhur0gcGllIGNoYXJ0IOG6qW4gbmjDo24NCnBpZSgNCiAgdGFuc3VhdF9tYXJpdGFsU3RhdHVzLA0KICBsYWJlbHMgPSBOQSwNCiAgbWFpbiAgID0gIlThuqduIHN14bqldCBiaeG6v24gTWFyaXRhbFN0YXR1cyIsDQogIGNvbCAgICA9IHJhaW5ib3cobGVuZ3RoKG5oYW5tYXJpdGFsU3RhdHVzKSksDQogIGJvcmRlciA9ICJ3aGl0ZSIpDQoNCiMgVGjDqm0gbGVnZW5kIGLDqm4gbmdvw6BpDQpsZWdlbmQoDQogIHggICAgICA9InRvcHJpZ2h0IiwNCiAgbGVnZW5kID0gcGFzdGUobmFtZXModGFuc3VhdF9tYXJpdGFsU3RhdHVzKSxuaGFubWFyaXRhbFN0YXR1cyksDQogIGZpbGwgICA9IHJhaW5ib3cobGVuZ3RoKG5oYW5tYXJpdGFsU3RhdHVzKSkNCikNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNCmBgYHtyfQ0KIyDEkOG6v20gc+G7kSBuZ8aw4budaSBr4bq/dCBow7RuIChNKSB2w6AgxJHhu5ljIHRow6JuIChTKQ0KbXNfY291bnRzIDwtIHRhYmxlKGR0JE1hcml0YWxTdGF0dXMpDQoNCiMgQ2jDqm5oIGzhu4djaCB24buBIHPhu5EgbMaw4bujbmcgZ2nhu69hIGhhaSBuaMOzbQ0KbXNfZGlmZiA8LSBhYnMobXNfY291bnRzWyJNIl0gLSBtc19jb3VudHNbIlMiXSkNCmBgYA0KDQotICAgVuG6rXkgdHJvbmcgYuG7mSBk4buvIGxp4buHdSBuw6B5IGPDsw0KICAgIGByIHRhYmxlKGR0JE1hcml0YWxTdGF0dXMpWzFdL3N1bShucm93KGR0KSkqMTAwYCAlIMSRw6Mga+G6v3QgaMO0biB2w6ANCiAgICBgciB0YWJsZShkdCRNYXJpdGFsU3RhdHVzKVsyXS9zdW0obnJvdyhkdCkpKjEwMGAlIMSR4buZYyB0aMOibi4NCg0KLSAgIFRyb25nIGLhu5kgZOG7ryBsaeG7h3UgbsOgeSBjw7MgYHIgbXNfY291bnRzWyJNIl1gIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biB2w6ANCiAgICBgciBtc19jb3VudHNbIlMiXWAgbmfGsOG7nWkgxJHhu5ljIHRow6JuLiBOaMOzbSBr4bq/dCBow7RuIG5oaeG7gXUgaMahbiBuaMOzbSDEkeG7mWMNCiAgICB0aMOibiBgciBtc19kaWZmYCBuZ8aw4budaS4NCg0KIyMgKipCaeG6v24gQ2l0eSoqDQoNCioqQuG6o25nIHThuqduIHPhu5EqKg0KDQpgYGB7cn0NCiMgTOG6rXAgYuG6o25nIHThuqduIHPhu5EgYmnhur9uIENpdHkNCnRhbnNvX2NpdHkgPC0gdGFibGUoZHQkQ2l0eSkNCg0KIyBT4bqvcCB44bq/cCBnaeG6o20gZOG6p24gxJHhu4MgeGVtIGPDoWMgdGjDoG5oIHBo4buRIHBo4buVIGJp4bq/biBuaOG6pXQNCnRhbnNvX2NpdHkgPC0gc29ydCh0YW5zb19jaXR5LCBkZWNyZWFzaW5nID0gVFJVRSkNCg0KIyBIaeG7g24gdGjhu4sgdG/DoG4gYuG7mSBi4bqjbmcgdOG6p24gc+G7kQ0KdGFuc29fY2l0eQ0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQpiYXJwbG90KA0KICB0YW5zb19jaXR5LA0KICBtYWluICAgPSAiVOG6p24gc+G7kSBiaeG6v24gdGjDoG5oIHBo4buRIiwNCiAgY2V4Lm5hbWVzID0gMC40LA0KICB4bGFiICAgPSAiU+G7kSBxdWFuIHPDoXQiLA0KICB5bGFiICAgPSAiVGjDoG5oIHBo4buRIiwNCiAgbGFzICAgID0gMSwgICAgICAgICAgICAjIHhvYXkgbmjDo24gdHLhu6VjIHkgbmdhbmcNCiAgY29sICAgID0gInN0ZWVsYmx1ZSIsDQogIGJvcmRlciA9ICJ3aGl0ZSIsDQogIGhvcml6ICA9IFRSVUUgICAgICAgICAgIyB24bq9IHRoYW5oIG5nYW5nIMSR4buDIMSR4buNYyBuaMOjbiBk4buFIGjGoW4NCikNCmBgYA0KDQoqKkLhuqNuZyB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCnRhbnN1YXRfY2l0eSAgPC0gdGFuc29fY2l0eS9zdW0obnJvdyhkdCkpDQp0YW5zdWF0X2NpdHkNCmBgYA0KDQoqKkJp4buDdSDEkeG7kyoqDQoNCmBgYHtyfQ0KIyBNw6B1IGNobyB04burbmcgbMOhdA0KY29scyA8LSByYWluYm93KGxlbmd0aCh0YW5zdWF0X2NpdHkpKQ0KDQojIE5ow6NuIHBo4bqnbiB0csSDbQ0KbmhhbmNpdHkgPC0gcGFzdGUwKCByb3VuZCh0YW5zdWF0X2NpdHkgKiAxMDAsIDEpLCAiJSIpDQoNCiMgVuG6vSBwaWUgY2hhcnQg4bqpbiBuaMOjbg0KcGllKA0KICB0YW5zdWF0X2NpdHksDQogIGxhYmVscyA9IE5BLA0KICBtYWluICAgPSAiVOG6p24gc3XhuqV0IGJp4bq/biBjaXR5IiwNCiAgY29sICAgID0gY29scywNCiAgYm9yZGVyID0gIndoaXRlIikNCg0KIyBUaMOqbSBsZWdlbmQgYsOqbiBuZ2/DoGkNCmxlZ2VuZCgNCiAgeCAgICAgICAgID0idG9wcmlnaHQiLA0KICBsZWdlbmQgICAgPSBwYXN0ZShuYW1lcyh0YW5zdWF0X2NpdHkpLG5oYW5jaXR5KSwNCiAgZmlsbCAgICAgID0gY29scywNCiAgYnR5ICAgICAgID0gIm4iLCAgICAgICAjIGLhu48gdmnhu4FuDQogIGNleCAgICAgICA9IDAuNSwgICAgICAgIyB0aHUgbmjhu48gY2jhu68NCiAgbmNvbCAgICAgID0gMiwgICAgICAgICAjIGNoaWEgdGjDoG5oIDIgY+G7mXQNCiAgeC5pbnRlcnNwID0gMC41LCAgICAgICAjIGdpw6NuIGtob+G6o25nIGPDoWNoIGNo4buv4oCTa8O9IGhp4buHdSBuZ2FuZw0KICB5LmludGVyc3AgPSAwLjcgICAgICAgICMgZ2nDo24ga2hv4bqjbmcgY8OhY2ggZ2nhu69hIGPDoWMgZMOybmcNCikNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNCi0gICBUcm9uZyBi4buZIGThu68gbGnhu4d1IG7DoHksIHRow6BuaCBwaOG7kSBjw7MgdOG7tyBs4buHIGdpYW8gZOG7i2NoIGNhbyBuaOG6pXQgbMOgIFNhbGVtDQogICAgduG7m2kga2hv4bqjbmcgYHIgcm91bmQodGFibGUoZHQkQ2l0eSlbIlNhbGVtIl0vbnJvdyhkdCkqMTAwLCAyKWAlLCB0aeG6v3ANCiAgICB0aGVvIGzDoCBUYWNvbWENCiAgICAoYHIgcm91bmQodGFibGUoZHQkQ2l0eSlbIlRhY29tYSJdL25yb3coZHQpKjEwMCwgMilgJSksIExvcyBBbmdlbGVzDQogICAgKGByIHJvdW5kKHRhYmxlKGR0JENpdHkpWyJMb3MgQW5nZWxlcyJdL25yb3coZHQpKjEwMCwgMilgJSkgdsOgDQogICAgU2VhdHRsZSAoYHIgcm91bmQodGFibGUoZHQkQ2l0eSlbIlNlYXR0bGUiXS9ucm93KGR0KSoxMDAsIDIpYCUpLg0KDQotICAgQ8OhYyB0aMOgbmggcGjhu5Egbmjhu48gaMahbiBuaMawIEhpZGFsZ28NCiAgICAoYHIgcm91bmQodGFibGUoZHQkQ2l0eSlbIkhpZGFsZ28iXS9ucm93KGR0KSoxMDAsIDIpYCUpIGhv4bq3Yw0KICAgIEd1YWRhbGFqYXJhDQogICAgKGByIHJvdW5kKHRhYmxlKGR0JENpdHkpWyJHdWFkYWxhamFyYSJdL25yb3coZHQpKjEwMCwgMilgJSkgY8OzIHThu7cgbOG7hw0KICAgIHRo4bqlcCBoxqFuIG5oaeG7gXUuDQoNCi0gICDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBnaWFvIGThu4tjaCBjaOG7pyB54bq/dSB04bqtcCB0cnVuZyDhu58gbeG7mXQgc+G7kSB0aMOgbmggcGjhu5EgbOG7m24NCiAgICB24bubaSBkw6JuIHPhu5EgaG/hurdjIGhv4bqhdCDEkeG7mW5nIGtpbmggdOG6vyBjYW8gaMahbi4gQ8OhYyB0aMOgbmggcGjhu5Egbmjhu48gaMahbg0KICAgIMSRw7NuZyBnw7NwIMOtdCBoxqFuIHbDoG8gdOG7lW5nIHPhu5EgZ2lhbyBk4buLY2gsIGPDsyB0aOG7gyBkbyBxdXkgbcO0IHRo4buLIHRyxrDhu51uZw0KICAgIG5o4buPIGhv4bq3YyBt4bupYyDEkeG7mSBwaOG7lSBiaeG6v24gY+G7p2Egc+G6o24gcGjhuqltIHRo4bqlcC4NCg0KLSAgIE5nb8OgaSByYSwgdmnhu4djIHBow6JuIGLhu5EgbsOgeSBjxaluZyBjw7MgdGjhu4MgcGjhuqNuIMOhbmggY2hp4bq/biBsxrDhu6NjIHRp4bq/cCB0aOG7iw0KICAgIGhv4bq3YyBrw6puaCBwaMOibiBwaOG7kWkgbcOgIHNpw6p1IHRo4buLIMSRYW5nIHThuq1wIHRydW5nIHbDoG8gY8OhYyBraHUgduG7sWMgxJHDtA0KICAgIHRo4buLIGzhu5tuLg0KDQojIyAqKkJp4bq/biBTdGF0ZW9yUHJvdmluY2UqKg0KDQoqKkLhuqNuZyB04bqnbiBz4buRKioNCg0KYGBge3J9DQojTOG6rXAgYuG6o25nIHThuqduIHPhu5EgY+G7p2EgYmnhur9uIFN0YXRlb3JQcm92aW5jZQ0KdGFuc29fc3RhdGVvclByb3ZpbmNlIDwtIHRhYmxlKGR0JFN0YXRlb3JQcm92aW5jZSkNCnRhbnNvX3N0YXRlb3JQcm92aW5jZQ0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQpiYXJwbG90KA0KICB0YW5zb19zdGF0ZW9yUHJvdmluY2UsDQogIG1haW4gICA9ICJU4bqnbiBz4buRIGJp4bq/biBiYW5nIGhv4bq3YyB04buJbmgiLA0KICBjZXgubmFtZXMgPSAwLjQsDQogIHhsYWIgICA9ICJT4buRIHF1YW4gc8OhdCIsDQogIHlsYWIgICA9ICJiYW5nIGhv4bq3YyB04buJbmgiLA0KICBsYXMgICAgPSAxLCAgICAgICAgICAgICMgeG9heSBuaMOjbiB0cuG7pWMgeSBuZ2FuZw0KICBjb2wgICAgPSAiZ3JlZW4iLA0KICBib3JkZXIgPSAid2hpdGUiLA0KICBob3JpeiAgPSBUUlVFICAgICAgICAgICMgduG6vSB0aGFuaCBuZ2FuZyDEkeG7gyDEkeG7jWMgbmjDo24gZOG7hSBoxqFuDQopDQpgYGANCg0KKipC4bqjbmcgdOG6p24gc3XhuqV0KioNCg0KYGBge3J9DQojTOG6rXAgYuG6o25nIHThuqduIHN14bqldCBj4bunYSBiaeG6v24gU3RhdGVvclByb3ZpbmNlDQp0YW5zdWF0X3N0YXRlb3JQcm92aW5jZSA8LSB0YW5zb19zdGF0ZW9yUHJvdmluY2Uvc3VtKG5yb3coZHQpKQ0KdGFuc3VhdF9zdGF0ZW9yUHJvdmluY2UNCmBgYA0KDQoqKsSQ4buTIHRo4buLKioNCg0KYGBge3J9DQojIE3DoHUgY2hvIHThu6tuZyBsw6F0DQpjb2xzIDwtIHJhaW5ib3cobGVuZ3RoKHRhbnN1YXRfc3RhdGVvclByb3ZpbmNlKSkNCg0KIyBOaMOjbiBwaOG6p24gdHLEg20NCm5oYW5zdGF0ZW9yUHJvdmluY2UgPC0gcGFzdGUwKCByb3VuZCh0YW5zdWF0X3N0YXRlb3JQcm92aW5jZSAqIDEwMCwgMSksICIlIikNCg0KIyBW4bq9IHBpZSBjaGFydCDhuqluIG5ow6NuDQpwaWUoDQogIHRhbnN1YXRfc3RhdGVvclByb3ZpbmNlLA0KICBsYWJlbHMgPSBOQSwNCiAgbWFpbiAgID0gIlThuqduIHN14bqldCBiaeG6v24gYmFuZyBob+G6t2MgdOG7iW5oIiwNCiAgY29sICAgID0gY29scywNCiAgYm9yZGVyID0gIndoaXRlIikNCg0KIyBUaMOqbSBsZWdlbmQgYsOqbiBuZ2/DoGkNCmxlZ2VuZCgNCiAgeCAgICAgICAgID0idG9wcmlnaHQiLA0KICBsZWdlbmQgICAgPSBwYXN0ZShuYW1lcyh0YW5zdWF0X3N0YXRlb3JQcm92aW5jZSksbmhhbnN0YXRlb3JQcm92aW5jZSksDQogIGZpbGwgICAgICA9IGNvbHMsDQogIGJ0eSAgICAgICA9ICJuIiwgICAgICAgIyBi4buPIHZp4buBbg0KICBjZXggICAgICAgPSAwLjUsICAgICAgICMgdGh1IG5o4buPIGNo4buvDQogIG5jb2wgICAgICA9IDIsICAgICAgICAgIyBjaGlhIHRow6BuaCAyIGPhu5l0DQopDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKiBUcm9uZyBi4buZIGThu68gbGnhu4d1IG7DoHksIGJhbmcgaG/hurdjIHThu4luaCBjw7MgdOG7tyBs4buHIGdpYW8gZOG7i2NoDQps4bubbiBuaOG6pXQgbMOgIFdBIHbhu5tpIGtob+G6o25nDQpgciByb3VuZCh0YWJsZShkdCRTdGF0ZW9yUHJvdmluY2UpWyJXQSJdL25yb3coZHQpKjEwMCwgMilgJSwgdGnhur9wIHRoZW8NCmzDoCBDQSAoYHIgcm91bmQodGFibGUoZHQkU3RhdGVvclByb3ZpbmNlKVsiQ0EiXS9ucm93KGR0KSoxMDAsIDIpYCUpIHbDoA0KT1IgKGByIHJvdW5kKHRhYmxlKGR0JFN0YXRlb3JQcm92aW5jZSlbIk9SIl0vbnJvdyhkdCkqMTAwLCAyKWAlKS4gQ8OhYw0KYmFuZyBuaMawIEphbGlzY28NCihgciByb3VuZCh0YWJsZShkdCRTdGF0ZW9yUHJvdmluY2UpWyJKYWxpc2NvIl0vbnJvdyhkdCkqMTAwLCAyKWAlKSB2w6ANCkd1ZXJyZXJvDQooYHIgcm91bmQodGFibGUoZHQkU3RhdGVvclByb3ZpbmNlKVsiR3VlcnJlcm8iXS9ucm93KGR0KSoxMDAsIDIpYCUpDQpjaGnhur9tIHThu7cgbOG7hyB0aOG6pXAgaMahbi4gTmjGsCB24bqteSwgZOG7ryBsaeG7h3UgY2hvIHRo4bqleSBz4buxIHThuq1wIHRydW5nIGdpYW8gZOG7i2NoDQpjYW8g4bufIG3hu5l0IHPhu5EgYmFuZyBjaMOtbmguDQoNCiMjICoqQmnhur9uIENvdW50cnkqKg0KDQoqKkLhuqNuZyB04bqnbiBz4buRKioNCg0KYGBge3J9DQojTOG6rXAgYuG6o25nIHThuqduIHPhu5EgY+G7p2EgYmnhur9uIENvdW50cnkNCnRhbnNvX2NvdW50cnkgPC0gdGFibGUoZHQkQ291bnRyeSkNCnRhbnNvX2NvdW50cnkNCmBgYA0KDQoqKkJp4buDdSDEkeG7kyoqDQoNCmBgYHtyfQ0KYmFycGxvdCgNCiAgdGFuc29fY291bnRyeSwNCiAgbWFpbiAgID0gInThuqduIHPhu5EgYmnhur9uIHF14buRYyBnaWEiLA0KICB4bGFiICAgPSAicXXhu5FjIGdpYSIsDQogIHlsYWIgICA9ICJz4buRIGzGsOG7o25nIiwNCiAgbGFzICAgID0gMSwNCiAgY29sICAgID0gYygiYnJvd24iLCJvcmFuZ2UiLCJwaW5rIiksDQogIGJvcmRlciA9ICJ3aGl0ZSINCikNCmBgYA0KDQoqKkLhuqNuZyB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCiNM4bqtcCBi4bqjbmcgdOG6p24gc3XhuqV0IGPhu6dhIGJp4bq/biBDb3VudHJ5DQp0YW5zdWF0X2NvdW50cnkgPC0gdGFuc29fY291bnRyeS9zdW0obnJvdyhkdCkpDQp0YW5zdWF0X2NvdW50cnkNCmBgYA0KDQoqKkJp4buDdSDEkeG7kyoqDQoNCmBgYHtyfQ0KIyBOaMOjbiBwaOG6p24gdHLEg20NCm5oYW5jb3VudHJ5IDwtIHBhc3RlMCggcm91bmQodGFuc3VhdF9jb3VudHJ5ICogMTAwLCAxKSwgIiUiKQ0KIyBW4bq9IHBpZSBjaGFydCDhuqluIG5ow6NuDQpwaWUoDQogIHRhbnN1YXRfY291bnRyeSwNCiAgbGFiZWxzID0gTkEsDQogIG1haW4gICA9ICJU4bqnbiBzdeG6pXQgYmnhur9uIHF14buRYyBnaWEiLA0KICBjb2wgICAgPSByYWluYm93KGxlbmd0aChuaGFuY291bnRyeSkpLA0KICBib3JkZXIgPSAid2hpdGUiKQ0KDQojIFRow6ptIGxlZ2VuZCBiw6puIG5nb8OgaQ0KbGVnZW5kKA0KICB4ICAgICAgPSJ0b3ByaWdodCIsDQogIGxlZ2VuZCA9IHBhc3RlKG5hbWVzKHRhbnN1YXRfY291bnRyeSksbmhhbmNvdW50cnkpLA0KICBmaWxsICAgPSByYWluYm93KGxlbmd0aChuaGFuY291bnRyeSkpLA0KICBidHkgICAgPSJuIg0KKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KYGBge3J9DQojIMSQ4bq/bSBz4buRIGLhuqNuIGdoaSB0aGVvIHF14buRYyBnaWENCmN0eV9jb3VudHMgPC0gdGFibGUoZHQkQ291bnRyeSkNCg0KIyBDaMOqbmggbOG7h2NoIHbhu4Egc+G7kSBsxrDhu6NuZyBnaeG7r2EgcXXhu5FjIGdpYSDEkcO0bmcgbmjhuqV0IHbDoCDDrXQgbmjhuqV0DQpjdHlfZGlmZiA8LSBtYXgoY3R5X2NvdW50cykgLSBtaW4oY3R5X2NvdW50cykNCmBgYA0KDQotICAgVuG6rXkgdHJvbmcgYuG7mSBk4buvIGxp4buHdSBuw6B5IGPDsw0KICAgIGByIHRhYmxlKGR0JENvdW50cnkpWzFdL3N1bShucm93KGR0KSkqMTAwYCAlIOG7nyBDYW5hZGEsDQogICAgYHIgdGFibGUoZHQkQ291bnRyeSlbMl0vc3VtKG5yb3coZHQpKSoxMDBgJSDhu58gTWV4aWNvIHbDoA0KICAgIGByIHRhYmxlKGR0JENvdW50cnkpWzNdL3N1bShucm93KGR0KSkqMTAwYCUg4bufIFVTQS4NCg0KLSAgIFF14buRYyBnaWEgxJHDtG5nIG5o4bqldCBjw7MgYHIgbWF4KGN0eV9jb3VudHMpYCwgcXXhu5FjIGdpYSDDrXQgbmjhuqV0IGPDsyByDQogICAgYG1pbihjdHlfY291bnRzKWAuDQoNCi0gICBT4buxIGNow6puaCBs4buHY2ggZ2nhu69hIGhhaSBxdeG7kWMgZ2lhIG7DoHkgbMOgIGByIGN0eV9kaWZmYCBuZ8aw4budaS4NCg0KIyMgKipCaeG6v24gUHJvZHVjdEZhbWlseSoqDQoNCioqQuG6o25nIHThuqduIHPhu5EqKg0KDQpgYGB7cn0NCiNM4bqtcCBi4bqjbmcgdOG6p24gc+G7kSBj4bunYSBiaeG6v24gUHJvZHVjdEZhbWlseQ0KdGFuc29fcHJvZHVjdEZhbWlseSA8LSB0YWJsZShkdCRQcm9kdWN0RmFtaWx5KQ0KdGFuc29fcHJvZHVjdEZhbWlseQ0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQpiYXJwbG90KA0KICB0YW5zb19wcm9kdWN0RmFtaWx5LA0KICBtYWluICAgPSAidOG6p24gc+G7kSBiaeG6v24gbmjDs20gc+G6o24gcGjhuqltIiwNCiAgeGxhYiAgID0gIm5ow7NtIHPhuqNuIHBo4bqpbSIsDQogIHlsYWIgICA9ICJz4buRIGzGsOG7o25nIiwNCiAgbGFzICAgID0gMSwNCiAgY29sICAgID0gYygieWVsbG93IiwicHVycGxlIiwicGluayIpLA0KICBib3JkZXIgPSAid2hpdGUiDQopDQpgYGANCg0KKipC4bqjbmcgdOG6p24gc3XhuqV0KioNCg0KYGBge3J9DQojTOG6rXAgYuG6o25nIHThuqduIHN14bqldCBj4bunYSBiaeG6v24gUHJvZHVjdEZhbWlseQ0KdGFuc3VhdF9wcm9kdWN0RmFtaWx5IDwtIHRhbnNvX3Byb2R1Y3RGYW1pbHkvc3VtKG5yb3coZHQpKQ0KdGFuc3VhdF9wcm9kdWN0RmFtaWx5DQpgYGANCg0KKipCaeG7g3UgxJHhu5MqKg0KDQpgYGB7cn0NCg0KY29scyA8LSBjKCJsaWdodGJsdWUiLCJsaWdodHBpbmsiLCJsaWdodGdyZWVuIikNCiMgTmjDo24gcGjhuqduIHRyxINtDQpuaGFucHJvZHVjdEZhbWlseSA8LSBwYXN0ZTAoIHJvdW5kKHRhbnN1YXRfcHJvZHVjdEZhbWlseSAqIDEwMCwgMSksICIlIikNCiMgVuG6vSBwaWUgY2hhcnQg4bqpbiBuaMOjbg0KcGllKA0KICB0YW5zdWF0X3Byb2R1Y3RGYW1pbHksDQogIGxhYmVscyA9IE5BLA0KICBtYWluICAgPSAiVOG6p24gc3XhuqV0IGJp4bq/biBuaMOzbSBz4bqjbiBwaOG6qW0iLA0KICBjb2wgICAgPSBjb2xzLA0KICBib3JkZXIgPSAid2hpdGUiKQ0KDQojIFRow6ptIGxlZ2VuZCBiw6puIG5nb8OgaQ0KbGVnZW5kKA0KICB4ICAgICAgPSJ0b3ByaWdodCIsDQogIGxlZ2VuZCA9IHBhc3RlKG5hbWVzKHRhbnN1YXRfcHJvZHVjdEZhbWlseSksbmhhbnByb2R1Y3RGYW1pbHkpLA0KICBmaWxsICAgPSBjb2xzLA0KICApDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQotICAgVuG6rXkgdHJvbmcgYuG7mSBk4buvIGxp4buHdSBuw6B5IGPDsw0KICAgIGByIHRhYmxlKGR0JFByb2R1Y3RGYW1pbHkpWzFdL3N1bShucm93KGR0KSkqMTAwYCAlIMSR4buTIHXhu5FuZywNCiAgICBgciB0YWJsZShkdCRQcm9kdWN0RmFtaWx5KVsyXS9zdW0obnJvdyhkdCkpKjEwMGAlIHRo4bupYyDEg24gdsOgDQogICAgYHIgdGFibGUoZHQkUHJvZHVjdEZhbWlseSlbM10vc3VtKG5yb3coZHQpKSoxMDBgJSBraMO0bmcgdGnDqnUgdGjhu6UNCiAgICDEkcaw4bujYy4NCg0KIyMgKipCaeG6v24gUHJvZHVjdERlcGFydG1lbnQqKg0KDQoqKkLhuqNuZyB04bqnbiBz4buRKioNCg0KYGBge3J9DQojIEzhuq1wIGLhuqNuZyB04bqnbiBz4buRDQp0YW5zb19wcm9kdWN0RGVwYXJ0bWVudCA8LSB0YWJsZShkdCRQcm9kdWN0RGVwYXJ0bWVudCkNCnRhbnNvX3Byb2R1Y3REZXBhcnRtZW50DQpgYGANCg0KKipCaeG7g3UgxJHhu5MqKg0KDQpgYGB7cn0NCmJhcnBsb3QoDQogIHRhbnNvX3Byb2R1Y3REZXBhcnRtZW50LA0KICBtYWluICAgPSAiVOG6p24gc+G7kSBiaeG6v24gYuG7mSBwaOG6rW4gc+G6o24gcGjhuqltIHRyb25nIG5ow7NtIiwNCiAgY2V4Lm5hbWVzID0gMC40LA0KICB4bGFiICAgPSAiU+G7kSBxdWFuIHPDoXQiLA0KICB5bGFiICAgPSAiIiwNCiAgbGFzICAgID0gMSwgICAgICAgICAgICAjIHhvYXkgbmjDo24gdHLhu6VjIHkgbmdhbmcNCiAgY29sICAgID0gImxpZ2h0Ymx1ZSIsDQogIGJvcmRlciA9ICJ3aGl0ZSIsDQogIGhvcml6ICA9IFRSVUUgICAgICAgICAgIyB24bq9IHRoYW5oIG5nYW5nIMSR4buDIMSR4buNYyBuaMOjbiBk4buFIGjGoW4NCikNCmBgYA0KDQoqKkLhuqNuZyB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCnRhbnN1YXRfcHJvZHVjdERlcGFydG1lbnQgPC10YW5zb19wcm9kdWN0RGVwYXJ0bWVudC9zdW0obnJvdyhkdCkpDQp0YW5zdWF0X3Byb2R1Y3REZXBhcnRtZW50DQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQotICAgVHJvbmcgYuG7mSBk4buvIGxp4buHdSwgbmjDs20gc+G6o24gcGjhuqltIGPDsyB04bu3IGzhu4cgZ2lhbyBk4buLY2ggY2FvIG5o4bqldCBsw6ANCiAgICBQcm9kdWNlIHbhu5tpDQogICAgYHIgcm91bmQodGFibGUoZHQkUHJvZHVjdERlcGFydG1lbnQpWyJQcm9kdWNlIl0vbnJvdyhkdCkqMTAwLCAyKWAlLA0KICAgIHRp4bq/cCB0aGVvIGzDoCBTbmFjayBGb29kcw0KICAgIChgciByb3VuZCh0YWJsZShkdCRQcm9kdWN0RGVwYXJ0bWVudClbIlNuYWNrIEZvb2RzIl0vbnJvdyhkdCkqMTAwLCAyKWAlKQ0KICAgIHbDoCBIb3VzZWhvbGQNCiAgICAoYHIgcm91bmQodGFibGUoZHQkUHJvZHVjdERlcGFydG1lbnQpWyJIb3VzZWhvbGQiXS9ucm93KGR0KSoxMDAsIDIpYCUpLg0KICAgIE5ow7NtIEZyb3plbiBGb29kcyBjxaluZyBjaGnhur9tIHThu7cgbOG7hyDEkcOhbmcga+G7gyBsw6ANCiAgICBgciByb3VuZCh0YWJsZShkdCRQcm9kdWN0RGVwYXJ0bWVudClbIkZyb3plbiBGb29kcyJdL25yb3coZHQpKjEwMCwgMilgJS4NCiAgICBDw6FjIG5ow7NtIG5oxrAgQ2Fyb3VzZWwNCiAgICAoYHIgcm91bmQodGFibGUoZHQkUHJvZHVjdERlcGFydG1lbnQpWyJDYXJvdXNlbCJdL25yb3coZHQpKjEwMCwgMilgJSkNCiAgICB2w6AgQ2hlY2tvdXQNCiAgICAoYHIgcm91bmQodGFibGUoZHQkUHJvZHVjdERlcGFydG1lbnQpWyJDaGVja291dCJdL25yb3coZHQpKjEwMCwgMilgJSkNCiAgICBjw7MgdOG7tyBs4buHIHRo4bqlcCBoxqFuIG5oaeG7gXUuDQoNCiMjICoqQmnhur9uIFByb2R1Y3RDYXRlZ29yeSoqDQoNCioqQuG6o25nIHThuqduIHPhu5EqKg0KDQpgYGB7cn0NCnRhbnNvX3Byb2R1Y3RDYXRlZ29yeSA8LSB0YWJsZShkdCRQcm9kdWN0Q2F0ZWdvcnkpDQp0YW5zb19wcm9kdWN0Q2F0ZWdvcnkNCmBgYA0KDQoqKkJp4buDdSDEkeG7kyoqDQoNCmBgYHtyfQ0KYmFycGxvdCgNCiAgdGFuc29fcHJvZHVjdENhdGVnb3J5LA0KICBtYWluICAgPSAiVOG6p24gc+G7kSBiaeG6v24gaOG6oW5nIG3hu6VjIHPhuqNuIHBo4bqpbSBj4bulIHRo4buDIiwNCiAgY2V4Lm5hbWVzID0gMC40LA0KICB4bGFiICAgPSAiU+G7kSBxdWFuIHPDoXQiLA0KICB5bGFiICAgPSAiIiwNCiAgbGFzICAgID0gMSwgICAgICAgICAgICAjIHhvYXkgbmjDo24gdHLhu6VjIHkgbmdhbmcNCiAgY29sICAgID0gImxpZ2h0cGluayIsDQogIGJvcmRlciA9ICJ3aGl0ZSIsDQogIGhvcml6ICA9IFRSVUUgICAgICAgICAgIyB24bq9IHRoYW5oIG5nYW5nIMSR4buDIMSR4buNYyBuaMOjbiBk4buFIGjGoW4NCikNCmBgYA0KDQoqKkLhuqNuZyB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCnRhbnN1YXRfcHJvZHVjdENhdGVnb3J5IDwtIHRhbnNvX3Byb2R1Y3RDYXRlZ29yeS9zdW0obnJvdyhkdCkpIA0KdGFuc3VhdF9wcm9kdWN0Q2F0ZWdvcnkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNCi0gICBUcm9uZyBi4buZIGThu68gbGnhu4d1LCBuaMOzbSBz4bqjbiBwaOG6qW0gY8OzIHThu7cgbOG7hyBnaWFvIGThu4tjaCBjYW8gbmjhuqV0IGzDoA0KICAgIFZlZ2V0YWJsZXMgduG7m2kNCiAgICBgciByb3VuZCh0YWJsZShkdCRQcm9kdWN0Q2F0ZWdvcnkpWyJWZWdldGFibGVzIl0vbnJvdyhkdCkqMTAwLCAyKWAlLA0KICAgIHRp4bq/cCB0aGVvIGzDoCBTbmFjayBGb29kcw0KICAgIChgciByb3VuZCh0YWJsZShkdCRQcm9kdWN0Q2F0ZWdvcnkpWyJTbmFjayBGb29kcyJdL25yb3coZHQpKjEwMCwgMilgJSkNCiAgICB2w6AgRGFpcnkNCiAgICAoYHIgcm91bmQodGFibGUoZHQkUHJvZHVjdENhdGVnb3J5KVsiRGFpcnkiXS9ucm93KGR0KSoxMDAsIDIpYCUpLg0KICAgIEPDoWMgbmjDs20gxJHDs25nIGjhu5lwIG5oxrAgQ2FubmVkIE95c3RlcnMNCiAgICAoYHIgcm91bmQodGFibGUoZHQkUHJvZHVjdENhdGVnb3J5KVsiQ2FubmVkIE95c3RlcnMiXS9ucm93KGR0KSoxMDAsIDIpYCUpDQogICAgdsOgIENhbm5lZCBDbGFtcw0KICAgIChgciByb3VuZCh0YWJsZShkdCRQcm9kdWN0Q2F0ZWdvcnkpWyJDYW5uZWQgQ2xhbXMiXS9ucm93KGR0KSoxMDAsIDIpYCUpDQogICAgY2hp4bq/bSB04bu3IGzhu4cgcuG6pXQgbmjhu48sIGNobyB0aOG6pXkgc+G7sSDGsHUgdGnDqm4gbXVhIGjDoG5nIHTGsMahaSB2w6AgxJHhu5MgxINuIG5o4bq5Lg0KDQojIyAqKkJp4bq/biBBbm51YWxJbmNvbWUqKg0KDQoqKkLhuqNuZyB04bqnbiBz4buRKioNCg0KYGBge3J9DQojIELhuqNuZyB04bqnbiBzdeG6pXQgY2hvIEFubnVhbEluY29tZQ0KdGFuc29fYW5udWFsSW5jb21lIDwtIHRhYmxlKGR0JEFubnVhbEluY29tZSkNCnRhbnNvX2FubnVhbEluY29tZQ0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQpiYXJwbG90KA0KICB0YW5zb19hbm51YWxJbmNvbWUsDQogIG1haW4gICA9ICJU4bqnbiBz4buRIHRoZW8gVGh1IG5o4bqtcCIsDQogIGNleC5uYW1lcyA9IDAuNCwNCiAgeGxhYiAgID0gIkFubnVhbEluY29tZSIsDQogIHlsYWIgICA9ICJz4buRIHRodSBuaOG6rXAiLA0KICBsYXMgICAgPSAxLCAgICAgICAgICAgICMgeG9heSBuaMOjbiB0cuG7pWMgeSBuZ2FuZw0KICBjb2wgICAgPSAibGlnaHRibHVlIiwNCiAgYm9yZGVyID0gIndoaXRlIiwNCiAgaG9yaXogID0gVFJVRSAgICAgICAgICAjIHbhur0gdGhhbmggbmdhbmcgxJHhu4MgxJHhu41jIG5ow6NuIGThu4UgaMahbg0KKQ0KYGBgDQoNCioqQuG6o25nIHThuqduIHN14bqldCoqDQoNCmBgYHtyfQ0KdGFuc3VhdF9hbm51YWxJbmNvbWUgPC0gdGFuc29fYW5udWFsSW5jb21lL3N1bShucm93KGR0KSkgDQp0YW5zdWF0X2FubnVhbEluY29tZQ0KYGBgDQoNCioqQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQojIE3DoHUgY2hvIHThu6tuZyBsw6F0DQpjb2xzIDwtIHJhaW5ib3cobGVuZ3RoKHRhbnN1YXRfYW5udWFsSW5jb21lKSkNCg0KIyBOaMOjbiBwaOG6p24gdHLEg20NCm5oYW5hbm51YWxJbmNvbWUgPC0gcGFzdGUwKCByb3VuZCh0YW5zdWF0X2FubnVhbEluY29tZSAqIDEwMCwgMSksICIlIikNCg0KIyBW4bq9IHBpZSBjaGFydCDhuqluIG5ow6NuDQpwaWUoDQogIHRhbnN1YXRfYW5udWFsSW5jb21lLA0KICBsYWJlbHMgPSBOQSwNCiAgbWFpbiAgID0gIlThuqduIHN14bqldCBiaeG6v24gdGh1IG5o4bqtcCIsDQogIGNvbCAgICA9IGNvbHMsDQogIGJvcmRlciA9ICJ3aGl0ZSIpDQoNCiMgVGjDqm0gbGVnZW5kIGLDqm4gbmdvw6BpDQpsZWdlbmQoDQogIHggICAgICAgICA9InRvcHJpZ2h0IiwNCiAgbGVnZW5kICAgID0gcGFzdGUobmFtZXModGFuc3VhdF9hbm51YWxJbmNvbWUpLG5oYW5hbm51YWxJbmNvbWUpLA0KICBmaWxsICAgICAgPSBjb2xzLA0KICBidHkgICAgICAgPSAibiIsICAgICAgICMgYuG7jyB2aeG7gW4NCiAgY2V4ICAgICAgID0gMC41LCAgICAgICAjIHRodSBuaOG7jyBjaOG7rw0KICBuY29sICAgICAgPSAyLCAgICAgICAgICMgY2hpYSB0aMOgbmggMiBj4buZdA0KICB4LmludGVyc3AgPSAwLjUsICAgICAgICMgZ2nDo24ga2hv4bqjbmcgY8OhY2ggY2jhu6/igJNrw70gaGnhu4d1IG5nYW5nDQogIHkuaW50ZXJzcCA9IDAuNyAgICAgICAgIyBnacOjbiBraG/huqNuZyBjw6FjaCBnaeG7r2EgY8OhYyBkw7JuZw0KKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KLSAgIFPhu7EgcGjDom4gYuG7kSB0aHUgbmjhuq1wIGtow7RuZyDEkeG7gXUgcGjhuqNuIMOhbmggY8ahIGPhuqV1IGtow6FjaCBow6BuZyBj4bunYSBzacOqdQ0KICAgIHRo4buLIGhv4bq3YyDEkcahbiB24buLIGto4bqjbyBzw6F0OiB04bqtcCB0cnVuZyBuaGnhu4F1IOG7nyBjw6FjIG5ow7NtIHRodSBuaOG6rXAgdHJ1bmcNCiAgICBiw6xuaCDEkeG6v24gdHJ1bmcgY2FvLCB0cm9uZyBraGkgbmjDs20gdGh1IG5o4bqtcCBxdcOhIHRo4bqlcCBob+G6t2MgcXXDoSBjYW8NCiAgICB4deG6pXQgaGnhu4duIMOtdCBoxqFuLg0KDQotICAgxJDDonkgY8OzIHRo4buDIGzDoCBk4bqldSBoaeG7h3UgxJHhu4MgZG9hbmggbmdoaeG7h3AgxJFp4buBdSBjaOG7iW5oIGNoaeG6v24gbMaw4bujYyB0aeG6v3ANCiAgICBj4bqtbiB0aOG7iyB0csaw4budbmcsIG5oxrAgdOG6rXAgdHJ1bmcgbmhp4buBdSBoxqFuIHbDoG8gY8OhYyBuaMOzbSB0aHUgbmjhuq1wIMSRYW5nDQogICAgY2hp4bq/bSDGsHUgdGjhur8sIGhv4bq3YyBt4bufIHLhu5luZyBjw6FjIGNow61uaCBzw6FjaCDGsHUgxJHDo2kgxJHhu4MgdGh1IGjDunQgbmjDs20NCiAgICBraMOhY2ggaMOgbmcgw610IHBo4buVIGJp4bq/biBoxqFuLg0KDQojICoqUGjhuqduIDMuIMav4buaQyBMxq/hu6JORyBLSE/huqJORyBWw4AgS0nhu4JNIMSQ4buKTkggR0nhuqIgVEhVWeG6vlQgQ0hPIFThu7YgTOG7hiAoTeG7mFQgQknhur5OKSoqDQoNCmBgYHtyfQ0KIyBU4buVbmcgc+G7kSBi4bqjbiBnaGkgKG4pDQpuIDwtIG5yb3coZHQpDQpgYGANCg0KKipHaeG6oyB0aHV54bq/dCDEkeG6t3QgcmEgbmjGsCBzYXU6KioNCg0KLSAgICoqSOKCgCoqOiBwID0gcOKCgA0KDQotICAgKipI4oKBKio6IHAg4omgIHDigoANCg0KIyMgKipHZW5kZXIgKGZlbWFsZSkqKg0KDQpgYGB7cn0NCiMgMSkgxJDhur9tIHPhu5Ega2jDoWNoIG7hu68NCmNvdW50X2ZlbWFsZSA8LSBzdW0oZHQkR2VuZGVyID09ICJGIikNCg0KIyAyKSDEkOG6t3QgSOKCgDogcF9GID0gMC41MDsgSOKCgTogcF9GIOKJoCAwLjUwDQpwMCA8LSAwLjUNCiMgMykgVGjhu7FjIGhp4buHbiBwcm9wLnRlc3QNCnJlc19mZW1hbGUgPC0gcHJvcC50ZXN0KHggICAgICAgICA9IGNvdW50X2ZlbWFsZSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG4gICAgICAgICA9IG4sDQogICAgICAgICAgICAgICAgICAgICAgICBwICAgICAgICAgPSBwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmYubGV2ZWw9IDAuOTUpDQpwcmludChyZXNfZmVtYWxlKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQqKg0KDQotICAgVGEgY8OzIHAtdmFsdWUgPSAwLjAxODIgXDwgzrEgPSAwLjA1LCBiw6FjIEjigoAgKHThu4kgbOG7hyBu4buvID0gMC41KSB2w6AgY2jhuqVwDQogICAgbmjhuq1uIEjigoE6IHThu4kgbOG7hyBu4buvIGtow6FjIDUwJSDhu58gbeG7qWMgw70gbmdoxKlhIDUlLg0KDQotICAgS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7iSBs4buHIG7hu68gbMOgIFswLjUwMTcsIDAuNTE4M10sIGtow7RuZyBjaOG7qWEgMC41LA0KICAgIGPhu6duZyBj4buRIHLhurFuZyB04buJIGzhu4cgbuG7ryB0aOG7sWMgc+G7sSBjYW8gaMahbiA1MCUuDQoNCi0gICDGr+G7m2MgdMOtbmggdOG7iSBs4buHIG7hu68gdHJvbmcgbeG6q3UgbMOgIHDMgiDiiYggMC41MSAoNTElKSwgbmdoxKlhIGzDoCB04buJIGzhu4cgbuG7rw0KICAgIHbGsOG7o3QgbmfGsOG7oW5nIDUwJSBraG/huqNuZyAxJS4NCg0KIyMgKipIb21lb3duZXIgKHllcykqKg0KDQpgYGB7cn0NCmNvdW50X293bmVyIDwtIHN1bShkdCRIb21lb3duZXIgPT0gIlkiKQ0KcDBfb3duZXIgICA8LSAwLjUwICAgIyBHaeG6oyB0aHV54bq/dCBI4oKAOiA1MCUgbMOgIGPDsyBz4buhIGjhu691IG5ow6ANCg0KcmVzX293bmVyIDwtIHByb3AudGVzdCh4ICAgICAgICAgPSBjb3VudF9vd25lciwNCiAgICAgICAgICAgICAgICAgICAgICAgbiAgICAgICAgID0gbiwNCiAgICAgICAgICAgICAgICAgICAgICAgcCAgICAgICAgID0gcDBfb3duZXIsDQogICAgICAgICAgICAgICAgICAgICAgIGNvbmYubGV2ZWw9IDAuOTUpDQpwcmludChyZXNfb3duZXIpDQpgYGANCg0KKipOaOG6rW4geMOpdCoqDQoNCi0gICBUYSBjw7MgcC12YWx1ZSBcPCAyLjJlLTE2IFw8IM6xID0gMC4wNSwgbsOqbiBiw6FjIGLhu48gSOKCgCAodOG7iSBs4buHIHPhu58gaOG7r3UNCiAgICBuaMOgID0gMC41KSB2w6AgY2jhuqVwIG5o4bqtbiBI4oKBOiB04buJIGzhu4cgY2jhu6cgc+G7nyBo4buvdSBraMOhYyA1MCUg4bufIG3hu6ljIMO9IG5naMSpYQ0KICAgIDUlLg0KDQotICAgS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7iSBs4buHIGNo4bunIHPhu58gaOG7r3UgbMOgIFswLjU5MjUsIDAuNjA4N10sIGtow7RuZw0KICAgIGJhbyBn4buTbSAwLjUsIGto4bqzbmcgxJHhu4tuaCB04buJIGzhu4cgY2jhu6cgc+G7nyBo4buvdSB0aOG7sWMgc+G7sSBjYW8gaMahbiA1MCUuDQoNCi0gICDGr+G7m2MgdMOtbmggdOG7iSBs4buHIGNo4bunIHPhu58gaOG7r3UgdHJvbmcgbeG6q3UgbMOgIHDMgiDiiYggMC42MDA2ICg2MC4wNiUpLCBuZ2jEqWEgbMOgDQogICAgdOG7iSBs4buHIGNo4bunIHPhu58gaOG7r3Ugdsaw4bujdCA1MCUga2hv4bqjbmcgMTAlLg0KDQojIyAqKlByb2R1Y3RGYW1pbHkgKGZvb2QpKioNCg0KYGBge3J9DQpjb3VudF9mb29kIDwtIHN1bShkdCRQcm9kdWN0RmFtaWx5ID09ICJGb29kIikNCnAwX2Zvb2QgICAgPC0gMC41MCAgICMgSOKCgDogNTAlIGdpYW8gZOG7i2NoIHRodeG7mWMgbmjDs20gRm9vZA0KDQpyZXNfZm9vZCA8LSBwcm9wLnRlc3QoeCAgICAgICAgID0gY291bnRfZm9vZCwNCiAgICAgICAgICAgICAgICAgICAgICBuICAgICAgICAgPSBuLA0KICAgICAgICAgICAgICAgICAgICAgIHAgICAgICAgICA9IHAwX2Zvb2QsDQogICAgICAgICAgICAgICAgICAgICAgY29uZi5sZXZlbD0gMC45NSkNCnByaW50KHJlc19mb29kKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQqKg0KDQotICAgVGEgY8OzIHAtdmFsdWUgXDwgMi4yZS0xNiBcPCDOsSA9IDAuMDUsIG7Dqm4gYsOhYyBi4buPIEjigoAgKHThu4kgbOG7hyBmb29kID0NCiAgICAwLjUpIHbDoCBjaOG6pXAgbmjhuq1uIEjigoE6IHThu4kgbOG7hyBmb29kIGtow6FjIDUwJSDhu58gbeG7qWMgw70gbmdoxKlhIDUlLg0KDQotICAgS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7iSBs4buHIGZvb2QgbMOgIFswLjcxNDcsIDAuNzI5NV0sIGtow7RuZyBiYW8gZ+G7k20NCiAgICAwLjUsIGto4bqzbmcgxJHhu4tuaCB04buJIGzhu4cgZm9vZCB0aOG7sWMgc+G7sSBjYW8gaMahbiA1MCUuDQoNCi0gICDGr+G7m2MgdMOtbmggdOG7iSBs4buHIGZvb2QgdHJvbmcgbeG6q3UgbMOgIHDMgiDiiYggMC43MjIyICg3Mi4yMiUpLCBuZ2jEqWEgbMOgIHThu4kgbOG7hw0KICAgIGZvb2Qgdsaw4bujdCBuZ8aw4buhbmcgNTAlIGtob+G6o25nIDIyJeKAlG3hu5l0IGNow6puaCBs4buHY2ggxJHDoW5nIGvhu4MgY+G6oyB24buBIHRo4buxYw0KICAgIHRp4buFbiB2w6AgdGjhu5FuZyBrw6ouDQoNCiMgKipQaOG6p24gNC4gUEjDgk4gVMONQ0ggTeG7kEkgUVVBTiBI4buGIEdJ4buuQSBIQUkgQknhur5OIMSQ4buKTkggVMONTkgqKg0KDQojIyAqKkdlbmRlciB2w6AgUHJvZHVjdEZhbWlseSoqDQoNCiMjIyAqKkLhuqNuZyB04bqnbiBz4buRIHbDoCB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCiMgQuG6o25nIGNow6lvIGNvdW50cw0KdGFiX2dmIDwtIHRhYmxlKEdlbmRlciA9IGR0JEdlbmRlciwgUHJvZHVjdEZhbWlseSA9IGR0JFByb2R1Y3RGYW1pbHkpDQp0YWJfZ2YNCg0KIyBU4buJIGzhu4cgdGhlbyBow6BuZyAocm934oCQJSkNCnBjdF9nZiA8LSByb3VuZChwcm9wLnRhYmxlKHRhYl9nZiwgbWFyZ2luID0gMSkgKiAxMDAsIDEpDQpwY3RfZ2YNCmBgYA0KDQoqKk5o4bqtbiB4w6l0KioNCg0KKioqRHJpbmsqKioNCg0KLSAgIFbhu4Egc+G7kSBsxrDhu6NuZzogbuG7ryBjw7MgNjY5IGdpYW8gZOG7i2NoIHNvIHbhu5tpIDU4MSBj4bunYSBuYW0sIG5oaeG7gXUgaMahbiA4OA0KICAgIGdpYW8gZOG7i2NoLg0KDQotICAgVuG7gSB04buJIGzhu4c6IG7hu68gY2hp4bq/bSA5LjMlIHThu5VuZyBnaWFvIGThu4tjaCBj4bunYSBtw6xuaCwgbmFtIGNoaeG6v20gOC40JSwNCiAgICBjaMOqbmggKzAuOSUuDQoNClbhuq15IHBo4bulIG7hu68gY8OzIHh1IGjGsOG7m25nIG11YSDEkeG7kyB14buRbmcgaMahaSBuaGnhu4F1IGjGoW4gbmFtLCBuaMawbmcgY2jDqm5oIGNoxrBhDQrEkeG6v24gMSUuDQoNCioqKkZvb2QqKioNCg0KLSAgIFbhu4Egc+G7kSBsxrDhu6NuZzogbuG7ryA1LjE0OSBnaWFvIGThu4tjaCwgbmFtIDUuMDA0LCBuaGnhu4F1IGjGoW4gMTQ1IGdpYW8gZOG7i2NoLg0KDQotICAgVuG7gSB04buJIGzhu4c6IG7hu68gNzEuOCUsIG5hbSA3Mi42JSwgY2jDqm5oIOKIkjAuOCUuDQoNClbhuq15IGTDuSBjw7Mgbmhp4buBdSBnaWFvIGThu4tjaCBGb29kIGjGoW4gduG7gSBjb24gc+G7kSB0dXnhu4d0IMSR4buRaSwgdsOsIHThu5VuZyBnaWFvDQpk4buLY2ggY+G7p2EgbuG7ryBjxaluZyBuaGnhu4F1IGjGoW4sIG7Dqm4gdOG7iSBs4buHIGzhuqFpIHRo4bqlcCBoxqFuIG5hbSBt4buZdCBjaMO6dC4NCg0KKioqTm9uLUNvbnN1bWFibGUqKioNCg0KLSAgIFbhu4Egc+G7kSBsxrDhu6NuZzogbuG7ryAxLjM1MiBnaWFvIGThu4tjaCwgbmFtIDEuMzA0LCBuaGnhu4F1IGjGoW4gNDggZ2lhbyBk4buLY2guDQoNCi0gICBW4buBIHThu4kgbOG7hzogY+G6oyBoYWkgxJHhu4F1IDE4LjklLCBjaMOqbmggMC4wJS4NCg0KduG6rXkgc+G7sSBraMOhYyBiaeG7h3QgdGjhuq10IHPhu7EgcuG6pXQgbmjhu48sIHThu4kgbOG7hyBuZ2FuZyBi4bqxbmcuDQoNCiMjIyAqKsSQ4buTIHRo4buLKioNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpnZl9kZiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKEdlbmRlciA9IGR0JEdlbmRlciwgUHJvZHVjdEZhbWlseSA9IGR0JFByb2R1Y3RGYW1pbHkpKQ0KDQpnZ3Bsb3QoICBnZl9kZiwgYWVzKHggICAgID0gUHJvZHVjdEZhbWlseSx5ICAgICA9IEZyZXEsIGZpbGwgID0gR2VuZGVyLCBncm91cCA9IEdlbmRlcikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksICB3aWR0aCAgICA9IDAuNykgKw0KICBzY2FsZV9maWxsX21hbnVhbCgNCiAgICBuYW1lICAgPSAiR2nhu5tpIHTDrW5oIiwNCiAgICB2YWx1ZXMgPSBjKCJGIiA9ICJsaWdodGdyZWVuIiwgIk0iID0gInllbGxvdyIpLA0KICAgIGxhYmVscyA9IGMoIk7hu68iLCAiTmFtIikNCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU+G7kSBnaWFvIGThu4tjaCB0aGVvIHPhuqNuIHBo4bqpbSAmIGdp4bubaSB0w61uaCIsDQogICAgeCAgICAgPSAiTmjDs20gc+G6o24gcGjhuqltIiwNCiAgICB5ICAgICA9ICJT4buRIGdpYW8gZOG7i2NoIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMjICoqS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nIMSR4buZYyBs4bqtcCoqDQoNCioqR2nhuqMgdGh1eeG6v3Qga2nhu4NtIMSR4buLbmg6KioNCg0KLSAgICoqSOKCgCoqOiBHaeG7m2kgdsOgIG5ow7NtIHPhuqNuIHBo4bqpbWzDoCBoYWkgYmnhur9uIMSR4buZYyBs4bqtcC4NCg0KLSAgICoqSOKCgSoqOiBHaeG7m2kgdsOgIG5ow7NtIHPhuqNuIHBo4bqpbSBjw7MgbGnDqm4gcXVhbi4NCg0KYGBge3J9DQp0ZXN0X2dmIDwtIGNoaXNxLnRlc3QodGFiX2dmKQ0KdGVzdF9nZg0KYGBgDQoNCioqTmjhuq1uIHjDqXQqKg0KDQotICAgcC12YWx1ZSA9IDAuMTcyMiBcPiAwLjA1IHbhuq15IGNo4bqlcCBuaOG6rW4gSOKCgCBuZ2jEqWEgbMOgIGtow7RuZyDEkeG7pyBi4bqxbmcNCiAgICBjaOG7qW5nIMSR4buDIGNobyBy4bqxbmcgZ2nhu5tpIHTDrW5oIOG6o25oIGjGsOG7n25nIMSRw6FuZyBr4buDIMSR4bq/biBuaMOzbSBz4bqjbiBwaOG6qW0gbXVhLg0KDQojIyAqKk1hcml0YWxTdGF0dXMgdsOgIEhvbWVvd25lcioqDQoNCiMjIyAqKkLhuqNuZyB04bqnbiBz4buRIHbDoCB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCnRhYl9tbyA8LSB0YWJsZShNYXJpdGFsID0gZHQkTWFyaXRhbFN0YXR1cywgT3duZXIgPSBkdCRIb21lb3duZXIpDQp0YWJfbW8NCg0KcGN0X21vIDwtIHJvdW5kKHByb3AudGFibGUodGFiX21vLCBtYXJnaW4gPSAxKSAqIDEwMCwgMSkNCnBjdF9tbw0KYGBgDQoNCmBgYHtyfQ0KIyBHaeG6oyBz4butIHRhYl9tbyDEkcOjIMSRxrDhu6NjIHThuqFvIG5oxrAgdHLDqm4NCmRpZmZfb3duZXJfY291bnQgICAgIDwtIHRhYl9tb1siTSIsICJZIl0gLSB0YWJfbW9bIlMiLCAiWSJdDQpkaWZmX25vdF9vd25lcl9jb3VudCA8LSB0YWJfbW9bIlMiLCAiTiJdIC0gdGFiX21vWyJNIiwgIk4iXQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQqKg0KDQotICAgVHJvbmcgYuG7mSBk4buvIGxp4buHdSwgY8OzIGByIHRhYl9tb1siUyIsICJOIl1gIG5nxrDhu51pIMSR4buZYyB0aMOibiBraMO0bmcgc+G7nw0KICAgIGjhu691IG5ow6AgdsOgIGByIHRhYl9tb1siUyIsICJZIl1gIG5nxrDhu51pIMSR4buZYyB0aMOibiBz4bufIGjhu691IG5ow6AuIE5nb8OgaSByYSwNCiAgICBjw7MgYHIgdGFiX21vWyJNIiwgIk4iXWAgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIGtow7RuZyBz4bufIGjhu691IG5ow6AgdsOgDQogICAgYHIgdGFiX21vWyJNIiwgIlkiXWAgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIHPhu58gaOG7r3UgbmjDoC4NCg0KLSAgIFPhu5EgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIHPhu58gaOG7r3UgbmjDoCBuaGnhu4F1IGjGoW4gbmfGsOG7nWkgxJHhu5ljIHRow6JuIGzDoA0KICAgIGByIGRpZmZfb3duZXJfY291bnRgIG5nxrDhu51pLg0KDQotICAgTmfGsOG7nWkgxJHhu5ljIHRow6JuIGtow7RuZyBz4bufIGjhu691IG5ow6Agbmhp4buBdSBoxqFuIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biBsw6ANCiAgICBgciBhYnMoZGlmZl9ub3Rfb3duZXJfY291bnQpYCBuZ8aw4budaS4NCg0KIyMjICoqxJDhu5MgdGhpKioNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQptb19kZiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKE1hcml0YWwgPSBkdCRNYXJpdGFsU3RhdHVzLCBPd25lciAgID0gZHQkSG9tZW93bmVyKSkNCg0KZ2dwbG90KCAgbW9fZGYsIGFlcyh4ICAgICA9IE1hcml0YWwseSAgICAgPSBGcmVxLCBmaWxsICA9IE93bmVyLCBncm91cCA9IE93bmVyKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgIHdpZHRoICAgID0gMC43KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKA0KICAgIG5hbWUgICA9ICJT4bufIGjhu691IG5ow6AiLA0KICAgIHZhbHVlcyA9IGMoIlkiID0gImxpZ2h0Ymx1ZSIsIk4iID0gImxpZ2h0cGluayIpLA0KICAgIGxhYmVscyA9IGMoIkPDsyIsICJLaMO0bmciKQ0KICApICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJT4buRIGtow6FjaCBjw7Mva2jDtG5nIHPhu58gaOG7r3UgbmjDoCB0aGVvIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiIsDQogICAgeCAgICAgPSAiVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIiwNCiAgICB5ICAgICA9ICJT4buRIGtow6FjaCBow6BuZyINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCiMjIyAqKktp4buDbSDEkeG7i25oIENoaS1iw6xuaCBwaMawxqFuZyDEkeG7mWMgbOG6rXAqKg0KDQoqKkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oOioqDQoNCi0gICAqKkjigoAqKjogVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIHbDoCB2aeG7h2Mgc+G7nyBo4buvdSBuaMOgIGzDoCBoYWkgYmnhur9uIMSR4buZYyBs4bqtcC4NCg0KLSAgICoqSOKCgSoqOiBUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gdsOgIHZp4buHYyBz4bufIGjhu691IG5ow6AgY8OzIGxpw6puIHF1YW4uDQoNCmBgYHtyfQ0KdGVzdF9tbyA8LSBjaGlzcS50ZXN0KHRhYl9tbykNCnRlc3RfbW8NCmBgYA0KDQoqKk5o4bqtbiB4w6l0KioNCg0KLSAgIHAtdmFsdWUgXDwgMi4yZS0xNiBcPCAwLjA1IHbhuq15IGLDoWMgYuG7jyBI4oKAIG5naMSpYSBsw6AgxJHhu6cgYuG6sW5nIGNo4bupbmcgxJHhu4MNCiAgICBjaG8gcuG6sW5nIFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiB2w6Agdmnhu4djIHPhu58gaOG7r3UgbmjDoCBjw7MgbGnDqm4gcXVhbi4NCg0KIyMgKipBbm51YWxJbmNvbWUgdsOgIFByb2R1Y3RDYXRlZ29yeSoqDQoNCiMjIyAqKkLhuqNuZyB04bqnbiBz4buRIHbDoCB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCnRhYl9hcCA8LSB0YWJsZShJbmNvbWUgPSBkdCRBbm51YWxJbmNvbWUsIENhdGVnb3J5ID0gZHQkUHJvZHVjdENhdGVnb3J5KQ0KdGFiX2FwDQoNCnBjdF9hcCA8LSByb3VuZChwcm9wLnRhYmxlKHRhYl9hcCwgbWFyZ2luID0gMSkgKiAxMDAsIDEpDQpwY3RfYXANCmBgYA0KDQoqKk5o4bqtbiB4w6l0KioNCg0KLSAgIE5ow7NtIHRodSBuaOG6rXAgdOG7qyBgIiQzMEsgLSAkNTBLImAgZ2hpIG5o4bqtbiBz4buRIGdpYW8gZOG7i2NoIGNhbyBuaOG6pXQg4bufDQogICAgaOG6p3UgaOG6v3QgY8OhYyBkYW5oIG3hu6VjLCB2w60gZOG7pToNCg0KICAgIC0gICBTbmFjayBGb29kczogYHIgdGFiX2FwWyIkMzBLIC0gJDUwSyIsICJTbmFjayBGb29kcyJdYCBnaWFvIGThu4tjaC4NCiAgICAtICAgVmVnZXRhYmxlczogYHIgdGFiX2FwWyIkMzBLIC0gJDUwSyIsICJWZWdldGFibGVzIl1gIGdpYW8gZOG7i2NoLg0KICAgIC0gICBEYWlyeTogYHIgdGFiX2FwWyIkMzBLIC0gJDUwSyIsICJEYWlyeSJdYCBnaWFvIGThu4tjaC4NCg0KICAgIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgbMOgIGRvIG5ow7NtIHRodSBuaOG6rXAgdHJ1bmcgbMawdSBjw7Mga2jhuqMgbsSDbmcgY2hpIHRpw6p1DQogICAgY2FvIG5oxrBuZyB24bqrbiDGsHUgdGnDqm4gY8OhYyBt4bq3dCBow6BuZyB0aGnhur90IHnhur91Lg0KDQotICAgTmjDs20gdGh1IG5o4bqtcCB0aOG6pXAgKGAiJDEwSyAtICQzMEsiYCkgY8WpbmcgY8OzIGzGsOG7o25nIGdpYW8gZOG7i2NoIHTGsMahbmcNCiAgICDEkeG7kWkgbOG7m24sIMSR4bq3YyBiaeG7h3Qg4bufOg0KDQogICAgLSAgIFZlZ2V0YWJsZXM6IGByIHRhYl9hcFsiJDEwSyAtICQzMEsiLCAiVmVnZXRhYmxlcyJdYCBnaWFvIGThu4tjaC4NCiAgICAtICAgU25hY2sgRm9vZHM6IGByIHRhYl9hcFsiJDEwSyAtICQzMEsiLCAiU25hY2sgRm9vZHMiXWAgZ2lhbyBk4buLY2guDQoNCiAgICDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBuaHUgY+G6p3UgduG7m2kgc+G6o24gcGjhuqltIGPGoSBi4bqjbiwgZ2nDoSBj4bqjIHBo4bqjaSBjaMSDbmcgduG6q24NCiAgICBy4bqldCBjYW8uDQoNCi0gICBOZ8aw4bujYyBs4bqhaSwgbmjDs20gdGh1IG5o4bqtcCBjYW8gKGAiJDEzMEsgLSAkMTUwSyJgLCBgIiQxNTBLICsiYCkgY8OzIHPhu5ENCiAgICBnaWFvIGThu4tjaCB0aOG6pXAgaMahbiByw7UgcuG7h3QsIHbDrSBk4bulOg0KDQogICAgLSAgIFNuYWNrIEZvb2RzOiBgciB0YWJfYXBbIiQxNTBLICsiLCAiU25hY2sgRm9vZHMiXWAgZ2lhbyBk4buLY2guDQogICAgLSAgIFZlZ2V0YWJsZXM6IGByIHRhYl9hcFsiJDE1MEsgKyIsICJWZWdldGFibGVzIl1gIGdpYW8gZOG7i2NoLg0KDQogICAgQ8OzIHRo4buDIGRvIHPhu5EgbeG6q3UgbmjDs20gdGh1IG5o4bqtcCBjYW8gw610IGjGoW4gaG/hurdjIGjhu40gxrB1IHRpw6puIG11YSBz4bqvbQ0KICAgIG9ubGluZSwgc+G6o24gcGjhuqltIGNhbyBj4bqlcCBoxqFuLg0KDQojIyMgKipLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcgxJHhu5ljIGzhuq1wKioNCg0KKipHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaDoqKg0KDQotICAgKipI4oKAKio6IEhhaSBiaeG6v24ga2hv4bqjbmcgdGh1IG5o4bqtcCBo4bqxbmcgbsSDbSB2w6AgaOG6oW5nIG3hu6VjIHPhuqNuIHBo4bqpbSBsw6ANCiAgICDEkeG7mWMgbOG6rXAuDQoNCi0gICAqKkjigoEqKjogSGFpIGJp4bq/biBraG/huqNuZyB0aHUgbmjhuq1wIGjhurFuZyBuxINtIHbDoCBo4bqhbmcgbeG7pWMgc+G6o24gcGjhuqltIGPDsw0KICAgIG3hu5FpIGxpw6puIHF1YW4uDQoNCmBgYHtyfQ0KdGVzdF9zcCA8LSBjaGlzcS50ZXN0KHRhYl9hcCkNCnRlc3Rfc3ANCmBgYA0KDQoqKk5o4bqtbiB4w6l0KioNCg0KLSAgIHAtdmFsdWUgPSAwLjY4OTcgXD4gMC4wNSB24bqteSBjaOG6pXAgbmjhuq1uIEjigoAgbmdoxKlhIGzDoCBraMO0bmcgxJHhu6cgYuG6sW5nDQogICAgY2jhu6luZyDEkeG7gyBjaG8gcuG6sW5nIEhhaSBiaeG6v24ga2hv4bqjbmcgdGh1IG5o4bqtcCBo4bqxbmcgbsSDbSB2w6AgaOG6oW5nIG3hu6VjIHPhuqNuDQogICAgcGjhuqltIGzDoCDEkeG7mWMgbOG6rXAuDQoNCiMgKipQaOG6p24gNTogVOG7lE5HIEvhur5UIFbDgCBUSOG6ok8gTFXhuqxOKioNCg0KIyMgKipUw7NtIHThuq90IGvhur90IHF14bqjIGNow61uaCoqDQoNCiMjIyAqKk5ow6JuIGto4bqpdSBo4buNYyoqDQoNCi0gICAqKkdp4bubaSB0w61uaCoqOg0KICAgIC0gICBO4buvIGNoaeG6v20gNTElLCBuYW0gY2hp4bq/bSA0OSXigJR0xrDGoW5nIMSR4buRaSBjw6JuIGLhurFuZy5cDQogICAgLSAgIEjDoG5oIHZpIG11YSBz4bqvbSB0xrDGoW5nIMSR4buTbmcsIGNo4buJIGtow6FjIGJp4buHdCBuaOG7jyDhu58gbeG7mXQgc+G7kSBkYW5oIG3hu6VjDQogICAgICAgICh2w60gZOG7pTogV29tZW7igJlzIEhlYWx0aCwgQmVhdXR5KS4NCi0gICAqKlTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiAmIE5ow6Ag4bufKio6DQogICAgLSAgIE5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biAoTSkgdsOgIMSR4buZYyB0aMOibiAoUykgcGjDom4gYuG7kSBn4bqnbiBi4bqxbmcgbmhhdS5cDQogICAgLSAgIDYwJSBraMOhY2ggaMOgbmcgc+G7nyBo4buvdSBuaMOgIChIb21lb3duZXIgPSBZKS5cDQogICAgLSAgIE5nxrDhu51pIGvhur90IGjDtG4gY8OzIHThu4kgbOG7hyBz4bufIGjhu691IG5ow6AgY2FvIGjGoW4gKDc1JSB2cy4gNDYlKSwgdGjhu4MNCiAgICAgICAgaGnhu4duIHPhu7Eg4buVbiDEkeG7i25oIHTDoGkgY2jDrW5oIHbDoCBuaHUgY+G6p3UgbXVhIHPhuq9tIGNobyBnaWEgxJHDrG5oLg0KDQojIyMgKipUaHUgbmjhuq1wKioNCg0KLSAgIE5ow7NtICoqXCQzMEvigJNcJDUwSyoqIGNoaeG6v20gxJHDtG5nIG5o4bqldCAoMzIsNyUpLCBwaOG6o24gw6FuaCB04bqnbmcgbOG7m3ANCiAgICB0cnVuZyBsxrB1LlwNCi0gICBOaMOzbSB0aHUgbmjhuq1wIHRo4bqlcCAoXCQxMEvigJNcJDMwSykgdsOgIHRydW5nIGLDrG5o4oCTY2FvIChcJDUwS+KAk1wkOTBLKQ0KICAgIGPFqW5nIGNoaeG6v20gdOG7tyB0cuG7jW5nIGzhu5tuIChcfjI1JSBt4buXaSBuaMOzbSkuXA0KLSAgIE5ow7NtICoqXD4gXCQxNTBLKiogY2jhu4kgXH4yJSwgbeG6q3Ugbmjhu48gbmjGsG5nIGPDsyB4dSBoxrDhu5tuZyB0acOqdSBkw7luZyBz4bqjbg0KICAgIHBo4bqpbSBjYW8gY+G6pXAsIGThu4tjaCB24bulIHRp4buHbiBs4bujaS4NCg0KIyMjICoqUGjDom4gYuG7kSDEkeG7i2EgbMO9KioNCg0KLSAgICoqUXXhu5FjIGdpYSoqOiA2OCUgZ2lhbyBk4buLY2ggdOG7qyBN4bu5OyBjw7JuIGzhuqFpIHThu6sgQ2FuYWRhLCBNZXhpY28uXA0KLSAgICoqQmFuZyoqOiBXQSwgQ0EsIE9SIGNoaeG6v20gcGjhuqduIGzhu5tu4oCUdMawxqFuZyDhu6luZyB24bubaSBjw6FjIHRow6BuaCBwaOG7kQ0KICAgIFNhbGVtLCBUYWNvbWEsIExvcyBBbmdlbGVzIMSR4bupbmcgxJHhuqd1IHbhu4Egc+G7kSBsxrDhu6NuZyBnaWFvIGThu4tjaC5cDQotICAgKipUaMOgbmggcGjhu5EqKjogU2FsZW0gKFx+MTAlIGdpYW8gZOG7i2NoKSwgVGFjb21hIChcfjklKSwgTG9zIEFuZ2VsZXMNCiAgICAoXH42JSkuDQoNCiMjIyAqKkjDoG5oIHZpIHRoZW8gc+G6o24gcGjhuqltKioNCg0KLSAgICoqUHJvZHVjdEZhbWlseSoqOg0KICAgIC0gICBGb29kICg3MiwyJSksIE5vbi1jb25zdW1hYmxlICgxOSUpLCBEcmluayAoOSUpLlwNCi0gICAqKlByb2R1Y3REZXBhcnRtZW50Kio6DQogICAgLSAgIFByb2R1Y2UgKDEyLDMlKSwgU25hY2sgRm9vZHMgKDExLDQlKSwgRGFpcnkgKDYsNCUpLCBGcm96ZW4gRm9vZHMNCiAgICAgICAgKDksOCUpLlwNCi0gICAqKlByb2R1Y3RDYXRlZ29yeSoqOg0KICAgIC0gICBOaMOzbSByYXUgY+G7pyB0xrDGoWkgdsOgIMSR4buTIMSDbiBuaGFuaCDEkeG7qW5nIMSR4bqndSDhu58gaOG6p3UgaOG6v3QgY8OhYyBwaMOibiBraMO6Yw0KICAgICAgICB0aHUgbmjhuq1wLlwNCiAgICAtICAgTmjDs20gdGh1IG5o4bqtcCB0aOG6pXDigJN0cnVuZyBiw6xuaCDGsHUgdGnDqm4gY8OhYyBt4bq3dCBow6BuZyB0aGnhur90IHnhur91LA0KICAgICAgICBnacOhIGPhuqMgcGjhuqNpIGNoxINuZzsgdGh1IG5o4bqtcCBjYW8gbXVhIG5oaeG7gXUgc25hY2ssIGZyb3plbiB2w6Agc+G6o24NCiAgICAgICAgcGjhuqltIGNoxINtIHPDs2Mgc+G7qWMga2jhu49lLg0KDQojIyAqKkjhuqFuIGNo4bq/KioNCg0KMS4gICoqVGhp4bq/dSBiaeG6v24gxJHhu4tuaCBsxrDhu6NuZyoqOiBraMO0bmcgcGjDom4gdMOtY2ggc8OidSB24buBIHR14buVaSwgZ2nDoSB0cuG7iyDEkcahbg0KICAgIGjDoG5nLCB04bqnbiBzdeG6pXQgbXVhLlwNCjIuICAqKk3huqt1IGtow7RuZyDEkeG7k25nIMSR4buBdSoqOiBuaMOzbSB0aHUgbmjhuq1wIHLhuqV0IGNhbyB2w6AgY8OhYyB0aMOgbmggcGjhu5Egbmjhu48NCiAgICBjw7Mgw610IHF1YW4gc8OhdCwgZ2nhuqNtIHTDrW5oIMSR4bqhaSBkaeG7h24uXA0KMy4gICoqVMawxqFuZyBxdWFuIGNow6lvKio6IGNoxrBhIMSRaeG7gXUgY2jhu4luaCBt4buRaSBsacOqbiBo4buHIGdp4buvYSB0aHUgbmjhuq1wLCBuaMOgDQogICAg4bufLCDEkeG7i2EgbMO9LlwNCjQuICAqKkdp4bubaSB0w61uaCAmIHbEg24gaMOzYSoqOiBjaMawYSBraGFpIHRow6FjIGtow6FjIGJp4buHdCBjaGkgdGnhur90IGdp4buvYQ0KICAgIG5hbS9u4buvIGhv4bq3YyB0aGVvIHbDuW5nIG1p4buBbi4NCg0KIyMgKirEkOG7gSB4deG6pXQgY2hp4bq/biBsxrDhu6NjKioNCg0KLSAgICoqUGjDom4ga2jDumMgJiBNYXJrZXRpbmcqKg0KICAgIC0gICBOaMOzbSBcJDMwS+KAk1wkNzBLOiBjaMO6IHRy4buNbmcgY29tYm8gcmF1IGPhu6cgdMawxqFpLCBz4buvYSwgdGjhu7FjIHBo4bqpbQ0KICAgICAgICDEkcO0bmcgbOG6oW5oOyDGsHUgxJHDo2kgdGhlbyBnw7NpLlwNCiAgICAtICAgTmjDs20gxJHDoyBr4bq/dCBow7RuICYgY8OzIG5ow6A6IMawdSDEkcOjaSDEkeG7kyBnaWEgZOG7pW5nLCBnw7NpIGdpYW8gaMOgbmcgxJHhu4tuaA0KICAgICAgICBr4buzLlwNCi0gICAqKkvDqm5oIHBow6JuIHBo4buRaSoqDQogICAgLSAgIE3hu58gcuG7mW5nIHThuqFpIFNhbGVtLCBUYWNvbWEsIExvcyBBbmdlbGVzOyB04buRaSDGsHUga+G7hyBow6BuZyBjaG8NCiAgICAgICAgUHJvZHVjZSwgU25hY2sgRm9vZHMsIERhaXJ5LlwNCiAgICAtICAgWGVtIHjDqXQgZ2nhuqNtIGRp4buHbiB0w61jaCB24bubaSBkYW5oIG3hu6VjIMOtdCBiw6FuICh2w60gZOG7pSBDYW5uZWQNCiAgICAgICAgT3lzdGVycywgQ2FuZGxlcykuXA0KLSAgICoqQ8O0bmcgbmdo4buHICYgQ8OhIG5ow6JuIGjDs2EqKg0KICAgIC0gICBEw7luZyBDUk0gdGh1IHRo4bqtcCB0aMOqbSBk4buvIGxp4buHdSDEkeG7i25oIGzGsOG7o25nLCBwaMOibiB0w61jaCBow6BuaCB2aQ0KICAgICAgICB0aGVvIHRo4budaSBnaWFuIHRo4buxYzsgZ+G7o2kgw70gc+G6o24gcGjhuqltIHThu7EgxJHhu5luZy4NCg0KIyMgKipIxrDhu5tuZyBuZ2hpw6puIGPhu6l1IHRp4bq/cCB0aGVvKioNCg0KMS4gIFNvIHPDoW5oIOKAnHRodSBuaOG6rXAgY2FvICsgxJHhu5ljIHRow6JuICsgY8OzIG5ow6DigJ0gdnMuIOKAnHRodSBuaOG6rXAgY2FvICsgxJHDow0KICAgIGvhur90IGjDtG7igJ0gduG7gSBow6BuaCB2aSBtdWEgc+G6r20uXA0KMi4gIOG6om5oIGjGsOG7n25nIGPhu6dhIHR14buVaSBr4bq/dCBo4bujcCB24bubaSBow7RuIG5ow6JuIHbDoCB0aHUgbmjhuq1wIMSR4bq/biBs4buxYSBjaOG7jW4gc+G6o24NCiAgICBwaOG6qW0uXA0KMy4gIFPhu7Ega2jDoWMgYmnhu4d0IHRpw6p1IGTDuW5nIHRp4buHbiBs4bujaSAoRnJvemVuLCBTbmFjaykgZ2nhu69hIMSRw7QgdGjhu4sg4oCTIG7DtG5nDQogICAgdGjDtG4uXA0KNC4gIEtow6FjaCBuw6BvIGNoaSBt4bqhbmggY2hvIE5vbi1jb25zdW1hYmxlP1wNCjUuICBQaMOibiB0w61jaCB04bu3IHRy4buNbmcgY2hpIHRpw6p1IGNoaSB0aeG6v3QgdGhlbyB04burbmcgbeG7qWMgdGh1IG5o4bqtcCB2w6AgZGFuaA0KICAgIG3hu6VjIHPhuqNuIHBo4bqpbS4NCg0KIyAqKkE6IMSQ4buMQyBWw4AgQ0hV4bqoTiBC4buKIFRSxq/hu5pDIEJV4buUSSBI4buMQyoqDQoNCiMjICoqR2nhu5tpIHRoaeG7h3UgY2h1bmcqKg0KDQpUdeG6p24gbsOgeSwgY2jDum5nIHRhIMSRaSBzw6J1IHbDoG8gc3V5IGRp4buFbiB0aOG7kW5nIGvDqiB0csOqbiBi4bqjbmcgbmfhuqt1IG5oacOqbg0KKENvbnRpbmdlbmN5IFRhYmxlKSwgxJHhurdjIGJp4buHdCB04bqtcCB0cnVuZyB2w6BvOg0KDQotICAgS2nhu4NtIMSR4buLbmggQ2hpLXNxdWFyZSB24buBIHTDrW5oIMSR4buZYyBs4bqtcCBnaeG7r2EgaGFpIGJp4bq/biBwaMOibiBsb+G6oWkuDQotICAgQ8OhYyBjaOG7iSBz4buRIMSRbyBsxrDhu51uZyBt4buRaSBsacOqbiBo4buHIHRyb25nIGLhuqNuZyAyeDI6ICoqUmVsYXRpdmUgUmlzaw0KICAgIChSUikqKiB2w6AgKipPZGRzIFJhdGlvIChPUikqKi4NCi0gICBDw6FjaCB0w61uaCBraG/huqNuZyB0aW4gY+G6rXkgY2hvIE9kZHMgUmF0aW8uDQotICAg4buobmcgZOG7pW5nIGPDoWMga2nhur9uIHRo4bupYyB0csOqbiB2w6BvIG3hu5l0IHbDrSBk4bulIHRo4buxYyB04bq/IHThu6sgYuG7mSBk4buvIGxp4buHdQ0KICAgICoqU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zKiouDQoNCioqxJDhu41jIGThu68gbGnhu4d1IHbDoCBraMOhbSBwaMOhKioNCg0KYGBge3J9DQpsaWJyYXJ5KCJjc3YiKQ0KZGF0YSA8LSByZWFkLmNzdigiQzovVXNlcnMvQVNVUy9Eb3dubG9hZHMvU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zLmNzdiIsIGhlYWRlciA9IFQpDQpzdHIoZGF0YSkNCmBgYA0KDQrEkOG6p3UgdGnDqm4sIHRhIHPhur0gc+G7rSBk4bulbmcgMiBiaeG6v24gxJHhu4tuaCB0w61uaDogKipHZW5kZXIqKiAoR2nhu5tpIHTDrW5oKSB2w6ANCioqSG9tZW93bmVyKiogKEPDsyBz4bufIGjhu691IG5ow6AgaGF5IGtow7RuZykgxJHhu4MgdGnhur9uIGjDoG5oIMSRxrBhIHJhIHbDrSBk4bulIGPFqW5nDQpuaMawIHBow6JuIHTDrWNoLg0KDQojIyAqKkLhuqNuZyBuZ+G6q3Ugbmhpw6puKioNCg0KQuG6o25nIG5n4bqrdSBuaGnDqm4gKGNvbnRpbmdlbmN5IHRhYmxlKSBsw6AgY8O0bmcgY+G7pSB0aOG7kW5nIGvDqiBkw7luZyDEkeG7gyB0csOsbmgNCmLDoHkgdOG6p24gc+G7kSBj4bunYSBjw6FjIGJp4bq/biBwaMOibiBsb+G6oWkuIFRyb25nIHRyxrDhu51uZyBo4bujcCDEkcahbiBnaeG6o24gbmjhuqV0IOKAkyBi4bqjbmcNCjJ4MiDigJMgYuG6o25nIGPDsyBk4bqhbmc6DQoNCnwgICAgICAgICAgICAgICAgICB8IEJp4bq/biBCID0gWWVzIHwgQmnhur9uIEIgPSBObyB8DQp8LS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18DQp8ICoqQmnhur9uIEEgPSBZZXMqKiB8IGEgICAgICAgICAgICB8IGIgICAgICAgICAgIHwNCnwgKipCaeG6v24gQSA9IE5vKiogIHwgYyAgICAgICAgICAgIHwgZCAgICAgICAgICAgfA0KDQpUcm9uZyBwaMOibiB0w61jaCB0aOG7kW5nIGvDqiwgYuG6o25nIDJ4MiB0aMaw4budbmcgZMO5bmcgxJHhu4M6DQoNCi0gICBTbyBzw6FuaCB4w6FjIHN14bqldCBnaeG7r2EgaGFpIG5ow7NtIChuaMawIE5hbSB2cyBO4buvKS4NCi0gICBUw61uaCB0b8OhbiBjw6FjIGNo4buJIHPhu5EgxJFvIGzGsOG7nW5nIG3hu5FpIGxpw6puIGjhu4c6IFJpc2ssIE9kZHMsIFJlbGF0aXZlIFJpc2sNCiAgICAoUlIpLCBPZGRzIFJhdGlvIChPUikuDQotICAgS2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3QgduG7gSBz4buxIMSR4buZYyBs4bqtcCBnaeG7r2EgaGFpIGJp4bq/biAoQ2hpLXNxdWFyZSB0ZXN0LA0KICAgIEZpc2hlcuKAmXMgRXhhY3QgVGVzdCwuLi4pLg0KDQpC4bqjbmcgY8OzIHRo4buDIHNpbmggcmEgdOG7qyBjw6FjIHBow6JuIHBo4buRaSBuaMawOg0KDQotICAgKipNdWx0aW5vbWlhbCoqOiBu4bq/dSB04buVbmcgc+G7kSBxdWFuIHPDoXQgY+G7kSDEkeG7i25oLg0KLSAgICoqUG9pc3NvbioqOiBu4bq/dSB04burbmcgw7QgdHJvbmcgYuG6o25nIGzDoCBiaeG6v24gUG9pc3NvbiDEkeG7mWMgbOG6rXAgKMOhcCBk4bulbmcNCiAgICBraGkgZOG7ryBsaeG7h3UgaGnhur9tKS4NCg0KKipDw6FjIGLGsOG7m2MgdGjhu7FjIGhp4buHbiB0cm9uZyBSKioNCg0KYGBge3J9DQp0YWJsZV9nZW5kZXJfaG9tZW93bmVyIDwtIHRhYmxlKGRhdGEkR2VuZGVyLCBkYXRhJEhvbWVvd25lcikNCnRhYmxlX2dlbmRlcl9ob21lb3duZXINCmBgYA0KDQojIyAqKktp4buDbSDEkeG7i25oIENoaS1zcXVhcmUgduG7gSB0w61uaCDEkeG7mWMgbOG6rXAqKg0KDQoqKkzDvSB0aHV54bq/dDogS2nhu4NtIMSR4buLbmggQ2hpLXNxdWFyZSoqDQoNCkTDuW5nIMSR4buDIGtp4buDbSB0cmEgeGVtIGhhaSBiaeG6v24gcGjDom4gbG/huqFpIGPDsyDEkeG7mWMgbOG6rXAgdGjhu5FuZyBrw6oga2jDtG5nLg0KDQotICAgKipHaeG6oyB0aHV54bq/dCBI4oKAKio6IEhhaSBiaeG6v24gxJHhu5ljIGzhuq1wLg0KLSAgICoqR2nhuqMgdGh1eeG6v3QgSOKCgSoqOiBIYWkgYmnhur9uIGPDsyBt4buRaSBsacOqbiBo4buHLg0KDQpDaOG7iSBz4buRIGtp4buDbSDEkeG7i25oOiAkJA0KWF4yID0gXHN1bSBcZnJhY3soT197aWp9IC0gRV97aWp9KV4yfXtFX3tpan19DQokJA0KDQpUcm9uZyDEkcOzOg0KDQotICAgJE9fe2lqfSQgbMOgIHThuqduIHPhu5EgcXVhbiBzw6F0DQotICAgJEVfe2lqfSQgbMOgIHThuqduIHPhu5Ega+G7syB24buNbmcuDQoNCk7hur91IHAtdmFsdWUgXDwgMC4wNSwgdGEgY8OzIMSR4bunIGPGoSBz4bufIMSR4buDIGLDoWMgYuG7jyBI4oKAIOKGkiBDw7MgYuG6sW5nIGNo4bupbmcgduG7gSBz4buxDQpwaOG7pSB0aHXhu5ljIGdp4buvYSBoYWkgYmnhur9uLg0KDQoqKkPDoWMgYsaw4bubYyB0aOG7sWMgaGnhu4duIHRyb25nIFIqKg0KDQpgYGB7cn0NCmNoaXNxLnRlc3QodGFibGVfZ2VuZGVyX2hvbWVvd25lciwgY29ycmVjdCA9IEZBTFNFKQ0KYGBgDQoNCiMjICoqVMOtbmggT2RkcyBSYXRpbywgUmVsYXRpdmUgUmlzayoqDQoNCiMjIyAqKlThu7cgc+G7kSBuZ3V5IGPGoSAoUmVsYXRpdmUgUmlzayAtIFJSKSoqDQoNCioqS2jDoWkgbmnhu4dtOioqIFJlbGF0aXZlIFJpc2sgKFJSKSBsw6AgdOG7tyBs4buHIGdp4buvYSB4w6FjIHN14bqldCB44bqjeSByYSBz4buxIGtp4buHbg0K4bufIG5ow7NtIHRp4bq/cCB4w7pjIHNvIHbhu5tpIG5ow7NtIGtow7RuZyB0aeG6v3AgeMO6Yy4NCg0KKipDw7RuZyB0aOG7qWM6KioNCg0KJCQNClJSID0gXGZyYWN7XGZyYWN7YX17YStifX17XGZyYWN7Y317YytkfX0NCiQkDQoNCioqRGnhu4VuIGdp4bqjaToqKg0KDQotICAgUlIgPSAxOiBLaMO0bmcgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IHbhu4Egbmd1eSBjxqEgZ2nhu69hIGhhaSBuaMOzbS4NCi0gICBSUiBcPiAxOiBOZ3V5IGPGoSDhu58gbmjDs20gdGnhur9wIHjDumMgY2FvIGjGoW4gbmjDs20ga2jDtG5nIHRp4bq/cCB4w7pjLg0KLSAgIFJSIFw8IDE6IE5ndXkgY8ahIOG7nyBuaMOzbSB0aeG6v3AgeMO6YyB0aOG6pXAgaMahbiBuaMOzbSBraMO0bmcgdGnhur9wIHjDumMuDQoNCiMjIyAqKlThu7cgc+G7kSBjaMOqbmggKE9kZHMgUmF0aW8gLSBPUikqKg0KDQoqKktow6FpIG5p4buHbToqKiBPZGRzIFJhdGlvIChPUikgbMOgIHThu7cgbOG7hyBnaeG7r2Egb2RkcyB44bqjeSByYSBz4buxIGtp4buHbiDhu58gbmjDs20NCnRp4bq/cCB4w7pjIHNvIHbhu5tpIG5ow7NtIGtow7RuZyB0aeG6v3AgeMO6Yy4NCg0KKipDw7RuZyB0aOG7qWM6KioNCg0KJCQNCk9SID0gXGZyYWN7XGZyYWN7YX17Yn19e1xmcmFje2N9e2R9fSA9IFxmcmFje2EgXHRpbWVzIGR9e2IgXHRpbWVzIGN9DQokJA0KDQoqKkRp4buFbiBnaeG6o2k6KioNCg0KLSAgIE9SID0gMTogS2jDtG5nIGPDsyBz4buxIGtow6FjIGJp4buHdCB24buBIG9kZHMgZ2nhu69hIGhhaSBuaMOzbS4NCi0gICBPUiBcPiAxOiBPZGRzIHjhuqN5IHJhIHPhu7Ega2nhu4duIOG7nyBuaMOzbSB0aeG6v3AgeMO6YyBjYW8gaMahbiBuaMOzbSBraMO0bmcgdGnhur9wDQogICAgeMO6Yy4NCi0gICBPUiBcPCAxOiBPZGRzIHjhuqN5IHJhIHPhu7Ega2nhu4duIOG7nyBuaMOzbSB0aeG6v3AgeMO6YyB0aOG6pXAgaMahbiBuaMOzbSBraMO0bmcNCiAgICB0aeG6v3AgeMO6Yy4NCg0KKipDw6FjIGLGsOG7m2MgdGjhu7FjIGhp4buHbiB0csOqbiBSKioNCg0KYGBge3J9DQojIEzhuqV5IHPhu5EgbGnhu4d1DQphIDwtIHRhYmxlX2dlbmRlcl9ob21lb3duZXJbIkYiLCAiWSJdDQpiIDwtIHRhYmxlX2dlbmRlcl9ob21lb3duZXJbIkYiLCAiTiJdDQpjIDwtIHRhYmxlX2dlbmRlcl9ob21lb3duZXJbIk0iLCAiWSJdDQpkIDwtIHRhYmxlX2dlbmRlcl9ob21lb3duZXJbIk0iLCAiTiJdDQoNCiMgVMOtbmggT2Rkcw0Kb2Rkc19mZW1hbGUgPC0gYSAvIGINCm9kZHNfbWFsZSA8LSBjIC8gZA0KDQojIE9kZHMgUmF0aW8gKE9SKQ0Kb3IgPC0gb2Rkc19mZW1hbGUgLyBvZGRzX21hbGUNCg0KIyBSZWxhdGl2ZSBSaXNrIChSUikNCnJpc2tfZmVtYWxlIDwtIGEgLyAoYSArIGIpDQpyaXNrX21hbGUgPC0gYyAvIChjICsgZCkNCnJyIDwtIHJpc2tfZmVtYWxlIC8gcmlza19tYWxlDQoNCmxpc3QoDQogIG9kZHNfZmVtYWxlID0gb2Rkc19mZW1hbGUsDQogIG9kZHNfbWFsZSA9IG9kZHNfbWFsZSwNCiAgT1IgPSBvciwNCiAgUlIgPSBycg0KKQ0KYGBgDQoNCioqS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gT2RkcyBSYXRpbyoqDQoNCkRvIE9SIGtow7RuZyBwaMOibiBwaOG7kWkgY2h14bqpbiwgbsOqbiBs4bqleSBsb2coT1IpIMSR4buDIHjDonkgZOG7sW5nIGtob+G6o25nIHRpbiBj4bqteToNCg0KJCQNCkNJX3tsb2coT1IpfSA9IFxsb2coT1IpIFxwbSBaIFxjZG90IFNFX3tsb2coT1IpfQ0KJCQNCg0KVuG7m2k6ICQkDQpTRSA9IFxzcXJ0e1xmcmFjezF9e2F9ICsgXGZyYWN7MX17Yn0gKyBcZnJhY3sxfXtjfSArIFxmcmFjezF9e2R9fQ0KJCQNCg0KQ2h1eeG7g24gduG7gSB0aGFuZyBPUiBi4bqxbmcgaMOgbSBtxak6ICRlXntDSX0kLg0KDQoqKkPDoWMgYsaw4bubYyB0aOG7sWMgaGnhu4duIHRyw6puIFIqKg0KDQpgYGB7cn0NCnNlX2xvZ19vciA8LSBzcXJ0KDEvYSArIDEvYiArIDEvYyArIDEvZCkNCnogPC0gMS45NiAgIyBo4buHIHPhu5EgY2hvIDk1JQ0KY2lfbG93ZXIgPC0gZXhwKGxvZyhvcikgLSB6ICogc2VfbG9nX29yKQ0KY2lfdXBwZXIgPC0gZXhwKGxvZyhvcikgKyB6ICogc2VfbG9nX29yKQ0KYyhjaV9sb3dlciwgY2lfdXBwZXIpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQotICAgTuG6v3UgKipPUiBcPCAxKiosIG9kZHMgY+G7p2Egdmnhu4djIHPhu58gaOG7r3UgbmjDoCDhu58gbmjDs20gRmVtYWxlIG5o4buPIGjGoW4NCiAgICBNYWxlLg0KLSAgIE7hur91ICoqUlIgXDwgMSoqLCBwaOG7pSBu4buvIGPDsyBuZ3V5IGPGoSBz4bufIGjhu691IG5ow6AgdGjhuqVwIGjGoW4gbmFtIGdp4bubaS4NCg0KS+G6v3QgbHXhuq1uIGPhuqduIMSRaSBrw6htIHbhu5tpIGtp4buDbSDEkeG7i25oIENoaS1zcXVhcmUgdsOgIGtob+G6o25nIHRpbiBj4bqteSwga2jDtG5nDQpuw6puIGNo4buJIG5ow6xuIHbDoG8gT1IvUlIuDQoNCsSQw6J5IGzDoCBt4buZdCB2w60gZOG7pSDEkWnhu4NuIGjDrG5oIGNobyB2aeG7h2Mgc+G7rSBk4bulbmcgT2RkcyBSYXRpbyB0cm9uZyBraW5oIHThur8veMOjDQpo4buZaSBo4buNYyDEkeG7gyBtw7QgdOG6oyBt4buRaSBsacOqbiBo4buHIGdp4buvYSBoYWkgxJHhurdjIMSRaeG7g20gcGjDom4gbG/huqFpLg0KDQojIyAqKlRo4buxYyBow6BuaCB0csOqbiBi4buZIGThu68gbGnhu4d1KioNCg0KKipU4bqhbyBi4bqjbmcgdOG6p24gc+G7kSoqDQoNCmBgYHtyfQ0KIyBC4bqjbmcgdOG6p24gc+G7kSBjaMOpbyBnaeG7r2EgTWFyaXRhbFN0YXR1cyB2w6AgSG9tZW93bmVyDQp0YmwgPC0gdGFibGUoZGF0YSRNYXJpdGFsU3RhdHVzLCBkYXRhJEhvbWVvd25lcikNCnRibA0KYGBgDQoNCioqTmjhuq1uIHjDqXQqKg0KDQotICAgKipLaMOhY2ggaMOgbmcgxJHDoyBr4bq/dCBow7RuIChNKSoqOiBDw7MgdOG7m2kgNTE0NyBuZ8aw4budaSBz4bufIGjhu691IG5ow6Ag4bufLCBjaGnhur9tDQogICAgcGjhuqduIGzhu5tuIHRyb25nIG5ow7NtIG7DoHksIHRyb25nIGtoaSBjaOG7iSBjw7MgMTcxOSBuZ8aw4budaSBraMO0bmcgc+G7nyBo4buvdQ0KICAgIG5ow6AuDQoNCi0gICAqKktow6FjaCBow6BuZyDEkeG7mWMgdGjDom4gKFMpKio6IE5nxrDhu6NjIGzhuqFpLCBuaMOzbSBuw6B5IGPDsyB4dSBoxrDhu5tuZyBraMO0bmcNCiAgICBz4bufIGjhu691IG5ow6Ag4bufIGNhbyBoxqFuIHbhu5tpIDM4OTYgbmfGsOG7nWksIHRyb25nIGtoaSBz4buRIG5nxrDhu51pIHPhu58gaOG7r3UgbmjDoA0KICAgIGNo4buJIGzDoCAzMjk3IG5nxrDhu51pLg0KDQoqKktp4buDbSDEkeG7i25oIENoaS1zcXVhcmUqKg0KDQpgYGB7cn0NCmNoaV90ZXN0IDwtIGNoaXNxLnRlc3QodGJsKQ0KY2hpX3Rlc3QNCmBgYA0KDQoqKkvhur90IHF14bqjIGtp4buDbSDEkeG7i25oOioqDQoNCi0gICBHacOhIHRy4buLIHRo4buRbmcga8OqIENoaS1iw6xuaCBwaMawxqFuZzogWC1zcXVhcmVkID0gMTI0MS4yDQoNCi0gICBC4bqtYyB04buxIGRvOiBkZiA9IDENCg0KLSAgIEdpw6EgdHLhu4sgcDogcC12YWx1ZSBcPCAyLjJlLTE2DQoNCioqS+G6v3QgbHXhuq1uOioqDQoNCi0gICBWw6wgZ2nDoSB0cuG7iyBwIHLhuqV0IG5o4buPIChwIFw8IDAuMDUpLCB0YSBiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3Qga2jDtG5nIEgwLg0KICAgIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IGPDsyBt4buRaSBsacOqbiBo4buHIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogZ2nhu69hIHTDrG5oIHRy4bqhbmcNCiAgICBow7RuIG5ow6JuIHbDoCB0w6xuaCB0cuG6oW5nIHPhu58gaOG7r3UgbmjDoC4NCg0KKipUw61uaCBPZGRzIFJhdGlvIHbDoCBSZWxhdGl2ZSBSaXNrKioNCg0KYGBge3J9DQojIEzhu41jIGThu68gbGnhu4d1OiBjaOG7iSBs4bqleSBNYXJyaWVkIHbDoCBTaW5nbGUNCmRhdGEyIDwtIHN1YnNldChkYXRhLCBNYXJpdGFsU3RhdHVzICVpbiUgYygiTSIsICJTIikpDQoNCiMgVOG6oW8gYuG6o25nIDJ4Mg0KdGJsMiA8LSB0YWJsZShkYXRhMiRNYXJpdGFsU3RhdHVzLCBkYXRhMiRIb21lb3duZXIpDQp0YmwyDQoNCiMgVMOtbmggdG/DoW4gT2RkcyBSYXRpbyB2w6AgUmVsYXRpdmUgUmlzaw0KbGlicmFyeShlcGlSKQ0KZXBpX3Jlc3VsdCA8LSBlcGkuMmJ5Mih0YmwyLCBtZXRob2QgPSAiY29ob3J0LmNvdW50IiwgY29uZi5sZXZlbCA9IDAuOTUpDQplcGlfcmVzdWx0DQpgYGANCg0KIyMgKipL4bq/dCBxdeG6oyBwaMOibiB0w61jaCoqDQoNCioqQuG6o25nIGNow6lvIHThuqduIHN14bqldCBnaeG7r2EgTWFyaXRhbFN0YXR1cyB2w6AgSG9tZW93bmVyKioNCg0KfCBNYXJpdGFsIFN0YXR1cyB8IEtow7RuZyBz4bufIGjhu691IG5ow6AgKE4pIHwgQ8OzIHPhu58gaOG7r3UgbmjDoCAoWSkgfCBU4buVbmcgY+G7mW5nIHwNCnwtLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwNCnwgTWFycmllZCAoTSkgICAgfCAxLDcxOSAgICAgICAgICAgICAgICB8IDUsMTQ3ICAgICAgICAgICAgIHwgNiw4NjYgICAgIHwNCnwgU2luZ2xlIChTKSAgICAgfCAzLDg5NiAgICAgICAgICAgICAgICB8IDMsMjk3ICAgICAgICAgICAgIHwgNywxOTMgICAgIHwNCnwgKipU4buVbmcgY+G7mW5nKiogIHwgNSw2MTUgICAgICAgICAgICAgICAgfCA4LDQ0NCAgICAgICAgICAgICB8IDE0LDA1OSAgICB8DQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoqKlThu7cgbOG7hyBoaeG7h24gbeG6r2MgKEluY2lkZW5jZSBSaXNrKSoqDQoNCi0gICAqKk5ow7NtIE1hcnJpZWQqKjogMjUuMDQlIChDSTogMjQuMDIg4oCTIDI2LjA4KQ0KLSAgICoqTmjDs20gU2luZ2xlKio6IDU0LjE2JSAoQ0k6IDUzLjAwIOKAkyA1NS4zMikNCg0KTmjhu69uZyBuZ8aw4budaSAqKsSR4buZYyB0aMOibioqIGPDsyB4w6FjIHN14bqldCBraMO0bmcgc+G7nyBo4buvdSBuaMOgICoqY2FvIGjGoW4gZ+G6pXANCsSRw7RpKiogc28gduG7m2kgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KKipSZWxhdGl2ZSBSaXNrIChSUikqKg0KDQotICAgKipSUiA9IDAuNDYqKiAoOTUlIENJOiAwLjQ0IOKAkyAwLjQ4KQ0KDQpOZ3V5IGPGoSBraMO0bmcgc+G7nyBo4buvdSBuaMOgIOG7nyBuaMOzbSDEkcOjIGvhur90IGjDtG4gY2jhu4kgYuG6sW5nICoqNDYlKiogc28gduG7m2kgbmjDs20NCsSR4buZYyB0aMOibi4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCioqT2RkcyBSYXRpbyAoT1IpKioNCg0KLSAgICoqT1IgPSAwLjI4KiogKDk1JSBDSTogMC4yNiDigJMgMC4zMCkNCg0KWMOhYyBzdeG6pXQga2jDtG5nIHPhu58gaOG7r3UgbmjDoCDhu58gbmjDs20gxJHDoyBr4bq/dCBow7RuIHRo4bqlcCBoxqFuICoqNzIlKiogc28gduG7m2kgbmjDs20NCsSR4buZYyB0aMOibi4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCioqUmlzayBEaWZmZXJlbmNlIHbDoCBBdHRyaWJ1dGlvbioqDQoNCi0gICAqKkNow6puaCBs4buHY2ggbmd1eSBjxqEgdHV54buHdCDEkeG7kWkgKHJpc2sgZGlmZmVyZW5jZSkqKjogLTI5LjEzIMSRaeG7g20gcGjhuqduDQogICAgdHLEg20NCi0gICAqKlThu7cgbOG7hyBxdXkgdHLDoWNoIHRyb25nIG5ow7NtIHBoxqFpIG5oaeG7hW0gKGV4cG9zZWQpKio6IC0xMTYuMzQlDQotICAgKipU4bu3IGzhu4cgcXV5IHRyw6FjaCB0b8OgbiBkw6JuIChwb3B1bGF0aW9uKSoqOiAtMzUuNjIlDQoNCsSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IHLhurFuZyB2aeG7h2Mga+G6v3QgaMO0biBjw7MgdGjhu4MgZ2nDunAgZ2nhuqNtIMSRw6FuZyBr4buDIHLhu6dpIHJvDQpraMO0bmcgc+G7nyBo4buvdSBuaMOgIOG7nyBj4bqlcCDEkeG7mSBjw6EgbmjDom4gbOG6q24gZMOibiBz4buRLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KKipLaeG7g20gxJHhu4tuaCDDvSBuZ2jEqWEgdGjhu5FuZyBrw6oqKg0KDQotICAgKipDaGktc3F1YXJlZCB0ZXN0Kio6IM+HwrIoMSkgPSAxMjQyLjQzLCBwIFw8IDAuMDAxDQotICAgKipGaXNoZXLigJlzIGV4YWN0IHRlc3QqKjogcCBcPCAwLjAwMQ0KDQpL4bq/dCBxdeG6oyBraeG7g20gxJHhu4tuaCBjaG8gdGjhuqV5IG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiB2w6Agdmnhu4djDQpz4bufIGjhu691IG5ow6AgbMOgICoqcuG6pXQgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqioqIChwIFw8IDAuMDAxKS4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCioqS+G6v3QgbHXhuq1uOioqDQoNCi0gICBDw7MgbeG7kWkgbGnDqm4gaOG7hyBy4bqldCByw7UgcsOgbmcgdsOgIGPDsyDDvSBuZ2jEqWEgZ2nhu69hIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiB2w6ANCiAgICB2aeG7h2Mgc+G7nyBo4buvdSBuaMOgLg0KLSAgIE5o4buvbmcgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIGPDsyB04bu3IGzhu4cgdsOgIHjDoWMgc3XhuqV0IGtow7RuZyBz4bufIGjhu691IG5ow6AgKip0aOG6pXANCiAgICBoxqFuIMSRw6FuZyBr4buDKiogc28gduG7m2kgbmfGsOG7nWkgxJHhu5ljIHRow6JuLg0KLSAgIMSQw6J5IGzDoCBt4buZdCBwaMOhdCBoaeG7h24gcXVhbiB0cuG7jW5nIGPDsyB0aOG7gyDEkcaw4bujYyBz4butIGThu6VuZyB0cm9uZyBjw6FjIG5naGnDqm4NCiAgICBj4bupdSB4w6MgaOG7mWkgaOG7jWMgaG/hurdjIGNow61uaCBzw6FjaCBuaMOgIOG7ny4NCg0KIyAqKkI6IEhP4bqgVCDEkOG7mE5HIFRSw4pOIEzhu5pQKioNCg0KVHJvbmcgaG/huqF0IMSR4buZbmcgbsOgeSwgY2jDum5nIHRhIHPhur0gc+G7rSBk4bulbmcgZOG7ryBsaeG7h3UgKipTdXBlcm1hcmtldA0KVHJhbnNhY3Rpb25zKiogxJHhu4MgcGjDom4gdMOtY2ggbeG7kWkgbGnDqm4gaOG7hyBnaeG7r2EgY8OhYyBiaeG6v24gbmjhu4sgcGjDom4uIE3hu6VjIHRpw6p1DQpsw6A6DQoNCi0gICBU4bqhbyBi4bqjbmcgMngyDQotICAgVMOtbmggdsOgIGRp4buFbiBnaeG6o2kgSGnhu4d1IGhhaSB04bu3IGzhu4cgKERpZmZlcmVuY2UgaW4gUHJvcG9ydGlvbnMpDQotICAgVMOtbmggUmVsYXRpdmUgUmlzayAoUlIpIHbDoCBPZGRzIFJhdGlvIChPUikNCi0gICBUw61uaCBraG/huqNuZyB0aW4gY+G6rXkgOTUlIGNobyBPUg0KLSAgIFRo4buxYyBoaeG7h24gcGjDom4gdMOtY2ggcGjDom4gdOG6p25nIChzdHJhdGlmaWVkIGFuYWx5c2lzKQ0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMgKirEkOG7jWMgdsOgIGzDoG0gcXVlbiB24bubaSBk4buvIGxp4buHdSoqDQoNCkLhu5kgZOG7ryBsaeG7h3Ug4oCcU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25z4oCdIHBo4bqjbiDDoW5oIGPDoWMgZ2lhbyBk4buLY2ggbXVhIGjDoG5nDQpj4bunYSBraMOhY2ggaMOgbmcgdOG6oWkgbeG7mXQgc2nDqnUgdGjhu4sgdHJvbmcgbeG7mXQga2hv4bqjbmcgdGjhu51pIGdpYW4gY+G7pSB0aOG7gy4gTeG7l2kNCmTDsm5nIGThu68gbGnhu4d1IHTGsMahbmcg4bupbmcgduG7m2kgbeG7mXQgZ2lhbyBk4buLY2gsIGJhbyBn4buTbSB0aMO0bmcgdGluIG5ow6JuIGto4bqpdQ0KaOG7jWMgKGdp4bubaSB0w61uaCwgbG/huqFpIHRow6BuaCB2acOqbiwgY2hpIG5ow6FuaCksIMSR4bq3YyDEkWnhu4NtIHPhuqNuIHBo4bqpbSAobG/huqFpIHPhuqNuDQpwaOG6qW0sIGvDqm5oIHRoYW5oIHRvw6FuKSwgdsOgIGPDoWMgeeG6v3UgdOG7kSBow6BuaCB2aSB0acOqdSBkw7luZyAodGjhu51pIGdpYW4gbXVhDQpz4bqvbSwgbeG7qWMgxJHhu5kgaMOgaSBsw7JuZywgZ2nDoSB0cuG7iyDEkcahbiBow6BuZywuLi4pLiBU4bqtcCBk4buvIGxp4buHdSBn4buTbSAxNC4wNTkgcXVhbg0Kc8OhdCB2w6AgMTYgYmnhur9uLCBjdW5nIGPhuqVwIG7hu4FuIHThuqNuZyBjaGkgdGnhur90IMSR4buDIHBow6JuIHTDrWNoIGjDoG5oIHZpIGtow6FjaA0KaMOgbmcgdsOgIGhp4buHdSBxdeG6oyBraW5oIGRvYW5oIGPhu6dhIHNpw6p1IHRo4buLLg0KDQpgYGB7cn0NCiMgxJDhu41jIGZpbGUNCmxpYnJhcnkoImNzdiIpDQpkYXRhIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9BU1VTL0Rvd25sb2Fkcy9TdXBlcm1hcmtldCBUcmFuc2FjdGlvbnMuY3N2IiwgaGVhZGVyID0gVCkNCg0KIyBIaeG7g24gdGjhu4sgY+G6pXUgdHLDumMgZOG7ryBsaeG7h3UNCnN0cihkYXRhKQ0KDQojIEhp4buDbiB0aOG7iyB2w6BpIGTDsm5nIMSR4bqndSB2w6AgY3Xhu5FpDQpoZWFkKGRhdGEpDQp0YWlsKGRhdGEpDQoNCiMgQ2h1eeG7g24gY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCBwaMO5IGjhu6NwIHNhbmcgZmFjdG9yDQpmYWN0b3IgPC0gYygiR2VuZGVyIiwgIk1hcml0YWxTdGF0dXMiLCAiSG9tZW93bmVyIiwgIkFubnVhbEluY29tZSIsDQogICAgICAgICAgICAgICAgICAgICJDaXR5IiwgIlN0YXRlb3JQcm92aW5jZSIsICJDb3VudHJ5IiwNCiAgICAgICAgICAgICAgICAgICAgIlByb2R1Y3RGYW1pbHkiLCAiUHJvZHVjdERlcGFydG1lbnQiLCAiUHJvZHVjdENhdGVnb3J5IikNCg0KIyBLaeG7g20gdHJhIGJp4bq/biBuw6BvIHThu5NuIHThuqFpIHRyb25nIGRhdGENCmZhY3RvciA8LSBpbnRlcnNlY3QoZmFjdG9yLCBuYW1lcyhkYXRhKSkNCg0KIyBDaHV54buDbiBzYW5nIGZhY3Rvcg0KZGF0YVtmYWN0b3JdIDwtIGxhcHBseShkYXRhW2ZhY3Rvcl0sIGFzLmZhY3RvcikNCg0KIyBLaeG7g20gdHJhIGzhuqFpIGPhuqV1IHRyw7pjDQpzdHIoZGF0YSkNCmBgYA0KDQoqKkdp4bqjaSB0aMOtY2ggY8OhYyBiaeG6v24qKg0KDQpC4buZIGThu68gbGnhu4d1IGdoaSBs4bqhaSB0aMO0bmcgdGluIHbhu4EgY8OhYyBnaWFvIGThu4tjaCBtdWEgaMOgbmcgY+G7p2Ega2jDoWNoIGjDoG5nLA0KYmFvIGfhu5NtIHRow7RuZyB0aW4gbmjDom4ga2jhuql1IGjhu41jLCB0aMO0bmcgdGluIHPhuqNuIHBo4bqpbSwgc+G7kSBsxrDhu6NuZyBiw6FuIHJhIHbDoA0KZG9hbmggdGh1LiBE4buvIGxp4buHdSBiYW8gZ+G7k20gMTQwNTkgcXVhbiBzw6F0IHbDoCAxNiBiaeG6v24uIETGsOG7m2kgxJHDonkgbMOgIG3DtCB04bqjDQpjaGkgdGnhur90IGPDoWMgYmnhur9uIGPDsyB0cm9uZyBi4buZIGThu68gbGnhu4d1Og0KDQp8ICoqVMOqbiBCaeG6v24qKiB8ICoqw50gTmdoxKlhKiogfA0KfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8ICoqUHVyY2hhc2VEYXRlKiogfCBOZ8OgeSBnaWFvIGThu4tjaCBtdWEgaMOgbmcgZGnhu4VuIHJhICjEkeG7i25oIGThuqFuZyBuZ8OgeS90aMOhbmcvbsSDbSkuIHwNCnwgKipDdXN0b21lcklEKiogfCBNw6MgxJHhu4tuaCBkYW5oIGR1eSBuaOG6pXQgY2hvIG3hu5dpIGtow6FjaCBow6BuZy4gfA0KfCAqKkdlbmRlcioqIHwgR2nhu5tpIHTDrW5oIGPhu6dhIGtow6FjaCBow6BuZzogKipNKiogKE5hbSksICoqRioqIChO4buvKS4gfA0KfCAqKk1hcml0YWxTdGF0dXMqKiB8IFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibjogKipTKiogKMSQ4buZYyB0aMOibiksICoqTSoqICjEkMOjIGvhur90IGjDtG4pLiB8DQp8ICoqSG9tZW93bmVyKiogfCBUw6xuaCB0cuG6oW5nIHPhu58gaOG7r3UgbmjDoDogKipZKiogKEPDsyksICoqTioqIChLaMO0bmcpLiB8DQp8ICoqQ2hpbGRyZW4qKiB8IFPhu5EgbMaw4bujbmcgY29uIGPDoWkgY+G7p2Ega2jDoWNoIGjDoG5nLiB8DQp8ICoqQW5udWFsSW5jb21lKiogfCBN4bupYyB0aHUgbmjhuq1wIGjDoG5nIG7Eg20gdGhlbyBraG/huqNuZyAoVsOtIGThu6U6ICoqXCQzMEsgLSBcJDUwSyoqKS4gfA0KfCAqKkNpdHkqKiB8IFRow6BuaCBwaOG7kSBuxqFpIGtow6FjaCBow6BuZyB0aOG7sWMgaGnhu4duIGdpYW8gZOG7i2NoLiB8DQp8ICoqU3RhdGVvclByb3ZpbmNlKiogfCBCYW5nIGhv4bq3YyB04buJbmggKHbDrSBk4bulOiAqKkNBKiogY2hvIENhbGlmb3JuaWEsICoqT1IqKiBjaG8gT3JlZ29uKS4gfA0KfCAqKkNvdW50cnkqKiB8IFF14buRYyBnaWEuIHwNCnwgKipQcm9kdWN0RmFtaWx5KiogfCBOaMOzbSBz4bqjbiBwaOG6qW0gY2jDrW5oOiAqKkZvb2QqKiAoVGjhu7FjIHBo4bqpbSksICoqRHJpbmsqKiAoxJDhu5MgdeG7kW5nKSwgKipOb24tQ29uc3VtYWJsZSoqIChLaMO0bmcgdGnDqnUgZMO5bmcpLiB8DQp8ICoqUHJvZHVjdERlcGFydG1lbnQqKiB8IELhu5kgcGjhuq1uIHPhuqNuIHBo4bqpbSBuaMawICoqU25hY2sgRm9vZHMqKiwgKipGcm96ZW4gRm9vZHMqKiwgdi52LiB8DQp8ICoqUHJvZHVjdENhdGVnb3J5KiogfCBEYW5oIG3hu6VjIHPhuqNuIHBo4bqpbSBj4bulIHRo4buDIGjGoW4sIHbDrSBk4bulOiAqKkNhbmR5KiosICoqQmVlciBhbmQgV2luZSoqLiB8DQp8ICoqVW5pdHNTb2xkKiogfCBT4buRIGzGsOG7o25nIMSRxqFuIHbhu4sgc+G6o24gcGjhuqltIMSRw6MgYsOhbiB0cm9uZyBnaWFvIGThu4tjaCDEkcOzLiB8DQp8ICoqUmV2ZW51ZSoqIHwgRG9hbmggdGh1IHThu6sgZ2lhbyBk4buLY2ggKHTDrW5oIHRoZW8gVVNEKS4gfA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMgKipQaMOibiB0w61jaCBt4buRaSBsacOqbiBo4buHIGdp4buvYSBHZW5kZXIgdsOgIEhvbWVvd25lcioqDQoNCiMjIyAqKlThuqFvIGLhuqNuZyB04bqnbiBz4buRIGNow6lvKioNCg0KYGBge3J9DQp0YWJsZV9nZW5kZXJfaG9tZSA8LSB0YWJsZShkYXRhJEdlbmRlciwgZGF0YSRIb21lb3duZXIpDQp0YWJsZV9nZW5kZXJfaG9tZQ0KYGBgDQoNCkThu7FhIHbDoG8gYuG6o25nIHRyw6puOg0KDQotICAgKipO4buvIChGKSoqIGPDsyB04buVbmcgY+G7mW5nIGByIHN1bSh0YWJsZV9nZW5kZXJfaG9tZVsiRiIsIF0pYCBuZ8aw4budaSwNCiAgICB0cm9uZyDEkcOzIGByIHRhYmxlX2dlbmRlcl9ob21lWyJGIiwgIlkiXWAgbmfGsOG7nWkgc+G7nyBo4buvdSBuaMOgLCBjaGnhur9tDQogICAga2hv4bqjbmcNCiAgICBgciByb3VuZCgxMDAgKiB0YWJsZV9nZW5kZXJfaG9tZVsiRiIsICJZIl0gLyBzdW0odGFibGVfZ2VuZGVyX2hvbWVbIkYiLCBdKSwgMSlgJS4NCg0KLSAgICoqTmFtIChNKSoqIGPDsyB04buVbmcgY+G7mW5nIGByIHN1bSh0YWJsZV9nZW5kZXJfaG9tZVsiTSIsIF0pYCBuZ8aw4budaSwNCiAgICB24bubaSBgciB0YWJsZV9nZW5kZXJfaG9tZVsiTSIsICJZIl1gIG5nxrDhu51pIHPhu58gaOG7r3UgbmjDoCwgdMawxqFuZyDhu6luZw0KICAgIGtob+G6o25nDQogICAgYHIgcm91bmQoMTAwICogdGFibGVfZ2VuZGVyX2hvbWVbIk0iLCAiWSJdIC8gc3VtKHRhYmxlX2dlbmRlcl9ob21lWyJNIiwgXSksIDEpYCUuDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KVOG7tyBs4buHIHPhu58gaOG7r3UgbmjDoCBj4bunYSBu4buvIGPDsyB24bq7IG5o4buJbmggaMahbiBt4buZdCBjaMO6dCBzbyB24bubaSBuYW0gKGtob+G6o25nDQo2MC42JSBzbyB24bubaSA1OS41JSksIHR1eSBuaGnDqm4gc+G7sSBraMOhYyBiaeG7h3QgbsOgeSBsw6Aga2jDoSBuaOG7jy5cDQrEkOG7gyDEkcOhbmggZ2nDoSByw7UgcsOgbmcgaMahbiB24buBIG3hu6ljIMSR4buZIGxpw6puIGjhu4cgZ2nhu69hIGhhaSBiaeG6v24sIHRhIHPhur0gdGnhur9wIHThu6VjDQp0w61uaCBjw6FjIGNo4buJIHPhu5EgxJHhu4tuaCBsxrDhu6NuZyBuaMawOlwNCkhp4buHdSBoYWkgdOG7tyBs4buHIChEaWZmZXJlbmNlIGluIFByb3BvcnRpb25zKSwgUmVsYXRpdmUgUmlzayAoUlIpLCBPZGRzDQpSYXRpbyAoT1IpLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjICoqVMOtbmggSGnhu4d1IEhhaSBU4bu3IEzhu4cqKg0KDQpgYGB7cn0NCnByb3BfdGFibGUgPC0gcHJvcC50YWJsZSh0YWJsZV9nZW5kZXJfaG9tZSwgbWFyZ2luID0gMSkNCnByb3BfdGFibGUNCg0KZGlmZl9wcm9wIDwtIHByb3BfdGFibGVbMSwgIlkiXSAtIHByb3BfdGFibGVbMiwgIk4iXQ0KZGlmZl9wcm9wDQpgYGANCg0KVOG7tyBs4buHIHPhu58gaOG7r3UgbmjDoDoNCg0KLSAgIOG7niAqKm7hu68qKiBsw6AgYHIgcm91bmQocHJvcF90YWJsZVsxLCAiWSJdLCA0KWAgKHThu6ljIGzDoA0KICAgIGByIHJvdW5kKDEwMCAqIHByb3BfdGFibGVbMSwgIlkiXSwgMSlgJSkNCg0KLSAgIOG7niAqKm5hbSoqIGzDoCBgciByb3VuZChwcm9wX3RhYmxlWzIsICJZIl0sIDQpYCAodOG7qWMgbMOgDQogICAgYHIgcm91bmQoMTAwICogcHJvcF90YWJsZVsyLCAiWSJdLCAxKWAlKQ0KDQpIaeG7h3UgaGFpIHThu7cgbOG7hyBnaeG7r2EgbuG7ryB2w6AgbmFtIGzDoCBgciByb3VuZChkaWZmX3Byb3AsIDQpYCwgdMawxqFuZyDEkcawxqFuZw0KYHIgcm91bmQoMTAwICogZGlmZl9wcm9wLCAyKWAgxJFp4buDbSBwaOG6p24gdHLEg20uDQoNCioqS+G6v3QgbHXhuq1uOioqDQoNClThu7cgbOG7hyBu4buvIHPhu58gaOG7r3UgbmjDoCBjYW8gaMahbiBuYW0ga2hv4bqjbmcgMS4wMCUsIHR1eSBuaGnDqm4gbeG7qWMgY2jDqm5oIGzhu4djaA0KbsOgeSBraMOhIG5o4buPIHbDoCBjaMawYSB0aOG7gyBr4bq/dCBsdeG6rW4gY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiBu4bq/dSBjaMawYSB0w61uaA0Ka2hv4bqjbmcgdGluIGPhuq15IChjb25maWRlbmNlIGludGVydmFsKSBob+G6t2MgdGjhu7FjIGhp4buHbiBjw6FjIGtp4buDbSDEkeG7i25oIHRo4buRbmcNCmvDqiBjaMOtbmggdGjhu6ljIG5oxrAga2nhu4NtIMSR4buLbmggeiBob+G6t2MgY2hpIGLDrG5oIHBoxrDGoW5nLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjICoqVMOtbmggUmVsYXRpdmUgUmlzayAoUlIpKioNCg0KYGBge3J9DQpsaWJyYXJ5KGVwaXRvb2xzKQ0KcnJfcmVzdWx0IDwtIHJpc2tyYXRpbyh0YWJsZV9nZW5kZXJfaG9tZSkNCnJyX3Jlc3VsdCRtZWFzdXJlDQpgYGANCg0KROG7sWEgdsOgbyBr4bq/dCBxdeG6oyB0YSB0aOG6pXkgUmVsYXRpdmUgUmlzayAoUlIpIGPhu6dhIG5hbSBzbyB24bubaSBu4buvIGzDoA0KYHIgcm91bmQocnJfcmVzdWx0JG1lYXN1cmVbIk0iLCAiZXN0aW1hdGUiXSwgNClgLiBLaG/huqNuZyB0aW4gY+G6rXkgOTUlIGPhu6dhDQpSUiBu4bqxbSB0cm9uZyBraG/huqNuZyB04burIGByIHJvdW5kKHJyX3Jlc3VsdCRtZWFzdXJlWyJNIiwgImxvd2VyIl0sIDQpYCDEkeG6v24NCmByIHJvdW5kKHJyX3Jlc3VsdCRtZWFzdXJlWyJNIiwgInVwcGVyIl0sIDQpYC4NCg0KKipL4bq/dCBsdeG6rW46KipcDQpSUiBcPCAxIGNobyB0aOG6pXkgbmFtIGPDsyB04bu3IGzhu4cgc+G7nyBo4buvdSBuaMOgIHRo4bqlcCBoxqFuIG7hu68gbeG7mXQgY2jDunQgKGNo4buJIGPDsm4NCmtob+G6o25nIGByIHJvdW5kKHJyX3Jlc3VsdCRtZWFzdXJlWyJNIiwgImVzdGltYXRlIl0sIDQpICogMTAwYCUgc28gduG7m2kNCm7hu68pLiBUdXkgbmhpw6puLCB2w6wga2hv4bqjbmcgdGluIGPhuq15IDk1JSBiYW8gZ+G7k20gZ2nDoSB0cuG7iyAxLjAsIG7Dqm4ga2jDtG5nIGPDsw0KYuG6sW5nIGNo4bupbmcgxJHhu6cgbeG6oW5oIMSR4buDIGvhur90IGx14bqtbiBz4buxIGtow6FjIGJp4buHdCBuw6B5IGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ouIE7Ds2kNCmPDoWNoIGtow6FjLCB04bu3IGzhu4cgc+G7nyBo4buvdSBuaMOgIGdp4buvYSBuYW0gdsOgIG7hu68gY8OzIHRo4buDIGNvaSBsw6AgdMawxqFuZyDEkcawxqFuZy4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyAqKlTDrW5oIE9kZHMgUmF0aW8gKE9SKSB2w6AgS2hv4bqjbmcgVGluIEPhuq15KioNCg0KYGBge3J9DQpsaWJyYXJ5KGVwaXRvb2xzKQ0Kb3JfcmVzdWx0IDwtIG9kZHNyYXRpbyh0YWJsZV9nZW5kZXJfaG9tZSkNCm9yX3Jlc3VsdA0Kb3JfcmVzdWx0JGNvbmYuaW50DQpgYGANCg0KUGjDom4gdMOtY2ggYuG6o25nIHRow6wgZ2nhu69hIGhhaSBuaMOzbSBnaeG7m2kgdMOtbmggKEYgdsOgIE0pIGNobyB0aOG6pXk6DQoNCi0gICBU4bu3IHPhu5Egb2RkcyAob2RkcyByYXRpbykgZ2nhu69hIG5ow7NtIG5hbSAoTSkgc28gduG7m2kgbuG7ryAoRikgbMOgICoqMC45NioqLA0KICAgIHbhu5tpIGtob+G6o25nIHRpbiBj4bqteSA5NSUgbMOgICoqWzAuODk7IDEuMDJdKiouDQotICAgR2nDoSB0cuG7iyBwIHThu6sgY8OhYyBwaMOpcCBraeG7g20gxJHhu4tuaCBoYWkgcGjDrWE6DQogICAgLSAgIE1pZC1wIGV4YWN0OiAqKnAgPSAwLjE5NSoqDQogICAgLSAgIEZpc2hlcidzIGV4YWN0OiAqKnAgPSAwLjE5NioqDQogICAgLSAgIENoaS1zcXVhcmU6ICoqcCA9IDAuMTk1KioNCg0KRG8gdOG6pXQgY+G6oyBjw6FjIGdpw6EgdHLhu4sgcCDEkeG7gXUgbOG7m24gaMahbiBt4bupYyDDvSBuZ2jEqWEgdGjDtG5nIHRoxrDhu51uZyAoKirOsSA9DQowLjA1KiopLCBraMO0bmcgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogZ2nhu69hIG5ow7NtIG5hbSB2w6AgbuG7rw0KduG7gSBiaeG6v24gxJHGsOG7o2MgcGjDom4gdMOtY2guDQoNCk5oxrAgduG6rXksIGvhur90IHF14bqjIGNobyB0aOG6pXkga2jDtG5nIGPDsyBt4buRaSBsacOqbiBxdWFuIHLDtSBy4buHdCBnaeG7r2EgZ2nhu5tpIHTDrW5oDQp2w6AgYmnhur9uLCB0aGVvIHBow6JuIHTDrWNoIG9kZHMgcmF0aW8gdsOgIGPDoWMga2nhu4NtIMSR4buLbmggeMOhYyBzdeG6pXQgdMawxqFuZyDhu6luZy4NCg0K