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")
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")
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)
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()
LS0tCnRpdGxlOiAicmF3bGluc29uaSBwcm9qZWN0IgpQYXBlcjogIkNhcHR1cmluZyB1bmNhdGFsb2d1ZWQgZGlzdHJpYnV0aW9uIHJlY29yZHMgdG8gaW1wcm92ZSBjb25zZXJ2YXRpb24gYXNzZXNzbWVudHMgb2YgRGF0YSBEZWZpY2llbnQgc3BlY2llczogYSBjYXNlIHN0dWR5IHVzaW5nIHRoZSBnbG9zc3kgZ3Jhc3Mgc2tpbmsiCkF1dGhvcnMgb2YgdGhpcyBjb2RlOiBKdWxlcyBGYXJxdWhhciBhbmQgQXJtYW4gUGlsaQpEYXRlOiAxMi4wOS4yMDIyCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQojIyMgSW5zdGFsbCBwYWNrYWdlcwpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmxpYnJhcnkoZ2dwbG90MikgCmluc3RhbGwucGFja2FnZXMoJ3RpZHl2ZXJzZScpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKIyMjIyBEYXRhIGhhbmRsaW5nCmBgYHtyfQojIExvYWQgZGF0YQpyYXdsaWUuZGF0YSA8LSByZWFkLnRhYmxlKCdQc2V1ZGVtb2lhX3Jhd2xpbnNvbmlfcmVjb3Jkc19GSU5BTC5jc3YnLCBoZWFkZXI9VCxzZXA9JywnKSAgCnN0cihyYXdsaWUuZGF0YSkKVmlldyhyYXdsaWUuZGF0YSkKc3VtbWFyeShyYXdsaWUuZGF0YSkKYXR0YWNoKHJhd2xpZS5kYXRhKQoKIyMjIyBtYWtlIGEgbmV3IGRmIHdoaWNoIGV4Y2x1ZGVzIHJlY29yZHMgZnJvbSBvdXIgMjAyMS8yMDIyIHRpbGUgc3VydmV5cyBhbmQgYWN0aXZlIHN1cnZleXMgKGkuZS4gZnJvbSBhIHNlcGFyYXRlIHN0dWR5KQpyYXdsaWUuZGF0YTIgPC0gc3Vic2V0KHJhd2xpZS5kYXRhLCBHcm91cD09IlBlcnNvbmFsIGNvbW11bmljYXRpb24iIHwgR3JvdXA9PSJPbmxpbmUgZGF0YWJhc2VzIikKVmlldyhyYXdsaWUuZGF0YTIpCmBgYAojIyMjIENyZWF0IEJhciBwbG90IHNob3dpbmcgdGhlIG51bWJlciBvZiByZWNvcmRzIG9mIFBzZXVkZW1vaWEgcmF3bGlub25pIGluIGVhY2ggeWVhciBncm91cGVkIGJ5IHNvdXJjZS4KYGBge3J9CiMjIyMjIyBzdGFja2VkIGJhcnBsb3QKZ2dwbG90KHJhd2xpZS5kYXRhMiwgYWVzKFllYXIsIGZpbGw9R3JvdXApKSArIAogIGdlb21fYmFyKHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHJldmVyc2UgPSBUUlVFKSwgYWxwaGE9MC43LCBjb2xvcj0iYmxhY2siKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJjb3JuZmxvd2VyYmx1ZSIsIm1hcm9vbiIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG4uYnJlYWtzID0gMTApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZT0iTnVtYmVyIG9mIHJlY29yZHMiLCBuLmJyZWFrcyA9IDUpICsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IlJlY29yZCBzb3VyY2UiLCByZXZlcnNlID0gVFJVRSkpICsKICB0aGVtZV9idygpCmBgYAojIyMjIyBIQUJJVEFUIFNVSVRBQklMSVRZIE1PREVMTElORwpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZGlzbW8iKQppbnN0YWxsLnBhY2thZ2VzKCJtYXB0b29scyIpCmluc3RhbGwucGFja2FnZXMoIm1hcHMiKQppbnN0YWxsLnBhY2thZ2VzKCJtYXBkYXRhIikKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJDb29yZGluYXRlQ2xlYW5lciIpCmluc3RhbGwucGFja2FnZXMoInJhc3RlciIpCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQppbnN0YWxsLnBhY2thZ2VzKCJzY2FsZXMiKQppbnN0YWxsLnBhY2thZ2VzKCJzcFRoaW4iKQppbnN0YWxsLnBhY2thZ2VzKCJlY29zcGF0IikKaW5zdGFsbC5wYWNrYWdlcygic2YiKQppbnN0YWxsLnBhY2thZ2VzKCJybmF0dXJhbGVhcnRoZGF0YSIpCmluc3RhbGwucGFja2FnZXMoInJuYXR1cmFsZWFydGgiKQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQppbnN0YWxsLnBhY2thZ2VzKCJ1c2RtIikKaW5zdGFsbC5wYWNrYWdlcygiRU5NZXZhbCIpCmluc3RhbGwucGFja2FnZXMoInJKYXZhIikKaW5zdGFsbC5wYWNrYWdlcygibmNkZjQiKQppbnN0YWxsLnBhY2thZ2VzKCJiaW9tb2QyIikKCmxpYnJhcnkoYmlvbW9kMikKbGlicmFyeShkaXNtbykKbGlicmFyeShtYXB0b29scykKbGlicmFyeShtYXBzKSAgICAKbGlicmFyeShtYXBkYXRhKSAKbGlicmFyeShkcGx5cikKbGlicmFyeShDb29yZGluYXRlQ2xlYW5lcikKbGlicmFyeShyYXN0ZXIpCmxpYnJhcnkoc3BUaGluKQpsaWJyYXJ5KGVjb3NwYXQpCmxpYnJhcnkoc2YpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KHJuYXR1cmFsZWFydGhkYXRhKQpsaWJyYXJ5KHJuYXR1cmFsZWFydGgpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHVzZG0pCmxpYnJhcnkoRU5NZXZhbCkKbGlicmFyeShySmF2YSkKbGlicmFyeShuY2RmNCkKYGBgCiMjIyMgTE9BRCBPQ0NVUlJFTkNFIERBVEEKYGBge3J9CmdldHdkKCkKcmF3bGllLmRhdGEgPC0gcmVhZC50YWJsZSgncmF3bGllX2RhdGFfcHJlLXBvc3QuY3N2JywgaGVhZGVyPVQsc2VwPScsJykgICU+JSAKICBtdXRhdGUoU3BlY2llcz0iUHNldWRlbW9pYSByYXdsaW5zb25pIikKc3RyKHJhd2xpZS5kYXRhKQpWaWV3KHJhd2xpZS5kYXRhKQpgYGAKIyMjIyBnZXQgYXVzIG1hcApgYGB7cn0KYXVzX21hcCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwKICAgICAgICAgICAgICBjb3VudHJ5ID0gIkF1c3RyYWxpYSIsCiAgICAgICAgICAgICAgcmV0dXJuY2xhc3MgPSAic2YiKQpgYGAKIyMjIyBwbG90IHJlY29yZHMgb24gQXVzIG1hcApgYGB7cn0KZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IGF1c19tYXApICsKICBnZW9tX3BvaW50KGRhdGEgPSByYXdsaWUuZGF0YSwgCiAgICAgICAgICAgICBhZXMoeCA9IExvbmdpdHVkZSwgCiAgICAgICAgICAgICAgICAgeSA9IExhdGl0dWRlKSkgKwogIHRoZW1lX2J3KCkKYGBgCiMjIyMgdGhpbmluZyB0byAxa20KYGBge3J9CnJhd2xpZV9nZW9UaGluIDwtIHRoaW4obG9jLmRhdGEgPSByYXdsaWUuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxhdC5jb2wgPSAiTGF0aXR1ZGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgbG9uZy5jb2wgPSAiTG9uZ2l0dWRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWMuY29sID0gIlNwZWNpZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgdGhpbi5wYXIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgcmVwcyA9IDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIGxvY3MudGhpbm5lZC5saXN0LnJldHVybiA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICB3cml0ZS5maWxlcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgd3JpdGUubG9nLmZpbGUgPSBGQUxTRSkKcmF3bGllX2dlb1RoaW4gPC0gYXMuZGF0YS5mcmFtZShyYXdsaWVfZ2VvVGhpbls3XSkgCgojd3JpdGUuY3N2KHJhd2xpZV9nZW9UaGluLCAicmF3bGllX2dlb1RoaW4uY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAojIyMjIGxvYWQgYmFja2dyb3VuZCBiaW9yZWdpb25zCmBgYHtyfQpyYXdsaWVfYmlvcmVnaW9ucyA8LSBzdF9yZWFkKCIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvUmF3bGluc29uaS9yYXdsaWUgSUJSQSByZWdpb25zL3Jhd2xpZV9iYWNrZ3JvdW5kX1YzLnNocCIpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhID0gcmF3bGllX2Jpb3JlZ2lvbnMpICsKICBnZW9tX3BvaW50KGRhdGEgPSByYXdsaWUuZGF0YSwgCiAgICAgICAgICAgICBhZXMoeCA9IExvbmdpdHVkZSwgCiAgICAgICAgICAgICAgICAgeSA9IExhdGl0dWRlKSkgKwogIHRoZW1lX2J3KCkKYGBgCiMjIyMgVXBsb2FkaW5nIGFsbCBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcwpgYGB7cn0KIyBjcmVhdGUgdGVtcGxhdGUgcmFzdGVyCnJhc3Rlcl90ZW1wIDwtIHJhc3RlcihyYXdsaWVfYmlvcmVnaW9ucywgcmVzID0gMC4wMDgzMzMpCgojIHJlc2FtcGxpbmcgYWxsIHZhcmlhYmxlIHRvIGhhdmUgc2FtZSBkaW1lbnNpb25zIGFzIHRlbXBsYXRlIGJpb3JlZ2lvbiByYXN0ZXIKIyBXT1JMRENMSU0Kd29ybGRjbGltIDwtIHN0YWNrKGxpc3QuZmlsZXMocGF0aCA9ICIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvd2MyLjFfMzBzX2JpbyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXM9VFJVRSkpICU+JSAKICByZXNhbXBsZShyYXN0ZXJfdGVtcCwgCiAgICAgICAgICAgbWV0aG9kID0gImJpbGluZWFyIikgJT4lIAogIG1hc2socmF3bGllX2Jpb3JlZ2lvbnMpCgojRU5WSVJFTQplbnZpcmVtIDwtIHN0YWNrKGxpc3QuZmlsZXMocGF0aCA9ICIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvRU5WSVJFTV9lbGV2X0F1c3RyYWxpYV9jdXJyZW50XzMwYXJjc2VjX2dlbmVyaWMgY29weSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLnRpZiIsIGZ1bGwubmFtZXM9VFJVRSkpICU+JSAKICByZXNhbXBsZShyYXN0ZXJfdGVtcCwgCiAgICAgICAgICAgbWV0aG9kID0gImJpbGluZWFyIikgJT4lIAogIG1hc2socmF3bGllX2Jpb3JlZ2lvbnMpCgojIyMgTkRWSQoKTkRWSSA8LSBzdGFjayhsaXN0LmZpbGVzKHBhdGggPSAiL1ZvbHVtZXMvUEhPVE9TIDRUMS9RR0lTL01PRElTMTMgTkRWSSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLnRpZiIsIGZ1bGwubmFtZXM9VFJVRSkpICU+JSAKICByZXNhbXBsZShyYXN0ZXJfdGVtcCwgCiAgICAgICAgICAgbWV0aG9kID0gImJpbGluZWFyIikgJT4lIAogIG1hc2socmF3bGllX2Jpb3JlZ2lvbnMpCgojIERJU1QgVE8gV0FURVIgTElORVMgYW5kIEJPRElFUwp3YXRlcl9ldWNsaWRlYW4gPC0gc3RhY2sobGlzdC5maWxlcyhwYXRoID0gIi9Wb2x1bWVzL1BIT1RPUyA0VDEvUUdJUy9XYXRlciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLnRpZiIsIGZ1bGwubmFtZXM9VFJVRSkpICU+JSAKICByZXNhbXBsZShyYXN0ZXJfdGVtcCwgCiAgICAgICAgICAgbWV0aG9kID0gImJpbGluZWFyIikgJT4lIAogIG1hc2socmF3bGllX2Jpb3JlZ2lvbnMpCgojIHNvaWwgbW9pc3R1cmUKCnNvaWxfbW9pc3R1cmUgPC0gc3RhY2sobGlzdC5maWxlcyhwYXRoID0gIi9Wb2x1bWVzL1BIT1RPUyA0VDEvUUdJUy9Tb2lsIG1vaXN0dXJlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIudGlmIiwgZnVsbC5uYW1lcz1UUlVFKSkgJT4lIAogIHJlc2FtcGxlKHJhc3Rlcl90ZW1wLCAKICAgICAgICAgICBtZXRob2QgPSAiYmlsaW5lYXIiKSAlPiUgCiAgbWFzayhyYXdsaWVfYmlvcmVnaW9ucykKCiMgaHVtYW4gaW5kZXgKCmh1bWFuX2luZGV4IDwtIHN0YWNrKGxpc3QuZmlsZXMocGF0aCA9ICIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvaHVtYW4gaW5kZXgiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIi50aWYiLCBmdWxsLm5hbWVzPVRSVUUpKSAlPiUgCiAgcmVzYW1wbGUocmFzdGVyX3RlbXAsIAogICAgICAgICAgIG1ldGhvZCA9ICJiaWxpbmVhciIpICU+JSAKICBtYXNrKHJhd2xpZV9iaW9yZWdpb25zKQoKYGBgCiMjIyMgcGxvdCBzb21lIHZhcmlibGVzIHRvIGNoZWNrIHRoYXQgdGhleSBsb29rIGdvb2QKYGBge3J9CgpwbG90KHdvcmxkY2xpbSkKcGxvdChodW1hbl9pbmRleCkKCmBgYAojIyMjIHNhdmUgdmFyaWFibGVzIHRvIGEgcmFzdGVyIHN0YWNrIGNhbGxlZCBlbnYKYGBge3J9CmVudiA8LSBzdGFjayh3b3JsZGNsaW0sCiAgICAgICAgICAgICBlbnZpcmVtLAogICAgICAgICAgICAgTkRWSSwKICAgICAgICAgICAgIHdhdGVyX2V1Y2xpZGVhbiwKICAgICAgICAgICAgIHNvaWxfbW9pc3R1cmUsCiAgICAgICAgICAgICBodW1hbl9pbmRleCkKbmFtZXMoZW52KSA8LSBjKCJiaW8xIiwgCiAgICAgICAgICAgICAgICAgICAgImJpbzEwIiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTEiLAogICAgICAgICAgICAgICAgICAgICJiaW8xMiIsCiAgICAgICAgICAgICAgICAgICAgImJpbzEzIiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTQiLAogICAgICAgICAgICAgICAgICAgICJiaW8xNSIsCiAgICAgICAgICAgICAgICAgICAgImJpbzE2IiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTciLAogICAgICAgICAgICAgICAgICAgICJiaW8xOCIsCiAgICAgICAgICAgICAgICAgICAgImJpbzE5IiwKICAgICAgICAgICAgICAgICAgICAiYmlvMiIsCiAgICAgICAgICAgICAgICAgICAgImJpbzMiLAogICAgICAgICAgICAgICAgICAgICJiaW80IiwKICAgICAgICAgICAgICAgICAgICAiYmlvNSIsCiAgICAgICAgICAgICAgICAgICAgImJpbzYiLAogICAgICAgICAgICAgICAgICAgICJiaW83IiwKICAgICAgICAgICAgICAgICAgICAiYmlvOCIsCiAgICAgICAgICAgICAgICAgICAgImJpbzkiLAogICAgICAgICAgICAgICAgImFyaWRpdHkiLCAidG9wb3dldCIsICJ0cmkiLCJORFZJIiwgImRpc3RfdG9fd2F0ZXJib2RpZXMiLCAgImRpc3RfdG9fd2F0ZXJjb3Vyc2VzIiwic29pbF9tb2lzdHVyZSIsImh1bWFuX2luZmx1ZW5jZSIKICAgICAgICAgICAgICAgICAgICApCgojZGlyLmNyZWF0ZSgiZW52U3RhY2siKQojd3JpdGVSYXN0ZXIoZW52LCAiLi9lbnZTdGFjay9lbnYubmMiKQpgYGAKIyMjIyBleHRyYWN0IGVudmlyb25tZW50YWwgZGF0YSBiYXNlZCBvbiBnZW90aGluCmBgYHtyfQpyYXdsaWVfZW52IDwtIHJhc3Rlcjo6ZXh0cmFjdChlbnYsIHJhd2xpZV9nZW9UaGluKSAlPiUgCiAgY2JpbmQocmF3bGllX2dlb1RoaW4pICU+JSAKICBuYS5vbWl0KCkKCnJhd2xpZV9lbnYKCmBgYAojIyMjIGNoZWNrIGZvciBjb3JyZWxhdGlvbnMgYW1vbmcgdmFyaWFibGVzCmBgYHtyfQpyYXdsaWVfZW52ICU+JSAKICBjb3IobWV0aG9kPSJwZWFyc29uIikgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQoKYGBgCiMjIyMgUENBIHRvIGNoZWNrIGZvciBjb3JyZWxhdGlvbnMgYW1vbmcgdmFyaWFibGVzCmBgYHtyfQpzLmNvcmNpcmNsZShkdWRpLnBjYShyYXdsaWVfZW52Wy1jKDI4LDI5KV0sCiAgICAgICAgICAgICAgICAgICAgIHNjYW5uZiA9IEYsCiAgICAgICAgICAgICAgICAgICAgIG5mID0gMikkY28sIAogICAgICAgICAgICB4YXggPSAxLAogICAgICAgICAgICB5YXggPSAyLAogICAgICAgICAgICBncmlkID0gRkFMU0UpCmBgYAojIyMjIFZhcmlhbmNlIGluZmxhdGlvbiBmYWN0b3IgdGVzdCAoLTI4LDI5KSBpcyByZW1vdmluZyB0aGUgbGFzdCB0d28gY29sdW1ucyBmcm9tIHRoZSBkYXRhIGZyYW0gd2hpY2ggYXJlIGxhdCBhbmQgbG9uZwpgYGB7cn0KdmlmKGFzLmRhdGEuZnJhbWUocmF3bGllX2VudlstYygyOCwyOSldKSkKCnZpZnN0ZXAoYXMuZGF0YS5mcmFtZShyYXdsaWVfZW52Wy1jKDI4LDI5KV0pKQoKdmlmY29yKGFzLmRhdGEuZnJhbWUocmF3bGllX2VudlstYygyOCwyOSldKSwKICAgICAgIHRoID0gMC43KQpgYGAKIyMjIyBsb2FkaW5nIGluIHN0YWNrIG9mIHZhcmlhYmxlcyBBR0FJTgpgYGB7cn0KI3J1bjEKZW52IDwtIGJyaWNrKCIuL2VudlN0YWNrL2Vudi5uYyIpCm5hbWVzKGVudikgPC0gYygiYmlvMSIsIAogICAgICAgICAgICAgICAgICAgICJiaW8xMCIsCiAgICAgICAgICAgICAgICAgICAgImJpbzExIiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTIiLAogICAgICAgICAgICAgICAgICAgICJiaW8xMyIsCiAgICAgICAgICAgICAgICAgICAgImJpbzE0IiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTUiLAogICAgICAgICAgICAgICAgICAgICJiaW8xNiIsCiAgICAgICAgICAgICAgICAgICAgImJpbzE3IiwKICAgICAgICAgICAgICAgICAgICAiYmlvMTgiLAogICAgICAgICAgICAgICAgICAgICJiaW8xOSIsCiAgICAgICAgICAgICAgICAgICAgImJpbzIiLAogICAgICAgICAgICAgICAgICAgICJiaW8zIiwKICAgICAgICAgICAgICAgICAgICAiYmlvNCIsCiAgICAgICAgICAgICAgICAgICAgImJpbzUiLAogICAgICAgICAgICAgICAgICAgICJiaW82IiwKICAgICAgICAgICAgICAgICAgICAiYmlvNyIsCiAgICAgICAgICAgICAgICAgICAgImJpbzgiLAogICAgICAgICAgICAgICAgICAgICJiaW85IiwKICAgICAgICAgICAgICAgICJhcmlkaXR5IiwgInRvcG93ZXQiLCAidHJpIiwiTkRWSSIsICJkaXN0X3RvX3dhdGVyYm9kaWVzIiwgICJkaXN0X3RvX3dhdGVyY291cnNlcyIsInNvaWxfbW9pc3R1cmUiLCJodW1hbl9pbmZsdWVuY2UiCiAgICAgICAgICAgICAgICAgICAgKQpgYGAKIyMjIyBzdWJzZXR0aW5nIGJhc2VkIG9uIGRlc2lyZWQgdmFyaWFibGVzCmBgYHtyfQojcnVuMgplbnZfcHMgPC0gZW52W1tjKCJiaW81IiwKICAgICAgICAgICAgICAgICAiYmlvNiIsCiAgICAgICAgICAgICAgICAgImJpbzE1IiwKICAgICAgICAgICAgICAgICAiYXJpZGl0eSIsIAogICAgICAgICAgICAgICAgICJORFZJIiwgCiAgICAgICAgICAgICAgICAgInRvcG93ZXQiLAogICAgICAgICAgICAgICAgICJzb2lsX21vaXN0dXJlIildXQpwbG90KGVudl9wcykKI3N1bW1hcnkoZW52X3BzW1s3XV0pCnBsb3QoZW52X3BzW1sic29pbF9tb2lzdHVyZSJdXSkKcGxvdChlbnZfcHNbWyJORFZJIl1dKQpwbG90KGVudl9wc1tbImFyaWRpdHkiXV0pCnBsb3QoZW52X3BzW1siYmlvNSJdXSkKcGxvdChlbnZfcHNbWyJiaW82Il1dKQpwbG90KGVudl9wc1tbImJpbzE1Il1dKQpwbG90KGVudl9wc1tbInRvcG93ZXQiXV0pCmBgYAojIyMjIHJlYWRpbmcgY3N2IG9mIG9jYyBhbmQgYmcKYGBge3J9CiNydW4gMwpyYXdsaWVfZ2VvVGhpbiA8LSByZWFkLmNzdigicmF3bGllX2dlb1RoaW4uY3N2IikKcmF3bGllX2JnIDwtIHJlYWQuY3N2KCJyYXdsaWVfYmcuY3N2IikKYGBgCiMjIyMgZXh0cmFjdCBlbnZpcm8gZGF0YSBmcm9tIHJhd2xpZV9nZW90aGluIHBvaW50cyBiYXNlZCBvbiBzbWFsbGVyIGxpc3Qgb2YgbmV3IHByZXNlbGVjdGVkIHZhcmlhYmxlcwpgYGB7cn0KcmF3bGllX2VudiA8LSByYXN0ZXI6OmV4dHJhY3QoZW52X3BzLCByYXdsaWVfZ2VvVGhpbikgJT4lIAogIGNiaW5kKHJhd2xpZV9nZW9UaGluKSAlPiUgCiAgbmEub21pdCgpCgpyYXdsaWVfZW52CmBgYAoKYGBge3J9CnJhd2xpZV9lbnYgJT4lIAogIGNvcihtZXRob2Q9InBlYXJzb24iKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpCgpgYGAKCmBgYHtyfQpzLmNvcmNpcmNsZShkdWRpLnBjYShyYXdsaWVfZW52Wy1jKDgsOSldLAogICAgICAgICAgICAgICAgICAgICBzY2FubmYgPSBGLAogICAgICAgICAgICAgICAgICAgICBuZiA9IDIpJGNvLCAKICAgICAgICAgICAgeGF4ID0gMSwKICAgICAgICAgICAgeWF4ID0gMiwKICAgICAgICAgICAgZ3JpZCA9IEZBTFNFKQpgYGAKCmBgYHtyfQp2aWYoYXMuZGF0YS5mcmFtZShyYXdsaWVfZW52Wy1jKDgsOSldKSkKCnZpZnN0ZXAoYXMuZGF0YS5mcmFtZShyYXdsaWVfZW52Wy1jKDgsOSldKSkKCnZpZmNvcihhcy5kYXRhLmZyYW1lKHJhd2xpZV9lbnZbLWMoOCw5KV0pLAogICAgICAgdGggPSAwLjcyKQpgYGAKIyMjIyBWaXN1YWxpemluZyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiB1c2luZyBtYW50ZWwgciBjb3JyZWxvZ3JhbQoKU3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgbm90IHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gemVybyBpbiBtYW55IGRpc3RhbmNlcwpgYGB7cn0KcmF3bGllX2NvcnJlbG9ncmFtIDwtIHJhd2xpZV9nZW9UaGluICU+JSAKICBzdF9hc19zZihjb29yZHMgPSBjKCJMb25naXR1ZGUiLCAiTGF0aXR1ZGUiKSwKICAgICAgICAgICBjcnMgPSA0MzI2KSAlPiUgI2NvbnZlcnRpbmcgcHJvamVjdGlvbiBmcm9tIGxhdC9sb25nIHRvIG1ldHJlcyBmb3IgYmV0dGVyIGludGVycHJldGF0aW9uCiAgc3RfdHJhbnNmb3JtKGNycyA9IDMxMTIpICU+JSAKICBzdF9jb29yZGluYXRlcygpICU+JSAKICBjYmluZChyYXN0ZXI6OmV4dHJhY3QoZW52X3BzLCByYXdsaWVfZ2VvVGhpbikpICU+JSAKICBjYmluZChyYXdsaWVfZ2VvVGhpbikgJT4lIAogIG5hLm9taXQoKQoKZWNvc3BhdC5tYW50ZWwuY29ycmVsb2dyYW0oZGZ2YXIgPSByYXdsaWVfY29ycmVsb2dyYW0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHh5ID0gMToyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gMTAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x2YXIgPSAzOjEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXggPSAxMDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNsYXNzID0gNTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5wZXJtID0gMTAwKQpgYGAKIyMjIyBHRU5FUkFURSBCRyBQT0lOVFMgCmBgYHtyfQpsaWJyYXJ5KHNwYXRzdGF0KQoKI3JlZmVyZW5jZSBhbnkgb25lIG9mIHlvdXIgcmFzdGVycyBzbyB0aGF0IHRoZSBlbnZpcm9ubWVudGFsIHJhc3RlciBoYXMgc2FtZSBwcm9wZXJ0aWVzIGFzIGJpYXMgcmFzdGVyCnJhc3Rlcl9yZWYgPC0gZW52X3BzW1siYXJpZGl0eSJdXQoKc2FtcGxpbmdTaXRlcyA8LSByYXdsaWVfZ2VvVGhpbiAlPiUgCiAgc3RfYXNfc2YoY29vcmRzID0gYygiTG9uZ2l0dWRlIiwgIkxhdGl0dWRlIiksCiAgICAgICAgICAgY3JzID0gNDMyNikgJT4lICNjb252ZXJ0aW5nIHByb2plY3Rpb24gZnJvbSBsYXQvbG9uZyB0byBtZXRyZXMgZm9yIGJldHRlciBpbnRlcnByZXRhdGlvbgogIHN0X3RyYW5zZm9ybShjcnMgPSAzMTEyKSAlPiUgCiAgICAgICAgICAgICAgICAgc3RfY29vcmRpbmF0ZXMoKSAlPiUgCiAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZSgpCgpzaHAgPC0gcmF3bGllX2Jpb3JlZ2lvbnMgJT4lIAogICAgICAgIHN0X3RyYW5zZm9ybSgzMTEyKSAlPiUgCiAgc3RfdW5pb24oKQpgYGAKIyMjIyBWaXN1YWxpemUgcmVmZXJlbmNlIGRhdGEKClJlZmVyZW5jZSByYXN0ZXIKYGBge3J9CnBsb3QocmFzdGVyX3JlZikKYGBgCiMjIyMgU2FtcGxpbmcgc2l0ZXMKYGBge3J9CmdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSBzaHAgJT4lIHN0X2FzX3NmKCkpICsKICBnZW9tX3NmKGRhdGEgPSBzYW1wbGluZ1NpdGVzICU+JSAKICAgICAgICAgICAgICAgICAgc3RfYXNfc2YoY29vcmRzID0gYygiWCIsICJZIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjcnMgPSAzMTEyKSkgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCiMjIyMgUG9zdGVyaW8gQW5hbHlzaXMKCiNQb2ludC1wYXR0ZXJuIHByb2Nlc3MgdHJhbnNmb3JtYXRpb24KCkNyZWF0ZSBhIFBvaW50LXBhdHRlcm4gcHJvY2VzcyAoUFBQKSB1c2luZyB0aGUgcmF3IGRhdGEuIEhlcmUsIGkgdXNlZCB0aGUgTG9yZCBIb3dlIElzbGFuZCBzaGFwZWZpbGUgYXMgIndpbmRvdyIsIGFuZCB0aGUgY29vcmRpbmF0ZXMgb2YgdGhlIHNhbXBsaWduIHNpdGVzIGFzICJ4ID0gWCIgKG9yaWdpbmFsbHkgIkxvbmdpdHVkZSIgaW4gcmF3IGZpbGUpIGFuZCAiWSA9IHkiIChvcmlnaW5hbGx5ICJMYXRpdHVkZSIgaW4gcmF3IGZpbGUpLgoKYGBge3J9CndpbiA8LSBhcy5vd2luKHNocCkKcHBwIDwtIHBwcCh4ID0gcHVsbChkcGx5cjo6c2VsZWN0KHNhbXBsaW5nU2l0ZXMsIFgpKSwKICAgICAgICAgICB5ID0gcHVsbChkcGx5cjo6c2VsZWN0KHNhbXBsaW5nU2l0ZXMsIFkpKSwKICAgICAgICAgICB3aW5kb3cgPSB3aW4pCmBgYAoKIyMjIyBWaXN1YWxpemUgUFBQCmBgYHtyfQpwbG90KHBwcCkKCmBgYAojIyMjIENvbXB1dGUgdGhlIGJhbmR3aWR0aApJIHVzZWQgY3Jvc3MtdmFsaWRhdGlvbiB0byBzZWxlY3QgYSBzbW9vdGhpbmcgYmFuZHdpZHRoIGZvciB0aGUga2VybmVsIGVzdGltYXRpb24gb2YgcG9pbnQgcHJvY2VzcyBpbnRlbnNpdHkuIFRoZSBiYW5kd2lkdGggz4MgaXMgY2hvc2VuIHRvIG1pbmltaXNlIHRoZSBtZWFuLXNxdWFyZSBlcnJvciBjcml0ZXJpb24gZGVmaW5lZCBieSBEaWdnbGUgKDE5ODUpLgpgYGB7cn0KYncuZGlnZ2xlKFggPSBwcHApCgojc2lnbWEgdmFsdWUgaXMga2lsb21ldHJlcyByYWRpdXMgd2hlbiBzbW9vdGhpbmcgdGhlIGRlbnNpdGllcyBvZiBvY2N1cmVuY2VzCiNkb250IHJlcG9ydCBpZiBzcGVjaWZ5aW5nIHlvdXIgb3duIGJhbmR3aWR0aCAod2hpY2ggeW91IGFyZSkKYGBgCiMjIyMgQ29tcHV0ZSB0aGUgZGVuc2l0eSBvZiBQUFAKSGVyZSwgdGhlIGJhbmR3aWR0aCB3YXMgY29tcHV0ZWQgdXNpbmcgY3Jvc3MtdmFsaWRhdGlvbjsgZWRnZSBjb3JyZWN0aW9uIHdhcyBlbmFibGVkIGFuZCB1c2VkIGRpZ2dsZSBtZXRob2QuIEkgdGhlbiBjb252ZXJ0ZWQgdGhlIGJpYXMgZmlsZSBpbnRvIHJhc3RlciB3aXRoIGEgR0RBOTIgcHJvamVjdGlvbi4KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KYmlhc0ZpbGUgPC0gcmFzdGVyKGRlbnNpdHkucHBwKHBwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlcm5lbCA9ICJnYXVzc2lhbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWdtYSA9IDUwMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWRnZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdnbGUgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgIGNycyA9ICJFUFNHOjMxMTIiKQoKcmFzdGVyOjpjcnMoYmlhc0ZpbGUpIDwtICJFUFNHOjMxMTIiCmBgYAojIyMjIFZpc3VhbGl6ZSBkZW5zaXR5IG1hcCAvIGJpYXMgZmlsZSBSVU4gQVMgRlVMTCBDSFVOSwpgYGB7cn0KcGxvdChiaWFzRmlsZSkKcGxvdChzaHAsIAogICAgIGNvbG9yID0gTkEsIAogICAgIGFkZCA9IFRSVUUpCnBsb3Qoc2FtcGxpbmdTaXRlcyAlPiUgCiAgICAgICBzdF9hc19zZihjb29yZHMgPSBjKCJYIiwgIlkiKSksCiAgICAgYWRkID0gVFJVRSkKYGBgCiMjIyMgcmVzYW1wbGUgdGhlIGJpYXMgZmlsZSwgdG8gYWxpZ24gd2l0aCB0aGUgcmVmZXJlbmNlIHJhc3Rlci4KCk1heGVudCByZXF1aXJlcyBhbGwgcmFzdGVyIGZpbGVzIChlbnZpcm9uZW1udGFsIHJhc3RlcnMgYW5kIGJpYXMgZmlsZSkgdG8gaGF2ZSB0aGUgc2FtZSBwcm9qZWN0aW9uLCByZXNvbHV0aW9uLCBhbmQgZXhlbnQuIEJhc2ljYWxseSwgaWYgeW91IGNhbnQgc3RhY2soKSB0aGUgcmFzdGVyIGZpbGVzLCBtYXhlbnQgd29uJ3QgcnVuLgoKaGVyZSwgSSBmaXJzdCByZXByb2plY3RlZCB0aGUgYmlhcyBmaWxlIHRvIGEgV0dTIDg0IChyZWZlcmVuY2UgcmFzdGVyIHByb2plY3Rpb24pLCBhbmQgdGhlbiByZXNhbXBsZWQgdGhlIGJpYXMgZmlsZSBiYXNlZCBvbiB0aGUgcmVzb2x1dGlvbiBhbmQgZXh0ZW50IG9mIHRoZSByZWZlcmVuY2UgcmFzdGVyIHVzaW5nIGEgYmlsaW5lYXIgcmVzYW1wbGluZyBtZXRob2QuCgpgYGB7cn0KYmlhc0ZpbGVfZXhwb3J0IDwtIGJpYXNGaWxlICU+JQogICAgICAgICAgICAgICAgICAgICBwcm9qZWN0UmFzdGVyKGNycyA9ICJFUFNHOjQzMjYiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgIHJlc2FtcGxlKHkgPSByYXN0ZXJfcmVmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiYmlsaW5lYXIiKQpgYGAKIyMjIyBQbG90IGJpYXMgZmlsZQpgYGB7cn0KcGxvdChiaWFzRmlsZV9leHBvcnQpCmBgYAojIyMjIERvdWJsZSBjaGVja2luZyBpZiB0aGUgYmlhcyBmaWxlIGhhcyB0aGUgc2FtZSBwcm9wZXJ0aWVzIGFzIHRoYXQgb2YgdGhlIHJlZmVyZW5jZSByYXN0ZXIKCmBgYHtyfQojY3JzCnByb2o0c3RyaW5nKHJhc3Rlcl9yZWYpID09IHByb2o0c3RyaW5nKGJpYXNGaWxlX2V4cG9ydCkKI3Jlc29sdXRpb24KcmVzKHJhc3Rlcl9yZWYpID09IHJlcyhiaWFzRmlsZV9leHBvcnQpCiNleHRlbnQKZXh0ZW50KHJhc3Rlcl9yZWYpID09IGV4dGVudChiaWFzRmlsZV9leHBvcnQpCmBgYAojIyMjIHdyaXRlIGJpYXMgZmlsZQpGaW5hbGx5LCB0aGUgYmlhcyBmaWxlIGlzIHdyaXR0ZW4gaW4gdGhlICIuL291dHB1dCIgZm9sZGVyIG9mIHRoZSBSIHByb2plY3QuCmBgYHtyfQp3cml0ZVJhc3RlcihiaWFzRmlsZV9leHBvcnQsCiAgICAgICAgICAgICIvVm9sdW1lcy9QSE9UT1MgNFQxL1FHSVMvUmF3bGluc29uaV9wcm9qZWN0L2JpYXNmaWxlLnRpZiIsCiAgICAgICAgICAgIG92ZXJ3cml0ZSA9IFRSVUUpCgpzdW1tYXJ5KGJpYXNGaWxlX2V4cG9ydCkKYGBgCiMjIyMgTWFrZSBhbGwgTkFzIDAsIGFuZCB0aGVuIG1ha2UgYWxsIG5lZ2F0aXZlIDAKYGBge3J9CnZhbHVlcyhiaWFzRmlsZV9leHBvcnQpW2lzLm5hKHZhbHVlcyhiaWFzRmlsZV9leHBvcnQpKV0gPC0gMAoKdmFsdWVzKGJpYXNGaWxlX2V4cG9ydClbd2hpY2godmFsdWVzKGJpYXNGaWxlX2V4cG9ydCkgPCAwKV0gPC0gMAoKYGBgCiMjIyMgbWFraW5nIHRoZSBiaWFzIGJhY2tncm91bmQKYGBge3J9CnJhd2xpZV9iZ19iaWFzIDwtIHh5RnJvbUNlbGwoYmlhc0ZpbGVfZXhwb3J0LCBzYW1wbGUobmNlbGwoYmlhc0ZpbGVfZXhwb3J0KSwgMTAwMDAsIHByb2IgPSB2YWx1ZXMoYmlhc0ZpbGVfZXhwb3J0KSkpIAoKcmF3bGllX2JnX2JpYXMgPC0gcmF3bGllX2JnX2JpYXMgJT4lIAogIGFzX2RhdGFfZnJhbWUoKSAlPiUgCiAgcmVuYW1lKExvbmdpdHVkZSA9IHgsCiAgICAgICAgIExhdGl0dWRlID0geSkKICAKCnBsb3QocmF3bGllX2JnX2JpYXMpCiN3cml0ZS5jc3YocmF3bGllX2JnX2JpYXMsICJyYXdsaWVfYmdfYmlhcy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCiMjIyMgcnVuIG1vZGVsCmBgYHtyfQpzYXZlLmltYWdlKCkKCnJhd2xpZV9lbm0gPC0gRU5NZXZhbHVhdGUob2NjcyA9IHJhd2xpZV9nZW9UaGluLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBlbnZzID0gZW52X3BzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBiZyA9IHJhd2xpZV9iZ19iaWFzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICB0dW5lLmFyZ3MgPSBsaXN0KHJtPWMoMTozKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYz1jKCdMJywnTFEnLCAnTFFIJywgJ0gnKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFsZ29yaXRobT0nbWF4ZW50LmphcicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFydGl0aW9ucyA9ICJjaGVja2VyYm9hcmQyIiwgbnVtQ29yZXMgPSA2LCBwYXJhbGxlbD1UUlVFKQoKc2F2ZS5pbWFnZSgpCmBgYAojIyMjIGNoZWNraW5nIGJlc3QgbW9kZWwKYGBge3J9CnggPC0gcmF3bGllX2VubUByZXN1bHRzICU+JSAKICBhcnJhbmdlKGRlbHRhLkFJQ2MpCngKI3dyaXRlLmNzdih4LCAiTW9kZWxfZXZhbC5jc3YiKQpgYGAKIyMjIyB2YXJpYWJsZSBpbXBvcnRhbmNlIGFuZCByZXNwb25zZQpgYGB7cn0KbGlicmFyeShFTk1ldmFsKQpwbG90KGV2YWwubW9kZWxzKHJhd2xpZV9lbm0pW1sicm0uMV9mYy5MUSJdXSx0eXBlID0gImNsb2dsb2ciKSAKcmVzcG9uc2UoZXZhbC5tb2RlbHMocmF3bGllX2VubSlbWyJybS4xX2ZjLkxRIl1dKSAKYGBgCiMjIyMgcGxvdCBwcmVkaWN0aW9uCmBgYHtyfQpwbG90KGV2YWwucHJlZGljdGlvbnMocmF3bGllX2VubSlbWyJybS4xX2ZjLkxRIl1dKSAKcG9pbnRzKHJhd2xpZV9nZW9UaGluKQpgYGAKIyMjIyBzYXZlIHByZWRpY3Rpb24gYXMgYSB0aWYgZmlsZQpgYGB7cn0KcmFzdGVyOjp3cml0ZVJhc3RlcihldmFsLnByZWRpY3Rpb25zKHJhd2xpZV9lbm0pW1sicm0uMV9mYy5MUSJdXSwgInJhd2xpZS5TRE0uYmlhcy5jb3JyZWN0ZWQudGlmIiwgCiAgICAgICAgICAgIGZvcm1hdCA9ICJHVGlmZiIsIG92ZXJ3cml0ZSA9IFRSVUUpCgpzYXZlLmltYWdlKCkKYGBgCiMjIyMgdHJhbmZvcm1pbmcgaW50byBiaW5hcnkgbWFwCmBgYHtyfQojIyMjIGV4dHJhY3QgZml0dGVkIHNjb3JlcyBvZiBiYWNrZ3JvdW5kIGFuIG9jY3VycmVuY2UgcG9pbnRzCgojIGNvbWJpbmUgYmcgYW5kIGdlbyB0aGluIHBvaW50cwp0ZW1wIDwtIGJpbmRfcm93cyhyYXdsaWVfZ2VvVGhpbiAlPiUgCiAgICAgICAgICAgIG11dGF0ZShyYXdsaWUgPSAxKSwKICAgICAgICAgIHJhd2xpZV9iZ19iaWFzICU+JSAKICAgICAgICAgICAgbXV0YXRlKHJhd2xpZSA9IDApKQojZXh0cmFjdCBwcmVkaWN0aW9ucyBiYXNlZCBvbiBib3RoIG9jYyBhbmQgYmcgcG9pbnRzCmZpdHRlZF9kZiA8LSByYXN0ZXI6OmV4dHJhY3QoZXZhbC5wcmVkaWN0aW9ucyhyYXdsaWVfZW5tKVtbInJtLjFfZmMuTFEiXV0sIHRlbXBbLDE6Ml0pICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJlbmFtZSgiZml0dGVkIiA9ICIuIikgJT4lIAogIGJpbmRfY29scyh0ZW1wKSAlPiUgCiAgbmEub21pdCgpCmBgYAoKIyMjIyB0cmFuZm9ybWluZyBpbnRvIGJpbmFyeSBtYXAgKGNvbnRpbnVlZCkKYGBge3J9CiMgbG9vayBmb3IgdGhyZWF0c2hvbGQgdmFsdWUgKFBVVCAiY3V0b2ZmIiB2YWx1ZSBpbnRvIHRoZSBuZXh0IGZldyBsaW5lcyBvZiBjb2RlKQpsaWJyYXJ5KGJpb21vZDIpCkZpbmQuT3B0aW0uU3RhdChTdGF0PSJST0MiLAogICAgICAgICAgICAgICAgRml0ID0gZml0dGVkX2RmWywgImZpdHRlZCJdLAogICAgICAgICAgICAgICAgT2JzID0gZml0dGVkX2RmWywgInJhd2xpZSJdKQoKI3RyYW5zZm9ybSBwcmVkaWN0aW9uIGluIHRvIGJpbmFyeSBtYXBzCnBsb3QoQmluYXJ5VHJhbnNmb3JtYXRpb24oZXZhbC5wcmVkaWN0aW9ucyhyYXdsaWVfZW5tKVtbInJtLjFfZmMuTFEiXV0sIDAuNTg2Nzg0NSkpCgojc2F2ZQpyYXN0ZXI6OndyaXRlUmFzdGVyKEJpbmFyeVRyYW5zZm9ybWF0aW9uKGV2YWwucHJlZGljdGlvbnMocmF3bGllX2VubSlbWyJybS4xX2ZjLkxRIl1dLCAwLjU4Njc4NDUpLCAicmF3bGllLmJpbmFyeS5iaWFzLmNvcnJlY3RlZC50aWYiLCAKICAgICAgICAgICAgZm9ybWF0ID0gIkdUaWZmIiwgb3ZlcndyaXRlID0gVFJVRSkKCmBgYAojIyMjIHNhdmUgaW1hZ2UKYGBge3J9CgpzYXZlLmltYWdlKCkKYGBgCgoK