1 Preface

Mobile phones have revolutionized the way we communicate with each other and how we lead our daily lives. In particular smart phones introduce new usage ideas everyday, many of them relying on simple sensors in the phone. The GPS sensor for example can locate the phone whenever it has sufficient signal and apps provide their users with detailed location histories (if the user allows for this data collection). Using this kind of data to estimate how many people are at a certain location at a given time could be very informative, however, it requires for research to have the consent of all people - leading most likely to biased estimations for different reasons. A more effective way and privacy-securing way is the usage of Mobile Network Operator (MNO) data. Here MNO provider (e.g. Telecom, Vodafone,…) gives access to the their radio cell network and the numbers of phones logged to every cell/antenna. This means a chosen data analyst would not need access to detailed and highly personal location data but only receives a dataset containig the location of cells, their estimated coverage range and the number of phones logged to the respective antenna at a certain moment. EUROSTAT and the European National Statistical Institutes are experimenting with the potential usage and especially necessary methods and workflows for implementing such a data source into the general production of Official Statistics. Knowing when and where how many people are approximately corresponds to the statistical indicator called present population or de facto population. While the resident population takes into consideration only the individuals who permanently reside in a certain geographical area, the present population “is composed by all individuals who are physically present in the geographic area of interest at a selected reference time” [1].

EUROSTAT has organized in 2020 for the first time the EUROSTAT Coding Lab, offering EMOS students a chance in getting to know the production of Official Statistics on the European level with a particular focus on coding. This particular Coding Lab introduced the concepts of using MNO data for estimating present population statistics.

Thanks to this project and our mentors, we - a group of 4 international students from all over Europe - had the opportunity to dig deeper into the world of spatial analysis as well as simulation studies in R. Throughout this notebook, we faced multiple challenges: Developing code in a team, applying (almost) Big Data methods and concepts such as parallizing code, developing modular and fully reproducible code, or just working together from 4 different countries in times of Covid-19.

The notebook at hand relies on multiple scripts that follow a methodological chain. They are conceptualized and written in a modular fashion, making further use of the code for different parameters very easy. Many solutiones need to run for quite a while therefore certain objects are pre-built and only loaded into the notebook.

Our concrete research goal is to evaluate and compare different cutting edge estimation techniques of present population with MNO data. Because MNO data, even though aggregated, is very secure, we did not work with real data. Instead we needed to completely build our own toy world, aiming at a very realistic scenario which could be the base of our evaluation. This simulation setting gives us the unique opportunity to actually test the performance of different estimators because we are in control of the true values. The notebook is structured as follows: In the next section we introduce the generation of the toy world, consisting of a geographical area with a mobile phone population and a corresponding radio cell network. We mention most important features and parameters as well as explain how mobile phones are logged to radio cells (device-to-cell association). Following this we introduce two of the currently existing estimation strategies, explain their most important characteristics and assumptions and apply them to our toy world. In the final section we undertake a detailed evaluation of each estimator, focusing on statistical as well as geographical-distributional performance measures. We end this evaluation with further exploring the convergence behavior of one of the estimators and formulating further potential research goals in this area.

2 Toy world generation

Our toy world bases on population census data from the German Federal Statistical Office [2] (https://www.destatis.de/EN/Home/_node.html). This data entails continous population counts on a 100m * 100m grid. For our project we reduce the population count to a third to mimic the process of receiving data from an MNO provider - therefore we assume that the population count resembles the number of mobile phones in this area. For computational reasons, this version will only focus on a subset of the tiles located in the state of Bavaria, which is situated in the south-east of Germany. We chose this area because it comprises a high diversity of urban, suburban, and rural areas.

Terminology used in this project: Due to various definitions out there, it is imperial to define the different terminologies used in this project before going further to reduce unnecessary confusion. - When we talk about tiles, we mean any square on the regular 100 * 100 m2 grid. - An antenna is a device facilitating between radio transmission and reception. Specifically in our case, an antenna transmits and receives cell phone signals. This is also known as a cell. - A (radio) tower or commonly referred to as a cell tower, cellular site, or cellular base station is a tower equipped with antennas.

# change accordingly
knitr::opts_knit$set(root.dir = normalizePath("C:/Users/Marco/")) 
knitr::opts_chunk$set(fig.width = 9)
knitr::opts_knit$set(eval.after = "fig.cap")
library(tidyverse)
library(sf)
library(raster)
library(Matrix)
library(knitr)
library(kableExtra)
library(ggthemes)
library(cowplot)
library(transformr)
library(gganimate)
set.seed(762)

census.de.100m.tile <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/census.tile.final.rds") 
# Bounding box of focus area
bb.focus.dat <- data.frame(xmin = 4400000, xmax = 4500000,
                           ymin = 2700000, ymax = 2900000)
bb.focus.vec <- c(xmin = 4400000, xmax = 4500000,
                  ymin = 2700000, ymax = 2900000)
# Download data from : https://gadm.org/download_country_v3.html --> R(sf) level 1
germany.raw <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/gadm36_DEU_1_sf.rds") 
germany <- germany.raw %>%  
  st_transform(crs = 3035)
focus.area.plot <- germany %>%  
  ggplot() + 
  geom_sf() + 
  geom_rect(data = bb.focus.dat, aes(ymin = ymin, ymax = ymax,  
                                      xmin = xmin, xmax = xmax,  
                                     color = "red"),  
            size = 1, fill = "transparent") + 
  ggtitle("") + 
  scale_color_identity(name = "", 
                       labels = c("Focus area"), 
                       guide = "legend") +
  labs(x = NULL, y = NULL,
       title = "")
 
plot_grid(focus.area.plot, 
          labels = "Fig.1: Focusing on a part of South Bavaria",
          hjust = -0.1, label_size = 13)
We will only focus on a subset of the tiles located in the state of Bavaria because it comprises both urban, suburban, and rural areas

(#fig:focus area)We will only focus on a subset of the tiles located in the state of Bavaria because it comprises both urban, suburban, and rural areas

As mentioned above this area is very heterogeneous in urban-rural intensity. Knowing the location of urban centers is very important for the corresponding radio cell network as there are differences in cell coverage between these different area kinds. We are aiming at developing a 3-category classification for each tile: Rural, Suburban and Urban. Based on the census data on the tile level we cannot locate urban centers just yet. Classifying tiles on such a low spatial resolution into one of these categories independent from each other (i.e. based on their population numbers) would not lead to the true location of urban centers. Therefore we apply a spatial clustering algorithm to account for the spatial dependence. The plots below present our classification results:

tile.prop.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/tile.prop.plot.rds")

cluster.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/cluster.plot.rds")


plot_grid(cluster.plot, tile.prop.plot, labels = "Fig.2 : Population Classification",  
            hjust = -0.1, label_size = 14, rel_widths = c(0.8, 1)) 
Figure 2a shows the classification results from the clustering algorithm and the proportion of people in the area categories.While Figure 2b shows the distribution of the four different categories of tiles obtained throught spatial clustering.

(#fig:pop distribution 1)Figure 2a shows the classification results from the clustering algorithm and the proportion of people in the area categories.While Figure 2b shows the distribution of the four different categories of tiles obtained throught spatial clustering.

Figure 2 shows the classification results from the clustering algorithm and the proportion of people in the area categories. We aimed at having 4 different categories: Uninhabited, Rural, Suburban and Urban. When working at this low spatial resolution, it is discouraged to classify tiles independently based on their respective population value - one needs to take spatial dependence into consideration in order to identify urban centers. Therefore, we apply a spatial clustering method, mainly for identifying the last two categories. In order to run the clustering algorithm, the original census population is first divided into tiles above and below 15 peopl.e per tile. Tiles below 15 are either classified as Uninhabited or Rural, from the start (uninhabited corresponds to the tiles with 0 population). The clustering is then done on the tiles that are above 15 people per tile. Based on the results of the clustering, we define urban areas as clusters that have an agglomeration of more than 100 tiles. Suburban areas are defined as clusters that have more than 50 and less than or equal to 100 tiles. The remaining clusters are considered as Rural areas and therefore result in the same classification as the tiles from above, which had less than 15 people.

The stacked bar plot shows the proportions of the tiles according to the four categories. Based on our clustering algorithm, 2.47% of the tiles are urban areas. 6.9% of the tiles are uninhabited areas. 90.63% of the tiles are suburban areas, and NA% of the tiles are rural areas.

true.geo.eval.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/true.pop_map.rds")

ECCDF.true <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/ECCDF.true.rds")

ECDF.true <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/ECDF.true.rds")

 
ECCDF.pop.plot <- ECCDF.true +
  geom_hline(yintercept = -0.3010300, linetype = "dotted") + 
  geom_hline(yintercept = -1, linetype = "dotted") + 
  geom_text(x = 1.5, y = -0.2, label = "50% of the data") + 
  geom_text(x = 1.5, y = -0.9, label = "90% of the data") + 
  labs(y = "log10(Prob(Y > x))", x = "log10(Mobile phones)",  
        colour = "") + 
  ylim(-7, 0) +
  theme(legend.position = "bottom") 
 
ECDF.pop.plot <- ECDF.true +
  xlim(0, 30) +
  labs(y = "", x = "")

pop.dist.ecdf.insert <- ECCDF.pop.plot +
  annotation_custom(ggplotGrob(ECDF.pop.plot), 
                    xmin = 0, xmax = 1.5, 
                    ymin = -7, ymax = -3)
## Warning: Removed 416 rows containing missing values (geom_point).
plot_grid(true.geo.eval.plot, pop.dist.ecdf.insert, labels = "Fig. 3: Mobile phone density per tile",  
          hjust = -0.1, label_size = 14, rel_widths = c(0.8, 1))
## Warning: Removed 1 rows containing missing values (geom_point).
The Figure 3a shows the geographical distribution of the tiles classified thought the clustering algorithm of the population. In Figure 3b there is rapresented  the logarithm of ECCDF of the population data and the graph inside the figure 3b is the linear ECCDF.

(#fig:pop distribution 2)The Figure 3a shows the geographical distribution of the tiles classified thought the clustering algorithm of the population. In Figure 3b there is rapresented the logarithm of ECCDF of the population data and the graph inside the figure 3b is the linear ECCDF.

Figure 3 shows the mobile phone density per tile in the focus area. In particular, we have 4 different colors representing the clusters: Uninhabited, Rural, Suburban and Urban.

However, to have a deeper look of the mobile phone density per tile, we choose to represent the data with an empirical cumulative complementary distribution function (ECCDF) (using a log base 10 transformation).

The ECCDF is a step function with jumps i/n at observation values, where i is the number of tied observations at that value. Moreover, missing values are ignored and the objective “complementary” means that we need to subtract 1 - the cumulative probability. It is commonly used with variables that have a highly skewed distribution. We can see that this is the case - the population on this low spatial resolution is heavily right skewed.

As the figure suggests, 50% of the data are represented by uninhabited tiles with no phones; furthermore, 90% of the tiles contain less than half of the mobile phones in our focus area. One can also see the tiles’ classification based on the clustering results. Some tiles classified as Rural have higher values for their mobile phone population - this is because they are not considered as an Urban or Suburban cluster, as mentioned above. 10% left are tiles both urban and rural containing 0.5 and above mobile phones.

2.1 Generation of a synthetic Radio Network

We generate a radio network, which is composed of three layers. The layers follow the pop.area.kind variable - layer 1 (Rural) spans over the rural, suburban and urban tiles, layer 2 (Suburban) spans over the suburban and urban tiles and layer 3 (Urban) is spanned over the urban tiles.

Important features and parameters of the generated radio network are:

  • The layers follow a hexagon shape with cell towers located in the respective centroid of each hexagon

  • Towers vary in distance to each other of the same layer, i.e. how far/close are towers of the same layer located to each other: layer 1 = 27,000m; layer 2 = 7000m; layer 3 = 900m (-> the more urbanized, the closer the towers are too each other -> denser coverage). Furthermore, hexagon independent rotation in terms of the first layer is executed: layer 2 = 35 degrees; layer 3 = 70 degrees

  • Each cell tower location is jittered in order to break the symmetry. The jitter amount depends on the layer: layer 1 = 5000m, layer 2 = 1000m, layer 3 = 400m.

  • Each tower contains three antennas pointing into 120 degree differing directions.

  • The layer determines the coverage diameter of an antenna: layer 1 = 15,000m; layer 2 = 2500m; layer 3 = 500m

  • Each tile of the focus area is sufficiently covered by at least one antenna and the antennas’ coverage areas are allowed to overlap.

  • Parameters concerning the device to cell association are specified in the next section

The link to the source code for the layers.1 object as well as the coverage.areas.1 object is here.

The link to the source code for the layers object as well as the coverage.areas object is [here] (https://github.com/R-ramljak/MNO_Eurostat/blob/master/code/2_Radio%20cell%20generation.R).

layers <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/radio cell layers.rds") 
coverage.areas <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/coverage.areas.rds") 
 
coverage.layer1 <- coverage.areas %>%  
  filter(area.kind == "Rural") %>%  
  st_drop_geometry() %>%  
  dplyr::select(-antenna.centroid) %>%  
  st_as_sf(coords = c("X.tow", "Y.tow"), crs = 3035) 
 
layers.plot <- layers[[1]] %>% 
  st_as_sf(crs = 3035) %>%  
  ggplot() + 
    # geom_rect(data = bb.focus.dat, aes(ymin = ymin, ymax = ymax,  
    #                                   xmin = xmin, xmax = xmax),  
    #         color = "black", size = 0.3, alpha = 0.5, fill = alpha("grey", 0)) + 
  geom_sf(linetype = "dotted") + 
  geom_sf(data = coverage.layer1, aes(color = "#4273C5"), shape = 17) + 
  scale_color_identity(name = "", 
                       # breaks = c("Focus area"), 
                       labels = c("Jittered tower location"), 
                       guide = "legend") + 
  labs(x = NULL, y = NULL,
       title = "",
    subtitle = "Towers are located in the centroid of a hexagon.") +
  theme(plot.title = element_text(size=10, face="bold", hjust = 0.5),
  plot.subtitle = element_text(size=9,hjust = 0.5))
   
plot_grid(layers.plot,
          labels = "Fig. 4:Radio network - Example Layer 1 (Rural)",
          hjust = -0.1, label_size = 14)
The figure presents the hexagonal structure. Each triangle is a tower location with some randomness implemented.

(#fig:network layers)The figure presents the hexagonal structure. Each triangle is a tower location with some randomness implemented.

We use a hexagonal structure to place towers across our focus area. This is a quite realistic setup for cell towers. Each hexagon corresponds to one tower which is originally placed in the centroid of the respective hexagon. In order to exclude symmetrical structure, we implement some randomness in the exact location of the cell towers. Figure 3 exemplifies the effect of the jitter parameter in the 1st layer - the actual location deviates slightly from the centroid in order to break the symmetry of the underlying hexagonal structure. This is done for every layer.

The setup of a tower with its corresponding antennas is in every layer the same: Three antennas per tower, pointing into 120 degree differing directions. The animated visualization exemplifies this for any generic tower.

knitr::include_graphics("https://raw.githubusercontent.com/R-ramljak/MNO_Eurostat/master/Gifs/antenna%20animation.gif")

Basically, a tower is generated at its specified location, then three antennas are created. For the operationalized data structure, the antenna location is not really relevant as it corresponds to the respective tower location. What is more important are the antennas’ coverage area centroids because they describe the middle point of the then generated circular coverage area. The specific radius of any generic coverage area is layer specific and listed above. As indicated in the animation, an antenna specific coverage area is setup with a variable coverage intensity profile. Basically, cell phones that are closer to the coverage area centroid of any antenna, have a higher coverage probability, which will be later introduced as the signal strength parameter.

The following table presents the number of towers and the number of antennas of each layer. The number of antennas is not always a perfect factor of 3 as the coverage areas are cropped according to the focus area. This means if the complete coverage area of an antenna lies outside of the focus area it is discarded.

tile.count <- census.de.100m.tile %>%  
  st_drop_geometry() %>% 
  group_by(pop.area.kind) %>%  
  summarise(area.in.sq.km = n() / 100) %>% 
  arrange(desc(pop.area.kind)) %>% 
  mutate(area.in.sq.km = case_when(pop.area.kind == "Rural" ~ cumsum(area.in.sq.km),
                                   pop.area.kind == "Suburban" ~ cumsum(area.in.sq.km),
                                   pop.area.kind == "Urban" ~ cumsum(area.in.sq.km))) %>% 
  arrange(pop.area.kind)
## `summarise()` ungrouping output (override with `.groups` argument)
coverage.areas %>%  
  st_drop_geometry() %>%  
  group_by(area.kind, tower.ID) %>%  
  summarise(n.antenna = n(), .groups = "drop") %>%  
  ungroup() %>%  
  group_by(area.kind) %>%  
  summarise(n.tower = n(), 
            n.antenna = sum(n.antenna), .groups = "drop") %>%  
  left_join(tile.count, by = c("area.kind" = "pop.area.kind")) %>%  
  dplyr::select(layer = area.kind, n.tower, n.antenna, area.in.sq.km) %>%  
  kbl(caption = "Descriptive statistics per coverage layer") %>%
  kable_minimal() %>%
  footnote(general = "`area.in.sq.km` reports the actual area that was used for the generation of the coverage. Therefore, the first layer spans over the whole focus area, the second layer over the suburban and urban area, and the third layer over the urban area.")
(#tab:coverage areas 1)Descriptive statistics per coverage layer
layer n.tower n.antenna area.in.sq.km
Rural 119 334 18283.14
Suburban 220 659 1712.80
Urban 950 2848 451.94
Note:
area.in.sq.km reports the actual area that was used for the generation of the coverage. Therefore, the first layer spans over the whole focus area, the second layer over the suburban and urban area, and the third layer over the urban area.

As described in the parameter list above, rural areas are covered only by layer 1, suburban areas are covered by layer 1 and 2 and the urbanized areas are covered by all three layers. The average distance between multiple towers of the same layer decrease in layer 2 and layer 3 compared to layer 1. This leads to denser networks within these layers represented by the higher numbers of towers and therefore higher numbers of antennas in layer 2 and 3, given their area. The reason for this is that any generic antenna can only offer signal service to a limited amount of number of mobile phones. To cover all cell phones in more urbanized areas a denser radio cell network is needed in these areas.

The following figures present the actual coverage of each layer for the focus area.

coverage.area.plot <- coverage.areas %>%  
  ggplot() + 
  geom_sf(aes(col = area.kind), fill = NA) + 
  facet_grid(cols = vars(area.kind)) + 
  ggtitle("") + 
    scale_color_ptol(breaks = c("Rural", "Suburban", "Urban"), "Layer") +
  labs(x = NULL, y = NULL) +
  theme(axis.text.x=element_text(angle=90, hjust=1),plot.title = element_text(size = 10, face = "bold", hjust = 0.5),
  plot.subtitle = element_text(size = 9, hjust = 0.5))

plot_grid(coverage.area.plot, labels = "Fig. 5: Coverage per layer",
          hjust = -0.1, label_size = 14) 
The circles represent the coverage area of each antenna per layer. The signal density increases with increasing population density.

(#fig:coverage areas 2)The circles represent the coverage area of each antenna per layer. The signal density increases with increasing population density.

The interpretations of the table above correspond to the level of coverage of each layer. It should be noticed that the antennas’ coverage areas are allowed to overlap - with antennas of the same tower, as well as across towers of the same or another layer.

# Implement shape of focus area
coverage.area.full.plot <- coverage.areas %>% 
  ggplot() +
  geom_sf(aes(col = area.kind), fill = NA) +
  ggtitle("", subtitle = "Full coverage") +
    scale_color_ptol(breaks = c("Rural", "Suburban", "Urban"), "Layer") +
  theme(axis.text.x=element_text(angle=90, hjust=1),
        plot.title = element_text(size = 10, face = "bold", hjust = 0.5),
  plot.subtitle = element_text(size = 9, hjust = 0.5))

plot_grid(true.geo.eval.plot, coverage.area.full.plot, labels = "Fig. 6: Full coverage corresponding to the density", 
          hjust = -0.1, label_size = 14)
The figure on the left shows the geographical distribution of the tiles classified into the three layers based on the spatial clustering. On the right side, the coverage per layer is represented. The full coverage corresponds to the population density.

(#fig:coverage areas 3)The figure on the left shows the geographical distribution of the tiles classified into the three layers based on the spatial clustering. On the right side, the coverage per layer is represented. The full coverage corresponds to the population density.

Figure 6 presents the full network structure. By comparing the network structure to the tile density one can see that full, partially overlapping coverage is granted for all areas and that the network layering structure follows suit with the true geographical population density.

tiles.cat <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/coverage intensity.rds")
coverage.intensity <- tiles.cat %>%
  # left_join(census.de.100m.tile, by = "internal.id") %>% 
  # dplyr::select(internal.id, count, pop.area.kind) %>% 
  arrange(count) %>%
  mutate(prob = 1 / n()) %>%
  mutate(cum.prob = cumsum(prob))

coverage.intensity.plot <- coverage.intensity %>%
  ggplot() +
  stat_count(aes(count), fill = "#4477A9") +
  geom_vline(xintercept = mean(coverage.intensity$count), linetype = "solid", color = "#117733", size = 1.5) +
  geom_vline(xintercept = median(coverage.intensity$count), linetype = "solid", color = "#CC6677", size = 1.5) +
  annotate("text", x = median(coverage.intensity$count) - 2, y = 5e+05, color = "#CC6677",
           label = paste("Median =", median(coverage.intensity$count))) +
  annotate("text", x = round(mean(coverage.intensity$count), 2) + 2, y = 5e+05, color = "#117733", 
           label = paste("Mean =", round(mean(coverage.intensity$count), 2))) +
  labs(y = "Count of tiles", x = "Covered by # antennas", colour = "", title = "")
  # facet_grid(~pop.area.kind)
  
  
plot_grid(coverage.intensity.plot, labels = "Fig. 7: Number of antennas covering a tile",
          hjust = -0.1, label_size = 14)
The distribution is right skewed with a mean of 5.62, a minimum of 1, and a maximum of 21 antenna(s) per tile.

(#fig:coverage intensity)The distribution is right skewed with a mean of 5.62, a minimum of 1, and a maximum of 21 antenna(s) per tile.

Figure 7 shows a histogram representing the number of antennas per tile. The distribution is right skewed with a mean of 5.62, a minimum of 1 and a maximum of 21 antenna(s) per tile. Even though the coverage areas were generated synthetically, this distribution mimics a realistic layout.

2.2 Device-to-cell association

At this stage we have added to the geographically distributed mobile phone population a radio network, which is setup in three layers, spanning respectively across tiles that correspond to specific tile classification. (pop.area.kind).

The following module will establish the association between mobile phones of a generic tile to a relevant antenna. The result will be a reference matrix \(P\) of size \(I x J\), where I denotes the total number of radio cells (antennas), \(J\) is the total number of tiles and the elements correspond to the probability of the mobile phones of any tile \(j\) are registered in the cell \(i\). With \(P\) one is able to simulate the column vector \(c\) (random variable) which describes the total count of mobile phone associated to a radio cell.

Assuming that \(\mathcal{L}_{j}\) denotes the subset of radio cells covering a particular tile (remember, overlapping coverage areas are very common). This means that these respective radio cells are competing with each other to be associated with the cell phones in the tile. We therefore assign probabilities which describe the respective association between a radio cell \(i\) and tile \(j\). This probability depends on the parameter signal strength which we mimic with a simple linear function that describes the gradual decrease in signal the further away the tile centroid \(j\) is from the coverage area centroid of \(i\):

\[ s_{ij} = \frac{d_{ij}}{r_{i}} \]

We basically calculate the distance between the two centroids, \(d_{ij}\), and divide it between the radius of that radio cell, \(r_{i}\)- it is denoted by \(s_{ij}\). We introduce a minimum threshold value \(\nu\) which limits radio cells with a too low signal intensity \(s_{ij}\) for a particular tile to be able to be picked up by a mobile phone in that tile - resulting in the minimum value of 0. We also introduce a maximum threshold, describing tiles that are very close to the coverage area centroid, i.e. a high value for \(s_{ij}\) – when passing this threshold their respective \(s_{ij}\) values result in the maximum value 1. This particular operationalization of a function modeling the signal strength parameter instead of fixed categorical signal strength values makes the overall workflow of the notebook more realistic (granularity) and more modular as one can later implement very easy even more realistic functions describing the signal strength parameter. In this scenario we have implemented a minimum threshold of \(\nu = 0.01\) and a maximum threshold of \(\zeta = 0.01\) depending on \(r_{i}\). The exact operationalization can be found here.

The elements of \(P\) - the probability with which the mobile phones within a particular cell are associated with a particular radio cell - are defined by

\[ p_{ij} = \frac{s_{ij}}{\sum_{i \in \mathcal{L}_{j}} s_{ij}} \]

where \(s_{ij}\) describes the signal intensity of a particular cell \(i\) associated with a particular tile \(j\), and \(\mathcal{L}_{j}\) describes the subset of radio cells that are covering the tile \(j\). We then simulate the tile specific experiments - every mobile phone within a tile will be independently assigned to relevant radio cell with the probability \(p_{ij}\). The result is the column vector \(c\) which will act as a reference for the later on introduced estimation strategies.

signal.strength.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Plots/signal.strength.dist.plot.rds")

C.vec.df <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/C.vec.df.final.new.rds")
# ECCDF of population distribution 
ECCDF.phones.data <- C.vec.df %>% 
  mutate(layer = case_when(str_detect(antenna.ID, "RT") ~ "Layer 1",
                           str_detect(antenna.ID, "ST") ~ "Layer 2",
                           str_detect(antenna.ID, "UT") ~ "Layer 3")) %>% 
  arrange(phones.sum) %>%  
  mutate(prob = 1 / n()) %>%  
  mutate(cum.prob = cumsum(prob)) %>% 
  mutate(cum.prob.comp = 1 - cum.prob) %>% 
  mutate(log10.cum.prob.comp = log10(1 - cum.prob)) %>%  
  mutate(log10.phones = log10(phones.sum))

ECCDF.phones.plot <- ECCDF.phones.data %>%   
  ggplot() + 
  geom_point(aes(x = log10.phones, y = log10.cum.prob.comp, 
                 color = layer)) + 
  geom_hline(yintercept = -0.3010300, linetype = "dotted") + 
  geom_hline(yintercept = -1, linetype = "dotted") + 
  geom_text(x = 0.8, y = -0.2, label = "50% of the data") + 
  geom_text(x = 0.8, y = -0.9, label = "90% of the data") + 
  scale_color_ptol(breaks = c("Layer 1", "Layer 2", "Layer 3")) + 
  ylim(-4, 0) +
  ggtitle("", subtitle = "ECCDF and ECDF") +
  labs(y = "log10(Prob(Y > x))", x = "log10(Mobile phones)", colour = "")+
  theme(plot.title = element_text(size =10, face="bold", hjust = 0.5),
        plot.subtitle = element_text(size =9,hjust = 0.5))
ECDF.phones.plot <- ECCDF.phones.data %>%   
  ggplot() + 
  geom_point(aes(x = phones.sum, y = cum.prob.comp, color = layer)) + 
  scale_color_ptol(breaks = c("Uninhabitated", "Rural", "Suburban", "Urban"), guide = FALSE, expand = c(0, 0)) +
  labs(y = "", x = "") +
  xlim(0, 8000) +
  theme(plot.title = element_text(size = 10, face = "bold", hjust = 0.5),
        plot.subtitle = element_text(size = 9, hjust = 0.5),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())
pop.dist.ecdf.insert <- ECCDF.phones.plot +
  annotation_custom(ggplotGrob(ECDF.phones.plot), 
                    xmin = 0, xmax = 3, 
                    ymin = -4, ymax = -1.5)
    
plot_grid(signal.strength.plot, pop.dist.ecdf.insert, labels = "Device-to-cell association",  hjust = -0.1, label_size = 14)
## Warning: Removed 1 rows containing missing values (geom_point).
On the left one can see the synthetic distribution of the sij parameter depending on the network layer. The specified Path loss exponent controls sij in a way that it favors Layer 3 antennas and sanctions Layer 1 antennas in order to balance the resulting c.vector. On the right one can see that mobile devices are predominately associated with Layer 1 antennas.

(#fig:c.vector.distribution)On the left one can see the synthetic distribution of the sij parameter depending on the network layer. The specified Path loss exponent controls sij in a way that it favors Layer 3 antennas and sanctions Layer 1 antennas in order to balance the resulting c.vector. On the right one can see that mobile devices are predominately associated with Layer 1 antennas.

3 Estimation strategies

We have implemented two specific estimation strategies:

  • Voronoi tesselation (tower locations OR coverage area centroids as seeds)

  • MLE Poisson

All three of these estimation techniques produce a tile specific estimand. The sum of these estimands always exactly equals the sum of the c.vector, i.e. all registered mobile phones. This characteristic explains the strategy of all of these estimators: Taking the complete number of registered phones in the c.vector and allocating them across all the tiles. There is however a fundamental difference between the two estimators: The second one allows for the realistic setting of overlapping antenna coverage. As shown above there are many tiles that are covered by multiple antennas. Current research suggests that this can result in more accurate estimations.

3.1 Voronoi tesselation

Voronoi tesselation uses seeds to calculate Voronoi regions. For every seed there is one Voronoi region that contains the area that is closest to the particular seed. There are two seed specifications we are interested in:

  • Tower locations as seeds –> n = 1289

  • Coverage area centroid (per antenna) locations as seeds –> n = 3841

Below we specify the tower locations as seed points. These are then used to compute the Voronoi regions. Before we do that we need to make sure that the corresponding c.vector is aggregated on the toer level. We then join the Voronoi regions with the tiles to create an object that links tiles within respective Voronoi regions.

# Plot read in
VT.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/VT.plot.rds")
VA.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/VA.plot.rds")

plot_grid(VT.plot, VA.plot, labels = "Fig. 10: Voronoi tower estimation",  hjust = -0.1, label_size = 14)
The tower centroids were used as seeds for the creation of the Voronoi regions. The color scale is defined by the log with base 10 local density i.e. the absolute number of mobile phones within a Voronoi region divided by absolute area of the respecitve Voronoi region.

(#fig:voronoi antenna and tower prep plot)The tower centroids were used as seeds for the creation of the Voronoi regions. The color scale is defined by the log with base 10 local density i.e. the absolute number of mobile phones within a Voronoi region divided by absolute area of the respecitve Voronoi region.

We have now created the Voronoi regions for our focus area with tower locations as seeds as well as with antenna respective coverage area centroid locations as seeds. The number of seeds and Voronoi regions align with each other.

The spatial density per tile can be expressed as the ratio of the mobile phones in that region and the area of the Voronoi region:

\(d_{k} = \frac{\sum c_{i}} {A_{k}}\)

This region specific estimate corresponds to the tile estimate for a tile that is contained in this region. On the tile level there can be two cases that we need to differentiate:

  • Tiles that are completely contained within one Voronoi region

  • Tiles that intersect with two or more Vornoi regions

For the first case, the tile specific estimate corresponds to \(d_{k}\). For the second case we will calculate a weighted mean of the relevant Voronoi region estimates by using the corresponding tile area within each Voronoi region as weights.

VT.bird.example.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/VT.bird.example.plot.rds")

VT.example.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/working objects/VT.example.plot.rds") + theme(axis.text.x=element_text(angle = 90, hjust = 1))

plot_grid(VT.bird.example.plot, VT.example.plot, 
          labels = "Fig. 11: Example multiple tile",  hjust = -0.1, label_size = 14)
This is an example of a tile that intersects with multiple Voronoi regions. The labels and number correspond to the Voronoi region and the given area that are used as weights for the weighted mean estimator.

(#fig:Voronoi tower multiples)This is an example of a tile that intersects with multiple Voronoi regions. The labels and number correspond to the Voronoi region and the given area that are used as weights for the weighted mean estimator.

Here we visualize the second case with an example tile and example Voronoi regions from the Voronoi with tower locations as seeds. In the left plot we can see a small tile that is indicated in red. This tile is at the intersection of 4 Voronoi regions. The corresponding relative tile area intersecting with each Voronoi region can be seen in the right plot. The labels correspond to the Voronoi region ID and the below in brackets indicate the proportional weight that should be considered in calculting the tile specific weighted mean estimate. To compare this to the first case - where a tile is fully contained only in one region - the weight for the particular Voronoi region is 1. The same methodogolgy is pursued for the Voronoi antenna case.

3.2 MLE Poisson

MLE Poisson: \(\hat{u}^{m+1}_{j} = \hat{u}^{m}_{j}\sum_{i = 1}^{I} c_{i} \frac{p_{ij}}{\sum_{k = 1}^{J} p_{ik} \hat{u}^{m}_{k}}\)

4 Evaluation of all estimates

We created 4 final estimates:

  • Voronoi tesselation with tower locations as seeds

  • Voronoi tesselation with coverage area locations (antennas) as seeds

  • MLE uniform prior equal probability P.matrix after 1000 iterations

  • MLE uniform prior oracle probability P.matrix after 1000 iterations

In the following we compare the distributions of the final estimates to the true distribution of the mobile phone density per tile. Signficant variation can only be viewed in the tails of the dirstbution (ECCDF).

ECCDF.compare <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/ECCDF.estimates.rds")

ECDF.compare <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/ECDF.estimates.rds") +  xlim(0, 1000) +
  labs(y = "", x = "")

# # noch anpassen!!
# 
pop.dist.estimates.compare <- ECCDF.compare +
  annotation_custom(ggplotGrob(ECDF.compare),
                    xmin = 0, xmax = 1.5,
                    ymin = -6, ymax = -3)
## Warning: Removed 155 row(s) containing missing values (geom_path).
plot_grid(pop.dist.estimates.compare, 
          labels = "Estimator density comparison",  hjust = -0.1, label_size = 14)
## Warning: Removed 5 row(s) containing missing values (geom_path).
In this plot one can see the difference in ECCDF and ECDF of the final estimates of the differing strategies compared to the true mobile phone density.

(#fig:estimator pop dist compare)In this plot one can see the difference in ECCDF and ECDF of the final estimates of the differing strategies compared to the true mobile phone density.

In this section we want to further evaluate the 4 estimates by comparing them with different perspectives in mind to the actual true population. Each subsection defines the perspective-respective performance measure:

This section is still under construction. We will evaluate the estimators and their convergence behaviour from three perspectives:

  1. Geographical evaluation

  2. Statistical evaluation

4.1 Geographical Evaluation

For the geographical evaluation we use the following performance measure: The visual resemblance of fixed tile categories from the respective estimate and the actual true population on a map.

We basically build a map for every final estimate and compare it to the actual true population. We still need to interpret all of them.

true.geo.eval.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/true.pop_map.rds")

VT.geo.eval.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/VT.estimate_map.rds")


plot_grid(true.geo.eval.plot, VT.geo.eval.plot,
          labels = "Fig. 14 Comparing Voronoi tower estimate", label_size = 12,
          align = "hv", hjust = -0.1)

VA.geo.eval.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/VA.estimate_map.rds")

plot_grid(true.geo.eval.plot, VA.geo.eval.plot,
          labels = "Fig. 15 Comparing Voronoi antenna estimate", label_size = 12,
          align = "hv", hjust = -0.1)

# MLE.equal.geo.eval.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/MLE.oracle.estimate_map.rds")
# animate(MLE.equal.geo.eval.plot, fps = 10)

# plot_grid(true.geo.eval.plot, MLE.equal.geo.eval.plot,
#           labels = "Comparing MLE equal P.matrix estimate", label_size = 12,
#           align = "hv", hjust = -0.1)

knitr::include_graphics("https://raw.githubusercontent.com/R-ramljak/MNO_Eurostat/master/Gifs/MLE.equal.estimate_map_new.gif")

# MLE.true.geo.eval.plot <- readRDS("Vysoká škola ekonomická v Praze/Tony Wei Tse Hung - YAY/Estimates/Plot.files/MLE.oracle.estimate_map.rds")
# MLE.true.geo.eval.plot <- animate(MLE.true.geo.eval.plot, fps = 10)
# 
# 
# plot_grid(true.geo.eval.plot, MLE.true.geo.eval.plot,
#           labels = "Comparing MLE true P.matrix estimate", label_size = 12,
#           align = "hv", hjust = -0.1)

knitr::include_graphics("https://raw.githubusercontent.com/R-ramljak/MNO_Eurostat/master/Gifs/MLE.oracle.estimate_map_new.gif")

4.2 Statistical/Distributional Evaluation

In order to actually compare the numerical resemblance between the estimates and the actual true population we introduce two discrepancy performance measures.

  • Average Absolute Discrepancy: \(D_{avg}(u,v) = \frac{1}{U}\sum_{j = 1}^{J} |u_{j} - v_{j}|\)

  • Maximum Absolute Discrepancy: \(D_{max}(\textbf{u,v}) \overset{\underset{\mathrm{def}}{}}{=} \sum_{\mathit{j = 1}}^{\mathit{J}}\left | u_{j} - v_{j} \right |\)

aad.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/AADMAD/aad.comp.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "AAD")

mad.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/AADMAD/mad.comp.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "MAD")

plot_grid(aad.plot, mad.plot,
          labels = "Fig. 16 Voronoi Estimation vs MLE", 
          label_size = 12, align = "hv", hjust = -0.1) 

By calculating the two discrepancy measures, we can then evaluate the overall performance for each type of estimation. In general, the Voronoi estimates result in less discrepancy compared to both of the MLE estimates. Between the two MLE estimates, the true population matrix has a lower discrepancy than the equal population matrix. Between the two Voronoi estimates, the Voronoi estimation by antennas has a lower discrepancy than the Voronoi estimation by towers.

5 Excurse Evaluation: Looking deeper into the convergence behavior

In the course of our work we thought it was particularly interesting to further focus on the actual convergence behavior of the MLE-based estimators.

We will visualize the convergence behaviour/the evolution of the estimands up to 1000 iterations. This is executed based on a stratified sample (strata: three level pop.area.kind variable), n = 150)

5.1 Discrepancy measures per iteration

aad.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/AADMAD/equal.aad.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "AAD")

mad.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/AADMAD/equal.mad.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "MAD")

plot_grid(aad.plot, mad.plot,
          labels = "Fig. 17 Discrepancy Over Time, Equal Pop. Matrix", 
          label_size = 12, align = "hv", hjust = -0.1)

For the equal population matrix, the discrepancy values stabilizes as the number of iterations increases. More specifically, starting at the 700th iteration, the discrepancy values are largely the same.

aad.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/AADMAD/true.aad.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "AAD")

mad.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/AADMAD/true.mad.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "MAD")

plot_grid(aad.plot, mad.plot,
          labels = "Fig. 18 Discrepancy Over Time, True Pop. Matrix", 
          label_size = 12, align = "hv", hjust = -0.1)

For the true population matrix, the discrepancy values stabilizes as the number of iterations increases. More specifically, starting at the 300th iteration, the discrepancy values are largely the same.

5.2 Convergence behavior

equal.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/Estimation%20Plots/equal.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "Evolution")
equal.resid.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/Estimation%20Plots/equal.resid.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "Residual")

plot_grid(equal.plot, equal.resid.plot,
          labels = "Fig. 19 Convergence behaviour (Equal P.matrix)", 
          label_size = 12, hjust = -0.1) 
The left and right plots show a stratified sample (strata: area kind) and the tile specific estimatands' convergence behaviour. The convergence behaviour differs between area kinds. The right plot emphasizes that the true value is not necessarily reached.

(#fig:distributionl eval 1)The left and right plots show a stratified sample (strata: area kind) and the tile specific estimatands’ convergence behaviour. The convergence behaviour differs between area kinds. The right plot emphasizes that the true value is not necessarily reached.

The graphs above shows how the estimated population evolve over time (left) as well as its prediction error (right). From the graph on the left, most of the estimated population stabilizes rather quickly in rural and suburban tiles. With the urban tiles, it is harder to say exactly when the convergence will occur, especially there are a bit of variation. The residual plot (right) shows the error of prediction in comparison to the actual population in that specific tile. The rural tiles shows a trend of constant error of prediction over iterations. The suburban tiles generally shows the same trend as well, but also shows that there are tiles that overestimated. The urban tiles tend to have an underestimation.

true.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/Estimation%20Plots/true.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "Evolution")

true.resid.plot <- readRDS(url("https://github.com/R-ramljak/MNO_Eurostat/raw/master/Plots/Estimation%20Plots/true.resid.plot.rds", method = "libcurl")) + ggtitle("", subtitle = "Residual")

plot_grid(true.plot, true.resid.plot,
          labels = "Fig. 20 Convergence behaviour (True P.matrix)", 
          label_size = 12, align = "hv", hjust = -0.1) 
The left and right plots show a stratified sample (strata: area kind) and the tile specific estimatands' convergence behaviour (equal probability P.matrix). The convergence behaviour differs between area kinds. The right plot emphasizes that the true value is not necessarily reached.

(#fig:distributionl eval 2)The left and right plots show a stratified sample (strata: area kind) and the tile specific estimatands’ convergence behaviour (equal probability P.matrix). The convergence behaviour differs between area kinds. The right plot emphasizes that the true value is not necessarily reached.

Using the true population matrix, the estimated population stabilizes faster over time in comparison to the equal population matrix. However, there are a few tiles that do not stabilize as fast as we hoped. This is particularly evident in the urban tiles. The residual plot (right) shows the error of prediction over time by the type of tile. There seems to be a trend of increasing prediction error as the degree of urbanization increases as well. We can see that the range of error for suburban tiles range from 30 to -10 and the range of error for urban tiles are between 100 and -75. The suburban tiles seems to underestimate and the urban tiles seems to overestimate.

6 Final Remarks

Throughout this notebook we have first created the toy world, where we have generated semi-synthetic population data and a synthetic cell towers. After that, we then linked each person in the population to cell tower. We then estimated the population based on the cell-device association from the towers and then finally evaluated how well these estimation strategies perform in comparison with each other.

However, this is not the end of MNO. Rather this is the beginning of further explorations. There are still a lot more to discover. Topics such as the convergence behavior of MLE estimations or simulating an event based example such as people going on holiday where the towers would then be overloaded with users are all in the works. Other estimations should be used as well, such as the Earth Mover’s Distance or different evaluation metrics.

Up until now, we have found that the MLE estimations are not as accurate as the Voronoi estimations, but we believe this is only temporary. Further varied testing should be carried out to verify the different characteristics of each estimation strategy.

LS0tDQp0aXRsZTogRXN0aW1hdGluZyBwcmVzZW50IHBvcHVsYXRpb24gYmFzZWQgb24gTW9iaWxlIE5ldHdvcmsgT3BlcmF0b3IgZGF0YSAtIGEgc2ltdWxhdGlvbg0KICBzdHVkeQ0KYXV0aG9yOiAiU3RlZmFuaWEsIEdpdWxpYSwgVG9ueSwgTWFyY28iDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6DQogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfY2FwdGlvbjogeWVzDQprbml0OiAoZnVuY3Rpb24oaW5wdXRfZmlsZSwgZW5jb2RpbmcpIHsgb3V0X2RpciA8LSAnZG9jcyc7IHJtYXJrZG93bjo6cmVuZGVyKGlucHV0X2ZpbGUsDQogIGVuY29kaW5nPWVuY29kaW5nLCBvdXRwdXRfZmlsZT1maWxlLnBhdGgoZGlybmFtZShpbnB1dF9maWxlKSwgb3V0X2RpciwgJ2luZGV4Lmh0bWwnKSl9KQ0KLS0tDQo8c3R5bGU+DQpwLmNhcHRpb24gew0KICBmb250LXNpemU6IDAuOWVtOw0KICBjb2xvcjogZ3JheTsNCn0NCjwvc3R5bGU+DQoNCg0KIyBQcmVmYWNlDQpNb2JpbGUgcGhvbmVzIGhhdmUgcmV2b2x1dGlvbml6ZWQgdGhlIHdheSB3ZSBjb21tdW5pY2F0ZSB3aXRoIGVhY2ggb3RoZXIgYW5kIGhvdyB3ZSBsZWFkIG91ciBkYWlseSBsaXZlcy4gSW4gcGFydGljdWxhciBzbWFydCBwaG9uZXMgaW50cm9kdWNlIG5ldyB1c2FnZSBpZGVhcyBldmVyeWRheSwgbWFueSBvZiB0aGVtIHJlbHlpbmcgb24gc2ltcGxlIHNlbnNvcnMgaW4gdGhlIHBob25lLiBUaGUgR1BTIHNlbnNvciBmb3IgZXhhbXBsZSBjYW4gbG9jYXRlIHRoZSBwaG9uZSB3aGVuZXZlciBpdCBoYXMgc3VmZmljaWVudCBzaWduYWwgYW5kIGFwcHMgcHJvdmlkZSB0aGVpciB1c2VycyB3aXRoIGRldGFpbGVkIGxvY2F0aW9uIGhpc3RvcmllcyAoaWYgdGhlIHVzZXIgYWxsb3dzIGZvciB0aGlzIGRhdGEgY29sbGVjdGlvbikuIFVzaW5nIHRoaXMga2luZCBvZiBkYXRhIHRvIGVzdGltYXRlIGhvdyBtYW55IHBlb3BsZSBhcmUgYXQgYSBjZXJ0YWluIGxvY2F0aW9uIGF0IGEgZ2l2ZW4gdGltZSBjb3VsZCBiZSB2ZXJ5IGluZm9ybWF0aXZlLCBob3dldmVyLCBpdCByZXF1aXJlcyBmb3IgcmVzZWFyY2ggdG8gaGF2ZSB0aGUgY29uc2VudCBvZiBhbGwgcGVvcGxlIC0gbGVhZGluZyBtb3N0IGxpa2VseSB0byBiaWFzZWQgZXN0aW1hdGlvbnMgZm9yIGRpZmZlcmVudCByZWFzb25zLiBBIG1vcmUgZWZmZWN0aXZlIHdheSBhbmQgcHJpdmFjeS1zZWN1cmluZyB3YXkgaXMgdGhlIHVzYWdlIG9mIE1vYmlsZSBOZXR3b3JrIE9wZXJhdG9yIChNTk8pIGRhdGEuIEhlcmUgTU5PIHByb3ZpZGVyIChlLmcuIFRlbGVjb20sIFZvZGFmb25lLC4uLikgZ2l2ZXMgYWNjZXNzIHRvIHRoZSB0aGVpciByYWRpbyBjZWxsIG5ldHdvcmsgYW5kIHRoZSBudW1iZXJzIG9mIHBob25lcyBsb2dnZWQgdG8gZXZlcnkgY2VsbC9hbnRlbm5hLiBUaGlzIG1lYW5zIGEgY2hvc2VuIGRhdGEgYW5hbHlzdCB3b3VsZCBub3QgbmVlZCBhY2Nlc3MgdG8gZGV0YWlsZWQgYW5kIGhpZ2hseSBwZXJzb25hbCBsb2NhdGlvbiBkYXRhIGJ1dCBvbmx5IHJlY2VpdmVzIGEgZGF0YXNldCBjb250YWluaWcgdGhlIGxvY2F0aW9uIG9mIGNlbGxzLCB0aGVpciBlc3RpbWF0ZWQgY292ZXJhZ2UgcmFuZ2UgYW5kIHRoZSBudW1iZXIgb2YgcGhvbmVzIGxvZ2dlZCB0byB0aGUgcmVzcGVjdGl2ZSBhbnRlbm5hIGF0IGEgY2VydGFpbiBtb21lbnQuIEVVUk9TVEFUIGFuZCB0aGUgRXVyb3BlYW4gTmF0aW9uYWwgU3RhdGlzdGljYWwgSW5zdGl0dXRlcyBhcmUgZXhwZXJpbWVudGluZyB3aXRoIHRoZSBwb3RlbnRpYWwgdXNhZ2UgYW5kIGVzcGVjaWFsbHkgbmVjZXNzYXJ5IG1ldGhvZHMgYW5kIHdvcmtmbG93cyBmb3IgaW1wbGVtZW50aW5nIHN1Y2ggYSBkYXRhIHNvdXJjZSBpbnRvIHRoZSBnZW5lcmFsIHByb2R1Y3Rpb24gb2YgT2ZmaWNpYWwgU3RhdGlzdGljcy4gS25vd2luZyB3aGVuIGFuZCB3aGVyZSBob3cgbWFueSBwZW9wbGUgYXJlIGFwcHJveGltYXRlbHkgY29ycmVzcG9uZHMgdG8gdGhlIHN0YXRpc3RpY2FsIGluZGljYXRvciBjYWxsZWQgKnByZXNlbnQgcG9wdWxhdGlvbiogb3IgKmRlIGZhY3RvIHBvcHVsYXRpb24qLiBXaGlsZSB0aGUgcmVzaWRlbnQgcG9wdWxhdGlvbiB0YWtlcyBpbnRvIGNvbnNpZGVyYXRpb24gb25seSB0aGUgaW5kaXZpZHVhbHMgd2hvIHBlcm1hbmVudGx5IHJlc2lkZSBpbiBhIGNlcnRhaW4gZ2VvZ3JhcGhpY2FsIGFyZWEsIHRoZSBwcmVzZW50IHBvcHVsYXRpb24gImlzIGNvbXBvc2VkIGJ5IGFsbCBpbmRpdmlkdWFscyB3aG8gYXJlIHBoeXNpY2FsbHkgcHJlc2VudCBpbiB0aGUgZ2VvZ3JhcGhpYyBhcmVhIG9mIGludGVyZXN0IGF0IGEgc2VsZWN0ZWQgcmVmZXJlbmNlIHRpbWUiIFsxXS4NCiAgICANCkVVUk9TVEFUIGhhcyBvcmdhbml6ZWQgaW4gMjAyMCBmb3IgdGhlIGZpcnN0IHRpbWUgdGhlIEVVUk9TVEFUIENvZGluZyBMYWIsIG9mZmVyaW5nIEVNT1Mgc3R1ZGVudHMgYSBjaGFuY2UgaW4gZ2V0dGluZyB0byBrbm93IHRoZSBwcm9kdWN0aW9uIG9mIE9mZmljaWFsIFN0YXRpc3RpY3Mgb24gdGhlIEV1cm9wZWFuIGxldmVsIHdpdGggYSBwYXJ0aWN1bGFyIGZvY3VzIG9uIGNvZGluZy4gVGhpcyBwYXJ0aWN1bGFyIENvZGluZyBMYWIgaW50cm9kdWNlZCB0aGUgY29uY2VwdHMgb2YgdXNpbmcgTU5PIGRhdGEgZm9yIGVzdGltYXRpbmcgcHJlc2VudCBwb3B1bGF0aW9uIHN0YXRpc3RpY3MuICAgIA0KDQpUaGFua3MgdG8gdGhpcyBwcm9qZWN0IGFuZCBvdXIgbWVudG9ycywgd2UgLSBhIGdyb3VwIG9mIDQgaW50ZXJuYXRpb25hbCBzdHVkZW50cyBmcm9tIGFsbCBvdmVyIEV1cm9wZSAtIGhhZCB0aGUgb3Bwb3J0dW5pdHkgdG8gZGlnIGRlZXBlciBpbnRvIHRoZSB3b3JsZCBvZiBzcGF0aWFsIGFuYWx5c2lzIGFzIHdlbGwgYXMgc2ltdWxhdGlvbiBzdHVkaWVzIGluIFIuIFRocm91Z2hvdXQgdGhpcyBub3RlYm9vaywgd2UgZmFjZWQgbXVsdGlwbGUgY2hhbGxlbmdlczogRGV2ZWxvcGluZyBjb2RlIGluIGEgdGVhbSwgYXBwbHlpbmcgKGFsbW9zdCkgQmlnIERhdGEgbWV0aG9kcyBhbmQgY29uY2VwdHMgc3VjaCBhcyBwYXJhbGxpemluZyBjb2RlLCBkZXZlbG9waW5nIG1vZHVsYXIgYW5kIGZ1bGx5IHJlcHJvZHVjaWJsZSBjb2RlLCBvciBqdXN0IHdvcmtpbmcgdG9nZXRoZXIgZnJvbSA0IGRpZmZlcmVudCBjb3VudHJpZXMgaW4gdGltZXMgb2YgQ292aWQtMTkuIA0KDQpUaGUgbm90ZWJvb2sgYXQgaGFuZCByZWxpZXMgb24gbXVsdGlwbGUgc2NyaXB0cyB0aGF0IGZvbGxvdyBhIG1ldGhvZG9sb2dpY2FsIGNoYWluLiBUaGV5IGFyZSBjb25jZXB0dWFsaXplZCBhbmQgd3JpdHRlbiBpbiBhIG1vZHVsYXIgZmFzaGlvbiwgbWFraW5nIGZ1cnRoZXIgdXNlIG9mIHRoZSBjb2RlIGZvciBkaWZmZXJlbnQgcGFyYW1ldGVycyB2ZXJ5IGVhc3kuIE1hbnkgc29sdXRpb25lcyBuZWVkIHRvIHJ1biBmb3IgcXVpdGUgYSB3aGlsZSB0aGVyZWZvcmUgY2VydGFpbiBvYmplY3RzIGFyZSBwcmUtYnVpbHQgYW5kIG9ubHkgbG9hZGVkIGludG8gdGhlIG5vdGVib29rLg0KDQpPdXIgY29uY3JldGUgcmVzZWFyY2ggZ29hbCBpcyB0byBldmFsdWF0ZSBhbmQgY29tcGFyZSBkaWZmZXJlbnQgY3V0dGluZyBlZGdlIGVzdGltYXRpb24gdGVjaG5pcXVlcyBvZiBwcmVzZW50IHBvcHVsYXRpb24gd2l0aCBNTk8gZGF0YS4gQmVjYXVzZSBNTk8gZGF0YSwgZXZlbiB0aG91Z2ggYWdncmVnYXRlZCwgaXMgdmVyeSBzZWN1cmUsIHdlIGRpZCBub3Qgd29yayB3aXRoIHJlYWwgZGF0YS4gSW5zdGVhZCB3ZSBuZWVkZWQgdG8gY29tcGxldGVseSBidWlsZCBvdXIgb3duIHRveSB3b3JsZCwgYWltaW5nIGF0IGEgdmVyeSByZWFsaXN0aWMgc2NlbmFyaW8gd2hpY2ggY291bGQgYmUgdGhlIGJhc2Ugb2Ygb3VyIGV2YWx1YXRpb24uIFRoaXMgc2ltdWxhdGlvbiBzZXR0aW5nIGdpdmVzIHVzIHRoZSB1bmlxdWUgb3Bwb3J0dW5pdHkgdG8gYWN0dWFsbHkgdGVzdCB0aGUgcGVyZm9ybWFuY2Ugb2YgZGlmZmVyZW50IGVzdGltYXRvcnMgYmVjYXVzZSB3ZSBhcmUgaW4gY29udHJvbCBvZiB0aGUgdHJ1ZSB2YWx1ZXMuIFRoZSBub3RlYm9vayBpcyBzdHJ1Y3R1cmVkIGFzIGZvbGxvd3M6IEluIHRoZSBuZXh0IHNlY3Rpb24gd2UgaW50cm9kdWNlIHRoZSBnZW5lcmF0aW9uIG9mIHRoZSB0b3kgd29ybGQsIGNvbnNpc3Rpbmcgb2YgYSBnZW9ncmFwaGljYWwgYXJlYSB3aXRoIGEgbW9iaWxlIHBob25lIHBvcHVsYXRpb24gYW5kIGEgY29ycmVzcG9uZGluZyByYWRpbyBjZWxsIG5ldHdvcmsuIFdlIG1lbnRpb24gbW9zdCBpbXBvcnRhbnQgZmVhdHVyZXMgYW5kIHBhcmFtZXRlcnMgYXMgd2VsbCBhcyBleHBsYWluIGhvdyBtb2JpbGUgcGhvbmVzIGFyZSBsb2dnZWQgdG8gcmFkaW8gY2VsbHMgKGRldmljZS10by1jZWxsIGFzc29jaWF0aW9uKS4gRm9sbG93aW5nIHRoaXMgd2UgaW50cm9kdWNlIHR3byBvZiB0aGUgY3VycmVudGx5IGV4aXN0aW5nIGVzdGltYXRpb24gc3RyYXRlZ2llcywgZXhwbGFpbiB0aGVpciBtb3N0IGltcG9ydGFudCBjaGFyYWN0ZXJpc3RpY3MgYW5kIGFzc3VtcHRpb25zIGFuZCBhcHBseSB0aGVtIHRvIG91ciB0b3kgd29ybGQuIEluIHRoZSBmaW5hbCBzZWN0aW9uIHdlIHVuZGVydGFrZSBhIGRldGFpbGVkIGV2YWx1YXRpb24gb2YgZWFjaCBlc3RpbWF0b3IsIGZvY3VzaW5nIG9uIHN0YXRpc3RpY2FsIGFzIHdlbGwgYXMgZ2VvZ3JhcGhpY2FsLWRpc3RyaWJ1dGlvbmFsIHBlcmZvcm1hbmNlIG1lYXN1cmVzLiBXZSBlbmQgdGhpcyBldmFsdWF0aW9uIHdpdGggZnVydGhlciBleHBsb3JpbmcgdGhlIGNvbnZlcmdlbmNlIGJlaGF2aW9yIG9mIG9uZSBvZiB0aGUgZXN0aW1hdG9ycyBhbmQgZm9ybXVsYXRpbmcgZnVydGhlciBwb3RlbnRpYWwgcmVzZWFyY2ggZ29hbHMgaW4gdGhpcyBhcmVhLg0KDQojIFRveSB3b3JsZCBnZW5lcmF0aW9uDQoNCk91ciB0b3kgd29ybGQgYmFzZXMgb24gcG9wdWxhdGlvbiBjZW5zdXMgZGF0YSBmcm9tIHRoZSBHZXJtYW4gRmVkZXJhbCBTdGF0aXN0aWNhbCBPZmZpY2UgWzJdIChodHRwczovL3d3dy5kZXN0YXRpcy5kZS9FTi9Ib21lL19ub2RlLmh0bWwpLiBUaGlzIGRhdGEgZW50YWlscyBjb250aW5vdXMgcG9wdWxhdGlvbiBjb3VudHMgb24gYSAxMDBtICogMTAwbSBncmlkLiAqRm9yIG91ciBwcm9qZWN0IHdlIHJlZHVjZSB0aGUgcG9wdWxhdGlvbiBjb3VudCB0byBhIHRoaXJkIHRvIG1pbWljIHRoZSBwcm9jZXNzIG9mIHJlY2VpdmluZyBkYXRhIGZyb20gYW4gTU5PIHByb3ZpZGVyIC0gdGhlcmVmb3JlIHdlIGFzc3VtZSB0aGF0IHRoZSBwb3B1bGF0aW9uIGNvdW50IHJlc2VtYmxlcyB0aGUgbnVtYmVyIG9mIG1vYmlsZSBwaG9uZXMgaW4gdGhpcyBhcmVhLiogRm9yIGNvbXB1dGF0aW9uYWwgcmVhc29ucywgdGhpcyB2ZXJzaW9uIHdpbGwgb25seSBmb2N1cyBvbiBhIHN1YnNldCBvZiB0aGUgdGlsZXMgbG9jYXRlZCBpbiB0aGUgc3RhdGUgb2YgQmF2YXJpYSwgd2hpY2ggaXMgc2l0dWF0ZWQgaW4gdGhlIHNvdXRoLWVhc3Qgb2YgR2VybWFueS4gV2UgY2hvc2UgdGhpcyBhcmVhIGJlY2F1c2UgaXQgY29tcHJpc2VzIGEgaGlnaCBkaXZlcnNpdHkgb2YgdXJiYW4sIHN1YnVyYmFuLCBhbmQgcnVyYWwgYXJlYXMuDQoNCipUZXJtaW5vbG9neSB1c2VkIGluIHRoaXMgcHJvamVjdDoqDQpEdWUgdG8gdmFyaW91cyBkZWZpbml0aW9ucyBvdXQgdGhlcmUsIGl0IGlzIGltcGVyaWFsIHRvIGRlZmluZSB0aGUgZGlmZmVyZW50IHRlcm1pbm9sb2dpZXMgdXNlZCBpbiB0aGlzIHByb2plY3QgYmVmb3JlIGdvaW5nIGZ1cnRoZXIgdG8gcmVkdWNlIHVubmVjZXNzYXJ5IGNvbmZ1c2lvbi4NCi0gV2hlbiB3ZSB0YWxrIGFib3V0ICp0aWxlcyosIHdlIG1lYW4gYW55IHNxdWFyZSBvbiB0aGUgcmVndWxhciAxMDAgKiAxMDAgbTIgZ3JpZC4NCi0gQW4gKmFudGVubmEqIGlzIGEgZGV2aWNlIGZhY2lsaXRhdGluZyBiZXR3ZWVuIHJhZGlvIHRyYW5zbWlzc2lvbiBhbmQgcmVjZXB0aW9uLiBTcGVjaWZpY2FsbHkgaW4gb3VyIGNhc2UsIGFuIGFudGVubmEgdHJhbnNtaXRzIGFuZCByZWNlaXZlcyBjZWxsIHBob25lIHNpZ25hbHMuIFRoaXMgaXMgYWxzbyBrbm93biBhcyBhICpjZWxsKi4NCi0gQSAocmFkaW8pICp0b3dlciogb3IgY29tbW9ubHkgcmVmZXJyZWQgdG8gYXMgYSAqY2VsbCB0b3dlciwgY2VsbHVsYXIgc2l0ZSwgb3IgY2VsbHVsYXIgYmFzZSBzdGF0aW9uKiBpcyBhIHRvd2VyIGVxdWlwcGVkIHdpdGggYW50ZW5uYXMuDQoNCmBgYHtyLCBzZXR1cH0NCiMgY2hhbmdlIGFjY29yZGluZ2x5DQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9IG5vcm1hbGl6ZVBhdGgoIkM6L1VzZXJzL01hcmNvLyIpKSANCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGggPSA5KQ0Ka25pdHI6Om9wdHNfa25pdCRzZXQoZXZhbC5hZnRlciA9ICJmaWcuY2FwIikNCmBgYA0KDQpgYGB7ciBwYWNrYWdlcywgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzZikNCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShNYXRyaXgpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkoY293cGxvdCkNCmxpYnJhcnkodHJhbnNmb3JtcikNCmxpYnJhcnkoZ2dhbmltYXRlKQ0Kc2V0LnNlZWQoNzYyKQ0KDQpjZW5zdXMuZGUuMTAwbS50aWxlIDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvd29ya2luZyBvYmplY3RzL2NlbnN1cy50aWxlLmZpbmFsLnJkcyIpIA0KYGBgDQoNCg0KYGBge3IgZm9jdXMgYXJlYSwgZmlnLndpZHRoID0gNywgZmlnLmNhcD0iV2Ugd2lsbCBvbmx5IGZvY3VzIG9uIGEgc3Vic2V0IG9mIHRoZSB0aWxlcyBsb2NhdGVkIGluIHRoZSBzdGF0ZSBvZiBCYXZhcmlhIGJlY2F1c2UgaXQgY29tcHJpc2VzIGJvdGggdXJiYW4sIHN1YnVyYmFuLCBhbmQgcnVyYWwgYXJlYXMiIH0NCiMgQm91bmRpbmcgYm94IG9mIGZvY3VzIGFyZWENCmJiLmZvY3VzLmRhdCA8LSBkYXRhLmZyYW1lKHhtaW4gPSA0NDAwMDAwLCB4bWF4ID0gNDUwMDAwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSAyNzAwMDAwLCB5bWF4ID0gMjkwMDAwMCkNCmJiLmZvY3VzLnZlYyA8LSBjKHhtaW4gPSA0NDAwMDAwLCB4bWF4ID0gNDUwMDAwMCwNCiAgICAgICAgICAgICAgICAgIHltaW4gPSAyNzAwMDAwLCB5bWF4ID0gMjkwMDAwMCkNCiMgRG93bmxvYWQgZGF0YSBmcm9tIDogaHR0cHM6Ly9nYWRtLm9yZy9kb3dubG9hZF9jb3VudHJ5X3YzLmh0bWwgLS0+IFIoc2YpIGxldmVsIDENCmdlcm1hbnkucmF3IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvd29ya2luZyBvYmplY3RzL2dhZG0zNl9ERVVfMV9zZi5yZHMiKSANCmdlcm1hbnkgPC0gZ2VybWFueS5yYXcgJT4lICANCiAgc3RfdHJhbnNmb3JtKGNycyA9IDMwMzUpDQpmb2N1cy5hcmVhLnBsb3QgPC0gZ2VybWFueSAlPiUgIA0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX3NmKCkgKyANCiAgZ2VvbV9yZWN0KGRhdGEgPSBiYi5mb2N1cy5kYXQsIGFlcyh5bWluID0geW1pbiwgeW1heCA9IHltYXgsICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeG1pbiA9IHhtaW4sIHhtYXggPSB4bWF4LCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiksICANCiAgICAgICAgICAgIHNpemUgPSAxLCBmaWxsID0gInRyYW5zcGFyZW50IikgKyANCiAgZ2d0aXRsZSgiIikgKyANCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkobmFtZSA9ICIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiRm9jdXMgYXJlYSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSAibGVnZW5kIikgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwNCiAgICAgICB0aXRsZSA9ICIiKQ0KIA0KcGxvdF9ncmlkKGZvY3VzLmFyZWEucGxvdCwgDQogICAgICAgICAgbGFiZWxzID0gIkZpZy4xOiBGb2N1c2luZyBvbiBhIHBhcnQgb2YgU291dGggQmF2YXJpYSIsDQogICAgICAgICAgaGp1c3QgPSAtMC4xLCBsYWJlbF9zaXplID0gMTMpDQpgYGANCg0KDQpBcyBtZW50aW9uZWQgYWJvdmUgdGhpcyBhcmVhIGlzIHZlcnkgaGV0ZXJvZ2VuZW91cyBpbiB1cmJhbi1ydXJhbCBpbnRlbnNpdHkuIEtub3dpbmcgdGhlIGxvY2F0aW9uIG9mIHVyYmFuIGNlbnRlcnMgaXMgdmVyeSBpbXBvcnRhbnQgZm9yIHRoZSBjb3JyZXNwb25kaW5nIHJhZGlvIGNlbGwgbmV0d29yayBhcyB0aGVyZSBhcmUgZGlmZmVyZW5jZXMgaW4gY2VsbCBjb3ZlcmFnZSBiZXR3ZWVuIHRoZXNlIGRpZmZlcmVudCBhcmVhIGtpbmRzLiBXZSBhcmUgYWltaW5nIGF0IGRldmVsb3BpbmcgYSAzLWNhdGVnb3J5IGNsYXNzaWZpY2F0aW9uIGZvciBlYWNoIHRpbGU6IFJ1cmFsLCBTdWJ1cmJhbiBhbmQgVXJiYW4uIEJhc2VkIG9uIHRoZSBjZW5zdXMgZGF0YSBvbiB0aGUgdGlsZSBsZXZlbCB3ZSBjYW5ub3QgbG9jYXRlIHVyYmFuIGNlbnRlcnMganVzdCB5ZXQuIENsYXNzaWZ5aW5nIHRpbGVzIG9uIHN1Y2ggYSBsb3cgc3BhdGlhbCByZXNvbHV0aW9uIGludG8gb25lIG9mIHRoZXNlIGNhdGVnb3JpZXMgaW5kZXBlbmRlbnQgZnJvbSBlYWNoIG90aGVyIChpLmUuIGJhc2VkIG9uIHRoZWlyIHBvcHVsYXRpb24gbnVtYmVycykgd291bGQgbm90IGxlYWQgdG8gdGhlIHRydWUgbG9jYXRpb24gb2YgdXJiYW4gY2VudGVycy4gVGhlcmVmb3JlIHdlIGFwcGx5IGEgc3BhdGlhbCBjbHVzdGVyaW5nIGFsZ29yaXRobSB0byBhY2NvdW50IGZvciB0aGUgc3BhdGlhbCBkZXBlbmRlbmNlLiBUaGUgcGxvdHMgYmVsb3cgcHJlc2VudCBvdXIgY2xhc3NpZmljYXRpb24gcmVzdWx0czoNCmBgYHtyIHBvcCBkaXN0cmlidXRpb24gMSwgZmlnLmNhcD0gIkZpZ3VyZSAyYSBzaG93cyB0aGUgY2xhc3NpZmljYXRpb24gcmVzdWx0cyBmcm9tIHRoZSBjbHVzdGVyaW5nIGFsZ29yaXRobSBhbmQgdGhlIHByb3BvcnRpb24gb2YgcGVvcGxlIGluIHRoZSBhcmVhIGNhdGVnb3JpZXMuV2hpbGUgRmlndXJlIDJiIHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGZvdXIgZGlmZmVyZW50IGNhdGVnb3JpZXMgb2YgdGlsZXMgb2J0YWluZWQgdGhyb3VnaHQgc3BhdGlhbCBjbHVzdGVyaW5nLiJ9DQoNCnRpbGUucHJvcC5wbG90IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvRXN0aW1hdGVzL1Bsb3QuZmlsZXMvdGlsZS5wcm9wLnBsb3QucmRzIikNCg0KY2x1c3Rlci5wbG90IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvd29ya2luZyBvYmplY3RzL2NsdXN0ZXIucGxvdC5yZHMiKQ0KDQoNCnBsb3RfZ3JpZChjbHVzdGVyLnBsb3QsIHRpbGUucHJvcC5wbG90LCBsYWJlbHMgPSAiRmlnLjIgOiBQb3B1bGF0aW9uIENsYXNzaWZpY2F0aW9uIiwgIA0KICAgICAgICAgICAgaGp1c3QgPSAtMC4xLCBsYWJlbF9zaXplID0gMTQsIHJlbF93aWR0aHMgPSBjKDAuOCwgMSkpIA0KDQpgYGANCg0KRmlndXJlIDIgc2hvd3MgdGhlIGNsYXNzaWZpY2F0aW9uIHJlc3VsdHMgZnJvbSB0aGUgY2x1c3RlcmluZyBhbGdvcml0aG0gYW5kIHRoZSBwcm9wb3J0aW9uIG9mIHBlb3BsZSBpbiB0aGUgYXJlYSBjYXRlZ29yaWVzLiBXZSBhaW1lZCBhdCBoYXZpbmcgNCBkaWZmZXJlbnQgY2F0ZWdvcmllczogVW5pbmhhYml0ZWQsIFJ1cmFsLCBTdWJ1cmJhbiBhbmQgVXJiYW4uIFdoZW4gd29ya2luZyBhdCB0aGlzIGxvdyBzcGF0aWFsIHJlc29sdXRpb24sIGl0IGlzIGRpc2NvdXJhZ2VkIHRvIGNsYXNzaWZ5IHRpbGVzIGluZGVwZW5kZW50bHkgYmFzZWQgb24gdGhlaXIgcmVzcGVjdGl2ZSBwb3B1bGF0aW9uIHZhbHVlIC0gb25lIG5lZWRzIHRvIHRha2Ugc3BhdGlhbCBkZXBlbmRlbmNlIGludG8gY29uc2lkZXJhdGlvbiBpbiBvcmRlciB0byBpZGVudGlmeSB1cmJhbiBjZW50ZXJzLiBUaGVyZWZvcmUsIHdlIGFwcGx5IGEgc3BhdGlhbCBjbHVzdGVyaW5nIG1ldGhvZCwgbWFpbmx5IGZvciBpZGVudGlmeWluZyB0aGUgbGFzdCB0d28gY2F0ZWdvcmllcy4gSW4gb3JkZXIgdG8gcnVuIHRoZSBjbHVzdGVyaW5nIGFsZ29yaXRobSwgdGhlIG9yaWdpbmFsIGNlbnN1cyBwb3B1bGF0aW9uIGlzIGZpcnN0IGRpdmlkZWQgaW50byB0aWxlcyBhYm92ZSBhbmQgYmVsb3cgMTUgcGVvcGwuZSBwZXIgdGlsZS4gVGlsZXMgYmVsb3cgMTUgYXJlIGVpdGhlciBjbGFzc2lmaWVkIGFzIFVuaW5oYWJpdGVkIG9yIFJ1cmFsLCBmcm9tIHRoZSBzdGFydCAodW5pbmhhYml0ZWQgY29ycmVzcG9uZHMgdG8gdGhlIHRpbGVzIHdpdGggMCBwb3B1bGF0aW9uKS4gVGhlIGNsdXN0ZXJpbmcgaXMgdGhlbiBkb25lIG9uIHRoZSB0aWxlcyB0aGF0IGFyZSBhYm92ZSAxNSBwZW9wbGUgcGVyIHRpbGUuIEJhc2VkIG9uIHRoZSByZXN1bHRzIG9mIHRoZSBjbHVzdGVyaW5nLCB3ZSBkZWZpbmUgdXJiYW4gYXJlYXMgYXMgY2x1c3RlcnMgdGhhdCBoYXZlIGFuIGFnZ2xvbWVyYXRpb24gb2YgbW9yZSB0aGFuIDEwMCB0aWxlcy4gU3VidXJiYW4gYXJlYXMgYXJlIGRlZmluZWQgYXMgY2x1c3RlcnMgdGhhdCBoYXZlIG1vcmUgdGhhbiA1MCBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIDEwMCB0aWxlcy4gVGhlIHJlbWFpbmluZyBjbHVzdGVycyBhcmUgY29uc2lkZXJlZCBhcyBSdXJhbCBhcmVhcyBhbmQgdGhlcmVmb3JlIHJlc3VsdCBpbiB0aGUgc2FtZSBjbGFzc2lmaWNhdGlvbiBhcyB0aGUgdGlsZXMgZnJvbSBhYm92ZSwgd2hpY2ggaGFkIGxlc3MgdGhhbiAxNSBwZW9wbGUuDQoNClRoZSBzdGFja2VkIGJhciBwbG90IHNob3dzIHRoZSBwcm9wb3J0aW9ucyBvZiB0aGUgdGlsZXMgYWNjb3JkaW5nIHRvIHRoZSBmb3VyIGNhdGVnb3JpZXMuIEJhc2VkIG9uIG91ciBjbHVzdGVyaW5nIGFsZ29yaXRobSwgYHIgdGlsZS5wcm9wLnBsb3QkZGF0YSRwcm9wWzFdYCUgb2YgdGhlIHRpbGVzIGFyZSB1cmJhbiBhcmVhcy4gYHIgdGlsZS5wcm9wLnBsb3QkZGF0YSRwcm9wWzJdYCUgb2YgdGhlIHRpbGVzIGFyZSB1bmluaGFiaXRlZCBhcmVhcy4gYHIgdGlsZS5wcm9wLnBsb3QkZGF0YSRwcm9wWzNdYCUgb2YgdGhlIHRpbGVzIGFyZSBzdWJ1cmJhbiBhcmVhcywgYW5kIGByIHRpbGUucHJvcC5wbG90JGRhdGEkcHJvcFs0XWAlIG9mIHRoZSB0aWxlcyBhcmUgcnVyYWwgYXJlYXMuDQoNCmBgYHtyIHBvcCBkaXN0cmlidXRpb24gMiwgZmlnLmNhcD0gIlRoZSBGaWd1cmUgM2Egc2hvd3MgdGhlIGdlb2dyYXBoaWNhbCBkaXN0cmlidXRpb24gb2YgdGhlIHRpbGVzIGNsYXNzaWZpZWQgdGhvdWdodCB0aGUgY2x1c3RlcmluZyBhbGdvcml0aG0gb2YgdGhlIHBvcHVsYXRpb24uIEluIEZpZ3VyZSAzYiB0aGVyZSBpcyByYXByZXNlbnRlZCAgdGhlIGxvZ2FyaXRobSBvZiBFQ0NERiBvZiB0aGUgcG9wdWxhdGlvbiBkYXRhIGFuZCB0aGUgZ3JhcGggaW5zaWRlIHRoZSBmaWd1cmUgM2IgaXMgdGhlIGxpbmVhciBFQ0NERi4iIH0NCg0KdHJ1ZS5nZW8uZXZhbC5wbG90IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvRXN0aW1hdGVzL1Bsb3QuZmlsZXMvdHJ1ZS5wb3BfbWFwLnJkcyIpDQoNCkVDQ0RGLnRydWUgPC0gcmVhZFJEUygiVnlzb2vDoSDFoWtvbGEgZWtvbm9taWNrw6EgdiBQcmF6ZS9Ub255IFdlaSBUc2UgSHVuZyAtIFlBWS9Fc3RpbWF0ZXMvUGxvdC5maWxlcy9FQ0NERi50cnVlLnJkcyIpDQoNCkVDREYudHJ1ZSA8LSByZWFkUkRTKCJWeXNva8OhIMWha29sYSBla29ub21pY2vDoSB2IFByYXplL1RvbnkgV2VpIFRzZSBIdW5nIC0gWUFZL0VzdGltYXRlcy9QbG90LmZpbGVzL0VDREYudHJ1ZS5yZHMiKQ0KDQogDQpFQ0NERi5wb3AucGxvdCA8LSBFQ0NERi50cnVlICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLTAuMzAxMDMwMCwgbGluZXR5cGUgPSAiZG90dGVkIikgKyANCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLTEsIGxpbmV0eXBlID0gImRvdHRlZCIpICsgDQogIGdlb21fdGV4dCh4ID0gMS41LCB5ID0gLTAuMiwgbGFiZWwgPSAiNTAlIG9mIHRoZSBkYXRhIikgKyANCiAgZ2VvbV90ZXh0KHggPSAxLjUsIHkgPSAtMC45LCBsYWJlbCA9ICI5MCUgb2YgdGhlIGRhdGEiKSArIA0KICBsYWJzKHkgPSAibG9nMTAoUHJvYihZID4geCkpIiwgeCA9ICJsb2cxMChNb2JpbGUgcGhvbmVzKSIsICANCiAgICAgICAgY29sb3VyID0gIiIpICsgDQogIHlsaW0oLTcsIDApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpIA0KIA0KRUNERi5wb3AucGxvdCA8LSBFQ0RGLnRydWUgKw0KICB4bGltKDAsIDMwKSArDQogIGxhYnMoeSA9ICIiLCB4ID0gIiIpDQoNCnBvcC5kaXN0LmVjZGYuaW5zZXJ0IDwtIEVDQ0RGLnBvcC5wbG90ICsNCiAgYW5ub3RhdGlvbl9jdXN0b20oZ2dwbG90R3JvYihFQ0RGLnBvcC5wbG90KSwgDQogICAgICAgICAgICAgICAgICAgIHhtaW4gPSAwLCB4bWF4ID0gMS41LCANCiAgICAgICAgICAgICAgICAgICAgeW1pbiA9IC03LCB5bWF4ID0gLTMpDQoNCnBsb3RfZ3JpZCh0cnVlLmdlby5ldmFsLnBsb3QsIHBvcC5kaXN0LmVjZGYuaW5zZXJ0LCBsYWJlbHMgPSAiRmlnLiAzOiBNb2JpbGUgcGhvbmUgZGVuc2l0eSBwZXIgdGlsZSIsICANCiAgICAgICAgICBoanVzdCA9IC0wLjEsIGxhYmVsX3NpemUgPSAxNCwgcmVsX3dpZHRocyA9IGMoMC44LCAxKSkNCmBgYA0KDQpGaWd1cmUgMyBzaG93cyB0aGUgbW9iaWxlIHBob25lIGRlbnNpdHkgcGVyIHRpbGUgaW4gdGhlIGZvY3VzIGFyZWEuIEluIHBhcnRpY3VsYXIsIHdlIGhhdmUgNCBkaWZmZXJlbnQgY29sb3JzIHJlcHJlc2VudGluZyB0aGUgY2x1c3RlcnM6IFVuaW5oYWJpdGVkLCBSdXJhbCwgU3VidXJiYW4gYW5kIFVyYmFuLg0KDQpIb3dldmVyLCB0byBoYXZlIGEgZGVlcGVyIGxvb2sgb2YgdGhlIG1vYmlsZSBwaG9uZSBkZW5zaXR5IHBlciB0aWxlLCB3ZSBjaG9vc2UgdG8gcmVwcmVzZW50IHRoZSBkYXRhIHdpdGggYW4gZW1waXJpY2FsIGN1bXVsYXRpdmUgY29tcGxlbWVudGFyeSBkaXN0cmlidXRpb24gZnVuY3Rpb24gKEVDQ0RGKSAodXNpbmcgYSBsb2cgYmFzZSAxMCB0cmFuc2Zvcm1hdGlvbikuDQoNClRoZSBFQ0NERiBpcyBhIHN0ZXAgZnVuY3Rpb24gd2l0aCBqdW1wcyBgaS9uYCBhdCBvYnNlcnZhdGlvbiB2YWx1ZXMsIHdoZXJlIGBpYCBpcyB0aGUgbnVtYmVyIG9mIHRpZWQgb2JzZXJ2YXRpb25zIGF0IHRoYXQgdmFsdWUuIE1vcmVvdmVyLCBtaXNzaW5nIHZhbHVlcyBhcmUgaWdub3JlZCBhbmQgdGhlIG9iamVjdGl2ZSAiY29tcGxlbWVudGFyeSIgbWVhbnMgdGhhdCB3ZSBuZWVkIHRvIHN1YnRyYWN0IDEgLSB0aGUgY3VtdWxhdGl2ZSBwcm9iYWJpbGl0eS4gSXQgaXMgY29tbW9ubHkgdXNlZCB3aXRoIHZhcmlhYmxlcyB0aGF0IGhhdmUgYSBoaWdobHkgc2tld2VkIGRpc3RyaWJ1dGlvbi4gV2UgY2FuIHNlZSB0aGF0IHRoaXMgaXMgdGhlIGNhc2UgLSB0aGUgcG9wdWxhdGlvbiBvbiB0aGlzIGxvdyBzcGF0aWFsIHJlc29sdXRpb24gaXMgaGVhdmlseSByaWdodCBza2V3ZWQuDQoNCkFzIHRoZSBmaWd1cmUgc3VnZ2VzdHMsIDUwJSBvZiB0aGUgZGF0YSBhcmUgcmVwcmVzZW50ZWQgYnkgdW5pbmhhYml0ZWQgdGlsZXMgd2l0aCBubyBwaG9uZXM7IGZ1cnRoZXJtb3JlLCA5MCUgb2YgdGhlIHRpbGVzIGNvbnRhaW4gbGVzcyB0aGFuIGhhbGYgb2YgdGhlIG1vYmlsZSBwaG9uZXMgaW4gb3VyIGZvY3VzIGFyZWEuIE9uZSBjYW4gYWxzbyBzZWUgdGhlIHRpbGVzJyBjbGFzc2lmaWNhdGlvbiBiYXNlZCBvbiB0aGUgY2x1c3RlcmluZyByZXN1bHRzLiBTb21lIHRpbGVzIGNsYXNzaWZpZWQgYXMgUnVyYWwgaGF2ZSBoaWdoZXIgdmFsdWVzIGZvciB0aGVpciBtb2JpbGUgcGhvbmUgcG9wdWxhdGlvbiAtIHRoaXMgaXMgYmVjYXVzZSB0aGV5IGFyZSBub3QgY29uc2lkZXJlZCBhcyBhbiBVcmJhbiBvciBTdWJ1cmJhbiBjbHVzdGVyLCBhcyBtZW50aW9uZWQgYWJvdmUuIDEwJSBsZWZ0IGFyZSB0aWxlcyBib3RoIHVyYmFuIGFuZCBydXJhbCBjb250YWluaW5nIDAuNSBhbmQgYWJvdmUgbW9iaWxlIHBob25lcy4NCg0KIyMgR2VuZXJhdGlvbiBvZiBhIHN5bnRoZXRpYyBSYWRpbyBOZXR3b3JrDQoNCldlIGdlbmVyYXRlIGEgcmFkaW8gbmV0d29yaywgd2hpY2ggaXMgY29tcG9zZWQgb2YgdGhyZWUgbGF5ZXJzLiBUaGUgbGF5ZXJzIGZvbGxvdyB0aGUgcG9wLmFyZWEua2luZCB2YXJpYWJsZSAtIGxheWVyIDEgKFJ1cmFsKSBzcGFucyBvdmVyIHRoZSBydXJhbCwgc3VidXJiYW4gYW5kIHVyYmFuIHRpbGVzLCBsYXllciAyIChTdWJ1cmJhbikgc3BhbnMgb3ZlciB0aGUgc3VidXJiYW4gYW5kIHVyYmFuIHRpbGVzIGFuZCBsYXllciAzIChVcmJhbikgaXMgc3Bhbm5lZCBvdmVyIHRoZSB1cmJhbiB0aWxlcy4NCg0KKipJbXBvcnRhbnQgZmVhdHVyZXMgYW5kIHBhcmFtZXRlcnMgb2YgdGhlIGdlbmVyYXRlZCByYWRpbyBuZXR3b3JrIGFyZToqKg0KDQotICAgVGhlIGxheWVycyBmb2xsb3cgYSBoZXhhZ29uIHNoYXBlIHdpdGggY2VsbCB0b3dlcnMgbG9jYXRlZCBpbiB0aGUgcmVzcGVjdGl2ZSBjZW50cm9pZCBvZiBlYWNoIGhleGFnb24NCg0KLSAgIFRvd2VycyB2YXJ5IGluIGRpc3RhbmNlIHRvIGVhY2ggb3RoZXIgb2YgdGhlIHNhbWUgbGF5ZXIsIGkuZS4gaG93IGZhci9jbG9zZSBhcmUgdG93ZXJzIG9mIHRoZSBzYW1lIGxheWVyIGxvY2F0ZWQgdG8gZWFjaCBvdGhlcjogbGF5ZXIgMSA9IDI3LDAwMG07IGxheWVyIDIgPSA3MDAwbTsgbGF5ZXIgMyA9IDkwMG0gKC1cPiB0aGUgbW9yZSB1cmJhbml6ZWQsIHRoZSBjbG9zZXIgdGhlIHRvd2VycyBhcmUgdG9vIGVhY2ggb3RoZXIgLVw+IGRlbnNlciBjb3ZlcmFnZSkuIEZ1cnRoZXJtb3JlLCBoZXhhZ29uIGluZGVwZW5kZW50IHJvdGF0aW9uIGluIHRlcm1zIG9mIHRoZSBmaXJzdCBsYXllciBpcyBleGVjdXRlZDogbGF5ZXIgMiA9IDM1IGRlZ3JlZXM7IGxheWVyIDMgPSA3MCBkZWdyZWVzDQoNCi0gICBFYWNoIGNlbGwgdG93ZXIgbG9jYXRpb24gaXMgaml0dGVyZWQgaW4gb3JkZXIgdG8gYnJlYWsgdGhlIHN5bW1ldHJ5LiBUaGUgaml0dGVyIGFtb3VudCBkZXBlbmRzIG9uIHRoZSBsYXllcjogbGF5ZXIgMSA9IDUwMDBtLCBsYXllciAyID0gMTAwMG0sIGxheWVyIDMgPSA0MDBtLg0KDQotICAgRWFjaCB0b3dlciBjb250YWlucyB0aHJlZSBhbnRlbm5hcyBwb2ludGluZyBpbnRvIDEyMCBkZWdyZWUgZGlmZmVyaW5nIGRpcmVjdGlvbnMuDQoNCi0gICBUaGUgbGF5ZXIgZGV0ZXJtaW5lcyB0aGUgY292ZXJhZ2UgZGlhbWV0ZXIgb2YgYW4gYW50ZW5uYTogbGF5ZXIgMSA9IDE1LDAwMG07IGxheWVyIDIgPSAyNTAwbTsgbGF5ZXIgMyA9IDUwMG0NCg0KLSAgIEVhY2ggdGlsZSBvZiB0aGUgZm9jdXMgYXJlYSBpcyBzdWZmaWNpZW50bHkgY292ZXJlZCBieSBhdCBsZWFzdCBvbmUgYW50ZW5uYSBhbmQgdGhlIGFudGVubmFzJyBjb3ZlcmFnZSBhcmVhcyBhcmUgYWxsb3dlZCB0byBvdmVybGFwLg0KDQotICAgUGFyYW1ldGVycyBjb25jZXJuaW5nIHRoZSBkZXZpY2UgdG8gY2VsbCBhc3NvY2lhdGlvbiBhcmUgc3BlY2lmaWVkIGluIHRoZSBuZXh0IHNlY3Rpb24NCg0KVGhlIGxpbmsgdG8gdGhlIHNvdXJjZSBjb2RlIGZvciB0aGUgbGF5ZXJzLjEgb2JqZWN0IGFzIHdlbGwgYXMgdGhlIGNvdmVyYWdlLmFyZWFzLjEgb2JqZWN0IGlzIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vUi1yYW1samFrL01OT19HTS9ibG9iL21hc3Rlci8yX1JhZGlvJTIwY2VsbCUyMGdlbmVyYXRpb24uUikuDQoNClRoZSBsaW5rIHRvIHRoZSBzb3VyY2UgY29kZSBmb3IgdGhlIGxheWVycyBvYmplY3QgYXMgd2VsbCBhcyB0aGUgY292ZXJhZ2UuYXJlYXMgb2JqZWN0IGlzIFtoZXJlXSAoPGh0dHBzOi8vZ2l0aHViLmNvbS9SLXJhbWxqYWsvTU5PX0V1cm9zdGF0L2Jsb2IvbWFzdGVyL2NvZGUvMl9SYWRpbyUyMGNlbGwlMjBnZW5lcmF0aW9uLlI+KS4NCg0KYGBge3IgbmV0d29yayBsYXllcnMsIGZpZy53aWR0aCA9IDcsIGZpZy5jYXAgPSAiVGhlIGZpZ3VyZSBwcmVzZW50cyB0aGUgaGV4YWdvbmFsIHN0cnVjdHVyZS4gRWFjaCB0cmlhbmdsZSBpcyBhIHRvd2VyIGxvY2F0aW9uIHdpdGggc29tZSByYW5kb21uZXNzIGltcGxlbWVudGVkLiJ9DQpsYXllcnMgPC0gcmVhZFJEUygiVnlzb2vDoSDFoWtvbGEgZWtvbm9taWNrw6EgdiBQcmF6ZS9Ub255IFdlaSBUc2UgSHVuZyAtIFlBWS93b3JraW5nIG9iamVjdHMvcmFkaW8gY2VsbCBsYXllcnMucmRzIikgDQpjb3ZlcmFnZS5hcmVhcyA8LSByZWFkUkRTKCJWeXNva8OhIMWha29sYSBla29ub21pY2vDoSB2IFByYXplL1RvbnkgV2VpIFRzZSBIdW5nIC0gWUFZL3dvcmtpbmcgb2JqZWN0cy9jb3ZlcmFnZS5hcmVhcy5yZHMiKSANCiANCmNvdmVyYWdlLmxheWVyMSA8LSBjb3ZlcmFnZS5hcmVhcyAlPiUgIA0KICBmaWx0ZXIoYXJlYS5raW5kID09ICJSdXJhbCIpICU+JSAgDQogIHN0X2Ryb3BfZ2VvbWV0cnkoKSAlPiUgIA0KICBkcGx5cjo6c2VsZWN0KC1hbnRlbm5hLmNlbnRyb2lkKSAlPiUgIA0KICBzdF9hc19zZihjb29yZHMgPSBjKCJYLnRvdyIsICJZLnRvdyIpLCBjcnMgPSAzMDM1KSANCiANCmxheWVycy5wbG90IDwtIGxheWVyc1tbMV1dICU+JSANCiAgc3RfYXNfc2YoY3JzID0gMzAzNSkgJT4lICANCiAgZ2dwbG90KCkgKyANCiAgICAjIGdlb21fcmVjdChkYXRhID0gYmIuZm9jdXMuZGF0LCBhZXMoeW1pbiA9IHltaW4sIHltYXggPSB5bWF4LCAgDQogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeG1pbiA9IHhtaW4sIHhtYXggPSB4bWF4KSwgIA0KICAgICMgICAgICAgICBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjMsIGFscGhhID0gMC41LCBmaWxsID0gYWxwaGEoImdyZXkiLCAwKSkgKyANCiAgZ2VvbV9zZihsaW5ldHlwZSA9ICJkb3R0ZWQiKSArIA0KICBnZW9tX3NmKGRhdGEgPSBjb3ZlcmFnZS5sYXllcjEsIGFlcyhjb2xvciA9ICIjNDI3M0M1IiksIHNoYXBlID0gMTcpICsgDQogIHNjYWxlX2NvbG9yX2lkZW50aXR5KG5hbWUgPSAiIiwgDQogICAgICAgICAgICAgICAgICAgICAgICMgYnJlYWtzID0gYygiRm9jdXMgYXJlYSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiSml0dGVyZWQgdG93ZXIgbG9jYXRpb24iKSwgDQogICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gImxlZ2VuZCIpICsgDQogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLA0KICAgICAgIHRpdGxlID0gIiIsDQogICAgc3VidGl0bGUgPSAiVG93ZXJzIGFyZSBsb2NhdGVkIGluIHRoZSBjZW50cm9pZCBvZiBhIGhleGFnb24uIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIGZhY2U9ImJvbGQiLCBoanVzdCA9IDAuNSksDQogIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT05LGhqdXN0ID0gMC41KSkNCiAgIA0KcGxvdF9ncmlkKGxheWVycy5wbG90LA0KICAgICAgICAgIGxhYmVscyA9ICJGaWcuIDQ6UmFkaW8gbmV0d29yayAtIEV4YW1wbGUgTGF5ZXIgMSAoUnVyYWwpIiwNCiAgICAgICAgICBoanVzdCA9IC0wLjEsIGxhYmVsX3NpemUgPSAxNCkNCmBgYA0KDQpXZSB1c2UgYSBoZXhhZ29uYWwgc3RydWN0dXJlIHRvIHBsYWNlIHRvd2VycyBhY3Jvc3Mgb3VyIGZvY3VzIGFyZWEuIFRoaXMgaXMgYSBxdWl0ZSByZWFsaXN0aWMgc2V0dXAgZm9yIGNlbGwgdG93ZXJzLiBFYWNoIGhleGFnb24gY29ycmVzcG9uZHMgdG8gb25lIHRvd2VyIHdoaWNoIGlzIG9yaWdpbmFsbHkgcGxhY2VkIGluIHRoZSBjZW50cm9pZCBvZiB0aGUgcmVzcGVjdGl2ZSBoZXhhZ29uLiBJbiBvcmRlciB0byBleGNsdWRlIHN5bW1ldHJpY2FsIHN0cnVjdHVyZSwgd2UgaW1wbGVtZW50IHNvbWUgcmFuZG9tbmVzcyBpbiB0aGUgZXhhY3QgbG9jYXRpb24gb2YgdGhlIGNlbGwgdG93ZXJzLiBGaWd1cmUgMyBleGVtcGxpZmllcyB0aGUgZWZmZWN0IG9mIHRoZSBqaXR0ZXIgcGFyYW1ldGVyIGluIHRoZSAxc3QgbGF5ZXIgLSB0aGUgYWN0dWFsIGxvY2F0aW9uIGRldmlhdGVzIHNsaWdodGx5IGZyb20gdGhlIGNlbnRyb2lkIGluIG9yZGVyIHRvIGJyZWFrIHRoZSBzeW1tZXRyeSBvZiB0aGUgdW5kZXJseWluZyBoZXhhZ29uYWwgc3RydWN0dXJlLiBUaGlzIGlzIGRvbmUgZm9yIGV2ZXJ5IGxheWVyLg0KDQpUaGUgc2V0dXAgb2YgYSB0b3dlciB3aXRoIGl0cyBjb3JyZXNwb25kaW5nIGFudGVubmFzIGlzIGluIGV2ZXJ5IGxheWVyIHRoZSBzYW1lOiBUaHJlZSBhbnRlbm5hcyBwZXIgdG93ZXIsIHBvaW50aW5nIGludG8gMTIwIGRlZ3JlZSBkaWZmZXJpbmcgZGlyZWN0aW9ucy4gVGhlIGFuaW1hdGVkIHZpc3VhbGl6YXRpb24gZXhlbXBsaWZpZXMgdGhpcyBmb3IgYW55IGdlbmVyaWMgdG93ZXIuDQoNCmBgYHtyIGFuaW1hdGlvbn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vUi1yYW1samFrL01OT19FdXJvc3RhdC9tYXN0ZXIvR2lmcy9hbnRlbm5hJTIwYW5pbWF0aW9uLmdpZiIpDQpgYGANCg0KQmFzaWNhbGx5LCBhIHRvd2VyIGlzIGdlbmVyYXRlZCBhdCBpdHMgc3BlY2lmaWVkIGxvY2F0aW9uLCB0aGVuIHRocmVlIGFudGVubmFzIGFyZSBjcmVhdGVkLiBGb3IgdGhlIG9wZXJhdGlvbmFsaXplZCBkYXRhIHN0cnVjdHVyZSwgdGhlIGFudGVubmEgbG9jYXRpb24gaXMgbm90IHJlYWxseSByZWxldmFudCBhcyBpdCBjb3JyZXNwb25kcyB0byB0aGUgcmVzcGVjdGl2ZSB0b3dlciBsb2NhdGlvbi4gV2hhdCBpcyBtb3JlIGltcG9ydGFudCBhcmUgdGhlIGFudGVubmFzJyAqY292ZXJhZ2UgYXJlYSBjZW50cm9pZHMqIGJlY2F1c2UgdGhleSBkZXNjcmliZSB0aGUgbWlkZGxlIHBvaW50IG9mIHRoZSB0aGVuIGdlbmVyYXRlZCBjaXJjdWxhciBjb3ZlcmFnZSBhcmVhLiBUaGUgc3BlY2lmaWMgcmFkaXVzIG9mIGFueSBnZW5lcmljIGNvdmVyYWdlIGFyZWEgaXMgbGF5ZXIgc3BlY2lmaWMgYW5kIGxpc3RlZCBhYm92ZS4gQXMgaW5kaWNhdGVkIGluIHRoZSBhbmltYXRpb24sIGFuIGFudGVubmEgc3BlY2lmaWMgY292ZXJhZ2UgYXJlYSBpcyBzZXR1cCB3aXRoIGEgdmFyaWFibGUgKmNvdmVyYWdlIGludGVuc2l0eSBwcm9maWxlKi4gQmFzaWNhbGx5LCBjZWxsIHBob25lcyB0aGF0IGFyZSBjbG9zZXIgdG8gdGhlIGNvdmVyYWdlIGFyZWEgY2VudHJvaWQgb2YgYW55IGFudGVubmEsIGhhdmUgYSBoaWdoZXIgY292ZXJhZ2UgcHJvYmFiaWxpdHksIHdoaWNoIHdpbGwgYmUgbGF0ZXIgaW50cm9kdWNlZCBhcyB0aGUgKnNpZ25hbCBzdHJlbmd0aCogcGFyYW1ldGVyLg0KDQpUaGUgZm9sbG93aW5nIHRhYmxlIHByZXNlbnRzIHRoZSBudW1iZXIgb2YgdG93ZXJzIGFuZCB0aGUgbnVtYmVyIG9mIGFudGVubmFzIG9mIGVhY2ggbGF5ZXIuIFRoZSBudW1iZXIgb2YgYW50ZW5uYXMgaXMgbm90IGFsd2F5cyBhIHBlcmZlY3QgZmFjdG9yIG9mIDMgYXMgdGhlIGNvdmVyYWdlIGFyZWFzIGFyZSBjcm9wcGVkIGFjY29yZGluZyB0byB0aGUgZm9jdXMgYXJlYS4gVGhpcyBtZWFucyBpZiB0aGUgY29tcGxldGUgY292ZXJhZ2UgYXJlYSBvZiBhbiBhbnRlbm5hIGxpZXMgb3V0c2lkZSBvZiB0aGUgZm9jdXMgYXJlYSBpdCBpcyBkaXNjYXJkZWQuDQoNCmBgYHtyIGNvdmVyYWdlIGFyZWFzIDF9DQp0aWxlLmNvdW50IDwtIGNlbnN1cy5kZS4xMDBtLnRpbGUgJT4lICANCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JSANCiAgZ3JvdXBfYnkocG9wLmFyZWEua2luZCkgJT4lICANCiAgc3VtbWFyaXNlKGFyZWEuaW4uc3Eua20gPSBuKCkgLyAxMDApICU+JSANCiAgYXJyYW5nZShkZXNjKHBvcC5hcmVhLmtpbmQpKSAlPiUgDQogIG11dGF0ZShhcmVhLmluLnNxLmttID0gY2FzZV93aGVuKHBvcC5hcmVhLmtpbmQgPT0gIlJ1cmFsIiB+IGN1bXN1bShhcmVhLmluLnNxLmttKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wLmFyZWEua2luZCA9PSAiU3VidXJiYW4iIH4gY3Vtc3VtKGFyZWEuaW4uc3Eua20pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3AuYXJlYS5raW5kID09ICJVcmJhbiIgfiBjdW1zdW0oYXJlYS5pbi5zcS5rbSkpKSAlPiUgDQogIGFycmFuZ2UocG9wLmFyZWEua2luZCkNCg0KY292ZXJhZ2UuYXJlYXMgJT4lICANCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JSAgDQogIGdyb3VwX2J5KGFyZWEua2luZCwgdG93ZXIuSUQpICU+JSAgDQogIHN1bW1hcmlzZShuLmFudGVubmEgPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAgDQogIHVuZ3JvdXAoKSAlPiUgIA0KICBncm91cF9ieShhcmVhLmtpbmQpICU+JSAgDQogIHN1bW1hcmlzZShuLnRvd2VyID0gbigpLCANCiAgICAgICAgICAgIG4uYW50ZW5uYSA9IHN1bShuLmFudGVubmEpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgIA0KICBsZWZ0X2pvaW4odGlsZS5jb3VudCwgYnkgPSBjKCJhcmVhLmtpbmQiID0gInBvcC5hcmVhLmtpbmQiKSkgJT4lICANCiAgZHBseXI6OnNlbGVjdChsYXllciA9IGFyZWEua2luZCwgbi50b3dlciwgbi5hbnRlbm5hLCBhcmVhLmluLnNxLmttKSAlPiUgIA0KICBrYmwoY2FwdGlvbiA9ICJEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHBlciBjb3ZlcmFnZSBsYXllciIpICU+JQ0KICBrYWJsZV9taW5pbWFsKCkgJT4lDQogIGZvb3Rub3RlKGdlbmVyYWwgPSAiYGFyZWEuaW4uc3Eua21gIHJlcG9ydHMgdGhlIGFjdHVhbCBhcmVhIHRoYXQgd2FzIHVzZWQgZm9yIHRoZSBnZW5lcmF0aW9uIG9mIHRoZSBjb3ZlcmFnZS4gVGhlcmVmb3JlLCB0aGUgZmlyc3QgbGF5ZXIgc3BhbnMgb3ZlciB0aGUgd2hvbGUgZm9jdXMgYXJlYSwgdGhlIHNlY29uZCBsYXllciBvdmVyIHRoZSBzdWJ1cmJhbiBhbmQgdXJiYW4gYXJlYSwgYW5kIHRoZSB0aGlyZCBsYXllciBvdmVyIHRoZSB1cmJhbiBhcmVhLiIpDQpgYGANCg0KQXMgZGVzY3JpYmVkIGluIHRoZSBwYXJhbWV0ZXIgbGlzdCBhYm92ZSwgcnVyYWwgYXJlYXMgYXJlIGNvdmVyZWQgb25seSBieSBsYXllciAxLCBzdWJ1cmJhbiBhcmVhcyBhcmUgY292ZXJlZCBieSBsYXllciAxIGFuZCAyIGFuZCB0aGUgdXJiYW5pemVkIGFyZWFzIGFyZSBjb3ZlcmVkIGJ5IGFsbCB0aHJlZSBsYXllcnMuIFRoZSBhdmVyYWdlIGRpc3RhbmNlIGJldHdlZW4gbXVsdGlwbGUgdG93ZXJzIG9mIHRoZSBzYW1lIGxheWVyIGRlY3JlYXNlIGluIGxheWVyIDIgYW5kIGxheWVyIDMgY29tcGFyZWQgdG8gbGF5ZXIgMS4gVGhpcyBsZWFkcyB0byBkZW5zZXIgbmV0d29ya3Mgd2l0aGluIHRoZXNlIGxheWVycyByZXByZXNlbnRlZCBieSB0aGUgaGlnaGVyIG51bWJlcnMgb2YgdG93ZXJzIGFuZCB0aGVyZWZvcmUgaGlnaGVyIG51bWJlcnMgb2YgYW50ZW5uYXMgaW4gbGF5ZXIgMiBhbmQgMywgZ2l2ZW4gdGhlaXIgYXJlYS4gVGhlIHJlYXNvbiBmb3IgdGhpcyBpcyB0aGF0IGFueSBnZW5lcmljIGFudGVubmEgY2FuIG9ubHkgb2ZmZXIgc2lnbmFsIHNlcnZpY2UgdG8gYSBsaW1pdGVkIGFtb3VudCBvZiBudW1iZXIgb2YgbW9iaWxlIHBob25lcy4gVG8gY292ZXIgYWxsIGNlbGwgcGhvbmVzIGluIG1vcmUgdXJiYW5pemVkIGFyZWFzIGEgZGVuc2VyIHJhZGlvIGNlbGwgbmV0d29yayBpcyBuZWVkZWQgaW4gdGhlc2UgYXJlYXMuDQoNClRoZSBmb2xsb3dpbmcgZmlndXJlcyBwcmVzZW50IHRoZSBhY3R1YWwgY292ZXJhZ2Ugb2YgZWFjaCBsYXllciBmb3IgdGhlIGZvY3VzIGFyZWEuDQoNCmBgYHtyIGNvdmVyYWdlIGFyZWFzIDIsIGZpZy5jYXAgPSAiVGhlIGNpcmNsZXMgcmVwcmVzZW50IHRoZSBjb3ZlcmFnZSBhcmVhIG9mIGVhY2ggYW50ZW5uYSBwZXIgbGF5ZXIuIFRoZSBzaWduYWwgZGVuc2l0eSBpbmNyZWFzZXMgd2l0aCBpbmNyZWFzaW5nIHBvcHVsYXRpb24gZGVuc2l0eS4ifQ0KY292ZXJhZ2UuYXJlYS5wbG90IDwtIGNvdmVyYWdlLmFyZWFzICU+JSAgDQogIGdncGxvdCgpICsgDQogIGdlb21fc2YoYWVzKGNvbCA9IGFyZWEua2luZCksIGZpbGwgPSBOQSkgKyANCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhhcmVhLmtpbmQpKSArIA0KICBnZ3RpdGxlKCIiKSArIA0KICAgIHNjYWxlX2NvbG9yX3B0b2woYnJlYWtzID0gYygiUnVyYWwiLCAiU3VidXJiYW4iLCAiVXJiYW4iKSwgIkxheWVyIikgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpLHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksDQogIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGhqdXN0ID0gMC41KSkNCg0KcGxvdF9ncmlkKGNvdmVyYWdlLmFyZWEucGxvdCwgbGFiZWxzID0gIkZpZy4gNTogQ292ZXJhZ2UgcGVyIGxheWVyIiwNCiAgICAgICAgICBoanVzdCA9IC0wLjEsIGxhYmVsX3NpemUgPSAxNCkgDQpgYGANCg0KVGhlIGludGVycHJldGF0aW9ucyBvZiB0aGUgdGFibGUgYWJvdmUgY29ycmVzcG9uZCB0byB0aGUgbGV2ZWwgb2YgY292ZXJhZ2Ugb2YgZWFjaCBsYXllci4gSXQgc2hvdWxkIGJlIG5vdGljZWQgdGhhdCB0aGUgYW50ZW5uYXMnIGNvdmVyYWdlIGFyZWFzIGFyZSBhbGxvd2VkIHRvIG92ZXJsYXAgLSB3aXRoIGFudGVubmFzIG9mIHRoZSBzYW1lIHRvd2VyLCBhcyB3ZWxsIGFzIGFjcm9zcyB0b3dlcnMgb2YgdGhlIHNhbWUgb3IgYW5vdGhlciBsYXllci4NCg0KYGBge3IgY292ZXJhZ2UgYXJlYXMgMywgZmlnLmNhcCA9ICJUaGUgZmlndXJlIG9uIHRoZSBsZWZ0IHNob3dzIHRoZSBnZW9ncmFwaGljYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSB0aWxlcyBjbGFzc2lmaWVkIGludG8gdGhlIHRocmVlIGxheWVycyBiYXNlZCBvbiB0aGUgc3BhdGlhbCBjbHVzdGVyaW5nLiBPbiB0aGUgcmlnaHQgc2lkZSwgdGhlIGNvdmVyYWdlIHBlciBsYXllciBpcyByZXByZXNlbnRlZC4gVGhlIGZ1bGwgY292ZXJhZ2UgY29ycmVzcG9uZHMgdG8gdGhlIHBvcHVsYXRpb24gZGVuc2l0eS4ifQ0KIyBJbXBsZW1lbnQgc2hhcGUgb2YgZm9jdXMgYXJlYQ0KY292ZXJhZ2UuYXJlYS5mdWxsLnBsb3QgPC0gY292ZXJhZ2UuYXJlYXMgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YoYWVzKGNvbCA9IGFyZWEua2luZCksIGZpbGwgPSBOQSkgKw0KICBnZ3RpdGxlKCIiLCBzdWJ0aXRsZSA9ICJGdWxsIGNvdmVyYWdlIikgKw0KICAgIHNjYWxlX2NvbG9yX3B0b2woYnJlYWtzID0gYygiUnVyYWwiLCAiU3VidXJiYW4iLCAiVXJiYW4iKSwgIkxheWVyIikgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBoanVzdCA9IDAuNSkpDQoNCnBsb3RfZ3JpZCh0cnVlLmdlby5ldmFsLnBsb3QsIGNvdmVyYWdlLmFyZWEuZnVsbC5wbG90LCBsYWJlbHMgPSAiRmlnLiA2OiBGdWxsIGNvdmVyYWdlIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGRlbnNpdHkiLCANCiAgICAgICAgICBoanVzdCA9IC0wLjEsIGxhYmVsX3NpemUgPSAxNCkNCmBgYA0KDQpGaWd1cmUgNiBwcmVzZW50cyB0aGUgZnVsbCBuZXR3b3JrIHN0cnVjdHVyZS4gQnkgY29tcGFyaW5nIHRoZSBuZXR3b3JrIHN0cnVjdHVyZSB0byB0aGUgdGlsZSBkZW5zaXR5IG9uZSBjYW4gc2VlIHRoYXQgZnVsbCwgcGFydGlhbGx5IG92ZXJsYXBwaW5nIGNvdmVyYWdlIGlzIGdyYW50ZWQgZm9yIGFsbCBhcmVhcyBhbmQgdGhhdCB0aGUgbmV0d29yayBsYXllcmluZyBzdHJ1Y3R1cmUgZm9sbG93cyBzdWl0IHdpdGggdGhlIHRydWUgZ2VvZ3JhcGhpY2FsIHBvcHVsYXRpb24gZGVuc2l0eS4NCg0KYGBge3IgY292ZXJhZ2UgaW50ZW5zaXR5LCBmaWcud2lkdGggPSA3LCBmaWcuY2FwPSBwYXN0ZTAoIlRoZSBkaXN0cmlidXRpb24gaXMgcmlnaHQgc2tld2VkIHdpdGggYSBtZWFuIG9mICIsIHJvdW5kKG1lYW4oY292ZXJhZ2UuaW50ZW5zaXR5JGNvdW50KSwgMiksIiwgYSBtaW5pbXVtIG9mICIsIG1pbihjb3ZlcmFnZS5pbnRlbnNpdHkkY291bnQpLCIsIGFuZCBhIG1heGltdW0gb2YgIiwgbWF4KGNvdmVyYWdlLmludGVuc2l0eSRjb3VudCksIiBhbnRlbm5hKHMpIHBlciB0aWxlLiIpfQ0KdGlsZXMuY2F0IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvd29ya2luZyBvYmplY3RzL2NvdmVyYWdlIGludGVuc2l0eS5yZHMiKQ0KY292ZXJhZ2UuaW50ZW5zaXR5IDwtIHRpbGVzLmNhdCAlPiUNCiAgIyBsZWZ0X2pvaW4oY2Vuc3VzLmRlLjEwMG0udGlsZSwgYnkgPSAiaW50ZXJuYWwuaWQiKSAlPiUgDQogICMgZHBseXI6OnNlbGVjdChpbnRlcm5hbC5pZCwgY291bnQsIHBvcC5hcmVhLmtpbmQpICU+JSANCiAgYXJyYW5nZShjb3VudCkgJT4lDQogIG11dGF0ZShwcm9iID0gMSAvIG4oKSkgJT4lDQogIG11dGF0ZShjdW0ucHJvYiA9IGN1bXN1bShwcm9iKSkNCg0KY292ZXJhZ2UuaW50ZW5zaXR5LnBsb3QgPC0gY292ZXJhZ2UuaW50ZW5zaXR5ICU+JQ0KICBnZ3Bsb3QoKSArDQogIHN0YXRfY291bnQoYWVzKGNvdW50KSwgZmlsbCA9ICIjNDQ3N0E5IikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKGNvdmVyYWdlLmludGVuc2l0eSRjb3VudCksIGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAiIzExNzczMyIsIHNpemUgPSAxLjUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuKGNvdmVyYWdlLmludGVuc2l0eSRjb3VudCksIGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAiI0NDNjY3NyIsIHNpemUgPSAxLjUpICsNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gbWVkaWFuKGNvdmVyYWdlLmludGVuc2l0eSRjb3VudCkgLSAyLCB5ID0gNWUrMDUsIGNvbG9yID0gIiNDQzY2NzciLA0KICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJNZWRpYW4gPSIsIG1lZGlhbihjb3ZlcmFnZS5pbnRlbnNpdHkkY291bnQpKSkgKw0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSByb3VuZChtZWFuKGNvdmVyYWdlLmludGVuc2l0eSRjb3VudCksIDIpICsgMiwgeSA9IDVlKzA1LCBjb2xvciA9ICIjMTE3NzMzIiwgDQogICAgICAgICAgIGxhYmVsID0gcGFzdGUoIk1lYW4gPSIsIHJvdW5kKG1lYW4oY292ZXJhZ2UuaW50ZW5zaXR5JGNvdW50KSwgMikpKSArDQogIGxhYnMoeSA9ICJDb3VudCBvZiB0aWxlcyIsIHggPSAiQ292ZXJlZCBieSAjIGFudGVubmFzIiwgY29sb3VyID0gIiIsIHRpdGxlID0gIiIpDQogICMgZmFjZXRfZ3JpZCh+cG9wLmFyZWEua2luZCkNCiAgDQogIA0KcGxvdF9ncmlkKGNvdmVyYWdlLmludGVuc2l0eS5wbG90LCBsYWJlbHMgPSAiRmlnLiA3OiBOdW1iZXIgb2YgYW50ZW5uYXMgY292ZXJpbmcgYSB0aWxlIiwNCiAgICAgICAgICBoanVzdCA9IC0wLjEsIGxhYmVsX3NpemUgPSAxNCkNCmBgYA0KDQpGaWd1cmUgNyBzaG93cyBhIGhpc3RvZ3JhbSByZXByZXNlbnRpbmcgdGhlIG51bWJlciBvZiBhbnRlbm5hcyBwZXIgdGlsZS4gVGhlIGRpc3RyaWJ1dGlvbiBpcyByaWdodCBza2V3ZWQgd2l0aCBhIG1lYW4gb2YgYHIgcm91bmQobWVhbihjb3ZlcmFnZS5pbnRlbnNpdHkkY291bnQpLCAyKWAsIGEgbWluaW11bSBvZiBgciBtaW4oY292ZXJhZ2UuaW50ZW5zaXR5JGNvdW50KWAgYW5kIGEgbWF4aW11bSBvZiBgciBtYXgoY292ZXJhZ2UuaW50ZW5zaXR5JGNvdW50KWAgYW50ZW5uYShzKSBwZXIgdGlsZS4gRXZlbiB0aG91Z2ggdGhlIGNvdmVyYWdlIGFyZWFzIHdlcmUgZ2VuZXJhdGVkIHN5bnRoZXRpY2FsbHksIHRoaXMgZGlzdHJpYnV0aW9uIG1pbWljcyBhIHJlYWxpc3RpYyBsYXlvdXQuDQoNCiMjIERldmljZS10by1jZWxsIGFzc29jaWF0aW9uDQoNCkF0IHRoaXMgc3RhZ2Ugd2UgaGF2ZSBhZGRlZCB0byB0aGUgZ2VvZ3JhcGhpY2FsbHkgZGlzdHJpYnV0ZWQgbW9iaWxlIHBob25lIHBvcHVsYXRpb24gYSByYWRpbyBuZXR3b3JrLCB3aGljaCBpcyBzZXR1cCBpbiB0aHJlZSBsYXllcnMsIHNwYW5uaW5nIHJlc3BlY3RpdmVseSBhY3Jvc3MgdGlsZXMgdGhhdCBjb3JyZXNwb25kIHRvIHNwZWNpZmljIHRpbGUgY2xhc3NpZmljYXRpb24uIChgcG9wLmFyZWEua2luZGApLg0KDQpUaGUgZm9sbG93aW5nIG1vZHVsZSB3aWxsIGVzdGFibGlzaCB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiBtb2JpbGUgcGhvbmVzIG9mIGEgZ2VuZXJpYyB0aWxlIHRvIGEgcmVsZXZhbnQgYW50ZW5uYS4gVGhlIHJlc3VsdCB3aWxsIGJlIGEgcmVmZXJlbmNlIG1hdHJpeCAkUCQgb2Ygc2l6ZSAkSSB4IEokLCB3aGVyZSBJIGRlbm90ZXMgdGhlIHRvdGFsIG51bWJlciBvZiByYWRpbyBjZWxscyAoYW50ZW5uYXMpLCAkSiQgaXMgdGhlIHRvdGFsIG51bWJlciBvZiB0aWxlcyBhbmQgdGhlIGVsZW1lbnRzIGNvcnJlc3BvbmQgdG8gdGhlIHByb2JhYmlsaXR5IG9mIHRoZSBtb2JpbGUgcGhvbmVzIG9mIGFueSB0aWxlICRqJCBhcmUgcmVnaXN0ZXJlZCBpbiB0aGUgY2VsbCAkaSQuIFdpdGggJFAkIG9uZSBpcyBhYmxlIHRvIHNpbXVsYXRlIHRoZSBjb2x1bW4gdmVjdG9yICRjJCAocmFuZG9tIHZhcmlhYmxlKSB3aGljaCBkZXNjcmliZXMgdGhlIHRvdGFsIGNvdW50IG9mIG1vYmlsZSBwaG9uZSBhc3NvY2lhdGVkIHRvIGEgcmFkaW8gY2VsbC4NCg0KQXNzdW1pbmcgdGhhdCAkXG1hdGhjYWx7TH1fe2p9JCBkZW5vdGVzIHRoZSBzdWJzZXQgb2YgcmFkaW8gY2VsbHMgY292ZXJpbmcgYSBwYXJ0aWN1bGFyIHRpbGUgKHJlbWVtYmVyLCBvdmVybGFwcGluZyBjb3ZlcmFnZSBhcmVhcyBhcmUgdmVyeSBjb21tb24pLiBUaGlzIG1lYW5zIHRoYXQgdGhlc2UgcmVzcGVjdGl2ZSByYWRpbyBjZWxscyBhcmUgY29tcGV0aW5nIHdpdGggZWFjaCBvdGhlciB0byBiZSBhc3NvY2lhdGVkIHdpdGggdGhlIGNlbGwgcGhvbmVzIGluIHRoZSB0aWxlLiBXZSB0aGVyZWZvcmUgYXNzaWduIHByb2JhYmlsaXRpZXMgd2hpY2ggZGVzY3JpYmUgdGhlIHJlc3BlY3RpdmUgYXNzb2NpYXRpb24gYmV0d2VlbiBhIHJhZGlvIGNlbGwgJGkkIGFuZCB0aWxlICRqJC4gVGhpcyBwcm9iYWJpbGl0eSBkZXBlbmRzIG9uIHRoZSBwYXJhbWV0ZXIgc2lnbmFsIHN0cmVuZ3RoIHdoaWNoIHdlIG1pbWljIHdpdGggYSBzaW1wbGUgbGluZWFyIGZ1bmN0aW9uIHRoYXQgZGVzY3JpYmVzIHRoZSBncmFkdWFsIGRlY3JlYXNlIGluIHNpZ25hbCB0aGUgZnVydGhlciBhd2F5IHRoZSB0aWxlIGNlbnRyb2lkICRqJCBpcyBmcm9tIHRoZSBjb3ZlcmFnZSBhcmVhIGNlbnRyb2lkIG9mICRpJDoNCg0KJCQNCnNfe2lqfSA9IFxmcmFje2Rfe2lqfX17cl97aX19DQokJA0KDQpXZSBiYXNpY2FsbHkgY2FsY3VsYXRlIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHRoZSB0d28gY2VudHJvaWRzLCAkZF97aWp9JCwgYW5kIGRpdmlkZSBpdCBiZXR3ZWVuIHRoZSByYWRpdXMgb2YgdGhhdCByYWRpbyBjZWxsLCAkcl97aX0kLSBpdCBpcyBkZW5vdGVkIGJ5ICRzX3tpan0kLiBXZSBpbnRyb2R1Y2UgYSBtaW5pbXVtIHRocmVzaG9sZCB2YWx1ZSAkXG51JCB3aGljaCBsaW1pdHMgcmFkaW8gY2VsbHMgd2l0aCBhIHRvbyBsb3cgc2lnbmFsIGludGVuc2l0eSAkc197aWp9JCBmb3IgYSBwYXJ0aWN1bGFyIHRpbGUgdG8gYmUgYWJsZSB0byBiZSBwaWNrZWQgdXAgYnkgYSBtb2JpbGUgcGhvbmUgaW4gdGhhdCB0aWxlIC0gcmVzdWx0aW5nIGluIHRoZSBtaW5pbXVtIHZhbHVlIG9mIDAuIFdlIGFsc28gaW50cm9kdWNlIGEgbWF4aW11bSB0aHJlc2hvbGQsIGRlc2NyaWJpbmcgdGlsZXMgdGhhdCBhcmUgdmVyeSBjbG9zZSB0byB0aGUgY292ZXJhZ2UgYXJlYSBjZW50cm9pZCwgaS5lLiBhIGhpZ2ggdmFsdWUgZm9yICRzX3tpan0kIC0tIHdoZW4gcGFzc2luZyB0aGlzIHRocmVzaG9sZCB0aGVpciByZXNwZWN0aXZlICRzX3tpan0kIHZhbHVlcyByZXN1bHQgaW4gdGhlIG1heGltdW0gdmFsdWUgMS4gVGhpcyBwYXJ0aWN1bGFyIG9wZXJhdGlvbmFsaXphdGlvbiBvZiBhIGZ1bmN0aW9uIG1vZGVsaW5nIHRoZSBzaWduYWwgc3RyZW5ndGggcGFyYW1ldGVyIGluc3RlYWQgb2YgZml4ZWQgY2F0ZWdvcmljYWwgc2lnbmFsIHN0cmVuZ3RoIHZhbHVlcyBtYWtlcyB0aGUgb3ZlcmFsbCB3b3JrZmxvdyBvZiB0aGUgbm90ZWJvb2sgbW9yZSByZWFsaXN0aWMgKGdyYW51bGFyaXR5KSBhbmQgbW9yZSBtb2R1bGFyIGFzIG9uZSBjYW4gbGF0ZXIgaW1wbGVtZW50IHZlcnkgZWFzeSBldmVuIG1vcmUgcmVhbGlzdGljIGZ1bmN0aW9ucyBkZXNjcmliaW5nIHRoZSBzaWduYWwgc3RyZW5ndGggcGFyYW1ldGVyLiBJbiB0aGlzIHNjZW5hcmlvIHdlIGhhdmUgaW1wbGVtZW50ZWQgYSBtaW5pbXVtIHRocmVzaG9sZCBvZiAkXG51ID0gMC4wMSQgYW5kIGEgbWF4aW11bSB0aHJlc2hvbGQgb2YgJFx6ZXRhID0gMC4wMSQgZGVwZW5kaW5nIG9uICRyX3tpfSQuIFRoZSBleGFjdCBvcGVyYXRpb25hbGl6YXRpb24gY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vUi1yYW1samFrL01OT19HTS9ibG9iL21hc3Rlci8zX2RldmljZSUyMHRvJTIwY2VsbC5SKS4NCg0KVGhlIGVsZW1lbnRzIG9mICRQJCAtIHRoZSBwcm9iYWJpbGl0eSB3aXRoIHdoaWNoIHRoZSBtb2JpbGUgcGhvbmVzIHdpdGhpbiBhIHBhcnRpY3VsYXIgY2VsbCBhcmUgYXNzb2NpYXRlZCB3aXRoIGEgcGFydGljdWxhciByYWRpbyBjZWxsIC0gYXJlIGRlZmluZWQgYnkNCg0KJCQNCnBfe2lqfSA9IFxmcmFje3Nfe2lqfX17XHN1bV97aSBcaW4gXG1hdGhjYWx7TH1fe2p9fSBzX3tpan19DQokJA0KDQp3aGVyZSAkc197aWp9JCBkZXNjcmliZXMgdGhlIHNpZ25hbCBpbnRlbnNpdHkgb2YgYSBwYXJ0aWN1bGFyIGNlbGwgJGkkIGFzc29jaWF0ZWQgd2l0aCBhIHBhcnRpY3VsYXIgdGlsZSAkaiQsIGFuZCAkXG1hdGhjYWx7TH1fe2p9JCBkZXNjcmliZXMgdGhlIHN1YnNldCBvZiByYWRpbyBjZWxscyB0aGF0IGFyZSBjb3ZlcmluZyB0aGUgdGlsZSAkaiQuIFdlIHRoZW4gc2ltdWxhdGUgdGhlIHRpbGUgc3BlY2lmaWMgZXhwZXJpbWVudHMgLSBldmVyeSBtb2JpbGUgcGhvbmUgd2l0aGluIGEgdGlsZSB3aWxsIGJlIGluZGVwZW5kZW50bHkgYXNzaWduZWQgdG8gcmVsZXZhbnQgcmFkaW8gY2VsbCB3aXRoIHRoZSBwcm9iYWJpbGl0eSAkcF97aWp9JC4gVGhlIHJlc3VsdCBpcyB0aGUgY29sdW1uIHZlY3RvciAkYyQgd2hpY2ggd2lsbCBhY3QgYXMgYSByZWZlcmVuY2UgZm9yIHRoZSBsYXRlciBvbiBpbnRyb2R1Y2VkIGVzdGltYXRpb24gc3RyYXRlZ2llcy4NCg0KDQoNCmBgYHtyIGMudmVjdG9yLmRpc3RyaWJ1dGlvbiwgZmlnLmNhcD0gIk9uIHRoZSBsZWZ0IG9uZSBjYW4gc2VlIHRoZSBzeW50aGV0aWMgZGlzdHJpYnV0aW9uIG9mIHRoZSBzaWogcGFyYW1ldGVyIGRlcGVuZGluZyBvbiB0aGUgbmV0d29yayBsYXllci4gVGhlIHNwZWNpZmllZCBQYXRoIGxvc3MgZXhwb25lbnQgY29udHJvbHMgc2lqIGluIGEgd2F5IHRoYXQgaXQgZmF2b3JzIExheWVyIDMgYW50ZW5uYXMgYW5kIHNhbmN0aW9ucyBMYXllciAxIGFudGVubmFzIGluIG9yZGVyIHRvIGJhbGFuY2UgdGhlIHJlc3VsdGluZyBjLnZlY3Rvci4gT24gdGhlIHJpZ2h0IG9uZSBjYW4gc2VlIHRoYXQgbW9iaWxlIGRldmljZXMgYXJlIHByZWRvbWluYXRlbHkgYXNzb2NpYXRlZCB3aXRoIExheWVyIDEgYW50ZW5uYXMuIn0NCg0Kc2lnbmFsLnN0cmVuZ3RoLnBsb3QgPC0gcmVhZFJEUygiVnlzb2vDoSDFoWtvbGEgZWtvbm9taWNrw6EgdiBQcmF6ZS9Ub255IFdlaSBUc2UgSHVuZyAtIFlBWS9QbG90cy9zaWduYWwuc3RyZW5ndGguZGlzdC5wbG90LnJkcyIpDQoNCkMudmVjLmRmIDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvd29ya2luZyBvYmplY3RzL0MudmVjLmRmLmZpbmFsLm5ldy5yZHMiKQ0KIyBFQ0NERiBvZiBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbiANCkVDQ0RGLnBob25lcy5kYXRhIDwtIEMudmVjLmRmICU+JSANCiAgbXV0YXRlKGxheWVyID0gY2FzZV93aGVuKHN0cl9kZXRlY3QoYW50ZW5uYS5JRCwgIlJUIikgfiAiTGF5ZXIgMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KGFudGVubmEuSUQsICJTVCIpIH4gIkxheWVyIDIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChhbnRlbm5hLklELCAiVVQiKSB+ICJMYXllciAzIikpICU+JSANCiAgYXJyYW5nZShwaG9uZXMuc3VtKSAlPiUgIA0KICBtdXRhdGUocHJvYiA9IDEgLyBuKCkpICU+JSAgDQogIG11dGF0ZShjdW0ucHJvYiA9IGN1bXN1bShwcm9iKSkgJT4lIA0KICBtdXRhdGUoY3VtLnByb2IuY29tcCA9IDEgLSBjdW0ucHJvYikgJT4lIA0KICBtdXRhdGUobG9nMTAuY3VtLnByb2IuY29tcCA9IGxvZzEwKDEgLSBjdW0ucHJvYikpICU+JSAgDQogIG11dGF0ZShsb2cxMC5waG9uZXMgPSBsb2cxMChwaG9uZXMuc3VtKSkNCg0KRUNDREYucGhvbmVzLnBsb3QgPC0gRUNDREYucGhvbmVzLmRhdGEgJT4lICAgDQogIGdncGxvdCgpICsgDQogIGdlb21fcG9pbnQoYWVzKHggPSBsb2cxMC5waG9uZXMsIHkgPSBsb2cxMC5jdW0ucHJvYi5jb21wLCANCiAgICAgICAgICAgICAgICAgY29sb3IgPSBsYXllcikpICsgDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0wLjMwMTAzMDAsIGxpbmV0eXBlID0gImRvdHRlZCIpICsgDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC0xLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArIA0KICBnZW9tX3RleHQoeCA9IDAuOCwgeSA9IC0wLjIsIGxhYmVsID0gIjUwJSBvZiB0aGUgZGF0YSIpICsgDQogIGdlb21fdGV4dCh4ID0gMC44LCB5ID0gLTAuOSwgbGFiZWwgPSAiOTAlIG9mIHRoZSBkYXRhIikgKyANCiAgc2NhbGVfY29sb3JfcHRvbChicmVha3MgPSBjKCJMYXllciAxIiwgIkxheWVyIDIiLCAiTGF5ZXIgMyIpKSArIA0KICB5bGltKC00LCAwKSArDQogIGdndGl0bGUoIiIsIHN1YnRpdGxlID0gIkVDQ0RGIGFuZCBFQ0RGIikgKw0KICBsYWJzKHkgPSAibG9nMTAoUHJvYihZID4geCkpIiwgeCA9ICJsb2cxMChNb2JpbGUgcGhvbmVzKSIsIGNvbG91ciA9ICIiKSsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0xMCwgZmFjZT0iYm9sZCIsIGhqdXN0ID0gMC41KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID05LGhqdXN0ID0gMC41KSkNCkVDREYucGhvbmVzLnBsb3QgPC0gRUNDREYucGhvbmVzLmRhdGEgJT4lICAgDQogIGdncGxvdCgpICsgDQogIGdlb21fcG9pbnQoYWVzKHggPSBwaG9uZXMuc3VtLCB5ID0gY3VtLnByb2IuY29tcCwgY29sb3IgPSBsYXllcikpICsgDQogIHNjYWxlX2NvbG9yX3B0b2woYnJlYWtzID0gYygiVW5pbmhhYml0YXRlZCIsICJSdXJhbCIsICJTdWJ1cmJhbiIsICJVcmJhbiIpLCBndWlkZSA9IEZBTFNFLCBleHBhbmQgPSBjKDAsIDApKSArDQogIGxhYnMoeSA9ICIiLCB4ID0gIiIpICsNCiAgeGxpbSgwLCA4MDAwKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGhqdXN0ID0gMC41KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpDQpwb3AuZGlzdC5lY2RmLmluc2VydCA8LSBFQ0NERi5waG9uZXMucGxvdCArDQogIGFubm90YXRpb25fY3VzdG9tKGdncGxvdEdyb2IoRUNERi5waG9uZXMucGxvdCksIA0KICAgICAgICAgICAgICAgICAgICB4bWluID0gMCwgeG1heCA9IDMsIA0KICAgICAgICAgICAgICAgICAgICB5bWluID0gLTQsIHltYXggPSAtMS41KQ0KICAgIA0KcGxvdF9ncmlkKHNpZ25hbC5zdHJlbmd0aC5wbG90LCBwb3AuZGlzdC5lY2RmLmluc2VydCwgbGFiZWxzID0gIkRldmljZS10by1jZWxsIGFzc29jaWF0aW9uIiwgIGhqdXN0ID0gLTAuMSwgbGFiZWxfc2l6ZSA9IDE0KQ0KYGBgDQoNCg0KDQojIEVzdGltYXRpb24gc3RyYXRlZ2llcw0KDQpXZSBoYXZlIGltcGxlbWVudGVkIHR3byBzcGVjaWZpYyBlc3RpbWF0aW9uIHN0cmF0ZWdpZXM6DQoNCi0gICBWb3Jvbm9pIHRlc3NlbGF0aW9uICh0b3dlciBsb2NhdGlvbnMgT1IgY292ZXJhZ2UgYXJlYSBjZW50cm9pZHMgYXMgc2VlZHMpDQoNCi0gICBNTEUgUG9pc3Nvbg0KDQpBbGwgdGhyZWUgb2YgdGhlc2UgZXN0aW1hdGlvbiB0ZWNobmlxdWVzIHByb2R1Y2UgYSB0aWxlIHNwZWNpZmljIGVzdGltYW5kLiBUaGUgc3VtIG9mIHRoZXNlIGVzdGltYW5kcyBhbHdheXMgZXhhY3RseSBlcXVhbHMgdGhlIHN1bSBvZiB0aGUgYy52ZWN0b3IsIGkuZS4gYWxsIHJlZ2lzdGVyZWQgbW9iaWxlIHBob25lcy4gVGhpcyBjaGFyYWN0ZXJpc3RpYyBleHBsYWlucyB0aGUgc3RyYXRlZ3kgb2YgYWxsIG9mIHRoZXNlIGVzdGltYXRvcnM6IFRha2luZyB0aGUgY29tcGxldGUgbnVtYmVyIG9mIHJlZ2lzdGVyZWQgcGhvbmVzIGluIHRoZSBjLnZlY3RvciBhbmQgYWxsb2NhdGluZyB0aGVtIGFjcm9zcyBhbGwgdGhlIHRpbGVzLiBUaGVyZSBpcyBob3dldmVyIGEgZnVuZGFtZW50YWwgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gZXN0aW1hdG9yczogVGhlIHNlY29uZCBvbmUgYWxsb3dzIGZvciB0aGUgcmVhbGlzdGljIHNldHRpbmcgb2Ygb3ZlcmxhcHBpbmcgYW50ZW5uYSBjb3ZlcmFnZS4gQXMgc2hvd24gYWJvdmUgdGhlcmUgYXJlIG1hbnkgdGlsZXMgdGhhdCBhcmUgY292ZXJlZCBieSBtdWx0aXBsZSBhbnRlbm5hcy4gQ3VycmVudCByZXNlYXJjaCBzdWdnZXN0cyB0aGF0IHRoaXMgY2FuIHJlc3VsdCBpbiBtb3JlIGFjY3VyYXRlIGVzdGltYXRpb25zLg0KDQojIyBWb3Jvbm9pIHRlc3NlbGF0aW9uDQoNClZvcm9ub2kgdGVzc2VsYXRpb24gdXNlcyBzZWVkcyB0byBjYWxjdWxhdGUgVm9yb25vaSByZWdpb25zLiBGb3IgZXZlcnkgc2VlZCB0aGVyZSBpcyBvbmUgVm9yb25vaSByZWdpb24gdGhhdCBjb250YWlucyB0aGUgYXJlYSB0aGF0IGlzIGNsb3Nlc3QgdG8gdGhlIHBhcnRpY3VsYXIgc2VlZC4gVGhlcmUgYXJlIHR3byBzZWVkIHNwZWNpZmljYXRpb25zIHdlIGFyZSBpbnRlcmVzdGVkIGluOg0KDQotICAgVG93ZXIgbG9jYXRpb25zIGFzIHNlZWRzIC0tXD4gYG4gPWAgYHIgbGVuZ3RoKHVuaXF1ZShjb3ZlcmFnZS5hcmVhcyR0b3dlci5JRCkpYA0KDQotICAgQ292ZXJhZ2UgYXJlYSBjZW50cm9pZCAocGVyIGFudGVubmEpIGxvY2F0aW9ucyBhcyBzZWVkcyAtLVw+IGBuID1gIGByIGxlbmd0aCh1bmlxdWUoY292ZXJhZ2UuYXJlYXMkYW50ZW5uYS5JRCkpYA0KDQpCZWxvdyB3ZSBzcGVjaWZ5IHRoZSB0b3dlciBsb2NhdGlvbnMgYXMgc2VlZCBwb2ludHMuIFRoZXNlIGFyZSB0aGVuIHVzZWQgdG8gY29tcHV0ZSB0aGUgVm9yb25vaSByZWdpb25zLiBCZWZvcmUgd2UgZG8gdGhhdCB3ZSBuZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IHRoZSBjb3JyZXNwb25kaW5nIGMudmVjdG9yIGlzIGFnZ3JlZ2F0ZWQgb24gdGhlIHRvZXIgbGV2ZWwuIFdlIHRoZW4gam9pbiB0aGUgVm9yb25vaSByZWdpb25zIHdpdGggdGhlIHRpbGVzIHRvIGNyZWF0ZSBhbiBvYmplY3QgdGhhdCBsaW5rcyB0aWxlcyB3aXRoaW4gcmVzcGVjdGl2ZSBWb3Jvbm9pIHJlZ2lvbnMuDQoNCmBgYHtyIHZvcm9ub2kgYW50ZW5uYSBhbmQgdG93ZXIgcHJlcCBwbG90LCBmaWcuY2FwPSJUaGUgdG93ZXIgY2VudHJvaWRzIHdlcmUgdXNlZCBhcyBzZWVkcyBmb3IgdGhlIGNyZWF0aW9uIG9mIHRoZSBWb3Jvbm9pIHJlZ2lvbnMuIFRoZSBjb2xvciBzY2FsZSBpcyBkZWZpbmVkIGJ5IHRoZSBsb2cgd2l0aCBiYXNlIDEwIGxvY2FsIGRlbnNpdHkgaS5lLiB0aGUgYWJzb2x1dGUgbnVtYmVyIG9mIG1vYmlsZSBwaG9uZXMgd2l0aGluIGEgVm9yb25vaSByZWdpb24gZGl2aWRlZCBieSBhYnNvbHV0ZSBhcmVhIG9mIHRoZSByZXNwZWNpdHZlIFZvcm9ub2kgcmVnaW9uLiJ9DQoNCiMgUGxvdCByZWFkIGluDQpWVC5wbG90IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvd29ya2luZyBvYmplY3RzL1ZULnBsb3QucmRzIikNClZBLnBsb3QgPC0gcmVhZFJEUygiVnlzb2vDoSDFoWtvbGEgZWtvbm9taWNrw6EgdiBQcmF6ZS9Ub255IFdlaSBUc2UgSHVuZyAtIFlBWS93b3JraW5nIG9iamVjdHMvVkEucGxvdC5yZHMiKQ0KDQpwbG90X2dyaWQoVlQucGxvdCwgVkEucGxvdCwgbGFiZWxzID0gIkZpZy4gMTA6IFZvcm9ub2kgdG93ZXIgZXN0aW1hdGlvbiIsICBoanVzdCA9IC0wLjEsIGxhYmVsX3NpemUgPSAxNCkNCg0KYGBgDQoNCg0KV2UgaGF2ZSBub3cgY3JlYXRlZCB0aGUgVm9yb25vaSByZWdpb25zIGZvciBvdXIgZm9jdXMgYXJlYSB3aXRoIHRvd2VyIGxvY2F0aW9ucyBhcyBzZWVkcyBhcyB3ZWxsIGFzIHdpdGggYW50ZW5uYSByZXNwZWN0aXZlIGNvdmVyYWdlIGFyZWEgY2VudHJvaWQgbG9jYXRpb25zIGFzIHNlZWRzLiBUaGUgbnVtYmVyIG9mIHNlZWRzIGFuZCBWb3Jvbm9pIHJlZ2lvbnMgYWxpZ24gd2l0aCBlYWNoIG90aGVyLg0KDQpUaGUgc3BhdGlhbCBkZW5zaXR5IHBlciB0aWxlIGNhbiBiZSBleHByZXNzZWQgYXMgdGhlIHJhdGlvIG9mIHRoZSBtb2JpbGUgcGhvbmVzIGluIHRoYXQgcmVnaW9uIGFuZCB0aGUgYXJlYSBvZiB0aGUgVm9yb25vaSByZWdpb246DQoNCiRkX3trfSA9IFxmcmFje1xzdW0gY197aX19IHtBX3trfX0kDQoNClRoaXMgcmVnaW9uIHNwZWNpZmljIGVzdGltYXRlIGNvcnJlc3BvbmRzIHRvIHRoZSB0aWxlIGVzdGltYXRlIGZvciBhIHRpbGUgdGhhdCBpcyBjb250YWluZWQgaW4gdGhpcyByZWdpb24uIE9uIHRoZSB0aWxlIGxldmVsIHRoZXJlIGNhbiBiZSB0d28gY2FzZXMgdGhhdCB3ZSBuZWVkIHRvIGRpZmZlcmVudGlhdGU6DQoNCi0gICBUaWxlcyB0aGF0IGFyZSBjb21wbGV0ZWx5IGNvbnRhaW5lZCB3aXRoaW4gb25lIFZvcm9ub2kgcmVnaW9uIA0KDQotICAgVGlsZXMgdGhhdCBpbnRlcnNlY3Qgd2l0aCB0d28gb3IgbW9yZSBWb3Jub2kgcmVnaW9ucw0KDQpGb3IgdGhlIGZpcnN0IGNhc2UsIHRoZSB0aWxlIHNwZWNpZmljIGVzdGltYXRlIGNvcnJlc3BvbmRzIHRvICRkX3trfSQuIEZvciB0aGUgc2Vjb25kIGNhc2Ugd2Ugd2lsbCBjYWxjdWxhdGUgYSB3ZWlnaHRlZCBtZWFuIG9mIHRoZSByZWxldmFudCBWb3Jvbm9pIHJlZ2lvbiBlc3RpbWF0ZXMgYnkgdXNpbmcgdGhlIGNvcnJlc3BvbmRpbmcgdGlsZSBhcmVhIHdpdGhpbiBlYWNoIFZvcm9ub2kgcmVnaW9uIGFzIHdlaWdodHMuIA0KDQpgYGB7ciBWb3Jvbm9pIHRvd2VyIG11bHRpcGxlcywgZmlnLmNhcD0iVGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgdGlsZSB0aGF0IGludGVyc2VjdHMgd2l0aCBtdWx0aXBsZSBWb3Jvbm9pIHJlZ2lvbnMuIFRoZSBsYWJlbHMgYW5kIG51bWJlciBjb3JyZXNwb25kIHRvIHRoZSBWb3Jvbm9pIHJlZ2lvbiBhbmQgdGhlIGdpdmVuIGFyZWEgdGhhdCBhcmUgdXNlZCBhcyB3ZWlnaHRzIGZvciB0aGUgd2VpZ2h0ZWQgbWVhbiBlc3RpbWF0b3IuIn0NCg0KVlQuYmlyZC5leGFtcGxlLnBsb3QgPC0gcmVhZFJEUygiVnlzb2vDoSDFoWtvbGEgZWtvbm9taWNrw6EgdiBQcmF6ZS9Ub255IFdlaSBUc2UgSHVuZyAtIFlBWS93b3JraW5nIG9iamVjdHMvVlQuYmlyZC5leGFtcGxlLnBsb3QucmRzIikNCg0KVlQuZXhhbXBsZS5wbG90IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvd29ya2luZyBvYmplY3RzL1ZULmV4YW1wbGUucGxvdC5yZHMiKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQ0KDQpwbG90X2dyaWQoVlQuYmlyZC5leGFtcGxlLnBsb3QsIFZULmV4YW1wbGUucGxvdCwgDQogICAgICAgICAgbGFiZWxzID0gIkZpZy4gMTE6IEV4YW1wbGUgbXVsdGlwbGUgdGlsZSIsICBoanVzdCA9IC0wLjEsIGxhYmVsX3NpemUgPSAxNCkNCmBgYA0KDQpIZXJlIHdlIHZpc3VhbGl6ZSB0aGUgc2Vjb25kIGNhc2Ugd2l0aCBhbiBleGFtcGxlIHRpbGUgYW5kIGV4YW1wbGUgVm9yb25vaSByZWdpb25zIGZyb20gdGhlIFZvcm9ub2kgd2l0aCB0b3dlciBsb2NhdGlvbnMgYXMgc2VlZHMuIEluIHRoZSBsZWZ0IHBsb3Qgd2UgY2FuIHNlZSBhIHNtYWxsIHRpbGUgdGhhdCBpcyBpbmRpY2F0ZWQgaW4gcmVkLiBUaGlzIHRpbGUgaXMgYXQgdGhlIGludGVyc2VjdGlvbiBvZiA0IFZvcm9ub2kgcmVnaW9ucy4gVGhlIGNvcnJlc3BvbmRpbmcgcmVsYXRpdmUgdGlsZSBhcmVhIGludGVyc2VjdGluZyB3aXRoIGVhY2ggVm9yb25vaSByZWdpb24gY2FuIGJlIHNlZW4gaW4gdGhlIHJpZ2h0IHBsb3QuIFRoZSBsYWJlbHMgY29ycmVzcG9uZCB0byB0aGUgVm9yb25vaSByZWdpb24gSUQgYW5kIHRoZSBiZWxvdyBpbiBicmFja2V0cyBpbmRpY2F0ZSB0aGUgcHJvcG9ydGlvbmFsIHdlaWdodCB0aGF0IHNob3VsZCBiZSBjb25zaWRlcmVkIGluIGNhbGN1bHRpbmcgdGhlIHRpbGUgc3BlY2lmaWMgd2VpZ2h0ZWQgbWVhbiBlc3RpbWF0ZS4gVG8gY29tcGFyZSB0aGlzIHRvIHRoZSBmaXJzdCBjYXNlIC0gd2hlcmUgYSB0aWxlIGlzIGZ1bGx5IGNvbnRhaW5lZCBvbmx5IGluIG9uZSByZWdpb24gLSB0aGUgd2VpZ2h0IGZvciB0aGUgcGFydGljdWxhciBWb3Jvbm9pIHJlZ2lvbiBpcyAxLiBUaGUgc2FtZSBtZXRob2RvZ29sZ3kgaXMgcHVyc3VlZCBmb3IgdGhlIFZvcm9ub2kgYW50ZW5uYSBjYXNlLg0KDQoNCiMjIE1MRSBQb2lzc29uDQoNCk1MRSBQb2lzc29uOiAkXGhhdHt1fV57bSsxfV97an0gPSBcaGF0e3V9XnttfV97an1cc3VtX3tpID0gMX1ee0l9IGNfe2l9IFxmcmFje3Bfe2lqfX17XHN1bV97ayA9IDF9XntKfSBwX3tpa30gXGhhdHt1fV57bX1fe2t9fSQNCg0KDQojIEV2YWx1YXRpb24gb2YgYWxsIGVzdGltYXRlcw0KDQpXZSBjcmVhdGVkIDQgZmluYWwgZXN0aW1hdGVzOg0KDQotICAgVm9yb25vaSB0ZXNzZWxhdGlvbiB3aXRoIHRvd2VyIGxvY2F0aW9ucyBhcyBzZWVkcw0KDQotICAgVm9yb25vaSB0ZXNzZWxhdGlvbiB3aXRoIGNvdmVyYWdlIGFyZWEgbG9jYXRpb25zIChhbnRlbm5hcykgYXMgc2VlZHMNCg0KLSAgIE1MRSB1bmlmb3JtIHByaW9yIGVxdWFsIHByb2JhYmlsaXR5IFAubWF0cml4IGFmdGVyIDEwMDAgaXRlcmF0aW9ucw0KDQotICAgTUxFIHVuaWZvcm0gcHJpb3Igb3JhY2xlIHByb2JhYmlsaXR5IFAubWF0cml4IGFmdGVyIDEwMDAgaXRlcmF0aW9ucw0KDQpJbiB0aGUgZm9sbG93aW5nIHdlIGNvbXBhcmUgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIGZpbmFsIGVzdGltYXRlcyB0byB0aGUgdHJ1ZSBkaXN0cmlidXRpb24gb2YgdGhlIG1vYmlsZSBwaG9uZSBkZW5zaXR5IHBlciB0aWxlLiBTaWduZmljYW50IHZhcmlhdGlvbiBjYW4gb25seSBiZSB2aWV3ZWQgaW4gdGhlIHRhaWxzIG9mIHRoZSBkaXJzdGJ1dGlvbiAoRUNDREYpLg0KDQpgYGB7ciBlc3RpbWF0b3IgcG9wIGRpc3QgY29tcGFyZSwgZmlnLmNhcD0iSW4gdGhpcyBwbG90IG9uZSBjYW4gc2VlIHRoZSBkaWZmZXJlbmNlIGluIEVDQ0RGIGFuZCBFQ0RGIG9mIHRoZSBmaW5hbCBlc3RpbWF0ZXMgb2YgdGhlIGRpZmZlcmluZyBzdHJhdGVnaWVzIGNvbXBhcmVkIHRvIHRoZSB0cnVlIG1vYmlsZSBwaG9uZSBkZW5zaXR5LiJ9DQpFQ0NERi5jb21wYXJlIDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvRXN0aW1hdGVzL1Bsb3QuZmlsZXMvRUNDREYuZXN0aW1hdGVzLnJkcyIpDQoNCkVDREYuY29tcGFyZSA8LSByZWFkUkRTKCJWeXNva8OhIMWha29sYSBla29ub21pY2vDoSB2IFByYXplL1RvbnkgV2VpIFRzZSBIdW5nIC0gWUFZL0VzdGltYXRlcy9QbG90LmZpbGVzL0VDREYuZXN0aW1hdGVzLnJkcyIpICsgIHhsaW0oMCwgMTAwMCkgKw0KICBsYWJzKHkgPSAiIiwgeCA9ICIiKQ0KDQojICMgbm9jaCBhbnBhc3NlbiEhDQojIA0KcG9wLmRpc3QuZXN0aW1hdGVzLmNvbXBhcmUgPC0gRUNDREYuY29tcGFyZSArDQogIGFubm90YXRpb25fY3VzdG9tKGdncGxvdEdyb2IoRUNERi5jb21wYXJlKSwNCiAgICAgICAgICAgICAgICAgICAgeG1pbiA9IDAsIHhtYXggPSAxLjUsDQogICAgICAgICAgICAgICAgICAgIHltaW4gPSAtNiwgeW1heCA9IC0zKQ0KDQoNCnBsb3RfZ3JpZChwb3AuZGlzdC5lc3RpbWF0ZXMuY29tcGFyZSwgDQogICAgICAgICAgbGFiZWxzID0gIkVzdGltYXRvciBkZW5zaXR5IGNvbXBhcmlzb24iLCAgaGp1c3QgPSAtMC4xLCBsYWJlbF9zaXplID0gMTQpDQpgYGANCg0KDQpJbiB0aGlzIHNlY3Rpb24gd2Ugd2FudCB0byBmdXJ0aGVyIGV2YWx1YXRlIHRoZSA0IGVzdGltYXRlcyBieSBjb21wYXJpbmcgdGhlbSB3aXRoIGRpZmZlcmVudCBwZXJzcGVjdGl2ZXMgaW4gbWluZCB0byB0aGUgYWN0dWFsIHRydWUgcG9wdWxhdGlvbi4gRWFjaCBzdWJzZWN0aW9uIGRlZmluZXMgdGhlIHBlcnNwZWN0aXZlLXJlc3BlY3RpdmUgcGVyZm9ybWFuY2UgbWVhc3VyZToNCg0KVGhpcyBzZWN0aW9uIGlzIHN0aWxsIHVuZGVyIGNvbnN0cnVjdGlvbi4gV2Ugd2lsbCBldmFsdWF0ZSB0aGUgZXN0aW1hdG9ycyBhbmQgdGhlaXIgY29udmVyZ2VuY2UgYmVoYXZpb3VyIGZyb20gdGhyZWUgcGVyc3BlY3RpdmVzOg0KDQoxLiAgR2VvZ3JhcGhpY2FsIGV2YWx1YXRpb24NCg0KMi4gIFN0YXRpc3RpY2FsIGV2YWx1YXRpb24NCg0KDQojIyBHZW9ncmFwaGljYWwgRXZhbHVhdGlvbg0KDQpGb3IgdGhlIGdlb2dyYXBoaWNhbCBldmFsdWF0aW9uIHdlIHVzZSB0aGUgZm9sbG93aW5nIHBlcmZvcm1hbmNlIG1lYXN1cmU6IFRoZSB2aXN1YWwgcmVzZW1ibGFuY2Ugb2YgZml4ZWQgdGlsZSBjYXRlZ29yaWVzIGZyb20gdGhlIHJlc3BlY3RpdmUgZXN0aW1hdGUgYW5kIHRoZSBhY3R1YWwgdHJ1ZSBwb3B1bGF0aW9uIG9uIGEgbWFwLiAgICANCg0KV2UgYmFzaWNhbGx5IGJ1aWxkIGEgbWFwIGZvciBldmVyeSBmaW5hbCBlc3RpbWF0ZSBhbmQgY29tcGFyZSBpdCB0byB0aGUgYWN0dWFsIHRydWUgcG9wdWxhdGlvbi4gV2Ugc3RpbGwgbmVlZCB0byBpbnRlcnByZXQgYWxsIG9mIHRoZW0uDQoNCmBgYHtyIFZvcm9ub2kgdG93ZXIgZ2VvIGV2YWx9DQp0cnVlLmdlby5ldmFsLnBsb3QgPC0gcmVhZFJEUygiVnlzb2vDoSDFoWtvbGEgZWtvbm9taWNrw6EgdiBQcmF6ZS9Ub255IFdlaSBUc2UgSHVuZyAtIFlBWS9Fc3RpbWF0ZXMvUGxvdC5maWxlcy90cnVlLnBvcF9tYXAucmRzIikNCg0KVlQuZ2VvLmV2YWwucGxvdCA8LSByZWFkUkRTKCJWeXNva8OhIMWha29sYSBla29ub21pY2vDoSB2IFByYXplL1RvbnkgV2VpIFRzZSBIdW5nIC0gWUFZL0VzdGltYXRlcy9QbG90LmZpbGVzL1ZULmVzdGltYXRlX21hcC5yZHMiKQ0KDQoNCnBsb3RfZ3JpZCh0cnVlLmdlby5ldmFsLnBsb3QsIFZULmdlby5ldmFsLnBsb3QsDQogICAgICAgICAgbGFiZWxzID0gIkZpZy4gMTQgQ29tcGFyaW5nIFZvcm9ub2kgdG93ZXIgZXN0aW1hdGUiLCBsYWJlbF9zaXplID0gMTIsDQogICAgICAgICAgYWxpZ24gPSAiaHYiLCBoanVzdCA9IC0wLjEpDQoNCmBgYA0KDQpgYGB7ciBWb3Jvbm9pIGFudGVubmEgZ2VvIGV2YWx9DQpWQS5nZW8uZXZhbC5wbG90IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvRXN0aW1hdGVzL1Bsb3QuZmlsZXMvVkEuZXN0aW1hdGVfbWFwLnJkcyIpDQoNCnBsb3RfZ3JpZCh0cnVlLmdlby5ldmFsLnBsb3QsIFZBLmdlby5ldmFsLnBsb3QsDQogICAgICAgICAgbGFiZWxzID0gIkZpZy4gMTUgQ29tcGFyaW5nIFZvcm9ub2kgYW50ZW5uYSBlc3RpbWF0ZSIsIGxhYmVsX3NpemUgPSAxMiwNCiAgICAgICAgICBhbGlnbiA9ICJodiIsIGhqdXN0ID0gLTAuMSkNCmBgYA0KDQpgYGB7ciBNTEUgZXF1YWwgZ2VvIGV2YWx9DQojIE1MRS5lcXVhbC5nZW8uZXZhbC5wbG90IDwtIHJlYWRSRFMoIlZ5c29rw6EgxaFrb2xhIGVrb25vbWlja8OhIHYgUHJhemUvVG9ueSBXZWkgVHNlIEh1bmcgLSBZQVkvRXN0aW1hdGVzL1Bsb3QuZmlsZXMvTUxFLm9yYWNsZS5lc3RpbWF0ZV9tYXAucmRzIikNCiMgYW5pbWF0ZShNTEUuZXF1YWwuZ2VvLmV2YWwucGxvdCwgZnBzID0gMTApDQoNCiMgcGxvdF9ncmlkKHRydWUuZ2VvLmV2YWwucGxvdCwgTUxFLmVxdWFsLmdlby5ldmFsLnBsb3QsDQojICAgICAgICAgICBsYWJlbHMgPSAiQ29tcGFyaW5nIE1MRSBlcXVhbCBQLm1hdHJpeCBlc3RpbWF0ZSIsIGxhYmVsX3NpemUgPSAxMiwNCiMgICAgICAgICAgIGFsaWduID0gImh2IiwgaGp1c3QgPSAtMC4xKQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1ItcmFtbGphay9NTk9fRXVyb3N0YXQvbWFzdGVyL0dpZnMvTUxFLmVxdWFsLmVzdGltYXRlX21hcF9uZXcuZ2lmIikNCg0KDQpgYGANCg0KYGBge3IgTUxFIHRydWUgZ2VvIGV2YWx9DQojIE1MRS50cnVlLmdlby5ldmFsLnBsb3QgPC0gcmVhZFJEUygiVnlzb2vDoSDFoWtvbGEgZWtvbm9taWNrw6EgdiBQcmF6ZS9Ub255IFdlaSBUc2UgSHVuZyAtIFlBWS9Fc3RpbWF0ZXMvUGxvdC5maWxlcy9NTEUub3JhY2xlLmVzdGltYXRlX21hcC5yZHMiKQ0KIyBNTEUudHJ1ZS5nZW8uZXZhbC5wbG90IDwtIGFuaW1hdGUoTUxFLnRydWUuZ2VvLmV2YWwucGxvdCwgZnBzID0gMTApDQojIA0KIyANCiMgcGxvdF9ncmlkKHRydWUuZ2VvLmV2YWwucGxvdCwgTUxFLnRydWUuZ2VvLmV2YWwucGxvdCwNCiMgICAgICAgICAgIGxhYmVscyA9ICJDb21wYXJpbmcgTUxFIHRydWUgUC5tYXRyaXggZXN0aW1hdGUiLCBsYWJlbF9zaXplID0gMTIsDQojICAgICAgICAgICBhbGlnbiA9ICJodiIsIGhqdXN0ID0gLTAuMSkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9SLXJhbWxqYWsvTU5PX0V1cm9zdGF0L21hc3Rlci9HaWZzL01MRS5vcmFjbGUuZXN0aW1hdGVfbWFwX25ldy5naWYiKQ0KYGBgDQoNCiMjIFN0YXRpc3RpY2FsL0Rpc3RyaWJ1dGlvbmFsIEV2YWx1YXRpb24NCg0KSW4gb3JkZXIgdG8gYWN0dWFsbHkgY29tcGFyZSB0aGUgbnVtZXJpY2FsIHJlc2VtYmxhbmNlIGJldHdlZW4gdGhlIGVzdGltYXRlcyBhbmQgdGhlIGFjdHVhbCB0cnVlIHBvcHVsYXRpb24gd2UgaW50cm9kdWNlIHR3byBkaXNjcmVwYW5jeSBwZXJmb3JtYW5jZSBtZWFzdXJlcy4gDQoNCi0gICBBdmVyYWdlIEFic29sdXRlIERpc2NyZXBhbmN5OiAkRF97YXZnfSh1LHYpID0gXGZyYWN7MX17VX1cc3VtX3tqID0gMX1ee0p9IHx1X3tqfSAtIHZfe2p9fCQNCg0KLSAgIE1heGltdW0gQWJzb2x1dGUgRGlzY3JlcGFuY3k6ICREX3ttYXh9KFx0ZXh0YmZ7dSx2fSkgXG92ZXJzZXR7XHVuZGVyc2V0e1xtYXRocm17ZGVmfX17fX17PX0gXHN1bV97XG1hdGhpdHtqID0gMX19XntcbWF0aGl0e0p9fVxsZWZ0IHwgdV97an0gLSB2X3tqfSBccmlnaHQgfCQNCg0KYGBge3Igdm9yb25vaSB2cyBNTEV9DQoNCmFhZC5wbG90IDwtIHJlYWRSRFModXJsKCJodHRwczovL2dpdGh1Yi5jb20vUi1yYW1samFrL01OT19FdXJvc3RhdC9yYXcvbWFzdGVyL1Bsb3RzL0FBRE1BRC9hYWQuY29tcC5wbG90LnJkcyIsIG1ldGhvZCA9ICJsaWJjdXJsIikpICsgZ2d0aXRsZSgiIiwgc3VidGl0bGUgPSAiQUFEIikNCg0KbWFkLnBsb3QgPC0gcmVhZFJEUyh1cmwoImh0dHBzOi8vZ2l0aHViLmNvbS9SLXJhbWxqYWsvTU5PX0V1cm9zdGF0L3Jhdy9tYXN0ZXIvUGxvdHMvQUFETUFEL21hZC5jb21wLnBsb3QucmRzIiwgbWV0aG9kID0gImxpYmN1cmwiKSkgKyBnZ3RpdGxlKCIiLCBzdWJ0aXRsZSA9ICJNQUQiKQ0KDQpwbG90X2dyaWQoYWFkLnBsb3QsIG1hZC5wbG90LA0KICAgICAgICAgIGxhYmVscyA9ICJGaWcuIDE2IFZvcm9ub2kgRXN0aW1hdGlvbiB2cyBNTEUiLCANCiAgICAgICAgICBsYWJlbF9zaXplID0gMTIsIGFsaWduID0gImh2IiwgaGp1c3QgPSAtMC4xKSANCmBgYA0KQnkgY2FsY3VsYXRpbmcgdGhlIHR3byBkaXNjcmVwYW5jeSBtZWFzdXJlcywgd2UgY2FuIHRoZW4gZXZhbHVhdGUgdGhlIG92ZXJhbGwgcGVyZm9ybWFuY2UgZm9yIGVhY2ggdHlwZSBvZiBlc3RpbWF0aW9uLiBJbiBnZW5lcmFsLCB0aGUgVm9yb25vaSBlc3RpbWF0ZXMgcmVzdWx0IGluIGxlc3MgZGlzY3JlcGFuY3kgY29tcGFyZWQgdG8gYm90aCBvZiB0aGUgTUxFIGVzdGltYXRlcy4gQmV0d2VlbiB0aGUgdHdvIE1MRSBlc3RpbWF0ZXMsIHRoZSB0cnVlIHBvcHVsYXRpb24gbWF0cml4IGhhcyBhIGxvd2VyIGRpc2NyZXBhbmN5IHRoYW4gdGhlIGVxdWFsIHBvcHVsYXRpb24gbWF0cml4LiBCZXR3ZWVuIHRoZSB0d28gVm9yb25vaSBlc3RpbWF0ZXMsIHRoZSBWb3Jvbm9pIGVzdGltYXRpb24gYnkgYW50ZW5uYXMgaGFzIGEgbG93ZXIgZGlzY3JlcGFuY3kgdGhhbiB0aGUgVm9yb25vaSBlc3RpbWF0aW9uIGJ5IHRvd2Vycy4NCg0KIyBFeGN1cnNlIEV2YWx1YXRpb246IExvb2tpbmcgZGVlcGVyIGludG8gdGhlIGNvbnZlcmdlbmNlIGJlaGF2aW9yDQoNCkluIHRoZSBjb3Vyc2Ugb2Ygb3VyIHdvcmsgd2UgdGhvdWdodCBpdCB3YXMgcGFydGljdWxhcmx5IGludGVyZXN0aW5nIHRvIGZ1cnRoZXIgZm9jdXMgb24gdGhlIGFjdHVhbCBjb252ZXJnZW5jZSBiZWhhdmlvciBvZiB0aGUgTUxFLWJhc2VkIGVzdGltYXRvcnMuIA0KDQpXZSB3aWxsIHZpc3VhbGl6ZSB0aGUgY29udmVyZ2VuY2UgYmVoYXZpb3VyL3RoZSBldm9sdXRpb24gb2YgdGhlIGVzdGltYW5kcyB1cCB0byAxMDAwIGl0ZXJhdGlvbnMuIFRoaXMgaXMgZXhlY3V0ZWQgYmFzZWQgb24gYSBzdHJhdGlmaWVkIHNhbXBsZSAoc3RyYXRhOiB0aHJlZSBsZXZlbCBgcG9wLmFyZWEua2luZGAgdmFyaWFibGUpLCBuID0gMTUwKQ0KDQojIyBEaXNjcmVwYW5jeSBtZWFzdXJlcyBwZXIgaXRlcmF0aW9uDQoNCmBgYHtyfQ0KDQphYWQucGxvdCA8LSByZWFkUkRTKHVybCgiaHR0cHM6Ly9naXRodWIuY29tL1ItcmFtbGphay9NTk9fRXVyb3N0YXQvcmF3L21hc3Rlci9QbG90cy9BQURNQUQvZXF1YWwuYWFkLnBsb3QucmRzIiwgbWV0aG9kID0gImxpYmN1cmwiKSkgKyBnZ3RpdGxlKCIiLCBzdWJ0aXRsZSA9ICJBQUQiKQ0KDQptYWQucGxvdCA8LSByZWFkUkRTKHVybCgiaHR0cHM6Ly9naXRodWIuY29tL1ItcmFtbGphay9NTk9fRXVyb3N0YXQvcmF3L21hc3Rlci9QbG90cy9BQURNQUQvZXF1YWwubWFkLnBsb3QucmRzIiwgbWV0aG9kID0gImxpYmN1cmwiKSkgKyBnZ3RpdGxlKCIiLCBzdWJ0aXRsZSA9ICJNQUQiKQ0KDQpwbG90X2dyaWQoYWFkLnBsb3QsIG1hZC5wbG90LA0KICAgICAgICAgIGxhYmVscyA9ICJGaWcuIDE3IERpc2NyZXBhbmN5IE92ZXIgVGltZSwgRXF1YWwgUG9wLiBNYXRyaXgiLCANCiAgICAgICAgICBsYWJlbF9zaXplID0gMTIsIGFsaWduID0gImh2IiwgaGp1c3QgPSAtMC4xKQ0KYGBgDQpGb3IgdGhlIGVxdWFsIHBvcHVsYXRpb24gbWF0cml4LCB0aGUgZGlzY3JlcGFuY3kgdmFsdWVzIHN0YWJpbGl6ZXMgYXMgdGhlIG51bWJlciBvZiBpdGVyYXRpb25zIGluY3JlYXNlcy4gTW9yZSBzcGVjaWZpY2FsbHksIHN0YXJ0aW5nIGF0IHRoZSA3MDB0aCBpdGVyYXRpb24sIHRoZSBkaXNjcmVwYW5jeSB2YWx1ZXMgYXJlIGxhcmdlbHkgdGhlIHNhbWUuIA0KDQpgYGB7cn0NCmFhZC5wbG90IDwtIHJlYWRSRFModXJsKCJodHRwczovL2dpdGh1Yi5jb20vUi1yYW1samFrL01OT19FdXJvc3RhdC9yYXcvbWFzdGVyL1Bsb3RzL0FBRE1BRC90cnVlLmFhZC5wbG90LnJkcyIsIG1ldGhvZCA9ICJsaWJjdXJsIikpICsgZ2d0aXRsZSgiIiwgc3VidGl0bGUgPSAiQUFEIikNCg0KbWFkLnBsb3QgPC0gcmVhZFJEUyh1cmwoImh0dHBzOi8vZ2l0aHViLmNvbS9SLXJhbWxqYWsvTU5PX0V1cm9zdGF0L3Jhdy9tYXN0ZXIvUGxvdHMvQUFETUFEL3RydWUubWFkLnBsb3QucmRzIiwgbWV0aG9kID0gImxpYmN1cmwiKSkgKyBnZ3RpdGxlKCIiLCBzdWJ0aXRsZSA9ICJNQUQiKQ0KDQpwbG90X2dyaWQoYWFkLnBsb3QsIG1hZC5wbG90LA0KICAgICAgICAgIGxhYmVscyA9ICJGaWcuIDE4IERpc2NyZXBhbmN5IE92ZXIgVGltZSwgVHJ1ZSBQb3AuIE1hdHJpeCIsIA0KICAgICAgICAgIGxhYmVsX3NpemUgPSAxMiwgYWxpZ24gPSAiaHYiLCBoanVzdCA9IC0wLjEpDQpgYGANCkZvciB0aGUgdHJ1ZSBwb3B1bGF0aW9uIG1hdHJpeCwgdGhlIGRpc2NyZXBhbmN5IHZhbHVlcyBzdGFiaWxpemVzIGFzIHRoZSBudW1iZXIgb2YgaXRlcmF0aW9ucyBpbmNyZWFzZXMuIE1vcmUgc3BlY2lmaWNhbGx5LCBzdGFydGluZyBhdCB0aGUgMzAwdGggaXRlcmF0aW9uLCB0aGUgZGlzY3JlcGFuY3kgdmFsdWVzIGFyZSBsYXJnZWx5IHRoZSBzYW1lLiANCg0KIyMgQ29udmVyZ2VuY2UgYmVoYXZpb3INCg0KYGBge3IgZGlzdHJpYnV0aW9ubCBldmFsIDEsIGZpZy5jYXA9ICJUaGUgbGVmdCBhbmQgcmlnaHQgcGxvdHMgc2hvdyBhIHN0cmF0aWZpZWQgc2FtcGxlIChzdHJhdGE6IGFyZWEga2luZCkgYW5kIHRoZSB0aWxlIHNwZWNpZmljIGVzdGltYXRhbmRzJyBjb252ZXJnZW5jZSBiZWhhdmlvdXIuIFRoZSBjb252ZXJnZW5jZSBiZWhhdmlvdXIgZGlmZmVycyBiZXR3ZWVuIGFyZWEga2luZHMuIFRoZSByaWdodCBwbG90IGVtcGhhc2l6ZXMgdGhhdCB0aGUgdHJ1ZSB2YWx1ZSBpcyBub3QgbmVjZXNzYXJpbHkgcmVhY2hlZC4ifQ0KDQplcXVhbC5wbG90IDwtIHJlYWRSRFModXJsKCJodHRwczovL2dpdGh1Yi5jb20vUi1yYW1samFrL01OT19FdXJvc3RhdC9yYXcvbWFzdGVyL1Bsb3RzL0VzdGltYXRpb24lMjBQbG90cy9lcXVhbC5wbG90LnJkcyIsIG1ldGhvZCA9ICJsaWJjdXJsIikpICsgZ2d0aXRsZSgiIiwgc3VidGl0bGUgPSAiRXZvbHV0aW9uIikNCmVxdWFsLnJlc2lkLnBsb3QgPC0gcmVhZFJEUyh1cmwoImh0dHBzOi8vZ2l0aHViLmNvbS9SLXJhbWxqYWsvTU5PX0V1cm9zdGF0L3Jhdy9tYXN0ZXIvUGxvdHMvRXN0aW1hdGlvbiUyMFBsb3RzL2VxdWFsLnJlc2lkLnBsb3QucmRzIiwgbWV0aG9kID0gImxpYmN1cmwiKSkgKyBnZ3RpdGxlKCIiLCBzdWJ0aXRsZSA9ICJSZXNpZHVhbCIpDQoNCnBsb3RfZ3JpZChlcXVhbC5wbG90LCBlcXVhbC5yZXNpZC5wbG90LA0KICAgICAgICAgIGxhYmVscyA9ICJGaWcuIDE5IENvbnZlcmdlbmNlIGJlaGF2aW91ciAoRXF1YWwgUC5tYXRyaXgpIiwgDQogICAgICAgICAgbGFiZWxfc2l6ZSA9IDEyLCBoanVzdCA9IC0wLjEpIA0KDQpgYGANCg0KVGhlIGdyYXBocyBhYm92ZSBzaG93cyBob3cgdGhlIGVzdGltYXRlZCBwb3B1bGF0aW9uIGV2b2x2ZSBvdmVyIHRpbWUgKGxlZnQpIGFzIHdlbGwgYXMgaXRzIHByZWRpY3Rpb24gZXJyb3IgKHJpZ2h0KS4gRnJvbSB0aGUgZ3JhcGggb24gdGhlIGxlZnQsIG1vc3Qgb2YgdGhlIGVzdGltYXRlZCBwb3B1bGF0aW9uIHN0YWJpbGl6ZXMgcmF0aGVyIHF1aWNrbHkgaW4gcnVyYWwgYW5kIHN1YnVyYmFuIHRpbGVzLiBXaXRoIHRoZSB1cmJhbiB0aWxlcywgaXQgaXMgaGFyZGVyIHRvIHNheSBleGFjdGx5IHdoZW4gdGhlIGNvbnZlcmdlbmNlIHdpbGwgb2NjdXIsIGVzcGVjaWFsbHkgdGhlcmUgYXJlIGEgYml0IG9mIHZhcmlhdGlvbi4gVGhlIHJlc2lkdWFsIHBsb3QgKHJpZ2h0KSBzaG93cyB0aGUgZXJyb3Igb2YgcHJlZGljdGlvbiBpbiBjb21wYXJpc29uIHRvIHRoZSBhY3R1YWwgcG9wdWxhdGlvbiBpbiB0aGF0IHNwZWNpZmljIHRpbGUuIFRoZSBydXJhbCB0aWxlcyBzaG93cyBhIHRyZW5kIG9mIGNvbnN0YW50IGVycm9yIG9mIHByZWRpY3Rpb24gb3ZlciBpdGVyYXRpb25zLiBUaGUgc3VidXJiYW4gdGlsZXMgZ2VuZXJhbGx5IHNob3dzIHRoZSBzYW1lIHRyZW5kIGFzIHdlbGwsIGJ1dCBhbHNvIHNob3dzIHRoYXQgdGhlcmUgYXJlIHRpbGVzIHRoYXQgb3ZlcmVzdGltYXRlZC4gVGhlIHVyYmFuIHRpbGVzIHRlbmQgdG8gaGF2ZSBhbiB1bmRlcmVzdGltYXRpb24uDQoNCmBgYHtyIGRpc3RyaWJ1dGlvbmwgZXZhbCAyLCBmaWcuY2FwPSAiVGhlIGxlZnQgYW5kIHJpZ2h0IHBsb3RzIHNob3cgYSBzdHJhdGlmaWVkIHNhbXBsZSAoc3RyYXRhOiBhcmVhIGtpbmQpIGFuZCB0aGUgdGlsZSBzcGVjaWZpYyBlc3RpbWF0YW5kcycgY29udmVyZ2VuY2UgYmVoYXZpb3VyIChlcXVhbCBwcm9iYWJpbGl0eSBQLm1hdHJpeCkuIFRoZSBjb252ZXJnZW5jZSBiZWhhdmlvdXIgZGlmZmVycyBiZXR3ZWVuIGFyZWEga2luZHMuIFRoZSByaWdodCBwbG90IGVtcGhhc2l6ZXMgdGhhdCB0aGUgdHJ1ZSB2YWx1ZSBpcyBub3QgbmVjZXNzYXJpbHkgcmVhY2hlZC4ifQ0KDQp0cnVlLnBsb3QgPC0gcmVhZFJEUyh1cmwoImh0dHBzOi8vZ2l0aHViLmNvbS9SLXJhbWxqYWsvTU5PX0V1cm9zdGF0L3Jhdy9tYXN0ZXIvUGxvdHMvRXN0aW1hdGlvbiUyMFBsb3RzL3RydWUucGxvdC5yZHMiLCBtZXRob2QgPSAibGliY3VybCIpKSArIGdndGl0bGUoIiIsIHN1YnRpdGxlID0gIkV2b2x1dGlvbiIpDQoNCnRydWUucmVzaWQucGxvdCA8LSByZWFkUkRTKHVybCgiaHR0cHM6Ly9naXRodWIuY29tL1ItcmFtbGphay9NTk9fRXVyb3N0YXQvcmF3L21hc3Rlci9QbG90cy9Fc3RpbWF0aW9uJTIwUGxvdHMvdHJ1ZS5yZXNpZC5wbG90LnJkcyIsIG1ldGhvZCA9ICJsaWJjdXJsIikpICsgZ2d0aXRsZSgiIiwgc3VidGl0bGUgPSAiUmVzaWR1YWwiKQ0KDQpwbG90X2dyaWQodHJ1ZS5wbG90LCB0cnVlLnJlc2lkLnBsb3QsDQogICAgICAgICAgbGFiZWxzID0gIkZpZy4gMjAgQ29udmVyZ2VuY2UgYmVoYXZpb3VyIChUcnVlIFAubWF0cml4KSIsIA0KICAgICAgICAgIGxhYmVsX3NpemUgPSAxMiwgYWxpZ24gPSAiaHYiLCBoanVzdCA9IC0wLjEpIA0KDQpgYGANCg0KVXNpbmcgdGhlIHRydWUgcG9wdWxhdGlvbiBtYXRyaXgsIHRoZSBlc3RpbWF0ZWQgcG9wdWxhdGlvbiBzdGFiaWxpemVzIGZhc3RlciBvdmVyIHRpbWUgaW4gY29tcGFyaXNvbiB0byB0aGUgZXF1YWwgcG9wdWxhdGlvbiBtYXRyaXguIEhvd2V2ZXIsIHRoZXJlIGFyZSBhIGZldyB0aWxlcyB0aGF0IGRvIG5vdCBzdGFiaWxpemUgYXMgZmFzdCBhcyB3ZSBob3BlZC4gVGhpcyBpcyBwYXJ0aWN1bGFybHkgZXZpZGVudCBpbiB0aGUgdXJiYW4gdGlsZXMuIFRoZSByZXNpZHVhbCBwbG90IChyaWdodCkgc2hvd3MgdGhlIGVycm9yIG9mIHByZWRpY3Rpb24gb3ZlciB0aW1lIGJ5IHRoZSB0eXBlIG9mIHRpbGUuIFRoZXJlIHNlZW1zIHRvIGJlIGEgdHJlbmQgb2YgaW5jcmVhc2luZyBwcmVkaWN0aW9uIGVycm9yIGFzIHRoZSBkZWdyZWUgb2YgdXJiYW5pemF0aW9uIGluY3JlYXNlcyBhcyB3ZWxsLiBXZSBjYW4gc2VlIHRoYXQgdGhlIHJhbmdlIG9mIGVycm9yIGZvciBzdWJ1cmJhbiB0aWxlcyByYW5nZSBmcm9tIDMwIHRvIC0xMCBhbmQgdGhlIHJhbmdlIG9mIGVycm9yIGZvciB1cmJhbiB0aWxlcyBhcmUgYmV0d2VlbiAxMDAgYW5kIC03NS4gVGhlIHN1YnVyYmFuIHRpbGVzIHNlZW1zIHRvIHVuZGVyZXN0aW1hdGUgYW5kIHRoZSB1cmJhbiB0aWxlcyBzZWVtcyB0byBvdmVyZXN0aW1hdGUuDQoNCiMgRmluYWwgUmVtYXJrcw0KDQpUaHJvdWdob3V0IHRoaXMgbm90ZWJvb2sgd2UgaGF2ZSBmaXJzdCBjcmVhdGVkIHRoZSB0b3kgd29ybGQsIHdoZXJlIHdlIGhhdmUgZ2VuZXJhdGVkIHNlbWktc3ludGhldGljIHBvcHVsYXRpb24gZGF0YSBhbmQgYSBzeW50aGV0aWMgY2VsbCB0b3dlcnMuIEFmdGVyIHRoYXQsIHdlIHRoZW4gbGlua2VkIGVhY2ggcGVyc29uIGluIHRoZSBwb3B1bGF0aW9uIHRvIGNlbGwgdG93ZXIuIFdlIHRoZW4gZXN0aW1hdGVkIHRoZSBwb3B1bGF0aW9uIGJhc2VkIG9uIHRoZSBjZWxsLWRldmljZSBhc3NvY2lhdGlvbiBmcm9tIHRoZSB0b3dlcnMgYW5kIHRoZW4gZmluYWxseSBldmFsdWF0ZWQgaG93IHdlbGwgdGhlc2UgZXN0aW1hdGlvbiBzdHJhdGVnaWVzIHBlcmZvcm0gaW4gY29tcGFyaXNvbiB3aXRoIGVhY2ggb3RoZXIuIA0KDQpIb3dldmVyLCB0aGlzIGlzIG5vdCB0aGUgZW5kIG9mIE1OTy4gUmF0aGVyIHRoaXMgaXMgdGhlIGJlZ2lubmluZyBvZiBmdXJ0aGVyIGV4cGxvcmF0aW9ucy4gVGhlcmUgYXJlIHN0aWxsIGEgbG90IG1vcmUgdG8gZGlzY292ZXIuIFRvcGljcyBzdWNoIGFzIHRoZSBjb252ZXJnZW5jZSBiZWhhdmlvciBvZiBNTEUgZXN0aW1hdGlvbnMgb3Igc2ltdWxhdGluZyBhbiBldmVudCBiYXNlZCBleGFtcGxlIHN1Y2ggYXMgcGVvcGxlIGdvaW5nIG9uIGhvbGlkYXkgd2hlcmUgdGhlIHRvd2VycyB3b3VsZCB0aGVuIGJlIG92ZXJsb2FkZWQgd2l0aCB1c2VycyBhcmUgYWxsIGluIHRoZSB3b3Jrcy4gT3RoZXIgZXN0aW1hdGlvbnMgc2hvdWxkIGJlIHVzZWQgYXMgd2VsbCwgc3VjaCBhcyB0aGUgRWFydGggTW92ZXIncyBEaXN0YW5jZSBvciBkaWZmZXJlbnQgZXZhbHVhdGlvbiBtZXRyaWNzLg0KDQpVcCB1bnRpbCBub3csIHdlIGhhdmUgZm91bmQgdGhhdCB0aGUgTUxFIGVzdGltYXRpb25zIGFyZSBub3QgYXMgYWNjdXJhdGUgYXMgdGhlIFZvcm9ub2kgZXN0aW1hdGlvbnMsIGJ1dCB3ZSBiZWxpZXZlIHRoaXMgaXMgb25seSB0ZW1wb3JhcnkuIEZ1cnRoZXIgdmFyaWVkIHRlc3Rpbmcgc2hvdWxkIGJlIGNhcnJpZWQgb3V0IHRvIHZlcmlmeSB0aGUgZGlmZmVyZW50IGNoYXJhY3RlcmlzdGljcyBvZiBlYWNoIGVzdGltYXRpb24gc3RyYXRlZ3kuIA0KDQojIFJlZmVyZW5jZXMNCg0KWzFdIFJpY2NpYXRvIEYsIExhbnppZXJpIEcuLCBXaXJ0aG1hbm4gQS4sIGFuZCBTZXluYWV2ZSBHLigyMDIwKSBUb3dhcmRzIGEgbWV0aG9kb2xvZ2ljYWwgZnJhbWV3b3JrIGZvciBlc3RpbWF0aW5nIHByZXNlbnQgcG9wdWxhdGlvbiBkZW5zaXR5IGZyb20gbW9iaWxlIG5ldHdvcmsgb3BlcmF0b3IgZGF0YS4gPGh0dHBzOi8vZWMuZXVyb3BhLmV1L2V1cm9zdGF0L2Nyb3MvY29udGVudC90b3dhcmRzLW1ldGhvZG9sb2dpY2FsLWZyYW1ld29yay1lc3RpbWF0aW5nLXByZXNlbnQtcG9wdWxhdGlvbi1kZW5zaXR5LW1vYmlsZS1uZXR3b3JrLW9wZXJhdG9yLWRhdGEtZXh0ZW5kZWQtdmVyc2lvbl9lbj4NCg0KWzJdPGh0dHBzOi8vZ2FkbS5vcmcvZG93bmxvYWRfY291bnRyeV92My5odG1sPg0KDQpbM108aHR0cHM6Ly93d3cuZGVzdGF0aXMuZGUvRU4vSG9tZS9fbm9kZS5odG1sPg0KDQpbNF08aHR0cHM6Ly90bWEuaWZpcC5vcmcvMjAxNi9waGRTY2hvb2wvZGF0YS90b3lfZXhjZXJjaXNlX3NvbHV0aW9uLnBkZj4NCg==