Zadanie

Waszym zadaniem dzisiaj jest zamodelowanie - porównanie KMNK oraz regresji kwantylowej (różno-poziomowej) dla zmiennej “earnings” - wynagrodzenia.

Dobierz i przetestuj predyktory, kwantyle dla modeli. Wykonaj testy różnic współczynnikow dla finalnych modeli.

W przypadku problemów - obejrzyj video tutorial (włącz polskie napisy) oraz wejdź na jego stronę ze źródłami. Możesz również wykorzystać w/w przykłady.

data("CPSSW9298")
# ?CPSSW9298 

data92<-CPSSW9298 %>% filter(CPSSW9298$year==1998)
  data92%>%
  ggplot(aes(age,earnings))+
    geom_point()

data(data92) #dane 
p <- ggplot(data = data92) +
    geom_point(mapping = aes(x = age, y = earnings), color = "blue")
taus <- c(0.1, 0.25, 0.5, 0.75, 0.90, 0.95)
fits <- data.frame(
    coef(lm(earnings ~ age, data = data92)),
    sapply(taus, function(x) coef(rq(formula = earnings ~ age, data = data92, tau = x))))
names(fits) <- c("OLS", sprintf("$\\tau_{%0.2f}$", taus))
nf <- ncol(fits)
colors <- colorRampPalette(colors = c("black", "red"))(nf)
p <- p + geom_abline(intercept = fits[1, 1], slope = fits[2, 1], color = colors[1], linewidth = 1.5)
for (i in seq_len(nf)[-1]) {
    p <- p + geom_abline(intercept = fits[1, i], slope = fits[2, i], color = colors[i])
}
p

Wykres przedstawiający kształtowanie się zarobków w stosunku do wieku oraz regresje kwantylowe dla kwantyli 0.1, 0.25 , 0.5, 0.75, 0.90

data(data92) #dane 
p <- ggplot(data = data92) +
    geom_point(mapping = aes(x = gender, y = earnings), color = "blue")
taus <- c(0.1, 0.25, 0.5, 0.75, 0.90, 0.95)
fits <- data.frame(
    coef(lm(earnings ~ gender, data = data92)),
    sapply(taus, function(x) coef(rq(formula = earnings ~ gender, data = data92, tau = x))))
names(fits) <- c("OLS", sprintf("$\\tau_{%0.2f}$", taus))
nf <- ncol(fits)
colors <- colorRampPalette(colors = c("black", "red"))(nf)
p <- p + geom_abline(intercept = fits[1, 1], slope = fits[2, 1], color = colors[1], linewidth = 1.5)
for (i in seq_len(nf)[-1]) {
    p <- p + geom_abline(intercept = fits[1, i], slope = fits[2, i], color = colors[i])
}
p

Wykres przedstawiający kształtowanie się zarobków dla mężczyzn i kobiet oraz przedstawione regresje dla kwantyli 0.1, 0.25 , 0.5, 0.75, 0.90

knitr::kable(fits, format = "html", caption = "Oszacowania z KMNK oraz `quantreg`") %>%
    kable_styling("striped") %>%
    column_spec(1:8, background = "#ececec")
Oszacowania z KMNK oraz quantreg
OLS \(\tau_{0.10}\) \(\tau_{0.25}\) \(\tau_{0.50}\) \(\tau_{0.75}\) \(\tau_{0.90}\) \(\tau_{0.95}\)
(Intercept) 14.805467 7.019231 9.615385 13.461538 18.376068 24.038462 28.846153
genderfemale -2.044285 -1.019231 -1.442308 -1.923077 -2.991453 -2.884615 -3.846153
q2 <- rq(log(earnings) ~ age+degree+gender, data = data92, tau = 0.25)
q4 <- rq(log(earnings) ~ age+degree+gender, data = data92, tau = 0.50)
q6 <- rq(log(earnings) ~ age+degree+gender, data = data92, tau = 0.75)



stargazer(q2, q4, q6, title = "Wyniki regresji kwantylowych", type = "text")
## 
## Wyniki regresji kwantylowych
## ============================================
##                     Dependent variable:     
##                -----------------------------
##                        log(earnings)        
##                   (1)       (2)       (3)   
## --------------------------------------------
## age            0.020***  0.025***  0.027*** 
##                 (0.003)   (0.002)   (0.003) 
##                                             
## degreebachelor 0.398***  0.396***  0.369*** 
##                 (0.016)   (0.014)   (0.015) 
##                                             
## genderfemale   -0.181*** -0.195*** -0.212***
##                 (0.016)   (0.014)   (0.015) 
##                                             
## Constant       1.540***  1.714***  1.949*** 
##                 (0.085)   (0.075)   (0.079) 
##                                             
## --------------------------------------------
## Observations     5,911     5,911     5,911  
## ============================================
## Note:            *p<0.1; **p<0.05; ***p<0.01

Wyniki regresji kwantylowych kształtują się w sposób przedstawiony w tabeli powyżej

my_qr <- rq(earnings ~ age + gender, data = data92, tau = seq(0.25, 0.75, 0.25))

# Przetwarzanie wyników współczynników
intercept_slope <- coef(my_qr) %>%
  t() %>%
  data.frame()

# Ustawianie poprawnych nazw kolumn
colnames(intercept_slope) <- c("intercept", "slope_age", "slope_gender_female")

# Dodanie kolumny z kwantylami
intercept_slope$quantile <- rownames(intercept_slope)

# Wykres regresji kwantylowej
ggplot() +
  geom_point(data = data92, aes(x = age, y = earnings, color = gender), alpha = 0.5) +
  geom_abline(data = intercept_slope, aes(intercept = intercept, slope = slope_age, color = quantile)) +
  theme_minimal() +
  labs(x = "Wiek", y = "Zarobki", title = "Regresje kwantylowe z tau = 0.25, 0.50 oraz 0.75")


Wykres przedstawiający kształtowanie się zarobków w zależności od wieku oraz płci
Przedstawione są tu również regresje kwantylowe z tau 0.25, 0.50 i 0.75


```r
kmnk <- lm(log(earnings) ~ age + factor(degree) + factor(gender), data = data92)
summary(kmnk)
## 
## Call:
## lm(formula = log(earnings) ~ age + factor(degree) + factor(gender), 
##     data = data92)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.96583 -0.27644  0.02536  0.30209  1.50215 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)             1.78845    0.06230   28.71   <2e-16 ***
## age                     0.02142    0.00207   10.35   <2e-16 ***
## factor(degree)bachelor  0.38277    0.01173   32.64   <2e-16 ***
## factor(gender)female   -0.18003    0.01182  -15.23   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4457 on 5907 degrees of freedom
## Multiple R-squared:  0.1828, Adjusted R-squared:  0.1824 
## F-statistic: 440.5 on 3 and 5907 DF,  p-value: < 2.2e-16
kwantyle <- c(0.25, 0.50, 0.75)
reg_kwantylowa <- rq(log(earnings) ~ age+degree+gender,tau = kwantyle,data = data92)
summary(reg_kwantylowa, se = "boot")
## 
## Call: rq(formula = log(earnings) ~ age + degree + gender, tau = kwantyle, 
##     data = data92)
## 
## tau: [1] 0.25
## 
## Coefficients:
##                Value     Std. Error t value   Pr(>|t|) 
## (Intercept)      1.53975   0.09329   16.50566   0.00000
## age              0.02026   0.00320    6.32616   0.00000
## degreebachelor   0.39850   0.01732   23.00156   0.00000
## genderfemale    -0.18133   0.01695  -10.69557   0.00000
## 
## Call: rq(formula = log(earnings) ~ age + degree + gender, tau = kwantyle, 
##     data = data92)
## 
## tau: [1] 0.5
## 
## Coefficients:
##                Value     Std. Error t value   Pr(>|t|) 
## (Intercept)      1.71413   0.08190   20.92888   0.00000
## age              0.02479   0.00273    9.08393   0.00000
## degreebachelor   0.39563   0.01367   28.93719   0.00000
## genderfemale    -0.19526   0.01379  -14.16278   0.00000
## 
## Call: rq(formula = log(earnings) ~ age + degree + gender, tau = kwantyle, 
##     data = data92)
## 
## tau: [1] 0.75
## 
## Coefficients:
##                Value     Std. Error t value   Pr(>|t|) 
## (Intercept)      1.94914   0.07226   26.97351   0.00000
## age              0.02666   0.00238   11.21714   0.00000
## degreebachelor   0.36898   0.01442   25.59046   0.00000
## genderfemale    -0.21198   0.01400  -15.14580   0.00000

Zarówno dla modelu wykonanego KMNK jak i wszystkich modeli regresji kwantylowej, wszystkie zmienne objaśniające istotnie wpływają na kształtowanie się zarobków.

#Badanie statystycznej różnicy między 25 i 50 kwantylem warunkowym
kwantyle <- c(0.25, 0.50)
reg_kwantylowa <- rq(log(earnings) ~ age+degree+gender,tau = kwantyle,data = data92)
anova(reg_kwantylowa, test = "Wald", joint=TRUE)
## Quantile Regression Analysis of Deviance Table
## 
## Model: log(earnings) ~ age + degree + gender
## Joint Test of Equality of Slopes: tau in {  0.25 0.5  }
## 
##   Df Resid Df F value Pr(>F)
## 1  3    11819  1.5073 0.2104
anova(reg_kwantylowa, test = "Wald", joint = FALSE)
## Quantile Regression Analysis of Deviance Table
## 
## Model: log(earnings) ~ age + degree + gender
## Tests of Equality of Distinct Slopes: tau in {  0.25 0.5  }
## 
##                Df Resid Df F value  Pr(>F)  
## age             1    11821  3.3290 0.06809 .
## degreebachelor  1    11821  0.0416 0.83830  
## genderfemale    1    11821  0.9879 0.32028  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Test wskazuje że 25 i 50 kwantyl warunkowy nie są statystycznie różne

kwantyle <- c(0.25, 0.50, 0.75)

reg_kwantylowa <- rq(log(earnings) ~ age + factor(degree) + factor(gender), 
                     tau = kwantyle, 
                     data = data92)

anova(reg_kwantylowa, test = "Wald", joint = TRUE)
## Quantile Regression Analysis of Deviance Table
## 
## Model: log(earnings) ~ age + factor(degree) + factor(gender)
## Joint Test of Equality of Slopes: tau in {  0.25 0.5 0.75  }
## 
##   Df Resid Df F value  Pr(>F)  
## 1  6    17727  2.0933 0.05064 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
anova(reg_kwantylowa, test = "Wald", joint=FALSE)
## Quantile Regression Analysis of Deviance Table
## 
## Model: log(earnings) ~ age + factor(degree) + factor(gender)
## Tests of Equality of Distinct Slopes: tau in {  0.25 0.5 0.75  }
## 
##                        Df Resid Df F value Pr(>F)
## age                     2    17731  2.2269 0.1079
## factor(degree)bachelor  2    17731  2.1488 0.1167
## factor(gender)female    2    17731  1.4965 0.2239

Test na kwartylach pokazuje że dalej nie występują istotne statystycznie różnice między modelami dla poszczególnych kwartyli

Na koniec sprawdzamy miary dobroci dopasowania

## model kwantylowy
model1 <- rq(log(earnings) ~ age+degree+gender,tau = 0.1, data = data92)
reszty1 <- resid(model1)

## bezwarunkowy (pusty) model kwantylowy
model2 <- rq(log(earnings) ~ 1, tau = 0.1,data=data92)
reszty2 <- resid(model2)

goodfit(reszty1, reszty2, 0.1)
## [1] 0.07776773
## r2 modelu KMNK dla porównania
model_lm <- lm(log(earnings) ~ age+degree+gender, data = data92)

summary(model_lm)$r.squared
## [1] 0.1828058

Wartość miary dobroci dopasowania regresji kwantylowej wyniosła 0.06987542 a więc możemy stwierdzić że odchylenia bezwzględne w modelach w pełni sparametryzowanych były w mniejsze od odchyleń bezwzględnych w modelu kwantylowym bezwarunkowym. Wartość dopasowania r2 miała dość małą wartość 0.1871756, więc tylko około 18% zmienności kształtowania się wynagrodzeń zostało objaśnione przez ten model. Zarówno KMNK jak i regresja kwantylowa miały do siebie dość zbliżone wyniki jeśli chodzi o istotność zmiennych oraz ich oddziaływanie na zarobki.

LS0tDQp0aXRsZTogJ05pZWtsYXN5Y3puZSBtZXRvZHkgc3RhdHlzdHlraScNCnN1YnRpdGxlOiAnUmVncmVzamEga3dhbnR5bG93YScNCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCmF1dGhvcjogIk1pa2/FgmFqIE1vZ2llbG5pY2tpIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlDQogICAgZm9udHNpemU6IDEwcHQNCiAgICB0b2M6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgICBkZl9wcmludDogZGVmYXVsdA0KICAgIHRvY19kZXB0aDogNQ0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCiAgDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQogICBrbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KYGBge3IgcHJlcmVxcywgbWVzc2FnZSA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQpsaWJyYXJ5KENWWFIpDQpsaWJyYXJ5KEFFUikNCmxpYnJhcnkoc3RhcmdhemVyKQ0KbGlicmFyeShXUlREU3RpZGFsKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KHF1YW50cmVnKQ0KbGlicmFyeShQb2dyb21jeURhbnljaCkNCmBgYA0KDQojIyBaYWRhbmllDQoNCldhc3p5bSB6YWRhbmllbSBkemlzaWFqIGplc3QgemFtb2RlbG93YW5pZSAtIHBvcsOzd25hbmllIEtNTksgb3Jheg0KcmVncmVzamkga3dhbnR5bG93ZWogKHLDs8W8bm8tcG96aW9tb3dlaikgZGxhIHptaWVubmVqICJlYXJuaW5ncyIgLQ0Kd3luYWdyb2R6ZW5pYS4NCg0KRG9iaWVyeiBpIHByemV0ZXN0dWogcHJlZHlrdG9yeSwga3dhbnR5bGUgZGxhIG1vZGVsaS4gV3lrb25haiB0ZXN0eQ0KcsOzxbxuaWMgd3Nww7PFgmN6eW5uaWtvdyBkbGEgZmluYWxueWNoIG1vZGVsaS4NCg0KVyBwcnp5cGFka3UgcHJvYmxlbcOzdyAtIG9iZWpyenlqIHZpZGVvIHR1dG9yaWFsICh3xYLEhWN6IHBvbHNraWUgbmFwaXN5KQ0Kb3JheiB3ZWpkxbogbmEgamVnbyBzdHJvbsSZIHplIMW6csOzZMWCYW1pLiBNb8W8ZXN6IHLDs3duaWXFvCB3eWtvcnp5c3RhxIcgdy93DQpwcnp5a8WCYWR5Lg0KDQpgYGB7cn0NCmRhdGEoIkNQU1NXOTI5OCIpDQojID9DUFNTVzkyOTggDQoNCmRhdGE5MjwtQ1BTU1c5Mjk4ICU+JSBmaWx0ZXIoQ1BTU1c5Mjk4JHllYXI9PTE5OTgpDQogIGRhdGE5MiU+JQ0KICBnZ3Bsb3QoYWVzKGFnZSxlYXJuaW5ncykpKw0KICAgIGdlb21fcG9pbnQoKQ0KDQoNCg0KYGBgDQpgYGB7cn0NCmRhdGEoZGF0YTkyKSAjZGFuZSANCnAgPC0gZ2dwbG90KGRhdGEgPSBkYXRhOTIpICsNCiAgICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGFnZSwgeSA9IGVhcm5pbmdzKSwgY29sb3IgPSAiYmx1ZSIpDQp0YXVzIDwtIGMoMC4xLCAwLjI1LCAwLjUsIDAuNzUsIDAuOTAsIDAuOTUpDQpmaXRzIDwtIGRhdGEuZnJhbWUoDQogICAgY29lZihsbShlYXJuaW5ncyB+IGFnZSwgZGF0YSA9IGRhdGE5MikpLA0KICAgIHNhcHBseSh0YXVzLCBmdW5jdGlvbih4KSBjb2VmKHJxKGZvcm11bGEgPSBlYXJuaW5ncyB+IGFnZSwgZGF0YSA9IGRhdGE5MiwgdGF1ID0geCkpKSkNCm5hbWVzKGZpdHMpIDwtIGMoIk9MUyIsIHNwcmludGYoIiRcXHRhdV97JTAuMmZ9JCIsIHRhdXMpKQ0KbmYgPC0gbmNvbChmaXRzKQ0KY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYygiYmxhY2siLCAicmVkIikpKG5mKQ0KcCA8LSBwICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gZml0c1sxLCAxXSwgc2xvcGUgPSBmaXRzWzIsIDFdLCBjb2xvciA9IGNvbG9yc1sxXSwgbGluZXdpZHRoID0gMS41KQ0KZm9yIChpIGluIHNlcV9sZW4obmYpWy0xXSkgew0KICAgIHAgPC0gcCArIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGZpdHNbMSwgaV0sIHNsb3BlID0gZml0c1syLCBpXSwgY29sb3IgPSBjb2xvcnNbaV0pDQp9DQpwDQpgYGANCld5a3JlcyBwcnplZHN0YXdpYWrEhWN5IGtzenRhxYJ0b3dhbmllIHNpxJkgemFyb2Jrw7N3IHcgc3Rvc3Vua3UgZG8gd2lla3Ugb3Jheg0KcmVncmVzamUga3dhbnR5bG93ZSBkbGEga3dhbnR5bGkgMC4xLCAwLjI1ICwgMC41LCAwLjc1LCAwLjkwDQogDQoNCmBgYHtyfQ0KZGF0YShkYXRhOTIpICNkYW5lIA0KcCA8LSBnZ3Bsb3QoZGF0YSA9IGRhdGE5MikgKw0KICAgIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZ2VuZGVyLCB5ID0gZWFybmluZ3MpLCBjb2xvciA9ICJibHVlIikNCnRhdXMgPC0gYygwLjEsIDAuMjUsIDAuNSwgMC43NSwgMC45MCwgMC45NSkNCmZpdHMgPC0gZGF0YS5mcmFtZSgNCiAgICBjb2VmKGxtKGVhcm5pbmdzIH4gZ2VuZGVyLCBkYXRhID0gZGF0YTkyKSksDQogICAgc2FwcGx5KHRhdXMsIGZ1bmN0aW9uKHgpIGNvZWYocnEoZm9ybXVsYSA9IGVhcm5pbmdzIH4gZ2VuZGVyLCBkYXRhID0gZGF0YTkyLCB0YXUgPSB4KSkpKQ0KbmFtZXMoZml0cykgPC0gYygiT0xTIiwgc3ByaW50ZigiJFxcdGF1X3slMC4yZn0kIiwgdGF1cykpDQpuZiA8LSBuY29sKGZpdHMpDQpjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBjKCJibGFjayIsICJyZWQiKSkobmYpDQpwIDwtIHAgKyBnZW9tX2FibGluZShpbnRlcmNlcHQgPSBmaXRzWzEsIDFdLCBzbG9wZSA9IGZpdHNbMiwgMV0sIGNvbG9yID0gY29sb3JzWzFdLCBsaW5ld2lkdGggPSAxLjUpDQpmb3IgKGkgaW4gc2VxX2xlbihuZilbLTFdKSB7DQogICAgcCA8LSBwICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gZml0c1sxLCBpXSwgc2xvcGUgPSBmaXRzWzIsIGldLCBjb2xvciA9IGNvbG9yc1tpXSkNCn0NCnANCmBgYA0KDQpXeWtyZXMgcHJ6ZWRzdGF3aWFqxIVjeSBrc3p0YcWCdG93YW5pZSBzacSZIHphcm9ia8OzdyBkbGEgbcSZxbxjenl6biBpIGtvYmlldCBvcmF6IHByemVkc3Rhd2lvbmUgcmVncmVzamUgDQpkbGEga3dhbnR5bGkgMC4xLCAwLjI1ICwgMC41LCAwLjc1LCAwLjkwDQoNCg0KYGBge3J9DQprbml0cjo6a2FibGUoZml0cywgZm9ybWF0ID0gImh0bWwiLCBjYXB0aW9uID0gIk9zemFjb3dhbmlhIHogS01OSyBvcmF6IGBxdWFudHJlZ2AiKSAlPiUNCiAgICBrYWJsZV9zdHlsaW5nKCJzdHJpcGVkIikgJT4lDQogICAgY29sdW1uX3NwZWMoMTo4LCBiYWNrZ3JvdW5kID0gIiNlY2VjZWMiKQ0KYGBgDQoNCmBgYHtyfQ0KcTIgPC0gcnEobG9nKGVhcm5pbmdzKSB+IGFnZStkZWdyZWUrZ2VuZGVyLCBkYXRhID0gZGF0YTkyLCB0YXUgPSAwLjI1KQ0KcTQgPC0gcnEobG9nKGVhcm5pbmdzKSB+IGFnZStkZWdyZWUrZ2VuZGVyLCBkYXRhID0gZGF0YTkyLCB0YXUgPSAwLjUwKQ0KcTYgPC0gcnEobG9nKGVhcm5pbmdzKSB+IGFnZStkZWdyZWUrZ2VuZGVyLCBkYXRhID0gZGF0YTkyLCB0YXUgPSAwLjc1KQ0KDQoNCg0Kc3RhcmdhemVyKHEyLCBxNCwgcTYsIHRpdGxlID0gIld5bmlraSByZWdyZXNqaSBrd2FudHlsb3d5Y2giLCB0eXBlID0gInRleHQiKQ0KDQoNCmBgYA0KV3luaWtpIHJlZ3Jlc2ppIGt3YW50eWxvd3ljaCBrc3p0YcWCdHVqxIUgc2nEmSB3IHNwb3PDs2IgcHJ6ZWRzdGF3aW9ueSB3IHRhYmVsaSBwb3d5xbxlag0KDQpgYGB7cn0NCm15X3FyIDwtIHJxKGVhcm5pbmdzIH4gYWdlICsgZ2VuZGVyLCBkYXRhID0gZGF0YTkyLCB0YXUgPSBzZXEoMC4yNSwgMC43NSwgMC4yNSkpDQoNCiMgUHJ6ZXR3YXJ6YW5pZSB3eW5pa8OzdyB3c3DDs8WCY3p5bm5pa8Ozdw0KaW50ZXJjZXB0X3Nsb3BlIDwtIGNvZWYobXlfcXIpICU+JQ0KICB0KCkgJT4lDQogIGRhdGEuZnJhbWUoKQ0KDQojIFVzdGF3aWFuaWUgcG9wcmF3bnljaCBuYXp3IGtvbHVtbg0KY29sbmFtZXMoaW50ZXJjZXB0X3Nsb3BlKSA8LSBjKCJpbnRlcmNlcHQiLCAic2xvcGVfYWdlIiwgInNsb3BlX2dlbmRlcl9mZW1hbGUiKQ0KDQojIERvZGFuaWUga29sdW1ueSB6IGt3YW50eWxhbWkNCmludGVyY2VwdF9zbG9wZSRxdWFudGlsZSA8LSByb3duYW1lcyhpbnRlcmNlcHRfc2xvcGUpDQoNCiMgV3lrcmVzIHJlZ3Jlc2ppIGt3YW50eWxvd2VqDQpnZ3Bsb3QoKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IGRhdGE5MiwgYWVzKHggPSBhZ2UsIHkgPSBlYXJuaW5ncywgY29sb3IgPSBnZW5kZXIpLCBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX2FibGluZShkYXRhID0gaW50ZXJjZXB0X3Nsb3BlLCBhZXMoaW50ZXJjZXB0ID0gaW50ZXJjZXB0LCBzbG9wZSA9IHNsb3BlX2FnZSwgY29sb3IgPSBxdWFudGlsZSkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh4ID0gIldpZWsiLCB5ID0gIlphcm9ia2kiLCB0aXRsZSA9ICJSZWdyZXNqZSBrd2FudHlsb3dlIHogdGF1ID0gMC4yNSwgMC41MCBvcmF6IDAuNzUiKQ0KDQpgYGANCmBgYA0KDQpXeWtyZXMgcHJ6ZWRzdGF3aWFqxIVjeSBrc3p0YcWCdG93YW5pZSBzacSZIHphcm9ia8OzdyB3IHphbGXFvG5vxZtjaSBvZCB3aWVrdSBvcmF6IHDFgmNpDQpQcnplZHN0YXdpb25lIHPEhSB0dSByw7N3bmllxbwgcmVncmVzamUga3dhbnR5bG93ZSB6IHRhdSAwLjI1LCAwLjUwIGkgMC43NQ0KDQpgYGB7cn0NCmttbmsgPC0gbG0obG9nKGVhcm5pbmdzKSB+IGFnZSArIGZhY3RvcihkZWdyZWUpICsgZmFjdG9yKGdlbmRlciksIGRhdGEgPSBkYXRhOTIpDQpzdW1tYXJ5KGttbmspDQpgYGANCg0KDQpgYGB7cn0NCmt3YW50eWxlIDwtIGMoMC4yNSwgMC41MCwgMC43NSkNCnJlZ19rd2FudHlsb3dhIDwtIHJxKGxvZyhlYXJuaW5ncykgfiBhZ2UrZGVncmVlK2dlbmRlcix0YXUgPSBrd2FudHlsZSxkYXRhID0gZGF0YTkyKQ0Kc3VtbWFyeShyZWdfa3dhbnR5bG93YSwgc2UgPSAiYm9vdCIpDQpgYGANCg0KWmFyw7N3bm8gZGxhIG1vZGVsdSB3eWtvbmFuZWdvIEtNTksgamFrIGkgd3N6eXN0a2ljaCBtb2RlbGkgcmVncmVzamkga3dhbnR5bG93ZWosIHdzenlzdGtpZSANCnptaWVubmUgb2JqYcWbbmlhasSFY2UgaXN0b3RuaWUgd3DFgnl3YWrEhSBuYSBrc3p0YcWCdG93YW5pZSBzacSZIHphcm9ia8Ozdy4NCg0KDQoNCmBgYHtyfQ0KI0JhZGFuaWUgc3RhdHlzdHljem5laiByw7PFvG5pY3kgbWnEmWR6eSAyNSBpIDUwIGt3YW50eWxlbSB3YXJ1bmtvd3ltDQprd2FudHlsZSA8LSBjKDAuMjUsIDAuNTApDQpyZWdfa3dhbnR5bG93YSA8LSBycShsb2coZWFybmluZ3MpIH4gYWdlK2RlZ3JlZStnZW5kZXIsdGF1ID0ga3dhbnR5bGUsZGF0YSA9IGRhdGE5MikNCmFub3ZhKHJlZ19rd2FudHlsb3dhLCB0ZXN0ID0gIldhbGQiLCBqb2ludD1UUlVFKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmFub3ZhKHJlZ19rd2FudHlsb3dhLCB0ZXN0ID0gIldhbGQiLCBqb2ludCA9IEZBTFNFKQ0KYGBgDQpUZXN0IHdza2F6dWplIMW8ZSAyNSBpIDUwIGt3YW50eWwgd2FydW5rb3d5IG5pZSBzxIUgc3RhdHlzdHljem5pZSByw7PFvG5lIA0KDQoNCg0KDQpgYGB7cn0NCmt3YW50eWxlIDwtIGMoMC4yNSwgMC41MCwgMC43NSkNCg0KcmVnX2t3YW50eWxvd2EgPC0gcnEobG9nKGVhcm5pbmdzKSB+IGFnZSArIGZhY3RvcihkZWdyZWUpICsgZmFjdG9yKGdlbmRlciksIA0KICAgICAgICAgICAgICAgICAgICAgdGF1ID0ga3dhbnR5bGUsIA0KICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhdGE5MikNCg0KYW5vdmEocmVnX2t3YW50eWxvd2EsIHRlc3QgPSAiV2FsZCIsIGpvaW50ID0gVFJVRSkNCmBgYA0KYGBge3J9DQphbm92YShyZWdfa3dhbnR5bG93YSwgdGVzdCA9ICJXYWxkIiwgam9pbnQ9RkFMU0UpDQpgYGANClRlc3QgbmEga3dhcnR5bGFjaCBwb2thenVqZSDFvGUgZGFsZWogbmllIHd5c3TEmXB1asSFIGlzdG90bmUgc3RhdHlzdHljem5pZSByw7PFvG5pY2UgbWnEmWR6eSBtb2RlbGFtaQ0KZGxhIHBvc3pjemVnw7NsbnljaCBrd2FydHlsaQ0KDQoNCk5hIGtvbmllYyBzcHJhd2R6YW15IG1pYXJ5IGRvYnJvY2kgZG9wYXNvd2FuaWENCmBgYHtyfQ0KIyMgbW9kZWwga3dhbnR5bG93eQ0KbW9kZWwxIDwtIHJxKGxvZyhlYXJuaW5ncykgfiBhZ2UrZGVncmVlK2dlbmRlcix0YXUgPSAwLjEsIGRhdGEgPSBkYXRhOTIpDQpyZXN6dHkxIDwtIHJlc2lkKG1vZGVsMSkNCg0KIyMgYmV6d2FydW5rb3d5IChwdXN0eSkgbW9kZWwga3dhbnR5bG93eQ0KbW9kZWwyIDwtIHJxKGxvZyhlYXJuaW5ncykgfiAxLCB0YXUgPSAwLjEsZGF0YT1kYXRhOTIpDQpyZXN6dHkyIDwtIHJlc2lkKG1vZGVsMikNCg0KZ29vZGZpdChyZXN6dHkxLCByZXN6dHkyLCAwLjEpDQoNCiMjIHIyIG1vZGVsdSBLTU5LIGRsYSBwb3LDs3duYW5pYQ0KbW9kZWxfbG0gPC0gbG0obG9nKGVhcm5pbmdzKSB+IGFnZStkZWdyZWUrZ2VuZGVyLCBkYXRhID0gZGF0YTkyKQ0KDQpzdW1tYXJ5KG1vZGVsX2xtKSRyLnNxdWFyZWQNCg0KYGBgDQoNCg0KDQpXYXJ0b8WbxIcgbWlhcnkgZG9icm9jaSBkb3Bhc293YW5pYSByZWdyZXNqaSBrd2FudHlsb3dlaiB3eW5pb3PFgmEgMC4wNjk4NzU0MiBhIHdpxJljIA0KbW/FvGVteSBzdHdpZXJkemnEhyDFvGUgb2RjaHlsZW5pYSBiZXp3emdsxJlkbmUgdyBtb2RlbGFjaCB3IHBlxYJuaSBzcGFyYW1ldHJ5em93YW55Y2gNCmJ5xYJ5IHcgbW5pZWpzemUgb2Qgb2RjaHlsZcWEIGJlend6Z2zEmWRueWNoIHcgbW9kZWx1IGt3YW50eWxvd3ltIGJlendhcnVua293eW0uDQpXYXJ0b8WbxIcgZG9wYXNvd2FuaWEgcjIgbWlhxYJhIGRvxZvEhyBtYcWCxIUgd2FydG/Fm8SHIDAuMTg3MTc1Niwgd2nEmWMgdHlsa28gIG9rb8WCbyAxOCUNCnptaWVubm/Fm2NpIGtzenRhxYJ0b3dhbmlhIHNpxJkgd3luYWdyb2R6ZcWEIHpvc3RhxYJvIG9iamHFm25pb25lIHByemV6IHRlbiBtb2RlbC4NClphcsOzd25vIEtNTksgamFrIGkgcmVncmVzamEga3dhbnR5bG93YSBtaWHFgnkgZG8gc2llYmllIGRvxZvEhyB6YmxpxbxvbmUgd3luaWtpIGplxZtsaSANCmNob2R6aSBvIGlzdG90bm/Fm8SHIHptaWVubnljaCBvcmF6IGljaCBvZGR6aWHFgnl3YW5pZSBuYSB6YXJvYmtpLg0KDQoNCg==