Mit diesem Dokument werden aus den Dikablis Pupillenrohdaten mit dem Hochschule-München Lichtlabor(D113)-Setup auswertungsfähige Pupillendaten extrahiert. Die Auswertung ist gültig für das “Programm 0” aus dem Lightdome-Steuerrechner und für die “neue” Umrechnungsmethode von Pixeln zu mm, bei der vor Aufzeichnung ein Referenzmaß auf Augenebene im Kamerabild gezeigt wird. Dieses Programm beginnt mit einer Dunkeladapationsperiode von 90 Sekunden. Danach werden in ca. 15 Sekunden-Schritten die Wellenlängen von 700-400 nm in 5 nm Schritten abgefahren. Die Abfolge der Wellenlängenschritte verläuft in großen und kleinen Sprüngen. Zwischen jedem Schritt liegt eine Phase, in der die neue Wellenlänge eingestellt wird. Die Dauer dieser Phasen variiert in Abhängigkeit des Unterschieds zwischen den Wellenlängen.
Um den Code für eine neue Person anzupassen, sind die folgenden Eingriffe notwendig. Zeilenangaben beziehen sich auf das *.Rmd-File:
Zeile 37 -> Einfügen des korrekten Dateinamens / Pfad
Zeile 45 -> Versuchspersonencode einfügen
Zeilen 116-128 -> Prüfung, ob die Kriterien zur Messwertaussortierung bei Zirkularität, absolutem Abschnitt, und dem Schlussschnitt in Ordnung sind
Zeile 212-215 -> Nach Prüfung, ob die Tal-Erkennung funktioniert, Angabe des korrekten Index für den Referenzzeitpunkt. Sollte das beim linken Auge nicht möglich sein, muss der unterste Code-Chunk aus der Datei manuell hoch kopiert werden. Sollte der erste Beleuchtungszeitpunkt nicht erkannt werden, kann ein späterer Zeitpunkt angegeben werden - in diesem Fall muss spezifiziert werden, um wie viele Schritte der Programmstart zurückliegt.
Zeile 428/429 -> Die Auswahl, welches Auge schlussendlich für den Datenexport verwendet wird, wird standardmäßig automatisch vollzogen anhand der Pupille mit dem meisten Datenpunkten nach der Bereinigung. Sollte diese Auswahl nicht in Ordnung sein, muss hier manuell “R” oder “L” eingetragen werden.
Im folgenden Abschnitt werden alle notwendigen Bibliotheken geladen, sowie die Rohdaten eingelesen. Der Abschnitt endet mit einer Darstellung der Rohdaten der Pupillen, sowie der Zirkulariät.
library(tidyverse)
Es gab 11 Warnungen (Anzeige mit warnings())
library(anytime)
library(signal)
library(ggplot2)
library(cowplot)
library(ggpmisc)
library(readxl)
library(knitr)
setwd(dirname(rstudioapi::getActiveDocumentContext()$path)) # Setzen des Arbeitsverzeichnisses auf gleiches Verzeichnis wie Script
pup <- read.table("../data_input/P0/HJ081002_2_6. Messung Pr0 22.09.2020 123757_CsvData.txt", sep = "\t", header = TRUE, stringsAsFactors=F) # Einlesen der Daten Pupille
prog <- read.table("../data_input/program_data_ld.csv", dec = ",", sep = ";", header = TRUE, stringsAsFactors=F) # Einlesen der Programmdaten
corf <- read_excel("../Übersicht_VP.xlsx", sheet = "Uebersicht_VP", na="NA") #load in the file with all individual codes # Einlesen der Korrekturfaktoren
#Auswählen der notwendigen Spalten und Spalten umbenennen
#Umrechnen des UTC-Zeitstempels in lokale Zeit
#Berechnung des Pupillendurchmessers (nur für Referenzmaß - Die Korrekturfaktoren aller Probanden werden in einer separaten Datei gespeichert)
Code <- "HJ081002_c3"
dir.create(paste("../figures/", Code, sep=""))
pup <- select(pup, rec_time, UTC, Dikablis.Professional_Eye.Data_Original_Left.Eye_Pupil.Area, Dikablis.Professional_Eye.Data_Original_Left.Eye_Pupil.Height, Dikablis.Professional_Eye.Data_Original_Left.Eye_Pupil.Width, Dikablis.Professional_Eye.Data_Original_Right.Eye_Pupil.Area, Dikablis.Professional_Eye.Data_Original_Right.Eye_Pupil.Height, Dikablis.Professional_Eye.Data_Original_Right.Eye_Pupil.Width)
pup <- tibble(pup)
colnames(pup) <- c("time", "UTC", "La", "Lh", "Lw", "Ra", "Rh", "Rw")
pup$UTC <- anytime(pup$UTC/1000)
pup <- separate(pup, time, c("h", "m", "s"), sep = ":", convert = TRUE)
pup$time <- pup$s + pup$m*60 + pup$h*60*60
corf_L <- corf$Korr_Links[corf$Code == Code]
corf_R <- corf$Korr_Rechts[corf$Code == Code]
pup$Ld <- 2*sqrt(pup$La/pi)/corf_L
pup$Rd <- 2*sqrt(pup$Ra/pi)/corf_R
#Aufteilen in Pupille rechtes und linkes Auge
pupR <- select(pup, "time", "UTC", "Rd", "Ra", "Rh", "Rw")
pupR <- dplyr::filter(pupR, !is.na(Ra))
colnames(pupR) <- c("time", "UTC", "dia", "area", "height", "width")
pupL <- select(pup, "time", "UTC", "Ld", "La", "Lh", "Lw")
pupL <- dplyr::filter(pupL, !is.na(La))
colnames(pupL) <- c("time", "UTC", "dia", "area", "height", "width")
#Darstellung der Ergebnisse im Plot
# Rohdaten
Roh_plot <- ggplot() +
geom_line(data = pupL, aes(x = time, y = dia, col = "Left")) +
geom_line(data = pupR, aes(x = time, y = dia, col = "Right"), alpha = 0.6) +
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 50, y= 8), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_brewer(palette = "Set1", "Eye")+
ggtitle("Pupil-diameter data unchanged")+
ylab("Pupil diameter / mm") +
xlab("Time / seconds")+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))
Roh_plot
ggsave("Pupil_Raw.pdf", path = paste("../figures/", Code, sep=""), width=10, height = 5)

# Zirkularität
Roh_plot2 <- ggplot() +
geom_line(data = pupL, aes(x = time, y = width/height, col = "Left")) +
geom_line(data = pupR, aes(x = time, y = width/height, col = "Right"), alpha = 0.6) +
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 50, y= 1.01), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_brewer(palette = "Set1", "Eye")+
ggtitle("Pupil-circularity")+
ylab("Pupil diameter / mm") +
xlab("Time / seconds")+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))
Roh_plot2
ggsave("Pupil_Raw2.pdf", path = paste("../figures/", Code, sep=""), width=10, height = 5)

NA
NA
Im kommenden Abschnitt werden Artefakte und unplausible Messwerte entfernt. Zudem wird die Kurve geglättet.
#Entfernung von Ausreissern und Werten bei denen die Pupille eine zirkularität < 0,7 aufweist, zudem wird die letzten 2 Sekunden der Messung entfernt
pupRf <- pupR[1:(length(pupR$time)-120),]
pupRf <- dplyr::filter(pupRf, dia > 1) # Entfernung von Werten kleiner X mm
pupRf <- dplyr::filter(pupRf, dia < 8.5) # Entfernung von Werten größer 8 mm
pupRf <- dplyr::filter(pupRf, width/height > 0.70 & width/height > 0.70) # Entfernung von Werten für die die Zirkularität kleiner als 0,7 ausfällt
pupRf$dia_sm <- sgolayfilt(pupRf$dia, p=3, n=31) # Glättung der Kurve mittels Savitzky-Golay Filter
pupLf <- pupL[1:(length(pupL$time)-120),]
pupLf <- dplyr::filter(pupLf, dia > 1) # Entfernung von Werten kleiner X mm
pupLf <- dplyr::filter(pupLf, dia < 8.5) # Entfernung von Werten größer 8 mm
pupLf <- dplyr::filter(pupLf, width/height > 0.70 & width/height > 0.70) # Entfernung von Werten für die die Zirkularität kleiner als 0,7 ausfällt
pupLf$dia_sm <- sgolayfilt(pupLf$dia, p=3, n=31) # Glättung der Kurve mittels Savitzky-Golay Filter
Smooth_plot_test <- ggplot() +
geom_line(data = pupLf, aes(x = time, y = dia, col = "unsmoothed")) +
geom_line(data = pupLf, aes(x = time, y = dia_sm, col = "sg n=31"), alpha = 0.6) +
geom_line(data = pupLf, aes(x = time, y = sgolayfilt(dia, p=3, n=61), col = "sg n=61"), alpha = 0.6) +
geom_line(data = pupLf, aes(x = time, y = sgolayfilt(dia, p=3, n=91), col = "sg n=91"), alpha = 0.6) +
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 250, y= 8), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_brewer(palette = "Set1", "Eye")+
ggtitle("Pupil-diameter data smoothed, test settings")+
ylab("Pupil diameter / mm") +
xlab("Time / seconds")+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))+
coord_cartesian(xlim = c(250, 275), ylim = c(2,8))
Smooth_plot_test
ggsave("Pupil_Smooth_test.pdf", path = paste("../figures/", Code, sep=""), width=10, height = 5)

Smooth_plot <- ggplot() +
geom_line(data = pupLf, aes(x = time, y = dia_sm, col = "Left")) +
geom_line(data = pupRf, aes(x = time, y = dia_sm, col = "Right"), alpha = 0.6) +
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 50, y= 8), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_brewer(palette = "Set1", "Eye")+
ggtitle("Pupil-diameter data smoothed")+
ylab("Pupil diameter / mm") +
xlab("Time / seconds")+
coord_cartesian(ylim = c(2,8))+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))
Smooth_plot
ggsave("Pupil_Smooth.pdf", path = paste("../figures/", Code, sep=""), width=10, height = 5)

NA
NA
Im nächsten Abschnitt erfolgt die Zuordnung einzelner Zeitabschnitte zu den Wellenlängen.
#Bildung der 1. und 2. Ableitung. Lineare Transformation, damit die Überlagerung mit dem Pupillendurchmesser lesbar bleibt.
pupLf$dia_sm1 <- (sgolayfilt(pupLf$dia, p=3, n=31, m=1))*100+6
pupLf$dia_sm2 <- (sgolayfilt(pupLf$dia, p=3, n=31, m=2))*100+6
#Erkennung der Tiefpunkte der 2. Ableitung
vly <- ggplot(data = pupLf, aes(x=time, y=dia_sm2)) +
stat_valleys(span = 601, col = "green")
vly_data <- (layer_data(vly, i=1L)$xintercept)
#Darstellung der Tiefpunkte der 2. Ableitung
Derivative_test <- ggplot(data = pupLf, aes(x=time, y=dia_sm2, col="valley")) +
geom_line(data = pupLf, aes(x = time, y = dia_sm, col = "Diameter")) +
geom_line(data = pupRf, aes(x = time, y = dia_sm, col = "Diameter")) +
geom_line(aes(col = "2nd derivative"), alpha = 0.6) +
stat_valleys(span = 601, col = "green")+
geom_vline(xintercept = vly_data-0.1, lwd = 0.1, col="green")+
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 80, y= 8), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_brewer(palette = "Set1", "Type")+
ggtitle("Pupil-diameter data smoothed with 2nd derivative and valleys (-100ms)")+
ylab("Pupil diameter / mm") +
xlab("Time / seconds")+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))+
coord_cartesian(xlim = c(80, 200))
Derivative_test
ggsave("Pupil_Derivative_test.pdf", path = paste("../figures/", Code, sep=""), width=15, height = 5)

#Wahl eine Programmstartpunkts
vly_data <- tibble("index" = 1: length(vly_data), "time" = vly_data-0.1, "dif" = c(vly_data[1], diff(vly_data)))
kable(vly_data[1:20,], "pandoc", caption = "Time of 2nd derivative valleys (-100ms), first 20 rows", align = "c")# Tiefpunkte mit Zeitstempel
Time of 2nd derivative valleys (-100ms), first 20 rows
1 |
5.571 |
5.671 |
2 |
13.055 |
7.484 |
3 |
21.021 |
7.966 |
4 |
32.421 |
11.400 |
5 |
49.388 |
16.967 |
6 |
55.988 |
6.600 |
7 |
67.605 |
11.617 |
8 |
76.905 |
9.300 |
9 |
89.071 |
12.166 |
10 |
104.355 |
15.284 |
11 |
111.671 |
7.316 |
12 |
123.255 |
11.584 |
13 |
133.305 |
10.050 |
14 |
139.155 |
5.850 |
15 |
144.871 |
5.716 |
16 |
157.555 |
12.684 |
17 |
165.721 |
8.166 |
18 |
174.955 |
9.234 |
19 |
191.671 |
16.716 |
20 |
201.021 |
9.350 |
NA
time_cor <- 0
#Welcher index ist der Startzeitpunkt?
i <- 9 # Hier muss man auf Basis der Grafik und der Tabelle den Startzeitpunkt angeben
#Zeitkorrektur notwendig?
cor <- 1
pupLf$time_c <- pupLf$time - vly_data$time[vly_data$index == i] + time_cor*cor
pupRf$time_c <- pupRf$time - vly_data$time[vly_data$index == i] + time_cor*cor
#Ergänzung der Wellenlängen
wl_sec <- tibble(
"wl" = (prog$Peak_8),
"wl_b" = c(0, (cumsum(prog$intervall_0)+cumsum(prog$pause_0))[-length(prog$intervall_0)]),
"wl_e" = cumsum(prog$intervall_0)+cumsum(prog$pause_0)
)
tot_per <- sum(prog$intervall_0)+sum(prog$pause_0)
sequ <- c(0, cumsum(prog$intervall_0)+cumsum(prog$pause_0))
wl <- prog$Peak_8
pupLf$wl_step <- as.numeric(cut(pupLf$time_c,
breaks = sequ,
include.lowest = T,
right = F,
labels = wl))
pupLf$wl_time <- pupLf$time_c - wl_sec$wl_b[pupLf$wl_step]
pupLf$wl_step <- wl[pupLf$wl_step]
pupRf$wl_step <- as.numeric(cut(pupRf$time_c,
breaks = sequ,
include.lowest = T,
right = F,
labels = wl))
pupRf$wl_time <- pupRf$time_c - wl_sec$wl_b[pupRf$wl_step]
pupRf$wl_step <- wl[pupRf$wl_step]
#Darstellung der Daten mit neuem Start und den jeweiligen Wellenlängen
Timed_plot <- ggplot() +
geom_rect(data = wl_sec, aes(xmin= wl_b, xmax = wl_e, ymin = 2, ymax = 8, fill = wl))+
geom_line(data = pupLf, aes(x = time_c, y = dia_sm, col = "Left")) +
geom_line(data = pupRf, aes(x = time_c, y = dia_sm, col = "Right"), alpha = 0.6) +
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 50, y= 7.5), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_manual(values = c("grey80", "black"))+
scale_fill_gradientn(colors = c(rev(rainbow(53, start = 0, end = 0.80)), rev(rainbow(8, start = 0.94, end = 1))))+
ggtitle("Pupil-diameter during different wavelength")+
ylab("Pupil diameter / mm") +
xlab("Time / seconds")+
coord_cartesian(ylim = c(2,8))+
theme(legend.position = c(0.85,.22),legend.background = element_rect(fill="white", size = 0.5))
Timed_plot
ggsave("Timed_Smooth.pdf", path = paste("../figures/", Code, sep=""),limitsize=F, width=20, height = 5)

WL_plot <- ggplot() +
geom_line(data = pupLf, aes(x = as.factor(wl_step), y = dia_sm, col = "Left")) +
geom_line(data = pupRf, aes(x = as.factor(wl_step), y = dia_sm, col = "Right"), alpha = 0.6) +
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 50, y= 8), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_brewer(palette = "Set1", "Eye")+
ggtitle("Pupil-diameter per wavelength")+
ylab("Pupil diameter / mm") +
xlab("wavelength / nm")+
coord_cartesian(ylim = c(2,8))+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))
WL_plot
ggsave("Wavelength_Plot.pdf", path = paste("../figures/", Code, sep=""),limitsize=F, width=10, height = 5)

WL_plot2 <- ggplot() +
geom_line(data = pupLf, aes(x = wl_time, y = dia_sm, group = wl_step, col = wl_step)) +
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 0.5, y= 8), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_gradientn(colors = c(rev(rainbow(53, start = 0, end = 0.80)), rev(rainbow(8, start = 0.94, end = 1))))+
ggtitle("Pupil-diameter depending on wavelength")+
ylab("Pupil diameter / mm") +
xlab("Time / seconds")+
coord_cartesian(ylim = c(2,8))+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))
WL_plot2
ggsave("Wavelength_Plot2.pdf", path = paste("../figures/", Code, sep=""),limitsize=F, width=10, height = 7.5)

WL_plot2log <- ggplot() +
geom_line(data = pupLf, aes(x = log10(wl_time), y = dia_sm, group = wl_step, col = wl_step)) +
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = -1, y= 8), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_gradientn(colors = c(rev(rainbow(53, start = 0, end = 0.80)), rev(rainbow(8, start = 0.94, end = 1))))+
ggtitle("Pupil-diameter depending on wavelength")+
ylab("Pupil diameter / mm") +
xlab("Time / log10(seconds)")+
coord_cartesian(ylim = c(2,8), xlim = c(-1.5, log10(15)))+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))
WL_plot2log
ggsave("Wavelength_Plot2log.pdf", path = paste("../figures/", Code, sep=""),limitsize=F, width=10, height = 7.5)

Im folgenden Abschnitt werden Mittelwerte für jede Sekunde des Lichtreizes gebildet. Diese werden normiert, bezogen auf die Differenz zwischen der maximalen und minimalen Pupillenweite.
# Zunächst wird die -Baseline-Größe bestimmt. Sie wird hier definiert als der Mittelwert der Pupille in den letzten 5 Sekunden der Dunkeladaptation
# In Fällen, in denen die Pupille während der Belichtung niedrigere Werte annimmt, kann auch die größte Pupillengröße während der Belichtung gewählt werden. Dies erfolgt automatisch anhand des größeren Werts
L_norm <- as.numeric(
ifelse(pupLf %>% dplyr::filter(time_c < 0 & time_c > -5) %>% summarize(p_max = mean(dia_sm)) >
pupLf %>% dplyr::filter(time_c > 0 & time_c < tot_per) %>% summarize(p_max = max(dia_sm)),
pupLf %>% dplyr::filter(time_c < 0 & time_c > -5) %>% summarize(p_max = mean(dia_sm)),
pupLf %>% dplyr::filter(time_c > 0 & time_c < tot_per) %>% summarize(p_max = max(dia_sm))
))
# Im nächsten Schritt werden die Sekundenmittelwerte für jede Wellenlänge gebildet, zudem der Mittelwert der letzten 5 Sekunden und die minimalen Pupillengrößen für die jeweiligen Zeitintervalle
L_val <- pupLf %>% group_by(wl_step, wl_time %/% 1) %>% summarize(d_abs = mean(dia_sm))
`summarise()` regrouping output by 'wl_step' (override with `.groups` argument)
L_val10 <- pupLf %>% dplyr::filter(wl_time <= 13.9 & wl_time >= 9.9) %>% group_by(wl_step) %>% summarize(d_abs = mean(dia_sm))
`summarise()` ungrouping output (override with `.groups` argument)
names(L_val) <- c("wl", "time", "d_abs")
names(L_val10) <- c("wl", "d_abs")
temp <- L_val %>% dplyr::filter(wl != "NA") %>% group_by(time) %>% summarize(min = min(d_abs))
`summarise()` ungrouping output (override with `.groups` argument)
L_norm <- data_frame("Cond" = c("Dark", temp$time, "10_15"), "dia" = c(L_norm, temp$min, min(L_val10$d_abs)))
# Hier wird zunächst eine temporäre Variable erzeugt, welche für jede Zeile in den Sekundenmittelwertdaten die korrespondierende minimale Pupillengröße angibt.
temp <- as.numeric(as.character((cut(L_val$time,
breaks = 0:(max(prog$intervall_0+prog$pause_0) %/% 1 +1),
include.lowest = T,
right = F,
labels = L_norm$dia[2:(length(L_norm$dia)-1)]))
))
# Im folgenden Schritt werden relative Pupillenkonstriktionswerte gebildet, amp ist dabei die Konstriktionsamplitude bezogen auf die Baseline-Größe, amp2 auf die Spanne zwischen der Basline-Größe und der kleinsten, für diese Zeitspanne gemessenen Pupillengröße.
L_val$amp <- (L_norm$dia[L_norm$Cond == "Dark"] - L_val$d_abs)/L_norm$dia[L_norm$Cond == "Dark"]*100
L_val10$amp <- (L_norm$dia[L_norm$Cond == "Dark"] - L_val10$d_abs)/L_norm$dia[L_norm$Cond == "Dark"]*100
L_val$amp2 <- (L_norm$dia[L_norm$Cond == "Dark"] - L_val$d_abs)/(L_norm$dia[L_norm$Cond == "Dark"] - temp)*100
L_val10$amp2 <- (L_norm$dia[L_norm$Cond == "Dark"] - L_val10$d_abs)/(L_norm$dia[L_norm$Cond == "Dark"] - L_norm$dia[L_norm$Cond == "10_15"])*100
##Nun auch für das rechte Auge
# Zunächst wird die -Baseline-Größe bestimmt. Sie wird hier definiert als der Mittelwert der Pupille in den letzten 5 Sekunden der Dunkeladaptation
# In Fällen, in denen die Pupille während der Belichtung niedrigere Werte annimmt, kann auch die größte Pupillengröße während der Belichtung gewählt werden. Dies erfolgt automatisch anhand des größeren Werts
R_norm <- as.numeric(
ifelse(pupRf %>% dplyr::filter(time_c < 0 & time_c > -5) %>% summarize(p_max = mean(dia_sm)) >
pupRf %>% dplyr::filter(time_c > 0 & time_c < tot_per) %>% summarize(p_max = max(dia_sm)),
pupRf %>% dplyr::filter(time_c < 0 & time_c > -5) %>% summarize(p_max = mean(dia_sm)),
pupRf %>% dplyr::filter(time_c > 0 & time_c < tot_per) %>% summarize(p_max = max(dia_sm))
))
# Im nächsten Schritt werden die Sekundenmittelwerte für jede Wellenlänge gebildet, zudem der Mittelwert der letzten 5 Sekunden und die minimalen Pupillengrößen für die jeweiligen Zeitintervalle
R_val <- pupRf %>% group_by(wl_step, wl_time %/% 1) %>% summarize(d_abs = mean(dia_sm))
`summarise()` regrouping output by 'wl_step' (override with `.groups` argument)
R_val10 <- pupRf %>% dplyr::filter(wl_time <= 15 & wl_time >= 10) %>% group_by(wl_step) %>% summarize(d_abs = mean(dia_sm))
`summarise()` ungrouping output (override with `.groups` argument)
names(R_val) <- c("wl", "time", "d_abs")
names(R_val10) <- c("wl", "d_abs")
temp <- R_val %>% dplyr::filter(wl != "NA") %>% group_by(time) %>% summarize(min = min(d_abs))
`summarise()` ungrouping output (override with `.groups` argument)
R_norm <- data_frame("Cond" = c("Dark", temp$time, "10_15"), "dia" = c(R_norm, temp$min, min(R_val10$d_abs)))
# Im folgenden Schritt werden relative Pupillenkonstriktionswerte gebildet, amp ist dabei die Konstriktionsamplitude bezogen auf die Baseline-Größe, amp2 auf die Spanne zwischen der Basline-Größe und der kleinsten, für diese Zeitspanne gemessenen Pupillengröße.
temp <- as.numeric(as.character((cut(R_val$time,
breaks = 0:(max(prog$intervall_0+prog$pause_0) %/% 1 +1),
include.lowest = T,
right = F,
labels = R_norm$dia[2:(length(R_norm$dia)-1)]))
)) # Hier wird zunächst eine temporäre Variable erzeugt, welche für jede Zeile in den Sekundenmittelwertdaten die korrespondierende minimale Pupillengröße angibt.
R_val$amp <- (R_norm$dia[R_norm$Cond == "Dark"] - R_val$d_abs)/R_norm$dia[R_norm$Cond == "Dark"]*100
R_val10$amp <- (R_norm$dia[R_norm$Cond == "Dark"] - R_val10$d_abs)/R_norm$dia[R_norm$Cond == "Dark"]*100
R_val$amp2 <- (R_norm$dia[R_norm$Cond == "Dark"] - R_val$d_abs)/(R_norm$dia[R_norm$Cond == "Dark"] - temp)*100
R_val10$amp2 <- (R_norm$dia[R_norm$Cond == "Dark"] - R_val10$d_abs)/(R_norm$dia[R_norm$Cond == "Dark"] - R_norm$dia[R_norm$Cond == "10_15"])*100
#Abschließend die grafische Darstellung
Sens <- ggplot() +
geom_line(data = L_val, aes(x=wl, y=amp2, group = time, col = "Left"), alpha = 0.25) +
geom_line(data = R_val, aes(x=wl, y=amp2, group = time, col = "Right"), alpha = 0.25) +
geom_line(data = L_val10, aes(y=amp2, x=wl, col = "Left"), lwd = 1)+
geom_line(data = R_val10, aes(y=amp2, x=wl, col = "Right"), lwd = 1)+
geom_text(aes(label = paste("n=1, ", Code, ", P0", sep=""), x = 400, y= 100), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_brewer(palette = "Set1", "Eye")+
ggtitle("Sensitivity depending on wavelength and time (1-15 per second averages in lighter tone)")+
ylab("Sensitivity / %") +
xlab("Wavelength / nm")+
theme(legend.position = c(0.9,.2),legend.background = element_rect(fill="white", size = 0.5))
Sens
ggsave("Sensitivity.pdf", path = paste("../figures/", Code, sep=""),limitsize=F, width=10, height = 6)

Schließlich erfolgt der Export der Mittelwerte für alle Wellenlängen, sowie für die Normierungsrandbedingungen
#Entscheidung für ein Auge, auf Basis der meisten Datenverfügbarkeit, sofern nicht manuell etwas angegeben wird.
export <- ifelse(length(pupLf$dia_sm) > length(pupRf$dia_sm), "L", "R")
paste("the pupil of the following eye is used for export: ", ifelse(export == "R", "Right", "Left"))
[1] "the pupil of the following eye is used for export: Right"
#Erstellung der Exportdaten für die Sekundenmittelwerte, die 10-15 Sekundenmittelwerte, und für die Normierungsrandbedingungen
temp <- get(paste(export, "_norm", sep=""))
export_data3 <- data.frame(t(temp[-1]))
colnames(export_data3) <- temp$Cond
export_data3 <- tibble("Code" = Code, "Eye" = ifelse(export == "R", "Right", "Left"), "Date" = as.Date(pup$UTC[1]), "Time" = format(as.POSIXct(pup$UTC[1]), format = "%H:%M:%S"), "Dir" = "Central3", export_data3)
export_data0 <- get(paste("pup", export, "f", sep=""))
export_data0$amp1 <- (export_data3$Dark[1] - export_data0$dia_sm)/export_data3$Dark[1]*100
export_data1 <- get(paste(export, "_val", sep=""))[-length(get(paste(export, "_val", sep=""))$wl),]
export_data1$index <- match(export_data1$wl, wl)
export_data2 <- get(paste(export, "_val10", sep=""))
export_data2$index <- match(export_data2$wl, wl)
write_csv(export_data0, paste("../data_output/", Code, "_full.csv", sep="") )
write_csv(export_data1, paste("../data_output/", Code, "_all.csv", sep="") )
write_csv(export_data2, paste("../data_output/", Code, "_10_15.csv", sep="") )
write_csv(export_data3, paste("../data_output/", Code, "_norm.csv", sep="") )
#---- Anfang Code-Option
#Alternativ, wenn mit dem Rechten Auge die Zeit erfasst wird.
#Bildung der 1. und 2. Ableitung. Lineare Transformation, damit die Überlagerung mit dem Pupillendurchmesser lesbar bleibt.
pupRf$dia_sm1 <- (sgolayfilt(pupRf$dia, p=3, n=31, m=1))*100+6
pupRf$dia_sm2 <- (sgolayfilt(pupRf$dia, p=3, n=31, m=2))*100+6
#Erkennung der Tiefpunkte der 2. Ableitung
vly <- ggplot(data = pupRf, aes(x=time, y=dia_sm2)) +
stat_valleys(span = 601, col = "green")
vly_data <- (layer_data(vly, i=1L)$xintercept)
#Darstellung der Tiefpunkte der 2. Ableitung
Derivative_test <- ggplot(data = pupRf, aes(x=time, y=dia_sm2, col="valley")) +
geom_line(data = pupRf, aes(x = time, y = dia_sm, col = "Diameter")) +
geom_line(data = pupLf, aes(x = time, y = dia_sm, col = "Diameter")) +
geom_line(aes(col = "2st derivative"), alpha = 0.6) +
stat_valleys(span = 601, col = "green")+
geom_vline(xintercept = vly_data-0.1, lwd = 0.1, col="green")+
geom_text(aes(label = paste("n=1, ", Code, sep=""), x = 85, y= 8), size = 2.5)+
theme_cowplot(font_size = 8, font_family = "sans")+
scale_color_brewer(palette = "Set1", "Type")+
ggtitle("Pupil-diameter data smoothed with 2nd derivative and valleys (-100ms)")+
ylab("Pupil diameter / mm") +
xlab("Time / seconds")+
theme(legend.position = c(0.9,.1),legend.background = element_rect(fill="white", size = 0.5))+
coord_cartesian(xlim = c(85, 150))
Derivative_test
ggsave("Pupil_Derivative_test.pdf", path = paste("../figures/", Code, sep=""), width=10, height = 5)
#Wahl eines Programmstartpunkts
vly_data <- tibble("index" = 1: length(vly_data), "time" = vly_data-0.1, "dif" = c(vly_data[1], diff(vly_data)))
kable(vly_data[1:20,], "pandoc", caption = "Time of 2nd derivative valleys (-100ms), first 20 rows", align = "c")# Tiefpunkte mit Zeitstempel
#---- Ende Code-Option
LS0tCnRpdGxlOiAiUiBQdXBpbCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQpNaXQgZGllc2VtIERva3VtZW50IHdlcmRlbiBhdXMgZGVuIERpa2FibGlzIFB1cGlsbGVucm9oZGF0ZW4gbWl0IGRlbSBIb2Noc2NodWxlLU3DvG5jaGVuIExpY2h0bGFib3IoRDExMyktU2V0dXAgYXVzd2VydHVuZ3Nmw6RoaWdlIFB1cGlsbGVuZGF0ZW4gZXh0cmFoaWVydC4gRGllIEF1c3dlcnR1bmcgaXN0IGfDvGx0aWcgZsO8ciBkYXMgIlByb2dyYW1tIDAiIGF1cyBkZW0gTGlnaHRkb21lLVN0ZXVlcnJlY2huZXIgdW5kIGbDvHIgZGllICJuZXVlIiBVbXJlY2hudW5nc21ldGhvZGUgdm9uIFBpeGVsbiB6dSBtbSwgYmVpIGRlciB2b3IgQXVmemVpY2hudW5nIGVpbiBSZWZlcmVuem1hw58gYXVmIEF1Z2VuZWJlbmUgaW0gS2FtZXJhYmlsZCBnZXplaWd0IHdpcmQuIERpZXNlcyBQcm9ncmFtbSBiZWdpbm50IG1pdCBlaW5lciBEdW5rZWxhZGFwYXRpb25zcGVyaW9kZSB2b24gOTAgU2VrdW5kZW4uIERhbmFjaCB3ZXJkZW4gaW4gY2EuIDE1IFNla3VuZGVuLVNjaHJpdHRlbiBkaWUgV2VsbGVubMOkbmdlbiB2b24gNzAwLTQwMCBubSBpbiA1IG5tIFNjaHJpdHRlbiBhYmdlZmFocmVuLiBEaWUgQWJmb2xnZSBkZXIgV2VsbGVubMOkbmdlbnNjaHJpdHRlIHZlcmzDpHVmdCBpbiBncm/Dn2VuIHVuZCBrbGVpbmVuIFNwcsO8bmdlbi4gWndpc2NoZW4gamVkZW0gU2Nocml0dCBsaWVndCBlaW5lIFBoYXNlLCBpbiBkZXIgZGllIG5ldWUgV2VsbGVubMOkbmdlIGVpbmdlc3RlbGx0IHdpcmQuIERpZSBEYXVlciBkaWVzZXIgUGhhc2VuIHZhcmlpZXJ0IGluIEFiaMOkbmdpZ2tlaXQgZGVzIFVudGVyc2NoaWVkcyB6d2lzY2hlbiBkZW4gV2VsbGVubMOkbmdlbi4KClVtIGRlbiBDb2RlIGbDvHIgZWluZSBuZXVlIFBlcnNvbiBhbnp1cGFzc2VuLCBzaW5kIGRpZSBmb2xnZW5kZW4gRWluZ3JpZmZlIG5vdHdlbmRpZy4gWmVpbGVuYW5nYWJlbiBiZXppZWhlbiBzaWNoIGF1ZiBkYXMgKi5SbWQtRmlsZToKCjEuIFplaWxlIDM3IC0+IEVpbmbDvGdlbiBkZXMga29ycmVrdGVuIERhdGVpbmFtZW5zIC8gUGZhZAoKMi4gWmVpbGUgNDUgLT4gVmVyc3VjaHNwZXJzb25lbmNvZGUgZWluZsO8Z2VuCgozLiBaZWlsZW4gMTE2LTEyOCAtPiBQcsO8ZnVuZywgb2IgZGllIEtyaXRlcmllbiB6dXIgTWVzc3dlcnRhdXNzb3J0aWVydW5nIGJlaSBaaXJrdWxhcml0w6R0LCBhYnNvbHV0ZW0gQWJzY2huaXR0LCB1bmQgZGVtIFNjaGx1c3NzY2huaXR0IGluIE9yZG51bmcgc2luZAoKNC4gWmVpbGUgMjEyLTIxNSAtPiBOYWNoIFByw7xmdW5nLCBvYiBkaWUgVGFsLUVya2VubnVuZyBmdW5rdGlvbmllcnQsIEFuZ2FiZSBkZXMga29ycmVrdGVuIEluZGV4IGbDvHIgZGVuIFJlZmVyZW56emVpdHB1bmt0LiBTb2xsdGUgZGFzIGJlaW0gbGlua2VuIEF1Z2UgbmljaHQgbcO2Z2xpY2ggc2VpbiwgbXVzcyBkZXIgdW50ZXJzdGUgQ29kZS1DaHVuayBhdXMgZGVyIERhdGVpIG1hbnVlbGwgaG9jaCBrb3BpZXJ0IHdlcmRlbi4gU29sbHRlIGRlciBlcnN0ZSBCZWxldWNodHVuZ3N6ZWl0cHVua3QgbmljaHQgZXJrYW5udCB3ZXJkZW4sIGthbm4gZWluIHNww6R0ZXJlciBaZWl0cHVua3QgYW5nZWdlYmVuIHdlcmRlbiAtIGluIGRpZXNlbSBGYWxsIG11c3Mgc3BlemlmaXppZXJ0IHdlcmRlbiwgdW0gd2llIHZpZWxlIFNjaHJpdHRlIGRlciBQcm9ncmFtbXN0YXJ0IHp1csO8Y2tsaWVndC4KCjUuIFplaWxlIDQyOC80MjkgLT4gRGllIEF1c3dhaGwsIHdlbGNoZXMgQXVnZSBzY2hsdXNzZW5kbGljaCBmw7xyIGRlbiBEYXRlbmV4cG9ydCB2ZXJ3ZW5kZXQgd2lyZCwgd2lyZCBzdGFuZGFyZG3DpMOfaWcgYXV0b21hdGlzY2ggdm9sbHpvZ2VuIGFuaGFuZCBkZXIgUHVwaWxsZSBtaXQgZGVtIG1laXN0ZW4gRGF0ZW5wdW5rdGVuIG5hY2ggZGVyIEJlcmVpbmlndW5nLiBTb2xsdGUgZGllc2UgQXVzd2FobCBuaWNodCBpbiBPcmRudW5nIHNlaW4sIG11c3MgaGllciBtYW51ZWxsICJSIiBvZGVyICJMIiBlaW5nZXRyYWdlbiB3ZXJkZW4uCgoKSW0gZm9sZ2VuZGVuIEFic2Nobml0dCB3ZXJkZW4gYWxsZSBub3R3ZW5kaWdlbiBCaWJsaW90aGVrZW4gZ2VsYWRlbiwgc293aWUgZGllIFJvaGRhdGVuIGVpbmdlbGVzZW4uIERlciBBYnNjaG5pdHQgZW5kZXQgbWl0IGVpbmVyIERhcnN0ZWxsdW5nIGRlciBSb2hkYXRlbiBkZXIgUHVwaWxsZW4sIHNvd2llIGRlciBaaXJrdWxhcmnDpHQuCgpgYGB7ciBEYXRlbiBlaW5sZXNlbn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoYW55dGltZSkKbGlicmFyeShzaWduYWwpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdncG1pc2MpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGtuaXRyKQoKc2V0d2QoZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRBY3RpdmVEb2N1bWVudENvbnRleHQoKSRwYXRoKSkgIyBTZXR6ZW4gZGVzIEFyYmVpdHN2ZXJ6ZWljaG5pc3NlcyBhdWYgZ2xlaWNoZXMgVmVyemVpY2huaXMgd2llIFNjcmlwdCAKCnB1cCA8LSByZWFkLnRhYmxlKCIuLi9kYXRhX2lucHV0L1AwL0hKMDgxMDAyXzJfNi4gTWVzc3VuZyBQcjAgMjIuMDkuMjAyMCAxMjM3NTdfQ3N2RGF0YS50eHQiLCBzZXAgPSAiXHQiLCBoZWFkZXIgPSBUUlVFLCBzdHJpbmdzQXNGYWN0b3JzPUYpICMgRWlubGVzZW4gZGVyIERhdGVuIFB1cGlsbGUKcHJvZyA8LSByZWFkLnRhYmxlKCIuLi9kYXRhX2lucHV0L3Byb2dyYW1fZGF0YV9sZC5jc3YiLCBkZWMgPSAiLCIsIHNlcCA9ICI7IiwgaGVhZGVyID0gVFJVRSwgc3RyaW5nc0FzRmFjdG9ycz1GKSAjIEVpbmxlc2VuIGRlciBQcm9ncmFtbWRhdGVuCmNvcmYgPC0gcmVhZF9leGNlbCgiLi4vVcyIYmVyc2ljaHRfVlAueGxzeCIsIHNoZWV0ID0gIlVlYmVyc2ljaHRfVlAiLCBuYT0iTkEiKSAjbG9hZCBpbiB0aGUgZmlsZSB3aXRoIGFsbCBpbmRpdmlkdWFsIGNvZGVzICMgRWlubGVzZW4gZGVyIEtvcnJla3R1cmZha3RvcmVuCgojQXVzd8OkaGxlbiBkZXIgbm90d2VuZGlnZW4gU3BhbHRlbiB1bmQgU3BhbHRlbiB1bWJlbmVubmVuCiNVbXJlY2huZW4gZGVzIFVUQy1aZWl0c3RlbXBlbHMgaW4gbG9rYWxlIFplaXQKI0JlcmVjaG51bmcgZGVzIFB1cGlsbGVuZHVyY2htZXNzZXJzIChudXIgZsO8ciBSZWZlcmVuem1hw58gLSBEaWUgS29ycmVrdHVyZmFrdG9yZW4gYWxsZXIgUHJvYmFuZGVuIHdlcmRlbiBpbiBlaW5lciBzZXBhcmF0ZW4gRGF0ZWkgZ2VzcGVpY2hlcnQpCgpDb2RlIDwtICJISjA4MTAwMl9jMyIKCmRpci5jcmVhdGUocGFzdGUoIi4uL2ZpZ3VyZXMvIiwgQ29kZSwgc2VwPSIiKSkKCnB1cCA8LSBzZWxlY3QocHVwLCByZWNfdGltZSwgVVRDLCBEaWthYmxpcy5Qcm9mZXNzaW9uYWxfRXllLkRhdGFfT3JpZ2luYWxfTGVmdC5FeWVfUHVwaWwuQXJlYSwgRGlrYWJsaXMuUHJvZmVzc2lvbmFsX0V5ZS5EYXRhX09yaWdpbmFsX0xlZnQuRXllX1B1cGlsLkhlaWdodCwgRGlrYWJsaXMuUHJvZmVzc2lvbmFsX0V5ZS5EYXRhX09yaWdpbmFsX0xlZnQuRXllX1B1cGlsLldpZHRoLCBEaWthYmxpcy5Qcm9mZXNzaW9uYWxfRXllLkRhdGFfT3JpZ2luYWxfUmlnaHQuRXllX1B1cGlsLkFyZWEsIERpa2FibGlzLlByb2Zlc3Npb25hbF9FeWUuRGF0YV9PcmlnaW5hbF9SaWdodC5FeWVfUHVwaWwuSGVpZ2h0LCBEaWthYmxpcy5Qcm9mZXNzaW9uYWxfRXllLkRhdGFfT3JpZ2luYWxfUmlnaHQuRXllX1B1cGlsLldpZHRoKSAKCnB1cCA8LSB0aWJibGUocHVwKQoKY29sbmFtZXMocHVwKSA8LSBjKCJ0aW1lIiwgIlVUQyIsICJMYSIsICJMaCIsICJMdyIsICJSYSIsICJSaCIsICJSdyIpCgpwdXAkVVRDIDwtIGFueXRpbWUocHVwJFVUQy8xMDAwKQoKcHVwIDwtIHNlcGFyYXRlKHB1cCwgdGltZSwgYygiaCIsICJtIiwgInMiKSwgc2VwID0gIjoiLCBjb252ZXJ0ID0gVFJVRSkKcHVwJHRpbWUgPC0gcHVwJHMgKyBwdXAkbSo2MCArIHB1cCRoKjYwKjYwCgpjb3JmX0wgPC0gY29yZiRLb3JyX0xpbmtzW2NvcmYkQ29kZSA9PSBDb2RlXQpjb3JmX1IgPC0gY29yZiRLb3JyX1JlY2h0c1tjb3JmJENvZGUgPT0gQ29kZV0KCnB1cCRMZCA8LSAyKnNxcnQocHVwJExhL3BpKS9jb3JmX0wKCnB1cCRSZCA8LSAyKnNxcnQocHVwJFJhL3BpKS9jb3JmX1IKCiNBdWZ0ZWlsZW4gaW4gUHVwaWxsZSByZWNodGVzIHVuZCBsaW5rZXMgQXVnZQoKcHVwUiA8LSBzZWxlY3QocHVwLCAidGltZSIsICJVVEMiLCAiUmQiLCAiUmEiLCAiUmgiLCAiUnciKQpwdXBSIDwtIGRwbHlyOjpmaWx0ZXIocHVwUiwgIWlzLm5hKFJhKSkKY29sbmFtZXMocHVwUikgPC0gYygidGltZSIsICJVVEMiLCAiZGlhIiwgImFyZWEiLCAiaGVpZ2h0IiwgIndpZHRoIikKCnB1cEwgPC0gc2VsZWN0KHB1cCwgInRpbWUiLCAiVVRDIiwgIkxkIiwgIkxhIiwgIkxoIiwgIkx3IikKcHVwTCA8LSBkcGx5cjo6ZmlsdGVyKHB1cEwsICFpcy5uYShMYSkpCmNvbG5hbWVzKHB1cEwpIDwtIGMoInRpbWUiLCAiVVRDIiwgImRpYSIsICJhcmVhIiwgImhlaWdodCIsICJ3aWR0aCIpCgojRGFyc3RlbGx1bmcgZGVyIEVyZ2Vibmlzc2UgaW0gUGxvdAojIFJvaGRhdGVuClJvaF9wbG90IDwtIGdncGxvdCgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMLCBhZXMoeCA9IHRpbWUsIHkgPSBkaWEsIGNvbCA9ICJMZWZ0IikpICsKICBnZW9tX2xpbmUoZGF0YSA9IHB1cFIsIGFlcyh4ID0gdGltZSwgeSA9IGRpYSwgY29sID0gIlJpZ2h0IiksIGFscGhhID0gMC42KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsICIsIFAwIiwgc2VwPSIiKSwgeCA9IDUwLCB5PSA4KSwgc2l6ZSA9IDIuNSkrCiAgdGhlbWVfY293cGxvdChmb250X3NpemUgPSA4LCBmb250X2ZhbWlseSA9ICJzYW5zIikrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsICJFeWUiKSsKICBnZ3RpdGxlKCJQdXBpbC1kaWFtZXRlciBkYXRhIHVuY2hhbmdlZCIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigiVGltZSAvIHNlY29uZHMiKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKClJvaF9wbG90Cmdnc2F2ZSgiUHVwaWxfUmF3LnBkZiIsIHBhdGggPSBwYXN0ZSgiLi4vZmlndXJlcy8iLCBDb2RlLCBzZXA9IiIpLCB3aWR0aD0xMCwgaGVpZ2h0ID0gNSkKCiMgWmlya3VsYXJpdMOkdApSb2hfcGxvdDIgPC0gZ2dwbG90KCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHB1cEwsIGFlcyh4ID0gdGltZSwgeSA9IHdpZHRoL2hlaWdodCwgY29sID0gIkxlZnQiKSkgKwogIGdlb21fbGluZShkYXRhID0gcHVwUiwgYWVzKHggPSB0aW1lLCB5ID0gd2lkdGgvaGVpZ2h0LCBjb2wgPSAiUmlnaHQiKSwgYWxwaGEgPSAwLjYpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm49MSwgIiwgQ29kZSwgIiwgUDAiLCAgc2VwPSIiKSwgeCA9IDUwLCB5PSAxLjAxKSwgc2l6ZSA9IDIuNSkrCiAgdGhlbWVfY293cGxvdChmb250X3NpemUgPSA4LCBmb250X2ZhbWlseSA9ICJzYW5zIikrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsICJFeWUiKSsKICBnZ3RpdGxlKCJQdXBpbC1jaXJjdWxhcml0eSIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigiVGltZSAvIHNlY29uZHMiKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKClJvaF9wbG90MgpnZ3NhdmUoIlB1cGlsX1JhdzIucGRmIiwgcGF0aCA9IHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksIHdpZHRoPTEwLCBoZWlnaHQgPSA1KQoKCmBgYAoKCkltIGtvbW1lbmRlbiBBYnNjaG5pdHQgd2VyZGVuIEFydGVmYWt0ZSB1bmQgdW5wbGF1c2libGUgTWVzc3dlcnRlIGVudGZlcm50LiBadWRlbSB3aXJkIGRpZSBLdXJ2ZSBnZWdsw6R0dGV0LgpgYGB7ciBEYXRlbiBhdWZiZXJlaXRlbn0KI0VudGZlcm51bmcgdm9uIEF1c3JlaXNzZXJuIHVuZCBXZXJ0ZW4gYmVpIGRlbmVuIGRpZSBQdXBpbGxlIGVpbmUgemlya3VsYXJpdMOkdCA8IDAsNyBhdWZ3ZWlzdCwgenVkZW0gd2lyZCBkaWUgbGV0enRlbiAyIFNla3VuZGVuIGRlciBNZXNzdW5nIGVudGZlcm50CgpwdXBSZiA8LSBwdXBSWzE6KGxlbmd0aChwdXBSJHRpbWUpLTEyMCksXQpwdXBSZiA8LSBkcGx5cjo6ZmlsdGVyKHB1cFJmLCBkaWEgPiAxKSAjIEVudGZlcm51bmcgdm9uIFdlcnRlbiBrbGVpbmVyIFggbW0KcHVwUmYgPC0gZHBseXI6OmZpbHRlcihwdXBSZiwgZGlhIDwgOC41KSAjIEVudGZlcm51bmcgdm9uIFdlcnRlbiBncsO2w59lciA4IG1tCnB1cFJmIDwtIGRwbHlyOjpmaWx0ZXIocHVwUmYsIHdpZHRoL2hlaWdodCA+IDAuNzAgJiB3aWR0aC9oZWlnaHQgPiAwLjcwKSAjIEVudGZlcm51bmcgdm9uIFdlcnRlbiBmw7xyIGRpZSBkaWUgWmlya3VsYXJpdMOkdCBrbGVpbmVyIGFscyAwLDcgYXVzZsOkbGx0CnB1cFJmJGRpYV9zbSA8LSBzZ29sYXlmaWx0KHB1cFJmJGRpYSwgcD0zLCBuPTMxKSAjIEdsw6R0dHVuZyBkZXIgS3VydmUgbWl0dGVscyBTYXZpdHpreS1Hb2xheSBGaWx0ZXIKCnB1cExmIDwtIHB1cExbMToobGVuZ3RoKHB1cEwkdGltZSktMTIwKSxdCnB1cExmIDwtIGRwbHlyOjpmaWx0ZXIocHVwTGYsIGRpYSA+IDEpICMgRW50ZmVybnVuZyB2b24gV2VydGVuIGtsZWluZXIgWCBtbQpwdXBMZiA8LSBkcGx5cjo6ZmlsdGVyKHB1cExmLCBkaWEgPCA4LjUpICMgRW50ZmVybnVuZyB2b24gV2VydGVuIGdyw7bDn2VyIDggbW0KcHVwTGYgPC0gZHBseXI6OmZpbHRlcihwdXBMZiwgd2lkdGgvaGVpZ2h0ID4gMC43MCAmIHdpZHRoL2hlaWdodCA+IDAuNzApICMgRW50ZmVybnVuZyB2b24gV2VydGVuIGbDvHIgZGllIGRpZSBaaXJrdWxhcml0w6R0IGtsZWluZXIgYWxzIDAsNyBhdXNmw6RsbHQKcHVwTGYkZGlhX3NtIDwtIHNnb2xheWZpbHQocHVwTGYkZGlhLCBwPTMsIG49MzEpICMgR2zDpHR0dW5nIGRlciBLdXJ2ZSBtaXR0ZWxzIFNhdml0emt5LUdvbGF5IEZpbHRlcgoKU21vb3RoX3Bsb3RfdGVzdCA8LSBnZ3Bsb3QoKSArIAogIGdlb21fbGluZShkYXRhID0gcHVwTGYsIGFlcyh4ID0gdGltZSwgeSA9IGRpYSwgY29sID0gInVuc21vb3RoZWQiKSkgKwogIGdlb21fbGluZShkYXRhID0gcHVwTGYsIGFlcyh4ID0gdGltZSwgeSA9IGRpYV9zbSwgY29sID0gInNnIG49MzEiKSwgYWxwaGEgPSAwLjYpICsKICAgIGdlb21fbGluZShkYXRhID0gcHVwTGYsIGFlcyh4ID0gdGltZSwgeSA9IHNnb2xheWZpbHQoZGlhLCBwPTMsIG49NjEpLCBjb2wgPSAic2cgbj02MSIpLCBhbHBoYSA9IDAuNikgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSB0aW1lLCB5ID0gc2dvbGF5ZmlsdChkaWEsIHA9Mywgbj05MSksIGNvbCA9ICJzZyBuPTkxIiksIGFscGhhID0gMC42KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsICAiLCBQMCIsIHNlcD0iIiksIHggPSAyNTAsIHk9IDgpLCBzaXplID0gMi41KSsKICB0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZSA9IDgsIGZvbnRfZmFtaWx5ID0gInNhbnMiKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgIkV5ZSIpKwogIGdndGl0bGUoIlB1cGlsLWRpYW1ldGVyIGRhdGEgc21vb3RoZWQsIHRlc3Qgc2V0dGluZ3MiKSsKICB5bGFiKCJQdXBpbCBkaWFtZXRlciAvIG1tIikgKwogIHhsYWIoIlRpbWUgLyBzZWNvbmRzIikrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjksLjEpLGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9IndoaXRlIiwgc2l6ZSA9IDAuNSkpKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygyNTAsIDI3NSksIHlsaW0gPSBjKDIsOCkpCgpTbW9vdGhfcGxvdF90ZXN0Cmdnc2F2ZSgiUHVwaWxfU21vb3RoX3Rlc3QucGRmIiwgcGF0aCA9IHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksIHdpZHRoPTEwLCBoZWlnaHQgPSA1KQoKU21vb3RoX3Bsb3QgPC0gZ2dwbG90KCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHB1cExmLCBhZXMoeCA9IHRpbWUsIHkgPSBkaWFfc20sIGNvbCA9ICJMZWZ0IikpICsKICBnZW9tX2xpbmUoZGF0YSA9IHB1cFJmLCBhZXMoeCA9IHRpbWUsIHkgPSBkaWFfc20sIGNvbCA9ICJSaWdodCIpLCBhbHBoYSA9IDAuNikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgibj0xLCAiLCBDb2RlLCAgIiwgUDAiLCBzZXA9IiIpLCB4ID0gNTAsIHk9IDgpLCBzaXplID0gMi41KSsKICB0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZSA9IDgsIGZvbnRfZmFtaWx5ID0gInNhbnMiKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgIkV5ZSIpKwogIGdndGl0bGUoIlB1cGlsLWRpYW1ldGVyIGRhdGEgc21vb3RoZWQiKSsKICB5bGFiKCJQdXBpbCBkaWFtZXRlciAvIG1tIikgKwogIHhsYWIoIlRpbWUgLyBzZWNvbmRzIikrIAogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygyLDgpKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKClNtb290aF9wbG90Cmdnc2F2ZSgiUHVwaWxfU21vb3RoLnBkZiIsIHBhdGggPSAgcGFzdGUoIi4uL2ZpZ3VyZXMvIiwgQ29kZSwgc2VwPSIiKSwgd2lkdGg9MTAsIGhlaWdodCA9IDUpCgoKYGBgCgoKSW0gbsOkY2hzdGVuIEFic2Nobml0dCBlcmZvbGd0IGRpZSBadW9yZG51bmcgZWluemVsbmVyIFplaXRhYnNjaG5pdHRlIHp1IGRlbiBXZWxsZW5sw6RuZ2VuLgpgYGB7ciBXZWxsZW5sw6RuZ2VuIHp1b3JkbmVufQoKI0JpbGR1bmcgZGVyIDEuIHVuZCAyLiBBYmxlaXR1bmcuIExpbmVhcmUgVHJhbnNmb3JtYXRpb24sIGRhbWl0IGRpZSDDnGJlcmxhZ2VydW5nIG1pdCBkZW0gUHVwaWxsZW5kdXJjaG1lc3NlciBsZXNiYXIgYmxlaWJ0LgoKcHVwTGYkZGlhX3NtMSA8LSAoc2dvbGF5ZmlsdChwdXBMZiRkaWEsIHA9Mywgbj0zMSwgbT0xKSkqMTAwKzYKcHVwTGYkZGlhX3NtMiA8LSAoc2dvbGF5ZmlsdChwdXBMZiRkaWEsIHA9Mywgbj0zMSwgbT0yKSkqMTAwKzYKCgojRXJrZW5udW5nIGRlciBUaWVmcHVua3RlIGRlciAyLiBBYmxlaXR1bmcKdmx5IDwtIGdncGxvdChkYXRhID0gcHVwTGYsIGFlcyh4PXRpbWUsIHk9ZGlhX3NtMikpICsgCiAgc3RhdF92YWxsZXlzKHNwYW4gPSA2MDEsIGNvbCA9ICJncmVlbiIpCnZseV9kYXRhIDwtIChsYXllcl9kYXRhKHZseSwgaT0xTCkkeGludGVyY2VwdCkKCiNEYXJzdGVsbHVuZyBkZXIgVGllZnB1bmt0ZSBkZXIgMi4gQWJsZWl0dW5nCkRlcml2YXRpdmVfdGVzdCA8LSBnZ3Bsb3QoZGF0YSA9IHB1cExmLCBhZXMoeD10aW1lLCB5PWRpYV9zbTIsIGNvbD0idmFsbGV5IikpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSB0aW1lLCB5ID0gZGlhX3NtLCBjb2wgPSAiRGlhbWV0ZXIiKSkgKwogIGdlb21fbGluZShkYXRhID0gcHVwUmYsIGFlcyh4ID0gdGltZSwgeSA9IGRpYV9zbSwgY29sID0gIkRpYW1ldGVyIikpICsKICAgIGdlb21fbGluZShhZXMoY29sID0gIjJuZCBkZXJpdmF0aXZlIiksIGFscGhhID0gMC42KSArCiAgc3RhdF92YWxsZXlzKHNwYW4gPSA2MDEsIGNvbCA9ICJncmVlbiIpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHZseV9kYXRhLTAuMSwgbHdkID0gMC4xLCBjb2w9ImdyZWVuIikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsICAiLCBQMCIsIHNlcD0iIiksIHggPSA4MCwgeT0gOCksIHNpemUgPSAyLjUpKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCAiVHlwZSIpKwogIGdndGl0bGUoIlB1cGlsLWRpYW1ldGVyIGRhdGEgc21vb3RoZWQgd2l0aCAybmQgZGVyaXZhdGl2ZSBhbmQgdmFsbGV5cyAoLTEwMG1zKSIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigiVGltZSAvIHNlY29uZHMiKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkrCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDgwLCAyMDApKQoKRGVyaXZhdGl2ZV90ZXN0Cmdnc2F2ZSgiUHVwaWxfRGVyaXZhdGl2ZV90ZXN0LnBkZiIsIHBhdGggPSBwYXN0ZSgiLi4vZmlndXJlcy8iLCBDb2RlLCBzZXA9IiIpLCB3aWR0aD0xNSwgaGVpZ2h0ID0gNSkKCiNXYWhsIGVpbmUgUHJvZ3JhbW1zdGFydHB1bmt0cwoKdmx5X2RhdGEgPC0gdGliYmxlKCJpbmRleCIgPSAxOiBsZW5ndGgodmx5X2RhdGEpLCAidGltZSIgPSB2bHlfZGF0YS0wLjEsICJkaWYiID0gYyh2bHlfZGF0YVsxXSwgZGlmZih2bHlfZGF0YSkpKQprYWJsZSh2bHlfZGF0YVsxOjIwLF0sICJwYW5kb2MiLCBjYXB0aW9uID0gIlRpbWUgb2YgMm5kIGRlcml2YXRpdmUgdmFsbGV5cyAoLTEwMG1zKSwgZmlyc3QgMjAgcm93cyIsIGFsaWduID0gImMiKSMgVGllZnB1bmt0ZSBtaXQgWmVpdHN0ZW1wZWwKCmBgYAoKCmBgYHtyIFdlbGxlbmzDpG5nZW4genVvcmRuZW4yfQoKdGltZV9jb3IgPC0gMAoKI1dlbGNoZXIgaW5kZXggaXN0IGRlciBTdGFydHplaXRwdW5rdD8KaSA8LSA5ICMgSGllciBtdXNzIG1hbiBhdWYgQmFzaXMgZGVyIEdyYWZpayB1bmQgZGVyIFRhYmVsbGUgZGVuIFN0YXJ0emVpdHB1bmt0IGFuZ2ViZW4KCiNaZWl0a29ycmVrdHVyIG5vdHdlbmRpZz8KY29yIDwtIDEKCnB1cExmJHRpbWVfYyA8LSBwdXBMZiR0aW1lIC0gdmx5X2RhdGEkdGltZVt2bHlfZGF0YSRpbmRleCA9PSBpXSArIHRpbWVfY29yKmNvcgpwdXBSZiR0aW1lX2MgPC0gcHVwUmYkdGltZSAtIHZseV9kYXRhJHRpbWVbdmx5X2RhdGEkaW5kZXggPT0gaV0gKyB0aW1lX2Nvcipjb3IKCiNFcmfDpG56dW5nIGRlciBXZWxsZW5sw6RuZ2VuIAoKd2xfc2VjIDwtIHRpYmJsZSgKICAid2wiID0gKHByb2ckUGVha184KSwgCiAgIndsX2IiID0gYygwLCAoY3Vtc3VtKHByb2ckaW50ZXJ2YWxsXzApK2N1bXN1bShwcm9nJHBhdXNlXzApKVstbGVuZ3RoKHByb2ckaW50ZXJ2YWxsXzApXSksCiAgIndsX2UiID0gY3Vtc3VtKHByb2ckaW50ZXJ2YWxsXzApK2N1bXN1bShwcm9nJHBhdXNlXzApCiAgKQoKdG90X3BlciA8LSBzdW0ocHJvZyRpbnRlcnZhbGxfMCkrc3VtKHByb2ckcGF1c2VfMCkKCnNlcXUgPC0gYygwLCBjdW1zdW0ocHJvZyRpbnRlcnZhbGxfMCkrY3Vtc3VtKHByb2ckcGF1c2VfMCkpCndsIDwtIHByb2ckUGVha184CgpwdXBMZiR3bF9zdGVwIDwtIGFzLm51bWVyaWMoY3V0KHB1cExmJHRpbWVfYywKICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxdSwKICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBULAogICAgICAgICAgICAgICByaWdodCA9IEYsCiAgICAgICAgICAgICAgIGxhYmVscyA9IHdsKSkKCnB1cExmJHdsX3RpbWUgPC0gIHB1cExmJHRpbWVfYyAtIHdsX3NlYyR3bF9iW3B1cExmJHdsX3N0ZXBdCgpwdXBMZiR3bF9zdGVwIDwtIHdsW3B1cExmJHdsX3N0ZXBdCgoKcHVwUmYkd2xfc3RlcCA8LSBhcy5udW1lcmljKGN1dChwdXBSZiR0aW1lX2MsCiAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcXUsCiAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVCwKICAgICAgICAgICAgICAgcmlnaHQgPSBGLAogICAgICAgICAgICAgICBsYWJlbHMgPSB3bCkpCgpwdXBSZiR3bF90aW1lIDwtICBwdXBSZiR0aW1lX2MgLSB3bF9zZWMkd2xfYltwdXBSZiR3bF9zdGVwXQoKcHVwUmYkd2xfc3RlcCA8LSB3bFtwdXBSZiR3bF9zdGVwXQoKI0RhcnN0ZWxsdW5nIGRlciBEYXRlbiBtaXQgbmV1ZW0gU3RhcnQgdW5kIGRlbiBqZXdlaWxpZ2VuIFdlbGxlbmzDpG5nZW4KCgpUaW1lZF9wbG90IDwtIGdncGxvdCgpICsgCiAgZ2VvbV9yZWN0KGRhdGEgPSB3bF9zZWMsIGFlcyh4bWluPSB3bF9iLCB4bWF4ID0gd2xfZSwgeW1pbiA9IDIsIHltYXggPSA4LCBmaWxsID0gd2wpKSsKICBnZW9tX2xpbmUoZGF0YSA9IHB1cExmLCBhZXMoeCA9IHRpbWVfYywgeSA9IGRpYV9zbSwgY29sID0gIkxlZnQiKSkgKwogIGdlb21fbGluZShkYXRhID0gcHVwUmYsIGFlcyh4ID0gdGltZV9jLCB5ID0gZGlhX3NtLCBjb2wgPSAiUmlnaHQiKSwgYWxwaGEgPSAwLjYpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm49MSwgIiwgQ29kZSwgICIsIFAwIiwgc2VwPSIiKSwgeCA9IDUwLCB5PSA3LjUpLCBzaXplID0gMi41KSsKICB0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZSA9IDgsIGZvbnRfZmFtaWx5ID0gInNhbnMiKSsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZ3JleTgwIiwgImJsYWNrIikpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGMocmV2KHJhaW5ib3coNTMsIHN0YXJ0ID0gMCwgZW5kID0gMC44MCkpLCByZXYocmFpbmJvdyg4LCBzdGFydCA9IDAuOTQsIGVuZCA9IDEpKSkpKwogIGdndGl0bGUoIlB1cGlsLWRpYW1ldGVyIGR1cmluZyBkaWZmZXJlbnQgd2F2ZWxlbmd0aCIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigiVGltZSAvIHNlY29uZHMiKSsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDIsOCkpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44NSwuMjIpLGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9IndoaXRlIiwgc2l6ZSA9IDAuNSkpCgpUaW1lZF9wbG90Cmdnc2F2ZSgiVGltZWRfU21vb3RoLnBkZiIsIHBhdGggPSAgcGFzdGUoIi4uL2ZpZ3VyZXMvIiwgQ29kZSwgc2VwPSIiKSxsaW1pdHNpemU9Riwgd2lkdGg9MjAsIGhlaWdodCA9IDUpCgogV0xfcGxvdCA8LSBnZ3Bsb3QoKSArIAogIGdlb21fbGluZShkYXRhID0gcHVwTGYsIGFlcyh4ID0gYXMuZmFjdG9yKHdsX3N0ZXApLCB5ID0gZGlhX3NtLCBjb2wgPSAiTGVmdCIpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBSZiwgYWVzKHggPSBhcy5mYWN0b3Iod2xfc3RlcCksIHkgPSBkaWFfc20sIGNvbCA9ICJSaWdodCIpLCBhbHBoYSA9IDAuNikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgibj0xLCAiLCBDb2RlLCAgIiwgUDAiLCBzZXA9IiIpLCB4ID0gNTAsIHk9IDgpLCBzaXplID0gMi41KSsKICB0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZSA9IDgsIGZvbnRfZmFtaWx5ID0gInNhbnMiKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgIkV5ZSIpKwogIGdndGl0bGUoIlB1cGlsLWRpYW1ldGVyIHBlciB3YXZlbGVuZ3RoIikrCiAgeWxhYigiUHVwaWwgZGlhbWV0ZXIgLyBtbSIpICsKICB4bGFiKCJ3YXZlbGVuZ3RoIC8gbm0iKSsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDIsOCkpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45LC4xKSxsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIsIHNpemUgPSAwLjUpKQoKV0xfcGxvdApnZ3NhdmUoIldhdmVsZW5ndGhfUGxvdC5wZGYiLCBwYXRoID0gIHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksbGltaXRzaXplPUYsIHdpZHRoPTEwLCBoZWlnaHQgPSA1KQoKV0xfcGxvdDIgPC0gZ2dwbG90KCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHB1cExmLCBhZXMoeCA9IHdsX3RpbWUsIHkgPSBkaWFfc20sIGdyb3VwID0gd2xfc3RlcCwgY29sID0gd2xfc3RlcCkpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm49MSwgIiwgQ29kZSwgICIsIFAwIiwgc2VwPSIiKSwgeCA9IDAuNSwgeT0gOCksIHNpemUgPSAyLjUpKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBjKHJldihyYWluYm93KDUzLCBzdGFydCA9IDAsIGVuZCA9IDAuODApKSwgcmV2KHJhaW5ib3coOCwgc3RhcnQgPSAwLjk0LCBlbmQgPSAxKSkpKSsKICBnZ3RpdGxlKCJQdXBpbC1kaWFtZXRlciBkZXBlbmRpbmcgb24gd2F2ZWxlbmd0aCIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigiVGltZSAvIHNlY29uZHMiKSsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDIsOCkpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45LC4xKSxsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIsIHNpemUgPSAwLjUpKQoKV0xfcGxvdDIKZ2dzYXZlKCJXYXZlbGVuZ3RoX1Bsb3QyLnBkZiIsIHBhdGggPSAgcGFzdGUoIi4uL2ZpZ3VyZXMvIiwgQ29kZSwgc2VwPSIiKSxsaW1pdHNpemU9Riwgd2lkdGg9MTAsIGhlaWdodCA9IDcuNSkKCldMX3Bsb3QybG9nIDwtIGdncGxvdCgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSBsb2cxMCh3bF90aW1lKSwgeSA9IGRpYV9zbSwgZ3JvdXAgPSB3bF9zdGVwLCBjb2wgPSB3bF9zdGVwKSkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgibj0xLCAiLCBDb2RlLCAgIiwgUDAiLCBzZXA9IiIpLCB4ID0gLTEsIHk9IDgpLCBzaXplID0gMi41KSsKICB0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZSA9IDgsIGZvbnRfZmFtaWx5ID0gInNhbnMiKSsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gYyhyZXYocmFpbmJvdyg1Mywgc3RhcnQgPSAwLCBlbmQgPSAwLjgwKSksIHJldihyYWluYm93KDgsIHN0YXJ0ID0gMC45NCwgZW5kID0gMSkpKSkrCiAgZ2d0aXRsZSgiUHVwaWwtZGlhbWV0ZXIgZGVwZW5kaW5nIG9uIHdhdmVsZW5ndGgiKSsKICB5bGFiKCJQdXBpbCBkaWFtZXRlciAvIG1tIikgKwogIHhsYWIoIlRpbWUgLyBsb2cxMChzZWNvbmRzKSIpKyAKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMiw4KSwgeGxpbSA9IGMoLTEuNSwgbG9nMTAoMTUpKSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjksLjEpLGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9IndoaXRlIiwgc2l6ZSA9IDAuNSkpCgpXTF9wbG90MmxvZwpnZ3NhdmUoIldhdmVsZW5ndGhfUGxvdDJsb2cucGRmIiwgcGF0aCA9ICBwYXN0ZSgiLi4vZmlndXJlcy8iLCBDb2RlLCBzZXA9IiIpLGxpbWl0c2l6ZT1GLCB3aWR0aD0xMCwgaGVpZ2h0ID0gNy41KQoKYGBgCgoKSW0gZm9sZ2VuZGVuIEFic2Nobml0dCB3ZXJkZW4gTWl0dGVsd2VydGUgZsO8ciBqZWRlIFNla3VuZGUgZGVzIExpY2h0cmVpemVzIGdlYmlsZGV0LiBEaWVzZSB3ZXJkZW4gbm9ybWllcnQsIGJlem9nZW4gYXVmIGRpZSBEaWZmZXJlbnogendpc2NoZW4gZGVyIG1heGltYWxlbiB1bmQgbWluaW1hbGVuIFB1cGlsbGVud2VpdGUuCmBgYHtyIE1pdHRlbHdlcnRzYmlsZHVuZ30KIyBadW7DpGNoc3Qgd2lyZCBkaWUgLUJhc2VsaW5lLUdyw7bDn2UgYmVzdGltbXQuIFNpZSB3aXJkIGhpZXIgZGVmaW5pZXJ0IGFscyBkZXIgTWl0dGVsd2VydCBkZXIgUHVwaWxsZSBpbiBkZW4gbGV0enRlbiA1IFNla3VuZGVuIGRlciBEdW5rZWxhZGFwdGF0aW9uCiMgSW4gRsOkbGxlbiwgaW4gZGVuZW4gZGllIFB1cGlsbGUgd8OkaHJlbmQgZGVyIEJlbGljaHR1bmcgbmllZHJpZ2VyZSBXZXJ0ZSBhbm5pbW10LCBrYW5uIGF1Y2ggZGllIGdyw7bDn3RlIFB1cGlsbGVuZ3LDtsOfZSB3w6RocmVuZCBkZXIgQmVsaWNodHVuZyBnZXfDpGhsdCB3ZXJkZW4uIERpZXMgZXJmb2xndCBhdXRvbWF0aXNjaCBhbmhhbmQgZGVzIGdyw7bDn2VyZW4gV2VydHMKCkxfbm9ybSA8LSBhcy5udW1lcmljKAogICAgICAgICAgICAgICAgICBpZmVsc2UocHVwTGYgJT4lIGRwbHlyOjpmaWx0ZXIodGltZV9jIDwgMCAmIHRpbWVfYyA+IC01KSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1lYW4oZGlhX3NtKSkgPiAKICAgICAgICAgICAgICAgICAgIHB1cExmICU+JSBkcGx5cjo6ZmlsdGVyKHRpbWVfYyA+IDAgJiB0aW1lX2MgPCB0b3RfcGVyKSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1heChkaWFfc20pKSwgCiAgICAgICAgICAgICAgICAgcHVwTGYgJT4lIGRwbHlyOjpmaWx0ZXIodGltZV9jIDwgMCAmIHRpbWVfYyA+IC01KSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1lYW4oZGlhX3NtKSksIAogICAgICAgICAgICAgICAgIHB1cExmICU+JSBkcGx5cjo6ZmlsdGVyKHRpbWVfYyA+IDAgJiB0aW1lX2MgPCB0b3RfcGVyKSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1heChkaWFfc20pKQogICAgICAgICAgICAgICAgICkpCgojIEltIG7DpGNoc3RlbiBTY2hyaXR0IHdlcmRlbiBkaWUgU2VrdW5kZW5taXR0ZWx3ZXJ0ZSBmw7xyIGplZGUgV2VsbGVubMOkbmdlIGdlYmlsZGV0LCB6dWRlbSBkZXIgTWl0dGVsd2VydCBkZXIgbGV0enRlbiA1IFNla3VuZGVuIHVuZCBkaWUgbWluaW1hbGVuIFB1cGlsbGVuZ3LDtsOfZW4gZsO8ciBkaWUgamV3ZWlsaWdlbiBaZWl0aW50ZXJ2YWxsZQoKTF92YWwgPC0gcHVwTGYgJT4lIGdyb3VwX2J5KHdsX3N0ZXAsIHdsX3RpbWUgJS8lIDEpICU+JSBzdW1tYXJpemUoZF9hYnMgPSBtZWFuKGRpYV9zbSkpCkxfdmFsMTAgPC0gcHVwTGYgJT4lIGRwbHlyOjpmaWx0ZXIod2xfdGltZSA8PSAxMy45ICYgd2xfdGltZSA+PSA5LjkpICAlPiUgZ3JvdXBfYnkod2xfc3RlcCkgJT4lIHN1bW1hcml6ZShkX2FicyA9IG1lYW4oZGlhX3NtKSkKCm5hbWVzKExfdmFsKSA8LSBjKCJ3bCIsICJ0aW1lIiwgImRfYWJzIikKbmFtZXMoTF92YWwxMCkgPC0gYygid2wiLCAiZF9hYnMiKQoKdGVtcCA8LSBMX3ZhbCAlPiUgZHBseXI6OmZpbHRlcih3bCAhPSAiTkEiKSAlPiUgZ3JvdXBfYnkodGltZSkgJT4lIHN1bW1hcml6ZShtaW4gPSBtaW4oZF9hYnMpKQoKTF9ub3JtIDwtIGRhdGFfZnJhbWUoIkNvbmQiID0gYygiRGFyayIsIHRlbXAkdGltZSwgIjEwXzE1IiksICJkaWEiID0gYyhMX25vcm0sIHRlbXAkbWluLCBtaW4oTF92YWwxMCRkX2FicykpKQoKCiMgSGllciB3aXJkIHp1bsOkY2hzdCBlaW5lIHRlbXBvcsOkcmUgVmFyaWFibGUgZXJ6ZXVndCwgd2VsY2hlIGbDvHIgamVkZSBaZWlsZSBpbiBkZW4gU2VrdW5kZW5taXR0ZWx3ZXJ0ZGF0ZW4gZGllIGtvcnJlc3BvbmRpZXJlbmRlIG1pbmltYWxlIFB1cGlsbGVuZ3LDtsOfZSBhbmdpYnQuCgp0ZW1wIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKChjdXQoTF92YWwkdGltZSwKICAgICAgICAgICAgICAgYnJlYWtzID0gMDoobWF4KHByb2ckaW50ZXJ2YWxsXzArcHJvZyRwYXVzZV8wKSAlLyUgMSArMSksCiAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVCwKICAgICAgICAgICAgICAgcmlnaHQgPSBGLAogICAgICAgICAgICAgICBsYWJlbHMgPSBMX25vcm0kZGlhWzI6KGxlbmd0aChMX25vcm0kZGlhKS0xKV0pKQopKSAKCgojIEltIGZvbGdlbmRlbiBTY2hyaXR0IHdlcmRlbiByZWxhdGl2ZSBQdXBpbGxlbmtvbnN0cmlrdGlvbnN3ZXJ0ZSBnZWJpbGRldCwgYW1wIGlzdCBkYWJlaSBkaWUgS29uc3RyaWt0aW9uc2FtcGxpdHVkZSBiZXpvZ2VuIGF1ZiBkaWUgQmFzZWxpbmUtR3LDtsOfZSwgYW1wMiBhdWYgZGllIFNwYW5uZSB6d2lzY2hlbiBkZXIgQmFzbGluZS1HcsO2w59lIHVuZCBkZXIga2xlaW5zdGVuLCBmw7xyIGRpZXNlIFplaXRzcGFubmUgZ2VtZXNzZW5lbiBQdXBpbGxlbmdyw7bDn2UuCgpMX3ZhbCRhbXAgPC0gKExfbm9ybSRkaWFbTF9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIExfdmFsJGRfYWJzKS9MX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0qMTAwCkxfdmFsMTAkYW1wIDwtIChMX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0gLSBMX3ZhbDEwJGRfYWJzKS9MX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0qMTAwCgpMX3ZhbCRhbXAyIDwtIChMX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0gLSBMX3ZhbCRkX2FicykvKExfbm9ybSRkaWFbTF9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIHRlbXApKjEwMApMX3ZhbDEwJGFtcDIgPC0gKExfbm9ybSRkaWFbTF9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIExfdmFsMTAkZF9hYnMpLyhMX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0gLSBMX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICIxMF8xNSJdKSoxMDAKCiMjTnVuIGF1Y2ggZsO8ciBkYXMgcmVjaHRlIEF1Z2UKIyBadW7DpGNoc3Qgd2lyZCBkaWUgLUJhc2VsaW5lLUdyw7bDn2UgYmVzdGltbXQuIFNpZSB3aXJkIGhpZXIgZGVmaW5pZXJ0IGFscyBkZXIgTWl0dGVsd2VydCBkZXIgUHVwaWxsZSBpbiBkZW4gbGV0enRlbiA1IFNla3VuZGVuIGRlciBEdW5rZWxhZGFwdGF0aW9uCiMgSW4gRsOkbGxlbiwgaW4gZGVuZW4gZGllIFB1cGlsbGUgd8OkaHJlbmQgZGVyIEJlbGljaHR1bmcgbmllZHJpZ2VyZSBXZXJ0ZSBhbm5pbW10LCBrYW5uIGF1Y2ggZGllIGdyw7bDn3RlIFB1cGlsbGVuZ3LDtsOfZSB3w6RocmVuZCBkZXIgQmVsaWNodHVuZyBnZXfDpGhsdCB3ZXJkZW4uIERpZXMgZXJmb2xndCBhdXRvbWF0aXNjaCBhbmhhbmQgZGVzIGdyw7bDn2VyZW4gV2VydHMKClJfbm9ybSA8LSBhcy5udW1lcmljKAogICAgICAgICAgICAgICAgICBpZmVsc2UocHVwUmYgJT4lIGRwbHlyOjpmaWx0ZXIodGltZV9jIDwgMCAmIHRpbWVfYyA+IC01KSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1lYW4oZGlhX3NtKSkgPiAKICAgICAgICAgICAgICAgICAgIHB1cFJmICU+JSBkcGx5cjo6ZmlsdGVyKHRpbWVfYyA+IDAgJiB0aW1lX2MgPCB0b3RfcGVyKSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1heChkaWFfc20pKSwgCiAgICAgICAgICAgICAgICAgcHVwUmYgJT4lIGRwbHlyOjpmaWx0ZXIodGltZV9jIDwgMCAmIHRpbWVfYyA+IC01KSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1lYW4oZGlhX3NtKSksIAogICAgICAgICAgICAgICAgIHB1cFJmICU+JSBkcGx5cjo6ZmlsdGVyKHRpbWVfYyA+IDAgJiB0aW1lX2MgPCB0b3RfcGVyKSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1heChkaWFfc20pKQogICAgICAgICAgICAgICAgICkpCgojIEltIG7DpGNoc3RlbiBTY2hyaXR0IHdlcmRlbiBkaWUgU2VrdW5kZW5taXR0ZWx3ZXJ0ZSBmw7xyIGplZGUgV2VsbGVubMOkbmdlIGdlYmlsZGV0LCB6dWRlbSBkZXIgTWl0dGVsd2VydCBkZXIgbGV0enRlbiA1IFNla3VuZGVuIHVuZCBkaWUgbWluaW1hbGVuIFB1cGlsbGVuZ3LDtsOfZW4gZsO8ciBkaWUgamV3ZWlsaWdlbiBaZWl0aW50ZXJ2YWxsZQoKUl92YWwgPC0gcHVwUmYgJT4lIGdyb3VwX2J5KHdsX3N0ZXAsIHdsX3RpbWUgJS8lIDEpICU+JSBzdW1tYXJpemUoZF9hYnMgPSBtZWFuKGRpYV9zbSkpClJfdmFsMTAgPC0gcHVwUmYgJT4lIGRwbHlyOjpmaWx0ZXIod2xfdGltZSA8PSAxNSAmIHdsX3RpbWUgPj0gMTApICAlPiUgZ3JvdXBfYnkod2xfc3RlcCkgJT4lIHN1bW1hcml6ZShkX2FicyA9IG1lYW4oZGlhX3NtKSkKCm5hbWVzKFJfdmFsKSA8LSBjKCJ3bCIsICJ0aW1lIiwgImRfYWJzIikKbmFtZXMoUl92YWwxMCkgPC0gYygid2wiLCAiZF9hYnMiKQoKdGVtcCA8LSBSX3ZhbCAlPiUgZHBseXI6OmZpbHRlcih3bCAhPSAiTkEiKSAlPiUgZ3JvdXBfYnkodGltZSkgJT4lIHN1bW1hcml6ZShtaW4gPSBtaW4oZF9hYnMpKQoKUl9ub3JtIDwtIGRhdGFfZnJhbWUoIkNvbmQiID0gYygiRGFyayIsIHRlbXAkdGltZSwgIjEwXzE1IiksICJkaWEiID0gYyhSX25vcm0sIHRlbXAkbWluLCBtaW4oUl92YWwxMCRkX2FicykpKQoKCgojIEltIGZvbGdlbmRlbiBTY2hyaXR0IHdlcmRlbiByZWxhdGl2ZSBQdXBpbGxlbmtvbnN0cmlrdGlvbnN3ZXJ0ZSBnZWJpbGRldCwgYW1wIGlzdCBkYWJlaSBkaWUgS29uc3RyaWt0aW9uc2FtcGxpdHVkZSBiZXpvZ2VuIGF1ZiBkaWUgQmFzZWxpbmUtR3LDtsOfZSwgYW1wMiBhdWYgZGllIFNwYW5uZSB6d2lzY2hlbiBkZXIgQmFzbGluZS1HcsO2w59lIHVuZCBkZXIga2xlaW5zdGVuLCBmw7xyIGRpZXNlIFplaXRzcGFubmUgZ2VtZXNzZW5lbiBQdXBpbGxlbmdyw7bDn2UuCgp0ZW1wIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKChjdXQoUl92YWwkdGltZSwKICAgICAgICAgICAgICAgYnJlYWtzID0gMDoobWF4KHByb2ckaW50ZXJ2YWxsXzArcHJvZyRwYXVzZV8wKSAlLyUgMSArMSksCiAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVCwKICAgICAgICAgICAgICAgcmlnaHQgPSBGLAogICAgICAgICAgICAgICBsYWJlbHMgPSBSX25vcm0kZGlhWzI6KGxlbmd0aChSX25vcm0kZGlhKS0xKV0pKQopKSAjIEhpZXIgd2lyZCB6dW7DpGNoc3QgZWluZSB0ZW1wb3LDpHJlIFZhcmlhYmxlIGVyemV1Z3QsIHdlbGNoZSBmw7xyIGplZGUgWmVpbGUgaW4gZGVuIFNla3VuZGVubWl0dGVsd2VydGRhdGVuIGRpZSBrb3JyZXNwb25kaWVyZW5kZSBtaW5pbWFsZSBQdXBpbGxlbmdyw7bDn2UgYW5naWJ0LgoKUl92YWwkYW1wIDwtIChSX25vcm0kZGlhW1Jfbm9ybSRDb25kID09ICJEYXJrIl0gLSBSX3ZhbCRkX2FicykvUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiRGFyayJdKjEwMApSX3ZhbDEwJGFtcCA8LSAoUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiRGFyayJdIC0gUl92YWwxMCRkX2FicykvUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiRGFyayJdKjEwMAoKUl92YWwkYW1wMiA8LSAoUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiRGFyayJdIC0gUl92YWwkZF9hYnMpLyhSX25vcm0kZGlhW1Jfbm9ybSRDb25kID09ICJEYXJrIl0gLSB0ZW1wKSoxMDAKUl92YWwxMCRhbXAyIDwtIChSX25vcm0kZGlhW1Jfbm9ybSRDb25kID09ICJEYXJrIl0gLSBSX3ZhbDEwJGRfYWJzKS8oUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiRGFyayJdIC0gUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiMTBfMTUiXSkqMTAwCgoKI0Fic2NobGllw59lbmQgZGllIGdyYWZpc2NoZSBEYXJzdGVsbHVuZwpTZW5zIDwtICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBMX3ZhbCwgYWVzKHg9d2wsIHk9YW1wMiwgZ3JvdXAgPSB0aW1lLCBjb2wgPSAiTGVmdCIpLCBhbHBoYSA9IDAuMjUpICsKICBnZW9tX2xpbmUoZGF0YSA9IFJfdmFsLCBhZXMoeD13bCwgeT1hbXAyLCBncm91cCA9IHRpbWUsIGNvbCA9ICJSaWdodCIpLCBhbHBoYSA9IDAuMjUpICsKICBnZW9tX2xpbmUoZGF0YSA9IExfdmFsMTAsIGFlcyh5PWFtcDIsIHg9d2wsIGNvbCA9ICJMZWZ0IiksIGx3ZCA9IDEpKwogIGdlb21fbGluZShkYXRhID0gUl92YWwxMCwgYWVzKHk9YW1wMiwgeD13bCwgY29sID0gIlJpZ2h0IiksIGx3ZCA9IDEpKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgibj0xLCAiLCBDb2RlLCAiLCBQMCIsIHNlcD0iIiksIHggPSA0MDAsIHk9IDEwMCksIHNpemUgPSAyLjUpKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCAiRXllIikrCiAgZ2d0aXRsZSgiU2Vuc2l0aXZpdHkgZGVwZW5kaW5nIG9uIHdhdmVsZW5ndGggYW5kIHRpbWUgKDEtMTUgcGVyIHNlY29uZCBhdmVyYWdlcyBpbiBsaWdodGVyIHRvbmUpIikrCiAgeWxhYigiU2Vuc2l0aXZpdHkgLyAlIikgKwogIHhsYWIoIldhdmVsZW5ndGggLyBubSIpKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMiksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKClNlbnMKZ2dzYXZlKCJTZW5zaXRpdml0eS5wZGYiLCBwYXRoID0gIHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksbGltaXRzaXplPUYsIHdpZHRoPTEwLCBoZWlnaHQgPSA2KQoKYGBgCgoKU2NobGllw59saWNoIGVyZm9sZ3QgZGVyIEV4cG9ydCBkZXIgTWl0dGVsd2VydGUgZsO8ciBhbGxlIFdlbGxlbmzDpG5nZW4sIHNvd2llIGbDvHIgZGllIE5vcm1pZXJ1bmdzcmFuZGJlZGluZ3VuZ2VuCmBgYHtyIEV4cG9ydH0KI0VudHNjaGVpZHVuZyBmw7xyIGVpbiBBdWdlLCBhdWYgQmFzaXMgZGVyIG1laXN0ZW4gRGF0ZW52ZXJmw7xnYmFya2VpdCwgc29mZXJuIG5pY2h0IG1hbnVlbGwgZXR3YXMgYW5nZWdlYmVuIHdpcmQuCgpleHBvcnQgPC0gaWZlbHNlKGxlbmd0aChwdXBMZiRkaWFfc20pID4gbGVuZ3RoKHB1cFJmJGRpYV9zbSksICJMIiwgIlIiKQoKCnBhc3RlKCJ0aGUgcHVwaWwgb2YgdGhlIGZvbGxvd2luZyBleWUgaXMgdXNlZCBmb3IgZXhwb3J0OiAiLCBpZmVsc2UoZXhwb3J0ID09ICJSIiwgIlJpZ2h0IiwgIkxlZnQiKSkKCiNFcnN0ZWxsdW5nIGRlciBFeHBvcnRkYXRlbiBmw7xyIGRpZSBTZWt1bmRlbm1pdHRlbHdlcnRlLCBkaWUgMTAtMTUgU2VrdW5kZW5taXR0ZWx3ZXJ0ZSwgdW5kIGbDvHIgZGllIE5vcm1pZXJ1bmdzcmFuZGJlZGluZ3VuZ2VuCgp0ZW1wIDwtIGdldChwYXN0ZShleHBvcnQsICJfbm9ybSIsIHNlcD0iIikpCmV4cG9ydF9kYXRhMyA8LSBkYXRhLmZyYW1lKHQodGVtcFstMV0pKQpjb2xuYW1lcyhleHBvcnRfZGF0YTMpIDwtIHRlbXAkQ29uZApleHBvcnRfZGF0YTMgPC0gdGliYmxlKCJDb2RlIiA9IENvZGUsICJFeWUiID0gaWZlbHNlKGV4cG9ydCA9PSAiUiIsICJSaWdodCIsICJMZWZ0IiksICJEYXRlIiA9IGFzLkRhdGUocHVwJFVUQ1sxXSksICJUaW1lIiA9IGZvcm1hdChhcy5QT1NJWGN0KHB1cCRVVENbMV0pLCBmb3JtYXQgPSAiJUg6JU06JVMiKSwgIkRpciIgPSAiQ2VudHJhbDMiLCBleHBvcnRfZGF0YTMpCgpleHBvcnRfZGF0YTAgPC0gZ2V0KHBhc3RlKCJwdXAiLCBleHBvcnQsICJmIiwgc2VwPSIiKSkKZXhwb3J0X2RhdGEwJGFtcDEgPC0gKGV4cG9ydF9kYXRhMyREYXJrWzFdIC0gZXhwb3J0X2RhdGEwJGRpYV9zbSkvZXhwb3J0X2RhdGEzJERhcmtbMV0qMTAwCgpleHBvcnRfZGF0YTEgPC0gZ2V0KHBhc3RlKGV4cG9ydCwgIl92YWwiLCBzZXA9IiIpKVstbGVuZ3RoKGdldChwYXN0ZShleHBvcnQsICJfdmFsIiwgc2VwPSIiKSkkd2wpLF0KZXhwb3J0X2RhdGExJGluZGV4IDwtIG1hdGNoKGV4cG9ydF9kYXRhMSR3bCwgd2wpCgpleHBvcnRfZGF0YTIgPC0gZ2V0KHBhc3RlKGV4cG9ydCwgIl92YWwxMCIsIHNlcD0iIikpCmV4cG9ydF9kYXRhMiRpbmRleCA8LSBtYXRjaChleHBvcnRfZGF0YTIkd2wsIHdsKQoKd3JpdGVfY3N2KGV4cG9ydF9kYXRhMCwgcGFzdGUoIi4uL2RhdGFfb3V0cHV0LyIsIENvZGUsICJfZnVsbC5jc3YiLCBzZXA9IiIpICkKd3JpdGVfY3N2KGV4cG9ydF9kYXRhMSwgcGFzdGUoIi4uL2RhdGFfb3V0cHV0LyIsIENvZGUsICJfYWxsLmNzdiIsIHNlcD0iIikgKQp3cml0ZV9jc3YoZXhwb3J0X2RhdGEyLCBwYXN0ZSgiLi4vZGF0YV9vdXRwdXQvIiwgQ29kZSwgIl8xMF8xNS5jc3YiLCBzZXA9IiIpICkKd3JpdGVfY3N2KGV4cG9ydF9kYXRhMywgcGFzdGUoIi4uL2RhdGFfb3V0cHV0LyIsIENvZGUsICJfbm9ybS5jc3YiLCBzZXA9IiIpICkKCmBgYAoKCmBgYHtyIE9wdGlvbiwgZXZhbCA9IEZ9CiMtLS0tIEFuZmFuZyBDb2RlLU9wdGlvbgoKI0FsdGVybmF0aXYsIHdlbm4gbWl0IGRlbSBSZWNodGVuIEF1Z2UgZGllIFplaXQgZXJmYXNzdCB3aXJkLgoKI0JpbGR1bmcgZGVyIDEuIHVuZCAyLiBBYmxlaXR1bmcuIExpbmVhcmUgVHJhbnNmb3JtYXRpb24sIGRhbWl0IGRpZSDDnGJlcmxhZ2VydW5nIG1pdCBkZW0gUHVwaWxsZW5kdXJjaG1lc3NlciBsZXNiYXIgYmxlaWJ0LgoKcHVwUmYkZGlhX3NtMSA8LSAoc2dvbGF5ZmlsdChwdXBSZiRkaWEsIHA9Mywgbj0zMSwgbT0xKSkqMTAwKzYKcHVwUmYkZGlhX3NtMiA8LSAoc2dvbGF5ZmlsdChwdXBSZiRkaWEsIHA9Mywgbj0zMSwgbT0yKSkqMTAwKzYKCgojRXJrZW5udW5nIGRlciBUaWVmcHVua3RlIGRlciAyLiBBYmxlaXR1bmcKdmx5IDwtIGdncGxvdChkYXRhID0gcHVwUmYsIGFlcyh4PXRpbWUsIHk9ZGlhX3NtMikpICsgCiAgIHN0YXRfdmFsbGV5cyhzcGFuID0gNjAxLCBjb2wgPSAiZ3JlZW4iKQogdmx5X2RhdGEgPC0gKGxheWVyX2RhdGEodmx5LCBpPTFMKSR4aW50ZXJjZXB0KQoKI0RhcnN0ZWxsdW5nIGRlciBUaWVmcHVua3RlIGRlciAyLiBBYmxlaXR1bmcKIERlcml2YXRpdmVfdGVzdCA8LSBnZ3Bsb3QoZGF0YSA9IHB1cFJmLCBhZXMoeD10aW1lLCB5PWRpYV9zbTIsIGNvbD0idmFsbGV5IikpICsgCiAgIGdlb21fbGluZShkYXRhID0gcHVwUmYsIGFlcyh4ID0gdGltZSwgeSA9IGRpYV9zbSwgY29sID0gIkRpYW1ldGVyIikpICsKICAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSB0aW1lLCB5ID0gZGlhX3NtLCBjb2wgPSAiRGlhbWV0ZXIiKSkgKwogICAgIGdlb21fbGluZShhZXMoY29sID0gIjJzdCBkZXJpdmF0aXZlIiksIGFscGhhID0gMC42KSArCiAgIHN0YXRfdmFsbGV5cyhzcGFuID0gNjAxLCBjb2wgPSAiZ3JlZW4iKSsKICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gdmx5X2RhdGEtMC4xLCBsd2QgPSAwLjEsIGNvbD0iZ3JlZW4iKSsKICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsIHNlcD0iIiksIHggPSA4NSwgeT0gOCksIHNpemUgPSAyLjUpKwogICB0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZSA9IDgsIGZvbnRfZmFtaWx5ID0gInNhbnMiKSsKICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsICJUeXBlIikrCiAgIGdndGl0bGUoIlB1cGlsLWRpYW1ldGVyIGRhdGEgc21vb3RoZWQgd2l0aCAybmQgZGVyaXZhdGl2ZSBhbmQgdmFsbGV5cyAoLTEwMG1zKSIpKwogICB5bGFiKCJQdXBpbCBkaWFtZXRlciAvIG1tIikgKwogICB4bGFiKCJUaW1lIC8gc2Vjb25kcyIpKwogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkrCiAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYyg4NSwgMTUwKSkKCiBEZXJpdmF0aXZlX3Rlc3QKIGdnc2F2ZSgiUHVwaWxfRGVyaXZhdGl2ZV90ZXN0LnBkZiIsIHBhdGggPSBwYXN0ZSgiLi4vZmlndXJlcy8iLCBDb2RlLCBzZXA9IiIpLCB3aWR0aD0xMCwgaGVpZ2h0ID0gNSkKCiNXYWhsIGVpbmVzIFByb2dyYW1tc3RhcnRwdW5rdHMKCnZseV9kYXRhIDwtIHRpYmJsZSgiaW5kZXgiID0gMTogbGVuZ3RoKHZseV9kYXRhKSwgInRpbWUiID0gdmx5X2RhdGEtMC4xLCAiZGlmIiA9IGModmx5X2RhdGFbMV0sIGRpZmYodmx5X2RhdGEpKSkKa2FibGUodmx5X2RhdGFbMToyMCxdLCAicGFuZG9jIiwgY2FwdGlvbiA9ICJUaW1lIG9mIDJuZCBkZXJpdmF0aXZlIHZhbGxleXMgKC0xMDBtcyksIGZpcnN0IDIwIHJvd3MiLCBhbGlnbiA9ICJjIikjIFRpZWZwdW5rdGUgbWl0IFplaXRzdGVtcGVsCgojLS0tLSBFbmRlIENvZGUtT3B0aW9uCmBgYAoK