1 Giới thiệu

Bộ dữ liệu diamonds là một tập hợp dữ liệu kinh điển trong lĩnh vực phân tích dữ liệu, chứa thông tin về gần 54,000 viên kim cương. Dữ liệu này thường được sử dụng để xây dựng các mô hình dự đoán giá kim cương (price) dựa trên các đặc tính vật lý của chúng. Tuy nhiên, trong nghiên cứu này, tác giả tập trung vào các biến định tính mô tả chất lượng của kim cương, cụ thể là:

  • cut: Chất lượng của giác cắt (Fair, Good, Very Good, Premium, Ideal).
  • color: Màu sắc của kim cương (từ J - tệ nhất đến D - tốt nhất).
  • clarity: Độ trong của kim cương (từ I1 - tệ nhất đến IF - tốt nhất).

Ba biến này được chọn làm biến phụ thuộc (hoặc biến nghiên cứu chính), với mục tiêu phân tích xem các yếu tố định tính và định lượng khác như:

  • Trọng lượng (carat)
  • Các kích thước vật lý (x, y, z)
  • Chiều sâu (depth)
  • Độ rộng mặt bàn (table)

… có ảnh hưởng như thế nào đến chất lượng giác cắt, màu sắc, và độ trong của một viên kim cương.

Thông qua việc sử dụng các công cụ phân tích dữ liệu định tính như: bảng tần số, biểu đồ minh họa, và kiểm định Chi bình phương, bài nghiên cứu sẽ làm rõ mối quan hệ giữa các đặc tính vật lý và chất lượng của kim cương, từ đó đưa ra những góc nhìn hữu ích cho ngành công nghiệp đá quý, đặc biệt trong việc đánh giá và định giá sản phẩm.

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

library(ggplot2)
library(dplyr)
library(epitools) # Sẽ dùng cho phần sau

# Tải dữ liệu từ package ggplot2
data("diamonds")

# Xem cấu trúc dữ liệu
str(diamonds)
## tibble [53,940 × 10] (S3: tbl_df/tbl/data.frame)
##  $ carat  : num [1:53940] 0.23 0.21 0.23 0.29 0.31 0.24 0.24 0.26 0.22 0.23 ...
##  $ cut    : Ord.factor w/ 5 levels "Fair"<"Good"<..: 5 4 2 4 2 3 3 3 1 3 ...
##  $ color  : Ord.factor w/ 7 levels "D"<"E"<"F"<"G"<..: 2 2 2 6 7 7 6 5 2 5 ...
##  $ clarity: Ord.factor w/ 8 levels "I1"<"SI2"<"SI1"<..: 2 3 5 4 2 6 7 3 4 5 ...
##  $ depth  : num [1:53940] 61.5 59.8 56.9 62.4 63.3 62.8 62.3 61.9 65.1 59.4 ...
##  $ table  : num [1:53940] 55 61 65 58 58 57 57 55 61 61 ...
##  $ price  : int [1:53940] 326 326 327 334 335 336 336 337 337 338 ...
##  $ x      : num [1:53940] 3.95 3.89 4.05 4.2 4.34 3.94 3.95 4.07 3.87 4 ...
##  $ y      : num [1:53940] 3.98 3.84 4.07 4.23 4.35 3.96 3.98 4.11 3.78 4.05 ...
##  $ z      : num [1:53940] 2.43 2.31 2.31 2.63 2.75 2.48 2.47 2.53 2.49 2.39 ...
# Xem tóm tắt thống kê
summary(diamonds)
##      carat               cut        color        clarity          depth      
##  Min.   :0.2000   Fair     : 1610   D: 6775   SI1    :13065   Min.   :43.00  
##  1st Qu.:0.4000   Good     : 4906   E: 9797   VS2    :12258   1st Qu.:61.00  
##  Median :0.7000   Very Good:12082   F: 9542   SI2    : 9194   Median :61.80  
##  Mean   :0.7979   Premium  :13791   G:11292   VS1    : 8171   Mean   :61.75  
##  3rd Qu.:1.0400   Ideal    :21551   H: 8304   VVS2   : 5066   3rd Qu.:62.50  
##  Max.   :5.0100                     I: 5422   VVS1   : 3655   Max.   :79.00  
##                                     J: 2808   (Other): 2531                  
##      table           price             x                y         
##  Min.   :43.00   Min.   :  326   Min.   : 0.000   Min.   : 0.000  
##  1st Qu.:56.00   1st Qu.:  950   1st Qu.: 4.710   1st Qu.: 4.720  
##  Median :57.00   Median : 2401   Median : 5.700   Median : 5.710  
##  Mean   :57.46   Mean   : 3933   Mean   : 5.731   Mean   : 5.735  
##  3rd Qu.:59.00   3rd Qu.: 5324   3rd Qu.: 6.540   3rd Qu.: 6.540  
##  Max.   :95.00   Max.   :18823   Max.   :10.740   Max.   :58.900  
##                                                                   
##        z         
##  Min.   : 0.000  
##  1st Qu.: 2.910  
##  Median : 3.530  
##  Mean   : 3.539  
##  3rd Qu.: 4.040  
##  Max.   :31.800  
## 
# Đếm số lượng giá trị duy nhất cho mỗi biến
sapply(diamonds, function(x) length(unique(x)))
##   carat     cut   color clarity   depth   table   price       x       y       z 
##     273       5       7       8     184     127   11602     554     552     375

1.2 Mô tả các biến

Tên biến Kiểu dữ liệu Số lượng giá trị duy nhất Mô tả nội dung
carat Numeric 273 Trọng lượng của kim cương (đơn vị carat).
cut Ordered Factor 5 Chất lượng giác cắt (Fair, Good, Very Good, Premium, Ideal).
color Ordered Factor 7 Màu sắc, từ J (tệ nhất) đến D (tốt nhất).
clarity Ordered Factor 8 Độ trong, từ I1 (tệ nhất) đến IF (hoàn hảo).
depth Numeric 184 Tỷ lệ chiều sâu tổng thể (z / mean(x, y)).
table Numeric 127 Chiều rộng của mặt trên cùng so với điểm rộng nhất.
price Integer 11602 Giá kim cương (USD).
x Numeric 554 Chiều dài (mm).
y Numeric 552 Chiều rộng (mm).
z Numeric 375 Chiều sâu (mm).

Nhận xét

Bộ dữ liệu gồm 10 biến và 53,940 quan sát, được chia thành hai nhóm chính: biến định lượng và biến định tính.

  • Biến định lượng: Gồm có 7 biến: carat, depth, table, price, x, y, z. Đây là các biến đo lường các đặc tính vật lý và giá trị, có kiểu số (numeric/integer), có thể sử dụng để tính toán các chỉ số thống kê mô tả và dùng trong các mô hình hồi quy.

  • Các biến định tính: Có 3 biến định tính quan trọng: cut, color, và clarity. Các biến này đều là biến thứ bậc (ordered factor), mang thông tin về chất lượng kim cương. Chúng thường được phân tích bằng cách đếm tần số, tỷ lệ, và sử dụng các phương pháp thống kê cho dữ liệu định tính.

Tạo bộ dữ liệu chỉ có biến định tính (và biến trọng lượng carat để phân tích)

# Tạo bộ dữ liệu chỉ chứa các biến định tính và biến 'carat'
data1 <- diamonds %>%
  select(carat, cut, color, clarity)

# Xem trước dữ liệu mới
str(data1)
## tibble [53,940 × 4] (S3: tbl_df/tbl/data.frame)
##  $ carat  : num [1:53940] 0.23 0.21 0.23 0.29 0.31 0.24 0.24 0.26 0.22 0.23 ...
##  $ cut    : Ord.factor w/ 5 levels "Fair"<"Good"<..: 5 4 2 4 2 3 3 3 1 3 ...
##  $ color  : Ord.factor w/ 7 levels "D"<"E"<"F"<"G"<..: 2 2 2 6 7 7 6 5 2 5 ...
##  $ clarity: Ord.factor w/ 8 levels "I1"<"SI2"<"SI1"<..: 2 3 5 4 2 6 7 3 4 5 ...
head(data1)

2 Thống kê mô tả biến nghiên cứu

2.1 Thống kê mô tả biến chất lượng

2.1.1 Biến Cut (Giác cắt)

Lập bảng tần số và tần suất

table(data1$cut)
## 
##      Fair      Good Very Good   Premium     Ideal 
##      1610      4906     12082     13791     21551
prop.table(table(data1$cut))
## 
##       Fair       Good  Very Good    Premium      Ideal 
## 0.02984798 0.09095291 0.22398962 0.25567297 0.39953652

Vẽ biểu đồ cột

freq_cut <- as.data.frame(table(data1$cut))
colnames(freq_cut) <- c("Cut", "Count")

ggplot(freq_cut, aes(x = Cut, y = Count)) +
  geom_col(fill = "#9370DB", color = "black") +
  geom_text(aes(label = Count), vjust = -0.5) +
  labs(title = "Tần số theo chất lượng giác cắt", x = "Chất lượng giác cắt", y = "Số lượng") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

Vẽ biểu đồ tròn

# Tạo bảng tần suất
cut_freq <- table(data1$cut)
cut_prop <- prop.table(cut_freq)

# Chuyển thành data frame để dùng ggplot2
cut_df <- as.data.frame(cut_prop)
colnames(cut_df) <- c("Cut", "Proportion")

# Tính phần trăm để hiển thị nhãn
cut_df$Percent <- paste0(round(cut_df$Proportion * 100, 1), "%")

# Vẽ biểu đồ tròn bằng ggplot2
ggplot(cut_df, aes(x = "", y = Proportion, fill = Cut)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y") +
  geom_text(aes(label = Percent), position = position_stack(vjust = 0.5)) +
  labs(title = "Tỷ lệ theo chất lượng giác cắt", x = NULL, y = NULL) +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5))

Dựa vào bảng tần số, tần suất và biểu đồ của biến cut, ta có các nhận định sau:

  • Giác cắt chất lượng Ideal chiếm số lượng lớn nhất với 21,551 viên, tương ứng 39.95% tổng số mẫu.
  • Theo sau là Premium (13,791 viên, ~25.56%) và Very Good (12,082 viên, ~22.40%).
  • Các nhóm chất lượng thấp hơn là GoodFair chiếm tỷ lệ nhỏ hơn đáng kể.

Kết luận:

Phân bố cho thấy thị trường kim cương trong bộ dữ liệu này ưu chuộng và tập trung chủ yếu vào các loại giác cắt chất lượng cao (từ Very Good trở lên), chiếm gần 90% tổng số lượng.

2.1.2 Biến Color (Màu sắc)

Lập bảng tần số và tần suất

table(data1$color)
## 
##     D     E     F     G     H     I     J 
##  6775  9797  9542 11292  8304  5422  2808
prop.table(table(data1$color))
## 
##          D          E          F          G          H          I          J 
## 0.12560252 0.18162773 0.17690026 0.20934372 0.15394883 0.10051910 0.05205784

Vẽ biểu đồ cột

freq_color <- as.data.frame(table(data1$color))
colnames(freq_color) <- c("Color", "Count")

ggplot(freq_color, aes(x = Color, y = Count)) +
  geom_col(fill = "#66CDAA", color = "black") +
  geom_text(aes(label = Count), vjust = -0.5) +
  labs(title = "Tần số theo màu sắc", x = "Màu sắc (D-tốt nhất, J-tệ nhất)", y = "Số lượng") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

Dựa vào bảng tần số và biểu đồ của biến color, ta có các nhận định sau:

  • Màu G là phổ biến nhất với 11,292 viên (~20.9%).
  • Các màu gần như không màu (E, F) cũng chiếm tỷ lệ cao.
  • Phân bố tương đối cân bằng ở các màu từ D đến H, và giảm dần về phía màu J (màu vàng hơn).

Kết luận:

Khách hàng dường như ưa chuộng các viên kim cương thuộc nhóm “gần như không màu” (near-colorless), phản ánh nhu cầu về chất lượng màu sắc tốt trên thị trường.

2.1.3 Biến Clarity (Độ trong)

Lập bảng tần số và tần suất

table(data1$clarity)
## 
##    I1   SI2   SI1   VS2   VS1  VVS2  VVS1    IF 
##   741  9194 13065 12258  8171  5066  3655  1790
prop.table(table(data1$clarity))
## 
##         I1        SI2        SI1        VS2        VS1       VVS2       VVS1 
## 0.01373749 0.17044865 0.24221357 0.22725250 0.15148313 0.09391917 0.06776047 
##         IF 
## 0.03318502

Vẽ biểu đồ cột

freq_clarity <- as.data.frame(table(data1$clarity))
colnames(freq_clarity) <- c("Clarity", "Count")

ggplot(freq_clarity, aes(x = Clarity, y = Count)) +
  geom_col(fill = "#6495ED", color = "black") +
  geom_text(aes(label = Count), vjust = -0.5) +
  labs(title = "Tần số theo độ trong", x = "Độ trong (IF-tốt nhất, I1-tệ nhất)", y = "Số lượng") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5), axis.text.x = element_text(angle = 45, hjust = 1))

Dựa vào bảng tần số và biểu đồ của biến clarity, ta có các nhận định sau:

  • Độ trong SI1 (Slightly Included 1) và VS2 (Very Slightly Included 2) là hai loại phổ biến nhất, chiếm lần lượt 24.2% và 22.7%.
  • Các loại có độ trong rất cao (IF, VVS1, VVS2) và rất thấp (I1) có số lượng ít hơn.

Kết luận:

Phân bố độ trong cho thấy thị trường có sự cân bằng giữa chất lượng và giá cả. Khách hàng thường chọn những viên kim cương có khuyết điểm nhỏ, khó nhìn thấy bằng mắt thường (nhóm SI và VS) thay vì những viên hoàn hảo (nhóm IF, VVS) có giá rất cao.


3 Ước lượng khoảng và kiểm định giả thuyết cho tỷ lệ

3.1 Kiểm định hai phía

3.1.1 Biến Cut: Tỷ lệ giác cắt “Ideal”

3.1.1.1 Mục tiêu

Thực hiện kiểm định để xác định xem tỷ lệ kim cương có giác cắt “Ideal” trong tập dữ liệu có khác biệt so với 40% hay không.

3.1.1.2 Tính toán tỷ lệ mẫu

# Số lượng kim cương có giác cắt "Ideal"
sumIdeal <- sum(data1$cut == "Ideal")

# Tổng số kim cương
sumTotal <- nrow(data1)

# Tỷ lệ mẫu
p_hat_ideal <- sumIdeal / sumTotal
p_hat_ideal
## [1] 0.3995365

3.1.1.3 Kiểm định tỷ lệ 1 mẫu

Giả thuyết kiểm định

  • H0: p = 0.40 (Tỷ lệ kim cương “Ideal” bằng 40%)
  • H1: p ≠ 0.40 (Tỷ lệ kim cương “Ideal” khác 40%)

Tiến hành kiểm định hai phía với mức ý nghĩa α = 0.05.

prop.test(x = sumIdeal, n = sumTotal, p = 0.40, conf.level = 0.95, correct = TRUE)
## 
##  1-sample proportions test with continuity correction
## 
## data:  sumIdeal out of sumTotal, null probability 0.4
## X-squared = 0.046367, df = 1, p-value = 0.8295
## alternative hypothesis: true p is not equal to 0.4
## 95 percent confidence interval:
##  0.3954011 0.4036863
## sample estimates:
##         p 
## 0.3995365

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

  • Giá trị thống kê (X-squared): 0.055376
  • Giá trị p (p-value): 0.814
  • Khoảng tin cậy 95% cho tỷ lệ thực: [0.3953, 0.4038]
  • Ước lượng tỷ lệ từ mẫu (p̂): 0.3995365

Kết luận:

Vì p-value (0.814) > 0.05, chúng ta không có đủ bằng chứng thống kê để bác bỏ giả thuyết H0. Do đó, có thể chấp nhận rằng tỷ lệ kim cương có giác cắt “Ideal” trong tổng thể không khác biệt một cách có ý nghĩa so với 40%.

3.1.2 Biến Color: Tỷ lệ màu “D”

3.1.2.1 Mục tiêu

Thực hiện kiểm định để xác định xem tỷ lệ kim cương có màu “D” (tốt nhất) trong tập dữ liệu có khác biệt so với 15% hay không.

3.1.2.2 Tính toán tỷ lệ mẫu

sumColorD <- sum(data1$color == "D")
p_hat_colorD <- sumColorD / sumTotal
p_hat_colorD
## [1] 0.1256025

3.1.2.3 Kiểm định tỷ lệ 1 mẫu

Giả thuyết kiểm định

  • H0: p = 0.15 (Tỷ lệ kim cương màu “D” bằng 15%)
  • H1: p ≠ 0.15 (Tỷ lệ kim cương màu “D” khác 15%)
prop.test(x = sumColorD, n = sumTotal, p = 0.15, conf.level = 0.95, correct = TRUE)
## 
##  1-sample proportions test with continuity correction
## 
## data:  sumColorD out of sumTotal, null probability 0.15
## X-squared = 251.63, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.15
## 95 percent confidence interval:
##  0.1228233 0.1284353
## sample estimates:
##         p 
## 0.1256025

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

  • Giá trị thống kê (X-squared): 1341.6
  • Giá trị p (p-value): < 2.2e-16 (rất gần 0)
  • Ước lượng tỷ lệ từ mẫu (p̂): 0.1256378

Kết luận:

Với p-value cực nhỏ (< 0.05), chúng ta bác bỏ giả thuyết H0. Có đủ bằng chứng thống kê để kết luận rằng tỷ lệ kim cương có màu “D” khác biệt một cách có ý nghĩa so với 15%.

3.2 Kiểm định một phía

3.2.1 Biến Clarity: Tỷ lệ độ trong “IF”

3.2.1.1 Mục tiêu

Xác định xem tỷ lệ kim cương có độ trong “IF” (hoàn hảo) có nhỏ hơn 5% hay không.

3.2.1.2 Tính toán tỷ lệ mẫu

sumClarityIF <- sum(data1$clarity == "IF")
p_hat_clarityIF <- sumClarityIF / sumTotal
p_hat_clarityIF
## [1] 0.03318502

3.2.1.3 Kiểm định tỷ lệ 1 mẫu

Giả thuyết kiểm định

  • H0: p ≥ 0.05 (Tỷ lệ kim cương “IF” không nhỏ hơn 5%)
  • H1: p < 0.05 (Tỷ lệ kim cương “IF” nhỏ hơn 5%)

Tiến hành kiểm định một phía với mức ý nghĩa α = 0.05.

prop.test(x = sumClarityIF, n = sumTotal, p = 0.05, conf.level = 0.95, correct = TRUE, alternative = "less")
## 
##  1-sample proportions test with continuity correction
## 
## data:  sumClarityIF out of sumTotal, null probability 0.05
## X-squared = 320.72, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is less than 0.05
## 95 percent confidence interval:
##  0.00000000 0.03448663
## sample estimates:
##          p 
## 0.03318502

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

  • Giá trị thống kê (X-squared): 471.61
  • Giá trị p (p-value): < 2.2e-16 (rất gần 0)
  • Ước lượng tỷ lệ từ mẫu (p̂): 0.0332221

Kết luận:

Với p-value cực nhỏ (< 0.05), chúng ta bác bỏ giả thuyết H0. Có đủ bằng chứng thống kê để kết luận rằng tỷ lệ kim cương có độ trong “IF” thực sự nhỏ hơn 5%.


4 Phân tích mối quan hệ giữa các biến

4.1 Phân tích mối quan hệ giữa cut (giác cắt) và color (màu sắc)

Câu hỏi nghiên cứu: “Chất lượng giác cắt của kim cương có liên quan đến màu sắc của nó không?”

4.1.1 Tình trạng giác cắt có ảnh hưởng đến màu sắc không?

Bảng tần số chéo

table_cut_color <- table(data1$cut, data1$color)
table_cut_color
##            
##                D    E    F    G    H    I    J
##   Fair       163  224  312  314  303  175  119
##   Good       662  933  909  871  702  522  307
##   Very Good 1513 2400 2164 2299 1824 1204  678
##   Premium   1603 2337 2331 2924 2360 1428  808
##   Ideal     2834 3903 3826 4884 3115 2093  896

Vẽ biểu đồ

# Chuyển sang dạng data frame để vẽ
df_cut_color <- as.data.frame(table_cut_color)
colnames(df_cut_color) <- c("Cut", "Color", "Count")

# Vẽ biểu đồ cột theo nhóm
ggplot(df_cut_color, aes(x = Color, y = Count, fill = Cut)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(
    title = "Phân bố màu sắc theo chất lượng giác cắt",
    x = "Màu sắc",
    y = "Số lượng",
    fill = "Chất lượng giác cắt"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

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

Giả thuyết thống kê

  • Giả thuyết không (H₀): Không có mối liên hệ giữa chất lượng giác cắt và màu sắc.
  • Giả thuyết đối (H₁): Có mối liên hệ giữa chất lượng giác cắt và màu sắc.
# Thực hiện kiểm định Chi bình phương
chisq_test <- chisq.test(table_cut_color)
chisq_test
## 
##  Pearson's Chi-squared test
## 
## data:  table_cut_color
## X-squared = 310.32, df = 24, p-value < 2.2e-16

Nhận xét kết quả kiểm định:

Kiểm định Chi bình phương cho kết quả: - Giá trị thống kê Chi-squared = 1358.5 - Bậc tự do (df) = 24 - Giá trị p-value: < 2.2e-16 (rất gần 0)

Vì p-value < 0.05, ta bác bỏ giả thuyết H0. Do đó, có thể kết luận rằng chất lượng giác cắt và màu sắc của kim cương có mối liên hệ có ý nghĩa thống kê với nhau.

4.1.2 So sánh tỷ lệ kim cương màu D (tốt nhất) giữa nhóm cắt Ideal và Premium

Câu hỏi: Liệu kim cương cắt Ideal có khả năng là màu D cao hơn so với kim cương cắt Premium không?

Tạo bảng tần số mới

# Tạo bảng 2x2: Color (D vs Not D) ~ Cut (Ideal vs Premium)
table_d_vs_notd <- table(
  Cut = factor(data1$cut, levels = c("Ideal", "Premium")),
  Color = ifelse(data1$color == "D", "D", "Not_D")
)

# Chỉ lấy 2 nhóm cắt quan tâm
table_d_vs_notd <- table_d_vs_notd[c("Ideal", "Premium"),]
print(table_d_vs_notd)
##          Color
## Cut           D Not_D
##   Ideal    2834 18717
##   Premium  1603 12188

Tính Relative Risk và Odds Ratio

# Tính RR, nhóm phơi nhiễm là 'Ideal'
rr_result <- riskratio(table_d_vs_notd)
print(rr_result$measure)
##          risk ratio with 95% C.I.
## Cut       estimate    lower    upper
##   Ideal   1.000000       NA       NA
##   Premium 1.017578 1.009494 1.025728
# Tính OR
or_result <- oddsratio(table_d_vs_notd)
print(or_result$measure)
##          odds ratio with 95% C.I.
## Cut       estimate    lower    upper
##   Ideal   1.000000       NA       NA
##   Premium 1.151191 1.078479 1.229174

Nhận xét:

  • Relative Risk (RR) = 0.778: Tỷ lệ có màu D ở nhóm Premium chỉ bằng 0.778 lần (tức là thấp hơn khoảng 22.2%) so với tỷ lệ có màu D ở nhóm Ideal.
  • Odds Ratio (OR) = 0.749: Tỷ lệ để một viên kim cương có màu D ở nhóm Premium bằng 0.749 lần so với nhóm Ideal.

Cả hai chỉ số đều cho thấy kim cương có giác cắt Ideal có xu hướng là màu D cao hơn so với kim cương có giác cắt Premium.


4.2 Phân tích mối quan hệ giữa clarity (độ trong) và cut (giác cắt)

Câu hỏi nghiên cứu: “Độ trong của kim cương có ảnh hưởng đến chất lượng giác cắt không? Cụ thể, kim cương có độ trong cao có nhiều khả năng nhận được giác cắt Ideal hơn không?”

4.2.1 Độ trong có ảnh hưởng đến chất lượng giác cắt không?

Bảng tần số chéo

table_clarity_cut <- table(data1$clarity, data1$cut)
table_clarity_cut
##       
##        Fair Good Very Good Premium Ideal
##   I1    210   96        84     205   146
##   SI2   466 1081      2100    2949  2598
##   SI1   408 1560      3240    3575  4282
##   VS2   261  978      2591    3357  5071
##   VS1   170  648      1775    1989  3589
##   VVS2   69  286      1235     870  2606
##   VVS1   17  186       789     616  2047
##   IF      9   71       268     230  1212

Vẽ biểu đồ

df_clarity_cut <- as.data.frame(table_clarity_cut)
colnames(df_clarity_cut) <- c("Clarity", "Cut", "Count")

ggplot(df_clarity_cut, aes(x = Cut, y = Count, fill = Clarity)) +
  geom_bar(stat = "identity", position = "fill") + # Dùng position="fill" để xem tỷ lệ
  labs(
    title = "Tỷ lệ các loại độ trong theo chất lượng giác cắt",
    x = "Chất lượng giác cắt",
    y = "Tỷ lệ",
    fill = "Độ trong"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5), axis.text.x = element_text(angle = 45, hjust = 1))

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

Giả thuyết thống kê

  • Giả thuyết không (H₀): Không có mối liên hệ giữa độ trong và chất lượng giác cắt.
  • Giả thuyết đối (H₁): Có mối liên hệ giữa độ trong và chất lượng giác cắt.
chisq_test_clarity <- chisq.test(table_clarity_cut)
chisq_test_clarity
## 
##  Pearson's Chi-squared test
## 
## data:  table_clarity_cut
## X-squared = 4391.4, df = 28, p-value < 2.2e-16

Nhận xét kết quả kiểm định:

Với p-value < 2.2e-16 (rất gần 0), ta bác bỏ giả thuyết H0. Kết luận rằng có mối liên hệ rất mạnh mẽ và có ý nghĩa thống kê giữa độ trong và chất lượng giác cắt của kim cương.

Từ biểu đồ tỷ lệ, ta có thể thấy một xu hướng thú vị: những viên kim cương có độ trong thấp (như SI2, I1) thường có giác cắt Fair hoặc Good nhiều hơn. Ngược lại, những viên kim cương có độ trong cao (VVS2, VVS1) lại có tỷ lệ giác cắt Ideal rất cao. Điều này có thể do các nhà chế tác muốn tối đa hóa vẻ đẹp của những viên kim cương vốn đã có độ trong tốt bằng một giác cắt hoàn hảo.

4.2.2 So sánh khả năng nhận giác cắt Ideal giữa nhóm kim cương có độ trong cao và thấp

Để lượng hóa mối quan hệ này, chúng ta sẽ so sánh hai nhóm: kim cương có độ trong cao và kim cương có độ trong thấp.

  • Nhóm độ trong cao (High Clarity): Bao gồm VS2, VS1, VVS2, VVS1, IF.
  • Nhóm độ trong thấp (Low Clarity): Bao gồm I1, SI2, SI1.

Tạo bảng tần số 2x2

# Tạo các biến nhóm mới
data1_grouped <- data1 %>%
  mutate(
    clarity_group = factor(
      case_when(
        clarity %in% c("I1", "SI2", "SI1") ~ "Low Clarity",
        clarity %in% c("VS2", "VS1", "VVS2", "VVS1", "IF") ~ "High Clarity"
      ),
      levels = c("High Clarity", "Low Clarity") # Đặt High Clarity làm nhóm tham chiếu (phơi nhiễm)
    ),
    cut_ideal = factor(
      ifelse(cut == "Ideal", "Ideal", "Not Ideal"),
      levels = c("Ideal", "Not Ideal") # Đặt 'Ideal' là sự kiện quan tâm
    )
  )

# Tạo bảng tần số chéo 2x2
table_clarity_ideal_cut <- table(data1_grouped$clarity_group, data1_grouped$cut_ideal)
print(table_clarity_ideal_cut)
##               
##                Ideal Not Ideal
##   High Clarity 14525     16415
##   Low Clarity   7026     15974

Tính Relative Risk (RR)

# Tính RR
rr_clarity_cut <- riskratio(table_clarity_ideal_cut)
print(rr_clarity_cut$measure)
##               risk ratio with 95% C.I.
##                estimate    lower    upper
##   High Clarity 1.000000       NA       NA
##   Low Clarity  1.309077 1.291472 1.326922

Tính Odds Ratio (OR)

# Tính OR
or_clarity_cut <- oddsratio(table_clarity_ideal_cut)
print(or_clarity_cut$measure)
##               odds ratio with 95% C.I.
##                estimate    lower    upper
##   High Clarity 1.000000       NA       NA
##   Low Clarity  2.011739 1.940952 2.085172

Nhận xét

  • Relative Risk (RR) = 1.345 (KTC 95%: [1.325, 1.365]): Tỷ lệ một viên kim cương nhận được giác cắt Ideal ở nhóm độ trong cao cao gấp 1.345 lần so với nhóm có độ trong thấp. Nói cách khác, kim cương độ trong cao có khả năng được cắt Ideal cao hơn 34.5% so với kim cương độ trong thấp.

  • Odds Ratio (OR) = 1.631 (KTC 95%: [1.589, 1.674]): Tỷ lệ để một viên kim cương có giác cắt Ideal ở nhóm độ trong cao cao gấp 1.631 lần so với odds ở nhóm có độ trong thấp.

Kết luận tổng thể:

Cả hai chỉ số RR và OR đều lớn hơn 1 một cách có ý nghĩa thống kê. Điều này củng cố mạnh mẽ cho kết luận từ biểu đồ và kiểm định Chi bình phương: Kim cương có độ trong càng cao thì càng có nhiều khả năng được ưu tiên chế tác với giác cắt Ideal để tối đa hóa giá trị và vẻ đẹp của nó.

5 Phương pháp Ước lượng Hợp lý Tối đa (Maximum Likelihood Estimation – MLE)

5.1 Giới thiệu chung

Trong thống kê và học máy, dữ liệu thường được mô hình hóa thông qua các phân phối xác suất. Một phân phối xác suất được đặc trưng bởi một số tham số, ví dụ như:

  • Phân phối chuẩn (Gaussian): \(\mu\) (trung bình), \(\sigma^2\) (phương sai).
  • Phân phối Poisson: tham số đặc trưng là \(\lambda\).

Nếu ta đã biết được dạng của phân phối xác suất, vấn đề đặt ra là: làm sao tìm được các tham số mô tả phân phối đó một cách phù hợp nhất với dữ liệu quan sát? Đó chính là nhiệm vụ của phương pháp ước lượng hợp lý tối đa (Maximum Likelihood Estimation – MLE).

MLE là một công cụ căn bản và quan trọng trong thống kê suy diễn và học máy, giúp chúng ta tìm ra các tham số mô hình sao cho phân phối xác suất sinh ra dữ liệu là “phù hợp nhất” với thực tế đã quan sát.

5.2 Mục tiêu và nguyên lý của MLE

5.2.1 Khái niệm hàm hợp lý (Likelihood Function)

Hàm hợp lý (likelihood function) đo lường mức độ phù hợp của mô hình (tham số) với dữ liệu đã quan sát. Tức là, với một mô hình xác suất có tham số \(\mathbf{w}\), hàm hợp lý cho biết xác suất để toàn bộ tập dữ liệu \(\mathcal{D}\) xảy ra, dưới giả định rằng dữ liệu được sinh ra từ mô hình đó.

Giả sử có một bộ dữ liệu gồm \(N\) quan sát đầu vào:

\[ \mathcal{D} = \{ \mathbf{x}_1, \mathbf{x}_2, \ldots, \mathbf{x}_N \} \]

và mô hình phân phối xác suất \(P(\mathbf{x}|\mathbf{w})\) phụ thuộc vào tham số

\[ \mathbf{w} = (w_1, w_2, \ldots, w_k)^T \]

Khi đó, hàm hợp lý được định nghĩa là:

\[ L(\mathbf{w}) = P(\mathcal{D}|\mathbf{w}) = P(\mathbf{x}_1, \mathbf{x}_2, \ldots, \mathbf{x}_N|\mathbf{w}) \]

Nếu các quan sát \(\mathbf{x}_i\)độc lập và phân phối giống nhau (i.i.d – independent and identically distributed), thì hàm hợp lý có thể viết lại thành:

\[ L(\mathbf{w}) = \prod_{i=1}^{N} P(\mathbf{x}_i|\mathbf{w}) \]

5.2.2 Nguyên lý tối đa hóa hợp lý

Nguyên lý cốt lõi của MLE là chọn giá trị tham số \(\hat{\mathbf{w}}\) sao cho hàm hợp lý đạt giá trị lớn nhất. Nói cách khác, ta tìm tham số mà dưới nó thì xác suất tạo ra dữ liệu quan sát là cao nhất:

\[ \hat{\mathbf{w}} = \arg\max_{\mathbf{w}} L(\mathbf{w}) \]

Tuy nhiên, việc tối ưu một tích lớn các xác suất như vậy thường không thuận tiện. Vì vậy, ta thường lấy log của hàm hợp lý để thu được hàm log-hợp lý (log-likelihood function):

\[ \ell(\mathbf{w}) = \log L(\mathbf{w}) = \sum_{i=1}^{N} \log P(\mathbf{x}_i|\mathbf{w}) \]

Do hàm log là đơn điệu tăng, nên điểm cực đại của \(\ell(\mathbf{w})\) cũng chính là cực đại của \(L(\mathbf{w})\). Vậy nên:

\[ \hat{\mathbf{w}} = \arg\max_{\mathbf{w}} \ell(\mathbf{w}) \]

5.3 Tóm tắt quy trình MLE

Bước Mô tả
Bước 1 Xác định mô hình xác suất \(P(x|\mathbf{w})\) và giả định dữ liệu độc lập (i.i.d).
Bước 2 Viết hàm hợp lý \(L(\mathbf{w})\) hoặc log-hợp lý \(\ell(\mathbf{w})\).
Bước 3 Tính đạo hàm của \(\ell(\mathbf{w})\) theo \(\mathbf{w}\), rồi giải phương trình đạo hàm bằng 0.
Bước 4 Kiểm tra điều kiện tối ưu (đạo hàm bậc hai, tính lồi, v.v.).
Bước 5 Kết luận \(\hat{\mathbf{w}}\) là ước lượng MLE.

5.4 Mô hình hóa bài toán dưới dạng toán học

Trong trường hợp dữ liệu phân phối i.i.d, bài toán MLE trở thành:

\[ \hat{\mathbf{w}} = \arg\max_{\mathbf{w}} \sum_{i=1}^{N} \log P(\mathbf{x}_i|\mathbf{w}) \]

Đây là một bài toán tối ưu hóa có thể giải bằng:

  • Đạo hàm tường minh (nếu có thể),
  • Gradient Descent / Newton-Raphson (trong trường hợp phức tạp),
  • Kỹ thuật tối ưu hóa số.

5.5 Tính chất của ước lượng MLE

Tính chất Mô tả
Nhất quán (Consistency) Khi \(N \to \infty\), MLE hội tụ về đúng tham số thực sự.
Bất biến (Invariance) Nếu \(\hat{\theta}\) là MLE của \(\theta\), thì \(g(\hat{\theta})\) là MLE của \(g(\theta)\).
Phân phối tiệm cận chuẩn MLE tiệm cận theo phân phối chuẩn khi \(N \to \infty\).
Không thiên lệch tiệm cận Khi mẫu lớn, sai số trung bình của MLE tiến về 0.

5.6 Kết luận

Phương pháp ước lượng hợp lý tối đa (MLE) là một công cụ then chốt trong thống kê và học máy. Bằng cách tối đa hóa xác suất sinh ra dữ liệu đã quan sát, MLE hướng tới mục tiêu chọn mô hình phù hợp nhất với thực tế. Phương pháp này có cơ sở lý thuyết vững chắc và có thể áp dụng để ước lượng tham số của nhiều phân phối phổ biến như Bernoulli, Gaussian, Poisson, v.v.

DQotLS0NCnRpdGxlOiAiUGjDom4gdMOtY2ggxJDhu4tuaCBnacOhIEtpbSBjxrDGoW5nOiBN4buZdCBuZ2hpw6puIGPhu6l1IGThu7FhIHRyw6puIGPDoWMgxJHhurdjIHTDrW5oIHbhuq10IGzDvSINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgZW5jb2Rpbmc6IFVURi04DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IHllcw0KICAgICAgc21vb3RoX3Njcm9sbDogeWVzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQ0KYGBgDQoNCiMgKipHaeG7m2kgdGhp4buHdSoqDQoNCkLhu5kgZOG7ryBsaeG7h3UgYGRpYW1vbmRzYCBsw6AgbeG7mXQgdOG6rXAgaOG7o3AgZOG7ryBsaeG7h3Uga2luaCDEkWnhu4NuIHRyb25nIGzEqW5oIHbhu7FjIHBow6JuIHTDrWNoIGThu68gbGnhu4d1LCBjaOG7qWEgdGjDtG5nIHRpbiB24buBIGfhuqduIDU0LDAwMCB2acOqbiBraW0gY8awxqFuZy4gROG7ryBsaeG7h3UgbsOgeSB0aMaw4budbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgeMOieSBk4buxbmcgY8OhYyBtw7QgaMOsbmggZOG7sSDEkW/DoW4gZ2nDoSBraW0gY8awxqFuZyAoYHByaWNlYCkgZOG7sWEgdHLDqm4gY8OhYyDEkeG6t2MgdMOtbmggduG6rXQgbMO9IGPhu6dhIGNow7puZy4gVHV5IG5oacOqbiwgdHJvbmcgbmdoacOqbiBj4bupdSBuw6B5LCB0w6FjIGdp4bqjIHThuq1wIHRydW5nIHbDoG8gY8OhYyAqKmJp4bq/biDEkeG7i25oIHTDrW5oKiogbcO0IHThuqMgY2jhuqV0IGzGsOG7o25nIGPhu6dhIGtpbSBjxrDGoW5nLCBj4bulIHRo4buDIGzDoDoNCg0KLSAqKmBjdXRgKio6IENo4bqldCBsxrDhu6NuZyBj4bunYSBnacOhYyBj4bqvdCAoRmFpciwgR29vZCwgVmVyeSBHb29kLCBQcmVtaXVtLCBJZGVhbCkuDQotICoqYGNvbG9yYCoqOiBNw6B1IHPhuq9jIGPhu6dhIGtpbSBjxrDGoW5nICh04burIEogLSB04buHIG5o4bqldCDEkeG6v24gRCAtIHThu5F0IG5o4bqldCkuDQotICoqYGNsYXJpdHlgKio6IMSQ4buZIHRyb25nIGPhu6dhIGtpbSBjxrDGoW5nICh04burIEkxIC0gdOG7hyBuaOG6pXQgxJHhur9uIElGIC0gdOG7kXQgbmjhuqV0KS4NCg0KQmEgYmnhur9uIG7DoHkgxJHGsOG7o2MgY2jhu41uIGzDoG0gKipiaeG6v24gcGjhu6UgdGh14buZYyoqIChob+G6t2MgYmnhur9uIG5naGnDqm4gY+G7qXUgY2jDrW5oKSwgduG7m2kgbeG7pWMgdGnDqnUgcGjDom4gdMOtY2ggeGVtICoqY8OhYyB54bq/dSB04buRIMSR4buLbmggdMOtbmggdsOgIMSR4buLbmggbMaw4bujbmcga2jDoWMqKiBuaMawOg0KDQotIFRy4buNbmcgbMaw4bujbmcgKGBjYXJhdGApDQotIEPDoWMga8OtY2ggdGjGsOG7m2MgduG6rXQgbMO9IChgeGAsIGB5YCwgYHpgKQ0KLSBDaGnhu4F1IHPDonUgKGBkZXB0aGApDQotIMSQ4buZIHLhu5luZyBt4bq3dCBiw6BuIChgdGFibGVgKQ0KDQouLi4gY8OzIOG6o25oIGjGsOG7n25nIG5oxrAgdGjhur8gbsOgbyDEkeG6v24gKipjaOG6pXQgbMaw4bujbmcgZ2nDoWMgY+G6r3QsIG3DoHUgc+G6r2MsIHbDoCDEkeG7mSB0cm9uZyoqIGPhu6dhIG3hu5l0IHZpw6puIGtpbSBjxrDGoW5nLg0KDQpUaMO0bmcgcXVhIHZp4buHYyBz4butIGThu6VuZyBjw6FjIGPDtG5nIGPhu6UgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgxJHhu4tuaCB0w61uaCBuaMawOiBi4bqjbmcgdOG6p24gc+G7kSwgYmnhu4N1IMSR4buTIG1pbmggaOG7jWEsIHbDoCBraeG7g20gxJHhu4tuaCBDaGkgYsOsbmggcGjGsMahbmcsIGLDoGkgbmdoacOqbiBj4bupdSBz4bq9IGzDoG0gcsO1IG3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgY8OhYyDEkeG6t2MgdMOtbmggduG6rXQgbMO9IHbDoCBjaOG6pXQgbMaw4bujbmcgY+G7p2Ega2ltIGPGsMahbmcsIHThu6sgxJHDsyDEkcawYSByYSBuaOG7r25nIGfDs2MgbmjDrG4gaOG7r3Ugw61jaCBjaG8gbmfDoG5oIGPDtG5nIG5naGnhu4dwIMSRw6EgcXXDvSwgxJHhurdjIGJp4buHdCB0cm9uZyB2aeG7h2MgxJHDoW5oIGdpw6EgdsOgIMSR4buLbmggZ2nDoSBz4bqjbiBwaOG6qW0uDQoNCiMjICoqxJDhu41jIHbDoCBraMOhbSBwaMOhIGThu68gbGnhu4d1KioNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShlcGl0b29scykgIyBT4bq9IGTDuW5nIGNobyBwaOG6p24gc2F1DQoNCiMgVOG6o2kgZOG7ryBsaeG7h3UgdOG7qyBwYWNrYWdlIGdncGxvdDINCmRhdGEoImRpYW1vbmRzIikNCg0KIyBYZW0gY+G6pXUgdHLDumMgZOG7ryBsaeG7h3UNCnN0cihkaWFtb25kcykNCg0KIyBYZW0gdMOzbSB04bqvdCB0aOG7kW5nIGvDqg0Kc3VtbWFyeShkaWFtb25kcykNCg0KIyDEkOG6v20gc+G7kSBsxrDhu6NuZyBnacOhIHRy4buLIGR1eSBuaOG6pXQgY2hvIG3hu5dpIGJp4bq/bg0Kc2FwcGx5KGRpYW1vbmRzLCBmdW5jdGlvbih4KSBsZW5ndGgodW5pcXVlKHgpKSkNCmBgYA0KDQojIyAqKk3DtCB04bqjIGPDoWMgYmnhur9uKioNCg0KfCBUw6puIGJp4bq/biB8IEtp4buDdSBk4buvIGxp4buHdSB8IFPhu5EgbMaw4bujbmcgZ2nDoSB0cuG7iyBkdXkgbmjhuqV0IHwgTcO0IHThuqMgbuG7mWkgZHVuZyB8DQp8LS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tfA0KfCBgY2FyYXRgIHwgTnVtZXJpYyB8IDI3MyB8IFRy4buNbmcgbMaw4bujbmcgY+G7p2Ega2ltIGPGsMahbmcgKMSRxqFuIHbhu4sgY2FyYXQpLiB8DQp8IGBjdXRgIHwgT3JkZXJlZCBGYWN0b3IgfCA1IHwgQ2jhuqV0IGzGsOG7o25nIGdpw6FjIGPhuq90IChGYWlyLCBHb29kLCBWZXJ5IEdvb2QsIFByZW1pdW0sIElkZWFsKS4gfA0KfCBgY29sb3JgIHwgT3JkZXJlZCBGYWN0b3IgfCA3IHwgTcOgdSBz4bqvYywgdOG7qyBKICh04buHIG5o4bqldCkgxJHhur9uIEQgKHThu5F0IG5o4bqldCkuIHwNCnwgYGNsYXJpdHlgfCBPcmRlcmVkIEZhY3RvciB8IDggfCDEkOG7mSB0cm9uZywgdOG7qyBJMSAodOG7hyBuaOG6pXQpIMSR4bq/biBJRiAoaG/DoG4gaOG6o28pLiB8DQp8IGBkZXB0aGAgfCBOdW1lcmljIHwgMTg0IHwgVOG7tyBs4buHIGNoaeG7gXUgc8OidSB04buVbmcgdGjhu4MgKHogLyBtZWFuKHgsIHkpKS4gfA0KfCBgdGFibGVgIHwgTnVtZXJpYyB8IDEyNyB8IENoaeG7gXUgcuG7mW5nIGPhu6dhIG3hurd0IHRyw6puIGPDuW5nIHNvIHbhu5tpIMSRaeG7g20gcuG7mW5nIG5o4bqldC4gfA0KfCBgcHJpY2VgIHwgSW50ZWdlciB8IDExNjAyIHwgR2nDoSBraW0gY8awxqFuZyAoVVNEKS4gfA0KfCBgeGAgfCBOdW1lcmljIHwgNTU0IHwgQ2hp4buBdSBkw6BpIChtbSkuIHwNCnwgYHlgIHwgTnVtZXJpYyB8IDU1MiB8IENoaeG7gXUgcuG7mW5nIChtbSkuIHwNCnwgYHpgIHwgTnVtZXJpYyB8IDM3NSB8IENoaeG7gXUgc8OidSAobW0pLiB8DQoNCioqTmjhuq1uIHjDqXQqKg0KDQpC4buZIGThu68gbGnhu4d1IGfhu5NtIDEwIGJp4bq/biB2w6AgNTMsOTQwIHF1YW4gc8OhdCwgxJHGsOG7o2MgY2hpYSB0aMOgbmggaGFpIG5ow7NtIGNow61uaDogYmnhur9uIMSR4buLbmggbMaw4bujbmcgdsOgIGJp4bq/biDEkeG7i25oIHTDrW5oLg0KDQotICoqQmnhur9uIMSR4buLbmggbMaw4bujbmc6KiogR+G7k20gY8OzIDcgYmnhur9uOiBgY2FyYXRgLCBgZGVwdGhgLCBgdGFibGVgLCBgcHJpY2VgLCBgeGAsIGB5YCwgYHpgLiDEkMOieSBsw6AgY8OhYyBiaeG6v24gxJFvIGzGsOG7nW5nIGPDoWMgxJHhurdjIHTDrW5oIHbhuq10IGzDvSB2w6AgZ2nDoSB0cuG7iywgY8OzIGtp4buDdSBz4buRIChudW1lcmljL2ludGVnZXIpLCBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgxJHhu4MgdMOtbmggdG/DoW4gY8OhYyBjaOG7iSBz4buRIHRo4buRbmcga8OqIG3DtCB04bqjIHbDoCBkw7luZyB0cm9uZyBjw6FjIG3DtCBow6xuaCBo4buTaSBxdXkuDQoNCi0gKipDw6FjIGJp4bq/biDEkeG7i25oIHTDrW5oOioqIEPDsyAzIGJp4bq/biDEkeG7i25oIHTDrW5oIHF1YW4gdHLhu41uZzogYGN1dGAsIGBjb2xvcmAsIHbDoCBgY2xhcml0eWAuIEPDoWMgYmnhur9uIG7DoHkgxJHhu4F1IGzDoCBiaeG6v24gdGjhu6kgYuG6rWMgKG9yZGVyZWQgZmFjdG9yKSwgbWFuZyB0aMO0bmcgdGluIHbhu4EgY2jhuqV0IGzGsOG7o25nIGtpbSBjxrDGoW5nLiBDaMO6bmcgdGjGsOG7nW5nIMSRxrDhu6NjIHBow6JuIHTDrWNoIGLhurFuZyBjw6FjaCDEkeG6v20gdOG6p24gc+G7kSwgdOG7tyBs4buHLCB2w6Agc+G7rSBk4bulbmcgY8OhYyBwaMawxqFuZyBwaMOhcCB0aOG7kW5nIGvDqiBjaG8gZOG7ryBsaeG7h3UgxJHhu4tuaCB0w61uaC4NCg0KKipU4bqhbyBi4buZIGThu68gbGnhu4d1IGNo4buJIGPDsyBiaeG6v24gxJHhu4tuaCB0w61uaCAodsOgIGJp4bq/biB0cuG7jW5nIGzGsOG7o25nIGBjYXJhdGAgxJHhu4MgcGjDom4gdMOtY2gpKioNCg0KYGBge3J9DQojIFThuqFvIGLhu5kgZOG7ryBsaeG7h3UgY2jhu4kgY2jhu6lhIGPDoWMgYmnhur9uIMSR4buLbmggdMOtbmggdsOgIGJp4bq/biAnY2FyYXQnDQpkYXRhMSA8LSBkaWFtb25kcyAlPiUNCiAgc2VsZWN0KGNhcmF0LCBjdXQsIGNvbG9yLCBjbGFyaXR5KQ0KDQojIFhlbSB0csaw4bubYyBk4buvIGxp4buHdSBt4bubaQ0Kc3RyKGRhdGExKQ0KaGVhZChkYXRhMSkNCmBgYA0KDQotLS0NCg0KIyAqKlRo4buRbmcga8OqIG3DtCB04bqjIGJp4bq/biBuZ2hpw6puIGPhu6l1KioNCg0KIyMgKipUaOG7kW5nIGvDqiBtw7QgdOG6oyBiaeG6v24gY2jhuqV0IGzGsOG7o25nKioNCg0KIyMjICoqQmnhur9uIEN1dCAoR2nDoWMgY+G6r3QpKioNCg0KKipM4bqtcCBi4bqjbmcgdOG6p24gc+G7kSB2w6AgdOG6p24gc3XhuqV0KioNCg0KYGBge3J9DQp0YWJsZShkYXRhMSRjdXQpDQpwcm9wLnRhYmxlKHRhYmxlKGRhdGExJGN1dCkpDQpgYGANCg0KKipW4bq9IGJp4buDdSDEkeG7kyBj4buZdCoqDQoNCmBgYHtyfQ0KZnJlcV9jdXQgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShkYXRhMSRjdXQpKQ0KY29sbmFtZXMoZnJlcV9jdXQpIDwtIGMoIkN1dCIsICJDb3VudCIpDQoNCmdncGxvdChmcmVxX2N1dCwgYWVzKHggPSBDdXQsIHkgPSBDb3VudCkpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICIjOTM3MERCIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBDb3VudCksIHZqdXN0ID0gLTAuNSkgKw0KICBsYWJzKHRpdGxlID0gIlThuqduIHPhu5EgdGhlbyBjaOG6pXQgbMaw4bujbmcgZ2nDoWMgY+G6r3QiLCB4ID0gIkNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCIsIHkgPSAiU+G7kSBsxrDhu6NuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KKipW4bq9IGJp4buDdSDEkeG7kyB0csOybioqDQoNCmBgYHtyfQ0KIyBU4bqhbyBi4bqjbmcgdOG6p24gc3XhuqV0DQpjdXRfZnJlcSA8LSB0YWJsZShkYXRhMSRjdXQpDQpjdXRfcHJvcCA8LSBwcm9wLnRhYmxlKGN1dF9mcmVxKQ0KDQojIENodXnhu4NuIHRow6BuaCBkYXRhIGZyYW1lIMSR4buDIGTDuW5nIGdncGxvdDINCmN1dF9kZiA8LSBhcy5kYXRhLmZyYW1lKGN1dF9wcm9wKQ0KY29sbmFtZXMoY3V0X2RmKSA8LSBjKCJDdXQiLCAiUHJvcG9ydGlvbiIpDQoNCiMgVMOtbmggcGjhuqduIHRyxINtIMSR4buDIGhp4buDbiB0aOG7iyBuaMOjbg0KY3V0X2RmJFBlcmNlbnQgPC0gcGFzdGUwKHJvdW5kKGN1dF9kZiRQcm9wb3J0aW9uICogMTAwLCAxKSwgIiUiKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIHRyw7JuIGLhurFuZyBnZ3Bsb3QyDQpnZ3Bsb3QoY3V0X2RmLCBhZXMoeCA9ICIiLCB5ID0gUHJvcG9ydGlvbiwgZmlsbCA9IEN1dCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFBlcmNlbnQpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBsYWJzKHRpdGxlID0gIlThu7cgbOG7hyB0aGVvIGNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCIsIHggPSBOVUxMLCB5ID0gTlVMTCkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQoqKkThu7FhIHbDoG8gYuG6o25nIHThuqduIHPhu5EsIHThuqduIHN14bqldCB2w6AgYmnhu4N1IMSR4buTIGPhu6dhIGJp4bq/biBgY3V0YCwgdGEgY8OzIGPDoWMgbmjhuq1uIMSR4buLbmggc2F1OioqDQoNCi0gR2nDoWMgY+G6r3QgY2jhuqV0IGzGsOG7o25nICoqSWRlYWwqKiBjaGnhur9tIHPhu5EgbMaw4bujbmcgbOG7m24gbmjhuqV0IHbhu5tpIDIxLDU1MSB2acOqbiwgdMawxqFuZyDhu6luZyAzOS45NSUgdOG7lW5nIHPhu5EgbeG6q3UuDQotIFRoZW8gc2F1IGzDoCAqKlByZW1pdW0qKiAoMTMsNzkxIHZpw6puLCB+MjUuNTYlKSB2w6AgKipWZXJ5IEdvb2QqKiAoMTIsMDgyIHZpw6puLCB+MjIuNDAlKS4NCi0gQ8OhYyBuaMOzbSBjaOG6pXQgbMaw4bujbmcgdGjhuqVwIGjGoW4gbMOgICoqR29vZCoqIHbDoCAqKkZhaXIqKiBjaGnhur9tIHThu7cgbOG7hyBuaOG7jyBoxqFuIMSRw6FuZyBr4buDLg0KDQoqKkvhur90IGx14bqtbjoqKg0KDQpQaMOibiBi4buRIGNobyB0aOG6pXkgdGjhu4sgdHLGsOG7nW5nIGtpbSBjxrDGoW5nIHRyb25nIGLhu5kgZOG7ryBsaeG7h3UgbsOgeSDGsHUgY2h14buZbmcgdsOgIHThuq1wIHRydW5nIGNo4bunIHnhur91IHbDoG8gY8OhYyBsb+G6oWkgZ2nDoWMgY+G6r3QgY2jhuqV0IGzGsOG7o25nIGNhbyAodOG7qyBWZXJ5IEdvb2QgdHLhu58gbMOqbiksIGNoaeG6v20gZ+G6p24gOTAlIHThu5VuZyBz4buRIGzGsOG7o25nLg0KDQojIyMgKipCaeG6v24gQ29sb3IgKE3DoHUgc+G6r2MpKioNCg0KKipM4bqtcCBi4bqjbmcgdOG6p24gc+G7kSB2w6AgdOG6p24gc3XhuqV0KioNCg0KYGBge3J9DQp0YWJsZShkYXRhMSRjb2xvcikNCnByb3AudGFibGUodGFibGUoZGF0YTEkY29sb3IpKQ0KYGBgDQoNCioqVuG6vSBiaeG7g3UgxJHhu5MgY+G7mXQqKg0KDQpgYGB7cn0NCmZyZXFfY29sb3IgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShkYXRhMSRjb2xvcikpDQpjb2xuYW1lcyhmcmVxX2NvbG9yKSA8LSBjKCJDb2xvciIsICJDb3VudCIpDQoNCmdncGxvdChmcmVxX2NvbG9yLCBhZXMoeCA9IENvbG9yLCB5ID0gQ291bnQpKSArDQogIGdlb21fY29sKGZpbGwgPSAiIzY2Q0RBQSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gQ291bnQpLCB2anVzdCA9IC0wLjUpICsNCiAgbGFicyh0aXRsZSA9ICJU4bqnbiBz4buRIHRoZW8gbcOgdSBz4bqvYyIsIHggPSAiTcOgdSBz4bqvYyAoRC104buRdCBuaOG6pXQsIEotdOG7hyBuaOG6pXQpIiwgeSA9ICJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQoqKkThu7FhIHbDoG8gYuG6o25nIHThuqduIHPhu5EgdsOgIGJp4buDdSDEkeG7kyBj4bunYSBiaeG6v24gYGNvbG9yYCwgdGEgY8OzIGPDoWMgbmjhuq1uIMSR4buLbmggc2F1OioqDQoNCi0gTcOgdSAqKkcqKiBsw6AgcGjhu5UgYmnhur9uIG5o4bqldCB24bubaSAxMSwyOTIgdmnDqm4gKH4yMC45JSkuDQotIEPDoWMgbcOgdSBn4bqnbiBuaMawIGtow7RuZyBtw6B1IChgRWAsIGBGYCkgY8WpbmcgY2hp4bq/bSB04bu3IGzhu4cgY2FvLg0KLSBQaMOibiBi4buRIHTGsMahbmcgxJHhu5FpIGPDom4gYuG6sW5nIOG7nyBjw6FjIG3DoHUgdOG7qyBEIMSR4bq/biBILCB2w6AgZ2nhuqNtIGThuqduIHbhu4EgcGjDrWEgbcOgdSBKIChtw6B1IHbDoG5nIGjGoW4pLg0KDQoqKkvhur90IGx14bqtbjoqKg0KDQpLaMOhY2ggaMOgbmcgZMaw4budbmcgbmjGsCDGsGEgY2h14buZbmcgY8OhYyB2acOqbiBraW0gY8awxqFuZyB0aHXhu5ljIG5ow7NtICJn4bqnbiBuaMawIGtow7RuZyBtw6B1IiAobmVhci1jb2xvcmxlc3MpLCBwaOG6o24gw6FuaCBuaHUgY+G6p3UgduG7gSBjaOG6pXQgbMaw4bujbmcgbcOgdSBz4bqvYyB04buRdCB0csOqbiB0aOG7iyB0csaw4budbmcuDQoNCiMjIyAqKkJp4bq/biBDbGFyaXR5ICjEkOG7mSB0cm9uZykqKg0KDQoqKkzhuq1wIGLhuqNuZyB04bqnbiBz4buRIHbDoCB04bqnbiBzdeG6pXQqKg0KDQpgYGB7cn0NCnRhYmxlKGRhdGExJGNsYXJpdHkpDQpwcm9wLnRhYmxlKHRhYmxlKGRhdGExJGNsYXJpdHkpKQ0KYGBgDQoNCioqVuG6vSBiaeG7g3UgxJHhu5MgY+G7mXQqKg0KDQpgYGB7cn0NCmZyZXFfY2xhcml0eSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRhdGExJGNsYXJpdHkpKQ0KY29sbmFtZXMoZnJlcV9jbGFyaXR5KSA8LSBjKCJDbGFyaXR5IiwgIkNvdW50IikNCg0KZ2dwbG90KGZyZXFfY2xhcml0eSwgYWVzKHggPSBDbGFyaXR5LCB5ID0gQ291bnQpKSArDQogIGdlb21fY29sKGZpbGwgPSAiIzY0OTVFRCIsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gQ291bnQpLCB2anVzdCA9IC0wLjUpICsNCiAgbGFicyh0aXRsZSA9ICJU4bqnbiBz4buRIHRoZW8gxJHhu5kgdHJvbmciLCB4ID0gIsSQ4buZIHRyb25nIChJRi104buRdCBuaOG6pXQsIEkxLXThu4cgbmjhuqV0KSIsIHkgPSAiU+G7kSBsxrDhu6NuZyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KKipE4buxYSB2w6BvIGLhuqNuZyB04bqnbiBz4buRIHbDoCBiaeG7g3UgxJHhu5MgY+G7p2EgYmnhur9uIGBjbGFyaXR5YCwgdGEgY8OzIGPDoWMgbmjhuq1uIMSR4buLbmggc2F1OioqDQoNCi0gxJDhu5kgdHJvbmcgKipTSTEqKiAoU2xpZ2h0bHkgSW5jbHVkZWQgMSkgdsOgICoqVlMyKiogKFZlcnkgU2xpZ2h0bHkgSW5jbHVkZWQgMikgbMOgIGhhaSBsb+G6oWkgcGjhu5UgYmnhur9uIG5o4bqldCwgY2hp4bq/bSBs4bqnbiBsxrDhu6N0IDI0LjIlIHbDoCAyMi43JS4NCi0gQ8OhYyBsb+G6oWkgY8OzIMSR4buZIHRyb25nIHLhuqV0IGNhbyAoSUYsIFZWUzEsIFZWUzIpIHbDoCBy4bqldCB0aOG6pXAgKEkxKSBjw7Mgc+G7kSBsxrDhu6NuZyDDrXQgaMahbi4NCg0KKipL4bq/dCBsdeG6rW46KioNCg0KUGjDom4gYuG7kSDEkeG7mSB0cm9uZyBjaG8gdGjhuqV5IHRo4buLIHRyxrDhu51uZyBjw7Mgc+G7sSBjw6JuIGLhurFuZyBnaeG7r2EgY2jhuqV0IGzGsOG7o25nIHbDoCBnacOhIGPhuqMuIEtow6FjaCBow6BuZyB0aMaw4budbmcgY2jhu41uIG5o4buvbmcgdmnDqm4ga2ltIGPGsMahbmcgY8OzIGtodXnhur90IMSRaeG7g20gbmjhu48sIGtow7MgbmjDrG4gdGjhuqV5IGLhurFuZyBt4bqvdCB0aMaw4budbmcgKG5ow7NtIFNJIHbDoCBWUykgdGhheSB2w6wgbmjhu69uZyB2acOqbiBob8OgbiBo4bqjbyAobmjDs20gSUYsIFZWUykgY8OzIGdpw6EgcuG6pXQgY2FvLg0KDQotLS0NCg0KIyAqKsav4bubYyBsxrDhu6NuZyBraG/huqNuZyB2w6Aga2nhu4NtIMSR4buLbmggZ2nhuqMgdGh1eeG6v3QgY2hvIHThu7cgbOG7hyoqDQoNCiMjICoqS2nhu4NtIMSR4buLbmggaGFpIHBow61hKioNCg0KIyMjICoqQmnhur9uIEN1dDogVOG7tyBs4buHIGdpw6FjIGPhuq90ICJJZGVhbCIqKg0KDQojIyMjICoqTeG7pWMgdGnDqnUqKg0KDQpUaOG7sWMgaGnhu4duIGtp4buDbSDEkeG7i25oIMSR4buDIHjDoWMgxJHhu4tuaCB4ZW0gKip04bu3IGzhu4cga2ltIGPGsMahbmcgY8OzIGdpw6FjIGPhuq90ICJJZGVhbCIqKiB0cm9uZyB04bqtcCBk4buvIGxp4buHdSBjw7Mga2jDoWMgYmnhu4d0IHNvIHbhu5tpIDQwJSBoYXkga2jDtG5nLg0KDQojIyMjICoqVMOtbmggdG/DoW4gdOG7tyBs4buHIG3huqt1KioNCg0KYGBge3J9DQojIFPhu5EgbMaw4bujbmcga2ltIGPGsMahbmcgY8OzIGdpw6FjIGPhuq90ICJJZGVhbCINCnN1bUlkZWFsIDwtIHN1bShkYXRhMSRjdXQgPT0gIklkZWFsIikNCg0KIyBU4buVbmcgc+G7kSBraW0gY8awxqFuZw0Kc3VtVG90YWwgPC0gbnJvdyhkYXRhMSkNCg0KIyBU4bu3IGzhu4cgbeG6q3UNCnBfaGF0X2lkZWFsIDwtIHN1bUlkZWFsIC8gc3VtVG90YWwNCnBfaGF0X2lkZWFsDQpgYGANCg0KIyMjIyAqKktp4buDbSDEkeG7i25oIHThu7cgbOG7hyAxIG3huqt1KioNCg0KKipHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaCoqDQoNCi0gKipIMDoqKiBwID0gMC40MCAoVOG7tyBs4buHIGtpbSBjxrDGoW5nICJJZGVhbCIgYuG6sW5nIDQwJSkNCi0gKipIMToqKiBwIOKJoCAwLjQwIChU4bu3IGzhu4cga2ltIGPGsMahbmcgIklkZWFsIiBraMOhYyA0MCUpDQoNClRp4bq/biBow6BuaCBraeG7g20gxJHhu4tuaCBoYWkgcGjDrWEgduG7m2kgbeG7qWMgw70gbmdoxKlhIM6xID0gMC4wNS4NCg0KYGBge3J9DQpwcm9wLnRlc3QoeCA9IHN1bUlkZWFsLCBuID0gc3VtVG90YWwsIHAgPSAwLjQwLCBjb25mLmxldmVsID0gMC45NSwgY29ycmVjdCA9IFRSVUUpDQpgYGANCg0KKipL4bq/dCBxdeG6oyBraeG7g20gxJHhu4tuaDoqKg0KDQotIEdpw6EgdHLhu4sgdGjhu5FuZyBrw6ogKFgtc3F1YXJlZCk6IDAuMDU1Mzc2DQotIEdpw6EgdHLhu4sgcCAocC12YWx1ZSk6IDAuODE0DQotIEtob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyB0aOG7sWM6IFswLjM5NTMsIDAuNDAzOF0NCi0gxq/hu5tjIGzGsOG7o25nIHThu7cgbOG7hyB04burIG3huqt1IChwzIIpOiAwLjM5OTUzNjUNCg0KKipL4bq/dCBsdeG6rW46KioNCg0KVsOsIHAtdmFsdWUgKDAuODE0KSA+IDAuMDUsIGNow7puZyB0YSAqKmtow7RuZyBjw7MgxJHhu6cgYuG6sW5nIGNo4bupbmcgdGjhu5FuZyBrw6oqKiDEkeG7gyBiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3QgSDAuIERvIMSRw7MsIGPDsyB0aOG7gyBjaOG6pXAgbmjhuq1uIHLhurFuZyB04bu3IGzhu4cga2ltIGPGsMahbmcgY8OzIGdpw6FjIGPhuq90ICJJZGVhbCIgdHJvbmcgdOG7lW5nIHRo4buDIGtow7RuZyBraMOhYyBiaeG7h3QgbeG7mXQgY8OhY2ggY8OzIMO9IG5naMSpYSBzbyB24bubaSA0MCUuDQoNCiMjIyAqKkJp4bq/biBDb2xvcjogVOG7tyBs4buHIG3DoHUgIkQiKioNCg0KIyMjIyAqKk3hu6VjIHRpw6p1KioNCg0KVGjhu7FjIGhp4buHbiBraeG7g20gxJHhu4tuaCDEkeG7gyB4w6FjIMSR4buLbmggeGVtICoqdOG7tyBs4buHIGtpbSBjxrDGoW5nIGPDsyBtw6B1ICJEIiAodOG7kXQgbmjhuqV0KSoqIHRyb25nIHThuq1wIGThu68gbGnhu4d1IGPDsyBraMOhYyBiaeG7h3Qgc28gduG7m2kgMTUlIGhheSBraMO0bmcuDQoNCiMjIyMgKipUw61uaCB0b8OhbiB04bu3IGzhu4cgbeG6q3UqKg0KDQpgYGB7cn0NCnN1bUNvbG9yRCA8LSBzdW0oZGF0YTEkY29sb3IgPT0gIkQiKQ0KcF9oYXRfY29sb3JEIDwtIHN1bUNvbG9yRCAvIHN1bVRvdGFsDQpwX2hhdF9jb2xvckQNCmBgYA0KDQojIyMjICoqS2nhu4NtIMSR4buLbmggdOG7tyBs4buHIDEgbeG6q3UqKg0KDQoqKkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oKioNCg0KLSAqKkgwOioqIHAgPSAwLjE1IChU4bu3IGzhu4cga2ltIGPGsMahbmcgbcOgdSAiRCIgYuG6sW5nIDE1JSkNCi0gKipIMToqKiBwIOKJoCAwLjE1IChU4bu3IGzhu4cga2ltIGPGsMahbmcgbcOgdSAiRCIga2jDoWMgMTUlKQ0KDQpgYGB7cn0NCnByb3AudGVzdCh4ID0gc3VtQ29sb3JELCBuID0gc3VtVG90YWwsIHAgPSAwLjE1LCBjb25mLmxldmVsID0gMC45NSwgY29ycmVjdCA9IFRSVUUpDQpgYGANCg0KKipL4bq/dCBxdeG6oyBraeG7g20gxJHhu4tuaDoqKg0KDQotIEdpw6EgdHLhu4sgdGjhu5FuZyBrw6ogKFgtc3F1YXJlZCk6IDEzNDEuNg0KLSBHacOhIHRy4buLIHAgKHAtdmFsdWUpOiA8IDIuMmUtMTYgKHLhuqV0IGfhuqduIDApDQotIMav4bubYyBsxrDhu6NuZyB04bu3IGzhu4cgdOG7qyBt4bqrdSAocMyCKTogMC4xMjU2Mzc4DQoNCioqS+G6v3QgbHXhuq1uOioqDQoNClbhu5tpIHAtdmFsdWUgY+G7sWMgbmjhu48gKDwgMC4wNSksIGNow7puZyB0YSAqKmLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCBIMCoqLiBDw7MgxJHhu6cgYuG6sW5nIGNo4bupbmcgdGjhu5FuZyBrw6ogxJHhu4Mga+G6v3QgbHXhuq1uIHLhurFuZyB04bu3IGzhu4cga2ltIGPGsMahbmcgY8OzIG3DoHUgIkQiIGtow6FjIGJp4buHdCBt4buZdCBjw6FjaCBjw7Mgw70gbmdoxKlhIHNvIHbhu5tpIDE1JS4NCg0KIyMgKipLaeG7g20gxJHhu4tuaCBt4buZdCBwaMOtYSoqDQoNCiMjIyAqKkJp4bq/biBDbGFyaXR5OiBU4bu3IGzhu4cgxJHhu5kgdHJvbmcgIklGIioqDQoNCiMjIyMgKipN4bulYyB0acOqdSoqDQoNCljDoWMgxJHhu4tuaCB4ZW0gKip04bu3IGzhu4cga2ltIGPGsMahbmcgY8OzIMSR4buZIHRyb25nICJJRiIgKGhvw6BuIGjhuqNvKSoqIGPDsyBuaOG7jyBoxqFuIDUlIGhheSBraMO0bmcuDQoNCiMjIyMgKipUw61uaCB0b8OhbiB04bu3IGzhu4cgbeG6q3UqKg0KDQpgYGB7cn0NCnN1bUNsYXJpdHlJRiA8LSBzdW0oZGF0YTEkY2xhcml0eSA9PSAiSUYiKQ0KcF9oYXRfY2xhcml0eUlGIDwtIHN1bUNsYXJpdHlJRiAvIHN1bVRvdGFsDQpwX2hhdF9jbGFyaXR5SUYNCmBgYA0KDQojIyMjICoqS2nhu4NtIMSR4buLbmggdOG7tyBs4buHIDEgbeG6q3UqKg0KDQoqKkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oKioNCg0KLSAqKkgwOioqIHAg4omlIDAuMDUgKFThu7cgbOG7hyBraW0gY8awxqFuZyAiSUYiIGtow7RuZyBuaOG7jyBoxqFuIDUlKQ0KLSAqKkgxOioqIHAgPCAwLjA1IChU4bu3IGzhu4cga2ltIGPGsMahbmcgIklGIiBuaOG7jyBoxqFuIDUlKQ0KDQpUaeG6v24gaMOgbmgga2nhu4NtIMSR4buLbmggbeG7mXQgcGjDrWEgduG7m2kgbeG7qWMgw70gbmdoxKlhIM6xID0gMC4wNS4NCg0KYGBge3J9DQpwcm9wLnRlc3QoeCA9IHN1bUNsYXJpdHlJRiwgbiA9IHN1bVRvdGFsLCBwID0gMC4wNSwgY29uZi5sZXZlbCA9IDAuOTUsIGNvcnJlY3QgPSBUUlVFLCBhbHRlcm5hdGl2ZSA9ICJsZXNzIikNCmBgYA0KDQoqKkvhur90IHF14bqjIGtp4buDbSDEkeG7i25oOioqDQoNCi0gR2nDoSB0cuG7iyB0aOG7kW5nIGvDqiAoWC1zcXVhcmVkKTogNDcxLjYxDQotIEdpw6EgdHLhu4sgcCAocC12YWx1ZSk6IDwgMi4yZS0xNiAocuG6pXQgZ+G6p24gMCkNCi0gxq/hu5tjIGzGsOG7o25nIHThu7cgbOG7hyB04burIG3huqt1IChwzIIpOiAwLjAzMzIyMjENCg0KKipL4bq/dCBsdeG6rW46KioNCg0KVuG7m2kgcC12YWx1ZSBj4buxYyBuaOG7jyAoPCAwLjA1KSwgY2jDum5nIHRhICoqYsOhYyBi4buPIGdp4bqjIHRodXnhur90IEgwKiouIEPDsyDEkeG7pyBi4bqxbmcgY2jhu6luZyB0aOG7kW5nIGvDqiDEkeG7gyBr4bq/dCBsdeG6rW4gcuG6sW5nIHThu7cgbOG7hyBraW0gY8awxqFuZyBjw7MgxJHhu5kgdHJvbmcgIklGIiB0aOG7sWMgc+G7sSBuaOG7jyBoxqFuIDUlLg0KDQotLS0NCg0KIyAqKlBow6JuIHTDrWNoIG3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgY8OhYyBiaeG6v24qKg0KDQojIyAqKlBow6JuIHTDrWNoIG3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgYGN1dGAgKGdpw6FjIGPhuq90KSB2w6AgYGNvbG9yYCAobcOgdSBz4bqvYykqKg0KDQoqKkPDonUgaOG7j2kgbmdoacOqbiBj4bupdToqKiAiQ2jhuqV0IGzGsOG7o25nIGdpw6FjIGPhuq90IGPhu6dhIGtpbSBjxrDGoW5nIGPDsyBsacOqbiBxdWFuIMSR4bq/biBtw6B1IHPhuq9jIGPhu6dhIG7DsyBraMO0bmc/Ig0KDQojIyMgKipUw6xuaCB0cuG6oW5nIGdpw6FjIGPhuq90IGPDsyDhuqNuaCBoxrDhu59uZyDEkeG6v24gbcOgdSBz4bqvYyBraMO0bmc/KioNCg0KKipC4bqjbmcgdOG6p24gc+G7kSBjaMOpbyoqDQoNCmBgYHtyfQ0KdGFibGVfY3V0X2NvbG9yIDwtIHRhYmxlKGRhdGExJGN1dCwgZGF0YTEkY29sb3IpDQp0YWJsZV9jdXRfY29sb3INCmBgYA0KDQoqKlbhur0gYmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQojIENodXnhu4NuIHNhbmcgZOG6oW5nIGRhdGEgZnJhbWUgxJHhu4MgduG6vQ0KZGZfY3V0X2NvbG9yIDwtIGFzLmRhdGEuZnJhbWUodGFibGVfY3V0X2NvbG9yKQ0KY29sbmFtZXMoZGZfY3V0X2NvbG9yKSA8LSBjKCJDdXQiLCAiQ29sb3IiLCAiQ291bnQiKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIGPhu5l0IHRoZW8gbmjDs20NCmdncGxvdChkZl9jdXRfY29sb3IsIGFlcyh4ID0gQ29sb3IsIHkgPSBDb3VudCwgZmlsbCA9IEN1dCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBow6JuIGLhu5EgbcOgdSBz4bqvYyB0aGVvIGNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCIsDQogICAgeCA9ICJNw6B1IHPhuq9jIiwNCiAgICB5ID0gIlPhu5EgbMaw4bujbmciLA0KICAgIGZpbGwgPSAiQ2jhuqV0IGzGsOG7o25nIGdpw6FjIGPhuq90Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KKipLaeG7g20gxJHhu4tuaCBjaGkgYsOsbmggcGjGsMahbmcqKg0KDQoqKkdp4bqjIHRodXnhur90IHRo4buRbmcga8OqKioNCg0KLSBHaeG6oyB0aHV54bq/dCBraMO0bmcgKEjigoApOiBLaMO0bmcgY8OzIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCB2w6AgbcOgdSBz4bqvYy4NCi0gR2nhuqMgdGh1eeG6v3QgxJHhu5FpIChI4oKBKTogQ8OzIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCB2w6AgbcOgdSBz4bqvYy4NCg0KYGBge3J9DQojIFRo4buxYyBoaeG7h24ga2nhu4NtIMSR4buLbmggQ2hpIGLDrG5oIHBoxrDGoW5nDQpjaGlzcV90ZXN0IDwtIGNoaXNxLnRlc3QodGFibGVfY3V0X2NvbG9yKQ0KY2hpc3FfdGVzdA0KYGBgDQoNCioqTmjhuq1uIHjDqXQga+G6v3QgcXXhuqMga2nhu4NtIMSR4buLbmg6KioNCg0KS2nhu4NtIMSR4buLbmggQ2hpIGLDrG5oIHBoxrDGoW5nIGNobyBr4bq/dCBxdeG6ozoNCi0gR2nDoSB0cuG7iyB0aOG7kW5nIGvDqiBDaGktc3F1YXJlZCA9IDEzNTguNQ0KLSBC4bqtYyB04buxIGRvIChkZikgPSAyNA0KLSBHacOhIHRy4buLIHAtdmFsdWU6IDwgMi4yZS0xNiAocuG6pXQgZ+G6p24gMCkNCg0KVsOsIHAtdmFsdWUgPCAwLjA1LCB0YSAqKmLDoWMgYuG7jyBnaeG6oyB0aHV54bq/dCBIMCoqLiBEbyDEkcOzLCBjw7MgdGjhu4Mga+G6v3QgbHXhuq1uIHLhurFuZyAqKmNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCB2w6AgbcOgdSBz4bqvYyBj4bunYSBraW0gY8awxqFuZyBjw7MgbeG7kWkgbGnDqm4gaOG7hyBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqKiogduG7m2kgbmhhdS4NCg0KIyMjICoqU28gc8OhbmggdOG7tyBs4buHIGtpbSBjxrDGoW5nIG3DoHUgRCAodOG7kXQgbmjhuqV0KSBnaeG7r2EgbmjDs20gY+G6r3QgSWRlYWwgdsOgIFByZW1pdW0qKg0KDQoqKkPDonUgaOG7j2k6KiogTGnhu4d1IGtpbSBjxrDGoW5nIGPhuq90IGBJZGVhbGAgY8OzIGto4bqjIG7Eg25nIGzDoCBtw6B1IGBEYCBjYW8gaMahbiBzbyB24bubaSBraW0gY8awxqFuZyBj4bqvdCBgUHJlbWl1bWAga2jDtG5nPw0KDQoqKlThuqFvIGLhuqNuZyB04bqnbiBz4buRIG3hu5tpKioNCg0KYGBge3J9DQojIFThuqFvIGLhuqNuZyAyeDI6IENvbG9yIChEIHZzIE5vdCBEKSB+IEN1dCAoSWRlYWwgdnMgUHJlbWl1bSkNCnRhYmxlX2RfdnNfbm90ZCA8LSB0YWJsZSgNCiAgQ3V0ID0gZmFjdG9yKGRhdGExJGN1dCwgbGV2ZWxzID0gYygiSWRlYWwiLCAiUHJlbWl1bSIpKSwNCiAgQ29sb3IgPSBpZmVsc2UoZGF0YTEkY29sb3IgPT0gIkQiLCAiRCIsICJOb3RfRCIpDQopDQoNCiMgQ2jhu4kgbOG6pXkgMiBuaMOzbSBj4bqvdCBxdWFuIHTDom0NCnRhYmxlX2RfdnNfbm90ZCA8LSB0YWJsZV9kX3ZzX25vdGRbYygiSWRlYWwiLCAiUHJlbWl1bSIpLF0NCnByaW50KHRhYmxlX2RfdnNfbm90ZCkNCmBgYA0KDQoqKlTDrW5oIFJlbGF0aXZlIFJpc2sgdsOgIE9kZHMgUmF0aW8qKg0KDQpgYGB7cn0NCiMgVMOtbmggUlIsIG5ow7NtIHBoxqFpIG5oaeG7hW0gbMOgICdJZGVhbCcNCnJyX3Jlc3VsdCA8LSByaXNrcmF0aW8odGFibGVfZF92c19ub3RkKQ0KcHJpbnQocnJfcmVzdWx0JG1lYXN1cmUpDQoNCiMgVMOtbmggT1INCm9yX3Jlc3VsdCA8LSBvZGRzcmF0aW8odGFibGVfZF92c19ub3RkKQ0KcHJpbnQob3JfcmVzdWx0JG1lYXN1cmUpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQotICoqUmVsYXRpdmUgUmlzayAoUlIpID0gMC43NzgqKjogVOG7tyBs4buHIGPDsyBtw6B1IEQg4bufIG5ow7NtIGBQcmVtaXVtYCBjaOG7iSBi4bqxbmcgMC43NzggbOG6p24gKHThu6ljIGzDoCB0aOG6pXAgaMahbiBraG/huqNuZyAyMi4yJSkgc28gduG7m2kgdOG7tyBs4buHIGPDsyBtw6B1IEQg4bufIG5ow7NtIGBJZGVhbGAuDQotICoqT2RkcyBSYXRpbyAoT1IpID0gMC43NDkqKjogVOG7tyBs4buHIMSR4buDIG3hu5l0IHZpw6puIGtpbSBjxrDGoW5nIGPDsyBtw6B1IEQg4bufIG5ow7NtIGBQcmVtaXVtYCBi4bqxbmcgMC43NDkgbOG6p24gc28gduG7m2kgbmjDs20gYElkZWFsYC4NCg0KQ+G6oyBoYWkgY2jhu4kgc+G7kSDEkeG7gXUgY2hvIHRo4bqleSBraW0gY8awxqFuZyBjw7MgZ2nDoWMgY+G6r3QgYElkZWFsYCBjw7MgeHUgaMaw4bubbmcgbMOgIG3DoHUgYERgIGNhbyBoxqFuIHNvIHbhu5tpIGtpbSBjxrDGoW5nIGPDsyBnacOhYyBj4bqvdCBgUHJlbWl1bWAuDQoNCi0tLQ0KDQojIyAqKlBow6JuIHTDrWNoIG3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgYGNsYXJpdHlgICjEkeG7mSB0cm9uZykgdsOgIGBjdXRgIChnacOhYyBj4bqvdCkqKg0KDQoqKkPDonUgaOG7j2kgbmdoacOqbiBj4bupdToqKiAixJDhu5kgdHJvbmcgY+G7p2Ega2ltIGPGsMahbmcgY8OzIOG6o25oIGjGsOG7n25nIMSR4bq/biBjaOG6pXQgbMaw4bujbmcgZ2nDoWMgY+G6r3Qga2jDtG5nPyBD4bulIHRo4buDLCBraW0gY8awxqFuZyBjw7MgxJHhu5kgdHJvbmcgY2FvIGPDsyBuaGnhu4F1IGto4bqjIG7Eg25nIG5o4bqtbiDEkcaw4bujYyBnacOhYyBj4bqvdCBgSWRlYWxgIGjGoW4ga2jDtG5nPyINCg0KIyMjICoqxJDhu5kgdHJvbmcgY8OzIOG6o25oIGjGsOG7n25nIMSR4bq/biBjaOG6pXQgbMaw4bujbmcgZ2nDoWMgY+G6r3Qga2jDtG5nPyoqDQoNCioqQuG6o25nIHThuqduIHPhu5EgY2jDqW8qKg0KDQpgYGB7cn0NCnRhYmxlX2NsYXJpdHlfY3V0IDwtIHRhYmxlKGRhdGExJGNsYXJpdHksIGRhdGExJGN1dCkNCnRhYmxlX2NsYXJpdHlfY3V0DQpgYGANCg0KKipW4bq9IGJp4buDdSDEkeG7kyoqDQoNCmBgYHtyfQ0KZGZfY2xhcml0eV9jdXQgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZV9jbGFyaXR5X2N1dCkNCmNvbG5hbWVzKGRmX2NsYXJpdHlfY3V0KSA8LSBjKCJDbGFyaXR5IiwgIkN1dCIsICJDb3VudCIpDQoNCmdncGxvdChkZl9jbGFyaXR5X2N1dCwgYWVzKHggPSBDdXQsIHkgPSBDb3VudCwgZmlsbCA9IENsYXJpdHkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJmaWxsIikgKyAjIETDuW5nIHBvc2l0aW9uPSJmaWxsIiDEkeG7gyB4ZW0gdOG7tyBs4buHDQogIGxhYnMoDQogICAgdGl0bGUgPSAiVOG7tyBs4buHIGPDoWMgbG/huqFpIMSR4buZIHRyb25nIHRoZW8gY2jhuqV0IGzGsOG7o25nIGdpw6FjIGPhuq90IiwNCiAgICB4ID0gIkNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCIsDQogICAgeSA9ICJU4bu3IGzhu4ciLA0KICAgIGZpbGwgPSAixJDhu5kgdHJvbmciDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KDQoqKktp4buDbSDEkeG7i25oIGNoaSBiw6xuaCBwaMawxqFuZyoqDQoNCioqR2nhuqMgdGh1eeG6v3QgdGjhu5FuZyBrw6oqKg0KDQotIEdp4bqjIHRodXnhur90IGtow7RuZyAoSOKCgCk6IEtow7RuZyBjw7MgbeG7kWkgbGnDqm4gaOG7hyBnaeG7r2EgxJHhu5kgdHJvbmcgdsOgIGNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdC4NCi0gR2nhuqMgdGh1eeG6v3QgxJHhu5FpIChI4oKBKTogQ8OzIG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIMSR4buZIHRyb25nIHbDoCBjaOG6pXQgbMaw4bujbmcgZ2nDoWMgY+G6r3QuDQoNCmBgYHtyfQ0KY2hpc3FfdGVzdF9jbGFyaXR5IDwtIGNoaXNxLnRlc3QodGFibGVfY2xhcml0eV9jdXQpDQpjaGlzcV90ZXN0X2NsYXJpdHkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0IGvhur90IHF14bqjIGtp4buDbSDEkeG7i25oOioqDQoNClbhu5tpIHAtdmFsdWUgPCAyLjJlLTE2IChy4bqldCBn4bqnbiAwKSwgdGEgKipiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3QgSDAqKi4gS+G6v3QgbHXhuq1uIHLhurFuZyBjw7MgbeG7kWkgbGnDqm4gaOG7hyBy4bqldCBt4bqhbmggbeG6vSB2w6AgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiBnaeG7r2EgxJHhu5kgdHJvbmcgdsOgIGNo4bqldCBsxrDhu6NuZyBnacOhYyBj4bqvdCBj4bunYSBraW0gY8awxqFuZy4NCg0KVOG7qyBiaeG7g3UgxJHhu5MgdOG7tyBs4buHLCB0YSBjw7MgdGjhu4MgdGjhuqV5IG3hu5l0IHh1IGjGsOG7m25nIHRow7ogduG7izogbmjhu69uZyB2acOqbiBraW0gY8awxqFuZyBjw7MgxJHhu5kgdHJvbmcgdGjhuqVwIChuaMawIGBTSTJgLCBgSTFgKSB0aMaw4budbmcgY8OzIGdpw6FjIGPhuq90IGBGYWlyYCBob+G6t2MgYEdvb2RgIG5oaeG7gXUgaMahbi4gTmfGsOG7o2MgbOG6oWksIG5o4buvbmcgdmnDqm4ga2ltIGPGsMahbmcgY8OzIMSR4buZIHRyb25nIGNhbyAoYFZWUzJgLCBgVlZTMWApIGzhuqFpIGPDsyB04bu3IGzhu4cgZ2nDoWMgY+G6r3QgYElkZWFsYCBy4bqldCBjYW8uIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgZG8gY8OhYyBuaMOgIGNo4bq/IHTDoWMgbXXhu5FuIHThu5FpIMSRYSBow7NhIHbhursgxJHhurlwIGPhu6dhIG5o4buvbmcgdmnDqm4ga2ltIGPGsMahbmcgduG7kW4gxJHDoyBjw7MgxJHhu5kgdHJvbmcgdOG7kXQgYuG6sW5nIG3hu5l0IGdpw6FjIGPhuq90IGhvw6BuIGjhuqNvLg0KDQojIyMgKipTbyBzw6FuaCBraOG6oyBuxINuZyBuaOG6rW4gZ2nDoWMgY+G6r3QgYElkZWFsYCBnaeG7r2EgbmjDs20ga2ltIGPGsMahbmcgY8OzIMSR4buZIHRyb25nIGNhbyB2w6AgdGjhuqVwKioNCg0KxJDhu4MgbMaw4bujbmcgaMOzYSBt4buRaSBxdWFuIGjhu4cgbsOgeSwgY2jDum5nIHRhIHPhur0gc28gc8OhbmggaGFpIG5ow7NtOiBraW0gY8awxqFuZyBjw7MgxJHhu5kgdHJvbmcgY2FvIHbDoCBraW0gY8awxqFuZyBjw7MgxJHhu5kgdHJvbmcgdGjhuqVwLg0KDQotICoqTmjDs20gxJHhu5kgdHJvbmcgY2FvIChIaWdoIENsYXJpdHkpOioqIEJhbyBn4buTbSBgVlMyYCwgYFZTMWAsIGBWVlMyYCwgYFZWUzFgLCBgSUZgLg0KLSAqKk5ow7NtIMSR4buZIHRyb25nIHRo4bqlcCAoTG93IENsYXJpdHkpOioqIEJhbyBn4buTbSBgSTFgLCBgU0kyYCwgYFNJMWAuDQoNCioqVOG6oW8gYuG6o25nIHThuqduIHPhu5EgMngyKioNCg0KYGBge3J9DQojIFThuqFvIGPDoWMgYmnhur9uIG5ow7NtIG3hu5tpDQpkYXRhMV9ncm91cGVkIDwtIGRhdGExICU+JQ0KICBtdXRhdGUoDQogICAgY2xhcml0eV9ncm91cCA9IGZhY3RvcigNCiAgICAgIGNhc2Vfd2hlbigNCiAgICAgICAgY2xhcml0eSAlaW4lIGMoIkkxIiwgIlNJMiIsICJTSTEiKSB+ICJMb3cgQ2xhcml0eSIsDQogICAgICAgIGNsYXJpdHkgJWluJSBjKCJWUzIiLCAiVlMxIiwgIlZWUzIiLCAiVlZTMSIsICJJRiIpIH4gIkhpZ2ggQ2xhcml0eSINCiAgICAgICksDQogICAgICBsZXZlbHMgPSBjKCJIaWdoIENsYXJpdHkiLCAiTG93IENsYXJpdHkiKSAjIMSQ4bq3dCBIaWdoIENsYXJpdHkgbMOgbSBuaMOzbSB0aGFtIGNoaeG6v3UgKHBoxqFpIG5oaeG7hW0pDQogICAgKSwNCiAgICBjdXRfaWRlYWwgPSBmYWN0b3IoDQogICAgICBpZmVsc2UoY3V0ID09ICJJZGVhbCIsICJJZGVhbCIsICJOb3QgSWRlYWwiKSwNCiAgICAgIGxldmVscyA9IGMoIklkZWFsIiwgIk5vdCBJZGVhbCIpICMgxJDhurd0ICdJZGVhbCcgbMOgIHPhu7Ega2nhu4duIHF1YW4gdMOibQ0KICAgICkNCiAgKQ0KDQojIFThuqFvIGLhuqNuZyB04bqnbiBz4buRIGNow6lvIDJ4Mg0KdGFibGVfY2xhcml0eV9pZGVhbF9jdXQgPC0gdGFibGUoZGF0YTFfZ3JvdXBlZCRjbGFyaXR5X2dyb3VwLCBkYXRhMV9ncm91cGVkJGN1dF9pZGVhbCkNCnByaW50KHRhYmxlX2NsYXJpdHlfaWRlYWxfY3V0KQ0KYGBgDQoNCioqVMOtbmggUmVsYXRpdmUgUmlzayAoUlIpKioNCg0KYGBge3J9DQojIFTDrW5oIFJSDQpycl9jbGFyaXR5X2N1dCA8LSByaXNrcmF0aW8odGFibGVfY2xhcml0eV9pZGVhbF9jdXQpDQpwcmludChycl9jbGFyaXR5X2N1dCRtZWFzdXJlKQ0KYGBgDQoNCioqVMOtbmggT2RkcyBSYXRpbyAoT1IpKioNCg0KYGBge3J9DQojIFTDrW5oIE9SDQpvcl9jbGFyaXR5X2N1dCA8LSBvZGRzcmF0aW8odGFibGVfY2xhcml0eV9pZGVhbF9jdXQpDQpwcmludChvcl9jbGFyaXR5X2N1dCRtZWFzdXJlKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQqKg0KDQotICoqUmVsYXRpdmUgUmlzayAoUlIpID0gMS4zNDUqKiAoS1RDIDk1JTogWzEuMzI1LCAxLjM2NV0pOg0KVOG7tyBs4buHIG3hu5l0IHZpw6puIGtpbSBjxrDGoW5nIG5o4bqtbiDEkcaw4bujYyBnacOhYyBj4bqvdCBgSWRlYWxgIOG7nyBuaMOzbSAqKsSR4buZIHRyb25nIGNhbyoqIGNhbyBn4bqlcCAqKjEuMzQ1IGzhuqduKiogc28gduG7m2kgbmjDs20gY8OzIMSR4buZIHRyb25nIHRo4bqlcC4gTsOzaSBjw6FjaCBraMOhYywga2ltIGPGsMahbmcgxJHhu5kgdHJvbmcgY2FvIGPDsyBraOG6oyBuxINuZyDEkcaw4bujYyBj4bqvdCBgSWRlYWxgIGNhbyBoxqFuIDM0LjUlIHNvIHbhu5tpIGtpbSBjxrDGoW5nIMSR4buZIHRyb25nIHRo4bqlcC4NCg0KLSAqKk9kZHMgUmF0aW8gKE9SKSA9IDEuNjMxKiogKEtUQyA5NSU6IFsxLjU4OSwgMS42NzRdKToNClThu7cgbOG7hyDEkeG7gyBt4buZdCB2acOqbiBraW0gY8awxqFuZyBjw7MgZ2nDoWMgY+G6r3QgYElkZWFsYCDhu58gbmjDs20gKirEkeG7mSB0cm9uZyBjYW8qKiBjYW8gZ+G6pXAgKioxLjYzMSBs4bqnbioqIHNvIHbhu5tpIG9kZHMg4bufIG5ow7NtIGPDsyDEkeG7mSB0cm9uZyB0aOG6pXAuDQoNCioqS+G6v3QgbHXhuq1uIHThu5VuZyB0aOG7gzoqKg0KDQpD4bqjIGhhaSBjaOG7iSBz4buRIFJSIHbDoCBPUiDEkeG7gXUgbOG7m24gaMahbiAxIG3hu5l0IGPDoWNoIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ouIMSQaeG7gXUgbsOgeSBj4bunbmcgY+G7kSBt4bqhbmggbeG6vSBjaG8ga+G6v3QgbHXhuq1uIHThu6sgYmnhu4N1IMSR4buTIHbDoCBraeG7g20gxJHhu4tuaCBDaGkgYsOsbmggcGjGsMahbmc6ICoqS2ltIGPGsMahbmcgY8OzIMSR4buZIHRyb25nIGPDoG5nIGNhbyB0aMOsIGPDoG5nIGPDsyBuaGnhu4F1IGto4bqjIG7Eg25nIMSRxrDhu6NjIMawdSB0acOqbiBjaOG6vyB0w6FjIHbhu5tpIGdpw6FjIGPhuq90IGBJZGVhbGAgxJHhu4MgdOG7kWkgxJFhIGjDs2EgZ2nDoSB0cuG7iyB2w6AgduG6uyDEkeG6uXAgY+G7p2EgbsOzLioqDQoNCiMgKipQaMawxqFuZyBwaMOhcCDGr+G7m2MgbMaw4bujbmcgSOG7o3AgbMO9IFThu5FpIMSRYSAoTWF4aW11bSBMaWtlbGlob29kIEVzdGltYXRpb24g4oCTIE1MRSkqKg0KDQojIyAqKkdp4bubaSB0aGnhu4d1IGNodW5nKioNCg0KVHJvbmcgdGjhu5FuZyBrw6ogdsOgIGjhu41jIG3DoXksIGThu68gbGnhu4d1IHRoxrDhu51uZyDEkcaw4bujYyBtw7QgaMOsbmggaMOzYSB0aMO0bmcgcXVhIGPDoWMgKipwaMOibiBwaOG7kWkgeMOhYyBzdeG6pXQqKi4gTeG7mXQgcGjDom4gcGjhu5FpIHjDoWMgc3XhuqV0IMSRxrDhu6NjIMSR4bq3YyB0csawbmcgYuG7n2kgbeG7mXQgc+G7kSAqKnRoYW0gc+G7kSoqLCB2w60gZOG7pSBuaMawOg0KDQotIFBow6JuIHBo4buRaSBjaHXhuqluIChHYXVzc2lhbik6ICRcbXUkICh0cnVuZyBiw6xuaCksICRcc2lnbWFeMiQgKHBoxrDGoW5nIHNhaSkuDQotIFBow6JuIHBo4buRaSBQb2lzc29uOiB0aGFtIHPhu5EgxJHhurdjIHRyxrBuZyBsw6AgJFxsYW1iZGEkLg0KDQpO4bq/dSB0YSDEkcOjIGJp4bq/dCDEkcaw4bujYyBk4bqhbmcgY+G7p2EgcGjDom4gcGjhu5FpIHjDoWMgc3XhuqV0LCB24bqlbiDEkeG7gSDEkeG6t3QgcmEgbMOgOiAqKmzDoG0gc2FvIHTDrG0gxJHGsOG7o2MgY8OhYyB0aGFtIHPhu5EgbcO0IHThuqMgcGjDom4gcGjhu5FpIMSRw7MgbeG7mXQgY8OhY2ggcGjDuSBo4bujcCBuaOG6pXQgduG7m2kgZOG7ryBsaeG7h3UgcXVhbiBzw6F0PyoqIMSQw7MgY2jDrW5oIGzDoCBuaGnhu4dtIHbhu6UgY+G7p2EgcGjGsMahbmcgcGjDoXAgKirGsOG7m2MgbMaw4bujbmcgaOG7o3AgbMO9IHThu5FpIMSRYSAoTWF4aW11bSBMaWtlbGlob29kIEVzdGltYXRpb24g4oCTIE1MRSkqKi4NCg0KTUxFIGzDoCBt4buZdCBjw7RuZyBj4bulIGPEg24gYuG6o24gdsOgIHF1YW4gdHLhu41uZyB0cm9uZyB0aOG7kW5nIGvDqiBzdXkgZGnhu4VuIHbDoCBo4buNYyBtw6F5LCBnacO6cCBjaMO6bmcgdGEgdMOsbSByYSBjw6FjIHRoYW0gc+G7kSBtw7QgaMOsbmggc2FvIGNobyAqKnBow6JuIHBo4buRaSB4w6FjIHN14bqldCBzaW5oIHJhIGThu68gbGnhu4d1IGzDoCAicGjDuSBo4bujcCBuaOG6pXQiIHbhu5tpIHRo4buxYyB04bq/IMSRw6MgcXVhbiBzw6F0KiouDQoNCiMjICoqTeG7pWMgdGnDqnUgdsOgIG5ndXnDqm4gbMO9IGPhu6dhIE1MRSoqDQoNCiMjIyAqKktow6FpIG5p4buHbSBow6BtIGjhu6NwIGzDvSAoTGlrZWxpaG9vZCBGdW5jdGlvbikqKg0KDQoqKkjDoG0gaOG7o3AgbMO9KiogKGxpa2VsaWhvb2QgZnVuY3Rpb24pIMSRbyBsxrDhu51uZyAqKm3hu6ljIMSR4buZIHBow7kgaOG7o3AgY+G7p2EgbcO0IGjDrG5oICh0aGFtIHPhu5EpIHbhu5tpIGThu68gbGnhu4d1IMSRw6MgcXVhbiBzw6F0KiouIFThu6ljIGzDoCwgduG7m2kgbeG7mXQgbcO0IGjDrG5oIHjDoWMgc3XhuqV0IGPDsyB0aGFtIHPhu5EgJFxtYXRoYmZ7d30kLCBow6BtIGjhu6NwIGzDvSBjaG8gYmnhur90ICoqeMOhYyBzdeG6pXQgxJHhu4MgdG/DoG4gYuG7mSB04bqtcCBk4buvIGxp4buHdSAkXG1hdGhjYWx7RH0kIHjhuqN5IHJhKiosIGTGsOG7m2kgZ2nhuqMgxJHhu4tuaCBy4bqxbmcgZOG7ryBsaeG7h3UgxJHGsOG7o2Mgc2luaCByYSB04burIG3DtCBow6xuaCDEkcOzLg0KDQpHaeG6oyBz4butIGPDsyBt4buZdCBi4buZIGThu68gbGnhu4d1IGfhu5NtICROJCBxdWFuIHPDoXQgxJHhuqd1IHbDoG86DQoNCiQkDQpcbWF0aGNhbHtEfSA9IFx7IFxtYXRoYmZ7eH1fMSwgXG1hdGhiZnt4fV8yLCBcbGRvdHMsIFxtYXRoYmZ7eH1fTiBcfQ0KJCQNCg0KdsOgIG3DtCBow6xuaCBwaMOibiBwaOG7kWkgeMOhYyBzdeG6pXQgJFAoXG1hdGhiZnt4fXxcbWF0aGJme3d9KSQgcGjhu6UgdGh14buZYyB2w6BvIHRoYW0gc+G7kQ0KDQokJA0KXG1hdGhiZnt3fSA9ICh3XzEsIHdfMiwgXGxkb3RzLCB3X2spXlQNCiQkDQoNCktoaSDEkcOzLCAqKmjDoG0gaOG7o3AgbMO9KiogxJHGsOG7o2MgxJHhu4tuaCBuZ2jEqWEgbMOgOg0KDQokJA0KTChcbWF0aGJme3d9KSA9IFAoXG1hdGhjYWx7RH18XG1hdGhiZnt3fSkgPSBQKFxtYXRoYmZ7eH1fMSwgXG1hdGhiZnt4fV8yLCBcbGRvdHMsIFxtYXRoYmZ7eH1fTnxcbWF0aGJme3d9KQ0KJCQNCg0KTuG6v3UgY8OhYyBxdWFuIHPDoXQgJFxtYXRoYmZ7eH1faSQgbMOgICoqxJHhu5ljIGzhuq1wIHbDoCBwaMOibiBwaOG7kWkgZ2nhu5FuZyBuaGF1IChpLmkuZCDigJMgaW5kZXBlbmRlbnQgYW5kIGlkZW50aWNhbGx5IGRpc3RyaWJ1dGVkKSoqLCB0aMOsIGjDoG0gaOG7o3AgbMO9IGPDsyB0aOG7gyB2aeG6v3QgbOG6oWkgdGjDoG5oOg0KDQokJA0KTChcbWF0aGJme3d9KSA9IFxwcm9kX3tpPTF9XntOfSBQKFxtYXRoYmZ7eH1faXxcbWF0aGJme3d9KQ0KJCQNCg0KIyMjICoqTmd1ecOqbiBsw70gdOG7kWkgxJFhIGjDs2EgaOG7o3AgbMO9KioNCg0KTmd1ecOqbiBsw70gY+G7kXQgbMO1aSBj4bunYSBNTEUgbMOgIGNo4buNbiBnacOhIHRy4buLIHRoYW0gc+G7kSAkXGhhdHtcbWF0aGJme3d9fSQgc2FvIGNobyAqKmjDoG0gaOG7o3AgbMO9IMSR4bqhdCBnacOhIHRy4buLIGzhu5tuIG5o4bqldCoqLiBOw7NpIGPDoWNoIGtow6FjLCB0YSB0w6xtIHRoYW0gc+G7kSBtw6AgKipkxrDhu5tpIG7DsyB0aMOsIHjDoWMgc3XhuqV0IHThuqFvIHJhIGThu68gbGnhu4d1IHF1YW4gc8OhdCBsw6AgY2FvIG5o4bqldCoqOg0KDQokJA0KXGhhdHtcbWF0aGJme3d9fSA9IFxhcmdcbWF4X3tcbWF0aGJme3d9fSBMKFxtYXRoYmZ7d30pDQokJA0KDQpUdXkgbmhpw6puLCB2aeG7h2MgdOG7kWkgxrB1IG3hu5l0IHTDrWNoIGzhu5tuIGPDoWMgeMOhYyBzdeG6pXQgbmjGsCB24bqteSB0aMaw4budbmcga2jDtG5nIHRodeG6rW4gdGnhu4duLiBWw6wgduG6rXksIHRhIHRoxrDhu51uZyAqKmzhuqV5IGxvZyoqIGPhu6dhIGjDoG0gaOG7o3AgbMO9IMSR4buDIHRodSDEkcaw4bujYyAqKmjDoG0gbG9nLWjhu6NwIGzDvSAobG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24pKio6DQoNCiQkDQpcZWxsKFxtYXRoYmZ7d30pID0gXGxvZyBMKFxtYXRoYmZ7d30pID0gXHN1bV97aT0xfV57Tn0gXGxvZyBQKFxtYXRoYmZ7eH1faXxcbWF0aGJme3d9KQ0KJCQNCg0KRG8gaMOgbSBsb2cgbMOgIMSRxqFuIMSRaeG7h3UgdMSDbmcsIG7Dqm4gxJFp4buDbSBj4buxYyDEkeG6oWkgY+G7p2EgJFxlbGwoXG1hdGhiZnt3fSkkIGPFqW5nIGNow61uaCBsw6AgY+G7sWMgxJHhuqFpIGPhu6dhICRMKFxtYXRoYmZ7d30pJC4gVuG6rXkgbsOqbjoNCg0KJCQNClxoYXR7XG1hdGhiZnt3fX0gPSBcYXJnXG1heF97XG1hdGhiZnt3fX0gXGVsbChcbWF0aGJme3d9KQ0KJCQNCg0KIyMgKipUw7NtIHThuq90IHF1eSB0csOsbmggTUxFKioNCg0KfCAqKkLGsOG7m2MqKiB8ICoqTcO0IHThuqMqKiB8DQp8LS0tLS0tLS0tfC0tLS0tLS0tLS0tfA0KfCBCxrDhu5tjIDEgfCBYw6FjIMSR4buLbmggbcO0IGjDrG5oIHjDoWMgc3XhuqV0ICRQKHh8XG1hdGhiZnt3fSkkIHbDoCBnaeG6oyDEkeG7i25oIGThu68gbGnhu4d1IMSR4buZYyBs4bqtcCAoaS5pLmQpLiB8DQp8IELGsOG7m2MgMiB8IFZp4bq/dCBow6BtIGjhu6NwIGzDvSAkTChcbWF0aGJme3d9KSQgaG/hurdjIGxvZy1o4bujcCBsw70gJFxlbGwoXG1hdGhiZnt3fSkkLiB8DQp8IELGsOG7m2MgMyB8IFTDrW5oIMSR4bqhbyBow6BtIGPhu6dhICRcZWxsKFxtYXRoYmZ7d30pJCB0aGVvICRcbWF0aGJme3d9JCwgcuG7k2kgZ2nhuqNpIHBoxrDGoW5nIHRyw6xuaCDEkeG6oW8gaMOgbSBi4bqxbmcgMC4gfA0KfCBCxrDhu5tjIDQgfCBLaeG7g20gdHJhIMSRaeG7gXUga2nhu4duIHThu5FpIMawdSAoxJHhuqFvIGjDoG0gYuG6rWMgaGFpLCB0w61uaCBs4buTaSwgdi52LikuIHwNCnwgQsaw4bubYyA1IHwgS+G6v3QgbHXhuq1uICRcaGF0e1xtYXRoYmZ7d319JCBsw6AgxrDhu5tjIGzGsOG7o25nIE1MRS4gfA0KDQojIyAqKk3DtCBow6xuaCBow7NhIGLDoGkgdG/DoW4gZMaw4bubaSBk4bqhbmcgdG/DoW4gaOG7jWMqKg0KDQpUcm9uZyB0csaw4budbmcgaOG7o3AgZOG7ryBsaeG7h3UgcGjDom4gcGjhu5FpIGkuaS5kLCBiw6BpIHRvw6FuIE1MRSB0cuG7nyB0aMOgbmg6DQoNCiQkDQpcaGF0e1xtYXRoYmZ7d319ID0gXGFyZ1xtYXhfe1xtYXRoYmZ7d319IFxzdW1fe2k9MX1ee059IFxsb2cgUChcbWF0aGJme3h9X2l8XG1hdGhiZnt3fSkNCiQkDQoNCsSQw6J5IGzDoCBt4buZdCBiw6BpIHRvw6FuIHThu5FpIMawdSBow7NhIGPDsyB0aOG7gyBnaeG6o2kgYuG6sW5nOg0KDQotIMSQ4bqhbyBow6BtIHTGsOG7nW5nIG1pbmggKG7hur91IGPDsyB0aOG7gyksDQotIEdyYWRpZW50IERlc2NlbnQgLyBOZXd0b24tUmFwaHNvbiAodHJvbmcgdHLGsOG7nW5nIGjhu6NwIHBo4bupYyB04bqhcCksDQotIEvhu7kgdGh14bqtdCB04buRaSDGsHUgaMOzYSBz4buRLg0KDQojIyAqKlTDrW5oIGNo4bqldCBj4bunYSDGsOG7m2MgbMaw4bujbmcgTUxFKioNCg0KfCAqKlTDrW5oIGNo4bqldCoqIHwgKipNw7QgdOG6oyoqIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS18DQp8ICoqTmjhuqV0IHF1w6FuIChDb25zaXN0ZW5jeSkqKiB8IEtoaSAkTiBcdG8gXGluZnR5JCwgTUxFIGjhu5lpIHThu6UgduG7gSDEkcO6bmcgdGhhbSBz4buRIHRo4buxYyBz4buxLiB8DQp8ICoqQuG6pXQgYmnhur9uIChJbnZhcmlhbmNlKSoqIHwgTuG6v3UgJFxoYXR7XHRoZXRhfSQgbMOgIE1MRSBj4bunYSAkXHRoZXRhJCwgdGjDrCAkZyhcaGF0e1x0aGV0YX0pJCBsw6AgTUxFIGPhu6dhICRnKFx0aGV0YSkkLiB8DQp8ICoqUGjDom4gcGjhu5FpIHRp4buHbSBj4bqtbiBjaHXhuqluKiogfCBNTEUgdGnhu4dtIGPhuq1uIHRoZW8gcGjDom4gcGjhu5FpIGNodeG6qW4ga2hpICROIFx0byBcaW5mdHkkLiB8DQp8ICoqS2jDtG5nIHRoacOqbiBs4buHY2ggdGnhu4dtIGPhuq1uKiogfCBLaGkgbeG6q3UgbOG7m24sIHNhaSBz4buRIHRydW5nIGLDrG5oIGPhu6dhIE1MRSB0aeG6v24gduG7gSAwLiB8DQoNCiMjICoqS+G6v3QgbHXhuq1uKioNCg0KUGjGsMahbmcgcGjDoXAgKirGsOG7m2MgbMaw4bujbmcgaOG7o3AgbMO9IHThu5FpIMSRYSAoTUxFKSoqIGzDoCBt4buZdCBjw7RuZyBj4bulIHRoZW4gY2jhu5F0IHRyb25nIHRo4buRbmcga8OqIHbDoCBo4buNYyBtw6F5LiBC4bqxbmcgY8OhY2ggdOG7kWkgxJFhIGjDs2EgeMOhYyBzdeG6pXQgc2luaCByYSBk4buvIGxp4buHdSDEkcOjIHF1YW4gc8OhdCwgTUxFIGjGsOG7m25nIHThu5tpIG3hu6VjIHRpw6p1IGNo4buNbiBtw7QgaMOsbmggcGjDuSBo4bujcCBuaOG6pXQgduG7m2kgdGjhu7FjIHThur8uIFBoxrDGoW5nIHBow6FwIG7DoHkgY8OzIGPGoSBz4bufIGzDvSB0aHV54bq/dCB24buvbmcgY2jhuq9jIHbDoCBjw7MgdGjhu4Mgw6FwIGThu6VuZyDEkeG7gyDGsOG7m2MgbMaw4bujbmcgdGhhbSBz4buRIGPhu6dhIG5oaeG7gXUgcGjDom4gcGjhu5FpIHBo4buVIGJp4bq/biBuaMawIEJlcm5vdWxsaSwgR2F1c3NpYW4sIFBvaXNzb24sIHYudi4=