Read in the packages. The working directory is wherever the R Notebook is located. Note that RStoolbox has some dependencies that are kind of difficult to install on a Mac. The package makes running a PCA on total climate space super easy and has a lot of other functionality, so I think it’s worth the headache.

packages <- c("raster", "ggbiplot", "tidyverse", "sf", "RStoolbox", "leaflet", "maps", "plotly") #RStoolbox has some dependencies like openMP that can be difficult to compile on a Mac (needed for the dependent package "caret"). If you have High Sierra OS or newer, search for instructions specific to your OS- it's a lot easier than older OS's.
lapply(packages, require, character.only = TRUE)

Read in the spreadsheet and take a look at the data.

###read in spreadsheet
loc <- read.csv("worksheets/all-species.csv")
#make locality shape file and assign WGS coord system
coord.points <- st_as_sf(loc, coords = c("longitude", "latitude"), 
                         crs = 4326, agr = "constant")
#Take a gander at the head and structure of the data
head(loc)
str(loc)
'data.frame':   714 obs. of  9 variables:
 $ genus    : Factor w/ 9 levels "acanthoxyla",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ species  : Factor w/ 17 levels "acornutus","annulata",..: 16 16 16 16 16 16 16 16 16 16 ...
 $ id       : Factor w/ 714 levels "acan-sp_1","acan-sp_10",..: 1 46 57 68 79 90 101 112 123 2 ...
 $ latitude : num  -35.3 -35.7 -35.7 -35.3 -35.9 ...
 $ longitude: num  173 174 174 174 174 ...
 $ locality : Factor w/ 608 levels "0.5 km S of carpark, Puhipuhi Scenic Reserve, Kaikoura",..: 585 578 539 379 98 104 106 15 172 30 ...
 $ X        : logi  NA NA NA NA NA NA ...
 $ X.1      : logi  NA NA NA NA NA NA ...
 $ X.2      : logi  NA NA NA NA NA NA ...

Map

Plot a leaflet map of the localities. The leaflet map is interactive. You can click on the localities and a flag with some metadata will pop up!

#load a world map for plotting
w.map <- map("world", plot = FALSE)
#make color palette
pal <- colorFactor(palette = "inferno", domain = NULL)
#create popup labels for points
popup.label <- paste(coord.points$genus, coord.points$species, "<br>",
                     coord.points$id, "<br>",
                     coord.points$locality)
#plot in leaflet
l <- leaflet(data = w.map) %>% 
  addTiles() %>%
  fitBounds(lng1 = 165, lng2 = 185, lat1 = -30, lat2 = -55) %>%
  addCircleMarkers(data = coord.points,
                   color = ~pal(genus),
                   radius = 3,
                   popup = popup.label) %>%
  addLegend(data = coord.points, "bottomright", pal = pal, values = ~genus, opacity = .9)
l

PCA-Genera

Climate Data

Obtain the bioclim layers for analysis. I’m using all 19 for this preliminary exploration. I plotted the first bioclim just to make sure nothing seems wonky.

##get worldclim data
w <- getData("worldclim", var = "bio", res = 0.5, lon = 173, lat = -35)
#check it out
plot(w,1, xlim = c(165, 185), ylim= c(-55, -33))

PCA by locality

This is a PCA of the climate data extracted for each locality, rather than a PCA of the total climate space.

Run the pca and check out variable loadings and proportion of variance explained by components.

#extract data from worldclim for each locality. Making this into a data frame with columns labeled so the row labeling lines up after I remove the NAs.
#extract data from worldclim for each locality.
loc.clim <- data.frame(genus = coord.points$genus,
                       species = coord.points$species,
                       id = coord.points$id,
                       locality = coord.points$locality,
                       coords = as.character(coord.points$geometry),
                       raster::extract(w, coord.points, method = "simple")) %>% na.omit()
#make a matrix of only bioclim values
clim.mat <- loc.clim[,grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca <- prcomp(clim.mat, scale = TRUE)
summary.pca <- summary(clim.pca) #check out the components

Two plots: One plot of the PCA colored according to genus, with convex hulls surrounding the genera. It looks like this reflects a latitudinal gradient in temperature! You can interact with the PCA plot by clicking on points to view associated metadata. You can isolate the genus you want to view by double clicking the genus in the legend! You can also remove a genus by clicking on it once. There’s some other functionality you can explore in the toolbar at the top of the plot.

#add pca results to loc.clim data frame
loc.clim <- data.frame(loc.clim, clim.pca$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1, df$PC2), ]
hulls <- plyr::ddply(loc.clim, "genus", find_hull)
#make an interactive plot in plotly
p <- ggplot(data = loc.clim, aes(x = PC1, y = PC2, col = genus, fill = genus)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "inferno") + 
  scale_fill_viridis_d(option = "inferno") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly <- ggplotly(p, tooltip = c("text"))
#plot biplot
b <- ggbiplot(clim.pca, groups = loc.clim$genus, alpha = .7) +
  scale_color_viridis_d(option = "inferno") + 
  ggtitle("Biplot of extracted climate")

summary.pca
Importance of components:
                          PC1    PC2     PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10
Standard deviation     2.8205 2.5959 1.29925 1.03634 0.86397 0.75029 0.35359 0.22905 0.13868 0.11203
Proportion of Variance 0.4187 0.3547 0.08885 0.05653 0.03929 0.02963 0.00658 0.00276 0.00101 0.00066
Cumulative Proportion  0.4187 0.7734 0.86222 0.91874 0.95803 0.98766 0.99424 0.99700 0.99801 0.99867
                          PC11   PC12    PC13    PC14    PC15    PC16    PC17    PC18      PC19
Standard deviation     0.09749 0.0756 0.07171 0.04711 0.03566 0.03063 0.01582 0.01221 5.341e-16
Proportion of Variance 0.00050 0.0003 0.00027 0.00012 0.00007 0.00005 0.00001 0.00001 0.000e+00
Cumulative Proportion  0.99917 0.9995 0.99975 0.99986 0.99993 0.99998 0.99999 1.00000 1.000e+00
knitr::kable(round(clim.pca$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 -0.343 -0.023 -0.148
bio2_411 0.248 0.051 -0.528
bio3_411 -0.133 0.040 -0.425
bio4_411 0.302 0.062 -0.295
bio5_411 -0.297 -0.009 -0.376
bio6_411 -0.352 -0.029 0.000
bio7_411 0.284 0.041 -0.420
bio8_411 -0.191 0.046 -0.205
bio9_411 -0.297 -0.060 0.060
bio10_411 -0.332 -0.017 -0.220
bio11_411 -0.349 -0.034 -0.072
bio12_411 0.048 -0.381 -0.005
bio13_411 0.009 -0.381 -0.033
bio14_411 0.050 -0.372 -0.064
bio15_411 -0.208 -0.006 -0.057
bio16_411 0.004 -0.382 -0.016
bio17_411 0.076 -0.372 -0.024
bio18_411 0.081 -0.364 -0.073
bio19_411 -0.038 -0.369 0.002

Total Climate PCA

I conducted a PCA of the total climate space in New Zealand and extracted values for each locality.

Run the pca and check out variable loadings and proportion of variance explained by components.

#subset the world map to just New Zealand to make the analysis tractable
lims<-c(165,185, -55,-33)
submap<-crop(w,lims)
#run a scaled PCA on the climate data
pcamap<-rasterPCA(submap, spca=TRUE)
summary.pca.total <- summary(pcamap$model) #check out the components

Plot the principle components in geographic space.

#plot the PCs
plot(pcamap$map, 1:3)

Plot the first two PCs as a scatter plot. I couldn’t figure out how to plot a biplot with the data structure rasterPCA outputs. It seems like the latitudinal gradient in climate is spread across PC axes.

#extract data from pca for each locality. Making this into a data drame with columns labeled so the row labeling lines up after I remove the NAs.
loc.total.clim <- data.frame(genus = coord.points$genus,
                       species = coord.points$species,
                       id = coord.points$id,
                       locality = coord.points$locality,
                       coords = as.character(coord.points$geometry),
                       raster::extract(pcamap$map, coord.points, method = "simple")) %>% na.omit()
#make convex hull of genera
find.hull.total <- function(df) df[chull(df$PC1, df$PC2), ]
hulls.total <- plyr::ddply(loc.total.clim, "genus", find.hull.total)
#make an interactive plot in plotly
p.total <- ggplot(data = loc.total.clim, aes(x = PC1, y = PC2, col = genus, fill = genus)) +
  geom_polygon(data = hulls.total, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords, "<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "inferno") + 
  scale_fill_viridis_d(option = "inferno") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca.total$importance[2,1] * 100, 1),"%)"), x = paste("PC2 (", round(summary.pca.total$importance[2,2] * 100, 1),"%)")) +
  theme_minimal()
Ignoring unknown aesthetics: textThe plyr::rename operation has created duplicates for the following name(s): (`x`)
p.plotly.total <- ggplotly(p.total, tooltip = c("text"))
p.plotly.total
summary.pca.total
Importance of components:
                          Comp.1    Comp.2     Comp.3     Comp.4     Comp.5     Comp.6      Comp.7
Standard deviation     2.9368052 2.4375805 1.33337693 1.02359474 0.89722816 0.77573444 0.336790738
Proportion of Variance 0.4539382 0.3127262 0.09357337 0.05514454 0.04236939 0.03167179 0.005969895
Cumulative Proportion  0.4539382 0.7666644 0.86023777 0.91538230 0.95775169 0.98942348 0.995393373
                            Comp.8       Comp.9      Comp.10      Comp.11      Comp.12      Comp.13
Standard deviation     0.195236299 0.1360079252 0.1101757666 0.0819089406 0.0635551390 0.0609975574
Proportion of Variance 0.002006169 0.0009735871 0.0006388789 0.0003531092 0.0002125924 0.0001958264
Cumulative Proportion  0.997399542 0.9983731292 0.9990120082 0.9993651173 0.9995777097 0.9997735362
                            Comp.14      Comp.15      Comp.16      Comp.17      Comp.18 Comp.19
Standard deviation     0.0458378300 3.345402e-02 2.790399e-02 1.307653e-02 1.152850e-02       0
Proportion of Variance 0.0001105846 5.890375e-05 4.098068e-05 8.999776e-06 6.995071e-06       0
Cumulative Proportion  0.9998841207 9.999430e-01 9.999840e-01 9.999930e-01 1.000000e+00       1
#Table of loading scores for the first 3 PCs. 
knitr::kable(round(pcamap$model$loadings[,1:3],3)) 
Comp.1 Comp.2 Comp.3
bio1_411 0.287 0.191 0.179
bio2_411 -0.112 -0.238 0.512
bio3_411 0.186 0.057 0.034
bio4_411 -0.189 -0.260 0.352
bio5_411 0.263 0.136 0.384
bio6_411 0.282 0.225 0.047
bio7_411 -0.174 -0.241 0.453
bio8_411 0.189 0.012 0.292
bio9_411 0.204 0.219 -0.058
bio10_411 0.283 0.170 0.256
bio11_411 0.284 0.215 0.097
bio12_411 -0.247 0.279 0.065
bio13_411 -0.225 0.302 0.088
bio14_411 -0.244 0.269 0.098
bio15_411 0.148 0.156 0.125
bio16_411 -0.222 0.307 0.074
bio17_411 -0.264 0.249 0.075
bio18_411 -0.262 0.241 0.114
bio19_411 -0.191 0.325 0.028

PCA-Species

These are PCAs of environmental space for species within genera. Each climate PCA is of localities for a single genus, colored by species. I’m doing this even for genera with one species, so it’s easy to see if certain localities group together.

Acanthoxyla

#make a matrix of only bioclim values
clim.mat.acan <- loc.clim[loc.clim$genus == "acanthoxyla",grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca.acan <- prcomp(clim.mat.acan, scale = TRUE)
summary.pca.acan <- summary(clim.pca.acan) #check out the components
#add pca results to loc.clim data frame
loc.clim.acan <- data.frame(loc.clim[loc.clim$genus == "acanthoxyla",], clim.pca.acan$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1.1, df$PC2.1), ]
hulls <- plyr::ddply(loc.clim.acan, "genus", find_hull)
#make an interactive plot in plotly
p.acan <- ggplot(data = loc.clim.acan, aes(x = PC1.1, y = PC2.1, col = species, fill = species)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "inferno") + 
  scale_fill_viridis_d(option = "inferno") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly.acan <- ggplotly(p.acan, tooltip = c("text"))
#plot biplot
b.acan <- ggbiplot(clim.pca.acan, groups = loc.clim.acan$species, alpha = .7) +
  scale_color_viridis_d(option = "inferno") + 
  ggtitle("Biplot of extracted climate")
p.plotly.acan
b.acan

summary.pca.acan
Importance of components:
                          PC1    PC2    PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10
Standard deviation     2.8976 2.4081 1.4499 1.03416 0.99391 0.64837 0.37316 0.17888 0.15065 0.10865
Proportion of Variance 0.4419 0.3052 0.1106 0.05629 0.05199 0.02213 0.00733 0.00168 0.00119 0.00062
Cumulative Proportion  0.4419 0.7471 0.8578 0.91404 0.96603 0.98816 0.99549 0.99717 0.99836 0.99899
                          PC11    PC12    PC13    PC14    PC15    PC16    PC17    PC18      PC19
Standard deviation     0.07958 0.07073 0.05713 0.05208 0.03016 0.02200 0.01953 0.01351 1.003e-16
Proportion of Variance 0.00033 0.00026 0.00017 0.00014 0.00005 0.00003 0.00002 0.00001 0.000e+00
Cumulative Proportion  0.99932 0.99958 0.99975 0.99990 0.99994 0.99997 0.99999 1.00000 1.000e+00
knitr::kable(round(clim.pca.acan$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 -0.220 -0.303 0.131
bio2_411 0.191 0.155 0.499
bio3_411 -0.062 0.141 0.324
bio4_411 0.244 0.106 0.354
bio5_411 -0.152 -0.279 0.381
bio6_411 -0.256 -0.274 -0.004
bio7_411 0.232 0.117 0.434
bio8_411 -0.027 -0.275 -0.091
bio9_411 -0.251 -0.172 0.116
bio10_411 -0.197 -0.308 0.204
bio11_411 -0.243 -0.289 0.059
bio12_411 0.284 -0.232 -0.046
bio13_411 0.268 -0.253 0.009
bio14_411 0.289 -0.219 -0.049
bio15_411 -0.146 -0.087 0.300
bio16_411 0.264 -0.256 -0.004
bio17_411 0.293 -0.211 -0.065
bio18_411 0.295 -0.205 -0.054
bio19_411 0.220 -0.277 0.039

Argosarchus

#make a matrix of only bioclim values
clim.mat.argo <- loc.clim[loc.clim$genus == "argosarchus", grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca.argo <- prcomp(clim.mat.argo, scale = TRUE)
summary.pca.argo <- summary(clim.pca.argo) #check out the components
#add pca results to loc.clim data frame
loc.clim.argo <- data.frame(loc.clim[loc.clim$genus == "argosarchus",], clim.pca.argo$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1.1, df$PC2.1), ]
hulls <- plyr::ddply(loc.clim.argo, "genus", find_hull)
#make an interactive plot in plotly
p.argo <- ggplot(data = loc.clim.argo, aes(x = PC1.1, y = PC2.1, col = species, fill = species)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "inferno") + 
  scale_fill_viridis_d(option = "inferno") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca.argo$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca.argo$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly.argo <- ggplotly(p.argo, tooltip = c("text"))
#plot biplot
b.argo <- ggbiplot(clim.pca.argo, groups = loc.clim.argo$species, alpha = .7) +
  scale_color_viridis_d(option = "inferno") + 
  ggtitle("Biplot of extracted climate")
p.plotly.argo
b.argo

summary.pca.argo
Importance of components:
                          PC1    PC2    PC3     PC4     PC5     PC6    PC7    PC8    PC9    PC10
Standard deviation     2.6107 2.5769 1.5880 1.08155 0.94245 0.84133 0.3698 0.2092 0.1509 0.13650
Proportion of Variance 0.3587 0.3495 0.1327 0.06157 0.04675 0.03725 0.0072 0.0023 0.0012 0.00098
Cumulative Proportion  0.3587 0.7082 0.8409 0.90251 0.94926 0.98652 0.9937 0.9960 0.9972 0.99820
                          PC11    PC12    PC13    PC14    PC15    PC16    PC17    PC18     PC19
Standard deviation     0.12389 0.08684 0.07717 0.05097 0.03317 0.02797 0.02345 0.02016 2.68e-16
Proportion of Variance 0.00081 0.00040 0.00031 0.00014 0.00006 0.00004 0.00003 0.00002 0.00e+00
Cumulative Proportion  0.99900 0.99940 0.99971 0.99985 0.99991 0.99995 0.99998 1.00000 1.00e+00
knitr::kable(round(clim.pca.argo$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 0.253 -0.268 0.137
bio2_411 -0.139 0.198 0.487
bio3_411 0.018 0.020 0.421
bio4_411 -0.210 0.213 0.300
bio5_411 0.192 -0.174 0.437
bio6_411 0.254 -0.286 -0.040
bio7_411 -0.166 0.222 0.418
bio8_411 -0.038 -0.077 -0.082
bio9_411 0.223 -0.227 0.115
bio10_411 0.239 -0.247 0.233
bio11_411 0.265 -0.272 0.049
bio12_411 0.281 0.261 -0.038
bio13_411 0.303 0.232 0.003
bio14_411 0.246 0.289 -0.045
bio15_411 0.133 -0.160 0.152
bio16_411 0.307 0.228 -0.007
bio17_411 0.248 0.289 -0.046
bio18_411 0.225 0.305 -0.047
bio19_411 0.331 0.173 0.032

Asteliaphasma

#make a matrix of only bioclim values
clim.mat.aste <- loc.clim[loc.clim$genus == "asteliaphasma", grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca.aste <- prcomp(clim.mat.aste, scale = TRUE)
summary.pca.aste <- summary(clim.pca.aste) #check out the components
#add pca results to loc.clim data frame
loc.clim.aste <- data.frame(loc.clim[loc.clim$genus == "asteliaphasma",], clim.pca.aste$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1.1, df$PC2.1), ]
hulls <- plyr::ddply(loc.clim.aste, "genus", find_hull)
#make an interactive plot in plotly
p.aste <- ggplot(data = loc.clim.aste, aes(x = PC1.1, y = PC2.1, col = species, fill = species)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "viridis") + 
  scale_fill_viridis_d(option = "viridis") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca.aste$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca.aste$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly.aste <- ggplotly(p.aste, tooltip = c("text"))
#plot biplot
b.aste <- ggbiplot(clim.pca.aste, groups = loc.clim.aste$species, alpha = .7) +
  scale_color_viridis_d(option = "viridis") + 
  ggtitle("Biplot of extracted climate")
p.plotly.aste
b.aste

summary.pca.aste
Importance of components:
                          PC1    PC2     PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10
Standard deviation     3.5289 1.9449 1.08847 0.93035 0.68419 0.40024 0.19212 0.13894 0.10016 0.09172
Proportion of Variance 0.6554 0.1991 0.06236 0.04556 0.02464 0.00843 0.00194 0.00102 0.00053 0.00044
Cumulative Proportion  0.6554 0.8545 0.91687 0.96242 0.98706 0.99549 0.99743 0.99845 0.99898 0.99942
                          PC11    PC12    PC13    PC14    PC15    PC16    PC17      PC18    PC19
Standard deviation     0.05687 0.05344 0.04780 0.03677 0.02653 0.02020 0.01274 9.185e-16 1.8e-16
Proportion of Variance 0.00017 0.00015 0.00012 0.00007 0.00004 0.00002 0.00001 0.000e+00 0.0e+00
Cumulative Proportion  0.99959 0.99974 0.99986 0.99993 0.99997 0.99999 1.00000 1.000e+00 1.0e+00
knitr::kable(round(clim.pca.aste$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 -0.264 -0.159 -0.068
bio2_411 0.226 0.164 -0.445
bio3_411 -0.069 -0.207 -0.688
bio4_411 0.243 0.193 -0.241
bio5_411 -0.245 -0.123 -0.322
bio6_411 -0.261 -0.190 0.087
bio7_411 0.234 0.203 -0.314
bio8_411 -0.264 -0.175 0.009
bio9_411 -0.225 -0.102 -0.134
bio10_411 -0.260 -0.151 -0.114
bio11_411 -0.264 -0.177 -0.001
bio12_411 0.239 -0.272 0.017
bio13_411 0.203 -0.349 -0.021
bio14_411 0.230 -0.260 0.112
bio15_411 -0.148 -0.237 -0.093
bio16_411 0.210 -0.341 0.022
bio17_411 0.246 -0.227 0.041
bio18_411 0.229 -0.275 -0.022
bio19_411 0.210 -0.341 0.021

Clitarchus

#make a matrix of only bioclim values
clim.mat.clita <- loc.clim[loc.clim$genus == "clitarchus", grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca.clita <- prcomp(clim.mat.clita, scale = TRUE)
summary.pca.clita <- summary(clim.pca.clita) #check out the components
#add pca results to loc.clim data frame
loc.clim.clita <- data.frame(loc.clim[loc.clim$genus == "clitarchus",], clim.pca.clita$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1.1, df$PC2.1), ]
hulls <- plyr::ddply(loc.clim.clita, "species", find_hull)
#make an interactive plot in plotly
p.clita <- ggplot(data = loc.clim.clita, aes(x = PC1.1, y = PC2.1, col = species, fill = species)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "viridis") + 
  scale_fill_viridis_d(option = "viridis") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca.clita$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca.clita$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly.clita <- ggplotly(p.clita, tooltip = c("text"))
#plot biplot
b.clita <- ggbiplot(clim.pca.clita, groups = loc.clim.clita$species, alpha = .7) +
  scale_color_viridis_d(option = "viridis") + 
  ggtitle("Biplot of extracted climate")
p.plotly.clita
b.clita

summary.pca.clita
Importance of components:
                          PC1    PC2     PC3    PC4     PC5     PC6    PC7     PC8     PC9    PC10
Standard deviation     2.8287 2.6276 1.32815 1.1156 0.73394 0.53892 0.3776 0.22177 0.14594 0.13870
Proportion of Variance 0.4211 0.3634 0.09284 0.0655 0.02835 0.01529 0.0075 0.00259 0.00112 0.00101
Cumulative Proportion  0.4211 0.7845 0.87737 0.9429 0.97121 0.98650 0.9940 0.99659 0.99771 0.99873
                          PC11    PC12    PC13    PC14    PC15    PC16    PC17    PC18      PC19
Standard deviation     0.10155 0.07717 0.06308 0.04870 0.02999 0.01809 0.01515 0.01187 4.963e-16
Proportion of Variance 0.00054 0.00031 0.00021 0.00012 0.00005 0.00002 0.00001 0.00001 0.000e+00
Cumulative Proportion  0.99927 0.99958 0.99979 0.99992 0.99996 0.99998 0.99999 1.00000 1.000e+00
knitr::kable(round(clim.pca.clita$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 -0.317 -0.142 -0.099
bio2_411 0.129 0.256 -0.457
bio3_411 -0.166 0.081 -0.530
bio4_411 0.252 0.216 -0.236
bio5_411 -0.305 -0.055 -0.299
bio6_411 -0.304 -0.191 0.037
bio7_411 0.182 0.251 -0.355
bio8_411 -0.189 -0.209 0.105
bio9_411 -0.280 -0.066 -0.167
bio10_411 -0.314 -0.119 -0.152
bio11_411 -0.318 -0.157 -0.040
bio12_411 -0.176 0.322 0.126
bio13_411 -0.207 0.294 0.060
bio14_411 -0.180 0.303 0.161
bio15_411 -0.140 -0.061 -0.250
bio16_411 -0.211 0.293 0.078
bio17_411 -0.145 0.332 0.151
bio18_411 -0.149 0.325 0.149
bio19_411 -0.216 0.289 0.067

Micrarchus

#make a matrix of only bioclim values
clim.mat.micra <- loc.clim[loc.clim$genus == "micrarchus", grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca.micra <- prcomp(clim.mat.micra, scale = TRUE)
summary.pca.micra <- summary(clim.pca.micra) #check out the components
#add pca results to loc.clim data frame
loc.clim.micra <- data.frame(loc.clim[loc.clim$genus == "micrarchus",], clim.pca.micra$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1.1, df$PC2.1), ]
hulls <- plyr::ddply(loc.clim.micra, "species", find_hull)
#make an interactive plot in plotly
p.micra <- ggplot(data = loc.clim.micra, aes(x = PC1.1, y = PC2.1, col = species, fill = species)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "viridis") + 
  scale_fill_viridis_d(option = "viridis") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca.micra$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca.micra$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly.micra <- ggplotly(p.micra, tooltip = c("text"))
#plot biplot
b.micra <- ggbiplot(clim.pca.micra, groups = loc.clim.micra$species, alpha = .7) +
  scale_color_viridis_d(option = "viridis") + 
  ggtitle("Biplot of extracted climate")
p.plotly.micra
b.micra

summary.pca.micra
Importance of components:
                          PC1    PC2    PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10
Standard deviation     3.4602 1.8070 1.4755 1.04628 0.47265 0.37427 0.28044 0.13523 0.12413 0.08040
Proportion of Variance 0.6302 0.1719 0.1146 0.05762 0.01176 0.00737 0.00414 0.00096 0.00081 0.00034
Cumulative Proportion  0.6302 0.8020 0.9166 0.97422 0.98598 0.99335 0.99749 0.99846 0.99927 0.99961
                          PC11    PC12    PC13    PC14    PC15    PC16    PC17    PC18      PC19
Standard deviation     0.04868 0.04396 0.03954 0.02696 0.01967 0.01488 0.01171 0.01059 5.976e-17
Proportion of Variance 0.00012 0.00010 0.00008 0.00004 0.00002 0.00001 0.00001 0.00001 0.000e+00
Cumulative Proportion  0.99973 0.99983 0.99992 0.99995 0.99998 0.99999 0.99999 1.00000 1.000e+00
knitr::kable(round(clim.pca.micra$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 0.265 0.140 0.187
bio2_411 0.044 -0.384 0.474
bio3_411 0.215 -0.052 0.376
bio4_411 -0.145 -0.454 0.113
bio5_411 0.264 0.036 0.260
bio6_411 0.264 0.203 0.092
bio7_411 -0.069 -0.439 0.365
bio8_411 0.183 0.271 0.080
bio9_411 0.265 0.137 0.127
bio10_411 0.266 0.105 0.207
bio11_411 0.264 0.171 0.164
bio12_411 -0.259 0.189 0.187
bio13_411 -0.253 0.205 0.199
bio14_411 -0.256 0.177 0.201
bio15_411 0.130 0.077 0.062
bio16_411 -0.252 0.206 0.204
bio17_411 -0.256 0.184 0.209
bio18_411 -0.255 0.186 0.211
bio19_411 -0.254 0.175 0.189

Niveaphasma

#make a matrix of only bioclim values
clim.mat.nive <- loc.clim[loc.clim$genus == "niveaphasma", grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca.nive <- prcomp(clim.mat.nive, scale = TRUE)
summary.pca.nive <- summary(clim.pca.nive) #check out the components
#add pca results to loc.clim data frame
loc.clim.nive <- data.frame(loc.clim[loc.clim$genus == "niveaphasma",], clim.pca.nive$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1.1, df$PC2.1), ]
hulls <- plyr::ddply(loc.clim.nive, "species", find_hull)
#make an interactive plot in plotly
p.nive <- ggplot(data = loc.clim.nive, aes(x = PC1.1, y = PC2.1, col = species, fill = species)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "viridis") + 
  scale_fill_viridis_d(option = "viridis") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca.nive$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca.nive$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly.nive <- ggplotly(p.nive, tooltip = c("text"))
#plot biplot
b.nive <- ggbiplot(clim.pca.nive, groups = loc.clim.nive$species, alpha = .7) +
  scale_color_viridis_d(option = "viridis") + 
  ggtitle("Biplot of extracted climate")
p.plotly.nive
b.nive

summary.pca.nive
Importance of components:
                          PC1    PC2    PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10
Standard deviation     2.9075 2.3439 1.6667 1.03074 0.77498 0.58305 0.48456 0.11336 0.09999 0.07972
Proportion of Variance 0.4449 0.2892 0.1462 0.05592 0.03161 0.01789 0.01236 0.00068 0.00053 0.00033
Cumulative Proportion  0.4449 0.7341 0.8803 0.93621 0.96782 0.98571 0.99807 0.99874 0.99927 0.99960
                          PC11    PC12    PC13    PC14    PC15    PC16    PC17    PC18     PC19
Standard deviation     0.05147 0.04226 0.03754 0.02765 0.02184 0.01340 0.01209 0.01062 6.88e-16
Proportion of Variance 0.00014 0.00009 0.00007 0.00004 0.00003 0.00001 0.00001 0.00001 0.00e+00
Cumulative Proportion  0.99974 0.99984 0.99991 0.99995 0.99998 0.99999 0.99999 1.00000 1.00e+00
knitr::kable(round(clim.pca.nive$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 -0.212 -0.286 0.234
bio2_411 -0.053 0.355 0.221
bio3_411 -0.050 -0.292 -0.117
bio4_411 -0.042 0.388 0.209
bio5_411 -0.218 0.082 0.424
bio6_411 -0.139 -0.385 0.066
bio7_411 -0.027 0.387 0.230
bio8_411 -0.218 -0.008 0.258
bio9_411 -0.002 -0.238 0.191
bio10_411 -0.245 -0.148 0.347
bio11_411 -0.155 -0.369 0.118
bio12_411 0.322 -0.071 0.184
bio13_411 0.314 -0.077 0.217
bio14_411 0.329 -0.061 0.130
bio15_411 -0.150 0.011 0.384
bio16_411 0.315 -0.087 0.205
bio17_411 0.330 -0.054 0.145
bio18_411 0.319 -0.067 0.185
bio19_411 0.326 -0.079 0.148

Spinotectarchus

#make a matrix of only bioclim values
clim.mat.spin <- loc.clim[loc.clim$genus == "spinotectarchus", grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca.spin <- prcomp(clim.mat.spin, scale = TRUE)
summary.pca.spin <- summary(clim.pca.spin) #check out the components
#add pca results to loc.clim data frame
loc.clim.spin <- data.frame(loc.clim[loc.clim$genus == "spinotectarchus",], clim.pca.spin$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1.1, df$PC2.1), ]
hulls <- plyr::ddply(loc.clim.spin, "species", find_hull)
#make an interactive plot in plotly
p.spin <- ggplot(data = loc.clim.spin, aes(x = PC1.1, y = PC2.1, col = species, fill = species)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "viridis") + 
  scale_fill_viridis_d(option = "viridis") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca.spin$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca.spin$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly.spin <- ggplotly(p.spin, tooltip = c("text"))
#plot biplot
b.spin <- ggbiplot(clim.pca.spin, groups = loc.clim.spin$species, alpha = .7) +
  scale_color_viridis_d(option = "viridis") + 
  ggtitle("Biplot of extracted climate")
p.plotly.spin
b.spin

summary.pca.spin
Importance of components:
                          PC1    PC2     PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10
Standard deviation     3.6740 1.7717 1.04961 0.74836 0.67601 0.41693 0.17179 0.13411 0.09313 0.07134
Proportion of Variance 0.7105 0.1652 0.05798 0.02948 0.02405 0.00915 0.00155 0.00095 0.00046 0.00027
Cumulative Proportion  0.7105 0.8757 0.93363 0.96311 0.98716 0.99631 0.99786 0.99881 0.99927 0.99954
                          PC11    PC12    PC13    PC14    PC15    PC16      PC17      PC18      PC19
Standard deviation     0.05938 0.05019 0.03604 0.02482 0.02193 0.01971 6.536e-16 1.269e-16 3.144e-18
Proportion of Variance 0.00019 0.00013 0.00007 0.00003 0.00003 0.00002 0.000e+00 0.000e+00 0.000e+00
Cumulative Proportion  0.99972 0.99985 0.99992 0.99995 0.99998 1.00000 1.000e+00 1.000e+00 1.000e+00
knitr::kable(round(clim.pca.spin$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 -0.257 -0.130 -0.194
bio2_411 0.230 0.165 -0.351
bio3_411 -0.106 -0.360 -0.197
bio4_411 0.230 0.233 -0.239
bio5_411 -0.239 -0.097 -0.390
bio6_411 -0.254 -0.197 0.014
bio7_411 0.228 0.235 -0.273
bio8_411 -0.258 -0.165 -0.104
bio9_411 -0.215 -0.014 -0.395
bio10_411 -0.252 -0.109 -0.265
bio11_411 -0.258 -0.165 -0.104
bio12_411 0.239 -0.264 -0.037
bio13_411 0.220 -0.323 0.010
bio14_411 0.240 -0.237 -0.137
bio15_411 -0.152 -0.249 0.447
bio16_411 0.221 -0.322 0.029
bio17_411 0.247 -0.211 -0.129
bio18_411 0.238 -0.241 -0.172
bio19_411 0.221 -0.322 0.029

Tectarchus

#make a matrix of only bioclim values
clim.mat.tect <- loc.clim[loc.clim$genus == "tectarchus", grep("bio", names(loc.clim))] %>% as.matrix()
#run pca on climate variables
clim.pca.tect <- prcomp(clim.mat.tect, scale = TRUE)
summary.pca.tect <- summary(clim.pca.tect) #check out the components
#add pca results to loc.clim data frame
loc.clim.tect <- data.frame(loc.clim[loc.clim$genus == "tectarchus",], clim.pca.tect$x)
#make convex hull of genera
find_hull <- function(df) df[chull(df$PC1.1, df$PC2.1), ]
hulls <- plyr::ddply(loc.clim.tect, "species", find_hull)
#make an interactive plot in plotly
p.tect <- ggplot(data = loc.clim.tect, aes(x = PC1.1, y = PC2.1, col = species, fill = species)) +
  geom_polygon(data = hulls, alpha = 0.4)  + 
  geom_point(alpha = .7, size = 1, aes(text = paste("ID:", id, "<br>",
                                                    genus, species, "<br>",
                                                    "Long-Lat:", coords,"<br>",
                                                    "Locality:", locality))) + 
  scale_color_viridis_d(option = "viridis") + 
  scale_fill_viridis_d(option = "viridis") + 
  labs(title = "PCA of extracted climate", x = paste("PC1 (", round(summary.pca.tect$importance[2,1] * 100, 1),"%)"), y = paste("PC2 (", round(summary.pca.tect$importance[2,2] * 100, 1),"%)")) + theme_minimal()
Ignoring unknown aesthetics: text
p.plotly.tect <- ggplotly(p.tect, tooltip = c("text"))
#plot biplot
b.tect <- ggbiplot(clim.pca.tect, groups = loc.clim.tect$species, alpha = .7) +
  scale_color_viridis_d(option = "viridis") + 
  ggtitle("Biplot of extracted climate")
p.plotly.tect
b.tect

summary.pca.tect
Importance of components:
                          PC1    PC2    PC3     PC4     PC5     PC6     PC7    PC8     PC9    PC10
Standard deviation     2.7649 2.5672 1.5947 1.13698 0.63754 0.57252 0.35428 0.1689 0.11908 0.11043
Proportion of Variance 0.4024 0.3469 0.1338 0.06804 0.02139 0.01725 0.00661 0.0015 0.00075 0.00064
Cumulative Proportion  0.4024 0.7492 0.8831 0.95112 0.97251 0.98976 0.99637 0.9979 0.99862 0.99926
                          PC11    PC12    PC13    PC14    PC15    PC16    PC17    PC18     PC19
Standard deviation     0.07835 0.05082 0.04736 0.04012 0.02414 0.02156 0.01715 0.01214 1.15e-16
Proportion of Variance 0.00032 0.00014 0.00012 0.00008 0.00003 0.00002 0.00002 0.00001 0.00e+00
Cumulative Proportion  0.99958 0.99972 0.99984 0.99992 0.99995 0.99998 0.99999 1.00000 1.00e+00
knitr::kable(round(clim.pca.tect$rotation[,1:3],3)) #Table of loading scores for the first 3 PCs. 
PC1 PC2 PC3
bio1_411 0.309 -0.182 0.117
bio2_411 -0.122 0.137 0.539
bio3_411 0.159 -0.033 0.464
bio4_411 -0.214 0.247 0.289
bio5_411 0.273 -0.146 0.318
bio6_411 0.306 -0.201 -0.020
bio7_411 -0.175 0.158 0.465
bio8_411 0.221 -0.137 -0.105
bio9_411 0.268 -0.200 0.100
bio10_411 0.305 -0.167 0.181
bio11_411 0.304 -0.205 0.060
bio12_411 -0.211 -0.315 0.021
bio13_411 -0.209 -0.310 0.040
bio14_411 -0.214 -0.304 0.069
bio15_411 0.058 0.027 0.082
bio16_411 -0.204 -0.316 0.036
bio17_411 -0.216 -0.306 0.038
bio18_411 -0.223 -0.299 0.038
bio19_411 -0.197 -0.314 0.061

Tepakiphasma

Nothing. Only one locality.

LS0tCnRpdGxlOiAiU3RpY2sgSW5zZWN0IENsaW1hdGUgUENBIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogZmxhdGx5CiAgICBoaWdobGlnaHQ6IHRhbmdvCi0tLQoKUmVhZCBpbiB0aGUgcGFja2FnZXMuIFRoZSB3b3JraW5nIGRpcmVjdG9yeSBpcyB3aGVyZXZlciB0aGUgUiBOb3RlYm9vayBpcyBsb2NhdGVkLiBOb3RlIHRoYXQgUlN0b29sYm94IGhhcyBzb21lIGRlcGVuZGVuY2llcyB0aGF0IGFyZSBraW5kIG9mIGRpZmZpY3VsdCB0byBpbnN0YWxsIG9uIGEgTWFjLiBUaGUgcGFja2FnZSBtYWtlcyBydW5uaW5nIGEgUENBIG9uIHRvdGFsIGNsaW1hdGUgc3BhY2Ugc3VwZXIgZWFzeSBhbmQgaGFzIGEgbG90IG9mIG90aGVyIGZ1bmN0aW9uYWxpdHksIHNvIEkgdGhpbmsgaXQncyB3b3J0aCB0aGUgaGVhZGFjaGUuCgpgYGB7ciwgcmVzdWx0cz0iaGlkZSJ9CnBhY2thZ2VzIDwtIGMoInJhc3RlciIsICJnZ2JpcGxvdCIsICJ0aWR5dmVyc2UiLCAic2YiLCAiUlN0b29sYm94IiwgImxlYWZsZXQiLCAibWFwcyIsICJwbG90bHkiKSAjUlN0b29sYm94IGhhcyBzb21lIGRlcGVuZGVuY2llcyBsaWtlIG9wZW5NUCB0aGF0IGNhbiBiZSBkaWZmaWN1bHQgdG8gY29tcGlsZSBvbiBhIE1hYyAobmVlZGVkIGZvciB0aGUgZGVwZW5kZW50IHBhY2thZ2UgImNhcmV0IikuIElmIHlvdSBoYXZlIEhpZ2ggU2llcnJhIE9TIG9yIG5ld2VyLCBzZWFyY2ggZm9yIGluc3RydWN0aW9ucyBzcGVjaWZpYyB0byB5b3VyIE9TLSBpdCdzIGEgbG90IGVhc2llciB0aGFuIG9sZGVyIE9TJ3MuCmxhcHBseShwYWNrYWdlcywgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQpgYGAKCgpSZWFkIGluIHRoZSBzcHJlYWRzaGVldCBhbmQgdGFrZSBhIGxvb2sgYXQgdGhlIGRhdGEuCgpgYGB7cn0KIyMjcmVhZCBpbiBzcHJlYWRzaGVldApsb2MgPC0gcmVhZC5jc3YoIndvcmtzaGVldHMvYWxsLXNwZWNpZXMuY3N2IikKCgojbWFrZSBsb2NhbGl0eSBzaGFwZSBmaWxlIGFuZCBhc3NpZ24gV0dTIGNvb3JkIHN5c3RlbQpjb29yZC5wb2ludHMgPC0gc3RfYXNfc2YobG9jLCBjb29yZHMgPSBjKCJsb25naXR1ZGUiLCAibGF0aXR1ZGUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBjcnMgPSA0MzI2LCBhZ3IgPSAiY29uc3RhbnQiKQoKI1Rha2UgYSBnYW5kZXIgYXQgdGhlIGhlYWQgYW5kIHN0cnVjdHVyZSBvZiB0aGUgZGF0YQpoZWFkKGxvYykKc3RyKGxvYykKCmBgYAoKIyNNYXAKUGxvdCBhIGxlYWZsZXQgbWFwIG9mIHRoZSBsb2NhbGl0aWVzLiBUaGUgbGVhZmxldCBtYXAgaXMgaW50ZXJhY3RpdmUuIFlvdSBjYW4gY2xpY2sgb24gdGhlIGxvY2FsaXRpZXMgYW5kIGEgZmxhZyB3aXRoIHNvbWUgbWV0YWRhdGEgd2lsbCBwb3AgdXAhIAoKYGBge3J9CiNsb2FkIGEgd29ybGQgbWFwIGZvciBwbG90dGluZwp3Lm1hcCA8LSBtYXAoIndvcmxkIiwgcGxvdCA9IEZBTFNFKQoKCiNtYWtlIGNvbG9yIHBhbGV0dGUKcGFsIDwtIGNvbG9yRmFjdG9yKHBhbGV0dGUgPSAiaW5mZXJubyIsIGRvbWFpbiA9IE5VTEwpCgojY3JlYXRlIHBvcHVwIGxhYmVscyBmb3IgcG9pbnRzCnBvcHVwLmxhYmVsIDwtIHBhc3RlKGNvb3JkLnBvaW50cyRnZW51cywgY29vcmQucG9pbnRzJHNwZWNpZXMsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgY29vcmQucG9pbnRzJGlkLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgIGNvb3JkLnBvaW50cyRsb2NhbGl0eSkKCiNwbG90IGluIGxlYWZsZXQKbCA8LSBsZWFmbGV0KGRhdGEgPSB3Lm1hcCkgJT4lIAogIGFkZFRpbGVzKCkgJT4lCiAgZml0Qm91bmRzKGxuZzEgPSAxNjUsIGxuZzIgPSAxODUsIGxhdDEgPSAtMzAsIGxhdDIgPSAtNTUpICU+JQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGNvb3JkLnBvaW50cywKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnBhbChnZW51cyksCiAgICAgICAgICAgICAgICAgICByYWRpdXMgPSAzLAogICAgICAgICAgICAgICAgICAgcG9wdXAgPSBwb3B1cC5sYWJlbCkgJT4lCiAgYWRkTGVnZW5kKGRhdGEgPSBjb29yZC5wb2ludHMsICJib3R0b21yaWdodCIsIHBhbCA9IHBhbCwgdmFsdWVzID0gfmdlbnVzLCBvcGFjaXR5ID0gLjkpCgpsCmBgYAoKIyNQQ0EtR2VuZXJhIHsudGFic2V0fQoKIyMjQ2xpbWF0ZSBEYXRhCk9idGFpbiB0aGUgYmlvY2xpbSBsYXllcnMgZm9yIGFuYWx5c2lzLiBJJ20gdXNpbmcgYWxsIDE5IGZvciB0aGlzIHByZWxpbWluYXJ5IGV4cGxvcmF0aW9uLiBJIHBsb3R0ZWQgdGhlIGZpcnN0IGJpb2NsaW0ganVzdCB0byBtYWtlIHN1cmUgbm90aGluZyBzZWVtcyB3b25reS4KYGBge3J9CiMjZ2V0IHdvcmxkY2xpbSBkYXRhCncgPC0gZ2V0RGF0YSgid29ybGRjbGltIiwgdmFyID0gImJpbyIsIHJlcyA9IDAuNSwgbG9uID0gMTczLCBsYXQgPSAtMzUpCgojY2hlY2sgaXQgb3V0CnBsb3QodywxLCB4bGltID0gYygxNjUsIDE4NSksIHlsaW09IGMoLTU1LCAtMzMpKQpgYGAKCgojIyNQQ0EgYnkgbG9jYWxpdHkKVGhpcyBpcyBhIFBDQSBvZiB0aGUgY2xpbWF0ZSBkYXRhIGV4dHJhY3RlZCBmb3IgZWFjaCBsb2NhbGl0eSwgcmF0aGVyIHRoYW4gYSBQQ0Egb2YgdGhlIHRvdGFsIGNsaW1hdGUgc3BhY2UuCgpSdW4gdGhlIHBjYSBhbmQgY2hlY2sgb3V0IHZhcmlhYmxlIGxvYWRpbmdzIGFuZCBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGV4cGxhaW5lZCBieSBjb21wb25lbnRzLgoKYGBge3J9CiNleHRyYWN0IGRhdGEgZnJvbSB3b3JsZGNsaW0gZm9yIGVhY2ggbG9jYWxpdHkuIE1ha2luZyB0aGlzIGludG8gYSBkYXRhIGZyYW1lIHdpdGggY29sdW1ucyBsYWJlbGVkIHNvIHRoZSByb3cgbGFiZWxpbmcgbGluZXMgdXAgYWZ0ZXIgSSByZW1vdmUgdGhlIE5Bcy4KI2V4dHJhY3QgZGF0YSBmcm9tIHdvcmxkY2xpbSBmb3IgZWFjaCBsb2NhbGl0eS4KbG9jLmNsaW0gPC0gZGF0YS5mcmFtZShnZW51cyA9IGNvb3JkLnBvaW50cyRnZW51cywKICAgICAgICAgICAgICAgICAgICAgICBzcGVjaWVzID0gY29vcmQucG9pbnRzJHNwZWNpZXMsCiAgICAgICAgICAgICAgICAgICAgICAgaWQgPSBjb29yZC5wb2ludHMkaWQsCiAgICAgICAgICAgICAgICAgICAgICAgbG9jYWxpdHkgPSBjb29yZC5wb2ludHMkbG9jYWxpdHksCiAgICAgICAgICAgICAgICAgICAgICAgY29vcmRzID0gYXMuY2hhcmFjdGVyKGNvb3JkLnBvaW50cyRnZW9tZXRyeSksCiAgICAgICAgICAgICAgICAgICAgICAgcmFzdGVyOjpleHRyYWN0KHcsIGNvb3JkLnBvaW50cywgbWV0aG9kID0gInNpbXBsZSIpKSAlPiUgbmEub21pdCgpCgojbWFrZSBhIG1hdHJpeCBvZiBvbmx5IGJpb2NsaW0gdmFsdWVzCmNsaW0ubWF0IDwtIGxvYy5jbGltWyxncmVwKCJiaW8iLCBuYW1lcyhsb2MuY2xpbSkpXSAlPiUgYXMubWF0cml4KCkKCiNydW4gcGNhIG9uIGNsaW1hdGUgdmFyaWFibGVzCmNsaW0ucGNhIDwtIHByY29tcChjbGltLm1hdCwgc2NhbGUgPSBUUlVFKQpzdW1tYXJ5LnBjYSA8LSBzdW1tYXJ5KGNsaW0ucGNhKSAjY2hlY2sgb3V0IHRoZSBjb21wb25lbnRzCmBgYAoKVHdvIHBsb3RzOiBPbmUgcGxvdCBvZiB0aGUgUENBIGNvbG9yZWQgYWNjb3JkaW5nIHRvIGdlbnVzLCB3aXRoIGNvbnZleCBodWxscyBzdXJyb3VuZGluZyB0aGUgZ2VuZXJhLiBJdCBsb29rcyBsaWtlIHRoaXMgcmVmbGVjdHMgYSBsYXRpdHVkaW5hbCBncmFkaWVudCBpbiB0ZW1wZXJhdHVyZSEgWW91IGNhbiBpbnRlcmFjdCB3aXRoIHRoZSBQQ0EgcGxvdCBieSBjbGlja2luZyBvbiBwb2ludHMgdG8gdmlldyBhc3NvY2lhdGVkIG1ldGFkYXRhLiBZb3UgY2FuIGlzb2xhdGUgdGhlIGdlbnVzIHlvdSB3YW50IHRvIHZpZXcgYnkgZG91YmxlIGNsaWNraW5nIHRoZSBnZW51cyBpbiB0aGUgbGVnZW5kISBZb3UgY2FuIGFsc28gcmVtb3ZlIGEgZ2VudXMgYnkgY2xpY2tpbmcgb24gaXQgb25jZS4gVGhlcmUncyBzb21lIG90aGVyIGZ1bmN0aW9uYWxpdHkgeW91IGNhbiBleHBsb3JlIGluIHRoZSB0b29sYmFyIGF0IHRoZSB0b3Agb2YgdGhlIHBsb3QuCmBgYHtyfQojYWRkIHBjYSByZXN1bHRzIHRvIGxvYy5jbGltIGRhdGEgZnJhbWUKbG9jLmNsaW0gPC0gZGF0YS5mcmFtZShsb2MuY2xpbSwgY2xpbS5wY2EkeCkKCiNtYWtlIGNvbnZleCBodWxsIG9mIGdlbmVyYQpmaW5kX2h1bGwgPC0gZnVuY3Rpb24oZGYpIGRmW2NodWxsKGRmJFBDMSwgZGYkUEMyKSwgXQpodWxscyA8LSBwbHlyOjpkZHBseShsb2MuY2xpbSwgImdlbnVzIiwgZmluZF9odWxsKQoKI21ha2UgYW4gaW50ZXJhY3RpdmUgcGxvdCBpbiBwbG90bHkKcCA8LSBnZ3Bsb3QoZGF0YSA9IGxvYy5jbGltLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sID0gZ2VudXMsIGZpbGwgPSBnZW51cykpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IGh1bGxzLCBhbHBoYSA9IDAuNCkgICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IC43LCBzaXplID0gMSwgYWVzKHRleHQgPSBwYXN0ZSgiSUQ6IiwgaWQsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnVzLCBzcGVjaWVzLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9uZy1MYXQ6IiwgY29vcmRzLCI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb2NhbGl0eToiLCBsb2NhbGl0eSkpKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAiaW5mZXJubyIpICsgCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gImluZmVybm8iKSArIAogIGxhYnModGl0bGUgPSAiUENBIG9mIGV4dHJhY3RlZCBjbGltYXRlIiwgeCA9IHBhc3RlKCJQQzEgKCIsIHJvdW5kKHN1bW1hcnkucGNhJGltcG9ydGFuY2VbMiwxXSAqIDEwMCwgMSksIiUpIiksIHkgPSBwYXN0ZSgiUEMyICgiLCByb3VuZChzdW1tYXJ5LnBjYSRpbXBvcnRhbmNlWzIsMl0gKiAxMDAsIDEpLCIlKSIpKSArIHRoZW1lX21pbmltYWwoKQpwLnBsb3RseSA8LSBnZ3Bsb3RseShwLCB0b29sdGlwID0gYygidGV4dCIpKQojcGxvdCBiaXBsb3QKYiA8LSBnZ2JpcGxvdChjbGltLnBjYSwgZ3JvdXBzID0gbG9jLmNsaW0kZ2VudXMsIGFscGhhID0gLjcpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uID0gImluZmVybm8iKSArIAogIGdndGl0bGUoIkJpcGxvdCBvZiBleHRyYWN0ZWQgY2xpbWF0ZSIpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNiwgZWNobz1GQUxTRX0KcC5wbG90bHkKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDQsIGVjaG89RkFMU0V9CmIKYGBgCgpgYGB7cn0Kc3VtbWFyeS5wY2EKa25pdHI6OmthYmxlKHJvdW5kKGNsaW0ucGNhJHJvdGF0aW9uWywxOjNdLDMpKSAjVGFibGUgb2YgbG9hZGluZyBzY29yZXMgZm9yIHRoZSBmaXJzdCAzIFBDcy4gCmBgYAoKCiMjI1RvdGFsIENsaW1hdGUgUENBCkkgY29uZHVjdGVkIGEgUENBIG9mIHRoZSB0b3RhbCBjbGltYXRlIHNwYWNlIGluIE5ldyBaZWFsYW5kIGFuZCBleHRyYWN0ZWQgdmFsdWVzIGZvciBlYWNoIGxvY2FsaXR5LgoKUnVuIHRoZSBwY2EgYW5kIGNoZWNrIG91dCB2YXJpYWJsZSBsb2FkaW5ncyBhbmQgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgY29tcG9uZW50cy4KYGBge3J9CiNzdWJzZXQgdGhlIHdvcmxkIG1hcCB0byBqdXN0IE5ldyBaZWFsYW5kIHRvIG1ha2UgdGhlIGFuYWx5c2lzIHRyYWN0YWJsZQpsaW1zPC1jKDE2NSwxODUsIC01NSwtMzMpCnN1Ym1hcDwtY3JvcCh3LGxpbXMpCgojcnVuIGEgc2NhbGVkIFBDQSBvbiB0aGUgY2xpbWF0ZSBkYXRhCnBjYW1hcDwtcmFzdGVyUENBKHN1Ym1hcCwgc3BjYT1UUlVFKQoKCnN1bW1hcnkucGNhLnRvdGFsIDwtIHN1bW1hcnkocGNhbWFwJG1vZGVsKSAjY2hlY2sgb3V0IHRoZSBjb21wb25lbnRzCgpgYGAKClBsb3QgdGhlIHByaW5jaXBsZSBjb21wb25lbnRzIGluIGdlb2dyYXBoaWMgc3BhY2UuCmBgYHtyfQojcGxvdCB0aGUgUENzCnBsb3QocGNhbWFwJG1hcCwgMTozKQpgYGAKCgpQbG90IHRoZSBmaXJzdCB0d28gUENzIGFzIGEgc2NhdHRlciBwbG90LiBJIGNvdWxkbid0IGZpZ3VyZSBvdXQgaG93IHRvIHBsb3QgYSBiaXBsb3Qgd2l0aCB0aGUgZGF0YSBzdHJ1Y3R1cmUgcmFzdGVyUENBIG91dHB1dHMuIEl0IHNlZW1zIGxpa2UgdGhlIGxhdGl0dWRpbmFsIGdyYWRpZW50IGluIGNsaW1hdGUgaXMgc3ByZWFkIGFjcm9zcyBQQyBheGVzLiAKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQojZXh0cmFjdCBkYXRhIGZyb20gcGNhIGZvciBlYWNoIGxvY2FsaXR5LiBNYWtpbmcgdGhpcyBpbnRvIGEgZGF0YSBkcmFtZSB3aXRoIGNvbHVtbnMgbGFiZWxlZCBzbyB0aGUgcm93IGxhYmVsaW5nIGxpbmVzIHVwIGFmdGVyIEkgcmVtb3ZlIHRoZSBOQXMuCgoKbG9jLnRvdGFsLmNsaW0gPC0gZGF0YS5mcmFtZShnZW51cyA9IGNvb3JkLnBvaW50cyRnZW51cywKICAgICAgICAgICAgICAgICAgICAgICBzcGVjaWVzID0gY29vcmQucG9pbnRzJHNwZWNpZXMsCiAgICAgICAgICAgICAgICAgICAgICAgaWQgPSBjb29yZC5wb2ludHMkaWQsCiAgICAgICAgICAgICAgICAgICAgICAgbG9jYWxpdHkgPSBjb29yZC5wb2ludHMkbG9jYWxpdHksCiAgICAgICAgICAgICAgICAgICAgICAgY29vcmRzID0gYXMuY2hhcmFjdGVyKGNvb3JkLnBvaW50cyRnZW9tZXRyeSksCiAgICAgICAgICAgICAgICAgICAgICAgcmFzdGVyOjpleHRyYWN0KHBjYW1hcCRtYXAsIGNvb3JkLnBvaW50cywgbWV0aG9kID0gInNpbXBsZSIpKSAlPiUgbmEub21pdCgpCgojbWFrZSBjb252ZXggaHVsbCBvZiBnZW5lcmEKZmluZC5odWxsLnRvdGFsIDwtIGZ1bmN0aW9uKGRmKSBkZltjaHVsbChkZiRQQzEsIGRmJFBDMiksIF0KaHVsbHMudG90YWwgPC0gcGx5cjo6ZGRwbHkobG9jLnRvdGFsLmNsaW0sICJnZW51cyIsIGZpbmQuaHVsbC50b3RhbCkKCgojbWFrZSBhbiBpbnRlcmFjdGl2ZSBwbG90IGluIHBsb3RseQpwLnRvdGFsIDwtIGdncGxvdChkYXRhID0gbG9jLnRvdGFsLmNsaW0sIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2wgPSBnZW51cywgZmlsbCA9IGdlbnVzKSkgKwogIGdlb21fcG9seWdvbihkYXRhID0gaHVsbHMudG90YWwsIGFscGhhID0gMC40KSAgKyAKICBnZW9tX3BvaW50KGFscGhhID0gLjcsIHNpemUgPSAxLCBhZXModGV4dCA9IHBhc3RlKCJJRDoiLCBpZCwgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VudXMsIHNwZWNpZXMsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb25nLUxhdDoiLCBjb29yZHMsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb2NhbGl0eToiLCBsb2NhbGl0eSkpKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAiaW5mZXJubyIpICsgCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gImluZmVybm8iKSArIAogIGxhYnModGl0bGUgPSAiUENBIG9mIGV4dHJhY3RlZCBjbGltYXRlIiwgeCA9IHBhc3RlKCJQQzEgKCIsIHJvdW5kKHN1bW1hcnkucGNhLnRvdGFsJGltcG9ydGFuY2VbMiwxXSAqIDEwMCwgMSksIiUpIiksIHggPSBwYXN0ZSgiUEMyICgiLCByb3VuZChzdW1tYXJ5LnBjYS50b3RhbCRpbXBvcnRhbmNlWzIsMl0gKiAxMDAsIDEpLCIlKSIpKSArCiAgdGhlbWVfbWluaW1hbCgpCnAucGxvdGx5LnRvdGFsIDwtIGdncGxvdGx5KHAudG90YWwsIHRvb2x0aXAgPSBjKCJ0ZXh0IikpCnAucGxvdGx5LnRvdGFsCmBgYApgYGB7cn0Kc3VtbWFyeS5wY2EudG90YWwKI1RhYmxlIG9mIGxvYWRpbmcgc2NvcmVzIGZvciB0aGUgZmlyc3QgMyBQQ3MuIAprbml0cjo6a2FibGUocm91bmQocGNhbWFwJG1vZGVsJGxvYWRpbmdzWywxOjNdLDMpKSAKCmBgYAoKCiMjUENBLVNwZWNpZXMgey50YWJzZXR9ClRoZXNlIGFyZSBQQ0FzIG9mIGVudmlyb25tZW50YWwgc3BhY2UgZm9yIHNwZWNpZXMgd2l0aGluIGdlbmVyYS4gRWFjaCBjbGltYXRlIFBDQSBpcyBvZiBsb2NhbGl0aWVzIGZvciBhIHNpbmdsZSBnZW51cywgY29sb3JlZCBieSBzcGVjaWVzLiBJJ20gZG9pbmcgdGhpcyBldmVuIGZvciBnZW5lcmEgd2l0aCBvbmUgc3BlY2llcywgc28gaXQncyBlYXN5IHRvIHNlZSBpZiBjZXJ0YWluIGxvY2FsaXRpZXMgZ3JvdXAgdG9nZXRoZXIuIAoKIyMjQWNhbnRob3h5bGEKYGBge3J9CiNtYWtlIGEgbWF0cml4IG9mIG9ubHkgYmlvY2xpbSB2YWx1ZXMKY2xpbS5tYXQuYWNhbiA8LSBsb2MuY2xpbVtsb2MuY2xpbSRnZW51cyA9PSAiYWNhbnRob3h5bGEiLGdyZXAoImJpbyIsIG5hbWVzKGxvYy5jbGltKSldICU+JSBhcy5tYXRyaXgoKQoKI3J1biBwY2Egb24gY2xpbWF0ZSB2YXJpYWJsZXMKY2xpbS5wY2EuYWNhbiA8LSBwcmNvbXAoY2xpbS5tYXQuYWNhbiwgc2NhbGUgPSBUUlVFKQpzdW1tYXJ5LnBjYS5hY2FuIDwtIHN1bW1hcnkoY2xpbS5wY2EuYWNhbikgI2NoZWNrIG91dCB0aGUgY29tcG9uZW50cwoKYGBgCgoKYGBge3J9CiNhZGQgcGNhIHJlc3VsdHMgdG8gbG9jLmNsaW0gZGF0YSBmcmFtZQpsb2MuY2xpbS5hY2FuIDwtIGRhdGEuZnJhbWUobG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gImFjYW50aG94eWxhIixdLCBjbGltLnBjYS5hY2FuJHgpCgojbWFrZSBjb252ZXggaHVsbCBvZiBnZW5lcmEKZmluZF9odWxsIDwtIGZ1bmN0aW9uKGRmKSBkZltjaHVsbChkZiRQQzEuMSwgZGYkUEMyLjEpLCBdCmh1bGxzIDwtIHBseXI6OmRkcGx5KGxvYy5jbGltLmFjYW4sICJnZW51cyIsIGZpbmRfaHVsbCkKCiNtYWtlIGFuIGludGVyYWN0aXZlIHBsb3QgaW4gcGxvdGx5CnAuYWNhbiA8LSBnZ3Bsb3QoZGF0YSA9IGxvYy5jbGltLmFjYW4sIGFlcyh4ID0gUEMxLjEsIHkgPSBQQzIuMSwgY29sID0gc3BlY2llcywgZmlsbCA9IHNwZWNpZXMpKSArCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBodWxscywgYWxwaGEgPSAwLjQpICArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAuNywgc2l6ZSA9IDEsIGFlcyh0ZXh0ID0gcGFzdGUoIklEOiIsIGlkLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW51cywgc3BlY2llcywgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxvbmctTGF0OiIsIGNvb3JkcywiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9jYWxpdHk6IiwgbG9jYWxpdHkpKSkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uID0gImluZmVybm8iKSArIAogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbiA9ICJpbmZlcm5vIikgKyAKICBsYWJzKHRpdGxlID0gIlBDQSBvZiBleHRyYWN0ZWQgY2xpbWF0ZSIsIHggPSBwYXN0ZSgiUEMxICgiLCByb3VuZChzdW1tYXJ5LnBjYSRpbXBvcnRhbmNlWzIsMV0gKiAxMDAsIDEpLCIlKSIpLCB5ID0gcGFzdGUoIlBDMiAoIiwgcm91bmQoc3VtbWFyeS5wY2EkaW1wb3J0YW5jZVsyLDJdICogMTAwLCAxKSwiJSkiKSkgKyB0aGVtZV9taW5pbWFsKCkKcC5wbG90bHkuYWNhbiA8LSBnZ3Bsb3RseShwLmFjYW4sIHRvb2x0aXAgPSBjKCJ0ZXh0IikpCiNwbG90IGJpcGxvdApiLmFjYW4gPC0gZ2diaXBsb3QoY2xpbS5wY2EuYWNhbiwgZ3JvdXBzID0gbG9jLmNsaW0uYWNhbiRzcGVjaWVzLCBhbHBoYSA9IC43KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbiA9ICJpbmZlcm5vIikgKyAKICBnZ3RpdGxlKCJCaXBsb3Qgb2YgZXh0cmFjdGVkIGNsaW1hdGUiKQpgYGAKCmBgYHtyfQpwLnBsb3RseS5hY2FuCmBgYAoKYGBge3J9CmIuYWNhbgpgYGAKYGBge3J9CnN1bW1hcnkucGNhLmFjYW4Ka25pdHI6OmthYmxlKHJvdW5kKGNsaW0ucGNhLmFjYW4kcm90YXRpb25bLDE6M10sMykpICNUYWJsZSBvZiBsb2FkaW5nIHNjb3JlcyBmb3IgdGhlIGZpcnN0IDMgUENzLiAKCmBgYAoKCiMjI0FyZ29zYXJjaHVzCmBgYHtyfQojbWFrZSBhIG1hdHJpeCBvZiBvbmx5IGJpb2NsaW0gdmFsdWVzCmNsaW0ubWF0LmFyZ28gPC0gbG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gImFyZ29zYXJjaHVzIiwgZ3JlcCgiYmlvIiwgbmFtZXMobG9jLmNsaW0pKV0gJT4lIGFzLm1hdHJpeCgpCgojcnVuIHBjYSBvbiBjbGltYXRlIHZhcmlhYmxlcwpjbGltLnBjYS5hcmdvIDwtIHByY29tcChjbGltLm1hdC5hcmdvLCBzY2FsZSA9IFRSVUUpCnN1bW1hcnkucGNhLmFyZ28gPC0gc3VtbWFyeShjbGltLnBjYS5hcmdvKSAjY2hlY2sgb3V0IHRoZSBjb21wb25lbnRzCgpgYGAKCmBgYHtyfQojYWRkIHBjYSByZXN1bHRzIHRvIGxvYy5jbGltIGRhdGEgZnJhbWUKbG9jLmNsaW0uYXJnbyA8LSBkYXRhLmZyYW1lKGxvYy5jbGltW2xvYy5jbGltJGdlbnVzID09ICJhcmdvc2FyY2h1cyIsXSwgY2xpbS5wY2EuYXJnbyR4KQoKI21ha2UgY29udmV4IGh1bGwgb2YgZ2VuZXJhCmZpbmRfaHVsbCA8LSBmdW5jdGlvbihkZikgZGZbY2h1bGwoZGYkUEMxLjEsIGRmJFBDMi4xKSwgXQpodWxscyA8LSBwbHlyOjpkZHBseShsb2MuY2xpbS5hcmdvLCAiZ2VudXMiLCBmaW5kX2h1bGwpCgojbWFrZSBhbiBpbnRlcmFjdGl2ZSBwbG90IGluIHBsb3RseQpwLmFyZ28gPC0gZ2dwbG90KGRhdGEgPSBsb2MuY2xpbS5hcmdvLCBhZXMoeCA9IFBDMS4xLCB5ID0gUEMyLjEsIGNvbCA9IHNwZWNpZXMsIGZpbGwgPSBzcGVjaWVzKSkgKwogIGdlb21fcG9seWdvbihkYXRhID0gaHVsbHMsIGFscGhhID0gMC40KSAgKyAKICBnZW9tX3BvaW50KGFscGhhID0gLjcsIHNpemUgPSAxLCBhZXModGV4dCA9IHBhc3RlKCJJRDoiLCBpZCwgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VudXMsIHNwZWNpZXMsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb25nLUxhdDoiLCBjb29yZHMsIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxvY2FsaXR5OiIsIGxvY2FsaXR5KSkpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbiA9ICJpbmZlcm5vIikgKyAKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb24gPSAiaW5mZXJubyIpICsgCiAgbGFicyh0aXRsZSA9ICJQQ0Egb2YgZXh0cmFjdGVkIGNsaW1hdGUiLCB4ID0gcGFzdGUoIlBDMSAoIiwgcm91bmQoc3VtbWFyeS5wY2EuYXJnbyRpbXBvcnRhbmNlWzIsMV0gKiAxMDAsIDEpLCIlKSIpLCB5ID0gcGFzdGUoIlBDMiAoIiwgcm91bmQoc3VtbWFyeS5wY2EuYXJnbyRpbXBvcnRhbmNlWzIsMl0gKiAxMDAsIDEpLCIlKSIpKSArIHRoZW1lX21pbmltYWwoKQpwLnBsb3RseS5hcmdvIDwtIGdncGxvdGx5KHAuYXJnbywgdG9vbHRpcCA9IGMoInRleHQiKSkKI3Bsb3QgYmlwbG90CmIuYXJnbyA8LSBnZ2JpcGxvdChjbGltLnBjYS5hcmdvLCBncm91cHMgPSBsb2MuY2xpbS5hcmdvJHNwZWNpZXMsIGFscGhhID0gLjcpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uID0gImluZmVybm8iKSArIAogIGdndGl0bGUoIkJpcGxvdCBvZiBleHRyYWN0ZWQgY2xpbWF0ZSIpCmBgYAoKYGBge3J9CnAucGxvdGx5LmFyZ28KYGBgCgpgYGB7cn0KYi5hcmdvCmBgYAoKYGBge3J9CnN1bW1hcnkucGNhLmFyZ28Ka25pdHI6OmthYmxlKHJvdW5kKGNsaW0ucGNhLmFyZ28kcm90YXRpb25bLDE6M10sMykpICNUYWJsZSBvZiBsb2FkaW5nIHNjb3JlcyBmb3IgdGhlIGZpcnN0IDMgUENzLiAKYGBgCgojIyNBc3RlbGlhcGhhc21hCmBgYHtyfQojbWFrZSBhIG1hdHJpeCBvZiBvbmx5IGJpb2NsaW0gdmFsdWVzCmNsaW0ubWF0LmFzdGUgPC0gbG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gImFzdGVsaWFwaGFzbWEiLCBncmVwKCJiaW8iLCBuYW1lcyhsb2MuY2xpbSkpXSAlPiUgYXMubWF0cml4KCkKCiNydW4gcGNhIG9uIGNsaW1hdGUgdmFyaWFibGVzCmNsaW0ucGNhLmFzdGUgPC0gcHJjb21wKGNsaW0ubWF0LmFzdGUsIHNjYWxlID0gVFJVRSkKc3VtbWFyeS5wY2EuYXN0ZSA8LSBzdW1tYXJ5KGNsaW0ucGNhLmFzdGUpICNjaGVjayBvdXQgdGhlIGNvbXBvbmVudHMKCmBgYAoKYGBge3J9CiNhZGQgcGNhIHJlc3VsdHMgdG8gbG9jLmNsaW0gZGF0YSBmcmFtZQpsb2MuY2xpbS5hc3RlIDwtIGRhdGEuZnJhbWUobG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gImFzdGVsaWFwaGFzbWEiLF0sIGNsaW0ucGNhLmFzdGUkeCkKCiNtYWtlIGNvbnZleCBodWxsIG9mIGdlbmVyYQpmaW5kX2h1bGwgPC0gZnVuY3Rpb24oZGYpIGRmW2NodWxsKGRmJFBDMS4xLCBkZiRQQzIuMSksIF0KaHVsbHMgPC0gcGx5cjo6ZGRwbHkobG9jLmNsaW0uYXN0ZSwgImdlbnVzIiwgZmluZF9odWxsKQoKI21ha2UgYW4gaW50ZXJhY3RpdmUgcGxvdCBpbiBwbG90bHkKcC5hc3RlIDwtIGdncGxvdChkYXRhID0gbG9jLmNsaW0uYXN0ZSwgYWVzKHggPSBQQzEuMSwgeSA9IFBDMi4xLCBjb2wgPSBzcGVjaWVzLCBmaWxsID0gc3BlY2llcykpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IGh1bGxzLCBhbHBoYSA9IDAuNCkgICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IC43LCBzaXplID0gMSwgYWVzKHRleHQgPSBwYXN0ZSgiSUQ6IiwgaWQsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnVzLCBzcGVjaWVzLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9uZy1MYXQ6IiwgY29vcmRzLCI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb2NhbGl0eToiLCBsb2NhbGl0eSkpKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAidmlyaWRpcyIpICsgCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gInZpcmlkaXMiKSArIAogIGxhYnModGl0bGUgPSAiUENBIG9mIGV4dHJhY3RlZCBjbGltYXRlIiwgeCA9IHBhc3RlKCJQQzEgKCIsIHJvdW5kKHN1bW1hcnkucGNhLmFzdGUkaW1wb3J0YW5jZVsyLDFdICogMTAwLCAxKSwiJSkiKSwgeSA9IHBhc3RlKCJQQzIgKCIsIHJvdW5kKHN1bW1hcnkucGNhLmFzdGUkaW1wb3J0YW5jZVsyLDJdICogMTAwLCAxKSwiJSkiKSkgKyB0aGVtZV9taW5pbWFsKCkKcC5wbG90bHkuYXN0ZSA8LSBnZ3Bsb3RseShwLmFzdGUsIHRvb2x0aXAgPSBjKCJ0ZXh0IikpCiNwbG90IGJpcGxvdApiLmFzdGUgPC0gZ2diaXBsb3QoY2xpbS5wY2EuYXN0ZSwgZ3JvdXBzID0gbG9jLmNsaW0uYXN0ZSRzcGVjaWVzLCBhbHBoYSA9IC43KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbiA9ICJ2aXJpZGlzIikgKyAKICBnZ3RpdGxlKCJCaXBsb3Qgb2YgZXh0cmFjdGVkIGNsaW1hdGUiKQpgYGAKCmBgYHtyfQpwLnBsb3RseS5hc3RlCmBgYAoKYGBge3J9CmIuYXN0ZQpgYGAKYGBge3J9CnN1bW1hcnkucGNhLmFzdGUKa25pdHI6OmthYmxlKHJvdW5kKGNsaW0ucGNhLmFzdGUkcm90YXRpb25bLDE6M10sMykpICNUYWJsZSBvZiBsb2FkaW5nIHNjb3JlcyBmb3IgdGhlIGZpcnN0IDMgUENzLiAKYGBgCgoKIyMjQ2xpdGFyY2h1cwoKYGBge3J9CiNtYWtlIGEgbWF0cml4IG9mIG9ubHkgYmlvY2xpbSB2YWx1ZXMKY2xpbS5tYXQuY2xpdGEgPC0gbG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gImNsaXRhcmNodXMiLCBncmVwKCJiaW8iLCBuYW1lcyhsb2MuY2xpbSkpXSAlPiUgYXMubWF0cml4KCkKCiNydW4gcGNhIG9uIGNsaW1hdGUgdmFyaWFibGVzCmNsaW0ucGNhLmNsaXRhIDwtIHByY29tcChjbGltLm1hdC5jbGl0YSwgc2NhbGUgPSBUUlVFKQpzdW1tYXJ5LnBjYS5jbGl0YSA8LSBzdW1tYXJ5KGNsaW0ucGNhLmNsaXRhKSAjY2hlY2sgb3V0IHRoZSBjb21wb25lbnRzCgoKYGBgCgpgYGB7cn0KI2FkZCBwY2EgcmVzdWx0cyB0byBsb2MuY2xpbSBkYXRhIGZyYW1lCmxvYy5jbGltLmNsaXRhIDwtIGRhdGEuZnJhbWUobG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gImNsaXRhcmNodXMiLF0sIGNsaW0ucGNhLmNsaXRhJHgpCgojbWFrZSBjb252ZXggaHVsbCBvZiBnZW5lcmEKZmluZF9odWxsIDwtIGZ1bmN0aW9uKGRmKSBkZltjaHVsbChkZiRQQzEuMSwgZGYkUEMyLjEpLCBdCmh1bGxzIDwtIHBseXI6OmRkcGx5KGxvYy5jbGltLmNsaXRhLCAic3BlY2llcyIsIGZpbmRfaHVsbCkKCiNtYWtlIGFuIGludGVyYWN0aXZlIHBsb3QgaW4gcGxvdGx5CnAuY2xpdGEgPC0gZ2dwbG90KGRhdGEgPSBsb2MuY2xpbS5jbGl0YSwgYWVzKHggPSBQQzEuMSwgeSA9IFBDMi4xLCBjb2wgPSBzcGVjaWVzLCBmaWxsID0gc3BlY2llcykpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IGh1bGxzLCBhbHBoYSA9IDAuNCkgICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IC43LCBzaXplID0gMSwgYWVzKHRleHQgPSBwYXN0ZSgiSUQ6IiwgaWQsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnVzLCBzcGVjaWVzLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9uZy1MYXQ6IiwgY29vcmRzLCI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb2NhbGl0eToiLCBsb2NhbGl0eSkpKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAidmlyaWRpcyIpICsgCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gInZpcmlkaXMiKSArIAogIGxhYnModGl0bGUgPSAiUENBIG9mIGV4dHJhY3RlZCBjbGltYXRlIiwgeCA9IHBhc3RlKCJQQzEgKCIsIHJvdW5kKHN1bW1hcnkucGNhLmNsaXRhJGltcG9ydGFuY2VbMiwxXSAqIDEwMCwgMSksIiUpIiksIHkgPSBwYXN0ZSgiUEMyICgiLCByb3VuZChzdW1tYXJ5LnBjYS5jbGl0YSRpbXBvcnRhbmNlWzIsMl0gKiAxMDAsIDEpLCIlKSIpKSArIHRoZW1lX21pbmltYWwoKQpwLnBsb3RseS5jbGl0YSA8LSBnZ3Bsb3RseShwLmNsaXRhLCB0b29sdGlwID0gYygidGV4dCIpKQojcGxvdCBiaXBsb3QKYi5jbGl0YSA8LSBnZ2JpcGxvdChjbGltLnBjYS5jbGl0YSwgZ3JvdXBzID0gbG9jLmNsaW0uY2xpdGEkc3BlY2llcywgYWxwaGEgPSAuNykgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAidmlyaWRpcyIpICsgCiAgZ2d0aXRsZSgiQmlwbG90IG9mIGV4dHJhY3RlZCBjbGltYXRlIikKYGBgCgpgYGB7cn0KcC5wbG90bHkuY2xpdGEKYGBgCgoKYGBge3J9CmIuY2xpdGEKYGBgCmBgYHtyfQpzdW1tYXJ5LnBjYS5jbGl0YQprbml0cjo6a2FibGUocm91bmQoY2xpbS5wY2EuY2xpdGEkcm90YXRpb25bLDE6M10sMykpICNUYWJsZSBvZiBsb2FkaW5nIHNjb3JlcyBmb3IgdGhlIGZpcnN0IDMgUENzLiAKYGBgCgojIyNNaWNyYXJjaHVzCmBgYHtyfQojbWFrZSBhIG1hdHJpeCBvZiBvbmx5IGJpb2NsaW0gdmFsdWVzCmNsaW0ubWF0Lm1pY3JhIDwtIGxvYy5jbGltW2xvYy5jbGltJGdlbnVzID09ICJtaWNyYXJjaHVzIiwgZ3JlcCgiYmlvIiwgbmFtZXMobG9jLmNsaW0pKV0gJT4lIGFzLm1hdHJpeCgpCgojcnVuIHBjYSBvbiBjbGltYXRlIHZhcmlhYmxlcwpjbGltLnBjYS5taWNyYSA8LSBwcmNvbXAoY2xpbS5tYXQubWljcmEsIHNjYWxlID0gVFJVRSkKc3VtbWFyeS5wY2EubWljcmEgPC0gc3VtbWFyeShjbGltLnBjYS5taWNyYSkgI2NoZWNrIG91dCB0aGUgY29tcG9uZW50cwoKYGBgCgpgYGB7cn0KI2FkZCBwY2EgcmVzdWx0cyB0byBsb2MuY2xpbSBkYXRhIGZyYW1lCmxvYy5jbGltLm1pY3JhIDwtIGRhdGEuZnJhbWUobG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gIm1pY3JhcmNodXMiLF0sIGNsaW0ucGNhLm1pY3JhJHgpCgojbWFrZSBjb252ZXggaHVsbCBvZiBnZW5lcmEKZmluZF9odWxsIDwtIGZ1bmN0aW9uKGRmKSBkZltjaHVsbChkZiRQQzEuMSwgZGYkUEMyLjEpLCBdCmh1bGxzIDwtIHBseXI6OmRkcGx5KGxvYy5jbGltLm1pY3JhLCAic3BlY2llcyIsIGZpbmRfaHVsbCkKCiNtYWtlIGFuIGludGVyYWN0aXZlIHBsb3QgaW4gcGxvdGx5CnAubWljcmEgPC0gZ2dwbG90KGRhdGEgPSBsb2MuY2xpbS5taWNyYSwgYWVzKHggPSBQQzEuMSwgeSA9IFBDMi4xLCBjb2wgPSBzcGVjaWVzLCBmaWxsID0gc3BlY2llcykpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IGh1bGxzLCBhbHBoYSA9IDAuNCkgICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IC43LCBzaXplID0gMSwgYWVzKHRleHQgPSBwYXN0ZSgiSUQ6IiwgaWQsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnVzLCBzcGVjaWVzLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9uZy1MYXQ6IiwgY29vcmRzLCI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb2NhbGl0eToiLCBsb2NhbGl0eSkpKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAidmlyaWRpcyIpICsgCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gInZpcmlkaXMiKSArIAogIGxhYnModGl0bGUgPSAiUENBIG9mIGV4dHJhY3RlZCBjbGltYXRlIiwgeCA9IHBhc3RlKCJQQzEgKCIsIHJvdW5kKHN1bW1hcnkucGNhLm1pY3JhJGltcG9ydGFuY2VbMiwxXSAqIDEwMCwgMSksIiUpIiksIHkgPSBwYXN0ZSgiUEMyICgiLCByb3VuZChzdW1tYXJ5LnBjYS5taWNyYSRpbXBvcnRhbmNlWzIsMl0gKiAxMDAsIDEpLCIlKSIpKSArIHRoZW1lX21pbmltYWwoKQpwLnBsb3RseS5taWNyYSA8LSBnZ3Bsb3RseShwLm1pY3JhLCB0b29sdGlwID0gYygidGV4dCIpKQojcGxvdCBiaXBsb3QKYi5taWNyYSA8LSBnZ2JpcGxvdChjbGltLnBjYS5taWNyYSwgZ3JvdXBzID0gbG9jLmNsaW0ubWljcmEkc3BlY2llcywgYWxwaGEgPSAuNykgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAidmlyaWRpcyIpICsgCiAgZ2d0aXRsZSgiQmlwbG90IG9mIGV4dHJhY3RlZCBjbGltYXRlIikKYGBgCgpgYGB7cn0KcC5wbG90bHkubWljcmEKYGBgCgoKCmBgYHtyfQpiLm1pY3JhCmBgYApgYGB7cn0Kc3VtbWFyeS5wY2EubWljcmEKa25pdHI6OmthYmxlKHJvdW5kKGNsaW0ucGNhLm1pY3JhJHJvdGF0aW9uWywxOjNdLDMpKSAjVGFibGUgb2YgbG9hZGluZyBzY29yZXMgZm9yIHRoZSBmaXJzdCAzIFBDcy4gCmBgYAoKIyMjTml2ZWFwaGFzbWEKCmBgYHtyfQojbWFrZSBhIG1hdHJpeCBvZiBvbmx5IGJpb2NsaW0gdmFsdWVzCmNsaW0ubWF0Lm5pdmUgPC0gbG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gIm5pdmVhcGhhc21hIiwgZ3JlcCgiYmlvIiwgbmFtZXMobG9jLmNsaW0pKV0gJT4lIGFzLm1hdHJpeCgpCgojcnVuIHBjYSBvbiBjbGltYXRlIHZhcmlhYmxlcwpjbGltLnBjYS5uaXZlIDwtIHByY29tcChjbGltLm1hdC5uaXZlLCBzY2FsZSA9IFRSVUUpCnN1bW1hcnkucGNhLm5pdmUgPC0gc3VtbWFyeShjbGltLnBjYS5uaXZlKSAjY2hlY2sgb3V0IHRoZSBjb21wb25lbnRzCmBgYAoKCgpgYGB7cn0KI2FkZCBwY2EgcmVzdWx0cyB0byBsb2MuY2xpbSBkYXRhIGZyYW1lCmxvYy5jbGltLm5pdmUgPC0gZGF0YS5mcmFtZShsb2MuY2xpbVtsb2MuY2xpbSRnZW51cyA9PSAibml2ZWFwaGFzbWEiLF0sIGNsaW0ucGNhLm5pdmUkeCkKCiNtYWtlIGNvbnZleCBodWxsIG9mIGdlbmVyYQpmaW5kX2h1bGwgPC0gZnVuY3Rpb24oZGYpIGRmW2NodWxsKGRmJFBDMS4xLCBkZiRQQzIuMSksIF0KaHVsbHMgPC0gcGx5cjo6ZGRwbHkobG9jLmNsaW0ubml2ZSwgInNwZWNpZXMiLCBmaW5kX2h1bGwpCgojbWFrZSBhbiBpbnRlcmFjdGl2ZSBwbG90IGluIHBsb3RseQpwLm5pdmUgPC0gZ2dwbG90KGRhdGEgPSBsb2MuY2xpbS5uaXZlLCBhZXMoeCA9IFBDMS4xLCB5ID0gUEMyLjEsIGNvbCA9IHNwZWNpZXMsIGZpbGwgPSBzcGVjaWVzKSkgKwogIGdlb21fcG9seWdvbihkYXRhID0gaHVsbHMsIGFscGhhID0gMC40KSAgKyAKICBnZW9tX3BvaW50KGFscGhhID0gLjcsIHNpemUgPSAxLCBhZXModGV4dCA9IHBhc3RlKCJJRDoiLCBpZCwgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VudXMsIHNwZWNpZXMsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb25nLUxhdDoiLCBjb29yZHMsIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxvY2FsaXR5OiIsIGxvY2FsaXR5KSkpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbiA9ICJ2aXJpZGlzIikgKyAKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb24gPSAidmlyaWRpcyIpICsgCiAgbGFicyh0aXRsZSA9ICJQQ0Egb2YgZXh0cmFjdGVkIGNsaW1hdGUiLCB4ID0gcGFzdGUoIlBDMSAoIiwgcm91bmQoc3VtbWFyeS5wY2Eubml2ZSRpbXBvcnRhbmNlWzIsMV0gKiAxMDAsIDEpLCIlKSIpLCB5ID0gcGFzdGUoIlBDMiAoIiwgcm91bmQoc3VtbWFyeS5wY2Eubml2ZSRpbXBvcnRhbmNlWzIsMl0gKiAxMDAsIDEpLCIlKSIpKSArIHRoZW1lX21pbmltYWwoKQpwLnBsb3RseS5uaXZlIDwtIGdncGxvdGx5KHAubml2ZSwgdG9vbHRpcCA9IGMoInRleHQiKSkKI3Bsb3QgYmlwbG90CmIubml2ZSA8LSBnZ2JpcGxvdChjbGltLnBjYS5uaXZlLCBncm91cHMgPSBsb2MuY2xpbS5uaXZlJHNwZWNpZXMsIGFscGhhID0gLjcpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uID0gInZpcmlkaXMiKSArIAogIGdndGl0bGUoIkJpcGxvdCBvZiBleHRyYWN0ZWQgY2xpbWF0ZSIpCmBgYApgYGB7cn0KcC5wbG90bHkubml2ZQpgYGAKCmBgYHtyfQpiLm5pdmUKYGBgCmBgYHtyfQpzdW1tYXJ5LnBjYS5uaXZlCmtuaXRyOjprYWJsZShyb3VuZChjbGltLnBjYS5uaXZlJHJvdGF0aW9uWywxOjNdLDMpKSAjVGFibGUgb2YgbG9hZGluZyBzY29yZXMgZm9yIHRoZSBmaXJzdCAzIFBDcy4gCmBgYAoKIyMjU3Bpbm90ZWN0YXJjaHVzCgpgYGB7cn0KI21ha2UgYSBtYXRyaXggb2Ygb25seSBiaW9jbGltIHZhbHVlcwpjbGltLm1hdC5zcGluIDwtIGxvYy5jbGltW2xvYy5jbGltJGdlbnVzID09ICJzcGlub3RlY3RhcmNodXMiLCBncmVwKCJiaW8iLCBuYW1lcyhsb2MuY2xpbSkpXSAlPiUgYXMubWF0cml4KCkKCiNydW4gcGNhIG9uIGNsaW1hdGUgdmFyaWFibGVzCmNsaW0ucGNhLnNwaW4gPC0gcHJjb21wKGNsaW0ubWF0LnNwaW4sIHNjYWxlID0gVFJVRSkKc3VtbWFyeS5wY2Euc3BpbiA8LSBzdW1tYXJ5KGNsaW0ucGNhLnNwaW4pICNjaGVjayBvdXQgdGhlIGNvbXBvbmVudHMKCmBgYAoKYGBge3J9CiNhZGQgcGNhIHJlc3VsdHMgdG8gbG9jLmNsaW0gZGF0YSBmcmFtZQpsb2MuY2xpbS5zcGluIDwtIGRhdGEuZnJhbWUobG9jLmNsaW1bbG9jLmNsaW0kZ2VudXMgPT0gInNwaW5vdGVjdGFyY2h1cyIsXSwgY2xpbS5wY2Euc3BpbiR4KQoKI21ha2UgY29udmV4IGh1bGwgb2YgZ2VuZXJhCmZpbmRfaHVsbCA8LSBmdW5jdGlvbihkZikgZGZbY2h1bGwoZGYkUEMxLjEsIGRmJFBDMi4xKSwgXQpodWxscyA8LSBwbHlyOjpkZHBseShsb2MuY2xpbS5zcGluLCAic3BlY2llcyIsIGZpbmRfaHVsbCkKCiNtYWtlIGFuIGludGVyYWN0aXZlIHBsb3QgaW4gcGxvdGx5CnAuc3BpbiA8LSBnZ3Bsb3QoZGF0YSA9IGxvYy5jbGltLnNwaW4sIGFlcyh4ID0gUEMxLjEsIHkgPSBQQzIuMSwgY29sID0gc3BlY2llcywgZmlsbCA9IHNwZWNpZXMpKSArCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBodWxscywgYWxwaGEgPSAwLjQpICArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAuNywgc2l6ZSA9IDEsIGFlcyh0ZXh0ID0gcGFzdGUoIklEOiIsIGlkLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW51cywgc3BlY2llcywgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxvbmctTGF0OiIsIGNvb3JkcywiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9jYWxpdHk6IiwgbG9jYWxpdHkpKSkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uID0gInZpcmlkaXMiKSArIAogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbiA9ICJ2aXJpZGlzIikgKyAKICBsYWJzKHRpdGxlID0gIlBDQSBvZiBleHRyYWN0ZWQgY2xpbWF0ZSIsIHggPSBwYXN0ZSgiUEMxICgiLCByb3VuZChzdW1tYXJ5LnBjYS5zcGluJGltcG9ydGFuY2VbMiwxXSAqIDEwMCwgMSksIiUpIiksIHkgPSBwYXN0ZSgiUEMyICgiLCByb3VuZChzdW1tYXJ5LnBjYS5zcGluJGltcG9ydGFuY2VbMiwyXSAqIDEwMCwgMSksIiUpIikpICsgdGhlbWVfbWluaW1hbCgpCnAucGxvdGx5LnNwaW4gPC0gZ2dwbG90bHkocC5zcGluLCB0b29sdGlwID0gYygidGV4dCIpKQojcGxvdCBiaXBsb3QKYi5zcGluIDwtIGdnYmlwbG90KGNsaW0ucGNhLnNwaW4sIGdyb3VwcyA9IGxvYy5jbGltLnNwaW4kc3BlY2llcywgYWxwaGEgPSAuNykgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAidmlyaWRpcyIpICsgCiAgZ2d0aXRsZSgiQmlwbG90IG9mIGV4dHJhY3RlZCBjbGltYXRlIikKYGBgCgpgYGB7cn0KcC5wbG90bHkuc3BpbgpgYGAKCgpgYGB7cn0KYi5zcGluCmBgYApgYGB7cn0Kc3VtbWFyeS5wY2Euc3Bpbgprbml0cjo6a2FibGUocm91bmQoY2xpbS5wY2Euc3BpbiRyb3RhdGlvblssMTozXSwzKSkgI1RhYmxlIG9mIGxvYWRpbmcgc2NvcmVzIGZvciB0aGUgZmlyc3QgMyBQQ3MuIApgYGAKCiMjI1RlY3RhcmNodXMKYGBge3J9CiNtYWtlIGEgbWF0cml4IG9mIG9ubHkgYmlvY2xpbSB2YWx1ZXMKY2xpbS5tYXQudGVjdCA8LSBsb2MuY2xpbVtsb2MuY2xpbSRnZW51cyA9PSAidGVjdGFyY2h1cyIsIGdyZXAoImJpbyIsIG5hbWVzKGxvYy5jbGltKSldICU+JSBhcy5tYXRyaXgoKQoKI3J1biBwY2Egb24gY2xpbWF0ZSB2YXJpYWJsZXMKY2xpbS5wY2EudGVjdCA8LSBwcmNvbXAoY2xpbS5tYXQudGVjdCwgc2NhbGUgPSBUUlVFKQpzdW1tYXJ5LnBjYS50ZWN0IDwtIHN1bW1hcnkoY2xpbS5wY2EudGVjdCkgI2NoZWNrIG91dCB0aGUgY29tcG9uZW50cwpgYGAKCmBgYHtyfQojYWRkIHBjYSByZXN1bHRzIHRvIGxvYy5jbGltIGRhdGEgZnJhbWUKbG9jLmNsaW0udGVjdCA8LSBkYXRhLmZyYW1lKGxvYy5jbGltW2xvYy5jbGltJGdlbnVzID09ICJ0ZWN0YXJjaHVzIixdLCBjbGltLnBjYS50ZWN0JHgpCgojbWFrZSBjb252ZXggaHVsbCBvZiBnZW5lcmEKZmluZF9odWxsIDwtIGZ1bmN0aW9uKGRmKSBkZltjaHVsbChkZiRQQzEuMSwgZGYkUEMyLjEpLCBdCmh1bGxzIDwtIHBseXI6OmRkcGx5KGxvYy5jbGltLnRlY3QsICJzcGVjaWVzIiwgZmluZF9odWxsKQoKI21ha2UgYW4gaW50ZXJhY3RpdmUgcGxvdCBpbiBwbG90bHkKcC50ZWN0IDwtIGdncGxvdChkYXRhID0gbG9jLmNsaW0udGVjdCwgYWVzKHggPSBQQzEuMSwgeSA9IFBDMi4xLCBjb2wgPSBzcGVjaWVzLCBmaWxsID0gc3BlY2llcykpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IGh1bGxzLCBhbHBoYSA9IDAuNCkgICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IC43LCBzaXplID0gMSwgYWVzKHRleHQgPSBwYXN0ZSgiSUQ6IiwgaWQsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnVzLCBzcGVjaWVzLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9uZy1MYXQ6IiwgY29vcmRzLCI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb2NhbGl0eToiLCBsb2NhbGl0eSkpKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChvcHRpb24gPSAidmlyaWRpcyIpICsgCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gInZpcmlkaXMiKSArIAogIGxhYnModGl0bGUgPSAiUENBIG9mIGV4dHJhY3RlZCBjbGltYXRlIiwgeCA9IHBhc3RlKCJQQzEgKCIsIHJvdW5kKHN1bW1hcnkucGNhLnRlY3QkaW1wb3J0YW5jZVsyLDFdICogMTAwLCAxKSwiJSkiKSwgeSA9IHBhc3RlKCJQQzIgKCIsIHJvdW5kKHN1bW1hcnkucGNhLnRlY3QkaW1wb3J0YW5jZVsyLDJdICogMTAwLCAxKSwiJSkiKSkgKyB0aGVtZV9taW5pbWFsKCkKcC5wbG90bHkudGVjdCA8LSBnZ3Bsb3RseShwLnRlY3QsIHRvb2x0aXAgPSBjKCJ0ZXh0IikpCiNwbG90IGJpcGxvdApiLnRlY3QgPC0gZ2diaXBsb3QoY2xpbS5wY2EudGVjdCwgZ3JvdXBzID0gbG9jLmNsaW0udGVjdCRzcGVjaWVzLCBhbHBoYSA9IC43KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKG9wdGlvbiA9ICJ2aXJpZGlzIikgKyAKICBnZ3RpdGxlKCJCaXBsb3Qgb2YgZXh0cmFjdGVkIGNsaW1hdGUiKQpgYGAKCmBgYHtyfQpwLnBsb3RseS50ZWN0CmBgYAoKYGBge3J9CmIudGVjdApgYGAKCmBgYHtyfQpzdW1tYXJ5LnBjYS50ZWN0CmtuaXRyOjprYWJsZShyb3VuZChjbGltLnBjYS50ZWN0JHJvdGF0aW9uWywxOjNdLDMpKSAjVGFibGUgb2YgbG9hZGluZyBzY29yZXMgZm9yIHRoZSBmaXJzdCAzIFBDcy4gCmBgYAoKCiMjI1RlcGFraXBoYXNtYQpOb3RoaW5nLiBPbmx5IG9uZSBsb2NhbGl0eS4=