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 5” 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.

Um den Code für eine neue Person anzupassen, sind die folgenden Eingriffe notwendig. Zeilenangaben beziehen sich auf das *.Rmd-File:

  1. Zeile 37 -> Einfügen des korrekten Dateinamens / Pfad

  2. Zeile 45 -> Versuchspersonencode einfügen

  3. Zeilen 116-128 -> Prüfung, ob die Kriterien zur Messwertaussortierung bei Zirkularität, absolutem Abschnitt, und dem Schlussschnitt in Ordnung sind

  4. 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.

  5. 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/Down/EM111201_2. Messung 24.08.2020 171119_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 <- "EM111201"

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, ", Down", 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, ", Down",  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,  ", Down", 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, 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,  ", Down", 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,  ", Down", sep=""), x = 50, 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
index time dif
1 7.714 7.814
2 16.647 8.933
3 25.847 9.200
4 43.964 18.117
5 58.497 14.533
6 67.380 8.883
7 84.280 16.900
8 98.780 14.500
9 107.564 8.784
10 126.780 19.216
11 135.597 8.817
12 144.264 8.667
13 149.864 5.600
14 158.830 8.966
15 174.464 15.634
16 183.714 9.250
17 189.597 5.883
18 204.780 15.183
19 219.880 15.100
20 225.564 5.684

NA

sequ_per <- 15.145 #Sequenz Periode -> Ermittlung aus Video mit Geräuschanalyse

#Welcher index ist der Startzeitpunkt?
i <- 8 # Hier muss man auf Basis der Grafik und der Tabelle den Startzeitpunkt angeben

#Zeitkorrektur notwendig?
cor <- 0

pupLf$time_c <- pupLf$time - vly_data$time[vly_data$index == i] + sequ_per*cor
pupRf$time_c <- pupRf$time - vly_data$time[vly_data$index == i] + sequ_per*cor


#Ergänzung der Wellenlängen 

wl_sec <- tibble(
  "wl" = rev(prog$Peak_5), 
  "wl_b" = seq(from = 0, to = (length(prog$Peak_5)-1)*sequ_per, by = sequ_per),
  "wl_e" = seq(from = sequ_per, to = length(prog$Peak_5)*sequ_per, by = sequ_per)
  )

tot_per <- length(prog$Peak_5)*sequ_per

sequ <- seq(from=0, to = tot_per, by = sequ_per)
wl <- rev(prog$Peak_5)
prog$index <- length(prog$Peak_5):1

pupLf$wl_step <- as.numeric(cut(pupLf$time_c,
               breaks = sequ,
               include.lowest = T,
               right = F,
               labels = wl))

pupLf$wl_time <-  pupLf$time_c - (pupLf$wl_step-1)*sequ_per

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 - (pupRf$wl_step - 1)*sequ_per

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,  ", Down", 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,  ", Down", 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,  ", Down", 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,  ", Down", 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 <= 15 & wl_time >= 10)  %>% 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:(sequ_per %/% 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:(sequ_per %/% 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, ", Down", 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" = "Down", 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 = 50, 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
LS0tCnRpdGxlOiAiUiBQdXBpbCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQpNaXQgZGllc2VtIERva3VtZW50IHdlcmRlbiBhdXMgZGVuIERpa2FibGlzIFB1cGlsbGVucm9oZGF0ZW4gbWl0IGRlbSBIb2Noc2NodWxlLU3DvG5jaGVuIExpY2h0bGFib3IoRDExMyktU2V0dXAgYXVzd2VydHVuZ3Nmw6RoaWdlIFB1cGlsbGVuZGF0ZW4gZXh0cmFoaWVydC4gRGllIEF1c3dlcnR1bmcgaXN0IGfDvGx0aWcgZsO8ciBkYXMgIlByb2dyYW1tIDUiIGF1cyBkZW0gTGlnaHRkb21lLVN0ZXVlcnJlY2huZXIgdW5kIGbDvHIgZGllICJuZXVlIiBVbXJlY2hudW5nc21ldGhvZGUgdm9uIFBpeGVsbiB6dSBtbSwgYmVpIGRlciB2b3IgQXVmemVpY2hudW5nIGVpbiBSZWZlcmVuem1hw58gYXVmIEF1Z2VuZWJlbmUgaW0gS2FtZXJhYmlsZCBnZXplaWd0IHdpcmQuIERpZXNlcyBQcm9ncmFtbSBiZWdpbm50IG1pdCBlaW5lciBEdW5rZWxhZGFwYXRpb25zcGVyaW9kZSB2b24gOTAgU2VrdW5kZW4uIERhbmFjaCB3ZXJkZW4gaW4gY2EuIDE1IFNla3VuZGVuLVNjaHJpdHRlbiBkaWUgV2VsbGVubMOkbmdlbiB2b24gNzAwLTQwMCBubSBpbiA1IG5tIFNjaHJpdHRlbiBhYmdlZmFocmVuLiAKClVtIGRlbiBDb2RlIGbDvHIgZWluZSBuZXVlIFBlcnNvbiBhbnp1cGFzc2VuLCBzaW5kIGRpZSBmb2xnZW5kZW4gRWluZ3JpZmZlIG5vdHdlbmRpZy4gWmVpbGVuYW5nYWJlbiBiZXppZWhlbiBzaWNoIGF1ZiBkYXMgKi5SbWQtRmlsZToKCjEuIFplaWxlIDM3IC0+IEVpbmbDvGdlbiBkZXMga29ycmVrdGVuIERhdGVpbmFtZW5zIC8gUGZhZAoKMi4gWmVpbGUgNDUgLT4gVmVyc3VjaHNwZXJzb25lbmNvZGUgZWluZsO8Z2VuCgozLiBaZWlsZW4gMTE2LTEyOCAtPiBQcsO8ZnVuZywgb2IgZGllIEtyaXRlcmllbiB6dXIgTWVzc3dlcnRhdXNzb3J0aWVydW5nIGJlaSBaaXJrdWxhcml0w6R0LCBhYnNvbHV0ZW0gQWJzY2huaXR0LCB1bmQgZGVtIFNjaGx1c3NzY2huaXR0IGluIE9yZG51bmcgc2luZAoKNC4gWmVpbGUgMjEyLTIxNSAtPiBOYWNoIFByw7xmdW5nLCBvYiBkaWUgVGFsLUVya2VubnVuZyBmdW5rdGlvbmllcnQsIEFuZ2FiZSBkZXMga29ycmVrdGVuIEluZGV4IGbDvHIgZGVuIFJlZmVyZW56emVpdHB1bmt0LiBTb2xsdGUgZGFzIGJlaW0gbGlua2VuIEF1Z2UgbmljaHQgbcO2Z2xpY2ggc2VpbiwgbXVzcyBkZXIgdW50ZXJzdGUgQ29kZS1DaHVuayBhdXMgZGVyIERhdGVpIG1hbnVlbGwgaG9jaCBrb3BpZXJ0IHdlcmRlbi4gU29sbHRlIGRlciBlcnN0ZSBCZWxldWNodHVuZ3N6ZWl0cHVua3QgbmljaHQgZXJrYW5udCB3ZXJkZW4sIGthbm4gZWluIHNww6R0ZXJlciBaZWl0cHVua3QgYW5nZWdlYmVuIHdlcmRlbiAtIGluIGRpZXNlbSBGYWxsIG11c3Mgc3BlemlmaXppZXJ0IHdlcmRlbiwgdW0gd2llIHZpZWxlIFNjaHJpdHRlIGRlciBQcm9ncmFtbXN0YXJ0IHp1csO8Y2tsaWVndC4KCjUuIFplaWxlIDQyOC80MjkgLT4gRGllIEF1c3dhaGwsIHdlbGNoZXMgQXVnZSBzY2hsdXNzZW5kbGljaCBmw7xyIGRlbiBEYXRlbmV4cG9ydCB2ZXJ3ZW5kZXQgd2lyZCwgd2lyZCBzdGFuZGFyZG3DpMOfaWcgYXV0b21hdGlzY2ggdm9sbHpvZ2VuIGFuaGFuZCBkZXIgUHVwaWxsZSBtaXQgZGVtIG1laXN0ZW4gRGF0ZW5wdW5rdGVuIG5hY2ggZGVyIEJlcmVpbmlndW5nLiBTb2xsdGUgZGllc2UgQXVzd2FobCBuaWNodCBpbiBPcmRudW5nIHNlaW4sIG11c3MgaGllciBtYW51ZWxsICJSIiBvZGVyICJMIiBlaW5nZXRyYWdlbiB3ZXJkZW4uCgoKSW0gZm9sZ2VuZGVuIEFic2Nobml0dCB3ZXJkZW4gYWxsZSBub3R3ZW5kaWdlbiBCaWJsaW90aGVrZW4gZ2VsYWRlbiwgc293aWUgZGllIFJvaGRhdGVuIGVpbmdlbGVzZW4uIERlciBBYnNjaG5pdHQgZW5kZXQgbWl0IGVpbmVyIERhcnN0ZWxsdW5nIGRlciBSb2hkYXRlbiBkZXIgUHVwaWxsZW4sIHNvd2llIGRlciBaaXJrdWxhcmnDpHQuCgpgYGB7ciBEYXRlbiBlaW5sZXNlbn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoYW55dGltZSkKbGlicmFyeShzaWduYWwpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdncG1pc2MpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGtuaXRyKQoKc2V0d2QoZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRBY3RpdmVEb2N1bWVudENvbnRleHQoKSRwYXRoKSkgIyBTZXR6ZW4gZGVzIEFyYmVpdHN2ZXJ6ZWljaG5pc3NlcyBhdWYgZ2xlaWNoZXMgVmVyemVpY2huaXMgd2llIFNjcmlwdCAKCnB1cCA8LSByZWFkLnRhYmxlKCIuLi9kYXRhX2lucHV0L0Rvd24vRU0xMTEyMDFfMi4gTWVzc3VuZyAyNC4wOC4yMDIwIDE3MTExOV9Dc3ZEYXRhLnR4dCIsIHNlcCA9ICJcdCIsIGhlYWRlciA9IFRSVUUsIHN0cmluZ3NBc0ZhY3RvcnM9RikgIyBFaW5sZXNlbiBkZXIgRGF0ZW4gUHVwaWxsZQpwcm9nIDwtIHJlYWQudGFibGUoIi4uL2RhdGFfaW5wdXQvcHJvZ3JhbV9kYXRhX2xkLmNzdiIsIGRlYyA9ICIsIiwgc2VwID0gIjsiLCBoZWFkZXIgPSBUUlVFLCBzdHJpbmdzQXNGYWN0b3JzPUYpICMgRWlubGVzZW4gZGVyIFByb2dyYW1tZGF0ZW4KY29yZiA8LSByZWFkX2V4Y2VsKCIuLi9VzIhiZXJzaWNodF9WUC54bHN4Iiwgc2hlZXQgPSAiVWViZXJzaWNodF9WUCIsIG5hPSJOQSIpICNsb2FkIGluIHRoZSBmaWxlIHdpdGggYWxsIGluZGl2aWR1YWwgY29kZXMgIyBFaW5sZXNlbiBkZXIgS29ycmVrdHVyZmFrdG9yZW4KCiNBdXN3w6RobGVuIGRlciBub3R3ZW5kaWdlbiBTcGFsdGVuIHVuZCBTcGFsdGVuIHVtYmVuZW5uZW4KI1VtcmVjaG5lbiBkZXMgVVRDLVplaXRzdGVtcGVscyBpbiBsb2thbGUgWmVpdAojQmVyZWNobnVuZyBkZXMgUHVwaWxsZW5kdXJjaG1lc3NlcnMgKG51ciBmw7xyIFJlZmVyZW56bWHDnyAtIERpZSBLb3JyZWt0dXJmYWt0b3JlbiBhbGxlciBQcm9iYW5kZW4gd2VyZGVuIGluIGVpbmVyIHNlcGFyYXRlbiBEYXRlaSBnZXNwZWljaGVydCkKCkNvZGUgPC0gIkVNMTExMjAxIgoKZGlyLmNyZWF0ZShwYXN0ZSgiLi4vZmlndXJlcy8iLCBDb2RlLCBzZXA9IiIpKQoKcHVwIDwtIHNlbGVjdChwdXAsIHJlY190aW1lLCBVVEMsIERpa2FibGlzLlByb2Zlc3Npb25hbF9FeWUuRGF0YV9PcmlnaW5hbF9MZWZ0LkV5ZV9QdXBpbC5BcmVhLCBEaWthYmxpcy5Qcm9mZXNzaW9uYWxfRXllLkRhdGFfT3JpZ2luYWxfTGVmdC5FeWVfUHVwaWwuSGVpZ2h0LCBEaWthYmxpcy5Qcm9mZXNzaW9uYWxfRXllLkRhdGFfT3JpZ2luYWxfTGVmdC5FeWVfUHVwaWwuV2lkdGgsIERpa2FibGlzLlByb2Zlc3Npb25hbF9FeWUuRGF0YV9PcmlnaW5hbF9SaWdodC5FeWVfUHVwaWwuQXJlYSwgRGlrYWJsaXMuUHJvZmVzc2lvbmFsX0V5ZS5EYXRhX09yaWdpbmFsX1JpZ2h0LkV5ZV9QdXBpbC5IZWlnaHQsIERpa2FibGlzLlByb2Zlc3Npb25hbF9FeWUuRGF0YV9PcmlnaW5hbF9SaWdodC5FeWVfUHVwaWwuV2lkdGgpIAoKcHVwIDwtIHRpYmJsZShwdXApCgpjb2xuYW1lcyhwdXApIDwtIGMoInRpbWUiLCAiVVRDIiwgIkxhIiwgIkxoIiwgIkx3IiwgIlJhIiwgIlJoIiwgIlJ3IikKCnB1cCRVVEMgPC0gYW55dGltZShwdXAkVVRDLzEwMDApCgpwdXAgPC0gc2VwYXJhdGUocHVwLCB0aW1lLCBjKCJoIiwgIm0iLCAicyIpLCBzZXAgPSAiOiIsIGNvbnZlcnQgPSBUUlVFKQpwdXAkdGltZSA8LSBwdXAkcyArIHB1cCRtKjYwICsgcHVwJGgqNjAqNjAKCmNvcmZfTCA8LSBjb3JmJEtvcnJfTGlua3NbY29yZiRDb2RlID09IENvZGVdCmNvcmZfUiA8LSBjb3JmJEtvcnJfUmVjaHRzW2NvcmYkQ29kZSA9PSBDb2RlXQoKcHVwJExkIDwtIDIqc3FydChwdXAkTGEvcGkpL2NvcmZfTAoKcHVwJFJkIDwtIDIqc3FydChwdXAkUmEvcGkpL2NvcmZfUgoKI0F1ZnRlaWxlbiBpbiBQdXBpbGxlIHJlY2h0ZXMgdW5kIGxpbmtlcyBBdWdlCgpwdXBSIDwtIHNlbGVjdChwdXAsICJ0aW1lIiwgIlVUQyIsICJSZCIsICJSYSIsICJSaCIsICJSdyIpCnB1cFIgPC0gZHBseXI6OmZpbHRlcihwdXBSLCAhaXMubmEoUmEpKQpjb2xuYW1lcyhwdXBSKSA8LSBjKCJ0aW1lIiwgIlVUQyIsICJkaWEiLCAiYXJlYSIsICJoZWlnaHQiLCAid2lkdGgiKQoKcHVwTCA8LSBzZWxlY3QocHVwLCAidGltZSIsICJVVEMiLCAiTGQiLCAiTGEiLCAiTGgiLCAiTHciKQpwdXBMIDwtIGRwbHlyOjpmaWx0ZXIocHVwTCwgIWlzLm5hKExhKSkKY29sbmFtZXMocHVwTCkgPC0gYygidGltZSIsICJVVEMiLCAiZGlhIiwgImFyZWEiLCAiaGVpZ2h0IiwgIndpZHRoIikKCiNEYXJzdGVsbHVuZyBkZXIgRXJnZWJuaXNzZSBpbSBQbG90CiMgUm9oZGF0ZW4KUm9oX3Bsb3QgPC0gZ2dwbG90KCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHB1cEwsIGFlcyh4ID0gdGltZSwgeSA9IGRpYSwgY29sID0gIkxlZnQiKSkgKwogIGdlb21fbGluZShkYXRhID0gcHVwUiwgYWVzKHggPSB0aW1lLCB5ID0gZGlhLCBjb2wgPSAiUmlnaHQiKSwgYWxwaGEgPSAwLjYpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm49MSwgIiwgQ29kZSwgIiwgRG93biIsIHNlcD0iIiksIHggPSA1MCwgeT0gOCksIHNpemUgPSAyLjUpKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCAiRXllIikrCiAgZ2d0aXRsZSgiUHVwaWwtZGlhbWV0ZXIgZGF0YSB1bmNoYW5nZWQiKSsKICB5bGFiKCJQdXBpbCBkaWFtZXRlciAvIG1tIikgKwogIHhsYWIoIlRpbWUgLyBzZWNvbmRzIikrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjksLjEpLGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9IndoaXRlIiwgc2l6ZSA9IDAuNSkpCgpSb2hfcGxvdApnZ3NhdmUoIlB1cGlsX1Jhdy5wZGYiLCBwYXRoID0gcGFzdGUoIi4uL2ZpZ3VyZXMvIiwgQ29kZSwgc2VwPSIiKSwgd2lkdGg9MTAsIGhlaWdodCA9IDUpCgojIFppcmt1bGFyaXTDpHQKUm9oX3Bsb3QyIDwtIGdncGxvdCgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMLCBhZXMoeCA9IHRpbWUsIHkgPSB3aWR0aC9oZWlnaHQsIGNvbCA9ICJMZWZ0IikpICsKICBnZW9tX2xpbmUoZGF0YSA9IHB1cFIsIGFlcyh4ID0gdGltZSwgeSA9IHdpZHRoL2hlaWdodCwgY29sID0gIlJpZ2h0IiksIGFscGhhID0gMC42KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsICIsIERvd24iLCAgc2VwPSIiKSwgeCA9IDUwLCB5PSAxLjAxKSwgc2l6ZSA9IDIuNSkrCiAgdGhlbWVfY293cGxvdChmb250X3NpemUgPSA4LCBmb250X2ZhbWlseSA9ICJzYW5zIikrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsICJFeWUiKSsKICBnZ3RpdGxlKCJQdXBpbC1jaXJjdWxhcml0eSIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigiVGltZSAvIHNlY29uZHMiKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKClJvaF9wbG90MgpnZ3NhdmUoIlB1cGlsX1JhdzIucGRmIiwgcGF0aCA9IHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksIHdpZHRoPTEwLCBoZWlnaHQgPSA1KQoKCmBgYAoKCkltIGtvbW1lbmRlbiBBYnNjaG5pdHQgd2VyZGVuIEFydGVmYWt0ZSB1bmQgdW5wbGF1c2libGUgTWVzc3dlcnRlIGVudGZlcm50LiBadWRlbSB3aXJkIGRpZSBLdXJ2ZSBnZWdsw6R0dGV0LgpgYGB7ciBEYXRlbiBhdWZiZXJlaXRlbn0KI0VudGZlcm51bmcgdm9uIEF1c3JlaXNzZXJuIHVuZCBXZXJ0ZW4gYmVpIGRlbmVuIGRpZSBQdXBpbGxlIGVpbmUgemlya3VsYXJpdMOkdCA8IDAsNyBhdWZ3ZWlzdCwgenVkZW0gd2lyZCBkaWUgbGV0enRlbiAyIFNla3VuZGVuIGRlciBNZXNzdW5nIGVudGZlcm50CgpwdXBSZiA8LSBwdXBSWzE6KGxlbmd0aChwdXBSJHRpbWUpLTEyMCksXQpwdXBSZiA8LSBkcGx5cjo6ZmlsdGVyKHB1cFJmLCBkaWEgPiAxKSAjIEVudGZlcm51bmcgdm9uIFdlcnRlbiBrbGVpbmVyIFggbW0KcHVwUmYgPC0gZHBseXI6OmZpbHRlcihwdXBSZiwgZGlhIDwgOC41KSAjIEVudGZlcm51bmcgdm9uIFdlcnRlbiBncsO2w59lciA4IG1tCnB1cFJmIDwtIGRwbHlyOjpmaWx0ZXIocHVwUmYsIHdpZHRoL2hlaWdodCA+IDAuNzAgJiB3aWR0aC9oZWlnaHQgPiAwLjcwKSAjIEVudGZlcm51bmcgdm9uIFdlcnRlbiBmw7xyIGRpZSBkaWUgWmlya3VsYXJpdMOkdCBrbGVpbmVyIGFscyAwLDcgYXVzZsOkbGx0CnB1cFJmJGRpYV9zbSA8LSBzZ29sYXlmaWx0KHB1cFJmJGRpYSwgcD0zLCBuPTMxKSAjIEdsw6R0dHVuZyBkZXIgS3VydmUgbWl0dGVscyBTYXZpdHpreS1Hb2xheSBGaWx0ZXIKCnB1cExmIDwtIHB1cExbMToobGVuZ3RoKHB1cEwkdGltZSktMTIwKSxdCnB1cExmIDwtIGRwbHlyOjpmaWx0ZXIocHVwTGYsIGRpYSA+IDEpICMgRW50ZmVybnVuZyB2b24gV2VydGVuIGtsZWluZXIgWCBtbQpwdXBMZiA8LSBkcGx5cjo6ZmlsdGVyKHB1cExmLCBkaWEgPCA4LjUpICMgRW50ZmVybnVuZyB2b24gV2VydGVuIGdyw7bDn2VyIDggbW0KcHVwTGYgPC0gZHBseXI6OmZpbHRlcihwdXBMZiwgd2lkdGgvaGVpZ2h0ID4gMC43MCAmIHdpZHRoL2hlaWdodCA+IDAuNzApICMgRW50ZmVybnVuZyB2b24gV2VydGVuIGbDvHIgZGllIGRpZSBaaXJrdWxhcml0w6R0IGtsZWluZXIgYWxzIDAsNyBhdXNmw6RsbHQKcHVwTGYkZGlhX3NtIDwtIHNnb2xheWZpbHQocHVwTGYkZGlhLCBwPTMsIG49MzEpICMgR2zDpHR0dW5nIGRlciBLdXJ2ZSBtaXR0ZWxzIFNhdml0emt5LUdvbGF5IEZpbHRlcgoKU21vb3RoX3Bsb3RfdGVzdCA8LSBnZ3Bsb3QoKSArIAogIGdlb21fbGluZShkYXRhID0gcHVwTGYsIGFlcyh4ID0gdGltZSwgeSA9IGRpYSwgY29sID0gInVuc21vb3RoZWQiKSkgKwogIGdlb21fbGluZShkYXRhID0gcHVwTGYsIGFlcyh4ID0gdGltZSwgeSA9IGRpYV9zbSwgY29sID0gInNnIG49MzEiKSwgYWxwaGEgPSAwLjYpICsKICAgIGdlb21fbGluZShkYXRhID0gcHVwTGYsIGFlcyh4ID0gdGltZSwgeSA9IHNnb2xheWZpbHQoZGlhLCBwPTMsIG49NjEpLCBjb2wgPSAic2cgbj02MSIpLCBhbHBoYSA9IDAuNikgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSB0aW1lLCB5ID0gc2dvbGF5ZmlsdChkaWEsIHA9Mywgbj05MSksIGNvbCA9ICJzZyBuPTkxIiksIGFscGhhID0gMC42KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsICAiLCBEb3duIiwgc2VwPSIiKSwgeCA9IDUwLCB5PSA4KSwgc2l6ZSA9IDIuNSkrCiAgdGhlbWVfY293cGxvdChmb250X3NpemUgPSA4LCBmb250X2ZhbWlseSA9ICJzYW5zIikrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsICJFeWUiKSsKICBnZ3RpdGxlKCJQdXBpbC1kaWFtZXRlciBkYXRhIHNtb290aGVkLCB0ZXN0IHNldHRpbmdzIikrCiAgeWxhYigiUHVwaWwgZGlhbWV0ZXIgLyBtbSIpICsKICB4bGFiKCJUaW1lIC8gc2Vjb25kcyIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45LC4xKSxsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIsIHNpemUgPSAwLjUpKSsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMjUwLCAyNzUpLCB5bGltID0gYygyLDgpKQoKU21vb3RoX3Bsb3RfdGVzdApnZ3NhdmUoIlB1cGlsX1Ntb290aF90ZXN0LnBkZiIsIHBhdGggPSBwYXN0ZSgiLi4vZmlndXJlcy8iLCBDb2RlLCBzZXA9IiIpLCB3aWR0aD0xMCwgaGVpZ2h0ID0gNSkKClNtb290aF9wbG90IDwtIGdncGxvdCgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSB0aW1lLCB5ID0gZGlhX3NtLCBjb2wgPSAiTGVmdCIpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBSZiwgYWVzKHggPSB0aW1lLCB5ID0gZGlhX3NtLCBjb2wgPSAiUmlnaHQiKSwgYWxwaGEgPSAwLjYpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm49MSwgIiwgQ29kZSwgICIsIERvd24iLCBzZXA9IiIpLCB4ID0gNTAsIHk9IDgpLCBzaXplID0gMi41KSsKICB0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZSA9IDgsIGZvbnRfZmFtaWx5ID0gInNhbnMiKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgIkV5ZSIpKwogIGdndGl0bGUoIlB1cGlsLWRpYW1ldGVyIGRhdGEgc21vb3RoZWQiKSsKICB5bGFiKCJQdXBpbCBkaWFtZXRlciAvIG1tIikgKwogIHhsYWIoIlRpbWUgLyBzZWNvbmRzIikrIAogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygyLDgpKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKClNtb290aF9wbG90Cmdnc2F2ZSgiUHVwaWxfU21vb3RoLnBkZiIsIHBhdGggPSAgcGFzdGUoIi4uL2ZpZ3VyZXMvIiwgQ29kZSwgc2VwPSIiKSwgd2lkdGg9MTAsIGhlaWdodCA9IDUpCgoKYGBgCgoKSW0gbsOkY2hzdGVuIEFic2Nobml0dCBlcmZvbGd0IGRpZSBadW9yZG51bmcgZWluemVsbmVyIFplaXRhYnNjaG5pdHRlIHp1IGRlbiBXZWxsZW5sw6RuZ2VuLgpgYGB7ciBXZWxsZW5sw6RuZ2VuIHp1b3JkbmVufQoKI0JpbGR1bmcgZGVyIDEuIHVuZCAyLiBBYmxlaXR1bmcuIExpbmVhcmUgVHJhbnNmb3JtYXRpb24sIGRhbWl0IGRpZSDDnGJlcmxhZ2VydW5nIG1pdCBkZW0gUHVwaWxsZW5kdXJjaG1lc3NlciBsZXNiYXIgYmxlaWJ0LgoKcHVwTGYkZGlhX3NtMSA8LSAoc2dvbGF5ZmlsdChwdXBMZiRkaWEsIHA9Mywgbj0zMSwgbT0xKSkqMTAwKzYKcHVwTGYkZGlhX3NtMiA8LSAoc2dvbGF5ZmlsdChwdXBMZiRkaWEsIHA9Mywgbj0zMSwgbT0yKSkqMTAwKzYKCgojRXJrZW5udW5nIGRlciBUaWVmcHVua3RlIGRlciAyLiBBYmxlaXR1bmcKdmx5IDwtIGdncGxvdChkYXRhID0gcHVwTGYsIGFlcyh4PXRpbWUsIHk9ZGlhX3NtMikpICsgCiAgc3RhdF92YWxsZXlzKHNwYW4gPSA2MDEsIGNvbCA9ICJncmVlbiIpCnZseV9kYXRhIDwtIChsYXllcl9kYXRhKHZseSwgaT0xTCkkeGludGVyY2VwdCkKCiNEYXJzdGVsbHVuZyBkZXIgVGllZnB1bmt0ZSBkZXIgMi4gQWJsZWl0dW5nCkRlcml2YXRpdmVfdGVzdCA8LSBnZ3Bsb3QoZGF0YSA9IHB1cExmLCBhZXMoeD10aW1lLCB5PWRpYV9zbTIsIGNvbD0idmFsbGV5IikpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSB0aW1lLCB5ID0gZGlhX3NtLCBjb2wgPSAiRGlhbWV0ZXIiKSkgKwogIGdlb21fbGluZShkYXRhID0gcHVwUmYsIGFlcyh4ID0gdGltZSwgeSA9IGRpYV9zbSwgY29sID0gIkRpYW1ldGVyIikpICsKICAgIGdlb21fbGluZShhZXMoY29sID0gIjJuZCBkZXJpdmF0aXZlIiksIGFscGhhID0gMC42KSArCiAgc3RhdF92YWxsZXlzKHNwYW4gPSA2MDEsIGNvbCA9ICJncmVlbiIpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHZseV9kYXRhLTAuMSwgbHdkID0gMC4xLCBjb2w9ImdyZWVuIikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsICAiLCBEb3duIiwgc2VwPSIiKSwgeCA9IDUwLCB5PSA4KSwgc2l6ZSA9IDIuNSkrCiAgdGhlbWVfY293cGxvdChmb250X3NpemUgPSA4LCBmb250X2ZhbWlseSA9ICJzYW5zIikrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsICJUeXBlIikrCiAgZ2d0aXRsZSgiUHVwaWwtZGlhbWV0ZXIgZGF0YSBzbW9vdGhlZCB3aXRoIDJuZCBkZXJpdmF0aXZlIGFuZCB2YWxsZXlzICgtMTAwbXMpIikrCiAgeWxhYigiUHVwaWwgZGlhbWV0ZXIgLyBtbSIpICsKICB4bGFiKCJUaW1lIC8gc2Vjb25kcyIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45LC4xKSxsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIsIHNpemUgPSAwLjUpKSsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoODAsIDIwMCkpCgpEZXJpdmF0aXZlX3Rlc3QKZ2dzYXZlKCJQdXBpbF9EZXJpdmF0aXZlX3Rlc3QucGRmIiwgcGF0aCA9IHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksIHdpZHRoPTE1LCBoZWlnaHQgPSA1KQoKI1dhaGwgZWluZSBQcm9ncmFtbXN0YXJ0cHVua3RzCgp2bHlfZGF0YSA8LSB0aWJibGUoImluZGV4IiA9IDE6IGxlbmd0aCh2bHlfZGF0YSksICJ0aW1lIiA9IHZseV9kYXRhLTAuMSwgImRpZiIgPSBjKHZseV9kYXRhWzFdLCBkaWZmKHZseV9kYXRhKSkpCmthYmxlKHZseV9kYXRhWzE6MjAsXSwgInBhbmRvYyIsIGNhcHRpb24gPSAiVGltZSBvZiAybmQgZGVyaXZhdGl2ZSB2YWxsZXlzICgtMTAwbXMpLCBmaXJzdCAyMCByb3dzIiwgYWxpZ24gPSAiYyIpIyBUaWVmcHVua3RlIG1pdCBaZWl0c3RlbXBlbAoKYGBgCgoKYGBge3IgV2VsbGVubMOkbmdlbiB6dW9yZG5lbjJ9CgpzZXF1X3BlciA8LSAxNS4xNDUgI1NlcXVlbnogUGVyaW9kZSAtPiBFcm1pdHRsdW5nIGF1cyBWaWRlbyBtaXQgR2Vyw6R1c2NoYW5hbHlzZQoKI1dlbGNoZXIgaW5kZXggaXN0IGRlciBTdGFydHplaXRwdW5rdD8KaSA8LSA4ICMgSGllciBtdXNzIG1hbiBhdWYgQmFzaXMgZGVyIEdyYWZpayB1bmQgZGVyIFRhYmVsbGUgZGVuIFN0YXJ0emVpdHB1bmt0IGFuZ2ViZW4KCiNaZWl0a29ycmVrdHVyIG5vdHdlbmRpZz8KY29yIDwtIDAKCnB1cExmJHRpbWVfYyA8LSBwdXBMZiR0aW1lIC0gdmx5X2RhdGEkdGltZVt2bHlfZGF0YSRpbmRleCA9PSBpXSArIHNlcXVfcGVyKmNvcgpwdXBSZiR0aW1lX2MgPC0gcHVwUmYkdGltZSAtIHZseV9kYXRhJHRpbWVbdmx5X2RhdGEkaW5kZXggPT0gaV0gKyBzZXF1X3Blcipjb3IKCgojRXJnw6RuenVuZyBkZXIgV2VsbGVubMOkbmdlbiAKCndsX3NlYyA8LSB0aWJibGUoCiAgIndsIiA9IHJldihwcm9nJFBlYWtfNSksIAogICJ3bF9iIiA9IHNlcShmcm9tID0gMCwgdG8gPSAobGVuZ3RoKHByb2ckUGVha181KS0xKSpzZXF1X3BlciwgYnkgPSBzZXF1X3BlciksCiAgIndsX2UiID0gc2VxKGZyb20gPSBzZXF1X3BlciwgdG8gPSBsZW5ndGgocHJvZyRQZWFrXzUpKnNlcXVfcGVyLCBieSA9IHNlcXVfcGVyKQogICkKCnRvdF9wZXIgPC0gbGVuZ3RoKHByb2ckUGVha181KSpzZXF1X3BlcgoKc2VxdSA8LSBzZXEoZnJvbT0wLCB0byA9IHRvdF9wZXIsIGJ5ID0gc2VxdV9wZXIpCndsIDwtIHJldihwcm9nJFBlYWtfNSkKcHJvZyRpbmRleCA8LSBsZW5ndGgocHJvZyRQZWFrXzUpOjEKCnB1cExmJHdsX3N0ZXAgPC0gYXMubnVtZXJpYyhjdXQocHVwTGYkdGltZV9jLAogICAgICAgICAgICAgICBicmVha3MgPSBzZXF1LAogICAgICAgICAgICAgICBpbmNsdWRlLmxvd2VzdCA9IFQsCiAgICAgICAgICAgICAgIHJpZ2h0ID0gRiwKICAgICAgICAgICAgICAgbGFiZWxzID0gd2wpKQoKcHVwTGYkd2xfdGltZSA8LSAgcHVwTGYkdGltZV9jIC0gKHB1cExmJHdsX3N0ZXAtMSkqc2VxdV9wZXIKCnB1cExmJHdsX3N0ZXAgPC0gd2xbcHVwTGYkd2xfc3RlcF0KCgpwdXBSZiR3bF9zdGVwIDwtIGFzLm51bWVyaWMoY3V0KHB1cFJmJHRpbWVfYywKICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxdSwKICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBULAogICAgICAgICAgICAgICByaWdodCA9IEYsCiAgICAgICAgICAgICAgIGxhYmVscyA9IHdsKSkKCnB1cFJmJHdsX3RpbWUgPC0gIHB1cFJmJHRpbWVfYyAtIChwdXBSZiR3bF9zdGVwIC0gMSkqc2VxdV9wZXIKCnB1cFJmJHdsX3N0ZXAgPC0gd2xbcHVwUmYkd2xfc3RlcF0KCiNEYXJzdGVsbHVuZyBkZXIgRGF0ZW4gbWl0IG5ldWVtIFN0YXJ0IHVuZCBkZW4gamV3ZWlsaWdlbiBXZWxsZW5sw6RuZ2VuCgpUaW1lZF9wbG90IDwtIGdncGxvdCgpICsgCiAgZ2VvbV9yZWN0KGRhdGEgPSB3bF9zZWMsIGFlcyh4bWluPSB3bF9iLCB4bWF4ID0gd2xfZSwgeW1pbiA9IDIsIHltYXggPSA4LCBmaWxsID0gd2wpKSsKICBnZW9tX2xpbmUoZGF0YSA9IHB1cExmLCBhZXMoeCA9IHRpbWVfYywgeSA9IGRpYV9zbSwgY29sID0gIkxlZnQiKSkgKwogIGdlb21fbGluZShkYXRhID0gcHVwUmYsIGFlcyh4ID0gdGltZV9jLCB5ID0gZGlhX3NtLCBjb2wgPSAiUmlnaHQiKSwgYWxwaGEgPSAwLjYpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm49MSwgIiwgQ29kZSwgICIsIERvd24iLCBzZXA9IiIpLCB4ID0gNTAsIHk9IDcuNSksIHNpemUgPSAyLjUpKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5ODAiLCAiYmxhY2siKSkrCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzID0gYyhyZXYocmFpbmJvdyg1Mywgc3RhcnQgPSAwLCBlbmQgPSAwLjgwKSksIHJldihyYWluYm93KDgsIHN0YXJ0ID0gMC45NCwgZW5kID0gMSkpKSkrCiAgZ2d0aXRsZSgiUHVwaWwtZGlhbWV0ZXIgZHVyaW5nIGRpZmZlcmVudCB3YXZlbGVuZ3RoIikrCiAgeWxhYigiUHVwaWwgZGlhbWV0ZXIgLyBtbSIpICsKICB4bGFiKCJUaW1lIC8gc2Vjb25kcyIpKyAKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMiw4KSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjg1LC4yMiksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKClRpbWVkX3Bsb3QKZ2dzYXZlKCJUaW1lZF9TbW9vdGgucGRmIiwgcGF0aCA9ICBwYXN0ZSgiLi4vZmlndXJlcy8iLCBDb2RlLCBzZXA9IiIpLGxpbWl0c2l6ZT1GLCB3aWR0aD0yMCwgaGVpZ2h0ID0gNSkKCiBXTF9wbG90IDwtIGdncGxvdCgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSBhcy5mYWN0b3Iod2xfc3RlcCksIHkgPSBkaWFfc20sIGNvbCA9ICJMZWZ0IikpICsKICBnZW9tX2xpbmUoZGF0YSA9IHB1cFJmLCBhZXMoeCA9IGFzLmZhY3Rvcih3bF9zdGVwKSwgeSA9IGRpYV9zbSwgY29sID0gIlJpZ2h0IiksIGFscGhhID0gMC42KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsICAiLCBEb3duIiwgc2VwPSIiKSwgeCA9IDUwLCB5PSA4KSwgc2l6ZSA9IDIuNSkrCiAgdGhlbWVfY293cGxvdChmb250X3NpemUgPSA4LCBmb250X2ZhbWlseSA9ICJzYW5zIikrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsICJFeWUiKSsKICBnZ3RpdGxlKCJQdXBpbC1kaWFtZXRlciBwZXIgd2F2ZWxlbmd0aCIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigid2F2ZWxlbmd0aCAvIG5tIikrIAogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygyLDgpKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKCldMX3Bsb3QKZ2dzYXZlKCJXYXZlbGVuZ3RoX1Bsb3QucGRmIiwgcGF0aCA9ICBwYXN0ZSgiLi4vZmlndXJlcy8iLCBDb2RlLCBzZXA9IiIpLGxpbWl0c2l6ZT1GLCB3aWR0aD0xMCwgaGVpZ2h0ID0gNSkKCldMX3Bsb3QyIDwtIGdncGxvdCgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSB3bF90aW1lLCB5ID0gZGlhX3NtLCBncm91cCA9IHdsX3N0ZXAsIGNvbCA9IHdsX3N0ZXApKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCJuPTEsICIsIENvZGUsICAiLCBEb3duIiwgc2VwPSIiKSwgeCA9IDAuNSwgeT0gOCksIHNpemUgPSAyLjUpKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBjKHJldihyYWluYm93KDUzLCBzdGFydCA9IDAsIGVuZCA9IDAuODApKSwgcmV2KHJhaW5ib3coOCwgc3RhcnQgPSAwLjk0LCBlbmQgPSAxKSkpKSsKICBnZ3RpdGxlKCJQdXBpbC1kaWFtZXRlciBkZXBlbmRpbmcgb24gd2F2ZWxlbmd0aCIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigiVGltZSAvIHNlY29uZHMiKSsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDIsOCkpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45LC4xKSxsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIsIHNpemUgPSAwLjUpKQoKV0xfcGxvdDIKZ2dzYXZlKCJXYXZlbGVuZ3RoX1Bsb3QyLnBkZiIsIHBhdGggPSAgcGFzdGUoIi4uL2ZpZ3VyZXMvIiwgQ29kZSwgc2VwPSIiKSxsaW1pdHNpemU9Riwgd2lkdGg9MTAsIGhlaWdodCA9IDcuNSkKCldMX3Bsb3QybG9nIDwtIGdncGxvdCgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBwdXBMZiwgYWVzKHggPSBsb2cxMCh3bF90aW1lKSwgeSA9IGRpYV9zbSwgZ3JvdXAgPSB3bF9zdGVwLCBjb2wgPSB3bF9zdGVwKSkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgibj0xLCAiLCBDb2RlLCAgIiwgRG93biIsIHNlcD0iIiksIHggPSAtMSwgeT0gOCksIHNpemUgPSAyLjUpKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBjKHJldihyYWluYm93KDUzLCBzdGFydCA9IDAsIGVuZCA9IDAuODApKSwgcmV2KHJhaW5ib3coOCwgc3RhcnQgPSAwLjk0LCBlbmQgPSAxKSkpKSsKICBnZ3RpdGxlKCJQdXBpbC1kaWFtZXRlciBkZXBlbmRpbmcgb24gd2F2ZWxlbmd0aCIpKwogIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgeGxhYigiVGltZSAvIGxvZzEwKHNlY29uZHMpIikrIAogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygyLDgpLCB4bGltID0gYygtMS41LCBsb2cxMCgxNSkpKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMSksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKCldMX3Bsb3QybG9nCmdnc2F2ZSgiV2F2ZWxlbmd0aF9QbG90MmxvZy5wZGYiLCBwYXRoID0gIHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksbGltaXRzaXplPUYsIHdpZHRoPTEwLCBoZWlnaHQgPSA3LjUpCgpgYGAKCgpJbSBmb2xnZW5kZW4gQWJzY2huaXR0IHdlcmRlbiBNaXR0ZWx3ZXJ0ZSBmw7xyIGplZGUgU2VrdW5kZSBkZXMgTGljaHRyZWl6ZXMgZ2ViaWxkZXQuIERpZXNlIHdlcmRlbiBub3JtaWVydCwgYmV6b2dlbiBhdWYgZGllIERpZmZlcmVueiB6d2lzY2hlbiBkZXIgbWF4aW1hbGVuIHVuZCBtaW5pbWFsZW4gUHVwaWxsZW53ZWl0ZS4KYGBge3IgTWl0dGVsd2VydHNiaWxkdW5nfQojIFp1bsOkY2hzdCB3aXJkIGRpZSAtQmFzZWxpbmUtR3LDtsOfZSBiZXN0aW1tdC4gU2llIHdpcmQgaGllciBkZWZpbmllcnQgYWxzIGRlciBNaXR0ZWx3ZXJ0IGRlciBQdXBpbGxlIGluIGRlbiBsZXR6dGVuIDUgU2VrdW5kZW4gZGVyIER1bmtlbGFkYXB0YXRpb24KIyBJbiBGw6RsbGVuLCBpbiBkZW5lbiBkaWUgUHVwaWxsZSB3w6RocmVuZCBkZXIgQmVsaWNodHVuZyBuaWVkcmlnZXJlIFdlcnRlIGFubmltbXQsIGthbm4gYXVjaCBkaWUgZ3LDtsOfdGUgUHVwaWxsZW5ncsO2w59lIHfDpGhyZW5kIGRlciBCZWxpY2h0dW5nIGdld8OkaGx0IHdlcmRlbi4gRGllcyBlcmZvbGd0IGF1dG9tYXRpc2NoIGFuaGFuZCBkZXMgZ3LDtsOfZXJlbiBXZXJ0cwoKTF9ub3JtIDwtIGFzLm51bWVyaWMoCiAgICAgICAgICAgICAgICAgIGlmZWxzZShwdXBMZiAlPiUgZHBseXI6OmZpbHRlcih0aW1lX2MgPCAwICYgdGltZV9jID4gLTUpICAlPiUgc3VtbWFyaXplKHBfbWF4ID0gbWVhbihkaWFfc20pKSA+IAogICAgICAgICAgICAgICAgICAgcHVwTGYgJT4lIGRwbHlyOjpmaWx0ZXIodGltZV9jID4gMCAmIHRpbWVfYyA8IHRvdF9wZXIpICAlPiUgc3VtbWFyaXplKHBfbWF4ID0gbWF4KGRpYV9zbSkpLCAKICAgICAgICAgICAgICAgICBwdXBMZiAlPiUgZHBseXI6OmZpbHRlcih0aW1lX2MgPCAwICYgdGltZV9jID4gLTUpICAlPiUgc3VtbWFyaXplKHBfbWF4ID0gbWVhbihkaWFfc20pKSwgCiAgICAgICAgICAgICAgICAgcHVwTGYgJT4lIGRwbHlyOjpmaWx0ZXIodGltZV9jID4gMCAmIHRpbWVfYyA8IHRvdF9wZXIpICAlPiUgc3VtbWFyaXplKHBfbWF4ID0gbWF4KGRpYV9zbSkpCiAgICAgICAgICAgICAgICAgKSkKCiMgSW0gbsOkY2hzdGVuIFNjaHJpdHQgd2VyZGVuIGRpZSBTZWt1bmRlbm1pdHRlbHdlcnRlIGbDvHIgamVkZSBXZWxsZW5sw6RuZ2UgZ2ViaWxkZXQsIHp1ZGVtIGRlciBNaXR0ZWx3ZXJ0IGRlciBsZXR6dGVuIDUgU2VrdW5kZW4gdW5kIGRpZSBtaW5pbWFsZW4gUHVwaWxsZW5ncsO2w59lbiBmw7xyIGRpZSBqZXdlaWxpZ2VuIFplaXRpbnRlcnZhbGxlCgpMX3ZhbCA8LSBwdXBMZiAlPiUgZ3JvdXBfYnkod2xfc3RlcCwgd2xfdGltZSAlLyUgMSkgJT4lIHN1bW1hcml6ZShkX2FicyA9IG1lYW4oZGlhX3NtKSkKTF92YWwxMCA8LSBwdXBMZiAlPiUgZHBseXI6OmZpbHRlcih3bF90aW1lIDw9IDE1ICYgd2xfdGltZSA+PSAxMCkgICU+JSBncm91cF9ieSh3bF9zdGVwKSAlPiUgc3VtbWFyaXplKGRfYWJzID0gbWVhbihkaWFfc20pKQoKbmFtZXMoTF92YWwpIDwtIGMoIndsIiwgInRpbWUiLCAiZF9hYnMiKQpuYW1lcyhMX3ZhbDEwKSA8LSBjKCJ3bCIsICJkX2FicyIpCgp0ZW1wIDwtIExfdmFsICU+JSBkcGx5cjo6ZmlsdGVyKHdsICE9ICJOQSIpICU+JSBncm91cF9ieSh0aW1lKSAlPiUgc3VtbWFyaXplKG1pbiA9IG1pbihkX2FicykpCgpMX25vcm0gPC0gZGF0YV9mcmFtZSgiQ29uZCIgPSBjKCJEYXJrIiwgdGVtcCR0aW1lLCAiMTBfMTUiKSwgImRpYSIgPSBjKExfbm9ybSwgdGVtcCRtaW4sIG1pbihMX3ZhbDEwJGRfYWJzKSkpCgoKIyBIaWVyIHdpcmQgenVuw6RjaHN0IGVpbmUgdGVtcG9yw6RyZSBWYXJpYWJsZSBlcnpldWd0LCB3ZWxjaGUgZsO8ciBqZWRlIFplaWxlIGluIGRlbiBTZWt1bmRlbm1pdHRlbHdlcnRkYXRlbiBkaWUga29ycmVzcG9uZGllcmVuZGUgbWluaW1hbGUgUHVwaWxsZW5ncsO2w59lIGFuZ2lidC4KCnRlbXAgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoKGN1dChMX3ZhbCR0aW1lLAogICAgICAgICAgICAgICBicmVha3MgPSAwOihzZXF1X3BlciAlLyUgMSArMSksCiAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVCwKICAgICAgICAgICAgICAgcmlnaHQgPSBGLAogICAgICAgICAgICAgICBsYWJlbHMgPSBMX25vcm0kZGlhWzI6KGxlbmd0aChMX25vcm0kZGlhKS0xKV0pKQopKSAKCgojIEltIGZvbGdlbmRlbiBTY2hyaXR0IHdlcmRlbiByZWxhdGl2ZSBQdXBpbGxlbmtvbnN0cmlrdGlvbnN3ZXJ0ZSBnZWJpbGRldCwgYW1wIGlzdCBkYWJlaSBkaWUgS29uc3RyaWt0aW9uc2FtcGxpdHVkZSBiZXpvZ2VuIGF1ZiBkaWUgQmFzZWxpbmUtR3LDtsOfZSwgYW1wMiBhdWYgZGllIFNwYW5uZSB6d2lzY2hlbiBkZXIgQmFzbGluZS1HcsO2w59lIHVuZCBkZXIga2xlaW5zdGVuLCBmw7xyIGRpZXNlIFplaXRzcGFubmUgZ2VtZXNzZW5lbiBQdXBpbGxlbmdyw7bDn2UuCgpMX3ZhbCRhbXAgPC0gKExfbm9ybSRkaWFbTF9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIExfdmFsJGRfYWJzKS9MX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0qMTAwCkxfdmFsMTAkYW1wIDwtIChMX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0gLSBMX3ZhbDEwJGRfYWJzKS9MX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0qMTAwCgpMX3ZhbCRhbXAyIDwtIChMX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0gLSBMX3ZhbCRkX2FicykvKExfbm9ybSRkaWFbTF9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIHRlbXApKjEwMApMX3ZhbDEwJGFtcDIgPC0gKExfbm9ybSRkaWFbTF9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIExfdmFsMTAkZF9hYnMpLyhMX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICJEYXJrIl0gLSBMX25vcm0kZGlhW0xfbm9ybSRDb25kID09ICIxMF8xNSJdKSoxMDAKCiMjTnVuIGF1Y2ggZsO8ciBkYXMgcmVjaHRlIEF1Z2UKIyBadW7DpGNoc3Qgd2lyZCBkaWUgLUJhc2VsaW5lLUdyw7bDn2UgYmVzdGltbXQuIFNpZSB3aXJkIGhpZXIgZGVmaW5pZXJ0IGFscyBkZXIgTWl0dGVsd2VydCBkZXIgUHVwaWxsZSBpbiBkZW4gbGV0enRlbiA1IFNla3VuZGVuIGRlciBEdW5rZWxhZGFwdGF0aW9uCiMgSW4gRsOkbGxlbiwgaW4gZGVuZW4gZGllIFB1cGlsbGUgd8OkaHJlbmQgZGVyIEJlbGljaHR1bmcgbmllZHJpZ2VyZSBXZXJ0ZSBhbm5pbW10LCBrYW5uIGF1Y2ggZGllIGdyw7bDn3RlIFB1cGlsbGVuZ3LDtsOfZSB3w6RocmVuZCBkZXIgQmVsaWNodHVuZyBnZXfDpGhsdCB3ZXJkZW4uIERpZXMgZXJmb2xndCBhdXRvbWF0aXNjaCBhbmhhbmQgZGVzIGdyw7bDn2VyZW4gV2VydHMKClJfbm9ybSA8LSBhcy5udW1lcmljKAogICAgICAgICAgICAgICAgICBpZmVsc2UocHVwUmYgJT4lIGRwbHlyOjpmaWx0ZXIodGltZV9jIDwgMCAmIHRpbWVfYyA+IC01KSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1lYW4oZGlhX3NtKSkgPiAKICAgICAgICAgICAgICAgICAgIHB1cFJmICU+JSBkcGx5cjo6ZmlsdGVyKHRpbWVfYyA+IDAgJiB0aW1lX2MgPCB0b3RfcGVyKSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1heChkaWFfc20pKSwgCiAgICAgICAgICAgICAgICAgcHVwUmYgJT4lIGRwbHlyOjpmaWx0ZXIodGltZV9jIDwgMCAmIHRpbWVfYyA+IC01KSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1lYW4oZGlhX3NtKSksIAogICAgICAgICAgICAgICAgIHB1cFJmICU+JSBkcGx5cjo6ZmlsdGVyKHRpbWVfYyA+IDAgJiB0aW1lX2MgPCB0b3RfcGVyKSAgJT4lIHN1bW1hcml6ZShwX21heCA9IG1heChkaWFfc20pKQogICAgICAgICAgICAgICAgICkpCgojIEltIG7DpGNoc3RlbiBTY2hyaXR0IHdlcmRlbiBkaWUgU2VrdW5kZW5taXR0ZWx3ZXJ0ZSBmw7xyIGplZGUgV2VsbGVubMOkbmdlIGdlYmlsZGV0LCB6dWRlbSBkZXIgTWl0dGVsd2VydCBkZXIgbGV0enRlbiA1IFNla3VuZGVuIHVuZCBkaWUgbWluaW1hbGVuIFB1cGlsbGVuZ3LDtsOfZW4gZsO8ciBkaWUgamV3ZWlsaWdlbiBaZWl0aW50ZXJ2YWxsZQoKUl92YWwgPC0gcHVwUmYgJT4lIGdyb3VwX2J5KHdsX3N0ZXAsIHdsX3RpbWUgJS8lIDEpICU+JSBzdW1tYXJpemUoZF9hYnMgPSBtZWFuKGRpYV9zbSkpClJfdmFsMTAgPC0gcHVwUmYgJT4lIGRwbHlyOjpmaWx0ZXIod2xfdGltZSA8PSAxNSAmIHdsX3RpbWUgPj0gMTApICAlPiUgZ3JvdXBfYnkod2xfc3RlcCkgJT4lIHN1bW1hcml6ZShkX2FicyA9IG1lYW4oZGlhX3NtKSkKCm5hbWVzKFJfdmFsKSA8LSBjKCJ3bCIsICJ0aW1lIiwgImRfYWJzIikKbmFtZXMoUl92YWwxMCkgPC0gYygid2wiLCAiZF9hYnMiKQoKdGVtcCA8LSBSX3ZhbCAlPiUgZHBseXI6OmZpbHRlcih3bCAhPSAiTkEiKSAlPiUgZ3JvdXBfYnkodGltZSkgJT4lIHN1bW1hcml6ZShtaW4gPSBtaW4oZF9hYnMpKQoKUl9ub3JtIDwtIGRhdGFfZnJhbWUoIkNvbmQiID0gYygiRGFyayIsIHRlbXAkdGltZSwgIjEwXzE1IiksICJkaWEiID0gYyhSX25vcm0sIHRlbXAkbWluLCBtaW4oUl92YWwxMCRkX2FicykpKQoKCgojIEltIGZvbGdlbmRlbiBTY2hyaXR0IHdlcmRlbiByZWxhdGl2ZSBQdXBpbGxlbmtvbnN0cmlrdGlvbnN3ZXJ0ZSBnZWJpbGRldCwgYW1wIGlzdCBkYWJlaSBkaWUgS29uc3RyaWt0aW9uc2FtcGxpdHVkZSBiZXpvZ2VuIGF1ZiBkaWUgQmFzZWxpbmUtR3LDtsOfZSwgYW1wMiBhdWYgZGllIFNwYW5uZSB6d2lzY2hlbiBkZXIgQmFzbGluZS1HcsO2w59lIHVuZCBkZXIga2xlaW5zdGVuLCBmw7xyIGRpZXNlIFplaXRzcGFubmUgZ2VtZXNzZW5lbiBQdXBpbGxlbmdyw7bDn2UuCgp0ZW1wIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKChjdXQoUl92YWwkdGltZSwKICAgICAgICAgICAgICAgYnJlYWtzID0gMDooc2VxdV9wZXIgJS8lIDEgKzEpLAogICAgICAgICAgICAgICBpbmNsdWRlLmxvd2VzdCA9IFQsCiAgICAgICAgICAgICAgIHJpZ2h0ID0gRiwKICAgICAgICAgICAgICAgbGFiZWxzID0gUl9ub3JtJGRpYVsyOihsZW5ndGgoUl9ub3JtJGRpYSktMSldKSkKKSkgIyBIaWVyIHdpcmQgenVuw6RjaHN0IGVpbmUgdGVtcG9yw6RyZSBWYXJpYWJsZSBlcnpldWd0LCB3ZWxjaGUgZsO8ciBqZWRlIFplaWxlIGluIGRlbiBTZWt1bmRlbm1pdHRlbHdlcnRkYXRlbiBkaWUga29ycmVzcG9uZGllcmVuZGUgbWluaW1hbGUgUHVwaWxsZW5ncsO2w59lIGFuZ2lidC4KClJfdmFsJGFtcCA8LSAoUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiRGFyayJdIC0gUl92YWwkZF9hYnMpL1Jfbm9ybSRkaWFbUl9ub3JtJENvbmQgPT0gIkRhcmsiXSoxMDAKUl92YWwxMCRhbXAgPC0gKFJfbm9ybSRkaWFbUl9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIFJfdmFsMTAkZF9hYnMpL1Jfbm9ybSRkaWFbUl9ub3JtJENvbmQgPT0gIkRhcmsiXSoxMDAKClJfdmFsJGFtcDIgPC0gKFJfbm9ybSRkaWFbUl9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIFJfdmFsJGRfYWJzKS8oUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiRGFyayJdIC0gdGVtcCkqMTAwClJfdmFsMTAkYW1wMiA8LSAoUl9ub3JtJGRpYVtSX25vcm0kQ29uZCA9PSAiRGFyayJdIC0gUl92YWwxMCRkX2FicykvKFJfbm9ybSRkaWFbUl9ub3JtJENvbmQgPT0gIkRhcmsiXSAtIFJfbm9ybSRkaWFbUl9ub3JtJENvbmQgPT0gIjEwXzE1Il0pKjEwMAoKCiNBYnNjaGxpZcOfZW5kIGRpZSBncmFmaXNjaGUgRGFyc3RlbGx1bmcKU2VucyA8LSAgZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gTF92YWwsIGFlcyh4PXdsLCB5PWFtcDIsIGdyb3VwID0gdGltZSwgY29sID0gIkxlZnQiKSwgYWxwaGEgPSAwLjI1KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBSX3ZhbCwgYWVzKHg9d2wsIHk9YW1wMiwgZ3JvdXAgPSB0aW1lLCBjb2wgPSAiUmlnaHQiKSwgYWxwaGEgPSAwLjI1KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBMX3ZhbDEwLCBhZXMoeT1hbXAyLCB4PXdsLCBjb2wgPSAiTGVmdCIpLCBsd2QgPSAxKSsKICBnZW9tX2xpbmUoZGF0YSA9IFJfdmFsMTAsIGFlcyh5PWFtcDIsIHg9d2wsIGNvbCA9ICJSaWdodCIpLCBsd2QgPSAxKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm49MSwgIiwgQ29kZSwgIiwgRG93biIsIHNlcD0iIiksIHggPSA0MDAsIHk9IDEwMCksIHNpemUgPSAyLjUpKwogIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCAiRXllIikrCiAgZ2d0aXRsZSgiU2Vuc2l0aXZpdHkgZGVwZW5kaW5nIG9uIHdhdmVsZW5ndGggYW5kIHRpbWUgKDEtMTUgcGVyIHNlY29uZCBhdmVyYWdlcyBpbiBsaWdodGVyIHRvbmUpIikrCiAgeWxhYigiU2Vuc2l0aXZpdHkgLyAlIikgKwogIHhsYWIoIldhdmVsZW5ndGggLyBubSIpKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwuMiksbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLCBzaXplID0gMC41KSkKClNlbnMKZ2dzYXZlKCJTZW5zaXRpdml0eS5wZGYiLCBwYXRoID0gIHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksbGltaXRzaXplPUYsIHdpZHRoPTEwLCBoZWlnaHQgPSA2KQoKYGBgCgoKU2NobGllw59saWNoIGVyZm9sZ3QgZGVyIEV4cG9ydCBkZXIgTWl0dGVsd2VydGUgZsO8ciBhbGxlIFdlbGxlbmzDpG5nZW4sIHNvd2llIGbDvHIgZGllIE5vcm1pZXJ1bmdzcmFuZGJlZGluZ3VuZ2VuCmBgYHtyIEV4cG9ydH0KI0VudHNjaGVpZHVuZyBmw7xyIGVpbiBBdWdlLCBhdWYgQmFzaXMgZGVyIG1laXN0ZW4gRGF0ZW52ZXJmw7xnYmFya2VpdCwgc29mZXJuIG5pY2h0IG1hbnVlbGwgZXR3YXMgYW5nZWdlYmVuIHdpcmQuCgpleHBvcnQgPC0gaWZlbHNlKGxlbmd0aChwdXBMZiRkaWFfc20pID4gbGVuZ3RoKHB1cFJmJGRpYV9zbSksICJMIiwgIlIiKQoKCnBhc3RlKCJ0aGUgcHVwaWwgb2YgdGhlIGZvbGxvd2luZyBleWUgaXMgdXNlZCBmb3IgZXhwb3J0OiAiLCBpZmVsc2UoZXhwb3J0ID09ICJSIiwgIlJpZ2h0IiwgIkxlZnQiKSkKCiNFcnN0ZWxsdW5nIGRlciBFeHBvcnRkYXRlbiBmw7xyIGRpZSBTZWt1bmRlbm1pdHRlbHdlcnRlLCBkaWUgMTAtMTUgU2VrdW5kZW5taXR0ZWx3ZXJ0ZSwgdW5kIGbDvHIgZGllIE5vcm1pZXJ1bmdzcmFuZGJlZGluZ3VuZ2VuCgp0ZW1wIDwtIGdldChwYXN0ZShleHBvcnQsICJfbm9ybSIsIHNlcD0iIikpCmV4cG9ydF9kYXRhMyA8LSBkYXRhLmZyYW1lKHQodGVtcFstMV0pKQpjb2xuYW1lcyhleHBvcnRfZGF0YTMpIDwtIHRlbXAkQ29uZApleHBvcnRfZGF0YTMgPC0gdGliYmxlKCJDb2RlIiA9IENvZGUsICJFeWUiID0gaWZlbHNlKGV4cG9ydCA9PSAiUiIsICJSaWdodCIsICJMZWZ0IiksICJEYXRlIiA9IGFzLkRhdGUocHVwJFVUQ1sxXSksICJUaW1lIiA9IGZvcm1hdChhcy5QT1NJWGN0KHB1cCRVVENbMV0pLCBmb3JtYXQgPSAiJUg6JU06JVMiKSwgIkRpciIgPSAiRG93biIsIGV4cG9ydF9kYXRhMykKCmV4cG9ydF9kYXRhMCA8LSBnZXQocGFzdGUoInB1cCIsIGV4cG9ydCwgImYiLCBzZXA9IiIpKQpleHBvcnRfZGF0YTAkYW1wMSA8LSAoZXhwb3J0X2RhdGEzJERhcmtbMV0gLSBleHBvcnRfZGF0YTAkZGlhX3NtKS9leHBvcnRfZGF0YTMkRGFya1sxXSoxMDAKCmV4cG9ydF9kYXRhMSA8LSBnZXQocGFzdGUoZXhwb3J0LCAiX3ZhbCIsIHNlcD0iIikpWy1sZW5ndGgoZ2V0KHBhc3RlKGV4cG9ydCwgIl92YWwiLCBzZXA9IiIpKSR3bCksXQpleHBvcnRfZGF0YTEkaW5kZXggPC0gbWF0Y2goZXhwb3J0X2RhdGExJHdsLCB3bCkKCmV4cG9ydF9kYXRhMiA8LSBnZXQocGFzdGUoZXhwb3J0LCAiX3ZhbDEwIiwgc2VwPSIiKSkKZXhwb3J0X2RhdGEyJGluZGV4IDwtIG1hdGNoKGV4cG9ydF9kYXRhMiR3bCwgd2wpCgp3cml0ZV9jc3YoZXhwb3J0X2RhdGEwLCBwYXN0ZSgiLi4vZGF0YV9vdXRwdXQvIiwgQ29kZSwgIl9mdWxsLmNzdiIsIHNlcD0iIikgKQp3cml0ZV9jc3YoZXhwb3J0X2RhdGExLCBwYXN0ZSgiLi4vZGF0YV9vdXRwdXQvIiwgQ29kZSwgIl9hbGwuY3N2Iiwgc2VwPSIiKSApCndyaXRlX2NzdihleHBvcnRfZGF0YTIsIHBhc3RlKCIuLi9kYXRhX291dHB1dC8iLCBDb2RlLCAiXzEwXzE1LmNzdiIsIHNlcD0iIikgKQp3cml0ZV9jc3YoZXhwb3J0X2RhdGEzLCBwYXN0ZSgiLi4vZGF0YV9vdXRwdXQvIiwgQ29kZSwgIl9ub3JtLmNzdiIsIHNlcD0iIikgKQoKYGBgCgoKYGBge3IgT3B0aW9uLCBldmFsID0gRn0KIy0tLS0gQW5mYW5nIENvZGUtT3B0aW9uCgojQWx0ZXJuYXRpdiwgd2VubiBtaXQgZGVtIFJlY2h0ZW4gQXVnZSBkaWUgWmVpdCBlcmZhc3N0IHdpcmQuCgojQmlsZHVuZyBkZXIgMS4gdW5kIDIuIEFibGVpdHVuZy4gTGluZWFyZSBUcmFuc2Zvcm1hdGlvbiwgZGFtaXQgZGllIMOcYmVybGFnZXJ1bmcgbWl0IGRlbSBQdXBpbGxlbmR1cmNobWVzc2VyIGxlc2JhciBibGVpYnQuCgpwdXBSZiRkaWFfc20xIDwtIChzZ29sYXlmaWx0KHB1cFJmJGRpYSwgcD0zLCBuPTMxLCBtPTEpKSoxMDArNgpwdXBSZiRkaWFfc20yIDwtIChzZ29sYXlmaWx0KHB1cFJmJGRpYSwgcD0zLCBuPTMxLCBtPTIpKSoxMDArNgoKCiNFcmtlbm51bmcgZGVyIFRpZWZwdW5rdGUgZGVyIDIuIEFibGVpdHVuZwp2bHkgPC0gZ2dwbG90KGRhdGEgPSBwdXBSZiwgYWVzKHg9dGltZSwgeT1kaWFfc20yKSkgKyAKICAgc3RhdF92YWxsZXlzKHNwYW4gPSA2MDEsIGNvbCA9ICJncmVlbiIpCiB2bHlfZGF0YSA8LSAobGF5ZXJfZGF0YSh2bHksIGk9MUwpJHhpbnRlcmNlcHQpCgojRGFyc3RlbGx1bmcgZGVyIFRpZWZwdW5rdGUgZGVyIDIuIEFibGVpdHVuZwogRGVyaXZhdGl2ZV90ZXN0IDwtIGdncGxvdChkYXRhID0gcHVwUmYsIGFlcyh4PXRpbWUsIHk9ZGlhX3NtMiwgY29sPSJ2YWxsZXkiKSkgKyAKICAgZ2VvbV9saW5lKGRhdGEgPSBwdXBSZiwgYWVzKHggPSB0aW1lLCB5ID0gZGlhX3NtLCBjb2wgPSAiRGlhbWV0ZXIiKSkgKwogICBnZW9tX2xpbmUoZGF0YSA9IHB1cExmLCBhZXMoeCA9IHRpbWUsIHkgPSBkaWFfc20sIGNvbCA9ICJEaWFtZXRlciIpKSArCiAgICAgZ2VvbV9saW5lKGFlcyhjb2wgPSAiMnN0IGRlcml2YXRpdmUiKSwgYWxwaGEgPSAwLjYpICsKICAgc3RhdF92YWxsZXlzKHNwYW4gPSA2MDEsIGNvbCA9ICJncmVlbiIpKwogICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSB2bHlfZGF0YS0wLjEsIGx3ZCA9IDAuMSwgY29sPSJncmVlbiIpKwogICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIm49MSwgIiwgQ29kZSwgc2VwPSIiKSwgeCA9IDUwLCB5PSA4KSwgc2l6ZSA9IDIuNSkrCiAgIHRoZW1lX2Nvd3Bsb3QoZm9udF9zaXplID0gOCwgZm9udF9mYW1pbHkgPSAic2FucyIpKwogICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgIlR5cGUiKSsKICAgZ2d0aXRsZSgiUHVwaWwtZGlhbWV0ZXIgZGF0YSBzbW9vdGhlZCB3aXRoIDJuZCBkZXJpdmF0aXZlIGFuZCB2YWxsZXlzICgtMTAwbXMpIikrCiAgIHlsYWIoIlB1cGlsIGRpYW1ldGVyIC8gbW0iKSArCiAgIHhsYWIoIlRpbWUgLyBzZWNvbmRzIikrCiAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45LC4xKSxsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIsIHNpemUgPSAwLjUpKSsKICAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDg1LCAxNTApKQoKIERlcml2YXRpdmVfdGVzdAogZ2dzYXZlKCJQdXBpbF9EZXJpdmF0aXZlX3Rlc3QucGRmIiwgcGF0aCA9IHBhc3RlKCIuLi9maWd1cmVzLyIsIENvZGUsIHNlcD0iIiksIHdpZHRoPTEwLCBoZWlnaHQgPSA1KQoKI1dhaGwgZWluZXMgUHJvZ3JhbW1zdGFydHB1bmt0cwoKdmx5X2RhdGEgPC0gdGliYmxlKCJpbmRleCIgPSAxOiBsZW5ndGgodmx5X2RhdGEpLCAidGltZSIgPSB2bHlfZGF0YS0wLjEsICJkaWYiID0gYyh2bHlfZGF0YVsxXSwgZGlmZih2bHlfZGF0YSkpKQprYWJsZSh2bHlfZGF0YVsxOjIwLF0sICJwYW5kb2MiLCBjYXB0aW9uID0gIlRpbWUgb2YgMm5kIGRlcml2YXRpdmUgdmFsbGV5cyAoLTEwMG1zKSwgZmlyc3QgMjAgcm93cyIsIGFsaWduID0gImMiKSMgVGllZnB1bmt0ZSBtaXQgWmVpdHN0ZW1wZWwKCiMtLS0tIEVuZGUgQ29kZS1PcHRpb24KYGBgCgo=