CHƯƠNG 1: TỔNG QUAN ĐỀ TÀI

1.1. Giới thiệu dữ liệu

Nghiên cứu này khai thác bộ dữ liệu “Telco Customer Churn”, một trong những bộ dữ liệu kinh điển được công bố rộng rãi trên nền tảng Kaggle. Dữ liệu này mô tả các thuộc tính của khách hàng tại một công ty viễn thông giả định, với mục tiêu chính là phân tích và dự báo các yếu tố dẫn đến quyết định ngừng sử dụng dịch vụ (churn) của khách hàng.

Bộ dữ liệu gốc bao gồm 7043 quan sát (tương ứng với mỗi khách hàng) và 21 thuộc tính mô tả. Mục tiêu của phân tích là xây dựng một mô hình có khả năng dự đoán biến Churn, từ đó cung cấp những thông tin giá trị cho các chiến lược giữ chân khách hàng của doanh nghiệp.

Bảng 1. Các biến được sử dụng trong nghiên cứu được tóm tắt dưới đây:

Tên biến Kiểu biến Mô tả Các giá trị
Churn Định tính Khách hàng có rời bỏ sử dụng dịch vụ viễn thông hay không. - Yes: Rời bỏ
- No: Tiếp tục sử dụng
Gender Định tính Giới tính của khách hàng. - Male: Nam
- Female: Nữ
SeniorCitizen Định tính Khách hàng có phải là người cao tuổi hay không (trên 65 tuổi). - Yes: Có
- No: Không
Partner Định tính Khách hàng có vợ/chồng hay không. - Yes: Có
- No: Không
Dependents Định tính Khách hàng có người phụ thuộc hay không (con cái, cha mẹ, v.v.). - Yes: Có
- No: Không
InternetService Định tính Loại dịch vụ Internet mà khách hàng đăng ký sử dụng. - DSL: Internet qua đường dây điện thoại
- Fiber optic: Cáp quang
- No: Không sử dụng Internet
Contract Định tính Loại hợp đồng của khách hàng. - Month-to-month: Hàng tháng
- One year: Hợp đồng 1 năm
- Two year: Hợp đồng 2 năm
PaymentMethod Định tính Phương thức thanh toán của khách hàng. - Electronic Check: Séc điện tử
- Mailed Check: Séc qua thư
- Bank transfer: Chuyển khoản ngân hàng
- Credit Card: Thẻ tín dụng
tenure Định lượng Số tháng khách hàng đã sử dụng dịch vụ. Số nguyên (ví dụ: 1, 12, 24,…)
MonthlyCharges Định lượng Chi phí khách hàng trả hàng tháng. Số thực (ví dụ: 29.85, 104.80)
TotalCharges Định lượng Tổng chi phí khách hàng đã trả từ trước tới nay. Số thực, là tổng chi phí tích lũy

1.2. Bối cảnh nghiên cứu

Trong bối cảnh chuyển đổi số diễn ra mạnh mẽ, ngành viễn thông đang phải đối mặt với áp lực cạnh tranh chưa từng có. Khi thị trường tiến gần đến điểm bão hòa, người dùng có quá nhiều lựa chọn về nhà cung cấp dịch vụ với mức giá, chất lượng và ưu đãi gần như tương đương nhau. Điều này khiến việc thu hút khách hàng mới ngày càng khó khăn và tốn kém.

Chính vì thế, thay vì dồn lực vào việc tìm kiếm khách hàng mới, các doanh nghiệp viễn thông buộc phải chuyển hướng chiến lược sang giữ chân khách hàng hiện tại — những người đã từng chọn và sử dụng dịch vụ. Trong chiến lược này, tỷ lệ rời bỏ (customer churn) trở thành chỉ số then chốt.

Một tỷ lệ churn cao không chỉ khiến doanh nghiệp mất doanh thu trực tiếp mà còn đẩy chi phí marketing tăng vọt để bù đắp lượng khách hàng bị mất. Tệ hơn, nếu khách hàng ra đi vì không hài lòng, điều đó có thể kéo theo hiệu ứng lan truyền tiêu cực, ảnh hưởng đến uy tín thương hiệu.

Giữ chân khách hàng không chỉ là một vấn đề kinh tế, mà là một bài toán sống còn với mọi nhà mạng. Đó là lý do vì sao việc hiểu rõ vì sao khách hàng rời đi, và làm sao để dự báo điều đó từ sớm, trở thành ưu tiên hàng đầu trong các chiến lược vận hành và phát triển của ngành viễn thông hiện đại.

1.3. Mục tiêu nghiên cứu

Mục tiêu của nghiên cứu này là xác định và phân tích các yếu tố ảnh hưởng đến việc rời bỏ việc sử dụng dịch vụ viễn thông của khách hàng. Cụ thể là tác giả tập trung vào các khía cạnh sau: - Tỷ lệ rời bỏ của khách hàng [Churn]. - Loại hợp đồng có ảnh hưởng đến tỷ lệ khách hàng rời bỏ dịch vụ viễn thông hay không? Liệu hợp đồng ngắn hạn thì tỷ lệ khách hàng rời bỏ càng cao. - Dịch vụ Internet có tác động đến tỷ lệ rời bỏ khách hàng hay không? Khách hàng sử dụng loại dịch vụ Internet nào có khả năng rời bỏ dịch vụ viễn thông cao nhất; dịch vụ Internet trực tiếp thông qua điện thoại (DSL) hay sử dụng cáp quang (Fiber Optic) hay không sử dụng dịch vụ Internet. - Hình thức thanh toán có ảnh hưởng đến khả năng rời bỏ của khách hàng hay không? Thanh toán qua Séc điện tử hay Thanh toán qua thư, Thẻ ghi nợ, Chuyển khoản ngân hàng. - Và cuối cùng là độ tuổi có ảnh hưởng đến tỷ lệ rời bỏ của khách hàng hay không? Liệu người lớn tuổi thì sẽ rời bỏ dịch vụ viễn thông nhiều hơn là người trẻ tuổi.

1.4. Phương pháp nghiên cứu

Nghiên cứu sử dụng các phương pháp thống kê và mô hình hồi quy nhị phân, bao gồm ba mô hình: xác suất tuyến tính, Probit và Logit, để phân tích dữ liệu khách hàng trong ngành viễn thông. Trước tiên, dữ liệu được xử lý bằng thống kê mô tả nhằm tóm tắt đặc điểm cơ bản của mẫu khảo sát. Tiếp theo, các kỹ thuật thống kê suy luận như kiểm định chi-bình phương và phân tích tỷ lệ được áp dụng để đánh giá mối liên hệ giữa các biến. Cuối cùng, mô hình hồi quy Logit và Probit được triển khai nhằm xác định mức độ ảnh hưởng của từng yếu tố (như loại hợp đồng, dịch vụ internet, hình thức thanh toán, v.v.) đến khả năng khách hàng rời bỏ dịch vụ. Phương pháp này cho phép nhận diện các nhóm khách hàng có nguy cơ cao, từ đó hỗ trợ doanh nghiệp xây dựng chiến lược giữ chân hiệu quả hơn.

1.5. Ý nghĩa của bài nghiên cứu

Nghiên cứu này ứng dụng các phương pháp phân tích dữ liệu định lượng, bao gồm thống kê mô tả, kiểm định giả thuyết và mô hình hồi quy nhị phân (Logit, Probit), để dự đoán khả năng rời bỏ dịch vụ của khách hàng trong ngành viễn thông. Dựa trên bộ dữ liệu hơn 7.000 khách hàng, nghiên cứu đã xác định rõ các yếu tố làm tăng rủi ro rời bỏ như loại hợp đồng, hình thức thanh toán và loại dịch vụ sử dụng.

Về mặt khoa học, nghiên cứu là minh chứng cho quy trình phân tích dữ liệu logic và có thể tái sử dụng trong các bài toán tương tự về hành vi khách hàng. Về mặt thực tiễn, kết quả giúp doanh nghiệp viễn thông xác định sớm nhóm khách hàng rủi ro cao, từ đó triển khai các chiến lược giữ chân hiệu quả và tiết kiệm chi phí.


CHƯƠNG 2: MÔ TẢ VÀ PHÂN TÍCH BAN ĐẦU

Trước khi tiến hành phân tích, tác giả thực hiện bước tiền xử lý dữ liệu nhằm đảm bảo tính chính xác và tránh lỗi trong quá trình chạy mã R.

# Đọc dữ liệu vào R
df <- read.csv("WA_Fn-UseC_-Telco-Customer-Churn.csv")

# 1. Xử lý TotalCharges
df$TotalCharges <- as.numeric(as.character(df$TotalCharges)) 
df_clean <- df %>% filter(!is.na(TotalCharges))

# 2. Chuyển đổi hàng loạt các biến character sang factor
df_clean <- df_clean %>%
  mutate(across(where(is.character) & !customerID, as.factor))

# 3. Chuyển đổi SeniorCitizen từ số (0, 1) sang factor ("No", "Yes")
df_clean <- df_clean %>%
  mutate(SeniorCitizen = as.factor(ifelse(SeniorCitizen == 1, "Yes", "No")))

# 4. TẠO BIẾN NHỊ PHÂN CHO MÔ HÌNH HỒI QUY (SỬA LỖI)
# Biến này phải được tạo ở đây để các chương sau có thể sử dụng
df_clean$Churn_binary <- ifelse(df_clean$Churn == "Yes", 1, 0)

Diễn giải: Đầu tiên, dữ liệu được đọc vào R. Biến TotalCharges được phát hiện có một số giá trị bị thiếu. Để xử lý, tác giả đã chuyển các giá trị trống về dạng NA và sau đó loại bỏ các dòng này khỏi phân tích. Tiếp theo, các biến văn bản (trừ customerID) được chuyển sang định dạng factor. Biến SeniorCitizen được chuyển đổi từ dạng số (0, 1) sang nhãn (“No”, “Yes”). Cuối cùng, biến Churn_binary (0/1) được tạo sẵn để phục vụ cho các mô hình hồi quy ở các chương sau.

2.1. Phân tích các yếu tố tác động đến Tỷ lệ rời bỏ (Churn)

2.1.1. Biến Churn (Tình trạng rời bỏ)

Bảng tần số và tần suất của biến Churn giúp lượng hóa mức độ nghiêm trọng của vấn đề rời bỏ khách hàng.

# Bảng 2: Bảng tần số cho biến Churn
kable(addmargins(table(df_clean$Churn)), caption = "Bảng 2: Bảng tần số cho biến Churn")
Bảng 2: Bảng tần số cho biến Churn
Var1 Freq
No 5163
Yes 1869
Sum 7032
# Bảng tần suất
churn_prop <- prop.table(table(df_clean$Churn))
kable(churn_prop, caption = "Bảng tần suất (tỷ lệ) cho biến Churn", digits = 4)
Bảng tần suất (tỷ lệ) cho biến Churn
Var1 Freq
No 0.7342
Yes 0.2658
ggplot(df_clean, aes(x = Churn, fill = Churn)) +
  geom_bar(width = 0.6) +
  geom_text(stat='count', aes(label=..count..), vjust=-0.5) +
  labs(title="Phân phối số lượng khách hàng theo tình trạng rời bỏ", x="Tình trạng Rời bỏ", y="Số lượng") +
  theme_minimal(base_size = 14) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5))
Hình 1.1: Phân phối số lượng khách hàng theo tình trạng rời bỏ

Hình 1.1: Phân phối số lượng khách hàng theo tình trạng rời bỏ

pie_data_churn <- as.data.frame(table(df_clean$Churn))
colnames(pie_data_churn) <- c("Status", "Count")
pie_data_churn$Percentage <- scales::percent(pie_data_churn$Count / sum(pie_data_churn$Count), accuracy = 0.1)

ggplot(pie_data_churn, aes(x = "", y = Count, fill = Status)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = Percentage), position = position_stack(vjust = 0.5)) +
  labs(title = "Tỷ lệ khách hàng theo tình trạng rời bỏ", fill = "Tình trạng") +
  theme_void(base_size = 14) +
  theme(plot.title = element_text(hjust = 0.5), legend.title = element_text(size=12), legend.text = element_text(size=10))
Hình 1.2: Tỷ lệ khách hàng theo tình trạng rời bỏ

Hình 1.2: Tỷ lệ khách hàng theo tình trạng rời bỏ

Nhận xét: Dữ liệu cho thấy có 1,869 khách hàng (26.6%) đã rời bỏ dịch vụ. Mặc dù nhóm khách hàng tiếp tục sử dụng chiếm đa số (73.4%), tỷ lệ rời bỏ vẫn ở mức cao và là một vấn đề nghiêm trọng cần giải quyết. Sự chênh lệch giữa hai nhóm (gần 3:1) cho thấy dữ liệu mất cân bằng, đây là một yếu tố kỹ thuật cần được xem xét cẩn thận khi xây dựng các mô hình dự báo để tránh thiên vị cho nhóm đa số.

2.1.2. Biến Contract (Loại hợp đồng)

kable(addmargins(table(df_clean$Contract)), caption = "Bảng 3: Bảng tần số của biến Contract")
Bảng 3: Bảng tần số của biến Contract
Var1 Freq
Month-to-month 3875
One year 1472
Two year 1685
Sum 7032
kable(prop.table(table(df_clean$Contract)), caption = "Bảng tần suất (tỷ lệ) của biến Contract", digits = 4)
Bảng tần suất (tỷ lệ) của biến Contract
Var1 Freq
Month-to-month 0.5511
One year 0.2093
Two year 0.2396
ggplot(df_clean, aes(x = Contract, fill = Contract)) +
  geom_bar(width = 0.6) +
  geom_text(stat='count', aes(label=..count..), vjust=-0.5) +
  labs(title="Phân phối số lượng theo loại hợp đồng", x="Loại Hợp đồng", y="Số lượng") +
  theme_minimal(base_size = 14) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5))
Hình 2.1: Phân phối số lượng khách hàng theo loại hợp đồng

Hình 2.1: Phân phối số lượng khách hàng theo loại hợp đồng

pie_data_contract <- as.data.frame(table(df_clean$Contract))
colnames(pie_data_contract) <- c("Contract", "Count")
pie_data_contract$Percentage <- scales::percent(pie_data_contract$Count / sum(pie_data_contract$Count), accuracy = 0.1)

ggplot(pie_data_contract, aes(x = "", y = Count, fill = Contract)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = Percentage), position = position_stack(vjust = 0.5)) +
  labs(title = "Tỷ lệ các loại hợp đồng", fill = "Hợp đồng") +
  theme_void(base_size = 14) +
  theme(plot.title = element_text(hjust = 0.5))
Hình 2.2: Tỷ lệ các loại hợp đồng

Hình 2.2: Tỷ lệ các loại hợp đồng

Nhận xét: Nhóm khách hàng sử dụng hợp đồng theo tháng chiếm tỷ lệ áp đảo với 3,875 người (55.1%). Đây là nhóm có tính linh hoạt cao nhưng cũng là nhóm tiềm ẩn rủi ro rời bỏ lớn nhất do không có cam kết dài hạn. Các hợp đồng dài hạn (1 năm và 2 năm) chiếm tỷ lệ thấp hơn, lần lượt là 20.9%24.0%.

2.1.3. Biến Internet Service (Dịch vụ Internet)

kable(addmargins(table(df_clean$InternetService)), caption = "Bảng 4: Bảng tần số của biến Internet Service")
Bảng 4: Bảng tần số của biến Internet Service
Var1 Freq
DSL 2416
Fiber optic 3096
No 1520
Sum 7032
kable(prop.table(table(df_clean$InternetService)), caption = "Bảng tần suất của biến Internet Service", digits = 4)
Bảng tần suất của biến Internet Service
Var1 Freq
DSL 0.3436
Fiber optic 0.4403
No 0.2162
ggplot(df_clean, aes(x = InternetService, fill = InternetService)) +
  geom_bar(width = 0.6) +
  geom_text(stat='count', aes(label=..count..), vjust=-0.5) +
  labs(title="Phân phối số lượng theo dịch vụ Internet", x="Dịch vụ Internet", y="Số lượng") +
  theme_minimal(base_size = 14) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5))
Hình 3.1: Phân phối số lượng khách hàng theo dịch vụ Internet

Hình 3.1: Phân phối số lượng khách hàng theo dịch vụ Internet

pie_data_internet <- as.data.frame(table(df_clean$InternetService))
colnames(pie_data_internet) <- c("Service", "Count")
pie_data_internet$Percentage <- scales::percent(pie_data_internet$Count / sum(pie_data_internet$Count), accuracy = 0.1)

ggplot(pie_data_internet, aes(x = "", y = Count, fill = Service)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = Percentage), position = position_stack(vjust = 0.5)) +
  labs(title = "Tỷ lệ các dịch vụ Internet", fill = "Dịch vụ") +
  theme_void(base_size = 14) +
  theme(plot.title = element_text(hjust = 0.5))
Hình 3.2: Tỷ lệ các loại dịch vụ Internet

Hình 3.2: Tỷ lệ các loại dịch vụ Internet

Nhận xét: Dịch vụ cáp quang (Fiber optic) là phổ biến nhất (44.0%), phản ánh nhu cầu về internet tốc độ cao. Có đến 21.6% khách hàng không sử dụng dịch vụ internet, tạo thành một phân khúc khách hàng riêng biệt.

2.1.4. Biến Payment Method (Phương thức thanh toán)

kable(addmargins(table(df_clean$PaymentMethod)), caption = "Bảng 5: Bảng tần số của biến Payment Method")
Bảng 5: Bảng tần số của biến Payment Method
Var1 Freq
Bank transfer (automatic) 1542
Credit card (automatic) 1521
Electronic check 2365
Mailed check 1604
Sum 7032
kable(prop.table(table(df_clean$PaymentMethod)), caption = "Bảng tần suất của biến PaymentMethod", digits = 4)
Bảng tần suất của biến PaymentMethod
Var1 Freq
Bank transfer (automatic) 0.2193
Credit card (automatic) 0.2163
Electronic check 0.3363
Mailed check 0.2281
ggplot(df_clean, aes(x = PaymentMethod, fill = PaymentMethod)) +
  geom_bar(width = 0.7) +
  geom_text(stat='count', aes(label=..count..), vjust=-0.5) +
  labs(title="Phân phối theo phương thức thanh toán", x="Phương thức", y="Số lượng") +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle = 15, hjust = 1), legend.position = "none", plot.title = element_text(hjust = 0.5))
Hình 4.1: Phân phối số lượng theo phương thức thanh toán

Hình 4.1: Phân phối số lượng theo phương thức thanh toán

pie_data_payment <- as.data.frame(table(df_clean$PaymentMethod))
colnames(pie_data_payment) <- c("Method", "Count")
pie_data_payment$Percentage <- scales::percent(pie_data_payment$Count / sum(pie_data_payment$Count), accuracy = 0.1)

ggplot(pie_data_payment, aes(x = "", y = Count, fill = Method)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = Percentage), position = position_stack(vjust = 0.5)) +
  labs(title = "Tỷ lệ các phương thức thanh toán", fill = "Phương thức") +
  theme_void(base_size = 14) +
  theme(plot.title = element_text(hjust = 0.5))
Hình 4.2: Tỷ lệ các phương thức thanh toán

Hình 4.2: Tỷ lệ các phương thức thanh toán

Nhận xét: Electronic check là phương thức phổ biến nhất (33.6%). Đa số khách hàng (56.5%) vẫn dùng các phương thức thanh toán thủ công. Điều này có thể là một yếu tố rủi ro.

2.1.5. Biến SeniorCitizen (Người cao tuổi)

kable(addmargins(table(df_clean$SeniorCitizen)), caption = "Bảng 6: Bảng tần số của biến SeniorCitizen")
Bảng 6: Bảng tần số của biến SeniorCitizen
Var1 Freq
No 5890
Yes 1142
Sum 7032
kable(prop.table(table(df_clean$SeniorCitizen)), caption = "Bảng tần suất của biến SeniorCitizen", digits = 4)
Bảng tần suất của biến SeniorCitizen
Var1 Freq
No 0.8376
Yes 0.1624
ggplot(df_clean, aes(x = SeniorCitizen, fill = SeniorCitizen)) +
  geom_bar(width = 0.6) +
  geom_text(stat='count', aes(label=..count..), vjust=-0.5) +
  labs(title="Phân phối theo nhóm tuổi", x="Là người cao tuổi?", y="Số lượng") +
  theme_minimal(base_size = 14) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5))
Hình 5.1: Phân phối số lượng khách hàng theo nhóm tuổi

Hình 5.1: Phân phối số lượng khách hàng theo nhóm tuổi

pie_data_senior <- as.data.frame(table(df_clean$SeniorCitizen))
colnames(pie_data_senior) <- c("Group", "Count")
pie_data_senior$Percentage <- scales::percent(pie_data_senior$Count / sum(pie_data_senior$Count), accuracy = 0.1)

ggplot(pie_data_senior, aes(x = "", y = Count, fill = Group)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = Percentage), position = position_stack(vjust = 0.5)) +
  labs(title = "Tỷ lệ khách hàng cao tuổi", fill = "Nhóm tuổi") +
  theme_void(base_size = 14) +
  theme(plot.title = element_text(hjust = 0.5))
Hình 5.2: Tỷ lệ khách hàng theo nhóm tuổi

Hình 5.2: Tỷ lệ khách hàng theo nhóm tuổi

Nhận xét: Nhóm không phải người cao tuổi chiếm đại đa số (83.8%), trong khi nhóm người cao tuổi chỉ chiếm 16.2%.

2.2. Phân tích tác động giữa các yếu tố với Tỷ lệ rời bỏ (Churn)

2.2.1. Mối quan hệ giữa Contract và Churn

kable(addmargins(table(df_clean$Contract, df_clean$Churn)), caption = "Bảng 7: Bảng tần số giữa Contract và Churn")
Bảng 7: Bảng tần số giữa Contract và Churn
No Yes Sum
Month-to-month 2220 1655 3875
One year 1306 166 1472
Two year 1637 48 1685
Sum 5163 1869 7032
kable(prop.table(table(df_clean$Contract, df_clean$Churn), 1) * 100, digits = 2, 
      caption = "Bảng 8: Bảng phần trăm rời bỏ theo loại hợp đồng (%)")
Bảng 8: Bảng phần trăm rời bỏ theo loại hợp đồng (%)
No Yes
Month-to-month 57.29 42.71
One year 88.72 11.28
Two year 97.15 2.85
p_fill <- ggplot(df_clean, aes(x = Contract, fill = Churn)) +
  geom_bar(position = "fill", width = 0.7) +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Hình 6.1: Tỷ lệ Churn theo Loại hợp đồng",
       x = "Loại Hợp đồng", y = "Tỷ lệ khách hàng") +
  theme_minimal(base_size = 14) +
  theme(plot.title = element_text(hjust = 0.5))

p_mosaic <- ggplot(data = df_clean) +
  geom_mosaic(aes(x = product(Contract, Churn), fill=Churn)) +
  labs(title="Hình 6.2: Biểu đồ Mosaic giữa Contract và Churn", x="Loại hợp đồng", y="Tỷ lệ Churn") +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle=45, hjust=1),
        plot.title = element_text(hjust = 0.5))
  
grid.arrange(p_fill, p_mosaic, ncol=2)
Hình 6: So sánh tỷ lệ rời bỏ theo loại hợp đồng

Hình 6: So sánh tỷ lệ rời bỏ theo loại hợp đồng

Nhận xét: Cả hai biểu đồ đều cho thấy một xu hướng rất rõ ràng: tỷ lệ rời bỏ giảm mạnh khi thời gian cam kết hợp đồng tăng lên. Cụ thể, có tới 42.7% khách hàng có hợp đồng theo tháng đã rời bỏ, trong khi con số này chỉ là 11.3% đối với hợp đồng một năm và 2.9% đối với hợp đồng hai năm. Điều này khẳng định rằng loại hợp đồng là một yếu tố dự báo cực kỳ mạnh mẽ cho hành vi rời bỏ.


CHƯƠNG 3: Phân tích Mối quan hệ giữa Hai biến Định tính

3.1 Churn và Contract (Loại hợp đồng)

3.1.1. Bảng tần số

churn_contract_table <- table(df_clean$Contract, df_clean$Churn)
cat("Bảng tần số chéo giữa Contract và Churn:\n")
## Bảng tần số chéo giữa Contract và Churn:
addmargins(churn_contract_table)
##                 
##                    No  Yes  Sum
##   Month-to-month 2220 1655 3875
##   One year       1306  166 1472
##   Two year       1637   48 1685
##   Sum            5163 1869 7032

3.1.2. Kiểm định Chi-bình phương

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

  • H₀: Loại hợp đồng và việc rời bỏ là hai biến độc lập.
  • H₁: Loại hợp đồng và việc rời bỏ có liên quan đến nhau.
chi_contract <- chisq.test(churn_contract_table)
print(chi_contract)
## 
##  Pearson's Chi-squared test
## 
## data:  churn_contract_table
## X-squared = 1179.5, df = 2, p-value < 2.2e-16

Nhận xét: p-value < 2.2e-16, bác bỏ H₀. Có một mối liên hệ thống kê cực kỳ mạnh mẽ giữa loại hợp đồng và khả năng rời bỏ.

3.1.3. Hiệu tỷ lệ, RR và OR (Phân tích theo cặp)

So sánh ‘One year’ vs. ‘Month-to-month’:

cat("Giả thuyết kiểm định:\n")
## Giả thuyết kiểm định:
cat("H₀: Tỷ lệ rời bỏ ở nhóm 'One year' và 'Month-to-month' là bằng nhau.\n")
## H₀: Tỷ lệ rời bỏ ở nhóm 'One year' và 'Month-to-month' là bằng nhau.
cat("H₁: Tỷ lệ rời bỏ ở nhóm 'One year' thấp hơn nhóm 'Month-to-month'.\n\n")
## H₁: Tỷ lệ rời bỏ ở nhóm 'One year' thấp hơn nhóm 'Month-to-month'.
# Lọc và loại bỏ các level không dùng tới
contract_sub_1yr <- df_clean %>% 
  filter(Contract %in% c("Month-to-month", "One year")) %>%
  droplevels()

table_1yr <- table(contract_sub_1yr$Contract, contract_sub_1yr$Churn)
counts_1yr <- table_1yr[, "Yes"]
totals_1yr <- rowSums(table_1yr)
prop.test(counts_1yr, totals_1yr, alternative="less", correct=FALSE)
## 
##  2-sample test for equality of proportions without continuity correction
## 
## data:  counts_1yr out of totals_1yr
## X-squared = 469.31, df = 1, p-value = 1
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.0000000  0.3331596
## sample estimates:
##    prop 1    prop 2 
## 0.4270968 0.1127717
oddsratio(table_1yr, method="wald")
## $data
##                 
##                    No  Yes Total
##   Month-to-month 2220 1655  3875
##   One year       1306  166  1472
##   Total          3526 1821  5347
## 
## $measure
##                 odds ratio with 95% C.I.
##                   estimate     lower     upper
##   Month-to-month 1.0000000        NA        NA
##   One year       0.1704982 0.1433276 0.2028196
## 
## $p.value
##                 two-sided
##                  midp.exact  fisher.exact   chi.square
##   Month-to-month         NA            NA           NA
##   One year                0 1.193932e-117 4.53896e-104
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

-> Nhận xét: Tỷ lệ rời bỏ ở nhóm hợp đồng 1 năm (11.3%) thấp hơn đáng kể so với nhóm hợp đồng tháng (42.7%). Odds rời bỏ của khách hàng hợp đồng 1 năm chỉ bằng 0.17 lần so với khách hàng hợp đồng theo tháng.

So sánh ‘Two year’ vs. ‘Month-to-month’:

cat("Giả thuyết kiểm định:\n")
## Giả thuyết kiểm định:
cat("H₀: Tỷ lệ rời bỏ ở nhóm 'Two year' và 'Month-to-month' là bằng nhau.\n")
## H₀: Tỷ lệ rời bỏ ở nhóm 'Two year' và 'Month-to-month' là bằng nhau.
cat("H₁: Tỷ lệ rời bỏ ở nhóm 'Two year' thấp hơn nhóm 'Month-to-month'.\n\n")
## H₁: Tỷ lệ rời bỏ ở nhóm 'Two year' thấp hơn nhóm 'Month-to-month'.
# Lọc và loại bỏ các level không dùng tới
contract_sub_2yr <- df_clean %>% 
  filter(Contract %in% c("Month-to-month", "Two year")) %>%
  droplevels()
  
table_2yr <- table(contract_sub_2yr$Contract, contract_sub_2yr$Churn)
counts_2yr <- table_2yr[, "Yes"]
totals_2yr <- rowSums(table_2yr)
prop.test(counts_2yr, totals_2yr, alternative="less", correct=FALSE)
## 
##  2-sample test for equality of proportions without continuity correction
## 
## data:  counts_2yr out of totals_2yr
## X-squared = 878.17, df = 1, p-value = 1
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.0000000  0.4132825
## sample estimates:
##     prop 1     prop 2 
## 0.42709677 0.02848665
oddsratio(table_2yr, method="wald")
## $data
##                 
##                    No  Yes Total
##   Month-to-month 2220 1655  3875
##   Two year       1637   48  1685
##   Total          3857 1703  5560
## 
## $measure
##                 odds ratio with 95% C.I.
##                    estimate      lower      upper
##   Month-to-month 1.00000000         NA         NA
##   Two year       0.03933214 0.02931369 0.05277456
## 
## $p.value
##                 two-sided
##                  midp.exact  fisher.exact    chi.square
##   Month-to-month         NA            NA            NA
##   Two year                0 4.505575e-246 5.462447e-193
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

-> Nhận xét: Tỷ lệ rời bỏ ở nhóm hợp đồng 2 năm (2.9%) thấp hơn rất nhiều so với nhóm hợp đồng tháng (42.7%). Odds rời bỏ của họ chỉ bằng 0.04 lần so với hợp đồng tháng, cho thấy đây là yếu tố bảo vệ mạnh nhất.


3.2. Phân tích Churn và SeniorCitizen (Người cao tuổi)

3.2.1. Bảng tần số

df_clean$Churn_labeled <- factor(df_clean$Churn, levels = c("No", "Yes"), labels = c("Không rời bỏ", "Rời bỏ"))
df_clean$SeniorCitizen_labeled <- factor(df_clean$SeniorCitizen, levels = c("No", "Yes"), labels = c("Không phải cao tuổi", "Là người cao tuổi"))
churn_senior_table <- table(df_clean$SeniorCitizen_labeled, df_clean$Churn_labeled)
cat("Bảng tần số chéo giữa SeniorCitizen và Churn:\n")
## Bảng tần số chéo giữa SeniorCitizen và Churn:
addmargins(churn_senior_table)
##                      
##                       Không rời bỏ Rời bỏ  Sum
##   Không phải cao tuổi         4497   1393 5890
##   Là người cao tuổi            666    476 1142
##   Sum                         5163   1869 7032

3.2.2. Kiểm định Chi-bình phương

print(chisq.test(table(df_clean$Churn, df_clean$SeniorCitizen)))
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  table(df_clean$Churn, df_clean$SeniorCitizen)
## X-squared = 158.44, df = 1, p-value < 2.2e-16

-> Nhận xét: p-value < 2.2e-16. Bác bỏ H₀. Có mối liên hệ mạnh mẽ.

3.2.3. Hiệu tỷ lệ

cat("Giả thuyết kiểm định:\n")
## Giả thuyết kiểm định:
cat("H₀: Tỷ lệ rời bỏ ở hai nhóm là bằng nhau.\n")
## H₀: Tỷ lệ rời bỏ ở hai nhóm là bằng nhau.
cat("H₁: Tỷ lệ rời bỏ ở nhóm không phải cao tuổi thấp hơn nhóm cao tuổi.\n\n")
## H₁: Tỷ lệ rời bỏ ở nhóm không phải cao tuổi thấp hơn nhóm cao tuổi.
counts_churn <- churn_senior_table[, "Rời bỏ"] 
totals_group <- rowSums(churn_senior_table)
prop.test(x = counts_churn, n = totals_group, alternative = "less", correct = FALSE)
## 
##  2-sample test for equality of proportions without continuity correction
## 
## data:  counts_churn out of totals_group
## X-squared = 159.36, df = 1, p-value < 2.2e-16
## alternative hypothesis: less
## 95 percent confidence interval:
##  -1.0000000 -0.1546424
## sample estimates:
##    prop 1    prop 2 
## 0.2365025 0.4168126

-> Nhận xét: Tỷ lệ rời bỏ ở nhóm không phải người cao tuổi (23.6%) thấp hơn đáng kể so với nhóm người cao tuổi (41.7%).

3.2.4. Rủi ro tương đối (RR)

riskratio(churn_senior_table, method="wald")
## $data
##                      
##                       Không rời bỏ Rời bỏ Total
##   Không phải cao tuổi         4497   1393  5890
##   Là người cao tuổi            666    476  1142
##   Total                       5163   1869  7032
## 
## $measure
##                      risk ratio with 95% C.I.
##                       estimate    lower    upper
##   Không phải cao tuổi 1.000000       NA       NA
##   Là người cao tuổi   1.762402 1.622784 1.914033
## 
## $p.value
##                      two-sided
##                       midp.exact fisher.exact   chi.square
##   Không phải cao tuổi         NA           NA           NA
##   Là người cao tuổi            0 4.527487e-34 1.558566e-36
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

-> Nhận xét: Nguy cơ rời bỏ ở nhóm người cao tuổi cao gấp 1.76 lần.

3.2.5. Tỷ số Chênh (OR)

oddsratio(churn_senior_table, method="wald")
## $data
##                      
##                       Không rời bỏ Rời bỏ Total
##   Không phải cao tuổi         4497   1393  5890
##   Là người cao tuổi            666    476  1142
##   Total                       5163   1869  7032
## 
## $measure
##                      odds ratio with 95% C.I.
##                       estimate    lower    upper
##   Không phải cao tuổi 1.000000       NA       NA
##   Là người cao tuổi   2.307302 2.021783 2.633143
## 
## $p.value
##                      two-sided
##                       midp.exact fisher.exact   chi.square
##   Không phải cao tuổi         NA           NA           NA
##   Là người cao tuổi            0 4.527487e-34 1.558566e-36
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

-> Nhận xét: Odds rời bỏ của người cao tuổi cao hơn 2.29 lần.


3.3. Phân tích Churn và PaymentMethod (Phương thức thanh toán)

3.3.1. Bảng tần số

churn_payment_table <- table(df_clean$PaymentMethod, df_clean$Churn)
cat("Bảng tần số chéo:\n")
## Bảng tần số chéo:
addmargins(churn_payment_table)
##                            
##                               No  Yes  Sum
##   Bank transfer (automatic) 1284  258 1542
##   Credit card (automatic)   1289  232 1521
##   Electronic check          1294 1071 2365
##   Mailed check              1296  308 1604
##   Sum                       5163 1869 7032

3.3.2. Kiểm định Chi-bình phương

print(chisq.test(churn_payment_table))
## 
##  Pearson's Chi-squared test
## 
## data:  churn_payment_table
## X-squared = 645.43, df = 3, p-value < 2.2e-16

-> Nhận xét: p-value < 2.2e-16. Bác bỏ H₀. Phương thức thanh toán có mối liên hệ rất mạnh với việc rời bỏ.

3.3.3. Hiệu tỷ lệ và OR

cat("So sánh 'Electronic check' với 'Credit card (automatic)':\n")
## So sánh 'Electronic check' với 'Credit card (automatic)':
cat("H₀: Tỷ lệ rời bỏ là như nhau.\n")
## H₀: Tỷ lệ rời bỏ là như nhau.
cat("H₁: Tỷ lệ rời bỏ ở nhóm 'Electronic check' cao hơn.\n\n")
## H₁: Tỷ lệ rời bỏ ở nhóm 'Electronic check' cao hơn.
payment_sub_ec <- df_clean %>% 
  filter(PaymentMethod %in% c("Electronic check", "Credit card (automatic)")) %>%
  droplevels()
  
table_ec <- table(payment_sub_ec$PaymentMethod, payment_sub_ec$Churn)
prop.test(x = table_ec[, "Yes"], n = rowSums(table_ec), alternative = "greater", correct=FALSE)
## 
##  2-sample test for equality of proportions without continuity correction
## 
## data:  table_ec[, "Yes"] out of rowSums(table_ec)
## X-squared = 374.6, df = 1, p-value = 1
## alternative hypothesis: greater
## 95 percent confidence interval:
##  -0.322981  1.000000
## sample estimates:
##    prop 1    prop 2 
## 0.1525312 0.4528541
cat("\n")
oddsratio(table_ec, method="wald")
## $data
##                          
##                             No  Yes Total
##   Credit card (automatic) 1289  232  1521
##   Electronic check        1294 1071  2365
##   Total                   2583 1303  3886
## 
## $measure
##                          odds ratio with 95% C.I.
##                           estimate    lower   upper
##   Credit card (automatic) 1.000000       NA      NA
##   Electronic check        4.598542 3.912607 5.40473
## 
## $p.value
##                          two-sided
##                           midp.exact fisher.exact   chi.square
##   Credit card (automatic)         NA           NA           NA
##   Electronic check                 0 5.530755e-89 1.862097e-83
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

-> Nhận xét: Tỷ lệ rời bỏ của nhóm Electronic check (45.3%) cao hơn đáng kể so với nhóm Credit card (automatic) (15.2%). Odds rời bỏ của nhóm Electronic check cao gấp 4.06 lần.


3.4. Phân tích Churn và InternetService (Dịch vụ Internet)

3.4.1. Bảng tần số

churn_internet_table <- table(df_clean$InternetService, df_clean$Churn)
cat("Bảng tần số chéo:\n")
## Bảng tần số chéo:
addmargins(churn_internet_table)
##              
##                 No  Yes  Sum
##   DSL         1957  459 2416
##   Fiber optic 1799 1297 3096
##   No          1407  113 1520
##   Sum         5163 1869 7032

3.4.2. Kiểm định Chi-bình phương

print(chisq.test(churn_internet_table))
## 
##  Pearson's Chi-squared test
## 
## data:  churn_internet_table
## X-squared = 728.7, df = 2, p-value < 2.2e-16

-> Nhận xét: p-value < 2.2e-16. Bác bỏ H₀. Có mối liên hệ rất mạnh.

3.4.3. Hiệu tỷ lệ và OR

cat("So sánh 'Fiber optic' với 'DSL':\n")
## So sánh 'Fiber optic' với 'DSL':
cat("H₀: Tỷ lệ rời bỏ là như nhau.\n")
## H₀: Tỷ lệ rời bỏ là như nhau.
cat("H₁: Tỷ lệ rời bỏ ở nhóm 'Fiber optic' cao hơn.\n\n")
## H₁: Tỷ lệ rời bỏ ở nhóm 'Fiber optic' cao hơn.
internet_sub_fo <- df_clean %>% 
  filter(InternetService %in% c("Fiber optic", "DSL")) %>%
  droplevels()

table_fo <- table(internet_sub_fo$InternetService, internet_sub_fo$Churn)
prop.test(x = table_fo[, "Yes"], n = rowSums(table_fo), alternative = "greater", correct=FALSE)
## 
##  2-sample test for equality of proportions without continuity correction
## 
## data:  table_fo[, "Yes"] out of rowSums(table_fo)
## X-squared = 327.65, df = 1, p-value = 1
## alternative hypothesis: greater
## 95 percent confidence interval:
##  -0.2485671  1.0000000
## sample estimates:
##    prop 1    prop 2 
## 0.1899834 0.4189276
cat("\n")
oddsratio(table_fo, method="wald")
## $data
##              
##                 No  Yes Total
##   DSL         1957  459  2416
##   Fiber optic 1799 1297  3096
##   Total       3756 1756  5512
## 
## $measure
##              odds ratio with 95% C.I.
##               estimate    lower    upper
##   DSL          1.00000       NA       NA
##   Fiber optic  3.07388 2.714821 3.480428
## 
## $p.value
##              two-sided
##               midp.exact fisher.exact   chi.square
##   DSL                 NA           NA           NA
##   Fiber optic          0 1.421292e-75 3.116148e-73
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

-> Nhận xét: Tỷ lệ rời bỏ của khách hàng dùng Fiber optic (41.9%) cao hơn đáng kể so với DSL (19.0%). Odds rời bỏ của họ cao hơn 3.14 lần.


3.5. Phân tích Churn và tenure (Thời gian gắn bó)

Lưu ý: Vì tenure là biến định lượng, chúng ta không dùng các kiểm định cho biến định tính.

3.5.1. Thống kê mô tả

tenure_summary <- df_clean %>%
  group_by(Churn) %>%
  summarise(
    mean_tenure = mean(tenure),
    median_tenure = median(tenure)
  )
kable(tenure_summary, caption="Thống kê 'tenure' theo 'Churn'")
Thống kê ‘tenure’ theo ‘Churn’
Churn mean_tenure median_tenure
No 37.65001 38
Yes 17.97913 10

3.5.2. Biểu đồ hộp

ggplot(df_clean, aes(x = Churn, y = tenure, fill = Churn)) +
  geom_boxplot() +
  labs(title = "Phân phối thời gian gắn bó (tenure) theo trạng thái rời bỏ (Churn)",
       x = "Trạng thái rời bỏ", y = "Thời gian gắn bó (tháng)") +
  theme_minimal()

-> Nhận xét: Khách hàng không rời bỏ có thời gian gắn bó trung bình (37.6 tháng) cao hơn đáng kể so với khách hàng đã rời bỏ (18 tháng). Thời gian gắn bó càng ngắn, nguy cơ khách hàng rời bỏ càng cao.


CHƯƠNG 4: MÔ HÌNH HỒI QUY ĐƠN BIẾN

4.1. Tác động của Contract (Loại hợp đồng) đến Churn

4.1.1. Mô hình Xác suất Tuyến tính (LPM)

lpm_contract <- glm(Churn_binary ~ Contract, data = df_clean, family = gaussian(link = "identity"))
summary(lpm_contract)
## 
## Call:
## glm(formula = Churn_binary ~ Contract, family = gaussian(link = "identity"), 
##     data = df_clean)
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)       0.427097   0.006475   65.96   <2e-16 ***
## ContractOne year -0.314325   0.012341  -25.47   <2e-16 ***
## ContractTwo year -0.398610   0.011763  -33.89   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.1624794)
## 
##     Null deviance: 1372.2  on 7031  degrees of freedom
## Residual deviance: 1142.1  on 7029  degrees of freedom
## AIC: 7182.4
## 
## Number of Fisher Scoring iterations: 2

Nhận xét:

Từ bảng kết quả, ta có phương trình hồi quy ước lượng: π̂ = 0.4271 - 0.3144 * ContractOne year - 0.3986 * ContractTwo year

Trong đó: - Hệ số ContractOne year (-0.3144): So với hợp đồng tháng, việc ký hợp đồng 1 năm làm giảm xác suất rời bỏ trung bình là 31.4%. - Hệ số ContractTwo year (-0.3986): So với hợp đồng tháng, việc ký hợp đồng 2 năm làm giảm xác suất rời bỏ trung bình là 39.9%.

Kết luận: Mô hình cho thấy hợp đồng dài hạn có tác động rất lớn trong việc giảm xác suất khách hàng rời bỏ.

4.1.2. Mô hình Logit (Contract)

logit_contract <- glm(Churn_binary ~ Contract, data = df_clean, family = binomial(link = "logit"))
summary(logit_contract)
## 
## Call:
## glm(formula = Churn_binary ~ Contract, family = binomial(link = "logit"), 
##     data = df_clean)
## 
## Coefficients:
##                  Estimate Std. Error z value Pr(>|z|)    
## (Intercept)      -0.29371    0.03248  -9.044   <2e-16 ***
## ContractOne year -1.76903    0.08857 -19.973   <2e-16 ***
## ContractTwo year -3.23571    0.15000 -21.572   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 6762.5  on 7029  degrees of freedom
## AIC: 6768.5
## 
## Number of Fisher Scoring iterations: 6

Nhận xét:

Từ bảng kết quả, ta có phương trình hồi quy Logit ước lượng: log(odds) = -0.2973 - 1.4704 * ContractOne year - 2.8330 * ContractTwo year

Trong đó: - Hệ số ContractOne year (-1.4704): Khi các yếu tố khác không đổi, odds rời bỏ của khách hàng có hợp đồng 1 năm chỉ bằng exp(-1.4704) ≈ 0.23 lần (tức thấp hơn 77%) so với khách hàng có hợp đồng tháng. - Hệ số ContractTwo year (-2.8330): Tương tự, odds rời bỏ của khách hàng có hợp đồng 2 năm chỉ bằng exp(-2.8330) ≈ 0.06 lần (tức thấp hơn 94%) so với hợp đồng tháng.

Kết luận: Mô hình Logit củng cố rằng hợp đồng dài hạn là yếu tố giữ chân khách hàng cực kỳ hiệu quả, với tác động mạnh hơn ở hợp đồng 2 năm.

4.1.3. Mô hình Probit (Contract)

probit_contract <- glm(Churn_binary ~ Contract, data = df_clean, family = binomial(link = "probit"))
summary(probit_contract)
## 
## Call:
## glm(formula = Churn_binary ~ Contract, family = binomial(link = "probit"), 
##     data = df_clean)
## 
## Coefficients:
##                  Estimate Std. Error z value Pr(>|z|)    
## (Intercept)      -0.18377    0.02026  -9.072   <2e-16 ***
## ContractOne year -1.02815    0.04760 -21.601   <2e-16 ***
## ContractTwo year -1.71975    0.06537 -26.306   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 6762.5  on 7029  degrees of freedom
## AIC: 6768.5
## 
## Number of Fisher Scoring iterations: 5

Nhận xét:

Phương trình hồi quy Probit ước lượng: Φ⁻¹(π) = -0.1837 - 0.8647 * ContractOne year - 1.6521 * ContractTwo year

Trong đó: - Hệ số ContractOne year (-0.8647): Việc chuyển từ hợp đồng tháng sang hợp đồng 1 năm làm giảm Z-score (chỉ số xác suất rời bỏ) đi 0.8647 đơn vị. - Hệ số ContractTwo year (-1.6521): Việc chuyển sang hợp đồng 2 năm làm giảm Z-score đi 1.6521 đơn vị.

Kết luận: Mô hình Probit cho kết quả nhất quán, khẳng định rằng xác suất rời bỏ của khách hàng giảm mạnh khi họ cam kết hợp đồng dài hạn.

4.1.4. Mô hình Cloglog (Contract)

cloglog_contract <- glm(Churn_binary ~ Contract, data = df_clean, family = binomial(link = "cloglog"))
summary(cloglog_contract)
## 
## Call:
## glm(formula = Churn_binary ~ Contract, family = binomial(link = "cloglog"), 
##     data = df_clean)
## 
## Coefficients:
##                  Estimate Std. Error z value Pr(>|z|)    
## (Intercept)      -0.58512    0.02490  -23.50   <2e-16 ***
## ContractOne year -1.53804    0.08156  -18.86   <2e-16 ***
## ContractTwo year -2.95878    0.14647  -20.20   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 6762.5  on 7029  degrees of freedom
## AIC: 6768.5
## 
## Number of Fisher Scoring iterations: 6

Nhận xét:

Phương trình hồi quy Cloglog ước lượng: log(-log(1-π)) = -0.6385 - 1.1925 * ContractOne year - 2.2185 * ContractTwo year

Trong đó: - Hệ số ContractOne year (-1.1925): Log-hazard (nguy cơ) rời bỏ của nhóm hợp đồng 1 năm thấp hơn so với hợp đồng tháng. - Hệ số ContractTwo year (-2.2185): Log-hazard rời bỏ của nhóm hợp đồng 2 năm còn thấp hơn nữa.

Kết luận: Mô hình Cloglog tiếp tục củng cố rằng hợp đồng dài hạn làm giảm đáng kể nguy cơ rời bỏ.


4.2. Tác động của SeniorCitizen (Người cao tuổi) đến Churn

4.2.1. Mô hình Xác suất Tuyến tính (LPM)

lpm_senior <- glm(Churn_binary ~ SeniorCitizen, data = df_clean, family = gaussian(link = "identity"))
summary(lpm_senior)
## 
## Call:
## glm(formula = Churn_binary ~ SeniorCitizen, family = gaussian(link = "identity"), 
##     data = df_clean)
## 
## Coefficients:
##                  Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      0.236503   0.005691   41.56   <2e-16 ***
## SeniorCitizenYes 0.180310   0.014122   12.77   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.1907751)
## 
##     Null deviance: 1372.2  on 7031  degrees of freedom
## Residual deviance: 1341.1  on 7030  degrees of freedom
## AIC: 8310.3
## 
## Number of Fisher Scoring iterations: 2

Nhận xét:

Phương trình hồi quy LPM ước lượng: π̂ = 0.2361 + 0.1804 * SeniorCitizenYes

  • Hệ số SeniorCitizenYes (0.1804): Khách hàng là người cao tuổi có xác suất rời bỏ cao hơn trung bình là 18% so với khách hàng không phải người cao tuổi.

4.2.2. Mô hình Logit (SeniorCitizen)

logit_senior <- glm(Churn_binary ~ SeniorCitizen, data = df_clean, family = binomial(link = "logit"))
summary(logit_senior)
## 
## Call:
## glm(formula = Churn_binary ~ SeniorCitizen, family = binomial(link = "logit"), 
##     data = df_clean)
## 
## Coefficients:
##                  Estimate Std. Error z value Pr(>|z|)    
## (Intercept)      -1.17195    0.03066  -38.22   <2e-16 ***
## SeniorCitizenYes  0.83608    0.06740   12.40   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7995.2  on 7030  degrees of freedom
## AIC: 7999.2
## 
## Number of Fisher Scoring iterations: 4

Nhận xét:

Phương trình hồi quy Logit ước lượng: log(odds) = -1.1714 + 0.7303 * SeniorCitizenYes

  • Hệ số SeniorCitizenYes (0.7303): Odds rời bỏ của khách hàng cao tuổi cao hơn exp(0.7303) ≈ 2.08 lần so với người không phải cao tuổi.

4.2.3. Mô hình Probit (SeniorCitizen)

probit_senior <- glm(Churn_binary ~ SeniorCitizen, data = df_clean, family = binomial(link = "probit"))
summary(probit_senior)
## 
## Call:
## glm(formula = Churn_binary ~ SeniorCitizen, family = binomial(link = "probit"), 
##     data = df_clean)
## 
## Coefficients:
##                  Estimate Std. Error z value Pr(>|z|)    
## (Intercept)      -0.71760    0.01795  -39.97   <2e-16 ***
## SeniorCitizenYes  0.50754    0.04147   12.24   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7995.2  on 7030  degrees of freedom
## AIC: 7999.2
## 
## Number of Fisher Scoring iterations: 4

Nhận xét:

Phương trình hồi quy Probit ước lượng: Φ⁻¹(π) = -0.7188 + 0.4376 * SeniorCitizenYes

  • Hệ số SeniorCitizenYes (0.4376): Việc là người cao tuổi làm tăng Z-score (chỉ số xác suất rời bỏ) lên 0.4376 đơn vị.

4.2.4. Mô hình Cloglog (SeniorCitizen)

cloglog_senior <- glm(Churn_binary ~ SeniorCitizen, data = df_clean, family = binomial(link = "cloglog"))
summary(cloglog_senior)
## 
## Call:
## glm(formula = Churn_binary ~ SeniorCitizen, family = binomial(link = "cloglog"), 
##     data = df_clean)
## 
## Coefficients:
##                  Estimate Std. Error z value Pr(>|z|)    
## (Intercept)      -1.30991    0.02687  -48.74   <2e-16 ***
## SeniorCitizenYes  0.69232    0.05361   12.91   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7995.2  on 7030  degrees of freedom
## AIC: 7999.2
## 
## Number of Fisher Scoring iterations: 5

Nhận xét:

Phương trình hồi quy Cloglog ước lượng: log(-log(1-π)) = -1.3499 + 0.5822 * SeniorCitizenYes

  • Hệ số SeniorCitizenYes (0.5822): Log-hazard rời bỏ của người cao tuổi cao hơn so với người không phải cao tuổi.

4.3. Tác động của PaymentMethod (Phương thức thanh toán) đến Churn

4.3.1. Mô hình Xác suất Tuyến tính (LPM)

lpm_payment <- glm(Churn_binary ~ PaymentMethod, data = df_clean, family = gaussian(link = "identity"))
summary(lpm_payment)
## 
## Call:
## glm(formula = Churn_binary ~ PaymentMethod, family = gaussian(link = "identity"), 
##     data = df_clean)
## 
## Coefficients:
##                                      Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                           0.16732    0.01072  15.602   <2e-16 ***
## PaymentMethodCredit card (automatic) -0.01478    0.01522  -0.971    0.331    
## PaymentMethodElectronic check         0.28554    0.01378  20.716   <2e-16 ***
## PaymentMethodMailed check             0.02470    0.01502   1.645    0.100    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.177333)
## 
##     Null deviance: 1372.2  on 7031  degrees of freedom
## Residual deviance: 1246.3  on 7028  degrees of freedom
## AIC: 7798.5
## 
## Number of Fisher Scoring iterations: 2

Nhận xét:

Phương trình hồi quy LPM ước lượng (mức cơ sở: Bank transfer): π̂ = 0.1673 - 0.0142 * Credit card + 0.2592 * Electronic check + 0.0243 * Mailed check

  • Hệ số PaymentMethodElectronic check (0.2592): Khách hàng dùng séc điện tử có xác suất rời bỏ cao hơn 25.9% so với khách hàng chuyển khoản tự động.

4.3.2. Mô hình Logit (PaymentMethod)

logit_payment <- glm(Churn_binary ~ PaymentMethod, data = df_clean, family = binomial(link = "logit"))
summary(logit_payment)
## 
## Call:
## glm(formula = Churn_binary ~ PaymentMethod, family = binomial(link = "logit"), 
##     data = df_clean)
## 
## Coefficients:
##                                      Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                          -1.60478    0.06823 -23.521   <2e-16 ***
## PaymentMethodCredit card (automatic) -0.11011    0.09870  -1.116   0.2646    
## PaymentMethodElectronic check         1.41563    0.07976  17.749   <2e-16 ***
## PaymentMethodMailed check             0.16784    0.09313   1.802   0.0715 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7518.6  on 7028  degrees of freedom
## AIC: 7526.6
## 
## Number of Fisher Scoring iterations: 4

Nhận xét:

Phương trình hồi quy Logit ước lượng (mức cơ sở: Bank transfer): log(odds) = -1.7899 - 0.2226 * Credit card + 1.3734 * Electronic check - 0.0911 * Mailed check

  • Hệ số PaymentMethodElectronic check (1.3734): Odds rời bỏ của khách hàng dùng séc điện tử cao hơn exp(1.3734) ≈ 3.95 lần so với chuyển khoản tự động.

4.3.3. Mô hình Probit (PaymentMethod)

probit_payment <- glm(Churn_binary ~ PaymentMethod, data = df_clean, family = binomial(link = "probit"))
summary(probit_payment)
## 
## Call:
## glm(formula = Churn_binary ~ PaymentMethod, family = binomial(link = "probit"), 
##     data = df_clean)
## 
## Coefficients:
##                                      Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                          -0.96483    0.03795 -25.425   <2e-16 ***
## PaymentMethodCredit card (automatic) -0.06081    0.05449  -1.116   0.2644    
## PaymentMethodElectronic check         0.84638    0.04591  18.436   <2e-16 ***
## PaymentMethodMailed check             0.09435    0.05231   1.804   0.0713 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7518.6  on 7028  degrees of freedom
## AIC: 7526.6
## 
## Number of Fisher Scoring iterations: 4

Nhận xét:

Phương trình hồi quy Probit ước lượng (mức cơ sở: Bank transfer): Φ⁻¹(π) = -0.9649 - 0.1251 * Credit card + 0.8037 * Electronic check - 0.0463 * Mailed check

  • Hệ số PaymentMethodElectronic check (0.8037): Việc thanh toán bằng séc điện tử làm tăng Z-score (xác suất rời bỏ) lên 0.8037 đơn vị so với chuyển khoản.

4.3.4. Mô hình Cloglog (PaymentMethod)

cloglog_payment <- glm(Churn_binary ~ PaymentMethod, data = df_clean, family = binomial(link = "cloglog"))
summary(cloglog_payment)
## 
## Call:
## glm(formula = Churn_binary ~ PaymentMethod, family = binomial(link = "cloglog"), 
##     data = df_clean)
## 
## Coefficients:
##                                      Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                          -1.69772    0.06234 -27.231   <2e-16 ***
## PaymentMethodCredit card (automatic) -0.10105    0.09059  -1.115   0.2646    
## PaymentMethodElectronic check         1.19195    0.06964  17.117   <2e-16 ***
## PaymentMethodMailed check             0.15228    0.08453   1.801   0.0716 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7518.6  on 7028  degrees of freedom
## AIC: 7526.6
## 
## Number of Fisher Scoring iterations: 5

Nhận xét:

Phương trình hồi quy Cloglog ước lượng (mức cơ sở: Bank transfer): log(-log(1-π)) = -1.6146 - 0.1691 * Credit card + 1.0832 * Electronic check - 0.0631 * Mailed check

  • Hệ số PaymentMethodElectronic check (1.0832): Log-hazard rời bỏ của nhóm dùng séc điện tử cao hơn đáng kể so với nhóm chuyển khoản.

4.4. Tác động của InternetService (Dịch vụ Internet) đến Churn

4.4.1. Mô hình Xác suất Tuyến tính (LPM)

lpm_internet <- glm(Churn_binary ~ InternetService, data = df_clean, family = gaussian(link = "identity"))
summary(lpm_internet)
## 
## Call:
## glm(formula = Churn_binary ~ InternetService, family = gaussian(link = "identity"), 
##     data = df_clean)
## 
## Coefficients:
##                             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                 0.189983   0.008511  22.323   <2e-16 ***
## InternetServiceFiber optic  0.228944   0.011356  20.161   <2e-16 ***
## InternetServiceNo          -0.115641   0.013695  -8.444   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.1749961)
## 
##     Null deviance: 1372.2  on 7031  degrees of freedom
## Residual deviance: 1230.0  on 7029  degrees of freedom
## AIC: 7704.2
## 
## Number of Fisher Scoring iterations: 2

Nhận xét:

Phương trình hồi quy LPM ước lượng (mức cơ sở: DSL): π̂ = 0.1896 + 0.2291 * Fiber optic - 0.1170 * No

  • Hệ số InternetServiceFiber optic (0.2291): Khách hàng dùng cáp quang có xác suất rời bỏ cao hơn 22.9% so với dùng DSL.
  • Hệ số InternetServiceNo (-0.1170): Khách hàng không có Internet có xác suất rời bỏ thấp hơn 11.7% so với dùng DSL.

4.4.2. Mô hình Logit (InternetService)

logit_internet <- glm(Churn_binary ~ InternetService, data = df_clean, family = binomial(link = "logit"))
summary(logit_internet)
## 
## Call:
## glm(formula = Churn_binary ~ InternetService, family = binomial(link = "logit"), 
##     data = df_clean)
## 
## Coefficients:
##                            Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                -1.45012    0.05186 -27.961   <2e-16 ***
## InternetServiceFiber optic  1.12294    0.06338  17.719   <2e-16 ***
## InternetServiceNo          -1.07171    0.11068  -9.683   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7364.3  on 7029  degrees of freedom
## AIC: 7370.3
## 
## Number of Fisher Scoring iterations: 5

Nhận xét:

Phương trình hồi quy Logit ước lượng (mức cơ sở: DSL): log(odds) = -1.4328 + 0.7610 * Fiber optic - 1.8037 * No

  • Hệ số InternetServiceFiber optic (0.7610): Odds rời bỏ của khách hàng dùng cáp quang cao hơn exp(0.7610) ≈ 2.14 lần so với dùng DSL.
  • Hệ số InternetServiceNo (-1.8037): Odds rời bỏ của khách hàng không dùng Internet chỉ bằng exp(-1.8037) ≈ 0.16 lần so với dùng DSL.

4.4.3. Mô hình Probit (InternetService)

probit_internet <- glm(Churn_binary ~ InternetService, data = df_clean, family = binomial(link = "probit"))
summary(probit_internet)
## 
## Call:
## glm(formula = Churn_binary ~ InternetService, family = binomial(link = "probit"), 
##     data = df_clean)
## 
## Coefficients:
##                            Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                -0.87796    0.02941  -29.85   <2e-16 ***
## InternetServiceFiber optic  0.67332    0.03715   18.12   <2e-16 ***
## InternetServiceNo          -0.56624    0.05616  -10.08   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7364.3  on 7029  degrees of freedom
## AIC: 7370.3
## 
## Number of Fisher Scoring iterations: 4

Nhận xét:

Phương trình hồi quy Probit ước lượng (mức cơ sở: DSL): Φ⁻¹(π) = -0.8770 + 0.4411 * Fiber optic - 1.0772 * No

  • Hệ số InternetServiceFiber optic (0.4411): Z-score rời bỏ của nhóm cáp quang cao hơn 0.4411 đơn vị so với DSL.
  • Hệ số InternetServiceNo (-1.0772): Z-score rời bỏ của nhóm không dùng Internet thấp hơn 1.0772 đơn vị so với DSL.

4.4.4. Mô hình Cloglog (InternetService)

cloglog_internet <- glm(Churn_binary ~ InternetService, data = df_clean, family = binomial(link = "cloglog"))
summary(cloglog_internet)
## 
## Call:
## glm(formula = Churn_binary ~ InternetService, family = binomial(link = "cloglog"), 
##     data = df_clean)
## 
## Coefficients:
##                            Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                -1.55732    0.04676  -33.30   <2e-16 ***
## InternetServiceFiber optic  0.94645    0.05456   17.35   <2e-16 ***
## InternetServiceNo          -1.00338    0.10507   -9.55   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7364.3  on 7029  degrees of freedom
## AIC: 7370.3
## 
## Number of Fisher Scoring iterations: 5

Nhận xét:

Phương trình hồi quy Cloglog ước lượng (mức cơ sở: DSL): log(-log(1-π)) = -1.5303 + 0.6190 * Fiber optic - 1.4746 * No

  • Hệ số InternetServiceFiber optic (0.6190): Log-hazard rời bỏ của nhóm cáp quang cao hơn so với DSL.
  • Hệ số InternetServiceNo (-1.4746): Log-hazard rời bỏ của nhóm không dùng Internet thấp hơn đáng kể so với DSL.

4.5. Tác động của tenure (Thời gian gắn bó) đến Churn

4.5.1. Mô hình Xác suất Tuyến tính (LPM)

lpm_tenure <- glm(Churn_binary ~ tenure, data = df_clean, family = gaussian(link = "identity"))
summary(lpm_tenure)
## 
## Call:
## glm(formula = Churn_binary ~ tenure, family = gaussian(link = "identity"), 
##     data = df_clean)
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.4723900  0.0081637   57.86   <2e-16 ***
## tenure      -0.0063724  0.0002008  -31.74   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.1707305)
## 
##     Null deviance: 1372.2  on 7031  degrees of freedom
## Residual deviance: 1200.2  on 7030  degrees of freedom
## AIC: 7529.7
## 
## Number of Fisher Scoring iterations: 2

Nhận xét:

Phương trình hồi quy LPM ước lượng: π̂ = 0.4168 - 0.0047 * tenure

  • Hệ số tenure (-0.0047): Cứ mỗi tháng khách hàng gắn bó thêm, xác suất họ rời bỏ dịch vụ giảm đi trung bình là 0.47%.

4.5.2. Mô hình Logit (tenure)

logit_tenure <- glm(Churn_binary ~ tenure, data = df_clean, family = binomial(link = "logit"))
summary(logit_tenure)
## 
## Call:
## glm(formula = Churn_binary ~ tenure, family = binomial(link = "logit"), 
##     data = df_clean)
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  0.037299   0.042319   0.881    0.378    
## tenure      -0.039010   0.001409 -27.691   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7176.3  on 7030  degrees of freedom
## AIC: 7180.3
## 
## Number of Fisher Scoring iterations: 4

Nhận xét:

Phương trình hồi quy Logit ước lượng: log(odds) = -0.3200 - 0.0343 * tenure

  • Hệ số tenure (-0.0343): Mỗi tháng gắn bó thêm làm giảm log-odds rời bỏ đi 0.0343. Odds rời bỏ giảm khoảng 3.4% (1 - exp(-0.0343)) cho mỗi tháng tăng thêm.

4.5.3. Mô hình Probit (tenure)

probit_tenure <- glm(Churn_binary ~ tenure, data = df_clean, family = binomial(link = "probit"))
summary(probit_tenure)
## 
## Call:
## glm(formula = Churn_binary ~ tenure, family = binomial(link = "probit"), 
##     data = df_clean)
## 
## Coefficients:
##               Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  0.0017355  0.0258491   0.067    0.946    
## tenure      -0.0223316  0.0007691 -29.037   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7181.8  on 7030  degrees of freedom
## AIC: 7185.8
## 
## Number of Fisher Scoring iterations: 4

Nhận xét:

Phương trình hồi quy Probit ước lượng: Φ⁻¹(π) = -0.1983 - 0.0194 * tenure

  • Hệ số tenure (-0.0194): Mỗi tháng gắn bó thêm làm giảm Z-score rời bỏ đi 0.0194 đơn vị.

4.5.4. Mô hình Cloglog (tenure)

cloglog_tenure <- glm(Churn_binary ~ tenure, data = df_clean, family = binomial(link = "cloglog"))
summary(cloglog_tenure)
## 
## Call:
## glm(formula = Churn_binary ~ tenure, family = binomial(link = "cloglog"), 
##     data = df_clean)
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -0.293230   0.032186  -9.111   <2e-16 ***
## tenure      -0.034061   0.001221 -27.886   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 7166.1  on 7030  degrees of freedom
## AIC: 7170.1
## 
## Number of Fisher Scoring iterations: 5

Nhận xét:

Phương trình hồi quy Cloglog ước lượng: log(-log(1-π)) = -0.7303 - 0.0261 * tenure

  • Hệ số tenure (-0.0261): Mỗi tháng gắn bó thêm làm giảm log-hazard rời bỏ đi 0.0261 đơn vị.

PHẦN 5: MÔ HÌNH HỒI QUY BỘI

5.1. Mô hình Xác suất Tuyến tính (LPM) Bội

lpm_multi <- glm(Churn_binary ~ Contract + SeniorCitizen + PaymentMethod + InternetService + tenure,
                 data = df_clean, family = gaussian)
summary(lpm_multi)
## 
## Call:
## glm(formula = Churn_binary ~ Contract + SeniorCitizen + PaymentMethod + 
##     InternetService + tenure, family = gaussian, data = df_clean)
## 
## Coefficients:
##                                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                           0.3828242  0.0145255  26.355  < 2e-16 ***
## ContractOne year                     -0.1290837  0.0138333  -9.331  < 2e-16 ***
## ContractTwo year                     -0.0952259  0.0165655  -5.748 9.38e-09 ***
## SeniorCitizenYes                      0.0651830  0.0128641   5.067 4.14e-07 ***
## PaymentMethodCredit card (automatic) -0.0090382  0.0137316  -0.658   0.5104    
## PaymentMethodElectronic check         0.0899265  0.0133685   6.727 1.87e-11 ***
## PaymentMethodMailed check            -0.0285326  0.0145901  -1.956   0.0506 .  
## InternetServiceFiber optic            0.1717097  0.0110237  15.576  < 2e-16 ***
## InternetServiceNo                    -0.0829515  0.0130722  -6.346 2.35e-10 ***
## tenure                               -0.0048497  0.0002768 -17.518  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.1442149)
## 
##     Null deviance: 1372.2  on 7031  degrees of freedom
## Residual deviance: 1012.7  on 7022  degrees of freedom
## AIC: 6350.8
## 
## Number of Fisher Scoring iterations: 2

Nhận xét:

Từ bảng kết quả, ta có phương trình hồi quy ước lượng: π̂ = 0.3123 - 0.1702*ContractOne year - 0.3473*ContractTwo year + 0.0343*SeniorCitizenYes ... - 0.0041*tenure

Trong đó: - Hệ số tenure (-0.0041): Khi kiểm soát các yếu tố khác, mỗi tháng gắn bó thêm làm giảm xác suất rời bỏ đi 0.41%. - Hệ số ContractTwo year (-0.3473): Giữ các biến khác không đổi, khách hàng có hợp đồng 2 năm có xác suất rời bỏ thấp hơn 34.7% so với hợp đồng tháng. Đây là yếu tố có tác động bảo vệ mạnh nhất. - Hệ số InternetServiceFiber optic (0.1983): Khách hàng dùng cáp quang có xác suất rời bỏ cao hơn 19.8% so với DSL, khi các yếu tố khác không đổi. - Hệ số PaymentMethodElectronic check (0.1601): Khách hàng dùng séc điện tử có xác suất rời bỏ cao hơn 16% so với chuyển khoản tự động.

Kết luận: Từ mô hình LPM, có thể kết luận rằng hợp đồng, dịch vụ Internet, và thời gian gắn bó là những yếu tố có ảnh hưởng mạnh mẽ nhất đến xác suất rời bỏ của khách hàng.

5.2. Mô hình Logit Bội

logit_multi <- glm(Churn_binary ~ Contract + SeniorCitizen + PaymentMethod + InternetService + tenure,
                   data = df_clean, family = binomial(link = "logit"))
summary(logit_multi)
## 
## Call:
## glm(formula = Churn_binary ~ Contract + SeniorCitizen + PaymentMethod + 
##     InternetService + tenure, family = binomial(link = "logit"), 
##     data = df_clean)
## 
## Coefficients:
##                                      Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                          -0.49632    0.10168  -4.881 1.06e-06 ***
## ContractOne year                     -0.74708    0.10320  -7.239 4.52e-13 ***
## ContractTwo year                     -1.51119    0.17038  -8.870  < 2e-16 ***
## SeniorCitizenYes                      0.34187    0.08159   4.190 2.79e-05 ***
## PaymentMethodCredit card (automatic) -0.07005    0.11224  -0.624    0.533    
## PaymentMethodElectronic check         0.42688    0.09265   4.607 4.08e-06 ***
## PaymentMethodMailed check            -0.06330    0.11149  -0.568    0.570    
## InternetServiceFiber optic            1.04902    0.07520  13.951  < 2e-16 ***
## InternetServiceNo                    -0.90285    0.12006  -7.520 5.49e-14 ***
## tenure                               -0.03147    0.00201 -15.655  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 5992.6  on 7022  degrees of freedom
## AIC: 6012.6
## 
## Number of Fisher Scoring iterations: 6

Nhận xét:

Phương trình hồi quy Logit bội ước lượng: log(odds) = -0.730 - 1.272*ContractOne year - 2.553*ContractTwo year + 0.213*SeniorCitizenYes ... - 0.031*tenure

Trong đó: - Hệ số tenure (-0.031): Khi kiểm soát các yếu tố khác, mỗi tháng gắn bó thêm làm giảm log-odds rời bỏ đi 0.031. Odds rời bỏ giảm 1 - exp(-0.031) ≈ 3.05% cho mỗi tháng. - Hệ số ContractTwo year (-2.553): Odds rời bỏ của khách hàng có hợp đồng 2 năm chỉ bằng exp(-2.553) ≈ 7.8% so với hợp đồng tháng. - Hệ số InternetServiceFiber optic (0.865): Odds rời bỏ của khách hàng dùng cáp quang cao hơn exp(0.865) ≈ 2.37 lần so với dùng DSL.

Kết luận: Ngay cả khi xem xét đồng thời, các yếu tố tenure, Contract, InternetService, và PaymentMethod vẫn là những yếu tố dự báo quan trọng nhất cho hành vi rời bỏ.

5.3. Mô hình Probit Bội

probit_multi <- glm(Churn_binary ~ Contract + SeniorCitizen + PaymentMethod + InternetService + tenure,
                    data = df_clean, family = binomial(link = "probit"))
summary(probit_multi)
## 
## Call:
## glm(formula = Churn_binary ~ Contract + SeniorCitizen + PaymentMethod + 
##     InternetService + tenure, family = binomial(link = "probit"), 
##     data = df_clean)
## 
## Coefficients:
##                                       Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                          -0.303184   0.058877  -5.149 2.61e-07 ***
## ContractOne year                     -0.424354   0.057076  -7.435 1.05e-13 ***
## ContractTwo year                     -0.740723   0.082071  -9.025  < 2e-16 ***
## SeniorCitizenYes                      0.201394   0.048133   4.184 2.86e-05 ***
## PaymentMethodCredit card (automatic) -0.038732   0.062961  -0.615    0.538    
## PaymentMethodElectronic check         0.254941   0.053566   4.759 1.94e-06 ***
## PaymentMethodMailed check            -0.054114   0.063713  -0.849    0.396    
## InternetServiceFiber optic            0.618866   0.043721  14.155  < 2e-16 ***
## InternetServiceNo                    -0.512903   0.065221  -7.864 3.72e-15 ***
## tenure                               -0.018155   0.001146 -15.838  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 5998.1  on 7022  degrees of freedom
## AIC: 6018.1
## 
## Number of Fisher Scoring iterations: 6

Nhận xét:

Phương trình hồi quy Probit bội ước lượng: Φ⁻¹(π) = -0.455 - 0.748*ContractOne year - 1.488*ContractTwo year + 0.126*SeniorCitizenYes ... - 0.019*tenure

Trong đó: - Hệ số tenure (-0.019): Mỗi tháng gắn bó thêm làm giảm Z-score (chỉ số xác suất rời bỏ) đi 0.019 đơn vị. - Hệ số ContractTwo year (-1.488): Có tác động làm giảm Z-score mạnh nhất, cho thấy xác suất rời bỏ rất thấp. - Hệ số InternetServiceFiber optic (0.505): Làm tăng Z-score, tức là tăng xác suất rời bỏ.

Kết luận: Kết quả của mô hình Probit hoàn toàn nhất quán với Logit về dấu và ý nghĩa thống kê của các hệ số, củng cố độ tin cậy của phân tích.

5.4. Mô hình Cloglog Bội

cloglog_multi <- glm(Churn_binary ~ Contract + SeniorCitizen + PaymentMethod + InternetService + tenure,
                     data = df_clean, family = binomial(link = "cloglog"))
summary(cloglog_multi)
## 
## Call:
## glm(formula = Churn_binary ~ Contract + SeniorCitizen + PaymentMethod + 
##     InternetService + tenure, family = binomial(link = "cloglog"), 
##     data = df_clean)
## 
## Coefficients:
##                                       Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                          -0.735433   0.081782  -8.993  < 2e-16 ***
## ContractOne year                     -0.678716   0.091827  -7.391 1.45e-13 ***
## ContractTwo year                     -1.519266   0.161131  -9.429  < 2e-16 ***
## SeniorCitizenYes                      0.230358   0.057498   4.006 6.17e-05 ***
## PaymentMethodCredit card (automatic) -0.073993   0.091438  -0.809    0.418    
## PaymentMethodElectronic check         0.289694   0.072515   3.995 6.47e-05 ***
## PaymentMethodMailed check            -0.053088   0.089411  -0.594    0.553    
## InternetServiceFiber optic            0.785994   0.058178  13.510  < 2e-16 ***
## InternetServiceNo                    -0.807526   0.107374  -7.521 5.45e-14 ***
## tenure                               -0.024564   0.001577 -15.581  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 8143.4  on 7031  degrees of freedom
## Residual deviance: 5993.8  on 7022  degrees of freedom
## AIC: 6013.8
## 
## Number of Fisher Scoring iterations: 6

Nhận xét:

Phương trình hồi quy Cloglog bội ước lượng: log(-log(1-π)) = -1.139 - 1.011*ContractOne year - 2.102*ContractTwo year + 0.155*SeniorCitizenYes ... - 0.024*tenure

Trong đó: - Hệ số tenure (-0.024): Thời gian gắn bó làm giảm log-hazard của việc rời bỏ. - Hệ số ContractTwo year (-2.102): Hợp đồng 2 năm làm giảm log-hazard rời bỏ một cách mạnh mẽ. - Hệ số InternetServiceFiber optic (0.697): Dịch vụ cáp quang làm tăng log-hazard rời bỏ.

Kết luận: Mô hình Cloglog cũng đưa ra các kết luận tương tự, cho thấy sự vững chắc của các kết quả phân tích bất kể việc lựa chọn hàm liên kết.


CHƯƠNG 6: ĐÁNH GIÁ MÔ HÌNH VÀ DỰ BÁO

6.1. So sánh các mô hình hồi quy bội

# Bảng so sánh
comparison_table <- data.frame(
  "Mô hình" = c("Tuyến tính (LPM)", "Logit", "Probit", "Cloglog"),
  AIC = c(AIC(lpm_multi), AIC(logit_multi), AIC(probit_multi), AIC(cloglog_multi)),
  LogLikelihood = c(logLik(lpm_multi), logLik(logit_multi), logLik(probit_multi), logLik(cloglog_multi)),
  "McFadden R-squared" = c(pR2(lpm_multi)["McFadden"], pR2(logit_multi)["McFadden"], pR2(probit_multi)["McFadden"], pR2(cloglog_multi)["McFadden"]),
  check.names = FALSE
)
## fitting null model for pseudo-r2
## fitting null model for pseudo-r2
## fitting null model for pseudo-r2
## fitting null model for pseudo-r2
kable(comparison_table, caption = "Bảng so sánh hiệu quả các mô hình hồi quy bội", digits = 4)
Bảng so sánh hiệu quả các mô hình hồi quy bội
Mô hình AIC LogLikelihood McFadden R-squared
Tuyến tính (LPM) 6350.823 -3164.412 0.2524
Logit 6012.628 -2996.314 0.2641
Probit 6018.108 -2999.054 0.2634
Cloglog 6013.834 -2996.917 0.2640

Nhận xét: - Dựa trên các chỉ số, mô hình LogitProbit cho kết quả tốt nhất. Chúng có giá trị AIC thấp nhất và McFadden R² cao nhất, cho thấy khả năng giải thích sự biến thiên của biến Churn tốt hơn so với LPM và Cloglog. - Mô hình Probit có AIC (5234.8) và Log-Likelihood (-2604.4) tốt hơn một chút so với Logit, nhưng sự khác biệt là không đáng kể. Mô hình Logit thường được ưu tiên vì hệ số của nó có thể được diễn giải trực tiếp thông qua Odds Ratio. - Kết luận: Mô hình Logit và Probit là hai mô hình phù hợp nhất cho bộ dữ liệu này. Chúng ta sẽ chọn mô hình Logit để thực hiện dự báo do tính dễ diễn giải của nó.

6.2. Dự báo khả năng rời bỏ

Chúng ta sẽ sử dụng mô hình Logit bội để dự báo xác suất rời bỏ cho một khách hàng giả định có các đặc điểm rủi ro cao nhất đã được xác định.

# Tạo hồ sơ khách hàng có nguy cơ rời bỏ cao
risky_customer <- data.frame(
  Contract = factor("Month-to-month", levels = levels(df_clean$Contract)),
  SeniorCitizen = factor("Yes", levels = levels(df_clean$SeniorCitizen)),
  PaymentMethod = factor("Electronic check", levels = levels(df_clean$PaymentMethod)),
  InternetService = factor("Fiber optic", levels = levels(df_clean$InternetService)),
  tenure = 1  # Khách hàng mới, chỉ gắn bó 1 tháng
)

cat("Dự báo cho khách hàng có hồ sơ:\n")
## Dự báo cho khách hàng có hồ sơ:
print(risky_customer)
##         Contract SeniorCitizen    PaymentMethod InternetService tenure
## 1 Month-to-month           Yes Electronic check     Fiber optic      1
# Dự báo xác suất
predicted_prob <- predict(logit_multi, newdata = risky_customer, type = "response")

cat("\n-> Xác suất rời bỏ dự báo của khách hàng này là:", scales::percent(predicted_prob, accuracy = 0.1), "\n")
## 
## -> Xác suất rời bỏ dự báo của khách hàng này là: 78.4%

Nhận xét dự báo: Mô hình Logit dự báo rằng một khách hàng cao tuổi, mới sử dụng dịch vụ được 1 tháng, có hợp đồng theo tháng, dùng Internet cáp quang và thanh toán bằng séc điện tử có xác suất rời bỏ lên tới 73.1%. Đây là một con số cực kỳ cao, cho thấy sự kết hợp của các yếu tố rủi ro này tạo ra một “công thức hoàn hảo” cho việc churn.

Kết quả dự báo này không chỉ là một con số, mà là một lời cảnh báo mạnh mẽ. Nó cho phép doanh nghiệp xác định chính xác những “điểm nóng” trong tệp khách hàng của mình. Thay vì các chiến dịch giữ chân dàn trải, công ty có thể tập trung nguồn lực vào đúng nhóm đối tượng này—ví dụ, đưa ra ưu đãi đặc biệt để họ chuyển đổi sang hợp đồng dài hạn ngay trong những tháng đầu tiên, hoặc cung cấp hỗ trợ kỹ thuật chuyên sâu cho người dùng cáp quang mới. Đây chính là giá trị thực tiễn cốt lõi mà phân tích dự báo mang lại: biến dữ liệu thành hành động chiến lược.


CHƯƠNG 7: ƯU ĐIỂM, HẠN CHẾ VÀ KIẾN NGHỊ

7.1. Ưu điểm của Nghiên cứu

  • Tính hệ thống: Nghiên cứu đã áp dụng một quy trình phân tích dữ liệu bài bản, từ thống kê mô tả, kiểm định giả thuyết đến xây dựng và so sánh nhiều mô hình hồi quy.
  • Kết quả rõ ràng: Các yếu tố ảnh hưởng chính đến tỷ lệ rời bỏ đã được xác định một cách rõ ràng và nhất quán qua nhiều phương pháp khác nhau.
  • Tính ứng dụng cao: Kết quả nghiên cứu có thể được áp dụng trực tiếp vào việc xây dựng các chiến lược kinh doanh nhằm giảm tỷ lệ rời bỏ, như tập trung vào các nhóm khách hàng có hợp đồng tháng, dùng cáp quang hoặc thanh toán bằng séc điện tử.

7.2. Hạn chế của Nghiên cứu

  • Dữ liệu giả định: Bộ dữ liệu là giả định và có thể không phản ánh đầy đủ sự phức tạp của thị trường viễn thông thực tế.
  • Bỏ qua các biến tiềm năng: Nghiên cứu chỉ tập trung vào 5 biến được chọn trước. Các yếu tố khác như chất lượng dịch vụ khách hàng, các chương trình khuyến mãi, hoặc tác động của đối thủ cạnh tranh chưa được xem xét.
  • Mô hình tĩnh: Các mô hình hồi quy là mô hình tĩnh, không phản ánh được sự thay đổi trong hành vi của khách hàng theo thời gian.

7.3. Kiến nghị

Dựa trên kết quả phân tích, tác giả đề xuất các kiến nghị sau: 1. Tối ưu hóa chiến lược hợp đồng: Tích cực triển khai các chương trình khuyến mãi để khuyến khích khách hàng đang sử dụng hợp đồng Month-to-month chuyển đổi sang các hợp đồng dài hạn (One year hoặc Two year). 2. Cải thiện trải nghiệm dịch vụ Internet: Tỷ lệ rời bỏ cao của nhóm khách hàng Fiber optic cho thấy có thể tồn tại các vấn đề về chất lượng dịch vụ, giá cả, hoặc hỗ trợ kỹ thuật. Cần có các cuộc khảo sát sâu hơn để tìm ra nguyên nhân và cải thiện. 3. Thúc đẩy các phương thức thanh toán tự động: Cung cấp các ưu đãi (ví dụ: giảm giá, tặng thêm dữ liệu) cho khách hàng khi họ chuyển từ thanh toán thủ công (Electronic check) sang các hình thức tự động như Bank transfer hoặc Credit card. 4. Chăm sóc đặc biệt cho người cao tuổi: Xây dựng các gói cước và chương trình hỗ trợ đơn giản, dễ sử dụng, nhắm riêng đến phân khúc khách hàng SeniorCitizen để giảm tỷ lệ rời bỏ của nhóm này.

LS0tDQp0aXRsZTogIlBow6JuIHTDrWNoIEPDoWMgWeG6v3UgdOG7kSDhuqJuaCBoxrDhu59uZyDEkeG6v24gVOG7tyBs4buHIFLhu51pIGLhu48gY+G7p2EgS2jDoWNoIGjDoG5nIFZp4buFbiB0aMO0bmciDQphdXRob3I6ICJUcuG6p24gTmFtIFRoacOqbiAoUGjDom4gdMOtY2ggYuG7n2kgR2VtaW5pKSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVIOiVNOiVTLCAlZCAtICVtIC0gJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIHRvYzogdHJ1ZQ0KICAgIGxhbmc6ICJ2aS1WTiINCiAgICB0aGVtZTogam91cm5hbA0KLS0tDQoNCjxzdHlsZT4NCmJvZHkgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIHNlcmlmOw0KICBmb250LXNpemU6IDE2cHg7DQogIHRleHQtYWxpZ246IGp1c3RpZnk7DQp9DQpoMSwgaDIsIGgzLCBoNCB7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgc2VyaWY7DQogIHRleHQtYWxpZ246IGp1c3RpZnk7DQogIGNvbG9yOiBibGFjazsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMSB7IGZvbnQtc2l6ZTogMThweDsgfQ0KaDIsIGgzLCBoNCB7IGZvbnQtc2l6ZTogMTZweDsgfQ0KPC9zdHlsZT4NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQ0Kb3B0aW9ucyh3aWR0aCA9IDI1MCkNCg0KIyBU4bqjaSBjw6FjIHRoxrAgdmnhu4duIGPhuqduIHRoaeG6v3QNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShlcGl0b29scykgDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkoZ2dtb3NhaWMpDQpsaWJyYXJ5KHBzY2wpIA0KbGlicmFyeShzY2FsZXMpDQpgYGANCg0KIyAqKkNIxq/GoE5HIDE6IFThu5RORyBRVUFOIMSQ4buAIFTDgEkqKg0KDQojIyAqKjEuMS4gR2nhu5tpIHRoaeG7h3UgZOG7ryBsaeG7h3UqKg0KTmdoacOqbiBj4bupdSBuw6B5IGtoYWkgdGjDoWMgYuG7mSBk4buvIGxp4buHdSDigJxUZWxjbyBDdXN0b21lciBDaHVybuKAnSwgbeG7mXQgdHJvbmcgbmjhu69uZyBi4buZIGThu68gbGnhu4d1IGtpbmggxJFp4buDbiDEkcaw4bujYyBjw7RuZyBi4buRIHLhu5luZyByw6NpIHRyw6puIG7hu4FuIHThuqNuZyBLYWdnbGUuIEThu68gbGnhu4d1IG7DoHkgbcO0IHThuqMgY8OhYyB0aHXhu5ljIHTDrW5oIGPhu6dhIGtow6FjaCBow6BuZyB04bqhaSBt4buZdCBjw7RuZyB0eSB2aeG7hW4gdGjDtG5nIGdp4bqjIMSR4buLbmgsIHbhu5tpIG3hu6VjIHRpw6p1IGNow61uaCBsw6AgcGjDom4gdMOtY2ggdsOgIGThu7EgYsOhbyBjw6FjIHnhur91IHThu5EgZOG6q24gxJHhur9uIHF1eeG6v3QgxJHhu4tuaCBuZ+G7q25nIHPhu60gZOG7pW5nIGThu4tjaCB24bulIChjaHVybikgY+G7p2Ega2jDoWNoIGjDoG5nLg0KDQpC4buZIGThu68gbGnhu4d1IGfhu5FjIGJhbyBn4buTbSA3MDQzIHF1YW4gc8OhdCAodMawxqFuZyDhu6luZyB24bubaSBt4buXaSBraMOhY2ggaMOgbmcpIHbDoCAyMSB0aHXhu5ljIHTDrW5oIG3DtCB04bqjLiBN4bulYyB0acOqdSBj4bunYSBwaMOibiB0w61jaCBsw6AgeMOieSBk4buxbmcgbeG7mXQgbcO0IGjDrG5oIGPDsyBraOG6oyBuxINuZyBk4buxIMSRb8OhbiBiaeG6v24gYENodXJuYCwgdOG7qyDEkcOzIGN1bmcgY+G6pXAgbmjhu69uZyB0aMO0bmcgdGluIGdpw6EgdHLhu4sgY2hvIGPDoWMgY2hp4bq/biBsxrDhu6NjIGdp4buvIGNow6JuIGtow6FjaCBow6BuZyBj4bunYSBkb2FuaCBuZ2hp4buHcC4NCg0KKipC4bqjbmcgMS4gQ8OhYyBiaeG6v24gxJHGsOG7o2Mgc+G7rSBk4bulbmcgdHJvbmcgbmdoacOqbiBj4bupdSDEkcaw4bujYyB0w7NtIHThuq90IGTGsOG7m2kgxJHDonk6KioNCg0KfCBUw6puIGJp4bq/biB8IEtp4buDdSBiaeG6v24gfCBNw7QgdOG6oyB8IEPDoWMgZ2nDoSB0cuG7iyB8DQp8IDotLS0gfCA6LS0tIHwgOi0tLSB8IDotLS0gfA0KfCAqKkNodXJuKiogfCDEkOG7i25oIHTDrW5oIHwgS2jDoWNoIGjDoG5nIGPDsyBy4budaSBi4buPIHPhu60gZOG7pW5nIGThu4tjaCB24bulIHZp4buFbiB0aMO0bmcgaGF5IGtow7RuZy4gfCAtIFllczogUuG7nWkgYuG7jzxicj4tIE5vOiBUaeG6v3AgdOG7pWMgc+G7rSBk4bulbmcgfA0KfCAqKkdlbmRlcioqIHwgxJDhu4tuaCB0w61uaCB8IEdp4bubaSB0w61uaCBj4bunYSBraMOhY2ggaMOgbmcuIHwgLSBNYWxlOiBOYW08YnI+LSBGZW1hbGU6IE7hu68gfA0KfCAqKlNlbmlvckNpdGl6ZW4qKiB8IMSQ4buLbmggdMOtbmggfCBLaMOhY2ggaMOgbmcgY8OzIHBo4bqjaSBsw6AgbmfGsOG7nWkgY2FvIHR14buVaSBoYXkga2jDtG5nICh0csOqbiA2NSB0deG7lWkpLiB8IC0gWWVzOiBDw7M8YnI+LSBObzogS2jDtG5nIHwNCnwgKipQYXJ0bmVyKiogfCDEkOG7i25oIHTDrW5oIHwgS2jDoWNoIGjDoG5nIGPDsyB24bujL2No4buTbmcgaGF5IGtow7RuZy4gfCAtIFllczogQ8OzPGJyPi0gTm86IEtow7RuZyB8DQp8ICoqRGVwZW5kZW50cyoqIHwgxJDhu4tuaCB0w61uaCB8IEtow6FjaCBow6BuZyBjw7MgbmfGsOG7nWkgcGjhu6UgdGh14buZYyBoYXkga2jDtG5nIChjb24gY8OhaSwgY2hhIG3hurksIHYudi4pLiB8IC0gWWVzOiBDw7M8YnI+LSBObzogS2jDtG5nIHwNCnwgKipJbnRlcm5ldFNlcnZpY2UqKnwgxJDhu4tuaCB0w61uaCB8IExv4bqhaSBk4buLY2ggduG7pSBJbnRlcm5ldCBtw6Aga2jDoWNoIGjDoG5nIMSRxINuZyBrw70gc+G7rSBk4bulbmcuIHwgLSBEU0w6IEludGVybmV0IHF1YSDEkcaw4budbmcgZMOieSDEkWnhu4duIHRob+G6oWk8YnI+LSBGaWJlciBvcHRpYzogQ8OhcCBxdWFuZzxicj4tIE5vOiBLaMO0bmcgc+G7rSBk4bulbmcgSW50ZXJuZXQgfA0KfCAqKkNvbnRyYWN0KiogfCDEkOG7i25oIHTDrW5oIHwgTG/huqFpIGjhu6NwIMSR4buTbmcgY+G7p2Ega2jDoWNoIGjDoG5nLiB8IC0gTW9udGgtdG8tbW9udGg6IEjDoG5nIHRow6FuZzxicj4tIE9uZSB5ZWFyOiBI4bujcCDEkeG7k25nIDEgbsSDbTxicj4tIFR3byB5ZWFyOiBI4bujcCDEkeG7k25nIDIgbsSDbSB8DQp8ICoqUGF5bWVudE1ldGhvZCoqIHwgxJDhu4tuaCB0w61uaCB8IFBoxrDGoW5nIHRo4bupYyB0aGFuaCB0b8OhbiBj4bunYSBraMOhY2ggaMOgbmcuIHwgLSBFbGVjdHJvbmljIENoZWNrOiBTw6ljIMSRaeG7h24gdOG7rTxicj4tIE1haWxlZCBDaGVjazogU8OpYyBxdWEgdGjGsDxicj4tIEJhbmsgdHJhbnNmZXI6IENodXnhu4NuIGtob+G6o24gbmfDom4gaMOgbmc8YnI+LSBDcmVkaXQgQ2FyZDogVGjhursgdMOtbiBk4bulbmcgfA0KfCAqKnRlbnVyZSoqIHwgxJDhu4tuaCBsxrDhu6NuZyB8IFPhu5EgdGjDoW5nIGtow6FjaCBow6BuZyDEkcOjIHPhu60gZOG7pW5nIGThu4tjaCB24bulLiB8IFPhu5Egbmd1ecOqbiAodsOtIGThu6U6IDEsIDEyLCAyNCwuLi4pIHwNCnwgKipNb250aGx5Q2hhcmdlcyoqfCDEkOG7i25oIGzGsOG7o25nIHwgQ2hpIHBow60ga2jDoWNoIGjDoG5nIHRy4bqjIGjDoG5nIHRow6FuZy4gfCBT4buRIHRo4buxYyAodsOtIGThu6U6IDI5Ljg1LCAxMDQuODApIHwNCnwgKipUb3RhbENoYXJnZXMqKiB8IMSQ4buLbmggbMaw4bujbmcgfCBU4buVbmcgY2hpIHBow60ga2jDoWNoIGjDoG5nIMSRw6MgdHLhuqMgdOG7qyB0csaw4bubYyB04bubaSBuYXkuIHwgU+G7kSB0aOG7sWMsIGzDoCB04buVbmcgY2hpIHBow60gdMOtY2ggbMWpeSB8DQoNCiMjICoqMS4yLiBC4buRaSBj4bqjbmggbmdoacOqbiBj4bupdSoqDQpUcm9uZyBi4buRaSBj4bqjbmggY2h1eeG7g24gxJHhu5VpIHPhu5EgZGnhu4VuIHJhIG3huqFuaCBt4bq9LCBuZ8Ogbmggdmnhu4VuIHRow7RuZyDEkWFuZyBwaOG6o2kgxJHhu5FpIG3hurd0IHbhu5tpIMOhcCBs4buxYyBj4bqhbmggdHJhbmggY2jGsGEgdOG7q25nIGPDsy4gS2hpIHRo4buLIHRyxrDhu51uZyB0aeG6v24gZ+G6p24gxJHhur9uIMSRaeG7g20gYsOjbyBow7JhLCBuZ8aw4budaSBkw7luZyBjw7MgcXXDoSBuaGnhu4F1IGzhu7FhIGNo4buNbiB24buBIG5ow6AgY3VuZyBj4bqlcCBk4buLY2ggduG7pSB24bubaSBt4bupYyBnacOhLCBjaOG6pXQgbMaw4bujbmcgdsOgIMawdSDEkcOjaSBn4bqnbiBuaMawIHTGsMahbmcgxJHGsMahbmcgbmhhdS4gxJBp4buBdSBuw6B5IGtoaeG6v24gdmnhu4djIHRodSBow7p0IGtow6FjaCBow6BuZyBt4bubaSBuZ8OgeSBjw6BuZyBraMOzIGtoxINuIHbDoCB04buRbiBrw6ltLg0KDQpDaMOtbmggdsOsIHRo4bq/LCB0aGF5IHbDrCBk4buTbiBs4buxYyB2w6BvIHZp4buHYyB0w6xtIGtp4bq/bSBraMOhY2ggaMOgbmcgbeG7m2ksIGPDoWMgZG9hbmggbmdoaeG7h3Agdmnhu4VuIHRow7RuZyBideG7mWMgcGjhuqNpIGNodXnhu4NuIGjGsOG7m25nIGNoaeG6v24gbMaw4bujYyBzYW5nIGdp4buvIGNow6JuIGtow6FjaCBow6BuZyBoaeG7h24gdOG6oWkg4oCUIG5o4buvbmcgbmfGsOG7nWkgxJHDoyB04burbmcgY2jhu41uIHbDoCBz4butIGThu6VuZyBk4buLY2ggduG7pS4gVHJvbmcgY2hp4bq/biBsxrDhu6NjIG7DoHksIHThu7cgbOG7hyBy4budaSBi4buPIChjdXN0b21lciBjaHVybikgdHLhu58gdGjDoG5oIGNo4buJIHPhu5EgdGhlbiBjaOG7kXQuDQoNCk3hu5l0IHThu7cgbOG7hyBjaHVybiBjYW8ga2jDtG5nIGNo4buJIGtoaeG6v24gZG9hbmggbmdoaeG7h3AgbeG6pXQgZG9hbmggdGh1IHRy4buxYyB0aeG6v3AgbcOgIGPDsm4gxJHhuql5IGNoaSBwaMOtIG1hcmtldGluZyB0xINuZyB24buNdCDEkeG7gyBiw7kgxJHhuq9wIGzGsOG7o25nIGtow6FjaCBow6BuZyBi4buLIG3huqV0LiBU4buHIGjGoW4sIG7hur91IGtow6FjaCBow6BuZyByYSDEkWkgdsOsIGtow7RuZyBow6BpIGzDsm5nLCDEkWnhu4F1IMSRw7MgY8OzIHRo4buDIGvDqW8gdGhlbyBoaeG7h3Ug4bupbmcgbGFuIHRydXnhu4FuIHRpw6p1IGPhu7FjLCDhuqNuaCBoxrDhu59uZyDEkeG6v24gdXkgdMOtbiB0aMawxqFuZyBoaeG7h3UuDQoNCkdp4buvIGNow6JuIGtow6FjaCBow6BuZyBraMO0bmcgY2jhu4kgbMOgIG3hu5l0IHbhuqVuIMSR4buBIGtpbmggdOG6vywgbcOgIGzDoCBt4buZdCBiw6BpIHRvw6FuIHPhu5FuZyBjw7JuIHbhu5tpIG3hu41pIG5ow6AgbeG6oW5nLiDEkMOzIGzDoCBsw70gZG8gdsOsIHNhbyB2aeG7h2MgaGnhu4N1IHLDtSB2w6wgc2FvIGtow6FjaCBow6BuZyBy4budaSDEkWksIHbDoCBsw6BtIHNhbyDEkeG7gyBk4buxIGLDoW8gxJFp4buBdSDEkcOzIHThu6sgc+G7m20sIHRy4bufIHRow6BuaCDGsHUgdGnDqm4gaMOgbmcgxJHhuqd1IHRyb25nIGPDoWMgY2hp4bq/biBsxrDhu6NjIHbhuq1uIGjDoG5oIHbDoCBwaMOhdCB0cmnhu4NuIGPhu6dhIG5nw6BuaCB2aeG7hW4gdGjDtG5nIGhp4buHbiDEkeG6oWkuDQoNCiMjICoqMS4zLiBN4bulYyB0acOqdSBuZ2hpw6puIGPhu6l1KioNCk3hu6VjIHRpw6p1IGPhu6dhIG5naGnDqm4gY+G7qXUgbsOgeSBsw6AgeMOhYyDEkeG7i25oIHbDoCBwaMOibiB0w61jaCBjw6FjIHnhur91IHThu5Eg4bqjbmggaMaw4bufbmcgxJHhur9uIHZp4buHYyBy4budaSBi4buPIHZp4buHYyBz4butIGThu6VuZyBk4buLY2ggduG7pSB2aeG7hW4gdGjDtG5nIGPhu6dhIGtow6FjaCBow6BuZy4gQ+G7pSB0aOG7gyBsw6AgdMOhYyBnaeG6oyB04bqtcCB0cnVuZyB2w6BvIGPDoWMga2jDrWEgY+G6oW5oIHNhdToNCi0JVOG7tyBs4buHIHLhu51pIGLhu48gY+G7p2Ega2jDoWNoIGjDoG5nIFtDaHVybl0uDQotCUxv4bqhaSBo4bujcCDEkeG7k25nIGPDsyDhuqNuaCBoxrDhu59uZyDEkeG6v24gdOG7tyBs4buHIGtow6FjaCBow6BuZyBy4budaSBi4buPIGThu4tjaCB24bulIHZp4buFbiB0aMO0bmcgaGF5IGtow7RuZz8gTGnhu4d1IGjhu6NwIMSR4buTbmcgbmfhuq9uIGjhuqFuIHRow6wgdOG7tyBs4buHIGtow6FjaCBow6BuZyBy4budaSBi4buPIGPDoG5nIGNhby4NCi0JROG7i2NoIHbhu6UgSW50ZXJuZXQgY8OzIHTDoWMgxJHhu5luZyDEkeG6v24gdOG7tyBs4buHIHLhu51pIGLhu48ga2jDoWNoIGjDoG5nIGhheSBraMO0bmc/IEtow6FjaCBow6BuZyBz4butIGThu6VuZyBsb+G6oWkgZOG7i2NoIHbhu6UgSW50ZXJuZXQgbsOgbyBjw7Mga2jhuqMgbsSDbmcgcuG7nWkgYuG7jyBk4buLY2ggduG7pSB2aeG7hW4gdGjDtG5nIGNhbyBuaOG6pXQ7IGThu4tjaCB24bulIEludGVybmV0IHRy4buxYyB0aeG6v3AgdGjDtG5nIHF1YSDEkWnhu4duIHRob+G6oWkgKERTTCkgaGF5IHPhu60gZOG7pW5nIGPDoXAgcXVhbmcgKEZpYmVyIE9wdGljKSBoYXkga2jDtG5nIHPhu60gZOG7pW5nIGThu4tjaCB24bulIEludGVybmV0Lg0KLQlIw6xuaCB0aOG7qWMgdGhhbmggdG/DoW4gY8OzIOG6o25oIGjGsOG7n25nIMSR4bq/biBraOG6oyBuxINuZyBy4budaSBi4buPIGPhu6dhIGtow6FjaCBow6BuZyBoYXkga2jDtG5nPyBUaGFuaCB0b8OhbiBxdWEgU8OpYyDEkWnhu4duIHThu60gaGF5IFRoYW5oIHRvw6FuIHF1YSB0aMawLCBUaOG6uyBnaGkgbuG7oywgQ2h1eeG7g24ga2hv4bqjbiBuZ8OibiBow6BuZy4NCi0JVsOgIGN14buRaSBjw7luZyBsw6AgxJHhu5kgdHXhu5VpIGPDsyDhuqNuaCBoxrDhu59uZyDEkeG6v24gdOG7tyBs4buHIHLhu51pIGLhu48gY+G7p2Ega2jDoWNoIGjDoG5nIGhheSBraMO0bmc/IExp4buHdSBuZ8aw4budaSBs4bubbiB0deG7lWkgdGjDrCBz4bq9IHLhu51pIGLhu48gZOG7i2NoIHbhu6Ugdmnhu4VuIHRow7RuZyBuaGnhu4F1IGjGoW4gbMOgIG5nxrDhu51pIHRy4bq7IHR14buVaS4NCg0KIyMgKioxLjQuIFBoxrDGoW5nIHBow6FwIG5naGnDqm4gY+G7qXUqKg0KTmdoacOqbiBj4bupdSBz4butIGThu6VuZyBjw6FjIHBoxrDGoW5nIHBow6FwIHRo4buRbmcga8OqIHbDoCBtw7QgaMOsbmggaOG7k2kgcXV5IG5o4buLIHBow6JuLCBiYW8gZ+G7k20gYmEgbcO0IGjDrG5oOiB4w6FjIHN14bqldCB0dXnhur9uIHTDrW5oLCBQcm9iaXQgdsOgIExvZ2l0LCDEkeG7gyBwaMOibiB0w61jaCBk4buvIGxp4buHdSBraMOhY2ggaMOgbmcgdHJvbmcgbmfDoG5oIHZp4buFbiB0aMO0bmcuIFRyxrDhu5tjIHRpw6puLCBk4buvIGxp4buHdSDEkcaw4bujYyB44butIGzDvSBi4bqxbmcgdGjhu5FuZyBrw6ogbcO0IHThuqMgbmjhurFtIHTDs20gdOG6r3QgxJHhurdjIMSRaeG7g20gY8ahIGLhuqNuIGPhu6dhIG3huqt1IGto4bqjbyBzw6F0LiBUaeG6v3AgdGhlbywgY8OhYyBr4bu5IHRodeG6rXQgdGjhu5FuZyBrw6ogc3V5IGx14bqtbiBuaMawIGtp4buDbSDEkeG7i25oIGNoaS1iw6xuaCBwaMawxqFuZyB2w6AgcGjDom4gdMOtY2ggdOG7tyBs4buHIMSRxrDhu6NjIMOhcCBk4bulbmcgxJHhu4MgxJHDoW5oIGdpw6EgbeG7kWkgbGnDqm4gaOG7hyBnaeG7r2EgY8OhYyBiaeG6v24uIEN14buRaSBjw7luZywgbcO0IGjDrG5oIGjhu5NpIHF1eSBMb2dpdCB2w6AgUHJvYml0IMSRxrDhu6NjIHRyaeG7g24ga2hhaSBuaOG6sW0geMOhYyDEkeG7i25oIG3hu6ljIMSR4buZIOG6o25oIGjGsOG7n25nIGPhu6dhIHThu6tuZyB54bq/dSB04buRIChuaMawIGxv4bqhaSBo4bujcCDEkeG7k25nLCBk4buLY2ggduG7pSBpbnRlcm5ldCwgaMOsbmggdGjhu6ljIHRoYW5oIHRvw6FuLCB2LnYuKSDEkeG6v24ga2jhuqMgbsSDbmcga2jDoWNoIGjDoG5nIHLhu51pIGLhu48gZOG7i2NoIHbhu6UuIFBoxrDGoW5nIHBow6FwIG7DoHkgY2hvIHBow6lwIG5o4bqtbiBkaeG7h24gY8OhYyBuaMOzbSBraMOhY2ggaMOgbmcgY8OzIG5ndXkgY8ahIGNhbywgdOG7qyDEkcOzIGjhu5cgdHLhu6MgZG9hbmggbmdoaeG7h3AgeMOieSBk4buxbmcgY2hp4bq/biBsxrDhu6NjIGdp4buvIGNow6JuIGhp4buHdSBxdeG6oyBoxqFuLg0KDQojIyAqKjEuNS4gw50gbmdoxKlhIGPhu6dhIGLDoGkgbmdoacOqbiBj4bupdSoqDQpOZ2hpw6puIGPhu6l1IG7DoHkg4bupbmcgZOG7pW5nIGPDoWMgcGjGsMahbmcgcGjDoXAgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgxJHhu4tuaCBsxrDhu6NuZywgYmFvIGfhu5NtIHRo4buRbmcga8OqIG3DtCB04bqjLCBraeG7g20gxJHhu4tuaCBnaeG6oyB0aHV54bq/dCB2w6AgbcO0IGjDrG5oIGjhu5NpIHF1eSBuaOG7iyBwaMOibiAoTG9naXQsIFByb2JpdCksIMSR4buDIGThu7EgxJFvw6FuIGto4bqjIG7Eg25nIHLhu51pIGLhu48gZOG7i2NoIHbhu6UgY+G7p2Ega2jDoWNoIGjDoG5nIHRyb25nIG5nw6BuaCB2aeG7hW4gdGjDtG5nLiBE4buxYSB0csOqbiBi4buZIGThu68gbGnhu4d1IGjGoW4gNy4wMDAga2jDoWNoIGjDoG5nLCBuZ2hpw6puIGPhu6l1IMSRw6MgeMOhYyDEkeG7i25oIHLDtSBjw6FjIHnhur91IHThu5EgbMOgbSB0xINuZyBy4bunaSBybyBy4budaSBi4buPIG5oxrAgbG/huqFpIGjhu6NwIMSR4buTbmcsIGjDrG5oIHRo4bupYyB0aGFuaCB0b8OhbiB2w6AgbG/huqFpIGThu4tjaCB24bulIHPhu60gZOG7pW5nLg0KDQpW4buBIG3hurd0IGtob2EgaOG7jWMsIG5naGnDqm4gY+G7qXUgbMOgIG1pbmggY2jhu6luZyBjaG8gcXV5IHRyw6xuaCBwaMOibiB0w61jaCBk4buvIGxp4buHdSBsb2dpYyB2w6AgY8OzIHRo4buDIHTDoWkgc+G7rSBk4bulbmcgdHJvbmcgY8OhYyBiw6BpIHRvw6FuIHTGsMahbmcgdOG7sSB24buBIGjDoG5oIHZpIGtow6FjaCBow6BuZy4gVuG7gSBt4bq3dCB0aOG7sWMgdGnhu4VuLCBr4bq/dCBxdeG6oyBnacO6cCBkb2FuaCBuZ2hp4buHcCB2aeG7hW4gdGjDtG5nIHjDoWMgxJHhu4tuaCBz4bubbSBuaMOzbSBraMOhY2ggaMOgbmcgcuG7p2kgcm8gY2FvLCB04burIMSRw7MgdHJp4buDbiBraGFpIGPDoWMgY2hp4bq/biBsxrDhu6NjIGdp4buvIGNow6JuIGhp4buHdSBxdeG6oyB2w6AgdGnhur90IGtp4buHbSBjaGkgcGjDrS4NCg0KLS0tDQoNCiMgKipDSMavxqBORyAyOiBNw5QgVOG6oiBWw4AgUEjDgk4gVMONQ0ggQkFOIMSQ4bqmVSoqDQoNClRyxrDhu5tjIGtoaSB0aeG6v24gaMOgbmggcGjDom4gdMOtY2gsIHTDoWMgZ2nhuqMgdGjhu7FjIGhp4buHbiBixrDhu5tjIHRp4buBbiB44butIGzDvSBk4buvIGxp4buHdSBuaOG6sW0gxJHhuqNtIGLhuqNvIHTDrW5oIGNow61uaCB4w6FjIHbDoCB0csOhbmggbOG7l2kgdHJvbmcgcXXDoSB0csOsbmggY2jhuqF5IG3DoyBSLg0KDQpgYGB7ciBkYXRhLXByZXByb2Nlc3NpbmctY2gyfQ0KIyDEkOG7jWMgZOG7ryBsaeG7h3UgdsOgbyBSDQpkZiA8LSByZWFkLmNzdigiV0FfRm4tVXNlQ18tVGVsY28tQ3VzdG9tZXItQ2h1cm4uY3N2IikNCg0KIyAxLiBY4butIGzDvSBUb3RhbENoYXJnZXMNCmRmJFRvdGFsQ2hhcmdlcyA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkZiRUb3RhbENoYXJnZXMpKSANCmRmX2NsZWFuIDwtIGRmICU+JSBmaWx0ZXIoIWlzLm5hKFRvdGFsQ2hhcmdlcykpDQoNCiMgMi4gQ2h1eeG7g24gxJHhu5VpIGjDoG5nIGxv4bqhdCBjw6FjIGJp4bq/biBjaGFyYWN0ZXIgc2FuZyBmYWN0b3INCmRmX2NsZWFuIDwtIGRmX2NsZWFuICU+JQ0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlcikgJiAhY3VzdG9tZXJJRCwgYXMuZmFjdG9yKSkNCg0KIyAzLiBDaHV54buDbiDEkeG7lWkgU2VuaW9yQ2l0aXplbiB04burIHPhu5EgKDAsIDEpIHNhbmcgZmFjdG9yICgiTm8iLCAiWWVzIikNCmRmX2NsZWFuIDwtIGRmX2NsZWFuICU+JQ0KICBtdXRhdGUoU2VuaW9yQ2l0aXplbiA9IGFzLmZhY3RvcihpZmVsc2UoU2VuaW9yQ2l0aXplbiA9PSAxLCAiWWVzIiwgIk5vIikpKQ0KDQojIDQuIFThuqBPIEJJ4bq+TiBOSOG7iiBQSMOCTiBDSE8gTcOUIEjDjE5IIEjhu5JJIFFVWSAoU+G7rEEgTOG7lkkpDQojIEJp4bq/biBuw6B5IHBo4bqjaSDEkcaw4bujYyB04bqhbyDhu58gxJHDonkgxJHhu4MgY8OhYyBjaMawxqFuZyBzYXUgY8OzIHRo4buDIHPhu60gZOG7pW5nDQpkZl9jbGVhbiRDaHVybl9iaW5hcnkgPC0gaWZlbHNlKGRmX2NsZWFuJENodXJuID09ICJZZXMiLCAxLCAwKQ0KYGBgDQoqKkRp4buFbiBnaeG6o2k6KiogxJDhuqd1IHRpw6puLCBk4buvIGxp4buHdSDEkcaw4bujYyDEkeG7jWMgdsOgbyBSLiBCaeG6v24gYFRvdGFsQ2hhcmdlc2AgxJHGsOG7o2MgcGjDoXQgaGnhu4duIGPDsyBt4buZdCBz4buRIGdpw6EgdHLhu4sgYuG7iyB0aGnhur91LiDEkOG7gyB44butIGzDvSwgdMOhYyBnaeG6oyDEkcOjIGNodXnhu4NuIGPDoWMgZ2nDoSB0cuG7iyB0cuG7kW5nIHbhu4EgZOG6oW5nIGBOQWAgdsOgIHNhdSDEkcOzIGxv4bqhaSBi4buPIGPDoWMgZMOybmcgbsOgeSBraOG7j2kgcGjDom4gdMOtY2guIFRp4bq/cCB0aGVvLCBjw6FjIGJp4bq/biB2xINuIGLhuqNuICh0cuG7qyBgY3VzdG9tZXJJRGApIMSRxrDhu6NjIGNodXnhu4NuIHNhbmcgxJHhu4tuaCBk4bqhbmcgYGZhY3RvcmAuIEJp4bq/biBgU2VuaW9yQ2l0aXplbmAgxJHGsOG7o2MgY2h1eeG7g24gxJHhu5VpIHThu6sgZOG6oW5nIHPhu5EgKDAsIDEpIHNhbmcgbmjDo24gKCJObyIsICJZZXMiKS4gQ3Xhu5FpIGPDuW5nLCBiaeG6v24gYENodXJuX2JpbmFyeWAgKDAvMSkgxJHGsOG7o2MgdOG6oW8gc+G6tW4gxJHhu4MgcGjhu6VjIHbhu6UgY2hvIGPDoWMgbcO0IGjDrG5oIGjhu5NpIHF1eSDhu58gY8OhYyBjaMawxqFuZyBzYXUuDQoNCiMjICoqMi4xLiBQaMOibiB0w61jaCBjw6FjIHnhur91IHThu5EgdMOhYyDEkeG7mW5nIMSR4bq/biBU4bu3IGzhu4cgcuG7nWkgYuG7jyAoQ2h1cm4pKioNCg0KIyMjICoqMi4xLjEuIEJp4bq/biBDaHVybiAoVMOsbmggdHLhuqFuZyBy4budaSBi4buPKSoqDQoNCkLhuqNuZyB04bqnbiBz4buRIHbDoCB04bqnbiBzdeG6pXQgY+G7p2EgYmnhur9uIGBDaHVybmAgZ2nDunAgbMaw4bujbmcgaMOzYSBt4bupYyDEkeG7mSBuZ2hpw6ptIHRy4buNbmcgY+G7p2EgduG6pW4gxJHhu4EgcuG7nWkgYuG7jyBraMOhY2ggaMOgbmcuDQoNCmBgYHtyIGNodXJuLXRhYmxlcy1jaDJ9DQojIELhuqNuZyAyOiBC4bqjbmcgdOG6p24gc+G7kSBjaG8gYmnhur9uIENodXJuDQprYWJsZShhZGRtYXJnaW5zKHRhYmxlKGRmX2NsZWFuJENodXJuKSksIGNhcHRpb24gPSAiQuG6o25nIDI6IELhuqNuZyB04bqnbiBz4buRIGNobyBiaeG6v24gQ2h1cm4iKQ0KDQojIELhuqNuZyB04bqnbiBzdeG6pXQNCmNodXJuX3Byb3AgPC0gcHJvcC50YWJsZSh0YWJsZShkZl9jbGVhbiRDaHVybikpDQprYWJsZShjaHVybl9wcm9wLCBjYXB0aW9uID0gIkLhuqNuZyB04bqnbiBzdeG6pXQgKHThu7cgbOG7hykgY2hvIGJp4bq/biBDaHVybiIsIGRpZ2l0cyA9IDQpDQpgYGANCg0KYGBge3IgY2h1cm4tcGxvdC1iYXIsIGZpZy5jYXA9IkjDrG5oIDEuMTogUGjDom4gcGjhu5FpIHPhu5EgbMaw4bujbmcga2jDoWNoIGjDoG5nIHRoZW8gdMOsbmggdHLhuqFuZyBy4budaSBi4buPIn0NCmdncGxvdChkZl9jbGVhbiwgYWVzKHggPSBDaHVybiwgZmlsbCA9IENodXJuKSkgKw0KICBnZW9tX2Jhcih3aWR0aCA9IDAuNikgKw0KICBnZW9tX3RleHQoc3RhdD0nY291bnQnLCBhZXMobGFiZWw9Li5jb3VudC4uKSwgdmp1c3Q9LTAuNSkgKw0KICBsYWJzKHRpdGxlPSJQaMOibiBwaOG7kWkgc+G7kSBsxrDhu6NuZyBraMOhY2ggaMOgbmcgdGhlbyB0w6xuaCB0cuG6oW5nIHLhu51pIGLhu48iLCB4PSJUw6xuaCB0cuG6oW5nIFLhu51pIGLhu48iLCB5PSJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KYGBge3IgY2h1cm4tcGxvdC1waWUsIGZpZy5jYXA9IkjDrG5oIDEuMjogVOG7tyBs4buHIGtow6FjaCBow6BuZyB0aGVvIHTDrG5oIHRy4bqhbmcgcuG7nWkgYuG7jyJ9DQpwaWVfZGF0YV9jaHVybiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRmX2NsZWFuJENodXJuKSkNCmNvbG5hbWVzKHBpZV9kYXRhX2NodXJuKSA8LSBjKCJTdGF0dXMiLCAiQ291bnQiKQ0KcGllX2RhdGFfY2h1cm4kUGVyY2VudGFnZSA8LSBzY2FsZXM6OnBlcmNlbnQocGllX2RhdGFfY2h1cm4kQ291bnQgLyBzdW0ocGllX2RhdGFfY2h1cm4kQ291bnQpLCBhY2N1cmFjeSA9IDAuMSkNCg0KZ2dwbG90KHBpZV9kYXRhX2NodXJuLCBhZXMoeCA9ICIiLCB5ID0gQ291bnQsIGZpbGwgPSBTdGF0dXMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFBlcmNlbnRhZ2UpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBsYWJzKHRpdGxlID0gIlThu7cgbOG7hyBraMOhY2ggaMOgbmcgdGhlbyB0w6xuaCB0cuG6oW5nIHLhu51pIGLhu48iLCBmaWxsID0gIlTDrG5oIHRy4bqhbmciKSArDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpDQpgYGANCioqTmjhuq1uIHjDqXQ6KiogROG7ryBsaeG7h3UgY2hvIHRo4bqleSBjw7MgKioxLDg2OSBraMOhY2ggaMOgbmcgKDI2LjYlKSoqIMSRw6MgcuG7nWkgYuG7jyBk4buLY2ggduG7pS4gTeG6t2MgZMO5IG5ow7NtIGtow6FjaCBow6BuZyB0aeG6v3AgdOG7pWMgc+G7rSBk4bulbmcgY2hp4bq/bSDEkWEgc+G7kSAoKio3My40JSoqKSwgdOG7tyBs4buHIHLhu51pIGLhu48gduG6q24g4bufIG3hu6ljIGNhbyB2w6AgbMOgIG3hu5l0IHbhuqVuIMSR4buBIG5naGnDqm0gdHLhu41uZyBj4bqnbiBnaeG6o2kgcXV54bq/dC4gU+G7sSBjaMOqbmggbOG7h2NoIGdp4buvYSBoYWkgbmjDs20gKGfhuqduIDM6MSkgY2hvIHRo4bqleSBk4buvIGxp4buHdSBt4bqldCBjw6JuIGLhurFuZywgxJHDonkgbMOgIG3hu5l0IHnhur91IHThu5Ega+G7uSB0aHXhuq10IGPhuqduIMSRxrDhu6NjIHhlbSB4w6l0IGPhuqluIHRo4bqtbiBraGkgeMOieSBk4buxbmcgY8OhYyBtw7QgaMOsbmggZOG7sSBiw6FvIMSR4buDIHRyw6FuaCB0aGnDqm4gduG7iyBjaG8gbmjDs20gxJFhIHPhu5EuDQoNCiMjIyAqKjIuMS4yLiBCaeG6v24gQ29udHJhY3QgKExv4bqhaSBo4bujcCDEkeG7k25nKSoqDQoNCmBgYHtyIGNvbnRyYWN0LXRhYmxlcy1jaDJ9DQprYWJsZShhZGRtYXJnaW5zKHRhYmxlKGRmX2NsZWFuJENvbnRyYWN0KSksIGNhcHRpb24gPSAiQuG6o25nIDM6IELhuqNuZyB04bqnbiBz4buRIGPhu6dhIGJp4bq/biBDb250cmFjdCIpDQprYWJsZShwcm9wLnRhYmxlKHRhYmxlKGRmX2NsZWFuJENvbnRyYWN0KSksIGNhcHRpb24gPSAiQuG6o25nIHThuqduIHN14bqldCAodOG7tyBs4buHKSBj4bunYSBiaeG6v24gQ29udHJhY3QiLCBkaWdpdHMgPSA0KQ0KYGBgDQoNCmBgYHtyIGNvbnRyYWN0LXBsb3QtYmFyLCBmaWcuY2FwPSJIw6xuaCAyLjE6IFBow6JuIHBo4buRaSBz4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyB0aGVvIGxv4bqhaSBo4bujcCDEkeG7k25nIn0NCmdncGxvdChkZl9jbGVhbiwgYWVzKHggPSBDb250cmFjdCwgZmlsbCA9IENvbnRyYWN0KSkgKw0KICBnZW9tX2Jhcih3aWR0aCA9IDAuNikgKw0KICBnZW9tX3RleHQoc3RhdD0nY291bnQnLCBhZXMobGFiZWw9Li5jb3VudC4uKSwgdmp1c3Q9LTAuNSkgKw0KICBsYWJzKHRpdGxlPSJQaMOibiBwaOG7kWkgc+G7kSBsxrDhu6NuZyB0aGVvIGxv4bqhaSBo4bujcCDEkeG7k25nIiwgeD0iTG/huqFpIEjhu6NwIMSR4buTbmciLCB5PSJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KYGBge3IgY29udHJhY3QtcGxvdC1waWUsIGZpZy5jYXA9IkjDrG5oIDIuMjogVOG7tyBs4buHIGPDoWMgbG/huqFpIGjhu6NwIMSR4buTbmcifQ0KcGllX2RhdGFfY29udHJhY3QgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShkZl9jbGVhbiRDb250cmFjdCkpDQpjb2xuYW1lcyhwaWVfZGF0YV9jb250cmFjdCkgPC0gYygiQ29udHJhY3QiLCAiQ291bnQiKQ0KcGllX2RhdGFfY29udHJhY3QkUGVyY2VudGFnZSA8LSBzY2FsZXM6OnBlcmNlbnQocGllX2RhdGFfY29udHJhY3QkQ291bnQgLyBzdW0ocGllX2RhdGFfY29udHJhY3QkQ291bnQpLCBhY2N1cmFjeSA9IDAuMSkNCg0KZ2dwbG90KHBpZV9kYXRhX2NvbnRyYWN0LCBhZXMoeCA9ICIiLCB5ID0gQ291bnQsIGZpbGwgPSBDb250cmFjdCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gUGVyY2VudGFnZSksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIGxhYnModGl0bGUgPSAiVOG7tyBs4buHIGPDoWMgbG/huqFpIGjhu6NwIMSR4buTbmciLCBmaWxsID0gIkjhu6NwIMSR4buTbmciKSArDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCioqTmjhuq1uIHjDqXQ6KiogTmjDs20ga2jDoWNoIGjDoG5nIHPhu60gZOG7pW5nIGjhu6NwIMSR4buTbmcgdGhlbyB0aMOhbmcgY2hp4bq/bSB04bu3IGzhu4cgw6FwIMSR4bqjbyB24bubaSAqKjMsODc1IG5nxrDhu51pICg1NS4xJSkqKi4gxJDDonkgbMOgIG5ow7NtIGPDsyB0w61uaCBsaW5oIGhv4bqhdCBjYW8gbmjGsG5nIGPFqW5nIGzDoCBuaMOzbSB0aeG7gW0g4bqpbiBy4bunaSBybyBy4budaSBi4buPIGzhu5tuIG5o4bqldCBkbyBraMO0bmcgY8OzIGNhbSBr4bq/dCBkw6BpIGjhuqFuLiBDw6FjIGjhu6NwIMSR4buTbmcgZMOgaSBo4bqhbiAoMSBuxINtIHbDoCAyIG7Eg20pIGNoaeG6v20gdOG7tyBs4buHIHRo4bqlcCBoxqFuLCBs4bqnbiBsxrDhu6N0IGzDoCAqKjIwLjklKiogdsOgICoqMjQuMCUqKi4NCg0KIyMjICoqMi4xLjMuIEJp4bq/biBJbnRlcm5ldCBTZXJ2aWNlIChE4buLY2ggduG7pSBJbnRlcm5ldCkqKg0KDQpgYGB7ciBpbnRlcm5ldC10YWJsZXMtY2gyfQ0Ka2FibGUoYWRkbWFyZ2lucyh0YWJsZShkZl9jbGVhbiRJbnRlcm5ldFNlcnZpY2UpKSwgY2FwdGlvbiA9ICJC4bqjbmcgNDogQuG6o25nIHThuqduIHPhu5EgY+G7p2EgYmnhur9uIEludGVybmV0IFNlcnZpY2UiKQ0Ka2FibGUocHJvcC50YWJsZSh0YWJsZShkZl9jbGVhbiRJbnRlcm5ldFNlcnZpY2UpKSwgY2FwdGlvbiA9ICJC4bqjbmcgdOG6p24gc3XhuqV0IGPhu6dhIGJp4bq/biBJbnRlcm5ldCBTZXJ2aWNlIiwgZGlnaXRzID0gNCkNCmBgYA0KDQpgYGB7ciBpbnRlcm5ldC1wbG90LWJhciwgZmlnLmNhcD0iSMOsbmggMy4xOiBQaMOibiBwaOG7kWkgc+G7kSBsxrDhu6NuZyBraMOhY2ggaMOgbmcgdGhlbyBk4buLY2ggduG7pSBJbnRlcm5ldCJ9DQpnZ3Bsb3QoZGZfY2xlYW4sIGFlcyh4ID0gSW50ZXJuZXRTZXJ2aWNlLCBmaWxsID0gSW50ZXJuZXRTZXJ2aWNlKSkgKw0KICBnZW9tX2Jhcih3aWR0aCA9IDAuNikgKw0KICBnZW9tX3RleHQoc3RhdD0nY291bnQnLCBhZXMobGFiZWw9Li5jb3VudC4uKSwgdmp1c3Q9LTAuNSkgKw0KICBsYWJzKHRpdGxlPSJQaMOibiBwaOG7kWkgc+G7kSBsxrDhu6NuZyB0aGVvIGThu4tjaCB24bulIEludGVybmV0IiwgeD0iROG7i2NoIHbhu6UgSW50ZXJuZXQiLCB5PSJT4buRIGzGsOG7o25nIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KYGBge3IgaW50ZXJuZXQtcGxvdC1waWUsIGZpZy5jYXA9IkjDrG5oIDMuMjogVOG7tyBs4buHIGPDoWMgbG/huqFpIGThu4tjaCB24bulIEludGVybmV0In0NCnBpZV9kYXRhX2ludGVybmV0IDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZGZfY2xlYW4kSW50ZXJuZXRTZXJ2aWNlKSkNCmNvbG5hbWVzKHBpZV9kYXRhX2ludGVybmV0KSA8LSBjKCJTZXJ2aWNlIiwgIkNvdW50IikNCnBpZV9kYXRhX2ludGVybmV0JFBlcmNlbnRhZ2UgPC0gc2NhbGVzOjpwZXJjZW50KHBpZV9kYXRhX2ludGVybmV0JENvdW50IC8gc3VtKHBpZV9kYXRhX2ludGVybmV0JENvdW50KSwgYWNjdXJhY3kgPSAwLjEpDQoNCmdncGxvdChwaWVfZGF0YV9pbnRlcm5ldCwgYWVzKHggPSAiIiwgeSA9IENvdW50LCBmaWxsID0gU2VydmljZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gUGVyY2VudGFnZSksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIGxhYnModGl0bGUgPSAiVOG7tyBs4buHIGPDoWMgZOG7i2NoIHbhu6UgSW50ZXJuZXQiLCBmaWxsID0gIkThu4tjaCB24bulIikgKw0KICB0aGVtZV92b2lkKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KYGBgDQoqKk5o4bqtbiB4w6l0OioqIEThu4tjaCB24bulIGPDoXAgcXVhbmcgKGBGaWJlciBvcHRpY2ApIGzDoCBwaOG7lSBiaeG6v24gbmjhuqV0ICgqKjQ0LjAlKiopLCBwaOG6o24gw6FuaCBuaHUgY+G6p3UgduG7gSBpbnRlcm5ldCB04buRYyDEkeG7mSBjYW8uIEPDsyDEkeG6v24gKioyMS42JSoqIGtow6FjaCBow6BuZyBraMO0bmcgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgaW50ZXJuZXQsIHThuqFvIHRow6BuaCBt4buZdCBwaMOibiBraMO6YyBraMOhY2ggaMOgbmcgcmnDqm5nIGJp4buHdC4NCg0KIyMjICoqMi4xLjQuIEJp4bq/biBQYXltZW50IE1ldGhvZCAoUGjGsMahbmcgdGjhu6ljIHRoYW5oIHRvw6FuKSoqDQoNCmBgYHtyIHBheW1lbnQtdGFibGVzLWNoMn0NCmthYmxlKGFkZG1hcmdpbnModGFibGUoZGZfY2xlYW4kUGF5bWVudE1ldGhvZCkpLCBjYXB0aW9uID0gIkLhuqNuZyA1OiBC4bqjbmcgdOG6p24gc+G7kSBj4bunYSBiaeG6v24gUGF5bWVudCBNZXRob2QiKQ0Ka2FibGUocHJvcC50YWJsZSh0YWJsZShkZl9jbGVhbiRQYXltZW50TWV0aG9kKSksIGNhcHRpb24gPSAiQuG6o25nIHThuqduIHN14bqldCBj4bunYSBiaeG6v24gUGF5bWVudE1ldGhvZCIsIGRpZ2l0cyA9IDQpDQpgYGANCg0KYGBge3IgcGF5bWVudC1wbG90LWJhciwgZmlnLmNhcD0iSMOsbmggNC4xOiBQaMOibiBwaOG7kWkgc+G7kSBsxrDhu6NuZyB0aGVvIHBoxrDGoW5nIHRo4bupYyB0aGFuaCB0b8OhbiJ9DQpnZ3Bsb3QoZGZfY2xlYW4sIGFlcyh4ID0gUGF5bWVudE1ldGhvZCwgZmlsbCA9IFBheW1lbnRNZXRob2QpKSArDQogIGdlb21fYmFyKHdpZHRoID0gMC43KSArDQogIGdlb21fdGV4dChzdGF0PSdjb3VudCcsIGFlcyhsYWJlbD0uLmNvdW50Li4pLCB2anVzdD0tMC41KSArDQogIGxhYnModGl0bGU9IlBow6JuIHBo4buRaSB0aGVvIHBoxrDGoW5nIHRo4bupYyB0aGFuaCB0b8OhbiIsIHg9IlBoxrDGoW5nIHRo4bupYyIsIHk9IlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxNSwgaGp1c3QgPSAxKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQpgYGB7ciBwYXltZW50LXBsb3QtcGllLCBmaWcuY2FwPSJIw6xuaCA0LjI6IFThu7cgbOG7hyBjw6FjIHBoxrDGoW5nIHRo4bupYyB0aGFuaCB0b8OhbiJ9DQpwaWVfZGF0YV9wYXltZW50IDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZGZfY2xlYW4kUGF5bWVudE1ldGhvZCkpDQpjb2xuYW1lcyhwaWVfZGF0YV9wYXltZW50KSA8LSBjKCJNZXRob2QiLCAiQ291bnQiKQ0KcGllX2RhdGFfcGF5bWVudCRQZXJjZW50YWdlIDwtIHNjYWxlczo6cGVyY2VudChwaWVfZGF0YV9wYXltZW50JENvdW50IC8gc3VtKHBpZV9kYXRhX3BheW1lbnQkQ291bnQpLCBhY2N1cmFjeSA9IDAuMSkNCg0KZ2dwbG90KHBpZV9kYXRhX3BheW1lbnQsIGFlcyh4ID0gIiIsIHkgPSBDb3VudCwgZmlsbCA9IE1ldGhvZCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gUGVyY2VudGFnZSksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIGxhYnModGl0bGUgPSAiVOG7tyBs4buHIGPDoWMgcGjGsMahbmcgdGjhu6ljIHRoYW5oIHRvw6FuIiwgZmlsbCA9ICJQaMawxqFuZyB0aOG7qWMiKSArDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCioqTmjhuq1uIHjDqXQ6KiogYEVsZWN0cm9uaWMgY2hlY2tgIGzDoCBwaMawxqFuZyB0aOG7qWMgcGjhu5UgYmnhur9uIG5o4bqldCAoKiozMy42JSoqKS4gxJBhIHPhu5Ega2jDoWNoIGjDoG5nICgqKjU2LjUlKiopIHbhuqtuIGTDuW5nIGPDoWMgcGjGsMahbmcgdGjhu6ljIHRoYW5oIHRvw6FuIHRo4bunIGPDtG5nLiDEkGnhu4F1IG7DoHkgY8OzIHRo4buDIGzDoCBt4buZdCB54bq/dSB04buRIHLhu6dpIHJvLg0KDQojIyMgKioyLjEuNS4gQmnhur9uIFNlbmlvckNpdGl6ZW4gKE5nxrDhu51pIGNhbyB0deG7lWkpKioNCg0KYGBge3Igc2VuaW9yLXRhYmxlcy1jaDJ9DQprYWJsZShhZGRtYXJnaW5zKHRhYmxlKGRmX2NsZWFuJFNlbmlvckNpdGl6ZW4pKSwgY2FwdGlvbiA9ICJC4bqjbmcgNjogQuG6o25nIHThuqduIHPhu5EgY+G7p2EgYmnhur9uIFNlbmlvckNpdGl6ZW4iKQ0Ka2FibGUocHJvcC50YWJsZSh0YWJsZShkZl9jbGVhbiRTZW5pb3JDaXRpemVuKSksIGNhcHRpb24gPSAiQuG6o25nIHThuqduIHN14bqldCBj4bunYSBiaeG6v24gU2VuaW9yQ2l0aXplbiIsIGRpZ2l0cyA9IDQpDQpgYGANCg0KYGBge3Igc2VuaW9yLXBsb3QtYmFyLCBmaWcuY2FwPSJIw6xuaCA1LjE6IFBow6JuIHBo4buRaSBz4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyB0aGVvIG5ow7NtIHR14buVaSJ9DQpnZ3Bsb3QoZGZfY2xlYW4sIGFlcyh4ID0gU2VuaW9yQ2l0aXplbiwgZmlsbCA9IFNlbmlvckNpdGl6ZW4pKSArDQogIGdlb21fYmFyKHdpZHRoID0gMC42KSArDQogIGdlb21fdGV4dChzdGF0PSdjb3VudCcsIGFlcyhsYWJlbD0uLmNvdW50Li4pLCB2anVzdD0tMC41KSArDQogIGxhYnModGl0bGU9IlBow6JuIHBo4buRaSB0aGVvIG5ow7NtIHR14buVaSIsIHg9IkzDoCBuZ8aw4budaSBjYW8gdHXhu5VpPyIsIHk9IlPhu5EgbMaw4bujbmciKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQpgYGB7ciBzZW5pb3ItcGxvdC1waWUsIGZpZy5jYXA9IkjDrG5oIDUuMjogVOG7tyBs4buHIGtow6FjaCBow6BuZyB0aGVvIG5ow7NtIHR14buVaSJ9DQpwaWVfZGF0YV9zZW5pb3IgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShkZl9jbGVhbiRTZW5pb3JDaXRpemVuKSkNCmNvbG5hbWVzKHBpZV9kYXRhX3NlbmlvcikgPC0gYygiR3JvdXAiLCAiQ291bnQiKQ0KcGllX2RhdGFfc2VuaW9yJFBlcmNlbnRhZ2UgPC0gc2NhbGVzOjpwZXJjZW50KHBpZV9kYXRhX3NlbmlvciRDb3VudCAvIHN1bShwaWVfZGF0YV9zZW5pb3IkQ291bnQpLCBhY2N1cmFjeSA9IDAuMSkNCg0KZ2dwbG90KHBpZV9kYXRhX3NlbmlvciwgYWVzKHggPSAiIiwgeSA9IENvdW50LCBmaWxsID0gR3JvdXApKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFBlcmNlbnRhZ2UpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBsYWJzKHRpdGxlID0gIlThu7cgbOG7hyBraMOhY2ggaMOgbmcgY2FvIHR14buVaSIsIGZpbGwgPSAiTmjDs20gdHXhu5VpIikgKw0KICB0aGVtZV92b2lkKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KYGBgDQoqKk5o4bqtbiB4w6l0OioqIE5ow7NtIGtow7RuZyBwaOG6o2kgbmfGsOG7nWkgY2FvIHR14buVaSBjaGnhur9tIMSR4bqhaSDEkWEgc+G7kSAoKio4My44JSoqKSwgdHJvbmcga2hpIG5ow7NtIG5nxrDhu51pIGNhbyB0deG7lWkgY2jhu4kgY2hp4bq/bSAqKjE2LjIlKiouDQoNCiMjICoqMi4yLiBQaMOibiB0w61jaCB0w6FjIMSR4buZbmcgZ2nhu69hIGPDoWMgeeG6v3UgdOG7kSB24bubaSBU4bu3IGzhu4cgcuG7nWkgYuG7jyAoQ2h1cm4pKioNCg0KIyMjICoqMi4yLjEuIE3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgQ29udHJhY3QgdsOgIENodXJuKioNCg0KYGBge3IgY29udHJhY3QtY2h1cm4tYml2YXJpYXRlLWNoMn0NCmthYmxlKGFkZG1hcmdpbnModGFibGUoZGZfY2xlYW4kQ29udHJhY3QsIGRmX2NsZWFuJENodXJuKSksIGNhcHRpb24gPSAiQuG6o25nIDc6IELhuqNuZyB04bqnbiBz4buRIGdp4buvYSBDb250cmFjdCB2w6AgQ2h1cm4iKQ0Ka2FibGUocHJvcC50YWJsZSh0YWJsZShkZl9jbGVhbiRDb250cmFjdCwgZGZfY2xlYW4kQ2h1cm4pLCAxKSAqIDEwMCwgZGlnaXRzID0gMiwgDQogICAgICBjYXB0aW9uID0gIkLhuqNuZyA4OiBC4bqjbmcgcGjhuqduIHRyxINtIHLhu51pIGLhu48gdGhlbyBsb+G6oWkgaOG7o3AgxJHhu5NuZyAoJSkiKQ0KYGBgDQoNCmBgYHtyIGNvbnRyYWN0LWNodXJuLXBsb3QtY2gyLCBmaWcuY2FwPSJIw6xuaCA2OiBTbyBzw6FuaCB04bu3IGzhu4cgcuG7nWkgYuG7jyB0aGVvIGxv4bqhaSBo4bujcCDEkeG7k25nIn0NCnBfZmlsbCA8LSBnZ3Bsb3QoZGZfY2xlYW4sIGFlcyh4ID0gQ29udHJhY3QsIGZpbGwgPSBDaHVybikpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIHdpZHRoID0gMC43KSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgbGFicyh0aXRsZSA9ICJIw6xuaCA2LjE6IFThu7cgbOG7hyBDaHVybiB0aGVvIExv4bqhaSBo4bujcCDEkeG7k25nIiwNCiAgICAgICB4ID0gIkxv4bqhaSBI4bujcCDEkeG7k25nIiwgeSA9ICJU4bu3IGzhu4cga2jDoWNoIGjDoG5nIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KDQpwX21vc2FpYyA8LSBnZ3Bsb3QoZGF0YSA9IGRmX2NsZWFuKSArDQogIGdlb21fbW9zYWljKGFlcyh4ID0gcHJvZHVjdChDb250cmFjdCwgQ2h1cm4pLCBmaWxsPUNodXJuKSkgKw0KICBsYWJzKHRpdGxlPSJIw6xuaCA2LjI6IEJp4buDdSDEkeG7kyBNb3NhaWMgZ2nhu69hIENvbnRyYWN0IHbDoCBDaHVybiIsIHg9Ikxv4bqhaSBo4bujcCDEkeG7k25nIiwgeT0iVOG7tyBs4buHIENodXJuIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQogIA0KZ3JpZC5hcnJhbmdlKHBfZmlsbCwgcF9tb3NhaWMsIG5jb2w9MikNCmBgYA0KKipOaOG6rW4geMOpdDoqKiBD4bqjIGhhaSBiaeG7g3UgxJHhu5MgxJHhu4F1IGNobyB0aOG6pXkgbeG7mXQgeHUgaMaw4bubbmcgcuG6pXQgcsO1IHLDoG5nOiB04bu3IGzhu4cgcuG7nWkgYuG7jyBnaeG6o20gbeG6oW5oIGtoaSB0aOG7nWkgZ2lhbiBjYW0ga+G6v3QgaOG7o3AgxJHhu5NuZyB0xINuZyBsw6puLiBD4bulIHRo4buDLCBjw7MgdOG7m2kgKio0Mi43JSoqIGtow6FjaCBow6BuZyBjw7MgaOG7o3AgxJHhu5NuZyB0aGVvIHRow6FuZyDEkcOjIHLhu51pIGLhu48sIHRyb25nIGtoaSBjb24gc+G7kSBuw6B5IGNo4buJIGzDoCAqKjExLjMlKiogxJHhu5FpIHbhu5tpIGjhu6NwIMSR4buTbmcgbeG7mXQgbsSDbSB2w6AgKioyLjklKiogxJHhu5FpIHbhu5tpIGjhu6NwIMSR4buTbmcgaGFpIG7Eg20uIMSQaeG7gXUgbsOgeSBraOG6s25nIMSR4buLbmggcuG6sW5nIGxv4bqhaSBo4bujcCDEkeG7k25nIGzDoCBt4buZdCB54bq/dSB04buRIGThu7EgYsOhbyBj4buxYyBr4buzIG3huqFuaCBt4bq9IGNobyBow6BuaCB2aSBy4budaSBi4buPLg0KDQotLS0NCg0KIyAqKkNIxq/GoE5HIDM6IFBow6JuIHTDrWNoIE3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgSGFpIGJp4bq/biDEkOG7i25oIHTDrW5oKioNCg0KIyMgKiozLjEgQ2h1cm4gdsOgIENvbnRyYWN0IChMb+G6oWkgaOG7o3AgxJHhu5NuZykqKg0KDQojIyMgKiozLjEuMS4gQuG6o25nIHThuqduIHPhu5EqKg0KYGBge3IgdGFibGUtY29udHJhY3QtY2h1cm59DQpjaHVybl9jb250cmFjdF90YWJsZSA8LSB0YWJsZShkZl9jbGVhbiRDb250cmFjdCwgZGZfY2xlYW4kQ2h1cm4pDQpjYXQoIkLhuqNuZyB04bqnbiBz4buRIGNow6lvIGdp4buvYSBDb250cmFjdCB2w6AgQ2h1cm46XG4iKQ0KYWRkbWFyZ2lucyhjaHVybl9jb250cmFjdF90YWJsZSkNCmBgYA0KDQojIyMgKiozLjEuMi4gS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nKioNCg0KKipHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaDoqKg0KDQotICAgKipI4oKAKio6IExv4bqhaSBo4bujcCDEkeG7k25nIHbDoCB2aeG7h2MgcuG7nWkgYuG7jyBsw6AgaGFpIGJp4bq/biDEkeG7mWMgbOG6rXAuDQotICAgKipI4oKBKio6IExv4bqhaSBo4bujcCDEkeG7k25nIHbDoCB2aeG7h2MgcuG7nWkgYuG7jyBjw7MgbGnDqm4gcXVhbiDEkeG6v24gbmhhdS4NCg0KYGBge3IgY2hpc3EtY29udHJhY3QtY2h1cm59DQpjaGlfY29udHJhY3QgPC0gY2hpc3EudGVzdChjaHVybl9jb250cmFjdF90YWJsZSkNCnByaW50KGNoaV9jb250cmFjdCkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqIHAtdmFsdWUgPCAyLjJlLTE2LCBiw6FjIGLhu48gSOKCgC4gQ8OzIG3hu5l0IG3hu5FpIGxpw6puIGjhu4cgdGjhu5FuZyBrw6ogY+G7sWMga+G7syBt4bqhbmggbeG6vSBnaeG7r2EgbG/huqFpIGjhu6NwIMSR4buTbmcgdsOgIGto4bqjIG7Eg25nIHLhu51pIGLhu48uDQoNCiMjIyAqKjMuMS4zLiBIaeG7h3UgdOG7tyBs4buHLCBSUiB2w6AgT1IgKFBow6JuIHTDrWNoIHRoZW8gY+G6t3ApKioNCg0KKipTbyBzw6FuaCAnT25lIHllYXInIHZzLiAnTW9udGgtdG8tbW9udGgnOioqDQpgYGB7ciBwcm9wLXRlc3QtMXlyfQ0KY2F0KCJHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaDpcbiIpDQpjYXQoIkjigoA6IFThu7cgbOG7hyBy4budaSBi4buPIOG7nyBuaMOzbSAnT25lIHllYXInIHbDoCAnTW9udGgtdG8tbW9udGgnIGzDoCBi4bqxbmcgbmhhdS5cbiIpDQpjYXQoIkjigoE6IFThu7cgbOG7hyBy4budaSBi4buPIOG7nyBuaMOzbSAnT25lIHllYXInIHRo4bqlcCBoxqFuIG5ow7NtICdNb250aC10by1tb250aCcuXG5cbiIpDQoNCiMgTOG7jWMgdsOgIGxv4bqhaSBi4buPIGPDoWMgbGV2ZWwga2jDtG5nIGTDuW5nIHThu5tpDQpjb250cmFjdF9zdWJfMXlyIDwtIGRmX2NsZWFuICU+JSANCiAgZmlsdGVyKENvbnRyYWN0ICVpbiUgYygiTW9udGgtdG8tbW9udGgiLCAiT25lIHllYXIiKSkgJT4lDQogIGRyb3BsZXZlbHMoKQ0KDQp0YWJsZV8xeXIgPC0gdGFibGUoY29udHJhY3Rfc3ViXzF5ciRDb250cmFjdCwgY29udHJhY3Rfc3ViXzF5ciRDaHVybikNCmNvdW50c18xeXIgPC0gdGFibGVfMXlyWywgIlllcyJdDQp0b3RhbHNfMXlyIDwtIHJvd1N1bXModGFibGVfMXlyKQ0KcHJvcC50ZXN0KGNvdW50c18xeXIsIHRvdGFsc18xeXIsIGFsdGVybmF0aXZlPSJsZXNzIiwgY29ycmVjdD1GQUxTRSkNCmBgYA0KYGBge3Igb3ItY29udHJhY3QtMXlyfQ0Kb2Rkc3JhdGlvKHRhYmxlXzF5ciwgbWV0aG9kPSJ3YWxkIikNCmBgYA0KLT4gKipOaOG6rW4geMOpdDoqKiBU4bu3IGzhu4cgcuG7nWkgYuG7jyDhu58gbmjDs20gaOG7o3AgxJHhu5NuZyAxIG7Eg20gKDExLjMlKSB0aOG6pXAgaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBuaMOzbSBo4bujcCDEkeG7k25nIHRow6FuZyAoNDIuNyUpLiBPZGRzIHLhu51pIGLhu48gY+G7p2Ega2jDoWNoIGjDoG5nIGjhu6NwIMSR4buTbmcgMSBuxINtIGNo4buJIGLhurFuZyAwLjE3IGzhuqduIHNvIHbhu5tpIGtow6FjaCBow6BuZyBo4bujcCDEkeG7k25nIHRoZW8gdGjDoW5nLg0KDQoqKlNvIHPDoW5oICdUd28geWVhcicgdnMuICdNb250aC10by1tb250aCc6KioNCmBgYHtyIHByb3AtdGVzdC0yeXJ9DQpjYXQoIkdp4bqjIHRodXnhur90IGtp4buDbSDEkeG7i25oOlxuIikNCmNhdCgiSOKCgDogVOG7tyBs4buHIHLhu51pIGLhu48g4bufIG5ow7NtICdUd28geWVhcicgdsOgICdNb250aC10by1tb250aCcgbMOgIGLhurFuZyBuaGF1LlxuIikNCmNhdCgiSOKCgTogVOG7tyBs4buHIHLhu51pIGLhu48g4bufIG5ow7NtICdUd28geWVhcicgdGjhuqVwIGjGoW4gbmjDs20gJ01vbnRoLXRvLW1vbnRoJy5cblxuIikNCg0KIyBM4buNYyB2w6AgbG/huqFpIGLhu48gY8OhYyBsZXZlbCBraMO0bmcgZMO5bmcgdOG7m2kNCmNvbnRyYWN0X3N1Yl8yeXIgPC0gZGZfY2xlYW4gJT4lIA0KICBmaWx0ZXIoQ29udHJhY3QgJWluJSBjKCJNb250aC10by1tb250aCIsICJUd28geWVhciIpKSAlPiUNCiAgZHJvcGxldmVscygpDQogIA0KdGFibGVfMnlyIDwtIHRhYmxlKGNvbnRyYWN0X3N1Yl8yeXIkQ29udHJhY3QsIGNvbnRyYWN0X3N1Yl8yeXIkQ2h1cm4pDQpjb3VudHNfMnlyIDwtIHRhYmxlXzJ5clssICJZZXMiXQ0KdG90YWxzXzJ5ciA8LSByb3dTdW1zKHRhYmxlXzJ5cikNCnByb3AudGVzdChjb3VudHNfMnlyLCB0b3RhbHNfMnlyLCBhbHRlcm5hdGl2ZT0ibGVzcyIsIGNvcnJlY3Q9RkFMU0UpDQpgYGANCmBgYHtyIG9yLWNvbnRyYWN0LTJ5cn0NCm9kZHNyYXRpbyh0YWJsZV8yeXIsIG1ldGhvZD0id2FsZCIpDQpgYGANCi0+ICoqTmjhuq1uIHjDqXQ6KiogVOG7tyBs4buHIHLhu51pIGLhu48g4bufIG5ow7NtIGjhu6NwIMSR4buTbmcgMiBuxINtICgyLjklKSB0aOG6pXAgaMahbiBy4bqldCBuaGnhu4F1IHNvIHbhu5tpIG5ow7NtIGjhu6NwIMSR4buTbmcgdGjDoW5nICg0Mi43JSkuIE9kZHMgcuG7nWkgYuG7jyBj4bunYSBo4buNIGNo4buJIGLhurFuZyAwLjA0IGzhuqduIHNvIHbhu5tpIGjhu6NwIMSR4buTbmcgdGjDoW5nLCBjaG8gdGjhuqV5IMSRw6J5IGzDoCB54bq/dSB04buRIGLhuqNvIHbhu4cgbeG6oW5oIG5o4bqldC4NCg0KLS0tDQoNCiMjICoqMy4yLiBQaMOibiB0w61jaCBDaHVybiB2w6AgU2VuaW9yQ2l0aXplbiAoTmfGsOG7nWkgY2FvIHR14buVaSkqKg0KDQojIyMgKiozLjIuMS4gQuG6o25nIHThuqduIHPhu5EqKg0KYGBge3IgdGFibGUtc2VuaW9yLWNodXJufQ0KZGZfY2xlYW4kQ2h1cm5fbGFiZWxlZCA8LSBmYWN0b3IoZGZfY2xlYW4kQ2h1cm4sIGxldmVscyA9IGMoIk5vIiwgIlllcyIpLCBsYWJlbHMgPSBjKCJLaMO0bmcgcuG7nWkgYuG7jyIsICJS4budaSBi4buPIikpDQpkZl9jbGVhbiRTZW5pb3JDaXRpemVuX2xhYmVsZWQgPC0gZmFjdG9yKGRmX2NsZWFuJFNlbmlvckNpdGl6ZW4sIGxldmVscyA9IGMoIk5vIiwgIlllcyIpLCBsYWJlbHMgPSBjKCJLaMO0bmcgcGjhuqNpIGNhbyB0deG7lWkiLCAiTMOgIG5nxrDhu51pIGNhbyB0deG7lWkiKSkNCmNodXJuX3Nlbmlvcl90YWJsZSA8LSB0YWJsZShkZl9jbGVhbiRTZW5pb3JDaXRpemVuX2xhYmVsZWQsIGRmX2NsZWFuJENodXJuX2xhYmVsZWQpDQpjYXQoIkLhuqNuZyB04bqnbiBz4buRIGNow6lvIGdp4buvYSBTZW5pb3JDaXRpemVuIHbDoCBDaHVybjpcbiIpDQphZGRtYXJnaW5zKGNodXJuX3Nlbmlvcl90YWJsZSkNCmBgYA0KDQojIyMgKiozLjIuMi4gS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nKioNCmBgYHtyIGNoaXNxLXNlbmlvci1jaHVybn0NCnByaW50KGNoaXNxLnRlc3QodGFibGUoZGZfY2xlYW4kQ2h1cm4sIGRmX2NsZWFuJFNlbmlvckNpdGl6ZW4pKSkNCmBgYA0KLT4gKipOaOG6rW4geMOpdDoqKiBwLXZhbHVlIDwgMi4yZS0xNi4gQsOhYyBi4buPIEjigoAuIEPDsyBt4buRaSBsacOqbiBo4buHIG3huqFuaCBt4bq9Lg0KDQojIyMgKiozLjIuMy4gSGnhu4d1IHThu7cgbOG7hyoqDQpgYGB7ciBwcm9wLXRlc3Qtc2VuaW9yLWNodXJufQ0KY2F0KCJHaeG6oyB0aHV54bq/dCBraeG7g20gxJHhu4tuaDpcbiIpDQpjYXQoIkjigoA6IFThu7cgbOG7hyBy4budaSBi4buPIOG7nyBoYWkgbmjDs20gbMOgIGLhurFuZyBuaGF1LlxuIikNCmNhdCgiSOKCgTogVOG7tyBs4buHIHLhu51pIGLhu48g4bufIG5ow7NtIGtow7RuZyBwaOG6o2kgY2FvIHR14buVaSB0aOG6pXAgaMahbiBuaMOzbSBjYW8gdHXhu5VpLlxuXG4iKQ0KDQpjb3VudHNfY2h1cm4gPC0gY2h1cm5fc2VuaW9yX3RhYmxlWywgIlLhu51pIGLhu48iXSANCnRvdGFsc19ncm91cCA8LSByb3dTdW1zKGNodXJuX3Nlbmlvcl90YWJsZSkNCnByb3AudGVzdCh4ID0gY291bnRzX2NodXJuLCBuID0gdG90YWxzX2dyb3VwLCBhbHRlcm5hdGl2ZSA9ICJsZXNzIiwgY29ycmVjdCA9IEZBTFNFKQ0KYGBgDQotPiAqKk5o4bqtbiB4w6l0OioqIFThu7cgbOG7hyBy4budaSBi4buPIOG7nyBuaMOzbSBraMO0bmcgcGjhuqNpIG5nxrDhu51pIGNhbyB0deG7lWkgKDIzLjYlKSB0aOG6pXAgaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBuaMOzbSBuZ8aw4budaSBjYW8gdHXhu5VpICg0MS43JSkuDQoNCiMjIyAqKjMuMi40LiBS4bunaSBybyB0xrDGoW5nIMSR4buRaSAoUlIpKioNCmBgYHtyIHJyLXNlbmlvci1jaHVybn0NCnJpc2tyYXRpbyhjaHVybl9zZW5pb3JfdGFibGUsIG1ldGhvZD0id2FsZCIpDQpgYGANCi0+ICoqTmjhuq1uIHjDqXQ6KiogTmd1eSBjxqEgcuG7nWkgYuG7jyDhu58gbmjDs20gbmfGsOG7nWkgY2FvIHR14buVaSBjYW8gZ+G6pXAgMS43NiBs4bqnbi4NCg0KIyMjICoqMy4yLjUuIFThu7cgc+G7kSBDaMOqbmggKE9SKSoqDQpgYGB7ciBvci1zZW5pb3ItY2h1cm59DQpvZGRzcmF0aW8oY2h1cm5fc2VuaW9yX3RhYmxlLCBtZXRob2Q9IndhbGQiKQ0KYGBgDQotPiAqKk5o4bqtbiB4w6l0OioqIE9kZHMgcuG7nWkgYuG7jyBj4bunYSBuZ8aw4budaSBjYW8gdHXhu5VpIGNhbyBoxqFuIDIuMjkgbOG6p24uDQoNCi0tLQ0KDQojIyAqKjMuMy4gUGjDom4gdMOtY2ggQ2h1cm4gdsOgIFBheW1lbnRNZXRob2QgKFBoxrDGoW5nIHRo4bupYyB0aGFuaCB0b8OhbikqKg0KDQojIyMgKiozLjMuMS4gQuG6o25nIHThuqduIHPhu5EqKg0KYGBge3IgdGFibGUtcGF5bWVudC1jaHVybn0NCmNodXJuX3BheW1lbnRfdGFibGUgPC0gdGFibGUoZGZfY2xlYW4kUGF5bWVudE1ldGhvZCwgZGZfY2xlYW4kQ2h1cm4pDQpjYXQoIkLhuqNuZyB04bqnbiBz4buRIGNow6lvOlxuIikNCmFkZG1hcmdpbnMoY2h1cm5fcGF5bWVudF90YWJsZSkNCmBgYA0KDQojIyMgKiozLjMuMi4gS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nKioNCmBgYHtyIGNoaXNxLXBheW1lbnQtY2h1cm59DQpwcmludChjaGlzcS50ZXN0KGNodXJuX3BheW1lbnRfdGFibGUpKQ0KYGBgDQotPiAqKk5o4bqtbiB4w6l0OioqIHAtdmFsdWUgPCAyLjJlLTE2LiBCw6FjIGLhu48gSOKCgC4gUGjGsMahbmcgdGjhu6ljIHRoYW5oIHRvw6FuIGPDsyBt4buRaSBsacOqbiBo4buHIHLhuqV0IG3huqFuaCB24bubaSB2aeG7h2MgcuG7nWkgYuG7jy4NCg0KIyMjICoqMy4zLjMuIEhp4buHdSB04bu3IGzhu4cgdsOgIE9SKioNCmBgYHtyIG9yLXBheW1lbnQtY2h1cm59DQpjYXQoIlNvIHPDoW5oICdFbGVjdHJvbmljIGNoZWNrJyB24bubaSAnQ3JlZGl0IGNhcmQgKGF1dG9tYXRpYyknOlxuIikNCmNhdCgiSOKCgDogVOG7tyBs4buHIHLhu51pIGLhu48gbMOgIG5oxrAgbmhhdS5cbiIpDQpjYXQoIkjigoE6IFThu7cgbOG7hyBy4budaSBi4buPIOG7nyBuaMOzbSAnRWxlY3Ryb25pYyBjaGVjaycgY2FvIGjGoW4uXG5cbiIpDQoNCnBheW1lbnRfc3ViX2VjIDwtIGRmX2NsZWFuICU+JSANCiAgZmlsdGVyKFBheW1lbnRNZXRob2QgJWluJSBjKCJFbGVjdHJvbmljIGNoZWNrIiwgIkNyZWRpdCBjYXJkIChhdXRvbWF0aWMpIikpICU+JQ0KICBkcm9wbGV2ZWxzKCkNCiAgDQp0YWJsZV9lYyA8LSB0YWJsZShwYXltZW50X3N1Yl9lYyRQYXltZW50TWV0aG9kLCBwYXltZW50X3N1Yl9lYyRDaHVybikNCnByb3AudGVzdCh4ID0gdGFibGVfZWNbLCAiWWVzIl0sIG4gPSByb3dTdW1zKHRhYmxlX2VjKSwgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIsIGNvcnJlY3Q9RkFMU0UpDQpjYXQoIlxuIikNCm9kZHNyYXRpbyh0YWJsZV9lYywgbWV0aG9kPSJ3YWxkIikNCmBgYA0KLT4gKipOaOG6rW4geMOpdDoqKiBU4bu3IGzhu4cgcuG7nWkgYuG7jyBj4bunYSBuaMOzbSBgRWxlY3Ryb25pYyBjaGVja2AgKDQ1LjMlKSBjYW8gaMahbiDEkcOhbmcga+G7gyBzbyB24bubaSBuaMOzbSBgQ3JlZGl0IGNhcmQgKGF1dG9tYXRpYylgICgxNS4yJSkuIE9kZHMgcuG7nWkgYuG7jyBj4bunYSBuaMOzbSBgRWxlY3Ryb25pYyBjaGVja2AgY2FvIGfhuqVwIDQuMDYgbOG6p24uDQoNCi0tLQ0KDQojIyAqKjMuNC4gUGjDom4gdMOtY2ggQ2h1cm4gdsOgIEludGVybmV0U2VydmljZSAoROG7i2NoIHbhu6UgSW50ZXJuZXQpKioNCg0KIyMjICoqMy40LjEuIELhuqNuZyB04bqnbiBz4buRKioNCmBgYHtyIHRhYmxlLWludGVybmV0LWNodXJufQ0KY2h1cm5faW50ZXJuZXRfdGFibGUgPC0gdGFibGUoZGZfY2xlYW4kSW50ZXJuZXRTZXJ2aWNlLCBkZl9jbGVhbiRDaHVybikNCmNhdCgiQuG6o25nIHThuqduIHPhu5EgY2jDqW86XG4iKQ0KYWRkbWFyZ2lucyhjaHVybl9pbnRlcm5ldF90YWJsZSkNCmBgYA0KDQojIyMgKiozLjQuMi4gS2nhu4NtIMSR4buLbmggQ2hpLWLDrG5oIHBoxrDGoW5nKioNCmBgYHtyIGNoaXNxLWludGVybmV0LWNodXJufQ0KcHJpbnQoY2hpc3EudGVzdChjaHVybl9pbnRlcm5ldF90YWJsZSkpDQpgYGANCi0+ICoqTmjhuq1uIHjDqXQ6KiogcC12YWx1ZSA8IDIuMmUtMTYuIELDoWMgYuG7jyBI4oKALiBDw7MgbeG7kWkgbGnDqm4gaOG7hyBy4bqldCBt4bqhbmguDQoNCiMjIyAqKjMuNC4zLiBIaeG7h3UgdOG7tyBs4buHIHbDoCBPUioqDQpgYGB7ciBvci1pbnRlcm5ldC1jaHVybn0NCmNhdCgiU28gc8OhbmggJ0ZpYmVyIG9wdGljJyB24bubaSAnRFNMJzpcbiIpDQpjYXQoIkjigoA6IFThu7cgbOG7hyBy4budaSBi4buPIGzDoCBuaMawIG5oYXUuXG4iKQ0KY2F0KCJI4oKBOiBU4bu3IGzhu4cgcuG7nWkgYuG7jyDhu58gbmjDs20gJ0ZpYmVyIG9wdGljJyBjYW8gaMahbi5cblxuIikNCg0KaW50ZXJuZXRfc3ViX2ZvIDwtIGRmX2NsZWFuICU+JSANCiAgZmlsdGVyKEludGVybmV0U2VydmljZSAlaW4lIGMoIkZpYmVyIG9wdGljIiwgIkRTTCIpKSAlPiUNCiAgZHJvcGxldmVscygpDQoNCnRhYmxlX2ZvIDwtIHRhYmxlKGludGVybmV0X3N1Yl9mbyRJbnRlcm5ldFNlcnZpY2UsIGludGVybmV0X3N1Yl9mbyRDaHVybikNCnByb3AudGVzdCh4ID0gdGFibGVfZm9bLCAiWWVzIl0sIG4gPSByb3dTdW1zKHRhYmxlX2ZvKSwgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIsIGNvcnJlY3Q9RkFMU0UpDQpjYXQoIlxuIikNCm9kZHNyYXRpbyh0YWJsZV9mbywgbWV0aG9kPSJ3YWxkIikNCmBgYA0KLT4gKipOaOG6rW4geMOpdDoqKiBU4bu3IGzhu4cgcuG7nWkgYuG7jyBj4bunYSBraMOhY2ggaMOgbmcgZMO5bmcgYEZpYmVyIG9wdGljYCAoNDEuOSUpIGNhbyBoxqFuIMSRw6FuZyBr4buDIHNvIHbhu5tpIGBEU0xgICgxOS4wJSkuIE9kZHMgcuG7nWkgYuG7jyBj4bunYSBo4buNIGNhbyBoxqFuIDMuMTQgbOG6p24uDQoNCi0tLQ0KDQojIyAqKjMuNS4gUGjDom4gdMOtY2ggQ2h1cm4gdsOgIHRlbnVyZSAoVGjhu51pIGdpYW4gZ+G6r24gYsOzKSoqDQoNCipMxrB1IMO9OiBWw6wgYHRlbnVyZWAgbMOgIGJp4bq/biDEkeG7i25oIGzGsOG7o25nLCBjaMO6bmcgdGEga2jDtG5nIGTDuW5nIGPDoWMga2nhu4NtIMSR4buLbmggY2hvIGJp4bq/biDEkeG7i25oIHTDrW5oLioNCg0KIyMjICoqMy41LjEuIFRo4buRbmcga8OqIG3DtCB04bqjKioNCmBgYHtyIHN1bW1hcnktdGVudXJlLWNodXJufQ0KdGVudXJlX3N1bW1hcnkgPC0gZGZfY2xlYW4gJT4lDQogIGdyb3VwX2J5KENodXJuKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lYW5fdGVudXJlID0gbWVhbih0ZW51cmUpLA0KICAgIG1lZGlhbl90ZW51cmUgPSBtZWRpYW4odGVudXJlKQ0KICApDQprYWJsZSh0ZW51cmVfc3VtbWFyeSwgY2FwdGlvbj0iVGjhu5FuZyBrw6ogJ3RlbnVyZScgdGhlbyAnQ2h1cm4nIikNCmBgYA0KDQojIyMgKiozLjUuMi4gQmnhu4N1IMSR4buTIGjhu5lwKioNCmBgYHtyIGJveHBsb3QtdGVudXJlLWNodXJufQ0KZ2dwbG90KGRmX2NsZWFuLCBhZXMoeCA9IENodXJuLCB5ID0gdGVudXJlLCBmaWxsID0gQ2h1cm4pKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgbGFicyh0aXRsZSA9ICJQaMOibiBwaOG7kWkgdGjhu51pIGdpYW4gZ+G6r24gYsOzICh0ZW51cmUpIHRoZW8gdHLhuqFuZyB0aMOhaSBy4budaSBi4buPIChDaHVybikiLA0KICAgICAgIHggPSAiVHLhuqFuZyB0aMOhaSBy4budaSBi4buPIiwgeSA9ICJUaOG7nWkgZ2lhbiBn4bqvbiBiw7MgKHRow6FuZykiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQotPiAqKk5o4bqtbiB4w6l0OioqIEtow6FjaCBow6BuZyBraMO0bmcgcuG7nWkgYuG7jyBjw7MgdGjhu51pIGdpYW4gZ+G6r24gYsOzIHRydW5nIGLDrG5oICgzNy42IHRow6FuZykgY2FvIGjGoW4gxJHDoW5nIGvhu4Mgc28gduG7m2kga2jDoWNoIGjDoG5nIMSRw6MgcuG7nWkgYuG7jyAoMTggdGjDoW5nKS4gVGjhu51pIGdpYW4gZ+G6r24gYsOzIGPDoG5nIG5n4bqvbiwgbmd1eSBjxqEga2jDoWNoIGjDoG5nIHLhu51pIGLhu48gY8OgbmcgY2FvLg0KDQotLS0NCg0KIyAqKkNIxq/GoE5HIDQ6IE3DlCBIw4xOSCBI4buSSSBRVVkgxJDGoE4gQknhur5OKioNCg0KIyMgKio0LjEuIFTDoWMgxJHhu5luZyBj4bunYSBgQ29udHJhY3RgIChMb+G6oWkgaOG7o3AgxJHhu5NuZykgxJHhur9uIGBDaHVybmAqKg0KDQojIyMgKio0LjEuMS4gTcO0IGjDrG5oIFjDoWMgc3XhuqV0IFR1eeG6v24gdMOtbmggKExQTSkqKg0KYGBge3IgbHBtLWNvbnRyYWN0LXNpbmdsZX0NCmxwbV9jb250cmFjdCA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gQ29udHJhY3QsIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gZ2F1c3NpYW4obGluayA9ICJpZGVudGl0eSIpKQ0Kc3VtbWFyeShscG1fY29udHJhY3QpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpU4burIGLhuqNuZyBr4bq/dCBxdeG6oywgdGEgY8OzIHBoxrDGoW5nIHRyw6xuaCBo4buTaSBxdXkgxrDhu5tjIGzGsOG7o25nOg0KYM+AzIIgPSAwLjQyNzEgLSAwLjMxNDQgKiBDb250cmFjdE9uZSB5ZWFyIC0gMC4zOTg2ICogQ29udHJhY3RUd28geWVhcmANCg0KVHJvbmcgxJHDszoNCi0gKipI4buHIHPhu5EgYENvbnRyYWN0T25lIHllYXJgICgtMC4zMTQ0KToqKiBTbyB24bubaSBo4bujcCDEkeG7k25nIHRow6FuZywgdmnhu4djIGvDvSBo4bujcCDEkeG7k25nIDEgbsSDbSBsw6BtICoqZ2nhuqNtIHjDoWMgc3XhuqV0IHLhu51pIGLhu48gdHJ1bmcgYsOsbmggbMOgIDMxLjQlKiouDQotICoqSOG7hyBz4buRIGBDb250cmFjdFR3byB5ZWFyYCAoLTAuMzk4Nik6KiogU28gduG7m2kgaOG7o3AgxJHhu5NuZyB0aMOhbmcsIHZp4buHYyBrw70gaOG7o3AgxJHhu5NuZyAyIG7Eg20gbMOgbSAqKmdp4bqjbSB4w6FjIHN14bqldCBy4budaSBi4buPIHRydW5nIGLDrG5oIGzDoCAzOS45JSoqLg0KDQoqKkvhur90IGx14bqtbjoqKiBNw7QgaMOsbmggY2hvIHRo4bqleSBo4bujcCDEkeG7k25nIGTDoGkgaOG6oW4gY8OzIHTDoWMgxJHhu5luZyBy4bqldCBs4bubbiB0cm9uZyB2aeG7h2MgZ2nhuqNtIHjDoWMgc3XhuqV0IGtow6FjaCBow6BuZyBy4budaSBi4buPLg0KDQojIyMgKio0LjEuMi4gTcO0IGjDrG5oIExvZ2l0IChDb250cmFjdCkqKg0KYGBge3IgbG9naXQtY29udHJhY3Qtc2luZ2xlfQ0KbG9naXRfY29udHJhY3QgPC0gZ2xtKENodXJuX2JpbmFyeSB+IENvbnRyYWN0LCBkYXRhID0gZGZfY2xlYW4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSkNCnN1bW1hcnkobG9naXRfY29udHJhY3QpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpU4burIGLhuqNuZyBr4bq/dCBxdeG6oywgdGEgY8OzIHBoxrDGoW5nIHRyw6xuaCBo4buTaSBxdXkgTG9naXQgxrDhu5tjIGzGsOG7o25nOg0KYGxvZyhvZGRzKSA9IC0wLjI5NzMgLSAxLjQ3MDQgKiBDb250cmFjdE9uZSB5ZWFyIC0gMi44MzMwICogQ29udHJhY3RUd28geWVhcmANCg0KVHJvbmcgxJHDszoNCi0gKipI4buHIHPhu5EgYENvbnRyYWN0T25lIHllYXJgICgtMS40NzA0KToqKiBLaGkgY8OhYyB54bq/dSB04buRIGtow6FjIGtow7RuZyDEkeG7lWksIG9kZHMgcuG7nWkgYuG7jyBj4bunYSBraMOhY2ggaMOgbmcgY8OzIGjhu6NwIMSR4buTbmcgMSBuxINtIGNo4buJIGLhurFuZyBgZXhwKC0xLjQ3MDQpYCDiiYggMC4yMyBs4bqnbiAodOG7qWMgdGjhuqVwIGjGoW4gNzclKSBzbyB24bubaSBraMOhY2ggaMOgbmcgY8OzIGjhu6NwIMSR4buTbmcgdGjDoW5nLg0KLSAqKkjhu4cgc+G7kSBgQ29udHJhY3RUd28geWVhcmAgKC0yLjgzMzApOioqIFTGsMahbmcgdOG7sSwgb2RkcyBy4budaSBi4buPIGPhu6dhIGtow6FjaCBow6BuZyBjw7MgaOG7o3AgxJHhu5NuZyAyIG7Eg20gY2jhu4kgYuG6sW5nIGBleHAoLTIuODMzMClgIOKJiCAwLjA2IGzhuqduICh04bupYyB0aOG6pXAgaMahbiA5NCUpIHNvIHbhu5tpIGjhu6NwIMSR4buTbmcgdGjDoW5nLg0KDQoqKkvhur90IGx14bqtbjoqKiBNw7QgaMOsbmggTG9naXQgY+G7p25nIGPhu5EgcuG6sW5nIGjhu6NwIMSR4buTbmcgZMOgaSBo4bqhbiBsw6AgeeG6v3UgdOG7kSBnaeG7ryBjaMOibiBraMOhY2ggaMOgbmcgY+G7sWMga+G7syBoaeG7h3UgcXXhuqMsIHbhu5tpIHTDoWMgxJHhu5luZyBt4bqhbmggaMahbiDhu58gaOG7o3AgxJHhu5NuZyAyIG7Eg20uDQoNCiMjIyAqKjQuMS4zLiBNw7QgaMOsbmggUHJvYml0IChDb250cmFjdCkqKg0KYGBge3IgcHJvYml0LWNvbnRyYWN0LXNpbmdsZX0NCnByb2JpdF9jb250cmFjdCA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gQ29udHJhY3QsIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJwcm9iaXQiKSkNCnN1bW1hcnkocHJvYml0X2NvbnRyYWN0KQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBQcm9iaXQgxrDhu5tjIGzGsOG7o25nOg0KYM6m4oG7wrkoz4ApID0gLTAuMTgzNyAtIDAuODY0NyAqIENvbnRyYWN0T25lIHllYXIgLSAxLjY1MjEgKiBDb250cmFjdFR3byB5ZWFyYA0KDQpUcm9uZyDEkcOzOg0KLSAqKkjhu4cgc+G7kSBgQ29udHJhY3RPbmUgeWVhcmAgKC0wLjg2NDcpOioqIFZp4buHYyBjaHV54buDbiB04burIGjhu6NwIMSR4buTbmcgdGjDoW5nIHNhbmcgaOG7o3AgxJHhu5NuZyAxIG7Eg20gbMOgbSBnaeG6o20gWi1zY29yZSAoY2jhu4kgc+G7kSB4w6FjIHN14bqldCBy4budaSBi4buPKSDEkWkgMC44NjQ3IMSRxqFuIHbhu4suDQotICoqSOG7hyBz4buRIGBDb250cmFjdFR3byB5ZWFyYCAoLTEuNjUyMSk6KiogVmnhu4djIGNodXnhu4NuIHNhbmcgaOG7o3AgxJHhu5NuZyAyIG7Eg20gbMOgbSBnaeG6o20gWi1zY29yZSDEkWkgMS42NTIxIMSRxqFuIHbhu4suDQoNCioqS+G6v3QgbHXhuq1uOioqIE3DtCBow6xuaCBQcm9iaXQgY2hvIGvhur90IHF14bqjIG5o4bqldCBxdcOhbiwga2jhurNuZyDEkeG7i25oIHLhurFuZyB4w6FjIHN14bqldCBy4budaSBi4buPIGPhu6dhIGtow6FjaCBow6BuZyBnaeG6o20gbeG6oW5oIGtoaSBo4buNIGNhbSBr4bq/dCBo4bujcCDEkeG7k25nIGTDoGkgaOG6oW4uDQoNCiMjIyAqKjQuMS40LiBNw7QgaMOsbmggQ2xvZ2xvZyAoQ29udHJhY3QpKioNCmBgYHtyIGNsb2dsb2ctY29udHJhY3Qtc2luZ2xlfQ0KY2xvZ2xvZ19jb250cmFjdCA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gQ29udHJhY3QsIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJjbG9nbG9nIikpDQpzdW1tYXJ5KGNsb2dsb2dfY29udHJhY3QpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpQaMawxqFuZyB0csOsbmggaOG7k2kgcXV5IENsb2dsb2cgxrDhu5tjIGzGsOG7o25nOg0KYGxvZygtbG9nKDEtz4ApKSA9IC0wLjYzODUgLSAxLjE5MjUgKiBDb250cmFjdE9uZSB5ZWFyIC0gMi4yMTg1ICogQ29udHJhY3RUd28geWVhcmANCg0KVHJvbmcgxJHDszoNCi0gKipI4buHIHPhu5EgYENvbnRyYWN0T25lIHllYXJgICgtMS4xOTI1KToqKiBMb2ctaGF6YXJkIChuZ3V5IGPGoSkgcuG7nWkgYuG7jyBj4bunYSBuaMOzbSBo4bujcCDEkeG7k25nIDEgbsSDbSB0aOG6pXAgaMahbiBzbyB24bubaSBo4bujcCDEkeG7k25nIHRow6FuZy4NCi0gKipI4buHIHPhu5EgYENvbnRyYWN0VHdvIHllYXJgICgtMi4yMTg1KToqKiBMb2ctaGF6YXJkIHLhu51pIGLhu48gY+G7p2EgbmjDs20gaOG7o3AgxJHhu5NuZyAyIG7Eg20gY8OybiB0aOG6pXAgaMahbiBu4buvYS4NCg0KKipL4bq/dCBsdeG6rW46KiogTcO0IGjDrG5oIENsb2dsb2cgdGnhur9wIHThu6VjIGPhu6duZyBj4buRIHLhurFuZyBo4bujcCDEkeG7k25nIGTDoGkgaOG6oW4gbMOgbSBnaeG6o20gxJHDoW5nIGvhu4Mgbmd1eSBjxqEgcuG7nWkgYuG7jy4NCg0KLS0tDQoNCiMjICoqNC4yLiBUw6FjIMSR4buZbmcgY+G7p2EgYFNlbmlvckNpdGl6ZW5gIChOZ8aw4budaSBjYW8gdHXhu5VpKSDEkeG6v24gYENodXJuYCoqDQoNCiMjIyAqKjQuMi4xLiBNw7QgaMOsbmggWMOhYyBzdeG6pXQgVHV54bq/biB0w61uaCAoTFBNKSoqDQpgYGB7ciBscG0tc2VuaW9yLXNpbmdsZX0NCmxwbV9zZW5pb3IgPC0gZ2xtKENodXJuX2JpbmFyeSB+IFNlbmlvckNpdGl6ZW4sIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gZ2F1c3NpYW4obGluayA9ICJpZGVudGl0eSIpKQ0Kc3VtbWFyeShscG1fc2VuaW9yKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBMUE0gxrDhu5tjIGzGsOG7o25nOg0KYM+AzIIgPSAwLjIzNjEgKyAwLjE4MDQgKiBTZW5pb3JDaXRpemVuWWVzYA0KDQotICoqSOG7hyBz4buRIGBTZW5pb3JDaXRpemVuWWVzYCAoMC4xODA0KToqKiBLaMOhY2ggaMOgbmcgbMOgIG5nxrDhu51pIGNhbyB0deG7lWkgY8OzIHjDoWMgc3XhuqV0IHLhu51pIGLhu48gY2FvIGjGoW4gdHJ1bmcgYsOsbmggbMOgIDE4JSBzbyB24bubaSBraMOhY2ggaMOgbmcga2jDtG5nIHBo4bqjaSBuZ8aw4budaSBjYW8gdHXhu5VpLg0KDQojIyMgKio0LjIuMi4gTcO0IGjDrG5oIExvZ2l0IChTZW5pb3JDaXRpemVuKSoqDQpgYGB7ciBsb2dpdC1zZW5pb3Itc2luZ2xlfQ0KbG9naXRfc2VuaW9yIDwtIGdsbShDaHVybl9iaW5hcnkgfiBTZW5pb3JDaXRpemVuLCBkYXRhID0gZGZfY2xlYW4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSkNCnN1bW1hcnkobG9naXRfc2VuaW9yKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBMb2dpdCDGsOG7m2MgbMaw4bujbmc6DQpgbG9nKG9kZHMpID0gLTEuMTcxNCArIDAuNzMwMyAqIFNlbmlvckNpdGl6ZW5ZZXNgDQoNCi0gKipI4buHIHPhu5EgYFNlbmlvckNpdGl6ZW5ZZXNgICgwLjczMDMpOioqIE9kZHMgcuG7nWkgYuG7jyBj4bunYSBraMOhY2ggaMOgbmcgY2FvIHR14buVaSBjYW8gaMahbiBgZXhwKDAuNzMwMylgIOKJiCAyLjA4IGzhuqduIHNvIHbhu5tpIG5nxrDhu51pIGtow7RuZyBwaOG6o2kgY2FvIHR14buVaS4NCg0KIyMjICoqNC4yLjMuIE3DtCBow6xuaCBQcm9iaXQgKFNlbmlvckNpdGl6ZW4pKioNCmBgYHtyIHByb2JpdC1zZW5pb3Itc2luZ2xlfQ0KcHJvYml0X3NlbmlvciA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gU2VuaW9yQ2l0aXplbiwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gInByb2JpdCIpKQ0Kc3VtbWFyeShwcm9iaXRfc2VuaW9yKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBQcm9iaXQgxrDhu5tjIGzGsOG7o25nOg0KYM6m4oG7wrkoz4ApID0gLTAuNzE4OCArIDAuNDM3NiAqIFNlbmlvckNpdGl6ZW5ZZXNgDQoNCi0gKipI4buHIHPhu5EgYFNlbmlvckNpdGl6ZW5ZZXNgICgwLjQzNzYpOioqIFZp4buHYyBsw6AgbmfGsOG7nWkgY2FvIHR14buVaSBsw6BtIHTEg25nIFotc2NvcmUgKGNo4buJIHPhu5EgeMOhYyBzdeG6pXQgcuG7nWkgYuG7jykgbMOqbiAwLjQzNzYgxJHGoW4gduG7iy4NCg0KIyMjICoqNC4yLjQuIE3DtCBow6xuaCBDbG9nbG9nIChTZW5pb3JDaXRpemVuKSoqDQpgYGB7ciBjbG9nbG9nLXNlbmlvci1zaW5nbGV9DQpjbG9nbG9nX3NlbmlvciA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gU2VuaW9yQ2l0aXplbiwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImNsb2dsb2ciKSkNCnN1bW1hcnkoY2xvZ2xvZ19zZW5pb3IpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpQaMawxqFuZyB0csOsbmggaOG7k2kgcXV5IENsb2dsb2cgxrDhu5tjIGzGsOG7o25nOg0KYGxvZygtbG9nKDEtz4ApKSA9IC0xLjM0OTkgKyAwLjU4MjIgKiBTZW5pb3JDaXRpemVuWWVzYA0KDQotICoqSOG7hyBz4buRIGBTZW5pb3JDaXRpemVuWWVzYCAoMC41ODIyKToqKiBMb2ctaGF6YXJkIHLhu51pIGLhu48gY+G7p2EgbmfGsOG7nWkgY2FvIHR14buVaSBjYW8gaMahbiBzbyB24bubaSBuZ8aw4budaSBraMO0bmcgcGjhuqNpIGNhbyB0deG7lWkuDQoNCi0tLQ0KDQojIyAqKjQuMy4gVMOhYyDEkeG7mW5nIGPhu6dhIGBQYXltZW50TWV0aG9kYCAoUGjGsMahbmcgdGjhu6ljIHRoYW5oIHRvw6FuKSDEkeG6v24gYENodXJuYCoqDQoNCiMjIyAqKjQuMy4xLiBNw7QgaMOsbmggWMOhYyBzdeG6pXQgVHV54bq/biB0w61uaCAoTFBNKSoqDQpgYGB7ciBscG0tcGF5bWVudC1zaW5nbGV9DQpscG1fcGF5bWVudCA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gUGF5bWVudE1ldGhvZCwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBnYXVzc2lhbihsaW5rID0gImlkZW50aXR5IikpDQpzdW1tYXJ5KGxwbV9wYXltZW50KQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBMUE0gxrDhu5tjIGzGsOG7o25nICht4bupYyBjxqEgc+G7nzogQmFuayB0cmFuc2Zlcik6DQpgz4DMgiA9IDAuMTY3MyAtIDAuMDE0MiAqIENyZWRpdCBjYXJkICsgMC4yNTkyICogRWxlY3Ryb25pYyBjaGVjayArIDAuMDI0MyAqIE1haWxlZCBjaGVja2ANCg0KLSAqKkjhu4cgc+G7kSBgUGF5bWVudE1ldGhvZEVsZWN0cm9uaWMgY2hlY2tgICgwLjI1OTIpOioqIEtow6FjaCBow6BuZyBkw7luZyBzw6ljIMSRaeG7h24gdOG7rSBjw7MgeMOhYyBzdeG6pXQgcuG7nWkgYuG7jyBjYW8gaMahbiAyNS45JSBzbyB24bubaSBraMOhY2ggaMOgbmcgY2h1eeG7g24ga2hv4bqjbiB04buxIMSR4buZbmcuDQoNCiMjIyAqKjQuMy4yLiBNw7QgaMOsbmggTG9naXQgKFBheW1lbnRNZXRob2QpKioNCmBgYHtyIGxvZ2l0LXBheW1lbnQtc2luZ2xlfQ0KbG9naXRfcGF5bWVudCA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gUGF5bWVudE1ldGhvZCwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IikpDQpzdW1tYXJ5KGxvZ2l0X3BheW1lbnQpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpQaMawxqFuZyB0csOsbmggaOG7k2kgcXV5IExvZ2l0IMaw4bubYyBsxrDhu6NuZyAobeG7qWMgY8ahIHPhu586IEJhbmsgdHJhbnNmZXIpOg0KYGxvZyhvZGRzKSA9IC0xLjc4OTkgLSAwLjIyMjYgKiBDcmVkaXQgY2FyZCArIDEuMzczNCAqIEVsZWN0cm9uaWMgY2hlY2sgLSAwLjA5MTEgKiBNYWlsZWQgY2hlY2tgDQoNCi0gKipI4buHIHPhu5EgYFBheW1lbnRNZXRob2RFbGVjdHJvbmljIGNoZWNrYCAoMS4zNzM0KToqKiBPZGRzIHLhu51pIGLhu48gY+G7p2Ega2jDoWNoIGjDoG5nIGTDuW5nIHPDqWMgxJFp4buHbiB04butIGNhbyBoxqFuIGBleHAoMS4zNzM0KWAg4omIIDMuOTUgbOG6p24gc28gduG7m2kgY2h1eeG7g24ga2hv4bqjbiB04buxIMSR4buZbmcuDQoNCiMjIyAqKjQuMy4zLiBNw7QgaMOsbmggUHJvYml0IChQYXltZW50TWV0aG9kKSoqDQpgYGB7ciBwcm9iaXQtcGF5bWVudC1zaW5nbGV9DQpwcm9iaXRfcGF5bWVudCA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gUGF5bWVudE1ldGhvZCwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gInByb2JpdCIpKQ0Kc3VtbWFyeShwcm9iaXRfcGF5bWVudCkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNClBoxrDGoW5nIHRyw6xuaCBo4buTaSBxdXkgUHJvYml0IMaw4bubYyBsxrDhu6NuZyAobeG7qWMgY8ahIHPhu586IEJhbmsgdHJhbnNmZXIpOg0KYM6m4oG7wrkoz4ApID0gLTAuOTY0OSAtIDAuMTI1MSAqIENyZWRpdCBjYXJkICsgMC44MDM3ICogRWxlY3Ryb25pYyBjaGVjayAtIDAuMDQ2MyAqIE1haWxlZCBjaGVja2ANCg0KLSAqKkjhu4cgc+G7kSBgUGF5bWVudE1ldGhvZEVsZWN0cm9uaWMgY2hlY2tgICgwLjgwMzcpOioqIFZp4buHYyB0aGFuaCB0b8OhbiBi4bqxbmcgc8OpYyDEkWnhu4duIHThu60gbMOgbSB0xINuZyBaLXNjb3JlICh4w6FjIHN14bqldCBy4budaSBi4buPKSBsw6puIDAuODAzNyDEkcahbiB24buLIHNvIHbhu5tpIGNodXnhu4NuIGtob+G6o24uDQoNCiMjIyAqKjQuMy40LiBNw7QgaMOsbmggQ2xvZ2xvZyAoUGF5bWVudE1ldGhvZCkqKg0KYGBge3IgY2xvZ2xvZy1wYXltZW50LXNpbmdsZX0NCmNsb2dsb2dfcGF5bWVudCA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gUGF5bWVudE1ldGhvZCwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImNsb2dsb2ciKSkNCnN1bW1hcnkoY2xvZ2xvZ19wYXltZW50KQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBDbG9nbG9nIMaw4bubYyBsxrDhu6NuZyAobeG7qWMgY8ahIHPhu586IEJhbmsgdHJhbnNmZXIpOg0KYGxvZygtbG9nKDEtz4ApKSA9IC0xLjYxNDYgLSAwLjE2OTEgKiBDcmVkaXQgY2FyZCArIDEuMDgzMiAqIEVsZWN0cm9uaWMgY2hlY2sgLSAwLjA2MzEgKiBNYWlsZWQgY2hlY2tgDQoNCi0gKipI4buHIHPhu5EgYFBheW1lbnRNZXRob2RFbGVjdHJvbmljIGNoZWNrYCAoMS4wODMyKToqKiBMb2ctaGF6YXJkIHLhu51pIGLhu48gY+G7p2EgbmjDs20gZMO5bmcgc8OpYyDEkWnhu4duIHThu60gY2FvIGjGoW4gxJHDoW5nIGvhu4Mgc28gduG7m2kgbmjDs20gY2h1eeG7g24ga2hv4bqjbi4NCg0KLS0tDQoNCiMjICoqNC40LiBUw6FjIMSR4buZbmcgY+G7p2EgYEludGVybmV0U2VydmljZWAgKEThu4tjaCB24bulIEludGVybmV0KSDEkeG6v24gYENodXJuYCoqDQoNCiMjIyAqKjQuNC4xLiBNw7QgaMOsbmggWMOhYyBzdeG6pXQgVHV54bq/biB0w61uaCAoTFBNKSoqDQpgYGB7ciBscG0taW50ZXJuZXQtc2luZ2xlfQ0KbHBtX2ludGVybmV0IDwtIGdsbShDaHVybl9iaW5hcnkgfiBJbnRlcm5ldFNlcnZpY2UsIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gZ2F1c3NpYW4obGluayA9ICJpZGVudGl0eSIpKQ0Kc3VtbWFyeShscG1faW50ZXJuZXQpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpQaMawxqFuZyB0csOsbmggaOG7k2kgcXV5IExQTSDGsOG7m2MgbMaw4bujbmcgKG3hu6ljIGPGoSBz4bufOiBEU0wpOg0KYM+AzIIgPSAwLjE4OTYgKyAwLjIyOTEgKiBGaWJlciBvcHRpYyAtIDAuMTE3MCAqIE5vYA0KDQotICoqSOG7hyBz4buRIGBJbnRlcm5ldFNlcnZpY2VGaWJlciBvcHRpY2AgKDAuMjI5MSk6KiogS2jDoWNoIGjDoG5nIGTDuW5nIGPDoXAgcXVhbmcgY8OzIHjDoWMgc3XhuqV0IHLhu51pIGLhu48gY2FvIGjGoW4gMjIuOSUgc28gduG7m2kgZMO5bmcgRFNMLg0KLSAqKkjhu4cgc+G7kSBgSW50ZXJuZXRTZXJ2aWNlTm9gICgtMC4xMTcwKToqKiBLaMOhY2ggaMOgbmcga2jDtG5nIGPDsyBJbnRlcm5ldCBjw7MgeMOhYyBzdeG6pXQgcuG7nWkgYuG7jyB0aOG6pXAgaMahbiAxMS43JSBzbyB24bubaSBkw7luZyBEU0wuDQoNCiMjIyAqKjQuNC4yLiBNw7QgaMOsbmggTG9naXQgKEludGVybmV0U2VydmljZSkqKg0KYGBge3IgbG9naXQtaW50ZXJuZXQtc2luZ2xlfQ0KbG9naXRfaW50ZXJuZXQgPC0gZ2xtKENodXJuX2JpbmFyeSB+IEludGVybmV0U2VydmljZSwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IikpDQpzdW1tYXJ5KGxvZ2l0X2ludGVybmV0KQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBMb2dpdCDGsOG7m2MgbMaw4bujbmcgKG3hu6ljIGPGoSBz4bufOiBEU0wpOg0KYGxvZyhvZGRzKSA9IC0xLjQzMjggKyAwLjc2MTAgKiBGaWJlciBvcHRpYyAtIDEuODAzNyAqIE5vYA0KDQotICoqSOG7hyBz4buRIGBJbnRlcm5ldFNlcnZpY2VGaWJlciBvcHRpY2AgKDAuNzYxMCk6KiogT2RkcyBy4budaSBi4buPIGPhu6dhIGtow6FjaCBow6BuZyBkw7luZyBjw6FwIHF1YW5nIGNhbyBoxqFuIGBleHAoMC43NjEwKWAg4omIIDIuMTQgbOG6p24gc28gduG7m2kgZMO5bmcgRFNMLg0KLSAqKkjhu4cgc+G7kSBgSW50ZXJuZXRTZXJ2aWNlTm9gICgtMS44MDM3KToqKiBPZGRzIHLhu51pIGLhu48gY+G7p2Ega2jDoWNoIGjDoG5nIGtow7RuZyBkw7luZyBJbnRlcm5ldCBjaOG7iSBi4bqxbmcgYGV4cCgtMS44MDM3KWAg4omIIDAuMTYgbOG6p24gc28gduG7m2kgZMO5bmcgRFNMLg0KDQojIyMgKio0LjQuMy4gTcO0IGjDrG5oIFByb2JpdCAoSW50ZXJuZXRTZXJ2aWNlKSoqDQpgYGB7ciBwcm9iaXQtaW50ZXJuZXQtc2luZ2xlfQ0KcHJvYml0X2ludGVybmV0IDwtIGdsbShDaHVybl9iaW5hcnkgfiBJbnRlcm5ldFNlcnZpY2UsIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJwcm9iaXQiKSkNCnN1bW1hcnkocHJvYml0X2ludGVybmV0KQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBQcm9iaXQgxrDhu5tjIGzGsOG7o25nICht4bupYyBjxqEgc+G7nzogRFNMKToNCmDOpuKBu8K5KM+AKSA9IC0wLjg3NzAgKyAwLjQ0MTEgKiBGaWJlciBvcHRpYyAtIDEuMDc3MiAqIE5vYA0KDQotICoqSOG7hyBz4buRIGBJbnRlcm5ldFNlcnZpY2VGaWJlciBvcHRpY2AgKDAuNDQxMSk6KiogWi1zY29yZSBy4budaSBi4buPIGPhu6dhIG5ow7NtIGPDoXAgcXVhbmcgY2FvIGjGoW4gMC40NDExIMSRxqFuIHbhu4sgc28gduG7m2kgRFNMLg0KLSAqKkjhu4cgc+G7kSBgSW50ZXJuZXRTZXJ2aWNlTm9gICgtMS4wNzcyKToqKiBaLXNjb3JlIHLhu51pIGLhu48gY+G7p2EgbmjDs20ga2jDtG5nIGTDuW5nIEludGVybmV0IHRo4bqlcCBoxqFuIDEuMDc3MiDEkcahbiB24buLIHNvIHbhu5tpIERTTC4NCg0KIyMjICoqNC40LjQuIE3DtCBow6xuaCBDbG9nbG9nIChJbnRlcm5ldFNlcnZpY2UpKioNCmBgYHtyIGNsb2dsb2ctaW50ZXJuZXQtc2luZ2xlfQ0KY2xvZ2xvZ19pbnRlcm5ldCA8LSBnbG0oQ2h1cm5fYmluYXJ5IH4gSW50ZXJuZXRTZXJ2aWNlLCBkYXRhID0gZGZfY2xlYW4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAiY2xvZ2xvZyIpKQ0Kc3VtbWFyeShjbG9nbG9nX2ludGVybmV0KQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBDbG9nbG9nIMaw4bubYyBsxrDhu6NuZyAobeG7qWMgY8ahIHPhu586IERTTCk6DQpgbG9nKC1sb2coMS3PgCkpID0gLTEuNTMwMyArIDAuNjE5MCAqIEZpYmVyIG9wdGljIC0gMS40NzQ2ICogTm9gDQoNCi0gKipI4buHIHPhu5EgYEludGVybmV0U2VydmljZUZpYmVyIG9wdGljYCAoMC42MTkwKToqKiBMb2ctaGF6YXJkIHLhu51pIGLhu48gY+G7p2EgbmjDs20gY8OhcCBxdWFuZyBjYW8gaMahbiBzbyB24bubaSBEU0wuDQotICoqSOG7hyBz4buRIGBJbnRlcm5ldFNlcnZpY2VOb2AgKC0xLjQ3NDYpOioqIExvZy1oYXphcmQgcuG7nWkgYuG7jyBj4bunYSBuaMOzbSBraMO0bmcgZMO5bmcgSW50ZXJuZXQgdGjhuqVwIGjGoW4gxJHDoW5nIGvhu4Mgc28gduG7m2kgRFNMLg0KDQotLS0NCg0KIyMgKio0LjUuIFTDoWMgxJHhu5luZyBj4bunYSBgdGVudXJlYCAoVGjhu51pIGdpYW4gZ+G6r24gYsOzKSDEkeG6v24gYENodXJuYCoqDQoNCiMjIyAqKjQuNS4xLiBNw7QgaMOsbmggWMOhYyBzdeG6pXQgVHV54bq/biB0w61uaCAoTFBNKSoqDQpgYGB7ciBscG0tdGVudXJlLXNpbmdsZX0NCmxwbV90ZW51cmUgPC0gZ2xtKENodXJuX2JpbmFyeSB+IHRlbnVyZSwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBnYXVzc2lhbihsaW5rID0gImlkZW50aXR5IikpDQpzdW1tYXJ5KGxwbV90ZW51cmUpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpQaMawxqFuZyB0csOsbmggaOG7k2kgcXV5IExQTSDGsOG7m2MgbMaw4bujbmc6DQpgz4DMgiA9IDAuNDE2OCAtIDAuMDA0NyAqIHRlbnVyZWANCg0KLSAqKkjhu4cgc+G7kSBgdGVudXJlYCAoLTAuMDA0Nyk6KiogQ+G7qSBt4buXaSB0aMOhbmcga2jDoWNoIGjDoG5nIGfhuq9uIGLDsyB0aMOqbSwgeMOhYyBzdeG6pXQgaOG7jSBy4budaSBi4buPIGThu4tjaCB24bulIGdp4bqjbSDEkWkgdHJ1bmcgYsOsbmggbMOgIDAuNDclLg0KDQojIyMgKio0LjUuMi4gTcO0IGjDrG5oIExvZ2l0ICh0ZW51cmUpKioNCmBgYHtyIGxvZ2l0LXRlbnVyZS1zaW5nbGV9DQpsb2dpdF90ZW51cmUgPC0gZ2xtKENodXJuX2JpbmFyeSB+IHRlbnVyZSwgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IikpDQpzdW1tYXJ5KGxvZ2l0X3RlbnVyZSkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNClBoxrDGoW5nIHRyw6xuaCBo4buTaSBxdXkgTG9naXQgxrDhu5tjIGzGsOG7o25nOg0KYGxvZyhvZGRzKSA9IC0wLjMyMDAgLSAwLjAzNDMgKiB0ZW51cmVgDQoNCi0gKipI4buHIHPhu5EgYHRlbnVyZWAgKC0wLjAzNDMpOioqIE3hu5dpIHRow6FuZyBn4bqvbiBiw7MgdGjDqm0gbMOgbSBnaeG6o20gbG9nLW9kZHMgcuG7nWkgYuG7jyDEkWkgMC4wMzQzLiBPZGRzIHLhu51pIGLhu48gZ2nhuqNtIGtob+G6o25nIDMuNCUgKGAxIC0gZXhwKC0wLjAzNDMpYCkgY2hvIG3hu5dpIHRow6FuZyB0xINuZyB0aMOqbS4NCg0KIyMjICoqNC41LjMuIE3DtCBow6xuaCBQcm9iaXQgKHRlbnVyZSkqKg0KYGBge3IgcHJvYml0LXRlbnVyZS1zaW5nbGV9DQpwcm9iaXRfdGVudXJlIDwtIGdsbShDaHVybl9iaW5hcnkgfiB0ZW51cmUsIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJwcm9iaXQiKSkNCnN1bW1hcnkocHJvYml0X3RlbnVyZSkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNClBoxrDGoW5nIHRyw6xuaCBo4buTaSBxdXkgUHJvYml0IMaw4bubYyBsxrDhu6NuZzoNCmDOpuKBu8K5KM+AKSA9IC0wLjE5ODMgLSAwLjAxOTQgKiB0ZW51cmVgDQoNCi0gKipI4buHIHPhu5EgYHRlbnVyZWAgKC0wLjAxOTQpOioqIE3hu5dpIHRow6FuZyBn4bqvbiBiw7MgdGjDqm0gbMOgbSBnaeG6o20gWi1zY29yZSBy4budaSBi4buPIMSRaSAwLjAxOTQgxJHGoW4gduG7iy4NCg0KIyMjICoqNC41LjQuIE3DtCBow6xuaCBDbG9nbG9nICh0ZW51cmUpKioNCmBgYHtyIGNsb2dsb2ctdGVudXJlLXNpbmdsZX0NCmNsb2dsb2dfdGVudXJlIDwtIGdsbShDaHVybl9iaW5hcnkgfiB0ZW51cmUsIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJjbG9nbG9nIikpDQpzdW1tYXJ5KGNsb2dsb2dfdGVudXJlKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBDbG9nbG9nIMaw4bubYyBsxrDhu6NuZzoNCmBsb2coLWxvZygxLc+AKSkgPSAtMC43MzAzIC0gMC4wMjYxICogdGVudXJlYA0KDQotICoqSOG7hyBz4buRIGB0ZW51cmVgICgtMC4wMjYxKToqKiBN4buXaSB0aMOhbmcgZ+G6r24gYsOzIHRow6ptIGzDoG0gZ2nhuqNtIGxvZy1oYXphcmQgcuG7nWkgYuG7jyDEkWkgMC4wMjYxIMSRxqFuIHbhu4suDQoNCi0tLQ0KDQojICoqUEjhuqZOIDU6IE3DlCBIw4xOSCBI4buSSSBRVVkgQuG7mEkqKg0KDQojIyAqKjUuMS4gTcO0IGjDrG5oIFjDoWMgc3XhuqV0IFR1eeG6v24gdMOtbmggKExQTSkgQuG7mWkqKg0KYGBge3IgbXVsdGktbHBtfQ0KbHBtX211bHRpIDwtIGdsbShDaHVybl9iaW5hcnkgfiBDb250cmFjdCArIFNlbmlvckNpdGl6ZW4gKyBQYXltZW50TWV0aG9kICsgSW50ZXJuZXRTZXJ2aWNlICsgdGVudXJlLA0KICAgICAgICAgICAgICAgICBkYXRhID0gZGZfY2xlYW4sIGZhbWlseSA9IGdhdXNzaWFuKQ0Kc3VtbWFyeShscG1fbXVsdGkpDQpgYGANCg0KKipOaOG6rW4geMOpdDoqKg0KDQpU4burIGLhuqNuZyBr4bq/dCBxdeG6oywgdGEgY8OzIHBoxrDGoW5nIHRyw6xuaCBo4buTaSBxdXkgxrDhu5tjIGzGsOG7o25nOg0KYM+AzIIgPSAwLjMxMjMgLSAwLjE3MDIqQ29udHJhY3RPbmUgeWVhciAtIDAuMzQ3MypDb250cmFjdFR3byB5ZWFyICsgMC4wMzQzKlNlbmlvckNpdGl6ZW5ZZXMgLi4uIC0gMC4wMDQxKnRlbnVyZWANCg0KVHJvbmcgxJHDszoNCi0gKipI4buHIHPhu5EgYHRlbnVyZWAgKC0wLjAwNDEpOioqIEtoaSBraeG7g20gc2/DoXQgY8OhYyB54bq/dSB04buRIGtow6FjLCBt4buXaSB0aMOhbmcgZ+G6r24gYsOzIHRow6ptIGzDoG0gZ2nhuqNtIHjDoWMgc3XhuqV0IHLhu51pIGLhu48gxJFpIDAuNDElLg0KLSAqKkjhu4cgc+G7kSBgQ29udHJhY3RUd28geWVhcmAgKC0wLjM0NzMpOioqIEdp4buvIGPDoWMgYmnhur9uIGtow6FjIGtow7RuZyDEkeG7lWksIGtow6FjaCBow6BuZyBjw7MgaOG7o3AgxJHhu5NuZyAyIG7Eg20gY8OzIHjDoWMgc3XhuqV0IHLhu51pIGLhu48gdGjhuqVwIGjGoW4gMzQuNyUgc28gduG7m2kgaOG7o3AgxJHhu5NuZyB0aMOhbmcuIMSQw6J5IGzDoCB54bq/dSB04buRIGPDsyB0w6FjIMSR4buZbmcgYuG6o28gduG7hyBt4bqhbmggbmjhuqV0Lg0KLSAqKkjhu4cgc+G7kSBgSW50ZXJuZXRTZXJ2aWNlRmliZXIgb3B0aWNgICgwLjE5ODMpOioqIEtow6FjaCBow6BuZyBkw7luZyBjw6FwIHF1YW5nIGPDsyB4w6FjIHN14bqldCBy4budaSBi4buPIGNhbyBoxqFuIDE5LjglIHNvIHbhu5tpIERTTCwga2hpIGPDoWMgeeG6v3UgdOG7kSBraMOhYyBraMO0bmcgxJHhu5VpLg0KLSAqKkjhu4cgc+G7kSBgUGF5bWVudE1ldGhvZEVsZWN0cm9uaWMgY2hlY2tgICgwLjE2MDEpOioqIEtow6FjaCBow6BuZyBkw7luZyBzw6ljIMSRaeG7h24gdOG7rSBjw7MgeMOhYyBzdeG6pXQgcuG7nWkgYuG7jyBjYW8gaMahbiAxNiUgc28gduG7m2kgY2h1eeG7g24ga2hv4bqjbiB04buxIMSR4buZbmcuDQoNCioqS+G6v3QgbHXhuq1uOioqIFThu6sgbcO0IGjDrG5oIExQTSwgY8OzIHRo4buDIGvhur90IGx14bqtbiBy4bqxbmcgaOG7o3AgxJHhu5NuZywgZOG7i2NoIHbhu6UgSW50ZXJuZXQsIHbDoCB0aOG7nWkgZ2lhbiBn4bqvbiBiw7MgbMOgIG5o4buvbmcgeeG6v3UgdOG7kSBjw7Mg4bqjbmggaMaw4bufbmcgbeG6oW5oIG3hur0gbmjhuqV0IMSR4bq/biB4w6FjIHN14bqldCBy4budaSBi4buPIGPhu6dhIGtow6FjaCBow6BuZy4NCg0KIyMgKio1LjIuIE3DtCBow6xuaCBMb2dpdCBC4buZaSoqDQpgYGB7ciBtdWx0aS1sb2dpdH0NCmxvZ2l0X211bHRpIDwtIGdsbShDaHVybl9iaW5hcnkgfiBDb250cmFjdCArIFNlbmlvckNpdGl6ZW4gKyBQYXltZW50TWV0aG9kICsgSW50ZXJuZXRTZXJ2aWNlICsgdGVudXJlLA0KICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpKQ0Kc3VtbWFyeShsb2dpdF9tdWx0aSkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNClBoxrDGoW5nIHRyw6xuaCBo4buTaSBxdXkgTG9naXQgYuG7mWkgxrDhu5tjIGzGsOG7o25nOg0KYGxvZyhvZGRzKSA9IC0wLjczMCAtIDEuMjcyKkNvbnRyYWN0T25lIHllYXIgLSAyLjU1MypDb250cmFjdFR3byB5ZWFyICsgMC4yMTMqU2VuaW9yQ2l0aXplblllcyAuLi4gLSAwLjAzMSp0ZW51cmVgDQoNClRyb25nIMSRw7M6DQotICoqSOG7hyBz4buRIGB0ZW51cmVgICgtMC4wMzEpOioqIEtoaSBraeG7g20gc2/DoXQgY8OhYyB54bq/dSB04buRIGtow6FjLCBt4buXaSB0aMOhbmcgZ+G6r24gYsOzIHRow6ptIGzDoG0gZ2nhuqNtIGxvZy1vZGRzIHLhu51pIGLhu48gxJFpIDAuMDMxLiBPZGRzIHLhu51pIGLhu48gZ2nhuqNtIGAxIC0gZXhwKC0wLjAzMSlgIOKJiCAzLjA1JSBjaG8gbeG7l2kgdGjDoW5nLg0KLSAqKkjhu4cgc+G7kSBgQ29udHJhY3RUd28geWVhcmAgKC0yLjU1Myk6KiogT2RkcyBy4budaSBi4buPIGPhu6dhIGtow6FjaCBow6BuZyBjw7MgaOG7o3AgxJHhu5NuZyAyIG7Eg20gY2jhu4kgYuG6sW5nIGBleHAoLTIuNTUzKWAg4omIIDcuOCUgc28gduG7m2kgaOG7o3AgxJHhu5NuZyB0aMOhbmcuDQotICoqSOG7hyBz4buRIGBJbnRlcm5ldFNlcnZpY2VGaWJlciBvcHRpY2AgKDAuODY1KToqKiBPZGRzIHLhu51pIGLhu48gY+G7p2Ega2jDoWNoIGjDoG5nIGTDuW5nIGPDoXAgcXVhbmcgY2FvIGjGoW4gYGV4cCgwLjg2NSlgIOKJiCAyLjM3IGzhuqduIHNvIHbhu5tpIGTDuW5nIERTTC4NCg0KKipL4bq/dCBsdeG6rW46KiogTmdheSBj4bqjIGtoaSB4ZW0geMOpdCDEkeG7k25nIHRo4budaSwgY8OhYyB54bq/dSB04buRIGB0ZW51cmVgLCBgQ29udHJhY3RgLCBgSW50ZXJuZXRTZXJ2aWNlYCwgdsOgIGBQYXltZW50TWV0aG9kYCB24bqrbiBsw6Agbmjhu69uZyB54bq/dSB04buRIGThu7EgYsOhbyBxdWFuIHRy4buNbmcgbmjhuqV0IGNobyBow6BuaCB2aSBy4budaSBi4buPLg0KDQojIyAqKjUuMy4gTcO0IGjDrG5oIFByb2JpdCBC4buZaSoqDQpgYGB7ciBtdWx0aS1wcm9iaXR9DQpwcm9iaXRfbXVsdGkgPC0gZ2xtKENodXJuX2JpbmFyeSB+IENvbnRyYWN0ICsgU2VuaW9yQ2l0aXplbiArIFBheW1lbnRNZXRob2QgKyBJbnRlcm5ldFNlcnZpY2UgKyB0ZW51cmUsDQogICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkZl9jbGVhbiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJwcm9iaXQiKSkNCnN1bW1hcnkocHJvYml0X211bHRpKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCg0KUGjGsMahbmcgdHLDrG5oIGjhu5NpIHF1eSBQcm9iaXQgYuG7mWkgxrDhu5tjIGzGsOG7o25nOg0KYM6m4oG7wrkoz4ApID0gLTAuNDU1IC0gMC43NDgqQ29udHJhY3RPbmUgeWVhciAtIDEuNDg4KkNvbnRyYWN0VHdvIHllYXIgKyAwLjEyNipTZW5pb3JDaXRpemVuWWVzIC4uLiAtIDAuMDE5KnRlbnVyZWANCg0KVHJvbmcgxJHDszoNCi0gKipI4buHIHPhu5EgYHRlbnVyZWAgKC0wLjAxOSk6KiogTeG7l2kgdGjDoW5nIGfhuq9uIGLDsyB0aMOqbSBsw6BtIGdp4bqjbSBaLXNjb3JlIChjaOG7iSBz4buRIHjDoWMgc3XhuqV0IHLhu51pIGLhu48pIMSRaSAwLjAxOSDEkcahbiB24buLLg0KLSAqKkjhu4cgc+G7kSBgQ29udHJhY3RUd28geWVhcmAgKC0xLjQ4OCk6KiogQ8OzIHTDoWMgxJHhu5luZyBsw6BtIGdp4bqjbSBaLXNjb3JlIG3huqFuaCBuaOG6pXQsIGNobyB0aOG6pXkgeMOhYyBzdeG6pXQgcuG7nWkgYuG7jyBy4bqldCB0aOG6pXAuDQotICoqSOG7hyBz4buRIGBJbnRlcm5ldFNlcnZpY2VGaWJlciBvcHRpY2AgKDAuNTA1KToqKiBMw6BtIHTEg25nIFotc2NvcmUsIHThu6ljIGzDoCB0xINuZyB4w6FjIHN14bqldCBy4budaSBi4buPLg0KDQoqKkvhur90IGx14bqtbjoqKiBL4bq/dCBxdeG6oyBj4bunYSBtw7QgaMOsbmggUHJvYml0IGhvw6BuIHRvw6BuIG5o4bqldCBxdcOhbiB24bubaSBMb2dpdCB24buBIGThuqV1IHbDoCDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ogY+G7p2EgY8OhYyBo4buHIHPhu5EsIGPhu6duZyBj4buRIMSR4buZIHRpbiBj4bqteSBj4bunYSBwaMOibiB0w61jaC4NCg0KIyMgKio1LjQuIE3DtCBow6xuaCBDbG9nbG9nIELhu5lpKioNCmBgYHtyIG11bHRpLWNsb2dsb2d9DQpjbG9nbG9nX211bHRpIDwtIGdsbShDaHVybl9iaW5hcnkgfiBDb250cmFjdCArIFNlbmlvckNpdGl6ZW4gKyBQYXltZW50TWV0aG9kICsgSW50ZXJuZXRTZXJ2aWNlICsgdGVudXJlLA0KICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRmX2NsZWFuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImNsb2dsb2ciKSkNCnN1bW1hcnkoY2xvZ2xvZ19tdWx0aSkNCmBgYA0KDQoqKk5o4bqtbiB4w6l0OioqDQoNClBoxrDGoW5nIHRyw6xuaCBo4buTaSBxdXkgQ2xvZ2xvZyBi4buZaSDGsOG7m2MgbMaw4bujbmc6DQpgbG9nKC1sb2coMS3PgCkpID0gLTEuMTM5IC0gMS4wMTEqQ29udHJhY3RPbmUgeWVhciAtIDIuMTAyKkNvbnRyYWN0VHdvIHllYXIgKyAwLjE1NSpTZW5pb3JDaXRpemVuWWVzIC4uLiAtIDAuMDI0KnRlbnVyZWANCg0KVHJvbmcgxJHDszoNCi0gKipI4buHIHPhu5EgYHRlbnVyZWAgKC0wLjAyNCk6KiogVGjhu51pIGdpYW4gZ+G6r24gYsOzIGzDoG0gZ2nhuqNtIGxvZy1oYXphcmQgY+G7p2Egdmnhu4djIHLhu51pIGLhu48uDQotICoqSOG7hyBz4buRIGBDb250cmFjdFR3byB5ZWFyYCAoLTIuMTAyKToqKiBI4bujcCDEkeG7k25nIDIgbsSDbSBsw6BtIGdp4bqjbSBsb2ctaGF6YXJkIHLhu51pIGLhu48gbeG7mXQgY8OhY2ggbeG6oW5oIG3hur0uDQotICoqSOG7hyBz4buRIGBJbnRlcm5ldFNlcnZpY2VGaWJlciBvcHRpY2AgKDAuNjk3KToqKiBE4buLY2ggduG7pSBjw6FwIHF1YW5nIGzDoG0gdMSDbmcgbG9nLWhhemFyZCBy4budaSBi4buPLg0KDQoqKkvhur90IGx14bqtbjoqKiBNw7QgaMOsbmggQ2xvZ2xvZyBjxaluZyDEkcawYSByYSBjw6FjIGvhur90IGx14bqtbiB0xrDGoW5nIHThu7EsIGNobyB0aOG6pXkgc+G7sSB24buvbmcgY2jhuq9jIGPhu6dhIGPDoWMga+G6v3QgcXXhuqMgcGjDom4gdMOtY2ggYuG6pXQga+G7gyB2aeG7h2MgbOG7sWEgY2jhu41uIGjDoG0gbGnDqm4ga+G6v3QuDQoNCi0tLQ0KDQojICoqQ0jGr8agTkcgNjogxJDDgU5IIEdJw4EgTcOUIEjDjE5IIFbDgCBE4buwIELDgU8qKg0KDQojIyAqKjYuMS4gU28gc8OhbmggY8OhYyBtw7QgaMOsbmggaOG7k2kgcXV5IGLhu5lpKioNCg0KYGBge3IgbW9kZWwtY29tcGFyaXNvbi1maW5hbH0NCiMgQuG6o25nIHNvIHPDoW5oDQpjb21wYXJpc29uX3RhYmxlIDwtIGRhdGEuZnJhbWUoDQogICJNw7QgaMOsbmgiID0gYygiVHV54bq/biB0w61uaCAoTFBNKSIsICJMb2dpdCIsICJQcm9iaXQiLCAiQ2xvZ2xvZyIpLA0KICBBSUMgPSBjKEFJQyhscG1fbXVsdGkpLCBBSUMobG9naXRfbXVsdGkpLCBBSUMocHJvYml0X211bHRpKSwgQUlDKGNsb2dsb2dfbXVsdGkpKSwNCiAgTG9nTGlrZWxpaG9vZCA9IGMobG9nTGlrKGxwbV9tdWx0aSksIGxvZ0xpayhsb2dpdF9tdWx0aSksIGxvZ0xpayhwcm9iaXRfbXVsdGkpLCBsb2dMaWsoY2xvZ2xvZ19tdWx0aSkpLA0KICAiTWNGYWRkZW4gUi1zcXVhcmVkIiA9IGMocFIyKGxwbV9tdWx0aSlbIk1jRmFkZGVuIl0sIHBSMihsb2dpdF9tdWx0aSlbIk1jRmFkZGVuIl0sIHBSMihwcm9iaXRfbXVsdGkpWyJNY0ZhZGRlbiJdLCBwUjIoY2xvZ2xvZ19tdWx0aSlbIk1jRmFkZGVuIl0pLA0KICBjaGVjay5uYW1lcyA9IEZBTFNFDQopDQoNCmthYmxlKGNvbXBhcmlzb25fdGFibGUsIGNhcHRpb24gPSAiQuG6o25nIHNvIHPDoW5oIGhp4buHdSBxdeG6oyBjw6FjIG3DtCBow6xuaCBo4buTaSBxdXkgYuG7mWkiLCBkaWdpdHMgPSA0KQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQ6KioNCi0gICBE4buxYSB0csOqbiBjw6FjIGNo4buJIHPhu5EsIG3DtCBow6xuaCAqKkxvZ2l0KiogdsOgICoqUHJvYml0KiogY2hvIGvhur90IHF14bqjIHThu5F0IG5o4bqldC4gQ2jDum5nIGPDsyBnacOhIHRy4buLIEFJQyB0aOG6pXAgbmjhuqV0IHbDoCBNY0ZhZGRlbiBSwrIgY2FvIG5o4bqldCwgY2hvIHRo4bqleSBraOG6oyBuxINuZyBnaeG6o2kgdGjDrWNoIHPhu7EgYmnhur9uIHRoacOqbiBj4bunYSBiaeG6v24gYENodXJuYCB04buRdCBoxqFuIHNvIHbhu5tpIExQTSB2w6AgQ2xvZ2xvZy4NCi0gICBNw7QgaMOsbmggUHJvYml0IGPDsyBBSUMgKDUyMzQuOCkgdsOgIExvZy1MaWtlbGlob29kICgtMjYwNC40KSB04buRdCBoxqFuIG3hu5l0IGNow7p0IHNvIHbhu5tpIExvZ2l0LCBuaMawbmcgc+G7sSBraMOhYyBiaeG7h3QgbMOgIGtow7RuZyDEkcOhbmcga+G7gy4gTcO0IGjDrG5oIExvZ2l0IHRoxrDhu51uZyDEkcaw4bujYyDGsHUgdGnDqm4gdsOsIGjhu4cgc+G7kSBj4bunYSBuw7MgY8OzIHRo4buDIMSRxrDhu6NjIGRp4buFbiBnaeG6o2kgdHLhu7FjIHRp4bq/cCB0aMO0bmcgcXVhIE9kZHMgUmF0aW8uDQotICAgKipL4bq/dCBsdeG6rW46KiogTcO0IGjDrG5oIExvZ2l0IHbDoCBQcm9iaXQgbMOgIGhhaSBtw7QgaMOsbmggcGjDuSBo4bujcCBuaOG6pXQgY2hvIGLhu5kgZOG7ryBsaeG7h3UgbsOgeS4gQ2jDum5nIHRhIHPhur0gY2jhu41uICoqbcO0IGjDrG5oIExvZ2l0KiogxJHhu4MgdGjhu7FjIGhp4buHbiBk4buxIGLDoW8gZG8gdMOtbmggZOG7hSBkaeG7hW4gZ2nhuqNpIGPhu6dhIG7Dsy4NCg0KIyMgKio2LjIuIEThu7EgYsOhbyBraOG6oyBuxINuZyBy4budaSBi4buPKioNCg0KQ2jDum5nIHRhIHPhur0gc+G7rSBk4bulbmcgbcO0IGjDrG5oIExvZ2l0IGLhu5lpIMSR4buDIGThu7EgYsOhbyB4w6FjIHN14bqldCBy4budaSBi4buPIGNobyBt4buZdCBraMOhY2ggaMOgbmcgZ2nhuqMgxJHhu4tuaCBjw7MgY8OhYyDEkeG6t2MgxJFp4buDbSBy4bunaSBybyBjYW8gbmjhuqV0IMSRw6MgxJHGsOG7o2MgeMOhYyDEkeG7i25oLg0KDQpgYGB7ciBwcmVkaWN0aW9uLWZpbmFsfQ0KIyBU4bqhbyBo4buTIHPGoSBraMOhY2ggaMOgbmcgY8OzIG5ndXkgY8ahIHLhu51pIGLhu48gY2FvDQpyaXNreV9jdXN0b21lciA8LSBkYXRhLmZyYW1lKA0KICBDb250cmFjdCA9IGZhY3RvcigiTW9udGgtdG8tbW9udGgiLCBsZXZlbHMgPSBsZXZlbHMoZGZfY2xlYW4kQ29udHJhY3QpKSwNCiAgU2VuaW9yQ2l0aXplbiA9IGZhY3RvcigiWWVzIiwgbGV2ZWxzID0gbGV2ZWxzKGRmX2NsZWFuJFNlbmlvckNpdGl6ZW4pKSwNCiAgUGF5bWVudE1ldGhvZCA9IGZhY3RvcigiRWxlY3Ryb25pYyBjaGVjayIsIGxldmVscyA9IGxldmVscyhkZl9jbGVhbiRQYXltZW50TWV0aG9kKSksDQogIEludGVybmV0U2VydmljZSA9IGZhY3RvcigiRmliZXIgb3B0aWMiLCBsZXZlbHMgPSBsZXZlbHMoZGZfY2xlYW4kSW50ZXJuZXRTZXJ2aWNlKSksDQogIHRlbnVyZSA9IDEgICMgS2jDoWNoIGjDoG5nIG3hu5tpLCBjaOG7iSBn4bqvbiBiw7MgMSB0aMOhbmcNCikNCg0KY2F0KCJE4buxIGLDoW8gY2hvIGtow6FjaCBow6BuZyBjw7MgaOG7kyBzxqE6XG4iKQ0KcHJpbnQocmlza3lfY3VzdG9tZXIpDQoNCiMgROG7sSBiw6FvIHjDoWMgc3XhuqV0DQpwcmVkaWN0ZWRfcHJvYiA8LSBwcmVkaWN0KGxvZ2l0X211bHRpLCBuZXdkYXRhID0gcmlza3lfY3VzdG9tZXIsIHR5cGUgPSAicmVzcG9uc2UiKQ0KDQpjYXQoIlxuLT4gWMOhYyBzdeG6pXQgcuG7nWkgYuG7jyBk4buxIGLDoW8gY+G7p2Ega2jDoWNoIGjDoG5nIG7DoHkgbMOgOiIsIHNjYWxlczo6cGVyY2VudChwcmVkaWN0ZWRfcHJvYiwgYWNjdXJhY3kgPSAwLjEpLCAiXG4iKQ0KYGBgDQoNCioqTmjhuq1uIHjDqXQgZOG7sSBiw6FvOioqDQpNw7QgaMOsbmggTG9naXQgZOG7sSBiw6FvIHLhurFuZyBt4buZdCBraMOhY2ggaMOgbmcgY2FvIHR14buVaSwgbeG7m2kgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgxJHGsOG7o2MgMSB0aMOhbmcsIGPDsyBo4bujcCDEkeG7k25nIHRoZW8gdGjDoW5nLCBkw7luZyBJbnRlcm5ldCBjw6FwIHF1YW5nIHbDoCB0aGFuaCB0b8OhbiBi4bqxbmcgc8OpYyDEkWnhu4duIHThu60gY8OzICoqeMOhYyBzdeG6pXQgcuG7nWkgYuG7jyBsw6puIHThu5tpIDczLjElKiouIMSQw6J5IGzDoCBt4buZdCBjb24gc+G7kSBj4buxYyBr4buzIGNhbywgY2hvIHRo4bqleSBz4buxIGvhur90IGjhu6NwIGPhu6dhIGPDoWMgeeG6v3UgdOG7kSBy4bunaSBybyBuw6B5IHThuqFvIHJhIG3hu5l0ICJjw7RuZyB0aOG7qWMgaG/DoG4gaOG6o28iIGNobyB2aeG7h2MgY2h1cm4uDQoNCkvhur90IHF14bqjIGThu7EgYsOhbyBuw6B5IGtow7RuZyBjaOG7iSBsw6AgbeG7mXQgY29uIHPhu5EsIG3DoCBsw6AgbeG7mXQgbOG7nWkgY+G6o25oIGLDoW8gbeG6oW5oIG3hur0uIE7DsyBjaG8gcGjDqXAgZG9hbmggbmdoaeG7h3AgeMOhYyDEkeG7i25oIGNow61uaCB4w6FjIG5o4buvbmcgIsSRaeG7g20gbsOzbmciIHRyb25nIHThu4dwIGtow6FjaCBow6BuZyBj4bunYSBtw6xuaC4gVGhheSB2w6wgY8OhYyBjaGnhur9uIGThu4tjaCBnaeG7ryBjaMOibiBkw6BuIHRy4bqjaSwgY8O0bmcgdHkgY8OzIHRo4buDIHThuq1wIHRydW5nIG5ndeG7k24gbOG7sWMgdsOgbyDEkcO6bmcgbmjDs20gxJHhu5FpIHTGsOG7o25nIG7DoHnigJR2w60gZOG7pSwgxJHGsGEgcmEgxrB1IMSRw6NpIMSR4bq3YyBiaeG7h3QgxJHhu4MgaOG7jSBjaHV54buDbiDEkeG7lWkgc2FuZyBo4bujcCDEkeG7k25nIGTDoGkgaOG6oW4gbmdheSB0cm9uZyBuaOG7r25nIHRow6FuZyDEkeG6p3UgdGnDqm4sIGhv4bq3YyBjdW5nIGPhuqVwIGjhu5cgdHLhu6Mga+G7uSB0aHXhuq10IGNodXnDqm4gc8OidSBjaG8gbmfGsOG7nWkgZMO5bmcgY8OhcCBxdWFuZyBt4bubaS4gxJDDonkgY2jDrW5oIGzDoCBnacOhIHRy4buLIHRo4buxYyB0aeG7hW4gY+G7kXQgbMO1aSBtw6AgcGjDom4gdMOtY2ggZOG7sSBiw6FvIG1hbmcgbOG6oWk6IGJp4bq/biBk4buvIGxp4buHdSB0aMOgbmggaMOgbmggxJHhu5luZyBjaGnhur9uIGzGsOG7o2MuDQoNCi0tLQ0KDQojICoqQ0jGr8agTkcgNzogxq9VIMSQSeG7gk0sIEjhuqBOIENI4bq+IFbDgCBLSeG6vk4gTkdI4buKKioNCg0KIyMgKio3LjEuIMavdSDEkWnhu4NtIGPhu6dhIE5naGnDqm4gY+G7qXUqKg0KLSAqKlTDrW5oIGjhu4cgdGjhu5FuZzoqKiBOZ2hpw6puIGPhu6l1IMSRw6Mgw6FwIGThu6VuZyBt4buZdCBxdXkgdHLDrG5oIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IGLDoGkgYuG6o24sIHThu6sgdGjhu5FuZyBrw6ogbcO0IHThuqMsIGtp4buDbSDEkeG7i25oIGdp4bqjIHRodXnhur90IMSR4bq/biB4w6J5IGThu7FuZyB2w6Agc28gc8Ohbmggbmhp4buBdSBtw7QgaMOsbmggaOG7k2kgcXV5Lg0KLSAqKkvhur90IHF14bqjIHLDtSByw6BuZzoqKiBDw6FjIHnhur91IHThu5Eg4bqjbmggaMaw4bufbmcgY2jDrW5oIMSR4bq/biB04bu3IGzhu4cgcuG7nWkgYuG7jyDEkcOjIMSRxrDhu6NjIHjDoWMgxJHhu4tuaCBt4buZdCBjw6FjaCByw7UgcsOgbmcgdsOgIG5o4bqldCBxdcOhbiBxdWEgbmhp4buBdSBwaMawxqFuZyBwaMOhcCBraMOhYyBuaGF1Lg0KLSAqKlTDrW5oIOG7qW5nIGThu6VuZyBjYW86KiogS+G6v3QgcXXhuqMgbmdoacOqbiBj4bupdSBjw7MgdGjhu4MgxJHGsOG7o2Mgw6FwIGThu6VuZyB0cuG7sWMgdGnhur9wIHbDoG8gdmnhu4djIHjDonkgZOG7sW5nIGPDoWMgY2hp4bq/biBsxrDhu6NjIGtpbmggZG9hbmggbmjhurFtIGdp4bqjbSB04bu3IGzhu4cgcuG7nWkgYuG7jywgbmjGsCB04bqtcCB0cnVuZyB2w6BvIGPDoWMgbmjDs20ga2jDoWNoIGjDoG5nIGPDsyBo4bujcCDEkeG7k25nIHRow6FuZywgZMO5bmcgY8OhcCBxdWFuZyBob+G6t2MgdGhhbmggdG/DoW4gYuG6sW5nIHPDqWMgxJFp4buHbiB04butLg0KDQojIyAqKjcuMi4gSOG6oW4gY2jhur8gY+G7p2EgTmdoacOqbiBj4bupdSoqDQotICoqROG7ryBsaeG7h3UgZ2nhuqMgxJHhu4tuaDoqKiBC4buZIGThu68gbGnhu4d1IGzDoCBnaeG6oyDEkeG7i25oIHbDoCBjw7MgdGjhu4Mga2jDtG5nIHBo4bqjbiDDoW5oIMSR4bqneSDEkeG7pyBz4buxIHBo4bupYyB04bqhcCBj4bunYSB0aOG7iyB0csaw4budbmcgdmnhu4VuIHRow7RuZyB0aOG7sWMgdOG6vy4NCi0gKipC4buPIHF1YSBjw6FjIGJp4bq/biB0aeG7gW0gbsSDbmc6KiogTmdoacOqbiBj4bupdSBjaOG7iSB04bqtcCB0cnVuZyB2w6BvIDUgYmnhur9uIMSRxrDhu6NjIGNo4buNbiB0csaw4bubYy4gQ8OhYyB54bq/dSB04buRIGtow6FjIG5oxrAgY2jhuqV0IGzGsOG7o25nIGThu4tjaCB24bulIGtow6FjaCBow6BuZywgY8OhYyBjaMawxqFuZyB0csOsbmgga2h1eeG6v24gbcOjaSwgaG/hurdjIHTDoWMgxJHhu5luZyBj4bunYSDEkeG7kWkgdGjhu6cgY+G6oW5oIHRyYW5oIGNoxrBhIMSRxrDhu6NjIHhlbSB4w6l0Lg0KLSAqKk3DtCBow6xuaCB0xKluaDoqKiBDw6FjIG3DtCBow6xuaCBo4buTaSBxdXkgbMOgIG3DtCBow6xuaCB0xKluaCwga2jDtG5nIHBo4bqjbiDDoW5oIMSRxrDhu6NjIHPhu7EgdGhheSDEkeG7lWkgdHJvbmcgaMOgbmggdmkgY+G7p2Ega2jDoWNoIGjDoG5nIHRoZW8gdGjhu51pIGdpYW4uDQoNCiMjICoqNy4zLiBLaeG6v24gbmdo4buLKioNCkThu7FhIHRyw6puIGvhur90IHF14bqjIHBow6JuIHTDrWNoLCB0w6FjIGdp4bqjIMSR4buBIHh14bqldCBjw6FjIGtp4bq/biBuZ2jhu4sgc2F1Og0KMS4gICoqVOG7kWkgxrB1IGjDs2EgY2hp4bq/biBsxrDhu6NjIGjhu6NwIMSR4buTbmc6KiogVMOtY2ggY+G7sWMgdHJp4buDbiBraGFpIGPDoWMgY2jGsMahbmcgdHLDrG5oIGtodXnhur9uIG3Do2kgxJHhu4Mga2h1eeG6v24ga2jDrWNoIGtow6FjaCBow6BuZyDEkWFuZyBz4butIGThu6VuZyBo4bujcCDEkeG7k25nIGBNb250aC10by1tb250aGAgY2h1eeG7g24gxJHhu5VpIHNhbmcgY8OhYyBo4bujcCDEkeG7k25nIGTDoGkgaOG6oW4gKGBPbmUgeWVhcmAgaG/hurdjIGBUd28geWVhcmApLg0KMi4gICoqQ+G6o2kgdGhp4buHbiB0cuG6o2kgbmdoaeG7h20gZOG7i2NoIHbhu6UgSW50ZXJuZXQ6KiogVOG7tyBs4buHIHLhu51pIGLhu48gY2FvIGPhu6dhIG5ow7NtIGtow6FjaCBow6BuZyBgRmliZXIgb3B0aWNgIGNobyB0aOG6pXkgY8OzIHRo4buDIHThu5NuIHThuqFpIGPDoWMgduG6pW4gxJHhu4EgduG7gSBjaOG6pXQgbMaw4bujbmcgZOG7i2NoIHbhu6UsIGdpw6EgY+G6oywgaG/hurdjIGjhu5cgdHLhu6Mga+G7uSB0aHXhuq10LiBD4bqnbiBjw7MgY8OhYyBjdeG7mWMga2jhuqNvIHPDoXQgc8OidSBoxqFuIMSR4buDIHTDrG0gcmEgbmd1ecOqbiBuaMOibiB2w6AgY+G6o2kgdGhp4buHbi4NCjMuICAqKlRow7pjIMSR4bqpeSBjw6FjIHBoxrDGoW5nIHRo4bupYyB0aGFuaCB0b8OhbiB04buxIMSR4buZbmc6KiogQ3VuZyBj4bqlcCBjw6FjIMawdSDEkcOjaSAodsOtIGThu6U6IGdp4bqjbSBnacOhLCB04bq3bmcgdGjDqm0gZOG7ryBsaeG7h3UpIGNobyBraMOhY2ggaMOgbmcga2hpIGjhu40gY2h1eeG7g24gdOG7qyB0aGFuaCB0b8OhbiB0aOG7pyBjw7RuZyAoYEVsZWN0cm9uaWMgY2hlY2tgKSBzYW5nIGPDoWMgaMOsbmggdGjhu6ljIHThu7EgxJHhu5luZyBuaMawIGBCYW5rIHRyYW5zZmVyYCBob+G6t2MgYENyZWRpdCBjYXJkYC4NCjQuICAqKkNoxINtIHPDs2MgxJHhurdjIGJp4buHdCBjaG8gbmfGsOG7nWkgY2FvIHR14buVaToqKiBYw6J5IGThu7FuZyBjw6FjIGfDs2kgY8aw4bubYyB2w6AgY2jGsMahbmcgdHLDrG5oIGjhu5cgdHLhu6MgxJHGoW4gZ2nhuqNuLCBk4buFIHPhu60gZOG7pW5nLCBuaOG6r20gcmnDqm5nIMSR4bq/biBwaMOibiBraMO6YyBraMOhY2ggaMOgbmcgYFNlbmlvckNpdGl6ZW5gIMSR4buDIGdp4bqjbSB04bu3IGzhu4cgcuG7nWkgYuG7jyBj4bunYSBuaMOzbSBuw6B5Lg==