library(showtext)
font_add(family = "Arial", regular = "arial.ttf")  # Đảm bảo font Arial có trên máy
showtext_auto()
library(tidyverse)
library(ggplot2)
library(epitools)
library(DescTools)
library(DT)
library(energy)
library(readr)
options(digits = 4)

Phân tích Dữ liệu Giao dịch Siêu thị

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

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

#Đọc dữ liệu từ file CSV
data <-read.csv("C:/Users/Hoang Quyen/Downloads/Supermarket Transactions.csv")
#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 ...

Kết quả trả về cho thấy data là một data.frame gồm 14,059 quan sát (dòng) và 16 biến (cột). Mỗi biến được liệt kê với tên, kiểu dữ liệu (chẳng hạn như int, chr, hoặc num) và một số giá trị mẫu ban đầu.

Biến định tính.

  • Gender: Giới tính (M/F) – phân loại nhị phân.
  • MaritalStatus: Tình trạng hôn nhân (M/S) – phân loại nhị phân.
  • Homeowner: Sở hữu nhà (Y/N) – phân loại nhị phân.
  • AnnualIncome: Thu nhập hàng năm (e.g., $10K–$30K, $30K–$50K,…) – phân loại thứ tự (ordinal), vì các khoảng thu nhập có thứ tự nhưng không phải số liên tục.
  • City: Thành phố (e.g., Los Angeles, Salem,…) – phân loại danh nghĩa (nominal).
  • StateorProvince: Bang hoặc tỉnh (e.g., CA, WA, BC,…) – phân loại danh nghĩa.
  • Country: Quốc gia (USA, Canada, Mexico) – phân loại danh nghĩa.
  • ProductFamily: Nhóm sản phẩm (Food, Non-Consumable, Drink) – phân loại danh nghĩa.
  • ProductDepartment: Bộ phận sản phẩm (e.g., Produce, Snack Foods, Dairy,…) – phân loại danh nghĩa.
  • ProductCategory: Danh mục sản phẩm (e.g., Vegetables, Snack Foods, Dairy,…) – phân loại danh nghĩa.

Biến định lượng (Quantitative Variables):

  • UnitsSold: Số lượng sản phẩm bán ra (1–7) – biến định lượng rời rạc.
  • Revenue: Doanh thu ($1.48–$44.78) – biến định lượng liên tục.
# Hiển thị 5 dòng đầu và cuối
head(data, 5)
##   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
##    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
##   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
tail(data, 5)
##           X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children
## 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
## 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
## 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

Hai hàm head() và tail() được sử dụng để hiển thị lần lượt 5 dòng đầu tiên và 5 dòng cuối cùng của bộ dữ liệu, giúp đánh giá sơ bộ tính nhất quán, định dạng và tính hợp lý của các giá trị trong từng biến. Qua việc quan sát mẫu này, có thể nhận thấy:

  • Dữ liệu trải dài từ ngày 2007-12-18 đến 2009-12-31, cho thấy đây là một tập dữ liệu có yếu tố thời gian kéo dài 3 năm.

  • Giá trị ở biến AnnualIncome được biểu diễn dưới dạng khoảng thu nhập (ví dụ: “$30K - $50K”), phù hợp để xem như biến phân loại.

  • Các biến như ProductFamily, ProductDepartment, ProductCategory thể hiện cấu trúc phân loại sản phẩm nhiều cấp, điều này có thể được khai thác trong các phân tích đa biến.

Kiểm tra Giá trị Thiếu (NA)

Một bước kiểm tra quan trọng trong quy trình tiền xử lý dữ liệu là xác định các giá trị thiếu (NA) trong các biến định tính. Trong đoạn mã trên, các biến định tính được liệt kê thủ công vào vector qualitative_cols, sau đó hàm sapply() được sử dụng kết hợp với hàm is.na() để đếm số lượng giá trị thiếu trên từng biến.

#Kiểm tra NA trong các cột định tính
qualitative_cols <- c("Gender", "MaritalStatus", "Homeowner", "AnnualIncome", 
                      "City", "StateorProvince", "Country", 
                      "ProductFamily", "ProductDepartment", "ProductCategory")
sapply(data[qualitative_cols], function(x) sum(is.na(x)))
##            Gender     MaritalStatus         Homeowner      AnnualIncome 
##                 0                 0                 0                 0 
##              City   StateorProvince           Country     ProductFamily 
##                 0                 0                 0                 0 
## ProductDepartment   ProductCategory 
##                 0                 0

Kết quả kiểm tra cho thấy không có giá trị thiếu ở bất kỳ biến định tính nào. Điều này rất quan trọng vì dữ liệu đầy đủ giúp đơn giản hóa quá trình phân tích, đồng thời loại bỏ nhu cầu xử lý thiếu như loại bỏ dòng, nội suy, hoặc thay thế giá trị.

Chuyển đổi Kiểu Dữ liệu sang Factor

Việc chuyển đổi các biến định tính từ kiểu ký tự (character) sang kiểu nhân tố (factor) là bước then chốt để đảm bảo R hiểu đúng bản chất của dữ liệu, đặc biệt trong các phân tích thống kê mô tả, kiểm định giả thuyết hoặc mô hình hóa.

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

#Kiểm tra lại cấu trúc
str(data[qualitative_cols])
## 'data.frame':    14059 obs. of  10 variables:
##  $ 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 ...
##  $ 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 ...

Sau chuyển đổi: - Gender có 2 mức độ (“F”, “M”), phù hợp với biến nhị phân.

  • MaritalStatus gồm 2 mức (“M” – Married, “S” – Single).

  • AnnualIncome có 8 khoảng thu nhập, được xử lý như biến phân loại thứ tự.

  • City và StateorProvince có số lượng mức độ lớn hơn (lần lượt 23 và 10), phản ánh sự đa dạng về địa lý.

  • ProductCategory có đến 45 mức độ, phản ánh sự đa dạng của danh mục sản phẩm trong hệ thống siêu thị.

Việc chuyển sang factor cũng tối ưu hóa bộ nhớ, đồng thời cho phép sử dụng nhiều hàm thống kê chuyên biệt như table(), summary(), tapply(), hoặc mô hình phân loại như glm().

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

Với mỗi biến định tính, tạo bảng tần suất, tỷ lệ phần trăm, biểu đồ và nhận xét.

Biến Gender

#Bảng tần suất và tỷ lệ
gender_freq <- table(data$Gender)
gender_prop <- prop.table(gender_freq) * 100
gender_table <- data.frame(Frequency = gender_freq, Percentage = gender_prop)
print(gender_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1              F           7170               F        50.99936
## 2              M           6889               M        49.00064
#Biểu đồ tròn
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
ggplot(data, aes(x = "", fill = Gender)) +
  geom_bar(width = 1) +
  coord_polar("y") +
  labs(title = "Phân bố Giới tính", fill = "Gender") +
  theme_void()

Kết quả phân tích cho thấy trong tổng số quan sát, có 7170 khách hàng là nữ (chiếm 51%) và 6889 khách hàng là nam (chiếm 49%). Sự phân bố giới tính giữa nam và nữ khá cân bằng. Biểu đồ tròn minh họa rõ sự tương đồng về tỷ lệ giới tính trong tập dữ liệu.

Biến MaritalStatus

#Bảng tần suất và tỷ lệ
marital_freq <- table(data$MaritalStatus)
marital_prop <- prop.table(marital_freq) * 100
marital_table <- data.frame(Frequency = marital_freq, Percentage = marital_prop)
print(marital_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1              M           6866               M        48.83704
## 2              S           7193               S        51.16296
# Biểu đồ cột
ggplot(data, aes(x = MaritalStatus, fill = MaritalStatus)) +
  geom_bar() +
  labs(title = "Phân bố Tình trạng Hôn nhân", x = "Marital Status", y = "Số lượng") +
  theme_minimal()

Trong tập dữ liệu, số lượng khách hàng độc thân là 7193 người (chiếm 51.16%), trong khi đã kết hôn là 6866 người (48.84%). Phân bố tình trạng hôn nhân giữa hai nhóm này cũng khá đồng đều, với sự chênh lệch không đáng kể. Biểu đồ cột cho thấy mức độ tương đương giữa hai nhóm.

Biến Homeowner

#Bảng tần suất và tỷ lệ
homeowner_freq <- table(data$Homeowner)
homeowner_prop <- prop.table(homeowner_freq) * 100
homeowner_table <- data.frame(Frequency = homeowner_freq, Percentage = homeowner_prop)
print(homeowner_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1              N           5615               N        39.93883
## 2              Y           8444               Y        60.06117
#Biểu đồ tròn
ggplot(data, aes(x = "", fill = Homeowner)) +
  geom_bar(width = 1) +
  coord_polar("y") +
  labs(title = "Phân bố Tình trạng Sở hữu Nhà", fill = "Homeowner") +
  theme_void()

Tỷ lệ khách hàng sở hữu nhà (Y) chiếm ưu thế với 8444 người (60.06%) so với nhóm không sở hữu nhà (N) là 5615 người (39.94%). Sự chênh lệch này cho thấy đa số khách hàng trong mẫu có mức độ ổn định nhà ở cao. Biểu đồ tròn làm rõ sự chênh lệch giữa hai nhóm.

Biến AnnualIncome

#Bảng tần suất và tỷ lệ
income_freq <- table(data$AnnualIncome)
income_prop <- prop.table(income_freq) * 100
income_table <- data.frame(Frequency = income_freq, Percentage = income_prop)
print(income_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1    $10K - $30K           3090     $10K - $30K       21.978804
## 2  $110K - $130K            643   $110K - $130K        4.573583
## 3  $130K - $150K            760   $130K - $150K        5.405790
## 4        $150K +            273         $150K +        1.941817
## 5    $30K - $50K           4601     $30K - $50K       32.726367
## 6    $50K - $70K           2370     $50K - $70K       16.857529
## 7    $70K - $90K           1709     $70K - $90K       12.155914
## 8   $90K - $110K            613    $90K - $110K        4.360196
#Biểu đồ cột
ggplot(data, aes(x = AnnualIncome, fill = AnnualIncome)) +
  geom_bar() +
  labs(title = "Phân bố Thu nhập Hàng năm", x = "Annual Income", y = "Số lượng") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Thu nhập của khách hàng được chia thành nhiều nhóm. Phân khúc phổ biến nhất là từ $30K–$50K (32.73%) và $10K–$30K (21.98%). Trong khi đó, nhóm có thu nhập trên $150K chỉ chiếm 1.94%. Phân bố thu nhập cho thấy đa số khách hàng thuộc tầng lớp có thu nhập trung bình – thấp. Biểu đồ cột minh họa sự phân bố không đồng đều và tập trung ở mức thu nhập thấp và trung bình.

Biến City

city_freq <- table(data$City) # Tạo bảng tần suất

city_prop <- prop.table(city_freq) * 100 # Tính tỷ lệ phần trăm


city_table <- data.frame(City = names(city_freq), 
                        Frequency = as.vector(city_freq), 
                        Percentage = as.vector(city_prop)) # Chuyển thành data.frame

print(city_table) # Hiển thị toàn bộ bảng
##             City Frequency Percentage
## 1       Acapulco       383  2.7242336
## 2     Bellingham       143  1.0171420
## 3  Beverly Hills       811  5.7685468
## 4      Bremerton       834  5.9321431
## 5        Camacho       452  3.2150224
## 6    Guadalajara        75  0.5334661
## 7        Hidalgo       845  6.0103848
## 8    Los Angeles       926  6.5865282
## 9         Merida       654  4.6518245
## 10   Mexico City       194  1.3798990
## 11       Orizaba       464  3.3003770
## 12      Portland       876  6.2308841
## 13         Salem      1386  9.8584537
## 14    San Andres       621  4.4170994
## 15     San Diego       866  6.1597553
## 16 San Francisco       130  0.9246746
## 17       Seattle       922  6.5580767
## 18       Spokane       875  6.2237712
## 19        Tacoma      1257  8.9408920
## 20     Vancouver       633  4.5024539
## 21      Victoria       176  1.2518671
## 22   Walla Walla       160  1.1380610
## 23        Yakima       376  2.6744434
ggplot(city_table, aes(x = City, y = Frequency, fill = City)) +
  geom_bar(stat = "identity") +
  labs(title = "Phân bố Thành phố", x = "Thành phố", y = "Số lượng") +
  theme_minimal()+
   theme(axis.text.x = element_text(angle = 45, hjust = 1))

Khách hàng đến từ nhiều thành phố khác nhau, trong đó Salem (9.86%), Tacoma (8.94%) và Zacatecas (9.23%) là những nơi có số lượng khách hàng cao nhất. Những thành phố như San Francisco (0.92%) và Guadalajara (0.53%) lại có số lượng ít hơn nhiều. Biểu đồ cột cho thấy sự phân hóa rõ rệt theo vùng địa lý.

Biến StateorProvince

#Bảng tần suất và tỷ lệ
state_freq <- table(data$StateorProvince)
state_prop <- prop.table(state_freq) * 100
state_table <- data.frame(Frequency = state_freq, Percentage = state_prop)
print(state_table)
##    Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1              BC            809              BC       5.7543211
## 2              CA           2733              CA      19.4395049
## 3              DF            815              DF       5.7969984
## 4        Guerrero            383        Guerrero       2.7242336
## 5         Jalisco             75         Jalisco       0.5334661
## 6              OR           2262              OR      16.0893378
## 7        Veracruz            464        Veracruz       3.3003770
## 8              WA           4567              WA      32.4845295
## 9         Yucatan            654         Yucatan       4.6518245
## 10      Zacatecas           1297       Zacatecas       9.2254072
#Biểu đồ cột
ggplot(data, aes(x = StateorProvince, fill = StateorProvince)) +
  geom_bar() +
  labs(title = "Phân bố Bang/Tỉnh", x = "State or Province", y = "Số lượng") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Phân bố theo bang hoặc tỉnh cho thấy Washington (WA) là khu vực chiếm tỷ trọng lớn nhất với 32.48% khách hàng, tiếp theo là California (CA) với 19.44% và Oregon (OR) với 16.09%. Điều này phản ánh sự tập trung dân số tại một số bang lớn. Biểu đồ cột làm rõ sự phân bố không đồng đều này.

Biến Country

#Bảng tần suất và tỷ lệ
country_freq <- table(data$Country)
country_prop <- prop.table(country_freq) * 100
country_table <- data.frame(Frequency = country_freq, Percentage = country_prop)
print(country_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1         Canada            809          Canada        5.754321
## 2         Mexico           3688          Mexico       26.232307
## 3            USA           9562             USA       68.013372
#Biểu đồ cột
ggplot(data, aes(x = Country, fill = Country)) +
  geom_bar() +
  labs(title = "Phân bố Quốc gia", x = "Country", y = "Số lượng") +
  theme_minimal()

Khách hàng chủ yếu đến từ Hoa Kỳ (68.01%), sau đó là Mexico (26.23%) và Canada (5.75%). Dữ liệu cho thấy thị trường chính của siêu thị tập trung tại Mỹ. Biểu đồ cột nhấn mạnh sự áp đảo của khách hàng từ Hoa Kỳ.

Biến ProductFamily

#Bảng tần suất và tỷ lệ
prod_family_freq <- table(data$ProductFamily)
prod_family_prop <- prop.table(prod_family_freq) * 100
prod_family_table <- data.frame(Frequency = prod_family_freq, Percentage = prod_family_prop)
print(prod_family_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1          Drink           1250           Drink        8.891102
## 2           Food          10153            Food       72.217085
## 3 Non-Consumable           2656  Non-Consumable       18.891813
#Biểu đồ cột
ggplot(data, aes(x = ProductFamily, fill = ProductFamily)) +
  geom_bar() +
  labs(title = "Phân bố Nhóm Sản phẩm", x = "Product Family", y = "Số lượng") +
  theme_minimal()

Nhóm sản phẩm Food (Thực phẩm) chiếm ưu thế vượt trội (72.22%), tiếp đến là Non-Consumable (Phi tiêu dùng) với 18.89% và Drink (Đồ uống) là 8.89%. Điều này phản ánh siêu thị chủ yếu kinh doanh thực phẩm. Biểu đồ cột làm nổi bật tỷ trọng lớn của nhóm thực phẩm.

Biến ProductDepartment

#Bảng tần suất và tỷ lệ
prod_dept_freq <- table(data$ProductDepartment)
prod_dept_prop <- prop.table(prod_dept_freq) * 100
prod_dept_table <- data.frame(Frequency = prod_dept_freq, Percentage = prod_dept_prop)
print(prod_dept_table)
##         Frequency.Var1 Frequency.Freq     Percentage.Var1 Percentage.Freq
## 1  Alcoholic Beverages            356 Alcoholic Beverages       2.5321858
## 2          Baked Goods            425         Baked Goods       3.0229746
## 3         Baking Goods           1072        Baking Goods       7.6250089
## 4            Beverages            680           Beverages       4.8367594
## 5      Breakfast Foods            188     Breakfast Foods       1.3372217
## 6         Canned Foods            977        Canned Foods       6.9492852
## 7      Canned Products            109     Canned Products       0.7753041
## 8             Carousel             59            Carousel       0.4196600
## 9             Checkout             82            Checkout       0.5832563
## 10               Dairy            903               Dairy       6.4229319
## 11                Deli            699                Deli       4.9719041
## 12                Eggs            198                Eggs       1.4083505
## 13        Frozen Foods           1382        Frozen Foods       9.8300021
## 14  Health and Hygiene            893  Health and Hygiene       6.3518031
## 15           Household           1420           Household      10.1002916
## 16                Meat             89                Meat       0.6330464
## 17         Periodicals            202         Periodicals       1.4368020
## 18             Produce           1994             Produce      14.1830856
## 19             Seafood            102             Seafood       0.7255139
## 20         Snack Foods           1600         Snack Foods      11.3806103
## 21              Snacks            352              Snacks       2.5037343
## 22       Starchy Foods            277       Starchy Foods       1.9702682
#Biểu đồ cột
ggplot(data, aes(x = ProductDepartment, fill = ProductDepartment)) +
  geom_bar() +
  labs(title = "Phân bố Bộ phận Sản phẩm", x = "Product Department", y = "Số lượng") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Danh mục có tần suất cao nhất là Vegetables (12.29%), Snack Foods (11.38%), và Produce (14.18%). Một số danh mục hiếm như Canned Oysters, Miscellaneous, và Candles có tỷ lệ dưới 0.5%. Phân tích này cho thấy sự tập trung mạnh mẽ vào các danh mục thực phẩm tươi sống và đồ ăn nhẹ. Biểu đồ cột giúp trực quan hóa rõ nét 10 danh mục phổ biến nhất.

Biến ProductCategory

# Tạo bảng tần suất
prod_cat_freq <- table(data$ProductCategory)

# Tính tỷ lệ phần trăm
prod_cat_prop <- prop.table(prod_cat_freq) * 100

# Chuyển thành data.frame
prod_cat_table <- data.frame(Category = names(prod_cat_freq), 
                            Frequency = as.vector(prod_cat_freq), 
                            Percentage = as.vector(prod_cat_prop))

# Hiển thị toàn bộ bảng
print(prod_cat_table)
##                Category Frequency Percentage
## 1          Baking Goods       484  3.4426346
## 2     Bathroom Products       365  2.5962017
## 3         Beer and Wine       356  2.5321858
## 4                 Bread       425  3.0229746
## 5       Breakfast Foods       417  2.9660716
## 6               Candles        45  0.3200797
## 7                 Candy       352  2.5037343
## 8      Canned Anchovies        44  0.3129668
## 9          Canned Clams        53  0.3769827
## 10       Canned Oysters        35  0.2489508
## 11      Canned Sardines        40  0.2845153
## 12        Canned Shrimp        38  0.2702895
## 13          Canned Soup       404  2.8736041
## 14          Canned Tuna        87  0.6188207
## 15 Carbonated Beverages       154  1.0953837
## 16    Cleaning Supplies       189  1.3443346
## 17        Cold Remedies        93  0.6614980
## 18                Dairy       903  6.4229319
## 19        Decongestants        85  0.6045949
## 20               Drinks       135  0.9602390
## 21                 Eggs       198  1.4083505
## 22           Electrical       355  2.5250729
## 23      Frozen Desserts       323  2.2974607
## 24       Frozen Entrees       118  0.8393200
## 25                Fruit       765  5.4413543
## 26             Hardware       129  0.9175617
## 27        Hot Beverages       226  1.6075112
## 28              Hygiene       197  1.4012376
## 29     Jams and Jellies       588  4.1823743
## 30     Kitchen Products       217  1.5434953
## 31            Magazines       202  1.4368020
## 32                 Meat       761  5.4129028
## 33        Miscellaneous        42  0.2987410
## 34  Packaged Vegetables        48  0.3414183
## 35       Pain Relievers       192  1.3656732
## 36       Paper Products       345  2.4539441
## 37                Pizza       194  1.3798990
## 38     Plastic Products       141  1.0029163
## 39 Pure Juice Beverages       165  1.1736254
## 40              Seafood       102  0.7255139
## 41          Side Dishes       153  1.0882709
## 42          Snack Foods      1600 11.3806103
## 43            Specialty       289  2.0556227
## 44        Starchy Foods       277  1.9702682
## 45           Vegetables      1728 12.2910591
# Biểu đồ cột 
ggplot(prod_cat_table, aes(x = Category, y = Frequency)) +
  geom_bar(stat = "identity") +
  labs(title = "Phân bố Danh mục Sản phẩm", x = "Danh mục Sản phẩm", y = "Số lượng") +
  theme_minimal() +
   theme(axis.text.x = element_text(angle = 45, hjust = 1))

Danh mục có tần suất cao nhất là Vegetables (12.29%), Snack Foods (11.38%), và Produce (14.18%). Một số danh mục hiếm như Canned Oysters, Miscellaneous, và Candles có tỷ lệ dưới 0.5%. Phân tích này cho thấy sự tập trung mạnh mẽ vào các danh mục thực phẩm tươi sống và đồ ăn nhẹ. Biểu đồ cột giúp trực quan hóa rõ nét 10 danh mục phổ biến nhất.

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

Trong phần này, mục tiêu là ước lượng khoảng tin cậy cho tỷ lệ của một số hạng mục định tính cụ thể và thực hiện kiểm định giả thuyết một tỷ lệ, nhằm kiểm tra xem tỷ lệ quan sát được trong mẫu có khác biệt đáng kể so với một tỷ lệ giả định hay không.

Biến Gender (Hạng mục: Nữ)

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

H₀: Tỷ lệ nữ trong mẫu bằng 50% (p = 0.5)

H₁: Tỷ lệ nữ khác 50%

#Ước lượng Khoảng Tin cậy
n <- nrow(data)
female_count <- sum(data$Gender == "F")
prop_female <- female_count / n
se_female <- sqrt(prop_female * (1 - prop_female) / n)
ci_female <- prop_female + c(-1, 1) * 1.96 * se_female
cat("Khoảng tin cậy 95% cho tỷ lệ Nữ:", round(ci_female * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Nữ: 50.17 51.83 %
#Kiểm định Giả thuyết (H0: Tỷ lệ Nữ = 0.5)
prop.test(female_count, n, p = 0.5, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  female_count out of n, null probability 0.5
## X-squared = 5.5765, df = 1, p-value = 0.0182
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5016931 0.5182886
## sample estimates:
##         p 
## 0.5099936

Kết quả phân tích

Khoảng tin cậy 95%: [50.17%, 51.83%]

Giá trị p-value: 0.02 < 0.05

Nhận xét

Vì khoảng tin cậy không chứa đúng 50%, và giá trị p nhỏ hơn 0.05, ta có đủ bằng chứng để bác bỏ giả thuyết H0. Như vậy, tỷ lệ khách hàng nữ thực tế có sự khác biệt đáng kể so với mức giả định 50%, mặc dù sự khác biệt là nhỏ. Điều này cho thấy khách hàng nữ chiếm tỷ lệ nhỉnh hơn một chút so với khách hàng nam.

Biến MaritalStatus (Hạng mục: Đã kết hôn)

Giả thuyết kiểm định

H0: Tỷ lệ đã kết hôn = 50%

H1: Tỷ lệ đã kết hôn ≠ 50%

#Ước lượng Khoảng Tin cậy
married_count <- sum(data$MaritalStatus == "M")
prop_married <- married_count / n
se_married <- sqrt(prop_married * (1 - prop_married) / n)
ci_married <- prop_married + c(-1, 1) * 1.96 * se_married
cat("Khoảng tin cậy 95% cho tỷ lệ Đã kết hôn:", round(ci_married * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Đã kết hôn: 48.01 49.66 %
#Kiểm định Giả thuyết (H0: Tỷ lệ Đã kết hôn = 0.5)
prop.test(married_count, n, p = 0.5, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  married_count out of n, null probability 0.5
## X-squared = 7.5593, df = 1, p-value = 0.00597
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.4800765 0.4966708
## sample estimates:
##         p 
## 0.4883704

Kết quả phân tích

Khoảng tin cậy 95%: [48.01%, 49.66%]

p-value: 0.006 < 0.05

Nhận xét Tỷ lệ khách hàng đã kết hôn thấp hơn đáng kể so với mức giả định 50%. Khoảng tin cậy không chứa 0.5 và p-value nhỏ cho thấy có ý nghĩa thống kê. Do đó, đa phần khách hàng là người chưa kết hôn, điều này có thể gợi ý về xu hướng chi tiêu hoặc lối sống khác biệt.

Biến Homeowner (Hạng mục: Có nhà)

Giả thuyết kiểm định

H0: Tỷ lệ sở hữu nhà = 60%

H1: Tỷ lệ sở hữu nhà ≠ 60%

#Ước lượng Khoảng Tin cậy
homeowner_count <- sum(data$Homeowner == "Y")
prop_homeowner <- homeowner_count / n
se_homeowner <- sqrt(prop_homeowner * (1 - prop_homeowner) / n)
ci_homeowner <- prop_homeowner + c(-1, 1) * 1.96 * se_homeowner
cat("Khoảng tin cậy 95% cho tỷ lệ Sở hữu Nhà:", round(ci_homeowner * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Sở hữu Nhà: 59.25 60.87 %
#Kiểm định Giả thuyết (H0: Tỷ lệ Sở hữu Nhà = 0.6)
prop.test(homeowner_count, n, p = 0.6, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  homeowner_count out of n, null probability 0.6
## X-squared = 0.019445, df = 1, p-value = 0.8891
## alternative hypothesis: true p is not equal to 0.6
## 95 percent confidence interval:
##  0.5924537 0.6087145
## sample estimates:
##         p 
## 0.6006117

Kết quả phân tích

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

p-value: 0.90 > 0.05

Nhận xét Khoảng tin cậy bao gồm giá trị 60% và p-value rất lớn, do đó không có đủ bằng chứng để bác bỏ giả thuyết H0. Điều này cho thấy tỷ lệ khách hàng sở hữu nhà phù hợp với giả định, tức là khoảng 60% khách hàng là chủ sở hữu nhà.

Biến AnnualIncome (Hạng mục: $30K - $50K)

Giả thuyết kiểm định

H0: Tỷ lệ thu nhập này = 30%

H1: Tỷ lệ ≠ 30%

#Ước lượng Khoảng Tin cậy
income_count <- sum(data$AnnualIncome == "$30K - $50K")
prop_income <- income_count / n
se_income <- sqrt(prop_income * (1 - prop_income) / n)
ci_income <- prop_income + c(-1, 1) * 1.96 * se_income
cat("Khoảng tin cậy 95% cho tỷ lệ $30K - $50K:", round(ci_income * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ $30K - $50K: 31.95 33.5 %
#Kiểm định Giả thuyết (H0: Tỷ lệ $30K - $50K = 0.3)
prop.test(income_count, n, p = 0.3, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  income_count out of n, null probability 0.3
## X-squared = 49.633, df = 1, p-value = 1.854e-12
## alternative hypothesis: true p is not equal to 0.3
## 95 percent confidence interval:
##  0.3195204 0.3351018
## sample estimates:
##         p 
## 0.3272637

Kết quả phân tích

Khoảng tin cậy 95%: [31.95%, 33.51%]

p-value: 2e-12 < 0.05

Nhận xét Tỷ lệ khách hàng thuộc nhóm thu nhập 30K–50K cao hơn đáng kể so với 30%, và điều này có ý nghĩa thống kê mạnh. Kết quả cho thấy đây là nhóm thu nhập phổ biến, có thể là mục tiêu tiếp thị hiệu quả.

Biến City (Hạng mục: Salem)

Giả thuyết kiểm định

H0: Tỷ lệ khách hàng từ Salem = 15%

H1: Tỷ lệ ≠ 15%

#Ước lượng Khoảng Tin cậy
city_count <- sum(data$City == "Salem")
prop_city <- city_count / n
se_city <- sqrt(prop_city * (1 - prop_city) / n)
ci_city <- prop_city + c(-1, 1) * 1.96 * se_city
cat("Khoảng tin cậy 95% cho tỷ lệ Salem:", round(ci_city * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Salem: 9.37 10.35 %
#Kiểm định Giả thuyết (H0: Tỷ lệ Salem = 0.15)
prop.test(city_count, n, p = 0.15, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  city_count out of n, null probability 0.15
## X-squared = 291.09, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.15
## 95 percent confidence interval:
##  0.09373125 0.10365871
## sample estimates:
##          p 
## 0.09858454

Kết quả phân tích

Khoảng tin cậy 95%: [9.37%, 10.35%]

p-value: < 2e-16

Nhận xét Tỷ lệ khách hàng đến từ Salem thấp hơn nhiều so với giả định 15%. Khoảng tin cậy nhỏ và p rất thấp cho thấy sự khác biệt có ý nghĩa rõ rệt. Điều này cho thấy Salem không phải thị trường trọng yếu trong dữ liệu hiện tại.

Biến StateorProvince (Hạng mục: WA)

Giả thuyết kiểm định

H0: Tỷ lệ khách hàng ở bang WA = 40%

H1: Tỷ lệ ≠ 40%

#Ước lượng Khoảng Tin cậy
state_count <- sum(data$StateorProvince == "WA")
prop_state <- state_count / n
se_state <- sqrt(prop_state * (1 - prop_state) / n)
ci_state <- prop_state + c(-1, 1) * 1.96 * se_state
cat("Khoảng tin cậy 95% cho tỷ lệ WA:", round(ci_state * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ WA: 31.71 33.26 %
#Kiểm định Giả thuyết (H0: Tỷ lệ WA = 0.4)
prop.test(state_count, n, p = 0.4, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  state_count out of n, null probability 0.4
## X-squared = 330.56, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.4
## 95 percent confidence interval:
##  0.3171175 0.3326693
## sample estimates:
##         p 
## 0.3248453

Kết quả phân tích

Khoảng tin cậy 95%: [31.71%, 33.26%]

p-value: < 2e-16

Nhận xét Tỷ lệ khách hàng từ bang WA thấp hơn đáng kể so với giả định. Điều này cho thấy WA không chiếm ưu thế trong mẫu, và có thể cần điều chỉnh nếu mẫu cần đại diện cho bang này.

# Đếm số lượng giao dịch cho Canada và Mexico
canada_count <- sum(data$Country == "Canada")  # 809
mexico_count <- sum(data$Country == "Mexico")  # 3688
n <- nrow(data)  # 14059
# Kiểm định giả thuyết
prop.test(c(canada_count, mexico_count), n = c(n, n), 
          p = c(0.5, 0.5), alternative = "less", conf.level = 0.95)
## 
##  2-sample test for given proportions with continuity correction
## 
## data:  c(canada_count, mexico_count) out of c(n, n), null probabilities c(0.5, 0.5)
## X-squared = 14183, df = 2, p-value < 2.2e-16
## alternative hypothesis: two.sided
## null values:
## prop 1 prop 2 
##    0.5    0.5 
## sample estimates:
##     prop 1     prop 2 
## 0.05754321 0.26232307

Biến Country (Hạng mục: USA)

Giả thuyết kiểm định

H0: Tỷ lệ khách hàng từ USA = 80%

H1: Tỷ lệ ≠ 80%

#Ước lượng Khoảng Tin cậy
country_count <- sum(data$Country == "USA")
prop_country <- country_count / n
se_country <- sqrt(prop_country * (1 - prop_country) / n)
ci_country <- prop_country + c(-1, 1) * 1.96 * se_country
cat("Khoảng tin cậy 95% cho tỷ lệ USA:", round(ci_country * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ USA: 67.24 68.78 %
#Kiểm định Giả thuyết (H0: Tỷ lệ USA = 0.8)
prop.test(country_count, n, p = 0.8, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  country_count out of n, null probability 0.8
## X-squared = 1261.7, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.8
## 95 percent confidence interval:
##  0.6723397 0.6878289
## sample estimates:
##         p 
## 0.6801337

Kết quả phân tích

Khoảng tin cậy 95%: [67.24%, 68.78%]

p-value: < 2e-16

Nhận xét Tỷ lệ khách hàng từ Hoa Kỳ thấp hơn hẳn so với giả định 80%. Điều này cho thấy dữ liệu không hoàn toàn tập trung vào thị trường Mỹ, có thể do doanh nghiệp mở rộng ra quốc tế hoặc lấy mẫu không đại diện.

Biến ProductFamily (Hạng mục: Food)

Giả thuyết kiểm định

H0: Tỷ lệ ≥ 70%

H1: Tỷ lệ < 70%

#Ước lượng Khoảng Tin cậy
food_count <- sum(data$ProductFamily == "Food")
prop_food <- food_count / n
se_food <- sqrt(prop_food * (1 - prop_food) / n)
ci_food <- prop_food + c(-1, 1) * 1.96 * se_food
cat("Khoảng tin cậy 95% cho tỷ lệ Food:", round(ci_food * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Food: 71.48 72.96 %
#Kiểm định Giả thuyết (H0: Tỷ lệ Food ≥ 0.7)
prop.test(food_count, n, p = 0.7, alternative = "greater", conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  food_count out of n, null probability 0.7
## X-squared = 32.802, df = 1, p-value = 5.101e-09
## alternative hypothesis: true p is greater than 0.7
## 95 percent confidence interval:
##  0.7158789 1.0000000
## sample estimates:
##         p 
## 0.7221709

Kết quả phân tích

Khoảng tin cậy 95%: [71.59%, 100%]

p-value: 5e-09

Nhận xét Vì p rất nhỏ và toàn bộ khoảng tin cậy nằm trên 70%, có đủ bằng chứng khẳng định rằng tỷ lệ sản phẩm thuộc nhóm “Food” lớn hơn 70%, cho thấy nhóm này chiếm ưu thế lớn trong danh mục.

Biến ProductDepartment (Hạng mục: Snack Foods)

Giả thuyết kiểm định

H0: Tỷ lệ Snack Foods = 15%

H1: Tỷ lệ ≠ 15%

#Ước lượng Khoảng Tin cậy
dept_count <- sum(data$ProductDepartment == "Snack Foods")
prop_dept <- dept_count / n
se_dept <- sqrt(prop_dept * (1 - prop_dept) / n)
ci_dept <- prop_dept + c(-1, 1) * 1.96 * se_dept
cat("Khoảng tin cậy 95% cho tỷ lệ Snack Foods:", round(ci_dept * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Snack Foods: 10.86 11.91 %
#Kiểm định Giả thuyết (H0: Tỷ lệ Snack Foods = 0.15)
prop.test(dept_count, n, p = 0.15, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  dept_count out of n, null probability 0.15
## X-squared = 144.17, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.15
## 95 percent confidence interval:
##  0.1086269 0.1191977
## sample estimates:
##         p 
## 0.1138061

Kết quả phân tích

Khoảng tin cậy 95%: [10.86%, 11.91%]

p-value: < 2e-16

Nhận xét Tỷ lệ sản phẩm Snack Foods thấp hơn đáng kể so với giả định. Có thể thấy rằng mặc dù phổ biến nhưng chưa đến mức chiếm 15%, và doanh nghiệp có thể cân nhắc phân phối phù hợp hơn.

Biến ProductCategory (Hạng mục: Snack Foods)

#Ước lượng Khoảng Tin cậy
cat_count <- sum(data$ProductCategory == "Snack Foods")
prop_cat <- cat_count / n
se_cat <- sqrt(prop_cat * (1 - prop_cat) / n)
ci_cat <- prop_cat + c(-1, 1) * 1.96 * se_cat
cat("Khoảng tin cậy 95% cho tỷ lệ Snack Foods:", round(ci_cat * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Snack Foods: 10.86 11.91 %
#Kiểm định Giả thuyết (H0: Tỷ lệ Snack Foods = 0.15)
prop.test(cat_count, n, p = 0.15, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  cat_count out of n, null probability 0.15
## X-squared = 144.17, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.15
## 95 percent confidence interval:
##  0.1086269 0.1191977
## sample estimates:
##         p 
## 0.1138061

Kết quả phân tích

Khoảng tin cậy 95%: [10.86%, 11.91%]

p-value: < 2e-16

Nhận xét: Tỷ lệ chỉ khoảng 11.38%, thấp hơn 15% nên cũng bác bỏ giả thuyết H0.

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

** Cặp MaritalStatus và Homeowner**

#Bảng Tần suất Chéo
cross_table1 <- table(data$MaritalStatus, data$Homeowner)
cross_prop1 <- prop.table(cross_table1, margin = 1) * 100
print(cross_table1)
##    
##        N    Y
##   M 1719 5147
##   S 3896 3297
print(round(cross_prop1, 2))
##    
##         N     Y
##   M 25.04 74.96
##   S 54.16 45.84

Dữ liệu được phân loại theo hai biến định tính: MaritalStatus (Tình trạng hôn nhân: M – Married, S – Single) và Homeowner (Sở hữu nhà: Y – Yes, N – No). Bảng tần suất cho thấy người đã kết hôn chiếm tỷ lệ sở hữu nhà cao hơn (74,96%) so với người độc thân (45,84%). Điều này thể hiện sự khác biệt đáng kể trong hành vi sở hữu nhà giữa hai nhóm hôn nhân.

#Trực quan hóa
ggplot(data, aes(x = MaritalStatus, fill = Homeowner)) +
  geom_bar(position = "fill") +
  labs(title = "Sở hữu Nhà theo Tình trạng Hôn nhân", x = "Marital Status", y = "Tỷ lệ", fill = "Homeowner") +
  theme_minimal()

Biểu đồ thanh tỷ lệ (stacked bar chart theo tỷ lệ phần trăm) trực quan hóa điều này rất rõ ràng: người đã kết hôn có xu hướng sở hữu nhà nhiều hơn đáng kể so với người độc thân.

Nhằm kiểm định xem MaritalStatus và Homeowner có mối quan hệ thống kê hay không, kiểm định Chi-bình phương được sử dụng.

Giả thuyết H₀: Hai biến MaritalStatus và Homeowner là độc lập.

Giả thuyết H₁: Hai biến có mối liên hệ thống kê.

#Kiểm định Chi-bình phương
chi_test1 <- chisq.test(cross_table1)
print(chi_test1)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  cross_table1
## X-squared = 1241.2, df = 1, p-value < 2.2e-16

Kết quả:

Giá trị thống kê chi bình phương (X²) = 1241

Bậc tự do (df) = 1

p-value < 2e-16

Nhận xét:

Kiểm định Chi-bình phương (Pearson’s Chi-squared Test) nhằm xác định xem hai biến định tính có độc lập nhau hay không. Ở đây, giá trị p rất nhỏ (< 0,05), cho thấy bác bỏ giả thuyết độc lập, tức là có mối liên hệ có ý nghĩa thống kê giữa tình trạng hôn nhân và sở hữu nhà. Cụ thể, người đã kết hôn có xu hướng sở hữu nhà nhiều hơn so với người độc thân.

Cặp AnnualIncome và ProductFamily

#Bảng Tần suất Chéo
cross_table2 <- table(data$AnnualIncome, data$ProductFamily)
cross_prop2 <- prop.table(cross_table2, margin = 1) * 100
print(cross_table2)
##                
##                 Drink Food Non-Consumable
##   $10K - $30K     267 2232            591
##   $110K - $130K    59  468            116
##   $130K - $150K    56  556            148
##   $150K +          25  199             49
##   $30K - $50K     421 3340            840
##   $50K - $70K     193 1705            472
##   $70K - $90K     156 1221            332
##   $90K - $110K     73  432            108
print(round(cross_prop2, 2))
##                
##                 Drink  Food Non-Consumable
##   $10K - $30K    8.64 72.23          19.13
##   $110K - $130K  9.18 72.78          18.04
##   $130K - $150K  7.37 73.16          19.47
##   $150K +        9.16 72.89          17.95
##   $30K - $50K    9.15 72.59          18.26
##   $50K - $70K    8.14 71.94          19.92
##   $70K - $90K    9.13 71.45          19.43
##   $90K - $110K  11.91 70.47          17.62

Bảng cho thấy phần lớn các nhóm thu nhập tiêu dùng chủ yếu ở nhóm sản phẩm “Food” (chiếm khoảng 70–73%), tiếp theo là “Non-Consumable” và thấp nhất là “Drink”, bất kể mức thu nhập. Tỷ lệ này tương đối ổn định giữa các nhóm thu nhập, cho thấy sự phân bố đồng đều theo nhóm sản phẩm.

#Trực quan hóa
ggplot(data, aes(x = AnnualIncome, fill = ProductFamily)) +
  geom_bar(position = "fill") +
  labs(title = "Nhóm Sản phẩm theo Thu nhập", x = "Annual Income", y = "Tỷ lệ", fill = "Product Family") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Biểu đồ tỷ lệ theo nhóm thu nhập cho thấy dù thu nhập tăng hay giảm, tỷ trọng các nhóm sản phẩm vẫn không có sự chênh lệch lớn.

Nhằm kiểm định xem AnnualIncome và ProductFamily có mối quan hệ thống kê hay không, kiểm định Chi-bình phương được sử dụng.

Giả thuyết H₀: Hai biến AnnualIncomer và ProductFamily là độc lập.

Giả thuyết H₁: Hai biến có mối liên hệ thống kê.

#Kiểm định Chi-bình phương
chi_test2 <- chisq.test(cross_table2)
print(chi_test2)
## 
##  Pearson's Chi-squared test
## 
## data:  cross_table2
## X-squared = 14.84, df = 14, p-value = 0.3892

Kết quả:

Giá trị thống kê X² = 15

df = 14

p-value = 0.4

Nhận xét:

Với p-value = 0.4 (> 0.05), ta không bác bỏ giả thuyết độc lập, tức là không có bằng chứng thống kê cho thấy mối quan hệ giữa thu nhập và loại sản phẩm được tiêu dùng. Điều này cho thấy hành vi mua sắm theo nhóm sản phẩm dường như không bị ảnh hưởng bởi mức thu nhập.

** Cặp Gender và MaritalStatus**

#Bảng tần suất chéo
cross_table3 <- table(data$Gender, data$ MaritalStatus)
cross_prop3 <- prop.table(cross_table3, margin = 1) * 100
print(cross_table3)
##    
##        M    S
##   F 3602 3568
##   M 3264 3625
print(round(cross_prop3, 2))
##    
##         M     S
##   F 50.24 49.76
##   M 47.38 52.62

Nhìn chung, kết quả cho thấy tỷ lệ người kết hôn và độc thân giữa nam và nữ là khá cân bằng. Trong đó, nữ giới có tỷ lệ kết hôn cao hơn một chút so với nam giới (50.24% so với 47.38%), trong khi nam giới có tỷ lệ độc thân cao hơn (52.62%).

# Biểu đồ cột chồng
ggplot(data, aes(x = Gender, fill = MaritalStatus)) +
  geom_bar(position = "fill") +
  labs(title = "Phân bố Tình trạng hôn nhân theo Giới tính", x = "Gender", y = "Tỷ lệ", fill = " MaritalStatus") +
  theme_minimal() +
   theme(axis.text.x = element_text(angle = 45, hjust = 1))

Nhằm kiểm định xem Gender và MaritalStatus có mối quan hệ thống kê hay không, kiểm định Chi-bình phương được sử dụng.

Giả thuyết H₀: Hai biến Gender và MaritalStatus là độc lập.

Giả thuyết H₁: Hai biến có mối liên hệ thống kê.

# Kiểm định Chi-bình phương
chi_test3 <- chisq.test(cross_table3)
print(chi_test3)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  cross_table3
## X-squared = 11.365, df = 1, p-value = 0.0007485

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

Giá trị thống kê Chi-squared: X² = 11

Bậc tự do: df = 1

Giá trị p: p-value < 7e-04

Nhận xét: Với giá trị p nhỏ hơn 0.05 rất nhiều (p < 7e-04), ta bác bỏ giả thuyết H₀. Điều này cho thấy có mối liên hệ thống kê rõ rệt giữa giới tính và tình trạng hôn nhân trong tập dữ liệu. Nói cách khác, giới tính có ảnh hưởng đáng kể đến tình trạng hôn nhân của khách hàng siêu thị.

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

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

Phân tích các biến định tính trong tập dữ liệu Supermarket Transactions.csv đã cung cấp những hiểu biết đáng chú ý về đặc điểm nhân khẩu học của khách hàng và hành vi tiêu dùng của họ. Một số phát hiện nổi bật gồm:

  • Giới tính phân bố khá cân bằng, nhưng tỷ lệ nữ có phần nhỉnh hơn (khoảng 51%), điều này có thể phản ánh vai trò thường thấy của phụ nữ trong quyết định mua sắm gia đình.
  • Tình trạng hôn nhân cho thấy gần 49% khách hàng đã kết hôn, gợi ý rằng nhu cầu mua sắm của hộ gia đình là một yếu tố quan trọng trong hành vi tiêu dùng.
  • Tỷ lệ sở hữu nhà cao (khoảng 60%) cho thấy phần lớn khách hàng có mức độ ổn định kinh tế nhất định.
  • Thu nhập phân bố chủ yếu trong nhóm 30.000–50.000 USD (chiếm hơn 32%), cho thấy tập khách hàng chủ yếu thuộc nhóm thu nhập trung bình.
  • Hành vi tiêu dùng tập trung mạnh vào nhóm sản phẩm Thực phẩm (hơn 72%), trong đó các danh mục như Snack FoodsBreakfast Foods cũng chiếm tỷ trọng đáng kể.
  • Các phân tích bảng chéo và kiểm định Chi-squared đã phát hiện những mối liên hệ có ý nghĩa thống kê giữa nhiều cặp biến như: Giới tính – Tình trạng hôn nhân, Tình trạng hôn nhân – Sở hữu nhà, Tình trạng hôn nhân – Nhóm sản phẩm, v.v., cho thấy đặc điểm nhân khẩu học có thể ảnh hưởng đến hành vi mua hàng.

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

Dù đã mang lại nhiều kết quả hữu ích, phân tích vẫn tồn tại một số hạn chế:

  • Giới hạn ở biến định tính: Việc chỉ tập trung vào các biến định tính khiến phân tích thiếu chiều sâu trong việc đo lường cường độ tiêu dùng (ví dụ: giá trị đơn hàng, tần suất mua sắm).
  • Chất lượng và tính đầy đủ của dữ liệu: Một số biến có thể bị thiếu giá trị hoặc chưa được chuẩn hóa hoàn toàn.
  • Kích thước mẫu không đều: Một số nhóm (ví dụ: thành phố Salem hay bang WA) có số lượng quan sát nhỏ, có thể làm giảm độ tin cậy của các kiểm định thống kê liên quan.
  • Chưa kiểm soát yếu tố nhiễu: Một số mối quan hệ quan sát được có thể bị ảnh hưởng bởi các biến ẩn chưa được đưa vào mô hình.

Đề xuất cho doanh nghiệp

Từ các phát hiện trên, có thể đưa ra một số đề xuất như sau:

  • Chiến lược phân khúc khách hàng: Do tỷ lệ khách hàng nữ và đã kết hôn khá cao, doanh nghiệp có thể xây dựng các chương trình khuyến mãi hoặc sản phẩm hướng đến nhóm khách hàng gia đình hoặc phụ nữ nội trợ.
  • Tối ưu hóa danh mục sản phẩm: Với mức độ tiêu dùng cao cho nhóm thực phẩm, đặc biệt là Snack Foods, doanh nghiệp nên tiếp tục mở rộng chủng loại hoặc thương hiệu trong danh mục này.
  • Phân bổ nguồn lực tiếp thị theo khu vực: Vì tỷ lệ khách hàng chênh lệch theo thành phố/bang, cần xem xét lại chiến lược phân phối và quảng bá theo địa phương, đặc biệt tại những nơi có tiềm năng chưa được khai thác như Salem.

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

Phân tích này mở ra một số câu hỏi và hướng nghiên cứu có thể tiếp tục khai thác:

  • Mối quan hệ với các biến định lượng: Liệu thu nhập, độ tuổi hay giá trị hóa đơn trung bình có ảnh hưởng đến lựa chọn nhóm sản phẩm hay không?
  • Phân tích kết hợp định tính và định lượng: Kết hợp thêm các yếu tố như số lượng sản phẩm mua, giá trị giao dịch, hoặc thời gian mua hàng để hiểu sâu hơn hành vi tiêu dùng.
  • Phân cụm khách hàng (Customer segmentation): Có thể áp dụng các kỹ thuật học máy (machine learning) để phân cụm khách hàng dựa trên nhiều biến định tính và định lượng kết hợp.
  • Phân tích xu hướng theo thời gian: Nếu dữ liệu có yếu tố thời gian (ví dụ ngày mua hàng), có thể xem xét hành vi tiêu dùng theo mùa vụ hoặc chu kỳ tuần/tháng.

Phân tích Suy diễn Thống kê trong Bảng Ngẫu nhiên 2x2

** Lý thuyết**

Rủi ro tương đối (Relative Risk)

Khái niệm: Rủi ro tương đối (Relative Risk, viết tắt là RR) là một chỉ số thống kê được sử dụng để so sánh xác suất xảy ra một biến cố (thường là “thành công” hoặc “có đặc điểm”) giữa hai nhóm phân biệt theo biến độc lập. Chỉ số này đặc biệt phổ biến trong các nghiên cứu dịch tễ học dạng thuần tập (cohort studies).

Ký hiệu và công thức:

Gọi \pi_1\pi_2 lần lượt là xác suất thành công ở hai nhóm so sánh, khi đó rủi ro tương đối được định nghĩa như sau:

RR = \frac{\pi_1}{\pi_2}

Giải thích:

RR cho biết xác suất xảy ra sự kiện ở nhóm thứ nhất gấp bao nhiêu lần so với nhóm thứ hai. Nếu:

  • RR = 1`: Không có sự khác biệt giữa hai nhóm.
  • RR > 1`: Nhóm 1 có xác suất xảy ra sự kiện cao hơn nhóm 2.
  • RR < 1`: Nhóm 1 có xác suất xảy ra sự kiện thấp hơn nhóm 2.

Ví dụ minh họa:

Giả sử một nghiên cứu khảo sát về tỷ lệ người “có nhà riêng” giữa hai nhóm người:

Nhóm Có nhà (Success) Không có nhà (Fail) Tổng số
Nhóm A 80 20 100
Nhóm B 40 60 100

Khi đó:

  • _A = = 0.8
  • _B = = 0.4

Suy ra:

RR = \frac{0.8}{0.4} = 2

Kết luận: Xác suất có nhà riêng ở nhóm A gấp 2 lần so với nhóm B.


Tỷ lệ chênh (Odds Ratio)

Khái niệm: Tỷ lệ chênh (Odds Ratio, viết tắt là OR) là một chỉ số thể hiện mức độ chênh lệch giữa tỷ lệ cược xảy ra sự kiện trong hai nhóm. Khác với RR dựa trên xác suất, OR so sánh tỷ lệ giữa xác suất thành công và thất bại trong mỗi nhóm.

Tỷ lệ cược (Odds): Tỷ lệ cược (odd) của một nhóm \(i\) được định nghĩa là:

odd_i = \frac{\pi_i}{1 - \pi_i}

Tỷ lệ chênh giữa hai nhóm \(i\)\(j\):

OR = \frac{odd_i}{odd_j} = \frac{\dfrac{\pi_i}{1 - \pi_i}}{\dfrac{\pi_j}{1 - \pi_j}} = \frac{\pi_i(1 - \pi_j)}{\pi_j(1 - \pi_i)}

Giải thích: OR đo lường mức độ chênh lệch giữa khả năng xảy ra và không xảy ra sự kiện trong hai nhóm. Nếu:

  • OR = 1: Không có sự khác biệt.
  • OR > 1: Nhóm i có tỷ lệ cược thành công cao hơn nhóm j.
  • OR < 1: Nhóm i có tỷ lệ cược thành công thấp hơn nhóm j.

Ví dụ minh họa (tiếp tục từ ví dụ RR):

  • Tỷ lệ cược nhóm A: \frac{0.8}{0.2} = 4
  • Tỷ lệ cược nhóm B: \frac{0.4}{0.6} = \frac{2}{3}

Khi đó:

OR = \frac{4}{2/3} = 6

Kết luận: Tỷ lệ cược thành công (có nhà) ở nhóm A cao gấp 6 lần nhóm B.


So sánh giữa Odds Ratio và Relative Risk

Đặc điểm Rủi ro tương đối (RR) Tỷ lệ chênh (OR)
Công thức \(\frac{\pi_1}{\pi_2}\) \(\frac{\pi_1(1 - \pi_2)}{\pi_2(1 - \pi_1)}\)
Dựa trên Xác suất (probability) Tỷ lệ cược (odds)
Ý nghĩa So sánh khả năng xảy ra sự kiện So sánh mức độ chênh lệch giữa odds
Trường hợp sử dụng chính Nghiên cứu thuần tập (cohort) Hồi quy logistic, nghiên cứu bệnh-chứng (case-control)
Diễn giải trực tiếp cho người không chuyên Dễ hơn Khó hơn
Giá trị giới hạn \(> 0\), thường từ 0 đến ∞ \(> 0\), thường từ 0 đến ∞

Phân tích cặp Gender và Homeowner

#Tạo bảng tần suất chéo
cross_table_gender <- table(data$Gender, data$Homeowner)
addmargins(cross_table_gender)
##      
##           N     Y   Sum
##   F    2826  4344  7170
##   M    2789  4100  6889
##   Sum  5615  8444 14059
#Tính RR (Homeowner = Y cho F so với M)
library(DescTools)
## Warning: package 'DescTools' was built under R version 4.4.3
RelRisk(cross_table_gender)
## [1] 0.9735554
library(epitools)
riskratio(cross_table_gender)
## $data
##        
##            N    Y Total
##   F     2826 4344  7170
##   M     2789 4100  6889
##   Total 5615 8444 14059
## 
## $measure
##    risk ratio with 95% C.I.
##      estimate     lower    upper
##   F 1.0000000        NA       NA
##   M 0.9823291 0.9561812 1.009192
## 
## $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] "Unconditional MLE & normal approximation (Wald) CI"
epitab(cross_table_gender, method = "riskratio")
## $tab
##    
##        N        p0    Y        p1 riskratio     lower    upper   p.value
##   F 2826 0.3941423 4344 0.6058577 1.0000000        NA       NA        NA
##   M 2789 0.4048483 4100 0.5951517 0.9823291 0.9561812 1.009192 0.1964833
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"

Tỷ số rủi ro (Risk Ratio - RR):

Tính toán bằng RelRisk() cho thấy RR = 0.9736 (theo DescTools) và RR = 0.9823 với khoảng tin cậy 95% là (0.9562; 1.009) (theo epitools).

Điều này ngụ ý rằng nam giới có nguy cơ sở hữu nhà thấp hơn một chút so với nữ giới, tuy nhiên khác biệt không có ý nghĩa thống kê (p = 0.1965 > 0.05).

# Tính OR
OddsRatio(cross_table_gender) 
## [1] 0.9563518
oddsratio(cross_table_gender) 
## $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"
epitab(cross_table_gender, method = "oddsratio")
## $tab
##    
##        N        p0    Y        p1 oddsratio     lower    upper   p.value
##   F 2826 0.5032947 4344 0.5144481 1.0000000        NA       NA        NA
##   M 2789 0.4967053 4100 0.4855519 0.9563518 0.8939173 1.023147 0.1964833
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"

Tỷ số odds (Odds Ratio - OR):

OR = 0.9564 với khoảng tin cậy 95% là (0.8939; 1.023).

Kết quả này cũng cho thấy khả năng sở hữu nhà giữa hai giới là tương đương, và sự khác biệt không có ý nghĩa thống kê (p = 0.1965).

Mối liên hệ giữa giới tính và khả năng sở hữu nhà không đủ mạnh để được xem là có ý nghĩa thống kê. Tỷ lệ sở hữu nhà của nữ giới (60.59%) chỉ nhỉnh hơn nam giới (59.52%) một cách không đáng kể. Do đó, không thể khẳng định rằng giới tính là yếu tố ảnh hưởng đến việc sở hữu nhà trong mẫu dữ liệu này.

Phân tích cặp MaritalStatus và Homeowner

# Tạo bảng tần suất chéo
cross_table_ms <- table(data$MaritalStatus, data$Homeowner)
addmargins(cross_table_ms)
##      
##           N     Y   Sum
##   M    1719  5147  6866
##   S    3896  3297  7193
##   Sum  5615  8444 14059
#Tính RR
RelRisk(cross_table_ms)
## [1] 0.4622354
riskratio(cross_table_ms)
## $data
##        
##            N    Y Total
##   M     1719 5147  6866
##   S     3896 3297  7193
##   Total 5615 8444 14059
## 
## $measure
##    risk ratio with 95% C.I.
##      estimate     lower     upper
##   M 1.0000000        NA        NA
##   S 0.6114466 0.5942071 0.6291862
## 
## $p.value
##    two-sided
##     midp.exact  fisher.exact    chi.square
##   M         NA            NA            NA
##   S          0 1.822183e-277 3.663022e-272
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
epitab(cross_table_ms, method = "riskratio")
## $tab
##    
##        N        p0    Y        p1 riskratio     lower     upper       p.value
##   M 1719 0.2503641 5147 0.7496359 1.0000000        NA        NA            NA
##   S 3896 0.5416377 3297 0.4583623 0.6114466 0.5942071 0.6291862 1.822183e-277
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"

Tỷ số rủi ro (Risk Ratio - RR) Giá trị RR = 0.6114, với khoảng tin cậy 95% là (0.5942; 0.6292).

Điều này có nghĩa là nguy cơ sở hữu nhà của người độc thân chỉ bằng khoảng 61,14% so với người đã kết hôn.

Khác biệt này là có ý nghĩa thống kê cao với p-value ≈ 1.82×10⁻²⁷⁷ (Fisher’s exact test).

#Tính OR
OddsRatio(cross_table_ms)
## [1] 0.2826322
oddsratio(cross_table_ms)
## $data
##        
##            N    Y Total
##   M     1719 5147  6866
##   S     3896 3297  7193
##   Total 5615 8444 14059
## 
## $measure
##    odds ratio with 95% C.I.
##     estimate     lower     upper
##   M 1.000000        NA        NA
##   S 0.282673 0.2630995 0.3036164
## 
## $p.value
##    two-sided
##     midp.exact  fisher.exact    chi.square
##   M         NA            NA            NA
##   S          0 1.822183e-277 3.663022e-272
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
epitab(cross_table_ms, method = "oddsratio")
## $tab
##    
##        N        p0    Y        p1 oddsratio     lower     upper       p.value
##   M 1719 0.3061443 5147 0.6095452 1.0000000        NA        NA            NA
##   S 3896 0.6938557 3297 0.3904548 0.2826322 0.2630929 0.3036227 1.822183e-277
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"

Tỷ số odds (Odds Ratio - OR) Giá trị OR = 0.2826, với khoảng tin cậy 95% là (0.2631; 0.3036).

Điều đó cho thấy rằng odds (tỷ số khả năng xảy ra và không xảy ra) sở hữu nhà của người độc thân thấp hơn khoảng 71.7% so với người đã kết hôn.

Kết quả này cũng có ý nghĩa thống kê rất cao (p ≈ 1.82×10⁻²⁷⁷).

Phân tích định lượng cho thấy tình trạng hôn nhân là yếu tố có ảnh hưởng rõ rệt và có ý nghĩa thống kê cao đến việc sở hữu nhà trong mẫu khảo sát. Cụ thể, người độc thân có nguy cơ và odds sở hữu nhà thấp hơn đáng kể so với người đã kết hôn. Kết quả này có thể phản ánh các yếu tố xã hội và kinh tế như nhu cầu ổn định gia đình, khả năng tài chính kết hợp từ hai cá nhân trong hôn nhân, hoặc các chính sách hỗ trợ mua nhà cho gia đình.

LS0tDQp0aXRsZTogIk5oaeG7h20gduG7pSAyIg0KYXV0aG9yOiAiSG/DoG5nIFF1ecOqbiINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVIOiVNOiVTLCAlZCAtICVtIC0gJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UgIA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogdHJ1ZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCmBgYHtyIGVjaG89IFRSVUUsIGV2YWw9RkFMU0V9DQpsaWJyYXJ5KHNob3d0ZXh0KQ0KZm9udF9hZGQoZmFtaWx5ID0gIkFyaWFsIiwgcmVndWxhciA9ICJhcmlhbC50dGYiKSAgIyDEkOG6o20gYuG6o28gZm9udCBBcmlhbCBjw7MgdHLDqm4gbcOheQ0Kc2hvd3RleHRfYXV0bygpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZXBpdG9vbHMpDQpsaWJyYXJ5KERlc2NUb29scykNCmxpYnJhcnkoRFQpDQpsaWJyYXJ5KGVuZXJneSkNCmxpYnJhcnkocmVhZHIpDQpvcHRpb25zKGRpZ2l0cyA9IDQpDQpgYGANCg0KKipQaMOibiB0w61jaCBE4buvIGxp4buHdSBHaWFvIGThu4tjaCBTacOqdSB0aOG7iyoqDQoNCiMgKipQaOG6p24gMTogVMOsbSBoaeG7g3UgdsOgIENodeG6qW4gYuG7iyBk4buvIGxp4buHdSoqDQoNCiMjICoqxJDhu41jIHbDoCBMw6BtIHF1ZW4gROG7ryBsaeG7h3UqKg0KDQpgYGB7cn0NCiPEkOG7jWMgZOG7ryBsaeG7h3UgdOG7qyBmaWxlIENTVg0KZGF0YSA8LXJlYWQuY3N2KCJDOi9Vc2Vycy9Ib2FuZyBRdXllbi9Eb3dubG9hZHMvU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zLmNzdiIpDQpgYGANCg0KYGBge3J9DQojSGnhu4NuIHRo4buLIGPhuqV1IHRyw7pjIGThu68gbGnhu4d1DQpzdHIoZGF0YSkNCmBgYA0KDQpL4bq/dCBxdeG6oyB0cuG6oyB24buBIGNobyB0aOG6pXkgZGF0YSBsw6AgbeG7mXQgZGF0YS5mcmFtZSBn4buTbSAxNCwwNTkgcXVhbiBzw6F0IChkw7JuZykgdsOgIDE2IGJp4bq/biAoY+G7mXQpLiBN4buXaSBiaeG6v24gxJHGsOG7o2MgbGnhu4d0IGvDqiB24bubaSB0w6puLCBraeG7g3UgZOG7ryBsaeG7h3UgKGNo4bqzbmcgaOG6oW4gbmjGsCBpbnQsIGNociwgaG/hurdjIG51bSkgdsOgIG3hu5l0IHPhu5EgZ2nDoSB0cuG7iyBt4bqrdSBiYW4gxJHhuqd1LiANCg0KKkJp4bq/biDEkeG7i25oIHTDrW5oLioNCg0KIC0gR2VuZGVyOiBHaeG7m2kgdMOtbmggKE0vRikg4oCTIHBow6JuIGxv4bqhaSBuaOG7iyBwaMOibi4NCiAtIE1hcml0YWxTdGF0dXM6IFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiAoTS9TKSDigJMgcGjDom4gbG/huqFpIG5o4buLIHBow6JuLg0KIC0gSG9tZW93bmVyOiBT4bufIGjhu691IG5ow6AgKFkvTikg4oCTIHBow6JuIGxv4bqhaSBuaOG7iyBwaMOibi4NCiAtIEFubnVhbEluY29tZTogVGh1IG5o4bqtcCBow6BuZyBuxINtIChlLmcuLCAkMTBL4oCTJDMwSywgJDMwS+KAkyQ1MEssLi4uKSDigJMgcGjDom4gbG/huqFpIHRo4bupIHThu7EgKG9yZGluYWwpLCB2w6wgY8OhYyBraG/huqNuZyB0aHUgbmjhuq1wIGPDsyB0aOG7qSB04buxIG5oxrBuZyBraMO0bmcgcGjhuqNpIHPhu5EgbGnDqm4gdOG7pWMuDQogLSBDaXR5OiBUaMOgbmggcGjhu5EgKGUuZy4sIExvcyBBbmdlbGVzLCBTYWxlbSwuLi4pIOKAkyBwaMOibiBsb+G6oWkgZGFuaCBuZ2jEqWEgKG5vbWluYWwpLg0KIC0gU3RhdGVvclByb3ZpbmNlOiBCYW5nIGhv4bq3YyB04buJbmggKGUuZy4sIENBLCBXQSwgQkMsLi4uKSDigJMgcGjDom4gbG/huqFpIGRhbmggbmdoxKlhLg0KIC0gQ291bnRyeTogUXXhu5FjIGdpYSAoVVNBLCBDYW5hZGEsIE1leGljbykg4oCTIHBow6JuIGxv4bqhaSBkYW5oIG5naMSpYS4NCiAtIFByb2R1Y3RGYW1pbHk6IE5ow7NtIHPhuqNuIHBo4bqpbSAoRm9vZCwgTm9uLUNvbnN1bWFibGUsIERyaW5rKSDigJMgcGjDom4gbG/huqFpIGRhbmggbmdoxKlhLg0KIC0gUHJvZHVjdERlcGFydG1lbnQ6IELhu5kgcGjhuq1uIHPhuqNuIHBo4bqpbSAoZS5nLiwgUHJvZHVjZSwgU25hY2sgRm9vZHMsIERhaXJ5LC4uLikg4oCTIHBow6JuIGxv4bqhaSBkYW5oIG5naMSpYS4NCiAtIFByb2R1Y3RDYXRlZ29yeTogRGFuaCBt4bulYyBz4bqjbiBwaOG6qW0gKGUuZy4sIFZlZ2V0YWJsZXMsIFNuYWNrIEZvb2RzLCBEYWlyeSwuLi4pIOKAkyBwaMOibiBsb+G6oWkgZGFuaCBuZ2jEqWEuDQoNCipCaeG6v24gxJHhu4tuaCBsxrDhu6NuZyAoUXVhbnRpdGF0aXZlIFZhcmlhYmxlcyk6Kg0KDQogLSBVbml0c1NvbGQ6IFPhu5EgbMaw4bujbmcgc+G6o24gcGjhuqltIGLDoW4gcmEgKDHigJM3KSDigJMgYmnhur9uIMSR4buLbmggbMaw4bujbmcgcuG7nWkgcuG6oWMuDQogLSBSZXZlbnVlOiBEb2FuaCB0aHUgKCQxLjQ44oCTJDQ0Ljc4KSDigJMgYmnhur9uIMSR4buLbmggbMaw4bujbmcgbGnDqm4gdOG7pWMuDQogDQpgYGB7cn0NCiMgSGnhu4NuIHRo4buLIDUgZMOybmcgxJHhuqd1IHbDoCBjdeG7kWkNCmhlYWQoZGF0YSwgNSkNCnRhaWwoZGF0YSwgNSkNCmBgYA0KDQpIYWkgaMOgbSBoZWFkKCkgdsOgIHRhaWwoKSDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyBoaeG7g24gdGjhu4sgbOG6p24gbMaw4bujdCA1IGTDsm5nIMSR4bqndSB0acOqbiB2w6AgNSBkw7JuZyBjdeG7kWkgY8O5bmcgY+G7p2EgYuG7mSBk4buvIGxp4buHdSwgZ2nDunAgxJHDoW5oIGdpw6Egc8ahIGLhu5kgdMOtbmggbmjhuqV0IHF1w6FuLCDEkeG7i25oIGThuqFuZyB2w6AgdMOtbmggaOG7o3AgbMO9IGPhu6dhIGPDoWMgZ2nDoSB0cuG7iyB0cm9uZyB04burbmcgYmnhur9uLg0KUXVhIHZp4buHYyBxdWFuIHPDoXQgbeG6q3UgbsOgeSwgY8OzIHRo4buDIG5o4bqtbiB0aOG6pXk6DQoNCi0gROG7ryBsaeG7h3UgdHLhuqNpIGTDoGkgdOG7qyBuZ8OgeSAyMDA3LTEyLTE4IMSR4bq/biAyMDA5LTEyLTMxLCBjaG8gdGjhuqV5IMSRw6J5IGzDoCBt4buZdCB04bqtcCBk4buvIGxp4buHdSBjw7MgeeG6v3UgdOG7kSB0aOG7nWkgZ2lhbiBrw6lvIGTDoGkgMyBuxINtLg0KDQoNCi0gR2nDoSB0cuG7iyDhu58gYmnhur9uIEFubnVhbEluY29tZSDEkcaw4bujYyBiaeG7g3UgZGnhu4VuIGTGsOG7m2kgZOG6oW5nIGtob+G6o25nIHRodSBuaOG6rXAgKHbDrSBk4bulOiAiJDMwSyAtICQ1MEsiKSwgcGjDuSBo4bujcCDEkeG7gyB4ZW0gbmjGsCBiaeG6v24gcGjDom4gbG/huqFpLg0KDQoNCi0gQ8OhYyBiaeG6v24gbmjGsCBQcm9kdWN0RmFtaWx5LCBQcm9kdWN0RGVwYXJ0bWVudCwgUHJvZHVjdENhdGVnb3J5IHRo4buDIGhp4buHbiBj4bqldSB0csO6YyBwaMOibiBsb+G6oWkgc+G6o24gcGjhuqltIG5oaeG7gXUgY+G6pXAsIMSRaeG7gXUgbsOgeSBjw7MgdGjhu4MgxJHGsOG7o2Mga2hhaSB0aMOhYyB0cm9uZyBjw6FjIHBow6JuIHTDrWNoIMSRYSBiaeG6v24uDQoNCiMjICoqS2nhu4NtIHRyYSBHacOhIHRy4buLIFRoaeG6v3UgKE5BKSoqDQoNCk3hu5l0IGLGsOG7m2Mga2nhu4NtIHRyYSBxdWFuIHRy4buNbmcgdHJvbmcgcXV5IHRyw6xuaCB0aeG7gW4geOG7rSBsw70gZOG7ryBsaeG7h3UgbMOgIHjDoWMgxJHhu4tuaCBjw6FjIGdpw6EgdHLhu4sgdGhp4bq/dSAoTkEpIHRyb25nIGPDoWMgYmnhur9uIMSR4buLbmggdMOtbmguIFRyb25nIMSRb+G6oW4gbcOjIHRyw6puLCBjw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oIMSRxrDhu6NjIGxp4buHdCBrw6ogdGjhu6cgY8O0bmcgdsOgbyB2ZWN0b3IgcXVhbGl0YXRpdmVfY29scywgc2F1IMSRw7MgaMOgbSBzYXBwbHkoKSDEkcaw4bujYyBz4butIGThu6VuZyBr4bq/dCBo4bujcCB24bubaSBow6BtIGlzLm5hKCkgxJHhu4MgxJHhur9tIHPhu5EgbMaw4bujbmcgZ2nDoSB0cuG7iyB0aGnhur91IHRyw6puIHThu6tuZyBiaeG6v24uDQoNCmBgYHtyfQ0KI0tp4buDbSB0cmEgTkEgdHJvbmcgY8OhYyBj4buZdCDEkeG7i25oIHTDrW5oDQpxdWFsaXRhdGl2ZV9jb2xzIDwtIGMoIkdlbmRlciIsICJNYXJpdGFsU3RhdHVzIiwgIkhvbWVvd25lciIsICJBbm51YWxJbmNvbWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAiQ2l0eSIsICJTdGF0ZW9yUHJvdmluY2UiLCAiQ291bnRyeSIsIA0KICAgICAgICAgICAgICAgICAgICAgICJQcm9kdWN0RmFtaWx5IiwgIlByb2R1Y3REZXBhcnRtZW50IiwgIlByb2R1Y3RDYXRlZ29yeSIpDQpzYXBwbHkoZGF0YVtxdWFsaXRhdGl2ZV9jb2xzXSwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkNCmBgYA0KDQpL4bq/dCBxdeG6oyBraeG7g20gdHJhIGNobyB0aOG6pXkga2jDtG5nIGPDsyBnacOhIHRy4buLIHRoaeG6v3Ug4bufIGLhuqV0IGvhu7MgYmnhur9uIMSR4buLbmggdMOtbmggbsOgby4gxJBp4buBdSBuw6B5IHLhuqV0IHF1YW4gdHLhu41uZyB2w6wgZOG7ryBsaeG7h3UgxJHhuqd5IMSR4bunIGdpw7pwIMSRxqFuIGdp4bqjbiBow7NhIHF1w6EgdHLDrG5oIHBow6JuIHTDrWNoLCDEkeG7k25nIHRo4budaSBsb+G6oWkgYuG7jyBuaHUgY+G6p3UgeOG7rSBsw70gdGhp4bq/dSBuaMawIGxv4bqhaSBi4buPIGTDsm5nLCBu4buZaSBzdXksIGhv4bq3YyB0aGF5IHRo4bq/IGdpw6EgdHLhu4suDQoNCiMjICoqQ2h1eeG7g24gxJHhu5VpIEtp4buDdSBE4buvIGxp4buHdSBzYW5nIEZhY3RvcioqDQoNClZp4buHYyBjaHV54buDbiDEkeG7lWkgY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCB04burIGtp4buDdSBrw70gdOG7sSAoY2hhcmFjdGVyKSBzYW5nIGtp4buDdSBuaMOibiB04buRIChmYWN0b3IpIGzDoCBixrDhu5tjIHRoZW4gY2jhu5F0IMSR4buDIMSR4bqjbSBi4bqjbyBSIGhp4buDdSDEkcO6bmcgYuG6o24gY2jhuqV0IGPhu6dhIGThu68gbGnhu4d1LCDEkeG6t2MgYmnhu4d0IHRyb25nIGPDoWMgcGjDom4gdMOtY2ggdGjhu5FuZyBrw6ogbcO0IHThuqMsIGtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IGhv4bq3YyBtw7QgaMOsbmggaMOzYS4NCg0KDQpgYGB7cn0NCiNDaHV54buDbiDEkeG7lWkgc2FuZyBmYWN0b3INCmRhdGFbcXVhbGl0YXRpdmVfY29sc10gPC0gbGFwcGx5KGRhdGFbcXVhbGl0YXRpdmVfY29sc10sIGFzLmZhY3RvcikNCg0KI0tp4buDbSB0cmEgbOG6oWkgY+G6pXUgdHLDumMNCnN0cihkYXRhW3F1YWxpdGF0aXZlX2NvbHNdKQ0KYGBgDQpTYXUgY2h1eeG7g24gxJHhu5VpOg0KLSBHZW5kZXIgY8OzIDIgbeG7qWMgxJHhu5kgKCJGIiwgIk0iKSwgcGjDuSBo4bujcCB24bubaSBiaeG6v24gbmjhu4sgcGjDom4uDQoNCg0KLSBNYXJpdGFsU3RhdHVzIGfhu5NtIDIgbeG7qWMgKCJNIiDigJMgTWFycmllZCwgIlMiIOKAkyBTaW5nbGUpLg0KDQoNCi0gQW5udWFsSW5jb21lIGPDsyA4IGtob+G6o25nIHRodSBuaOG6rXAsIMSRxrDhu6NjIHjhu60gbMO9IG5oxrAgYmnhur9uIHBow6JuIGxv4bqhaSB0aOG7qSB04buxLg0KDQoNCi0gQ2l0eSB2w6AgU3RhdGVvclByb3ZpbmNlIGPDsyBz4buRIGzGsOG7o25nIG3hu6ljIMSR4buZIGzhu5tuIGjGoW4gKGzhuqduIGzGsOG7o3QgMjMgdsOgIDEwKSwgcGjhuqNuIMOhbmggc+G7sSDEkWEgZOG6oW5nIHbhu4EgxJHhu4thIGzDvS4NCg0KDQotIFByb2R1Y3RDYXRlZ29yeSBjw7MgxJHhur9uIDQ1IG3hu6ljIMSR4buZLCBwaOG6o24gw6FuaCBz4buxIMSRYSBk4bqhbmcgY+G7p2EgZGFuaCBt4bulYyBz4bqjbiBwaOG6qW0gdHJvbmcgaOG7hyB0aOG7kW5nIHNpw6p1IHRo4buLLg0KDQoNClZp4buHYyBjaHV54buDbiBzYW5nIGZhY3RvciBjxaluZyB04buRaSDGsHUgaMOzYSBi4buZIG5o4bubLCDEkeG7k25nIHRo4budaSBjaG8gcGjDqXAgc+G7rSBk4bulbmcgbmhp4buBdSBow6BtIHRo4buRbmcga8OqIGNodXnDqm4gYmnhu4d0IG5oxrAgdGFibGUoKSwgc3VtbWFyeSgpLCB0YXBwbHkoKSwgaG/hurdjIG3DtCBow6xuaCBwaMOibiBsb+G6oWkgbmjGsCBnbG0oKS4NCg0KDQojICoqUGjhuqduIDI6IFBow6JuIHTDrWNoIE3DtCB04bqjIE3hu5l0IGJp4bq/biDEkOG7i25oIHTDrW5oIChVbml2YXJpYXRlIERlc2NyaXB0aXZlIEFuYWx5c2lzKSoqDQpW4bubaSBt4buXaSBiaeG6v24gxJHhu4tuaCB0w61uaCwgdOG6oW8gYuG6o25nIHThuqduIHN14bqldCwgdOG7tyBs4buHIHBo4bqnbiB0csSDbSwgYmnhu4N1IMSR4buTIHbDoCBuaOG6rW4geMOpdC4NCg0KIyMgKipCaeG6v24gR2VuZGVyKioNCmBgYHtyfQ0KI0LhuqNuZyB04bqnbiBzdeG6pXQgdsOgIHThu7cgbOG7hw0KZ2VuZGVyX2ZyZXEgPC0gdGFibGUoZGF0YSRHZW5kZXIpDQpnZW5kZXJfcHJvcCA8LSBwcm9wLnRhYmxlKGdlbmRlcl9mcmVxKSAqIDEwMA0KZ2VuZGVyX3RhYmxlIDwtIGRhdGEuZnJhbWUoRnJlcXVlbmN5ID0gZ2VuZGVyX2ZyZXEsIFBlcmNlbnRhZ2UgPSBnZW5kZXJfcHJvcCkNCnByaW50KGdlbmRlcl90YWJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KI0Jp4buDdSDEkeG7kyB0csOybg0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gIiIsIGZpbGwgPSBHZW5kZXIpKSArDQogIGdlb21fYmFyKHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBi4buRIEdp4bubaSB0w61uaCIsIGZpbGwgPSAiR2VuZGVyIikgKw0KICB0aGVtZV92b2lkKCkNCmBgYA0KDQpL4bq/dCBxdeG6oyBwaMOibiB0w61jaCBjaG8gdGjhuqV5IHRyb25nIHThu5VuZyBz4buRIHF1YW4gc8OhdCwgY8OzIDcxNzAga2jDoWNoIGjDoG5nIGzDoCBu4buvIChjaGnhur9tIDUxJSkgdsOgIDY4ODkga2jDoWNoIGjDoG5nIGzDoCBuYW0gKGNoaeG6v20gNDklKS4gU+G7sSBwaMOibiBi4buRIGdp4bubaSB0w61uaCBnaeG7r2EgbmFtIHbDoCBu4buvIGtow6EgY8OibiBi4bqxbmcuIEJp4buDdSDEkeG7kyB0csOybiBtaW5oIGjhu41hIHLDtSBz4buxIHTGsMahbmcgxJHhu5NuZyB24buBIHThu7cgbOG7hyBnaeG7m2kgdMOtbmggdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UuDQoNCg0KIyMgKipCaeG6v24gTWFyaXRhbFN0YXR1cyoqDQoNCmBgYHtyfQ0KI0LhuqNuZyB04bqnbiBzdeG6pXQgdsOgIHThu7cgbOG7hw0KbWFyaXRhbF9mcmVxIDwtIHRhYmxlKGRhdGEkTWFyaXRhbFN0YXR1cykNCm1hcml0YWxfcHJvcCA8LSBwcm9wLnRhYmxlKG1hcml0YWxfZnJlcSkgKiAxMDANCm1hcml0YWxfdGFibGUgPC0gZGF0YS5mcmFtZShGcmVxdWVuY3kgPSBtYXJpdGFsX2ZyZXEsIFBlcmNlbnRhZ2UgPSBtYXJpdGFsX3Byb3ApDQpwcmludChtYXJpdGFsX3RhYmxlKQ0KYGBgDQoNCmBgYHtyfQ0KIyBCaeG7g3UgxJHhu5MgY+G7mXQNCmdncGxvdChkYXRhLCBhZXMoeCA9IE1hcml0YWxTdGF0dXMsIGZpbGwgPSBNYXJpdGFsU3RhdHVzKSkgKw0KICBnZW9tX2JhcigpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBi4buRIFTDrG5oIHRy4bqhbmcgSMO0biBuaMOibiIsIHggPSAiTWFyaXRhbCBTdGF0dXMiLCB5ID0gIlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNClRyb25nIHThuq1wIGThu68gbGnhu4d1LCBz4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyDEkeG7mWMgdGjDom4gbMOgIDcxOTMgbmfGsOG7nWkgKGNoaeG6v20gNTEuMTYlKSwgdHJvbmcga2hpIMSRw6Mga+G6v3QgaMO0biBsw6AgNjg2NiBuZ8aw4budaSAoNDguODQlKS4gUGjDom4gYuG7kSB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gZ2nhu69hIGhhaSBuaMOzbSBuw6B5IGPFqW5nIGtow6EgxJHhu5NuZyDEkeG7gXUsIHbhu5tpIHPhu7EgY2jDqm5oIGzhu4djaCBraMO0bmcgxJHDoW5nIGvhu4MuIEJp4buDdSDEkeG7kyBj4buZdCBjaG8gdGjhuqV5IG3hu6ljIMSR4buZIHTGsMahbmcgxJHGsMahbmcgZ2nhu69hIGhhaSBuaMOzbS4NCg0KIyMgKipCaeG6v24gSG9tZW93bmVyKioNCg0KYGBge3J9DQojQuG6o25nIHThuqduIHN14bqldCB2w6AgdOG7tyBs4buHDQpob21lb3duZXJfZnJlcSA8LSB0YWJsZShkYXRhJEhvbWVvd25lcikNCmhvbWVvd25lcl9wcm9wIDwtIHByb3AudGFibGUoaG9tZW93bmVyX2ZyZXEpICogMTAwDQpob21lb3duZXJfdGFibGUgPC0gZGF0YS5mcmFtZShGcmVxdWVuY3kgPSBob21lb3duZXJfZnJlcSwgUGVyY2VudGFnZSA9IGhvbWVvd25lcl9wcm9wKQ0KcHJpbnQoaG9tZW93bmVyX3RhYmxlKQ0KYGBgDQoNCg0KYGBge3J9DQojQmnhu4N1IMSR4buTIHRyw7JuDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSAiIiwgZmlsbCA9IEhvbWVvd25lcikpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAxKSArDQogIGNvb3JkX3BvbGFyKCJ5IikgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgVMOsbmggdHLhuqFuZyBT4bufIGjhu691IE5ow6AiLCBmaWxsID0gIkhvbWVvd25lciIpICsNCiAgdGhlbWVfdm9pZCgpDQpgYGANCg0KVOG7tyBs4buHIGtow6FjaCBow6BuZyBz4bufIGjhu691IG5ow6AgKFkpIGNoaeG6v20gxrB1IHRo4bq/IHbhu5tpIDg0NDQgbmfGsOG7nWkgKDYwLjA2JSkgc28gduG7m2kgbmjDs20ga2jDtG5nIHPhu58gaOG7r3UgbmjDoCAoTikgbMOgIDU2MTUgbmfGsOG7nWkgKDM5Ljk0JSkuIFPhu7EgY2jDqm5oIGzhu4djaCBuw6B5IGNobyB0aOG6pXkgxJFhIHPhu5Ega2jDoWNoIGjDoG5nIHRyb25nIG3huqt1IGPDsyBt4bupYyDEkeG7mSDhu5VuIMSR4buLbmggbmjDoCDhu58gY2FvLiBCaeG7g3UgxJHhu5MgdHLDsm4gbMOgbSByw7Ugc+G7sSBjaMOqbmggbOG7h2NoIGdp4buvYSBoYWkgbmjDs20uDQoNCg0KDQojIyAqKkJp4bq/biBBbm51YWxJbmNvbWUqKg0KDQpgYGB7cn0NCiNC4bqjbmcgdOG6p24gc3XhuqV0IHbDoCB04bu3IGzhu4cNCmluY29tZV9mcmVxIDwtIHRhYmxlKGRhdGEkQW5udWFsSW5jb21lKQ0KaW5jb21lX3Byb3AgPC0gcHJvcC50YWJsZShpbmNvbWVfZnJlcSkgKiAxMDANCmluY29tZV90YWJsZSA8LSBkYXRhLmZyYW1lKEZyZXF1ZW5jeSA9IGluY29tZV9mcmVxLCBQZXJjZW50YWdlID0gaW5jb21lX3Byb3ApDQpwcmludChpbmNvbWVfdGFibGUpDQpgYGANCg0KYGBge3J9DQojQmnhu4N1IMSR4buTIGPhu5l0DQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBBbm51YWxJbmNvbWUsIGZpbGwgPSBBbm51YWxJbmNvbWUpKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgVGh1IG5o4bqtcCBIw6BuZyBuxINtIiwgeCA9ICJBbm51YWwgSW5jb21lIiwgeSA9ICJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KYGBgDQoNClRodSBuaOG6rXAgY+G7p2Ega2jDoWNoIGjDoG5nIMSRxrDhu6NjIGNoaWEgdGjDoG5oIG5oaeG7gXUgbmjDs20uIFBow6JuIGtow7pjIHBo4buVIGJp4bq/biBuaOG6pXQgbMOgIHThu6sgJDMwS+KAkyQ1MEsgKDMyLjczJSkgdsOgICQxMEvigJMkMzBLICgyMS45OCUpLiBUcm9uZyBraGkgxJHDsywgbmjDs20gY8OzIHRodSBuaOG6rXAgdHLDqm4gJDE1MEsgY2jhu4kgY2hp4bq/bSAxLjk0JS4gUGjDom4gYuG7kSB0aHUgbmjhuq1wIGNobyB0aOG6pXkgxJFhIHPhu5Ega2jDoWNoIGjDoG5nIHRodeG7mWMgdOG6p25nIGzhu5twIGPDsyB0aHUgbmjhuq1wIHRydW5nIGLDrG5oIOKAkyB0aOG6pXAuIEJp4buDdSDEkeG7kyBj4buZdCBtaW5oIGjhu41hIHPhu7EgcGjDom4gYuG7kSBraMO0bmcgxJHhu5NuZyDEkeG7gXUgdsOgIHThuq1wIHRydW5nIOG7nyBt4bupYyB0aHUgbmjhuq1wIHRo4bqlcCB2w6AgdHJ1bmcgYsOsbmguDQoNCiMjICoqQmnhur9uIENpdHkqKg0KDQpgYGB7cn0NCg0KY2l0eV9mcmVxIDwtIHRhYmxlKGRhdGEkQ2l0eSkgIyBU4bqhbyBi4bqjbmcgdOG6p24gc3XhuqV0DQoNCmNpdHlfcHJvcCA8LSBwcm9wLnRhYmxlKGNpdHlfZnJlcSkgKiAxMDAgIyBUw61uaCB04bu3IGzhu4cgcGjhuqduIHRyxINtDQoNCg0KY2l0eV90YWJsZSA8LSBkYXRhLmZyYW1lKENpdHkgPSBuYW1lcyhjaXR5X2ZyZXEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgIEZyZXF1ZW5jeSA9IGFzLnZlY3RvcihjaXR5X2ZyZXEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgIFBlcmNlbnRhZ2UgPSBhcy52ZWN0b3IoY2l0eV9wcm9wKSkgIyBDaHV54buDbiB0aMOgbmggZGF0YS5mcmFtZQ0KDQpwcmludChjaXR5X3RhYmxlKSAjIEhp4buDbiB0aOG7iyB0b8OgbiBi4buZIGLhuqNuZw0KDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdChjaXR5X3RhYmxlLCBhZXMoeCA9IENpdHksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBDaXR5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgVGjDoG5oIHBo4buRIiwgeCA9ICJUaMOgbmggcGjhu5EiLCB5ID0gIlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoKSsNCiAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KS2jDoWNoIGjDoG5nIMSR4bq/biB04burIG5oaeG7gXUgdGjDoG5oIHBo4buRIGtow6FjIG5oYXUsIHRyb25nIMSRw7MgU2FsZW0gKDkuODYlKSwgVGFjb21hICg4Ljk0JSkgdsOgIFphY2F0ZWNhcyAoOS4yMyUpIGzDoCBuaOG7r25nIG7GoWkgY8OzIHPhu5EgbMaw4bujbmcga2jDoWNoIGjDoG5nIGNhbyBuaOG6pXQuIE5o4buvbmcgdGjDoG5oIHBo4buRIG5oxrAgU2FuIEZyYW5jaXNjbyAoMC45MiUpIHbDoCBHdWFkYWxhamFyYSAoMC41MyUpIGzhuqFpIGPDsyBz4buRIGzGsOG7o25nIMOtdCBoxqFuIG5oaeG7gXUuIEJp4buDdSDEkeG7kyBj4buZdCBjaG8gdGjhuqV5IHPhu7EgcGjDom4gaMOzYSByw7UgcuG7h3QgdGhlbyB2w7luZyDEkeG7i2EgbMO9Lg0KDQojIyAqKkJp4bq/biBTdGF0ZW9yUHJvdmluY2UqKg0KDQpgYGB7cn0NCiNC4bqjbmcgdOG6p24gc3XhuqV0IHbDoCB04bu3IGzhu4cNCnN0YXRlX2ZyZXEgPC0gdGFibGUoZGF0YSRTdGF0ZW9yUHJvdmluY2UpDQpzdGF0ZV9wcm9wIDwtIHByb3AudGFibGUoc3RhdGVfZnJlcSkgKiAxMDANCnN0YXRlX3RhYmxlIDwtIGRhdGEuZnJhbWUoRnJlcXVlbmN5ID0gc3RhdGVfZnJlcSwgUGVyY2VudGFnZSA9IHN0YXRlX3Byb3ApDQpwcmludChzdGF0ZV90YWJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KI0Jp4buDdSDEkeG7kyBj4buZdA0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gU3RhdGVvclByb3ZpbmNlLCBmaWxsID0gU3RhdGVvclByb3ZpbmNlKSkgKw0KICBnZW9tX2JhcigpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBi4buRIEJhbmcvVOG7iW5oIiwgeCA9ICJTdGF0ZSBvciBQcm92aW5jZSIsIHkgPSAiU+G7kSBsxrDhu6NuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KDQpQaMOibiBi4buRIHRoZW8gYmFuZyBob+G6t2MgdOG7iW5oIGNobyB0aOG6pXkgV2FzaGluZ3RvbiAoV0EpIGzDoCBraHUgduG7sWMgY2hp4bq/bSB04bu3IHRy4buNbmcgbOG7m24gbmjhuqV0IHbhu5tpIDMyLjQ4JSBraMOhY2ggaMOgbmcsIHRp4bq/cCB0aGVvIGzDoCBDYWxpZm9ybmlhIChDQSkgduG7m2kgMTkuNDQlIHbDoCBPcmVnb24gKE9SKSB24bubaSAxNi4wOSUuIMSQaeG7gXUgbsOgeSBwaOG6o24gw6FuaCBz4buxIHThuq1wIHRydW5nIGTDom4gc+G7kSB04bqhaSBt4buZdCBz4buRIGJhbmcgbOG7m24uIEJp4buDdSDEkeG7kyBj4buZdCBsw6BtIHLDtSBz4buxIHBow6JuIGLhu5Ega2jDtG5nIMSR4buTbmcgxJHhu4F1IG7DoHkuDQoNCiMjICoqQmnhur9uIENvdW50cnkqKg0KDQpgYGB7cn0NCiNC4bqjbmcgdOG6p24gc3XhuqV0IHbDoCB04bu3IGzhu4cNCmNvdW50cnlfZnJlcSA8LSB0YWJsZShkYXRhJENvdW50cnkpDQpjb3VudHJ5X3Byb3AgPC0gcHJvcC50YWJsZShjb3VudHJ5X2ZyZXEpICogMTAwDQpjb3VudHJ5X3RhYmxlIDwtIGRhdGEuZnJhbWUoRnJlcXVlbmN5ID0gY291bnRyeV9mcmVxLCBQZXJjZW50YWdlID0gY291bnRyeV9wcm9wKQ0KcHJpbnQoY291bnRyeV90YWJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KI0Jp4buDdSDEkeG7kyBj4buZdA0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gQ291bnRyeSwgZmlsbCA9IENvdW50cnkpKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgUXXhu5FjIGdpYSIsIHggPSAiQ291bnRyeSIsIHkgPSAiU+G7kSBsxrDhu6NuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KS2jDoWNoIGjDoG5nIGNo4bunIHnhur91IMSR4bq/biB04burIEhvYSBL4buzICg2OC4wMSUpLCBzYXUgxJHDsyBsw6AgTWV4aWNvICgyNi4yMyUpIHbDoCBDYW5hZGEgKDUuNzUlKS4gROG7ryBsaeG7h3UgY2hvIHRo4bqleSB0aOG7iyB0csaw4budbmcgY2jDrW5oIGPhu6dhIHNpw6p1IHRo4buLIHThuq1wIHRydW5nIHThuqFpIE3hu7kuIEJp4buDdSDEkeG7kyBj4buZdCBuaOG6pW4gbeG6oW5oIHPhu7Egw6FwIMSR4bqjbyBj4bunYSBraMOhY2ggaMOgbmcgdOG7qyBIb2EgS+G7sy4NCg0KIyMgKipCaeG6v24gUHJvZHVjdEZhbWlseSoqDQoNCmBgYHtyfQ0KI0LhuqNuZyB04bqnbiBzdeG6pXQgdsOgIHThu7cgbOG7hw0KcHJvZF9mYW1pbHlfZnJlcSA8LSB0YWJsZShkYXRhJFByb2R1Y3RGYW1pbHkpDQpwcm9kX2ZhbWlseV9wcm9wIDwtIHByb3AudGFibGUocHJvZF9mYW1pbHlfZnJlcSkgKiAxMDANCnByb2RfZmFtaWx5X3RhYmxlIDwtIGRhdGEuZnJhbWUoRnJlcXVlbmN5ID0gcHJvZF9mYW1pbHlfZnJlcSwgUGVyY2VudGFnZSA9IHByb2RfZmFtaWx5X3Byb3ApDQpwcmludChwcm9kX2ZhbWlseV90YWJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KI0Jp4buDdSDEkeG7kyBj4buZdA0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gUHJvZHVjdEZhbWlseSwgZmlsbCA9IFByb2R1Y3RGYW1pbHkpKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgTmjDs20gU+G6o24gcGjhuqltIiwgeCA9ICJQcm9kdWN0IEZhbWlseSIsIHkgPSAiU+G7kSBsxrDhu6NuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KTmjDs20gc+G6o24gcGjhuqltIEZvb2QgKFRo4buxYyBwaOG6qW0pIGNoaeG6v20gxrB1IHRo4bq/IHbGsOG7o3QgdHLhu5lpICg3Mi4yMiUpLCB0aeG6v3AgxJHhur9uIGzDoCBOb24tQ29uc3VtYWJsZSAoUGhpIHRpw6p1IGTDuW5nKSB24bubaSAxOC44OSUgdsOgIERyaW5rICjEkOG7kyB14buRbmcpIGzDoCA4Ljg5JS4gxJBp4buBdSBuw6B5IHBo4bqjbiDDoW5oIHNpw6p1IHRo4buLIGNo4bunIHnhur91IGtpbmggZG9hbmggdGjhu7FjIHBo4bqpbS4gQmnhu4N1IMSR4buTIGPhu5l0IGzDoG0gbuG7lWkgYuG6rXQgdOG7tyB0cuG7jW5nIGzhu5tuIGPhu6dhIG5ow7NtIHRo4buxYyBwaOG6qW0uDQoNCg0KIyMgKipCaeG6v24gUHJvZHVjdERlcGFydG1lbnQqKg0KDQpgYGB7cn0NCiNC4bqjbmcgdOG6p24gc3XhuqV0IHbDoCB04bu3IGzhu4cNCnByb2RfZGVwdF9mcmVxIDwtIHRhYmxlKGRhdGEkUHJvZHVjdERlcGFydG1lbnQpDQpwcm9kX2RlcHRfcHJvcCA8LSBwcm9wLnRhYmxlKHByb2RfZGVwdF9mcmVxKSAqIDEwMA0KcHJvZF9kZXB0X3RhYmxlIDwtIGRhdGEuZnJhbWUoRnJlcXVlbmN5ID0gcHJvZF9kZXB0X2ZyZXEsIFBlcmNlbnRhZ2UgPSBwcm9kX2RlcHRfcHJvcCkNCnByaW50KHByb2RfZGVwdF90YWJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KI0Jp4buDdSDEkeG7kyBj4buZdA0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gUHJvZHVjdERlcGFydG1lbnQsIGZpbGwgPSBQcm9kdWN0RGVwYXJ0bWVudCkpICsNCiAgZ2VvbV9iYXIoKSArDQogIGxhYnModGl0bGUgPSAiUGjDom4gYuG7kSBC4buZIHBo4bqtbiBT4bqjbiBwaOG6qW0iLCB4ID0gIlByb2R1Y3QgRGVwYXJ0bWVudCIsIHkgPSAiU+G7kSBsxrDhu6NuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCg0KYGBgDQoNCkRhbmggbeG7pWMgY8OzIHThuqduIHN14bqldCBjYW8gbmjhuqV0IGzDoCBWZWdldGFibGVzICgxMi4yOSUpLCBTbmFjayBGb29kcyAoMTEuMzglKSwgdsOgIFByb2R1Y2UgKDE0LjE4JSkuIE3hu5l0IHPhu5EgZGFuaCBt4bulYyBoaeG6v20gbmjGsCBDYW5uZWQgT3lzdGVycywgTWlzY2VsbGFuZW91cywgdsOgIENhbmRsZXMgY8OzIHThu7cgbOG7hyBkxrDhu5tpIDAuNSUuIFBow6JuIHTDrWNoIG7DoHkgY2hvIHRo4bqleSBz4buxIHThuq1wIHRydW5nIG3huqFuaCBt4bq9IHbDoG8gY8OhYyBkYW5oIG3hu6VjIHRo4buxYyBwaOG6qW0gdMawxqFpIHPhu5FuZyB2w6AgxJHhu5MgxINuIG5o4bq5LiBCaeG7g3UgxJHhu5MgY+G7mXQgZ2nDunAgdHLhu7FjIHF1YW4gaMOzYSByw7UgbsOpdCAxMCBkYW5oIG3hu6VjIHBo4buVIGJp4bq/biBuaOG6pXQuDQoNCg0KIyMgKipCaeG6v24gUHJvZHVjdENhdGVnb3J5KioNCg0KYGBge3J9DQojIFThuqFvIGLhuqNuZyB04bqnbiBzdeG6pXQNCnByb2RfY2F0X2ZyZXEgPC0gdGFibGUoZGF0YSRQcm9kdWN0Q2F0ZWdvcnkpDQoNCiMgVMOtbmggdOG7tyBs4buHIHBo4bqnbiB0csSDbQ0KcHJvZF9jYXRfcHJvcCA8LSBwcm9wLnRhYmxlKHByb2RfY2F0X2ZyZXEpICogMTAwDQoNCiMgQ2h1eeG7g24gdGjDoG5oIGRhdGEuZnJhbWUNCnByb2RfY2F0X3RhYmxlIDwtIGRhdGEuZnJhbWUoQ2F0ZWdvcnkgPSBuYW1lcyhwcm9kX2NhdF9mcmVxKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRnJlcXVlbmN5ID0gYXMudmVjdG9yKHByb2RfY2F0X2ZyZXEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQZXJjZW50YWdlID0gYXMudmVjdG9yKHByb2RfY2F0X3Byb3ApKQ0KDQojIEhp4buDbiB0aOG7iyB0b8OgbiBi4buZIGLhuqNuZw0KcHJpbnQocHJvZF9jYXRfdGFibGUpDQpgYGANCg0KDQpgYGB7cn0NCiMgQmnhu4N1IMSR4buTIGPhu5l0IA0KZ2dwbG90KHByb2RfY2F0X3RhYmxlLCBhZXMoeCA9IENhdGVnb3J5LCB5ID0gRnJlcXVlbmN5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgRGFuaCBt4bulYyBT4bqjbiBwaOG6qW0iLCB4ID0gIkRhbmggbeG7pWMgU+G6o24gcGjhuqltIiwgeSA9ICJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCiAgDQpgYGANCg0KRGFuaCBt4bulYyBjw7MgdOG6p24gc3XhuqV0IGNhbyBuaOG6pXQgbMOgIFZlZ2V0YWJsZXMgKDEyLjI5JSksIFNuYWNrIEZvb2RzICgxMS4zOCUpLCB2w6AgUHJvZHVjZSAoMTQuMTglKS4gTeG7mXQgc+G7kSBkYW5oIG3hu6VjIGhp4bq/bSBuaMawIENhbm5lZCBPeXN0ZXJzLCBNaXNjZWxsYW5lb3VzLCB2w6AgQ2FuZGxlcyBjw7MgdOG7tyBs4buHIGTGsOG7m2kgMC41JS4gUGjDom4gdMOtY2ggbsOgeSBjaG8gdGjhuqV5IHPhu7EgdOG6rXAgdHJ1bmcgbeG6oW5oIG3hur0gdsOgbyBjw6FjIGRhbmggbeG7pWMgdGjhu7FjIHBo4bqpbSB0xrDGoWkgc+G7kW5nIHbDoCDEkeG7kyDEg24gbmjhurkuIEJp4buDdSDEkeG7kyBj4buZdCBnacO6cCB0cuG7sWMgcXVhbiBow7NhIHLDtSBuw6l0IDEwIGRhbmggbeG7pWMgcGjhu5UgYmnhur9uIG5o4bqldC4NCg0KDQojICoqUGjhuqduIDM6IMav4bubYyBsxrDhu6NuZyBLaG/huqNuZyB2w6AgS2nhu4NtIMSR4buLbmggR2nhuqMgdGh1eeG6v3QgY2hvIFThu7cgbOG7hyoqDQoNClRyb25nIHBo4bqnbiBuw6B5LCBt4bulYyB0acOqdSBsw6AgxrDhu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSBjaG8gdOG7tyBs4buHIGPhu6dhIG3hu5l0IHPhu5EgaOG6oW5nIG3hu6VjIMSR4buLbmggdMOtbmggY+G7pSB0aOG7gyB2w6AgdGjhu7FjIGhp4buHbiBraeG7g20gxJHhu4tuaCBnaeG6oyB0aHV54bq/dCBt4buZdCB04bu3IGzhu4csIG5o4bqxbSBraeG7g20gdHJhIHhlbSB04bu3IGzhu4cgcXVhbiBzw6F0IMSRxrDhu6NjIHRyb25nIG3huqt1IGPDsyBraMOhYyBiaeG7h3QgxJHDoW5nIGvhu4Mgc28gduG7m2kgbeG7mXQgdOG7tyBs4buHIGdp4bqjIMSR4buLbmggaGF5IGtow7RuZy4NCg0KIyMgKipCaeG6v24gR2VuZGVyIChI4bqhbmcgbeG7pWM6IE7hu68pKioNCg0KR2nhuqMgdGh1eeG6v3Qga2nhu4NtIMSR4buLbmg6DQoNCkjigoA6IFThu7cgbOG7hyBu4buvIHRyb25nIG3huqt1IGLhurFuZyA1MCUgKHAgPSAwLjUpDQoNCkjigoE6IFThu7cgbOG7hyBu4buvIGtow6FjIDUwJQ0KDQoNCmBgYHtyfQ0KI8av4bubYyBsxrDhu6NuZyBLaG/huqNuZyBUaW4gY+G6rXkNCm4gPC0gbnJvdyhkYXRhKQ0KZmVtYWxlX2NvdW50IDwtIHN1bShkYXRhJEdlbmRlciA9PSAiRiIpDQpwcm9wX2ZlbWFsZSA8LSBmZW1hbGVfY291bnQgLyBuDQpzZV9mZW1hbGUgPC0gc3FydChwcm9wX2ZlbWFsZSAqICgxIC0gcHJvcF9mZW1hbGUpIC8gbikNCmNpX2ZlbWFsZSA8LSBwcm9wX2ZlbWFsZSArIGMoLTEsIDEpICogMS45NiAqIHNlX2ZlbWFsZQ0KY2F0KCJLaG/huqNuZyB0aW4gY+G6rXkgOTUlIGNobyB04bu3IGzhu4cgTuG7rzoiLCByb3VuZChjaV9mZW1hbGUgKiAxMDAsIDIpLCAiJVxuIikNCmBgYA0KDQpgYGB7cn0NCiNLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dCAoSDA6IFThu7cgbOG7hyBO4buvID0gMC41KQ0KcHJvcC50ZXN0KGZlbWFsZV9jb3VudCwgbiwgcCA9IDAuNSwgY29uZi5sZXZlbCA9IDAuOTUpDQpgYGANCkvhur90IHF14bqjIHBow6JuIHTDrWNoDQoNCktob+G6o25nIHRpbiBj4bqteSA5NSU6IFs1MC4xNyUsIDUxLjgzJV0NCg0KR2nDoSB0cuG7iyBwLXZhbHVlOiAwLjAyIDwgMC4wNQ0KDQpOaOG6rW4geMOpdA0KDQpWw6wga2hv4bqjbmcgdGluIGPhuq15IGtow7RuZyBjaOG7qWEgxJHDum5nIDUwJSwgdsOgIGdpw6EgdHLhu4sgcCBuaOG7jyBoxqFuIDAuMDUsIHRhIGPDsyDEkeG7pyBi4bqxbmcgY2jhu6luZyDEkeG7gyBiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3QgSDAuIE5oxrAgduG6rXksIHThu7cgbOG7hyBraMOhY2ggaMOgbmcgbuG7ryB0aOG7sWMgdOG6vyBjw7Mgc+G7sSBraMOhYyBiaeG7h3QgxJHDoW5nIGvhu4Mgc28gduG7m2kgbeG7qWMgZ2nhuqMgxJHhu4tuaCA1MCUsIG3hurdjIGTDuSBz4buxIGtow6FjIGJp4buHdCBsw6Agbmjhu48uIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IGtow6FjaCBow6BuZyBu4buvIGNoaeG6v20gdOG7tyBs4buHIG5o4buJbmggaMahbiBt4buZdCBjaMO6dCBzbyB24bubaSBraMOhY2ggaMOgbmcgbmFtLg0KDQojIyAqKkJp4bq/biBNYXJpdGFsU3RhdHVzIChI4bqhbmcgbeG7pWM6IMSQw6Mga+G6v3QgaMO0bikqKg0KDQpHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaA0KDQpIMDogVOG7tyBs4buHIMSRw6Mga+G6v3QgaMO0biA9IDUwJQ0KDQpIMTogVOG7tyBs4buHIMSRw6Mga+G6v3QgaMO0biDiiaAgNTAlDQoNCg0KYGBge3J9DQojxq/hu5tjIGzGsOG7o25nIEtob+G6o25nIFRpbiBj4bqteQ0KbWFycmllZF9jb3VudCA8LSBzdW0oZGF0YSRNYXJpdGFsU3RhdHVzID09ICJNIikNCnByb3BfbWFycmllZCA8LSBtYXJyaWVkX2NvdW50IC8gbg0Kc2VfbWFycmllZCA8LSBzcXJ0KHByb3BfbWFycmllZCAqICgxIC0gcHJvcF9tYXJyaWVkKSAvIG4pDQpjaV9tYXJyaWVkIDwtIHByb3BfbWFycmllZCArIGMoLTEsIDEpICogMS45NiAqIHNlX21hcnJpZWQNCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIMSQw6Mga+G6v3QgaMO0bjoiLCByb3VuZChjaV9tYXJyaWVkICogMTAwLCAyKSwgIiVcbiIpDQpgYGANCg0KYGBge3J9DQoNCiNLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dCAoSDA6IFThu7cgbOG7hyDEkMOjIGvhur90IGjDtG4gPSAwLjUpDQpwcm9wLnRlc3QobWFycmllZF9jb3VudCwgbiwgcCA9IDAuNSwgY29uZi5sZXZlbCA9IDAuOTUpDQpgYGANCkvhur90IHF14bqjIHBow6JuIHTDrWNoDQoNCktob+G6o25nIHRpbiBj4bqteSA5NSU6IFs0OC4wMSUsIDQ5LjY2JV0NCg0KcC12YWx1ZTogMC4wMDYgPCAwLjA1DQoNCk5o4bqtbiB4w6l0DQpU4bu3IGzhu4cga2jDoWNoIGjDoG5nIMSRw6Mga+G6v3QgaMO0biB0aOG6pXAgaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBt4bupYyBnaeG6oyDEkeG7i25oIDUwJS4gS2hv4bqjbmcgdGluIGPhuq15IGtow7RuZyBjaOG7qWEgMC41IHbDoCBwLXZhbHVlIG5o4buPIGNobyB0aOG6pXkgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqi4gRG8gxJHDsywgxJFhIHBo4bqnbiBraMOhY2ggaMOgbmcgbMOgIG5nxrDhu51pIGNoxrBhIGvhur90IGjDtG4sIMSRaeG7gXUgbsOgeSBjw7MgdGjhu4MgZ+G7o2kgw70gduG7gSB4dSBoxrDhu5tuZyBjaGkgdGnDqnUgaG/hurdjIGzhu5FpIHPhu5FuZyBraMOhYyBiaeG7h3QuDQoNCiMjICoqQmnhur9uIEhvbWVvd25lciAoSOG6oW5nIG3hu6VjOiBDw7MgbmjDoCkqKg0KDQpHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaA0KDQpIMDogVOG7tyBs4buHIHPhu58gaOG7r3UgbmjDoCA9IDYwJQ0KDQpIMTogVOG7tyBs4buHIHPhu58gaOG7r3UgbmjDoCDiiaAgNjAlDQoNCmBgYHtyfQ0KI8av4bubYyBsxrDhu6NuZyBLaG/huqNuZyBUaW4gY+G6rXkNCmhvbWVvd25lcl9jb3VudCA8LSBzdW0oZGF0YSRIb21lb3duZXIgPT0gIlkiKQ0KcHJvcF9ob21lb3duZXIgPC0gaG9tZW93bmVyX2NvdW50IC8gbg0Kc2VfaG9tZW93bmVyIDwtIHNxcnQocHJvcF9ob21lb3duZXIgKiAoMSAtIHByb3BfaG9tZW93bmVyKSAvIG4pDQpjaV9ob21lb3duZXIgPC0gcHJvcF9ob21lb3duZXIgKyBjKC0xLCAxKSAqIDEuOTYgKiBzZV9ob21lb3duZXINCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIFPhu58gaOG7r3UgTmjDoDoiLCByb3VuZChjaV9ob21lb3duZXIgKiAxMDAsIDIpLCAiJVxuIikNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCiNLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dCAoSDA6IFThu7cgbOG7hyBT4bufIGjhu691IE5ow6AgPSAwLjYpDQpwcm9wLnRlc3QoaG9tZW93bmVyX2NvdW50LCBuLCBwID0gMC42LCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQpL4bq/dCBxdeG6oyBwaMOibiB0w61jaA0KDQpLaG/huqNuZyB0aW4gY+G6rXkgOTUlOiBbNTkuMjUlLCA2MC44NyVdDQoNCnAtdmFsdWU6IDAuOTAgPiAwLjA1DQoNCk5o4bqtbiB4w6l0DQpLaG/huqNuZyB0aW4gY+G6rXkgYmFvIGfhu5NtIGdpw6EgdHLhu4sgNjAlIHbDoCBwLXZhbHVlIHLhuqV0IGzhu5tuLCBkbyDEkcOzIGtow7RuZyBjw7MgxJHhu6cgYuG6sW5nIGNo4bupbmcgxJHhu4MgYsOhYyBi4buPIGdp4bqjIHRodXnhur90IEgwLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSB04bu3IGzhu4cga2jDoWNoIGjDoG5nIHPhu58gaOG7r3UgbmjDoCBwaMO5IGjhu6NwIHbhu5tpIGdp4bqjIMSR4buLbmgsIHThu6ljIGzDoCBraG/huqNuZyA2MCUga2jDoWNoIGjDoG5nIGzDoCBjaOG7pyBz4bufIGjhu691IG5ow6AuDQoNCiMjICoqQmnhur9uIEFubnVhbEluY29tZSAoSOG6oW5nIG3hu6VjOiAkMzBLIC0gJDUwSykqKg0KDQpHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaA0KDQpIMDogVOG7tyBs4buHIHRodSBuaOG6rXAgbsOgeSA9IDMwJQ0KDQpIMTogVOG7tyBs4buHIOKJoCAzMCUNCg0KYGBge3J9DQojxq/hu5tjIGzGsOG7o25nIEtob+G6o25nIFRpbiBj4bqteQ0KaW5jb21lX2NvdW50IDwtIHN1bShkYXRhJEFubnVhbEluY29tZSA9PSAiJDMwSyAtICQ1MEsiKQ0KcHJvcF9pbmNvbWUgPC0gaW5jb21lX2NvdW50IC8gbg0Kc2VfaW5jb21lIDwtIHNxcnQocHJvcF9pbmNvbWUgKiAoMSAtIHByb3BfaW5jb21lKSAvIG4pDQpjaV9pbmNvbWUgPC0gcHJvcF9pbmNvbWUgKyBjKC0xLCAxKSAqIDEuOTYgKiBzZV9pbmNvbWUNCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHICQzMEsgLSAkNTBLOiIsIHJvdW5kKGNpX2luY29tZSAqIDEwMCwgMiksICIlXG4iKQ0KYGBgDQoNCg0KYGBge3J9DQojS2nhu4NtIMSR4buLbmggR2nhuqMgdGh1eeG6v3QgKEgwOiBU4bu3IGzhu4cgJDMwSyAtICQ1MEsgPSAwLjMpDQpwcm9wLnRlc3QoaW5jb21lX2NvdW50LCBuLCBwID0gMC4zLCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQpL4bq/dCBxdeG6oyBwaMOibiB0w61jaA0KDQpLaG/huqNuZyB0aW4gY+G6rXkgOTUlOiBbMzEuOTUlLCAzMy41MSVdDQoNCnAtdmFsdWU6IDJlLTEyIDwgMC4wNQ0KDQpOaOG6rW4geMOpdA0KVOG7tyBs4buHIGtow6FjaCBow6BuZyB0aHXhu5ljIG5ow7NtIHRodSBuaOG6rXAgMzBL4oCTNTBLIGNhbyBoxqFuIMSRw6FuZyBr4buDIHNvIHbhu5tpIDMwJSwgdsOgIMSRaeG7gXUgbsOgeSBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIG3huqFuaC4gS+G6v3QgcXXhuqMgY2hvIHRo4bqleSDEkcOieSBsw6AgbmjDs20gdGh1IG5o4bqtcCBwaOG7lSBiaeG6v24sIGPDsyB0aOG7gyBsw6AgbeG7pWMgdGnDqnUgdGnhur9wIHRo4buLIGhp4buHdSBxdeG6oy4NCg0KIyMgKipCaeG6v24gQ2l0eSAoSOG6oW5nIG3hu6VjOiBTYWxlbSkqKg0KDQpHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaA0KDQpIMDogVOG7tyBs4buHIGtow6FjaCBow6BuZyB04burIFNhbGVtID0gMTUlDQoNCkgxOiBU4bu3IGzhu4cg4omgIDE1JQ0KDQpgYGB7cn0NCiPGr+G7m2MgbMaw4bujbmcgS2hv4bqjbmcgVGluIGPhuq15DQpjaXR5X2NvdW50IDwtIHN1bShkYXRhJENpdHkgPT0gIlNhbGVtIikNCnByb3BfY2l0eSA8LSBjaXR5X2NvdW50IC8gbg0Kc2VfY2l0eSA8LSBzcXJ0KHByb3BfY2l0eSAqICgxIC0gcHJvcF9jaXR5KSAvIG4pDQpjaV9jaXR5IDwtIHByb3BfY2l0eSArIGMoLTEsIDEpICogMS45NiAqIHNlX2NpdHkNCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIFNhbGVtOiIsIHJvdW5kKGNpX2NpdHkgKiAxMDAsIDIpLCAiJVxuIikNCg0KYGBgDQoNCg0KYGBge3J9DQojS2nhu4NtIMSR4buLbmggR2nhuqMgdGh1eeG6v3QgKEgwOiBU4bu3IGzhu4cgU2FsZW0gPSAwLjE1KQ0KcHJvcC50ZXN0KGNpdHlfY291bnQsIG4sIHAgPSAwLjE1LCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQpL4bq/dCBxdeG6oyBwaMOibiB0w61jaA0KDQpLaG/huqNuZyB0aW4gY+G6rXkgOTUlOiBbOS4zNyUsIDEwLjM1JV0NCg0KcC12YWx1ZTogPCAyZS0xNg0KDQpOaOG6rW4geMOpdA0KVOG7tyBs4buHIGtow6FjaCBow6BuZyDEkeG6v24gdOG7qyBTYWxlbSB0aOG6pXAgaMahbiBuaGnhu4F1IHNvIHbhu5tpIGdp4bqjIMSR4buLbmggMTUlLiBLaG/huqNuZyB0aW4gY+G6rXkgbmjhu48gdsOgIHAgcuG6pXQgdGjhuqVwIGNobyB0aOG6pXkgc+G7sSBraMOhYyBiaeG7h3QgY8OzIMO9IG5naMSpYSByw7UgcuG7h3QuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IFNhbGVtIGtow7RuZyBwaOG6o2kgdGjhu4sgdHLGsOG7nW5nIHRy4buNbmcgeeG6v3UgdHJvbmcgZOG7ryBsaeG7h3UgaGnhu4duIHThuqFpLg0KDQojIyAqKkJp4bq/biBTdGF0ZW9yUHJvdmluY2UgKEjhuqFuZyBt4bulYzogV0EpKioNCg0KR2nhuqMgdGh1eeG6v3Qga2nhu4NtIMSR4buLbmgNCg0KSDA6IFThu7cgbOG7hyBraMOhY2ggaMOgbmcg4bufIGJhbmcgV0EgPSA0MCUNCg0KSDE6IFThu7cgbOG7hyDiiaAgNDAlDQoNCmBgYHtyfQ0KI8av4bubYyBsxrDhu6NuZyBLaG/huqNuZyBUaW4gY+G6rXkNCnN0YXRlX2NvdW50IDwtIHN1bShkYXRhJFN0YXRlb3JQcm92aW5jZSA9PSAiV0EiKQ0KcHJvcF9zdGF0ZSA8LSBzdGF0ZV9jb3VudCAvIG4NCnNlX3N0YXRlIDwtIHNxcnQocHJvcF9zdGF0ZSAqICgxIC0gcHJvcF9zdGF0ZSkgLyBuKQ0KY2lfc3RhdGUgPC0gcHJvcF9zdGF0ZSArIGMoLTEsIDEpICogMS45NiAqIHNlX3N0YXRlDQpjYXQoIktob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBXQToiLCByb3VuZChjaV9zdGF0ZSAqIDEwMCwgMiksICIlXG4iKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiNLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dCAoSDA6IFThu7cgbOG7hyBXQSA9IDAuNCkNCnByb3AudGVzdChzdGF0ZV9jb3VudCwgbiwgcCA9IDAuNCwgY29uZi5sZXZlbCA9IDAuOTUpDQpgYGANCg0KS+G6v3QgcXXhuqMgcGjDom4gdMOtY2gNCg0KS2hv4bqjbmcgdGluIGPhuq15IDk1JTogWzMxLjcxJSwgMzMuMjYlXQ0KDQpwLXZhbHVlOiA8IDJlLTE2DQoNCk5o4bqtbiB4w6l0DQpU4bu3IGzhu4cga2jDoWNoIGjDoG5nIHThu6sgYmFuZyBXQSB0aOG6pXAgaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBnaeG6oyDEkeG7i25oLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBXQSBraMO0bmcgY2hp4bq/bSDGsHUgdGjhur8gdHJvbmcgbeG6q3UsIHbDoCBjw7MgdGjhu4MgY+G6p24gxJFp4buBdSBjaOG7iW5oIG7hur91IG3huqt1IGPhuqduIMSR4bqhaSBkaeG7h24gY2hvIGJhbmcgbsOgeS4NCg0KDQpgYGB7cn0NCiMgxJDhur9tIHPhu5EgbMaw4bujbmcgZ2lhbyBk4buLY2ggY2hvIENhbmFkYSB2w6AgTWV4aWNvDQpjYW5hZGFfY291bnQgPC0gc3VtKGRhdGEkQ291bnRyeSA9PSAiQ2FuYWRhIikgICMgODA5DQptZXhpY29fY291bnQgPC0gc3VtKGRhdGEkQ291bnRyeSA9PSAiTWV4aWNvIikgICMgMzY4OA0KbiA8LSBucm93KGRhdGEpICAjIDE0MDU5DQpgYGANCg0KDQpgYGB7cn0NCiMgS2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3QNCnByb3AudGVzdChjKGNhbmFkYV9jb3VudCwgbWV4aWNvX2NvdW50KSwgbiA9IGMobiwgbiksIA0KICAgICAgICAgIHAgPSBjKDAuNSwgMC41KSwgYWx0ZXJuYXRpdmUgPSAibGVzcyIsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KYGBgDQoNCiMjICoqQmnhur9uIENvdW50cnkgKEjhuqFuZyBt4bulYzogVVNBKSoqDQoNCkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oDQoNCkgwOiBU4bu3IGzhu4cga2jDoWNoIGjDoG5nIHThu6sgVVNBID0gODAlDQoNCkgxOiBU4bu3IGzhu4cg4omgIDgwJQ0KDQoNCmBgYHtyfQ0KI8av4bubYyBsxrDhu6NuZyBLaG/huqNuZyBUaW4gY+G6rXkNCmNvdW50cnlfY291bnQgPC0gc3VtKGRhdGEkQ291bnRyeSA9PSAiVVNBIikNCnByb3BfY291bnRyeSA8LSBjb3VudHJ5X2NvdW50IC8gbg0Kc2VfY291bnRyeSA8LSBzcXJ0KHByb3BfY291bnRyeSAqICgxIC0gcHJvcF9jb3VudHJ5KSAvIG4pDQpjaV9jb3VudHJ5IDwtIHByb3BfY291bnRyeSArIGMoLTEsIDEpICogMS45NiAqIHNlX2NvdW50cnkNCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIFVTQToiLCByb3VuZChjaV9jb3VudHJ5ICogMTAwLCAyKSwgIiVcbiIpDQpgYGANCg0KYGBge3J9DQojS2nhu4NtIMSR4buLbmggR2nhuqMgdGh1eeG6v3QgKEgwOiBU4bu3IGzhu4cgVVNBID0gMC44KQ0KcHJvcC50ZXN0KGNvdW50cnlfY291bnQsIG4sIHAgPSAwLjgsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KYGBgDQoNCkvhur90IHF14bqjIHBow6JuIHTDrWNoDQoNCktob+G6o25nIHRpbiBj4bqteSA5NSU6IFs2Ny4yNCUsIDY4Ljc4JV0NCg0KcC12YWx1ZTogPCAyZS0xNg0KDQpOaOG6rW4geMOpdA0KVOG7tyBs4buHIGtow6FjaCBow6BuZyB04burIEhvYSBL4buzIHRo4bqlcCBoxqFuIGjhurNuIHNvIHbhu5tpIGdp4bqjIMSR4buLbmggODAlLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBk4buvIGxp4buHdSBraMO0bmcgaG/DoG4gdG/DoG4gdOG6rXAgdHJ1bmcgdsOgbyB0aOG7iyB0csaw4budbmcgTeG7uSwgY8OzIHRo4buDIGRvIGRvYW5oIG5naGnhu4dwIG3hu58gcuG7mW5nIHJhIHF14buRYyB04bq/IGhv4bq3YyBs4bqleSBt4bqrdSBraMO0bmcgxJHhuqFpIGRp4buHbi4NCg0KIyMgKipCaeG6v24gUHJvZHVjdEZhbWlseSAoSOG6oW5nIG3hu6VjOiBGb29kKSoqDQoNCkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oDQoNCkgwOiBU4bu3IGzhu4cg4omlIDcwJQ0KDQpIMTogVOG7tyBs4buHIDwgNzAlIA0KDQpgYGB7cn0NCiPGr+G7m2MgbMaw4bujbmcgS2hv4bqjbmcgVGluIGPhuq15DQpmb29kX2NvdW50IDwtIHN1bShkYXRhJFByb2R1Y3RGYW1pbHkgPT0gIkZvb2QiKQ0KcHJvcF9mb29kIDwtIGZvb2RfY291bnQgLyBuDQpzZV9mb29kIDwtIHNxcnQocHJvcF9mb29kICogKDEgLSBwcm9wX2Zvb2QpIC8gbikNCmNpX2Zvb2QgPC0gcHJvcF9mb29kICsgYygtMSwgMSkgKiAxLjk2ICogc2VfZm9vZA0KY2F0KCJLaG/huqNuZyB0aW4gY+G6rXkgOTUlIGNobyB04bu3IGzhu4cgRm9vZDoiLCByb3VuZChjaV9mb29kICogMTAwLCAyKSwgIiVcbiIpDQpgYGANCg0KYGBge3J9DQojS2nhu4NtIMSR4buLbmggR2nhuqMgdGh1eeG6v3QgKEgwOiBU4bu3IGzhu4cgRm9vZCDiiaUgMC43KQ0KcHJvcC50ZXN0KGZvb2RfY291bnQsIG4sIHAgPSAwLjcsIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiLCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQpL4bq/dCBxdeG6oyBwaMOibiB0w61jaA0KDQpLaG/huqNuZyB0aW4gY+G6rXkgOTUlOiBbNzEuNTklLCAxMDAlXQ0KDQpwLXZhbHVlOiA1ZS0wOQ0KDQpOaOG6rW4geMOpdA0KVsOsIHAgcuG6pXQgbmjhu48gdsOgIHRvw6BuIGLhu5kga2hv4bqjbmcgdGluIGPhuq15IG7hurFtIHRyw6puIDcwJSwgY8OzIMSR4bunIGLhurFuZyBjaOG7qW5nIGto4bqzbmcgxJHhu4tuaCBy4bqxbmcgdOG7tyBs4buHIHPhuqNuIHBo4bqpbSB0aHXhu5ljIG5ow7NtIOKAnEZvb2TigJ0gbOG7m24gaMahbiA3MCUsIGNobyB0aOG6pXkgbmjDs20gbsOgeSBjaGnhur9tIMawdSB0aOG6vyBs4bubbiB0cm9uZyBkYW5oIG3hu6VjLg0KDQojIyAqKkJp4bq/biBQcm9kdWN0RGVwYXJ0bWVudCAoSOG6oW5nIG3hu6VjOiBTbmFjayBGb29kcykqKg0KDQpHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaA0KDQpIMDogVOG7tyBs4buHIFNuYWNrIEZvb2RzID0gMTUlDQoNCkgxOiBU4bu3IGzhu4cg4omgIDE1JQ0KDQpgYGB7cn0NCiPGr+G7m2MgbMaw4bujbmcgS2hv4bqjbmcgVGluIGPhuq15DQpkZXB0X2NvdW50IDwtIHN1bShkYXRhJFByb2R1Y3REZXBhcnRtZW50ID09ICJTbmFjayBGb29kcyIpDQpwcm9wX2RlcHQgPC0gZGVwdF9jb3VudCAvIG4NCnNlX2RlcHQgPC0gc3FydChwcm9wX2RlcHQgKiAoMSAtIHByb3BfZGVwdCkgLyBuKQ0KY2lfZGVwdCA8LSBwcm9wX2RlcHQgKyBjKC0xLCAxKSAqIDEuOTYgKiBzZV9kZXB0DQpjYXQoIktob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBTbmFjayBGb29kczoiLCByb3VuZChjaV9kZXB0ICogMTAwLCAyKSwgIiVcbiIpDQpgYGANCg0KYGBge3J9DQojS2nhu4NtIMSR4buLbmggR2nhuqMgdGh1eeG6v3QgKEgwOiBU4bu3IGzhu4cgU25hY2sgRm9vZHMgPSAwLjE1KQ0KcHJvcC50ZXN0KGRlcHRfY291bnQsIG4sIHAgPSAwLjE1LCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQpL4bq/dCBxdeG6oyBwaMOibiB0w61jaA0KDQpLaG/huqNuZyB0aW4gY+G6rXkgOTUlOiBbMTAuODYlLCAxMS45MSVdDQoNCnAtdmFsdWU6IDwgMmUtMTYNCg0KTmjhuq1uIHjDqXQNClThu7cgbOG7hyBz4bqjbiBwaOG6qW0gU25hY2sgRm9vZHMgdGjhuqVwIGjGoW4gxJHDoW5nIGvhu4Mgc28gduG7m2kgZ2nhuqMgxJHhu4tuaC4gQ8OzIHRo4buDIHRo4bqleSBy4bqxbmcgbeG6t2MgZMO5IHBo4buVIGJp4bq/biBuaMawbmcgY2jGsGEgxJHhur9uIG3hu6ljIGNoaeG6v20gMTUlLCB2w6AgZG9hbmggbmdoaeG7h3AgY8OzIHRo4buDIGPDom4gbmjhuq9jIHBow6JuIHBo4buRaSBwaMO5IGjhu6NwIGjGoW4uDQoNCg0KDQojIyAqKkJp4bq/biBQcm9kdWN0Q2F0ZWdvcnkgKEjhuqFuZyBt4bulYzogU25hY2sgRm9vZHMpKioNCmBgYHtyfQ0KI8av4bubYyBsxrDhu6NuZyBLaG/huqNuZyBUaW4gY+G6rXkNCmNhdF9jb3VudCA8LSBzdW0oZGF0YSRQcm9kdWN0Q2F0ZWdvcnkgPT0gIlNuYWNrIEZvb2RzIikNCnByb3BfY2F0IDwtIGNhdF9jb3VudCAvIG4NCnNlX2NhdCA8LSBzcXJ0KHByb3BfY2F0ICogKDEgLSBwcm9wX2NhdCkgLyBuKQ0KY2lfY2F0IDwtIHByb3BfY2F0ICsgYygtMSwgMSkgKiAxLjk2ICogc2VfY2F0DQpjYXQoIktob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBTbmFjayBGb29kczoiLCByb3VuZChjaV9jYXQgKiAxMDAsIDIpLCAiJVxuIikNCmBgYA0KDQpgYGB7cn0NCiNLaeG7g20gxJHhu4tuaCBHaeG6oyB0aHV54bq/dCAoSDA6IFThu7cgbOG7hyBTbmFjayBGb29kcyA9IDAuMTUpDQpwcm9wLnRlc3QoY2F0X2NvdW50LCBuLCBwID0gMC4xNSwgY29uZi5sZXZlbCA9IDAuOTUpDQoNCmBgYA0KS+G6v3QgcXXhuqMgcGjDom4gdMOtY2gNCg0KS2hv4bqjbmcgdGluIGPhuq15IDk1JTogWzEwLjg2JSwgMTEuOTElXQ0KDQpwLXZhbHVlOiA8IDJlLTE2DQoNCk5o4bqtbiB4w6l0Og0KVOG7tyBs4buHIGNo4buJIGtob+G6o25nIDExLjM4JSwgdGjhuqVwIGjGoW4gMTUlIG7Dqm4gY8WpbmcgYsOhYyBi4buPIGdp4bqjIHRodXnhur90IEgwLg0KDQoNCiMgKipQaOG6p24gNDogUGjDom4gdMOtY2ggTeG7kWkgcXVhbiBo4buHIGdp4buvYSBIYWkgYmnhur9uIMSQ4buLbmggdMOtbmgqKg0KDQojIyAqKiBD4bq3cCBNYXJpdGFsU3RhdHVzIHbDoCBIb21lb3duZXIqKg0KDQpgYGB7cn0NCiNC4bqjbmcgVOG6p24gc3XhuqV0IENow6lvDQpjcm9zc190YWJsZTEgPC0gdGFibGUoZGF0YSRNYXJpdGFsU3RhdHVzLCBkYXRhJEhvbWVvd25lcikNCmNyb3NzX3Byb3AxIDwtIHByb3AudGFibGUoY3Jvc3NfdGFibGUxLCBtYXJnaW4gPSAxKSAqIDEwMA0KcHJpbnQoY3Jvc3NfdGFibGUxKQ0KcHJpbnQocm91bmQoY3Jvc3NfcHJvcDEsIDIpKQ0KYGBgDQpE4buvIGxp4buHdSDEkcaw4bujYyBwaMOibiBsb+G6oWkgdGhlbyBoYWkgYmnhur9uIMSR4buLbmggdMOtbmg6IE1hcml0YWxTdGF0dXMgKFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibjogTSDigJMgTWFycmllZCwgUyDigJMgU2luZ2xlKSB2w6AgSG9tZW93bmVyIChT4bufIGjhu691IG5ow6A6IFkg4oCTIFllcywgTiDigJMgTm8pLiBC4bqjbmcgdOG6p24gc3XhuqV0IGNobyB0aOG6pXkgbmfGsOG7nWkgxJHDoyBr4bq/dCBow7RuIGNoaeG6v20gdOG7tyBs4buHIHPhu58gaOG7r3UgbmjDoCBjYW8gaMahbiAoNzQsOTYlKSBzbyB24bubaSBuZ8aw4budaSDEkeG7mWMgdGjDom4gKDQ1LDg0JSkuIMSQaeG7gXUgbsOgeSB0aOG7gyBoaeG7h24gc+G7sSBraMOhYyBiaeG7h3QgxJHDoW5nIGvhu4MgdHJvbmcgaMOgbmggdmkgc+G7nyBo4buvdSBuaMOgIGdp4buvYSBoYWkgbmjDs20gaMO0biBuaMOibi4NCg0KYGBge3J9DQojVHLhu7FjIHF1YW4gaMOzYQ0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gTWFyaXRhbFN0YXR1cywgZmlsbCA9IEhvbWVvd25lcikpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsNCiAgbGFicyh0aXRsZSA9ICJT4bufIGjhu691IE5ow6AgdGhlbyBUw6xuaCB0cuG6oW5nIEjDtG4gbmjDom4iLCB4ID0gIk1hcml0YWwgU3RhdHVzIiwgeSA9ICJU4bu3IGzhu4ciLCBmaWxsID0gIkhvbWVvd25lciIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCkJp4buDdSDEkeG7kyB0aGFuaCB04bu3IGzhu4cgKHN0YWNrZWQgYmFyIGNoYXJ0IHRoZW8gdOG7tyBs4buHIHBo4bqnbiB0csSDbSkgdHLhu7FjIHF1YW4gaMOzYSDEkWnhu4F1IG7DoHkgcuG6pXQgcsO1IHLDoG5nOiBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4gY8OzIHh1IGjGsOG7m25nIHPhu58gaOG7r3UgbmjDoCBuaGnhu4F1IGjGoW4gxJHDoW5nIGvhu4Mgc28gduG7m2kgbmfGsOG7nWkgxJHhu5ljIHRow6JuLg0KDQpOaOG6sW0ga2nhu4NtIMSR4buLbmggeGVtIE1hcml0YWxTdGF0dXMgdsOgIEhvbWVvd25lciBjw7MgbeG7kWkgcXVhbiBo4buHIHRo4buRbmcga8OqIGhheSBraMO0bmcsIGtp4buDbSDEkeG7i25oIENoaS1iw6xuaCBwaMawxqFuZyDEkcaw4bujYyBz4butIGThu6VuZy4NCg0KR2nhuqMgdGh1eeG6v3QgSOKCgDogSGFpIGJp4bq/biBNYXJpdGFsU3RhdHVzIHbDoCBIb21lb3duZXIgbMOgIMSR4buZYyBs4bqtcC4NCg0KR2nhuqMgdGh1eeG6v3QgSOKCgTogSGFpIGJp4bq/biBjw7MgbeG7kWkgbGnDqm4gaOG7hyB0aOG7kW5nIGvDqi4NCg0KYGBge3J9DQoNCiNLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcNCmNoaV90ZXN0MSA8LSBjaGlzcS50ZXN0KGNyb3NzX3RhYmxlMSkNCnByaW50KGNoaV90ZXN0MSkNCmBgYA0KS+G6v3QgcXXhuqM6DQoNCkdpw6EgdHLhu4sgdGjhu5FuZyBrw6ogY2hpIGLDrG5oIHBoxrDGoW5nIChYwrIpID0gMTI0MQ0KDQpC4bqtYyB04buxIGRvIChkZikgPSAxDQoNCnAtdmFsdWUgPCAyZS0xNg0KDQpOaOG6rW4geMOpdDoNCg0KS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nIChQZWFyc29uJ3MgQ2hpLXNxdWFyZWQgVGVzdCkgbmjhurFtIHjDoWMgxJHhu4tuaCB4ZW0gaGFpIGJp4bq/biDEkeG7i25oIHTDrW5oIGPDsyDEkeG7mWMgbOG6rXAgbmhhdSBoYXkga2jDtG5nLiDhu54gxJHDonksIGdpw6EgdHLhu4sgcCBy4bqldCBuaOG7jyAoPCAwLDA1KSwgY2hvIHRo4bqleSBiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3QgxJHhu5ljIGzhuq1wLCB04bupYyBsw6AgY8OzIG3hu5FpIGxpw6puIGjhu4cgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiBnaeG7r2EgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIHbDoCBz4bufIGjhu691IG5ow6AuIEPhu6UgdGjhu4MsIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0biBjw7MgeHUgaMaw4bubbmcgc+G7nyBo4buvdSBuaMOgIG5oaeG7gXUgaMahbiBzbyB24bubaSBuZ8aw4budaSDEkeG7mWMgdGjDom4uDQoNCg0KIyMgKipD4bq3cCBBbm51YWxJbmNvbWUgdsOgIFByb2R1Y3RGYW1pbHkqKg0KDQoNCg0KYGBge3J9DQojQuG6o25nIFThuqduIHN14bqldCBDaMOpbw0KY3Jvc3NfdGFibGUyIDwtIHRhYmxlKGRhdGEkQW5udWFsSW5jb21lLCBkYXRhJFByb2R1Y3RGYW1pbHkpDQpjcm9zc19wcm9wMiA8LSBwcm9wLnRhYmxlKGNyb3NzX3RhYmxlMiwgbWFyZ2luID0gMSkgKiAxMDANCnByaW50KGNyb3NzX3RhYmxlMikNCnByaW50KHJvdW5kKGNyb3NzX3Byb3AyLCAyKSkNCmBgYA0KDQpC4bqjbmcgY2hvIHRo4bqleSBwaOG6p24gbOG7m24gY8OhYyBuaMOzbSB0aHUgbmjhuq1wIHRpw6p1IGTDuW5nIGNo4bunIHnhur91IOG7nyBuaMOzbSBz4bqjbiBwaOG6qW0g4oCcRm9vZOKAnSAoY2hp4bq/bSBraG/huqNuZyA3MOKAkzczJSksIHRp4bq/cCB0aGVvIGzDoCDigJxOb24tQ29uc3VtYWJsZeKAnSB2w6AgdGjhuqVwIG5o4bqldCBsw6Ag4oCcRHJpbmvigJ0sIGLhuqV0IGvhu4MgbeG7qWMgdGh1IG5o4bqtcC4gVOG7tyBs4buHIG7DoHkgdMawxqFuZyDEkeG7kWkg4buVbiDEkeG7i25oIGdp4buvYSBjw6FjIG5ow7NtIHRodSBuaOG6rXAsIGNobyB0aOG6pXkgc+G7sSBwaMOibiBi4buRIMSR4buTbmcgxJHhu4F1IHRoZW8gbmjDs20gc+G6o24gcGjhuqltLg0KDQpgYGB7cn0NCiNUcuG7sWMgcXVhbiBow7NhDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBBbm51YWxJbmNvbWUsIGZpbGwgPSBQcm9kdWN0RmFtaWx5KSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKw0KICBsYWJzKHRpdGxlID0gIk5ow7NtIFPhuqNuIHBo4bqpbSB0aGVvIFRodSBuaOG6rXAiLCB4ID0gIkFubnVhbCBJbmNvbWUiLCB5ID0gIlThu7cgbOG7hyIsIGZpbGwgPSAiUHJvZHVjdCBGYW1pbHkiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KQmnhu4N1IMSR4buTIHThu7cgbOG7hyB0aGVvIG5ow7NtIHRodSBuaOG6rXAgY2hvIHRo4bqleSBkw7kgdGh1IG5o4bqtcCB0xINuZyBoYXkgZ2nhuqNtLCB04bu3IHRy4buNbmcgY8OhYyBuaMOzbSBz4bqjbiBwaOG6qW0gduG6q24ga2jDtG5nIGPDsyBz4buxIGNow6puaCBs4buHY2ggbOG7m24uDQoNCk5o4bqxbSBraeG7g20gxJHhu4tuaCB4ZW0gQW5udWFsSW5jb21lIHbDoCBQcm9kdWN0RmFtaWx5IGPDsyBt4buRaSBxdWFuIGjhu4cgdGjhu5FuZyBrw6ogaGF5IGtow7RuZywga2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nIMSRxrDhu6NjIHPhu60gZOG7pW5nLg0KDQpHaeG6oyB0aHV54bq/dCBI4oKAOiBIYWkgYmnhur9uIEFubnVhbEluY29tZXIgdsOgIFByb2R1Y3RGYW1pbHkgbMOgIMSR4buZYyBs4bqtcC4NCg0KR2nhuqMgdGh1eeG6v3QgSOKCgTogSGFpIGJp4bq/biBjw7MgbeG7kWkgbGnDqm4gaOG7hyB0aOG7kW5nIGvDqi4NCg0KYGBge3J9DQojS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nDQpjaGlfdGVzdDIgPC0gY2hpc3EudGVzdChjcm9zc190YWJsZTIpDQpwcmludChjaGlfdGVzdDIpDQpgYGANCkvhur90IHF14bqjOg0KDQpHacOhIHRy4buLIHRo4buRbmcga8OqIFjCsiA9IDE1DQoNCmRmID0gMTQNCg0KcC12YWx1ZSA9IDAuNA0KDQpOaOG6rW4geMOpdDoNCg0KVuG7m2kgcC12YWx1ZSA9IDAuNCAoPiAwLjA1KSwgdGEga2jDtG5nIGLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCDEkeG7mWMgbOG6rXAsIHThu6ljIGzDoCBraMO0bmcgY8OzIGLhurFuZyBjaOG7qW5nIHRo4buRbmcga8OqIGNobyB0aOG6pXkgbeG7kWkgcXVhbiBo4buHIGdp4buvYSB0aHUgbmjhuq1wIHbDoCBsb+G6oWkgc+G6o24gcGjhuqltIMSRxrDhu6NjIHRpw6p1IGTDuW5nLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBow6BuaCB2aSBtdWEgc+G6r20gdGhlbyBuaMOzbSBz4bqjbiBwaOG6qW0gZMaw4budbmcgbmjGsCBraMO0bmcgYuG7iyDhuqNuaCBoxrDhu59uZyBi4bufaSBt4bupYyB0aHUgbmjhuq1wLg0KDQoNCg0KIyMgKiogQ+G6t3AgR2VuZGVyIHbDoCAgTWFyaXRhbFN0YXR1cyoqDQoNCmBgYHtyfQ0KI0LhuqNuZyB04bqnbiBzdeG6pXQgY2jDqW8NCmNyb3NzX3RhYmxlMyA8LSB0YWJsZShkYXRhJEdlbmRlciwgZGF0YSQgTWFyaXRhbFN0YXR1cykNCmNyb3NzX3Byb3AzIDwtIHByb3AudGFibGUoY3Jvc3NfdGFibGUzLCBtYXJnaW4gPSAxKSAqIDEwMA0KcHJpbnQoY3Jvc3NfdGFibGUzKQ0KcHJpbnQocm91bmQoY3Jvc3NfcHJvcDMsIDIpKQ0KYGBgDQoNCk5ow6xuIGNodW5nLCBr4bq/dCBxdeG6oyBjaG8gdGjhuqV5IHThu7cgbOG7hyBuZ8aw4budaSBr4bq/dCBow7RuIHbDoCDEkeG7mWMgdGjDom4gZ2nhu69hIG5hbSB2w6AgbuG7ryBsw6Aga2jDoSBjw6JuIGLhurFuZy4gVHJvbmcgxJHDsywgbuG7ryBnaeG7m2kgY8OzIHThu7cgbOG7hyBr4bq/dCBow7RuIGNhbyBoxqFuIG3hu5l0IGNow7p0IHNvIHbhu5tpIG5hbSBnaeG7m2kgKDUwLjI0JSBzbyB24bubaSA0Ny4zOCUpLCB0cm9uZyBraGkgbmFtIGdp4bubaSBjw7MgdOG7tyBs4buHIMSR4buZYyB0aMOibiBjYW8gaMahbiAoNTIuNjIlKS4NCg0KYGBge3J9DQojIEJp4buDdSDEkeG7kyBj4buZdCBjaOG7k25nDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBHZW5kZXIsIGZpbGwgPSBNYXJpdGFsU3RhdHVzKSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgVMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIHRoZW8gR2nhu5tpIHTDrW5oIiwgeCA9ICJHZW5kZXIiLCB5ID0gIlThu7cgbOG7hyIsIGZpbGwgPSAiIE1hcml0YWxTdGF0dXMiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQpgYGANCg0KTmjhurFtIGtp4buDbSDEkeG7i25oIHhlbSBHZW5kZXIgdsOgIE1hcml0YWxTdGF0dXMgY8OzIG3hu5FpIHF1YW4gaOG7hyB0aOG7kW5nIGvDqiBoYXkga2jDtG5nLCBraeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcuDQoNCkdp4bqjIHRodXnhur90IEjigoA6IEhhaSBiaeG6v24gR2VuZGVyIHbDoCBNYXJpdGFsU3RhdHVzIGzDoCDEkeG7mWMgbOG6rXAuDQoNCkdp4bqjIHRodXnhur90IEjigoE6IEhhaSBiaeG6v24gY8OzIG3hu5FpIGxpw6puIGjhu4cgdGjhu5FuZyBrw6ouDQoNCmBgYHtyfQ0KIyBLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcNCmNoaV90ZXN0MyA8LSBjaGlzcS50ZXN0KGNyb3NzX3RhYmxlMykNCnByaW50KGNoaV90ZXN0MykNCmBgYA0KDQpL4bq/dCBxdeG6oyBraeG7g20gxJHhu4tuaDoNCg0KR2nDoSB0cuG7iyB0aOG7kW5nIGvDqiBDaGktc3F1YXJlZDogWMKyID0gMTENCg0KQuG6rWMgdOG7sSBkbzogZGYgPSAxDQoNCkdpw6EgdHLhu4sgcDogcC12YWx1ZSA8IDdlLTA0DQoNCk5o4bqtbiB4w6l0OiANClbhu5tpIGdpw6EgdHLhu4sgcCBuaOG7jyBoxqFuIDAuMDUgcuG6pXQgbmhp4buBdSAocCA8IDdlLTA0KSwgdGEgYsOhYyBi4buPIGdp4bqjIHRodXnhur90IEjigoAuIMSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IGPDsyBt4buRaSBsacOqbiBo4buHIHRo4buRbmcga8OqIHLDtSBy4buHdCBnaeG7r2EgZ2nhu5tpIHTDrW5oIHbDoCB0w6xuaCB0cuG6oW5nIGjDtG4gbmjDom4gdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UuIE7Ds2kgY8OhY2gga2jDoWMsIGdp4bubaSB0w61uaCBjw7Mg4bqjbmggaMaw4bufbmcgxJHDoW5nIGvhu4MgxJHhur9uIHTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiBj4bunYSBraMOhY2ggaMOgbmcgc2nDqnUgdGjhu4suDQoNCg0KIyAqKlBo4bqnbiA1OiBU4buVbmcga+G6v3QgdsOgIFRo4bqjbyBsdeG6rW4qKg0KDQojIyAqKlTDs20gdOG6r3Qgbmjhu69uZyBwaMOhdCBoaeG7h24gY2jDrW5oKioNCg0KUGjDom4gdMOtY2ggY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCB0cm9uZyB04bqtcCBk4buvIGxp4buHdSAqU3VwZXJtYXJrZXQgVHJhbnNhY3Rpb25zLmNzdiogxJHDoyBjdW5nIGPhuqVwIG5o4buvbmcgaGnhu4N1IGJp4bq/dCDEkcOhbmcgY2jDuiDDvSB24buBIMSR4bq3YyDEkWnhu4NtIG5ow6JuIGto4bqpdSBo4buNYyBj4bunYSBraMOhY2ggaMOgbmcgdsOgIGjDoG5oIHZpIHRpw6p1IGTDuW5nIGPhu6dhIGjhu40uIE3hu5l0IHPhu5EgcGjDoXQgaGnhu4duIG7hu5VpIGLhuq10IGfhu5NtOg0KDQoqICoqR2nhu5tpIHTDrW5oKiogcGjDom4gYuG7kSBraMOhIGPDom4gYuG6sW5nLCBuaMawbmcgdOG7tyBs4buHIG7hu68gY8OzIHBo4bqnbiBuaOG7iW5oIGjGoW4gKGtob+G6o25nIDUxJSksIMSRaeG7gXUgbsOgeSBjw7MgdGjhu4MgcGjhuqNuIMOhbmggdmFpIHRyw7IgdGjGsOG7nW5nIHRo4bqleSBj4bunYSBwaOG7pSBu4buvIHRyb25nIHF1eeG6v3QgxJHhu4tuaCBtdWEgc+G6r20gZ2lhIMSRw6xuaC4NCiogKipUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4qKiBjaG8gdGjhuqV5IGfhuqduIDQ5JSBraMOhY2ggaMOgbmcgxJHDoyBr4bq/dCBow7RuLCBn4bujaSDDvSBy4bqxbmcgbmh1IGPhuqd1IG11YSBz4bqvbSBj4bunYSBo4buZIGdpYSDEkcOsbmggbMOgIG3hu5l0IHnhur91IHThu5EgcXVhbiB0cuG7jW5nIHRyb25nIGjDoG5oIHZpIHRpw6p1IGTDuW5nLg0KKiAqKlThu7cgbOG7hyBz4bufIGjhu691IG5ow6AgY2FvIChraG/huqNuZyA2MCUpKiogY2hvIHRo4bqleSBwaOG6p24gbOG7m24ga2jDoWNoIGjDoG5nIGPDsyBt4bupYyDEkeG7mSDhu5VuIMSR4buLbmgga2luaCB04bq/IG5o4bqldCDEkeG7i25oLg0KKiAqKlRodSBuaOG6rXAqKiBwaMOibiBi4buRIGNo4bunIHnhur91IHRyb25nIG5ow7NtIDMwLjAwMOKAkzUwLjAwMCBVU0QgKGNoaeG6v20gaMahbiAzMiUpLCBjaG8gdGjhuqV5IHThuq1wIGtow6FjaCBow6BuZyBjaOG7pyB54bq/dSB0aHXhu5ljIG5ow7NtIHRodSBuaOG6rXAgdHJ1bmcgYsOsbmguDQoqICoqSMOgbmggdmkgdGnDqnUgZMO5bmcqKiB04bqtcCB0cnVuZyBt4bqhbmggdsOgbyBuaMOzbSBz4bqjbiBwaOG6qW0gKipUaOG7sWMgcGjhuqltKiogKGjGoW4gNzIlKSwgdHJvbmcgxJHDsyBjw6FjIGRhbmggbeG7pWMgbmjGsCAqKlNuYWNrIEZvb2RzKiogdsOgICoqQnJlYWtmYXN0IEZvb2RzKiogY8WpbmcgY2hp4bq/bSB04bu3IHRy4buNbmcgxJHDoW5nIGvhu4MuDQoqIEPDoWMgcGjDom4gdMOtY2ggYuG6o25nIGNow6lvIHbDoCBraeG7g20gxJHhu4tuaCBDaGktc3F1YXJlZCDEkcOjIHBow6F0IGhp4buHbiAqKm5o4buvbmcgbeG7kWkgbGnDqm4gaOG7hyBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqKiogZ2nhu69hIG5oaeG7gXUgY+G6t3AgYmnhur9uIG5oxrA6ICpHaeG7m2kgdMOtbmgg4oCTIFTDrG5oIHRy4bqhbmcgaMO0biBuaMOibiosICpUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4g4oCTIFPhu58gaOG7r3UgbmjDoCosICpUw6xuaCB0cuG6oW5nIGjDtG4gbmjDom4g4oCTIE5ow7NtIHPhuqNuIHBo4bqpbSosIHYudi4sIGNobyB0aOG6pXkgxJHhurdjIMSRaeG7g20gbmjDom4ga2jhuql1IGjhu41jIGPDsyB0aOG7gyDhuqNuaCBoxrDhu59uZyDEkeG6v24gaMOgbmggdmkgbXVhIGjDoG5nLg0KDQojIyAqKkjhuqFuIGNo4bq/IGPhu6dhIHBow6JuIHTDrWNoKioNCg0KRMO5IMSRw6MgbWFuZyBs4bqhaSBuaGnhu4F1IGvhur90IHF14bqjIGjhu691IMOtY2gsIHBow6JuIHTDrWNoIHbhuqtuIHThu5NuIHThuqFpIG3hu5l0IHPhu5EgaOG6oW4gY2jhur86DQoNCiogKipHaeG7m2kgaOG6oW4g4bufIGJp4bq/biDEkeG7i25oIHTDrW5oKio6IFZp4buHYyBjaOG7iSB04bqtcCB0cnVuZyB2w6BvIGPDoWMgYmnhur9uIMSR4buLbmggdMOtbmgga2hp4bq/biBwaMOibiB0w61jaCB0aGnhur91IGNoaeG7gXUgc8OidSB0cm9uZyB2aeG7h2MgxJFvIGzGsOG7nW5nIGPGsOG7nW5nIMSR4buZIHRpw6p1IGTDuW5nICh2w60gZOG7pTogZ2nDoSB0cuG7iyDEkcahbiBow6BuZywgdOG6p24gc3XhuqV0IG11YSBz4bqvbSkuDQoqICoqQ2jhuqV0IGzGsOG7o25nIHbDoCB0w61uaCDEkeG6p3kgxJHhu6cgY+G7p2EgZOG7ryBsaeG7h3UqKjogTeG7mXQgc+G7kSBiaeG6v24gY8OzIHRo4buDIGLhu4sgdGhp4bq/dSBnacOhIHRy4buLIGhv4bq3YyBjaMawYSDEkcaw4bujYyBjaHXhuqluIGjDs2EgaG/DoG4gdG/DoG4uDQoqICoqS8OtY2ggdGjGsOG7m2MgbeG6q3Uga2jDtG5nIMSR4buBdSoqOiBN4buZdCBz4buRIG5ow7NtICh2w60gZOG7pTogdGjDoG5oIHBo4buRIFNhbGVtIGhheSBiYW5nIFdBKSBjw7Mgc+G7kSBsxrDhu6NuZyBxdWFuIHPDoXQgbmjhu48sIGPDsyB0aOG7gyBsw6BtIGdp4bqjbSDEkeG7mSB0aW4gY+G6rXkgY+G7p2EgY8OhYyBraeG7g20gxJHhu4tuaCB0aOG7kW5nIGvDqiBsacOqbiBxdWFuLg0KKiAqKkNoxrBhIGtp4buDbSBzb8OhdCB54bq/dSB04buRIG5oaeG7hXUqKjogTeG7mXQgc+G7kSBt4buRaSBxdWFuIGjhu4cgcXVhbiBzw6F0IMSRxrDhu6NjIGPDsyB0aOG7gyBi4buLIOG6o25oIGjGsOG7n25nIGLhu59pIGPDoWMgYmnhur9uIOG6qW4gY2jGsGEgxJHGsOG7o2MgxJHGsGEgdsOgbyBtw7QgaMOsbmguDQoNCiMjIyAqKsSQ4buBIHh14bqldCBjaG8gZG9hbmggbmdoaeG7h3AqKg0KDQpU4burIGPDoWMgcGjDoXQgaGnhu4duIHRyw6puLCBjw7MgdGjhu4MgxJHGsGEgcmEgbeG7mXQgc+G7kSDEkeG7gSB4deG6pXQgbmjGsCBzYXU6DQoNCiogKipDaGnhur9uIGzGsOG7o2MgcGjDom4ga2jDumMga2jDoWNoIGjDoG5nKio6IERvIHThu7cgbOG7hyBraMOhY2ggaMOgbmcgbuG7ryB2w6AgxJHDoyBr4bq/dCBow7RuIGtow6EgY2FvLCBkb2FuaCBuZ2hp4buHcCBjw7MgdGjhu4MgeMOieSBk4buxbmcgY8OhYyBjaMawxqFuZyB0csOsbmgga2h1eeG6v24gbcOjaSBob+G6t2Mgc+G6o24gcGjhuqltIGjGsOG7m25nIMSR4bq/biBuaMOzbSBraMOhY2ggaMOgbmcgZ2lhIMSRw6xuaCBob+G6t2MgcGjhu6UgbuG7ryBu4buZaSB0cuG7oy4NCiogKipU4buRaSDGsHUgaMOzYSBkYW5oIG3hu6VjIHPhuqNuIHBo4bqpbSoqOiBW4bubaSBt4bupYyDEkeG7mSB0acOqdSBkw7luZyBjYW8gY2hvIG5ow7NtIHRo4buxYyBwaOG6qW0sIMSR4bq3YyBiaeG7h3QgbMOgICoqU25hY2sgRm9vZHMqKiwgZG9hbmggbmdoaeG7h3AgbsOqbiB0aeG6v3AgdOG7pWMgbeG7nyBy4buZbmcgY2jhu6duZyBsb+G6oWkgaG/hurdjIHRoxrDGoW5nIGhp4buHdSB0cm9uZyBkYW5oIG3hu6VjIG7DoHkuDQoqICoqUGjDom4gYuG7lSBuZ3Xhu5NuIGzhu7FjIHRp4bq/cCB0aOG7iyB0aGVvIGtodSB24buxYyoqOiBWw6wgdOG7tyBs4buHIGtow6FjaCBow6BuZyBjaMOqbmggbOG7h2NoIHRoZW8gdGjDoG5oIHBo4buRL2JhbmcsIGPhuqduIHhlbSB4w6l0IGzhuqFpIGNoaeG6v24gbMaw4bujYyBwaMOibiBwaOG7kWkgdsOgIHF14bqjbmcgYsOhIHRoZW8gxJHhu4thIHBoxrDGoW5nLCDEkeG6t2MgYmnhu4d0IHThuqFpIG5o4buvbmcgbsahaSBjw7MgdGnhu4FtIG7Eg25nIGNoxrBhIMSRxrDhu6NjIGtoYWkgdGjDoWMgbmjGsCBTYWxlbS4NCg0KIyMjICoqQ8OidSBo4buPaSBt4bufIHbDoCBoxrDhu5tuZyBuZ2hpw6puIGPhu6l1IHRp4bq/cCB0aGVvKioNCg0KUGjDom4gdMOtY2ggbsOgeSBt4bufIHJhIG3hu5l0IHPhu5EgY8OidSBo4buPaSB2w6AgaMaw4bubbmcgbmdoacOqbiBj4bupdSBjw7MgdGjhu4MgdGnhur9wIHThu6VjIGtoYWkgdGjDoWM6DQoNCiogKipN4buRaSBxdWFuIGjhu4cgduG7m2kgY8OhYyBiaeG6v24gxJHhu4tuaCBsxrDhu6NuZyoqOiBMaeG7h3UgdGh1IG5o4bqtcCwgxJHhu5kgdHXhu5VpIGhheSBnacOhIHRy4buLIGjDs2EgxJHGoW4gdHJ1bmcgYsOsbmggY8OzIOG6o25oIGjGsOG7n25nIMSR4bq/biBs4buxYSBjaOG7jW4gbmjDs20gc+G6o24gcGjhuqltIGhheSBraMO0bmc/DQoqICoqUGjDom4gdMOtY2gga+G6v3QgaOG7o3AgxJHhu4tuaCB0w61uaCB2w6AgxJHhu4tuaCBsxrDhu6NuZyoqOiBL4bq/dCBo4bujcCB0aMOqbSBjw6FjIHnhur91IHThu5EgbmjGsCBz4buRIGzGsOG7o25nIHPhuqNuIHBo4bqpbSBtdWEsIGdpw6EgdHLhu4sgZ2lhbyBk4buLY2gsIGhv4bq3YyB0aOG7nWkgZ2lhbiBtdWEgaMOgbmcgxJHhu4MgaGnhu4N1IHPDonUgaMahbiBow6BuaCB2aSB0acOqdSBkw7luZy4NCiogKipQaMOibiBj4bulbSBraMOhY2ggaMOgbmcgKEN1c3RvbWVyIHNlZ21lbnRhdGlvbikqKjogQ8OzIHRo4buDIMOhcCBk4bulbmcgY8OhYyBr4bu5IHRodeG6rXQgaOG7jWMgbcOheSAobWFjaGluZSBsZWFybmluZykgxJHhu4MgcGjDom4gY+G7pW0ga2jDoWNoIGjDoG5nIGThu7FhIHRyw6puIG5oaeG7gXUgYmnhur9uIMSR4buLbmggdMOtbmggdsOgIMSR4buLbmggbMaw4bujbmcga+G6v3QgaOG7o3AuDQoqICoqUGjDom4gdMOtY2ggeHUgaMaw4bubbmcgdGhlbyB0aOG7nWkgZ2lhbioqOiBO4bq/dSBk4buvIGxp4buHdSBjw7MgeeG6v3UgdOG7kSB0aOG7nWkgZ2lhbiAodsOtIGThu6UgbmfDoHkgbXVhIGjDoG5nKSwgY8OzIHRo4buDIHhlbSB4w6l0IGjDoG5oIHZpIHRpw6p1IGTDuW5nIHRoZW8gbcO5YSB24bulIGhv4bq3YyBjaHUga+G7syB0deG6p24vdGjDoW5nLg0KDQotLS0NCg0KDQojICoqUGjDom4gdMOtY2ggU3V5IGRp4buFbiBUaOG7kW5nIGvDqiB0cm9uZyBC4bqjbmcgTmfhuqt1IG5oacOqbiAyeDIqKg0KIyMgKiogTMO9IHRodXnhur90KioNCg0KDQojIyAqKlLhu6dpIHJvIHTGsMahbmcgxJHhu5FpIChSZWxhdGl2ZSBSaXNrKSoqDQoNCioqS2jDoWkgbmnhu4dtOioqDQpS4bunaSBybyB0xrDGoW5nIMSR4buRaSAoUmVsYXRpdmUgUmlzaywgdmnhur90IHThuq90IGzDoCBSUikgbMOgIG3hu5l0IGNo4buJIHPhu5EgdGjhu5FuZyBrw6ogxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4Mgc28gc8OhbmggeMOhYyBzdeG6pXQgeOG6o3kgcmEgbeG7mXQgYmnhur9uIGPhu5EgKHRoxrDhu51uZyBsw6Ag4oCcdGjDoG5oIGPDtG5n4oCdIGhv4bq3YyDigJxjw7MgxJHhurdjIMSRaeG7g23igJ0pIGdp4buvYSBoYWkgbmjDs20gcGjDom4gYmnhu4d0IHRoZW8gYmnhur9uIMSR4buZYyBs4bqtcC4gQ2jhu4kgc+G7kSBuw6B5IMSR4bq3YyBiaeG7h3QgcGjhu5UgYmnhur9uIHRyb25nIGPDoWMgbmdoacOqbiBj4bupdSBk4buLY2ggdOG7hSBo4buNYyBk4bqhbmcgdGh14bqnbiB04bqtcCAoY29ob3J0IHN0dWRpZXMpLg0KDQoqKkvDvSBoaeG7h3UgdsOgIGPDtG5nIHRo4bupYzoqKg0KDQpH4buNaSBgXHBpXzFgIHbDoCBgXHBpXzJgIGzhuqduIGzGsOG7o3QgbMOgIHjDoWMgc3XhuqV0IHRow6BuaCBjw7RuZyDhu58gaGFpIG5ow7NtIHNvIHPDoW5oLCBraGkgxJHDsyBy4bunaSBybyB0xrDGoW5nIMSR4buRaSDEkcaw4bujYyDEkeG7i25oIG5naMSpYSBuaMawIHNhdToNCg0KDQpSUiA9IGBcZnJhY3tccGlfMX17XHBpXzJ9YA0KDQoqKkdp4bqjaSB0aMOtY2g6KioNCg0KUlIgY2hvIGJp4bq/dCB4w6FjIHN14bqldCB44bqjeSByYSBz4buxIGtp4buHbiDhu58gbmjDs20gdGjhu6kgbmjhuqV0IGfhuqVwIGJhbyBuaGnDqnUgbOG6p24gc28gduG7m2kgbmjDs20gdGjhu6kgaGFpLiBO4bq/dToNCg0KKiBSUiA9IDFgOiBLaMO0bmcgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IGdp4buvYSBoYWkgbmjDs20uDQoqIFJSID4gMWA6IE5ow7NtIDEgY8OzIHjDoWMgc3XhuqV0IHjhuqN5IHJhIHPhu7Ega2nhu4duIGNhbyBoxqFuIG5ow7NtIDIuDQoqIFJSIDwgMWA6IE5ow7NtIDEgY8OzIHjDoWMgc3XhuqV0IHjhuqN5IHJhIHPhu7Ega2nhu4duIHRo4bqlcCBoxqFuIG5ow7NtIDIuDQoNCioqVsOtIGThu6UgbWluaCBo4buNYToqKg0KDQpHaeG6oyBz4butIG3hu5l0IG5naGnDqm4gY+G7qXUga2jhuqNvIHPDoXQgduG7gSB04bu3IGzhu4cgbmfGsOG7nWkg4oCcY8OzIG5ow6AgcmnDqm5n4oCdIGdp4buvYSBoYWkgbmjDs20gbmfGsOG7nWk6DQoNCnwgTmjDs20gICB8IEPDsyBuaMOgIChTdWNjZXNzKSB8IEtow7RuZyBjw7MgbmjDoCAoRmFpbCkgfCBU4buVbmcgc+G7kSB8DQp8IC0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLSB8DQp8IE5ow7NtIEEgfCA4MCAgICAgICAgICAgICAgIHwgMjAgICAgICAgICAgICAgICAgICB8IDEwMCAgICAgfA0KfCBOaMOzbSBCIHwgNDAgICAgICAgICAgICAgICB8IDYwICAgICAgICAgICAgICAgICAgfCAxMDAgICAgIHwNCg0KS2hpIMSRw7M6DQoNCiogXHBpX0EgPSBcZnJhY3s4MH17MTAwfSA9IDAuOA0KKiBccGlfQiA9IFxmcmFjezQwfXsxMDB9ID0gMC40DQoNClN1eSByYToNCg0KYFJSID0gXGZyYWN7MC44fXswLjR9ID0gMmANCg0KKipL4bq/dCBsdeG6rW46KiogWMOhYyBzdeG6pXQgY8OzIG5ow6AgcmnDqm5nIOG7nyBuaMOzbSBBIGfhuqVwIDIgbOG6p24gc28gduG7m2kgbmjDs20gQi4NCg0KLS0tDQoNCiMjICoqVOG7tyBs4buHIGNow6puaCAoT2RkcyBSYXRpbykqKg0KDQoqKktow6FpIG5p4buHbToqKg0KVOG7tyBs4buHIGNow6puaCAoT2RkcyBSYXRpbywgdmnhur90IHThuq90IGzDoCBPUikgbMOgIG3hu5l0IGNo4buJIHPhu5EgdGjhu4MgaGnhu4duIG3hu6ljIMSR4buZIGNow6puaCBs4buHY2ggZ2nhu69hIHThu7cgbOG7hyBjxrDhu6NjIHjhuqN5IHJhIHPhu7Ega2nhu4duIHRyb25nIGhhaSBuaMOzbS4gS2jDoWMgduG7m2kgUlIgZOG7sWEgdHLDqm4geMOhYyBzdeG6pXQsIE9SIHNvIHPDoW5oIHThu7cgbOG7hyBnaeG7r2EgeMOhYyBzdeG6pXQgdGjDoG5oIGPDtG5nIHbDoCB0aOG6pXQgYuG6oWkgdHJvbmcgbeG7l2kgbmjDs20uDQoNCioqVOG7tyBs4buHIGPGsOG7o2MgKE9kZHMpOioqDQpU4bu3IGzhu4cgY8aw4bujYyAob2RkKSBj4bunYSBt4buZdCBuaMOzbSAkaSQgxJHGsOG7o2MgxJHhu4tuaCBuZ2jEqWEgbMOgOg0KDQpgb2RkX2kgPSBcZnJhY3tccGlfaX17MSAtIFxwaV9pfWANCg0KDQoqKlThu7cgbOG7hyBjaMOqbmggZ2nhu69hIGhhaSBuaMOzbSAkaSQgdsOgICRqJDoqKg0KDQpgT1IgPSBcZnJhY3tvZGRfaX17b2RkX2p9ID0gXGZyYWN7XGRmcmFje1xwaV9pfXsxIC0gXHBpX2l9fXtcZGZyYWN7XHBpX2p9ezEgLSBccGlfan19ID0gXGZyYWN7XHBpX2koMSAtIFxwaV9qKX17XHBpX2ooMSAtIFxwaV9pKX1gDQoNCioqR2nhuqNpIHRow61jaDoqKg0KT1IgxJFvIGzGsOG7nW5nIG3hu6ljIMSR4buZIGNow6puaCBs4buHY2ggZ2nhu69hIGto4bqjIG7Eg25nIHjhuqN5IHJhIHbDoCBraMO0bmcgeOG6o3kgcmEgc+G7sSBraeG7h24gdHJvbmcgaGFpIG5ow7NtLiBO4bq/dToNCg0KKiBPUiA9IDE6IEtow7RuZyBjw7Mgc+G7sSBraMOhYyBiaeG7h3QuDQoqIE9SID4gMTogTmjDs20gaSBjw7MgdOG7tyBs4buHIGPGsOG7o2MgdGjDoG5oIGPDtG5nIGNhbyBoxqFuIG5ow7NtIGouDQoqIE9SIDwgMTogTmjDs20gaSBjw7MgdOG7tyBs4buHIGPGsOG7o2MgdGjDoG5oIGPDtG5nIHRo4bqlcCBoxqFuIG5ow7NtIGouDQoNCioqVsOtIGThu6UgbWluaCBo4buNYSAodGnhur9wIHThu6VjIHThu6sgdsOtIGThu6UgUlIpOioqDQoNCiogVOG7tyBs4buHIGPGsOG7o2MgbmjDs20gQTogYFxmcmFjezAuOH17MC4yfSA9IDRgDQoqIFThu7cgbOG7hyBjxrDhu6NjIG5ow7NtIEI6IGBcZnJhY3swLjR9ezAuNn0gPSBcZnJhY3syfXszfWANCg0KS2hpIMSRw7M6DQoNCmBPUiA9IFxmcmFjezR9ezIvM30gPSA2YA0KDQoqKkvhur90IGx14bqtbjoqKiBU4bu3IGzhu4cgY8aw4bujYyB0aMOgbmggY8O0bmcgKGPDsyBuaMOgKSDhu58gbmjDs20gQSBjYW8gZ+G6pXAgNiBs4bqnbiBuaMOzbSBCLg0KDQotLS0NCg0KIyMgKipTbyBzw6FuaCBnaeG7r2EgT2RkcyBSYXRpbyB2w6AgUmVsYXRpdmUgUmlzayoqDQoNCnwgxJDhurdjIMSRaeG7g20gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgUuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgKFJSKSAgICAgICAgICAgfCBU4bu3IGzhu4cgY2jDqm5oIChPUikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfA0KfCBDw7RuZyB0aOG7qWMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAkXGZyYWN7XHBpXzF9e1xwaV8yfSQgICAgICAgICAgIHwgJFxmcmFje1xwaV8xKDEgLSBccGlfMil9e1xwaV8yKDEgLSBccGlfMSl9JCAgICAgICAgICAgIHwNCnwgROG7sWEgdHLDqm4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWMOhYyBzdeG6pXQgKHByb2JhYmlsaXR5KSAgICAgICAgICB8IFThu7cgbOG7hyBjxrDhu6NjIChvZGRzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCDDnSBuZ2jEqWEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IFNvIHPDoW5oIGto4bqjIG7Eg25nIHjhuqN5IHJhIHPhu7Ega2nhu4duIHwgU28gc8OhbmggbeG7qWMgxJHhu5kgY2jDqm5oIGzhu4djaCBnaeG7r2Egb2RkcyAgICAgICAgICAgICAgICAgICAgfA0KfCBUcsaw4budbmcgaOG7o3Agc+G7rSBk4bulbmcgY2jDrW5oICAgICAgICAgICAgICAgICAgIHwgTmdoacOqbiBj4bupdSB0aHXhuqduIHThuq1wIChjb2hvcnQpICAgfCBI4buTaSBxdXkgbG9naXN0aWMsIG5naGnDqm4gY+G7qXUgYuG7h25oLWNo4bupbmcgKGNhc2UtY29udHJvbCkgfA0KfCBEaeG7hW4gZ2nhuqNpIHRy4buxYyB0aeG6v3AgY2hvIG5nxrDhu51pIGtow7RuZyBjaHV5w6puIHwgROG7hSBoxqFuICAgICAgICAgICAgICAgICAgICAgICAgICB8IEtow7MgaMahbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgR2nDoSB0cuG7iyBnaeG7m2kgaOG6oW4gICAgICAgICAgICAgICAgICAgICAgICAgICB8ICQ+IDAkLCB0aMaw4budbmcgdOG7qyAwIMSR4bq/biDiiJ4gICAgICAgIHwgJD4gMCQsIHRoxrDhu51uZyB04burIDAgxJHhur9uIOKIniAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQoNCg0KDQojIyAqKlBow6JuIHTDrWNoIGPhurdwIEdlbmRlciB2w6AgSG9tZW93bmVyKioNCg0KYGBge3J9DQojVOG6oW8gYuG6o25nIHThuqduIHN14bqldCBjaMOpbw0KY3Jvc3NfdGFibGVfZ2VuZGVyIDwtIHRhYmxlKGRhdGEkR2VuZGVyLCBkYXRhJEhvbWVvd25lcikNCmFkZG1hcmdpbnMoY3Jvc3NfdGFibGVfZ2VuZGVyKQ0KYGBgDQoNCg0KYGBge3J9DQojVMOtbmggUlIgKEhvbWVvd25lciA9IFkgY2hvIEYgc28gduG7m2kgTSkNCmxpYnJhcnkoRGVzY1Rvb2xzKQ0KDQpSZWxSaXNrKGNyb3NzX3RhYmxlX2dlbmRlcikNCiAgDQpsaWJyYXJ5KGVwaXRvb2xzKQ0Kcmlza3JhdGlvKGNyb3NzX3RhYmxlX2dlbmRlcikNCmVwaXRhYihjcm9zc190YWJsZV9nZW5kZXIsIG1ldGhvZCA9ICJyaXNrcmF0aW8iKQ0KYGBgDQoNClThu7cgc+G7kSBy4bunaSBybyAoUmlzayBSYXRpbyAtIFJSKToNCg0KVMOtbmggdG/DoW4gYuG6sW5nIFJlbFJpc2soKSBjaG8gdGjhuqV5IFJSID0gMC45NzM2ICh0aGVvIERlc2NUb29scykgdsOgIFJSID0gMC45ODIzIHbhu5tpIGtob+G6o25nIHRpbiBj4bqteSA5NSUgbMOgICgwLjk1NjI7IDEuMDA5KSAodGhlbyBlcGl0b29scykuDQoNCsSQaeG7gXUgbsOgeSBuZ+G7pSDDvSBy4bqxbmcgbmFtIGdp4bubaSBjw7Mgbmd1eSBjxqEgc+G7nyBo4buvdSBuaMOgIHRo4bqlcCBoxqFuIG3hu5l0IGNow7p0IHNvIHbhu5tpIG7hu68gZ2nhu5tpLCB0dXkgbmhpw6puIGtow6FjIGJp4buHdCBraMO0bmcgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiAocCA9IDAuMTk2NSA+IDAuMDUpLg0KDQpgYGB7cn0NCiMgVMOtbmggT1INCk9kZHNSYXRpbyhjcm9zc190YWJsZV9nZW5kZXIpIA0Kb2Rkc3JhdGlvKGNyb3NzX3RhYmxlX2dlbmRlcikgDQplcGl0YWIoY3Jvc3NfdGFibGVfZ2VuZGVyLCBtZXRob2QgPSAib2Rkc3JhdGlvIikNCmBgYA0KDQpU4bu3IHPhu5Egb2RkcyAoT2RkcyBSYXRpbyAtIE9SKToNCg0KT1IgPSAwLjk1NjQgduG7m2kga2hv4bqjbmcgdGluIGPhuq15IDk1JSBsw6AgKDAuODkzOTsgMS4wMjMpLg0KDQpL4bq/dCBxdeG6oyBuw6B5IGPFqW5nIGNobyB0aOG6pXkga2jhuqMgbsSDbmcgc+G7nyBo4buvdSBuaMOgIGdp4buvYSBoYWkgZ2nhu5tpIGzDoCB0xrDGoW5nIMSRxrDGoW5nLCB2w6Agc+G7sSBraMOhYyBiaeG7h3Qga2jDtG5nIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogKHAgPSAwLjE5NjUpLg0KDQoNCk3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGdp4bubaSB0w61uaCB2w6Aga2jhuqMgbsSDbmcgc+G7nyBo4buvdSBuaMOgIGtow7RuZyDEkeG7pyBt4bqhbmggxJHhu4MgxJHGsOG7o2MgeGVtIGzDoCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqLiBU4bu3IGzhu4cgc+G7nyBo4buvdSBuaMOgIGPhu6dhIG7hu68gZ2nhu5tpICg2MC41OSUpIGNo4buJIG5o4buJbmggaMahbiBuYW0gZ2nhu5tpICg1OS41MiUpIG3hu5l0IGPDoWNoIGtow7RuZyDEkcOhbmcga+G7gy4gRG8gxJHDsywga2jDtG5nIHRo4buDIGto4bqzbmcgxJHhu4tuaCBy4bqxbmcgZ2nhu5tpIHTDrW5oIGzDoCB54bq/dSB04buRIOG6o25oIGjGsOG7n25nIMSR4bq/biB2aeG7h2Mgc+G7nyBo4buvdSBuaMOgIHRyb25nIG3huqt1IGThu68gbGnhu4d1IG7DoHkuDQoNCg0KDQojIyAqKlBow6JuIHTDrWNoIGPhurdwIE1hcml0YWxTdGF0dXMgdsOgIEhvbWVvd25lcioqDQpgYGB7cn0NCiMgVOG6oW8gYuG6o25nIHThuqduIHN14bqldCBjaMOpbw0KY3Jvc3NfdGFibGVfbXMgPC0gdGFibGUoZGF0YSRNYXJpdGFsU3RhdHVzLCBkYXRhJEhvbWVvd25lcikNCmFkZG1hcmdpbnMoY3Jvc3NfdGFibGVfbXMpDQpgYGANCg0KDQpgYGB7cn0NCiNUw61uaCBSUg0KUmVsUmlzayhjcm9zc190YWJsZV9tcykNCnJpc2tyYXRpbyhjcm9zc190YWJsZV9tcykNCmVwaXRhYihjcm9zc190YWJsZV9tcywgbWV0aG9kID0gInJpc2tyYXRpbyIpDQpgYGANCg0KVOG7tyBz4buRIHLhu6dpIHJvIChSaXNrIFJhdGlvIC0gUlIpDQpHacOhIHRy4buLIFJSID0gMC42MTE0LCB24bubaSBraG/huqNuZyB0aW4gY+G6rXkgOTUlIGzDoCAoMC41OTQyOyAwLjYyOTIpLg0KDQrEkGnhu4F1IG7DoHkgY8OzIG5naMSpYSBsw6Agbmd1eSBjxqEgc+G7nyBo4buvdSBuaMOgIGPhu6dhIG5nxrDhu51pIMSR4buZYyB0aMOibiBjaOG7iSBi4bqxbmcga2hv4bqjbmcgNjEsMTQlIHNvIHbhu5tpIG5nxrDhu51pIMSRw6Mga+G6v3QgaMO0bi4NCg0KS2jDoWMgYmnhu4d0IG7DoHkgbMOgIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogY2FvIHbhu5tpIHAtdmFsdWUg4omIIDEuODLDlzEw4oG7wrLigbfigbcgKEZpc2hlcidzIGV4YWN0IHRlc3QpLg0KDQpgYGB7cn0NCiNUw61uaCBPUg0KT2Rkc1JhdGlvKGNyb3NzX3RhYmxlX21zKQ0Kb2Rkc3JhdGlvKGNyb3NzX3RhYmxlX21zKQ0KZXBpdGFiKGNyb3NzX3RhYmxlX21zLCBtZXRob2QgPSAib2Rkc3JhdGlvIikNCmBgYA0KDQogVOG7tyBz4buRIG9kZHMgKE9kZHMgUmF0aW8gLSBPUikNCkdpw6EgdHLhu4sgT1IgPSAwLjI4MjYsIHbhu5tpIGtob+G6o25nIHRpbiBj4bqteSA5NSUgbMOgICgwLjI2MzE7IDAuMzAzNikuDQoNCsSQaeG7gXUgxJHDsyBjaG8gdGjhuqV5IHLhurFuZyBvZGRzICh04bu3IHPhu5Ega2jhuqMgbsSDbmcgeOG6o3kgcmEgdsOgIGtow7RuZyB44bqjeSByYSkgc+G7nyBo4buvdSBuaMOgIGPhu6dhIG5nxrDhu51pIMSR4buZYyB0aMOibiB0aOG6pXAgaMahbiBraG/huqNuZyA3MS43JSBzbyB24bubaSBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4uDQoNCkvhur90IHF14bqjIG7DoHkgY8WpbmcgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiBy4bqldCBjYW8gKHAg4omIIDEuODLDlzEw4oG7wrLigbfigbcpLg0KDQpQaMOibiB0w61jaCDEkeG7i25oIGzGsOG7o25nIGNobyB0aOG6pXkgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuIGzDoCB54bq/dSB04buRIGPDsyDhuqNuaCBoxrDhu59uZyByw7UgcuG7h3QgdsOgIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogY2FvIMSR4bq/biB2aeG7h2Mgc+G7nyBo4buvdSBuaMOgIHRyb25nIG3huqt1IGto4bqjbyBzw6F0LiBD4bulIHRo4buDLCBuZ8aw4budaSDEkeG7mWMgdGjDom4gY8OzIG5ndXkgY8ahIHbDoCBvZGRzIHPhu58gaOG7r3UgbmjDoCB0aOG6pXAgaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBuZ8aw4budaSDEkcOjIGvhur90IGjDtG4uIEvhur90IHF14bqjIG7DoHkgY8OzIHRo4buDIHBo4bqjbiDDoW5oIGPDoWMgeeG6v3UgdOG7kSB4w6MgaOG7mWkgdsOgIGtpbmggdOG6vyBuaMawIG5odSBj4bqndSDhu5VuIMSR4buLbmggZ2lhIMSRw6xuaCwga2jhuqMgbsSDbmcgdMOgaSBjaMOtbmgga+G6v3QgaOG7o3AgdOG7qyBoYWkgY8OhIG5ow6JuIHRyb25nIGjDtG4gbmjDom4sIGhv4bq3YyBjw6FjIGNow61uaCBzw6FjaCBo4buXIHRy4bujIG11YSBuaMOgIGNobyBnaWEgxJHDrG5oLg0KDQoNCg==