MIDTERM

Markdown Author: Jessie Bell

Download this Rmd: Top right corner → Code → Download Rmd

1. PNW Map

1.1

Map precipitation using ggplot.

a: Read in pnw_norms.rds

PNW_df <- readRDS("MidtermData/data/pnw_norms.rds")

b: Use map_data to create states of interest

usa <- map_data("state")

idaho <- subset(usa, region=="idaho")

washington <- subset(usa, region=="washington")

oregon <- subset(usa, region=="oregon")

PNW <- rbind(idaho, washington, oregon)

PNW_df$Inches <- PNW_df$prcp

c: Create ggplot

p1 <- ggplot(data=PNW, aes(x=long, y=lat)) + 
  geom_polygon(data=PNW, aes(group=group), color="white", fill="gray") +
  guides(fill=FALSE)

p1+ geom_point(data=PNW_df, aes(x=longitude, y=latitude, color=Inches, size=Inches))+
  scale_color_viridis_b(alpha=0.5, guide="legend")+ #colors
  scale_size_continuous(range=c(1,6))+ #combine 2 legends
  theme(axis.text.x=element_blank(), 
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(), 
        axis.ticks.y=element_blank(),
        panel.background=element_blank(), #remove gray grid
    legend.position = c(0.87, 0.7), #legend location
    text = element_text(family = "Corbel"), #corbel font
    plot.title = element_text(hjust = 0.5))+
    labs(title='Total Annual Precipitation (1991-2020)', y=(expression(paste("z ", symbol('\256')))), x="")
**Figure 1:** Map showing the 30-year averages of precipitation throughout Idaho, Oregon, and Washington State, USA using 435 stations. Annual climate normals were calculated using average precipitation in inches with data from ```FedData``` from the ```ROpenSci``` package in R.

Figure 1: Map showing the 30-year averages of precipitation throughout Idaho, Oregon, and Washington State, USA using 435 stations. Annual climate normals were calculated using average precipitation in inches with data from FedData from the ROpenSci package in R.

1.2

Map temperature using tmap.

a: Read in the data (see 1.1a above)

b: Convert data frame into simple features

PNW_sf <- st_as_sf(x = PNW_df,                         
           coords = c("longitude", "latitude"),
           crs = 4326)

c: Create tmap

PNW_sf$"Average Temps (F)" <- PNW_sf$tavg


tmap_mode("view")
tm_shape(PNW_sf) +
  tm_symbols(id="name", col="Average Temps (F)", alpha=0.7, palette = rev(c("red","#ffb3c8", "#f5f5f5","#2698ce","#003666")))

Figure 2: Map showing 30-year average temperatures (°F) throughout Idaho, Oregon, and Washington State, USA using 435 stations. Highest averages occuring near Yakima, WA, Medford and Portland, OR, and at Browlee Dam in Idaho. Click on the points to see where each data point is located, or click the layers icon to change the basemap.

2. Point Pattern Analysis

2.1

Analyze the PPA using various plots, tables, statistics, and include a summary paragraph.

a: Read in hardwood_ppp.rds

hardwoods_ppp <- readRDS("MidtermData/data/hardwood_ppp.rds")

b: Convert ppp → df

# create data frame with coordinates and marks
hardwoods_df <- data.frame(x = hardwoods_ppp$x, y = hardwoods_ppp$y, Trees=hardwoods_ppp$marks)

c: Summarize hardwoods_ppp using the summary function

summary(hardwoods_ppp)
## Marked planar point pattern:  1351 points
## Average intensity 0.001552001 points per square feet
## 
## Coordinates are given to 5 decimal places
## 
## Multitype:
##          frequency proportion    intensity
## blackoak       135 0.09992598 0.0001550852
## hickory        702 0.51961510 0.0008064433
## maple          514 0.38045890 0.0005904727
## 
## Window: rectangle = [0, 933] x [0, 933] feet
## Window area = 870489 square feet
## Unit of length: 1 feet

d: Explore the data with ggplot

#make cute colors
cols <- c("#f8766d", "#00bfc4", "#94bd30")

ggplot()+
  geom_point(hardwoods_df, mapping=aes(x, y, color=Trees, pch=Trees))+
   scale_colour_manual(name = "TREES",
                      labels = c("Black oak", "Hickory", "Maple"),
                      values = cols) +   
  scale_shape_manual(name = "TREES",
                     labels = c("Black oak", "Hickory", "Maple"),
                     values = c(19, 17, 16))+
  theme_light()+
  labs(x="EASTING (FT)", y="NORTHING (FT)")
**Figure 3:** Showing the spatial arrangement of three tree types (n=1351) within 20 acres. Data were taken from Diggle (1883).

Figure 3: Showing the spatial arrangement of three tree types (n=1351) within 20 acres. Data were taken from Diggle (1883).

e: Create a density plot using persp

Tree_Density <- density(hardwoods_ppp)

#make pretty continuous colors for density plot
colramp <- colorRampPalette(cols)(100)
m<- persp(Tree_Density, colmap = colramp, theta = 0, phi = 10)
**Figure 4:** Density plot showing highest density of trees with lower values of x and higher values of y (in the Northwest corner of the plot). There seems to be a high density of trees along the entire eastern plot border as well. This does not tell us if there are interactions between tree types though.

Figure 4: Density plot showing highest density of trees with lower values of x and higher values of y (in the Northwest corner of the plot). There seems to be a high density of trees along the entire eastern plot border as well. This does not tell us if there are interactions between tree types though.

f: Create density plots for each species individually

#split the treetypes
split_pp <- split(hardwoods_ppp)

dens_all <- density(split_pp)
plot(dens_all, col=cols, main="")
**Figure 5:** Plots of density patterns for each tree type individually. Both black oak and hickory seem to be more dense in the northern part of the plot and maple seems to be more dense in the southern half. Black oak and hickory might show clustering at some point. I imagine that, by looking at these plots, maple will be competitive with the others.

Figure 5: Plots of density patterns for each tree type individually. Both black oak and hickory seem to be more dense in the northern part of the plot and maple seems to be more dense in the southern half. Black oak and hickory might show clustering at some point. I imagine that, by looking at these plots, maple will be competitive with the others.

g: Look for interactions between tree types using alltypes function and then plot function

Treetypes <- alltypes(hardwoods_ppp, "L", envelope=T, verbose=F)
plot(Treetypes[1,3], main="Black Oak & Maple")
**Figure 6:** Plot showing the transformation of Ripley's K for black oak and maple trees in a 20 acre plot. As predicted, maple and black oak are competing for some resource.

Figure 6: Plot showing the transformation of Ripley’s K for black oak and maple trees in a 20 acre plot. As predicted, maple and black oak are competing for some resource.

plot(Treetypes[1,2], main="Black Oak & Hickory")
**Figure 7:** Plot showing the transformation of Ripley K for black oak and hickory trees in a 20 acre plot. As predicted, these trees begin to clump at about 50 ft.

Figure 7: Plot showing the transformation of Ripley K for black oak and hickory trees in a 20 acre plot. As predicted, these trees begin to clump at about 50 ft.

plot(Treetypes[2,3], main="Hickory & Maple")
**Figure 8:** Plot showing the transformation of Ripley's K for hickory and maple trees in a 20 acre plot. They are competitive at all distances shown.

Figure 8: Plot showing the transformation of Ripley’s K for hickory and maple trees in a 20 acre plot. They are competitive at all distances shown.

Summary

In the context of a 20-acre plot, the point pattern analysis above revealed significant insights into the spatial distribution of trees, particularly maple, black oak, and hickory species. By examining \(\hat{L}\), the transformed Ripley’s K function, it was evident that competition existed between maple and the other two tree types (Fig. 6 & 8). Beyond a distance of approximately 50 feet, a pattern of clumping emerged between black oak and hickory, indicating a tendency for these species to cluster together (Fig. 7). Conversely, prior to the 50-foot threshold, the distribution of black oak and hickory exhibited complete spatial randomness.

2.2

Based on the limited information I’ve given you, how might soil moisture vary in this plot?

Answer

I have very limited tree knowledge, so I had to look this up. Maple trees are considered, mesophytic, meaning that they require a moderate amount of water to grow. Both oak and hickory are supposidly more drought tolerant and require less water, and because of this, I think that moisture levels are highest near the maple trees on the southern end of the plot (Fig. 3 & 5).

Reference

3. Variograms & Anisotropy

3.1

Use the variogram function in the gstat library to plot an empirical variogram of the particulate matter. Describe what you see. Is there autocorrelation in the data? Output: A plot and a sentence or two.

a: Read in pm_observations.rds

pm_sf <- readRDS("MidtermData/data/pm_observations.rds")
pm_df <- as.data.frame(pm_sf, xy=T)

b: Plot the data with ggplot

xyL = data.frame(st_coordinates(st_cast(pm_sf$geometry,"MULTIPOINT")))

xyL$pm <- pm_sf$pm

#break data up 
xyL_df_mutated <- xyL %>%
  mutate(Unitless = cut(xyL$pm, breaks = 5))

ggplot(xyL_df_mutated)+
geom_point(aes(x=X, y=Y,color=Unitless, size=Unitless), alpha=0.7)+
  scale_color_discrete(labels=c('0.00', '0.25', '0.50', "0.75", "1.00"))+
  scale_size_discrete(labels=c('0.00', '0.25', '0.50', "0.75", "1.00"))+
  labs(x="EASTING (M)", y="NORTHING (M)")
**Figure 9:** Particulate matter (unitless) for 100 $km^2$ site.

Figure 9: Particulate matter (unitless) for 100 \(km^2\) site.

c: Create a variogram & summary sentence (see figure 10 caption)

pmVar <- variogram(pm~1, pm_sf, cloud=F)
plot(pmVar,pch=20,cex=1, col=c("red", "orange", "pink", "steelblue"),
     ylab=expression(Semivariance~(gamma)),
     xlab="Distance (m)", main = "Particulate Matter")
**Figure 10:** Variogram showing isotropy. Points are autocorrelated with a separation distance of 0-1000 m, after which there is no longer any obvious autocorrelation.

Figure 10: Variogram showing isotropy. Points are autocorrelated with a separation distance of 0-1000 m, after which there is no longer any obvious autocorrelation.

3.2

Repeat but use the alpha argument to look at directionality in the data. If you set alpha to c(0,45,90,135) you’ll be looking at axes from south to north, southwest to northwest, west to east, and southeast to northwest. Describe what you see. How has your understanding changed? Output: A plot and a sentence or two.

a: Create a directional variogram & summary sentence (see figure 11 caption)

pmVar <- variogram(pm~1, pm_sf, alpha=c(0,45,90,135))
plot(pmVar,pch=20,cex=1,col=c("red", "orange", "pink", "steelblue"),
     ylab=expression(Semivariance~(gamma)),
     xlab="Distance (m)", main = "Particulate Matter Directionality")
**Figure 11:** Directional variogram showing anisotropy, with all directions except 45 looking relatively similar. The 0 graph shows S to N, 45 shows SW to NW, 90 shows W to E, and 135 shows SE to NE. There seems to be spatial autocorrelation from SW to NW in the 45 plot at distances of up to 1000 m between points. After 1000 m between points there is no spatial autocorrelation.

Figure 11: Directional variogram showing anisotropy, with all directions except 45 looking relatively similar. The 0 graph shows S to N, 45 shows SW to NW, 90 shows W to E, and 135 shows SE to NE. There seems to be spatial autocorrelation from SW to NW in the 45 plot at distances of up to 1000 m between points. After 1000 m between points there is no spatial autocorrelation.

4. Moran’s I & Scale

4.1

Make a map of the canopy height data. Show each plot (i.e., HARV 037, HARV 043, HARV 046, and HARV 047).

a: read in the data

canopyheight <- readRDS("MidtermData/data/harvSubsetCHM.rds")

b: Summarize the data deets & convert

#summary(canopyheight)

#crs(canopyheight)

xyL2 <- data.frame(st_coordinates(st_cast(canopyheight$geometry),"MULTIPOINT",  crs = st_crs(32618)))

xyL2$covertype <- canopyheight$covertype
xyL2$chm <- canopyheight$chm
xyL2$plotID <- canopyheight$plotID

c: Bring in CHM data

CHM_Harv <- raster("data/NEON-DS-Airborne-Remote-Sensing/HARV/CHM/HARV_chmCrop.tif")

d: Convert .tif into df

CHM_Harv_df <- as.data.frame(CHM_Harv, xy=T)

e: Plot map using ggplot

a <- ggplot() +
  geom_raster(data = CHM_Harv_df , aes(x = x, y = y, fill = HARV_chmCrop)) +
    scale_fill_viridis_c(name="M")+
  geom_sf(data = canopyheight$geometry, color=alpha("white",0.5))+
  coord_sf()+
  labs(x="EASTING (M)", y="NORTHING (M)", title="Canopy Height", subtitle = "UTM Zone 18N")+
    xlim(731400, 732000)+
  ylim(4713150, 4713800)+
  theme(axis.text.x=element_text(angle=45, hjust=1), axis.text.y=element_text(angle=45, hjust = 1))+
  annotate("text", x = 731510, y=4713355, label = "46", size=2.2)+
  annotate("text", x = 731932.5, y=4713232.5, label = "47", size=2.2)+
  annotate("text", x = 731840, y=4713715, label = "43", size=2.2)+
    annotate("text", x = 731635, y=4713300, label = "37", size=2.2)

f: Try to make what Andy made (and fail because points just are not rasters)

Harv_043 <- subset(canopyheight, plotID=="HARV_043")


b <- ggplot() +
  geom_sf(data=Harv_043$geometry, aes(color=Harv_043$chm), size=5)+
  scale_color_viridis_c(name="m")+
   xlim(c(731800, 731890))+
  ylim(c(4713675, 4713755))

g: Create polygons around point sites and clip CHM_Harv to polygons

#adds polygon to outline each plot
polygons_Harv <- canopyheight %>%
  st_as_sf(coords = c("lon", "lat")) %>%
  group_by(plotID) %>%
  summarize(geometry = st_union(geometry)) %>%
  st_convex_hull()

#convert polygons to shape file (because it is easier to work with):
#st_write(polygons_Harv, "data/Harvplots.shp", driver="Esri Shapefile")

#read in new shape file
polygons_Harv_shp  <- read_sf('data/Harvplots.shp')

#clip the raster for canopy height (the .tif) to the boudary of your new shape file
masked <- mask(CHM_Harv, polygons_Harv_shp) #creates raster layer 

#note that mask function WILL NOT KNIT if you have cache=T in your chunk. Took me a long time to get this to knit.

#make dataframe for ggplot
masked <- as.data.frame(masked, xy=T)

h: Create plots using ggplot geom_raster function with limits

#build cute circles for your final map
H_043 <- ggplot() +
  geom_raster(data = na.omit(masked), aes(x, y, fill=HARV_chmCrop), show.legend = F)+
  scale_fill_viridis_c(na.value = "white")+
  xlim(c(731800, 731890))+
  ylim(c(4713675, 4713755))+
  labs(x="", y="")+
  theme(panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.border = element_blank(),
    panel.background = element_blank(), 
    panel.grid.major.x = element_blank(), 
    axis.ticks.x = element_blank(),
               axis.text.x = element_blank(), 
    axis.ticks.y = element_blank(),
               axis.text.y = element_blank(), 
    plot.title = element_text(hjust = 0.5, face="bold", size = 15))

H_047 <- ggplot() +
  geom_raster(data = na.omit(masked), aes(x, y, fill=HARV_chmCrop), show.legend = F)+
  scale_fill_viridis_c(na.value = "white")+
  xlim(c(731890, 731975))+
  ylim(c(4713190, 4713275))+
  labs(x="", y="")+
  theme(panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.border = element_blank(),
    panel.background = element_blank(), 
    panel.grid.major.x = element_blank(), 
    axis.ticks.x = element_blank(),
               axis.text.x = element_blank(), 
    axis.ticks.y = element_blank(),
               axis.text.y = element_blank(), 
    plot.title = element_text(hjust = 0.5, face="bold", size = 15)) 



H_037 <- ggplot() +
  geom_raster(data = na.omit(masked), aes(x, y, fill=HARV_chmCrop), show.legend = F)+
  scale_fill_viridis_c(na.value = "white")+
  xlim(c(731890, 731975))+
  ylim(c(4713190, 4713275))+
  labs(x="", y="")+
  theme(panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.border = element_blank(),
    panel.background = element_blank(), 
    panel.grid.major.x = element_blank(), 
    axis.ticks.x = element_blank(),
               axis.text.x = element_blank(), 
    axis.ticks.y = element_blank(),
               axis.text.y = element_blank(), 
    plot.title = element_text(hjust = 0.5, face="bold", size = 15)) 


H_046 <- ggplot() +
  geom_raster(data = na.omit(masked), aes(x, y, fill=HARV_chmCrop), show.legend = F)+
  scale_fill_viridis_c(na.value = "white")+
  xlim(c(731472, 731555))+
  ylim(c(4713315, 4713395))+
  labs(x="", y="")+
  theme(panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.border = element_blank(),
    panel.background = element_blank(), 
    panel.grid.major.x = element_blank(), 
    axis.ticks.x = element_blank(),
               axis.text.x = element_blank(), 
    axis.ticks.y = element_blank(),
               axis.text.y = element_blank(), 
    plot.title = element_text(hjust = 0.5, face="bold", size = 15)) 

i: Plots

a
**Figure 12:** Showing all plots included in the autocorrelation analysis of the Harvard tree sites. Here you can see that plots 46 and 47 are closest in proximity to one another, which would make me suspect they have similar, if not identical correlograms for ther spatial autocorrelation. The legend is showing canopy height in meters. The canopy height is highest in the southern part of the map and is lowest in the northeast end of the plot, with a few more low canopy sites on the western side of the plot.

Figure 12: Showing all plots included in the autocorrelation analysis of the Harvard tree sites. Here you can see that plots 46 and 47 are closest in proximity to one another, which would make me suspect they have similar, if not identical correlograms for ther spatial autocorrelation. The legend is showing canopy height in meters. The canopy height is highest in the southern part of the map and is lowest in the northeast end of the plot, with a few more low canopy sites on the western side of the plot.

ggarrange(H_037, H_043, H_046, H_047, labels = c("A. 37", "B. 43", "C. 46", "D. 47"),
                    ncol = 2, nrow = 2)
**Figure 13:** Showing canopy heights of each plot above, using the same legend. Plots 37 and 43 (A & B) are both evergreen plots made up of white pine (*Pinus strobus*) and eastern hemlock (*Tsuga canadensis*). Plots 46 and 47 (C & D) are made up of deciduous broadleaf trees, predominately comprised of red oak (*Quercus rubra*) and red maple (*Acer rubrum*).

Figure 13: Showing canopy heights of each plot above, using the same legend. Plots 37 and 43 (A & B) are both evergreen plots made up of white pine (Pinus strobus) and eastern hemlock (Tsuga canadensis). Plots 46 and 47 (C & D) are made up of deciduous broadleaf trees, predominately comprised of red oak (Quercus rubra) and red maple (Acer rubrum).

4.2

Calculate a correlogram for each plot. Describe the behavior of Moran’s I for each plot.

a: Set up the data

cor_037 <- subset(canopyheight, plotID=="HARV_037")
cor_043 <- subset(canopyheight, plotID=="HARV_043")
cor_046 <- subset(canopyheight, plotID=="HARV_046")
cor_047 <- subset(canopyheight, plotID=="HARV_047")

#037
X_037 <- st_coordinates(cor_037)[,1]
Y_037 <- st_coordinates(cor_037)[,2]
CH_037 <- cor_037$chm

#043
X_043 <- st_coordinates(cor_043)[,1]
Y_043 <- st_coordinates(cor_043)[,2]
CH_043 <- cor_043$chm

#046
X_046 <- st_coordinates(cor_046)[,1]
Y_046 <- st_coordinates(cor_046)[,2]
CH_046 <- cor_046$chm

#047
X_047 <- st_coordinates(cor_047)[,1]
Y_047 <- st_coordinates(cor_047)[,2]
CH_047 <- cor_047$chm

b: Calculate max distance

#037
(max(X_037)-min(X_037))/3
## [1] 26
(max(Y_037)-min(Y_037))/3
## [1] 26.33333

c: Plot the correlogram for continuous data & describe the plots (Fig. 14 caption)

# 037
I_037 <- spline.correlog(x=X_037, y=Y_037, z=CH_037, 
                         resamp=100, xmax=40, quiet=TRUE)


# 043
I_043 <- spline.correlog(x=X_043, y=Y_043, z=CH_043, 
                         resamp=100, xmax=40, quiet=TRUE)

# 046
I_046 <- spline.correlog(x=X_046, y=Y_046, z=CH_046, 
                         resamp=100, xmax=40, quiet=TRUE)

# 047
I_047 <- spline.correlog(x=X_047, y=Y_047, z=CH_047, 
                         resamp=100, xmax=40, quiet=TRUE)

par(mfrow=c(2, 2))
plot(I_037, main="A. 37 Moran's I")
plot(I_043, main="B. 43 Moran's I")
plot(I_046, main="A. 46 Moran's I")
plot(I_047, main="A. 47 Moran's I")
**Figure 14:** Moran's I spatial correlogram of canopy height for Harvard tree plots. There seems to be strong spatial autocorrelations up to 5 m for plots A & B but this drops off rapidly after 5 m. The spatial autocorrelation is strong for plots C & D at close distances but the correlation drops much less rapidly that those for the evergreen trees (A & B). It is not surprising that the plots with similar tree structure are identical in their correlogram outputs. Plots 37 & 46 (A & C) are very close in proximity to one another and it is surprising that they are not more similar in canopy height, suggesting that tree composition can also change rapidly, speculatively due to elevation and cardinal direction of the plots.

Figure 14: Moran’s I spatial correlogram of canopy height for Harvard tree plots. There seems to be strong spatial autocorrelations up to 5 m for plots A & B but this drops off rapidly after 5 m. The spatial autocorrelation is strong for plots C & D at close distances but the correlation drops much less rapidly that those for the evergreen trees (A & B). It is not surprising that the plots with similar tree structure are identical in their correlogram outputs. Plots 37 & 46 (A & C) are very close in proximity to one another and it is surprising that they are not more similar in canopy height, suggesting that tree composition can also change rapidly, speculatively due to elevation and cardinal direction of the plots.

4.3

Speculate about how spatial autocorrelation is linked to the characteristic scale of the two different forest types. Backing up any wild speculation with the literature is encouraged.

Crown shapes and canopy height of both evergreen and deciduous forests likely influence spatial autocorrelation patterns in these plots. Evergreen forests likely show stronger spatial autocorrelation at smaller scales (Fig. 14A & B) because they have denser canopies, while deciduous forests seem to only show spatial autocorrelation at larger scales because they have broader, open canopies (Fig. 14C & D), though there are likley other factors influencing this as well. This speculation is supported by each of the provided paper readings in our midterm, which all suggest that the relationship between organismal characteristics and spatial autocorrelation is very complex and influenced by a range of things including species composition, canopy structure, sex, scale, and environmental conditions.

LS0tDQp0aXRsZTogIiAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNzczogc3R5bGUuY3NzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGLCBjYWNoZSA9IFQpDQoNCmxpYnJhcnkoZ3N0YXQpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkobmNmKQ0KbGlicmFyeShzcGRlcCkNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkoZ3QpDQpsaWJyYXJ5KHNwKQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KHVzbWFwKQ0KbGlicmFyeShzdGF0cykNCmxpYnJhcnkoc3BhdHN0YXQpDQpsaWJyYXJ5KHRlcnJhKQ0KbGlicmFyeShnZ3Jhc3RyKQ0KbGlicmFyeShkZXZ0b29scykNCmxpYnJhcnkoZ2duZXdzY2FsZSkNCmxpYnJhcnkodG1hcHRvb2xzKQ0KbGlicmFyeShyYXN0ZXIpDQpsaWJyYXJ5KHJhc3Rlcml6ZSkNCmxpYnJhcnkoZmFzdGVyaXplKQ0KbGlicmFyeSh0aWR5dGVycmEpDQoNCmBgYA0KDQojIyBNSURURVJNDQoNCmBgYHtjc3MsIGVjaG89RkFMU0V9DQoud2F0Y2gtb3V0IHsNCiAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7DQogIGJvcmRlcjogMXB4IHNvbGlkICMyMjg3OGE7DQogIGZvbnQtc2l6ZTogMTBweDsNCn0NCmBgYA0KDQpbKipNYXJrZG93biBBdXRob3I6Kipde3N0eWxlPSJjb2xvcjogIzc2Y2E0ZTsifSBKZXNzaWUgQmVsbA0KDQpbKipEb3dubG9hZCB0aGlzIFJtZDoqKl17c3R5bGU9ImNvbG9yOiAjMjk3NDhhOyJ9IFRvcCByaWdodCBjb3JuZXIg4oaSIENvZGUg4oaSIERvd25sb2FkIFJtZA0KDQp8IA0KDQojIyMgKioxLiBQTlcgTWFwKioNCg0KIyMjIyAxLjEgDQoNCk1hcCBwcmVjaXBpdGF0aW9uIHVzaW5nIGdncGxvdC4gDQoNCioqYToqKiBSZWFkIGluIGBgYHBud19ub3Jtcy5yZHNgYGANCg0KDQpgYGB7ciBkYXRhcmVhZCwgY2xhc3Muc291cmNlPSJ3YXRjaC1vdXQifQ0KUE5XX2RmIDwtIHJlYWRSRFMoIk1pZHRlcm1EYXRhL2RhdGEvcG53X25vcm1zLnJkcyIpDQpgYGANCg0KKipiOioqIFVzZSBgYGBtYXBfZGF0YWBgYCB0byBjcmVhdGUgc3RhdGVzIG9mIGludGVyZXN0DQoNCmBgYHtyIHN0YXRlb2ZpbnRlcmVzdCwgY2xhc3Muc291cmNlPSJ3YXRjaC1vdXQifQ0KDQp1c2EgPC0gbWFwX2RhdGEoInN0YXRlIikNCg0KaWRhaG8gPC0gc3Vic2V0KHVzYSwgcmVnaW9uPT0iaWRhaG8iKQ0KDQp3YXNoaW5ndG9uIDwtIHN1YnNldCh1c2EsIHJlZ2lvbj09Indhc2hpbmd0b24iKQ0KDQpvcmVnb24gPC0gc3Vic2V0KHVzYSwgcmVnaW9uPT0ib3JlZ29uIikNCg0KUE5XIDwtIHJiaW5kKGlkYWhvLCB3YXNoaW5ndG9uLCBvcmVnb24pDQoNClBOV19kZiRJbmNoZXMgPC0gUE5XX2RmJHByY3ANCg0KYGBgDQoNCg0KKipjOioqIENyZWF0ZSBgYGBnZ3Bsb3RgYGANCg0KYGBge3IgZ2csIGNsYXNzLnNvdXJjZT0id2F0Y2gtb3V0IiwgZmlnLmNhcD0iKipGaWd1cmUgMToqKiBNYXAgc2hvd2luZyB0aGUgMzAteWVhciBhdmVyYWdlcyBvZiBwcmVjaXBpdGF0aW9uIHRocm91Z2hvdXQgSWRhaG8sIE9yZWdvbiwgYW5kIFdhc2hpbmd0b24gU3RhdGUsIFVTQSB1c2luZyA0MzUgc3RhdGlvbnMuIEFubnVhbCBjbGltYXRlIG5vcm1hbHMgd2VyZSBjYWxjdWxhdGVkIHVzaW5nIGF2ZXJhZ2UgcHJlY2lwaXRhdGlvbiBpbiBpbmNoZXMgd2l0aCBkYXRhIGZyb20gYGBgRmVkRGF0YWBgYCBmcm9tIHRoZSBgYGBST3BlblNjaWBgYCBwYWNrYWdlIGluIFIuIn0NCg0KcDEgPC0gZ2dwbG90KGRhdGE9UE5XLCBhZXMoeD1sb25nLCB5PWxhdCkpICsgDQogIGdlb21fcG9seWdvbihkYXRhPVBOVywgYWVzKGdyb3VwPWdyb3VwKSwgY29sb3I9IndoaXRlIiwgZmlsbD0iZ3JheSIpICsNCiAgZ3VpZGVzKGZpbGw9RkFMU0UpDQoNCnAxKyBnZW9tX3BvaW50KGRhdGE9UE5XX2RmLCBhZXMoeD1sb25naXR1ZGUsIHk9bGF0aXR1ZGUsIGNvbG9yPUluY2hlcywgc2l6ZT1JbmNoZXMpKSsNCiAgc2NhbGVfY29sb3JfdmlyaWRpc19iKGFscGhhPTAuNSwgZ3VpZGU9ImxlZ2VuZCIpKyAjY29sb3JzDQogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZT1jKDEsNikpKyAjY29tYmluZSAyIGxlZ2VuZHMNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksICNyZW1vdmUgZ3JheSBncmlkDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjg3LCAwLjcpLCAjbGVnZW5kIGxvY2F0aW9uDQogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiQ29yYmVsIiksICNjb3JiZWwgZm9udA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSsNCiAgICBsYWJzKHRpdGxlPSdUb3RhbCBBbm51YWwgUHJlY2lwaXRhdGlvbiAoMTk5MS0yMDIwKScsIHk9KGV4cHJlc3Npb24ocGFzdGUoInogIiwgc3ltYm9sKCdcMjU2JykpKSksIHg9IiIpDQoNCmBgYA0KDQojIyMjIDEuMg0KDQpNYXAgdGVtcGVyYXR1cmUgdXNpbmcgYGBgdG1hcGBgYC4NCg0KKiphOioqIFJlYWQgaW4gdGhlIGRhdGEgKHNlZSAxLjFhIGFib3ZlKQ0KDQoqKmI6KiogQ29udmVydCBkYXRhIGZyYW1lIGludG8gc2ltcGxlIGZlYXR1cmVzDQoNCmBgYHtyfQ0KUE5XX3NmIDwtIHN0X2FzX3NmKHggPSBQTldfZGYsICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICBjb29yZHMgPSBjKCJsb25naXR1ZGUiLCAibGF0aXR1ZGUiKSwNCiAgICAgICAgICAgY3JzID0gNDMyNikNCmBgYA0KDQoNCioqYzoqKiBDcmVhdGUgYGBgdG1hcGBgYA0KDQpgYGB7ciB0bWFwLCB3YXJuaW5nPUYsIG1lc3NhZ2U9RiwgZmlnLmNhcD0iIiB9DQpQTldfc2YkIkF2ZXJhZ2UgVGVtcHMgKEYpIiA8LSBQTldfc2YkdGF2Zw0KDQoNCnRtYXBfbW9kZSgidmlldyIpDQp0bV9zaGFwZShQTldfc2YpICsNCiAgdG1fc3ltYm9scyhpZD0ibmFtZSIsIGNvbD0iQXZlcmFnZSBUZW1wcyAoRikiLCBhbHBoYT0wLjcsIHBhbGV0dGUgPSByZXYoYygicmVkIiwiI2ZmYjNjOCIsICIjZjVmNWY1IiwiIzI2OThjZSIsIiMwMDM2NjYiKSkpDQpgYGANCg0KKipGaWd1cmUgMjoqKiBNYXAgc2hvd2luZyAzMC15ZWFyIGF2ZXJhZ2UgdGVtcGVyYXR1cmVzICjCsEYpIHRocm91Z2hvdXQgSWRhaG8sIE9yZWdvbiwgYW5kIFdhc2hpbmd0b24gU3RhdGUsIFVTQSB1c2luZyA0MzUgc3RhdGlvbnMuIEhpZ2hlc3QgYXZlcmFnZXMgb2NjdXJpbmcgbmVhciBZYWtpbWEsIFdBLCBNZWRmb3JkIGFuZCBQb3J0bGFuZCwgT1IsIGFuZCBhdCBCcm93bGVlIERhbSBpbiBJZGFoby4gQ2xpY2sgb24gdGhlIHBvaW50cyB0byBzZWUgd2hlcmUgZWFjaCBkYXRhIHBvaW50IGlzIGxvY2F0ZWQsIG9yIGNsaWNrIHRoZSBsYXllcnMgaWNvbiB0byBjaGFuZ2UgdGhlIGJhc2VtYXAuDQoNCiMjIyAqKjIuIFBvaW50IFBhdHRlcm4gQW5hbHlzaXMqKg0KDQojIyMjIDIuMSANCg0KQW5hbHl6ZSB0aGUgUFBBIHVzaW5nIHZhcmlvdXMgcGxvdHMsIHRhYmxlcywgc3RhdGlzdGljcywgYW5kIGluY2x1ZGUgYSBzdW1tYXJ5IHBhcmFncmFwaC4NCg0KKiphOioqIFJlYWQgaW4gYGBgaGFyZHdvb2RfcHBwLnJkc2BgYA0KDQpgYGB7ciBkYXRhcmVhZGluMiwgY2xhc3Muc291cmNlPSJ3YXRjaC1vdXQifQ0KaGFyZHdvb2RzX3BwcCA8LSByZWFkUkRTKCJNaWR0ZXJtRGF0YS9kYXRhL2hhcmR3b29kX3BwcC5yZHMiKQ0KYGBgDQoNCioqYjoqKiBDb252ZXJ0IGBgYHBwcGBgYCDihpIgYGBgZGZgYGANCg0KYGBge3IgZGF0YSBleHBsb3JhdGlvbn0NCiMgY3JlYXRlIGRhdGEgZnJhbWUgd2l0aCBjb29yZGluYXRlcyBhbmQgbWFya3MNCmhhcmR3b29kc19kZiA8LSBkYXRhLmZyYW1lKHggPSBoYXJkd29vZHNfcHBwJHgsIHkgPSBoYXJkd29vZHNfcHBwJHksIFRyZWVzPWhhcmR3b29kc19wcHAkbWFya3MpDQoNCmBgYA0KDQoNCioqYzoqKiBTdW1tYXJpemUgYGBgaGFyZHdvb2RzX3BwcGBgYCB1c2luZyB0aGUgYGBgc3VtbWFyeWBgYCBmdW5jdGlvbg0KDQpgYGB7ciB0YWJsZX0NCnN1bW1hcnkoaGFyZHdvb2RzX3BwcCkNCmBgYA0KDQoqKmQ6KiogRXhwbG9yZSB0aGUgZGF0YSB3aXRoIGBgYGdncGxvdGBgYA0KDQpgYGB7ciBnZ3Bsb3QyLCBmaWcuY2FwPSIqKkZpZ3VyZSAzOioqIFNob3dpbmcgdGhlIHNwYXRpYWwgYXJyYW5nZW1lbnQgb2YgdGhyZWUgdHJlZSB0eXBlcyAobj0xMzUxKSB3aXRoaW4gMjAgYWNyZXMuIERhdGEgd2VyZSB0YWtlbiBmcm9tIERpZ2dsZSAoMTg4MykuIn0NCg0KI21ha2UgY3V0ZSBjb2xvcnMNCmNvbHMgPC0gYygiI2Y4NzY2ZCIsICIjMDBiZmM0IiwgIiM5NGJkMzAiKQ0KDQpnZ3Bsb3QoKSsNCiAgZ2VvbV9wb2ludChoYXJkd29vZHNfZGYsIG1hcHBpbmc9YWVzKHgsIHksIGNvbG9yPVRyZWVzLCBwY2g9VHJlZXMpKSsNCiAgIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZSA9ICJUUkVFUyIsDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQmxhY2sgb2FrIiwgIkhpY2tvcnkiLCAiTWFwbGUiKSwNCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjb2xzKSArICAgDQogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIlRSRUVTIiwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkJsYWNrIG9hayIsICJIaWNrb3J5IiwgIk1hcGxlIiksDQogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKDE5LCAxNywgMTYpKSsNCiAgdGhlbWVfbGlnaHQoKSsNCiAgbGFicyh4PSJFQVNUSU5HIChGVCkiLCB5PSJOT1JUSElORyAoRlQpIikNCg0KYGBgDQoNCioqZToqKiBDcmVhdGUgYSBkZW5zaXR5IHBsb3QgdXNpbmcgYGBgcGVyc3BgYGANCg0KYGBge3IgZGVuc2l0eSwgZmlnLmNhcD0iKipGaWd1cmUgNDoqKiBEZW5zaXR5IHBsb3Qgc2hvd2luZyBoaWdoZXN0IGRlbnNpdHkgb2YgdHJlZXMgd2l0aCBsb3dlciB2YWx1ZXMgb2YgeCBhbmQgaGlnaGVyIHZhbHVlcyBvZiB5IChpbiB0aGUgTm9ydGh3ZXN0IGNvcm5lciBvZiB0aGUgcGxvdCkuIFRoZXJlIHNlZW1zIHRvIGJlIGEgaGlnaCBkZW5zaXR5IG9mIHRyZWVzIGFsb25nIHRoZSBlbnRpcmUgZWFzdGVybiBwbG90IGJvcmRlciBhcyB3ZWxsLiBUaGlzIGRvZXMgbm90IHRlbGwgdXMgaWYgdGhlcmUgYXJlIGludGVyYWN0aW9ucyBiZXR3ZWVuIHRyZWUgdHlwZXMgdGhvdWdoLiJ9DQpUcmVlX0RlbnNpdHkgPC0gZGVuc2l0eShoYXJkd29vZHNfcHBwKQ0KDQojbWFrZSBwcmV0dHkgY29udGludW91cyBjb2xvcnMgZm9yIGRlbnNpdHkgcGxvdA0KY29scmFtcCA8LSBjb2xvclJhbXBQYWxldHRlKGNvbHMpKDEwMCkNCm08LSBwZXJzcChUcmVlX0RlbnNpdHksIGNvbG1hcCA9IGNvbHJhbXAsIHRoZXRhID0gMCwgcGhpID0gMTApDQoNCmBgYA0KDQoqKmY6KiogQ3JlYXRlIGRlbnNpdHkgcGxvdHMgZm9yIGVhY2ggc3BlY2llcyBpbmRpdmlkdWFsbHkNCg0KYGBge3IgZGVuc2FsbCwgZmlnLmNhcD0iKipGaWd1cmUgNToqKiBQbG90cyBvZiBkZW5zaXR5IHBhdHRlcm5zIGZvciBlYWNoIHRyZWUgdHlwZSBpbmRpdmlkdWFsbHkuIEJvdGggYmxhY2sgb2FrIGFuZCBoaWNrb3J5IHNlZW0gdG8gYmUgbW9yZSBkZW5zZSBpbiB0aGUgbm9ydGhlcm4gcGFydCBvZiB0aGUgcGxvdCBhbmQgbWFwbGUgc2VlbXMgdG8gYmUgbW9yZSBkZW5zZSBpbiB0aGUgc291dGhlcm4gaGFsZi4gQmxhY2sgb2FrIGFuZCBoaWNrb3J5IG1pZ2h0IHNob3cgY2x1c3RlcmluZyBhdCBzb21lIHBvaW50LiBJIGltYWdpbmUgdGhhdCwgYnkgbG9va2luZyBhdCB0aGVzZSBwbG90cywgbWFwbGUgd2lsbCBiZSBjb21wZXRpdGl2ZSB3aXRoIHRoZSBvdGhlcnMuIn0NCg0KI3NwbGl0IHRoZSB0cmVldHlwZXMNCnNwbGl0X3BwIDwtIHNwbGl0KGhhcmR3b29kc19wcHApDQoNCmRlbnNfYWxsIDwtIGRlbnNpdHkoc3BsaXRfcHApDQpwbG90KGRlbnNfYWxsLCBjb2w9Y29scywgbWFpbj0iIikNCmBgYA0KDQoNCioqZzoqKiBMb29rIGZvciBpbnRlcmFjdGlvbnMgYmV0d2VlbiB0cmVlIHR5cGVzIHVzaW5nICBgYGBhbGx0eXBlc2BgYCBmdW5jdGlvbiBhbmQgdGhlbiBgYGBwbG90YGBgIGZ1bmN0aW9uDQoNCmBgYHtyIHRyZWUgdHlwZXN9DQpUcmVldHlwZXMgPC0gYWxsdHlwZXMoaGFyZHdvb2RzX3BwcCwgIkwiLCBlbnZlbG9wZT1ULCB2ZXJib3NlPUYpDQpgYGANCg0KDQpgYGB7ciBwbG90IGludGVyMSwgZmlnLmNhcD0iKipGaWd1cmUgNjoqKiBQbG90IHNob3dpbmcgdGhlIHRyYW5zZm9ybWF0aW9uIG9mIFJpcGxleSdzIEsgZm9yIGJsYWNrIG9hayBhbmQgbWFwbGUgdHJlZXMgaW4gYSAyMCBhY3JlIHBsb3QuIEFzIHByZWRpY3RlZCwgbWFwbGUgYW5kIGJsYWNrIG9hayBhcmUgY29tcGV0aW5nIGZvciBzb21lIHJlc291cmNlLiJ9DQpwbG90KFRyZWV0eXBlc1sxLDNdLCBtYWluPSJCbGFjayBPYWsgJiBNYXBsZSIpDQpgYGANCg0KYGBge3IgcGxvdHNzc3MsIGZpZy5jYXA9IioqRmlndXJlIDc6KiogUGxvdCBzaG93aW5nIHRoZSB0cmFuc2Zvcm1hdGlvbiBvZiBSaXBsZXkgSyBmb3IgYmxhY2sgb2FrIGFuZCBoaWNrb3J5IHRyZWVzIGluIGEgMjAgYWNyZSBwbG90LiBBcyBwcmVkaWN0ZWQsIHRoZXNlIHRyZWVzIGJlZ2luIHRvIGNsdW1wIGF0IGFib3V0IDUwIGZ0LiJ9DQpwbG90KFRyZWV0eXBlc1sxLDJdLCBtYWluPSJCbGFjayBPYWsgJiBIaWNrb3J5IikNCmBgYA0KDQoNCmBgYHtyIHBsb3QgaW50ZXIzLCBmaWcuY2FwPSIqKkZpZ3VyZSA4OioqIFBsb3Qgc2hvd2luZyB0aGUgdHJhbnNmb3JtYXRpb24gb2YgUmlwbGV5J3MgSyBmb3IgaGlja29yeSBhbmQgbWFwbGUgdHJlZXMgaW4gYSAyMCBhY3JlIHBsb3QuIFRoZXkgYXJlIGNvbXBldGl0aXZlIGF0IGFsbCBkaXN0YW5jZXMgc2hvd24uIn0NCnBsb3QoVHJlZXR5cGVzWzIsM10sIG1haW49IkhpY2tvcnkgJiBNYXBsZSIpDQpgYGANCg0KIyMjIyMjICoqU3VtbWFyeSoqDQoNCkluIHRoZSBjb250ZXh0IG9mIGEgMjAtYWNyZSBwbG90LCB0aGUgcG9pbnQgcGF0dGVybiBhbmFseXNpcyBhYm92ZSByZXZlYWxlZCBzaWduaWZpY2FudCBpbnNpZ2h0cyBpbnRvIHRoZSBzcGF0aWFsIGRpc3RyaWJ1dGlvbiBvZiB0cmVlcywgcGFydGljdWxhcmx5IG1hcGxlLCBibGFjayBvYWssIGFuZCBoaWNrb3J5IHNwZWNpZXMuIEJ5IGV4YW1pbmluZyAkXGhhdHtMfSQsIHRoZSB0cmFuc2Zvcm1lZCBSaXBsZXkncyBLIGZ1bmN0aW9uLCBpdCB3YXMgZXZpZGVudCB0aGF0IGNvbXBldGl0aW9uIGV4aXN0ZWQgYmV0d2VlbiBtYXBsZSBhbmQgdGhlIG90aGVyIHR3byB0cmVlIHR5cGVzIChGaWcuIDYgJiA4KS4gQmV5b25kIGEgZGlzdGFuY2Ugb2YgYXBwcm94aW1hdGVseSA1MCBmZWV0LCBhIHBhdHRlcm4gb2YgY2x1bXBpbmcgZW1lcmdlZCBiZXR3ZWVuIGJsYWNrIG9hayBhbmQgaGlja29yeSwgaW5kaWNhdGluZyBhIHRlbmRlbmN5IGZvciB0aGVzZSBzcGVjaWVzIHRvIGNsdXN0ZXIgdG9nZXRoZXIgKEZpZy4gNykuIENvbnZlcnNlbHksIHByaW9yIHRvIHRoZSA1MC1mb290IHRocmVzaG9sZCwgdGhlIGRpc3RyaWJ1dGlvbiBvZiBibGFjayBvYWsgYW5kIGhpY2tvcnkgZXhoaWJpdGVkIGNvbXBsZXRlIHNwYXRpYWwgcmFuZG9tbmVzcy4NCg0KIyMjIyAyLjINCg0KQmFzZWQgb24gdGhlIGxpbWl0ZWQgaW5mb3JtYXRpb24gSeKAmXZlIGdpdmVuIHlvdSwgaG93IG1pZ2h0IHNvaWwgbW9pc3R1cmUgdmFyeSBpbiB0aGlzIHBsb3Q/IA0KDQojIyMjIyMgKipBbnN3ZXIqKg0KDQpJIGhhdmUgdmVyeSBsaW1pdGVkIHRyZWUga25vd2xlZGdlLCBzbyBJIGhhZCB0byBsb29rIHRoaXMgdXAuIE1hcGxlIHRyZWVzIGFyZSBjb25zaWRlcmVkLCAqKm1lc29waHl0aWMqKiwgbWVhbmluZyB0aGF0IHRoZXkgcmVxdWlyZSBhIG1vZGVyYXRlIGFtb3VudCBvZiB3YXRlciB0byBncm93LiBCb3RoIG9hayBhbmQgaGlja29yeSBhcmUgc3VwcG9zaWRseSBtb3JlIGRyb3VnaHQgdG9sZXJhbnQgYW5kIHJlcXVpcmUgbGVzcyB3YXRlciwgYW5kIGJlY2F1c2Ugb2YgdGhpcywgSSB0aGluayB0aGF0IG1vaXN0dXJlIGxldmVscyBhcmUgaGlnaGVzdCBuZWFyIHRoZSBtYXBsZSB0cmVlcyBvbiB0aGUgc291dGhlcm4gZW5kIG9mIHRoZSBwbG90IChGaWcuIDMgJiA1KS4NCg0KDQpbUmVmZXJlbmNlXShodHRwczovL3NpdGVzLmxzYS51bWljaC5lZHUvY3dkaWNrLWxhYi8yMDE2LzAzLzI3L29hay1oaWNrb3J5LWZvcmVzdC1hLXZlc3RpZ2Utb2YtbmF0aXZlLWFtZXJpY2FuLWxhbmQtdXNlLykNCg0KIyMjICoqMy4gVmFyaW9ncmFtcyAmIEFuaXNvdHJvcHkqKg0KDQojIyMjIDMuMSANCg0KVXNlIHRoZSB2YXJpb2dyYW0gZnVuY3Rpb24gaW4gdGhlIGBgYGdzdGF0YGBgIGxpYnJhcnkgdG8gcGxvdCBhbiBlbXBpcmljYWwgdmFyaW9ncmFtIG9mIHRoZSBwYXJ0aWN1bGF0ZSBtYXR0ZXIuIERlc2NyaWJlIHdoYXQgeW91IHNlZS4gSXMgdGhlcmUgYXV0b2NvcnJlbGF0aW9uIGluIHRoZSBkYXRhPyAqKk91dHB1dDoqKiBBIHBsb3QgYW5kIGEgc2VudGVuY2Ugb3IgdHdvLg0KDQoqKmE6KiogUmVhZCBpbiBgYGBwbV9vYnNlcnZhdGlvbnMucmRzYGBgDQoNCmBgYHtyIHJlYWRpbm9tb2JzfQ0KDQpwbV9zZiA8LSByZWFkUkRTKCJNaWR0ZXJtRGF0YS9kYXRhL3BtX29ic2VydmF0aW9ucy5yZHMiKQ0KDQpgYGANCmBgYHtyfQ0KcG1fZGYgPC0gYXMuZGF0YS5mcmFtZShwbV9zZiwgeHk9VCkNCmBgYA0KDQoNCioqYjoqKiBQbG90IHRoZSBkYXRhIHdpdGggYGBgZ2dwbG90YGBgDQpgYGB7ciBnZ3Bsb3QgZGF0YSAsZmlnLmNhcD0iKipGaWd1cmUgOToqKiBQYXJ0aWN1bGF0ZSBtYXR0ZXIgKHVuaXRsZXNzKSBmb3IgMTAwICRrbV4yJCBzaXRlLiJ9DQoNCnh5TCA9IGRhdGEuZnJhbWUoc3RfY29vcmRpbmF0ZXMoc3RfY2FzdChwbV9zZiRnZW9tZXRyeSwiTVVMVElQT0lOVCIpKSkNCg0KeHlMJHBtIDwtIHBtX3NmJHBtDQoNCiNicmVhayBkYXRhIHVwIA0KeHlMX2RmX211dGF0ZWQgPC0geHlMICU+JQ0KICBtdXRhdGUoVW5pdGxlc3MgPSBjdXQoeHlMJHBtLCBicmVha3MgPSA1KSkNCg0KZ2dwbG90KHh5TF9kZl9tdXRhdGVkKSsNCmdlb21fcG9pbnQoYWVzKHg9WCwgeT1ZLGNvbG9yPVVuaXRsZXNzLCBzaXplPVVuaXRsZXNzKSwgYWxwaGE9MC43KSsNCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobGFiZWxzPWMoJzAuMDAnLCAnMC4yNScsICcwLjUwJywgIjAuNzUiLCAiMS4wMCIpKSsNCiAgc2NhbGVfc2l6ZV9kaXNjcmV0ZShsYWJlbHM9YygnMC4wMCcsICcwLjI1JywgJzAuNTAnLCAiMC43NSIsICIxLjAwIikpKw0KICBsYWJzKHg9IkVBU1RJTkcgKE0pIiwgeT0iTk9SVEhJTkcgKE0pIikNCg0KDQpgYGANCg0KDQoqKmM6KiogQ3JlYXRlIGEgdmFyaW9ncmFtICYgc3VtbWFyeSBzZW50ZW5jZSAoc2VlIGZpZ3VyZSAxMCBjYXB0aW9uKQ0KDQpgYGB7ciB2YXJpb2dyYW0sIGZpZy5jYXA9IioqRmlndXJlIDEwOioqIFZhcmlvZ3JhbSBzaG93aW5nIGlzb3Ryb3B5LiBQb2ludHMgYXJlIGF1dG9jb3JyZWxhdGVkIHdpdGggYSBzZXBhcmF0aW9uIGRpc3RhbmNlIG9mIDAtMTAwMCBtLCBhZnRlciB3aGljaCB0aGVyZSBpcyBubyBsb25nZXIgYW55IG9idmlvdXMgYXV0b2NvcnJlbGF0aW9uLiJ9DQpwbVZhciA8LSB2YXJpb2dyYW0ocG1+MSwgcG1fc2YsIGNsb3VkPUYpDQpwbG90KHBtVmFyLHBjaD0yMCxjZXg9MSwgY29sPWMoInJlZCIsICJvcmFuZ2UiLCAicGluayIsICJzdGVlbGJsdWUiKSwNCiAgICAgeWxhYj1leHByZXNzaW9uKFNlbWl2YXJpYW5jZX4oZ2FtbWEpKSwNCiAgICAgeGxhYj0iRGlzdGFuY2UgKG0pIiwgbWFpbiA9ICJQYXJ0aWN1bGF0ZSBNYXR0ZXIiKQ0KDQpgYGANCg0KIyMjIyAzLjINCg0KUmVwZWF0IGJ1dCB1c2UgdGhlIGFscGhhIGFyZ3VtZW50IHRvIGxvb2sgYXQgZGlyZWN0aW9uYWxpdHkgaW4gdGhlIGRhdGEuIElmIHlvdSBzZXQgYGBgYWxwaGFgYGAgdG8gYygwLDQ1LDkwLDEzNSkgeW914oCZbGwgYmUgbG9va2luZyBhdCBheGVzIGZyb20gc291dGggdG8gbm9ydGgsIHNvdXRod2VzdCB0byBub3J0aHdlc3QsIHdlc3QgdG8gZWFzdCwgYW5kIHNvdXRoZWFzdCB0byBub3J0aHdlc3QuIERlc2NyaWJlIHdoYXQgeW91IHNlZS4gSG93IGhhcyB5b3VyIHVuZGVyc3RhbmRpbmcgY2hhbmdlZD8gKipPdXRwdXQ6KiogQSBwbG90IGFuZCBhIHNlbnRlbmNlIG9yIHR3by4NCg0KKiphOioqIENyZWF0ZSBhIGRpcmVjdGlvbmFsIHZhcmlvZ3JhbSAmIHN1bW1hcnkgc2VudGVuY2UgKHNlZSBmaWd1cmUgMTEgY2FwdGlvbikNCg0KYGBge3IgdmFyaW9ncmFtMiwgZmlnLmNhcD0iKipGaWd1cmUgMTE6KiogRGlyZWN0aW9uYWwgdmFyaW9ncmFtIHNob3dpbmcgYW5pc290cm9weSwgd2l0aCBhbGwgZGlyZWN0aW9ucyBleGNlcHQgNDUgbG9va2luZyByZWxhdGl2ZWx5IHNpbWlsYXIuIFRoZSAwIGdyYXBoIHNob3dzIFMgdG8gTiwgNDUgc2hvd3MgU1cgdG8gTlcsIDkwIHNob3dzIFcgdG8gRSwgYW5kIDEzNSBzaG93cyBTRSB0byBORS4gVGhlcmUgc2VlbXMgdG8gYmUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gZnJvbSBTVyB0byBOVyBpbiB0aGUgNDUgcGxvdCBhdCBkaXN0YW5jZXMgb2YgdXAgdG8gMTAwMCBtIGJldHdlZW4gcG9pbnRzLiBBZnRlciAxMDAwIG0gYmV0d2VlbiBwb2ludHMgdGhlcmUgaXMgbm8gc3BhdGlhbCBhdXRvY29ycmVsYXRpb24uIn0NCnBtVmFyIDwtIHZhcmlvZ3JhbShwbX4xLCBwbV9zZiwgYWxwaGE9YygwLDQ1LDkwLDEzNSkpDQpwbG90KHBtVmFyLHBjaD0yMCxjZXg9MSxjb2w9YygicmVkIiwgIm9yYW5nZSIsICJwaW5rIiwgInN0ZWVsYmx1ZSIpLA0KICAgICB5bGFiPWV4cHJlc3Npb24oU2VtaXZhcmlhbmNlfihnYW1tYSkpLA0KICAgICB4bGFiPSJEaXN0YW5jZSAobSkiLCBtYWluID0gIlBhcnRpY3VsYXRlIE1hdHRlciBEaXJlY3Rpb25hbGl0eSIpDQpgYGANCg0KDQojIyMgKio0LiBNb3JhbidzIEkgJiBTY2FsZSoqDQoNCiMjIyMgNC4xDQoNCk1ha2UgYSBtYXAgb2YgdGhlIGNhbm9weSBoZWlnaHQgZGF0YS4gU2hvdyBlYWNoIHBsb3QgKGkuZS4sIEhBUlYgMDM3LCBIQVJWIDA0MywgSEFSViAwNDYsIGFuZCBIQVJWIDA0NykuIA0KDQoqKmE6KiogcmVhZCBpbiB0aGUgZGF0YQ0KYGBge3IgZGF0YXJlYWRzMX0NCmNhbm9weWhlaWdodCA8LSByZWFkUkRTKCJNaWR0ZXJtRGF0YS9kYXRhL2hhcnZTdWJzZXRDSE0ucmRzIikNCg0KYGBgDQoNCioqYjoqKiBTdW1tYXJpemUgdGhlIGRhdGEgZGVldHMgJiBjb252ZXJ0DQoNCmBgYHtyIHN1bW1hcnl9DQojc3VtbWFyeShjYW5vcHloZWlnaHQpDQoNCiNjcnMoY2Fub3B5aGVpZ2h0KQ0KDQp4eUwyIDwtIGRhdGEuZnJhbWUoc3RfY29vcmRpbmF0ZXMoc3RfY2FzdChjYW5vcHloZWlnaHQkZ2VvbWV0cnkpLCJNVUxUSVBPSU5UIiwgIGNycyA9IHN0X2NycygzMjYxOCkpKQ0KDQp4eUwyJGNvdmVydHlwZSA8LSBjYW5vcHloZWlnaHQkY292ZXJ0eXBlDQp4eUwyJGNobSA8LSBjYW5vcHloZWlnaHQkY2htDQp4eUwyJHBsb3RJRCA8LSBjYW5vcHloZWlnaHQkcGxvdElEDQoNCg0KYGBgDQoqKmM6KiogQnJpbmcgaW4gQ0hNIGRhdGENCg0KYGBge3IgY2htfQ0KQ0hNX0hhcnYgPC0gcmFzdGVyKCJkYXRhL05FT04tRFMtQWlyYm9ybmUtUmVtb3RlLVNlbnNpbmcvSEFSVi9DSE0vSEFSVl9jaG1Dcm9wLnRpZiIpDQpgYGANCg0KKipkOioqIENvbnZlcnQgYGBgLnRpZmBgYCBpbnRvIGBgYGRmYGBgDQpgYGB7ciBjb252ZXJ0fQ0KQ0hNX0hhcnZfZGYgPC0gYXMuZGF0YS5mcmFtZShDSE1fSGFydiwgeHk9VCkNCmBgYA0KDQoqKmU6KiogUGxvdCBtYXAgdXNpbmcgYGBgZ2dwbG90YGBgDQpgYGB7ciBwbHRvcywgd2FybmluZz1GLCBtZXNzYWdlPUYsIGNhY2hlPVR9DQphIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IENITV9IYXJ2X2RmICwgYWVzKHggPSB4LCB5ID0geSwgZmlsbCA9IEhBUlZfY2htQ3JvcCkpICsNCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYW1lPSJNIikrDQogIGdlb21fc2YoZGF0YSA9IGNhbm9weWhlaWdodCRnZW9tZXRyeSwgY29sb3I9YWxwaGEoIndoaXRlIiwwLjUpKSsNCiAgY29vcmRfc2YoKSsNCiAgbGFicyh4PSJFQVNUSU5HIChNKSIsIHk9Ik5PUlRISU5HIChNKSIsIHRpdGxlPSJDYW5vcHkgSGVpZ2h0Iiwgc3VidGl0bGUgPSAiVVRNIFpvbmUgMThOIikrDQogICAgeGxpbSg3MzE0MDAsIDczMjAwMCkrDQogIHlsaW0oNDcxMzE1MCwgNDcxMzgwMCkrDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3QgPSAxKSkrDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDczMTUxMCwgeT00NzEzMzU1LCBsYWJlbCA9ICI0NiIsIHNpemU9Mi4yKSsNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gNzMxOTMyLjUsIHk9NDcxMzIzMi41LCBsYWJlbCA9ICI0NyIsIHNpemU9Mi4yKSsNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gNzMxODQwLCB5PTQ3MTM3MTUsIGxhYmVsID0gIjQzIiwgc2l6ZT0yLjIpKw0KICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDczMTYzNSwgeT00NzEzMzAwLCBsYWJlbCA9ICIzNyIsIHNpemU9Mi4yKQ0KDQogIA0KDQpgYGANCg0KDQoqKmY6KiogVHJ5IHRvIG1ha2Ugd2hhdCBBbmR5IG1hZGUgKGFuZCBmYWlsIGJlY2F1c2UgcG9pbnRzIGp1c3QgYXJlIG5vdCByYXN0ZXJzKQ0KYGBge3Igb3RoZXIgcGxvdHMsIHdhcm5pbmc9Rn0NCkhhcnZfMDQzIDwtIHN1YnNldChjYW5vcHloZWlnaHQsIHBsb3RJRD09IkhBUlZfMDQzIikNCg0KDQpiIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhPUhhcnZfMDQzJGdlb21ldHJ5LCBhZXMoY29sb3I9SGFydl8wNDMkY2htKSwgc2l6ZT01KSsNCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG5hbWU9Im0iKSsNCiAgIHhsaW0oYyg3MzE4MDAsIDczMTg5MCkpKw0KICB5bGltKGMoNDcxMzY3NSwgNDcxMzc1NSkpDQoNCg0KYGBgDQoNCg0KKipnOioqIENyZWF0ZSBwb2x5Z29ucyBhcm91bmQgcG9pbnQgc2l0ZXMgYW5kIGNsaXAgYGBgQ0hNX0hhcnZgYGAgdG8gcG9seWdvbnMNCg0KYGBge3IgZ2V0dGluZyBjcmF6eSwgd2FybmluZz1GQUxTRSwgZXZhbD1UfQ0KI2FkZHMgcG9seWdvbiB0byBvdXRsaW5lIGVhY2ggcGxvdA0KcG9seWdvbnNfSGFydiA8LSBjYW5vcHloZWlnaHQgJT4lDQogIHN0X2FzX3NmKGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSkgJT4lDQogIGdyb3VwX2J5KHBsb3RJRCkgJT4lDQogIHN1bW1hcml6ZShnZW9tZXRyeSA9IHN0X3VuaW9uKGdlb21ldHJ5KSkgJT4lDQogIHN0X2NvbnZleF9odWxsKCkNCg0KI2NvbnZlcnQgcG9seWdvbnMgdG8gc2hhcGUgZmlsZSAoYmVjYXVzZSBpdCBpcyBlYXNpZXIgdG8gd29yayB3aXRoKToNCiNzdF93cml0ZShwb2x5Z29uc19IYXJ2LCAiZGF0YS9IYXJ2cGxvdHMuc2hwIiwgZHJpdmVyPSJFc3JpIFNoYXBlZmlsZSIpDQoNCiNyZWFkIGluIG5ldyBzaGFwZSBmaWxlDQpwb2x5Z29uc19IYXJ2X3NocCAgPC0gcmVhZF9zZignZGF0YS9IYXJ2cGxvdHMuc2hwJykNCg0KI2NsaXAgdGhlIHJhc3RlciBmb3IgY2Fub3B5IGhlaWdodCAodGhlIC50aWYpIHRvIHRoZSBib3VkYXJ5IG9mIHlvdXIgbmV3IHNoYXBlIGZpbGUNCm1hc2tlZCA8LSBtYXNrKENITV9IYXJ2LCBwb2x5Z29uc19IYXJ2X3NocCkgI2NyZWF0ZXMgcmFzdGVyIGxheWVyIA0KDQojbm90ZSB0aGF0IG1hc2sgZnVuY3Rpb24gV0lMTCBOT1QgS05JVCBpZiB5b3UgaGF2ZSBjYWNoZT1UIGluIHlvdXIgY2h1bmsuIFRvb2sgbWUgYSBsb25nIHRpbWUgdG8gZ2V0IHRoaXMgdG8ga25pdC4NCg0KI21ha2UgZGF0YWZyYW1lIGZvciBnZ3Bsb3QNCm1hc2tlZCA8LSBhcy5kYXRhLmZyYW1lKG1hc2tlZCwgeHk9VCkNCg0KYGBgDQoNCg0KKipoOioqIENyZWF0ZSBwbG90cyB1c2luZyBgYGBnZ3Bsb3RgYGAgYGBgZ2VvbV9yYXN0ZXJgYGAgZnVuY3Rpb24gd2l0aCBsaW1pdHMNCmBgYHtyIG1ha2UgcGxvdHMgb2YgcGxvdHN9DQoNCiNidWlsZCBjdXRlIGNpcmNsZXMgZm9yIHlvdXIgZmluYWwgbWFwDQpIXzA0MyA8LSBnZ3Bsb3QoKSArDQogIGdlb21fcmFzdGVyKGRhdGEgPSBuYS5vbWl0KG1hc2tlZCksIGFlcyh4LCB5LCBmaWxsPUhBUlZfY2htQ3JvcCksIHNob3cubGVnZW5kID0gRikrDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hLnZhbHVlID0gIndoaXRlIikrDQogIHhsaW0oYyg3MzE4MDAsIDczMTg5MCkpKw0KICB5bGltKGMoNDcxMzY3NSwgNDcxMzc1NSkpKw0KICBsYWJzKHg9IiIsIHk9IiIpKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIA0KICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCANCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiwgc2l6ZSA9IDE1KSkNCg0KSF8wNDcgPC0gZ2dwbG90KCkgKw0KICBnZW9tX3Jhc3RlcihkYXRhID0gbmEub21pdChtYXNrZWQpLCBhZXMoeCwgeSwgZmlsbD1IQVJWX2NobUNyb3ApLCBzaG93LmxlZ2VuZCA9IEYpKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYS52YWx1ZSA9ICJ3aGl0ZSIpKw0KICB4bGltKGMoNzMxODkwLCA3MzE5NzUpKSsNCiAgeWxpbShjKDQ3MTMxOTAsIDQ3MTMyNzUpKSsNCiAgbGFicyh4PSIiLCB5PSIiKSsNCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCANCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksIA0KICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCANCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIsIHNpemUgPSAxNSkpIA0KDQoNCg0KSF8wMzcgPC0gZ2dwbG90KCkgKw0KICBnZW9tX3Jhc3RlcihkYXRhID0gbmEub21pdChtYXNrZWQpLCBhZXMoeCwgeSwgZmlsbD1IQVJWX2NobUNyb3ApLCBzaG93LmxlZ2VuZCA9IEYpKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYS52YWx1ZSA9ICJ3aGl0ZSIpKw0KICB4bGltKGMoNzMxODkwLCA3MzE5NzUpKSsNCiAgeWxpbShjKDQ3MTMxOTAsIDQ3MTMyNzUpKSsNCiAgbGFicyh4PSIiLCB5PSIiKSsNCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCANCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksIA0KICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCANCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIsIHNpemUgPSAxNSkpIA0KDQoNCkhfMDQ2IDwtIGdncGxvdCgpICsNCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IG5hLm9taXQobWFza2VkKSwgYWVzKHgsIHksIGZpbGw9SEFSVl9jaG1Dcm9wKSwgc2hvdy5sZWdlbmQgPSBGKSsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobmEudmFsdWUgPSAid2hpdGUiKSsNCiAgeGxpbShjKDczMTQ3MiwgNzMxNTU1KSkrDQogIHlsaW0oYyg0NzEzMzE1LCA0NzEzMzk1KSkrDQogIGxhYnMoeD0iIiwgeT0iIikrDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLCANCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiLCBzaXplID0gMTUpKSANCmBgYA0KDQoNCioqaToqKiBQbG90cw0KYGBge3IgcGxvdGEsIGZpZy5jYXA9IioqRmlndXJlIDEyOioqIFNob3dpbmcgYWxsIHBsb3RzIGluY2x1ZGVkIGluIHRoZSBhdXRvY29ycmVsYXRpb24gYW5hbHlzaXMgb2YgdGhlIEhhcnZhcmQgdHJlZSBzaXRlcy4gSGVyZSB5b3UgY2FuIHNlZSB0aGF0IHBsb3RzIDQ2IGFuZCA0NyBhcmUgY2xvc2VzdCBpbiBwcm94aW1pdHkgdG8gb25lIGFub3RoZXIsIHdoaWNoIHdvdWxkIG1ha2UgbWUgc3VzcGVjdCB0aGV5IGhhdmUgc2ltaWxhciwgaWYgbm90IGlkZW50aWNhbCBjb3JyZWxvZ3JhbXMgZm9yIHRoZXIgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24uIFRoZSBsZWdlbmQgaXMgc2hvd2luZyBjYW5vcHkgaGVpZ2h0IGluIG1ldGVycy4gVGhlIGNhbm9weSBoZWlnaHQgaXMgaGlnaGVzdCBpbiB0aGUgc291dGhlcm4gcGFydCBvZiB0aGUgbWFwIGFuZCBpcyBsb3dlc3QgaW4gdGhlIG5vcnRoZWFzdCBlbmQgb2YgdGhlIHBsb3QsIHdpdGggYSBmZXcgbW9yZSBsb3cgY2Fub3B5IHNpdGVzIG9uIHRoZSB3ZXN0ZXJuIHNpZGUgb2YgdGhlIHBsb3QuIn0NCmENCmBgYA0KDQpgYGB7ciBhbGxwbG90cywgZmlnLmNhcD0iKipGaWd1cmUgMTM6KiogU2hvd2luZyBjYW5vcHkgaGVpZ2h0cyBvZiBlYWNoIHBsb3QgYWJvdmUsIHVzaW5nIHRoZSBzYW1lIGxlZ2VuZC4gUGxvdHMgMzcgYW5kIDQzIChBICYgQikgYXJlIGJvdGggZXZlcmdyZWVuIHBsb3RzIG1hZGUgdXAgb2Ygd2hpdGUgcGluZSAoKlBpbnVzIHN0cm9idXMqKSBhbmQgZWFzdGVybiBoZW1sb2NrICgqVHN1Z2EgY2FuYWRlbnNpcyopLiBQbG90cyA0NiBhbmQgNDcgKEMgJiBEKSBhcmUgbWFkZSB1cCBvZiBkZWNpZHVvdXMgYnJvYWRsZWFmIHRyZWVzLCBwcmVkb21pbmF0ZWx5IGNvbXByaXNlZCBvZiByZWQgb2FrICgqUXVlcmN1cyBydWJyYSopIGFuZCByZWQgbWFwbGUgKCpBY2VyIHJ1YnJ1bSopLiIgfQ0KZ2dhcnJhbmdlKEhfMDM3LCBIXzA0MywgSF8wNDYsIEhfMDQ3LCBsYWJlbHMgPSBjKCJBLiAzNyIsICJCLiA0MyIsICJDLiA0NiIsICJELiA0NyIpLA0KICAgICAgICAgICAgICAgICAgICBuY29sID0gMiwgbnJvdyA9IDIpDQpgYGANCg0KIyMjIyA0LjINCg0KQ2FsY3VsYXRlIGEgY29ycmVsb2dyYW0gZm9yIGVhY2ggcGxvdC4gRGVzY3JpYmUgdGhlIGJlaGF2aW9yIG9mIE1vcmFu4oCZcyBJIGZvciBlYWNoIHBsb3QuDQoNCioqYToqKiBTZXQgdXAgdGhlIGRhdGENCg0KYGBge3IgeHl6fQ0KY29yXzAzNyA8LSBzdWJzZXQoY2Fub3B5aGVpZ2h0LCBwbG90SUQ9PSJIQVJWXzAzNyIpDQpjb3JfMDQzIDwtIHN1YnNldChjYW5vcHloZWlnaHQsIHBsb3RJRD09IkhBUlZfMDQzIikNCmNvcl8wNDYgPC0gc3Vic2V0KGNhbm9weWhlaWdodCwgcGxvdElEPT0iSEFSVl8wNDYiKQ0KY29yXzA0NyA8LSBzdWJzZXQoY2Fub3B5aGVpZ2h0LCBwbG90SUQ9PSJIQVJWXzA0NyIpDQoNCiMwMzcNClhfMDM3IDwtIHN0X2Nvb3JkaW5hdGVzKGNvcl8wMzcpWywxXQ0KWV8wMzcgPC0gc3RfY29vcmRpbmF0ZXMoY29yXzAzNylbLDJdDQpDSF8wMzcgPC0gY29yXzAzNyRjaG0NCg0KIzA0Mw0KWF8wNDMgPC0gc3RfY29vcmRpbmF0ZXMoY29yXzA0MylbLDFdDQpZXzA0MyA8LSBzdF9jb29yZGluYXRlcyhjb3JfMDQzKVssMl0NCkNIXzA0MyA8LSBjb3JfMDQzJGNobQ0KDQojMDQ2DQpYXzA0NiA8LSBzdF9jb29yZGluYXRlcyhjb3JfMDQ2KVssMV0NCllfMDQ2IDwtIHN0X2Nvb3JkaW5hdGVzKGNvcl8wNDYpWywyXQ0KQ0hfMDQ2IDwtIGNvcl8wNDYkY2htDQoNCiMwNDcNClhfMDQ3IDwtIHN0X2Nvb3JkaW5hdGVzKGNvcl8wNDcpWywxXQ0KWV8wNDcgPC0gc3RfY29vcmRpbmF0ZXMoY29yXzA0NylbLDJdDQpDSF8wNDcgPC0gY29yXzA0NyRjaG0NCmBgYA0KDQoqKmI6KiogQ2FsY3VsYXRlIG1heCBkaXN0YW5jZQ0KDQpgYGB7ciBkaXN0fQ0KIzAzNw0KKG1heChYXzAzNyktbWluKFhfMDM3KSkvMw0KKG1heChZXzAzNyktbWluKFlfMDM3KSkvMw0KDQoNCmBgYA0KDQoqKmM6KiogUGxvdCB0aGUgY29ycmVsb2dyYW0gZm9yIGNvbnRpbnVvdXMgZGF0YSAmIGRlc2NyaWJlIHRoZSBwbG90cyAoRmlnLiAxNCBjYXB0aW9uKQ0KYGBge3IgY29ybywgY2FjaGU9VCwgZmlnLmNhcD0iKipGaWd1cmUgMTQ6KiogTW9yYW4ncyBJIHNwYXRpYWwgY29ycmVsb2dyYW0gb2YgY2Fub3B5IGhlaWdodCBmb3IgSGFydmFyZCB0cmVlIHBsb3RzLiBUaGVyZSBzZWVtcyB0byBiZSBzdHJvbmcgc3BhdGlhbCBhdXRvY29ycmVsYXRpb25zIHVwIHRvIDUgbSBmb3IgcGxvdHMgQSAmIEIgYnV0IHRoaXMgZHJvcHMgb2ZmIHJhcGlkbHkgYWZ0ZXIgNSBtLiBUaGUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgc3Ryb25nIGZvciBwbG90cyBDICYgRCBhdCBjbG9zZSBkaXN0YW5jZXMgYnV0IHRoZSBjb3JyZWxhdGlvbiBkcm9wcyBtdWNoIGxlc3MgcmFwaWRseSB0aGF0IHRob3NlIGZvciB0aGUgZXZlcmdyZWVuIHRyZWVzIChBICYgQikuIEl0IGlzIG5vdCBzdXJwcmlzaW5nIHRoYXQgdGhlIHBsb3RzIHdpdGggc2ltaWxhciB0cmVlIHN0cnVjdHVyZSBhcmUgaWRlbnRpY2FsIGluIHRoZWlyIGNvcnJlbG9ncmFtIG91dHB1dHMuIFBsb3RzIDM3ICYgNDYgKEEgJiBDKSBhcmUgdmVyeSBjbG9zZSBpbiBwcm94aW1pdHkgdG8gb25lIGFub3RoZXIgYW5kIGl0IGlzIHN1cnByaXNpbmcgdGhhdCB0aGV5IGFyZSBub3QgbW9yZSBzaW1pbGFyIGluIGNhbm9weSBoZWlnaHQsIHN1Z2dlc3RpbmcgdGhhdCB0cmVlIGNvbXBvc2l0aW9uIGNhbiBhbHNvIGNoYW5nZSByYXBpZGx5LCBzcGVjdWxhdGl2ZWx5IGR1ZSB0byBlbGV2YXRpb24gYW5kIGNhcmRpbmFsIGRpcmVjdGlvbiBvZiB0aGUgcGxvdHMuIiB9DQoNCiMgMDM3DQpJXzAzNyA8LSBzcGxpbmUuY29ycmVsb2coeD1YXzAzNywgeT1ZXzAzNywgej1DSF8wMzcsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2FtcD0xMDAsIHhtYXg9NDAsIHF1aWV0PVRSVUUpDQoNCg0KIyAwNDMNCklfMDQzIDwtIHNwbGluZS5jb3JyZWxvZyh4PVhfMDQzLCB5PVlfMDQzLCB6PUNIXzA0MywgDQogICAgICAgICAgICAgICAgICAgICAgICAgcmVzYW1wPTEwMCwgeG1heD00MCwgcXVpZXQ9VFJVRSkNCg0KIyAwNDYNCklfMDQ2IDwtIHNwbGluZS5jb3JyZWxvZyh4PVhfMDQ2LCB5PVlfMDQ2LCB6PUNIXzA0NiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgcmVzYW1wPTEwMCwgeG1heD00MCwgcXVpZXQ9VFJVRSkNCg0KIyAwNDcNCklfMDQ3IDwtIHNwbGluZS5jb3JyZWxvZyh4PVhfMDQ3LCB5PVlfMDQ3LCB6PUNIXzA0NywgDQogICAgICAgICAgICAgICAgICAgICAgICAgcmVzYW1wPTEwMCwgeG1heD00MCwgcXVpZXQ9VFJVRSkNCg0KcGFyKG1mcm93PWMoMiwgMikpDQpwbG90KElfMDM3LCBtYWluPSJBLiAzNyBNb3JhbidzIEkiKQ0KcGxvdChJXzA0MywgbWFpbj0iQi4gNDMgTW9yYW4ncyBJIikNCnBsb3QoSV8wNDYsIG1haW49IkEuIDQ2IE1vcmFuJ3MgSSIpDQpwbG90KElfMDQ3LCBtYWluPSJBLiA0NyBNb3JhbidzIEkiKQ0KYGBgDQoNCg0KIyMjIyA0LjMNCg0KU3BlY3VsYXRlIGFib3V0IGhvdyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpcyBsaW5rZWQgdG8gdGhlIGNoYXJhY3RlcmlzdGljIHNjYWxlIG9mIHRoZSB0d28gZGlmZmVyZW50IGZvcmVzdCB0eXBlcy4gQmFja2luZyB1cCBhbnkgd2lsZCBzcGVjdWxhdGlvbiB3aXRoIHRoZSBsaXRlcmF0dXJlIGlzIGVuY291cmFnZWQuDQoNCg0KQ3Jvd24gc2hhcGVzIGFuZCBjYW5vcHkgaGVpZ2h0IG9mIGJvdGggZXZlcmdyZWVuIGFuZCBkZWNpZHVvdXMgZm9yZXN0cyBsaWtlbHkgaW5mbHVlbmNlIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIHBhdHRlcm5zIGluIHRoZXNlIHBsb3RzLiBFdmVyZ3JlZW4gZm9yZXN0cyBsaWtlbHkgc2hvdyBzdHJvbmdlciBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBhdCBzbWFsbGVyIHNjYWxlcyAoRmlnLiAxNEEgJiBCKSBiZWNhdXNlIHRoZXkgaGF2ZSBkZW5zZXIgY2Fub3BpZXMsIHdoaWxlIGRlY2lkdW91cyBmb3Jlc3RzIHNlZW0gdG8gb25seSBzaG93IHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGF0IGxhcmdlciBzY2FsZXMgYmVjYXVzZSB0aGV5IGhhdmUgYnJvYWRlciwgb3BlbiBjYW5vcGllcyAoRmlnLiAxNEMgJiBEKSwgdGhvdWdoIHRoZXJlIGFyZSBsaWtsZXkgb3RoZXIgZmFjdG9ycyBpbmZsdWVuY2luZyB0aGlzIGFzIHdlbGwuIFRoaXMgc3BlY3VsYXRpb24gaXMgc3VwcG9ydGVkIGJ5IGVhY2ggb2YgdGhlIHByb3ZpZGVkIHBhcGVyIHJlYWRpbmdzIGluIG91ciBtaWR0ZXJtLCB3aGljaCBhbGwgc3VnZ2VzdCB0aGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBvcmdhbmlzbWFsIGNoYXJhY3RlcmlzdGljcyBhbmQgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgdmVyeSBjb21wbGV4IGFuZCBpbmZsdWVuY2VkIGJ5IGEgcmFuZ2Ugb2YgdGhpbmdzIGluY2x1ZGluZyBzcGVjaWVzIGNvbXBvc2l0aW9uLCBjYW5vcHkgc3RydWN0dXJlLCBzZXgsIHNjYWxlLCBhbmQgZW52aXJvbm1lbnRhbCBjb25kaXRpb25zLg0KDQoNCjxkaXYgY2xhc3M9InRvY2lmeS1leHRlbmQtcGFnZSIgZGF0YS11bmlxdWU9InRvY2lmeS1leHRlbmQtcGFnZSIgc3R5bGU9ImhlaWdodDogMDsiPjwvZGl2Pg0K