Instructions and Overview

This week, I’d like you to primarily focus on preparing your final presentation. However, we will also spend just a bit of time documenting the uncertainty in each of the numbers and plots on our dashboards.

Getting Started

Load the relevant libraries

library(tidyverse)
library(lubridate)
library(shiny)
library(shinydashboard)
library(shinyWidgets)

Import and clean example datasets

hospitals <- read.csv("https://raw.githubusercontent.com/lindsaypoirier/STS-115/master/datasets/Hospitals.csv", stringsAsFactors = FALSE)

cases <- read.csv("https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv", stringsAsFactors = FALSE)

#Do not worry about this line of code for now. Since the cases data gets appended every day with a new column representing that day's case counts, if we want the total cases per country, we need to add up all of the previous day's counts into a new column. The column below does this for us. 
cases <- 
  cases %>% 
  mutate(Total.Cases = 
           cases %>% 
           select(starts_with("X")) %>% 
           rowSums()
         ) %>%
  select(Province.State, Country.Region, Total.Cases)

hospitals$ZIP <- as.character(hospitals$ZIP)

hospitals$ZIP <- str_pad(hospitals$ZIP, 5, pad = "0") 

is.na(hospitals) <- hospitals == "NOT AVAILABLE"
is.na(hospitals) <- hospitals == -999
is.na(cases) <- cases == ""

hospitals$SOURCEDATE <- ymd_hms(hospitals$SOURCEDATE)
hospitals$VAL_DATE <- ymd_hms(hospitals$VAL_DATE)

Import and clean your dataset

#Copy and paste relevant code from Lab 4 to import your data here. 

#Copy and paste relevant code from Lab 4 to clean your data here. This includes any row binding, character removals, converions in variable type, date formatting, or NA conversions. 

Continue your shiny app

At this point, we are going to add text to the front interface of our Shiny app considering the issues that are not addressed in each of our calculations or plots. Follow the instructions below to fill your text into comment boxes on the front page of the app.

We won’t be touching the input variables this week. First copy and paste your input variables from lab 7.

#======================
#COPY AND PASTE THE INPUT VARIABLES SECTION FROM LAB 7 BELOW
#======================
geo_input_choices <- 
  #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
  hospitals %>% 
  #REPLACE STATE BELOW WITH YOUR OWN GEOGRAPHIC VARIABLE
  select(STATE) %>% 
  distinct() %>% 
  #REPLACE STATE BELOW WITH YOUR OWN GEOGRAPHIC VARIABLE
  arrange(STATE)

#COMMENT LINES BELOW IF YOU DO NOT HAVE A TEMPORAL VARIABLE IN YOUR DATAFRAME
date_input_start <- 
  #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
  hospitals %>% 
  #REPLACE SOURCEDATE BELOW WITH YOUR OWN TEMPORAL VARIABLE
  summarize(date = min(SOURCEDATE))

date_input_end <- 
  #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
  hospitals %>% 
  #REPLACE SOURCEDATE BELOW WITH YOUR OWN TEMPORAL VARIABLE
  summarize(date = max(SOURCEDATE))
#COMMENT LINES ABOVE IF YOU DO NOT HAVE A TEMPORAL VARIABLE IN YOUR DATAFRAME

#======================
#COPY AND PASTE THE INPUT VARIABLES SECTION FROM LAB 7 ABOVE
#======================

In the UI function below, you are going to complete the 7 statements following the commented instruction “#COMPLETE THE STATEMENT BELOW FOR…” Once you’ve completed these statements, copy and paste the rest of the UI function from lab 8 where I’ve indicated.

ui <- dashboardPage(
  
  #REPLACE 'TITLE HERE' BELOW WITH YOUR OWN TITLE
  dashboardHeader(title = "TITLE HERE"),
  #REPLACE 'TITLE HERE' ABOVE WITH YOUR OWN TITLE
  
  dashboardSidebar(
      sidebarMenu(
        menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
        menuItem("About the Data", tabName = "about", icon = icon("info-sign"))
      ),
      selectInput(inputId = "geo_val", label = "Select an geography:", choices = geo_input_choices, selected = geo_input_choices[1]),
      #COMMENT LINE BELOW IF YOU DO NOT HAVE A TEMPORAL VARIABLE IN YOUR DATAFRAME
      dateRangeInput(inputId = "date_val", label = "Select a date range:", start = date_input_start$date, end = date_input_end$date)
      #COMMENT LINE ABOVE IF YOU DO NOT HAVE A TEMPORAL VARIABLE IN YOUR DATAFRAME
  ),
  
  dashboardBody(
    tags$head(tags$style(HTML('.content-wrapper { overflow: auto; }'))),
    tabItems(
      tabItem(tabName = "dashboard",
        infoBoxOutput("value1", width = 4),
        infoBoxOutput("value2", width = 4),
        infoBoxOutput("value3", width = 4),
        
        #COMPLETE THE STATEMENT BELOW FOR VALUEBOX 1 
        box(tags$p("The number above does not account for..."), width = 4),
        
        #COMPLETE THE STATEMENT BELOW FOR VALUEBOX 2 
        box(tags$p("The number above does not account for..."), width = 4),
       
        #COMPLETE THE STATEMENT BELOW FOR VALUEBOX 3 
        box(tags$p("The number above does not account for git, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam ei"), width = 4),
     
        box(plotOutput("plot1")),
        box(plotOutput("plot2")),
        
        #COMPLETE THE STATEMENT BELOW FOR PLOT 1        
        box(tags$p("The plot above does not account for..."), width = 6),
        
        #COMPLETE THE STATEMENT BELOW FOR PLOT 2  
        box(tags$p("The plot above does not account for..."), width = 6),
        
        box(plotOutput("plot3")),
        box(plotOutput("plot4")),
        
        #COMPLETE THE STATEMENT BELOW FOR PLOT 3
        box(tags$p("The plot above does not account for..."), width = 6),
        
        #COMPLETE THE STATEMENT BELOW FOR PLOT 4
        box(tags$p("The plot above does not account for..."), width = 6)
      ),
      
#======================
#COPY AND PASTE THE REMAINDER OF THE UI FUNCTION FROM LAB 8 BELOW
#======================
      tabItem(tabName = "about",
              tags$h1("Data Source"),
                #REPLACE TEXT IN QUOTATIONS BELOW WITH YOUR OWN TEXT ABOUT YOUR DATA'S SOURCE
              tags$p("Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"),
              #REPLACE TEXT IN QUOTATIONS ABOVE WITH YOUR OWN TEXT ABOUT YOUR DATA'S SOURCE
              
              tags$h1("Data Context"),
              #REPLACE TEXT IN QUOTATIONS BELOW WITH YOUR OWN TEXT ABOUT YOUR DATA'S CONTEXT
              tags$p("Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"),
              #REPLACE TEXT IN QUOTATIONS ABOVE WITH YOUR OWN TEXT ABOUT YOUR DATA'S SOURCE
              
              tags$h1("Insights"),
              #REPLACE TEXT IN QUOTATIONS BELOW WITH YOUR OWN TEXT ABOUT YOUR INSIGHTS
              tags$p("Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"),
              #REPLACE TEXT IN QUOTATIONS ABOVE WITH YOUR OWN TEXT ABOUT YOUR INSIGHTS
              
              tags$h1("Knowledge Gaps"),
              #REPLACE TEXT IN QUOTATIONS BELOW WITH YOUR OWN TEXT ABOUT YOUR KNOWLEDGE GAPS
              tags$p("Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?")
              #REPLACE TEXT IN QUOTATIONS ABOVE WITH YOUR OWN TEXT ABOUT YOUR KNOWLEDGE GAPS
      )
    )
  )
)
  
#======================
#COPY AND PASTE THE REMAINDER OF THE UI FUNCTION FROM LAB 8 ABOVE
#======================

We won’t be touching the server function this week. You can copy and paste yours from Lab 7 to replace my code below.

#======================
#COPY AND PASTE THE SERVER FUNCTION FROM LAB 7 BELOW
#======================

server <- function(input, output) {
  
  output$value1 <- renderInfoBox({
    quant_insight1 <-
    #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
    hospitals %>% 
    #REPLACE STATE WITH YOUR OWN GEOGRAPHIC VARIABLE AND SOURCEDATE WITH YOUR OWN TEMPORAL VARIABLE
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%      
    #COPY AND PASTE YOUR FUNCTION HERE FROM LAB 6
      filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
      summarize(median_value = median(BEDS, na.rm = TRUE))
    
    #REPLACE 'FILL DESCRIPTION HERE' BELOW WITH YOUR OWN DESCRIPTION
    infoBox(quant_insight1,'FILL DESCRIPTION HERE', icon = icon("stats", lib='glyphicon'), color = "purple")
  })
  
  output$value2 <- renderInfoBox({
    quant_insight2 <- 
    #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
    hospitals %>% 
    #REPLACE STATE WITH YOUR OWN GEOGRAPHIC VARIABLE AND SOURCEDATE WITH YOUR OWN TEMPORAL VARIABLE
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
    #COPY AND PASTE YOUR FUNCTION HERE FROM LAB 6
      filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
      summarize(median_value = median(BEDS, na.rm = TRUE))
    
    #REPLACE 'FILL DESCRIPTION HERE' BELOW WITH YOUR OWN DESCRIPTION
    infoBox(quant_insight2,'FILL DESCRIPTION HERE', icon = icon("stats", lib='glyphicon'), color = "purple")
  })
  
  output$value3 <- renderInfoBox({
    quant_insight3 <- 
    #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
    hospitals %>% 
    #REPLACE STATE WITH YOUR OWN GEOGRAPHIC VARIABLE AND SOURCEDATE WITH YOUR OWN TEMPORAL VARIABLE
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
    #COPY AND PASTE YOUR FUNCTION HERE FROM LAB 6
      filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
      summarize(median_value = median(BEDS, na.rm = TRUE))

    #REPLACE 'FILL DESCRIPTION HERE' BELOW WITH YOUR OWN DESCRIPTION
    infoBox(quant_insight3,'FILL DESCRIPTION HERE', icon = icon("stats", lib='glyphicon'), color = "purple")
  })
  
  output$plot1 <- renderPlot({
    #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
    hospitals %>% 
    #REPLACE STATE WITH YOUR OWN GEOGRAPHIC VARIABLE AND SOURCEDATE WITH YOUR OWN TEMPORAL VARIABLE
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
    #COPY AND PASTE YOUR PLOT HERE FROM LAB 6
      filter(STATUS == "OPEN") %>%
      ggplot(aes(x = TYPE)) + 
      geom_bar() +
      labs(title = "Number of Hospitals in the US that are Open by Type", x = "Type", y = "Count of Hospitals") + 
      theme_bw() +
      theme(axis.text.x = element_text(angle = 90, hjust=1)) 
  })
  
  output$plot2 <- renderPlot({
    #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
    hospitals %>% 
    #REPLACE STATE WITH YOUR OWN GEOGRAPHIC VARIABLE AND SOURCEDATE WITH YOUR OWN TEMPORAL VARIABLE
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
    #COPY AND PASTE YOUR PLOT HERE FROM LAB 6
      filter(STATUS == "OPEN") %>%
      ggplot(aes(x = TYPE)) + 
      geom_bar() +
      labs(title = "Number of Hospitals in the US that are Open by Type", x = "Type", y = "Count of Hospitals") + 
      theme_bw() +
      theme(axis.text.x = element_text(angle = 90, hjust=1)) 
  })
  
  output$plot3 <- renderPlot({
    #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
    hospitals %>% 
    #REPLACE STATE WITH YOUR OWN GEOGRAPHIC VARIABLE AND SOURCEDATE WITH YOUR OWN TEMPORAL VARIABLE
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
    #COPY AND PASTE YOUR PLOT HERE FROM LAB 6
      filter(STATUS == "OPEN") %>%
      ggplot(aes(x = TYPE)) + 
      geom_bar() +
      labs(title = "Number of Hospitals in the US that are Open by Type", x = "Type", y = "Count of Hospitals") + 
      theme_bw() +
      theme(axis.text.x = element_text(angle = 90, hjust=1)) 
  })
  
  output$plot4 <- renderPlot({
    #REPLACE hospitals BELOW WITH YOUR OWN DATAFRAME
    hospitals %>% 
    #REPLACE STATE WITH YOUR OWN GEOGRAPHIC VARIABLE AND SOURCEDATE WITH YOUR OWN TEMPORAL VARIABLE
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
    #COPY AND PASTE YOUR PLOT HERE FROM LAB 6
      filter(STATUS == "OPEN") %>%
      ggplot(aes(x = TYPE)) + 
      geom_bar() +
      labs(title = "Number of Hospitals in the US that are Open by Type", x = "Type", y = "Count of Hospitals") + 
      theme_bw() +
      theme(axis.text.x = element_text(angle = 90, hjust=1)) 
  })
} 
#======================
#COPY AND PASTE THE SERVER FUNCTION FROM LAB 7 ABOVE
#======================
shinyApp(ui, server)

Listening on http://127.0.0.1:6574
NA
LS0tCnRpdGxlOiAiTGFiIDkgLSBQcmVzZW50aW5nIERhdGEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMycKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCiMjIEluc3RydWN0aW9ucyBhbmQgT3ZlcnZpZXcKClRoaXMgd2VlaywgSSdkIGxpa2UgeW91IHRvIHByaW1hcmlseSBmb2N1cyBvbiBwcmVwYXJpbmcgeW91ciBmaW5hbCBwcmVzZW50YXRpb24uIEhvd2V2ZXIsIHdlIHdpbGwgYWxzbyBzcGVuZCBqdXN0IGEgYml0IG9mIHRpbWUgZG9jdW1lbnRpbmcgdGhlIHVuY2VydGFpbnR5IGluIGVhY2ggb2YgdGhlIG51bWJlcnMgYW5kIHBsb3RzIG9uIG91ciBkYXNoYm9hcmRzLiAKCiMjIEdldHRpbmcgU3RhcnRlZAoKIyMjIExvYWQgdGhlIHJlbGV2YW50IGxpYnJhcmllcwoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShzaGlueSkKbGlicmFyeShzaGlueWRhc2hib2FyZCkKbGlicmFyeShzaGlueVdpZGdldHMpCmBgYAoKIyMjIEltcG9ydCBhbmQgY2xlYW4gZXhhbXBsZSBkYXRhc2V0cyAKCmBgYHtyfQpob3NwaXRhbHMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9saW5kc2F5cG9pcmllci9TVFMtMTE1L21hc3Rlci9kYXRhc2V0cy9Ib3NwaXRhbHMuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKY2FzZXMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DU1NFR0lTYW5kRGF0YS9DT1ZJRC0xOS9tYXN0ZXIvY3NzZV9jb3ZpZF8xOV9kYXRhL2Nzc2VfY292aWRfMTlfdGltZV9zZXJpZXMvdGltZV9zZXJpZXNfY292aWQxOV9jb25maXJtZWRfZ2xvYmFsLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCiNEbyBub3Qgd29ycnkgYWJvdXQgdGhpcyBsaW5lIG9mIGNvZGUgZm9yIG5vdy4gU2luY2UgdGhlIGNhc2VzIGRhdGEgZ2V0cyBhcHBlbmRlZCBldmVyeSBkYXkgd2l0aCBhIG5ldyBjb2x1bW4gcmVwcmVzZW50aW5nIHRoYXQgZGF5J3MgY2FzZSBjb3VudHMsIGlmIHdlIHdhbnQgdGhlIHRvdGFsIGNhc2VzIHBlciBjb3VudHJ5LCB3ZSBuZWVkIHRvIGFkZCB1cCBhbGwgb2YgdGhlIHByZXZpb3VzIGRheSdzIGNvdW50cyBpbnRvIGEgbmV3IGNvbHVtbi4gVGhlIGNvbHVtbiBiZWxvdyBkb2VzIHRoaXMgZm9yIHVzLiAKY2FzZXMgPC0gCiAgY2FzZXMgJT4lIAogIG11dGF0ZShUb3RhbC5DYXNlcyA9IAogICAgICAgICAgIGNhc2VzICU+JSAKICAgICAgICAgICBzZWxlY3Qoc3RhcnRzX3dpdGgoIlgiKSkgJT4lIAogICAgICAgICAgIHJvd1N1bXMoKQogICAgICAgICApICU+JQogIHNlbGVjdChQcm92aW5jZS5TdGF0ZSwgQ291bnRyeS5SZWdpb24sIFRvdGFsLkNhc2VzKQoKaG9zcGl0YWxzJFpJUCA8LSBhcy5jaGFyYWN0ZXIoaG9zcGl0YWxzJFpJUCkKCmhvc3BpdGFscyRaSVAgPC0gc3RyX3BhZChob3NwaXRhbHMkWklQLCA1LCBwYWQgPSAiMCIpIAoKaXMubmEoaG9zcGl0YWxzKSA8LSBob3NwaXRhbHMgPT0gIk5PVCBBVkFJTEFCTEUiCmlzLm5hKGhvc3BpdGFscykgPC0gaG9zcGl0YWxzID09IC05OTkKaXMubmEoY2FzZXMpIDwtIGNhc2VzID09ICIiCgpob3NwaXRhbHMkU09VUkNFREFURSA8LSB5bWRfaG1zKGhvc3BpdGFscyRTT1VSQ0VEQVRFKQpob3NwaXRhbHMkVkFMX0RBVEUgPC0geW1kX2htcyhob3NwaXRhbHMkVkFMX0RBVEUpCmBgYAoKIyMjIEltcG9ydCBhbmQgY2xlYW4geW91ciBkYXRhc2V0CgpgYGB7cn0KI0NvcHkgYW5kIHBhc3RlIHJlbGV2YW50IGNvZGUgZnJvbSBMYWIgNCB0byBpbXBvcnQgeW91ciBkYXRhIGhlcmUuIAoKI0NvcHkgYW5kIHBhc3RlIHJlbGV2YW50IGNvZGUgZnJvbSBMYWIgNCB0byBjbGVhbiB5b3VyIGRhdGEgaGVyZS4gVGhpcyBpbmNsdWRlcyBhbnkgcm93IGJpbmRpbmcsIGNoYXJhY3RlciByZW1vdmFscywgY29udmVyaW9ucyBpbiB2YXJpYWJsZSB0eXBlLCBkYXRlIGZvcm1hdHRpbmcsIG9yIE5BIGNvbnZlcnNpb25zLiAKYGBgCgojIyBDb250aW51ZSB5b3VyIHNoaW55IGFwcAoKQXQgdGhpcyBwb2ludCwgd2UgYXJlIGdvaW5nIHRvIGFkZCB0ZXh0IHRvIHRoZSBmcm9udCBpbnRlcmZhY2Ugb2Ygb3VyIFNoaW55IGFwcCBjb25zaWRlcmluZyB0aGUgaXNzdWVzIHRoYXQgYXJlIG5vdCBhZGRyZXNzZWQgaW4gZWFjaCBvZiBvdXIgY2FsY3VsYXRpb25zIG9yIHBsb3RzLiBGb2xsb3cgdGhlIGluc3RydWN0aW9ucyBiZWxvdyB0byBmaWxsIHlvdXIgdGV4dCBpbnRvIGNvbW1lbnQgYm94ZXMgb24gdGhlIGZyb250IHBhZ2Ugb2YgdGhlIGFwcC4KCldlIHdvbid0IGJlIHRvdWNoaW5nIHRoZSBpbnB1dCB2YXJpYWJsZXMgdGhpcyB3ZWVrLiBGaXJzdCBjb3B5IGFuZCBwYXN0ZSB5b3VyIGlucHV0IHZhcmlhYmxlcyBmcm9tIGxhYiA3LgoKYGBge3J9CiM9PT09PT09PT09PT09PT09PT09PT09CiNDT1BZIEFORCBQQVNURSBUSEUgSU5QVVQgVkFSSUFCTEVTIFNFQ1RJT04gRlJPTSBMQUIgNyBCRUxPVwojPT09PT09PT09PT09PT09PT09PT09PQpnZW9faW5wdXRfY2hvaWNlcyA8LSAKICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICBob3NwaXRhbHMgJT4lIAogICNSRVBMQUNFIFNUQVRFIEJFTE9XIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRQogIHNlbGVjdChTVEFURSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogICNSRVBMQUNFIFNUQVRFIEJFTE9XIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRQogIGFycmFuZ2UoU1RBVEUpCgojQ09NTUVOVCBMSU5FUyBCRUxPVyBJRiBZT1UgRE8gTk9UIEhBVkUgQSBURU1QT1JBTCBWQVJJQUJMRSBJTiBZT1VSIERBVEFGUkFNRQpkYXRlX2lucHV0X3N0YXJ0IDwtIAogICNSRVBMQUNFIGhvc3BpdGFscyBCRUxPVyBXSVRIIFlPVVIgT1dOIERBVEFGUkFNRQogIGhvc3BpdGFscyAlPiUgCiAgI1JFUExBQ0UgU09VUkNFREFURSBCRUxPVyBXSVRIIFlPVVIgT1dOIFRFTVBPUkFMIFZBUklBQkxFCiAgc3VtbWFyaXplKGRhdGUgPSBtaW4oU09VUkNFREFURSkpCgpkYXRlX2lucHV0X2VuZCA8LSAKICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICBob3NwaXRhbHMgJT4lIAogICNSRVBMQUNFIFNPVVJDRURBVEUgQkVMT1cgV0lUSCBZT1VSIE9XTiBURU1QT1JBTCBWQVJJQUJMRQogIHN1bW1hcml6ZShkYXRlID0gbWF4KFNPVVJDRURBVEUpKQojQ09NTUVOVCBMSU5FUyBBQk9WRSBJRiBZT1UgRE8gTk9UIEhBVkUgQSBURU1QT1JBTCBWQVJJQUJMRSBJTiBZT1VSIERBVEFGUkFNRQoKIz09PT09PT09PT09PT09PT09PT09PT0KI0NPUFkgQU5EIFBBU1RFIFRIRSBJTlBVVCBWQVJJQUJMRVMgU0VDVElPTiBGUk9NIExBQiA3IEFCT1ZFCiM9PT09PT09PT09PT09PT09PT09PT09CmBgYAoKSW4gdGhlIFVJIGZ1bmN0aW9uIGJlbG93LCB5b3UgYXJlIGdvaW5nIHRvIGNvbXBsZXRlIHRoZSA3IHN0YXRlbWVudHMgZm9sbG93aW5nIHRoZSBjb21tZW50ZWQgaW5zdHJ1Y3Rpb24gIiNDT01QTEVURSBUSEUgU1RBVEVNRU5UIEJFTE9XIEZPUi4uLiIgT25jZSB5b3UndmUgY29tcGxldGVkIHRoZXNlIHN0YXRlbWVudHMsIGNvcHkgYW5kIHBhc3RlIHRoZSByZXN0IG9mIHRoZSBVSSBmdW5jdGlvbiBmcm9tIGxhYiA4IHdoZXJlIEkndmUgaW5kaWNhdGVkLiAKCmBgYHtyfQp1aSA8LSBkYXNoYm9hcmRQYWdlKAogIAogICNSRVBMQUNFICdUSVRMRSBIRVJFJyBCRUxPVyBXSVRIIFlPVVIgT1dOIFRJVExFCiAgZGFzaGJvYXJkSGVhZGVyKHRpdGxlID0gIlRJVExFIEhFUkUiKSwKICAjUkVQTEFDRSAnVElUTEUgSEVSRScgQUJPVkUgV0lUSCBZT1VSIE9XTiBUSVRMRQogIAogIGRhc2hib2FyZFNpZGViYXIoCiAgICAgIHNpZGViYXJNZW51KAogICAgICAgIG1lbnVJdGVtKCJEYXNoYm9hcmQiLCB0YWJOYW1lID0gImRhc2hib2FyZCIsIGljb24gPSBpY29uKCJkYXNoYm9hcmQiKSksCiAgICAgICAgbWVudUl0ZW0oIkFib3V0IHRoZSBEYXRhIiwgdGFiTmFtZSA9ICJhYm91dCIsIGljb24gPSBpY29uKCJpbmZvLXNpZ24iKSkKICAgICAgKSwKICAgICAgc2VsZWN0SW5wdXQoaW5wdXRJZCA9ICJnZW9fdmFsIiwgbGFiZWwgPSAiU2VsZWN0IGFuIGdlb2dyYXBoeToiLCBjaG9pY2VzID0gZ2VvX2lucHV0X2Nob2ljZXMsIHNlbGVjdGVkID0gZ2VvX2lucHV0X2Nob2ljZXNbMV0pLAogICAgICAjQ09NTUVOVCBMSU5FIEJFTE9XIElGIFlPVSBETyBOT1QgSEFWRSBBIFRFTVBPUkFMIFZBUklBQkxFIElOIFlPVVIgREFUQUZSQU1FCiAgICAgIGRhdGVSYW5nZUlucHV0KGlucHV0SWQgPSAiZGF0ZV92YWwiLCBsYWJlbCA9ICJTZWxlY3QgYSBkYXRlIHJhbmdlOiIsIHN0YXJ0ID0gZGF0ZV9pbnB1dF9zdGFydCRkYXRlLCBlbmQgPSBkYXRlX2lucHV0X2VuZCRkYXRlKQogICAgICAjQ09NTUVOVCBMSU5FIEFCT1ZFIElGIFlPVSBETyBOT1QgSEFWRSBBIFRFTVBPUkFMIFZBUklBQkxFIElOIFlPVVIgREFUQUZSQU1FCiAgKSwKICAKICBkYXNoYm9hcmRCb2R5KAogICAgdGFncyRoZWFkKHRhZ3Mkc3R5bGUoSFRNTCgnLmNvbnRlbnQtd3JhcHBlciB7IG92ZXJmbG93OiBhdXRvOyB9JykpKSwKICAgIHRhYkl0ZW1zKAogICAgICB0YWJJdGVtKHRhYk5hbWUgPSAiZGFzaGJvYXJkIiwKICAgICAgICBpbmZvQm94T3V0cHV0KCJ2YWx1ZTEiLCB3aWR0aCA9IDQpLAogICAgICAgIGluZm9Cb3hPdXRwdXQoInZhbHVlMiIsIHdpZHRoID0gNCksCiAgICAgICAgaW5mb0JveE91dHB1dCgidmFsdWUzIiwgd2lkdGggPSA0KSwKICAgICAgICAKICAgICAgICAjQ09NUExFVEUgVEhFIFNUQVRFTUVOVCBCRUxPVyBGT1IgVkFMVUVCT1ggMSAKICAgICAgICBib3godGFncyRwKCJUaGUgbnVtYmVyIGFib3ZlIGRvZXMgbm90IGFjY291bnQgZm9yLi4uIiksIHdpZHRoID0gNCksCiAgICAgICAgCiAgICAgICAgI0NPTVBMRVRFIFRIRSBTVEFURU1FTlQgQkVMT1cgRk9SIFZBTFVFQk9YIDIgCiAgICAgICAgYm94KHRhZ3MkcCgiVGhlIG51bWJlciBhYm92ZSBkb2VzIG5vdCBhY2NvdW50IGZvci4uLiIpLCB3aWR0aCA9IDQpLAogICAgICAgCiAgICAgICAgI0NPTVBMRVRFIFRIRSBTVEFURU1FTlQgQkVMT1cgRk9SIFZBTFVFQk9YIDMgCiAgICAgICAgYm94KHRhZ3MkcCgiVGhlIG51bWJlciBhYm92ZSBkb2VzIG5vdCBhY2NvdW50IGZvciBnaXQsIHNlZCBxdWlhIGNvbnNlcXV1bnR1ciBtYWduaSBkb2xvcmVzIGVvcyBxdWkgcmF0aW9uZSB2b2x1cHRhdGVtIHNlcXVpIG5lc2NpdW50LiBOZXF1ZSBwb3JybyBxdWlzcXVhbSBlc3QsIHF1aSBkb2xvcmVtIGlwc3VtIHF1aWEgZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyLCBhZGlwaXNjaSB2ZWxpdCwgc2VkIHF1aWEgbm9uIG51bXF1YW0gZWkiKSwgd2lkdGggPSA0KSwKICAgICAKICAgICAgICBib3gocGxvdE91dHB1dCgicGxvdDEiKSksCiAgICAgICAgYm94KHBsb3RPdXRwdXQoInBsb3QyIikpLAogICAgICAgIAogICAgICAgICNDT01QTEVURSBUSEUgU1RBVEVNRU5UIEJFTE9XIEZPUiBQTE9UIDEgICAgICAgIAogICAgICAgIGJveCh0YWdzJHAoIlRoZSBwbG90IGFib3ZlIGRvZXMgbm90IGFjY291bnQgZm9yLi4uIiksIHdpZHRoID0gNiksCiAgICAgICAgCiAgICAgICAgI0NPTVBMRVRFIFRIRSBTVEFURU1FTlQgQkVMT1cgRk9SIFBMT1QgMiAgCiAgICAgICAgYm94KHRhZ3MkcCgiVGhlIHBsb3QgYWJvdmUgZG9lcyBub3QgYWNjb3VudCBmb3IuLi4iKSwgd2lkdGggPSA2KSwKICAgICAgICAKICAgICAgICBib3gocGxvdE91dHB1dCgicGxvdDMiKSksCiAgICAgICAgYm94KHBsb3RPdXRwdXQoInBsb3Q0IikpLAogICAgICAgIAogICAgICAgICNDT01QTEVURSBUSEUgU1RBVEVNRU5UIEJFTE9XIEZPUiBQTE9UIDMKICAgICAgICBib3godGFncyRwKCJUaGUgcGxvdCBhYm92ZSBkb2VzIG5vdCBhY2NvdW50IGZvci4uLiIpLCB3aWR0aCA9IDYpLAogICAgICAgIAogICAgICAgICNDT01QTEVURSBUSEUgU1RBVEVNRU5UIEJFTE9XIEZPUiBQTE9UIDQKICAgICAgICBib3godGFncyRwKCJUaGUgcGxvdCBhYm92ZSBkb2VzIG5vdCBhY2NvdW50IGZvci4uLiIpLCB3aWR0aCA9IDYpCiAgICAgICksCiAgICAgIAojPT09PT09PT09PT09PT09PT09PT09PQojQ09QWSBBTkQgUEFTVEUgVEhFIFJFTUFJTkRFUiBPRiBUSEUgVUkgRlVOQ1RJT04gRlJPTSBMQUIgOCBCRUxPVwojPT09PT09PT09PT09PT09PT09PT09PQogICAgICB0YWJJdGVtKHRhYk5hbWUgPSAiYWJvdXQiLAogICAgICAgICAgICAgIHRhZ3MkaDEoIkRhdGEgU291cmNlIiksCiAgICAgICAgICAgICAgICAjUkVQTEFDRSBURVhUIElOIFFVT1RBVElPTlMgQkVMT1cgV0lUSCBZT1VSIE9XTiBURVhUIEFCT1VUIFlPVVIgREFUQSdTIFNPVVJDRQogICAgICAgICAgICAgIHRhZ3MkcCgiU2VkIHV0IHBlcnNwaWNpYXRpcyB1bmRlIG9tbmlzIGlzdGUgbmF0dXMgZXJyb3Igc2l0IHZvbHVwdGF0ZW0gYWNjdXNhbnRpdW0gZG9sb3JlbXF1ZSBsYXVkYW50aXVtLCB0b3RhbSByZW0gYXBlcmlhbSwgZWFxdWUgaXBzYSBxdWFlIGFiIGlsbG8gaW52ZW50b3JlIHZlcml0YXRpcyBldCBxdWFzaSBhcmNoaXRlY3RvIGJlYXRhZSB2aXRhZSBkaWN0YSBzdW50IGV4cGxpY2Fiby4gTmVtbyBlbmltIGlwc2FtIHZvbHVwdGF0ZW0gcXVpYSB2b2x1cHRhcyBzaXQgYXNwZXJuYXR1ciBhdXQgb2RpdCBhdXQgZnVnaXQsIHNlZCBxdWlhIGNvbnNlcXV1bnR1ciBtYWduaSBkb2xvcmVzIGVvcyBxdWkgcmF0aW9uZSB2b2x1cHRhdGVtIHNlcXVpIG5lc2NpdW50LiBOZXF1ZSBwb3JybyBxdWlzcXVhbSBlc3QsIHF1aSBkb2xvcmVtIGlwc3VtIHF1aWEgZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyLCBhZGlwaXNjaSB2ZWxpdCwgc2VkIHF1aWEgbm9uIG51bXF1YW0gZWl1cyBtb2RpIHRlbXBvcmEgaW5jaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYW0gYWxpcXVhbSBxdWFlcmF0IHZvbHVwdGF0ZW0uIFV0IGVuaW0gYWQgbWluaW1hIHZlbmlhbSwgcXVpcyBub3N0cnVtIGV4ZXJjaXRhdGlvbmVtIHVsbGFtIGNvcnBvcmlzIHN1c2NpcGl0IGxhYm9yaW9zYW0sIG5pc2kgdXQgYWxpcXVpZCBleCBlYSBjb21tb2RpIGNvbnNlcXVhdHVyPyBRdWlzIGF1dGVtIHZlbCBldW0gaXVyZSByZXByZWhlbmRlcml0IHF1aSBpbiBlYSB2b2x1cHRhdGUgdmVsaXQgZXNzZSBxdWFtIG5paGlsIG1vbGVzdGlhZSBjb25zZXF1YXR1ciwgdmVsIGlsbHVtIHF1aSBkb2xvcmVtIGV1bSBmdWdpYXQgcXVvIHZvbHVwdGFzIG51bGxhIHBhcmlhdHVyPyIpLAogICAgICAgICAgICAgICNSRVBMQUNFIFRFWFQgSU4gUVVPVEFUSU9OUyBBQk9WRSBXSVRIIFlPVVIgT1dOIFRFWFQgQUJPVVQgWU9VUiBEQVRBJ1MgU09VUkNFCiAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgdGFncyRoMSgiRGF0YSBDb250ZXh0IiksCiAgICAgICAgICAgICAgI1JFUExBQ0UgVEVYVCBJTiBRVU9UQVRJT05TIEJFTE9XIFdJVEggWU9VUiBPV04gVEVYVCBBQk9VVCBZT1VSIERBVEEnUyBDT05URVhUCiAgICAgICAgICAgICAgdGFncyRwKCJTZWQgdXQgcGVyc3BpY2lhdGlzIHVuZGUgb21uaXMgaXN0ZSBuYXR1cyBlcnJvciBzaXQgdm9sdXB0YXRlbSBhY2N1c2FudGl1bSBkb2xvcmVtcXVlIGxhdWRhbnRpdW0sIHRvdGFtIHJlbSBhcGVyaWFtLCBlYXF1ZSBpcHNhIHF1YWUgYWIgaWxsbyBpbnZlbnRvcmUgdmVyaXRhdGlzIGV0IHF1YXNpIGFyY2hpdGVjdG8gYmVhdGFlIHZpdGFlIGRpY3RhIHN1bnQgZXhwbGljYWJvLiBOZW1vIGVuaW0gaXBzYW0gdm9sdXB0YXRlbSBxdWlhIHZvbHVwdGFzIHNpdCBhc3Blcm5hdHVyIGF1dCBvZGl0IGF1dCBmdWdpdCwgc2VkIHF1aWEgY29uc2VxdXVudHVyIG1hZ25pIGRvbG9yZXMgZW9zIHF1aSByYXRpb25lIHZvbHVwdGF0ZW0gc2VxdWkgbmVzY2l1bnQuIE5lcXVlIHBvcnJvIHF1aXNxdWFtIGVzdCwgcXVpIGRvbG9yZW0gaXBzdW0gcXVpYSBkb2xvciBzaXQgYW1ldCwgY29uc2VjdGV0dXIsIGFkaXBpc2NpIHZlbGl0LCBzZWQgcXVpYSBub24gbnVtcXVhbSBlaXVzIG1vZGkgdGVtcG9yYSBpbmNpZHVudCB1dCBsYWJvcmUgZXQgZG9sb3JlIG1hZ25hbSBhbGlxdWFtIHF1YWVyYXQgdm9sdXB0YXRlbS4gVXQgZW5pbSBhZCBtaW5pbWEgdmVuaWFtLCBxdWlzIG5vc3RydW0gZXhlcmNpdGF0aW9uZW0gdWxsYW0gY29ycG9yaXMgc3VzY2lwaXQgbGFib3Jpb3NhbSwgbmlzaSB1dCBhbGlxdWlkIGV4IGVhIGNvbW1vZGkgY29uc2VxdWF0dXI/IFF1aXMgYXV0ZW0gdmVsIGV1bSBpdXJlIHJlcHJlaGVuZGVyaXQgcXVpIGluIGVhIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIHF1YW0gbmloaWwgbW9sZXN0aWFlIGNvbnNlcXVhdHVyLCB2ZWwgaWxsdW0gcXVpIGRvbG9yZW0gZXVtIGZ1Z2lhdCBxdW8gdm9sdXB0YXMgbnVsbGEgcGFyaWF0dXI/IiksCiAgICAgICAgICAgICAgI1JFUExBQ0UgVEVYVCBJTiBRVU9UQVRJT05TIEFCT1ZFIFdJVEggWU9VUiBPV04gVEVYVCBBQk9VVCBZT1VSIERBVEEnUyBTT1VSQ0UKICAgICAgICAgICAgICAKICAgICAgICAgICAgICB0YWdzJGgxKCJJbnNpZ2h0cyIpLAogICAgICAgICAgICAgICNSRVBMQUNFIFRFWFQgSU4gUVVPVEFUSU9OUyBCRUxPVyBXSVRIIFlPVVIgT1dOIFRFWFQgQUJPVVQgWU9VUiBJTlNJR0hUUwogICAgICAgICAgICAgIHRhZ3MkcCgiU2VkIHV0IHBlcnNwaWNpYXRpcyB1bmRlIG9tbmlzIGlzdGUgbmF0dXMgZXJyb3Igc2l0IHZvbHVwdGF0ZW0gYWNjdXNhbnRpdW0gZG9sb3JlbXF1ZSBsYXVkYW50aXVtLCB0b3RhbSByZW0gYXBlcmlhbSwgZWFxdWUgaXBzYSBxdWFlIGFiIGlsbG8gaW52ZW50b3JlIHZlcml0YXRpcyBldCBxdWFzaSBhcmNoaXRlY3RvIGJlYXRhZSB2aXRhZSBkaWN0YSBzdW50IGV4cGxpY2Fiby4gTmVtbyBlbmltIGlwc2FtIHZvbHVwdGF0ZW0gcXVpYSB2b2x1cHRhcyBzaXQgYXNwZXJuYXR1ciBhdXQgb2RpdCBhdXQgZnVnaXQsIHNlZCBxdWlhIGNvbnNlcXV1bnR1ciBtYWduaSBkb2xvcmVzIGVvcyBxdWkgcmF0aW9uZSB2b2x1cHRhdGVtIHNlcXVpIG5lc2NpdW50LiBOZXF1ZSBwb3JybyBxdWlzcXVhbSBlc3QsIHF1aSBkb2xvcmVtIGlwc3VtIHF1aWEgZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyLCBhZGlwaXNjaSB2ZWxpdCwgc2VkIHF1aWEgbm9uIG51bXF1YW0gZWl1cyBtb2RpIHRlbXBvcmEgaW5jaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYW0gYWxpcXVhbSBxdWFlcmF0IHZvbHVwdGF0ZW0uIFV0IGVuaW0gYWQgbWluaW1hIHZlbmlhbSwgcXVpcyBub3N0cnVtIGV4ZXJjaXRhdGlvbmVtIHVsbGFtIGNvcnBvcmlzIHN1c2NpcGl0IGxhYm9yaW9zYW0sIG5pc2kgdXQgYWxpcXVpZCBleCBlYSBjb21tb2RpIGNvbnNlcXVhdHVyPyBRdWlzIGF1dGVtIHZlbCBldW0gaXVyZSByZXByZWhlbmRlcml0IHF1aSBpbiBlYSB2b2x1cHRhdGUgdmVsaXQgZXNzZSBxdWFtIG5paGlsIG1vbGVzdGlhZSBjb25zZXF1YXR1ciwgdmVsIGlsbHVtIHF1aSBkb2xvcmVtIGV1bSBmdWdpYXQgcXVvIHZvbHVwdGFzIG51bGxhIHBhcmlhdHVyPyIpLAogICAgICAgICAgICAgICNSRVBMQUNFIFRFWFQgSU4gUVVPVEFUSU9OUyBBQk9WRSBXSVRIIFlPVVIgT1dOIFRFWFQgQUJPVVQgWU9VUiBJTlNJR0hUUwogICAgICAgICAgICAgIAogICAgICAgICAgICAgIHRhZ3MkaDEoIktub3dsZWRnZSBHYXBzIiksCiAgICAgICAgICAgICAgI1JFUExBQ0UgVEVYVCBJTiBRVU9UQVRJT05TIEJFTE9XIFdJVEggWU9VUiBPV04gVEVYVCBBQk9VVCBZT1VSIEtOT1dMRURHRSBHQVBTCiAgICAgICAgICAgICAgdGFncyRwKCJTZWQgdXQgcGVyc3BpY2lhdGlzIHVuZGUgb21uaXMgaXN0ZSBuYXR1cyBlcnJvciBzaXQgdm9sdXB0YXRlbSBhY2N1c2FudGl1bSBkb2xvcmVtcXVlIGxhdWRhbnRpdW0sIHRvdGFtIHJlbSBhcGVyaWFtLCBlYXF1ZSBpcHNhIHF1YWUgYWIgaWxsbyBpbnZlbnRvcmUgdmVyaXRhdGlzIGV0IHF1YXNpIGFyY2hpdGVjdG8gYmVhdGFlIHZpdGFlIGRpY3RhIHN1bnQgZXhwbGljYWJvLiBOZW1vIGVuaW0gaXBzYW0gdm9sdXB0YXRlbSBxdWlhIHZvbHVwdGFzIHNpdCBhc3Blcm5hdHVyIGF1dCBvZGl0IGF1dCBmdWdpdCwgc2VkIHF1aWEgY29uc2VxdXVudHVyIG1hZ25pIGRvbG9yZXMgZW9zIHF1aSByYXRpb25lIHZvbHVwdGF0ZW0gc2VxdWkgbmVzY2l1bnQuIE5lcXVlIHBvcnJvIHF1aXNxdWFtIGVzdCwgcXVpIGRvbG9yZW0gaXBzdW0gcXVpYSBkb2xvciBzaXQgYW1ldCwgY29uc2VjdGV0dXIsIGFkaXBpc2NpIHZlbGl0LCBzZWQgcXVpYSBub24gbnVtcXVhbSBlaXVzIG1vZGkgdGVtcG9yYSBpbmNpZHVudCB1dCBsYWJvcmUgZXQgZG9sb3JlIG1hZ25hbSBhbGlxdWFtIHF1YWVyYXQgdm9sdXB0YXRlbS4gVXQgZW5pbSBhZCBtaW5pbWEgdmVuaWFtLCBxdWlzIG5vc3RydW0gZXhlcmNpdGF0aW9uZW0gdWxsYW0gY29ycG9yaXMgc3VzY2lwaXQgbGFib3Jpb3NhbSwgbmlzaSB1dCBhbGlxdWlkIGV4IGVhIGNvbW1vZGkgY29uc2VxdWF0dXI/IFF1aXMgYXV0ZW0gdmVsIGV1bSBpdXJlIHJlcHJlaGVuZGVyaXQgcXVpIGluIGVhIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIHF1YW0gbmloaWwgbW9sZXN0aWFlIGNvbnNlcXVhdHVyLCB2ZWwgaWxsdW0gcXVpIGRvbG9yZW0gZXVtIGZ1Z2lhdCBxdW8gdm9sdXB0YXMgbnVsbGEgcGFyaWF0dXI/IikKICAgICAgICAgICAgICAjUkVQTEFDRSBURVhUIElOIFFVT1RBVElPTlMgQUJPVkUgV0lUSCBZT1VSIE9XTiBURVhUIEFCT1VUIFlPVVIgS05PV0xFREdFIEdBUFMKICAgICAgKQogICAgKQogICkKKQogIAojPT09PT09PT09PT09PT09PT09PT09PQojQ09QWSBBTkQgUEFTVEUgVEhFIFJFTUFJTkRFUiBPRiBUSEUgVUkgRlVOQ1RJT04gRlJPTSBMQUIgOCBBQk9WRQojPT09PT09PT09PT09PT09PT09PT09PQpgYGAKCldlIHdvbid0IGJlIHRvdWNoaW5nIHRoZSBzZXJ2ZXIgZnVuY3Rpb24gdGhpcyB3ZWVrLiBZb3UgY2FuIGNvcHkgYW5kIHBhc3RlIHlvdXJzIGZyb20gTGFiIDcgdG8gcmVwbGFjZSBteSBjb2RlIGJlbG93LiAKCmBgYHtyfQojPT09PT09PT09PT09PT09PT09PT09PQojQ09QWSBBTkQgUEFTVEUgVEhFIFNFUlZFUiBGVU5DVElPTiBGUk9NIExBQiA3IEJFTE9XCiM9PT09PT09PT09PT09PT09PT09PT09CgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIAogIG91dHB1dCR2YWx1ZTEgPC0gcmVuZGVySW5mb0JveCh7CiAgICBxdWFudF9pbnNpZ2h0MSA8LQogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lICAgICAgCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBGVU5DVElPTiBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICAgICAgc3VtbWFyaXplKG1lZGlhbl92YWx1ZSA9IG1lZGlhbihCRURTLCBuYS5ybSA9IFRSVUUpKQogICAgCiAgICAjUkVQTEFDRSAnRklMTCBERVNDUklQVElPTiBIRVJFJyBCRUxPVyBXSVRIIFlPVVIgT1dOIERFU0NSSVBUSU9OCiAgICBpbmZvQm94KHF1YW50X2luc2lnaHQxLCdGSUxMIERFU0NSSVBUSU9OIEhFUkUnLCBpY29uID0gaWNvbigic3RhdHMiLCBsaWI9J2dseXBoaWNvbicpLCBjb2xvciA9ICJwdXJwbGUiKQogIH0pCiAgCiAgb3V0cHV0JHZhbHVlMiA8LSByZW5kZXJJbmZvQm94KHsKICAgIHF1YW50X2luc2lnaHQyIDwtIAogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBGVU5DVElPTiBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICAgICAgc3VtbWFyaXplKG1lZGlhbl92YWx1ZSA9IG1lZGlhbihCRURTLCBuYS5ybSA9IFRSVUUpKQogICAgCiAgICAjUkVQTEFDRSAnRklMTCBERVNDUklQVElPTiBIRVJFJyBCRUxPVyBXSVRIIFlPVVIgT1dOIERFU0NSSVBUSU9OCiAgICBpbmZvQm94KHF1YW50X2luc2lnaHQyLCdGSUxMIERFU0NSSVBUSU9OIEhFUkUnLCBpY29uID0gaWNvbigic3RhdHMiLCBsaWI9J2dseXBoaWNvbicpLCBjb2xvciA9ICJwdXJwbGUiKQogIH0pCiAgCiAgb3V0cHV0JHZhbHVlMyA8LSByZW5kZXJJbmZvQm94KHsKICAgIHF1YW50X2luc2lnaHQzIDwtIAogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBGVU5DVElPTiBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICAgICAgc3VtbWFyaXplKG1lZGlhbl92YWx1ZSA9IG1lZGlhbihCRURTLCBuYS5ybSA9IFRSVUUpKQoKICAgICNSRVBMQUNFICdGSUxMIERFU0NSSVBUSU9OIEhFUkUnIEJFTE9XIFdJVEggWU9VUiBPV04gREVTQ1JJUFRJT04KICAgIGluZm9Cb3gocXVhbnRfaW5zaWdodDMsJ0ZJTEwgREVTQ1JJUFRJT04gSEVSRScsIGljb24gPSBpY29uKCJzdGF0cyIsIGxpYj0nZ2x5cGhpY29uJyksIGNvbG9yID0gInB1cnBsZSIpCiAgfSkKICAKICBvdXRwdXQkcGxvdDEgPC0gcmVuZGVyUGxvdCh7CiAgICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICAgIGhvc3BpdGFscyAlPiUgCiAgICAjUkVQTEFDRSBTVEFURSBXSVRIIFlPVVIgT1dOIEdFT0dSQVBISUMgVkFSSUFCTEUgQU5EIFNPVVJDRURBVEUgV0lUSCBZT1VSIE9XTiBURU1QT1JBTCBWQVJJQUJMRQogICAgICBmaWx0ZXIoCiAgICAgICAgU1RBVEUgPT0gaW5wdXQkZ2VvX3ZhbCAmIAogICAgICAgIFNPVVJDRURBVEUgPiBpbnB1dCRkYXRlX3ZhbFsxXSAmCiAgICAgICAgU09VUkNFREFURSA8IGlucHV0JGRhdGVfdmFsWzJdCiAgICAgICAgKSAlPiUKICAgICNDT1BZIEFORCBQQVNURSBZT1VSIFBMT1QgSEVSRSBGUk9NIExBQiA2CiAgICAgIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICAgICAgZ2dwbG90KGFlcyh4ID0gVFlQRSkpICsgCiAgICAgIGdlb21fYmFyKCkgKwogICAgICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSAKICB9KQogIAogIG91dHB1dCRwbG90MiA8LSByZW5kZXJQbG90KHsKICAgICNSRVBMQUNFIGhvc3BpdGFscyBCRUxPVyBXSVRIIFlPVVIgT1dOIERBVEFGUkFNRQogICAgaG9zcGl0YWxzICU+JSAKICAgICNSRVBMQUNFIFNUQVRFIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRSBBTkQgU09VUkNFREFURSBXSVRIIFlPVVIgT1dOIFRFTVBPUkFMIFZBUklBQkxFCiAgICAgIGZpbHRlcigKICAgICAgICBTVEFURSA9PSBpbnB1dCRnZW9fdmFsICYgCiAgICAgICAgU09VUkNFREFURSA+IGlucHV0JGRhdGVfdmFsWzFdICYKICAgICAgICBTT1VSQ0VEQVRFIDwgaW5wdXQkZGF0ZV92YWxbMl0KICAgICAgICApICU+JQogICAgI0NPUFkgQU5EIFBBU1RFIFlPVVIgUExPVCBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogICAgICBnZ3Bsb3QoYWVzKHggPSBUWVBFKSkgKyAKICAgICAgZ2VvbV9iYXIoKSArCiAgICAgIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBUeXBlIiwgeCA9ICJUeXBlIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbHMiKSArIAogICAgICB0aGVtZV9idygpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpIAogIH0pCiAgCiAgb3V0cHV0JHBsb3QzIDwtIHJlbmRlclBsb3QoewogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBQTE9UIEhFUkUgRlJPTSBMQUIgNgogICAgICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgICAgIGdncGxvdChhZXMoeCA9IFRZUEUpKSArIAogICAgICBnZW9tX2JhcigpICsKICAgICAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIpICsgCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgCiAgfSkKICAKICBvdXRwdXQkcGxvdDQgPC0gcmVuZGVyUGxvdCh7CiAgICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICAgIGhvc3BpdGFscyAlPiUgCiAgICAjUkVQTEFDRSBTVEFURSBXSVRIIFlPVVIgT1dOIEdFT0dSQVBISUMgVkFSSUFCTEUgQU5EIFNPVVJDRURBVEUgV0lUSCBZT1VSIE9XTiBURU1QT1JBTCBWQVJJQUJMRQogICAgICBmaWx0ZXIoCiAgICAgICAgU1RBVEUgPT0gaW5wdXQkZ2VvX3ZhbCAmIAogICAgICAgIFNPVVJDRURBVEUgPiBpbnB1dCRkYXRlX3ZhbFsxXSAmCiAgICAgICAgU09VUkNFREFURSA8IGlucHV0JGRhdGVfdmFsWzJdCiAgICAgICAgKSAlPiUKICAgICNDT1BZIEFORCBQQVNURSBZT1VSIFBMT1QgSEVSRSBGUk9NIExBQiA2CiAgICAgIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICAgICAgZ2dwbG90KGFlcyh4ID0gVFlQRSkpICsgCiAgICAgIGdlb21fYmFyKCkgKwogICAgICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSAKICB9KQp9IAojPT09PT09PT09PT09PT09PT09PT09PQojQ09QWSBBTkQgUEFTVEUgVEhFIFNFUlZFUiBGVU5DVElPTiBGUk9NIExBQiA3IEFCT1ZFCiM9PT09PT09PT09PT09PT09PT09PT09CmBgYAoKYGBge3J9CnNoaW55QXBwKHVpLCBzZXJ2ZXIpCmBgYAoK