Analiza danych projekt zespołowy
W ramach zaliczenia przedmiotu Analiza danych na kierunku Analityka
Gospodarcza II zostaliśmy zobligowani do wykonania specjalnego projektu
wybranego przez prowadzącego.
Wylosowanym zestawem danych okazał się zbiór dotyczący
supermarketów.
Niniejszy projekt składa się z sześciu części tematycznych
odpowiednio wyróżnionych nagłówkami stylu H2.
Tu będzie spis treści
Wprowadzenie
W dynamicznym świecie handlu detalicznego, rozwój supermarketów w
najbardziej zaludnionych miastach osiąga coraz to nowe szczyty
konkurencyjności. W kontekście tego zjawiska, kluczowym elementem staje
się dogłębna analiza danych sprzedażowych różnych supermarketów.
Niniejszy projekt ma na celu zbadanie i zrozumienie trendów
sprzedażowych w trzech oddziałach jedenej firmy będącej supermarketem,
reprezentujących różnorodne lokalizacje i demografie klientów.
Dane, na których opiera się ta analiza, zostały zebrane w ciągu
trzech miesięcy, od stycznia do marca 2019 roku, i zawierają szczegółowe
informacje na temat każdej transakcji. Fundamentami wykonanej w
projekcie analizy są takie zmienne jak: numer identyfikacyjny faktury
(Invoice ID), oddział, w którym dokonano zakupu (Branch), lokalizacja
supermarketu (City), typ klienta (Customer type), płeć (Gender), linia
produktów (Product line), cena jednostkowa (Unit price), ilość
zakupionych produktów (Quantity), opłata podatkowa (Tax), całkowita cena
zakupu (Total), data (Date) i czas transakcji (Time), metoda płatności
(Payment), koszt sprzedanych towarów (COGS), procentowa marża brutto
(Gross margin percentage), dochód brutto (Gross income) oraz ocena
klienta (Rating).
W kontekście rosnącej konkurencji na rynku, zrozumienie tych danych
może okazać się kluczowe dla formułowania strategii biznesowych i w
nadążaniu za dynamicznymi zmianami. Analizując, jak różne czynniki,
takie jak lokalizacja, typ klienta czy wybór produktów, wpływają na
wyniki sprzedaży, możemy lepiej zrozumieć potrzeby i preferencje
konsumentów. To z kolei może prowadzić do bardziej celowych i
skutecznych decyzji biznesowych, co jest niezwykle istotne w świecie,
gdzie klient i jego doświadczenia stanowią o sukcesie firmy.
Celem tego projektu jest nie tylko zrozumienie obecnych trendów, ale
także identyfikacja potencjalnych obszarów do rozwoju i innowacji w
branży supermarketów. Przez skupienie się na danych historycznych,
projekt ten ma na celu dostarczenie wartościowych wskazówek dla
przyszłych decyzji strategicznych i operacyjnych w branży
supermarketów.
Data Cleansing & Data Wrangling - czyli czyścimy i ujednolicamy
dane!
Pierwszy etap merytorycznej pracy z danymi, w żargonie analityków
danych określany jako “Data Cleansing” oraz “Data Wrangling”, to nic
innego jak czyszczenie i ujednolicanie danych na potrzeby niniejszego
projektu.
Rozpakowanie danych w programie RStudio i wyświetlenie ich
zawartości
Zanim jednak wdrożone zostaną takie prace, należy wgrać dane do
programu R i zerknąć na tablicę. W tym miejscu zweryfikowaliśmy typy
wszystkich zmiennych.
dane <- read.csv("Biedronki.csv")
Na potrzeby prac należy zainstalować niezbędne biblioteki, które
towarzyszyć będą na etapie czyszcznia danych.
install.packages("tidyverse")
install.packages("dlookr")
install.packages("editrules")
install.packages("VIM")
install.packages("deducorrect")
install.packages("ISLR")
library(tidyverse)
library(dlookr)
library(editrules)
library(VIM)
library(deducorrect)
library(ISLR)
Przechodząc do czyszczenia,cały proces rozpoczeliśmy od sprawdzenia,
ile przypadków danych jest kompletnych, czyli czy występując NA. Jednak
braki danych to nie wszystko. Postanowiliśmy sprawdzić, czy w zbiorze
danych znajdują się jakieś wartości specjalne. Do tego posłużyła
specjalna funkcja. Na wypadek, gdyby pojawiły się jakieś wartości
specjalne, zdecydowaliśmy się, że przypiszemy im wartości NA. W tym celu
wykorzystaliśmy pętlę. Tak przeprowadzone operacje pozwalają wydrukować
statystyki opisowe dla zmiennych.
sum(complete.cases(dane))
is.special <- function(x){
if (is.numeric(x)) !is.finite(x) else is.na(x)}
sapply(dane, is.special)
for (n in colnames(dane)){
is.na(dane[[n]]) <- is.special(dane[[n]])
}
summary(dane)
Powyższy kod pozwala stwierdzić, że w zbiorze danych nie ma NA.
Jednak postanowiliśmy zagłębić się jeszcze w słuszność tego twierdzenia.
Ostatecznym potwierdzeniem będzie dla nas wizualizacja obecności
ewentualnych NA. W tym celu pobraliśmy specjalny pakiet “naniar”.
install.packages("naniar")
library(naniar)
vis_miss(dane)
Co do braków danych mamy już absolutną pewność. Dzięki temu możemy
pójść dalej i spojrzeć na to jak ukształtowują się zmienne jakościowe
(liczbowe). W tym celu wykorzystamy popularną metodę wizualizacji -
wykresy pudełkowe.Taki zabieg na danych pozwoli na wyselekcjonowanie
tych zmiennych ciągłych, które zawierają wartości odstające.
boxplot(dane$Unit.price)
boxplot(dane$Tax.5.) #zawiera wartości odstające
boxplot(dane$Total) #zawiera wartości odstające
boxplot(dane$cogs) #zawiera wartości odstające
boxplot(dane$gross.margin.percentage)
boxplot(dane$gross.income) #zawiera wartości odstające
boxplot(dane$Rating)
Wizualizacja danych - spójrzmy jakie mamy informacje!
Po tym jak przeprowadziliśmy procedurę czyszczenia i ujednolicania
naszych wejściowych danych, możemy skupić się na ich konkretnej
wizualizacji. Postanowiliśmy za pomocą wykresu kolumnowego przedstawić
stosunek produktów do ceny z podatkiem. Zwizuowaliśmy również stosunek
miasta do ceny zawierającej podatek oraz stosunek miasta do satysfakcji
klienta. Jednak zacznijmy od początku.
install.packages('ggplot2')
library('ggplot2')
ggplot(dane, aes(x = dane$Product.line, y = dane$Total)) +
geom_col(fill="lightpink2") +
xlab("Kryteria produktów") +
ylab("Cena wraz z podatkiem [$]")
Intepretacja: Analizując kryteria produktów oraz ceny, które mają już
wliczony podatek, to w sklepie dyskontowym Biedronka najdroższe produkty
względem cenowym znajdują się w jedzeniach i napojach, co uważamy, że
jest zjawiskiem negatywnym, ponieważ podatki stanowią większość ceny
przez podatek cukrowy.
Skupimy się teraz na stosunku miasta do ceny z obowiązującym
podatkiem.
ggplot(dane, aes(x = dane$City, y = dane$Total)) +
geom_col(fill="green4")+
xlab("Miasto") +
ylab("Cena wraz z podatkiem [$]")
Interpretacja: Biorąc pod uwagę miasta oraz cena z wliczony z
podatkiem, można wysunąć pewne wnioski, a mianowicie miasto Naypyitaw
charakteryzuje się najdroższymi produktami, z kolei dwa pozostałe miasta
pod nazwami: Mandalay i Yangon są na tym samym poziomie.
Następnie postanowiliśmy zobrazować relację ceny do satysfakcji
klienta.
ggplot(dane, aes(x = dane$Total, y = dane$Rating)) +
geom_col(size=1, fill="blue4")+
xlab("Cena z podatkiem") +
ylab("Satysfakcja klienta")
Interpretacja: Biorąc pod uwagę stosunek satysfakcji klienta do samej
ceny z wliczonym podatkiem, można wysunąc następujące wnioski.
Największą liczbą ocen charakteryzują się ceny w okolicach 500$, zaś
najmniejszą liczbą ocen ceny równe 1000 dol, bądź wyższe.
Najwyższy czas zatem zbadać kształtowanie się ilości. Zaczęliśmy od
ilości ocen satysfakcji klienta.
ggplot(dane, aes(dane$Rating)) +
geom_bar(fill="purple4")+
xlab("Satysfakcja klienta") +
ylab("Ilość ocen")
Interpretacja: Analizując poniższy wykres można stwierdzić, iż
największą ilością ocen satysfakcji klienta zyskała ocena 6. Jest to
powyżej połowy, co jest pozytywnym wynikiem dla sklepu dyskontowego.
Warto spojrzeć teraz na liczbę wykonanych zakupów w poszczególnych
miastach.
ggplot(dane, aes(dane$City)) +
geom_bar(fill="lightgreen")+
xlab("Miasto") +
ylab("Ilość faktur")
Interpretacja: Powyższy wykres przedstawia ilość wykonanych zakupów w
oparciu o trzy miasta. Największą liczbą dokonanych zakupów
charakteryzuje się miasto Yangon, zaś najmniejszą Naypyitaw.
Zobrazujemy teraz liczbę płatności ze względu na sposób ich
dokonania.
ggplot(dane, aes(dane$Payment)) +
geom_bar(fill="lightpink")+
xlab("Rodzaj płatności") +
ylab("Ilość płatności")
Intepretacja: Wykres przedstawia ilość płatności z podziałem na
rodzaje. Największym zainteresowaniem cieszy się tradycyjna płatność,
czyli płatność gotówką oraz elektronicznym portfelem, natomiast
najmniejszym karta kredytowa jest to duże zaskoczenie, patrząc na to, że
coraz więcej społeczeństwa odbiega od używania gotówki.
Ostatnią tego typu graficzną prezentacją jest stosunek ilości
produktów przynależących do określonych grup.
ggplot(dane, aes(dane$Product.line)) +
geom_bar(fill="orange2")+
xlab("Rodzaj produktu") +
ylab("Ilość")
Intepretacja: Wykres kolumnowy przedstawia ilość produktów, które
posiada każdy z rodzai produktów. Najwięcej produktów należy do grupy
pod nazwą:modowe akcesoria, zaś najmniejszą: zdrowie i uroda.
Następnie postanowiliśmy wykonać wizualizację rozkładów
poszczególnych zmiennych ilościowych. Zaczęliśmy od przedstawienia za
pomocą histogramu relacji ilości produktów zakupionych przez
klientów.
ggplot(dane, aes(dane$Quantity)) +
geom_histogram(fill="lightblue")+
xlab("Ilość produktów") +
ylab("Potwórzenia ilości produktów zakupionych przez klientów")
Intepretacja: Wykres przedstawia powtórzenia w kontekście ilości
produktó zakupionych przez klientów sklepu. Największy wynik wynosi 10
produktów, ponieważ powtórzył się on ponad 100 razy. Natomiast
najmniejszą ilością charakteryzuje się ilość 8 produktów, bo powtórzenia
wyniosły tylko ok. 86 powtórzeń.
Następnie zastanowiliśmy się na tym jak wygląda rozkład opłaty
podatkowej.
ggplot(dane, aes(dane$Tax.5.)) +
geom_density(fill = "cornsilk")+
xlab("Opłata podatkowa") +
ylab("Ilość powtórzeń występującej opłaty podatkowej")
Intepretacja: Wykres przedstawia rozkład opłat podatkowych w
wysokości 5% dla klienta dokonującego zakupy można stwierdzić, że
największą ilościa charakteryzuje się podatek o wysokości ok. 6-7
dolara.
Wizualizacji poddaliśmy również liczbę kupionych produktów w danej
cenie w różnych oddziałach supermarketów.
ggplot(dane, aes(dane$Unit.price)) +
geom_histogram(binwidth = 4, center = 2.5, fill = "green3") +
facet_wrap(vars(dane$Branch)) +
xlab("Cena każdego produktu [$]") +
ylab("Ilość powtórzeń")
Intepretacja: Wizualizacja rozkładów z podziałem na oddział
supercentrum pokazuje nam ile razy kupiono produkt za daną cenę.
Największymi wynikami wyróżnia się supercentrum C, czyli miejscowość
Naypyitaw, ponieważ posiada największą ilość powtórzeń ceny 100 dolara w
porównaniu z innymi oddziałami.
Zbadaliśmy również jak wygląda rozkład ocen satysfakcji z podziałem
na płeć.
ggplot(dane, aes(dane$Rating)) +
geom_histogram(binwidth = 4, center = 2.5, fill = "pink") +
facet_wrap(vars(dane$Gender)) +
xlab("Ocena satysfakcji") +
ylab("Ilość powtórzeń")
Intepretacja: Wizualizacja rozkładów obrazuje nam ilość ocen
satysfakcji w oparciu na podział względem płci. Mężczyźni wyróżniają się
na tle kobiet, ponieważ najczęściej z większą ilością powtórzeń
wybierali oceny w przedziale od 5.0-8.0. Kobiety również skłaniały się
do tego samego przedziału, jednakże możemy zauważyć, że sklep Biedronka
posiada więcej klientów płci męskiej, niż płci żeńskiej.
Za ciekawe uznaliśmy również przedstawienie za pomocą wykresu, cen z
podatkiem w poszczególnych miesiącach. W tym celu musieliśmy wgrać
niezbędne biblioteki.
install.packages("colorspace")
library(colorspace)
library(ggforce)
library(ggridges)
dane$month <- format( as.Date (dane$Date, format=" %m/%d/%Y ")," %m ")
ggplot(dane, aes(x = dane$month, y = dane$gross.income)) +
geom_point(size = 0.75, fill="black") +
xlab("Miesiąc") +
ylab("Dochód brutto")
Intepretacja: analizując rozkład, który opiera się podziałem na
miesiące względem dochodu brutto, można stwierdzić iż styczeń był
najbardziej dochodowym miesiącem, jeśli chodzi o ceny posiadające wysoki
zysk brutto. Natomiast najniższy dochód brutto osiągnięty przez filie
supermarketu został osiągnięty w marcu.
Analiza opisowa - z czym w końcu mamy do czynienia?
Gdy już nasz zbiór danych nie skrywa wizualnych tajemnic, możemy
ruszać do pracy z analizą opisową. Zaczynamy od wyznaczenia zakresu cen
z wliczonym podatkiem oraz prac z tymi informacjami.
range(dane$Total) #znajdujemy zakres cen z wliczonym podatkiem
max(dane$Total)-min(dane$Total)
Intepretacja: Biedronka charakteryzuje się minimalną (10.68) oraz
maksymalną ceną z podatkiem (1042.65), co pozwala stwierdzić, że sklep
dyskontowy charakteryzuje się zróżnicowanym poziomem cen w produktach,
które posiada. Z przedstawionych powyżej operacji wiadomym jest również,
że różnica pomiędzy maksymalną, a minimalną ceną (z podatkiem) wynosi
1031.97 dolara.
Przejdziemy teraz do dalszych prac.
limits<-cut(dane$Total,seq(0,1100,by=100))
table1<-table(limits)
transform(table1,Rel_Freq=prop.table(Freq),Cum_Freq=cumsum(Freq))
# Przedstawmy powyższe na wykresie
hist(dane$Total,prob=TRUE,breaks=seq(0,1100,by=100),main="Total",sub="w $")
lines(density(dane$Total),col=6)
install.packages("classInt")
library(classInt)
tab1<-classIntervals(dane$Total,n=11,style="fixed",fixedBreaks=seq(0,1100,by=100))
tab1
jenks.tests(tab1)
Zajmiemy się teraz statystykami opisowymi dla zmian całkowitej
sprzedaży wraz z podatkiem. Oprócz obecnych pakietów, potrzebny będzie
jeszcze inny: “kableExtra”.
library(kableExtra)
dane%>%
group_by(Gender)%>%
summarize('Suma sprzedaży'=sum(dane$Total),
'Średnia sprzedaż'=mean(dane$Total),
'Mediana sprzedaży'=median(dane$Total),
'Minimalna sprzedaż'=min(dane$Total),
'Maksymalna sprzedaż'=max(dane$Total),
'Odchylenie standardowe'=sd(dane$Total))%>%
arrange(desc('Suma sprzedaży')) %>%
kbl()%>%
kable_styling(bootstrap_options = c("striped", "hover","responsive"),position="center")
(Interpretacja wyników).Teraz zajmiemy się spojrzeniem na statystyki
dotyczące oceny satysfakcji klienta.
dane%>%
group_by(City)%>%
summarize('Suma ocen satysfakcji klientów'=sum(dane$Rating),
'Średnia ocen satysfakcji'=mean(dane$Rating),
'Mediana ocen satysfakcji'=median(dane$Rating),
'Minimalna ocena satysfakcji'=min(dane$Rating),
'Maksymalna ocena satysfakcji'=max(dane$Rating),
'Odchylenie standardowe'=sd(dane$Rating))%>%
arrange(desc('Suma ocen satysfakcji')) %>%
kbl()%>%
kable_styling(bootstrap_options = c("striped", "hover","responsive"),position="center")
(Interpretacja wyników).Kolejne statystyki dotyczą natomiast cen
produktów
dane%>%
group_by(Product.line)%>%
summarize('Suma cen produktów'=sum(dane$Rating),
'Średnia cen produktów'=mean(dane$Rating),
'Mediana cen produktów'=median(dane$Rating),
'Minimalna cen produktów'=min(dane$Rating),
'Maksymalna cena produktów'=max(dane$Rating),
'Odchylenie standardowe'=sd(dane$Rating))%>%
arrange(desc('Suma cen produktów')) %>%
kbl()%>%
kable_styling(bootstrap_options = c("striped", "hover","responsive"),position="center")
Wnioskowanie - warto sprawdzić pytania badawcze!
Hipotezy, które postawiliśmy w niniejszym projekcie na potrzeby
weryfikacji wybranych zjawisk.
Prace w tym zakresie rozpoczynamy od pobrania niezbędnych bibliotek
do R, popularnych z zakresu testowania statystycznego.
install.packages("ggstatsplot")
library(ggstatsplot)
Pierwszy wariant hipotez: H0: Kobiety kupują więcej produktów z
kategorii: zdrowie i uroda niż mężczyźni; H1: Kobiety nie kupują więcej
produktów z kategorii: zdrowie i uroda niż mężczyźni.
data=dane
x=dane$Gender
y=dane$Product.line
ggpiestats(x=Gender,
y=Product.line,
data=dane)
Wartość p (p-value) na poziomie 0,33 pokazuje, że nie ma podstaw do
odrzucenia hipotezy zerowej. Oznacza to, że kobiety rzeczywiście kupują
więcej produktów z kategorii produktów “zdrowie i uroda”.
Drugi wariant hipotez: H0: Mężczyźni kupują więcej produktów z
kategorii: elektronika niż kobiety; H1: Mężczyźni nie kupują więcej
produktów z kategorii: elektronika niż kobiety.
data=dane
x=dane$Gender
y=dane$Product.line
ggpiestats(x=Gender,
y=Product.line,
data=dane)
Wartość p (p-value) na poziomie 0,33 pokazuje, że nie ma podstaw do
odrzucenia hipotezy zerowej. Oznacza to, że mężczyźni kupują więcej
produktów z kategorii: elektronika niż kobiety.
Trzeci wariant hipotez: H0: Klienci posiadający kartę lojalnościową
wydają mniej od osób jej nieposiadających; H1: Klienci posiadający kartę
lojalnościową wydają więcej od osób jej nieposiadających.
data=dane
x=dane$Customer.type
y=dane$Total
ggbetweenstats(x=Customer.type,
y=Total,
data=dane)
Wynik wartości p (p-value) na poziomie 0,53 pokazuje, że nie ma
podstaw do odrzucenia hipotezy zerowej. Oznacza to, że klienci
posiadający kartę lojalnościową wydaj mniej od osób jej
nieposiadających.
Czwarty wariant hipotez: H0: Mężczyźni częściej od kobiet płacą za
zakupy eportfelem; H1: Mężczyźni rzadziej od kobiet płacą za zakupy
eportfelem.
data=dane
x=dane$Gender
y=dane$Payment
ggpiestats(x=Gender,
y=Payment,
data=dane)
Wynik wartości p (p-value) na poziomie 0,23 pokazuje, że nie ma
podstaw do odrzucenia hipotezy zerowej. Oznacza to, że mężczyźni
częściej od kobiet płacą za zakupy eportfelem.
Podsumowanie i wnioski końcowe - co wiemy z całej pracy?
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIEFuYWxpemEgZGFueWNoIHByb2pla3QgemVzcG/Fgm93eSANCg0KVyByYW1hY2ggemFsaWN6ZW5pYSBwcnplZG1pb3R1IEFuYWxpemEgZGFueWNoIG5hIGtpZXJ1bmt1IEFuYWxpdHlrYSBHb3Nwb2RhcmN6YSBJSSANCnpvc3RhbGnFm215IHpvYmxpZ293YW5pIGRvIHd5a29uYW5pYSBzcGVjamFsbmVnbyBwcm9qZWt0dSB3eWJyYW5lZ28gcHJ6ZXogcHJvd2FkesSFY2Vnby4gIA0KV3lsb3Nvd2FueW0gemVzdGF3ZW0gZGFueWNoIG9rYXphxYIgc2nEmSB6YmnDs3IgZG90eWN6xIVjeSBzdXBlcm1hcmtldMOzdy4gDQoNCk5pbmllanN6eSBwcm9qZWt0IHNrxYJhZGEgc2nEmSB6IHN6ZcWbY2l1IGN6xJnFm2NpIHRlbWF0eWN6bnljaCBvZHBvd2llZG5pbyB3eXLDs8W8bmlvbnljaCANCm5hZ8WCw7N3a2FtaSBzdHlsdSBIMi4gDQoNClR1IGLEmWR6aWUgc3BpcyB0cmXFm2NpIA0KDQojIyBXcHJvd2FkemVuaWUgDQoNClcgZHluYW1pY3pueW0gxZt3aWVjaWUgaGFuZGx1IGRldGFsaWN6bmVnbywgcm96d8OzaiBzdXBlcm1hcmtldMOzdyB3IG5hamJhcmR6aWVqIHphbHVkbmlvbnljaCBtaWFzdGFjaCBvc2nEhWdhIGNvcmF6IHRvIG5vd2Ugc3pjenl0eSBrb25rdXJlbmN5am5vxZtjaS4gVyBrb250ZWvFm2NpZSB0ZWdvIHpqYXdpc2thLCBrbHVjem93eW0gZWxlbWVudGVtIHN0YWplIHNpxJkgZG9nxYLEmWJuYSBhbmFsaXphIGRhbnljaCBzcHJ6ZWRhxbxvd3ljaCANCnLDs8W8bnljaCBzdXBlcm1hcmtldMOzdy4gTmluaWVqc3p5IHByb2pla3QgbWEgbmEgY2VsdSB6YmFkYW5pZSBpIHpyb3p1bWllbmllIHRyZW5kw7N3IHNwcnplZGHFvG93eWNoIHcgdHJ6ZWNoIG9kZHppYcWCYWNoIGplZGVuZWogZmlybXkgYsSZZMSFY2VqIHN1cGVybWFya2V0ZW0sIHJlcHJlemVudHVqxIVjeWNoIHLDs8W8bm9yb2RuZSBsb2thbGl6YWNqZSBpIGRlbW9ncmFmaWUga2xpZW50w7N3Lg0KDQpEYW5lLCBuYSBrdMOzcnljaCBvcGllcmEgc2nEmSB0YSBhbmFsaXphLCB6b3N0YcWCeSB6ZWJyYW5lIHcgY2nEhWd1IHRyemVjaCBtaWVzacSZY3ksIG9kIHN0eWN6bmlhIGRvIG1hcmNhIDIwMTkgcm9rdSwgaSB6YXdpZXJhasSFIHN6Y3plZ8OzxYJvd2UgaW5mb3JtYWNqZSBuYSB0ZW1hdCBrYcW8ZGVqIHRyYW5zYWtjamkuIEZ1bmRhbWVudGFtaSB3eWtvbmFuZWogdyBwcm9qZWtjaWUgYW5hbGl6eSBzxIUgdGFraWUgem1pZW5uZSBqYWs6IG51bWVyIGlkZW50eWZpa2FjeWpueSBmYWt0dXJ5IChJbnZvaWNlIElEKSwgb2RkemlhxYIsIHcga3TDs3J5bSBkb2tvbmFubyB6YWt1cHUgKEJyYW5jaCksIGxva2FsaXphY2phIHN1cGVybWFya2V0dSAoQ2l0eSksIHR5cCBrbGllbnRhIChDdXN0b21lciB0eXBlKSwgcMWCZcSHIChHZW5kZXIpLCBsaW5pYSBwcm9kdWt0w7N3IChQcm9kdWN0IGxpbmUpLCBjZW5hIGplZG5vc3Rrb3dhIChVbml0IHByaWNlKSwgaWxvxZvEhyB6YWt1cGlvbnljaCBwcm9kdWt0w7N3IChRdWFudGl0eSksIG9wxYJhdGEgcG9kYXRrb3dhIChUYXgpLCBjYcWCa293aXRhIGNlbmEgemFrdXB1IChUb3RhbCksIGRhdGEgKERhdGUpIGkgY3phcyB0cmFuc2FrY2ppIChUaW1lKSwgbWV0b2RhIHDFgmF0bm/Fm2NpIChQYXltZW50KSwga29zenQgc3ByemVkYW55Y2ggdG93YXLDs3cgKENPR1MpLCBwcm9jZW50b3dhIG1hcsW8YSBicnV0dG8gKEdyb3NzIG1hcmdpbiBwZXJjZW50YWdlKSwgZG9jaMOzZCBicnV0dG8gKEdyb3NzIGluY29tZSkgb3JheiBvY2VuYSBrbGllbnRhIChSYXRpbmcpLg0KDQpXIGtvbnRla8WbY2llIHJvc27EhWNlaiBrb25rdXJlbmNqaSBuYSByeW5rdSwgenJvenVtaWVuaWUgdHljaCBkYW55Y2ggbW/FvGUgb2themHEhyBzacSZIGtsdWN6b3dlIGRsYSBmb3JtdcWCb3dhbmlhIHN0cmF0ZWdpaSBiaXpuZXNvd3ljaCBpIHcgbmFkxIXFvGFuaXUgemEgZHluYW1pY3pueW1pIHptaWFuYW1pLiBBbmFsaXp1asSFYywgamFrIHLDs8W8bmUgY3p5bm5pa2ksIHRha2llIGphayBsb2thbGl6YWNqYSwgdHlwIGtsaWVudGEgY3p5IHd5YsOzciBwcm9kdWt0w7N3LCB3cMWCeXdhasSFIG5hIHd5bmlraSBzcHJ6ZWRhxbx5LCBtb8W8ZW15IGxlcGllaiB6cm96dW1pZcSHIHBvdHJ6ZWJ5IGkgcHJlZmVyZW5jamUga29uc3VtZW50w7N3LiBUbyB6IGtvbGVpIG1vxbxlIHByb3dhZHppxIcgZG8gYmFyZHppZWogY2Vsb3d5Y2ggaSBza3V0ZWN6bnljaCBkZWN5emppIGJpem5lc293eWNoLCBjbyBqZXN0IG5pZXp3eWtsZSBpc3RvdG5lIHcgxZt3aWVjaWUsIGdkemllIGtsaWVudCBpIGplZ28gZG/Fm3dpYWRjemVuaWEgc3Rhbm93acSFIG8gc3VrY2VzaWUgZmlybXkuDQoNCkNlbGVtIHRlZ28gcHJvamVrdHUgamVzdCBuaWUgdHlsa28genJvenVtaWVuaWUgb2JlY255Y2ggdHJlbmTDs3csIGFsZSB0YWvFvGUgaWRlbnR5ZmlrYWNqYSBwb3RlbmNqYWxueWNoIG9ic3phcsOzdyBkbyByb3p3b2p1IGkgaW5ub3dhY2ppIHcgYnJhbsW8eSBzdXBlcm1hcmtldMOzdy4gUHJ6ZXogc2t1cGllbmllIHNpxJkgbmEgZGFueWNoIGhpc3Rvcnljem55Y2gsIHByb2pla3QgdGVuIG1hIG5hIGNlbHUgZG9zdGFyY3plbmllIHdhcnRvxZtjaW93eWNoIHdza2F6w7N3ZWsgZGxhIHByenlzesWCeWNoIGRlY3l6amkgc3RyYXRlZ2ljem55Y2ggaSBvcGVyYWN5am55Y2ggdyBicmFuxbx5IHN1cGVybWFya2V0w7N3Lg0KDQojIyBEYXRhIENsZWFuc2luZyAmIERhdGEgV3JhbmdsaW5nIC0gY3p5bGkgY3p5xZtjaW15IGkgdWplZG5vbGljYW15IGRhbmUhIA0KDQpQaWVyd3N6eSBldGFwIG1lcnl0b3J5Y3puZWogcHJhY3kgeiBkYW55bWksIHcgxbxhcmdvbmllIGFuYWxpdHlrw7N3IGRhbnljaCBva3JlxZtsYW55IGpha28gIkRhdGEgQ2xlYW5zaW5nIiBvcmF6ICJEYXRhIFdyYW5nbGluZyIsIHRvIG5pYyBpbm5lZ28gamFrIGN6eXN6Y3plbmllIGkgdWplZG5vbGljYW5pZSBkYW55Y2ggbmEgcG90cnplYnkgbmluaWVqc3plZ28gcHJvamVrdHUuIA0KDQojIyMgUm96cGFrb3dhbmllIGRhbnljaCB3IHByb2dyYW1pZSBSU3R1ZGlvIGkgd3nFm3dpZXRsZW5pZSBpY2ggemF3YXJ0b8WbY2kNCg0KWmFuaW0gamVkbmFrIHdkcm/FvG9uZSB6b3N0YW7EhSB0YWtpZSBwcmFjZSwgbmFsZcW8eSB3Z3JhxIcgZGFuZSBkbyBwcm9ncmFtdSBSIGkgemVya27EhcSHIG5hIHRhYmxpY8SZLiBXIHR5bSBtaWVqc2N1IA0KendlcnlmaWtvd2FsacWbbXkgdHlweSB3c3p5c3RraWNoIHptaWVubnljaC4gDQoNCmBgYHtyfQ0KZGFuZSA8LSByZWFkLmNzdigiQmllZHJvbmtpLmNzdiIpDQpgYGANCg0KTmEgcG90cnplYnkgcHJhYyBuYWxlxbx5IHphaW5zdGFsb3dhxIcgbmllemLEmWRuZSBiaWJsaW90ZWtpLCBrdMOzcmUgdG93YXJ6eXN6ecSHIGLEmWTEhSBuYSBldGFwaWUgY3p5c3pjem5pYSBkYW55Y2guIA0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQppbnN0YWxsLnBhY2thZ2VzKCJkbG9va3IiKQ0KaW5zdGFsbC5wYWNrYWdlcygiZWRpdHJ1bGVzIikNCmluc3RhbGwucGFja2FnZXMoIlZJTSIpDQppbnN0YWxsLnBhY2thZ2VzKCJkZWR1Y29ycmVjdCIpDQppbnN0YWxsLnBhY2thZ2VzKCJJU0xSIikNCg0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRsb29rcikNCmxpYnJhcnkoZWRpdHJ1bGVzKQ0KbGlicmFyeShWSU0pDQpsaWJyYXJ5KGRlZHVjb3JyZWN0KQ0KbGlicmFyeShJU0xSKSANCmBgYA0KDQpQcnplY2hvZHrEhWMgZG8gY3p5c3pjemVuaWEsY2HFgnkgcHJvY2VzIHJvenBvY3plbGnFm215IG9kIHNwcmF3ZHplbmlhLCBpbGUgcHJ6eXBhZGvDs3cgZGFueWNoIGplc3Qga29tcGxldG55Y2gsIGN6eWxpIGN6eSB3eXN0xJlwdWrEhWMgTkEuIEplZG5hayBicmFraSBkYW55Y2ggdG8gbmllIHdzenlzdGtvLiBQb3N0YW5vd2lsacWbbXkgc3ByYXdkemnEhywgY3p5IHcgemJpb3J6ZSBkYW55Y2ggem5hamR1asSFIHNpxJkgamFraWXFmyB3YXJ0b8WbY2kgc3BlY2phbG5lLiBEbyB0ZWdvIHBvc8WCdcW8ecWCYSBzcGVjamFsbmEgZnVua2NqYS4gTmEgd3lwYWRlaywgZ2R5YnkgcG9qYXdpxYJ5IHNpxJkgamFraWXFmyB3YXJ0b8WbY2kgc3BlY2phbG5lLCB6ZGVjeWRvd2FsacWbbXkgc2nEmSwgxbxlIHByenlwaXN6ZW15IGltIHdhcnRvxZtjaSBOQS4gVyB0eW0gY2VsdSB3eWtvcnp5c3RhbGnFm215IHDEmXRsxJkuIFRhayBwcnplcHJvd2Fkem9uZSBvcGVyYWNqZSBwb3p3YWxhasSFIHd5ZHJ1a293YcSHIHN0YXR5c3R5a2kgb3Bpc293ZSBkbGEgem1pZW5ueWNoLiANCiANCmBgYHtyfQ0Kc3VtKGNvbXBsZXRlLmNhc2VzKGRhbmUpKQ0KDQppcy5zcGVjaWFsIDwtIGZ1bmN0aW9uKHgpew0KICBpZiAoaXMubnVtZXJpYyh4KSkgIWlzLmZpbml0ZSh4KSBlbHNlIGlzLm5hKHgpfQ0Kc2FwcGx5KGRhbmUsIGlzLnNwZWNpYWwpDQoNCmZvciAobiBpbiBjb2xuYW1lcyhkYW5lKSl7DQogIGlzLm5hKGRhbmVbW25dXSkgPC0gaXMuc3BlY2lhbChkYW5lW1tuXV0pDQp9DQpzdW1tYXJ5KGRhbmUpDQpgYGANCg0KUG93ecW8c3p5IGtvZCBwb3p3YWxhIHN0d2llcmR6acSHLCDFvGUgdyB6YmlvcnplIGRhbnljaCBuaWUgbWEgTkEuIEplZG5hayBwb3N0YW5vd2lsacWbbXkgemFnxYLEmWJpxIcgc2nEmSBqZXN6Y3plIHcgc8WCdXN6bm/Fm8SHIHRlZ28gdHdpZXJkemVuaWEuIE9zdGF0ZWN6bnltIHBvdHdpZXJkemVuaWVtIGLEmWR6aWUgZGxhIG5hcyB3aXp1YWxpemFjamEgb2JlY25vxZtjaSBld2VudHVhbG55Y2ggTkEuIFcgdHltIGNlbHUgcG9icmFsacWbbXkgc3BlY2phbG55IHBha2lldCAibmFuaWFyIi4gDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygibmFuaWFyIikNCmxpYnJhcnkobmFuaWFyKQ0KdmlzX21pc3MoZGFuZSkNCmBgYA0KDQpDbyBkbyBicmFrw7N3IGRhbnljaCBtYW15IGp1xbwgYWJzb2x1dG7EhSBwZXdub8WbxIcuIER6acSZa2kgdGVtdSBtb8W8ZW15IHDDs2rFm8SHIGRhbGVqIGkgc3BvanJ6ZcSHIG5hIHRvIGphayB1a3N6dGHFgnRvd3VqxIUgc2nEmSB6bWllbm5lIGpha2/Fm2Npb3dlIChsaWN6Ym93ZSkuIFcgdHltIGNlbHUgd3lrb3J6eXN0YW15IHBvcHVsYXJuxIUgbWV0b2TEmSB3aXp1YWxpemFjamkgLSB3eWtyZXN5IHB1ZGXFgmtvd2UuVGFraSB6YWJpZWcgbmEgZGFueWNoIHBvendvbGkgbmEgd3lzZWxla2Nqb25vd2FuaWUgdHljaCB6bWllbm55Y2ggY2nEhWfFgnljaCwga3TDs3JlIHphd2llcmFqxIUgd2FydG/Fm2NpIG9kc3RhasSFY2UuIA0KDQpgYGB7cn0NCmJveHBsb3QoZGFuZSRVbml0LnByaWNlKQ0KYm94cGxvdChkYW5lJFRheC41LikgI3phd2llcmEgd2FydG/Fm2NpIG9kc3RhasSFY2UNCmJveHBsb3QoZGFuZSRUb3RhbCkgI3phd2llcmEgd2FydG/Fm2NpIG9kc3RhasSFY2UgDQpib3hwbG90KGRhbmUkY29ncykgI3phd2llcmEgd2FydG/Fm2NpIG9kc3RhasSFY2UNCmJveHBsb3QoZGFuZSRncm9zcy5tYXJnaW4ucGVyY2VudGFnZSkgDQpib3hwbG90KGRhbmUkZ3Jvc3MuaW5jb21lKSAjemF3aWVyYSB3YXJ0b8WbY2kgb2RzdGFqxIVjZQ0KYm94cGxvdChkYW5lJFJhdGluZykNCmBgYA0KDQojIyBXaXp1YWxpemFjamEgZGFueWNoIC0gc3DDs2pyem15IGpha2llIG1hbXkgaW5mb3JtYWNqZSEgDQoNClBvIHR5bSBqYWsgcHJ6ZXByb3dhZHppbGnFm215IHByb2NlZHVyxJkgY3p5c3pjemVuaWEgaSB1amVkbm9saWNhbmlhIG5hc3p5Y2ggd2VqxZtjaW93eWNoIGRhbnljaCwgbW/FvGVteSBza3VwacSHIHNpxJkgbmEgaWNoIGtvbmtyZXRuZWogd2l6dWFsaXphY2ppLiBQb3N0YW5vd2lsacWbbXkgemEgcG9tb2PEhSB3eWtyZXN1IGtvbHVtbm93ZWdvIHByemVkc3Rhd2nEhyBzdG9zdW5layBwcm9kdWt0w7N3IGRvIGNlbnkgeiBwb2RhdGtpZW0uIFp3aXp1b3dhbGnFm215IHLDs3duaWXFvCBzdG9zdW5layBtaWFzdGEgZG8gY2VueSB6YXdpZXJhasSFY2VqIHBvZGF0ZWsgb3JheiBzdG9zdW5layBtaWFzdGEgZG8gc2F0eXNmYWtjamkga2xpZW50YS4gSmVkbmFrIHphY3puaWpteSBvZCBwb2N6xIV0a3UuIA0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoJ2dncGxvdDInKQ0KbGlicmFyeSgnZ2dwbG90MicpDQpnZ3Bsb3QoZGFuZSwgYWVzKHggPSBkYW5lJFByb2R1Y3QubGluZSwgeSA9IGRhbmUkVG90YWwpKSArDQogIGdlb21fY29sKGZpbGw9ImxpZ2h0cGluazIiKSArIA0KICB4bGFiKCJLcnl0ZXJpYSBwcm9kdWt0w7N3IikgKw0KICB5bGFiKCJDZW5hIHdyYXogeiBwb2RhdGtpZW0gWyRdIikNCmBgYA0KDQpJbnRlcHJldGFjamE6IEFuYWxpenVqxIVjIGtyeXRlcmlhIHByb2R1a3TDs3cgb3JheiBjZW55LCBrdMOzcmUgbWFqxIUganXFvCB3bGljem9ueSBwb2RhdGVrLCB0byB3IHNrbGVwaWUgZHlza29udG93eW0NCkJpZWRyb25rYSBuYWpkcm/FvHN6ZSBwcm9kdWt0eSB3emdsxJlkZW0gY2Vub3d5bSB6bmFqZHVqxIUgc2nEmSB3IGplZHplbmlhY2ggaSBuYXBvamFjaCwgY28gdXdhxbxhbXksIMW8ZSBqZXN0IHpqYXdpc2tpZW0NCm5lZ2F0eXdueW0sIHBvbmlld2HFvCBwb2RhdGtpIHN0YW5vd2nEhSB3acSZa3N6b8WbxIcgY2VueSBwcnpleiBwb2RhdGVrIGN1a3Jvd3kuIA0KDQpTa3VwaW15IHNpxJkgdGVyYXogbmEgc3Rvc3Vua3UgbWlhc3RhIGRvIGNlbnkgeiBvYm93acSFenVqxIVjeW0gcG9kYXRraWVtLiANCg0KYGBge3J9DQpnZ3Bsb3QoZGFuZSwgYWVzKHggPSBkYW5lJENpdHksIHkgPSBkYW5lJFRvdGFsKSkgKw0KICBnZW9tX2NvbChmaWxsPSJncmVlbjQiKSsNCiAgeGxhYigiTWlhc3RvIikgKw0KICB5bGFiKCJDZW5hIHdyYXogeiBwb2RhdGtpZW0gWyRdIikNCmBgYA0KDQpJbnRlcnByZXRhY2phOiBCaW9yxIVjIHBvZCB1d2FnxJkgbWlhc3RhIG9yYXogY2VuYSB6IHdsaWN6b255IHogcG9kYXRraWVtLCBtb8W8bmEgd3lzdW7EhcSHIHBld25lIHduaW9za2ksIGEgbWlhbm93aWNpZSBtaWFzdG8gTmF5cHlpdGF3IGNoYXJha3Rlcnl6dWplIHNpxJkgbmFqZHJvxbxzenltaSBwcm9kdWt0YW1pLCB6IGtvbGVpIGR3YSBwb3pvc3RhxYJlIG1pYXN0YSBwb2QgbmF6d2FtaTogTWFuZGFsYXkgaSBZYW5nb24gc8SFIG5hIHR5bSBzYW15bSBwb3ppb21pZS4NCg0KTmFzdMSZcG5pZSBwb3N0YW5vd2lsacWbbXkgem9icmF6b3dhxIcgcmVsYWNqxJkgY2VueSBkbyBzYXR5c2Zha2NqaSBrbGllbnRhLiANCg0KYGBge3J9DQpnZ3Bsb3QoZGFuZSwgYWVzKHggPSBkYW5lJFRvdGFsLCB5ID0gZGFuZSRSYXRpbmcpKSArDQogIGdlb21fY29sKHNpemU9MSwgZmlsbD0iYmx1ZTQiKSsNCiAgeGxhYigiQ2VuYSB6IHBvZGF0a2llbSIpICsNCiAgeWxhYigiU2F0eXNmYWtjamEga2xpZW50YSIpDQpgYGANCg0KSW50ZXJwcmV0YWNqYTogQmlvcsSFYyBwb2QgdXdhZ8SZIHN0b3N1bmVrIHNhdHlzZmFrY2ppIGtsaWVudGEgZG8gc2FtZWogY2VueSB6IHdsaWN6b255bSBwb2RhdGtpZW0sIG1vxbxuYSB3eXN1bsSFYyBuYXN0xJlwdWrEhWNlIHduaW9za2kuIE5handpxJlrc3rEhSBsaWN6YsSFIG9jZW4gY2hhcmFrdGVyeXp1asSFIHNpxJkgY2VueSB3IG9rb2xpY2FjaCA1MDAkLCB6YcWbIG5ham1uaWVqc3rEhSBsaWN6YsSFIG9jZW4gY2VueSByw7N3bmUgMTAwMCBkb2wsIGLEhWTFuiB3ecW8c3plLg0KDQpOYWp3ecW8c3p5IGN6YXMgemF0ZW0gemJhZGHEhyBrc3p0YcWCdG93YW5pZSBzacSZIGlsb8WbY2kuIFphY3rEmWxpxZtteSBvZCBpbG/Fm2NpIG9jZW4gc2F0eXNmYWtjamkga2xpZW50YS4gDQoNCmBgYHtyfQ0KZ2dwbG90KGRhbmUsIGFlcyhkYW5lJFJhdGluZykpICsNCiAgZ2VvbV9iYXIoZmlsbD0icHVycGxlNCIpKw0KICB4bGFiKCJTYXR5c2Zha2NqYSBrbGllbnRhIikgKw0KICB5bGFiKCJJbG/Fm8SHIG9jZW4iKQ0KYGBgDQoNCkludGVycHJldGFjamE6IEFuYWxpenVqxIVjIHBvbmnFvHN6eSB3eWtyZXMgbW/FvG5hIHN0d2llcmR6acSHLCBpxbwgbmFqd2nEmWtzesSFIGlsb8WbY2nEhSBvY2VuIHNhdHlzZmFrY2ppIGtsaWVudGEgenlza2HFgmEgb2NlbmEgNi4gSmVzdCB0byBwb3d5xbxlaiBwb8WCb3d5LCBjbyBqZXN0IHBvenl0eXdueW0gd3luaWtpZW0gZGxhIHNrbGVwdSBkeXNrb250b3dlZ28uDQoNCldhcnRvIHNwb2pyemXEhyB0ZXJheiBuYSBsaWN6YsSZIHd5a29uYW55Y2ggemFrdXDDs3cgdyBwb3N6Y3plZ8OzbG55Y2ggbWlhc3RhY2guIA0KDQpgYGB7cn0NCmdncGxvdChkYW5lLCBhZXMoZGFuZSRDaXR5KSkgKw0KICBnZW9tX2JhcihmaWxsPSJsaWdodGdyZWVuIikrDQogIHhsYWIoIk1pYXN0byIpICsNCiAgeWxhYigiSWxvxZvEhyBmYWt0dXIiKQ0KYGBgDQoNCkludGVycHJldGFjamE6IFBvd3nFvHN6eSB3eWtyZXMgcHJ6ZWRzdGF3aWEgaWxvxZvEhyB3eWtvbmFueWNoIHpha3Vww7N3IHcgb3BhcmNpdSBvIHRyenkgbWlhc3RhLiBOYWp3acSZa3N6xIUgbGljemLEhSBkb2tvbmFueWNoIHpha3Vww7N3IGNoYXJha3Rlcnl6dWplIHNpxJkgbWlhc3RvIFlhbmdvbiwgemHFmyBuYWptbmllanN6xIUgTmF5cHlpdGF3Lg0KDQpab2JyYXp1amVteSB0ZXJheiBsaWN6YsSZIHDFgmF0bm/Fm2NpIHplIHd6Z2zEmWR1IG5hIHNwb3PDs2IgaWNoIGRva29uYW5pYS4gDQoNCmBgYHtyfQ0KZ2dwbG90KGRhbmUsIGFlcyhkYW5lJFBheW1lbnQpKSArDQogIGdlb21fYmFyKGZpbGw9ImxpZ2h0cGluayIpKw0KICB4bGFiKCJSb2R6YWogcMWCYXRub8WbY2kiKSArDQogIHlsYWIoIklsb8WbxIcgcMWCYXRub8WbY2kiKQ0KYGBgDQoNCkludGVwcmV0YWNqYTogV3lrcmVzIHByemVkc3Rhd2lhIGlsb8WbxIcgcMWCYXRub8WbY2kgeiBwb2R6aWHFgmVtIG5hIHJvZHphamUuIE5handpxJlrc3p5bSB6YWludGVyZXNvd2FuaWVtIGNpZXN6eSBzacSZIA0KdHJhZHljeWpuYSBwxYJhdG5vxZvEhywgY3p5bGkgcMWCYXRub8WbxIcgZ290w7N3a8SFIG9yYXogZWxla3Ryb25pY3pueW0gcG9ydGZlbGVtLCBuYXRvbWlhc3QgbmFqbW5pZWpzenltIGthcnRhIGtyZWR5dG93YQ0KamVzdCB0byBkdcW8ZSB6YXNrb2N6ZW5pZSwgcGF0cnrEhWMgbmEgdG8sIMW8ZSBjb3JheiB3acSZY2VqIHNwb8WCZWN6ZcWEc3R3YSBvZGJpZWdhIG9kIHXFvHl3YW5pYSBnb3TDs3draS4NCg0KT3N0YXRuacSFIHRlZ28gdHlwdSBncmFmaWN6bsSFIHByZXplbnRhY2rEhSBqZXN0IHN0b3N1bmVrIGlsb8WbY2kgcHJvZHVrdMOzdyBwcnp5bmFsZcW8xIVjeWNoIGRvIG9rcmXFm2xvbnljaCBncnVwLiANCg0KYGBge3J9DQpnZ3Bsb3QoZGFuZSwgYWVzKGRhbmUkUHJvZHVjdC5saW5lKSkgKw0KICBnZW9tX2JhcihmaWxsPSJvcmFuZ2UyIikrDQogIHhsYWIoIlJvZHphaiBwcm9kdWt0dSIpICsNCiAgeWxhYigiSWxvxZvEhyIpDQpgYGANCg0KSW50ZXByZXRhY2phOiBXeWtyZXMga29sdW1ub3d5IHByemVkc3Rhd2lhIGlsb8WbxIcgcHJvZHVrdMOzdywga3TDs3JlIHBvc2lhZGEga2HFvGR5IHogcm9kemFpIHByb2R1a3TDs3cuIE5handpxJljZWogcHJvZHVrdMOzdyBuYWxlxbx5IGRvIGdydXB5IHBvZCBuYXp3xIU6bW9kb3dlIGFrY2Vzb3JpYSwgemHFmyBuYWptbmllanN6xIU6IHpkcm93aWUgaSB1cm9kYS4gDQoNCk5hc3TEmXBuaWUgcG9zdGFub3dpbGnFm215IHd5a29uYcSHIHdpenVhbGl6YWNqxJkgcm96a8WCYWTDs3cgcG9zemN6ZWfDs2xueWNoIHptaWVubnljaCBpbG/Fm2Npb3d5Y2guIFphY3rEmWxpxZtteSBvZCBwcnplZHN0YXdpZW5pYSB6YSBwb21vY8SFIGhpc3RvZ3JhbXUgcmVsYWNqaSBpbG/Fm2NpIHByb2R1a3TDs3cgemFrdXBpb255Y2ggcHJ6ZXoga2xpZW50w7N3LiANCg0KYGBge3J9DQpnZ3Bsb3QoZGFuZSwgYWVzKGRhbmUkUXVhbnRpdHkpKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGw9ImxpZ2h0Ymx1ZSIpKw0KICB4bGFiKCJJbG/Fm8SHIHByb2R1a3TDs3ciKSArDQogIHlsYWIoIlBvdHfDs3J6ZW5pYSBpbG/Fm2NpIHByb2R1a3TDs3cgemFrdXBpb255Y2ggcHJ6ZXoga2xpZW50w7N3IikNCmBgYA0KDQpJbnRlcHJldGFjamE6IFd5a3JlcyBwcnplZHN0YXdpYSBwb3d0w7NyemVuaWEgdyBrb250ZWvFm2NpZSBpbG/Fm2NpIHByb2R1a3TDsyB6YWt1cGlvbnljaCBwcnpleiBrbGllbnTDs3cgc2tsZXB1LiBOYWp3acSZa3N6eSB3eW5payB3eW5vc2kgMTAgcHJvZHVrdMOzdywgcG9uaWV3YcW8IHBvd3TDs3J6ecWCIHNpxJkgb24gcG9uYWQgMTAwIHJhenkuIE5hdG9taWFzdCBuYWptbmllanN6xIUgaWxvxZtjacSFIGNoYXJha3Rlcnl6dWplIHNpxJkgaWxvxZvEhyA4IHByb2R1a3TDs3csIGJvIHBvd3TDs3J6ZW5pYSB3eW5pb3PFgnkgdHlsa28gb2suIDg2IHBvd3TDs3J6ZcWELiANCg0KTmFzdMSZcG5pZSB6YXN0YW5vd2lsacWbbXkgc2nEmSBuYSB0eW0gamFrIHd5Z2zEhWRhIHJvemvFgmFkIG9wxYJhdHkgcG9kYXRrb3dlai4gDQoNCmBgYHtyfQ0KZ2dwbG90KGRhbmUsIGFlcyhkYW5lJFRheC41LikpICsNCmdlb21fZGVuc2l0eShmaWxsID0gImNvcm5zaWxrIikrDQogIHhsYWIoIk9wxYJhdGEgcG9kYXRrb3dhIikgKw0KICB5bGFiKCJJbG/Fm8SHIHBvd3TDs3J6ZcWEIHd5c3TEmXB1asSFY2VqIG9wxYJhdHkgcG9kYXRrb3dlaiIpDQpgYGANCg0KSW50ZXByZXRhY2phOiBXeWtyZXMgcHJ6ZWRzdGF3aWEgcm96a8WCYWQgb3DFgmF0IHBvZGF0a293eWNoIHcgd3lzb2tvxZtjaSA1JSBkbGEga2xpZW50YSBkb2tvbnVqxIVjZWdvIHpha3VweSBtb8W8bmEgc3R3aWVyZHppxIcsIMW8ZSBuYWp3acSZa3N6xIUgaWxvxZtjaWEgY2hhcmFrdGVyeXp1amUgc2nEmSBwb2RhdGVrIG8gd3lzb2tvxZtjaSBvay4gNi03IGRvbGFyYS4NCg0KV2l6dWFsaXphY2ppIHBvZGRhbGnFm215IHLDs3duaWXFvCBsaWN6YsSZIGt1cGlvbnljaCBwcm9kdWt0w7N3IHcgZGFuZWogY2VuaWUgdyByw7PFvG55Y2ggb2RkemlhxYJhY2ggc3VwZXJtYXJrZXTDs3cuIA0KDQpgYGB7cn0NCmdncGxvdChkYW5lLCBhZXMoZGFuZSRVbml0LnByaWNlKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDQsIGNlbnRlciA9IDIuNSwgZmlsbCA9ICJncmVlbjMiKSArDQogIGZhY2V0X3dyYXAodmFycyhkYW5lJEJyYW5jaCkpICsNCiAgeGxhYigiQ2VuYSBrYcW8ZGVnbyBwcm9kdWt0dSBbJF0iKSArDQogIHlsYWIoIklsb8WbxIcgcG93dMOzcnplxYQiKQ0KYGBgDQoNCkludGVwcmV0YWNqYTogV2l6dWFsaXphY2phIHJvemvFgmFkw7N3IHogcG9kemlhxYJlbSBuYSBvZGR6aWHFgiBzdXBlcmNlbnRydW0gcG9rYXp1amUgbmFtIGlsZSByYXp5IGt1cGlvbm8gcHJvZHVrdCB6YSBkYW7EhSBjZW7EmS4gTmFqd2nEmWtzenltaSB3eW5pa2FtaSB3eXLDs8W8bmlhIHNpxJkgc3VwZXJjZW50cnVtIEMsIGN6eWxpIG1pZWpzY293b8WbxIcgTmF5cHlpdGF3LCBwb25pZXdhxbwgcG9zaWFkYSBuYWp3acSZa3N6xIUgaWxvxZvEhyBwb3d0w7NyemXFhCBjZW55IDEwMCBkb2xhcmEgdyBwb3LDs3duYW5pdSB6ICBpbm55bWkgb2RkemlhxYJhbWkuDQoNClpiYWRhbGnFm215IHLDs3duaWXFvCBqYWsgd3lnbMSFZGEgcm96a8WCYWQgb2NlbiBzYXR5c2Zha2NqaSB6IHBvZHppYcWCZW0gbmEgcMWCZcSHLiANCg0KYGBge3J9DQpnZ3Bsb3QoZGFuZSwgYWVzKGRhbmUkUmF0aW5nKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDQsIGNlbnRlciA9IDIuNSwgZmlsbCA9ICJwaW5rIikgKw0KICBmYWNldF93cmFwKHZhcnMoZGFuZSRHZW5kZXIpKSArDQogIHhsYWIoIk9jZW5hIHNhdHlzZmFrY2ppIikgKw0KICB5bGFiKCJJbG/Fm8SHIHBvd3TDs3J6ZcWEIikNCmBgYA0KDQpJbnRlcHJldGFjamE6IFdpenVhbGl6YWNqYSByb3prxYJhZMOzdyBvYnJhenVqZSBuYW0gaWxvxZvEhyBvY2VuIHNhdHlzZmFrY2ppIHcgb3BhcmNpdSBuYSBwb2R6aWHFgiB3emdsxJlkZW0gIHDFgmNpLiBNxJnFvGN6ecW6bmkgd3lyw7PFvG5pYWrEhSBzacSZIG5hIHRsZSBrb2JpZXQsIHBvbmlld2HFvCBuYWpjesSZxZtjaWVqIHogd2nEmWtzesSFIGlsb8WbY2nEhSBwb3d0w7NyemXFhCB3eWJpZXJhbGkgb2NlbnkgdyBwcnplZHppYWxlIG9kIDUuMC04LjAuDQpLb2JpZXR5IHLDs3duaWXFvCBza8WCYW5pYcWCeSBzacSZIGRvIHRlZ28gc2FtZWdvIHByemVkemlhxYJ1LCBqZWRuYWvFvGUgbW/FvGVteSB6YXV3YcW8ecSHLCDFvGUgc2tsZXAgQmllZHJvbmthIHBvc2lhZGEgd2nEmWNlaiBrbGllbnTDs3cgcMWCY2kgbcSZc2tpZWosIG5pxbwgcMWCY2kgxbxlxYRza2llai4gDQoNClphIGNpZWthd2UgdXpuYWxpxZtteSByw7N3bmllxbwgcHJ6ZWRzdGF3aWVuaWUgemEgcG9tb2PEhSB3eWtyZXN1LCBjZW4geiBwb2RhdGtpZW0gdyBwb3N6Y3plZ8OzbG55Y2ggbWllc2nEhWNhY2guIFcgdHltIGNlbHUgbXVzaWVsacWbbXkgd2dyYcSHIG5pZXpixJlkbmUgYmlibGlvdGVraS4gDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiY29sb3JzcGFjZSIpDQpsaWJyYXJ5KGNvbG9yc3BhY2UpDQpsaWJyYXJ5KGdnZm9yY2UpDQpsaWJyYXJ5KGdncmlkZ2VzKQ0KDQpkYW5lJG1vbnRoIDwtIGZvcm1hdCggYXMuRGF0ZSAoZGFuZSREYXRlLCBmb3JtYXQ9IiAlbS8lZC8lWSAiKSwiICVtICIpDQpnZ3Bsb3QoZGFuZSwgYWVzKHggPSBkYW5lJG1vbnRoLCB5ID0gZGFuZSRncm9zcy5pbmNvbWUpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNzUsIGZpbGw9ImJsYWNrIikgKw0KICAgICAgeGxhYigiTWllc2nEhWMiKSArDQogICAgICB5bGFiKCJEb2Now7NkIGJydXR0byIpDQpgYGANCg0KSW50ZXByZXRhY2phOiBhbmFsaXp1asSFYyByb3prxYJhZCwga3TDs3J5IG9waWVyYSBzacSZIHBvZHppYcWCZW0gbmEgbWllc2nEhWNlIHd6Z2zEmWRlbSBkb2Nob2R1IGJydXR0bywgbW/FvG5hIHN0d2llcmR6acSHIGnFvCBzdHljemXFhCBiecWCIG5hamJhcmR6aWVqIGRvY2hvZG93eW0gbWllc2nEhWNlbSwgamXFm2xpIGNob2R6aSBvIGNlbnkgcG9zaWFkYWrEhWNlIHd5c29raSB6eXNrIGJydXR0by4gTmF0b21pYXN0IG5ham5pxbxzenkgZG9jaMOzZCBicnV0dG8gb3NpxIVnbmnEmXR5IHByemV6IGZpbGllIHN1cGVybWFya2V0dSB6b3N0YcWCIG9zacSFZ25pxJl0eSB3IG1hcmN1LiANCg0KIyMgQW5hbGl6YSBvcGlzb3dhIC0geiBjenltIHcga2/FhGN1IG1hbXkgZG8gY3p5bmllbmlhPyANCg0KR2R5IGp1xbwgbmFzeiB6YmnDs3IgZGFueWNoIG5pZSBza3J5d2Egd2l6dWFsbnljaCB0YWplbW5pYywgbW/FvGVteSBydXN6YcSHIGRvIHByYWN5IHogYW5hbGl6xIUgb3Bpc293xIUuIFphY3p5bmFteSBvZCB3eXpuYWN6ZW5pYSB6YWtyZXN1IGNlbiB6IHdsaWN6b255bSBwb2RhdGtpZW0gb3JheiBwcmFjIHogdHltaSBpbmZvcm1hY2phbWkuIA0KDQpgYGB7cn0NCnJhbmdlKGRhbmUkVG90YWwpICN6bmFqZHVqZW15IHpha3JlcyBjZW4geiB3bGljem9ueW0gcG9kYXRraWVtDQptYXgoZGFuZSRUb3RhbCktbWluKGRhbmUkVG90YWwpDQpgYGANCg0KSW50ZXByZXRhY2phOiBCaWVkcm9ua2EgY2hhcmFrdGVyeXp1amUgc2nEmSBtaW5pbWFsbsSFICgxMC42OCkgb3JheiBtYWtzeW1hbG7EhSBjZW7EhSB6IHBvZGF0a2llbSAoMTA0Mi42NSksIGNvIHBvendhbGEgc3R3aWVyZHppxIcsIMW8ZSBza2xlcCBkeXNrb250b3d5IGNoYXJha3Rlcnl6dWplIHNpxJkgenLDs8W8bmljb3dhbnltIHBvemlvbWVtIGNlbiB3IHByb2R1a3RhY2gsIGt0w7NyZSBwb3NpYWRhLiBaIHByemVkc3Rhd2lvbnljaCBwb3d5xbxlaiBvcGVyYWNqaSB3aWFkb215bSBqZXN0IHLDs3duaWXFvCwgxbxlIHLDs8W8bmljYSBwb21pxJlkenkgbWFrc3ltYWxuxIUsIGEgbWluaW1hbG7EhSBjZW7EhSAoeiBwb2RhdGtpZW0pIHd5bm9zaSAxMDMxLjk3IGRvbGFyYS4gDQoNClByemVqZHppZW15IHRlcmF6IGRvIGRhbHN6eWNoIHByYWMuDQoNCmBgYHtyfQ0KbGltaXRzPC1jdXQoZGFuZSRUb3RhbCxzZXEoMCwxMTAwLGJ5PTEwMCkpDQp0YWJsZTE8LXRhYmxlKGxpbWl0cykNCnRyYW5zZm9ybSh0YWJsZTEsUmVsX0ZyZXE9cHJvcC50YWJsZShGcmVxKSxDdW1fRnJlcT1jdW1zdW0oRnJlcSkpDQoNCiMgUHJ6ZWRzdGF3bXkgcG93ecW8c3plIG5hIHd5a3Jlc2llIA0KDQpoaXN0KGRhbmUkVG90YWwscHJvYj1UUlVFLGJyZWFrcz1zZXEoMCwxMTAwLGJ5PTEwMCksbWFpbj0iVG90YWwiLHN1Yj0idyAkIikNCmxpbmVzKGRlbnNpdHkoZGFuZSRUb3RhbCksY29sPTYpDQoNCmluc3RhbGwucGFja2FnZXMoImNsYXNzSW50IikNCmxpYnJhcnkoY2xhc3NJbnQpDQoNCnRhYjE8LWNsYXNzSW50ZXJ2YWxzKGRhbmUkVG90YWwsbj0xMSxzdHlsZT0iZml4ZWQiLGZpeGVkQnJlYWtzPXNlcSgwLDExMDAsYnk9MTAwKSkNCnRhYjENCg0KamVua3MudGVzdHModGFiMSkNCmBgYA0KDQpaYWptaWVteSBzacSZIHRlcmF6IHN0YXR5c3R5a2FtaSBvcGlzb3d5bWkgZGxhIHptaWFuIGNhxYJrb3dpdGVqIHNwcnplZGHFvHkgd3JheiB6IHBvZGF0a2llbS4gT3Byw7NjeiBvYmVjbnljaCBwYWtpZXTDs3csIHBvdHJ6ZWJueSBixJlkemllIGplc3pjemUgaW5ueTogImthYmxlRXh0cmEiLiANCg0KYGBge3J9DQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpkYW5lJT4lDQogIGdyb3VwX2J5KEdlbmRlciklPiUNCiAgc3VtbWFyaXplKCdTdW1hIHNwcnplZGHFvHknPXN1bShkYW5lJFRvdGFsKSwNCiAgICAgICAgICAgICfFmnJlZG5pYSBzcHJ6ZWRhxbwnPW1lYW4oZGFuZSRUb3RhbCksDQogICAgICAgICAgICAnTWVkaWFuYSBzcHJ6ZWRhxbx5Jz1tZWRpYW4oZGFuZSRUb3RhbCksDQogICAgICAgICAgICAnTWluaW1hbG5hIHNwcnplZGHFvCc9bWluKGRhbmUkVG90YWwpLA0KICAgICAgICAgICAgJ01ha3N5bWFsbmEgc3ByemVkYcW8Jz1tYXgoZGFuZSRUb3RhbCksDQogICAgICAgICAgICAnT2RjaHlsZW5pZSBzdGFuZGFyZG93ZSc9c2QoZGFuZSRUb3RhbCkpJT4lDQogIGFycmFuZ2UoZGVzYygnU3VtYSBzcHJ6ZWRhxbx5JykpICU+JQ0KICBrYmwoKSU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsInJlc3BvbnNpdmUiKSxwb3NpdGlvbj0iY2VudGVyIikNCmBgYA0KDQooSW50ZXJwcmV0YWNqYSB3eW5pa8OzdykuVGVyYXogemFqbWllbXkgc2nEmSBzcG9qcnplbmllbSBuYSBzdGF0eXN0eWtpIGRvdHljesSFY2Ugb2Nlbnkgc2F0eXNmYWtjamkga2xpZW50YS4gDQoNCmBgYHtyfQ0KZGFuZSU+JQ0KICBncm91cF9ieShDaXR5KSU+JQ0KICBzdW1tYXJpemUoJ1N1bWEgb2NlbiBzYXR5c2Zha2NqaSBrbGllbnTDs3cnPXN1bShkYW5lJFJhdGluZyksDQogICAgICAgICAgICAnxZpyZWRuaWEgb2NlbiBzYXR5c2Zha2NqaSc9bWVhbihkYW5lJFJhdGluZyksDQogICAgICAgICAgICAnTWVkaWFuYSBvY2VuIHNhdHlzZmFrY2ppJz1tZWRpYW4oZGFuZSRSYXRpbmcpLA0KICAgICAgICAgICAgJ01pbmltYWxuYSBvY2VuYSBzYXR5c2Zha2NqaSc9bWluKGRhbmUkUmF0aW5nKSwNCiAgICAgICAgICAgICdNYWtzeW1hbG5hIG9jZW5hIHNhdHlzZmFrY2ppJz1tYXgoZGFuZSRSYXRpbmcpLA0KICAgICAgICAgICAgJ09kY2h5bGVuaWUgc3RhbmRhcmRvd2UnPXNkKGRhbmUkUmF0aW5nKSklPiUNCiAgYXJyYW5nZShkZXNjKCdTdW1hIG9jZW4gc2F0eXNmYWtjamknKSkgJT4lDQogIGtibCgpJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwicmVzcG9uc2l2ZSIpLHBvc2l0aW9uPSJjZW50ZXIiKQ0KYGBgDQoNCihJbnRlcnByZXRhY2phIHd5bmlrw7N3KS5Lb2xlam5lIHN0YXR5c3R5a2kgZG90eWN6xIUgbmF0b21pYXN0IGNlbiBwcm9kdWt0w7N3IA0KDQpgYGB7cn0NCmRhbmUlPiUNCiAgZ3JvdXBfYnkoUHJvZHVjdC5saW5lKSU+JQ0KICBzdW1tYXJpemUoJ1N1bWEgY2VuIHByb2R1a3TDs3cnPXN1bShkYW5lJFJhdGluZyksDQogICAgICAgICAgICAnxZpyZWRuaWEgY2VuIHByb2R1a3TDs3cnPW1lYW4oZGFuZSRSYXRpbmcpLA0KICAgICAgICAgICAgJ01lZGlhbmEgY2VuIHByb2R1a3TDs3cnPW1lZGlhbihkYW5lJFJhdGluZyksDQogICAgICAgICAgICAnTWluaW1hbG5hIGNlbiBwcm9kdWt0w7N3Jz1taW4oZGFuZSRSYXRpbmcpLA0KICAgICAgICAgICAgJ01ha3N5bWFsbmEgY2VuYSBwcm9kdWt0w7N3Jz1tYXgoZGFuZSRSYXRpbmcpLA0KICAgICAgICAgICAgJ09kY2h5bGVuaWUgc3RhbmRhcmRvd2UnPXNkKGRhbmUkUmF0aW5nKSklPiUNCiAgYXJyYW5nZShkZXNjKCdTdW1hIGNlbiBwcm9kdWt0w7N3JykpICU+JQ0KICBrYmwoKSU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsInJlc3BvbnNpdmUiKSxwb3NpdGlvbj0iY2VudGVyIikNCmBgYA0KDQoNCiMjIFduaW9za293YW5pZSAtIHdhcnRvIHNwcmF3ZHppxIcgcHl0YW5pYSBiYWRhd2N6ZSEgDQoNCkhpcG90ZXp5LCBrdMOzcmUgcG9zdGF3aWxpxZtteSB3IG5pbmllanN6eW0gcHJvamVrY2llIG5hIHBvdHJ6ZWJ5IHdlcnlmaWthY2ppIHd5YnJhbnljaCB6amF3aXNrLiANCg0KUHJhY2UgdyB0eW0gemFrcmVzaWUgcm96cG9jenluYW15IG9kIHBvYnJhbmlhIG5pZXpixJlkbnljaCBiaWJsaW90ZWsgZG8gUiwgcG9wdWxhcm55Y2ggeiB6YWtyZXN1IHRlc3Rvd2FuaWEgc3RhdHlzdHljem5lZ28uIA0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJnZ3N0YXRzcGxvdCIpDQpsaWJyYXJ5KGdnc3RhdHNwbG90KQ0KYGBgDQoNClBpZXJ3c3p5IHdhcmlhbnQgaGlwb3RlejogDQpIMDogS29iaWV0eSBrdXB1asSFIHdpxJljZWogcHJvZHVrdMOzdyB6IGthdGVnb3JpaTogemRyb3dpZSBpIHVyb2RhIG5pxbwgbcSZxbxjennFum5pOyANCkgxOiBLb2JpZXR5IG5pZSBrdXB1asSFIHdpxJljZWogcHJvZHVrdMOzdyB6IGthdGVnb3JpaTogemRyb3dpZSBpIHVyb2RhIG5pxbwgbcSZxbxjennFum5pLg0KDQpgYGB7cn0NCmRhdGE9ZGFuZQ0KeD1kYW5lJEdlbmRlcg0KeT1kYW5lJFByb2R1Y3QubGluZQ0KZ2dwaWVzdGF0cyh4PUdlbmRlciwNCiAgICAgICAgICAgeT1Qcm9kdWN0LmxpbmUsDQogICAgICAgICAgIGRhdGE9ZGFuZSkNCmBgYA0KDQpXYXJ0b8WbxIcgcCAocC12YWx1ZSkgbmEgcG96aW9taWUgMCwzMyBwb2thenVqZSwgxbxlIG5pZSBtYSBwb2RzdGF3IGRvIG9kcnp1Y2VuaWEgaGlwb3RlenkgemVyb3dlai4gT3puYWN6YSB0bywgxbxlIGtvYmlldHkgcnplY3p5d2nFm2NpZSBrdXB1asSFIHdpxJljZWogcHJvZHVrdMOzdyB6IGthdGVnb3JpaSBwcm9kdWt0w7N3ICJ6ZHJvd2llIGkgdXJvZGEiLiANCg0KRHJ1Z2kgd2FyaWFudCBoaXBvdGV6OiANCkgwOiBNxJnFvGN6ecW6bmkga3VwdWrEhSB3acSZY2VqIHByb2R1a3TDs3cgeiBrYXRlZ29yaWk6IGVsZWt0cm9uaWthIG5pxbwga29iaWV0eTsgDQpIMTogTcSZxbxjennFum5pIG5pZSBrdXB1asSFIHdpxJljZWogcHJvZHVrdMOzdyB6IGthdGVnb3JpaTogZWxla3Ryb25pa2EgbmnFvCBrb2JpZXR5LiANCg0KYGBge3J9DQpkYXRhPWRhbmUNCng9ZGFuZSRHZW5kZXINCnk9ZGFuZSRQcm9kdWN0LmxpbmUNCmdncGllc3RhdHMoeD1HZW5kZXIsDQogICAgICAgICAgIHk9UHJvZHVjdC5saW5lLA0KICAgICAgICAgICBkYXRhPWRhbmUpDQpgYGANCg0KV2FydG/Fm8SHIHAgKHAtdmFsdWUpIG5hIHBvemlvbWllIDAsMzMgcG9rYXp1amUsIMW8ZSBuaWUgbWEgcG9kc3RhdyBkbyBvZHJ6dWNlbmlhIGhpcG90ZXp5IHplcm93ZWouIE96bmFjemEgdG8sIMW8ZSBtxJnFvGN6ecW6bmkga3VwdWrEhSB3acSZY2VqIHByb2R1a3TDs3cgeiBrYXRlZ29yaWk6IGVsZWt0cm9uaWthIG5pxbwga29iaWV0eS4gDQoNClRyemVjaSB3YXJpYW50IGhpcG90ZXo6IA0KSDA6IEtsaWVuY2kgcG9zaWFkYWrEhWN5IGthcnTEmSBsb2phbG5vxZtjaW93xIUgd3lkYWrEhSBtbmllaiBvZCBvc8OzYiBqZWogbmllcG9zaWFkYWrEhWN5Y2g7IA0KSDE6IEtsaWVuY2kgcG9zaWFkYWrEhWN5IGthcnTEmSBsb2phbG5vxZtjaW93xIUgd3lkYWrEhSB3acSZY2VqIG9kIG9zw7NiIGplaiBuaWVwb3NpYWRhasSFY3ljaC4gDQoNCmBgYHtyfQ0KZGF0YT1kYW5lDQp4PWRhbmUkQ3VzdG9tZXIudHlwZQ0KeT1kYW5lJFRvdGFsDQoNCmdnYmV0d2VlbnN0YXRzKHg9Q3VzdG9tZXIudHlwZSwNCiAgICAgICAgICAgeT1Ub3RhbCwNCiAgICAgICAgICAgZGF0YT1kYW5lKQ0KYGBgDQoNCld5bmlrIHdhcnRvxZtjaSBwIChwLXZhbHVlKSBuYSBwb3ppb21pZSAwLDUzIHBva2F6dWplLCDFvGUgbmllIG1hIHBvZHN0YXcgZG8gb2RyenVjZW5pYSBoaXBvdGV6eSB6ZXJvd2VqLiBPem5hY3phIHRvLCDFvGUga2xpZW5jaSBwb3NpYWRhasSFY3kga2FydMSZIGxvamFsbm/Fm2Npb3fEhSB3eWRhaiBtbmllaiBvZCBvc8OzYiBqZWogbmllcG9zaWFkYWrEhWN5Y2guIA0KDQpDendhcnR5IHdhcmlhbnQgaGlwb3RlejogDQpIMDogTcSZxbxjennFum5pIGN6xJnFm2NpZWogb2Qga29iaWV0IHDFgmFjxIUgemEgemFrdXB5IGVwb3J0ZmVsZW07IA0KSDE6IE3EmcW8Y3p5xbpuaSByemFkemllaiBvZCBrb2JpZXQgcMWCYWPEhSB6YSB6YWt1cHkgZXBvcnRmZWxlbS4gDQoNCmBgYHtyfQ0KZGF0YT1kYW5lDQp4PWRhbmUkR2VuZGVyDQp5PWRhbmUkUGF5bWVudA0KZ2dwaWVzdGF0cyh4PUdlbmRlciwNCiAgICAgICAgICAgeT1QYXltZW50LA0KICAgICAgICAgICBkYXRhPWRhbmUpDQpgYGANCg0KV3luaWsgd2FydG/Fm2NpIHAgKHAtdmFsdWUpIG5hIHBvemlvbWllIDAsMjMgcG9rYXp1amUsIMW8ZSBuaWUgbWEgcG9kc3RhdyBkbyBvZHJ6dWNlbmlhIGhpcG90ZXp5IHplcm93ZWouIE96bmFjemEgdG8sIMW8ZSBtxJnFvGN6ecW6bmkgY3rEmcWbY2llaiBvZCBrb2JpZXQgcMWCYWPEhSB6YSB6YWt1cHkgZXBvcnRmZWxlbS4gDQoNCiMjIFBvZHN1bW93YW5pZSBpIHduaW9za2kga2/FhGNvd2UgLSBjbyB3aWVteSB6IGNhxYJlaiBwcmFjeT8gDQoNCg0KDQoNCg==