Tên: Mai Huy
MSSV: 43.01.104.065
Số thứ tự: 08
Câu b) Create a training set consisting of the first 200 observations, and a test set consisting of the remaining observations.
# Tập train gồm 200 quan sát đầu
train <- 1:200
# Lấy 200 quan sát đầu trong tập dữ liệu Hitters làm tập train
Hitters.train <- Hitters[train, ]
# Lấy các quan sát còn lại ngoài tập train làm tập test
Hitters.test <- Hitters[-train, ]
Câu d) Produce a plot with different shrinkage values on the x-axis and the corresponding test set MSE on the y-axis.
# set.seed dùng để tái tạo những vector random giống nhau theo tương ứng với giá trị được đưa vào hàm seed
set.seed(1)
# Tạo ra một mảng trống với độ dài bằng vector lambdas để lưu các giá trị MSE tương ứng mỗi learning rate khác nhau
test.err <- rep(NA, length(lambdas))
for (i in 1:length(lambdas)) {
boost.hitters <- gbm(Salary ~ ., data = Hitters.train, distribution = "gaussian", n.trees = 1000, shrinkage = lambdas[i])
yhat <- predict(boost.hitters, Hitters.test, n.trees = 1000)
test.err[i] <- mean((yhat - Hitters.test$Salary)^2)
}
plot(lambdas, test.err, type = "b", xlab = "Shrinkage values", ylab = "Test MSE")

Với mỗi giá trị trong vector lambdas, ta gán cho mô hình một giá trị learning rate khác nhau, sau đó tiến hành dự đoán và tính MSE trên tập test, lưu lại từng giá trị MSE ứng với mỗi learning rate đó trong mảng trống test.err
Sau đó ta biểu diễn trên biểu đồ với x là giá trị learning của mô hình, y là giá trị MSE trên tập test
# Giá trị MSE nhỏ nhất trên tập test
min(test.err)
[1] 0.2540265
# Giá trị learning khiến cho MSE trên tập test là nhỏ nhất
lambdas[which.min(test.err)]
[1] 0.07943282
Câu e) Compare the test MSE of boosting to the test MSE that results from applying two of the regression approaches seen in Chapters 3 and 6.
# Load thư viện glmnet
library(glmnet)
# Tạo mô hình hồi quy bội với Salary là biến đầu ra và các biến lại là biến đầu vào, tập huấn luyện là Hitters.train
fit1 <- lm(Salary ~ ., data = Hitters.train)
# Tiến hành dự đoán trên tập test
pred1 <- predict(fit1, Hitters.test)
# Tính Mean Squared Error (MSE) giữa giá trị dự đoán và giá trị thật
mean((pred1 - Hitters.test$Salary)^2)
[1] 0.4917959
MSE khi dùng hồi quy bội là 0.4917959
# Tạo 1 một ma trận mô hình với biến đầu ra là Salary, biến đầu vào là các biến loại, tập dữ liệu là tập Hitters.train
x <- model.matrix(Salary ~ ., data = Hitters.train)
# Tạo 1 một ma trận mô hình với biến đầu ra là Salary, biến đầu vào là các biến loại, tập dữ liệu là tập Hitters.test
x.test <- model.matrix(Salary ~ ., data = Hitters.test)
# Lấy biến Salary trên tập Hitters.train
y <- Hitters.train$Salary
# Tạo mô hình ridge regression với x là biến đầu vào, đầu ra là y, alpha =0 nhằm sử dụng ridge penalty
fit2 <- glmnet(x, y, alpha = 0)
# Tiến hành dự đoán trên tập x.test với s=0.01 là giá trị áp dụng cho ridge penalty
pred2 <- predict(fit2, s = 0.01, newx = x.test)
# Tính Mean Squared Error (MSE) giữa giá trị dự đoán và giá trị thật\
mean((pred2 - Hitters.test$Salary)^2)
[1] 0.4570283
MSE khi dùng ridge regression là 0.4570283
Ta thấy là MSE khi dùng mô hình boosting thấp hơn cả linear regression và ridge regression
Câu f)Which variables appear to be the most important predictors in the boosted model?
# Xây dụng mô hình boosting với biến đầu ra là Salary và các biến còn lại là biến đầu vào, mô hình dùng phân phối gaussian, số lượng cây = 1000, learning rate bằng giá trị mà cho ra MSE nhỏ nhất trên tập test
boost.hitters <- gbm(Salary ~ ., data = Hitters.train, distribution = "gaussian", n.trees = 1000, shrinkage = lambdas[which.min(test.err)])
# Hiển thị biểu dô mức quan trọng các biến
summary(boost.hitters)

Ta thấy biến CAtBat là biến quan trọng nhất là mức độ ảnh hưởng là 22.9336528
Câu g) Now apply bagging to the training set. What is the test set MSE for this approach?
# set.seed dùng để tái tạo những vector random giống nhau theo tương ứng với giá trị được đưa vào hàm seed
set.seed(1)
# Tạo mô hình randomforest để dự đoan giá trị Salary là biến đầu ra và lấy tất cả các biến còn lại làm biến đầu vào trong tập Hitters.train
bag.hitters <- randomForest(Salary ~ ., data = Hitters.train, mtry = 19, ntree = 500)
- mtry =13: có 19 yếu tố đầu vào được sử dụng cho mỗi lúc phân chia cây
- ntree = 500: số lượng cây là 500
# Đưa ra dự đoán trên tập test ,biến yhat.bag trả về các giá trị dự đoán trên tập test
yhat.bag <- predict(bag.hitters, newdata = Hitters.test)
# Tính Mean Squared Error (MSE) giữa giá trị dự đoán và giá trị thật
mean((yhat.bag - Hitters.test$Salary)^2)
[1] 0.2299324
Ta thấy MSE của mô hình bagging là 0.2299324, nhỏ hơn so với mô hình boosting(0.2540265)
LS0tDQp0aXRsZTogIkLDoGkgdOG6rXAgMV8gdHXhuqduIDEwIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMjIFTDqm46IE1haSBIdXkNCiMjIyBNU1NWOiA0My4wMS4xMDQuMDY1DQojIyMgU+G7kSB0aOG7qSB04buxOiAwOA0KDQojIyMgQ8OidSBhKSBSZW1vdmUgdGhlIG9ic2VydmF0aW9ucyBmb3Igd2hvbSB0aGUgc2FsYXJ5IGluZm9ybWF0aW9uIGlzIHVua25vd24sIGFuZCB0aGVuIGxvZy10cmFuc2Zvcm0gdGhlIHNhbGFyaWVzLg0KDQpgYGB7cn0NCiMgTG9hZCB0aMawIHZp4buHbiBNYXNzDQpsaWJyYXJ5KE1BU1MpDQojIExvYWQgdGjGsCB2aeG7h24gSVNMUg0KbGlicmFyeShJU0xSKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiMgQuG7jyBuaOG7r25nIHF1YW4gc8OhdCBtw6AgdGjDtG5nIHRpbiBi4buLIHRy4buRbmcgdsOgIGPhuq1wIG5o4bqtcCBs4bqhaSB04bqtcCBk4buvIGxp4buHdSBIaXRsZXJzIG3hu5tpDQpIaXR0ZXJzIDwtIG5hLm9taXQoSGl0dGVycykNCiMgVHLhuqMgduG7gSBj4buZdCBzYWxhcnkgc2F1IGtoaSDEkcaw4bujYyBsb2cNCkhpdHRlcnMkU2FsYXJ5IDwtIGxvZyhIaXR0ZXJzJFNhbGFyeSkNCmBgYA0KDQojIyMgQ8OidSBiKSBDcmVhdGUgYSB0cmFpbmluZyBzZXQgY29uc2lzdGluZyBvZiB0aGUgZmlyc3QgMjAwIG9ic2VydmF0aW9ucywgYW5kIGEgdGVzdCBzZXQgY29uc2lzdGluZyBvZiB0aGUgcmVtYWluaW5nIG9ic2VydmF0aW9ucy4NCg0KDQpgYGB7cn0NCiMgVOG6rXAgdHJhaW4gZ+G7k20gMjAwIHF1YW4gc8OhdCDEkeG6p3UNCnRyYWluIDwtIDE6MjAwDQojIEzhuqV5IDIwMCBxdWFuIHPDoXQgxJHhuqd1IHRyb25nIHThuq1wIGThu68gbGnhu4d1IEhpdHRlcnMgbMOgbSB04bqtcCB0cmFpbg0KSGl0dGVycy50cmFpbiA8LSBIaXR0ZXJzW3RyYWluLCBdDQojIEzhuqV5IGPDoWMgcXVhbiBzw6F0IGPDsm4gbOG6oWkgbmdvw6BpIHThuq1wIHRyYWluIGzDoG0gdOG6rXAgdGVzdA0KSGl0dGVycy50ZXN0IDwtIEhpdHRlcnNbLXRyYWluLCBdDQpgYGANCg0KIyMjIGPDonUgYykgUGVyZm9ybSBib29zdGluZyBvbiB0aGUgdHJhaW5pbmcgc2V0IHdpdGggMSwwMDAgdHJlZXMgZm9yIGEgcmFuZ2Ugb2YgdmFsdWVzIG9mIHRoZSBzaHJpbmthZ2UgcGFyYW1ldGVyIEEuIFByb2R1Y2UgYSBwbG90IHdpdGggZGlmZmVyZW50IHNocmlua2FnZSB2YWx1ZXMgb24gdGhlIHgtYXhpcyBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgdHJhaW5pbmcgc2V0IE1TRSBvbiB0aGUgeS1heGlzLg0KDQpgYGB7cn0NCmBgYA0KDQoNCg0KDQpgYGB7cn0NCiMgTG9hZCB0aMawIHZp4buHbiBnYm0NCmxpYnJhcnkoZ2JtKQ0KIyBzZXQuc2VlZCBkw7luZyDEkeG7gyB0w6FpIHThuqFvIG5o4buvbmcgdmVjdG9yIHJhbmRvbSBnaeG7kW5nIG5oYXUgdGhlbyB0xrDGoW5nIOG7qW5nIHbhu5tpIGdpw6EgdHLhu4sgxJHGsOG7o2MgxJHGsGEgdsOgbyBow6BtIHNlZWQNCnNldC5zZWVkKDEpDQojIFThuqFvIG3hu5l0IGTDo3kgc+G7kSB24bubaSBz4buRIMSR4bqndSBsw6AgLTEwLCBz4buRIGN14buRaSBsw6AgLTAuMiwgZ2nDoSB0cuG7iyBt4buXaSBixrDhu5tjIG5o4bqjeSBsw6AgMC4xIA0KcG93cyA8LSBzZXEoLTEwLCAtMC4yLCBieSA9IDAuMSkNCiMgbGFtYmRhcyBsw6AgbeG7mXQgdmVjdG9yIGNo4bupYSBnacOhIHRy4buLIDEwXnggduG7m2kgeCBsw6AgY8OhYyBnacOhIHRy4buLIHRyb25nIHZlY3RvciBwb3dzDQpsYW1iZGFzIDwtIDEwXnBvd3MNCiMgVOG6oW8gcmEgbeG7mXQgbeG6o25nIHRy4buRbmcgduG7m2kgxJHhu5kgZMOgaSBi4bqxbmcgdmVjdG9yIGxhbWJkYXMNCnRyYWluLmVyciA8LSByZXAoTkEsIGxlbmd0aChsYW1iZGFzKSkNCmBgYA0KDQpgYGB7cn0NCmZvciAoaSBpbiAxOmxlbmd0aChsYW1iZGFzKSkgew0KICAgIGJvb3N0LmhpdHRlcnMgPC0gZ2JtKFNhbGFyeSB+IC4sIGRhdGEgPSBIaXR0ZXJzLnRyYWluLCBkaXN0cmlidXRpb24gPSAiZ2F1c3NpYW4iLCBuLnRyZWVzID0gMTAwMCwgc2hyaW5rYWdlID0gbGFtYmRhc1tpXSkNCiAgICBwcmVkLnRyYWluIDwtIHByZWRpY3QoYm9vc3QuaGl0dGVycywgSGl0dGVycy50cmFpbiwgbi50cmVlcyA9IDEwMDApDQogICAgdHJhaW4uZXJyW2ldIDwtIG1lYW4oKHByZWQudHJhaW4gLSBIaXR0ZXJzLnRyYWluJFNhbGFyeSleMikNCn0NCnBsb3QobGFtYmRhcywgdHJhaW4uZXJyLCB0eXBlID0gImIiLCB4bGFiID0gIlNocmlua2FnZSB2YWx1ZXMiLCB5bGFiID0gIlRyYWluaW5nIE1TRSIpDQpgYGANCg0KVuG7m2kgbeG7l2kgZ2nDoSB0cuG7iyB0cm9uZyB2ZWN0b3IgbGFtYmRhcywgdGEgZ8OhbiBjaG8gbcO0IGjDrG5oIG3hu5l0IGdpw6EgdHLhu4sgbGVhcm5pbmcgcmF0ZSBraMOhYyBuaGF1LCBzYXUgxJHDsyB0aeG6v24gaMOgbmggZOG7sSDEkW/DoW4gdsOgIHTDrW5oIE1TRSB0csOqbiB04bqtcCBodeG6pW4gbHV54buHbiwgbMawdSBs4bqhaSB04burbmcgZ2nDoSB0cuG7iyBNU0Ug4bupbmcgduG7m2kgbeG7l2kgbGVhcm5pbmcgcmF0ZSDEkcOzIHRyb25nIG3huqNuZyB0cuG7kW5nIHRyYWluLmVycg0KDQpTYXUgxJHDsyB0YSBiaeG7g3UgZGnhu4VuIHRyw6puIGJp4buDdSDEkeG7kyB24bubaSB4IGzDoCBnacOhIHRy4buLIGxlYXJuaW5nIGPhu6dhIG3DtCBow6xuaCwgeSBsw6AgZ2nDoSB0cuG7iyBNU0UgdHLDqm4gdOG6rXAgaHXhuqVuIGx1eeG7h24sIHRhIHRo4bqleSB24bubaSBsZWFybmluZyByYXRlIGtob+G6o25nIGfhuqduIDAuNjUgdGjDrCBtw7QgaMOsbmggY2hvIGvhur90IHF14bqjIE1TRSB0csOqbiB04bqtcCB0cmFpbiBsw6Agbmjhu48gbmjhuqV0DQoNCiMjIyBDw6J1IGQpIFByb2R1Y2UgYSBwbG90IHdpdGggZGlmZmVyZW50IHNocmlua2FnZSB2YWx1ZXMgb24gdGhlIHgtYXhpcyBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgdGVzdCBzZXQgTVNFIG9uIHRoZSB5LWF4aXMuDQoNCg0KYGBge3J9DQojIHNldC5zZWVkIGTDuW5nIMSR4buDIHTDoWkgdOG6oW8gbmjhu69uZyB2ZWN0b3IgcmFuZG9tIGdp4buRbmcgbmhhdSB0aGVvIHTGsMahbmcg4bupbmcgduG7m2kgZ2nDoSB0cuG7iyDEkcaw4bujYyDEkcawYSB2w6BvIGjDoG0gc2VlZA0Kc2V0LnNlZWQoMSkNCiMgVOG6oW8gcmEgbeG7mXQgbeG6o25nIHRy4buRbmcgduG7m2kgxJHhu5kgZMOgaSBi4bqxbmcgdmVjdG9yIGxhbWJkYXMgxJHhu4MgbMawdSBjw6FjIGdpw6EgdHLhu4sgTVNFIHTGsMahbmcg4bupbmcgbeG7l2kgbGVhcm5pbmcgcmF0ZSBraMOhYyBuaGF1DQp0ZXN0LmVyciA8LSByZXAoTkEsIGxlbmd0aChsYW1iZGFzKSkNCmZvciAoaSBpbiAxOmxlbmd0aChsYW1iZGFzKSkgew0KICAgIGJvb3N0LmhpdHRlcnMgPC0gZ2JtKFNhbGFyeSB+IC4sIGRhdGEgPSBIaXR0ZXJzLnRyYWluLCBkaXN0cmlidXRpb24gPSAiZ2F1c3NpYW4iLCBuLnRyZWVzID0gMTAwMCwgc2hyaW5rYWdlID0gbGFtYmRhc1tpXSkNCiAgICB5aGF0IDwtIHByZWRpY3QoYm9vc3QuaGl0dGVycywgSGl0dGVycy50ZXN0LCBuLnRyZWVzID0gMTAwMCkNCiAgICB0ZXN0LmVycltpXSA8LSBtZWFuKCh5aGF0IC0gSGl0dGVycy50ZXN0JFNhbGFyeSleMikNCn0NCnBsb3QobGFtYmRhcywgdGVzdC5lcnIsIHR5cGUgPSAiYiIsIHhsYWIgPSAiU2hyaW5rYWdlIHZhbHVlcyIsIHlsYWIgPSAiVGVzdCBNU0UiKQ0KYGBgDQoNClbhu5tpIG3hu5dpIGdpw6EgdHLhu4sgdHJvbmcgdmVjdG9yIGxhbWJkYXMsIHRhIGfDoW4gY2hvIG3DtCBow6xuaCBt4buZdCBnacOhIHRy4buLIGxlYXJuaW5nIHJhdGUga2jDoWMgbmhhdSwgc2F1IMSRw7MgdGnhur9uIGjDoG5oIGThu7EgxJFvw6FuIHbDoCB0w61uaCBNU0UgdHLDqm4gdOG6rXAgdGVzdCwgbMawdSBs4bqhaSB04burbmcgZ2nDoSB0cuG7iyBNU0Ug4bupbmcgduG7m2kgbeG7l2kgbGVhcm5pbmcgcmF0ZSDEkcOzIHRyb25nIG3huqNuZyB0cuG7kW5nIHRlc3QuZXJyDQoNClNhdSDEkcOzIHRhIGJp4buDdSBkaeG7hW4gdHLDqm4gYmnhu4N1IMSR4buTIHbhu5tpIHggbMOgIGdpw6EgdHLhu4sgbGVhcm5pbmcgY+G7p2EgbcO0IGjDrG5oLCB5IGzDoCBnacOhIHRy4buLIE1TRSB0csOqbiB04bqtcCB0ZXN0DQoNCmBgYHtyfQ0KIyBHacOhIHRy4buLIE1TRSBuaOG7jyBuaOG6pXQgdHLDqm4gdOG6rXAgdGVzdA0KbWluKHRlc3QuZXJyKQ0KYGBgDQoNCmBgYHtyfQ0KIyBHacOhIHRy4buLIGxlYXJuaW5nIGtoaeG6v24gY2hvIE1TRSB0csOqbiB04bqtcCB0ZXN0IGzDoCBuaOG7jyBuaOG6pXQgDQpsYW1iZGFzW3doaWNoLm1pbih0ZXN0LmVycildDQpgYGANCg0KIyMjIEPDonUgZSkgQ29tcGFyZSB0aGUgdGVzdCBNU0Ugb2YgYm9vc3RpbmcgdG8gdGhlIHRlc3QgTVNFIHRoYXQgcmVzdWx0cyBmcm9tIGFwcGx5aW5nIHR3byBvZiB0aGUgcmVncmVzc2lvbiBhcHByb2FjaGVzIHNlZW4gaW4gQ2hhcHRlcnMgMyBhbmQgNi4NCg0KDQoNCmBgYHtyfQ0KIyBMb2FkIHRoxrAgdmnhu4duIGdsbW5ldA0KbGlicmFyeShnbG1uZXQpDQpgYGANCg0KYGBge3J9DQojIFThuqFvIG3DtCBow6xuaCBo4buTaSBxdXkgYuG7mWkgduG7m2kgU2FsYXJ5IGzDoCBiaeG6v24gxJHhuqd1IHJhIHbDoCBjw6FjIGJp4bq/biBs4bqhaSBsw6AgYmnhur9uIMSR4bqndSB2w6BvLCB04bqtcCBodeG6pW4gbHV54buHbiBsw6AgSGl0dGVycy50cmFpbg0KZml0MSA8LSBsbShTYWxhcnkgfiAuLCBkYXRhID0gSGl0dGVycy50cmFpbikNCiMgVGnhur9uIGjDoG5oIGThu7EgxJFvw6FuIHRyw6puIHThuq1wIHRlc3QNCnByZWQxIDwtIHByZWRpY3QoZml0MSwgSGl0dGVycy50ZXN0KQ0KIyBUw61uaCBNZWFuIFNxdWFyZWQgRXJyb3IgKE1TRSkgZ2nhu69hIGdpw6EgdHLhu4sgZOG7sSDEkW/DoW4gdsOgIGdpw6EgdHLhu4sgdGjhuq10DQptZWFuKChwcmVkMSAtIEhpdHRlcnMudGVzdCRTYWxhcnkpXjIpDQpgYGANCg0KTVNFIGtoaSBkw7luZyBo4buTaSBxdXkgYuG7mWkgbMOgICAwLjQ5MTc5NTkNCg0KYGBge3J9DQojIFThuqFvIDEgbeG7mXQgbWEgdHLhuq1uIG3DtCBow6xuaCB24bubaSBiaeG6v24gxJHhuqd1IHJhIGzDoCBTYWxhcnksIGJp4bq/biDEkeG6p3UgdsOgbyBsw6AgY8OhYyBiaeG6v24gbG/huqFpLCB04bqtcCBk4buvIGxp4buHdSBsw6AgdOG6rXAgSGl0dGVycy50cmFpbg0KeCA8LSBtb2RlbC5tYXRyaXgoU2FsYXJ5IH4gLiwgZGF0YSA9IEhpdHRlcnMudHJhaW4pDQojIFThuqFvIDEgbeG7mXQgbWEgdHLhuq1uIG3DtCBow6xuaCB24bubaSBiaeG6v24gxJHhuqd1IHJhIGzDoCBTYWxhcnksIGJp4bq/biDEkeG6p3UgdsOgbyBsw6AgY8OhYyBiaeG6v24gbG/huqFpLCB04bqtcCBk4buvIGxp4buHdSBsw6AgdOG6rXAgSGl0dGVycy50ZXN0DQp4LnRlc3QgPC0gbW9kZWwubWF0cml4KFNhbGFyeSB+IC4sIGRhdGEgPSBIaXR0ZXJzLnRlc3QpDQojIEzhuqV5IGJp4bq/biBTYWxhcnkgdHLDqm4gdOG6rXAgSGl0dGVycy50cmFpbg0KeSA8LSBIaXR0ZXJzLnRyYWluJFNhbGFyeQ0KIyBU4bqhbyBtw7QgaMOsbmggcmlkZ2UgcmVncmVzc2lvbiB24bubaSB4IGzDoCBiaeG6v24gxJHhuqd1IHbDoG8sIMSR4bqndSByYSBsw6AgeSwgYWxwaGEgPTAgbmjhurFtIHPhu60gZOG7pW5nIHJpZGdlIHBlbmFsdHkNCmZpdDIgPC0gZ2xtbmV0KHgsIHksIGFscGhhID0gMCkNCiMgVGnhur9uIGjDoG5oIGThu7EgxJFvw6FuIHRyw6puIHThuq1wIHgudGVzdCB24bubaSBzPTAuMDEgbMOgIGdpw6EgdHLhu4sgw6FwIGThu6VuZyBjaG8gcmlkZ2UgcGVuYWx0eQ0KcHJlZDIgPC0gcHJlZGljdChmaXQyLCBzID0gMC4wMSwgbmV3eCA9IHgudGVzdCkNCiMgVMOtbmggTWVhbiBTcXVhcmVkIEVycm9yIChNU0UpIGdp4buvYSBnacOhIHRy4buLIGThu7EgxJFvw6FuIHbDoCBnacOhIHRy4buLIHRo4bqtdFwNCm1lYW4oKHByZWQyIC0gSGl0dGVycy50ZXN0JFNhbGFyeSleMikNCmBgYA0KDQpNU0Uga2hpIGTDuW5nIHJpZGdlIHJlZ3Jlc3Npb24gbMOgICAwLjQ1NzAyODMNCg0KVGEgdGjhuqV5IGzDoCBNU0Uga2hpIGTDuW5nIG3DtCBow6xuaCBib29zdGluZyB0aOG6pXAgaMahbiBj4bqjIGxpbmVhciByZWdyZXNzaW9uIHZhzIAgcmlkZ2UgcmVncmVzc2lvbg0KDQojIyMgQ8OidSBmKVdoaWNoIHZhcmlhYmxlcyBhcHBlYXIgdG8gYmUgdGhlIG1vc3QgaW1wb3J0YW50IHByZWRpY3RvcnMgaW4gdGhlIGJvb3N0ZWQgbW9kZWw/DQoNCmBgYHtyfQ0KIyBYw6J5IGThu6VuZyBtw7QgaMOsbmggYm9vc3RpbmcgduG7m2kgYmnhur9uIMSR4bqndSByYSBsw6AgU2FsYXJ5IHbDoCBjw6FjIGJp4bq/biBjw7JuIGzhuqFpIGzDoCBiaeG6v24gxJHhuqd1IHbDoG8sIG3DtCBow6xuaCBkw7luZyBwaMOibiBwaOG7kWkgZ2F1c3NpYW4sIHPhu5EgbMaw4bujbmcgY8OieSA9IDEwMDAsIGxlYXJuaW5nIHJhdGUgYuG6sW5nIGdpw6EgdHLhu4sgbcOgIGNobyByYSBNU0Ugbmjhu48gbmjhuqV0IHRyw6puIHThuq1wIHRlc3QNCmJvb3N0LmhpdHRlcnMgPC0gZ2JtKFNhbGFyeSB+IC4sIGRhdGEgPSBIaXR0ZXJzLnRyYWluLCBkaXN0cmlidXRpb24gPSAiZ2F1c3NpYW4iLCBuLnRyZWVzID0gMTAwMCwgc2hyaW5rYWdlID0gbGFtYmRhc1t3aGljaC5taW4odGVzdC5lcnIpXSkNCiMgSGnhu4NuIHRo4buLIGJp4buDdSBkw7QgbeG7qWMgcXVhbiB0cuG7jW5nIGPDoWMgYmnhur9uDQpzdW1tYXJ5KGJvb3N0LmhpdHRlcnMpDQpgYGANCg0KVGEgdGjhuqV5IGJp4bq/biBDQXRCYXQgbMOgIGJp4bq/biBxdWFuIHRy4buNbmcgbmjhuqV0IGzDoCBt4bupYyDEkeG7mSDhuqNuaCBoxrDhu59uZyBsw6AgMjIuOTMzNjUyOAkNCg0KIyMjIEPDonUgZykgTm93IGFwcGx5IGJhZ2dpbmcgdG8gdGhlIHRyYWluaW5nIHNldC4gV2hhdCBpcyB0aGUgdGVzdCBzZXQgTVNFIGZvciB0aGlzIGFwcHJvYWNoPw0KDQpgYGB7cn0NCiMgc2V0LnNlZWQgZMO5bmcgxJHhu4MgdMOhaSB04bqhbyBuaOG7r25nIHZlY3RvciByYW5kb20gZ2nhu5FuZyBuaGF1IHRoZW8gdMawxqFuZyDhu6luZyB24bubaSBnacOhIHRy4buLIMSRxrDhu6NjIMSRxrBhIHbDoG8gaMOgbSBzZWVkDQpzZXQuc2VlZCgxKQ0KIyBU4bqhbyBtw7QgaMOsbmggcmFuZG9tZm9yZXN0IMSR4buDIGThu7EgxJFvYW4gZ2nDoSB0cuG7iyBTYWxhcnkgbMOgIGJp4bq/biDEkeG6p3UgcmEgdsOgIGzhuqV5IHThuqV0IGPhuqMgY8OhYyBiaeG6v24gY8OybiBs4bqhaSBsw6BtIGJp4bq/biDEkeG6p3UgdsOgbyB0cm9uZyB04bqtcCBIaXR0ZXJzLnRyYWluDQpiYWcuaGl0dGVycyA8LSByYW5kb21Gb3Jlc3QoU2FsYXJ5IH4gLiwgZGF0YSA9IEhpdHRlcnMudHJhaW4sIG10cnkgPSAxOSwgbnRyZWUgPSA1MDApDQpgYGANCg0KLSBtdHJ5ID0xMzogY8OzIDE5IHnhur91IHThu5EgxJHhuqd1IHbDoG8gxJHGsOG7o2Mgc+G7rSBk4bulbmcgY2hvIG3hu5dpIGzDumMgcGjDom4gY2hpYSBjw6J5IA0KLSBudHJlZSA9IDUwMDogc+G7kSBsxrDhu6NuZyBjw6J5IGzDoCA1MDANCg0KYGBge3J9DQojIMSQxrBhIHJhIGThu7EgxJFvw6FuIHRyw6puIHThuq1wIHRlc3QgLGJp4bq/biB5aGF0LmJhZyB0cuG6oyB24buBIGPDoWMgZ2nDoSB0cuG7iyBk4buxIMSRb8OhbiB0csOqbiB04bqtcCB0ZXN0DQp5aGF0LmJhZyA8LSBwcmVkaWN0KGJhZy5oaXR0ZXJzLCBuZXdkYXRhID0gSGl0dGVycy50ZXN0KQ0KIyBUw61uaCBNZWFuIFNxdWFyZWQgRXJyb3IgKE1TRSkgZ2nhu69hIGdpw6EgdHLhu4sgZOG7sSDEkW/DoW4gdsOgIGdpw6EgdHLhu4sgdGjhuq10DQptZWFuKCh5aGF0LmJhZyAtIEhpdHRlcnMudGVzdCRTYWxhcnkpXjIpDQpgYGANCg0KVGEgdGjhuqV5IE1TRSBj4bunYSBtw7QgaMOsbmggYmFnZ2luZyBsw6AgMC4yMjk5MzI0LCBuaOG7jyBoxqFuIHNvIHbhu5tpIG3DtCBow6xuaCBib29zdGluZygwLjI1NDAyNjUpDQo=