Dlaczego kwantylowa?

Dlaczego potrzebujemy regresji kwantylowej (QR)?

W szczególności, QR:

  • jest odporna na punkty odstające i wpływowe

  • nie zakłada stałej wariancji (znanej jako homoskedastyczność) dla zmiennej odpowiedzi lub reszt

  • nie zakłada normalności ale główną zaletą QR w porównaniu z regresją liniową (LR) jest to, że QR bada różne wartości zmiennej odpowiedzi, a nie tylko średnią, i dostarcza w związku z tym pełniejszego obrazu związków między zmiennymi!

Wprowadzenie

Regresja kwantylowa (ang. quantile regression) została zaproponowana przez Koenkera i Bassetta (1978). Szczególny przypadek regresji kwantylowej dla kwantyla rzędu 0,5 (czyli mediany) jest równoważny estymatorowi LAD (ang. Least Absolute Deviation) – minimalizuje sumę bezwzględnych błędów.
Wprowadzenie różnych kwantyli regresji daje pełniejszy opis rozkładów warunkowych zwłaszcza w przypadku rozkładów asymetrycznych lub uciętych.

Wymagania

Wymagana jest jedna liczbowa zmienna zależna. Zmienna przewidywana musi być zmienną ilościową. Predyktory mogą być zmiennymi ilościowymi lub sztucznymi zmiennymi w przypadku predyktorów jakościowych. Aby można było uruchomić analizę, wymagany jest wyraz wolny lub co najmniej jeden predyktor.

Regresja kwantylowa nie czyni założeń dotyczących rozkładu zmiennej przewidywanej i jest odporna na wpływ obserwacji odstających.

Analiza kwantylowa jest pokrewna regresji metodą najmniejszych kwadratów.

Zadanie

Teraz Wasza kolej ;-)

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.

Na początku wczytujemy dane:

data("CPSSW9298")
#?CPSSW9298 

Zestaw danych CPSSW9298 jest używany do analizy rynku pracy. Obejmuje następujące zmienne:

-year: Rok, w którym dane zostały zebrane -earnings: Wynagrodzenie badanej osoby (wyrażone w tysiącach) -degree: Poziom wykształcenia badanej osoby, np. “highschool” (szkoła średnia), “bachelor” (tytuł licencjata) -gender: Płeć osoby, np. “male” (mężczyzna), “female” (kobieta) -age: Wiek badanej osoby

Wizualizacja danych

Teraz zostanie przeprowadzona analiza kilku wykresów, aby zbadać i lepiej zrozumieć zależności pomiędzy różnymi zmiennymi.

ggplot(CPSSW9298, aes(x = earnings)) +
  geom_histogram(bins = 30, fill = "mediumpurple", color = "black") +
  labs(
    title = "Rozkład wynagrodzeń",
    x = "Wynagrodzenie (w tysiącach)",
    y = "Liczba obserwacji"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, color = "black"),
    axis.title = element_text(size = 12, color = "black"),
    axis.text = element_text(size = 10)
  )

Rozkład wynagrodzeń jest asymetryczny, z wyraźnym prawostronnym ogonem, co oznacza, że większa liczba osób zarabia niższe wynagrodzenia, podczas gdy wyższe wynagrodzenia są rzadsze. Kształt sugeruje, że wynagrodzenia mogą być rozkładem skośnym (skośność prawostronna).Najwięcej osób zarabia około 10 tysięcy (zauważalny najwyższy słupek histogramu w tej okolicy).

ggplot(CPSSW9298, aes(x = degree, y = earnings, fill = degree)) +
  geom_boxplot() +
  scale_fill_manual(values = c("mediumpurple", "gold")) + 
  labs(
    title = "Wynagrodzenie względem wykształcenia",
    x = "Poziom wykształcenia",
    y = "Wynagrodzenie (w tysiącach)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, color = "black"),  
    axis.title = element_text(size = 12, color = "black"),  
    axis.text = element_text(size = 10),
    legend.position = "none"
  )

Osoby z wykształceniem “bachelor” (licencjackim) mają wyższą medianę wynagrodzeń w porównaniu do osób z wykształceniem “highschool” (średnim).Wynagrodzenia dla obu grup są zróżnicowane, ale rozstęp międzykwartylowy (odległość między dolnym i górnym kwartylem) jest większy dla osób z wykształceniem licencjackim, co wskazuje na większe zróżnicowanie wynagrodzeń w tej grupie.W obu grupach widać obecność wartości odstających (outliers), czyli osób zarabiających znacznie więcej niż większość. Liczba wartości odstających jest wyższa w grupie z wykształceniem “bachelor”.

ggplot(CPSSW9298, aes(x = year, y = earnings)) +
  stat_summary(fun = "mean", geom = "line", aes(group = 1), color = "darkorchid", linewidth = 1) +
  stat_summary(fun = "mean", geom = "point", color = "purple", size = 2) +
  labs(
    title = "Średnie wynagrodzenie w czasie",
    x = "Rok",
    y = "Średnie wynagrodzenie (w tysiącach)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, color = "black"),
    axis.title = element_text(size = 12, color = "black"),
    axis.text = element_text(size = 10)
  )

Średnie wynagrodzenie systematycznie rosło w czasie w analizowanym okresie (1992–1998). Taki wzrost może wynikać z ogólnej poprawy gospodarki, inflacji, lub zmian w strukturze rynku pracy.

ggplot(CPSSW9298, aes(x = gender, y = earnings, fill = gender)) +
  geom_boxplot() +
  scale_fill_manual(values = c("mediumpurple", "gold")) +
  labs(
    title = "Wynagrodzenie względem płci",
    x = "Płeć",
    y = "Wynagrodzenie (w tysiącach)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, color = "black"),
    axis.title = element_text(size = 12, color = "black"),
    axis.text = element_text(size = 10),
    legend.position = "none"
  )

Mężczyźni (“male”) mają wyższą medianę wynagrodzeń w porównaniu do kobiet (“female”).Wynagrodzenia zarówno mężczyzn, jak i kobiet charakteryzują się obecnością wartości odstających, ale mężczyźni mają większy rozstęp maksymalnych wynagrodzeń.

ggplot(CPSSW9298, aes(x = earnings, fill = gender)) +
  geom_histogram(alpha = 0.7, bins = 30, position = "identity") +
  scale_fill_manual(values = c("mediumpurple", "gold")) +
  labs(
    title = "Rozkład wynagrodzeń według płci",
    x = "Wynagrodzenie (w tysiącach)",
    y = "Liczba obserwacji"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    axis.title = element_text(size = 14),
    axis.text = element_text(size = 12),
    legend.title = element_blank()
  )

Wynagrodzenia dla obu płci mają prawostronną skośność – większość osób zarabia w dolnym zakresie wynagrodzeń (poniżej 20 tysięcy), a liczba osób zarabiających więcej systematycznie maleje. Mężczyźni osiągają szerszy zakres wynagrodzeń, w tym najwyższe zarobki, co potwierdzają dłuższe „ogony” fioletowego rozkładu.

ggplot(CPSSW9298, aes(x = age, y = earnings)) +
  geom_point(alpha = 0.7, color = "mediumpurple") +
  geom_smooth(aes(x = age, y = earnings), method = "lm", formula = y ~ x, se = FALSE, linetype = "dashed", color = "gold") +
  labs(
    title = "Wynagrodzenie względem wieku",
    x = "wiek",
    y = "wynagrodzenie (w tysiącach)"
  ) +
  facet_grid(gender ~ degree) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    axis.title = element_text(size = 14),
    axis.text = element_text(size = 12)
  )

Powyższy wykres potwierdza dotychczasowe obserwacje.Osoby z wykształceniem “bachelor” (licencjackim) osiągają wyższe wynagrodzenia w porównaniu do osób z wykształceniem “highschool” (średnim). Jest to widoczne zarówno w przypadku mężczyzn, jak i kobiet.Różnica między wynagrodzeniami mężczyzn i kobiet jest widoczna zarówno w grupie osób z wykształceniem średnim, jak i licencjackim.

Model liniowy

model_lm <- lm(CPSSW9298$earnings ~ CPSSW9298$degree + CPSSW9298$gender + CPSSW9298$age)
summary(model_lm)  
## 
## Call:
## lm(formula = CPSSW9298$earnings ~ CPSSW9298$degree + CPSSW9298$gender + 
##     CPSSW9298$age)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -15.023  -3.735  -0.819   2.755  33.526 
## 
## Coefficients:
##                          Estimate Std. Error t value Pr(>|t|)    
## (Intercept)               1.70477    0.52435   3.251  0.00115 ** 
## CPSSW9298$degreebachelor  4.91123    0.09938  49.418  < 2e-16 ***
## CPSSW9298$genderfemale   -2.24217    0.09902 -22.643  < 2e-16 ***
## CPSSW9298$age             0.33245    0.01740  19.106  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 5.665 on 13497 degrees of freedom
## Multiple R-squared:  0.1877, Adjusted R-squared:  0.1876 
## F-statistic:  1040 on 3 and 13497 DF,  p-value: < 2.2e-16

Interpretacje:

  • Osoby z wykształceniem licencjackim zarabiają średnio o 4.91 tys. więcej niż osoby z wykształceniem średnim (przy stałej płci i wieku).
  • Kobiety zarabiają średnio o 2.24 tys. mniej niż mężczyźni (przy stałym poziomie wykształcenia i wieku).
  • Każdy dodatkowy rok życia zwiększa zarobki średnio o 0.33 tys. (przy stałej płci i wykształceniu).

Model wyjaśnia około 18.77% zmienności w zarobkach. Oznacza to, że model nie uwzględnia wielu innych czynników, które wpływają na zarobki (np. branża, lokalizacja, doświadczenie zawodowe).

Regresja kwantylowa

data <- CPSSW9298
kwantyle <- c(0.25, 0.50, 0.75)
reg_kwantylowa <- rq(earnings ~ age + degree + gender , tau = kwantyle, data = data)
summary(reg_kwantylowa, se = "boot")
## 
## Call: rq(formula = earnings ~ age + degree + gender, tau = kwantyle, 
##     data = data)
## 
## tau: [1] 0.25
## 
## Coefficients:
##                Value     Std. Error t value   Pr(>|t|) 
## (Intercept)      2.67308   0.38777    6.89339   0.00000
## age              0.17308   0.01365   12.67920   0.00000
## degreebachelor   3.59188   0.06431   55.84980   0.00000
## genderfemale    -1.32265   0.07062  -18.72785   0.00000
## 
## Call: rq(formula = earnings ~ age + degree + gender, tau = kwantyle, 
##     data = data)
## 
## tau: [1] 0.5
## 
## Coefficients:
##                Value     Std. Error t value   Pr(>|t|) 
## (Intercept)      1.45427   0.49704    2.92588   0.00344
## age              0.31389   0.01729   18.15274   0.00000
## degreebachelor   4.70043   0.11085   42.40338   0.00000
## genderfemale    -2.12970   0.09624  -22.12868   0.00000
## 
## Call: rq(formula = earnings ~ age + degree + gender, tau = kwantyle, 
##     data = data)
## 
## tau: [1] 0.75
## 
## Coefficients:
##                Value     Std. Error t value   Pr(>|t|) 
## (Intercept)      1.53846   0.92264    1.66747   0.09544
## age              0.43269   0.02998   14.43478   0.00000
## degreebachelor   5.75962   0.15277   37.70122   0.00000
## genderfemale    -2.97009   0.12878  -23.06241   0.00000

Analiza wpływu wieku, wykształcenia i płci na zarobki w różnych kwantylach dostarcza interesujących wniosków. Wyniki wskazują, że starszy wiek ma większy wpływ na zarobki osób znajdujących się w wyższych kwantylach wynagrodzeń. W dolnym 25% zarobków każdy rok życia zwiększa wynagrodzenie o 0.17 tys., podczas gdy w grupie najlepiej zarabiających (75%) wzrost wynosi już 0.43 tys. Oznacza to, że starszy wiek bardziej korzystnie wpływa na osoby osiągające wyższe dochody.

Wykształcenie licencjackie również odgrywa istotną rolę, szczególnie w medianie i górnych kwantylach. W grupie osób z najniższymi zarobkami wykształcenie licencjackie zwiększa wynagrodzenie średnio o 3.59 tys., ale w medianie i wśród najlepiej zarabiających wpływ ten rośnie do 4.70 tys. Świadczy to o tym, że wyższe wykształcenie ma szczególną wartość wśród osób z wyższymi dochodami.

Różnice w wynagrodzeniach między płciami są widoczne we wszystkich kwantylach, ale najbardziej niepokojące są w górnym 25% zarobków. Kobiety zarabiają mniej niż mężczyźni, a różnice te rosną w zależności od poziomu dochodów: od 1.32 tys. w najniższych zarobkach do 2.97 tys. wśród najlepiej zarabiających.

plot(rq(earnings ~ age + degree + gender, tau = c(0.25, 0.5, 0.75), data = data))

kwantyle <- c(0.25, 0.50, 0.75)
model_q25 <- rq(earnings ~ age + degree + gender, tau = 0.25, data = data)
model_q50 <- rq(earnings ~ age + degree + gender, tau = 0.50, data = data)
model_q75 <- rq(earnings ~ age + degree + gender, tau = 0.75, data = data)
coef_q25 <- coef(model_q25)
coef_q50 <- coef(model_q50)
coef_q75 <- coef(model_q75)

coef_table <- data.frame(
  Kwantyl = c(0.25, 0.50, 0.75),
  Intercept = c(coef_q25[1], coef_q50[1], coef_q75[1]),
  Age = c(coef_q25["age"], coef_q50["age"], coef_q75["age"]),
  Degree = c(coef_q25["degreebachelor"], coef_q50["degreebachelor"], coef_q75["degreebachelor"]),
  Gender = c(coef_q25["genderfemale"], coef_q50["genderfemale"], coef_q75["genderfemale"])
)

print(coef_table)
##   Kwantyl Intercept       Age   Degree    Gender
## 1    0.25  2.673078 0.1730769 3.591880 -1.322649
## 2    0.50  1.454274 0.3138889 4.700427 -2.129701
## 3    0.75  1.538464 0.4326922 5.759616 -2.970085

Tabela przedstawia wyniki regresji kwantylowej dla trzech wybranych kwantyli: 0.25 (dolne 25% zarobków), 0.50 (mediana zarobków), i 0.75 (górne 25% zarobków). Jest to analiza, która pozwala zobaczyć, jak zmienne niezależne wpływają na zarobki w różnych częściach rozkładu wynagrodzeń, a nie tylko na średnią (jak w klasycznej regresji liniowej).

Weryfikacja statystyczna istotności różnic między pierwszym, drugim i trzecim kwartylem

anova(reg_kwantylowa, test = "Wald", joint=TRUE)
## Quantile Regression Analysis of Deviance Table
## 
## Model: earnings ~ age + degree + gender
## Joint Test of Equality of Slopes: tau in {  0.25 0.5 0.75  }
## 
##   Df Resid Df F value    Pr(>F)    
## 1  6    40497   90.65 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Hipoteza zerowa: Współczynniki dla kwantyli są takie same. Hipoteza alternatywna: Współczynniki różnią się między kwantylami.

Ponieważ wartość p jest bardzo niska, odrzucamy hipotezę zerową. Oznacza to, że wpływ zmiennych (wiek, wykształcenie, płeć) różni się w różnych częściach rozkładu zarobków.

anova(reg_kwantylowa, test = "Wald", joint=FALSE)
## Quantile Regression Analysis of Deviance Table
## 
## Model: earnings ~ age + degree + gender
## Tests of Equality of Distinct Slopes: tau in {  0.25 0.5 0.75  }
## 
##                Df Resid Df F value    Pr(>F)    
## age             2    40501  72.465 < 2.2e-16 ***
## degreebachelor  2    40501 117.817 < 2.2e-16 ***
## genderfemale    2    40501  88.771 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Wszystkie zmienne (age, degreebachelor, genderfemale) mają istotnie różny wpływ na zarobki w zależności od kwantyla.

Dobroć dopasowania

# Obliczenie reszt dla modeli
reszty_lm <- resid(model_lm)  
model2 <- rq(earnings ~ 1, tau = 0.25, data = data)  
reszty_2 <- resid(model2) 
model3 <- rq(earnings ~ 1, tau = 0.75,data=data)
reszty3 <- resid(model3)

par(mfrow = c(1, 3))  # Podziel przestrzeń na 3 kolumny

# Histogram dla modelu liniowego
hist(reszty_lm,
     main = "Histogram reszt (model liniowy)",
     xlab = "Reszty",
     col = "black", border = "grey")

# Histogram dla modelu kwantylowego tau = 0.25
hist(reszty_2,
     main = "Histogram reszt (tau = 0.25)",
     xlab = "Reszty",
     col = "gold", border = "black")

# Histogram dla modelu kwantylowego tau = 0.75
hist(reszty3,
     main = "Histogram reszt (tau = 0.75)",
     xlab = "Reszty",
     col = "purple", border = "black")

coef_long <- reshape2::melt(coef_table, id.vars = "Kwantyl", 
                            variable.name = "Zmienna", value.name = "Współczynnik")
ggplot(coef_long, aes(x = Kwantyl, y = Współczynnik, color = Zmienna)) +
  geom_line(size = 1) +
  geom_point(size = 2) +
  labs(
    title = "Współczynniki regresji kwantylowej",
    x = "Kwantyl",
    y = "Współczynnik",
    color = "Zmienna"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16),
    axis.title = element_text(size = 12),
    legend.title = element_text(size = 12)
  )
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Wpływ zmiennych jest zróżnicowany w różnych częściach rozkładu zarobków, co wskazuje na to, że klasyczna regresja liniowa (która zakłada stały wpływ zmiennych na całość rozkładu) mogłaby nie uchwycić tych różnic.

-Wpływ wieku rośnie wraz ze wzrostem kwantyla. Starszy wiek ma największy wpływ na zarobki w grupie najlepiej zarabiających, co jest zgodne z oczekiwaniem, że doświadczenie zawodowe bardziej się opłaca w tej grupie. - Wykształcenie ma rosnący wpływ w miarę wzrostu kwantyla. Sugeruje to, że wartość wyższego wykształcenia jest bardziej doceniana w grupie osób osiągających najwyższe dochody. - Wartości ujemne współczynnika Gender wskazują na niższe zarobki kobiet w porównaniu do mężczyzn.

LS0tDQp0aXRsZTogJ1JlZ3Jlc2phIGt3YW50eWxvd2EnDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQphdXRob3I6ICJNYcWCZ29yemF0YSBEdWRhbm93aWN6Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlDQogICAgZm9udHNpemU6IDEwcHQNCiAgICB0b2M6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgICBkZl9wcmludDogZGVmYXVsdA0KICAgIHRvY19kZXB0aDogNQ0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQpgYGB7ciBwcmVyZXFzLCBtZXNzYWdlID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCmxpYnJhcnkoQ1ZYUikNCmxpYnJhcnkoQUVSKQ0KbGlicmFyeShzdGFyZ2F6ZXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkocXVhbnRyZWcpDQpsaWJyYXJ5KFBvZ3JvbWN5RGFueWNoKQ0KbGlicmFyeSh2Y2QpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KYGBgDQoNCiMjIERsYWN6ZWdvIGt3YW50eWxvd2E/DQoNCkRsYWN6ZWdvIHBvdHJ6ZWJ1amVteSByZWdyZXNqaSBrd2FudHlsb3dlaiAoUVIpPw0KDQpXIHN6Y3plZ8OzbG5vxZtjaSwgUVI6DQoNCi0gICBqZXN0IG9kcG9ybmEgbmEgcHVua3R5IG9kc3RhasSFY2UgaSB3cMWCeXdvd2UNCg0KLSAgIG5pZSB6YWvFgmFkYSBzdGHFgmVqIHdhcmlhbmNqaSAoem5hbmVqIGpha28gaG9tb3NrZWRhc3R5Y3pub8WbxIcpIGRsYQ0KICAgIHptaWVubmVqIG9kcG93aWVkemkgbHViIHJlc3p0DQoNCi0gICBuaWUgemFrxYJhZGEgbm9ybWFsbm/Fm2NpIGFsZSBnxYLDs3duxIUgemFsZXTEhSBRUiB3IHBvcsOzd25hbml1IHogcmVncmVzasSFDQogICAgbGluaW93xIUgKExSKSBqZXN0IHRvLCDFvGUgUVIgYmFkYSByw7PFvG5lIHdhcnRvxZtjaSB6bWllbm5laiBvZHBvd2llZHppLA0KICAgIGEgbmllIHR5bGtvIMWbcmVkbmnEhSwgaSBkb3N0YXJjemEgdyB6d2nEhXprdSB6IHR5bSBwZcWCbmllanN6ZWdvIG9icmF6dQ0KICAgIHp3acSFemvDs3cgbWnEmWR6eSB6bWllbm55bWkhDQoNCiMjIFdwcm93YWR6ZW5pZQ0KDQpSZWdyZXNqYSBrd2FudHlsb3dhIChhbmcuIHF1YW50aWxlIHJlZ3Jlc3Npb24pIHpvc3RhxYJhIHphcHJvcG9ub3dhbmENCnByemV6IEtvZW5rZXJhIGkgQmFzc2V0dGEgKDE5NzgpLiBTemN6ZWfDs2xueSBwcnp5cGFkZWsgcmVncmVzamkNCmt3YW50eWxvd2VqIGRsYSBrd2FudHlsYSByesSZZHUgMCw1IChjenlsaSBtZWRpYW55KSBqZXN0IHLDs3dub3dhxbxueQ0KZXN0eW1hdG9yb3dpIExBRCAoYW5nLiBMZWFzdCBBYnNvbHV0ZSBEZXZpYXRpb24pIC0tIG1pbmltYWxpenVqZSBzdW3EmQ0KYmV6d3pnbMSZZG55Y2ggYsWCxJlkw7N3LlwNCldwcm93YWR6ZW5pZSByw7PFvG55Y2gga3dhbnR5bGkgcmVncmVzamkgZGFqZSBwZcWCbmllanN6eSBvcGlzIHJvemvFgmFkw7N3DQp3YXJ1bmtvd3ljaCB6d8WCYXN6Y3phIHcgcHJ6eXBhZGt1IHJvemvFgmFkw7N3IGFzeW1ldHJ5Y3pueWNoIGx1YiB1Y2nEmXR5Y2guDQoNCg0KIyMgV3ltYWdhbmlhDQoNCld5bWFnYW5hIGplc3QgamVkbmEgbGljemJvd2Egem1pZW5uYSB6YWxlxbxuYS4gWm1pZW5uYSBwcnpld2lkeXdhbmEgbXVzaQ0KYnnEhyB6bWllbm7EhSBpbG/Fm2Npb3fEhS4gUHJlZHlrdG9yeSBtb2fEhSBiecSHIHptaWVubnltaSBpbG/Fm2Npb3d5bWkgbHViDQpzenR1Y3pueW1pIHptaWVubnltaSB3IHByenlwYWRrdSBwcmVkeWt0b3LDs3cgamFrb8WbY2lvd3ljaC4gQWJ5IG1vxbxuYQ0KYnnFgm8gdXJ1Y2hvbWnEhyBhbmFsaXrEmSwgd3ltYWdhbnkgamVzdCB3eXJheiB3b2xueSBsdWIgY28gbmFqbW5pZWogamVkZW4NCnByZWR5a3Rvci4NCg0KUmVncmVzamEga3dhbnR5bG93YSBuaWUgY3p5bmkgemHFgm/FvGXFhCBkb3R5Y3rEhWN5Y2ggcm96a8WCYWR1IHptaWVubmVqDQpwcnpld2lkeXdhbmVqIGkgamVzdCBvZHBvcm5hIG5hIHdwxYJ5dyBvYnNlcndhY2ppIG9kc3RhasSFY3ljaC4NCg0KQW5hbGl6YSBrd2FudHlsb3dhIGplc3QgcG9rcmV3bmEgcmVncmVzamkgbWV0b2TEhSBuYWptbmllanN6eWNoDQprd2FkcmF0w7N3Lg0KDQojIyBaYWRhbmllDQoNClRlcmF6IFdhc3phIGtvbGVqIDstKQ0KDQpXYXN6eW0gemFkYW5pZW0gZHppc2lhaiBqZXN0IHphbW9kZWxvd2FuaWUgLSBwb3LDs3duYW5pZSBLTU5LIG9yYXoNCnJlZ3Jlc2ppIGt3YW50eWxvd2VqIChyw7PFvG5vLXBvemlvbW93ZWopIGRsYSB6bWllbm5laiAiZWFybmluZ3MiIC0NCnd5bmFncm9kemVuaWEuDQoNCkRvYmllcnogaSBwcnpldGVzdHVqIHByZWR5a3RvcnksIGt3YW50eWxlIGRsYSBtb2RlbGkuIFd5a29uYWogdGVzdHkNCnLDs8W8bmljIHdzcMOzxYJjenlubmlrb3cgZGxhIGZpbmFsbnljaCBtb2RlbGkuDQoNClcgcHJ6eXBhZGt1IHByb2JsZW3Ds3cgLSBvYmVqcnp5aiB2aWRlbyB0dXRvcmlhbCAod8WCxIVjeiBwb2xza2llIG5hcGlzeSkNCm9yYXogd2VqZMW6IG5hIGplZ28gc3Ryb27EmSB6ZSDFunLDs2TFgmFtaS4gTW/FvGVzeiByw7N3bmllxbwgd3lrb3J6eXN0YcSHIHcvdw0KcHJ6eWvFgmFkeS4NCg0KTmEgcG9jesSFdGt1IHdjenl0dWplbXkgZGFuZToNCg0KYGBge3J9DQpkYXRhKCJDUFNTVzkyOTgiKQ0KIz9DUFNTVzkyOTggDQpgYGANCg0KWmVzdGF3IGRhbnljaCBDUFNTVzkyOTggamVzdCB1xbx5d2FueSBkbyBhbmFsaXp5IHJ5bmt1IHByYWN5LiBPYmVqbXVqZSBuYXN0xJlwdWrEhWNlIHptaWVubmU6DQoNCi15ZWFyOiBSb2ssIHcga3TDs3J5bSBkYW5lIHpvc3RhxYJ5IHplYnJhbmUNCi1lYXJuaW5nczogV3luYWdyb2R6ZW5pZSBiYWRhbmVqIG9zb2J5ICh3eXJhxbxvbmUgdyB0eXNpxIVjYWNoKQ0KLWRlZ3JlZTogUG96aW9tIHd5a3N6dGHFgmNlbmlhIGJhZGFuZWogb3NvYnksIG5wLiAiaGlnaHNjaG9vbCIgKHN6a2/FgmEgxZtyZWRuaWEpLCAiYmFjaGVsb3IiICh0eXR1xYIgbGljZW5jamF0YSkNCi1nZW5kZXI6IFDFgmXEhyBvc29ieSwgbnAuICJtYWxlIiAobcSZxbxjenl6bmEpLCAiZmVtYWxlIiAoa29iaWV0YSkNCi1hZ2U6IFdpZWsgYmFkYW5laiBvc29ieQ0KDQojIyMgV2l6dWFsaXphY2phIGRhbnljaA0KDQpUZXJheiB6b3N0YW5pZSBwcnplcHJvd2Fkem9uYSBhbmFsaXphIGtpbGt1IHd5a3Jlc8OzdywgYWJ5IHpiYWRhxIcgaSBsZXBpZWogenJvenVtaWXEhyB6YWxlxbxub8WbY2kgcG9tacSZZHp5IHLDs8W8bnltaSB6bWllbm55bWkuIA0KDQpgYGB7cn0NCmdncGxvdChDUFNTVzkyOTgsIGFlcyh4ID0gZWFybmluZ3MpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJtZWRpdW1wdXJwbGUiLCBjb2xvciA9ICJibGFjayIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSb3prxYJhZCB3eW5hZ3JvZHplxYQiLA0KICAgIHggPSAiV3luYWdyb2R6ZW5pZSAodyB0eXNpxIVjYWNoKSIsDQogICAgeSA9ICJMaWN6YmEgb2JzZXJ3YWNqaSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiwgY29sb3IgPSAiYmxhY2siKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKQ0KICApDQpgYGANCg0KUm96a8WCYWQgd3luYWdyb2R6ZcWEIGplc3QgYXN5bWV0cnljem55LCB6IHd5cmHFum55bSBwcmF3b3N0cm9ubnltIG9nb25lbSwgY28gb3puYWN6YSwgxbxlIHdpxJlrc3phIGxpY3piYSBvc8OzYiB6YXJhYmlhIG5pxbxzemUgd3luYWdyb2R6ZW5pYSwgcG9kY3phcyBnZHkgd3nFvHN6ZSB3eW5hZ3JvZHplbmlhIHPEhSByemFkc3plLiBLc3p0YcWCdCBzdWdlcnVqZSwgxbxlIHd5bmFncm9kemVuaWEgbW9nxIUgYnnEhyByb3prxYJhZGVtIHNrb8WbbnltIChza2/Fm25vxZvEhyBwcmF3b3N0cm9ubmEpLk5handpxJljZWogb3PDs2IgemFyYWJpYSBva2/Fgm8gMTAgdHlzacSZY3kgKHphdXdhxbxhbG55IG5hand5xbxzenkgc8WCdXBlayBoaXN0b2dyYW11IHcgdGVqIG9rb2xpY3kpLg0KDQpgYGB7cn0NCmdncGxvdChDUFNTVzkyOTgsIGFlcyh4ID0gZGVncmVlLCB5ID0gZWFybmluZ3MsIGZpbGwgPSBkZWdyZWUpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibWVkaXVtcHVycGxlIiwgImdvbGQiKSkgKyANCiAgbGFicygNCiAgICB0aXRsZSA9ICJXeW5hZ3JvZHplbmllIHd6Z2zEmWRlbSB3eWtzenRhxYJjZW5pYSIsDQogICAgeCA9ICJQb3ppb20gd3lrc3p0YcWCY2VuaWEiLA0KICAgIHkgPSAiV3luYWdyb2R6ZW5pZSAodyB0eXNpxIVjYWNoKSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiwgY29sb3IgPSAiYmxhY2siKSwgIA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpLCAgDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCmBgYA0KDQpPc29ieSB6IHd5a3N6dGHFgmNlbmllbSAiYmFjaGVsb3IiIChsaWNlbmNqYWNraW0pIG1hasSFIHd5xbxzesSFIG1lZGlhbsSZIHd5bmFncm9kemXFhCB3IHBvcsOzd25hbml1IGRvIG9zw7NiIHogd3lrc3p0YcWCY2VuaWVtICJoaWdoc2Nob29sIiAoxZtyZWRuaW0pLld5bmFncm9kemVuaWEgZGxhIG9idSBncnVwIHPEhSB6csOzxbxuaWNvd2FuZSwgYWxlIHJvenN0xJlwIG1pxJlkenlrd2FydHlsb3d5IChvZGxlZ8WCb8WbxIcgbWnEmWR6eSBkb2xueW0gaSBnw7NybnltIGt3YXJ0eWxlbSkgamVzdCB3acSZa3N6eSBkbGEgb3PDs2IgeiB3eWtzenRhxYJjZW5pZW0gbGljZW5jamFja2ltLCBjbyB3c2thenVqZSBuYSB3acSZa3N6ZSB6csOzxbxuaWNvd2FuaWUgd3luYWdyb2R6ZcWEIHcgdGVqIGdydXBpZS5XIG9idSBncnVwYWNoIHdpZGHEhyBvYmVjbm/Fm8SHIHdhcnRvxZtjaSBvZHN0YWrEhWN5Y2ggKG91dGxpZXJzKSwgY3p5bGkgb3PDs2IgemFyYWJpYWrEhWN5Y2ggem5hY3puaWUgd2nEmWNlaiBuacW8IHdpxJlrc3pvxZvEhy4gTGljemJhIHdhcnRvxZtjaSBvZHN0YWrEhWN5Y2ggamVzdCB3ecW8c3phIHcgZ3J1cGllIHogd3lrc3p0YcWCY2VuaWVtICJiYWNoZWxvciIuDQoNCmBgYHtyfQ0KZ2dwbG90KENQU1NXOTI5OCwgYWVzKHggPSB5ZWFyLCB5ID0gZWFybmluZ3MpKSArDQogIHN0YXRfc3VtbWFyeShmdW4gPSAibWVhbiIsIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IDEpLCBjb2xvciA9ICJkYXJrb3JjaGlkIiwgbGluZXdpZHRoID0gMSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuID0gIm1lYW4iLCBnZW9tID0gInBvaW50IiwgY29sb3IgPSAicHVycGxlIiwgc2l6ZSA9IDIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICLFmnJlZG5pZSB3eW5hZ3JvZHplbmllIHcgY3phc2llIiwNCiAgICB4ID0gIlJvayIsDQogICAgeSA9ICLFmnJlZG5pZSB3eW5hZ3JvZHplbmllICh3IHR5c2nEhWNhY2gpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBjb2xvciA9ICJibGFjayIpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApDQogICkNCg0KYGBgDQoNCsWacmVkbmllIHd5bmFncm9kemVuaWUgc3lzdGVtYXR5Y3puaWUgcm9zxYJvIHcgY3phc2llIHcgYW5hbGl6b3dhbnltIG9rcmVzaWUgKDE5OTLigJMxOTk4KS4gVGFraSB3enJvc3QgbW/FvGUgd3luaWthxIcgeiBvZ8OzbG5laiBwb3ByYXd5IGdvc3BvZGFya2ksIGluZmxhY2ppLCBsdWIgem1pYW4gdyBzdHJ1a3R1cnplIHJ5bmt1IHByYWN5Lg0KDQpgYGB7cn0NCmdncGxvdChDUFNTVzkyOTgsIGFlcyh4ID0gZ2VuZGVyLCB5ID0gZWFybmluZ3MsIGZpbGwgPSBnZW5kZXIpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibWVkaXVtcHVycGxlIiwgImdvbGQiKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIld5bmFncm9kemVuaWUgd3pnbMSZZGVtIHDFgmNpIiwNCiAgICB4ID0gIlDFgmXEhyIsDQogICAgeSA9ICJXeW5hZ3JvZHplbmllICh3IHR5c2nEhWNhY2gpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBjb2xvciA9ICJibGFjayIpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApDQpgYGANCg0KTcSZxbxjennFum5pICgibWFsZSIpIG1hasSFIHd5xbxzesSFIG1lZGlhbsSZIHd5bmFncm9kemXFhCB3IHBvcsOzd25hbml1IGRvIGtvYmlldCAoImZlbWFsZSIpLld5bmFncm9kemVuaWEgemFyw7N3bm8gbcSZxbxjenl6biwgamFrIGkga29iaWV0IGNoYXJha3Rlcnl6dWrEhSBzacSZIG9iZWNub8WbY2nEhSB3YXJ0b8WbY2kgb2RzdGFqxIVjeWNoLCBhbGUgbcSZxbxjennFum5pIG1hasSFIHdpxJlrc3p5IHJvenN0xJlwIG1ha3N5bWFsbnljaCB3eW5hZ3JvZHplxYQuDQoNCmBgYHtyfQ0KZ2dwbG90KENQU1NXOTI5OCwgYWVzKHggPSBlYXJuaW5ncywgZmlsbCA9IGdlbmRlcikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWxwaGEgPSAwLjcsIGJpbnMgPSAzMCwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIm1lZGl1bXB1cnBsZSIsICJnb2xkIikpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSb3prxYJhZCB3eW5hZ3JvZHplxYQgd2VkxYJ1ZyBwxYJjaSIsDQogICAgeCA9ICJXeW5hZ3JvZHplbmllICh3IHR5c2nEhWNhY2gpIiwNCiAgICB5ID0gIkxpY3piYSBvYnNlcndhY2ppIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpDQogICkNCmBgYA0KDQpXeW5hZ3JvZHplbmlhIGRsYSBvYnUgcMWCY2kgbWFqxIUgcHJhd29zdHJvbm7EhSBza2/Fm25vxZvEhyDigJMgd2nEmWtzem/Fm8SHIG9zw7NiIHphcmFiaWEgdyBkb2xueW0gemFrcmVzaWUgd3luYWdyb2R6ZcWEIChwb25pxbxlaiAyMCB0eXNpxJljeSksIGEgbGljemJhIG9zw7NiIHphcmFiaWFqxIVjeWNoIHdpxJljZWogc3lzdGVtYXR5Y3puaWUgbWFsZWplLiBNxJnFvGN6ecW6bmkgb3NpxIVnYWrEhSBzemVyc3p5IHpha3JlcyB3eW5hZ3JvZHplxYQsIHcgdHltIG5hand5xbxzemUgemFyb2JraSwgY28gcG90d2llcmR6YWrEhSBkxYJ1xbxzemUg4oCeb2dvbnnigJ0gZmlvbGV0b3dlZ28gcm96a8WCYWR1Lg0KDQpgYGB7cn0NCmdncGxvdChDUFNTVzkyOTgsIGFlcyh4ID0gYWdlLCB5ID0gZWFybmluZ3MpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjcsIGNvbG9yID0gIm1lZGl1bXB1cnBsZSIpICsNCiAgZ2VvbV9zbW9vdGgoYWVzKHggPSBhZ2UsIHkgPSBlYXJuaW5ncyksIG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgc2UgPSBGQUxTRSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ29sZCIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJXeW5hZ3JvZHplbmllIHd6Z2zEmWRlbSB3aWVrdSIsDQogICAgeCA9ICJ3aWVrIiwNCiAgICB5ID0gInd5bmFncm9kemVuaWUgKHcgdHlzacSFY2FjaCkiDQogICkgKw0KICBmYWNldF9ncmlkKGdlbmRlciB+IGRlZ3JlZSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKQ0KICApDQpgYGANCg0KUG93ecW8c3p5IHd5a3JlcyBwb3R3aWVyZHphIGRvdHljaGN6YXNvd2Ugb2JzZXJ3YWNqZS5Pc29ieSB6IHd5a3N6dGHFgmNlbmllbSAiYmFjaGVsb3IiIChsaWNlbmNqYWNraW0pIG9zacSFZ2FqxIUgd3nFvHN6ZSB3eW5hZ3JvZHplbmlhIHcgcG9yw7N3bmFuaXUgZG8gb3PDs2IgeiB3eWtzenRhxYJjZW5pZW0gImhpZ2hzY2hvb2wiICjFm3JlZG5pbSkuIEplc3QgdG8gd2lkb2N6bmUgemFyw7N3bm8gdyBwcnp5cGFka3UgbcSZxbxjenl6biwgamFrIGkga29iaWV0LlLDs8W8bmljYSBtacSZZHp5IHd5bmFncm9kemVuaWFtaSBtxJnFvGN6eXpuIGkga29iaWV0IGplc3Qgd2lkb2N6bmEgemFyw7N3bm8gdyBncnVwaWUgb3PDs2IgeiB3eWtzenRhxYJjZW5pZW0gxZtyZWRuaW0sIGphayBpIGxpY2VuY2phY2tpbS4NCg0KIyMjIE1vZGVsIGxpbmlvd3kNCg0KYGBge3J9DQptb2RlbF9sbSA8LSBsbShDUFNTVzkyOTgkZWFybmluZ3MgfiBDUFNTVzkyOTgkZGVncmVlICsgQ1BTU1c5Mjk4JGdlbmRlciArIENQU1NXOTI5OCRhZ2UpDQpzdW1tYXJ5KG1vZGVsX2xtKSAgDQpgYGANCg0KSW50ZXJwcmV0YWNqZToNCg0KLSBPc29ieSB6IHd5a3N6dGHFgmNlbmllbSBsaWNlbmNqYWNraW0gemFyYWJpYWrEhSDFm3JlZG5pbyBvIDQuOTEgdHlzLiB3acSZY2VqIG5pxbwgb3NvYnkgeiB3eWtzenRhxYJjZW5pZW0gxZtyZWRuaW0gKHByenkgc3RhxYJlaiBwxYJjaSBpIHdpZWt1KS4NCi0gS29iaWV0eSB6YXJhYmlhasSFIMWbcmVkbmlvIG8gMi4yNCB0eXMuIG1uaWVqIG5pxbwgbcSZxbxjennFum5pIChwcnp5IHN0YcWCeW0gcG96aW9taWUgd3lrc3p0YcWCY2VuaWEgaSB3aWVrdSkuDQotIEthxbxkeSBkb2RhdGtvd3kgcm9rIMW8eWNpYSB6d2nEmWtzemEgemFyb2JraSDFm3JlZG5pbyBvIDAuMzMgdHlzLiAocHJ6eSBzdGHFgmVqIHDFgmNpIGkgd3lrc3p0YcWCY2VuaXUpLg0KDQpNb2RlbCB3eWphxZtuaWEgb2tvxYJvIDE4Ljc3JSB6bWllbm5vxZtjaSB3IHphcm9ia2FjaC4gT3puYWN6YSB0bywgxbxlIG1vZGVsIG5pZSB1d3pnbMSZZG5pYSB3aWVsdSBpbm55Y2ggY3p5bm5pa8Ozdywga3TDs3JlIHdwxYJ5d2FqxIUgbmEgemFyb2JraSAobnAuIGJyYW7FvGEsIGxva2FsaXphY2phLCBkb8Wbd2lhZGN6ZW5pZSB6YXdvZG93ZSkuDQoNCiMjIyBSZWdyZXNqYSBrd2FudHlsb3dhDQoNCmBgYHtyfQ0KZGF0YSA8LSBDUFNTVzkyOTgNCmt3YW50eWxlIDwtIGMoMC4yNSwgMC41MCwgMC43NSkNCnJlZ19rd2FudHlsb3dhIDwtIHJxKGVhcm5pbmdzIH4gYWdlICsgZGVncmVlICsgZ2VuZGVyICwgdGF1ID0ga3dhbnR5bGUsIGRhdGEgPSBkYXRhKQ0Kc3VtbWFyeShyZWdfa3dhbnR5bG93YSwgc2UgPSAiYm9vdCIpDQpgYGANCg0KQW5hbGl6YSB3cMWCeXd1IHdpZWt1LCB3eWtzenRhxYJjZW5pYSBpIHDFgmNpIG5hIHphcm9ia2kgdyByw7PFvG55Y2gga3dhbnR5bGFjaCBkb3N0YXJjemEgaW50ZXJlc3VqxIVjeWNoIHduaW9za8Ozdy4gV3luaWtpIHdza2F6dWrEhSwgxbxlIHN0YXJzenkgd2llayBtYSB3acSZa3N6eSB3cMWCeXcgbmEgemFyb2JraSBvc8OzYiB6bmFqZHVqxIVjeWNoIHNpxJkgdyB3ecW8c3p5Y2gga3dhbnR5bGFjaCB3eW5hZ3JvZHplxYQuIFcgZG9sbnltIDI1JSB6YXJvYmvDs3cga2HFvGR5IHJvayDFvHljaWEgendpxJlrc3phIHd5bmFncm9kemVuaWUgbyAwLjE3IHR5cy4sIHBvZGN6YXMgZ2R5IHcgZ3J1cGllIG5hamxlcGllaiB6YXJhYmlhasSFY3ljaCAoNzUlKSB3enJvc3Qgd3lub3NpIGp1xbwgMC40MyB0eXMuIE96bmFjemEgdG8sIMW8ZSBzdGFyc3p5IHdpZWsgYmFyZHppZWoga29yenlzdG5pZSB3cMWCeXdhIG5hIG9zb2J5IG9zacSFZ2FqxIVjZSB3ecW8c3plIGRvY2hvZHkuDQoNCld5a3N6dGHFgmNlbmllIGxpY2VuY2phY2tpZSByw7N3bmllxbwgb2Rncnl3YSBpc3RvdG7EhSByb2zEmSwgc3pjemVnw7NsbmllIHcgbWVkaWFuaWUgaSBnw7NybnljaCBrd2FudHlsYWNoLiBXIGdydXBpZSBvc8OzYiB6IG5ham5pxbxzenltaSB6YXJvYmthbWkgd3lrc3p0YcWCY2VuaWUgbGljZW5jamFja2llIHp3acSZa3N6YSB3eW5hZ3JvZHplbmllIMWbcmVkbmlvIG8gMy41OSB0eXMuLCBhbGUgdyBtZWRpYW5pZSBpIHfFm3LDs2QgbmFqbGVwaWVqIHphcmFiaWFqxIVjeWNoIHdwxYJ5dyB0ZW4gcm/Fm25pZSBkbyA0LjcwIHR5cy4gxZp3aWFkY3p5IHRvIG8gdHltLCDFvGUgd3nFvHN6ZSB3eWtzenRhxYJjZW5pZSBtYSBzemN6ZWfDs2xuxIUgd2FydG/Fm8SHIHfFm3LDs2Qgb3PDs2IgeiB3ecW8c3p5bWkgZG9jaG9kYW1pLg0KDQpSw7PFvG5pY2UgdyB3eW5hZ3JvZHplbmlhY2ggbWnEmWR6eSBwxYJjaWFtaSBzxIUgd2lkb2N6bmUgd2Ugd3N6eXN0a2ljaCBrd2FudHlsYWNoLCBhbGUgbmFqYmFyZHppZWogbmllcG9rb2rEhWNlIHPEhSB3IGfDs3JueW0gMjUlIHphcm9ia8Ozdy4gS29iaWV0eSB6YXJhYmlhasSFIG1uaWVqIG5pxbwgbcSZxbxjennFum5pLCBhIHLDs8W8bmljZSB0ZSByb3NuxIUgdyB6YWxlxbxub8WbY2kgb2QgcG96aW9tdSBkb2Nob2TDs3c6IG9kIDEuMzIgdHlzLiB3IG5ham5pxbxzenljaCB6YXJvYmthY2ggZG8gMi45NyB0eXMuIHfFm3LDs2QgbmFqbGVwaWVqIHphcmFiaWFqxIVjeWNoLiANCg0KYGBge3J9DQpwbG90KHJxKGVhcm5pbmdzIH4gYWdlICsgZGVncmVlICsgZ2VuZGVyLCB0YXUgPSBjKDAuMjUsIDAuNSwgMC43NSksIGRhdGEgPSBkYXRhKSkNCmBgYA0KDQpgYGB7cn0NCmt3YW50eWxlIDwtIGMoMC4yNSwgMC41MCwgMC43NSkNCm1vZGVsX3EyNSA8LSBycShlYXJuaW5ncyB+IGFnZSArIGRlZ3JlZSArIGdlbmRlciwgdGF1ID0gMC4yNSwgZGF0YSA9IGRhdGEpDQptb2RlbF9xNTAgPC0gcnEoZWFybmluZ3MgfiBhZ2UgKyBkZWdyZWUgKyBnZW5kZXIsIHRhdSA9IDAuNTAsIGRhdGEgPSBkYXRhKQ0KbW9kZWxfcTc1IDwtIHJxKGVhcm5pbmdzIH4gYWdlICsgZGVncmVlICsgZ2VuZGVyLCB0YXUgPSAwLjc1LCBkYXRhID0gZGF0YSkNCmNvZWZfcTI1IDwtIGNvZWYobW9kZWxfcTI1KQ0KY29lZl9xNTAgPC0gY29lZihtb2RlbF9xNTApDQpjb2VmX3E3NSA8LSBjb2VmKG1vZGVsX3E3NSkNCg0KY29lZl90YWJsZSA8LSBkYXRhLmZyYW1lKA0KICBLd2FudHlsID0gYygwLjI1LCAwLjUwLCAwLjc1KSwNCiAgSW50ZXJjZXB0ID0gYyhjb2VmX3EyNVsxXSwgY29lZl9xNTBbMV0sIGNvZWZfcTc1WzFdKSwNCiAgQWdlID0gYyhjb2VmX3EyNVsiYWdlIl0sIGNvZWZfcTUwWyJhZ2UiXSwgY29lZl9xNzVbImFnZSJdKSwNCiAgRGVncmVlID0gYyhjb2VmX3EyNVsiZGVncmVlYmFjaGVsb3IiXSwgY29lZl9xNTBbImRlZ3JlZWJhY2hlbG9yIl0sIGNvZWZfcTc1WyJkZWdyZWViYWNoZWxvciJdKSwNCiAgR2VuZGVyID0gYyhjb2VmX3EyNVsiZ2VuZGVyZmVtYWxlIl0sIGNvZWZfcTUwWyJnZW5kZXJmZW1hbGUiXSwgY29lZl9xNzVbImdlbmRlcmZlbWFsZSJdKQ0KKQ0KDQpwcmludChjb2VmX3RhYmxlKQ0KYGBgDQoNClRhYmVsYSBwcnplZHN0YXdpYSB3eW5pa2kgcmVncmVzamkga3dhbnR5bG93ZWogZGxhIHRyemVjaCB3eWJyYW55Y2gga3dhbnR5bGk6IDAuMjUgKGRvbG5lIDI1JSB6YXJvYmvDs3cpLCAwLjUwIChtZWRpYW5hIHphcm9ia8OzdyksIGkgMC43NSAoZ8Ozcm5lIDI1JSB6YXJvYmvDs3cpLiBKZXN0IHRvIGFuYWxpemEsIGt0w7NyYSBwb3p3YWxhIHpvYmFjennEhywgamFrIHptaWVubmUgbmllemFsZcW8bmUgd3DFgnl3YWrEhSBuYSB6YXJvYmtpIHcgcsOzxbxueWNoIGN6xJnFm2NpYWNoIHJvemvFgmFkdSB3eW5hZ3JvZHplxYQsIGEgbmllIHR5bGtvIG5hIMWbcmVkbmnEhSAoamFrIHcga2xhc3ljem5laiByZWdyZXNqaSBsaW5pb3dlaikuDQoNCiMjIyBXZXJ5ZmlrYWNqYSBzdGF0eXN0eWN6bmEgaXN0b3Rub8WbY2kgcsOzxbxuaWMgbWnEmWR6eSBwaWVyd3N6eW0sIGRydWdpbSBpIHRyemVjaW0ga3dhcnR5bGVtDQoNCmBgYHtyfQ0KYW5vdmEocmVnX2t3YW50eWxvd2EsIHRlc3QgPSAiV2FsZCIsIGpvaW50PVRSVUUpDQpgYGANCg0KSGlwb3RlemEgemVyb3dhOiBXc3DDs8WCY3p5bm5pa2kgZGxhIGt3YW50eWxpIHPEhSB0YWtpZSBzYW1lLg0KSGlwb3RlemEgYWx0ZXJuYXR5d25hOiBXc3DDs8WCY3p5bm5pa2kgcsOzxbxuacSFIHNpxJkgbWnEmWR6eSBrd2FudHlsYW1pLg0KDQpQb25pZXdhxbwgd2FydG/Fm8SHIHAgamVzdCBiYXJkem8gbmlza2EsIG9kcnp1Y2FteSBoaXBvdGV6xJkgemVyb3fEhS4gT3puYWN6YSB0bywgxbxlIHdwxYJ5dyB6bWllbm55Y2ggKHdpZWssIHd5a3N6dGHFgmNlbmllLCBwxYJlxIcpIHLDs8W8bmkgc2nEmSB3IHLDs8W8bnljaCBjesSZxZtjaWFjaCByb3prxYJhZHUgemFyb2Jrw7N3Lg0KDQpgYGB7cn0NCmFub3ZhKHJlZ19rd2FudHlsb3dhLCB0ZXN0ID0gIldhbGQiLCBqb2ludD1GQUxTRSkNCmBgYA0KDQpXc3p5c3RraWUgem1pZW5uZSAoYWdlLCBkZWdyZWViYWNoZWxvciwgZ2VuZGVyZmVtYWxlKSBtYWrEhSBpc3RvdG5pZSByw7PFvG55IHdwxYJ5dyBuYSB6YXJvYmtpIHcgemFsZcW8bm/Fm2NpIG9kIGt3YW50eWxhLg0KDQojIyMgRG9icm/EhyBkb3Bhc293YW5pYQ0KDQpgYGB7cn0NCiMgT2JsaWN6ZW5pZSByZXN6dCBkbGEgbW9kZWxpDQpyZXN6dHlfbG0gPC0gcmVzaWQobW9kZWxfbG0pICANCm1vZGVsMiA8LSBycShlYXJuaW5ncyB+IDEsIHRhdSA9IDAuMjUsIGRhdGEgPSBkYXRhKSAgDQpyZXN6dHlfMiA8LSByZXNpZChtb2RlbDIpIA0KbW9kZWwzIDwtIHJxKGVhcm5pbmdzIH4gMSwgdGF1ID0gMC43NSxkYXRhPWRhdGEpDQpyZXN6dHkzIDwtIHJlc2lkKG1vZGVsMykNCg0KcGFyKG1mcm93ID0gYygxLCAzKSkgICMgUG9kemllbCBwcnplc3RyemXFhCBuYSAzIGtvbHVtbnkNCg0KIyBIaXN0b2dyYW0gZGxhIG1vZGVsdSBsaW5pb3dlZ28NCmhpc3QocmVzenR5X2xtLA0KICAgICBtYWluID0gIkhpc3RvZ3JhbSByZXN6dCAobW9kZWwgbGluaW93eSkiLA0KICAgICB4bGFiID0gIlJlc3p0eSIsDQogICAgIGNvbCA9ICJibGFjayIsIGJvcmRlciA9ICJncmV5IikNCg0KIyBIaXN0b2dyYW0gZGxhIG1vZGVsdSBrd2FudHlsb3dlZ28gdGF1ID0gMC4yNQ0KaGlzdChyZXN6dHlfMiwNCiAgICAgbWFpbiA9ICJIaXN0b2dyYW0gcmVzenQgKHRhdSA9IDAuMjUpIiwNCiAgICAgeGxhYiA9ICJSZXN6dHkiLA0KICAgICBjb2wgPSAiZ29sZCIsIGJvcmRlciA9ICJibGFjayIpDQoNCiMgSGlzdG9ncmFtIGRsYSBtb2RlbHUga3dhbnR5bG93ZWdvIHRhdSA9IDAuNzUNCmhpc3QocmVzenR5MywNCiAgICAgbWFpbiA9ICJIaXN0b2dyYW0gcmVzenQgKHRhdSA9IDAuNzUpIiwNCiAgICAgeGxhYiA9ICJSZXN6dHkiLA0KICAgICBjb2wgPSAicHVycGxlIiwgYm9yZGVyID0gImJsYWNrIikNCg0KYGBgDQoNCmBgYHtyfQ0KDQpjb2VmX2xvbmcgPC0gcmVzaGFwZTI6Om1lbHQoY29lZl90YWJsZSwgaWQudmFycyA9ICJLd2FudHlsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUubmFtZSA9ICJabWllbm5hIiwgdmFsdWUubmFtZSA9ICJXc3DDs8WCY3p5bm5payIpDQpnZ3Bsb3QoY29lZl9sb25nLCBhZXMoeCA9IEt3YW50eWwsIHkgPSBXc3DDs8WCY3p5bm5paywgY29sb3IgPSBabWllbm5hKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIldzcMOzxYJjenlubmlraSByZWdyZXNqaSBrd2FudHlsb3dlaiIsDQogICAgeCA9ICJLd2FudHlsIiwNCiAgICB5ID0gIldzcMOzxYJjenlubmlrIiwNCiAgICBjb2xvciA9ICJabWllbm5hIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2KSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikNCiAgKQ0KYGBgDQoNCldwxYJ5dyB6bWllbm55Y2ggamVzdCB6csOzxbxuaWNvd2FueSB3IHLDs8W8bnljaCBjesSZxZtjaWFjaCByb3prxYJhZHUgemFyb2Jrw7N3LCBjbyB3c2thenVqZSBuYSB0bywgxbxlIGtsYXN5Y3puYSByZWdyZXNqYSBsaW5pb3dhIChrdMOzcmEgemFrxYJhZGEgc3RhxYJ5IHdwxYJ5dyB6bWllbm55Y2ggbmEgY2HFgm/Fm8SHIHJvemvFgmFkdSkgbW9nxYJhYnkgbmllIHVjaHd5Y2nEhyB0eWNoIHLDs8W8bmljLg0KDQotV3DFgnl3IHdpZWt1IHJvxZtuaWUgd3JheiB6ZSB3enJvc3RlbSBrd2FudHlsYS4gU3RhcnN6eSB3aWVrIG1hIG5handpxJlrc3p5IHdwxYJ5dyBuYSB6YXJvYmtpIHcgZ3J1cGllIG5hamxlcGllaiB6YXJhYmlhasSFY3ljaCwgY28gamVzdCB6Z29kbmUgeiBvY3pla2l3YW5pZW0sIMW8ZSBkb8Wbd2lhZGN6ZW5pZSB6YXdvZG93ZSBiYXJkemllaiBzacSZIG9wxYJhY2EgdyB0ZWogZ3J1cGllLg0KLSBXeWtzenRhxYJjZW5pZSBtYSByb3NuxIVjeSB3cMWCeXcgdyBtaWFyxJkgd3pyb3N0dSBrd2FudHlsYS4gU3VnZXJ1amUgdG8sIMW8ZSB3YXJ0b8WbxIcgd3nFvHN6ZWdvIHd5a3N6dGHFgmNlbmlhIGplc3QgYmFyZHppZWogZG9jZW5pYW5hIHcgZ3J1cGllIG9zw7NiIG9zacSFZ2FqxIVjeWNoIG5hand5xbxzemUgZG9jaG9keS4NCi0gV2FydG/Fm2NpIHVqZW1uZSB3c3DDs8WCY3p5bm5pa2EgR2VuZGVyIHdza2F6dWrEhSBuYSBuacW8c3plIHphcm9ia2kga29iaWV0IHcgcG9yw7N3bmFuaXUgZG8gbcSZxbxjenl6bi4NCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=