Instructions and Overview

At this point in the quarter, we have produced a number of plots and calculate a number of measures in regards to our data. Now, we’re going to explore in more depth how the stories the data tell change depending on where we look. This exploration will turn into user inputs in our Shiny app.

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://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.

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

Facets

To get us started in putting our data into context, we are going to look at some of the plots we produced in previous labs grouped according to a categorical variable in our dataset.

By faceting plots, we split them into a series of panels each representing the grouped data associated with a particular value in a categorical variable. Let’s start with an easy example from our hospitals data - faceting a bar plot of the number of hospitals that have a helipad by state. We can facet a plot by adding: + facet_wrap(~VARIABLE_NAME) to the call.

#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE)) + geom_bar() + facet_wrap(~CATEGORICAL_VARIABLE)

#without facet_wrap()
hospitals %>% 
  ggplot(aes(x = HELIPAD)) + 
  geom_bar() +
  labs(title = "Number of Hospitals by Helipad Status", x ="Helipad", y = "Count of Hospitals" ) +
  theme_bw()


#with facet_wrap()
hospitals %>% 
  ggplot(aes(x = HELIPAD)) + 
  geom_bar() +
  facet_wrap(~STATE) +
  labs(title = "Number of Hospitals by Helipad Status", x ="Helipad", y = "Count of Hospitals" ) +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 45, hjust=1, size = 6), 
        axis.text.y = element_text(size = 6),
        strip.text = element_text(size = 6)) 

NA

The first plot suggests that more hospitals have helipads than those that don’t. Grouping this by state, however, we can see that in some states (like California and New York), more hospitals don’t have helipads than those that do. Faceting can help us zoom into the data for more geographic specificity.

Let’s also facet data by a temporal variable. Assuming we have already converted a date/time variable in our dataset into a data/time format (using lubridate in lab 4), we should be able to extract a year, month, day (and if available hour, minute, and second) from the data using these lubridate functions:

  • year(DATE_VARIABLE) will extract the year from the date
  • month(DATE_VARIABLE) will extract the month from the date
  • day(DATE_VARIABLE) will extract the day from the date
  • … and so on
#without facet_wrap()
hospitals %>% 
  ggplot(aes(x = STATUS)) + 
  geom_bar() +
  labs(title = "Number of Hospitals by Status", x ="Status", y = "Count of Hospitals" ) +
  theme_bw()


#with facet_wrap()
hospitals %>% 
  ggplot(aes(x = STATUS)) + 
  geom_bar() +
  labs(title = "Number of Hospitals by Status", x ="Status", y = "Count of Hospitals" ) +
  facet_wrap(~year(SOURCEDATE)) +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 45, hjust=1, size = 6), 
        axis.text.y = element_text(size = 6),
        strip.text = element_text(size = 6)) 

Faceting this plot by the year in which the data was sourced helps put the STATUS field into context. We can see that the vast majority of the data represented in the plot was sourced in 2018. We know that hospitals across the country are not open or closed in perpetuity, so we need to take the temporal context of the data into consideration when presenting our results.

If we have qualified observational units in our dataset, faceting allows us to group data by one of the qualifying variables and display the data as a set of side-by-side plots. For instance, remember how we have been filtering to the most recent year data was reported when plotting the world_health_econ data. Instead, we could facet() the data to demonstrate how different health ecnomics indicators change over time.

world_health_econ %>%
  ggplot(aes(x = tot_health_sp_pp, y = life_exp, size = pop, col = continent)) + 
  geom_point(shape = 21, stroke = 0.5) +
  facet_wrap(~year) +
  labs(title = "Relationship between Country Total Health Spending Per Person and Life Expectancy", x = "Total Health Spending Per Person", y = "Life Expectancy", size = "Population", col = "Continent") + # To add titles and labels
  theme_bw() +
  scale_size_continuous(range = c(1, 10), labels = scales::comma)

Copy and paste a plot from one of your previous labs. Then copy it again and facet it by a geographic or temporal variable.

#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE)) + geom_bar() + facet_wrap(~CATEGORICAL_VARIABLE)

#Copy and paste a previoulsy created plot here. 

#Copy that plot again and facet it by a geographic or temporal variable. Adjust the theme as I have above to make your plot more legible.  

How do the stories that the two plots tell differ? What does your first plot tell you about the geo-political landscape of the issue you are studying? - OR - What does the first plot tell you about the temporal landscape of the issue you are studying?

Fill your response here. 

Repeat the exercise you completed above for a second plot you created in a previous lab.

#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE)) + geom_bar() + facet_wrap(~CATEGORICAL_VARIABLE)

#Copy and paste a previoulsy created plot here. 

#Copy that plot again and facet it by a geographic or temporal variable. Adjust the theme as I have above to make your plot more legible.  

How do the stories that the two plots tell differ? What does your second plot tell you about the geo-political landscape of the issue you are studying? - OR - What does the second plot tell you about the temporal landscape of the issue you are studying?

Fill your response here. 

The Importance of Place and Time

Time and place often matter a great deal in how we interpret data. Let me provide a few examples that demonstrate why:

Case Study 1: Chrono-politics of Calls to 311 during Hurricane Sandy

311 is basically a customer service number for cities - a number for residents and visitors to report non-emergency issues, such as potholes and graffiti, to city officials. In most cities, every call to 311 gets aggregated in a database, and increasingly, city officials are performing data analysis on the calls to figure out where certain issues in the city are concentrated. If they receive a number of calls about missed garbage pick-ups in a certain community, they may divert attention and resources there for improved sanitation. Often this data is publicly accessible for communities to analyze.

When Hurricane Sandy hit NYC in 2012, the City leveraged data about calls New Yorkers had made to 311 to track where a number of different issues were occurring. I’ve included a sample of that data regarding calls about damaged trees and lack of heat and hot water in apartments in a dataset below.

library(scales)
nyc311 <- read.csv("https://github.com/lindsaypoirier/STS-115/blob/master/datasets/311_before_2015.csv?raw=true", stringsAsFactors = FALSE) 
nyc311 %>% head(10)

Visualizing data about 311 calls in the three months following the disaster indeed showed a spike in complaints about issues like damaged trees and lack of heat in apartment buildings throughout the city. Leveraging this data, the city was able to position the devastation of the disaster as episodic - a result of natural forces beyond their control.

nyc311 %>% 
  filter(year(Created.Date) == 2012 & month(Created.Date) %in% c(7:11)) %>%
  ggplot(aes(x = as.Date(Created.Date), group = 1)) +
  geom_vline(xintercept=as.Date(c("2012-10-29")),linetype=4, colour="black") +
  geom_line(stat="count") + 
  facet_wrap(~Complaint.Type) + 
  labs(x="Month", y="Count") +
  scale_x_date() +
  theme_bw() +
  annotate(geom = "label", x = as.Date("2012-10-29"), y = 4000, label = "Hurricane Sandy", angle = 90)

However, social researchers have argued that it is not so simple to delimit the temporal boundaries of a disaster. While a natural event may happen on a particular day or span of days, the structural conditions of the communities they impact have much longer timespans. Natural events occurring in delimited periods of time often exacerbate existing social issues like poverty, lack of affordable housing, and unequal access to healthcare.

Let’s zoom out on the 311 data to look at these issues over the course of years versus these three months. Complaints to 311 about damaged trees do spike following most major natural events. However, complaints about lack of heat in apartments spike every year in October …because in New York, that’s when it gets cold. By only looking at the data in months immediately after the disaster, the city could obscure the big picture - that poor New Yorkers face apartment negligence every year, not just immediately following a hurricane. The temporal context in which we analyze data matters a great deal for how we interpret it.

nyc311 %>% 
  ggplot(aes(x=as.Date(Created.Date), col=as.factor(year(Created.Date)), group = year(Created.Date))) +
  geom_vline(xintercept=as.Date(c("2010-03-12","2010-09-16","2011-08-28","2011-10-29","2012-10-29")),linetype=4, colour="black") +
  geom_line(stat = "count") + 
  facet_wrap(~Complaint.Type) +
  labs(x="Month", col="Year") +
  scale_x_date(breaks = "3 months", labels=date_format("%b-%y")) +
  theme_bw() +
  annotate(geom = "label", x = as.Date("2010-03-12"), y = 4000, label = "nor'easter", angle = 90) +
  annotate(geom = "label", x = as.Date("2010-09-16"), y = 4000, label = "tornadoes", angle = 90) +
  annotate(geom = "label", x = as.Date("2011-08-28"), y = 4000, label = "Hurricane Irene", angle = 90) +
  annotate(geom = "label", x = as.Date("2011-10-29"), y = 4500, label = "Halloween nor'easter", angle = 90) +
  annotate(geom = "label", x = as.Date("2012-10-29"), y = 4000, label = "Hurricane Sandy", angle = 90)

  #nor'easter, tornadoes, Irene, Halloween nor'easter, Sandy

See: Liboiron, Max. 2015. “Disaster Data, Data Activism: Grassroots Responses to Representing Superstorm Sandy.” In Extreme Weather and Global Media, edited by Julia Leyda and Diane Negra. Taylor & Francis Group. https://doi.org/10.4324/9781315756486-7.

Case Study 2: Geo-politics of Calls to 311 during Hurricane Sandy

library(leaflet)

nyc311 %>%
  filter(Created.Date > "2012-10-28" & Created.Date < "2012-10-30" & Complaint.Type == "Damaged Tree") %>%
  leaflet() %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  addMarkers(~Longitude, ~Latitude, clusterOptions = markerClusterOptions())
Data contains 47 rows with either missing or invalid lat/lon values and will be ignored

Case Study 3: Covid-19 Case Reporting by Country

Let’s take a look at the number of Covid-19 cases reported each day by each country. To do so, we will be reimporting the cases data as a time series - that is, as a dataset that reports the number of cases per day. On import, every column represents a specific date and the case totals for that date are the values stored in that column.

cases_time_series <- 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)

head(cases_time_series)

Aside: Tidying Data with Gather

This section is just FYI. You may skip it if not interested

Note how the column headers are formatted above. When dates are stored as column names and not as values in and of themselves, it can be very difficult to manipulate the data based on dates. Remember that column names are not data in and of themselves but a reference to a vector of values. The dates in this dataset are a reference to a vector of case numbers. Because the date values are not represented in the data, but only as a reference to case numbers, we can’t filter observations to specific dates or to dates that happened before or after another date. The code below reshapes the data so that such filtering is possible. Using gather(), for every province/country in the dataset, a new row will be created in the dataset for every date data was reported. The reshaped data will have two new columns: Case.Date (the date reported) and Cases (the number reported on that date). Basically, we will take wide data (many columns with fewer rows), and reshape it into long data (fewer columns with more rows).

If you’d like to know more about how to use gather() to create tidy data, I highly recommend this chapter in R for Data Science.

You’ll also note above that R automatically places an “X” character in front of numeric column names. Below we remove that X character and then we transform the values into a date-time format.

cases_time_series <- cases_time_series %>% 
  gather(key = "Case.Date", value = "Cases", -Province.State, -Country.Region, -Lat, -Long) %>%
  mutate(Case.Date = str_remove(Case.Date, pattern = "X")) %>%
  mutate(Case.Date = mdy(Case.Date))

head(cases_time_series)
Rejoin here if you skipped the section above.

Now let’s plot the total number of cases reported each day, faceted by country. (This may take a bit of time to load.)

cases_time_series %>% 
  ggplot(aes(x = Case.Date, y = Cases)) + 
  stat_summary(geom = "col", fun.y = "sum") + 
  facet_wrap(~Country.Region) +
  labs(title = "Time Series of Case Counts in the US by Day and Country", x = "Case Date", y = "Cases") +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 45, hjust=1, size = 6), 
        axis.text.y = element_text(size = 6),
        strip.text = element_text(size = 6)) +
  scale_y_continuous(labels = scales::comma) #Change labels from scientific to comma notation

One observation that might stand out in this plot is just how few cases were reported in Russia through mid-March. As of March 24, 2020, Russia had reported fewer than 500 cases of Covid-19. For a country covering more than 6 million square miles, with a population of 145 million, and in such close proximity to China where the case counts are highest, these numbers are surprisingly low. Russian officials have claimed that measures they took - such as shutting down the Russian border with China and setting up isolation zones for quarantined patients - have helped to keep the virus under control. However, several news reports have been published casting skepticism on the numbers, suggesting that in Russia there is a widespread culture against producing information that may draw negative international attention. To interpret this plot then, we need to have an understanding of global geopolitics, or politics mediated by geography, demography, and cross-border relations. The numbers that we see reported in some parts of the world will vary from numbers reported in other parts of the world, not because the values are actually different, but because there are different cultures of reporting in certain countries.

Characterize the geopolitics in your own dataset. Why might it be important to consider the variable of place when interpreting your data?

Fill your response here.

Case Study 4: Covid-19 Cases over Time

Now let’s look at a time series of cases reported in the US.

cases_time_series %>% 
  filter(Country.Region == "US") %>%
  ggplot(aes(x = Case.Date, y = Cases)) + 
  stat_summary(geom = "col", fun.y = "sum") +
  labs(title = "Time Series of Case Counts in the US by Day", x = "Case Date", y = "Cases") +
  theme_bw() +
  scale_y_continuous(labels = scales::comma) #Change labels from scientific to comma notation

This plot indicates that few cases were reported prior to mid-March. However, to responsibly interpret this plot, we need to pay close attention to how case totals are produced. The numbers of confirmed cases reported in this dataset are based on the number of Covid-19 tests that are reported positive. However, the extent of testing in the US has been variable since January due to a number of political, regulatory, and material roadblocks. Up through February, very few tests were being conducted in the US as the federal government downplayed the threat posed by the virus. A series of follow-up events continued to shift the testing landscape:

  • February 5: The CDC shipped coronavirus test kits to state labs with contaminated reagents. These labs ended up having to send their samples to the CDC for testing.
  • February 29th: Up until this point, FDA regulations prevented labs from developing their own coronavirus test kits. On February, 29th, this rule was lifted allowing high-complexity labs to develop and run tests under what is called an Emergency Use Authorization.
  • March 12th: Up until this point, in order for a lab to begin testing patients, they needed to be authorized by the FDA to do so. On March 12, the FDA granted more flexibility to states to authorize this testing.
  • While these regulatory changes quickened the pace at which labs could test patients, at this point, a new issue was emerging. Labs began reporting critical shortages of testing supplies and reagents for conducting tests.

With every change in the testing landscape, we can expect that the number of cases reported will also change. To interpret this plot, we need to have an understanding of chrono-politics, or the politics of time. Importantly, these regulatory timelines are playing out differently in different countries. There is much to consider at the intersection of geo-politics and chrono-politics.

Characterize the chrono-politics in your own dataset. Why might it be important to consider the variable of time when interpreting your data?

Fill your response here.

Other Confounding Variables

Sometimes, when we are analyzing data, it can seem as though there is a strong relationship between two variables in our dataset. Perhaps life expenctancy increases as spending on health increases, or perhaps the number of staff at a hospital increases as the number of beds at the hospital increases. We may assume that there is is a causal relationship between these two variables. Confounding variables, however, refer to a third phenomena that influences the relationship we see between two variables in a dataset. While it may appear as though two variables are highly correlated, a shared association with a confounding variable may be mediating that correlation. Before we make any claims with our data it is important that we consider such variables.

For instance, consider if were to look at data documenting the relationship between the number of Covid-19 cases each country has reported and the number of deaths it has reported.

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

is.na(deaths) <- deaths == ""

deaths <- 
  deaths %>% 
  mutate(Total.Deaths = 
           deaths %>% 
           select(starts_with("X")) %>% 
           rowSums()
         ) %>%
  select(Province.State, Country.Region, Total.Deaths) %>%
  right_join(cases, by = c("Province.State", "Country.Region"))
deaths %>% 
  group_by(Country.Region) %>%
  summarize(Total.Cases = sum(Total.Cases, na.rm = TRUE), Total.Deaths = sum(Total.Deaths, na.rm = TRUE)) %>%
  ungroup() %>%
  ggplot(aes(x = Total.Cases, y = Total.Deaths)) + 
  geom_point(shape = 21, stroke = 1) +
  labs(title = "Relationship between Total Covid-19 Deaths and Total Cases Globally", x = "Cases", y = "Deaths") + # To add titles and labels
  theme_bw() +
  scale_x_continuous(trans='log10', labels =  scales::comma) +
  scale_y_continuous(trans='log10', labels = scales::comma)

Keep in mind that each dot above represents a country. Before we make any assumptions about the causal relationship between these two variables, there are number of confounding variables to consider:

  • What is the median age of the population in the country?
  • How advanced is the country’s healthcare system?
  • To what extent do citizens in the country have access to healthcare?
  • How soon were social distancing policies put into place in the country?
  • How is the country documenting a Covid-19 related case/death?
  • Not to mention the geopolitics and chronopolitics we described above?

Can you come up with others?

Population

When comparing certain phenomena across places - particuarly phenomena that are related to human activity - it is often important to consider how population can impact the numbers we see. For instance, when assessing the readiness of hospitals to take on an influx of Covid-19 patients across counties and/or states in the US, we need to not only consider the number of beds available, but also the population of the county and/or state. Population is one confounding variable, among many, that will mediate the relationship between hospital readiness for patient intake and the number of beds available.

Consider another example. In 2018, I was at a conference in Brooklyn, listening to a representative from MasterCard discuss the importance of opening up data and getting it into the hands of community members to anaylze. A health practitioner from NYC’s Department of Mental Health and Hygeine stood up to voice his concerns to the speaker. He said that it worries him that untrained community members may draw poor assumptions from the data. He described a dataset that documented the number mental health discharges by neighborhood in New York, and how it indicated that there were far more discharges in low income communities. This, he went on, could potentially lead someone to conclude that poor people are more likely to experience mental health issues or to instigate gun violence. However, he went on to assert that many community members might not know just from looking at the data that there are far more mental health hospitals in low income communities in NYC than in higher income communities. …and that this is often because higher income communities have more power to lobby for keeping such hospitals out of their backyards! In this case, the practitioner was expressing concern that community members may not consider a significant confounding variable mediating the number of mental health discharges across NYC communities: the number of hospitals in each community.

In what ways might the distinct sizes or populations of a place impact how you compare issues across your data?

Fill your response here.

Semantic Changes

Semantics refer to the meaning of words. When I say the word ‘apple’ you are likely to conjure up an image in your head of what I am referring to. In using the word, I am attempting to signify something that exists in the world so that we both may communicate about that thing. Semantics refer to the meaning behind this signifier. When we work with data, we are dealing with a number of signifiers that have have particular meanings behind them.

We always view data in a particular moment in time. However, over time, our understanding of particular phenomena inevitably shifts as we gain more knowledge, as culture changes, or as new phenomena come into existence or into our awareness. An entire sub-field of anthropology is dedicated to studying how language changes culturally over time. For instance, consider how gender pronouns have shifted as the politics of gender have also shifted. While historically, the pronoun “he” was often used as a generic pronoun in English language, the femininst movement played a key role in shifting our language systems to reject this use and to encourage more gender neutral language. More recently, transgender pronouns have become more present in our langauge systems, indicating the continuity of culture shifts.

Research in information studies has shown how even categories that have been institutionally standardized are constantly changing. For instance, Geoffrey Bowker and Susan Leigh Star have traced changes in the International Classification of Diseases (or the ICD) - a coding/classifcation system for diseases maintained by the World Health Organization. Medical professionals reference the ICD to diagnose patients based on symptoms and their social circumstances; in other words, every time an individual is diagnosed with something, that something has an associated code in the ICD. The ICD has been revised(with codes added, removed, reorganized, and edited) ten times - the most recent version of the classification system being ICD-11. These revisions not only reflect new research on diseases, but also changes in culture. For instance, how abortion gets coded in the ICD has been politically, ethically, and religiously charged.

While ICD-11 does have a classification for Covid-19, ICD-10 does not, and ICD-10 is considered current and in use until January 1, 2022 when it will be replaced by the new version. This means that, in the current system for assigning codes to diagnoses, there is no formal signifier for referring to the disease. Because of this, the WHO had to administer an emergency ICD-10 code for use in diagnosing patients with Covid-19. The current language system had to adapt to the new circumstances - and in this case very quickly. You can read more about this here.

When we’re working with data, these issues can matter a great deal. When classifications change in our data, i.e. when new terms become available, when categories break into two, or when signifers are removed, it also changes how we interpret quantities represented in the data.

For instance, when I worked for NYC’s civic data team, I would regularly work with open 311 data. Every 311 call is coded with a certain category, such as Noise, No Heat and Hot Water in Building, Rat Sighting, or Broken Tree Limb. We would often filter the data to certain categories and create maps of the number of complaints deriving from different neighborhoods about that issue. However, these categories were collectively maintained by over 70 city agencies which were constantly changing how they recorded issues. For instance, In 2015, the category HEATING (referring to a heating issue in an apartment) changed to HEAT/HOT WATER. If we did not know that the categories were changing, we may have looked at the data and thought that there was a sudden drop off in heating complaints or a sudden uptick in hot water complaints - when in fact, it was just the language in encoded in the system changing.

In what ways have semantics, along with the words used to represent certain meanings, changed over time in your dataset?

Fill your response here.

Last week you listed a number of questions that your quantitative calculations might help you to address. Select two of those questions, and list them below. Then consider what confounding variables you may need to consider before assuming the value you calculated or the plot you created could adequately address that question.

What was one question you identified last week?

Fill your response here.

What confounding variable might you need to consider before assuming your calculation could answer that question?

Fill your response here.

What was one question you identified last week?

Fill your response here.

What confounding variable might you need to consider before assuming your calculation could answer that question?

Fill your response here.

Continue your shiny app.

We are now going to add the capacity for users to specify specific geographies and timeframes when viewing the data in our app. While I believe all of you have a geography represented in your data, some of you do not have date and time represented in your data. If this is the case, you may remove the commented data-time inputs from the code below.

At this point, we will begin working in the ui code block and creating more crosstalk between the ui and the server. Users will input information into the front end of the app, and that input will be communicated to the server. More specifically, users will select a geography and a data/timeframe, and the server will filter the dataset according to the selected features and recreate the values/plots on the filtered data.

Be sure to follow all commented instructions below to add inputs to your Shiny app.

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

Replace the title with your own below. Also comment out or remove the lines regarding the temporal variable if you do not have a temporal variable in your dataset.

ui <- dashboardPage(
  
  #REPLACE 'TITLE HERE' BELOW WITH YOUR OWN TITLE
  dashboardHeader(title = "TITLE HERE"),
  #REPLACE 'TITLE HERE' ABOVE WITH YOUR OWN TITLE
  
  dashboardSidebar(
      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(
      infoBoxOutput("value1", width = 4),
      infoBoxOutput("value2", width = 4),
      infoBoxOutput("value3", width = 4),
   
      box(plotOutput("plot1")),
      box(plotOutput("plot2")),
      box(plotOutput("plot3")),
      box(plotOutput("plot4"))

  )
)

In each of your functions below, you are going to add a filter statement, filtering to the user input. You may begin by copying and pasting your server function from lab 6 into this section. Then you are going to add the filter condition that I’ve listed below to each calculation and plot:

  filter(
    STATE == input$geo_val & 
    SOURCEDATE > input$date_val[1] &
    SOURCEDATE < input$date_val[2]
    )
    

Be sure to replace STATE with your geographic variable and SOURCEDATE with your temporal variable in the above filter condition.

server <- function(input, output) {
  
  output$value1 <- renderInfoBox({
    quant_insight1 <-
    #REPLACE BELOW WITH YOUR OWN CODE
    hospitals %>% 
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%      
      filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
      summarize(median_value = median(BEDS, na.rm = TRUE))
    #REPLACE ABOVE WITH YOUR OWN CODE
    
    #REPLACE 'FILL DESCRIPTION HERE' BELOW WITH YOUR OWN DESCRIPTION
    infoBox(quant_insight1,'FILL DESCRIPTION HERE', icon = icon("stats", lib='glyphicon'), color = "purple")
    #REPLACE 'FILL DESCRIPTION HERE' ABOVE WITH YOUR OWN DESCRIPTION
  })
  
  output$value2 <- renderInfoBox({
    quant_insight2 <- 
    #REPLACE BELOW WITH YOUR OWN CODE
    hospitals %>% 
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
      filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
      summarize(median_value = median(BEDS, na.rm = TRUE))
    #REPLACE ABOVE WITH YOUR OWN CODE 
    
    #REPLACE 'FILL DESCRIPTION HERE' BELOW WITH YOUR OWN DESCRIPTION
    infoBox(quant_insight2,'FILL DESCRIPTION HERE', icon = icon("stats", lib='glyphicon'), color = "purple")
    #REPLACE 'FILL DESCRIPTION HERE' ABOVE WITH YOUR OWN DESCRIPTION
  })
  
  output$value3 <- renderInfoBox({
    quant_insight3 <- 
    #REPLACE BELOW WITH YOUR OWN CODE
    hospitals %>% 
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
      filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
      summarize(median_value = median(BEDS, na.rm = TRUE))
    #REPLACE ABOVE WITH YOUR OWN CODE 
    
    #REPLACE 'FILL DESCRIPTION HERE' BELOW WITH YOUR OWN DESCRIPTION
    infoBox(quant_insight3,'FILL DESCRIPTION HERE', icon = icon("stats", lib='glyphicon'), color = "purple")
    #REPLACE 'FILL DESCRIPTION HERE' ABOVE WITH YOUR OWN DESCRIPTION
  })
  
  
  output$plot1 <- renderPlot({
    #REPLACE BELOW WITH YOUR OWN PLOT
    hospitals %>% 
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
      ggplot(aes(x = TYPE)) + geom_bar()
    #REPLACE ABOVE WITH YOUR OWN PLOT 
    
  })
  
  output$plot2 <- renderPlot({
    #REPLACE BELOW WITH YOUR OWN PLOT
    hospitals %>% 
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
      ggplot(aes(x = TYPE)) + geom_bar()
    #REPLACE ABOVE WITH YOUR OWN PLOT 
  })
  
  output$plot3 <- renderPlot({
    #REPLACE BELOW WITH YOUR OWN PLOT
    hospitals %>% 
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
      ggplot(aes(x = TYPE)) + geom_bar()
    #REPLACE ABOVE WITH YOUR OWN PLOT  
    
  })
  
  output$plot4 <- renderPlot({
    #REPLACE BELOW WITH YOUR OWN PLOT
    hospitals %>% 
      filter(
        STATE == input$geo_val & 
        SOURCEDATE > input$date_val[1] &
        SOURCEDATE < input$date_val[2]
        ) %>%
      ggplot(aes(x = TYPE)) + geom_bar()
    #REPLACE ABOVE WITH YOUR OWN PLOT  
  })
  
}
shinyApp(ui, server)

Listening on http://127.0.0.1:6574
NA
LS0tCnRpdGxlOiAiTGFiIDcgLSBHZW9ncmFwaGljIGFuZCBUZW1wb3JhbCBDb250ZXh0IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogJzMnCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIyBJbnN0cnVjdGlvbnMgYW5kIE92ZXJ2aWV3CgpBdCB0aGlzIHBvaW50IGluIHRoZSBxdWFydGVyLCB3ZSBoYXZlIHByb2R1Y2VkIGEgbnVtYmVyIG9mIHBsb3RzIGFuZCBjYWxjdWxhdGUgYSBudW1iZXIgb2YgbWVhc3VyZXMgaW4gcmVnYXJkcyB0byBvdXIgZGF0YS4gTm93LCB3ZSdyZSBnb2luZyB0byBleHBsb3JlIGluIG1vcmUgZGVwdGggaG93IHRoZSBzdG9yaWVzIHRoZSBkYXRhIHRlbGwgY2hhbmdlIGRlcGVuZGluZyBvbiB3aGVyZSB3ZSBsb29rLiBUaGlzIGV4cGxvcmF0aW9uIHdpbGwgdHVybiBpbnRvIHVzZXIgaW5wdXRzIGluIG91ciBTaGlueSBhcHAuIAoKIyMgR2V0dGluZyBTdGFydGVkCgojIyMgTG9hZCB0aGUgcmVsZXZhbnQgbGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoc2hpbnkpCmxpYnJhcnkoc2hpbnlkYXNoYm9hcmQpCmxpYnJhcnkoc2hpbnlXaWRnZXRzKQpgYGAKCiMjIyBJbXBvcnQgYW5kIGNsZWFuIGV4YW1wbGUgZGF0YXNldHMgCgpgYGB7cn0KaG9zcGl0YWxzIDwtIHJlYWQuY3N2KCJodHRwczovL29wZW5kYXRhLmFyY2dpcy5jb20vZGF0YXNldHMvNmFjNWUzMjU0NjhjNGNiOWI5MDVmMTcyOGQ2ZmJmMGZfMC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgp3b3JsZF9oZWFsdGhfZWNvbiA8LSByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2xpbmRzYXlwb2lyaWVyL1NUUy0xMTUvbWFzdGVyL2RhdGFzZXRzL3dvcmxkX2hlYWx0aF9lY29uLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmNhc2VzIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkvbWFzdGVyL2Nzc2VfY292aWRfMTlfZGF0YS9jc3NlX2NvdmlkXzE5X3RpbWVfc2VyaWVzL3RpbWVfc2VyaWVzX2NvdmlkMTlfY29uZmlybWVkX2dsb2JhbC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojRG8gbm90IHdvcnJ5IGFib3V0IHRoaXMgbGluZSBvZiBjb2RlIGZvciBub3cuIFNpbmNlIHRoZSBjYXNlcyBkYXRhIGdldHMgYXBwZW5kZWQgZXZlcnkgZGF5IHdpdGggYSBuZXcgY29sdW1uIHJlcHJlc2VudGluZyB0aGF0IGRheSdzIGNhc2UgY291bnRzLCBpZiB3ZSB3YW50IHRoZSB0b3RhbCBjYXNlcyBwZXIgY291bnRyeSwgd2UgbmVlZCB0byBhZGQgdXAgYWxsIG9mIHRoZSBwcmV2aW91cyBkYXkncyBjb3VudHMgaW50byBhIG5ldyBjb2x1bW4uIFRoZSBjb2x1bW4gYmVsb3cgZG9lcyB0aGlzIGZvciB1cy4gCmNhc2VzIDwtIAogIGNhc2VzICU+JSAKICBtdXRhdGUoVG90YWwuQ2FzZXMgPSAKICAgICAgICAgICBjYXNlcyAlPiUgCiAgICAgICAgICAgc2VsZWN0KHN0YXJ0c193aXRoKCJYIikpICU+JSAKICAgICAgICAgICByb3dTdW1zKCkKICAgICAgICAgKSAlPiUKICBzZWxlY3QoUHJvdmluY2UuU3RhdGUsIENvdW50cnkuUmVnaW9uLCBUb3RhbC5DYXNlcykKCmhvc3BpdGFscyRaSVAgPC0gYXMuY2hhcmFjdGVyKGhvc3BpdGFscyRaSVApCgpob3NwaXRhbHMkWklQIDwtIHN0cl9wYWQoaG9zcGl0YWxzJFpJUCwgNSwgcGFkID0gIjAiKSAKCmlzLm5hKGhvc3BpdGFscykgPC0gaG9zcGl0YWxzID09ICJOT1QgQVZBSUxBQkxFIgppcy5uYShob3NwaXRhbHMpIDwtIGhvc3BpdGFscyA9PSAtOTk5CmlzLm5hKGNhc2VzKSA8LSBjYXNlcyA9PSAiIgoKaG9zcGl0YWxzJFNPVVJDRURBVEUgPC0geW1kX2htcyhob3NwaXRhbHMkU09VUkNFREFURSkKaG9zcGl0YWxzJFZBTF9EQVRFIDwtIHltZF9obXMoaG9zcGl0YWxzJFZBTF9EQVRFKQpgYGAKCiMjIyBJbXBvcnQgYW5kIGNsZWFuIHlvdXIgZGF0YXNldC4gCgpgYGB7cn0KI0NvcHkgYW5kIHBhc3RlIHJlbGV2YW50IGNvZGUgZnJvbSBMYWIgNCB0byBpbXBvcnQgeW91ciBkYXRhIGhlcmUuIAoKI0NvcHkgYW5kIHBhc3RlIHJlbGV2YW50IGNvZGUgZnJvbSBMYWIgNCB0byBjbGVhbiB5b3VyIGRhdGEgaGVyZS4gVGhpcyBpbmNsdWRlcyBhbnkgcm93IGJpbmRpbmcsIGNoYXJhY3RlciByZW1vdmFscywgY29udmVyaW9ucyBpbiB2YXJpYWJsZSB0eXBlLCBkYXRlIGZvcm1hdHRpbmcsIG9yIE5BIGNvbnZlcnNpb25zLiAKYGBgCgojIyBGYWNldHMKClRvIGdldCB1cyBzdGFydGVkIGluIHB1dHRpbmcgb3VyIGRhdGEgaW50byBjb250ZXh0LCB3ZSBhcmUgZ29pbmcgdG8gbG9vayBhdCBzb21lIG9mIHRoZSBwbG90cyB3ZSBwcm9kdWNlZCBpbiBwcmV2aW91cyBsYWJzIGdyb3VwZWQgYWNjb3JkaW5nIHRvIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgaW4gb3VyIGRhdGFzZXQuIAoKQnkgKmZhY2V0aW5nKiBwbG90cywgd2Ugc3BsaXQgdGhlbSBpbnRvIGEgc2VyaWVzIG9mIHBhbmVscyBlYWNoIHJlcHJlc2VudGluZyB0aGUgZ3JvdXBlZCBkYXRhIGFzc29jaWF0ZWQgd2l0aCBhIHBhcnRpY3VsYXIgdmFsdWUgaW4gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZS4gTGV0J3Mgc3RhcnQgd2l0aCBhbiBlYXN5IGV4YW1wbGUgZnJvbSBvdXIgaG9zcGl0YWxzIGRhdGEgLSBmYWNldGluZyBhIGJhciBwbG90IG9mIHRoZSBudW1iZXIgb2YgaG9zcGl0YWxzIHRoYXQgaGF2ZSBhIGhlbGlwYWQgYnkgc3RhdGUuIApXZSBjYW4gZmFjZXQgYSBwbG90IGJ5IGFkZGluZzogKyBmYWNldF93cmFwKH5WQVJJQUJMRV9OQU1FKSB0byB0aGUgY2FsbC4gCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI2RmICU+JSBnZ3Bsb3QoYWVzKHggPSBDQVRFR09SSUNBTF9WQVJJQUJMRSkpICsgZ2VvbV9iYXIoKSArIGZhY2V0X3dyYXAofkNBVEVHT1JJQ0FMX1ZBUklBQkxFKQoKI3dpdGhvdXQgZmFjZXRfd3JhcCgpCmhvc3BpdGFscyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gSEVMSVBBRCkpICsgCiAgZ2VvbV9iYXIoKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGJ5IEhlbGlwYWQgU3RhdHVzIiwgeCA9IkhlbGlwYWQiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIgKSArCiAgdGhlbWVfYncoKQoKI3dpdGggZmFjZXRfd3JhcCgpCmhvc3BpdGFscyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gSEVMSVBBRCkpICsgCiAgZ2VvbV9iYXIoKSArCiAgZmFjZXRfd3JhcCh+U1RBVEUpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgYnkgSGVsaXBhZCBTdGF0dXMiLCB4ID0iSGVsaXBhZCIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIiApICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xLCBzaXplID0gNiksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSkgCiAgCmBgYAoKVGhlIGZpcnN0IHBsb3Qgc3VnZ2VzdHMgdGhhdCBtb3JlIGhvc3BpdGFscyBoYXZlIGhlbGlwYWRzIHRoYW4gdGhvc2UgdGhhdCBkb24ndC4gR3JvdXBpbmcgdGhpcyBieSBzdGF0ZSwgaG93ZXZlciwgd2UgY2FuIHNlZSB0aGF0IGluIHNvbWUgc3RhdGVzIChsaWtlIENhbGlmb3JuaWEgYW5kIE5ldyBZb3JrKSwgbW9yZSBob3NwaXRhbHMgZG9uJ3QgaGF2ZSBoZWxpcGFkcyB0aGFuIHRob3NlIHRoYXQgZG8uIEZhY2V0aW5nIGNhbiBoZWxwIHVzIHpvb20gaW50byB0aGUgZGF0YSBmb3IgbW9yZSBnZW9ncmFwaGljIHNwZWNpZmljaXR5LiAKCkxldCdzIGFsc28gZmFjZXQgZGF0YSBieSBhIHRlbXBvcmFsIHZhcmlhYmxlLiBBc3N1bWluZyB3ZSBoYXZlIGFscmVhZHkgY29udmVydGVkIGEgZGF0ZS90aW1lIHZhcmlhYmxlIGluIG91ciBkYXRhc2V0IGludG8gYSBkYXRhL3RpbWUgZm9ybWF0ICh1c2luZyBsdWJyaWRhdGUgaW4gbGFiIDQpLCB3ZSBzaG91bGQgYmUgYWJsZSB0byBleHRyYWN0IGEgeWVhciwgbW9udGgsIGRheSAoYW5kIGlmIGF2YWlsYWJsZSBob3VyLCBtaW51dGUsIGFuZCBzZWNvbmQpIGZyb20gdGhlIGRhdGEgdXNpbmcgdGhlc2UgbHVicmlkYXRlIGZ1bmN0aW9uczoKCiogeWVhcihEQVRFX1ZBUklBQkxFKSB3aWxsIGV4dHJhY3QgdGhlIHllYXIgZnJvbSB0aGUgZGF0ZQoqIG1vbnRoKERBVEVfVkFSSUFCTEUpIHdpbGwgZXh0cmFjdCB0aGUgbW9udGggZnJvbSB0aGUgZGF0ZQoqIGRheShEQVRFX1ZBUklBQkxFKSB3aWxsIGV4dHJhY3QgdGhlIGRheSBmcm9tIHRoZSBkYXRlCiogLi4uIGFuZCBzbyBvbgoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiN3aXRob3V0IGZhY2V0X3dyYXAoKQpob3NwaXRhbHMgJT4lIAogIGdncGxvdChhZXMoeCA9IFNUQVRVUykpICsgCiAgZ2VvbV9iYXIoKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGJ5IFN0YXR1cyIsIHggPSJTdGF0dXMiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIgKSArCiAgdGhlbWVfYncoKQoKI3dpdGggZmFjZXRfd3JhcCgpCmhvc3BpdGFscyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gU1RBVFVTKSkgKyAKICBnZW9tX2JhcigpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgYnkgU3RhdHVzIiwgeCA9IlN0YXR1cyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIiApICsKICBmYWNldF93cmFwKH55ZWFyKFNPVVJDRURBVEUpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MSwgc2l6ZSA9IDYpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpIApgYGAKRmFjZXRpbmcgdGhpcyBwbG90IGJ5IHRoZSB5ZWFyIGluIHdoaWNoIHRoZSBkYXRhIHdhcyBzb3VyY2VkIGhlbHBzIHB1dCB0aGUgU1RBVFVTIGZpZWxkIGludG8gY29udGV4dC4gV2UgY2FuIHNlZSB0aGF0IHRoZSB2YXN0IG1ham9yaXR5IG9mIHRoZSBkYXRhIHJlcHJlc2VudGVkIGluIHRoZSBwbG90IHdhcyBzb3VyY2VkIGluIDIwMTguIFdlIGtub3cgdGhhdCBob3NwaXRhbHMgYWNyb3NzIHRoZSBjb3VudHJ5IGFyZSBub3Qgb3BlbiBvciBjbG9zZWQgaW4gcGVycGV0dWl0eSwgc28gd2UgbmVlZCB0byB0YWtlIHRoZSB0ZW1wb3JhbCBjb250ZXh0IG9mIHRoZSBkYXRhIGludG8gY29uc2lkZXJhdGlvbiB3aGVuIHByZXNlbnRpbmcgb3VyIHJlc3VsdHMuIAoKSWYgd2UgaGF2ZSBxdWFsaWZpZWQgb2JzZXJ2YXRpb25hbCB1bml0cyBpbiBvdXIgZGF0YXNldCwgZmFjZXRpbmcgYWxsb3dzIHVzIHRvIGdyb3VwIGRhdGEgYnkgb25lIG9mIHRoZSBxdWFsaWZ5aW5nIHZhcmlhYmxlcyBhbmQgZGlzcGxheSB0aGUgZGF0YSBhcyBhIHNldCBvZiBzaWRlLWJ5LXNpZGUgcGxvdHMuICBGb3IgaW5zdGFuY2UsIHJlbWVtYmVyIGhvdyB3ZSBoYXZlIGJlZW4gZmlsdGVyaW5nIHRvIHRoZSBtb3N0IHJlY2VudCB5ZWFyIGRhdGEgd2FzIHJlcG9ydGVkIHdoZW4gcGxvdHRpbmcgdGhlIHdvcmxkX2hlYWx0aF9lY29uIGRhdGEuIEluc3RlYWQsIHdlIGNvdWxkIGZhY2V0KCkgdGhlIGRhdGEgdG8gZGVtb25zdHJhdGUgaG93IGRpZmZlcmVudCBoZWFsdGggZWNub21pY3MgaW5kaWNhdG9ycyBjaGFuZ2Ugb3ZlciB0aW1lLiAKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQp3b3JsZF9oZWFsdGhfZWNvbiAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0b3RfaGVhbHRoX3NwX3BwLCB5ID0gbGlmZV9leHAsIHNpemUgPSBwb3AsIGNvbCA9IGNvbnRpbmVudCkpICsgCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzdHJva2UgPSAwLjUpICsKICBmYWNldF93cmFwKH55ZWFyKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBDb3VudHJ5IFRvdGFsIEhlYWx0aCBTcGVuZGluZyBQZXIgUGVyc29uIGFuZCBMaWZlIEV4cGVjdGFuY3kiLCB4ID0gIlRvdGFsIEhlYWx0aCBTcGVuZGluZyBQZXIgUGVyc29uIiwgeSA9ICJMaWZlIEV4cGVjdGFuY3kiLCBzaXplID0gIlBvcHVsYXRpb24iLCBjb2wgPSAiQ29udGluZW50IikgKyAjIFRvIGFkZCB0aXRsZXMgYW5kIGxhYmVscwogIHRoZW1lX2J3KCkgKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMSwgMTApLCBsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKQpgYGAKCkNvcHkgYW5kIHBhc3RlIGEgcGxvdCBmcm9tIG9uZSBvZiB5b3VyIHByZXZpb3VzIGxhYnMuIFRoZW4gY29weSBpdCBhZ2FpbiBhbmQgZmFjZXQgaXQgYnkgYSBnZW9ncmFwaGljIG9yIHRlbXBvcmFsIHZhcmlhYmxlLiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojZGYgJT4lIGdncGxvdChhZXMoeCA9IENBVEVHT1JJQ0FMX1ZBUklBQkxFKSkgKyBnZW9tX2JhcigpICsgZmFjZXRfd3JhcCh+Q0FURUdPUklDQUxfVkFSSUFCTEUpCgojQ29weSBhbmQgcGFzdGUgYSBwcmV2aW91bHN5IGNyZWF0ZWQgcGxvdCBoZXJlLiAKCiNDb3B5IHRoYXQgcGxvdCBhZ2FpbiBhbmQgZmFjZXQgaXQgYnkgYSBnZW9ncmFwaGljIG9yIHRlbXBvcmFsIHZhcmlhYmxlLiBBZGp1c3QgdGhlIHRoZW1lIGFzIEkgaGF2ZSBhYm92ZSB0byBtYWtlIHlvdXIgcGxvdCBtb3JlIGxlZ2libGUuICAKYGBgCgpIb3cgZG8gdGhlIHN0b3JpZXMgdGhhdCB0aGUgdHdvIHBsb3RzIHRlbGwgZGlmZmVyPyBXaGF0IGRvZXMgeW91ciBmaXJzdCBwbG90IHRlbGwgeW91IGFib3V0IHRoZSBnZW8tcG9saXRpY2FsIGxhbmRzY2FwZSBvZiB0aGUgaXNzdWUgeW91IGFyZSBzdHVkeWluZz8gLSBPUiAtIFdoYXQgZG9lcyB0aGUgZmlyc3QgcGxvdCB0ZWxsIHlvdSBhYm91dCB0aGUgdGVtcG9yYWwgbGFuZHNjYXBlIG9mIHRoZSBpc3N1ZSB5b3UgYXJlIHN0dWR5aW5nPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKClJlcGVhdCB0aGUgZXhlcmNpc2UgeW91IGNvbXBsZXRlZCBhYm92ZSBmb3IgYSBzZWNvbmQgcGxvdCB5b3UgY3JlYXRlZCBpbiBhIHByZXZpb3VzIGxhYi4gIAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gQ0FURUdPUklDQUxfVkFSSUFCTEUpKSArIGdlb21fYmFyKCkgKyBmYWNldF93cmFwKH5DQVRFR09SSUNBTF9WQVJJQUJMRSkKCiNDb3B5IGFuZCBwYXN0ZSBhIHByZXZpb3Vsc3kgY3JlYXRlZCBwbG90IGhlcmUuIAoKI0NvcHkgdGhhdCBwbG90IGFnYWluIGFuZCBmYWNldCBpdCBieSBhIGdlb2dyYXBoaWMgb3IgdGVtcG9yYWwgdmFyaWFibGUuIEFkanVzdCB0aGUgdGhlbWUgYXMgSSBoYXZlIGFib3ZlIHRvIG1ha2UgeW91ciBwbG90IG1vcmUgbGVnaWJsZS4gIApgYGAKCkhvdyBkbyB0aGUgc3RvcmllcyB0aGF0IHRoZSB0d28gcGxvdHMgdGVsbCBkaWZmZXI/IFdoYXQgZG9lcyB5b3VyIHNlY29uZCBwbG90IHRlbGwgeW91IGFib3V0IHRoZSBnZW8tcG9saXRpY2FsIGxhbmRzY2FwZSBvZiB0aGUgaXNzdWUgeW91IGFyZSBzdHVkeWluZz8gLSBPUiAtIFdoYXQgZG9lcyB0aGUgc2Vjb25kIHBsb3QgdGVsbCB5b3UgYWJvdXQgdGhlIHRlbXBvcmFsIGxhbmRzY2FwZSBvZiB0aGUgaXNzdWUgeW91IGFyZSBzdHVkeWluZz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgojIyBUaGUgSW1wb3J0YW5jZSBvZiBQbGFjZSBhbmQgVGltZQoKVGltZSBhbmQgcGxhY2Ugb2Z0ZW4gbWF0dGVyIGEgZ3JlYXQgZGVhbCBpbiBob3cgd2UgaW50ZXJwcmV0IGRhdGEuIExldCBtZSBwcm92aWRlIGEgZmV3IGV4YW1wbGVzIHRoYXQgZGVtb25zdHJhdGUgd2h5OgoKIyMjIENhc2UgU3R1ZHkgMTogQ2hyb25vLXBvbGl0aWNzIG9mIENhbGxzIHRvIDMxMSBkdXJpbmcgSHVycmljYW5lIFNhbmR5CgozMTEgaXMgYmFzaWNhbGx5IGEgY3VzdG9tZXIgc2VydmljZSBudW1iZXIgZm9yIGNpdGllcyAtIGEgbnVtYmVyIGZvciByZXNpZGVudHMgYW5kIHZpc2l0b3JzIHRvIHJlcG9ydCBub24tZW1lcmdlbmN5IGlzc3Vlcywgc3VjaCBhcyBwb3Rob2xlcyBhbmQgZ3JhZmZpdGksIHRvIGNpdHkgb2ZmaWNpYWxzLiBJbiBtb3N0IGNpdGllcywgZXZlcnkgY2FsbCB0byAzMTEgZ2V0cyBhZ2dyZWdhdGVkIGluIGEgZGF0YWJhc2UsIGFuZCBpbmNyZWFzaW5nbHksIGNpdHkgb2ZmaWNpYWxzIGFyZSBwZXJmb3JtaW5nIGRhdGEgYW5hbHlzaXMgb24gdGhlIGNhbGxzIHRvIGZpZ3VyZSBvdXQgd2hlcmUgY2VydGFpbiBpc3N1ZXMgaW4gdGhlIGNpdHkgYXJlIGNvbmNlbnRyYXRlZC4gSWYgdGhleSByZWNlaXZlIGEgbnVtYmVyIG9mIGNhbGxzIGFib3V0IG1pc3NlZCBnYXJiYWdlIHBpY2stdXBzIGluIGEgY2VydGFpbiBjb21tdW5pdHksIHRoZXkgbWF5IGRpdmVydCBhdHRlbnRpb24gYW5kIHJlc291cmNlcyB0aGVyZSBmb3IgaW1wcm92ZWQgc2FuaXRhdGlvbi4gT2Z0ZW4gdGhpcyBkYXRhIGlzIHB1YmxpY2x5IGFjY2Vzc2libGUgZm9yIGNvbW11bml0aWVzIHRvIGFuYWx5emUuIAoKV2hlbiBIdXJyaWNhbmUgU2FuZHkgaGl0IE5ZQyBpbiAyMDEyLCB0aGUgQ2l0eSBsZXZlcmFnZWQgZGF0YSBhYm91dCBjYWxscyBOZXcgWW9ya2VycyBoYWQgbWFkZSB0byAzMTEgdG8gdHJhY2sgd2hlcmUgYSBudW1iZXIgb2YgZGlmZmVyZW50IGlzc3VlcyB3ZXJlIG9jY3VycmluZy4gSSd2ZSBpbmNsdWRlZCBhIHNhbXBsZSBvZiB0aGF0IGRhdGEgcmVnYXJkaW5nIGNhbGxzIGFib3V0IGRhbWFnZWQgdHJlZXMgYW5kIGxhY2sgb2YgaGVhdCBhbmQgaG90IHdhdGVyIGluIGFwYXJ0bWVudHMgaW4gYSBkYXRhc2V0IGJlbG93LgoKYGBge3J9CmxpYnJhcnkoc2NhbGVzKQpueWMzMTEgPC0gcmVhZC5jc3YoImh0dHBzOi8vZ2l0aHViLmNvbS9saW5kc2F5cG9pcmllci9TVFMtMTE1L2Jsb2IvbWFzdGVyL2RhdGFzZXRzLzMxMV9iZWZvcmVfMjAxNS5jc3Y/cmF3PXRydWUiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpIApueWMzMTEgJT4lIGhlYWQoMTApCmBgYAoKVmlzdWFsaXppbmcgZGF0YSBhYm91dCAzMTEgY2FsbHMgaW4gdGhlIHRocmVlIG1vbnRocyBmb2xsb3dpbmcgdGhlIGRpc2FzdGVyIGluZGVlZCBzaG93ZWQgYSBzcGlrZSBpbiBjb21wbGFpbnRzIGFib3V0IGlzc3VlcyBsaWtlIGRhbWFnZWQgdHJlZXMgYW5kIGxhY2sgb2YgaGVhdCBpbiBhcGFydG1lbnQgYnVpbGRpbmdzIHRocm91Z2hvdXQgdGhlIGNpdHkuIExldmVyYWdpbmcgdGhpcyBkYXRhLCB0aGUgY2l0eSB3YXMgYWJsZSB0byBwb3NpdGlvbiB0aGUgZGV2YXN0YXRpb24gb2YgdGhlIGRpc2FzdGVyIGFzIGVwaXNvZGljIC0gYSByZXN1bHQgb2YgbmF0dXJhbCBmb3JjZXMgYmV5b25kIHRoZWlyIGNvbnRyb2wuCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KbnljMzExICU+JSAKICBmaWx0ZXIoeWVhcihDcmVhdGVkLkRhdGUpID09IDIwMTIgJiBtb250aChDcmVhdGVkLkRhdGUpICVpbiUgYyg3OjExKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYXMuRGF0ZShDcmVhdGVkLkRhdGUpLCBncm91cCA9IDEpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWFzLkRhdGUoYygiMjAxMi0xMC0yOSIpKSxsaW5ldHlwZT00LCBjb2xvdXI9ImJsYWNrIikgKwogIGdlb21fbGluZShzdGF0PSJjb3VudCIpICsgCiAgZmFjZXRfd3JhcCh+Q29tcGxhaW50LlR5cGUpICsgCiAgbGFicyh4PSJNb250aCIsIHk9IkNvdW50IikgKwogIHNjYWxlX3hfZGF0ZSgpICsKICB0aGVtZV9idygpICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IGFzLkRhdGUoIjIwMTItMTAtMjkiKSwgeSA9IDQwMDAsIGxhYmVsID0gIkh1cnJpY2FuZSBTYW5keSIsIGFuZ2xlID0gOTApCmBgYAoKSG93ZXZlciwgc29jaWFsIHJlc2VhcmNoZXJzIGhhdmUgYXJndWVkIHRoYXQgaXQgaXMgbm90IHNvIHNpbXBsZSB0byBkZWxpbWl0IHRoZSB0ZW1wb3JhbCBib3VuZGFyaWVzIG9mIGEgZGlzYXN0ZXIuIFdoaWxlIGEgbmF0dXJhbCBldmVudCBtYXkgaGFwcGVuIG9uIGEgcGFydGljdWxhciBkYXkgb3Igc3BhbiBvZiBkYXlzLCB0aGUgc3RydWN0dXJhbCBjb25kaXRpb25zIG9mIHRoZSBjb21tdW5pdGllcyB0aGV5IGltcGFjdCBoYXZlIG11Y2ggbG9uZ2VyIHRpbWVzcGFucy4gTmF0dXJhbCBldmVudHMgb2NjdXJyaW5nIGluIGRlbGltaXRlZCBwZXJpb2RzIG9mIHRpbWUgb2Z0ZW4gZXhhY2VyYmF0ZSBleGlzdGluZyBzb2NpYWwgaXNzdWVzIGxpa2UgcG92ZXJ0eSwgbGFjayBvZiBhZmZvcmRhYmxlIGhvdXNpbmcsIGFuZCB1bmVxdWFsIGFjY2VzcyB0byBoZWFsdGhjYXJlLiAKCkxldCdzIHpvb20gb3V0IG9uIHRoZSAzMTEgZGF0YSB0byBsb29rIGF0IHRoZXNlIGlzc3VlcyBvdmVyIHRoZSBjb3Vyc2Ugb2YgeWVhcnMgdmVyc3VzIHRoZXNlIHRocmVlIG1vbnRocy4gIENvbXBsYWludHMgdG8gMzExIGFib3V0IGRhbWFnZWQgdHJlZXMgZG8gc3Bpa2UgZm9sbG93aW5nIG1vc3QgbWFqb3IgbmF0dXJhbCBldmVudHMuIEhvd2V2ZXIsIGNvbXBsYWludHMgYWJvdXQgbGFjayBvZiBoZWF0IGluIGFwYXJ0bWVudHMgc3Bpa2UgZXZlcnkgeWVhciBpbiBPY3RvYmVyIC4uLmJlY2F1c2UgaW4gTmV3IFlvcmssIHRoYXQncyB3aGVuIGl0IGdldHMgY29sZC4gQnkgb25seSBsb29raW5nIGF0IHRoZSBkYXRhIGluIG1vbnRocyBpbW1lZGlhdGVseSBhZnRlciB0aGUgZGlzYXN0ZXIsIHRoZSBjaXR5IGNvdWxkIG9ic2N1cmUgdGhlIGJpZyBwaWN0dXJlIC0gdGhhdCBwb29yIE5ldyBZb3JrZXJzIGZhY2UgYXBhcnRtZW50IG5lZ2xpZ2VuY2UgZXZlcnkgeWVhciwgbm90IGp1c3QgaW1tZWRpYXRlbHkgZm9sbG93aW5nIGEgaHVycmljYW5lLiBUaGUgdGVtcG9yYWwgY29udGV4dCBpbiB3aGljaCB3ZSBhbmFseXplIGRhdGEgbWF0dGVycyBhIGdyZWF0IGRlYWwgZm9yIGhvdyB3ZSBpbnRlcnByZXQgaXQuIAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9Cm55YzMxMSAlPiUgCiAgZ2dwbG90KGFlcyh4PWFzLkRhdGUoQ3JlYXRlZC5EYXRlKSwgY29sPWFzLmZhY3Rvcih5ZWFyKENyZWF0ZWQuRGF0ZSkpLCBncm91cCA9IHllYXIoQ3JlYXRlZC5EYXRlKSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9YXMuRGF0ZShjKCIyMDEwLTAzLTEyIiwiMjAxMC0wOS0xNiIsIjIwMTEtMDgtMjgiLCIyMDExLTEwLTI5IiwiMjAxMi0xMC0yOSIpKSxsaW5ldHlwZT00LCBjb2xvdXI9ImJsYWNrIikgKwogIGdlb21fbGluZShzdGF0ID0gImNvdW50IikgKyAKICBmYWNldF93cmFwKH5Db21wbGFpbnQuVHlwZSkgKwogIGxhYnMoeD0iTW9udGgiLCBjb2w9IlllYXIiKSArCiAgc2NhbGVfeF9kYXRlKGJyZWFrcyA9ICIzIG1vbnRocyIsIGxhYmVscz1kYXRlX2Zvcm1hdCgiJWItJXkiKSkgKwogIHRoZW1lX2J3KCkgKwogIGFubm90YXRlKGdlb20gPSAibGFiZWwiLCB4ID0gYXMuRGF0ZSgiMjAxMC0wMy0xMiIpLCB5ID0gNDAwMCwgbGFiZWwgPSAibm9yJ2Vhc3RlciIsIGFuZ2xlID0gOTApICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IGFzLkRhdGUoIjIwMTAtMDktMTYiKSwgeSA9IDQwMDAsIGxhYmVsID0gInRvcm5hZG9lcyIsIGFuZ2xlID0gOTApICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IGFzLkRhdGUoIjIwMTEtMDgtMjgiKSwgeSA9IDQwMDAsIGxhYmVsID0gIkh1cnJpY2FuZSBJcmVuZSIsIGFuZ2xlID0gOTApICsKICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwgeCA9IGFzLkRhdGUoIjIwMTEtMTAtMjkiKSwgeSA9IDQ1MDAsIGxhYmVsID0gIkhhbGxvd2VlbiBub3InZWFzdGVyIiwgYW5nbGUgPSA5MCkgKwogIGFubm90YXRlKGdlb20gPSAibGFiZWwiLCB4ID0gYXMuRGF0ZSgiMjAxMi0xMC0yOSIpLCB5ID0gNDAwMCwgbGFiZWwgPSAiSHVycmljYW5lIFNhbmR5IiwgYW5nbGUgPSA5MCkKICAjbm9yJ2Vhc3RlciwgdG9ybmFkb2VzLCBJcmVuZSwgSGFsbG93ZWVuIG5vcidlYXN0ZXIsIFNhbmR5CmBgYAoKPiBTZWU6IExpYm9pcm9uLCBNYXguIDIwMTUuIOKAnERpc2FzdGVyIERhdGEsIERhdGEgQWN0aXZpc206IEdyYXNzcm9vdHMgUmVzcG9uc2VzIHRvIFJlcHJlc2VudGluZyBTdXBlcnN0b3JtIFNhbmR5LuKAnSBJbiBFeHRyZW1lIFdlYXRoZXIgYW5kIEdsb2JhbCBNZWRpYSwgZWRpdGVkIGJ5IEp1bGlhIExleWRhIGFuZCBEaWFuZSBOZWdyYS4gVGF5bG9yICYgRnJhbmNpcyBHcm91cC4gaHR0cHM6Ly9kb2kub3JnLzEwLjQzMjQvOTc4MTMxNTc1NjQ4Ni03LgoKIyMjIENhc2UgU3R1ZHkgMjogR2VvLXBvbGl0aWNzIG9mIENhbGxzIHRvIDMxMSBkdXJpbmcgSHVycmljYW5lIFNhbmR5CgpgYGB7cn0KbGlicmFyeShsZWFmbGV0KQoKbnljMzExICU+JQogIGZpbHRlcihDcmVhdGVkLkRhdGUgPiAiMjAxMi0xMC0yOCIgJiBDcmVhdGVkLkRhdGUgPCAiMjAxMi0xMC0zMCIgJiBDb21wbGFpbnQuVHlwZSA9PSAiRGFtYWdlZCBUcmVlIikgJT4lCiAgbGVhZmxldCgpICU+JSAKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUKICBhZGRNYXJrZXJzKH5Mb25naXR1ZGUsIH5MYXRpdHVkZSwgY2x1c3Rlck9wdGlvbnMgPSBtYXJrZXJDbHVzdGVyT3B0aW9ucygpKQpgYGAKCgojIyMgQ2FzZSBTdHVkeSAzOiBDb3ZpZC0xOSBDYXNlIFJlcG9ydGluZyBieSBDb3VudHJ5CgpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgbnVtYmVyIG9mIENvdmlkLTE5IGNhc2VzIHJlcG9ydGVkIGVhY2ggZGF5IGJ5IGVhY2ggY291bnRyeS4gVG8gZG8gc28sIHdlIHdpbGwgYmUgcmVpbXBvcnRpbmcgdGhlIGNhc2VzIGRhdGEgYXMgYSB0aW1lIHNlcmllcyAtIHRoYXQgaXMsIGFzIGEgZGF0YXNldCB0aGF0IHJlcG9ydHMgdGhlIG51bWJlciBvZiBjYXNlcyBwZXIgZGF5LiBPbiBpbXBvcnQsIGV2ZXJ5IGNvbHVtbiByZXByZXNlbnRzIGEgc3BlY2lmaWMgZGF0ZSBhbmQgdGhlIGNhc2UgdG90YWxzIGZvciB0aGF0IGRhdGUgYXJlIHRoZSB2YWx1ZXMgc3RvcmVkIGluIHRoYXQgY29sdW1uLiAKCmBgYHtyfQpjYXNlc190aW1lX3NlcmllcyA8LSByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NTU0VHSVNhbmREYXRhL0NPVklELTE5L21hc3Rlci9jc3NlX2NvdmlkXzE5X2RhdGEvY3NzZV9jb3ZpZF8xOV90aW1lX3Nlcmllcy90aW1lX3Nlcmllc19jb3ZpZDE5X2NvbmZpcm1lZF9nbG9iYWwuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKaGVhZChjYXNlc190aW1lX3NlcmllcykKYGBgCgojIyMjIEFzaWRlOiBUaWR5aW5nIERhdGEgd2l0aCBHYXRoZXIgCgojIyMjIyBUaGlzIHNlY3Rpb24gaXMganVzdCBGWUkuIFlvdSBtYXkgc2tpcCBpdCBpZiBub3QgaW50ZXJlc3RlZAoKTm90ZSBob3cgdGhlIGNvbHVtbiBoZWFkZXJzIGFyZSBmb3JtYXR0ZWQgYWJvdmUuIFdoZW4gZGF0ZXMgYXJlIHN0b3JlZCBhcyBjb2x1bW4gbmFtZXMgYW5kIG5vdCBhcyB2YWx1ZXMgaW4gYW5kIG9mIHRoZW1zZWx2ZXMsIGl0IGNhbiBiZSB2ZXJ5IGRpZmZpY3VsdCB0byBtYW5pcHVsYXRlIHRoZSBkYXRhIGJhc2VkIG9uIGRhdGVzLiBSZW1lbWJlciB0aGF0IGNvbHVtbiBuYW1lcyBhcmUgbm90IGRhdGEgaW4gYW5kIG9mIHRoZW1zZWx2ZXMgYnV0IGEgcmVmZXJlbmNlIHRvIGEgdmVjdG9yIG9mIHZhbHVlcy4gVGhlIGRhdGVzIGluIHRoaXMgZGF0YXNldCBhcmUgYSByZWZlcmVuY2UgdG8gYSB2ZWN0b3Igb2YgY2FzZSBudW1iZXJzLiBCZWNhdXNlIHRoZSBkYXRlIHZhbHVlcyBhcmUgbm90IHJlcHJlc2VudGVkICppbiogdGhlIGRhdGEsIGJ1dCBvbmx5IGFzIGEgcmVmZXJlbmNlIHRvIGNhc2UgbnVtYmVycywgd2UgY2FuJ3QgZmlsdGVyIG9ic2VydmF0aW9ucyB0byBzcGVjaWZpYyBkYXRlcyBvciB0byBkYXRlcyB0aGF0IGhhcHBlbmVkIGJlZm9yZSBvciBhZnRlciBhbm90aGVyIGRhdGUuIFRoZSBjb2RlIGJlbG93IHJlc2hhcGVzIHRoZSBkYXRhIHNvIHRoYXQgc3VjaCBmaWx0ZXJpbmcgaXMgcG9zc2libGUuICBVc2luZyAqKmdhdGhlcigpKiosIGZvciBldmVyeSBwcm92aW5jZS9jb3VudHJ5IGluIHRoZSBkYXRhc2V0LCBhIG5ldyByb3cgd2lsbCBiZSBjcmVhdGVkIGluIHRoZSBkYXRhc2V0IGZvciBldmVyeSBkYXRlIGRhdGEgd2FzIHJlcG9ydGVkLiBUaGUgcmVzaGFwZWQgZGF0YSB3aWxsIGhhdmUgdHdvIG5ldyBjb2x1bW5zOiBDYXNlLkRhdGUgKHRoZSBkYXRlIHJlcG9ydGVkKSBhbmQgQ2FzZXMgKHRoZSBudW1iZXIgcmVwb3J0ZWQgb24gdGhhdCBkYXRlKS4gQmFzaWNhbGx5LCB3ZSB3aWxsIHRha2Ugd2lkZSBkYXRhIChtYW55IGNvbHVtbnMgd2l0aCBmZXdlciByb3dzKSwgYW5kIHJlc2hhcGUgaXQgaW50byBsb25nIGRhdGEgKGZld2VyIGNvbHVtbnMgd2l0aCBtb3JlIHJvd3MpLiAKCklmIHlvdSdkIGxpa2UgdG8ga25vdyBtb3JlIGFib3V0IGhvdyB0byB1c2UgZ2F0aGVyKCkgdG8gY3JlYXRlIHRpZHkgZGF0YSwgSSBoaWdobHkgcmVjb21tZW5kIFt0aGlzXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3RpZHktZGF0YS5odG1sKSBjaGFwdGVyIGluIFIgZm9yIERhdGEgU2NpZW5jZS4KCllvdSdsbCBhbHNvIG5vdGUgYWJvdmUgdGhhdCBSIGF1dG9tYXRpY2FsbHkgcGxhY2VzIGFuICJYIiBjaGFyYWN0ZXIgaW4gZnJvbnQgb2YgbnVtZXJpYyBjb2x1bW4gbmFtZXMuIEJlbG93IHdlIHJlbW92ZSB0aGF0IFggY2hhcmFjdGVyIGFuZCB0aGVuIHdlIHRyYW5zZm9ybSB0aGUgdmFsdWVzIGludG8gYSBkYXRlLXRpbWUgZm9ybWF0LiAgIAoKYGBge3J9CmNhc2VzX3RpbWVfc2VyaWVzIDwtIGNhc2VzX3RpbWVfc2VyaWVzICU+JSAKICBnYXRoZXIoa2V5ID0gIkNhc2UuRGF0ZSIsIHZhbHVlID0gIkNhc2VzIiwgLVByb3ZpbmNlLlN0YXRlLCAtQ291bnRyeS5SZWdpb24sIC1MYXQsIC1Mb25nKSAlPiUKICBtdXRhdGUoQ2FzZS5EYXRlID0gc3RyX3JlbW92ZShDYXNlLkRhdGUsIHBhdHRlcm4gPSAiWCIpKSAlPiUKICBtdXRhdGUoQ2FzZS5EYXRlID0gbWR5KENhc2UuRGF0ZSkpCgpoZWFkKGNhc2VzX3RpbWVfc2VyaWVzKQpgYGAKCiMjIyMjIFJlam9pbiBoZXJlIGlmIHlvdSBza2lwcGVkIHRoZSBzZWN0aW9uIGFib3ZlLgoKTm93IGxldCdzIHBsb3QgdGhlIHRvdGFsIG51bWJlciBvZiBjYXNlcyByZXBvcnRlZCBlYWNoIGRheSwgZmFjZXRlZCBieSBjb3VudHJ5LiAoVGhpcyBtYXkgdGFrZSBhIGJpdCBvZiB0aW1lIHRvIGxvYWQuKQoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CmNhc2VzX3RpbWVfc2VyaWVzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBDYXNlLkRhdGUsIHkgPSBDYXNlcykpICsgCiAgc3RhdF9zdW1tYXJ5KGdlb20gPSAiY29sIiwgZnVuLnkgPSAic3VtIikgKyAKICBmYWNldF93cmFwKH5Db3VudHJ5LlJlZ2lvbikgKwogIGxhYnModGl0bGUgPSAiVGltZSBTZXJpZXMgb2YgQ2FzZSBDb3VudHMgaW4gdGhlIFVTIGJ5IERheSBhbmQgQ291bnRyeSIsIHggPSAiQ2FzZSBEYXRlIiwgeSA9ICJDYXNlcyIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xLCBzaXplID0gNiksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSAjQ2hhbmdlIGxhYmVscyBmcm9tIHNjaWVudGlmaWMgdG8gY29tbWEgbm90YXRpb24KYGBgCgpPbmUgb2JzZXJ2YXRpb24gdGhhdCBtaWdodCBzdGFuZCBvdXQgaW4gdGhpcyBwbG90IGlzIGp1c3QgaG93IGZldyBjYXNlcyB3ZXJlIHJlcG9ydGVkIGluIFJ1c3NpYSB0aHJvdWdoIG1pZC1NYXJjaC4gQXMgb2YgTWFyY2ggMjQsIDIwMjAsIFJ1c3NpYSBoYWQgcmVwb3J0ZWQgZmV3ZXIgdGhhbiA1MDAgY2FzZXMgb2YgQ292aWQtMTkuIEZvciBhIGNvdW50cnkgY292ZXJpbmcgbW9yZSB0aGFuIDYgbWlsbGlvbiBzcXVhcmUgbWlsZXMsIHdpdGggYSBwb3B1bGF0aW9uIG9mIDE0NSBtaWxsaW9uLCBhbmQgaW4gc3VjaCBjbG9zZSBwcm94aW1pdHkgdG8gQ2hpbmEgd2hlcmUgdGhlIGNhc2UgY291bnRzIGFyZSBoaWdoZXN0LCB0aGVzZSBudW1iZXJzIGFyZSBzdXJwcmlzaW5nbHkgbG93LiBSdXNzaWFuIG9mZmljaWFscyBoYXZlIGNsYWltZWQgdGhhdCBtZWFzdXJlcyB0aGV5IHRvb2sgLSBzdWNoIGFzIHNodXR0aW5nIGRvd24gdGhlIFJ1c3NpYW4gYm9yZGVyIHdpdGggQ2hpbmEgYW5kIHNldHRpbmcgdXAgaXNvbGF0aW9uIHpvbmVzIGZvciBxdWFyYW50aW5lZCBwYXRpZW50cyAtIGhhdmUgaGVscGVkIHRvIGtlZXAgdGhlIHZpcnVzIHVuZGVyIGNvbnRyb2wuIEhvd2V2ZXIsIHNldmVyYWwgbmV3cyByZXBvcnRzIGhhdmUgYmVlbiBwdWJsaXNoZWQgY2FzdGluZyBza2VwdGljaXNtIG9uIHRoZSBudW1iZXJzLCBzdWdnZXN0aW5nIHRoYXQgaW4gUnVzc2lhIHRoZXJlIGlzIGEgd2lkZXNwcmVhZCBjdWx0dXJlIGFnYWluc3QgcHJvZHVjaW5nIGluZm9ybWF0aW9uIHRoYXQgbWF5IGRyYXcgbmVnYXRpdmUgaW50ZXJuYXRpb25hbCBhdHRlbnRpb24uIFRvIGludGVycHJldCB0aGlzIHBsb3QgdGhlbiwgd2UgbmVlZCB0byBoYXZlIGFuIHVuZGVyc3RhbmRpbmcgb2YgZ2xvYmFsICpnZW9wb2xpdGljcyosIG9yIHBvbGl0aWNzIG1lZGlhdGVkIGJ5IGdlb2dyYXBoeSwgZGVtb2dyYXBoeSwgYW5kIGNyb3NzLWJvcmRlciByZWxhdGlvbnMuIFRoZSBudW1iZXJzIHRoYXQgd2Ugc2VlIHJlcG9ydGVkIGluIHNvbWUgcGFydHMgb2YgdGhlIHdvcmxkIHdpbGwgdmFyeSBmcm9tIG51bWJlcnMgcmVwb3J0ZWQgaW4gb3RoZXIgcGFydHMgb2YgdGhlIHdvcmxkLCBub3QgYmVjYXVzZSB0aGUgdmFsdWVzIGFyZSBhY3R1YWxseSBkaWZmZXJlbnQsIGJ1dCBiZWNhdXNlIHRoZXJlIGFyZSBkaWZmZXJlbnQgY3VsdHVyZXMgb2YgcmVwb3J0aW5nIGluIGNlcnRhaW4gY291bnRyaWVzLiAKCkNoYXJhY3Rlcml6ZSB0aGUgZ2VvcG9saXRpY3MgaW4geW91ciBvd24gZGF0YXNldC4gV2h5IG1pZ2h0IGl0IGJlIGltcG9ydGFudCB0byBjb25zaWRlciB0aGUgdmFyaWFibGUgb2YgcGxhY2Ugd2hlbiBpbnRlcnByZXRpbmcgeW91ciBkYXRhPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuCmBgYAoKIyMjIENhc2UgU3R1ZHkgNDogQ292aWQtMTkgQ2FzZXMgb3ZlciBUaW1lCgpOb3cgbGV0J3MgbG9vayBhdCBhIHRpbWUgc2VyaWVzIG9mIGNhc2VzIHJlcG9ydGVkIGluIHRoZSBVUy4gCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KY2FzZXNfdGltZV9zZXJpZXMgJT4lIAogIGZpbHRlcihDb3VudHJ5LlJlZ2lvbiA9PSAiVVMiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBDYXNlLkRhdGUsIHkgPSBDYXNlcykpICsgCiAgc3RhdF9zdW1tYXJ5KGdlb20gPSAiY29sIiwgZnVuLnkgPSAic3VtIikgKwogIGxhYnModGl0bGUgPSAiVGltZSBTZXJpZXMgb2YgQ2FzZSBDb3VudHMgaW4gdGhlIFVTIGJ5IERheSIsIHggPSAiQ2FzZSBEYXRlIiwgeSA9ICJDYXNlcyIpICsKICB0aGVtZV9idygpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgI0NoYW5nZSBsYWJlbHMgZnJvbSBzY2llbnRpZmljIHRvIGNvbW1hIG5vdGF0aW9uCmBgYAoKVGhpcyBwbG90IGluZGljYXRlcyB0aGF0IGZldyBjYXNlcyB3ZXJlIHJlcG9ydGVkIHByaW9yIHRvIG1pZC1NYXJjaC4gSG93ZXZlciwgdG8gcmVzcG9uc2libHkgaW50ZXJwcmV0IHRoaXMgcGxvdCwgd2UgbmVlZCB0byBwYXkgY2xvc2UgYXR0ZW50aW9uIHRvIGhvdyBjYXNlIHRvdGFscyBhcmUgcHJvZHVjZWQuIFRoZSBudW1iZXJzIG9mIGNvbmZpcm1lZCBjYXNlcyByZXBvcnRlZCBpbiB0aGlzIGRhdGFzZXQgYXJlIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgQ292aWQtMTkgdGVzdHMgdGhhdCBhcmUgcmVwb3J0ZWQgcG9zaXRpdmUuIEhvd2V2ZXIsIHRoZSBleHRlbnQgb2YgdGVzdGluZyBpbiB0aGUgVVMgaGFzIGJlZW4gdmFyaWFibGUgc2luY2UgSmFudWFyeSBkdWUgdG8gYSBudW1iZXIgb2YgcG9saXRpY2FsLCByZWd1bGF0b3J5LCBhbmQgbWF0ZXJpYWwgcm9hZGJsb2Nrcy4gVXAgdGhyb3VnaCBGZWJydWFyeSwgdmVyeSBmZXcgdGVzdHMgd2VyZSBiZWluZyBjb25kdWN0ZWQgaW4gdGhlIFVTIGFzIHRoZSBmZWRlcmFsIGdvdmVybm1lbnQgZG93bnBsYXllZCB0aGUgdGhyZWF0IHBvc2VkIGJ5IHRoZSB2aXJ1cy4gQSBzZXJpZXMgb2YgZm9sbG93LXVwIGV2ZW50cyBjb250aW51ZWQgdG8gc2hpZnQgdGhlIHRlc3RpbmcgbGFuZHNjYXBlOgoKKiBGZWJydWFyeSA1OiBUaGUgQ0RDIFtzaGlwcGVkXShodHRwczovL3d3dy50ZWNobm9sb2d5cmV2aWV3LmNvbS9zLzYxNTMyMy93aHktdGhlLWNkYy1ib3RjaGVkLWl0cy1jb3JvbmF2aXJ1cy10ZXN0aW5nLykgY29yb25hdmlydXMgdGVzdCBraXRzIHRvIHN0YXRlIGxhYnMgd2l0aCBjb250YW1pbmF0ZWQgcmVhZ2VudHMuIFRoZXNlIGxhYnMgZW5kZWQgdXAgaGF2aW5nIHRvIHNlbmQgdGhlaXIgc2FtcGxlcyB0byB0aGUgQ0RDIGZvciB0ZXN0aW5nLiAKKiBGZWJydWFyeSAyOXRoOiBVcCB1bnRpbCB0aGlzIHBvaW50LCBGREEgcmVndWxhdGlvbnMgcHJldmVudGVkIGxhYnMgZnJvbSBkZXZlbG9waW5nIHRoZWlyIG93biBjb3JvbmF2aXJ1cyB0ZXN0IGtpdHMuIE9uIEZlYnJ1YXJ5LCAyOXRoLCB0aGlzIHJ1bGUgd2FzIFtsaWZ0ZWRdKGh0dHBzOi8vd3d3LmZkYS5nb3YvbmV3cy1ldmVudHMvcHJlc3MtYW5ub3VuY2VtZW50cy9jb3JvbmF2aXJ1cy1jb3ZpZC0xOS11cGRhdGUtZmRhLWlzc3Vlcy1uZXctcG9saWN5LWhlbHAtZXhwZWRpdGUtYXZhaWxhYmlsaXR5LWRpYWdub3N0aWNzKSBhbGxvd2luZyBoaWdoLWNvbXBsZXhpdHkgbGFicyB0byBkZXZlbG9wIGFuZCBydW4gdGVzdHMgdW5kZXIgd2hhdCBpcyBjYWxsZWQgYW4gRW1lcmdlbmN5IFVzZSBBdXRob3JpemF0aW9uLiAKKiBNYXJjaCAxMnRoOiBVcCB1bnRpbCB0aGlzIHBvaW50LCBpbiBvcmRlciBmb3IgYSBsYWIgdG8gYmVnaW4gdGVzdGluZyBwYXRpZW50cywgdGhleSBuZWVkZWQgdG8gYmUgYXV0aG9yaXplZCBieSB0aGUgRkRBIHRvIGRvIHNvLiBPbiBNYXJjaCAxMiwgdGhlIEZEQSBbZ3JhbnRlZF0oaHR0cHM6Ly93d3cuZmRhLmdvdi9uZXdzLWV2ZW50cy9wcmVzcy1hbm5vdW5jZW1lbnRzL2Nvcm9uYXZpcnVzLWNvdmlkLTE5LXVwZGF0ZS1mZGEtZ2l2ZXMtZmxleGliaWxpdHktbmV3LXlvcmstc3RhdGUtZGVwYXJ0bWVudC1oZWFsdGgtZmRhLWlzc3VlcykgbW9yZSBmbGV4aWJpbGl0eSB0byBzdGF0ZXMgdG8gYXV0aG9yaXplIHRoaXMgdGVzdGluZy4KKiBXaGlsZSB0aGVzZSByZWd1bGF0b3J5IGNoYW5nZXMgcXVpY2tlbmVkIHRoZSBwYWNlIGF0IHdoaWNoIGxhYnMgY291bGQgdGVzdCBwYXRpZW50cywgYXQgdGhpcyBwb2ludCwgYSBuZXcgaXNzdWUgd2FzIGVtZXJnaW5nLiBMYWJzIGJlZ2FuIHJlcG9ydGluZyBbY3JpdGljYWwgc2hvcnRhZ2VzXShodHRwczovL3d3dy5uZXd5b3JrZXIuY29tL25ld3MvbmV3cy1kZXNrL3doeS13aWRlc3ByZWFkLWNvcm9uYXZpcnVzLXRlc3RpbmctaXNudC1jb21pbmctYW55dGltZS1zb29uKSBvZiB0ZXN0aW5nIHN1cHBsaWVzIGFuZCByZWFnZW50cyBmb3IgY29uZHVjdGluZyB0ZXN0cy4gCgpXaXRoIGV2ZXJ5IGNoYW5nZSBpbiB0aGUgdGVzdGluZyBsYW5kc2NhcGUsIHdlIGNhbiBleHBlY3QgdGhhdCB0aGUgbnVtYmVyIG9mIGNhc2VzIHJlcG9ydGVkIHdpbGwgYWxzbyBjaGFuZ2UuIFRvIGludGVycHJldCB0aGlzIHBsb3QsIHdlIG5lZWQgdG8gaGF2ZSBhbiB1bmRlcnN0YW5kaW5nIG9mICpjaHJvbm8tcG9saXRpY3MqLCBvciB0aGUgcG9saXRpY3Mgb2YgdGltZS4gSW1wb3J0YW50bHksIHRoZXNlIHJlZ3VsYXRvcnkgdGltZWxpbmVzIGFyZSBwbGF5aW5nIG91dCBkaWZmZXJlbnRseSBpbiBkaWZmZXJlbnQgY291bnRyaWVzLiBUaGVyZSBpcyBtdWNoIHRvIGNvbnNpZGVyIGF0IHRoZSBpbnRlcnNlY3Rpb24gb2YgZ2VvLXBvbGl0aWNzIGFuZCBjaHJvbm8tcG9saXRpY3MuIAoKQ2hhcmFjdGVyaXplIHRoZSBjaHJvbm8tcG9saXRpY3MgaW4geW91ciBvd24gZGF0YXNldC4gV2h5IG1pZ2h0IGl0IGJlIGltcG9ydGFudCB0byBjb25zaWRlciB0aGUgdmFyaWFibGUgb2YgdGltZSB3aGVuIGludGVycHJldGluZyB5b3VyIGRhdGE/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4KYGBgCgojIyBPdGhlciBDb25mb3VuZGluZyBWYXJpYWJsZXMKClNvbWV0aW1lcywgd2hlbiB3ZSBhcmUgYW5hbHl6aW5nIGRhdGEsIGl0IGNhbiBzZWVtIGFzIHRob3VnaCB0aGVyZSBpcyBhIHN0cm9uZyByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gdmFyaWFibGVzIGluIG91ciBkYXRhc2V0LiBQZXJoYXBzIGxpZmUgZXhwZW5jdGFuY3kgaW5jcmVhc2VzIGFzIHNwZW5kaW5nIG9uIGhlYWx0aCBpbmNyZWFzZXMsIG9yIHBlcmhhcHMgdGhlIG51bWJlciBvZiBzdGFmZiBhdCBhIGhvc3BpdGFsIGluY3JlYXNlcyBhcyB0aGUgbnVtYmVyIG9mIGJlZHMgYXQgdGhlIGhvc3BpdGFsIGluY3JlYXNlcy4gV2UgbWF5IGFzc3VtZSB0aGF0IHRoZXJlIGlzIGlzIGEgY2F1c2FsIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZXNlIHR3byB2YXJpYWJsZXMuICpDb25mb3VuZGluZyB2YXJpYWJsZXMqLCBob3dldmVyLCByZWZlciB0byBhIHRoaXJkIHBoZW5vbWVuYSB0aGF0IGluZmx1ZW5jZXMgdGhlIHJlbGF0aW9uc2hpcCB3ZSBzZWUgYmV0d2VlbiB0d28gdmFyaWFibGVzIGluIGEgZGF0YXNldC4gV2hpbGUgaXQgbWF5IGFwcGVhciBhcyB0aG91Z2ggdHdvIHZhcmlhYmxlcyBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQsIGEgc2hhcmVkIGFzc29jaWF0aW9uIHdpdGggYSBjb25mb3VuZGluZyB2YXJpYWJsZSBtYXkgYmUgbWVkaWF0aW5nIHRoYXQgY29ycmVsYXRpb24uIEJlZm9yZSB3ZSBtYWtlIGFueSBjbGFpbXMgd2l0aCBvdXIgZGF0YSBpdCBpcyBpbXBvcnRhbnQgdGhhdCB3ZSBjb25zaWRlciBzdWNoIHZhcmlhYmxlcy4gCgpGb3IgaW5zdGFuY2UsIGNvbnNpZGVyIGlmIHdlcmUgdG8gbG9vayBhdCBkYXRhIGRvY3VtZW50aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIENvdmlkLTE5IGNhc2VzIGVhY2ggY291bnRyeSBoYXMgcmVwb3J0ZWQgYW5kIHRoZSBudW1iZXIgb2YgZGVhdGhzIGl0IGhhcyByZXBvcnRlZC4gCgpgYGB7cn0KZGVhdGhzIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkvbWFzdGVyL2Nzc2VfY292aWRfMTlfZGF0YS9jc3NlX2NvdmlkXzE5X3RpbWVfc2VyaWVzL3RpbWVfc2VyaWVzX2NvdmlkMTlfZGVhdGhzX2dsb2JhbC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgppcy5uYShkZWF0aHMpIDwtIGRlYXRocyA9PSAiIgoKZGVhdGhzIDwtIAogIGRlYXRocyAlPiUgCiAgbXV0YXRlKFRvdGFsLkRlYXRocyA9IAogICAgICAgICAgIGRlYXRocyAlPiUgCiAgICAgICAgICAgc2VsZWN0KHN0YXJ0c193aXRoKCJYIikpICU+JSAKICAgICAgICAgICByb3dTdW1zKCkKICAgICAgICAgKSAlPiUKICBzZWxlY3QoUHJvdmluY2UuU3RhdGUsIENvdW50cnkuUmVnaW9uLCBUb3RhbC5EZWF0aHMpICU+JQogIHJpZ2h0X2pvaW4oY2FzZXMsIGJ5ID0gYygiUHJvdmluY2UuU3RhdGUiLCAiQ291bnRyeS5SZWdpb24iKSkKCmBgYAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CmRlYXRocyAlPiUgCiAgZ3JvdXBfYnkoQ291bnRyeS5SZWdpb24pICU+JQogIHN1bW1hcml6ZShUb3RhbC5DYXNlcyA9IHN1bShUb3RhbC5DYXNlcywgbmEucm0gPSBUUlVFKSwgVG90YWwuRGVhdGhzID0gc3VtKFRvdGFsLkRlYXRocywgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGdncGxvdChhZXMoeCA9IFRvdGFsLkNhc2VzLCB5ID0gVG90YWwuRGVhdGhzKSkgKyAKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHN0cm9rZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIFRvdGFsIENvdmlkLTE5IERlYXRocyBhbmQgVG90YWwgQ2FzZXMgR2xvYmFsbHkiLCB4ID0gIkNhc2VzIiwgeSA9ICJEZWF0aHMiKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zPSdsb2cxMCcsIGxhYmVscyA9ICBzY2FsZXM6OmNvbW1hKSArCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSdsb2cxMCcsIGxhYmVscyA9IHNjYWxlczo6Y29tbWEpCmBgYAoKS2VlcCBpbiBtaW5kIHRoYXQgZWFjaCBkb3QgYWJvdmUgcmVwcmVzZW50cyBhIGNvdW50cnkuIEJlZm9yZSB3ZSBtYWtlIGFueSBhc3N1bXB0aW9ucyBhYm91dCB0aGUgY2F1c2FsIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZXNlIHR3byB2YXJpYWJsZXMsIHRoZXJlIGFyZSBudW1iZXIgb2YgY29uZm91bmRpbmcgdmFyaWFibGVzIHRvIGNvbnNpZGVyOgoKKiBXaGF0IGlzIHRoZSBtZWRpYW4gYWdlIG9mIHRoZSBwb3B1bGF0aW9uIGluIHRoZSBjb3VudHJ5PwoqIEhvdyBhZHZhbmNlZCBpcyB0aGUgY291bnRyeSdzIGhlYWx0aGNhcmUgc3lzdGVtPwoqIFRvIHdoYXQgZXh0ZW50IGRvIGNpdGl6ZW5zIGluIHRoZSBjb3VudHJ5IGhhdmUgYWNjZXNzIHRvIGhlYWx0aGNhcmU/CiogSG93IHNvb24gd2VyZSBzb2NpYWwgZGlzdGFuY2luZyBwb2xpY2llcyBwdXQgaW50byBwbGFjZSBpbiB0aGUgY291bnRyeT8KKiBIb3cgaXMgdGhlIGNvdW50cnkgZG9jdW1lbnRpbmcgYSBDb3ZpZC0xOSByZWxhdGVkIGNhc2UvZGVhdGg/CiogTm90IHRvIG1lbnRpb24gdGhlIGdlb3BvbGl0aWNzIGFuZCBjaHJvbm9wb2xpdGljcyB3ZSBkZXNjcmliZWQgYWJvdmU/CgpDYW4geW91IGNvbWUgdXAgd2l0aCBvdGhlcnM/CgojIyMgUG9wdWxhdGlvbgoKV2hlbiBjb21wYXJpbmcgY2VydGFpbiBwaGVub21lbmEgYWNyb3NzIHBsYWNlcyAtIHBhcnRpY3Vhcmx5IHBoZW5vbWVuYSB0aGF0IGFyZSByZWxhdGVkIHRvIGh1bWFuIGFjdGl2aXR5IC0gaXQgaXMgb2Z0ZW4gaW1wb3J0YW50IHRvIGNvbnNpZGVyIGhvdyBwb3B1bGF0aW9uIGNhbiBpbXBhY3QgdGhlIG51bWJlcnMgd2Ugc2VlLiBGb3IgaW5zdGFuY2UsIHdoZW4gYXNzZXNzaW5nIHRoZSByZWFkaW5lc3Mgb2YgaG9zcGl0YWxzIHRvIHRha2Ugb24gYW4gaW5mbHV4IG9mIENvdmlkLTE5IHBhdGllbnRzIGFjcm9zcyBjb3VudGllcyBhbmQvb3Igc3RhdGVzIGluIHRoZSBVUywgd2UgbmVlZCB0byBub3Qgb25seSBjb25zaWRlciB0aGUgbnVtYmVyIG9mIGJlZHMgYXZhaWxhYmxlLCBidXQgYWxzbyB0aGUgcG9wdWxhdGlvbiBvZiB0aGUgY291bnR5IGFuZC9vciBzdGF0ZS4gUG9wdWxhdGlvbiBpcyBvbmUgY29uZm91bmRpbmcgdmFyaWFibGUsIGFtb25nIG1hbnksIHRoYXQgd2lsbCBtZWRpYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBob3NwaXRhbCByZWFkaW5lc3MgZm9yIHBhdGllbnQgaW50YWtlIGFuZCB0aGUgbnVtYmVyIG9mIGJlZHMgYXZhaWxhYmxlLiAKCkNvbnNpZGVyIGFub3RoZXIgZXhhbXBsZS4gSW4gMjAxOCwgSSB3YXMgYXQgYSBjb25mZXJlbmNlIGluIEJyb29rbHluLCBsaXN0ZW5pbmcgdG8gYSByZXByZXNlbnRhdGl2ZSBmcm9tIE1hc3RlckNhcmQgZGlzY3VzcyB0aGUgaW1wb3J0YW5jZSBvZiBvcGVuaW5nIHVwIGRhdGEgYW5kIGdldHRpbmcgaXQgaW50byB0aGUgaGFuZHMgb2YgY29tbXVuaXR5IG1lbWJlcnMgdG8gYW5heWx6ZS4gQSBoZWFsdGggcHJhY3RpdGlvbmVyIGZyb20gTllDJ3MgRGVwYXJ0bWVudCBvZiBNZW50YWwgSGVhbHRoIGFuZCBIeWdlaW5lIHN0b29kIHVwIHRvIHZvaWNlIGhpcyBjb25jZXJucyB0byB0aGUgc3BlYWtlci4gSGUgc2FpZCB0aGF0IGl0IHdvcnJpZXMgaGltIHRoYXQgdW50cmFpbmVkIGNvbW11bml0eSBtZW1iZXJzIG1heSBkcmF3IHBvb3IgYXNzdW1wdGlvbnMgZnJvbSB0aGUgZGF0YS4gSGUgZGVzY3JpYmVkIGEgZGF0YXNldCB0aGF0IGRvY3VtZW50ZWQgdGhlIG51bWJlciBtZW50YWwgaGVhbHRoIGRpc2NoYXJnZXMgYnkgbmVpZ2hib3Job29kIGluIE5ldyBZb3JrLCBhbmQgaG93IGl0IGluZGljYXRlZCB0aGF0IHRoZXJlIHdlcmUgZmFyIG1vcmUgZGlzY2hhcmdlcyBpbiBsb3cgaW5jb21lIGNvbW11bml0aWVzLiBUaGlzLCBoZSB3ZW50IG9uLCBjb3VsZCBwb3RlbnRpYWxseSBsZWFkIHNvbWVvbmUgdG8gY29uY2x1ZGUgdGhhdCBwb29yIHBlb3BsZSBhcmUgbW9yZSBsaWtlbHkgdG8gZXhwZXJpZW5jZSBtZW50YWwgaGVhbHRoIGlzc3VlcyBvciB0byBpbnN0aWdhdGUgZ3VuIHZpb2xlbmNlLiBIb3dldmVyLCBoZSB3ZW50IG9uIHRvIGFzc2VydCB0aGF0IG1hbnkgY29tbXVuaXR5IG1lbWJlcnMgbWlnaHQgbm90IGtub3cganVzdCBmcm9tIGxvb2tpbmcgYXQgdGhlIGRhdGEgdGhhdCB0aGVyZSBhcmUgZmFyIG1vcmUgbWVudGFsIGhlYWx0aCBob3NwaXRhbHMgaW4gbG93IGluY29tZSBjb21tdW5pdGllcyBpbiBOWUMgdGhhbiBpbiBoaWdoZXIgaW5jb21lIGNvbW11bml0aWVzLiAuLi5hbmQgdGhhdCB0aGlzIGlzIG9mdGVuIGJlY2F1c2UgaGlnaGVyIGluY29tZSBjb21tdW5pdGllcyBoYXZlIG1vcmUgcG93ZXIgdG8gbG9iYnkgZm9yIGtlZXBpbmcgc3VjaCBob3NwaXRhbHMgb3V0IG9mIHRoZWlyIGJhY2t5YXJkcyEgSW4gdGhpcyBjYXNlLCB0aGUgcHJhY3RpdGlvbmVyIHdhcyBleHByZXNzaW5nIGNvbmNlcm4gdGhhdCBjb21tdW5pdHkgbWVtYmVycyBtYXkgbm90IGNvbnNpZGVyIGEgc2lnbmlmaWNhbnQgY29uZm91bmRpbmcgdmFyaWFibGUgbWVkaWF0aW5nIHRoZSBudW1iZXIgb2YgbWVudGFsIGhlYWx0aCBkaXNjaGFyZ2VzIGFjcm9zcyBOWUMgY29tbXVuaXRpZXM6IHRoZSBudW1iZXIgb2YgaG9zcGl0YWxzIGluIGVhY2ggY29tbXVuaXR5LiAKCkluIHdoYXQgd2F5cyBtaWdodCB0aGUgZGlzdGluY3Qgc2l6ZXMgb3IgcG9wdWxhdGlvbnMgb2YgYSBwbGFjZSBpbXBhY3QgaG93IHlvdSBjb21wYXJlIGlzc3VlcyBhY3Jvc3MgeW91ciBkYXRhPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuCmBgYAoKIyMjIFNlbWFudGljIENoYW5nZXMKCipTZW1hbnRpY3MqIHJlZmVyIHRvIHRoZSBtZWFuaW5nIG9mIHdvcmRzLiBXaGVuIEkgc2F5IHRoZSB3b3JkICdhcHBsZScgeW91IGFyZSBsaWtlbHkgdG8gY29uanVyZSB1cCBhbiBpbWFnZSBpbiB5b3VyIGhlYWQgb2Ygd2hhdCBJIGFtIHJlZmVycmluZyB0by4gSW4gdXNpbmcgdGhlIHdvcmQsIEkgYW0gYXR0ZW1wdGluZyB0byBzaWduaWZ5IHNvbWV0aGluZyB0aGF0IGV4aXN0cyBpbiB0aGUgd29ybGQgc28gdGhhdCB3ZSBib3RoIG1heSBjb21tdW5pY2F0ZSBhYm91dCB0aGF0IHRoaW5nLiBTZW1hbnRpY3MgcmVmZXIgdG8gdGhlIG1lYW5pbmcgYmVoaW5kIHRoaXMgc2lnbmlmaWVyLiBXaGVuIHdlIHdvcmsgd2l0aCBkYXRhLCB3ZSBhcmUgZGVhbGluZyB3aXRoIGEgbnVtYmVyIG9mIHNpZ25pZmllcnMgdGhhdCBoYXZlIGhhdmUgcGFydGljdWxhciBtZWFuaW5ncyBiZWhpbmQgdGhlbS4gCgpXZSBhbHdheXMgdmlldyBkYXRhIGluIGEgcGFydGljdWxhciBtb21lbnQgaW4gdGltZS4gSG93ZXZlciwgb3ZlciB0aW1lLCBvdXIgdW5kZXJzdGFuZGluZyBvZiBwYXJ0aWN1bGFyIHBoZW5vbWVuYSBpbmV2aXRhYmx5IHNoaWZ0cyBhcyB3ZSBnYWluIG1vcmUga25vd2xlZGdlLCBhcyBjdWx0dXJlIGNoYW5nZXMsIG9yIGFzIG5ldyBwaGVub21lbmEgY29tZSBpbnRvIGV4aXN0ZW5jZSBvciBpbnRvIG91ciBhd2FyZW5lc3MuIEFuIGVudGlyZSBzdWItZmllbGQgb2YgYW50aHJvcG9sb2d5IGlzIGRlZGljYXRlZCB0byBzdHVkeWluZyBob3cgbGFuZ3VhZ2UgY2hhbmdlcyBjdWx0dXJhbGx5IG92ZXIgdGltZS4gRm9yIGluc3RhbmNlLCBjb25zaWRlciBob3cgZ2VuZGVyIHByb25vdW5zIGhhdmUgc2hpZnRlZCBhcyB0aGUgcG9saXRpY3Mgb2YgZ2VuZGVyIGhhdmUgYWxzbyBzaGlmdGVkLiBXaGlsZSBoaXN0b3JpY2FsbHksIHRoZSBwcm9ub3VuICJoZSIgd2FzIG9mdGVuIHVzZWQgYXMgYSBnZW5lcmljIHByb25vdW4gaW4gRW5nbGlzaCBsYW5ndWFnZSwgdGhlIGZlbWluaW5zdCBtb3ZlbWVudCBwbGF5ZWQgYSBrZXkgcm9sZSBpbiBzaGlmdGluZyBvdXIgbGFuZ3VhZ2Ugc3lzdGVtcyB0byByZWplY3QgdGhpcyB1c2UgYW5kIHRvIGVuY291cmFnZSBtb3JlIGdlbmRlciBuZXV0cmFsIGxhbmd1YWdlLiBNb3JlIHJlY2VudGx5LCB0cmFuc2dlbmRlciBwcm9ub3VucyBoYXZlIGJlY29tZSBtb3JlIHByZXNlbnQgaW4gb3VyIGxhbmdhdWdlIHN5c3RlbXMsIGluZGljYXRpbmcgdGhlIGNvbnRpbnVpdHkgb2YgY3VsdHVyZSBzaGlmdHMuIAoKUmVzZWFyY2ggaW4gaW5mb3JtYXRpb24gc3R1ZGllcyBoYXMgc2hvd24gaG93IGV2ZW4gY2F0ZWdvcmllcyB0aGF0IGhhdmUgYmVlbiBpbnN0aXR1dGlvbmFsbHkgc3RhbmRhcmRpemVkIGFyZSBjb25zdGFudGx5IGNoYW5naW5nLiBGb3IgaW5zdGFuY2UsIEdlb2ZmcmV5IEJvd2tlciBhbmQgU3VzYW4gTGVpZ2ggU3RhciBoYXZlIHRyYWNlZCBjaGFuZ2VzIGluIHRoZSBJbnRlcm5hdGlvbmFsIENsYXNzaWZpY2F0aW9uIG9mIERpc2Vhc2VzIChvciB0aGUgSUNEKSAtIGEgY29kaW5nL2NsYXNzaWZjYXRpb24gc3lzdGVtIGZvciBkaXNlYXNlcyBtYWludGFpbmVkIGJ5IHRoZSBXb3JsZCBIZWFsdGggT3JnYW5pemF0aW9uLiBNZWRpY2FsIHByb2Zlc3Npb25hbHMgcmVmZXJlbmNlIHRoZSBJQ0QgdG8gZGlhZ25vc2UgcGF0aWVudHMgYmFzZWQgb24gc3ltcHRvbXMgYW5kIHRoZWlyIHNvY2lhbCBjaXJjdW1zdGFuY2VzOyBpbiBvdGhlciB3b3JkcywgZXZlcnkgdGltZSBhbiBpbmRpdmlkdWFsIGlzIGRpYWdub3NlZCB3aXRoIHNvbWV0aGluZywgdGhhdCBzb21ldGhpbmcgaGFzIGFuIGFzc29jaWF0ZWQgY29kZSBpbiB0aGUgSUNELiBUaGUgSUNEIGhhcyBiZWVuIHJldmlzZWQod2l0aCBjb2RlcyBhZGRlZCwgcmVtb3ZlZCwgcmVvcmdhbml6ZWQsIGFuZCBlZGl0ZWQpIHRlbiB0aW1lcyAtIHRoZSBtb3N0IHJlY2VudCB2ZXJzaW9uIG9mIHRoZSBjbGFzc2lmaWNhdGlvbiBzeXN0ZW0gYmVpbmcgSUNELTExLiBUaGVzZSByZXZpc2lvbnMgbm90IG9ubHkgcmVmbGVjdCBuZXcgcmVzZWFyY2ggb24gZGlzZWFzZXMsIGJ1dCBhbHNvIGNoYW5nZXMgaW4gY3VsdHVyZS4gRm9yIGluc3RhbmNlLCBob3cgYWJvcnRpb24gZ2V0cyBjb2RlZCBpbiB0aGUgSUNEIGhhcyBiZWVuIHBvbGl0aWNhbGx5LCBldGhpY2FsbHksIGFuZCByZWxpZ2lvdXNseSBjaGFyZ2VkLiAKCldoaWxlIElDRC0xMSBkb2VzIGhhdmUgYSBjbGFzc2lmaWNhdGlvbiBmb3IgQ292aWQtMTksIElDRC0xMCBkb2VzIG5vdCwgYW5kIElDRC0xMCBpcyBjb25zaWRlcmVkIGN1cnJlbnQgYW5kIGluIHVzZSB1bnRpbCBKYW51YXJ5IDEsIDIwMjIgd2hlbiBpdCB3aWxsIGJlIHJlcGxhY2VkIGJ5IHRoZSBuZXcgdmVyc2lvbi4gVGhpcyBtZWFucyB0aGF0LCBpbiB0aGUgY3VycmVudCBzeXN0ZW0gZm9yIGFzc2lnbmluZyBjb2RlcyB0byBkaWFnbm9zZXMsIHRoZXJlIGlzIG5vIGZvcm1hbCBzaWduaWZpZXIgZm9yIHJlZmVycmluZyB0byB0aGUgZGlzZWFzZS4gQmVjYXVzZSBvZiB0aGlzLCB0aGUgV0hPIGhhZCB0byBhZG1pbmlzdGVyIGFuIGVtZXJnZW5jeSBJQ0QtMTAgY29kZSBmb3IgdXNlIGluIGRpYWdub3NpbmcgcGF0aWVudHMgd2l0aCBDb3ZpZC0xOS4gVGhlIGN1cnJlbnQgbGFuZ3VhZ2Ugc3lzdGVtIGhhZCB0byBhZGFwdCB0byB0aGUgbmV3IGNpcmN1bXN0YW5jZXMgLSBhbmQgaW4gdGhpcyBjYXNlIHZlcnkgcXVpY2tseS4gWW91IGNhbiByZWFkIG1vcmUgYWJvdXQgdGhpcyBbaGVyZV0oaHR0cHM6Ly93d3cud2hvLmludC9jbGFzc2lmaWNhdGlvbnMvaWNkL2NvdmlkMTkvZW4vKS4KCldoZW4gd2UncmUgd29ya2luZyB3aXRoIGRhdGEsIHRoZXNlIGlzc3VlcyBjYW4gbWF0dGVyIGEgZ3JlYXQgZGVhbC4gV2hlbiBjbGFzc2lmaWNhdGlvbnMgY2hhbmdlIGluIG91ciBkYXRhLCBpLmUuIHdoZW4gbmV3IHRlcm1zIGJlY29tZSBhdmFpbGFibGUsIHdoZW4gY2F0ZWdvcmllcyBicmVhayBpbnRvIHR3bywgb3Igd2hlbiBzaWduaWZlcnMgYXJlIHJlbW92ZWQsIGl0IGFsc28gY2hhbmdlcyBob3cgd2UgaW50ZXJwcmV0IHF1YW50aXRpZXMgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGEuIAoKRm9yIGluc3RhbmNlLCB3aGVuIEkgd29ya2VkIGZvciBOWUMncyBjaXZpYyBkYXRhIHRlYW0sIEkgd291bGQgcmVndWxhcmx5IHdvcmsgd2l0aCBvcGVuIDMxMSBkYXRhLiBFdmVyeSAzMTEgY2FsbCBpcyBjb2RlZCB3aXRoIGEgY2VydGFpbiBjYXRlZ29yeSwgc3VjaCBhcyBOb2lzZSwgTm8gSGVhdCBhbmQgSG90IFdhdGVyIGluIEJ1aWxkaW5nLCBSYXQgU2lnaHRpbmcsIG9yIEJyb2tlbiBUcmVlIExpbWIuIFdlIHdvdWxkIG9mdGVuIGZpbHRlciB0aGUgZGF0YSB0byBjZXJ0YWluIGNhdGVnb3JpZXMgYW5kIGNyZWF0ZSBtYXBzIG9mIHRoZSBudW1iZXIgb2YgY29tcGxhaW50cyBkZXJpdmluZyBmcm9tIGRpZmZlcmVudCBuZWlnaGJvcmhvb2RzIGFib3V0IHRoYXQgaXNzdWUuIEhvd2V2ZXIsIHRoZXNlIGNhdGVnb3JpZXMgd2VyZSBjb2xsZWN0aXZlbHkgbWFpbnRhaW5lZCBieSBvdmVyIDcwIGNpdHkgYWdlbmNpZXMgd2hpY2ggd2VyZSBjb25zdGFudGx5IGNoYW5naW5nIGhvdyB0aGV5IHJlY29yZGVkIGlzc3Vlcy4gRm9yIGluc3RhbmNlLCBJbiAyMDE1LCB0aGUgY2F0ZWdvcnkgSEVBVElORyAocmVmZXJyaW5nIHRvIGEgaGVhdGluZyBpc3N1ZSBpbiBhbiBhcGFydG1lbnQpIGNoYW5nZWQgdG8gSEVBVC9IT1QgV0FURVIuIElmIHdlIGRpZCBub3Qga25vdyB0aGF0IHRoZSBjYXRlZ29yaWVzIHdlcmUgY2hhbmdpbmcsIHdlIG1heSBoYXZlIGxvb2tlZCBhdCB0aGUgZGF0YSBhbmQgdGhvdWdodCB0aGF0IHRoZXJlIHdhcyBhIHN1ZGRlbiBkcm9wIG9mZiBpbiBoZWF0aW5nIGNvbXBsYWludHMgb3IgYSBzdWRkZW4gdXB0aWNrIGluIGhvdCB3YXRlciBjb21wbGFpbnRzIC0gd2hlbiBpbiBmYWN0LCBpdCB3YXMganVzdCB0aGUgbGFuZ3VhZ2UgaW4gZW5jb2RlZCBpbiB0aGUgc3lzdGVtIGNoYW5naW5nLiAKCkluIHdoYXQgd2F5cyBoYXZlIHNlbWFudGljcywgYWxvbmcgd2l0aCB0aGUgd29yZHMgdXNlZCB0byByZXByZXNlbnQgY2VydGFpbiBtZWFuaW5ncywgY2hhbmdlZCBvdmVyIHRpbWUgaW4geW91ciBkYXRhc2V0PwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuCmBgYAoKTGFzdCB3ZWVrIHlvdSBsaXN0ZWQgYSBudW1iZXIgb2YgcXVlc3Rpb25zIHRoYXQgeW91ciBxdWFudGl0YXRpdmUgY2FsY3VsYXRpb25zIG1pZ2h0IGhlbHAgeW91IHRvIGFkZHJlc3MuIFNlbGVjdCB0d28gb2YgdGhvc2UgcXVlc3Rpb25zLCBhbmQgbGlzdCB0aGVtIGJlbG93LiBUaGVuIGNvbnNpZGVyIHdoYXQgY29uZm91bmRpbmcgdmFyaWFibGVzIHlvdSBtYXkgbmVlZCB0byBjb25zaWRlciBiZWZvcmUgYXNzdW1pbmcgdGhlIHZhbHVlIHlvdSBjYWxjdWxhdGVkIG9yIHRoZSBwbG90IHlvdSBjcmVhdGVkIGNvdWxkIGFkZXF1YXRlbHkgYWRkcmVzcyB0aGF0IHF1ZXN0aW9uLgoKV2hhdCB3YXMgb25lIHF1ZXN0aW9uIHlvdSBpZGVudGlmaWVkIGxhc3Qgd2Vlaz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLgpgYGAKCldoYXQgY29uZm91bmRpbmcgdmFyaWFibGUgbWlnaHQgeW91IG5lZWQgdG8gY29uc2lkZXIgYmVmb3JlIGFzc3VtaW5nIHlvdXIgY2FsY3VsYXRpb24gY291bGQgYW5zd2VyIHRoYXQgcXVlc3Rpb24/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4KYGBgCgpXaGF0IHdhcyBvbmUgcXVlc3Rpb24geW91IGlkZW50aWZpZWQgbGFzdCB3ZWVrPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuCmBgYAoKV2hhdCBjb25mb3VuZGluZyB2YXJpYWJsZSBtaWdodCB5b3UgbmVlZCB0byBjb25zaWRlciBiZWZvcmUgYXNzdW1pbmcgeW91ciBjYWxjdWxhdGlvbiBjb3VsZCBhbnN3ZXIgdGhhdCBxdWVzdGlvbj8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLgpgYGAKCiMjIENvbnRpbnVlIHlvdXIgc2hpbnkgYXBwLgoKV2UgYXJlIG5vdyBnb2luZyB0byBhZGQgdGhlIGNhcGFjaXR5IGZvciB1c2VycyB0byBzcGVjaWZ5IHNwZWNpZmljIGdlb2dyYXBoaWVzIGFuZCB0aW1lZnJhbWVzIHdoZW4gdmlld2luZyB0aGUgZGF0YSBpbiBvdXIgYXBwLiBXaGlsZSBJIGJlbGlldmUgYWxsIG9mIHlvdSBoYXZlIGEgZ2VvZ3JhcGh5IHJlcHJlc2VudGVkIGluIHlvdXIgZGF0YSwgc29tZSBvZiB5b3UgZG8gbm90IGhhdmUgZGF0ZSBhbmQgdGltZSByZXByZXNlbnRlZCBpbiB5b3VyIGRhdGEuIElmIHRoaXMgaXMgdGhlIGNhc2UsIHlvdSBtYXkgcmVtb3ZlIHRoZSBjb21tZW50ZWQgZGF0YS10aW1lIGlucHV0cyBmcm9tIHRoZSBjb2RlIGJlbG93LiAKCkF0IHRoaXMgcG9pbnQsIHdlIHdpbGwgYmVnaW4gd29ya2luZyBpbiB0aGUgdWkgY29kZSBibG9jayBhbmQgY3JlYXRpbmcgbW9yZSBjcm9zc3RhbGsgYmV0d2VlbiB0aGUgdWkgYW5kIHRoZSBzZXJ2ZXIuIFVzZXJzIHdpbGwgaW5wdXQgaW5mb3JtYXRpb24gaW50byB0aGUgZnJvbnQgZW5kIG9mIHRoZSBhcHAsIGFuZCB0aGF0IGlucHV0IHdpbGwgYmUgY29tbXVuaWNhdGVkIHRvIHRoZSBzZXJ2ZXIuIE1vcmUgc3BlY2lmaWNhbGx5LCB1c2VycyB3aWxsIHNlbGVjdCBhIGdlb2dyYXBoeSBhbmQgYSBkYXRhL3RpbWVmcmFtZSwgYW5kIHRoZSBzZXJ2ZXIgd2lsbCBmaWx0ZXIgdGhlIGRhdGFzZXQgYWNjb3JkaW5nIHRvIHRoZSBzZWxlY3RlZCBmZWF0dXJlcyBhbmQgcmVjcmVhdGUgdGhlIHZhbHVlcy9wbG90cyBvbiB0aGUgZmlsdGVyZWQgZGF0YS4gCgpCZSBzdXJlIHRvIGZvbGxvdyBhbGwgY29tbWVudGVkIGluc3RydWN0aW9ucyBiZWxvdyB0byBhZGQgaW5wdXRzIHRvIHlvdXIgU2hpbnkgYXBwLiAKCmBgYHtyfQpnZW9faW5wdXRfY2hvaWNlcyA8LSAKICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICBob3NwaXRhbHMgJT4lIAogICNSRVBMQUNFIFNUQVRFIEJFTE9XIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRQogIHNlbGVjdChTVEFURSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogICNSRVBMQUNFIFNUQVRFIEJFTE9XIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRQogIGFycmFuZ2UoU1RBVEUpCgojUkVNT1ZFIExJTkVTIEJFTE9XIElGIFlPVSBETyBOT1QgSEFWRSBBIFRFTVBPUkFMIFZBUklBQkxFIElOIFlPVVIgREFUQUZSQU1FCmRhdGVfaW5wdXRfc3RhcnQgPC0gCiAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgaG9zcGl0YWxzICU+JSAKICAjUkVQTEFDRSBTT1VSQ0VEQVRFIEJFTE9XIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICBzdW1tYXJpemUoZGF0ZSA9IG1pbihTT1VSQ0VEQVRFKSkKCmRhdGVfaW5wdXRfZW5kIDwtIAogICNSRVBMQUNFIGhvc3BpdGFscyBCRUxPVyBXSVRIIFlPVVIgT1dOIERBVEFGUkFNRQogIGhvc3BpdGFscyAlPiUgCiAgI1JFUExBQ0UgU09VUkNFREFURSBCRUxPVyBXSVRIIFlPVVIgT1dOIFRFTVBPUkFMIFZBUklBQkxFCiAgc3VtbWFyaXplKGRhdGUgPSBtYXgoU09VUkNFREFURSkpCiNSRU1PVkUgTElORVMgQUJPVkUgSUYgWU9VIERPIE5PVCBIQVZFIEEgVEVNUE9SQUwgVkFSSUFCTEUgSU4gWU9VUiBEQVRBRlJBTUUKYGBgCgpSZXBsYWNlIHRoZSB0aXRsZSB3aXRoIHlvdXIgb3duIGJlbG93LiBBbHNvIGNvbW1lbnQgb3V0IG9yIHJlbW92ZSB0aGUgbGluZXMgcmVnYXJkaW5nIHRoZSB0ZW1wb3JhbCB2YXJpYWJsZSBpZiB5b3UgZG8gbm90IGhhdmUgYSB0ZW1wb3JhbCB2YXJpYWJsZSBpbiB5b3VyIGRhdGFzZXQuCgpgYGB7cn0KdWkgPC0gZGFzaGJvYXJkUGFnZSgKICAKICAjUkVQTEFDRSAnVElUTEUgSEVSRScgQkVMT1cgV0lUSCBZT1VSIE9XTiBUSVRMRQogIGRhc2hib2FyZEhlYWRlcih0aXRsZSA9ICJUSVRMRSBIRVJFIiksCiAgI1JFUExBQ0UgJ1RJVExFIEhFUkUnIEFCT1ZFIFdJVEggWU9VUiBPV04gVElUTEUKICAKICBkYXNoYm9hcmRTaWRlYmFyKAogICAgICBzZWxlY3RJbnB1dChpbnB1dElkID0gImdlb192YWwiLCBsYWJlbCA9ICJTZWxlY3QgYW4gZ2VvZ3JhcGh5OiIsIGNob2ljZXMgPSBnZW9faW5wdXRfY2hvaWNlcywgc2VsZWN0ZWQgPSBnZW9faW5wdXRfY2hvaWNlc1sxXSksCiAgICAgICNSRU1PVkUgTElORSBCRUxPVyBJRiBZT1UgRE8gTk9UIEhBVkUgQSBURU1QT1JBTCBWQVJJQUJMRSBJTiBZT1VSIERBVEFGUkFNRQogICAgICBkYXRlUmFuZ2VJbnB1dChpbnB1dElkID0gImRhdGVfdmFsIiwgbGFiZWwgPSAiU2VsZWN0IGEgZGF0ZSByYW5nZToiLCBzdGFydCA9IGRhdGVfaW5wdXRfc3RhcnQkZGF0ZSwgZW5kID0gZGF0ZV9pbnB1dF9lbmQkZGF0ZSkKICAgICAgI1JFTU9WRSBMSU5FIEFCT1ZFIElGIFlPVSBETyBOT1QgSEFWRSBBIFRFTVBPUkFMIFZBUklBQkxFIElOIFlPVVIgREFUQUZSQU1FCiAgKSwKICAKICBkYXNoYm9hcmRCb2R5KAogICAgICBpbmZvQm94T3V0cHV0KCJ2YWx1ZTEiLCB3aWR0aCA9IDQpLAogICAgICBpbmZvQm94T3V0cHV0KCJ2YWx1ZTIiLCB3aWR0aCA9IDQpLAogICAgICBpbmZvQm94T3V0cHV0KCJ2YWx1ZTMiLCB3aWR0aCA9IDQpLAogICAKICAgICAgYm94KHBsb3RPdXRwdXQoInBsb3QxIikpLAogICAgICBib3gocGxvdE91dHB1dCgicGxvdDIiKSksCiAgICAgIGJveChwbG90T3V0cHV0KCJwbG90MyIpKSwKICAgICAgYm94KHBsb3RPdXRwdXQoInBsb3Q0IikpCgogICkKKQpgYGAKCkluIGVhY2ggb2YgeW91ciBmdW5jdGlvbnMgYmVsb3csIHlvdSBhcmUgZ29pbmcgdG8gYWRkIGEgZmlsdGVyIHN0YXRlbWVudCwgZmlsdGVyaW5nIHRvIHRoZSB1c2VyIGlucHV0LiBZb3UgbWF5IGJlZ2luIGJ5IGNvcHlpbmcgYW5kIHBhc3RpbmcgeW91ciBzZXJ2ZXIgZnVuY3Rpb24gZnJvbSBsYWIgNiBpbnRvIHRoaXMgc2VjdGlvbi4gVGhlbiB5b3UgYXJlIGdvaW5nIHRvIGFkZCB0aGUgZmlsdGVyIGNvbmRpdGlvbiB0aGF0IEkndmUgbGlzdGVkIGJlbG93IHRvIGVhY2ggY2FsY3VsYXRpb24gYW5kIHBsb3Q6CgogICAgICBmaWx0ZXIoCiAgICAgICAgU1RBVEUgPT0gaW5wdXQkZ2VvX3ZhbCAmIAogICAgICAgIFNPVVJDRURBVEUgPiBpbnB1dCRkYXRlX3ZhbFsxXSAmCiAgICAgICAgU09VUkNFREFURSA8IGlucHV0JGRhdGVfdmFsWzJdCiAgICAgICAgKQogICAgICAgIApCZSBzdXJlIHRvIHJlcGxhY2UgU1RBVEUgd2l0aCB5b3VyIGdlb2dyYXBoaWMgdmFyaWFibGUgYW5kIFNPVVJDRURBVEUgd2l0aCB5b3VyIHRlbXBvcmFsIHZhcmlhYmxlIGluIHRoZSBhYm92ZSBmaWx0ZXIgY29uZGl0aW9uLiAgCgpgYGB7cn0Kc2VydmVyIDwtIGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQpIHsKICAKICBvdXRwdXQkdmFsdWUxIDwtIHJlbmRlckluZm9Cb3goewogICAgcXVhbnRfaW5zaWdodDEgPC0KICAgICNSRVBMQUNFIGhvc3BpdGFscyBCRUxPVyBXSVRIIFlPVVIgT1dOIERBVEFGUkFNRQogICAgaG9zcGl0YWxzICU+JSAKICAgICNSRVBMQUNFIFNUQVRFIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRSBBTkQgU09VUkNFREFURSBXSVRIIFlPVVIgT1dOIFRFTVBPUkFMIFZBUklBQkxFCiAgICAgIGZpbHRlcigKICAgICAgICBTVEFURSA9PSBpbnB1dCRnZW9fdmFsICYgCiAgICAgICAgU09VUkNFREFURSA+IGlucHV0JGRhdGVfdmFsWzFdICYKICAgICAgICBTT1VSQ0VEQVRFIDwgaW5wdXQkZGF0ZV92YWxbMl0KICAgICAgICApICU+JSAgICAgIAogICAgI0NPUFkgQU5EIFBBU1RFIFlPVVIgRlVOQ1RJT04gSEVSRSBGUk9NIExBQiA2CiAgICAgIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iICYgVFlQRSA9PSAiR0VORVJBTCBBQ1VURSBDQVJFIikgJT4lCiAgICAgIHN1bW1hcml6ZShtZWRpYW5fdmFsdWUgPSBtZWRpYW4oQkVEUywgbmEucm0gPSBUUlVFKSkKICAgIAogICAgI1JFUExBQ0UgJ0ZJTEwgREVTQ1JJUFRJT04gSEVSRScgQkVMT1cgV0lUSCBZT1VSIE9XTiBERVNDUklQVElPTgogICAgaW5mb0JveChxdWFudF9pbnNpZ2h0MSwnRklMTCBERVNDUklQVElPTiBIRVJFJywgaWNvbiA9IGljb24oInN0YXRzIiwgbGliPSdnbHlwaGljb24nKSwgY29sb3IgPSAicHVycGxlIikKICB9KQogIAogIG91dHB1dCR2YWx1ZTIgPC0gcmVuZGVySW5mb0JveCh7CiAgICBxdWFudF9pbnNpZ2h0MiA8LSAKICAgICNSRVBMQUNFIGhvc3BpdGFscyBCRUxPVyBXSVRIIFlPVVIgT1dOIERBVEFGUkFNRQogICAgaG9zcGl0YWxzICU+JSAKICAgICNSRVBMQUNFIFNUQVRFIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRSBBTkQgU09VUkNFREFURSBXSVRIIFlPVVIgT1dOIFRFTVBPUkFMIFZBUklBQkxFCiAgICAgIGZpbHRlcigKICAgICAgICBTVEFURSA9PSBpbnB1dCRnZW9fdmFsICYgCiAgICAgICAgU09VUkNFREFURSA+IGlucHV0JGRhdGVfdmFsWzFdICYKICAgICAgICBTT1VSQ0VEQVRFIDwgaW5wdXQkZGF0ZV92YWxbMl0KICAgICAgICApICU+JQogICAgI0NPUFkgQU5EIFBBU1RFIFlPVVIgRlVOQ1RJT04gSEVSRSBGUk9NIExBQiA2CiAgICAgIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iICYgVFlQRSA9PSAiR0VORVJBTCBBQ1VURSBDQVJFIikgJT4lCiAgICAgIHN1bW1hcml6ZShtZWRpYW5fdmFsdWUgPSBtZWRpYW4oQkVEUywgbmEucm0gPSBUUlVFKSkKICAgIAogICAgI1JFUExBQ0UgJ0ZJTEwgREVTQ1JJUFRJT04gSEVSRScgQkVMT1cgV0lUSCBZT1VSIE9XTiBERVNDUklQVElPTgogICAgaW5mb0JveChxdWFudF9pbnNpZ2h0MiwnRklMTCBERVNDUklQVElPTiBIRVJFJywgaWNvbiA9IGljb24oInN0YXRzIiwgbGliPSdnbHlwaGljb24nKSwgY29sb3IgPSAicHVycGxlIikKICB9KQogIAogIG91dHB1dCR2YWx1ZTMgPC0gcmVuZGVySW5mb0JveCh7CiAgICBxdWFudF9pbnNpZ2h0MyA8LSAKICAgICNSRVBMQUNFIGhvc3BpdGFscyBCRUxPVyBXSVRIIFlPVVIgT1dOIERBVEFGUkFNRQogICAgaG9zcGl0YWxzICU+JSAKICAgICNSRVBMQUNFIFNUQVRFIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRSBBTkQgU09VUkNFREFURSBXSVRIIFlPVVIgT1dOIFRFTVBPUkFMIFZBUklBQkxFCiAgICAgIGZpbHRlcigKICAgICAgICBTVEFURSA9PSBpbnB1dCRnZW9fdmFsICYgCiAgICAgICAgU09VUkNFREFURSA+IGlucHV0JGRhdGVfdmFsWzFdICYKICAgICAgICBTT1VSQ0VEQVRFIDwgaW5wdXQkZGF0ZV92YWxbMl0KICAgICAgICApICU+JQogICAgI0NPUFkgQU5EIFBBU1RFIFlPVVIgRlVOQ1RJT04gSEVSRSBGUk9NIExBQiA2CiAgICAgIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iICYgVFlQRSA9PSAiR0VORVJBTCBBQ1VURSBDQVJFIikgJT4lCiAgICAgIHN1bW1hcml6ZShtZWRpYW5fdmFsdWUgPSBtZWRpYW4oQkVEUywgbmEucm0gPSBUUlVFKSkKCiAgICAjUkVQTEFDRSAnRklMTCBERVNDUklQVElPTiBIRVJFJyBCRUxPVyBXSVRIIFlPVVIgT1dOIERFU0NSSVBUSU9OCiAgICBpbmZvQm94KHF1YW50X2luc2lnaHQzLCdGSUxMIERFU0NSSVBUSU9OIEhFUkUnLCBpY29uID0gaWNvbigic3RhdHMiLCBsaWI9J2dseXBoaWNvbicpLCBjb2xvciA9ICJwdXJwbGUiKQogIH0pCiAgCiAgb3V0cHV0JHBsb3QxIDwtIHJlbmRlclBsb3QoewogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBQTE9UIEhFUkUgRlJPTSBMQUIgNgogICAgICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgICAgIGdncGxvdChhZXMoeCA9IFRZUEUpKSArIAogICAgICBnZW9tX2JhcigpICsKICAgICAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIpICsgCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgCiAgfSkKICAKICBvdXRwdXQkcGxvdDIgPC0gcmVuZGVyUGxvdCh7CiAgICAjUkVQTEFDRSBob3NwaXRhbHMgQkVMT1cgV0lUSCBZT1VSIE9XTiBEQVRBRlJBTUUKICAgIGhvc3BpdGFscyAlPiUgCiAgICAjUkVQTEFDRSBTVEFURSBXSVRIIFlPVVIgT1dOIEdFT0dSQVBISUMgVkFSSUFCTEUgQU5EIFNPVVJDRURBVEUgV0lUSCBZT1VSIE9XTiBURU1QT1JBTCBWQVJJQUJMRQogICAgICBmaWx0ZXIoCiAgICAgICAgU1RBVEUgPT0gaW5wdXQkZ2VvX3ZhbCAmIAogICAgICAgIFNPVVJDRURBVEUgPiBpbnB1dCRkYXRlX3ZhbFsxXSAmCiAgICAgICAgU09VUkNFREFURSA8IGlucHV0JGRhdGVfdmFsWzJdCiAgICAgICAgKSAlPiUKICAgICNDT1BZIEFORCBQQVNURSBZT1VSIFBMT1QgSEVSRSBGUk9NIExBQiA2CiAgICAgIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICAgICAgZ2dwbG90KGFlcyh4ID0gVFlQRSkpICsgCiAgICAgIGdlb21fYmFyKCkgKwogICAgICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSAKICB9KQogIAogIG91dHB1dCRwbG90MyA8LSByZW5kZXJQbG90KHsKICAgICNSRVBMQUNFIGhvc3BpdGFscyBCRUxPVyBXSVRIIFlPVVIgT1dOIERBVEFGUkFNRQogICAgaG9zcGl0YWxzICU+JSAKICAgICNSRVBMQUNFIFNUQVRFIFdJVEggWU9VUiBPV04gR0VPR1JBUEhJQyBWQVJJQUJMRSBBTkQgU09VUkNFREFURSBXSVRIIFlPVVIgT1dOIFRFTVBPUkFMIFZBUklBQkxFCiAgICAgIGZpbHRlcigKICAgICAgICBTVEFURSA9PSBpbnB1dCRnZW9fdmFsICYgCiAgICAgICAgU09VUkNFREFURSA+IGlucHV0JGRhdGVfdmFsWzFdICYKICAgICAgICBTT1VSQ0VEQVRFIDwgaW5wdXQkZGF0ZV92YWxbMl0KICAgICAgICApICU+JQogICAgI0NPUFkgQU5EIFBBU1RFIFlPVVIgUExPVCBIRVJFIEZST00gTEFCIDYKICAgICAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogICAgICBnZ3Bsb3QoYWVzKHggPSBUWVBFKSkgKyAKICAgICAgZ2VvbV9iYXIoKSArCiAgICAgIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBUeXBlIiwgeCA9ICJUeXBlIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbHMiKSArIAogICAgICB0aGVtZV9idygpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpIAogIH0pCiAgCiAgb3V0cHV0JHBsb3Q0IDwtIHJlbmRlclBsb3QoewogICAgI1JFUExBQ0UgaG9zcGl0YWxzIEJFTE9XIFdJVEggWU9VUiBPV04gREFUQUZSQU1FCiAgICBob3NwaXRhbHMgJT4lIAogICAgI1JFUExBQ0UgU1RBVEUgV0lUSCBZT1VSIE9XTiBHRU9HUkFQSElDIFZBUklBQkxFIEFORCBTT1VSQ0VEQVRFIFdJVEggWU9VUiBPV04gVEVNUE9SQUwgVkFSSUFCTEUKICAgICAgZmlsdGVyKAogICAgICAgIFNUQVRFID09IGlucHV0JGdlb192YWwgJiAKICAgICAgICBTT1VSQ0VEQVRFID4gaW5wdXQkZGF0ZV92YWxbMV0gJgogICAgICAgIFNPVVJDRURBVEUgPCBpbnB1dCRkYXRlX3ZhbFsyXQogICAgICAgICkgJT4lCiAgICAjQ09QWSBBTkQgUEFTVEUgWU9VUiBQTE9UIEhFUkUgRlJPTSBMQUIgNgogICAgICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgICAgIGdncGxvdChhZXMoeCA9IFRZUEUpKSArIAogICAgICBnZW9tX2JhcigpICsKICAgICAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIpICsgCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgCiAgfSkKICAKfQpgYGAKCmBgYHtyfQpzaGlueUFwcCh1aSwgc2VydmVyKQpgYGAKCgoKCgoKCg==