1 Zad 1

Zestaw danych “Prestige” (z pakietu “car”) zawiera dane nt. prestiżu 102 Kanadyjskich zawodów z 1971 roku. Zawiera on zmienne takie jak:

-education - która określa średnią liczbę lat edukacji wymaganych dla danego zawodu

-income - przedstawiający średni roczny dochód osób pracujących w danym zawodzie

-women - który informuje o procentowej ilości kobiet w każdym zawodzie

-prestige - który odnosi się do społecznie postrzeganego prestiżu zawodu

-census - czyli numer klasyfikacyjny zawodu zgodnie z klasyfikacją spisu powszechnego

-type - który klasyfikuje zawody na kategorie takie jak profesjonalne czy rolnicze

Do zbadania zależności między prestiżem a różnymi zmiennymi wykorzystaną zostane metody regresji nieparametrycznej. Na początku wczytujemy dane.

data("Prestige")
attach(Prestige)
## Następujący obiekt został zakryty z package:datasets:
## 
##     women

1.1 Wykres ukazujący relację między dochodem, a prestiżem.

Związek wygląda na nieliniowy. Dla zawodów, które zarabiają mniej niż $10K, istnieje silna (pozytywna) liniowa zależność pomiędzy dochodem a prestiżem. Jednak w przypadku zawodów, które zarabiają od 10 do 25 tysięcy dolarów, związek ten ma znacznie inne (osłabione) nachylenie. Podsumowując, można zauważyć, że w miarę jak dochód wzrasta, prestiż zawodu nie rośnie proporcjonalnie i pojawia się większe rozproszenie wartości prestiżu.

ggplot(Prestige, aes(x = income, y = prestige)) +
  geom_point(color = "purple", size = 3, alpha = 0.6) +  
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE, color = "red") +  
  labs(
    title = "Relacja między dochodem a prestiżem zawodu",
    caption = "Dane źródłowe: Pakiet 'car'"
  ) +
  theme_minimal() +  
  theme(
    plot.title = element_text(hjust = 0.5)  
  )

1.2 Estymacja nieliniowej zależności

Poniżej wykorzystano metodę locpoly() z pakietu KernSmooth do estymacji nieliniowej zależności, gdzie stopień polinomu wynosi zero (średnie jądrowe), a szerokość pasma ustalono na pięć.

fit <- locpoly(prestige, income,
               degree=0, bandwidth=5) %>% as_tibble()
ggplot(Prestige) +
  geom_point(aes(x=prestige,y=income)) +
  geom_line(data=fit, aes(x=x,y=y), col='purple')

Na niższych poziomach prestiżu dochód rośnie powoli, co sugeruje, że dla mniej prestiżowych zawodów wzrost prestiżu nie przekłada się znacząco na dochody. Dla zawodów o średnim poziomie prestiżu (około 25–50 punktów) dochód rośnie bardziej liniowo, co może sugerować umiarkowaną korelację między prestiżem a dochodem w tej grupie zawodów.Dla zawodów o wyższym prestiżu (powyżej 50 punktów) dochód rośnie wykładniczo, co sugeruje, że wśród wysoko prestiżowych zawodów nawet niewielki wzrost prestiżu może wiązać się z bardzo dużym wzrostem dochodów.

1.2.1 Zmiana szerokości pasma

Wartość parametru bandwidth (w tym przypadku 10) kontroluje poziom wygładzenia linii trendu. Mniejsze wartości pasma powodują większą wrażliwość na lokalne wahania danych, co prowadzi do bardziej szczegółowej (czasem zygzakowatej) linii trendu. Z kolei większe wartości bandwidth wygładzają krzywą, co zmniejsza wpływ lokalnych fluktuacji na estymację trendu.

fit <- locpoly(prestige, income,
               degree=0, bandwidth=10) %>% as_tibble()
ggplot(Prestige) +
  geom_point(aes(x=prestige,y=income)) +
  geom_line(data=fit, aes(x=x,y=y), col='purple')

fit <- locpoly(prestige, income,
               degree=0, bandwidth=3) %>% as_tibble()
ggplot(Prestige) +
  geom_point(aes(x=prestige,y=income)) +
  geom_line(data=fit, aes(x=x,y=y), col='purple')

1.2.2 Manipulacja degree wielomianu

Stopień polinomu (degree) wpływa na złożoność modelu - większe wartości pozwalają na bardziej złożone krzywe, które mogą lepiej oddać zawiłości danych.Poniżej znajduje się zmodyfikowany kod, który wykorzystuje degree=2 i szerokość pasma bandwidth=10.

fit <- locpoly(prestige, income,
               degree=2, bandwidth=10) %>% as_tibble()
ggplot(Prestige) +
  geom_point(aes(x=prestige,y=income)) +
  geom_line(data=fit, aes(x=x,y=y), col='purple')

1.3 Interpolacja splotów

Poniżej wykorzytano metodę interpolacji splotów (spline) do wygładzenia zależności między dwiema zmiennymi.Użycie splotów interpolujących pozwala na bardziej elastyczne dopasowanie do danych, szczególnie gdy relacja między zmiennymi jest skomplikowana i nie jest dobrze modelowana przez proste funkcje liniowe.

cv=TRUE: Opcja ta włącza walidację krzyżową. Używając walidacji krzyżowej, funkcja automatycznie wybiera wartość parametru lambda, która minimalizuje błąd predykcji, zapewniając optymalne wygładzenie.

Do zmiennej prestige dodano niewielki szum za pomocą rnorm(length(prestige), 0, 0.01). Jest to zabieg, który pozwala uniknąć problemów związanych z danymi o identycznych wartościach x, które mogłyby wpłynąć na stabilność dopasowania. Wartości x muszą być unikalne lub przynajmniej różnić się minimalnie, aby funkcja smooth.spline() mogła działać poprawnie, ponieważ funkcja ta jest przeznaczona dla zestawów danych o różnorodnych wartościach na osi x.

smr <- smooth.spline(prestige + rnorm(length(prestige), 0, 0.01), income, cv = TRUE)
smr <- data.frame(x=smr$x,y=smr$y)
ggplot(Prestige) +
  geom_point(aes(x=prestige,y=income)) +
  ggtitle("Prestige (Sploty interpolujące, lambda wybrana przez CV)") +
  geom_line(data=smr, aes(x=x, y=y), col='purple')  +
  theme_minimal() +  
  theme(
    plot.title = element_text(hjust = 0.5)  
  )

1.3.1 Sploty naturalne

Naturalne sploty to jedna z form interpolacji splajnowej, która szczególnie dobrze nadaje się do modelowania nieliniowych zależności w danych o naturalnych granicach. W odróżnieniu od splajnowych dopasowań bez ograniczeń, sploty naturalne zakładają, że krzywa dopasowania jest liniowa na krańcach przedziału, co pozwala uniknąć nienaturalnych wygięć na końcach danych. Jest to przydatne w sytuacjach, gdy wartości jednej ze zmiennych mają ograniczenia, jak np. income (dochód), który nie może być ujemny.

fit <- lm(prestige ~ ns(income, df=6), Prestige)
ggplot(Prestige) +
    geom_point(aes(x=income,y=prestige)) +
    ggtitle("Prestige wzgl. dochodu (Naturalne sploty, 6 df)") +
    geom_line(aes(x=income, y=fitted(fit)), col='purple') +
    theme_minimal() +  
  theme(
    plot.title = element_text(hjust = 0.5)  
  )

Na początku linia trendu wzrasta stosunkowo stromo, co sugeruje, że wzrost dochodu w niższym zakresie ma znaczący wpływ na wzrost prestiżu zawodów.W środkowym zakresie dochodów linia trendu wykazuje największe przyspieszenie, co wskazuje na to, że w tym segmencie dochodowym występuje największa zmienność w postrzeganiu prestiżu. W wyższym zakresie dochodów linia trendu staje się bardziej płaska, co może oznaczać, że po pewnym punkcie krytycznym dalsze wzrosty dochodu nie przynoszą proporcjonalnych zysków w postrzeganym prestiżu.

fit <- lm(prestige ~ ns(income, df=12), Prestige)
ggplot(Prestige) +
    geom_point(aes(x=income,y=prestige)) +
    ggtitle("Prestige wzgl. dochodu (Naturalne sploty, 12 df)") +
    geom_line(aes(x=income, y=fitted(fit)), col='purple') +
     theme_minimal() +  
  theme(
    plot.title = element_text(hjust = 0.5)  
  )

1.4 LOESS

Najbardziej znaną implementacją jest loess (lokalnie kwadratowy). Używa się tutaj jądra tri-cube i zmiennej szerokości pasma. Span kontroluje szerokość pasma, a degree jest rzędem wielomianu. Można użyć family=“symmetric” dla solidnego dopasowania.

smr <- loess(prestige ~ income, data=Prestige, span=0.15, degree=2, family="symmetric")
ggplot(Prestige) +
  geom_point(aes(x=income, y=prestige), color="black") +  
  geom_line(aes(x=income, y=fitted(smr)), color='purple') + 
  ggtitle("Prestige względem dochodu (Loess: span=0.15, degree=2, robust fitting)") +
       theme_minimal() +  
  theme(
    plot.title = element_text(hjust = 0.5)  
  )

Niski dochód: Na początku linia LOESS dobrze odwzorowuje lokalne minimum, jednak jest kilka obszarów, gdzie linia znacznie odchyla się od punktów danych, szczególnie przy bardzo niskich dochodach. Średni dochód: W tym zakresie linia dosyć dobrze śledzi główne trendy danych, choć występują punkty, które są daleko od przewidywanej linii trendu. Wysoki dochód: Linia wydaje się być płaska i nie odzwierciedla dobrze dystrybucji danych w tym zakresie, gdzie zmienność danych jest znaczna.

2 Zad 2

Zbiór danych “mcycle” (z pakietu MASS) zawiera n=133 pary punktów czasowych (w ms) i obserwowanych przyspieszeń głowy (w g), które zostały zarejestrowane w symulowanym wypadku motocyklowym.

Do zbadania zależności między czasem a przyspieszeniem wykorzystana została metoda regresji nieparametrycznej.Na początku wczytujemy dane.

data("mcycle")
attach(mcycle)

2.1 Wykres ukazujący relację między czasem, a przyśpieszeniem.

ggplot(mcycle, aes(x = times, y = accel)) +
  geom_point(color = "darkgreen", size = 2, alpha = 0.6) +  
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE, color = "red") +  
  labs(
    title = "Relacja między czasem a przyśpieszeniem",
    caption = "Dane źródłowe: Pakiet 'MASS'"
  ) +
  theme_minimal() +  
  theme(
    plot.title = element_text(hjust = 0.5)  
  )

2.2 Estymacja nieliniowej zależności

Poniżej wykorzystano metodę locpoly() z pakietu KernSmooth do estymacji nieliniowej zależności, gdzie stopień polinomu wynosi 2, a szerokość pasma ustalono na pięć.

fit2 <- locpoly(times, accel,
                degree=2, bandwidth=5) %>% as_tibble()
ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  geom_line(data=fit2, aes(x=x,y=y), col='red')+
  ggtitle("Relacja między czasem a przyspieszeniem")+
  theme_minimal() +  
  theme(
    plot.title = element_text(hjust = 0.5)  
  )

2.3 Interpolacja splotów

times_unique <- times + rnorm(length(times), 0, 1e-6)
smr1 <- smooth.spline(times_unique, accel, cv=TRUE)
## Warning in smooth.spline(times_unique, accel, cv = TRUE): cross-validation with
## non-unique 'x' values seems doubtful
smr1 <- data.frame(x=smr1$x,y=smr1$y)
ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  ggtitle("Sploty interpolujące, lambda wybrana przez CV") +
  geom_line(data=smr1, aes(x=x, y=y), col='red') +
    theme_minimal() +  
  theme(
    plot.title = element_text(hjust = 0.5)  
  )

Dane wykazują wyraźne oscylacje przyspieszenia w zależności od czasu. Na początku przyspieszenie spada, osiągając minimum około czasu 20, po czym gwałtownie wzrasta do maksimum około czasu 30. Następnie ponownie spada i stabilizuje się na poziomie zbliżonym do zera, wskazując na wygaszenie oscylacji.

Krzywa uzyskana za pomocą metody smooth spline skutecznie odwzorowuje ogólną tendencję w danych, dostosowując się do zmienności przyspieszenia w miarę upływu czasu. Wybór wartości parametru lambda poprzez walidację krzyżową pozwala na optymalne wygładzenie, co oznacza, że krzywa dobrze oddaje ogólny wzorzec bez nadmiernego dopasowania do lokalnych fluktuacji.

Wykorzystanie spline’ów pozwala na wychwycenie i oddanie zmian w przyspieszeniu, uwzględniając zarówno gwałtowne wzrosty i spadki, jak i stabilizację na końcu. Dzięki temu krzywa jest płynna, ale nie traci szczegółów charakterystycznych dla danych, co daje pełniejszy obraz dynamiki przyspieszenia w funkcji czasu.

LS0tDQp0aXRsZTogIk5pZWtsYXN5Y3puZSBtZXRvZHkgc3RhdHlzdHlraSINCnN1YnRpdGxlOiAiUmVncmVzamEgbmllcGFyYW1ldHJ5Y3puYSINCmF1dGhvcjogIk1hxYJnb3J6YXRhIER1ZGFub3dpY3osIEV3YSBCcmV6YSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlDQogICAgZm9udHNpemU6IDhwdA0KICAgIHRvYzogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IGZhbHNlDQplZGl0b3Jfb3B0aW9uczogDQogIG1hcmtkb3duOiANCiAgICB3cmFwOiA3Mg0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KDQpsaWJyYXJ5KGNhcikgICAgICAgICAgDQpsaWJyYXJ5KEtlcm5TbW9vdGgpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoTUFTUykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpYmJsZSkNCmxpYnJhcnkoc3BsaW5lcykNCg0KYGBgDQoNCiMgWmFkIDENCg0KWmVzdGF3IGRhbnljaCAiUHJlc3RpZ2UiICh6IHBha2lldHUgImNhciIpIHphd2llcmEgZGFuZSBudC4gcHJlc3Rpxbx1IDEwMg0KS2FuYWR5anNraWNoIHphd29kw7N3IHogMTk3MSByb2t1LiBaYXdpZXJhIG9uIHptaWVubmUgdGFraWUgamFrOg0KDQotZWR1Y2F0aW9uIC0ga3TDs3JhIG9rcmXFm2xhIMWbcmVkbmnEhSBsaWN6YsSZIGxhdCBlZHVrYWNqaSB3eW1hZ2FueWNoIGRsYSBkYW5lZ28gemF3b2R1DQoNCi1pbmNvbWUgLSBwcnplZHN0YXdpYWrEhWN5IMWbcmVkbmkgcm9jem55IGRvY2jDs2Qgb3PDs2IgcHJhY3VqxIVjeWNoIHcgZGFueW0gemF3b2R6aWUNCg0KLXdvbWVuIC0ga3TDs3J5IGluZm9ybXVqZSBvIHByb2NlbnRvd2VqIGlsb8WbY2kga29iaWV0IHcga2HFvGR5bSB6YXdvZHppZQ0KDQotcHJlc3RpZ2UgLSBrdMOzcnkgb2Rub3NpIHNpxJkgZG8gc3BvxYJlY3puaWUgcG9zdHJ6ZWdhbmVnbyBwcmVzdGnFvHUgemF3b2R1DQoNCi1jZW5zdXMgLSBjenlsaSBudW1lciBrbGFzeWZpa2FjeWpueSB6YXdvZHUgemdvZG5pZSB6IGtsYXN5ZmlrYWNqxIUgc3Bpc3UgcG93c3plY2huZWdvDQoNCi10eXBlIC0ga3TDs3J5IGtsYXN5ZmlrdWplIHphd29keSBuYSBrYXRlZ29yaWUgdGFraWUgamFrIHByb2Zlc2pvbmFsbmUgY3p5IHJvbG5pY3plDQoNCkRvIHpiYWRhbmlhIHphbGXFvG5vxZtjaSBtacSZZHp5IHByZXN0acW8ZW0gYSByw7PFvG55bWkgem1pZW5ueW1pIHd5a29yenlzdGFuxIUgem9zdGFuZSBtZXRvZHkgcmVncmVzamkgbmllcGFyYW1ldHJ5Y3puZWouIE5hIHBvY3rEhXRrdSB3Y3p5dHVqZW15IGRhbmUuDQoNCmBgYHtyfQ0KZGF0YSgiUHJlc3RpZ2UiKQ0KYXR0YWNoKFByZXN0aWdlKQ0KYGBgDQoNCiMjIFd5a3JlcyB1a2F6dWrEhWN5IHJlbGFjasSZIG1pxJlkenkgZG9jaG9kZW0sIGEgcHJlc3RpxbxlbS4NCg0KWndpxIV6ZWsgd3lnbMSFZGEgbmEgbmllbGluaW93eS4gRGxhIHphd29kw7N3LCBrdMOzcmUgemFyYWJpYWrEhSBtbmllaiBuacW8ICQxMEssIGlzdG5pZWplIHNpbG5hIChwb3p5dHl3bmEpIGxpbmlvd2EgemFsZcW8bm/Fm8SHIHBvbWnEmWR6eSBkb2Nob2RlbSBhIHByZXN0acW8ZW0uIEplZG5hayB3IHByenlwYWRrdSB6YXdvZMOzdywga3TDs3JlIHphcmFiaWFqxIUgb2QgMTAgZG8gMjUgdHlzacSZY3kgZG9sYXLDs3csIHp3acSFemVrIHRlbiBtYSB6bmFjem5pZSBpbm5lIChvc8WCYWJpb25lKSBuYWNoeWxlbmllLiBQb2RzdW1vd3VqxIVjLCBtb8W8bmEgemF1d2HFvHnEhywgxbxlIHcgbWlhcsSZIGphayBkb2Now7NkIHd6cmFzdGEsIHByZXN0acW8IHphd29kdSBuaWUgcm/Fm25pZSBwcm9wb3Jjam9uYWxuaWUgaSBwb2phd2lhIHNpxJkgd2nEmWtzemUgcm96cHJvc3plbmllIHdhcnRvxZtjaSBwcmVzdGnFvHUuIA0KDQpgYGB7cn0NCmdncGxvdChQcmVzdGlnZSwgYWVzKHggPSBpbmNvbWUsIHkgPSBwcmVzdGlnZSkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMywgYWxwaGEgPSAwLjYpICsgIA0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsgIA0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJlbGFjamEgbWnEmWR6eSBkb2Nob2RlbSBhIHByZXN0acW8ZW0gemF3b2R1IiwNCiAgICBjYXB0aW9uID0gIkRhbmUgxbpyw7NkxYJvd2U6IFBha2lldCAnY2FyJyINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArICANCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkgIA0KICApDQpgYGANCg0KIyMgRXN0eW1hY2phIG5pZWxpbmlvd2VqIHphbGXFvG5vxZtjaQ0KDQpQb25pxbxlaiB3eWtvcnp5c3Rhbm8gbWV0b2TEmSBsb2Nwb2x5KCkgeiBwYWtpZXR1IEtlcm5TbW9vdGggZG8gZXN0eW1hY2ppIG5pZWxpbmlvd2VqIHphbGXFvG5vxZtjaSwgZ2R6aWUgc3RvcGllxYQgcG9saW5vbXUgd3lub3NpIHplcm8gKMWbcmVkbmllIGrEhWRyb3dlKSwgYSBzemVyb2tvxZvEhyBwYXNtYSB1c3RhbG9ubyBuYSBwacSZxIcuIA0KDQpgYGB7cn0NCmZpdCA8LSBsb2Nwb2x5KHByZXN0aWdlLCBpbmNvbWUsDQogICAgICAgICAgICAgICBkZWdyZWU9MCwgYmFuZHdpZHRoPTUpICU+JSBhc190aWJibGUoKQ0KZ2dwbG90KFByZXN0aWdlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9cHJlc3RpZ2UseT1pbmNvbWUpKSArDQogIGdlb21fbGluZShkYXRhPWZpdCwgYWVzKHg9eCx5PXkpLCBjb2w9J3B1cnBsZScpDQpgYGANCg0KTmEgbmnFvHN6eWNoIHBvemlvbWFjaCBwcmVzdGnFvHUgZG9jaMOzZCByb8WbbmllIHBvd29saSwgY28gc3VnZXJ1amUsIMW8ZSBkbGEgbW5pZWogcHJlc3Rpxbxvd3ljaCB6YXdvZMOzdyB3enJvc3QgcHJlc3Rpxbx1IG5pZSBwcnpla8WCYWRhIHNpxJkgem5hY3rEhWNvIG5hIGRvY2hvZHkuIERsYSB6YXdvZMOzdyBvIMWbcmVkbmltIHBvemlvbWllIHByZXN0acW8dSAob2tvxYJvIDI14oCTNTAgcHVua3TDs3cpIGRvY2jDs2Qgcm/Fm25pZSBiYXJkemllaiBsaW5pb3dvLCBjbyBtb8W8ZSBzdWdlcm93YcSHIHVtaWFya293YW7EhSBrb3JlbGFjasSZIG1pxJlkenkgcHJlc3RpxbxlbSBhIGRvY2hvZGVtIHcgdGVqIGdydXBpZSB6YXdvZMOzdy5EbGEgemF3b2TDs3cgbyB3ecW8c3p5bSBwcmVzdGnFvHUgKHBvd3nFvGVqIDUwIHB1bmt0w7N3KSBkb2Now7NkIHJvxZtuaWUgd3lrxYJhZG5pY3pvLCBjbyBzdWdlcnVqZSwgxbxlIHfFm3LDs2Qgd3lzb2tvIHByZXN0acW8b3d5Y2ggemF3b2TDs3cgbmF3ZXQgbmlld2llbGtpIHd6cm9zdCBwcmVzdGnFvHUgbW/FvGUgd2nEhXphxIcgc2nEmSB6IGJhcmR6byBkdcW8eW0gd3pyb3N0ZW0gZG9jaG9kw7N3Lg0KDQojIyMgWm1pYW5hIHN6ZXJva2/Fm2NpIHBhc21hDQoNCldhcnRvxZvEhyBwYXJhbWV0cnUgYmFuZHdpZHRoICh3IHR5bSBwcnp5cGFka3UgMTApIGtvbnRyb2x1amUgcG96aW9tIHd5Z8WCYWR6ZW5pYSBsaW5paSB0cmVuZHUuIE1uaWVqc3plIHdhcnRvxZtjaSBwYXNtYSBwb3dvZHVqxIUgd2nEmWtzesSFIHdyYcW8bGl3b8WbxIcgbmEgbG9rYWxuZSB3YWhhbmlhIGRhbnljaCwgY28gcHJvd2FkemkgZG8gYmFyZHppZWogc3pjemVnw7PFgm93ZWogKGN6YXNlbSB6eWd6YWtvd2F0ZWopIGxpbmlpIHRyZW5kdS4gWiBrb2xlaSB3acSZa3N6ZSB3YXJ0b8WbY2kgYmFuZHdpZHRoIHd5Z8WCYWR6YWrEhSBrcnp5d8SFLCBjbyB6bW5pZWpzemEgd3DFgnl3IGxva2FsbnljaCBmbHVrdHVhY2ppIG5hIGVzdHltYWNqxJkgdHJlbmR1Lg0KDQpgYGB7cn0NCmZpdCA8LSBsb2Nwb2x5KHByZXN0aWdlLCBpbmNvbWUsDQogICAgICAgICAgICAgICBkZWdyZWU9MCwgYmFuZHdpZHRoPTEwKSAlPiUgYXNfdGliYmxlKCkNCmdncGxvdChQcmVzdGlnZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXByZXN0aWdlLHk9aW5jb21lKSkgKw0KICBnZW9tX2xpbmUoZGF0YT1maXQsIGFlcyh4PXgseT15KSwgY29sPSdwdXJwbGUnKQ0KYGBgDQpgYGB7cn0NCmZpdCA8LSBsb2Nwb2x5KHByZXN0aWdlLCBpbmNvbWUsDQogICAgICAgICAgICAgICBkZWdyZWU9MCwgYmFuZHdpZHRoPTMpICU+JSBhc190aWJibGUoKQ0KZ2dwbG90KFByZXN0aWdlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9cHJlc3RpZ2UseT1pbmNvbWUpKSArDQogIGdlb21fbGluZShkYXRhPWZpdCwgYWVzKHg9eCx5PXkpLCBjb2w9J3B1cnBsZScpDQpgYGANCg0KIyMjIE1hbmlwdWxhY2phIGRlZ3JlZSB3aWVsb21pYW51DQoNClN0b3BpZcWEIHBvbGlub211IChkZWdyZWUpIHdwxYJ5d2EgbmEgesWCb8W8b25vxZvEhyBtb2RlbHUgLSB3acSZa3N6ZSB3YXJ0b8WbY2kgcG96d2FsYWrEhSBuYSBiYXJkemllaiB6xYJvxbxvbmUga3J6eXdlLCBrdMOzcmUgbW9nxIUgbGVwaWVqIG9kZGHEhyB6YXdpxYJvxZtjaSBkYW55Y2guUG9uacW8ZWogem5hamR1amUgc2nEmSB6bW9keWZpa293YW55IGtvZCwga3TDs3J5IHd5a29yenlzdHVqZSBkZWdyZWU9MiBpIHN6ZXJva2/Fm8SHIHBhc21hIGJhbmR3aWR0aD0xMC4NCg0KYGBge3J9DQpmaXQgPC0gbG9jcG9seShwcmVzdGlnZSwgaW5jb21lLA0KICAgICAgICAgICAgICAgZGVncmVlPTIsIGJhbmR3aWR0aD0xMCkgJT4lIGFzX3RpYmJsZSgpDQpnZ3Bsb3QoUHJlc3RpZ2UpICsNCiAgZ2VvbV9wb2ludChhZXMoeD1wcmVzdGlnZSx5PWluY29tZSkpICsNCiAgZ2VvbV9saW5lKGRhdGE9Zml0LCBhZXMoeD14LHk9eSksIGNvbD0ncHVycGxlJykNCmBgYA0KDQojIyBJbnRlcnBvbGFjamEgc3Bsb3TDs3cNCg0KUG9uacW8ZWogd3lrb3J6eXRhbm8gbWV0b2TEmSBpbnRlcnBvbGFjamkgc3Bsb3TDs3cgKHNwbGluZSkgZG8gd3lnxYJhZHplbmlhIHphbGXFvG5vxZtjaSBtacSZZHp5IGR3aWVtYSB6bWllbm55bWkuVcW8eWNpZSBzcGxvdMOzdyBpbnRlcnBvbHVqxIVjeWNoIHBvendhbGEgbmEgYmFyZHppZWogZWxhc3R5Y3puZSBkb3Bhc293YW5pZSBkbyBkYW55Y2gsIHN6Y3plZ8OzbG5pZSBnZHkgcmVsYWNqYSBtacSZZHp5IHptaWVubnltaSBqZXN0IHNrb21wbGlrb3dhbmEgaSBuaWUgamVzdCBkb2JyemUgbW9kZWxvd2FuYSBwcnpleiBwcm9zdGUgZnVua2NqZSBsaW5pb3dlLg0KDQpjdj1UUlVFOiBPcGNqYSB0YSB3xYLEhWN6YSB3YWxpZGFjasSZIGtyennFvG93xIUuIFXFvHl3YWrEhWMgd2FsaWRhY2ppIGtyennFvG93ZWosIGZ1bmtjamEgYXV0b21hdHljem5pZSB3eWJpZXJhIHdhcnRvxZvEhyBwYXJhbWV0cnUgbGFtYmRhLCBrdMOzcmEgbWluaW1hbGl6dWplIGLFgsSFZCBwcmVkeWtjamksIHphcGV3bmlhasSFYyBvcHR5bWFsbmUgd3lnxYJhZHplbmllLg0KDQpEbyB6bWllbm5laiBwcmVzdGlnZSBkb2Rhbm8gbmlld2llbGtpIHN6dW0gemEgcG9tb2PEhSBybm9ybShsZW5ndGgocHJlc3RpZ2UpLCAwLCAwLjAxKS4gSmVzdCB0byB6YWJpZWcsIGt0w7NyeSBwb3p3YWxhIHVuaWtuxIXEhyBwcm9ibGVtw7N3IHp3acSFemFueWNoIHogZGFueW1pIG8gaWRlbnR5Y3pueWNoIHdhcnRvxZtjaWFjaCB4LCBrdMOzcmUgbW9nxYJ5Ynkgd3DFgnluxIXEhyBuYSBzdGFiaWxub8WbxIcgZG9wYXNvd2FuaWEuIFdhcnRvxZtjaSB4IG11c3rEhSBiecSHIHVuaWthbG5lIGx1YiBwcnp5bmFqbW5pZWogcsOzxbxuacSHIHNpxJkgbWluaW1hbG5pZSwgYWJ5IGZ1bmtjamEgc21vb3RoLnNwbGluZSgpIG1vZ8WCYSBkemlhxYJhxIcgcG9wcmF3bmllLCBwb25pZXdhxbwgZnVua2NqYSB0YSBqZXN0IHByemV6bmFjem9uYSBkbGEgemVzdGF3w7N3IGRhbnljaCBvIHLDs8W8bm9yb2RueWNoIHdhcnRvxZtjaWFjaCBuYSBvc2kgeC4NCg0KYGBge3J9DQpzbXIgPC0gc21vb3RoLnNwbGluZShwcmVzdGlnZSArIHJub3JtKGxlbmd0aChwcmVzdGlnZSksIDAsIDAuMDEpLCBpbmNvbWUsIGN2ID0gVFJVRSkNCnNtciA8LSBkYXRhLmZyYW1lKHg9c21yJHgseT1zbXIkeSkNCmdncGxvdChQcmVzdGlnZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXByZXN0aWdlLHk9aW5jb21lKSkgKw0KICBnZ3RpdGxlKCJQcmVzdGlnZSAoU3Bsb3R5IGludGVycG9sdWrEhWNlLCBsYW1iZGEgd3licmFuYSBwcnpleiBDVikiKSArDQogIGdlb21fbGluZShkYXRhPXNtciwgYWVzKHg9eCwgeT15KSwgY29sPSdwdXJwbGUnKSAgKw0KICB0aGVtZV9taW5pbWFsKCkgKyAgDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpICANCiAgKQ0KYGBgDQoNCiMjIyBTcGxvdHkgbmF0dXJhbG5lIA0KDQpOYXR1cmFsbmUgc3Bsb3R5IHRvIGplZG5hIHogZm9ybSBpbnRlcnBvbGFjamkgc3BsYWpub3dlaiwga3TDs3JhIHN6Y3plZ8OzbG5pZSBkb2JyemUgbmFkYWplIHNpxJkgZG8gbW9kZWxvd2FuaWEgbmllbGluaW93eWNoIHphbGXFvG5vxZtjaSB3IGRhbnljaCBvIG5hdHVyYWxueWNoIGdyYW5pY2FjaC4gVyBvZHLDs8W8bmllbml1IG9kIHNwbGFqbm93eWNoIGRvcGFzb3dhxYQgYmV6IG9ncmFuaWN6ZcWELCBzcGxvdHkgbmF0dXJhbG5lIHpha8WCYWRhasSFLCDFvGUga3J6eXdhIGRvcGFzb3dhbmlhIGplc3QgbGluaW93YSBuYSBrcmHFhGNhY2ggcHJ6ZWR6aWHFgnUsIGNvIHBvendhbGEgdW5pa27EhcSHIG5pZW5hdHVyYWxueWNoIHd5Z2nEmcSHIG5hIGtvxYRjYWNoIGRhbnljaC4gSmVzdCB0byBwcnp5ZGF0bmUgdyBzeXR1YWNqYWNoLCBnZHkgd2FydG/Fm2NpIGplZG5laiB6ZSB6bWllbm55Y2ggbWFqxIUgb2dyYW5pY3plbmlhLCBqYWsgbnAuIGluY29tZSAoZG9jaMOzZCksIGt0w7NyeSBuaWUgbW/FvGUgYnnEhyB1amVtbnkuDQoNCmBgYHtyfQ0KZml0IDwtIGxtKHByZXN0aWdlIH4gbnMoaW5jb21lLCBkZj02KSwgUHJlc3RpZ2UpDQpnZ3Bsb3QoUHJlc3RpZ2UpICsNCiAgICBnZW9tX3BvaW50KGFlcyh4PWluY29tZSx5PXByZXN0aWdlKSkgKw0KICAgIGdndGl0bGUoIlByZXN0aWdlIHd6Z2wuIGRvY2hvZHUgKE5hdHVyYWxuZSBzcGxvdHksIDYgZGYpIikgKw0KICAgIGdlb21fbGluZShhZXMoeD1pbmNvbWUsIHk9Zml0dGVkKGZpdCkpLCBjb2w9J3B1cnBsZScpICsNCiAgICB0aGVtZV9taW5pbWFsKCkgKyAgDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpICANCiAgKQ0KYGBgDQoNCk5hIHBvY3rEhXRrdSBsaW5pYSB0cmVuZHUgd3pyYXN0YSBzdG9zdW5rb3dvIHN0cm9tbywgY28gc3VnZXJ1amUsIMW8ZSB3enJvc3QgZG9jaG9kdSB3IG5pxbxzenltIHpha3Jlc2llIG1hIHpuYWN6xIVjeSB3cMWCeXcgbmEgd3pyb3N0IHByZXN0acW8dSB6YXdvZMOzdy5XIMWbcm9ka293eW0gemFrcmVzaWUgZG9jaG9kw7N3IGxpbmlhIHRyZW5kdSB3eWthenVqZSBuYWp3acSZa3N6ZSBwcnp5c3BpZXN6ZW5pZSwgY28gd3NrYXp1amUgbmEgdG8sIMW8ZSB3IHR5bSBzZWdtZW5jaWUgZG9jaG9kb3d5bSB3eXN0xJlwdWplIG5handpxJlrc3phIHptaWVubm/Fm8SHIHcgcG9zdHJ6ZWdhbml1IHByZXN0acW8dS4gVyB3ecW8c3p5bSB6YWtyZXNpZSBkb2Nob2TDs3cgbGluaWEgdHJlbmR1IHN0YWplIHNpxJkgYmFyZHppZWogcMWCYXNrYSwgY28gbW/FvGUgb3puYWN6YcSHLCDFvGUgcG8gcGV3bnltIHB1bmtjaWUga3J5dHljem55bSBkYWxzemUgd3pyb3N0eSBkb2Nob2R1IG5pZSBwcnp5bm9zesSFIHByb3BvcmNqb25hbG55Y2ggenlza8OzdyB3IHBvc3RyemVnYW55bSBwcmVzdGnFvHUuDQoNCmBgYHtyfQ0KZml0IDwtIGxtKHByZXN0aWdlIH4gbnMoaW5jb21lLCBkZj0xMiksIFByZXN0aWdlKQ0KZ2dwbG90KFByZXN0aWdlKSArDQogICAgZ2VvbV9wb2ludChhZXMoeD1pbmNvbWUseT1wcmVzdGlnZSkpICsNCiAgICBnZ3RpdGxlKCJQcmVzdGlnZSB3emdsLiBkb2Nob2R1IChOYXR1cmFsbmUgc3Bsb3R5LCAxMiBkZikiKSArDQogICAgZ2VvbV9saW5lKGFlcyh4PWluY29tZSwgeT1maXR0ZWQoZml0KSksIGNvbD0ncHVycGxlJykgKw0KICAgICB0aGVtZV9taW5pbWFsKCkgKyAgDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpICANCiAgKQ0KYGBgDQoNCiMjIExPRVNTDQoNCk5hamJhcmR6aWVqIHpuYW7EhSBpbXBsZW1lbnRhY2rEhSBqZXN0IGxvZXNzIChsb2thbG5pZSBrd2FkcmF0b3d5KS4gVcW8eXdhIHNpxJkgdHV0YWogasSFZHJhIHRyaS1jdWJlIGkgem1pZW5uZWogc3plcm9rb8WbY2kgcGFzbWEuDQpTcGFuIGtvbnRyb2x1amUgc3plcm9rb8WbxIcgcGFzbWEsIGEgZGVncmVlIGplc3QgcnrEmWRlbSB3aWVsb21pYW51LiBNb8W8bmEgdcW8ecSHIGZhbWlseT0ic3ltbWV0cmljIiBkbGEgc29saWRuZWdvIGRvcGFzb3dhbmlhLg0KDQpgYGB7cn0NCnNtciA8LSBsb2VzcyhwcmVzdGlnZSB+IGluY29tZSwgZGF0YT1QcmVzdGlnZSwgc3Bhbj0wLjE1LCBkZWdyZWU9MiwgZmFtaWx5PSJzeW1tZXRyaWMiKQ0KZ2dwbG90KFByZXN0aWdlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9aW5jb21lLCB5PXByZXN0aWdlKSwgY29sb3I9ImJsYWNrIikgKyAgDQogIGdlb21fbGluZShhZXMoeD1pbmNvbWUsIHk9Zml0dGVkKHNtcikpLCBjb2xvcj0ncHVycGxlJykgKyANCiAgZ2d0aXRsZSgiUHJlc3RpZ2Ugd3pnbMSZZGVtIGRvY2hvZHUgKExvZXNzOiBzcGFuPTAuMTUsIGRlZ3JlZT0yLCByb2J1c3QgZml0dGluZykiKSArDQogICAgICAgdGhlbWVfbWluaW1hbCgpICsgIA0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSAgDQogICkNCmBgYA0KDQpOaXNraSBkb2Now7NkOiBOYSBwb2N6xIV0a3UgbGluaWEgTE9FU1MgZG9icnplIG9kd3pvcm93dWplIGxva2FsbmUgbWluaW11bSwgamVkbmFrIGplc3Qga2lsa2Egb2JzemFyw7N3LCBnZHppZSBsaW5pYSB6bmFjem5pZSBvZGNoeWxhIHNpxJkgb2QgcHVua3TDs3cgZGFueWNoLCBzemN6ZWfDs2xuaWUgcHJ6eSBiYXJkem8gbmlza2ljaCBkb2Nob2RhY2guDQrFmnJlZG5pIGRvY2jDs2Q6IFcgdHltIHpha3Jlc2llIGxpbmlhIGRvc3nEhyBkb2JyemUgxZtsZWR6aSBnxYLDs3duZSB0cmVuZHkgZGFueWNoLCBjaG/EhyB3eXN0xJlwdWrEhSBwdW5rdHksIGt0w7NyZSBzxIUgZGFsZWtvIG9kIHByemV3aWR5d2FuZWogbGluaWkgdHJlbmR1Lg0KV3lzb2tpIGRvY2jDs2Q6IExpbmlhIHd5ZGFqZSBzacSZIGJ5xIcgcMWCYXNrYSBpIG5pZSBvZHp3aWVyY2llZGxhIGRvYnJ6ZSBkeXN0cnlidWNqaSBkYW55Y2ggdyB0eW0gemFrcmVzaWUsIGdkemllIHptaWVubm/Fm8SHIGRhbnljaCBqZXN0IHpuYWN6bmEuDQoNCiMgWmFkIDIgDQoNClpiacOzciBkYW55Y2gg4oCcbWN5Y2xl4oCdICh6IHBha2lldHUgTUFTUykgemF3aWVyYSBuPTEzMyBwYXJ5IHB1bmt0w7N3IGN6YXNvd3ljaCAodyBtcykgaSBvYnNlcndvd2FueWNoIHByenlzcGllc3plxYQgZ8WCb3d5ICh3IGcpLCBrdMOzcmUgem9zdGHFgnkgemFyZWplc3Ryb3dhbmUgdyBzeW11bG93YW55bSB3eXBhZGt1IG1vdG9jeWtsb3d5bS4NCg0KRG8gemJhZGFuaWEgemFsZcW8bm/Fm2NpIG1pxJlkenkgY3phc2VtIGEgcHJ6eXNwaWVzemVuaWVtIHd5a29yenlzdGFuYSB6b3N0YcWCYSBtZXRvZGEgcmVncmVzamkgbmllcGFyYW1ldHJ5Y3puZWouTmEgcG9jesSFdGt1IHdjenl0dWplbXkgZGFuZS4NCg0KYGBge3J9DQpkYXRhKCJtY3ljbGUiKQ0KYXR0YWNoKG1jeWNsZSkNCmBgYA0KDQojIyBXeWtyZXMgdWthenVqxIVjeSByZWxhY2rEmSBtacSZZHp5IGN6YXNlbSwgYSBwcnp5xZtwaWVzemVuaWVtLg0KDQpgYGB7cn0NCmdncGxvdChtY3ljbGUsIGFlcyh4ID0gdGltZXMsIHkgPSBhY2NlbCkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJkYXJrZ3JlZW4iLCBzaXplID0gMiwgYWxwaGEgPSAwLjYpICsgIA0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsgIA0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJlbGFjamEgbWnEmWR6eSBjemFzZW0gYSBwcnp5xZtwaWVzemVuaWVtIiwNCiAgICBjYXB0aW9uID0gIkRhbmUgxbpyw7NkxYJvd2U6IFBha2lldCAnTUFTUyciDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKyAgDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpICANCiAgKQ0KYGBgDQoNCiMjIEVzdHltYWNqYSBuaWVsaW5pb3dlaiB6YWxlxbxub8WbY2kNCg0KUG9uacW8ZWogd3lrb3J6eXN0YW5vIG1ldG9kxJkgbG9jcG9seSgpIHogcGFraWV0dSBLZXJuU21vb3RoIGRvIGVzdHltYWNqaSBuaWVsaW5pb3dlaiB6YWxlxbxub8WbY2ksIGdkemllIHN0b3BpZcWEIHBvbGlub211IHd5bm9zaSAyLCBhIHN6ZXJva2/Fm8SHIHBhc21hIHVzdGFsb25vIG5hIHBpxJnEhy4gDQoNCmBgYHtyfQ0KZml0MiA8LSBsb2Nwb2x5KHRpbWVzLCBhY2NlbCwNCiAgICAgICAgICAgICAgICBkZWdyZWU9MiwgYmFuZHdpZHRoPTUpICU+JSBhc190aWJibGUoKQ0KZ2dwbG90KG1jeWNsZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXRpbWVzLHk9YWNjZWwpKSArDQogIGdlb21fbGluZShkYXRhPWZpdDIsIGFlcyh4PXgseT15KSwgY29sPSdyZWQnKSsNCiAgZ2d0aXRsZSgiUmVsYWNqYSBtacSZZHp5IGN6YXNlbSBhIHByenlzcGllc3plbmllbSIpKw0KICB0aGVtZV9taW5pbWFsKCkgKyAgDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpICANCiAgKQ0KYGBgDQoNCiMjIEludGVycG9sYWNqYSBzcGxvdMOzdw0KDQpgYGB7cn0NCnRpbWVzX3VuaXF1ZSA8LSB0aW1lcyArIHJub3JtKGxlbmd0aCh0aW1lcyksIDAsIDFlLTYpDQpzbXIxIDwtIHNtb290aC5zcGxpbmUodGltZXNfdW5pcXVlLCBhY2NlbCwgY3Y9VFJVRSkNCnNtcjEgPC0gZGF0YS5mcmFtZSh4PXNtcjEkeCx5PXNtcjEkeSkNCmdncGxvdChtY3ljbGUpICsNCiAgZ2VvbV9wb2ludChhZXMoeD10aW1lcyx5PWFjY2VsKSkgKw0KICBnZ3RpdGxlKCJTcGxvdHkgaW50ZXJwb2x1asSFY2UsIGxhbWJkYSB3eWJyYW5hIHByemV6IENWIikgKw0KICBnZW9tX2xpbmUoZGF0YT1zbXIxLCBhZXMoeD14LCB5PXkpLCBjb2w9J3JlZCcpICsNCiAgICB0aGVtZV9taW5pbWFsKCkgKyAgDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpICANCiAgKQ0KYGBgDQoNCkRhbmUgd3lrYXp1asSFIHd5cmHFum5lIG9zY3lsYWNqZSBwcnp5c3BpZXN6ZW5pYSB3IHphbGXFvG5vxZtjaSBvZCBjemFzdS4gTmEgcG9jesSFdGt1IHByenlzcGllc3plbmllIHNwYWRhLCBvc2nEhWdhasSFYyBtaW5pbXVtIG9rb8WCbyBjemFzdSAyMCwgcG8gY3p5bSBnd2HFgnRvd25pZSB3enJhc3RhIGRvIG1ha3NpbXVtIG9rb8WCbyBjemFzdSAzMC4gTmFzdMSZcG5pZSBwb25vd25pZSBzcGFkYSBpIHN0YWJpbGl6dWplIHNpxJkgbmEgcG96aW9taWUgemJsacW8b255bSBkbyB6ZXJhLCB3c2thenVqxIVjIG5hIHd5Z2FzemVuaWUgb3NjeWxhY2ppLg0KDQpLcnp5d2EgdXp5c2thbmEgemEgcG9tb2PEhSBtZXRvZHkgc21vb3RoIHNwbGluZSBza3V0ZWN6bmllIG9kd3pvcm93dWplIG9nw7NsbsSFIHRlbmRlbmNqxJkgdyBkYW55Y2gsIGRvc3Rvc293dWrEhWMgc2nEmSBkbyB6bWllbm5vxZtjaSBwcnp5c3BpZXN6ZW5pYSB3IG1pYXLEmSB1cMWCeXd1IGN6YXN1LiBXeWLDs3Igd2FydG/Fm2NpIHBhcmFtZXRydSBsYW1iZGEgcG9wcnpleiB3YWxpZGFjasSZIGtyennFvG93xIUgcG96d2FsYSBuYSBvcHR5bWFsbmUgd3lnxYJhZHplbmllLCBjbyBvem5hY3phLCDFvGUga3J6eXdhIGRvYnJ6ZSBvZGRhamUgb2fDs2xueSB3em9yemVjIGJleiBuYWRtaWVybmVnbyBkb3Bhc293YW5pYSBkbyBsb2thbG55Y2ggZmx1a3R1YWNqaS4NCg0KV3lrb3J6eXN0YW5pZSBzcGxpbmUnw7N3IHBvendhbGEgbmEgd3ljaHd5Y2VuaWUgaSBvZGRhbmllIHptaWFuIHcgcHJ6eXNwaWVzemVuaXUsIHV3emdsxJlkbmlhasSFYyB6YXLDs3dubyBnd2HFgnRvd25lIHd6cm9zdHkgaSBzcGFka2ksIGphayBpIHN0YWJpbGl6YWNqxJkgbmEga2/FhGN1LiBEemnEmWtpIHRlbXUga3J6eXdhIGplc3QgcMWCeW5uYSwgYWxlIG5pZSB0cmFjaSBzemN6ZWfDs8WCw7N3IGNoYXJha3RlcnlzdHljem55Y2ggZGxhIGRhbnljaCwgY28gZGFqZSBwZcWCbmllanN6eSBvYnJheiBkeW5hbWlraSBwcnp5c3BpZXN6ZW5pYSB3IGZ1bmtjamkgY3phc3UuDQoNCg0K