Presenter: Nicolas Palominos
Duration: 60 minutes
Repository: https://github.com/npalomin/CASA_seminar_2020
URL: https://npalomin.github.io/CASA_seminar_2020/casa0005_seminar1.html

This seminar was presented on November 21, 2020 for the CASA GIS and Science Module at University College London. The topic presented was “Exploring the concept of 15-minute cities using service area analysis around train stations in London”

1 Learning outcomes

  1. Understand and apply basic service area analysis in R
  2. Conduct point-in-polygon queries
  3. Use of the mapboxapi package
  4. Understand basic concepts of accessibility analysis and diversity
  5. Knowledge of the Points of Interest data set from Ordnance Survey

2 Introduction

The concept of 15-minutes cities has gained traction as a sustainable city planning strategy to create mixed-used and compact self-sufficient neighbourhoods. More recently, with the several urban mobility restrictions and lifestyle transformations originated from Covid-19, it has emerged as an urban planning framework for pandemic response and recovery.

The main idea behind the concept is that work, study, leisure, shopping and other basic human activities are available within a 15-minute trip mainly using active travel modes (walking and cycling).

This way long commutes are avoided originating important benefits to urban quality of life by both re-organising the use of dwellers’ time and reducing the externalities of urban transport among others.

Because of the predominant high dependency of private car transportation it is probable that many urban areas will not have the characteristics of good quality local environments across different urban domains (commercial and service activities, housing, public services, transport infrastructure, open and public spaces, employment).

Fig. Diagrammatic representation of a 15-minute city from ft.com

Fig. Multiple-dimensions of a 20-minute neighbourhood (Melbourne) from c40knowledgehub.org

Suburban areas often have less access to these features. Accessibility is a central concept in spatial analysis as it involves a cost often represented ‘spatially’ (distance, time), yet there is no agreed definition. For the purpose of this exercise, a useful definition is suggested by Batty (2009)

A well defined form of [accesibility] associates some measure of an opportunity at a place with the cost of actually realising that opportunity

Service area analysis finds all accessible streets (that is, streets that are within a specified impedance, cost expressed in time or distance). For example, the 10-minute service area for a given point on a network includes all the streets that can be reached within ten minutes from that point. Therefore, the geography of the street network is taken into account to calculate distance (see Gutierrez and Garcia-Palomares, 2008).

Fig. Service Area Isochrone vs ‘As-the-crow-Flies’ from Gutierrez and Garcia-Palomares, 2008. The isochrone shape (irregular polygon) is more accurate to represent equal cost of access (expressed in distance)

To conduct the analysis we will use Mapbox. The Mapbox platform provides mapping and navigation services with data mostly taken from open data sources such as OpenStreetMap. For example, the Isochrone API allows you to request polygon or line features that show areas that are reachable within a specified amount of time from a location.

#knitr::knit_exit()

3 Getting started

3.1 Install packages and load libraries

#install.packages("mapboxapi", dependencies = TRUE)
library(mapboxapi)
library(sf)
library(tidyverse)
library(tmap)
library(mapview) # to create fast interactive maps
library(ggplot2) # to create visualisations
library(ggthemes) # to style visualisations

3.2 Load and prepare data

For this exercise we will use the following data sets:

  • Rail and Tube stations in London: We will assume this are activity nodes or points from which we will calculate the service area (from the tubecreature project by Oliver O’Brien at CDRC)
  • POI Points of Interest: Directory of all Businesses and Services in Great Britain created by Ordnance Survey and available through Digimap licence (log in to https://digimap.edina.ac.uk/, navigate to Ordnance Survey > Data Download > Boundary and Location Data).
# derived from OSM, stations are represented as one point. Lines are also simplified and loaded here to provide context
stations <- st_read("https://raw.githubusercontent.com/oobrien/vis/master/tube/data/tfl_stations.json")
## Reading layer `tfl_stations' from data source `https://raw.githubusercontent.com/oobrien/vis/master/tube/data/tfl_stations.json' using driver `GeoJSON'
## Simple feature collection with 529 features and 9 fields
## geometry type:  POINT
## dimension:      XY
## bbox:           xmin: -0.9729138 ymin: 51.33461 xmax: 0.3306072 ymax: 51.7469
## CRS:            4326
lines <- st_read("https://raw.githubusercontent.com/oobrien/vis/master/tube/data/tfl_lines.json")
## Reading layer `tfl_lines' from data source `https://raw.githubusercontent.com/oobrien/vis/master/tube/data/tfl_lines.json' using driver `GeoJSON'
## Simple feature collection with 700 features and 2 fields
## geometry type:  LINESTRING
## dimension:      XY
## bbox:           xmin: -0.9729138 ymin: 51.11713 xmax: 0.3305912 ymax: 51.90153
## CRS:            4326
# get from data folder in case you can't download it yourself
# warning: the whole of the UK data set is ~1.5GB and aroung 4 million obs. We will crop to the bounding box of the study area
# the poi.rds is croped to the study area and has less attributes and saved as R object(RDS) to reduce its size
# to load a RDS straight from a URL requires a built-in decompressor function called gzcon plus the readRDS function
# this file is 10MB ~480k obs.
poi <- readRDS(gzcon(url("https://npalomin.github.io/casa0005/seminar/poi.rds")))
# Data Copyright Note
# Ordnance Survey Digimap: Licensed Data: © Crown copyright and database rights 2020 Ordnance Survey (100025252). This material includes data licensed from PointX© Database Right/Copyright 2020.

Quick plot to check Stations and Lines

qtm(lines) + qtm(stations)

Clip lines to the station’s bounding box

lines <-st_crop(lines,stations)

Check POI data

sample_n(poi, 10)

3.2.1 Point density visualisation

The POI data set for the study area contains N = 479360 obs. Below is a point density visualisation to have an overview of the general spatial pattern

# create new sf with CRS 4326 and X and Y variables
poi_4326 <- poi %>%
  #sample_n(100000) %>%
  st_transform(4326) %>% # tranform to same CRS as stations and lines
  cbind(st_coordinates(.)) # get X and Y coordinates
# plot
ggplot() +
  geom_bin2d(data = poi_4326, aes(X, Y), binwidth = c(0.01, 0.01)) + # heatmap of 2d bin counts
  geom_sf(data = lines, col="white", size=0.1) +
  theme_tufte() +
  scale_fill_viridis_c(option = "plasma") +
  labs(x="", y="")

3.3 Setting mapbox access token

In case you haven’t yet created a Mapbox account you can create one here

Access your account and create and copy the “default public token” that appears on your screen

# paste token here
# my_token <- "YOUR TOKEN GOES HERE"

4 Service area analysis

4.1 Generate service area polygons

# create a unique id variable "sid"
stations <- stations %>%
  rowid_to_column(., "sid")
# sample 5 stations
#s5s <- sample_n(stations, 100)
s5s <- stations
# central stations
#c5s <- stations %>%
#  slice(c(150,49,147,23,215,500))

To calculate the isochrones we use mb_isochrone function with the following parameters

  • location(s)
  • profile = “walking”, “driving”, “cycling”
  • time in minutes
  • id = column identifier from location
  • access_token = my_token
w_iso <- mb_isochrone(s5s, "walking", time = 10, id_column = "sid", access_token = my_token)
# get variables from station sf to join with isochrones
stations_kv <- stations %>%
  select("sid","name", "zone") %>%
  st_drop_geometry()
# join
w_iso <- w_iso %>%
  merge(., stations_kv, by.x="id", by.y="sid") %>%
  rename(s_name = name) # to avoid conflict with POI name

Plot a sample of isochrones

# select 9 random isochrones
r9s <- sample(w_iso$id, 9)

w_iso_9 <- w_iso %>%
  filter(id %in% r9s)

s9 <- stations %>%
  filter(sid %in% r9s)

tm_shape(w_iso_9) +
  tm_polygons(col = "tomato",
             border.lwd = 0.3,
             alpha = 0.7) +
  tm_facets(by="s_name", ncol = 3) +
tm_shape(s9) +
  tm_symbols(col = "navy",
             size = 0.2) +
tm_shape(lines) +
  tm_lines(lwd=0.2) +
  tm_layout(legend.show = F, outer.margins = 0, panel.label.bg.color = 'white')

4.2 Analyse service areas

4.2.1 What do we know about the POI attributes?

Plot a sample of POI

sample_POI <- sample_n(poi_4326, 500)
# handy package/function to plot interactive map
mapview(sample_POI)

How many variables do each of the columns have?

poi_4326 %>%
  st_drop_geometry() %>%
  select(groupname, categoryname, classname) %>%
  mutate(n_groupname = n_distinct(groupname),
         n_categoryname = n_distinct(categoryname),
         n_classname = n_distinct(classname)) %>%
  select(n_groupname, n_categoryname, n_classname) %>%
  unique()

As it is often the case with classification schemes, these are structured hierarchically. The ‘classname’ and ‘categoryname’ variables are nested into the 9 levels of the ‘groupname’ variable.

levels(poi_4326$groupname) 
## [1] "Accommodation, Eating and Drinking" "Attractions"                       
## [3] "Commercial Services"                "Education and Health"              
## [5] "Manufacturing and Production"       "Public Infrastructure"             
## [7] "Retail"                             "Sport and Entertainment"           
## [9] "Transport"

This summary will give us the count of data points in each level. A simple analysis of the service areas would be to count the number of observations within the area, but it would be interesting to examine to what group do those points belong. Is the accessibility to points of interest measured by counting the number of observations?, it worth having a deeper look into the kind of points are at reach within an area.

# how many observations do you have for 'groupname'
poi_4326 %>%
  st_drop_geometry() %>%
  count(groupname, sort = TRUE)

Now we can look at the composition of the groups (groupname variable). This table shows the amount of different values in each group

poi_4326 %>%
  st_drop_geometry() %>% 
  select(groupname, categoryname) %>% 
  unique() %>%
  count(groupname)

Here we are a step from building a dendogram, which is a netowork representation of hierarchical relationships such as the classification scheme of POI that we are studying.

# Libraries
library(ggraph)
library(igraph)
# create a hierarchy from data frame to examine classification scheme
poi_hier <- poi_4326 %>%
  st_drop_geometry() %>%
  select(groupname, categoryname, classname) %>%
  unique() 

rownames(poi_hier) <- NULL
# transform it to a edge list
edges_level0_1 <- poi_hier %>%
  select(groupname) %>% 
  mutate(head = "POI") %>%
  unique() %>% 
  rename(from=head, to=groupname) %>%
  select(2,1)

edges_level1_2 <- poi_hier %>% 
  select(groupname, categoryname) %>% 
  unique() %>% 
  rename(from=groupname, to=categoryname)

edges_level2_3 <- poi_hier %>% 
  select(categoryname, classname) %>% 
  unique() %>% rename(from=categoryname, to=classname)

edge_list  <- rbind(edges_level0_1, edges_level1_2)
edge_list  <- rbind(edge_list, edges_level2_3)
# Now we can plot the graph object
poi_graph <- graph_from_data_frame(edge_list)

ggraph(poi_graph, layout = 'dendrogram', circular = FALSE) + 
  geom_edge_diagonal(alpha = 0.1, size=0.5) +
  geom_node_point(color="tomato", size=0.01) +
  geom_node_text(aes(label=c("", poi_graph[[1]]$POI$name, rep("",662))), size=2.5) +
  theme_void() +
  coord_flip() +
  scale_y_reverse() 
Hierarchical struture of the POIs 'group', 'categories', 'class' parent-child relationships. This can help to better understand the richness of urban features available in the study area

Hierarchical struture of the POIs ‘group’, ‘categories’, ‘class’ parent-child relationships. This can help to better understand the richness of urban features available in the study area

4.2.2 POI counts per service area

# Join station identifier to POI and select only those intersecting with the isochrones (omit points with NA)
# this joins the isochrone data to the POIs
poi_sa <- poi_4326 %>%
  st_join(., w_iso) %>%
  na.omit() # omit POI that do not intersect with any service area

poi_count <- poi_sa %>%
  group_by(id, s_name) %>%
  summarise(n=n())
poi_count
# create a single point per service area to plot
poi_count_centroid <- st_centroid(poi_count)

Create a proportional symbol map weighted by count to examine the opportunities available within the study areas.

#tmap_mode("plot")
tm_shape(lines) +
  tm_lines(lwd=0.1) +
tm_shape(poi_count_centroid) +
  tm_bubbles(col = "tomato",
             size = "n",
             alpha = 0.4,
             border.lwd = 0.3,
             style = "kmeans",
             title.size="Count") +
  tm_layout(title = "Points of Interest within a 10-minute walking service area from rail stations in London", title.size = 0.77) +
  tm_credits(size = 3, text = "Ordnance Survey Digimap: Licensed Data: © Crown copyright and database rights 2020 Ordnance Survey (100025252). This material includes data licensed from PointX© Database Right/Copyright 2020\nMap created by Nicolas Palominos", position = c("right", "BOTTOM"))

Let us investigate the richness of POIs in each area by looking at the type of class, category or group the points belong to. Richness is a measure of diversity which can help assess the variety of opportunities that are accessible within the study area which is more complex than the absolute count.

This table summarises the number of different ‘groups’ in each study area. The great majority of the service areas have POIs that belong to the 9 groups.

#
poi_sa %>%
  st_drop_geometry() %>%
  group_by(id, groupname, s_name) %>%
  summarise(n=n()) %>% # total number of observations per group
  group_by(s_name) %>%
  mutate(richness=n_distinct(groupname)) %>% # distinct number of groups
  select(3,5) %>% 
  unique()

What is the spatial pattern of the 9 different groups?

# create a sf object with the 'group' summary
poi_count_gr <- poi_sa %>%
  group_by(id, groupname) %>% # groupname count by station
  summarise(n=n())
poi_count_gr
# create a single point per service area to plot
poi_count_gr_cen <- st_centroid(poi_count_gr)
tm_shape(lines) +
  tm_lines(lwd=0.1) +
tm_shape(poi_count_gr_cen) +
  tm_bubbles(col = "tomato",
             size = "n",
             alpha = 0.4,
             border.lwd = 0.3,
             style = "kmeans",
             title.size="Count") +
  tm_facets(by="groupname") +
  tm_layout(legend.show = F, outer.margins = 0, panel.label.bg.color = 'white', frame = F)

4.2.3 Diversity analysis: point types per service area

All the nine groups (Accommodation, Eating and Drinking; Attractions; Commercial Services; Education and Health; Manufacturing and Production; Public Infrastructure; Retail; Sport and Entertainment; Transport) seem to be relevant for a self-sufficient neighbourhood. Let’s quantify the richness of these groups by looking at the type of points that are located in each service area.

# create summary of obs. by station
pps <- poi_sa %>%
  st_drop_geometry() %>%
  count(id) %>%
  rename(station_count = n)

# create a 'Richness' metric by 'Group', "Category' and 'Class'
div_tab <- poi_sa %>%
  st_drop_geometry() %>%
  group_by(id, s_name) %>%
  summarise(rich_g = n_distinct(groupname),
            rich_cat = n_distinct(categoryname),
            rich_cla = n_distinct(classname))

# merge
div_tab <- div_tab %>%
  merge(., pps)

# merge to stations to get geometry back (the approach above was different, we created centroids)
sta_div <- stations %>%
  select("sid","name", "zone") %>%
  merge(., div_tab, by.x="sid", by.y="id")

Plot it

tmap_mode("plot")
tm_shape(lines) +
  tm_lines(lwd=0.1) +
tm_shape(sta_div) +
  tm_symbols(col = "rich_cla",
             palette="RdPu",
             size = 0.1,
             shape = "station_count",
             alpha = 0.8,
             border.lwd = 0.3,
             style = "kmeans",
             n = 3,
             shapes.n = 3,
             shapes.legend.fill = "gray30",
             title.shape="Count",
             title.col="Diversity") +
  tm_layout(title = "Diversity of Points of Interest within a 10-minute walking service area from rail stations in London", main.title = "", title.size = 0.77) +
  tm_credits(size = 3, text = "Ordnance Survey Digimap: Licensed Data: © Crown copyright and database rights 2020 Ordnance Survey (100025252). This material includes data licensed from PointX© Database Right/Copyright 2020\nMap created by Nicolas Palominos", position = c("right", "BOTTOM"))

According to the pattern displayed in previous analysis, centrally located stations have a good provision of urban facilities according to both number and variety. Zone 1 in London more or less matches the planning definition of the Central Activity Zone which is effectively not only a self-sufficient area but also a provider of services for the whole of London. For a more meaningful analysis of potentially under-served areas we will filter out zone 1, and zoom-in to compare the top and tail areas according to richness quantified by the number of distinct ‘classes’ located within the service area.

# get stations with lowest diversity
tail <- sta_div %>%
  # keep all that are not zone = 1
  filter(zone != "1") %>%
  arrange(rich_g, rich_cat, rich_cla) %>% # arrange is ascendant by default (order of sorting factors affect result)
  slice(1:3)
tail
# get stations with highest diversity
head <- sta_div %>%
  # keep all that are not zone = 1
  filter(zone != "1") %>%
  arrange(desc(rich_g, rich_cat, rich_cla)) %>%
  slice(1:3)
head
# get POI and isochrones from sf by station id (sid)

# tail
tail_iso <- w_iso %>%
  filter(id %in% tail$sid)
tail_poi <- poi_sa %>%
  filter(id %in% tail$sid)

# head
head_iso <- w_iso %>%
  filter(id %in% head$sid)
head_poi <- poi_sa %>%
  filter(id %in% head$sid)

Plot head and tail

tmap_mode("plot")
tm_shape(lines) +
  tm_lines(lwd=0.1) +
tm_shape(head) +
  tm_dots(col = "tomato",
             size = 0.3,
             alpha = 0.8,
             border.lwd = 0.3) +
  tm_text("rich_cla", size = 0.7, just=c("center", 2)) +
tm_shape(head) +
  tm_dots(col = "tomato",
             size = 0.1,
             alpha = 0.8,
             border.lwd = 0.3) +
  tm_text("name", size = 0.5, just=c("center", 4)) +
tm_shape(tail) +
  tm_dots(col = "pink",
             size = 0.3,
             alpha = 0.8,
             border.lwd = 0.3) +
  tm_text("rich_cla", size = 0.7, just=c("center", 2)) +
tm_shape(tail) +
  tm_dots(col = "pink",
             size = 0.1,
             alpha = 0.8,
             border.lwd = 0.3) +
  tm_text("name", size = 0.5, just=c("center", 4)) +
tm_shape(stations) +
  tm_dots(col = "gray20",
             size = 0.007,
             alpha = 0.3,
             border.lwd = 0.001) +
  tm_layout(title = "10-minute walking service areas with higher and lower diversity according to number of 'classes'", inner.margins = c(0.08,0,0,0), title.size = 0.77) 

Zooming-in

# create custom palette
g_col <- c('#e6194B', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#42d4f4', '#f032e6', '#fabed4', '#469990')

tmap_mode("plot")
head_m <- tm_shape(lines) +
  tm_lines(lwd=0.1) +
tm_shape(head_iso) +
  tm_polygons(col = "grey90",
             border.lwd = 0.3,
             alpha = 0.7) +
tm_facets(by="s_name", nrow = 1) +
tm_shape(head_poi) +
  tm_dots(col = "groupname",
          palette = g_col,
             size = 0.2,
             alpha = 0.8,
             border.lwd = 0.3,
             title="Group") +
  tm_layout(title = "", frame=FALSE, panel.label.bg.color = 'white', main.title = "Higher diversity", main.title.size = 0.8) +
tm_legend(show = FALSE) 

tail_m <- tm_shape(lines) +
  tm_lines(lwd=0.1) +
tm_shape(tail_iso) +
  tm_polygons(col = "grey90",
             border.lwd = 0.3,
             alpha = 0.7) +
tm_facets(by="s_name", nrow = 1) +
tm_shape(tail_poi) +
  tm_dots(col = "groupname",
          palette = g_col,
             size = 0.2,
             alpha = 0.8,
             border.lwd = 0.3,
             title="Group") +
  tm_layout(title = "", frame=FALSE, panel.label.bg.color = 'white', main.title = "Lower diversity", main.title.size = 0.8) +
tm_legend(show = FALSE)

legend <- tm_shape(lines) +
  tm_lines(lwd=0.1) +
tm_shape(tail_iso) +
  tm_polygons(col = "grey90",
             border.lwd = 0.3,
             alpha = 0.7) +
tm_shape(tail_poi) +
  tm_dots(col = "groupname",
          palette = g_col,
             size = 0.2,
             alpha = 0.8,
             border.lwd = 0.3,
             title="Group") +
  tm_layout(title = "", frame=FALSE, panel.label.bg.color = 'white', main.title = "Lower diversity", main.title.size = 0.8, legend.only =T)
tmap_arrange(head_m, legend, tail_m, nrow = 2, widths = c(0.75, 0.25))

What is the increase in diversity if we change the mode of transport to define the extent of the service area in the areas with lowest diversity?

# low diversity service area stations
ldsas <- stations %>%
  filter(sid %in% tail$sid)
# get isochrones for cycling mode
w_iso_low <- mb_isochrone(ldsas, "cycling", time = 10, id_column = "sid", access_token = my_token)

# join stations data
w_iso_low <- w_iso_low %>%
  merge(., stations_kv, by.x="id", by.y="sid") %>%
  rename(s_name = name) # to avoid conflict with POI name
#Join station identifier to POI and select only those intersecting with the isochrones (omit points with NA)
poi_low <- poi_sa %>%
  select(-id, -time, -s_name, -zone) %>% # already in poi_sa from previous join
  st_join(., w_iso_low) %>%
  na.omit() # omit POI that do not intersect with service area
# create a 'Richness' metric by 'Group', "Category' and 'Class'
div_low <- poi_low %>%
  st_drop_geometry() %>%
  group_by(id, s_name) %>%
  summarise(rich_g = n_distinct(groupname),
            rich_cat = n_distinct(categoryname),
            rich_cla = n_distinct(classname))

# merge to stations to get geometry back (the approach above was different, we created centroids)
sta_div <- stations %>%
  select("sid","name", "zone") %>%
  merge(., div_low, by.x="sid", by.y="id")
# print summary table: lowest diversity cycling mode
sta_div
tm_shape(lines) +
  tm_lines(lwd=0.3) +
tm_shape(tail_iso) +
  tm_polygons(col = "beige",
             border.lwd = 0.3,
             alpha = 0.8) +
tm_shape(poi_low) +
  tm_dots(col = "groupname",
          palette = g_col,
             size = 0.2,
             alpha = 0.8,
             border.lwd = 0.3,
             title="Group") +
tm_shape(w_iso_low) +
  tm_polygons(col = "beige",
             border.lwd = 0.3,
             border.col = "tomato",
             alpha = 0.1) +
tm_facets(by="s_name", nrow = 1) +
  tm_layout(title = "", frame=FALSE, panel.label.bg.color = 'white', main.title = "Lower diversity according to 'classes' type\nWalking and Cycling 10-minutes service area definitions", main.title.size = 0.8, legend.outside=TRUE, legend.outside.position = "bottom", legend.outside.size=0.25) +
  tm_legend(show =T)

The 10-minutes cycling service area of Coombe Lane has a POI diversity richness of 204 according to distinct classes which is in some way comparable to the 10-minutes walking service area of Archway, which has a richness of 175. However, further questions remain about other variables not considered in this analysis that characterise a 15-minute city, such as the quality of the street environment or the housing and demographic diversity, among others.

5 Final comments

  • We used service area analysis to create a new geographic area definition to perform a comparative analysis of the number and diversity of urban facilities surrounding train stations.

  • For what other applications could this research method could be useful for? For example, instead of train stations the centre points could be schools to investigate the kind of urban facilities students have access to.

  • We used a licensed high quality data set of Point of Interest available for the the whole of the UK. However, a similar analysis could be replicated elsewhere using OpenStreetMap data (e.g. examining amenity and shop features).

  • We only considered one variable to investigate the concept of 15-minute cities, however, it would have been interesting to incorporate other variables more directly related to quantifying the cost of trips using active travel modes.

  • While we used the geography of the street network to define the study areas, there was no quantification of the characteristics of the street environment. There are plenty of data sets that could contribute to expand this analysis, such as street greenery, street hierarchy, cycle lanes and streetspace allocation.

6 Feedback

If you have any feedback or comments please feel free to contact me at @npalomin or

LS0tCnRpdGxlOiAiQ0FTQSAwMDA1IEdJUyBhbmQgU2NpZW5jZSBTZW1pbmFyIDEiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiAnMycKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBzZWxmX2NvbnRhaW5lZDogbm8KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKbGlicmFyeShwbmcpCmxpYnJhcnkoZ3JpZCkKYGBgCgpQcmVzZW50ZXI6IE5pY29sYXMgUGFsb21pbm9zICAKRHVyYXRpb246IDYwIG1pbnV0ZXMgIApSZXBvc2l0b3J5OiBodHRwczovL2dpdGh1Yi5jb20vbnBhbG9taW4vQ0FTQV9zZW1pbmFyXzIwMjAgIApVUkw6IGh0dHBzOi8vbnBhbG9taW4uZ2l0aHViLmlvL0NBU0Ffc2VtaW5hcl8yMDIwL2Nhc2EwMDA1X3NlbWluYXIxLmh0bWwgIAoKVGhpcyBzZW1pbmFyIHdhcyBwcmVzZW50ZWQgb24gTm92ZW1iZXIgMjEsIDIwMjAgZm9yIHRoZSBDQVNBIEdJUyBhbmQgU2NpZW5jZSBNb2R1bGUgYXQgVW5pdmVyc2l0eSBDb2xsZWdlIExvbmRvbi4gVGhlIHRvcGljIHByZXNlbnRlZCB3YXMgKioiRXhwbG9yaW5nIHRoZSBjb25jZXB0IG9mIDE1LW1pbnV0ZSBjaXRpZXMgdXNpbmcgc2VydmljZSBhcmVhIGFuYWx5c2lzIGFyb3VuZCB0cmFpbiBzdGF0aW9ucyBpbiBMb25kb24iKioKCiMgTGVhcm5pbmcgb3V0Y29tZXMKCjEuICBVbmRlcnN0YW5kIGFuZCBhcHBseSBiYXNpYyBzZXJ2aWNlIGFyZWEgYW5hbHlzaXMgaW4gUgoyLiAgQ29uZHVjdCBwb2ludC1pbi1wb2x5Z29uIHF1ZXJpZXMKMy4gIFVzZSBvZiB0aGUgbWFwYm94YXBpIHBhY2thZ2UKNC4gIFVuZGVyc3RhbmQgYmFzaWMgY29uY2VwdHMgb2YgYWNjZXNzaWJpbGl0eSBhbmFseXNpcyBhbmQgZGl2ZXJzaXR5CjUuICBLbm93bGVkZ2Ugb2YgdGhlIFBvaW50cyBvZiBJbnRlcmVzdCBkYXRhIHNldCBmcm9tIE9yZG5hbmNlIFN1cnZleQoKIyBJbnRyb2R1Y3Rpb24KCjxkaXYgY2xhc3MgPSAicm93Ij4KICAKPGRpdiBjbGFzcyA9ICJjb2wtbWQtOCI+ClRoZSBjb25jZXB0IG9mICoqMTUtbWludXRlcyoqIGNpdGllcyBoYXMgZ2FpbmVkIHRyYWN0aW9uIGFzIGEgc3VzdGFpbmFibGUgY2l0eSBwbGFubmluZyBzdHJhdGVneSB0byBjcmVhdGUgbWl4ZWQtdXNlZCBhbmQgY29tcGFjdCBzZWxmLXN1ZmZpY2llbnQgbmVpZ2hib3VyaG9vZHMuIE1vcmUgcmVjZW50bHksIHdpdGggdGhlIHNldmVyYWwgdXJiYW4gbW9iaWxpdHkgcmVzdHJpY3Rpb25zIGFuZCBsaWZlc3R5bGUgdHJhbnNmb3JtYXRpb25zIG9yaWdpbmF0ZWQgZnJvbSBDb3ZpZC0xOSwgaXQgaGFzIGVtZXJnZWQgYXMgYW4gdXJiYW4gcGxhbm5pbmcgZnJhbWV3b3JrIGZvciBwYW5kZW1pYyByZXNwb25zZSBhbmQgcmVjb3ZlcnkuCgpUaGUgbWFpbiBpZGVhIGJlaGluZCB0aGUgY29uY2VwdCBpcyB0aGF0IHdvcmssIHN0dWR5LCBsZWlzdXJlLCBzaG9wcGluZyBhbmQgb3RoZXIgYmFzaWMgaHVtYW4gYWN0aXZpdGllcyBhcmUgYXZhaWxhYmxlIHdpdGhpbiBhIDE1LW1pbnV0ZSB0cmlwIG1haW5seSB1c2luZyBhY3RpdmUgdHJhdmVsIG1vZGVzICh3YWxraW5nIGFuZCBjeWNsaW5nKS4KClRoaXMgd2F5IGxvbmcgY29tbXV0ZXMgYXJlIGF2b2lkZWQgb3JpZ2luYXRpbmcgaW1wb3J0YW50IGJlbmVmaXRzIHRvIHVyYmFuIHF1YWxpdHkgb2YgbGlmZSBieSBib3RoIHJlLW9yZ2FuaXNpbmcgdGhlIHVzZSBvZiBkd2VsbGVycycgdGltZSBhbmQgcmVkdWNpbmcgdGhlIGV4dGVybmFsaXRpZXMgb2YgdXJiYW4gdHJhbnNwb3J0IGFtb25nIG90aGVycy4KCkJlY2F1c2Ugb2YgdGhlIHByZWRvbWluYW50IGhpZ2ggZGVwZW5kZW5jeSBvZiBwcml2YXRlIGNhciB0cmFuc3BvcnRhdGlvbiBpdCBpcyBwcm9iYWJsZSB0aGF0IG1hbnkgdXJiYW4gYXJlYXMgd2lsbCBub3QgaGF2ZSB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIGdvb2QgcXVhbGl0eSBsb2NhbCBlbnZpcm9ubWVudHMgYWNyb3NzIGRpZmZlcmVudCB1cmJhbiBkb21haW5zIChjb21tZXJjaWFsIGFuZCBzZXJ2aWNlIGFjdGl2aXRpZXMsIGhvdXNpbmcsIHB1YmxpYyBzZXJ2aWNlcywgdHJhbnNwb3J0IGluZnJhc3RydWN0dXJlLCBvcGVuIGFuZCBwdWJsaWMgc3BhY2VzLCBlbXBsb3ltZW50KS4gCgo8L2Rpdj4KICAKPGRpdiBjbGFzcyA9ICJjb2wtbWQtNCI+CjxjZW50ZXI+CgohW0ZpZy4gRGlhZ3JhbW1hdGljIHJlcHJlc2VudGF0aW9uIG9mIGEgMTUtbWludXRlIGNpdHkgZnJvbSBmdC5jb21dKGltZy9jbG9jay5wbmcpe3dpZHRoPSIzMDAifQoKPC9jZW50ZXI+CjwvZGl2PgoKPC9kaXY+Cgo8Y2VudGVyPgoKIVtGaWcuIE11bHRpcGxlLWRpbWVuc2lvbnMgb2YgYSAyMC1taW51dGUgbmVpZ2hib3VyaG9vZCAoTWVsYm91cm5lKSBmcm9tIGM0MGtub3dsZWRnZWh1Yi5vcmddKGltZy9tZWxib3VybmUucG5nKXt3aWR0aD0iNTAwIn0KCjwvY2VudGVyPgoKU3VidXJiYW4gYXJlYXMgb2Z0ZW4gaGF2ZSBsZXNzIGFjY2VzcyB0byB0aGVzZSBmZWF0dXJlcy4gQWNjZXNzaWJpbGl0eSBpcyBhIGNlbnRyYWwgY29uY2VwdCBpbiBzcGF0aWFsIGFuYWx5c2lzIGFzIGl0IGludm9sdmVzIGEgY29zdCBvZnRlbiByZXByZXNlbnRlZCAnc3BhdGlhbGx5JyAoZGlzdGFuY2UsIHRpbWUpLCB5ZXQgdGhlcmUgaXMgbm8gYWdyZWVkCmRlZmluaXRpb24uIEZvciB0aGUgcHVycG9zZSBvZiB0aGlzIGV4ZXJjaXNlLCBhIHVzZWZ1bCBkZWZpbml0aW9uIGlzIHN1Z2dlc3RlZCBieSBbQmF0dHkgKDIwMDkpXShodHRwczovL2RvaS5vcmcvMTAuMTA2OC9iMzYwMmVkKQoKPiBBIHdlbGwgZGVmaW5lZCBmb3JtIG9mIFthY2Nlc2liaWxpdHldIGFzc29jaWF0ZXMgc29tZSBtZWFzdXJlIG9mIGFuIG9wcG9ydHVuaXR5IGF0CmEgcGxhY2Ugd2l0aCB0aGUgY29zdCBvZiBhY3R1YWxseSByZWFsaXNpbmcgdGhhdCBvcHBvcnR1bml0eQoKKipTZXJ2aWNlIGFyZWEgYW5hbHlzaXMqKiBmaW5kcyBhbGwgYWNjZXNzaWJsZSBzdHJlZXRzICh0aGF0IGlzLCBzdHJlZXRzIHRoYXQgYXJlIHdpdGhpbiBhIHNwZWNpZmllZCBpbXBlZGFuY2UsIGNvc3QgZXhwcmVzc2VkIGluIHRpbWUgb3IgZGlzdGFuY2UpLiBGb3IgZXhhbXBsZSwgdGhlIDEwLW1pbnV0ZSBzZXJ2aWNlIGFyZWEgZm9yIGEgZ2l2ZW4gcG9pbnQgb24gYSBuZXR3b3JrIGluY2x1ZGVzIGFsbCB0aGUgc3RyZWV0cyB0aGF0IGNhbiBiZSByZWFjaGVkIHdpdGhpbiB0ZW4gbWludXRlcyBmcm9tIHRoYXQgcG9pbnQuIFRoZXJlZm9yZSwgdGhlIGdlb2dyYXBoeSBvZiB0aGUgc3RyZWV0IG5ldHdvcmsgaXMgdGFrZW4gaW50byBhY2NvdW50IHRvIGNhbGN1bGF0ZSBkaXN0YW5jZSAoc2VlIFtHdXRpZXJyZXogYW5kIEdhcmNpYS1QYWxvbWFyZXMsIDIwMDhdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDY4L2IzMzA0MykpLgoKPGNlbnRlcj4KCiFbRmlnLiBTZXJ2aWNlIEFyZWEgSXNvY2hyb25lIHZzICdBcy10aGUtY3Jvdy1GbGllcycgZnJvbSBHdXRpZXJyZXogYW5kIEdhcmNpYS1QYWxvbWFyZXMsIDIwMDguIFRoZSBpc29jaHJvbmUgc2hhcGUgKGlycmVndWxhciBwb2x5Z29uKSBpcyBtb3JlIGFjY3VyYXRlIHRvIHJlcHJlc2VudCBlcXVhbCBjb3N0IG9mIGFjY2VzcyAoZXhwcmVzc2VkIGluIGRpc3RhbmNlKV0oaW1nL3NlcnZpY2UucG5nKXt3aWR0aD0iNjAwIn0KCjwvY2VudGVyPgoKVG8gY29uZHVjdCB0aGUgYW5hbHlzaXMgd2Ugd2lsbCB1c2UgTWFwYm94LiBUaGUgKipNYXBib3gqKiBwbGF0Zm9ybSBwcm92aWRlcyBtYXBwaW5nIGFuZCBuYXZpZ2F0aW9uIHNlcnZpY2VzIHdpdGggZGF0YSBtb3N0bHkgdGFrZW4gZnJvbSBvcGVuIGRhdGEgc291cmNlcyBzdWNoIGFzIE9wZW5TdHJlZXRNYXAuIEZvciBleGFtcGxlLCB0aGUgW0lzb2Nocm9uZSBBUEldKGh0dHBzOi8vZG9jcy5tYXBib3guY29tL3BsYXlncm91bmQvaXNvY2hyb25lLykgYWxsb3dzIHlvdSB0byByZXF1ZXN0IHBvbHlnb24gb3IgbGluZSBmZWF0dXJlcyB0aGF0IHNob3cgYXJlYXMgdGhhdCBhcmUgcmVhY2hhYmxlIHdpdGhpbiBhIHNwZWNpZmllZCBhbW91bnQgb2YgdGltZSBmcm9tIGEgbG9jYXRpb24uCgpgYGB7cn0KI2tuaXRyOjprbml0X2V4aXQoKQpgYGAKCiMgR2V0dGluZyBzdGFydGVkCgojIyBJbnN0YWxsIHBhY2thZ2VzIGFuZCBsb2FkIGxpYnJhcmllcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2luc3RhbGwucGFja2FnZXMoIm1hcGJveGFwaSIsIGRlcGVuZGVuY2llcyA9IFRSVUUpCmxpYnJhcnkobWFwYm94YXBpKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0bWFwKQpsaWJyYXJ5KG1hcHZpZXcpICMgdG8gY3JlYXRlIGZhc3QgaW50ZXJhY3RpdmUgbWFwcwpsaWJyYXJ5KGdncGxvdDIpICMgdG8gY3JlYXRlIHZpc3VhbGlzYXRpb25zCmxpYnJhcnkoZ2d0aGVtZXMpICMgdG8gc3R5bGUgdmlzdWFsaXNhdGlvbnMKYGBgCgojIyBMb2FkIGFuZCBwcmVwYXJlIGRhdGEKCkZvciB0aGlzIGV4ZXJjaXNlIHdlIHdpbGwgdXNlIHRoZSBmb2xsb3dpbmcgZGF0YSBzZXRzOgoKKiBSYWlsIGFuZCBUdWJlIHN0YXRpb25zIGluIExvbmRvbjogV2Ugd2lsbCBhc3N1bWUgdGhpcyBhcmUgYWN0aXZpdHkgbm9kZXMgb3IgcG9pbnRzIGZyb20gd2hpY2ggd2Ugd2lsbCBjYWxjdWxhdGUgdGhlIHNlcnZpY2UgYXJlYSAoZnJvbSB0aGUgW3R1YmVjcmVhdHVyZV0oaHR0cHM6Ly90dWJlY3JlYXR1cmUuY29tLyMvdG90YWwvY3VycmVudC9zYW1lLyovKi9GRlRGVEYvMTMvLTAuMTAwMC81MS41MjAwLykgcHJvamVjdCBieSBPbGl2ZXIgTydCcmllbiBhdCBDRFJDKQoqIFBPSSBbUG9pbnRzIG9mIEludGVyZXN0XShodHRwczovL3d3dy5vcmRuYW5jZXN1cnZleS5jby51ay9idXNpbmVzcy1nb3Zlcm5tZW50L3Byb2R1Y3RzL3BvaW50cy1vZi1pbnRlcmVzdCk6IERpcmVjdG9yeSBvZiBhbGwgQnVzaW5lc3NlcyBhbmQgU2VydmljZXMgaW4gR3JlYXQgQnJpdGFpbiBjcmVhdGVkIGJ5IE9yZG5hbmNlIFN1cnZleSBhbmQgYXZhaWxhYmxlIHRocm91Z2ggRGlnaW1hcCBsaWNlbmNlIChsb2cgaW4gdG8gaHR0cHM6Ly9kaWdpbWFwLmVkaW5hLmFjLnVrLywgbmF2aWdhdGUgdG8gT3JkbmFuY2UgU3VydmV5ID4gRGF0YSBEb3dubG9hZCA+IEJvdW5kYXJ5IGFuZCBMb2NhdGlvbiBEYXRhKS4gCgpgYGB7cn0KIyBkZXJpdmVkIGZyb20gT1NNLCBzdGF0aW9ucyBhcmUgcmVwcmVzZW50ZWQgYXMgb25lIHBvaW50LiBMaW5lcyBhcmUgYWxzbyBzaW1wbGlmaWVkIGFuZCBsb2FkZWQgaGVyZSB0byBwcm92aWRlIGNvbnRleHQKc3RhdGlvbnMgPC0gc3RfcmVhZCgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL29vYnJpZW4vdmlzL21hc3Rlci90dWJlL2RhdGEvdGZsX3N0YXRpb25zLmpzb24iKQpsaW5lcyA8LSBzdF9yZWFkKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vb29icmllbi92aXMvbWFzdGVyL3R1YmUvZGF0YS90ZmxfbGluZXMuanNvbiIpCiMgZ2V0IGZyb20gZGF0YSBmb2xkZXIgaW4gY2FzZSB5b3UgY2FuJ3QgZG93bmxvYWQgaXQgeW91cnNlbGYKIyB3YXJuaW5nOiB0aGUgd2hvbGUgb2YgdGhlIFVLIGRhdGEgc2V0IGlzIH4xLjVHQiBhbmQgYXJvdW5nIDQgbWlsbGlvbiBvYnMuIFdlIHdpbGwgY3JvcCB0byB0aGUgYm91bmRpbmcgYm94IG9mIHRoZSBzdHVkeSBhcmVhCiMgdGhlIHBvaS5yZHMgaXMgY3JvcGVkIHRvIHRoZSBzdHVkeSBhcmVhIGFuZCBoYXMgbGVzcyBhdHRyaWJ1dGVzIGFuZCBzYXZlZCBhcyBSIG9iamVjdChSRFMpIHRvIHJlZHVjZSBpdHMgc2l6ZQojIHRvIGxvYWQgYSBSRFMgc3RyYWlnaHQgZnJvbSBhIFVSTCByZXF1aXJlcyBhIGJ1aWx0LWluIGRlY29tcHJlc3NvciBmdW5jdGlvbiBjYWxsZWQgZ3pjb24gcGx1cyB0aGUgcmVhZFJEUyBmdW5jdGlvbgojIHRoaXMgZmlsZSBpcyAxME1CIH40ODBrIG9icy4KcG9pIDwtIHJlYWRSRFMoZ3pjb24odXJsKCJodHRwczovL25wYWxvbWluLmdpdGh1Yi5pby9jYXNhMDAwNS9zZW1pbmFyL3BvaS5yZHMiKSkpCiMgRGF0YSBDb3B5cmlnaHQgTm90ZQojIE9yZG5hbmNlIFN1cnZleSBEaWdpbWFwOiBMaWNlbnNlZCBEYXRhOiDCqSBDcm93biBjb3B5cmlnaHQgYW5kIGRhdGFiYXNlIHJpZ2h0cyAyMDIwIE9yZG5hbmNlIFN1cnZleSAoMTAwMDI1MjUyKS4gVGhpcyBtYXRlcmlhbCBpbmNsdWRlcyBkYXRhIGxpY2Vuc2VkIGZyb20gUG9pbnRYwqkgRGF0YWJhc2UgUmlnaHQvQ29weXJpZ2h0IDIwMjAuCmBgYAoKUXVpY2sgcGxvdCB0byBjaGVjayBTdGF0aW9ucyBhbmQgTGluZXMKYGBge3J9CnF0bShsaW5lcykgKyBxdG0oc3RhdGlvbnMpCmBgYAoKQ2xpcCBsaW5lcyB0byB0aGUgc3RhdGlvbidzIGJvdW5kaW5nIGJveApgYGB7cn0KbGluZXMgPC1zdF9jcm9wKGxpbmVzLHN0YXRpb25zKQpgYGAKCkNoZWNrIFBPSSBkYXRhCmBgYHtyfQpzYW1wbGVfbihwb2ksIDEwKQpgYGAKCiMjIyBQb2ludCBkZW5zaXR5IHZpc3VhbGlzYXRpb24KClRoZSBQT0kgZGF0YSBzZXQgZm9yIHRoZSBzdHVkeSBhcmVhIGNvbnRhaW5zIE4gPSA0NzkzNjAgb2JzLiBCZWxvdyBpcyBhIHBvaW50IGRlbnNpdHkgdmlzdWFsaXNhdGlvbiB0byBoYXZlIGFuIG92ZXJ2aWV3IG9mIHRoZSBnZW5lcmFsIHNwYXRpYWwgcGF0dGVybgoKYGBge3J9CiMgY3JlYXRlIG5ldyBzZiB3aXRoIENSUyA0MzI2IGFuZCBYIGFuZCBZIHZhcmlhYmxlcwpwb2lfNDMyNiA8LSBwb2kgJT4lCiAgI3NhbXBsZV9uKDEwMDAwMCkgJT4lCiAgc3RfdHJhbnNmb3JtKDQzMjYpICU+JSAjIHRyYW5mb3JtIHRvIHNhbWUgQ1JTIGFzIHN0YXRpb25zIGFuZCBsaW5lcwogIGNiaW5kKHN0X2Nvb3JkaW5hdGVzKC4pKSAjIGdldCBYIGFuZCBZIGNvb3JkaW5hdGVzCiMgcGxvdApnZ3Bsb3QoKSArCiAgZ2VvbV9iaW4yZChkYXRhID0gcG9pXzQzMjYsIGFlcyhYLCBZKSwgYmlud2lkdGggPSBjKDAuMDEsIDAuMDEpKSArICMgaGVhdG1hcCBvZiAyZCBiaW4gY291bnRzCiAgZ2VvbV9zZihkYXRhID0gbGluZXMsIGNvbD0id2hpdGUiLCBzaXplPTAuMSkgKwogIHRoZW1lX3R1ZnRlKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiKSArCiAgbGFicyh4PSIiLCB5PSIiKQpgYGAKCiMjIFNldHRpbmcgbWFwYm94IGFjY2VzcyB0b2tlbgoKSW4gY2FzZSB5b3UgaGF2ZW4ndCB5ZXQgY3JlYXRlZCBhIE1hcGJveCBhY2NvdW50IHlvdSBjYW4gY3JlYXRlIG9uZSBbaGVyZV0oaHR0cHM6Ly9hY2NvdW50Lm1hcGJveC5jb20vYXV0aC9zaWdudXAvP3JvdXRlLXRvPSUyMmh0dHBzOi8vYWNjb3VudC5tYXBib3guY29tLyUyMikgIAoKQWNjZXNzIHlvdXIgYWNjb3VudCBhbmQgY3JlYXRlIGFuZCBjb3B5IHRoZSDigJxkZWZhdWx0IHB1YmxpYyB0b2tlbuKAnSB0aGF0IGFwcGVhcnMgb24geW91ciBzY3JlZW4KYGBge3IgaW5jbHVkZT1GQUxTRX0KIyBwYXN0ZSB0b2tlbiBoZXJlCiMgUExFQVNFIFVTRSBZT1VSIE9XTiBUT0tFTiBPVEhFUldJU0UgSSBDT1VMRCBJTkNVUiBJTiBDSEFSR0VTIEFOIEJFIE9CTElHRUQgVE8gREVBQ1RJVkFURSBUSElTIFRPS0VOCm15X3Rva2VuIDwtICJway5leUoxSWpvaWJuQmhiRzl0YVc0aUxDSmhJam9pWTJvd01ERjVZWFF4TURBMmVETXlibXd3ZDJ0cVlUVTNiU0o5LkljdnJrdTZRNTdvOEwwZ25jSkk4OWciCiNtYl9hY2Nlc3NfdG9rZW4obXlfdG9rZW4sIGluc3RhbGwgPSBUUlVFKQpgYGAKCmBgYHtyfQojIHBhc3RlIHRva2VuIGhlcmUKIyBteV90b2tlbiA8LSAiWU9VUiBUT0tFTiBHT0VTIEhFUkUiCmBgYAoKIyBTZXJ2aWNlIGFyZWEgYW5hbHlzaXMKCiMjIEdlbmVyYXRlIHNlcnZpY2UgYXJlYSBwb2x5Z29ucwoKYGBge3J9CiMgY3JlYXRlIGEgdW5pcXVlIGlkIHZhcmlhYmxlICJzaWQiCnN0YXRpb25zIDwtIHN0YXRpb25zICU+JQogIHJvd2lkX3RvX2NvbHVtbiguLCAic2lkIikKYGBgCgpgYGB7cn0KIyBzYW1wbGUgNSBzdGF0aW9ucwojczVzIDwtIHNhbXBsZV9uKHN0YXRpb25zLCAxMDApCnM1cyA8LSBzdGF0aW9ucwojIGNlbnRyYWwgc3RhdGlvbnMKI2M1cyA8LSBzdGF0aW9ucyAlPiUKIyAgc2xpY2UoYygxNTAsNDksMTQ3LDIzLDIxNSw1MDApKQpgYGAKClRvIGNhbGN1bGF0ZSB0aGUgaXNvY2hyb25lcyB3ZSB1c2UgYG1iX2lzb2Nocm9uZWAgZnVuY3Rpb24gd2l0aCB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgIAoKKiBsb2NhdGlvbihzKQoqIHByb2ZpbGUgPSAid2Fsa2luZyIsICJkcml2aW5nIiwgImN5Y2xpbmciCiogdGltZSBpbiBtaW51dGVzCiogaWQgPSBjb2x1bW4gaWRlbnRpZmllciBmcm9tIGxvY2F0aW9uCiogYWNjZXNzX3Rva2VuID0gbXlfdG9rZW4KYGBge3J9CndfaXNvIDwtIG1iX2lzb2Nocm9uZShzNXMsICJ3YWxraW5nIiwgdGltZSA9IDEwLCBpZF9jb2x1bW4gPSAic2lkIiwgYWNjZXNzX3Rva2VuID0gbXlfdG9rZW4pCmBgYAoKYGBge3J9CiMgZ2V0IHZhcmlhYmxlcyBmcm9tIHN0YXRpb24gc2YgdG8gam9pbiB3aXRoIGlzb2Nocm9uZXMKc3RhdGlvbnNfa3YgPC0gc3RhdGlvbnMgJT4lCiAgc2VsZWN0KCJzaWQiLCJuYW1lIiwgInpvbmUiKSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkKIyBqb2luCndfaXNvIDwtIHdfaXNvICU+JQogIG1lcmdlKC4sIHN0YXRpb25zX2t2LCBieS54PSJpZCIsIGJ5Lnk9InNpZCIpICU+JQogIHJlbmFtZShzX25hbWUgPSBuYW1lKSAjIHRvIGF2b2lkIGNvbmZsaWN0IHdpdGggUE9JIG5hbWUKYGBgCgpQbG90IGEgc2FtcGxlIG9mIGlzb2Nocm9uZXMKYGBge3J9CiMgc2VsZWN0IDkgcmFuZG9tIGlzb2Nocm9uZXMKcjlzIDwtIHNhbXBsZSh3X2lzbyRpZCwgOSkKCndfaXNvXzkgPC0gd19pc28gJT4lCiAgZmlsdGVyKGlkICVpbiUgcjlzKQoKczkgPC0gc3RhdGlvbnMgJT4lCiAgZmlsdGVyKHNpZCAlaW4lIHI5cykKCnRtX3NoYXBlKHdfaXNvXzkpICsKICB0bV9wb2x5Z29ucyhjb2wgPSAidG9tYXRvIiwKICAgICAgICAgICAgIGJvcmRlci5sd2QgPSAwLjMsCiAgICAgICAgICAgICBhbHBoYSA9IDAuNykgKwogIHRtX2ZhY2V0cyhieT0ic19uYW1lIiwgbmNvbCA9IDMpICsKdG1fc2hhcGUoczkpICsKICB0bV9zeW1ib2xzKGNvbCA9ICJuYXZ5IiwKICAgICAgICAgICAgIHNpemUgPSAwLjIpICsKdG1fc2hhcGUobGluZXMpICsKICB0bV9saW5lcyhsd2Q9MC4yKSArCiAgdG1fbGF5b3V0KGxlZ2VuZC5zaG93ID0gRiwgb3V0ZXIubWFyZ2lucyA9IDAsIHBhbmVsLmxhYmVsLmJnLmNvbG9yID0gJ3doaXRlJykKYGBgCgojIyBBbmFseXNlIHNlcnZpY2UgYXJlYXMKCiMjIyBXaGF0IGRvIHdlIGtub3cgYWJvdXQgdGhlIFBPSSBhdHRyaWJ1dGVzPwoKUGxvdCBhIHNhbXBsZSBvZiBQT0kKYGBge3J9CnNhbXBsZV9QT0kgPC0gc2FtcGxlX24ocG9pXzQzMjYsIDUwMCkKIyBoYW5keSBwYWNrYWdlL2Z1bmN0aW9uIHRvIHBsb3QgaW50ZXJhY3RpdmUgbWFwCm1hcHZpZXcoc2FtcGxlX1BPSSkKYGBgCgpIb3cgbWFueSB2YXJpYWJsZXMgZG8gZWFjaCBvZiB0aGUgY29sdW1ucyBoYXZlPwpgYGB7cn0KcG9pXzQzMjYgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogIHNlbGVjdChncm91cG5hbWUsIGNhdGVnb3J5bmFtZSwgY2xhc3NuYW1lKSAlPiUKICBtdXRhdGUobl9ncm91cG5hbWUgPSBuX2Rpc3RpbmN0KGdyb3VwbmFtZSksCiAgICAgICAgIG5fY2F0ZWdvcnluYW1lID0gbl9kaXN0aW5jdChjYXRlZ29yeW5hbWUpLAogICAgICAgICBuX2NsYXNzbmFtZSA9IG5fZGlzdGluY3QoY2xhc3NuYW1lKSkgJT4lCiAgc2VsZWN0KG5fZ3JvdXBuYW1lLCBuX2NhdGVnb3J5bmFtZSwgbl9jbGFzc25hbWUpICU+JQogIHVuaXF1ZSgpCmBgYApBcyBpdCBpcyBvZnRlbiB0aGUgY2FzZSB3aXRoIGNsYXNzaWZpY2F0aW9uIHNjaGVtZXMsIHRoZXNlIGFyZSBzdHJ1Y3R1cmVkIGhpZXJhcmNoaWNhbGx5LiBUaGUgJ2NsYXNzbmFtZScgYW5kICdjYXRlZ29yeW5hbWUnIHZhcmlhYmxlcyBhcmUgbmVzdGVkIGludG8gdGhlIDkgbGV2ZWxzIG9mIHRoZSAnZ3JvdXBuYW1lJyB2YXJpYWJsZS4KCmBgYHtyfQpsZXZlbHMocG9pXzQzMjYkZ3JvdXBuYW1lKSAKYGBgCgpUaGlzIHN1bW1hcnkgd2lsbCBnaXZlIHVzIHRoZSBjb3VudCBvZiBkYXRhIHBvaW50cyBpbiBlYWNoIGxldmVsLiBBIHNpbXBsZSBhbmFseXNpcyBvZiB0aGUgc2VydmljZSBhcmVhcyB3b3VsZCBiZSB0byBjb3VudCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyB3aXRoaW4gdGhlIGFyZWEsIGJ1dCBpdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBleGFtaW5lIHRvIHdoYXQgZ3JvdXAgZG8gdGhvc2UgcG9pbnRzIGJlbG9uZy4gSXMgdGhlIGFjY2Vzc2liaWxpdHkgdG8gcG9pbnRzIG9mIGludGVyZXN0IG1lYXN1cmVkIGJ5IGNvdW50aW5nIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zPywgaXQgd29ydGggaGF2aW5nIGEgZGVlcGVyIGxvb2sgaW50byB0aGUga2luZCBvZiBwb2ludHMgYXJlIGF0IHJlYWNoIHdpdGhpbiBhbiBhcmVhLiAgCgpgYGB7cn0KIyBob3cgbWFueSBvYnNlcnZhdGlvbnMgZG8geW91IGhhdmUgZm9yICdncm91cG5hbWUnCnBvaV80MzI2ICU+JQogIHN0X2Ryb3BfZ2VvbWV0cnkoKSAlPiUKICBjb3VudChncm91cG5hbWUsIHNvcnQgPSBUUlVFKQpgYGAKCk5vdyB3ZSBjYW4gbG9vayBhdCB0aGUgY29tcG9zaXRpb24gb2YgdGhlIGdyb3VwcyAoZ3JvdXBuYW1lIHZhcmlhYmxlKS4gVGhpcyB0YWJsZSBzaG93cyB0aGUgYW1vdW50IG9mIGRpZmZlcmVudCB2YWx1ZXMgaW4gZWFjaCBncm91cCAKCmBgYHtyfQpwb2lfNDMyNiAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lIAogIHNlbGVjdChncm91cG5hbWUsIGNhdGVnb3J5bmFtZSkgJT4lIAogIHVuaXF1ZSgpICU+JQogIGNvdW50KGdyb3VwbmFtZSkKYGBgCgpIZXJlIHdlIGFyZSBhIHN0ZXAgZnJvbSBidWlsZGluZyBhIGRlbmRvZ3JhbSwgd2hpY2ggaXMgYSBuZXRvd29yayByZXByZXNlbnRhdGlvbiBvZiBoaWVyYXJjaGljYWwgcmVsYXRpb25zaGlwcyBzdWNoIGFzIHRoZSBjbGFzc2lmaWNhdGlvbiBzY2hlbWUgb2YgUE9JIHRoYXQgd2UgYXJlIHN0dWR5aW5nLiAgCgpgYGB7cn0KIyBMaWJyYXJpZXMKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoaWdyYXBoKQojIGNyZWF0ZSBhIGhpZXJhcmNoeSBmcm9tIGRhdGEgZnJhbWUgdG8gZXhhbWluZSBjbGFzc2lmaWNhdGlvbiBzY2hlbWUKcG9pX2hpZXIgPC0gcG9pXzQzMjYgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogIHNlbGVjdChncm91cG5hbWUsIGNhdGVnb3J5bmFtZSwgY2xhc3NuYW1lKSAlPiUKICB1bmlxdWUoKSAKCnJvd25hbWVzKHBvaV9oaWVyKSA8LSBOVUxMCmBgYAoKYGBge3J9CiMgdHJhbnNmb3JtIGl0IHRvIGEgZWRnZSBsaXN0CmVkZ2VzX2xldmVsMF8xIDwtIHBvaV9oaWVyICU+JQogIHNlbGVjdChncm91cG5hbWUpICU+JSAKICBtdXRhdGUoaGVhZCA9ICJQT0kiKSAlPiUKICB1bmlxdWUoKSAlPiUgCiAgcmVuYW1lKGZyb209aGVhZCwgdG89Z3JvdXBuYW1lKSAlPiUKICBzZWxlY3QoMiwxKQoKZWRnZXNfbGV2ZWwxXzIgPC0gcG9pX2hpZXIgJT4lIAogIHNlbGVjdChncm91cG5hbWUsIGNhdGVnb3J5bmFtZSkgJT4lIAogIHVuaXF1ZSgpICU+JSAKICByZW5hbWUoZnJvbT1ncm91cG5hbWUsIHRvPWNhdGVnb3J5bmFtZSkKCmVkZ2VzX2xldmVsMl8zIDwtIHBvaV9oaWVyICU+JSAKICBzZWxlY3QoY2F0ZWdvcnluYW1lLCBjbGFzc25hbWUpICU+JSAKICB1bmlxdWUoKSAlPiUgcmVuYW1lKGZyb209Y2F0ZWdvcnluYW1lLCB0bz1jbGFzc25hbWUpCgplZGdlX2xpc3QgIDwtIHJiaW5kKGVkZ2VzX2xldmVsMF8xLCBlZGdlc19sZXZlbDFfMikKZWRnZV9saXN0ICA8LSByYmluZChlZGdlX2xpc3QsIGVkZ2VzX2xldmVsMl8zKQpgYGAKCmBgYHtyIGZpZy5jYXA9IkhpZXJhcmNoaWNhbCBzdHJ1dHVyZSBvZiB0aGUgUE9JcyAnZ3JvdXAnLCAnY2F0ZWdvcmllcycsICdjbGFzcycgcGFyZW50LWNoaWxkIHJlbGF0aW9uc2hpcHMuIFRoaXMgY2FuIGhlbHAgdG8gYmV0dGVyIHVuZGVyc3RhbmQgdGhlIHJpY2huZXNzIG9mIHVyYmFuIGZlYXR1cmVzIGF2YWlsYWJsZSBpbiB0aGUgc3R1ZHkgYXJlYSJ9CiMgTm93IHdlIGNhbiBwbG90IHRoZSBncmFwaCBvYmplY3QKcG9pX2dyYXBoIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShlZGdlX2xpc3QpCgpnZ3JhcGgocG9pX2dyYXBoLCBsYXlvdXQgPSAnZGVuZHJvZ3JhbScsIGNpcmN1bGFyID0gRkFMU0UpICsgCiAgZ2VvbV9lZGdlX2RpYWdvbmFsKGFscGhhID0gMC4xLCBzaXplPTAuNSkgKwogIGdlb21fbm9kZV9wb2ludChjb2xvcj0idG9tYXRvIiwgc2l6ZT0wLjAxKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsPWMoIiIsIHBvaV9ncmFwaFtbMV1dJFBPSSRuYW1lLCByZXAoIiIsNjYyKSkpLCBzaXplPTIuNSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV95X3JldmVyc2UoKSAKYGBgCgojIyMgUE9JIGNvdW50cyBwZXIgc2VydmljZSBhcmVhCgpgYGB7cn0KIyBKb2luIHN0YXRpb24gaWRlbnRpZmllciB0byBQT0kgYW5kIHNlbGVjdCBvbmx5IHRob3NlIGludGVyc2VjdGluZyB3aXRoIHRoZSBpc29jaHJvbmVzIChvbWl0IHBvaW50cyB3aXRoIE5BKQojIHRoaXMgam9pbnMgdGhlIGlzb2Nocm9uZSBkYXRhIHRvIHRoZSBQT0lzCnBvaV9zYSA8LSBwb2lfNDMyNiAlPiUKICBzdF9qb2luKC4sIHdfaXNvKSAlPiUKICBuYS5vbWl0KCkgIyBvbWl0IFBPSSB0aGF0IGRvIG5vdCBpbnRlcnNlY3Qgd2l0aCBhbnkgc2VydmljZSBhcmVhCgpwb2lfY291bnQgPC0gcG9pX3NhICU+JQogIGdyb3VwX2J5KGlkLCBzX25hbWUpICU+JQogIHN1bW1hcmlzZShuPW4oKSkKcG9pX2NvdW50CmBgYAoKYGBge3J9CiMgY3JlYXRlIGEgc2luZ2xlIHBvaW50IHBlciBzZXJ2aWNlIGFyZWEgdG8gcGxvdApwb2lfY291bnRfY2VudHJvaWQgPC0gc3RfY2VudHJvaWQocG9pX2NvdW50KQpgYGAKCkNyZWF0ZSBhIHByb3BvcnRpb25hbCBzeW1ib2wgbWFwIHdlaWdodGVkIGJ5IGNvdW50IHRvIGV4YW1pbmUgdGhlIG9wcG9ydHVuaXRpZXMgYXZhaWxhYmxlIHdpdGhpbiB0aGUgc3R1ZHkgYXJlYXMuCgpgYGB7cn0KI3RtYXBfbW9kZSgicGxvdCIpCnRtX3NoYXBlKGxpbmVzKSArCiAgdG1fbGluZXMobHdkPTAuMSkgKwp0bV9zaGFwZShwb2lfY291bnRfY2VudHJvaWQpICsKICB0bV9idWJibGVzKGNvbCA9ICJ0b21hdG8iLAogICAgICAgICAgICAgc2l6ZSA9ICJuIiwKICAgICAgICAgICAgIGFscGhhID0gMC40LAogICAgICAgICAgICAgYm9yZGVyLmx3ZCA9IDAuMywKICAgICAgICAgICAgIHN0eWxlID0gImttZWFucyIsCiAgICAgICAgICAgICB0aXRsZS5zaXplPSJDb3VudCIpICsKICB0bV9sYXlvdXQodGl0bGUgPSAiUG9pbnRzIG9mIEludGVyZXN0IHdpdGhpbiBhIDEwLW1pbnV0ZSB3YWxraW5nIHNlcnZpY2UgYXJlYSBmcm9tIHJhaWwgc3RhdGlvbnMgaW4gTG9uZG9uIiwgdGl0bGUuc2l6ZSA9IDAuNzcpICsKICB0bV9jcmVkaXRzKHNpemUgPSAzLCB0ZXh0ID0gIk9yZG5hbmNlIFN1cnZleSBEaWdpbWFwOiBMaWNlbnNlZCBEYXRhOiDCqSBDcm93biBjb3B5cmlnaHQgYW5kIGRhdGFiYXNlIHJpZ2h0cyAyMDIwIE9yZG5hbmNlIFN1cnZleSAoMTAwMDI1MjUyKS4gVGhpcyBtYXRlcmlhbCBpbmNsdWRlcyBkYXRhIGxpY2Vuc2VkIGZyb20gUG9pbnRYwqkgRGF0YWJhc2UgUmlnaHQvQ29weXJpZ2h0IDIwMjBcbk1hcCBjcmVhdGVkIGJ5IE5pY29sYXMgUGFsb21pbm9zIiwgcG9zaXRpb24gPSBjKCJyaWdodCIsICJCT1RUT00iKSkKYGBgCgpMZXQgdXMgaW52ZXN0aWdhdGUgdGhlIHJpY2huZXNzIG9mIFBPSXMgaW4gZWFjaCBhcmVhIGJ5IGxvb2tpbmcgYXQgdGhlIHR5cGUgb2YgY2xhc3MsIGNhdGVnb3J5IG9yIGdyb3VwIHRoZSBwb2ludHMgYmVsb25nIHRvLiBSaWNobmVzcyBpcyBhIG1lYXN1cmUgb2YgZGl2ZXJzaXR5IHdoaWNoIGNhbiBoZWxwIGFzc2VzcyB0aGUgdmFyaWV0eSBvZiBvcHBvcnR1bml0aWVzIHRoYXQgYXJlIGFjY2Vzc2libGUgd2l0aGluIHRoZSBzdHVkeSBhcmVhIHdoaWNoIGlzIG1vcmUgY29tcGxleCB0aGFuIHRoZSBhYnNvbHV0ZSBjb3VudC4KClRoaXMgdGFibGUgc3VtbWFyaXNlcyB0aGUgbnVtYmVyIG9mIGRpZmZlcmVudCAnZ3JvdXBzJyBpbiBlYWNoIHN0dWR5IGFyZWEuIFRoZSBncmVhdCBtYWpvcml0eSBvZiB0aGUgc2VydmljZSBhcmVhcyBoYXZlIFBPSXMgdGhhdCBiZWxvbmcgdG8gdGhlIDkgZ3JvdXBzLgpgYGB7cn0KIwpwb2lfc2EgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogIGdyb3VwX2J5KGlkLCBncm91cG5hbWUsIHNfbmFtZSkgJT4lCiAgc3VtbWFyaXNlKG49bigpKSAlPiUgIyB0b3RhbCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIHBlciBncm91cAogIGdyb3VwX2J5KHNfbmFtZSkgJT4lCiAgbXV0YXRlKHJpY2huZXNzPW5fZGlzdGluY3QoZ3JvdXBuYW1lKSkgJT4lICMgZGlzdGluY3QgbnVtYmVyIG9mIGdyb3VwcwogIHNlbGVjdCgzLDUpICU+JSAKICB1bmlxdWUoKQpgYGAKCldoYXQgaXMgdGhlIHNwYXRpYWwgcGF0dGVybiBvZiB0aGUgOSBkaWZmZXJlbnQgZ3JvdXBzPwoKYGBge3J9CiMgY3JlYXRlIGEgc2Ygb2JqZWN0IHdpdGggdGhlICdncm91cCcgc3VtbWFyeQpwb2lfY291bnRfZ3IgPC0gcG9pX3NhICU+JQogIGdyb3VwX2J5KGlkLCBncm91cG5hbWUpICU+JSAjIGdyb3VwbmFtZSBjb3VudCBieSBzdGF0aW9uCiAgc3VtbWFyaXNlKG49bigpKQpwb2lfY291bnRfZ3IKYGBgCgpgYGB7cn0KIyBjcmVhdGUgYSBzaW5nbGUgcG9pbnQgcGVyIHNlcnZpY2UgYXJlYSB0byBwbG90CnBvaV9jb3VudF9ncl9jZW4gPC0gc3RfY2VudHJvaWQocG9pX2NvdW50X2dyKQpgYGAKCmBgYHtyfQp0bV9zaGFwZShsaW5lcykgKwogIHRtX2xpbmVzKGx3ZD0wLjEpICsKdG1fc2hhcGUocG9pX2NvdW50X2dyX2NlbikgKwogIHRtX2J1YmJsZXMoY29sID0gInRvbWF0byIsCiAgICAgICAgICAgICBzaXplID0gIm4iLAogICAgICAgICAgICAgYWxwaGEgPSAwLjQsCiAgICAgICAgICAgICBib3JkZXIubHdkID0gMC4zLAogICAgICAgICAgICAgc3R5bGUgPSAia21lYW5zIiwKICAgICAgICAgICAgIHRpdGxlLnNpemU9IkNvdW50IikgKwogIHRtX2ZhY2V0cyhieT0iZ3JvdXBuYW1lIikgKwogIHRtX2xheW91dChsZWdlbmQuc2hvdyA9IEYsIG91dGVyLm1hcmdpbnMgPSAwLCBwYW5lbC5sYWJlbC5iZy5jb2xvciA9ICd3aGl0ZScsIGZyYW1lID0gRikKYGBgCgojIyMgRGl2ZXJzaXR5IGFuYWx5c2lzOiBwb2ludCB0eXBlcyBwZXIgc2VydmljZSBhcmVhCgpBbGwgdGhlIG5pbmUgZ3JvdXBzIChBY2NvbW1vZGF0aW9uLCBFYXRpbmcgYW5kIERyaW5raW5nOyBBdHRyYWN0aW9uczsgQ29tbWVyY2lhbCBTZXJ2aWNlczsgRWR1Y2F0aW9uIGFuZCBIZWFsdGg7IE1hbnVmYWN0dXJpbmcgYW5kIFByb2R1Y3Rpb247IFB1YmxpYyBJbmZyYXN0cnVjdHVyZTsgUmV0YWlsOyBTcG9ydCBhbmQgRW50ZXJ0YWlubWVudDsgVHJhbnNwb3J0KSBzZWVtIHRvIGJlIHJlbGV2YW50IGZvciBhIHNlbGYtc3VmZmljaWVudCBuZWlnaGJvdXJob29kLiBMZXQncyBxdWFudGlmeSB0aGUgcmljaG5lc3Mgb2YgdGhlc2UgZ3JvdXBzIGJ5IGxvb2tpbmcgYXQgdGhlIHR5cGUgb2YgcG9pbnRzIHRoYXQgYXJlIGxvY2F0ZWQgaW4gZWFjaCBzZXJ2aWNlIGFyZWEuCgpgYGB7cn0KIyBjcmVhdGUgc3VtbWFyeSBvZiBvYnMuIGJ5IHN0YXRpb24KcHBzIDwtIHBvaV9zYSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lCiAgY291bnQoaWQpICU+JQogIHJlbmFtZShzdGF0aW9uX2NvdW50ID0gbikKCiMgY3JlYXRlIGEgJ1JpY2huZXNzJyBtZXRyaWMgYnkgJ0dyb3VwJywgIkNhdGVnb3J5JyBhbmQgJ0NsYXNzJwpkaXZfdGFiIDwtIHBvaV9zYSAlPiUKICBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lCiAgZ3JvdXBfYnkoaWQsIHNfbmFtZSkgJT4lCiAgc3VtbWFyaXNlKHJpY2hfZyA9IG5fZGlzdGluY3QoZ3JvdXBuYW1lKSwKICAgICAgICAgICAgcmljaF9jYXQgPSBuX2Rpc3RpbmN0KGNhdGVnb3J5bmFtZSksCiAgICAgICAgICAgIHJpY2hfY2xhID0gbl9kaXN0aW5jdChjbGFzc25hbWUpKQoKIyBtZXJnZQpkaXZfdGFiIDwtIGRpdl90YWIgJT4lCiAgbWVyZ2UoLiwgcHBzKQoKIyBtZXJnZSB0byBzdGF0aW9ucyB0byBnZXQgZ2VvbWV0cnkgYmFjayAodGhlIGFwcHJvYWNoIGFib3ZlIHdhcyBkaWZmZXJlbnQsIHdlIGNyZWF0ZWQgY2VudHJvaWRzKQpzdGFfZGl2IDwtIHN0YXRpb25zICU+JQogIHNlbGVjdCgic2lkIiwibmFtZSIsICJ6b25lIikgJT4lCiAgbWVyZ2UoLiwgZGl2X3RhYiwgYnkueD0ic2lkIiwgYnkueT0iaWQiKQpgYGAKClBsb3QgaXQKYGBge3J9CnRtYXBfbW9kZSgicGxvdCIpCnRtX3NoYXBlKGxpbmVzKSArCiAgdG1fbGluZXMobHdkPTAuMSkgKwp0bV9zaGFwZShzdGFfZGl2KSArCiAgdG1fc3ltYm9scyhjb2wgPSAicmljaF9jbGEiLAogICAgICAgICAgICAgcGFsZXR0ZT0iUmRQdSIsCiAgICAgICAgICAgICBzaXplID0gMC4xLAogICAgICAgICAgICAgc2hhcGUgPSAic3RhdGlvbl9jb3VudCIsCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCwKICAgICAgICAgICAgIGJvcmRlci5sd2QgPSAwLjMsCiAgICAgICAgICAgICBzdHlsZSA9ICJrbWVhbnMiLAogICAgICAgICAgICAgbiA9IDMsCiAgICAgICAgICAgICBzaGFwZXMubiA9IDMsCiAgICAgICAgICAgICBzaGFwZXMubGVnZW5kLmZpbGwgPSAiZ3JheTMwIiwKICAgICAgICAgICAgIHRpdGxlLnNoYXBlPSJDb3VudCIsCiAgICAgICAgICAgICB0aXRsZS5jb2w9IkRpdmVyc2l0eSIpICsKICB0bV9sYXlvdXQodGl0bGUgPSAiRGl2ZXJzaXR5IG9mIFBvaW50cyBvZiBJbnRlcmVzdCB3aXRoaW4gYSAxMC1taW51dGUgd2Fsa2luZyBzZXJ2aWNlIGFyZWEgZnJvbSByYWlsIHN0YXRpb25zIGluIExvbmRvbiIsIG1haW4udGl0bGUgPSAiIiwgdGl0bGUuc2l6ZSA9IDAuNzcpICsKICB0bV9jcmVkaXRzKHNpemUgPSAzLCB0ZXh0ID0gIk9yZG5hbmNlIFN1cnZleSBEaWdpbWFwOiBMaWNlbnNlZCBEYXRhOiDCqSBDcm93biBjb3B5cmlnaHQgYW5kIGRhdGFiYXNlIHJpZ2h0cyAyMDIwIE9yZG5hbmNlIFN1cnZleSAoMTAwMDI1MjUyKS4gVGhpcyBtYXRlcmlhbCBpbmNsdWRlcyBkYXRhIGxpY2Vuc2VkIGZyb20gUG9pbnRYwqkgRGF0YWJhc2UgUmlnaHQvQ29weXJpZ2h0IDIwMjBcbk1hcCBjcmVhdGVkIGJ5IE5pY29sYXMgUGFsb21pbm9zIiwgcG9zaXRpb24gPSBjKCJyaWdodCIsICJCT1RUT00iKSkKYGBgCgpBY2NvcmRpbmcgdG8gdGhlIHBhdHRlcm4gZGlzcGxheWVkIGluIHByZXZpb3VzIGFuYWx5c2lzLCBjZW50cmFsbHkgbG9jYXRlZCBzdGF0aW9ucyBoYXZlIGEgZ29vZCBwcm92aXNpb24gb2YgdXJiYW4gZmFjaWxpdGllcyBhY2NvcmRpbmcgdG8gYm90aCBudW1iZXIgYW5kIHZhcmlldHkuIFpvbmUgMSBpbiBMb25kb24gbW9yZSBvciBsZXNzIG1hdGNoZXMgdGhlIHBsYW5uaW5nIGRlZmluaXRpb24gb2YgdGhlIENlbnRyYWwgQWN0aXZpdHkgWm9uZSB3aGljaCBpcyBlZmZlY3RpdmVseSBub3Qgb25seSBhIHNlbGYtc3VmZmljaWVudCBhcmVhIGJ1dCBhbHNvIGEgcHJvdmlkZXIgb2Ygc2VydmljZXMgZm9yIHRoZSB3aG9sZSBvZiBMb25kb24uIEZvciBhIG1vcmUgbWVhbmluZ2Z1bCBhbmFseXNpcyBvZiBwb3RlbnRpYWxseSB1bmRlci1zZXJ2ZWQgYXJlYXMgd2Ugd2lsbCBmaWx0ZXIgb3V0IHpvbmUgMSwgYW5kIHpvb20taW4gdG8gY29tcGFyZSB0aGUgdG9wIGFuZCB0YWlsIGFyZWFzIGFjY29yZGluZyB0byByaWNobmVzcyBxdWFudGlmaWVkIGJ5IHRoZSBudW1iZXIgb2YgZGlzdGluY3QgJ2NsYXNzZXMnIGxvY2F0ZWQgd2l0aGluIHRoZSBzZXJ2aWNlIGFyZWEuCgpgYGB7cn0KIyBnZXQgc3RhdGlvbnMgd2l0aCBsb3dlc3QgZGl2ZXJzaXR5CnRhaWwgPC0gc3RhX2RpdiAlPiUKICAjIGtlZXAgYWxsIHRoYXQgYXJlIG5vdCB6b25lID0gMQogIGZpbHRlcih6b25lICE9ICIxIikgJT4lCiAgYXJyYW5nZShyaWNoX2csIHJpY2hfY2F0LCByaWNoX2NsYSkgJT4lICMgYXJyYW5nZSBpcyBhc2NlbmRhbnQgYnkgZGVmYXVsdCAob3JkZXIgb2Ygc29ydGluZyBmYWN0b3JzIGFmZmVjdCByZXN1bHQpCiAgc2xpY2UoMTozKQp0YWlsCmBgYAoKYGBge3J9CiMgZ2V0IHN0YXRpb25zIHdpdGggaGlnaGVzdCBkaXZlcnNpdHkKaGVhZCA8LSBzdGFfZGl2ICU+JQogICMga2VlcCBhbGwgdGhhdCBhcmUgbm90IHpvbmUgPSAxCiAgZmlsdGVyKHpvbmUgIT0gIjEiKSAlPiUKICBhcnJhbmdlKGRlc2MocmljaF9nLCByaWNoX2NhdCwgcmljaF9jbGEpKSAlPiUKICBzbGljZSgxOjMpCmhlYWQKYGBgCgpgYGB7cn0KIyBnZXQgUE9JIGFuZCBpc29jaHJvbmVzIGZyb20gc2YgYnkgc3RhdGlvbiBpZCAoc2lkKQoKIyB0YWlsCnRhaWxfaXNvIDwtIHdfaXNvICU+JQogIGZpbHRlcihpZCAlaW4lIHRhaWwkc2lkKQp0YWlsX3BvaSA8LSBwb2lfc2EgJT4lCiAgZmlsdGVyKGlkICVpbiUgdGFpbCRzaWQpCgojIGhlYWQKaGVhZF9pc28gPC0gd19pc28gJT4lCiAgZmlsdGVyKGlkICVpbiUgaGVhZCRzaWQpCmhlYWRfcG9pIDwtIHBvaV9zYSAlPiUKICBmaWx0ZXIoaWQgJWluJSBoZWFkJHNpZCkKYGBgCgpQbG90IGhlYWQgYW5kIHRhaWwKCmBgYHtyfQp0bWFwX21vZGUoInBsb3QiKQp0bV9zaGFwZShsaW5lcykgKwogIHRtX2xpbmVzKGx3ZD0wLjEpICsKdG1fc2hhcGUoaGVhZCkgKwogIHRtX2RvdHMoY29sID0gInRvbWF0byIsCiAgICAgICAgICAgICBzaXplID0gMC4zLAogICAgICAgICAgICAgYWxwaGEgPSAwLjgsCiAgICAgICAgICAgICBib3JkZXIubHdkID0gMC4zKSArCiAgdG1fdGV4dCgicmljaF9jbGEiLCBzaXplID0gMC43LCBqdXN0PWMoImNlbnRlciIsIDIpKSArCnRtX3NoYXBlKGhlYWQpICsKICB0bV9kb3RzKGNvbCA9ICJ0b21hdG8iLAogICAgICAgICAgICAgc2l6ZSA9IDAuMSwKICAgICAgICAgICAgIGFscGhhID0gMC44LAogICAgICAgICAgICAgYm9yZGVyLmx3ZCA9IDAuMykgKwogIHRtX3RleHQoIm5hbWUiLCBzaXplID0gMC41LCBqdXN0PWMoImNlbnRlciIsIDQpKSArCnRtX3NoYXBlKHRhaWwpICsKICB0bV9kb3RzKGNvbCA9ICJwaW5rIiwKICAgICAgICAgICAgIHNpemUgPSAwLjMsCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCwKICAgICAgICAgICAgIGJvcmRlci5sd2QgPSAwLjMpICsKICB0bV90ZXh0KCJyaWNoX2NsYSIsIHNpemUgPSAwLjcsIGp1c3Q9YygiY2VudGVyIiwgMikpICsKdG1fc2hhcGUodGFpbCkgKwogIHRtX2RvdHMoY29sID0gInBpbmsiLAogICAgICAgICAgICAgc2l6ZSA9IDAuMSwKICAgICAgICAgICAgIGFscGhhID0gMC44LAogICAgICAgICAgICAgYm9yZGVyLmx3ZCA9IDAuMykgKwogIHRtX3RleHQoIm5hbWUiLCBzaXplID0gMC41LCBqdXN0PWMoImNlbnRlciIsIDQpKSArCnRtX3NoYXBlKHN0YXRpb25zKSArCiAgdG1fZG90cyhjb2wgPSAiZ3JheTIwIiwKICAgICAgICAgICAgIHNpemUgPSAwLjAwNywKICAgICAgICAgICAgIGFscGhhID0gMC4zLAogICAgICAgICAgICAgYm9yZGVyLmx3ZCA9IDAuMDAxKSArCiAgdG1fbGF5b3V0KHRpdGxlID0gIjEwLW1pbnV0ZSB3YWxraW5nIHNlcnZpY2UgYXJlYXMgd2l0aCBoaWdoZXIgYW5kIGxvd2VyIGRpdmVyc2l0eSBhY2NvcmRpbmcgdG8gbnVtYmVyIG9mICdjbGFzc2VzJyIsIGlubmVyLm1hcmdpbnMgPSBjKDAuMDgsMCwwLDApLCB0aXRsZS5zaXplID0gMC43NykgCmBgYAoKWm9vbWluZy1pbgoKYGBge3J9CiMgY3JlYXRlIGN1c3RvbSBwYWxldHRlCmdfY29sIDwtIGMoJyNlNjE5NEInLCAnIzNjYjQ0YicsICcjZmZlMTE5JywgJyM0MzYzZDgnLCAnI2Y1ODIzMScsICcjNDJkNGY0JywgJyNmMDMyZTYnLCAnI2ZhYmVkNCcsICcjNDY5OTkwJykKCnRtYXBfbW9kZSgicGxvdCIpCmhlYWRfbSA8LSB0bV9zaGFwZShsaW5lcykgKwogIHRtX2xpbmVzKGx3ZD0wLjEpICsKdG1fc2hhcGUoaGVhZF9pc28pICsKICB0bV9wb2x5Z29ucyhjb2wgPSAiZ3JleTkwIiwKICAgICAgICAgICAgIGJvcmRlci5sd2QgPSAwLjMsCiAgICAgICAgICAgICBhbHBoYSA9IDAuNykgKwp0bV9mYWNldHMoYnk9InNfbmFtZSIsIG5yb3cgPSAxKSArCnRtX3NoYXBlKGhlYWRfcG9pKSArCiAgdG1fZG90cyhjb2wgPSAiZ3JvdXBuYW1lIiwKICAgICAgICAgIHBhbGV0dGUgPSBnX2NvbCwKICAgICAgICAgICAgIHNpemUgPSAwLjIsCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCwKICAgICAgICAgICAgIGJvcmRlci5sd2QgPSAwLjMsCiAgICAgICAgICAgICB0aXRsZT0iR3JvdXAiKSArCiAgdG1fbGF5b3V0KHRpdGxlID0gIiIsIGZyYW1lPUZBTFNFLCBwYW5lbC5sYWJlbC5iZy5jb2xvciA9ICd3aGl0ZScsIG1haW4udGl0bGUgPSAiSGlnaGVyIGRpdmVyc2l0eSIsIG1haW4udGl0bGUuc2l6ZSA9IDAuOCkgKwp0bV9sZWdlbmQoc2hvdyA9IEZBTFNFKSAKCnRhaWxfbSA8LSB0bV9zaGFwZShsaW5lcykgKwogIHRtX2xpbmVzKGx3ZD0wLjEpICsKdG1fc2hhcGUodGFpbF9pc28pICsKICB0bV9wb2x5Z29ucyhjb2wgPSAiZ3JleTkwIiwKICAgICAgICAgICAgIGJvcmRlci5sd2QgPSAwLjMsCiAgICAgICAgICAgICBhbHBoYSA9IDAuNykgKwp0bV9mYWNldHMoYnk9InNfbmFtZSIsIG5yb3cgPSAxKSArCnRtX3NoYXBlKHRhaWxfcG9pKSArCiAgdG1fZG90cyhjb2wgPSAiZ3JvdXBuYW1lIiwKICAgICAgICAgIHBhbGV0dGUgPSBnX2NvbCwKICAgICAgICAgICAgIHNpemUgPSAwLjIsCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCwKICAgICAgICAgICAgIGJvcmRlci5sd2QgPSAwLjMsCiAgICAgICAgICAgICB0aXRsZT0iR3JvdXAiKSArCiAgdG1fbGF5b3V0KHRpdGxlID0gIiIsIGZyYW1lPUZBTFNFLCBwYW5lbC5sYWJlbC5iZy5jb2xvciA9ICd3aGl0ZScsIG1haW4udGl0bGUgPSAiTG93ZXIgZGl2ZXJzaXR5IiwgbWFpbi50aXRsZS5zaXplID0gMC44KSArCnRtX2xlZ2VuZChzaG93ID0gRkFMU0UpCgpsZWdlbmQgPC0gdG1fc2hhcGUobGluZXMpICsKICB0bV9saW5lcyhsd2Q9MC4xKSArCnRtX3NoYXBlKHRhaWxfaXNvKSArCiAgdG1fcG9seWdvbnMoY29sID0gImdyZXk5MCIsCiAgICAgICAgICAgICBib3JkZXIubHdkID0gMC4zLAogICAgICAgICAgICAgYWxwaGEgPSAwLjcpICsKdG1fc2hhcGUodGFpbF9wb2kpICsKICB0bV9kb3RzKGNvbCA9ICJncm91cG5hbWUiLAogICAgICAgICAgcGFsZXR0ZSA9IGdfY29sLAogICAgICAgICAgICAgc2l6ZSA9IDAuMiwKICAgICAgICAgICAgIGFscGhhID0gMC44LAogICAgICAgICAgICAgYm9yZGVyLmx3ZCA9IDAuMywKICAgICAgICAgICAgIHRpdGxlPSJHcm91cCIpICsKICB0bV9sYXlvdXQodGl0bGUgPSAiIiwgZnJhbWU9RkFMU0UsIHBhbmVsLmxhYmVsLmJnLmNvbG9yID0gJ3doaXRlJywgbWFpbi50aXRsZSA9ICJMb3dlciBkaXZlcnNpdHkiLCBtYWluLnRpdGxlLnNpemUgPSAwLjgsIGxlZ2VuZC5vbmx5ID1UKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnRtYXBfYXJyYW5nZShoZWFkX20sIGxlZ2VuZCwgdGFpbF9tLCBucm93ID0gMiwgd2lkdGhzID0gYygwLjc1LCAwLjI1KSkKYGBgCiAgCldoYXQgaXMgdGhlIGluY3JlYXNlIGluIGRpdmVyc2l0eSBpZiB3ZSBjaGFuZ2UgdGhlIG1vZGUgb2YgdHJhbnNwb3J0IHRvIGRlZmluZSB0aGUgZXh0ZW50IG9mIHRoZSBzZXJ2aWNlIGFyZWEgaW4gdGhlIGFyZWFzIHdpdGggbG93ZXN0IGRpdmVyc2l0eT8gIAoKYGBge3J9CiMgbG93IGRpdmVyc2l0eSBzZXJ2aWNlIGFyZWEgc3RhdGlvbnMKbGRzYXMgPC0gc3RhdGlvbnMgJT4lCiAgZmlsdGVyKHNpZCAlaW4lIHRhaWwkc2lkKQpgYGAKCmBgYHtyfQojIGdldCBpc29jaHJvbmVzIGZvciBjeWNsaW5nIG1vZGUKd19pc29fbG93IDwtIG1iX2lzb2Nocm9uZShsZHNhcywgImN5Y2xpbmciLCB0aW1lID0gMTAsIGlkX2NvbHVtbiA9ICJzaWQiLCBhY2Nlc3NfdG9rZW4gPSBteV90b2tlbikKCiMgam9pbiBzdGF0aW9ucyBkYXRhCndfaXNvX2xvdyA8LSB3X2lzb19sb3cgJT4lCiAgbWVyZ2UoLiwgc3RhdGlvbnNfa3YsIGJ5Lng9ImlkIiwgYnkueT0ic2lkIikgJT4lCiAgcmVuYW1lKHNfbmFtZSA9IG5hbWUpICMgdG8gYXZvaWQgY29uZmxpY3Qgd2l0aCBQT0kgbmFtZQpgYGAKCmBgYHtyfQojSm9pbiBzdGF0aW9uIGlkZW50aWZpZXIgdG8gUE9JIGFuZCBzZWxlY3Qgb25seSB0aG9zZSBpbnRlcnNlY3Rpbmcgd2l0aCB0aGUgaXNvY2hyb25lcyAob21pdCBwb2ludHMgd2l0aCBOQSkKcG9pX2xvdyA8LSBwb2lfc2EgJT4lCiAgc2VsZWN0KC1pZCwgLXRpbWUsIC1zX25hbWUsIC16b25lKSAlPiUgIyBhbHJlYWR5IGluIHBvaV9zYSBmcm9tIHByZXZpb3VzIGpvaW4KICBzdF9qb2luKC4sIHdfaXNvX2xvdykgJT4lCiAgbmEub21pdCgpICMgb21pdCBQT0kgdGhhdCBkbyBub3QgaW50ZXJzZWN0IHdpdGggc2VydmljZSBhcmVhCmBgYAoKYGBge3J9CiMgY3JlYXRlIGEgJ1JpY2huZXNzJyBtZXRyaWMgYnkgJ0dyb3VwJywgIkNhdGVnb3J5JyBhbmQgJ0NsYXNzJwpkaXZfbG93IDwtIHBvaV9sb3cgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogIGdyb3VwX2J5KGlkLCBzX25hbWUpICU+JQogIHN1bW1hcmlzZShyaWNoX2cgPSBuX2Rpc3RpbmN0KGdyb3VwbmFtZSksCiAgICAgICAgICAgIHJpY2hfY2F0ID0gbl9kaXN0aW5jdChjYXRlZ29yeW5hbWUpLAogICAgICAgICAgICByaWNoX2NsYSA9IG5fZGlzdGluY3QoY2xhc3NuYW1lKSkKCiMgbWVyZ2UgdG8gc3RhdGlvbnMgdG8gZ2V0IGdlb21ldHJ5IGJhY2sgKHRoZSBhcHByb2FjaCBhYm92ZSB3YXMgZGlmZmVyZW50LCB3ZSBjcmVhdGVkIGNlbnRyb2lkcykKc3RhX2RpdiA8LSBzdGF0aW9ucyAlPiUKICBzZWxlY3QoInNpZCIsIm5hbWUiLCAiem9uZSIpICU+JQogIG1lcmdlKC4sIGRpdl9sb3csIGJ5Lng9InNpZCIsIGJ5Lnk9ImlkIikKYGBgCgpgYGB7cn0KIyBwcmludCBzdW1tYXJ5IHRhYmxlOiBsb3dlc3QgZGl2ZXJzaXR5IGN5Y2xpbmcgbW9kZQpzdGFfZGl2CmBgYAoKYGBge3J9CnRtX3NoYXBlKGxpbmVzKSArCiAgdG1fbGluZXMobHdkPTAuMykgKwp0bV9zaGFwZSh0YWlsX2lzbykgKwogIHRtX3BvbHlnb25zKGNvbCA9ICJiZWlnZSIsCiAgICAgICAgICAgICBib3JkZXIubHdkID0gMC4zLAogICAgICAgICAgICAgYWxwaGEgPSAwLjgpICsKdG1fc2hhcGUocG9pX2xvdykgKwogIHRtX2RvdHMoY29sID0gImdyb3VwbmFtZSIsCiAgICAgICAgICBwYWxldHRlID0gZ19jb2wsCiAgICAgICAgICAgICBzaXplID0gMC4yLAogICAgICAgICAgICAgYWxwaGEgPSAwLjgsCiAgICAgICAgICAgICBib3JkZXIubHdkID0gMC4zLAogICAgICAgICAgICAgdGl0bGU9Ikdyb3VwIikgKwp0bV9zaGFwZSh3X2lzb19sb3cpICsKICB0bV9wb2x5Z29ucyhjb2wgPSAiYmVpZ2UiLAogICAgICAgICAgICAgYm9yZGVyLmx3ZCA9IDAuMywKICAgICAgICAgICAgIGJvcmRlci5jb2wgPSAidG9tYXRvIiwKICAgICAgICAgICAgIGFscGhhID0gMC4xKSArCnRtX2ZhY2V0cyhieT0ic19uYW1lIiwgbnJvdyA9IDEpICsKICB0bV9sYXlvdXQodGl0bGUgPSAiIiwgZnJhbWU9RkFMU0UsIHBhbmVsLmxhYmVsLmJnLmNvbG9yID0gJ3doaXRlJywgbWFpbi50aXRsZSA9ICJMb3dlciBkaXZlcnNpdHkgYWNjb3JkaW5nIHRvICdjbGFzc2VzJyB0eXBlXG5XYWxraW5nIGFuZCBDeWNsaW5nIDEwLW1pbnV0ZXMgc2VydmljZSBhcmVhIGRlZmluaXRpb25zIiwgbWFpbi50aXRsZS5zaXplID0gMC44LCBsZWdlbmQub3V0c2lkZT1UUlVFLCBsZWdlbmQub3V0c2lkZS5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQub3V0c2lkZS5zaXplPTAuMjUpICsKICB0bV9sZWdlbmQoc2hvdyA9VCkKYGBgCgpUaGUgMTAtbWludXRlcyBjeWNsaW5nIHNlcnZpY2UgYXJlYSBvZiAqKkNvb21iZSBMYW5lKiogaGFzIGEgUE9JIGRpdmVyc2l0eSByaWNobmVzcyBvZiAyMDQgYWNjb3JkaW5nIHRvIGRpc3RpbmN0IGNsYXNzZXMgd2hpY2ggaXMgaW4gc29tZSB3YXkgY29tcGFyYWJsZSB0byB0aGUgMTAtbWludXRlcyB3YWxraW5nIHNlcnZpY2UgYXJlYSBvZiBBcmNod2F5LCB3aGljaCBoYXMgYSByaWNobmVzcyBvZiAxNzUuIEhvd2V2ZXIsIGZ1cnRoZXIgcXVlc3Rpb25zIHJlbWFpbiBhYm91dCBvdGhlciB2YXJpYWJsZXMgbm90IGNvbnNpZGVyZWQgaW4gdGhpcyBhbmFseXNpcyB0aGF0IGNoYXJhY3RlcmlzZSBhIDE1LW1pbnV0ZSBjaXR5LCBzdWNoIGFzIHRoZSBxdWFsaXR5IG9mIHRoZSBzdHJlZXQgZW52aXJvbm1lbnQgb3IgdGhlIGhvdXNpbmcgYW5kIGRlbW9ncmFwaGljIGRpdmVyc2l0eSwgYW1vbmcgb3RoZXJzLiAKCiMgRmluYWwgY29tbWVudHMKCiogV2UgdXNlZCAqKnNlcnZpY2UgYXJlYSBhbmFseXNpcyoqIHRvIGNyZWF0ZSBhIG5ldyBnZW9ncmFwaGljIGFyZWEgZGVmaW5pdGlvbiB0byBwZXJmb3JtIGEgY29tcGFyYXRpdmUgYW5hbHlzaXMgb2YgdGhlIG51bWJlciBhbmQgZGl2ZXJzaXR5IG9mIHVyYmFuIGZhY2lsaXRpZXMgc3Vycm91bmRpbmcgdHJhaW4gc3RhdGlvbnMuCgoqIEZvciB3aGF0IG90aGVyIGFwcGxpY2F0aW9ucyBjb3VsZCB0aGlzIHJlc2VhcmNoIG1ldGhvZCBjb3VsZCBiZSB1c2VmdWwgZm9yPyBGb3IgZXhhbXBsZSwgaW5zdGVhZCBvZiB0cmFpbiBzdGF0aW9ucyB0aGUgY2VudHJlIHBvaW50cyBjb3VsZCBiZSBzY2hvb2xzIHRvIGludmVzdGlnYXRlIHRoZSBraW5kIG9mIHVyYmFuIGZhY2lsaXRpZXMgc3R1ZGVudHMgaGF2ZSBhY2Nlc3MgdG8uCgoqIFdlIHVzZWQgYSBsaWNlbnNlZCBoaWdoIHF1YWxpdHkgZGF0YSBzZXQgb2YgUG9pbnQgb2YgSW50ZXJlc3QgYXZhaWxhYmxlIGZvciB0aGUgdGhlIHdob2xlIG9mIHRoZSBVSy4gSG93ZXZlciwgYSBzaW1pbGFyIGFuYWx5c2lzIGNvdWxkIGJlIHJlcGxpY2F0ZWQgZWxzZXdoZXJlIHVzaW5nIE9wZW5TdHJlZXRNYXAgZGF0YSAoZS5nLiBleGFtaW5pbmcgIFthbWVuaXR5XShodHRwczovL3dpa2kub3BlbnN0cmVldG1hcC5vcmcvd2lraS9LZXk6YW1lbml0eSkgYW5kIFtzaG9wXShodHRwczovL3dpa2kub3BlbnN0cmVldG1hcC5vcmcvd2lraS9LZXk6c2hvcCkgZmVhdHVyZXMpLgoKKiBXZSBvbmx5IGNvbnNpZGVyZWQgb25lIHZhcmlhYmxlIHRvIGludmVzdGlnYXRlIHRoZSBjb25jZXB0IG9mIDE1LW1pbnV0ZSBjaXRpZXMsIGhvd2V2ZXIsIGl0IHdvdWxkIGhhdmUgYmVlbiBpbnRlcmVzdGluZyB0byBpbmNvcnBvcmF0ZSBvdGhlciB2YXJpYWJsZXMgbW9yZSBkaXJlY3RseSByZWxhdGVkIHRvIHF1YW50aWZ5aW5nIHRoZSBjb3N0IG9mIHRyaXBzIHVzaW5nIGFjdGl2ZSB0cmF2ZWwgbW9kZXMuIAoKKiBXaGlsZSB3ZSB1c2VkIHRoZSBnZW9ncmFwaHkgb2YgdGhlIHN0cmVldCBuZXR3b3JrIHRvIGRlZmluZSB0aGUgc3R1ZHkgYXJlYXMsIHRoZXJlIHdhcyBubyBxdWFudGlmaWNhdGlvbiBvZiB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBzdHJlZXQgZW52aXJvbm1lbnQuIFRoZXJlIGFyZSBwbGVudHkgb2YgZGF0YSBzZXRzIHRoYXQgY291bGQgY29udHJpYnV0ZSB0byBleHBhbmQgdGhpcyBhbmFseXNpcywgc3VjaCBhcyBzdHJlZXQgZ3JlZW5lcnksIHN0cmVldCBoaWVyYXJjaHksIGN5Y2xlIGxhbmVzIGFuZCBzdHJlZXRzcGFjZSBhbGxvY2F0aW9uLgoKIyBGZWVkYmFjawoKSWYgeW91IGhhdmUgYW55IGZlZWRiYWNrIG9yIGNvbW1lbnRzIHBsZWFzZSBmZWVsIGZyZWUgdG8gY29udGFjdCBtZSBhdCBAbnBhbG9taW4gb3Igbi5wYWxvbWlub3MuMTZAdWNsLmFjLnVrCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CgpoMSwgaDIsIGgzIHsKICBjb2xvcjogIzIzNzA3MDsgCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiCn0KCmJvZHkgewogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIgp9CgphIHsKICBjb2xvcjogIzIzNzA3MDsgCn0KCi5pbnZlcnNlIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjMjM3MDcwOyAKCn0KCi5saXN0LWdyb3VwLWl0ZW0uYWN0aXZlLCAubGlzdC1ncm91cC1pdGVtLmFjdGl2ZTpmb2N1cywgLmxpc3QtZ3JvdXAtaXRlbS5hY3RpdmU6aG92ZXIgewogICAgei1pbmRleDogMjsKICAgIGNvbG9yOiAjZmZmOwogICAgYmFja2dyb3VuZC1jb2xvcjogIzIzNzA3MDsKICAgIGJvcmRlci1jb2xvcjogIzIzNzA3MDsKfQpgYGAK