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.

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/

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().

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().

#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().

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)

4. Add selection input and process selected data

Now, let’s add selection input for interactive plot in shiny. You could choose the selection function you like from step 2. The goal is to create selection choices for survived and sex variables for the plot.

Here is an example:

Try to run the following shiny app example:

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!

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.

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)

# 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.

LS0tCnRpdGxlOiAnIENyZWF0aW5nIGFuIFIgU2hpbnkgQXBwJwpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKRGF0ZTogMDQvMDUvMjAyMwotLS0KCkluIHRoaXMgbGFiLCB3ZSdsbCBjcmVhdGUgdGhlIFNoaW55IGFwcC4gVGhpcyBsYWIgd2lsbCBndWlkZSB5b3Ugd3JpdGUgYSBzaGlueSBhcHBsaWNhdGlvbiwgY3JlYXRlIGludGVyYWN0aXZlIHBsb3RzLCBwdWJsaXNoIHRoZSBzaGlueSBhcHBsaWNhdGlvbiBvbiBSU3R1ZGlvJ3Mgc2hpbnkgc2VydmVyLCB0aGVuIHlvdSB3aWxsIGJlIGFibGUgdG8gc2hhcmUgdGhlIGFwcGxpY2F0aW9uIGxpbmsuIFRoaXMgbGluayBjb250YWlucyB0aGUgdGhlIHNoaW55IGFwcCBkZW1vIHdlIHdhbnQgeW91IGNyZWF0ZSBkdXJpbmcgdGhpcyBsYWIsIGFuZCB5b3UgY291bGQgcHVibGlzaCBpdCBvbiBzaGlueSBzZXJ2ZXIuIDxodHRwczovL3h1ZWhhbmNoZW4uc2hpbnlhcHBzLmlvL3NoaW55YXBwLz4KClNoaW55IGlzIGFuIFIgcGFja2FnZSB0aGF0IGFsbG93cyB5b3UgdG8gZWFzaWx5IGNyZWF0ZSByaWNoLCBpbnRlcmFjdGl2ZSB3ZWIgYXBwcy4gU2hpbnkgYWxsb3dzIHlvdSB0byB0YWtlIHlvdXIgd29yayBpbiBSIGFuZCBleHBvc2UgaXQgdmlhIGEgd2ViIGJyb3dzZXIgc28gdGhhdCBhbnlvbmUgY2FuIHVzZSBpdC4gU2hpbnkgbWFrZXMgeW91IGxvb2sgYXdlc29tZSBieSBtYWtpbmcgaXQgZWFzeSB0byBwcm9kdWNlIHBvbGlzaGVkIHdlYiBhcHBzIHdpdGggYSBtaW5pbXVtIGFtb3VudCBvZiBwYWluLgoKIyAxLiBCYXNpYyAiU2hpbnkiIHN0cnVjdHVyZQoKYGBge3J9CiNpbnN0YWxsIHNldmVyYWwgcGFja2FnZXMKbGlicmFyeShzaGlueSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpgYGAKClRoZXJlIGFyZSBzZXZlcmFsIHdheXMgdG8gY3JlYXRlIGEgU2hpbnkgYXBwLgoKLSAgIFRoZSBzaW1wbGVzdCBpcyB0byBjcmVhdGUgYSBuZXcgZGlyZWN0b3J5IGZvciB5b3VyIGFwcCwgYW5kIHB1dCBhIHNpbmdsZSBmaWxlIGNhbGxlZCBzaGlueUFwcC5SIGluIGl0LgoKLSAgIE9yIHlvdSBjb3VsZCBzcGxpdCB5b3VyIGNvZGUgaW50byB0aHJlZSBmaWxlcyBmb3IgYmV0dGVyIG9yZ2FuaXphdGlvbjogdWkuUiwgc2VydmVyLlIsIHNoaW55QXBwLlIuCgpIZXJlIHdlIHB1dCBpdCBpbnRvIHNpbmdsZSBjaHVuayBvZiB0aGUgbm90ZWJvb2sgbGlrZSBhIHNpbmdsZSBzaGlueUFwcC5SIGZpbGUsIHNvIHlvdSBjb3VsZCBkaXJlY3RseSBydW4geW91ciBjb2RlIGluIHRoaXMgbm90ZWJvb2suCgpTaGlueSBhcHBsaWNhdGlvbnMgYXJlIGRpdmlkZWQgaW50byB0d28gcGFydHM6IHRoZSBVc2VyIEludGVyZmFjZSAoVUkpIGFuZCB0aGUgU2VydmVyLgoKLSAgIFRoZSBVSSBpcyByZXNwb25zaWJsZSBmb3IgdGhlIGFwcCBwcmVzZW50YXRpb24sIHdoaWxlIHRoZSBzZXJ2ZXIgaXMgcmVzcG9uc2libGUgZm9yIHRoZSBhcHAgbG9naWMuCgogICAgLSAgIFRoZSBVSSBpcyByZXNwb25zaWJsZSBmb3IgdGhlIGFwcCBwcmVzZW50YXRpb24uIEl0J3MgdHlwaWNhbGx5IGRlZmluZWQgdXNpbmcgdGhlICoqYGZsdWlkUGFnZSgpYCoqIG9yICoqYGZpeGVkUGFnZSgpYCoqIGZ1bmN0aW9ucyBmcm9tIHRoZSAqKmBzaGlueWAqKiBwYWNrYWdlLCBhbG9uZyB3aXRoIHZhcmlvdXMgVUkgZWxlbWVudHMgc3VjaCBhcyAqKmBwbG90T3V0cHV0KClgKiosICoqYHRleHRJbnB1dCgpYCoqLCAqKmBzZWxlY3RJbnB1dCgpYCoqLCBhbmQgc28gb24uIFRoZXNlIGVsZW1lbnRzIGFyZSBhcnJhbmdlZCB1c2luZyBsYXlvdXQgZnVuY3Rpb25zIHN1Y2ggYXMgKipgZmx1aWRSb3coKWAqKiwgKipgY29sdW1uKClgKiosICoqYHNpZGViYXJQYW5lbCgpYCoqLCBhbmQgb3RoZXJzLgoKICAgIC0gICBUaGUgc2VydmVyLCBvbiB0aGUgb3RoZXIgaGFuZCwgY29udGFpbnMgdGhlIGFwcCdzIGxvZ2ljIGFuZCBkYXRhIHByb2Nlc3NpbmcuIEl0IGRlZmluZXMgcmVhY3RpdmUgZXhwcmVzc2lvbnMgdXNpbmcgdGhlICoqYHJlYWN0aXZlKClgKiogb3IgKipgb2JzZXJ2ZSgpYCoqIGZ1bmN0aW9ucyB0aGF0IHVwZGF0ZSBiYXNlZCBvbiB1c2VyIGlucHV0IG9yIG90aGVyIHJlYWN0aXZlIHZhbHVlcy4gVGhlIHNlcnZlciBhbHNvIGNvbnRhaW5zIHRoZSBjb2RlIHRoYXQgZ2VuZXJhdGVzIHRoZSBvdXRwdXQgZGlzcGxheWVkIGluIHRoZSBVSSwgdXNpbmcgZnVuY3Rpb25zIHN1Y2ggYXMgKipgcmVuZGVyUGxvdCgpYCoqLCAqKmByZW5kZXJUYWJsZSgpYCoqLCBvciAqKmByZW5kZXJVSSgpYCoqLgoKVGhlIFVJIGFuZCBzZXJ2ZXIgd29yayB0b2dldGhlciB0byBjcmVhdGUgYW4gaW50ZXJhY3RpdmUgU2hpbnkgYXBwbGljYXRpb24gdGhhdCB1cGRhdGVzIGluIHJlYWwtdGltZSBiYXNlZCBvbiB1c2VyIGlucHV0IGFuZCByZWFjdGl2ZSB2YWx1ZXMuIENoZWNrIG1vcmUgZGV0YWlscyBvbiA8aHR0cHM6Ly9zaGlueS5yc3R1ZGlvLmNvbS90dXRvcmlhbC8+CgotICAgUnVuIHRoZSBmb2xsb3dpbmcgYmFzaWMgc2hpbnkgY29kZSwgb3BlbiB0aGUgYnJvd2VyLCB0aGVuIHlvdSBzaG91bGQgc2VlIGFuIGVtcHR5IHdlYiBhcHBsaWNhdGlvbi4KCi0gICBOb3RpY2UgdGhhdCBvbmNlIHlvdSBjbG9zZSB0aGUgd2Vic2l0ZSwgeW91IG1pZ2h0IHNlZSB0aGUgZXJyb3IgcmV0dXJucyBsaWtlOiBMaXN0ZW5pbmcgb24gPGh0dHA6Ly8+Li4uLi4uIFlvdSBjb3VsZCBpZ25vcmUgdGhpcyBlcnJvci4KCmBgYHtyfQp1aSA8LSBmbHVpZFBhZ2UoCiAgI3VpIGRlc2lnbiBnb2VzIGhlcmUKKQpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogICMgc2VydmVyIGxvZ2ljIGdvZXMgaGVyZQp9CiNQcmV2aWV3aW5nIHRoZSBhcHBsaWNhdGlvbi4gCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKYGBgCgojIDIuIEJhc2ljIFVJIGRlc2lnbjoKCk5vdywgbGV0J3MgZGVmaW5lIHRoZSB1aSBmdW5jdGlvbi4gVGhlcmUgYXJlIG1hbnkgYXBwcm9hY2hlcyB0byBhbGxvdyB0aGUgdXNlciB0byBjaG9vc2UgZnJvbSBhIHByZXNwZWNpZmllZCBzZXQgb2Ygb3B0aW9uczogZS5nLiBzZWxlY3RJbnB1dCgpIGFuZCByYWRpb0J1dHRvbnMoKS4KCi0gICBSdW4gdGhlIGZvbGxvd2luZyBleGFtcGxlIGFuZCBzZWUgdGhlIHVpIHByZXNlbnRhdGlvbi4KLSAgIE5vdGljZSB0aGF0IGZvciBVSSBmdW5jdGlvbiwgaXQgb25seSBzaG93cyB0aGUgYXBwIHByZXNlbnRhdGlvbiwgdGhlcmUgaXMgbm8gZGF0YSBwcm9jZXNzaW5nIGRlZmluZWQgaGVyZS4gVGhlIFVJIHByb3ZpZGVzIHRoZSB1c2VyIHdpdGggYSB3YXkgdG8gaW50ZXJhY3Qgd2l0aCB0aGUgYXBwLCB3aGlsZSB0aGUgU2VydmVyIHByb2Nlc3NlcyB0aGUgdXNlcidzIGlucHV0IGFuZCBnZW5lcmF0ZXMgb3V0cHV0IHRoYXQgaXMgZGlzcGxheWVkIGluIHRoZSBVSS4gV2Ugd2lsbCB0YWxrIGFib3V0IGl0IGxhdGVyIG9uLgoKYGBge3J9CmFuaW1hbHMgPC0gYygiZG9nIiwgImNhdCIsICJtb3VzZSIsICJiaXJkIiwgIm90aGVyIiwgIkkgaGF0ZSBhbmltYWxzIikKCnVpIDwtIGZsdWlkUGFnZSgKICBzZWxlY3RJbnB1dCgiYW5pbWFsIiwgIldoYXQncyB5b3VyIGZhdm91cml0ZSBzdGF0ZT8iLCBzdGF0ZS5uYW1lKSwKICByYWRpb0J1dHRvbnMoImFuaW1hbCIsICJXaGF0J3MgeW91ciBmYXZvdXJpdGUgYW5pbWFsPyIsIGFuaW1hbHMpCikKdWkKYGBgCgpUaGVyZSdzIG5vIHdheSB0byBzZWxlY3QgbXVsdGlwbGUgdmFsdWVzIHdpdGggcmFkaW8gYnV0dG9ucywgYnV0IHRoZXJlJ3MgYW4gYWx0ZXJuYXRpdmUgdGhhdCdzIGNvbmNlcHR1YWxseSBzaW1pbGFyOiBjaGVja2JveEdyb3VwSW5wdXQoKSBvciBzZWxlY3RpemVJbnB1dCgpLgoKLSAgIFRyeSB0byB3cml0ZSB1aSBmdW5jdGlvbiBmb3IgdGhlIHF1ZXN0aW9uOiAiV2hhdCBhbmltYWxzIGRvIHlvdSBsaWtlPyIgdXNpbmcgY2hlY2tib3hHcm91cElucHV0KCkgb3Igc2VsZWN0aXplSW5wdXQoKS4KCmBgYHtyfQojY29kZSBzdGFydCBoZXJlOgp1aSA8LSBmbHVpZFBhZ2UoCiAgY2hlY2tib3hHcm91cElucHV0KCJhbmltYWwiLCAiV2hhdCBhbmltYWxzIGRvIHlvdSBsaWtlPyIsIGFuaW1hbHMpCikKdWkKI2NvZGUgZW5kIGhlcmUKYGBgCgojIDMuIENyZWF0ZSB0aGUgdWkgYW5kIHNlcnZlciBmdW5jdGlvbiBmb3IgcGxvdC4KCk5vdyBsZXQncyBjcmVhdGUgc2hpbnkgYXBwIGZvciB0aGUgcGxvdCEKCllvdSBjYW4gZGlzcGxheSBhbnkgdHlwZSBvZiBSIGdyYXBoaWMgKGJhc2UsIGdncGxvdDIsIG9yIG90aGVyd2lzZSkgd2l0aCBwbG90T3V0cHV0KCkgYW5kIHJlbmRlclBsb3QoKS4KCi0gICBFeHBsb3JlIHRoZSBpbnB1dCBhbmQgb3V0cHV0IGFyZ3VtZW50IGluIHNlcnZlciBmdW50aW9uLiBUaGUgaW5wdXQgYXJndW1lbnQgcmVwcmVzZW50cyB0aGUgdXNlcidzIGlucHV0cyAoZS5nLiBmb3JtIGlucHV0cywgYnV0dG9ucyBjbGlja2VkLCBldGMuKSwgYW5kIHRoZSBvdXRwdXQgYXJndW1lbnQgcmVwcmVzZW50cyB0aGUgb3V0cHV0cyAoZS5nLiBwbG90cywgdGFibGVzLCBldGMuKSB0aGF0IHdpbGwgYmUgZGlzcGxheWVkIHRvIHRoZSB1c2VyLgoKLSAgIE91dHB1dHMgaW4gdGhlIFVJIGNyZWF0ZSBwbGFjZWhvbGRlcnMgdGhhdCBhcmUgbGF0ZXIgZmlsbGVkIGJ5IHRoZSBzZXJ2ZXIgZnVuY3Rpb24uIExpa2UgaW5wdXRzLCBvdXRwdXRzIHRha2UgYSB1bmlxdWUgSUQgYXMgdGhlaXIgZmlyc3QgYXJndW1lbnQ6IGlmIHlvdXIgVUkgc3BlY2lmaWNhdGlvbiBjcmVhdGVzIGFuIG91dHB1dCB3aXRoIElEICoqYCJwbG90ImAqKiwgbGlrZSAqKmBwbG90T3V0cHV0KCJwbG90IilgKiosIHlvdSdsbCBhY2Nlc3MgaXQgaW4gdGhlIHNlcnZlciBmdW5jdGlvbiB3aXRoICoqYG91dHB1dCRwbG90YCoqLgoKLSAgIEluIFIsICoqYHt9YCoqIGlzIHVzZWQgdG8gY3JlYXRlIGEgYmxvY2sgb2YgY29kZSB0aGF0IGNhbiBjb250YWluIG9uZSBvciBtb3JlIGV4cHJlc3Npb25zIG9yIHN0YXRlbWVudHMuIEluIHRoZSBjb250ZXh0IG9mIGEgZnVuY3Rpb24sIHRoZSAqKmB7fWAqKiBibG9jayBkZWZpbmVzIHRoZSBmdW5jdGlvbiBib2R5LCB3aGljaCBjb250YWlucyB0aGUgY29kZSB0aGF0IGlzIGV4ZWN1dGVkIHdoZW4gdGhlIGZ1bmN0aW9uIGlzIGNhbGxlZC4KCi0gICBUcnkgdG8gcnVuIHRoZSBmb2xsb3dpbmcgZXhhbXBsZToKCmBgYHtyfQp1aSA8LSBmbHVpZFBhZ2UoCiAgcGxvdE91dHB1dCgicGxvdCIpLAopCgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIG91dHB1dCRwbG90IDwtIHJlbmRlclBsb3QoewogICAgcGxvdChtdGNhcnMkd3QsIG10Y2FycyRtcGcpCiAgfSwgcmVzID0gOTYpCn0Kc2hpbnlBcHAodWkgPSB1aSwgc2VydmVyID0gc2VydmVyKQpgYGAKCkFmdGVyIHJ1bm5pbmcgdGhlIGV4YW1wbGUsIExldCdzIHN0YXJ0IGJ5IGJ1aWxkaW5nIGEgc2ltcGxlIHNoaW55IHBsb3QhCgpXZSB0cnkgdG8gZXhwbG9yZSB0aGUgdG9waWMgIlRpdGFuaWM6IFdoYXQgSGVscGVkIFlvdSBTdXJ2aXZlPyIuIFRoZSBnb2FsIGlzIHRvIGFzayBzZXZlcmFsIHF1ZXN0aW9ucyBhbmQgdXNpbmcgcGxvdCB0byBleHBsb3JlIGl0LgoKLSAgIFF1ZXN0aW9uIC0gV2hhdCB3YXMgdGhlIHN1cnZpdmFsIHJhdGUgYnkgZ2VuZGVyPwoKLSAgIFdlIGNhbiBjcmVhdGUgYSBncm91cGVkIGJhcmNoYXJ0LgoKICAgIEhlcmUgaXMgYW4gZXhhbXBsZSBwbG90OgoKIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9zYW1hbnRoYTk2L2NzZTE2MC9ibG9iL21haW4vZTEucG5nP3Jhdz10cnVlKQoKRmlyc3Qgd2UgbG9hZCBkYXRhIGFuZCBkbyBzaW1wbGUgY2xlYW4uCgpgYGB7cn0KIyBsb2FkIHRpdGFuaWMgZGF0YXNldApsaWJyYXJ5KHRpdGFuaWMpCnRpdGFuaWMgPC0gdGl0YW5pY190cmFpbgp0aXRhbmljIDwtIG5hLm9taXQodGl0YW5pYykKdGl0YW5pYyRQY2xhc3MgPC0gYXMuZmFjdG9yKHRpdGFuaWMkUGNsYXNzKQp0aXRhbmljJFN1cnZpdmVkIDwtIGFzLmZhY3Rvcih0aXRhbmljJFN1cnZpdmVkKQp0aXRhbmljJFNleCA8LSBhcy5mYWN0b3IodGl0YW5pYyRTZXgpCgpgYGAKCi0gICBZb3UgY291bGQgdHJ5IHRvIGNyZWF0ZSB0aGUgYmFyIGNoYXJ0IGZpcnN0LCB0aGVuIHB1dCBpdCBpbnRvIHVpIGFuZCBzZXJ2ZXIgZnVuY3Rpb24uCgogICAgLSAgIFVzaW5nICoqYGdlb21fYmFyKClgKiogaW4gKipgcmVuZGVyUGxvdCgpIGJsb2NrYCoqLiBZb3UgY2FuIHNwZWNpZnkgKipgcG9zaXRpb24gPSAiZG9kZ2UiYCoqIHRvIGdlbmVyYXRlIGEgZ3JvdXBlZCBiYXIgY2hhcnQuCgpgYGB7cn0KCnVpIDwtIGZsdWlkUGFnZSgKICAgICNjb2RlIHN0YXJ0IGhlcmU6CiAgICBwbG90T3V0cHV0KCJwbG90IiksCiAgICAjY29kZSBlbmQgaGVyZQopCgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogICNjb2RlIHN0YXJ0IGhlcmU6CiAgb3V0cHV0JHBsb3QgPC0gcmVuZGVyUGxvdCh7CiAgZ2dwbG90KHRpdGFuaWMsIGFlcyh4ID0gU2V4LCBmaWxsID0gU3Vydml2ZWQpKSArIAogIHRoZW1lX2J3KCkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnMoeSA9ICJQYXNzZW5nZXIgQ291bnQiLAogICAgICAgdGl0bGUgPSAiUGFzc2VuZ2VyIENvdW50IGJ5IFNleCIpCiAgfSwgcmVzID0gOTYpCiAgCiAgI2NvZGUgZW5kIGhlcmUKfQpzaGlueUFwcCh1aSA9IHVpLCBzZXJ2ZXIgPSBzZXJ2ZXIpCmBgYAoKIyA0LiBBZGQgc2VsZWN0aW9uIGlucHV0IGFuZCBwcm9jZXNzIHNlbGVjdGVkIGRhdGEKCk5vdywgbGV0J3MgYWRkIHNlbGVjdGlvbiBpbnB1dCBmb3IgaW50ZXJhY3RpdmUgcGxvdCBpbiBzaGlueS4gWW91IGNvdWxkIGNob29zZSB0aGUgc2VsZWN0aW9uIGZ1bmN0aW9uIHlvdSBsaWtlIGZyb20gc3RlcCAyLiBUaGUgZ29hbCBpcyB0byBjcmVhdGUgc2VsZWN0aW9uIGNob2ljZXMgZm9yIHN1cnZpdmVkIGFuZCBzZXggdmFyaWFibGVzIGZvciB0aGUgcGxvdC4KCi0gICAqKmBDaGVja2JveEdyb3VwSW5wdXQoKWAqKjpGb3Igc3Vydml2YWwgc2VsZWN0aW9uLCB0aGUgY2hvaWNlcyBmb3IgdGhlIGlucHV0IGFyZSAic3Vydml2ZWQiIGFuZCAiZGllZCIsIHdoaWNoIGNvcnJlc3BvbmQgdG8gdGhlIG51bWVyaWMgdmFsdWVzIG9mIDEgYW5kIDAsIHJlc3BlY3RpdmVseS4gVGhlc2UgY2hvaWNlcyBhcmUgc3BlY2lmaWVkIHVzaW5nIHRoZSAqKmBjaG9pY2VzYCoqIGFyZ3VtZW50LlRoZSAqKmBzZWxlY3RlZGAqKiBhcmd1bWVudCBpcyB1c2VkIHRvIHNldCB0aGUgZGVmYXVsdCBzZWxlY3Rpb25zIGZvciB0aGUgY2hlY2tib3hlcy4gV2hlbiB0aGUgdXNlciBpbnRlcmFjdHMgd2l0aCB0aGUgaW5wdXQgZWxlbWVudCwgdGhlIHNlbGVjdGVkIGNob2ljZXMgYXJlIHN0b3JlZCBpbiB0aGUgKipgaW5wdXQkc3Vydml2YWxgKiogdmFyaWFibGUgaW4gdGhlIFNoaW55IGFwcCBzZXJ2ZXIuCgotICAgVGhlICoqYHN1YnNldCgpYCoqIGZ1bmN0aW9uIHRha2VzIHRoZSBkYXRhIGFzIGl0cyBmaXJzdCBhcmd1bWVudCwgZm9sbG93ZWQgYnkgdGhlIGNvbmRpdGlvbnMgdG8gZmlsdGVyIHRoZSBkYXRhLiBVc2VzIHRoZSAqKmBzdWJzZXQoKWAqKiBmdW5jdGlvbiB0byBmaWx0ZXIgdGhlICoqYHRpdGFuaWNgKiogZGF0YXNldCBiYXNlZCBvbiB0d28gY29uZGl0aW9uczogKipgc2V4ID09IGlucHV0JHNleGAqKiBhbmQgKipgc3Vydml2ZWQgPT0gaW5wdXQkc3Vydml2YWxgKiouIEl0IGNoZWNrcyBpZiB0aGUgZ2VuZGVyIG9mIGVhY2ggcGFzc2VuZ2VyIGluIHRoZSB0aXRhbmljIGRhdGFzZXQgaXMgY29udGFpbmVkIGluIHRoZSAqKmBpbnB1dCRzZXhgKiogdmVjdG9yIGFuZCBpZiB0aGUgc3Vydml2YWwgc3RhdHVzIG9mIGVhY2ggcGFzc2VuZ2VyIGlzIGNvbnRhaW5lZCBpbiB0aGUgKipgaW5wdXQkc3Vydml2YWxgKiogdmVjdG9yLiB3ZSBjb3VsZCB3cml0ZSB0aGUgY29uZGl0aW9uKipgKFNleCA9PSBpbnB1dCRzZXhbMV18IFNleCA9PSBpbnB1dCRzZXhbMl0pLmAqKiBJdCBpcyBjaGVja2luZyBpZiB0aGUgdmFsdWUgaW4gdGhlICoqYFNleGAqKiBjb2x1bW4gb2YgdGhlICoqYHRpdGFuaWNgKiogZGF0YSBmcmFtZSBpcyBlcXVhbCB0byB0aGUgZmlyc3Qgb3Igc2Vjb25kIGVsZW1lbnQgaW4gdGhlICoqYGlucHV0JHNleGAqKiB2ZWN0b3IuIEJ5IHVzaW5nICoqYFsxXWAqKiBhZnRlciAqKmBpbnB1dCRzZXhgKiosIHdlIGFyZSBzcGVjaWZ5aW5nIHRoYXQgd2Ugb25seSB3YW50IHRvIGNvbXBhcmUgd2l0aCB0aGUgZmlyc3QgZWxlbWVudCBpbiB0aGUgdmVjdG9yLgoKSGVyZSBpcyBhbiBleGFtcGxlOiAhW10oaHR0cHM6Ly9naXRodWIuY29tL3NhbWFudGhhOTYvY3NlMTYwL2Jsb2IvbWFpbi9lMi5wbmc/cmF3PXRydWUpCgpUcnkgdG8gcnVuIHRoZSBmb2xsb3dpbmcgc2hpbnkgYXBwIGV4YW1wbGU6CgpgYGB7cn0KCnVpIDwtIGZsdWlkUGFnZSgKICAgICNBZGQgdHdvIGNoZWNrYm94R3JvdXBJbnB1dCgpIGVsZW1lbnRzLCBvbmUgZm9yIHRoZSBzdXJ2aXZhbCBzdGF0dXMgYW5kIG9uZSBmb3IgdGhlIGdlbmRlciBvZiB0aGUgcGFzc2VuZ2Vycy4gU2V0IHRoZWlyIGluaXRpYWwgc2VsZWN0aW9ucyB1c2luZyB0aGUgc2VsZWN0ZWQgYXJndW1lbnQuCiAgICBjaGVja2JveEdyb3VwSW5wdXQoInN1cnZpdmFsIiwgIkRpZCB0aGUgcGFzc2VuZ2VyIHN1cnZpdmU/IiwgIGNob2ljZXMgPSBjKCJzdXJ2aXZlZCIgPSAxLCAiZGllZCIgPSAwKSwgc2VsZWN0ZWQgPSBjKDEsMCkpLAogICAgY2hlY2tib3hHcm91cElucHV0KCJzZXgiLCAiV2hhdCBpcyB0aGUgZ2VuZGVyIG9mIHRoZSBwYXNzZW5nZXI/IiwgY2hvaWNlcyA9IGMoIm1hbGUiLCAiZmVtYWxlIiksIHNlbGVjdGVkID0gYygibWFsZSIsICJmZW1hbGUiKSksCiAgICAjQWRkIGEgcGxvdE91dHB1dCgpIGVsZW1lbnQgdG8gZGlzcGxheSB0aGUgcGxvdC4KICAgIHBsb3RPdXRwdXQoInBsb3QiKSwKCikKCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7CiBvdXRwdXQkcGxvdCA8LSByZW5kZXJQbG90KHsKICAgICNJbiB0aGUgcmVuZGVyUGxvdCgpIGZ1bmN0aW9uLCBmaWx0ZXIgdGhlIGRhdGEgYmFzZWQgb24gdGhlIHNlbGVjdGVkIGdlbmRlciBhbmQgc3Vydml2YWwgc3RhdHVzIHVzaW5nIHN1YnNldCgpLgogICAgZmlsdGVyZWRfZGF0YSA8LSBzdWJzZXQodGl0YW5pYywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU2V4ID09IGlucHV0JHNleFsxXXwgU2V4ID09aW5wdXQkc2V4WzJdKSAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU3Vydml2ZWQgPT0gaW5wdXQkc3Vydml2YWxbMV18U3Vydml2ZWQgPT0gaW5wdXQkc3Vydml2YWxbMl0pKQogICAgI0NyZWF0ZSBiYXJjaGFydCB1c2luZyB0aGUgZmlsdGVyZWQgZGF0YS4KICAgICNjb2RlIHN0YXJ0IGhlcmU6CiAgICBnZ3Bsb3QoZmlsdGVyZWRfZGF0YSwgYWVzKHggPSBTZXgsIGZpbGwgPSBTdXJ2aXZlZCkpICsgCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IC4uY291bnQuLiksIHN0YXQgPSAiY291bnQiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwgdmp1c3QgPSAtMC41LCBzaXplID0gMykgKwogICAgICAjQWRkIGxhYmVscyB0byB0aGUgcGxvdCB1c2luZyBsYWJzKCkgZm9yIHRoZSB5LWF4aXMgYW5kIHRpdGxlLgogICAgICBsYWJzKHkgPSAiUGFzc2VuZ2VyIENvdW50IiwKICAgICAgICAgICB0aXRsZSA9ICJQYXNzZW5nZXIgQ291bnQgYnkgU2V4IikKICAgICNjb2RlIGVuZCBoZXJlCiAgICAKICAgIH0sIHJlcyA9IDk2KQp9CgojRmluYWxseSwgcnVuIHRoZSBTaGlueSBhcHAgdXNpbmcgc2hpbnlBcHAoKS4Kc2hpbnlBcHAodWkgPSB1aSwgc2VydmVyID0gc2VydmVyKQpgYGAKCiMgNS4gQnVpbGQgb3VyIHNoaW55IGFwcC4KCiMgUXVlc3Rpb24gLSBXaGF0IGlzIHRoZSBudW1iZXIgb2Ygc3Vydml2YWwgcGFzc2VuZ2VycyBieSBhZ2Ugd2hlbiBzZWdtZW50ZWQgYnkgZ2VuZGVyIGFuZCBjbGFzcyBvZiB0aWNrZXQ/CgotICAgQSByZWxhdGVkIHZpc3VhbGl6YXRpb24gdG8gdGhlIGhpc3RvZ3JhbSBpcyBhIGRlbnNpdHkgcGxvdC4gVGhpbmsgb2YgYSBkZW5zaXR5IHBsb3QgYXMgYSBzbW9vdGhlZCB2ZXJzaW9uIG9mIHRoZSBoaXN0b2dyYW0uCgotICAgPGRpdj4KCiAgICAxLiAgVUk6IENyZWF0ZSBzZWxlY3Rpb24gaW5wdXQgZm9yIHBjbGFzcywgc2V4LCBzdXJ2aXZlZCwgYW5kIHNsaWRlcklucHV0KCkgZm9yIGFnZS4KCiAgICA8L2Rpdj4KCi0gICA8ZGl2PgoKICAgIDIuICBTZXJ2ZXI6IFdlIGNhbiB1c2UgZmFjZXRfd3JhcChTZXggXH4gUGNsYXNzKSArIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgdG8gYWxsb3cgZm9yIHZpc3VhbCBkcmlsbC1kb3duIHZpYSBkZW5zaXR5IHBsb3RzLiBUaGVuIHdlIG5lZWQgdG8gdGhpbmsgaG93IHRvIGdldCBmaWx0ZXJlZCBpbnB1dCBkYXRhIGJhc2VkIG9uIGhvdyB1c2VyIHNlbGVjdGlvbi4KCiAgICAgICAgLSAgIEZvciBiZXR0ZXIgdmlzdWFsaXphdGlvbiwgd2UgbmVlZCB0byBjcmVhdGUgYSBuZXcgZGF0YSBmcmFtZSAqKmB0aXRhbmljX2NvbXBsZXRlYCoqIHdpdGggYWxsIHBvc3NpYmxlIGNvbWJpbmF0aW9ucyBvZiBQY2xhc3MgYW5kIFNleC4gVGhlIHJlYXNvbiBmb3IgY3JlYXRpbmcgYSBuZXcgZGF0YSBmcmFtZSB3aXRoIGFsbCBwb3NzaWJsZSBjb21iaW5hdGlvbnMgb2YgUGNsYXNzIGFuZCBTZXggaXMgdG8gZW5zdXJlIHRoYXQgdGhlIHBsb3QgYWx3YXlzIGRpc3BsYXlzIGFsbCBjb21iaW5hdGlvbnMgb2YgUGNsYXNzIGFuZCBTZXgsIGV2ZW4gaWYgdGhlcmUgYXJlIG5vIG9ic2VydmF0aW9ucyBpbiB0aGUgb3JpZ2luYWwgZGF0YXNldCBmb3IgYSBwYXJ0aWN1bGFyIGNvbWJpbmF0aW9uLiBUaGlzIGlzIGltcG9ydGFudCBmb3IgdGhlIHZpc3VhbGl6YXRpb24gdG8gYWNjdXJhdGVseSByZWZsZWN0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGRhdGEgYW5kIGF2b2lkIG1pc2xlYWRpbmcgaW50ZXJwcmV0YXRpb25zLgoKICAgICAgICAtICAgVXNlcyB0aGUgKipgc3Vic2V0KClgKiogZnVuY3Rpb24gdG8gZmlsdGVyIHRoZSAqKmB0aXRhbmljX2NvbXBsZXRlYCoqIGRhdGFzZXQuIEluIHRoaXMgY2FzZSwgKipgcGNsYXNzYCoqLCAqKmBzZXhgKiosICoqYGFnZWAqKiwgYW5kICoqYHN1cnZpdmVkYCoqIHZhcmlhYmxlcyBhcmUgZmlsdGVyZWQgdXNpbmcgdGhlICoqYD09YCoqIG9wZXJhdG9yIHRvIG1hdGNoIHRoZSB1c2VyLXNlbGVjdGVkIHZhbHVlcy4gVGhlICoqYGFnZWAqKiB2YXJpYWJsZSBpcyBmaWx0ZXJlZCBiYXNlZCBvbiBhIHJhbmdlIG9mIHZhbHVlcyB1c2luZyB0aGUgKipgPj1gKiogYW5kICoqYDw9YCoqIG9wZXJhdG9ycy4gKipgaW5wdXQkYWdlWzFdYCoqIGFuZCAqKmBpbnB1dCRhZ2VbMl1gKiogYXJlIHVzZWQgdG8gZXh0cmFjdCB0aGUgbWluaW11bSBhbmQgbWF4aW11bSBhZ2UgdmFsdWVzIHNlbGVjdGVkIGJ5IHRoZSB1c2VyIHVzaW5nIHRoZSAqKmBzbGlkZXJJbnB1dCgpYCoqIGZ1bmN0aW9uLgoKICAgICAgICAtICAgKipgV2UgcHV0IHRoZSBzZWJzZXQoKSBpbnNpZGUgdGhlIFJlYWN0aXZlIGZ1bmN0aW9uIGluIHRoaXMgY2FzZS4gUmVhY3RpdmUoKWAqKiBmdW5jdGlvbiBjcmVhdGVzIGEgcmVhY3RpdmUgZXhwcmVzc2lvbiB0aGF0IGZpbHRlcnMgdGhlIGRhdGEgaW4gKipgdGl0YW5pY19jb21wbGV0ZWAqKiBiYXNlZCBvbiB0aGUgdXNlciBpbnB1dCB2YWx1ZXMgZm9yICoqYHBjbGFzc2AqKiwgKipgc2V4YCoqLCAqKmBhZ2VgKiogYW5kICoqYHN1cnZpdmVkYCoqLiBUaGUgcmVhY3RpdmUgZXhwcmVzc2lvbiByZXR1cm5zIHRoZSBmaWx0ZXJlZCBkYXRhIHRoYXQgY2FuIGJlIHVzZWQgdG8gcmVuZGVyIHRoZSBwbG90LiBXaGVuZXZlciB0aGVyZSBpcyBhIGNoYW5nZSBpbiBhbnkgb2YgdGhlIGlucHV0IHZhbHVlcywgdGhlIHJlYWN0aXZlIGV4cHJlc3Npb24gd2lsbCByZS1leGVjdXRlIGFuZCB0aGUgcGxvdCB3aWxsIGJlIHVwZGF0ZWQgYWNjb3JkaW5nbHkuCgogICAgPC9kaXY+CgotICAgSGVyZSBpcyBhbiBleGFtcGxlOiA8aHR0cHM6Ly94dWVoYW5jaGVuLnNoaW55YXBwcy5pby9zaGlueWFwcC8+IVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9zYW1hbnRoYTk2L2NzZTE2MC9ibG9iL21haW4vZTMucG5nP3Jhdz10cnVlKQoKYGBge3J9CnVpIDwtIGZsdWlkUGFnZSgKICAjdXNlIGZsdWlkUm93KCkgdG8gY29udHJvbCB0aGUgcGxvdCBsYXlvdXQKICBmbHVpZFJvdygKICAgIGNvbHVtbih3aWR0aCA9IDQsCiAgICAgICAgICAgI3NlbGVjdGlvbiBjb250cm9sIHBhcnQKICAgICAgICAgICAgI2NvZGUgc3RhcnQgaGVyZToKICAgICAgICAgICAgICAgI0FkZCB0aHJlZSBzZWxlY3Rpb24gZWxlbWVudHMsIG9uZSBmb3IgdGhlIHN1cnZpdmFsIHN0YXR1cywgb25lIGZvciBwY2xhc3MgYW5kIG9uZSBmb3IgdGhlIGdlbmRlciBvZiB0aGUgcGFzc2VuZ2Vycy4gU2V0IHRoZWlyIGluaXRpYWwgc2VsZWN0aW9ucyB1c2luZyB0aGUgc2VsZWN0ZWQgYXJndW1lbnQuCiAgICAgICAgICAgICAgICNBZGQgb25lIHNsaWRlciBmb3Igc2VsZWN0aW5nIGFnZSByYW5nZS4KICAgICAgICAgICBjaGVja2JveEdyb3VwSW5wdXQoInBjbGFzcyIsICJTZWxlY3QgUGNsYXNzIiwgY2hvaWNlcyA9IGMoIkZpcnN0IGNsYXNzIj0xLCAiU2Vjb25kIGNsYXNzIj0yLCAiVGhpcmQgY2xhc3MiID0gMyksc2VsZWN0ZWQgPSBjKDEsMiwzKSksCiAgICAgICAgICAgY2hlY2tib3hHcm91cElucHV0KCJzZXgiLCAiU2VsZWN0IFNleCIsIGNob2ljZXMgPSBjKCJtYWxlIiwiZmVtYWxlIiksc2VsZWN0ZWQgPSBjKCJtYWxlIiwgImZlbWFsZSIpKSwKICAgICAgICAgICBzbGlkZXJJbnB1dCgiYWdlIiwgIlNlbGVjdCBBZ2UgUmFuZ2UiLCBtaW4gPSAwLCBtYXggPSA4MCwgdmFsdWUgPSBjKDAsIDgwKSksCiAgICAgICAgICAgY2hlY2tib3hHcm91cElucHV0KCJzdXJ2aXZhbCIsICJEaWQgdGhlIHBhc3NlbmdlciBzdXJ2aXZlPyIsICBjaG9pY2VzID0gYygic3Vydml2ZWQiID0gMSwgImRpZWQiID0gMCksIHNlbGVjdGVkID0gYygxLDApKQogICAgICAgICAgIAogICAgICAgICAgIAogICAgICAgICAgICAjY29kZSBlbmQgaGVyZQogICAgKSwKICAgIGNvbHVtbih3aWR0aCA9IDgsCiAgICAgICAgICAgI2Rpc3BsYXkgcGxvdCBwYXJ0CiAgICAgICAgICAgICAjY29kZSBzdGFydCBoZXJlOgogICAgICAgICAgIHBsb3RPdXRwdXQoInBsb3QiKSwKICAgICAgICAgICAKICAgICAgICAgICAgI2NvZGUgZW5kIGhlcmU6CiAgICApCiAgKQopCgoKCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7CiAgIyBDcmVhdGUgYSBuZXcgZGF0YSBmcmFtZSB3aXRoIGFsbCBwb3NzaWJsZSBjb21iaW5hdGlvbnMgb2YgUGNsYXNzIGFuZCBTZXgKICAgIGFsbF9jb21iaW5hdGlvbnMgPC0gZXhwYW5kLmdyaWQoUGNsYXNzID0gYygiMSIsICIyIiwgIjMiKSwgU2V4ID0gYygiZmVtYWxlIiwgIm1hbGUiKSkKCiAgICAjIEpvaW4gdGhlIG5ldyBkYXRhIGZyYW1lIHdpdGggdGhlIG9yaWdpbmFsIHRpdGFuaWMgZGF0YXNldAogICAgdGl0YW5pY19jb21wbGV0ZSA8LSBtZXJnZShhbGxfY29tYmluYXRpb25zLCB0aXRhbmljLCBieSA9IGMoIlBjbGFzcyIsICJTZXgiKSwgYWxsLnggPSBUUlVFKQoKICAgICMgQ29udmVydCBQY2xhc3MgYW5kIFN1cnZpdmVkIHRvIGZhY3RvcnMKICAgIHRpdGFuaWNfY29tcGxldGUkUGNsYXNzIDwtIGFzLmZhY3Rvcih0aXRhbmljX2NvbXBsZXRlJFBjbGFzcykKICAgIHRpdGFuaWNfY29tcGxldGUkU3Vydml2ZWQgPC0gYXMuZmFjdG9yKHRpdGFuaWNfY29tcGxldGUkU3Vydml2ZWQpCiAgCiAgI2NvZGUgc3RhcnQgaGVyZToKICAgICNmaWx0ZXIgdGhlIGRhdGEgYmFzZWQgb24gdGhlIHNlbGVjdGVkIGdlbmRlciwgc3Vydml2YWwgc3RhdHVzLCBhbmQgYWdlIHJhbmdlLgoKCnRpdGFuaWNfZmlsdGVyZWQgPC0gcmVhY3RpdmUoewogICNjb2RlIHN0YXJ0IGhlcmU6CiAgI3VzZSBzdWJzZXQoKSBhbmQgdGFrZSB0aXRhbmljX2NvbXBsZXRlIGFzIGRhdGEKICAjaW5zaWRlIHN1YnNldCgp77yMIHdyaXRlIGNvbmRpdGlvbnMgZm9yIHBjbGFzcywgc2V4LCBhZ2UsIGFuZCBzdXJ2aXZlZCB2YXJpYWJsZXMgdG8gbWF0Y2ggdXNlciBzZWxlY3RlZCB2YWx1ZXMuCiAgCgogIHN1YnNldCh0aXRhbmljX2NvbXBsZXRlLCAoU2V4ID09IGlucHV0JHNleFsxXSB8IFNleCA9PSBpbnB1dCRzZXhbMl0pJiAKICAgICAgICAgKFN1cnZpdmVkID09IGlucHV0JHN1cnZpdmFsWzFdIHwgU3Vydml2ZWQgPT0gaW5wdXQkc3Vydml2YWxbMl0pJiAKICAgICAgICAgQWdlID49IGlucHV0JGFnZVsxXSAmIEFnZSA8PSBpbnB1dCRhZ2VbMl0mCiAgICAgICAgIChQY2xhc3MgPT0gaW5wdXQkcGNsYXNzWzFdIHwgUGNsYXNzID09IGlucHV0JHBjbGFzc1syXSB8IFBjbGFzcyA9PSBpbnB1dCRwY2xhc3NbM10pKQoKICAKICAKICAjY29kZSBlbmQgaGVyZQogIH0pCgoKICBvdXRwdXQkcGxvdCA8LSByZW5kZXJQbG90KHsKICAgIAogICAgI2NvZGUgc3RhcnQgaGVyZToKICAgICNjcmVhdGVzIGEgZ2dwbG90IG9iamVjdCB1c2luZyB0aGUgZmlsdGVyZWQgZGF0YSBhcyBpbnB1dDogdGl0YW5pY19maWx0ZXJlZCgpLCBzZXR0aW5nICAgICAgdGhlIHgtYXhpcyB0byB0aGUgQWdlIGNvbHVtbiBhbmQgdGhlIGZpbGwgdG8gdGhlIFN1cnZpdmVkIGNvbHVtbiAKICAgICN1c2UgZmFjZXRfd3JhcCgpLCBnZW9tX2RlbnNpdHkoKQogICAgCgogICAgZ2dwbG90KHRpdGFuaWNfZmlsdGVyZWQoKSwgYWVzKHggPSBBZ2UsIGZpbGwgPSBTdXJ2aXZlZCkpICsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIGZhY2V0X3dyYXAoU2V4IH4gUGNsYXNzKSArCiAgICAgIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKwogICAgICBsYWJzKHkgPSAiQWdlIiwKICAgICAgICAgICB4ID0gIlN1cnZpdmVkIiwKICAgICAgICAgICB0aXRsZSA9ICJQYXNzZW5nZXIgQ291bnQgYnkgQWdlLCBQY2xhc3MgYW5kIFNleCIpCiAgICAjY29kZSBlbmQgaGVyZQogICAgCiAgfSwgcmVzID0gOTYpCn0KCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKYGBgCgpOb3csIExldCdzIGV4cGxvcmUgdGhlIGludGVyYWN0aXZlIHBsb3Qgd2l0aCBtb3VzZSBldmVudHMgdXNpbmcgc2hpbnkgcGFja2FnZSEKCiMgNi4gSW50ZXJhY3Rpdml0eSBvZiBzaGlueSBwbG90OiBtb3VzZSBldmVudHMKCk9uZSBvZiB0aGUgY29vbGVzdCB0aGluZ3MgYWJvdXQgKipgcGxvdE91dHB1dCgpYCoqIGlzIHRoYXQgYXMgd2VsbCBhcyBiZWluZyBhbiBvdXRwdXQgdGhhdCBkaXNwbGF5cyBwbG90cywgaXQgY2FuIGFsc28gYmUgYW4gaW5wdXQgdGhhdCByZXNwb25kcyB0byBwb2ludGVyIGV2ZW50cy4gVGhhdCBhbGxvd3MgeW91IHRvIGNyZWF0ZSBpbnRlcmFjdGl2ZSBncmFwaGljcyB3aGVyZSB0aGUgdXNlciBpbnRlcmFjdHMgZGlyZWN0bHkgd2l0aCB0aGUgZGF0YSBvbiB0aGUgcGxvdC4KCkEgcGxvdCBjYW4gcmVzcG9uZCB0byBmb3VyIGRpZmZlcmVudCBtb3VzZSBldmVudHM6IGNsaWNrLCBkYmxjbGljayAoZG91YmxlIGNsaWNrKSwgaG92ZXIgKHdoZW4gdGhlIG1vdXNlIHN0YXlzIGluIHRoZSBzYW1lIHBsYWNlIGZvciBhIGxpdHRsZSB3aGlsZSksIGFuZCBicnVzaCAoYSByZWN0YW5ndWxhciBzZWxlY3Rpb24gdG9vbCkuCgpUcnkgdG8gdXNlICoqYHBsb3RPdXRwdXQoInBsb3QiLCBjbGljayA9ICJwbG90X2NsaWNrIilgKiogLiBUaGlzIGNyZWF0ZXMgYW4gKipgaW5wdXQkcGxvdF9jbGlja2AqKiB0aGF0IHlvdSBjYW4gdXNlIHRvIGhhbmRsZSBtb3VzZSBjbGlja3Mgb24gdGhlIHBsb3QuCgpOb3csIExldCdzIGV4cGxvcmUgdGhlIGludGVyYWN0aXZlIHBsb3Qgd2l0aCBtb3VzZSBldmVudHMgdXNpbmcgc2hpbnkgcGFja2FnZSEKCi0gICBIZXJlIGlzIGFuIGV4YW1wbGUgdXNpbmcgbXRjYXJzIGRhdGFzZXQuIFRyeSBpdCBvdXQgYW5kIHdlIHdpbGwgdXNlIHRoaXMgcG9pbnRlciBldmVudHMgaW5wdXQgbGF0ZXIgZm9yIGNpdGliaWtlIGFuYWx5c2lzCgpgYGB7cn0KdWkgPC0gZmx1aWRQYWdlKAogICNjb2RlIHN0YXJ0IGhlcmU6CiAgcGxvdE91dHB1dCgicGxvdCIsIGNsaWNrID0gInBsb3RfY2xpY2siKSwKICB2ZXJiYXRpbVRleHRPdXRwdXQoImluZm8iKQopCgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIG91dHB1dCRwbG90IDwtIHJlbmRlclBsb3QoewogICAgcGxvdChtdGNhcnMkd3QsIG10Y2FycyRtcGcpCiAgfSwgcmVzID0gOTYpCgogIG91dHB1dCRpbmZvIDwtIHJlbmRlclByaW50KHsKICAgIHJlcShpbnB1dCRwbG90X2NsaWNrKQogICAgeCA8LSByb3VuZChpbnB1dCRwbG90X2NsaWNrJHgsIDIpCiAgICB5IDwtIHJvdW5kKGlucHV0JHBsb3RfY2xpY2skeSwgMikKICAgIGNhdCgiWyIsIHgsICIsICIsIHksICJdIiwgc2VwID0gIiIpCiAgfSkKfQpzaGlueUFwcCh1aSA9IHVpLCBzZXJ2ZXIgPSBzZXJ2ZXIpCmBgYAoKTGV0J3Mgc3RhcnQgdG8gY3JlYXRlIHRoZSBpbnRlcmFjdGl2ZSBwbG90IGZvciBjaXRpYmlrZSBkYXRhc2V0IHVzaW5nIHNoaW55IHBhY2thZ2UuCgojIDcuIENyZWF0ZSBpbnRlcmFjdGl2ZSBsaW5lIGdyYXBoIHdpdGggbW91c2UgZXZlbnQKClF1ZXN0aW9uOiBJcyB0aGVyZSBhIHNlYXNvbmFsaXR5PyBBc3N1bXB0aW9uOiB0aGVyZSBhcmUgZmV3ZXIgdHJpcHMgZHVyaW5nIHdpbnRlcnMgYW5kIG1vcmUgdHJpcHMgZHVyaW5nIHN1bW1lcnMuCgpXZSB3YW50IHRvIGRpc3BsYXlzIGEgbGluZSBncmFwaCBvZiB0aGUgY291bnQgb2YgYmlrZSByZW50YWxzIHRvIGxldCB5b3Ugb2JzZXJ2ZSB3aGV0aGVyIHRoZXJlIGlzIGEgc2Vhc29uYWxpdHkgZm9yIHRoZSBjb3VudCBvZiBiaWtlIHJlbnRhbHMuCgotICAgRm9yIGJldHRlciBvYnNlcnZhdGlvbiwgd2UgbmVlZCB0byBhZ2dyZWdhdGUgZGF0YSBieSBkYXRlIGFuZCBzaG93IHRoZSBzdW0gb2YgdGhlIGJpa2UgcmVudGFsIGNvdW50cy4KCmBgYHtyfQpsaWJyYXJ5KGx1YnJpZGF0ZSkKI2xvYWQgdGhlIGRhdGFzZXQKZGF0YXNldCA8LSByZWFkLmNzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NhbWFudGhhOTYvY3NlMTYwL21haW4vdHJhaW4uY3N2JykKZGF0YXNldCRkYXRlIDwtIGRhdGUoZGF0YXNldCRkYXRldGltZSkKIyBDaGVjayB0aGUgcmVzdWx0CmhlYWQoZGF0YXNldCkKYGBgCgotICAgQ3JlYXRlIGludGVyYWN0aXZpdHkgYnkgYXBwbGluZyB0aGUgY2xpY2sgb3IgaG92ZXIgbGlrZSB0aGUgZXhhbXBsZSBzaG93ZWQgYmVmb3JlLgoKLSAgIFNob3cgdGhlIGNvcnJzcG9uZGluZyBiaWtlIHJlbnRhbCBpbmZvcm1hdGlvbiBmb3IgdGhhdCBkYXRhIHlvdSBjbGljayBvciBob3Zlci4gSGVyZSBpcyBhbiBleGFtcGxlOiAhW10oaHR0cHM6Ly9naXRodWIuY29tL3NhbWFudGhhOTYvY3NlMTYwL2Jsb2IvbWFpbi9leGFtcGxlNS5wbmc/cmF3PXRydWUpCgogICAgVHJ5IHRvIHJ1biB0aGUgZm9sbG93aW5nIGNvZGUgYW5kIGV4cGxvcmUgdGhlIG1vdXNlIGV2ZW50IGZvciBzaGlueSBhcHAuIE5vIG5lZWQgdG8gd3JpdGUgdGhlIGNvZGUuCgpgYGB7cn0KCiMgQWdncmVnYXRlIGRhdGEgYnkgZGF0ZSB0byBzdG9yZSB0aGUgdmFsdWUKCmRhdGVfZGF0YSA8LSBzdW1tYXJpc2UoZ3JvdXBfYnkoZGF0YXNldCwgZGF0ZSksIHRvdGFsX2NvdW50ID0gc3VtKGNvdW50KSkKCiMgRGVmaW5lIHRoZSBVSQp1aSA8LSBmbHVpZFBhZ2UoCiAgdGl0bGVQYW5lbCgiRXhwbG9yZSBCaWtlIFJlbnRhbHMgc2Vhc29uYWxpdHkiKSwKICAKICBtYWluUGFuZWwoCiAgICBwbG90T3V0cHV0KCJwbG90IiwgaG92ZXIgPSBob3Zlck9wdHMoInBsb3RfaG92ZXIiKSksCiAgICB2ZXJiYXRpbVRleHRPdXRwdXQoImluZm8iKQogICkKKQoKIyBEZWZpbmUgdGhlIHNlcnZlcgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIAogICMgQ3JlYXRlIHRoZSBwbG90OmxpbmUgZ3JhcGggb2YgdGhlIGNvdW50IG9mIGJpa2UgcmVudGFscyBieSBkYXRlCiAgICBvdXRwdXQkcGxvdCA8LSByZW5kZXJQbG90KHsKICAgIGdncGxvdChkYXRlX2RhdGEsIGFlcyh4ID0gZGF0ZSwgeSA9IHRvdGFsX2NvdW50KSkgKwogICAgICBnZW9tX2xpbmUoKSArCiAgICAgIGxhYnModGl0bGUgPSAiRXhwbG9yZSBCaWtlIFJlbnRhbHMgc2Vhc29uYWxpdHkiLAogICAgICAgICAgIHggPSAiRGF0ZSIsCiAgICAgICAgICAgeSA9ICJDb3VudCIpCiAgfSkKCiAgCiAgIyBDcmVhdGUgdGhlIGhvdmVyIG9yIGNsaWNrIGluZm9ybWF0aW9uCiAgCiAgb3V0cHV0JGluZm8gPC0gcmVuZGVyUHJpbnQoewogICAgaWYgKGlzLm51bGwoaW5wdXQkcGxvdF9ob3ZlcikpIHsKICAgICAgcmV0dXJuKCkKICAgIH0KICAgIAogICAgeCA8LSBhcy5udW1lcmljKGlucHV0JHBsb3RfaG92ZXIkeCkKICAgIHkgPC0gYXMubnVtZXJpYyhpbnB1dCRwbG90X2hvdmVyJHkpCiAgICAKICAgICMgRmluZCB0aGUgY2xvc2VzdCBwb2ludCB0byB0aGUgaG92ZXIgbG9jYXRpb24KICAgIGNsb3Nlc3RfcG9pbnQgPC0gd2hpY2gubWluKGFicyhhcy5udW1lcmljKGRhdGVfZGF0YSRkYXRlKSAtIHgpKQogICAgCiAgICBwYXN0ZSgKICAgICAgI3Nob3cgaW5mb3JtYXRpb24gb2YgY2xpY2sgcG9pbnQgYWJvdXQgaXRzIGRhdGUgYW5kIGNvdW50CiAgICAgICJEYXRlOiIsIGRhdGVfZGF0YSRkYXRlW2Nsb3Nlc3RfcG9pbnRdLAogICAgICAiQ291bnQ6IiwgZGF0ZV9kYXRhJHRvdGFsX2NvdW50W2Nsb3Nlc3RfcG9pbnRdCiAgICApCiAgfSkKICAKfQoKIyBSdW4gdGhlIGFwcApzaGlueUFwcCh1aSwgc2VydmVyKQoKCmBgYAoKIyA4LiBPcmdhbml6ZSB0aGUgUi4gZmlsZXMKCkZvciB0aGlzIG5vdGVib29rLCB3ZSBwdXQgdGhlbSBpbnRvIG9uZSBjaHVuayB0byBydW4gdGhlIHNoaW55IGNvZGUuCgpJZiB3ZSB3YW50IHRvIGtlZXAgeW91ciBjb2RlIG9yZ2FuaXplZCBhbmQgZWFzaWVyIHRvIG1haW50YWluLCB3ZSBjb3VsZCBzZXBhcmF0ZSB0aGUgVUkgYW5kIHNlcnZlciBmdW5jdGlvbnMgaW50byBzZXBhcmF0ZSBmaWxlcy4uCgp3ZSBzZXQgdXAgdGhyZWUgZmlsZXM6IHVpLlIgdG8gZGVmaW5lIHRoZSBhcHAgcHJlc2VudGF0aW9uLCBzZXJ2ZXIuUiB0byBkZWZpbmUgdGhlIGFwcCBsb2dpYywgYW5kIHNoaW55QXBwLlIgdG8gcnVuIHRoZSBmb3JtZXIgdHdvLgoKLSAgIFJlbWVtYmVyIHRvIHNhdmUgdGhlc2UgdGhyZWUgUiBzY3JpcHRzIGluIHRoZSBzYW1lIGRpcmVjdG9yeSBhcyB0aGUgYXBwLlIgZmlsZS4KCi0gICBEZWZpbmUgdGhlIHVpIGFuZCBzZXJ2ZXIgZnVuY3Rpb24gaW4gdWkuUiBhbmQgc2VydmVyLlIgc2VwZXJhdGVseS4KCjEudWkuUgoKYGBge3J9CnVpIDwtIGZsdWlkUGFnZSgKICAjIFVJIGVsZW1lbnRzIGdvIGhlcmUKKQojIHJldHVybiB0aGUgVUkgb2JqZWN0CnVpCmBgYAoKMi5zZXJ2ZXIuUgoKYGBge3J9CnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7CiAgIyBzZXJ2ZXIgbG9naWMgZ29lcyBoZXJlCn0KIyByZXR1cm4gdGhlIHNlcnZlciBvYmplY3QKc2VydmVyCmBgYAoKMy5zaGlueUFwcC5SCgogICAgc291cmNlIHRoZSB1aS5SIGFuZCBzZXJ2ZXIuUiBmaWxlcyBhbmQgdGhlbiBjYWxsIHRoZSBzaGlueUFwcCBmdW5jdGlvbiB3aXRoIHRoZSB1aSBhbmQgc2VydmVyIG9iamVjdHMuCgpgYGB7cn0KIyBzb3VyY2UgdGhlIFVJIGFuZCBzZXJ2ZXIgZmlsZXMKc291cmNlKCJ1aS5SIikKc291cmNlKCJzZXJ2ZXIuUiIpCgojIGNyZWF0ZSB0aGUgU2hpbnkgYXBwCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKYGBgCgpDb21iaW5lIHRoZXNlIHRocmVlIFIgc3JpY3B0cyBhbmQgYWxsIG90aGVyIG1hdGVyaWFscyhlLmcuaW1hZ2UpIGludG8gb25lIHNpbmdsZSBmb2xkZXIsIHdoaWNoIHRoZSBmb2xkZXIgcGF0aCB3aWxsIGJlIHRoZSBwYXRoIHRvIHB1Ymxpc2ggeW91ciBzaGlueSBhcHAuCgojIDkuIFB1Ymxpc2ggdGhlIHNoaW55IGFwcC4KCk5vdywgTGV0J3MgcHVibGlzaCBvdXIgc2hpbnkgYXBwLiBDcmVhdGUgZnJlZSBhY2NvdW50IG9uIHNoaW55YXBwLmlvLiBJbnN0YWxsIHRoZSByc2Nvbm5lY3QgcGFja2FnZSwgYXV0aG9yaXplIGFjY291bnQgYW5kIGRlcGxveSB5b3VyIGFwcCEgPGh0dHBzOi8vd3d3LnNoaW55YXBwcy5pby9hZG1pbi8jL2Rhc2hib2FyZD4KCmBgYHtyfQpsaWJyYXJ5KHJzY29ubmVjdCkKCiNUaGUgcnNjb25uZWN0IHBhY2thZ2UgbXVzdCBiZSBhdXRob3JpemVkIHRvIHlvdXIgYWNjb3VudCB1c2luZyBhIHRva2VuIGFuZCBzZWNyZXQuIFBhc3RlIGl0IGludG8geW91ciBSIGNvbnNvbGUgdG8gYXV0aG9yaXplIHlvdXIgYWNjb3VudC4KI3JzY29ubmVjdDo6c2V0QWNjb3VudEluZm8obmFtZT0neW91ciBuYW1lJywKCQkJICAjdG9rZW49J3lvdXIgdG9rZW4nLAoJCQkgICNzZWNyZXQ9JzxTRUNSRVQ+JykKCiNPbmNlIHRoZSByc2Nvbm5lY3QgcGFja2FnZSBoYXMgYmVlbiBjb25maWd1cmVkLCB5b3UncmUgcmVhZHkgdG8gZGVwbG95IHlvdXIgZmlyc3QgYXBwbGljYXRpb24uIAojcnNjb25uZWN0OjpkZXBsb3lBcHAoJy9Vc2Vycy9zYW1hbnRoYWNoZW4vRGVza3RvcC9zaGlueWFwcCcpCmBgYAoKT25jZSB5b3UgaGF2ZSBwdWJsaXNoZWQgeW91ciBhcHAsIHlvdSBzdGlsbCBjYW4gY29udGludWUgbW9kaWZ5IHlvdXIgYXBwIGFuZCByZXB1Ymxpc2ggaXQuCgotICAgRm9yIHRoaXMgbGFiLCBzdWJtaXQgeW91ciBub3RlYm9vayBhbmQgeW91ciBwdWJsaXNoZWQgbGluayBmb3Igc3RlcCA1Lgo=