Click on “Code” symbols to unfold code (folded by default).

require(ggplot2)
require(grid)
require(gridExtra)
require(gganimate)
require(plotly)
require(lubridate)
require(colorRamps)
require(lmodel2)
require(broom)
require(pander)
source("selSessionRefs.R")
#Certified
load("/home/alobo/owncloudRSpect/RSpect/RefMCAA01.rda")
#load("C:/Users/Specim/ownCloud/RSpect/RefMCAA01.rda")

1. Stability of White Reference spectra

1.1 Stability of White Reference Radiance spectra (Data on cont. measurements 20221220)

We assess the stability of HSILab SpectroPi readings using the Spectralon White reference Method: continuous (every minute) radiance readings using time.measure.py with settings:

  • IT STS: 126 ms
  • IT NIRQUEST: 30 ms
  • Scans: 20

Radiance readings are not stable in the long term, but reading the white reference prior to each sample (as we do in our protocol) successfully results on stable and reproducible reflectance measurements.

fdir <- "../USBRaspberryBackup_20221219/time_measures2022"
lista <- data.frame(fname=list.files(fdir, patt=glob2rx("*.txt")), fdir=fdir)
Radcont <- data.frame(V1=0, V2=0, Radianceant=0, RadianceDif0=0, RadianceDif=0, sample=NA)
for (i in 1:nrow(lista)){
  if(i >1) radant <- a$V2
  a <- read.csv(file.path(lista[i,2], lista[i,1]),sep=" ", header=FALSE)
  if(i==1) radini <- radant <- a$V2
  a$Radianceant <- radant
  a$RadianceDif0 <- a$V2-radini
  a$RadianceDif <- a$V2-radant
  a$sample <- i
  Radcont <- rbind(Radcont,a)
}
colnames(Radcont) <- c("Wavelength", "Radiance", "Radianceant", "RadianceDif0","RadianceDif","Sample")
Radcont <- Radcont[-1,]
# dim(Radcont)
# head(Radcont)

#Display Selected readings:
sel <- Radcont[Radcont$Sample %in% c(2,25,50,75,100,135),]
sel$Reflectance0 <- sel$Radiance/Radcont$Radiance[Radcont$Sample==1]
sel$Reflectanceant <- sel$Radiance/sel$Radianceant
#table(sel$Sample)
samplenames <- paste0("t=",unique(sel$Sample))
names(samplenames) <- unique(sel$Sample)

#Raw Radiance data
ggRadcontsel <- ggplot(data=sel) +
  geom_point(aes(x=Wavelength, y=Radiance, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  geom_line (aes(x=Wavelength, y=Radiance, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  xlim(c(400, 2600))  + 
  #facet_wrap(~Sample, labeller=as_labeller(samplenames)) + 
  theme(legend.position="none") +
  #ggtitle("Stability of Radiance (White Reference)", subtitle = "Raw data")
  ggtitle("Radiance", subtitle = "Raw data")
#ggRadcontsel
ggsave(ggRadcontsel, filename="ggRadcontsel.jpeg",units="px", width=2100, height=2100)

#Radiance data (1st reading subtracted)
ggRadDif0contsel <- ggplot(data=sel) +
  geom_point(aes(x=Wavelength, y=RadianceDif0, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  geom_line (aes(x=Wavelength, y=RadianceDif0, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  xlim(c(400, 2600)) + ylim(c(-200,600)) + 
  #facet_wrap(~Sample, labeller=as_labeller(samplenames)) +
  ylab("Radiance - Radiance at t=0") +  
  theme(legend.position="none") +
  #ggtitle("Stability of Radiance (White Reference)", subtitle = "initial Radiance subtracted")
  ggtitle("Radiance", subtitle = "initial Radiance subtracted")
#ggRadDif0contsel

#grid.arrange(ggRadcontsel, ggRadDif0contsel, ncol=2,
#                           top=textGrob("Stability of Readings (White Reference)"))
ggsave(ggRadDif0contsel, filename="ggRadDif0contsel.jpeg",units="px", width=2100, height=2100)
#Display all radiance readings (raw data)
ggRadcont <- ggplot(data=Radcont,aes(x=Wavelength, y=Radiance, group=Sample,color=Sample)) +
  geom_point(alpha=1, size=0.5) +
  geom_line (alpha=1, linewidth=0.5) +
  #geom_line(data=Radcont[Radcont$Sample==2,]) +
  xlim(c(400, 2600))  +
  ggtitle("Stability of Radiance (White Reference)", subtitle = "Raw data")
#Visualizing all readings (samples) at once is not useful
# ggRadcont
# #ggplotly(ggRadcont) takes too long
# Rather use animation:

#not run in notebook:
#ggRadcont.anim <- ggRadcont + transition_time(Sample) +
#  labs(title = "Time: {frame_time}")
#animate(ggRadcont.anim)
#anim_save("ggWRadcont.anim.gif")

#Display all radiance readings (1st reading subtracted)
ggRadDifcont <- ggplot(data=Radcont, aes(x=Wavelength, y=RadianceDif0, group=Sample,color=Sample)) +
  #geom_point(alpha=1, size=0.5) +
  #geom_line (alpha=1, linewidth=0.5) +
  geom_line(data=Radcont[Radcont$Sample==2,]) +
  xlim(c(400, 2600))  +
  ggtitle("Stability of Radiance (White Reference)", subtitle = "initial Radiance subtracted")
#ggRadDifcont

#not run in notebook:
#ggRadDifcont_anim1 <- ggRadDifcont + transition_time(Sample) +
#  labs(title = "Time: {frame_time}") 
#animate(ggRadDifcont_anim1)
#anim_save("ggWRadDifcont_anim1.gif")
Raw Data Initial reading subtracted
animate animate

1.2 Stability of White reference Reflectance spectra (Data on cont. measurements 20221220)

The variablity of Reflectance readings is compensated by the ratio to a radiance reading that is close in time (eg. immediately prior) to that of the sample, as it is customary in lab and field protocols.

#Display Selected readings:
fdir <- "../USBRaspberryBackup_20221219/time_measures2022"
sel <- Radcont[Radcont$Sample %in% c(2,25,50,75,100,135),]
sel$Reflectance0 <- sel$Radiance/Radcont$Radiance[Radcont$Sample==1]
sel$Reflectanceant <- sel$Radiance/sel$Radianceant
#table(sel$Sample)
samplenames <- paste0("t=",unique(sel$Sample))
names(samplenames) <- unique(sel$Sample)

#Raw Radiance data
ggRadcontsel <- ggplot(data=sel) +
  geom_point(aes(x=Wavelength, y=Radiance, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  geom_line (aes(x=Wavelength, y=Radiance, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  xlim(c(400, 2600))  + facet_wrap(~Sample, labeller=as_labeller(samplenames)) + theme(legend.position="none") +
  #ggtitle("Stability of Radiance (White Reference)", subtitle = "Raw data")
  ggtitle("Radiance", subtitle = "Raw data")
#ggRadcontsel

#Radiance data (1st reading subtracted)
ggRadDif0contsel <- ggplot(data=sel) +
  geom_point(aes(x=Wavelength, y=RadianceDif0, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  geom_line (aes(x=Wavelength, y=RadianceDif0, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  xlim(c(400, 2600)) + ylim(c(-200,600)) + facet_wrap(~Sample, labeller=as_labeller(samplenames)) +
  ylab("Radiance - Radiance at t=0") +  theme(legend.position="none") +
  #ggtitle("Stability of Radiance (White Reference)", subtitle = "initial Radiance subtracted")
  ggtitle("Radiance", subtitle = "initial Radiance subtracted")
#ggRadDif0contsel

#Reflectance data (basis: 1st radiance reading)
ggRefl0contsel <- ggplot(data=sel) +
  geom_point(aes(x=Wavelength, y=Reflectance0, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  geom_line (aes(x=Wavelength, y=Reflectance0, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  xlim(c(400, 2600)) + ylim(c(0.9, 1.1)) + facet_wrap(~Sample, labeller=as_labeller(samplenames)) + 
  ylab("Radiance/Radiance at t=0") +  theme(legend.position="none") +
  #ggtitle("Stability of Reflectance (White Reference)", subtitle = "basis: initial Radiance")
  ggtitle("Reflectance", subtitle = "basis: initial Radiance")
#ggRefl0contsel

#Reflectance data (basis: previous radiance reading)
ggReflantcontsel <- ggplot(data=sel) +
  geom_point(aes(x=Wavelength, y=Reflectanceant, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  geom_line (aes(x=Wavelength, y=Reflectanceant, group=Sample,color=Sample),alpha=0.5, size=0.5) +
  xlim(c(400, 2600)) +  ylim(c(0.9, 1.1)) + facet_wrap(~Sample, labeller=as_labeller(samplenames)) +
  ylab("Radiance/Radiance at t=t-1") +  theme(legend.position="none") +
  #ggtitle("Stability of Reflectance (White Reference)", subtitle = "basis: previous Radiance")
  ggtitle("Reflectance", subtitle = "basis: previous Radiance")
#ggReflantcontsel

Wstability <- grid.arrange(ggRadcontsel, ggRadDif0contsel, ggRefl0contsel,ggReflantcontsel,
                           top=textGrob("Stability of Readings (White Reference)"))

#print(Wstability)
#not run in nb
#ggsave(Wstability, file="Wstability.pdf", width=12, height=8)

Selecting a given wavelength, we emphasize the drift of radiance readings and the stabilization by using the ratio to the previous (within 1’) reading: reflectance variability becomes bounded to +/- 0.0001

#Variability of Reflectance @1418 nm 
Radcont1418 <- Radcont[round(Radcont$Wavelength)==1419 ,]
Radcont1418$Reflectance0 <- Radcont1418$Radiance/Radcont1418$Radiance[Radcont1418$Sample==1]
Radcont1418$Reflectanceant <- Radcont1418$Radiance/Radcont1418$Radianceant

#Radiance @1418 nm
ggRad1418 <- ggplot(data=Radcont1418) +
  geom_point(aes(x=as.numeric(Sample), y=Radiance)) +
  xlab("Time (min)") + ylab("Radiance@1418.5820 nm")+ 
  ggtitle("Radiance")
#ggRad1418

#Reflectance @1418 nm  (basis: 1st radiance reading)
ggRefl01418 <- ggplot(data=Radcont1418) +
  geom_point(aes(x=as.numeric(Sample), y=Reflectance0)) +
  xlab("Time (min)") + ylab("Reflectance@1418.5820 nm")+ 
  ylim(c(0.999, 1.005)) +
  ggtitle("", subtitle = "basis: initial Radiance")
#ggRefl01418

#Reflectance @1418 nm  (basis: previous radiance reading)
ggReflant1418 <- ggplot(data=Radcont1418) +
  geom_point(aes(x=as.numeric(Sample), y=Reflectanceant)) +
  xlab("Time (min)") + ylab("Reflectance@1418.5820 nm")+ 
  ylim(c(0.999, 1.005)) +
  ggtitle("", subtitle = "basis: previous Radiance")
#ggReflant1418

#Wstability1418 <- grid.arrange(ggRad1418,ggRefl01418,ggReflant1418)
#ggsave(Wstability1418, file="Wstability1418.pdf", width=10, height=14, top=textGrob("Stability of Readings (White Reference)"))
Wstability1418 <- grid.arrange(ggRefl01418,ggReflant1418)

2. Stability of Standard Reference spectra (20230102 data)

Initial and final (138’ later) Reflectance measurements of the Standard reference are slightly shifted, despite having measured the white reference immediately before the target. Integration times (IT) were set to those calculated as optima by SpR: 46 ms (STS) and 15 ms (NIRQUEST).

fdir <- "../time_measures20230102"
lista <- data.frame(fname=list.files(fdir, patt=glob2rx("*.txt")), fdir=fdir)[-(1:121),] #exclude auto-capture readings
#lista <- lista[-1,]

#Inital and final (138' later) Reflectance measurements with IT 46 ms (STS) and 15 ms (NIRQUEST)
listasel <- lista[1:2,]
selRefs <- selSessionRefs(selflist=listasel)
selRefs$sample[selRefs$sample=="Ref_1"] <- "Initial" 
selRefs$sample[selRefs$sample=="Ref_2"] <- "Final" 
ggRefRefl <- ggplot(data=selRefs,aes(x=Wavelength, y=Reflectance)) +
  geom_point(alpha=1, size=0.5,aes(group=sample,color=sample)) +
  geom_line (alpha=1, linewidth=0.5, aes(group=sample, color=sample)) +
  #geom_line(data=Radcont[Radcont$Sample==2,]) +
  #geom_line(data=RefMCAA01, aes(x=Wavelength, y=Reflectance),col="grey") +
  geom_vline(aes(xintercept=1418.5820),linetype=4) +
  xlim(c(400, 2600)) +
  theme(legend.position="bottom") +
  ggtitle("Reflectance (Standard Target)", subtitle = "Initial and final readings (IT: 46 ms, 15 ms)")
#ggplotly(ggRefRefl)
ggplotly(ggRefRefl)  %>%
  layout(legend = list(orientation = "h", x = 0.7, y = 0.1))

Initial and Final Radiance and Reflectance spectra are linearly related with slopes close to 1. Relatively large intercept values indicate again a drift in Radiance, which is reduced (but not eliminated) in Reflectance measurements: 0.006 for the STS-IT (400-900 nm) and -0.07 for the NIRQUEST (950-2600 nm).

d <- selRefs[,c(1:6)]
ds <- plyr::ddply(d, c("sample","Wavelength"), summarise, 
                  Radiance = (Radiance-Dark),
                  WRadiance = WhiteRad,
                  Reflectance = Reflectance)

dsw <- data.frame(Wavelength=ds$Wavelength[ds$sample=="Initial"],
                  InitialRefl=ds$Reflectance[ds$sample=="Initial"], FinalRefl=ds$Reflectance[ds$sample=="Final"],
                  Initial=ds$Radiance[ds$sample=="Initial"], Final=ds$Radiance[ds$sample=="Final"],
                  WInitial=ds$WRadiance[ds$sample=="Initial"], WFinal=ds$WRadiance[ds$sample=="Final"])
dsw$Instrument <- "STS-IT"
dsw$Instrument[dsw$Wavelength>850] <- "NIRQUEST"

lm2Rad1 <- lmodel2(Final~Initial, data=dsw[dsw$Instrument=="STS-IT",])
lm2Rad2 <- lmodel2(Final~Initial, data=dsw[dsw$Instrument=="NIRQUEST",])
#lm2Rad1$regression.results[2,]
#lm2Rad2$regression.results[2,]

lm2W1 <- lmodel2(WFinal~WInitial, data=dsw[dsw$Instrument=="STS-IT",])
lm2W2 <- lmodel2(WFinal~WInitial, data=dsw[dsw$Instrument=="NIRQUEST",])
#lm2W1$regression.results[2,]
#lm2W2$regression.results[2,]

lm2Refl1 <- lmodel2(FinalRefl~InitialRefl, data=dsw[dsw$Instrument=="STS-IT",])
lm2Refl2 <- lmodel2(FinalRefl~InitialRefl, data=dsw[dsw$Instrument=="NIRQUEST",])
#lm2Refl1$regression.results[2,]
#lm2Refl2$regression.results[2,]

a <- rbind(
  lm2W1$regression.results[2,2:3],
  lm2W2$regression.results[2,2:3],
  lm2Rad1$regression.results[2,2:3],
  lm2Rad2$regression.results[2,2:3],
  lm2Refl1$regression.results[2,2:3],
  lm2Refl2$regression.results[2,2:3])
a$Instrument <- rep(c("STS-IT", "NIRQUEST"),3)
a$Target <- c(rep("W",2), rep("Std",4))
a$Magnitude <- c(rep("Radiance",4), rep("Reflectance",2))
a <- a[,c(4,5,3,1,2)]
rownames(a) <- NULL


ggWRad <- ggplot(data=dsw, aes(x=WInitial, y=WFinal,color=Instrument)) +
  geom_point() +
  geom_abline(aes(intercept=lm2W1$regression.results[2,2], slope=lm2W1$regression.results[2,3])) +
  geom_abline(aes(intercept=lm2W2$regression.results[2,2], slope=lm2W2$regression.results[2,3])) +
  geom_abline(aes(intercept=0, slope=1), linetype=4) +
  xlab("Radiance (Initial measurement)") +  ylab("Radiance (Final measurement)") + 
  theme(legend.position = c(.85,.15), aspect.ratio=1) + 
  ggtitle("White Reference") 
ggRad <- ggplot(data=dsw, aes(x=Initial, y=Final,color=Instrument)) +
  geom_point() +
  geom_abline(aes(intercept=lm2Rad1$regression.results[2,2], slope=lm2Rad1$regression.results[2,3])) +
  geom_abline(aes(intercept=lm2Rad2$regression.results[2,2], slope=lm2Rad2$regression.results[2,3])) +
  geom_abline(aes(intercept=0, slope=1), linetype=4) +
  xlab("Radiance (Initial measurement)") +  ylab("Radiance (Final measurement)") + 
  theme(legend.position = c(.85,.15), aspect.ratio=1) +
  ggtitle("Standard Reference")
ggRefl <- ggplot(data=dsw, aes(x=InitialRefl, y=FinalRefl,color=Instrument)) +
  geom_point() +
  geom_abline(aes(intercept=lm2Refl1$regression.results[2,2], slope=lm2Refl1$regression.results[2,3])) +
  geom_abline(aes(intercept=lm2Refl2$regression.results[2,2], slope=lm2Refl2$regression.results[2,3])) +
  geom_abline(aes(intercept=0, slope=1), linetype=4)+
  xlab("Reflectance (Initial measurement)") +  ylab("Reflectance (Final measurement)") + 
  theme(legend.position = c(.85,.15), aspect.ratio=1) +
  ggtitle("Standard Reference")
grid.arrange(ggWRad, ggRad,  nrow=1)

pander::pander(arrange(a[1:4,]))#dplyr::arrange returns the df without rownames

------------------------------------------------------
 Target   Magnitude   Instrument   Intercept   Slope  
-------- ----------- ------------ ----------- --------
   W      Radiance      STS-IT       37.3      1.033  

   W      Radiance     NIRQUEST     -64.54     0.9872 

  Std     Radiance      STS-IT       37.26     1.018  

  Std     Radiance     NIRQUEST     -63.48     0.9601 
------------------------------------------------------
ggRefl

pander::pander(arrange(a[5:6,]))

--------------------------------------------------------
 Target    Magnitude    Instrument   Intercept   Slope  
-------- ------------- ------------ ----------- --------
  Std     Reflectance     STS-IT     0.006145    0.9826 

  Std     Reflectance    NIRQUEST    -0.07384    1.067  
--------------------------------------------------------
LS0tCnRpdGxlOiAiU3RhYmlsaXR5IG9mIFNwZWN0cm9SYXNwIHNwZWN0cmEgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZmlnX2NhcHRpb246IFRSVUUKLS0tCgotICAgW0FndXN0aW4uTG9ib1xAZ2VvM2Jjbi5jc2ljLmVzXShtYWlsdG86QWd1c3Rpbi5Mb2JvQGdlbzNiY24uY3NpYy5lcyl7LmVtYWlsfQotICAgMjAyMjEyMjIsIDIwMjMwMTAzLCAyMDIzMDEwOSwgMjAyMzAyMDYKCipDbGljayBvbiAiQ29kZSIgc3ltYm9scyB0byB1bmZvbGQgY29kZSAoZm9sZGVkIGJ5IGRlZmF1bHQpLioKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUoZ3JpZCkKcmVxdWlyZShncmlkRXh0cmEpCnJlcXVpcmUoZ2dhbmltYXRlKQpyZXF1aXJlKHBsb3RseSkKcmVxdWlyZShsdWJyaWRhdGUpCnJlcXVpcmUoY29sb3JSYW1wcykKcmVxdWlyZShsbW9kZWwyKQpyZXF1aXJlKGJyb29tKQpyZXF1aXJlKHBhbmRlcikKc291cmNlKCJzZWxTZXNzaW9uUmVmcy5SIikKI0NlcnRpZmllZApsb2FkKCIvaG9tZS9hbG9iby9vd25jbG91ZFJTcGVjdC9SU3BlY3QvUmVmTUNBQTAxLnJkYSIpCiNsb2FkKCJDOi9Vc2Vycy9TcGVjaW0vb3duQ2xvdWQvUlNwZWN0L1JlZk1DQUEwMS5yZGEiKQpgYGAKCiMjIDEuIFN0YWJpbGl0eSBvZiBXaGl0ZSBSZWZlcmVuY2Ugc3BlY3RyYQojIyMgMS4xIFN0YWJpbGl0eSBvZiBXaGl0ZSBSZWZlcmVuY2UgUmFkaWFuY2Ugc3BlY3RyYSAoRGF0YSBvbiBjb250LiBtZWFzdXJlbWVudHMgMjAyMjEyMjApCgpXZSBhc3Nlc3MgdGhlIHN0YWJpbGl0eSBvZiBIU0lMYWIgU3BlY3Ryb1BpIHJlYWRpbmdzIHVzaW5nIHRoZSBTcGVjdHJhbG9uIFdoaXRlIHJlZmVyZW5jZSBNZXRob2Q6IGNvbnRpbnVvdXMgKGV2ZXJ5IG1pbnV0ZSkgcmFkaWFuY2UgcmVhZGluZ3MgdXNpbmcgdGltZS5tZWFzdXJlLnB5IHdpdGggc2V0dGluZ3M6CgotICAgSVQgU1RTOiAxMjYgbXMKLSAgIElUIE5JUlFVRVNUOiAzMCBtcwotICAgU2NhbnM6IDIwCgpSYWRpYW5jZSByZWFkaW5ncyBhcmUgbm90IHN0YWJsZSBpbiB0aGUgbG9uZyB0ZXJtLCBidXQgcmVhZGluZyB0aGUgd2hpdGUgcmVmZXJlbmNlIHByaW9yIHRvIGVhY2ggc2FtcGxlIChhcyB3ZSBkbyBpbiBvdXIgcHJvdG9jb2wpIHN1Y2Nlc3NmdWxseSByZXN1bHRzIG9uIHN0YWJsZSBhbmQgcmVwcm9kdWNpYmxlIHJlZmxlY3RhbmNlIG1lYXN1cmVtZW50cy4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmZkaXIgPC0gIi4uL1VTQlJhc3BiZXJyeUJhY2t1cF8yMDIyMTIxOS90aW1lX21lYXN1cmVzMjAyMiIKbGlzdGEgPC0gZGF0YS5mcmFtZShmbmFtZT1saXN0LmZpbGVzKGZkaXIsIHBhdHQ9Z2xvYjJyeCgiKi50eHQiKSksIGZkaXI9ZmRpcikKUmFkY29udCA8LSBkYXRhLmZyYW1lKFYxPTAsIFYyPTAsIFJhZGlhbmNlYW50PTAsIFJhZGlhbmNlRGlmMD0wLCBSYWRpYW5jZURpZj0wLCBzYW1wbGU9TkEpCmZvciAoaSBpbiAxOm5yb3cobGlzdGEpKXsKICBpZihpID4xKSByYWRhbnQgPC0gYSRWMgogIGEgPC0gcmVhZC5jc3YoZmlsZS5wYXRoKGxpc3RhW2ksMl0sIGxpc3RhW2ksMV0pLHNlcD0iICIsIGhlYWRlcj1GQUxTRSkKICBpZihpPT0xKSByYWRpbmkgPC0gcmFkYW50IDwtIGEkVjIKICBhJFJhZGlhbmNlYW50IDwtIHJhZGFudAogIGEkUmFkaWFuY2VEaWYwIDwtIGEkVjItcmFkaW5pCiAgYSRSYWRpYW5jZURpZiA8LSBhJFYyLXJhZGFudAogIGEkc2FtcGxlIDwtIGkKICBSYWRjb250IDwtIHJiaW5kKFJhZGNvbnQsYSkKfQpjb2xuYW1lcyhSYWRjb250KSA8LSBjKCJXYXZlbGVuZ3RoIiwgIlJhZGlhbmNlIiwgIlJhZGlhbmNlYW50IiwgIlJhZGlhbmNlRGlmMCIsIlJhZGlhbmNlRGlmIiwiU2FtcGxlIikKUmFkY29udCA8LSBSYWRjb250Wy0xLF0KIyBkaW0oUmFkY29udCkKIyBoZWFkKFJhZGNvbnQpCgojRGlzcGxheSBTZWxlY3RlZCByZWFkaW5nczoKc2VsIDwtIFJhZGNvbnRbUmFkY29udCRTYW1wbGUgJWluJSBjKDIsMjUsNTAsNzUsMTAwLDEzNSksXQpzZWwkUmVmbGVjdGFuY2UwIDwtIHNlbCRSYWRpYW5jZS9SYWRjb250JFJhZGlhbmNlW1JhZGNvbnQkU2FtcGxlPT0xXQpzZWwkUmVmbGVjdGFuY2VhbnQgPC0gc2VsJFJhZGlhbmNlL3NlbCRSYWRpYW5jZWFudAojdGFibGUoc2VsJFNhbXBsZSkKc2FtcGxlbmFtZXMgPC0gcGFzdGUwKCJ0PSIsdW5pcXVlKHNlbCRTYW1wbGUpKQpuYW1lcyhzYW1wbGVuYW1lcykgPC0gdW5pcXVlKHNlbCRTYW1wbGUpCgojUmF3IFJhZGlhbmNlIGRhdGEKZ2dSYWRjb250c2VsIDwtIGdncGxvdChkYXRhPXNlbCkgKwogIGdlb21fcG9pbnQoYWVzKHg9V2F2ZWxlbmd0aCwgeT1SYWRpYW5jZSwgZ3JvdXA9U2FtcGxlLGNvbG9yPVNhbXBsZSksYWxwaGE9MC41LCBzaXplPTAuNSkgKwogIGdlb21fbGluZSAoYWVzKHg9V2F2ZWxlbmd0aCwgeT1SYWRpYW5jZSwgZ3JvdXA9U2FtcGxlLGNvbG9yPVNhbXBsZSksYWxwaGE9MC41LCBzaXplPTAuNSkgKwogIHhsaW0oYyg0MDAsIDI2MDApKSAgKyAKICAjZmFjZXRfd3JhcCh+U2FtcGxlLCBsYWJlbGxlcj1hc19sYWJlbGxlcihzYW1wbGVuYW1lcykpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogICNnZ3RpdGxlKCJTdGFiaWxpdHkgb2YgUmFkaWFuY2UgKFdoaXRlIFJlZmVyZW5jZSkiLCBzdWJ0aXRsZSA9ICJSYXcgZGF0YSIpCiAgZ2d0aXRsZSgiUmFkaWFuY2UiLCBzdWJ0aXRsZSA9ICJSYXcgZGF0YSIpCiNnZ1JhZGNvbnRzZWwKZ2dzYXZlKGdnUmFkY29udHNlbCwgZmlsZW5hbWU9ImdnUmFkY29udHNlbC5qcGVnIix1bml0cz0icHgiLCB3aWR0aD0yMTAwLCBoZWlnaHQ9MjEwMCkKCiNSYWRpYW5jZSBkYXRhICgxc3QgcmVhZGluZyBzdWJ0cmFjdGVkKQpnZ1JhZERpZjBjb250c2VsIDwtIGdncGxvdChkYXRhPXNlbCkgKwogIGdlb21fcG9pbnQoYWVzKHg9V2F2ZWxlbmd0aCwgeT1SYWRpYW5jZURpZjAsIGdyb3VwPVNhbXBsZSxjb2xvcj1TYW1wbGUpLGFscGhhPTAuNSwgc2l6ZT0wLjUpICsKICBnZW9tX2xpbmUgKGFlcyh4PVdhdmVsZW5ndGgsIHk9UmFkaWFuY2VEaWYwLCBncm91cD1TYW1wbGUsY29sb3I9U2FtcGxlKSxhbHBoYT0wLjUsIHNpemU9MC41KSArCiAgeGxpbShjKDQwMCwgMjYwMCkpICsgeWxpbShjKC0yMDAsNjAwKSkgKyAKICAjZmFjZXRfd3JhcCh+U2FtcGxlLCBsYWJlbGxlcj1hc19sYWJlbGxlcihzYW1wbGVuYW1lcykpICsKICB5bGFiKCJSYWRpYW5jZSAtIFJhZGlhbmNlIGF0IHQ9MCIpICsgIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICAjZ2d0aXRsZSgiU3RhYmlsaXR5IG9mIFJhZGlhbmNlIChXaGl0ZSBSZWZlcmVuY2UpIiwgc3VidGl0bGUgPSAiaW5pdGlhbCBSYWRpYW5jZSBzdWJ0cmFjdGVkIikKICBnZ3RpdGxlKCJSYWRpYW5jZSIsIHN1YnRpdGxlID0gImluaXRpYWwgUmFkaWFuY2Ugc3VidHJhY3RlZCIpCiNnZ1JhZERpZjBjb250c2VsCgojZ3JpZC5hcnJhbmdlKGdnUmFkY29udHNlbCwgZ2dSYWREaWYwY29udHNlbCwgbmNvbD0yLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9wPXRleHRHcm9iKCJTdGFiaWxpdHkgb2YgUmVhZGluZ3MgKFdoaXRlIFJlZmVyZW5jZSkiKSkKZ2dzYXZlKGdnUmFkRGlmMGNvbnRzZWwsIGZpbGVuYW1lPSJnZ1JhZERpZjBjb250c2VsLmpwZWciLHVuaXRzPSJweCIsIHdpZHRoPTIxMDAsIGhlaWdodD0yMTAwKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTIuNSwgIGZpZy5zaG93PSdob2xkJywgb3V0LndpZHRoID0gJzUwJSd9CiNEaXNwbGF5IGFsbCByYWRpYW5jZSByZWFkaW5ncyAocmF3IGRhdGEpCmdnUmFkY29udCA8LSBnZ3Bsb3QoZGF0YT1SYWRjb250LGFlcyh4PVdhdmVsZW5ndGgsIHk9UmFkaWFuY2UsIGdyb3VwPVNhbXBsZSxjb2xvcj1TYW1wbGUpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0xLCBzaXplPTAuNSkgKwogIGdlb21fbGluZSAoYWxwaGE9MSwgbGluZXdpZHRoPTAuNSkgKwogICNnZW9tX2xpbmUoZGF0YT1SYWRjb250W1JhZGNvbnQkU2FtcGxlPT0yLF0pICsKICB4bGltKGMoNDAwLCAyNjAwKSkgICsKICBnZ3RpdGxlKCJTdGFiaWxpdHkgb2YgUmFkaWFuY2UgKFdoaXRlIFJlZmVyZW5jZSkiLCBzdWJ0aXRsZSA9ICJSYXcgZGF0YSIpCiNWaXN1YWxpemluZyBhbGwgcmVhZGluZ3MgKHNhbXBsZXMpIGF0IG9uY2UgaXMgbm90IHVzZWZ1bAojIGdnUmFkY29udAojICNnZ3Bsb3RseShnZ1JhZGNvbnQpIHRha2VzIHRvbyBsb25nCiMgUmF0aGVyIHVzZSBhbmltYXRpb246Cgojbm90IHJ1biBpbiBub3RlYm9vazoKI2dnUmFkY29udC5hbmltIDwtIGdnUmFkY29udCArIHRyYW5zaXRpb25fdGltZShTYW1wbGUpICsKIyAgbGFicyh0aXRsZSA9ICJUaW1lOiB7ZnJhbWVfdGltZX0iKQojYW5pbWF0ZShnZ1JhZGNvbnQuYW5pbSkKI2FuaW1fc2F2ZSgiZ2dXUmFkY29udC5hbmltLmdpZiIpCgojRGlzcGxheSBhbGwgcmFkaWFuY2UgcmVhZGluZ3MgKDFzdCByZWFkaW5nIHN1YnRyYWN0ZWQpCmdnUmFkRGlmY29udCA8LSBnZ3Bsb3QoZGF0YT1SYWRjb250LCBhZXMoeD1XYXZlbGVuZ3RoLCB5PVJhZGlhbmNlRGlmMCwgZ3JvdXA9U2FtcGxlLGNvbG9yPVNhbXBsZSkpICsKICAjZ2VvbV9wb2ludChhbHBoYT0xLCBzaXplPTAuNSkgKwogICNnZW9tX2xpbmUgKGFscGhhPTEsIGxpbmV3aWR0aD0wLjUpICsKICBnZW9tX2xpbmUoZGF0YT1SYWRjb250W1JhZGNvbnQkU2FtcGxlPT0yLF0pICsKICB4bGltKGMoNDAwLCAyNjAwKSkgICsKICBnZ3RpdGxlKCJTdGFiaWxpdHkgb2YgUmFkaWFuY2UgKFdoaXRlIFJlZmVyZW5jZSkiLCBzdWJ0aXRsZSA9ICJpbml0aWFsIFJhZGlhbmNlIHN1YnRyYWN0ZWQiKQojZ2dSYWREaWZjb250Cgojbm90IHJ1biBpbiBub3RlYm9vazoKI2dnUmFkRGlmY29udF9hbmltMSA8LSBnZ1JhZERpZmNvbnQgKyB0cmFuc2l0aW9uX3RpbWUoU2FtcGxlKSArCiMgIGxhYnModGl0bGUgPSAiVGltZToge2ZyYW1lX3RpbWV9IikgCiNhbmltYXRlKGdnUmFkRGlmY29udF9hbmltMSkKI2FuaW1fc2F2ZSgiZ2dXUmFkRGlmY29udF9hbmltMS5naWYiKQoKYGBgCgoKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8UmF3IERhdGEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8SW5pdGlhbCByZWFkaW5nIHN1YnRyYWN0ZWQgICAgICAgICAgICAgICB8Cis6PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ois6PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09OisKfCFbXShnZ1JhZGNvbnRzZWwuanBlZykgICAgICAgICAgICAgICAgICAgfCFbXShnZ1JhZERpZjBjb250c2VsLmpwZWcpICAgICAgICAgICAgICAgfAp8W2FuaW1hdGVdKC4vZ2dXUmFkY29udC5hbmltLmdpZikgICAgICAgICB8W2FuaW1hdGVdKC4vZ2dXUmFkRGlmY29udF9hbmltMS5naWYpICAgICB8Cis9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSs9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSsKCiAKCgoKIyMjIDEuMiBTdGFiaWxpdHkgb2YgV2hpdGUgcmVmZXJlbmNlIFJlZmxlY3RhbmNlIHNwZWN0cmEgIChEYXRhIG9uIGNvbnQuIG1lYXN1cmVtZW50cyAyMDIyMTIyMCkKClRoZSB2YXJpYWJsaXR5IG9mIFJlZmxlY3RhbmNlIHJlYWRpbmdzIGlzIGNvbXBlbnNhdGVkIGJ5IHRoZSByYXRpbyB0byBhIHJhZGlhbmNlIHJlYWRpbmcgdGhhdCBpcyBjbG9zZSBpbiB0aW1lIChlZy4gaW1tZWRpYXRlbHkgcHJpb3IpIHRvIHRoYXQgb2YgdGhlIHNhbXBsZSwgYXMgaXQgaXMgY3VzdG9tYXJ5IGluIGxhYiBhbmQgZmllbGQgcHJvdG9jb2xzLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQojRGlzcGxheSBTZWxlY3RlZCByZWFkaW5nczoKZmRpciA8LSAiLi4vVVNCUmFzcGJlcnJ5QmFja3VwXzIwMjIxMjE5L3RpbWVfbWVhc3VyZXMyMDIyIgpzZWwgPC0gUmFkY29udFtSYWRjb250JFNhbXBsZSAlaW4lIGMoMiwyNSw1MCw3NSwxMDAsMTM1KSxdCnNlbCRSZWZsZWN0YW5jZTAgPC0gc2VsJFJhZGlhbmNlL1JhZGNvbnQkUmFkaWFuY2VbUmFkY29udCRTYW1wbGU9PTFdCnNlbCRSZWZsZWN0YW5jZWFudCA8LSBzZWwkUmFkaWFuY2Uvc2VsJFJhZGlhbmNlYW50CiN0YWJsZShzZWwkU2FtcGxlKQpzYW1wbGVuYW1lcyA8LSBwYXN0ZTAoInQ9Iix1bmlxdWUoc2VsJFNhbXBsZSkpCm5hbWVzKHNhbXBsZW5hbWVzKSA8LSB1bmlxdWUoc2VsJFNhbXBsZSkKCiNSYXcgUmFkaWFuY2UgZGF0YQpnZ1JhZGNvbnRzZWwgPC0gZ2dwbG90KGRhdGE9c2VsKSArCiAgZ2VvbV9wb2ludChhZXMoeD1XYXZlbGVuZ3RoLCB5PVJhZGlhbmNlLCBncm91cD1TYW1wbGUsY29sb3I9U2FtcGxlKSxhbHBoYT0wLjUsIHNpemU9MC41KSArCiAgZ2VvbV9saW5lIChhZXMoeD1XYXZlbGVuZ3RoLCB5PVJhZGlhbmNlLCBncm91cD1TYW1wbGUsY29sb3I9U2FtcGxlKSxhbHBoYT0wLjUsIHNpemU9MC41KSArCiAgeGxpbShjKDQwMCwgMjYwMCkpICArIGZhY2V0X3dyYXAoflNhbXBsZSwgbGFiZWxsZXI9YXNfbGFiZWxsZXIoc2FtcGxlbmFtZXMpKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICAjZ2d0aXRsZSgiU3RhYmlsaXR5IG9mIFJhZGlhbmNlIChXaGl0ZSBSZWZlcmVuY2UpIiwgc3VidGl0bGUgPSAiUmF3IGRhdGEiKQogIGdndGl0bGUoIlJhZGlhbmNlIiwgc3VidGl0bGUgPSAiUmF3IGRhdGEiKQojZ2dSYWRjb250c2VsCgojUmFkaWFuY2UgZGF0YSAoMXN0IHJlYWRpbmcgc3VidHJhY3RlZCkKZ2dSYWREaWYwY29udHNlbCA8LSBnZ3Bsb3QoZGF0YT1zZWwpICsKICBnZW9tX3BvaW50KGFlcyh4PVdhdmVsZW5ndGgsIHk9UmFkaWFuY2VEaWYwLCBncm91cD1TYW1wbGUsY29sb3I9U2FtcGxlKSxhbHBoYT0wLjUsIHNpemU9MC41KSArCiAgZ2VvbV9saW5lIChhZXMoeD1XYXZlbGVuZ3RoLCB5PVJhZGlhbmNlRGlmMCwgZ3JvdXA9U2FtcGxlLGNvbG9yPVNhbXBsZSksYWxwaGE9MC41LCBzaXplPTAuNSkgKwogIHhsaW0oYyg0MDAsIDI2MDApKSArIHlsaW0oYygtMjAwLDYwMCkpICsgZmFjZXRfd3JhcCh+U2FtcGxlLCBsYWJlbGxlcj1hc19sYWJlbGxlcihzYW1wbGVuYW1lcykpICsKICB5bGFiKCJSYWRpYW5jZSAtIFJhZGlhbmNlIGF0IHQ9MCIpICsgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICAjZ2d0aXRsZSgiU3RhYmlsaXR5IG9mIFJhZGlhbmNlIChXaGl0ZSBSZWZlcmVuY2UpIiwgc3VidGl0bGUgPSAiaW5pdGlhbCBSYWRpYW5jZSBzdWJ0cmFjdGVkIikKICBnZ3RpdGxlKCJSYWRpYW5jZSIsIHN1YnRpdGxlID0gImluaXRpYWwgUmFkaWFuY2Ugc3VidHJhY3RlZCIpCiNnZ1JhZERpZjBjb250c2VsCgojUmVmbGVjdGFuY2UgZGF0YSAoYmFzaXM6IDFzdCByYWRpYW5jZSByZWFkaW5nKQpnZ1JlZmwwY29udHNlbCA8LSBnZ3Bsb3QoZGF0YT1zZWwpICsKICBnZW9tX3BvaW50KGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UwLCBncm91cD1TYW1wbGUsY29sb3I9U2FtcGxlKSxhbHBoYT0wLjUsIHNpemU9MC41KSArCiAgZ2VvbV9saW5lIChhZXMoeD1XYXZlbGVuZ3RoLCB5PVJlZmxlY3RhbmNlMCwgZ3JvdXA9U2FtcGxlLGNvbG9yPVNhbXBsZSksYWxwaGE9MC41LCBzaXplPTAuNSkgKwogIHhsaW0oYyg0MDAsIDI2MDApKSArIHlsaW0oYygwLjksIDEuMSkpICsgZmFjZXRfd3JhcCh+U2FtcGxlLCBsYWJlbGxlcj1hc19sYWJlbGxlcihzYW1wbGVuYW1lcykpICsgCiAgeWxhYigiUmFkaWFuY2UvUmFkaWFuY2UgYXQgdD0wIikgKyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogICNnZ3RpdGxlKCJTdGFiaWxpdHkgb2YgUmVmbGVjdGFuY2UgKFdoaXRlIFJlZmVyZW5jZSkiLCBzdWJ0aXRsZSA9ICJiYXNpczogaW5pdGlhbCBSYWRpYW5jZSIpCiAgZ2d0aXRsZSgiUmVmbGVjdGFuY2UiLCBzdWJ0aXRsZSA9ICJiYXNpczogaW5pdGlhbCBSYWRpYW5jZSIpCiNnZ1JlZmwwY29udHNlbAoKI1JlZmxlY3RhbmNlIGRhdGEgKGJhc2lzOiBwcmV2aW91cyByYWRpYW5jZSByZWFkaW5nKQpnZ1JlZmxhbnRjb250c2VsIDwtIGdncGxvdChkYXRhPXNlbCkgKwogIGdlb21fcG9pbnQoYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZWFudCwgZ3JvdXA9U2FtcGxlLGNvbG9yPVNhbXBsZSksYWxwaGE9MC41LCBzaXplPTAuNSkgKwogIGdlb21fbGluZSAoYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZWFudCwgZ3JvdXA9U2FtcGxlLGNvbG9yPVNhbXBsZSksYWxwaGE9MC41LCBzaXplPTAuNSkgKwogIHhsaW0oYyg0MDAsIDI2MDApKSArICB5bGltKGMoMC45LCAxLjEpKSArIGZhY2V0X3dyYXAoflNhbXBsZSwgbGFiZWxsZXI9YXNfbGFiZWxsZXIoc2FtcGxlbmFtZXMpKSArCiAgeWxhYigiUmFkaWFuY2UvUmFkaWFuY2UgYXQgdD10LTEiKSArICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgI2dndGl0bGUoIlN0YWJpbGl0eSBvZiBSZWZsZWN0YW5jZSAoV2hpdGUgUmVmZXJlbmNlKSIsIHN1YnRpdGxlID0gImJhc2lzOiBwcmV2aW91cyBSYWRpYW5jZSIpCiAgZ2d0aXRsZSgiUmVmbGVjdGFuY2UiLCBzdWJ0aXRsZSA9ICJiYXNpczogcHJldmlvdXMgUmFkaWFuY2UiKQojZ2dSZWZsYW50Y29udHNlbAoKV3N0YWJpbGl0eSA8LSBncmlkLmFycmFuZ2UoZ2dSYWRjb250c2VsLCBnZ1JhZERpZjBjb250c2VsLCBnZ1JlZmwwY29udHNlbCxnZ1JlZmxhbnRjb250c2VsLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0b3A9dGV4dEdyb2IoIlN0YWJpbGl0eSBvZiBSZWFkaW5ncyAoV2hpdGUgUmVmZXJlbmNlKSIpKQojcHJpbnQoV3N0YWJpbGl0eSkKI25vdCBydW4gaW4gbmIKI2dnc2F2ZShXc3RhYmlsaXR5LCBmaWxlPSJXc3RhYmlsaXR5LnBkZiIsIHdpZHRoPTEyLCBoZWlnaHQ9OCkKYGBgCgoKU2VsZWN0aW5nIGEgZ2l2ZW4gd2F2ZWxlbmd0aCwgd2UgZW1waGFzaXplIHRoZSBkcmlmdCBvZiByYWRpYW5jZSByZWFkaW5ncyBhbmQgdGhlIHN0YWJpbGl6YXRpb24gYnkgdXNpbmcgdGhlIHJhdGlvIHRvIHRoZSBwcmV2aW91cyAod2l0aGluIDEnKSByZWFkaW5nOiByZWZsZWN0YW5jZSB2YXJpYWJpbGl0eSBiZWNvbWVzIGJvdW5kZWQgdG8gKy8tIDAuMDAwMQoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsICBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OH0KI1ZhcmlhYmlsaXR5IG9mIFJlZmxlY3RhbmNlIEAxNDE4IG5tIApSYWRjb250MTQxOCA8LSBSYWRjb250W3JvdW5kKFJhZGNvbnQkV2F2ZWxlbmd0aCk9PTE0MTkgLF0KUmFkY29udDE0MTgkUmVmbGVjdGFuY2UwIDwtIFJhZGNvbnQxNDE4JFJhZGlhbmNlL1JhZGNvbnQxNDE4JFJhZGlhbmNlW1JhZGNvbnQxNDE4JFNhbXBsZT09MV0KUmFkY29udDE0MTgkUmVmbGVjdGFuY2VhbnQgPC0gUmFkY29udDE0MTgkUmFkaWFuY2UvUmFkY29udDE0MTgkUmFkaWFuY2VhbnQKCiNSYWRpYW5jZSBAMTQxOCBubQpnZ1JhZDE0MTggPC0gZ2dwbG90KGRhdGE9UmFkY29udDE0MTgpICsKICBnZW9tX3BvaW50KGFlcyh4PWFzLm51bWVyaWMoU2FtcGxlKSwgeT1SYWRpYW5jZSkpICsKICB4bGFiKCJUaW1lIChtaW4pIikgKyB5bGFiKCJSYWRpYW5jZUAxNDE4LjU4MjAgbm0iKSsgCiAgZ2d0aXRsZSgiUmFkaWFuY2UiKQojZ2dSYWQxNDE4CgojUmVmbGVjdGFuY2UgQDE0MTggbm0gIChiYXNpczogMXN0IHJhZGlhbmNlIHJlYWRpbmcpCmdnUmVmbDAxNDE4IDwtIGdncGxvdChkYXRhPVJhZGNvbnQxNDE4KSArCiAgZ2VvbV9wb2ludChhZXMoeD1hcy5udW1lcmljKFNhbXBsZSksIHk9UmVmbGVjdGFuY2UwKSkgKwogIHhsYWIoIlRpbWUgKG1pbikiKSArIHlsYWIoIlJlZmxlY3RhbmNlQDE0MTguNTgyMCBubSIpKyAKICB5bGltKGMoMC45OTksIDEuMDA1KSkgKwogIGdndGl0bGUoIiIsIHN1YnRpdGxlID0gImJhc2lzOiBpbml0aWFsIFJhZGlhbmNlIikKI2dnUmVmbDAxNDE4CgojUmVmbGVjdGFuY2UgQDE0MTggbm0gIChiYXNpczogcHJldmlvdXMgcmFkaWFuY2UgcmVhZGluZykKZ2dSZWZsYW50MTQxOCA8LSBnZ3Bsb3QoZGF0YT1SYWRjb250MTQxOCkgKwogIGdlb21fcG9pbnQoYWVzKHg9YXMubnVtZXJpYyhTYW1wbGUpLCB5PVJlZmxlY3RhbmNlYW50KSkgKwogIHhsYWIoIlRpbWUgKG1pbikiKSArIHlsYWIoIlJlZmxlY3RhbmNlQDE0MTguNTgyMCBubSIpKyAKICB5bGltKGMoMC45OTksIDEuMDA1KSkgKwogIGdndGl0bGUoIiIsIHN1YnRpdGxlID0gImJhc2lzOiBwcmV2aW91cyBSYWRpYW5jZSIpCiNnZ1JlZmxhbnQxNDE4CgojV3N0YWJpbGl0eTE0MTggPC0gZ3JpZC5hcnJhbmdlKGdnUmFkMTQxOCxnZ1JlZmwwMTQxOCxnZ1JlZmxhbnQxNDE4KQojZ2dzYXZlKFdzdGFiaWxpdHkxNDE4LCBmaWxlPSJXc3RhYmlsaXR5MTQxOC5wZGYiLCB3aWR0aD0xMCwgaGVpZ2h0PTE0LCB0b3A9dGV4dEdyb2IoIlN0YWJpbGl0eSBvZiBSZWFkaW5ncyAoV2hpdGUgUmVmZXJlbmNlKSIpKQpXc3RhYmlsaXR5MTQxOCA8LSBncmlkLmFycmFuZ2UoZ2dSZWZsMDE0MTgsZ2dSZWZsYW50MTQxOCkKYGBgCiMjIDIuIFN0YWJpbGl0eSBvZiBTdGFuZGFyZCBSZWZlcmVuY2Ugc3BlY3RyYSAoMjAyMzAxMDIgZGF0YSkKCkluaXRpYWwgYW5kIGZpbmFsICgxMzgnIGxhdGVyKSBSZWZsZWN0YW5jZSBtZWFzdXJlbWVudHMgb2YgdGhlIFN0YW5kYXJkIHJlZmVyZW5jZSBhcmUgc2xpZ2h0bHkgc2hpZnRlZCwgZGVzcGl0ZSBoYXZpbmcgbWVhc3VyZWQgdGhlIHdoaXRlIHJlZmVyZW5jZSBpbW1lZGlhdGVseSBiZWZvcmUgdGhlIHRhcmdldC4gSW50ZWdyYXRpb24gdGltZXMgKElUKSB3ZXJlIHNldCB0byB0aG9zZSBjYWxjdWxhdGVkIGFzIG9wdGltYSBieSBTcFI6IDQ2IG1zIChTVFMpIGFuZCAxNSBtcyAoTklSUVVFU1QpLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQpmZGlyIDwtICIuLi90aW1lX21lYXN1cmVzMjAyMzAxMDIiCmxpc3RhIDwtIGRhdGEuZnJhbWUoZm5hbWU9bGlzdC5maWxlcyhmZGlyLCBwYXR0PWdsb2IycngoIioudHh0IikpLCBmZGlyPWZkaXIpWy0oMToxMjEpLF0gI2V4Y2x1ZGUgYXV0by1jYXB0dXJlIHJlYWRpbmdzCiNsaXN0YSA8LSBsaXN0YVstMSxdCgojSW5pdGFsIGFuZCBmaW5hbCAoMTM4JyBsYXRlcikgUmVmbGVjdGFuY2UgbWVhc3VyZW1lbnRzIHdpdGggSVQgNDYgbXMgKFNUUykgYW5kIDE1IG1zIChOSVJRVUVTVCkKbGlzdGFzZWwgPC0gbGlzdGFbMToyLF0Kc2VsUmVmcyA8LSBzZWxTZXNzaW9uUmVmcyhzZWxmbGlzdD1saXN0YXNlbCkKc2VsUmVmcyRzYW1wbGVbc2VsUmVmcyRzYW1wbGU9PSJSZWZfMSJdIDwtICJJbml0aWFsIiAKc2VsUmVmcyRzYW1wbGVbc2VsUmVmcyRzYW1wbGU9PSJSZWZfMiJdIDwtICJGaW5hbCIgCmdnUmVmUmVmbCA8LSBnZ3Bsb3QoZGF0YT1zZWxSZWZzLGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0xLCBzaXplPTAuNSxhZXMoZ3JvdXA9c2FtcGxlLGNvbG9yPXNhbXBsZSkpICsKICBnZW9tX2xpbmUgKGFscGhhPTEsIGxpbmV3aWR0aD0wLjUsIGFlcyhncm91cD1zYW1wbGUsIGNvbG9yPXNhbXBsZSkpICsKICAjZ2VvbV9saW5lKGRhdGE9UmFkY29udFtSYWRjb250JFNhbXBsZT09MixdKSArCiAgI2dlb21fbGluZShkYXRhPVJlZk1DQUEwMSwgYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZSksY29sPSJncmV5IikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9MTQxOC41ODIwKSxsaW5ldHlwZT00KSArCiAgeGxpbShjKDQwMCwgMjYwMCkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICBnZ3RpdGxlKCJSZWZsZWN0YW5jZSAoU3RhbmRhcmQgVGFyZ2V0KSIsIHN1YnRpdGxlID0gIkluaXRpYWwgYW5kIGZpbmFsIHJlYWRpbmdzIChJVDogNDYgbXMsIDE1IG1zKSIpCiNnZ3Bsb3RseShnZ1JlZlJlZmwpCmdncGxvdGx5KGdnUmVmUmVmbCkgICU+JQogIGxheW91dChsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC43LCB5ID0gMC4xKSkKYGBgCgpJbml0aWFsIGFuZCBGaW5hbCBSYWRpYW5jZSBhbmQgUmVmbGVjdGFuY2Ugc3BlY3RyYSBhcmUgbGluZWFybHkgcmVsYXRlZCB3aXRoIHNsb3BlcyBjbG9zZSB0byAxLiBSZWxhdGl2ZWx5IGxhcmdlIGludGVyY2VwdCB2YWx1ZXMgaW5kaWNhdGUgYWdhaW4gYSBkcmlmdCBpbiBSYWRpYW5jZSwgd2hpY2ggaXMgcmVkdWNlZCAoYnV0IG5vdCBlbGltaW5hdGVkKSBpbiBSZWZsZWN0YW5jZSBtZWFzdXJlbWVudHM6IDAuMDA2IGZvciB0aGUgU1RTLUlUICg0MDAtOTAwIG5tKSBhbmQgLTAuMDcgZm9yIHRoZSBOSVJRVUVTVCAoOTUwLTI2MDAgbm0pLiAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsICBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Nn0KZCA8LSBzZWxSZWZzWyxjKDE6NildCmRzIDwtIHBseXI6OmRkcGx5KGQsIGMoInNhbXBsZSIsIldhdmVsZW5ndGgiKSwgc3VtbWFyaXNlLCAKICAgICAgICAgICAgICAgICAgUmFkaWFuY2UgPSAoUmFkaWFuY2UtRGFyayksCiAgICAgICAgICAgICAgICAgIFdSYWRpYW5jZSA9IFdoaXRlUmFkLAogICAgICAgICAgICAgICAgICBSZWZsZWN0YW5jZSA9IFJlZmxlY3RhbmNlKQoKZHN3IDwtIGRhdGEuZnJhbWUoV2F2ZWxlbmd0aD1kcyRXYXZlbGVuZ3RoW2RzJHNhbXBsZT09IkluaXRpYWwiXSwKICAgICAgICAgICAgICAgICAgSW5pdGlhbFJlZmw9ZHMkUmVmbGVjdGFuY2VbZHMkc2FtcGxlPT0iSW5pdGlhbCJdLCBGaW5hbFJlZmw9ZHMkUmVmbGVjdGFuY2VbZHMkc2FtcGxlPT0iRmluYWwiXSwKICAgICAgICAgICAgICAgICAgSW5pdGlhbD1kcyRSYWRpYW5jZVtkcyRzYW1wbGU9PSJJbml0aWFsIl0sIEZpbmFsPWRzJFJhZGlhbmNlW2RzJHNhbXBsZT09IkZpbmFsIl0sCiAgICAgICAgICAgICAgICAgIFdJbml0aWFsPWRzJFdSYWRpYW5jZVtkcyRzYW1wbGU9PSJJbml0aWFsIl0sIFdGaW5hbD1kcyRXUmFkaWFuY2VbZHMkc2FtcGxlPT0iRmluYWwiXSkKZHN3JEluc3RydW1lbnQgPC0gIlNUUy1JVCIKZHN3JEluc3RydW1lbnRbZHN3JFdhdmVsZW5ndGg+ODUwXSA8LSAiTklSUVVFU1QiCgpsbTJSYWQxIDwtIGxtb2RlbDIoRmluYWx+SW5pdGlhbCwgZGF0YT1kc3dbZHN3JEluc3RydW1lbnQ9PSJTVFMtSVQiLF0pCmxtMlJhZDIgPC0gbG1vZGVsMihGaW5hbH5Jbml0aWFsLCBkYXRhPWRzd1tkc3ckSW5zdHJ1bWVudD09Ik5JUlFVRVNUIixdKQojbG0yUmFkMSRyZWdyZXNzaW9uLnJlc3VsdHNbMixdCiNsbTJSYWQyJHJlZ3Jlc3Npb24ucmVzdWx0c1syLF0KCmxtMlcxIDwtIGxtb2RlbDIoV0ZpbmFsfldJbml0aWFsLCBkYXRhPWRzd1tkc3ckSW5zdHJ1bWVudD09IlNUUy1JVCIsXSkKbG0yVzIgPC0gbG1vZGVsMihXRmluYWx+V0luaXRpYWwsIGRhdGE9ZHN3W2RzdyRJbnN0cnVtZW50PT0iTklSUVVFU1QiLF0pCiNsbTJXMSRyZWdyZXNzaW9uLnJlc3VsdHNbMixdCiNsbTJXMiRyZWdyZXNzaW9uLnJlc3VsdHNbMixdCgpsbTJSZWZsMSA8LSBsbW9kZWwyKEZpbmFsUmVmbH5Jbml0aWFsUmVmbCwgZGF0YT1kc3dbZHN3JEluc3RydW1lbnQ9PSJTVFMtSVQiLF0pCmxtMlJlZmwyIDwtIGxtb2RlbDIoRmluYWxSZWZsfkluaXRpYWxSZWZsLCBkYXRhPWRzd1tkc3ckSW5zdHJ1bWVudD09Ik5JUlFVRVNUIixdKQojbG0yUmVmbDEkcmVncmVzc2lvbi5yZXN1bHRzWzIsXQojbG0yUmVmbDIkcmVncmVzc2lvbi5yZXN1bHRzWzIsXQoKYSA8LSByYmluZCgKICBsbTJXMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyOjNdLAogIGxtMlcyJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDI6M10sCiAgbG0yUmFkMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyOjNdLAogIGxtMlJhZDIkcmVncmVzc2lvbi5yZXN1bHRzWzIsMjozXSwKICBsbTJSZWZsMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyOjNdLAogIGxtMlJlZmwyJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDI6M10pCmEkSW5zdHJ1bWVudCA8LSByZXAoYygiU1RTLUlUIiwgIk5JUlFVRVNUIiksMykKYSRUYXJnZXQgPC0gYyhyZXAoIlciLDIpLCByZXAoIlN0ZCIsNCkpCmEkTWFnbml0dWRlIDwtIGMocmVwKCJSYWRpYW5jZSIsNCksIHJlcCgiUmVmbGVjdGFuY2UiLDIpKQphIDwtIGFbLGMoNCw1LDMsMSwyKV0Kcm93bmFtZXMoYSkgPC0gTlVMTAoKCmdnV1JhZCA8LSBnZ3Bsb3QoZGF0YT1kc3csIGFlcyh4PVdJbml0aWFsLCB5PVdGaW5hbCxjb2xvcj1JbnN0cnVtZW50KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdD1sbTJXMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyXSwgc2xvcGU9bG0yVzEkcmVncmVzc2lvbi5yZXN1bHRzWzIsM10pKSArCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdD1sbTJXMiRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyXSwgc2xvcGU9bG0yVzIkcmVncmVzc2lvbi5yZXN1bHRzWzIsM10pKSArCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdD0wLCBzbG9wZT0xKSwgbGluZXR5cGU9NCkgKwogIHhsYWIoIlJhZGlhbmNlIChJbml0aWFsIG1lYXN1cmVtZW50KSIpICsgIHlsYWIoIlJhZGlhbmNlIChGaW5hbCBtZWFzdXJlbWVudCkiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjg1LC4xNSksIGFzcGVjdC5yYXRpbz0xKSArIAogIGdndGl0bGUoIldoaXRlIFJlZmVyZW5jZSIpIApnZ1JhZCA8LSBnZ3Bsb3QoZGF0YT1kc3csIGFlcyh4PUluaXRpYWwsIHk9RmluYWwsY29sb3I9SW5zdHJ1bWVudCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQ9bG0yUmFkMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyXSwgc2xvcGU9bG0yUmFkMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwzXSkpICsKICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0PWxtMlJhZDIkcmVncmVzc2lvbi5yZXN1bHRzWzIsMl0sIHNsb3BlPWxtMlJhZDIkcmVncmVzc2lvbi5yZXN1bHRzWzIsM10pKSArCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdD0wLCBzbG9wZT0xKSwgbGluZXR5cGU9NCkgKwogIHhsYWIoIlJhZGlhbmNlIChJbml0aWFsIG1lYXN1cmVtZW50KSIpICsgIHlsYWIoIlJhZGlhbmNlIChGaW5hbCBtZWFzdXJlbWVudCkiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjg1LC4xNSksIGFzcGVjdC5yYXRpbz0xKSArCiAgZ2d0aXRsZSgiU3RhbmRhcmQgUmVmZXJlbmNlIikKZ2dSZWZsIDwtIGdncGxvdChkYXRhPWRzdywgYWVzKHg9SW5pdGlhbFJlZmwsIHk9RmluYWxSZWZsLGNvbG9yPUluc3RydW1lbnQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0PWxtMlJlZmwxJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDJdLCBzbG9wZT1sbTJSZWZsMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwzXSkpICsKICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0PWxtMlJlZmwyJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDJdLCBzbG9wZT1sbTJSZWZsMiRyZWdyZXNzaW9uLnJlc3VsdHNbMiwzXSkpICsKICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0PTAsIHNsb3BlPTEpLCBsaW5ldHlwZT00KSsKICB4bGFiKCJSZWZsZWN0YW5jZSAoSW5pdGlhbCBtZWFzdXJlbWVudCkiKSArICB5bGFiKCJSZWZsZWN0YW5jZSAoRmluYWwgbWVhc3VyZW1lbnQpIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC44NSwuMTUpLCBhc3BlY3QucmF0aW89MSkgKwogIGdndGl0bGUoIlN0YW5kYXJkIFJlZmVyZW5jZSIpCmdyaWQuYXJyYW5nZShnZ1dSYWQsIGdnUmFkLCAgbnJvdz0xKQpwYW5kZXI6OnBhbmRlcihhcnJhbmdlKGFbMTo0LF0pKSNkcGx5cjo6YXJyYW5nZSByZXR1cm5zIHRoZSBkZiB3aXRob3V0IHJvd25hbWVzCmdnUmVmbApwYW5kZXI6OnBhbmRlcihhcnJhbmdlKGFbNTo2LF0pKQpgYGAK