Install packages

install.packages("ggplot2")
library(ggplot2) 
install.packages('tidyverse')
library(tidyverse)

Data handling

# Load data
rawlie.data <- read.table('Pseudemoia_rawlinsoni_records_FINAL.csv', header=T,sep=',')  
str(rawlie.data)
View(rawlie.data)
summary(rawlie.data)
attach(rawlie.data)

#### make a new df which excludes records from our 2021/2022 tile surveys and active surveys (i.e. from a separate study)
rawlie.data2 <- subset(rawlie.data, Group=="Personal communication" | Group=="Online databases")
View(rawlie.data2)

Creat Bar plot showing the number of records of Pseudemoia rawlinoni in each year grouped by source.

###### stacked barplot
ggplot(rawlie.data2, aes(Year, fill=Group)) + 
  geom_bar(position=position_stack(reverse = TRUE), alpha=0.7, color="black")  +
  scale_fill_manual(values=c("cornflowerblue","maroon")) +
  scale_x_continuous(n.breaks = 10) +
  scale_y_continuous(name="Number of records", n.breaks = 5) +
  guides(fill=guide_legend(title="Record source", reverse = TRUE)) +
  theme_bw()
HABITAT SUITABILITY MODELLING
install.packages("dismo")
install.packages("maptools")
install.packages("maps")
install.packages("mapdata")
install.packages("dplyr")
install.packages("CoordinateCleaner")
install.packages("raster")
install.packages("ggplot2")
install.packages("scales")
install.packages("spThin")
install.packages("ecospat")
install.packages("sf")
install.packages("rnaturalearthdata")
install.packages("rnaturalearth")
install.packages("tidyverse")
install.packages("usdm")
install.packages("ENMeval")
install.packages("rJava")
install.packages("ncdf4")
install.packages("biomod2")

library(biomod2)
library(dismo)
library(maptools)
library(maps)    
library(mapdata) 
library(dplyr)
library(CoordinateCleaner)
library(raster)
library(spThin)
library(ecospat)
library(sf)
library(scales)
library(rnaturalearthdata)
library(rnaturalearth)
library(tidyverse)
library(usdm)
library(ENMeval)
library(rJava)
library(ncdf4)

LOAD OCCURRENCE DATA

getwd()
rawlie.data <- read.table('rawlie_data_pre-post.csv', header=T,sep=',')  %>% 
  mutate(Species="Pseudemoia rawlinsoni")
str(rawlie.data)
View(rawlie.data)

get aus map

aus_map <- ne_countries(scale = "medium",
              country = "Australia",
              returnclass = "sf")

plot records on Aus map

ggplot() +
  geom_sf(data = aus_map) +
  geom_point(data = rawlie.data, 
             aes(x = Longitude, 
                 y = Latitude)) +
  theme_bw()

thining to 1km

rawlie_geoThin <- thin(loc.data = rawlie.data,
                         lat.col = "Latitude",
                         long.col = "Longitude",
                         spec.col = "Species",
                         thin.par = 1,
                         reps = 100,
                         locs.thinned.list.return = TRUE,
                         write.files = FALSE,
                         write.log.file = FALSE)
rawlie_geoThin <- as.data.frame(rawlie_geoThin[7]) 

#write.csv(rawlie_geoThin, "rawlie_geoThin.csv", row.names = FALSE)

load background bioregions

rawlie_bioregions <- st_read("/Volumes/PHOTOS 4T1/QGIS/Rawlinsoni/rawlie IBRA regions/rawlie_background_V3.shp")

ggplot() +
  geom_sf(data = rawlie_bioregions) +
  geom_point(data = rawlie.data, 
             aes(x = Longitude, 
                 y = Latitude)) +
  theme_bw()

Uploading all environmental variables

# create template raster
raster_temp <- raster(rawlie_bioregions, res = 0.008333)

# resampling all variable to have same dimensions as template bioregion raster
# WORLDCLIM
worldclim <- stack(list.files(path = "/Volumes/PHOTOS 4T1/QGIS/wc2.1_30s_bio", 
                             full.names=TRUE)) %>% 
  resample(raster_temp, 
           method = "bilinear") %>% 
  mask(rawlie_bioregions)

#ENVIREM
envirem <- stack(list.files(path = "/Volumes/PHOTOS 4T1/QGIS/ENVIREM_elev_Australia_current_30arcsec_generic copy", 
                             pattern = ".tif", full.names=TRUE)) %>% 
  resample(raster_temp, 
           method = "bilinear") %>% 
  mask(rawlie_bioregions)

### NDVI

NDVI <- stack(list.files(path = "/Volumes/PHOTOS 4T1/QGIS/MODIS13 NDVI", 
                             pattern = ".tif", full.names=TRUE)) %>% 
  resample(raster_temp, 
           method = "bilinear") %>% 
  mask(rawlie_bioregions)

# DIST TO WATER LINES and BODIES
water_euclidean <- stack(list.files(path = "/Volumes/PHOTOS 4T1/QGIS/Water", 
                             pattern = ".tif", full.names=TRUE)) %>% 
  resample(raster_temp, 
           method = "bilinear") %>% 
  mask(rawlie_bioregions)

# soil moisture

soil_moisture <- stack(list.files(path = "/Volumes/PHOTOS 4T1/QGIS/Soil moisture", 
                             pattern = ".tif", full.names=TRUE)) %>% 
  resample(raster_temp, 
           method = "bilinear") %>% 
  mask(rawlie_bioregions)

# human index

human_index <- stack(list.files(path = "/Volumes/PHOTOS 4T1/QGIS/human index", 
                             pattern = ".tif", full.names=TRUE)) %>% 
  resample(raster_temp, 
           method = "bilinear") %>% 
  mask(rawlie_bioregions)

plot some varibles to check that they look good


plot(worldclim)
plot(human_index)

save variables to a raster stack called env

env <- stack(worldclim,
             envirem,
             NDVI,
             water_euclidean,
             soil_moisture,
             human_index)
names(env) <- c("bio1", 
                    "bio10",
                    "bio11",
                    "bio12",
                    "bio13",
                    "bio14",
                    "bio15",
                    "bio16",
                    "bio17",
                    "bio18",
                    "bio19",
                    "bio2",
                    "bio3",
                    "bio4",
                    "bio5",
                    "bio6",
                    "bio7",
                    "bio8",
                    "bio9",
                "aridity", "topowet", "tri","NDVI", "dist_to_waterbodies",  "dist_to_watercourses","soil_moisture","human_influence"
                    )

#dir.create("envStack")
#writeRaster(env, "./envStack/env.nc")

extract environmental data based on geothin

rawlie_env <- raster::extract(env, rawlie_geoThin) %>% 
  cbind(rawlie_geoThin) %>% 
  na.omit()

rawlie_env

check for correlations among variables

rawlie_env %>% 
  cor(method="pearson") %>% 
  as.data.frame()

PCA to check for correlations among variables

s.corcircle(dudi.pca(rawlie_env[-c(28,29)],
                     scannf = F,
                     nf = 2)$co, 
            xax = 1,
            yax = 2,
            grid = FALSE)

Variance inflation factor test (-28,29) is removing the last two columns from the data fram which are lat and long

vif(as.data.frame(rawlie_env[-c(28,29)]))

vifstep(as.data.frame(rawlie_env[-c(28,29)]))

vifcor(as.data.frame(rawlie_env[-c(28,29)]),
       th = 0.7)

loading in stack of variables AGAIN

#run1
env <- brick("./envStack/env.nc")
names(env) <- c("bio1", 
                    "bio10",
                    "bio11",
                    "bio12",
                    "bio13",
                    "bio14",
                    "bio15",
                    "bio16",
                    "bio17",
                    "bio18",
                    "bio19",
                    "bio2",
                    "bio3",
                    "bio4",
                    "bio5",
                    "bio6",
                    "bio7",
                    "bio8",
                    "bio9",
                "aridity", "topowet", "tri","NDVI", "dist_to_waterbodies",  "dist_to_watercourses","soil_moisture","human_influence"
                    )

subsetting based on desired variables

#run2
env_ps <- env[[c("bio5",
                 "bio6",
                 "bio15",
                 "aridity", 
                 "NDVI", 
                 "topowet",
                 "soil_moisture")]]
plot(env_ps)
#summary(env_ps[[7]])
plot(env_ps[["soil_moisture"]])
plot(env_ps[["NDVI"]])
plot(env_ps[["aridity"]])
plot(env_ps[["bio5"]])
plot(env_ps[["bio6"]])
plot(env_ps[["bio15"]])
plot(env_ps[["topowet"]])

reading csv of occ and bg

#run 3
rawlie_geoThin <- read.csv("rawlie_geoThin.csv")
rawlie_bg <- read.csv("rawlie_bg.csv")

extract enviro data from rawlie_geothin points based on smaller list of new preselected variables

rawlie_env <- raster::extract(env_ps, rawlie_geoThin) %>% 
  cbind(rawlie_geoThin) %>% 
  na.omit()

rawlie_env
rawlie_env %>% 
  cor(method="pearson") %>% 
  as.data.frame()
s.corcircle(dudi.pca(rawlie_env[-c(8,9)],
                     scannf = F,
                     nf = 2)$co, 
            xax = 1,
            yax = 2,
            grid = FALSE)
vif(as.data.frame(rawlie_env[-c(8,9)]))

vifstep(as.data.frame(rawlie_env[-c(8,9)]))

vifcor(as.data.frame(rawlie_env[-c(8,9)]),
       th = 0.72)

Visualizing spatial autocorrelation using mantel r correlogram

Spatial autocorrelation is not significantly different from zero in many distances

rawlie_correlogram <- rawlie_geoThin %>% 
  st_as_sf(coords = c("Longitude", "Latitude"),
           crs = 4326) %>% #converting projection from lat/long to metres for better interpretation
  st_transform(crs = 3112) %>% 
  st_coordinates() %>% 
  cbind(raster::extract(env_ps, rawlie_geoThin)) %>% 
  cbind(rawlie_geoThin) %>% 
  na.omit()

ecospat.mantel.correlogram(dfvar = rawlie_correlogram, 
                             colxy = 1:2, 
                             n = 100, 
                             colvar = 3:10, 
                             max = 10000, 
                             nclass = 50, 
                             nperm = 100)

GENERATE BG POINTS

library(spatstat)

#reference any one of your rasters so that the environmental raster has same properties as bias raster
raster_ref <- env_ps[["aridity"]]

samplingSites <- rawlie_geoThin %>% 
  st_as_sf(coords = c("Longitude", "Latitude"),
           crs = 4326) %>% #converting projection from lat/long to metres for better interpretation
  st_transform(crs = 3112) %>% 
                 st_coordinates() %>% 
                 data.frame()

shp <- rawlie_bioregions %>% 
        st_transform(3112) %>% 
  st_union()

Visualize reference data

Reference raster

plot(raster_ref)

Sampling sites

ggplot() +
  geom_sf(data = shp %>% st_as_sf()) +
  geom_sf(data = samplingSites %>% 
                  st_as_sf(coords = c("X", "Y"), 
                           crs = 3112)) +
  theme_minimal()

Posterio Analysis

#Point-pattern process transformation

Create a Point-pattern process (PPP) using the raw data. Here, i used the Lord Howe Island shapefile as “window”, and the coordinates of the samplign sites as “x = X” (originally “Longitude” in raw file) and “Y = y” (originally “Latitude” in raw file).

win <- as.owin(shp)
ppp <- ppp(x = pull(dplyr::select(samplingSites, X)),
           y = pull(dplyr::select(samplingSites, Y)),
           window = win)

Visualize PPP

plot(ppp)

Compute the bandwidth

I used cross-validation to select a smoothing bandwidth for the kernel estimation of point process intensity. The bandwidth σ is chosen to minimise the mean-square error criterion defined by Diggle (1985).

bw.diggle(X = ppp)

#sigma value is kilometres radius when smoothing the densities of occurences
#dont report if specifying your own bandwidth (which you are)

Compute the density of PPP

Here, the bandwidth was computed using cross-validation; edge correction was enabled and used diggle method. I then converted the bias file into raster with a GDA92 projection.

biasFile <- raster(density.ppp(ppp,
                               kernel = "gaussian",
                               sigma = 50000,
                               edge = TRUE,
                               diggle = TRUE),
                   crs = "EPSG:3112")

raster::crs(biasFile) <- "EPSG:3112"

Visualize density map / bias file RUN AS FULL CHUNK

plot(biasFile)
plot(shp, 
     color = NA, 
     add = TRUE)
plot(samplingSites %>% 
       st_as_sf(coords = c("X", "Y")),
     add = TRUE)

resample the bias file, to align with the reference raster.

Maxent requires all raster files (environemntal rasters and bias file) to have the same projection, resolution, and exent. Basically, if you cant stack() the raster files, maxent won’t run.

here, I first reprojected the bias file to a WGS 84 (reference raster projection), and then resampled the bias file based on the resolution and extent of the reference raster using a bilinear resampling method.

biasFile_export <- biasFile %>%
                     projectRaster(crs = "EPSG:4326") %>% 
                     resample(y = raster_ref,
                              method = "bilinear")

Plot bias file

plot(biasFile_export)

Double checking if the bias file has the same properties as that of the reference raster

#crs
proj4string(raster_ref) == proj4string(biasFile_export)
#resolution
res(raster_ref) == res(biasFile_export)
#extent
extent(raster_ref) == extent(biasFile_export)

write bias file

Finally, the bias file is written in the “./output” folder of the R project.

writeRaster(biasFile_export,
            "/Volumes/PHOTOS 4T1/QGIS/Rawlinsoni_project/biasfile.tif",
            overwrite = TRUE)

summary(biasFile_export)

Make all NAs 0, and then make all negative 0

values(biasFile_export)[is.na(values(biasFile_export))] <- 0

values(biasFile_export)[which(values(biasFile_export) < 0)] <- 0

making the bias background

rawlie_bg_bias <- xyFromCell(biasFile_export, sample(ncell(biasFile_export), 10000, prob = values(biasFile_export))) 

rawlie_bg_bias <- rawlie_bg_bias %>% 
  as_data_frame() %>% 
  rename(Longitude = x,
         Latitude = y)
  

plot(rawlie_bg_bias)
#write.csv(rawlie_bg_bias, "rawlie_bg_bias.csv", row.names = FALSE)

run model

save.image()

rawlie_enm <- ENMevaluate(occs = rawlie_geoThin, 
                          envs = env_ps, 
                          bg = rawlie_bg_bias, 
                          tune.args = list(rm=c(1:3), 
                                           fc=c('L','LQ', 'LQH', 'H')), 
                          algorithm='maxent.jar',
                          partitions = "checkerboard2", numCores = 6, parallel=TRUE)

save.image()

checking best model

x <- rawlie_enm@results %>% 
  arrange(delta.AICc)
x
#write.csv(x, "Model_eval.csv")

variable importance and response

library(ENMeval)
plot(eval.models(rawlie_enm)[["rm.1_fc.LQ"]],type = "cloglog") 
response(eval.models(rawlie_enm)[["rm.1_fc.LQ"]]) 

plot prediction

plot(eval.predictions(rawlie_enm)[["rm.1_fc.LQ"]]) 
points(rawlie_geoThin)

save prediction as a tif file

raster::writeRaster(eval.predictions(rawlie_enm)[["rm.1_fc.LQ"]], "rawlie.SDM.bias.corrected.tif", 
            format = "GTiff", overwrite = TRUE)

save.image()

tranforming into binary map

#### extract fitted scores of background an occurrence points

# combine bg and geo thin points
temp <- bind_rows(rawlie_geoThin %>% 
            mutate(rawlie = 1),
          rawlie_bg_bias %>% 
            mutate(rawlie = 0))
#extract predictions based on both occ and bg points
fitted_df <- raster::extract(eval.predictions(rawlie_enm)[["rm.1_fc.LQ"]], temp[,1:2]) %>% 
  as.data.frame() %>% 
  rename("fitted" = ".") %>% 
  bind_cols(temp) %>% 
  na.omit()

tranforming into binary map (continued)

# look for threatshold value (PUT "cutoff" value into the next few lines of code)
library(biomod2)
Find.Optim.Stat(Stat="ROC",
                Fit = fitted_df[, "fitted"],
                Obs = fitted_df[, "rawlie"])

#transform prediction in to binary maps
plot(BinaryTransformation(eval.predictions(rawlie_enm)[["rm.1_fc.LQ"]], 0.5867845))

#save
raster::writeRaster(BinaryTransformation(eval.predictions(rawlie_enm)[["rm.1_fc.LQ"]], 0.5867845), "rawlie.binary.bias.corrected.tif", 
            format = "GTiff", overwrite = TRUE)

save image


save.image()
LS0tCnRpdGxlOiAicmF3bGluc29uaSBwcm9qZWN0IgpQYXBlcjogIkNhcHR1cmluZyB1bmNhdGFsb2d1ZWQgZGlzdHJpYnV0aW9uIHJlY29yZHMgdG8gaW1wcm92ZSBjb25zZXJ2YXRpb24gYXNzZXNzbWVudHMgb2YgRGF0YSBEZWZpY2llbnQgc3BlY2llczogYSBjYXNlIHN0dWR5IHVzaW5nIHRoZSBnbG9zc3kgZ3Jhc3Mgc2tpbmsiCkF1dGhvcnMgb2YgdGhpcyBjb2RlOiBKdWxlcyBGYXJxdWhhciBhbmQgQXJtYW4gUGlsaQpEYXRlOiAxMi4wOS4yMDIyCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQojIyMgSW5zdGFsbCBwYWNrYWdlcwpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmxpYnJhcnkoZ2dwbG90MikgCmluc3RhbGwucGFja2FnZXMoJ3RpZHl2ZXJzZScpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKIyMjIyBEYXRhIGhhbmRsaW5nCmBgYHtyfQojIExvYWQgZGF0YQpyYXdsaWUuZGF0YSA8LSByZWFkLnRhYmxlKCdQc2V1ZGVtb2lhX3Jhd2xpbnNvbmlfcmVjb3Jkc19GSU5BTC5jc3YnLCBoZWFkZXI9VCxzZXA9JywnKSAgCnN0cihyYXdsaWUuZGF0YSkKVmlldyhyYXdsaWUuZGF0YSkKc3VtbWFyeShyYXdsaWUuZGF0YSkKYXR0YWNoKHJhd2xpZS5kYXRhKQoKIyMjIyBtYWtlIGEgbmV3IGRmIHdoaWNoIGV4Y2x1ZGVzIHJlY29yZHMgZnJvbSBvdXIgMjAyMS8yMDIyIHRpbGUgc3VydmV5cyBhbmQgYWN0aXZlIHN1cnZleXMgKGkuZS4gZnJvbSBhIHNlcGFyYXRlIHN0dWR5KQpyYXdsaWUuZGF0YTIgPC0gc3Vic2V0KHJhd2xpZS5kYXRhLCBHcm91cD09IlBlcnNvbmFsIGNvbW11bmljYXRpb24iIHwgR3JvdXA9PSJPbmxpbmUgZGF0YWJhc2VzIikKVmlldyhyYXdsaWUuZGF0YTIpCmBgYAojIyMjIENyZWF0IEJhciBwbG90IHNob3dpbmcgdGhlIG51bWJlciBvZiByZWNvcmRzIG9mIFBzZXVkZW1vaWEgcmF3bGlub25pIGluIGVhY2ggeWVhciBncm91cGVkIGJ5IHNvdXJjZS4KYGBge3J9CiMjIyMjIyBzdGFja2VkIGJhcnBsb3QKZ2dwbG90KHJhd2xpZS5kYXRhMiwgYWVzKFllYXIsIGZpbGw9R3JvdXApKSArIAogIGdlb21fYmFyKHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHJldmVyc2UgPSBUUlVFKSwgYWxwaGE9MC43LCBjb2xvcj0iYmxhY2siKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJjb3JuZmxvd2VyYmx1ZSIsIm1hcm9vbiIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG4uYnJlYWtzID0gMTApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZT0iTnVtYmVyIG9mIHJlY29yZHMiLCBuLmJyZWFrcyA9IDUpICsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IlJlY29yZCBzb3VyY2UiLCByZXZlcnNlID0gVFJVRSkpICsKICB0aGVtZV9idygpCmBgYAojIyMjIyBIQUJJVEFUIFNVSVRBQklMSVRZIE1PREVMTElORwpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZGlzbW8iKQppbnN0YWxsLnBhY2thZ2VzKCJtYXB0b29scyIpCmluc3RhbGwucGFja2FnZXMoIm1hcHMiKQppbnN0YWxsLnBhY2thZ2VzKCJtYXBkYXRhIikKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJDb29yZGluYXRlQ2xlYW5lciIpCmluc3RhbGwucGFja2FnZXMoInJhc3RlciIpCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQppbnN0YWxsLnBhY2thZ2VzKCJzY2FsZXMiKQppbnN0YWxsLnBhY2thZ2VzKCJzcFRoaW4iKQppbnN0YWxsLnBhY2thZ2VzKCJlY29zcGF0IikKaW5zdGFsbC5wYWNrYWdlcygic2YiKQppbnN0YWxsLnBhY2thZ2VzKCJybmF0dXJhbGVhcnRoZGF0YSIpCmluc3RhbGwucGFja2FnZXMoInJuYXR1cmFsZWFydGgiKQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQppbnN0YWxsLnBhY2thZ2VzKCJ1c2RtIikKaW5zdGFsbC5wYWNrYWdlcygiRU5NZXZhbCIpCmluc3RhbGwucGFja2FnZXMoInJKYXZhIikKaW5zdGFsbC5wYWNrYWdlcygibmNkZjQiKQppbnN0YWxsLnBhY2thZ2VzKCJiaW9tb2QyIikKCmxpYnJhcnkoYmlvbW9kMikKbGlicmFyeShkaXNtbykKbGlicmFyeShtYXB0b29scykKbGlicmFyeShtYXBzKSAgICAKbGlicmFyeShtYXBkYXRhKSAKbGlicmFyeShkcGx5cikKbGlicmFyeShDb29yZGluYXRlQ2xlYW5lcikKbGlicmFyeShyYXN0ZXIpCmxpYnJhcnkoc3BUaGluKQpsaWJyYXJ5KGVjb3NwYXQpCmxpYnJhcnkoc2YpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KHJuYXR1cmFsZWFydGhkYXRhKQpsaWJyYXJ5KHJuYXR1cmFsZWFydGgpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHVzZG0pCmxpYnJhcnkoRU5NZXZhbCkKbGlicmFyeShySmF2YSkKbGlicmFyeShuY2RmNCkKYGBgCiMjIyMgTE9BRCBPQ0NVUlJFTkNFIERBVEEKYGBge3J9CmdldHdkKCkKcmF3bGllLmRhdGEgPC0gcmVhZC50YWJsZSgncmF3bGllX2RhdGFfcHJlLXBvc3QuY3N2JywgaGVhZGVyPVQsc2VwPScsJykgICU+JSAKICBtdXRhdGUoU3BlY2llcz0iUHNldWRlbW9pYSByYXdsaW5zb25pIikKc3RyKHJhd2xpZS5kYXRhKQpWaWV3KHJhd2xpZS5kYXRhKQpgYGAKIyMjIyBnZXQgYXVzIG1hcApgYGB7cn0KYXVzX21hcCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwKICAgICAgICAgICAgICBjb3VudHJ5ID0gIkF1c3RyYWxpYSIsCiAgICAgICAgICAgICAgcmV0dXJuY2xhc3MgPSAic2YiKQpgYGAKIyMjIyBwbG90IHJlY29yZHMgb24gQXVzIG1hcApgYGB7cn0KZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IGF1c19tYXApICsKICBnZW9tX3BvaW50KGRhdGEgPSByYXdsaWUuZGF0YSwgCiAgICAgICAgICAgICBhZXMoeCA9IExvbmdpdHVkZSwgCiAgICAgICAgICAgICAgICAgeSA9IExhdGl0dWRlKSkgKwogIHRoZW1lX2J3KCkKYGBgCiMjIyMgdGhpbmluZyB0byAxa20KYGBge3J9CnJhd2xpZV9nZW9UaGluIDwtIHRoaW4obG9jLmRhdGEgPSByYXdsaWUuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxhdC5jb2wgPSAiTGF0aXR1ZGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgbG9uZy5jb2wgPSAiTG9uZ2l0dWRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWMuY29sID0gIlNwZWNpZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgdGhpbi5wYXIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgcmVwcyA9IDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIGxvY3MudGhpbm5lZC5saXN0LnJldHVybiA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICB3cml0ZS5maWxlcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgd3JpdGUubG9nLmZpbGUgPSBGQUxTRSkKcmF3bGllX2dlb1RoaW4gPC0gYXMuZGF0YS5mcmFtZShyYXdsaWVfZ2VvVGhpbls3XSkgCgojd3JpdGUuY3N2KHJhd2xpZV9nZW9UaGluLCAicmF3bGllX2dlb1RoaW4uY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAojIyMjIGxvYWQgYmFja2dyb3VuZCBiaW9yZWdpb25zCmBgYHtyfQpyYXdsaWVfYmlvcmVnaW9ucyA8LSBzdF9yZWFkKCIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvUmF3bGluc29uaS9yYXdsaWUgSUJSQSByZWdpb25zL3Jhd2xpZV9iYWNrZ3JvdW5kX1YzLnNocCIpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhID0gcmF3bGllX2Jpb3JlZ2lvbnMpICsKICBnZW9tX3BvaW50KGRhdGEgPSByYXdsaWUuZGF0YSwgCiAgICAgICAgICAgICBhZXMoeCA9IExvbmdpdHVkZSwgCiAgICAgICAgICAgICAgICAgeSA9IExhdGl0dWRlKSkgKwogIHRoZW1lX2J3KCkKYGBgCiMjIyMgVXBsb2FkaW5nIGFsbCBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcwpgYGB7cn0KIyBjcmVhdGUgdGVtcGxhdGUgcmFzdGVyCnJhc3Rlcl90ZW1wIDwtIHJhc3RlcihyYXdsaWVfYmlvcmVnaW9ucywgcmVzID0gMC4wMDgzMzMpCgojIHJlc2FtcGxpbmcgYWxsIHZhcmlhYmxlIHRvIGhhdmUgc2FtZSBkaW1lbnNpb25zIGFzIHRlbXBsYXRlIGJpb3JlZ2lvbiByYXN0ZXIKIyBXT1JMRENMSU0Kd29ybGRjbGltIDwtIHN0YWNrKGxpc3QuZmlsZXMocGF0aCA9ICIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvd2MyLjFfMzBzX2JpbyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXM9VFJVRSkpICU+JSAKICByZXNhbXBsZShyYXN0ZXJfdGVtcCwgCiAgICAgICAgICAgbWV0aG9kID0gImJpbGluZWFyIikgJT4lIAogIG1hc2socmF3bGllX2Jpb3JlZ2lvbnMpCgojRU5WSVJFTQplbnZpcmVtIDwtIHN0YWNrKGxpc3QuZmlsZXMocGF0aCA9ICIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvRU5WSVJFTV9lbGV2X0F1c3RyYWxpYV9jdXJyZW50XzMwYXJjc2VjX2dlbmVyaWMgY29weSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLnRpZiIsIGZ1bGwubmFtZXM9VFJVRSkpICU+JSAKICByZXNhbXBsZShyYXN0ZXJfdGVtcCwgCiAgICAgICAgICAgbWV0aG9kID0gImJpbGluZWFyIikgJT4lIAogIG1hc2socmF3bGllX2Jpb3JlZ2lvbnMpCgojIyMgTkRWSQoKTkRWSSA8LSBzdGFjayhsaXN0LmZpbGVzKHBhdGggPSAiL1ZvbHVtZXMvUEhPVE9TIDRUMS9RR0lTL01PRElTMTMgTkRWSSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLnRpZiIsIGZ1bGwubmFtZXM9VFJVRSkpICU+JSAKICByZXNhbXBsZShyYXN0ZXJfdGVtcCwgCiAgICAgICAgICAgbWV0aG9kID0gImJpbGluZWFyIikgJT4lIAogIG1hc2socmF3bGllX2Jpb3JlZ2lvbnMpCgojIERJU1QgVE8gV0FURVIgTElORVMgYW5kIEJPRElFUwp3YXRlcl9ldWNsaWRlYW4gPC0gc3RhY2sobGlzdC5maWxlcyhwYXRoID0gIi9Wb2x1bWVzL1BIT1RPUyA0VDEvUUdJUy9XYXRlciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLnRpZiIsIGZ1bGwubmFtZXM9VFJVRSkpICU+JSAKICByZXNhbXBsZShyYXN0ZXJfdGVtcCwgCiAgICAgICAgICAgbWV0aG9kID0gImJpbGluZWFyIikgJT4lIAogIG1hc2socmF3bGllX2Jpb3JlZ2lvbnMpCgojIHNvaWwgbW9pc3R1cmUKCnNvaWxfbW9pc3R1cmUgPC0gc3RhY2sobGlzdC5maWxlcyhwYXRoID0gIi9Wb2x1bWVzL1BIT1RPUyA0VDEvUUdJUy9Tb2lsIG1vaXN0dXJlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIudGlmIiwgZnVsbC5uYW1lcz1UUlVFKSkgJT4lIAogIHJlc2FtcGxlKHJhc3Rlcl90ZW1wLCAKICAgICAgICAgICBtZXRob2QgPSAiYmlsaW5lYXIiKSAlPiUgCiAgbWFzayhyYXdsaWVfYmlvcmVnaW9ucykKCiMgaHVtYW4gaW5kZXgKCmh1bWFuX2luZGV4IDwtIHN0YWNrKGxpc3QuZmlsZXMocGF0aCA9ICIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvaHVtYW4gaW5kZXgiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIi50aWYiLCBmdWxsLm5hbWVzPVRSVUUpKSAlPiUgCiAgcmVzYW1wbGUocmFzdGVyX3RlbXAsIAogICAgICAgICAgIG1ldGhvZCA9ICJiaWxpbmVhciIpICU+JSAKICBtYXNrKHJhd2xpZV9iaW9yZWdpb25zKQoKYGBgCiMjIyMgcGxvdCBzb21lIHZhcmlibGVzIHRvIGNoZWNrIHRoYXQgdGhleSBsb29rIGdvb2QKYGBge3J9CgpwbG90KHdvcmxkY2xpbSkKcGxvdChodW1hbl9pbmRleCkKCmBgYAojIyMjIHNhdmUgdmFyaWFibGVzIHRvIGEgcmFzdGVyIHN0YWNrIGNhbGxlZCBlbnYKYGBge3J9CmVudiA8LSBzdGFjayh3b3JsZGNsaW0sCiAgICAgICAgICAgICBlbnZpcmVtLAogICAgICAgICAgICAgTkRWSSwKICAgICAgICAgICAgIHdhdGVyX2V1Y2xpZGVhbiwKICAgICAgICAgICAgIHNvaWxfbW9pc3R1cmUsCiAgICAgICAgICAgICBodW1hbl9pbmRleCkKbmFtZXMoZW52KSA8LSBjKCJiaW8xIiwgCiAgICAgICAgICAgICAgICAgICAgImJpbzEwIiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTEiLAogICAgICAgICAgICAgICAgICAgICJiaW8xMiIsCiAgICAgICAgICAgICAgICAgICAgImJpbzEzIiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTQiLAogICAgICAgICAgICAgICAgICAgICJiaW8xNSIsCiAgICAgICAgICAgICAgICAgICAgImJpbzE2IiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTciLAogICAgICAgICAgICAgICAgICAgICJiaW8xOCIsCiAgICAgICAgICAgICAgICAgICAgImJpbzE5IiwKICAgICAgICAgICAgICAgICAgICAiYmlvMiIsCiAgICAgICAgICAgICAgICAgICAgImJpbzMiLAogICAgICAgICAgICAgICAgICAgICJiaW80IiwKICAgICAgICAgICAgICAgICAgICAiYmlvNSIsCiAgICAgICAgICAgICAgICAgICAgImJpbzYiLAogICAgICAgICAgICAgICAgICAgICJiaW83IiwKICAgICAgICAgICAgICAgICAgICAiYmlvOCIsCiAgICAgICAgICAgICAgICAgICAgImJpbzkiLAogICAgICAgICAgICAgICAgImFyaWRpdHkiLCAidG9wb3dldCIsICJ0cmkiLCJORFZJIiwgImRpc3RfdG9fd2F0ZXJib2RpZXMiLCAgImRpc3RfdG9fd2F0ZXJjb3Vyc2VzIiwic29pbF9tb2lzdHVyZSIsImh1bWFuX2luZmx1ZW5jZSIKICAgICAgICAgICAgICAgICAgICApCgojZGlyLmNyZWF0ZSgiZW52U3RhY2siKQojd3JpdGVSYXN0ZXIoZW52LCAiLi9lbnZTdGFjay9lbnYubmMiKQpgYGAKIyMjIyBleHRyYWN0IGVudmlyb25tZW50YWwgZGF0YSBiYXNlZCBvbiBnZW90aGluCmBgYHtyfQpyYXdsaWVfZW52IDwtIHJhc3Rlcjo6ZXh0cmFjdChlbnYsIHJhd2xpZV9nZW9UaGluKSAlPiUgCiAgY2JpbmQocmF3bGllX2dlb1RoaW4pICU+JSAKICBuYS5vbWl0KCkKCnJhd2xpZV9lbnYKCmBgYAojIyMjIGNoZWNrIGZvciBjb3JyZWxhdGlvbnMgYW1vbmcgdmFyaWFibGVzCmBgYHtyfQpyYXdsaWVfZW52ICU+JSAKICBjb3IobWV0aG9kPSJwZWFyc29uIikgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQoKYGBgCiMjIyMgUENBIHRvIGNoZWNrIGZvciBjb3JyZWxhdGlvbnMgYW1vbmcgdmFyaWFibGVzCmBgYHtyfQpzLmNvcmNpcmNsZShkdWRpLnBjYShyYXdsaWVfZW52Wy1jKDI4LDI5KV0sCiAgICAgICAgICAgICAgICAgICAgIHNjYW5uZiA9IEYsCiAgICAgICAgICAgICAgICAgICAgIG5mID0gMikkY28sIAogICAgICAgICAgICB4YXggPSAxLAogICAgICAgICAgICB5YXggPSAyLAogICAgICAgICAgICBncmlkID0gRkFMU0UpCmBgYAojIyMjIFZhcmlhbmNlIGluZmxhdGlvbiBmYWN0b3IgdGVzdCAoLTI4LDI5KSBpcyByZW1vdmluZyB0aGUgbGFzdCB0d28gY29sdW1ucyBmcm9tIHRoZSBkYXRhIGZyYW0gd2hpY2ggYXJlIGxhdCBhbmQgbG9uZwpgYGB7cn0KdmlmKGFzLmRhdGEuZnJhbWUocmF3bGllX2VudlstYygyOCwyOSldKSkKCnZpZnN0ZXAoYXMuZGF0YS5mcmFtZShyYXdsaWVfZW52Wy1jKDI4LDI5KV0pKQoKdmlmY29yKGFzLmRhdGEuZnJhbWUocmF3bGllX2VudlstYygyOCwyOSldKSwKICAgICAgIHRoID0gMC43KQpgYGAKIyMjIyBsb2FkaW5nIGluIHN0YWNrIG9mIHZhcmlhYmxlcyBBR0FJTgpgYGB7cn0KI3J1bjEKZW52IDwtIGJyaWNrKCIuL2VudlN0YWNrL2Vudi5uYyIpCm5hbWVzKGVudikgPC0gYygiYmlvMSIsIAogICAgICAgICAgICAgICAgICAgICJiaW8xMCIsCiAgICAgICAgICAgICAgICAgICAgImJpbzExIiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTIiLAogICAgICAgICAgICAgICAgICAgICJiaW8xMyIsCiAgICAgICAgICAgICAgICAgICAgImJpbzE0IiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTUiLAogICAgICAgICAgICAgICAgICAgICJiaW8xNiIsCiAgICAgICAgICAgICAgICAgICAgImJpbzE3IiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTgiLAogICAgICAgICAgICAgICAgICAgICJiaW8xOSIsCiAgICAgICAgICAgICAgICAgICAgImJpbzIiLAogICAgICAgICAgICAgICAgICAgICJiaW8zIiwKICAgICAgICAgICAgICAgICAgICAiYmlvNCIsCiAgICAgICAgICAgICAgICAgICAgImJpbzUiLAogICAgICAgICAgICAgICAgICAgICJiaW82IiwKICAgICAgICAgICAgICAgICAgICAiYmlvNyIsCiAgICAgICAgICAgICAgICAgICAgImJpbzgiLAogICAgICAgICAgICAgICAgICAgICJiaW85IiwKICAgICAgICAgICAgICAgICJhcmlkaXR5IiwgInRvcG93ZXQiLCAidHJpIiwiTkRWSSIsICJkaXN0X3RvX3dhdGVyYm9kaWVzIiwgICJkaXN0X3RvX3dhdGVyY291cnNlcyIsInNvaWxfbW9pc3R1cmUiLCJodW1hbl9pbmZsdWVuY2UiCiAgICAgICAgICAgICAgICAgICAgKQpgYGAKIyMjIyBzdWJzZXR0aW5nIGJhc2VkIG9uIGRlc2lyZWQgdmFyaWFibGVzCmBgYHtyfQojcnVuMgplbnZfcHMgPC0gZW52W1tjKCJiaW81IiwKICAgICAgICAgICAgICAgICAiYmlvNiIsCiAgICAgICAgICAgICAgICAgImJpbzE1IiwKICAgICAgICAgICAgICAgICAiYXJpZGl0eSIsIAogICAgICAgICAgICAgICAgICJORFZJIiwgCiAgICAgICAgICAgICAgICAgInRvcG93ZXQiLAogICAgICAgICAgICAgICAgICJzb2lsX21vaXN0dXJlIildXQpwbG90KGVudl9wcykKI3N1bW1hcnkoZW52X3BzW1s3XV0pCnBsb3QoZW52X3BzW1sic29pbF9tb2lzdHVyZSJdXSkKcGxvdChlbnZfcHNbWyJORFZJIl1dKQpwbG90KGVudl9wc1tbImFyaWRpdHkiXV0pCnBsb3QoZW52X3BzW1siYmlvNSJdXSkKcGxvdChlbnZfcHNbWyJiaW82Il1dKQpwbG90KGVudl9wc1tbImJpbzE1Il1dKQpwbG90KGVudl9wc1tbInRvcG93ZXQiXV0pCmBgYAojIyMjIHJlYWRpbmcgY3N2IG9mIG9jYyBhbmQgYmcKYGBge3J9CiNydW4gMwpyYXdsaWVfZ2VvVGhpbiA8LSByZWFkLmNzdigicmF3bGllX2dlb1RoaW4uY3N2IikKcmF3bGllX2JnIDwtIHJlYWQuY3N2KCJyYXdsaWVfYmcuY3N2IikKYGBgCiMjIyMgZXh0cmFjdCBlbnZpcm8gZGF0YSBmcm9tIHJhd2xpZV9nZW90aGluIHBvaW50cyBiYXNlZCBvbiBzbWFsbGVyIGxpc3Qgb2YgbmV3IHByZXNlbGVjdGVkIHZhcmlhYmxlcwpgYGB7cn0KcmF3bGllX2VudiA8LSByYXN0ZXI6OmV4dHJhY3QoZW52X3BzLCByYXdsaWVfZ2VvVGhpbikgJT4lIAogIGNiaW5kKHJhd2xpZV9nZW9UaGluKSAlPiUgCiAgbmEub21pdCgpCgpyYXdsaWVfZW52CmBgYAoKYGBge3J9CnJhd2xpZV9lbnYgJT4lIAogIGNvcihtZXRob2Q9InBlYXJzb24iKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpCgpgYGAKCmBgYHtyfQpzLmNvcmNpcmNsZShkdWRpLnBjYShyYXdsaWVfZW52Wy1jKDgsOSldLAogICAgICAgICAgICAgICAgICAgICBzY2FubmYgPSBGLAogICAgICAgICAgICAgICAgICAgICBuZiA9IDIpJGNvLCAKICAgICAgICAgICAgeGF4ID0gMSwKICAgICAgICAgICAgeWF4ID0gMiwKICAgICAgICAgICAgZ3JpZCA9IEZBTFNFKQpgYGAKCmBgYHtyfQp2aWYoYXMuZGF0YS5mcmFtZShyYXdsaWVfZW52Wy1jKDgsOSldKSkKCnZpZnN0ZXAoYXMuZGF0YS5mcmFtZShyYXdsaWVfZW52Wy1jKDgsOSldKSkKCnZpZmNvcihhcy5kYXRhLmZyYW1lKHJhd2xpZV9lbnZbLWMoOCw5KV0pLAogICAgICAgdGggPSAwLjcyKQpgYGAKIyMjIyBWaXN1YWxpemluZyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiB1c2luZyBtYW50ZWwgciBjb3JyZWxvZ3JhbQoKU3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgbm90IHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gemVybyBpbiBtYW55IGRpc3RhbmNlcwpgYGB7cn0KcmF3bGllX2NvcnJlbG9ncmFtIDwtIHJhd2xpZV9nZW9UaGluICU+JSAKICBzdF9hc19zZihjb29yZHMgPSBjKCJMb25naXR1ZGUiLCAiTGF0aXR1ZGUiKSwKICAgICAgICAgICBjcnMgPSA0MzI2KSAlPiUgI2NvbnZlcnRpbmcgcHJvamVjdGlvbiBmcm9tIGxhdC9sb25nIHRvIG1ldHJlcyBmb3IgYmV0dGVyIGludGVycHJldGF0aW9uCiAgc3RfdHJhbnNmb3JtKGNycyA9IDMxMTIpICU+JSAKICBzdF9jb29yZGluYXRlcygpICU+JSAKICBjYmluZChyYXN0ZXI6OmV4dHJhY3QoZW52X3BzLCByYXdsaWVfZ2VvVGhpbikpICU+JSAKICBjYmluZChyYXdsaWVfZ2VvVGhpbikgJT4lIAogIG5hLm9taXQoKQoKZWNvc3BhdC5tYW50ZWwuY29ycmVsb2dyYW0oZGZ2YXIgPSByYXdsaWVfY29ycmVsb2dyYW0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHh5ID0gMToyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gMTAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x2YXIgPSAzOjEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXggPSAxMDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNsYXNzID0gNTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5wZXJtID0gMTAwKQpgYGAKIyMjIyBHRU5FUkFURSBCRyBQT0lOVFMgCmBgYHtyfQpsaWJyYXJ5KHNwYXRzdGF0KQoKI3JlZmVyZW5jZSBhbnkgb25lIG9mIHlvdXIgcmFzdGVycyBzbyB0aGF0IHRoZSBlbnZpcm9ubWVudGFsIHJhc3RlciBoYXMgc2FtZSBwcm9wZXJ0aWVzIGFzIGJpYXMgcmFzdGVyCnJhc3Rlcl9yZWYgPC0gZW52X3BzW1siYXJpZGl0eSJdXQoKc2FtcGxpbmdTaXRlcyA8LSByYXdsaWVfZ2VvVGhpbiAlPiUgCiAgc3RfYXNfc2YoY29vcmRzID0gYygiTG9uZ2l0dWRlIiwgIkxhdGl0dWRlIiksCiAgICAgICAgICAgY3JzID0gNDMyNikgJT4lICNjb252ZXJ0aW5nIHByb2plY3Rpb24gZnJvbSBsYXQvbG9uZyB0byBtZXRyZXMgZm9yIGJldHRlciBpbnRlcnByZXRhdGlvbgogIHN0X3RyYW5zZm9ybShjcnMgPSAzMTEyKSAlPiUgCiAgICAgICAgICAgICAgICAgc3RfY29vcmRpbmF0ZXMoKSAlPiUgCiAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZSgpCgpzaHAgPC0gcmF3bGllX2Jpb3JlZ2lvbnMgJT4lIAogICAgICAgIHN0X3RyYW5zZm9ybSgzMTEyKSAlPiUgCiAgc3RfdW5pb24oKQpgYGAKIyMjIyBWaXN1YWxpemUgcmVmZXJlbmNlIGRhdGEKClJlZmVyZW5jZSByYXN0ZXIKYGBge3J9CnBsb3QocmFzdGVyX3JlZikKYGBgCiMjIyMgU2FtcGxpbmcgc2l0ZXMKYGBge3J9CmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSBzaHAgJT4lIHN0X2FzX3NmKCkpICsKICBnZW9tX3NmKGRhdGEgPSBzYW1wbGluZ1NpdGVzICU+JSAKICAgICAgICAgICAgICAgICAgc3RfYXNfc2YoY29vcmRzID0gYygiWCIsICJZIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjcnMgPSAzMTEyKSkgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCiMjIyMgUG9zdGVyaW8gQW5hbHlzaXMKCiNQb2ludC1wYXR0ZXJuIHByb2Nlc3MgdHJhbnNmb3JtYXRpb24KCkNyZWF0ZSBhIFBvaW50LXBhdHRlcm4gcHJvY2VzcyAoUFBQKSB1c2luZyB0aGUgcmF3IGRhdGEuIEhlcmUsIGkgdXNlZCB0aGUgTG9yZCBIb3dlIElzbGFuZCBzaGFwZWZpbGUgYXMgIndpbmRvdyIsIGFuZCB0aGUgY29vcmRpbmF0ZXMgb2YgdGhlIHNhbXBsaWduIHNpdGVzIGFzICJ4ID0gWCIgKG9yaWdpbmFsbHkgIkxvbmdpdHVkZSIgaW4gcmF3IGZpbGUpIGFuZCAiWSA9IHkiIChvcmlnaW5hbGx5ICJMYXRpdHVkZSIgaW4gcmF3IGZpbGUpLgoKYGBge3J9CndpbiA8LSBhcy5vd2luKHNocCkKcHBwIDwtIHBwcCh4ID0gcHVsbChkcGx5cjo6c2VsZWN0KHNhbXBsaW5nU2l0ZXMsIFgpKSwKICAgICAgICAgICB5ID0gcHVsbChkcGx5cjo6c2VsZWN0KHNhbXBsaW5nU2l0ZXMsIFkpKSwKICAgICAgICAgICB3aW5kb3cgPSB3aW4pCmBgYAoKIyMjIyBWaXN1YWxpemUgUFBQCmBgYHtyfQpwbG90KHBwcCkKCmBgYAojIyMjIENvbXB1dGUgdGhlIGJhbmR3aWR0aApJIHVzZWQgY3Jvc3MtdmFsaWRhdGlvbiB0byBzZWxlY3QgYSBzbW9vdGhpbmcgYmFuZHdpZHRoIGZvciB0aGUga2VybmVsIGVzdGltYXRpb24gb2YgcG9pbnQgcHJvY2VzcyBpbnRlbnNpdHkuIFRoZSBiYW5kd2lkdGggz4MgaXMgY2hvc2VuIHRvIG1pbmltaXNlIHRoZSBtZWFuLXNxdWFyZSBlcnJvciBjcml0ZXJpb24gZGVmaW5lZCBieSBEaWdnbGUgKDE5ODUpLgpgYGB7cn0KYncuZGlnZ2xlKFggPSBwcHApCgojc2lnbWEgdmFsdWUgaXMga2lsb21ldHJlcyByYWRpdXMgd2hlbiBzbW9vdGhpbmcgdGhlIGRlbnNpdGllcyBvZiBvY2N1cmVuY2VzCiNkb250IHJlcG9ydCBpZiBzcGVjaWZ5aW5nIHlvdXIgb3duIGJhbmR3aWR0aCAod2hpY2ggeW91IGFyZSkKYGBgCiMjIyMgQ29tcHV0ZSB0aGUgZGVuc2l0eSBvZiBQUFAKSGVyZSwgdGhlIGJhbmR3aWR0aCB3YXMgY29tcHV0ZWQgdXNpbmcgY3Jvc3MtdmFsaWRhdGlvbjsgZWRnZSBjb3JyZWN0aW9uIHdhcyBlbmFibGVkIGFuZCB1c2VkIGRpZ2dsZSBtZXRob2QuIEkgdGhlbiBjb252ZXJ0ZWQgdGhlIGJpYXMgZmlsZSBpbnRvIHJhc3RlciB3aXRoIGEgR0RBOTIgcHJvamVjdGlvbi4KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KYmlhc0ZpbGUgPC0gcmFzdGVyKGRlbnNpdHkucHBwKHBwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlcm5lbCA9ICJnYXVzc2lhbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWdtYSA9IDUwMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWRnZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdnbGUgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgIGNycyA9ICJFUFNHOjMxMTIiKQoKcmFzdGVyOjpjcnMoYmlhc0ZpbGUpIDwtICJFUFNHOjMxMTIiCmBgYAojIyMjIFZpc3VhbGl6ZSBkZW5zaXR5IG1hcCAvIGJpYXMgZmlsZSBSVU4gQVMgRlVMTCBDSFVOSwpgYGB7cn0KcGxvdChiaWFzRmlsZSkKcGxvdChzaHAsIAogICAgIGNvbG9yID0gTkEsIAogICAgIGFkZCA9IFRSVUUpCnBsb3Qoc2FtcGxpbmdTaXRlcyAlPiUgCiAgICAgICBzdF9hc19zZihjb29yZHMgPSBjKCJYIiwgIlkiKSksCiAgICAgYWRkID0gVFJVRSkKYGBgCiMjIyMgcmVzYW1wbGUgdGhlIGJpYXMgZmlsZSwgdG8gYWxpZ24gd2l0aCB0aGUgcmVmZXJlbmNlIHJhc3Rlci4KCk1heGVudCByZXF1aXJlcyBhbGwgcmFzdGVyIGZpbGVzIChlbnZpcm9uZW1udGFsIHJhc3RlcnMgYW5kIGJpYXMgZmlsZSkgdG8gaGF2ZSB0aGUgc2FtZSBwcm9qZWN0aW9uLCByZXNvbHV0aW9uLCBhbmQgZXhlbnQuIEJhc2ljYWxseSwgaWYgeW91IGNhbnQgc3RhY2soKSB0aGUgcmFzdGVyIGZpbGVzLCBtYXhlbnQgd29uJ3QgcnVuLgoKaGVyZSwgSSBmaXJzdCByZXByb2plY3RlZCB0aGUgYmlhcyBmaWxlIHRvIGEgV0dTIDg0IChyZWZlcmVuY2UgcmFzdGVyIHByb2plY3Rpb24pLCBhbmQgdGhlbiByZXNhbXBsZWQgdGhlIGJpYXMgZmlsZSBiYXNlZCBvbiB0aGUgcmVzb2x1dGlvbiBhbmQgZXh0ZW50IG9mIHRoZSByZWZlcmVuY2UgcmFzdGVyIHVzaW5nIGEgYmlsaW5lYXIgcmVzYW1wbGluZyBtZXRob2QuCgpgYGB7cn0KYmlhc0ZpbGVfZXhwb3J0IDwtIGJpYXNGaWxlICU+JQogICAgICAgICAgICAgICAgICAgICBwcm9qZWN0UmFzdGVyKGNycyA9ICJFUFNHOjQzMjYiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgIHJlc2FtcGxlKHkgPSByYXN0ZXJfcmVmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiYmlsaW5lYXIiKQpgYGAKIyMjIyBQbG90IGJpYXMgZmlsZQpgYGB7cn0KcGxvdChiaWFzRmlsZV9leHBvcnQpCmBgYAojIyMjIERvdWJsZSBjaGVja2luZyBpZiB0aGUgYmlhcyBmaWxlIGhhcyB0aGUgc2FtZSBwcm9wZXJ0aWVzIGFzIHRoYXQgb2YgdGhlIHJlZmVyZW5jZSByYXN0ZXIKCmBgYHtyfQojY3JzCnByb2o0c3RyaW5nKHJhc3Rlcl9yZWYpID09IHByb2o0c3RyaW5nKGJpYXNGaWxlX2V4cG9ydCkKI3Jlc29sdXRpb24KcmVzKHJhc3Rlcl9yZWYpID09IHJlcyhiaWFzRmlsZV9leHBvcnQpCiNleHRlbnQKZXh0ZW50KHJhc3Rlcl9yZWYpID09IGV4dGVudChiaWFzRmlsZV9leHBvcnQpCmBgYAojIyMjIHdyaXRlIGJpYXMgZmlsZQpGaW5hbGx5LCB0aGUgYmlhcyBmaWxlIGlzIHdyaXR0ZW4gaW4gdGhlICIuL291dHB1dCIgZm9sZGVyIG9mIHRoZSBSIHByb2plY3QuCmBgYHtyfQp3cml0ZVJhc3RlcihiaWFzRmlsZV9leHBvcnQsCiAgICAgICAgICAgICIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvUmF3bGluc29uaV9wcm9qZWN0L2JpYXNmaWxlLnRpZiIsCiAgICAgICAgICAgIG92ZXJ3cml0ZSA9IFRSVUUpCgpzdW1tYXJ5KGJpYXNGaWxlX2V4cG9ydCkKYGBgCiMjIyMgTWFrZSBhbGwgTkFzIDAsIGFuZCB0aGVuIG1ha2UgYWxsIG5lZ2F0aXZlIDAKYGBge3J9CnZhbHVlcyhiaWFzRmlsZV9leHBvcnQpW2lzLm5hKHZhbHVlcyhiaWFzRmlsZV9leHBvcnQpKV0gPC0gMAoKdmFsdWVzKGJpYXNGaWxlX2V4cG9ydClbd2hpY2godmFsdWVzKGJpYXNGaWxlX2V4cG9ydCkgPCAwKV0gPC0gMAoKYGBgCiMjIyMgbWFraW5nIHRoZSBiaWFzIGJhY2tncm91bmQKYGBge3J9CnJhd2xpZV9iZ19iaWFzIDwtIHh5RnJvbUNlbGwoYmlhc0ZpbGVfZXhwb3J0LCBzYW1wbGUobmNlbGwoYmlhc0ZpbGVfZXhwb3J0KSwgMTAwMDAsIHByb2IgPSB2YWx1ZXMoYmlhc0ZpbGVfZXhwb3J0KSkpIAoKcmF3bGllX2JnX2JpYXMgPC0gcmF3bGllX2JnX2JpYXMgJT4lIAogIGFzX2RhdGFfZnJhbWUoKSAlPiUgCiAgcmVuYW1lKExvbmdpdHVkZSA9IHgsCiAgICAgICAgIExhdGl0dWRlID0geSkKICAKCnBsb3QocmF3bGllX2JnX2JpYXMpCiN3cml0ZS5jc3YocmF3bGllX2JnX2JpYXMsICJyYXdsaWVfYmdfYmlhcy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCiMjIyMgcnVuIG1vZGVsCmBgYHtyfQpzYXZlLmltYWdlKCkKCnJhd2xpZV9lbm0gPC0gRU5NZXZhbHVhdGUob2NjcyA9IHJhd2xpZV9nZW9UaGluLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBlbnZzID0gZW52X3BzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBiZyA9IHJhd2xpZV9iZ19iaWFzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICB0dW5lLmFyZ3MgPSBsaXN0KHJtPWMoMTozKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYz1jKCdMJywnTFEnLCAnTFFIJywgJ0gnKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFsZ29yaXRobT0nbWF4ZW50LmphcicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFydGl0aW9ucyA9ICJjaGVja2VyYm9hcmQyIiwgbnVtQ29yZXMgPSA2LCBwYXJhbGxlbD1UUlVFKQoKc2F2ZS5pbWFnZSgpCmBgYAojIyMjIGNoZWNraW5nIGJlc3QgbW9kZWwKYGBge3J9CnggPC0gcmF3bGllX2VubUByZXN1bHRzICU+JSAKICBhcnJhbmdlKGRlbHRhLkFJQ2MpCngKI3dyaXRlLmNzdih4LCAiTW9kZWxfZXZhbC5jc3YiKQpgYGAKIyMjIyB2YXJpYWJsZSBpbXBvcnRhbmNlIGFuZCByZXNwb25zZQpgYGB7cn0KbGlicmFyeShFTk1ldmFsKQpwbG90KGV2YWwubW9kZWxzKHJhd2xpZV9lbm0pW1sicm0uMV9mYy5MUSJdXSx0eXBlID0gImNsb2dsb2ciKSAKcmVzcG9uc2UoZXZhbC5tb2RlbHMocmF3bGllX2VubSlbWyJybS4xX2ZjLkxRIl1dKSAKYGBgCiMjIyMgcGxvdCBwcmVkaWN0aW9uCmBgYHtyfQpwbG90KGV2YWwucHJlZGljdGlvbnMocmF3bGllX2VubSlbWyJybS4xX2ZjLkxRIl1dKSAKcG9pbnRzKHJhd2xpZV9nZW9UaGluKQpgYGAKIyMjIyBzYXZlIHByZWRpY3Rpb24gYXMgYSB0aWYgZmlsZQpgYGB7cn0KcmFzdGVyOjp3cml0ZVJhc3RlcihldmFsLnByZWRpY3Rpb25zKHJhd2xpZV9lbm0pW1sicm0uMV9mYy5MUSJdXSwgInJhd2xpZS5TRE0uYmlhcy5jb3JyZWN0ZWQudGlmIiwgCiAgICAgICAgICAgIGZvcm1hdCA9ICJHVGlmZiIsIG92ZXJ3cml0ZSA9IFRSVUUpCgpzYXZlLmltYWdlKCkKYGBgCiMjIyMgdHJhbmZvcm1pbmcgaW50byBiaW5hcnkgbWFwCmBgYHtyfQojIyMjIGV4dHJhY3QgZml0dGVkIHNjb3JlcyBvZiBiYWNrZ3JvdW5kIGFuIG9jY3VycmVuY2UgcG9pbnRzCgojIGNvbWJpbmUgYmcgYW5kIGdlbyB0aGluIHBvaW50cwp0ZW1wIDwtIGJpbmRfcm93cyhyYXdsaWVfZ2VvVGhpbiAlPiUgCiAgICAgICAgICAgIG11dGF0ZShyYXdsaWUgPSAxKSwKICAgICAgICAgIHJhd2xpZV9iZ19iaWFzICU+JSAKICAgICAgICAgICAgbXV0YXRlKHJhd2xpZSA9IDApKQojZXh0cmFjdCBwcmVkaWN0aW9ucyBiYXNlZCBvbiBib3RoIG9jYyBhbmQgYmcgcG9pbnRzCmZpdHRlZF9kZiA8LSByYXN0ZXI6OmV4dHJhY3QoZXZhbC5wcmVkaWN0aW9ucyhyYXdsaWVfZW5tKVtbInJtLjFfZmMuTFEiXV0sIHRlbXBbLDE6Ml0pICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJlbmFtZSgiZml0dGVkIiA9ICIuIikgJT4lIAogIGJpbmRfY29scyh0ZW1wKSAlPiUgCiAgbmEub21pdCgpCmBgYAoKIyMjIyB0cmFuZm9ybWluZyBpbnRvIGJpbmFyeSBtYXAgKGNvbnRpbnVlZCkKYGBge3J9CiMgbG9vayBmb3IgdGhyZWF0c2hvbGQgdmFsdWUgKFBVVCAiY3V0b2ZmIiB2YWx1ZSBpbnRvIHRoZSBuZXh0IGZldyBsaW5lcyBvZiBjb2RlKQpsaWJyYXJ5KGJpb21vZDIpCkZpbmQuT3B0aW0uU3RhdChTdGF0PSJST0MiLAogICAgICAgICAgICAgICAgRml0ID0gZml0dGVkX2RmWywgImZpdHRlZCJdLAogICAgICAgICAgICAgICAgT2JzID0gZml0dGVkX2RmWywgInJhd2xpZSJdKQoKI3RyYW5zZm9ybSBwcmVkaWN0aW9uIGluIHRvIGJpbmFyeSBtYXBzCnBsb3QoQmluYXJ5VHJhbnNmb3JtYXRpb24oZXZhbC5wcmVkaWN0aW9ucyhyYXdsaWVfZW5tKVtbInJtLjFfZmMuTFEiXV0sIDAuNTg2Nzg0NSkpCgojc2F2ZQpyYXN0ZXI6OndyaXRlUmFzdGVyKEJpbmFyeVRyYW5zZm9ybWF0aW9uKGV2YWwucHJlZGljdGlvbnMocmF3bGllX2VubSlbWyJybS4xX2ZjLkxRIl1dLCAwLjU4Njc4NDUpLCAicmF3bGllLmJpbmFyeS5iaWFzLmNvcnJlY3RlZC50aWYiLCAKICAgICAgICAgICAgZm9ybWF0ID0gIkdUaWZmIiwgb3ZlcndyaXRlID0gVFJVRSkKCmBgYAojIyMjIHNhdmUgaW1hZ2UKYGBge3J9CgpzYXZlLmltYWdlKCkKYGBgCgoK