PHÂN TÍCH THỐNG KÊ CHO DỮ LIỆU ĐỊNH TÍNH: CƠ SỞ LÝ THUYẾT


1. Giới thiệu chung

Trong nghiên cứu kinh tế và kinh doanh, nhiều biến quan trọng mang tính chất định tính, ví dụ như giới tính, hành vi tiêu dùng (mua/không mua), sở hữu tài sản (có/không). Phân tích thống kê đối với những biến này giúp hiểu được cấu trúc dân số, đặc điểm khách hàng và mối quan hệ giữa các nhóm.

Có hai cấp độ phân tích cơ bản:

  • Phân tích một biến định tính: mô tả phân phối của biến.
  • Phân tích hai biến định tính: đánh giá mối liên hệ giữa hai biến, kiểm định giả thuyết và ước lượng mức độ liên quan.

2. Phân tích mô tả một biến định tính

2.1. Tần suất và tần suất tương đối

Giả sử ta quan sát biến định tính như “Giới tính” với hai giá trị: Nam, Nữ. Có thể mô tả biến này bằng:

  • Tần suất tuyệt đối (frequency): số lần mỗi giá trị xuất hiện.
  • Tần suất tương đối: tần suất chia cho tổng quan sát (tính theo %).

2.2. Trực quan hóa

Các biểu đồ thường dùng: bar chart (cột), pie chart (tròn) để thể hiện tỷ lệ từng nhóm.


3. Ước lượng và kiểm định giả thuyết cho tỷ lệ (1 biến)

Giả sử ta đang quan tâm đến một biến nhị phân (ví dụ: sở hữu nhà – Có/Không).

3.1. Ước lượng khoảng tin cậy (KTC) cho tỷ lệ

Nếu trong mẫu có \(\hat{p}\) là tỷ lệ người “Có nhà”, ta ước lượng KTC 95% cho tỷ lệ thật \(p\) bằng:

\[ \hat{p} \pm z_{0.025} \cdot \sqrt{ \frac{ \hat{p}(1 - \hat{p}) }{n} } \]

Trong đó:

  • \(\hat{p}\): tỷ lệ mẫu
  • \(n\): kích thước mẫu
  • \(z_{0.025} \approx 1.96\): giá trị phân phối chuẩn

3.2. Kiểm định giả thuyết về tỷ lệ

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

  • \(H_0: p = p_0\)
  • \(H_1: p \ne p_0\)

Dùng kiểm định z:

\[ z = \frac{ \hat{p} - p_0 }{ \sqrt{ \frac{p_0(1 - p_0)}{n} } } \]


4. Phân tích hai biến định tính

4.1. Bảng chéo (contingency table)

Hai biến định tính (vd: Giới tính & Sở hữu nhà) được trình bày dưới dạng bảng chéo 2x2:

Có nhà Không có Tổng
Nam a b a + b
Nữ c d c + d
Tổng a + c b + d n

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

Mục tiêu: kiểm tra xem hai biến có quan hệ hay độc lập.

  • Giả thuyết:

    • \(H_0\): hai biến độc lập
    • \(H_1\): hai biến có liên hệ
  • Thống kê kiểm định:

\[ \chi^2 = \sum \frac{(O_{ij} - E_{ij})^2}{E_{ij}} \]

Trong đó:

  • \(O_{ij}\): giá trị quan sát
  • \(E_{ij}\): kỳ vọng nếu hai biến độc lập

5. Cấu trúc xác suất trong bảng ngẫu nhiên

Bảng chéo (bảng đếm) thực chất là một biểu hiện cụ thể của một mô hình xác suất ngẫu nhiên.

5.1. Các mô hình xác suất sinh ra bảng

  • Phân phối đa thức (Multinomial): Mỗi hàng là một biến đa thức (multinomial trial).
  • Phân phối siêu bội (Hypergeometric): Nếu tổng hàng/cột cố định, thường dùng trong phép hoán vị ngẫu nhiên.
  • Phân phối Poisson: thường dùng để mô hình hóa số đếm hiếm, ít dùng trong bảng 2x2.

Mục đích: Giúp hiểu rằng các kiểm định như Chi-square không chỉ mang tính cơ học, mà có nền tảng xác suất phía sau.


6. So sánh hai tỷ lệ: Các thước đo mối liên hệ

Khi muốn so sánh hai nhóm về một kết quả nhị phân, có ba thước đo phổ biến:


6.1. Hiệu hai tỷ lệ (Difference in proportions)

\[ \hat{p}_1 - \hat{p}_2 \]

  • Diễn giải: sự khác biệt tuyệt đối giữa hai tỷ lệ.
  • KTC 95%:

\[ (\hat{p}_1 - \hat{p}_2) \pm z \cdot \sqrt{ \frac{ \hat{p}_1 (1 - \hat{p}_1) }{n_1} + \frac{ \hat{p}_2 (1 - \hat{p}_2) }{n_2} } \]


6.2. Tỷ số nguy cơ (Relative Risk – RR)

\[ RR = \frac{ \hat{p}_1 }{ \hat{p}_2 } \]

  • Diễn giải: Nhóm 1 có khả năng có kết quả (vd: sở hữu nhà) gấp bao nhiêu lần so với nhóm 2.
  • Dễ hiểu và trực tiếp nhưng chỉ dùng được trong thiết kế có tính thời gian (vd: nghiên cứu cohort, điều tra dọc).

6.3. Tỷ số chênh (Odds Ratio – OR)

a. Odds là gì?

Nếu xác suất xảy ra sự kiện là \(p\), thì:

\[ \text{Odds} = \frac{p}{1 - p} \]

→ là “tỷ số cược”: bao nhiêu lần có so với không.

b. Odds Ratio là gì?

\[ OR = \frac{ \text{Odds nhóm 1} }{ \text{Odds nhóm 2} } = \frac{ad}{bc} \]

c. Diễn giải OR:

  • OR = 1: không khác biệt
  • OR > 1: nhóm 1 có odds cao hơn
  • OR < 1: nhóm 1 có odds thấp hơn
  • OR = 2 → odds nhóm 1 gấp 2 lần nhóm 2

d. Khi nào OR ≈ RR?

→ Khi sự kiện là hiếm (xác suất nhỏ), OR và RR gần như tương đương.

e. Tại sao OR quan trọng?

  • Dùng được cả trong nghiên cứu hồi cứu (case-control).
  • Tính đối xứng: OR(A vs B) = 1 / OR(B vs A)
  • Ứng dụng rộng trong hồi quy logistic – phổ biến trong nghiên cứu kinh tế lượng.

7. Khoảng tin cậy cho Odds Ratio

Do phân phối OR lệch, nên KTC tính dựa trên log(OR):

\[ \text{KTC 95%}: \log(OR) \pm z \cdot SE(\log(OR)) \Rightarrow \text{Exponentiate để ra } [L, U] \]

Nếu KTC chứa 1 → không có khác biệt có ý nghĩa thống kê.


8. Ví dụ minh họa trong kinh tế

Câu hỏi:

Khách hàng nữ có khả năng sở hữu nhà cao hơn khách hàng nam không?

Giả sử bảng 2x2:

Có nhà Không Tổng
Nam 40 60 100
Nữ 66 54 120
  • Hiệu tỷ lệ: 66/120 – 40/100 = 0.55 – 0.40 = 0.15
  • RR = 0.55 / 0.40 = 1.375 → Nữ có xác suất sở hữu nhà cao hơn 37.5%
  • Odds Nam = 40/60 = 0.67 Odds Nữ = 66/54 ≈ 1.22 → OR = 1.22 / 0.67 ≈ 1.82 → Odds sở hữu nhà của Nữ gấp ~1.8 lần so với Nam.

9. Kết luận

Phân tích dữ liệu định tính không chỉ dừng lại ở đếm số liệu và vẽ biểu đồ. Các thước đo như hiệu tỷ lệ, RR, ORkiểm định Chi-bình phương cho phép người nghiên cứu rút ra kết luận có cơ sở xác suất. Odds Ratio, dù ban đầu có vẻ khó hiểu, nhưng lại là công cụ cực kỳ hữu ích, đặc biệt trong các mô hình kinh tế lượng hiện đại.


library(showtext)
font_add(family = "Arial", regular = "arial.ttf")  
showtext_auto()
library(tidyverse)
library(ggplot2)
library(epitools)
library(DescTools)
library(DT)
library(energy)
library(readr)
options(digits = 4)

THỰC HÀNH PHÂN TÍCH THỐNG KÊ CHO DỮ LIỆU ĐỊNH TÍNH DỰA TRÊN BỘ DỮ LIỆU :Consumer Behavior and Shopping Habits

1. TỔNG QUAN VỀ BỘ DỮ LIỆU

Tổng quan về bộ dữ liệu Consumer Behavior and Shopping Habits

Bộ dữ liệu Consumer Behavior and Shopping Habits trên Kaggle cung cấp thông tin chi tiết về hành vi mua sắm và sở thích của người tiêu dùng trong lĩnh vực thương mại điện tử. Dữ liệu này được mô tả là một tập hợp toàn diện, bao gồm nhiều khía cạnh về hành vi người tiêu dùng, giúp các nhà phân tích và doanh nghiệp hiểu rõ hơn về cách người tiêu dùng đưa ra quyết định mua sắm. Bộ dữ liệu này rất hữu ích để phân tích xu hướng mua sắm, tối ưu hóa chiến lược tiếp thị, cải thiện sản phẩm và nâng cao trải nghiệm khách hàng.

Nội dung chính của bộ dữ liệu

  • Mô tả: Bộ dữ liệu tập trung vào các hành vi mua sắm, bao gồm thông tin về nhân khẩu học (demographics), lịch sử mua hàng, sở thích sản phẩm, tần suất mua sắm, và thói quen mua sắm trực tuyến hoặc ngoại tuyến. Đây là dữ liệu tổng hợp (synthetic data) mô phỏng hành vi mua sắm thực tế, phù hợp để phân tích hành vi tiêu dùng và xu hướng bán lẻ.
  • Ứng dụng: Dữ liệu có thể được sử dụng để:
    • Phân tích xu hướng tiêu dùng.
    • Xây dựng các mô hình dự đoán hành vi mua sắm.
    • Tối ưu hóa chiến lược tiếp thị và danh mục sản phẩm.
    • Nghiên cứu sự khác biệt trong hành vi mua sắm theo giới tính, độ tuổi, hoặc các yếu tố nhân khẩu học khác.

Danh sách các biến và phân loại

#Đọc dữ liệu từ file CSV
data <- read.csv("C:/Users/Hoang Quyen/Downloads/shopping_behavior_updated.csv")
#Hiển thị cấu trúc dữ liệu
str(data)
## 'data.frame':    3900 obs. of  18 variables:
##  $ Customer.ID           : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Age                   : int  55 19 50 21 45 46 63 27 26 57 ...
##  $ Gender                : chr  "Male" "Male" "Male" "Male" ...
##  $ Item.Purchased        : chr  "Blouse" "Sweater" "Jeans" "Sandals" ...
##  $ Category              : chr  "Clothing" "Clothing" "Clothing" "Footwear" ...
##  $ Purchase.Amount..USD. : int  53 64 73 90 49 20 85 34 97 31 ...
##  $ Location              : chr  "Kentucky" "Maine" "Massachusetts" "Rhode Island" ...
##  $ Size                  : chr  "L" "L" "S" "M" ...
##  $ Color                 : chr  "Gray" "Maroon" "Maroon" "Maroon" ...
##  $ Season                : chr  "Winter" "Winter" "Spring" "Spring" ...
##  $ Review.Rating         : num  3.1 3.1 3.1 3.5 2.7 2.9 3.2 3.2 2.6 4.8 ...
##  $ Subscription.Status   : chr  "Yes" "Yes" "Yes" "Yes" ...
##  $ Shipping.Type         : chr  "Express" "Express" "Free Shipping" "Next Day Air" ...
##  $ Discount.Applied      : chr  "Yes" "Yes" "Yes" "Yes" ...
##  $ Promo.Code.Used       : chr  "Yes" "Yes" "Yes" "Yes" ...
##  $ Previous.Purchases    : int  14 2 23 49 31 14 49 19 8 4 ...
##  $ Payment.Method        : chr  "Venmo" "Cash" "Credit Card" "PayPal" ...
##  $ Frequency.of.Purchases: chr  "Fortnightly" "Fortnightly" "Weekly" "Weekly" ...
#Hiển thị 5 dòng đầu và cuối
head(data, 5)
##   Customer.ID Age Gender Item.Purchased Category Purchase.Amount..USD.
## 1           1  55   Male         Blouse Clothing                    53
## 2           2  19   Male        Sweater Clothing                    64
## 3           3  50   Male          Jeans Clothing                    73
## 4           4  21   Male        Sandals Footwear                    90
## 5           5  45   Male         Blouse Clothing                    49
##        Location Size     Color Season Review.Rating Subscription.Status
## 1      Kentucky    L      Gray Winter           3.1                 Yes
## 2         Maine    L    Maroon Winter           3.1                 Yes
## 3 Massachusetts    S    Maroon Spring           3.1                 Yes
## 4  Rhode Island    M    Maroon Spring           3.5                 Yes
## 5        Oregon    M Turquoise Spring           2.7                 Yes
##   Shipping.Type Discount.Applied Promo.Code.Used Previous.Purchases
## 1       Express              Yes             Yes                 14
## 2       Express              Yes             Yes                  2
## 3 Free Shipping              Yes             Yes                 23
## 4  Next Day Air              Yes             Yes                 49
## 5 Free Shipping              Yes             Yes                 31
##   Payment.Method Frequency.of.Purchases
## 1          Venmo            Fortnightly
## 2           Cash            Fortnightly
## 3    Credit Card                 Weekly
## 4         PayPal                 Weekly
## 5         PayPal               Annually
tail(data, 5)
##      Customer.ID Age Gender Item.Purchased    Category Purchase.Amount..USD.
## 3896        3896  40 Female         Hoodie    Clothing                    28
## 3897        3897  52 Female       Backpack Accessories                    49
## 3898        3898  46 Female           Belt Accessories                    33
## 3899        3899  44 Female          Shoes    Footwear                    77
## 3900        3900  52 Female        Handbag Accessories                    81
##        Location Size     Color Season Review.Rating Subscription.Status
## 3896   Virginia    L Turquoise Summer           4.2                  No
## 3897       Iowa    L     White Spring           4.5                  No
## 3898 New Jersey    L     Green Spring           2.9                  No
## 3899  Minnesota    S     Brown Summer           3.8                  No
## 3900 California    M     Beige Spring           3.1                  No
##       Shipping.Type Discount.Applied Promo.Code.Used Previous.Purchases
## 3896 2-Day Shipping               No              No                 32
## 3897   Store Pickup               No              No                 41
## 3898       Standard               No              No                 24
## 3899        Express               No              No                 24
## 3900   Store Pickup               No              No                 33
##      Payment.Method Frequency.of.Purchases
## 3896          Venmo                 Weekly
## 3897  Bank Transfer              Bi-Weekly
## 3898          Venmo              Quarterly
## 3899          Venmo                 Weekly
## 3900          Venmo              Quarterly
#Kiểm tra NA trong các cột định tính

cat_vars <- c("Gender", "Item.Purchased", "Category", "Location", "Size", "Color", 
              "Season", "Subscription.Status", "Shipping.Type", "Discount.Applied", 
              "Promo.Code.Used", "Payment.Method", "Frequency.of.Purchases")
sapply(data[cat_vars], function(x) sum(is.na(x)))
##                 Gender         Item.Purchased               Category 
##                      0                      0                      0 
##               Location                   Size                  Color 
##                      0                      0                      0 
##                 Season    Subscription.Status          Shipping.Type 
##                      0                      0                      0 
##       Discount.Applied        Promo.Code.Used         Payment.Method 
##                      0                      0                      0 
## Frequency.of.Purchases 
##                      0
#Chuyển đổi sang factor
data[cat_vars] <- lapply(data[cat_vars], as.factor)

#Kiểm tra lại cấu trúc
str(data[cat_vars])
## 'data.frame':    3900 obs. of  13 variables:
##  $ Gender                : Factor w/ 2 levels "Female","Male": 2 2 2 2 2 2 2 2 2 2 ...
##  $ Item.Purchased        : Factor w/ 25 levels "Backpack","Belt",..: 3 24 12 15 3 21 17 19 5 8 ...
##  $ Category              : Factor w/ 4 levels "Accessories",..: 2 2 2 3 2 3 2 2 4 1 ...
##  $ Location              : Factor w/ 50 levels "Alabama","Alaska",..: 17 19 21 39 37 50 26 18 48 25 ...
##  $ Size                  : Factor w/ 4 levels "L","M","S","XL": 1 1 3 2 2 2 2 1 1 2 ...
##  $ Color                 : Factor w/ 25 levels "Beige","Black",..: 8 13 13 13 22 24 8 6 20 17 ...
##  $ Season                : Factor w/ 4 levels "Fall","Spring",..: 4 4 2 2 2 3 1 4 3 2 ...
##  $ Subscription.Status   : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 2 2 2 ...
##  $ Shipping.Type         : Factor w/ 6 levels "2-Day Shipping",..: 2 2 3 4 3 5 3 3 2 1 ...
##  $ Discount.Applied      : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 2 2 2 ...
##  $ Promo.Code.Used       : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 2 2 2 ...
##  $ Payment.Method        : Factor w/ 6 levels "Bank Transfer",..: 6 2 3 5 5 6 2 3 6 2 ...
##  $ Frequency.of.Purchases: Factor w/ 7 levels "Annually","Bi-Weekly",..: 4 4 7 7 1 7 6 7 1 6 ...

Dựa trên mô tả từ nguồn và phân tích cấu trúc dữ liệu, các cột trong bộ dữ liệu bao gồm:

  1. Customer ID (Định lượng): Mã định danh duy nhất cho mỗi khách hàng.
  2. Age (Định lượng): Tuổi của khách hàng.
  3. Gender (Định tính): Giới tính của khách hàng (ví dụ: Male, Female).
  4. Item Purchased (Định tính): Sản phẩm được mua (ví dụ: áo, giày, v.v.).
  5. Category (Định tính): Danh mục sản phẩm (ví dụ: Clothing, Accessories, Footwear, Outerwear).
  6. Purchase Amount (USD) (Định lượng): Số tiền chi cho giao dịch (tính bằng USD).
  7. Location (Định tính): Địa điểm mua sắm (ví dụ: tên thành phố hoặc tiểu bang).
  8. Size (Định tính): Kích cỡ sản phẩm (ví dụ: S, M, L, XL).
  9. Color (Định tính): Màu sắc sản phẩm.
  10. Season (Định tính): Mùa mua sắm (ví dụ: Spring, Summer, Fall, Winter).
  11. Review Rating (Định lượng): Điểm đánh giá sản phẩm (thường là thang điểm từ 1-5).
  12. Subscription Status (Định tính): Trạng thái đăng ký (ví dụ: Yes, No).
  13. Shipping Type (Định tính): Loại hình vận chuyển (ví dụ: Free Shipping, Standard, Express).
  14. Discount Applied (Định tính): Có áp dụng giảm giá hay không (Yes/No).
  15. Promo Code Used (Định tính): Có sử dụng mã khuyến mãi hay không (Yes/No).
  16. Previous Purchases (Định lượng): Số lượng giao dịch trước đó của khách hàng.
  17. Payment Method (Định tính): Phương thức thanh toán (ví dụ: Credit Card, PayPal, Cash).
  18. Frequency of Purchases (Định tính): Tần suất mua sắm (ví dụ: Daily, Weekly, Monthly, Yearly).

Tổng kết phân loại biến: - Biến định tính (Categorical): 12 biến - Gender, Item Purchased, Category, Location, Size, Color, Season, Subscription Status, Shipping Type, Discount Applied, Promo Code Used, Payment Method, Frequency of Purchases. - Biến định lượng (Numerical): 4 biến - Customer ID, Age, Purchase Amount (USD), Review Rating, Previous Purchases.

Kết luận

Bộ dữ liệu Consumer Behavior and Shopping Habits chứa 3900 dòng18 cột, với 12 biến định tính4 biến định lượng. Nó cung cấp một cái nhìn toàn diện về hành vi tiêu dùng, từ nhân khẩu học đến thói quen mua sắm, rất hữu ích cho các nhà phân tích dữ liệu và doanh nghiệp muốn tối ưu hóa chiến lược kinh doanh.

THỐNG KÊ MÔ TẢ 1 BIẾN

GENDER

#Bảng tần số 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         Female           1248          Female              32
## 2           Male           2652            Male              68
#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()

Tỷ lệ người mua theo giới tính cho thấy Male chiếm ưu thế rõ rệt với 68%, trong khi Female chỉ chiếm 32%. Biểu đồ tròn minh họa sự mất cân đối này rất rõ ràng. Kết quả này khác biệt đáng kể so với xu hướng thực tế trong các bộ dữ liệu thương mại điện tử, vốn thường ghi nhận tỷ lệ Female ở mức khoảng 68%. Do đó, có khả năng tồn tại sai sót trong khâu nhập liệu hoặc thu thập dữ liệu, và cần tiến hành kiểm tra, đối chiếu lại dữ liệu gốc để đảm bảo tính chính xác.

ITEM.PURCHASED

# Bảng tần số và tỷ lệ
item_freq <- table(data$Item.Purchased)
item_prop <- prop.table(item_freq) * 100
item_table <- data.frame(Frequency = item_freq, Percentage = item_prop)
print(item_table)
##    Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1        Backpack            143        Backpack        3.666667
## 2            Belt            161            Belt        4.128205
## 3          Blouse            171          Blouse        4.384615
## 4           Boots            144           Boots        3.692308
## 5            Coat            161            Coat        4.128205
## 6           Dress            166           Dress        4.256410
## 7          Gloves            140          Gloves        3.589744
## 8         Handbag            153         Handbag        3.923077
## 9             Hat            154             Hat        3.948718
## 10         Hoodie            151          Hoodie        3.871795
## 11         Jacket            163          Jacket        4.179487
## 12          Jeans            124           Jeans        3.179487
## 13        Jewelry            171         Jewelry        4.384615
## 14          Pants            171           Pants        4.384615
## 15        Sandals            160         Sandals        4.102564
## 16          Scarf            157           Scarf        4.025641
## 17          Shirt            169           Shirt        4.333333
## 18          Shoes            150           Shoes        3.846154
## 19         Shorts            157          Shorts        4.025641
## 20          Skirt            158           Skirt        4.051282
## 21       Sneakers            145        Sneakers        3.717949
## 22          Socks            159           Socks        4.076923
## 23     Sunglasses            161      Sunglasses        4.128205
## 24        Sweater            164         Sweater        4.205128
## 25        T-shirt            147         T-shirt        3.769231
# Biểu đồ cột (do có nhiều giá trị)
ggplot(data, aes(x = Item.Purchased, fill = Item.Purchased)) +
  geom_bar() +
  labs(title = "Phân bố Sản phẩm được mua", x = "Item Purchased", y = "Tần số") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Dữ liệu ghi nhận có khoảng 25 loại sản phẩm khác nhau, trong đó Blouse chỉ chiếm 4.38% tổng số lượt mua (171/3900). Biểu đồ cột thể hiện sự phân bố khá đồng đều giữa các mặt hàng phổ biến như Blouse, Pants, và Jewelry. Không có sản phẩm nào vượt trội hoàn toàn về tần suất, điều này phản ánh sự đa dạng trong lựa chọn sản phẩm của khách hàng – một đặc điểm phổ biến trong hành vi mua sắm thời trang.

CATEGORY

# Bảng tần số và tỷ lệ
category_freq <- table(data$Category)
category_prop <- prop.table(category_freq) * 100
category_table <- data.frame(Frequency = category_freq, Percentage = category_prop)
print(category_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1    Accessories           1240     Accessories       31.794872
## 2       Clothing           1737        Clothing       44.538462
## 3       Footwear            599        Footwear       15.358974
## 4      Outerwear            324       Outerwear        8.307692
# Biểu đồ tròn
ggplot(data, aes(x = "", fill = Category)) +
  geom_bar(width = 1) +
  coord_polar("y") +
  labs(title = "Phân bố Danh mục Sản phẩm", fill = "Category") +
  theme_void()

Danh mục sản phẩm Clothing chiếm tỷ trọng lớn nhất với 44.54%, tiếp theo là Accessories, Footwear, và Outerwear. Biểu đồ tròn thể hiện rõ Clothing là danh mục nổi bật, cho thấy xu hướng tập trung mua sắm vào các sản phẩm thời trang cơ bản.

LOCATION

# Bảng tần số và tỷ lệ
location_freq <- table(data$Location)
location_prop <- prop.table(location_freq) * 100
location_table <- data.frame(Frequency = location_freq, Percentage = location_prop)
print(location_table)
##    Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1         Alabama             89         Alabama        2.282051
## 2          Alaska             72          Alaska        1.846154
## 3         Arizona             65         Arizona        1.666667
## 4        Arkansas             79        Arkansas        2.025641
## 5      California             95      California        2.435897
## 6        Colorado             75        Colorado        1.923077
## 7     Connecticut             78     Connecticut        2.000000
## 8        Delaware             86        Delaware        2.205128
## 9         Florida             68         Florida        1.743590
## 10        Georgia             79         Georgia        2.025641
## 11         Hawaii             65          Hawaii        1.666667
## 12          Idaho             93           Idaho        2.384615
## 13       Illinois             92        Illinois        2.358974
## 14        Indiana             79         Indiana        2.025641
## 15           Iowa             69            Iowa        1.769231
## 16         Kansas             63          Kansas        1.615385
## 17       Kentucky             79        Kentucky        2.025641
## 18      Louisiana             84       Louisiana        2.153846
## 19          Maine             77           Maine        1.974359
## 20       Maryland             86        Maryland        2.205128
## 21  Massachusetts             72   Massachusetts        1.846154
## 22       Michigan             73        Michigan        1.871795
## 23      Minnesota             88       Minnesota        2.256410
## 24    Mississippi             80     Mississippi        2.051282
## 25       Missouri             81        Missouri        2.076923
## 26        Montana             96         Montana        2.461538
## 27       Nebraska             87        Nebraska        2.230769
## 28         Nevada             87          Nevada        2.230769
## 29  New Hampshire             71   New Hampshire        1.820513
## 30     New Jersey             67      New Jersey        1.717949
## 31     New Mexico             81      New Mexico        2.076923
## 32       New York             87        New York        2.230769
## 33 North Carolina             78  North Carolina        2.000000
## 34   North Dakota             83    North Dakota        2.128205
## 35           Ohio             77            Ohio        1.974359
## 36       Oklahoma             75        Oklahoma        1.923077
## 37         Oregon             74          Oregon        1.897436
## 38   Pennsylvania             74    Pennsylvania        1.897436
## 39   Rhode Island             63    Rhode Island        1.615385
## 40 South Carolina             76  South Carolina        1.948718
## 41   South Dakota             70    South Dakota        1.794872
## 42      Tennessee             77       Tennessee        1.974359
## 43          Texas             77           Texas        1.974359
## 44           Utah             71            Utah        1.820513
## 45        Vermont             85         Vermont        2.179487
## 46       Virginia             77        Virginia        1.974359
## 47     Washington             73      Washington        1.871795
## 48  West Virginia             81   West Virginia        2.076923
## 49      Wisconsin             75       Wisconsin        1.923077
## 50        Wyoming             71         Wyoming        1.820513
# Biểu đồ cột 
ggplot(data, aes(x = Location, fill = Location)) +
  geom_bar() +
  labs(title = "Phân bố Địa điểm", x = "Location", y = "Tần số") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        legend.position = "none")

Phân tích địa lý cho thấy New York chỉ chiếm 2.23%, trong khi các tiểu bang như California và Texas cũng có tần suất xuất hiện cao. Biểu đồ cột phản ánh sự phân bổ khá đều giữa ~50 bang, không có bang nào chiếm ưu thế áp đảo. Điều này cho thấy dữ liệu được thu thập từ nhiều khu vực khác nhau, phản ánh tính đại diện cao.

SIZE

# Bảng tần số và tỷ lệ
size_freq <- table(data$Size)
size_prop <- prop.table(size_freq) * 100
size_table <- data.frame(Frequency = size_freq, Percentage = size_prop)
print(size_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1              L           1053               L              27
## 2              M           1755               M              45
## 3              S            663               S              17
## 4             XL            429              XL              11
# Biểu đồ tròn
ggplot(data, aes(x = "", fill = Size)) +
  geom_bar(width = 1) +
  coord_polar("y") +
  labs(title = "Phân bố Kích cỡ", fill = "Size") +
  theme_void()

Kích cỡ M (Medium) chiếm tỷ lệ cao nhất với 45%, vượt trội so với các size còn lại như L, S, và XL. Biểu đồ tròn khẳng định xu hướng chọn kích cỡ trung bình – đây là kết quả phù hợp với chuẩn cơ thể phổ biến trong ngành thời trang.

SEASON

# Bảng tần số và tỷ lệ
season_freq <- table(data$Season)
season_prop <- prop.table(season_freq) * 100
season_table <- data.frame(Frequency = season_freq, Percentage = season_prop)
print(season_table)
##   Frequency.Var1 Frequency.Freq Percentage.Var1 Percentage.Freq
## 1           Fall            975            Fall        25.00000
## 2         Spring            999          Spring        25.61538
## 3         Summer            955          Summer        24.48718
## 4         Winter            971          Winter        24.89744
# Biểu đồ tròn
ggplot(data, aes(x = "", fill = Season)) +
  geom_bar(width = 1) +
  coord_polar("y") +
  labs(title = "Phân bố Mùa mua sắm", fill = "Season") +
  theme_void()

Phân bố theo mùa khá đồng đều với mùa Xuân (Spring) chiếm 25.62%. Các mùa còn lại (Summer, Fall, Winter) có tỷ lệ xấp xỉ nhau (~25%). Biểu đồ tròn xác nhận không có sự thiên lệch rõ rệt theo mùa, điều này phản ánh hành vi mua sắm không phụ thuộc vào yếu tố thời vụ trong tập dữ liệu này.

ƯỚC LƯỢNG KHOẢNG VÀ KIỂM ĐỊNH GIẢ THUYẾT CHO TỶ LỆ

GENDER

# Ước lượng khoảng tin cậy 95% cho tỷ lệ Female
n <- nrow(data)
female_count <- sum(data$Gender == "Female")
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ữ: 30.54 33.46 %
  • Giả thuyết:

    • \(H_0: p = 0.5\) (Tỷ lệ nữ là 50%)
    • \(H_1: p \ne 0.5\)
# 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 = 504.72, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.3054166 0.3349408
## sample estimates:
##    p 
## 0.32
  • Kết quả:

    • Tỷ lệ nữ: 32.05%
    • Khoảng tin cậy 95%: [30.54%; 33.46%]
    • \(p\)-value của kiểm định: < 2.2e-16
  • Nhận xét:\(p\)-value rất nhỏ (< 0.05), bác bỏ \(H_0\). Tỷ lệ nữ trong mẫu khác biệt có ý nghĩa thống kê so với 50%, cho thấy dữ liệu có thiên lệch giới tính nghiêng về nam.

ITEM.PURCHASED

# Ước lượng khoảng tin cậy 95% cho tỷ lệ Blouse
item_count <- sum(data$Item.Purchased == "Blouse")
prop_item <- item_count / n
se_item <- sqrt(prop_item * (1 - prop_item) / n)
ci_item <- prop_item + c(-1, 1) * 1.96 * se_item
cat("Khoảng tin cậy 95% cho tỷ lệ Blouse:", round(ci_item * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Blouse: 3.74 5.03 %
  • Giả thuyết:

    • \(H_0: p = 0.05\)
    • \(H_1: p \ne 0.05\)
# Kiểm định giả thuyết (H0: Tỷ lệ Blouse = 0.05)
prop.test(item_count, n, p = 0.05, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  item_count out of n, null probability 0.05
## X-squared = 2.9811, df = 1, p-value = 0.08424
## alternative hypothesis: true p is not equal to 0.05
## 95 percent confidence interval:
##  0.03773730 0.05087059
## sample estimates:
##          p 
## 0.04384615
  • Kết quả:

    • Tỷ lệ Blouse: 4.38%
    • Khoảng tin cậy 95%: [3.74%; 5.03%]
    • \(p\)-value của kiểm định: ≈ 0.08
  • Nhận xét:\(p\)-value > 0.05, không bác bỏ \(H_0\). Tỷ lệ khách mua Blouse không khác biệt đáng kể so với giả định 5%, tức là giả định ban đầu hợp lý.

CATEGORY

# Ước lượng khoảng tin cậy 95% cho tỷ lệ Clothing
category_count <- sum(data$Category == "Clothing")
prop_category <- category_count / n
se_category <- sqrt(prop_category * (1 - prop_category) / n)
ci_category <- prop_category + c(-1, 1) * 1.96 * se_category
cat("Khoảng tin cậy 95% cho tỷ lệ Clothing:", round(ci_category * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Clothing: 42.98 46.1 %
  • Giả thuyết:

    • \(H_0: p = 0.4\)
    • \(H_1: p \ne 0.4\)
# Kiểm định giả thuyết (H0: Tỷ lệ Clothing = 0.4)
prop.test(category_count, n, p = 0.4, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  category_count out of n, null probability 0.4
## X-squared = 33.282, df = 1, p-value = 7.97e-09
## alternative hypothesis: true p is not equal to 0.4
## 95 percent confidence interval:
##  0.4297199 0.4611577
## sample estimates:
##         p 
## 0.4453846
  • Kết quả:

    • Tỷ lệ Clothing: 44.54%
    • Khoảng tin cậy 95%: [42.98%; 46.10%]
    • \(p\)-value của kiểm định: < 0.00000001
  • Nhận xét:\(p\)-value < 0.05, bác bỏ \(H_0\). Tỷ lệ sản phẩm Clothing cao hơn 40% một cách có ý nghĩa thống kê, chứng tỏ đây là loại hàng hóa chiếm ưu thế trong dữ liệu.

LOCATION

# Ước lượng khoảng tin cậy 95% cho tỷ lệ New York
location_count <- sum(data$Location == "New York")
prop_location <- location_count / n
se_location <- sqrt(prop_location * (1 - prop_location) / n)
ci_location <- prop_location + c(-1, 1) * 1.96 * se_location
cat("Khoảng tin cậy 95% cho tỷ tỉ lệ New York:", round(ci_location * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ tỉ lệ New York: 1.77 2.69 %
  • Giả thuyết:

    • \(H_0: p = 0.02\)
    • \(H_1: p \ne 0.02\)
# Kiểm định giả thuyết (H0: Tỷ lệ New York = 0.02)
prop.test(location_count, n, p = 0.02, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  location_count out of n, null probability 0.02
## X-squared = 0.94519, df = 1, p-value = 0.3309
## alternative hypothesis: true p is not equal to 0.02
## 95 percent confidence interval:
##  0.01800617 0.02757519
## sample estimates:
##          p 
## 0.02230769
  • Kết quả:

    • Tỷ lệ khách ở New York: 2.23%
    • Khoảng tin cậy 95%: [1.77%; 2.69%]
    • \(p\)-value của kiểm định: ≈ 0.30
  • Nhận xét:\(p\)-value > 0.05, không bác bỏ \(H_0\). Tỷ lệ khách hàng từ New York phù hợp với giả định 2%, không có sự khác biệt đáng kể.

SIZE

# Ước lượng khoảng tin cậy 95% cho tỷ lệ Size M
size_count <- sum(data$Size == "M")
prop_size <- size_count / n
se_size <- sqrt(prop_size * (1 - prop_size) / n)
ci_size <- prop_size + c(-1, 1) * 1.96 * se_size
cat("Khoảng tin cậy 95% cho tỷ lệ Size M:", round(ci_size * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Size M: 43.44 46.56 %
  • Giả thuyết:

    • \(H_0: p = 0.4\)
    • \(H_1: p \ne 0.4\)
# Kiểm định giả thuyết (H0: Tỷ lệ Size M = 0.4)
prop.test(size_count, n, p = 0.4, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  size_count out of n, null probability 0.4
## X-squared = 40.417, df = 1, p-value = 2.052e-10
## alternative hypothesis: true p is not equal to 0.4
## 95 percent confidence interval:
##  0.4343155 0.4657837
## sample estimates:
##    p 
## 0.45
  • Kết quả:

    • Tỷ lệ Size M: 45%
    • Khoảng tin cậy 95%: [43.44%; 46.56%]
    • \(p\)-value của kiểm định: < 0.000000002
  • Nhận xét:\(p\)-value rất nhỏ, bác bỏ \(H_0\). Tỷ lệ khách hàng chọn Size M cao hơn 40% một cách đáng kể, xác nhận đây là size phổ biến nhất.

SEASON

# Ước lượng khoảng tin cậy 95% cho tỷ lệ Spring
season_count <- sum(data$Season == "Spring")
prop_season <- season_count / n
se_season <- sqrt(prop_season * (1 - prop_season) / n)
ci_season <- prop_season + c(-1, 1) * 1.96 * se_season
cat("Khoảng tin cậy 95% cho tỷ lệ Spring:", round(ci_season * 100, 2), "%\n")
## Khoảng tin cậy 95% cho tỷ lệ Spring: 24.25 26.99 %
  • Giả thuyết:

    • \(H_0: p = 0.25\)
    • \(H_1: p \ne 0.25\)
# Kiểm định giả thuyết (H0: Tỷ lệ Spring = 0.25)
prop.test(season_count, n, p = 0.25, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  season_count out of n, null probability 0.25
## X-squared = 0.75521, df = 1, p-value = 0.3848
## alternative hypothesis: true p is not equal to 0.25
## 95 percent confidence interval:
##  0.2425730 0.2702191
## sample estimates:
##         p 
## 0.2561538
  • Kết quả:

    • Tỷ lệ mùa Xuân: 25.62%
    • Khoảng tin cậy 95%: [24.25%; 26.99%]
    • \(p\)-value của kiểm định: ≈ 0.40
  • Nhận xét:\(p\)-value > 0.05, không bác bỏ \(H_0\). Tỷ lệ đơn hàng trong mùa Xuân không khác biệt đáng kể so với 25%, cho thấy phân bố đơn hàng đồng đều theo mùa.

Phân tích cặp biến: Season và Item.Purchased

Biến độc lập: Season

Biến phụ thuộc: Item.Purchased (chọn “Blouse” làm “thành công”)

# Tạo cột nhị phân cho Item.Purchased (Blouse = Y, không phải Blouse = N)
data$Blouse <- ifelse(data$Item.Purchased == "Blouse", "Y", "N")
# Tạo bảng tần số
tmp_season <- table(data$Season, data$Blouse)
addmargins(tmp_season)
##         
##             N    Y  Sum
##   Fall    933   42  975
##   Spring  953   46  999
##   Summer  912   43  955
##   Winter  931   40  971
##   Sum    3729  171 3900
  • Tỷ lệ Blouse (dựa trên phân tích trước đó):
    • Fall: 42/975 = 4.31%.
    • Spring: 46/999 = 4.60%.
    • Summer: 43/955 = 4.50%.
    • Winter: 40/971 = 4.12%.
  • Nhận xét: Phân bố các sản phẩm, bao gồm Blouse, tương đối đồng đều giữa các mùa, với tỷ lệ ~4-5% cho Blouse.
# Rủi ro tương đối (Relative Risk)
# Tính RR với Y là Blouse, so sánh các mùa với Spring
library(epitools)
library(DescTools)
## Warning: package 'DescTools' was built under R version 4.4.3
cat("\nRủi ro tương đối (Season, Blouse = Y):\n")
## 
## Rủi ro tương đối (Season, Blouse = Y):
riskratio(tmp_season, rev = 'c')  # Đổi cột để Y là Blouse
## $data
##         
##            Y    N Total
##   Fall    42  933   975
##   Spring  46  953   999
##   Summer  43  912   955
##   Winter  40  931   971
##   Total  171 3729  3900
## 
## $measure
##         risk ratio with 95% C.I.
##           estimate     lower    upper
##   Fall   1.0000000        NA       NA
##   Spring 0.9968972 0.9780844 1.016072
##   Summer 0.9979630 0.9790263 1.017266
##   Winter 1.0019670 0.9834663 1.020816
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact chi.square
##   Fall           NA           NA         NA
##   Spring  0.7511795    0.8274736  0.7492895
##   Summer  0.8355881    0.9117484  0.8347120
##   Winter  0.8374976    0.9102619  0.8362825
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
epitab(tmp_season, method = 'riskratio', rev = 'c')
## $tab
##         
##           Y         p0   N        p1 riskratio     lower    upper   p.value
##   Fall   42 0.04307692 933 0.9569231 1.0000000        NA       NA        NA
##   Spring 46 0.04604605 953 0.9539540 0.9968972 0.9780844 1.016072 0.8274736
##   Summer 43 0.04502618 912 0.9549738 0.9979630 0.9790263 1.017266 0.9117484
##   Winter 40 0.04119464 931 0.9588054 1.0019670 0.9834663 1.020816 0.9102619
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"
  • Kết quả (so với Fall):
    • Spring: RR = 0.9969 [0.9781, 1.016], \(p\)-value = 0.8275.
    • Summer: RR = 0.9980 [0.9790, 1.017], \(p\)-value = 0.9117.
    • Winter: RR = 1.0020 [0.9835, 1.021], \(p\)-value = 0.9103.
  • Diễn giải:
    • RR gần 1 cho tất cả các mùa, với khoảng tin cậy 95% bao gồm 1, cho thấy không có sự khác biệt đáng kể về xác suất mua Blouse giữa Spring, Summer, Winter so với Fall.
    • \(p\)-value cao (>0.8) từ kiểm định Fisher (trong epitab()) xác nhận không có ý nghĩa thống kê, phù hợp với tỷ lệ đồng đều (~4-5%).
  • Nhận xét:
    • Kết quả RR nhất quán với phân tích trước đó (dùng Fall làm tham chiếu), cho thấy hành vi mua Blouse không phụ thuộc đáng kể vào mùa.
    • Việc sử dụng Spring trong chú thích nhưng Fall trong kết quả gây nhầm lẫn, cần sửa để đảm bảo tính rõ ràng.
# Tỷ lệ chênh (Odds Ratio)
# Tính OR với Y là Blouse, so sánh các mùa với Spring
cat("\nTỷ lệ chênh (Season, Blouse = Y):\n")
## 
## Tỷ lệ chênh (Season, Blouse = Y):
oddsratio(tmp_season, rev = 'c')
## $data
##         
##            Y    N Total
##   Fall    42  933   975
##   Spring  46  953   999
##   Summer  43  912   955
##   Winter  40  931   971
##   Total  171 3729  3900
## 
## $measure
##         odds ratio with 95% C.I.
##           estimate     lower    upper
##   Fall   1.0000000        NA       NA
##   Spring 0.9329309 0.6057622 1.433182
##   Summer 0.9548638 0.6161842 1.478726
##   Winter 1.0475269 0.6715138 1.636456
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact chi.square
##   Fall           NA           NA         NA
##   Spring  0.7511795    0.8274736  0.7492895
##   Summer  0.8355881    0.9117484  0.8347120
##   Winter  0.8374976    0.9102619  0.8362825
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
epitab(tmp_season, method = 'oddsratio', rev = 'c')
## $tab
##         
##           Y        p0   N        p1 oddsratio     lower    upper   p.value
##   Fall   42 0.2456140 933 0.2502011 1.0000000        NA       NA        NA
##   Spring 46 0.2690058 953 0.2555645 0.9326157 0.6079339 1.430702 0.8274736
##   Summer 43 0.2514620 912 0.2445696 0.9547596 0.6180504 1.474906 0.9117484
##   Winter 40 0.2339181 931 0.2496648 1.0477492 0.6731517 1.630804 0.9102619
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"
  • Kết quả (so với Fall):
    • Spring: OR = 0.9329 [0.6058, 1.433], \(p\)-value = 0.8275.
    • Summer: OR = 0.9549 [0.6162, 1.479], \(p\)-value = 0.9117.
    • Winter: OR = 1.0475 [0.6715, 1.636], \(p\)-value = 0.9103.
  • Diễn giải:
    • OR cũng gần 1, với khoảng tin cậy 95% bao gồm 1, cho thấy không có sự khác biệt đáng kể về tỷ lệ cược mua Blouse giữa các mùa so với Fall.
    • \(p\)-value cao (>0.8) từ kiểm định Fisher nhất quán với RR, xác nhận không có mối quan hệ đáng kể.
  • Nhận xét:
    • OR hỗ trợ kết luận từ RR, cho thấy không có sự khác biệt thống kê giữa các mùa trong việc mua Blouse.
    • Khoảng tin cậy của OR rộng hơn RR (do tỷ lệ cược nhạy hơn với biến động tỷ lệ nhỏ), nhưng vẫn bao gồm 1, phù hợp với dữ liệu.
## Phân tích cặp biến: Gender và Size Biến độc lập: Gender
Biến phụ thuộc: Size (chọn “M” làm “thành công”)
# Tạo cột nhị phân cho Size (M = Y, không phải M = N)
data$Size_M <- ifelse(data$Size == "M", "Y", "N")
# Tạo bảng tần số
tmp_gender <- table(data$Gender, data$Size_M)
addmargins(tmp_gender)
##         
##             N    Y  Sum
##   Female  658  590 1248
##   Male   1487 1165 2652
##   Sum    2145 1755 3900
  • Tỷ lệ chọn Size M:
    • Female: 590/1248 = 47.28%.
    • Male: 1165/2652 = 43.93%.
# Rủi ro tương đối (Relative Risk)
# Tính RR với Y là Size M, so sánh Male với Female
cat("\nRủi ro tương đối (Gender, Size M = Y):\n")
## 
## Rủi ro tương đối (Gender, Size M = Y):
riskratio(tmp_gender, rev = 'c')  # Đổi cột để Y là Size M
## $data
##         
##             Y    N Total
##   Female  590  658  1248
##   Male   1165 1487  2652
##   Total  1755 2145  3900
## 
## $measure
##         risk ratio with 95% C.I.
##          estimate     lower    upper
##   Female 1.000000        NA       NA
##   Male   1.063472 0.9991309 1.131957
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact chi.square
##   Female         NA           NA         NA
##   Male   0.05029278   0.05334186 0.05004174
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
epitab(tmp_gender, method = 'riskratio', rev = 'c')
## $tab
##         
##             Y        p0    N        p1 riskratio     lower    upper    p.value
##   Female  590 0.4727564  658 0.5272436  1.000000        NA       NA         NA
##   Male   1165 0.4392911 1487 0.5607089  1.063472 0.9991309 1.131957 0.05334186
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"
  • RR (Male so với Female): 1.063 [0.9991, 1.132], \(p\)-value = 0.05334.
  • Diễn giải:
    • RR = 1.063 cho thấy Male có xác suất chọn Size M cao hơn Female khoảng 6.3%, nhưng khoảng tin cậy 95% (0.9991, 1.132) bao gồm giá trị 1, và \(p\)-value = 0.05334 (>0.05), nên không đủ bằng chứng để kết luận sự khác biệt là có ý nghĩa thống kê ở mức \(\alpha = 0.05\).
    • Kết quả từ epitab(method = 'riskratio') nhất quán với riskratio(), sử dụng kiểm định Fisher để tính \(p\)-value.
# Tỷ lệ chênh (Odds Ratio)
# Tính OR với Y là Size M, so sánh Male với Female
cat("\nTỷ lệ chênh (Gender, Size M = Y):\n")
## 
## Tỷ lệ chênh (Gender, Size M = Y):
oddsratio(tmp_gender, rev = 'c')
## $data
##         
##             Y    N Total
##   Female  590  658  1248
##   Male   1165 1487  2652
##   Total  1755 2145  3900
## 
## $measure
##         odds ratio with 95% C.I.
##          estimate     lower    upper
##   Female 1.000000        NA       NA
##   Male   1.144455 0.9998011 1.309921
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact chi.square
##   Female         NA           NA         NA
##   Male   0.05029278   0.05334186 0.05004174
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
epitab(tmp_gender, method = 'oddsratio', rev = 'c')
## $tab
##         
##             Y        p0    N        p1 oddsratio     lower    upper    p.value
##   Female  590 0.3361823  658 0.3067599  1.000000        NA       NA         NA
##   Male   1165 0.6638177 1487 0.6932401  1.144488 0.9999395 1.309932 0.05334186
## 
## $measure
## [1] "wald"
## 
## $conf.level
## [1] 0.95
## 
## $pvalue
## [1] "fisher.exact"
  • OR (Male so với Female): 1.144 [0.9999, 1.31], \(p\)-value = 0.05334.
  • Diễn giải:
    • OR = 1.144 cho thấy tỷ lệ cược chọn Size M của Male cao hơn Female khoảng 14.4%, nhưng khoảng tin cậy 95% (0.9999, 1.31) sát với 1, và \(p\)-value = 0.05334 (>0.05), nên sự khác biệt không đạt ý nghĩa thống kê.
    • Kết quả từ epitab(method = 'oddsratio') nhất quán với oddsratio(), sử dụng phương pháp “median-unbiased estimate” và kiểm định Fisher.

Kiểm định Chi-bình phương: Season và Item.Purchased

# Tạo bảng tần số chéo
table_season_item <- table(data$Season, data$Item.Purchased)
cat("\nBảng tần số chéo: Season và Item.Purchased\n")
## 
## Bảng tần số chéo: Season và Item.Purchased
print(addmargins(table_season_item))
##         
##          Backpack Belt Blouse Boots Coat Dress Gloves Handbag  Hat Hoodie
##   Fall         34   41     42    35   34    36     37      48   50     36
##   Spring       39   41     46    40   46    43     42      36   27     36
##   Summer       45   39     43    38   42    47     29      35   37     31
##   Winter       25   40     40    31   39    40     32      34   40     48
##   Sum         143  161    171   144  161   166    140     153  154    151
##         
##          Jacket Jeans Jewelry Pants Sandals Scarf Shirt Shoes Shorts Skirt
##   Fall       54    32      35    38      44    40    39    26     35    46
##   Spring     35    32      42    32      44    41    42    40     47    46
##   Summer     33    31      47    50      40    43    38    46     40    28
##   Winter     41    29      47    51      32    33    50    38     35    38
##   Sum       163   124     171   171     160   157   169   150    157   158
##         
##          Sneakers Socks Sunglasses Sweater T-shirt  Sum
##   Fall         31    42         39      42      39  975
##   Spring       39    40         33      52      38  999
##   Summer       36    42         37      28      30  955
##   Winter       39    35         52      42      40  971
##   Sum         145   159        161     164     147 3900
# Kiểm định Chi-bình phương
chi_season_item <- chisq.test(table_season_item)
cat("\nKiểm định Chi-bình phương: Season và Item.Purchased\n")
## 
## Kiểm định Chi-bình phương: Season và Item.Purchased
print(chi_season_item)
## 
##  Pearson's Chi-squared test
## 
## data:  table_season_item
## X-squared = 78.192, df = 72, p-value = 0.2887
- **Kết quả**:
 - \(\chi^2 = 78\), bậc tự do (\( df \)) = 72, \( p \)-value = 0.3.
  • Diễn giải:
    • \(p\)-value = 0.3 (>0.05), không bác bỏ giả thuyết \(H_0\), cho thấy không có mối quan hệ đáng kể giữa SeasonItem.Purchased.
    • Kết quả này nhất quán với phân tích RR và OR trước đó (cho biến nhị phân Blouse), với RR và OR gần 1 và \(p\)-value cao (>0.8), cho thấy không có sự khác biệt đáng kể về xác suất mua Blouse giữa các mùa.
LS0tDQp0aXRsZTogIk5oaeG7h20gduG7pSB0deG6p24gNCINCmF1dGhvcjogIkhvw6BuZyBRdXnDqm4iDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclSDolTTolUywgJWQgLSAlbSAtICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlICANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDUNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IHRydWUNCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCi0tLQ0KDQotLS0NCg0KIyAqKlBIw4JOIFTDjUNIIFRI4buQTkcgS8OKIENITyBE4buuIExJ4buGVSDEkOG7ik5IIFTDjU5IOiBDxqAgU+G7niBMw50gVEhVWeG6vlQqKg0KDQotLS0NCg0KIyMgKioxLiBHaeG7m2kgdGhp4buHdSBjaHVuZyoqDQoNClRyb25nIG5naGnDqm4gY+G7qXUga2luaCB04bq/IHbDoCBraW5oIGRvYW5oLCBuaGnhu4F1IGJp4bq/biBxdWFuIHRy4buNbmcgbWFuZyB0w61uaCBjaOG6pXQgxJHhu4tuaCB0w61uaCwgdsOtIGThu6UgbmjGsCBnaeG7m2kgdMOtbmgsIGjDoG5oIHZpIHRpw6p1IGTDuW5nIChtdWEva2jDtG5nIG11YSksIHPhu58gaOG7r3UgdMOgaSBz4bqjbiAoY8OzL2tow7RuZykuIFBow6JuIHTDrWNoIHRo4buRbmcga8OqIMSR4buRaSB24bubaSBuaOG7r25nIGJp4bq/biBuw6B5IGdpw7pwIGhp4buDdSDEkcaw4bujYyBj4bqldSB0csO6YyBkw6JuIHPhu5EsIMSR4bq3YyDEkWnhu4NtIGtow6FjaCBow6BuZyB2w6AgbeG7kWkgcXVhbiBo4buHIGdp4buvYSBjw6FjIG5ow7NtLg0KDQpDw7MgaGFpIGPhuqVwIMSR4buZIHBow6JuIHTDrWNoIGPGoSBi4bqjbjoNCg0KKiAqKlBow6JuIHTDrWNoIG3hu5l0IGJp4bq/biDEkeG7i25oIHTDrW5oKio6IG3DtCB04bqjIHBow6JuIHBo4buRaSBj4bunYSBiaeG6v24uDQoqICoqUGjDom4gdMOtY2ggaGFpIGJp4bq/biDEkeG7i25oIHTDrW5oKio6IMSRw6FuaCBnacOhIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGhhaSBiaeG6v24sIGtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IHbDoCDGsOG7m2MgbMaw4bujbmcgbeG7qWMgxJHhu5kgbGnDqm4gcXVhbi4NCg0KLS0tDQoNCiMjICoqMi4gUGjDom4gdMOtY2ggbcO0IHThuqMgbeG7mXQgYmnhur9uIMSR4buLbmggdMOtbmgqKg0KDQojIyMgMi4xLiBU4bqnbiBzdeG6pXQgdsOgIHThuqduIHN14bqldCB0xrDGoW5nIMSR4buRaQ0KDQpHaeG6oyBz4butIHRhIHF1YW4gc8OhdCBiaeG6v24gxJHhu4tuaCB0w61uaCBuaMawIOKAnEdp4bubaSB0w61uaOKAnSB24bubaSBoYWkgZ2nDoSB0cuG7izogTmFtLCBO4buvLiBDw7MgdGjhu4MgbcO0IHThuqMgYmnhur9uIG7DoHkgYuG6sW5nOg0KDQoqICoqVOG6p24gc3XhuqV0IHR1eeG7h3QgxJHhu5FpIChmcmVxdWVuY3kpKio6IHPhu5EgbOG6p24gbeG7l2kgZ2nDoSB0cuG7iyB4deG6pXQgaGnhu4duLg0KKiAqKlThuqduIHN14bqldCB0xrDGoW5nIMSR4buRaSoqOiB04bqnbiBzdeG6pXQgY2hpYSBjaG8gdOG7lW5nIHF1YW4gc8OhdCAodMOtbmggdGhlbyAlKS4NCg0KIyMjIDIuMi4gVHLhu7FjIHF1YW4gaMOzYQ0KDQpDw6FjIGJp4buDdSDEkeG7kyB0aMaw4budbmcgZMO5bmc6IGJhciBjaGFydCAoY+G7mXQpLCBwaWUgY2hhcnQgKHRyw7JuKSDEkeG7gyB0aOG7gyBoaeG7h24gdOG7tyBs4buHIHThu6tuZyBuaMOzbS4NCg0KLS0tDQoNCiMjICoqMy4gxq/hu5tjIGzGsOG7o25nIHbDoCBraeG7g20gxJHhu4tuaCBnaeG6oyB0aHV54bq/dCBjaG8gdOG7tyBs4buHICgxIGJp4bq/bikqKg0KDQpHaeG6oyBz4butIHRhIMSRYW5nIHF1YW4gdMOibSDEkeG6v24gbeG7mXQgYmnhur9uIG5o4buLIHBow6JuICh2w60gZOG7pTogc+G7nyBo4buvdSBuaMOgIOKAkyBDw7MvS2jDtG5nKS4NCg0KIyMjIDMuMS4gxq/hu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSAoS1RDKSBjaG8gdOG7tyBs4buHDQoNCk7hur91IHRyb25nIG3huqt1IGPDsyAkXGhhdHtwfSQgbMOgIHThu7cgbOG7hyBuZ8aw4budaSDigJxDw7MgbmjDoOKAnSwgdGEgxrDhu5tjIGzGsOG7o25nIEtUQyA5NSUgY2hvIHThu7cgbOG7hyB0aOG6rXQgJHAkIGLhurFuZzoNCg0KJCQNClxoYXR7cH0gXHBtIHpfezAuMDI1fSBcY2RvdCBcc3FydHsgXGZyYWN7IFxoYXR7cH0oMSAtIFxoYXR7cH0pIH17bn0gfQ0KJCQNCg0KVHJvbmcgxJHDszoNCg0KKiAkXGhhdHtwfSQ6IHThu7cgbOG7hyBt4bqrdQ0KKiAkbiQ6IGvDrWNoIHRoxrDhu5tjIG3huqt1DQoqICR6X3swLjAyNX0gXGFwcHJveCAxLjk2JDogZ2nDoSB0cuG7iyBwaMOibiBwaOG7kWkgY2h14bqpbg0KDQojIyMgMy4yLiBLaeG7g20gxJHhu4tuaCBnaeG6oyB0aHV54bq/dCB24buBIHThu7cgbOG7hw0KDQpHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaDoNCg0KKiAkSF8wOiBwID0gcF8wJA0KKiAkSF8xOiBwIFxuZSBwXzAkDQoNCkTDuW5nIGtp4buDbSDEkeG7i25oIHo6DQoNCiQkDQp6ID0gXGZyYWN7IFxoYXR7cH0gLSBwXzAgfXsgXHNxcnR7IFxmcmFje3BfMCgxIC0gcF8wKX17bn0gfSB9DQokJA0KDQotLS0NCg0KIyMgKio0LiBQaMOibiB0w61jaCBoYWkgYmnhur9uIMSR4buLbmggdMOtbmgqKg0KDQojIyMgNC4xLiBC4bqjbmcgY2jDqW8gKGNvbnRpbmdlbmN5IHRhYmxlKQ0KDQpIYWkgYmnhur9uIMSR4buLbmggdMOtbmggKHZkOiBHaeG7m2kgdMOtbmggJiBT4bufIGjhu691IG5ow6ApIMSRxrDhu6NjIHRyw6xuaCBiw6B5IGTGsOG7m2kgZOG6oW5nIGLhuqNuZyBjaMOpbyAyeDI6DQoNCnwgICAgICB8IEPDsyBuaMOgIHwgS2jDtG5nIGPDsyB8IFThu5VuZyAgfA0KfCAtLS0tIHwgLS0tLS0tIHwgLS0tLS0tLS0gfCAtLS0tLSB8DQp8IE5hbSAgfCBhICAgICAgfCBiICAgICAgICB8IGEgKyBiIHwNCnwgTuG7ryAgIHwgYyAgICAgIHwgZCAgICAgICAgfCBjICsgZCB8DQp8IFThu5VuZyB8IGEgKyBjICB8IGIgKyBkICAgIHwgbiAgICAgfA0KDQojIyMgNC4yLiBLaeG7g20gxJHhu4tuaCDEkeG7mWMgbOG6rXA6IENoaS1iw6xuaCBwaMawxqFuZw0KDQpN4bulYyB0acOqdToga2nhu4NtIHRyYSB4ZW0gaGFpIGJp4bq/biBjw7MgcXVhbiBo4buHIGhheSDEkeG7mWMgbOG6rXAuDQoNCiogKipHaeG6oyB0aHV54bq/dDoqKg0KDQogICogJEhfMCQ6IGhhaSBiaeG6v24gxJHhu5ljIGzhuq1wDQogICogJEhfMSQ6IGhhaSBiaeG6v24gY8OzIGxpw6puIGjhu4cNCg0KKiAqKlRo4buRbmcga8OqIGtp4buDbSDEkeG7i25oOioqDQoNCiQkDQpcY2hpXjIgPSBcc3VtIFxmcmFjeyhPX3tpan0gLSBFX3tpan0pXjJ9e0Vfe2lqfX0NCiQkDQoNClRyb25nIMSRw7M6DQoNCiogJE9fe2lqfSQ6IGdpw6EgdHLhu4sgcXVhbiBzw6F0DQoqICRFX3tpan0kOiBr4buzIHbhu41uZyBu4bq/dSBoYWkgYmnhur9uIMSR4buZYyBs4bqtcA0KDQotLS0NCg0KIyMgKio1LiBD4bqldSB0csO6YyB4w6FjIHN14bqldCB0cm9uZyBi4bqjbmcgbmfhuqt1IG5oacOqbioqDQoNCkLhuqNuZyBjaMOpbyAoYuG6o25nIMSR4bq/bSkgdGjhu7FjIGNo4bqldCBsw6AgbeG7mXQgYmnhu4N1IGhp4buHbiBj4bulIHRo4buDIGPhu6dhIG3hu5l0IG3DtCBow6xuaCB4w6FjIHN14bqldCBuZ+G6q3Ugbmhpw6puLg0KDQojIyMgNS4xLiBDw6FjIG3DtCBow6xuaCB4w6FjIHN14bqldCBzaW5oIHJhIGLhuqNuZw0KDQoqICoqUGjDom4gcGjhu5FpIMSRYSB0aOG7qWMgKE11bHRpbm9taWFsKSoqOiBN4buXaSBow6BuZyBsw6AgbeG7mXQgYmnhur9uIMSRYSB0aOG7qWMgKG11bHRpbm9taWFsIHRyaWFsKS4NCiogKipQaMOibiBwaOG7kWkgc2nDqnUgYuG7mWkgKEh5cGVyZ2VvbWV0cmljKSoqOiBO4bq/dSB04buVbmcgaMOgbmcvY+G7mXQgY+G7kSDEkeG7i25oLCB0aMaw4budbmcgZMO5bmcgdHJvbmcgcGjDqXAgaG/DoW4gduG7iyBuZ+G6q3Ugbmhpw6puLg0KKiAqKlBow6JuIHBo4buRaSBQb2lzc29uKio6IHRoxrDhu51uZyBkw7luZyDEkeG7gyBtw7QgaMOsbmggaMOzYSBz4buRIMSR4bq/bSBoaeG6v20sIMOtdCBkw7luZyB0cm9uZyBi4bqjbmcgMngyLg0KDQoqKk3hu6VjIMSRw61jaDoqKiBHacO6cCBoaeG7g3UgcuG6sW5nIGPDoWMga2nhu4NtIMSR4buLbmggbmjGsCBDaGktc3F1YXJlIGtow7RuZyBjaOG7iSBtYW5nIHTDrW5oIGPGoSBo4buNYywgbcOgIGPDsyBu4buBbiB04bqjbmcgeMOhYyBzdeG6pXQgcGjDrWEgc2F1Lg0KDQotLS0NCg0KIyMgKio2LiBTbyBzw6FuaCBoYWkgdOG7tyBs4buHOiBDw6FjIHRoxrDhu5tjIMSRbyBt4buRaSBsacOqbiBo4buHKioNCg0KS2hpIG114buRbiBzbyBzw6FuaCBoYWkgbmjDs20gduG7gSBt4buZdCBr4bq/dCBxdeG6oyBuaOG7iyBwaMOibiwgY8OzIGJhIHRoxrDhu5tjIMSRbyBwaOG7lSBiaeG6v246DQoNCi0tLQ0KDQojIyMgNi4xLiBIaeG7h3UgaGFpIHThu7cgbOG7hyAoRGlmZmVyZW5jZSBpbiBwcm9wb3J0aW9ucykNCg0KJCQNClxoYXR7cH1fMSAtIFxoYXR7cH1fMg0KJCQNCg0KKiBEaeG7hW4gZ2nhuqNpOiBz4buxIGtow6FjIGJp4buHdCB0dXnhu4d0IMSR4buRaSBnaeG7r2EgaGFpIHThu7cgbOG7hy4NCiogS1RDIDk1JToNCg0KJCQNCihcaGF0e3B9XzEgLSBcaGF0e3B9XzIpIFxwbSB6IFxjZG90IFxzcXJ0eyBcZnJhY3sgXGhhdHtwfV8xICgxIC0gXGhhdHtwfV8xKSB9e25fMX0gKyBcZnJhY3sgXGhhdHtwfV8yICgxIC0gXGhhdHtwfV8yKSB9e25fMn0gfQ0KJCQNCg0KLS0tDQoNCiMjIyA2LjIuIFThu7cgc+G7kSBuZ3V5IGPGoSAoUmVsYXRpdmUgUmlzayDigJMgUlIpDQoNCiQkDQpSUiA9IFxmcmFjeyBcaGF0e3B9XzEgfXsgXGhhdHtwfV8yIH0NCiQkDQoNCiogRGnhu4VuIGdp4bqjaTogTmjDs20gMSBjw7Mga2jhuqMgbsSDbmcgY8OzIGvhur90IHF14bqjICh2ZDogc+G7nyBo4buvdSBuaMOgKSBn4bqlcCBiYW8gbmhpw6p1IGzhuqduIHNvIHbhu5tpIG5ow7NtIDIuDQoqIEThu4UgaGnhu4N1IHbDoCB0cuG7sWMgdGnhur9wIG5oxrBuZyBjaOG7iSBkw7luZyDEkcaw4bujYyB0cm9uZyB0aGnhur90IGvhur8gY8OzIHTDrW5oIHRo4budaSBnaWFuICh2ZDogbmdoacOqbiBj4bupdSBjb2hvcnQsIMSRaeG7gXUgdHJhIGThu41jKS4NCg0KLS0tDQoNCiMjIyA2LjMuIFThu7cgc+G7kSBjaMOqbmggKE9kZHMgUmF0aW8g4oCTIE9SKQ0KDQojIyMjIGEuIE9kZHMgbMOgIGfDrD8NCg0KTuG6v3UgeMOhYyBzdeG6pXQgeOG6o3kgcmEgc+G7sSBraeG7h24gbMOgICRwJCwgdGjDrDoNCg0KJCQNClx0ZXh0e09kZHN9ID0gXGZyYWN7cH17MSAtIHB9DQokJA0KDQrihpIgbMOgIOKAnHThu7cgc+G7kSBjxrDhu6Nj4oCdOiBiYW8gbmhpw6p1IGzhuqduIGPDsyBzbyB24bubaSBraMO0bmcuDQoNCiMjIyMgYi4gT2RkcyBSYXRpbyBsw6AgZ8OsPw0KDQokJA0KT1IgPSBcZnJhY3sgXHRleHR7T2RkcyBuaMOzbSAxfSB9eyBcdGV4dHtPZGRzIG5ow7NtIDJ9IH0gPSBcZnJhY3thZH17YmN9DQokJA0KDQojIyMjIGMuIERp4buFbiBnaeG6o2kgT1I6DQoNCiogT1IgPSAxOiBraMO0bmcga2jDoWMgYmnhu4d0DQoqIE9SID4gMTogbmjDs20gMSBjw7Mgb2RkcyBjYW8gaMahbg0KKiBPUiA8IDE6IG5ow7NtIDEgY8OzIG9kZHMgdGjhuqVwIGjGoW4NCiogT1IgPSAyIOKGkiBvZGRzIG5ow7NtIDEgZ+G6pXAgMiBs4bqnbiBuaMOzbSAyDQoNCiMjIyMgZC4gS2hpIG7DoG8gT1Ig4omIIFJSPw0KDQrihpIgS2hpIHPhu7Ega2nhu4duIGzDoCAqKmhp4bq/bSoqICh4w6FjIHN14bqldCBuaOG7jyksIE9SIHbDoCBSUiBn4bqnbiBuaMawIHTGsMahbmcgxJHGsMahbmcuDQoNCiMjIyMgZS4gVOG6oWkgc2FvIE9SIHF1YW4gdHLhu41uZz8NCg0KKiBEw7luZyDEkcaw4bujYyBj4bqjIHRyb25nIG5naGnDqm4gY+G7qXUgaOG7k2kgY+G7qXUgKGNhc2UtY29udHJvbCkuDQoqIFTDrW5oIMSR4buRaSB44bupbmc6IE9SKEEgdnMgQikgPSAxIC8gT1IoQiB2cyBBKQ0KKiAqKuG7qG5nIGThu6VuZyBy4buZbmcgdHJvbmcgaOG7k2kgcXV5IGxvZ2lzdGljKiog4oCTIHBo4buVIGJp4bq/biB0cm9uZyBuZ2hpw6puIGPhu6l1IGtpbmggdOG6vyBsxrDhu6NuZy4NCg0KLS0tDQoNCiMjICoqNy4gS2hv4bqjbmcgdGluIGPhuq15IGNobyBPZGRzIFJhdGlvKioNCg0KRG8gcGjDom4gcGjhu5FpIE9SIGzhu4djaCwgbsOqbiBLVEMgdMOtbmggZOG7sWEgdHLDqm4gbG9nKE9SKToNCg0KJCQNClx0ZXh0e0tUQyA5NSV9OiBcbG9nKE9SKSBccG0geiBcY2RvdCBTRShcbG9nKE9SKSkNClxSaWdodGFycm93IFx0ZXh0e0V4cG9uZW50aWF0ZSDEkeG7gyByYSB9IFtMLCBVXQ0KJCQNCg0KTuG6v3UgS1RDIGNo4bupYSAxIOKGkiBraMO0bmcgY8OzIGtow6FjIGJp4buHdCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqLg0KDQotLS0NCg0KIyMgKio4LiBWw60gZOG7pSBtaW5oIGjhu41hIHRyb25nIGtpbmggdOG6vyoqDQoNCiMjIyBDw6J1IGjhu49pOg0KDQpLaMOhY2ggaMOgbmcgbuG7ryBjw7Mga2jhuqMgbsSDbmcgc+G7nyBo4buvdSBuaMOgIGNhbyBoxqFuIGtow6FjaCBow6BuZyBuYW0ga2jDtG5nPw0KDQoqKkdp4bqjIHPhu60gYuG6o25nIDJ4MjoqKg0KDQp8ICAgICB8IEPDsyBuaMOgIHwgS2jDtG5nIHwgVOG7lW5nIHwNCnwgLS0tIHwgLS0tLS0tIHwgLS0tLS0gfCAtLS0tIHwNCnwgTmFtIHwgNDAgICAgIHwgNjAgICAgfCAxMDAgIHwNCnwgTuG7ryAgfCA2NiAgICAgfCA1NCAgICB8IDEyMCAgfA0KDQoqIEhp4buHdSB04bu3IGzhu4c6IDY2LzEyMCDigJMgNDAvMTAwID0gMC41NSDigJMgMC40MCA9IDAuMTUNCiogUlIgPSAwLjU1IC8gMC40MCA9IDEuMzc1IOKGkiBO4buvIGPDsyB4w6FjIHN14bqldCBz4bufIGjhu691IG5ow6AgY2FvIGjGoW4gMzcuNSUNCiogT2RkcyBOYW0gPSA0MC82MCA9IDAuNjcNCiAgT2RkcyBO4buvID0gNjYvNTQg4omIIDEuMjINCiAg4oaSIE9SID0gMS4yMiAvIDAuNjcg4omIIDEuODINCiAg4oaSIE9kZHMgc+G7nyBo4buvdSBuaMOgIGPhu6dhIE7hu68gZ+G6pXAgXH4xLjggbOG6p24gc28gduG7m2kgTmFtLg0KDQotLS0NCg0KIyMgKio5LiBL4bq/dCBsdeG6rW4qKg0KDQpQaMOibiB0w61jaCBk4buvIGxp4buHdSDEkeG7i25oIHTDrW5oIGtow7RuZyBjaOG7iSBk4burbmcgbOG6oWkg4bufIMSR4bq/bSBz4buRIGxp4buHdSB2w6AgduG6vSBiaeG7g3UgxJHhu5MuIEPDoWMgdGjGsOG7m2MgxJFvIG5oxrAgKipoaeG7h3UgdOG7tyBs4buHLCBSUiwgT1IqKiB2w6AgKipraeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcqKiBjaG8gcGjDqXAgbmfGsOG7nWkgbmdoacOqbiBj4bupdSByw7p0IHJhIGvhur90IGx14bqtbiBjw7MgY8ahIHPhu58geMOhYyBzdeG6pXQuICoqT2RkcyBSYXRpbyoqLCBkw7kgYmFuIMSR4bqndSBjw7MgduG6uyBraMOzIGhp4buDdSwgbmjGsG5nIGzhuqFpIGzDoCBjw7RuZyBj4bulIGPhu7FjIGvhu7MgaOG7r3Ugw61jaCwgxJHhurdjIGJp4buHdCB0cm9uZyBjw6FjIG3DtCBow6xuaCBraW5oIHThur8gbMaw4bujbmcgaGnhu4duIMSR4bqhaS4NCg0KLS0tDQoNCmBgYHtyIGVjaG89IFRSVUUsIGV2YWw9RkFMU0V9DQpsaWJyYXJ5KHNob3d0ZXh0KQ0KZm9udF9hZGQoZmFtaWx5ID0gIkFyaWFsIiwgcmVndWxhciA9ICJhcmlhbC50dGYiKSAgDQpzaG93dGV4dF9hdXRvKCkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShlcGl0b29scykNCmxpYnJhcnkoRGVzY1Rvb2xzKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkoZW5lcmd5KQ0KbGlicmFyeShyZWFkcikNCm9wdGlvbnMoZGlnaXRzID0gNCkNCmBgYA0KDQojICoqVEjhu7BDIEjDgE5IIFBIw4JOIFTDjUNIIFRI4buQTkcgS8OKIENITyBE4buuIExJ4buGVSDEkOG7ik5IIFTDjU5IIEThu7BBIFRSw4pOIELhu5ggROG7riBMSeG7hlUgOkNvbnN1bWVyIEJlaGF2aW9yIGFuZCBTaG9wcGluZyBIYWJpdHMqKg0KDQojIyAqKjEuIFThu5RORyBRVUFOIFbhu4AgQuG7mCBE4buuIExJ4buGVSoqDQoNCiMjIyBU4buVbmcgcXVhbiB24buBIGLhu5kgZOG7ryBsaeG7h3UgQ29uc3VtZXIgQmVoYXZpb3IgYW5kIFNob3BwaW5nIEhhYml0cw0KDQpC4buZIGThu68gbGnhu4d1ICoqQ29uc3VtZXIgQmVoYXZpb3IgYW5kIFNob3BwaW5nIEhhYml0cyoqIHRyw6puIEthZ2dsZSBjdW5nIGPhuqVwIHRow7RuZyB0aW4gY2hpIHRp4bq/dCB24buBIGjDoG5oIHZpIG11YSBz4bqvbSB2w6Agc+G7nyB0aMOtY2ggY+G7p2EgbmfGsOG7nWkgdGnDqnUgZMO5bmcgdHJvbmcgbMSpbmggduG7sWMgdGjGsMahbmcgbeG6oWkgxJFp4buHbiB04butLiBE4buvIGxp4buHdSBuw6B5IMSRxrDhu6NjIG3DtCB04bqjIGzDoCBt4buZdCB04bqtcCBo4bujcCB0b8OgbiBkaeG7h24sIGJhbyBn4buTbSBuaGnhu4F1IGtow61hIGPhuqFuaCB24buBIGjDoG5oIHZpIG5nxrDhu51pIHRpw6p1IGTDuW5nLCBnacO6cCBjw6FjIG5ow6AgcGjDom4gdMOtY2ggdsOgIGRvYW5oIG5naGnhu4dwIGhp4buDdSByw7UgaMahbiB24buBIGPDoWNoIG5nxrDhu51pIHRpw6p1IGTDuW5nIMSRxrBhIHJhIHF1eeG6v3QgxJHhu4tuaCBtdWEgc+G6r20uIELhu5kgZOG7ryBsaeG7h3UgbsOgeSBy4bqldCBo4buvdSDDrWNoIMSR4buDIHBow6JuIHTDrWNoIHh1IGjGsOG7m25nIG11YSBz4bqvbSwgdOG7kWkgxrB1IGjDs2EgY2hp4bq/biBsxrDhu6NjIHRp4bq/cCB0aOG7iywgY+G6o2kgdGhp4buHbiBz4bqjbiBwaOG6qW0gdsOgIG7Dom5nIGNhbyB0cuG6o2kgbmdoaeG7h20ga2jDoWNoIGjDoG5nLltdKGh0dHBzOi8vbWVkaXVtLmNvbS8lNDB2bXJhanB1dDIwL2NvbnN1bWVyLWJlaGF2aW9yLWFuZC1zaG9wcGluZy1oYWJpdHMtZjJiMDRjYmI4NzRiKQ0KDQojIyMjICoqTuG7mWkgZHVuZyBjaMOtbmggY+G7p2EgYuG7mSBk4buvIGxp4buHdSoqDQotICoqTcO0IHThuqMqKjogQuG7mSBk4buvIGxp4buHdSB04bqtcCB0cnVuZyB2w6BvIGPDoWMgaMOgbmggdmkgbXVhIHPhuq9tLCBiYW8gZ+G7k20gdGjDtG5nIHRpbiB24buBIG5ow6JuIGto4bqpdSBo4buNYyAoZGVtb2dyYXBoaWNzKSwgbOG7i2NoIHPhu60gbXVhIGjDoG5nLCBz4bufIHRow61jaCBz4bqjbiBwaOG6qW0sIHThuqduIHN14bqldCBtdWEgc+G6r20sIHbDoCB0aMOzaSBxdWVuIG11YSBz4bqvbSB0cuG7sWMgdHV54bq/biBob+G6t2Mgbmdv4bqhaSB0dXnhur9uLiDEkMOieSBsw6AgZOG7ryBsaeG7h3UgdOG7lW5nIGjhu6NwIChzeW50aGV0aWMgZGF0YSkgbcO0IHBo4buPbmcgaMOgbmggdmkgbXVhIHPhuq9tIHRo4buxYyB04bq/LCBwaMO5IGjhu6NwIMSR4buDIHBow6JuIHTDrWNoIGjDoG5oIHZpIHRpw6p1IGTDuW5nIHbDoCB4dSBoxrDhu5tuZyBiw6FuIGzhursuW10oaHR0cHM6Ly9tZWRpdW0uY29tLyU0MHZtcmFqcHV0MjAvY29uc3VtZXItYmVoYXZpb3ItYW5kLXNob3BwaW5nLWhhYml0cy1mMmIwNGNiYjg3NGIpW10oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9jb2RlL2p1YW5tY2FicmVyYS9jb25zdW1lci1iZWhhdmlvci1hbmQtc2hvcHBpbmctaGFiaXRzLWRhdGFzZXQpDQotICoq4buobmcgZOG7pW5nKio6IEThu68gbGnhu4d1IGPDsyB0aOG7gyDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gzoNCiAgLSBQaMOibiB0w61jaCB4dSBoxrDhu5tuZyB0acOqdSBkw7luZy4NCiAgLSBYw6J5IGThu7FuZyBjw6FjIG3DtCBow6xuaCBk4buxIMSRb8OhbiBow6BuaCB2aSBtdWEgc+G6r20uDQogIC0gVOG7kWkgxrB1IGjDs2EgY2hp4bq/biBsxrDhu6NjIHRp4bq/cCB0aOG7iyB2w6AgZGFuaCBt4bulYyBz4bqjbiBwaOG6qW0uDQogIC0gTmdoacOqbiBj4bupdSBz4buxIGtow6FjIGJp4buHdCB0cm9uZyBow6BuaCB2aSBtdWEgc+G6r20gdGhlbyBnaeG7m2kgdMOtbmgsIMSR4buZIHR14buVaSwgaG/hurdjIGPDoWMgeeG6v3UgdOG7kSBuaMOibiBraOG6qXUgaOG7jWMga2jDoWMuDQoNCg0KIyMjIyAqKkRhbmggc8OhY2ggY8OhYyBiaeG6v24gdsOgIHBow6JuIGxv4bqhaSoqDQoNCmBgYHtyfQ0KI8SQ4buNYyBk4buvIGxp4buHdSB04burIGZpbGUgQ1NWDQpkYXRhIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9Ib2FuZyBRdXllbi9Eb3dubG9hZHMvc2hvcHBpbmdfYmVoYXZpb3JfdXBkYXRlZC5jc3YiKQ0KI0hp4buDbiB0aOG7iyBj4bqldSB0csO6YyBk4buvIGxp4buHdQ0Kc3RyKGRhdGEpDQpgYGANCg0KYGBge3J9DQojSGnhu4NuIHRo4buLIDUgZMOybmcgxJHhuqd1IHbDoCBjdeG7kWkNCmhlYWQoZGF0YSwgNSkNCnRhaWwoZGF0YSwgNSkNCg0KYGBgDQoNCmBgYHtyfQ0KI0tp4buDbSB0cmEgTkEgdHJvbmcgY8OhYyBj4buZdCDEkeG7i25oIHTDrW5oDQoNCmNhdF92YXJzIDwtIGMoIkdlbmRlciIsICJJdGVtLlB1cmNoYXNlZCIsICJDYXRlZ29yeSIsICJMb2NhdGlvbiIsICJTaXplIiwgIkNvbG9yIiwgDQogICAgICAgICAgICAgICJTZWFzb24iLCAiU3Vic2NyaXB0aW9uLlN0YXR1cyIsICJTaGlwcGluZy5UeXBlIiwgIkRpc2NvdW50LkFwcGxpZWQiLCANCiAgICAgICAgICAgICAgIlByb21vLkNvZGUuVXNlZCIsICJQYXltZW50Lk1ldGhvZCIsICJGcmVxdWVuY3kub2YuUHVyY2hhc2VzIikNCnNhcHBseShkYXRhW2NhdF92YXJzXSwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkNCmBgYA0KDQpgYGB7cn0NCiNDaHV54buDbiDEkeG7lWkgc2FuZyBmYWN0b3INCmRhdGFbY2F0X3ZhcnNdIDwtIGxhcHBseShkYXRhW2NhdF92YXJzXSwgYXMuZmFjdG9yKQ0KDQojS2nhu4NtIHRyYSBs4bqhaSBj4bqldSB0csO6Yw0Kc3RyKGRhdGFbY2F0X3ZhcnNdKQ0KYGBgDQoNCkThu7FhIHRyw6puIG3DtCB04bqjIHThu6sgbmd14buTbiB2w6AgcGjDom4gdMOtY2ggY+G6pXUgdHLDumMgZOG7ryBsaeG7h3UsIGPDoWMgY+G7mXQgdHJvbmcgYuG7mSBk4buvIGxp4buHdSBiYW8gZ+G7k206DQoNCjEuICoqQ3VzdG9tZXIgSUQqKiAoxJDhu4tuaCBsxrDhu6NuZyk6IE3DoyDEkeG7i25oIGRhbmggZHV5IG5o4bqldCBjaG8gbeG7l2kga2jDoWNoIGjDoG5nLg0KMi4gKipBZ2UqKiAoxJDhu4tuaCBsxrDhu6NuZyk6IFR14buVaSBj4bunYSBraMOhY2ggaMOgbmcuDQozLiAqKkdlbmRlcioqICjEkOG7i25oIHTDrW5oKTogR2nhu5tpIHTDrW5oIGPhu6dhIGtow6FjaCBow6BuZyAodsOtIGThu6U6IE1hbGUsIEZlbWFsZSkuDQo0LiAqKkl0ZW0gUHVyY2hhc2VkKiogKMSQ4buLbmggdMOtbmgpOiBT4bqjbiBwaOG6qW0gxJHGsOG7o2MgbXVhICh2w60gZOG7pTogw6FvLCBnacOgeSwgdi52LikuDQo1LiAqKkNhdGVnb3J5KiogKMSQ4buLbmggdMOtbmgpOiBEYW5oIG3hu6VjIHPhuqNuIHBo4bqpbSAodsOtIGThu6U6IENsb3RoaW5nLCBBY2Nlc3NvcmllcywgRm9vdHdlYXIsIE91dGVyd2VhcikuDQo2LiAqKlB1cmNoYXNlIEFtb3VudCAoVVNEKSoqICjEkOG7i25oIGzGsOG7o25nKTogU+G7kSB0aeG7gW4gY2hpIGNobyBnaWFvIGThu4tjaCAodMOtbmggYuG6sW5nIFVTRCkuDQo3LiAqKkxvY2F0aW9uKiogKMSQ4buLbmggdMOtbmgpOiDEkOG7i2EgxJFp4buDbSBtdWEgc+G6r20gKHbDrSBk4bulOiB0w6puIHRow6BuaCBwaOG7kSBob+G6t2MgdGnhu4N1IGJhbmcpLg0KOC4gKipTaXplKiogKMSQ4buLbmggdMOtbmgpOiBLw61jaCBj4buhIHPhuqNuIHBo4bqpbSAodsOtIGThu6U6IFMsIE0sIEwsIFhMKS4NCjkuICoqQ29sb3IqKiAoxJDhu4tuaCB0w61uaCk6IE3DoHUgc+G6r2Mgc+G6o24gcGjhuqltLg0KMTAuICoqU2Vhc29uKiogKMSQ4buLbmggdMOtbmgpOiBNw7lhIG11YSBz4bqvbSAodsOtIGThu6U6IFNwcmluZywgU3VtbWVyLCBGYWxsLCBXaW50ZXIpLg0KMTEuICoqUmV2aWV3IFJhdGluZyoqICjEkOG7i25oIGzGsOG7o25nKTogxJBp4buDbSDEkcOhbmggZ2nDoSBz4bqjbiBwaOG6qW0gKHRoxrDhu51uZyBsw6AgdGhhbmcgxJFp4buDbSB04burIDEtNSkuDQoxMi4gKipTdWJzY3JpcHRpb24gU3RhdHVzKiogKMSQ4buLbmggdMOtbmgpOiBUcuG6oW5nIHRow6FpIMSRxINuZyBrw70gKHbDrSBk4bulOiBZZXMsIE5vKS4NCjEzLiAqKlNoaXBwaW5nIFR5cGUqKiAoxJDhu4tuaCB0w61uaCk6IExv4bqhaSBow6xuaCB24bqtbiBjaHV54buDbiAodsOtIGThu6U6IEZyZWUgU2hpcHBpbmcsIFN0YW5kYXJkLCBFeHByZXNzKS4NCjE0LiAqKkRpc2NvdW50IEFwcGxpZWQqKiAoxJDhu4tuaCB0w61uaCk6IEPDsyDDoXAgZOG7pW5nIGdp4bqjbSBnacOhIGhheSBraMO0bmcgKFllcy9ObykuDQoxNS4gKipQcm9tbyBDb2RlIFVzZWQqKiAoxJDhu4tuaCB0w61uaCk6IEPDsyBz4butIGThu6VuZyBtw6Mga2h1eeG6v24gbcOjaSBoYXkga2jDtG5nIChZZXMvTm8pLg0KMTYuICoqUHJldmlvdXMgUHVyY2hhc2VzKiogKMSQ4buLbmggbMaw4bujbmcpOiBT4buRIGzGsOG7o25nIGdpYW8gZOG7i2NoIHRyxrDhu5tjIMSRw7MgY+G7p2Ega2jDoWNoIGjDoG5nLg0KMTcuICoqUGF5bWVudCBNZXRob2QqKiAoxJDhu4tuaCB0w61uaCk6IFBoxrDGoW5nIHRo4bupYyB0aGFuaCB0b8OhbiAodsOtIGThu6U6IENyZWRpdCBDYXJkLCBQYXlQYWwsIENhc2gpLg0KMTguICoqRnJlcXVlbmN5IG9mIFB1cmNoYXNlcyoqICjEkOG7i25oIHTDrW5oKTogVOG6p24gc3XhuqV0IG11YSBz4bqvbSAodsOtIGThu6U6IERhaWx5LCBXZWVrbHksIE1vbnRobHksIFllYXJseSkuDQoNCioqVOG7lW5nIGvhur90IHBow6JuIGxv4bqhaSBiaeG6v24qKjoNCi0gKipCaeG6v24gxJHhu4tuaCB0w61uaCAoQ2F0ZWdvcmljYWwpKio6IDEyIGJp4bq/bg0KICAtIEdlbmRlciwgSXRlbSBQdXJjaGFzZWQsIENhdGVnb3J5LCBMb2NhdGlvbiwgU2l6ZSwgQ29sb3IsIFNlYXNvbiwgU3Vic2NyaXB0aW9uIFN0YXR1cywgU2hpcHBpbmcgVHlwZSwgRGlzY291bnQgQXBwbGllZCwgUHJvbW8gQ29kZSBVc2VkLCBQYXltZW50IE1ldGhvZCwgRnJlcXVlbmN5IG9mIFB1cmNoYXNlcy4NCi0gKipCaeG6v24gxJHhu4tuaCBsxrDhu6NuZyAoTnVtZXJpY2FsKSoqOiA0IGJp4bq/bg0KICAtIEN1c3RvbWVyIElELCBBZ2UsIFB1cmNoYXNlIEFtb3VudCAoVVNEKSwgUmV2aWV3IFJhdGluZywgUHJldmlvdXMgUHVyY2hhc2VzLg0KDQoNCg0KDQojIyMjICoqS+G6v3QgbHXhuq1uKioNCkLhu5kgZOG7ryBsaeG7h3UgKipDb25zdW1lciBCZWhhdmlvciBhbmQgU2hvcHBpbmcgSGFiaXRzKiogY2jhu6lhICoqMzkwMCBkw7JuZyoqIHbDoCAqKjE4IGPhu5l0KiosIHbhu5tpICoqMTIgYmnhur9uIMSR4buLbmggdMOtbmgqKiB2w6AgKio0IGJp4bq/biDEkeG7i25oIGzGsOG7o25nKiouIE7DsyBjdW5nIGPhuqVwIG3hu5l0IGPDoWkgbmjDrG4gdG/DoG4gZGnhu4duIHbhu4EgaMOgbmggdmkgdGnDqnUgZMO5bmcsIHThu6sgbmjDom4ga2jhuql1IGjhu41jIMSR4bq/biB0aMOzaSBxdWVuIG11YSBz4bqvbSwgcuG6pXQgaOG7r3Ugw61jaCBjaG8gY8OhYyBuaMOgIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IHbDoCBkb2FuaCBuZ2hp4buHcCBtdeG7kW4gdOG7kWkgxrB1IGjDs2EgY2hp4bq/biBsxrDhu6NjIGtpbmggZG9hbmguIA0KDQojIyAqKlRI4buQTkcgS8OKIE3DlCBU4bqiIDEgQknhur5OKioNCg0KIyMjICoqR0VOREVSKioNCg0KYGBge3J9DQojQuG6o25nIHThuqduIHPhu5EgdsOgIHThu7cgbOG7hw0KZ2VuZGVyX2ZyZXEgPC0gdGFibGUoZGF0YSRHZW5kZXIpDQpnZW5kZXJfcHJvcCA8LSBwcm9wLnRhYmxlKGdlbmRlcl9mcmVxKSAqIDEwMA0KZ2VuZGVyX3RhYmxlIDwtIGRhdGEuZnJhbWUoRnJlcXVlbmN5ID0gZ2VuZGVyX2ZyZXEsIFBlcmNlbnRhZ2UgPSBnZW5kZXJfcHJvcCkNCnByaW50KGdlbmRlcl90YWJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KI0Jp4buDdSDEkeG7kyB0csOybg0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gIiIsIGZpbGwgPSBHZW5kZXIpKSArDQogIGdlb21fYmFyKHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBi4buRIEdp4bubaSB0w61uaCIsIGZpbGwgPSAiR2VuZGVyIikgKw0KICB0aGVtZV92b2lkKCkNCmBgYA0KDQpU4bu3IGzhu4cgbmfGsOG7nWkgbXVhIHRoZW8gZ2nhu5tpIHTDrW5oIGNobyB0aOG6pXkgTWFsZSBjaGnhur9tIMawdSB0aOG6vyByw7UgcuG7h3QgduG7m2kgNjglLCB0cm9uZyBraGkgRmVtYWxlIGNo4buJIGNoaeG6v20gMzIlLiBCaeG7g3UgxJHhu5MgdHLDsm4gbWluaCBo4buNYSBz4buxIG3huqV0IGPDom4gxJHhu5FpIG7DoHkgcuG6pXQgcsO1IHLDoG5nLiBL4bq/dCBxdeG6oyBuw6B5IGtow6FjIGJp4buHdCDEkcOhbmcga+G7gyBzbyB24bubaSB4dSBoxrDhu5tuZyB0aOG7sWMgdOG6vyB0cm9uZyBjw6FjIGLhu5kgZOG7ryBsaeG7h3UgdGjGsMahbmcgbeG6oWkgxJFp4buHbiB04butLCB24buRbiB0aMaw4budbmcgZ2hpIG5o4bqtbiB04bu3IGzhu4cgRmVtYWxlIOG7nyBt4bupYyBraG/huqNuZyA2OCUuIERvIMSRw7MsIGPDsyBraOG6oyBuxINuZyB04buTbiB04bqhaSBzYWkgc8OzdCB0cm9uZyBraMOidSBuaOG6rXAgbGnhu4d1IGhv4bq3YyB0aHUgdGjhuq1wIGThu68gbGnhu4d1LCB2w6AgY+G6p24gdGnhur9uIGjDoG5oIGtp4buDbSB0cmEsIMSR4buRaSBjaGnhur91IGzhuqFpIGThu68gbGnhu4d1IGfhu5FjIMSR4buDIMSR4bqjbSBi4bqjbyB0w61uaCBjaMOtbmggeMOhYy4NCg0KIyMjICoqSVRFTS5QVVJDSEFTRUQqKg0KDQoNCmBgYHtyfQ0KIyBC4bqjbmcgdOG6p24gc+G7kSB2w6AgdOG7tyBs4buHDQppdGVtX2ZyZXEgPC0gdGFibGUoZGF0YSRJdGVtLlB1cmNoYXNlZCkNCml0ZW1fcHJvcCA8LSBwcm9wLnRhYmxlKGl0ZW1fZnJlcSkgKiAxMDANCml0ZW1fdGFibGUgPC0gZGF0YS5mcmFtZShGcmVxdWVuY3kgPSBpdGVtX2ZyZXEsIFBlcmNlbnRhZ2UgPSBpdGVtX3Byb3ApDQpwcmludChpdGVtX3RhYmxlKQ0KYGBgDQoNCg0KYGBge3J9DQojIEJp4buDdSDEkeG7kyBj4buZdCAoZG8gY8OzIG5oaeG7gXUgZ2nDoSB0cuG7iykNCmdncGxvdChkYXRhLCBhZXMoeCA9IEl0ZW0uUHVyY2hhc2VkLCBmaWxsID0gSXRlbS5QdXJjaGFzZWQpKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgU+G6o24gcGjhuqltIMSRxrDhu6NjIG11YSIsIHggPSAiSXRlbSBQdXJjaGFzZWQiLCB5ID0gIlThuqduIHPhu5EiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KROG7ryBsaeG7h3UgZ2hpIG5o4bqtbiBjw7Mga2hv4bqjbmcgMjUgbG/huqFpIHPhuqNuIHBo4bqpbSBraMOhYyBuaGF1LCB0cm9uZyDEkcOzIEJsb3VzZSBjaOG7iSBjaGnhur9tIDQuMzglIHThu5VuZyBz4buRIGzGsOG7o3QgbXVhICgxNzEvMzkwMCkuIEJp4buDdSDEkeG7kyBj4buZdCB0aOG7gyBoaeG7h24gc+G7sSBwaMOibiBi4buRIGtow6EgxJHhu5NuZyDEkeG7gXUgZ2nhu69hIGPDoWMgbeG6t3QgaMOgbmcgcGjhu5UgYmnhur9uIG5oxrAgQmxvdXNlLCBQYW50cywgdsOgIEpld2VscnkuIEtow7RuZyBjw7Mgc+G6o24gcGjhuqltIG7DoG8gdsaw4bujdCB0cuG7mWkgaG/DoG4gdG/DoG4gduG7gSB04bqnbiBzdeG6pXQsIMSRaeG7gXUgbsOgeSBwaOG6o24gw6FuaCBz4buxIMSRYSBk4bqhbmcgdHJvbmcgbOG7sWEgY2jhu41uIHPhuqNuIHBo4bqpbSBj4bunYSBraMOhY2ggaMOgbmcg4oCTIG3hu5l0IMSR4bq3YyDEkWnhu4NtIHBo4buVIGJp4bq/biB0cm9uZyBow6BuaCB2aSBtdWEgc+G6r20gdGjhu51pIHRyYW5nLg0KDQojIyMgKipDQVRFR09SWSoqDQoNCmBgYHtyfQ0KIyBC4bqjbmcgdOG6p24gc+G7kSB2w6AgdOG7tyBs4buHDQpjYXRlZ29yeV9mcmVxIDwtIHRhYmxlKGRhdGEkQ2F0ZWdvcnkpDQpjYXRlZ29yeV9wcm9wIDwtIHByb3AudGFibGUoY2F0ZWdvcnlfZnJlcSkgKiAxMDANCmNhdGVnb3J5X3RhYmxlIDwtIGRhdGEuZnJhbWUoRnJlcXVlbmN5ID0gY2F0ZWdvcnlfZnJlcSwgUGVyY2VudGFnZSA9IGNhdGVnb3J5X3Byb3ApDQpwcmludChjYXRlZ29yeV90YWJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KIyBCaeG7g3UgxJHhu5MgdHLDsm4NCmdncGxvdChkYXRhLCBhZXMoeCA9ICIiLCBmaWxsID0gQ2F0ZWdvcnkpKSArDQogIGdlb21fYmFyKHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBi4buRIERhbmggbeG7pWMgU+G6o24gcGjhuqltIiwgZmlsbCA9ICJDYXRlZ29yeSIpICsNCiAgdGhlbWVfdm9pZCgpDQpgYGANCg0KRGFuaCBt4bulYyBz4bqjbiBwaOG6qW0gQ2xvdGhpbmcgY2hp4bq/bSB04bu3IHRy4buNbmcgbOG7m24gbmjhuqV0IHbhu5tpIDQ0LjU0JSwgdGnhur9wIHRoZW8gbMOgIEFjY2Vzc29yaWVzLCBGb290d2VhciwgdsOgIE91dGVyd2Vhci4gQmnhu4N1IMSR4buTIHRyw7JuIHRo4buDIGhp4buHbiByw7UgQ2xvdGhpbmcgbMOgIGRhbmggbeG7pWMgbuG7lWkgYuG6rXQsIGNobyB0aOG6pXkgeHUgaMaw4bubbmcgdOG6rXAgdHJ1bmcgbXVhIHPhuq9tIHbDoG8gY8OhYyBz4bqjbiBwaOG6qW0gdGjhu51pIHRyYW5nIGPGoSBi4bqjbi4NCg0KIyMjICoqTE9DQVRJT04qKg0KDQpgYGB7cn0NCiMgQuG6o25nIHThuqduIHPhu5EgdsOgIHThu7cgbOG7hw0KbG9jYXRpb25fZnJlcSA8LSB0YWJsZShkYXRhJExvY2F0aW9uKQ0KbG9jYXRpb25fcHJvcCA8LSBwcm9wLnRhYmxlKGxvY2F0aW9uX2ZyZXEpICogMTAwDQpsb2NhdGlvbl90YWJsZSA8LSBkYXRhLmZyYW1lKEZyZXF1ZW5jeSA9IGxvY2F0aW9uX2ZyZXEsIFBlcmNlbnRhZ2UgPSBsb2NhdGlvbl9wcm9wKQ0KcHJpbnQobG9jYXRpb25fdGFibGUpDQpgYGANCg0KDQpgYGB7cn0NCiMgQmnhu4N1IMSR4buTIGPhu5l0IA0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gTG9jYXRpb24sIGZpbGwgPSBMb2NhdGlvbikpICsNCiAgZ2VvbV9iYXIoKSArDQogIGxhYnModGl0bGUgPSAiUGjDom4gYuG7kSDEkOG7i2EgxJFp4buDbSIsIHggPSAiTG9jYXRpb24iLCB5ID0gIlThuqduIHPhu5EiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQpQaMOibiB0w61jaCDEkeG7i2EgbMO9IGNobyB0aOG6pXkgTmV3IFlvcmsgY2jhu4kgY2hp4bq/bSAyLjIzJSwgdHJvbmcga2hpIGPDoWMgdGnhu4N1IGJhbmcgbmjGsCBDYWxpZm9ybmlhIHbDoCBUZXhhcyBjxaluZyBjw7MgdOG6p24gc3XhuqV0IHh14bqldCBoaeG7h24gY2FvLiBCaeG7g3UgxJHhu5MgY+G7mXQgcGjhuqNuIMOhbmggc+G7sSBwaMOibiBi4buVIGtow6EgxJHhu4F1IGdp4buvYSB+NTAgYmFuZywga2jDtG5nIGPDsyBiYW5nIG7DoG8gY2hp4bq/bSDGsHUgdGjhur8gw6FwIMSR4bqjby4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgZOG7ryBsaeG7h3UgxJHGsOG7o2MgdGh1IHRo4bqtcCB04burIG5oaeG7gXUga2h1IHbhu7FjIGtow6FjIG5oYXUsIHBo4bqjbiDDoW5oIHTDrW5oIMSR4bqhaSBkaeG7h24gY2FvLg0KDQojIyMgKipTSVpFKioNCg0KYGBge3J9DQojIELhuqNuZyB04bqnbiBz4buRIHbDoCB04bu3IGzhu4cNCnNpemVfZnJlcSA8LSB0YWJsZShkYXRhJFNpemUpDQpzaXplX3Byb3AgPC0gcHJvcC50YWJsZShzaXplX2ZyZXEpICogMTAwDQpzaXplX3RhYmxlIDwtIGRhdGEuZnJhbWUoRnJlcXVlbmN5ID0gc2l6ZV9mcmVxLCBQZXJjZW50YWdlID0gc2l6ZV9wcm9wKQ0KcHJpbnQoc2l6ZV90YWJsZSkNCmBgYA0KDQoNCmBgYHtyfQ0KIyBCaeG7g3UgxJHhu5MgdHLDsm4NCmdncGxvdChkYXRhLCBhZXMoeCA9ICIiLCBmaWxsID0gU2l6ZSkpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAxKSArDQogIGNvb3JkX3BvbGFyKCJ5IikgKw0KICBsYWJzKHRpdGxlID0gIlBow6JuIGLhu5EgS8OtY2ggY+G7oSIsIGZpbGwgPSAiU2l6ZSIpICsNCiAgdGhlbWVfdm9pZCgpDQpgYGANCg0KS8OtY2ggY+G7oSBNIChNZWRpdW0pIGNoaeG6v20gdOG7tyBs4buHIGNhbyBuaOG6pXQgduG7m2kgNDUlLCB2xrDhu6N0IHRy4buZaSBzbyB24bubaSBjw6FjIHNpemUgY8OybiBs4bqhaSBuaMawIEwsIFMsIHbDoCBYTC4gQmnhu4N1IMSR4buTIHRyw7JuIGto4bqzbmcgxJHhu4tuaCB4dSBoxrDhu5tuZyBjaOG7jW4ga8OtY2ggY+G7oSB0cnVuZyBiw6xuaCDigJMgxJHDonkgbMOgIGvhur90IHF14bqjIHBow7kgaOG7o3AgduG7m2kgY2h14bqpbiBjxqEgdGjhu4MgcGjhu5UgYmnhur9uIHRyb25nIG5nw6BuaCB0aOG7nWkgdHJhbmcuDQoNCiMjIyAqKlNFQVNPTioqDQoNCmBgYHtyfQ0KIyBC4bqjbmcgdOG6p24gc+G7kSB2w6AgdOG7tyBs4buHDQpzZWFzb25fZnJlcSA8LSB0YWJsZShkYXRhJFNlYXNvbikNCnNlYXNvbl9wcm9wIDwtIHByb3AudGFibGUoc2Vhc29uX2ZyZXEpICogMTAwDQpzZWFzb25fdGFibGUgPC0gZGF0YS5mcmFtZShGcmVxdWVuY3kgPSBzZWFzb25fZnJlcSwgUGVyY2VudGFnZSA9IHNlYXNvbl9wcm9wKQ0KcHJpbnQoc2Vhc29uX3RhYmxlKQ0KYGBgDQoNCg0KYGBge3J9DQojIEJp4buDdSDEkeG7kyB0csOybg0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gIiIsIGZpbGwgPSBTZWFzb24pKSArDQogIGdlb21fYmFyKHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBi4buRIE3DuWEgbXVhIHPhuq9tIiwgZmlsbCA9ICJTZWFzb24iKSArDQogIHRoZW1lX3ZvaWQoKQ0KYGBgDQoNClBow6JuIGLhu5EgdGhlbyBtw7lhIGtow6EgxJHhu5NuZyDEkeG7gXUgduG7m2kgbcO5YSBYdcOibiAoU3ByaW5nKSBjaGnhur9tIDI1LjYyJS4gQ8OhYyBtw7lhIGPDsm4gbOG6oWkgKFN1bW1lciwgRmFsbCwgV2ludGVyKSBjw7MgdOG7tyBs4buHIHjhuqVwIHjhu4kgbmhhdSAofjI1JSkuIEJp4buDdSDEkeG7kyB0csOybiB4w6FjIG5o4bqtbiBraMO0bmcgY8OzIHPhu7EgdGhpw6puIGzhu4djaCByw7UgcuG7h3QgdGhlbyBtw7lhLCDEkWnhu4F1IG7DoHkgcGjhuqNuIMOhbmggaMOgbmggdmkgbXVhIHPhuq9tIGtow7RuZyBwaOG7pSB0aHXhu5ljIHbDoG8geeG6v3UgdOG7kSB0aOG7nWkgduG7pSB0cm9uZyB04bqtcCBk4buvIGxp4buHdSBuw6B5Lg0KDQojIyAqKsav4buaQyBMxq/hu6JORyBLSE/huqJORyBWw4AgS0nhu4JNIMSQ4buKTkggR0nhuqIgVEhVWeG6vlQgQ0hPIFThu7YgTOG7hioqDQoNCiMjIyAqKkdFTkRFUioqDQoNCmBgYHtyfQ0KIyDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIEZlbWFsZQ0KbiA8LSBucm93KGRhdGEpDQpmZW1hbGVfY291bnQgPC0gc3VtKGRhdGEkR2VuZGVyID09ICJGZW1hbGUiKQ0KcHJvcF9mZW1hbGUgPC0gZmVtYWxlX2NvdW50IC8gbg0Kc2VfZmVtYWxlIDwtIHNxcnQocHJvcF9mZW1hbGUgKiAoMSAtIHByb3BfZmVtYWxlKSAvIG4pDQpjaV9mZW1hbGUgPC0gcHJvcF9mZW1hbGUgKyBjKC0xLCAxKSAqIDEuOTYgKiBzZV9mZW1hbGUNCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIE7hu686Iiwgcm91bmQoY2lfZmVtYWxlICogMTAwLCAyKSwgIiVcbiIpDQpgYGANCg0KKiAqKkdp4bqjIHRodXnhur90OioqDQoNCiAgKiAkSF8wOiBwID0gMC41JCAoVOG7tyBs4buHIG7hu68gbMOgIDUwJSkNCiAgKiAkSF8xOiBwIFxuZSAwLjUkDQoNCg0KYGBge3J9DQojIEtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IChIMDogVOG7tyBs4buHIE7hu68gPSAwLjUpDQpwcm9wLnRlc3QoZmVtYWxlX2NvdW50LCBuLCBwID0gMC41LCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KKiAqKkvhur90IHF14bqjOioqDQoNCiAgKiBU4bu3IGzhu4cgbuG7rzogMzIuMDUlDQogICogS2hv4bqjbmcgdGluIGPhuq15IDk1JTogKipcWzMwLjU0JTsgMzMuNDYlXSoqDQogICogJHAkLXZhbHVlIGPhu6dhIGtp4buDbSDEkeG7i25oOiAqKjwgMi4yZS0xNioqDQoNCiogKipOaOG6rW4geMOpdDoqKiBWw6wgJHAkLXZhbHVlIHLhuqV0IG5o4buPICg8IDAuMDUpLCAqKmLDoWMgYuG7jyAkSF8wJCoqLiBU4bu3IGzhu4cgbuG7ryB0cm9uZyBt4bqrdSAqKmtow6FjIGJp4buHdCBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqIHNvIHbhu5tpIDUwJSoqLCBjaG8gdGjhuqV5ICoqZOG7ryBsaeG7h3UgY8OzIHRoacOqbiBs4buHY2ggZ2nhu5tpIHTDrW5oIG5naGnDqm5nIHbhu4EgbmFtKiouDQoNCiMjIyAqKklURU0uUFVSQ0hBU0VEKioNCg0KYGBge3J9DQoNCg0KIyDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIEJsb3VzZQ0KaXRlbV9jb3VudCA8LSBzdW0oZGF0YSRJdGVtLlB1cmNoYXNlZCA9PSAiQmxvdXNlIikNCnByb3BfaXRlbSA8LSBpdGVtX2NvdW50IC8gbg0Kc2VfaXRlbSA8LSBzcXJ0KHByb3BfaXRlbSAqICgxIC0gcHJvcF9pdGVtKSAvIG4pDQpjaV9pdGVtIDwtIHByb3BfaXRlbSArIGMoLTEsIDEpICogMS45NiAqIHNlX2l0ZW0NCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIEJsb3VzZToiLCByb3VuZChjaV9pdGVtICogMTAwLCAyKSwgIiVcbiIpDQpgYGANCg0KKiAqKkdp4bqjIHRodXnhur90OioqDQoNCiAgKiAkSF8wOiBwID0gMC4wNSQNCiAgKiAkSF8xOiBwIFxuZSAwLjA1JA0KDQpgYGB7cn0NCiMgS2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3QgKEgwOiBU4bu3IGzhu4cgQmxvdXNlID0gMC4wNSkNCnByb3AudGVzdChpdGVtX2NvdW50LCBuLCBwID0gMC4wNSwgY29uZi5sZXZlbCA9IDAuOTUpDQoNCmBgYA0KDQoNCiogKipL4bq/dCBxdeG6ozoqKg0KDQogICogVOG7tyBs4buHIEJsb3VzZTogNC4zOCUNCiAgKiBLaG/huqNuZyB0aW4gY+G6rXkgOTUlOiAqKlxbMy43NCU7IDUuMDMlXSoqDQogICogJHAkLXZhbHVlIGPhu6dhIGtp4buDbSDEkeG7i25oOiAqKuKJiCAwLjA4KioNCg0KKiAqKk5o4bqtbiB4w6l0OioqIFbDrCAkcCQtdmFsdWUgPiAwLjA1LCAqKmtow7RuZyBiw6FjIGLhu48gJEhfMCQqKi4gVOG7tyBs4buHIGtow6FjaCBtdWEgQmxvdXNlICoqa2jDtG5nIGtow6FjIGJp4buHdCDEkcOhbmcga+G7gyBzbyB24bubaSBnaeG6oyDEkeG7i25oIDUlKiosIHThu6ljIGzDoCAqKmdp4bqjIMSR4buLbmggYmFuIMSR4bqndSBo4bujcCBsw70qKi4NCg0KIyMjICoqQ0FURUdPUlkqKg0KDQpgYGB7cn0NCiMgxq/hu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBDbG90aGluZw0KY2F0ZWdvcnlfY291bnQgPC0gc3VtKGRhdGEkQ2F0ZWdvcnkgPT0gIkNsb3RoaW5nIikNCnByb3BfY2F0ZWdvcnkgPC0gY2F0ZWdvcnlfY291bnQgLyBuDQpzZV9jYXRlZ29yeSA8LSBzcXJ0KHByb3BfY2F0ZWdvcnkgKiAoMSAtIHByb3BfY2F0ZWdvcnkpIC8gbikNCmNpX2NhdGVnb3J5IDwtIHByb3BfY2F0ZWdvcnkgKyBjKC0xLCAxKSAqIDEuOTYgKiBzZV9jYXRlZ29yeQ0KY2F0KCJLaG/huqNuZyB0aW4gY+G6rXkgOTUlIGNobyB04bu3IGzhu4cgQ2xvdGhpbmc6Iiwgcm91bmQoY2lfY2F0ZWdvcnkgKiAxMDAsIDIpLCAiJVxuIikNCmBgYA0KDQoqICoqR2nhuqMgdGh1eeG6v3Q6KioNCg0KICAqICRIXzA6IHAgPSAwLjQkDQogICogJEhfMTogcCBcbmUgMC40JA0KDQpgYGB7cn0NCiMgS2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3QgKEgwOiBU4bu3IGzhu4cgQ2xvdGhpbmcgPSAwLjQpDQpwcm9wLnRlc3QoY2F0ZWdvcnlfY291bnQsIG4sIHAgPSAwLjQsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KYGBgDQoNCiogKipL4bq/dCBxdeG6ozoqKg0KDQogICogVOG7tyBs4buHIENsb3RoaW5nOiA0NC41NCUNCiAgKiBLaG/huqNuZyB0aW4gY+G6rXkgOTUlOiAqKlxbNDIuOTglOyA0Ni4xMCVdKioNCiAgKiAkcCQtdmFsdWUgY+G7p2Ega2nhu4NtIMSR4buLbmg6ICoqPCAwLjAwMDAwMDAxKioNCg0KKiAqKk5o4bqtbiB4w6l0OioqIFbDrCAkcCQtdmFsdWUgPCAwLjA1LCAqKmLDoWMgYuG7jyAkSF8wJCoqLiBU4bu3IGzhu4cgc+G6o24gcGjhuqltIENsb3RoaW5nICoqY2FvIGjGoW4gNDAlIG3hu5l0IGPDoWNoIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6oqKiwgY2jhu6luZyB04buPIMSRw6J5IGzDoCAqKmxv4bqhaSBow6BuZyBow7NhIGNoaeG6v20gxrB1IHRo4bq/IHRyb25nIGThu68gbGnhu4d1KiouDQoNCiMjIyAqKkxPQ0FUSU9OKioNCg0KYGBge3J9DQojIMav4bubYyBsxrDhu6NuZyBraG/huqNuZyB0aW4gY+G6rXkgOTUlIGNobyB04bu3IGzhu4cgTmV3IFlvcmsNCmxvY2F0aW9uX2NvdW50IDwtIHN1bShkYXRhJExvY2F0aW9uID09ICJOZXcgWW9yayIpDQpwcm9wX2xvY2F0aW9uIDwtIGxvY2F0aW9uX2NvdW50IC8gbg0Kc2VfbG9jYXRpb24gPC0gc3FydChwcm9wX2xvY2F0aW9uICogKDEgLSBwcm9wX2xvY2F0aW9uKSAvIG4pDQpjaV9sb2NhdGlvbiA8LSBwcm9wX2xvY2F0aW9uICsgYygtMSwgMSkgKiAxLjk2ICogc2VfbG9jYXRpb24NCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyB04buJIGzhu4cgTmV3IFlvcms6Iiwgcm91bmQoY2lfbG9jYXRpb24gKiAxMDAsIDIpLCAiJVxuIikNCmBgYA0KDQoqICoqR2nhuqMgdGh1eeG6v3Q6KioNCg0KICAqICRIXzA6IHAgPSAwLjAyJA0KICAqICRIXzE6IHAgXG5lIDAuMDIkDQoNCmBgYHtyfQ0KIyBLaeG7g20gxJHhu4tuaCBnaeG6oyB0aHV54bq/dCAoSDA6IFThu7cgbOG7hyBOZXcgWW9yayA9IDAuMDIpDQpwcm9wLnRlc3QobG9jYXRpb25fY291bnQsIG4sIHAgPSAwLjAyLCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQoqICoqS+G6v3QgcXXhuqM6KioNCg0KICAqIFThu7cgbOG7hyBraMOhY2gg4bufIE5ldyBZb3JrOiAyLjIzJQ0KICAqIEtob+G6o25nIHRpbiBj4bqteSA5NSU6ICoqXFsxLjc3JTsgMi42OSVdKioNCiAgKiAkcCQtdmFsdWUgY+G7p2Ega2nhu4NtIMSR4buLbmg6ICoq4omIIDAuMzAqKg0KDQoqICoqTmjhuq1uIHjDqXQ6KiogVsOsICRwJC12YWx1ZSA+IDAuMDUsICoqa2jDtG5nIGLDoWMgYuG7jyAkSF8wJCoqLiBU4bu3IGzhu4cga2jDoWNoIGjDoG5nIHThu6sgTmV3IFlvcmsgKipwaMO5IGjhu6NwIHbhu5tpIGdp4bqjIMSR4buLbmggMiUqKiwga2jDtG5nIGPDsyBz4buxIGtow6FjIGJp4buHdCDEkcOhbmcga+G7gy4NCg0KIyMjICoqU0laRSoqDQoNCmBgYHtyfQ0KIyDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIFNpemUgTQ0Kc2l6ZV9jb3VudCA8LSBzdW0oZGF0YSRTaXplID09ICJNIikNCnByb3Bfc2l6ZSA8LSBzaXplX2NvdW50IC8gbg0Kc2Vfc2l6ZSA8LSBzcXJ0KHByb3Bfc2l6ZSAqICgxIC0gcHJvcF9zaXplKSAvIG4pDQpjaV9zaXplIDwtIHByb3Bfc2l6ZSArIGMoLTEsIDEpICogMS45NiAqIHNlX3NpemUNCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIFNpemUgTToiLCByb3VuZChjaV9zaXplICogMTAwLCAyKSwgIiVcbiIpDQpgYGANCg0KKiAqKkdp4bqjIHRodXnhur90OioqDQoNCiAgKiAkSF8wOiBwID0gMC40JA0KICAqICRIXzE6IHAgXG5lIDAuNCQNCg0KYGBge3J9DQojIEtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IChIMDogVOG7tyBs4buHIFNpemUgTSA9IDAuNCkNCnByb3AudGVzdChzaXplX2NvdW50LCBuLCBwID0gMC40LCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQoqICoqS+G6v3QgcXXhuqM6KioNCg0KICAqIFThu7cgbOG7hyBTaXplIE06IDQ1JQ0KICAqIEtob+G6o25nIHRpbiBj4bqteSA5NSU6ICoqXFs0My40NCU7IDQ2LjU2JV0qKg0KICAqICRwJC12YWx1ZSBj4bunYSBraeG7g20gxJHhu4tuaDogKio8IDAuMDAwMDAwMDAyKioNCg0KKiAqKk5o4bqtbiB4w6l0OioqIFbDrCAkcCQtdmFsdWUgcuG6pXQgbmjhu48sICoqYsOhYyBi4buPICRIXzAkKiouIFThu7cgbOG7hyBraMOhY2ggaMOgbmcgY2jhu41uIFNpemUgTSAqKmNhbyBoxqFuIDQwJSBt4buZdCBjw6FjaCDEkcOhbmcga+G7gyoqLCB4w6FjIG5o4bqtbiDEkcOieSBsw6AgKipzaXplIHBo4buVIGJp4bq/biBuaOG6pXQqKi4NCg0KIyMjICoqU0VBU09OKioNCg0KYGBge3J9DQojIMav4bubYyBsxrDhu6NuZyBraG/huqNuZyB0aW4gY+G6rXkgOTUlIGNobyB04bu3IGzhu4cgU3ByaW5nDQpzZWFzb25fY291bnQgPC0gc3VtKGRhdGEkU2Vhc29uID09ICJTcHJpbmciKQ0KcHJvcF9zZWFzb24gPC0gc2Vhc29uX2NvdW50IC8gbg0Kc2Vfc2Vhc29uIDwtIHNxcnQocHJvcF9zZWFzb24gKiAoMSAtIHByb3Bfc2Vhc29uKSAvIG4pDQpjaV9zZWFzb24gPC0gcHJvcF9zZWFzb24gKyBjKC0xLCAxKSAqIDEuOTYgKiBzZV9zZWFzb24NCmNhdCgiS2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIFNwcmluZzoiLCByb3VuZChjaV9zZWFzb24gKiAxMDAsIDIpLCAiJVxuIikNCmBgYA0KDQoNCiogKipHaeG6oyB0aHV54bq/dDoqKg0KDQogICogJEhfMDogcCA9IDAuMjUkDQogICogJEhfMTogcCBcbmUgMC4yNSQNCg0KYGBge3J9DQojIEtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IChIMDogVOG7tyBs4buHIFNwcmluZyA9IDAuMjUpDQpwcm9wLnRlc3Qoc2Vhc29uX2NvdW50LCBuLCBwID0gMC4yNSwgY29uZi5sZXZlbCA9IDAuOTUpDQpgYGANCg0KKiAqKkvhur90IHF14bqjOioqDQoNCiAgKiBU4bu3IGzhu4cgbcO5YSBYdcOibjogMjUuNjIlDQogICogS2hv4bqjbmcgdGluIGPhuq15IDk1JTogKipcWzI0LjI1JTsgMjYuOTklXSoqDQogICogJHAkLXZhbHVlIGPhu6dhIGtp4buDbSDEkeG7i25oOiAqKuKJiCAwLjQwKioNCg0KKiAqKk5o4bqtbiB4w6l0OioqIFbDrCAkcCQtdmFsdWUgPiAwLjA1LCAqKmtow7RuZyBiw6FjIGLhu48gJEhfMCQqKi4gVOG7tyBs4buHIMSRxqFuIGjDoG5nIHRyb25nIG3DuWEgWHXDom4gKipraMO0bmcga2jDoWMgYmnhu4d0IMSRw6FuZyBr4buDIHNvIHbhu5tpIDI1JSoqLCBjaG8gdGjhuqV5ICoqcGjDom4gYuG7kSDEkcahbiBow6BuZyDEkeG7k25nIMSR4buBdSB0aGVvIG3DuWEqKi4NCg0KIyMjIFBow6JuIHTDrWNoIGPhurdwIGJp4bq/bjogU2Vhc29uIHbDoCBJdGVtLlB1cmNoYXNlZA0KQmnhur9uIMSR4buZYyBs4bqtcDogU2Vhc29uDQoNCkJp4bq/biBwaOG7pSB0aHXhu5ljOiBJdGVtLlB1cmNoYXNlZCAoY2jhu41uICJCbG91c2UiIGzDoG0gInRow6BuaCBjw7RuZyIpDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KYGBge3J9DQojIFThuqFvIGPhu5l0IG5o4buLIHBow6JuIGNobyBJdGVtLlB1cmNoYXNlZCAoQmxvdXNlID0gWSwga2jDtG5nIHBo4bqjaSBCbG91c2UgPSBOKQ0KZGF0YSRCbG91c2UgPC0gaWZlbHNlKGRhdGEkSXRlbS5QdXJjaGFzZWQgPT0gIkJsb3VzZSIsICJZIiwgIk4iKQ0KYGBgDQoNCg0KYGBge3J9DQojIFThuqFvIGLhuqNuZyB04bqnbiBz4buRDQp0bXBfc2Vhc29uIDwtIHRhYmxlKGRhdGEkU2Vhc29uLCBkYXRhJEJsb3VzZSkNCmFkZG1hcmdpbnModG1wX3NlYXNvbikNCmBgYA0KICAtICoqVOG7tyBs4buHIEJsb3VzZSoqIChk4buxYSB0csOqbiBwaMOibiB0w61jaCB0csaw4bubYyDEkcOzKToNCiAgICAgLSBGYWxsOiA0Mi85NzUgPSA0LjMxJS4NCiAgICAgLSBTcHJpbmc6IDQ2Lzk5OSA9IDQuNjAlLg0KICAgICAtIFN1bW1lcjogNDMvOTU1ID0gNC41MCUuDQogICAgIC0gV2ludGVyOiA0MC85NzEgPSA0LjEyJS4NCiAgIC0gKipOaOG6rW4geMOpdCoqOiBQaMOibiBi4buRIGPDoWMgc+G6o24gcGjhuqltLCBiYW8gZ+G7k20gKipCbG91c2UqKiwgdMawxqFuZyDEkeG7kWkgxJHhu5NuZyDEkeG7gXUgZ2nhu69hIGPDoWMgbcO5YSwgduG7m2kgdOG7tyBs4buHIH40LTUlIGNobyAqKkJsb3VzZSoqLg0KDQoNCmBgYHtyfQ0KIyBS4bunaSBybyB0xrDGoW5nIMSR4buRaSAoUmVsYXRpdmUgUmlzaykNCiMgVMOtbmggUlIgduG7m2kgWSBsw6AgQmxvdXNlLCBzbyBzw6FuaCBjw6FjIG3DuWEgduG7m2kgU3ByaW5nDQpsaWJyYXJ5KGVwaXRvb2xzKQ0KbGlicmFyeShEZXNjVG9vbHMpDQpjYXQoIlxuUuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgKFNlYXNvbiwgQmxvdXNlID0gWSk6XG4iKQ0Kcmlza3JhdGlvKHRtcF9zZWFzb24sIHJldiA9ICdjJykgICMgxJDhu5VpIGPhu5l0IMSR4buDIFkgbMOgIEJsb3VzZQ0KZXBpdGFiKHRtcF9zZWFzb24sIG1ldGhvZCA9ICdyaXNrcmF0aW8nLCByZXYgPSAnYycpDQpgYGANCg0KLSAqKkvhur90IHF14bqjKiogKHNvIHbhu5tpICoqRmFsbCoqKToNCiAgLSBTcHJpbmc6IFJSID0gMC45OTY5IFswLjk3ODEsIDEuMDE2XSwgXCggcCBcKS12YWx1ZSA9IDAuODI3NS4NCiAgLSBTdW1tZXI6IFJSID0gMC45OTgwIFswLjk3OTAsIDEuMDE3XSwgXCggcCBcKS12YWx1ZSA9IDAuOTExNy4NCiAgLSBXaW50ZXI6IFJSID0gMS4wMDIwIFswLjk4MzUsIDEuMDIxXSwgXCggcCBcKS12YWx1ZSA9IDAuOTEwMy4NCi0gKipEaeG7hW4gZ2nhuqNpKio6DQogIC0gUlIgZ+G6p24gMSBjaG8gdOG6pXQgY+G6oyBjw6FjIG3DuWEsIHbhu5tpIGtob+G6o25nIHRpbiBj4bqteSA5NSUgYmFvIGfhu5NtIDEsIGNobyB0aOG6pXkga2jDtG5nIGPDsyBz4buxIGtow6FjIGJp4buHdCDEkcOhbmcga+G7gyB24buBIHjDoWMgc3XhuqV0IG11YSAqKkJsb3VzZSoqIGdp4buvYSAqKlNwcmluZyoqLCAqKlN1bW1lcioqLCAqKldpbnRlcioqIHNvIHbhu5tpICoqRmFsbCoqLg0KICAtIFwoIHAgXCktdmFsdWUgY2FvICg+MC44KSB04burIGtp4buDbSDEkeG7i25oIEZpc2hlciAodHJvbmcgYGVwaXRhYigpYCkgeMOhYyBuaOG6rW4ga2jDtG5nIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6osIHBow7kgaOG7o3AgduG7m2kgdOG7tyBs4buHIMSR4buTbmcgxJHhu4F1ICh+NC01JSkuDQotICoqTmjhuq1uIHjDqXQqKjoNCiAgLSBL4bq/dCBxdeG6oyBSUiBuaOG6pXQgcXXDoW4gduG7m2kgcGjDom4gdMOtY2ggdHLGsOG7m2MgxJHDsyAoZMO5bmcgKipGYWxsKiogbMOgbSB0aGFtIGNoaeG6v3UpLCBjaG8gdGjhuqV5IGjDoG5oIHZpIG11YSAqKkJsb3VzZSoqIGtow7RuZyBwaOG7pSB0aHXhu5ljIMSRw6FuZyBr4buDIHbDoG8gbcO5YS4NCiAgLSBWaeG7h2Mgc+G7rSBk4bulbmcgKipTcHJpbmcqKiB0cm9uZyBjaMO6IHRow61jaCBuaMawbmcgKipGYWxsKiogdHJvbmcga+G6v3QgcXXhuqMgZ8OieSBuaOG6p20gbOG6q24sIGPhuqduIHPhu61hIMSR4buDIMSR4bqjbSBi4bqjbyB0w61uaCByw7UgcsOgbmcuDQoNCmBgYHtyfQ0KIyBU4bu3IGzhu4cgY2jDqm5oIChPZGRzIFJhdGlvKQ0KIyBUw61uaCBPUiB24bubaSBZIGzDoCBCbG91c2UsIHNvIHPDoW5oIGPDoWMgbcO5YSB24bubaSBTcHJpbmcNCmNhdCgiXG5U4bu3IGzhu4cgY2jDqm5oIChTZWFzb24sIEJsb3VzZSA9IFkpOlxuIikNCm9kZHNyYXRpbyh0bXBfc2Vhc29uLCByZXYgPSAnYycpDQplcGl0YWIodG1wX3NlYXNvbiwgbWV0aG9kID0gJ29kZHNyYXRpbycsIHJldiA9ICdjJykNCmBgYA0KDQotICoqS+G6v3QgcXXhuqMqKiAoc28gduG7m2kgKipGYWxsKiopOg0KICAtIFNwcmluZzogT1IgPSAwLjkzMjkgWzAuNjA1OCwgMS40MzNdLCBcKCBwIFwpLXZhbHVlID0gMC44Mjc1Lg0KICAtIFN1bW1lcjogT1IgPSAwLjk1NDkgWzAuNjE2MiwgMS40NzldLCBcKCBwIFwpLXZhbHVlID0gMC45MTE3Lg0KICAtIFdpbnRlcjogT1IgPSAxLjA0NzUgWzAuNjcxNSwgMS42MzZdLCBcKCBwIFwpLXZhbHVlID0gMC45MTAzLg0KLSAqKkRp4buFbiBnaeG6o2kqKjoNCiAgLSBPUiBjxaluZyBn4bqnbiAxLCB24bubaSBraG/huqNuZyB0aW4gY+G6rXkgOTUlIGJhbyBn4buTbSAxLCBjaG8gdGjhuqV5IGtow7RuZyBjw7Mgc+G7sSBraMOhYyBiaeG7h3QgxJHDoW5nIGvhu4MgduG7gSB04bu3IGzhu4cgY8aw4bujYyBtdWEgKipCbG91c2UqKiBnaeG7r2EgY8OhYyBtw7lhIHNvIHbhu5tpICoqRmFsbCoqLg0KICAtIFwoIHAgXCktdmFsdWUgY2FvICg+MC44KSB04burIGtp4buDbSDEkeG7i25oIEZpc2hlciBuaOG6pXQgcXXDoW4gduG7m2kgUlIsIHjDoWMgbmjhuq1uIGtow7RuZyBjw7MgbeG7kWkgcXVhbiBo4buHIMSRw6FuZyBr4buDLg0KLSAqKk5o4bqtbiB4w6l0Kio6DQogIC0gT1IgaOG7lyB0cuG7oyBr4bq/dCBsdeG6rW4gdOG7qyBSUiwgY2hvIHRo4bqleSBraMO0bmcgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IHRo4buRbmcga8OqIGdp4buvYSBjw6FjIG3DuWEgdHJvbmcgdmnhu4djIG11YSAqKkJsb3VzZSoqLg0KICAtIEtob+G6o25nIHRpbiBj4bqteSBj4bunYSBPUiBy4buZbmcgaMahbiBSUiAoZG8gdOG7tyBs4buHIGPGsOG7o2MgbmjhuqF5IGjGoW4gduG7m2kgYmnhur9uIMSR4buZbmcgdOG7tyBs4buHIG5o4buPKSwgbmjGsG5nIHbhuqtuIGJhbyBn4buTbSAxLCBwaMO5IGjhu6NwIHbhu5tpIGThu68gbGnhu4d1Lg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIyBQaMOibiB0w61jaCBj4bq3cCBiaeG6v246IEdlbmRlciB2w6AgU2l6ZQ0KQmnhur9uIMSR4buZYyBs4bqtcDogR2VuZGVyDQoNCkJp4bq/biBwaOG7pSB0aHXhu5ljOiBTaXplIChjaOG7jW4gIk0iIGzDoG0gInRow6BuaCBjw7RuZyIpDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmBgYHtyfQ0KIyBU4bqhbyBj4buZdCBuaOG7iyBwaMOibiBjaG8gU2l6ZSAoTSA9IFksIGtow7RuZyBwaOG6o2kgTSA9IE4pDQpkYXRhJFNpemVfTSA8LSBpZmVsc2UoZGF0YSRTaXplID09ICJNIiwgIlkiLCAiTiIpDQpgYGANCg0KDQpgYGB7cn0NCiMgVOG6oW8gYuG6o25nIHThuqduIHPhu5ENCnRtcF9nZW5kZXIgPC0gdGFibGUoZGF0YSRHZW5kZXIsIGRhdGEkU2l6ZV9NKQ0KYWRkbWFyZ2lucyh0bXBfZ2VuZGVyKQ0KYGBgDQoNCiAgIC0gKipU4bu3IGzhu4cgY2jhu41uIFNpemUgTSoqOg0KICAgICAtICoqRmVtYWxlKio6IDU5MC8xMjQ4ID0gNDcuMjglLg0KICAgICAtICoqTWFsZSoqOiAxMTY1LzI2NTIgPSA0My45MyUuDQoNCg0KYGBge3J9DQojIFLhu6dpIHJvIHTGsMahbmcgxJHhu5FpIChSZWxhdGl2ZSBSaXNrKQ0KIyBUw61uaCBSUiB24bubaSBZIGzDoCBTaXplIE0sIHNvIHPDoW5oIE1hbGUgduG7m2kgRmVtYWxlDQpjYXQoIlxuUuG7p2kgcm8gdMawxqFuZyDEkeG7kWkgKEdlbmRlciwgU2l6ZSBNID0gWSk6XG4iKQ0Kcmlza3JhdGlvKHRtcF9nZW5kZXIsIHJldiA9ICdjJykgICMgxJDhu5VpIGPhu5l0IMSR4buDIFkgbMOgIFNpemUgTQ0KZXBpdGFiKHRtcF9nZW5kZXIsIG1ldGhvZCA9ICdyaXNrcmF0aW8nLCByZXYgPSAnYycpDQpgYGANCg0KICAtIFJSIChNYWxlIHNvIHbhu5tpIEZlbWFsZSk6IDEuMDYzIFswLjk5OTEsIDEuMTMyXSwgXCggcCBcKS12YWx1ZSA9IDAuMDUzMzQuDQogICAtICoqRGnhu4VuIGdp4bqjaSoqOg0KICAgICAtIFJSID0gMS4wNjMgY2hvIHRo4bqleSAqKk1hbGUqKiBjw7MgeMOhYyBzdeG6pXQgY2jhu41uICoqU2l6ZSBNKiogY2FvIGjGoW4gKipGZW1hbGUqKiBraG/huqNuZyA2LjMlLCBuaMawbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSAoMC45OTkxLCAxLjEzMikgYmFvIGfhu5NtIGdpw6EgdHLhu4sgMSwgdsOgIFwoIHAgXCktdmFsdWUgPSAwLjA1MzM0ICg+MC4wNSksIG7Dqm4ga2jDtG5nIMSR4bunIGLhurFuZyBjaOG7qW5nIMSR4buDIGvhur90IGx14bqtbiBz4buxIGtow6FjIGJp4buHdCBsw6AgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiDhu58gbeG7qWMgXChcYWxwaGEgPSAwLjA1XCkuDQogICAgIC0gS+G6v3QgcXXhuqMgdOG7qyBgZXBpdGFiKG1ldGhvZCA9ICdyaXNrcmF0aW8nKWAgbmjhuqV0IHF1w6FuIHbhu5tpIGByaXNrcmF0aW8oKWAsIHPhu60gZOG7pW5nIGtp4buDbSDEkeG7i25oIEZpc2hlciDEkeG7gyB0w61uaCBcKCBwIFwpLXZhbHVlLg0KDQpgYGB7cn0NCiMgVOG7tyBs4buHIGNow6puaCAoT2RkcyBSYXRpbykNCiMgVMOtbmggT1IgduG7m2kgWSBsw6AgU2l6ZSBNLCBzbyBzw6FuaCBNYWxlIHbhu5tpIEZlbWFsZQ0KY2F0KCJcblThu7cgbOG7hyBjaMOqbmggKEdlbmRlciwgU2l6ZSBNID0gWSk6XG4iKQ0Kb2Rkc3JhdGlvKHRtcF9nZW5kZXIsIHJldiA9ICdjJykNCmVwaXRhYih0bXBfZ2VuZGVyLCBtZXRob2QgPSAnb2Rkc3JhdGlvJywgcmV2ID0gJ2MnKQ0KYGBgDQoNCiAgIC0gT1IgKE1hbGUgc28gduG7m2kgRmVtYWxlKTogMS4xNDQgWzAuOTk5OSwgMS4zMV0sIFwoIHAgXCktdmFsdWUgPSAwLjA1MzM0Lg0KICAgLSAqKkRp4buFbiBnaeG6o2kqKjoNCiAgICAgLSBPUiA9IDEuMTQ0IGNobyB0aOG6pXkgdOG7tyBs4buHIGPGsOG7o2MgY2jhu41uICoqU2l6ZSBNKiogY+G7p2EgKipNYWxlKiogY2FvIGjGoW4gKipGZW1hbGUqKiBraG/huqNuZyAxNC40JSwgbmjGsG5nIGtob+G6o25nIHRpbiBj4bqteSA5NSUgKDAuOTk5OSwgMS4zMSkgc8OhdCB24bubaSAxLCB2w6AgXCggcCBcKS12YWx1ZSA9IDAuMDUzMzQgKD4wLjA1KSwgbsOqbiBz4buxIGtow6FjIGJp4buHdCBraMO0bmcgxJHhuqF0IMO9IG5naMSpYSB0aOG7kW5nIGvDqi4NCiAgICAgLSBL4bq/dCBxdeG6oyB04burIGBlcGl0YWIobWV0aG9kID0gJ29kZHNyYXRpbycpYCBuaOG6pXQgcXXDoW4gduG7m2kgYG9kZHNyYXRpbygpYCwgc+G7rSBk4bulbmcgcGjGsMahbmcgcGjDoXAgIm1lZGlhbi11bmJpYXNlZCBlc3RpbWF0ZSIgdsOgIGtp4buDbSDEkeG7i25oIEZpc2hlci4NCg0KIEtp4buDbSDEkeG7i25oIENoaS1iw6xuaCBwaMawxqFuZzogU2Vhc29uIHbDoCBJdGVtLlB1cmNoYXNlZA0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpgYGB7cn0NCiMgVOG6oW8gYuG6o25nIHThuqduIHPhu5EgY2jDqW8NCnRhYmxlX3NlYXNvbl9pdGVtIDwtIHRhYmxlKGRhdGEkU2Vhc29uLCBkYXRhJEl0ZW0uUHVyY2hhc2VkKQ0KY2F0KCJcbkLhuqNuZyB04bqnbiBz4buRIGNow6lvOiBTZWFzb24gdsOgIEl0ZW0uUHVyY2hhc2VkXG4iKQ0KcHJpbnQoYWRkbWFyZ2lucyh0YWJsZV9zZWFzb25faXRlbSkpDQpgYGANCg0KDQpgYGB7cn0NCiMgS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nDQpjaGlfc2Vhc29uX2l0ZW0gPC0gY2hpc3EudGVzdCh0YWJsZV9zZWFzb25faXRlbSkNCmNhdCgiXG5LaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmc6IFNlYXNvbiB2w6AgSXRlbS5QdXJjaGFzZWRcbiIpDQpwcmludChjaGlfc2Vhc29uX2l0ZW0pDQpgYGANCg0KICAgIC0gKipL4bq/dCBxdeG6oyoqOg0KICAgICAtIFwoXGNoaV4yID0gNzhcKSwgYuG6rWMgdOG7sSBkbyAoXCggZGYgXCkpID0gNzIsIFwoIHAgXCktdmFsdWUgPSAwLjMuDQogICAtICoqRGnhu4VuIGdp4bqjaSoqOg0KICAgICAtIFwoIHAgXCktdmFsdWUgPSAwLjMgKD4wLjA1KSwga2jDtG5nIGLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCBcKCBIXzAgXCksIGNobyB0aOG6pXkga2jDtG5nIGPDsyBt4buRaSBxdWFuIGjhu4cgxJHDoW5nIGvhu4MgZ2nhu69hICoqU2Vhc29uKiogdsOgICoqSXRlbS5QdXJjaGFzZWQqKi4NCiAgICAgLSBL4bq/dCBxdeG6oyBuw6B5IG5o4bqldCBxdcOhbiB24bubaSBwaMOibiB0w61jaCBSUiB2w6AgT1IgdHLGsOG7m2MgxJHDsyAoY2hvIGJp4bq/biBuaOG7iyBwaMOibiAqKkJsb3VzZSoqKSwgduG7m2kgUlIgdsOgIE9SIGfhuqduIDEgdsOgIFwoIHAgXCktdmFsdWUgY2FvICg+MC44KSwgY2hvIHRo4bqleSBraMO0bmcgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IMSRw6FuZyBr4buDIHbhu4EgeMOhYyBzdeG6pXQgbXVhICoqQmxvdXNlKiogZ2nhu69hIGPDoWMgbcO5YS4NCg0KDQoNCg0K