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")

3. Other potential sources of variability (20230110 data)

3.1 Size of White reference (20230123 data)

Given the similar size of the small white reference () and the probe, we conjectured that some variability at positioning the white reference under the probe could imply a variable part of the black casing interfering the white reading. Nevertheless, results show that while there is a notorious difference in the mean because the larger White reference () is not as bright as the small one (see SpR_Wcomparison_np.Rmd), the standard deviations are very similar.

#with/without monitor
fdir <- "../Test20230110"
lista <- data.frame(fname=list.files(fdir, patt=glob2rx("*.txt")), fdir=fdir)[7:16,]
selRefs <- selSessionRefs(selflist=lista)
selRefs$W <- selRefs$sample
selRefs$W <- plyr::mapvalues(selRefs$sample, from=unique(selRefs$sample), to=rep(c("Big W", "Small W"),c(5,5) ))

d <- selRefs[,c(1:6,15)]
ds <- plyr::ddply(d, c("W","Wavelength"), summarise, 
                  Reflectance.m = mean(Reflectance), Reflectance.sd = sd(Reflectance),
                  Radiance.m = mean(Radiance-Dark), Radiance.sd = sd(Radiance-Dark),
                  WRadiance.m = mean(WhiteRad), WRadiance.sd = sd(WhiteRad))

# ggRefl <- ggplot(ds) +
#   geom_point(aes(x=Wavelength, y=Reflectance.m, color=W)) +
#   geom_line(aes(x=Wavelength, y=Reflectance.m+Reflectance.sd, color=W)) +
#   geom_line(aes(x=Wavelength, y=Reflectance.m-Reflectance.sd, color=W)) +
#   ylab("Reflectance (mean +/- sd)") +
#   ggtitle("Standard reference")
# ggRefl + xlim(c(1500, 2000))
# #+ylim(c(25000, 50000))
# 
# RadStd <- ggplot(ds) +
#   geom_point(aes(x=Wavelength, y=Radiance.m, color=W)) +
#   geom_line(aes(x=Wavelength, y=Radiance.m+Radiance.sd, color=W)) +
#   geom_line(aes(x=Wavelength, y=Radiance.m-Radiance.sd, color=W)) +
#   ylab("Radiance (averag +/- sd)") +
#   ggtitle("Standard reference")
# RadStd+xlim(c(1500, 2000))+ylim(c(25000, 50000))
 
 
RadW <- ggplot(ds) +
   geom_point(aes(x=Wavelength, y=WRadiance.m, color=W))+
   geom_line(aes(x=Wavelength, y=WRadiance.m + WRadiance.sd, color=W)) +
   geom_line(aes(x=Wavelength, y=WRadiance.m - WRadiance.sd, color=W)) +
   ylab("Radiance (averag +/- sd)") +
   ggtitle("White references")
RadW

RadW+xlim(c(1500, 2000))+ylim(c(30000, 50000))

# grid.arrange(RadStd, RadW, RadStd+xlim(c(1500, 2000))+ylim(c(25000, 50000)),  RadW+xlim(c(1500, 2000))+ylim(c(25000, 50000)))

3.2 Instrument

NOTE: the problem of the Reflectance factor for the Big W must be solved, otherwise Reflectance can be > 1

Two different units of the NIRQUEST spectrometer acquired similar spectra, including no improvement in the absorption at 1260 nm. SpR found different optimum IT for each unit (57 ms vs. 45 ms).

fdir <- "../Test20230110"
lista <- data.frame(fname=list.files(fdir, patt=glob2rx("*.txt")), fdir=fdir)[17:26,]
selRefs <- selSessionRefs(selflist=lista)
selRefs$Instrument <- plyr::mapvalues(selRefs$sample, from=unique(selRefs$sample), to=rep(c("GEO3BCN", "UAB"), c(5,5)))

ggRefRefl <- ggplot(data=selRefs,aes(x=Wavelength, y=Reflectance, label1=intT1, label2=intT2)) +
  geom_point(alpha=1, size=0.5,aes(group=sample,color=Instrument)) +
  geom_line (alpha=1, linewidth=0.5, aes(group=sample, color=Instrument)) +
  #geom_line(data=Radcont[Radcont$Sample==2,]) +
  #geom_line(data=RefMCAA01, aes(x=Wavelength, y=Reflectance),col="grey") +
  xlim(c(400, 2600)) +
  #theme(legend.position="bottom") +
  labs(color="") +
  ggtitle("Reflectance (Standard Target)", subtitle = "")
#ggRefRefl
ggplotly(ggRefRefl)  %>%
  layout(legend = list(orientation = "h", x = 0.4, y = 0.1))

Major axis regression among both NIRQUEST units resulted in a linear relationship with slope not significantly different to 1 and a very close to 0 intercept:

d <- selRefs[,c(1:6,15)]

ds <- plyr::ddply(d, c("Instrument","Wavelength"), summarise, 
                  Reflectance.m = mean(Reflectance), Reflectance.sd = sd(Reflectance),
                  Radiance.m = mean(Radiance-Dark), Radiance.sd = sd(Radiance-Dark),
                  WRadiance.m = mean(WhiteRad), WRadiance.sd = sd(WhiteRad))
                  
dsw <- data.frame(Wavelength=ds$Wavelength[ds$Instrument=="GEO3BCN"],
                  GEO3BCN_Refl.m=ds$Reflectance.m[ds$Instrument=="GEO3BCN"],
                  UAB_Refl.m=ds$Reflectance.m[ds$Instrument=="UAB"])

lm2Refl1 <- lmodel2(UAB_Refl.m~GEO3BCN_Refl.m, data=dsw)

ggRefl <- ggplot(data=dsw, aes(x= GEO3BCN_Refl.m, y=UAB_Refl.m)) +
  geom_point() +
  geom_abline(aes(intercept=lm2Refl1$regression.results[2,2], slope=lm2Refl1$regression.results[2,3])) +
  geom_abline(aes(intercept=0, slope=1), linetype=4)+
  xlab("Reflectance (GEO3BCN NIRQUEST unit)") +  ylab("Reflectance (UAB NIRQUEST unit)") + 
  theme(legend.position = c(.85,.15), aspect.ratio=1) +
  ggtitle("Standard Reference (2 different NIRQUEST units)")
ggRefl

pander::pander(arrange(lm2Refl1$regression.results[2,2:3])) #

--------------------
 Intercept   Slope  
----------- --------
  0.00887    0.9975 
--------------------
pander::pander(arrange(lm2Refl1$confidence.intervals[2,2:5]))

-------------------------------------------------------------
 2.5%-Intercept   97.5%-Intercept   2.5%-Slope   97.5%-Slope 
---------------- ----------------- ------------ -------------
    0.002034          0.01566         0.9908        1.004    
-------------------------------------------------------------

3.3 Integration Time (20230102 data)

We analysed the effect of IT in NIRQUEST reflectance measurements, by varying IT around the optimum value as calculated by SpR, while keeping the IT of the STS-IT system constant at the optimum:

  • STS IT: 46 (optimum value as calculated by SpR software)
  • NIRQUEST IT: 16 (optimum), 6, 10, 11, 21, 26
fdir <- "../time_measures20230102"
lista <- data.frame(fname=list.files(fdir, patt=glob2rx("*.txt")), fdir=fdir)[-(1:121),] #exclude auto-capture readings
listasel2 <- lista[2:8,]
selRefs <- selSessionRefs(selflist=listasel2)
ggRefRefl <- ggplot(data=selRefs,aes(x=Wavelength, y=Reflectance)) +
  geom_point(alpha=1, size=0.5,aes(group=sample,color=intT2)) +
  geom_line (alpha=1, linewidth=0.5,aes(group=sample,color=intT2)) +
  #geom_line(data=Radcont[Radcont$Sample==2,]) +
  #geom_line(data=RefMCAA01, aes(x=Wavelength, y=Reflectance),col="grey" ) +
  xlim(c(400, 2600)) +
  ggtitle("Reflectance (Standard Target)", subtitle = "Initial and final reading (IT: 46 ms, 15 ms)")
#ggplotly(ggRefRefl + scale_fill_continuous_diverging(palette = "Purple-Green"))
ggplotly(ggRefRefl + scale_color_gradientn(colours = blue2green2red(7)))  %>%
  layout(legend = list(orientation = "h", x = 0.4, y = 0.1))
#21 and 26 clearly have too long an IT
#STS variabilty ~ NIRQUEST variability, despite the fact that IT in STS was kept constant (46 ms)

IT of 21 ms and 26 ms were clearly too long, but discarding these two values, the variability of NIRQUEST spectra (with variable IT) was close to that of STS Reflectance spectra, which were acquired with constant IT. This implies that fluctuations around the optimum IT are not translated into reflectance fluctuations as long as they are moderate, do not imply saturation or under-exposure, and the IT value is kept the same for the target and the white reference.

#note that values calculated with the large white reference are less variable.
#listasel3 <- lista[c(3,9:11),]
#selRefs <- selSessionRefs(selflist=listasel3)

#selRefs$sample <- plyr::mapvalues(selRefs$sample, from=c(paste0("Ref_", 1:4)), to=c("small_46_16","big_46_16","big_51_16","small_37_12_contact" ))
#selRefs$Reflectance[selRefs$sample=="big_46_16"] <- selRefs$Reflectance[selRefs$sample=="big_46_16"] * 0.8
#selRefs$Reflectance[selRefs$sample=="big_51_16"] <- selRefs$Reflectance[selRefs$sample=="big_51_16"] * 0.8
#ggRefRefl <- ggplot(data=selRefs) +
#  geom_point(aes(x=Wavelength, y=Reflectance, group=sample,color=sample), alpha=1, size=0.5) +
#  geom_line (aes(x=Wavelength, y=Reflectance, group=sample,color=sample), alpha=1, linewidth=0.5) +
#  geom_line(data=RefMCAA01, aes(x=Wavelength, y=Reflectance),col="grey" ) +
#  xlim(c(400, 2600)) +
#  ggtitle("Reflectance (Standard Target)", subtitle = "Initial and final reading (IT: 46 ms, 15 ms)")
#ggplotly(ggRefRefl)

3.4 Light from PC monitor

We tested the eventual effect of the light from the PC monitor, which light was always set to a minimum and oriented to the opposite direction of the measuring setup (and also note we were using a probe with its own light source). Results indicated no difference between having the PC monitor on/off during the measurements:

#with/without monitor
fdir <- "../Test20230110"
lista <- data.frame(fname=list.files(fdir, patt=glob2rx("*.txt")), fdir=fdir)[1:2,]
selRefs <- selSessionRefs(selflist=lista)
selRefs$monitor <- selRefs$sample
selRefs$monitor[selRefs$sample=="Ref_1"] <- "ON" 
selRefs$monitor[selRefs$sample=="Ref_2"] <- "OFF"

d <- selRefs[,c(1:6, 15)]
ds <- plyr::ddply(d, c("monitor","Wavelength"), summarise, 
                  Reflectance.m = mean(Reflectance), Reflectance.sd = sd(Reflectance),
                  Radiance.m = mean(Radiance-Dark), Radiance.sd = sd(Radiance-Dark),
                  WRadiance.m = mean(WhiteRad), WRadiance.sd = sd(WhiteRad))
                  
dsw <- data.frame(Wavelength=ds$Wavelength[ds$monitor=="ON"],
                  ON_Refl.m=ds$Reflectance.m[ds$monitor=="ON"],
                  OFF_Refl.m=ds$Reflectance.m[ds$monitor=="OFF"])

lm2Refl1 <- lmodel2(OFF_Refl.m ~ ON_Refl.m, data=dsw)

pander(arrange(lm2Refl1$regression.results[2,2:3]))

-------------------
 Intercept   Slope 
----------- -------
 0.0009625     1   
-------------------
pander(arrange(lm2Refl1$confidence.intervals[2,-1]))

-------------------------------------------------------------
 2.5%-Intercept   97.5%-Intercept   2.5%-Slope   97.5%-Slope 
---------------- ----------------- ------------ -------------
    -0.00109          0.00301         0.9979        1.002    
-------------------------------------------------------------
ggRefRefl <- ggplot(data=selRefs,aes(x=Wavelength, y=Reflectance)) +
  geom_point(alpha=1, size=0.5,aes(group=sample,color=monitor)) +
  geom_line (alpha=1, linewidth=0.5, aes(group=sample, color=monitor)) +
  #geom_line(data=Radcont[Radcont$Sample==2,]) +
  #geom_line(data=RefMCAA01, aes(x=Wavelength, y=Reflectance),col="grey") +
  xlim(c(400, 2600)) +
  theme(legend.position=c(0.9, 0.1)) +
  labs(color="") +
  ggtitle("Reflectance (Standard Target)", subtitle = "(IT: 53 ms, 17 ms)")
ggRefRefl

3.5 Holder (20230130 Data)

In order to protect the white reference, we take the white reading with the reference within a black holder that attaches to the probe leaving a constant distance of 5 mm from the probe to the reference. We carried out the following measurements:

Table 1 Setup of measurements of white and target (standard) references
spectrum name White holder White distance Target holder Target distance
contact No 0.0 No 0.0
holder0 No 5.0 No 5.0
holder1 Yes 5.0 Yes 10.0
holder2 Yes 5.0 No 10.0
holder3 Yes 5.0 No 5.0
field Yes 5.0 No 0.0

Even such a short distance as 5 mm has a significant impact in the Radiance measurements of both the white and the standard references (compare “contact” and “holder0” in the figures). In the case of the white reference, the holder itself has some influence in the reading, probably because some light is actually absorbed: radiance spectra acquired with the holder (spectra “holder1” to “holder3”) are darker than those acquired without the holder at the same distance (5 mm).

fdir <- "../Test20230130"
lista <- data.frame(fname=list.files(fdir, patt=glob2rx("*.txt")), fdir=fdir)
#lista[17,1]
#file.rename(file.path(fdir, lista[17,1]),file.path(fdir, "20180201_130532_017_StdRef_adapt3_spectrum.txt")) #not following naming convention; only once
lista <- data.frame(fname=list.files(fdir, patt=glob2rx("*.txt")), fdir=fdir)
#lista
a <- strsplit(lista[,1], "_")
a <- sapply(a, function(x){x[5]})
a[a=="mind"] <- "contact"
a[a=="adapt4"] <- "holder0"
a <- sub("adapt","holder",a)
selRefs <- selSessionRefs(selflist=lista)
selRefs$holder <- selRefs$sample
selRefs$holder <- plyr::mapvalues(selRefs$holder, from=unique(selRefs$sample), to=a)
Wavelength2 <- selRefs$Wavelength[selRefs$holder=="holder3"]
WhiteRad2 <- selRefs$WhiteRad[selRefs$holder=="holder3"]
Reflectance2 <- (selRefs$Radiance-selRefs$Dark)[selRefs$holder=="contact"]/WhiteRad2
Reflectance <- selRefs$Reflectance[selRefs$holder=="contact"]

ggRefWRad <- ggplot(data=selRefs,aes(x=Wavelength, y=WhiteRad)) +
  geom_point(alpha=1, size=0.5,aes(group=sample,color=holder)) +
  geom_line (alpha=1, linewidth=0.5,aes(group=sample,color=holder)) +
  xlim(c(400, 2600)) + ylim(0, 60000) + ylab("Radiance")
  #ggtitle("Radiance (White reference)", subtitle = "")
ggRefRad <- ggplot(data=selRefs,aes(x=Wavelength, y=Radiance-Dark)) +
  geom_point(alpha=1, size=0.5,aes(group=sample,color=holder)) +
  geom_line (alpha=1, linewidth=0.5,aes(group=sample,color=holder)) +
  xlim(c(400, 2600)) + ylim(0, 60000) + ylab("Radiance")
  #ggtitle("Radiance (Standard Target)", subtitle = "")
ggRefRefl <- ggplot(data=selRefs,aes(x=Wavelength, y=Reflectance)) +
  geom_point(alpha=1, size=0.5,aes(group=sample,color=holder)) +
  geom_line (alpha=1, linewidth=0.5,aes(group=sample,color=holder)) +
  #geom_line(data=Radcont[Radcont$Sample==2,]) +
  geom_line(data=RefMCAA01, aes(x=Wavelength, y=Reflectance),col="grey" ) +
  xlim(c(400, 2600)) + 
  theme(legend.position=c(0.92, 0.2)) +
  ggtitle("Reflectance of Standard Reference", subtitle = "")
#d2 <- data.frame(Wavelength=Wavelength2, Reflectance=Reflectance2)
d2 <- data.frame(Wavelength=Wavelength2, Reflectance=c(Reflectance,Reflectance2), 
                 holder=c(rep("contact", length(Wavelength2)),
                          rep("field",   length(Wavelength2))))
RefMCAA01$sample <- "Certification"
x <- RefMCAA01[,c(1,3,4)]
names(x)[3] <- "holder"
d2 <- rbind(d2,x)                                                     
ggRefRefl2 <- ggplot(data=d2,
                     aes(x=Wavelength, y=Reflectance, color=holder)) +
  geom_point(alpha=1, size=0.5) +
  geom_line (alpha=1, linewidth=0.5) +
  #geom_line(data=Radcont[Radcont$Sample==2,]) +
  geom_line(data=RefMCAA01, aes(x=Wavelength, y=Reflectance),col="grey" ) +
  xlim(c(400, 2600)) +
  ggtitle("Reflectance of Standard Reference", subtitle = "")

#ggRefRefl 
#+ geom_point(data=d2,alpha=1, size=0.5) + geom_line (data=d2,alpha=1, linewidth=0.5)
#ggRefRefl2

#subplot() does not display ggtitle() info:
subplot(style(ggplotly(ggRefWRad), showlegend=FALSE), ggplotly(ggRefRad), nrows = 2, titleY = TRUE, titleX = TRUE, margin = 0.1 ) %>%
  #layout(legend = list(title="", orientation = "h", x = 0.15, y = 0.38),
  layout(legend = list(title="", orientation = "v", x = 0.05, y = 0.98),
         annotations=list(
           list(
              x = 0.1,  
              y = 1.0,  
              text = "White reference",  
              xref = "paper",  
              yref = "paper",  
              xanchor = "center",  
              yanchor = "bottom",  
              showarrow = FALSE),
            list(
              x = 0.1,  
              y = 0.40,  
              text = "Standard reference",  
              xref = "paper",  
              yref = "paper",  
              xanchor = "center",  
              yanchor = "bottom",  
              showarrow = FALSE)))

Radiance spectra “holder1” and “holder2” were acquired at longer a distance (1 cm) of the Standard reference, and were too dark to actually record the spectral features in their respective Reflectance spectra. This fact highlights the importance of keeping the probe in contact with (or at least closer than 5 mm to) the target.

#ggplotly(ggRefWRad)
#ggplotly(ggRefRad)
ggplotly(ggRefRefl)  %>%
  layout(legend = list(title="", orientation = "h", x = 0.1, y = 0.05))

Field measurements introduce a concern. The common procedure in the field is to keep the holder on for the White reference (as a mean to protect it, which implies 5mm distance from the probe to the white reference). The probe, instead, is kept in contact with the target (ensuring a constant 5 mm distance from probe to target is impossible by freehand in the field). Therefore, the white reference and the target are not acquired with identical probe-to-target distance. Replicating this procedure in the lab results on the reflectance spectrum “field”, which is clearly shifted upwards: target radiance is measured in contact but white radiance is measured at 5 mm. While no natural target is as bright as the Standard Referenc (thus Reflectance reading > 1 as in here are highly unlikely) the offset is too high and we should modify the holder to keep a distance < 5 mm.

ggplotly(ggRefRefl2)  %>%
  layout(legend = list(title="", orientation = "h", x = 0.4, y = 0.05))
d3 <- data.frame(Wavelength=selRefs$Wavelength[selRefs$holder=="holder3"],
                 WhiteRadContact = selRefs$WhiteRad[selRefs$holder=="contact"],
                 WhiteRadHolder0 = selRefs$WhiteRad[selRefs$holder=="holder0"],
                 WhiteRadHolder3 = selRefs$WhiteRad[selRefs$holder=="holder3"])
d3$Instrument <- "STS-IT"
d3$Instrument[dsw$Wavelength>850] <- "NIRQUEST"

lm2WRad1a <- lmodel2(WhiteRadHolder0 ~ WhiteRadContact, data=d3[d3$Instrument=="STS-IT",])
lm2WRad1b <- lmodel2(WhiteRadHolder0 ~ WhiteRadContact, data=d3[d3$Instrument=="NIRQUEST",])
lm2WRadH3a <- lmodel2(WhiteRadHolder3 ~ WhiteRadContact, data=d3[d3$Instrument=="STS-IT",])
lm2WRadH3b <- lmodel2(WhiteRadHolder3 ~ WhiteRadContact, data=d3[d3$Instrument=="NIRQUEST",])

gglm2H0 <- ggplot(data=d3[d3$Instrument=="STS-IT",], aes(label=Wavelength)) +
  geom_point(aes(x=WhiteRadContact, y=WhiteRadHolder0, color=Instrument),alpha=0.5) +
  geom_abline(aes(intercept=lm2WRad1a$regression.results[2,2], slope=lm2WRad1a$regression.results[2,3])) +
  geom_abline(aes(intercept=lm2WRad1b$regression.results[2,2], slope=lm2WRad1b$regression.results[2,3])) +
  geom_abline(aes(intercept=0, slope=1), linetype=4) +
  #xlim(c(0,3000)) + ylim(c(0,3000)) +
  xlab("Radiance (contact)") +  ylab("Radiance (5 mm)") + 
  theme(legend.position = c(.8,.15), aspect.ratio=1) + 
  ggtitle("White Reference") 
gglm2H3 <- ggplot(data=d3) +
  geom_point(aes(x=WhiteRadContact, y=WhiteRadHolder3, color=Instrument)) +
  geom_abline(aes(intercept=lm2WRadH3a$regression.results[2,2], slope=lm2WRadH3a$regression.results[2,3])) +
  geom_abline(aes(intercept=lm2WRadH3b$regression.results[2,2], slope=lm2WRadH3b$regression.results[2,3])) +
  geom_abline(aes(intercept=0, slope=1), linetype=4) +
  xlim(c(0,3000)) + ylim(c(0,3000)) +
  xlab("Radiance (contact)") +  ylab("Radiance (5 mm holder on)") + 
  theme(legend.position = c(.8,.15), aspect.ratio=1) + 
  ggtitle("White Reference") 
gglm2H3H0 <- ggplot(data=d3) +
  geom_point(aes(x=WhiteRadHolder0, y=WhiteRadHolder3, color=Instrument)) +
  #geom_abline(aes(intercept=lm2WRadH3a$regression.results[2,2], slope=lm2WRadH3a$regression.results[2,3])) +
  #geom_abline(aes(intercept=lm2WRadH3b$regression.results[2,2], slope=lm2WRadH3b$regression.results[2,3])) +
  geom_abline(aes(intercept=0, slope=1), linetype=4) +
  xlim(c(0,3000)) + ylim(c(0,3000)) +
  xlab("Radiance (5 mm)") +  ylab("Radiance (5 mm holder on)") + 
  theme(legend.position = c(.8,.15), aspect.ratio=1) + 
  ggtitle("White Reference") 

#grid.arrange(gglm2H0, gglm2H3, gglm2H3H0, ncol=3)

TBD

  • spectra of holder material
  • plot Wcontact vs W5mm holder0, and vs. W holder3
  • a full analysis of distance effect (from 5 mm to 5cm)
  • illuminate with ASD bulb

5. Conclusions

LS0tCnRpdGxlOiAiT3RoZXIgcG90ZW50aWFsIHNvdXJjZXMgb2YgdmFyaWFiaWxpdHkgb2YgU3BlY3Ryb1Jhc3Agc3BlY3RyYSAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBmaWdfY2FwdGlvbjogVFJVRQotLS0KCi0gICBbQWd1c3Rpbi5Mb2JvXEBnZW8zYmNuLmNzaWMuZXNdKG1haWx0bzpBZ3VzdGluLkxvYm9AZ2VvM2Jjbi5jc2ljLmVzKXsuZW1haWx9Ci0gICAyMDIyMTIyMiwgMjAyMzAxMDMsIDIwMjMwMTA5LCAyMDIzMDIwNgoKKkNsaWNrIG9uICJDb2RlIiBzeW1ib2xzIHRvIHVuZm9sZCBjb2RlIChmb2xkZWQgYnkgZGVmYXVsdCkuKgoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnJlcXVpcmUoZ2dwbG90MikKcmVxdWlyZShncmlkKQpyZXF1aXJlKGdyaWRFeHRyYSkKcmVxdWlyZShnZ2FuaW1hdGUpCnJlcXVpcmUocGxvdGx5KQpyZXF1aXJlKGx1YnJpZGF0ZSkKcmVxdWlyZShjb2xvclJhbXBzKQpyZXF1aXJlKGxtb2RlbDIpCnJlcXVpcmUoYnJvb20pCnJlcXVpcmUocGFuZGVyKQpzb3VyY2UoInNlbFNlc3Npb25SZWZzLlIiKQojQ2VydGlmaWVkCmxvYWQoIi9ob21lL2Fsb2JvL293bmNsb3VkUlNwZWN0L1JTcGVjdC9SZWZNQ0FBMDEucmRhIikKI2xvYWQoIkM6L1VzZXJzL1NwZWNpbS9vd25DbG91ZC9SU3BlY3QvUmVmTUNBQTAxLnJkYSIpCmBgYAoKIyMgMy4gT3RoZXIgcG90ZW50aWFsIHNvdXJjZXMgb2YgdmFyaWFiaWxpdHkgKDIwMjMwMTEwIGRhdGEpCgojIyMgMy4xIFNpemUgb2YgV2hpdGUgcmVmZXJlbmNlICgyMDIzMDEyMyBkYXRhKQoKR2l2ZW4gdGhlIHNpbWlsYXIgc2l6ZSBvZiB0aGUgc21hbGwgd2hpdGUgcmVmZXJlbmNlICgpIGFuZCB0aGUgcHJvYmUsIHdlIGNvbmplY3R1cmVkIHRoYXQgc29tZSB2YXJpYWJpbGl0eSBhdCBwb3NpdGlvbmluZyB0aGUgd2hpdGUgcmVmZXJlbmNlIHVuZGVyIHRoZSBwcm9iZSBjb3VsZCBpbXBseSBhIHZhcmlhYmxlIHBhcnQgb2YgdGhlIGJsYWNrIGNhc2luZyBpbnRlcmZlcmluZyB0aGUgd2hpdGUgcmVhZGluZy4gTmV2ZXJ0aGVsZXNzLCByZXN1bHRzIHNob3cgdGhhdCB3aGlsZSB0aGVyZSBpcyBhIG5vdG9yaW91cyBkaWZmZXJlbmNlIGluIHRoZSBtZWFuIGJlY2F1c2UgdGhlIGxhcmdlciBXaGl0ZSByZWZlcmVuY2UgKCkgaXMgbm90IGFzIGJyaWdodCBhcyB0aGUgc21hbGwgb25lIChzZWUgU3BSX1djb21wYXJpc29uX25wLlJtZCksIHRoZSBzdGFuZGFyZCBkZXZpYXRpb25zIGFyZSB2ZXJ5IHNpbWlsYXIuCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQojd2l0aC93aXRob3V0IG1vbml0b3IKZmRpciA8LSAiLi4vVGVzdDIwMjMwMTEwIgpsaXN0YSA8LSBkYXRhLmZyYW1lKGZuYW1lPWxpc3QuZmlsZXMoZmRpciwgcGF0dD1nbG9iMnJ4KCIqLnR4dCIpKSwgZmRpcj1mZGlyKVs3OjE2LF0Kc2VsUmVmcyA8LSBzZWxTZXNzaW9uUmVmcyhzZWxmbGlzdD1saXN0YSkKc2VsUmVmcyRXIDwtIHNlbFJlZnMkc2FtcGxlCnNlbFJlZnMkVyA8LSBwbHlyOjptYXB2YWx1ZXMoc2VsUmVmcyRzYW1wbGUsIGZyb209dW5pcXVlKHNlbFJlZnMkc2FtcGxlKSwgdG89cmVwKGMoIkJpZyBXIiwgIlNtYWxsIFciKSxjKDUsNSkgKSkKCmQgPC0gc2VsUmVmc1ssYygxOjYsMTUpXQpkcyA8LSBwbHlyOjpkZHBseShkLCBjKCJXIiwiV2F2ZWxlbmd0aCIpLCBzdW1tYXJpc2UsIAogICAgICAgICAgICAgICAgICBSZWZsZWN0YW5jZS5tID0gbWVhbihSZWZsZWN0YW5jZSksIFJlZmxlY3RhbmNlLnNkID0gc2QoUmVmbGVjdGFuY2UpLAogICAgICAgICAgICAgICAgICBSYWRpYW5jZS5tID0gbWVhbihSYWRpYW5jZS1EYXJrKSwgUmFkaWFuY2Uuc2QgPSBzZChSYWRpYW5jZS1EYXJrKSwKICAgICAgICAgICAgICAgICAgV1JhZGlhbmNlLm0gPSBtZWFuKFdoaXRlUmFkKSwgV1JhZGlhbmNlLnNkID0gc2QoV2hpdGVSYWQpKQoKIyBnZ1JlZmwgPC0gZ2dwbG90KGRzKSArCiMgICBnZW9tX3BvaW50KGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UubSwgY29sb3I9VykpICsKIyAgIGdlb21fbGluZShhZXMoeD1XYXZlbGVuZ3RoLCB5PVJlZmxlY3RhbmNlLm0rUmVmbGVjdGFuY2Uuc2QsIGNvbG9yPVcpKSArCiMgICBnZW9tX2xpbmUoYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZS5tLVJlZmxlY3RhbmNlLnNkLCBjb2xvcj1XKSkgKwojICAgeWxhYigiUmVmbGVjdGFuY2UgKG1lYW4gKy8tIHNkKSIpICsKIyAgIGdndGl0bGUoIlN0YW5kYXJkIHJlZmVyZW5jZSIpCiMgZ2dSZWZsICsgeGxpbShjKDE1MDAsIDIwMDApKQojICMreWxpbShjKDI1MDAwLCA1MDAwMCkpCiMgCiMgUmFkU3RkIDwtIGdncGxvdChkcykgKwojICAgZ2VvbV9wb2ludChhZXMoeD1XYXZlbGVuZ3RoLCB5PVJhZGlhbmNlLm0sIGNvbG9yPVcpKSArCiMgICBnZW9tX2xpbmUoYWVzKHg9V2F2ZWxlbmd0aCwgeT1SYWRpYW5jZS5tK1JhZGlhbmNlLnNkLCBjb2xvcj1XKSkgKwojICAgZ2VvbV9saW5lKGFlcyh4PVdhdmVsZW5ndGgsIHk9UmFkaWFuY2UubS1SYWRpYW5jZS5zZCwgY29sb3I9VykpICsKIyAgIHlsYWIoIlJhZGlhbmNlIChhdmVyYWcgKy8tIHNkKSIpICsKIyAgIGdndGl0bGUoIlN0YW5kYXJkIHJlZmVyZW5jZSIpCiMgUmFkU3RkK3hsaW0oYygxNTAwLCAyMDAwKSkreWxpbShjKDI1MDAwLCA1MDAwMCkpCiAKIApSYWRXIDwtIGdncGxvdChkcykgKwogICBnZW9tX3BvaW50KGFlcyh4PVdhdmVsZW5ndGgsIHk9V1JhZGlhbmNlLm0sIGNvbG9yPVcpKSsKICAgZ2VvbV9saW5lKGFlcyh4PVdhdmVsZW5ndGgsIHk9V1JhZGlhbmNlLm0gKyBXUmFkaWFuY2Uuc2QsIGNvbG9yPVcpKSArCiAgIGdlb21fbGluZShhZXMoeD1XYXZlbGVuZ3RoLCB5PVdSYWRpYW5jZS5tIC0gV1JhZGlhbmNlLnNkLCBjb2xvcj1XKSkgKwogICB5bGFiKCJSYWRpYW5jZSAoYXZlcmFnICsvLSBzZCkiKSArCiAgIGdndGl0bGUoIldoaXRlIHJlZmVyZW5jZXMiKQpSYWRXClJhZFcreGxpbShjKDE1MDAsIDIwMDApKSt5bGltKGMoMzAwMDAsIDUwMDAwKSkKIyBncmlkLmFycmFuZ2UoUmFkU3RkLCBSYWRXLCBSYWRTdGQreGxpbShjKDE1MDAsIDIwMDApKSt5bGltKGMoMjUwMDAsIDUwMDAwKSksICBSYWRXK3hsaW0oYygxNTAwLCAyMDAwKSkreWxpbShjKDI1MDAwLCA1MDAwMCkpKQpgYGAKCiMjIyAzLjIgSW5zdHJ1bWVudAoqTk9URTogdGhlIHByb2JsZW0gb2YgdGhlIFJlZmxlY3RhbmNlIGZhY3RvciBmb3IgdGhlIEJpZyBXIG11c3QgYmUgc29sdmVkLCBvdGhlcndpc2UgUmVmbGVjdGFuY2UgY2FuIGJlID4gMSoKClR3byBkaWZmZXJlbnQgdW5pdHMgb2YgdGhlIE5JUlFVRVNUIHNwZWN0cm9tZXRlciBhY3F1aXJlZCBzaW1pbGFyIHNwZWN0cmEsIGluY2x1ZGluZyBubyBpbXByb3ZlbWVudCBpbiB0aGUgYWJzb3JwdGlvbiBhdCAxMjYwIG5tLiBTcFIgZm91bmQgZGlmZmVyZW50IG9wdGltdW0gSVQgZm9yIGVhY2ggdW5pdCAoNTcgbXMgdnMuIDQ1IG1zKS4KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQpmZGlyIDwtICIuLi9UZXN0MjAyMzAxMTAiCmxpc3RhIDwtIGRhdGEuZnJhbWUoZm5hbWU9bGlzdC5maWxlcyhmZGlyLCBwYXR0PWdsb2IycngoIioudHh0IikpLCBmZGlyPWZkaXIpWzE3OjI2LF0Kc2VsUmVmcyA8LSBzZWxTZXNzaW9uUmVmcyhzZWxmbGlzdD1saXN0YSkKc2VsUmVmcyRJbnN0cnVtZW50IDwtIHBseXI6Om1hcHZhbHVlcyhzZWxSZWZzJHNhbXBsZSwgZnJvbT11bmlxdWUoc2VsUmVmcyRzYW1wbGUpLCB0bz1yZXAoYygiR0VPM0JDTiIsICJVQUIiKSwgYyg1LDUpKSkKCmdnUmVmUmVmbCA8LSBnZ3Bsb3QoZGF0YT1zZWxSZWZzLGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UsIGxhYmVsMT1pbnRUMSwgbGFiZWwyPWludFQyKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MSwgc2l6ZT0wLjUsYWVzKGdyb3VwPXNhbXBsZSxjb2xvcj1JbnN0cnVtZW50KSkgKwogIGdlb21fbGluZSAoYWxwaGE9MSwgbGluZXdpZHRoPTAuNSwgYWVzKGdyb3VwPXNhbXBsZSwgY29sb3I9SW5zdHJ1bWVudCkpICsKICAjZ2VvbV9saW5lKGRhdGE9UmFkY29udFtSYWRjb250JFNhbXBsZT09MixdKSArCiAgI2dlb21fbGluZShkYXRhPVJlZk1DQUEwMSwgYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZSksY29sPSJncmV5IikgKwogIHhsaW0oYyg0MDAsIDI2MDApKSArCiAgI3RoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogIGxhYnMoY29sb3I9IiIpICsKICBnZ3RpdGxlKCJSZWZsZWN0YW5jZSAoU3RhbmRhcmQgVGFyZ2V0KSIsIHN1YnRpdGxlID0gIiIpCiNnZ1JlZlJlZmwKZ2dwbG90bHkoZ2dSZWZSZWZsKSAgJT4lCiAgbGF5b3V0KGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAiaCIsIHggPSAwLjQsIHkgPSAwLjEpKQpgYGAKCk1ham9yIGF4aXMgcmVncmVzc2lvbiBhbW9uZyBib3RoIE5JUlFVRVNUIHVuaXRzIHJlc3VsdGVkIGluIGEgbGluZWFyIHJlbGF0aW9uc2hpcCB3aXRoIHNsb3BlIG5vdCBzaWduaWZpY2FudGx5IGRpZmZlcmVudCB0byAxIGFuZCBhIHZlcnkgY2xvc2UgdG8gMCBpbnRlcmNlcHQ6CgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCAgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTZ9CmQgPC0gc2VsUmVmc1ssYygxOjYsMTUpXQoKZHMgPC0gcGx5cjo6ZGRwbHkoZCwgYygiSW5zdHJ1bWVudCIsIldhdmVsZW5ndGgiKSwgc3VtbWFyaXNlLCAKICAgICAgICAgICAgICAgICAgUmVmbGVjdGFuY2UubSA9IG1lYW4oUmVmbGVjdGFuY2UpLCBSZWZsZWN0YW5jZS5zZCA9IHNkKFJlZmxlY3RhbmNlKSwKICAgICAgICAgICAgICAgICAgUmFkaWFuY2UubSA9IG1lYW4oUmFkaWFuY2UtRGFyayksIFJhZGlhbmNlLnNkID0gc2QoUmFkaWFuY2UtRGFyayksCiAgICAgICAgICAgICAgICAgIFdSYWRpYW5jZS5tID0gbWVhbihXaGl0ZVJhZCksIFdSYWRpYW5jZS5zZCA9IHNkKFdoaXRlUmFkKSkKICAgICAgICAgICAgICAgICAgCmRzdyA8LSBkYXRhLmZyYW1lKFdhdmVsZW5ndGg9ZHMkV2F2ZWxlbmd0aFtkcyRJbnN0cnVtZW50PT0iR0VPM0JDTiJdLAogICAgICAgICAgICAgICAgICBHRU8zQkNOX1JlZmwubT1kcyRSZWZsZWN0YW5jZS5tW2RzJEluc3RydW1lbnQ9PSJHRU8zQkNOIl0sCiAgICAgICAgICAgICAgICAgIFVBQl9SZWZsLm09ZHMkUmVmbGVjdGFuY2UubVtkcyRJbnN0cnVtZW50PT0iVUFCIl0pCgpsbTJSZWZsMSA8LSBsbW9kZWwyKFVBQl9SZWZsLm1+R0VPM0JDTl9SZWZsLm0sIGRhdGE9ZHN3KQoKZ2dSZWZsIDwtIGdncGxvdChkYXRhPWRzdywgYWVzKHg9IEdFTzNCQ05fUmVmbC5tLCB5PVVBQl9SZWZsLm0pKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0PWxtMlJlZmwxJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDJdLCBzbG9wZT1sbTJSZWZsMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwzXSkpICsKICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0PTAsIHNsb3BlPTEpLCBsaW5ldHlwZT00KSsKICB4bGFiKCJSZWZsZWN0YW5jZSAoR0VPM0JDTiBOSVJRVUVTVCB1bml0KSIpICsgIHlsYWIoIlJlZmxlY3RhbmNlIChVQUIgTklSUVVFU1QgdW5pdCkiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjg1LC4xNSksIGFzcGVjdC5yYXRpbz0xKSArCiAgZ2d0aXRsZSgiU3RhbmRhcmQgUmVmZXJlbmNlICgyIGRpZmZlcmVudCBOSVJRVUVTVCB1bml0cykiKQpnZ1JlZmwKcGFuZGVyOjpwYW5kZXIoYXJyYW5nZShsbTJSZWZsMSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyOjNdKSkgIwpwYW5kZXI6OnBhbmRlcihhcnJhbmdlKGxtMlJlZmwxJGNvbmZpZGVuY2UuaW50ZXJ2YWxzWzIsMjo1XSkpCgpgYGAgIAogIAoKCiMjIyAzLjMgSW50ZWdyYXRpb24gVGltZSAoMjAyMzAxMDIgZGF0YSkKCldlIGFuYWx5c2VkIHRoZSBlZmZlY3Qgb2YgSVQgaW4gTklSUVVFU1QgcmVmbGVjdGFuY2UgbWVhc3VyZW1lbnRzLCBieSB2YXJ5aW5nIElUIGFyb3VuZCB0aGUgb3B0aW11bSB2YWx1ZSBhcyBjYWxjdWxhdGVkIGJ5IFNwUiwgd2hpbGUga2VlcGluZyB0aGUgSVQgb2YgdGhlIFNUUy1JVCBzeXN0ZW0gY29uc3RhbnQgYXQgdGhlIG9wdGltdW06CgoqIFNUUyBJVDogICAgICA0NiAob3B0aW11bSB2YWx1ZSBhcyBjYWxjdWxhdGVkIGJ5IFNwUiBzb2Z0d2FyZSkKKiBOSVJRVUVTVCBJVDogMTYgKG9wdGltdW0pLCA2LCAxMCwgMTEsIDIxLCAyNgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQpmZGlyIDwtICIuLi90aW1lX21lYXN1cmVzMjAyMzAxMDIiCmxpc3RhIDwtIGRhdGEuZnJhbWUoZm5hbWU9bGlzdC5maWxlcyhmZGlyLCBwYXR0PWdsb2IycngoIioudHh0IikpLCBmZGlyPWZkaXIpWy0oMToxMjEpLF0gI2V4Y2x1ZGUgYXV0by1jYXB0dXJlIHJlYWRpbmdzCmxpc3Rhc2VsMiA8LSBsaXN0YVsyOjgsXQpzZWxSZWZzIDwtIHNlbFNlc3Npb25SZWZzKHNlbGZsaXN0PWxpc3Rhc2VsMikKZ2dSZWZSZWZsIDwtIGdncGxvdChkYXRhPXNlbFJlZnMsYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZSkpICsKICBnZW9tX3BvaW50KGFscGhhPTEsIHNpemU9MC41LGFlcyhncm91cD1zYW1wbGUsY29sb3I9aW50VDIpKSArCiAgZ2VvbV9saW5lIChhbHBoYT0xLCBsaW5ld2lkdGg9MC41LGFlcyhncm91cD1zYW1wbGUsY29sb3I9aW50VDIpKSArCiAgI2dlb21fbGluZShkYXRhPVJhZGNvbnRbUmFkY29udCRTYW1wbGU9PTIsXSkgKwogICNnZW9tX2xpbmUoZGF0YT1SZWZNQ0FBMDEsIGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UpLGNvbD0iZ3JleSIgKSArCiAgeGxpbShjKDQwMCwgMjYwMCkpICsKICBnZ3RpdGxlKCJSZWZsZWN0YW5jZSAoU3RhbmRhcmQgVGFyZ2V0KSIsIHN1YnRpdGxlID0gIkluaXRpYWwgYW5kIGZpbmFsIHJlYWRpbmcgKElUOiA0NiBtcywgMTUgbXMpIikKI2dncGxvdGx5KGdnUmVmUmVmbCArIHNjYWxlX2ZpbGxfY29udGludW91c19kaXZlcmdpbmcocGFsZXR0ZSA9ICJQdXJwbGUtR3JlZW4iKSkKZ2dwbG90bHkoZ2dSZWZSZWZsICsgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnMgPSBibHVlMmdyZWVuMnJlZCg3KSkpICAlPiUKICBsYXlvdXQobGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuNCwgeSA9IDAuMSkpCiMyMSBhbmQgMjYgY2xlYXJseSBoYXZlIHRvbyBsb25nIGFuIElUCiNTVFMgdmFyaWFiaWx0eSB+IE5JUlFVRVNUIHZhcmlhYmlsaXR5LCBkZXNwaXRlIHRoZSBmYWN0IHRoYXQgSVQgaW4gU1RTIHdhcyBrZXB0IGNvbnN0YW50ICg0NiBtcykKYGBgCgpJVCBvZiAyMSBtcyBhbmQgMjYgbXMgd2VyZSBjbGVhcmx5IHRvbyBsb25nLCBidXQgZGlzY2FyZGluZyB0aGVzZSB0d28gdmFsdWVzLCB0aGUgdmFyaWFiaWxpdHkgb2YgTklSUVVFU1Qgc3BlY3RyYSAod2l0aCB2YXJpYWJsZSBJVCkgd2FzIGNsb3NlIHRvIHRoYXQgb2YgU1RTIFJlZmxlY3RhbmNlIHNwZWN0cmEsIHdoaWNoIHdlcmUgYWNxdWlyZWQgd2l0aCBjb25zdGFudCBJVC4gVGhpcyBpbXBsaWVzIHRoYXQgZmx1Y3R1YXRpb25zIGFyb3VuZCB0aGUgb3B0aW11bSBJVCBhcmUgbm90IHRyYW5zbGF0ZWQgaW50byByZWZsZWN0YW5jZSBmbHVjdHVhdGlvbnMgYXMgbG9uZyBhcyB0aGV5IGFyZSBtb2RlcmF0ZSwgZG8gbm90IGltcGx5IHNhdHVyYXRpb24gb3IgdW5kZXItZXhwb3N1cmUsIGFuZCB0aGUgSVQgdmFsdWUgaXMga2VwdCB0aGUgc2FtZSBmb3IgdGhlIHRhcmdldCBhbmQgdGhlIHdoaXRlIHJlZmVyZW5jZS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsICBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0KI25vdGUgdGhhdCB2YWx1ZXMgY2FsY3VsYXRlZCB3aXRoIHRoZSBsYXJnZSB3aGl0ZSByZWZlcmVuY2UgYXJlIGxlc3MgdmFyaWFibGUuCiNsaXN0YXNlbDMgPC0gbGlzdGFbYygzLDk6MTEpLF0KI3NlbFJlZnMgPC0gc2VsU2Vzc2lvblJlZnMoc2VsZmxpc3Q9bGlzdGFzZWwzKQoKI3NlbFJlZnMkc2FtcGxlIDwtIHBseXI6Om1hcHZhbHVlcyhzZWxSZWZzJHNhbXBsZSwgZnJvbT1jKHBhc3RlMCgiUmVmXyIsIDE6NCkpLCB0bz1jKCJzbWFsbF80Nl8xNiIsImJpZ180Nl8xNiIsImJpZ181MV8xNiIsInNtYWxsXzM3XzEyX2NvbnRhY3QiICkpCiNzZWxSZWZzJFJlZmxlY3RhbmNlW3NlbFJlZnMkc2FtcGxlPT0iYmlnXzQ2XzE2Il0gPC0gc2VsUmVmcyRSZWZsZWN0YW5jZVtzZWxSZWZzJHNhbXBsZT09ImJpZ180Nl8xNiJdICogMC44CiNzZWxSZWZzJFJlZmxlY3RhbmNlW3NlbFJlZnMkc2FtcGxlPT0iYmlnXzUxXzE2Il0gPC0gc2VsUmVmcyRSZWZsZWN0YW5jZVtzZWxSZWZzJHNhbXBsZT09ImJpZ181MV8xNiJdICogMC44CiNnZ1JlZlJlZmwgPC0gZ2dwbG90KGRhdGE9c2VsUmVmcykgKwojICBnZW9tX3BvaW50KGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UsIGdyb3VwPXNhbXBsZSxjb2xvcj1zYW1wbGUpLCBhbHBoYT0xLCBzaXplPTAuNSkgKwojICBnZW9tX2xpbmUgKGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UsIGdyb3VwPXNhbXBsZSxjb2xvcj1zYW1wbGUpLCBhbHBoYT0xLCBsaW5ld2lkdGg9MC41KSArCiMgIGdlb21fbGluZShkYXRhPVJlZk1DQUEwMSwgYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZSksY29sPSJncmV5IiApICsKIyAgeGxpbShjKDQwMCwgMjYwMCkpICsKIyAgZ2d0aXRsZSgiUmVmbGVjdGFuY2UgKFN0YW5kYXJkIFRhcmdldCkiLCBzdWJ0aXRsZSA9ICJJbml0aWFsIGFuZCBmaW5hbCByZWFkaW5nIChJVDogNDYgbXMsIDE1IG1zKSIpCiNnZ3Bsb3RseShnZ1JlZlJlZmwpCmBgYAojIyMgMy40IExpZ2h0IGZyb20gUEMgbW9uaXRvcgoKV2UgdGVzdGVkIHRoZSBldmVudHVhbCBlZmZlY3Qgb2YgdGhlIGxpZ2h0IGZyb20gdGhlIFBDIG1vbml0b3IsIHdoaWNoIGxpZ2h0IHdhcyBhbHdheXMgc2V0IHRvIGEgbWluaW11bSBhbmQgb3JpZW50ZWQgdG8gdGhlIG9wcG9zaXRlIGRpcmVjdGlvbiBvZiB0aGUgbWVhc3VyaW5nIHNldHVwIChhbmQgYWxzbyBub3RlIHdlIHdlcmUgdXNpbmcgYSBwcm9iZSB3aXRoIGl0cyBvd24gbGlnaHQgc291cmNlKS4gUmVzdWx0cyBpbmRpY2F0ZWQgbm8gZGlmZmVyZW5jZSBiZXR3ZWVuIGhhdmluZyB0aGUgUEMgbW9uaXRvciBvbi9vZmYgZHVyaW5nIHRoZSBtZWFzdXJlbWVudHM6CgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSJob2xkIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTZ9CiN3aXRoL3dpdGhvdXQgbW9uaXRvcgpmZGlyIDwtICIuLi9UZXN0MjAyMzAxMTAiCmxpc3RhIDwtIGRhdGEuZnJhbWUoZm5hbWU9bGlzdC5maWxlcyhmZGlyLCBwYXR0PWdsb2IycngoIioudHh0IikpLCBmZGlyPWZkaXIpWzE6MixdCnNlbFJlZnMgPC0gc2VsU2Vzc2lvblJlZnMoc2VsZmxpc3Q9bGlzdGEpCnNlbFJlZnMkbW9uaXRvciA8LSBzZWxSZWZzJHNhbXBsZQpzZWxSZWZzJG1vbml0b3Jbc2VsUmVmcyRzYW1wbGU9PSJSZWZfMSJdIDwtICJPTiIgCnNlbFJlZnMkbW9uaXRvcltzZWxSZWZzJHNhbXBsZT09IlJlZl8yIl0gPC0gIk9GRiIKCmQgPC0gc2VsUmVmc1ssYygxOjYsIDE1KV0KZHMgPC0gcGx5cjo6ZGRwbHkoZCwgYygibW9uaXRvciIsIldhdmVsZW5ndGgiKSwgc3VtbWFyaXNlLCAKICAgICAgICAgICAgICAgICAgUmVmbGVjdGFuY2UubSA9IG1lYW4oUmVmbGVjdGFuY2UpLCBSZWZsZWN0YW5jZS5zZCA9IHNkKFJlZmxlY3RhbmNlKSwKICAgICAgICAgICAgICAgICAgUmFkaWFuY2UubSA9IG1lYW4oUmFkaWFuY2UtRGFyayksIFJhZGlhbmNlLnNkID0gc2QoUmFkaWFuY2UtRGFyayksCiAgICAgICAgICAgICAgICAgIFdSYWRpYW5jZS5tID0gbWVhbihXaGl0ZVJhZCksIFdSYWRpYW5jZS5zZCA9IHNkKFdoaXRlUmFkKSkKICAgICAgICAgICAgICAgICAgCmRzdyA8LSBkYXRhLmZyYW1lKFdhdmVsZW5ndGg9ZHMkV2F2ZWxlbmd0aFtkcyRtb25pdG9yPT0iT04iXSwKICAgICAgICAgICAgICAgICAgT05fUmVmbC5tPWRzJFJlZmxlY3RhbmNlLm1bZHMkbW9uaXRvcj09Ik9OIl0sCiAgICAgICAgICAgICAgICAgIE9GRl9SZWZsLm09ZHMkUmVmbGVjdGFuY2UubVtkcyRtb25pdG9yPT0iT0ZGIl0pCgpsbTJSZWZsMSA8LSBsbW9kZWwyKE9GRl9SZWZsLm0gfiBPTl9SZWZsLm0sIGRhdGE9ZHN3KQoKcGFuZGVyKGFycmFuZ2UobG0yUmVmbDEkcmVncmVzc2lvbi5yZXN1bHRzWzIsMjozXSkpCnBhbmRlcihhcnJhbmdlKGxtMlJlZmwxJGNvbmZpZGVuY2UuaW50ZXJ2YWxzWzIsLTFdKSkKCmdnUmVmUmVmbCA8LSBnZ3Bsb3QoZGF0YT1zZWxSZWZzLGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0xLCBzaXplPTAuNSxhZXMoZ3JvdXA9c2FtcGxlLGNvbG9yPW1vbml0b3IpKSArCiAgZ2VvbV9saW5lIChhbHBoYT0xLCBsaW5ld2lkdGg9MC41LCBhZXMoZ3JvdXA9c2FtcGxlLCBjb2xvcj1tb25pdG9yKSkgKwogICNnZW9tX2xpbmUoZGF0YT1SYWRjb250W1JhZGNvbnQkU2FtcGxlPT0yLF0pICsKICAjZ2VvbV9saW5lKGRhdGE9UmVmTUNBQTAxLCBhZXMoeD1XYXZlbGVuZ3RoLCB5PVJlZmxlY3RhbmNlKSxjb2w9ImdyZXkiKSArCiAgeGxpbShjKDQwMCwgMjYwMCkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249YygwLjksIDAuMSkpICsKICBsYWJzKGNvbG9yPSIiKSArCiAgZ2d0aXRsZSgiUmVmbGVjdGFuY2UgKFN0YW5kYXJkIFRhcmdldCkiLCBzdWJ0aXRsZSA9ICIoSVQ6IDUzIG1zLCAxNyBtcykiKQpnZ1JlZlJlZmwKYGBgCiMjIyAzLjUgSG9sZGVyICgyMDIzMDEzMCBEYXRhKQpJbiBvcmRlciB0byBwcm90ZWN0IHRoZSB3aGl0ZSByZWZlcmVuY2UsIHdlIHRha2UgdGhlIHdoaXRlIHJlYWRpbmcgd2l0aCB0aGUgcmVmZXJlbmNlIHdpdGhpbiBhIGJsYWNrIGhvbGRlciB0aGF0IGF0dGFjaGVzIHRvIHRoZSBwcm9iZSBsZWF2aW5nCmEgY29uc3RhbnQgZGlzdGFuY2Ugb2YgNSBtbSBmcm9tIHRoZSBwcm9iZSB0byB0aGUgcmVmZXJlbmNlLiBXZSBjYXJyaWVkIG91dCB0aGUgZm9sbG93aW5nIG1lYXN1cmVtZW50czoKCistLS0tLS0tLSstLS0tLS0rLS0tLS0tLS0rLS0tLS0tKy0tLS0tLS0tKwp8c3BlY3RydW18V2hpdGUgfFdoaXRlICAgfFRhcmdldHxUYXJnZXQgIHwKfG5hbWUgICAgfGhvbGRlcnxkaXN0YW5jZXxob2xkZXJ8ZGlzdGFuY2V8Cis9PT09PT09PSs6PT09PTorPT09PT09PTorOj09PT06Kz09PT09PT06Kwp8Y29udGFjdCB8Tm8gICAgfCAgICAwLjAgfE5vICAgIHwwLjAgICAgIHwKKz09PT09PT09Kz09PT09PSs9PT09PT09PSs9PT09PT0rPT09PT09PT0rCnxob2xkZXIwIHxObyAgICB8ICAgIDUuMCB8Tm8gICAgfDUuMCAgICAgfAorPT09PT09PT0rPT09PT09Kz09PT09PT09Kz09PT09PSs9PT09PT09PSsKfGhvbGRlcjEgfFllcyAgIHwgICAgNS4wIHxZZXMgICB8MTAuMCAgICB8Cis9PT09PT09PSs9PT09PT0rPT09PT09PT0rPT09PT09Kz09PT09PT09Kwp8aG9sZGVyMiB8WWVzICAgfCAgICA1LjAgfE5vICAgIHwxMC4wICAgIHwKKz09PT09PT09Kz09PT09PSs9PT09PT09PSs9PT09PT0rPT09PT09PT0rCnxob2xkZXIzIHxZZXMgICB8ICAgIDUuMCB8Tm8gICAgfDUuMCAgICAgfAorPT09PT09PT0rPT09PT09Kz09PT09PT09Kz09PT09PSs9PT09PT09PSsKfGZpZWxkICAgfFllcyAgIHwgICAgNS4wIHxObyAgICB8MC4wICAgICB8Cis9PT09PT09PSs9PT09PT0rPT09PT09PT0rPT09PT09Kz09PT09PT09Kwo6IFRhYmxlIDEgU2V0dXAgb2YgbWVhc3VyZW1lbnRzIG9mIHdoaXRlIGFuZCB0YXJnZXQgKHN0YW5kYXJkKSByZWZlcmVuY2VzCgpFdmVuIHN1Y2ggYSBzaG9ydCBkaXN0YW5jZSBhcyA1IG1tIGhhcyBhIHNpZ25pZmljYW50IGltcGFjdCBpbiB0aGUgUmFkaWFuY2UgbWVhc3VyZW1lbnRzIG9mIGJvdGggdGhlIHdoaXRlIGFuZCB0aGUgc3RhbmRhcmQgcmVmZXJlbmNlcyAoY29tcGFyZSAiY29udGFjdCIgYW5kICJob2xkZXIwIiBpbiB0aGUgZmlndXJlcykuIEluIHRoZSBjYXNlIG9mIHRoZSB3aGl0ZSByZWZlcmVuY2UsIHRoZSBob2xkZXIgaXRzZWxmIGhhcyBzb21lIGluZmx1ZW5jZSBpbiB0aGUgcmVhZGluZywgcHJvYmFibHkgYmVjYXVzZSBzb21lIGxpZ2h0IGlzIGFjdHVhbGx5IGFic29yYmVkOiByYWRpYW5jZSBzcGVjdHJhIGFjcXVpcmVkIHdpdGggdGhlIGhvbGRlciAoc3BlY3RyYSAiaG9sZGVyMSIgdG8gImhvbGRlcjMiKSBhcmUgZGFya2VyIHRoYW4gdGhvc2UgYWNxdWlyZWQgd2l0aG91dCB0aGUgaG9sZGVyIGF0IHRoZSBzYW1lIGRpc3RhbmNlICg1IG1tKS4gIApgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSJob2xkIiwgZmlnLmNhcD1UUlVFLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTJ9CmZkaXIgPC0gIi4uL1Rlc3QyMDIzMDEzMCIKbGlzdGEgPC0gZGF0YS5mcmFtZShmbmFtZT1saXN0LmZpbGVzKGZkaXIsIHBhdHQ9Z2xvYjJyeCgiKi50eHQiKSksIGZkaXI9ZmRpcikKI2xpc3RhWzE3LDFdCiNmaWxlLnJlbmFtZShmaWxlLnBhdGgoZmRpciwgbGlzdGFbMTcsMV0pLGZpbGUucGF0aChmZGlyLCAiMjAxODAyMDFfMTMwNTMyXzAxN19TdGRSZWZfYWRhcHQzX3NwZWN0cnVtLnR4dCIpKSAjbm90IGZvbGxvd2luZyBuYW1pbmcgY29udmVudGlvbjsgb25seSBvbmNlCmxpc3RhIDwtIGRhdGEuZnJhbWUoZm5hbWU9bGlzdC5maWxlcyhmZGlyLCBwYXR0PWdsb2IycngoIioudHh0IikpLCBmZGlyPWZkaXIpCiNsaXN0YQphIDwtIHN0cnNwbGl0KGxpc3RhWywxXSwgIl8iKQphIDwtIHNhcHBseShhLCBmdW5jdGlvbih4KXt4WzVdfSkKYVthPT0ibWluZCJdIDwtICJjb250YWN0IgphW2E9PSJhZGFwdDQiXSA8LSAiaG9sZGVyMCIKYSA8LSBzdWIoImFkYXB0IiwiaG9sZGVyIixhKQpzZWxSZWZzIDwtIHNlbFNlc3Npb25SZWZzKHNlbGZsaXN0PWxpc3RhKQpzZWxSZWZzJGhvbGRlciA8LSBzZWxSZWZzJHNhbXBsZQpzZWxSZWZzJGhvbGRlciA8LSBwbHlyOjptYXB2YWx1ZXMoc2VsUmVmcyRob2xkZXIsIGZyb209dW5pcXVlKHNlbFJlZnMkc2FtcGxlKSwgdG89YSkKV2F2ZWxlbmd0aDIgPC0gc2VsUmVmcyRXYXZlbGVuZ3RoW3NlbFJlZnMkaG9sZGVyPT0iaG9sZGVyMyJdCldoaXRlUmFkMiA8LSBzZWxSZWZzJFdoaXRlUmFkW3NlbFJlZnMkaG9sZGVyPT0iaG9sZGVyMyJdClJlZmxlY3RhbmNlMiA8LSAoc2VsUmVmcyRSYWRpYW5jZS1zZWxSZWZzJERhcmspW3NlbFJlZnMkaG9sZGVyPT0iY29udGFjdCJdL1doaXRlUmFkMgpSZWZsZWN0YW5jZSA8LSBzZWxSZWZzJFJlZmxlY3RhbmNlW3NlbFJlZnMkaG9sZGVyPT0iY29udGFjdCJdCgpnZ1JlZldSYWQgPC0gZ2dwbG90KGRhdGE9c2VsUmVmcyxhZXMoeD1XYXZlbGVuZ3RoLCB5PVdoaXRlUmFkKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MSwgc2l6ZT0wLjUsYWVzKGdyb3VwPXNhbXBsZSxjb2xvcj1ob2xkZXIpKSArCiAgZ2VvbV9saW5lIChhbHBoYT0xLCBsaW5ld2lkdGg9MC41LGFlcyhncm91cD1zYW1wbGUsY29sb3I9aG9sZGVyKSkgKwogIHhsaW0oYyg0MDAsIDI2MDApKSArIHlsaW0oMCwgNjAwMDApICsgeWxhYigiUmFkaWFuY2UiKQogICNnZ3RpdGxlKCJSYWRpYW5jZSAoV2hpdGUgcmVmZXJlbmNlKSIsIHN1YnRpdGxlID0gIiIpCmdnUmVmUmFkIDwtIGdncGxvdChkYXRhPXNlbFJlZnMsYWVzKHg9V2F2ZWxlbmd0aCwgeT1SYWRpYW5jZS1EYXJrKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MSwgc2l6ZT0wLjUsYWVzKGdyb3VwPXNhbXBsZSxjb2xvcj1ob2xkZXIpKSArCiAgZ2VvbV9saW5lIChhbHBoYT0xLCBsaW5ld2lkdGg9MC41LGFlcyhncm91cD1zYW1wbGUsY29sb3I9aG9sZGVyKSkgKwogIHhsaW0oYyg0MDAsIDI2MDApKSArIHlsaW0oMCwgNjAwMDApICsgeWxhYigiUmFkaWFuY2UiKQogICNnZ3RpdGxlKCJSYWRpYW5jZSAoU3RhbmRhcmQgVGFyZ2V0KSIsIHN1YnRpdGxlID0gIiIpCmdnUmVmUmVmbCA8LSBnZ3Bsb3QoZGF0YT1zZWxSZWZzLGFlcyh4PVdhdmVsZW5ndGgsIHk9UmVmbGVjdGFuY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0xLCBzaXplPTAuNSxhZXMoZ3JvdXA9c2FtcGxlLGNvbG9yPWhvbGRlcikpICsKICBnZW9tX2xpbmUgKGFscGhhPTEsIGxpbmV3aWR0aD0wLjUsYWVzKGdyb3VwPXNhbXBsZSxjb2xvcj1ob2xkZXIpKSArCiAgI2dlb21fbGluZShkYXRhPVJhZGNvbnRbUmFkY29udCRTYW1wbGU9PTIsXSkgKwogIGdlb21fbGluZShkYXRhPVJlZk1DQUEwMSwgYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZSksY29sPSJncmV5IiApICsKICB4bGltKGMoNDAwLCAyNjAwKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249YygwLjkyLCAwLjIpKSArCiAgZ2d0aXRsZSgiUmVmbGVjdGFuY2Ugb2YgU3RhbmRhcmQgUmVmZXJlbmNlIiwgc3VidGl0bGUgPSAiIikKI2QyIDwtIGRhdGEuZnJhbWUoV2F2ZWxlbmd0aD1XYXZlbGVuZ3RoMiwgUmVmbGVjdGFuY2U9UmVmbGVjdGFuY2UyKQpkMiA8LSBkYXRhLmZyYW1lKFdhdmVsZW5ndGg9V2F2ZWxlbmd0aDIsIFJlZmxlY3RhbmNlPWMoUmVmbGVjdGFuY2UsUmVmbGVjdGFuY2UyKSwgCiAgICAgICAgICAgICAgICAgaG9sZGVyPWMocmVwKCJjb250YWN0IiwgbGVuZ3RoKFdhdmVsZW5ndGgyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJmaWVsZCIsICAgbGVuZ3RoKFdhdmVsZW5ndGgyKSkpKQpSZWZNQ0FBMDEkc2FtcGxlIDwtICJDZXJ0aWZpY2F0aW9uIgp4IDwtIFJlZk1DQUEwMVssYygxLDMsNCldCm5hbWVzKHgpWzNdIDwtICJob2xkZXIiCmQyIDwtIHJiaW5kKGQyLHgpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKZ2dSZWZSZWZsMiA8LSBnZ3Bsb3QoZGF0YT1kMiwKICAgICAgICAgICAgICAgICAgICAgYWVzKHg9V2F2ZWxlbmd0aCwgeT1SZWZsZWN0YW5jZSwgY29sb3I9aG9sZGVyKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MSwgc2l6ZT0wLjUpICsKICBnZW9tX2xpbmUgKGFscGhhPTEsIGxpbmV3aWR0aD0wLjUpICsKICAjZ2VvbV9saW5lKGRhdGE9UmFkY29udFtSYWRjb250JFNhbXBsZT09MixdKSArCiAgZ2VvbV9saW5lKGRhdGE9UmVmTUNBQTAxLCBhZXMoeD1XYXZlbGVuZ3RoLCB5PVJlZmxlY3RhbmNlKSxjb2w9ImdyZXkiICkgKwogIHhsaW0oYyg0MDAsIDI2MDApKSArCiAgZ2d0aXRsZSgiUmVmbGVjdGFuY2Ugb2YgU3RhbmRhcmQgUmVmZXJlbmNlIiwgc3VidGl0bGUgPSAiIikKCiNnZ1JlZlJlZmwgCiMrIGdlb21fcG9pbnQoZGF0YT1kMixhbHBoYT0xLCBzaXplPTAuNSkgKyBnZW9tX2xpbmUgKGRhdGE9ZDIsYWxwaGE9MSwgbGluZXdpZHRoPTAuNSkKI2dnUmVmUmVmbDIKCiNzdWJwbG90KCkgZG9lcyBub3QgZGlzcGxheSBnZ3RpdGxlKCkgaW5mbzoKc3VicGxvdChzdHlsZShnZ3Bsb3RseShnZ1JlZldSYWQpLCBzaG93bGVnZW5kPUZBTFNFKSwgZ2dwbG90bHkoZ2dSZWZSYWQpLCBucm93cyA9IDIsIHRpdGxlWSA9IFRSVUUsIHRpdGxlWCA9IFRSVUUsIG1hcmdpbiA9IDAuMSApICU+JQogICNsYXlvdXQobGVnZW5kID0gbGlzdCh0aXRsZT0iIiwgb3JpZW50YXRpb24gPSAiaCIsIHggPSAwLjE1LCB5ID0gMC4zOCksCiAgbGF5b3V0KGxlZ2VuZCA9IGxpc3QodGl0bGU9IiIsIG9yaWVudGF0aW9uID0gInYiLCB4ID0gMC4wNSwgeSA9IDAuOTgpLAogICAgICAgICBhbm5vdGF0aW9ucz1saXN0KAogICAgICAgICAgIGxpc3QoCiAgICAgICAgCSAgeCA9IDAuMSwgIAogICAgICAgIAkgIHkgPSAxLjAsICAKICAgICAgICAJICB0ZXh0ID0gIldoaXRlIHJlZmVyZW5jZSIsICAKICAgICAgICAJICB4cmVmID0gInBhcGVyIiwgIAogICAgICAgIAkgIHlyZWYgPSAicGFwZXIiLCAgCiAgICAgICAgCSAgeGFuY2hvciA9ICJjZW50ZXIiLCAgCiAgICAgICAgCSAgeWFuY2hvciA9ICJib3R0b20iLCAgCiAgICAgICAgCSAgc2hvd2Fycm93ID0gRkFMU0UpLAogICAgICAgIAlsaXN0KAogICAgICAgIAkgIHggPSAwLjEsICAKICAgICAgICAJICB5ID0gMC40MCwgIAogICAgICAgIAkgIHRleHQgPSAiU3RhbmRhcmQgcmVmZXJlbmNlIiwgIAogICAgICAgIAkgIHhyZWYgPSAicGFwZXIiLCAgCiAgICAgICAgCSAgeXJlZiA9ICJwYXBlciIsICAKICAgICAgICAJICB4YW5jaG9yID0gImNlbnRlciIsICAKICAgICAgICAJICB5YW5jaG9yID0gImJvdHRvbSIsICAKICAgICAgICAJICBzaG93YXJyb3cgPSBGQUxTRSkpKQpgYGAKUmFkaWFuY2Ugc3BlY3RyYSAiaG9sZGVyMSIgYW5kICJob2xkZXIyIiB3ZXJlIGFjcXVpcmVkIGF0IGxvbmdlciBhIGRpc3RhbmNlICgxIGNtKSBvZiB0aGUgU3RhbmRhcmQgcmVmZXJlbmNlLCBhbmQgd2VyZSB0b28gZGFyayB0byBhY3R1YWxseSByZWNvcmQgdGhlIHNwZWN0cmFsIGZlYXR1cmVzIGluIHRoZWlyIHJlc3BlY3RpdmUgUmVmbGVjdGFuY2Ugc3BlY3RyYS4gVGhpcyBmYWN0IGhpZ2hsaWdodHMgdGhlIGltcG9ydGFuY2Ugb2Yga2VlcGluZyB0aGUgcHJvYmUgaW4gY29udGFjdCB3aXRoIChvciBhdCBsZWFzdCBjbG9zZXIgdGhhbiA1IG1tIHRvKSB0aGUgdGFyZ2V0LiAgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSJob2xkIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CiNnZ3Bsb3RseShnZ1JlZldSYWQpCiNnZ3Bsb3RseShnZ1JlZlJhZCkKZ2dwbG90bHkoZ2dSZWZSZWZsKSAgJT4lCiAgbGF5b3V0KGxlZ2VuZCA9IGxpc3QodGl0bGU9IiIsIG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC4xLCB5ID0gMC4wNSkpCmBgYApGaWVsZCBtZWFzdXJlbWVudHMgaW50cm9kdWNlIGEgY29uY2Vybi4gVGhlIGNvbW1vbiBwcm9jZWR1cmUgaW4gdGhlIGZpZWxkIGlzIHRvIGtlZXAgdGhlIGhvbGRlciBvbiBmb3IgdGhlIFdoaXRlIHJlZmVyZW5jZSAoYXMgYSBtZWFuIHRvIHByb3RlY3QgaXQsIHdoaWNoIGltcGxpZXMgNW1tIGRpc3RhbmNlIGZyb20gdGhlIHByb2JlIHRvIHRoZSB3aGl0ZSByZWZlcmVuY2UpLiBUaGUgcHJvYmUsIGluc3RlYWQsIGlzIGtlcHQgaW4gY29udGFjdCB3aXRoIHRoZSB0YXJnZXQgKGVuc3VyaW5nIGEgY29uc3RhbnQgNSBtbSBkaXN0YW5jZSBmcm9tIHByb2JlIHRvIHRhcmdldCBpcyBpbXBvc3NpYmxlIGJ5IGZyZWVoYW5kIGluIHRoZSBmaWVsZCkuIFRoZXJlZm9yZSwgdGhlIHdoaXRlIHJlZmVyZW5jZSBhbmQgdGhlIHRhcmdldCBhcmUgbm90IGFjcXVpcmVkIHdpdGggaWRlbnRpY2FsIHByb2JlLXRvLXRhcmdldCBkaXN0YW5jZS4gUmVwbGljYXRpbmcgdGhpcyBwcm9jZWR1cmUgaW4gdGhlIGxhYiByZXN1bHRzIG9uIHRoZSByZWZsZWN0YW5jZSBzcGVjdHJ1bSAiZmllbGQiLCB3aGljaCBpcyBjbGVhcmx5IHNoaWZ0ZWQgdXB3YXJkczogdGFyZ2V0IHJhZGlhbmNlIGlzIG1lYXN1cmVkIGluIGNvbnRhY3QgYnV0IHdoaXRlIHJhZGlhbmNlIGlzIG1lYXN1cmVkIGF0IDUgbW0uIFdoaWxlIG5vIG5hdHVyYWwgdGFyZ2V0IGlzIGFzIGJyaWdodCBhcyB0aGUgU3RhbmRhcmQgUmVmZXJlbmMgKHRodXMgUmVmbGVjdGFuY2UgcmVhZGluZyA+IDEgYXMgaW4gaGVyZSBhcmUgaGlnaGx5IHVubGlrZWx5KSB0aGUgb2Zmc2V0IGlzIHRvbyBoaWdoIGFuZCB3ZSBzaG91bGQgbW9kaWZ5IHRoZSBob2xkZXIgdG8ga2VlcCBhIGRpc3RhbmNlIDwgNSBtbS4gCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSJob2xkIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CmdncGxvdGx5KGdnUmVmUmVmbDIpICAlPiUKICBsYXlvdXQobGVnZW5kID0gbGlzdCh0aXRsZT0iIiwgb3JpZW50YXRpb24gPSAiaCIsIHggPSAwLjQsIHkgPSAwLjA1KSkKYGBgCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9ImhvbGQiLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9NX0KZDMgPC0gZGF0YS5mcmFtZShXYXZlbGVuZ3RoPXNlbFJlZnMkV2F2ZWxlbmd0aFtzZWxSZWZzJGhvbGRlcj09ImhvbGRlcjMiXSwKICAgICAgICAgICAgICAgICBXaGl0ZVJhZENvbnRhY3QgPSBzZWxSZWZzJFdoaXRlUmFkW3NlbFJlZnMkaG9sZGVyPT0iY29udGFjdCJdLAogICAgICAgICAgICAgICAgIFdoaXRlUmFkSG9sZGVyMCA9IHNlbFJlZnMkV2hpdGVSYWRbc2VsUmVmcyRob2xkZXI9PSJob2xkZXIwIl0sCiAgICAgICAgICAgICAgICAgV2hpdGVSYWRIb2xkZXIzID0gc2VsUmVmcyRXaGl0ZVJhZFtzZWxSZWZzJGhvbGRlcj09ImhvbGRlcjMiXSkKZDMkSW5zdHJ1bWVudCA8LSAiU1RTLUlUIgpkMyRJbnN0cnVtZW50W2RzdyRXYXZlbGVuZ3RoPjg1MF0gPC0gIk5JUlFVRVNUIgoKbG0yV1JhZDFhIDwtIGxtb2RlbDIoV2hpdGVSYWRIb2xkZXIwIH4gV2hpdGVSYWRDb250YWN0LCBkYXRhPWQzW2QzJEluc3RydW1lbnQ9PSJTVFMtSVQiLF0pCmxtMldSYWQxYiA8LSBsbW9kZWwyKFdoaXRlUmFkSG9sZGVyMCB+IFdoaXRlUmFkQ29udGFjdCwgZGF0YT1kM1tkMyRJbnN0cnVtZW50PT0iTklSUVVFU1QiLF0pCmxtMldSYWRIM2EgPC0gbG1vZGVsMihXaGl0ZVJhZEhvbGRlcjMgfiBXaGl0ZVJhZENvbnRhY3QsIGRhdGE9ZDNbZDMkSW5zdHJ1bWVudD09IlNUUy1JVCIsXSkKbG0yV1JhZEgzYiA8LSBsbW9kZWwyKFdoaXRlUmFkSG9sZGVyMyB+IFdoaXRlUmFkQ29udGFjdCwgZGF0YT1kM1tkMyRJbnN0cnVtZW50PT0iTklSUVVFU1QiLF0pCgpnZ2xtMkgwIDwtIGdncGxvdChkYXRhPWQzW2QzJEluc3RydW1lbnQ9PSJTVFMtSVQiLF0sIGFlcyhsYWJlbD1XYXZlbGVuZ3RoKSkgKwogIGdlb21fcG9pbnQoYWVzKHg9V2hpdGVSYWRDb250YWN0LCB5PVdoaXRlUmFkSG9sZGVyMCwgY29sb3I9SW5zdHJ1bWVudCksYWxwaGE9MC41KSArCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdD1sbTJXUmFkMWEkcmVncmVzc2lvbi5yZXN1bHRzWzIsMl0sIHNsb3BlPWxtMldSYWQxYSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwzXSkpICsKICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0PWxtMldSYWQxYiRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyXSwgc2xvcGU9bG0yV1JhZDFiJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDNdKSkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQ9MCwgc2xvcGU9MSksIGxpbmV0eXBlPTQpICsKICAjeGxpbShjKDAsMzAwMCkpICsgeWxpbShjKDAsMzAwMCkpICsKICB4bGFiKCJSYWRpYW5jZSAoY29udGFjdCkiKSArICB5bGFiKCJSYWRpYW5jZSAoNSBtbSkiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjgsLjE1KSwgYXNwZWN0LnJhdGlvPTEpICsgCiAgZ2d0aXRsZSgiV2hpdGUgUmVmZXJlbmNlIikgCmdnbG0ySDMgPC0gZ2dwbG90KGRhdGE9ZDMpICsKICBnZW9tX3BvaW50KGFlcyh4PVdoaXRlUmFkQ29udGFjdCwgeT1XaGl0ZVJhZEhvbGRlcjMsIGNvbG9yPUluc3RydW1lbnQpKSArCiAgZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdD1sbTJXUmFkSDNhJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDJdLCBzbG9wZT1sbTJXUmFkSDNhJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDNdKSkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQ9bG0yV1JhZEgzYiRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyXSwgc2xvcGU9bG0yV1JhZEgzYiRyZWdyZXNzaW9uLnJlc3VsdHNbMiwzXSkpICsKICBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0PTAsIHNsb3BlPTEpLCBsaW5ldHlwZT00KSArCiAgeGxpbShjKDAsMzAwMCkpICsgeWxpbShjKDAsMzAwMCkpICsKICB4bGFiKCJSYWRpYW5jZSAoY29udGFjdCkiKSArICB5bGFiKCJSYWRpYW5jZSAoNSBtbSBob2xkZXIgb24pIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC44LC4xNSksIGFzcGVjdC5yYXRpbz0xKSArIAogIGdndGl0bGUoIldoaXRlIFJlZmVyZW5jZSIpIApnZ2xtMkgzSDAgPC0gZ2dwbG90KGRhdGE9ZDMpICsKICBnZW9tX3BvaW50KGFlcyh4PVdoaXRlUmFkSG9sZGVyMCwgeT1XaGl0ZVJhZEhvbGRlcjMsIGNvbG9yPUluc3RydW1lbnQpKSArCiAgI2dlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQ9bG0yV1JhZEgzYSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwyXSwgc2xvcGU9bG0yV1JhZEgzYSRyZWdyZXNzaW9uLnJlc3VsdHNbMiwzXSkpICsKICAjZ2VvbV9hYmxpbmUoYWVzKGludGVyY2VwdD1sbTJXUmFkSDNiJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDJdLCBzbG9wZT1sbTJXUmFkSDNiJHJlZ3Jlc3Npb24ucmVzdWx0c1syLDNdKSkgKwogIGdlb21fYWJsaW5lKGFlcyhpbnRlcmNlcHQ9MCwgc2xvcGU9MSksIGxpbmV0eXBlPTQpICsKICB4bGltKGMoMCwzMDAwKSkgKyB5bGltKGMoMCwzMDAwKSkgKwogIHhsYWIoIlJhZGlhbmNlICg1IG1tKSIpICsgIHlsYWIoIlJhZGlhbmNlICg1IG1tIGhvbGRlciBvbikiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjgsLjE1KSwgYXNwZWN0LnJhdGlvPTEpICsgCiAgZ2d0aXRsZSgiV2hpdGUgUmVmZXJlbmNlIikgCgojZ3JpZC5hcnJhbmdlKGdnbG0ySDAsIGdnbG0ySDMsIGdnbG0ySDNIMCwgbmNvbD0zKQoKYGBgCipUQkQqCgoqIHNwZWN0cmEgb2YgaG9sZGVyIG1hdGVyaWFsCiogcGxvdCBXY29udGFjdCB2cyBXNW1tIGhvbGRlcjAsIGFuZCB2cy4gVyBob2xkZXIzCiogYSBmdWxsIGFuYWx5c2lzIG9mIGRpc3RhbmNlIGVmZmVjdCAoZnJvbSA1IG1tIHRvIDVjbSkKKiBpbGx1bWluYXRlIHdpdGggQVNEIGJ1bGIKCiMjIDUuIENvbmNsdXNpb25zCgoqIEV2ZXJ5IHRhcmdldCByZWFkaW5nIG11c3QgaGF2ZSBhIHdoaXRlIHJlZmVyZW5jZSByZWFkaW5nIHNob3J0bHkgYmVmb3JlLgoqIFRoZSBpbnN1ZmZpY2llbnQgcmVzcG9uc2UgaW4gc29tZSBhYnNvcnB0aW9uIGZlYXR1cmVzIGlzIG5vdCBjYXVzZWQgYnkgcHJvY2VkdXJhbCBlcnJvcnMgYW5kIGlzIG5vdCBhbiBzcGVjaWZpYyB0cmFpdCBvZiBvdXIgTklSUVVFU1QgdW5pdC4gSXQgaXMgYWR2aXNlZCB0byB0YWtlIGEgcmVhZGluZyB3aXRoIHRoZSBzdGFuZGFyZCByZWZlcmVuY2UgKGluIGFkZGl0aW9uIHRvIHRoZSB3aGl0ZSByZWZlcmVuY2UpLCBhbmQgaW1wbGVtZW50IGEgY29ycmVjdGlvbiBhdCBwb3N0LXByb2Nlc3NpbmcuCiogUHJvYmUgdG8gdGFyZ2V0IGRpc3RhbmNlIGhhcyBhIG1ham9yIGVmZmVjdCwgZXZlbiBmb3IgNSBtbSAod2UgdXNlIGEgKmNvbnRhY3QqIHByb2JlKS4gV2Ugc2hvdWxkIHRyeSB0byBtb2RpZnkgdGhlIGhvbGRlciB0byByZWR1Y2UgdGhlIHByb2JlLXRvLXdoaXRlIHJlZmVyZW5jZSBkaXN0YW5jZS4KCgo=