Overview

This workshop is brought to you by R-Ladies Paris. Today we will explore how to use basic concepts of ggplot2 to create our own plots!

This workshop is divided into 5 sections:

  1. Set Up (5 min)
  2. Data Prep (10 min)
  3. Plot 1 (15 min)
  4. Plot 2 (15 min)
  5. Plot 3 (20 min)

1. Set Up

Install Libraries

Don’t know if you have the libraries already? No problem. Execute the code below to get started, if you have them already installed it will skip this step, otherwise it will start installing.

Hat tip to Antoine Soetewey for this cool trick.

#list of packages used in this workshop
Warning: The working directory was changed to /Users/tanyashapiro/Desktop/workshop/code inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
packages<- c("tidyverse","ggimage","sysfonts","showtext")

# if package not already installed, install package
installed_packages <- packages %in% rownames(installed.packages())
if (any(installed_packages == FALSE)) {
  install.packages(packages[!installed_packages])
}

Import Libraries

Tidyverse. ggplot2 is not explicitly included among our library import lists below. Instead, we’re loading in tidyverse. Tidyverse is a bundle of packages, which includes ggplot2 and dplyr.

Extensions. There are also several extension packages that complement ggplot2. Today we’ll explore how to work with ggplot extensions with ggimage and ggtext.

Other Packages. Last but not least, we will use sysfonts and showtext to load different font families and adjust the typography.

#includes dplyr + ggplot
library(tidyverse)
##ggplot extension packages
library(ggimage)
#to add google font libraries
library(sysfonts)
library(showtext)

Load Fonts

To customize fonts in our plots, we’ll import a couple of fonts using sysfonts and showtext. We can use sysfonts to add fonts from Google’s Font Library without downloading them locally with font_add_google.

💡 Tip: For chart typefaces, you can’t go wrong with a clean sans-serif font. There’s a great article about this topic by Lisa Charlotte Muth- Which fonts to use for your charts and tables .

#load fonts with sysfonts package
sysfonts::font_add_google("Roboto","Roboto")
sysfonts::font_add_google("Creepster","Creepster")
#to automatically render fonts, use showtext_auto()
showtext::showtext_auto()

2. Data Prep

The data we’re using today is from The Movie Database and contains information on over 35K Horror Movies from the 1950s until today 😱

Shout out to Georgios Karamanis for inspiring our topic, I was inspired to wrangle this data after finding a similar one Georgios submitted for #TidyTuesdayback in 2019.

An alternative title to this workshop

Data Dictionary

Variable Type Definition Example
id int unique movie id 4488
original_title char original movie title Friday the 13th
title char movie title Friday the 13th
original_language char movie language en
overview char movie overview/desc Camp counselors are stalked…
tagline char tagline They were warned…
release_date date release date 1980-05-09
poster_path char image url /HzrPn1gEHWixfMOvOehOTlHROo.jpg
popularity num popularity 58.957
vote_count int total votes 2289
vote_average num average rating 6.4
budget int movie budget 550000
revenue int movie revenue 59754601
runtime int movie runtime (min) 95
status char movie status Released
genre_names char list of genre tags Horror, Thriller
collection_id num collection id (nullable) 9735
collection_name char collection name (nullable) Friday the 13th Collection

Preview Data

Let’s load in our data and take a look at what we’re working with. Our data is stored on a GitHub repository, we can load in data with readr::read_csv() along with the url to the csv.

#download data from GitHub repository
raw <- readr::read_csv("https://raw.githubusercontent.com/tashapiro/horror-movies/main/data/horror_movies.csv")
#preview data
head(raw,5)

Quick Clean-Up

We’ll use dplyr to make a few tweaks, namely to modify existing columns and add a couple of new ones with mutate. To learn more about dplyr, check out this slick cheatsheet by RStuido.

🧹 To-Dos:

  • Express budget and revenue in millions
  • Convert release_date from char to date
  • Create release_year and release_month
  • Append poster_path to themoviedb url to create a poster_url
#url for poster images, need this to concatenate with poster path
base_url<-'https://www.themoviedb.org/t/p/w1280'

df <- raw|>
  mutate(budget = budget/1000000,
         revenue = revenue/1000000,
         #convert release date from char to date
         release_date = as.Date(release_date),
         #truncate date on year and month
         release_year = as.numeric(format(release_date, '%Y')),
         release_month = as.numeric(format(release_date, '%m')),
         #concatenate base url with poster path to get poster url
         poster_url = paste0(base_url,poster_path))

#preview data
head(df,5)

Before We Plot…

Building Blocks


3. Plot 1: Scatter

Slasher films are a popular sub-genre of Horror. For our scatter plot, let’s visualize how some of the most popular slasher franchise films compare to one another.

Pre-Plotting

We’ll need to slice and dice our data a bit. Using dplyr::filter(), pull in only records for films associated to Halloween, Friday the 13th, Scream, or A Nightmare on Elm Street.

#list of slasher collection titles
slashers<- c("Halloween Collection",
             "Friday the 13th Collection",
             "Scream Collection",
             "A Nightmare on Elm Street Collection")

#create slashers dataframe object
df_slashers<-df|>
  #filter only show movies in slasher collections, add budget and revenue filter
  filter(collection_name %in% slashers & budget>0 & revenue>0)|>
  #remove "Collection" from collection_name
  mutate(collection_name = gsub(" Collection","",collection_name))|>
  #subet columns with select
  select(title, collection_name, budget, revenue, popularity)

#preview data
head(df_slashers,5)

Basic Scatter Plot

The Essentials. We always start with ggplot(). There are two main arguments, data and mapping. Let’s use our df_slashers data frame, for our mapping we need aes() and additional arguments to specify x (budget) and y (revenue).

Plot Titles. We can use labs() to adjust all types of plot labels. In this example, let’s change our title, subtitle, axis titles, and caption.

ggplot(data=df_slashers, mapping=aes(y=revenue, x=budget))+
  geom_point()+
  labs(title="Slasher Movies: Revenue vs. Budget", 
       subtitle = "Includes movies from Friday the 13th, A Nightmare on Elm Street, Scream, \nand Halloween collections.",
       caption = "Data from The Movie Database",
       y="Revenue (millions)",
       x="Budget (millions)")

Level Up Scatter Plot

More Aes Arguments. Depending on the geom, aes() can contain more than just the x and y value pairs. In our scatter plot, we can also adjust details like size and color. Here, we’ll map size to popularity and color to collection_name.

Static Aesthetics. Adjust the opacity of points with alpha.

Intro to Scales. To override our default color options from our color mapping, we can modify with a color scales. In this example, we’ll use scale_color_manual and pass in a list of hex color values. Here are some I’ve pre-selected: “#DB2B39”,“#29335C”,“#F3A712”,“#3ED58E”

Intro to Themes. Try out a new theme, here’s a full list of default themes (e.g. theme_minimal, theme_light, theme_classic)

💡 Tip: There are a bunch of color palette libraries you can explore. If you want something more custom, palette generator sites like Coolors are also nice!

#create ggplot and score in a variable name
plot_scatter<-ggplot(df_slashers, mapping=aes(y=revenue, x=budget))+
  geom_point(mapping=aes(size=popularity, color=collection_name), alpha=0.6)+
  scale_color_manual(values = c("#DB2B39","#29335C","#F3A712",'#3ED58E'))+
  guides(
    color = guide_legend(override.aes = list(size=4)),
    size = guide_legend(override.aes=list(shape=21,color="black",fill="white"))
  )+
  labs(title="Slasher Movies: Revenue vs. Budget", 
       subtitle = "Comparison of movies in popular slasher franchise series.",
       y="Revenue (millions)",
       x="Budget (millions)",
        caption = "Data from The Movie Database",
       size = "Popularity", 
       color = "Franchise")+
  theme_minimal()

plot_scatter


#uncomment to save plot
#ggsave(filename="plot_scatter.png", plot=plot_scatter, width =7 , height=5, units="in", bg="white")

4. Plot 2 : Line

Plot how many movies were released by month and year.

Pre-Plotting

First, we’ll need to aggregate our data with dplyr group_by on release_month and release_year. Since this data set spans back to the 50s, let’s filter to only show release_year between 2016 and 2021.

df_monthly<-df|>
  #aggregate data by year and month
  group_by(release_year, release_month)|>
  #summarise total movies, n() equivalent of count
  summarise(count=n())|>
  #filter to only get years between 2016 and 2021
  filter(release_year>=2016 & release_year<=2021)

head(df_monthly,5)

Basic Line Chart

How many movies were released month-over-month in 2021?

#subset rows to pull only months from release year 2021
df_monthly_2021<- df_monthly|>filter(release_year==2021)

#create line plot with plot titles
ggplot(data = df_monthly_2021, 
       mapping=aes(x=release_month, y=count))+
  geom_line()+
    labs(x="Month",
       y="Number of Movies", x="Month",
       title = "Horror Movies by Release Month (2021)",
       caption = "Data from The Movie Database")

Level Up Line Chart

More Scales. Notice our first plot we have an issue with the x axis, it’s plotting it on a continuous scale because release_month is numeric. Our y axis is also starting ~90 instead of 0. We can use scales to modify our x and y axis (e.g. limits, breaks, and labels). We’ll need scale_y_continuous to change the y axis and scale_x_continuous to change our x axis.

Annotations. Sometimes its helpful to call out specific observations in our plots. We can add annotations with an annotate layer. For long annotations, use in your text to introduce a line break, e.g. “Wrap text.”

Custom Theme. We tested out one of ggplot’s default themes before, now let’s try creating our own custom theme .

💡 Tip: The annotate layer is useful if you want to include text that isn’t your data frame (e.g. single observation about a trend). If the label exists in the data, check out geom_text or geom_label.

Unlike Fred from Accounting, we never forget about themes


Palette Variables. Storing color palettes as variables can be useful when developing custom themes. Let’s set up our palette variables first.

#set up palette for future use
pal_text <- "white"
pal_subtext <- "#DFDFDF"
pal_grid <- "grey30"
pal_bg<-'#191919'
#expand on line chart
plot_line<-ggplot(data = df_monthly_2021, 
       mapping=aes(x=release_month, y=count))+
  geom_line(color="green")+
  annotate(geom="label", 
           label="Horror movies popular right \naround Halloween",
           x=10, y=410, color=pal_text, fill=pal_bg, size=3)+
  scale_x_continuous(breaks=1:12, labels=month.abb[1:12])+
  scale_y_continuous(limits=c(0,450))+
  labs(x="",
       y="Number of Movies", x="Month",
       title = "Total Horror Movies by Release Month (2021)",
       caption = "Data from The Movie Database")+
   theme(
        #adjust plot background + gridlines
        plot.background = element_rect(fill=pal_bg, color=pal_bg),
        panel.background = element_rect(fill=pal_bg),
        panel.grid.minor = element_blank(),
        panel.grid = element_line(color=pal_grid, size=0.2),
        #modify text color
        text = element_text(color=pal_text),
        axis.text = element_text(color=pal_text),
        axis.title.y = element_text(size=10, margin=margin(r=10)),
        plot.title = element_text(family="Creepster", size=25, hjust=0.5),
        plot.subtitle = element_text(hjust=0.5),
        #add padding around the plot
        plot.margin = margin(l=20, r=20, b=10, t=20))

plot_line


#uncomment to save plot
#ggsave(filename="plot_line.png", plot=plot_line, width=7, height=5, units="in")

Line Charts + Facets

What if we wanted to see seasonality and compare across different years?

To create multiple plots, we can use ggplot facet_wrap to pivot a plot on a data variable. Using our df_monthly data, use facet_wrap with release_year to show month-over-month trends per year.

💡 Tip: Applying annotate on a facet plot will apply the annotation to all plots. To annotate a singular plot, recommend creating a new data frame with a facet variable and using geom_text or geom_label.

plot_facet<-ggplot(data = df_monthly, mapping=aes(x=release_month, y=count, group=1))+
  geom_line(color="green")+
  facet_wrap(~release_year)+
  scale_x_continuous(breaks=1:12, labels=month.abb[1:12])+
  labs(x="",
       y="New Releases", 
       title = "Most Horror Movies released around Halloween",
       caption = "Data from The Movie Database",
       subtitle = "Total movie releases by month & year. Big spike in October, Halloween falls on October 31st.")+
  theme(
        #modify plot background + gridlines
        plot.background = element_rect(fill=pal_bg, color=pal_bg),
        panel.background = element_rect(fill=pal_bg),
        strip.background = element_rect(fill="#521EA4"),
        panel.grid.minor = element_blank(),
        panel.grid = element_line(color=pal_grid, size=0.2),
        #modify text 
        text = element_text(color=pal_text),
        axis.text = element_text(color=pal_text),
        axis.text.x=element_text(angle=90, size=9),
        plot.title = element_text(family="Creepster", size=20, hjust=0.5),
        plot.subtitle = element_text(hjust=0.5, size=10),
        strip.text=element_text(color=pal_text),
        #add padding around plot
        plot.margin = margin(l=20, r=20, b=10, t=20))

plot_facet


#uncomment to save plot
#ggsave(filename="plot_facet.png", plot=plot_facet, width =7 , height=5, units="in")

Plot 3: Bar Plot

Visualize the top 10 horror movies by revenue.

Pre-Plotting

To rank our data set in descending order by revenue, we can use dplyr arrange(). We’ll simplify and pick the columns we need for plotting with select(). Finally, use head() to grab the first 10 rows of data.

#get top movies based on revenue
df_top_movies<-df|>
  #arrange data in descending order revenue
  arrange(-revenue)|>
  #select specific columns
  select(title, release_year, revenue, budget, poster_url)|>
  #select first 10 rows
  head(10)

head(df_top_movies,10)

Basic Bar Plot

Use geom_col and map y to title and x to revenue.

💡 Tip: When you encounter discrete variables with long names like movie title, it might be easier to read as a horizontal bar chart instead of traditional bar chart.

#plot horizontal bar chart, add plot labels
ggplot(data=df_top_movies, mapping=aes(y=title, x=revenue))+
  geom_col()+
    labs(x="Revenue (millions)", y="",
       title="Horror Movies That Killed The Box Office",
       subtitle="Top horror movies based on total revenue.",
       caption = "Graphic @tanya_shapiro | Data tmdb API"
       )

Level Up Bar Plot

Reordering. For discrete variables like movie title, ggplot will default to ordering in alphabetical order. We can use the base R function reorder() within our y mapping to change the order of our title by revenue.

Layering Geoms. The beauty of ggplot is all in the layering - you can keep building by adding more than one geom! To test this concept, we’ll add the revenue numbers outside the bars with geom_text.

🗒️ Note: Another trick for reordering discrete variables is to convert them to factors in before passing them into ggplot.

pal_bar<-'#A70000'

ggplot(data=df_top_movies, 
       mapping=aes(y=reorder(title,revenue), x=revenue))+
  geom_col(fill = pal_bar, width=0.6)+
  geom_text(mapping=aes(label=round(revenue,0), x=revenue+20), 
            color="white", size=4)+
  scale_x_continuous(limits=c(0,750), expand=c(0,0))+
  labs(x="Revenue (millions)", y="",
       title="Horror Movies That Killed The Box Office",
       subtitle="Top horror movies based on total revenue. Data from The Movie Database as of October 2022.",
       caption = "Graphic @tanya_shapiro | Data tmdb API"
       )+
  theme(panel.background = element_rect(fill=pal_bg),
        axis.text = element_text(color="white", size=10),
        axis.ticks = element_blank(),
        plot.background = element_rect(fill=pal_bg, color=pal_bg),
        plot.subtitle = element_text(color="#DFDFDF", size=12),
        text = element_text(color="white"),
        panel.grid = element_blank(),
        plot.margin = margin(t=20, b=20, l=20, r=20),
        plot.title = element_text(family="Creepster", size=30),
        panel.grid.major.x= element_line(color="#2C2C2C", size=0.2))

Advanced Bar Plot

Keep Layering. Add in budget revenue for comparison. We can create a bullet bar graph by overlaying a thinner geom_col over our existing set up. Use the width argument to adjust its thickness.

Intro to More Geoms. The world of geoms goes beyond the geoms listed in ggplot2. There are tons of ggplot extension’s to explore that work with ggplot2. In this example, we will plot the movie poster images with ggimage geom_image.

Annotations + Arrows. Sometimes the placements of annotations is a little tricky, we might want to draw a line and arrow connecting our text to the observation. To draw straight lines, we can use geom_segment, to draw a curved line we can use geom_curve. Use the arrow argument and arrow() to add an arrow head.

🗒️ Note: For curved lines, a negative curvature values create left-hand curves and positive values create right-hand curves.

plot_bar<-ggplot(data=df_top_movies, mapping=aes(y=reorder(title,revenue), x=revenue))+
  #horizontal bar chart with revenue and budget
  geom_col(fill=pal_bar, width=0.4)+
  geom_col(mapping=aes(x=budget), fill='#600000', width=0.2)+
  #text with revenue amounts
  geom_text(mapping=aes(x=revenue+18, label=round(revenue,0)), 
            color="white", size=3.5)+
  #text with movie title + year
  geom_text(mapping=aes(x=0, y=title, label=paste0(title, " (",release_year,")")), 
            color="white", vjust=-2.2, hjust=0)+
  #poster images - map image to url path
  geom_image(mapping=aes(x=-50, image=poster_url))+
  #annotation for budget with arrow
  annotate(geom="text", color="white", x=250, y=9.5, label="Movie Budget", size=3)+
  geom_curve(mapping=aes(x=250, xend=205, y=9.35, yend=9), 
             color="white", curvature=-0.2, size=0.2, alpha=0.6,
             arrow = arrow(length = unit(0.07, "inch")))+
  #format x axis to adjust limits and breaks
  scale_x_continuous(expand=c(0,0), 
                     limits=c(-70,750),
                     breaks = c(0, 100,200, 300, 400, 500, 600, 700))+
  #titles and labels
  labs(y="", x="USD (millions)", 
       title="Horror Movies That Killed The Box Office", 
       subtitle="Top horror movies based on total revenue. Movie budget amount added for reference.\nData from The Movie Database as of October 2022.\n",
       caption = "Graphic @tanya_shapiro | Data tmdb API")+
  #custom theme 
  theme(
    #change background color
    plot.background =element_rect(fill=pal_bg, color=pal_bg),
    panel.background =element_rect(fill=pal_bg, color=pal_bg),
    #modify text font
    text = element_text(color=pal_text, family="Roboto"),
    axis.text = element_text(color=pal_text),
    axis.title.x = element_text(margin=margin(t=10)),
    axis.text.y = element_blank(),
    plot.subtitle = element_text(color=pal_subtext, size=12),
    plot.caption = element_text(color=pal_subtext, size=10),
    plot.title=element_text(family="Creepster", size=30, color=pal_text),
    #adjust lines for ticks and grid
    axis.ticks = element_blank(),
    panel.grid = element_blank(),
    panel.grid.major.x= element_line(color=pal_grid, size=0.2),
    #add padding around plot
    plot.margin = margin(t=20, b=20, l=20, r=20)
  )

plot_bar


#uncomment to save file
#ggsave(filename="plot_bar.png", plot=plot_bar, height=8, width=8, units="in")

The Workshop Sequel

This concludes our workshop session today, but it’s just the beginning of your ggplotting adventure.

Next step is just for you. Create your own ggplot using the Horror Movies data set and share your work with us on Twitter.

If you have any questions regarding our ggplot workshop, please feel free to reach out to me @tanya_shapiro. Thank you!

#create your own ggplot
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIHtnZ3Bsb3QyfSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZmlnLmFsaWduPSJjZW50ZXIiKQojc2V0IHRvIGFwcHJvcHJpYXRlIGRpcmVjdG9yeSBwYXRoLCBkZWZhdWx0IHRvIERlc2t0b3AKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXI9In4vRGVza3RvcCIpCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybSA9IEZBTFNFKQojb3B0aW9ucyhyZXBvcyA9IGxpc3QoQ1JBTj0iaHR0cDovL2NyYW4ucnN0dWRpby5jb20vIikpCmBgYAoKYGBge2NzcywgZWNobz1GQUxTRX0KLnRhYmxlIHRyOm50aC1jaGlsZChldmVuKSB7IGJhY2tncm91bmQ6ICNlZWU7IH0KYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIE92ZXJ2aWV3CgpUaGlzIHdvcmtzaG9wIGlzIGJyb3VnaHQgdG8geW91IGJ5IFsqKlItTGFkaWVzIFBhcmlzKipdKGh0dHBzOi8vdHdpdHRlci5jb20vcmxhZGllc3BhcmlzKS4gVG9kYXkgd2Ugd2lsbCBleHBsb3JlIGhvdyB0byB1c2UgYmFzaWMgY29uY2VwdHMgb2YgWyoqZ2dwbG90MioqXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy8pIHRvIGNyZWF0ZSBvdXIgb3duIHBsb3RzIQoKVGhpcyB3b3Jrc2hvcCBpcyBkaXZpZGVkIGludG8gNSBzZWN0aW9uczoKCjEuICBTZXQgVXAgKDUgbWluKQoyLiAgRGF0YSBQcmVwICgxMCBtaW4pCjMuICBQbG90IDEgKDE1IG1pbikKNC4gIFBsb3QgMiAoMTUgbWluKQo1LiAgUGxvdCAzICgyMCBtaW4pCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIDEuIFNldCBVcAoKIyMjIEluc3RhbGwgTGlicmFyaWVzCgpEb24ndCBrbm93IGlmIHlvdSBoYXZlIHRoZSBsaWJyYXJpZXMgYWxyZWFkeT8gTm8gcHJvYmxlbS4gRXhlY3V0ZSB0aGUgY29kZSBiZWxvdyB0byBnZXQgc3RhcnRlZCwgaWYgeW91IGhhdmUgdGhlbSBhbHJlYWR5IGluc3RhbGxlZCBpdCB3aWxsIHNraXAgdGhpcyBzdGVwLCBvdGhlcndpc2UgaXQgd2lsbCBzdGFydCBpbnN0YWxsaW5nLgoKSGF0IHRpcCB0byBBbnRvaW5lIFNvZXRld2V5IGZvciB0aGlzIFtjb29sIHRyaWNrXShodHRwczovL3N0YXRzYW5kci5jb20vYmxvZy9hbi1lZmZpY2llbnQtd2F5LXRvLWluc3RhbGwtYW5kLWxvYWQtci1wYWNrYWdlcy8pLgoKYGBge3IgZG93bmxvYWR9CiNsaXN0IG9mIHBhY2thZ2VzIHVzZWQgaW4gdGhpcyB3b3Jrc2hvcApwYWNrYWdlczwtIGMoInRpZHl2ZXJzZSIsImdnaW1hZ2UiLCJzeXNmb250cyIsInNob3d0ZXh0IikKCiMgaWYgcGFja2FnZSBub3QgYWxyZWFkeSBpbnN0YWxsZWQsIGluc3RhbGwgcGFja2FnZQppbnN0YWxsZWRfcGFja2FnZXMgPC0gcGFja2FnZXMgJWluJSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkKaWYgKGFueShpbnN0YWxsZWRfcGFja2FnZXMgPT0gRkFMU0UpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcyhwYWNrYWdlc1shaW5zdGFsbGVkX3BhY2thZ2VzXSkKfQpgYGAKCiMjIyBJbXBvcnQgTGlicmFyaWVzCgpbKipUaWR5dmVyc2UqKl17LnVuZGVybGluZX0uIGdncGxvdDIgaXMgbm90IGV4cGxpY2l0bHkgaW5jbHVkZWQgYW1vbmcgb3VyIGxpYnJhcnkgaW1wb3J0IGxpc3RzIGJlbG93LiBJbnN0ZWFkLCB3ZSdyZSBsb2FkaW5nIGluIFt0aWR5dmVyc2VdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvcGFja2FnZXMvKS4gVGlkeXZlcnNlIGlzIGEgYnVuZGxlIG9mIHBhY2thZ2VzLCB3aGljaCBpbmNsdWRlcyAqKmdncGxvdDIqKiBhbmQgKipkcGx5cioqLgoKWyoqRXh0ZW5zaW9ucyoqXXsudW5kZXJsaW5lfS4gVGhlcmUgYXJlIGFsc28gc2V2ZXJhbCBbZXh0ZW5zaW9uIHBhY2thZ2VzXShodHRwczovL2V4dHMuZ2dwbG90Mi50aWR5dmVyc2Uub3JnLykgdGhhdCBjb21wbGVtZW50IGdncGxvdDIuIFRvZGF5IHdlJ2xsIGV4cGxvcmUgaG93IHRvIHdvcmsgd2l0aCBnZ3Bsb3QgZXh0ZW5zaW9ucyB3aXRoICoqZ2dpbWFnZSoqIGFuZCAqKmdndGV4dCoqLgoKWyoqT3RoZXIgUGFja2FnZXMqKl17LnVuZGVybGluZX0uIExhc3QgYnV0IG5vdCBsZWFzdCwgd2Ugd2lsbCB1c2UgKipzeXNmb250cyoqIGFuZCAqKnNob3d0ZXh0KiogdG8gbG9hZCBkaWZmZXJlbnQgZm9udCBmYW1pbGllcyBhbmQgYWRqdXN0IHRoZSB0eXBvZ3JhcGh5LgoKYGBge3IgbGlicmFyaWVzLCBtZXNzYWdlPUZBTFNFfQojaW5jbHVkZXMgZHBseXIgKyBnZ3Bsb3QKbGlicmFyeSh0aWR5dmVyc2UpCiMjZ2dwbG90IGV4dGVuc2lvbiBwYWNrYWdlcwpsaWJyYXJ5KGdnaW1hZ2UpCiN0byBhZGQgZ29vZ2xlIGZvbnQgbGlicmFyaWVzCmxpYnJhcnkoc3lzZm9udHMpCmxpYnJhcnkoc2hvd3RleHQpCmBgYAoKIyMjIExvYWQgRm9udHMKClRvIGN1c3RvbWl6ZSBmb250cyBpbiBvdXIgcGxvdHMsIHdlJ2xsIGltcG9ydCBhIGNvdXBsZSBvZiBmb250cyB1c2luZyBbKipzeXNmb250cyoqXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc3lzZm9udHMvc3lzZm9udHMucGRmKSBhbmQgKipzaG93dGV4dC4qKiBXZSBjYW4gdXNlIHN5c2ZvbnRzIHRvIGFkZCBmb250cyBmcm9tIFsqKkdvb2dsZSdzIEZvbnQgTGlicmFyeSoqXShodHRwczovL2ZvbnRzLmdvb2dsZS5jb20vKSB3aXRob3V0IGRvd25sb2FkaW5nIHRoZW0gbG9jYWxseSB3aXRoIGBmb250X2FkZF9nb29nbGVgLgoKKvCfkqEgVGlwOiBGb3IgY2hhcnQgdHlwZWZhY2VzLCB5b3UgY2FuJ3QgZ28gd3Jvbmcgd2l0aCBhIGNsZWFuIHNhbnMtc2VyaWYgZm9udC4gVGhlcmUncyBhIGdyZWF0IGFydGljbGUgYWJvdXQgdGhpcyB0b3BpYyBieSBMaXNhIENoYXJsb3R0ZSBNdXRoLSBbV2hpY2ggZm9udHMgdG8gdXNlIGZvciB5b3VyIGNoYXJ0cyBhbmQgdGFibGVzXShodHRwczovL2Jsb2cuZGF0YXdyYXBwZXIuZGUvZm9udHMtZm9yLWRhdGEtdmlzdWFsaXphdGlvbi8pIC4qCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Rhc2hhcGlyby9ob3Jyb3ItbW92aWVzL21haW4vaW1hZ2VzL2ZvbnQtcHJldmlldy5wbmcpCgpgYGB7ciBmb250c30KI2xvYWQgZm9udHMgd2l0aCBzeXNmb250cyBwYWNrYWdlCnN5c2ZvbnRzOjpmb250X2FkZF9nb29nbGUoIlJvYm90byIsIlJvYm90byIpCnN5c2ZvbnRzOjpmb250X2FkZF9nb29nbGUoIkNyZWVwc3RlciIsIkNyZWVwc3RlciIpCiN0byBhdXRvbWF0aWNhbGx5IHJlbmRlciBmb250cywgdXNlIHNob3d0ZXh0X2F1dG8oKQpzaG93dGV4dDo6c2hvd3RleHRfYXV0bygpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyAyLiBEYXRhIFByZXAKClRoZSBkYXRhIHdlJ3JlIHVzaW5nIHRvZGF5IGlzIGZyb20gWyoqVGhlIE1vdmllIERhdGFiYXNlKipdKGh0dHBzOi8vd3d3LnRoZW1vdmllZGIub3JnLykgYW5kIGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIG92ZXIgMzVLICoqSG9ycm9yIE1vdmllcyoqIGZyb20gdGhlIDE5NTBzIHVudGlsIHRvZGF5IPCfmLEKClNob3V0IG91dCB0byBbKipHZW9yZ2lvcyBLYXJhbWFuaXMqKl0oaHR0cHM6Ly90d2l0dGVyLmNvbS9nZW9rYXJhbWFuaXMpIGZvciBpbnNwaXJpbmcgb3VyIHRvcGljLCBJIHdhcyBpbnNwaXJlZCB0byB3cmFuZ2xlIHRoaXMgZGF0YSBhZnRlciBmaW5kaW5nIGEgc2ltaWxhciBvbmUgR2Vvcmdpb3Mgc3VibWl0dGVkIGZvciBbKiojVGlkeVR1ZXNkYXkqKl0oaHR0cHM6Ly9naXRodWIuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS90cmVlL21hc3Rlci9kYXRhLzIwMTkvMjAxOS0xMC0yMiliYWNrIGluIDIwMTkuCgo8Y2VudGVyPiFbQW4gYWx0ZXJuYXRpdmUgdGl0bGUgdG8gdGhpcyB3b3Jrc2hvcF0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Rhc2hhcGlyby9ob3Jyb3ItbW92aWVzL21haW4vaW1hZ2VzL2xpdHRsZS13b3Jrc2hvcC5qcGVnKXt3aWR0aD0iNjAlIn08L2NlbnRlcj4KCiMjIyBEYXRhIERpY3Rpb25hcnkKCnwgKipWYXJpYWJsZSoqICAgICAgICAgIHwgKipUeXBlKiogfCAqKkRlZmluaXRpb24qKiAgICAgICAgICAgICB8ICoqRXhhbXBsZSoqICAgICAgICAgICAgICAgICAgICAgfAp8Oi0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS06fDotLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCAqKmlkKiogICAgICAgICAgICAgICAgfCAgIGludCAgICB8IHVuaXF1ZSBtb3ZpZSBpZCAgICAgICAgICAgIHwgNDQ4OCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgKipvcmlnaW5hbF90aXRsZSoqICAgIHwgICBjaGFyICAgfCBvcmlnaW5hbCBtb3ZpZSB0aXRsZSAgICAgICB8IEZyaWRheSB0aGUgMTN0aCAgICAgICAgICAgICAgICAgfAp8ICoqdGl0bGUqKiAgICAgICAgICAgICB8ICAgY2hhciAgIHwgbW92aWUgdGl0bGUgICAgICAgICAgICAgICAgfCBGcmlkYXkgdGhlIDEzdGggICAgICAgICAgICAgICAgIHwKfCAqKm9yaWdpbmFsX2xhbmd1YWdlKiogfCAgIGNoYXIgICB8IG1vdmllIGxhbmd1YWdlICAgICAgICAgICAgIHwgZW4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgKipvdmVydmlldyoqICAgICAgICAgIHwgICBjaGFyICAgfCBtb3ZpZSBvdmVydmlldy9kZXNjICAgICAgICB8IENhbXAgY291bnNlbG9ycyBhcmUgc3RhbGtlZC4uLiAgfAp8ICoqdGFnbGluZSoqICAgICAgICAgICB8ICAgY2hhciAgIHwgdGFnbGluZSAgICAgICAgICAgICAgICAgICAgfCBUaGV5IHdlcmUgd2FybmVkLi4uICAgICAgICAgICAgIHwKfCAqKnJlbGVhc2VfZGF0ZSoqICAgICAgfCAgIGRhdGUgICB8IHJlbGVhc2UgZGF0ZSAgICAgICAgICAgICAgIHwgMTk4MC0wNS0wOSAgICAgICAgICAgICAgICAgICAgICB8CnwgKipwb3N0ZXJfcGF0aCoqICAgICAgIHwgICBjaGFyICAgfCBpbWFnZSB1cmwgICAgICAgICAgICAgICAgICB8IC9IenJQbjFnRUhXaXhmTU92T2VoT1RsSFJPby5qcGcgfAp8ICoqcG9wdWxhcml0eSoqICAgICAgICB8ICAgbnVtICAgIHwgcG9wdWxhcml0eSAgICAgICAgICAgICAgICAgfCA1OC45NTcgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAqKnZvdGVfY291bnQqKiAgICAgICAgfCAgIGludCAgICB8IHRvdGFsIHZvdGVzICAgICAgICAgICAgICAgIHwgMjI4OSAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgKip2b3RlX2F2ZXJhZ2UqKiAgICAgIHwgICBudW0gICAgfCBhdmVyYWdlIHJhdGluZyAgICAgICAgICAgICB8IDYuNCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICoqYnVkZ2V0KiogICAgICAgICAgICB8ICAgaW50ICAgIHwgbW92aWUgYnVkZ2V0ICAgICAgICAgICAgICAgfCA1NTAwMDAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAqKnJldmVudWUqKiAgICAgICAgICAgfCAgIGludCAgICB8IG1vdmllIHJldmVudWUgICAgICAgICAgICAgIHwgNTk3NTQ2MDEgICAgICAgICAgICAgICAgICAgICAgICB8CnwgKipydW50aW1lKiogICAgICAgICAgIHwgICBpbnQgICAgfCBtb3ZpZSBydW50aW1lIChtaW4pICAgICAgICB8IDk1ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICoqc3RhdHVzKiogICAgICAgICAgICB8ICAgY2hhciAgIHwgbW92aWUgc3RhdHVzICAgICAgICAgICAgICAgfCBSZWxlYXNlZCAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAqKmdlbnJlX25hbWVzKiogICAgICAgfCAgIGNoYXIgICB8IGxpc3Qgb2YgZ2VucmUgdGFncyAgICAgICAgIHwgSG9ycm9yLCBUaHJpbGxlciAgICAgICAgICAgICAgICB8CnwgKipjb2xsZWN0aW9uX2lkKiogICAgIHwgICBudW0gICAgfCBjb2xsZWN0aW9uIGlkIChudWxsYWJsZSkgICB8IDk3MzUgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICoqY29sbGVjdGlvbl9uYW1lKiogICB8ICAgY2hhciAgIHwgY29sbGVjdGlvbiBuYW1lIChudWxsYWJsZSkgfCBGcmlkYXkgdGhlIDEzdGggQ29sbGVjdGlvbiAgICAgIHwKCiMjIyBQcmV2aWV3IERhdGEKCkxldCdzIGxvYWQgaW4gb3VyIGRhdGEgYW5kIHRha2UgYSBsb29rIGF0IHdoYXQgd2UncmUgd29ya2luZyB3aXRoLiBPdXIgZGF0YSBpcyBzdG9yZWQgb24gYSAqKkdpdEh1YioqIHJlcG9zaXRvcnksIHdlIGNhbiBsb2FkIGluIGRhdGEgd2l0aCBgcmVhZHI6OnJlYWRfY3N2KClgIGFsb25nIHdpdGggdGhlIHVybCB0byB0aGUgY3N2LgoKYGBge3IgZGF0YS1sb2FkLCBtZXNzYWdlPUZBTFNFfQojZG93bmxvYWQgZGF0YSBmcm9tIEdpdEh1YiByZXBvc2l0b3J5CnJhdyA8LSByZWFkcjo6cmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS90YXNoYXBpcm8vaG9ycm9yLW1vdmllcy9tYWluL2RhdGEvaG9ycm9yX21vdmllcy5jc3YiKQojcHJldmlldyBkYXRhCmhlYWQocmF3LDUpCmBgYAoKIyMjIFF1aWNrIENsZWFuLVVwCgpXZSdsbCB1c2UgKipkcGx5cioqIHRvIG1ha2UgYSBmZXcgdHdlYWtzLCBuYW1lbHkgdG8gbW9kaWZ5IGV4aXN0aW5nIGNvbHVtbnMgYW5kIGFkZCBhIGNvdXBsZSBvZiBuZXcgb25lcyB3aXRoIGBtdXRhdGVgLiBUbyBsZWFybiBtb3JlIGFib3V0IGRwbHlyLCBjaGVjayBvdXQgdGhpcyBzbGljayBbY2hlYXRzaGVldF0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDIvZGF0YS13cmFuZ2xpbmctY2hlYXRzaGVldC5wZGYpIGJ5IFJTdHVpZG8uCgrwn6e5IFRvLURvczoKCi0gICBFeHByZXNzICpidWRnZXQqIGFuZCAqcmV2ZW51ZSogaW4gbWlsbGlvbnMKLSAgIENvbnZlcnQgKnJlbGVhc2VfZGF0ZSogZnJvbSBjaGFyIHRvIGRhdGUKLSAgIENyZWF0ZSAqcmVsZWFzZV95ZWFyKiBhbmQgKnJlbGVhc2VfbW9udGgqCi0gICBBcHBlbmQgKnBvc3Rlcl9wYXRoKiB0byB0aGVtb3ZpZWRiIHVybCB0byBjcmVhdGUgYSAqcG9zdGVyX3VybCoKCmBgYHtyIGRhdGEtY2xlYW51cCwgbWVzc2FnZT1GQUxTRX0KI3VybCBmb3IgcG9zdGVyIGltYWdlcywgbmVlZCB0aGlzIHRvIGNvbmNhdGVuYXRlIHdpdGggcG9zdGVyIHBhdGgKYmFzZV91cmw8LSdodHRwczovL3d3dy50aGVtb3ZpZWRiLm9yZy90L3AvdzEyODAnCgpkZiA8LSByYXd8PgogIG11dGF0ZShidWRnZXQgPSBidWRnZXQvMTAwMDAwMCwKICAgICAgICAgcmV2ZW51ZSA9IHJldmVudWUvMTAwMDAwMCwKICAgICAgICAgI2NvbnZlcnQgcmVsZWFzZSBkYXRlIGZyb20gY2hhciB0byBkYXRlCiAgICAgICAgIHJlbGVhc2VfZGF0ZSA9IGFzLkRhdGUocmVsZWFzZV9kYXRlKSwKICAgICAgICAgI3RydW5jYXRlIGRhdGUgb24geWVhciBhbmQgbW9udGgKICAgICAgICAgcmVsZWFzZV95ZWFyID0gYXMubnVtZXJpYyhmb3JtYXQocmVsZWFzZV9kYXRlLCAnJVknKSksCiAgICAgICAgIHJlbGVhc2VfbW9udGggPSBhcy5udW1lcmljKGZvcm1hdChyZWxlYXNlX2RhdGUsICclbScpKSwKICAgICAgICAgI2NvbmNhdGVuYXRlIGJhc2UgdXJsIHdpdGggcG9zdGVyIHBhdGggdG8gZ2V0IHBvc3RlciB1cmwKICAgICAgICAgcG9zdGVyX3VybCA9IHBhc3RlMChiYXNlX3VybCxwb3N0ZXJfcGF0aCkpCgojcHJldmlldyBkYXRhCmhlYWQoZGYsNSkKYGBgCgojIyBCZWZvcmUgV2UgUGxvdC4uLgoKIVtdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS90YXNoYXBpcm8vaG9ycm9yLW1vdmllcy9tYWluL2ltYWdlcy9nZ3Bsb3QtY2FrZS5wbmcpCgoqKkJ1aWxkaW5nIEJsb2NrcyoqCgotICAgKipnZ3Bsb3QqKiAtIGhvdyB3ZSBpbml0aWFsaXplIHRoZSBnZ3Bsb3Qgb2JqZWN0LCBvcHRpb25hbCB0byBpbmNsdWRlIGRhdGEgYW5kIG1hcHBpbmcgaGVyZSAoYWN0cyBhcyB0aGUgcGFyZW50IGZvciBmdXR1cmUgZ2VvbXMpLgoKLSAgICoqR2VvbSBMYXllcnMqKiAtIHRoZSBjb21wb25lbnQgdG8gb3VyIHBsb3QuIFdlIGNhbiBzcGVjaWZ5IHR5cGUgd2l0aCBkaWZmZXJlbnQgW2dlb20gZnVuY3Rpb25zXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvI2xheWVycyksIGUuZy4gZm9yIGEgc2NhdHRlciBwbG90IHdlJ2xsIHVzZSBgZ2VvbV9wb2ludCgpYGFuZCBmb3IgYSBiYXIgY2hhcnQgd2UgY2FuIHVzZSBgZ2VvbV9jb2woKWAgb3IgYGdlb21fYmFyKClgLgoKLSAgICoqQWVzKiogLSBhZXN0aGV0aWMgbWFwcGluZyBvZiBkYXRhIHZhcmlhYmxlcyB0byB2aXN1YWwgcHJvcGVydGllcyAoZS5nLiB4LCB5LCBjb2xvciwgc2l6ZSkgaW4gb3VyIHBsb3QuIFNldCBpbiBgZ2dwbG90KClgIG9yIGluZGl2aWR1YWwgZ2VvbSBsYXllcnMuCgotICAgKipTY2FsZXMqKiAtIGZpbmUgdHVuaW5nIHRoZSBkZXRhaWxzIG9mIG91ciBwbG90cywgZS5nLiB0d2Vha2luZyBheGlzIGxpbWl0cywgYXhpcyBsYWJlbHMsIGNvbG9yIHZhbHVlcywgZXRjLiBTY2FsZXMgYXJlIHNwZWNpZmljIHRvIGRhdGEgdHlwZXMgKGUuZy4gZGlzY3JldGUsIGNvbnRpbnVvdXMpLgoKLSAgICoqTGFicyoqIC0gcGxvdCBsYWJlbGluZywgZS5nLiBwbG90IHRpdGxlIGFuZCBheGlzIGxhYmVscwoKLSAgICoqVGhlbWVzKiogLSBob3cgd2UgY2FuIGFkanVzdCB0aGUgbG9vaywgZmVlbCwgYW5kIG92ZXJhbGwgc3R5bGUgb2Ygb3VyIHBsb3QuIFRoZXJlIGFyZSBbb3V0IG9mIHRoZSBib3ggdGhlbWUgb3B0aW9uc10oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dndGhlbWUuaHRtbCksIGUuZy4gYHRoZW1lX2J3KClgIG9yIHdlIGNhbiBjcmVhdGUgb3VyIGN1c3RvbSB0aGVtZSB1c2luZyBgdGhlbWUoKWAgYW5kIG1vZGlmeSBjb21wb25lbnRzIHdpdGhpbiB0aGUgZnVuY3Rpb24uCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIDMuIFBsb3QgMTogU2NhdHRlcgoKU2xhc2hlciBmaWxtcyBhcmUgYSBwb3B1bGFyIHN1Yi1nZW5yZSBvZiBIb3Jyb3IuIEZvciBvdXIgc2NhdHRlciBwbG90LCBsZXQncyB2aXN1YWxpemUgaG93IHNvbWUgb2YgdGhlIG1vc3QgcG9wdWxhciBzbGFzaGVyIGZyYW5jaGlzZSBmaWxtcyBjb21wYXJlIHRvIG9uZSBhbm90aGVyLgoKPGNlbnRlcj4hW10oaHR0cHM6Ly82NC5tZWRpYS50dW1ibHIuY29tLzU5ZTVhZDM4ODM0NmI5ZGRiNGE3ZTBlYTFhNmMzYmYzLzRiOGIxMWVmZDUyOTQ1MmItZDQvczU0MHg4MTAvOGI4YTBhM2FmNzVlMmE5ZWY1NGM0NjUzZDg4MDU2ZGNlZmNiNjUzNS5qcGcpe3dpZHRoPSIzNzUifTwvY2VudGVyPgoKIyMjIFByZS1QbG90dGluZwoKV2UnbGwgbmVlZCB0byBzbGljZSBhbmQgZGljZSBvdXIgZGF0YSBhIGJpdC4gVXNpbmcgYGRwbHlyOjpmaWx0ZXIoKWAsIHB1bGwgaW4gb25seSByZWNvcmRzIGZvciBmaWxtcyBhc3NvY2lhdGVkIHRvICoqSGFsbG93ZWVuKiosICoqRnJpZGF5IHRoZSAxM3RoKiosICoqU2NyZWFtKiosIG9yICoqQSBOaWdodG1hcmUgb24gRWxtIFN0cmVldCoqLgoKYGBge3Igc2NhdHRlci1kYXRhLCBmaWcuYWxpZ249ImNlbnRlciIsIG1lc3NhZ2U9RkFMU0V9CiNsaXN0IG9mIHNsYXNoZXIgY29sbGVjdGlvbiB0aXRsZXMKc2xhc2hlcnM8LSBjKCJIYWxsb3dlZW4gQ29sbGVjdGlvbiIsCiAgICAgICAgICAgICAiRnJpZGF5IHRoZSAxM3RoIENvbGxlY3Rpb24iLAogICAgICAgICAgICAgIlNjcmVhbSBDb2xsZWN0aW9uIiwKICAgICAgICAgICAgICJBIE5pZ2h0bWFyZSBvbiBFbG0gU3RyZWV0IENvbGxlY3Rpb24iKQoKI2NyZWF0ZSBzbGFzaGVycyBkYXRhZnJhbWUgb2JqZWN0CmRmX3NsYXNoZXJzPC1kZnw+CiAgI2ZpbHRlciBvbmx5IHNob3cgbW92aWVzIGluIHNsYXNoZXIgY29sbGVjdGlvbnMsIGFkZCBidWRnZXQgYW5kIHJldmVudWUgZmlsdGVyCiAgZmlsdGVyKGNvbGxlY3Rpb25fbmFtZSAlaW4lIHNsYXNoZXJzICYgYnVkZ2V0PjAgJiByZXZlbnVlPjApfD4KICAjcmVtb3ZlICJDb2xsZWN0aW9uIiBmcm9tIGNvbGxlY3Rpb25fbmFtZQogIG11dGF0ZShjb2xsZWN0aW9uX25hbWUgPSBnc3ViKCIgQ29sbGVjdGlvbiIsIiIsY29sbGVjdGlvbl9uYW1lKSl8PgogICNzdWJldCBjb2x1bW5zIHdpdGggc2VsZWN0CiAgc2VsZWN0KHRpdGxlLCBjb2xsZWN0aW9uX25hbWUsIGJ1ZGdldCwgcmV2ZW51ZSwgcG9wdWxhcml0eSkKCiNwcmV2aWV3IGRhdGEKaGVhZChkZl9zbGFzaGVycyw1KQpgYGAKCiMjIyBCYXNpYyBTY2F0dGVyIFBsb3QKClsqKlRoZSBFc3NlbnRpYWxzKipdey51bmRlcmxpbmV9LiBXZSBhbHdheXMgc3RhcnQgd2l0aCBgZ2dwbG90KClgLiBUaGVyZSBhcmUgdHdvIG1haW4gYXJndW1lbnRzLCAqKmRhdGEqKiBhbmQgKiptYXBwaW5nLioqIExldCdzIHVzZSBvdXIgZGZfc2xhc2hlcnMgZGF0YSBmcmFtZSwgZm9yIG91ciBtYXBwaW5nIHdlIG5lZWQgYGFlcygpYCBhbmQgYWRkaXRpb25hbCBhcmd1bWVudHMgdG8gc3BlY2lmeSAqKngqKiAoKmJ1ZGdldCopIGFuZCAqKnkqKiAoKnJldmVudWUqKS4KClsqKlBsb3QgVGl0bGVzKipdey51bmRlcmxpbmV9LiBXZSBjYW4gdXNlIGBsYWJzKClgIHRvIGFkanVzdCBhbGwgdHlwZXMgb2YgcGxvdCBsYWJlbHMuIEluIHRoaXMgZXhhbXBsZSwgbGV0J3MgY2hhbmdlIG91ciAqKnRpdGxlKiosICoqc3VidGl0bGUqKiwgKipheGlzIHRpdGxlcyoqLCBhbmQgKipjYXB0aW9uKiouCgpgYGB7ciBiYXNpYy1zY2F0dGVyLCBmaWcuYWxpZ249ImNlbnRlciIsIG1lc3NhZ2U9RkFMU0V9CmdncGxvdChkYXRhPWRmX3NsYXNoZXJzLCBtYXBwaW5nPWFlcyh5PXJldmVudWUsIHg9YnVkZ2V0KSkrCiAgZ2VvbV9wb2ludCgpKwogIGxhYnModGl0bGU9IlNsYXNoZXIgTW92aWVzOiBSZXZlbnVlIHZzLiBCdWRnZXQiLCAKICAgICAgIHN1YnRpdGxlID0gIkluY2x1ZGVzIG1vdmllcyBmcm9tIEZyaWRheSB0aGUgMTN0aCwgQSBOaWdodG1hcmUgb24gRWxtIFN0cmVldCwgU2NyZWFtLCBcbmFuZCBIYWxsb3dlZW4gY29sbGVjdGlvbnMuIiwKICAgICAgIGNhcHRpb24gPSAiRGF0YSBmcm9tIFRoZSBNb3ZpZSBEYXRhYmFzZSIsCiAgICAgICB5PSJSZXZlbnVlIChtaWxsaW9ucykiLAogICAgICAgeD0iQnVkZ2V0IChtaWxsaW9ucykiKQpgYGAKCiMjIyBMZXZlbCBVcCBTY2F0dGVyIFBsb3QKClsqKk1vcmUgQWVzIEFyZ3VtZW50cyoqXXsudW5kZXJsaW5lfSoqLioqIERlcGVuZGluZyBvbiB0aGUgZ2VvbSwgYGFlcygpYCBjYW4gY29udGFpbiBtb3JlIHRoYW4ganVzdCB0aGUgeCBhbmQgeSB2YWx1ZSBwYWlycy4gSW4gb3VyIHNjYXR0ZXIgcGxvdCwgd2UgY2FuIGFsc28gYWRqdXN0IGRldGFpbHMgbGlrZSAqKnNpemUqKiBhbmQgKipjb2xvcioqLiBIZXJlLCB3ZSdsbCBtYXAgKipzaXplKiogdG8gKnBvcHVsYXJpdHkqIGFuZCAqKmNvbG9yKiogdG8gKmNvbGxlY3Rpb25fbmFtZS4qCgpbKipTdGF0aWMgQWVzdGhldGljcyoqXXsudW5kZXJsaW5lfS4gQWRqdXN0IHRoZSBvcGFjaXR5IG9mIHBvaW50cyB3aXRoICoqYWxwaGEuKioKClsqKkludHJvIHRvIFNjYWxlcyoqXXsudW5kZXJsaW5lfS4gVG8gb3ZlcnJpZGUgb3VyIGRlZmF1bHQgY29sb3Igb3B0aW9ucyBmcm9tIG91ciBjb2xvciBtYXBwaW5nLCB3ZSBjYW4gbW9kaWZ5IHdpdGggYSBjb2xvciBzY2FsZXMuIEluIHRoaXMgZXhhbXBsZSwgd2UnbGwgdXNlIFtgc2NhbGVfY29sb3JfbWFudWFsYF0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3NjYWxlX21hbnVhbC5odG1sKSBhbmQgcGFzcyBpbiBhIGxpc3Qgb2YgaGV4IGNvbG9yIHZhbHVlcyoqLioqIEhlcmUgYXJlIHNvbWUgSSd2ZSBwcmUtc2VsZWN0ZWQ6ICIjREIyQjM5IiwiIzI5MzM1QyIsIiNGM0E3MTIiLCIjM0VENThFIgoKWyoqSW50cm8gdG8gVGhlbWVzKipdey51bmRlcmxpbmV9LiBUcnkgb3V0IGEgbmV3IHRoZW1lLCBoZXJlJ3MgYSBmdWxsIGxpc3Qgb2YgW2RlZmF1bHQgdGhlbWVzXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2d0aGVtZS5odG1sI2FyZ3VtZW50cykgKGUuZy4gYHRoZW1lX21pbmltYWxgLCBgdGhlbWVfbGlnaHRgLCBgdGhlbWVfY2xhc3NpY2ApCgoq8J+SoSBUaXA6IFRoZXJlIGFyZSBhIGJ1bmNoIG9mIFtjb2xvciBwYWxldHRlIGxpYnJhcmllc10oaHR0cHM6Ly93d3cuZGF0YW5vdmlhLmNvbS9lbi9ibG9nL3RvcC1yLWNvbG9yLXBhbGV0dGVzLXRvLWtub3ctZm9yLWdyZWF0LWRhdGEtdmlzdWFsaXphdGlvbi8pIHlvdSBjYW4gZXhwbG9yZS4gSWYgeW91IHdhbnQgc29tZXRoaW5nIG1vcmUgY3VzdG9tLCBwYWxldHRlIGdlbmVyYXRvciBzaXRlcyBsaWtlIFtDb29sb3JzXShodHRwczovL2Nvb2xvcnMuY28vKSBhcmUgYWxzbyBuaWNlISoKCmBgYHtyIGludGVybS1zY2F0dGVyLCBmaWcuYWxpZ249ImNlbnRlciIsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0zIH0KI2NyZWF0ZSBnZ3Bsb3QgYW5kIHNjb3JlIGluIGEgdmFyaWFibGUgbmFtZQpwbG90X3NjYXR0ZXI8LWdncGxvdChkZl9zbGFzaGVycywgbWFwcGluZz1hZXMoeT1yZXZlbnVlLCB4PWJ1ZGdldCkpKwogIGdlb21fcG9pbnQobWFwcGluZz1hZXMoc2l6ZT1wb3B1bGFyaXR5LCBjb2xvcj1jb2xsZWN0aW9uX25hbWUpLCBhbHBoYT0wLjYpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjREIyQjM5IiwiIzI5MzM1QyIsIiNGM0E3MTIiLCcjM0VENThFJykpKwogIGd1aWRlcygKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSksCiAgICBzaXplID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcz1saXN0KHNoYXBlPTIxLGNvbG9yPSJibGFjayIsZmlsbD0id2hpdGUiKSkKICApKwogIGxhYnModGl0bGU9IlNsYXNoZXIgTW92aWVzOiBSZXZlbnVlIHZzLiBCdWRnZXQiLCAKICAgICAgIHN1YnRpdGxlID0gIkNvbXBhcmlzb24gb2YgbW92aWVzIGluIHBvcHVsYXIgc2xhc2hlciBmcmFuY2hpc2Ugc2VyaWVzLiIsCiAgICAgICB5PSJSZXZlbnVlIChtaWxsaW9ucykiLAogICAgICAgeD0iQnVkZ2V0IChtaWxsaW9ucykiLAogICAgICAgIGNhcHRpb24gPSAiRGF0YSBmcm9tIFRoZSBNb3ZpZSBEYXRhYmFzZSIsCiAgICAgICBzaXplID0gIlBvcHVsYXJpdHkiLCAKICAgICAgIGNvbG9yID0gIkZyYW5jaGlzZSIpKwogIHRoZW1lX21pbmltYWwoKQoKcGxvdF9zY2F0dGVyCgojdW5jb21tZW50IHRvIHNhdmUgcGxvdAojZ2dzYXZlKGZpbGVuYW1lPSJwbG90X3NjYXR0ZXIucG5nIiwgcGxvdD1wbG90X3NjYXR0ZXIsIHdpZHRoID03ICwgaGVpZ2h0PTUsIHVuaXRzPSJpbiIsIGJnPSJ3aGl0ZSIpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyA0LiBQbG90IDIgOiBMaW5lCgpQbG90IGhvdyBtYW55IG1vdmllcyB3ZXJlIHJlbGVhc2VkIGJ5IG1vbnRoIGFuZCB5ZWFyLgoKIyMjIFByZS1QbG90dGluZwoKRmlyc3QsIHdlJ2xsIG5lZWQgdG8gYWdncmVnYXRlIG91ciBkYXRhIHdpdGggZHBseXIgYGdyb3VwX2J5YCBvbiAqcmVsZWFzZV9tb250aCogYW5kICpyZWxlYXNlX3llYXIqLiBTaW5jZSB0aGlzIGRhdGEgc2V0IHNwYW5zIGJhY2sgdG8gdGhlIDUwcywgbGV0J3MgYGZpbHRlcmAgdG8gb25seSBzaG93ICpyZWxlYXNlX3llYXIqIGJldHdlZW4gMjAxNiBhbmQgMjAyMS4KCmBgYHtyIGRhdGEtcHJldmlld30KZGZfbW9udGhseTwtZGZ8PgogICNhZ2dyZWdhdGUgZGF0YSBieSB5ZWFyIGFuZCBtb250aAogIGdyb3VwX2J5KHJlbGVhc2VfeWVhciwgcmVsZWFzZV9tb250aCl8PgogICNzdW1tYXJpc2UgdG90YWwgbW92aWVzLCBuKCkgZXF1aXZhbGVudCBvZiBjb3VudAogIHN1bW1hcmlzZShjb3VudD1uKCkpfD4KICAjZmlsdGVyIHRvIG9ubHkgZ2V0IHllYXJzIGJldHdlZW4gMjAxNiBhbmQgMjAyMQogIGZpbHRlcihyZWxlYXNlX3llYXI+PTIwMTYgJiByZWxlYXNlX3llYXI8PTIwMjEpCgpoZWFkKGRmX21vbnRobHksNSkKYGBgCgojIyMgQmFzaWMgTGluZSBDaGFydAoKSG93IG1hbnkgbW92aWVzIHdlcmUgcmVsZWFzZWQgbW9udGgtb3Zlci1tb250aCBpbiAyMDIxPwoKYGBge3IgYmFzaWMtbGluZS1wbG90LCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD0zfQojc3Vic2V0IHJvd3MgdG8gcHVsbCBvbmx5IG1vbnRocyBmcm9tIHJlbGVhc2UgeWVhciAyMDIxCmRmX21vbnRobHlfMjAyMTwtIGRmX21vbnRobHl8PmZpbHRlcihyZWxlYXNlX3llYXI9PTIwMjEpCgojY3JlYXRlIGxpbmUgcGxvdCB3aXRoIHBsb3QgdGl0bGVzCmdncGxvdChkYXRhID0gZGZfbW9udGhseV8yMDIxLCAKICAgICAgIG1hcHBpbmc9YWVzKHg9cmVsZWFzZV9tb250aCwgeT1jb3VudCkpKwogIGdlb21fbGluZSgpKwogICAgbGFicyh4PSJNb250aCIsCiAgICAgICB5PSJOdW1iZXIgb2YgTW92aWVzIiwgeD0iTW9udGgiLAogICAgICAgdGl0bGUgPSAiSG9ycm9yIE1vdmllcyBieSBSZWxlYXNlIE1vbnRoICgyMDIxKSIsCiAgICAgICBjYXB0aW9uID0gIkRhdGEgZnJvbSBUaGUgTW92aWUgRGF0YWJhc2UiKQpgYGAKCiMjIyBMZXZlbCBVcCBMaW5lIENoYXJ0CgpbKipNb3JlIFNjYWxlcyoqXXsudW5kZXJsaW5lfSoqLioqIE5vdGljZSBvdXIgZmlyc3QgcGxvdCB3ZSBoYXZlIGFuIGlzc3VlIHdpdGggdGhlIHggYXhpcywgaXQncyBwbG90dGluZyBpdCBvbiBhIGNvbnRpbnVvdXMgc2NhbGUgYmVjYXVzZSAqcmVsZWFzZV9tb250aCogaXMgbnVtZXJpYy4gT3VyIHkgYXhpcyBpcyBhbHNvIHN0YXJ0aW5nIFx+OTAgaW5zdGVhZCBvZiAwLiBXZSBjYW4gdXNlIHNjYWxlcyB0byBtb2RpZnkgb3VyIHggYW5kIHkgYXhpcyAoZS5nLiBsaW1pdHMsIGJyZWFrcywgYW5kIGxhYmVscykuIFdlJ2xsIG5lZWQgYHNjYWxlX3lfY29udGludW91c2AgdG8gY2hhbmdlIHRoZSB5IGF4aXMgYW5kIGBzY2FsZV94X2NvbnRpbnVvdXNgIHRvIGNoYW5nZSBvdXIgeCBheGlzLgoKWyoqQW5ub3RhdGlvbnMqKl17LnVuZGVybGluZX0uIFNvbWV0aW1lcyBpdHMgaGVscGZ1bCB0byBjYWxsIG91dCBzcGVjaWZpYyBvYnNlcnZhdGlvbnMgaW4gb3VyIHBsb3RzLiBXZSBjYW4gYWRkIGFubm90YXRpb25zIHdpdGggYW4gYGFubm90YXRlYCBsYXllci4gRm9yIGxvbmcgYW5ub3RhdGlvbnMsIHVzZSBcbiBpbiB5b3VyIHRleHQgdG8gaW50cm9kdWNlIGEgbGluZSBicmVhaywgZS5nLiAiV3JhcCBcbnRoaXMgdGV4dC4iCgpbKipDdXN0b20gVGhlbWUqKl17LnVuZGVybGluZX0uIFdlIHRlc3RlZCBvdXQgb25lIG9mIGdncGxvdCdzIGRlZmF1bHQgdGhlbWVzIGJlZm9yZSwgbm93IGxldCdzIHRyeSBjcmVhdGluZyBvdXIgb3duIGN1c3RvbSBgdGhlbWVgIC4KCvCfkqEgKlRpcDogVGhlIGBhbm5vdGF0ZWAgbGF5ZXIgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGluY2x1ZGUgdGV4dCB0aGF0IGlzbid0IHlvdXIgZGF0YSBmcmFtZSAoZS5nLiBzaW5nbGUgb2JzZXJ2YXRpb24gYWJvdXQgYSB0cmVuZCkuIElmIHRoZSBsYWJlbCBleGlzdHMgaW4gdGhlIGRhdGEsIGNoZWNrIG91dCBgZ2VvbV90ZXh0YCBvciBgZ2VvbV9sYWJlbC5gKgoKPGNlbnRlcj4hW1VubGlrZSBGcmVkIGZyb20gQWNjb3VudGluZywgd2UgbmV2ZXIgZm9yZ2V0IGFib3V0IHRoZW1lc10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Rhc2hhcGlyby9ob3Jyb3ItbW92aWVzL21haW4vaW1hZ2VzL3RoZW1lLnBuZyl7d2lkdGg9IjYwJSJ9PC9jZW50ZXI+CgpcClsqKlBhbGV0dGUgVmFyaWFibGVzKipdey51bmRlcmxpbmV9LiBTdG9yaW5nIGNvbG9yIHBhbGV0dGVzIGFzIHZhcmlhYmxlcyBjYW4gYmUgdXNlZnVsIHdoZW4gZGV2ZWxvcGluZyBjdXN0b20gdGhlbWVzLiBMZXQncyBzZXQgdXAgb3VyIHBhbGV0dGUgdmFyaWFibGVzIGZpcnN0LgoKYGBge3J9CiNzZXQgdXAgcGFsZXR0ZSBmb3IgZnV0dXJlIHVzZQpwYWxfdGV4dCA8LSAid2hpdGUiCnBhbF9zdWJ0ZXh0IDwtICIjREZERkRGIgpwYWxfZ3JpZCA8LSAiZ3JleTMwIgpwYWxfYmc8LScjMTkxOTE5JwpgYGAKCmBgYHtyIGludGVybS1saW5lLXBsb3QsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTN9CiNleHBhbmQgb24gbGluZSBjaGFydApwbG90X2xpbmU8LWdncGxvdChkYXRhID0gZGZfbW9udGhseV8yMDIxLCAKICAgICAgIG1hcHBpbmc9YWVzKHg9cmVsZWFzZV9tb250aCwgeT1jb3VudCkpKwogIGdlb21fbGluZShjb2xvcj0iZ3JlZW4iKSsKICBhbm5vdGF0ZShnZW9tPSJsYWJlbCIsIAogICAgICAgICAgIGxhYmVsPSJIb3Jyb3IgbW92aWVzIHBvcHVsYXIgcmlnaHQgXG5hcm91bmQgSGFsbG93ZWVuIiwKICAgICAgICAgICB4PTEwLCB5PTQxMCwgY29sb3I9cGFsX3RleHQsIGZpbGw9cGFsX2JnLCBzaXplPTMpKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9MToxMiwgbGFiZWxzPW1vbnRoLmFiYlsxOjEyXSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKDAsNDUwKSkrCiAgbGFicyh4PSIiLAogICAgICAgeT0iTnVtYmVyIG9mIE1vdmllcyIsIHg9Ik1vbnRoIiwKICAgICAgIHRpdGxlID0gIlRvdGFsIEhvcnJvciBNb3ZpZXMgYnkgUmVsZWFzZSBNb250aCAoMjAyMSkiLAogICAgICAgY2FwdGlvbiA9ICJEYXRhIGZyb20gVGhlIE1vdmllIERhdGFiYXNlIikrCiAgIHRoZW1lKAogICAgICAgICNhZGp1c3QgcGxvdCBiYWNrZ3JvdW5kICsgZ3JpZGxpbmVzCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9cGFsX2JnLCBjb2xvcj1wYWxfYmcpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1wYWxfYmcpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvcj1wYWxfZ3JpZCwgc2l6ZT0wLjIpLAogICAgICAgICNtb2RpZnkgdGV4dCBjb2xvcgogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3I9cGFsX3RleHQpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj1wYWxfdGV4dCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIG1hcmdpbj1tYXJnaW4ocj0xMCkpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5PSJDcmVlcHN0ZXIiLCBzaXplPTI1LCBoanVzdD0wLjUpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3Q9MC41KSwKICAgICAgICAjYWRkIHBhZGRpbmcgYXJvdW5kIHRoZSBwbG90CiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4obD0yMCwgcj0yMCwgYj0xMCwgdD0yMCkpCgpwbG90X2xpbmUKCiN1bmNvbW1lbnQgdG8gc2F2ZSBwbG90CiNnZ3NhdmUoZmlsZW5hbWU9InBsb3RfbGluZS5wbmciLCBwbG90PXBsb3RfbGluZSwgd2lkdGg9NywgaGVpZ2h0PTUsIHVuaXRzPSJpbiIpCmBgYAoKIyMjIExpbmUgQ2hhcnRzICsgRmFjZXRzCgpXaGF0IGlmIHdlIHdhbnRlZCB0byBzZWUgc2Vhc29uYWxpdHkgYW5kIGNvbXBhcmUgYWNyb3NzIGRpZmZlcmVudCB5ZWFycz8KClRvIGNyZWF0ZSBtdWx0aXBsZSBwbG90cywgd2UgY2FuIHVzZSBnZ3Bsb3QgW2BmYWNldF93cmFwYF0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2ZhY2V0X3dyYXAuaHRtbCkgdG8gcGl2b3QgYSBwbG90IG9uIGEgZGF0YSB2YXJpYWJsZS4gVXNpbmcgb3VyICoqZGZfbW9udGhseSoqIGRhdGEsIHVzZSBgZmFjZXRfd3JhcGAgd2l0aCAqcmVsZWFzZV95ZWFyKiB0byBzaG93IG1vbnRoLW92ZXItbW9udGggdHJlbmRzIHBlciB5ZWFyLgoK8J+SoSAqVGlwKjogKkFwcGx5aW5nIGBhbm5vdGF0ZWAgb24gYSBmYWNldCBwbG90IHdpbGwgYXBwbHkgdGhlIGFubm90YXRpb24gdG8gYWxsIHBsb3RzLiBUbyBhbm5vdGF0ZSBhIHNpbmd1bGFyIHBsb3QsIHJlY29tbWVuZCBjcmVhdGluZyBhIG5ldyBkYXRhIGZyYW1lIHdpdGggYSBmYWNldCB2YXJpYWJsZSBhbmQgdXNpbmcgYGdlb21fdGV4dGAgb3IgYGdlb21fbGFiZWxgLioKCmBgYHtyIDRjLmZhY2V0LWxpbmUtY2hhcnQsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTMuNX0KcGxvdF9mYWNldDwtZ2dwbG90KGRhdGEgPSBkZl9tb250aGx5LCBtYXBwaW5nPWFlcyh4PXJlbGVhc2VfbW9udGgsIHk9Y291bnQsIGdyb3VwPTEpKSsKICBnZW9tX2xpbmUoY29sb3I9ImdyZWVuIikrCiAgZmFjZXRfd3JhcCh+cmVsZWFzZV95ZWFyKSsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPTE6MTIsIGxhYmVscz1tb250aC5hYmJbMToxMl0pKwogIGxhYnMoeD0iIiwKICAgICAgIHk9Ik5ldyBSZWxlYXNlcyIsIAogICAgICAgdGl0bGUgPSAiTW9zdCBIb3Jyb3IgTW92aWVzIHJlbGVhc2VkIGFyb3VuZCBIYWxsb3dlZW4iLAogICAgICAgY2FwdGlvbiA9ICJEYXRhIGZyb20gVGhlIE1vdmllIERhdGFiYXNlIiwKICAgICAgIHN1YnRpdGxlID0gIlRvdGFsIG1vdmllIHJlbGVhc2VzIGJ5IG1vbnRoICYgeWVhci4gQmlnIHNwaWtlIGluIE9jdG9iZXIsIEhhbGxvd2VlbiBmYWxscyBvbiBPY3RvYmVyIDMxc3QuIikrCiAgdGhlbWUoCiAgICAgICAgI21vZGlmeSBwbG90IGJhY2tncm91bmQgKyBncmlkbGluZXMKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1wYWxfYmcsIGNvbG9yPXBhbF9iZyksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPXBhbF9iZyksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSIjNTIxRUE0IiksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG9yPXBhbF9ncmlkLCBzaXplPTAuMiksCiAgICAgICAgI21vZGlmeSB0ZXh0IAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3I9cGFsX3RleHQpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj1wYWxfdGV4dCksCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCBzaXplPTkpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5PSJDcmVlcHN0ZXIiLCBzaXplPTIwLCBoanVzdD0wLjUpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3Q9MC41LCBzaXplPTEwKSwKICAgICAgICBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChjb2xvcj1wYWxfdGV4dCksCiAgICAgICAgI2FkZCBwYWRkaW5nIGFyb3VuZCBwbG90CiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4obD0yMCwgcj0yMCwgYj0xMCwgdD0yMCkpCgpwbG90X2ZhY2V0CgojdW5jb21tZW50IHRvIHNhdmUgcGxvdAojZ2dzYXZlKGZpbGVuYW1lPSJwbG90X2ZhY2V0LnBuZyIsIHBsb3Q9cGxvdF9mYWNldCwgd2lkdGggPTcgLCBoZWlnaHQ9NSwgdW5pdHM9ImluIikKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIFBsb3QgMzogQmFyIFBsb3QKClZpc3VhbGl6ZSB0aGUgdG9wIDEwIGhvcnJvciBtb3ZpZXMgYnkgcmV2ZW51ZS4KCiMjIyBQcmUtUGxvdHRpbmcKClRvIHJhbmsgb3VyIGRhdGEgc2V0IGluIGRlc2NlbmRpbmcgb3JkZXIgYnkgcmV2ZW51ZSwgd2UgY2FuIHVzZSBkcGx5ciBgYXJyYW5nZSgpYC4gV2UnbGwgc2ltcGxpZnkgYW5kIHBpY2sgdGhlIGNvbHVtbnMgd2UgbmVlZCBmb3IgcGxvdHRpbmcgd2l0aCBgc2VsZWN0KClgLiBGaW5hbGx5LCB1c2UgYGhlYWQoKWAgdG8gZ3JhYiB0aGUgZmlyc3QgMTAgcm93cyBvZiBkYXRhLgoKYGBge3IgYmFyLXBsb3QtZGF0YX0KI2dldCB0b3AgbW92aWVzIGJhc2VkIG9uIHJldmVudWUKZGZfdG9wX21vdmllczwtZGZ8PgogICNhcnJhbmdlIGRhdGEgaW4gZGVzY2VuZGluZyBvcmRlciByZXZlbnVlCiAgYXJyYW5nZSgtcmV2ZW51ZSl8PgogICNzZWxlY3Qgc3BlY2lmaWMgY29sdW1ucwogIHNlbGVjdCh0aXRsZSwgcmVsZWFzZV95ZWFyLCByZXZlbnVlLCBidWRnZXQsIHBvc3Rlcl91cmwpfD4KICAjc2VsZWN0IGZpcnN0IDEwIHJvd3MKICBoZWFkKDEwKQoKaGVhZChkZl90b3BfbW92aWVzLDEwKQpgYGAKCiMjIyBCYXNpYyBCYXIgUGxvdAoKVXNlIFtgZ2VvbV9jb2xgXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9iYXIuaHRtbCkgYW5kIG1hcCAqKnkqKiB0byAqdGl0bGUqIGFuZCAqKngqKiB0byAqcmV2ZW51ZSouCgrwn5KhICpUaXA6IFdoZW4geW91IGVuY291bnRlciBkaXNjcmV0ZSB2YXJpYWJsZXMgd2l0aCBsb25nIG5hbWVzIGxpa2UgbW92aWUgdGl0bGUsIGl0IG1pZ2h0IGJlIGVhc2llciB0byByZWFkIGFzIGEgaG9yaXpvbnRhbCBiYXIgY2hhcnQgaW5zdGVhZCBvZiB0cmFkaXRpb25hbCBiYXIgY2hhcnQuKgoKYGBge3IgYmFzaWMtYmFyLXBsb3QsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTN9CiNwbG90IGhvcml6b250YWwgYmFyIGNoYXJ0LCBhZGQgcGxvdCBsYWJlbHMKZ2dwbG90KGRhdGE9ZGZfdG9wX21vdmllcywgbWFwcGluZz1hZXMoeT10aXRsZSwgeD1yZXZlbnVlKSkrCiAgZ2VvbV9jb2woKSsKICAgIGxhYnMoeD0iUmV2ZW51ZSAobWlsbGlvbnMpIiwgeT0iIiwKICAgICAgIHRpdGxlPSJIb3Jyb3IgTW92aWVzIFRoYXQgS2lsbGVkIFRoZSBCb3ggT2ZmaWNlIiwKICAgICAgIHN1YnRpdGxlPSJUb3AgaG9ycm9yIG1vdmllcyBiYXNlZCBvbiB0b3RhbCByZXZlbnVlLiIsCiAgICAgICBjYXB0aW9uID0gIkdyYXBoaWMgQHRhbnlhX3NoYXBpcm8gfCBEYXRhIHRtZGIgQVBJIgogICAgICAgKQpgYGAKCiMjIyBMZXZlbCBVcCBCYXIgUGxvdAoKWyoqUmVvcmRlcmluZyoqXXsudW5kZXJsaW5lfSoqLioqIEZvciBkaXNjcmV0ZSB2YXJpYWJsZXMgbGlrZSBtb3ZpZSAqdGl0bGUsKiBnZ3Bsb3Qgd2lsbCBkZWZhdWx0IHRvIG9yZGVyaW5nIGluIGFscGhhYmV0aWNhbCBvcmRlci4gV2UgY2FuIHVzZSB0aGUgYmFzZSBSIGZ1bmN0aW9uIFtgcmVvcmRlcigpYF0oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3N0YXRzL3ZlcnNpb25zLzMuNi4yL3RvcGljcy9yZW9yZGVyLmRlZmF1bHQpIHdpdGhpbiBvdXIgeSBtYXBwaW5nIHRvIGNoYW5nZSB0aGUgb3JkZXIgb2Ygb3VyICp0aXRsZSogYnkgKnJldmVudWUqLgoKWyoqTGF5ZXJpbmcgR2VvbXMqKl17LnVuZGVybGluZX0uIFRoZSBiZWF1dHkgb2YgZ2dwbG90IGlzIGFsbCBpbiB0aGUgbGF5ZXJpbmcgLSB5b3UgY2FuIGtlZXAgYnVpbGRpbmcgYnkgYWRkaW5nIG1vcmUgdGhhbiBvbmUgZ2VvbSEgVG8gdGVzdCB0aGlzIGNvbmNlcHQsIHdlJ2xsIGFkZCB0aGUgKnJldmVudWUqIG51bWJlcnMgb3V0c2lkZSB0aGUgYmFycyB3aXRoIFtgZ2VvbV90ZXh0YF0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dlb21fdGV4dC5odG1sKS4KCvCfl5LvuI8gKk5vdGU6IEFub3RoZXIgdHJpY2sgZm9yIHJlb3JkZXJpbmcgZGlzY3JldGUgdmFyaWFibGVzIGlzIHRvIGNvbnZlcnQgdGhlbSB0byBmYWN0b3JzIGluIGJlZm9yZSBwYXNzaW5nIHRoZW0gaW50byBnZ3Bsb3QuKgoKYGBge3IgaW50ZXJtLWJhci1wbG90LCBmaWcuYWxpZ249ImNlbnRlciIsIGZpZy53aWR0aD00fQpwYWxfYmFyPC0nI0E3MDAwMCcKCmdncGxvdChkYXRhPWRmX3RvcF9tb3ZpZXMsIAogICAgICAgbWFwcGluZz1hZXMoeT1yZW9yZGVyKHRpdGxlLHJldmVudWUpLCB4PXJldmVudWUpKSsKICBnZW9tX2NvbChmaWxsID0gcGFsX2Jhciwgd2lkdGg9MC42KSsKICBnZW9tX3RleHQobWFwcGluZz1hZXMobGFiZWw9cm91bmQocmV2ZW51ZSwwKSwgeD1yZXZlbnVlKzIwKSwgCiAgICAgICAgICAgIGNvbG9yPSJ3aGl0ZSIsIHNpemU9NCkrCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDAsNzUwKSwgZXhwYW5kPWMoMCwwKSkrCiAgbGFicyh4PSJSZXZlbnVlIChtaWxsaW9ucykiLCB5PSIiLAogICAgICAgdGl0bGU9IkhvcnJvciBNb3ZpZXMgVGhhdCBLaWxsZWQgVGhlIEJveCBPZmZpY2UiLAogICAgICAgc3VidGl0bGU9IlRvcCBob3Jyb3IgbW92aWVzIGJhc2VkIG9uIHRvdGFsIHJldmVudWUuIERhdGEgZnJvbSBUaGUgTW92aWUgRGF0YWJhc2UgYXMgb2YgT2N0b2JlciAyMDIyLiIsCiAgICAgICBjYXB0aW9uID0gIkdyYXBoaWMgQHRhbnlhX3NoYXBpcm8gfCBEYXRhIHRtZGIgQVBJIgogICAgICAgKSsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9cGFsX2JnKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3I9IndoaXRlIiwgc2l6ZT0xMCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1wYWxfYmcsIGNvbG9yPXBhbF9iZyksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iI0RGREZERiIsIHNpemU9MTIpLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3I9IndoaXRlIiksCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0PTIwLCBiPTIwLCBsPTIwLCByPTIwKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseT0iQ3JlZXBzdGVyIiwgc2l6ZT0zMCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54PSBlbGVtZW50X2xpbmUoY29sb3I9IiMyQzJDMkMiLCBzaXplPTAuMikpCgpgYGAKCiMjIyBBZHZhbmNlZCBCYXIgUGxvdAoKWyoqS2VlcCBMYXllcmluZyoqXXsudW5kZXJsaW5lfS4gQWRkIGluIGJ1ZGdldCByZXZlbnVlIGZvciBjb21wYXJpc29uLiBXZSBjYW4gY3JlYXRlIGEgYnVsbGV0IGJhciBncmFwaCBieSBvdmVybGF5aW5nIGEgdGhpbm5lciBgZ2VvbV9jb2xgIG92ZXIgb3VyIGV4aXN0aW5nIHNldCB1cC4gVXNlIHRoZSAqKndpZHRoKiogYXJndW1lbnQgdG8gYWRqdXN0IGl0cyB0aGlja25lc3MuCgpbKipJbnRybyB0byBNb3JlIEdlb21zKipdey51bmRlcmxpbmV9LiBUaGUgd29ybGQgb2YgZ2VvbXMgZ29lcyBiZXlvbmQgdGhlIGdlb21zIGxpc3RlZCBpbiBnZ3Bsb3QyLiBUaGVyZSBhcmUgdG9ucyBvZiBnZ3Bsb3QgZXh0ZW5zaW9uJ3MgdG8gZXhwbG9yZSB0aGF0IHdvcmsgd2l0aCBnZ3Bsb3QyLiBJbiB0aGlzIGV4YW1wbGUsIHdlIHdpbGwgcGxvdCB0aGUgbW92aWUgcG9zdGVyIGltYWdlcyB3aXRoICoqZ2dpbWFnZSoqIFtgZ2VvbV9pbWFnZWBdKGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9nZ2ltYWdlL3ZlcnNpb25zLzAuMy4xL3RvcGljcy9nZW9tX2ltYWdlKS4KClsqKkFubm90YXRpb25zICsgQXJyb3dzKipdey51bmRlcmxpbmV9LiBTb21ldGltZXMgdGhlIHBsYWNlbWVudHMgb2YgYW5ub3RhdGlvbnMgaXMgYSBsaXR0bGUgdHJpY2t5LCB3ZSBtaWdodCB3YW50IHRvIFtkcmF3IGEgbGluZV0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dlb21fc2VnbWVudC5odG1sKSBhbmQgYXJyb3cgY29ubmVjdGluZyBvdXIgdGV4dCB0byB0aGUgb2JzZXJ2YXRpb24uIFRvIGRyYXcgc3RyYWlnaHQgbGluZXMsIHdlIGNhbiB1c2UgYGdlb21fc2VnbWVudGAsIHRvIGRyYXcgYSBjdXJ2ZWQgbGluZSB3ZSBjYW4gdXNlIGBnZW9tX2N1cnZlYC4gVXNlIHRoZSAqKmFycm93KiogYXJndW1lbnQgYW5kIGBhcnJvdygpYCB0byBhZGQgYW4gYXJyb3cgaGVhZC4KCvCfl5LvuI8gKk5vdGU6IEZvciBjdXJ2ZWQgbGluZXMsIGEgbmVnYXRpdmUgY3VydmF0dXJlIHZhbHVlcyBjcmVhdGUgbGVmdC1oYW5kIGN1cnZlcyBhbmQgcG9zaXRpdmUgdmFsdWVzIGNyZWF0ZSByaWdodC1oYW5kIGN1cnZlcy4qCgpgYGB7ciBhZHYtYmFyLXBsb3QsIGZpZy5oZWlnaHQ9My43LCBmaWcud2lkdGg9My43fQpwbG90X2JhcjwtZ2dwbG90KGRhdGE9ZGZfdG9wX21vdmllcywgbWFwcGluZz1hZXMoeT1yZW9yZGVyKHRpdGxlLHJldmVudWUpLCB4PXJldmVudWUpKSsKICAjaG9yaXpvbnRhbCBiYXIgY2hhcnQgd2l0aCByZXZlbnVlIGFuZCBidWRnZXQKICBnZW9tX2NvbChmaWxsPXBhbF9iYXIsIHdpZHRoPTAuNCkrCiAgZ2VvbV9jb2wobWFwcGluZz1hZXMoeD1idWRnZXQpLCBmaWxsPScjNjAwMDAwJywgd2lkdGg9MC4yKSsKICAjdGV4dCB3aXRoIHJldmVudWUgYW1vdW50cwogIGdlb21fdGV4dChtYXBwaW5nPWFlcyh4PXJldmVudWUrMTgsIGxhYmVsPXJvdW5kKHJldmVudWUsMCkpLCAKICAgICAgICAgICAgY29sb3I9IndoaXRlIiwgc2l6ZT0zLjUpKwogICN0ZXh0IHdpdGggbW92aWUgdGl0bGUgKyB5ZWFyCiAgZ2VvbV90ZXh0KG1hcHBpbmc9YWVzKHg9MCwgeT10aXRsZSwgbGFiZWw9cGFzdGUwKHRpdGxlLCAiICgiLHJlbGVhc2VfeWVhciwiKSIpKSwgCiAgICAgICAgICAgIGNvbG9yPSJ3aGl0ZSIsIHZqdXN0PS0yLjIsIGhqdXN0PTApKwogICNwb3N0ZXIgaW1hZ2VzIC0gbWFwIGltYWdlIHRvIHVybCBwYXRoCiAgZ2VvbV9pbWFnZShtYXBwaW5nPWFlcyh4PS01MCwgaW1hZ2U9cG9zdGVyX3VybCkpKwogICNhbm5vdGF0aW9uIGZvciBidWRnZXQgd2l0aCBhcnJvdwogIGFubm90YXRlKGdlb209InRleHQiLCBjb2xvcj0id2hpdGUiLCB4PTI1MCwgeT05LjUsIGxhYmVsPSJNb3ZpZSBCdWRnZXQiLCBzaXplPTMpKwogIGdlb21fY3VydmUobWFwcGluZz1hZXMoeD0yNTAsIHhlbmQ9MjA1LCB5PTkuMzUsIHllbmQ9OSksIAogICAgICAgICAgICAgY29sb3I9IndoaXRlIiwgY3VydmF0dXJlPS0wLjIsIHNpemU9MC4yLCBhbHBoYT0wLjYsCiAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4wNywgImluY2giKSkpKwogICNmb3JtYXQgeCBheGlzIHRvIGFkanVzdCBsaW1pdHMgYW5kIGJyZWFrcwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQ9YygwLDApLCAKICAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoLTcwLDc1MCksCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMCwgMTAwLDIwMCwgMzAwLCA0MDAsIDUwMCwgNjAwLCA3MDApKSsKICAjdGl0bGVzIGFuZCBsYWJlbHMKICBsYWJzKHk9IiIsIHg9IlVTRCAobWlsbGlvbnMpIiwgCiAgICAgICB0aXRsZT0iSG9ycm9yIE1vdmllcyBUaGF0IEtpbGxlZCBUaGUgQm94IE9mZmljZSIsIAogICAgICAgc3VidGl0bGU9IlRvcCBob3Jyb3IgbW92aWVzIGJhc2VkIG9uIHRvdGFsIHJldmVudWUuIE1vdmllIGJ1ZGdldCBhbW91bnQgYWRkZWQgZm9yIHJlZmVyZW5jZS5cbkRhdGEgZnJvbSBUaGUgTW92aWUgRGF0YWJhc2UgYXMgb2YgT2N0b2JlciAyMDIyLlxuIiwKICAgICAgIGNhcHRpb24gPSAiR3JhcGhpYyBAdGFueWFfc2hhcGlybyB8IERhdGEgdG1kYiBBUEkiKSsKICAjY3VzdG9tIHRoZW1lIAogIHRoZW1lKAogICAgI2NoYW5nZSBiYWNrZ3JvdW5kIGNvbG9yCiAgICBwbG90LmJhY2tncm91bmQgPWVsZW1lbnRfcmVjdChmaWxsPXBhbF9iZywgY29sb3I9cGFsX2JnKSwKICAgIHBhbmVsLmJhY2tncm91bmQgPWVsZW1lbnRfcmVjdChmaWxsPXBhbF9iZywgY29sb3I9cGFsX2JnKSwKICAgICNtb2RpZnkgdGV4dCBmb250CiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPXBhbF90ZXh0LCBmYW1pbHk9IlJvYm90byIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPXBhbF90ZXh0KSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW49bWFyZ2luKHQ9MTApKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvcj1wYWxfc3VidGV4dCwgc2l6ZT0xMiksCiAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoY29sb3I9cGFsX3N1YnRleHQsIHNpemU9MTApLAogICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoZmFtaWx5PSJDcmVlcHN0ZXIiLCBzaXplPTMwLCBjb2xvcj1wYWxfdGV4dCksCiAgICAjYWRqdXN0IGxpbmVzIGZvciB0aWNrcyBhbmQgZ3JpZAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLng9IGVsZW1lbnRfbGluZShjb2xvcj1wYWxfZ3JpZCwgc2l6ZT0wLjIpLAogICAgI2FkZCBwYWRkaW5nIGFyb3VuZCBwbG90CiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0PTIwLCBiPTIwLCBsPTIwLCByPTIwKQogICkKCnBsb3RfYmFyCgojdW5jb21tZW50IHRvIHNhdmUgZmlsZQojZ2dzYXZlKGZpbGVuYW1lPSJwbG90X2Jhci5wbmciLCBwbG90PXBsb3RfYmFyLCBoZWlnaHQ9OCwgd2lkdGg9OCwgdW5pdHM9ImluIikKYGBgCgojIyBUaGUgV29ya3Nob3AgU2VxdWVsCgpUaGlzIGNvbmNsdWRlcyBvdXIgd29ya3Nob3Agc2Vzc2lvbiB0b2RheSwgYnV0IGl0J3MganVzdCB0aGUgYmVnaW5uaW5nIG9mIHlvdXIgZ2dwbG90dGluZyBhZHZlbnR1cmUuCgpOZXh0IHN0ZXAgaXMganVzdCBmb3IgeW91LiBDcmVhdGUgeW91ciBvd24gZ2dwbG90IHVzaW5nIHRoZSBIb3Jyb3IgTW92aWVzIGRhdGEgc2V0IGFuZCBzaGFyZSB5b3VyIHdvcmsgd2l0aCB1cyBvbiBUd2l0dGVyLgoKSWYgeW91IGhhdmUgYW55IHF1ZXN0aW9ucyByZWdhcmRpbmcgb3VyIGdncGxvdCB3b3Jrc2hvcCwgcGxlYXNlIGZlZWwgZnJlZSB0byByZWFjaCBvdXQgdG8gbWUgW1xAdGFueWFfc2hhcGlyb10oaHR0cHM6Ly90d2l0dGVyLmNvbS90YW55YV9zaGFwaXJvKS4gVGhhbmsgeW91IQoKYGBge3IgZW5kLXBsb3R9CiNjcmVhdGUgeW91ciBvd24gZ2dwbG90CmBgYAo=