Zadanie

Posłużymy się zbiorem danych diagnozy społecznej.

Na jego podstawie Twoim zadaniem jest oszacowanie rozkładu “p64 Pana/Pani wlasny (osobisty) dochod miesieczny netto (na reke)” według województw/płci.

Postaraj się oszacować zarówno rozkład gęstości jak i skumulowanej gęstości (dystrybuanty).

data("diagnoza")
data("diagnozaDict")
new_df <- data.frame(p64_var=diagnoza$gp64,
                     region=diagnoza$wojewodztwo,
                     gender=diagnoza$plec)
num_nan_values <- colSums(is.na(new_df))
for(col_name in names(num_nan_values)){
  cat(paste('Liczba braków danych w kolumnie', col_name, 'wynosi', num_nan_values[col_name], '\n'))
}
## Liczba braków danych w kolumnie p64_var wynosi 18773 
## Liczba braków danych w kolumnie region wynosi 0 
## Liczba braków danych w kolumnie gender wynosi 40

Liczba braków danych w kolumnie p64_var stanowi blisko połowę wszystkich danych tej zmiennej. Patrząc jedynie na nowy zbiór danych wyselekcjonowany z “Diagnozy” nie ma podstaw do określenia natury braków danych, ponieważ w przypadku pozostałych dwóch zmiennych braki danych stanowią nieznaczną część lub w ogóle ich nie ma (zmienna województwo). Nie mając pełnej informacji o rozkładzie zmiennej “p64 Pana/Pani wlasny (osobisty) dochod miesieczny netto (na reke)” należy pamiętać o uniknięciu generalizacji wniosków. Z tego powodu, wykonam dwie różne estymację. Pierwszą po usunięciu braków danych oraz drugą dopiero po przekształceniu braków danych na średnią wartość ze wszystkich dostępnych obserwacji.

new_df_clean <- na.omit(new_df)
cat(paste('Unikalne wartości dotyczące zmiennej płeć to:', unique(new_df_clean$gender), '\n'))
## Unikalne wartości dotyczące zmiennej płeć to: mężczyzna 
##  Unikalne wartości dotyczące zmiennej płeć to: kobieta
female_data <- new_df_clean$p64_var[new_df_clean$gender == "kobieta"]
male_data <- new_df_clean$p64_var[new_df_clean$gender == "mężczyzna"]

female_density <- density(female_data, bw=3000)
male_density <- density(male_data, bw=3000)

plot(female_density, lwd=2, main=paste('Wykres gęstości dla dochodów względem płci - kobieta')) 

plot(male_density, lwd=2, main=paste('Wykres gęstości dla dochodów względem płci - mężczyzna')) 

ggplot(new_df_clean, aes(x=p64_var, color=gender, fill=gender)) +
  geom_density(alpha=0.3, bw=4000) + 
  labs(title='Porównanie gęstości dochodów względem płci (usunięte nan)', 
       x='Zarobki',
       y='Gęstość')+
  theme_minimal()

female_cdf <- approxfun(female_density$x, cumsum(female_density$y) / sum(female_density$y))
male_cdf <- approxfun(male_density$x, cumsum(male_density$y) / sum(male_density$y))

cat(paste('Jaki procent respondentów będących kobietą osiąga dochód netto niższy lub równy 10000: ', female_cdf(10000)*100, '%', sep="", '\n'))
## Jaki procent respondentów będących kobietą osiąga dochód netto niższy lub równy 10000: 99.4422417105648%
cat(paste('Jaki procent respondentów będących mężczyzną osiąga dochód netto niższy lub równy 10000: ',male_cdf(10000)*100, '%', sep=""))
## Jaki procent respondentów będących mężczyzną osiąga dochód netto niższy lub równy 10000: 98.8422799360035%
plot(female_density$x, female_cdf(female_density$x), type = "l", col = "red",
     xlab = "Value", ylab = "CDF", main = "CDF for Female data")

plot(male_density$x, male_cdf(male_density$x), type = "l", col = "blue",
     xlab = "Value", ylab = "CDF", main = "CDF for Male data")

cat(paste('Częstości występowania wartości w zmiennej płeć:\n'))
## Częstości występowania wartości w zmiennej płeć:
table(new_df$gender)
## 
## mężczyzna   kobieta 
##     18355     20066
cat('\n')            
new_df_impute <- new_df %>%
  mutate(p64_var=ifelse(is.na(p64_var), mean(p64_var, na.rm=TRUE), p64_var),
         gender=ifelse(gender=='kobieta', 1, ifelse(gender=='mężczyzna', 2, NA)) %>%
           as.numeric(),
         gender=ifelse(is.na(gender), 1, gender))

cat(paste('Unikalne wartości dotyczące zmiennej płeć to:', unique(new_df_impute$gender), '\n'))
## Unikalne wartości dotyczące zmiennej płeć to: 1 
##  Unikalne wartości dotyczące zmiennej płeć to: 2
female_data_impute <- new_df_impute$p64_var[new_df_impute$gender == 1]
male_data_impute <- new_df_impute$p64_var[new_df_impute$gender == 2]

female_density_impute <- density(female_data_impute, bw=3000)
male_density_impute <- density(male_data_impute, bw=3000)

plot(female_density_impute, lwd=2, main=paste('Wykres gęstości dla dochodów względem płci - kobieta')) 

plot(male_density_impute, lwd=2, main=paste('Wykres gęstości dla dochodów względem płci - mężczyzna')) 

ggplot(new_df_impute, aes(x=p64_var, color=factor(gender, labels=c('mężczyzna', 'kobieta')), fill=factor(gender, labels=c('mężczyzna', 'kobieta')))) +
  geom_density(alpha=0.3, bw=3000) + 
  labs(title='Porównanie gęstości zarobków względem płci (imputacja)', 
       x='Zarobki',
       y='Gęstość',
       color='Płeć',
       fill='Płeć')+
  theme_minimal()

female_cdf_impute <- approxfun(female_density_impute$x, cumsum(female_density_impute$y) / sum(female_density_impute$y))
male_cdf_impute <- approxfun(male_density_impute$x, cumsum(male_density_impute$y) / sum(male_density_impute$y))

paste('Jaki procent respondentów będących kobietą osiąga dochód netto niższy lub równy 10000:', female_cdf_impute(10000)*100, '%')
## [1] "Jaki procent respondentów będących kobietą osiąga dochód netto niższy lub równy 10000: 99.5692651140786 %"
paste('Jaki procent respondentów będących mężczyzną osiąga dochód netto niższy lub równy 10000:',male_cdf_impute(10000)*100, '%')
## [1] "Jaki procent respondentów będących mężczyzną osiąga dochód netto niższy lub równy 10000: 99.2940367645413 %"
plot(female_density_impute$x, female_cdf_impute(female_density_impute$x), type = "l", col = "red",
     xlab = "Value", ylab = "CDF", main = "CDF for Female data")

plot(male_density_impute$x, male_cdf_impute(male_density_impute$x), type = "l", col = "blue",
     xlab = "Value", ylab = "CDF", main = "CDF for Male data")

Powyżej zaprezentowałem oszacowania rozkładów gęstości oraz skumulowanej gęstości z podziałem na płeć. Wykres, który powstał w wyniku usuwania brakujących wartości lepiej obrazuje różnice w dochodzie miesięcznym netto. Mniej widoczne jest to w przypadku danych, gdzie użyta została technika uzupełniania braków, co jest jak najbardziej prawdziwe, gdyż połowa braków została uzupełniona średnią (stąd m.in. mediana taka sama dla dwóch grup).

Korzystając z wykresu dystrybuanty można napisać, że : - 99.6% procent respondentów (kobiet) osiąga dochód netto niższy lub równy 10000 (dane po usunięciu NAN), - 99.4% procent respondentów (kobiet) osiąga dochód netto niższy lub równy 10000 (dane imputowane), - 99,3% procent respondentów (mężczyzn) osiąga dochód netto niższy lub równy 10000 (dane po usunięciu NAN), - 98,8% procent respondentów (mężczyzn) osiąga dochód netto niższy lub równy 10000 (dane imputowane).

Jak to wygląda dla województw? Wezmę województwa, z których pochodziło najwięcej ankietowanych tj. Mazowieckie, Śląśkie i Wielkopolskie. Przygotuję zarówno dla okrojonego dataframu, jak i tego z imputacją.

cat(paste('Częstości występowania wartości w zmiennej region:\n'))
## Częstości występowania wartości w zmiennej region:
table(new_df$region)
## 
##          BD/ND/FALA        Dolnośląskie  Kujawsko-Pomorskie           Lubelskie 
##                   0                2596                2068                2620 
##            Lubuskie             Łódzkie         Małopolskie         Mazowieckie 
##                1210                2552                2917                4478 
##            Opolskie        Podkarpackie           Podlaskie           Pomorskie 
##                1277                2535                1512                2201 
##             Śląskie      Świętokrzyskie Warmińsko-Mazurskie       Wielkopolskie 
##                4185                1859                1814                3106 
## Zachodnio-Pomorskie 
##                1531
cat('\n')    
mazowieckie <- new_df_clean$p64_var[new_df_clean$region=='Mazowieckie']
slaskie <- new_df_clean$p64_var[new_df_clean$region=='Śląskie']
wielkopolskie <- new_df_clean$p64_var[new_df_clean$region=='Wielkopolskie']
new_df_clean <- new_df_clean %>%
  filter(region %in% c('Mazowieckie', 'Śląskie', 'Wielkopolskie'))

ggplot(new_df_clean, aes(x=p64_var, color=factor(region, labels=c('Mazowieckie', 'Śląskie', 'Wielkopolskie')), fill=factor(region, labels=c('Mazowieckie', 'Śląskie', 'Wielkopolskie')))) +
  geom_density(alpha=0.2, bw=3000) + 
  labs(title='Porównanie gęstości dochodów względem województw (usunięte nan)', 
       x='Dochód',
       y='Gęstość',
       color='Region',
       fill='Region')+
  theme_minimal()

mazowieckie_density <- density(mazowieckie, bw=3000)
slaskie_density <- density(slaskie, bw=3000)
wielkopolskie_density <- density(wielkopolskie, bw=3000)

mazowieckie_cdf <- approxfun(mazowieckie_density$x, cumsum(mazowieckie_density$y) / sum(mazowieckie_density$y))
slaskie_cdf <- approxfun(slaskie_density$x, cumsum(slaskie_density$y) / sum(slaskie_density$y))
wielkopolskie_cdf <- approxfun(wielkopolskie_density$x, cumsum(wielkopolskie_density$y) / sum(wielkopolskie_density$y))

cat(paste('Jaki procent respondentów z województwa mazowieckiego osiąga dochód netto niższy lub równy 5000: ', mazowieckie_cdf(5000)*100, '%', sep="", '\n'))
## Jaki procent respondentów z województwa mazowieckiego osiąga dochód netto niższy lub równy 5000: 83.3657094206963%
cat(paste('Jaki procent respondentów z województwa śląskiego osiąga dochód netto niższy lub równy 5000: ',slaskie_cdf(5000)*100, '%', sep="",'\n'))
## Jaki procent respondentów z województwa śląskiego osiąga dochód netto niższy lub równy 5000: 83.8719849806908%
cat(paste('Jaki procent respondentów z województwa wielkopolskiego osiąga dochód netto niższy lub równy 5000: ',wielkopolskie_cdf(5000)*100, '%', sep="",'\n'))
## Jaki procent respondentów z województwa wielkopolskiego osiąga dochód netto niższy lub równy 5000: 84.9960248631507%
plot(mazowieckie_density$x, mazowieckie_cdf(mazowieckie_density$x), type = "l", col = "pink",
     xlab = "Value", ylab = "CDF", main = "CDF for Mazowieckie data")

plot(slaskie_density$x, slaskie_cdf(slaskie_density$x), type = "l", col = "lightgreen",
     xlab = "Value", ylab = "CDF", main = "CDF for Śląskie data")

plot(wielkopolskie_density$x, wielkopolskie_cdf(wielkopolskie_density$x), type = "l", col = "lightblue",
     xlab = "Value", ylab = "CDF", main = "CDF for Wielkopolskie data")

mazowieckie <- new_df_impute$p64_var[new_df_impute$region=='Mazowieckie']
slaskie <- new_df_impute$p64_var[new_df_impute$region=='Śląskie']
wielkopolskie <- new_df_impute$p64_var[new_df_impute$region=='Wielkopolskie']
new_df_impute <- new_df_impute %>%
  filter(region %in% c('Mazowieckie', 'Śląskie', 'Wielkopolskie'))

ggplot(new_df_impute, aes(x=p64_var, color=factor(region, labels=c('Mazowieckie', 'Śląskie', 'Wielkopolskie')), fill=factor(region, labels=c('Mazowieckie', 'Śląskie', 'Wielkopolskie')))) +
  geom_density(alpha=0.2, bw=3000) + 
  labs(title='Porównanie gęstości dochodów względem województw (imputacja nan)', 
       x='Dochód',
       y='Gęstość',
       color='Region',
       fill='Region')+
  theme_minimal()

mazowieckie_density_impute <- density(mazowieckie, bw=3000)
slaskie_density_impute <- density(slaskie, bw=3000)
wielkopolskie_density_impute <- density(wielkopolskie, bw=3000)

mazowieckie_cdf_impute <- approxfun(mazowieckie_density_impute$x, cumsum(mazowieckie_density_impute$y) / sum(mazowieckie_density_impute$y))
slaskie_cdf_impute <- approxfun(slaskie_density_impute$x, cumsum(slaskie_density_impute$y) / sum(slaskie_density_impute$y))
wielkopolskie_cdf_impute <- approxfun(wielkopolskie_density_impute$x, cumsum(wielkopolskie_density_impute$y) / sum(wielkopolskie_density_impute$y))

cat(paste('Jaki procent respondentów z województwa mazowieckiego osiąga dochód netto niższy lub równy 5000: ', mazowieckie_cdf_impute(5000)*100, '%', sep="", '\n'))
## Jaki procent respondentów z województwa mazowieckiego osiąga dochód netto niższy lub równy 5000: 84.7378227280673%
cat(paste('Jaki procent respondentów z województwa śląskiego osiąga dochód netto niższy lub równy 5000: ',slaskie_cdf_impute(5000)*100, '%', sep="",'\n'))
## Jaki procent respondentów z województwa śląskiego osiąga dochód netto niższy lub równy 5000: 85.1981556791398%
cat(paste('Jaki procent respondentów z województwa wielkopolskiego osiąga dochód netto niższy lub równy 5000: ',wielkopolskie_cdf_impute(5000)*100, '%', sep="",'\n'))
## Jaki procent respondentów z województwa wielkopolskiego osiąga dochód netto niższy lub równy 5000: 85.693087036592%
plot(mazowieckie_density_impute$x, mazowieckie_cdf_impute(mazowieckie_density_impute$x), type = "l", col = "pink",
     xlab = "Value", ylab = "CDF", main = "CDF for Mazowieckie data")

plot(slaskie_density_impute$x, slaskie_cdf_impute(slaskie_density_impute$x), type = "l", col = "lightgreen",
     xlab = "Value", ylab = "CDF", main = "CDF for Śląskie data")

plot(wielkopolskie_density_impute$x, wielkopolskie_cdf_impute(wielkopolskie_density_impute$x), type = "l", col = "lightblue",
     xlab = "Value", ylab = "CDF", main = "CDF for Wielkopolskie data")

Wnioski

Działając na zbiorze danych Diagnoza, a właściwie na jego części (3 zmienne), chcąc oszacować rozkład dochodu miesięcznego netto według płci i województw, osiągnięty został zamierzony efekt. To znaczy, podejście do pracy miało mieć charakter holistyczny, to znaczy przemyślany i zwracający uwagę na szersze spektrum. Do braków danych podszedłem na dwa sposoby, skutecznie implementując podejście dla każdego z wątków pracy.

Główne wyniki po pracy:

dochód względem płci:

  • 99.6% procent respondentów (kobiet) osiąga dochód netto niższy lub równy 10000 (dane po usunięciu NAN),
  • 99.4% procent respondentów (kobiet) osiąga dochód netto niższy lub równy 10000 (dane imputowane),
  • 99,3% procent respondentów (mężczyzn) osiąga dochód netto niższy lub równy 10000 (dane po usunięciu NAN),
  • 98,8% procent respondentów (mężczyzn) osiąga dochód netto niższy lub równy 10000 (dane imputowane).

dochód względem wybranych województw:

  • 83.4% procent respondentów z województwa mazowieckiego osiąga dochód netto niższy lub równy 5000 (dane po usunięciu NAN),
  • 84.7% procent respondentów z województwa mazowieckiego osiąga dochód netto niższy lub równy 5000 (dane imputowane),
  • 83,9% procent respondentów z województwa śląskiego osiąga dochód netto niższy lub równy 5000 (dane po usunięciu NAN),
  • 85,2% procent respondentów z województwa śląskiego osiąga dochód netto niższy lub równy 5000 (dane imputowane),
  • 85% procent respondentów województwa wielkopolskiego osiąga dochód netto niższy lub równy 5000 (dane po usunięciu NAN),
  • 85,7% procent respondentów województwa wielkopolskiego osiąga dochód netto niższy lub równy 5000 (dane imputowane).

Zatem warto zauważyć, że nieznaczna część respondentów osiągała dochód powyżej 10000 złotych miesięcznie na rękę jeżeli chodzi o porównanie względem płci. Uogólniając zaledwie 1 osoba na 100 bez podziału na płeć zarabia powyżej 10000 złotych. Natomiast względem województw obniżenie poziomu o połowę do 5000 złotych nie spowodowało znaczącego spadku w liczności respondentów deklarujących taki poziom dochodów. Można zatem uogólnić, że ponad 8 na 10 osób z wybranych województw osiąga dochód miesięczny netto nieprzekraczający 5000 złotych.

LS0tDQp0aXRsZTogIk5pZWtsYXN5Y3puZSBtZXRvZHkgc3RhdHlzdHlraSINCnN1YnRpdGxlOiAiTmllcGFyYW1ldHJ5Y3puYSBlc3R5bWFjamEgZHlzdHJ5YnVhbnR5Ig0KYXV0aG9yOiAiUGlvdHIgU3p5cHVsacWEc2tpIg0KZGF0ZTogIjIwMjQtMTAtMjIiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIGZvbnRzaXplOiA4cHQNCiAgICB0b2M6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCiNpbnN0YWxsLnBhY2thZ2VzKCdzcGF0c3RhdCcpDQpsaWJyYXJ5KHNwYXRzdGF0KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KFBvZ3JvbWN5RGFueWNoKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShiYXNlKQ0KYGBgDQoNCiMjIFphZGFuaWUNCg0KUG9zxYJ1xbx5bXkgc2nEmSB6YmlvcmVtIGRhbnljaCBkaWFnbm96eSBzcG/FgmVjem5lai4gDQoNCk5hIGplZ28gcG9kc3Rhd2llIFR3b2ltIHphZGFuaWVtIGplc3Qgb3N6YWNvd2FuaWUgcm96a8WCYWR1ICJwNjQgUGFuYS9QYW5pIHdsYXNueSAob3NvYmlzdHkpIGRvY2hvZCBtaWVzaWVjem55IG5ldHRvIChuYSByZWtlKSIgd2VkxYJ1ZyB3b2pld8OzZHp0dy9wxYJjaS4NCg0KUG9zdGFyYWogc2nEmSBvc3phY293YcSHIHphcsOzd25vIHJvemvFgmFkIGfEmXN0b8WbY2kgamFrIGkgc2t1bXVsb3dhbmVqIGfEmXN0b8WbY2kgKGR5c3RyeWJ1YW50eSkuDQoNCmBgYHtyfQ0KZGF0YSgiZGlhZ25vemEiKQ0KZGF0YSgiZGlhZ25vemFEaWN0IikNCmBgYA0KDQpgYGB7cn0NCm5ld19kZiA8LSBkYXRhLmZyYW1lKHA2NF92YXI9ZGlhZ25vemEkZ3A2NCwNCiAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbj1kaWFnbm96YSR3b2pld29kenR3bywNCiAgICAgICAgICAgICAgICAgICAgIGdlbmRlcj1kaWFnbm96YSRwbGVjKQ0KYGBgDQoNCmBgYHtyfQ0KbnVtX25hbl92YWx1ZXMgPC0gY29sU3Vtcyhpcy5uYShuZXdfZGYpKQ0KZm9yKGNvbF9uYW1lIGluIG5hbWVzKG51bV9uYW5fdmFsdWVzKSl7DQogIGNhdChwYXN0ZSgnTGljemJhIGJyYWvDs3cgZGFueWNoIHcga29sdW1uaWUnLCBjb2xfbmFtZSwgJ3d5bm9zaScsIG51bV9uYW5fdmFsdWVzW2NvbF9uYW1lXSwgJ1xuJykpDQp9DQpgYGANCg0KTGljemJhIGJyYWvDs3cgZGFueWNoIHcga29sdW1uaWUgcDY0X3ZhciBzdGFub3dpIGJsaXNrbyBwb8WCb3fEmSB3c3p5c3RraWNoIGRhbnljaCB0ZWogem1pZW5uZWouIFBhdHJ6xIVjIGplZHluaWUgbmEgbm93eSB6YmnDs3IgZGFueWNoIHd5c2VsZWtjam9ub3dhbnkgeiAiRGlhZ25venkiIG5pZSBtYSBwb2RzdGF3IGRvIG9rcmXFm2xlbmlhIG5hdHVyeSBicmFrw7N3IGRhbnljaCwgcG9uaWV3YcW8IHcgcHJ6eXBhZGt1IHBvem9zdGHFgnljaCBkd8OzY2ggem1pZW5ueWNoIGJyYWtpIGRhbnljaCBzdGFub3dpxIUgbmllem5hY3puxIUgY3rEmcWbxIcgbHViIHcgb2fDs2xlIGljaCBuaWUgbWEgKHptaWVubmEgd29qZXfDs2R6dHdvKS4gTmllIG1hasSFYyBwZcWCbmVqIGluZm9ybWFjamkgbyByb3prxYJhZHppZSB6bWllbm5laiAicDY0IFBhbmEvUGFuaSB3bGFzbnkgKG9zb2Jpc3R5KSBkb2Nob2QgbWllc2llY3pueSBuZXR0byAobmEgcmVrZSkiIG5hbGXFvHkgcGFtacSZdGHEhyBvIHVuaWtuacSZY2l1IGdlbmVyYWxpemFjamkgd25pb3Nrw7N3LiBaIHRlZ28gcG93b2R1LCB3eWtvbmFtIGR3aWUgcsOzxbxuZSBlc3R5bWFjasSZLiBQaWVyd3N6xIUgcG8gdXN1bmnEmWNpdSBicmFrw7N3IGRhbnljaCBvcmF6IGRydWfEhSBkb3BpZXJvIHBvIHByemVrc3p0YcWCY2VuaXUgYnJha8OzdyBkYW55Y2ggbmEgxZtyZWRuacSFIHdhcnRvxZvEhyB6ZSB3c3p5c3RraWNoIGRvc3TEmXBueWNoIG9ic2Vyd2FjamkuIA0KDQpgYGB7cn0NCm5ld19kZl9jbGVhbiA8LSBuYS5vbWl0KG5ld19kZikNCmBgYA0KDQpgYGB7cn0NCmNhdChwYXN0ZSgnVW5pa2FsbmUgd2FydG/Fm2NpIGRvdHljesSFY2Ugem1pZW5uZWogcMWCZcSHIHRvOicsIHVuaXF1ZShuZXdfZGZfY2xlYW4kZ2VuZGVyKSwgJ1xuJykpDQoNCmZlbWFsZV9kYXRhIDwtIG5ld19kZl9jbGVhbiRwNjRfdmFyW25ld19kZl9jbGVhbiRnZW5kZXIgPT0gImtvYmlldGEiXQ0KbWFsZV9kYXRhIDwtIG5ld19kZl9jbGVhbiRwNjRfdmFyW25ld19kZl9jbGVhbiRnZW5kZXIgPT0gIm3EmcW8Y3p5em5hIl0NCg0KZmVtYWxlX2RlbnNpdHkgPC0gZGVuc2l0eShmZW1hbGVfZGF0YSwgYnc9MzAwMCkNCm1hbGVfZGVuc2l0eSA8LSBkZW5zaXR5KG1hbGVfZGF0YSwgYnc9MzAwMCkNCg0KcGxvdChmZW1hbGVfZGVuc2l0eSwgbHdkPTIsIG1haW49cGFzdGUoJ1d5a3JlcyBnxJlzdG/Fm2NpIGRsYSBkb2Nob2TDs3cgd3pnbMSZZGVtIHDFgmNpIC0ga29iaWV0YScpKSANCnBsb3QobWFsZV9kZW5zaXR5LCBsd2Q9MiwgbWFpbj1wYXN0ZSgnV3lrcmVzIGfEmXN0b8WbY2kgZGxhIGRvY2hvZMOzdyB3emdsxJlkZW0gcMWCY2kgLSBtxJnFvGN6eXpuYScpKSANCmBgYA0KDQpgYGB7cn0NCmdncGxvdChuZXdfZGZfY2xlYW4sIGFlcyh4PXA2NF92YXIsIGNvbG9yPWdlbmRlciwgZmlsbD1nZW5kZXIpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYT0wLjMsIGJ3PTQwMDApICsgDQogIGxhYnModGl0bGU9J1BvcsOzd25hbmllIGfEmXN0b8WbY2kgZG9jaG9kw7N3IHd6Z2zEmWRlbSBwxYJjaSAodXN1bmnEmXRlIG5hbiknLCANCiAgICAgICB4PSdaYXJvYmtpJywNCiAgICAgICB5PSdHxJlzdG/Fm8SHJykrDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KZmVtYWxlX2NkZiA8LSBhcHByb3hmdW4oZmVtYWxlX2RlbnNpdHkkeCwgY3Vtc3VtKGZlbWFsZV9kZW5zaXR5JHkpIC8gc3VtKGZlbWFsZV9kZW5zaXR5JHkpKQ0KbWFsZV9jZGYgPC0gYXBwcm94ZnVuKG1hbGVfZGVuc2l0eSR4LCBjdW1zdW0obWFsZV9kZW5zaXR5JHkpIC8gc3VtKG1hbGVfZGVuc2l0eSR5KSkNCg0KY2F0KHBhc3RlKCdKYWtpIHByb2NlbnQgcmVzcG9uZGVudMOzdyBixJlkxIVjeWNoIGtvYmlldMSFIG9zacSFZ2EgZG9jaMOzZCBuZXR0byBuacW8c3p5IGx1YiByw7N3bnkgMTAwMDA6ICcsIGZlbWFsZV9jZGYoMTAwMDApKjEwMCwgJyUnLCBzZXA9IiIsICdcbicpKQ0KY2F0KHBhc3RlKCdKYWtpIHByb2NlbnQgcmVzcG9uZGVudMOzdyBixJlkxIVjeWNoIG3EmcW8Y3p5em7EhSBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDEwMDAwOiAnLG1hbGVfY2RmKDEwMDAwKSoxMDAsICclJywgc2VwPSIiKSkNCg0KcGxvdChmZW1hbGVfZGVuc2l0eSR4LCBmZW1hbGVfY2RmKGZlbWFsZV9kZW5zaXR5JHgpLCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwNCiAgICAgeGxhYiA9ICJWYWx1ZSIsIHlsYWIgPSAiQ0RGIiwgbWFpbiA9ICJDREYgZm9yIEZlbWFsZSBkYXRhIikNCnBsb3QobWFsZV9kZW5zaXR5JHgsIG1hbGVfY2RmKG1hbGVfZGVuc2l0eSR4KSwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLA0KICAgICB4bGFiID0gIlZhbHVlIiwgeWxhYiA9ICJDREYiLCBtYWluID0gIkNERiBmb3IgTWFsZSBkYXRhIikNCmBgYA0KDQpgYGB7cn0NCmNhdChwYXN0ZSgnQ3rEmXN0b8WbY2kgd3lzdMSZcG93YW5pYSB3YXJ0b8WbY2kgdyB6bWllbm5laiBwxYJlxIc6XG4nKSkNCnRhYmxlKG5ld19kZiRnZW5kZXIpDQpjYXQoJ1xuJykgICAgICAgICAgICANCg0KbmV3X2RmX2ltcHV0ZSA8LSBuZXdfZGYgJT4lDQogIG11dGF0ZShwNjRfdmFyPWlmZWxzZShpcy5uYShwNjRfdmFyKSwgbWVhbihwNjRfdmFyLCBuYS5ybT1UUlVFKSwgcDY0X3ZhciksDQogICAgICAgICBnZW5kZXI9aWZlbHNlKGdlbmRlcj09J2tvYmlldGEnLCAxLCBpZmVsc2UoZ2VuZGVyPT0nbcSZxbxjenl6bmEnLCAyLCBOQSkpICU+JQ0KICAgICAgICAgICBhcy5udW1lcmljKCksDQogICAgICAgICBnZW5kZXI9aWZlbHNlKGlzLm5hKGdlbmRlciksIDEsIGdlbmRlcikpDQoNCmNhdChwYXN0ZSgnVW5pa2FsbmUgd2FydG/Fm2NpIGRvdHljesSFY2Ugem1pZW5uZWogcMWCZcSHIHRvOicsIHVuaXF1ZShuZXdfZGZfaW1wdXRlJGdlbmRlciksICdcbicpKQ0KYGBgDQoNCmBgYHtyfQ0KZmVtYWxlX2RhdGFfaW1wdXRlIDwtIG5ld19kZl9pbXB1dGUkcDY0X3ZhcltuZXdfZGZfaW1wdXRlJGdlbmRlciA9PSAxXQ0KbWFsZV9kYXRhX2ltcHV0ZSA8LSBuZXdfZGZfaW1wdXRlJHA2NF92YXJbbmV3X2RmX2ltcHV0ZSRnZW5kZXIgPT0gMl0NCg0KZmVtYWxlX2RlbnNpdHlfaW1wdXRlIDwtIGRlbnNpdHkoZmVtYWxlX2RhdGFfaW1wdXRlLCBidz0zMDAwKQ0KbWFsZV9kZW5zaXR5X2ltcHV0ZSA8LSBkZW5zaXR5KG1hbGVfZGF0YV9pbXB1dGUsIGJ3PTMwMDApDQoNCnBsb3QoZmVtYWxlX2RlbnNpdHlfaW1wdXRlLCBsd2Q9MiwgbWFpbj1wYXN0ZSgnV3lrcmVzIGfEmXN0b8WbY2kgZGxhIGRvY2hvZMOzdyB3emdsxJlkZW0gcMWCY2kgLSBrb2JpZXRhJykpIA0KcGxvdChtYWxlX2RlbnNpdHlfaW1wdXRlLCBsd2Q9MiwgbWFpbj1wYXN0ZSgnV3lrcmVzIGfEmXN0b8WbY2kgZGxhIGRvY2hvZMOzdyB3emdsxJlkZW0gcMWCY2kgLSBtxJnFvGN6eXpuYScpKSANCmBgYA0KYGBge3J9DQpnZ3Bsb3QobmV3X2RmX2ltcHV0ZSwgYWVzKHg9cDY0X3ZhciwgY29sb3I9ZmFjdG9yKGdlbmRlciwgbGFiZWxzPWMoJ23EmcW8Y3p5em5hJywgJ2tvYmlldGEnKSksIGZpbGw9ZmFjdG9yKGdlbmRlciwgbGFiZWxzPWMoJ23EmcW8Y3p5em5hJywgJ2tvYmlldGEnKSkpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYT0wLjMsIGJ3PTMwMDApICsgDQogIGxhYnModGl0bGU9J1BvcsOzd25hbmllIGfEmXN0b8WbY2kgemFyb2Jrw7N3IHd6Z2zEmWRlbSBwxYJjaSAoaW1wdXRhY2phKScsIA0KICAgICAgIHg9J1phcm9ia2knLA0KICAgICAgIHk9J0fEmXN0b8WbxIcnLA0KICAgICAgIGNvbG9yPSdQxYJlxIcnLA0KICAgICAgIGZpbGw9J1DFgmXEhycpKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCmZlbWFsZV9jZGZfaW1wdXRlIDwtIGFwcHJveGZ1bihmZW1hbGVfZGVuc2l0eV9pbXB1dGUkeCwgY3Vtc3VtKGZlbWFsZV9kZW5zaXR5X2ltcHV0ZSR5KSAvIHN1bShmZW1hbGVfZGVuc2l0eV9pbXB1dGUkeSkpDQptYWxlX2NkZl9pbXB1dGUgPC0gYXBwcm94ZnVuKG1hbGVfZGVuc2l0eV9pbXB1dGUkeCwgY3Vtc3VtKG1hbGVfZGVuc2l0eV9pbXB1dGUkeSkgLyBzdW0obWFsZV9kZW5zaXR5X2ltcHV0ZSR5KSkNCg0KcGFzdGUoJ0pha2kgcHJvY2VudCByZXNwb25kZW50w7N3IGLEmWTEhWN5Y2gga29iaWV0xIUgb3NpxIVnYSBkb2Now7NkIG5ldHRvIG5pxbxzenkgbHViIHLDs3dueSAxMDAwMDonLCBmZW1hbGVfY2RmX2ltcHV0ZSgxMDAwMCkqMTAwLCAnJScpDQpwYXN0ZSgnSmFraSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgYsSZZMSFY3ljaCBtxJnFvGN6eXpuxIUgb3NpxIVnYSBkb2Now7NkIG5ldHRvIG5pxbxzenkgbHViIHLDs3dueSAxMDAwMDonLG1hbGVfY2RmX2ltcHV0ZSgxMDAwMCkqMTAwLCAnJScpDQoNCnBsb3QoZmVtYWxlX2RlbnNpdHlfaW1wdXRlJHgsIGZlbWFsZV9jZGZfaW1wdXRlKGZlbWFsZV9kZW5zaXR5X2ltcHV0ZSR4KSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsDQogICAgIHhsYWIgPSAiVmFsdWUiLCB5bGFiID0gIkNERiIsIG1haW4gPSAiQ0RGIGZvciBGZW1hbGUgZGF0YSIpDQpwbG90KG1hbGVfZGVuc2l0eV9pbXB1dGUkeCwgbWFsZV9jZGZfaW1wdXRlKG1hbGVfZGVuc2l0eV9pbXB1dGUkeCksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwNCiAgICAgeGxhYiA9ICJWYWx1ZSIsIHlsYWIgPSAiQ0RGIiwgbWFpbiA9ICJDREYgZm9yIE1hbGUgZGF0YSIpDQpgYGANCg0KUG93ecW8ZWogemFwcmV6ZW50b3dhxYJlbSBvc3phY293YW5pYSByb3prxYJhZMOzdyBnxJlzdG/Fm2NpIG9yYXogc2t1bXVsb3dhbmVqIGfEmXN0b8WbY2kgeiBwb2R6aWHFgmVtIG5hIHDFgmXEhy4gV3lrcmVzLCBrdMOzcnkgcG93c3RhxYIgdyB3eW5pa3UgdXN1d2FuaWEgYnJha3VqxIVjeWNoIHdhcnRvxZtjaSBsZXBpZWogb2JyYXp1amUgcsOzxbxuaWNlIHcgZG9jaG9kemllIG1pZXNpxJljem55bSBuZXR0by4gTW5pZWogd2lkb2N6bmUgamVzdCB0byB3IHByenlwYWRrdSBkYW55Y2gsIGdkemllIHXFvHl0YSB6b3N0YcWCYSB0ZWNobmlrYSB1enVwZcWCbmlhbmlhIGJyYWvDs3csIGNvIGplc3QgamFrIG5hamJhcmR6aWVqIHByYXdkeml3ZSwgZ2R5xbwgcG/Fgm93YSBicmFrw7N3IHpvc3RhxYJhIHV6dXBlxYJuaW9uYSDFm3JlZG5pxIUgKHN0xIVkIG0uaW4uIG1lZGlhbmEgdGFrYSBzYW1hIGRsYSBkd8OzY2ggZ3J1cCkuIA0KDQpLb3J6eXN0YWrEhWMgeiB3eWtyZXN1IGR5c3RyeWJ1YW50eSBtb8W8bmEgbmFwaXNhxIcsIMW8ZSA6IA0KLSA5OS42JSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgKGtvYmlldCkgb3NpxIVnYSBkb2Now7NkIG5ldHRvIG5pxbxzenkgbHViIHLDs3dueSAxMDAwMCAoZGFuZSBwbyB1c3VuacSZY2l1IE5BTiksDQotIDk5LjQlIHByb2NlbnQgcmVzcG9uZGVudMOzdyAoa29iaWV0KSBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDEwMDAwIChkYW5lIGltcHV0b3dhbmUpLA0KLSA5OSwzJSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgKG3EmcW8Y3p5em4pIG9zacSFZ2EgZG9jaMOzZCBuZXR0byBuacW8c3p5IGx1YiByw7N3bnkgMTAwMDAgKGRhbmUgcG8gdXN1bmnEmWNpdSBOQU4pLA0KLSA5OCw4JSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgKG3EmcW8Y3p5em4pIG9zacSFZ2EgZG9jaMOzZCBuZXR0byBuacW8c3p5IGx1YiByw7N3bnkgMTAwMDAgKGRhbmUgaW1wdXRvd2FuZSkuDQoNCg0KSmFrIHRvIHd5Z2zEhWRhIGRsYSB3b2pld8OzZHp0dz8gV2V6bcSZIHdvamV3w7NkenR3YSwgeiBrdMOzcnljaCBwb2Nob2R6acWCbyBuYWp3acSZY2VqIGFua2lldG93YW55Y2ggdGouIE1hem93aWVja2llLCDFmmzEhcWba2llIGkgV2llbGtvcG9sc2tpZS4gUHJ6eWdvdHVqxJkgemFyw7N3bm8gZGxhIG9rcm9qb25lZ28gZGF0YWZyYW11LCBqYWsgaSB0ZWdvIHogaW1wdXRhY2rEhS4NCg0KYGBge3J9DQpjYXQocGFzdGUoJ0N6xJlzdG/Fm2NpIHd5c3TEmXBvd2FuaWEgd2FydG/Fm2NpIHcgem1pZW5uZWogcmVnaW9uOlxuJykpDQp0YWJsZShuZXdfZGYkcmVnaW9uKQ0KY2F0KCdcbicpICAgIA0KYGBgDQoNCmBgYHtyfQ0KbWF6b3dpZWNraWUgPC0gbmV3X2RmX2NsZWFuJHA2NF92YXJbbmV3X2RmX2NsZWFuJHJlZ2lvbj09J01hem93aWVja2llJ10NCnNsYXNraWUgPC0gbmV3X2RmX2NsZWFuJHA2NF92YXJbbmV3X2RmX2NsZWFuJHJlZ2lvbj09J8WabMSFc2tpZSddDQp3aWVsa29wb2xza2llIDwtIG5ld19kZl9jbGVhbiRwNjRfdmFyW25ld19kZl9jbGVhbiRyZWdpb249PSdXaWVsa29wb2xza2llJ10NCmBgYA0KDQpgYGB7cn0NCm5ld19kZl9jbGVhbiA8LSBuZXdfZGZfY2xlYW4gJT4lDQogIGZpbHRlcihyZWdpb24gJWluJSBjKCdNYXpvd2llY2tpZScsICfFmmzEhXNraWUnLCAnV2llbGtvcG9sc2tpZScpKQ0KDQpnZ3Bsb3QobmV3X2RmX2NsZWFuLCBhZXMoeD1wNjRfdmFyLCBjb2xvcj1mYWN0b3IocmVnaW9uLCBsYWJlbHM9YygnTWF6b3dpZWNraWUnLCAnxZpsxIVza2llJywgJ1dpZWxrb3BvbHNraWUnKSksIGZpbGw9ZmFjdG9yKHJlZ2lvbiwgbGFiZWxzPWMoJ01hem93aWVja2llJywgJ8WabMSFc2tpZScsICdXaWVsa29wb2xza2llJykpKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4yLCBidz0zMDAwKSArIA0KICBsYWJzKHRpdGxlPSdQb3LDs3duYW5pZSBnxJlzdG/Fm2NpIGRvY2hvZMOzdyB3emdsxJlkZW0gd29qZXfDs2R6dHcgKHVzdW5pxJl0ZSBuYW4pJywgDQogICAgICAgeD0nRG9jaMOzZCcsDQogICAgICAgeT0nR8SZc3RvxZvEhycsDQogICAgICAgY29sb3I9J1JlZ2lvbicsDQogICAgICAgZmlsbD0nUmVnaW9uJykrDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KbWF6b3dpZWNraWVfZGVuc2l0eSA8LSBkZW5zaXR5KG1hem93aWVja2llLCBidz0zMDAwKQ0Kc2xhc2tpZV9kZW5zaXR5IDwtIGRlbnNpdHkoc2xhc2tpZSwgYnc9MzAwMCkNCndpZWxrb3BvbHNraWVfZGVuc2l0eSA8LSBkZW5zaXR5KHdpZWxrb3BvbHNraWUsIGJ3PTMwMDApDQoNCm1hem93aWVja2llX2NkZiA8LSBhcHByb3hmdW4obWF6b3dpZWNraWVfZGVuc2l0eSR4LCBjdW1zdW0obWF6b3dpZWNraWVfZGVuc2l0eSR5KSAvIHN1bShtYXpvd2llY2tpZV9kZW5zaXR5JHkpKQ0Kc2xhc2tpZV9jZGYgPC0gYXBwcm94ZnVuKHNsYXNraWVfZGVuc2l0eSR4LCBjdW1zdW0oc2xhc2tpZV9kZW5zaXR5JHkpIC8gc3VtKHNsYXNraWVfZGVuc2l0eSR5KSkNCndpZWxrb3BvbHNraWVfY2RmIDwtIGFwcHJveGZ1bih3aWVsa29wb2xza2llX2RlbnNpdHkkeCwgY3Vtc3VtKHdpZWxrb3BvbHNraWVfZGVuc2l0eSR5KSAvIHN1bSh3aWVsa29wb2xza2llX2RlbnNpdHkkeSkpDQoNCmNhdChwYXN0ZSgnSmFraSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgeiB3b2pld8OzZHp0d2EgbWF6b3dpZWNraWVnbyBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDUwMDA6ICcsIG1hem93aWVja2llX2NkZig1MDAwKSoxMDAsICclJywgc2VwPSIiLCAnXG4nKSkNCmNhdChwYXN0ZSgnSmFraSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgeiB3b2pld8OzZHp0d2EgxZtsxIVza2llZ28gb3NpxIVnYSBkb2Now7NkIG5ldHRvIG5pxbxzenkgbHViIHLDs3dueSA1MDAwOiAnLHNsYXNraWVfY2RmKDUwMDApKjEwMCwgJyUnLCBzZXA9IiIsJ1xuJykpDQpjYXQocGFzdGUoJ0pha2kgcHJvY2VudCByZXNwb25kZW50w7N3IHogd29qZXfDs2R6dHdhIHdpZWxrb3BvbHNraWVnbyBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDUwMDA6ICcsd2llbGtvcG9sc2tpZV9jZGYoNTAwMCkqMTAwLCAnJScsIHNlcD0iIiwnXG4nKSkNCg0KcGxvdChtYXpvd2llY2tpZV9kZW5zaXR5JHgsIG1hem93aWVja2llX2NkZihtYXpvd2llY2tpZV9kZW5zaXR5JHgpLCB0eXBlID0gImwiLCBjb2wgPSAicGluayIsDQogICAgIHhsYWIgPSAiVmFsdWUiLCB5bGFiID0gIkNERiIsIG1haW4gPSAiQ0RGIGZvciBNYXpvd2llY2tpZSBkYXRhIikNCnBsb3Qoc2xhc2tpZV9kZW5zaXR5JHgsIHNsYXNraWVfY2RmKHNsYXNraWVfZGVuc2l0eSR4KSwgdHlwZSA9ICJsIiwgY29sID0gImxpZ2h0Z3JlZW4iLA0KICAgICB4bGFiID0gIlZhbHVlIiwgeWxhYiA9ICJDREYiLCBtYWluID0gIkNERiBmb3IgxZpsxIVza2llIGRhdGEiKQ0KcGxvdCh3aWVsa29wb2xza2llX2RlbnNpdHkkeCwgd2llbGtvcG9sc2tpZV9jZGYod2llbGtvcG9sc2tpZV9kZW5zaXR5JHgpLCB0eXBlID0gImwiLCBjb2wgPSAibGlnaHRibHVlIiwNCiAgICAgeGxhYiA9ICJWYWx1ZSIsIHlsYWIgPSAiQ0RGIiwgbWFpbiA9ICJDREYgZm9yIFdpZWxrb3BvbHNraWUgZGF0YSIpDQpgYGANCg0KYGBge3J9DQptYXpvd2llY2tpZSA8LSBuZXdfZGZfaW1wdXRlJHA2NF92YXJbbmV3X2RmX2ltcHV0ZSRyZWdpb249PSdNYXpvd2llY2tpZSddDQpzbGFza2llIDwtIG5ld19kZl9pbXB1dGUkcDY0X3ZhcltuZXdfZGZfaW1wdXRlJHJlZ2lvbj09J8WabMSFc2tpZSddDQp3aWVsa29wb2xza2llIDwtIG5ld19kZl9pbXB1dGUkcDY0X3ZhcltuZXdfZGZfaW1wdXRlJHJlZ2lvbj09J1dpZWxrb3BvbHNraWUnXQ0KYGBgDQoNCmBgYHtyfQ0KbmV3X2RmX2ltcHV0ZSA8LSBuZXdfZGZfaW1wdXRlICU+JQ0KICBmaWx0ZXIocmVnaW9uICVpbiUgYygnTWF6b3dpZWNraWUnLCAnxZpsxIVza2llJywgJ1dpZWxrb3BvbHNraWUnKSkNCg0KZ2dwbG90KG5ld19kZl9pbXB1dGUsIGFlcyh4PXA2NF92YXIsIGNvbG9yPWZhY3RvcihyZWdpb24sIGxhYmVscz1jKCdNYXpvd2llY2tpZScsICfFmmzEhXNraWUnLCAnV2llbGtvcG9sc2tpZScpKSwgZmlsbD1mYWN0b3IocmVnaW9uLCBsYWJlbHM9YygnTWF6b3dpZWNraWUnLCAnxZpsxIVza2llJywgJ1dpZWxrb3BvbHNraWUnKSkpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYT0wLjIsIGJ3PTMwMDApICsgDQogIGxhYnModGl0bGU9J1BvcsOzd25hbmllIGfEmXN0b8WbY2kgZG9jaG9kw7N3IHd6Z2zEmWRlbSB3b2pld8OzZHp0dyAoaW1wdXRhY2phIG5hbiknLCANCiAgICAgICB4PSdEb2Now7NkJywNCiAgICAgICB5PSdHxJlzdG/Fm8SHJywNCiAgICAgICBjb2xvcj0nUmVnaW9uJywNCiAgICAgICBmaWxsPSdSZWdpb24nKSsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3Igd25pb3NraX0NCm1hem93aWVja2llX2RlbnNpdHlfaW1wdXRlIDwtIGRlbnNpdHkobWF6b3dpZWNraWUsIGJ3PTMwMDApDQpzbGFza2llX2RlbnNpdHlfaW1wdXRlIDwtIGRlbnNpdHkoc2xhc2tpZSwgYnc9MzAwMCkNCndpZWxrb3BvbHNraWVfZGVuc2l0eV9pbXB1dGUgPC0gZGVuc2l0eSh3aWVsa29wb2xza2llLCBidz0zMDAwKQ0KDQptYXpvd2llY2tpZV9jZGZfaW1wdXRlIDwtIGFwcHJveGZ1bihtYXpvd2llY2tpZV9kZW5zaXR5X2ltcHV0ZSR4LCBjdW1zdW0obWF6b3dpZWNraWVfZGVuc2l0eV9pbXB1dGUkeSkgLyBzdW0obWF6b3dpZWNraWVfZGVuc2l0eV9pbXB1dGUkeSkpDQpzbGFza2llX2NkZl9pbXB1dGUgPC0gYXBwcm94ZnVuKHNsYXNraWVfZGVuc2l0eV9pbXB1dGUkeCwgY3Vtc3VtKHNsYXNraWVfZGVuc2l0eV9pbXB1dGUkeSkgLyBzdW0oc2xhc2tpZV9kZW5zaXR5X2ltcHV0ZSR5KSkNCndpZWxrb3BvbHNraWVfY2RmX2ltcHV0ZSA8LSBhcHByb3hmdW4od2llbGtvcG9sc2tpZV9kZW5zaXR5X2ltcHV0ZSR4LCBjdW1zdW0od2llbGtvcG9sc2tpZV9kZW5zaXR5X2ltcHV0ZSR5KSAvIHN1bSh3aWVsa29wb2xza2llX2RlbnNpdHlfaW1wdXRlJHkpKQ0KDQpjYXQocGFzdGUoJ0pha2kgcHJvY2VudCByZXNwb25kZW50w7N3IHogd29qZXfDs2R6dHdhIG1hem93aWVja2llZ28gb3NpxIVnYSBkb2Now7NkIG5ldHRvIG5pxbxzenkgbHViIHLDs3dueSA1MDAwOiAnLCBtYXpvd2llY2tpZV9jZGZfaW1wdXRlKDUwMDApKjEwMCwgJyUnLCBzZXA9IiIsICdcbicpKQ0KY2F0KHBhc3RlKCdKYWtpIHByb2NlbnQgcmVzcG9uZGVudMOzdyB6IHdvamV3w7NkenR3YSDFm2zEhXNraWVnbyBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDUwMDA6ICcsc2xhc2tpZV9jZGZfaW1wdXRlKDUwMDApKjEwMCwgJyUnLCBzZXA9IiIsJ1xuJykpDQpjYXQocGFzdGUoJ0pha2kgcHJvY2VudCByZXNwb25kZW50w7N3IHogd29qZXfDs2R6dHdhIHdpZWxrb3BvbHNraWVnbyBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDUwMDA6ICcsd2llbGtvcG9sc2tpZV9jZGZfaW1wdXRlKDUwMDApKjEwMCwgJyUnLCBzZXA9IiIsJ1xuJykpDQoNCnBsb3QobWF6b3dpZWNraWVfZGVuc2l0eV9pbXB1dGUkeCwgbWF6b3dpZWNraWVfY2RmX2ltcHV0ZShtYXpvd2llY2tpZV9kZW5zaXR5X2ltcHV0ZSR4KSwgdHlwZSA9ICJsIiwgY29sID0gInBpbmsiLA0KICAgICB4bGFiID0gIlZhbHVlIiwgeWxhYiA9ICJDREYiLCBtYWluID0gIkNERiBmb3IgTWF6b3dpZWNraWUgZGF0YSIpDQpwbG90KHNsYXNraWVfZGVuc2l0eV9pbXB1dGUkeCwgc2xhc2tpZV9jZGZfaW1wdXRlKHNsYXNraWVfZGVuc2l0eV9pbXB1dGUkeCksIHR5cGUgPSAibCIsIGNvbCA9ICJsaWdodGdyZWVuIiwNCiAgICAgeGxhYiA9ICJWYWx1ZSIsIHlsYWIgPSAiQ0RGIiwgbWFpbiA9ICJDREYgZm9yIMWabMSFc2tpZSBkYXRhIikNCnBsb3Qod2llbGtvcG9sc2tpZV9kZW5zaXR5X2ltcHV0ZSR4LCB3aWVsa29wb2xza2llX2NkZl9pbXB1dGUod2llbGtvcG9sc2tpZV9kZW5zaXR5X2ltcHV0ZSR4KSwgdHlwZSA9ICJsIiwgY29sID0gImxpZ2h0Ymx1ZSIsDQogICAgIHhsYWIgPSAiVmFsdWUiLCB5bGFiID0gIkNERiIsIG1haW4gPSAiQ0RGIGZvciBXaWVsa29wb2xza2llIGRhdGEiKQ0KYGBgDQoNCiMjIFduaW9za2kNCg0KRHppYcWCYWrEhWMgbmEgemJpb3J6ZSBkYW55Y2ggRGlhZ25vemEsIGEgd8WCYcWbY2l3aWUgbmEgamVnbyBjesSZxZtjaSAoMyB6bWllbm5lKSwgY2hjxIVjIG9zemFjb3dhxIcgcm96a8WCYWQgZG9jaG9kdSBtaWVzacSZY3puZWdvIG5ldHRvIHdlZMWCdWcgcMWCY2kgaSB3b2pld8OzZHp0dywgb3NpxIVnbmnEmXR5IHpvc3RhxYIgemFtaWVyem9ueSBlZmVrdC4gVG8gem5hY3p5LCBwb2RlasWbY2llIGRvIHByYWN5IG1pYcWCbyBtaWXEhyBjaGFyYWt0ZXIgaG9saXN0eWN6bnksIHRvIHpuYWN6eSBwcnplbXnFm2xhbnkgaSB6d3JhY2FqxIVjeSB1d2FnxJkgbmEgc3plcnN6ZSBzcGVrdHJ1bS4gRG8gYnJha8OzdyBkYW55Y2ggcG9kc3plZMWCZW0gbmEgZHdhIHNwb3NvYnksIHNrdXRlY3puaWUgaW1wbGVtZW50dWrEhWMgcG9kZWrFm2NpZSBkbGEga2HFvGRlZ28geiB3xIV0a8OzdyBwcmFjeS4gDQoNCkfFgsOzd25lIHd5bmlraSBwbyBwcmFjeTogDQoNCioqZG9jaMOzZCB3emdsxJlkZW0gcMWCY2k6KiogDQoNCiAgLSA5OS42JSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgKiooa29iaWV0KSoqIG9zacSFZ2EgZG9jaMOzZCBuZXR0byBuacW8c3p5IGx1YiByw7N3bnkgMTAwMDAgKGRhbmUgcG8gdXN1bmnEmWNpdSBOQU4pLA0KICAtIDk5LjQlIHByb2NlbnQgcmVzcG9uZGVudMOzdyAqKihrb2JpZXQpKiogb3NpxIVnYSBkb2Now7NkIG5ldHRvIG5pxbxzenkgbHViIHLDs3dueSAxMDAwMCAoZGFuZSBpbXB1dG93YW5lKSwNCiAgLSA5OSwzJSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgKioobcSZxbxjenl6bikqKiBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDEwMDAwIChkYW5lIHBvIHVzdW5pxJljaXUgTkFOKSwNCiAgLSA5OCw4JSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgKioobcSZxbxjenl6bikqKiBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDEwMDAwIChkYW5lIGltcHV0b3dhbmUpLg0KDQoqKmRvY2jDs2Qgd3pnbMSZZGVtIHd5YnJhbnljaCB3b2pld8OzZHp0dzoqKg0KDQogIC0gODMuNCUgcHJvY2VudCByZXNwb25kZW50w7N3IHogKip3b2pld8OzZHp0d2EgbWF6b3dpZWNraWVnbyoqIG9zacSFZ2EgZG9jaMOzZCBuZXR0byBuacW8c3p5IGx1YiByw7N3bnkgNTAwMCAoZGFuZSBwbyB1c3VuacSZY2l1IE5BTiksDQogIC0gODQuNyUgcHJvY2VudCByZXNwb25kZW50w7N3IHogKip3b2pld8OzZHp0d2EgbWF6b3dpZWNraWVnbyoqIG9zacSFZ2EgZG9jaMOzZCBuZXR0byBuacW8c3p5IGx1YiByw7N3bnkgNTAwMCAoZGFuZSBpbXB1dG93YW5lKSwNCiAgLSA4Myw5JSBwcm9jZW50IHJlc3BvbmRlbnTDs3cgeiAqKndvamV3w7NkenR3YSDFm2zEhXNraWVnbyoqIG9zacSFZ2EgZG9jaMOzZCBuZXR0byBuacW8c3p5IGx1YiByw7N3bnkgNTAwMCAoZGFuZSBwbyB1c3VuacSZY2l1IE5BTiksDQogIC0gODUsMiUgcHJvY2VudCByZXNwb25kZW50w7N3IHogKip3b2pld8OzZHp0d2EgxZtsxIVza2llZ28qKiBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDUwMDAgKGRhbmUgaW1wdXRvd2FuZSksDQogIC0gODUlIHByb2NlbnQgcmVzcG9uZGVudMOzdyAqKndvamV3w7NkenR3YSB3aWVsa29wb2xza2llZ28qKiBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDUwMDAgKGRhbmUgcG8gdXN1bmnEmWNpdSBOQU4pLA0KICAtIDg1LDclIHByb2NlbnQgcmVzcG9uZGVudMOzdyAqKndvamV3w7NkenR3YSB3aWVsa29wb2xza2llZ28qKiBvc2nEhWdhIGRvY2jDs2QgbmV0dG8gbmnFvHN6eSBsdWIgcsOzd255IDUwMDAgKGRhbmUgaW1wdXRvd2FuZSkuDQoNCg0KWmF0ZW0gd2FydG8gemF1d2HFvHnEhywgxbxlIG5pZXpuYWN6bmEgY3rEmcWbxIcgcmVzcG9uZGVudMOzdyBvc2nEhWdhxYJhIGRvY2jDs2QgcG93ecW8ZWogMTAwMDAgesWCb3R5Y2ggbWllc2nEmWN6bmllIG5hIHLEmWvEmSBqZcW8ZWxpIGNob2R6aSBvIHBvcsOzd25hbmllIHd6Z2zEmWRlbSBwxYJjaS4gVW9nw7NsbmlhasSFYyB6YWxlZHdpZSAxIG9zb2JhIG5hIDEwMCBiZXogcG9kemlhxYJ1IG5hIHDFgmXEhyB6YXJhYmlhIHBvd3nFvGVqIDEwMDAwIHrFgm90eWNoLiBOYXRvbWlhc3Qgd3pnbMSZZGVtIHdvamV3w7NkenR3IG9ibmnFvGVuaWUgcG96aW9tdSBvIHBvxYJvd8SZIGRvIDUwMDAgesWCb3R5Y2ggbmllIHNwb3dvZG93YcWCbyB6bmFjesSFY2VnbyBzcGFka3UgdyBsaWN6bm/Fm2NpIHJlc3BvbmRlbnTDs3cgZGVrbGFydWrEhWN5Y2ggdGFraSBwb3ppb20gZG9jaG9kw7N3LiBNb8W8bmEgemF0ZW0gdW9nw7NsbmnEhywgxbxlIHBvbmFkIDggbmEgMTAgb3PDs2IgeiB3eWJyYW55Y2ggd29qZXfDs2R6dHcgb3NpxIVnYSBkb2Now7NkIG1pZXNpxJljem55IG5ldHRvIG5pZXByemVrcmFjemFqxIVjeSA1MDAwIHrFgm90eWNoLiANCg0KDQo=