Zadanie raport 5.
Opis zadania
Przetestowanie metod (regresja grzbietowa i lasso) oraz metod oceny
(zestaw walidacyjny, walidacja krzyżowa) na zbiorze danych Wage z
ISLR.
Skonfigurujmy nasze dane:
Wczytujemy dane:
library(ISLR)
data("Wage")
place<-Wage
Tworzymy wektor zmiennej wynikowej.
x = model.matrix(wage~., place)[,-1]
y = Wage %>%
select(wage) %>%
unlist() %>%
as.numeric()
Regresja grzbietowa
Model regresji grzbietowej dla pełnych danych wygląda
następująco:
grid = 10^seq(10, -2, length = 100)
ridge_mod = glmnet(x, y, alpha = 0, lambda = grid)
plot(ridge_mod) # wykres współczynników

dim(coef(ridge_mod))
## [1] 26 100
#Wymiar macierzy predyktorów
Uzyskana macierz jest macierzą wymiaru 26 na 100.
Dzielenie próbek
Podzielimy teraz próbki na zbiór treningowy i testowy w celu
oszacowania błędu testu regresji grzbietowej i lasso.
set.seed(1)
train = Wage %>%
sample_frac(0.5)
test = Wage %>%
setdiff(train)
x_train = model.matrix(wage~., train)[,-1]
x_test = model.matrix(wage~., test)[,-1]
y_train = train %>%
select(wage) %>%
unlist() %>%
as.numeric()
y_test = test %>%
select(wage) %>%
unlist() %>%
as.numeric()
Wybierz lamdę, która minimalizuje treningowy MSE
set.seed(1)
cv.out = cv.glmnet(x_train, y_train, alpha = 0)
# Dopasuj model regresji grzbietowej na danych treningowych
bestlam = cv.out$lambda.min # Wybierz lamdę, która minimalizuje treningowy MSE
bestlam
## [1] 3.939486
Wykres na podstawie najlepszej lambdy dla MSE
plot(cv.out)

Oszacowanie MSE
Następnie dopasowujemy model regresji grzbietowej na zbiorze
treningowym i oceniamy jego MSE na zbiorze testowym, używając \(\lambda = bestlam\) . Czyli oszacowanie dla
regresji z lambdą optymalną wyznaczoną wcześniej.
ridge_pred = predict(ridge_mod, s = bestlam, newx = x_test)
mean((ridge_pred - y_test)^2)
## [1] 169.468
Oszacowania współczynników
Ponownie wyznaczamy nasz model regresji grzbietowej na pełnym
zestawie danych i sprawdzamy oszacowania współczynników.
out = glmnet(x, y, alpha = 0) # Dopasuj model regresji grzbietowej do pełnego zbioru danych
predict(out, type = "coefficients", s = bestlam)[1:10,] # Wyświetlanie współczynników przy użyciu lambda wybranego przez CV
## (Intercept) year age maritl2. Married
## -3.529273e+02 3.706173e-04 1.909890e-02 8.771868e-01
## maritl3. Widowed maritl4. Divorced maritl5. Separated race2. Black
## -2.610242e+00 -6.036440e-01 -9.351872e-01 -1.106809e+00
## race3. Asian race4. Other
## -4.492573e-01 -4.079098e-01
Regresja OLS
Model kmnk dla s=0 (lambda równa 0) i oszacowanie MSE.
ridge_pred = predict(ridge_mod, s = 0, newx = x_test)
mean((ridge_pred - y_test)^2) # Oblicz testowe MSE
## [1] 151.514
lm(wage ~ year + age + maritl + race, data = train)
##
## Call:
## lm(formula = wage ~ year + age + maritl + race, data = train)
##
## Coefficients:
## (Intercept) year age maritl2. Married
## -3038.2309 1.5526 0.5551 17.7962
## maritl3. Widowed maritl4. Divorced maritl5. Separated race2. Black
## 5.6667 1.8302 2.6743 -6.1402
## race3. Asian race4. Other
## 3.8241 -20.1080
Procedura Lasso
lasso_mod = glmnet(x_train,
y_train,
alpha = 1,
lambda = grid) # Dopasuj model lasso do danych treningowych
plot(lasso_mod) # Wykreśl współczynniki

Teraz przeprowadzimy walidację krzyżową i obliczymy związany z nią
błąd testu i przedstawimy oszacowane MSE:
set.seed(1)
cv.out = cv.glmnet(x_train, y_train, alpha = 1) # Dopasuj model lasso do danych treningowych
plot(cv.out) # Narysuj wykres MSE dla próby uczącej jako funkcję lambda

MSE dla lambdy optymalnej i współczynniki regresji Lasso
Oszacowanie MSE testowego dla optymlanej lambdy przedstawia się
następująco:
bestlam = cv.out$lambda.min # Wybierz lamdę, która minimalizuje MSE w próbie uczącej
lasso_pred = predict(lasso_mod, s = bestlam, newx = x_test) # Użyj najlepszej lambdy do przewidywania danych testowych
mean((lasso_pred - y_test)^2) # Oblicz MSE w próbie testowej
## [1] 154.8086
Teraz wyświetlone zostaną współczynniki regresji Lasso z lambdą
optymalną.
out = glmnet(x, y, alpha = 1, lambda = grid)
# Dopasuj model lasso do pełnego zbioru danych
lasso_coef = predict(out, type = "coefficients", s = bestlam)[1:10,]
# Wyświetlanie współczynników przy użyciu lambda wybranego przez CV
lasso_coef
## (Intercept) year age maritl2. Married
## -4.075268e+02 -8.908553e-05 -3.182844e-05 -3.296052e-04
## maritl3. Widowed maritl4. Divorced maritl5. Separated race2. Black
## 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
## race3. Asian race4. Other
## 0.000000e+00 0.000000e+00
Tylko cztery zmienne spośród badanych zmiennych nie przyjęły wartości
zerowych, dlatego nie wszystkie zmienne są statystycznie istotne.
Zmienne istotne
Tylko niezerowe zmienne to:
lasso_coef[lasso_coef != 0] # Wyświetlanie tylko niezerowych współczynników
## (Intercept) year age maritl2. Married
## -4.075268e+02 -8.908553e-05 -3.182844e-05 -3.296052e-04
Odpowiedzi na pytania:
- Który zbiór danych wybrałeś?
Wybrany został zbiór danych “Wage” z biblioteki ISLR, czyli
zależności płac.
- Jaka była Twoja zmienna zależna (tzn. co próbowałeś modelować)?
Wage, czyli płaca.
- Czy oczekiwałeś, że regresja grzbietowa będzie lepsza od lasso czy
odwrotnie? Pokaż odpowiednie raporty, miary dopasowania i krótko je omów
(porównaj).
Oczekiwaliśmy, że wyniki obu regresji będą podobne, jako iż regresja
lasso oraz grzbietowa same w sobie podobne. Metoda lasso sama w swoich
założeniach ma zwiększać dokładność przewidywań, w porównaniu do metody
grzbietowej, dlatego wydaje się, że to właśnie ta pierwsza metoda jest
lepsza. Wartość MSE w przypadku metody Lasso wychodzi niższa niż w
przypadku metody grzbietowej.(175 - grzbietowa, do 155 - Lasso)
- Jak wypada w stosunku do OLS?
W stosunku do OLS kilka zmiennych zostało wyzerowanych, zatem według
Lasso selekcjonuje istotne zmienne.
- Które predyktory okazały się ważne w ostatecznym modelu
(modelach)?
W ostatecznym modelu istotne okazały się następujące predyktory :
year, age, maritl2. Married, education2. HS Grad, education3. Some
College education5., Advanced Degree
LS0tDQp0aXRsZTogIlJhcG9ydCA1LiINCmF1dGhvcjogIkthdGFyenluYSBMZXdjenVrLCBKdWxpdXN6IEFsZnV0aCwgUGlvdHIgV2ljaG93c2tpIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUNCiAgICBmb250c2l6ZTogMTBwdA0KICAgIHRvYzogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KICAgIGRmX3ByaW50OiBkZWZhdWx0DQogICAgdG9jX2RlcHRoOiA1DQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzUnDQpzdWJ0aXRsZTogUmVndWxhcnl6YWNqYQ0KZWRpdG9yX29wdGlvbnM6DQogIG1hcmtkb3duOg0KICAgIHdyYXA6IDcyDQotLS0NCg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCmxpYnJhcnkoSVNMUikNCmxpYnJhcnkoZ2xtbmV0KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpgYGANCg0KIyMgWmFkYW5pZSByYXBvcnQgNS4NCg0KIyMgT3BpcyB6YWRhbmlhDQpQcnpldGVzdG93YW5pZSBtZXRvZCAocmVncmVzamEgZ3J6YmlldG93YSBpIGxhc3NvKSBvcmF6IG1ldG9kIG9jZW55ICh6ZXN0YXcgd2FsaWRhY3lqbnksIHdhbGlkYWNqYSBrcnp5xbxvd2EpIG5hIHpiaW9yemUgZGFueWNoIFdhZ2UgeiBJU0xSLg0KDQpTa29uZmlndXJ1am15IG5hc3plIGRhbmU6DQoNCldjenl0dWplbXkgZGFuZToNCmBgYHtyfQ0KbGlicmFyeShJU0xSKQ0KDQpkYXRhKCJXYWdlIikNCnBsYWNlPC1XYWdlDQpgYGANClR3b3J6eW15IHdla3RvciB6bWllbm5laiB3eW5pa293ZWouDQpgYGB7cn0NCnggPSBtb2RlbC5tYXRyaXgod2FnZX4uLCBwbGFjZSlbLC0xXQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KeSA9IFdhZ2UgJT4lDQogIHNlbGVjdCh3YWdlKSAlPiUNCiAgdW5saXN0KCkgJT4lDQogIGFzLm51bWVyaWMoKQ0KYGBgDQoNCiMjIFJlZ3Jlc2phIGdyemJpZXRvd2ENCg0KTW9kZWwgcmVncmVzamkgZ3J6YmlldG93ZWogZGxhIHBlxYJueWNoIGRhbnljaCB3eWdsxIVkYSBuYXN0xJlwdWrEhWNvOg0KDQpgYGB7cn0NCmdyaWQgPSAxMF5zZXEoMTAsIC0yLCBsZW5ndGggPSAxMDApDQpyaWRnZV9tb2QgPSBnbG1uZXQoeCwgeSwgYWxwaGEgPSAwLCBsYW1iZGEgPSBncmlkKQ0KcGxvdChyaWRnZV9tb2QpICMgd3lrcmVzIHdzcMOzxYJjenlubmlrw7N3DQpgYGANCmBgYHtyfQ0KZGltKGNvZWYocmlkZ2VfbW9kKSkNCiNXeW1pYXIgbWFjaWVyenkgcHJlZHlrdG9yw7N3DQpgYGANClV6eXNrYW5hIG1hY2llcnogamVzdCBtYWNpZXJ6xIUgd3ltaWFydSAyNiBuYSAxMDAuDQoNCg0KIyMgRHppZWxlbmllIHByw7NiZWsNCg0KUG9kemllbGlteSB0ZXJheiBwcsOzYmtpIG5hIHpiacOzciB0cmVuaW5nb3d5IGkgdGVzdG93eSB3IGNlbHUgb3N6YWNvd2FuaWEgYsWCxJlkdSB0ZXN0dSByZWdyZXNqaSBncnpiaWV0b3dlaiBpIGxhc3NvLg0KDQpgYGB7cn0NCnNldC5zZWVkKDEpDQoNCnRyYWluID0gV2FnZSAlPiUNCiAgc2FtcGxlX2ZyYWMoMC41KQ0KDQp0ZXN0ID0gV2FnZSAlPiUNCiAgc2V0ZGlmZih0cmFpbikNCg0KeF90cmFpbiA9IG1vZGVsLm1hdHJpeCh3YWdlfi4sIHRyYWluKVssLTFdDQp4X3Rlc3QgPSBtb2RlbC5tYXRyaXgod2FnZX4uLCB0ZXN0KVssLTFdDQoNCnlfdHJhaW4gPSB0cmFpbiAlPiUNCiAgc2VsZWN0KHdhZ2UpICU+JQ0KICB1bmxpc3QoKSAlPiUNCiAgYXMubnVtZXJpYygpDQoNCnlfdGVzdCA9IHRlc3QgJT4lDQogIHNlbGVjdCh3YWdlKSAlPiUNCiAgdW5saXN0KCkgJT4lDQogIGFzLm51bWVyaWMoKQ0KYGBgDQoNCiMjIFd5YmllcnogbGFtZMSZLCBrdMOzcmEgbWluaW1hbGl6dWplIHRyZW5pbmdvd3kgTVNFDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMSkNCmN2Lm91dCA9IGN2LmdsbW5ldCh4X3RyYWluLCB5X3RyYWluLCBhbHBoYSA9IDApIA0KIyBEb3Bhc3VqIG1vZGVsIHJlZ3Jlc2ppIGdyemJpZXRvd2VqIG5hIGRhbnljaCB0cmVuaW5nb3d5Y2gNCmJlc3RsYW0gPSBjdi5vdXQkbGFtYmRhLm1pbiAgIyBXeWJpZXJ6IGxhbWTEmSwga3TDs3JhIG1pbmltYWxpenVqZSB0cmVuaW5nb3d5IE1TRSANCmJlc3RsYW0NCmBgYA0KV3lrcmVzIG5hIHBvZHN0YXdpZSBuYWpsZXBzemVqIGxhbWJkeSBkbGEgTVNFDQoNCmBgYHtyfQ0KcGxvdChjdi5vdXQpDQpgYGANCg0KDQojIyBPc3phY293YW5pZSBNU0UNCg0KTmFzdMSZcG5pZSBkb3Bhc293dWplbXkgbW9kZWwgcmVncmVzamkgZ3J6YmlldG93ZWogbmEgemJpb3J6ZSB0cmVuaW5nb3d5bSBpIG9jZW5pYW15IGplZ28gTVNFIG5hIHpiaW9yemUgdGVzdG93eW0sIHXFvHl3YWrEhWMgJFxsYW1iZGEgPSBiZXN0bGFtJCAuIEN6eWxpIG9zemFjb3dhbmllIGRsYSByZWdyZXNqaSB6IGxhbWJkxIUgb3B0eW1hbG7EhSB3eXpuYWN6b27EhSB3Y3plxZtuaWVqLg0KDQpgYGB7cn0NCnJpZGdlX3ByZWQgPSBwcmVkaWN0KHJpZGdlX21vZCwgcyA9IGJlc3RsYW0sIG5ld3ggPSB4X3Rlc3QpDQptZWFuKChyaWRnZV9wcmVkIC0geV90ZXN0KV4yKQ0KYGBgDQoNCiMjIE9zemFjb3dhbmlhIHdzcMOzxYJjenlubmlrw7N3DQoNClBvbm93bmllIHd5em5hY3phbXkgbmFzeiBtb2RlbCByZWdyZXNqaSBncnpiaWV0b3dlaiBuYSBwZcWCbnltIHplc3Rhd2llIGRhbnljaCBpIHNwcmF3ZHphbXkgb3N6YWNvd2FuaWEgd3Nww7PFgmN6eW5uaWvDs3cuDQoNCg0KYGBge3J9DQpvdXQgPSBnbG1uZXQoeCwgeSwgYWxwaGEgPSAwKSAjIERvcGFzdWogbW9kZWwgcmVncmVzamkgZ3J6YmlldG93ZWogZG8gcGXFgm5lZ28gemJpb3J1IGRhbnljaA0KcHJlZGljdChvdXQsIHR5cGUgPSAiY29lZmZpY2llbnRzIiwgcyA9IGJlc3RsYW0pWzE6MTAsXSAjIFd5xZt3aWV0bGFuaWUgd3Nww7PFgmN6eW5uaWvDs3cgcHJ6eSB1xbx5Y2l1IGxhbWJkYSB3eWJyYW5lZ28gcHJ6ZXogQ1YNCmBgYA0KDQojIyBSZWdyZXNqYSBPTFMNCg0KTW9kZWwga21uayBkbGEgcz0wIChsYW1iZGEgcsOzd25hIDApIGkgb3N6YWNvd2FuaWUgTVNFLg0KDQpgYGB7cn0NCnJpZGdlX3ByZWQgPSBwcmVkaWN0KHJpZGdlX21vZCwgcyA9IDAsIG5ld3ggPSB4X3Rlc3QpDQoNCm1lYW4oKHJpZGdlX3ByZWQgLSB5X3Rlc3QpXjIpICMgT2JsaWN6IHRlc3Rvd2UgTVNFDQpgYGANCg0KYGBge3J9DQpsbSh3YWdlIH4geWVhciArIGFnZSArIG1hcml0bCArIHJhY2UsIGRhdGEgPSB0cmFpbikNCmBgYA0KIyMgUHJvY2VkdXJhIExhc3NvDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsYXNzb19tb2QgPSBnbG1uZXQoeF90cmFpbiwgDQogICAgICAgICAgICAgICAgICAgeV90cmFpbiwgDQogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxLCANCiAgICAgICAgICAgICAgICAgICBsYW1iZGEgPSBncmlkKSAjIERvcGFzdWogbW9kZWwgbGFzc28gZG8gZGFueWNoIHRyZW5pbmdvd3ljaA0KDQpwbG90KGxhc3NvX21vZCkgICAgIyBXeWtyZcWbbCB3c3DDs8WCY3p5bm5pa2kNCmBgYA0KDQpUZXJheiBwcnplcHJvd2FkemlteSB3YWxpZGFjasSZIGtyennFvG93xIUgaSBvYmxpY3p5bXkgendpxIV6YW55IHogbmnEhSBixYLEhWQgdGVzdHUgaSBwcnplZHN0YXdpbXkgb3N6YWNvd2FuZSBNU0U6DQoNCg0KYGBge3J9DQpzZXQuc2VlZCgxKQ0KY3Yub3V0ID0gY3YuZ2xtbmV0KHhfdHJhaW4sIHlfdHJhaW4sIGFscGhhID0gMSkgIyBEb3Bhc3VqIG1vZGVsIGxhc3NvIGRvIGRhbnljaCB0cmVuaW5nb3d5Y2gNCnBsb3QoY3Yub3V0KSAjIE5hcnlzdWogd3lrcmVzIE1TRSBkbGEgcHLDs2J5IHVjesSFY2VqIGpha28gZnVua2NqxJkgbGFtYmRhDQpgYGANCg0KIyMgTVNFIGRsYSBsYW1iZHkgb3B0eW1hbG5laiBpIHdzcMOzxYJjenlubmlraSByZWdyZXNqaSBMYXNzbw0KDQpPc3phY293YW5pZSBNU0UgdGVzdG93ZWdvIGRsYSBvcHR5bWxhbmVqIGxhbWJkeSBwcnplZHN0YXdpYSBzacSZIG5hc3TEmXB1asSFY286DQoNCmBgYHtyfQ0KYmVzdGxhbSA9IGN2Lm91dCRsYW1iZGEubWluICMgV3liaWVyeiBsYW1kxJksIGt0w7NyYSBtaW5pbWFsaXp1amUgTVNFIHcgcHLDs2JpZSB1Y3rEhWNlag0KbGFzc29fcHJlZCA9IHByZWRpY3QobGFzc29fbW9kLCBzID0gYmVzdGxhbSwgbmV3eCA9IHhfdGVzdCkgIyBVxbx5aiBuYWpsZXBzemVqIGxhbWJkeSBkbyBwcnpld2lkeXdhbmlhIGRhbnljaCB0ZXN0b3d5Y2gNCm1lYW4oKGxhc3NvX3ByZWQgLSB5X3Rlc3QpXjIpICMgT2JsaWN6IE1TRSB3IHByw7NiaWUgdGVzdG93ZWoNCmBgYA0KDQoNClRlcmF6IHd5xZt3aWV0bG9uZSB6b3N0YW7EhSB3c3DDs8WCY3p5bm5pa2kgcmVncmVzamkgTGFzc28geiBsYW1iZMSFIG9wdHltYWxuxIUuDQpgYGB7cn0NCm91dCA9IGdsbW5ldCh4LCB5LCBhbHBoYSA9IDEsIGxhbWJkYSA9IGdyaWQpIA0KIyBEb3Bhc3VqIG1vZGVsIGxhc3NvIGRvIHBlxYJuZWdvIHpiaW9ydSBkYW55Y2gNCmxhc3NvX2NvZWYgPSBwcmVkaWN0KG91dCwgdHlwZSA9ICJjb2VmZmljaWVudHMiLCBzID0gYmVzdGxhbSlbMToxMCxdIA0KIyBXecWbd2lldGxhbmllIHdzcMOzxYJjenlubmlrw7N3IHByenkgdcW8eWNpdSBsYW1iZGEgd3licmFuZWdvIHByemV6IENWDQpsYXNzb19jb2VmDQpgYGANCg0KVHlsa28gY3p0ZXJ5IHptaWVubmUgc3BvxZtyw7NkIGJhZGFueWNoIHptaWVubnljaCBuaWUgcHJ6eWrEmcWCeSB3YXJ0b8WbY2kgemVyb3d5Y2gsIGRsYXRlZ28gbmllIHdzenlzdGtpZSB6bWllbm5lIHPEhSBzdGF0eXN0eWN6bmllIGlzdG90bmUuDQoNCiMjIFptaWVubmUgaXN0b3RuZQ0KDQpUeWxrbyBuaWV6ZXJvd2Ugem1pZW5uZSB0bzoNCmBgYHtyfQ0KbGFzc29fY29lZltsYXNzb19jb2VmICE9IDBdICMgV3nFm3dpZXRsYW5pZSB0eWxrbyBuaWV6ZXJvd3ljaCB3c3DDs8WCY3p5bm5pa8Ozdw0KYGBgDQoNCg0KDQoNCiMjIE9kcG93aWVkemkgbmEgcHl0YW5pYToNCg0KIC0gS3TDs3J5IHpiacOzciBkYW55Y2ggd3licmHFgmXFmz8NCg0KIFd5YnJhbnkgem9zdGHFgiB6YmnDs3IgZGFueWNoICJXYWdlIiB6IGJpYmxpb3Rla2kgSVNMUiwgY3p5bGkgemFsZcW8bm/Fm2NpIHDFgmFjLg0KIA0KIC0gSmFrYSBiecWCYSBUd29qYSB6bWllbm5hIHphbGXFvG5hICh0em4uIGNvIHByw7Nib3dhxYJlxZsgbW9kZWxvd2HEhyk/DQoNCiAgV2FnZSwgY3p5bGkgcMWCYWNhLiAgICANCiANCiAtIEN6eSBvY3pla2l3YcWCZcWbLCDFvGUgcmVncmVzamEgZ3J6YmlldG93YSBixJlkemllIGxlcHN6YSBvZCBsYXNzbyBjenkgb2R3cm90bmllPyBQb2thxbwgb2Rwb3dpZWRuaWUgcmFwb3J0eSwgbWlhcnkgZG9wYXNvd2FuaWEgaSBrcsOzdGtvIGplIG9tw7N3IChwb3LDs3duYWopLg0KIA0KIE9jemVraXdhbGnFm215LCDFvGUgd3luaWtpIG9idSByZWdyZXNqaSBixJlkxIUgcG9kb2JuZSwgamFrbyBpxbwgcmVncmVzamEgbGFzc28gb3JheiBncnpiaWV0b3dhIHNhbWUgdyBzb2JpZSBwb2RvYm5lLiBNZXRvZGEgbGFzc28gc2FtYSB3IHN3b2ljaCB6YcWCb8W8ZW5pYWNoIG1hIHp3acSZa3N6YcSHIGRva8WCYWRub8WbxIcgcHJ6ZXdpZHl3YcWELCB3IHBvcsOzd25hbml1IGRvIG1ldG9keSBncnpiaWV0b3dlaiwgZGxhdGVnbyB3eWRhamUgc2nEmSwgxbxlIHRvIHfFgmHFm25pZSB0YSBwaWVyd3N6YSBtZXRvZGEgamVzdCBsZXBzemEuDQogV2FydG/Fm8SHIE1TRSB3IHByenlwYWRrdSBtZXRvZHkgTGFzc28gd3ljaG9kemkgbmnFvHN6YSBuacW8IHcgcHJ6eXBhZGt1IG1ldG9keSBncnpiaWV0b3dlai4oMTc1IC0gZ3J6YmlldG93YSwgZG8gMTU1IC0gTGFzc28pDQogDQogLSBKYWsgd3lwYWRhIHcgc3Rvc3Vua3UgZG8gT0xTPw0KDQpXIHN0b3N1bmt1IGRvIE9MUyBraWxrYSB6bWllbm55Y2ggem9zdGHFgm8gd3l6ZXJvd2FueWNoLCB6YXRlbSB3ZWTFgnVnIExhc3NvIHNlbGVrY2pvbnVqZSBpc3RvdG5lIHptaWVubmUuDQogDQogLSBLdMOzcmUgcHJlZHlrdG9yeSBva2F6YcWCeSBzacSZIHdhxbxuZSB3IG9zdGF0ZWN6bnltIG1vZGVsdSAobW9kZWxhY2gpPw0KIA0KIFcgb3N0YXRlY3pueW0gbW9kZWx1IGlzdG90bmUgb2themHFgnkgc2nEmSBuYXN0xJlwdWrEhWNlIHByZWR5a3RvcnkgOiAgeWVhciwgYWdlLCBtYXJpdGwyLiBNYXJyaWVkLCBlZHVjYXRpb24yLiBIUyBHcmFkLCBlZHVjYXRpb24zLiBTb21lIENvbGxlZ2UgZWR1Y2F0aW9uNS4sIEFkdmFuY2VkIERlZ3JlZSAgDQogDQog