Tên: Mai Huy
MSSV: 43.01.104.065
Số thứ tự: 08
# Load thư viện ISLR chứa tập dữ liệu Auto
library(ISLR)
# attach dùng để khiến cho những biến feature trong dữ liệu có sẵn trong Rstudio theo tên
attach(Auto)
The following objects are masked from Auto (pos = 3):
acceleration, cylinders, displacement, horsepower, mpg, name, origin, weight, year
Câu a) Tạo ra cột mpg01 trong dữ liệu Auto
# Tạo một vecto gồm 392 giá trị = 0 tương trị SỐ lượng quan sát trong dữ liệu AUto
mpg01 <- rep(0, length(mpg))
#Chuyển các thành phần sang = 1 khi giá trị mpg > mức trung vị của nó
mpg01[mpg > median(mpg)] <- 1
# Tạo 1 dữ liệu Auto mới khi thêm biến mpg01 vào
Auto <- data.frame(Auto, mpg01)
Câu b) Mô tả mối tương giữa biến mpg01 và các biến khác
# Ma trận tương quan giữa các biến khi bỏ đi biến định tính Name
cor(Auto[, -9])
mpg cylinders displacement horsepower weight acceleration year origin mpg01
mpg 1.0000000 -0.7776175 -0.8051269 -0.7784268 -0.8322442 0.4233285 0.5805410 0.5652088 0.8369392
cylinders -0.7776175 1.0000000 0.9508233 0.8429834 0.8975273 -0.5046834 -0.3456474 -0.5689316 -0.7591939
displacement -0.8051269 0.9508233 1.0000000 0.8972570 0.9329944 -0.5438005 -0.3698552 -0.6145351 -0.7534766
horsepower -0.7784268 0.8429834 0.8972570 1.0000000 0.8645377 -0.6891955 -0.4163615 -0.4551715 -0.6670526
weight -0.8322442 0.8975273 0.9329944 0.8645377 1.0000000 -0.4168392 -0.3091199 -0.5850054 -0.7577566
acceleration 0.4233285 -0.5046834 -0.5438005 -0.6891955 -0.4168392 1.0000000 0.2903161 0.2127458 0.3468215
year 0.5805410 -0.3456474 -0.3698552 -0.4163615 -0.3091199 0.2903161 1.0000000 0.1815277 0.4299042
origin 0.5652088 -0.5689316 -0.6145351 -0.4551715 -0.5850054 0.2127458 0.1815277 1.0000000 0.5136984
mpg01 0.8369392 -0.7591939 -0.7534766 -0.6670526 -0.7577566 0.3468215 0.4299042 0.5136984 1.0000000
# Ma trận biểu đồ phân tán khi bỏ đi biến định tính Name
pairs(Auto[, -9])

# Hiển thị các biểu đồ ở cửa sổ 2x3
par(mfrow=c(2,3))
# Tạo ra biểu đồ hộp với x= mpg01 và y= cylinders
boxplot(cylinders ~ mpg01, data = Auto, main = "Cylinders vs mpg01")
# Tạo ra biểu đồ hộp với x= mpg01 và y= displacement
boxplot(displacement ~ mpg01, data = Auto, main = "Displacement vs mpg01")
# Tạo ra biểu đồ hộp với x= mpg01 và y= horsepower
boxplot(horsepower ~ mpg01, data = Auto, main = "Horsepower vs mpg01")
# Tạo ra biểu đồ hộp với x= mpg01 và y= weight
boxplot(weight ~ mpg01, data = Auto, main = "Weight vs mpg01")
# Tạo ra biểu đồ hộp với x= mpg01 và y= acceleration
boxplot(acceleration ~ mpg01, data = Auto, main = "Acceleration vs mpg01")
# Tạo ra biểu đồ hộp với x= mpg01 và y= year
boxplot(year ~ mpg01, data = Auto, main = "Year vs mpg01")

CHúng ta thấy rằng có mối liên hệ giữa biến mpg01 với các biến cylinders, displacement, horsepower, weight do chỉ số tương quan của mpg01 với các biến này tương đối lớn.
Câu c) Chia tập train và test
#Vecto train gồm 392 phần từ tương ướng với tập dữ liệu quan sát, dòng nào trong data có số năm chẵn sẽ trả về true, còn lại trả về false
train <- (year %% 2 == 0)
# Tập train là tập trong dữ liệu chứa năm chẵn
Auto.train <- Auto[train, ]
# Tập test là tập trong dữ liệu chứa năm lẻ
Auto.test <- Auto[!train, ]
# Tạo ra một vector gồm 182 giá trị mpg01 = 1 hoặc 0 cho những năm lẻ
mpg01.test <- mpg01[!train]
Câu d) Áp dụng LDA
# Load thư viện MASS
library(MASS)
# Phân tích khác biệt tuyến tính với 4 biến đầu vào có nhiều mối quan hệ với mpg01 nhất là cylinders, weight, displacement, horsepower trong tập dữ liệu của những năm chẵn
fit.lda <- lda(mpg01 ~ cylinders + weight + displacement + horsepower, data = Auto, subset = train)
# Thông tin khác biệt tuyến tính
fit.lda
Call:
lda(mpg01 ~ cylinders + weight + displacement + horsepower, data = Auto,
subset = train)
Prior probabilities of groups:
0 1
0.4571429 0.5428571
Group means:
cylinders weight displacement horsepower
0 6.812500 3604.823 271.7396 133.14583
1 4.070175 2314.763 111.6623 77.92105
Coefficients of linear discriminants:
LD1
cylinders -0.6741402638
weight -0.0011465750
displacement 0.0004481325
horsepower 0.0059035377
Kết quả hàm lda() chỉ ra rẳng 45.71% dữ liệu huấn luyện có mpg01=0
Đồng thời cho biết giá trị trung bình của mỗi nhóm biến đầu (cylinders, weight, displacement, horsepower) vào tương ứng với mỗi phân loại 1 và 0
Hàm lda() cũng cung cấp những hệ số phân biệt của các biến đầu vào , nếu -0.6741402638 x cylinders + -0.0011465750 x weight + 0.0004481325 x displacement + 0.0059035377 x horsepower lớn thì LDA sẽ dự đoán lượng khí gas cao (mpg01 = 1). Nếu nhỏ thì sẽ dự đoán lượng khí gas thấp (mpg01=0)
# Hàm predict dùng để dự đoán xác suất lượng khí gas cao (mpg01 = 1) với tập data truyền vào là tập test chỉ chứa các năm lẻ
pred.lda <- predict(fit.lda, Auto.test)
# Tên các thuộc tính trong lda.pred
names(pred.lda)
[1] "class" "posterior" "x"
class chứa dự đoán của LDA về khả năng lượng khí gas cao hay thấp cho 392 dòng dữ liệu của năm lẻ
posterior là xác suất hậu nghiệm, xác suất dự đoán lượng khí gas cao hay thấp cho 392 dòng dữ liệu của năm lẻ
x là hệ số khác biệt tuyết tính (linear discriminants)
# Dùng hàm table() để tạo ra một ma trận để quyết định xem có bao nhiêu quan sát được phân loại đúng, bao nhiêu bị phân loại sai
table(pred.lda$class, mpg01.test)
mpg01.test
0 1
0 86 9
1 14 73
# Dự đoán %số dòng dự đoán sai
mean(pred.lda$class != mpg01.test)
[1] 0.1263736
CHúng ta kết luận là tỉ lệ dự đoán sai của LDA là khoảng 12,63%
Câu e) Áp dụng QDA
# Phân tích khác biệt bình phương với 4 biến đầu vào có nhiều mối quan hệ với mpg01 nhất là cylinders, weight, displacement, horsepower trong tập dữ liệu của những năm chẵn
fit.qda <- qda(mpg01 ~ cylinders + weight + displacement + horsepower, data = Auto, subset = train)
fit.qda
Call:
qda(mpg01 ~ cylinders + weight + displacement + horsepower, data = Auto,
subset = train)
Prior probabilities of groups:
0 1
0.4571429 0.5428571
Group means:
cylinders weight displacement horsepower
0 6.812500 3604.823 271.7396 133.14583
1 4.070175 2314.763 111.6623 77.92105
Kết quả hàm qda() chỉ ra rẳng 45.71% dữ liệu huấn luyện có mpg01=0 tương tự như LDA
Đồng thời cho biết giá trị trung bình của mỗi nhóm biến đầu (cylinders, weight, displacement, horsepower) vào tương ứng với mỗi phân loại 1 và 0
# Hàm predict dùng để dự đoán xác suất lượng khí gas cao (mpg01 = 1) với tập data truyền vào là tập test chỉ chứa các năm lẻ
pred.qda <- predict(fit.qda, Auto.test)
# Dùng hàm table() để tạo ra một ma trận để quyết định xem có bao nhiêu quan sát được phân loại đúng, bao nhiêu bị phân loại sai
table(pred.qda$class, mpg01.test)
mpg01.test
0 1
0 89 13
1 11 69
# Dự đoán %số dòng dự đoán sai
mean(pred.qda$class != mpg01.test)
[1] 0.1318681
CHúng ta kết luận là tỉ lệ dự đoán sai của QDA là khoảng 13,186%
Câu f) Áp dụng Logistic Regression
Chúng ta sẽ fit mô hình logistic Regression để dự đoán biến đầu ra mpg01 và sử dụng các biến đầu vào là cylinders, weight, displacement và horsepower. Hàm glm() và đưa vào biến family =binomial dùng để chạy 1 mô hình Logistic Regression.
# Fit mô hình Logistic Regresion để dự đoán biến đầu ra mpg01 trong dữ liệu AUto chỉ chứa các năm chẵn
fit.glm <- glm(mpg01 ~ cylinders + weight + displacement + horsepower, data = Auto, family = binomial, subset = train)
# Hàm predict dùng để dự đoán xác suất lượng khí gas cao (mpg01 = 1), type = "response" để xuất ra xác xuất theo dạng P(Y = 1|X)
probs <- predict(fit.glm, Auto.test, type = "response")
# Tạo một vecto gồm 392 thành phần = 0 tương ứng với số quan sát của những năm lẻ
pred.glm <- rep(0, length(probs))
#Chuyển các thành phần sang 1 khi xác suất dự đoán lớn hơn 0.5
pred.glm[probs > 0.5] <- 1
table(pred.glm, mpg01.test)
mpg01.test
pred.glm 0 1
0 89 11
1 11 71
# Dự đoán %số dòng dự đoán sai
mean(pred.glm != mpg01.test)
[1] 0.1208791
CHúng ta kết luận là tỉ lệ dự đoán sai của Logistic Regression là khoảng 12,08%
LS0tDQp0aXRsZTogIkLDoGkgdOG6rXAgMl9UdeG6p24gNSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCg0KIyMjIFTDqm46IE1haSBIdXkNCiMjIyBNU1NWOiA0My4wMS4xMDQuMDY1DQojIyMgU+G7kSB0aOG7qSB04buxOiAwOA0KDQpgYGB7cn0NCiMgTG9hZCB0aMawIHZp4buHbiBJU0xSIGNo4bupYSB04bqtcCBk4buvIGxp4buHdSBBdXRvDQpsaWJyYXJ5KElTTFIpDQojIGF0dGFjaCBkw7luZyDEkeG7gyBraGnhur9uIGNobyBuaOG7r25nIGJp4bq/biBmZWF0dXJlIHRyb25nIGThu68gbGnhu4d1IGPDsyBz4bq1biB0cm9uZyBSc3R1ZGlvIHRoZW8gdMOqbg0KYXR0YWNoKEF1dG8pDQpgYGANCg0KIyMgQ8OidSBhKSBU4bqhbyByYSBj4buZdCBtcGcwMSB0cm9uZyBk4buvIGxp4buHdSBBdXRvDQoNCmBgYHtyfQ0KIyBU4bqhbyBt4buZdCB2ZWN0byBn4buTbSAzOTIgZ2nDoSB0cuG7iyA9IDAgdMawxqFuZyB0cuG7iyBT4buQIGzGsOG7o25nIHF1YW4gc8OhdCB0cm9uZyBk4buvIGxp4buHdSBBVXRvDQptcGcwMSA8LSByZXAoMCwgbGVuZ3RoKG1wZykpDQpgYGANCg0KYGBge3J9DQojQ2h1eeG7g24gY8OhYyB0aMOgbmggcGjhuqduIHNhbmcgPSAxIGtoaSBnacOhIHRy4buLIG1wZyA+IG3hu6ljIHRydW5nIHbhu4sgY+G7p2EgbsOzDQptcGcwMVttcGcgPiBtZWRpYW4obXBnKV0gPC0gMQ0KYGBgDQoNCg0KYGBge3J9DQojIFThuqFvIDEgZOG7ryBsaeG7h3UgQXV0byBt4bubaSBraGkgdGjDqm0gYmnhur9uIG1wZzAxIHbDoG8NCkF1dG8gPC0gZGF0YS5mcmFtZShBdXRvLCBtcGcwMSkNCmBgYA0KDQojIyBDw6J1IGIpIE3DtCB04bqjIG3hu5FpIHTGsMahbmcgZ2nhu69hIGJp4bq/biBtcGcwMSB2w6AgY8OhYyBiaeG6v24ga2jDoWMNCg0KYGBge3J9DQojIE1hIHRy4bqtbiB0xrDGoW5nIHF1YW4gZ2nhu69hIGPDoWMgYmnhur9uIGtoaSBi4buPIMSRaSBiaeG6v24gxJHhu4tuaCB0w61uaCBOYW1lDQpjb3IoQXV0b1ssIC05XSkNCmBgYA0KDQpgYGB7cn0NCiMgTWEgdHLhuq1uIGJp4buDdSDEkeG7kyBwaMOibiB0w6FuIGtoaSBi4buPIMSRaSBiaeG6v24gxJHhu4tuaCB0w61uaCBOYW1lDQpwYWlycyhBdXRvWywgLTldKQ0KYGBgDQoNCmBgYHtyfQ0KIyBIaeG7g24gdGjhu4sgY8OhYyBiaeG7g3UgxJHhu5Mg4bufIGPhu61hIHPhu5UgMngzDQpwYXIobWZyb3c9YygyLDMpKQ0KIyBU4bqhbyByYSBiaeG7g3UgxJHhu5MgaOG7mXAgduG7m2kgeD0gbXBnMDEgdsOgIHk9IGN5bGluZGVycw0KYm94cGxvdChjeWxpbmRlcnMgfiBtcGcwMSwgZGF0YSA9IEF1dG8sIG1haW4gPSAiQ3lsaW5kZXJzIHZzIG1wZzAxIikNCiMgVOG6oW8gcmEgYmnhu4N1IMSR4buTIGjhu5lwIHbhu5tpIHg9IG1wZzAxIHbDoCB5PSBkaXNwbGFjZW1lbnQNCmJveHBsb3QoZGlzcGxhY2VtZW50IH4gbXBnMDEsIGRhdGEgPSBBdXRvLCBtYWluID0gIkRpc3BsYWNlbWVudCB2cyBtcGcwMSIpDQojIFThuqFvIHJhIGJp4buDdSDEkeG7kyBo4buZcCB24bubaSB4PSBtcGcwMSB2w6AgeT0gaG9yc2Vwb3dlcg0KYm94cGxvdChob3JzZXBvd2VyIH4gbXBnMDEsIGRhdGEgPSBBdXRvLCBtYWluID0gIkhvcnNlcG93ZXIgdnMgbXBnMDEiKQ0KIyBU4bqhbyByYSBiaeG7g3UgxJHhu5MgaOG7mXAgduG7m2kgeD0gbXBnMDEgdsOgIHk9IHdlaWdodA0KYm94cGxvdCh3ZWlnaHQgfiBtcGcwMSwgZGF0YSA9IEF1dG8sIG1haW4gPSAiV2VpZ2h0IHZzIG1wZzAxIikNCiMgVOG6oW8gcmEgYmnhu4N1IMSR4buTIGjhu5lwIHbhu5tpIHg9IG1wZzAxIHbDoCB5PSBhY2NlbGVyYXRpb24NCmJveHBsb3QoYWNjZWxlcmF0aW9uIH4gbXBnMDEsIGRhdGEgPSBBdXRvLCBtYWluID0gIkFjY2VsZXJhdGlvbiB2cyBtcGcwMSIpDQojIFThuqFvIHJhIGJp4buDdSDEkeG7kyBo4buZcCB24bubaSB4PSBtcGcwMSB2w6AgeT0geWVhcg0KYm94cGxvdCh5ZWFyIH4gbXBnMDEsIGRhdGEgPSBBdXRvLCBtYWluID0gIlllYXIgdnMgbXBnMDEiKQ0KYGBgDQoNCkNIw7puZyB0YSB0aOG6pXkgcuG6sW5nIGPDsyBt4buRaSBsacOqbiBo4buHIGdp4buvYSBiaeG6v24gbXBnMDEgduG7m2kgY8OhYyBiaeG6v24gY3lsaW5kZXJzLCBkaXNwbGFjZW1lbnQsIGhvcnNlcG93ZXIsIHdlaWdodCBkbyBjaOG7iSBz4buRIHTGsMahbmcgcXVhbiBj4bunYSBtcGcwMSB24bubaSBjw6FjIGJp4bq/biBuw6B5IHTGsMahbmcgxJHhu5FpIGzhu5tuLg0KDQojIyBDw6J1IGMpIENoaWEgdOG6rXAgdHJhaW4gdsOgIHRlc3QNCg0KYGBge3J9DQojVmVjdG8gdHJhaW4gZ+G7k20gMzkyIHBo4bqnbiB04burIHTGsMahbmcgxrDhu5tuZyB24bubaSB04bqtcCBk4buvIGxp4buHdSBxdWFuIHPDoXQsIGTDsm5nIG7DoG8gdHJvbmcgZGF0YSBjw7Mgc+G7kSBuxINtIGNo4bq1biBz4bq9IHRy4bqjIHbhu4EgdHJ1ZSwgY8OybiBs4bqhaSB0cuG6oyB24buBIGZhbHNlDQp0cmFpbiA8LSAoeWVhciAlJSAyID09IDApDQpgYGANCg0KDQpgYGB7cn0NCiMgVOG6rXAgdHJhaW4gbMOgIHThuq1wIHRyb25nIGThu68gbGnhu4d1IGNo4bupYSBuxINtIGNo4bq1bg0KQXV0by50cmFpbiA8LSBBdXRvW3RyYWluLCBdDQpgYGANCg0KYGBge3J9DQojIFThuq1wIHRlc3QgbMOgIHThuq1wIHRyb25nIGThu68gbGnhu4d1IGNo4bupYSBuxINtIGzhursNCkF1dG8udGVzdCA8LSBBdXRvWyF0cmFpbiwgXQ0KYGBgDQoNCg0KYGBge3J9DQojIFThuqFvIHJhIG3hu5l0IHZlY3RvciBn4buTbSAxODIgZ2nDoSB0cuG7iyBtcGcwMSA9IDEgaG/hurdjIDAgY2hvIG5o4buvbmcgbsSDbSBs4bq7DQptcGcwMS50ZXN0IDwtIG1wZzAxWyF0cmFpbl0NCmBgYA0KDQojIyBDw6J1IGQpIMOBcCBk4bulbmcgTERBDQoNCmBgYHtyfQ0KIyBMb2FkIHRoxrAgdmnhu4duIE1BU1MNCmxpYnJhcnkoTUFTUykNCiMgUGjDom4gdMOtY2gga2jDoWMgYmnhu4d0IHR1eeG6v24gdMOtbmggduG7m2kgNCBiaeG6v24gxJHhuqd1IHbDoG8gY8OzIG5oaeG7gXUgbeG7kWkgcXVhbiBo4buHIHbhu5tpIG1wZzAxIG5o4bqldCBsw6AgY3lsaW5kZXJzLCB3ZWlnaHQsIGRpc3BsYWNlbWVudCwgaG9yc2Vwb3dlciB0cm9uZyB04bqtcCBk4buvIGxp4buHdSBj4bunYSBuaOG7r25nIG7Eg20gY2jhurVuDQpmaXQubGRhIDwtIGxkYShtcGcwMSB+IGN5bGluZGVycyArIHdlaWdodCArIGRpc3BsYWNlbWVudCArIGhvcnNlcG93ZXIsIGRhdGEgPSBBdXRvLCBzdWJzZXQgPSB0cmFpbikNCmBgYA0KDQoNCmBgYHtyfQ0KIyBUaMO0bmcgdGluIGtow6FjIGJp4buHdCB0dXnhur9uIHTDrW5oDQpmaXQubGRhDQpgYGANCg0KS+G6v3QgcXXhuqMgaMOgbSBsZGEoKSBjaOG7iSByYSBy4bqzbmcgNDUuNzElIGThu68gbGnhu4d1IGh14bqlbiBsdXnhu4duIGPDsyBtcGcwMT0wDQoNCsSQ4buTbmcgdGjhu51pIGNobyBiaeG6v3QgZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBj4bunYSBt4buXaSBuaMOzbSBiaeG6v24gxJHhuqd1IChjeWxpbmRlcnMsIHdlaWdodCwgZGlzcGxhY2VtZW50LCBob3JzZXBvd2VyKSB2w6BvIHTGsMahbmcg4bupbmcgduG7m2kgbeG7l2kgcGjDom4gbG/huqFpIDEgdsOgIDANCg0KSMOgbSBsZGEoKSBjxaluZyBjdW5nIGPhuqVwIG5o4buvbmcgaOG7hyBz4buRIHBow6JuIGJp4buHdCBj4bunYSBjw6FjIGJp4bq/biDEkeG6p3UgdsOgbyAsIG7hur91IC0wLjY3NDE0MDI2MzggeCBjeWxpbmRlcnMgKyAtMC4wMDExNDY1NzUwIHggd2VpZ2h0ICsgIDAuMDAwNDQ4MTMyNSB4IGRpc3BsYWNlbWVudCArIDAuMDA1OTAzNTM3NyB4IGhvcnNlcG93ZXIgbOG7m24gdGjDrCBMREEgc+G6vSBk4buxIMSRb8OhbiBsxrDhu6NuZyBraMOtIGdhcyBjYW8gKG1wZzAxID0gMSkuIE7hur91IG5o4buPIHRow6wgc+G6vSBk4buxIMSRb8OhbiBsxrDhu6NuZyBraMOtIGdhcyB0aOG6pXAgKG1wZzAxPTApDQoNCmBgYHtyfQ0KIyBIw6BtIHByZWRpY3QgZMO5bmcgxJHhu4MgZOG7sSDEkW/DoW4geMOhYyBzdeG6pXQgbMaw4bujbmcga2jDrSBnYXMgY2FvIChtcGcwMSA9IDEpIHbhu5tpIHThuq1wIGRhdGEgdHJ1eeG7gW4gdsOgbyBsw6AgdOG6rXAgdGVzdCBjaOG7iSBjaOG7qWEgY8OhYyBuxINtIGzhursNCnByZWQubGRhIDwtIHByZWRpY3QoZml0LmxkYSwgQXV0by50ZXN0KQ0KYGBgDQoNCmBgYHtyfQ0KIyBUw6puIGPDoWMgdGh14buZYyB0w61uaCB0cm9uZyBsZGEucHJlZA0KbmFtZXMocHJlZC5sZGEpDQpgYGANCg0KY2xhc3MgY2jhu6lhIGThu7EgxJFvw6FuIGPhu6dhIExEQSB24buBIGto4bqjIG7Eg25nIGzGsOG7o25nIGtow60gZ2FzIGNhbyBoYXkgdGjhuqVwIGNobyAzOTIgZMOybmcgZOG7ryBsaeG7h3UgY+G7p2EgbsSDbSBs4bq7DQoNCnBvc3RlcmlvciBsw6AgeMOhYyBzdeG6pXQgaOG6rXUgbmdoaeG7h20sIHjDoWMgc3XhuqV0IGThu7EgxJFvw6FuIGzGsOG7o25nIGtow60gZ2FzIGNhbyBoYXkgdGjhuqVwIGNobyAzOTIgZMOybmcgZOG7ryBsaeG7h3UgY+G7p2EgbsSDbSBs4bq7DQoNCnggbMOgIGjhu4cgc+G7kSBraMOhYyBiaeG7h3QgdHV54bq/dCB0w61uaCAobGluZWFyIGRpc2NyaW1pbmFudHMpDQoNCmBgYHtyfQ0KIyBEw7luZyBow6BtIHRhYmxlKCkgxJHhu4MgdOG6oW8gcmEgbeG7mXQgbWEgdHLhuq1uIMSR4buDIHF1eeG6v3QgxJHhu4tuaCB4ZW0gY8OzIGJhbyBuaGnDqnUgcXVhbiBzw6F0IMSRxrDhu6NjIHBow6JuIGxv4bqhaSDEkcO6bmcsIGJhbyBuaGnDqnUgYuG7iyBwaMOibiBsb+G6oWkgc2FpDQp0YWJsZShwcmVkLmxkYSRjbGFzcywgbXBnMDEudGVzdCkNCmBgYA0KDQpgYGB7cn0NCiMgROG7sSDEkW/DoW4gJXPhu5EgZMOybmcgZOG7sSDEkW/DoW4gc2FpDQptZWFuKHByZWQubGRhJGNsYXNzICE9IG1wZzAxLnRlc3QpDQpgYGANCg0KQ0jDum5nIHRhIGvhur90IGx14bqtbiBsw6AgdOG7iSBs4buHIGThu7EgxJFvw6FuIHNhaSBj4bunYSBMREEgbMOgIGtob+G6o25nIDEyLDYzJQ0KDQojIyBDw6J1IGUpIMOBcCBk4bulbmcgUURBDQoNCmBgYHtyfQ0KIyBQaMOibiB0w61jaCBraMOhYyBiaeG7h3QgYsOsbmggcGjGsMahbmcgduG7m2kgNCBiaeG6v24gxJHhuqd1IHbDoG8gY8OzIG5oaeG7gXUgbeG7kWkgcXVhbiBo4buHIHbhu5tpIG1wZzAxIG5o4bqldCBsw6AgY3lsaW5kZXJzLCB3ZWlnaHQsIGRpc3BsYWNlbWVudCwgaG9yc2Vwb3dlciB0cm9uZyB04bqtcCBk4buvIGxp4buHdSBj4bunYSBuaOG7r25nIG7Eg20gY2jhurVuDQpmaXQucWRhIDwtIHFkYShtcGcwMSB+IGN5bGluZGVycyArIHdlaWdodCArIGRpc3BsYWNlbWVudCArIGhvcnNlcG93ZXIsIGRhdGEgPSBBdXRvLCBzdWJzZXQgPSB0cmFpbikNCmBgYA0KDQpgYGB7cn0NCiMgVGjDtG5nIHRpbiBraMOhYyBiaeG7h3QgYsOsbmggcGjGsMahbmcNCmZpdC5xZGENCmBgYA0KDQpL4bq/dCBxdeG6oyBow6BtIHFkYSgpIGNo4buJIHJhIHLhurNuZyA0NS43MSUgZOG7ryBsaeG7h3UgaHXhuqVuIGx1eeG7h24gY8OzIG1wZzAxPTAgdMawxqFuZyB04buxIG5oxrAgTERBDQoNCsSQ4buTbmcgdGjhu51pIGNobyBiaeG6v3QgZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBj4bunYSBt4buXaSBuaMOzbSBiaeG6v24gxJHhuqd1IChjeWxpbmRlcnMsIHdlaWdodCwgZGlzcGxhY2VtZW50LCBob3JzZXBvd2VyKSB2w6BvIHTGsMahbmcg4bupbmcgduG7m2kgbeG7l2kgcGjDom4gbG/huqFpIDEgdsOgIDANCg0KYGBge3J9DQojIEjDoG0gcHJlZGljdCBkw7luZyDEkeG7gyBk4buxIMSRb8OhbiB4w6FjIHN14bqldCBsxrDhu6NuZyBraMOtIGdhcyBjYW8gKG1wZzAxID0gMSkgduG7m2kgdOG6rXAgZGF0YSB0cnV54buBbiB2w6BvIGzDoCB04bqtcCB0ZXN0IGNo4buJIGNo4bupYSBjw6FjIG7Eg20gbOG6uw0KcHJlZC5xZGEgPC0gcHJlZGljdChmaXQucWRhLCBBdXRvLnRlc3QpDQpgYGANCg0KDQpgYGB7cn0NCiMgRMO5bmcgaMOgbSB0YWJsZSgpIMSR4buDIHThuqFvIHJhIG3hu5l0IG1hIHRy4bqtbiDEkeG7gyBxdXnhur90IMSR4buLbmggeGVtIGPDsyBiYW8gbmhpw6p1IHF1YW4gc8OhdCDEkcaw4bujYyBwaMOibiBsb+G6oWkgxJHDum5nLCBiYW8gbmhpw6p1IGLhu4sgcGjDom4gbG/huqFpIHNhaQ0KdGFibGUocHJlZC5xZGEkY2xhc3MsIG1wZzAxLnRlc3QpDQpgYGANCg0KDQpgYGB7cn0NCiMgROG7sSDEkW/DoW4gJXPhu5EgZMOybmcgZOG7sSDEkW/DoW4gc2FpDQptZWFuKHByZWQucWRhJGNsYXNzICE9IG1wZzAxLnRlc3QpDQpgYGANCg0KQ0jDum5nIHRhIGvhur90IGx14bqtbiBsw6AgdOG7iSBs4buHIGThu7EgxJFvw6FuIHNhaSBj4bunYSBRREEgbMOgIGtob+G6o25nIDEzLDE4NiUNCg0KIyMgQ8OidSBmKSDDgXAgZOG7pW5nIExvZ2lzdGljIFJlZ3Jlc3Npb24NCg0KQ2jDum5nIHRhIHPhur0gZml0IG3DtCBow6xuaCBsb2dpc3RpYyBSZWdyZXNzaW9uIMSR4buDIGThu7EgxJFvw6FuIGJp4bq/biDEkeG6p3UgcmEgbXBnMDEgdsOgIHPhu60gZOG7pW5nIGPDoWMgYmnhur9uIMSR4bqndSB2w6BvIGzDoCBjeWxpbmRlcnMsIHdlaWdodCwgZGlzcGxhY2VtZW50IHbDoCBob3JzZXBvd2VyLiBIw6BtIGdsbSgpIHbDoCDEkcawYSB2w6BvIGJp4bq/biBmYW1pbHkgPWJpbm9taWFsIGTDuW5nIMSR4buDIGNo4bqheSAxIG3DtCBow6xuaCBMb2dpc3RpYyBSZWdyZXNzaW9uLg0KDQpgYGB7cn0NCiMgRml0IG3DtCBow6xuaCBMb2dpc3RpYyBSZWdyZXNpb24gxJHhu4MgZOG7sSDEkW/DoW4gYmnhur9uIMSR4bqndSByYSBtcGcwMSB0cm9uZyBk4buvIGxp4buHdSBBVXRvIGNo4buJIGNo4bupYSBjw6FjIG7Eg20gY2jhurVuDQpmaXQuZ2xtIDwtIGdsbShtcGcwMSB+IGN5bGluZGVycyArIHdlaWdodCArIGRpc3BsYWNlbWVudCArIGhvcnNlcG93ZXIsIGRhdGEgPSBBdXRvLCBmYW1pbHkgPSBiaW5vbWlhbCwgc3Vic2V0ID0gdHJhaW4pDQpgYGANCg0KYGBge3J9DQojIEjDoG0gcHJlZGljdCBkw7luZyDEkeG7gyBk4buxIMSRb8OhbiB4w6FjIHN14bqldCBsxrDhu6NuZyBraMOtIGdhcyBjYW8gKG1wZzAxID0gMSksIHR5cGUgPSAicmVzcG9uc2UiIMSR4buDIHh14bqldCByYSB4w6FjIHh14bqldCB0aGVvIGThuqFuZyBQKFkgPSAxfFgpDQpwcm9icyA8LSBwcmVkaWN0KGZpdC5nbG0sIEF1dG8udGVzdCwgdHlwZSA9ICJyZXNwb25zZSIpDQpgYGANCg0KYGBge3J9DQojIFThuqFvIG3hu5l0IHZlY3RvIGfhu5NtIDM5MiB0aMOgbmggcGjhuqduID0gMCAgdMawxqFuZyDhu6luZyB24bubaSBz4buRIHF1YW4gc8OhdCBj4bunYSBuaOG7r25nIG7Eg20gbOG6uw0KcHJlZC5nbG0gPC0gcmVwKDAsIGxlbmd0aChwcm9icykpDQpgYGANCg0KYGBge3J9DQojQ2h1eeG7g24gY8OhYyB0aMOgbmggcGjhuqduIHNhbmcgMSBraGkgeMOhYyBzdeG6pXQgZOG7sSDEkW/DoW4gbOG7m24gaMahbiAwLjUNCnByZWQuZ2xtW3Byb2JzID4gMC41XSA8LSAxDQpgYGANCg0KDQpgYGB7cn0NCiMgRMO5bmcgaMOgbSB0YWJsZSgpIMSR4buDIHThuqFvIHJhIG3hu5l0IG1hIHRy4bqtbiDEkeG7gyBxdXnhur90IMSR4buLbmggeGVtIGPDsyBiYW8gbmhpw6p1IHF1YW4gc8OhdCDEkcaw4bujYyBwaMOibiBsb+G6oWkgxJHDum5nLCBiYW8gbmhpw6p1IGLhu4sgcGjDom4gbG/huqFpIHNhaQ0KdGFibGUocHJlZC5nbG0sIG1wZzAxLnRlc3QpDQpgYGANCg0KYGBge3J9DQojIEThu7EgxJFvw6FuICVz4buRIGTDsm5nIGThu7EgxJFvw6FuIHNhaQ0KbWVhbihwcmVkLmdsbSAhPSBtcGcwMS50ZXN0KQ0KYGBgDQoNCkNIw7puZyB0YSBr4bq/dCBsdeG6rW4gbMOgIHThu4kgbOG7hyBk4buxIMSRb8OhbiBzYWkgY+G7p2EgTG9naXN0aWMgUmVncmVzc2lvbiBsw6Aga2hv4bqjbmcgMTIsMDgl