Instructions and Overview

In this lab, you will refer to the plots you created in each of your previous labs to summarize insights and critiques of the dataset you’ve been analyzing. This text will be added to an “About” page on your data dashboard.

Getting Started

Load the relevant libraries

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

Import and clean example datasets

hospitals <- read.csv("https://opendata.arcgis.com/datasets/6ac5e325468c4cb9b905f1728d6fbf0f_0.csv", stringsAsFactors = FALSE)

world_health_econ <- read.csv("https://raw.githubusercontent.com/lindsaypoirier/STS-115/master/datasets/world_health_econ.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.

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

Summarize Insights

In about 500 words, describe how your understanding of your topic has advanced as a result of your research. Reference specific statistics, plots, or tables in this section to communicate what key insights you were able to draw from the data. Some things to consider as you are writing this section:

  1. Be sure to contextualize your findings in the appropriate temporal and geographic context. If your dataset is about the average age of homeowners, and it only spans from 2012-2015 and covers the state of CA:
  • Imprecise: “There are more general acute care hospitals than any other hospital.”
  • Better: “Based on data aggregated from government sources by Oak Ridge National Laboratory since 2012, there are more general acute care hospitals in the United States than any other type of hospital.”
  1. Make a clear distinction between what the data empirically shows you and how you interpret the results. Again, imagine that your dataset is about the average age of homeowners:
  • Imprecise: “This data indicates that many hospitals do not have enough beds to take on new patients.”
  • Better: “According to this data, the median number of beds at general acute hospitals in the US is 139. Comparing this to the case rates in the US since January, this suggests that many hospitals will not have enough beds available to take on the influx in patients.”
  1. Consider your data issues:
  • Imprecise: “From January to present the growth of the Covid-19 cases has increased most dramatically in the US.”
  • Better: “From January to present the growth of the Covid-19 cases has increased most dramatically in the US. However, since the case data is only as accurate as the portion of the population being test and countries are testing at different capacities, this measure may be imprecise.”
Fill your response here. 

Characterize Knowledge Gaps

In what ways might the data in your dataset be inaccurate? Describe in specific detail how these inaccuracies might affect your data analysis. Reference a specific analysis you’ve completed (either through transformation or plotting), and describe how this issue might impact how you interpret your data analysis.

Fill your response here. 

In what ways might your dataset be incomplete or non-representative of the extent of the issues? Describe in specific detail how the data’s incompleteness might affect your data analysis. Reference a specific analysis you’ve completed (either through transformation or plotting), and describe how this issue might impact how you interpret your data analysis.

Fill your response here. 

In what ways have you had to make assumptions in order to glean insights from your dataset? Describe in specific detail how these assumptions might affect your data analysis. Reference a specific analysis you’ve completed (either through transformation or plotting), and describe how this issue might impact how you interpret your data analysis.

Fill your response here. 

What don’t you know about your data domain that has made it difficult to interpret the data? Describe in specific detail how these cultural gaps might affect your data analysis. Reference a specific analysis you’ve completed (either through transformation or plotting), and describe how this issue might impact how you interpret your data analysis.

Fill your response here. 

BONUS (+1): Using the functions we have learned in R, create one plot that graphically represents one of the issues that you outlined above. It might be a plot that displays the sampling gaps. It might be a plot that showcases where data quality issues are present in your data. It might be a set of plots that show how different results are produced when different assumptions are made. Write a caption for this plot, explaining how it illustrates potential issues with your data analysis.

rr #Fill code here.

Continue your shiny app.

Now we will aggregate all of the text that you produced above, along with text that you produced in lab 3 into an “About the Data” page on your Shiny App. Follow the instructions below to fill your text into a new page created on the front end 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
#======================

rr geo_input_choices <- hospitals %>% select(STATE) %>% distinct() %>% arrange(STATE) date_input_start <- hospitals %>% summarize(date = min(SOURCEDATE)) date_input_end <- hospitals %>% summarize(date = max(SOURCEDATE))

ui <- dashboardPage(

#REPLACE ‘TITLE HERE’ BELOW WITH YOUR OWN TITLE dashboardHeader(title = HERE), #REPLACE ‘TITLE HERE’ ABOVE WITH YOUR OWN TITLE

dashboardSidebar( sidebarMenu( menuItem(, tabName = , icon = icon()), menuItem(the Data, tabName = , icon = icon(-sign)) ), selectInput(inputId = _val, label = an geography:, choices = geo_input_choices, selected = geo_input_choices[1]), dateRangeInput(inputId = \date_val, label = a date range:, start = date_input_start\(date, end = date_input_end\)date) ),

dashboardBody( tabItems( tabItem(tabName = , infoBoxOutput(1, width = 4), infoBoxOutput(2, width = 4), infoBoxOutput(3, width = 4),

    box(plotOutput(\plot1\)),
    box(plotOutput(\plot2\)),
    box(plotOutput(\plot3\)),
    box(plotOutput(\plot4\))
  ),
  tabItem(tabName = \about\,
          tags$h1(\Data Source\),
          tags$p(\Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium

```

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

rr server <- function(input, output) {

output$value1 <- renderInfoBox({ quant_insight1 <- 0 #Replace ‘0’ above with the code for one of the values you calculated above. Replace ‘FILL DESCRIPTION HERE’ with a brief description of this number.
infoBox(quant_insight1,‘FILL DESCRIPTION HERE’, icon = icon(, lib=‘glyphicon’), color = ) })

output$value2 <- renderInfoBox({ quant_insight2 <- 0 #Replace ‘0’ above with the code for one of the values you calculated above. Replace ‘FILL DESCRIPTION HERE’ with a brief description of this number.
infoBox(quant_insight2,‘FILL DESCRIPTION HERE’, icon = icon(, lib=‘glyphicon’), color = ) })

output$value3 <- renderInfoBox({ quant_insight3 <- 0 #Replace ‘0’ above with the code for one of the values you calculated above. Replace ‘FILL DESCRIPTION HERE’ with a brief description of this number.
infoBox(quant_insight3,‘FILL DESCRIPTION HERE’, icon = icon(, lib=‘glyphicon’), color = ) })

output\(plot1 <- renderPlot({ hospitals %>% filter( STATE == input\)geo_val & SOURCEDATE > input\(date_val[1] & SOURCEDATE < input\)date_val[2] ) %>% ggplot(aes(x = TYPE)) + geom_bar() #Replace plot above with your own plot.

})

output\(plot2 <- renderPlot({ hospitals %>% filter( STATE == input\)geo_val & SOURCEDATE > input\(date_val[1] & SOURCEDATE < input\)date_val[2] ) %>% ggplot(aes(x = TYPE)) + geom_bar() #Replace plot above with your own plot. })

output\(plot3 <- renderPlot({ hospitals %>% filter( STATE == input\)geo_val & SOURCEDATE > input\(date_val[1] & SOURCEDATE < input\)date_val[2] ) %>% ggplot(aes(x = TYPE)) + geom_bar() #Replace plot above with your own plot.

})

output\(plot4 <- renderPlot({ hospitals %>% filter( STATE == input\)geo_val & SOURCEDATE > input\(date_val[1] & SOURCEDATE < input\)date_val[2] ) %>% ggplot(aes(x = TYPE)) + geom_bar() #Replace plot above with your own plot. })

}

rr shinyApp(ui, server)


Listening on http://127.0.0.1:3920
NA
LS0tCnRpdGxlOiAiTGFiIDggLSBTdW1tYXJpemluZyBJbnNpZ2h0cyBhbmQgRGF0YSBHYXBzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICczJwplZGl0b3Jfb3B0aW9uczoKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKIyMgSW5zdHJ1Y3Rpb25zIGFuZCBPdmVydmlldwoKSW4gdGhpcyBsYWIsIHlvdSB3aWxsIHJlZmVyIHRvIHRoZSBwbG90cyB5b3UgY3JlYXRlZCBpbiBlYWNoIG9mIHlvdXIgcHJldmlvdXMgbGFicyB0byBzdW1tYXJpemUgaW5zaWdodHMgYW5kIGNyaXRpcXVlcyBvZiB0aGUgZGF0YXNldCB5b3UndmUgYmVlbiBhbmFseXppbmcuIFRoaXMgdGV4dCB3aWxsIGJlIGFkZGVkIHRvIGFuICJBYm91dCIgcGFnZSBvbiB5b3VyIGRhdGEgZGFzaGJvYXJkLiAgCgojIyBHZXR0aW5nIFN0YXJ0ZWQKCiMjIyBMb2FkIHRoZSByZWxldmFudCBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShzaGlueSkKbGlicmFyeShzaGlueWRhc2hib2FyZCkKbGlicmFyeShzaGlueVdpZGdldHMpCmBgYAoKIyMjIEltcG9ydCBhbmQgY2xlYW4gZXhhbXBsZSBkYXRhc2V0cyAKCmBgYHtyfQpob3NwaXRhbHMgPC0gcmVhZC5jc3YoImh0dHBzOi8vb3BlbmRhdGEuYXJjZ2lzLmNvbS9kYXRhc2V0cy82YWM1ZTMyNTQ2OGM0Y2I5YjkwNWYxNzI4ZDZmYmYwZl8wLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCndvcmxkX2hlYWx0aF9lY29uIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbGluZHNheXBvaXJpZXIvU1RTLTExNS9tYXN0ZXIvZGF0YXNldHMvd29ybGRfaGVhbHRoX2Vjb24uY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKY2FzZXMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DU1NFR0lTYW5kRGF0YS9DT1ZJRC0xOS9tYXN0ZXIvY3NzZV9jb3ZpZF8xOV9kYXRhL2Nzc2VfY292aWRfMTlfdGltZV9zZXJpZXMvdGltZV9zZXJpZXNfY292aWQxOV9jb25maXJtZWRfZ2xvYmFsLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCiNEbyBub3Qgd29ycnkgYWJvdXQgdGhpcyBsaW5lIG9mIGNvZGUgZm9yIG5vdy4gU2luY2UgdGhlIGNhc2VzIGRhdGEgZ2V0cyBhcHBlbmRlZCBldmVyeSBkYXkgd2l0aCBhIG5ldyBjb2x1bW4gcmVwcmVzZW50aW5nIHRoYXQgZGF5J3MgY2FzZSBjb3VudHMsIGlmIHdlIHdhbnQgdGhlIHRvdGFsIGNhc2VzIHBlciBjb3VudHJ5LCB3ZSBuZWVkIHRvIGFkZCB1cCBhbGwgb2YgdGhlIHByZXZpb3VzIGRheSdzIGNvdW50cyBpbnRvIGEgbmV3IGNvbHVtbi4gVGhlIGNvbHVtbiBiZWxvdyBkb2VzIHRoaXMgZm9yIHVzLiAKY2FzZXMgPC0gCiAgY2FzZXMgJT4lIAogIG11dGF0ZShUb3RhbC5DYXNlcyA9IAogICAgICAgICAgIGNhc2VzICU+JSAKICAgICAgICAgICBzZWxlY3Qoc3RhcnRzX3dpdGgoIlgiKSkgJT4lIAogICAgICAgICAgIHJvd1N1bXMoKQogICAgICAgICApICU+JQogIHNlbGVjdChQcm92aW5jZS5TdGF0ZSwgQ291bnRyeS5SZWdpb24sIFRvdGFsLkNhc2VzKQoKaG9zcGl0YWxzJFpJUCA8LSBhcy5jaGFyYWN0ZXIoaG9zcGl0YWxzJFpJUCkKCmhvc3BpdGFscyRaSVAgPC0gc3RyX3BhZChob3NwaXRhbHMkWklQLCA1LCBwYWQgPSAiMCIpIAoKaXMubmEoaG9zcGl0YWxzKSA8LSBob3NwaXRhbHMgPT0gIk5PVCBBVkFJTEFCTEUiCmlzLm5hKGhvc3BpdGFscykgPC0gaG9zcGl0YWxzID09IC05OTkKaXMubmEoY2FzZXMpIDwtIGNhc2VzID09ICIiCgpob3NwaXRhbHMkU09VUkNFREFURSA8LSB5bWRfaG1zKGhvc3BpdGFscyRTT1VSQ0VEQVRFKQpob3NwaXRhbHMkVkFMX0RBVEUgPC0geW1kX2htcyhob3NwaXRhbHMkVkFMX0RBVEUpCmBgYAoKIyMjIEltcG9ydCBhbmQgY2xlYW4geW91ciBkYXRhc2V0LiAKCmBgYHtyfQojQ29weSBhbmQgcGFzdGUgcmVsZXZhbnQgY29kZSBmcm9tIExhYiA0IHRvIGltcG9ydCB5b3VyIGRhdGEgaGVyZS4gCgojQ29weSBhbmQgcGFzdGUgcmVsZXZhbnQgY29kZSBmcm9tIExhYiA0IHRvIGNsZWFuIHlvdXIgZGF0YSBoZXJlLiBUaGlzIGluY2x1ZGVzIGFueSByb3cgYmluZGluZywgY2hhcmFjdGVyIHJlbW92YWxzLCBjb252ZXJpb25zIGluIHZhcmlhYmxlIHR5cGUsIGRhdGUgZm9ybWF0dGluZywgb3IgTkEgY29udmVyc2lvbnMuIApgYGAKCiMjIFN1bW1hcml6ZSBJbnNpZ2h0cwoKSW4gYWJvdXQgNTAwIHdvcmRzLCBkZXNjcmliZSBob3cgeW91ciB1bmRlcnN0YW5kaW5nIG9mIHlvdXIgdG9waWMgaGFzIGFkdmFuY2VkIGFzIGEgcmVzdWx0IG9mIHlvdXIgcmVzZWFyY2guIFJlZmVyZW5jZSBzcGVjaWZpYyBzdGF0aXN0aWNzLCBwbG90cywgb3IgdGFibGVzIGluIHRoaXMgc2VjdGlvbiB0byBjb21tdW5pY2F0ZSB3aGF0IGtleSBpbnNpZ2h0cyB5b3Ugd2VyZSBhYmxlIHRvIGRyYXcgZnJvbSB0aGUgZGF0YS4gU29tZSB0aGluZ3MgdG8gY29uc2lkZXIgYXMgeW91IGFyZSB3cml0aW5nIHRoaXMgc2VjdGlvbjoKCjEuIEJlIHN1cmUgdG8gY29udGV4dHVhbGl6ZSB5b3VyIGZpbmRpbmdzIGluIHRoZSBhcHByb3ByaWF0ZSB0ZW1wb3JhbCBhbmQgZ2VvZ3JhcGhpYyBjb250ZXh0LiBJZiB5b3VyIGRhdGFzZXQgaXMgYWJvdXQgdGhlIGF2ZXJhZ2UgYWdlIG9mIGhvbWVvd25lcnMsIGFuZCBpdCBvbmx5IHNwYW5zIGZyb20gMjAxMi0yMDE1IGFuZCBjb3ZlcnMgdGhlIHN0YXRlIG9mIENBOgogICogSW1wcmVjaXNlOiAiVGhlcmUgYXJlIG1vcmUgZ2VuZXJhbCBhY3V0ZSBjYXJlIGhvc3BpdGFscyB0aGFuIGFueSBvdGhlciBob3NwaXRhbC4iCiAgKiBCZXR0ZXI6ICJCYXNlZCBvbiBkYXRhIGFnZ3JlZ2F0ZWQgZnJvbSBnb3Zlcm5tZW50IHNvdXJjZXMgYnkgT2FrIFJpZGdlIE5hdGlvbmFsIExhYm9yYXRvcnkgc2luY2UgMjAxMiwgdGhlcmUgYXJlIG1vcmUgZ2VuZXJhbCBhY3V0ZSBjYXJlIGhvc3BpdGFscyBpbiB0aGUgVW5pdGVkIFN0YXRlcyB0aGFuIGFueSBvdGhlciB0eXBlIG9mIGhvc3BpdGFsLiIKMi4gTWFrZSBhIGNsZWFyIGRpc3RpbmN0aW9uIGJldHdlZW4gd2hhdCB0aGUgZGF0YSBlbXBpcmljYWxseSBzaG93cyB5b3UgYW5kIGhvdyB5b3UgaW50ZXJwcmV0IHRoZSByZXN1bHRzLiBBZ2FpbiwgaW1hZ2luZSB0aGF0IHlvdXIgZGF0YXNldCBpcyBhYm91dCB0aGUgYXZlcmFnZSBhZ2Ugb2YgaG9tZW93bmVyczoKICAqIEltcHJlY2lzZTogIlRoaXMgZGF0YSBpbmRpY2F0ZXMgdGhhdCBtYW55IGhvc3BpdGFscyBkbyBub3QgaGF2ZSBlbm91Z2ggYmVkcyB0byB0YWtlIG9uIG5ldyBwYXRpZW50cy4iIAogICogQmV0dGVyOiAiQWNjb3JkaW5nIHRvIHRoaXMgZGF0YSwgdGhlIG1lZGlhbiBudW1iZXIgb2YgYmVkcyBhdCBnZW5lcmFsIGFjdXRlIGhvc3BpdGFscyBpbiB0aGUgVVMgaXMgMTM5LiBDb21wYXJpbmcgdGhpcyB0byB0aGUgY2FzZSByYXRlcyBpbiB0aGUgVVMgc2luY2UgSmFudWFyeSwgdGhpcyBzdWdnZXN0cyB0aGF0IG1hbnkgaG9zcGl0YWxzIHdpbGwgbm90IGhhdmUgZW5vdWdoIGJlZHMgYXZhaWxhYmxlIHRvIHRha2Ugb24gdGhlIGluZmx1eCBpbiBwYXRpZW50cy4iCjMuIENvbnNpZGVyIHlvdXIgZGF0YSBpc3N1ZXM6CiAgKiBJbXByZWNpc2U6ICJGcm9tIEphbnVhcnkgdG8gcHJlc2VudCB0aGUgZ3Jvd3RoIG9mIHRoZSBDb3ZpZC0xOSBjYXNlcyBoYXMgaW5jcmVhc2VkIG1vc3QgZHJhbWF0aWNhbGx5IGluIHRoZSBVUy4iCiAgKiBCZXR0ZXI6ICJGcm9tIEphbnVhcnkgdG8gcHJlc2VudCB0aGUgZ3Jvd3RoIG9mIHRoZSBDb3ZpZC0xOSBjYXNlcyBoYXMgaW5jcmVhc2VkIG1vc3QgZHJhbWF0aWNhbGx5IGluIHRoZSBVUy4gSG93ZXZlciwgc2luY2UgdGhlIGNhc2UgZGF0YSBpcyBvbmx5IGFzIGFjY3VyYXRlIGFzIHRoZSBwb3J0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIGJlaW5nIHRlc3QgYW5kIGNvdW50cmllcyBhcmUgdGVzdGluZyBhdCBkaWZmZXJlbnQgY2FwYWNpdGllcywgdGhpcyBtZWFzdXJlIG1heSBiZSBpbXByZWNpc2UuIgoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCiMjIENoYXJhY3Rlcml6ZSBLbm93bGVkZ2UgR2FwcwoKSW4gd2hhdCB3YXlzIG1pZ2h0IHRoZSBkYXRhIGluIHlvdXIgZGF0YXNldCBiZSBpbmFjY3VyYXRlPyBEZXNjcmliZSBpbiBzcGVjaWZpYyBkZXRhaWwgaG93IHRoZXNlIGluYWNjdXJhY2llcyBtaWdodCBhZmZlY3QgeW91ciBkYXRhIGFuYWx5c2lzLiBSZWZlcmVuY2UgYSBzcGVjaWZpYyBhbmFseXNpcyB5b3UndmUgY29tcGxldGVkIChlaXRoZXIgdGhyb3VnaCB0cmFuc2Zvcm1hdGlvbiBvciBwbG90dGluZyksIGFuZCBkZXNjcmliZSBob3cgdGhpcyBpc3N1ZSBtaWdodCBpbXBhY3QgaG93IHlvdSBpbnRlcnByZXQgeW91ciBkYXRhIGFuYWx5c2lzLgoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCkluIHdoYXQgd2F5cyBtaWdodCB5b3VyIGRhdGFzZXQgYmUgaW5jb21wbGV0ZSBvciBub24tcmVwcmVzZW50YXRpdmUgb2YgdGhlIGV4dGVudCBvZiB0aGUgaXNzdWVzPyBEZXNjcmliZSBpbiBzcGVjaWZpYyBkZXRhaWwgaG93IHRoZSBkYXRhJ3MgaW5jb21wbGV0ZW5lc3MgbWlnaHQgYWZmZWN0IHlvdXIgZGF0YSBhbmFseXNpcy4gIFJlZmVyZW5jZSBhIHNwZWNpZmljIGFuYWx5c2lzIHlvdSd2ZSBjb21wbGV0ZWQgKGVpdGhlciB0aHJvdWdoIHRyYW5zZm9ybWF0aW9uIG9yIHBsb3R0aW5nKSwgYW5kIGRlc2NyaWJlIGhvdyB0aGlzIGlzc3VlIG1pZ2h0IGltcGFjdCBob3cgeW91IGludGVycHJldCB5b3VyIGRhdGEgYW5hbHlzaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKSW4gd2hhdCB3YXlzIGhhdmUgeW91IGhhZCB0byBtYWtlIGFzc3VtcHRpb25zIGluIG9yZGVyIHRvIGdsZWFuIGluc2lnaHRzIGZyb20geW91ciBkYXRhc2V0PyBEZXNjcmliZSBpbiBzcGVjaWZpYyBkZXRhaWwgaG93IHRoZXNlIGFzc3VtcHRpb25zIG1pZ2h0IGFmZmVjdCB5b3VyIGRhdGEgYW5hbHlzaXMuICBSZWZlcmVuY2UgYSBzcGVjaWZpYyBhbmFseXNpcyB5b3UndmUgY29tcGxldGVkIChlaXRoZXIgdGhyb3VnaCB0cmFuc2Zvcm1hdGlvbiBvciBwbG90dGluZyksIGFuZCBkZXNjcmliZSBob3cgdGhpcyBpc3N1ZSBtaWdodCBpbXBhY3QgaG93IHlvdSBpbnRlcnByZXQgeW91ciBkYXRhIGFuYWx5c2lzLgoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCldoYXQgZG9u4oCZdCB5b3Uga25vdyBhYm91dCB5b3VyIGRhdGEgZG9tYWluIHRoYXQgaGFzIG1hZGUgaXQgZGlmZmljdWx0IHRvIGludGVycHJldCB0aGUgZGF0YT8gRGVzY3JpYmUgaW4gc3BlY2lmaWMgZGV0YWlsIGhvdyB0aGVzZSBjdWx0dXJhbCBnYXBzIG1pZ2h0IGFmZmVjdCB5b3VyIGRhdGEgYW5hbHlzaXMuICBSZWZlcmVuY2UgYSBzcGVjaWZpYyBhbmFseXNpcyB5b3UndmUgY29tcGxldGVkIChlaXRoZXIgdGhyb3VnaCB0cmFuc2Zvcm1hdGlvbiBvciBwbG90dGluZyksIGFuZCBkZXNjcmliZSBob3cgdGhpcyBpc3N1ZSBtaWdodCBpbXBhY3QgaG93IHlvdSBpbnRlcnByZXQgeW91ciBkYXRhIGFuYWx5c2lzLgoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCkJPTlVTICgrMSk6IFVzaW5nIHRoZSBmdW5jdGlvbnMgd2UgaGF2ZSBsZWFybmVkIGluIFIsIGNyZWF0ZSBvbmUgcGxvdCB0aGF0IGdyYXBoaWNhbGx5IHJlcHJlc2VudHMgb25lIG9mIHRoZSBpc3N1ZXMgdGhhdCB5b3Ugb3V0bGluZWQgYWJvdmUuIEl0IG1pZ2h0IGJlIGEgcGxvdCB0aGF0IGRpc3BsYXlzIHRoZSBzYW1wbGluZyBnYXBzLiBJdCBtaWdodCBiZSBhIHBsb3QgdGhhdCBzaG93Y2FzZXMgd2hlcmUgZGF0YSBxdWFsaXR5IGlzc3VlcyBhcmUgcHJlc2VudCBpbiB5b3VyIGRhdGEuIEl0IG1pZ2h0IGJlIGEgc2V0IG9mIHBsb3RzIHRoYXQgc2hvdyBob3cgZGlmZmVyZW50IHJlc3VsdHMgYXJlIHByb2R1Y2VkIHdoZW4gZGlmZmVyZW50IGFzc3VtcHRpb25zIGFyZSBtYWRlLiBXcml0ZSBhIGNhcHRpb24gZm9yIHRoaXMgcGxvdCwgZXhwbGFpbmluZyBob3cgaXQgaWxsdXN0cmF0ZXMgcG90ZW50aWFsIGlzc3VlcyB3aXRoIHlvdXIgZGF0YSBhbmFseXNpcy4gCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI0ZpbGwgY29kZSBoZXJlLiAKYGBgCgoKIyMgQ29udGludWUgeW91ciBzaGlueSBhcHAuCgpOb3cgd2Ugd2lsbCBhZ2dyZWdhdGUgYWxsIG9mIHRoZSB0ZXh0IHRoYXQgeW91IHByb2R1Y2VkIGFib3ZlLCBhbG9uZyB3aXRoIHRleHQgdGhhdCB5b3UgcHJvZHVjZWQgaW4gbGFiIDMgaW50byBhbiAiQWJvdXQgdGhlIERhdGEiIHBhZ2Ugb24geW91ciBTaGlueSBBcHAuIEZvbGxvdyB0aGUgaW5zdHJ1Y3Rpb25zIGJlbG93IHRvIGZpbGwgeW91ciB0ZXh0IGludG8gYSBuZXcgcGFnZSBjcmVhdGVkIG9uIHRoZSBmcm9udCBlbmQgb2YgdGhlIGFwcC4gCgpXZSB3b24ndCBiZSB0b3VjaGluZyB0aGUgaW5wdXQgdmFyaWFibGVzIHRoaXMgd2Vlay4gRmlyc3QgY29weSBhbmQgcGFzdGUgeW91ciBpbnB1dCB2YXJpYWJsZXMgZnJvbSBsYWIgNy4KCmBgYHtyfQojPT09PT09PT09PT09PT09PT09PT09PQojQ09QWSBBTkQgUEFTVEUgVEhFIElOUFVUIFZBUklBQkxFUyBTRUNUSU9OIEZST00gTEFCIDcgQkVMT1cKIz09PT09PT09PT09PT09PT09PT09PT0KZ2VvX2lucHV0X2Nob2ljZXMgPC0gCiAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgaG9zcGl0YWxzICU+JSAKICAjUkVQTEFDRSBTVEFURSBCRUxPVyBXSVRIIFlPVVIgT1dOIEdFT0dSQVBISUMgVkFSSUFCTEUKICBzZWxlY3QoU1RBVEUpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICAjUkVQTEFDRSBTVEFURSBCRUxPVyBXSVRIIFlPVVIgT1dOIEdFT0dSQVBISUMgVkFSSUFCTEUKICBhcnJhbmdlKFNUQVRFKQoKI0NPTU1FTlQgTElORVMgQkVMT1cgSUYgWU9VIERPIE5PVCBIQVZFIEEgVEVNUE9SQUwgVkFSSUFCTEUgSU4gWU9VUiBEQVRBRlJBTUUKZGF0ZV9pbnB1dF9zdGFydCA8LSAKICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICBob3NwaXRhbHMgJT4lIAogICNSRVBMQUNFIFNPVVJDRURBVEUgQkVMT1cgV0lUSCBZT1VSIE9XTiBURU1QT1JBTCBWQVJJQUJMRQogIHN1bW1hcml6ZShkYXRlID0gbWluKFNPVVJDRURBVEUpKQoKZGF0ZV9pbnB1dF9lbmQgPC0gCiAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgaG9zcGl0YWxzICU+JSAKICAjUkVQTEFDRSBTT1VSQ0VEQVRFIEJFTE9XIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICBzdW1tYXJpemUoZGF0ZSA9IG1heChTT1VSQ0VEQVRFKSkKI0NPTU1FTlQgTElORVMgQUJPVkUgSUYgWU9VIERPIE5PVCBIQVZFIEEgVEVNUE9SQUwgVkFSSUFCTEUgSU4gWU9VUiBEQVRBRlJBTUUKCiM9PT09PT09PT09PT09PT09PT09PT09CiNDT1BZIEFORCBQQVNURSBUSEUgSU5QVVQgVkFSSUFCTEVTIFNFQ1RJT04gRlJPTSBMQUIgNyBBQk9WRQojPT09PT09PT09PT09PT09PT09PT09PQpgYGAKCgpgYGB7cn0KdWkgPC0gZGFzaGJvYXJkUGFnZSgKICAKICAjUkVQTEFDRSAnVElUTEUgSEVSRScgQkVMT1cgV0lUSCBZT1VSIE9XTiBUSVRMRQogIGRhc2hib2FyZEhlYWRlcih0aXRsZSA9ICJUSVRMRSBIRVJFIiksCiAgI1JFUExBQ0UgJ1RJVExFIEhFUkUnIEFCT1ZFIFdJVEggWU9VUiBPV04gVElUTEUKICAKICBkYXNoYm9hcmRTaWRlYmFyKAogICAgICBzaWRlYmFyTWVudSgKICAgICAgICBtZW51SXRlbSgiRGFzaGJvYXJkIiwgdGFiTmFtZSA9ICJkYXNoYm9hcmQiLCBpY29uID0gaWNvbigiZGFzaGJvYXJkIikpLAogICAgICAgIG1lbnVJdGVtKCJBYm91dCB0aGUgRGF0YSIsIHRhYk5hbWUgPSAiYWJvdXQiLCBpY29uID0gaWNvbigiaW5mby1zaWduIikpCiAgICAgICksCiAgICAgIHNlbGVjdElucHV0KGlucHV0SWQgPSAiZ2VvX3ZhbCIsIGxhYmVsID0gIlNlbGVjdCBhbiBnZW9ncmFwaHk6IiwgY2hvaWNlcyA9IGdlb19pbnB1dF9jaG9pY2VzLCBzZWxlY3RlZCA9IGdlb19pbnB1dF9jaG9pY2VzWzFdKSwKICAgICAgI0NPTU1FTlQgTElORSBCRUxPVyBJRiBZT1UgRE8gTk9UIEhBVkUgQSBURU1QT1JBTCBWQVJJQUJMRSBJTiBZT1VSIERBVEFGUkFNRQogICAgICBkYXRlUmFuZ2VJbnB1dChpbnB1dElkID0gImRhdGVfdmFsIiwgbGFiZWwgPSAiU2VsZWN0IGEgZGF0ZSByYW5nZToiLCBzdGFydCA9IGRhdGVfaW5wdXRfc3RhcnQkZGF0ZSwgZW5kID0gZGF0ZV9pbnB1dF9lbmQkZGF0ZSkKICAgICAgI0NPTU1FTlQgTElORSBBQk9WRSBJRiBZT1UgRE8gTk9UIEhBVkUgQSBURU1QT1JBTCBWQVJJQUJMRSBJTiBZT1VSIERBVEFGUkFNRQogICksCiAgCiAgZGFzaGJvYXJkQm9keSgKICAgIHRhYkl0ZW1zKAogICAgICB0YWJJdGVtKHRhYk5hbWUgPSAiZGFzaGJvYXJkIiwKICAgICAgICBpbmZvQm94T3V0cHV0KCJ2YWx1ZTEiLCB3aWR0aCA9IDQpLAogICAgICAgIGluZm9Cb3hPdXRwdXQoInZhbHVlMiIsIHdpZHRoID0gNCksCiAgICAgICAgaW5mb0JveE91dHB1dCgidmFsdWUzIiwgd2lkdGggPSA0KSwKICAgICAKICAgICAgICBib3gocGxvdE91dHB1dCgicGxvdDEiKSksCiAgICAgICAgYm94KHBsb3RPdXRwdXQoInBsb3QyIikpLAogICAgICAgIGJveChwbG90T3V0cHV0KCJwbG90MyIpKSwKICAgICAgICBib3gocGxvdE91dHB1dCgicGxvdDQiKSkKICAgICAgKSwKICAgICAgdGFiSXRlbSh0YWJOYW1lID0gImFib3V0IiwKICAgICAgICAgICAgICB0YWdzJGgxKCJEYXRhIFNvdXJjZSIpLAogICAgICAgICAgICAgICAgI1JFUExBQ0UgVEVYVCBJTiBRVU9UQVRJT05TIEJFTE9XIFdJVEggWU9VUiBPV04gVEVYVCBBQk9VVCBZT1VSIERBVEEnUyBTT1VSQ0UKICAgICAgICAgICAgICB0YWdzJHAoIlNlZCB1dCBwZXJzcGljaWF0aXMgdW5kZSBvbW5pcyBpc3RlIG5hdHVzIGVycm9yIHNpdCB2b2x1cHRhdGVtIGFjY3VzYW50aXVtIGRvbG9yZW1xdWUgbGF1ZGFudGl1bSwgdG90YW0gcmVtIGFwZXJpYW0sIGVhcXVlIGlwc2EgcXVhZSBhYiBpbGxvIGludmVudG9yZSB2ZXJpdGF0aXMgZXQgcXVhc2kgYXJjaGl0ZWN0byBiZWF0YWUgdml0YWUgZGljdGEgc3VudCBleHBsaWNhYm8uIE5lbW8gZW5pbSBpcHNhbSB2b2x1cHRhdGVtIHF1aWEgdm9sdXB0YXMgc2l0IGFzcGVybmF0dXIgYXV0IG9kaXQgYXV0IGZ1Z2l0LCBzZWQgcXVpYSBjb25zZXF1dW50dXIgbWFnbmkgZG9sb3JlcyBlb3MgcXVpIHJhdGlvbmUgdm9sdXB0YXRlbSBzZXF1aSBuZXNjaXVudC4gTmVxdWUgcG9ycm8gcXVpc3F1YW0gZXN0LCBxdWkgZG9sb3JlbSBpcHN1bSBxdWlhIGRvbG9yIHNpdCBhbWV0LCBjb25zZWN0ZXR1ciwgYWRpcGlzY2kgdmVsaXQsIHNlZCBxdWlhIG5vbiBudW1xdWFtIGVpdXMgbW9kaSB0ZW1wb3JhIGluY2lkdW50IHV0IGxhYm9yZSBldCBkb2xvcmUgbWFnbmFtIGFsaXF1YW0gcXVhZXJhdCB2b2x1cHRhdGVtLiBVdCBlbmltIGFkIG1pbmltYSB2ZW5pYW0sIHF1aXMgbm9zdHJ1bSBleGVyY2l0YXRpb25lbSB1bGxhbSBjb3Jwb3JpcyBzdXNjaXBpdCBsYWJvcmlvc2FtLCBuaXNpIHV0IGFsaXF1aWQgZXggZWEgY29tbW9kaSBjb25zZXF1YXR1cj8gUXVpcyBhdXRlbSB2ZWwgZXVtIGl1cmUgcmVwcmVoZW5kZXJpdCBxdWkgaW4gZWEgdm9sdXB0YXRlIHZlbGl0IGVzc2UgcXVhbSBuaWhpbCBtb2xlc3RpYWUgY29uc2VxdWF0dXIsIHZlbCBpbGx1bSBxdWkgZG9sb3JlbSBldW0gZnVnaWF0IHF1byB2b2x1cHRhcyBudWxsYSBwYXJpYXR1cj8iKSwKICAgICAgICAgICAgICAjUkVQTEFDRSBURVhUIElOIFFVT1RBVElPTlMgQUJPVkUgV0lUSCBZT1VSIE9XTiBURVhUIEFCT1VUIFlPVVIgREFUQSdTIFNPVVJDRQogICAgICAgICAgICAgIAogICAgICAgICAgICAgIHRhZ3MkaDEoIkRhdGEgQ29udGV4dCIpLAogICAgICAgICAgICAgICNSRVBMQUNFIFRFWFQgSU4gUVVPVEFUSU9OUyBCRUxPVyBXSVRIIFlPVVIgT1dOIFRFWFQgQUJPVVQgWU9VUiBEQVRBJ1MgQ09OVEVYVAogICAgICAgICAgICAgIHRhZ3MkcCgiU2VkIHV0IHBlcnNwaWNpYXRpcyB1bmRlIG9tbmlzIGlzdGUgbmF0dXMgZXJyb3Igc2l0IHZvbHVwdGF0ZW0gYWNjdXNhbnRpdW0gZG9sb3JlbXF1ZSBsYXVkYW50aXVtLCB0b3RhbSByZW0gYXBlcmlhbSwgZWFxdWUgaXBzYSBxdWFlIGFiIGlsbG8gaW52ZW50b3JlIHZlcml0YXRpcyBldCBxdWFzaSBhcmNoaXRlY3RvIGJlYXRhZSB2aXRhZSBkaWN0YSBzdW50IGV4cGxpY2Fiby4gTmVtbyBlbmltIGlwc2FtIHZvbHVwdGF0ZW0gcXVpYSB2b2x1cHRhcyBzaXQgYXNwZXJuYXR1ciBhdXQgb2RpdCBhdXQgZnVnaXQsIHNlZCBxdWlhIGNvbnNlcXV1bnR1ciBtYWduaSBkb2xvcmVzIGVvcyBxdWkgcmF0aW9uZSB2b2x1cHRhdGVtIHNlcXVpIG5lc2NpdW50LiBOZXF1ZSBwb3JybyBxdWlzcXVhbSBlc3QsIHF1aSBkb2xvcmVtIGlwc3VtIHF1aWEgZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyLCBhZGlwaXNjaSB2ZWxpdCwgc2VkIHF1aWEgbm9uIG51bXF1YW0gZWl1cyBtb2RpIHRlbXBvcmEgaW5jaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYW0gYWxpcXVhbSBxdWFlcmF0IHZvbHVwdGF0ZW0uIFV0IGVuaW0gYWQgbWluaW1hIHZlbmlhbSwgcXVpcyBub3N0cnVtIGV4ZXJjaXRhdGlvbmVtIHVsbGFtIGNvcnBvcmlzIHN1c2NpcGl0IGxhYm9yaW9zYW0sIG5pc2kgdXQgYWxpcXVpZCBleCBlYSBjb21tb2RpIGNvbnNlcXVhdHVyPyBRdWlzIGF1dGVtIHZlbCBldW0gaXVyZSByZXByZWhlbmRlcml0IHF1aSBpbiBlYSB2b2x1cHRhdGUgdmVsaXQgZXNzZSBxdWFtIG5paGlsIG1vbGVzdGlhZSBjb25zZXF1YXR1ciwgdmVsIGlsbHVtIHF1aSBkb2xvcmVtIGV1bSBmdWdpYXQgcXVvIHZvbHVwdGFzIG51bGxhIHBhcmlhdHVyPyIpLAogICAgICAgICAgICAgICNSRVBMQUNFIFRFWFQgSU4gUVVPVEFUSU9OUyBBQk9WRSBXSVRIIFlPVVIgT1dOIFRFWFQgQUJPVVQgWU9VUiBEQVRBJ1MgU09VUkNFCiAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgdGFncyRoMSgiSW5zaWdodHMiKSwKICAgICAgICAgICAgICAjUkVQTEFDRSBURVhUIElOIFFVT1RBVElPTlMgQkVMT1cgV0lUSCBZT1VSIE9XTiBURVhUIEFCT1VUIFlPVVIgSU5TSUdIVFMKICAgICAgICAgICAgICB0YWdzJHAoIlNlZCB1dCBwZXJzcGljaWF0aXMgdW5kZSBvbW5pcyBpc3RlIG5hdHVzIGVycm9yIHNpdCB2b2x1cHRhdGVtIGFjY3VzYW50aXVtIGRvbG9yZW1xdWUgbGF1ZGFudGl1bSwgdG90YW0gcmVtIGFwZXJpYW0sIGVhcXVlIGlwc2EgcXVhZSBhYiBpbGxvIGludmVudG9yZSB2ZXJpdGF0aXMgZXQgcXVhc2kgYXJjaGl0ZWN0byBiZWF0YWUgdml0YWUgZGljdGEgc3VudCBleHBsaWNhYm8uIE5lbW8gZW5pbSBpcHNhbSB2b2x1cHRhdGVtIHF1aWEgdm9sdXB0YXMgc2l0IGFzcGVybmF0dXIgYXV0IG9kaXQgYXV0IGZ1Z2l0LCBzZWQgcXVpYSBjb25zZXF1dW50dXIgbWFnbmkgZG9sb3JlcyBlb3MgcXVpIHJhdGlvbmUgdm9sdXB0YXRlbSBzZXF1aSBuZXNjaXVudC4gTmVxdWUgcG9ycm8gcXVpc3F1YW0gZXN0LCBxdWkgZG9sb3JlbSBpcHN1bSBxdWlhIGRvbG9yIHNpdCBhbWV0LCBjb25zZWN0ZXR1ciwgYWRpcGlzY2kgdmVsaXQsIHNlZCBxdWlhIG5vbiBudW1xdWFtIGVpdXMgbW9kaSB0ZW1wb3JhIGluY2lkdW50IHV0IGxhYm9yZSBldCBkb2xvcmUgbWFnbmFtIGFsaXF1YW0gcXVhZXJhdCB2b2x1cHRhdGVtLiBVdCBlbmltIGFkIG1pbmltYSB2ZW5pYW0sIHF1aXMgbm9zdHJ1bSBleGVyY2l0YXRpb25lbSB1bGxhbSBjb3Jwb3JpcyBzdXNjaXBpdCBsYWJvcmlvc2FtLCBuaXNpIHV0IGFsaXF1aWQgZXggZWEgY29tbW9kaSBjb25zZXF1YXR1cj8gUXVpcyBhdXRlbSB2ZWwgZXVtIGl1cmUgcmVwcmVoZW5kZXJpdCBxdWkgaW4gZWEgdm9sdXB0YXRlIHZlbGl0IGVzc2UgcXVhbSBuaWhpbCBtb2xlc3RpYWUgY29uc2VxdWF0dXIsIHZlbCBpbGx1bSBxdWkgZG9sb3JlbSBldW0gZnVnaWF0IHF1byB2b2x1cHRhcyBudWxsYSBwYXJpYXR1cj8iKSwKICAgICAgICAgICAgICAjUkVQTEFDRSBURVhUIElOIFFVT1RBVElPTlMgQUJPVkUgV0lUSCBZT1VSIE9XTiBURVhUIEFCT1VUIFlPVVIgSU5TSUdIVFMKICAgICAgICAgICAgICAKICAgICAgICAgICAgICB0YWdzJGgxKCJLbm93bGVkZ2UgR2FwcyIpLAogICAgICAgICAgICAgICNSRVBMQUNFIFRFWFQgSU4gUVVPVEFUSU9OUyBCRUxPVyBXSVRIIFlPVVIgT1dOIFRFWFQgQUJPVVQgWU9VUiBLTk9XTEVER0UgR0FQUwogICAgICAgICAgICAgIHRhZ3MkcCgiU2VkIHV0IHBlcnNwaWNpYXRpcyB1bmRlIG9tbmlzIGlzdGUgbmF0dXMgZXJyb3Igc2l0IHZvbHVwdGF0ZW0gYWNjdXNhbnRpdW0gZG9sb3JlbXF1ZSBsYXVkYW50aXVtLCB0b3RhbSByZW0gYXBlcmlhbSwgZWFxdWUgaXBzYSBxdWFlIGFiIGlsbG8gaW52ZW50b3JlIHZlcml0YXRpcyBldCBxdWFzaSBhcmNoaXRlY3RvIGJlYXRhZSB2aXRhZSBkaWN0YSBzdW50IGV4cGxpY2Fiby4gTmVtbyBlbmltIGlwc2FtIHZvbHVwdGF0ZW0gcXVpYSB2b2x1cHRhcyBzaXQgYXNwZXJuYXR1ciBhdXQgb2RpdCBhdXQgZnVnaXQsIHNlZCBxdWlhIGNvbnNlcXV1bnR1ciBtYWduaSBkb2xvcmVzIGVvcyBxdWkgcmF0aW9uZSB2b2x1cHRhdGVtIHNlcXVpIG5lc2NpdW50LiBOZXF1ZSBwb3JybyBxdWlzcXVhbSBlc3QsIHF1aSBkb2xvcmVtIGlwc3VtIHF1aWEgZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyLCBhZGlwaXNjaSB2ZWxpdCwgc2VkIHF1aWEgbm9uIG51bXF1YW0gZWl1cyBtb2RpIHRlbXBvcmEgaW5jaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYW0gYWxpcXVhbSBxdWFlcmF0IHZvbHVwdGF0ZW0uIFV0IGVuaW0gYWQgbWluaW1hIHZlbmlhbSwgcXVpcyBub3N0cnVtIGV4ZXJjaXRhdGlvbmVtIHVsbGFtIGNvcnBvcmlzIHN1c2NpcGl0IGxhYm9yaW9zYW0sIG5pc2kgdXQgYWxpcXVpZCBleCBlYSBjb21tb2RpIGNvbnNlcXVhdHVyPyBRdWlzIGF1dGVtIHZlbCBldW0gaXVyZSByZXByZWhlbmRlcml0IHF1aSBpbiBlYSB2b2x1cHRhdGUgdmVsaXQgZXNzZSBxdWFtIG5paGlsIG1vbGVzdGlhZSBjb25zZXF1YXR1ciwgdmVsIGlsbHVtIHF1aSBkb2xvcmVtIGV1bSBmdWdpYXQgcXVvIHZvbHVwdGFzIG51bGxhIHBhcmlhdHVyPyIpCiAgICAgICAgICAgICAgI1JFUExBQ0UgVEVYVCBJTiBRVU9UQVRJT05TIEFCT1ZFIFdJVEggWU9VUiBPV04gVEVYVCBBQk9VVCBZT1VSIEtOT1dMRURHRSBHQVBTCiAgICAgICkKICAgICkKICApCikKYGBgCgpXZSB3b24ndCBiZSB0b3VjaGluZyB0aGUgc2VydmVyIGZ1bmN0aW9uIHRoaXMgd2Vlay4gWW91IGNhbiBjb3B5IGFuZCBwYXN0ZSB5b3VycyBmcm9tIExhYiA3IHRvIHJlcGxhY2UgbXkgY29kZSBiZWxvdy4gCgpgYGB7cn0KIz09PT09PT09PT09PT09PT09PT09PT0KI0NPUFkgQU5EIFBBU1RFIFRIRSBTRVJWRVIgRlVOQ1RJT04gRlJPTSBMQUIgNyBCRUxPVwojPT09PT09PT09PT09PT09PT09PT09PQpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIAogIG91dHB1dCR2YWx1ZTEgPC0gcmVuZGVySW5mb0JveCh7CiAgICBxdWFudF9pbnNpZ2h0MSA8LQogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lICAgICAgCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBGVU5DVElPTiBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICAgICAgc3VtbWFyaXplKG1lZGlhbl92YWx1ZSA9IG1lZGlhbihCRURTLCBuYS5ybSA9IFRSVUUpKQogICAgCiAgICAjUkVQTEFDRSAnRklMTCBERVNDUklQVElPTiBIRVJFJyBCRUxPVyBXSVRIIFlPVVIgT1dOIERFU0NSSVBUSU9OCiAgICBpbmZvQm94KHF1YW50X2luc2lnaHQxLCdGSUxMIERFU0NSSVBUSU9OIEhFUkUnLCBpY29uID0gaWNvbigic3RhdHMiLCBsaWI9J2dseXBoaWNvbicpLCBjb2xvciA9ICJwdXJwbGUiKQogIH0pCiAgCiAgb3V0cHV0JHZhbHVlMiA8LSByZW5kZXJJbmZvQm94KHsKICAgIHF1YW50X2luc2lnaHQyIDwtIAogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBGVU5DVElPTiBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICAgICAgc3VtbWFyaXplKG1lZGlhbl92YWx1ZSA9IG1lZGlhbihCRURTLCBuYS5ybSA9IFRSVUUpKQogICAgCiAgICAjUkVQTEFDRSAnRklMTCBERVNDUklQVElPTiBIRVJFJyBCRUxPVyBXSVRIIFlPVVIgT1dOIERFU0NSSVBUSU9OCiAgICBpbmZvQm94KHF1YW50X2luc2lnaHQyLCdGSUxMIERFU0NSSVBUSU9OIEhFUkUnLCBpY29uID0gaWNvbigic3RhdHMiLCBsaWI9J2dseXBoaWNvbicpLCBjb2xvciA9ICJwdXJwbGUiKQogIH0pCiAgCiAgb3V0cHV0JHZhbHVlMyA8LSByZW5kZXJJbmZvQm94KHsKICAgIHF1YW50X2luc2lnaHQzIDwtIAogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBGVU5DVElPTiBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICAgICAgc3VtbWFyaXplKG1lZGlhbl92YWx1ZSA9IG1lZGlhbihCRURTLCBuYS5ybSA9IFRSVUUpKQoKICAgICNSRVBMQUNFICdGSUxMIERFU0NSSVBUSU9OIEhFUkUnIEJFTE9XIFdJVEggWU9VUiBPV04gREVTQ1JJUFRJT04KICAgIGluZm9Cb3gocXVhbnRfaW5zaWdodDMsJ0ZJTEwgREVTQ1JJUFRJT04gSEVSRScsIGljb24gPSBpY29uKCJzdGF0cyIsIGxpYj0nZ2x5cGhpY29uJyksIGNvbG9yID0gInB1cnBsZSIpCiAgfSkKICAKICBvdXRwdXQkcGxvdDEgPC0gcmVuZGVyUGxvdCh7CiAgICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICAgIGhvc3BpdGFscyAlPiUgCiAgICAjUkVQTEFDRSBTVEFURSBXSVRIIFlPVVIgT1dOIEdFT0dSQVBISUMgVkFSSUFCTEUgQU5EIFNPVVJDRURBVEUgV0lUSCBZT1VSIE9XTiBURU1QT1JBTCBWQVJJQUJMRQogICAgICBmaWx0ZXIoCiAgICAgICAgU1RBVEUgPT0gaW5wdXQkZ2VvX3ZhbCAmIAogICAgICAgIFNPVVJDRURBVEUgPiBpbnB1dCRkYXRlX3ZhbFsxXSAmCiAgICAgICAgU09VUkNFREFURSA8IGlucHV0JGRhdGVfdmFsWzJdCiAgICAgICAgKSAlPiUKICAgICNDT1BZIEFORCBQQVNURSBZT1VSIFBMT1QgSEVSRSBGUk9NIExBQiA2CiAgICAgIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICAgICAgZ2dwbG90KGFlcyh4ID0gVFlQRSkpICsgCiAgICAgIGdlb21fYmFyKCkgKwogICAgICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSAKICB9KQogIAogIG91dHB1dCRwbG90MiA8LSByZW5kZXJQbG90KHsKICAgICNSRVBMQUNFIGhvc3BpdGFscyBCRUxPVyBXSVRIIFlPVVIgT1dOIERBVEFGUkFNRQogICAgaG9zcGl0YWxzICU+JSAKICAgICNSRVBMQUNFIFNUQVRFIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRSBBTkQgU09VUkNFREFURSBXSVRIIFlPVVIgT1dOIFRFTVBPUkFMIFZBUklBQkxFCiAgICAgIGZpbHRlcigKICAgICAgICBTVEFURSA9PSBpbnB1dCRnZW9fdmFsICYgCiAgICAgICAgU09VUkNFREFURSA+IGlucHV0JGRhdGVfdmFsWzFdICYKICAgICAgICBTT1VSQ0VEQVRFIDwgaW5wdXQkZGF0ZV92YWxbMl0KICAgICAgICApICU+JQogICAgI0NPUFkgQU5EIFBBU1RFIFlPVVIgUExPVCBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogICAgICBnZ3Bsb3QoYWVzKHggPSBUWVBFKSkgKyAKICAgICAgZ2VvbV9iYXIoKSArCiAgICAgIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBUeXBlIiwgeCA9ICJUeXBlIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbHMiKSArIAogICAgICB0aGVtZV9idygpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpIAogIH0pCiAgCiAgb3V0cHV0JHBsb3QzIDwtIHJlbmRlclBsb3QoewogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBQTE9UIEhFUkUgRlJPTSBMQUIgNgogICAgICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgICAgIGdncGxvdChhZXMoeCA9IFRZUEUpKSArIAogICAgICBnZW9tX2JhcigpICsKICAgICAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIpICsgCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgCiAgfSkKICAKICBvdXRwdXQkcGxvdDQgPC0gcmVuZGVyUGxvdCh7CiAgICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICAgIGhvc3BpdGFscyAlPiUgCiAgICAjUkVQTEFDRSBTVEFURSBXSVRIIFlPVVIgT1dOIEdFT0dSQVBISUMgVkFSSUFCTEUgQU5EIFNPVVJDRURBVEUgV0lUSCBZT1VSIE9XTiBURU1QT1JBTCBWQVJJQUJMRQogICAgICBmaWx0ZXIoCiAgICAgICAgU1RBVEUgPT0gaW5wdXQkZ2VvX3ZhbCAmIAogICAgICAgIFNPVVJDRURBVEUgPiBpbnB1dCRkYXRlX3ZhbFsxXSAmCiAgICAgICAgU09VUkNFREFURSA8IGlucHV0JGRhdGVfdmFsWzJdCiAgICAgICAgKSAlPiUKICAgICNDT1BZIEFORCBQQVNURSBZT1VSIFBMT1QgSEVSRSBGUk9NIExBQiA2CiAgICAgIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICAgICAgZ2dwbG90KGFlcyh4ID0gVFlQRSkpICsgCiAgICAgIGdlb21fYmFyKCkgKwogICAgICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSAKICB9KQogIAp9CiM9PT09PT09PT09PT09PT09PT09PT09CiNDT1BZIEFORCBQQVNURSBUSEUgU0VSVkVSIEZVTkNUSU9OIEZST00gTEFCIDcgQUJPVkUKIz09PT09PT09PT09PT09PT09PT09PT0KYGBgCgoKYGBge3J9CnNoaW55QXBwKHVpLCBzZXJ2ZXIpCmBgYAoKCg==