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

# Đọc bộ dữ liệu
d <- read.csv("D:/naaaaaa/PTDLDT/Invistico_Airline.csv", header = T)
  • Bộ dữ liệu bao gồm thông tin chi tiết về những khách hàng đã từng bay cùng họ. Phản hồi của khách hàng về nhiều bối cảnh khác nhau và dữ liệu chuyến bay của họ đã được hợp nhất. Mục đích chính của bộ dữ liệu này là dự đoán liệu một khách hàng tương lai có hài lòng với dịch vụ của họ hay không dựa trên thông tin chi tiết về các giá trị tham số khác.

  • Ngoài ra, các hãng hàng không cần biết khía cạnh nào của các dịch vụ mà họ cung cấp phải được nhấn mạnh hơn để tạo ra nhiều khách hàng hài lòng hơn.

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

# Cấu trúc bộ dữ liệu
str(d)
## 'data.frame':    129880 obs. of  22 variables:
##  $ satisfaction                     : chr  "satisfied" "satisfied" "satisfied" "satisfied" ...
##  $ Gender                           : chr  "Female" "Male" "Female" "Female" ...
##  $ Customer.Type                    : chr  "Loyal Customer" "Loyal Customer" "Loyal Customer" "Loyal Customer" ...
##  $ Age                              : int  65 47 15 60 70 30 66 10 56 22 ...
##  $ Type.of.Travel                   : chr  "Personal Travel" "Personal Travel" "Personal Travel" "Personal Travel" ...
##  $ Class                            : chr  "Eco" "Business" "Eco" "Eco" ...
##  $ Flight.Distance                  : int  265 2464 2138 623 354 1894 227 1812 73 1556 ...
##  $ Seat.comfort                     : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Departure.Arrival.time.convenient: int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Food.and.drink                   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Gate.location                    : int  2 3 3 3 3 3 3 3 3 3 ...
##  $ Inflight.wifi.service            : int  2 0 2 3 4 2 2 2 5 2 ...
##  $ Inflight.entertainment           : int  4 2 0 4 3 0 5 0 3 0 ...
##  $ Online.support                   : int  2 2 2 3 4 2 5 2 5 2 ...
##  $ Ease.of.Online.booking           : int  3 3 2 1 2 2 5 2 4 2 ...
##  $ On.board.service                 : int  3 4 3 1 2 5 5 3 4 2 ...
##  $ Leg.room.service                 : int  0 4 3 0 0 4 0 3 0 4 ...
##  $ Baggage.handling                 : int  3 4 4 1 2 5 5 4 1 5 ...
##  $ Checkin.service                  : int  5 2 4 4 4 5 5 5 5 3 ...
##  $ Cleanliness                      : int  3 3 4 1 2 4 5 4 4 4 ...
##  $ Online.boarding                  : int  2 2 2 3 5 2 3 2 4 2 ...
##  $ Departure.Delay.in.Minutes       : int  0 310 0 0 0 0 17 0 0 30 ...

Bộ dữ liệu gồm 129.880 quan sát và 22 biến, thu thập thông tin về trải nghiệm khách hàng trên các chuyến bay thương mại, tập trung vào mức độ hài lòng và các yếu tố ảnh hưởng đến đánh giá của khách hàng.

  1. satisfaction (chr): Mức độ hài lòng của khách hàng. Gồm 2 giá trị: “satisfied” và “dissatisfied”.

  2. Gender (chr): Giới tính của hành khách: “Male” hoặc “Female”.

  3. Customer.Type (chr): Loại khách hàng: “Loyal Customer” (khách thân thiết) hoặc “disloyal Customer” (khách không thường xuyên).

  4. Age (int): Tuổi của hành khách (tính bằng năm).

  5. Type.of.Travel (chr): Mục đích chuyến đi: “Business travel” hoặc “Personal Travel”.

  6. Class (chr): Hạng ghế: “Eco”, “Eco Plus”, hoặc “Business”.

  7. Flight.Distance (int): Quãng đường bay (tính bằng dặm).

Các biến sau là đánh giá từ hành khách về trải nghiệm dịch vụ:

  1. Seat.comfort: Độ thoải mái ghế ngồi

  2. Departure.Arrival.time.convenient: Thuận tiện thời gian bay

  3. Food.and.drink: Đánh giá đồ ăn và thức uống

  4. Gate.location: Vị trí cổng lên máy bay

  5. Inflight.wifi.service: Dịch vụ wifi trên máy bay

  6. Inflight.entertainment: Giải trí trên máy bay

  7. Online.support: Hỗ trợ trực tuyến

  8. Ease.of.Online.booking: Dễ dàng khi đặt vé online

  9. On.board.service: Dịch vụ trên khoang

  10. Leg.room.service: Chỗ để chân

  11. Baggage.handling: Xử lý hành lý

  12. Checkin.service: Dịch vụ làm thủ tục check-in

  13. Cleanliness: Mức độ sạch sẽ

  14. Online.boarding: Trải nghiệm lên máy bay online

  15. Departure.Delay.in.Minutes (int): Thời gian trễ khởi hành (tính bằng phút).Giá trị lớn biểu thị chuyến bay bị trễ nhiều.

2. Kiểm tra dữ liệu thiếu

# Kiểm tra dữ liệu thiếu
sum(is.na(d))
## [1] 0

Khi thực hiện lệnh sum(is.na(data)), kết quả trả về là 0, cho thấy bộ dữ liệu hoàn toàn không chứa giá trị bị thiếu (NA).

3. Chuyển dạng dữ liệu

d$FlightRangeGroup <- cut(d$Flight.Distance,
                          breaks = c(0, 1000, 3500, Inf),
                          labels = c("Short-haul", "Medium-haul", "Long-haul"),
                          right = TRUE)
d$satisfaction <- as.factor(d$satisfaction)
d$Gender <- as.factor(d$Gender)
d$Customer.Type <- as.factor(d$Customer.Type)
d$Type.of.Travel <- as.factor(d$Type.of.Travel)
d$Class <- as.factor(d$Class)
summary(d$Flight.Distance)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##      50    1359    1925    1981    2544    6951
# Tạo biến định tính
bdt <- c( "satisfaction", "Gender", "Customer.Type", "Type.of.Travel", "Class", "FlightRangeGroup" )

# Tạo bộ dữ liệu mới chỉ có biến định tính
dt <- d[, bdt]

Các biến này được trích xuất và tạo thành một bộ dữ liệu con, dùng riêng cho phân tích định tính (bảng tần số, biểu đồ cột, kiểm định tỉ lệ, odds ratio, risk ratio…). Việc giới hạn phân tích vào các biến định tính giúp tập trung vào so sánh đặc điểm giữa các nhóm, đồng thời tránh sự phức tạp từ các biến định lượng trong phạm vi phân tích hiện tại.

Phần 2: Phân tích mô tả một biến Định tính

1. Satisfaction

# Lập bảng tần số
hailong <- table(dt$satisfaction)
hailong
## 
## dissatisfied    satisfied 
##        58793        71087
# Lập bảng tần suất
table(dt$satisfaction)/sum(nrow(dt))
## 
## dissatisfied    satisfied 
##    0.4526717    0.5473283
library(ggplot2)

# Đưa về dạng data frame
df_hailong <- as.data.frame(hailong)
colnames(df_hailong) <- c("satisfaction", "Count")

# Tính phần trăm và thêm vào data frame
df_hailong$Percent <- round(df_hailong$Count / sum(df_hailong$Count) * 100, 1)

# Tạo nhãn ghép với %
df_hailong$Label <- paste0(df_hailong$Percent, "%")

# Vẽ biểu đồ tròn
ggplot(df_hailong, aes(x = "", y = Count, fill = satisfaction)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar(theta = "y") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  labs(title = "Biểu đồ 1: Biểu đồ thể hiện mức độ hài lòng của khách hàng") +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5))

Biểu đồ thể hiện tỷ lệ giữa hai nhóm mức độ hài lòng cho thấy tỷ lệ hành khách không hài lòng chiếm khoảng 45,3%, trong khi số hài lòng chiếm khoảng 54,7%. Mặc dù nhóm hài lòng chiếm ưu thế, khoảng cách không quá lớn, cho thấy vẫn còn một tỷ lệ đáng kể hành khách chưa hài lòng. Điều này là dấu hiệu cần cải thiện chất lượng dịch vụ để tăng mức độ hài lòng chung.

2. Gender

# Lập bảng tần số
gioitinh <- table(dt$Gender)
gioitinh
## 
## Female   Male 
##  65899  63981
# Lập bảng tần suất
table(dt$Gender)/sum(nrow(dt))
## 
##    Female      Male 
## 0.5073837 0.4926163
library(ggplot2)

# Đưa về dạng data frame
df_gioitinh <- as.data.frame(gioitinh)
colnames(df_gioitinh) <- c("Gender", "Count")

# Tính phần trăm và thêm vào data frame
df_gioitinh$Percent <- round(df_gioitinh$Count / sum(df_gioitinh$Count) * 100, 1)

# Tạo nhãn ghép với %
df_gioitinh$Label <- paste0(df_gioitinh$Percent, "%")

# Vẽ biểu đồ tròn
ggplot(df_gioitinh, aes(x = "", y = Count, fill = Gender)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar(theta = "y") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  labs(title = "Biểu đồ 2: Biểu đồ thể hiện giới tính của khách hàng") +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5))

Tỷ lệ giới tính trong tập dữ liệu khá cân bằng, với nữ chiếm khoảng 50,7% và nam chiếm khoảng 49,3%. Sự phân bố gần như ngang nhau này giúp đảm bảo tính đại diện giữa hai giới khi phân tích các yếu tố liên quan đến mức độ hài lòng hoặc hành vi du lịch. Điều này cũng tạo điều kiện thuận lợi cho việc so sánh giới tính mà không bị thiên lệch.

3. Customer Type

# Lập bảng tần số
phanloai <- table(dt$Customer.Type)
phanloai
## 
## disloyal Customer    Loyal Customer 
##             23780            106100
# Lập bảng tần suất
table(dt$Customer.Type)/sum(nrow(dt))
## 
## disloyal Customer    Loyal Customer 
##         0.1830921         0.8169079
library(ggplot2)

# Đưa về dạng data frame
df_phanloai <- as.data.frame(phanloai)
colnames(df_phanloai) <- c("Customer.Type", "Count")

# Tính phần trăm và thêm vào data frame
df_phanloai$Percent <- round(df_phanloai$Count / sum(df_phanloai$Count) * 100, 1)

# Tạo nhãn ghép với %
df_phanloai$Label <- paste0(df_phanloai$Percent, "%")

# Vẽ biểu đồ tròn
ggplot(df_phanloai, aes(x = "", y = Count, fill = Customer.Type)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar(theta = "y") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  labs(title = "Biểu đồ 3: Biểu đồ thể hiện phân bố loại khách hàng") +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5))

Phần lớn khách hàng trong tập dữ liệu là khách hàng thân thiết (Loyal Customer), chiếm khoảng 81,7%, trong khi khách hàng không trung thành (Disloyal Customer) chỉ chiếm khoảng 18,3%. Sự chênh lệch này cho thấy nhóm khách hàng thân thiết là đối tượng chính trong khảo sát, và có thể ảnh hưởng đến mức độ hài lòng chung của toàn bộ dữ liệu. Đây cũng là yếu tố quan trọng cần xem xét khi phân tích hành vi hoặc cảm nhận dịch vụ.

4. Type of Travel

# Lập bảng tần số
mucdich <- table(dt$Type.of.Travel)
mucdich
## 
## Business travel Personal Travel 
##           89693           40187
# Lập bảng tần suất
table(dt$Type.of.Travel)/sum(nrow(dt))
## 
## Business travel Personal Travel 
##       0.6905836       0.3094164
library(ggplot2)

# Đưa về dạng data frame
df_mucdich <- as.data.frame(mucdich)
colnames(df_mucdich) <- c("Type.of.Travel", "Count")

# Tính phần trăm và thêm vào data frame
df_mucdich$Percent <- round(df_mucdich$Count / sum(df_mucdich$Count) * 100, 1)

# Tạo nhãn ghép với %
df_mucdich$Label <- paste0(df_mucdich$Percent, "%")

# Vẽ biểu đồ tròn
ggplot(df_mucdich, aes(x = "", y = Count, fill = Type.of.Travel)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar(theta = "y") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  labs(title = "Biểu đồ 4: Biểu đồ thể hiện mục đích bay của khách hàng") +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5))

Đa số hành khách trong bộ dữ liệu thực hiện Business Travel (công tác), chiếm khoảng 69%, trong khi Personal Travel (du lịch cá nhân) chiếm khoảng 31%. Điều này cho thấy mẫu dữ liệu thiên về nhóm khách đi công tác, và có thể ảnh hưởng đến mức độ hài lòng hoặc các yếu tố dịch vụ được đánh giá, vì mục đích chuyến đi thường ảnh hưởng đến kỳ vọng và trải nghiệm của khách hàng.

5. Class

# Lập bảng tần số
hangve <- table(dt$Class)
hangve
## 
## Business      Eco Eco Plus 
##    62160    58309     9411
# Lập bảng tần suất
table(dt$Class)/sum(nrow(dt))
## 
##   Business        Eco   Eco Plus 
## 0.47859563 0.44894518 0.07245919
library(ggplot2)

# Đưa về dạng data frame
df_hangve <- as.data.frame(hangve)
colnames(df_hangve) <- c("Class", "Count")

# Tính phần trăm và thêm vào data frame
df_hangve$Percent <- round(df_hangve$Count / sum(df_hangve$Count) * 100, 1)

# Tạo nhãn ghép với %
df_hangve$Label <- paste0(df_hangve$Percent, "%")

# Vẽ biểu đồ tròn
ggplot(df_hangve, aes(x = "", y = Count, fill = Class)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar(theta = "y") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  labs(title = "Biểu đồ 5: Biểu đồ phân bố khách hàng theo hạng vé") +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5))

Trong bộ dữ liệu, đa số hành khách sử dụng ghế hạng Business, chiếm khoảng 47.9%, theo sau là hạng Eco (phổ thông) với 44.9%, và Eco Plus chỉ chiếm 7.2%. Điều này cho thấy mẫu dữ liệu có xu hướng tập trung vào nhóm khách hàng cao cấp hơn, và có thể phản ánh các đánh giá dịch vụ ở góc nhìn của nhóm khách chi tiêu nhiều hơn.

6. Flight Distance

# Lập bảng tần số
khoangcach <- table(dt$FlightRangeGroup)
khoangcach
## 
##  Short-haul Medium-haul   Long-haul 
##       22572       95940       11368
# Lập bảng tần suất
table(dt$FlightRangeGroup)/sum(nrow(dt))
## 
##  Short-haul Medium-haul   Long-haul 
##  0.17379119  0.73868186  0.08752695
library(ggplot2)

# Đưa về dạng data frame
df_khoangcach <- as.data.frame(khoangcach)
colnames(df_khoangcach) <- c("FlightRangerGroup", "Count")

# Tính phần trăm và thêm vào data frame
df_khoangcach$Percent <- round(df_khoangcach$Count / sum(df_khoangcach$Count) * 100, 1)

# Tạo nhãn ghép với %
df_khoangcach$Label <- paste0(df_khoangcach$Percent, "%")

# Vẽ biểu đồ tròn
ggplot(df_khoangcach, aes(x = "", y = Count, fill = FlightRangerGroup)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar(theta = "y") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  labs(title = "Biểu đồ 6: Biểu đồ phân bố chuyến bay theo khoảng cách") +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5))

Khoảng cách chuyến bay trong bộ dữ liệu được phân loại thành ba nhóm chính: Short-haul (chuyến bay ngắn), Medium-haul (chuyến bay tầm trung), và Long-haul (chuyến bay dài). Kết quả phân tích cho thấy phần lớn khách hàng trong bộ dữ liệu chọn chuyến bay tầm trung, chiếm đến gần 74% tổng số chuyến bay. Đây là nhóm chiếm ưu thế, thể hiện rằng đa số hành khách có xu hướng di chuyển trong phạm vi khoảng cách trung bình, có thể do nhu cầu công việc hoặc du lịch trong các vùng địa lý không quá xa nhau.

Ngược lại, các chuyến bay ngắn chiếm khoảng 17.4%, cho thấy một tỷ lệ nhỏ hành khách sử dụng các chuyến bay trong khoảng cách gần hơn, có thể là các chuyến bay nội địa hoặc các chặng bay ngắn lân cận. Chuyến bay dài, tuy chiếm tỷ lệ thấp nhất với khoảng 8.8%, vẫn phản ánh sự hiện diện của một nhóm hành khách cần di chuyển quãng đường xa hơn, có thể là các chuyến bay quốc tế hoặc xuyên lục địa.

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

1. Satisfation (Satisfied)

Giả thuyết kiểm định

\(H_0\): p ≤ 0.5 (Tỷ lệ khách hàng hài lòng nhỏ hơn bằng 50%

\(H_1\): p > 0.5 (Tỷ lệ khách hàng hài lòng lớn hơn 50%

# Lấy số lượng Female và tổng số quan sát
count_satisfied <- hailong["satisfied"]
n_satisfaction <- sum(hailong)


# 1. Ước lượng khoảng tin cậy 95% cho tỷ lệ Female
prop.test_satisfaction <- prop.test(count_satisfied, n_satisfaction,p = 0.5, conf.level = 0.95, correct = TRUE, alternative = "greater")
print(prop.test_satisfaction)
## 
##  1-sample proportions test with continuity correction
## 
## data:  count_satisfied out of n_satisfaction, null probability 0.5
## X-squared = 1163.5, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is greater than 0.5
## 95 percent confidence interval:
##  0.5450517 1.0000000
## sample estimates:
##         p 
## 0.5473283
  • Tỷ lệ khách hàng hài lòng trong mẫu khảo sát thực tế là 54.73%.

  • Khoảng tin cậy 95%, khoảng ước lượng tỷ lệ khách hàng hài lòng nằm trong khoảng từ 54.5% đến 100%

  • Giá trị p-value < (\(\alpha\) = 0.05), bác bỏ giả thuyết \(H_0\) ở mức ý nghĩa 5%.

=> Vậy tỷ lệ khách hàng hài lòng lớn hơn 50%

2. Gender (Female)

Giả thuyết kiểm định

\(H_0\): p \(\neq\) 0.5 (Tỷ lệ khách hàng nữ khác 50%)

\(H_1\): p = 0.5 (Tỷ lệ khách hàng nữ là 50%)

# Lấy số lượng Female và tổng số quan sát
count_female <- gioitinh["Female"]
n_gender <- sum(gioitinh)


# 1. Ước lượng khoảng tin cậy 95% cho tỷ lệ Female
prop.test_gender <- prop.test(count_female, n_gender,p = 0.5, conf.level = 0.95)
print(prop.test_gender)
## 
##  1-sample proportions test with continuity correction
## 
## data:  count_female out of n_gender, null probability 0.5
## X-squared = 28.294, df = 1, p-value = 1.042e-07
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5046608 0.5101063
## sample estimates:
##         p 
## 0.5073837
  • Tỷ lệ khách hàng nữ trong mẫu khảo sát thực tế là 50.74%.

  • Khoảng tin cậy 95%, khoảng ước lượng tỷ lệ khách hàng nữ nằm trong khoảng từ 50.47% đến 51.01%

  • Giá trị p-value < (\(\alpha\) = 0.05), bác bỏ giả thuyết \(H_0\) ở mức ý nghĩa 5%.

=> Vậy tỷ lệ khách hàng nữ khác 50%

3. Customer Type (Loyal Customer)

Giả thuyết kiểm định

\(H_0\): p ≤ 0.8 (Tỷ lệ khách hàng trung thành nhỏ hơn bằng 80%)

\(H_1\): p > 0.8 (Tỷ lệ khách hàng trung thành lớn hơn 80%)

# Lấy số lượng Female và tổng số quan sát
count_loyal <- phanloai["Loyal Customer"]
n_customertype <- sum(phanloai)


# 1. Ước lượng khoảng tin cậy 95% cho tỷ lệ Loyal Customer
prop.test_customertype <- prop.test(count_loyal, n_customertype, p = 0.8, conf.level = 0.95, alternative = "greater")
print(prop.test_customertype)
## 
##  1-sample proportions test with continuity correction
## 
## data:  count_loyal out of n_customertype, null probability 0.8
## X-squared = 231.96, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is greater than 0.8
## 95 percent confidence interval:
##  0.8151323 1.0000000
## sample estimates:
##         p 
## 0.8169079
  • Tỷ lệ khách hàng trung thành trong mẫu khảo sát thực tế là 81.7%.

  • Khoảng tin cậy 95%, khoảng ước lượng tỷ lệ khách hàng trung thành nằm trong khoảng từ 81.51% đến 100%

  • Giá trị p-value < (\(\alpha\) = 0.05), bác bỏ giả thuyết \(H_0\) ở mức ý nghĩa 5%.

=> Vậy tỷ lệ khách hàng trung thành lớn hơn 80%

4. Type of Travel (Personal Travel)

Giả thuyết kiểm định

\(H_0\): p ≥ 0.5 (Tỷ lệ khách hàng cá nhân lớn hơn bằng 50%)

\(H_1\): p < 0.5 (Tỷ lệ khách hàng cá nhân bé hơn 50%)

# Lấy số lượng Female và tổng số quan sát
count_personal <- mucdich["Personal Travel"]
n_typeoftravel <- sum(mucdich)


# 1. Ước lượng khoảng tin cậy 95% cho tỷ lệ Loyal Customer
prop.test_typeoftravel <- prop.test(count_personal, n_typeoftravel, p = 0.5, conf.level = 0.95, alternative = "less")
print(prop.test_typeoftravel)
## 
##  1-sample proportions test with continuity correction
## 
## data:  count_personal out of n_typeoftravel, null probability 0.5
## X-squared = 18869, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is less than 0.5
## 95 percent confidence interval:
##  0.000000 0.311534
## sample estimates:
##         p 
## 0.3094164
  • Tỷ lệ khách hàng trung thành trong mẫu khảo sát thực tế là 30.94%.

  • Khoảng tin cậy 95%, khoảng ước lượng tỷ lệ khách hàng cá nhân nằm trong khoảng từ 0% đến 31.15%

  • Giá trị p-value < (\(\alpha\) = 0.05), bác bỏ giả thuyết \(H_0\) ở mức ý nghĩa 5%.

=> Vậy tỷ lệ khách hàng cá nhân bé hơn 50%

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

4.1.Satisfaction and Type of Travel

4.1.1. Bảng tần suất chéo

Bảng tần số

# Tạo bảng tần suất chéo giữa Gender và MaritalStatus

satisfaction_typeoftravel<- table(dt$satisfaction, dt$Type.of.Travel)

# Thêm tổng hàng và tổng cột
satisfaction_typeoftravel1<- addmargins(satisfaction_typeoftravel)

satisfaction_typeoftravel1
##               
##                Business travel Personal Travel    Sum
##   dissatisfied           37337           21456  58793
##   satisfied              52356           18731  71087
##   Sum                    89693           40187 129880

Bảng tần suất

# Theo hàng: trong từng giới tính, tỉ lệ từng tình trạng hôn nhân
prop_satisfaction_typeoftravel_row <- prop.table(satisfaction_typeoftravel, 1) * 100
round(prop_satisfaction_typeoftravel_row , 2)
##               
##                Business travel Personal Travel
##   dissatisfied           63.51           36.49
##   satisfied              73.65           26.35

Biểu đồ trực quan hóa

library(ggplot2)

df_satisfaction_typeoftravel <- as.data.frame(satisfaction_typeoftravel)
colnames(df_satisfaction_typeoftravel) <- c("satisfaction", "Type.of.Travel", "Count")

ggplot(df_satisfaction_typeoftravel, aes(x = satisfaction, y = Count, fill = Type.of.Travel)) +
  geom_bar(stat = "identity", position = "fill") +  # hoặc "dodge" nếu muốn số lượng
  labs(title = "Tỷ lệ Type of Travel theo Satisfaction",
       x = "Trải nghiệm khách hàng", y = "Tỷ lệ", fill = "Phân loại mục đích chuyến bay") +
  scale_y_continuous(labels = scales::percent) +
  theme_minimal()

Nhận xét

Từ biểu đồ trên, có thể thấy rõ sự khác biệt về mục đích chuyến bay giữa hai nhóm khách hàng: hài lòng và không hài lòng với trải nghiệm chuyến bay.

  • Cụ thể, trong nhóm khách hàng hài lòng (Satisfied), phần lớn là những người đi công tác (Business Travel), chiếm tỷ lệ 73.65%, trong khi chỉ có 26.35% là khách hàng đi vì mục đích cá nhân (Personal Travel). Điều này cho thấy nhóm khách hàng đi công tác có xu hướng đánh giá cao hơn về dịch vụ hoặc trải nghiệm tổng thể của chuyến bay.

  • Ngược lại, trong nhóm khách hàng không hài lòng (Dissatisfied), mặc dù tỷ lệ khách đi công tác vẫn chiếm đa số (63.51%), nhưng tỷ lệ khách đi vì mục đích cá nhân đã tăng lên, chiếm 36.49% cao hơn so với nhóm hài lòng.

4.1.2. Kiểm định thống kê

Giả thuyết kiểm định

\(H_0\): Trải nghiệm khách hàng và mục đích chuyến bay độc lập

\(H_1\): Trải nghiệm khách hàng và mục đích chuyến bay phụ thuộc

# Thực hiện kiểm định Chi bình phương
chi_satisfaction_typeoftravel <- chisq.test(satisfaction_typeoftravel)

# Hiển thị kết quả
chi_satisfaction_typeoftravel
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  satisfaction_typeoftravel
## X-squared = 1549.4, df = 1, p-value < 2.2e-16

Kết quả:

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

  • Bậc tự do (df) = 1

  • p-value < 2.2e-16

Giá trị p-value < \(\alpha\) = 0.05, nên bác bỏ H₀ ở mức ý nghĩa 5%.

Điều này cho thấy có mối liên hệ có ý nghĩa thống kê giữa Satisfaction và Type of Travel. Nói cách khác mục đích chuyến bay có ảnh hưởng đến mức độ hài lòng của khách hàng.

4.1.3. Hiệu tỷ lệ

satisfaction_typeoftravel1
##               
##                Business travel Personal Travel    Sum
##   dissatisfied           37337           21456  58793
##   satisfied              52356           18731  71087
##   Sum                    89693           40187 129880

\[ p_1 = P(\text{Satisfaction} = \text{Satisfied} \mid \text{Type of Travel} = PersonalTravel) \] \[ p_1 = P(\text{Satisfaction} = \text{Satisfied} \mid \text{Type of Travel} = BusinessTravel) \] Giả thuyết kiểm định

\(H_0\): \(p_1 - p_2 = 0\) (Tỷ lệ khách hàng cá nhân và công tác hài lòng bằng nhau)

\(H_1\): \(p_1 - p_2 < 0\) (Tỷ lệ khách hàng cá nhân hài lòng ít hơn tỷ lệ khách hàng công tác hài lòng)

counts <- c(satisfaction_typeoftravel["satisfied", "Personal Travel"], satisfaction_typeoftravel["satisfied", "Business travel"])   

totals <- c(sum(satisfaction_typeoftravel["satisfied", ]), sum(satisfaction_typeoftravel["dissatisfied", ]))  

test <- prop.test(counts, totals, alternative = "less", correct = FALSE)
test
## 
##  2-sample test for equality of proportions without continuity correction
## 
## data:  counts out of totals
## X-squared = 51063, df = 1, p-value < 2.2e-16
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.0000000 -0.6235745
## sample estimates:
##    prop 1    prop 2 
## 0.2634940 0.8905142

Tỷ lệ mẫu:

  • Nhóm 1 (prop 1): 26.35%

  • Nhóm 2 (prop 2): 89.05%

Kết quả

  • Khoảng tin cậy 95%, cho hiệu \(p_1 - p_2\) từ -1.0000 đến -0.6236

  • Giá trị p-value < \(\alpha\) = 0.05, nên bác bỏ H₀ ở mức ý nghĩa 5%.

=> Vậy tỷ lệ ở nhóm 1 (26.35%) nhỏ hơn có ý nghĩa thống kê so với nhóm 2 (89.05%).

4.1.4. Tỷ số Nguy cơ (Relative Risk - RR):

library(DescTools)
## Warning: package 'DescTools' was built under R version 4.3.3
library(epitools)



# Tính RR
riskratio(satisfaction_typeoftravel, method = "wald")
## $data
##               
##                Business travel Personal Travel  Total
##   dissatisfied           37337           21456  58793
##   satisfied              52356           18731  71087
##   Total                  89693           40187 129880
## 
## $measure
##               risk ratio with 95% C.I.
##                 estimate     lower     upper
##   dissatisfied 1.0000000        NA        NA
##   satisfied    0.7220174 0.7103644 0.7338614
## 
## $p.value
##               two-sided
##                midp.exact fisher.exact chi.square
##   dissatisfied         NA           NA         NA
##   satisfied             0            0          0
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
  • Dữ liệu tổng hợp cho thấy trong số 129.880 khách hàng, có 58.793 người không hài lòng với 37.337 người với mục đích Business travel , và 71.087 người hài lòng với 52.356 người với mục đích Business Travel. Khi so sánh tỷ lệ nhập viện giữa hai nhóm, nhóm người không hài lòng được chọn làm nhóm tham chiếu với tỷ lệ rủi ro chuẩn là 1.

  • Kết quả tính toán cho thấy tỷ số rủi ro (Risk Ratio) của số người không hài lòng so với số người hài lòng là 0.722. Điều này có nghĩa là số người không hài lòng có nguy cơ là người có mục đích Business travel thấp hơn 27.8% so với số người hài lòng trong mẫu dữ liệu này.

  • Khoảng tin cậy 95% của tỷ số rủi ro cho số người hài lòng dao động từ 0.7103 đến 0.7339. Vì khoảng này không bao gồm giá trị 1, điều đó cho thấy sự khác biệt về khánh hàng công tác hài lòng và không hài lòng có mức ý nghĩa thống kê. Nói tóm lại, tỷ lệ không hài lòng ở nhóm Business travel chỉ bằng khoảng 72.2% so với tỉ lệ hài lòng, cho thấy mức độ hài lòng của khách đi công tác cao hơn rõ rệt so với tỉ lệ khách hàng không hài lòng.

4.1.5. Tỷ số Chênh (Odds Ratio - OR):

or_result <- oddsratio(satisfaction_typeoftravel)
print(or_result)
## $data
##               
##                Business travel Personal Travel  Total
##   dissatisfied           37337           21456  58793
##   satisfied              52356           18731  71087
##   Total                  89693           40187 129880
## 
## $measure
##               odds ratio with 95% C.I.
##                 estimate     lower     upper
##   dissatisfied 1.0000000        NA        NA
##   satisfied    0.6225699 0.6080022 0.6374796
## 
## $p.value
##               two-sided
##                midp.exact fisher.exact chi.square
##   dissatisfied         NA           NA         NA
##   satisfied             0            0          0
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

Khách hàng đi công tác (Business travel) có odds hài lòng thấp hơn đáng kể so với khách đi cá nhân (Personal travel), với OR = 0.623; 95% CI [0.608, 0.637]. Điều này cho thấy khách đi công tác có xu hướng đánh giá chuyến bay thấp hơn, và sự khác biệt này có ý nghĩa thống kê (p < 0.001).

LS0tDQp0aXRsZTogIk5oaeG7h20gduG7pSB0deG6p24gNCINCmF1dGhvcjogIkh14buzbmggTmfhu41jIERp4buHcCAtIDIyMjEwMDAyOTUiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclSDolTTolUywgJWQgLSAlbSAtICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jOiB0cnVlDQogIHBkZl9kb2N1bWVudDoNCiAgICBsYXRleF9lbmdpbmU6IHhlbGF0ZXgNCi0tLQ0KDQoNCjxzdHlsZT4NCmJvZHkgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIHNhbnMtc2VyaWY7DQogIGZvbnQtc2l6ZTogMTZweDsNCiAgdGV4dC1hbGlnbjoganVzdGlmeTsNCiAgbGluZS1oZWlnaHQ6IDEuNTsNCn0NCmgxIHsNCiAgY29sb3I6IHJlZDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCn0NCmgyIHsNCiAgY29sb3I6IGJsYWNrOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmgzIHsNCiAgY29sb3I6IGJsYWNrOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmg0IHsNCiAgY29sb3I6IGJsYWNrOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCjwvc3R5bGU+DQoNCg0KDQojIyBQaOG6p24gMTogVMOsbSBoaeG7g3UgdsOgIENodeG6qW4gYuG7iyBk4buvIGxp4buHdQ0KYGBge3J9DQojIMSQ4buNYyBi4buZIGThu68gbGnhu4d1DQpkIDwtIHJlYWQuY3N2KCJEOi9uYWFhYWFhL1BURExEVC9JbnZpc3RpY29fQWlybGluZS5jc3YiLCBoZWFkZXIgPSBUKQ0KYGBgDQoNCi0gQuG7mSBk4buvIGxp4buHdSBiYW8gZ+G7k20gdGjDtG5nIHRpbiBjaGkgdGnhur90IHbhu4Egbmjhu69uZyBraMOhY2ggaMOgbmcgxJHDoyB04burbmcgYmF5IGPDuW5nIGjhu40uIFBo4bqjbiBo4buTaSBj4bunYSBraMOhY2ggaMOgbmcgduG7gSBuaGnhu4F1IGLhu5FpIGPhuqNuaCBraMOhYyBuaGF1IHbDoCBk4buvIGxp4buHdSBjaHV54bq/biBiYXkgY+G7p2EgaOG7jSDEkcOjIMSRxrDhu6NjIGjhu6NwIG5o4bqldC4gTeG7pWMgxJHDrWNoIGNow61uaCBj4bunYSBi4buZIGThu68gbGnhu4d1IG7DoHkgbMOgIGThu7EgxJFvw6FuIGxp4buHdSBt4buZdCBraMOhY2ggaMOgbmcgdMawxqFuZyBsYWkgY8OzIGjDoGkgbMOybmcgduG7m2kgZOG7i2NoIHbhu6UgY+G7p2EgaOG7jSBoYXkga2jDtG5nIGThu7FhIHRyw6puIHRow7RuZyB0aW4gY2hpIHRp4bq/dCB24buBIGPDoWMgZ2nDoSB0cuG7iyB0aGFtIHPhu5Ega2jDoWMuDQoNCi0gTmdvw6BpIHJhLCBjw6FjIGjDo25nIGjDoG5nIGtow7RuZyBj4bqnbiBiaeG6v3Qga2jDrWEgY+G6oW5oIG7DoG8gY+G7p2EgY8OhYyBk4buLY2ggduG7pSBtw6AgaOG7jSBjdW5nIGPhuqVwIHBo4bqjaSDEkcaw4bujYyBuaOG6pW4gbeG6oW5oIGjGoW4gxJHhu4MgdOG6oW8gcmEgbmhp4buBdSBraMOhY2ggaMOgbmcgaMOgaSBsw7JuZyBoxqFuLg0KDQoNCiMjIyAxLiBD4bqldSB0csO6YyBi4buZIGThu68gbGnhu4d1DQoNCmBgYHtyfQ0KIyBD4bqldSB0csO6YyBi4buZIGThu68gbGnhu4d1DQpzdHIoZCkNCmBgYA0KQuG7mSBk4buvIGxp4buHdSBn4buTbSAxMjkuODgwIHF1YW4gc8OhdCB2w6AgMjIgYmnhur9uLCB0aHUgdGjhuq1wIHRow7RuZyB0aW4gduG7gSB0cuG6o2kgbmdoaeG7h20ga2jDoWNoIGjDoG5nIHRyw6puIGPDoWMgY2h1eeG6v24gYmF5IHRoxrDGoW5nIG3huqFpLCB04bqtcCB0cnVuZyB2w6BvIG3hu6ljIMSR4buZIGjDoGkgbMOybmcgdsOgIGPDoWMgeeG6v3UgdOG7kSDhuqNuaCBoxrDhu59uZyDEkeG6v24gxJHDoW5oIGdpw6EgY+G7p2Ega2jDoWNoIGjDoG5nLg0KDQoxLiBzYXRpc2ZhY3Rpb24gKGNocik6IE3hu6ljIMSR4buZIGjDoGkgbMOybmcgY+G7p2Ega2jDoWNoIGjDoG5nLiBH4buTbSAyIGdpw6EgdHLhu4s6ICJzYXRpc2ZpZWQiIHbDoCAiZGlzc2F0aXNmaWVkIi4NCg0KMi4gR2VuZGVyIChjaHIpOiBHaeG7m2kgdMOtbmggY+G7p2EgaMOgbmgga2jDoWNoOiAiTWFsZSIgaG/hurdjICJGZW1hbGUiLg0KDQozLiBDdXN0b21lci5UeXBlIChjaHIpOiBMb+G6oWkga2jDoWNoIGjDoG5nOiAiTG95YWwgQ3VzdG9tZXIiIChraMOhY2ggdGjDom4gdGhp4bq/dCkgaG/hurdjICJkaXNsb3lhbCBDdXN0b21lciIgKGtow6FjaCBraMO0bmcgdGjGsOG7nW5nIHh1ecOqbikuDQoNCjQuIEFnZSAoaW50KTogVHXhu5VpIGPhu6dhIGjDoG5oIGtow6FjaCAodMOtbmggYuG6sW5nIG7Eg20pLg0KDQo1LiBUeXBlLm9mLlRyYXZlbCAoY2hyKTogTeG7pWMgxJHDrWNoIGNodXnhur9uIMSRaTogIkJ1c2luZXNzIHRyYXZlbCIgaG/hurdjICJQZXJzb25hbCBUcmF2ZWwiLg0KDQo2LiBDbGFzcyAoY2hyKTogSOG6oW5nIGdo4bq/OiAiRWNvIiwgIkVjbyBQbHVzIiwgaG/hurdjICJCdXNpbmVzcyIuDQoNCjcuIEZsaWdodC5EaXN0YW5jZSAoaW50KTogUXXDo25nIMSRxrDhu51uZyBiYXkgKHTDrW5oIGLhurFuZyBk4bq3bSkuDQoNCg0KQ8OhYyBiaeG6v24gc2F1IGzDoCDEkcOhbmggZ2nDoSB04burIGjDoG5oIGtow6FjaCB24buBIHRy4bqjaSBuZ2hp4buHbSBk4buLY2ggduG7pToNCg0KOC4gU2VhdC5jb21mb3J0OiDEkOG7mSB0aG/huqNpIG3DoWkgZ2jhur8gbmfhu5NpDQoNCjkuIERlcGFydHVyZS5BcnJpdmFsLnRpbWUuY29udmVuaWVudDogVGh14bqtbiB0aeG7h24gdGjhu51pIGdpYW4gYmF5DQoNCjEwLiBGb29kLmFuZC5kcmluazogxJDDoW5oIGdpw6EgxJHhu5MgxINuIHbDoCB0aOG7qWMgdeG7kW5nDQoNCjExLiBHYXRlLmxvY2F0aW9uOiBW4buLIHRyw60gY+G7lW5nIGzDqm4gbcOheSBiYXkNCg0KMTIuIEluZmxpZ2h0LndpZmkuc2VydmljZTogROG7i2NoIHbhu6Ugd2lmaSB0csOqbiBtw6F5IGJheQ0KDQoxMy4gSW5mbGlnaHQuZW50ZXJ0YWlubWVudDogR2nhuqNpIHRyw60gdHLDqm4gbcOheSBiYXkNCg0KMTQuIE9ubGluZS5zdXBwb3J0OiBI4buXIHRy4bujIHRy4buxYyB0dXnhur9uDQoNCjE1LiBFYXNlLm9mLk9ubGluZS5ib29raW5nOiBE4buFIGTDoG5nIGtoaSDEkeG6t3QgdsOpIG9ubGluZQ0KDQoxNi4gT24uYm9hcmQuc2VydmljZTogROG7i2NoIHbhu6UgdHLDqm4ga2hvYW5nDQoNCjE3LiBMZWcucm9vbS5zZXJ2aWNlOiBDaOG7lyDEkeG7gyBjaMOibg0KDQoxOC4gQmFnZ2FnZS5oYW5kbGluZzogWOG7rSBsw70gaMOgbmggbMO9DQoNCjE5LiBDaGVja2luLnNlcnZpY2U6IEThu4tjaCB24bulIGzDoG0gdGjhu6cgdOG7pWMgY2hlY2staW4NCg0KMjAuIENsZWFubGluZXNzOiBN4bupYyDEkeG7mSBz4bqhY2ggc+G6vQ0KDQoyMS4gT25saW5lLmJvYXJkaW5nOiBUcuG6o2kgbmdoaeG7h20gbMOqbiBtw6F5IGJheSBvbmxpbmUNCg0KMjIuIERlcGFydHVyZS5EZWxheS5pbi5NaW51dGVzIChpbnQpOiBUaOG7nWkgZ2lhbiB0cuG7hSBraOG7n2kgaMOgbmggKHTDrW5oIGLhurFuZyBwaMO6dCkuR2nDoSB0cuG7iyBs4bubbiBiaeG7g3UgdGjhu4sgY2h1eeG6v24gYmF5IGLhu4sgdHLhu4Ugbmhp4buBdS4NCg0KDQoNCiMjIyAyLiBLaeG7g20gdHJhIGThu68gbGnhu4d1IHRoaeG6v3UNCg0KYGBge3J9DQojIEtp4buDbSB0cmEgZOG7ryBsaeG7h3UgdGhp4bq/dQ0Kc3VtKGlzLm5hKGQpKQ0KYGBgDQpLaGkgdGjhu7FjIGhp4buHbiBs4buHbmggc3VtKGlzLm5hKGRhdGEpKSwga+G6v3QgcXXhuqMgdHLhuqMgduG7gSBsw6AgMCwgY2hvIHRo4bqleSBi4buZIGThu68gbGnhu4d1IGhvw6BuIHRvw6BuIGtow7RuZyBjaOG7qWEgZ2nDoSB0cuG7iyBi4buLIHRoaeG6v3UgKE5BKS4gDQoNCg0KIyMjIDMuIENodXnhu4NuIGThuqFuZyBk4buvIGxp4buHdQ0KDQpgYGB7cn0NCg0KZCRGbGlnaHRSYW5nZUdyb3VwIDwtIGN1dChkJEZsaWdodC5EaXN0YW5jZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygwLCAxMDAwLCAzNTAwLCBJbmYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJTaG9ydC1oYXVsIiwgIk1lZGl1bS1oYXVsIiwgIkxvbmctaGF1bCIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IFRSVUUpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KZCRzYXRpc2ZhY3Rpb24gPC0gYXMuZmFjdG9yKGQkc2F0aXNmYWN0aW9uKQ0KZCRHZW5kZXIgPC0gYXMuZmFjdG9yKGQkR2VuZGVyKQ0KZCRDdXN0b21lci5UeXBlIDwtIGFzLmZhY3RvcihkJEN1c3RvbWVyLlR5cGUpDQpkJFR5cGUub2YuVHJhdmVsIDwtIGFzLmZhY3RvcihkJFR5cGUub2YuVHJhdmVsKQ0KZCRDbGFzcyA8LSBhcy5mYWN0b3IoZCRDbGFzcykNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoZCRGbGlnaHQuRGlzdGFuY2UpDQoNCmBgYA0KDQpgYGB7cn0NCiMgVOG6oW8gYmnhur9uIMSR4buLbmggdMOtbmgNCmJkdCA8LSBjKCAic2F0aXNmYWN0aW9uIiwgIkdlbmRlciIsICJDdXN0b21lci5UeXBlIiwgIlR5cGUub2YuVHJhdmVsIiwgIkNsYXNzIiwgIkZsaWdodFJhbmdlR3JvdXAiICkNCg0KIyBU4bqhbyBi4buZIGThu68gbGnhu4d1IG3hu5tpIGNo4buJIGPDsyBiaeG6v24gxJHhu4tuaCB0w61uaA0KZHQgPC0gZFssIGJkdF0NCmBgYA0KDQpDw6FjIGJp4bq/biBuw6B5IMSRxrDhu6NjIHRyw61jaCB4deG6pXQgdsOgIHThuqFvIHRow6BuaCBt4buZdCBi4buZIGThu68gbGnhu4d1IGNvbiwgZMO5bmcgcmnDqm5nIGNobyBwaMOibiB0w61jaCDEkeG7i25oIHTDrW5oIChi4bqjbmcgdOG6p24gc+G7kSwgYmnhu4N1IMSR4buTIGPhu5l0LCBraeG7g20gxJHhu4tuaCB04buJIGzhu4csIG9kZHMgcmF0aW8sIHJpc2sgcmF0aW/igKYpLiBWaeG7h2MgZ2nhu5tpIGjhuqFuIHBow6JuIHTDrWNoIHbDoG8gY8OhYyBiaeG6v24gxJHhu4tuaCB0w61uaCBnacO6cCB04bqtcCB0cnVuZyB2w6BvIHNvIHPDoW5oIMSR4bq3YyDEkWnhu4NtIGdp4buvYSBjw6FjIG5ow7NtLCDEkeG7k25nIHRo4budaSB0csOhbmggc+G7sSBwaOG7qWMgdOG6oXAgdOG7qyBjw6FjIGJp4bq/biDEkeG7i25oIGzGsOG7o25nIHRyb25nIHBo4bqhbSB2aSBwaMOibiB0w61jaCBoaeG7h24gdOG6oWkuDQoNCiMjIFBo4bqnbiAyOiAgUGjDom4gdMOtY2ggbcO0IHThuqMgbeG7mXQgYmnhur9uIMSQ4buLbmggdMOtbmggDQoNCiMjIyAxLiBTYXRpc2ZhY3Rpb24NCg0KYGBge3J9DQojIEzhuq1wIGLhuqNuZyB04bqnbiBz4buRDQpoYWlsb25nIDwtIHRhYmxlKGR0JHNhdGlzZmFjdGlvbikNCmhhaWxvbmcNCmBgYA0KDQpgYGB7cn0NCiMgTOG6rXAgYuG6o25nIHThuqduIHN14bqldA0KdGFibGUoZHQkc2F0aXNmYWN0aW9uKS9zdW0obnJvdyhkdCkpDQpgYGANCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIMSQxrBhIHbhu4EgZOG6oW5nIGRhdGEgZnJhbWUNCmRmX2hhaWxvbmcgPC0gYXMuZGF0YS5mcmFtZShoYWlsb25nKQ0KY29sbmFtZXMoZGZfaGFpbG9uZykgPC0gYygic2F0aXNmYWN0aW9uIiwgIkNvdW50IikNCg0KIyBUw61uaCBwaOG6p24gdHLEg20gdsOgIHRow6ptIHbDoG8gZGF0YSBmcmFtZQ0KZGZfaGFpbG9uZyRQZXJjZW50IDwtIHJvdW5kKGRmX2hhaWxvbmckQ291bnQgLyBzdW0oZGZfaGFpbG9uZyRDb3VudCkgKiAxMDAsIDEpDQoNCiMgVOG6oW8gbmjDo24gZ2jDqXAgduG7m2kgJQ0KZGZfaGFpbG9uZyRMYWJlbCA8LSBwYXN0ZTAoZGZfaGFpbG9uZyRQZXJjZW50LCAiJSIpDQoNCiMgVuG6vSBiaeG7g3UgxJHhu5MgdHLDsm4NCmdncGxvdChkZl9oYWlsb25nLCBhZXMoeCA9ICIiLCB5ID0gQ291bnQsIGZpbGwgPSBzYXRpc2ZhY3Rpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IExhYmVsKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsNCiAgbGFicyh0aXRsZSA9ICJCaeG7g3UgxJHhu5MgMTogQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBt4bupYyDEkeG7mSBow6BpIGzDsm5nIGPhu6dhIGtow6FjaCBow6BuZyIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiB04bu3IGzhu4cgZ2nhu69hIGhhaSBuaMOzbSBt4bupYyDEkeG7mSBow6BpIGzDsm5nIGNobyB0aOG6pXkgdOG7tyBs4buHIGjDoG5oIGtow6FjaCBraMO0bmcgaMOgaSBsw7JuZyBjaGnhur9tIGtob+G6o25nIDQ1LDMlLCB0cm9uZyBraGkgc+G7kSBow6BpIGzDsm5nIGNoaeG6v20ga2hv4bqjbmcgNTQsNyUuIE3hurdjIGTDuSBuaMOzbSBow6BpIGzDsm5nIGNoaeG6v20gxrB1IHRo4bq/LCBraG/huqNuZyBjw6FjaCBraMO0bmcgcXXDoSBs4bubbiwgY2hvIHRo4bqleSB24bqrbiBjw7JuIG3hu5l0IHThu7cgbOG7hyDEkcOhbmcga+G7gyBow6BuaCBraMOhY2ggY2jGsGEgaMOgaSBsw7JuZy4gxJBp4buBdSBuw6B5IGzDoCBk4bqldSBoaeG7h3UgY+G6p24gY+G6o2kgdGhp4buHbiBjaOG6pXQgbMaw4bujbmcgZOG7i2NoIHbhu6UgxJHhu4MgdMSDbmcgbeG7qWMgxJHhu5kgaMOgaSBsw7JuZyBjaHVuZy4NCg0KDQojIyMgMi4gR2VuZGVyDQoNCmBgYHtyfQ0KIyBM4bqtcCBi4bqjbmcgdOG6p24gc+G7kQ0KZ2lvaXRpbmggPC0gdGFibGUoZHQkR2VuZGVyKQ0KZ2lvaXRpbmgNCmBgYA0KDQpgYGB7cn0NCiMgTOG6rXAgYuG6o25nIHThuqduIHN14bqldA0KdGFibGUoZHQkR2VuZGVyKS9zdW0obnJvdyhkdCkpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgxJDGsGEgduG7gSBk4bqhbmcgZGF0YSBmcmFtZQ0KZGZfZ2lvaXRpbmggPC0gYXMuZGF0YS5mcmFtZShnaW9pdGluaCkNCmNvbG5hbWVzKGRmX2dpb2l0aW5oKSA8LSBjKCJHZW5kZXIiLCAiQ291bnQiKQ0KDQojIFTDrW5oIHBo4bqnbiB0csSDbSB2w6AgdGjDqm0gdsOgbyBkYXRhIGZyYW1lDQpkZl9naW9pdGluaCRQZXJjZW50IDwtIHJvdW5kKGRmX2dpb2l0aW5oJENvdW50IC8gc3VtKGRmX2dpb2l0aW5oJENvdW50KSAqIDEwMCwgMSkNCg0KIyBU4bqhbyBuaMOjbiBnaMOpcCB24bubaSAlDQpkZl9naW9pdGluaCRMYWJlbCA8LSBwYXN0ZTAoZGZfZ2lvaXRpbmgkUGVyY2VudCwgIiUiKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIHRyw7JuDQpnZ3Bsb3QoZGZfZ2lvaXRpbmgsIGFlcyh4ID0gIiIsIHkgPSBDb3VudCwgZmlsbCA9IEdlbmRlcikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTGFiZWwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBsYWJzKHRpdGxlID0gIkJp4buDdSDEkeG7kyAyOiBCaeG7g3UgxJHhu5MgdGjhu4MgaGnhu4duIGdp4bubaSB0w61uaCBj4bunYSBraMOhY2ggaMOgbmciKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KYGBgDQoNClThu7cgbOG7hyBnaeG7m2kgdMOtbmggdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3Uga2jDoSBjw6JuIGLhurFuZywgduG7m2kgbuG7ryBjaGnhur9tIGtob+G6o25nIDUwLDclIHbDoCBuYW0gY2hp4bq/bSBraG/huqNuZyA0OSwzJS4gU+G7sSBwaMOibiBi4buRIGfhuqduIG5oxrAgbmdhbmcgbmhhdSBuw6B5IGdpw7pwIMSR4bqjbSBi4bqjbyB0w61uaCDEkeG6oWkgZGnhu4duIGdp4buvYSBoYWkgZ2nhu5tpIGtoaSBwaMOibiB0w61jaCBjw6FjIHnhur91IHThu5EgbGnDqm4gcXVhbiDEkeG6v24gbeG7qWMgxJHhu5kgaMOgaSBsw7JuZyBob+G6t2MgaMOgbmggdmkgZHUgbOG7i2NoLiDEkGnhu4F1IG7DoHkgY8WpbmcgdOG6oW8gxJFp4buBdSBraeG7h24gdGh14bqtbiBs4bujaSBjaG8gdmnhu4djIHNvIHPDoW5oIGdp4bubaSB0w61uaCBtw6Aga2jDtG5nIGLhu4sgdGhpw6puIGzhu4djaC4NCg0KDQojIyMgMy4gQ3VzdG9tZXIgVHlwZQ0KDQpgYGB7cn0NCiMgTOG6rXAgYuG6o25nIHThuqduIHPhu5ENCnBoYW5sb2FpIDwtIHRhYmxlKGR0JEN1c3RvbWVyLlR5cGUpDQpwaGFubG9haQ0KYGBgDQoNCmBgYHtyfQ0KIyBM4bqtcCBi4bqjbmcgdOG6p24gc3XhuqV0DQp0YWJsZShkdCRDdXN0b21lci5UeXBlKS9zdW0obnJvdyhkdCkpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgxJDGsGEgduG7gSBk4bqhbmcgZGF0YSBmcmFtZQ0KZGZfcGhhbmxvYWkgPC0gYXMuZGF0YS5mcmFtZShwaGFubG9haSkNCmNvbG5hbWVzKGRmX3BoYW5sb2FpKSA8LSBjKCJDdXN0b21lci5UeXBlIiwgIkNvdW50IikNCg0KIyBUw61uaCBwaOG6p24gdHLEg20gdsOgIHRow6ptIHbDoG8gZGF0YSBmcmFtZQ0KZGZfcGhhbmxvYWkkUGVyY2VudCA8LSByb3VuZChkZl9waGFubG9haSRDb3VudCAvIHN1bShkZl9waGFubG9haSRDb3VudCkgKiAxMDAsIDEpDQoNCiMgVOG6oW8gbmjDo24gZ2jDqXAgduG7m2kgJQ0KZGZfcGhhbmxvYWkkTGFiZWwgPC0gcGFzdGUwKGRmX3BoYW5sb2FpJFBlcmNlbnQsICIlIikNCg0KIyBW4bq9IGJp4buDdSDEkeG7kyB0csOybg0KZ2dwbG90KGRmX3BoYW5sb2FpLCBhZXMoeCA9ICIiLCB5ID0gQ291bnQsIGZpbGwgPSBDdXN0b21lci5UeXBlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBMYWJlbCksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIGxhYnModGl0bGUgPSAiQmnhu4N1IMSR4buTIDM6IEJp4buDdSDEkeG7kyB0aOG7gyBoaeG7h24gcGjDom4gYuG7kSBsb+G6oWkga2jDoWNoIGjDoG5nIikgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQpQaOG6p24gbOG7m24ga2jDoWNoIGjDoG5nIHRyb25nIHThuq1wIGThu68gbGnhu4d1IGzDoCBraMOhY2ggaMOgbmcgdGjDom4gdGhp4bq/dCAoTG95YWwgQ3VzdG9tZXIpLCBjaGnhur9tIGtob+G6o25nIDgxLDclLCB0cm9uZyBraGkga2jDoWNoIGjDoG5nIGtow7RuZyB0cnVuZyB0aMOgbmggKERpc2xveWFsIEN1c3RvbWVyKSBjaOG7iSBjaGnhur9tIGtob+G6o25nIDE4LDMlLiBT4buxIGNow6puaCBs4buHY2ggbsOgeSBjaG8gdGjhuqV5IG5ow7NtIGtow6FjaCBow6BuZyB0aMOibiB0aGnhur90IGzDoCDEkeG7kWkgdMaw4bujbmcgY2jDrW5oIHRyb25nIGto4bqjbyBzw6F0LCB2w6AgY8OzIHRo4buDIOG6o25oIGjGsOG7n25nIMSR4bq/biBt4bupYyDEkeG7mSBow6BpIGzDsm5nIGNodW5nIGPhu6dhIHRvw6BuIGLhu5kgZOG7ryBsaeG7h3UuIMSQw6J5IGPFqW5nIGzDoCB54bq/dSB04buRIHF1YW4gdHLhu41uZyBj4bqnbiB4ZW0geMOpdCBraGkgcGjDom4gdMOtY2ggaMOgbmggdmkgaG/hurdjIGPhuqNtIG5o4bqtbiBk4buLY2ggduG7pS4NCg0KDQoNCiMjIyA0LiBUeXBlIG9mIFRyYXZlbA0KDQpgYGB7cn0NCiMgTOG6rXAgYuG6o25nIHThuqduIHPhu5ENCm11Y2RpY2ggPC0gdGFibGUoZHQkVHlwZS5vZi5UcmF2ZWwpDQptdWNkaWNoDQpgYGANCg0KYGBge3J9DQojIEzhuq1wIGLhuqNuZyB04bqnbiBzdeG6pXQNCnRhYmxlKGR0JFR5cGUub2YuVHJhdmVsKS9zdW0obnJvdyhkdCkpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgxJDGsGEgduG7gSBk4bqhbmcgZGF0YSBmcmFtZQ0KZGZfbXVjZGljaCA8LSBhcy5kYXRhLmZyYW1lKG11Y2RpY2gpDQpjb2xuYW1lcyhkZl9tdWNkaWNoKSA8LSBjKCJUeXBlLm9mLlRyYXZlbCIsICJDb3VudCIpDQoNCiMgVMOtbmggcGjhuqduIHRyxINtIHbDoCB0aMOqbSB2w6BvIGRhdGEgZnJhbWUNCmRmX211Y2RpY2gkUGVyY2VudCA8LSByb3VuZChkZl9tdWNkaWNoJENvdW50IC8gc3VtKGRmX211Y2RpY2gkQ291bnQpICogMTAwLCAxKQ0KDQojIFThuqFvIG5ow6NuIGdow6lwIHbhu5tpICUNCmRmX211Y2RpY2gkTGFiZWwgPC0gcGFzdGUwKGRmX211Y2RpY2gkUGVyY2VudCwgIiUiKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIHRyw7JuDQpnZ3Bsb3QoZGZfbXVjZGljaCwgYWVzKHggPSAiIiwgeSA9IENvdW50LCBmaWxsID0gVHlwZS5vZi5UcmF2ZWwpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IExhYmVsKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsNCiAgbGFicyh0aXRsZSA9ICJCaeG7g3UgxJHhu5MgNDogQmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBt4bulYyDEkcOtY2ggYmF5IGPhu6dhIGtow6FjaCBow6BuZyIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCsSQYSBz4buRIGjDoG5oIGtow6FjaCB0cm9uZyBi4buZIGThu68gbGnhu4d1IHRo4buxYyBoaeG7h24gQnVzaW5lc3MgVHJhdmVsIChjw7RuZyB0w6FjKSwgY2hp4bq/bSBraG/huqNuZyA2OSUsIHRyb25nIGtoaSBQZXJzb25hbCBUcmF2ZWwgKGR1IGzhu4tjaCBjw6EgbmjDom4pIGNoaeG6v20ga2hv4bqjbmcgMzElLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBt4bqrdSBk4buvIGxp4buHdSB0aGnDqm4gduG7gSBuaMOzbSBraMOhY2ggxJFpIGPDtG5nIHTDoWMsIHbDoCBjw7MgdGjhu4Mg4bqjbmggaMaw4bufbmcgxJHhur9uIG3hu6ljIMSR4buZIGjDoGkgbMOybmcgaG/hurdjIGPDoWMgeeG6v3UgdOG7kSBk4buLY2ggduG7pSDEkcaw4bujYyDEkcOhbmggZ2nDoSwgdsOsIG3hu6VjIMSRw61jaCBjaHV54bq/biDEkWkgdGjGsOG7nW5nIOG6o25oIGjGsOG7n25nIMSR4bq/biBr4buzIHbhu41uZyB2w6AgdHLhuqNpIG5naGnhu4dtIGPhu6dhIGtow6FjaCBow6BuZy4NCg0KDQojIyMgNS4gQ2xhc3MNCg0KYGBge3J9DQojIEzhuq1wIGLhuqNuZyB04bqnbiBz4buRDQpoYW5ndmUgPC0gdGFibGUoZHQkQ2xhc3MpDQpoYW5ndmUNCmBgYA0KDQpgYGB7cn0NCiMgTOG6rXAgYuG6o25nIHThuqduIHN14bqldA0KdGFibGUoZHQkQ2xhc3MpL3N1bShucm93KGR0KSkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyDEkMawYSB24buBIGThuqFuZyBkYXRhIGZyYW1lDQpkZl9oYW5ndmUgPC0gYXMuZGF0YS5mcmFtZShoYW5ndmUpDQpjb2xuYW1lcyhkZl9oYW5ndmUpIDwtIGMoIkNsYXNzIiwgIkNvdW50IikNCg0KIyBUw61uaCBwaOG6p24gdHLEg20gdsOgIHRow6ptIHbDoG8gZGF0YSBmcmFtZQ0KZGZfaGFuZ3ZlJFBlcmNlbnQgPC0gcm91bmQoZGZfaGFuZ3ZlJENvdW50IC8gc3VtKGRmX2hhbmd2ZSRDb3VudCkgKiAxMDAsIDEpDQoNCiMgVOG6oW8gbmjDo24gZ2jDqXAgduG7m2kgJQ0KZGZfaGFuZ3ZlJExhYmVsIDwtIHBhc3RlMChkZl9oYW5ndmUkUGVyY2VudCwgIiUiKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIHRyw7JuDQpnZ3Bsb3QoZGZfaGFuZ3ZlLCBhZXMoeCA9ICIiLCB5ID0gQ291bnQsIGZpbGwgPSBDbGFzcykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTGFiZWwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBsYWJzKHRpdGxlID0gIkJp4buDdSDEkeG7kyA1OiBCaeG7g3UgxJHhu5MgcGjDom4gYuG7kSBraMOhY2ggaMOgbmcgdGhlbyBo4bqhbmcgdsOpIikgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQpUcm9uZyBi4buZIGThu68gbGnhu4d1LCDEkWEgc+G7kSBow6BuaCBraMOhY2ggc+G7rSBk4bulbmcgZ2jhur8gaOG6oW5nIEJ1c2luZXNzLCBjaGnhur9tIGtob+G6o25nIDQ3LjklLCB0aGVvIHNhdSBsw6AgaOG6oW5nIEVjbyAocGjhu5UgdGjDtG5nKSB24bubaSA0NC45JSwgdsOgIEVjbyBQbHVzIGNo4buJIGNoaeG6v20gNy4yJS4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgbeG6q3UgZOG7ryBsaeG7h3UgY8OzIHh1IGjGsOG7m25nIHThuq1wIHRydW5nIHbDoG8gbmjDs20ga2jDoWNoIGjDoG5nIGNhbyBj4bqlcCBoxqFuLCB2w6AgY8OzIHRo4buDIHBo4bqjbiDDoW5oIGPDoWMgxJHDoW5oIGdpw6EgZOG7i2NoIHbhu6Ug4bufIGfDs2MgbmjDrG4gY+G7p2EgbmjDs20ga2jDoWNoIGNoaSB0acOqdSBuaGnhu4F1IGjGoW4uDQoNCiMjIyA2LiBGbGlnaHQgRGlzdGFuY2UNCg0KYGBge3J9DQojIEzhuq1wIGLhuqNuZyB04bqnbiBz4buRDQpraG9hbmdjYWNoIDwtIHRhYmxlKGR0JEZsaWdodFJhbmdlR3JvdXApDQpraG9hbmdjYWNoDQpgYGANCg0KYGBge3J9DQojIEzhuq1wIGLhuqNuZyB04bqnbiBzdeG6pXQNCnRhYmxlKGR0JEZsaWdodFJhbmdlR3JvdXApL3N1bShucm93KGR0KSkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyDEkMawYSB24buBIGThuqFuZyBkYXRhIGZyYW1lDQpkZl9raG9hbmdjYWNoIDwtIGFzLmRhdGEuZnJhbWUoa2hvYW5nY2FjaCkNCmNvbG5hbWVzKGRmX2tob2FuZ2NhY2gpIDwtIGMoIkZsaWdodFJhbmdlckdyb3VwIiwgIkNvdW50IikNCg0KIyBUw61uaCBwaOG6p24gdHLEg20gdsOgIHRow6ptIHbDoG8gZGF0YSBmcmFtZQ0KZGZfa2hvYW5nY2FjaCRQZXJjZW50IDwtIHJvdW5kKGRmX2tob2FuZ2NhY2gkQ291bnQgLyBzdW0oZGZfa2hvYW5nY2FjaCRDb3VudCkgKiAxMDAsIDEpDQoNCiMgVOG6oW8gbmjDo24gZ2jDqXAgduG7m2kgJQ0KZGZfa2hvYW5nY2FjaCRMYWJlbCA8LSBwYXN0ZTAoZGZfa2hvYW5nY2FjaCRQZXJjZW50LCAiJSIpDQoNCiMgVuG6vSBiaeG7g3UgxJHhu5MgdHLDsm4NCmdncGxvdChkZl9raG9hbmdjYWNoLCBhZXMoeCA9ICIiLCB5ID0gQ291bnQsIGZpbGwgPSBGbGlnaHRSYW5nZXJHcm91cCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gTGFiZWwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBsYWJzKHRpdGxlID0gIkJp4buDdSDEkeG7kyA2OiBCaeG7g3UgxJHhu5MgcGjDom4gYuG7kSBjaHV54bq/biBiYXkgdGhlbyBraG/huqNuZyBjw6FjaCIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCktob+G6o25nIGPDoWNoIGNodXnhur9uIGJheSB0cm9uZyBi4buZIGThu68gbGnhu4d1IMSRxrDhu6NjIHBow6JuIGxv4bqhaSB0aMOgbmggYmEgbmjDs20gY2jDrW5oOiBTaG9ydC1oYXVsIChjaHV54bq/biBiYXkgbmfhuq9uKSwgTWVkaXVtLWhhdWwgKGNodXnhur9uIGJheSB04bqnbSB0cnVuZyksIHbDoCBMb25nLWhhdWwgKGNodXnhur9uIGJheSBkw6BpKS4gS+G6v3QgcXXhuqMgcGjDom4gdMOtY2ggY2hvIHRo4bqleSBwaOG6p24gbOG7m24ga2jDoWNoIGjDoG5nIHRyb25nIGLhu5kgZOG7ryBsaeG7h3UgY2jhu41uIGNodXnhur9uIGJheSB04bqnbSB0cnVuZywgY2hp4bq/bSDEkeG6v24gZ+G6p24gNzQlIHThu5VuZyBz4buRIGNodXnhur9uIGJheS4gxJDDonkgbMOgIG5ow7NtIGNoaeG6v20gxrB1IHRo4bq/LCB0aOG7gyBoaeG7h24gcuG6sW5nIMSRYSBz4buRIGjDoG5oIGtow6FjaCBjw7MgeHUgaMaw4bubbmcgZGkgY2h1eeG7g24gdHJvbmcgcGjhuqFtIHZpIGtob+G6o25nIGPDoWNoIHRydW5nIGLDrG5oLCBjw7MgdGjhu4MgZG8gbmh1IGPhuqd1IGPDtG5nIHZp4buHYyBob+G6t2MgZHUgbOG7i2NoIHRyb25nIGPDoWMgdsO5bmcgxJHhu4thIGzDvSBraMO0bmcgcXXDoSB4YSBuaGF1Lg0KDQpOZ8aw4bujYyBs4bqhaSwgY8OhYyBjaHV54bq/biBiYXkgbmfhuq9uIGNoaeG6v20ga2hv4bqjbmcgMTcuNCUsIGNobyB0aOG6pXkgbeG7mXQgdOG7tyBs4buHIG5o4buPIGjDoG5oIGtow6FjaCBz4butIGThu6VuZyBjw6FjIGNodXnhur9uIGJheSB0cm9uZyBraG/huqNuZyBjw6FjaCBn4bqnbiBoxqFuLCBjw7MgdGjhu4MgbMOgIGPDoWMgY2h1eeG6v24gYmF5IG7hu5lpIMSR4buLYSBob+G6t2MgY8OhYyBjaOG6t25nIGJheSBuZ+G6r24gbMOibiBj4bqtbi4gQ2h1eeG6v24gYmF5IGTDoGksIHR1eSBjaGnhur9tIHThu7cgbOG7hyB0aOG6pXAgbmjhuqV0IHbhu5tpIGtob+G6o25nIDguOCUsIHbhuqtuIHBo4bqjbiDDoW5oIHPhu7EgaGnhu4duIGRp4buHbiBj4bunYSBt4buZdCBuaMOzbSBow6BuaCBraMOhY2ggY+G6p24gZGkgY2h1eeG7g24gcXXDo25nIMSRxrDhu51uZyB4YSBoxqFuLCBjw7MgdGjhu4MgbMOgIGPDoWMgY2h1eeG6v24gYmF5IHF14buRYyB04bq/IGhv4bq3YyB4dXnDqm4gbOG7pWMgxJHhu4thLg0KDQoNCiMjIFBo4bqnbiAzOiDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdsOgIEtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IGNobyB04bu3IGzhu4cgDQoNCiMjIyAxLiBTYXRpc2ZhdGlvbiAoU2F0aXNmaWVkKQ0KDQoqKkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oKioNCg0KJEhfMCQ6IHAg4omkIDAuNSAoVOG7tyBs4buHIGtow6FjaCBow6BuZyBow6BpIGzDsm5nIG5o4buPIGjGoW4gYuG6sW5nIDUwJQ0KDQokSF8xJDogcCA+IDAuNSAoVOG7tyBs4buHIGtow6FjaCBow6BuZyBow6BpIGzDsm5nIGzhu5tuIGjGoW4gNTAlDQoNCmBgYHtyfQ0KIyBM4bqleSBz4buRIGzGsOG7o25nIEZlbWFsZSB2w6AgdOG7lW5nIHPhu5EgcXVhbiBzw6F0DQpjb3VudF9zYXRpc2ZpZWQgPC0gaGFpbG9uZ1sic2F0aXNmaWVkIl0NCm5fc2F0aXNmYWN0aW9uIDwtIHN1bShoYWlsb25nKQ0KDQoNCiMgMS4gxq/hu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBGZW1hbGUNCnByb3AudGVzdF9zYXRpc2ZhY3Rpb24gPC0gcHJvcC50ZXN0KGNvdW50X3NhdGlzZmllZCwgbl9zYXRpc2ZhY3Rpb24scCA9IDAuNSwgY29uZi5sZXZlbCA9IDAuOTUsIGNvcnJlY3QgPSBUUlVFLCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikNCnByaW50KHByb3AudGVzdF9zYXRpc2ZhY3Rpb24pDQpgYGANCg0KLSBU4bu3IGzhu4cga2jDoWNoIGjDoG5nIGjDoGkgbMOybmcgdHJvbmcgbeG6q3Uga2jhuqNvIHPDoXQgdGjhu7FjIHThur8gbMOgIDU0LjczJS4NCg0KLSBLaG/huqNuZyB0aW4gY+G6rXkgOTUlLCBraG/huqNuZyDGsOG7m2MgbMaw4bujbmcgdOG7tyBs4buHIGtow6FjaCBow6BuZyBow6BpIGzDsm5nIG7hurFtIHRyb25nIGtob+G6o25nIHThu6sgNTQuNSUgxJHhur9uIDEwMCUNCg0KLSBHacOhIHRy4buLIHAtdmFsdWUgPCAoJFxhbHBoYSQgPSAwLjA1KSwgYsOhYyBi4buPIGdp4bqjIHRodXnhur90ICRIXzAkIOG7nyBt4bupYyDDvSBuZ2jEqWEgNSUuDQoNCj0+IFbhuq15IHThu7cgbOG7hyBraMOhY2ggaMOgbmcgaMOgaSBsw7JuZyBs4bubbiBoxqFuIDUwJQ0KDQojIyMgMi4gR2VuZGVyIChGZW1hbGUpDQoNCioqR2nhuqMgdGh1eeG6v3Qga2nhu4NtIMSR4buLbmgqKg0KDQokSF8wJDogcCAkXG5lcSQgMC41IChU4bu3IGzhu4cga2jDoWNoIGjDoG5nIG7hu68ga2jDoWMgNTAlKQ0KDQokSF8xJDogcCA9IDAuNSAoVOG7tyBs4buHIGtow6FjaCBow6BuZyBu4buvIGzDoCA1MCUpDQoNCmBgYHtyfQ0KIyBM4bqleSBz4buRIGzGsOG7o25nIEZlbWFsZSB2w6AgdOG7lW5nIHPhu5EgcXVhbiBzw6F0DQpjb3VudF9mZW1hbGUgPC0gZ2lvaXRpbmhbIkZlbWFsZSJdDQpuX2dlbmRlciA8LSBzdW0oZ2lvaXRpbmgpDQoNCg0KIyAxLiDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIEZlbWFsZQ0KcHJvcC50ZXN0X2dlbmRlciA8LSBwcm9wLnRlc3QoY291bnRfZmVtYWxlLCBuX2dlbmRlcixwID0gMC41LCBjb25mLmxldmVsID0gMC45NSkNCnByaW50KHByb3AudGVzdF9nZW5kZXIpDQpgYGANCg0KLSBU4bu3IGzhu4cga2jDoWNoIGjDoG5nIG7hu68gdHJvbmcgbeG6q3Uga2jhuqNvIHPDoXQgdGjhu7FjIHThur8gbMOgIDUwLjc0JS4NCg0KLSBLaG/huqNuZyB0aW4gY+G6rXkgOTUlLCBraG/huqNuZyDGsOG7m2MgbMaw4bujbmcgdOG7tyBs4buHIGtow6FjaCBow6BuZyBu4buvIG7hurFtIHRyb25nIGtob+G6o25nIHThu6sgNTAuNDclIMSR4bq/biA1MS4wMSUNCg0KLSBHacOhIHRy4buLIHAtdmFsdWUgPCAoJFxhbHBoYSQgPSAwLjA1KSwgYsOhYyBi4buPIGdp4bqjIHRodXnhur90ICRIXzAkIOG7nyBt4bupYyDDvSBuZ2jEqWEgNSUuDQoNCj0+IFbhuq15IHThu7cgbOG7hyBraMOhY2ggaMOgbmcgbuG7ryBraMOhYyA1MCUNCg0KDQojIyMgMy4gQ3VzdG9tZXIgVHlwZSAoTG95YWwgQ3VzdG9tZXIpDQoNCioqR2nhuqMgdGh1eeG6v3Qga2nhu4NtIMSR4buLbmgqKg0KDQokSF8wJDogcCDiiaQgIDAuOCAoVOG7tyBs4buHIGtow6FjaCBow6BuZyB0cnVuZyB0aMOgbmggbmjhu48gaMahbiBi4bqxbmcgODAlKQ0KDQokSF8xJDogcCA+IDAuOCAoVOG7tyBs4buHIGtow6FjaCBow6BuZyB0cnVuZyB0aMOgbmggbOG7m24gaMahbiA4MCUpDQoNCmBgYHtyfQ0KIyBM4bqleSBz4buRIGzGsOG7o25nIEZlbWFsZSB2w6AgdOG7lW5nIHPhu5EgcXVhbiBzw6F0DQpjb3VudF9sb3lhbCA8LSBwaGFubG9haVsiTG95YWwgQ3VzdG9tZXIiXQ0Kbl9jdXN0b21lcnR5cGUgPC0gc3VtKHBoYW5sb2FpKQ0KDQoNCiMgMS4gxq/hu5tjIGzGsOG7o25nIGtob+G6o25nIHRpbiBj4bqteSA5NSUgY2hvIHThu7cgbOG7hyBMb3lhbCBDdXN0b21lcg0KcHJvcC50ZXN0X2N1c3RvbWVydHlwZSA8LSBwcm9wLnRlc3QoY291bnRfbG95YWwsIG5fY3VzdG9tZXJ0eXBlLCBwID0gMC44LCBjb25mLmxldmVsID0gMC45NSwgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpDQpwcmludChwcm9wLnRlc3RfY3VzdG9tZXJ0eXBlKQ0KYGBgDQoNCi0gVOG7tyBs4buHIGtow6FjaCBow6BuZyB0cnVuZyB0aMOgbmggdHJvbmcgbeG6q3Uga2jhuqNvIHPDoXQgdGjhu7FjIHThur8gbMOgIDgxLjclLg0KDQotIEtob+G6o25nIHRpbiBj4bqteSA5NSUsIGtob+G6o25nIMaw4bubYyBsxrDhu6NuZyB04bu3IGzhu4cga2jDoWNoIGjDoG5nIHRydW5nIHRow6BuaCBu4bqxbSB0cm9uZyBraG/huqNuZyB04burIDgxLjUxJSDEkeG6v24gMTAwJQ0KDQotIEdpw6EgdHLhu4sgcC12YWx1ZSA8ICgkXGFscGhhJCA9IDAuMDUpLCBiw6FjIGLhu48gZ2nhuqMgdGh1eeG6v3QgJEhfMCQg4bufIG3hu6ljIMO9IG5naMSpYSA1JS4NCg0KPT4gVuG6rXkgdOG7tyBs4buHIGtow6FjaCBow6BuZyB0cnVuZyB0aMOgbmggbOG7m24gaMahbiA4MCUNCg0KDQojIyMgNC4gVHlwZSBvZiBUcmF2ZWwgKFBlcnNvbmFsIFRyYXZlbCkNCg0KKipHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaCoqDQoNCiRIXzAkOiBwIOKJpSAgMC41IChU4bu3IGzhu4cga2jDoWNoIGjDoG5nIGPDoSBuaMOibiBs4bubbiBoxqFuIGLhurFuZyA1MCUpDQoNCiRIXzEkOiBwIDwgMC41IChU4bu3IGzhu4cga2jDoWNoIGjDoG5nIGPDoSBuaMOibiBiw6kgaMahbiA1MCUpDQoNCmBgYHtyfQ0KIyBM4bqleSBz4buRIGzGsOG7o25nIEZlbWFsZSB2w6AgdOG7lW5nIHPhu5EgcXVhbiBzw6F0DQpjb3VudF9wZXJzb25hbCA8LSBtdWNkaWNoWyJQZXJzb25hbCBUcmF2ZWwiXQ0Kbl90eXBlb2Z0cmF2ZWwgPC0gc3VtKG11Y2RpY2gpDQoNCg0KIyAxLiDGr+G7m2MgbMaw4bujbmcga2hv4bqjbmcgdGluIGPhuq15IDk1JSBjaG8gdOG7tyBs4buHIExveWFsIEN1c3RvbWVyDQpwcm9wLnRlc3RfdHlwZW9mdHJhdmVsIDwtIHByb3AudGVzdChjb3VudF9wZXJzb25hbCwgbl90eXBlb2Z0cmF2ZWwsIHAgPSAwLjUsIGNvbmYubGV2ZWwgPSAwLjk1LCBhbHRlcm5hdGl2ZSA9ICJsZXNzIikNCnByaW50KHByb3AudGVzdF90eXBlb2Z0cmF2ZWwpDQpgYGANCg0KLSBU4bu3IGzhu4cga2jDoWNoIGjDoG5nIHRydW5nIHRow6BuaCB0cm9uZyBt4bqrdSBraOG6o28gc8OhdCB0aOG7sWMgdOG6vyBsw6AgMzAuOTQlLg0KDQotIEtob+G6o25nIHRpbiBj4bqteSA5NSUsIGtob+G6o25nIMaw4bubYyBsxrDhu6NuZyB04bu3IGzhu4cga2jDoWNoIGjDoG5nIGPDoSBuaMOibiBu4bqxbSB0cm9uZyBraG/huqNuZyB04burIDAlIMSR4bq/biAzMS4xNSUNCg0KLSBHacOhIHRy4buLIHAtdmFsdWUgPCAoJFxhbHBoYSQgPSAwLjA1KSwgYsOhYyBi4buPIGdp4bqjIHRodXnhur90ICRIXzAkIOG7nyBt4bupYyDDvSBuZ2jEqWEgNSUuDQoNCj0+IFbhuq15IHThu7cgbOG7hyBraMOhY2ggaMOgbmcgY8OhIG5ow6JuIGLDqSBoxqFuIDUwJQ0KDQoNCiMjIFBo4bqnbiA0OiBQaMOibiB0w61jaCBt4buRaSBxdWFuIGjhu4cgZ2nhu69hIGhhaSBiaeG6v24gxJDhu4tuaCB0w61uaA0KDQojIyMgNC4xLlNhdGlzZmFjdGlvbiBhbmQgVHlwZSBvZiBUcmF2ZWwNCg0KIyMjIyA0LjEuMS4gQuG6o25nIHThuqduIHN14bqldCBjaMOpbw0KDQoqKkLhuqNuZyB04bqnbiBz4buRKioNCmBgYHtyfQ0KIyBU4bqhbyBi4bqjbmcgdOG6p24gc3XhuqV0IGNow6lvIGdp4buvYSBHZW5kZXIgdsOgIE1hcml0YWxTdGF0dXMNCg0Kc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbDwtIHRhYmxlKGR0JHNhdGlzZmFjdGlvbiwgZHQkVHlwZS5vZi5UcmF2ZWwpDQoNCiMgVGjDqm0gdOG7lW5nIGjDoG5nIHbDoCB04buVbmcgY+G7mXQNCnNhdGlzZmFjdGlvbl90eXBlb2Z0cmF2ZWwxPC0gYWRkbWFyZ2lucyhzYXRpc2ZhY3Rpb25fdHlwZW9mdHJhdmVsKQ0KDQpzYXRpc2ZhY3Rpb25fdHlwZW9mdHJhdmVsMQ0KYGBgDQoNCg0KKipC4bqjbmcgdOG6p24gc3XhuqV0KioNCg0KYGBge3J9DQojIFRoZW8gaMOgbmc6IHRyb25nIHThu6tuZyBnaeG7m2kgdMOtbmgsIHThu4kgbOG7hyB04burbmcgdMOsbmggdHLhuqFuZyBow7RuIG5ow6JuDQpwcm9wX3NhdGlzZmFjdGlvbl90eXBlb2Z0cmF2ZWxfcm93IDwtIHByb3AudGFibGUoc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbCwgMSkgKiAxMDANCnJvdW5kKHByb3Bfc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbF9yb3cgLCAyKQ0KDQpgYGANCioqQmnhu4N1IMSR4buTIHRy4buxYyBxdWFuIGjDs2EqKg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KZGZfc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbCA8LSBhcy5kYXRhLmZyYW1lKHNhdGlzZmFjdGlvbl90eXBlb2Z0cmF2ZWwpDQpjb2xuYW1lcyhkZl9zYXRpc2ZhY3Rpb25fdHlwZW9mdHJhdmVsKSA8LSBjKCJzYXRpc2ZhY3Rpb24iLCAiVHlwZS5vZi5UcmF2ZWwiLCAiQ291bnQiKQ0KDQpnZ3Bsb3QoZGZfc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbCwgYWVzKHggPSBzYXRpc2ZhY3Rpb24sIHkgPSBDb3VudCwgZmlsbCA9IFR5cGUub2YuVHJhdmVsKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsgICMgaG/hurdjICJkb2RnZSIgbuG6v3UgbXXhu5FuIHPhu5EgbMaw4bujbmcNCiAgbGFicyh0aXRsZSA9ICJU4bu3IGzhu4cgVHlwZSBvZiBUcmF2ZWwgdGhlbyBTYXRpc2ZhY3Rpb24iLA0KICAgICAgIHggPSAiVHLhuqNpIG5naGnhu4dtIGtow6FjaCBow6BuZyIsIHkgPSAiVOG7tyBs4buHIiwgZmlsbCA9ICJQaMOibiBsb+G6oWkgbeG7pWMgxJHDrWNoIGNodXnhur9uIGJheSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoqTmjhuq1uIHjDqXQqDQoNClThu6sgYmnhu4N1IMSR4buTIHRyw6puLCBjw7MgdGjhu4MgdGjhuqV5IHLDtSBz4buxIGtow6FjIGJp4buHdCB24buBIG3hu6VjIMSRw61jaCBjaHV54bq/biBiYXkgZ2nhu69hIGhhaSBuaMOzbSBraMOhY2ggaMOgbmc6IGjDoGkgbMOybmcgdsOgIGtow7RuZyBow6BpIGzDsm5nIHbhu5tpIHRy4bqjaSBuZ2hp4buHbSBjaHV54bq/biBiYXkuDQoNCi0gQ+G7pSB0aOG7gywgdHJvbmcgbmjDs20ga2jDoWNoIGjDoG5nIGjDoGkgbMOybmcgKFNhdGlzZmllZCksIHBo4bqnbiBs4bubbiBsw6Agbmjhu69uZyBuZ8aw4budaSDEkWkgY8O0bmcgdMOhYyAoQnVzaW5lc3MgVHJhdmVsKSwgY2hp4bq/bSB04bu3IGzhu4cgNzMuNjUlLCB0cm9uZyBraGkgY2jhu4kgY8OzIDI2LjM1JSBsw6Aga2jDoWNoIGjDoG5nIMSRaSB2w6wgbeG7pWMgxJHDrWNoIGPDoSBuaMOibiAoUGVyc29uYWwgVHJhdmVsKS4gxJBp4buBdSBuw6B5IGNobyB0aOG6pXkgbmjDs20ga2jDoWNoIGjDoG5nIMSRaSBjw7RuZyB0w6FjIGPDsyB4dSBoxrDhu5tuZyDEkcOhbmggZ2nDoSBjYW8gaMahbiB24buBIGThu4tjaCB24bulIGhv4bq3YyB0cuG6o2kgbmdoaeG7h20gdOG7lW5nIHRo4buDIGPhu6dhIGNodXnhur9uIGJheS4NCg0KLSBOZ8aw4bujYyBs4bqhaSwgdHJvbmcgbmjDs20ga2jDoWNoIGjDoG5nIGtow7RuZyBow6BpIGzDsm5nIChEaXNzYXRpc2ZpZWQpLCBt4bq3YyBkw7kgdOG7tyBs4buHIGtow6FjaCDEkWkgY8O0bmcgdMOhYyB24bqrbiBjaGnhur9tIMSRYSBz4buRICg2My41MSUpLCBuaMawbmcgdOG7tyBs4buHIGtow6FjaCDEkWkgdsOsIG3hu6VjIMSRw61jaCBjw6EgbmjDom4gxJHDoyB0xINuZyBsw6puLCBjaGnhur9tIDM2LjQ5JSBjYW8gaMahbiBzbyB24bubaSBuaMOzbSBow6BpIGzDsm5nLg0KDQojIyMjIDQuMS4yLiBLaeG7g20gxJHhu4tuaCB0aOG7kW5nIGvDqg0KDQoqKkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oKioNCg0KJEhfMCQ6IFRy4bqjaSBuZ2hp4buHbSBraMOhY2ggaMOgbmcgdsOgIG3hu6VjIMSRw61jaCBjaHV54bq/biBiYXkgxJHhu5ljIGzhuq1wDQoNCiRIXzEkOiBUcuG6o2kgbmdoaeG7h20ga2jDoWNoIGjDoG5nIHbDoCBt4bulYyDEkcOtY2ggY2h1eeG6v24gYmF5IHBo4bulIHRodeG7mWMNCg0KDQpgYGB7cn0NCiMgVGjhu7FjIGhp4buHbiBraeG7g20gxJHhu4tuaCBDaGkgYsOsbmggcGjGsMahbmcNCmNoaV9zYXRpc2ZhY3Rpb25fdHlwZW9mdHJhdmVsIDwtIGNoaXNxLnRlc3Qoc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbCkNCg0KIyBIaeG7g24gdGjhu4sga+G6v3QgcXXhuqMNCmNoaV9zYXRpc2ZhY3Rpb25fdHlwZW9mdHJhdmVsDQpgYGANCipL4bq/dCBxdeG6ozoqDQoNCi0gR2nDoSB0cuG7iyB0aOG7kW5nIGvDqiBDaGkgYsOsbmggcGjGsMahbmc6IFjCsiA9IDAuNDUzNDkNCg0KLSBC4bqtYyB04buxIGRvIChkZikgPSAxDQoNCi0gcC12YWx1ZSA8IDIuMmUtMTYNCg0KR2nDoSB0cuG7iyBwLXZhbHVlIDwgJFxhbHBoYSQgPSAwLjA1LCBuw6puIGLDoWMgYuG7jyBI4oKAIOG7nyBt4bupYyDDvSBuZ2jEqWEgNSUuDQoNCsSQaeG7gXUgbsOgeSBjaG8gdGjhuqV5IGPDsyBt4buRaSBsacOqbiBo4buHIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogZ2nhu69hIFNhdGlzZmFjdGlvbiB2w6AgVHlwZSBvZiBUcmF2ZWwuIE7Ds2kgY8OhY2gga2jDoWMgbeG7pWMgxJHDrWNoIGNodXnhur9uIGJheSBjw7Mg4bqjbmggaMaw4bufbmcgxJHhur9uIG3hu6ljIMSR4buZIGjDoGkgbMOybmcgY+G7p2Ega2jDoWNoIGjDoG5nLg0KDQojIyMjIDQuMS4zLiBIaeG7h3UgdOG7tyBs4buHIA0KDQpgYGB7cn0NCnNhdGlzZmFjdGlvbl90eXBlb2Z0cmF2ZWwxDQpgYGANCiQkDQpwXzEgPSBQKFx0ZXh0e1NhdGlzZmFjdGlvbn0gPSBcdGV4dHtTYXRpc2ZpZWR9IFxtaWQgXHRleHR7VHlwZSBvZiBUcmF2ZWx9ID0gUGVyc29uYWxUcmF2ZWwpDQokJA0KJCQNCnBfMSA9IFAoXHRleHR7U2F0aXNmYWN0aW9ufSA9IFx0ZXh0e1NhdGlzZmllZH0gXG1pZCBcdGV4dHtUeXBlIG9mIFRyYXZlbH0gPSBCdXNpbmVzc1RyYXZlbCkNCiQkDQoqKkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oKioNCg0KJEhfMCQ6ICRwXzEgLSBwXzIgPSAwJCAoVOG7tyBs4buHIGtow6FjaCBow6BuZyBjw6EgbmjDom4gdsOgIGPDtG5nIHTDoWMgaMOgaSBsw7JuZyBi4bqxbmcgbmhhdSkNCg0KJEhfMSQ6ICRwXzEgLSBwXzIgPCAwJCAoVOG7tyBs4buHIGtow6FjaCBow6BuZyBjw6EgbmjDom4gaMOgaSBsw7JuZyDDrXQgaMahbiB04bu3IGzhu4cga2jDoWNoIGjDoG5nIGPDtG5nIHTDoWMgaMOgaSBsw7JuZykNCg0KYGBge3J9DQoNCmNvdW50cyA8LSBjKHNhdGlzZmFjdGlvbl90eXBlb2Z0cmF2ZWxbInNhdGlzZmllZCIsICJQZXJzb25hbCBUcmF2ZWwiXSwgc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbFsic2F0aXNmaWVkIiwgIkJ1c2luZXNzIHRyYXZlbCJdKSAgIA0KDQp0b3RhbHMgPC0gYyhzdW0oc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbFsic2F0aXNmaWVkIiwgXSksIHN1bShzYXRpc2ZhY3Rpb25fdHlwZW9mdHJhdmVsWyJkaXNzYXRpc2ZpZWQiLCBdKSkgIA0KDQp0ZXN0IDwtIHByb3AudGVzdChjb3VudHMsIHRvdGFscywgYWx0ZXJuYXRpdmUgPSAibGVzcyIsIGNvcnJlY3QgPSBGQUxTRSkNCnRlc3QNCmBgYA0KVOG7tyBs4buHIG3huqt1Og0KDQotIE5ow7NtIDEgKHByb3AgMSk6IDI2LjM1JQ0KDQotIE5ow7NtIDIgKHByb3AgMik6IDg5LjA1JQ0KDQpL4bq/dCBxdeG6ow0KDQotIEtob+G6o25nIHRpbiBj4bqteSA5NSUsIGNobyBoaeG7h3UgJHBfMSAtIHBfMiQgdOG7qyAtMS4wMDAwIMSR4bq/biAtMC42MjM2DQoNCi0gR2nDoSB0cuG7iyBwLXZhbHVlIDwgJFxhbHBoYSQgPSAwLjA1LCBuw6puIGLDoWMgYuG7jyBI4oKAIOG7nyBt4bupYyDDvSBuZ2jEqWEgNSUuDQoNCj0+IFbhuq15IHThu7cgbOG7hyDhu58gbmjDs20gMSAoMjYuMzUlKSBuaOG7jyBoxqFuIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogc28gduG7m2kgbmjDs20gMiAoODkuMDUlKS4NCg0KIyMjIyA0LjEuNC4gVOG7tyBz4buRIE5ndXkgY8ahIChSZWxhdGl2ZSBSaXNrIC0gUlIpOg0KDQpgYGB7cn0NCmxpYnJhcnkoRGVzY1Rvb2xzKQ0KbGlicmFyeShlcGl0b29scykNCg0KDQoNCiMgVMOtbmggUlINCnJpc2tyYXRpbyhzYXRpc2ZhY3Rpb25fdHlwZW9mdHJhdmVsLCBtZXRob2QgPSAid2FsZCIpDQpgYGANCg0KLSBE4buvIGxp4buHdSB04buVbmcgaOG7o3AgY2hvIHRo4bqleSB0cm9uZyBz4buRIDEyOS44ODAga2jDoWNoIGjDoG5nLCBjw7MgNTguNzkzIG5nxrDhu51pIGtow7RuZyBow6BpIGzDsm5nIHbhu5tpIDM3LjMzNyBuZ8aw4budaSB24bubaSBt4bulYyDEkcOtY2ggQnVzaW5lc3MgdHJhdmVsICwgdsOgIDcxLjA4NyBuZ8aw4budaSBow6BpIGzDsm5nIHbhu5tpIDUyLjM1NiBuZ8aw4budaSB24bubaSBt4bulYyDEkcOtY2ggQnVzaW5lc3MgVHJhdmVsLiBLaGkgc28gc8OhbmggdOG7tyBs4buHIG5o4bqtcCB2aeG7h24gZ2nhu69hIGhhaSBuaMOzbSwgbmjDs20gbmfGsOG7nWkga2jDtG5nIGjDoGkgbMOybmcgxJHGsOG7o2MgY2jhu41uIGzDoG0gbmjDs20gdGhhbSBjaGnhur91IHbhu5tpIHThu7cgbOG7hyBy4bunaSBybyBjaHXhuqluIGzDoCAxLg0KDQotIEvhur90IHF14bqjIHTDrW5oIHRvw6FuIGNobyB0aOG6pXkgdOG7tyBz4buRIHLhu6dpIHJvIChSaXNrIFJhdGlvKSBj4bunYSBz4buRIG5nxrDhu51pIGtow7RuZyBow6BpIGzDsm5nIHNvIHbhu5tpIHPhu5EgbmfGsOG7nWkgaMOgaSBsw7JuZyBsw6AgMC43MjIuIMSQaeG7gXUgbsOgeSBjw7MgbmdoxKlhIGzDoCBz4buRIG5nxrDhu51pIGtow7RuZyBow6BpIGzDsm5nIGPDsyBuZ3V5IGPGoSBsw6AgbmfGsOG7nWkgY8OzIG3hu6VjIMSRw61jaCBCdXNpbmVzcyB0cmF2ZWwgdGjhuqVwIGjGoW4gMjcuOCUgc28gduG7m2kgc+G7kSBuZ8aw4budaSBow6BpIGzDsm5nIHRyb25nIG3huqt1IGThu68gbGnhu4d1IG7DoHkuDQoNCi0gS2hv4bqjbmcgdGluIGPhuq15IDk1JSBj4bunYSB04bu3IHPhu5EgcuG7p2kgcm8gY2hvIHPhu5EgbmfGsOG7nWkgaMOgaSBsw7JuZyBkYW8gxJHhu5luZyB04burIDAuNzEwMyDEkeG6v24gMC43MzM5LiBWw6wga2hv4bqjbmcgbsOgeSBraMO0bmcgYmFvIGfhu5NtIGdpw6EgdHLhu4sgMSwgxJFp4buBdSDEkcOzIGNobyB0aOG6pXkgc+G7sSBraMOhYyBiaeG7h3QgduG7gSBraMOhbmggaMOgbmcgY8O0bmcgdMOhYyBow6BpIGzDsm5nIHbDoCBraMO0bmcgaMOgaSBsw7JuZyBjw7MgbeG7qWMgw70gbmdoxKlhIHRo4buRbmcga8OqLiBOw7NpIHTDs20gbOG6oWksIHThu7cgbOG7hyBraMO0bmcgaMOgaSBsw7JuZyDhu58gbmjDs20gQnVzaW5lc3MgdHJhdmVsIGNo4buJIGLhurFuZyBraG/huqNuZyA3Mi4yJSBzbyB24bubaSB04buJIGzhu4cgaMOgaSBsw7JuZywgY2hvIHRo4bqleSBt4bupYyDEkeG7mSBow6BpIGzDsm5nIGPhu6dhIGtow6FjaCDEkWkgY8O0bmcgdMOhYyBjYW8gaMahbiByw7UgcuG7h3Qgc28gduG7m2kgdOG7iSBs4buHIGtow6FjaCBow6BuZyBraMO0bmcgaMOgaSBsw7JuZy4NCg0KDQojIyMjIDQuMS41LiBU4bu3IHPhu5EgQ2jDqm5oIChPZGRzIFJhdGlvIC0gT1IpOg0KDQpgYGB7cn0NCm9yX3Jlc3VsdCA8LSBvZGRzcmF0aW8oc2F0aXNmYWN0aW9uX3R5cGVvZnRyYXZlbCkNCnByaW50KG9yX3Jlc3VsdCkNCmBgYA0KDQpLaMOhY2ggaMOgbmcgxJFpIGPDtG5nIHTDoWMgKEJ1c2luZXNzIHRyYXZlbCkgY8OzIG9kZHMgaMOgaSBsw7JuZyB0aOG6pXAgaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBraMOhY2ggxJFpIGPDoSBuaMOibiAoUGVyc29uYWwgdHJhdmVsKSwgduG7m2kgT1IgPSAwLjYyMzsgOTUlIENJIFswLjYwOCwgMC42MzddLg0KxJBp4buBdSBuw6B5IGNobyB0aOG6pXkga2jDoWNoIMSRaSBjw7RuZyB0w6FjIGPDsyB4dSBoxrDhu5tuZyDEkcOhbmggZ2nDoSBjaHV54bq/biBiYXkgdGjhuqVwIGjGoW4sIHbDoCBz4buxIGtow6FjIGJp4buHdCBuw6B5IGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogKHAgPCAwLjAwMSkuDQoNCg0K