PHẦN 1: CHUẨN BỊ VÀ TÌM HIỂU DỮ LIỆU
1.1 Đọc dữ liệu
library(readxl)
tcc <- read_excel("D:/download/tcc.xlsx")
1.2 Sơ lược về bộ dữ liệu
Nội dung của bộ dữ liệu là khảo sát quyết định ngưng sử dụng dịch vụ
Internet của khách hàng, bao gồm:
CustomerID: Mã khách hàng
Gender: Giới tính
InternetService: Dịch vụ Internet đang sử dụng (Bao gồm Internet
cáp quang - Fiber optic và Đường dây thuê bao số - DSL)
Contract: Loại hợp đồng (Bao gồm hàng tháng, hàng năm và 2
năm)
PaymentMethod: Phương thức thanh toán (Bao gồm séc điện tử, séc
gửi qua bưu điện, thẻ tín dụng và chuyển khoản)
MonthlyCharges: Phí hàng tháng (Tính bằng USD)
Churn1, Churn: Quyết định ngưng sử dụng dịch vụ. (1 là Yes, 0 là
No)
Dataset bao gồm 8 biến và 7043 quan sát, không có dữ liệu trống.
PHẦN 2: PHÂN TÍCH VÀ MÔ TẢ CÁC BIẾN ĐỊNH TÍNH
2.1 Gender
Tần số, tần suất
# Lập bảng tần số
gender_f <- table(tcc$gender)
# Lập bảng tần suất
gender_p <- prop.table(gender_f)*100
# Kết hợp thành một bảng
gender <- data.frame(
Category = names(gender_f),
Frequency = as.vector(gender_f),
Percentage = round(as.vector(gender_p), 2)
)
gender
Biểu đồ
ggplot(data = gender, aes(x = '', y = Frequency, fill = Category)) +
geom_col() +
coord_polar('y') +
geom_text(aes(label = percent(Frequency/length(tcc$gender))), position = position_stack(vjust = 0.5)) +
labs(title = 'Figure 1: Gender of Customers') +
scale_fill_brewer(palette = "Set3") +
theme(plot.title = element_text(hjust = 0.5, face = 'bold'))

Nhận xét: Số lượng khách hàng là nam chiếm
khoảng 50.48% và số lượng khách hàng nữ là 49.52% cho thấy rằng số lượng
khách hàng nam đang có tỷ lệ cao hơn số khách hàng nữ nhưng sự chênh
lệch đó là không đáng kể, chỉ khoảng chưa tới 1%.
2.2 Churn
Tần số, tần suất
# Lập bảng tần số
ch_f <- table(tcc$Churn)
# Lập bảng tần suất
ch_p <- prop.table(ch_f)*100
# Kết hợp thành một bảng
churn <- data.frame(
Category = names(ch_f),
Frequency = as.vector(ch_f),
Percentage = round(as.vector(ch_p), 2)
)
churn
Biểu đồ
ggplot(data = churn, aes(x = '', y = Frequency, fill = Category)) +
geom_col() +
coord_polar('y') +
geom_text(aes(label = percent(Frequency/length(tcc$gender))), position = position_stack(vjust = 0.5)) +
labs(title = 'Figure 2: Churn of Customers') +
scale_fill_brewer(palette = "Set3") +
theme(plot.title = element_text(hjust = 0.5, face = 'bold'))

Nhận xét: Số lượng khách hàng chọn tiếp tục
sử dụng dịch vụ là 73%, khoảng 5174 khách hàng và số khách hàng chọn
ngưng sử dụng dịch vụ chiếm 27%, khoảng 1869 khách hàng. Điều này cho
thấy rằng số khách hàng đều chọn tiếp tục sử dụng dịch vụ internet chiếm
ưu thế so với số khách hàng không sử dụng dịch vụ.
2.3 InternetService
Bảng tần số, tần suất
# Lập bảng tần số
is_f <- table(tcc$InternetService)
# Lập bảng tần suất
is_p <- prop.table(is_f)*100
# Kết hợp thành một bảng
is <- data.frame(
Category = names(is_f),
Frequency = as.vector(is_f),
Percentage = round(as.vector(is_p), 2)
)
is
Biểu đồ
ggplot(data = is, aes(x = '', y = Frequency, fill = Category)) +
geom_col() +
coord_polar('y') +
geom_text(aes(label = percent(Frequency/length(tcc$gender))), position = position_stack(vjust = 0.5)) +
labs(title = 'Figure 3: Internet Service of Customers') +
scale_fill_brewer(palette = "Set3") +
theme(plot.title = element_text(hjust = 0.5, face = 'bold'))

PHẦN 3: ƯỚC LƯỢNG KHOẢNG VÀ KIỂM ĐỊNH GIẢ THUYẾT CHO TỶ
LỆ
3.1 Gender
# Số lượng khách hàng nữ
fm <- sum(tcc$gender == "Female")
# Tổng số khách hàng
total <- length(tcc$gender)
# Kiểm định tỷ lệ
prop.test(fm, total, p = 0.495, conf.level = 0.95)
##
## 1-sample proportions test with continuity correction
##
## data: fm out of total, null probability 0.495
## X-squared = 0.00083849, df = 1, p-value = 0.9769
## alternative hypothesis: true p is not equal to 0.495
## 95 percent confidence interval:
## 0.4835017 0.5069906
## sample estimates:
## p
## 0.4952435
Đặt giả thuyết: \[
\left\{
\begin{array}{ll}
H_0: & \text{Tỷ lệ thực số khách hàng là nữ } = 0.495 \\
H_1: & \text{Tỷ lệ thực số khách hàng là nữ } \ne 0.495
\end{array}
\right.
\]
Ta thấy rằng p_value = 0.9769 > 5%, nghĩa là không có đủ cơ sở để
bác bỏ H0. Nghĩa là thực tế tỷ lệ số khách hàng nữ là 49.5%, ngoài ra,
tỷ lệ khách hàng nữ còn được ước lượng là nằm trong khoảng
48.35-50.7%.
3.2 Churn
# Số lượng No
continue <- sum(tcc$Churn == "No")
# Tổng số khách hàng
total <- length(tcc$gender)
# Kiểm định tỷ lệ
prop.test(continue, total, p = 0.73, conf.level = 0.95)
##
## 1-sample proportions test with continuity correction
##
## data: continue out of total, null probability 0.73
## X-squared = 0.74274, df = 1, p-value = 0.3888
## alternative hypothesis: true p is not equal to 0.73
## 95 percent confidence interval:
## 0.7241207 0.7448820
## sample estimates:
## p
## 0.7346301
Đặt giả thuyết: \[
\left\{
\begin{array}{ll}
H_0: & \text{Tỷ lệ thực số khách hàng tiếp tục sử dụng dịch vụ } =
0.73 \\
H_1: & \text{Tỷ lệ thực số khách hàng tiếp tục sử dụng dịch vụ } \ne
0.73
\end{array}
\right.
\]
Ta thấy rằng p_value = 0.3888 > 5%, nghĩa là không có đủ cơ sở để
bác bỏ H0. Nghĩa là thực tế tỷ lệ số khách hàng chọn tiếp tục sử dụng
dịch vụ là 73%, ngoài ra, tỷ lệ khách hàng tiếp tục sử dụng dịch vụ còn
được ước lượng là nằm trong khoảng 72.41-74.48%.
PHẦN 4: PHÂN TÍCH MỐI QUAN HỆ GIỮA CÁC BIẾN
InternetService và
churn
Bảng tần suất chéo
is_churn <- table(tcc$InternetService,tcc$Churn)
is_churn
##
## No Yes
## DSL 1962 459
## Fiber optic 1799 1297
## No 1413 113
4.2 Biểu đồ
df_is_churn <- as.data.frame(is_churn)
colnames(df_is_churn) <- c("Internet Service","Churn","Freq")
ggplot(df_is_churn, aes(x = Churn, y = Freq, fill = `Internet Service`)) +
geom_col(position = position_dodge()) +
labs(title = 'Figure 4', x = 'Churn', y = 'Frequency') +
scale_fill_brewer(palette = "Set2") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
plot.title = element_text(hjust = 0.5, face = "bold"))

4.3 Kiểm định Chi-bình phương
chisq.test(is_churn)
##
## Pearson's Chi-squared test
##
## data: is_churn
## X-squared = 732.31, df = 2, p-value < 2.2e-16
Đặt giả thuyết: \[
\left\{
\begin{array}{ll}
H_0: & \text{Không có mối quan hệ giữa hai biến phân loại } \\
H_1: & \text{Có tồn tại mối quan hệ giữa hai biến phân loại }
\end{array}
\right.
\]
Ta thấy kết quả kiểm định cho ra giá trị p_value = 0.000 < 5%,
nghĩa là đủ cơ sở để bác bỏ \(H_0\).
Vậy mối quan hệ giữa loại dịch vụ và quyết định ngưng sử dụng dịch vụ là
có liên quan đến nhau.
4.4 Tính Relative Risk - RR
library(epitools)
rr <- riskratio(is_churn)
rr
## $data
##
## No Yes Total
## DSL 1962 459 2421
## Fiber optic 1799 1297 3096
## No 1413 113 1526
## Total 5174 1869 7043
##
## $measure
## risk ratio with 95% C.I.
## estimate lower upper
## DSL 1.0000000 NA NA
## Fiber optic 2.2096380 2.0149902 2.4230887
## No 0.3905764 0.3211862 0.4749579
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## DSL NA NA NA
## Fiber optic 0 5.462658e-76 1.352046e-73
## No 0 1.775062e-25 9.986103e-24
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
Với nhóm Fiber optic so với DSL, ta có giá trị RR = 2.21 và nằm trong
khoảng 2.02-2.42 với độ tin cậy 95%, nghĩa là tỷ lệ khách hàng sử dụng
dịch vụ Fiber optic có tỷ lệ ngưng sử dụng dịch vụ cao hơn hẳn so với
các khách hàng dùng DSL. Cụ thể, nhóm sử dụng Fiber optic có tỷ lệ dừng
sử dụng cao hơn 121% so với nhóm DSL.
Với nhóm không dùng so với DSL, ta có giá trị RR = 0.39 và nằm trong
khoảng 0.32-0.47 với độ tin cậy 95%, nghĩa là tỷ lệ khách hàng không
dùng dịch vụ có tỷ lệ ngưng sử dụng dịch vụ thấp hơn so với các khách
hàng dùng DSL. Cụ thể, nhóm không dùng internet có tỷ lệ dừng sử dụng
thấp hơn so với nhóm DSL là 61%.
4.5 Tính Odds Ratio - OR
or <- oddsratio(is_churn)
or
## $data
##
## No Yes Total
## DSL 1962 459 2421
## Fiber optic 1799 1297 3096
## No 1413 113 1526
## Total 5174 1869 7043
##
## $measure
## odds ratio with 95% C.I.
## estimate lower upper
## DSL 1.0000000 NA NA
## Fiber optic 3.0805710 2.7224910 3.4904113
## No 0.3422587 0.2743666 0.4236615
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## DSL NA NA NA
## Fiber optic 0 5.462658e-76 1.352046e-73
## No 0 1.775062e-25 9.986103e-24
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
Ở nhóm Fiber optic, giá trị OR = 3.08 và nằm trong khoảng 2.72-3.49
với độ tin cậy 95% cho thấy việc khách hàng sử dụng Fiber optic có tỷ lệ
dừng sử dụng dịch vụ cao hơn gấp 3 lần so với DSL.
Ở nhóm không sử dụng dịch vụ, giá trị OR = 0.34 và nằm trong khoảng
0.27-0.42 với độ tin cậy 95% cho thấy việc khách hàng không sử dụng dịch
vụ có tỷ lệ dừng sử dụng ít hơn hẳn so với DSL.
LS0tDQp0aXRsZTogIk5ndXnhu4VuIFRy4bqnbiBLaMOhbmggU2FuXzQiDQphdXRob3I6ICJOZ3V54buFbiBUcuG6p24gS2jDoW5oIFNhbiINCmRhdGU6ICIyMDI1LTA2LTA4Ig0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2NfZGVwdGg6IDINCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KYGBge2NzcywgZWNobz1GQUxTRX0NCi8qIFTEg25nIGPhu6EgY2jhu68gdG/DoG4gYuG7mSB2xINuIGLhuqNuICovDQpib2R5IHsNCiAgZm9udC1zaXplOiAxOHB4Ow0KfQ0KDQovKiBUxINuZyBj4buhIGNo4buvIHRpw6p1IMSR4buBICovDQpoMSB7IGZvbnQtc2l6ZTogMi4yZW07IH0NCmgyIHsgZm9udC1zaXplOiAxLjhlbTsgfQ0KaDMgeyBmb250LXNpemU6IDEuNWVtOyB9DQoNCi8qIFTEg25nIGPhu6EgY2jhu68gxJFv4bqhbiB2xINuICovDQpwIHsNCiAgZm9udC1zaXplOiAxLjFlbTsNCiAgbGluZS1oZWlnaHQ6IDEuNjsgLyogVMSDbmcga2hv4bqjbmcgY8OhY2ggZMOybmcgY2hvIGThu4UgxJHhu41jICovDQp9DQoNCi8qIFTEg25nIGPhu6EgY2jhu68gY29kZSAqLw0KY29kZSB7DQogIGZvbnQtc2l6ZTogMTZweDsNCn0NCmBgYA0KDQojICoqUEjhuqZOIDE6IENIVeG6qE4gQuG7iiBWw4AgVMOMTSBISeG7glUgROG7riBMSeG7hlUqKg0KDQojIyAqKjEuMSDEkOG7jWMgZOG7ryBsaeG7h3UqKg0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KdGNjIDwtIHJlYWRfZXhjZWwoIkQ6L2Rvd25sb2FkL3RjYy54bHN4IikNCmBgYA0KDQojIyAqKjEuMiBTxqEgbMaw4bujYyB24buBIGLhu5kgZOG7ryBsaeG7h3UqKg0KDQpO4buZaSBkdW5nIGPhu6dhIGLhu5kgZOG7ryBsaeG7h3UgbMOgIGto4bqjbyBzw6F0IHF1eeG6v3QgxJHhu4tuaCBuZ8awbmcgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgSW50ZXJuZXQgY+G7p2Ega2jDoWNoIGjDoG5nLCBiYW8gZ+G7k206DQoNCi0gQ3VzdG9tZXJJRDogTcOjIGtow6FjaCBow6BuZw0KDQotIEdlbmRlcjogR2nhu5tpIHTDrW5oDQoNCi0gSW50ZXJuZXRTZXJ2aWNlOiBE4buLY2ggduG7pSBJbnRlcm5ldCDEkWFuZyBz4butIGThu6VuZyAoQmFvIGfhu5NtIEludGVybmV0IGPDoXAgcXVhbmcgLSBGaWJlciBvcHRpYyB2w6AgxJDGsOG7nW5nIGTDonkgdGh1w6ogYmFvIHPhu5EgLSBEU0wpDQoNCi0gQ29udHJhY3Q6IExv4bqhaSBo4bujcCDEkeG7k25nIChCYW8gZ+G7k20gaMOgbmcgdGjDoW5nLCBow6BuZyBuxINtIHbDoCAyIG7Eg20pDQoNCi0gUGF5bWVudE1ldGhvZDogUGjGsMahbmcgdGjhu6ljIHRoYW5oIHRvw6FuIChCYW8gZ+G7k20gc8OpYyDEkWnhu4duIHThu60sIHPDqWMgZ+G7rWkgcXVhIGLGsHUgxJFp4buHbiwgdGjhursgdMOtbiBk4bulbmcgdsOgIGNodXnhu4NuIGtob+G6o24pDQoNCi0gTW9udGhseUNoYXJnZXM6IFBow60gaMOgbmcgdGjDoW5nIChUw61uaCBi4bqxbmcgVVNEKQ0KDQotIENodXJuMSwgQ2h1cm46IFF1eeG6v3QgxJHhu4tuaCBuZ8awbmcgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UuICgxIGzDoCBZZXMsIDAgbMOgIE5vKQ0KDQpEYXRhc2V0IGJhbyBn4buTbSA4IGJp4bq/biB2w6AgNzA0MyBxdWFuIHPDoXQsIGtow7RuZyBjw7MgZOG7ryBsaeG7h3UgdHLhu5FuZy4NCg0KIyAqKlBI4bqmTiAyOiBQSMOCTiBUw41DSCBWw4AgTcOUIFThuqIgQ8OBQyBCSeG6vk4gxJDhu4pOSCBUw41OSCoqDQoNCiMjICoqMi4xIEdlbmRlcioqDQoNCioqKlThuqduIHPhu5EsIHThuqduIHN14bqldCoqKg0KDQpgYGB7cn0NCiMgTOG6rXAgYuG6o25nIHThuqduIHPhu5ENCmdlbmRlcl9mIDwtIHRhYmxlKHRjYyRnZW5kZXIpDQoNCiMgTOG6rXAgYuG6o25nIHThuqduIHN14bqldA0KZ2VuZGVyX3AgPC0gcHJvcC50YWJsZShnZW5kZXJfZikqMTAwDQoNCiMgS+G6v3QgaOG7o3AgdGjDoG5oIG3hu5l0IGLhuqNuZw0KZ2VuZGVyIDwtIGRhdGEuZnJhbWUoDQogIENhdGVnb3J5ID0gbmFtZXMoZ2VuZGVyX2YpLA0KICBGcmVxdWVuY3kgPSBhcy52ZWN0b3IoZ2VuZGVyX2YpLA0KICBQZXJjZW50YWdlID0gcm91bmQoYXMudmVjdG9yKGdlbmRlcl9wKSwgMikNCikNCmdlbmRlcg0KYGBgDQoNCioqKkJp4buDdSDEkeG7kyoqKg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGdlbmRlciwgYWVzKHggPSAnJywgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IENhdGVnb3J5KSkgKw0KICBnZW9tX2NvbCgpICsNCiAgY29vcmRfcG9sYXIoJ3knKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KEZyZXF1ZW5jeS9sZW5ndGgodGNjJGdlbmRlcikpKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsNCiAgbGFicyh0aXRsZSA9ICdGaWd1cmUgMTogR2VuZGVyIG9mIEN1c3RvbWVycycpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gJ2JvbGQnKSkgIA0KYGBgDQoNCioqKk5o4bqtbiB4w6l0OioqKiBT4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyBsw6AgbmFtIGNoaeG6v20ga2hv4bqjbmcgNTAuNDglIHbDoCBz4buRIGzGsOG7o25nIGtow6FjaCBow6BuZyBu4buvIGzDoCA0OS41MiUgY2hvIHRo4bqleSBy4bqxbmcgc+G7kSBsxrDhu6NuZyBraMOhY2ggaMOgbmcgbmFtIMSRYW5nIGPDsyB04bu3IGzhu4cgY2FvIGjGoW4gc+G7kSBraMOhY2ggaMOgbmcgbuG7ryBuaMawbmcgc+G7sSBjaMOqbmggbOG7h2NoIMSRw7MgbMOgIGtow7RuZyDEkcOhbmcga+G7gywgY2jhu4kga2hv4bqjbmcgY2jGsGEgdOG7m2kgMSUuDQoNCiMjICoqMi4yIENodXJuKioNCg0KKioqVOG6p24gc+G7kSwgdOG6p24gc3XhuqV0KioqDQoNCmBgYHtyfQ0KIyBM4bqtcCBi4bqjbmcgdOG6p24gc+G7kQ0KY2hfZiA8LSB0YWJsZSh0Y2MkQ2h1cm4pDQoNCiMgTOG6rXAgYuG6o25nIHThuqduIHN14bqldA0KY2hfcCA8LSBwcm9wLnRhYmxlKGNoX2YpKjEwMA0KDQojIEvhur90IGjhu6NwIHRow6BuaCBt4buZdCBi4bqjbmcNCmNodXJuIDwtIGRhdGEuZnJhbWUoDQogIENhdGVnb3J5ID0gbmFtZXMoY2hfZiksDQogIEZyZXF1ZW5jeSA9IGFzLnZlY3RvcihjaF9mKSwNCiAgUGVyY2VudGFnZSA9IHJvdW5kKGFzLnZlY3RvcihjaF9wKSwgMikNCikNCmNodXJuDQpgYGANCg0KKioqQmnhu4N1IMSR4buTKioqDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBjaHVybiwgYWVzKHggPSAnJywgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IENhdGVnb3J5KSkgKw0KICBnZW9tX2NvbCgpICsNCiAgY29vcmRfcG9sYXIoJ3knKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KEZyZXF1ZW5jeS9sZW5ndGgodGNjJGdlbmRlcikpKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsNCiAgbGFicyh0aXRsZSA9ICdGaWd1cmUgMjogQ2h1cm4gb2YgQ3VzdG9tZXJzJykgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAnYm9sZCcpKSAgDQpgYGANCg0KKioqTmjhuq1uIHjDqXQ6KioqIFPhu5EgbMaw4bujbmcga2jDoWNoIGjDoG5nIGNo4buNbiB0aeG6v3AgdOG7pWMgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgbMOgIDczJSwga2hv4bqjbmcgNTE3NCBraMOhY2ggaMOgbmcgdsOgIHPhu5Ega2jDoWNoIGjDoG5nIGNo4buNbiBuZ8awbmcgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgY2hp4bq/bSAyNyUsIGtob+G6o25nIDE4Njkga2jDoWNoIGjDoG5nLiDEkGnhu4F1IG7DoHkgY2hvIHRo4bqleSBy4bqxbmcgc+G7kSBraMOhY2ggaMOgbmcgxJHhu4F1IGNo4buNbiB0aeG6v3AgdOG7pWMgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgaW50ZXJuZXQgY2hp4bq/bSDGsHUgdGjhur8gc28gduG7m2kgc+G7kSBraMOhY2ggaMOgbmcga2jDtG5nIHPhu60gZOG7pW5nIGThu4tjaCB24bulLg0KDQojIyAqKjIuMyBJbnRlcm5ldFNlcnZpY2UqKg0KDQoqKipC4bqjbmcgdOG6p24gc+G7kSwgdOG6p24gc3XhuqV0KioqDQoNCmBgYHtyfQ0KIyBM4bqtcCBi4bqjbmcgdOG6p24gc+G7kQ0KaXNfZiA8LSB0YWJsZSh0Y2MkSW50ZXJuZXRTZXJ2aWNlKQ0KDQojIEzhuq1wIGLhuqNuZyB04bqnbiBzdeG6pXQNCmlzX3AgPC0gcHJvcC50YWJsZShpc19mKSoxMDANCg0KIyBL4bq/dCBo4bujcCB0aMOgbmggbeG7mXQgYuG6o25nDQppcyA8LSBkYXRhLmZyYW1lKA0KICBDYXRlZ29yeSA9IG5hbWVzKGlzX2YpLA0KICBGcmVxdWVuY3kgPSBhcy52ZWN0b3IoaXNfZiksDQogIFBlcmNlbnRhZ2UgPSByb3VuZChhcy52ZWN0b3IoaXNfcCksIDIpDQopDQppcw0KYGBgDQoNCioqKkJp4buDdSDEkeG7kyoqKg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gaXMsIGFlcyh4ID0gJycsIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBDYXRlZ29yeSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGNvb3JkX3BvbGFyKCd5JykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudChGcmVxdWVuY3kvbGVuZ3RoKHRjYyRnZW5kZXIpKSksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIGxhYnModGl0bGUgPSAnRmlndXJlIDM6IEludGVybmV0IFNlcnZpY2Ugb2YgQ3VzdG9tZXJzJykgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAnYm9sZCcpKSAgDQpgYGANCg0KIyAqKlBI4bqmTiAzOiDGr+G7mkMgTMav4buiTkcgS0hP4bqiTkcgVsOAIEtJ4buCTSDEkOG7ik5IIEdJ4bqiIFRIVVnhur5UIENITyBU4bu2IEzhu4YqKg0KDQojIyAqKjMuMSBHZW5kZXIqKg0KDQpgYGB7cn0NCiMgU+G7kSBsxrDhu6NuZyBraMOhY2ggaMOgbmcgbuG7rw0KZm0gPC0gc3VtKHRjYyRnZW5kZXIgPT0gIkZlbWFsZSIpDQojIFThu5VuZyBz4buRIGtow6FjaCBow6BuZw0KdG90YWwgPC0gbGVuZ3RoKHRjYyRnZW5kZXIpDQojIEtp4buDbSDEkeG7i25oIHThu7cgbOG7hw0KcHJvcC50ZXN0KGZtLCB0b3RhbCwgcCA9IDAuNDk1LCBjb25mLmxldmVsID0gMC45NSkNCmBgYA0KDQrEkOG6t3QgZ2nhuqMgdGh1eeG6v3Q6IA0KJCQNClxsZWZ0XHsNClxiZWdpbnthcnJheX17bGx9DQpIXzA6ICYgXHRleHR7VOG7tyBs4buHIHRo4buxYyBz4buRIGtow6FjaCBow6BuZyBsw6AgbuG7ryB9ID0gMC40OTUgXFwNCkhfMTogJiBcdGV4dHtU4bu3IGzhu4cgdGjhu7FjIHPhu5Ega2jDoWNoIGjDoG5nIGzDoCBu4buvIH0gXG5lIDAuNDk1DQpcZW5ke2FycmF5fQ0KXHJpZ2h0Lg0KJCQNCg0KVGEgdGjhuqV5IHLhurFuZyBwX3ZhbHVlID0gMC45NzY5ID4gNSUsIG5naMSpYSBsw6Aga2jDtG5nIGPDsyDEkeG7pyBjxqEgc+G7nyDEkeG7gyBiw6FjIGLhu48gSDAuIE5naMSpYSBsw6AgdGjhu7FjIHThur8gdOG7tyBs4buHIHPhu5Ega2jDoWNoIGjDoG5nIG7hu68gbMOgIDQ5LjUlLCBuZ2/DoGkgcmEsIHThu7cgbOG7hyBraMOhY2ggaMOgbmcgbuG7ryBjw7JuIMSRxrDhu6NjIMaw4bubYyBsxrDhu6NuZyBsw6AgbuG6sW0gdHJvbmcga2hv4bqjbmcgNDguMzUtNTAuNyUuDQoNCiMjICoqMy4yIENodXJuKioNCg0KYGBge3J9DQojIFPhu5EgbMaw4bujbmcgTm8NCmNvbnRpbnVlIDwtIHN1bSh0Y2MkQ2h1cm4gPT0gIk5vIikNCiMgVOG7lW5nIHPhu5Ega2jDoWNoIGjDoG5nDQp0b3RhbCA8LSBsZW5ndGgodGNjJGdlbmRlcikNCiMgS2nhu4NtIMSR4buLbmggdOG7tyBs4buHDQpwcm9wLnRlc3QoY29udGludWUsIHRvdGFsLCBwID0gMC43MywgY29uZi5sZXZlbCA9IDAuOTUpDQpgYGANCg0KxJDhurd0IGdp4bqjIHRodXnhur90OiANCiQkDQpcbGVmdFx7DQpcYmVnaW57YXJyYXl9e2xsfQ0KSF8wOiAmIFx0ZXh0e1Thu7cgbOG7hyB0aOG7sWMgc+G7kSBraMOhY2ggaMOgbmcgdGnhur9wIHThu6VjIHPhu60gZOG7pW5nIGThu4tjaCB24bulIH0gPSAwLjczIFxcDQpIXzE6ICYgXHRleHR7VOG7tyBs4buHIHRo4buxYyBz4buRIGtow6FjaCBow6BuZyB0aeG6v3AgdOG7pWMgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgfSBcbmUgMC43Mw0KXGVuZHthcnJheX0NClxyaWdodC4NCiQkDQoNClRhIHRo4bqleSBy4bqxbmcgcF92YWx1ZSA9IDAuMzg4OCA+IDUlLCBuZ2jEqWEgbMOgIGtow7RuZyBjw7MgxJHhu6cgY8ahIHPhu58gxJHhu4MgYsOhYyBi4buPIEgwLiBOZ2jEqWEgbMOgIHRo4buxYyB04bq/IHThu7cgbOG7hyBz4buRIGtow6FjaCBow6BuZyBjaOG7jW4gdGnhur9wIHThu6VjIHPhu60gZOG7pW5nIGThu4tjaCB24bulIGzDoCA3MyUsIG5nb8OgaSByYSwgdOG7tyBs4buHIGtow6FjaCBow6BuZyB0aeG6v3AgdOG7pWMgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgY8OybiDEkcaw4bujYyDGsOG7m2MgbMaw4bujbmcgbMOgIG7hurFtIHRyb25nIGtob+G6o25nIDcyLjQxLTc0LjQ4JS4NCg0KIyAqKlBI4bqmTiA0OiBQSMOCTiBUw41DSCBN4buQSSBRVUFOIEjhu4YgR0nhu65BIEPDgUMgQknhur5OKioNCg0KKipgSW50ZXJuZXRTZXJ2aWNlYCB2w6AgYGNodXJuYCoqDQoNCioqKkLhuqNuZyB04bqnbiBzdeG6pXQgY2jDqW8qKioNCg0KYGBge3J9DQppc19jaHVybiA8LSB0YWJsZSh0Y2MkSW50ZXJuZXRTZXJ2aWNlLHRjYyRDaHVybikNCmlzX2NodXJuDQpgYGANCg0KIyMgKio0LjIgQmnhu4N1IMSR4buTKioNCg0KYGBge3J9DQpkZl9pc19jaHVybiA8LSBhcy5kYXRhLmZyYW1lKGlzX2NodXJuKQ0KY29sbmFtZXMoZGZfaXNfY2h1cm4pIDwtIGMoIkludGVybmV0IFNlcnZpY2UiLCJDaHVybiIsIkZyZXEiKQ0KZ2dwbG90KGRmX2lzX2NodXJuLCBhZXMoeCA9IENodXJuLCB5ID0gRnJlcSwgZmlsbCA9IGBJbnRlcm5ldCBTZXJ2aWNlYCkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSArDQogIGxhYnModGl0bGUgPSAnRmlndXJlIDQnLCB4ID0gJ0NodXJuJywgeSA9ICdGcmVxdWVuY3knKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkNCmBgYA0KDQojIyAqKjQuMyBLaeG7g20gxJHhu4tuaCBDaGktYsOsbmggcGjGsMahbmcqKg0KDQpgYGB7cn0NCmNoaXNxLnRlc3QoaXNfY2h1cm4pDQpgYGANCsSQ4bq3dCBnaeG6oyB0aHV54bq/dDoNCiQkDQpcbGVmdFx7DQpcYmVnaW57YXJyYXl9e2xsfQ0KSF8wOiAmIFx0ZXh0e0tow7RuZyBjw7MgbeG7kWkgcXVhbiBo4buHIGdp4buvYSBoYWkgYmnhur9uIHBow6JuIGxv4bqhaSB9IFxcDQpIXzE6ICYgXHRleHR7Q8OzIHThu5NuIHThuqFpIG3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgaGFpIGJp4bq/biBwaMOibiBsb+G6oWkgfQ0KXGVuZHthcnJheX0NClxyaWdodC4NCiQkDQoNClRhIHRo4bqleSBr4bq/dCBxdeG6oyBraeG7g20gxJHhu4tuaCBjaG8gcmEgZ2nDoSB0cuG7iyBwX3ZhbHVlID0gMC4wMDAgPCA1JSwgbmdoxKlhIGzDoCDEkeG7pyBjxqEgc+G7nyDEkeG7gyBiw6FjIGLhu48gJEhfMCQuIFbhuq15IG3hu5FpIHF1YW4gaOG7hyBnaeG7r2EgbG/huqFpIGThu4tjaCB24bulIHbDoCBxdXnhur90IMSR4buLbmggbmfGsG5nIHPhu60gZOG7pW5nIGThu4tjaCB24bulIGzDoCBjw7MgbGnDqm4gcXVhbiDEkeG6v24gbmhhdS4NCg0KIyMgKio0LjQgVMOtbmggUmVsYXRpdmUgUmlzayAtIFJSKioNCg0KYGBge3J9DQpsaWJyYXJ5KGVwaXRvb2xzKQ0KcnIgPC0gcmlza3JhdGlvKGlzX2NodXJuKQ0KcnINCmBgYA0KVuG7m2kgbmjDs20gRmliZXIgb3B0aWMgc28gduG7m2kgRFNMLCB0YSBjw7MgZ2nDoSB0cuG7iyBSUiA9IDIuMjEgdsOgIG7hurFtIHRyb25nIGtob+G6o25nIDIuMDItMi40MiB24bubaSDEkeG7mSB0aW4gY+G6rXkgOTUlLCBuZ2jEqWEgbMOgIHThu7cgbOG7hyBraMOhY2ggaMOgbmcgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgRmliZXIgb3B0aWMgY8OzIHThu7cgbOG7hyBuZ8awbmcgc+G7rSBk4bulbmcgZOG7i2NoIHbhu6UgY2FvIGjGoW4gaOG6s24gc28gduG7m2kgY8OhYyBraMOhY2ggaMOgbmcgZMO5bmcgRFNMLiBD4bulIHRo4buDLCBuaMOzbSBz4butIGThu6VuZyBGaWJlciBvcHRpYyBjw7MgdOG7tyBs4buHIGThu6tuZyBz4butIGThu6VuZyBjYW8gaMahbiAxMjElIHNvIHbhu5tpIG5ow7NtIERTTC4NCg0KVuG7m2kgbmjDs20ga2jDtG5nIGTDuW5nIHNvIHbhu5tpIERTTCwgdGEgY8OzIGdpw6EgdHLhu4sgUlIgPSAwLjM5IHbDoCBu4bqxbSB0cm9uZyBraG/huqNuZyAwLjMyLTAuNDcgduG7m2kgxJHhu5kgdGluIGPhuq15IDk1JSwgbmdoxKlhIGzDoCB04bu3IGzhu4cga2jDoWNoIGjDoG5nIGtow7RuZyBkw7luZyBk4buLY2ggduG7pSBjw7MgdOG7tyBs4buHIG5nxrBuZyBz4butIGThu6VuZyBk4buLY2ggduG7pSB0aOG6pXAgaMahbiBzbyB24bubaSBjw6FjIGtow6FjaCBow6BuZyBkw7luZyBEU0wuIEPhu6UgdGjhu4MsIG5ow7NtIGtow7RuZyBkw7luZyBpbnRlcm5ldCBjw7MgdOG7tyBs4buHIGThu6tuZyBz4butIGThu6VuZyB0aOG6pXAgaMahbiBzbyB24bubaSBuaMOzbSBEU0wgbMOgIDYxJS4NCg0KDQojIyAqKjQuNSBUw61uaCBPZGRzIFJhdGlvIC0gT1IqKg0KDQpgYGB7cn0NCm9yIDwtIG9kZHNyYXRpbyhpc19jaHVybikNCm9yDQpgYGANCg0K4bueIG5ow7NtIEZpYmVyIG9wdGljLCBnacOhIHRy4buLIE9SID0gMy4wOCB2w6AgbuG6sW0gdHJvbmcga2hv4bqjbmcgMi43Mi0zLjQ5IHbhu5tpIMSR4buZIHRpbiBj4bqteSA5NSUgY2hvIHRo4bqleSB2aeG7h2Mga2jDoWNoIGjDoG5nIHPhu60gZOG7pW5nIEZpYmVyIG9wdGljIGPDsyB04bu3IGzhu4cgZOG7q25nIHPhu60gZOG7pW5nIGThu4tjaCB24bulIGNhbyBoxqFuIGfhuqVwIDMgbOG6p24gc28gduG7m2kgRFNMLg0KDQrhu54gbmjDs20ga2jDtG5nIHPhu60gZOG7pW5nIGThu4tjaCB24bulLCBnacOhIHRy4buLIE9SID0gMC4zNCB2w6AgbuG6sW0gdHJvbmcga2hv4bqjbmcgMC4yNy0wLjQyIHbhu5tpIMSR4buZIHRpbiBj4bqteSA5NSUgY2hvIHRo4bqleSB2aeG7h2Mga2jDoWNoIGjDoG5nIGtow7RuZyBz4butIGThu6VuZyBk4buLY2ggduG7pSBjw7MgdOG7tyBs4buHIGThu6tuZyBz4butIGThu6VuZyDDrXQgaMahbiBo4bqzbiBzbyB24bubaSBEU0wuDQoNCg0KDQo=