library(car)
library(KernSmooth)
library(tidyverse)
library(ggplot2)
library(splines)
library(MASS)

1 Zadanie 1

Zestaw danych “Prestige” (z pakietu “car”) zawiera dane nt. prestiżu n=102 Kanadyjskich zawodów z 1971 roku, a także średni dochód w danym zawodzie. Do zbadania zależności między prestiżem a dochodem wykorzystaj metody regresji nieparametrycznej.

Najpierw załaduj dane i zwizualizuj relację pomiędzy dochodem (X) a prestiżem (Y).

Prestige$income <- as.numeric(Prestige$income)
Prestige$prestige <- as.numeric(Prestige$prestige)
ggplot(Prestige)+
  geom_point(aes(x=income, y=prestige),colour='red')

Patrząc na wykres powiązania pomiędzy income a prestige widzim że kropki układają w sposób sugerujący że związek tych czynników jest nieliniowy. Dla zawodów, które zarabiają mniej niż $10K,widzimy , że wartości zależności pomiędzy dochodem a prestiżem układają się nieliniowo. W przypadku zawodów, które zarabiają od 10 do 25 tysięcy dolarów, związek ten ma znacznie inne nachylenie.

1.1 Metoda lokalnego wygładzania-Local polynomial regression (locpoly)

Główne parametry, takie jak degree i bandwidth, mają kluczowy wpływ na sposób, w jaki wygładzana jest zależność. Parametr degree określa stopień wielomianu użytego do lokalnej aproksymacji. Parametr bandwidth określa szerokość pasma, które jest używane do wygładzania.

Degree=0 ->lokalna średnich (regresja najbliższych sąsiadów)

Degree=1 -> lokalnej regresja liniowa

Degree=2 ->lokalna regresja kwadratowa

1.1.1 Porównanie różnych bandwidth

fit1a <- locpoly(income,prestige, 
        degree=0, bandwidth=800,gridsize = 100000) %>% as.tibble

ggplot(Prestige) +
  geom_point(aes(x=income,y=prestige)) +
  geom_line(data=fit1a, aes(x=x,y=y), col='blue')+
  ggtitle("Szerokość pasma równa 800")+
  labs(subtitle = "Kernel Smothing")

Zwiększam szerokość pasma do 5

fit1b <- locpoly(income,prestige,
        degree=0, bandwidth=1000,gridsize = 260000) %>% as.tibble

ggplot(Prestige) +
  geom_point(aes(x=income,y=prestige)) +
  geom_line(data=fit1b, aes(x=x,y=y), col='red')+
  ggtitle("Szerokość pasma równa 1000")+
  labs(subtitle = "Kernel Smothing")

Porównanie:

Niebieska linia: szerokość pasma 1 Czerwona linia: szerokość pasma 5

ggplot(Prestige) +
  geom_point(aes(x=income,y=prestige)) +
  geom_line(data=fit1a, aes(x=x,y=y), col='blue')+
  geom_line(data=fit1b, aes(x=x,y=y), col='red')+
  ggtitle("Porówananie dwóch szerokości pasm")+
  labs(subtitle = "Kernel Smothing")

Aby dopasować szerokośc pasma - cross validation

dopasowana <- dpill(income,prestige)
fit1d <- locpoly(income,prestige,
        degree=0, bandwidth=dopasowana) %>% as.tibble

ggplot(Prestige) +
  geom_point(aes(x=income, y=prestige))+
  geom_line(data=fit1d, aes(x=x,y=y), col='lightgreen',size=1)+
ggtitle("Dopasowana szerokość pasma wynosi:", round(dopasowana, 4))

1.1.2 Porównanie różnych degree (stopień wielomianu)

fit2a <- locpoly(income,prestige,
        degree=0, bandwidth=dopasowana) %>% as.tibble
fit2b <- locpoly(income,prestige,
        degree=1, bandwidth=dopasowana) %>% as.tibble
fit2c <- locpoly(income,prestige,
        degree=2, bandwidth=dopasowana) %>% as.tibble

ggplot(Prestige) +
  geom_point(aes(income,prestige)) +
  geom_line(data=fit2a, aes(x=x,y=y), col='darkblue',size=0.8)+
  geom_line(data=fit2b, aes(x=x,y=y), col='hotpink',size=0.8)+
  geom_line(data=fit2c, aes(x=x,y=y), col='darkgoldenrod2',size=0.8)+
  ggtitle("Porówananie trzech stopni wielomianu")

Można zauważyć, że wybór degree wpływa na funkcję gęstości na wykresie. W przypadku degree=0 występuje underfitting. Lepszym wyborem byłoby degree równe 1 lub 2.

1.2 Lokalnie kwadratowy-Loess

smr1 <- loess (prestige~income,span=0.75, degree=1,
               family="gaussian")

ggplot(Prestige) +
  geom_point(aes(x=income,y=prestige))+
  geom_line(aes(x=income,y=fitted(smr1)), col='blueviolet',size=1)

smr2 <- loess (prestige~income,span=0.75, degree=2,
               family="gaussian")

ggplot(Prestige) +
  geom_point(aes(x=income,y=prestige))+
  geom_line(aes(x=income,y=fitted(smr2)), col='darkgoldenrod',size=1)

ggplot(Prestige) +
  geom_point(x=income,y=prestige)+
  geom_smooth(aes(x=income,y=prestige),method='loess',span=0.22)

1.3 Sploty interpolujące - smooth.spline

1.3.1 Zmienianie parametru ‘spar’

fit3a <-smooth.spline(income,prestige,spar=0.2) 
smr3a <- data.frame(x=fit3a$x,y=fit3a$y)

fit3b <-smooth.spline(income,prestige, spar=0.8) 
smr3b <- data.frame(x=fit3b$x,y=fit3b$y)

ggplot(Prestige) +
  geom_point(aes(x=income,y=prestige)) +
  geom_line(data=smr3a, aes(x=x,y=y), col='lawngreen',size=0.8)+
  geom_line(data=smr3b, aes(x=x,y=y), col='plum3',size=0.8)+
  ggtitle("Porównanie różnych wartości parametru 'spar'")+
  labs(subtitle = "Sploty interpolujące")

Aby automatycznie wybrać szerokośc pasma można zastosować cross validation

1.3.2 Zastosowanie cross validation (CV=TRUE)

smr3d <- smooth.spline(income,prestige,cv=TRUE)
lambda_value <- smr3d$lambda
smr3d <- data.frame(x=smr3d$x,y=smr3d$y)


ggplot(Prestige) +
  geom_point(aes(x=income,y=prestige)) +
  ggtitle("Sploty interpolujące, lambda wybrana przez CV:", round(lambda_value, 4)) +
  geom_line(data=smr3d, aes(x=x, y=y), col='darkgoldenrod2')

1.4 Porównanie funkcji locpoly i smooth.spline

Fioletowa linia - locpoly Różowa linia - smooth.spline

FIT <- locpoly(income,prestige,
        degree=1, bandwidth=dopasowana) %>% as.tibble

SMR <- smooth.spline(income,prestige,cv=TRUE)
SMR <- data.frame(x=SMR$x,y=SMR$y)

ggplot(Prestige) +
  geom_point(aes(x=income,y=prestige)) +
  geom_line(data=FIT, aes(x=x,y=y), col='blueviolet')+
  geom_line(data=SMR, aes(x=x,y=y), col='hotpink')+
ggtitle("Porównanie funkcji locpoly i smooth.spline") + 
scale_color_manual(values = c("locpoly" = "blueviolet", "smooth.spline" = "hotpink"), 
                   labels = c("locpoly", "smooth.spline")) + labs(color = "Function")

1.5 Naturalne sploty

Naturalne sploty, 6 df oznaczone kolorem niebieskim
10 df oznaczone kolorem fioletowym 12 df oznaczone kolorem zielonym

Fit1 <-lm(prestige~ns(income,df=6),Prestige)
Fit2 <-lm(prestige~ns(income,df=10),Prestige)
Fit3 <-lm(prestige~ns(income,df=12),Prestige)

ggplot(Prestige)+
  geom_point(aes(x=income,y=prestige))+
  ggtitle("Naturalne sploty")+
  geom_line(aes(x=income,y=fitted(Fit1)),col='darkblue')+
  geom_line(aes(x=income,y=fitted(Fit2)),col='darkmagenta')+
  geom_line(aes(x=income,y=fitted(Fit3)),col='darkgreen')

1.6 Sploty oraz geom_smooth()

ggplot(Prestige) +
    geom_point(aes(x=income,y=prestige)) +
    geom_smooth(aes(x=income,y=fitted(Fit1)), method='gam',
      formula = y ~ s(x,k=12), se=TRUE)

Predykcjia z przedziałem ufności 0,1

fit4 <- lm(prestige ~ ns(income, df = 6), Prestige)
pred_fit4 <- data.frame(income = Prestige$income,
                   predict(fit4, interval = "confidence"))
ggplot(Prestige, aes(x=income,y=prestige)) +
    geom_point() +
    geom_line(data = pred_fit4, aes(y = fit), color = "darkblue") +
    geom_ribbon(data = pred_fit4, aes(ymin = lwr, ymax = upr), alpha = 0.1)

2 Zadanie 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 wykorzystaj metody regresji nieparametrycznej.

Najpierw wczytaj dane i zwizualizuj zależność między czasem (X) a przyspieszeniem (Y).

Zależność wygląda na nieliniową.

Przyspieszenie jest

-stabilne od 0-15 ms

-spada gwałtownie od ok. 15-20 ms

-rośnie szybko od 20-30 ms

-spada ponownie od 30-40 ms,

-zaczyna się stabilizować

2.1 Metoda lokalnego wygładzania-Local polynomial regression (locpoly)

2.1.1 Porównanie różnych bandwidth

fit_1 <- locpoly(times, accel,
        degree=0, bandwidth=1,gridsize = 100) %>% as.tibble

ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  geom_line(data=fit_1-1, aes(x=x,y=y), col='hotpink')+
  ggtitle("Szerokość pasma równa 1")+
  labs(subtitle = "Kernel Smothing")

Zwiększam szerokość pasma do 5

fit_2 <- locpoly(times, accel,
        degree=0, bandwidth=5,gridsize = 1000) %>% as.tibble

ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  geom_line(data=fit_2, aes(x=x,y=y), col='darkblue')+
  ggtitle("Szerokość pasma równa 5")+
  labs(subtitle = "Kernel Smothing")

Porównanie:

Różowa linia: szerokość pasma 1

Niebieska linia: szerokość pasma 5

ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  geom_line(data=fit_1, aes(x=x,y=y), col='hotpink')+
  geom_line(data=fit_2, aes(x=x,y=y), col='darkblue')+
  ggtitle("Porówananie dwóch szerokości pasm")+
  labs(subtitle = "Kernel smoothing")

2.1.2 Cross validation

dopasowana_2 <- dpill(times, accel)
fit_3 <- locpoly(times, accel,
        degree=0, bandwidth=dopasowana_2) %>% as.tibble

paste("Dopasowana szerokość pasma wynosi:", round(dopasowana_2, 4))
## [1] "Dopasowana szerokość pasma wynosi: 1.4453"
ggplot(mcycle) +
  geom_point(aes(x=times,y=accel))+
  geom_line(data=fit_3, aes(x=x,y=y), col='darkmagenta',size=1)

2.1.3 Porównanie różnych degree (stopień wielomianu)

fit_1a<- locpoly(times, accel,
        degree=0, bandwidth=dopasowana_2) %>% as.tibble
fit_2a <- locpoly(times, accel,,
        degree=1, bandwidth=dopasowana_2) %>% as.tibble
fit_3a <- locpoly(times, accel,
        degree=2, bandwidth=dopasowana_2) %>% as.tibble

ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  geom_line(data=fit_1a, aes(x=x,y=y), col='darkblue',size=0.8)+
  geom_line(data=fit_2a, aes(x=x,y=y), col='hotpink',size=0.8)+
  geom_line(data=fit_3a, aes(x=x,y=y), col='darkmagenta',size=0.8)+
  ggtitle("Porówananie trzech stopni wielomianu")+
  labs(subtitle = "Kernel Smothing")

2.2 Loess - lokalnie kwadratowy

smr_1 <- loess (accel~times,span=0.75, degree=2,
               family="gaussian")

ggplot(mcycle) +
  geom_point(aes(x=times,y=accel))+
  geom_line(aes(x=times,y=fitted(smr_1)), col='darkgoldenrod2',size=1)

ggplot(mcycle) +
  geom_point(aes(x=times,y=accel))+
  geom_smooth(aes(x=times,y=accel),method='loess',span=0.22)

2.3 Sploty interpolujące - smooth.spline

2.3.1 Zmienianie parametru ‘spar’

fit_4 <-smooth.spline(times, accel, spar=0.2) 
smr_4<- data.frame(x=fit_4$x,y=fit_4$y)

fit_5 <-smooth.spline(times, accel,, spar=0.8) 
smr_5 <- data.frame(x=fit_5$x,y=fit_5$y)

ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  geom_line(data=smr_4, aes(x=x,y=y), col='blueviolet',size=0.8)+
  geom_line(data=smr_5, aes(x=x,y=y), col='darkgoldenrod2',size=0.8)+
  ggtitle("Porównanie różnych wartości parametru 'spar'")+
  labs(subtitle = "Sploty interpolujące")

Aby automatycznie wybrać szerokośc pasma można zastosować cross validation

2.3.2 Zastosowanie cross validation (CV=TRUE)

Smr_2 <- smooth.spline(times,accel,cv=TRUE)
lambda_value2<- Smr_2$lambda
Smr_2 <- data.frame(x=Smr_2$x,y=Smr_2$y)
ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  ggtitle("Sploty interpolujące, lambda wybrana przez CV", round(lambda_value2, 4))+
  geom_line(data=Smr_2, aes(x=x, y=y), col='darkblue')

2.4 Porównanie funkcji locpoly i smooth.spline

fit_6 <- locpoly(times, accel,
        degree=2, bandwidth=dopasowana) %>% as.tibble

smr_6 <- smooth.spline(times,accel,cv=TRUE)
smr_6 <- data.frame(x=smr_6$x,y=smr_6$y)

ggplot(mcycle) +
  geom_point(aes(x=times,y=accel)) +
  geom_line(data=fit_6, aes(x=x,y=y), col='skyblue')+
  geom_line(data=smr_6, aes(x=x,y=y), col='hotpink')+
  ggtitle("Porównanie funkcji locpoly i smooth.spline")

2.5 Naturalne sploty

fit_7 <-lm(accel~ns(times,df=6),mcycle)
fit_7b <-lm(accel~ns(times,df=12),mcycle)
fit_7c <-lm(accel~ns(times,df=12),mcycle)

ggplot(mcycle)+
  geom_point(aes(x=times,y=accel))+
  ggtitle("Naturalne sploty")+
  labs(subtitle = "6 kolor różowy, 10 kolor fioletowy,12 kolor granatowy")+
  geom_line(aes(x=times,y=fitted(fit_7)),col='hotpink')+
  geom_line(aes(x=times,y=fitted(fit_7b)),col='darkmagenta')+
  geom_line(aes(x=times,y=fitted(fit_7c)),col='darkblue')

2.6 Sploty oraz geom_smooth()

ggplot(mcycle) +
    geom_point(aes(x=times,y=accel)) +
    geom_smooth(aes(x=times,y=fitted(fit_7)), method='gam',
      formula = y ~ s(x,k=12), se=TRUE)

fit_8 <- lm(accel ~ ns(times, df = 6), data = mcycle)
pred_8 <- data.frame(times = mcycle$times,
                     predict(fit_8, interval = "confidence"))
colnames(pred_8) <- c("times", "fit_8", "lwr", "upr")

ggplot(mcycle, aes(x = times, y = accel)) +
  geom_point() +
  geom_line(data = pred_8, aes(x = times, y = fit_8), color = "blueviolet") +
  geom_ribbon(data = pred_8, aes(x = times, ymin = lwr, ymax = upr), alpha = 0.1) 

LS0tDQp0aXRsZTogIlJhcG9ydCAzIg0Kc3VidGl0bGU6ICJSZWdyZXNqYSBuaWVwYXJhbWV0cnljem5hIg0KYXV0aG9yOiAiUGF1bGluYSBGZXJlbmllYyINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlDQogICAgZm9udHNpemU6IDhwdA0KICAgIHRvYzogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IGZhbHNlDQplZGl0b3Jfb3B0aW9uczogDQogIG1hcmtkb3duOiANCiAgICB3cmFwOiA3Mg0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShjYXIpDQpsaWJyYXJ5KEtlcm5TbW9vdGgpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc3BsaW5lcykNCmxpYnJhcnkoTUFTUykNCmBgYA0KDQojIFphZGFuaWUgMSANCg0KWmVzdGF3IGRhbnljaCDigJxQcmVzdGlnZeKAnSAoeiBwYWtpZXR1IOKAnGNhcuKAnSkgemF3aWVyYSBkYW5lIG50LiBwcmVzdGnFvHUgbj0xMDIgS2FuYWR5anNraWNoIHphd29kw7N3IHogMTk3MSByb2t1LCBhIHRha8W8ZSDFm3JlZG5pIGRvY2jDs2QgdyBkYW55bSB6YXdvZHppZS4gRG8gemJhZGFuaWEgemFsZcW8bm/Fm2NpIG1pxJlkenkgcHJlc3RpxbxlbSBhIGRvY2hvZGVtIHd5a29yenlzdGFqIG1ldG9keSByZWdyZXNqaSBuaWVwYXJhbWV0cnljem5lai4NCg0KTmFqcGllcncgemHFgmFkdWogZGFuZSBpIHp3aXp1YWxpenVqIHJlbGFjasSZIHBvbWnEmWR6eSBkb2Nob2RlbSAoWCkgYSBwcmVzdGnFvGVtIChZKS4NCg0KYGBge3IsZWNobz1GQUxTRSx3YXJuaW5nPUZBTFNFLGluY2x1ZGU9RkFMU0V9DQpkYXRhKCJQcmVzdGlnZSIpDQphdHRhY2goUHJlc3RpZ2UpDQpgYGANCg0KYGBge3J9DQpQcmVzdGlnZSRpbmNvbWUgPC0gYXMubnVtZXJpYyhQcmVzdGlnZSRpbmNvbWUpDQpQcmVzdGlnZSRwcmVzdGlnZSA8LSBhcy5udW1lcmljKFByZXN0aWdlJHByZXN0aWdlKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KFByZXN0aWdlKSsNCiAgZ2VvbV9wb2ludChhZXMoeD1pbmNvbWUsIHk9cHJlc3RpZ2UpLGNvbG91cj0ncmVkJykNCmBgYA0KUGF0cnrEhWMgbmEgd3lrcmVzIHBvd2nEhXphbmlhIHBvbWnEmWR6eSBpbmNvbWUgYSBwcmVzdGlnZSB3aWR6aW0gxbxlIGtyb3BraSB1a8WCYWRhasSFIHcgc3Bvc8OzYiBzdWdlcnVqxIVjeSDFvGUgendpxIV6ZWsgdHljaCBjenlubmlrw7N3IGplc3QgIG5pZWxpbmlvd3kuIA0KRGxhIHphd29kw7N3LCBrdMOzcmUgemFyYWJpYWrEhSBtbmllaiBuacW8ICQxMEssd2lkemlteSAsIMW8ZSB3YXJ0b8WbY2kgemFsZcW8bm/Fm2NpIHBvbWnEmWR6eSBkb2Nob2RlbSBhIHByZXN0acW8ZW0gdWvFgmFkYWrEhSBzacSZIG5pZWxpbmlvd28uIA0KVyBwcnp5cGFka3UgemF3b2TDs3csIGt0w7NyZSB6YXJhYmlhasSFIG9kIDEwIGRvIDI1IHR5c2nEmWN5IGRvbGFyw7N3LCB6d2nEhXplayB0ZW4gbWEgem5hY3puaWUgaW5uZSBuYWNoeWxlbmllLg0KDQoNCg0KIyMgTWV0b2RhIGxva2FsbmVnbyB3eWfFgmFkemFuaWEtTG9jYWwgcG9seW5vbWlhbCByZWdyZXNzaW9uIChsb2Nwb2x5KSANCg0KR8WCw7N3bmUgcGFyYW1ldHJ5LCB0YWtpZSBqYWsgZGVncmVlIGkgYmFuZHdpZHRoLCBtYWrEhSBrbHVjem93eSB3cMWCeXcgbmEgc3Bvc8OzYiwgdyBqYWtpIHd5Z8WCYWR6YW5hIGplc3QgemFsZcW8bm/Fm8SHLg0KUGFyYW1ldHIgZGVncmVlIG9rcmXFm2xhIHN0b3BpZcWEIHdpZWxvbWlhbnUgdcW8eXRlZ28gZG8gbG9rYWxuZWogYXByb2tzeW1hY2ppLiANClBhcmFtZXRyIGJhbmR3aWR0aCBva3JlxZtsYSBzemVyb2tvxZvEhyBwYXNtYSwga3TDs3JlIGplc3QgdcW8eXdhbmUgZG8gd3lnxYJhZHphbmlhLg0KDQpEZWdyZWU9MCAtPmxva2FsbmEgxZtyZWRuaWNoIChyZWdyZXNqYSBuYWpibGnFvHN6eWNoIHPEhXNpYWTDs3cpIA0KDQpEZWdyZWU9MSAtPiBsb2thbG5laiByZWdyZXNqYSBsaW5pb3dhIA0KDQpEZWdyZWU9MiAtPmxva2FsbmEgcmVncmVzamEga3dhZHJhdG93YQ0KDQoNCiMjIyBQb3LDs3duYW5pZSByw7PFvG55Y2ggYmFuZHdpZHRoDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpmaXQxYSA8LSBsb2Nwb2x5KGluY29tZSxwcmVzdGlnZSwgDQogICAgICAgIGRlZ3JlZT0wLCBiYW5kd2lkdGg9ODAwLGdyaWRzaXplID0gMTAwMDAwKSAlPiUgYXMudGliYmxlDQoNCmdncGxvdChQcmVzdGlnZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PWluY29tZSx5PXByZXN0aWdlKSkgKw0KICBnZW9tX2xpbmUoZGF0YT1maXQxYSwgYWVzKHg9eCx5PXkpLCBjb2w9J2JsdWUnKSsNCiAgZ2d0aXRsZSgiU3plcm9rb8WbxIcgcGFzbWEgcsOzd25hIDgwMCIpKw0KICBsYWJzKHN1YnRpdGxlID0gIktlcm5lbCBTbW90aGluZyIpDQpgYGANCg0KWndpxJlrc3phbSBzemVyb2tvxZvEhyBwYXNtYSBkbyA1DQogIA0KYGBge3J9DQpmaXQxYiA8LSBsb2Nwb2x5KGluY29tZSxwcmVzdGlnZSwNCiAgICAgICAgZGVncmVlPTAsIGJhbmR3aWR0aD0xMDAwLGdyaWRzaXplID0gMjYwMDAwKSAlPiUgYXMudGliYmxlDQoNCmdncGxvdChQcmVzdGlnZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PWluY29tZSx5PXByZXN0aWdlKSkgKw0KICBnZW9tX2xpbmUoZGF0YT1maXQxYiwgYWVzKHg9eCx5PXkpLCBjb2w9J3JlZCcpKw0KICBnZ3RpdGxlKCJTemVyb2tvxZvEhyBwYXNtYSByw7N3bmEgMTAwMCIpKw0KICBsYWJzKHN1YnRpdGxlID0gIktlcm5lbCBTbW90aGluZyIpDQpgYGANClBvcsOzd25hbmllOg0KDQpOaWViaWVza2EgbGluaWE6IHN6ZXJva2/Fm8SHIHBhc21hIDENCkN6ZXJ3b25hIGxpbmlhOiBzemVyb2tvxZvEhyBwYXNtYSA1DQoNCmBgYHtyfQ0KZ2dwbG90KFByZXN0aWdlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9aW5jb21lLHk9cHJlc3RpZ2UpKSArDQogIGdlb21fbGluZShkYXRhPWZpdDFhLCBhZXMoeD14LHk9eSksIGNvbD0nYmx1ZScpKw0KICBnZW9tX2xpbmUoZGF0YT1maXQxYiwgYWVzKHg9eCx5PXkpLCBjb2w9J3JlZCcpKw0KICBnZ3RpdGxlKCJQb3LDs3dhbmFuaWUgZHfDs2NoIHN6ZXJva2/Fm2NpIHBhc20iKSsNCiAgbGFicyhzdWJ0aXRsZSA9ICJLZXJuZWwgU21vdGhpbmciKQ0KYGBgDQoNCg0KDQpBYnkgZG9wYXNvd2HEhyBzemVyb2tvxZtjIHBhc21hIC0gY3Jvc3MgdmFsaWRhdGlvbg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KDQpkb3Bhc293YW5hIDwtIGRwaWxsKGluY29tZSxwcmVzdGlnZSkNCmZpdDFkIDwtIGxvY3BvbHkoaW5jb21lLHByZXN0aWdlLA0KICAgICAgICBkZWdyZWU9MCwgYmFuZHdpZHRoPWRvcGFzb3dhbmEpICU+JSBhcy50aWJibGUNCg0KZ2dwbG90KFByZXN0aWdlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9aW5jb21lLCB5PXByZXN0aWdlKSkrDQogIGdlb21fbGluZShkYXRhPWZpdDFkLCBhZXMoeD14LHk9eSksIGNvbD0nbGlnaHRncmVlbicsc2l6ZT0xKSsNCmdndGl0bGUoIkRvcGFzb3dhbmEgc3plcm9rb8WbxIcgcGFzbWEgd3lub3NpOiIsIHJvdW5kKGRvcGFzb3dhbmEsIDQpKQ0KYGBgDQoNCiMjIyBQb3LDs3duYW5pZSByw7PFvG55Y2ggZGVncmVlIChzdG9waWXFhCB3aWVsb21pYW51KQ0KDQpgYGB7cn0NCmZpdDJhIDwtIGxvY3BvbHkoaW5jb21lLHByZXN0aWdlLA0KICAgICAgICBkZWdyZWU9MCwgYmFuZHdpZHRoPWRvcGFzb3dhbmEpICU+JSBhcy50aWJibGUNCmZpdDJiIDwtIGxvY3BvbHkoaW5jb21lLHByZXN0aWdlLA0KICAgICAgICBkZWdyZWU9MSwgYmFuZHdpZHRoPWRvcGFzb3dhbmEpICU+JSBhcy50aWJibGUNCmZpdDJjIDwtIGxvY3BvbHkoaW5jb21lLHByZXN0aWdlLA0KICAgICAgICBkZWdyZWU9MiwgYmFuZHdpZHRoPWRvcGFzb3dhbmEpICU+JSBhcy50aWJibGUNCg0KZ2dwbG90KFByZXN0aWdlKSArDQogIGdlb21fcG9pbnQoYWVzKGluY29tZSxwcmVzdGlnZSkpICsNCiAgZ2VvbV9saW5lKGRhdGE9Zml0MmEsIGFlcyh4PXgseT15KSwgY29sPSdkYXJrYmx1ZScsc2l6ZT0wLjgpKw0KICBnZW9tX2xpbmUoZGF0YT1maXQyYiwgYWVzKHg9eCx5PXkpLCBjb2w9J2hvdHBpbmsnLHNpemU9MC44KSsNCiAgZ2VvbV9saW5lKGRhdGE9Zml0MmMsIGFlcyh4PXgseT15KSwgY29sPSdkYXJrZ29sZGVucm9kMicsc2l6ZT0wLjgpKw0KICBnZ3RpdGxlKCJQb3LDs3dhbmFuaWUgdHJ6ZWNoIHN0b3BuaSB3aWVsb21pYW51IikNCmBgYA0KDQpNb8W8bmEgemF1d2HFvHnEhywgxbxlIHd5YsOzciBkZWdyZWUgd3DFgnl3YSBuYSBmdW5rY2rEmSBnxJlzdG/Fm2NpIG5hIHd5a3Jlc2llLiBXIHByenlwYWRrdSBkZWdyZWU9MCB3eXN0xJlwdWplIHVuZGVyZml0dGluZy4gTGVwc3p5bSB3eWJvcmVtIGJ5xYJvYnkgZGVncmVlIHLDs3duZSAxIGx1YiAyLg0KDQojIyBMb2thbG5pZSBrd2FkcmF0b3d5LUxvZXNzDQoNCmBgYHtyfQ0Kc21yMSA8LSBsb2VzcyAocHJlc3RpZ2V+aW5jb21lLHNwYW49MC43NSwgZGVncmVlPTEsDQogICAgICAgICAgICAgICBmYW1pbHk9ImdhdXNzaWFuIikNCg0KZ2dwbG90KFByZXN0aWdlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9aW5jb21lLHk9cHJlc3RpZ2UpKSsNCiAgZ2VvbV9saW5lKGFlcyh4PWluY29tZSx5PWZpdHRlZChzbXIxKSksIGNvbD0nYmx1ZXZpb2xldCcsc2l6ZT0xKQ0KYGBgDQpgYGB7cn0NCnNtcjIgPC0gbG9lc3MgKHByZXN0aWdlfmluY29tZSxzcGFuPTAuNzUsIGRlZ3JlZT0yLA0KICAgICAgICAgICAgICAgZmFtaWx5PSJnYXVzc2lhbiIpDQoNCmdncGxvdChQcmVzdGlnZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PWluY29tZSx5PXByZXN0aWdlKSkrDQogIGdlb21fbGluZShhZXMoeD1pbmNvbWUseT1maXR0ZWQoc21yMikpLCBjb2w9J2Rhcmtnb2xkZW5yb2QnLHNpemU9MSkNCmBgYA0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpnZ3Bsb3QoUHJlc3RpZ2UpICsNCiAgZ2VvbV9wb2ludCh4PWluY29tZSx5PXByZXN0aWdlKSsNCiAgZ2VvbV9zbW9vdGgoYWVzKHg9aW5jb21lLHk9cHJlc3RpZ2UpLG1ldGhvZD0nbG9lc3MnLHNwYW49MC4yMikNCmBgYA0KDQojIyBTcGxvdHkgaW50ZXJwb2x1asSFY2UgLSBzbW9vdGguc3BsaW5lDQoNCiMjIyBabWllbmlhbmllIHBhcmFtZXRydSAnc3BhcicNCg0KYGBge3J9DQoNCmZpdDNhIDwtc21vb3RoLnNwbGluZShpbmNvbWUscHJlc3RpZ2Usc3Bhcj0wLjIpIA0Kc21yM2EgPC0gZGF0YS5mcmFtZSh4PWZpdDNhJHgseT1maXQzYSR5KQ0KDQpmaXQzYiA8LXNtb290aC5zcGxpbmUoaW5jb21lLHByZXN0aWdlLCBzcGFyPTAuOCkgDQpzbXIzYiA8LSBkYXRhLmZyYW1lKHg9Zml0M2IkeCx5PWZpdDNiJHkpDQoNCmdncGxvdChQcmVzdGlnZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PWluY29tZSx5PXByZXN0aWdlKSkgKw0KICBnZW9tX2xpbmUoZGF0YT1zbXIzYSwgYWVzKHg9eCx5PXkpLCBjb2w9J2xhd25ncmVlbicsc2l6ZT0wLjgpKw0KICBnZW9tX2xpbmUoZGF0YT1zbXIzYiwgYWVzKHg9eCx5PXkpLCBjb2w9J3BsdW0zJyxzaXplPTAuOCkrDQogIGdndGl0bGUoIlBvcsOzd25hbmllIHLDs8W8bnljaCB3YXJ0b8WbY2kgcGFyYW1ldHJ1ICdzcGFyJyIpKw0KICBsYWJzKHN1YnRpdGxlID0gIlNwbG90eSBpbnRlcnBvbHVqxIVjZSIpDQpgYGANCg0KQWJ5IGF1dG9tYXR5Y3puaWUgd3licmHEhyBzemVyb2tvxZtjIHBhc21hIG1vxbxuYSB6YXN0b3Nvd2HEhyBjcm9zcyB2YWxpZGF0aW9uDQoNCiMjIyBaYXN0b3Nvd2FuaWUgY3Jvc3MgdmFsaWRhdGlvbiAoQ1Y9VFJVRSkNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCnNtcjNkIDwtIHNtb290aC5zcGxpbmUoaW5jb21lLHByZXN0aWdlLGN2PVRSVUUpDQpsYW1iZGFfdmFsdWUgPC0gc21yM2QkbGFtYmRhDQpzbXIzZCA8LSBkYXRhLmZyYW1lKHg9c21yM2QkeCx5PXNtcjNkJHkpDQoNCg0KZ2dwbG90KFByZXN0aWdlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9aW5jb21lLHk9cHJlc3RpZ2UpKSArDQogIGdndGl0bGUoIlNwbG90eSBpbnRlcnBvbHVqxIVjZSwgbGFtYmRhIHd5YnJhbmEgcHJ6ZXogQ1Y6Iiwgcm91bmQobGFtYmRhX3ZhbHVlLCA0KSkgKw0KICBnZW9tX2xpbmUoZGF0YT1zbXIzZCwgYWVzKHg9eCwgeT15KSwgY29sPSdkYXJrZ29sZGVucm9kMicpDQpgYGANCg0KIyMgUG9yw7N3bmFuaWUgZnVua2NqaSBsb2Nwb2x5IGkgc21vb3RoLnNwbGluZQ0KDQpGaW9sZXRvd2EgbGluaWEgLSBsb2Nwb2x5DQpSw7PFvG93YSBsaW5pYSAtIHNtb290aC5zcGxpbmUNCg0KYGBge3Isd2FybmluZz1GQUxTRX0NCkZJVCA8LSBsb2Nwb2x5KGluY29tZSxwcmVzdGlnZSwNCiAgICAgICAgZGVncmVlPTEsIGJhbmR3aWR0aD1kb3Bhc293YW5hKSAlPiUgYXMudGliYmxlDQoNClNNUiA8LSBzbW9vdGguc3BsaW5lKGluY29tZSxwcmVzdGlnZSxjdj1UUlVFKQ0KU01SIDwtIGRhdGEuZnJhbWUoeD1TTVIkeCx5PVNNUiR5KQ0KDQpnZ3Bsb3QoUHJlc3RpZ2UpICsNCiAgZ2VvbV9wb2ludChhZXMoeD1pbmNvbWUseT1wcmVzdGlnZSkpICsNCiAgZ2VvbV9saW5lKGRhdGE9RklULCBhZXMoeD14LHk9eSksIGNvbD0nYmx1ZXZpb2xldCcpKw0KICBnZW9tX2xpbmUoZGF0YT1TTVIsIGFlcyh4PXgseT15KSwgY29sPSdob3RwaW5rJykrDQpnZ3RpdGxlKCJQb3LDs3duYW5pZSBmdW5rY2ppIGxvY3BvbHkgaSBzbW9vdGguc3BsaW5lIikgKyANCnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJsb2Nwb2x5IiA9ICJibHVldmlvbGV0IiwgInNtb290aC5zcGxpbmUiID0gImhvdHBpbmsiKSwgDQogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygibG9jcG9seSIsICJzbW9vdGguc3BsaW5lIikpICsgbGFicyhjb2xvciA9ICJGdW5jdGlvbiIpDQoNCmBgYA0KDQojIyBOYXR1cmFsbmUgc3Bsb3R5DQoNCk5hdHVyYWxuZSBzcGxvdHksIA0KNiBkZiBvem5hY3pvbmUga29sb3JlbSBuaWViaWVza2ltICANCjEwIGRmIG96bmFjem9uZSBrb2xvcmVtIGZpb2xldG93eW0NCjEyIGRmIG96bmFjem9uZSBrb2xvcmVtIHppZWxvbnltDQoNCmBgYHtyfQ0KRml0MSA8LWxtKHByZXN0aWdlfm5zKGluY29tZSxkZj02KSxQcmVzdGlnZSkNCkZpdDIgPC1sbShwcmVzdGlnZX5ucyhpbmNvbWUsZGY9MTApLFByZXN0aWdlKQ0KRml0MyA8LWxtKHByZXN0aWdlfm5zKGluY29tZSxkZj0xMiksUHJlc3RpZ2UpDQoNCmdncGxvdChQcmVzdGlnZSkrDQogIGdlb21fcG9pbnQoYWVzKHg9aW5jb21lLHk9cHJlc3RpZ2UpKSsNCiAgZ2d0aXRsZSgiTmF0dXJhbG5lIHNwbG90eSIpKw0KICBnZW9tX2xpbmUoYWVzKHg9aW5jb21lLHk9Zml0dGVkKEZpdDEpKSxjb2w9J2RhcmtibHVlJykrDQogIGdlb21fbGluZShhZXMoeD1pbmNvbWUseT1maXR0ZWQoRml0MikpLGNvbD0nZGFya21hZ2VudGEnKSsNCiAgZ2VvbV9saW5lKGFlcyh4PWluY29tZSx5PWZpdHRlZChGaXQzKSksY29sPSdkYXJrZ3JlZW4nKQ0KYGBgDQoNCiMjIFNwbG90eSBvcmF6IGdlb21fc21vb3RoKCkNCg0KYGBge3J9DQpnZ3Bsb3QoUHJlc3RpZ2UpICsNCiAgICBnZW9tX3BvaW50KGFlcyh4PWluY29tZSx5PXByZXN0aWdlKSkgKw0KICAgIGdlb21fc21vb3RoKGFlcyh4PWluY29tZSx5PWZpdHRlZChGaXQxKSksIG1ldGhvZD0nZ2FtJywNCiAgICAgIGZvcm11bGEgPSB5IH4gcyh4LGs9MTIpLCBzZT1UUlVFKQ0KYGBgDQogUHJlZHlrY2ppYSB6IHByemVkemlhxYJlbSB1Zm5vxZtjaSAwLDENCiANCmBgYHtyfQ0KZml0NCA8LSBsbShwcmVzdGlnZSB+IG5zKGluY29tZSwgZGYgPSA2KSwgUHJlc3RpZ2UpDQpwcmVkX2ZpdDQgPC0gZGF0YS5mcmFtZShpbmNvbWUgPSBQcmVzdGlnZSRpbmNvbWUsDQogICAgICAgICAgICAgICAgICAgcHJlZGljdChmaXQ0LCBpbnRlcnZhbCA9ICJjb25maWRlbmNlIikpDQpnZ3Bsb3QoUHJlc3RpZ2UsIGFlcyh4PWluY29tZSx5PXByZXN0aWdlKSkgKw0KICAgIGdlb21fcG9pbnQoKSArDQogICAgZ2VvbV9saW5lKGRhdGEgPSBwcmVkX2ZpdDQsIGFlcyh5ID0gZml0KSwgY29sb3IgPSAiZGFya2JsdWUiKSArDQogICAgZ2VvbV9yaWJib24oZGF0YSA9IHByZWRfZml0NCwgYWVzKHltaW4gPSBsd3IsIHltYXggPSB1cHIpLCBhbHBoYSA9IDAuMSkNCmBgYA0KDQojIFphZGFuaWUgMiANCg0KWmJpw7NyIGRhbnljaCDigJxtY3ljbGXigJ0gKHogcGFraWV0dSBNQVNTKSB6YXdpZXJhIG49MTMzIHBhcnkgcHVua3TDs3cgY3phc293eWNoICh3IG1zKSBpIG9ic2Vyd293YW55Y2ggcHJ6eXNwaWVzemXFhCBnxYJvd3kgKHcgZyksIGt0w7NyZSB6b3N0YcWCeSB6YXJlamVzdHJvd2FuZSB3IHN5bXVsb3dhbnltIHd5cGFka3UgbW90b2N5a2xvd3ltLg0KDQpEbyB6YmFkYW5pYSB6YWxlxbxub8WbY2kgbWnEmWR6eSBjemFzZW0gYSBwcnp5c3BpZXN6ZW5pZW0gd3lrb3J6eXN0YWogbWV0b2R5IHJlZ3Jlc2ppIG5pZXBhcmFtZXRyeWN6bmVqLg0KDQpOYWpwaWVydyB3Y3p5dGFqIGRhbmUgaSB6d2l6dWFsaXp1aiB6YWxlxbxub8WbxIcgbWnEmWR6eSBjemFzZW0gKFgpIGEgcHJ6eXNwaWVzemVuaWVtIChZKS4NCg0KYGBge3IsIGVjaG89RkFMU0Usd0FSTklORz1GQUxTRSx9DQpkYXRhKCJtY3ljbGUiKQ0KYXR0YWNoKG1jeWNsZSkNCg0KZ2dwbG90KG1jeWNsZSkrDQogIGdlb21fcG9pbnQoYWVzKHg9dGltZXMseT1hY2NlbCkpDQpgYGANClphbGXFvG5vxZvEhyB3eWdsxIVkYSBuYSBuaWVsaW5pb3fEhS4NCg0KUHJ6eXNwaWVzemVuaWUgamVzdCANCg0KLXN0YWJpbG5lIG9kIDAtMTUgbXMNCg0KLXNwYWRhIGd3YcWCdG93bmllIG9kIG9rLiAxNS0yMCBtcw0KDQotcm/Fm25pZSBzenlia28gb2QgMjAtMzAgbXMNCg0KLXNwYWRhIHBvbm93bmllIG9kIDMwLTQwIG1zLCANCg0KLXphY3p5bmEgc2nEmSBzdGFiaWxpem93YcSHDQoNCg0KIyMgTWV0b2RhIGxva2FsbmVnbyB3eWfFgmFkemFuaWEtTG9jYWwgcG9seW5vbWlhbCByZWdyZXNzaW9uIChsb2Nwb2x5KQ0KDQojIyMgUG9yw7N3bmFuaWUgcsOzxbxueWNoIGJhbmR3aWR0aA0KDQpgYGB7cn0NCmZpdF8xIDwtIGxvY3BvbHkodGltZXMsIGFjY2VsLA0KICAgICAgICBkZWdyZWU9MCwgYmFuZHdpZHRoPTEsZ3JpZHNpemUgPSAxMDApICU+JSBhcy50aWJibGUNCg0KZ2dwbG90KG1jeWNsZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXRpbWVzLHk9YWNjZWwpKSArDQogIGdlb21fbGluZShkYXRhPWZpdF8xLTEsIGFlcyh4PXgseT15KSwgY29sPSdob3RwaW5rJykrDQogIGdndGl0bGUoIlN6ZXJva2/Fm8SHIHBhc21hIHLDs3duYSAxIikrDQogIGxhYnMoc3VidGl0bGUgPSAiS2VybmVsIFNtb3RoaW5nIikNCiAgDQpgYGANCg0KWndpxJlrc3phbSBzemVyb2tvxZvEhyBwYXNtYSBkbyA1DQogIA0KYGBge3J9DQpmaXRfMiA8LSBsb2Nwb2x5KHRpbWVzLCBhY2NlbCwNCiAgICAgICAgZGVncmVlPTAsIGJhbmR3aWR0aD01LGdyaWRzaXplID0gMTAwMCkgJT4lIGFzLnRpYmJsZQ0KDQpnZ3Bsb3QobWN5Y2xlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9dGltZXMseT1hY2NlbCkpICsNCiAgZ2VvbV9saW5lKGRhdGE9Zml0XzIsIGFlcyh4PXgseT15KSwgY29sPSdkYXJrYmx1ZScpKw0KICBnZ3RpdGxlKCJTemVyb2tvxZvEhyBwYXNtYSByw7N3bmEgNSIpKw0KICBsYWJzKHN1YnRpdGxlID0gIktlcm5lbCBTbW90aGluZyIpDQpgYGANClBvcsOzd25hbmllOg0KDQpSw7PFvG93YSBsaW5pYTogc3plcm9rb8WbxIcgcGFzbWEgMQ0KDQpOaWViaWVza2EgbGluaWE6IHN6ZXJva2/Fm8SHIHBhc21hIDUNCg0KYGBge3J9DQpnZ3Bsb3QobWN5Y2xlKSArDQogIGdlb21fcG9pbnQoYWVzKHg9dGltZXMseT1hY2NlbCkpICsNCiAgZ2VvbV9saW5lKGRhdGE9Zml0XzEsIGFlcyh4PXgseT15KSwgY29sPSdob3RwaW5rJykrDQogIGdlb21fbGluZShkYXRhPWZpdF8yLCBhZXMoeD14LHk9eSksIGNvbD0nZGFya2JsdWUnKSsNCiAgZ2d0aXRsZSgiUG9yw7N3YW5hbmllIGR3w7NjaCBzemVyb2tvxZtjaSBwYXNtIikrDQogIGxhYnMoc3VidGl0bGUgPSAiS2VybmVsIHNtb290aGluZyIpDQpgYGANCg0KDQojIyMgQ3Jvc3MgdmFsaWRhdGlvbg0KDQpgYGB7cn0NCg0KZG9wYXNvd2FuYV8yIDwtIGRwaWxsKHRpbWVzLCBhY2NlbCkNCmZpdF8zIDwtIGxvY3BvbHkodGltZXMsIGFjY2VsLA0KICAgICAgICBkZWdyZWU9MCwgYmFuZHdpZHRoPWRvcGFzb3dhbmFfMikgJT4lIGFzLnRpYmJsZQ0KDQpwYXN0ZSgiRG9wYXNvd2FuYSBzemVyb2tvxZvEhyBwYXNtYSB3eW5vc2k6Iiwgcm91bmQoZG9wYXNvd2FuYV8yLCA0KSkNCg0KZ2dwbG90KG1jeWNsZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXRpbWVzLHk9YWNjZWwpKSsNCiAgZ2VvbV9saW5lKGRhdGE9Zml0XzMsIGFlcyh4PXgseT15KSwgY29sPSdkYXJrbWFnZW50YScsc2l6ZT0xKQ0KYGBgDQoNCiMjIyBQb3LDs3duYW5pZSByw7PFvG55Y2ggZGVncmVlIChzdG9waWXFhCB3aWVsb21pYW51KQ0KDQpgYGB7cn0NCmZpdF8xYTwtIGxvY3BvbHkodGltZXMsIGFjY2VsLA0KICAgICAgICBkZWdyZWU9MCwgYmFuZHdpZHRoPWRvcGFzb3dhbmFfMikgJT4lIGFzLnRpYmJsZQ0KZml0XzJhIDwtIGxvY3BvbHkodGltZXMsIGFjY2VsLCwNCiAgICAgICAgZGVncmVlPTEsIGJhbmR3aWR0aD1kb3Bhc293YW5hXzIpICU+JSBhcy50aWJibGUNCmZpdF8zYSA8LSBsb2Nwb2x5KHRpbWVzLCBhY2NlbCwNCiAgICAgICAgZGVncmVlPTIsIGJhbmR3aWR0aD1kb3Bhc293YW5hXzIpICU+JSBhcy50aWJibGUNCg0KZ2dwbG90KG1jeWNsZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXRpbWVzLHk9YWNjZWwpKSArDQogIGdlb21fbGluZShkYXRhPWZpdF8xYSwgYWVzKHg9eCx5PXkpLCBjb2w9J2RhcmtibHVlJyxzaXplPTAuOCkrDQogIGdlb21fbGluZShkYXRhPWZpdF8yYSwgYWVzKHg9eCx5PXkpLCBjb2w9J2hvdHBpbmsnLHNpemU9MC44KSsNCiAgZ2VvbV9saW5lKGRhdGE9Zml0XzNhLCBhZXMoeD14LHk9eSksIGNvbD0nZGFya21hZ2VudGEnLHNpemU9MC44KSsNCiAgZ2d0aXRsZSgiUG9yw7N3YW5hbmllIHRyemVjaCBzdG9wbmkgd2llbG9taWFudSIpKw0KICBsYWJzKHN1YnRpdGxlID0gIktlcm5lbCBTbW90aGluZyIpDQpgYGANCg0KIyMgTG9lc3MgLSBsb2thbG5pZSBrd2FkcmF0b3d5DQoNCmBgYHtyfQ0Kc21yXzEgPC0gbG9lc3MgKGFjY2VsfnRpbWVzLHNwYW49MC43NSwgZGVncmVlPTIsDQogICAgICAgICAgICAgICBmYW1pbHk9ImdhdXNzaWFuIikNCg0KZ2dwbG90KG1jeWNsZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXRpbWVzLHk9YWNjZWwpKSsNCiAgZ2VvbV9saW5lKGFlcyh4PXRpbWVzLHk9Zml0dGVkKHNtcl8xKSksIGNvbD0nZGFya2dvbGRlbnJvZDInLHNpemU9MSkNCmBgYA0KDQpgYGB7cixtZXNzYWdlPUZBTFNFfQ0KZ2dwbG90KG1jeWNsZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXRpbWVzLHk9YWNjZWwpKSsNCiAgZ2VvbV9zbW9vdGgoYWVzKHg9dGltZXMseT1hY2NlbCksbWV0aG9kPSdsb2Vzcycsc3Bhbj0wLjIyKQ0KYGBgDQoNCiMjIFNwbG90eSBpbnRlcnBvbHVqxIVjZSAtIHNtb290aC5zcGxpbmUNCg0KIyMjIFptaWVuaWFuaWUgcGFyYW1ldHJ1IOKAmHNwYXLigJkNCg0KYGBge3J9DQpmaXRfNCA8LXNtb290aC5zcGxpbmUodGltZXMsIGFjY2VsLCBzcGFyPTAuMikgDQpzbXJfNDwtIGRhdGEuZnJhbWUoeD1maXRfNCR4LHk9Zml0XzQkeSkNCg0KZml0XzUgPC1zbW9vdGguc3BsaW5lKHRpbWVzLCBhY2NlbCwsIHNwYXI9MC44KSANCnNtcl81IDwtIGRhdGEuZnJhbWUoeD1maXRfNSR4LHk9Zml0XzUkeSkNCg0KZ2dwbG90KG1jeWNsZSkgKw0KICBnZW9tX3BvaW50KGFlcyh4PXRpbWVzLHk9YWNjZWwpKSArDQogIGdlb21fbGluZShkYXRhPXNtcl80LCBhZXMoeD14LHk9eSksIGNvbD0nYmx1ZXZpb2xldCcsc2l6ZT0wLjgpKw0KICBnZW9tX2xpbmUoZGF0YT1zbXJfNSwgYWVzKHg9eCx5PXkpLCBjb2w9J2Rhcmtnb2xkZW5yb2QyJyxzaXplPTAuOCkrDQogIGdndGl0bGUoIlBvcsOzd25hbmllIHLDs8W8bnljaCB3YXJ0b8WbY2kgcGFyYW1ldHJ1ICdzcGFyJyIpKw0KICBsYWJzKHN1YnRpdGxlID0gIlNwbG90eSBpbnRlcnBvbHVqxIVjZSIpDQpgYGANCg0KQWJ5IGF1dG9tYXR5Y3puaWUgd3licmHEhyBzemVyb2tvxZtjIHBhc21hIG1vxbxuYSB6YXN0b3Nvd2HEhyBjcm9zcyB2YWxpZGF0aW9uDQoNCiMjIyBaYXN0b3Nvd2FuaWUgY3Jvc3MgdmFsaWRhdGlvbiAoQ1Y9VFJVRSkNCg0KYGBge3Igd2FybmluZz1GQUxTRX0NClNtcl8yIDwtIHNtb290aC5zcGxpbmUodGltZXMsYWNjZWwsY3Y9VFJVRSkNCmxhbWJkYV92YWx1ZTI8LSBTbXJfMiRsYW1iZGENClNtcl8yIDwtIGRhdGEuZnJhbWUoeD1TbXJfMiR4LHk9U21yXzIkeSkNCmdncGxvdChtY3ljbGUpICsNCiAgZ2VvbV9wb2ludChhZXMoeD10aW1lcyx5PWFjY2VsKSkgKw0KICBnZ3RpdGxlKCJTcGxvdHkgaW50ZXJwb2x1asSFY2UsIGxhbWJkYSB3eWJyYW5hIHByemV6IENWIiwgcm91bmQobGFtYmRhX3ZhbHVlMiwgNCkpKw0KICBnZW9tX2xpbmUoZGF0YT1TbXJfMiwgYWVzKHg9eCwgeT15KSwgY29sPSdkYXJrYmx1ZScpDQpgYGANCg0KIyMgUG9yw7N3bmFuaWUgZnVua2NqaSBsb2Nwb2x5IGkgc21vb3RoLnNwbGluZQ0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KZml0XzYgPC0gbG9jcG9seSh0aW1lcywgYWNjZWwsDQogICAgICAgIGRlZ3JlZT0yLCBiYW5kd2lkdGg9ZG9wYXNvd2FuYSkgJT4lIGFzLnRpYmJsZQ0KDQpzbXJfNiA8LSBzbW9vdGguc3BsaW5lKHRpbWVzLGFjY2VsLGN2PVRSVUUpDQpzbXJfNiA8LSBkYXRhLmZyYW1lKHg9c21yXzYkeCx5PXNtcl82JHkpDQoNCmdncGxvdChtY3ljbGUpICsNCiAgZ2VvbV9wb2ludChhZXMoeD10aW1lcyx5PWFjY2VsKSkgKw0KICBnZW9tX2xpbmUoZGF0YT1maXRfNiwgYWVzKHg9eCx5PXkpLCBjb2w9J3NreWJsdWUnKSsNCiAgZ2VvbV9saW5lKGRhdGE9c21yXzYsIGFlcyh4PXgseT15KSwgY29sPSdob3RwaW5rJykrDQogIGdndGl0bGUoIlBvcsOzd25hbmllIGZ1bmtjamkgbG9jcG9seSBpIHNtb290aC5zcGxpbmUiKQ0KYGBgDQoNCiMjIE5hdHVyYWxuZSBzcGxvdHkNCg0KDQpgYGB7cn0NCmZpdF83IDwtbG0oYWNjZWx+bnModGltZXMsZGY9NiksbWN5Y2xlKQ0KZml0XzdiIDwtbG0oYWNjZWx+bnModGltZXMsZGY9MTIpLG1jeWNsZSkNCmZpdF83YyA8LWxtKGFjY2Vsfm5zKHRpbWVzLGRmPTEyKSxtY3ljbGUpDQoNCmdncGxvdChtY3ljbGUpKw0KICBnZW9tX3BvaW50KGFlcyh4PXRpbWVzLHk9YWNjZWwpKSsNCiAgZ2d0aXRsZSgiTmF0dXJhbG5lIHNwbG90eSIpKw0KICBsYWJzKHN1YnRpdGxlID0gIjYga29sb3IgcsOzxbxvd3ksIDEwIGtvbG9yIGZpb2xldG93eSwxMiBrb2xvciBncmFuYXRvd3kiKSsNCiAgZ2VvbV9saW5lKGFlcyh4PXRpbWVzLHk9Zml0dGVkKGZpdF83KSksY29sPSdob3RwaW5rJykrDQogIGdlb21fbGluZShhZXMoeD10aW1lcyx5PWZpdHRlZChmaXRfN2IpKSxjb2w9J2RhcmttYWdlbnRhJykrDQogIGdlb21fbGluZShhZXMoeD10aW1lcyx5PWZpdHRlZChmaXRfN2MpKSxjb2w9J2RhcmtibHVlJykNCmBgYA0KDQojIyBTcGxvdHkgb3JheiBnZW9tX3Ntb290aCgpDQoNCmBgYHtyfQ0KZ2dwbG90KG1jeWNsZSkgKw0KICAgIGdlb21fcG9pbnQoYWVzKHg9dGltZXMseT1hY2NlbCkpICsNCiAgICBnZW9tX3Ntb290aChhZXMoeD10aW1lcyx5PWZpdHRlZChmaXRfNykpLCBtZXRob2Q9J2dhbScsDQogICAgICBmb3JtdWxhID0geSB+IHMoeCxrPTEyKSwgc2U9VFJVRSkNCmBgYA0KDQoNCg0KYGBge3J9DQpmaXRfOCA8LSBsbShhY2NlbCB+IG5zKHRpbWVzLCBkZiA9IDYpLCBkYXRhID0gbWN5Y2xlKQ0KcHJlZF84IDwtIGRhdGEuZnJhbWUodGltZXMgPSBtY3ljbGUkdGltZXMsDQogICAgICAgICAgICAgICAgICAgICBwcmVkaWN0KGZpdF84LCBpbnRlcnZhbCA9ICJjb25maWRlbmNlIikpDQpjb2xuYW1lcyhwcmVkXzgpIDwtIGMoInRpbWVzIiwgImZpdF84IiwgImx3ciIsICJ1cHIiKQ0KDQpnZ3Bsb3QobWN5Y2xlLCBhZXMoeCA9IHRpbWVzLCB5ID0gYWNjZWwpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fbGluZShkYXRhID0gcHJlZF84LCBhZXMoeCA9IHRpbWVzLCB5ID0gZml0XzgpLCBjb2xvciA9ICJibHVldmlvbGV0IikgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gcHJlZF84LCBhZXMoeCA9IHRpbWVzLCB5bWluID0gbHdyLCB5bWF4ID0gdXByKSwgYWxwaGEgPSAwLjEpIA0KDQoNCg0KYGBgDQoNCg==