Analiza opisowa

Jednym ze sposobów zrozumienia, jak działa rząd miasta, jest spojrzenie na to, kogo zatrudnia i jak jego pracownicy są wynagradzani. Dane te zawierają nazwiska, nazwę stanowiska i wynagrodzenie pracowników miasta San Francisco w ujęciu rocznym od 2011 do 2014 roku.

Oto kilka pomysłów na eksplorację danych:

  • Jak zmieniały się wynagrodzenia w czasie między różnymi grupami ludzi?

  • Jak płaca podstawowa, wynagrodzenie za nadgodziny i świadczenia są rozdzielane pomiędzy różne grupy?

  • Czy w tym zestawie danych istnieją dowody na dyskryminację płacową ze względu na płeć?

  • Jak przydzielany jest budżet w zależności od grupy i zakresu obowiązków?

# wymiary ramki:
dim(salaries)
## [1] 148654     13
# nazwy kolumn:
names(salaries)
##  [1] "Id"               "EmployeeName"     "JobTitle"         "BasePay"         
##  [5] "OvertimePay"      "OtherPay"         "Benefits"         "TotalPay"        
##  [9] "TotalPayBenefits" "Year"             "Notes"            "Agency"          
## [13] "Status"

Histogramy

hist(salaries$TotalPay,main="Total Pay", xlab="Pay (in dollars)")
abline(v = mean(salaries$TotalPay),lty="dashed")
abline(v = median(salaries$TotalPay))
legend("topright", legend=c("Mediana","Średnia"),lty=c("solid","dashed"))

par(mfrow=c(2,2))
hist(salaries$TotalPay,main="Total Pay, default breaks", xlab="Pay (in dollars)")
hist(salaries$TotalPay,main="Total Pay, breaks=100", xlab="Pay (in dollars)", breaks=100)
hist(salaries$TotalPay,main="Total Pay, breaks=1000", xlab="Pay (in dollars)",breaks=1000)

hist(salaries$TotalPay,main="Total Pay, Zoomed-in", xlab="Pay (in dollars)", xlim=c(0,1e5), breaks=1000)

salaries2 <- subset(salaries, JobTitle=="Firefighter" & Status=="FT")
dim(salaries2)
## [1] 738  13
par(mfrow=c(2,2))
hist(salaries2$TotalPay,main="Firefighters, default breaks", xlab="Pay (in dollars)")
hist(salaries2$TotalPay,main="Firefighters, breaks=30", xlab="Pay (in dollars)", breaks=30)
hist(salaries2$TotalPay,main="Firefighters, breaks=100", xlab="Pay (in dollars)", breaks=100)
hist(salaries2$TotalPay,main="Firefighters, breaks=1000", xlab="Pay (in dollars)",breaks=1000)

Wykresy pudełkowe

par(mfrow=c(1,1))
boxplot(salaries$TotalPay,main="Total Pay, breaks=1000", ylab="Pay (in dollars)")

Estymacja funkcji gęstości

Pierwszy raport dotyczy nieparametrycznej estymacji gęstości. Klasycznym nieparametrycznym estymatorem gęstości jest histogram, który dostarcza nieciągłe i stałe oszacowania. W tym raporcie skupiono się na niektórych alternatywach, które zapewniają ciągłe lub nawet gładkie oszacowania zamiast.

Metody kernelowe stanowią ważną klasę gładkich estymatorów gęstości i zaimplementowane są przez funkcję R density(). Estymatory te są w zasadzie tylko lokalnie ważonymi średnimi, a ich obliczenie jest stosunkowo proste w teorii. W praktyce, różne wybory sposobu implementacji obliczeń mogą jednak mieć duży wpływ na rzeczywisty czas obliczeń, a implementację kernelowych estymatorów gęstości zilustruje trzy punkty:

  • jeśli to możliwe, wybierz wektoryzowane implementacje w R,
  • jeśli niewielka strata w dokładności jest do zaakceptowania, przybliżone rozwiązanie może być o rzędy wielkości szybsze niż implementacja literalna,
  • czas potrzebny do numerycznej oceny różnych funkcje elementarne może bardzo zależeć od funkcji i sposobu implementacji obliczeń.

Metody kernelowe opierają się na jednym lub więcej parametrach regularności, które muszą być dobrane tak, aby osiągnąć właściwą równowagę w dostosowaniu do danych bez zbytniego dostosowywania się do losowej zmienności w danych.

Wybór odpowiedniej ilości regularności jest równie ważny jak wybór metody do użycia w pierwszej kolejności. W rzeczywistości może być ważniejszy. Tak naprawdę nie mamy kompletnej implementacji nieparametrycznego estymatora dopóki nie zaimplementujemy automatycznego, opartego na danych sposobu wyboru ilości regulacji.

Implementacja tylko obliczeń dla oceny estymatora jądra, powiedzmy, i pozostawiając to całkowicie użytkownikowi wyboru szerokości pasma jest pracą w połowie wykonaną. Metody i implementacje do wyboru szerokości pasma są więc w tym raporcie omówione dość szczegółowo.

W ostatniej części przeprowadzona jest analiza prawdopodobieństwa. Robi się to w celu dalszego wyjaśnienia, dlaczego potrzebne są estymatory z regularyzacją w celu uniknięcia nadmiernego dopasowania do danych, oraz dlaczego nie istnieje w ogóle nieparametryczny maksymalnego prawdopodobieństwa estymatora gęstości. Regularyzację prawdopodobieństwamożna osiągnąć poprzez ograniczenie szacunków gęstości do rodziny coraz bardziej elastycznych gęstości parametrycznych, które są dopasowane do danych. Jest to znane jako metoda sit. Inne podejście opiera się na rozszerzeniach bazowych, ale w obu przypadkach automatyczny wybór wielkości regularności jest tak samo ważny jak w przypadku metod jądrowych.

Aby utworzyć wykres gęstości jądra, musisz oszacować gęstość jądra. W tym celu można użyć funkcji density, a następnie przekazać obiekt density do funkcji plot.

# dane
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data)

# Kernel density plot
plot(d, lwd = 2, main = "Default kernel density plot")

Argument jądra funkcji gęstości domyślnie używa jądra gaussowskiego (kernel = “gaussian”), ale dostępnych jest więcej typów jądra, takich jak “prostokątne”, “trójkątne”, “epanechnikov”, “biweight”, “cosine” i “optcosine”. Wybór będzie zależał od twoich danych, ale w większości scenariuszy wartość domyślna jest najbardziej zalecana.

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             kernel = "rectangular")

# Kernel density plot
plot(d, lwd = 2, main = "Rectangular kernel")

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             kernel = "triangular")

# Kernel density plot
plot(d, lwd = 2, main = "Triangular kernel")

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             kernel = "epanechnikov")

# Kernel density plot
plot(d, lwd = 2, main = "Epanechnikov kernel")

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             kernel = "biweight")

# Kernel density plot
plot(d, lwd = 2, main = "Biweight kernel")

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             kernel = "cosine")

# Kernel density plot
plot(d, lwd = 2, main = "Cosine kernel")

Selekcja pasma

Argument bw funkcji gęstości pozwala na zmianę używanego pasma wygładzania. Możesz przekazać wartość lub ciąg znaków podający regułę wyboru lub funkcję. Domyślną wartością jest “nrd0” (lub bw.nrd0(.)), która implementuje podejście oparte na zasadzie reguły kciuka :-) Inne dostępne opcje to:

Reguła Scotta (1992)

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             bw = "nrd")

# Kernel density plot
plot(d, lwd = 2, main = "nrd bandwidth")

Nieobciążona cross-walidacja

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             bw = "ucv")

# Kernel density plot
plot(d, lwd = 2, main = "ucv bandwidth")

Obciążona cross-walidacja

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             bw = "bcv")

# Kernel density plot
plot(d, lwd = 2, main = "bcv bandwidth") 

Metoda Sheather & Jones (1991)

# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)

# Kernel density estimation
d <- density(data,
             bw = "SJ")

# Kernel density plot
plot(d, lwd = 2, main = "SJ bandwidth")

Ostrzeżenie!

Szerokość pasma musi być bardzo starannie dobrana! Mała szerokość pasma spowoduje powstanie nadmiernie dopasowanej krzywej, natomiast zbyt duża szerokość pasma spowoduje powstanie krzywej nadmiernie wygładzonej.

Ćwiczenie 1.

Uruchom demo estymatora funkcji gęstości kernel. Zmieniaj zarówno dane wejściowe, jak i opcje estymatora - szerokość pasma oraz rodzaj funkcji jądrowej. Czy widzisz istotne różnice w oszacowaniu?

#install.packages("remotes") #tylko raz! potem #
#remotes::install_github("hericks/KDE") #tylko raz! potem #
#install.packages("htmltools")
library(KDE)
shiny_kde() 
Shiny applications not supported in static R Markdown documents

Tak, widać istotne różnice. Zwiększenie sd spłaszcza nam rozkład, modyfikacja średniej przesuwa środek rozkładu. Modyfikacja szerokości pasma wpływa na bliskość dopasowania rozkładu do danych (czym mniejsza wartość, tym bardziej dopasowana krzywa)

Ćwiczenie 2.

Wykorzystując dowolną funkcję R do estymacji funkcji gęstości oszacuj jej przebieg dla wynagrodzeń (zbiór danych salaries) strażaków w San Francisco. Wykorzystaj metody graficzne dostępne w pakiecie ggplot2. Mile widziane przekroje oraz odpowiedzi na pytania badawcze zadane na wstępie.

library(tidyverse)
## Warning: pakiet 'ggplot2' został zbudowany w wersji R 4.3.3
## Warning: pakiet 'readr' został zbudowany w wersji R 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
salariesFFSanF <- subset(salaries, JobTitle=="Firefighter" & Agency=="San Francisco")
dim(salariesFFSanF)
## [1] 2359   13

Histogram wynagrodzeń dla strażaków z San Francisco.

sr_mediana_linie <- data.frame(nazwa = c("Średnia",
                                     "Mediana"),
                       wartość     = c(mean(salariesFFSanF$TotalPay),
                                  median(salariesFFSanF$TotalPay)))

ggplot(salariesFFSanF,aes(x = TotalPay)) +
  geom_histogram(binwidth=10000, color="yellow",fill="red") +
  labs(x = "Pay (in dollars)", y = "Frequency", title = "Histogram wynagrodzeń strażaków w San Francisco") +
  geom_vline(data=sr_mediana_linie,aes(xintercept = wartość,
                               linetype = nazwa,
                               col = nazwa),linewidth=1,color="black")+
  theme_minimal()

- Jak zmieniały się wynagrodzenia w czasie między różnymi grupami ludzi?

##Poniżej histogram zmian wynagrodzeń strażaków z SF na przestrzeni lat, ponieważ działamy cały czas tylko na strażakach.

sr_mediana_linie_2012 <- data.frame(nazwa = c("Średnia z 2012",
                                     "Mediana z 2012"), wartość = c(mean(salariesFFSanF$TotalPay[salariesFFSanF$Year==2012]),
 median(salariesFFSanF$TotalPay[salariesFFSanF$Year==2012])))

ggplot(salariesFFSanF,aes(x = TotalPay)) +
  geom_histogram(binwidth=25000, color="yellow",fill="red") +
  labs(x = "Pay (in dollars)", y = "Frequency", title = "Histogram wynagrodzeń strażaków w San Francisco") +
  geom_vline(data=sr_mediana_linie,aes(xintercept = wartość,
                               linetype = nazwa,
                               col = nazwa),linewidth=1,color="black")+
  theme_minimal()+
  facet_grid(. ~ Year)

Widzimy, że względem roku 2012, w 2013 roku liczba strażaków zarabiajacych tyle co srednia i mediana z 2012 roku zwiększyła się. Za to w roku 2014 wróciła do podobnych poziomów co w 2012 roku. Dowodem jest zmiana średniej płący na przestrzeni tych lat, gdzie po peaku w 2013 roku, spadła ona w 2014 roku do poziomu niższego niż w 2012

sr_mediany_lata <- data.frame(Rok = c(2012,2013,2014), 
                                    średnie = c(mean(salariesFFSanF$TotalPay[salariesFFSanF$Year==2012]),
mean(salariesFFSanF$TotalPay[salariesFFSanF$Year==2013]),
mean(salariesFFSanF$TotalPay[salariesFFSanF$Year==2014])),
                                    mediany = c(median(salariesFFSanF$TotalPay[salariesFFSanF$Year==2012]),
median(salariesFFSanF$TotalPay[salariesFFSanF$Year==2013]),
median(salariesFFSanF$TotalPay[salariesFFSanF$Year==2014])))

##Wykres pokazujący zmiany średniej i mediany płac dla strażaków w San Francisco na przestrzeni lat 2012-2014

ggplot(sr_mediany_lata, aes(Rok, średnie)) + 
    geom_ribbon(aes(ymin = średnie, ymax = mediany),fill = "yellow")+
  geom_line(aes(x=Rok,y=mediany,color="Mediany"),lwd=1)+
  geom_line(aes(x=Rok,y=średnie,color="Średnie"),lwd=1)+
  labs(x = "Year", y = "Total Pay (in Dollars)", title = "Zmiany różnicy między średnią i medianą na przestrzeni trzech lat wśród strażaków San Francisco")

Możemy zauwazyć zmiany wysokości średniej i mediany płacy dla strażaków na przestrzeni lat, tak jak było to wspomniane w poprzednim akapicie. Co więcej, widoczna jest zwiększająca się różnica między medianą a średnią, która jest coraz bardziej mniejsza od mediany. W związku z tym, możemy stwierdzić, że ponad połowa strażaków zarabia więcej niż średnia wynagrodzenia dla wszystkich strażaków.

  • Jak płaca podstawowa, wynagrodzenie za nadgodziny i świadczenia są rozdzielane pomiędzy różne grupy?
salariesFFSanF$Benefits<-as.numeric(salariesFFSanF$Benefits)
salariesFFSanF$OvertimePay<-as.numeric(salariesFFSanF$OvertimePay)
salariesFFSanF$BasePay<-as.numeric(salariesFFSanF$BasePay)

##Płaca podstawowa

sr_mediana_linie_basepay <- data.frame(nazwa = c("Średnia dla FT",
                                     "Mediana dla FT"), 
                                     wartość=c(mean(salariesFFSanF$BasePay[salariesFFSanF$Status=='FT']),
 median(salariesFFSanF$BasePay[salariesFFSanF$Status=='FT'])))

ggplot(salariesFFSanF,aes(x = BasePay)) +
  geom_histogram(binwidth=25000, color="orange",fill="darkred") +
  labs(x = "Base Pay", y = "Frequency", title = "Histogram płacy podstawowej dla strażaków w San Francisco") +
  geom_vline(data=sr_mediana_linie_basepay,aes(xintercept = wartość,
                               linetype = nazwa,
                               col = nazwa),linewidth=1,color="black")+
  theme_minimal()+
  facet_grid(. ~ Status)
## Warning: Removed 11 rows containing non-finite outside the scale range
## (`stat_bin()`).

##Wynagrodzenie za nadgodziny

sr_mediana_linie_overtime <- data.frame(nazwa = c("Średnia",
                                     "Mediana"), wartość = c(mean(salariesFFSanF$OvertimePay),
 median(salariesFFSanF$OvertimePay)))

ggplot(salariesFFSanF,aes(x = OvertimePay)) +
  geom_histogram(binwidth=25000, color="orange",fill="maroon") +
  labs(x = "Overtime Pay", y = "Frequency", title = "Histogram płacy za nadgodziny dla strażaków w San Francisco") +
  geom_vline(data=sr_mediana_linie_overtime,aes(xintercept = wartość,
                               linetype = nazwa,
                               col = nazwa),linewidth=1,color="black")+
  theme_minimal()+
  facet_grid(. ~ Status)

##Benefity

sr_mediana_linie_benefits <- data.frame(nazwa = c("Średnia",
                                     "Mediana"), wartość = c(mean(salariesFFSanF$Benefits),
 median(salariesFFSanF$Benefits)))

ggplot(salariesFFSanF,aes(x = Benefits)) +
  geom_histogram(binwidth=10000, color="red",fill="darkorange") +
  labs(x = "Benefits", y = "Frequency", title = "Histogram świadczeń/Benefitów dla strażaków w San Francisco") +
  geom_vline(data=sr_mediana_linie_benefits,aes(xintercept = wartość,
                               linetype = nazwa,
                               col = nazwa),linewidth=1,color="black")+
  theme_minimal()+
  facet_grid(. ~ Status)

Możemy zauważyć, że wydatki budżetowe na płacę podstawową, płacę za nadgodziny i benefity różnią się w zależności od tego czy ktoś pracuje na pełen etat (FT) czy na pół etatu (ST). Zgodnie z oczekiwaniem, wszystkie te wartości są niższe dla strażaków, którzy nie pracują na pełen etat.

  • Czy w tym zestawie danych istnieją dowody na dyskryminację płacową ze względu na płeć? W tym zestawie danych nie mamy informacji na temat płci, więc nie jesteśmy w stanie tego obliczyć.

Oszacowanie gęstości rozkładu wynagrodzeń strażaków w San Francisco:

# Kernel density estimation
d <- density(salariesFFSanF$TotalPay,
             kernel = "gaussian")

# Kernel density plot
plot(d, lwd = 2, main = "Gaussian kernel")

Wybrałem domyślne, gaussowskie jądro, które tak jak było wspomniane, zazwyczaj jest najlepsze. Mamy tu do czynienia z rozkładem bimodalnym, który niejako wyjaśnia nam zauważony wcześniej fakt, że mediana jest wyższa od średniej. Poprzez istotną liczbę (niejako drugą modę) strażaków zarabiających małe pieniądze <0;50 000 USD>, którzy zaniżają znacząco średnią wynagrodzeń, a nie jest ich wystarczająco dużo żeby istotnie zaniżyć medianę.

LS0tDQp0aXRsZTogIktlcm5lbCINCmF1dGhvcjogIk1pY2hhxYIgS3XFum5pZXdza2kgJiBBZ2F0YSBMZXlrIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlDQogICAgZm9udHNpemU6IDEwcHQNCiAgICB0b2M6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgICBkZl9wcmludDogZGVmYXVsdA0KICAgIHRvY19kZXB0aDogNQ0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCm9wdGlvbnMoc2NpcGVuPTk5OSwgZGlnaXRzPTMpDQpzYWxhcmllcyA8LSByZWFkLmNzdigiaHR0cHM6Ly9naXRodWIuY29tL2tmbGlzaWtvd3NraS9kcy9yYXcvbWFzdGVyL1NhbGFyaWVzLmNzdiIpDQpgYGANCg0KIyBBbmFsaXphIG9waXNvd2ENCg0KSmVkbnltIHplIHNwb3NvYsOzdyB6cm96dW1pZW5pYSwgamFrIGR6aWHFgmEgcnrEhWQgbWlhc3RhLCBqZXN0IHNwb2pyemVuaWUgbmEgdG8sIGtvZ28gemF0cnVkbmlhIGkgamFrIGplZ28gcHJhY293bmljeSBzxIUgd3luYWdyYWR6YW5pLiBEYW5lIHRlIHphd2llcmFqxIUgbmF6d2lza2EsIG5henfEmSBzdGFub3dpc2thIGkgd3luYWdyb2R6ZW5pZSBwcmFjb3duaWvDs3cgbWlhc3RhIFNhbiBGcmFuY2lzY28gdyB1asSZY2l1IHJvY3pueW0gb2QgMjAxMSBkbyAyMDE0IHJva3UuDQoNCk90byBraWxrYSBwb215c8WCw7N3IG5hIGVrc3Bsb3JhY2rEmSBkYW55Y2g6DQoNCi0gSmFrIHptaWVuaWHFgnkgc2nEmSB3eW5hZ3JvZHplbmlhIHcgY3phc2llIG1pxJlkenkgcsOzxbxueW1pIGdydXBhbWkgbHVkemk/DQoNCi0gSmFrIHDFgmFjYSBwb2RzdGF3b3dhLCB3eW5hZ3JvZHplbmllIHphIG5hZGdvZHppbnkgaSDFm3dpYWRjemVuaWEgc8SFIHJvemR6aWVsYW5lIHBvbWnEmWR6eSByw7PFvG5lIGdydXB5Pw0KDQotIEN6eSB3IHR5bSB6ZXN0YXdpZSBkYW55Y2ggaXN0bmllasSFIGRvd29keSBuYSBkeXNrcnltaW5hY2rEmSBwxYJhY293xIUgemUgd3pnbMSZZHUgbmEgcMWCZcSHPw0KDQotIEphayBwcnp5ZHppZWxhbnkgamVzdCBidWTFvGV0IHcgemFsZcW8bm/Fm2NpIG9kIGdydXB5IGkgemFrcmVzdSBvYm93acSFemvDs3c/DQoNCmBgYHtyIH0NCiMgd3ltaWFyeSByYW1raToNCmRpbShzYWxhcmllcykNCiMgbmF6d3kga29sdW1uOg0KbmFtZXMoc2FsYXJpZXMpDQpgYGANCg0KIyMgSGlzdG9ncmFteQ0KDQpgYGB7ciB9DQpoaXN0KHNhbGFyaWVzJFRvdGFsUGF5LG1haW49IlRvdGFsIFBheSIsIHhsYWI9IlBheSAoaW4gZG9sbGFycykiKQ0KYWJsaW5lKHYgPSBtZWFuKHNhbGFyaWVzJFRvdGFsUGF5KSxsdHk9ImRhc2hlZCIpDQphYmxpbmUodiA9IG1lZGlhbihzYWxhcmllcyRUb3RhbFBheSkpDQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kPWMoIk1lZGlhbmEiLCLFmnJlZG5pYSIpLGx0eT1jKCJzb2xpZCIsImRhc2hlZCIpKQ0KYGBgDQoNCmBgYHtyIH0NCnBhcihtZnJvdz1jKDIsMikpDQpoaXN0KHNhbGFyaWVzJFRvdGFsUGF5LG1haW49IlRvdGFsIFBheSwgZGVmYXVsdCBicmVha3MiLCB4bGFiPSJQYXkgKGluIGRvbGxhcnMpIikNCmhpc3Qoc2FsYXJpZXMkVG90YWxQYXksbWFpbj0iVG90YWwgUGF5LCBicmVha3M9MTAwIiwgeGxhYj0iUGF5IChpbiBkb2xsYXJzKSIsIGJyZWFrcz0xMDApDQpoaXN0KHNhbGFyaWVzJFRvdGFsUGF5LG1haW49IlRvdGFsIFBheSwgYnJlYWtzPTEwMDAiLCB4bGFiPSJQYXkgKGluIGRvbGxhcnMpIixicmVha3M9MTAwMCkNCmBgYA0KDQpgYGB7ciB9DQpoaXN0KHNhbGFyaWVzJFRvdGFsUGF5LG1haW49IlRvdGFsIFBheSwgWm9vbWVkLWluIiwgeGxhYj0iUGF5IChpbiBkb2xsYXJzKSIsIHhsaW09YygwLDFlNSksIGJyZWFrcz0xMDAwKQ0KYGBgDQoNCmBgYHtyIH0NCnNhbGFyaWVzMiA8LSBzdWJzZXQoc2FsYXJpZXMsIEpvYlRpdGxlPT0iRmlyZWZpZ2h0ZXIiICYgU3RhdHVzPT0iRlQiKQ0KZGltKHNhbGFyaWVzMikNCmBgYA0KDQpgYGB7ciB9DQpwYXIobWZyb3c9YygyLDIpKQ0KaGlzdChzYWxhcmllczIkVG90YWxQYXksbWFpbj0iRmlyZWZpZ2h0ZXJzLCBkZWZhdWx0IGJyZWFrcyIsIHhsYWI9IlBheSAoaW4gZG9sbGFycykiKQ0KaGlzdChzYWxhcmllczIkVG90YWxQYXksbWFpbj0iRmlyZWZpZ2h0ZXJzLCBicmVha3M9MzAiLCB4bGFiPSJQYXkgKGluIGRvbGxhcnMpIiwgYnJlYWtzPTMwKQ0KaGlzdChzYWxhcmllczIkVG90YWxQYXksbWFpbj0iRmlyZWZpZ2h0ZXJzLCBicmVha3M9MTAwIiwgeGxhYj0iUGF5IChpbiBkb2xsYXJzKSIsIGJyZWFrcz0xMDApDQpoaXN0KHNhbGFyaWVzMiRUb3RhbFBheSxtYWluPSJGaXJlZmlnaHRlcnMsIGJyZWFrcz0xMDAwIiwgeGxhYj0iUGF5IChpbiBkb2xsYXJzKSIsYnJlYWtzPTEwMDApDQpgYGANCg0KIyMgV3lrcmVzeSBwdWRlxYJrb3dlDQoNCmBgYHtyIH0NCnBhcihtZnJvdz1jKDEsMSkpDQpib3hwbG90KHNhbGFyaWVzJFRvdGFsUGF5LG1haW49IlRvdGFsIFBheSwgYnJlYWtzPTEwMDAiLCB5bGFiPSJQYXkgKGluIGRvbGxhcnMpIikNCmBgYA0KDQojIEVzdHltYWNqYSBmdW5rY2ppIGfEmXN0b8WbY2kNCg0KUGllcndzenkgcmFwb3J0IGRvdHljenkgbmllcGFyYW1ldHJ5Y3puZWogZXN0eW1hY2ppIGfEmXN0b8WbY2kuIEtsYXN5Y3pueW0gbmllcGFyYW1ldHJ5Y3pueW0gZXN0eW1hdG9yZW0gZ8SZc3RvxZtjaSBqZXN0IGhpc3RvZ3JhbSwga3TDs3J5IGRvc3RhcmN6YSBuaWVjacSFZ8WCZSBpIHN0YcWCZSBvc3phY293YW5pYS4gVyB0eW0gcmFwb3JjaWUgc2t1cGlvbm8gc2nEmSBuYSBuaWVrdMOzcnljaA0KYWx0ZXJuYXR5d2FjaCwga3TDs3JlIHphcGV3bmlhasSFIGNpxIVnxYJlIGx1YiBuYXdldCBnxYJhZGtpZSBvc3phY293YW5pYSB6YW1pYXN0Lg0KDQoqTWV0b2R5IGtlcm5lbG93ZSogc3Rhbm93acSFIHdhxbxuxIUga2xhc8SZIGfFgmFka2ljaCBlc3R5bWF0b3LDs3cgZ8SZc3RvxZtjaSBpIHphaW1wbGVtZW50b3dhbmUgc8SFIHByemV6IGZ1bmtjasSZIFIgYGRlbnNpdHkoKWAuIEVzdHltYXRvcnkgdGUgc8SFIHcgemFzYWR6aWUgdHlsa28gbG9rYWxuaWUgd2HFvG9ueW1pIMWbcmVkbmltaSwgYSBpY2ggb2JsaWN6ZW5pZSBqZXN0IHN0b3N1bmtvd28gcHJvc3RlIHcgdGVvcmlpLiBXIHByYWt0eWNlLCByw7PFvG5lIHd5Ym9yeSBzcG9zb2J1IGltcGxlbWVudGFjamkgb2JsaWN6ZcWEIG1vZ8SFIGplZG5hayBtaWXEhyBkdcW8eSB3cMWCeXcgbmEgcnplY3p5d2lzdHkgY3phcw0Kb2JsaWN6ZcWELCBhIGltcGxlbWVudGFjasSZIGtlcm5lbG93eWNoIGVzdHltYXRvcsOzdyBnxJlzdG/Fm2NpIHppbHVzdHJ1amUgdHJ6eSBwdW5rdHk6DQoNCi0gICBqZcWbbGkgdG8gbW/FvGxpd2UsIHd5Ymllcnogd2VrdG9yeXpvd2FuZSBpbXBsZW1lbnRhY2plIHcgUiwNCi0gICBqZcWbbGkgbmlld2llbGthIHN0cmF0YSB3IGRva8WCYWRub8WbY2kgamVzdCBkbyB6YWFrY2VwdG93YW5pYSwgcHJ6eWJsacW8b25lIHJvendpxIV6YW5pZSBtb8W8ZSBiecSHIG8gcnrEmWR5IHdpZWxrb8WbY2kgc3p5YnN6ZSBuacW8IGltcGxlbWVudGFjamEgbGl0ZXJhbG5hLA0KLSAgIGN6YXMgcG90cnplYm55IGRvIG51bWVyeWN6bmVqIG9jZW55IHLDs8W8bnljaCBbZnVua2NqZSBlbGVtZW50YXJuZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRWxlbWVudGFyeV9mdW5jdGlvbikgbW/FvGUgYmFyZHpvIHphbGXFvGXEhyBvZCBmdW5rY2ppIGkgc3Bvc29idSBpbXBsZW1lbnRhY2ppIG9ibGljemXFhC4NCg0KTWV0b2R5IGtlcm5lbG93ZSBvcGllcmFqxIUgc2nEmSBuYSBqZWRueW0gbHViIHdpxJljZWogKnBhcmFtZXRyYWNoIHJlZ3VsYXJub8WbY2kqLCBrdMOzcmUgbXVzesSFIGJ5xIcgZG9icmFuZSB0YWssIGFieSBvc2nEhWduxIXEhyB3xYJhxZtjaXfEhSByw7N3bm93YWfEmSB3IGRvc3Rvc293YW5pdSBkbyBkYW55Y2ggYmV6IHpieXRuaWVnbyBkb3N0b3Nvd3l3YW5pYSBzacSZIGRvIGxvc293ZWogem1pZW5ub8WbY2kgdyBkYW55Y2guDQoNCld5YsOzciBvZHBvd2llZG5pZWogaWxvxZtjaSByZWd1bGFybm/Fm2NpIGplc3QgcsOzd25pZSB3YcW8bnkgamFrIHd5YsOzciBtZXRvZHkgZG8gdcW8eWNpYSB3IHBpZXJ3c3plaiBrb2xlam5vxZtjaS4gVyAgcnplY3p5d2lzdG/Fm2NpIG1vxbxlIGJ5xIcgd2HFvG5pZWpzenkuIFRhayBuYXByYXdkxJkgbmllIG1hbXkga29tcGxldG5laiBpbXBsZW1lbnRhY2ppIG5pZXBhcmFtZXRyeWN6bmVnbyBlc3R5bWF0b3JhIGRvcMOza2kgbmllIHphaW1wbGVtZW50dWplbXkgYXV0b21hdHljem5lZ28sIG9wYXJ0ZWdvIG5hIGRhbnljaCBzcG9zb2J1IHd5Ym9ydSBpbG/Fm2NpIHJlZ3VsYWNqaS4NCg0KSW1wbGVtZW50YWNqYSB0eWxrbyBvYmxpY3plxYQgZGxhIG9jZW55IGVzdHltYXRvcmEgasSFZHJhLCBwb3dpZWR6bXksIGkgcG96b3N0YXdpYWrEhWMgdG8gY2HFgmtvd2ljaWUgdcW8eXRrb3duaWtvd2kgd3lib3J1IHN6ZXJva2/Fm2NpIHBhc21hIGplc3QgcHJhY8SFIHcgcG/Fgm93aWUgd3lrb25hbsSFLiBNZXRvZHkgaSBpbXBsZW1lbnRhY2plIGRvIHd5Ym9ydSBzemVyb2tvxZtjaSBwYXNtYSBzxIUgd2nEmWMgdyB0eW0gcmFwb3JjaWUgb23Ds3dpb25lIGRvxZvEhyBzemN6ZWfDs8WCb3dvLg0KDQpXIG9zdGF0bmllaiBjesSZxZtjaSBwcnplcHJvd2Fkem9uYSBqZXN0IGFuYWxpemEgcHJhd2RvcG9kb2JpZcWEc3R3YS4gUm9iaSBzacSZIHRvIHcgY2VsdSBkYWxzemVnbyB3eWphxZtuaWVuaWEsIGRsYWN6ZWdvIHBvdHJ6ZWJuZSBzxIUgZXN0eW1hdG9yeSB6IHJlZ3VsYXJ5emFjasSFIHcgY2VsdSB1bmlrbmnEmWNpYSBuYWRtaWVybmVnbyBkb3Bhc293YW5pYSBkbyBkYW55Y2gsIG9yYXogZGxhY3plZ28gbmllIGlzdG5pZWplIHcgb2fDs2xlIG5pZXBhcmFtZXRyeWN6bnkgbWFrc3ltYWxuZWdvIHByYXdkb3BvZG9iaWXFhHN0d2EgZXN0eW1hdG9yYSBnxJlzdG/Fm2NpLiBSZWd1bGFyeXphY2rEmSBwcmF3ZG9wb2RvYmllxYRzdHdhbW/FvG5hIG9zacSFZ27EhcSHIHBvcHJ6ZXogb2dyYW5pY3plbmllIHN6YWN1bmvDs3cgZ8SZc3RvxZtjaSBkbyByb2R6aW55IGNvcmF6IGJhcmR6aWVqIGVsYXN0eWN6bnljaCBnxJlzdG/Fm2NpIHBhcmFtZXRyeWN6bnljaCwga3TDs3JlIHPEhSBkb3Bhc293YW5lIGRvIGRhbnljaC4gSmVzdCB0byB6bmFuZSBqYWtvICptZXRvZGEgc2l0Ki4gSW5uZSBwb2RlasWbY2llIG9waWVyYSBzacSZIG5hIHJvenN6ZXJ6ZW5pYWNoIGJhem93eWNoLCBhbGUgdyBvYnUgcHJ6eXBhZGthY2ggYXV0b21hdHljem55IHd5YsOzciB3aWVsa2/Fm2NpIHJlZ3VsYXJub8WbY2kgamVzdCB0YWsgc2FtbyB3YcW8bnkgamFrIHcgcHJ6eXBhZGt1IG1ldG9kIGrEhWRyb3d5Y2guDQoNCkFieSB1dHdvcnp5xIcgd3lrcmVzIGfEmXN0b8WbY2kgasSFZHJhLCBtdXNpc3ogb3N6YWNvd2HEhyBnxJlzdG/Fm8SHIGrEhWRyYS4gVyB0eW0gY2VsdSBtb8W8bmEgdcW8ecSHIGZ1bmtjamkgZGVuc2l0eSwgYSBuYXN0xJlwbmllIHByemVrYXphxIcgb2JpZWt0IGRlbnNpdHkgZG8gZnVua2NqaSBwbG90Lg0KDQpgYGB7cn0NCiMgZGFuZQ0Kc2V0LnNlZWQoMTQwMTIwMjEpDQpkYXRhIDwtIHJub3JtKDIwMCwgbWVhbiA9IDQpDQoNCiMgS2VybmVsIGRlbnNpdHkgZXN0aW1hdGlvbg0KZCA8LSBkZW5zaXR5KGRhdGEpDQoNCiMgS2VybmVsIGRlbnNpdHkgcGxvdA0KcGxvdChkLCBsd2QgPSAyLCBtYWluID0gIkRlZmF1bHQga2VybmVsIGRlbnNpdHkgcGxvdCIpDQoNCmBgYA0KDQpBcmd1bWVudCBqxIVkcmEgZnVua2NqaSBnxJlzdG/Fm2NpIGRvbXnFm2xuaWUgdcW8eXdhIGrEhWRyYSBnYXVzc293c2tpZWdvIChrZXJuZWwgPSAiZ2F1c3NpYW4iKSwgYWxlIGRvc3TEmXBueWNoIGplc3Qgd2nEmWNlaiB0eXDDs3cgasSFZHJhLCB0YWtpY2ggamFrICJwcm9zdG9rxIV0bmUiLCAidHLDs2prxIV0bmUiLCAiZXBhbmVjaG5pa292IiwgImJpd2VpZ2h0IiwgImNvc2luZSIgaSAib3B0Y29zaW5lIi4gV3liw7NyIGLEmWR6aWUgemFsZcW8YcWCIG9kIHR3b2ljaCBkYW55Y2gsIGFsZSB3IHdpxJlrc3pvxZtjaSBzY2VuYXJpdXN6eSB3YXJ0b8WbxIcgZG9tecWbbG5hIGplc3QgbmFqYmFyZHppZWogemFsZWNhbmEuDQoNCmBgYHtyfQ0KIyBEYXRhDQpzZXQuc2VlZCgxNDAxMjAyMSkNCmRhdGEgPC0gcm5vcm0oMjAwLCBtZWFuID0gNCkNCg0KIyBLZXJuZWwgZGVuc2l0eSBlc3RpbWF0aW9uDQpkIDwtIGRlbnNpdHkoZGF0YSwNCiAgICAgICAgICAgICBrZXJuZWwgPSAicmVjdGFuZ3VsYXIiKQ0KDQojIEtlcm5lbCBkZW5zaXR5IHBsb3QNCnBsb3QoZCwgbHdkID0gMiwgbWFpbiA9ICJSZWN0YW5ndWxhciBrZXJuZWwiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBEYXRhDQpzZXQuc2VlZCgxNDAxMjAyMSkNCmRhdGEgPC0gcm5vcm0oMjAwLCBtZWFuID0gNCkNCg0KIyBLZXJuZWwgZGVuc2l0eSBlc3RpbWF0aW9uDQpkIDwtIGRlbnNpdHkoZGF0YSwNCiAgICAgICAgICAgICBrZXJuZWwgPSAidHJpYW5ndWxhciIpDQoNCiMgS2VybmVsIGRlbnNpdHkgcGxvdA0KcGxvdChkLCBsd2QgPSAyLCBtYWluID0gIlRyaWFuZ3VsYXIga2VybmVsIikNCmBgYA0KDQpgYGB7cn0NCiMgRGF0YQ0Kc2V0LnNlZWQoMTQwMTIwMjEpDQpkYXRhIDwtIHJub3JtKDIwMCwgbWVhbiA9IDQpDQoNCiMgS2VybmVsIGRlbnNpdHkgZXN0aW1hdGlvbg0KZCA8LSBkZW5zaXR5KGRhdGEsDQogICAgICAgICAgICAga2VybmVsID0gImVwYW5lY2huaWtvdiIpDQoNCiMgS2VybmVsIGRlbnNpdHkgcGxvdA0KcGxvdChkLCBsd2QgPSAyLCBtYWluID0gIkVwYW5lY2huaWtvdiBrZXJuZWwiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBEYXRhDQpzZXQuc2VlZCgxNDAxMjAyMSkNCmRhdGEgPC0gcm5vcm0oMjAwLCBtZWFuID0gNCkNCg0KIyBLZXJuZWwgZGVuc2l0eSBlc3RpbWF0aW9uDQpkIDwtIGRlbnNpdHkoZGF0YSwNCiAgICAgICAgICAgICBrZXJuZWwgPSAiYml3ZWlnaHQiKQ0KDQojIEtlcm5lbCBkZW5zaXR5IHBsb3QNCnBsb3QoZCwgbHdkID0gMiwgbWFpbiA9ICJCaXdlaWdodCBrZXJuZWwiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBEYXRhDQpzZXQuc2VlZCgxNDAxMjAyMSkNCmRhdGEgPC0gcm5vcm0oMjAwLCBtZWFuID0gNCkNCg0KIyBLZXJuZWwgZGVuc2l0eSBlc3RpbWF0aW9uDQpkIDwtIGRlbnNpdHkoZGF0YSwNCiAgICAgICAgICAgICBrZXJuZWwgPSAiY29zaW5lIikNCg0KIyBLZXJuZWwgZGVuc2l0eSBwbG90DQpwbG90KGQsIGx3ZCA9IDIsIG1haW4gPSAiQ29zaW5lIGtlcm5lbCIpDQpgYGANCg0KIyMgU2VsZWtjamEgcGFzbWENCg0KQXJndW1lbnQgYncgZnVua2NqaSBnxJlzdG/Fm2NpIHBvendhbGEgbmEgem1pYW7EmSB1xbx5d2FuZWdvIHBhc21hIHd5Z8WCYWR6YW5pYS4gTW/FvGVzeiBwcnpla2F6YcSHIHdhcnRvxZvEhyBsdWIgY2nEhWcgem5ha8OzdyBwb2RhasSFY3kgcmVndcWCxJkgd3lib3J1IGx1YiBmdW5rY2rEmS4gRG9tecWbbG7EhSB3YXJ0b8WbY2nEhSBqZXN0ICJucmQwIiAobHViIGJ3Lm5yZDAoLikpLCBrdMOzcmEgaW1wbGVtZW50dWplIHBvZGVqxZtjaWUgb3BhcnRlIG5hIHphc2FkemllIHJlZ3XFgnkga2NpdWthIDotKSBJbm5lIGRvc3TEmXBuZSBvcGNqZSB0bzoNCg0KIyMjIFJlZ3XFgmEgU2NvdHRhICgxOTkyKQ0KDQpgYGB7cn0NCiMgRGF0YQ0Kc2V0LnNlZWQoMTQwMTIwMjEpDQpkYXRhIDwtIHJub3JtKDIwMCwgbWVhbiA9IDQpDQoNCiMgS2VybmVsIGRlbnNpdHkgZXN0aW1hdGlvbg0KZCA8LSBkZW5zaXR5KGRhdGEsDQogICAgICAgICAgICAgYncgPSAibnJkIikNCg0KIyBLZXJuZWwgZGVuc2l0eSBwbG90DQpwbG90KGQsIGx3ZCA9IDIsIG1haW4gPSAibnJkIGJhbmR3aWR0aCIpDQpgYGANCg0KIyMjIE5pZW9iY2nEhcW8b25hIGNyb3NzLXdhbGlkYWNqYQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBEYXRhDQpzZXQuc2VlZCgxNDAxMjAyMSkNCmRhdGEgPC0gcm5vcm0oMjAwLCBtZWFuID0gNCkNCg0KIyBLZXJuZWwgZGVuc2l0eSBlc3RpbWF0aW9uDQpkIDwtIGRlbnNpdHkoZGF0YSwNCiAgICAgICAgICAgICBidyA9ICJ1Y3YiKQ0KDQojIEtlcm5lbCBkZW5zaXR5IHBsb3QNCnBsb3QoZCwgbHdkID0gMiwgbWFpbiA9ICJ1Y3YgYmFuZHdpZHRoIikNCmBgYA0KDQojIyMgT2JjacSFxbxvbmEgY3Jvc3Mtd2FsaWRhY2phDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIERhdGENCnNldC5zZWVkKDE0MDEyMDIxKQ0KZGF0YSA8LSBybm9ybSgyMDAsIG1lYW4gPSA0KQ0KDQojIEtlcm5lbCBkZW5zaXR5IGVzdGltYXRpb24NCmQgPC0gZGVuc2l0eShkYXRhLA0KICAgICAgICAgICAgIGJ3ID0gImJjdiIpDQoNCiMgS2VybmVsIGRlbnNpdHkgcGxvdA0KcGxvdChkLCBsd2QgPSAyLCBtYWluID0gImJjdiBiYW5kd2lkdGgiKSANCg0KYGBgDQoNCiMjIyBNZXRvZGEgU2hlYXRoZXIgJiBKb25lcyAoMTk5MSkNCg0KYGBge3J9DQojIERhdGENCnNldC5zZWVkKDE0MDEyMDIxKQ0KZGF0YSA8LSBybm9ybSgyMDAsIG1lYW4gPSA0KQ0KDQojIEtlcm5lbCBkZW5zaXR5IGVzdGltYXRpb24NCmQgPC0gZGVuc2l0eShkYXRhLA0KICAgICAgICAgICAgIGJ3ID0gIlNKIikNCg0KIyBLZXJuZWwgZGVuc2l0eSBwbG90DQpwbG90KGQsIGx3ZCA9IDIsIG1haW4gPSAiU0ogYmFuZHdpZHRoIikNCmBgYA0KDQpPc3RyemXFvGVuaWUhDQoNCjogICBTemVyb2tvxZvEhyBwYXNtYSBtdXNpIGJ5xIcgYmFyZHpvIHN0YXJhbm5pZSBkb2JyYW5hISBNYcWCYSBzemVyb2tvxZvEhyBwYXNtYSBzcG93b2R1amUgcG93c3RhbmllIG5hZG1pZXJuaWUgZG9wYXNvd2FuZWoga3J6eXdlaiwgbmF0b21pYXN0IHpieXQgZHXFvGEgc3plcm9rb8WbxIcgcGFzbWEgc3Bvd29kdWplIHBvd3N0YW5pZSBrcnp5d2VqIG5hZG1pZXJuaWUgd3lnxYJhZHpvbmVqLg0KDQojIMSGd2ljemVuaWUgMS4NCg0KVXJ1Y2hvbSBkZW1vIGVzdHltYXRvcmEgZnVua2NqaSBnxJlzdG/Fm2NpIGtlcm5lbC4gWm1pZW5pYWogemFyw7N3bm8gZGFuZSB3ZWrFm2Npb3dlLCBqYWsgaSBvcGNqZSBlc3R5bWF0b3JhIC0gc3plcm9rb8WbxIcgcGFzbWEgb3JheiByb2R6YWogZnVua2NqaSBqxIVkcm93ZWouIEN6eSB3aWR6aXN6IGlzdG90bmUgcsOzxbxuaWNlIHcgb3N6YWNvd2FuaXU/DQoNCmBgYHtyIGN3aWN6ZW5pZTF9DQojaW5zdGFsbC5wYWNrYWdlcygicmVtb3RlcyIpICN0eWxrbyByYXohIHBvdGVtICMNCiNyZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiaGVyaWNrcy9LREUiKSAjdHlsa28gcmF6ISBwb3RlbSAjDQojaW5zdGFsbC5wYWNrYWdlcygiaHRtbHRvb2xzIikNCmxpYnJhcnkoS0RFKQ0Kc2hpbnlfa2RlKCkgDQpgYGANClRhaywgd2lkYcSHIGlzdG90bmUgcsOzxbxuaWNlLiBad2nEmWtzemVuaWUgc2Qgc3DFgmFzemN6YSBuYW0gcm96a8WCYWQsIG1vZHlmaWthY2phIMWbcmVkbmllaiBwcnplc3V3YSDFm3JvZGVrIHJvemvFgmFkdS4gTW9keWZpa2FjamEgc3plcm9rb8WbY2kgcGFzbWEgd3DFgnl3YSBuYSBibGlza2/Fm8SHIGRvcGFzb3dhbmlhIHJvemvFgmFkdSBkbyBkYW55Y2ggKGN6eW0gbW5pZWpzemEgd2FydG/Fm8SHLCB0eW0gYmFyZHppZWogZG9wYXNvd2FuYSBrcnp5d2EpDQoNCiMgxIZ3aWN6ZW5pZSAyLg0KDQpXeWtvcnp5c3R1asSFYyBkb3dvbG7EhSBmdW5rY2rEmSBSIGRvIGVzdHltYWNqaSBmdW5rY2ppIGfEmXN0b8WbY2kgb3N6YWN1aiBqZWogcHJ6ZWJpZWcgZGxhIHd5bmFncm9kemXFhCAoemJpw7NyIGRhbnljaCBzYWxhcmllcykgc3RyYcW8YWvDs3cgdyBTYW4gRnJhbmNpc2NvLiBXeWtvcnp5c3RhaiBtZXRvZHkgZ3JhZmljem5lIGRvc3TEmXBuZSB3IHBha2llY2llIGdncGxvdDIuIE1pbGUgd2lkemlhbmUgcHJ6ZWtyb2plIG9yYXogb2Rwb3dpZWR6aSBuYSBweXRhbmlhIGJhZGF3Y3plIHphZGFuZSBuYSB3c3TEmXBpZS4NCg0KDQpgYGB7ciB9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQpgYGB7ciB9DQpzYWxhcmllc0ZGU2FuRiA8LSBzdWJzZXQoc2FsYXJpZXMsIEpvYlRpdGxlPT0iRmlyZWZpZ2h0ZXIiICYgQWdlbmN5PT0iU2FuIEZyYW5jaXNjbyIpDQpkaW0oc2FsYXJpZXNGRlNhbkYpDQpgYGANCkhpc3RvZ3JhbSB3eW5hZ3JvZHplxYQgZGxhIHN0cmHFvGFrw7N3IHogU2FuIEZyYW5jaXNjby4NCg0KYGBge3J9DQpzcl9tZWRpYW5hX2xpbmllIDwtIGRhdGEuZnJhbWUobmF6d2EgPSBjKCLFmnJlZG5pYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lZGlhbmEiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgd2FydG/Fm8SHICAgICA9IGMobWVhbihzYWxhcmllc0ZGU2FuRiRUb3RhbFBheSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVkaWFuKHNhbGFyaWVzRkZTYW5GJFRvdGFsUGF5KSkpDQoNCmdncGxvdChzYWxhcmllc0ZGU2FuRixhZXMoeCA9IFRvdGFsUGF5KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xMDAwMCwgY29sb3I9InllbGxvdyIsZmlsbD0icmVkIikgKw0KICBsYWJzKHggPSAiUGF5IChpbiBkb2xsYXJzKSIsIHkgPSAiRnJlcXVlbmN5IiwgdGl0bGUgPSAiSGlzdG9ncmFtIHd5bmFncm9kemXFhCBzdHJhxbxha8OzdyB3IFNhbiBGcmFuY2lzY28iKSArDQogIGdlb21fdmxpbmUoZGF0YT1zcl9tZWRpYW5hX2xpbmllLGFlcyh4aW50ZXJjZXB0ID0gd2FydG/Fm8SHLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gbmF6d2EsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbmF6d2EpLGxpbmV3aWR0aD0xLGNvbG9yPSJibGFjayIpKw0KICB0aGVtZV9taW5pbWFsKCkNCiAgDQpgYGANCi0gSmFrIHptaWVuaWHFgnkgc2nEmSB3eW5hZ3JvZHplbmlhIHcgY3phc2llIG1pxJlkenkgcsOzxbxueW1pIGdydXBhbWkgbHVkemk/DQoNCiMjUG9uacW8ZWogaGlzdG9ncmFtICB6bWlhbiB3eW5hZ3JvZHplxYQgc3RyYcW8YWvDs3cgeiBTRiBuYSBwcnplc3RyemVuaSBsYXQsIHBvbmlld2HFvCBkemlhxYJhbXkgY2HFgnkgY3phcyB0eWxrbyBuYSBzdHJhxbxha2FjaC4NCg0KYGBge3J9DQpzcl9tZWRpYW5hX2xpbmllXzIwMTIgPC0gZGF0YS5mcmFtZShuYXp3YSA9IGMoIsWacmVkbmlhIHogMjAxMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lZGlhbmEgeiAyMDEyIiksIHdhcnRvxZvEhyA9IGMobWVhbihzYWxhcmllc0ZGU2FuRiRUb3RhbFBheVtzYWxhcmllc0ZGU2FuRiRZZWFyPT0yMDEyXSksDQogbWVkaWFuKHNhbGFyaWVzRkZTYW5GJFRvdGFsUGF5W3NhbGFyaWVzRkZTYW5GJFllYXI9PTIwMTJdKSkpDQoNCmdncGxvdChzYWxhcmllc0ZGU2FuRixhZXMoeCA9IFRvdGFsUGF5KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0yNTAwMCwgY29sb3I9InllbGxvdyIsZmlsbD0icmVkIikgKw0KICBsYWJzKHggPSAiUGF5IChpbiBkb2xsYXJzKSIsIHkgPSAiRnJlcXVlbmN5IiwgdGl0bGUgPSAiSGlzdG9ncmFtIHd5bmFncm9kemXFhCBzdHJhxbxha8OzdyB3IFNhbiBGcmFuY2lzY28iKSArDQogIGdlb21fdmxpbmUoZGF0YT1zcl9tZWRpYW5hX2xpbmllLGFlcyh4aW50ZXJjZXB0ID0gd2FydG/Fm8SHLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gbmF6d2EsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbmF6d2EpLGxpbmV3aWR0aD0xLGNvbG9yPSJibGFjayIpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGZhY2V0X2dyaWQoLiB+IFllYXIpDQoNCmBgYA0KV2lkemlteSwgxbxlIHd6Z2zEmWRlbSByb2t1IDIwMTIsIHcgMjAxMyByb2t1IGxpY3piYSBzdHJhxbxha8OzdyB6YXJhYmlhamFjeWNoIHR5bGUgY28gc3JlZG5pYSBpIG1lZGlhbmEgeiAyMDEyIHJva3UgendpxJlrc3p5xYJhIHNpxJkuIFphIHRvIHcgcm9rdSAyMDE0IHdyw7NjacWCYSBkbyBwb2RvYm55Y2ggcG96aW9tw7N3IGNvIHcgMjAxMiByb2t1LiBEb3dvZGVtIGplc3Qgem1pYW5hIMWbcmVkbmllaiBwxYLEhWN5IG5hIHByemVzdHJ6ZW5pIHR5Y2ggbGF0LCBnZHppZSBwbyBwZWFrdSB3IDIwMTMgcm9rdSwgc3BhZMWCYSBvbmEgdyAyMDE0IHJva3UgZG8gcG96aW9tdSBuacW8c3plZ28gbmnFvCB3IDIwMTINCmBgYHtyfQ0KDQpzcl9tZWRpYW55X2xhdGEgPC0gZGF0YS5mcmFtZShSb2sgPSBjKDIwMTIsMjAxMywyMDE0KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDFm3JlZG5pZSA9IGMobWVhbihzYWxhcmllc0ZGU2FuRiRUb3RhbFBheVtzYWxhcmllc0ZGU2FuRiRZZWFyPT0yMDEyXSksDQptZWFuKHNhbGFyaWVzRkZTYW5GJFRvdGFsUGF5W3NhbGFyaWVzRkZTYW5GJFllYXI9PTIwMTNdKSwNCm1lYW4oc2FsYXJpZXNGRlNhbkYkVG90YWxQYXlbc2FsYXJpZXNGRlNhbkYkWWVhcj09MjAxNF0pKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbnkgPSBjKG1lZGlhbihzYWxhcmllc0ZGU2FuRiRUb3RhbFBheVtzYWxhcmllc0ZGU2FuRiRZZWFyPT0yMDEyXSksDQptZWRpYW4oc2FsYXJpZXNGRlNhbkYkVG90YWxQYXlbc2FsYXJpZXNGRlNhbkYkWWVhcj09MjAxM10pLA0KbWVkaWFuKHNhbGFyaWVzRkZTYW5GJFRvdGFsUGF5W3NhbGFyaWVzRkZTYW5GJFllYXI9PTIwMTRdKSkpDQpgYGANCg0KIyNXeWtyZXMgcG9rYXp1asSFY3kgem1pYW55IMWbcmVkbmllaiBpIG1lZGlhbnkgcMWCYWMgZGxhIHN0cmHFvGFrw7N3IHcgU2FuIEZyYW5jaXNjbyBuYSBwcnplc3RyemVuaSBsYXQgMjAxMi0yMDE0DQoNCmBgYHtyfQ0KZ2dwbG90KHNyX21lZGlhbnlfbGF0YSwgYWVzKFJvaywgxZtyZWRuaWUpKSArIA0KICAgIGdlb21fcmliYm9uKGFlcyh5bWluID0gxZtyZWRuaWUsIHltYXggPSBtZWRpYW55KSxmaWxsID0gInllbGxvdyIpKw0KICBnZW9tX2xpbmUoYWVzKHg9Um9rLHk9bWVkaWFueSxjb2xvcj0iTWVkaWFueSIpLGx3ZD0xKSsNCiAgZ2VvbV9saW5lKGFlcyh4PVJvayx5PcWbcmVkbmllLGNvbG9yPSLFmnJlZG5pZSIpLGx3ZD0xKSsNCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIlRvdGFsIFBheSAoaW4gRG9sbGFycykiLCB0aXRsZSA9ICJabWlhbnkgcsOzxbxuaWN5IG1pxJlkenkgxZtyZWRuacSFIGkgbWVkaWFuxIUgbmEgcHJ6ZXN0cnplbmkgdHJ6ZWNoIGxhdCB3xZtyw7NkIHN0cmHFvGFrw7N3IFNhbiBGcmFuY2lzY28iKQ0KDQpgYGANCk1vxbxlbXkgemF1d2F6ecSHIHptaWFueSB3eXNva2/Fm2NpIMWbcmVkbmllaiBpIG1lZGlhbnkgcMWCYWN5IGRsYSBzdHJhxbxha8OzdyBuYSBwcnplc3RyemVuaSBsYXQsIHRhayBqYWsgYnnFgm8gdG8gd3Nwb21uaWFuZSB3IHBvcHJ6ZWRuaW0gYWthcGljaWUuIENvIHdpxJljZWosIHdpZG9jem5hIGplc3QgendpxJlrc3phasSFY2Egc2nEmSByw7PFvG5pY2EgbWnEmWR6eSBtZWRpYW7EhSBhIMWbcmVkbmnEhSwga3TDs3JhIGplc3QgY29yYXogYmFyZHppZWogbW5pZWpzemEgb2QgbWVkaWFueS4gVyB6d2nEhXprdSB6IHR5bSwgbW/FvGVteSBzdHdpZXJkemnEhywgxbxlIHBvbmFkIHBvxYJvd2Egc3RyYcW8YWvDs3cgemFyYWJpYSB3acSZY2VqIG5pxbwgxZtyZWRuaWEgd3luYWdyb2R6ZW5pYSBkbGEgd3N6eXN0a2ljaCBzdHJhxbxha8Ozdy4NCg0KLSBKYWsgcMWCYWNhIHBvZHN0YXdvd2EsIHd5bmFncm9kemVuaWUgemEgbmFkZ29kemlueSBpIMWbd2lhZGN6ZW5pYSBzxIUgcm96ZHppZWxhbmUgcG9tacSZZHp5IHLDs8W8bmUgZ3J1cHk/DQpgYGB7cn0NCnNhbGFyaWVzRkZTYW5GJEJlbmVmaXRzPC1hcy5udW1lcmljKHNhbGFyaWVzRkZTYW5GJEJlbmVmaXRzKQ0Kc2FsYXJpZXNGRlNhbkYkT3ZlcnRpbWVQYXk8LWFzLm51bWVyaWMoc2FsYXJpZXNGRlNhbkYkT3ZlcnRpbWVQYXkpDQpzYWxhcmllc0ZGU2FuRiRCYXNlUGF5PC1hcy5udW1lcmljKHNhbGFyaWVzRkZTYW5GJEJhc2VQYXkpDQpgYGANCg0KDQojI1DFgmFjYSBwb2RzdGF3b3dhDQoNCmBgYHtyfQ0Kc3JfbWVkaWFuYV9saW5pZV9iYXNlcGF5IDwtIGRhdGEuZnJhbWUobmF6d2EgPSBjKCLFmnJlZG5pYSBkbGEgRlQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZWRpYW5hIGRsYSBGVCIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJ0b8WbxIc9YyhtZWFuKHNhbGFyaWVzRkZTYW5GJEJhc2VQYXlbc2FsYXJpZXNGRlNhbkYkU3RhdHVzPT0nRlQnXSksDQogbWVkaWFuKHNhbGFyaWVzRkZTYW5GJEJhc2VQYXlbc2FsYXJpZXNGRlNhbkYkU3RhdHVzPT0nRlQnXSkpKQ0KDQpnZ3Bsb3Qoc2FsYXJpZXNGRlNhbkYsYWVzKHggPSBCYXNlUGF5KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0yNTAwMCwgY29sb3I9Im9yYW5nZSIsZmlsbD0iZGFya3JlZCIpICsNCiAgbGFicyh4ID0gIkJhc2UgUGF5IiwgeSA9ICJGcmVxdWVuY3kiLCB0aXRsZSA9ICJIaXN0b2dyYW0gcMWCYWN5IHBvZHN0YXdvd2VqIGRsYSBzdHJhxbxha8OzdyB3IFNhbiBGcmFuY2lzY28iKSArDQogIGdlb21fdmxpbmUoZGF0YT1zcl9tZWRpYW5hX2xpbmllX2Jhc2VwYXksYWVzKHhpbnRlcmNlcHQgPSB3YXJ0b8WbxIcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSBuYXp3YSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBuYXp3YSksbGluZXdpZHRoPTEsY29sb3I9ImJsYWNrIikrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgZmFjZXRfZ3JpZCguIH4gU3RhdHVzKQ0KDQpgYGANCg0KIyNXeW5hZ3JvZHplbmllIHphIG5hZGdvZHppbnkNCmBgYHtyfQ0Kc3JfbWVkaWFuYV9saW5pZV9vdmVydGltZSA8LSBkYXRhLmZyYW1lKG5hendhID0gYygixZpyZWRuaWEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZWRpYW5hIiksIHdhcnRvxZvEhyA9IGMobWVhbihzYWxhcmllc0ZGU2FuRiRPdmVydGltZVBheSksDQogbWVkaWFuKHNhbGFyaWVzRkZTYW5GJE92ZXJ0aW1lUGF5KSkpDQoNCmdncGxvdChzYWxhcmllc0ZGU2FuRixhZXMoeCA9IE92ZXJ0aW1lUGF5KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0yNTAwMCwgY29sb3I9Im9yYW5nZSIsZmlsbD0ibWFyb29uIikgKw0KICBsYWJzKHggPSAiT3ZlcnRpbWUgUGF5IiwgeSA9ICJGcmVxdWVuY3kiLCB0aXRsZSA9ICJIaXN0b2dyYW0gcMWCYWN5IHphIG5hZGdvZHppbnkgZGxhIHN0cmHFvGFrw7N3IHcgU2FuIEZyYW5jaXNjbyIpICsNCiAgZ2VvbV92bGluZShkYXRhPXNyX21lZGlhbmFfbGluaWVfb3ZlcnRpbWUsYWVzKHhpbnRlcmNlcHQgPSB3YXJ0b8WbxIcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSBuYXp3YSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBuYXp3YSksbGluZXdpZHRoPTEsY29sb3I9ImJsYWNrIikrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgZmFjZXRfZ3JpZCguIH4gU3RhdHVzKQ0KDQpgYGANCg0KIyNCZW5lZml0eQ0KYGBge3J9DQpzcl9tZWRpYW5hX2xpbmllX2JlbmVmaXRzIDwtIGRhdGEuZnJhbWUobmF6d2EgPSBjKCLFmnJlZG5pYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lZGlhbmEiKSwgd2FydG/Fm8SHID0gYyhtZWFuKHNhbGFyaWVzRkZTYW5GJEJlbmVmaXRzKSwNCiBtZWRpYW4oc2FsYXJpZXNGRlNhbkYkQmVuZWZpdHMpKSkNCg0KZ2dwbG90KHNhbGFyaWVzRkZTYW5GLGFlcyh4ID0gQmVuZWZpdHMpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwMDAwLCBjb2xvcj0icmVkIixmaWxsPSJkYXJrb3JhbmdlIikgKw0KICBsYWJzKHggPSAiQmVuZWZpdHMiLCB5ID0gIkZyZXF1ZW5jeSIsIHRpdGxlID0gIkhpc3RvZ3JhbSDFm3dpYWRjemXFhC9CZW5lZml0w7N3IGRsYSBzdHJhxbxha8OzdyB3IFNhbiBGcmFuY2lzY28iKSArDQogIGdlb21fdmxpbmUoZGF0YT1zcl9tZWRpYW5hX2xpbmllX2JlbmVmaXRzLGFlcyh4aW50ZXJjZXB0ID0gd2FydG/Fm8SHLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gbmF6d2EsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbmF6d2EpLGxpbmV3aWR0aD0xLGNvbG9yPSJibGFjayIpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGZhY2V0X2dyaWQoLiB+IFN0YXR1cykNCg0KYGBgDQoNCk1vxbxlbXkgemF1d2HFvHnEhywgxbxlIHd5ZGF0a2kgYnVkxbxldG93ZSBuYSBwxYJhY8SZIHBvZHN0YXdvd8SFLCBwxYJhY8SZIHphIG5hZGdvZHppbnkgaSBiZW5lZml0eSByw7PFvG5pxIUgc2nEmSB3IHphbGXFvG5vxZtjaSBvZCB0ZWdvIGN6eSBrdG/FmyBwcmFjdWplIG5hIHBlxYJlbiBldGF0IChGVCkgY3p5IG5hIHDDs8WCIGV0YXR1IChTVCkuIFpnb2RuaWUgeiBvY3pla2l3YW5pZW0sIHdzenlzdGtpZSB0ZSB3YXJ0b8WbY2kgc8SFIG5pxbxzemUgZGxhIHN0cmHFvGFrw7N3LCBrdMOzcnp5IG5pZSBwcmFjdWrEhSBuYSBwZcWCZW4gZXRhdC4NCg0KLSBDenkgdyB0eW0gemVzdGF3aWUgZGFueWNoIGlzdG5pZWrEhSBkb3dvZHkgbmEgZHlza3J5bWluYWNqxJkgcMWCYWNvd8SFIHplIHd6Z2zEmWR1IG5hIHDFgmXEhz8NClcgdHltIHplc3Rhd2llIGRhbnljaCBuaWUgbWFteSBpbmZvcm1hY2ppIG5hIHRlbWF0IHDFgmNpLCB3acSZYyBuaWUgamVzdGXFm215IHcgc3RhbmllIHRlZ28gb2JsaWN6ecSHLg0KDQoNCg0KT3N6YWNvd2FuaWUgZ8SZc3RvxZtjaSByb3prxYJhZHUgd3luYWdyb2R6ZcWEIHN0cmHFvGFrw7N3IHcgU2FuIEZyYW5jaXNjbzoNCmBgYHtyfQ0KIyBLZXJuZWwgZGVuc2l0eSBlc3RpbWF0aW9uDQpkIDwtIGRlbnNpdHkoc2FsYXJpZXNGRlNhbkYkVG90YWxQYXksDQogICAgICAgICAgICAga2VybmVsID0gImdhdXNzaWFuIikNCg0KIyBLZXJuZWwgZGVuc2l0eSBwbG90DQpwbG90KGQsIGx3ZCA9IDIsIG1haW4gPSAiR2F1c3NpYW4ga2VybmVsIikNCmBgYA0KV3licmHFgmVtIGRvbXnFm2xuZSwgZ2F1c3Nvd3NraWUgasSFZHJvLCBrdMOzcmUgdGFrIGphayBiecWCbyB3c3BvbW5pYW5lLCB6YXp3eWN6YWogamVzdCBuYWpsZXBzemUuDQpNYW15IHR1IGRvIGN6eW5pZW5pYSB6IHJvemvFgmFkZW0gYmltb2RhbG55bSwga3TDs3J5IG5pZWpha28gd3lqYcWbbmlhIG5hbSB6YXV3YcW8b255IHdjemXFm25pZWogZmFrdCwgxbxlIG1lZGlhbmEgamVzdCB3ecW8c3phIG9kIMWbcmVkbmllai4gUG9wcnpleiBpc3RvdG7EhSBsaWN6YsSZIChuaWVqYWtvIGRydWfEhSBtb2TEmSkgc3RyYcW8YWvDs3cgemFyYWJpYWrEhWN5Y2ggbWHFgmUgcGllbmnEhWR6ZSA8MDs1MCAwMDAgVVNEPiwga3TDs3J6eSB6YW5pxbxhasSFIHpuYWN6xIVjbyDFm3JlZG5pxIUgd3luYWdyb2R6ZcWELCBhIG5pZSBqZXN0IGljaCB3eXN0YXJjemFqxIVjbyBkdcW8byDFvGVieSBpc3RvdG5pZSB6YW5pxbx5xIcgbWVkaWFuxJkuDQo=