In this lab, we’ll create the Shiny app. This lab will guide you
write a shiny application, create interactive plots, publish the shiny
application on RStudio’s shiny server, then you will be able to share
the application link. This link contains the the shiny app demo we want
you create during this lab, and you could publish it on shiny server. https://xuehanchen.shinyapps.io/shinyapp/
Shiny is an R package that allows you to easily create rich,
interactive web apps. Shiny allows you to take your work in R and expose
it via a web browser so that anyone can use it. Shiny makes you look
awesome by making it easy to produce polished web apps with a minimum
amount of pain.
1. Basic “Shiny” structure
There are several ways to create a Shiny app.
The simplest is to create a new directory for your app, and put a
single file called shinyApp.R in it.
Or you could split your code into three files for better
organization: ui.R, server.R, shinyApp.R.
Here we put it into single chunk of the notebook like a single
shinyApp.R file, so you could directly run your code in this
notebook.
Shiny applications are divided into two parts: the User Interface
(UI) and the Server.
The UI and server work together to create an interactive Shiny
application that updates in real-time based on user input and reactive
values. Check more details on https://shiny.rstudio.com/tutorial/
Run the following basic shiny code, open the brower, then you
should see an empty web application.
Notice that once you close the website, you might see the error
returns like: Listening on http://……
You could ignore this error.
ui <- fluidPage(
#ui design goes here
)
server <- function(input, output) {
# server logic goes here
}
#Previewing the application.
shinyApp(ui = ui, server = server)
2. Basic UI design:
Now, let’s define the ui function. There are many approaches to allow
the user to choose from a prespecified set of options:
e.g. selectInput() and radioButtons().
- Run the following example and see the ui presentation.
- Notice that for UI function, it only shows the app presentation,
there is no data processing defined here. The UI provides the user with
a way to interact with the app, while the Server processes the user’s
input and generates output that is displayed in the UI. We will talk
about it later on.
animals <- c("dog", "cat", "mouse", "bird", "other", "I hate animals")
ui <- fluidPage(
selectInput("animal", "What's your favourite state?", state.name),
radioButtons("animal", "What's your favourite animal?", animals)
)
ui
There’s no way to select multiple values with radio buttons, but
there’s an alternative that’s conceptually similar: checkboxGroupInput()
or selectizeInput().
- Try to write ui function for the question: “What animals do you
like?” using checkboxGroupInput() or selectizeInput().
#code start here:
ui <- fluidPage(
checkboxGroupInput("animal", "What animals do you like?", animals)
)
ui
#code end here
3. Create the ui and server function for plot.
Now let’s create shiny app for the plot!
You can display any type of R graphic (base, ggplot2, or otherwise)
with plotOutput() and renderPlot().
Explore the input and output argument in server funtion. The
input argument represents the user’s inputs (e.g. form inputs, buttons
clicked, etc.), and the output argument represents the outputs
(e.g. plots, tables, etc.) that will be displayed to the user.
Outputs in the UI create placeholders that are later filled by
the server function. Like inputs, outputs take a unique ID as their
first argument: if your UI specification creates an output with ID
"plot", like
plotOutput("plot"), you’ll access it in
the server function with
output$plot.
In R, {} is used to create a block
of code that can contain one or more expressions or statements. In the
context of a function, the {} block
defines the function body, which contains the code that is executed when
the function is called.
Try to run the following example:
ui <- fluidPage(
plotOutput("plot"),
)
server <- function(input, output) {
output$plot <- renderPlot({
plot(mtcars$wt, mtcars$mpg)
}, res = 96)
}
shinyApp(ui = ui, server = server)
After running the example, Let’s start by building a simple shiny
plot!
We try to explore the topic “Titanic: What Helped You Survive?”. The
goal is to ask several questions and using plot to explore it.

First we load data and do simple clean.
# load titanic dataset
library(titanic)
titanic <- titanic_train
titanic <- na.omit(titanic)
titanic$Pclass <- as.factor(titanic$Pclass)
titanic$Survived <- as.factor(titanic$Survived)
titanic$Sex <- as.factor(titanic$Sex)
ui <- fluidPage(
#code start here:
plotOutput("plot"),
#code end here
)
server <- function(input, output) {
#code start here:
output$plot <- renderPlot({
ggplot(titanic, aes(x = Sex, fill = Survived)) +
theme_bw() +
geom_bar(position = "dodge") +
labs(y = "Passenger Count",
title = "Passenger Count by Sex")
}, res = 96)
#code end here
}
shinyApp(ui = ui, server = server)
5. Build our shiny app.
Question - What is the number of survival passengers by age when
segmented by gender and class of ticket?
ui <- fluidPage(
#use fluidRow() to control the plot layout
fluidRow(
column(width = 4,
#selection control part
#code start here:
#Add three selection elements, one for the survival status, one for pclass and one for the gender of the passengers. Set their initial selections using the selected argument.
#Add one slider for selecting age range.
checkboxGroupInput("pclass", "Select Pclass", choices = c("First class"=1, "Second class"=2, "Third class" = 3),selected = c(1,2,3)),
checkboxGroupInput("sex", "Select Sex", choices = c("male","female"),selected = c("male", "female")),
sliderInput("age", "Select Age Range", min = 0, max = 80, value = c(0, 80)),
checkboxGroupInput("survival", "Did the passenger survive?", choices = c("survived" = 1, "died" = 0), selected = c(1,0))
#code end here
),
column(width = 8,
#display plot part
#code start here:
plotOutput("plot"),
#code end here:
)
)
)
server <- function(input, output) {
# Create a new data frame with all possible combinations of Pclass and Sex
all_combinations <- expand.grid(Pclass = c("1", "2", "3"), Sex = c("female", "male"))
# Join the new data frame with the original titanic dataset
titanic_complete <- merge(all_combinations, titanic, by = c("Pclass", "Sex"), all.x = TRUE)
# Convert Pclass and Survived to factors
titanic_complete$Pclass <- as.factor(titanic_complete$Pclass)
titanic_complete$Survived <- as.factor(titanic_complete$Survived)
#code start here:
#filter the data based on the selected gender, survival status, and age range.
titanic_filtered <- reactive({
#code start here:
#use subset() and take titanic_complete as data
#inside subset(), write conditions for pclass, sex, age, and survived variables to match user selected values.
subset(titanic_complete, (Sex == input$sex[1] | Sex == input$sex[2])&
(Survived == input$survival[1] | Survived == input$survival[2])&
Age >= input$age[1] & Age <= input$age[2]&
(Pclass == input$pclass[1] | Pclass == input$pclass[2] | Pclass == input$pclass[3]))
#code end here
})
output$plot <- renderPlot({
#code start here:
#creates a ggplot object using the filtered data as input: titanic_filtered(), setting the x-axis to the Age column and the fill to the Survived column
#use facet_wrap(), geom_density()
ggplot(titanic_filtered(), aes(x = Age, fill = Survived)) +
theme_bw() +
facet_wrap(Sex ~ Pclass) +
geom_density(alpha = 0.5) +
labs(y = "Age",
x = "Survived",
title = "Passenger Count by Age, Pclass and Sex")
#code end here
}, res = 96)
}
shinyApp(ui = ui, server = server)
Now, Let’s explore the interactive plot with mouse events using shiny
package!
6. Interactivity of shiny plot: mouse events
One of the coolest things about
plotOutput() is that as well as being an
output that displays plots, it can also be an input that responds to
pointer events. That allows you to create interactive graphics where the
user interacts directly with the data on the plot.
A plot can respond to four different mouse events: click, dblclick
(double click), hover (when the mouse stays in the same place for a
little while), and brush (a rectangular selection tool).
Try to use
plotOutput("plot", click = "plot_click") .
This creates an input$plot_click that you
can use to handle mouse clicks on the plot.
Now, Let’s explore the interactive plot with mouse events using shiny
package!
- Here is an example using mtcars dataset. Try it out and we will use
this pointer events input later for citibike analysis
Let’s start to create the interactive plot for citibike dataset using
shiny package.
7. Create interactive line graph with mouse event
Question: Is there a seasonality? Assumption: there are fewer trips
during winters and more trips during summers.
We want to displays a line graph of the count of bike rentals to let
you observe whether there is a seasonality for the count of bike
rentals.
- For better observation, we need to aggregate data by date and show
the sum of the bike rental counts.
library(lubridate)
#load the dataset
dataset <- read.csv('https://raw.githubusercontent.com/samantha96/cse160/main/train.csv')
dataset$date <- date(dataset$datetime)
# Check the result
head(dataset)
Create interactivity by appling the click or hover like the
example showed before.
Show the corrsponding bike rental information for that data you
click or hover. Here is an example: 
Try to run the following code and explore the mouse event for shiny
app. No need to write the code.
# Aggregate data by date to store the value
date_data <- summarise(group_by(dataset, date), total_count = sum(count))
# Define the UI
ui <- fluidPage(
titlePanel("Explore Bike Rentals seasonality"),
mainPanel(
plotOutput("plot", hover = hoverOpts("plot_hover")),
verbatimTextOutput("info")
)
)
# Define the server
server <- function(input, output) {
# Create the plot:line graph of the count of bike rentals by date
output$plot <- renderPlot({
ggplot(date_data, aes(x = date, y = total_count)) +
geom_line() +
labs(title = "Explore Bike Rentals seasonality",
x = "Date",
y = "Count")
})
# Create the hover or click information
output$info <- renderPrint({
if (is.null(input$plot_hover)) {
return()
}
x <- as.numeric(input$plot_hover$x)
y <- as.numeric(input$plot_hover$y)
# Find the closest point to the hover location
closest_point <- which.min(abs(as.numeric(date_data$date) - x))
paste(
#show information of click point about its date and count
"Date:", date_data$date[closest_point],
"Count:", date_data$total_count[closest_point]
)
})
}
# Run the app
shinyApp(ui, server)
8. Organize the R. files
For this notebook, we put them into one chunk to run the shiny
code.
If we want to keep your code organized and easier to maintain, we
could separate the UI and server functions into separate files..
we set up three files: ui.R to define the app presentation, server.R
to define the app logic, and shinyApp.R to run the former two.
1.ui.R
2.server.R
server <- function(input, output) {
# server logic goes here
}
# return the server object
server
3.shinyApp.R
source the ui.R and server.R files and then call the shinyApp function with the ui and server objects.
# source the UI and server files
source("ui.R")
source("server.R")
# create the Shiny app
shinyApp(ui = ui, server = server)
Combine these three R sricpts and all other materials(e.g.image) into
one single folder, which the folder path will be the path to publish
your shiny app.
9. Publish the shiny app.
Now, Let’s publish our shiny app. Create free account on shinyapp.io.
Install the rsconnect package, authorize account and deploy your app! https://www.shinyapps.io/admin/#/dashboard
library(rsconnect)
#The rsconnect package must be authorized to your account using a token and secret. Paste it into your R console to authorize your account.
#rsconnect::setAccountInfo(name='your name',
#token='your token',
#secret='<SECRET>')
#Once the rsconnect package has been configured, you're ready to deploy your first application.
#rsconnect::deployApp('/Users/samanthachen/Desktop/shinyapp')
Once you have published your app, you still can continue modify your
app and republish it.
- For this lab, submit your notebook and your published link for step
5.
LS0tCnRpdGxlOiAnIENyZWF0aW5nIGFuIFIgU2hpbnkgQXBwJwpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKRGF0ZTogMDQvMDUvMjAyMwotLS0KCkluIHRoaXMgbGFiLCB3ZSdsbCBjcmVhdGUgdGhlIFNoaW55IGFwcC4gVGhpcyBsYWIgd2lsbCBndWlkZSB5b3Ugd3JpdGUgYSBzaGlueSBhcHBsaWNhdGlvbiwgY3JlYXRlIGludGVyYWN0aXZlIHBsb3RzLCBwdWJsaXNoIHRoZSBzaGlueSBhcHBsaWNhdGlvbiBvbiBSU3R1ZGlvJ3Mgc2hpbnkgc2VydmVyLCB0aGVuIHlvdSB3aWxsIGJlIGFibGUgdG8gc2hhcmUgdGhlIGFwcGxpY2F0aW9uIGxpbmsuIFRoaXMgbGluayBjb250YWlucyB0aGUgdGhlIHNoaW55IGFwcCBkZW1vIHdlIHdhbnQgeW91IGNyZWF0ZSBkdXJpbmcgdGhpcyBsYWIsIGFuZCB5b3UgY291bGQgcHVibGlzaCBpdCBvbiBzaGlueSBzZXJ2ZXIuIDxodHRwczovL3h1ZWhhbmNoZW4uc2hpbnlhcHBzLmlvL3NoaW55YXBwLz4KClNoaW55IGlzIGFuIFIgcGFja2FnZSB0aGF0IGFsbG93cyB5b3UgdG8gZWFzaWx5IGNyZWF0ZSByaWNoLCBpbnRlcmFjdGl2ZSB3ZWIgYXBwcy4gU2hpbnkgYWxsb3dzIHlvdSB0byB0YWtlIHlvdXIgd29yayBpbiBSIGFuZCBleHBvc2UgaXQgdmlhIGEgd2ViIGJyb3dzZXIgc28gdGhhdCBhbnlvbmUgY2FuIHVzZSBpdC4gU2hpbnkgbWFrZXMgeW91IGxvb2sgYXdlc29tZSBieSBtYWtpbmcgaXQgZWFzeSB0byBwcm9kdWNlIHBvbGlzaGVkIHdlYiBhcHBzIHdpdGggYSBtaW5pbXVtIGFtb3VudCBvZiBwYWluLgoKIyAxLiBCYXNpYyAiU2hpbnkiIHN0cnVjdHVyZQoKYGBge3J9CiNpbnN0YWxsIHNldmVyYWwgcGFja2FnZXMKbGlicmFyeShzaGlueSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpgYGAKClRoZXJlIGFyZSBzZXZlcmFsIHdheXMgdG8gY3JlYXRlIGEgU2hpbnkgYXBwLgoKLSAgIFRoZSBzaW1wbGVzdCBpcyB0byBjcmVhdGUgYSBuZXcgZGlyZWN0b3J5IGZvciB5b3VyIGFwcCwgYW5kIHB1dCBhIHNpbmdsZSBmaWxlIGNhbGxlZCBzaGlueUFwcC5SIGluIGl0LgoKLSAgIE9yIHlvdSBjb3VsZCBzcGxpdCB5b3VyIGNvZGUgaW50byB0aHJlZSBmaWxlcyBmb3IgYmV0dGVyIG9yZ2FuaXphdGlvbjogdWkuUiwgc2VydmVyLlIsIHNoaW55QXBwLlIuCgpIZXJlIHdlIHB1dCBpdCBpbnRvIHNpbmdsZSBjaHVuayBvZiB0aGUgbm90ZWJvb2sgbGlrZSBhIHNpbmdsZSBzaGlueUFwcC5SIGZpbGUsIHNvIHlvdSBjb3VsZCBkaXJlY3RseSBydW4geW91ciBjb2RlIGluIHRoaXMgbm90ZWJvb2suCgpTaGlueSBhcHBsaWNhdGlvbnMgYXJlIGRpdmlkZWQgaW50byB0d28gcGFydHM6IHRoZSBVc2VyIEludGVyZmFjZSAoVUkpIGFuZCB0aGUgU2VydmVyLgoKLSAgIFRoZSBVSSBpcyByZXNwb25zaWJsZSBmb3IgdGhlIGFwcCBwcmVzZW50YXRpb24sIHdoaWxlIHRoZSBzZXJ2ZXIgaXMgcmVzcG9uc2libGUgZm9yIHRoZSBhcHAgbG9naWMuCgogICAgLSAgIFRoZSBVSSBpcyByZXNwb25zaWJsZSBmb3IgdGhlIGFwcCBwcmVzZW50YXRpb24uIEl0J3MgdHlwaWNhbGx5IGRlZmluZWQgdXNpbmcgdGhlICoqYGZsdWlkUGFnZSgpYCoqIG9yICoqYGZpeGVkUGFnZSgpYCoqIGZ1bmN0aW9ucyBmcm9tIHRoZSAqKmBzaGlueWAqKiBwYWNrYWdlLCBhbG9uZyB3aXRoIHZhcmlvdXMgVUkgZWxlbWVudHMgc3VjaCBhcyAqKmBwbG90T3V0cHV0KClgKiosICoqYHRleHRJbnB1dCgpYCoqLCAqKmBzZWxlY3RJbnB1dCgpYCoqLCBhbmQgc28gb24uIFRoZXNlIGVsZW1lbnRzIGFyZSBhcnJhbmdlZCB1c2luZyBsYXlvdXQgZnVuY3Rpb25zIHN1Y2ggYXMgKipgZmx1aWRSb3coKWAqKiwgKipgY29sdW1uKClgKiosICoqYHNpZGViYXJQYW5lbCgpYCoqLCBhbmQgb3RoZXJzLgoKICAgIC0gICBUaGUgc2VydmVyLCBvbiB0aGUgb3RoZXIgaGFuZCwgY29udGFpbnMgdGhlIGFwcCdzIGxvZ2ljIGFuZCBkYXRhIHByb2Nlc3NpbmcuIEl0IGRlZmluZXMgcmVhY3RpdmUgZXhwcmVzc2lvbnMgdXNpbmcgdGhlICoqYHJlYWN0aXZlKClgKiogb3IgKipgb2JzZXJ2ZSgpYCoqIGZ1bmN0aW9ucyB0aGF0IHVwZGF0ZSBiYXNlZCBvbiB1c2VyIGlucHV0IG9yIG90aGVyIHJlYWN0aXZlIHZhbHVlcy4gVGhlIHNlcnZlciBhbHNvIGNvbnRhaW5zIHRoZSBjb2RlIHRoYXQgZ2VuZXJhdGVzIHRoZSBvdXRwdXQgZGlzcGxheWVkIGluIHRoZSBVSSwgdXNpbmcgZnVuY3Rpb25zIHN1Y2ggYXMgKipgcmVuZGVyUGxvdCgpYCoqLCAqKmByZW5kZXJUYWJsZSgpYCoqLCBvciAqKmByZW5kZXJVSSgpYCoqLgoKVGhlIFVJIGFuZCBzZXJ2ZXIgd29yayB0b2dldGhlciB0byBjcmVhdGUgYW4gaW50ZXJhY3RpdmUgU2hpbnkgYXBwbGljYXRpb24gdGhhdCB1cGRhdGVzIGluIHJlYWwtdGltZSBiYXNlZCBvbiB1c2VyIGlucHV0IGFuZCByZWFjdGl2ZSB2YWx1ZXMuIENoZWNrIG1vcmUgZGV0YWlscyBvbiA8aHR0cHM6Ly9zaGlueS5yc3R1ZGlvLmNvbS90dXRvcmlhbC8+CgotICAgUnVuIHRoZSBmb2xsb3dpbmcgYmFzaWMgc2hpbnkgY29kZSwgb3BlbiB0aGUgYnJvd2VyLCB0aGVuIHlvdSBzaG91bGQgc2VlIGFuIGVtcHR5IHdlYiBhcHBsaWNhdGlvbi4KCi0gICBOb3RpY2UgdGhhdCBvbmNlIHlvdSBjbG9zZSB0aGUgd2Vic2l0ZSwgeW91IG1pZ2h0IHNlZSB0aGUgZXJyb3IgcmV0dXJucyBsaWtlOiBMaXN0ZW5pbmcgb24gPGh0dHA6Ly8+Li4uLi4uIFlvdSBjb3VsZCBpZ25vcmUgdGhpcyBlcnJvci4KCmBgYHtyfQp1aSA8LSBmbHVpZFBhZ2UoCiAgI3VpIGRlc2lnbiBnb2VzIGhlcmUKKQpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogICMgc2VydmVyIGxvZ2ljIGdvZXMgaGVyZQp9CiNQcmV2aWV3aW5nIHRoZSBhcHBsaWNhdGlvbi4gCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKYGBgCgojIDIuIEJhc2ljIFVJIGRlc2lnbjoKCk5vdywgbGV0J3MgZGVmaW5lIHRoZSB1aSBmdW5jdGlvbi4gVGhlcmUgYXJlIG1hbnkgYXBwcm9hY2hlcyB0byBhbGxvdyB0aGUgdXNlciB0byBjaG9vc2UgZnJvbSBhIHByZXNwZWNpZmllZCBzZXQgb2Ygb3B0aW9uczogZS5nLiBzZWxlY3RJbnB1dCgpIGFuZCByYWRpb0J1dHRvbnMoKS4KCi0gICBSdW4gdGhlIGZvbGxvd2luZyBleGFtcGxlIGFuZCBzZWUgdGhlIHVpIHByZXNlbnRhdGlvbi4KLSAgIE5vdGljZSB0aGF0IGZvciBVSSBmdW5jdGlvbiwgaXQgb25seSBzaG93cyB0aGUgYXBwIHByZXNlbnRhdGlvbiwgdGhlcmUgaXMgbm8gZGF0YSBwcm9jZXNzaW5nIGRlZmluZWQgaGVyZS4gVGhlIFVJIHByb3ZpZGVzIHRoZSB1c2VyIHdpdGggYSB3YXkgdG8gaW50ZXJhY3Qgd2l0aCB0aGUgYXBwLCB3aGlsZSB0aGUgU2VydmVyIHByb2Nlc3NlcyB0aGUgdXNlcidzIGlucHV0IGFuZCBnZW5lcmF0ZXMgb3V0cHV0IHRoYXQgaXMgZGlzcGxheWVkIGluIHRoZSBVSS4gV2Ugd2lsbCB0YWxrIGFib3V0IGl0IGxhdGVyIG9uLgoKYGBge3J9CmFuaW1hbHMgPC0gYygiZG9nIiwgImNhdCIsICJtb3VzZSIsICJiaXJkIiwgIm90aGVyIiwgIkkgaGF0ZSBhbmltYWxzIikKCnVpIDwtIGZsdWlkUGFnZSgKICBzZWxlY3RJbnB1dCgiYW5pbWFsIiwgIldoYXQncyB5b3VyIGZhdm91cml0ZSBzdGF0ZT8iLCBzdGF0ZS5uYW1lKSwKICByYWRpb0J1dHRvbnMoImFuaW1hbCIsICJXaGF0J3MgeW91ciBmYXZvdXJpdGUgYW5pbWFsPyIsIGFuaW1hbHMpCikKdWkKYGBgCgpUaGVyZSdzIG5vIHdheSB0byBzZWxlY3QgbXVsdGlwbGUgdmFsdWVzIHdpdGggcmFkaW8gYnV0dG9ucywgYnV0IHRoZXJlJ3MgYW4gYWx0ZXJuYXRpdmUgdGhhdCdzIGNvbmNlcHR1YWxseSBzaW1pbGFyOiBjaGVja2JveEdyb3VwSW5wdXQoKSBvciBzZWxlY3RpemVJbnB1dCgpLgoKLSAgIFRyeSB0byB3cml0ZSB1aSBmdW5jdGlvbiBmb3IgdGhlIHF1ZXN0aW9uOiAiV2hhdCBhbmltYWxzIGRvIHlvdSBsaWtlPyIgdXNpbmcgY2hlY2tib3hHcm91cElucHV0KCkgb3Igc2VsZWN0aXplSW5wdXQoKS4KCmBgYHtyfQojY29kZSBzdGFydCBoZXJlOgp1aSA8LSBmbHVpZFBhZ2UoCiAgY2hlY2tib3hHcm91cElucHV0KCJhbmltYWwiLCAiV2hhdCBhbmltYWxzIGRvIHlvdSBsaWtlPyIsIGFuaW1hbHMpCikKdWkKI2NvZGUgZW5kIGhlcmUKYGBgCgojIDMuIENyZWF0ZSB0aGUgdWkgYW5kIHNlcnZlciBmdW5jdGlvbiBmb3IgcGxvdC4KCk5vdyBsZXQncyBjcmVhdGUgc2hpbnkgYXBwIGZvciB0aGUgcGxvdCEKCllvdSBjYW4gZGlzcGxheSBhbnkgdHlwZSBvZiBSIGdyYXBoaWMgKGJhc2UsIGdncGxvdDIsIG9yIG90aGVyd2lzZSkgd2l0aCBwbG90T3V0cHV0KCkgYW5kIHJlbmRlclBsb3QoKS4KCi0gICBFeHBsb3JlIHRoZSBpbnB1dCBhbmQgb3V0cHV0IGFyZ3VtZW50IGluIHNlcnZlciBmdW50aW9uLiBUaGUgaW5wdXQgYXJndW1lbnQgcmVwcmVzZW50cyB0aGUgdXNlcidzIGlucHV0cyAoZS5nLiBmb3JtIGlucHV0cywgYnV0dG9ucyBjbGlja2VkLCBldGMuKSwgYW5kIHRoZSBvdXRwdXQgYXJndW1lbnQgcmVwcmVzZW50cyB0aGUgb3V0cHV0cyAoZS5nLiBwbG90cywgdGFibGVzLCBldGMuKSB0aGF0IHdpbGwgYmUgZGlzcGxheWVkIHRvIHRoZSB1c2VyLgoKLSAgIE91dHB1dHMgaW4gdGhlIFVJIGNyZWF0ZSBwbGFjZWhvbGRlcnMgdGhhdCBhcmUgbGF0ZXIgZmlsbGVkIGJ5IHRoZSBzZXJ2ZXIgZnVuY3Rpb24uIExpa2UgaW5wdXRzLCBvdXRwdXRzIHRha2UgYSB1bmlxdWUgSUQgYXMgdGhlaXIgZmlyc3QgYXJndW1lbnQ6IGlmIHlvdXIgVUkgc3BlY2lmaWNhdGlvbiBjcmVhdGVzIGFuIG91dHB1dCB3aXRoIElEICoqYCJwbG90ImAqKiwgbGlrZSAqKmBwbG90T3V0cHV0KCJwbG90IilgKiosIHlvdSdsbCBhY2Nlc3MgaXQgaW4gdGhlIHNlcnZlciBmdW5jdGlvbiB3aXRoICoqYG91dHB1dCRwbG90YCoqLgoKLSAgIEluIFIsICoqYHt9YCoqIGlzIHVzZWQgdG8gY3JlYXRlIGEgYmxvY2sgb2YgY29kZSB0aGF0IGNhbiBjb250YWluIG9uZSBvciBtb3JlIGV4cHJlc3Npb25zIG9yIHN0YXRlbWVudHMuIEluIHRoZSBjb250ZXh0IG9mIGEgZnVuY3Rpb24sIHRoZSAqKmB7fWAqKiBibG9jayBkZWZpbmVzIHRoZSBmdW5jdGlvbiBib2R5LCB3aGljaCBjb250YWlucyB0aGUgY29kZSB0aGF0IGlzIGV4ZWN1dGVkIHdoZW4gdGhlIGZ1bmN0aW9uIGlzIGNhbGxlZC4KCi0gICBUcnkgdG8gcnVuIHRoZSBmb2xsb3dpbmcgZXhhbXBsZToKCmBgYHtyfQp1aSA8LSBmbHVpZFBhZ2UoCiAgcGxvdE91dHB1dCgicGxvdCIpLAopCgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIG91dHB1dCRwbG90IDwtIHJlbmRlclBsb3QoewogICAgcGxvdChtdGNhcnMkd3QsIG10Y2FycyRtcGcpCiAgfSwgcmVzID0gOTYpCn0Kc2hpbnlBcHAodWkgPSB1aSwgc2VydmVyID0gc2VydmVyKQpgYGAKCkFmdGVyIHJ1bm5pbmcgdGhlIGV4YW1wbGUsIExldCdzIHN0YXJ0IGJ5IGJ1aWxkaW5nIGEgc2ltcGxlIHNoaW55IHBsb3QhCgpXZSB0cnkgdG8gZXhwbG9yZSB0aGUgdG9waWMgIlRpdGFuaWM6IFdoYXQgSGVscGVkIFlvdSBTdXJ2aXZlPyIuIFRoZSBnb2FsIGlzIHRvIGFzayBzZXZlcmFsIHF1ZXN0aW9ucyBhbmQgdXNpbmcgcGxvdCB0byBleHBsb3JlIGl0LgoKLSAgIFF1ZXN0aW9uIC0gV2hhdCB3YXMgdGhlIHN1cnZpdmFsIHJhdGUgYnkgZ2VuZGVyPwoKLSAgIFdlIGNhbiBjcmVhdGUgYSBncm91cGVkIGJhcmNoYXJ0LgoKICAgIEhlcmUgaXMgYW4gZXhhbXBsZSBwbG90OgoKIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9zYW1hbnRoYTk2L2NzZTE2MC9ibG9iL21haW4vZTEucG5nP3Jhdz10cnVlKQoKRmlyc3Qgd2UgbG9hZCBkYXRhIGFuZCBkbyBzaW1wbGUgY2xlYW4uCgpgYGB7cn0KIyBsb2FkIHRpdGFuaWMgZGF0YXNldApsaWJyYXJ5KHRpdGFuaWMpCnRpdGFuaWMgPC0gdGl0YW5pY190cmFpbgp0aXRhbmljIDwtIG5hLm9taXQodGl0YW5pYykKdGl0YW5pYyRQY2xhc3MgPC0gYXMuZmFjdG9yKHRpdGFuaWMkUGNsYXNzKQp0aXRhbmljJFN1cnZpdmVkIDwtIGFzLmZhY3Rvcih0aXRhbmljJFN1cnZpdmVkKQp0aXRhbmljJFNleCA8LSBhcy5mYWN0b3IodGl0YW5pYyRTZXgpCgpgYGAKCi0gICBZb3UgY291bGQgdHJ5IHRvIGNyZWF0ZSB0aGUgYmFyIGNoYXJ0IGZpcnN0LCB0aGVuIHB1dCBpdCBpbnRvIHVpIGFuZCBzZXJ2ZXIgZnVuY3Rpb24uCgogICAgLSAgIFVzaW5nICoqYGdlb21fYmFyKClgKiogaW4gKipgcmVuZGVyUGxvdCgpIGJsb2NrYCoqLiBZb3UgY2FuIHNwZWNpZnkgKipgcG9zaXRpb24gPSAiZG9kZ2UiYCoqIHRvIGdlbmVyYXRlIGEgZ3JvdXBlZCBiYXIgY2hhcnQuCgpgYGB7cn0KCnVpIDwtIGZsdWlkUGFnZSgKICAgICNjb2RlIHN0YXJ0IGhlcmU6CiAgICBwbG90T3V0cHV0KCJwbG90IiksCiAgICAjY29kZSBlbmQgaGVyZQopCgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogICNjb2RlIHN0YXJ0IGhlcmU6CiAgb3V0cHV0JHBsb3QgPC0gcmVuZGVyUGxvdCh7CiAgZ2dwbG90KHRpdGFuaWMsIGFlcyh4ID0gU2V4LCBmaWxsID0gU3Vydml2ZWQpKSArIAogIHRoZW1lX2J3KCkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnMoeSA9ICJQYXNzZW5nZXIgQ291bnQiLAogICAgICAgdGl0bGUgPSAiUGFzc2VuZ2VyIENvdW50IGJ5IFNleCIpCiAgfSwgcmVzID0gOTYpCiAgCiAgI2NvZGUgZW5kIGhlcmUKfQpzaGlueUFwcCh1aSA9IHVpLCBzZXJ2ZXIgPSBzZXJ2ZXIpCmBgYAoKIyA0LiBBZGQgc2VsZWN0aW9uIGlucHV0IGFuZCBwcm9jZXNzIHNlbGVjdGVkIGRhdGEKCk5vdywgbGV0J3MgYWRkIHNlbGVjdGlvbiBpbnB1dCBmb3IgaW50ZXJhY3RpdmUgcGxvdCBpbiBzaGlueS4gWW91IGNvdWxkIGNob29zZSB0aGUgc2VsZWN0aW9uIGZ1bmN0aW9uIHlvdSBsaWtlIGZyb20gc3RlcCAyLiBUaGUgZ29hbCBpcyB0byBjcmVhdGUgc2VsZWN0aW9uIGNob2ljZXMgZm9yIHN1cnZpdmVkIGFuZCBzZXggdmFyaWFibGVzIGZvciB0aGUgcGxvdC4KCi0gICAqKmBDaGVja2JveEdyb3VwSW5wdXQoKWAqKjpGb3Igc3Vydml2YWwgc2VsZWN0aW9uLCB0aGUgY2hvaWNlcyBmb3IgdGhlIGlucHV0IGFyZSAic3Vydml2ZWQiIGFuZCAiZGllZCIsIHdoaWNoIGNvcnJlc3BvbmQgdG8gdGhlIG51bWVyaWMgdmFsdWVzIG9mIDEgYW5kIDAsIHJlc3BlY3RpdmVseS4gVGhlc2UgY2hvaWNlcyBhcmUgc3BlY2lmaWVkIHVzaW5nIHRoZSAqKmBjaG9pY2VzYCoqIGFyZ3VtZW50LlRoZSAqKmBzZWxlY3RlZGAqKiBhcmd1bWVudCBpcyB1c2VkIHRvIHNldCB0aGUgZGVmYXVsdCBzZWxlY3Rpb25zIGZvciB0aGUgY2hlY2tib3hlcy4gV2hlbiB0aGUgdXNlciBpbnRlcmFjdHMgd2l0aCB0aGUgaW5wdXQgZWxlbWVudCwgdGhlIHNlbGVjdGVkIGNob2ljZXMgYXJlIHN0b3JlZCBpbiB0aGUgKipgaW5wdXQkc3Vydml2YWxgKiogdmFyaWFibGUgaW4gdGhlIFNoaW55IGFwcCBzZXJ2ZXIuCgotICAgVGhlICoqYHN1YnNldCgpYCoqIGZ1bmN0aW9uIHRha2VzIHRoZSBkYXRhIGFzIGl0cyBmaXJzdCBhcmd1bWVudCwgZm9sbG93ZWQgYnkgdGhlIGNvbmRpdGlvbnMgdG8gZmlsdGVyIHRoZSBkYXRhLiBVc2VzIHRoZSAqKmBzdWJzZXQoKWAqKiBmdW5jdGlvbiB0byBmaWx0ZXIgdGhlICoqYHRpdGFuaWNgKiogZGF0YXNldCBiYXNlZCBvbiB0d28gY29uZGl0aW9uczogKipgc2V4ID09IGlucHV0JHNleGAqKiBhbmQgKipgc3Vydml2ZWQgPT0gaW5wdXQkc3Vydml2YWxgKiouIEl0IGNoZWNrcyBpZiB0aGUgZ2VuZGVyIG9mIGVhY2ggcGFzc2VuZ2VyIGluIHRoZSB0aXRhbmljIGRhdGFzZXQgaXMgY29udGFpbmVkIGluIHRoZSAqKmBpbnB1dCRzZXhgKiogdmVjdG9yIGFuZCBpZiB0aGUgc3Vydml2YWwgc3RhdHVzIG9mIGVhY2ggcGFzc2VuZ2VyIGlzIGNvbnRhaW5lZCBpbiB0aGUgKipgaW5wdXQkc3Vydml2YWxgKiogdmVjdG9yLiB3ZSBjb3VsZCB3cml0ZSB0aGUgY29uZGl0aW9uKipgKFNleCA9PSBpbnB1dCRzZXhbMV18IFNleCA9PSBpbnB1dCRzZXhbMl0pLmAqKiBJdCBpcyBjaGVja2luZyBpZiB0aGUgdmFsdWUgaW4gdGhlICoqYFNleGAqKiBjb2x1bW4gb2YgdGhlICoqYHRpdGFuaWNgKiogZGF0YSBmcmFtZSBpcyBlcXVhbCB0byB0aGUgZmlyc3Qgb3Igc2Vjb25kIGVsZW1lbnQgaW4gdGhlICoqYGlucHV0JHNleGAqKiB2ZWN0b3IuIEJ5IHVzaW5nICoqYFsxXWAqKiBhZnRlciAqKmBpbnB1dCRzZXhgKiosIHdlIGFyZSBzcGVjaWZ5aW5nIHRoYXQgd2Ugb25seSB3YW50IHRvIGNvbXBhcmUgd2l0aCB0aGUgZmlyc3QgZWxlbWVudCBpbiB0aGUgdmVjdG9yLgoKSGVyZSBpcyBhbiBleGFtcGxlOiAhW10oaHR0cHM6Ly9naXRodWIuY29tL3NhbWFudGhhOTYvY3NlMTYwL2Jsb2IvbWFpbi9lMi5wbmc/cmF3PXRydWUpCgpUcnkgdG8gcnVuIHRoZSBmb2xsb3dpbmcgc2hpbnkgYXBwIGV4YW1wbGU6CgpgYGB7cn0KCnVpIDwtIGZsdWlkUGFnZSgKICAgICNBZGQgdHdvIGNoZWNrYm94R3JvdXBJbnB1dCgpIGVsZW1lbnRzLCBvbmUgZm9yIHRoZSBzdXJ2aXZhbCBzdGF0dXMgYW5kIG9uZSBmb3IgdGhlIGdlbmRlciBvZiB0aGUgcGFzc2VuZ2Vycy4gU2V0IHRoZWlyIGluaXRpYWwgc2VsZWN0aW9ucyB1c2luZyB0aGUgc2VsZWN0ZWQgYXJndW1lbnQuCiAgICBjaGVja2JveEdyb3VwSW5wdXQoInN1cnZpdmFsIiwgIkRpZCB0aGUgcGFzc2VuZ2VyIHN1cnZpdmU/IiwgIGNob2ljZXMgPSBjKCJzdXJ2aXZlZCIgPSAxLCAiZGllZCIgPSAwKSwgc2VsZWN0ZWQgPSBjKDEsMCkpLAogICAgY2hlY2tib3hHcm91cElucHV0KCJzZXgiLCAiV2hhdCBpcyB0aGUgZ2VuZGVyIG9mIHRoZSBwYXNzZW5nZXI/IiwgY2hvaWNlcyA9IGMoIm1hbGUiLCAiZmVtYWxlIiksIHNlbGVjdGVkID0gYygibWFsZSIsICJmZW1hbGUiKSksCiAgICAjQWRkIGEgcGxvdE91dHB1dCgpIGVsZW1lbnQgdG8gZGlzcGxheSB0aGUgcGxvdC4KICAgIHBsb3RPdXRwdXQoInBsb3QiKSwKCikKCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7CiBvdXRwdXQkcGxvdCA8LSByZW5kZXJQbG90KHsKICAgICNJbiB0aGUgcmVuZGVyUGxvdCgpIGZ1bmN0aW9uLCBmaWx0ZXIgdGhlIGRhdGEgYmFzZWQgb24gdGhlIHNlbGVjdGVkIGdlbmRlciBhbmQgc3Vydml2YWwgc3RhdHVzIHVzaW5nIHN1YnNldCgpLgogICAgZmlsdGVyZWRfZGF0YSA8LSBzdWJzZXQodGl0YW5pYywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU2V4ID09IGlucHV0JHNleFsxXXwgU2V4ID09aW5wdXQkc2V4WzJdKSAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU3Vydml2ZWQgPT0gaW5wdXQkc3Vydml2YWxbMV18U3Vydml2ZWQgPT0gaW5wdXQkc3Vydml2YWxbMl0pKQogICAgI0NyZWF0ZSBiYXJjaGFydCB1c2luZyB0aGUgZmlsdGVyZWQgZGF0YS4KICAgICNjb2RlIHN0YXJ0IGhlcmU6CiAgICBnZ3Bsb3QoZmlsdGVyZWRfZGF0YSwgYWVzKHggPSBTZXgsIGZpbGwgPSBTdXJ2aXZlZCkpICsgCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IC4uY291bnQuLiksIHN0YXQgPSAiY291bnQiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwgdmp1c3QgPSAtMC41LCBzaXplID0gMykgKwogICAgICAjQWRkIGxhYmVscyB0byB0aGUgcGxvdCB1c2luZyBsYWJzKCkgZm9yIHRoZSB5LWF4aXMgYW5kIHRpdGxlLgogICAgICBsYWJzKHkgPSAiUGFzc2VuZ2VyIENvdW50IiwKICAgICAgICAgICB0aXRsZSA9ICJQYXNzZW5nZXIgQ291bnQgYnkgU2V4IikKICAgICNjb2RlIGVuZCBoZXJlCiAgICAKICAgIH0sIHJlcyA9IDk2KQp9CgojRmluYWxseSwgcnVuIHRoZSBTaGlueSBhcHAgdXNpbmcgc2hpbnlBcHAoKS4Kc2hpbnlBcHAodWkgPSB1aSwgc2VydmVyID0gc2VydmVyKQpgYGAKCiMgNS4gQnVpbGQgb3VyIHNoaW55IGFwcC4KCiMgUXVlc3Rpb24gLSBXaGF0IGlzIHRoZSBudW1iZXIgb2Ygc3Vydml2YWwgcGFzc2VuZ2VycyBieSBhZ2Ugd2hlbiBzZWdtZW50ZWQgYnkgZ2VuZGVyIGFuZCBjbGFzcyBvZiB0aWNrZXQ/CgotICAgQSByZWxhdGVkIHZpc3VhbGl6YXRpb24gdG8gdGhlIGhpc3RvZ3JhbSBpcyBhIGRlbnNpdHkgcGxvdC4gVGhpbmsgb2YgYSBkZW5zaXR5IHBsb3QgYXMgYSBzbW9vdGhlZCB2ZXJzaW9uIG9mIHRoZSBoaXN0b2dyYW0uCgotICAgPGRpdj4KCiAgICAxLiAgVUk6IENyZWF0ZSBzZWxlY3Rpb24gaW5wdXQgZm9yIHBjbGFzcywgc2V4LCBzdXJ2aXZlZCwgYW5kIHNsaWRlcklucHV0KCkgZm9yIGFnZS4KCiAgICA8L2Rpdj4KCi0gICA8ZGl2PgoKICAgIDIuICBTZXJ2ZXI6IFdlIGNhbiB1c2UgZmFjZXRfd3JhcChTZXggXH4gUGNsYXNzKSArIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgdG8gYWxsb3cgZm9yIHZpc3VhbCBkcmlsbC1kb3duIHZpYSBkZW5zaXR5IHBsb3RzLiBUaGVuIHdlIG5lZWQgdG8gdGhpbmsgaG93IHRvIGdldCBmaWx0ZXJlZCBpbnB1dCBkYXRhIGJhc2VkIG9uIGhvdyB1c2VyIHNlbGVjdGlvbi4KCiAgICAgICAgLSAgIEZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbiwgd2UgbmVlZCB0byBjcmVhdGUgYSBuZXcgZGF0YSBmcmFtZSAqKmB0aXRhbmljX2NvbXBsZXRlYCoqIHdpdGggYWxsIHBvc3NpYmxlIGNvbWJpbmF0aW9ucyBvZiBQY2xhc3MgYW5kIFNleC4gVGhlIHJlYXNvbiBmb3IgY3JlYXRpbmcgYSBuZXcgZGF0YSBmcmFtZSB3aXRoIGFsbCBwb3NzaWJsZSBjb21iaW5hdGlvbnMgb2YgUGNsYXNzIGFuZCBTZXggaXMgdG8gZW5zdXJlIHRoYXQgdGhlIHBsb3QgYWx3YXlzIGRpc3BsYXlzIGFsbCBjb21iaW5hdGlvbnMgb2YgUGNsYXNzIGFuZCBTZXgsIGV2ZW4gaWYgdGhlcmUgYXJlIG5vIG9ic2VydmF0aW9ucyBpbiB0aGUgb3JpZ2luYWwgZGF0YXNldCBmb3IgYSBwYXJ0aWN1bGFyIGNvbWJpbmF0aW9uLiBUaGlzIGlzIGltcG9ydGFudCBmb3IgdGhlIHZpc3VhbGl6YXRpb24gdG8gYWNjdXJhdGVseSByZWZsZWN0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGRhdGEgYW5kIGF2b2lkIG1pc2xlYWRpbmcgaW50ZXJwcmV0YXRpb25zLgoKICAgICAgICAtICAgVXNlcyB0aGUgKipgc3Vic2V0KClgKiogZnVuY3Rpb24gdG8gZmlsdGVyIHRoZSAqKmB0aXRhbmljX2NvbXBsZXRlYCoqIGRhdGFzZXQuIEluIHRoaXMgY2FzZSwgKipgcGNsYXNzYCoqLCAqKmBzZXhgKiosICoqYGFnZWAqKiwgYW5kICoqYHN1cnZpdmVkYCoqIHZhcmlhYmxlcyBhcmUgZmlsdGVyZWQgdXNpbmcgdGhlICoqYD09YCoqIG9wZXJhdG9yIHRvIG1hdGNoIHRoZSB1c2VyLXNlbGVjdGVkIHZhbHVlcy4gVGhlICoqYGFnZWAqKiB2YXJpYWJsZSBpcyBmaWx0ZXJlZCBiYXNlZCBvbiBhIHJhbmdlIG9mIHZhbHVlcyB1c2luZyB0aGUgKipgPj1gKiogYW5kICoqYDw9YCoqIG9wZXJhdG9ycy4gKipgaW5wdXQkYWdlWzFdYCoqIGFuZCAqKmBpbnB1dCRhZ2VbMl1gKiogYXJlIHVzZWQgdG8gZXh0cmFjdCB0aGUgbWluaW11bSBhbmQgbWF4aW11bSBhZ2UgdmFsdWVzIHNlbGVjdGVkIGJ5IHRoZSB1c2VyIHVzaW5nIHRoZSAqKmBzbGlkZXJJbnB1dCgpYCoqIGZ1bmN0aW9uLgoKICAgICAgICAtICAgKipgV2UgcHV0IHRoZSBzZWJzZXQoKSBpbnNpZGUgdGhlIFJlYWN0aXZlIGZ1bmN0aW9uIGluIHRoaXMgY2FzZS4gUmVhY3RpdmUoKWAqKiBmdW5jdGlvbiBjcmVhdGVzIGEgcmVhY3RpdmUgZXhwcmVzc2lvbiB0aGF0IGZpbHRlcnMgdGhlIGRhdGEgaW4gKipgdGl0YW5pY19jb21wbGV0ZWAqKiBiYXNlZCBvbiB0aGUgdXNlciBpbnB1dCB2YWx1ZXMgZm9yICoqYHBjbGFzc2AqKiwgKipgc2V4YCoqLCAqKmBhZ2VgKiogYW5kICoqYHN1cnZpdmVkYCoqLiBUaGUgcmVhY3RpdmUgZXhwcmVzc2lvbiByZXR1cm5zIHRoZSBmaWx0ZXJlZCBkYXRhIHRoYXQgY2FuIGJlIHVzZWQgdG8gcmVuZGVyIHRoZSBwbG90LiBXaGVuZXZlciB0aGVyZSBpcyBhIGNoYW5nZSBpbiBhbnkgb2YgdGhlIGlucHV0IHZhbHVlcywgdGhlIHJlYWN0aXZlIGV4cHJlc3Npb24gd2lsbCByZS1leGVjdXRlIGFuZCB0aGUgcGxvdCB3aWxsIGJlIHVwZGF0ZWQgYWNjb3JkaW5nbHkuCgogICAgPC9kaXY+CgotICAgSGVyZSBpcyBhbiBleGFtcGxlOiA8aHR0cHM6Ly94dWVoYW5jaGVuLnNoaW55YXBwcy5pby9zaGlueWFwcC8+IVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9zYW1hbnRoYTk2L2NzZTE2MC9ibG9iL21haW4vZTMucG5nP3Jhdz10cnVlKQoKYGBge3J9CnVpIDwtIGZsdWlkUGFnZSgKICAjdXNlIGZsdWlkUm93KCkgdG8gY29udHJvbCB0aGUgcGxvdCBsYXlvdXQKICBmbHVpZFJvdygKICAgIGNvbHVtbih3aWR0aCA9IDQsCiAgICAgICAgICAgI3NlbGVjdGlvbiBjb250cm9sIHBhcnQKICAgICAgICAgICAgI2NvZGUgc3RhcnQgaGVyZToKICAgICAgICAgICAgICAgI0FkZCB0aHJlZSBzZWxlY3Rpb24gZWxlbWVudHMsIG9uZSBmb3IgdGhlIHN1cnZpdmFsIHN0YXR1cywgb25lIGZvciBwY2xhc3MgYW5kIG9uZSBmb3IgdGhlIGdlbmRlciBvZiB0aGUgcGFzc2VuZ2Vycy4gU2V0IHRoZWlyIGluaXRpYWwgc2VsZWN0aW9ucyB1c2luZyB0aGUgc2VsZWN0ZWQgYXJndW1lbnQuCiAgICAgICAgICAgICAgICNBZGQgb25lIHNsaWRlciBmb3Igc2VsZWN0aW5nIGFnZSByYW5nZS4KICAgICAgICAgICBjaGVja2JveEdyb3VwSW5wdXQoInBjbGFzcyIsICJTZWxlY3QgUGNsYXNzIiwgY2hvaWNlcyA9IGMoIkZpcnN0IGNsYXNzIj0xLCAiU2Vjb25kIGNsYXNzIj0yLCAiVGhpcmQgY2xhc3MiID0gMyksc2VsZWN0ZWQgPSBjKDEsMiwzKSksCiAgICAgICAgICAgY2hlY2tib3hHcm91cElucHV0KCJzZXgiLCAiU2VsZWN0IFNleCIsIGNob2ljZXMgPSBjKCJtYWxlIiwiZmVtYWxlIiksc2VsZWN0ZWQgPSBjKCJtYWxlIiwgImZlbWFsZSIpKSwKICAgICAgICAgICBzbGlkZXJJbnB1dCgiYWdlIiwgIlNlbGVjdCBBZ2UgUmFuZ2UiLCBtaW4gPSAwLCBtYXggPSA4MCwgdmFsdWUgPSBjKDAsIDgwKSksCiAgICAgICAgICAgY2hlY2tib3hHcm91cElucHV0KCJzdXJ2aXZhbCIsICJEaWQgdGhlIHBhc3NlbmdlciBzdXJ2aXZlPyIsICBjaG9pY2VzID0gYygic3Vydml2ZWQiID0gMSwgImRpZWQiID0gMCksIHNlbGVjdGVkID0gYygxLDApKQogICAgICAgICAgIAogICAgICAgICAgIAogICAgICAgICAgICAjY29kZSBlbmQgaGVyZQogICAgKSwKICAgIGNvbHVtbih3aWR0aCA9IDgsCiAgICAgICAgICAgI2Rpc3BsYXkgcGxvdCBwYXJ0CiAgICAgICAgICAgICAjY29kZSBzdGFydCBoZXJlOgogICAgICAgICAgIHBsb3RPdXRwdXQoInBsb3QiKSwKICAgICAgICAgICAKICAgICAgICAgICAgI2NvZGUgZW5kIGhlcmU6CiAgICApCiAgKQopCgoKCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7CiAgIyBDcmVhdGUgYSBuZXcgZGF0YSBmcmFtZSB3aXRoIGFsbCBwb3NzaWJsZSBjb21iaW5hdGlvbnMgb2YgUGNsYXNzIGFuZCBTZXgKICAgIGFsbF9jb21iaW5hdGlvbnMgPC0gZXhwYW5kLmdyaWQoUGNsYXNzID0gYygiMSIsICIyIiwgIjMiKSwgU2V4ID0gYygiZmVtYWxlIiwgIm1hbGUiKSkKCiAgICAjIEpvaW4gdGhlIG5ldyBkYXRhIGZyYW1lIHdpdGggdGhlIG9yaWdpbmFsIHRpdGFuaWMgZGF0YXNldAogICAgdGl0YW5pY19jb21wbGV0ZSA8LSBtZXJnZShhbGxfY29tYmluYXRpb25zLCB0aXRhbmljLCBieSA9IGMoIlBjbGFzcyIsICJTZXgiKSwgYWxsLnggPSBUUlVFKQoKICAgICMgQ29udmVydCBQY2xhc3MgYW5kIFN1cnZpdmVkIHRvIGZhY3RvcnMKICAgIHRpdGFuaWNfY29tcGxldGUkUGNsYXNzIDwtIGFzLmZhY3Rvcih0aXRhbmljX2NvbXBsZXRlJFBjbGFzcykKICAgIHRpdGFuaWNfY29tcGxldGUkU3Vydml2ZWQgPC0gYXMuZmFjdG9yKHRpdGFuaWNfY29tcGxldGUkU3Vydml2ZWQpCiAgCiAgI2NvZGUgc3RhcnQgaGVyZToKICAgICNmaWx0ZXIgdGhlIGRhdGEgYmFzZWQgb24gdGhlIHNlbGVjdGVkIGdlbmRlciwgc3Vydml2YWwgc3RhdHVzLCBhbmQgYWdlIHJhbmdlLgoKCnRpdGFuaWNfZmlsdGVyZWQgPC0gcmVhY3RpdmUoewogICNjb2RlIHN0YXJ0IGhlcmU6CiAgI3VzZSBzdWJzZXQoKSBhbmQgdGFrZSB0aXRhbmljX2NvbXBsZXRlIGFzIGRhdGEKICAjaW5zaWRlIHN1YnNldCgp77yMIHdyaXRlIGNvbmRpdGlvbnMgZm9yIHBjbGFzcywgc2V4LCBhZ2UsIGFuZCBzdXJ2aXZlZCB2YXJpYWJsZXMgdG8gbWF0Y2ggdXNlciBzZWxlY3RlZCB2YWx1ZXMuCiAgCgogIHN1YnNldCh0aXRhbmljX2NvbXBsZXRlLCAoU2V4ID09IGlucHV0JHNleFsxXSB8IFNleCA9PSBpbnB1dCRzZXhbMl0pJiAKICAgICAgICAgKFN1cnZpdmVkID09IGlucHV0JHN1cnZpdmFsWzFdIHwgU3Vydml2ZWQgPT0gaW5wdXQkc3Vydml2YWxbMl0pJiAKICAgICAgICAgQWdlID49IGlucHV0JGFnZVsxXSAmIEFnZSA8PSBpbnB1dCRhZ2VbMl0mCiAgICAgICAgIChQY2xhc3MgPT0gaW5wdXQkcGNsYXNzWzFdIHwgUGNsYXNzID09IGlucHV0JHBjbGFzc1syXSB8IFBjbGFzcyA9PSBpbnB1dCRwY2xhc3NbM10pKQoKICAKICAKICAjY29kZSBlbmQgaGVyZQogIH0pCgoKICBvdXRwdXQkcGxvdCA8LSByZW5kZXJQbG90KHsKICAgIAogICAgI2NvZGUgc3RhcnQgaGVyZToKICAgICNjcmVhdGVzIGEgZ2dwbG90IG9iamVjdCB1c2luZyB0aGUgZmlsdGVyZWQgZGF0YSBhcyBpbnB1dDogdGl0YW5pY19maWx0ZXJlZCgpLCBzZXR0aW5nICAgICAgdGhlIHgtYXhpcyB0byB0aGUgQWdlIGNvbHVtbiBhbmQgdGhlIGZpbGwgdG8gdGhlIFN1cnZpdmVkIGNvbHVtbiAKICAgICN1c2UgZmFjZXRfd3JhcCgpLCBnZW9tX2RlbnNpdHkoKQogICAgCgogICAgZ2dwbG90KHRpdGFuaWNfZmlsdGVyZWQoKSwgYWVzKHggPSBBZ2UsIGZpbGwgPSBTdXJ2aXZlZCkpICsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIGZhY2V0X3dyYXAoU2V4IH4gUGNsYXNzKSArCiAgICAgIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKwogICAgICBsYWJzKHkgPSAiQWdlIiwKICAgICAgICAgICB4ID0gIlN1cnZpdmVkIiwKICAgICAgICAgICB0aXRsZSA9ICJQYXNzZW5nZXIgQ291bnQgYnkgQWdlLCBQY2xhc3MgYW5kIFNleCIpCiAgICAjY29kZSBlbmQgaGVyZQogICAgCiAgfSwgcmVzID0gOTYpCn0KCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKYGBgCgpOb3csIExldCdzIGV4cGxvcmUgdGhlIGludGVyYWN0aXZlIHBsb3Qgd2l0aCBtb3VzZSBldmVudHMgdXNpbmcgc2hpbnkgcGFja2FnZSEKCiMgNi4gSW50ZXJhY3Rpdml0eSBvZiBzaGlueSBwbG90OiBtb3VzZSBldmVudHMKCk9uZSBvZiB0aGUgY29vbGVzdCB0aGluZ3MgYWJvdXQgKipgcGxvdE91dHB1dCgpYCoqIGlzIHRoYXQgYXMgd2VsbCBhcyBiZWluZyBhbiBvdXRwdXQgdGhhdCBkaXNwbGF5cyBwbG90cywgaXQgY2FuIGFsc28gYmUgYW4gaW5wdXQgdGhhdCByZXNwb25kcyB0byBwb2ludGVyIGV2ZW50cy4gVGhhdCBhbGxvd3MgeW91IHRvIGNyZWF0ZSBpbnRlcmFjdGl2ZSBncmFwaGljcyB3aGVyZSB0aGUgdXNlciBpbnRlcmFjdHMgZGlyZWN0bHkgd2l0aCB0aGUgZGF0YSBvbiB0aGUgcGxvdC4KCkEgcGxvdCBjYW4gcmVzcG9uZCB0byBmb3VyIGRpZmZlcmVudCBtb3VzZSBldmVudHM6IGNsaWNrLCBkYmxjbGljayAoZG91YmxlIGNsaWNrKSwgaG92ZXIgKHdoZW4gdGhlIG1vdXNlIHN0YXlzIGluIHRoZSBzYW1lIHBsYWNlIGZvciBhIGxpdHRsZSB3aGlsZSksIGFuZCBicnVzaCAoYSByZWN0YW5ndWxhciBzZWxlY3Rpb24gdG9vbCkuCgpUcnkgdG8gdXNlICoqYHBsb3RPdXRwdXQoInBsb3QiLCBjbGljayA9ICJwbG90X2NsaWNrIilgKiogLiBUaGlzIGNyZWF0ZXMgYW4gKipgaW5wdXQkcGxvdF9jbGlja2AqKiB0aGF0IHlvdSBjYW4gdXNlIHRvIGhhbmRsZSBtb3VzZSBjbGlja3Mgb24gdGhlIHBsb3QuCgpOb3csIExldCdzIGV4cGxvcmUgdGhlIGludGVyYWN0aXZlIHBsb3Qgd2l0aCBtb3VzZSBldmVudHMgdXNpbmcgc2hpbnkgcGFja2FnZSEKCi0gICBIZXJlIGlzIGFuIGV4YW1wbGUgdXNpbmcgbXRjYXJzIGRhdGFzZXQuIFRyeSBpdCBvdXQgYW5kIHdlIHdpbGwgdXNlIHRoaXMgcG9pbnRlciBldmVudHMgaW5wdXQgbGF0ZXIgZm9yIGNpdGliaWtlIGFuYWx5c2lzCgpgYGB7cn0KdWkgPC0gZmx1aWRQYWdlKAogICNjb2RlIHN0YXJ0IGhlcmU6CiAgcGxvdE91dHB1dCgicGxvdCIsIGNsaWNrID0gInBsb3RfY2xpY2siKSwKICB2ZXJiYXRpbVRleHRPdXRwdXQoImluZm8iKQopCgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIG91dHB1dCRwbG90IDwtIHJlbmRlclBsb3QoewogICAgcGxvdChtdGNhcnMkd3QsIG10Y2FycyRtcGcpCiAgfSwgcmVzID0gOTYpCgogIG91dHB1dCRpbmZvIDwtIHJlbmRlclByaW50KHsKICAgIHJlcShpbnB1dCRwbG90X2NsaWNrKQogICAgeCA8LSByb3VuZChpbnB1dCRwbG90X2NsaWNrJHgsIDIpCiAgICB5IDwtIHJvdW5kKGlucHV0JHBsb3RfY2xpY2skeSwgMikKICAgIGNhdCgiWyIsIHgsICIsICIsIHksICJdIiwgc2VwID0gIiIpCiAgfSkKfQpzaGlueUFwcCh1aSA9IHVpLCBzZXJ2ZXIgPSBzZXJ2ZXIpCmBgYAoKTGV0J3Mgc3RhcnQgdG8gY3JlYXRlIHRoZSBpbnRlcmFjdGl2ZSBwbG90IGZvciBjaXRpYmlrZSBkYXRhc2V0IHVzaW5nIHNoaW55IHBhY2thZ2UuCgojIDcuIENyZWF0ZSBpbnRlcmFjdGl2ZSBsaW5lIGdyYXBoIHdpdGggbW91c2UgZXZlbnQKClF1ZXN0aW9uOiBJcyB0aGVyZSBhIHNlYXNvbmFsaXR5PyBBc3N1bXB0aW9uOiB0aGVyZSBhcmUgZmV3ZXIgdHJpcHMgZHVyaW5nIHdpbnRlcnMgYW5kIG1vcmUgdHJpcHMgZHVyaW5nIHN1bW1lcnMuCgpXZSB3YW50IHRvIGRpc3BsYXlzIGEgbGluZSBncmFwaCBvZiB0aGUgY291bnQgb2YgYmlrZSByZW50YWxzIHRvIGxldCB5b3Ugb2JzZXJ2ZSB3aGV0aGVyIHRoZXJlIGlzIGEgc2Vhc29uYWxpdHkgZm9yIHRoZSBjb3VudCBvZiBiaWtlIHJlbnRhbHMuCgotICAgRm9yIGJldHRlciBvYnNlcnZhdGlvbiwgd2UgbmVlZCB0byBhZ2dyZWdhdGUgZGF0YSBieSBkYXRlIGFuZCBzaG93IHRoZSBzdW0gb2YgdGhlIGJpa2UgcmVudGFsIGNvdW50cy4KCmBgYHtyfQpsaWJyYXJ5KGx1YnJpZGF0ZSkKI2xvYWQgdGhlIGRhdGFzZXQKZGF0YXNldCA8LSByZWFkLmNzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NhbWFudGhhOTYvY3NlMTYwL21haW4vdHJhaW4uY3N2JykKZGF0YXNldCRkYXRlIDwtIGRhdGUoZGF0YXNldCRkYXRldGltZSkKIyBDaGVjayB0aGUgcmVzdWx0CmhlYWQoZGF0YXNldCkKYGBgCgotICAgQ3JlYXRlIGludGVyYWN0aXZpdHkgYnkgYXBwbGluZyB0aGUgY2xpY2sgb3IgaG92ZXIgbGlrZSB0aGUgZXhhbXBsZSBzaG93ZWQgYmVmb3JlLgoKLSAgIFNob3cgdGhlIGNvcnJzcG9uZGluZyBiaWtlIHJlbnRhbCBpbmZvcm1hdGlvbiBmb3IgdGhhdCBkYXRhIHlvdSBjbGljayBvciBob3Zlci4gSGVyZSBpcyBhbiBleGFtcGxlOiAhW10oaHR0cHM6Ly9naXRodWIuY29tL3NhbWFudGhhOTYvY3NlMTYwL2Jsb2IvbWFpbi9leGFtcGxlNS5wbmc/cmF3PXRydWUpCgogICAgVHJ5IHRvIHJ1biB0aGUgZm9sbG93aW5nIGNvZGUgYW5kIGV4cGxvcmUgdGhlIG1vdXNlIGV2ZW50IGZvciBzaGlueSBhcHAuIE5vIG5lZWQgdG8gd3JpdGUgdGhlIGNvZGUuCgpgYGB7cn0KCiMgQWdncmVnYXRlIGRhdGEgYnkgZGF0ZSB0byBzdG9yZSB0aGUgdmFsdWUKCmRhdGVfZGF0YSA8LSBzdW1tYXJpc2UoZ3JvdXBfYnkoZGF0YXNldCwgZGF0ZSksIHRvdGFsX2NvdW50ID0gc3VtKGNvdW50KSkKCiMgRGVmaW5lIHRoZSBVSQp1aSA8LSBmbHVpZFBhZ2UoCiAgdGl0bGVQYW5lbCgiRXhwbG9yZSBCaWtlIFJlbnRhbHMgc2Vhc29uYWxpdHkiKSwKICAKICBtYWluUGFuZWwoCiAgICBwbG90T3V0cHV0KCJwbG90IiwgaG92ZXIgPSBob3Zlck9wdHMoInBsb3RfaG92ZXIiKSksCiAgICB2ZXJiYXRpbVRleHRPdXRwdXQoImluZm8iKQogICkKKQoKIyBEZWZpbmUgdGhlIHNlcnZlcgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIAogICMgQ3JlYXRlIHRoZSBwbG90OmxpbmUgZ3JhcGggb2YgdGhlIGNvdW50IG9mIGJpa2UgcmVudGFscyBieSBkYXRlCiAgICBvdXRwdXQkcGxvdCA8LSByZW5kZXJQbG90KHsKICAgIGdncGxvdChkYXRlX2RhdGEsIGFlcyh4ID0gZGF0ZSwgeSA9IHRvdGFsX2NvdW50KSkgKwogICAgICBnZW9tX2xpbmUoKSArCiAgICAgIGxhYnModGl0bGUgPSAiRXhwbG9yZSBCaWtlIFJlbnRhbHMgc2Vhc29uYWxpdHkiLAogICAgICAgICAgIHggPSAiRGF0ZSIsCiAgICAgICAgICAgeSA9ICJDb3VudCIpCiAgfSkKCiAgCiAgIyBDcmVhdGUgdGhlIGhvdmVyIG9yIGNsaWNrIGluZm9ybWF0aW9uCiAgCiAgb3V0cHV0JGluZm8gPC0gcmVuZGVyUHJpbnQoewogICAgaWYgKGlzLm51bGwoaW5wdXQkcGxvdF9ob3ZlcikpIHsKICAgICAgcmV0dXJuKCkKICAgIH0KICAgIAogICAgeCA8LSBhcy5udW1lcmljKGlucHV0JHBsb3RfaG92ZXIkeCkKICAgIHkgPC0gYXMubnVtZXJpYyhpbnB1dCRwbG90X2hvdmVyJHkpCiAgICAKICAgICMgRmluZCB0aGUgY2xvc2VzdCBwb2ludCB0byB0aGUgaG92ZXIgbG9jYXRpb24KICAgIGNsb3Nlc3RfcG9pbnQgPC0gd2hpY2gubWluKGFicyhhcy5udW1lcmljKGRhdGVfZGF0YSRkYXRlKSAtIHgpKQogICAgCiAgICBwYXN0ZSgKICAgICAgI3Nob3cgaW5mb3JtYXRpb24gb2YgY2xpY2sgcG9pbnQgYWJvdXQgaXRzIGRhdGUgYW5kIGNvdW50CiAgICAgICJEYXRlOiIsIGRhdGVfZGF0YSRkYXRlW2Nsb3Nlc3RfcG9pbnRdLAogICAgICAiQ291bnQ6IiwgZGF0ZV9kYXRhJHRvdGFsX2NvdW50W2Nsb3Nlc3RfcG9pbnRdCiAgICApCiAgfSkKICAKfQoKIyBSdW4gdGhlIGFwcApzaGlueUFwcCh1aSwgc2VydmVyKQoKCmBgYAoKIyA4LiBPcmdhbml6ZSB0aGUgUi4gZmlsZXMKCkZvciB0aGlzIG5vdGVib29rLCB3ZSBwdXQgdGhlbSBpbnRvIG9uZSBjaHVuayB0byBydW4gdGhlIHNoaW55IGNvZGUuCgpJZiB3ZSB3YW50IHRvIGtlZXAgeW91ciBjb2RlIG9yZ2FuaXplZCBhbmQgZWFzaWVyIHRvIG1haW50YWluLCB3ZSBjb3VsZCBzZXBhcmF0ZSB0aGUgVUkgYW5kIHNlcnZlciBmdW5jdGlvbnMgaW50byBzZXBhcmF0ZSBmaWxlcy4uCgp3ZSBzZXQgdXAgdGhyZWUgZmlsZXM6IHVpLlIgdG8gZGVmaW5lIHRoZSBhcHAgcHJlc2VudGF0aW9uLCBzZXJ2ZXIuUiB0byBkZWZpbmUgdGhlIGFwcCBsb2dpYywgYW5kIHNoaW55QXBwLlIgdG8gcnVuIHRoZSBmb3JtZXIgdHdvLgoKLSAgIFJlbWVtYmVyIHRvIHNhdmUgdGhlc2UgdGhyZWUgUiBzY3JpcHRzIGluIHRoZSBzYW1lIGRpcmVjdG9yeSBhcyB0aGUgYXBwLlIgZmlsZS4KCi0gICBEZWZpbmUgdGhlIHVpIGFuZCBzZXJ2ZXIgZnVuY3Rpb24gaW4gdWkuUiBhbmQgc2VydmVyLlIgc2VwZXJhdGVseS4KCjEudWkuUgoKYGBge3J9CnVpIDwtIGZsdWlkUGFnZSgKICAjIFVJIGVsZW1lbnRzIGdvIGhlcmUKKQojIHJldHVybiB0aGUgVUkgb2JqZWN0CnVpCmBgYAoKMi5zZXJ2ZXIuUgoKYGBge3J9CnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7CiAgIyBzZXJ2ZXIgbG9naWMgZ29lcyBoZXJlCn0KIyByZXR1cm4gdGhlIHNlcnZlciBvYmplY3QKc2VydmVyCmBgYAoKMy5zaGlueUFwcC5SCgogICAgc291cmNlIHRoZSB1aS5SIGFuZCBzZXJ2ZXIuUiBmaWxlcyBhbmQgdGhlbiBjYWxsIHRoZSBzaGlueUFwcCBmdW5jdGlvbiB3aXRoIHRoZSB1aSBhbmQgc2VydmVyIG9iamVjdHMuCgpgYGB7cn0KIyBzb3VyY2UgdGhlIFVJIGFuZCBzZXJ2ZXIgZmlsZXMKc291cmNlKCJ1aS5SIikKc291cmNlKCJzZXJ2ZXIuUiIpCgojIGNyZWF0ZSB0aGUgU2hpbnkgYXBwCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKYGBgCgpDb21iaW5lIHRoZXNlIHRocmVlIFIgc3JpY3B0cyBhbmQgYWxsIG90aGVyIG1hdGVyaWFscyhlLmcuaW1hZ2UpIGludG8gb25lIHNpbmdsZSBmb2xkZXIsIHdoaWNoIHRoZSBmb2xkZXIgcGF0aCB3aWxsIGJlIHRoZSBwYXRoIHRvIHB1Ymxpc2ggeW91ciBzaGlueSBhcHAuCgojIDkuIFB1Ymxpc2ggdGhlIHNoaW55IGFwcC4KCk5vdywgTGV0J3MgcHVibGlzaCBvdXIgc2hpbnkgYXBwLiBDcmVhdGUgZnJlZSBhY2NvdW50IG9uIHNoaW55YXBwLmlvLiBJbnN0YWxsIHRoZSByc2Nvbm5lY3QgcGFja2FnZSwgYXV0aG9yaXplIGFjY291bnQgYW5kIGRlcGxveSB5b3VyIGFwcCEgPGh0dHBzOi8vd3d3LnNoaW55YXBwcy5pby9hZG1pbi8jL2Rhc2hib2FyZD4KCmBgYHtyfQpsaWJyYXJ5KHJzY29ubmVjdCkKCiNUaGUgcnNjb25uZWN0IHBhY2thZ2UgbXVzdCBiZSBhdXRob3JpemVkIHRvIHlvdXIgYWNjb3VudCB1c2luZyBhIHRva2VuIGFuZCBzZWNyZXQuIFBhc3RlIGl0IGludG8geW91ciBSIGNvbnNvbGUgdG8gYXV0aG9yaXplIHlvdXIgYWNjb3VudC4KI3JzY29ubmVjdDo6c2V0QWNjb3VudEluZm8obmFtZT0neW91ciBuYW1lJywKCQkJICAjdG9rZW49J3lvdXIgdG9rZW4nLAoJCQkgICNzZWNyZXQ9JzxTRUNSRVQ+JykKCiNPbmNlIHRoZSByc2Nvbm5lY3QgcGFja2FnZSBoYXMgYmVlbiBjb25maWd1cmVkLCB5b3UncmUgcmVhZHkgdG8gZGVwbG95IHlvdXIgZmlyc3QgYXBwbGljYXRpb24uIAojcnNjb25uZWN0OjpkZXBsb3lBcHAoJy9Vc2Vycy9zYW1hbnRoYWNoZW4vRGVza3RvcC9zaGlueWFwcCcpCmBgYAoKT25jZSB5b3UgaGF2ZSBwdWJsaXNoZWQgeW91ciBhcHAsIHlvdSBzdGlsbCBjYW4gY29udGludWUgbW9kaWZ5IHlvdXIgYXBwIGFuZCByZXB1Ymxpc2ggaXQuCgotICAgRm9yIHRoaXMgbGFiLCBzdWJtaXQgeW91ciBub3RlYm9vayBhbmQgeW91ciBwdWJsaXNoZWQgbGluayBmb3Igc3RlcCA1Lgo=