Exploring CO2 emissions across time

Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given dataset, and should not be used in the context of making policy decisions without external consultation from scientific experts.

This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 (CC BY-NC 3.0) United States License.

To cite this case study please use:

Wright, Carrie and Ontiveros, Michael and Jager, Leah and Taub, Margaret and Hicks, Stephanie. (2020). https://github.com/opencasestudies/ocs-bp-co2-emissions. Exploring CO2 emissions across time (Version v1.0.0).

To access the GitHub repository for this case study see here: https://github.com//opencasestudies/ocs-bp-co2-emissions. This case study is part of a series of public health case studies for the Bloomberg American Health Initiative.

Please help us by filling out our survey.

Motivation


This case study explores how different countries have contributed to Carbon Dioxide (CO2) emissions over time and how CO2 emission rates may relate to increasing global temperatures and increased rates of natural disasters and storms. We used this report from the EPA as the basis for motivating this case study, as it provides background information about how CO2 emissions and other greenhouse gases have influenced the climate and weather patterns.

CO2 makes up the largest proportion of greenhouse gas emissions in the United States:

[source]

A variety of sources and sectors contribute to greenhouse gas emissions:

[source]

Transportation and Electricity contribute the most metric tons of CO2:

[source]

So why should we pay attention to greenhouse gases?

According to the US Environmental Protection Agency (EPA) Inventory of U.S. Greenhouse Gas Emissions and Sinks 2020 Report:

Greenhouse gases absorb infrared radiation, thereby trapping heat in the atmosphere and making the planet warmer. The most important greenhouse gases directly emitted by humans include carbon dioxide (CO2), methane (CH4), nitrous oxide (N2O), and several fluorine-containing halogenated substances. Although CO2, CH4, and N2O occur naturally in the atmosphere, human activities have changed their atmospheric concentrations. From the pre- industrial era (i.e., ending about 1750) to 2018, concentrations of these greenhouse gases have increased globally by 46, 165, and 23 percent, respectively (IPCC 2013; NOAA/ESRL 2019a, 2019b, 2019c).

* IPCC stands for the Intergovernmental Panel on Climate Change

In fact, there are many signs that our planet is experiencing warmer temperatures:

[source]

The connection between greenhouse gas levels and global temperatures and the influence of increased global temperatures on human health are motivated by these reports:

The National Climate Assessment Report states that:

Heat-trapping gases already in the atmosphere have committed us to a hotter future with more climate-related impacts over the next few decades. The magnitude of climate change beyond the next few decades depends primarily on the amount of heat-trapping gases that human activities emit globally, now and in the future.

See the following links for more information about how greenhouse gases have influenced global temperatures: 1) The EPA report on green house gases
2) The National Climate Assessment (NCA) summary from 2014) 3) The World101 website about how countries are adapting to climate change

Main Questions


Our main questions:

  1. How have global CO2 emission rates changed over time? In particular for the US, and how does the US compare to other countries?
  2. Are CO2 emissions in the US, global temperatures, and natural disaster rates in the US associated?

Learning Objectives


In this case study, we will explore CO2 emission data from around the world. We will also focus on the US specifically to evaluate patterns of temperatures and natural disaster activity.

This case study will particularly focus on how to use different datasets that span different ranges of time, as well as how to create visualizations of patterns over time. We will especially focus on using packages and functions from the tidyverse, such as dplyr, tidyr, and ggplot2.

The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R especially legible and intuitive.

The skills, methods, and concepts that students will be familiar with by the end of this case study are:

Data Science Learning Objectives:

  1. Importing data from various types of Excel files and CSV files
  2. Apply action verbs in dplyr for data wrangling
  3. How to pivot between “long” and “wide” datasets
  4. Joining together multiple datasets using dplyr
  5. How to create effective longitudinal data visualizations with ggplot2
  6. How to add text, color, and labels to ggplot2 plots
  7. How to create faceted ggplot2 plots

Statistical Learning Objectives:

  1. Introduction to correlation coefficient as a summary statistic
  2. Relationship between correlation and linear regression
  3. Correlation is not causation


We will begin by loading the packages that we will need:

library(here)
library(readxl)
library(readr)
library(dplyr)
library(magrittr)
library(stringr)
library(purrr)
library(tidyr)
library(forcats)
library(ggplot2)
library(directlabels)
library(ggrepel)
library(broom)
library(patchwork)

Packages used in this case study:

Package Use in this case study
here to easily load and save data
readxl to import the Excel file data
readr to import the csv file data
dplyr to view and wrangle the data, by modifying variables, renaming variables, selecting variables, creating variables, and arranging values within a variable
magrittr to use and reassign data objects using the %<>%pipe operator
stringr to select only the first 4 characters of date data
purrr to apply a function on a list of tibbles (tibbles are the tidyverse version of a data frame)
tidyr to drop rows with NA values from a tibble
forcats to reorder the levels of a factor
ggplot2 to make visualizations
directlabels to add labels to plots easily
ggrepel to add labels that don’t overlap to plots
broom to make the output form statistical tests easier to work with
patchwork to combine plots

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

Context


Now we will describe a bit more background about greenhouse gas emissions and the potential influence of these emissions on public health.

Greenhouse gas emissions are due to both natural processes and anthropogenic (human-derived) activities.

These emissions are one of the contributing factors to rising global temperatures, which can have a great influence on public health as illustrated in the following image:

[source]

According to the US Environmental Protection Agency (EPA) Inventory of U.S. Greenhouse Gas Emissions and Sinks 2020 Report:

Gases in the atmosphere can contribute to climate change both directly and indirectly. Direct effects occur when the gas itself absorbs radiation. Indirect radiative forcing occurs when chemical transformations of the substance produce other greenhouse gases, when a gas influences the atmospheric lifetimes of other gases, and/or when a gas affects atmospheric processes that alter the radiative balance of the earth (e.g., affect cloud formation or albedo).

The Global Warming Potential (GWP) compares the ability of a greenhouse gas to trap heat in the atmosphere relative to another gas.

The GWP of a greenhouse gas is defined as the ratio of the accumulated radiative forcing within a specific time horizon caused by emitting 1 kilogram of the gas, relative to that of the reference gas CO2 (IPCC 2013). Therefore GWP-weighted emissions are provided in million metric tons of CO2 equivalent (MMT CO2 Eq.)

[source]

CO2 is actually the least heat-trapping gas of the greenhouse gases:

[source]

However, because CO2 is so much more abundant and stays in the atmosphere so much longer than other greenhouse gases, it has been the largest contributor to global warming. See here for more details.

It is also important to keep in mind that there is a lag between greenhouse gas emissions and temperature changes that we experience because much of Earth’s thermal energy (and CO2) gets stored in the ocean.

Due to a process called thermal inertia, the heat stored in the ocean will eventually be transfered to the surface of the Earth long after the gases were emitted that resulted in the increased ocean temperature.

See here for more explanation.

Furthermore, rising CO2 levels in the ocean also influence ocean acidity:

[source]

As CO2 levels rise in the ocean, the pH becomes more acidic, which makes it difficult for organisms to maintain their shells or skeletons that are made of calcium carbonate, thus making it more difficult for these organisms to survive and impacting their role in the ecosystem and food chain.

Furthermore, greenhouse gas emissions are believed to influence weather patterns as shown in this report.

Indeed, events with high levels of precipitation which can induce flooding and property damage are generally increasing around the country:

Limitations


An important limitation regarding this data analysis to keep in mind is the datasets only include countries and years in which countries were reporting such information to the agencies that collected the data. Thus, the data are incomplete. For example, while we have a fairly good sense of CO2 emissions globally for later years, additional emissions were also produced by countries that are not included in the data.

What are the data?


In this case study we will be using data related to CO2 emissions, as well as other data that may influence, be influenced or relate to CO2 emissions. Most of our data is from Gapminder that was originally obtained from the World Bank.

In addition, we will use some data that is specific to the United States from the National Oceanic and Atmospheric Administration (NOAA), which is an agency that collects weather and climate data.

Data Time span Source Original Source Description Citation
CO2 emissions 1751-2014 Gapminder Carbon Dioxide Information Analysis Center (CDIAC) CO2 emissions in tonnes or metric tons (equivalent to approximately 2,204.6 pounds) per person by country NA
GDP per capita (percent yearly growth) 1801-2019 Gapminder World Bank Growth Domestic Product (which is an overall measure of the health of nation’s economy) per person by country NA
Energy use per person 1960-2015 Gapminder World Bank Use of primary energy before transformation to other end-use fuels, by country NA
US Natural Disasters 1980-2019 The National Oceanic and Atmospheric Administration (NOAA) The National Oceanic and Atmospheric Administration (NOAA) US data about:
– Droughts
– Floods
– Freezes
– Severe Storms
– Tropical Cyclones
– Wildfires
– Winter Storms
NOAA National Centers for Environmental Information (NCEI) U.S. Billion-Dollar Weather and Climate Disasters (2020). https://www.ncdc.noaa.gov/billions/, DOI: 10.25921/stkw-7w73
Temperature 1895-2019 The National Oceanic and Atmospheric Administration (NOAA) The National Oceanic and Atmospheric Administration (NOAA) US National yearly average temperature (in Fahrenheit) from 1895 to 2019 NOAA National Centers for Environmental information, Climate at a Glance: National Time Series, published June 2020, retrieved on June 26, 2020 from https://www.ncdc.noaa.gov/cag/

To obtain the temperature data, the annual average temperatures were selected as shown in this image:

[source]

Importantly, notice that the data we would like to use span different time periods:

Data Time span
CO2 emissions 1751 to 2014
GDP per capita (yearly growth) 1801 to 2019
Energy use per person 1960 to 2015
US Natural Disasters 1980 to 2019
Temperature 1895 to 2019

We will explore more about this a bit later.

Question Opportunity

What concerns might arise about reliability and variation of measurement practices over time?

Data Import


In our case, we downloaded the data for the files from the various sources as indicated in the table above and put them within a “raw” subdirectory of a “data” directory for our project. If you use an RStudio project, then you can use the here() function of the here package to make the path for importing this data simpler. The here package automatically starts looking for files based on where you have a .Rproj file which is created when you start a new RStudio project. We can specify that we want to look for the “yearly_co2_emissions_1000_tonnes.xlsx” file within the “raw” directory within the “data” directory within a directory where our .Rproj file is located by separating the names of these directories using commas and listing “data” first.


Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.


To read in the files that were downloaded from the various sources as indicated in the table above, we will use the read_xlsx() and read_xls() functions of the readxl package to import the data from the .xlsx and .xls files, respectively. We will also use the here() function of the here package to more easily specify the path to our files relative to the directory where the .Rproj file is located.

CO2_emissions <- readxl::read_xlsx(here("data","raw", "yearly_co2_emissions_1000_tonnes.xlsx"))
gdp_growth    <- readxl::read_xlsx(here("data", "raw", "gdp_per_capita_yearly_growth.xlsx"))
energy_use    <- readxl::read_xlsx(here("data", "raw", "energy_use_per_person.xlsx"))

If you had trouble downloading these files, you can do so at our GitHub repo or more directly by clicking here, here, and here.

We will use the read_csv() function of the readr package to import the data from the .csv files.

However, for these files there are some lines that we would like to not import because the number of columns differ for some rows. If we don’t account for this, then we may end up importing fewer columns of the data that we would like.

In the first 5 rows shown below in the data/disasters.csv file, you can see that the first two rows does not have the same number of columns as the subsequent rows and are just (sub)titles.

To do this, we can skip rows using the skip = 2 argument of the read_csv() function.

us_disaster <- readr::read_csv(here("data", "raw", "disasters.csv"), skip = 2)

If you had trouble downloading this file, you can do so at our GitHub repo or more directly by clicking here.

Now looking at the data/temperature.csv file, we see that the first four lines do not have the same number of columns as the subsequent lines.

We will skip importing all 4 lines by using skip = 4. We can also replace all instances of "-99" with NA using the na = "-99" argument of the read_csv() function. The “-99” needs to be in quotation marks because this argument expects characters.


Click here for an explanation about data types in R and about character strings.

There are several classes of data in R programming, meaning that certain objects will be treated or interpreted differently. Character is one of these classes. A character string is an individual data value made up of characters. This can be a paragraph, like the legend for the table, or it can be a single letter or number like the letter “a” or the number “3”. If data are of class character, than the numeric values will not be processed like a numeric value in a mathematical sense. If you want your numeric values to be interpreted that way, they need to be converted to a numeric class. The options typically used are integer (which has no decimal place) and double precision (which has a decimal place).

A variable that is a factor has a set of particular values called levels (this can be numbers or characters). Even if these are numeric, they will be interpreted as levels (i.e., as if they were characters) not as mathematical numbers. The values of a factor are assumed to have a particular ordering; by default the order is alphabetical, but this is not always the correct/intuitive ordering. You can modify the order of these levels with the forcats package.


us_temperature <- readr::read_csv(here("data", "raw", "temperature.csv"), skip = 4, na = "-99")

If you had trouble downloading this file, you can do so at our GitHub repo or more directly by clicking here.

Great! now we have imported all of the data that we will need.

To allow users to skip import we will save the data as an RDA file:

save(CO2_emissions, 
     gdp_growth,
     energy_use, 
     us_disaster, 
     us_temperature, 
     file = here::here("data", "imported", "co2_data_imported.rda"))

Data Wrangling


If you have been following along but stopped, we could load our imported data like so:

load(here::here("data", "imported", "co2_data_imported.rda"))

If you skipped the data import section click here.

An RDA file (stands for R data) of the data can be found here or slightly more directly here. Download this file and then place it in your current working directory within a subdirectory called “imported” within a directory called “data” to copy and paste our code. We used an RStudio project and the here package to navigate to the file more easily.

load(here::here("data", "imported", "co2_data_imported.rda"))

Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



Next, we take a look at our data that we just imported. We will need to do some data wrangling to allow us to evaluate how CO2 emissions have changed over time and how emissions may relate to energy use, GDP, etc. Let’s explore how to do that with useful functions and packages from the tidyverse.

Yearly CO2 Emissions


First, let’s take a look at the CO2 data (CO2_emissions). We can use the slice_head() function of the dplyr package to see just the first rows of our data. We can specify how many rows we would like to see by using the n = argument.

We will use the %>% pipe from the magrittr package (although it is also imported by other tidyverse packages, like dplyr), which can be used to define the input for later sequential steps. This will make more sense when we have multiple sequential steps using the same data object.

CO2_emissions %>%
  slice_head(n = 3)
# A tibble: 3 × 265
  country  `1751` `1752` `1753` `1754` `1755` `1756` `1757` `1758` `1759` `1760`
  <chr>     <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 Afghani…     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
2 Albania      NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
3 Algeria      NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
# ℹ 254 more variables: `1761` <dbl>, `1762` <dbl>, `1763` <dbl>, `1764` <dbl>,
#   `1765` <dbl>, `1766` <dbl>, `1767` <dbl>, `1768` <dbl>, `1769` <dbl>,
#   `1770` <dbl>, `1771` <dbl>, `1772` <dbl>, `1773` <dbl>, `1774` <dbl>,
#   `1775` <dbl>, `1776` <dbl>, `1777` <dbl>, `1778` <dbl>, `1779` <dbl>,
#   `1780` <dbl>, `1781` <dbl>, `1782` <dbl>, `1783` <dbl>, `1784` <dbl>,
#   `1785` <dbl>, `1786` <dbl>, `1787` <dbl>, `1788` <dbl>, `1789` <dbl>,
#   `1790` <dbl>, `1791` <dbl>, `1792` <dbl>, `1793` <dbl>, `1794` <dbl>, …

Another useful function is slice_sample() to look at a selection of random rows using pseudorandom numbers for the index of rows to show. To continue to get the same random values or for others to get the same values, we need to set a seed first. We can do this with the set.seed() base function. We just specify a number with this function and that will allow us to get the same subset of values from the slice_sample() function. If two different people ran this code (without set.seed()), they would each see a different subset of rows. For data exploration, this isn’t a huge deal, but if we’d like separate analysts running the same code to see the same output, we will use set.seed(). If we changed set.seed(123) to set.seed(333), we would obtain a different random sample of rows.

set.seed(123)

CO2_emissions %>%
  slice_sample(n = 3)
# A tibble: 3 × 265
  country  `1751` `1752` `1753` `1754` `1755` `1756` `1757` `1758` `1759` `1760`
  <chr>     <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 Sri Lan…     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
2 Tuvalu       NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
3 Banglad…     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
# ℹ 254 more variables: `1761` <dbl>, `1762` <dbl>, `1763` <dbl>, `1764` <dbl>,
#   `1765` <dbl>, `1766` <dbl>, `1767` <dbl>, `1768` <dbl>, `1769` <dbl>,
#   `1770` <dbl>, `1771` <dbl>, `1772` <dbl>, `1773` <dbl>, `1774` <dbl>,
#   `1775` <dbl>, `1776` <dbl>, `1777` <dbl>, `1778` <dbl>, `1779` <dbl>,
#   `1780` <dbl>, `1781` <dbl>, `1782` <dbl>, `1783` <dbl>, `1784` <dbl>,
#   `1785` <dbl>, `1786` <dbl>, `1787` <dbl>, `1788` <dbl>, `1789` <dbl>,
#   `1790` <dbl>, `1791` <dbl>, `1792` <dbl>, `1793` <dbl>, `1794` <dbl>, …

Question Opportunity

Try setting a different seed to see the difference in the output.

#set.seed() #fill in the set.seed function with a number and uncomment it by removing the `#`
set.seed(100)
CO2_emissions %>%
  slice_sample(n = 3)

OK, we see each country is represented along one row and each column contains yearly CO2 emissions. We also see that there are a lot of NA values.

We can also use the glimpse() function of the dplyr package to view our data. This allows us to see all of our variables at once. We will see a tiny bit of each variable/column with the data displayed on the right.

# Scroll through the output!
CO2_emissions %>%
  dplyr::glimpse()
Rows: 192
Columns: 265
$ country <chr> "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Ant…
$ `1751`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1752`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1753`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1754`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1755`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1756`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1757`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1758`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1759`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1760`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1761`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1762`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1763`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1764`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1765`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1766`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1767`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1768`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1769`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1770`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1771`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1772`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1773`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1774`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1775`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1776`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1777`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1778`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1779`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1780`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1781`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1782`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1783`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1784`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1785`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1786`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1787`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1788`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1789`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1790`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1791`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1792`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1793`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1794`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1795`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1796`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1797`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1798`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1799`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1800`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1801`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1802`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1803`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1804`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1805`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1806`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1807`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 169, NA, NA, NA, NA, NA, N…
$ `1808`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1809`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1810`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1811`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1812`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1813`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1814`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1815`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1816`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1817`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1818`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ `1819`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 253, NA, NA, NA, NA, NA, N…
$ `1820`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 334, NA, NA, NA, NA, NA, N…
$ `1821`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 359, NA, NA, NA, NA, NA, N…
$ `1822`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 367, NA, NA, NA, NA, NA, N…
$ `1823`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 348, NA, NA, NA, NA, NA, N…
$ `1824`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 400, NA, NA, NA, NA, NA, N…
$ `1825`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 403, NA, NA, NA, NA, NA, N…
$ `1826`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 458, NA, NA, NA, NA, NA, N…
$ `1827`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 477, NA, NA, NA, NA, NA, N…
$ `1828`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 458, NA, NA, NA, NA, NA, N…
$ `1829`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 477, NA, NA, NA, NA, NA, N…
$ `1830`  <dbl> NA, NA, NA, NA, NA, NA, NA, 0.032, NA, 495.000, 0.308, NA, NA,…
$ `1831`  <dbl> NA, NA, NA, NA, NA, NA, NA, 3.84e-02, NA, 4.80e+02, 3.70e-01, …
$ `1832`  <dbl> NA, NA, NA, NA, NA, NA, NA, 2.56e-02, NA, 5.13e+02, 2.47e-01, …
$ `1833`  <dbl> NA, NA, NA, NA, NA, NA, NA, 0.032, NA, 429.000, 0.308, NA, NA,…
$ `1834`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 587, NA, NA, NA, NA, NA, N…
$ `1835`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 634, NA, NA, NA, NA, NA, N…
$ `1836`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 675, NA, NA, NA, NA, NA, N…
$ `1837`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 708, NA, NA, NA, NA, NA, N…
$ `1838`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 851, NA, NA, NA, NA, NA, N…
$ `1839`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 1060, NA, NA, NA, NA, NA, …
$ `1840`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 1170, NA, NA, NA, NA, NA, …
$ `1841`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 1320, NA, NA, NA, NA, NA, …
$ `1842`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 1460, NA, NA, NA, NA, NA, …
$ `1843`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 1270, NA, NA, NA, NA, NA, …
$ `1844`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 1600, NA, NA, NA, NA, NA, …
$ `1845`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 1800, NA, NA, NA, NA, NA, …
$ `1846`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 2120, NA, NA, NA, NA, NA, …
$ `1847`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 2080, NA, NA, NA, NA, NA, …
$ `1848`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 2340, NA, NA, NA, NA, NA, …
$ `1849`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 2260, NA, NA, NA, NA, NA, …
$ `1850`  <dbl> NA, NA, NA, NA, NA, NA, NA, 0.198, NA, 2330.000, 1.910, NA, NA…
$ `1851`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 2340, NA, NA, NA, NA, NA, …
$ `1852`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 2810, NA, NA, NA, NA, NA, …
$ `1853`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 3230, NA, NA, NA, NA, NA, …
$ `1854`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 3180, NA, NA, NA, NA, NA, …
$ `1855`  <dbl> NA, NA, NA, NA, NA, NA, NA, 6.01e-01, NA, 3.70e+03, 5.80e+00, …
$ `1856`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 4240, NA, NA, NA, NA, NA, …
$ `1857`  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, 4880, NA, NA, NA, NA, NA, …
$ `1858`  <dbl> NA, NA, NA, NA, NA, NA, NA, 8.44e-01, NA, 7.25e+03, 8.14e+00, …
$ `1859`  <dbl> NA, NA, NA, NA, NA, NA, NA, 8.95e-01, NA, 5.87e+03, 8.64e+00, …
$ `1860`  <dbl> NA, NA, NA, NA, NA, NA, NA, 1.18, 279.00, 6150.00, 11.40, NA, …
$ `1861`  <dbl> NA, NA, NA, NA, NA, NA, NA, 1.5, 510.0, 6380.0, 14.5, NA, NA, …
$ `1862`  <dbl> NA, NA, NA, NA, NA, NA, NA, 1.36, 356.00, 6360.00, 13.10, NA, …
$ `1863`  <dbl> NA, NA, NA, NA, NA, NA, NA, 1.42, 400.00, 5880.00, 13.70, NA, …
$ `1864`  <dbl> NA, NA, NA, NA, NA, NA, NA, 1.59, 268.00, 5080.00, 15.40, NA, …
$ `1865`  <dbl> NA, NA, NA, NA, NA, NA, NA, 1.52, 422.00, 5360.00, 14.70, NA, …
$ `1866`  <dbl> NA, NA, NA, NA, NA, NA, NA, 4.81, 697.00, 3600.00, 46.40, NA, …
$ `1867`  <dbl> NA, NA, NA, NA, NA, NA, NA, 5.52, 895.00, 4920.00, 53.20, NA, …
$ `1868`  <dbl> NA, NA, NA, NA, NA, NA, NA, 4.59, 733.00, 6080.00, 44.30, NA, …
$ `1869`  <dbl> NA, NA, NA, NA, NA, NA, NA, 6.23, 642.00, 6490.00, 60.10, NA, …
$ `1870`  <dbl> NA, NA, NA, NA, NA, NA, NA, 6.76, 601.00, 7370.00, 65.20, NA, …
$ `1871`  <dbl> NA, NA, NA, NA, NA, NA, NA, 9.12, 693.00, 10200.00, 88.00, NA,…
$ `1872`  <dbl> NA, NA, NA, NA, NA, NA, NA, 9.36, 708.00, 10000.00, 90.40, NA,…
$ `1873`  <dbl> NA, NA, NA, NA, NA, NA, NA, 8.79, 869.00, 10700.00, 84.80, NA,…
$ `1874`  <dbl> NA, NA, NA, NA, NA, NA, NA, 10.7, 891.0, 9160.0, 103.0, NA, NA…
$ `1875`  <dbl> NA, NA, NA, NA, NA, NA, NA, 12.3, 829.0, 7870.0, 119.0, NA, NA…
$ `1876`  <dbl> NA, NA, NA, NA, NA, NA, NA, 15.2, 931.0, 8100.0, 147.0, NA, NA…
$ `1877`  <dbl> NA, NA, NA, NA, NA, NA, NA, 15.6, 1070.0, 7290.0, 150.0, NA, N…
$ `1878`  <dbl> NA, NA, NA, NA, NA, NA, NA, 20.3, 968.0, 7250.0, 196.0, NA, NA…
$ `1879`  <dbl> NA, NA, NA, NA, NA, NA, NA, 20.9, 1460.0, 8870.0, 201.0, NA, N…
$ `1880`  <dbl> NA, NA, NA, NA, NA, NA, NA, 24.5, 2210.0, 23700.0, 236.0, NA, …
$ `1881`  <dbl> NA, NA, NA, NA, NA, NA, NA, 25.80, 1770.00, 10300.00, 249.00, …
$ `1882`  <dbl> NA, NA, NA, NA, NA, NA, NA, 27.20, 2010.00, 10600.00, 262.00, …
$ `1883`  <dbl> NA, NA, NA, NA, NA, NA, NA, 30.90, 2430.00, 11800.00, 298.00, …
$ `1884`  <dbl> NA, NA, NA, NA, NA, NA, NA, 31.4, 2570.0, 11500.0, 303.0, NA, …
$ `1885`  <dbl> NA, NA, NA, NA, NA, NA, NA, 34.20, 2910.00, 12100.00, 330.00, …
$ `1886`  <dbl> NA, NA, NA, NA, NA, NA, NA, 35.10, 2890.00, 11400.00, 338.00, …
$ `1887`  <dbl> NA, NA, NA, NA, NA, NA, 1090.0, 37.1, 3040.0, 12300.0, 358.0, …
$ `1888`  <dbl> NA, NA, NA, NA, NA, NA, 891.0, 38.7, 3530.0, 12000.0, 373.0, N…
$ `1889`  <dbl> NA, NA, NA, NA, NA, NA, 1760.0, 41.8, 3430.0, 12900.0, 403.0, …
$ `1890`  <dbl> NA, NA, NA, NA, NA, NA, 1370.0, 47.3, 3550.0, 13000.0, 457.0, …
$ `1891`  <dbl> NA, NA, NA, NA, NA, NA, 939.0, 52.1, 4010.0, 15000.0, 503.0, N…
$ `1892`  <dbl> NA, NA, NA, NA, NA, NA, 1390.0, 55.1, 4150.0, 14500.0, 532.0, …
$ `1893`  <dbl> NA, NA, NA, NA, NA, NA, 1550.0, 64.6, 3970.0, 17700.0, 624.0, …
$ `1894`  <dbl> NA, NA, NA, NA, NA, NA, 1990.0, 65.8, 4360.0, 18100.0, 635.0, …
$ `1895`  <dbl> NA, NA, NA, NA, NA, NA, 2270.0, 75.6, 4590.0, 20400.0, 730.0, …
$ `1896`  <dbl> NA, NA, NA, NA, NA, NA, 2310, 77, 4510, 21300, 743, NA, NA, NA…
$ `1897`  <dbl> NA, NA, NA, NA, NA, NA, 2080, 89, 4980, 23000, 859, NA, NA, NA…
$ `1898`  <dbl> NA, NA, NA, NA, NA, NA, 2350.0, 99.9, 5620.0, 24500.0, 964.0, …
$ `1899`  <dbl> NA, NA, NA, NA, NA, NA, 2920, 116, 5790, 24800, 1120, NA, NA, …
$ `1900`  <dbl> NA, NA, NA, NA, NA, NA, 2070, 131, 10200, 27700, 1270, NA, NA,…
$ `1901`  <dbl> NA, NA, NA, NA, NA, NA, 2490, 135, 11400, 28400, 1300, NA, NA,…
$ `1902`  <dbl> NA, NA, NA, NA, NA, NA, 2820, 130, 11400, 25700, 1260, NA, NA,…
$ `1903`  <dbl> NA, NA, NA, NA, NA, NA, 2860, 127, 11200, 25600, 1230, NA, NA,…
$ `1904`  <dbl> NA, NA, NA, NA, NA, NA, 3800, 142, 11600, 26900, 1370, NA, NA,…
$ `1905`  <dbl> NA, NA, NA, NA, NA, NA, 3990, 126, 12100, 28100, 1220, NA, NA,…
$ `1906`  <dbl> NA, NA, NA, NA, NA, NA, 6260, 144, 14400, 33600, 1390, NA, NA,…
$ `1907`  <dbl> NA, NA, NA, NA, NA, NA, 6260, 161, 15500, 42200, 1560, NA, NA,…
$ `1908`  <dbl> NA, NA, NA, NA, NA, NA, 7620, 162, 16800, 59000, 1570, NA, NA,…
$ `1909`  <dbl> NA, NA, NA, NA, NA, NA, 5940, 172, 14600, 42200, 1660, NA, NA,…
$ `1910`  <dbl> NA, NA, NA, NA, NA, NA, 8910, 168, 17500, 57600, 1620, NA, NA,…
$ `1911`  <dbl> NA, NA, NA, NA, NA, NA, 9950, 174, 19300, 48100, 1680, NA, NA,…
$ `1912`  <dbl> NA, NA, NA, NA, NA, NA, 9490, 198, 20800, 50000, 1910, NA, NA,…
$ `1913`  <dbl> NA, NA, NA, NA, NA, NA, 10200, 215, 22400, 59700, 2070, NA, NA…
$ `1914`  <dbl> NA, NA, NA, NA, NA, NA, 8680, 194, 24500, 48900, 1870, NA, NA,…
$ `1915`  <dbl> NA, NA, NA, NA, NA, NA, 6950, 178, 21800, 34900, 1720, NA, NA,…
$ `1916`  <dbl> NA, NA, 3.67, NA, NA, NA, 4990.00, 189.00, 19300.00, 8040.00, …
$ `1917`  <dbl> NA, NA, 7.33, NA, NA, NA, 2230.00, 174.00, 20800.00, 3450.00, …
$ `1918`  <dbl> NA, NA, 18.3, NA, NA, NA, 2520.0, 69.5, 23000.0, 3340.0, 671.0…
$ `1919`  <dbl> NA, NA, 18.3, NA, NA, NA, 3730.0, 59.4, 21800.0, 3020.0, 573.0…
$ `1920`  <dbl> NA, NA, 22.0, NA, NA, NA, 5900.0, 54.2, 25800.0, 14500.0, 523.…
$ `1921`  <dbl> NA, NA, 25.7, NA, NA, NA, 5540.0, 58.7, 23200.0, 19400.0, 567.…
$ `1922`  <dbl> NA, NA, 25.7, NA, NA, NA, 7300.0, 71.6, 24400.0, 18600.0, 692.…
$ `1923`  <dbl> NA, NA, 14.7, NA, NA, NA, 8450.0, 79.1, 24900.0, 17800.0, 764.…
$ `1924`  <dbl> NA, NA, 29.3, NA, NA, NA, 11000.0, 94.3, 27100.0, 20100.0, 910…
$ `1925`  <dbl> NA, NA, 33.0, NA, NA, NA, 11200.0, 93.1, 28300.0, 19000.0, 898…
$ `1926`  <dbl> NA, NA, 40.3, NA, NA, NA, 11300.0, 135.0, 27900.0, 18600.0, 13…
$ `1927`  <dbl> NA, NA, 58.7, NA, NA, NA, 13400.0, 168.0, 28900.0, 20100.0, 16…
$ `1928`  <dbl> NA, NA, 73.30, NA, NA, NA, 12800.00, 186.00, 26300.00, 21200.0…
$ `1929`  <dbl> NA, NA, 80.70, NA, NA, NA, 13100.00, 201.00, 23700.00, 24200.0…
$ `1930`  <dbl> NA, NA, 84.30, NA, NA, NA, 12800.00, 273.00, 22000.00, 18900.0…
$ `1931`  <dbl> NA, NA, 99.00, NA, NA, NA, 12900.00, 328.00, 19600.00, 18100.0…
$ `1932`  <dbl> NA, NA, 114.00, NA, NA, NA, 13100.00, 369.00, 20400.00, 15200.…
$ `1933`  <dbl> NA, 7.33, 121.00, NA, NA, NA, 13200.00, 412.00, 21600.00, 1420…
$ `1934`  <dbl> NA, 7.33, 139.00, NA, NA, NA, 14300.00, 499.00, 22700.00, 1380…
$ `1935`  <dbl> NA, 18.3, 132.0, NA, NA, NA, 14000.0, 565.0, 25300.0, 13900.0,…
$ `1936`  <dbl> NA, 128.0, 51.3, NA, NA, NA, 15100.0, 648.0, 27100.0, 13600.0,…
$ `1937`  <dbl> NA, 297.0, 69.7, NA, NA, NA, 16700.0, 662.0, 28900.0, 15300.0,…
$ `1938`  <dbl> NA, 348, 33, NA, NA, NA, 16400, 699, 28100, 5790, 6750, NA, 34…
$ `1939`  <dbl> NA, 433.00, 161.00, NA, NA, NA, 17400.00, 707.00, 32200.00, 63…
$ `1940`  <dbl> NA, 693, 238, NA, NA, NA, 15900, 848, 29100, 7350, 8190, NA, 2…
$ `1941`  <dbl> NA, 627, 312, NA, NA, NA, 14000, 745, 34600, 7980, 7190, NA, 2…
$ `1942`  <dbl> NA, 744, 499, NA, NA, NA, 13500, 513, 36500, 8560, 4950, NA, 2…
$ `1943`  <dbl> NA, 462, 469, NA, NA, NA, 14100, 655, 35000, 9620, 6320, NA, 2…
$ `1944`  <dbl> NA, 154, 499, NA, NA, NA, 14000, 613, 34200, 9400, 5920, NA, 2…
$ `1945`  <dbl> NA, 121, 616, NA, NA, NA, 13700, 649, 32700, 4570, 6270, NA, 3…
$ `1946`  <dbl> NA, 484, 763, NA, NA, NA, 13700, 730, 35500, 12800, 7040, NA, …
$ `1947`  <dbl> NA, 928.00, 744.00, NA, NA, NA, 14500.00, 878.00, 38000.00, 17…
$ `1948`  <dbl> NA, 704.00, 803.00, NA, NA, NA, 17400.00, 935.00, 38500.00, 24…
$ `1949`  <dbl> 14.70, 1020.00, 909.00, NA, NA, NA, 15400.00, 1060.00, 37700.0…
$ `1950`  <dbl> 84.3, 297.0, 3790.0, NA, 187.0, NA, 30000.0, 1180.0, 54800.0, …
$ `1951`  <dbl> 91.7, 403.0, 4140.0, NA, 249.0, NA, 35000.0, 1280.0, 59100.0, …
$ `1952`  <dbl> 91.7, 374.0, 3890.0, NA, 312.0, NA, 36100.0, 1370.0, 60300.0, …
$ `1953`  <dbl> 106.0, 414.0, 4000.0, NA, 275.0, NA, 35200.0, 1450.0, 59500.0,…
$ `1954`  <dbl> 106.0, 502.0, 4160.0, NA, 348.0, NA, 36800.0, 1590.0, 67900.0,…
$ `1955`  <dbl> 154.0, 664.0, 4610.0, NA, 414.0, NA, 39600.0, 1800.0, 70700.0,…
$ `1956`  <dbl> 183.0, 840.0, 5000.0, NA, 502.0, NA, 44300.0, 1970.0, 73100.0,…
$ `1957`  <dbl> 293.0, 1510.0, 5540.0, NA, 620.0, 22.0, 47700.0, 2160.0, 74600…
$ `1958`  <dbl> 330.0, 1200.0, 5220.0, NA, 594.0, 29.3, 44200.0, 2310.0, 77700…
$ `1959`  <dbl> 385.0, 1440.0, 5670.0, NA, 620.0, 29.3, 49000.0, 2430.0, 83800…
$ `1960`  <dbl> 414.0, 2020.0, 6160.0, NA, 550.0, 36.7, 48800.0, 2530.0, 88200…
$ `1961`  <dbl> 491.0, 2280.0, 6070.0, NA, 455.0, 47.7, 51200.0, 2600.0, 90600…
$ `1962`  <dbl> 689.0, 2460.0, 5670.0, NA, 1180.0, 103.0, 53700.0, 2730.0, 949…
$ `1963`  <dbl> 708.0, 2080.0, 5430.0, NA, 1150.0, 84.3, 50100.0, 2930.0, 1010…
$ `1964`  <dbl> 840.0, 2020.0, 5650.0, NA, 1220.0, 91.7, 55700.0, 3120.0, 1090…
$ `1965`  <dbl> 1010.0, 2170.0, 6600.0, NA, 1190.0, 150.0, 58900.0, 3310.0, 12…
$ `1966`  <dbl> 1090.0, 2550.0, 8430.0, NA, 1550.0, 348.0, 63100.0, 3490.0, 12…
$ `1967`  <dbl> 1280, 2680, 8440, NA, 994, 565, 65500, 3650, 129000, 40000, 35…
$ `1968`  <dbl> 1220, 3070, 9060, NA, 1670, 990, 69100, 3750, 135000, 42400, 3…
$ `1969`  <dbl> 942, 3250, 11300, NA, 2790, 1260, 77300, 3910, 142000, 44700, …
$ `1970`  <dbl> 1.67e+03, 3.74e+03, 1.51e+04, NA, 3.58e+03, 4.62e+02, 8.27e+04…
$ `1971`  <dbl> 1.90e+03, 4.35e+03, 1.87e+04, NA, 3.41e+03, 4.25e+02, 8.89e+04…
$ `1972`  <dbl> 1.53e+03, 5.64e+03, 2.83e+04, NA, 4.51e+03, 3.74e+02, 9.02e+04…
$ `1973`  <dbl> 1.64e+03, 5.29e+03, 3.83e+04, NA, 4.88e+03, 3.30e+02, 9.41e+04…
$ `1974`  <dbl> 1.92e+03, 4.35e+03, 3.19e+04, NA, 4.87e+03, 4.29e+02, 9.56e+04…
$ `1975`  <dbl> 2.13e+03, 4.59e+03, 3.20e+04, NA, 4.42e+03, 7.08e+02, 9.49e+04…
$ `1976`  <dbl> 1.99e+03, 4.95e+03, 3.92e+04, NA, 3.29e+03, 4.03e+02, 9.98e+04…
$ `1977`  <dbl> 2.39e+03, 5.72e+03, 4.19e+04, NA, 3.53e+03, 4.66e+02, 1.01e+05…
$ `1978`  <dbl> 2160, 6490, 62500, NA, 5410, 491, 103000, 5810, 202000, 57500,…
$ `1979`  <dbl> 2240, 7590, 45600, NA, 5500, 407, 111000, 5850, 205000, 61600,…
$ `1980`  <dbl> 1760, 5170, 66500, NA, 5350, 143, 109000, 6080, 221000, 52300,…
$ `1981`  <dbl> 1980.0, 7340.0, 46400.0, NA, 5280.0, 106.0, 102000.0, 5970.0, …
$ `1982`  <dbl> 2100, 7310, 39300, NA, 4650, 293, 103000, 6080, 234000, 53900,…
$ `1983`  <dbl> 2520.0, 7630.0, 52600.0, NA, 5120.0, 84.3, 105000.0, 6170.0, 2…
$ `1984`  <dbl> 2830.0, 7830.0, 71100.0, NA, 5010.0, 147.0, 107000.0, 6230.0, …
$ `1985`  <dbl> 3510.0, 7880.0, 72800.0, NA, 4700.0, 249.0, 101000.0, 6710.0, …
$ `1986`  <dbl> 3140, 8060, 76300, NA, 4660, 249, 104000, 6730, 240000, 54100,…
$ `1987`  <dbl> 3120, 7440, 84100, NA, 5820, 275, 115000, 7020, 256000, 57700,…
$ `1988`  <dbl> 2870, 7330, 83900, NA, 5130, 286, 121000, 7210, 261000, 53300,…
$ `1989`  <dbl> 2780.0, 8980.0, 80000.0, NA, 5010.0, 286.0, 117000.0, 7060.0, …
$ `1990`  <dbl> 2610, 5520, 77000, 407, 5120, 282, 112000, 6620, 264000, 57700…
$ `1991`  <dbl> 2440, 4290, 79000, 407, 5090, 268, 117000, 6380, 261000, 61600…
$ `1992`  <dbl> 1390, 2520, 80100, 407, 5200, 264, 121000, 5830, 268000, 56700…
$ `1993`  <dbl> 1350, 2340, 82200, 411, 5780, 271, 118000, 2560, 277000, 57100…
$ `1994`  <dbl> 1290, 1930, 86400, 407, 3890, 268, 122000, 2710, 278000, 57100…
$ `1995`  <dbl> 1240, 2090, 95300, 425, 11000, 275, 128000, 3410, 282000, 5980…
$ `1996`  <dbl> 1180, 2020, 97100, 455, 10500, 293, 135000, 2560, 302000, 6320…
$ `1997`  <dbl> 1100, 1540, 87300, 466, 7380, 308, 138000, 3230, 306000, 62700…
$ `1998`  <dbl> 1040, 1750, 107000, 491, 7310, 319, 140000, 3360, 317000, 6370…
$ `1999`  <dbl> 821, 2980, 92000, 513, 9160, 330, 147000, 3010, 325000, 61900,…
$ `2000`  <dbl> 774, 3020, 87900, 524, 9540, 345, 142000, 3470, 329000, 62300,…
$ `2001`  <dbl> 818, 3220, 84200, 524, 9730, 348, 134000, 3540, 325000, 65900,…
$ `2002`  <dbl> 1070, 3750, 89900, 532, 12700, 370, 125000, 3040, 341000, 6710…
$ `2003`  <dbl> 1200, 4290, 91600, 535, 9060, 403, 135000, 3430, 336000, 72200…
$ `2004`  <dbl> 950, 4170, 88500, 561, 18800, 422, 158000, 3640, 343000, 72400…
$ `2005`  <dbl> 1330, 4250, 107000, 576, 19200, 429, 162000, 4350, 350000, 742…
$ `2006`  <dbl> 1650, 3900, 101000, 546, 22300, 444, 175000, 4380, 365000, 722…
$ `2007`  <dbl> 2270, 3930, 109000, 539, 25200, 469, 175000, 5060, 372000, 697…
$ `2008`  <dbl> 4210, 4370, 110000, 539, 25700, 480, 189000, 5560, 386000, 690…
$ `2009`  <dbl> 6770, 4380, 121000, 517, 27800, 510, 180000, 4360, 395000, 627…
$ `2010`  <dbl> 8460, 4600, 119000, 517, 29100, 524, 188000, 4220, 391000, 675…
$ `2011`  <dbl> 12200, 5240, 121000, 491, 30300, 513, 192000, 4920, 392000, 65…
$ `2012`  <dbl> 10800, 4910, 130000, 488, 33400, 524, 192000, 5690, 388000, 62…
$ `2013`  <dbl> 10000, 5060, 134000, 477, 32600, 524, 190000, 5500, 372000, 62…
$ `2014`  <dbl> 9810, 5720, 145000, 462, 34800, 532, 204000, 5530, 361000, 587…

We can also see that we have a large tibble.

CO2_emissions %>%
  class()
[1] "tbl_df"     "tbl"        "data.frame"

This is the object that is created when we read in the data with readr. A tibble (or tbl_df) is the tidyverse version of a data.frame object. Similar to data.frame, it is a table with variable information arranged as columns, and individual observations arranged as rows. However some nice differences are they do not change variable names or data types and they give more messages when something is wrong (e.g. when a variable does not exist), which forces the analyst to confront problems earlier. Tibbles also give us information about the class of each variable.

For example the country variable is made up of character (abbreviated as chr) values.

CO2_emissions %>%
  select(country)
# A tibble: 192 × 1
   country            
   <chr>              
 1 Afghanistan        
 2 Albania            
 3 Algeria            
 4 Andorra            
 5 Angola             
 6 Antigua and Barbuda
 7 Argentina          
 8 Armenia            
 9 Australia          
10 Austria            
# ℹ 182 more rows

We see that we have 192 rows different country variables and CO2 emission values for 264 different years (from 1751 to 2014).

names(CO2_emissions)
  [1] "country" "1751"    "1752"    "1753"    "1754"    "1755"    "1756"   
  [8] "1757"    "1758"    "1759"    "1760"    "1761"    "1762"    "1763"   
 [15] "1764"    "1765"    "1766"    "1767"    "1768"    "1769"    "1770"   
 [22] "1771"    "1772"    "1773"    "1774"    "1775"    "1776"    "1777"   
 [29] "1778"    "1779"    "1780"    "1781"    "1782"    "1783"    "1784"   
 [36] "1785"    "1786"    "1787"    "1788"    "1789"    "1790"    "1791"   
 [43] "1792"    "1793"    "1794"    "1795"    "1796"    "1797"    "1798"   
 [50] "1799"    "1800"    "1801"    "1802"    "1803"    "1804"    "1805"   
 [57] "1806"    "1807"    "1808"    "1809"    "1810"    "1811"    "1812"   
 [64] "1813"    "1814"    "1815"    "1816"    "1817"    "1818"    "1819"   
 [71] "1820"    "1821"    "1822"    "1823"    "1824"    "1825"    "1826"   
 [78] "1827"    "1828"    "1829"    "1830"    "1831"    "1832"    "1833"   
 [85] "1834"    "1835"    "1836"    "1837"    "1838"    "1839"    "1840"   
 [92] "1841"    "1842"    "1843"    "1844"    "1845"    "1846"    "1847"   
 [99] "1848"    "1849"    "1850"    "1851"    "1852"    "1853"    "1854"   
[106] "1855"    "1856"    "1857"    "1858"    "1859"    "1860"    "1861"   
[113] "1862"    "1863"    "1864"    "1865"    "1866"    "1867"    "1868"   
[120] "1869"    "1870"    "1871"    "1872"    "1873"    "1874"    "1875"   
[127] "1876"    "1877"    "1878"    "1879"    "1880"    "1881"    "1882"   
[134] "1883"    "1884"    "1885"    "1886"    "1887"    "1888"    "1889"   
[141] "1890"    "1891"    "1892"    "1893"    "1894"    "1895"    "1896"   
[148] "1897"    "1898"    "1899"    "1900"    "1901"    "1902"    "1903"   
[155] "1904"    "1905"    "1906"    "1907"    "1908"    "1909"    "1910"   
[162] "1911"    "1912"    "1913"    "1914"    "1915"    "1916"    "1917"   
[169] "1918"    "1919"    "1920"    "1921"    "1922"    "1923"    "1924"   
[176] "1925"    "1926"    "1927"    "1928"    "1929"    "1930"    "1931"   
[183] "1932"    "1933"    "1934"    "1935"    "1936"    "1937"    "1938"   
[190] "1939"    "1940"    "1941"    "1942"    "1943"    "1944"    "1945"   
[197] "1946"    "1947"    "1948"    "1949"    "1950"    "1951"    "1952"   
[204] "1953"    "1954"    "1955"    "1956"    "1957"    "1958"    "1959"   
[211] "1960"    "1961"    "1962"    "1963"    "1964"    "1965"    "1966"   
[218] "1967"    "1968"    "1969"    "1970"    "1971"    "1972"    "1973"   
[225] "1974"    "1975"    "1976"    "1977"    "1978"    "1979"    "1980"   
[232] "1981"    "1982"    "1983"    "1984"    "1985"    "1986"    "1987"   
[239] "1988"    "1989"    "1990"    "1991"    "1992"    "1993"    "1994"   
[246] "1995"    "1996"    "1997"    "1998"    "1999"    "2000"    "2001"   
[253] "2002"    "2003"    "2004"    "2005"    "2006"    "2007"    "2008"   
[260] "2009"    "2010"    "2011"    "2012"    "2013"    "2014"   

Recall, the values are emissions in metric tons, also called tonnes. Scrolling through the glimpse() function above, we can also see that there are fewer NA values for later years.

In this next code chunk, we will introduce the %<>% operator from the magrittr package. This allows us to use our CO2_emissions data and reassign it to a modified version at the same time. Let’s modify CO2_emissions to make it more usable for making visualizations. Specifically, we will use the pivot_longer() function of the dplyr package to convert our data into what is called “long” format. This is also sometimes referred to as “narrow” format.

This means that we will have more rows and fewer columns than our current format.

Right now our data is in what is called “wide” format. In wide format, each variable is listed as its own column. In contrast, in long format, variables maybe collapsed into a column that identifies the variables and a column of values. See here for more information about the difference between the two formats.

We want to collapse all of the values for the emission data across the different individual year variables into one new Emissions variable. We will identify what year they are from by creating a new Year variable. The cols = argument allows us to specify which columns we want to pivot (or not pivot) to create these new columns. We want to keep our country data as an ID variable so we will exclude it using the - sign, by default all other columns will be used.

CO2_emissions  %<>%
  pivot_longer(cols = -country,
               names_to = "Year",
               values_to = "Emissions")

set.seed(123)

CO2_emissions %>%
  slice_sample(n = 6)
# A tibble: 6 × 3
  country     Year  Emissions
  <chr>       <chr>     <dbl>
1 Bahamas     1832       NA  
2 Montenegro  1843       NA  
3 Mongolia    1892       NA  
4 Samoa       1791       NA  
5 Azerbaijan  1867       53.2
6 Timor-Leste 2010      235  

Question Opportunity

Think a moment about what the dimensions of the CO2_emissions tibble are now and why? How would you check this?

Hint : Checking has something to do with a unique aspect about tibbles.

# Write some code to check this
dim(CO2_emissions)

Let’s say we also want to rename the country variable to be capitalized. To do this, we can use the rename() function of the dplyr package to rename this variable. When renaming variables the syntax is new-name = old-name, where the new name is listed first before the =.

You may also note that the Year variable is currently of class type character. We would like to change it to be numeric. To do this we will use the mutate() function, which is also part of the dplyr package. This function allows us to create and modify variables. We will also use this function to create a variable called Label which will have "CO2 Emissions (Metric Tons)" as the value for every row, to be used when we create plots later.

CO2_emissions  %<>%
   dplyr::rename(Country = country) %>%
   dplyr::mutate(Year = as.numeric(Year),
                 Label = "CO2 Emissions (Metric Tons)")

Now let’s take a look to see how our data has changed:

set.seed(123)

CO2_emissions %>%
  slice_sample(n = 6)
# A tibble: 6 × 4
  Country      Year Emissions Label                      
  <chr>       <dbl>     <dbl> <chr>                      
1 Bahamas      1832      NA   CO2 Emissions (Metric Tons)
2 Montenegro   1843      NA   CO2 Emissions (Metric Tons)
3 Mongolia     1892      NA   CO2 Emissions (Metric Tons)
4 Samoa        1791      NA   CO2 Emissions (Metric Tons)
5 Azerbaijan   1867      53.2 CO2 Emissions (Metric Tons)
6 Timor-Leste  2010     235   CO2 Emissions (Metric Tons)

Great, we can see that now the Year variable is of class double (abbreviated dbl), which is a numeric class.

Now, let’s take a look at the Country variable to check if there is anything unexpected. We will use the distinct() function of the dplyr package to view the unique values only. Finally, we use the pull() function of the dplyr package to extract the values from the column (this is similar to using the $ base R syntax e.g. CO2_emission$Country).

# Scroll through the output!
CO2_emissions %>%
  distinct(Country) %>%
  pull()
  [1] "Afghanistan"                    "Albania"                       
  [3] "Algeria"                        "Andorra"                       
  [5] "Angola"                         "Antigua and Barbuda"           
  [7] "Argentina"                      "Armenia"                       
  [9] "Australia"                      "Austria"                       
 [11] "Azerbaijan"                     "Bahamas"                       
 [13] "Bahrain"                        "Bangladesh"                    
 [15] "Barbados"                       "Belarus"                       
 [17] "Belgium"                        "Belize"                        
 [19] "Benin"                          "Bhutan"                        
 [21] "Bolivia"                        "Bosnia and Herzegovina"        
 [23] "Botswana"                       "Brazil"                        
 [25] "Brunei"                         "Bulgaria"                      
 [27] "Burkina Faso"                   "Burundi"                       
 [29] "Cambodia"                       "Cameroon"                      
 [31] "Canada"                         "Cape Verde"                    
 [33] "Central African Republic"       "Chad"                          
 [35] "Chile"                          "China"                         
 [37] "Colombia"                       "Comoros"                       
 [39] "Congo, Dem. Rep."               "Congo, Rep."                   
 [41] "Costa Rica"                     "Cote d'Ivoire"                 
 [43] "Croatia"                        "Cuba"                          
 [45] "Cyprus"                         "Czech Republic"                
 [47] "Denmark"                        "Djibouti"                      
 [49] "Dominica"                       "Dominican Republic"            
 [51] "Ecuador"                        "Egypt"                         
 [53] "El Salvador"                    "Equatorial Guinea"             
 [55] "Eritrea"                        "Estonia"                       
 [57] "Ethiopia"                       "Fiji"                          
 [59] "Finland"                        "France"                        
 [61] "Gabon"                          "Gambia"                        
 [63] "Georgia"                        "Germany"                       
 [65] "Ghana"                          "Greece"                        
 [67] "Grenada"                        "Guatemala"                     
 [69] "Guinea"                         "Guinea-Bissau"                 
 [71] "Guyana"                         "Haiti"                         
 [73] "Honduras"                       "Hungary"                       
 [75] "Iceland"                        "India"                         
 [77] "Indonesia"                      "Iran"                          
 [79] "Iraq"                           "Ireland"                       
 [81] "Israel"                         "Italy"                         
 [83] "Jamaica"                        "Japan"                         
 [85] "Jordan"                         "Kazakhstan"                    
 [87] "Kenya"                          "Kiribati"                      
 [89] "Kuwait"                         "Kyrgyz Republic"               
 [91] "Lao"                            "Latvia"                        
 [93] "Lebanon"                        "Lesotho"                       
 [95] "Liberia"                        "Libya"                         
 [97] "Liechtenstein"                  "Lithuania"                     
 [99] "Luxembourg"                     "Macedonia, FYR"                
[101] "Madagascar"                     "Malawi"                        
[103] "Malaysia"                       "Maldives"                      
[105] "Mali"                           "Malta"                         
[107] "Marshall Islands"               "Mauritania"                    
[109] "Mauritius"                      "Mexico"                        
[111] "Micronesia, Fed. Sts."          "Moldova"                       
[113] "Mongolia"                       "Montenegro"                    
[115] "Morocco"                        "Mozambique"                    
[117] "Myanmar"                        "Namibia"                       
[119] "Nauru"                          "Nepal"                         
[121] "Netherlands"                    "New Zealand"                   
[123] "Nicaragua"                      "Niger"                         
[125] "Nigeria"                        "North Korea"                   
[127] "Norway"                         "Oman"                          
[129] "Pakistan"                       "Palau"                         
[131] "Palestine"                      "Panama"                        
[133] "Papua New Guinea"               "Paraguay"                      
[135] "Peru"                           "Philippines"                   
[137] "Poland"                         "Portugal"                      
[139] "Qatar"                          "Romania"                       
[141] "Russia"                         "Rwanda"                        
[143] "Samoa"                          "Sao Tome and Principe"         
[145] "Saudi Arabia"                   "Senegal"                       
[147] "Serbia"                         "Seychelles"                    
[149] "Sierra Leone"                   "Singapore"                     
[151] "Slovak Republic"                "Slovenia"                      
[153] "Solomon Islands"                "Somalia"                       
[155] "South Africa"                   "South Korea"                   
[157] "South Sudan"                    "Spain"                         
[159] "Sri Lanka"                      "St. Kitts and Nevis"           
[161] "St. Lucia"                      "St. Vincent and the Grenadines"
[163] "Sudan"                          "Suriname"                      
[165] "Swaziland"                      "Sweden"                        
[167] "Switzerland"                    "Syria"                         
[169] "Tajikistan"                     "Tanzania"                      
[171] "Thailand"                       "Timor-Leste"                   
[173] "Togo"                           "Tonga"                         
[175] "Trinidad and Tobago"            "Tunisia"                       
[177] "Turkey"                         "Turkmenistan"                  
[179] "Tuvalu"                         "Uganda"                        
[181] "Ukraine"                        "United Arab Emirates"          
[183] "United Kingdom"                 "United States"                 
[185] "Uruguay"                        "Uzbekistan"                    
[187] "Vanuatu"                        "Venezuela"                     
[189] "Vietnam"                        "Yemen"                         
[191] "Zambia"                         "Zimbabwe"                      

These all look as expected!

Yearly Growth in GDP per Capita


Let’s take a look at the next dataset (gdp_growth) that we imported.

gdp_growth %>%
  slice_head(n = 3)
# A tibble: 3 × 220
  country       `1801`   `1802`   `1803`   `1804`   `1805`   `1806`   `1807`
  <chr>          <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
1 Afghanistan NA       NA       NA       NA       NA       NA       NA      
2 Albania      0.104    0.104    0.104    0.104    0.104    0.104    0.104  
3 Algeria     -0.00247 -0.00247 -0.00247 -0.00247 -0.00247 -0.00247 -0.00247
# ℹ 212 more variables: `1808` <dbl>, `1809` <dbl>, `1810` <dbl>, `1811` <dbl>,
#   `1812` <dbl>, `1813` <dbl>, `1814` <dbl>, `1815` <dbl>, `1816` <dbl>,
#   `1817` <dbl>, `1818` <dbl>, `1819` <dbl>, `1820` <dbl>, `1821` <dbl>,
#   `1822` <dbl>, `1823` <dbl>, `1824` <dbl>, `1825` <dbl>, `1826` <dbl>,
#   `1827` <dbl>, `1828` <dbl>, `1829` <dbl>, `1830` <dbl>, `1831` <dbl>,
#   `1832` <dbl>, `1833` <dbl>, `1834` <dbl>, `1835` <dbl>, `1836` <dbl>,
#   `1837` <dbl>, `1838` <dbl>, `1839` <dbl>, `1840` <dbl>, `1841` <dbl>, …

How many rows and columns are there are there? We can easily check by using the base dim() function, which evaluates the dimensions of an object.

dim(gdp_growth)
[1] 194 220

Interesting, it’s 194 rows (as opposed to 50688 above). We will deal with this and other differences in the sets of countries a bit later on. There are also 220 columns with a country column and a set of columns corresponding to different years.

names(gdp_growth)
  [1] "country" "1801"    "1802"    "1803"    "1804"    "1805"    "1806"   
  [8] "1807"    "1808"    "1809"    "1810"    "1811"    "1812"    "1813"   
 [15] "1814"    "1815"    "1816"    "1817"    "1818"    "1819"    "1820"   
 [22] "1821"    "1822"    "1823"    "1824"    "1825"    "1826"    "1827"   
 [29] "1828"    "1829"    "1830"    "1831"    "1832"    "1833"    "1834"   
 [36] "1835"    "1836"    "1837"    "1838"    "1839"    "1840"    "1841"   
 [43] "1842"    "1843"    "1844"    "1845"    "1846"    "1847"    "1848"   
 [50] "1849"    "1850"    "1851"    "1852"    "1853"    "1854"    "1855"   
 [57] "1856"    "1857"    "1858"    "1859"    "1860"    "1861"    "1862"   
 [64] "1863"    "1864"    "1865"    "1866"    "1867"    "1868"    "1869"   
 [71] "1870"    "1871"    "1872"    "1873"    "1874"    "1875"    "1876"   
 [78] "1877"    "1878"    "1879"    "1880"    "1881"    "1882"    "1883"   
 [85] "1884"    "1885"    "1886"    "1887"    "1888"    "1889"    "1890"   
 [92] "1891"    "1892"    "1893"    "1894"    "1895"    "1896"    "1897"   
 [99] "1898"    "1899"    "1900"    "1901"    "1902"    "1903"    "1904"   
[106] "1905"    "1906"    "1907"    "1908"    "1909"    "1910"    "1911"   
[113] "1912"    "1913"    "1914"    "1915"    "1916"    "1917"    "1918"   
[120] "1919"    "1920"    "1921"    "1922"    "1923"    "1924"    "1925"   
[127] "1926"    "1927"    "1928"    "1929"    "1930"    "1931"    "1932"   
[134] "1933"    "1934"    "1935"    "1936"    "1937"    "1938"    "1939"   
[141] "1940"    "1941"    "1942"    "1943"    "1944"    "1945"    "1946"   
[148] "1947"    "1948"    "1949"    "1950"    "1951"    "1952"    "1953"   
[155] "1954"    "1955"    "1956"    "1957"    "1958"    "1959"    "1960"   
[162] "1961"    "1962"    "1963"    "1964"    "1965"    "1966"    "1967"   
[169] "1968"    "1969"    "1970"    "1971"    "1972"    "1973"    "1974"   
[176] "1975"    "1976"    "1977"    "1978"    "1979"    "1980"    "1981"   
[183] "1982"    "1983"    "1984"    "1985"    "1986"    "1987"    "1988"   
[190] "1989"    "1990"    "1991"    "1992"    "1993"    "1994"    "1995"   
[197] "1996"    "1997"    "1998"    "1999"    "2000"    "2001"    "2002"   
[204] "2003"    "2004"    "2005"    "2006"    "2007"    "2008"    "2009"   
[211] "2010"    "2011"    "2012"    "2013"    "2014"    "2015"    "2016"   
[218] "2017"    "2018"    "2019"   

Yes, no other columns in this dataset.

Next, we will use the pivot_longer() to transform the data to long format, similar to what we did in the previous section.

We will also again change the country variable to be Country by using the rename() function, and we will make the Year variable numeric using the mutate() function.

Question Opportunity

Using what you just learned about pivot_longer(), rename(), and mutate() and without scrolling up, try to come up with the code to do the wrangling for this data.

# Try this out!
gdp_growth %>% # let's check before we reassign with %<>%
  pivot_longer(cols = -country,
               names_to = "Year",
               values_to = "gdp_growth")
gdp_growth %>% # let's check before we reassign with %<>%
  pivot_longer(cols = -country,
               names_to = "Year",
               values_to = "gdp_growth") %>%
  rename(Country = country)
gdp_growth %<>%
  pivot_longer(cols = -country,
               names_to = "Year",
               values_to = "gdp_growth") %>%
  rename(Country = country) %>%
  mutate(Year = as.numeric(Year),
         Label = "GDP Growth/Capita (%)") %>%
  rename(GDP = gdp_growth)

Click here to reveal the code.
gdp_growth %<>%
  pivot_longer(cols = -country,
               names_to = "Year",
               values_to = "gdp_growth") %>%
  rename(Country = country) %>%
  mutate(Year = as.numeric(Year),
         Label = "GDP Growth/Capita (%)") %>%
  rename(GDP = gdp_growth)

Now let’s see how this data has changed:

gdp_growth %>%
  slice_head(n = 6)
# A tibble: 6 × 4
  Country      Year   GDP Label                
  <chr>       <dbl> <dbl> <chr>                
1 Afghanistan  1801    NA GDP Growth/Capita (%)
2 Afghanistan  1802    NA GDP Growth/Capita (%)
3 Afghanistan  1803    NA GDP Growth/Capita (%)
4 Afghanistan  1804    NA GDP Growth/Capita (%)
5 Afghanistan  1805    NA GDP Growth/Capita (%)
6 Afghanistan  1806    NA GDP Growth/Capita (%)
gdp_growth %>%
  count(Year)
# A tibble: 219 × 2
    Year     n
   <dbl> <int>
 1  1801   194
 2  1802   194
 3  1803   194
 4  1804   194
 5  1805   194
 6  1806   194
 7  1807   194
 8  1808   194
 9  1809   194
10  1810   194
# ℹ 209 more rows

Again let’s check that the Country variable only contains values we would expect.

# Scroll through the output!
gdp_growth %>%
  distinct(Country) %>%
  pull()
  [1] "Afghanistan"                    "Albania"                       
  [3] "Algeria"                        "Andorra"                       
  [5] "Angola"                         "Antigua and Barbuda"           
  [7] "Argentina"                      "Armenia"                       
  [9] "Australia"                      "Austria"                       
 [11] "Azerbaijan"                     "Bahamas"                       
 [13] "Bahrain"                        "Bangladesh"                    
 [15] "Barbados"                       "Belarus"                       
 [17] "Belgium"                        "Belize"                        
 [19] "Benin"                          "Bhutan"                        
 [21] "Bolivia"                        "Bosnia and Herzegovina"        
 [23] "Botswana"                       "Brazil"                        
 [25] "Brunei"                         "Bulgaria"                      
 [27] "Burkina Faso"                   "Burundi"                       
 [29] "Cambodia"                       "Cameroon"                      
 [31] "Canada"                         "Cape Verde"                    
 [33] "Central African Republic"       "Chad"                          
 [35] "Chile"                          "China"                         
 [37] "Colombia"                       "Comoros"                       
 [39] "Congo, Dem. Rep."               "Congo, Rep."                   
 [41] "Costa Rica"                     "Cote d'Ivoire"                 
 [43] "Croatia"                        "Cuba"                          
 [45] "Cyprus"                         "Czech Republic"                
 [47] "Denmark"                        "Djibouti"                      
 [49] "Dominica"                       "Dominican Republic"            
 [51] "Ecuador"                        "Egypt"                         
 [53] "El Salvador"                    "Equatorial Guinea"             
 [55] "Eritrea"                        "Estonia"                       
 [57] "Ethiopia"                       "Fiji"                          
 [59] "Finland"                        "France"                        
 [61] "Gabon"                          "Gambia"                        
 [63] "Georgia"                        "Germany"                       
 [65] "Ghana"                          "Greece"                        
 [67] "Grenada"                        "Guatemala"                     
 [69] "Guinea"                         "Guinea-Bissau"                 
 [71] "Guyana"                         "Haiti"                         
 [73] "Honduras"                       "Hungary"                       
 [75] "Iceland"                        "India"                         
 [77] "Indonesia"                      "Iran"                          
 [79] "Iraq"                           "Ireland"                       
 [81] "Israel"                         "Italy"                         
 [83] "Jamaica"                        "Japan"                         
 [85] "Jordan"                         "Kazakhstan"                    
 [87] "Kenya"                          "Kiribati"                      
 [89] "Kuwait"                         "Kyrgyz Republic"               
 [91] "Lao"                            "Latvia"                        
 [93] "Lebanon"                        "Lesotho"                       
 [95] "Liberia"                        "Libya"                         
 [97] "Liechtenstein"                  "Lithuania"                     
 [99] "Luxembourg"                     "Macedonia, FYR"                
[101] "Madagascar"                     "Malawi"                        
[103] "Malaysia"                       "Maldives"                      
[105] "Mali"                           "Malta"                         
[107] "Marshall Islands"               "Mauritania"                    
[109] "Mauritius"                      "Mexico"                        
[111] "Micronesia, Fed. Sts."          "Moldova"                       
[113] "Monaco"                         "Mongolia"                      
[115] "Montenegro"                     "Morocco"                       
[117] "Mozambique"                     "Myanmar"                       
[119] "Namibia"                        "Nauru"                         
[121] "Nepal"                          "Netherlands"                   
[123] "New Zealand"                    "Nicaragua"                     
[125] "Niger"                          "Nigeria"                       
[127] "North Korea"                    "Norway"                        
[129] "Oman"                           "Pakistan"                      
[131] "Palau"                          "Palestine"                     
[133] "Panama"                         "Papua New Guinea"              
[135] "Paraguay"                       "Peru"                          
[137] "Philippines"                    "Poland"                        
[139] "Portugal"                       "Qatar"                         
[141] "Romania"                        "Russia"                        
[143] "Rwanda"                         "Samoa"                         
[145] "San Marino"                     "Sao Tome and Principe"         
[147] "Saudi Arabia"                   "Senegal"                       
[149] "Serbia"                         "Seychelles"                    
[151] "Sierra Leone"                   "Singapore"                     
[153] "Slovak Republic"                "Slovenia"                      
[155] "Solomon Islands"                "Somalia"                       
[157] "South Africa"                   "South Korea"                   
[159] "South Sudan"                    "Spain"                         
[161] "Sri Lanka"                      "St. Kitts and Nevis"           
[163] "St. Lucia"                      "St. Vincent and the Grenadines"
[165] "Sudan"                          "Suriname"                      
[167] "Swaziland"                      "Sweden"                        
[169] "Switzerland"                    "Syria"                         
[171] "Tajikistan"                     "Tanzania"                      
[173] "Thailand"                       "Timor-Leste"                   
[175] "Togo"                           "Tonga"                         
[177] "Trinidad and Tobago"            "Tunisia"                       
[179] "Turkey"                         "Turkmenistan"                  
[181] "Tuvalu"                         "Uganda"                        
[183] "Ukraine"                        "United Arab Emirates"          
[185] "United Kingdom"                 "United States"                 
[187] "Uruguay"                        "Uzbekistan"                    
[189] "Vanuatu"                        "Venezuela"                     
[191] "Vietnam"                        "Yemen"                         
[193] "Zambia"                         "Zimbabwe"                      

Also looks good!

Energy Use per Person


Now let’s take a look at the energy use per person data (energy_use) using slice_head() and glimpse().

energy_use %>%
  slice_head(n = 3)
# A tibble: 3 × 57
  country `1960` `1961` `1962` `1963` `1964` `1965` `1966` `1967` `1968` `1969`
  <chr>    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 Albania     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
2 Algeria     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
3 Angola      NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
# ℹ 46 more variables: `1970` <dbl>, `1971` <dbl>, `1972` <dbl>, `1973` <dbl>,
#   `1974` <dbl>, `1975` <dbl>, `1976` <dbl>, `1977` <dbl>, `1978` <dbl>,
#   `1979` <dbl>, `1980` <dbl>, `1981` <dbl>, `1982` <dbl>, `1983` <dbl>,
#   `1984` <dbl>, `1985` <dbl>, `1986` <dbl>, `1987` <dbl>, `1988` <dbl>,
#   `1989` <dbl>, `1990` <dbl>, `1991` <dbl>, `1992` <dbl>, `1993` <dbl>,
#   `1994` <dbl>, `1995` <dbl>, `1996` <dbl>, `1997` <dbl>, `1998` <dbl>,
#   `1999` <dbl>, `2000` <dbl>, `2001` <dbl>, `2002` <dbl>, `2003` <dbl>, …

energy_use %>%
  glimpse()
Rows: 169
Columns: 57
$ country <chr> "Albania", "Algeria", "Angola", "Antigua and Barbuda", "Argent…
$ `1960`  <dbl> NA, NA, NA, NA, NA, NA, 3060, 1550, NA, NA, NA, NA, NA, NA, 25…
$ `1961`  <dbl> NA, NA, NA, NA, NA, NA, 3120, 1550, NA, NA, NA, NA, NA, NA, 25…
$ `1962`  <dbl> NA, NA, NA, NA, NA, NA, 3170, 1680, NA, NA, NA, NA, NA, NA, 28…
$ `1963`  <dbl> NA, NA, NA, NA, NA, NA, 3280, 1820, NA, NA, NA, NA, NA, NA, 30…
$ `1964`  <dbl> NA, NA, NA, NA, NA, NA, 3350, 1860, NA, NA, NA, NA, NA, NA, 30…
$ `1965`  <dbl> NA, NA, NA, NA, NA, NA, 3460, 1850, NA, NA, NA, NA, NA, NA, 31…
$ `1966`  <dbl> NA, NA, NA, NA, NA, NA, 3550, 1900, NA, NA, NA, NA, NA, NA, 30…
$ `1967`  <dbl> NA, NA, NA, NA, NA, NA, 3690, 1920, NA, NA, NA, NA, NA, NA, 31…
$ `1968`  <dbl> NA, NA, NA, NA, NA, NA, 3760, 2050, NA, NA, NA, NA, NA, NA, 35…
$ `1969`  <dbl> NA, NA, NA, NA, NA, NA, 3790, 2180, NA, NA, NA, NA, NA, NA, 38…
$ `1970`  <dbl> NA, NA, NA, NA, NA, NA, 4060, 2420, NA, NA, NA, NA, NA, NA, 41…
$ `1971`  <dbl> 785.0, 232.0, 556.0, NA, 1380.0, NA, 3990.0, 2510.0, NA, NA, 6…
$ `1972`  <dbl> 866.0, 261.0, 584.0, NA, 1380.0, NA, 4040.0, 2630.0, NA, NA, 5…
$ `1973`  <dbl> 763.0, 305.0, 568.0, NA, 1410.0, NA, 4260.0, 2830.0, NA, NA, 8…
$ `1974`  <dbl> 777.0, 319.0, 565.0, NA, 1420.0, NA, 4290.0, 2730.0, NA, NA, 9…
$ `1975`  <dbl> 827.0, 330.0, 536.0, NA, 1380.0, NA, 4350.0, 2650.0, NA, NA, 8…
$ `1976`  <dbl> 891, 367, 515, NA, 1400, NA, 4410, 2870, NA, NA, 9580, 98, NA,…
$ `1977`  <dbl> 924.0, 399.0, 494.0, NA, 1420.0, NA, 4670.0, 2800.0, NA, NA, 8…
$ `1978`  <dbl> 1010.0, 477.0, 527.0, NA, 1430.0, NA, 4630.0, 2890.0, NA, NA, …
$ `1979`  <dbl> 864.0, 586.0, 518.0, NA, 1480.0, NA, 4680.0, 3140.0, NA, NA, 8…
$ `1980`  <dbl> 1150, 579, 511, NA, 1490, NA, 4740, 3070, NA, NA, 7790, 103, N…
$ `1981`  <dbl> 989, 611, 497, NA, 1430, NA, 4690, 2900, NA, NA, 8300, 102, NA…
$ `1982`  <dbl> 967, 771, 473, NA, 1420, NA, 4820, 2830, NA, NA, 9070, 105, NA…
$ `1983`  <dbl> 1000, 808, 469, NA, 1420, NA, 4560, 2840, NA, NA, 8500, 105, N…
$ `1984`  <dbl> 1020, 776, 458, NA, 1450, NA, 4650, 2950, NA, NA, 8830, 104, N…
$ `1985`  <dbl> 917, 786, 470, NA, 1360, NA, 4600, 3050, NA, NA, 9920, 107, NA…
$ `1986`  <dbl> 964, 862, 462, NA, 1420, NA, 4620, 3060, NA, NA, 10300, 111, N…
$ `1987`  <dbl> 922, 828, 461, NA, 1480, NA, 4770, 3170, NA, NA, 9520, 107, NA…
$ `1988`  <dbl> 928, 850, 467, NA, 1500, NA, 4700, 3200, NA, NA, 10500, 114, N…
$ `1989`  <dbl> 896, 820, 465, NA, 1440, NA, 5000, 3140, NA, NA, 10200, 117, N…
$ `1990`  <dbl> 813, 856, 483, 1480, 1410, 2180, 5060, 3240, 3170, 2520, 10600…
$ `1991`  <dbl> 573, 884, 480, NA, 1430, 2320, 4930, 3420, 3090, NA, 10100, 11…
$ `1992`  <dbl> 418, 884, 467, NA, 1480, 1200, 4960, 3250, 2460, NA, 10800, 11…
$ `1993`  <dbl> 412, 868, 468, NA, 1470, 652, 5150, 3260, 2180, NA, 11100, 123…
$ `1994`  <dbl> 441, 819, 459, NA, 1540, 420, 5090, 3230, 1950, NA, 11600, 126…
$ `1995`  <dbl> 417, 839, 445, NA, 1540, 511, 5130, 3370, 1810, NA, 11400, 134…
$ `1996`  <dbl> 448, 798, 445, NA, 1580, 562, 5390, 3580, 1510, NA, 11100, 132…
$ `1997`  <dbl> 385, 805, 443, NA, 1610, 594, 5470, 3550, 1440, NA, 12200, 135…
$ `1998`  <dbl> 427, 821, 430, NA, 1650, 610, 5550, 3610, 1490, NA, 12400, 138…
$ `1999`  <dbl> 576, 864, 439, NA, 1660, 594, 5610, 3590, 1370, NA, 11900, 137…
$ `2000`  <dbl> 580, 866, 437, NA, 1660, 656, 5640, 3570, 1400, NA, 12000, 139…
$ `2001`  <dbl> 597, 856, 442, NA, 1560, 657, 5450, 3760, 1410, NA, 11700, 149…
$ `2002`  <dbl> 660, 904, 447, NA, 1500, 618, 5570, 3770, 1410, NA, 11500, 150…
$ `2003`  <dbl> 648, 949, 466, NA, 1590, 657, 5570, 3970, 1480, NA, 11600, 155…
$ `2004`  <dbl> 715, 948, 462, 1530, 1720, 698, 5600, 4010, 1540, 2060, 10900,…
$ `2005`  <dbl> 720, 974, 431, 1530, 1710, 843, 5560, 4090, 1600, 2110, 11700,…
$ `2006`  <dbl> 707, 1030, 456, 1580, 1840, 865, 5710, 4080, 1560, 2100, 11600…
$ `2007`  <dbl> 680, 1070, 470, 1600, 1850, 973, 5870, 4020, 1410, 2070, 11200…
$ `2008`  <dbl> 711, 1070, 491, NA, 1920, 1030, 5960, 4030, 1520, NA, 11300, 1…
$ `2009`  <dbl> 732, 1150, 514, NA, 1850, 904, 5860, 3800, 1330, NA, 10300, 18…
$ `2010`  <dbl> 729, 1110, 521, NA, 1910, 863, 5790, 4050, 1280, NA, 10200, 20…
$ `2011`  <dbl> 765, 1140, 522, NA, 1930, 944, 5750, 3920, 1370, NA, 9910, 206…
$ `2012`  <dbl> 688, 1220, 553, NA, 1920, 1030, 5570, 3890, 1470, NA, 9660, 21…
$ `2013`  <dbl> 801, 1240, 534, NA, 1950, 1000, 5460, 3920, 1470, NA, 10400, 2…
$ `2014`  <dbl> 808, 1320, 545, NA, 2020, 1020, 5330, 3760, 1500, NA, 10600, 2…
$ `2015`  <dbl> NA, NA, NA, NA, NA, NA, 5480, 3800, NA, NA, NA, NA, NA, NA, 46…

Looks like we have 169 rows and 57 columns where we have a country column and again a set of years. To wrangle the energy_use data, we will again convert the data to long format, rename some variables, and mutate the Year data to be numeric.

Question Opportunity

Again try to come up with the code on your own to wrangle the data.

# Try this out!
energy_use %>% # let's check before we reassign with %<>%
  pivot_longer(cols = -country,
               names_to = "Year",
               values_to = "energy_use") %>%
  rename(Country = country)
energy_use %>% # let's check before we reassign with %<>%
  pivot_longer(cols = -country,
               names_to = "Year",
               values_to = "energy_use") %>%
  rename(Country = country) %>%
  mutate(Year = as.numeric(Year),
         Label = "Energy Use (kg, oil-eq./capita)") %>%
  rename(Energy = energy_use)

Click here to reveal the code.
energy_use %<>%
  pivot_longer(cols = -country,
               names_to = "Year",
               values_to = "energy_use") %>%
  rename(Country = country) %>%
  mutate(Year = as.numeric(Year),
         Label = "Energy Use (kg, oil-eq./capita)") %>%
  rename(Energy = energy_use)

set.seed(123)

energy_use %>%
  slice_sample(n = 3)
# A tibble: 3 × 4
  Country             Year Energy Label                          
  <chr>              <dbl>  <dbl> <chr>                          
1 Dominican Republic  2014    734 Energy Use (kg, oil-eq./capita)
2 Ecuador             2006    671 Energy Use (kg, oil-eq./capita)
3 Turkey              1997   1170 Energy Use (kg, oil-eq./capita)

Now we will check the Country variable:

# Scroll through the output!
energy_use %>%
  distinct(Country) %>%
  pull()
  [1] "Albania"                        "Algeria"                       
  [3] "Angola"                         "Antigua and Barbuda"           
  [5] "Argentina"                      "Armenia"                       
  [7] "Australia"                      "Austria"                       
  [9] "Azerbaijan"                     "Bahamas"                       
 [11] "Bahrain"                        "Bangladesh"                    
 [13] "Barbados"                       "Belarus"                       
 [15] "Belgium"                        "Belize"                        
 [17] "Benin"                          "Bhutan"                        
 [19] "Bolivia"                        "Bosnia and Herzegovina"        
 [21] "Botswana"                       "Brazil"                        
 [23] "Brunei"                         "Bulgaria"                      
 [25] "Cambodia"                       "Cameroon"                      
 [27] "Canada"                         "Cape Verde"                    
 [29] "Chile"                          "China"                         
 [31] "Colombia"                       "Comoros"                       
 [33] "Congo, Dem. Rep."               "Congo, Rep."                   
 [35] "Costa Rica"                     "Cote d'Ivoire"                 
 [37] "Croatia"                        "Cuba"                          
 [39] "Cyprus"                         "Czech Republic"                
 [41] "Denmark"                        "Djibouti"                      
 [43] "Dominica"                       "Dominican Republic"            
 [45] "Ecuador"                        "Egypt"                         
 [47] "El Salvador"                    "Equatorial Guinea"             
 [49] "Eritrea"                        "Estonia"                       
 [51] "Ethiopia"                       "Fiji"                          
 [53] "Finland"                        "France"                        
 [55] "Gabon"                          "Gambia"                        
 [57] "Georgia"                        "Germany"                       
 [59] "Ghana"                          "Greece"                        
 [61] "Grenada"                        "Guatemala"                     
 [63] "Guinea-Bissau"                  "Guyana"                        
 [65] "Haiti"                          "Honduras"                      
 [67] "Hungary"                        "Iceland"                       
 [69] "India"                          "Indonesia"                     
 [71] "Iran"                           "Iraq"                          
 [73] "Ireland"                        "Israel"                        
 [75] "Italy"                          "Jamaica"                       
 [77] "Japan"                          "Jordan"                        
 [79] "Kazakhstan"                     "Kenya"                         
 [81] "Kiribati"                       "Kuwait"                        
 [83] "Kyrgyz Republic"                "Latvia"                        
 [85] "Lebanon"                        "Lesotho"                       
 [87] "Libya"                          "Lithuania"                     
 [89] "Luxembourg"                     "Macedonia, FYR"                
 [91] "Malaysia"                       "Maldives"                      
 [93] "Malta"                          "Marshall Islands"              
 [95] "Mauritius"                      "Mexico"                        
 [97] "Moldova"                        "Mongolia"                      
 [99] "Montenegro"                     "Morocco"                       
[101] "Mozambique"                     "Myanmar"                       
[103] "Namibia"                        "Nepal"                         
[105] "Netherlands"                    "New Zealand"                   
[107] "Nicaragua"                      "Niger"                         
[109] "Nigeria"                        "North Korea"                   
[111] "Norway"                         "Oman"                          
[113] "Pakistan"                       "Palau"                         
[115] "Panama"                         "Paraguay"                      
[117] "Peru"                           "Philippines"                   
[119] "Poland"                         "Portugal"                      
[121] "Qatar"                          "Romania"                       
[123] "Russia"                         "Samoa"                         
[125] "Sao Tome and Principe"          "Saudi Arabia"                  
[127] "Senegal"                        "Serbia"                        
[129] "Seychelles"                     "Singapore"                     
[131] "Slovak Republic"                "Slovenia"                      
[133] "Solomon Islands"                "South Africa"                  
[135] "South Korea"                    "South Sudan"                   
[137] "Spain"                          "Sri Lanka"                     
[139] "St. Kitts and Nevis"            "St. Lucia"                     
[141] "St. Vincent and the Grenadines" "Sudan"                         
[143] "Suriname"                       "Swaziland"                     
[145] "Sweden"                         "Switzerland"                   
[147] "Syria"                          "Tajikistan"                    
[149] "Tanzania"                       "Thailand"                      
[151] "Timor-Leste"                    "Togo"                          
[153] "Tonga"                          "Trinidad and Tobago"           
[155] "Tunisia"                        "Turkey"                        
[157] "Turkmenistan"                   "Ukraine"                       
[159] "United Arab Emirates"           "United Kingdom"                
[161] "United States"                  "Uruguay"                       
[163] "Uzbekistan"                     "Vanuatu"                       
[165] "Venezuela"                      "Vietnam"                       
[167] "Yemen"                          "Zambia"                        
[169] "Zimbabwe"                      

Looks good!

US Specific Data


Now we will take a look at the US data about disasters and temperature.

Disasters


First, we consider the disasters that have occurred in the US.

us_disaster
# A tibble: 40 × 57
    Year `Drought Count` `Drought Cost` `Drought Lower 75` `Drought Upper 75`
   <dbl>           <dbl>          <dbl>              <dbl>              <dbl>
 1  1980               1           33.2               26.4               39.6
 2  1981               0            0                  0                  0  
 3  1982               0            0                  0                  0  
 4  1983               1            7.8                5.5                9  
 5  1984               0            0                  0                  0  
 6  1985               0            0                  0                  0  
 7  1986               1            4.2                3.5                5  
 8  1987               0            0                  0                  0  
 9  1988               1           44.4               33.8               54  
10  1989               1            6.4                5.6                7.4
# ℹ 30 more rows
# ℹ 52 more variables: `Drought Lower 90` <dbl>, `Drought Upper 90` <dbl>,
#   `Drought Lower 95` <dbl>, `Drought Upper 95` <dbl>, `Flooding Count` <dbl>,
#   `Flooding Cost` <dbl>, `Flooding Lower 75` <dbl>,
#   `Flooding Upper 75` <dbl>, `Flooding Lower 90` <dbl>,
#   `Flooding Upper 90` <dbl>, `Flooding Lower 95` <dbl>,
#   `Flooding Upper 95` <dbl>, `Freeze Count` <dbl>, `Freeze Cost` <dbl>, …

We are specifically interested in the Year and the variables that contain the word "Count". The other variables represent an estimate of the economic cost in billions of dollars, as well as the upper and lower bounds for simulations used to estimate the economic cost, which show the level of uncertainty in these estimates (at three different levels of confidence) as the true cost is unknown. See here for more information about the data. For this analysis, we will focus just on the number of disasters that occurred each year.

We will select our variables of interest using the select() and contains() functions in the dplyr package. Since we are selecting for variables with the word "Count" we need to use quotation marks around it.

Selecting for the variable Year does not require quotes because it is the full name of one of the existing variables.

us_disaster %<>%
           select(Year, contains("Count"))

us_disaster %>%
  slice_head(n = 6)
# A tibble: 6 × 8
   Year `Drought Count` `Flooding Count` `Freeze Count` `Severe Storm Count`
  <dbl>           <dbl>            <dbl>          <dbl>                <dbl>
1  1980               1                1              0                    0
2  1981               0                0              1                    1
3  1982               0                0              0                    2
4  1983               1                2              1                    0
5  1984               0                0              0                    2
6  1985               0                0              1                    0
# ℹ 3 more variables: `Tropical Cyclone Count` <dbl>, `Wildfire Count` <dbl>,
#   `Winter Storm Count` <dbl>

Now we want to create a new variable that will be the sum of all the different types of disasters for each year.

We don’t want to include the Year variable in our sum, so we can exclude it using the select function. To perform the sum for each year, we can use the base rowSums() function.

yearly_disasters <- us_disaster %>% 
                      select(-Year) %>%
                      rowSums()

yearly_disasters
 [1]  3  2  3  5  2  5  2  0  1  5  3  4  7  5  6  5  4  3 10  5  4  2  4  7  5
[26]  6  7  5 12  7  6 16 11  9  8 10 15 16 14 14

We could then add this to our us_diaster tibble like so using the bind_cols function of the dplyr package:

us_disaster %>% bind_cols(Disaters = yearly_disasters)
# A tibble: 40 × 9
    Year `Drought Count` `Flooding Count` `Freeze Count` `Severe Storm Count`
   <dbl>           <dbl>            <dbl>          <dbl>                <dbl>
 1  1980               1                1              0                    0
 2  1981               0                0              1                    1
 3  1982               0                0              0                    2
 4  1983               1                2              1                    0
 5  1984               0                0              0                    2
 6  1985               0                0              1                    0
 7  1986               1                0              0                    1
 8  1987               0                0              0                    0
 9  1988               1                0              0                    0
10  1989               1                0              1                    1
# ℹ 30 more rows
# ℹ 4 more variables: `Tropical Cyclone Count` <dbl>, `Wildfire Count` <dbl>,
#   `Winter Storm Count` <dbl>, Disaters <dbl>

However, we can actually create and add this new variable directly to the us_disaster tibble by using the mutate() function of dplyr and using the . notation.

We need to use the . notation to indicate that we are using the data that we already used as input (on the left side of the pipe) to our mutate() function (on the right side of our pipe), which in this case is the entire us_disaster tibble for our select() function. The output from the select() function will be used for the rowSums() function.

us_disaster %<>%
  mutate(Disasters = rowSums(select(., -Year)))

us_disaster %>%
  glimpse()
Rows: 40
Columns: 9
$ Year                     <dbl> 1980, 1981, 1982, 1983, 1984, 1985, 1986, 198…
$ `Drought Count`          <dbl> 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, …
$ `Flooding Count`         <dbl> 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, …
$ `Freeze Count`           <dbl> 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, …
$ `Severe Storm Count`     <dbl> 0, 1, 2, 0, 2, 0, 1, 0, 0, 1, 1, 1, 4, 1, 1, …
$ `Tropical Cyclone Count` <dbl> 1, 0, 0, 1, 0, 3, 0, 0, 0, 1, 0, 1, 2, 0, 1, …
$ `Wildfire Count`         <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, …
$ `Winter Storm Count`     <dbl> 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 2, …
$ Disasters                <dbl> 3, 2, 3, 5, 2, 5, 2, 0, 1, 5, 3, 4, 7, 5, 6, …

Great, now we are going to remove some of these variables and just keep the variables of interest using select().

We are also going to add a new variable called Country to indicate that this data is from the United States. Again this will create a new variable where every value is United States.

us_disaster %<>%
  dplyr::select(Year, Disasters) %>%
  mutate(Country = "United States") %>%
  pivot_longer(cols = c(-Country, -Year),
               names_to = "Indicator",
               values_to = "Value") %>%
  mutate(Label = "Number of Disasters")

us_disaster %>%
  slice_head(n = 6)
# A tibble: 6 × 5
   Year Country       Indicator Value Label              
  <dbl> <chr>         <chr>     <dbl> <chr>              
1  1980 United States Disasters     3 Number of Disasters
2  1981 United States Disasters     2 Number of Disasters
3  1982 United States Disasters     3 Number of Disasters
4  1983 United States Disasters     5 Number of Disasters
5  1984 United States Disasters     2 Number of Disasters
6  1985 United States Disasters     5 Number of Disasters

Great, this looks good now.

Question Opportunity

This dataset was slightly different from the other datasets and therefore required slightly different wrangling. Why was it necessary to exclude the Year variable from the pivot_longer() function? What would happen if we did not exclude Year?

# Try this out!

Temperature


Next, we consider the temperature in the US over time.

us_temperature %>%
  slice_head(n = 6)
# A tibble: 6 × 3
    Date Value Anomaly
   <dbl> <dbl>   <dbl>
1 189512  50.3   -1.68
2 189612  52.0   -0.03
3 189712  51.6   -0.46
4 189812  51.4   -0.59
5 189912  51.0   -1.01
6 190012  52.8    0.75

So a few things need to be fixed here.

First, the Date column looks a bit strange. The format of the numbers look like the year followed by the number 12 (representing 12 months).

We want to change this to only keep the first 4 characters in the Date variable string values.

However, first let’s make sure that indeed all of the Date variables are 6 characters long and that they all end with the number 12.

We can use a couple of functions in the stringr package to do this. This package is used for working with character strings. The str_length() function can be used to check the length of each value, while the str_ends() function can be used to check that all the values end with "12".

Let’s start with the str_length() function. These functions in the stringr package require a character vector. Thus we need to pull the values for the Date variable first using the pull() function of the dplyr package.

us_temperature %>%
  pull(Date) %>%
  str_length()
  [1] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
 [38] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
 [75] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
[112] 6 6 6 6 6 6 6 6 6 6 6 6 6 6

Great! It looks like all of the values are 6 characters long.

Now let’s check that they all end with "12". We just need to specify what pattern to look for.

us_temperature %>%
  pull(Date) %>%
  str_ends(pattern = "12")
  [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [16] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [31] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [46] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [61] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [76] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [91] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[106] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[121] TRUE TRUE TRUE TRUE TRUE

Great! Since all of the values are TRUE we know that all of the values in the Date variable end with "12".

It’s a good idea to always check that your data is as you expect.

Now we can use the str_sub() function of the stringr package to remove the "12" from each Date value.

We just need to indicate the start and stop characters.

In this case the start would be 1 and the 4th character would be where we want to stop, so we would use start = 1, stop = 4. We can do this inside of the mutate() function to modify the Date variable. In doing so, we will not need to use pull() to pull the values for the Date variable.

us_temperature %<>%
  mutate(Date = str_sub(Date, start = 1, end = 4))

us_temperature
# A tibble: 125 × 3
   Date  Value Anomaly
   <chr> <dbl>   <dbl>
 1 1895   50.3   -1.68
 2 1896   52.0   -0.03
 3 1897   51.6   -0.46
 4 1898   51.4   -0.59
 5 1899   51.0   -1.01
 6 1900   52.8    0.75
 7 1901   51.9   -0.15
 8 1902   51.6   -0.43
 9 1903   50.6   -1.4 
10 1904   51.2   -0.86
# ℹ 115 more rows

We also want to remove the Anomaly variable, which is an indicator of how different the national average temperature for that year was from the average temperature from 1901-2000 which was 52.02°F.

Then, we also want to create a Country variable. We will also change the name of the Date variable to Year so that it will be consistent with our other datasets. We also also want the Year to be numeric. We can accomplish both renaming and changing to numeric by using the mutate() function.

We also want to create an Indicator variable so that we can later tell what data the values in this tibble represent if we combine it with other tibbles and a Label variable, so that we will have informative labels if we make a plot with this data later.

Finally, we remove the Date variable and also order the columns just like the other us data using the select() function.

us_temperature %<>%
  dplyr::select(-Anomaly) %>%
  mutate(Country = "United States",
         Year = as.numeric(Date),
         Indicator = "Temperature",
         Label = "Temperature (Fahrenheit)") %>%
  select(Year, Country, Indicator, Value, Label)

us_temperature %>%
  slice_head(n = 6)
# A tibble: 6 × 5
   Year Country       Indicator   Value Label                   
  <dbl> <chr>         <chr>       <dbl> <chr>                   
1  1895 United States Temperature  50.3 Temperature (Fahrenheit)
2  1896 United States Temperature  52.0 Temperature (Fahrenheit)
3  1897 United States Temperature  51.6 Temperature (Fahrenheit)
4  1898 United States Temperature  51.4 Temperature (Fahrenheit)
5  1899 United States Temperature  51.0 Temperature (Fahrenheit)
6  1900 United States Temperature  52.8 Temperature (Fahrenheit)

Joining data


Now that we have wrangled the individual datasets, we are ready to put everything together. Specifically, we will join the individual datasets into one tibble using *_join() functions available in the dplyr package.

Before we begin though, we will need to make sure that there is at least one variable/column that has the same name across all datasets to be joined. Such variables with common names are called keys for joining your data.

These are the by="x1" arguments below where x1 is the name of the column in both the a and b datasets that we will join together.

[source]

There are several types of *_join() functions to consider. The full_join() function keeps all rows from both tibbles that are being joined and adds NA values as necessary if there are values within the key for either of the tibbles that is is not in the key of the other tibble.

We use the full_join() function as we have different time spans for each dataset and we would like to retain as much data as possible.

The full_join() function will simply create NA values for any of the years that are not in one of the datasets.

First, we check using the base summary() function that there are column names that are consistent in each dataset that we wish to combine.

summary(CO2_emissions)
   Country               Year        Emissions           Label          
 Length:50688       Min.   :1751   Min.   :       0   Length:50688      
 Class :character   1st Qu.:1817   1st Qu.:     550   Class :character  
 Mode  :character   Median :1882   Median :    4390   Mode  :character  
                    Mean   :1882   Mean   :   83808                     
                    3rd Qu.:1948   3rd Qu.:   31925                     
                    Max.   :2014   Max.   :10300000                     
                                   NA's   :33772                        
summary(gdp_growth)
   Country               Year           GDP             Label          
 Length:42486       Min.   :1801   Min.   :-67.500   Length:42486      
 Class :character   1st Qu.:1855   1st Qu.:  0.133   Class :character  
 Mode  :character   Median :1910   Median :  0.633   Mode  :character  
                    Mean   :1910   Mean   :  1.302                     
                    3rd Qu.:1965   3rd Qu.:  2.160                     
                    Max.   :2019   Max.   :145.000                     
                                   NA's   :2392                        
summary(energy_use)
   Country               Year          Energy            Label          
 Length:9464        Min.   :1960   Min.   :    9.58   Length:9464       
 Class :character   1st Qu.:1974   1st Qu.:  505.75   Class :character  
 Mode  :character   Median :1988   Median : 1185.00   Mode  :character  
                    Mean   :1988   Mean   : 2238.82                     
                    3rd Qu.:2001   3rd Qu.: 3030.00                     
                    Max.   :2015   Max.   :22000.00                     
                                   NA's   :3544                         

Question Opportunity

What variable or variables might we want to use to join our data by?


Click here to see an explanation for what variable or variables to join by after you have thought about it.

The Country, and Year variables are present in all of the datasets with values that overlap. Although Label is also present in the datasets, the values do not overlap. We can see that the minimum and maximum year is different for nearly all the datasets.

Next, we need to specify what columns/variables we will be joining by using the by = argument in the full_join() function, (recall that this variable is called the “key”)

data_wide <- CO2_emissions %>%
  full_join(gdp_growth, by = c("Country", "Year", "Label")) %>%
  full_join(energy_use, by = c("Country", "Year", "Label"))

set.seed(123)

data_wide %>%
  slice_sample(n = 6)
# A tibble: 6 × 6
  Country                   Year Emissions Label                      GDP Energy
  <chr>                    <dbl>     <dbl> <chr>                    <dbl>  <dbl>
1 Angola                    1899        NA GDP Growth/Capita (%)    0.425     NA
2 Central African Republic  1974        NA GDP Growth/Capita (%)   -4.92      NA
3 Bahamas                   1832        NA CO2 Emissions (Metric … NA         NA
4 Montenegro                1843        NA CO2 Emissions (Metric … NA         NA
5 Croatia                   2015        NA Energy Use (kg, oil-eq… NA         NA
6 Israel                    1885        NA GDP Growth/Capita (%)    0.582     NA

Click here to see an explanation for another option that works well for large numbers of tibbles

We can also do the same thing by using the reduce() function of the purrr package. This takes a list of elements (which can be tibbles) and then applies a function that requires two inputs iteratively using the first pair of elements and creating a single element and then applying the function again to the output element and the next listed element and so on and so forth.

For example we will use a list of tibbles and the full_join() function which requires two tibbles to combine. This will first combine CO2_emissions and gdp_growth and then take the resulting joined tibble and combine this with the energy_use tibble.

You can see that this is a great option if you have many datasets to combine!

data_wide <-
  list(CO2_emissions, gdp_growth, energy_use) %>%
  reduce(full_join, by = c("Country", "Year", "Label"))

set.seed(123)

data_wide %>%
  slice_sample(n = 6)
# A tibble: 6 × 6
  Country                   Year Emissions Label                      GDP Energy
  <chr>                    <dbl>     <dbl> <chr>                    <dbl>  <dbl>
1 Angola                    1899        NA GDP Growth/Capita (%)    0.425     NA
2 Central African Republic  1974        NA GDP Growth/Capita (%)   -4.92      NA
3 Bahamas                   1832        NA CO2 Emissions (Metric … NA         NA
4 Montenegro                1843        NA CO2 Emissions (Metric … NA         NA
5 Croatia                   2015        NA Energy Use (kg, oil-eq… NA         NA
6 Israel                    1885        NA GDP Growth/Capita (%)    0.582     NA
save(data_wide, file = here::here("www", "data", "exercise", "wide_data.rda"))

data_wide %>%
  glimpse()
Rows: 102,638
Columns: 6
$ Country   <chr> "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", …
$ Year      <dbl> 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, …
$ Emissions <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ Label     <chr> "CO2 Emissions (Metric Tons)", "CO2 Emissions (Metric Tons)"…
$ GDP       <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ Energy    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …

Nice, looks good!

We will also make a long version of this data, where we will create an new variable called Indicator that will indicate what dataset the data came from.

Question Opportunity

Try to come up with the code to do this.

# Try this out!
data_long <- data_wide %>%
  pivot_longer(cols = c(-Country, -Year, -Label),
               names_to = "Indicator",
               values_to = "Value")

Click here to reveal the code.
data_long <- data_wide %>%
  pivot_longer(cols = c(-Country, -Year, -Label),
               names_to = "Indicator",
               values_to = "Value")

set.seed(123)

data_long %>%
  slice_sample(n = 6)
# A tibble: 6 × 5
  Country      Year Label                       Indicator   Value
  <chr>       <dbl> <chr>                       <chr>       <dbl>
1 Ethiopia     1829 GDP Growth/Capita (%)       GDP        0.0197
2 Tanzania     1820 CO2 Emissions (Metric Tons) Energy    NA     
3 South Sudan  1907 CO2 Emissions (Metric Tons) GDP       NA     
4 Bangladesh   1931 GDP Growth/Capita (%)       GDP       -2     
5 Mongolia     1805 GDP Growth/Capita (%)       Emissions NA     
6 Spain        1805 CO2 Emissions (Metric Tons) Emissions NA     

We will now combine this data with the US data about disasters and temperatures.

us_disaster %>%
  slice_head(n = 6)
# A tibble: 6 × 5
   Year Country       Indicator Value Label              
  <dbl> <chr>         <chr>     <dbl> <chr>              
1  1980 United States Disasters     3 Number of Disasters
2  1981 United States Disasters     2 Number of Disasters
3  1982 United States Disasters     3 Number of Disasters
4  1983 United States Disasters     5 Number of Disasters
5  1984 United States Disasters     2 Number of Disasters
6  1985 United States Disasters     5 Number of Disasters
us_temperature %>%
  slice_head(n = 6)
# A tibble: 6 × 5
   Year Country       Indicator   Value Label                   
  <dbl> <chr>         <chr>       <dbl> <chr>                   
1  1895 United States Temperature  50.3 Temperature (Fahrenheit)
2  1896 United States Temperature  52.0 Temperature (Fahrenheit)
3  1897 United States Temperature  51.6 Temperature (Fahrenheit)
4  1898 United States Temperature  51.4 Temperature (Fahrenheit)
5  1899 United States Temperature  51.0 Temperature (Fahrenheit)
6  1900 United States Temperature  52.8 Temperature (Fahrenheit)

We will now use the bind_rows() function of the dplyr package which will just append the us_temperature data and the us_disaster data after the data_long data.

data_long <-
  list(data_long, us_disaster, us_temperature) %>%
  bind_rows() %>%
  mutate(Country = as.factor(Country))

We also converted the Country column to a factor in the last line of the code chunk.

We can check the top and bottom of the new data_long tibble to see that our us_temperature data is at the bottom. To see the end of our tibble we can use slice_tail() function of the dplyr package.

data_long %>%
  slice_head(n = 6)
# A tibble: 6 × 5
  Country      Year Label                       Indicator Value
  <fct>       <dbl> <chr>                       <chr>     <dbl>
1 Afghanistan  1751 CO2 Emissions (Metric Tons) Emissions    NA
2 Afghanistan  1751 CO2 Emissions (Metric Tons) GDP          NA
3 Afghanistan  1751 CO2 Emissions (Metric Tons) Energy       NA
4 Afghanistan  1752 CO2 Emissions (Metric Tons) Emissions    NA
5 Afghanistan  1752 CO2 Emissions (Metric Tons) GDP          NA
6 Afghanistan  1752 CO2 Emissions (Metric Tons) Energy       NA
data_long %>%
  slice_tail(n = 6)
# A tibble: 6 × 5
  Country        Year Label                    Indicator   Value
  <fct>         <dbl> <chr>                    <chr>       <dbl>
1 United States  2014 Temperature (Fahrenheit) Temperature  52.5
2 United States  2015 Temperature (Fahrenheit) Temperature  54.4
3 United States  2016 Temperature (Fahrenheit) Temperature  54.9
4 United States  2017 Temperature (Fahrenheit) Temperature  54.6
5 United States  2018 Temperature (Fahrenheit) Temperature  53.5
6 United States  2019 Temperature (Fahrenheit) Temperature  52.7
set.seed(123)

data_long %>%
  slice_sample(n = 10)
# A tibble: 10 × 5
   Country      Year Label                       Indicator   Value
   <fct>       <dbl> <chr>                       <chr>       <dbl>
 1 Ethiopia     1829 GDP Growth/Capita (%)       GDP        0.0197
 2 Tanzania     1820 CO2 Emissions (Metric Tons) Energy    NA     
 3 South Sudan  1907 CO2 Emissions (Metric Tons) GDP       NA     
 4 Bangladesh   1931 GDP Growth/Capita (%)       GDP       -2     
 5 Mongolia     1805 GDP Growth/Capita (%)       Emissions NA     
 6 Spain        1805 CO2 Emissions (Metric Tons) Emissions NA     
 7 Germany      1858 GDP Growth/Capita (%)       Emissions NA     
 8 Fiji         1837 CO2 Emissions (Metric Tons) GDP       NA     
 9 Jamaica      1823 CO2 Emissions (Metric Tons) Emissions NA     
10 Iceland      1926 CO2 Emissions (Metric Tons) Emissions NA     

Click here for details about the difference between full_join() and bind_rows()

The difference between this function and the full_join() function is that the bind_rows() function will essentially just append each dataset to each other, whereas the full_join() function collapses data that is comparable. Here, you will see an example of what the data would have been like for data_wide if we had made it using bind_rows() and if full_join() had been used but was not joined by the Label variable. Since the Label variable has unique values for each type of Indicator, this causes the full_join() result to be the same as bind_rows().

Let’s consider an example and look at the values for China in the year of 1980.

First we will use the bind_rows() function which automatically creates NA values for any variable that is missing from a data object that is added by combining the data object with another that contains that missing variable using this function.

data_wide_br <-
  list(CO2_emissions, gdp_growth, energy_use) %>%
  bind_rows()

data_wide_br %>%
 filter(Country == "China",
           Year == 1980)
# A tibble: 3 × 6
  Country  Year Emissions Label                             GDP Energy
  <chr>   <dbl>     <dbl> <chr>                           <dbl>  <dbl>
1 China    1980   1470000 CO2 Emissions (Metric Tons)     NA        NA
2 China    1980        NA GDP Growth/Capita (%)            2.16     NA
3 China    1980        NA Energy Use (kg, oil-eq./capita) NA       609

We see that we have three rows of data.

Now we will use the full_join() function two ways. First we will combine by Country and Year and Label.

data_wide_fj_label <-
  list(CO2_emissions, gdp_growth, energy_use) %>%
  reduce(full_join, by = c("Country", "Year", "Label"))

data_wide_fj_label %>%
  filter(Country == "China", Year == "1980")
# A tibble: 3 × 6
  Country  Year Emissions Label                             GDP Energy
  <chr>   <dbl>     <dbl> <chr>                           <dbl>  <dbl>
1 China    1980   1470000 CO2 Emissions (Metric Tons)     NA        NA
2 China    1980        NA GDP Growth/Capita (%)            2.16     NA
3 China    1980        NA Energy Use (kg, oil-eq./capita) NA       609

Again we have 3 rows of data. The data produced by bind_rows() and full_join() is identical (which we can check by using the setequal() function of the dplyr package) and has the same dimensions (which we can check by using the dim() base function).

dim(data_wide_br)
[1] 102638      6
dim(data_wide_fj_label)
[1] 102638      6
setequal(data_wide_fj_label, data_wide_br)
[1] TRUE

However, now we will join by only Country and Year:

data_wide_fj <-
  list(CO2_emissions, gdp_growth, energy_use) %>%
  reduce(full_join, by = c("Country", "Year"))

data_wide_fj %>%
  filter(Country == "China", Year == "1980")
# A tibble: 1 × 8
  Country  Year Emissions Label.x                       GDP Label.y Energy Label
  <chr>   <dbl>     <dbl> <chr>                       <dbl> <chr>    <dbl> <chr>
1 China    1980   1470000 CO2 Emissions (Metric Tons)  2.16 GDP Gr…    609 Ener…

Now we see that we have only a single row. The data that corresponds to the same year and country has been collapsed into a single but wider row.

This is something to keep in mind when you are wrangling your data. The choice of what function to use and how should depend on how you want the data to be after you combine the different sources of data together.


We have a few more things to do before we leave the data wrangling section.

We will create a new variable called Region that will indicate if the data is about the United States or a different country based on the values in the Country variable. To do this, we will use the case_when() function of the dplyr package.

For example, if the Country variable is equal to "United States" the value for the new variable will also be "United States", where as if the Country variable is not equal to "United States" but is some other character string value, such as "Afghanistan", then the value for the new variable will be "Rest of the World". We can specify that something is not equal by using the != operator.

The new values for the new variable Region are indicated after the specific conditional statements by using the ~ symbol.

data_long %<>%
  mutate(Region = case_when(Country == "United States" ~ "United States",
                            Country != "United States" ~ "Rest of the World"))

data_long  %>%
  arrange(Country) %>%
  slice_head(n = 6)
# A tibble: 6 × 6
  Country      Year Label                       Indicator Value Region          
  <fct>       <dbl> <chr>                       <chr>     <dbl> <chr>           
1 Afghanistan  1751 CO2 Emissions (Metric Tons) Emissions    NA Rest of the Wor…
2 Afghanistan  1751 CO2 Emissions (Metric Tons) GDP          NA Rest of the Wor…
3 Afghanistan  1751 CO2 Emissions (Metric Tons) Energy       NA Rest of the Wor…
4 Afghanistan  1752 CO2 Emissions (Metric Tons) Emissions    NA Rest of the Wor…
5 Afghanistan  1752 CO2 Emissions (Metric Tons) GDP          NA Rest of the Wor…
6 Afghanistan  1752 CO2 Emissions (Metric Tons) Energy       NA Rest of the Wor…

We can also remove rows for countries with NA values using the drop_na() function of the tidyr package to drop all years with missing data.

data_long_with_miss <-
  data_long %>%
  arrange(Country)

data_long %<>%
  drop_na() %>%
  arrange(Country)

You can see that by removing the NA values the data for Afghanistan starts at 1949 instead of 1751.

data_long %>%
  slice_head(n = 6)
# A tibble: 6 × 6
  Country      Year Label                       Indicator Value Region          
  <fct>       <dbl> <chr>                       <chr>     <dbl> <chr>           
1 Afghanistan  1949 CO2 Emissions (Metric Tons) Emissions  14.7 Rest of the Wor…
2 Afghanistan  1950 CO2 Emissions (Metric Tons) Emissions  84.3 Rest of the Wor…
3 Afghanistan  1951 CO2 Emissions (Metric Tons) Emissions  91.7 Rest of the Wor…
4 Afghanistan  1952 CO2 Emissions (Metric Tons) Emissions  91.7 Rest of the Wor…
5 Afghanistan  1953 CO2 Emissions (Metric Tons) Emissions 106   Rest of the Wor…
6 Afghanistan  1954 CO2 Emissions (Metric Tons) Emissions 106   Rest of the Wor…

Question Opportunity

Taking the data_long object, and using only data from the US, calculate the first and last year that a value was reported for each Label (e.g. CO2 emissions, energy use, etc). Do not save this data, but simply view it but not reassigning data_long.

Hint : Use the group_by() and summarize() functions in the dplyr package.

# Try this out!
data_long %>%
  filter(Country == "United States") %>%
    group_by(Label) %>% 
    summarize(first_reported_year = min(Year),
              last_reported_year = max(Year))

To allow users to skip import and wrangling we will save the data as an RDA file as well as a CSV file as this is often useful to send our data to collaborators. We will save this in a “wrangled” subdirectory of our “data” directory of our working directory.

save(data_long, file = here::here("data", "wrangled", "wrangled_data.rda"))
readr::write_csv(data_long, path = here::here("data","wrangled", "wrangled_data.csv"))

Exercise


We have created a dataset called wide_format that is in “wide” format. Write some code to convert it to “long” format. (We want 3 columns with names “ID”, “Variable”, and “Value”.)

wide_format
  ID Year Length
1  1 2015   20.0
2  2 2018   21.5
3  3 2019   19.0
wide_format %>%
  pivot_longer()
wide_format %>%
  pivot_longer(cols = -ID, names_to = "Variable", values_to = "Value")

 

mtcars is a built-in R dataset as shown below. Use this dataset to complete the following exercise.

mtcars
                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2

Write some code that will:

  1. Create a new dataset called new.mtcars from mtcars.
  2. Create a new column called car in new.mtcars that uses the values from the row names of mtcars. (Use the rownames_to_column function from the tibble package. See documentation here.)
  3. Only keep the car, mpg, and cyl columns of this new.mtcars dataset.
  4. Only keep the cars that have cyl = 4.
  5. Rearrange the dataset by mpg in descending order.
  6. Check your data by looking at the full new.mtcars object.

Note: replace the underscores(“_”) with your code with one character per “_”. Click “Submit Answer” to check your answer.

# step 1
new.mtcars <- mtcars %>%
  # step 2
  rownames_to_column(var = "___") %>%
  # step 3
  ______(___, ___, ___) %>%
  # step 4
  ______(___ == _) %>%
  # step 5
  _______(____(mpg))

new.mtcars
# step 2:
# The "var" argument is the name of the new column that will use the values from the row names. What is the column name?
# step 2:
# The "var" argument is the name of the new column that will use the values from the row names. What is the column name?

# step 3:
# Which function of the "dplyr" package select columns?
# step 2:
# The "var" argument is the name of the new column that will use the values from the row names. What is the column name?

# step 3:
# Which function of the "dplyr" package select columns?

# step 4:
# Which function of the "dplyr" package subset rows?
# step 2:
# The "var" argument is the name of the new column that will use the values from the row names. What is the column name?

# step 3:
# Which function of the "dplyr" package select columns?

# step 4:
# Which function of the "dplyr" package subset rows?

# step 5:
# Which function of the "dplyr" package will reorder the data?
# What argument do we need to reorder in descending order?
# Next hint will show you the solution
new.mtcars <- mtcars %>%
  rownames_to_column(var = "car") %>%
  select(car, mpg, cyl) %>%
  filter(cyl == 4) %>%
  arrange(desc(mpg))

new.mtcars

Data Visualization


If you have been following along but stopped, we could load our imported data like so:

load(here::here("data", "wrangled", "wrangled_data.rda"))

If you skipped the data wrangling section click here.

An RDA file (stands for R data) of the data can be found here or slightly more directly here. Download this file and then place it in your current working directory within a subdirectory called “wrangled” within a subdirectory called “data” to copy and paste our code. We used an RStudio project and the here package to navigate to the file more easily.

load(here::here("data", "wrangled", "wrangled_data.rda"))

Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



Now we will create some simple plots to examine the CO2 emissions over time using the ggplot2 package.

As you may have already seen, there are many functions available in base R that can create plots (e.g. plot(), boxplot()). Others include: hist(), qqplot(), etc. These functions are great because they come with a basic installation of R and can be quite powerful when you need a quick visualization of something when you are exploring data.

We are choosing to introduce ggplot2 because, in our opinion, it is one of the simplest ways for beginners to create relatively complicated plots that are intuitive and aesthetically pleasing.

The ggplot2 R package


The reasons ggplot2 is generally intuitive for beginners is the use of grammar of graphics or the gg in ggplot2. The idea is that you can construct many sentences by learning just a few nouns, adjectives, and verbs. There are specific “words” that we will introduce, and once you are comfortable with them, you will be able to create (or “write”) hundreds of different plots.

The critical part to making graphics using ggplot2 is the data needs to be in a tidy format. Given that we have just spent time putting our data in tidy format, we are primed to take advantage of all that ggplot2 has to offer!

We will show how it is easy to pipe tidy data (output) as input to other functions that create plots. This all works because we are working within the tidyverse.

What is the ggplot() function?

As explained by Hadley Wickham:

the grammar tells us that a statistical graphic is a mapping from data to aesthetic attributes (colour, shape, size) of geometric objects (points, lines, bars). The plot may also contain statistical transformations of the data and is drawn on a specific coordinates system.

ggplot2 Terminology

  • ggplot - the main function where you specify the dataset and variables to plot (this is where we define the x and y variable names)
  • geoms - geometric objects
    • e.g. geom_point(), geom_bar(), geom_line(), geom_histogram()
  • aes - aesthetics
    • shape, transparency, color, fill, line types
  • scales - define how your data will be plotted
    • continuous, discrete, log, etc

The function aes() is an aesthetic mapping function inside the ggplot() object. We use this function to specify plot attributes (e.g. x and y variable names) that will not change as we add more layers.

Anything that goes in the ggplot() object becomes a global setting. From there, we use the geom objects to add more layers to the base ggplot() object. These will define what we are interested in illustrating using the data.

CO2 Emissions

Let’s start by plotting the CO2 emissions over time. Because our dataset contains other variables, we first need to filter our data to only include the CO2 emissions data by using the filter() function of the dplyr package. To use this function we need to specify what value (e.g. Emissions) we want for a given variable or column (e.g. Indicator).

In this case, we filter to keep all rows where the Indicator variable is equal to the word Emissions. Notice that this needs to be in quotes, while the variable name does not.

data_long %>%
  filter(Indicator == "Emissions")
# A tibble: 16,916 × 6
   Country      Year Label                       Indicator Value Region         
   <fct>       <dbl> <chr>                       <chr>     <dbl> <chr>          
 1 Afghanistan  1949 CO2 Emissions (Metric Tons) Emissions  14.7 Rest of the Wo…
 2 Afghanistan  1950 CO2 Emissions (Metric Tons) Emissions  84.3 Rest of the Wo…
 3 Afghanistan  1951 CO2 Emissions (Metric Tons) Emissions  91.7 Rest of the Wo…
 4 Afghanistan  1952 CO2 Emissions (Metric Tons) Emissions  91.7 Rest of the Wo…
 5 Afghanistan  1953 CO2 Emissions (Metric Tons) Emissions 106   Rest of the Wo…
 6 Afghanistan  1954 CO2 Emissions (Metric Tons) Emissions 106   Rest of the Wo…
 7 Afghanistan  1955 CO2 Emissions (Metric Tons) Emissions 154   Rest of the Wo…
 8 Afghanistan  1956 CO2 Emissions (Metric Tons) Emissions 183   Rest of the Wo…
 9 Afghanistan  1957 CO2 Emissions (Metric Tons) Emissions 293   Rest of the Wo…
10 Afghanistan  1958 CO2 Emissions (Metric Tons) Emissions 330   Rest of the Wo…
# ℹ 16,906 more rows

We also need to sum the emissions across countries for each year. Here, we use the group_by() and summarize() function that we previously learned about.

data_long %>%
  filter(Indicator == "Emissions") %>%
  group_by(Year) %>%
  summarize(Emissions = sum(Value))
# A tibble: 264 × 2
    Year Emissions
   <dbl>     <dbl>
 1  1751      9360
 2  1752      9360
 3  1753      9360
 4  1754      9370
 5  1755      9370
 6  1756     10000
 7  1757     10000
 8  1758     10000
 9  1759     10000
10  1760     10000
# ℹ 254 more rows

Then, we use the aes() argument of the ggplot() function to define that our x-axis will be the Year variable, the y-axis will be the emission Value variable, and that our data should be grouped or separated by the Country variable.

data_long %>%
  filter(Indicator == "Emissions") %>%
  group_by(Year) %>%
  summarize(Emissions = sum(Value)) %>%
  ggplot(aes(x = Year, y = Emissions))

Looks like we got a blank plot. What happened? We need to tell R what type of plot we want. To do that, we need to add another layer to define how we want the plot to look. We do so by using the + sign in between each command.

Line plots

To tell R what type of plot we want, we need to add another layer to our ggplot object. To add a type of plot, we can use one of the many geom_* functions in ggplot2. For example, type geom into the RStudio console and you will see many options to scroll through.

Here, we will use the geom_line() function because we would like to create a line plot. We also use the size argument in geom_line() to control the size of the line.

data_long %>%
  filter(Indicator == "Emissions") %>%
  group_by(Year) %>%
  summarize(Emissions = sum(Value)) %>%
  ggplot(aes(x = Year, y = Emissions)) +
    geom_line(size = 1.5)

Wow, the CO2 is really rising sharply!

Finally, let’s make this plot really nice by adding a few final touches. To change title, caption, and the axis labels, we can use the labs() function. Again, notice that a plus sign is used between each layer that we add to the plot. To make CO2 appear with a subscript we can use ~CO[2]~.

data_long %>%
  filter(Indicator == "Emissions") %>%
  group_by(Year) %>%
  summarize(Emissions = sum(Value)) %>%
  ggplot(aes(x = Year, y = Emissions)) +
    geom_line(size = 1.5) +
    labs(title = "World " ~CO[2]~ " Emissions per Year (1751-2014)",
         caption = "Limited to reporting countries",
         y = "Emissions (Metric Tonnes)")

Next, we use the theme() function to change the font size of the x-axis, y-axis, axis titles, and the caption as shown below. To know what to call each element of the plot in this function to change the size type ?theme() in the console.

You will see a very large list that includes other plot aspects like the background and the legend. This function can be used to modify your plot to your specifications.

data_long %>%
  filter(Indicator == "Emissions") %>%
  group_by(Year) %>%
  summarize(Emissions = sum(Value)) %>%
  ggplot(aes(x = Year, y = Emissions)) +
    geom_line(size = 1.5) +
    labs(title = "World " ~CO[2]~ " Emissions per Year (1751-2014)",
         caption = "Limited to reporting countries",
         y = "Emissions (Metric Tonnes)") +
  theme_linedraw() +
  theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
       axis.title.x = element_text(size = 12),
       axis.title.y = element_text(size = 12),
       plot.caption = element_text(size = 12),
         plot.title = element_text(size = 16))

We can clearly see that global CO2 emissions have dramatically risen since 1900.

Notice, we used the function theme_linedraw() of ggplot2 to change the general appearance of the plot.

Useful tip: You can type theme_ in the RStudio console to see the various plot theme options available.

Great! We’ve created our first plot.

Before we leave this section, let’s save this theme so we do not have to keep typing the same code in future plots.

my_theme <-
  theme_linedraw() +
  theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
       axis.title.x = element_text(size = 12),
       axis.title.y = element_text(size = 12),
       plot.caption = element_text(size = 12),
         plot.title = element_text(size = 16))

In this way, we can just add another layer to our plot with the my_theme we created with the specifications of the sizes of the title and axis labels.

CO2_world <-
  data_long %>%
  filter(Indicator == "Emissions") %>%
  group_by(Year) %>%
  summarize(Emissions = sum(Value)) %>%
  ggplot(aes(x = Year, y = Emissions)) +
    geom_line(size = 1.5) +
    labs(title = "World " ~CO[2]~ " Emissions per Year (1751-2014)",
         caption = "Limited to reporting countries",
         y = "Emissions (Metric Tonnes)") +
  my_theme

We are also saving the plot to an object called CO2_world. To show the plot we simply type the name of the object:

CO2_world

Now let’s say we wanted to save this plot.

We could do so using the using the save() function to save this to a “plot” directory in our working directory as an RDA file and we can use the png() function to save a png for collaborators. We need to use dev.off() function to close the graphical device that we will use to create the png version of the plot so that we are ready to make another plot like this.

save(CO2_world, file =here::here("plots", "CO2_world.rda"))
png(here::here("plots", "CO2_world.png"))
CO2_world
dev.off()

One thing that would be nice to know is which countries are contributing the most or the least to CO2 emissions. Let’s continue to explore the data to investigate how CO2 emissions from individual countries have changed over time.

Next, we go back to using our data_long dataset. Here, we use the group argument in aes() which controls whether a line should be drawn

data_long %>%
  filter(Indicator == "Emissions") %>%
  ggplot(aes(x = Year, y = Value, group = Country)) +
  geom_line() +
  ylab("Emissions") +
  my_theme

We can see that many countries show a dramatic increase in emissions over time with a handful of countries with particularly high levels.

Question Opportunity

  • What happens when you do not use the group = Country argument?
  • What other aesthetic (i.e. aes() arguments) can be changed?

# Find out yourself!
data_long %>%
  filter(Indicator == "Emissions") %>%
  ggplot(aes(x = Year, y = Value)) +
  geom_line() +
  ylab("Emissions") +
  my_theme

Since we have many overlapping lines, we will make our lines slightly transparent by using the alpha argument.

This takes values from 0 to 1, where 0 is completely transparent and 1 is completely opaque.

We also add our my_theme controlling the size of the title and axis labels.

CO2_countries <-
  data_long %>%
  filter(Indicator == "Emissions") %>%
  ggplot(aes(x = Year, y = Value, group = Country)) +
  geom_line(alpha = 0.4) +
  labs(title = "Country" ~CO[2]~ "Emissions per Year (1751-2014)",
     caption = "Limited to reporting countries",
           y = "Emissions (Metric Tonnes)") +
  my_theme

CO2_countries

Our plot is starting to look really good. One question you still might have is which country corresponds to which line? Which line indicates the emissions in the US?

Adding color

We can add another “layer” on top of our first plot to add a blue line just for the US data. To do this we need to indicate what data we would like to plot, so we need to filter for just the US data and then we need to indicate that it will be colored by Country, even though in this case we only have one line to color. The default color would be a salmon pink color, but we would like blue. So we will use the scale_color_manual() function to manually choose the color that we want by using scale_colour_manual(values = c("blue")). Often you might use red to highlight a subset of the data, however, this can be difficult for viewers with certain types of colorblindness.

Notice how the color name needs to be in quotes and that the argument values = is used to specify what color values to use.

We can add this line to the plot in two ways.

Useful tip: Instead of retyping the original code to create the CO2_countries plot, we can just use the + operator:

CO2_countries +
  geom_line(data = data_long %>%
              filter(Indicator == "Emissions",
                     Country == "United States"),
              aes(x = Year, y = Value, color = Country)) +
  scale_colour_manual(values = c("blue"))

It looks like the US has long been the largest CO2 emission producing country until recently, when the US was surpassed by another country.

Let’s figure out who are the top 10 emission producing countries in 2014. Here, we filter the data for the year 2014, which was the final year of the data. Then, we can make a rank variable based on the Value variable for the amount of emissions produced.

There are many functions in the dplyr package for ranking values that are based on the SQL or specifically SQL rank functions. SQL is another programming language for managing large amounts of data. The difference in the rank functions mostly has to do with how to deal with ties in the data.
We will use dense_rank(), as we do not want gaps between ranks.

We want to do this in descending order because we want to rank by largest to smallest, so we will use the desc() function of the dplyr package. Then, we will arrange the output by rank using the arrange() function of the dplyr package.

top_10_count <-
  data_long %>%
  filter(Indicator == "Emissions", Year == 2014) %>%
  mutate(rank = dense_rank(desc(Value))) %>%
  filter(rank <= 10) %>%
  arrange(rank)

top_10_count
# A tibble: 10 × 7
   Country        Year Label                       Indicator  Value Region  rank
   <fct>         <dbl> <chr>                       <chr>      <dbl> <chr>  <int>
 1 China          2014 CO2 Emissions (Metric Tons) Emissions 1.03e7 Rest …     1
 2 United States  2014 CO2 Emissions (Metric Tons) Emissions 5.25e6 Unite…     2
 3 India          2014 CO2 Emissions (Metric Tons) Emissions 2.24e6 Rest …     3
 4 Russia         2014 CO2 Emissions (Metric Tons) Emissions 1.71e6 Rest …     4
 5 Japan          2014 CO2 Emissions (Metric Tons) Emissions 1.21e6 Rest …     5
 6 Germany        2014 CO2 Emissions (Metric Tons) Emissions 7.20e5 Rest …     6
 7 Iran           2014 CO2 Emissions (Metric Tons) Emissions 6.49e5 Rest …     7
 8 Saudi Arabia   2014 CO2 Emissions (Metric Tons) Emissions 6.01e5 Rest …     8
 9 South Korea    2014 CO2 Emissions (Metric Tons) Emissions 5.87e5 Rest …     9
10 Canada         2014 CO2 Emissions (Metric Tons) Emissions 5.37e5 Rest …    10

We can see that China is now the top emission producing country.

Question Opportunity

What are the bottom 10 emission producing countries in 2014?

# Write some code to find out
# 1st way: rank in descending order as we did before 
# 2nd way: rank in ascending order
bottom_10_count <-
  data_long %>%
  filter(Indicator == "Emissions", Year == 2014)
# 1st way of doing this
bottom_10_count <-
  data_long %>%
  filter(Indicator == "Emissions", Year == 2014) %>%
  mutate(rank = dense_rank(desc(Value))) %>%
  filter(rank >= max(rank) - 9) %>%
  arrange(rank)
bottom_10_count
# 2nd way of doing this
bottom_10_count <-
  data_long %>%
  filter(Indicator == "Emissions", Year == 2014) %>%
  mutate(rank = dense_rank(Value)) %>%
  filter(rank <= 10) %>%
  arrange(rank)
bottom_10_count
# Can you think of other ways? Try them out!

Let’s make a plot of just these top ten countries.

To do this, we need to filter the data to just these top countries by using the %in% operator to only keep countries in our Country variable that are also in the Country variable within top_10_count. We can use the pull() function also of the dplyr package to specifically grab just the Country data out of top_10_count.

Since we have 10 countries we will want to differentiate them by color.

To color our plot we will use the viridis color palette which is compatible with color-blindness by using the scale_color_viridis_d() function. This function is available by loading the ggplot2 package. There are a few variations for discrete values as _d, or binned continuous values as _b, or continuous values as _c. See here for more information.

Top10b <- data_long %>%
  filter(Country %in% pull(top_10_count, Country)) %>%
  filter(Indicator == "Emissions") %>%
  filter(Year >= 1900) %>%
  ggplot(aes(x = Year, y = Value, color = Country)) +
    geom_line() +
    scale_color_viridis_d() +
    labs(title = "Top 10 Emissions-producing Countries in 2010 (1900-2014)",
         subtitle = "Ordered by Emissions Produced in 2014",
         y = "Emissions (Metric Tons)",
         x = "Year") +
    my_theme

Top10b

It’s still a bit difficult to tell which line corresponds to which country. So, let’s add a text label directly to the plot. .

Adding text labels

One way to do this is to add text layer to our plot using the geom_text() function of the ggplot2 package. We need to first specify what variable or column we will use. However, we only want to pull the text labels for the top ten countries in the last year. To do this, we use the last() function of the dplyr package.

Then, we need to indicate that our text label will be based on the Country variable using the aes() aesthetics mapping argument. We will also get rid of our legend since we will not need it anymore, by using the theme() function of the ggplot2 package.

Top10b +
  geom_text(data = data_long %>%
              filter(Country %in% pull(top_10_count, Country)) %>%
              filter(Indicator == "Emissions") %>%
              filter(Year == last(Year)),
            aes(label = Country)) +
  theme(legend.position = "none")

Not bad, but some of the labels are overlapping and difficult to read. We can use the check_overlap = TRUE argument within the geom_text() function to remove overlapping variables. Also, we can expand the plot area horizontally so that the names are not cutoff by using scale_x_continuous(expand = c(0.2,0)). This takes a vector with two values. The first value indicates what percentage to expand the x axis in both directions. In our case we will expand by 15 percent. The second value indicates what absolute value to expand the limit of the x axis. In our case c(0.15,0) will achieve a similar result as c(0, 17), as the range of values from 1990 to 2014 is 114 years and 15% of this is 17.

Top10b +
  geom_text(data = data_long %>%
              filter(Country %in% pull(top_10_count, Country)) %>%
              filter(Indicator == "Emissions") %>%
              filter(Year == last(Year)),
            aes(label = Country),
            check_overlap = TRUE) +
  scale_x_continuous(expand = c(0.15, 0)) +
  theme(legend.position = "none")

This is easier to read now, but it also causes us to lose some of the labels. There are several alternative ways we can keep all of our labels and make them easier to read. The first package we will show is called directlabels.

The most simple option is to use the direct.label() function, which will automatically add labels at the end of the lines. However, it is a bit difficult to see some of our labels as they get automatically sized to fit the plot.

direct.label(Top10b) +
  scale_x_continuous(expand = c(0.3, 0))

Alternatively this can be done within the ggplot2 framework by layering using the geom_dl() function.

Top10b +
  scale_x_continuous(expand = c(0.3, 0)) +
  geom_dl(aes(label = Country), method = list("last.points","bumpup")) +
  theme(legend.position = "none")

This is more legible now. We have all 10 countries names listed and they are in order of the last data point and they are relatively close to the lines that they correspond to.

Another option is to use a different method in the directlables package. Here is a list of options.

For example, the "angled.boxes" method looks nice for some plots but does not work very well for our plot:

direct.label(Top10b, method = list("angled.boxes")) +
  scale_x_continuous(expand = c(0.3, 0))

However the "last.polygons" method works quite well:

direct.label(Top10b, method = list("last.polygons")) +
  scale_x_continuous(expand = c(0.3, 0))

The second package is the ggrepel package, which is especially good for crowded labels that might overlap one another. It allows for more control than the directlabels package.

Specifically, we will use the geom_text_repel() function from the ggrepel package. Just like with geom_text(), first we need to specify what data we want to include. Then, we specify with the aes() argument that our label will be based on the Country variable and we again specify what variable to use for our x axis and y axis, so that we indicate where the labels should be plotted.

Top10b +
  geom_text_repel(data = data_long %>%
                    filter(Country %in% pull(top_10_count, Country)) %>%
                    filter(Indicator == "Emissions") %>%
                    filter(Year == last(Year)),
                  aes(label = Country, x = Year, y = Value)) +
  theme(legend.position = "none") +
  scale_x_continuous(expand = c(0.3, 0))

You can see that this package creates segments that connect the label to the line.

There are many arguments to use to style your labels just the way that you want:

[source]

See the ggrepel vignette for more details.

Let’s play around with some of these options in the table above.

Top10b +
  geom_text_repel(data = data_long %>%
                    filter(Country %in% pull(top_10_count, Country)) %>%
                    filter(Indicator == "Emissions") %>%
                    filter(Year == last(Year)),
                  aes(label = Country, x = Year, y = Value),
                  nudge_x = 10,
                  hjust = 1,
                  vjust = 1,
                  segment.size = 0.25,
                  force = 1) +
  theme(legend.position = "none") +
  scale_x_continuous(expand = c(0.3, 0)) +
  scale_y_continuous(expand = c(0.3, 0))

Nice, that looks pretty good. For fun, let’s try showing our data in an entirely different way.

Tile plots

This time we will create a geom_tile plot.

To create this plot we will filter our data to include only the Countries included in the Country variable of the top_10_count.

Then, we will use the fct_reorder() function of the forcats package to order our countries based on the last emission value in 2014.

To use this function, the variable that is to be reordered is listed first. The variable that is being used to determine the order is listed second. Finally, a function to apply to the variable listed second is listed third. This function is used to determine the order. In this case, we want to determine the last value of the Value variable using the last() function (recall that this is also a function of the dplyr package). Then, the Country variable will be ordered by the last value of the Value variable.

To color our plot we will use the viridis color palette again but this time we will use the scale_fill_viridis_c() – recall that the _c indicates a continuous scale. See the scale_viridis reference for more information.

Top10t <-
  data_long %>%
  filter(Country %in% pull(top_10_count, Country)) %>%
  filter(Indicator == "Emissions") %>%
  filter(Year >= 1900) %>%
  ggplot(aes(x = Year, y = fct_reorder(Country, Value, last))) +
    geom_tile(aes(fill = log(Value))) +
    scale_fill_viridis_c()

Finally, let’s clean up the axes and the axes labels:

Top10t <- Top10t +
  scale_x_continuous(breaks = seq(1900, 2014, by = 5),
                     labels = seq(1900, 2014, by = 5)) +
  labs(title = "Top 10 " ~CO[2]~ "Emission-producing Countries",
       subtitle = "Ordered by Emissions Produced in 2014",
       fill = "Ln(CO2 Emissions (Metric Tonnes))") +
  theme_classic() +
  theme(axis.text.x = element_text(size = 12, angle = 90, color = "black"),
        axis.text.y = element_text(size = 12, color = "black"),
        axis.title = element_blank(),
        plot.caption = element_text(size = 12),
        plot.title = element_text(size = 16),
        legend.position = "bottom")

Top10t

Now let’s say we wanted to save this plot.

We could do so using the using the save() function to save this to a “plot” directory in our working directory as an RDA file and we can use the png() function to save a png for collaborators. We need to use dev.off() function to close the graphical device that we will use to create the png version of the plot so that we are ready to make another plot like this.

save(Top10t, file =here::here("plots", "Top10t.rda"))
png(here::here("plots", "Top10t.png"))
Top10t
dev.off()

We see that Germany had very low emission rates at the end of World War II. We also see that the US has consistently had high emission rates since 1900, but the emission rates in China recently surpassed that of the US. The portions of the plot that are white indicate that there is no emission data for that country.

Question Opportunity

Think about what the pros and cons are of tile and line plots. In what situations would a tile plot be a better choice for effective scientific communication? In what situations would a line plot be a better choice?

More than one variable


Now, we will visualize all the variables in our dataset.

Faceted plots

Here, we use the facet_wrap() function of the ggplot2 package, which plots multiple subplots simultaneously.

To use facet_wrap() with the option for a different y-axis scale for each subplot, we need to set the scales argument equal to "free_y". We can also indicate where we would like the label for the subplots to be located by using the strip.position argument.

ggplot(data_long, aes(x = Year, y = Value, group = Country)) +
  geom_line(alpha = 0.2) +
  geom_line(data = data_long %>%
              filter(Country == "United States"),
              aes(x = Year, y = Value, color = Country)) +
  scale_colour_manual(values = c("blue")) +
  labs(title = "Distribution of Indicators by Year and Value",
       y = "Indicator Value") +
  my_theme +
  theme(strip.text = element_text(size = 16, face = "bold")) +
  facet_wrap(Indicator ~ .,
             scales = "free_y",
             strip.position = "right",
             ncol = 1)

Notice that we can change the size or style of the font for these labels using the strip.text = argument of the theme() function. We can also specify how many rows or columns we would like the subplots to be shown.

We can also facet by more than one variable (e.g. Indicator and Region to show the data from the US compared to other countries).

In this case we want the same y-axis to be used across the rows. We will use the facet_grid() function this time instead of facet_wrap() because of the way that the two facet variables are displayed. The facet_grid() function will as you might expect, create an output of plots that are displayed in a grid.

The syntax here is to put the name of the two variables on the left or right side of the ~ symbol, which tells you to facet by rows (left) or columns (right).

First, we will filter out the data about disasters and temperature as this is only for the US, by using the filter() function and ! indicates that we want only values of the Indicator variable not in the list containing "Disasters" and "Temperature".

data_long %>%
  filter(!(Indicator %in% c("Disasters", "Temperature"))) %>%
  ggplot(aes(x = Year, y = Value, group = Country)) +
    geom_line() +
    facet_grid(Indicator ~ Region, scales = "free_y") +
    labs(title = "Distribution of Indicators by Year and Value",
         y = "Indicator Value") +
    my_theme +
    theme(strip.text = element_text(size = 16, face = "bold"))

From these plots we can see that each type of data spans a different time span.

Question Opportunity

What happens when you create the same plot with facet_wrap()? Why might this be preferable in certain cases?

# Try this out!

Question Opportunity

Calculate the total number of countries per year reporting C02 emissions, energy use and GDP. Plot this summary statistic (y-axis) across the years (x-axis). What do you see?

Hint : Use the tally() function in the dplyr package.

# Your code here

Line segment plots

There are also some other common visualization techniques that are good for showing the difference between a set of observations and a mean value across time.

One of those is a line segment plot. For simplicity, let’s focus only on the data from the US. Let’s calculate the mean across all years for the CO2 emission and temperature from 1980 to 2010. Recall that our Indicator variable describes what kind of data we have (Emissions, Temperature, GDP, Energy, Disasters). We will calculate the mean for each Indicator set of data by first grouping by this variable and then calculating the mean of the values of the Value variable for each set of data. We will call this new variable Mean. Then, we calculate the difference between each observation and the mean and create a new variable for these values called Diff_from_mean. Again, all of this is performed for each group of data separately. Once we have created the new variables, we want to use the ungroup() function so that we no longer perform functions on subsets of the data based on the Indicator variable. Finally, we will also create a factor variable about the sign of the Diff_from_mean value to distinguish positive or negative changes. We will use this to color our plots.

data_long_us <-
  data_long %>%
  filter(Country == "United States", Year >= 1980, Year <= 2010) %>%
  group_by(Indicator) %>%
  mutate(Mean = mean(Value), Diff_from_mean = Value - Mean) %>%
  ungroup() %>%
  mutate(Diff_color = sign(Diff_from_mean)) %>%
  mutate(Diff_color = as.factor(Diff_color))
glimpse(data_long_us)
Rows: 155
Columns: 9
$ Country        <fct> "United States", "United States", "United States", "Uni…
$ Year           <dbl> 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1…
$ Label          <chr> "CO2 Emissions (Metric Tons)", "CO2 Emissions (Metric T…
$ Indicator      <chr> "Emissions", "Emissions", "Emissions", "Emissions", "Em…
$ Value          <dbl> 4720000, 4540000, 4310000, 4340000, 4480000, 4490000, 4…
$ Region         <chr> "United States", "United States", "United States", "Uni…
$ Mean           <dbl> 5134194, 5134194, 5134194, 5134194, 5134194, 5134194, 5…
$ Diff_from_mean <dbl> -414193.548, -594193.548, -824193.548, -794193.548, -65…
$ Diff_color     <fct> -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,…

Next, we use the geom_segment() function to draw a straight line between points (x, y) and (xend, yend). In our case, this creates a plot that shows a bar for the difference between the observation and the mean across all the years.

data_long_us %>%
  filter(Indicator %in% c("Emissions", "Temperature", "Disasters")) %>%
  ggplot(aes(x = Year, y = Value)) +
    geom_segment(aes(x = Year, y = Value, xend = Year,
                     yend = Mean, color = Diff_color),
                 size = 3.25) +
  scale_color_manual(values = c("blue", "red")) +
  geom_hline(aes(yintercept = Mean), linetype = 1, color = "black") +
  facet_wrap(Indicator ~ ., scales = "free_y", ncol = 1) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 90),
         axis.title = element_blank(),
    legend.position = "none")  +
  labs(title = "US Disasters, Emissions, and Temperatures (1990-2010)",
    subtitle = "Indicator Mean of 1990-2010 Represented by Solid Black Line")

We can see from this plot that overall there has been an increase in disasters, emissions and temperature in the most recent years.

Question Opportunity

What trends do you see in GDP and energy use across time?

Scatter plots

Next, let’s zoom in on two of the variables: CO2 emissions and temperature. We use years between 1980 and 2014 as we have values for all of those years for these two variables.

We know that the datasets do not span the same amount of time. So let’s limit this plot to only the years where the data overlaps for both CO2 emissions and temperature.

We use the geom_point() function to create a scatter plot between the x and y variable defined in aes() where x is time and y is one of the two variables. We also add a line on top of the scatter plot that smooths the trend from the points. The smoother we used here is loess locally estimated scatterplot smoothing, a type of local polynomial regression fitting. This is a nonparametric regression that is also called a “moving regression” where subsets of points that are close to one another (hence the term local) are used in a least squares linear or nonlinear fit. Thus this results in a fit that may curve with the data.

CO2_temp_US_facet <-
  data_long %>%
  filter(Country == "United States", Year >= 1980, Year <= 2014,
         Indicator %in% c("Emissions", "Temperature")) %>%
  ggplot(aes(x = Year, y = Value)) +
  geom_point() +
  geom_smooth(method = "loess", se = FALSE) +
  scale_x_continuous(breaks = seq(1980, 2014, by = 5),
                     labels = seq(1980, 2014, by = 5)) +
  facet_wrap(Label ~ ., scales = "free_y", ncol = 1) +
  theme_classic() +
  theme(axis.text.x = element_text(size = 12, angle = 90, color = "black"),
        axis.text.y = element_text(size = 12, color = "black"),
        strip.text.x = element_text(size = 14),
         axis.title = element_blank(),
         plot.title = element_text(size = 16))
  labs(title = "US Emissions and Temperatures (1980-2014)")
$title
[1] "US Emissions and Temperatures (1980-2014)"

attr(,"class")
[1] "labels"
CO2_temp_US_facet

Note, we are showing a different theme here, namely the theme_classic() theme. We can see that there are similar patterns of CO2 emission levels and average annual temperatures.

We will save this plot now like so to our “plots” directory:

save(CO2_temp_US_facet, file =here::here("plots", "CO2_temp_US_facet.rda"))
png(here::here("plots", "CO2_temp_US_facet.png"))
CO2_temp_US_facet
dev.off()

Question Opportunity

  • Try show a similar plot without filtering by years and faceting by the other three variables: energy use, GDP and disasters. Are there other variables that look like they might have a similar pattern to CO2 emissions?
  • Try using a different smoother in geom_smooth().

# Your code here

Next, instead of looking at the variables separately in faceted plots, let’s look at the relationship between CO2 emissions and other variables directly. Thus, it is useful to have each of these indicators as their own variable.

We can do this by using pivot_wider() to transform our long data table into a wide format.

wide_US <-
  data_long %>%
  filter(Country == "United States", Year >= 1980, Year <= 2014) %>%
  select(-Label) %>%
  pivot_wider(names_from = Indicator, values_from = Value)

Let’s save this data as an rda file for future use and as a csv file, as this is often useful for collaborators. We will save this in a “wrangled” subdirectory of our “data” directory of our working directory.

save(wide_US, file = here::here("data", "wrangled", "wrangled_US_data.rda"))
readr::write_csv(wide_US, path = here::here("data", "wrangled", "wrangled_US_data.csv"))

Now we can specify which indicators we want to look at, so now we can specifically look at emissions and temperature.

CO2_temp_US <-
  wide_US %>%
  ggplot(aes(x = Emissions, y = Temperature)) +
    geom_point() +
    theme_classic() +
    theme(axis.text.x = element_text(size = 12, color = "black"),
          axis.text.y = element_text(size = 12, color = "black"),
           axis.title = element_text(size = 14),
           plot.title = element_text(size = 16)) +
    labs(title = "US Emissions and Temperature (1980-2014)",
         x = "Emissions (Metric Tonnes)",
         y = "Temperature (Fahrenheit)")


CO2_temp_US

It might be helpful to add a trend line to this. We can do so by using the geom_smooth() function of the ggplot2 package.

If we want to look at a linear trend we need to specify the method using the method = lm argument. This adds a line to the data based on a linear model of the data using the lm function of the stats package. We will discuss the se = FALSE argument later.

We can just add this to the plot object that we just created to create a plot with this trend line.

CO2_temp_US <- CO2_temp_US + geom_smooth(method = "lm", se = FALSE)
CO2_temp_US 

Indeed, it does look like there is a positive, linear trend.

We will also save this plot:

save(CO2_temp_US, file =here::here("plots", "CO2_temp_US.rda"))
png(here::here("plots", "CO2_temp_US.png"))
CO2_temp_US
dev.off()

Question Opportunity

  • Make similar plots for between CO2 emissions and other variables.
  • Are there other pairs variables that look like they might have a similar pattern to CO2 emissions?
  • Does this match what we saw above?
  • Do these trend look linear or non-linear?

# Your code here

Now that we see that there might be a linear relationship between CO2 emissions and temperature, let’s learn about some statistical techniques to measure the strength of that relationship.

Exercise


Suppose that we have a dataset called weight. Write some code to plot weight change by individual.
We want the plot to:

  • have title as “Weight Change”
  • have \(x\) axis as “Time_day” and \(y\) axis be “Weight_lb”
  • be a line plot
  • have different colors representing IDs 1, 2, and 3
  • have legend on the right of the plot

Note: first we need to use as.character() to convert “ID” from number to character.

weight
  ID Time_day Weight_lb
1  1        0       120
2  1       15       128
3  1       30       122
4  2        0       172
5  2       15       176
6  2       30       180
7  3        0       155
8  3       15       154
9  3       30       155
weight$ID <- as.character(weight$ID)
weight$ID <- as.character(weight$ID)
weight %>%
  ggplot(aes())
weight$ID <- as.character(weight$ID)
weight %>%
  ggplot(aes(x = Time_day, y = Weight_lb, color = ID)) +
  geom_line() +
  labs(title = "Weight Change")

Data Analysis


If you are following along and stopped you could load the data you will need like so:

load(here::here("data", "wrangled", "wrangled_US_data.rda"))

If you skipped the previous sections click here.

An RDA file (stands for R data) of the data (called wrangled_US_data.rda) can be found here or slightly more directly here. Download this file and then place it in your current working directory within a subdirectory called “wrangled” within a subdirectory called “data” to copy and paste our code. We used an RStudio project and the here package to navigate to the file more easily.

load(here::here("data", "wrangled", "wrangled_US_data.rda"))

Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



In this section, we are going to introduce some ways to better understand how two variables move together. We will focus on the CO2 emissions and temperature, but you will be encouraged to explore the relationship between CO2 emissions and the other variables.

Basic summary statistics


We can always calculate the sample mean and variance for two variables.

wide_US %>%
  summarize(mean(Emissions), mean(Temperature), sd(Emissions), sd(Temperature))
# A tibble: 1 × 4
  `mean(Emissions)` `mean(Temperature)` `sd(Emissions)` `sd(Temperature)`
              <dbl>               <dbl>           <dbl>             <dbl>
1          5142286.                52.9         450549.             0.891

These are useful, but on their own they do not summarize whether or not there is a relationship between Emissions and Temperature (also these are on different scales entirely).

What else could we use? Next, we are going to learn about the correlation coefficient, which is a summary statistic that describes how two variables are related or move together.

Correlation coefficient


We can use the correlation coefficient. Here, we are using this summary statistic to measure the strength of a linear relationship between two variables.

If we plot one variable on the x-axis and the other variable on the y-axis, we can see:

  1. The strength of the relationship - based on how well the points form a line
  2. The direction of the relationship - based on if the points progress upward or downward

If the variables point upward in a very clear line, then there is a strong positive relationship. If the points do not really form a line, then there is a weak linear relationship or no linear relationship. There may however be a nonlinear relationship if the points create a different but defined shape.

See here for more information on nonlinear relationships.

If the points form a downward sloping line, then there is a negative relationship.

[source]

The numbers below each plot above are called correlation coefficients. They range from -1 to 1. A value of zero indicates that there is no correlation between the variables. While a value of 1 or -1 indicates perfect correlation, the closer the coefficient is to 1 or -1, the stronger the relationship. The sign of the coefficient indicates the direction of the relationship. If there is a negative relationship then the variables show opposing changes from each other - as one gets larger the other gets smaller. If the sign is positive, then the variables increase similarly.

We previously made this plot:

load(here::here("plots", "CO2_temp_US.rda"))
CO2_temp_US

Let’s calculate the Pearson’s correlation coefficient called “Rho” \(\rho\) between CO2 emissions and temperature in the US. There are a few ways to calculate a correlation coefficient and this is one of the most common.

Formally, if we have a pair of observations \((x_1, y_1), \dots, (x_n,y_n)\), the correlation coefficient \(\rho\) between \(x\) and \(y\) is defined as

\[ \rho = \frac{1}{n-1} \sum_{i=1}^n \left( \frac{x_i-\mu_x}{\sigma_x} \right)\left( \frac{y_i-\mu_y}{\sigma_y} \right) \] where \(\mu_x, \mu_y\) are the means of \(x_1,\dots, x_n\) and \(y_1, \dots, y_n\), respectively, and \(\sigma_x, \sigma_y\) are the standard deviations.

Therefore, we can standardize the two variables and essentially average (the denominator is n-1) the standardized values to calculate the correlation coefficient rho.

Here we will manually perform the calculation. We will use the tally() function of the dplyr package to get the number of samples \(n\). In this case this is equivalent to the number of rows in the wide_US tibble. We need to then use the pull() function to specifically grab the value out of the tibble that is created from using this function. As you can see from using the base class() function that this is a tbl_df which is short for tibble data frame (the tidyverse version of a data frame) rather than just a number.

tally(wide_US)
# A tibble: 1 × 1
      n
  <int>
1    35
class(tally(wide_US))
[1] "tbl_df"     "tbl"        "data.frame"

When we check the class after using the pull() function we see that it is an integer.

pull(tally(wide_US), n)
[1] 35
class(pull(tally(wide_US), n))
[1] "integer"

We will also use the base scale() function to standardize the Emissions and Temperature values.

wide_US %>%
  summarize(rho = (1/(pull(tally(wide_US), n) -1)) *(sum(scale(Emissions) * scale(Temperature)))) %>%
  pull(rho)
[1] 0.4711717

Alternatively, you can use the cor() function in base R like so:

wide_US %>%
  summarize(r = cor(x = Emissions,
                    y = Temperature, 
               method = "pearson")) %>%
  pull(r)
[1] 0.4711717

If you want to learn more about why this is the calculation to determine the strength of the relationship between two variables, see this link.

Question Opportunity

There are different types of correlation coefficients. Look at the help file for the cor() function by typing ?cor() into the RStudio Console to learn more and then try a different method.

What are the differences?

Question Opportunity

  • Try calculating the correlation coefficient between CO2 emissions and the other variables.
  • What do you expect?

To test if the association between a pair of variables is statistically significant, you can use the cor.test() of the stats package to calculate the correlation coefficient, as well as confidence intervals for correlation coefficients.

We can use the tidy() function of the broom package to make the output more usable for working with in R. The role of this function is to pull numeric values from outputs and create a data frame of the values.

cor.test(pull(wide_US, Emissions),
         pull(wide_US, Temperature))

    Pearson's product-moment correlation

data:  pull(wide_US, Emissions) and pull(wide_US, Temperature)
t = 3.0686, df = 33, p-value = 0.004277
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.1636155 0.6952523
sample estimates:
      cor 
0.4711717 
broom::tidy(cor.test(pull(wide_US, Emissions),
         pull(wide_US, Temperature)))
# A tibble: 1 × 8
  estimate statistic p.value parameter conf.low conf.high method     alternative
     <dbl>     <dbl>   <dbl>     <int>    <dbl>     <dbl> <chr>      <chr>      
1    0.471      3.07 0.00428        33    0.164     0.695 Pearson's… two.sided  

We see that the correlation coefficient quantifying the strength of the linear relationship between C02 emissions and temperature is statistically significant.

Relationship between correlation and linear regression


Let’s briefly discuss the relationship between correlation and linear regression, which is further described in the Introduction to Data Science book.

We can use a regression line to predict a random variable \(Y\) given that we have gathered or observed some data about another variable \(X=x\). The regression line formally is defined as:

\[ \left( \frac{Y-\mu_Y}{\sigma_Y} \right) = \rho \left( \frac{x-\mu_X}{\sigma_X} \right) \] where \(\mu_X\) and \(\sigma_X\) (\(\mu_Y\) and \(\sigma_Y\)) are the mean and standard deviation of \(X\) (\(Y\)), and \(\rho\) is correlation between \(X\) and \(Y\). If \(x\) is larger than \(\mu_X\), then for every \(\sigma_X\), then \(Y\) will also increase \(\rho\) standard deviations above \(\mu_Y\).

Re-organizing the terms so that \(Y\) is on the left side and everything else is on the right side, we get:

\[ Y = \mu_Y + \rho \left( \frac{x-\mu_X}{\sigma_X} \right) \sigma_Y \] Thinking about some extreme examples:

  • If \(\rho\) = 0 (i.e. no correlation), we ignore the \(x\) term entirely and only predict \(Y\) using the mean \(\mu_Y\).
  • If \(\rho\) = 1 (or -1) (i.e. perfect correlation), the regression line predicts an increase (or decrease) that is the same number of SDs.
  • If \(\rho\) is between -1 and 1, then we predict using both terms on the right hand side.

To add regression lines to plots, we will need the above formula in the form:

\[ y= b + mx \mbox{ with slope } m = \rho \frac{\sigma_y}{\sigma_x} \mbox{ and intercept } b=\mu_y - m \mu_x \]

In our example, we can calculate the slope and intercept using the formula above and plot the line.

wide_US_summary <-
  wide_US %>%
  summarize(mu_x = mean(Emissions), sd_x = sd(Emissions),
            mu_y = mean(Temperature), sd_y = sd(Temperature),
            rho = cor(Emissions, Temperature),
            slope = rho * sd_y / sd_x,
            intercept = mu_y - rho * sd_y / sd_x * mu_x)

wide_US %>%
  ggplot(aes(x = Emissions, y = Temperature)) +
    geom_point() +
    geom_abline(slope = wide_US_summary$slope,
                intercept = wide_US_summary$intercept) +
  theme_linedraw() +
  theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
       axis.title.x = element_text(size = 12),
       axis.title.y = element_text(size = 12),
       plot.caption = element_text(size = 12),
         plot.title = element_text(size = 16))

Note: In the plot above, we use the scale of the original variables (CO2 emission and temperature), but the formula above implies that standardization of the variables (i.e. subtracting the mean and dividing by the standard deviation) allows the regression line to have an intercept of 0 and slope equal to \(\rho\). A similar plot in standardized units is given below.

CO2_temp_US_scaled<-wide_US %>%
  ggplot(aes(x = scale(Emissions), y = scale(Temperature))) +
    geom_point() +
    geom_smooth(method = "lm", se = FALSE) +
  labs(title = "US" ~ CO[2]~ "Emissions and Temperature (1980-2014)",
         y = "Scaled Temperature (Fahrenheit)",
         x = "Scaled Emissions (Metric Tonnes)") +
  theme_linedraw() +
  theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
       axis.title.x = element_text(size = 14),
       axis.title.y = element_text(size = 14),
       plot.caption = element_text(size = 12),
         plot.title = element_text(size = 16))

CO2_temp_US_scaled

Notice that we also use the geom_smooth(method = "lm") function that we previously used. Again, this adds a line corresponding to the slope and intercept from the lm() function from the stats R package.

Question Opportunity

What does se = FALSE mean? Try turning it to TRUE. What happens?

# Try this out!

Click here for the answer. se stands for standard error. The gray shading shows the confidence interval of the smooth line.

Limitations of Correlation


While correlation is useful in many settings to understand how two variables move together, correlation is not always a useful summary. For example, here are ways it might not be useful:

  • A linear relationship might not be the best way to capture the relationship.
  • If an individual were interested in understanding a causal relationship between two variables, as correlation does not imply causation. Another way of stating this is that simply showing there is a linear trend over time does not imply there is a causal relationship between these two variables.

As you can see from this plot, often data may show a similar pattern over time by random chance. See this website for more examples.

[source]

In this example and in our case study, data was collected over time. This type of data will often have what is called autocorrleation or serial correlation. This means that data points from one year to the next may be similar to one another or have some sort of internal structure related to time (such as seasonality). Let’s think about our CO2 emission and temperature data. You may be able to see how one year of CO2 emissions might be fairly similar to next year, because the number of sources (such as industrial factories and cars) in the US will change slightly from year to year, but they will be related to that of the previous years. Anytime we look at correlation between two variables that each have autocorrelation, this can result in a higher likelihood of correlation between these variables.

Indeed if we look at correlation between two random variables with autocorrelation we can see an inflation in the correlation rho values between the two variables, as compared to that of variables that do not have autocorrelation.

This is something to keep in mind when you evaluate how two things are related to one another over time. There are methods that have been developed to account for this in time series analysis (analyzing data over time). This does not mean that two variables (such as CO2 and temperature) may not be in fact correlated, it just means that we need to account for the autocorrelation within each variable, however this is beyond the scope of this case study.

Exercise


Summary


Summary Plot


The last thing we will do here is to create a plot that summarizes our major findings. We will use the plot_layout() function of the patchwork R package. The patchwork allows you to create a plot layout based on mathematical-like formulas. As you can see in this example we want the CO2_world and Top10t plot on top and we want another row with the CO2_temp_US_facet and the CO2_temp_US plot on the bottom. The plot_layout() function of the patchwork package then allows us to specify heights and widths for the plots.

We will also save the figure using the grDevices png() function. We can specify the name of our plot file and where we want it to be saved using the here() function of the here package. In this case in the img subdirectory of the directory containing our .Rproj file. We can also specify the size of the plot and the resolution using the res argument. The grDevices dev.off() function is necessary to close the graphics device.

This will include a few plots that we made previously in other sections. We saved these in the “plots” directory and will load these now for users who stopped and restarted or started at the data analysis section.

load(here::here("plots", "CO2_world.rda"))
load(here::here("plots", "Top10t.rda"))
load(here::here("plots", "CO2_temp_US_facet.rda"))
png(here::here("img", "mainplot.png"), units = "in", width = 12, height = 10, res = 300)
(CO2_world | Top10t) / (CO2_temp_US_facet | CO2_temp_US_scaled) +
  plot_layout(widths = c(1, 2),
              heights = unit(c(4, 10), c('cm', 'cm')))
dev.off()

Synopsis


In this case study we evaluated CO2 emissions from as far back as 1751 for some countries to 2014. We discovered that global levels of CO2 emissions have dramatically increased over time. We also learned that some countries have been responsible for particularly high levels.

We also took a look at how CO2 emissions might relate to other factors, such as temperature, energy use, and natural disasters. We learned that we can summarize the relationship between two sets of data using correlation coefficients. We also learned that we can use regression to predict or describe how changes in one variable may influence changes in another variable. Importantly, we also learned that just because two variables show strong correlation or show an association, it does not necessarily indicate that they are causally related.

However, there is quite a bit of scientific evidence to indicate that in fact CO2 emissions trap heat and lead to increased global temperatures. Yet, it is important to realize that there are other factors involved in the relationship between US CO2 emissions and US annual average temperatures. For example there are CO2 emissions from other countries in the atmosphere, there are other greenhouse gases, there is already existing CO2 in the atmosphere that will continue to trap heat for many years, and finally there is heat trapped in the ocean due to previous emissions that will cause delayed changes in surface temperatures. However, it is vital that we work around the globe to reduce future greenhouse gas emissions to mitigate the increased temperatures that we will experience due to previous and existing CO2 emissions, so that the warming temperatures aren’t as extreme as they could be. Furthermore, we need to prepare for increased rates of natural disasters and how these may influence people around the world. Evidence suggests that impoverished people are the most affected by disasters. We need to be particularly mindful of this as we prepare for the future.

Suggested Homework


Ask students to create a plot with labels showing the countries with the lowest CO2 emission levels.

Ask students to plot CO2 emissions and other variables (e.g. energy use) on a scatter plot, calculate the Pearson’s correlation coefficient, and discuss results.

Additional information


Session Info


sessionInfo()
R version 4.3.2 (2023-10-31)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so;  LAPACK version 3.10.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

time zone: Etc/UTC
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] patchwork_1.2.0        broom_1.0.5            ggrepel_0.9.5         
 [4] directlabels_2024.1.21 ggplot2_3.4.4          forcats_1.0.0         
 [7] tidyr_1.3.1            purrr_1.0.2            stringr_1.5.1         
[10] magrittr_2.0.3         dplyr_1.1.4            readr_2.1.5           
[13] readxl_1.4.3           gradethis_0.2.14       learnr_0.11.5.9000    
[16] here_1.0.1             knitr_1.45             shiny_1.8.1           

loaded via a namespace (and not attached):
 [1] gtable_0.3.4      xfun_0.43         bslib_0.6.2       htmlwidgets_1.6.4
 [5] lattice_0.21-9    tzdb_0.4.0        quadprog_1.5-8    vctrs_0.6.5      
 [9] tools_4.3.2       generics_0.1.3    parallel_4.3.2    tibble_3.2.1     
[13] fansi_1.0.6       highr_0.10        pkgconfig_2.0.3   Matrix_1.6-1.1   
[17] checkmate_2.3.1   lifecycle_1.0.4   farver_2.1.1      compiler_4.3.2   
[21] munsell_0.5.0     fontawesome_0.5.2 httpuv_1.6.15     htmltools_0.5.8  
[25] sass_0.4.9        yaml_2.3.8        later_1.3.2       pillar_1.9.0     
[29] crayon_1.5.2      jquerylib_0.1.4   ellipsis_0.3.2    cachem_1.0.8     
[33] nlme_3.1-163      mime_0.12         commonmark_1.9.1  tidyselect_1.2.0 
[37] digest_0.6.35     stringi_1.8.3     splines_4.3.2     labeling_0.4.3   
[41] rprojroot_2.0.4   fastmap_1.1.1     grid_4.3.2        colorspace_2.1-0 
[45] cli_3.6.2         utf8_1.2.4        withr_3.0.0       scales_1.3.0     
[49] promises_1.2.1    backports_1.4.1   bit64_4.0.5       rmarkdown_2.26   
[53] bit_4.0.5         cellranger_1.1.0  hms_1.1.3         evaluate_0.23    
[57] viridisLite_0.4.2 mgcv_1.9-0        markdown_1.12     rlang_1.1.3      
[61] Rcpp_1.0.12       xtable_1.8-4      glue_1.7.0        vroom_1.6.4      
[65] jsonlite_1.8.8    R6_2.5.1         

Acknowledgments


We would like to acknowledge Megan Latshaw for assisting in framing the major direction of the case study.

We would also like to acknowledge the Bloomberg American Health Initiative for funding this work.

LS0tCnRpdGxlOiB8CiAgIVtdKGh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9pbWcvaWNvbi1iYWhpLnBuZyl7d2lkdGg9MTIwcHggYWxpZ249bGVmdCBzdHlsZT0icGFkZGluZy1yaWdodDogMjBweCJ9CiAgRXhwbG9yaW5nIENPMiBlbWlzc2lvbnMgYWNyb3NzIHRpbWUKY3NzOiB3d3cvc3R5bGUuY3NzCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgaW5jbHVkZXM6CiAgICAgICBpbl9oZWFkZXI6IHd3dy9HQV9TY3JpcHQuUmh0bWwKICAgIHNlbGZfY29udGFpbmVkOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwpydW50aW1lOiBzaGlueV9wcmVyZW5kZXJlZAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAnOTAlJykKbGlicmFyeShrbml0cikKbGlicmFyeShoZXJlKQpsaWJyYXJ5KGxlYXJucikKbGlicmFyeShncmFkZXRoaXMpCmdyYWRldGhpczo6Z3JhZGV0aGlzX3NldHVwKCkKYGBgCgo8IS0tIE9wZW4gYWxsIGxpbmtzIGluIG5ldyB0YWItLT4gIAo8YmFzZSB0YXJnZXQ9Il9ibGFuayIvPiAKCgo8ZGl2IGFsaWduPSJsZWZ0IiBpZD0iZ29vZ2xlX3RyYW5zbGF0ZV9lbGVtZW50Iiw+PC9kaXY+Cgo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPScvL3RyYW5zbGF0ZS5nb29nbGUuY29tL3RyYW5zbGF0ZV9hL2VsZW1lbnQuanM/Y2I9Z29vZ2xlVHJhbnNsYXRlRWxlbWVudEluaXQnPjwvc2NyaXB0PgoKPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPgpmdW5jdGlvbiBnb29nbGVUcmFuc2xhdGVFbGVtZW50SW5pdCgpIHsKICBuZXcgZ29vZ2xlLnRyYW5zbGF0ZS5UcmFuc2xhdGVFbGVtZW50KHtwYWdlTGFuZ3VhZ2U6ICdlbid9LCAnZ29vZ2xlX3RyYW5zbGF0ZV9lbGVtZW50Jyk7Cn0KPC9zY3JpcHQ+CgoKIyMjIyB7Lm91dGxpbmUgfQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4IiwgZHBpPTMwMH0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInd3dy9pbWcvbWFpbnBsb3QucG5nIikKYGBgCgojIyMjCgojIyMjIHsuZGlzY2xhaW1lcl9ibG9ja30KCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pe3RhcmdldD0iX2JsYW5rIn0gcHJvamVjdCBpcyAqKnRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdmFyaW91cyBkYXRhIHNjaWVuY2UgbWV0aG9kcywgdG9vbHMsIGFuZCBzb2Z0d2FyZSBpbiB0aGUgY29udGV4dCBvZiBtZXNzeSwgcmVhbC13b3JsZCBkYXRhKiouIEEgZ2l2ZW4gY2FzZSBzdHVkeSBkb2VzIG5vdCBjb3ZlciBhbGwgYXNwZWN0cyBvZiB0aGUgcmVzZWFyY2ggcHJvY2VzcywgaXMgbm90IGNsYWltaW5nIHRvIGJlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHdheSB0byBhbmFseXplIGEgZ2l2ZW4gZGF0YXNldCwgYW5kIHNob3VsZCBub3QgYmUgdXNlZCBpbiB0aGUgY29udGV4dCBvZiBtYWtpbmcgcG9saWN5IGRlY2lzaW9ucyB3aXRob3V0IGV4dGVybmFsIGNvbnN1bHRhdGlvbiBmcm9tIHNjaWVudGlmaWMgZXhwZXJ0cy4gCgojIyMjCgojIyMjIHsubGljZW5zZV9ibG9ja30KClRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob25Db21tZXJjaWFsIDMuMCBbKENDIEJZLU5DIDMuMCldKGh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy8zLjAvdXMvKXt0YXJnZXQ9Il9ibGFuayJ9ICBVbml0ZWQgU3RhdGVzIExpY2Vuc2UuCgojIyMjCgojIyMjIHsucmVmZXJlbmNlX2Jsb2NrfQoKVG8gY2l0ZSB0aGlzIGNhc2Ugc3R1ZHkgcGxlYXNlIHVzZToKCldyaWdodCwgQ2FycmllIGFuZCBPbnRpdmVyb3MsIE1pY2hhZWwgYW5kIEphZ2VyLCBMZWFoIGFuZCBUYXViLCBNYXJnYXJldCBhbmQgSGlja3MsIFN0ZXBoYW5pZS4gKDIwMjApLiBodHRwczovL2dpdGh1Yi5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1jbzItZW1pc3Npb25zLiBFeHBsb3JpbmcgQ08yIGVtaXNzaW9ucyBhY3Jvc3MgdGltZSAoVmVyc2lvbiB2MS4wLjApLgoKIyMjIwoKVG8gYWNjZXNzIHRoZSBHaXRIdWIgcmVwb3NpdG9yeSBmb3IgdGhpcyBjYXNlIHN0dWR5IHNlZSBoZXJlOiBodHRwczovL2dpdGh1Yi5jb20vL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtY28yLWVtaXNzaW9ucy4KVGhpcyBjYXNlIHN0dWR5IGlzIHBhcnQgb2YgYSBzZXJpZXMgb2YgcHVibGljIGhlYWx0aCBjYXNlIHN0dWRpZXMgZm9yIHRoZSBbQmxvb21iZXJnIEFtZXJpY2FuIEhlYWx0aCBJbml0aWF0aXZlXShodHRwczovL2FtZXJpY2FuaGVhbHRoLmpodS5lZHUvb3Blbi1jYXNlLXN0dWRpZXMpLgoKClBsZWFzZSBoZWxwIHVzIGJ5IGZpbGxpbmcgb3V0IG91ciBzdXJ2ZXkuCgoKPGRpdiBzdHlsZT0iZGlzcGxheTogZmxleDsganVzdGlmeS1jb250ZW50OiBjZW50ZXI7Ij48aWZyYW1lIHNyYz0iaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vZm9ybXMvZC9lLzFGQUlwUUxTZnBONEZOM0tFTHFCTkVnZjJBdHBpN1d5N05xeTJiZVNrRlFJTkw3WTVzQU1WNV93L3ZpZXdmb3JtP2VtYmVkZGVkPXRydWUiIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcwMCIgZnJhbWVib3JkZXI9IjAiIG1hcmdpbmhlaWdodD0iMCIgbWFyZ2lud2lkdGg9IjAiPkxvYWRpbmfigKY8L2lmcmFtZT48L2Rpdj4KCgoKIyAqKk1vdGl2YXRpb24qKgoqKiogCgpUaGlzIGNhc2Ugc3R1ZHkgZXhwbG9yZXMgaG93IGRpZmZlcmVudCBjb3VudHJpZXMgaGF2ZSBjb250cmlidXRlZCB0byBDYXJib24gRGlveGlkZSAoQ08yKSBlbWlzc2lvbnMgb3ZlciB0aW1lIGFuZCBob3cgQ08yIGVtaXNzaW9uIHJhdGVzIG1heSByZWxhdGUgdG8gaW5jcmVhc2luZyBnbG9iYWwgdGVtcGVyYXR1cmVzIGFuZCBpbmNyZWFzZWQgcmF0ZXMgb2YgbmF0dXJhbCBkaXNhc3RlcnMgYW5kIHN0b3Jtcy4KV2UgdXNlZCB0aGlzIFtyZXBvcnQgZnJvbSB0aGUgRVBBXShodHRwczovL3d3dy5lcGEuZ292L3JlcG9ydC1lbnZpcm9ubWVudC9ncmVlbmhvdXNlLWdhc2VzKXt0YXJnZXQ9Il9ibGFuayJ9IGFzIHRoZSBiYXNpcyBmb3IgbW90aXZhdGluZyB0aGlzIGNhc2Ugc3R1ZHksIGFzIGl0IHByb3ZpZGVzIGJhY2tncm91bmQgaW5mb3JtYXRpb24gYWJvdXQgaG93IENPMiBlbWlzc2lvbnMgYW5kIG90aGVyIGdyZWVuaG91c2UgZ2FzZXMgaGF2ZSBpbmZsdWVuY2VkIHRoZSBjbGltYXRlIGFuZCB3ZWF0aGVyIHBhdHRlcm5zLgoKQ08yIG1ha2VzIHVwIHRoZSBsYXJnZXN0IHByb3BvcnRpb24gb2YgZ3JlZW5ob3VzZSBnYXMgZW1pc3Npb25zIGluIHRoZSBVbml0ZWQgU3RhdGVzOgoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNTAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygid3d3L2ltZy9lbWlzc2lvbnMuanBnIikKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3LmVwYS5nb3YvZ2hnZW1pc3Npb25zL2ludmVudG9yeS11cy1ncmVlbmhvdXNlLWdhcy1lbWlzc2lvbnMtYW5kLXNpbmtzKXt0YXJnZXQ9Il9ibGFuayJ9CgpBIHZhcmlldHkgb2Ygc291cmNlcyBhbmQgc2VjdG9ycyBjb250cmlidXRlIHRvIGdyZWVuaG91c2UgZ2FzIGVtaXNzaW9uczoKCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjUwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInd3dy9pbWcvc2VjdG9yLnBuZyIpCmBgYAoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5lcGEuZ292L2doZ2VtaXNzaW9ucy9pbnZlbnRvcnktdXMtZ3JlZW5ob3VzZS1nYXMtZW1pc3Npb25zLWFuZC1zaW5rcyl7dGFyZ2V0PSJfYmxhbmsifQoKVHJhbnNwb3J0YXRpb24gYW5kIEVsZWN0cmljaXR5IGNvbnRyaWJ1dGUgdGhlIG1vc3QgbWV0cmljIHRvbnMgb2YgQ08yOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI1MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL3NvdXJjZXNfcGllLmpwZyIpCmBgYAoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5lcGEuZ292L2doZ2VtaXNzaW9ucy9pbnZlbnRvcnktdXMtZ3JlZW5ob3VzZS1nYXMtZW1pc3Npb25zLWFuZC1zaW5rcyl7dGFyZ2V0PSJfYmxhbmsifQoKClNvIHdoeSBzaG91bGQgd2UgcGF5IGF0dGVudGlvbiB0byBncmVlbmhvdXNlIGdhc2VzPwoKQWNjb3JkaW5nIHRvIHRoZSBbVVMgRW52aXJvbm1lbnRhbCBQcm90ZWN0aW9uIEFnZW5jeSAoRVBBKSBJbnZlbnRvcnkgb2YgVS5TLiBHcmVlbmhvdXNlIEdhcyBFbWlzc2lvbnMgYW5kIFNpbmtzIDIwMjAgUmVwb3J0XShodHRwczovL3d3dy5lcGEuZ292L3NpdGVzL3Byb2R1Y3Rpb24vZmlsZXMvMjAyMC0wNC9kb2N1bWVudHMvdXMtZ2hnLWludmVudG9yeS0yMDIwLW1haW4tdGV4dC5wZGYpe3RhcmdldD0iX2JsYW5rIn06IAoKPiBHcmVlbmhvdXNlIGdhc2VzIGFic29yYiBpbmZyYXJlZCByYWRpYXRpb24sIHRoZXJlYnkgdHJhcHBpbmcgaGVhdCBpbiB0aGUgYXRtb3NwaGVyZSBhbmQgbWFraW5nIHRoZSBwbGFuZXQgd2FybWVyLiBUaGUgbW9zdCBpbXBvcnRhbnQgZ3JlZW5ob3VzZSBnYXNlcyBkaXJlY3RseSBlbWl0dGVkIGJ5IGh1bWFucyBpbmNsdWRlIGNhcmJvbiBkaW94aWRlIChDTzIpLCBtZXRoYW5lIChDSDQpLCBuaXRyb3VzIG94aWRlIChOMk8pLCBhbmQgc2V2ZXJhbCBmbHVvcmluZS1jb250YWluaW5nIGhhbG9nZW5hdGVkIHN1YnN0YW5jZXMuIEFsdGhvdWdoIENPMiwgQ0g0LCBhbmQgTjJPIG9jY3VyIG5hdHVyYWxseSBpbiB0aGUgYXRtb3NwaGVyZSwgaHVtYW4gYWN0aXZpdGllcyBoYXZlIGNoYW5nZWQgdGhlaXIgYXRtb3NwaGVyaWMgY29uY2VudHJhdGlvbnMuIEZyb20gdGhlIHByZS0gaW5kdXN0cmlhbCBlcmEgKGkuZS4sIGVuZGluZyBhYm91dCAxNzUwKSB0byAyMDE4LCBjb25jZW50cmF0aW9ucyBvZiB0aGVzZSBncmVlbmhvdXNlIGdhc2VzIGhhdmUgaW5jcmVhc2VkIGdsb2JhbGx5IGJ5IDQ2LCAxNjUsIGFuZCAyMyBwZXJjZW50LCByZXNwZWN0aXZlbHkgKElQQ0MgMjAxMzsgTk9BQS9FU1JMIDIwMTlhLCAyMDE5YiwgMjAxOWMpLiAKClwqIElQQ0Mgc3RhbmRzIGZvciB0aGUgSW50ZXJnb3Zlcm5tZW50YWwgUGFuZWwgb24gQ2xpbWF0ZSBDaGFuZ2UKCkluIGZhY3QsIHRoZXJlIGFyZSBtYW55IHNpZ25zIHRoYXQgb3VyIHBsYW5ldCBpcyBleHBlcmllbmNpbmcgd2FybWVyIHRlbXBlcmF0dXJlczoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNTAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygid3d3L2ltZy93YXJtaW5nLnBuZyIpCmBgYAoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL2RhdGEuZ2xvYmFsY2hhbmdlLmdvdi9yZXBvcnQvbmNhMy1vdmVydmlldyl7dGFyZ2V0PSJfYmxhbmsifQoKVGhlIGNvbm5lY3Rpb24gYmV0d2VlbiBncmVlbmhvdXNlIGdhcyBsZXZlbHMgYW5kIGdsb2JhbCB0ZW1wZXJhdHVyZXMgYW5kIHRoZSBpbmZsdWVuY2Ugb2YgaW5jcmVhc2VkIGdsb2JhbCB0ZW1wZXJhdHVyZXMgb24gaHVtYW4gaGVhbHRoIGFyZSBtb3RpdmF0ZWQgYnkgdGhlc2UgcmVwb3J0czoKCiMjIyMgey5yZWZlcmVuY2VfYmxvY2t9CgotIE1lbGlsbG8sIEouTS4sIFQuQy4gUmljaG1vbmQsIGFuZCBHLlcuIFlvaGUgKGVkcy4pLiAyMDE0LiBDbGltYXRlIGNoYW5nZSBpbXBhY3RzIGluIHRoZSBVbml0ZWQgU3RhdGVzOiBUaGUgdGhpcmQgTmF0aW9uYWwgQ2xpbWF0ZSBBc3Nlc3NtZW50LiBVLlMuIEdsb2JhbCBDaGFuZ2UgUmVzZWFyY2ggUHJvZ3JhbS4gIAoKLSAyMDIwLiDigJxJbnZlbnRvcnkgb2YgVVMgR3JlZW5ob3VzZSBHYXMgRW1pc3Npb25zIGFuZCBTaW5rczogMTk5MC0tMjAxOC7igJ0gRVBBIDQzMC1SLTIwLTAwMiwgVGVjaC4gUmVwLiBodHRwczovL3d3dy5lcGEuZ292L2doZ2VtaXNzaW9ucy9pbnZlbnRvcnktdXMtZ3JlZW5ob3VzZS1nYXMtZW1pc3Npb25zLWFuZC1zaW5rcy4KCgojIyMjCgpUaGUgW05hdGlvbmFsIENsaW1hdGUgQXNzZXNzbWVudCBSZXBvcnRdKGh0dHBzOi8vZGF0YS5nbG9iYWxjaGFuZ2UuZ292L3JlcG9ydC9uY2EzLW92ZXJ2aWV3KXt0YXJnZXQ9Il9ibGFuayJ9IHN0YXRlcyB0aGF0OgoKPiBIZWF0LXRyYXBwaW5nIGdhc2VzIGFscmVhZHkgaW4gdGhlIGF0bW9zcGhlcmUgaGF2ZSBjb21taXR0ZWQgdXMgdG8gYSBob3R0ZXIgZnV0dXJlIHdpdGggbW9yZSBjbGltYXRlLXJlbGF0ZWQgaW1wYWN0cyBvdmVyIHRoZSBuZXh0IGZldyBkZWNhZGVzLiBUaGUgbWFnbml0dWRlIG9mIGNsaW1hdGUgY2hhbmdlIGJleW9uZCB0aGUgbmV4dCBmZXcgZGVjYWRlcyBkZXBlbmRzIHByaW1hcmlseSBvbiB0aGUgYW1vdW50IG9mIGhlYXQtdHJhcHBpbmcgZ2FzZXMgdGhhdCBodW1hbiBhY3Rpdml0aWVzIGVtaXQgZ2xvYmFsbHksIG5vdyBhbmQgaW4gdGhlIGZ1dHVyZS4KClNlZSB0aGUgZm9sbG93aW5nIGxpbmtzIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGhvdyBncmVlbmhvdXNlIGdhc2VzIGhhdmUgaW5mbHVlbmNlZCBnbG9iYWwgdGVtcGVyYXR1cmVzOgoxKSBUaGUgRVBBIFtyZXBvcnRdKGh0dHBzOi8vd3d3LmVwYS5nb3YvcmVwb3J0LWVudmlyb25tZW50L2dyZWVuaG91c2UtZ2FzZXMpe3RhcmdldD0iX2JsYW5rIn0gb24gZ3JlZW4gaG91c2UgZ2FzZXMgIAoyKSBUaGUgTmF0aW9uYWwgQ2xpbWF0ZSBBc3Nlc3NtZW50IChOQ0EpIFtzdW1tYXJ5IGZyb20gMjAxNF0oaHR0cHM6Ly9uY2EyMDE0Lmdsb2JhbGNoYW5nZS5nb3YvKXt0YXJnZXQ9Il9ibGFuayJ9KSAKMykgVGhlIFtXb3JsZDEwMSB3ZWJzaXRlXShodHRwczovL3dvcmxkMTAxLmNmci5vcmcvZ2xvYmFsLWVyYS1pc3N1ZXMvY2xpbWF0ZS1jaGFuZ2UvY2xpbWF0ZS1jaGFuZ2UtYWRhcHRhdGlvbnMpe3RhcmdldD0iX2JsYW5rIn0gYWJvdXQgaG93IGNvdW50cmllcyBhcmUgYWRhcHRpbmcgdG8gY2xpbWF0ZSBjaGFuZ2UKCiMgKipNYWluIFF1ZXN0aW9ucyoqCioqKiAKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb25zOiA8L3U+PC9iPgoKMS4gSG93IGhhdmUgZ2xvYmFsIENPMiBlbWlzc2lvbiByYXRlcyBjaGFuZ2VkIG92ZXIgdGltZT8gSW4gcGFydGljdWxhciBmb3IgdGhlIFVTLCBhbmQgaG93IGRvZXMgdGhlIFVTIGNvbXBhcmUgdG8gb3RoZXIgY291bnRyaWVzPyAKMi4gQXJlIENPMiBlbWlzc2lvbnMgaW4gdGhlIFVTLCBnbG9iYWwgdGVtcGVyYXR1cmVzLCBhbmQgbmF0dXJhbCBkaXNhc3RlciByYXRlcyBpbiB0aGUgVVMgYXNzb2NpYXRlZD8gCgojIyMjCgojICoqTGVhcm5pbmcgT2JqZWN0aXZlcyoqIAoqKiogCgpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgZXhwbG9yZSBDTzIgZW1pc3Npb24gZGF0YSBmcm9tIGFyb3VuZCB0aGUgd29ybGQuIApXZSB3aWxsIGFsc28gZm9jdXMgb24gdGhlIFVTIHNwZWNpZmljYWxseSB0byBldmFsdWF0ZSBwYXR0ZXJucyBvZiB0ZW1wZXJhdHVyZXMgYW5kIG5hdHVyYWwgZGlzYXN0ZXIgYWN0aXZpdHkuIAoKVGhpcyBjYXNlIHN0dWR5IHdpbGwgcGFydGljdWxhcmx5IGZvY3VzIG9uIGhvdyB0byB1c2UgZGlmZmVyZW50IGRhdGFzZXRzIHRoYXQgc3BhbiBkaWZmZXJlbnQgcmFuZ2VzIG9mIHRpbWUsIGFzIHdlbGwgYXMgaG93IHRvIGNyZWF0ZSB2aXN1YWxpemF0aW9ucyBvZiBwYXR0ZXJucyBvdmVyIHRpbWUuIApXZSB3aWxsIGVzcGVjaWFsbHkgZm9jdXMgb24gdXNpbmcgcGFja2FnZXMgYW5kIGZ1bmN0aW9ucyBmcm9tIHRoZSBbYHRpZHl2ZXJzZWBdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9LCBzdWNoIGFzIGBkcGx5cmAsIGB0aWR5cmAsIGFuZCBgZ2dwbG90MmAuIAoKVGhlIHRpZHl2ZXJzZSBpcyBhIGxpYnJhcnkgb2YgcGFja2FnZXMgY3JlYXRlZCBieSBSU3R1ZGlvLiAKV2hpbGUgc29tZSBzdHVkZW50cyBtYXkgYmUgZmFtaWxpYXIgd2l0aCBwcmV2aW91cyBSIHByb2dyYW1taW5nIHBhY2thZ2VzLCB0aGVzZSBwYWNrYWdlcyBtYWtlIGRhdGEgc2NpZW5jZSBpbiBSIGVzcGVjaWFsbHkgbGVnaWJsZSBhbmQgaW50dWl0aXZlLgoKVGhlIHNraWxscywgbWV0aG9kcywgYW5kIGNvbmNlcHRzIHRoYXQgc3R1ZGVudHMgd2lsbCBiZSBmYW1pbGlhciB3aXRoIGJ5IHRoZSBlbmQgb2YgdGhpcyBjYXNlIHN0dWR5IGFyZToKCjx1PioqRGF0YSBTY2llbmNlIExlYXJuaW5nIE9iamVjdGl2ZXM6Kio8L3U+ICAKCjEuIEltcG9ydGluZyBkYXRhIGZyb20gdmFyaW91cyB0eXBlcyBvZiBFeGNlbCBmaWxlcyBhbmQgQ1NWIGZpbGVzCjIuIEFwcGx5IGFjdGlvbiB2ZXJicyBpbiBgZHBseXJgIGZvciBkYXRhIHdyYW5nbGluZwozLiBIb3cgdG8gcGl2b3QgYmV0d2VlbiAibG9uZyIgYW5kICJ3aWRlIiBkYXRhc2V0cwo0LiBKb2luaW5nIHRvZ2V0aGVyIG11bHRpcGxlIGRhdGFzZXRzIHVzaW5nIGBkcGx5cmAKNS4gSG93IHRvIGNyZWF0ZSBlZmZlY3RpdmUgbG9uZ2l0dWRpbmFsIGRhdGEgdmlzdWFsaXphdGlvbnMgd2l0aCBgZ2dwbG90MmAKNi4gSG93IHRvIGFkZCB0ZXh0LCBjb2xvciwgYW5kIGxhYmVscyB0byBgZ2dwbG90MmAgcGxvdHMKNy4gSG93IHRvIGNyZWF0ZSBmYWNldGVkIGBnZ3Bsb3QyYCBwbG90cwoKPHU+KipTdGF0aXN0aWNhbCBMZWFybmluZyBPYmplY3RpdmVzOioqPC91PiAgCgoxLiBJbnRyb2R1Y3Rpb24gdG8gY29ycmVsYXRpb24gY29lZmZpY2llbnQgYXMgYSBzdW1tYXJ5IHN0YXRpc3RpYwoyLiBSZWxhdGlvbnNoaXAgYmV0d2VlbiBjb3JyZWxhdGlvbiBhbmQgbGluZWFyIHJlZ3Jlc3Npb24KMy4gQ29ycmVsYXRpb24gaXMgbm90IGNhdXNhdGlvbgoKYGBge3IsIG91dC53aWR0aCA9ICIyMCUiLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL3RpZHl2ZXJzZS50aWR5dmVyc2Uub3JnL2xvZ28ucG5nIikKYGBgCgoqKiogCgoKV2Ugd2lsbCBiZWdpbiBieSBsb2FkaW5nIHRoZSBwYWNrYWdlcyB0aGF0IHdlIHdpbGwgbmVlZDoKCmBgYHtyfQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZm9yY2F0cykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRpcmVjdGxhYmVscykKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KHBhdGNod29yaykKYGBgCgo8dT4qKlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OioqIDwvdT4KCgogUGFja2FnZSAgIHwgVXNlIGluIHRoaXMgY2FzZSBzdHVkeSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbYGhlcmVgXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpe3RhcmdldD0iX2JsYW5rIn0gICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhCltgcmVhZHhsYF0oaHR0cHM6Ly9yZWFkeGwudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gaW1wb3J0IHRoZSBFeGNlbCBmaWxlIGRhdGEKW2ByZWFkcmBdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gaW1wb3J0IHRoZSBjc3YgZmlsZSBkYXRhCltgZHBseXJgXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICB8ICB0byB2aWV3IGFuZCB3cmFuZ2xlIHRoZSBkYXRhLCBieSBtb2RpZnlpbmcgdmFyaWFibGVzLCByZW5hbWluZyB2YXJpYWJsZXMsIHNlbGVjdGluZyB2YXJpYWJsZXMsIGNyZWF0aW5nIHZhcmlhYmxlcywgYW5kIGFycmFuZ2luZyB2YWx1ZXMgd2l0aGluIGEgdmFyaWFibGUgICAKW2BtYWdyaXR0cmBdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdyaXR0ci92aWduZXR0ZXMvbWFncml0dHIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgfCAgdG8gdXNlIGFuZCByZWFzc2lnbiBkYXRhIG9iamVjdHMgdXNpbmcgdGhlIGAlPD4lYHBpcGUgb3BlcmF0b3IKW2BzdHJpbmdyYF0oaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICB8IHRvIHNlbGVjdCBvbmx5IHRoZSBmaXJzdCA0IGNoYXJhY3RlcnMgb2YgZGF0ZSBkYXRhCltgcHVycnJgXShodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICB8IHRvIGFwcGx5IGEgZnVuY3Rpb24gb24gYSBsaXN0IG9mIHRpYmJsZXMgKHRpYmJsZXMgYXJlIHRoZSB0aWR5dmVyc2UgdmVyc2lvbiBvZiBhIGRhdGEgZnJhbWUpICAKW2B0aWR5cmBdKGh0dHBzOi8vdGlkeXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gZHJvcCByb3dzIHdpdGggYE5BYCB2YWx1ZXMgZnJvbSBhIHRpYmJsZQpbYGZvcmNhdHNgXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gcmVvcmRlciB0aGUgbGV2ZWxzIG9mIGEgZmFjdG9yCltgZ2dwbG90MmBdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIG1ha2UgdmlzdWFsaXphdGlvbnMKW2BkaXJlY3RsYWJlbHNgXShodHRwOi8vZGlyZWN0bGFiZWxzLnItZm9yZ2Uuci1wcm9qZWN0Lm9yZy9kb2NzL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBhZGQgbGFiZWxzIHRvIHBsb3RzIGVhc2lseQpbYGdncmVwZWxgXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2dyZXBlbC92aWduZXR0ZXMvZ2dyZXBlbC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gYWRkIGxhYmVscyB0aGF0IGRvbid0IG92ZXJsYXAgdG8gcGxvdHMKW2Bicm9vbWBdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvYmxvZy8yMDE4LzA3L2Jyb29tLTAtNS0wLykgfCB0byBtYWtlIHRoZSBvdXRwdXQgZm9ybSBzdGF0aXN0aWNhbCB0ZXN0cyBlYXNpZXIgdG8gd29yayB3aXRoCltgcGF0Y2h3b3JrYF0oaHR0cHM6Ly9naXRodWIuY29tL3Rob21hc3A4NS9wYXRjaHdvcmspe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gY29tYmluZSBwbG90cwpUaGUgZmlyc3QgdGltZSB3ZSB1c2UgYSBmdW5jdGlvbiwgd2Ugd2lsbCB1c2UgdGhlIGA6OmAgdG8gaW5kaWNhdGUgd2hpY2ggcGFja2FnZSB3ZSBhcmUgdXNpbmcuIFVubGVzcyB3ZSBoYXZlIG92ZXJsYXBwaW5nIGZ1bmN0aW9uIG5hbWVzLCB0aGlzIGlzIG5vdCBuZWNlc3NhcnksIGJ1dCB3ZSB3aWxsIGluY2x1ZGUgaXQgaGVyZSB0byBiZSBpbmZvcm1hdGl2ZSBhYm91dCB3aGVyZSB0aGUgZnVuY3Rpb25zIHdlIHdpbGwgdXNlIGNvbWUgZnJvbS4KCgojICoqQ29udGV4dCoqCioqKiAKCk5vdyB3ZSB3aWxsIGRlc2NyaWJlIGEgYml0IG1vcmUgYmFja2dyb3VuZCBhYm91dCBncmVlbmhvdXNlIGdhcyBlbWlzc2lvbnMgYW5kIHRoZSBwb3RlbnRpYWwgaW5mbHVlbmNlIG9mIHRoZXNlIGVtaXNzaW9ucyBvbiBwdWJsaWMgaGVhbHRoLiAKCkdyZWVuaG91c2UgZ2FzIGVtaXNzaW9ucyBhcmUgZHVlIHRvIGJvdGggbmF0dXJhbCBwcm9jZXNzZXMgYW5kIGFudGhyb3BvZ2VuaWMgKGh1bWFuLWRlcml2ZWQpIGFjdGl2aXRpZXMuIAoKVGhlc2UgZW1pc3Npb25zIGFyZSBvbmUgb2YgdGhlIGNvbnRyaWJ1dGluZyBmYWN0b3JzIHRvIHJpc2luZyBnbG9iYWwgdGVtcGVyYXR1cmVzLCB3aGljaCBjYW4gaGF2ZSBhIGdyZWF0IGluZmx1ZW5jZSBvbiBbcHVibGljIGhlYWx0aF0oaHR0cHM6Ly93d3cuZXBhLmdvdi9jbGltYXRlLWluZGljYXRvcnMvdW5kZXJzdGFuZGluZy1jb25uZWN0aW9ucy1iZXR3ZWVuLWNsaW1hdGUtY2hhbmdlLWFuZC1odW1hbi1oZWFsdGgpe3RhcmdldD0iX2JsYW5rIn0gIGFzIGlsbHVzdHJhdGVkIGluIHRoZSBmb2xsb3dpbmcgaW1hZ2U6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgid3d3IiwgImltZyIsICJjbGltYXRlX2NoYW5nZV9oZWFsdGhfaW1wYWN0cy5qcGciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3LmNkYy5nb3YvY2xpbWF0ZWFuZGhlYWx0aC9lZmZlY3RzL2RlZmF1bHQuaHRtKXt0YXJnZXQ9Il9ibGFuayJ9CgoKQWNjb3JkaW5nIHRvIHRoZSBbVVMgRW52aXJvbm1lbnRhbCBQcm90ZWN0aW9uIEFnZW5jeSAoRVBBKSBJbnZlbnRvcnkgb2YgVS5TLiBHcmVlbmhvdXNlIEdhcyBFbWlzc2lvbnMgYW5kIFNpbmtzIDIwMjAgUmVwb3J0XShodHRwczovL3d3dy5lcGEuZ292L3NpdGVzL3Byb2R1Y3Rpb24vZmlsZXMvMjAyMC0wNC9kb2N1bWVudHMvdXMtZ2hnLWludmVudG9yeS0yMDIwLW1haW4tdGV4dC5wZGYpe3RhcmdldD0iX2JsYW5rIn06Cgo+IEdhc2VzIGluIHRoZSBhdG1vc3BoZXJlIGNhbiBjb250cmlidXRlIHRvIGNsaW1hdGUgY2hhbmdlIGJvdGggZGlyZWN0bHkgYW5kIGluZGlyZWN0bHkuIERpcmVjdCBlZmZlY3RzIG9jY3VyIHdoZW4gdGhlIGdhcyBpdHNlbGYgYWJzb3JicyByYWRpYXRpb24uIEluZGlyZWN0IHJhZGlhdGl2ZSBmb3JjaW5nIG9jY3VycyB3aGVuIGNoZW1pY2FsIHRyYW5zZm9ybWF0aW9ucyBvZiB0aGUgc3Vic3RhbmNlIHByb2R1Y2Ugb3RoZXIgZ3JlZW5ob3VzZSBnYXNlcywgd2hlbiBhIGdhcyBpbmZsdWVuY2VzIHRoZSBhdG1vc3BoZXJpYyBsaWZldGltZXMgb2Ygb3RoZXIgZ2FzZXMsIGFuZC9vciB3aGVuIGEgZ2FzIGFmZmVjdHMgYXRtb3NwaGVyaWMgcHJvY2Vzc2VzIHRoYXQgYWx0ZXIgdGhlIHJhZGlhdGl2ZSBiYWxhbmNlIG9mIHRoZSBlYXJ0aCAoZS5nLiwgYWZmZWN0IGNsb3VkIGZvcm1hdGlvbiBvciBbYWxiZWRvXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BbGJlZG8pe3RhcmdldD0iX2JsYW5rIn0pLiAKClRoZSAqKkdsb2JhbCBXYXJtaW5nIFBvdGVudGlhbCAoR1dQKSoqIGNvbXBhcmVzIHRoZSAqKmFiaWxpdHkgb2YgYSBncmVlbmhvdXNlIGdhcyB0byB0cmFwIGhlYXQgaW4gdGhlIGF0bW9zcGhlcmUgcmVsYXRpdmUgdG8gYW5vdGhlciBnYXMqKi4KCj5UaGUgR1dQIG9mIGEgZ3JlZW5ob3VzZSBnYXMgaXMgZGVmaW5lZCBhcyB0aGUgcmF0aW8gb2YgdGhlIGFjY3VtdWxhdGVkIHJhZGlhdGl2ZSBmb3JjaW5nIHdpdGhpbiBhIHNwZWNpZmljIHRpbWUgaG9yaXpvbiBjYXVzZWQgYnkgZW1pdHRpbmcgMSBraWxvZ3JhbSBvZiB0aGUgZ2FzLCByZWxhdGl2ZSB0byB0aGF0IG9mIHRoZSByZWZlcmVuY2UgZ2FzIENPMiAoSVBDQyAyMDEzKS4gVGhlcmVmb3JlIEdXUC13ZWlnaHRlZCBlbWlzc2lvbnMgYXJlIHByb3ZpZGVkIGluIG1pbGxpb24gbWV0cmljIHRvbnMgb2YgQ08yIGVxdWl2YWxlbnQgKE1NVCBDTzIgRXEuKQoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5lcGEuZ292L3NpdGVzL3Byb2R1Y3Rpb24vZmlsZXMvMjAyMC0wNC9kb2N1bWVudHMvdXMtZ2hnLWludmVudG9yeS0yMDIwLW1haW4tdGV4dC5wZGYpe3RhcmdldD0iX2JsYW5rIn0KCkNPMiBpcyBhY3R1YWxseSB0aGUgbGVhc3QgaGVhdC10cmFwcGluZyBnYXMgb2YgdGhlIGdyZWVuaG91c2UgZ2FzZXM6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInd3dy9pbWcvR1dQLnBuZyIpCmBgYAoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5lcGEuZ292L3NpdGVzL3Byb2R1Y3Rpb24vZmlsZXMvMjAyMC0wNC9kb2N1bWVudHMvdXMtZ2hnLWludmVudG9yeS0yMDIwLW1haW4tdGV4dC5wZGYpe3RhcmdldD0iX2JsYW5rIn0KCkhvd2V2ZXIsIGJlY2F1c2UgQ08yIGlzIHNvIG11Y2ggbW9yZSBhYnVuZGFudCBhbmQgc3RheXMgaW4gdGhlIGF0bW9zcGhlcmUgc28gbXVjaCBsb25nZXIgdGhhbiBvdGhlciBncmVlbmhvdXNlIGdhc2VzLCBpdCBoYXMgYmVlbiB0aGUgbGFyZ2VzdCBjb250cmlidXRvciB0byBnbG9iYWwgd2FybWluZy4KU2VlIFtoZXJlXShodHRwczovL3d3dy51Y3N1c2Eub3JnL3Jlc291cmNlcy93aHktZG9lcy1jbzItZ2V0LW1vcmUtYXR0ZW50aW9uLW90aGVyLWdhc2VzIzp+OnRleHQ9Q08yJTIwc3RpY2tzJTIwYXJvdW5kLG94aWRlJTIwKE4yTykpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgZGV0YWlscy4KCkl0IGlzIGFsc28gaW1wb3J0YW50IHRvIGtlZXAgaW4gbWluZCB0aGF0IHRoZXJlIGlzIGEgW2xhZ10oaHR0cHM6Ly9lYXJ0aG9ic2VydmF0b3J5Lm5hc2EuZ292L2Jsb2dzL2NsaW1hdGVxYS93b3VsZC1ndy1zdG9wLXdpdGgtZ3JlZW5ob3VzZS1nYXNlcy8pIGJldHdlZW4gZ3JlZW5ob3VzZSBnYXMgZW1pc3Npb25zIGFuZCB0ZW1wZXJhdHVyZSBjaGFuZ2VzIHRoYXQgd2UgZXhwZXJpZW5jZSBiZWNhdXNlIG11Y2ggb2YgRWFydGgncyB0aGVybWFsIGVuZXJneSAoYW5kIENPMikgZ2V0cyBzdG9yZWQgaW4gdGhlIG9jZWFuLiAKCkR1ZSB0byBhIHByb2Nlc3MgY2FsbGVkIFt0aGVybWFsIGluZXJ0aWFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1ZvbHVtZXRyaWNfaGVhdF9jYXBhY2l0eSNUaGVybWFsX2luZXJ0aWEpLCB0aGUgaGVhdCBzdG9yZWQgaW4gdGhlIG9jZWFuIHdpbGwgZXZlbnR1YWxseSBiZSB0cmFuc2ZlcmVkIHRvIHRoZSBzdXJmYWNlIG9mIHRoZSBFYXJ0aCBsb25nIGFmdGVyIHRoZSBnYXNlcyB3ZXJlIGVtaXR0ZWQgdGhhdCByZXN1bHRlZCBpbiB0aGUgaW5jcmVhc2VkIG9jZWFuIHRlbXBlcmF0dXJlLgoKU2VlIFtoZXJlXShodHRwczovL2VhcnRob2JzZXJ2YXRvcnkubmFzYS5nb3YvYmxvZ3MvY2xpbWF0ZXFhL3dvdWxkLWd3LXN0b3Atd2l0aC1ncmVlbmhvdXNlLWdhc2VzLykgZm9yIG1vcmUgZXhwbGFuYXRpb24uCgpGdXJ0aGVybW9yZSwgcmlzaW5nIENPMiBsZXZlbHMgaW4gdGhlIG9jZWFuIGFsc28gaW5mbHVlbmNlIG9jZWFuIGFjaWRpdHk6CgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI1MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL29jZWFucy5wbmciKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly9kYXRhLmdsb2JhbGNoYW5nZS5nb3YvcmVwb3J0L25jYTMtb3ZlcnZpZXcpe3RhcmdldD0iX2JsYW5rIn0KCgpBcyBDTzIgbGV2ZWxzIHJpc2UgaW4gdGhlIG9jZWFuLCB0aGUgcEggYmVjb21lcyBtb3JlIGFjaWRpYywgd2hpY2ggbWFrZXMgaXQgZGlmZmljdWx0IGZvciBvcmdhbmlzbXMgdG8gbWFpbnRhaW4gdGhlaXIgc2hlbGxzIG9yIHNrZWxldG9ucyB0aGF0IGFyZSBtYWRlIG9mIGNhbGNpdW0gY2FyYm9uYXRlLCB0aHVzIG1ha2luZyBpdCBtb3JlIGRpZmZpY3VsdCBmb3IgdGhlc2Ugb3JnYW5pc21zIHRvIHN1cnZpdmUgYW5kIGltcGFjdGluZyB0aGVpciByb2xlIGluIHRoZSBlY29zeXN0ZW0gYW5kIGZvb2QgY2hhaW4uIAoKCkZ1cnRoZXJtb3JlLCBncmVlbmhvdXNlIGdhcyBlbWlzc2lvbnMgYXJlIGJlbGlldmVkIHRvIGluZmx1ZW5jZSB3ZWF0aGVyIHBhdHRlcm5zIGFzIHNob3duIGluIHRoaXMgW3JlcG9ydF0oaHR0cHM6Ly9kYXRhLmdsb2JhbGNoYW5nZS5nb3YvcmVwb3J0L25jYTMtb3ZlcnZpZXcpe3RhcmdldD0iX2JsYW5rIn0uIAoKSW5kZWVkLCBldmVudHMgd2l0aCBoaWdoIGxldmVscyBvZiBwcmVjaXBpdGF0aW9uIHdoaWNoIGNhbiBpbmR1Y2UgZmxvb2RpbmcgYW5kIHByb3BlcnR5IGRhbWFnZSBhcmUgZ2VuZXJhbGx5IGluY3JlYXNpbmcgYXJvdW5kIHRoZSBjb3VudHJ5OgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI1MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL3N0b3Jtcy5wbmciKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly9kYXRhLmdsb2JhbGNoYW5nZS5nb3YvcmVwb3J0L25jYTMtb3ZlcnZpZXcpe3RhcmdldD0iX2JsYW5rIn0KCgojICoqTGltaXRhdGlvbnMqKgoqKiogCgpBbiBpbXBvcnRhbnQgbGltaXRhdGlvbiByZWdhcmRpbmcgdGhpcyBkYXRhIGFuYWx5c2lzIHRvIGtlZXAgaW4gbWluZCBpcyB0aGUgZGF0YXNldHMgb25seSBpbmNsdWRlIGNvdW50cmllcyBhbmQgeWVhcnMgaW4gd2hpY2ggY291bnRyaWVzIHdlcmUgcmVwb3J0aW5nIHN1Y2ggaW5mb3JtYXRpb24gdG8gdGhlIGFnZW5jaWVzIHRoYXQgY29sbGVjdGVkIHRoZSBkYXRhLiAKVGh1cywgdGhlIGRhdGEgYXJlIGluY29tcGxldGUuIApGb3IgZXhhbXBsZSwgd2hpbGUgd2UgaGF2ZSBhIGZhaXJseSBnb29kIHNlbnNlIG9mIENPMiBlbWlzc2lvbnMgZ2xvYmFsbHkgZm9yIGxhdGVyIHllYXJzLCBhZGRpdGlvbmFsIGVtaXNzaW9ucyB3ZXJlIGFsc28gcHJvZHVjZWQgYnkgY291bnRyaWVzIHRoYXQgYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGUgZGF0YS4KCgojICoqV2hhdCBhcmUgdGhlIGRhdGE/KioKKioqIAoKSW4gdGhpcyBjYXNlIHN0dWR5IHdlIHdpbGwgYmUgdXNpbmcgZGF0YSByZWxhdGVkIHRvIENPMiBlbWlzc2lvbnMsIGFzIHdlbGwgYXMgb3RoZXIgZGF0YSB0aGF0IG1heSBpbmZsdWVuY2UsIGJlIGluZmx1ZW5jZWQgb3IgcmVsYXRlIHRvIENPMiBlbWlzc2lvbnMuIApNb3N0IG9mIG91ciBkYXRhIGlzIGZyb20gW0dhcG1pbmRlcl0oaHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZy9kYXRhLyl7dGFyZ2V0PSJfYmxhbmsifSB0aGF0IHdhcyBvcmlnaW5hbGx5IG9idGFpbmVkIGZyb20gdGhlIFtXb3JsZCBCYW5rXShodHRwczovL3d3dy53b3JsZGJhbmsub3JnL2VuL3doYXQtd2UtZG8pe3RhcmdldD0iX2JsYW5rIn0uCgpJbiBhZGRpdGlvbiwgd2Ugd2lsbCB1c2Ugc29tZSBkYXRhIHRoYXQgaXMgc3BlY2lmaWMgdG8gdGhlIFVuaXRlZCBTdGF0ZXMgZnJvbSB0aGUgW05hdGlvbmFsIE9jZWFuaWMgYW5kIEF0bW9zcGhlcmljIEFkbWluaXN0cmF0aW9uIChOT0FBKV0oaHR0cHM6Ly93d3cubm9hYS5nb3YvKXt0YXJnZXQ9Il9ibGFuayJ9LCB3aGljaCBpcyBhbiBhZ2VuY3kgdGhhdCBjb2xsZWN0cyB3ZWF0aGVyIGFuZCBjbGltYXRlIGRhdGEuCgoKCkRhdGEgICB8IFRpbWUgc3BhbiB8IFNvdXJjZSAgfCBPcmlnaW5hbCBTb3VyY2UgICB8IERlc2NyaXB0aW9uIHwgQ2l0YXRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0KKipDTzIgZW1pc3Npb25zKiogIHwxNzUxLTIwMTQgfCBbR2FwbWluZGVyXShodHRwczovL3d3dy5nYXBtaW5kZXIub3JnL2RhdGEvKXt0YXJnZXQ9Il9ibGFuayJ9ICB8IFtDYXJib24gRGlveGlkZSBJbmZvcm1hdGlvbiBBbmFseXNpcyBDZW50ZXIgKENESUFDKV0oaHR0cHM6Ly9jZGlhYy5lc3MtZGl2ZS5sYmwuZ292Lyl7dGFyZ2V0PSJfYmxhbmsifSAgfCAgQ08yIGVtaXNzaW9ucyBpbiB0b25uZXMgb3IgbWV0cmljIHRvbnMgKGVxdWl2YWxlbnQgdG8gYXBwcm94aW1hdGVseSAyLDIwNC42IHBvdW5kcykgcGVyIHBlcnNvbiBieSBjb3VudHJ5fCBOQQoqKkdEUCBwZXIgY2FwaXRhIChwZXJjZW50IHllYXJseSBncm93dGgpKiogfCAxODAxLTIwMTl8IFtHYXBtaW5kZXJdKGh0dHBzOi8vd3d3LmdhcG1pbmRlci5vcmcvZGF0YS8pe3RhcmdldD0iX2JsYW5rIn0gIHwgW1dvcmxkIEJhbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9OWS5HRFAuUENBUC5LRC5aRyl7dGFyZ2V0PSJfYmxhbmsifSAgfCAgW0dyb3d0aCBEb21lc3RpYyBQcm9kdWN0XShodHRwczovL3d3dy5pbnZlc3RvcGVkaWEuY29tL3Rlcm1zL2cvZ2RwLmFzcCM6fjp0ZXh0PUdyb3NzJTIwRG9tZXN0aWMlMjBQcm9kdWN0JTIwKEdEUCklMjBpcyUyMHRoZSUyMG1vbmV0YXJ5JTIwdmFsdWUlMjBvZiUyMGFsbCxleHBlbmRpdHVyZXMlMkMlMjBwcm9kdWN0aW9uJTJDJTIwb3IlMjBpbmNvbWVzLil7dGFyZ2V0PSJfYmxhbmsifSAgKHdoaWNoIGlzIGFuIG92ZXJhbGwgbWVhc3VyZSBvZiB0aGUgaGVhbHRoIG9mIG5hdGlvbidzIGVjb25vbXkpIHBlciBwZXJzb24gYnkgY291bnRyeXwgTkEKKipFbmVyZ3kgdXNlIHBlciBwZXJzb24qKiB8MTk2MC0yMDE1IHwgW0dhcG1pbmRlcl0oaHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZy9kYXRhLyl7dGFyZ2V0PSJfYmxhbmsifSAgfCBbV29ybGQgQmFua10oaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcvaW5kaWNhdG9yL0VHLlVTRS5QQ0FQLktHLk9FKXt0YXJnZXQ9Il9ibGFuayJ9ICB8ICBVc2Ugb2YgcHJpbWFyeSBlbmVyZ3kgYmVmb3JlIHRyYW5zZm9ybWF0aW9uIHRvIG90aGVyIGVuZC11c2UgZnVlbHMsIGJ5IGNvdW50cnkgfCBOQQoqKlVTIE5hdHVyYWwgRGlzYXN0ZXJzKiogfCAxOTgwLTIwMTkgfCBbVGhlIE5hdGlvbmFsIE9jZWFuaWMgYW5kIEF0bW9zcGhlcmljIEFkbWluaXN0cmF0aW9uIChOT0FBKV0oaHR0cHM6Ly93d3cubmNkYy5ub2FhLmdvdi9iaWxsaW9ucy90aW1lLXNlcmllcyl7dGFyZ2V0PSJfYmxhbmsifXwgW1RoZSBOYXRpb25hbCBPY2VhbmljIGFuZCBBdG1vc3BoZXJpYyBBZG1pbmlzdHJhdGlvbiAoTk9BQSkgXShodHRwczovL3d3dy5uY2RjLm5vYWEuZ292L2JpbGxpb25zL3RpbWUtc2VyaWVzKXt0YXJnZXQ9Il9ibGFuayJ9fCAgVVMgZGF0YSBhYm91dDogPGJyPiAtLSBEcm91Z2h0cyA8YnI+IC0tIEZsb29kcyA8YnI+IC0tIEZyZWV6ZXMgPGJyPiAtLSBTZXZlcmUgU3Rvcm1zIDxicj4gLS0gVHJvcGljYWwgQ3ljbG9uZXMgPGJyPiAtLSBXaWxkZmlyZXM8YnI+IC0tIFdpbnRlciBTdG9ybXMgfCBOT0FBIE5hdGlvbmFsIENlbnRlcnMgZm9yIEVudmlyb25tZW50YWwgSW5mb3JtYXRpb24gKE5DRUkpIFUuUy4gQmlsbGlvbi1Eb2xsYXIgV2VhdGhlciBhbmQgQ2xpbWF0ZSBEaXNhc3RlcnMgKDIwMjApLiBodHRwczovL3d3dy5uY2RjLm5vYWEuZ292L2JpbGxpb25zLywgRE9JOiAxMC4yNTkyMS9zdGt3LTd3NzMKKipUZW1wZXJhdHVyZSoqICB8IDE4OTUtMjAxOXwgIFtUaGUgTmF0aW9uYWwgT2NlYW5pYyBhbmQgQXRtb3NwaGVyaWMgQWRtaW5pc3RyYXRpb24gKE5PQUEpXShodHRwczovL3d3dy5uY2RjLm5vYWEuZ292L2NhZy9uYXRpb25hbC90aW1lLXNlcmllcyl7dGFyZ2V0PSJfYmxhbmsifSAgfCBbVGhlIE5hdGlvbmFsIE9jZWFuaWMgYW5kIEF0bW9zcGhlcmljIEFkbWluaXN0cmF0aW9uIChOT0FBKV0oaHR0cHM6Ly93d3cubmNkYy5ub2FhLmdvdi9jYWcvbmF0aW9uYWwvdGltZS1zZXJpZXMpe3RhcmdldD0iX2JsYW5rIn0gfCBVUyBOYXRpb25hbCB5ZWFybHkgYXZlcmFnZSB0ZW1wZXJhdHVyZSAoaW4gRmFocmVuaGVpdCkgZnJvbSAxODk1IHRvIDIwMTkgfCBOT0FBIE5hdGlvbmFsIENlbnRlcnMgZm9yIEVudmlyb25tZW50YWwgaW5mb3JtYXRpb24sIENsaW1hdGUgYXQgYSBHbGFuY2U6IE5hdGlvbmFsIFRpbWUgU2VyaWVzLCBwdWJsaXNoZWQgSnVuZSAyMDIwLCByZXRyaWV2ZWQgb24gSnVuZSAyNiwgMjAyMCBmcm9tIGh0dHBzOi8vd3d3Lm5jZGMubm9hYS5nb3YvY2FnLwoKClRvIG9idGFpbiB0aGUgdGVtcGVyYXR1cmUgZGF0YSwgdGhlIGFubnVhbCBhdmVyYWdlIHRlbXBlcmF0dXJlcyB3ZXJlIHNlbGVjdGVkIGFzIHNob3duIGluIHRoaXMgaW1hZ2U6CmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygid3d3L2ltZy90ZW1wLnBuZyIpCmBgYAoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5uY2RjLm5vYWEuZ292L2NhZy9uYXRpb25hbC90aW1lLXNlcmllcyl7dGFyZ2V0PSJfYmxhbmsifQoKCkltcG9ydGFudGx5LCBub3RpY2UgdGhhdCB0aGUgZGF0YSB3ZSB3b3VsZCBsaWtlIHRvIHVzZSBzcGFuIGRpZmZlcmVudCB0aW1lIHBlcmlvZHM6CgpEYXRhICAgfCBUaW1lIHNwYW4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQoqKkNPMiBlbWlzc2lvbnMqKiAgfDE3NTEgdG8gMjAxNCAKKipHRFAgcGVyIGNhcGl0YSAoeWVhcmx5IGdyb3d0aCkqKiB8IDE4MDEgdG8gMjAxOQoqKkVuZXJneSB1c2UgcGVyIHBlcnNvbioqIHwxOTYwIHRvIDIwMTUgCioqVVMgTmF0dXJhbCBEaXNhc3RlcnMqKiB8IDE5ODAgdG8gMjAxOSAKKipUZW1wZXJhdHVyZSoqICB8IDE4OTUgdG8gMjAxOQoKV2Ugd2lsbCBleHBsb3JlIG1vcmUgYWJvdXQgdGhpcyBhIGJpdCBsYXRlci4gCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKV2hhdCBjb25jZXJucyBtaWdodCBhcmlzZSBhYm91dCByZWxpYWJpbGl0eSBhbmQgdmFyaWF0aW9uIG9mIG1lYXN1cmVtZW50IHByYWN0aWNlcyBvdmVyIHRpbWU/CgojIyMjCgojICoqRGF0YSBJbXBvcnQqKgoqKiogCkluIG91ciBjYXNlLCB3ZSBkb3dubG9hZGVkIHRoZSBkYXRhIGZvciB0aGUgZmlsZXMgZnJvbSB0aGUgdmFyaW91cyBzb3VyY2VzIGFzIGluZGljYXRlZCBpbiB0aGUgdGFibGUgYWJvdmUgYW5kIHB1dCB0aGVtIHdpdGhpbiBhICJyYXciIHN1YmRpcmVjdG9yeSBvZiBhICJkYXRhIiBkaXJlY3RvcnkgZm9yIG91ciBwcm9qZWN0LiBJZiB5b3UgdXNlIGFuIFJTdHVkaW8gcHJvamVjdCwgdGhlbiB5b3UgY2FuIHVzZSB0aGUgYGhlcmUoKWAgZnVuY3Rpb24gb2YgdGhlIGBoZXJlYCBwYWNrYWdlIHRvIG1ha2UgdGhlIHBhdGggZm9yIGltcG9ydGluZyB0aGlzIGRhdGEgc2ltcGxlci4gVGhlIGBoZXJlYCBwYWNrYWdlIGF1dG9tYXRpY2FsbHkgc3RhcnRzIGxvb2tpbmcgZm9yIGZpbGVzIGJhc2VkIG9uIHdoZXJlIHlvdSBoYXZlIGEgYC5ScHJvamAgZmlsZSB3aGljaCBpcyBjcmVhdGVkIHdoZW4geW91IHN0YXJ0IGEgbmV3IFJTdHVkaW8gcHJvamVjdC4gV2UgY2FuIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRvIGxvb2sgZm9yIHRoZSAieWVhcmx5X2NvMl9lbWlzc2lvbnNfMTAwMF90b25uZXMueGxzeCIgZmlsZSB3aXRoaW4gdGhlICJyYXciIGRpcmVjdG9yeSB3aXRoaW4gdGhlICJkYXRhIiBkaXJlY3Rvcnkgd2l0aGluIGEgZGlyZWN0b3J5IHdoZXJlIG91ciBgLlJwcm9qYCBmaWxlIGlzIGxvY2F0ZWQgYnkgc2VwYXJhdGluZyB0aGUgbmFtZXMgb2YgdGhlc2UgZGlyZWN0b3JpZXMgdXNpbmcgY29tbWFzIGFuZCBsaXN0aW5nICJkYXRhIiBmaXJzdC4gCgoqKioKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBtb3JlIGFib3V0IGNyZWF0aW5nIG5ldyBwcm9qZWN0cyBpbiBSU3R1ZGlvLiA8L3N1bW1hcnk+CgpZb3UgY2FuIGNyZWF0ZSBhIHByb2plY3QgYnkgZ29pbmcgdG8gdGhlIEZpbGUgbWVudSBvZiBSU3R1ZGlvIGxpa2Ugc286CgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygid3d3L2ltZy9OZXdfcHJvamVjdC5wbmciKQpgYGAKCllvdSBjYW4gYWxzbyBkbyBzbyBieSBjbGlja2luZyB0aGUgcHJvamVjdCBidXR0b246CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL3Byb2plY3RfYnV0dG9uLnBuZyIpCmBgYAoKU2VlIFtoZXJlXShodHRwczovL3N1cHBvcnQucnN0dWRpby5jb20vaGMvZW4tdXMvYXJ0aWNsZXMvMjAwNTI2MjA3LVVzaW5nLVByb2plY3RzKSB0byBsZWFybiBtb3JlIGFib3V0IHVzaW5nIFJTdHVkaW8gcHJvamVjdHMgYW5kIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdGhlIGBoZXJlYCBwYWNrYWdlLgoKPC9kZXRhaWxzPgoKKioqCgpUbyByZWFkIGluIHRoZSBmaWxlcyB0aGF0IHdlcmUgZG93bmxvYWRlZCBmcm9tIHRoZSB2YXJpb3VzIHNvdXJjZXMgYXMgaW5kaWNhdGVkIGluIHRoZSB0YWJsZSBhYm92ZSwgd2Ugd2lsbCB1c2UgdGhlIGByZWFkX3hsc3goKWAgYW5kIGByZWFkX3hscygpYCBmdW5jdGlvbnMgb2YgdGhlIGByZWFkeGxgIHBhY2thZ2UgdG8gaW1wb3J0IHRoZSBkYXRhIGZyb20gdGhlIGAueGxzeGAgYW5kIGAueGxzYCBmaWxlcywgcmVzcGVjdGl2ZWx5LiBXZSB3aWxsIGFsc28gdXNlIHRoZSBgaGVyZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGhlcmVgIHBhY2thZ2UgdG8gbW9yZSBlYXNpbHkgc3BlY2lmeSB0aGUgcGF0aCB0byBvdXIgZmlsZXMgcmVsYXRpdmUgdG8gdGhlIGRpcmVjdG9yeSB3aGVyZSB0aGUgLlJwcm9qIGZpbGUgaXMgbG9jYXRlZC4gCgpgYGB7ciwgZXZhbD1GQUxTRX0KQ08yX2VtaXNzaW9ucyA8LSByZWFkeGw6OnJlYWRfeGxzeChoZXJlKCJkYXRhIiwicmF3IiwgInllYXJseV9jbzJfZW1pc3Npb25zXzEwMDBfdG9ubmVzLnhsc3giKSkKZ2RwX2dyb3d0aCAgICA8LSByZWFkeGw6OnJlYWRfeGxzeChoZXJlKCJkYXRhIiwgInJhdyIsICJnZHBfcGVyX2NhcGl0YV95ZWFybHlfZ3Jvd3RoLnhsc3giKSkKZW5lcmd5X3VzZSAgICA8LSByZWFkeGw6OnJlYWRfeGxzeChoZXJlKCJkYXRhIiwgInJhdyIsICJlbmVyZ3lfdXNlX3Blcl9wZXJzb24ueGxzeCIpKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpDTzJfZW1pc3Npb25zIDwtIHJlYWR4bDo6cmVhZF94bHN4KCJ3d3cvZGF0YS9yYXcveWVhcmx5X2NvMl9lbWlzc2lvbnNfMTAwMF90b25uZXMueGxzeCIpCmdkcF9ncm93dGggICAgPC0gcmVhZHhsOjpyZWFkX3hsc3goInd3dy9kYXRhL3Jhdy9nZHBfcGVyX2NhcGl0YV95ZWFybHlfZ3Jvd3RoLnhsc3giKQplbmVyZ3lfdXNlICAgIDwtIHJlYWR4bDo6cmVhZF94bHN4KCJ3d3cvZGF0YS9yYXcvZW5lcmd5X3VzZV9wZXJfcGVyc29uLnhsc3giKQpgYGAKCklmIHlvdSBoYWQgdHJvdWJsZSBkb3dubG9hZGluZyB0aGVzZSBmaWxlcywgeW91IGNhbiBkbyBzbyBhdCBvdXIgW0dpdEh1YiByZXBvXShodHRwczovL2dpdGh1Yi5jb20vL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtY28yLWVtaXNzaW9ucy90cmVlL21hc3Rlci9kYXRhL3Jhdy8pIG9yIG1vcmUgZGlyZWN0bHkgYnkgY2xpY2tpbmcgW2hlcmVdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLWNvMi1lbWlzc2lvbnMvbWFzdGVyL2RhdGEvcmF3L3llYXJseV9jbzJfZW1pc3Npb25zXzEwMDBfdG9ubmVzLnhsc3gpLCBbaGVyZV0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtY28yLWVtaXNzaW9ucy9tYXN0ZXIvZGF0YS9yYXcvZ2RwX3Blcl9jYXBpdGFfeWVhcmx5X2dyb3d0aC54bHN4KSwgYW5kIFtoZXJlXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1jbzItZW1pc3Npb25zL21hc3Rlci9kYXRhL3Jhdy9lbmVyZ3lfdXNlX3Blcl9wZXJzb24ueGxzeCkuCgpXZSB3aWxsIHVzZSB0aGUgYHJlYWRfY3N2KClgIGZ1bmN0aW9uIG9mIHRoZSBgcmVhZHJgIHBhY2thZ2UgdG8gaW1wb3J0IHRoZSBkYXRhIGZyb20gdGhlIGAuY3N2YCBmaWxlcy4KCkhvd2V2ZXIsIGZvciB0aGVzZSBmaWxlcyB0aGVyZSBhcmUgc29tZSBsaW5lcyB0aGF0IHdlIHdvdWxkIGxpa2UgdG8gbm90IGltcG9ydCBiZWNhdXNlIHRoZSBudW1iZXIgb2YgY29sdW1ucyBkaWZmZXIgZm9yIHNvbWUgcm93cy4gSWYgd2UgZG9uJ3QgYWNjb3VudCBmb3IgdGhpcywgdGhlbiB3ZSBtYXkgZW5kIHVwIGltcG9ydGluZyBmZXdlciBjb2x1bW5zIG9mIHRoZSBkYXRhIHRoYXQgd2Ugd291bGQgbGlrZS4KCkluIHRoZSBmaXJzdCA1IHJvd3Mgc2hvd24gYmVsb3cgaW4gdGhlIGBkYXRhL2Rpc2FzdGVycy5jc3ZgIGZpbGUsIHlvdSBjYW4gc2VlIHRoYXQgdGhlIGZpcnN0IHR3byByb3dzIGRvZXMgbm90IGhhdmUgdGhlIHNhbWUgbnVtYmVyIG9mIGNvbHVtbnMgYXMgdGhlIHN1YnNlcXVlbnQgcm93cyBhbmQgYXJlIGp1c3QgKHN1Yil0aXRsZXMuIAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjYwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL0Rpc2FzdGVycy5wbmciKQpgYGAKClRvIGRvIHRoaXMsIHdlIGNhbiBza2lwIHJvd3MgdXNpbmcgdGhlIGBza2lwID0gMmAgYXJndW1lbnQgb2YgdGhlIGByZWFkX2NzdigpYCBmdW5jdGlvbi4gCgpgYGB7ciwgZXZhbD1GQUxTRX0KdXNfZGlzYXN0ZXIgPC0gcmVhZHI6OnJlYWRfY3N2KGhlcmUoImRhdGEiLCAicmF3IiwgImRpc2FzdGVycy5jc3YiKSwgc2tpcCA9IDIpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CnVzX2Rpc2FzdGVyIDwtIHJlYWRyOjpyZWFkX2Nzdigid3d3L2RhdGEvcmF3L2Rpc2FzdGVycy5jc3YiLCBza2lwID0gMikKYGBgCgpJZiB5b3UgaGFkIHRyb3VibGUgZG93bmxvYWRpbmcgdGhpcyBmaWxlLCB5b3UgY2FuIGRvIHNvIGF0IG91ciBbR2l0SHViIHJlcG9dKGh0dHBzOi8vZ2l0aHViLmNvbS8vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1jbzItZW1pc3Npb25zL3RyZWUvbWFzdGVyL2RhdGEvcmF3KSBvciBtb3JlIGRpcmVjdGx5IGJ5IGNsaWNraW5nIFtoZXJlXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1jbzItZW1pc3Npb25zL21hc3Rlci9kYXRhL3Jhdy9kaXNhc3RlcnMuY3N2KS4KCk5vdyBsb29raW5nIGF0IHRoZSBgZGF0YS90ZW1wZXJhdHVyZS5jc3ZgIGZpbGUsIHdlIHNlZSB0aGF0IHRoZSBmaXJzdCBmb3VyIGxpbmVzIGRvIG5vdCBoYXZlIHRoZSBzYW1lIG51bWJlciBvZiBjb2x1bW5zIGFzIHRoZSBzdWJzZXF1ZW50IGxpbmVzLiAKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI2MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygid3d3L2ltZy90ZW1wZGF0YS5wbmciKQpgYGAKCldlIHdpbGwgc2tpcCBpbXBvcnRpbmcgYWxsIDQgbGluZXMgYnkgdXNpbmcgYHNraXAgPSA0YC4gCldlIGNhbiBhbHNvIHJlcGxhY2UgYWxsIGluc3RhbmNlcyBvZiBgIi05OSJgIHdpdGggYE5BYCB1c2luZyB0aGUgYG5hID0gIi05OSJgIGFyZ3VtZW50IG9mIHRoZSBgcmVhZF9jc3YoKWAgZnVuY3Rpb24uClRoZSAiLTk5IiBuZWVkcyB0byBiZSBpbiBxdW90YXRpb24gbWFya3MgYmVjYXVzZSB0aGlzIGFyZ3VtZW50IGV4cGVjdHMgY2hhcmFjdGVycy4KCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgZm9yIGFuIGV4cGxhbmF0aW9uIGFib3V0IGRhdGEgdHlwZXMgaW4gUiBhbmQgYWJvdXQgY2hhcmFjdGVyIHN0cmluZ3MuPC9zdW1tYXJ5PgoKVGhlcmUgYXJlIHNldmVyYWwgW2NsYXNzZXMgb2YgZGF0YSBpbiBSIHByb2dyYW1taW5nXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9SXyhwcm9ncmFtbWluZ19sYW5ndWFnZSkpLCBtZWFuaW5nIHRoYXQgY2VydGFpbiBvYmplY3RzIHdpbGwgYmUgdHJlYXRlZCBvciBpbnRlcnByZXRlZCBkaWZmZXJlbnRseS4gQ2hhcmFjdGVyIGlzIG9uZSBvZiB0aGVzZSBjbGFzc2VzLiBBIGNoYXJhY3RlciBzdHJpbmcgaXMgYW4gaW5kaXZpZHVhbCBkYXRhIHZhbHVlIG1hZGUgdXAgb2YgY2hhcmFjdGVycy4gVGhpcyBjYW4gYmUgYSBwYXJhZ3JhcGgsIGxpa2UgdGhlIGxlZ2VuZCBmb3IgdGhlIHRhYmxlLCBvciBpdCBjYW4gYmUgYSBzaW5nbGUgbGV0dGVyIG9yIG51bWJlciBsaWtlIHRoZSBsZXR0ZXIgImEiIG9yIHRoZSBudW1iZXIgIjMiLiBJZiBkYXRhIGFyZSBvZiBjbGFzcyBjaGFyYWN0ZXIsIHRoYW4gdGhlIG51bWVyaWMgdmFsdWVzIHdpbGwgbm90IGJlIHByb2Nlc3NlZCBsaWtlIGEgbnVtZXJpYyB2YWx1ZSBpbiBhIG1hdGhlbWF0aWNhbCBzZW5zZS4gSWYgeW91IHdhbnQgeW91ciBudW1lcmljIHZhbHVlcyB0byBiZSBpbnRlcnByZXRlZCB0aGF0IHdheSwgdGhleSBuZWVkIHRvIGJlIGNvbnZlcnRlZCB0byBhIG51bWVyaWMgY2xhc3MuIFRoZSBvcHRpb25zIHR5cGljYWxseSB1c2VkIGFyZSBpbnRlZ2VyICh3aGljaCBoYXMgbm8gZGVjaW1hbCBwbGFjZSkgYW5kIGRvdWJsZSBwcmVjaXNpb24gKHdoaWNoIGhhcyBhIGRlY2ltYWwgcGxhY2UpLgoKQSB2YXJpYWJsZSB0aGF0IGlzIGEgZmFjdG9yIGhhcyBhIHNldCBvZiBwYXJ0aWN1bGFyIHZhbHVlcyBjYWxsZWQgbGV2ZWxzICh0aGlzIGNhbiBiZSBudW1iZXJzIG9yIGNoYXJhY3RlcnMpLiBFdmVuIGlmIHRoZXNlIGFyZSBudW1lcmljLCB0aGV5IHdpbGwgYmUgaW50ZXJwcmV0ZWQgYXMgbGV2ZWxzIChpLmUuLCBhcyBpZiB0aGV5IHdlcmUgY2hhcmFjdGVycykgbm90IGFzIG1hdGhlbWF0aWNhbCBudW1iZXJzLiBUaGUgdmFsdWVzIG9mIGEgZmFjdG9yIGFyZSBhc3N1bWVkIHRvIGhhdmUgYSBwYXJ0aWN1bGFyIG9yZGVyaW5nOyBieSBkZWZhdWx0IHRoZSBvcmRlciBpcyBhbHBoYWJldGljYWwsIGJ1dCB0aGlzIGlzIG5vdCBhbHdheXMgdGhlIGNvcnJlY3QvaW50dWl0aXZlIG9yZGVyaW5nLiBZb3UgY2FuIG1vZGlmeSB0aGUgb3JkZXIgb2YgdGhlc2UgbGV2ZWxzIHdpdGggdGhlIGBmb3JjYXRzYCBwYWNrYWdlLgoKPC9kZXRhaWxzPiAKKioqCgpgYGB7ciwgZXZhbD1GQUxTRX0KdXNfdGVtcGVyYXR1cmUgPC0gcmVhZHI6OnJlYWRfY3N2KGhlcmUoImRhdGEiLCAicmF3IiwgInRlbXBlcmF0dXJlLmNzdiIpLCBza2lwID0gNCwgbmEgPSAiLTk5IikKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0KdXNfdGVtcGVyYXR1cmUgPC0gcmVhZHI6OnJlYWRfY3N2KCJ3d3cvZGF0YS9yYXcvdGVtcGVyYXR1cmUuY3N2Iiwgc2tpcCA9IDQsIG5hID0gIi05OSIpCmBgYAoKSWYgeW91IGhhZCB0cm91YmxlIGRvd25sb2FkaW5nIHRoaXMgZmlsZSwgeW91IGNhbiBkbyBzbyBhdCBvdXIgW0dpdEh1YiByZXBvXShodHRwczovL2dpdGh1Yi5jb20vL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtY28yLWVtaXNzaW9ucy90cmVlL21hc3Rlci9kYXRhL3Jhdykgb3IgbW9yZSBkaXJlY3RseSBieSBjbGlja2luZyBbaGVyZV0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtY28yLWVtaXNzaW9ucy9tYXN0ZXIvZGF0YS9yYXcvdGVtcGVyYXR1cmUuY3N2KS4KCkdyZWF0ISBub3cgd2UgaGF2ZSBpbXBvcnRlZCBhbGwgb2YgdGhlIGRhdGEgdGhhdCB3ZSB3aWxsIG5lZWQuCgpUbyBhbGxvdyB1c2VycyB0byBza2lwIGltcG9ydCB3ZSB3aWxsIHNhdmUgdGhlIGRhdGEgYXMgYW4gUkRBIGZpbGU6CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzYXZlKENPMl9lbWlzc2lvbnMsIAogICAgIGdkcF9ncm93dGgsCiAgICAgZW5lcmd5X3VzZSwgCiAgICAgdXNfZGlzYXN0ZXIsIAogICAgIHVzX3RlbXBlcmF0dXJlLCAKICAgICBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJpbXBvcnRlZCIsICJjbzJfZGF0YV9pbXBvcnRlZC5yZGEiKSkKYGBgCgojICoqRGF0YSBXcmFuZ2xpbmcqKgoqKiogCklmIHlvdSBoYXZlIGJlZW4gZm9sbG93aW5nIGFsb25nIGJ1dCBzdG9wcGVkLCB3ZSBjb3VsZCBsb2FkIG91ciBpbXBvcnRlZCBkYXRhIGxpa2Ugc286CmBgYHtyLCBldmFsPUZBTFNFfQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAiY28yX2RhdGFfaW1wb3J0ZWQucmRhIikpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CmxvYWQoInd3dy9kYXRhL2ltcG9ydGVkL2NvMl9kYXRhX2ltcG9ydGVkLnJkYSIpCmBgYAoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT4gSWYgeW91IHNraXBwZWQgdGhlIGRhdGEgaW1wb3J0IHNlY3Rpb24gY2xpY2sgaGVyZS4gPC9zdW1tYXJ5PgoKQW4gUkRBIGZpbGUgKHN0YW5kcyBmb3IgUiBkYXRhKSBvZiB0aGUgZGF0YSBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS8vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1jbzItZW1pc3Npb25zL3RyZWUvbWFzdGVyL2RhdGEvaW1wb3J0ZWQpIG9yIHNsaWdodGx5IG1vcmUgZGlyZWN0bHkgW2hlcmVdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLWNvMi1lbWlzc2lvbnMvbWFzdGVyL2RhdGEvaW1wb3J0ZWQvY28yX2RhdGFfaW1wb3J0ZWQucmRhKS4gRG93bmxvYWQgdGhpcyBmaWxlIGFuZCB0aGVuIHBsYWNlIGl0IGluIHlvdXIgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSB3aXRoaW4gYSBzdWJkaXJlY3RvcnkgY2FsbGVkICJpbXBvcnRlZCIgd2l0aGluIGEgZGlyZWN0b3J5IGNhbGxlZCAiZGF0YSIgdG8gY29weSBhbmQgcGFzdGUgb3VyIGNvZGUuIFdlIHVzZWQgYW4gUlN0dWRpbyBwcm9qZWN0IGFuZCB0aGUgW2BoZXJlYCBwYWNrYWdlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpIHRvIG5hdmlnYXRlIHRvIHRoZSBmaWxlIG1vcmUgZWFzaWx5LgoKYGBge3IsIGV2YWw9RkFMU0V9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YSIsICJpbXBvcnRlZCIsICJjbzJfZGF0YV9pbXBvcnRlZC5yZGEiKSkKYGBgCgoqKioKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBtb3JlIGFib3V0IGNyZWF0aW5nIG5ldyBwcm9qZWN0cyBpbiBSU3R1ZGlvLiA8L3N1bW1hcnk+CgpZb3UgY2FuIGNyZWF0ZSBhIHByb2plY3QgYnkgZ29pbmcgdG8gdGhlIEZpbGUgbWVudSBvZiBSU3R1ZGlvIGxpa2Ugc286CgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygid3d3L2ltZy9OZXdfcHJvamVjdC5wbmciKQpgYGAKCllvdSBjYW4gYWxzbyBkbyBzbyBieSBjbGlja2luZyB0aGUgcHJvamVjdCBidXR0b246CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL3Byb2plY3RfYnV0dG9uLnBuZyIpCmBgYAoKU2VlIFtoZXJlXShodHRwczovL3N1cHBvcnQucnN0dWRpby5jb20vaGMvZW4tdXMvYXJ0aWNsZXMvMjAwNTI2MjA3LVVzaW5nLVByb2plY3RzKSB0byBsZWFybiBtb3JlIGFib3V0IHVzaW5nIFJTdHVkaW8gcHJvamVjdHMgYW5kIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdGhlIGBoZXJlYCBwYWNrYWdlLgoKPC9kZXRhaWxzPgoqKioKPC9kZXRhaWxzPgoqKioKCgpOZXh0LCB3ZSB0YWtlIGEgbG9vayBhdCBvdXIgZGF0YSB0aGF0IHdlIGp1c3QgaW1wb3J0ZWQuIApXZSB3aWxsIG5lZWQgdG8gZG8gc29tZSBkYXRhIHdyYW5nbGluZyB0byBhbGxvdyB1cyB0byBldmFsdWF0ZSBob3cgQ08yIGVtaXNzaW9ucyBoYXZlIGNoYW5nZWQgb3ZlciB0aW1lIGFuZCBob3cgZW1pc3Npb25zIG1heSByZWxhdGUgdG8gZW5lcmd5IHVzZSwgR0RQLCBldGMuCkxldCdzIGV4cGxvcmUgaG93IHRvIGRvIHRoYXQgd2l0aCB1c2VmdWwgZnVuY3Rpb25zIGFuZCBwYWNrYWdlcyBmcm9tIHRoZSBgdGlkeXZlcnNlYC4gCgojIyAqKlllYXJseSBDT34yfiBFbWlzc2lvbnMqKgoqKioKCkZpcnN0LCBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgQ08yIGRhdGEgKGBDTzJfZW1pc3Npb25zYCkuIApXZSBjYW4gdXNlIHRoZSBgc2xpY2VfaGVhZCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIHNlZSBqdXN0IHRoZSBmaXJzdCByb3dzIG9mIG91ciBkYXRhLiAKV2UgY2FuIHNwZWNpZnkgaG93IG1hbnkgcm93cyB3ZSB3b3VsZCBsaWtlIHRvIHNlZSBieSB1c2luZyB0aGUgYG4gPWAgYXJndW1lbnQuIAoKV2Ugd2lsbCB1c2UgdGhlIGAlPiVgIHBpcGUgZnJvbSB0aGUgYG1hZ3JpdHRyYCBwYWNrYWdlIChhbHRob3VnaCBpdCBpcyBhbHNvIGltcG9ydGVkIGJ5IG90aGVyIGB0aWR5dmVyc2VgIHBhY2thZ2VzLCBsaWtlIGBkcGx5cmApLCB3aGljaCBjYW4gYmUgdXNlZCB0byBkZWZpbmUgdGhlIGlucHV0IGZvciBsYXRlciBzZXF1ZW50aWFsIHN0ZXBzLiAKVGhpcyB3aWxsIG1ha2UgbW9yZSBzZW5zZSB3aGVuIHdlIGhhdmUgbXVsdGlwbGUgc2VxdWVudGlhbCBzdGVwcyB1c2luZyB0aGUgc2FtZSBkYXRhIG9iamVjdC4gCgpgYGB7cn0KQ08yX2VtaXNzaW9ucyAlPiUKICBzbGljZV9oZWFkKG4gPSAzKQpgYGAKCkFub3RoZXIgdXNlZnVsIGZ1bmN0aW9uIGlzIGBzbGljZV9zYW1wbGUoKWAgdG8gbG9vayBhdCBhICoqc2VsZWN0aW9uIG9mIHJhbmRvbSByb3dzKiogdXNpbmcgW3BzZXVkb3JhbmRvbV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUHNldWRvcmFuZG9tbmVzcyl7dGFyZ2V0PSJfYmxhbmsifSBudW1iZXJzIGZvciB0aGUgaW5kZXggb2Ygcm93cyB0byBzaG93LiBUbyBjb250aW51ZSB0byBnZXQgdGhlIHNhbWUgcmFuZG9tIHZhbHVlcyBvciBmb3Igb3RoZXJzIHRvIGdldCB0aGUgc2FtZSB2YWx1ZXMsIHdlIG5lZWQgdG8gc2V0IGEgc2VlZCBmaXJzdC4gV2UgY2FuIGRvIHRoaXMgd2l0aCB0aGUgYHNldC5zZWVkKClgIGJhc2UgZnVuY3Rpb24uIFdlIGp1c3Qgc3BlY2lmeSBhIG51bWJlciB3aXRoIHRoaXMgZnVuY3Rpb24gYW5kIHRoYXQgd2lsbCBhbGxvdyB1cyB0byBnZXQgdGhlIHNhbWUgc3Vic2V0IG9mIHZhbHVlcyBmcm9tIHRoZSBgc2xpY2Vfc2FtcGxlKClgIGZ1bmN0aW9uLiBJZiB0d28gZGlmZmVyZW50IHBlb3BsZSByYW4gdGhpcyBjb2RlICh3aXRob3V0IHNldC5zZWVkKCkpLCB0aGV5IHdvdWxkIGVhY2ggc2VlIGEgZGlmZmVyZW50IHN1YnNldCBvZiByb3dzLiBGb3IgZGF0YSBleHBsb3JhdGlvbiwgdGhpcyBpc24ndCBhIGh1Z2UgZGVhbCwgYnV0IGlmIHdlJ2QgbGlrZSBzZXBhcmF0ZSBhbmFseXN0cyBydW5uaW5nIHRoZSBzYW1lIGNvZGUgdG8gc2VlIHRoZSBzYW1lIG91dHB1dCwgd2Ugd2lsbCB1c2Ugc2V0LnNlZWQoKS4gSWYgd2UgY2hhbmdlZCBzZXQuc2VlZCgxMjMpIHRvIHNldC5zZWVkKDMzMyksIHdlIHdvdWxkIG9idGFpbiBhIGRpZmZlcmVudCByYW5kb20gc2FtcGxlIG9mIHJvd3MuIAoKYGBge3J9CnNldC5zZWVkKDEyMykKCkNPMl9lbWlzc2lvbnMgJT4lCiAgc2xpY2Vfc2FtcGxlKG4gPSAzKQpgYGAKCiMjIyMgey50aGlua19xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpUcnkgc2V0dGluZyBhIGRpZmZlcmVudCBzZWVkIHRvIHNlZSB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgb3V0cHV0LgoKIyMjIwoKYGBge3IgRFdfQ29kZTEtc2V0dXB9CmxpYnJhcnkodGlkeXZlcnNlKQpsb2FkKGhlcmUoInd3dyIsICJkYXRhIiwgImltcG9ydGVkIiwgImNvMl9kYXRhX2ltcG9ydGVkLnJkYSIpKQpgYGAKCmBgYHtyIERXX0NvZGUxLCBleGVyY2lzZT1UUlVFfQojc2V0LnNlZWQoKSAjZmlsbCBpbiB0aGUgc2V0LnNlZWQgZnVuY3Rpb24gd2l0aCBhIG51bWJlciBhbmQgdW5jb21tZW50IGl0IGJ5IHJlbW92aW5nIHRoZSBgI2AKYGBgCgpgYGB7ciBEV19Db2RlMS1zb2x1dGlvbn0Kc2V0LnNlZWQoMTAwKQpDTzJfZW1pc3Npb25zICU+JQogIHNsaWNlX3NhbXBsZShuID0gMykKYGBgCgpPSywgd2Ugc2VlIGVhY2ggY291bnRyeSBpcyByZXByZXNlbnRlZCBhbG9uZyBvbmUgcm93IGFuZCBlYWNoIGNvbHVtbiBjb250YWlucyB5ZWFybHkgQ08yIGVtaXNzaW9ucy4gCldlIGFsc28gc2VlIHRoYXQgdGhlcmUgYXJlIGEgbG90IG9mIGBOQWAgdmFsdWVzLgoKV2UgY2FuIGFsc28gdXNlIHRoZSBgZ2xpbXBzZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIHZpZXcgb3VyIGRhdGEuIApUaGlzIGFsbG93cyB1cyB0byBzZWUgYWxsIG9mIG91ciB2YXJpYWJsZXMgYXQgb25jZS4gCldlIHdpbGwgc2VlIGEgdGlueSBiaXQgb2YgZWFjaCB2YXJpYWJsZS9jb2x1bW4gd2l0aCB0aGUgZGF0YSBkaXNwbGF5ZWQgb24gdGhlIHJpZ2h0LgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpDTzJfZW1pc3Npb25zICU+JQogIGRwbHlyOjpnbGltcHNlKCkKYGBgCiMjIyMKCgpXZSBjYW4gYWxzbyBzZWUgdGhhdCB3ZSBoYXZlIGEgbGFyZ2UgW3RpYmJsZV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy8pLiAKYGBge3J9CkNPMl9lbWlzc2lvbnMgJT4lCiAgY2xhc3MoKQpgYGAKClRoaXMgaXMgdGhlIG9iamVjdCB0aGF0IGlzIGNyZWF0ZWQgd2hlbiB3ZSByZWFkIGluIHRoZSBkYXRhIHdpdGggYHJlYWRyYC4gCkEgdGliYmxlIChvciBgdGJsX2RmYCkgaXMgdGhlIGB0aWR5dmVyc2VgIHZlcnNpb24gb2YgYSBgZGF0YS5mcmFtZWAgb2JqZWN0LiAKU2ltaWxhciB0byBgZGF0YS5mcmFtZWAsIGl0IGlzIGEgdGFibGUgd2l0aCB2YXJpYWJsZSBpbmZvcm1hdGlvbiBhcnJhbmdlZCBhcyBjb2x1bW5zLCBhbmQgaW5kaXZpZHVhbCBvYnNlcnZhdGlvbnMgYXJyYW5nZWQgYXMgcm93cy4gCkhvd2V2ZXIgc29tZSBuaWNlIGRpZmZlcmVuY2VzIGFyZSB0aGV5IGRvIG5vdCBjaGFuZ2UgdmFyaWFibGUgbmFtZXMgb3IgZGF0YSB0eXBlcyBhbmQgdGhleSBnaXZlIG1vcmUgbWVzc2FnZXMgd2hlbiBzb21ldGhpbmcgaXMgd3JvbmcgKGUuZy4gd2hlbiBhIHZhcmlhYmxlIGRvZXMgbm90IGV4aXN0KSwgd2hpY2ggZm9yY2VzIHRoZSBhbmFseXN0IHRvIGNvbmZyb250IHByb2JsZW1zIGVhcmxpZXIuIApUaWJibGVzIGFsc28gZ2l2ZSB1cyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY2xhc3Mgb2YgZWFjaCB2YXJpYWJsZS4gCgpGb3IgZXhhbXBsZSB0aGUgYGNvdW50cnlgIHZhcmlhYmxlIGlzIG1hZGUgdXAgb2YgY2hhcmFjdGVyIChhYmJyZXZpYXRlZCBhcyBgY2hyYCkgdmFsdWVzLgpgYGB7cn0KQ08yX2VtaXNzaW9ucyAlPiUKICBzZWxlY3QoY291bnRyeSkKYGBgCgpXZSBzZWUgdGhhdCB3ZSBoYXZlIGByIG5yb3coQ08yX2VtaXNzaW9ucylgIHJvd3MgZGlmZmVyZW50IGNvdW50cnkgdmFyaWFibGVzIGFuZCBDTzIgZW1pc3Npb24gdmFsdWVzIGZvciBgciBuY29sKENPMl9lbWlzc2lvbnMpIC0gMWAgZGlmZmVyZW50IHllYXJzIChmcm9tIDE3NTEgdG8gMjAxNCkuIApgYGB7cn0KbmFtZXMoQ08yX2VtaXNzaW9ucykKYGBgCgpSZWNhbGwsIHRoZSB2YWx1ZXMgYXJlIGVtaXNzaW9ucyBpbiBtZXRyaWMgdG9ucywgYWxzbyBjYWxsZWQgdG9ubmVzLgpTY3JvbGxpbmcgdGhyb3VnaCB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gYWJvdmUsIHdlIGNhbiBhbHNvIHNlZSB0aGF0IHRoZXJlIGFyZSBmZXdlciBgTkFgIHZhbHVlcyBmb3IgbGF0ZXIgeWVhcnMuCgpJbiB0aGlzIG5leHQgY29kZSBjaHVuaywgd2Ugd2lsbCBpbnRyb2R1Y2UgdGhlIGAlPD4lYCBvcGVyYXRvciBmcm9tIHRoZSBgbWFncml0dHJgIHBhY2thZ2UuIApUaGlzIGFsbG93cyB1cyB0byB1c2Ugb3VyIGBDTzJfZW1pc3Npb25zYCBkYXRhIGFuZCByZWFzc2lnbiBpdCB0byBhIG1vZGlmaWVkIHZlcnNpb24gYXQgdGhlIHNhbWUgdGltZS4gCkxldCdzIG1vZGlmeSBgQ08yX2VtaXNzaW9uc2AgdG8gbWFrZSBpdCBtb3JlIHVzYWJsZSBmb3IgbWFraW5nIHZpc3VhbGl6YXRpb25zLiAKU3BlY2lmaWNhbGx5LCB3ZSB3aWxsIHVzZSB0aGUgYHBpdm90X2xvbmdlcigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGNvbnZlcnQgb3VyIGRhdGEgaW50byB3aGF0IGlzIGNhbGxlZCAqKiJsb25nIioqIGZvcm1hdC4gVGhpcyBpcyBhbHNvIHNvbWV0aW1lcyByZWZlcnJlZCB0byBhcyAqKiJuYXJyb3ciKiogZm9ybWF0LgoKVGhpcyBtZWFucyB0aGF0IHdlIHdpbGwgaGF2ZSBtb3JlIHJvd3MgYW5kIGZld2VyIGNvbHVtbnMgdGhhbiBvdXIgY3VycmVudCBmb3JtYXQuCgpSaWdodCBub3cgb3VyIGRhdGEgaXMgaW4gd2hhdCBpcyBjYWxsZWQgKioid2lkZSIqKiBmb3JtYXQuIApJbiB3aWRlIGZvcm1hdCwgZWFjaCB2YXJpYWJsZSBpcyBsaXN0ZWQgYXMgaXRzIG93biBjb2x1bW4uIApJbiBjb250cmFzdCwgaW4gbG9uZyBmb3JtYXQsIHZhcmlhYmxlcyBtYXliZSBjb2xsYXBzZWQgaW50byBhIGNvbHVtbiB0aGF0IGlkZW50aWZpZXMgdGhlIHZhcmlhYmxlcyBhbmQgYSBjb2x1bW4gb2YgdmFsdWVzLiAKU2VlIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XaWRlX2FuZF9uYXJyb3dfZGF0YSl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gZm9ybWF0cy4KCldlIHdhbnQgdG8gY29sbGFwc2UgYWxsIG9mIHRoZSB2YWx1ZXMgZm9yIHRoZSBlbWlzc2lvbiBkYXRhIGFjcm9zcyB0aGUgZGlmZmVyZW50IGluZGl2aWR1YWwgeWVhciB2YXJpYWJsZXMgaW50byBvbmUgbmV3IGBFbWlzc2lvbnNgIHZhcmlhYmxlLiBXZSB3aWxsIGlkZW50aWZ5IHdoYXQgeWVhciB0aGV5IGFyZSBmcm9tIGJ5IGNyZWF0aW5nIGEgbmV3IGBZZWFyYCB2YXJpYWJsZS4gVGhlIGBjb2xzID1gIGFyZ3VtZW50IGFsbG93cyB1cyB0byBzcGVjaWZ5IHdoaWNoIGNvbHVtbnMgd2Ugd2FudCB0byBwaXZvdCAob3Igbm90IHBpdm90KSB0byBjcmVhdGUgdGhlc2UgbmV3IGNvbHVtbnMuIFdlIHdhbnQgdG8ga2VlcCBvdXIgYGNvdW50cnlgIGRhdGEgYXMgYW4gSUQgdmFyaWFibGUgc28gd2Ugd2lsbCBleGNsdWRlIGl0IHVzaW5nIHRoZSBgLWAgc2lnbiwgYnkgZGVmYXVsdCBhbGwgb3RoZXIgY29sdW1ucyB3aWxsIGJlIHVzZWQuCgpgYGB7cn0KQ08yX2VtaXNzaW9ucyAgJTw+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLWNvdW50cnksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlllYXIiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiRW1pc3Npb25zIikKCnNldC5zZWVkKDEyMykKCkNPMl9lbWlzc2lvbnMgJT4lCiAgc2xpY2Vfc2FtcGxlKG4gPSA2KQpgYGAKCgojIyMjIHsucmVjYWxsX2NvZGVfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKVGhpbmsgYSBtb21lbnQgYWJvdXQgd2hhdCB0aGUgZGltZW5zaW9ucyBvZiB0aGUgIGBDTzJfZW1pc3Npb25zYCB0aWJibGUgYXJlIG5vdyBhbmQgd2h5PyBIb3cgd291bGQgeW91IGNoZWNrIHRoaXM/Cgo8Yj48dT4gSGludCA8L3U+PC9iPjogQ2hlY2tpbmcgaGFzIHNvbWV0aGluZyB0byBkbyB3aXRoIGEgdW5pcXVlIGFzcGVjdCBhYm91dCB0aWJibGVzLiAKCiMjIyMKCmBgYHtyIERXX0NvZGUyLXNldHVwfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtYWdyaXR0cikKbG9hZChoZXJlKCJ3d3ciLCAiZGF0YSIsICJpbXBvcnRlZCIsICJjbzJfZGF0YV9pbXBvcnRlZC5yZGEiKSkKCkNPMl9lbWlzc2lvbnMgICU8PiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jb3VudHJ5LAogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIkVtaXNzaW9ucyIpCmBgYAoKYGBge3IgRFdfQ29kZTIsIGV4ZXJjaXNlPVRSVUV9CiMgV3JpdGUgc29tZSBjb2RlIHRvIGNoZWNrIHRoaXMKYGBgCgpgYGB7ciBEV19Db2RlMi1oaW50fQpkaW0oQ08yX2VtaXNzaW9ucykKYGBgCgpMZXQncyBzYXkgd2UgYWxzbyB3YW50IHRvIHJlbmFtZSB0aGUgYGNvdW50cnlgIHZhcmlhYmxlIHRvIGJlIGNhcGl0YWxpemVkLgpUbyBkbyB0aGlzLCB3ZSBjYW4gdXNlIHRoZSBgcmVuYW1lKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gcmVuYW1lIHRoaXMgdmFyaWFibGUuIApXaGVuIHJlbmFtaW5nIHZhcmlhYmxlcyB0aGUgc3ludGF4IGlzIGBuZXctbmFtZSA9IG9sZC1uYW1lYCwgd2hlcmUgdGhlIG5ldyBuYW1lIGlzIGxpc3RlZCBmaXJzdCBiZWZvcmUgdGhlIGA9YC4gCiAKWW91IG1heSBhbHNvIG5vdGUgdGhhdCB0aGUgYFllYXJgIHZhcmlhYmxlIGlzIGN1cnJlbnRseSBvZiBjbGFzcyB0eXBlIGNoYXJhY3Rlci4gV2Ugd291bGQgbGlrZSB0byBjaGFuZ2UgaXQgdG8gYmUgbnVtZXJpYy4gVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYG11dGF0ZSgpYCBmdW5jdGlvbiwgd2hpY2ggaXMgYWxzbyBwYXJ0IG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFRoaXMgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIGNyZWF0ZSBhbmQgbW9kaWZ5IHZhcmlhYmxlcy4gV2Ugd2lsbCBhbHNvIHVzZSB0aGlzIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhIHZhcmlhYmxlIGNhbGxlZCBgTGFiZWxgIHdoaWNoIHdpbGwgaGF2ZSBgIkNPMiBFbWlzc2lvbnMgKE1ldHJpYyBUb25zKSJgIGFzIHRoZSB2YWx1ZSBmb3IgZXZlcnkgcm93LCB0byBiZSB1c2VkIHdoZW4gd2UgY3JlYXRlIHBsb3RzIGxhdGVyLgoKCmBgYHtyfQpDTzJfZW1pc3Npb25zICAlPD4lCiAgIGRwbHlyOjpyZW5hbWUoQ291bnRyeSA9IGNvdW50cnkpICU+JQogICBkcGx5cjo6bXV0YXRlKFllYXIgPSBhcy5udW1lcmljKFllYXIpLAogICAgICAgICAgICAgICAgIExhYmVsID0gIkNPMiBFbWlzc2lvbnMgKE1ldHJpYyBUb25zKSIpCmBgYAoKTm93IGxldCdzIHRha2UgYSBsb29rIHRvIHNlZSBob3cgb3VyIGRhdGEgaGFzIGNoYW5nZWQ6CgpgYGB7cn0Kc2V0LnNlZWQoMTIzKQoKQ08yX2VtaXNzaW9ucyAlPiUKICBzbGljZV9zYW1wbGUobiA9IDYpCmBgYApHcmVhdCwgd2UgY2FuIHNlZSB0aGF0IG5vdyB0aGUgYFllYXJgIHZhcmlhYmxlIGlzIG9mIGNsYXNzIGRvdWJsZSAoYWJicmV2aWF0ZWQgYGRibGApLCB3aGljaCBpcyBhIG51bWVyaWMgY2xhc3MuCgpOb3csIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBgQ291bnRyeWAgdmFyaWFibGUgdG8gY2hlY2sgaWYgdGhlcmUgaXMgYW55dGhpbmcgdW5leHBlY3RlZC4gCldlIHdpbGwgdXNlIHRoZSBgZGlzdGluY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byB2aWV3IHRoZSB1bmlxdWUgdmFsdWVzIG9ubHkuCkZpbmFsbHksIHdlIHVzZSB0aGUgYHB1bGwoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBleHRyYWN0IHRoZSB2YWx1ZXMgZnJvbSB0aGUgY29sdW1uICh0aGlzIGlzIHNpbWlsYXIgdG8gdXNpbmcgdGhlIGAkYCBiYXNlIFIgc3ludGF4IGUuZy4gYENPMl9lbWlzc2lvbiRDb3VudHJ5YCkuIAoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpDTzJfZW1pc3Npb25zICU+JQogIGRpc3RpbmN0KENvdW50cnkpICU+JQogIHB1bGwoKQpgYGAKIyMjIwoKVGhlc2UgYWxsIGxvb2sgYXMgZXhwZWN0ZWQhCgoKIyMgKipZZWFybHkgR3Jvd3RoIGluIEdEUCBwZXIgQ2FwaXRhKioKKioqCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBuZXh0IGRhdGFzZXQgKGBnZHBfZ3Jvd3RoYCkgdGhhdCB3ZSBpbXBvcnRlZC4gCgpgYGB7cn0KZ2RwX2dyb3d0aCAlPiUKICBzbGljZV9oZWFkKG4gPSAzKQpgYGAKCkhvdyBtYW55IHJvd3MgYW5kIGNvbHVtbnMgYXJlIHRoZXJlIGFyZSB0aGVyZT8gV2UgY2FuIGVhc2lseSBjaGVjayBieSB1c2luZyB0aGUgYmFzZSBgZGltKClgIGZ1bmN0aW9uLCB3aGljaCBldmFsdWF0ZXMgdGhlIGRpbWVuc2lvbnMgb2YgYW4gb2JqZWN0LgoKYGBge3J9CmRpbShnZHBfZ3Jvd3RoKQpgYGAKCkludGVyZXN0aW5nLCBpdCdzIGByIG5yb3coZ2RwX2dyb3d0aClgIHJvd3MgKGFzIG9wcG9zZWQgdG8gYHIgbnJvdyhDTzJfZW1pc3Npb25zKWAgYWJvdmUpLiAKV2Ugd2lsbCBkZWFsIHdpdGggdGhpcyBhbmQgb3RoZXIgZGlmZmVyZW5jZXMgaW4gdGhlIHNldHMgb2YgY291bnRyaWVzIGEgYml0IGxhdGVyIG9uLgpUaGVyZSBhcmUgYWxzbyBgciBuY29sKGdkcF9ncm93dGgpYCBjb2x1bW5zIHdpdGggYSBgY291bnRyeWAgY29sdW1uIGFuZCBhIHNldCBvZiBjb2x1bW5zIGNvcnJlc3BvbmRpbmcgdG8gZGlmZmVyZW50IHllYXJzLiAKCmBgYHtyfQpuYW1lcyhnZHBfZ3Jvd3RoKQpgYGAKClllcywgbm8gb3RoZXIgY29sdW1ucyBpbiB0aGlzIGRhdGFzZXQuIAoKTmV4dCwgd2Ugd2lsbCB1c2UgdGhlIGBwaXZvdF9sb25nZXIoKWAgdG8gdHJhbnNmb3JtIHRoZSBkYXRhIHRvIGxvbmcgZm9ybWF0LCBzaW1pbGFyIHRvIHdoYXQgd2UgZGlkIGluIHRoZSBwcmV2aW91cyBzZWN0aW9uLgoKV2Ugd2lsbCBhbHNvIGFnYWluIGNoYW5nZSB0aGUgYGNvdW50cnlgIHZhcmlhYmxlIHRvIGJlIGBDb3VudHJ5YCBieSB1c2luZyB0aGUgYHJlbmFtZSgpYCBmdW5jdGlvbiwgYW5kIHdlIHdpbGwgbWFrZSB0aGUgYFllYXJgIHZhcmlhYmxlIG51bWVyaWMgdXNpbmcgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24uIAoKIyMjIyB7LnJlY2FsbF9jb2RlX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KClVzaW5nIHdoYXQgeW91IGp1c3QgbGVhcm5lZCBhYm91dCBgcGl2b3RfbG9uZ2VyKClgLCBgcmVuYW1lKClgLCBhbmQgYG11dGF0ZSgpYCBhbmQgd2l0aG91dCBzY3JvbGxpbmcgdXAsIHRyeSB0byBjb21lIHVwIHdpdGggdGhlIGNvZGUgdG8gZG8gdGhlIHdyYW5nbGluZyBmb3IgdGhpcyBkYXRhLgoKIyMjIwoKYGBge3IgRFdfQ29kZTMtc2V0dXB9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsb2FkKGhlcmUoInd3dyIsICJkYXRhIiwgImltcG9ydGVkIiwgImNvMl9kYXRhX2ltcG9ydGVkLnJkYSIpKQpgYGAKCmBgYHtyIERXX0NvZGUzLCBleGVyY2lzZT1UUlVFfQojIFRyeSB0aGlzIG91dCEKYGBgCgpgYGB7ciBEV19Db2RlMy1oaW50LTEsIGV2YWwgPSBGQUxTRX0KZ2RwX2dyb3d0aCAlPiUgIyBsZXQncyBjaGVjayBiZWZvcmUgd2UgcmVhc3NpZ24gd2l0aCAlPD4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtY291bnRyeSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiWWVhciIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJnZHBfZ3Jvd3RoIikKYGBgCgpgYGB7ciBEV19Db2RlMy1oaW50LTJ9CmdkcF9ncm93dGggJT4lICMgbGV0J3MgY2hlY2sgYmVmb3JlIHdlIHJlYXNzaWduIHdpdGggJTw+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLWNvdW50cnksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlllYXIiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiZ2RwX2dyb3d0aCIpICU+JQogIHJlbmFtZShDb3VudHJ5ID0gY291bnRyeSkKYGBgCgpgYGB7ciBEV19Db2RlMy1zb2x1dGlvbn0KZ2RwX2dyb3d0aCAlPD4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtY291bnRyeSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiWWVhciIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJnZHBfZ3Jvd3RoIikgJT4lCiAgcmVuYW1lKENvdW50cnkgPSBjb3VudHJ5KSAlPiUKICBtdXRhdGUoWWVhciA9IGFzLm51bWVyaWMoWWVhciksCiAgICAgICAgIExhYmVsID0gIkdEUCBHcm93dGgvQ2FwaXRhICglKSIpICU+JQogIHJlbmFtZShHRFAgPSBnZHBfZ3Jvd3RoKQpgYGAKCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpnZHBfZ3Jvd3RoICU8PiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jb3VudHJ5LAogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImdkcF9ncm93dGgiKSAlPiUKICByZW5hbWUoQ291bnRyeSA9IGNvdW50cnkpICU+JQogIG11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhZZWFyKSwKICAgICAgICAgTGFiZWwgPSAiR0RQIEdyb3d0aC9DYXBpdGEgKCUpIikgJT4lCiAgcmVuYW1lKEdEUCA9IGdkcF9ncm93dGgpCmBgYCAgCgo8L2RldGFpbHM+CioqKgoKYGBge3IsIGVjaG8gPSBGQUxTRX0KZ2RwX2dyb3d0aCAlPD4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtY291bnRyeSwKICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwKICAgICAgICAgIHZhbHVlc190byA9ICJnZHBfZ3Jvd3RoIikgJT4lCiAgcmVuYW1lKENvdW50cnkgPSBjb3VudHJ5KSAlPiUKICBtdXRhdGUoWWVhciA9IGFzLm51bWVyaWMoWWVhciksCiAgICAgICAgTGFiZWwgPSAiR0RQIEdyb3d0aC9DYXBpdGEgKCUpIikgJT4lCiAgcmVuYW1lKEdEUCA9IGdkcF9ncm93dGgpCmBgYAoKTm93IGxldCdzIHNlZSBob3cgdGhpcyBkYXRhIGhhcyBjaGFuZ2VkOgoKYGBge3J9CmdkcF9ncm93dGggJT4lCiAgc2xpY2VfaGVhZChuID0gNikKCmdkcF9ncm93dGggJT4lCiAgY291bnQoWWVhcikKYGBgCgpBZ2FpbiBsZXQncyBjaGVjayB0aGF0IHRoZSBgQ291bnRyeWAgdmFyaWFibGUgb25seSBjb250YWlucyB2YWx1ZXMgd2Ugd291bGQgZXhwZWN0LgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpnZHBfZ3Jvd3RoICU+JQogIGRpc3RpbmN0KENvdW50cnkpICU+JQogIHB1bGwoKQpgYGAKIyMjIwoKQWxzbyBsb29rcyBnb29kIQoKIyMgKipFbmVyZ3kgVXNlIHBlciBQZXJzb24qKgoqKioKCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgZW5lcmd5IHVzZSBwZXIgcGVyc29uIGRhdGEgKGBlbmVyZ3lfdXNlYCkgdXNpbmcgYHNsaWNlX2hlYWQoKWAgYW5kIGBnbGltcHNlKClgLiAKCmBgYHtyfQplbmVyZ3lfdXNlICU+JQogIHNsaWNlX2hlYWQobiA9IDMpCmBgYAoKIyMjIyB7LnNjcm9sbGFibGV9CmBgYHtyfQplbmVyZ3lfdXNlICU+JQogIGdsaW1wc2UoKQpgYGAKIyMjIwoKTG9va3MgbGlrZSB3ZSBoYXZlIGByIG5yb3coZW5lcmd5X3VzZSlgIHJvd3MgYW5kIGByIG5jb2woZW5lcmd5X3VzZSlgIGNvbHVtbnMgd2hlcmUgd2UgaGF2ZSBhIGBjb3VudHJ5YCBjb2x1bW4gYW5kIGFnYWluIGEgc2V0IG9mIHllYXJzLiAKVG8gd3JhbmdsZSB0aGUgYGVuZXJneV91c2VgIGRhdGEsIHdlIHdpbGwgYWdhaW4gY29udmVydCB0aGUgZGF0YSB0byBsb25nIGZvcm1hdCwgcmVuYW1lIHNvbWUgdmFyaWFibGVzLCBhbmQgbXV0YXRlIHRoZSBgWWVhcmAgZGF0YSB0byBiZSBudW1lcmljLgoKIyMjIyB7LnJlY2FsbF9jb2RlX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCkFnYWluIHRyeSB0byBjb21lIHVwIHdpdGggdGhlIGNvZGUgb24geW91ciBvd24gdG8gd3JhbmdsZSB0aGUgZGF0YS4KCiMjIyMKCmBgYHtyIERXX0NvZGU0LXNldHVwfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtYWdyaXR0cikKbG9hZChoZXJlKCJ3d3ciLCAiZGF0YSIsICJpbXBvcnRlZCIsICJjbzJfZGF0YV9pbXBvcnRlZC5yZGEiKSkKYGBgCgpgYGB7ciBEV19Db2RlNCwgZXhlcmNpc2U9VFJVRX0KIyBUcnkgdGhpcyBvdXQhCmBgYAoKYGBge3IgRFdfQ29kZTQtaGludC0xfQplbmVyZ3lfdXNlICU+JSAjIGxldCdzIGNoZWNrIGJlZm9yZSB3ZSByZWFzc2lnbiB3aXRoICU8PiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jb3VudHJ5LAogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImVuZXJneV91c2UiKSAlPiUKICByZW5hbWUoQ291bnRyeSA9IGNvdW50cnkpCmBgYAoKYGBge3IgRFdfQ29kZTQtaGludC0yfQplbmVyZ3lfdXNlICU+JSAjIGxldCdzIGNoZWNrIGJlZm9yZSB3ZSByZWFzc2lnbiB3aXRoICU8PiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jb3VudHJ5LAogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImVuZXJneV91c2UiKSAlPiUKICByZW5hbWUoQ291bnRyeSA9IGNvdW50cnkpICU+JQogIG11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhZZWFyKSwKICAgICAgICAgTGFiZWwgPSAiRW5lcmd5IFVzZSAoa2csIG9pbC1lcS4vY2FwaXRhKSIpICU+JQogIHJlbmFtZShFbmVyZ3kgPSBlbmVyZ3lfdXNlKQpgYGAKCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gcmV2ZWFsIHRoZSBjb2RlLiA8L3N1bW1hcnk+CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQplbmVyZ3lfdXNlICU8PiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1jb3VudHJ5LAogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImVuZXJneV91c2UiKSAlPiUKICByZW5hbWUoQ291bnRyeSA9IGNvdW50cnkpICU+JQogIG11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhZZWFyKSwKICAgICAgICAgTGFiZWwgPSAiRW5lcmd5IFVzZSAoa2csIG9pbC1lcS4vY2FwaXRhKSIpICU+JQogIHJlbmFtZShFbmVyZ3kgPSBlbmVyZ3lfdXNlKQpgYGAKPC9kZXRhaWxzPgoqKioKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmVuZXJneV91c2UgJTw+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLWNvdW50cnksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlllYXIiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiZW5lcmd5X3VzZSIpICU+JQogIHJlbmFtZShDb3VudHJ5ID0gY291bnRyeSkgJT4lCiAgbXV0YXRlKFllYXIgPSBhcy5udW1lcmljKFllYXIpLAogICAgICAgICBMYWJlbCA9ICJFbmVyZ3kgVXNlIChrZywgb2lsLWVxLi9jYXBpdGEpIikgJT4lCiAgcmVuYW1lKEVuZXJneSA9IGVuZXJneV91c2UpCmBgYAoKCmBgYHtyfQpzZXQuc2VlZCgxMjMpCgplbmVyZ3lfdXNlICU+JQogIHNsaWNlX3NhbXBsZShuID0gMykKYGBgCgpOb3cgd2Ugd2lsbCBjaGVjayB0aGUgYENvdW50cnlgIHZhcmlhYmxlOgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQplbmVyZ3lfdXNlICU+JQogIGRpc3RpbmN0KENvdW50cnkpICU+JQogIHB1bGwoKQpgYGAKIyMjIwoKTG9va3MgZ29vZCEKCiMjICoqVVMgU3BlY2lmaWMgRGF0YSoqCioqKgoKTm93IHdlIHdpbGwgdGFrZSBhIGxvb2sgYXQgdGhlIFVTIGRhdGEgYWJvdXQgZGlzYXN0ZXJzIGFuZCB0ZW1wZXJhdHVyZS4KCiMjIyAqKkRpc2FzdGVycyoqCioqKgoKRmlyc3QsIHdlIGNvbnNpZGVyIHRoZSBkaXNhc3RlcnMgdGhhdCBoYXZlIG9jY3VycmVkIGluIHRoZSBVUy4gCmBgYHtyfQp1c19kaXNhc3RlcgpgYGAKCldlIGFyZSBzcGVjaWZpY2FsbHkgaW50ZXJlc3RlZCBpbiB0aGUgYFllYXJgIGFuZCB0aGUgdmFyaWFibGVzIHRoYXQgY29udGFpbiB0aGUgd29yZCBgIkNvdW50ImAuIFRoZSBvdGhlciB2YXJpYWJsZXMgcmVwcmVzZW50IGFuIGVzdGltYXRlIG9mIHRoZSBlY29ub21pYyBjb3N0IGluIGJpbGxpb25zIG9mIGRvbGxhcnMsIGFzIHdlbGwgYXMgdGhlIHVwcGVyIGFuZCBsb3dlciBib3VuZHMgZm9yIHNpbXVsYXRpb25zIHVzZWQgdG8gZXN0aW1hdGUgdGhlIGVjb25vbWljIGNvc3QsIHdoaWNoIHNob3cgdGhlIGxldmVsIG9mIHVuY2VydGFpbnR5IGluIHRoZXNlIGVzdGltYXRlcyAoYXQgdGhyZWUgZGlmZmVyZW50IGxldmVscyBvZiBjb25maWRlbmNlKSBhcyB0aGUgdHJ1ZSBjb3N0IGlzIHVua25vd24uIFNlZSBbaGVyZV0oaHR0cHM6Ly93d3cubmNkYy5ub2FhLmdvdi9iaWxsaW9ucy90aW1lLXNlcmllcykgZm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGRhdGEuIEZvciB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIGZvY3VzIGp1c3Qgb24gdGhlIG51bWJlciBvZiBkaXNhc3RlcnMgdGhhdCBvY2N1cnJlZCBlYWNoIHllYXIuIAoKV2Ugd2lsbCBzZWxlY3Qgb3VyIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCB1c2luZyB0aGUgYHNlbGVjdCgpYCBhbmQgYGNvbnRhaW5zKClgIGZ1bmN0aW9ucyBpbiB0aGUgYGRwbHlyYCBwYWNrYWdlLiAKU2luY2Ugd2UgYXJlIHNlbGVjdGluZyBmb3IgdmFyaWFibGVzIHdpdGggdGhlIHdvcmQgYCJDb3VudCJgIHdlIG5lZWQgdG8gdXNlIHF1b3RhdGlvbiBtYXJrcyBhcm91bmQgaXQuIAoKU2VsZWN0aW5nIGZvciB0aGUgdmFyaWFibGUgYFllYXJgIGRvZXMgbm90IHJlcXVpcmUgcXVvdGVzIGJlY2F1c2UgaXQgaXMgdGhlIGZ1bGwgbmFtZSBvZiBvbmUgb2YgdGhlIGV4aXN0aW5nIHZhcmlhYmxlcy4KCgpgYGB7cn0KdXNfZGlzYXN0ZXIgJTw+JQogICAgICAgICAgIHNlbGVjdChZZWFyLCBjb250YWlucygiQ291bnQiKSkKCnVzX2Rpc2FzdGVyICU+JQogIHNsaWNlX2hlYWQobiA9IDYpCmBgYAoKTm93IHdlIHdhbnQgdG8gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIHRoYXQgd2lsbCBiZSB0aGUgc3VtIG9mIGFsbCB0aGUgZGlmZmVyZW50IHR5cGVzIG9mIGRpc2FzdGVycyBmb3IgZWFjaCB5ZWFyLiAKCldlIGRvbid0IHdhbnQgdG8gaW5jbHVkZSB0aGUgYFllYXJgIHZhcmlhYmxlIGluIG91ciBzdW0sIHNvIHdlIGNhbiBleGNsdWRlIGl0IHVzaW5nIHRoZSBgc2VsZWN0YCBmdW5jdGlvbi4gVG8gcGVyZm9ybSB0aGUgc3VtIGZvciBlYWNoIHllYXIsIHdlIGNhbiB1c2UgdGhlIGJhc2UgYHJvd1N1bXMoKWAgZnVuY3Rpb24uIAoKYGBge3J9CnllYXJseV9kaXNhc3RlcnMgPC0gdXNfZGlzYXN0ZXIgJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KC1ZZWFyKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIHJvd1N1bXMoKQoKeWVhcmx5X2Rpc2FzdGVycwpgYGAKCldlIGNvdWxkIHRoZW4gYWRkIHRoaXMgdG8gb3VyIGB1c19kaWFzdGVyYCB0aWJibGUgbGlrZSBzbyB1c2luZyB0aGUgYGJpbmRfY29sc2AgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZToKCmBgYHtyfQp1c19kaXNhc3RlciAlPiUgYmluZF9jb2xzKERpc2F0ZXJzID0geWVhcmx5X2Rpc2FzdGVycykKYGBgCgpIb3dldmVyLCB3ZSBjYW4gYWN0dWFsbHkgY3JlYXRlIGFuZCBhZGQgdGhpcyBuZXcgdmFyaWFibGUgZGlyZWN0bHkgdG8gdGhlIGB1c19kaXNhc3RlcmAgdGliYmxlIGJ5IHVzaW5nIHRoZSBgbXV0YXRlKClgIGZ1bmN0aW9uIG9mIGBkcGx5cmAgYW5kIHVzaW5nIHRoZSBgLmAgbm90YXRpb24uCgpXZSBuZWVkIHRvIHVzZSB0aGUgYC5gIG5vdGF0aW9uIHRvIGluZGljYXRlIHRoYXQgd2UgYXJlIHVzaW5nIHRoZSBkYXRhIHRoYXQgd2UgYWxyZWFkeSB1c2VkIGFzIGlucHV0IChvbiB0aGUgbGVmdCBzaWRlIG9mIHRoZSBwaXBlKSB0byBvdXIgYG11dGF0ZSgpYCBmdW5jdGlvbiAob24gdGhlIHJpZ2h0IHNpZGUgb2Ygb3VyIHBpcGUpLCB3aGljaCBpbiB0aGlzIGNhc2UgaXMgdGhlIGVudGlyZSBgdXNfZGlzYXN0ZXJgIHRpYmJsZSBmb3Igb3VyIGBzZWxlY3QoKWAgZnVuY3Rpb24uIFRoZSBvdXRwdXQgZnJvbSB0aGUgYHNlbGVjdCgpYCBmdW5jdGlvbiB3aWxsIGJlIHVzZWQgZm9yIHRoZSBgcm93U3VtcygpYCBmdW5jdGlvbi4gCgpgYGB7cn0KdXNfZGlzYXN0ZXIgJTw+JQogIG11dGF0ZShEaXNhc3RlcnMgPSByb3dTdW1zKHNlbGVjdCguLCAtWWVhcikpKQoKdXNfZGlzYXN0ZXIgJT4lCiAgZ2xpbXBzZSgpCmBgYAoKR3JlYXQsIG5vdyB3ZSBhcmUgZ29pbmcgdG8gcmVtb3ZlIHNvbWUgb2YgdGhlc2UgdmFyaWFibGVzIGFuZCBqdXN0IGtlZXAgdGhlIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCB1c2luZyBgc2VsZWN0KClgLgoKV2UgYXJlIGFsc28gZ29pbmcgdG8gYWRkIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBgQ291bnRyeWAgdG8gaW5kaWNhdGUgdGhhdCB0aGlzIGRhdGEgaXMgZnJvbSB0aGUgVW5pdGVkIFN0YXRlcy4gQWdhaW4gdGhpcyB3aWxsIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSB3aGVyZSBldmVyeSB2YWx1ZSBpcyBgVW5pdGVkIFN0YXRlc2AuCgpgYGB7cn0KdXNfZGlzYXN0ZXIgJTw+JQogIGRwbHlyOjpzZWxlY3QoWWVhciwgRGlzYXN0ZXJzKSAlPiUKICBtdXRhdGUoQ291bnRyeSA9ICJVbml0ZWQgU3RhdGVzIikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKC1Db3VudHJ5LCAtWWVhciksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkluZGljYXRvciIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJWYWx1ZSIpICU+JQogIG11dGF0ZShMYWJlbCA9ICJOdW1iZXIgb2YgRGlzYXN0ZXJzIikKCnVzX2Rpc2FzdGVyICU+JQogIHNsaWNlX2hlYWQobiA9IDYpCmBgYApHcmVhdCwgdGhpcyBsb29rcyBnb29kIG5vdy4gCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKVGhpcyBkYXRhc2V0IHdhcyBzbGlnaHRseSBkaWZmZXJlbnQgZnJvbSB0aGUgb3RoZXIgZGF0YXNldHMgYW5kIHRoZXJlZm9yZSByZXF1aXJlZCBzbGlnaHRseSBkaWZmZXJlbnQgd3JhbmdsaW5nLgpXaHkgd2FzIGl0IG5lY2Vzc2FyeSB0byBleGNsdWRlIHRoZSBgWWVhcmAgdmFyaWFibGUgZnJvbSB0aGUgYHBpdm90X2xvbmdlcigpYCBmdW5jdGlvbj8KV2hhdCB3b3VsZCBoYXBwZW4gaWYgd2UgZGlkIG5vdCBleGNsdWRlIGBZZWFyYD8KCiMjIyMKCmBgYHtyIERXX0NvZGU1LXNldHVwfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtYWdyaXR0cikKbG9hZChoZXJlKCJ3d3ciLCAiZGF0YSIsICJpbXBvcnRlZCIsICJjbzJfZGF0YV9pbXBvcnRlZC5yZGEiKSkKCnVzX2Rpc2FzdGVyICU8PiUKICBzZWxlY3QoWWVhciwgY29udGFpbnMoIkNvdW50IikpICU+JQogIG11dGF0ZShEaXNhc3RlcnMgPSByb3dTdW1zKHNlbGVjdCguLCAtWWVhcikpKQpgYGAKCmBgYHtyIERXX0NvZGU1LCBleGVyY2lzZT1UUlVFfQojIFRyeSB0aGlzIG91dCEKYGBgCgojIyMgKipUZW1wZXJhdHVyZSoqCioqKgoKTmV4dCwgd2UgY29uc2lkZXIgdGhlIHRlbXBlcmF0dXJlIGluIHRoZSBVUyBvdmVyIHRpbWUuICAKYGBge3J9CnVzX3RlbXBlcmF0dXJlICU+JQogIHNsaWNlX2hlYWQobiA9IDYpCmBgYApTbyBhIGZldyB0aGluZ3MgbmVlZCB0byBiZSBmaXhlZCBoZXJlLiAKCkZpcnN0LCB0aGUgYERhdGVgIGNvbHVtbiBsb29rcyBhIGJpdCBzdHJhbmdlLiBUaGUgZm9ybWF0IG9mIHRoZSBudW1iZXJzIGxvb2sgbGlrZSB0aGUgeWVhciBmb2xsb3dlZCBieSB0aGUgbnVtYmVyIDEyIChyZXByZXNlbnRpbmcgMTIgbW9udGhzKS4KCldlIHdhbnQgdG8gY2hhbmdlIHRoaXMgdG8gb25seSBrZWVwIHRoZSBmaXJzdCA0IGNoYXJhY3RlcnMgaW4gdGhlIGBEYXRlYCB2YXJpYWJsZSBzdHJpbmcgdmFsdWVzLiAKCkhvd2V2ZXIsIGZpcnN0IGxldCdzIG1ha2Ugc3VyZSB0aGF0IGluZGVlZCBhbGwgb2YgdGhlIGBEYXRlYCB2YXJpYWJsZXMgYXJlIDYgY2hhcmFjdGVycyBsb25nIGFuZCB0aGF0IHRoZXkgYWxsIGVuZCB3aXRoIHRoZSBudW1iZXIgMTIuCgpXZSBjYW4gdXNlIGEgY291cGxlIG9mIGZ1bmN0aW9ucyBpbiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgdG8gZG8gdGhpcy4gVGhpcyBwYWNrYWdlIGlzIHVzZWQgZm9yIHdvcmtpbmcgd2l0aCBjaGFyYWN0ZXIgc3RyaW5ncy4gIFRoZSBgc3RyX2xlbmd0aCgpYCBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBjaGVjayB0aGUgbGVuZ3RoIG9mIGVhY2ggdmFsdWUsIHdoaWxlIHRoZSBgc3RyX2VuZHMoKWAgZnVuY3Rpb24gY2FuIGJlIHVzZWQgdG8gY2hlY2sgdGhhdCBhbGwgdGhlIHZhbHVlcyBlbmQgd2l0aCBgIjEyImAuCgpMZXQncyBzdGFydCB3aXRoIHRoZSBgc3RyX2xlbmd0aCgpYCBmdW5jdGlvbi4gVGhlc2UgZnVuY3Rpb25zIGluIHRoZSBgc3RyaW5ncmAgcGFja2FnZSByZXF1aXJlIGEgY2hhcmFjdGVyIHZlY3Rvci4gVGh1cyB3ZSBuZWVkIHRvIHB1bGwgdGhlIHZhbHVlcyBmb3IgdGhlIGBEYXRlYCB2YXJpYWJsZSBmaXJzdCB1c2luZyB0aGUgYHB1bGwoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gCgpgYGB7cn0KdXNfdGVtcGVyYXR1cmUgJT4lCiAgcHVsbChEYXRlKSAlPiUKICBzdHJfbGVuZ3RoKCkKYGBgCkdyZWF0ISBJdCBsb29rcyBsaWtlIGFsbCBvZiB0aGUgdmFsdWVzIGFyZSA2IGNoYXJhY3RlcnMgbG9uZy4KCk5vdyBsZXQncyBjaGVjayB0aGF0IHRoZXkgYWxsIGVuZCB3aXRoIGAiMTIiYC4gV2UganVzdCBuZWVkIHRvIHNwZWNpZnkgd2hhdCBwYXR0ZXJuIHRvIGxvb2sgZm9yLiAKCmBgYHtyfQp1c190ZW1wZXJhdHVyZSAlPiUKICBwdWxsKERhdGUpICU+JQogIHN0cl9lbmRzKHBhdHRlcm4gPSAiMTIiKQoKYGBgCkdyZWF0ISBTaW5jZSBhbGwgb2YgdGhlIHZhbHVlcyBhcmUgYFRSVUVgIHdlIGtub3cgdGhhdCBhbGwgb2YgdGhlIHZhbHVlcyBpbiB0aGUgYERhdGVgIHZhcmlhYmxlIGVuZCB3aXRoIGAiMTIiYC4KCkl0J3MgYSBnb29kIGlkZWEgdG8gYWx3YXlzIGNoZWNrIHRoYXQgeW91ciBkYXRhIGlzIGFzIHlvdSBleHBlY3QuIAoKTm93IHdlIGNhbiB1c2UgdGhlIGBzdHJfc3ViKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZSB0byByZW1vdmUgdGhlIGAiMTIiYCBmcm9tIGVhY2ggYERhdGVgIHZhbHVlLgoKV2UganVzdCBuZWVkIHRvIGluZGljYXRlIHRoZSBzdGFydCBhbmQgc3RvcCBjaGFyYWN0ZXJzLiAKCkluIHRoaXMgY2FzZSB0aGUgc3RhcnQgd291bGQgYmUgMSBhbmQgdGhlIDR0aCBjaGFyYWN0ZXIgd291bGQgYmUgd2hlcmUgd2Ugd2FudCB0byBzdG9wLCBzbyB3ZSB3b3VsZCB1c2UgYHN0YXJ0ID0gMSwgc3RvcCA9IDRgLiBXZSBjYW4gZG8gdGhpcyBpbnNpZGUgb2YgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gdG8gbW9kaWZ5IHRoZSBgRGF0ZWAgdmFyaWFibGUuIEluIGRvaW5nIHNvLCB3ZSB3aWxsIG5vdCBuZWVkIHRvIHVzZSBgcHVsbCgpYCB0byBwdWxsIHRoZSB2YWx1ZXMgZm9yIHRoZSBgRGF0ZWAgdmFyaWFibGUuCgpgYGB7cn0KdXNfdGVtcGVyYXR1cmUgJTw+JQogIG11dGF0ZShEYXRlID0gc3RyX3N1YihEYXRlLCBzdGFydCA9IDEsIGVuZCA9IDQpKQoKdXNfdGVtcGVyYXR1cmUKYGBgCldlIGFsc28gd2FudCB0byByZW1vdmUgdGhlIGBBbm9tYWx5YCB2YXJpYWJsZSwgd2hpY2ggaXMgYW4gaW5kaWNhdG9yIG9mIGhvdyBkaWZmZXJlbnQgdGhlIG5hdGlvbmFsIGF2ZXJhZ2UgdGVtcGVyYXR1cmUgZm9yIHRoYXQgeWVhciB3YXMgZnJvbSB0aGUgYXZlcmFnZSB0ZW1wZXJhdHVyZSBmcm9tIDE5MDEtMjAwMCB3aGljaCB3YXMgNTIuMDImZGVnO0YuIAoKVGhlbiwgd2UgYWxzbyB3YW50IHRvIGNyZWF0ZSBhIGBDb3VudHJ5YCB2YXJpYWJsZS4gCldlIHdpbGwgYWxzbyBjaGFuZ2UgdGhlIG5hbWUgb2YgdGhlIGBEYXRlYCB2YXJpYWJsZSB0byBgWWVhcmAgc28gdGhhdCBpdCB3aWxsIGJlIGNvbnNpc3RlbnQgd2l0aCBvdXIgb3RoZXIgZGF0YXNldHMuIFdlIGFsc28gYWxzbyB3YW50IHRoZSBgWWVhcmAgdG8gYmUgbnVtZXJpYy4gCldlIGNhbiBhY2NvbXBsaXNoIGJvdGggcmVuYW1pbmcgYW5kIGNoYW5naW5nIHRvIG51bWVyaWMgYnkgdXNpbmcgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24uCgpXZSBhbHNvIHdhbnQgdG8gY3JlYXRlIGFuIGBJbmRpY2F0b3JgIHZhcmlhYmxlIHNvIHRoYXQgd2UgY2FuIGxhdGVyIHRlbGwgd2hhdCBkYXRhIHRoZSB2YWx1ZXMgaW4gdGhpcyB0aWJibGUgcmVwcmVzZW50IGlmIHdlIGNvbWJpbmUgaXQgd2l0aCBvdGhlciB0aWJibGVzIGFuZCBhIGBMYWJlbGAgdmFyaWFibGUsIHNvIHRoYXQgd2Ugd2lsbCBoYXZlIGluZm9ybWF0aXZlIGxhYmVscyBpZiB3ZSBtYWtlIGEgcGxvdCB3aXRoIHRoaXMgZGF0YSBsYXRlci4gCgpGaW5hbGx5LCB3ZSByZW1vdmUgdGhlIGBEYXRlYCB2YXJpYWJsZSBhbmQgYWxzbyBvcmRlciB0aGUgY29sdW1ucyBqdXN0IGxpa2UgdGhlIG90aGVyIHVzIGRhdGEgdXNpbmcgdGhlIGBzZWxlY3QoKWAgZnVuY3Rpb24uCgpgYGB7cn0KdXNfdGVtcGVyYXR1cmUgJTw+JQogIGRwbHlyOjpzZWxlY3QoLUFub21hbHkpICU+JQogIG11dGF0ZShDb3VudHJ5ID0gIlVuaXRlZCBTdGF0ZXMiLAogICAgICAgICBZZWFyID0gYXMubnVtZXJpYyhEYXRlKSwKICAgICAgICAgSW5kaWNhdG9yID0gIlRlbXBlcmF0dXJlIiwKICAgICAgICAgTGFiZWwgPSAiVGVtcGVyYXR1cmUgKEZhaHJlbmhlaXQpIikgJT4lCiAgc2VsZWN0KFllYXIsIENvdW50cnksIEluZGljYXRvciwgVmFsdWUsIExhYmVsKQoKdXNfdGVtcGVyYXR1cmUgJT4lCiAgc2xpY2VfaGVhZChuID0gNikKYGBgCgoKIyMgKipKb2luaW5nIGRhdGEqKgoqKioKCk5vdyB0aGF0IHdlIGhhdmUgd3JhbmdsZWQgdGhlIGluZGl2aWR1YWwgZGF0YXNldHMsIHdlIGFyZSByZWFkeSB0byBwdXQgZXZlcnl0aGluZyB0b2dldGhlci4gClNwZWNpZmljYWxseSwgd2Ugd2lsbCBfam9pbl8gdGhlIGluZGl2aWR1YWwgZGF0YXNldHMgaW50byBvbmUgdGliYmxlIHVzaW5nIGAqX2pvaW4oKWAgZnVuY3Rpb25zIGF2YWlsYWJsZSBpbiB0aGUgYGRwbHlyYCBwYWNrYWdlLiAKCkJlZm9yZSB3ZSBiZWdpbiB0aG91Z2gsIHdlIHdpbGwgbmVlZCB0byBtYWtlIHN1cmUgdGhhdCB0aGVyZSBpcyBhdCBsZWFzdCBvbmUgdmFyaWFibGUvY29sdW1uIHRoYXQgaGFzIHRoZSBzYW1lIG5hbWUgYWNyb3NzIGFsbCBkYXRhc2V0cyB0byBiZSBqb2luZWQuIFN1Y2ggdmFyaWFibGVzIHdpdGggY29tbW9uIG5hbWVzIGFyZSBjYWxsZWQgKiprZXlzKiogZm9yIGpvaW5pbmcgeW91ciBkYXRhLgoKVGhlc2UgYXJlIHRoZSBgYnk9IngxImAgYXJndW1lbnRzIGJlbG93IHdoZXJlIGB4MWAgaXMgdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiBpbiBib3RoIHRoZSBgYWAgYW5kIGBiYCBkYXRhc2V0cyB0aGF0IHdlIHdpbGwgam9pbiB0b2dldGhlci4gCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiNTAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInd3dy9pbWcvam9pbi5wbmciKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly9yc3R1ZGlvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxNS8wMi9kYXRhLXdyYW5nbGluZy1jaGVhdHNoZWV0LnBkZil7dGFyZ2V0PSJfYmxhbmsifQoKVGhlcmUgYXJlIHNldmVyYWwgdHlwZXMgb2YgYCpfam9pbigpYCBmdW5jdGlvbnMgdG8gY29uc2lkZXIuIFRoZSBgZnVsbF9qb2luKClgIGZ1bmN0aW9uIGtlZXBzIGFsbCByb3dzIGZyb20gYm90aCB0aWJibGVzIHRoYXQgYXJlIGJlaW5nIGpvaW5lZCBhbmQgYWRkcyBgTkFgIHZhbHVlcyBhcyBuZWNlc3NhcnkgaWYgdGhlcmUgYXJlIHZhbHVlcyB3aXRoaW4gdGhlIGtleSBmb3IgZWl0aGVyIG9mIHRoZSB0aWJibGVzIHRoYXQgaXMgaXMgbm90IGluIHRoZSBrZXkgb2YgdGhlIG90aGVyIHRpYmJsZS4gCgpXZSB1c2UgdGhlIGBmdWxsX2pvaW4oKWAgZnVuY3Rpb24gYXMgd2UgaGF2ZSBkaWZmZXJlbnQgdGltZSBzcGFucyBmb3IgZWFjaCBkYXRhc2V0IGFuZCB3ZSB3b3VsZCBsaWtlIHRvIHJldGFpbiBhcyBtdWNoIGRhdGEgYXMgcG9zc2libGUuIAoKVGhlIGBmdWxsX2pvaW4oKWAgZnVuY3Rpb24gd2lsbCBzaW1wbHkgY3JlYXRlIGBOQWAgdmFsdWVzIGZvciBhbnkgb2YgdGhlIHllYXJzIHRoYXQgYXJlIG5vdCBpbiBvbmUgb2YgdGhlIGRhdGFzZXRzLiAKCkZpcnN0LCB3ZSBjaGVjayB1c2luZyB0aGUgYmFzZSBgc3VtbWFyeSgpYCBmdW5jdGlvbiB0aGF0IHRoZXJlIGFyZSBjb2x1bW4gbmFtZXMgdGhhdCBhcmUgY29uc2lzdGVudCBpbiBlYWNoIGRhdGFzZXQgdGhhdCB3ZSB3aXNoIHRvIGNvbWJpbmUuCgpgYGB7cn0Kc3VtbWFyeShDTzJfZW1pc3Npb25zKQpzdW1tYXJ5KGdkcF9ncm93dGgpCnN1bW1hcnkoZW5lcmd5X3VzZSkKYGBgCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKV2hhdCB2YXJpYWJsZSBvciB2YXJpYWJsZXMgbWlnaHQgd2Ugd2FudCB0byB1c2UgdG8gam9pbiBvdXIgZGF0YSBieT8KCiMjIyMKCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIGFuIGV4cGxhbmF0aW9uIGZvciB3aGF0IHZhcmlhYmxlIG9yIHZhcmlhYmxlcyB0byBqb2luIGJ5IGFmdGVyIHlvdSBoYXZlIHRob3VnaHQgYWJvdXQgaXQuIDwvc3VtbWFyeT4KCgpUaGUgYENvdW50cnlgLCBhbmQgYFllYXJgIHZhcmlhYmxlcyBhcmUgcHJlc2VudCBpbiBhbGwgb2YgdGhlIGRhdGFzZXRzIHdpdGggdmFsdWVzIHRoYXQgb3ZlcmxhcC4gQWx0aG91Z2ggYExhYmVsYCBpcyBhbHNvIHByZXNlbnQgaW4gdGhlIGRhdGFzZXRzLCB0aGUgdmFsdWVzIGRvIG5vdCBvdmVybGFwLiBXZSBjYW4gc2VlIHRoYXQgdGhlIG1pbmltdW0gYW5kIG1heGltdW0geWVhciBpcyBkaWZmZXJlbnQgZm9yIG5lYXJseSBhbGwgdGhlIGRhdGFzZXRzLgoKCk5leHQsIHdlIG5lZWQgdG8gc3BlY2lmeSB3aGF0IGNvbHVtbnMvdmFyaWFibGVzIHdlIHdpbGwgYmUgam9pbmluZyBieSB1c2luZyB0aGUgYGJ5ID1gIGFyZ3VtZW50IGluIHRoZSBgZnVsbF9qb2luKClgIGZ1bmN0aW9uLCAocmVjYWxsIHRoYXQgdGhpcyB2YXJpYWJsZSBpcyBjYWxsZWQgdGhlICJrZXkiKQoKYGBge3J9CmRhdGFfd2lkZSA8LSBDTzJfZW1pc3Npb25zICU+JQogIGZ1bGxfam9pbihnZHBfZ3Jvd3RoLCBieSA9IGMoIkNvdW50cnkiLCAiWWVhciIsICJMYWJlbCIpKSAlPiUKICBmdWxsX2pvaW4oZW5lcmd5X3VzZSwgYnkgPSBjKCJDb3VudHJ5IiwgIlllYXIiLCAiTGFiZWwiKSkKCnNldC5zZWVkKDEyMykKCmRhdGFfd2lkZSAlPiUKICBzbGljZV9zYW1wbGUobiA9IDYpCmBgYAoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgYW4gZXhwbGFuYXRpb24gZm9yIGFub3RoZXIgb3B0aW9uIHRoYXQgd29ya3Mgd2VsbCBmb3IgbGFyZ2UgbnVtYmVycyBvZiB0aWJibGVzIDwvc3VtbWFyeT4KCldlIGNhbiBhbHNvIGRvIHRoZSBzYW1lIHRoaW5nIGJ5IHVzaW5nIHRoZSBgcmVkdWNlKClgIGZ1bmN0aW9uIG9mIHRoZSBgcHVycnJgIHBhY2thZ2UuICBUaGlzIHRha2VzIGEgbGlzdCBvZiBlbGVtZW50cyAod2hpY2ggY2FuIGJlIHRpYmJsZXMpIGFuZCB0aGVuIGFwcGxpZXMgYSBmdW5jdGlvbiB0aGF0IHJlcXVpcmVzIHR3byBpbnB1dHMgaXRlcmF0aXZlbHkgdXNpbmcgdGhlIGZpcnN0IHBhaXIgb2YgZWxlbWVudHMgYW5kIGNyZWF0aW5nIGEgc2luZ2xlIGVsZW1lbnQgYW5kIHRoZW4gYXBwbHlpbmcgdGhlIGZ1bmN0aW9uIGFnYWluIHRvIHRoZSBvdXRwdXQgZWxlbWVudCBhbmQgdGhlIG5leHQgbGlzdGVkIGVsZW1lbnQgYW5kIHNvIG9uIGFuZCBzbyBmb3J0aC4KCkZvciBleGFtcGxlIHdlIHdpbGwgdXNlIGEgbGlzdCBvZiB0aWJibGVzIGFuZCB0aGUgYGZ1bGxfam9pbigpYCBmdW5jdGlvbiB3aGljaCByZXF1aXJlcyB0d28gdGliYmxlcyB0byBjb21iaW5lLiBUaGlzIHdpbGwgZmlyc3QgY29tYmluZSBgQ08yX2VtaXNzaW9uc2AgYW5kICBgZ2RwX2dyb3d0aGAgYW5kIHRoZW4gdGFrZSB0aGUgcmVzdWx0aW5nIGpvaW5lZCB0aWJibGUgYW5kIGNvbWJpbmUgdGhpcyB3aXRoIHRoZSBgZW5lcmd5X3VzZWAgdGliYmxlLiAKCgpZb3UgY2FuIHNlZSB0aGF0IHRoaXMgaXMgYSBncmVhdCBvcHRpb24gaWYgeW91IGhhdmUgbWFueSBkYXRhc2V0cyB0byBjb21iaW5lIQoKYGBge3J9CmRhdGFfd2lkZSA8LQogIGxpc3QoQ08yX2VtaXNzaW9ucywgZ2RwX2dyb3d0aCwgZW5lcmd5X3VzZSkgJT4lCiAgcmVkdWNlKGZ1bGxfam9pbiwgYnkgPSBjKCJDb3VudHJ5IiwgIlllYXIiLCAiTGFiZWwiKSkKCnNldC5zZWVkKDEyMykKCmRhdGFfd2lkZSAlPiUKICBzbGljZV9zYW1wbGUobiA9IDYpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CnNhdmUoZGF0YV93aWRlLCBmaWxlID0gaGVyZTo6aGVyZSgid3d3IiwgImRhdGEiLCAiZXhlcmNpc2UiLCAid2lkZV9kYXRhLnJkYSIpKQpgYGAKCjwvZGV0YWlscz4gCjwvZGV0YWlscz4KKioqCgpgYGB7cn0KZGF0YV93aWRlICU+JQogIGdsaW1wc2UoKQpgYGAKCk5pY2UsIGxvb2tzIGdvb2QhCgoKV2Ugd2lsbCBhbHNvIG1ha2UgYSBsb25nIHZlcnNpb24gb2YgdGhpcyBkYXRhLCB3aGVyZSB3ZSB3aWxsIGNyZWF0ZSBhbiBuZXcgdmFyaWFibGUgY2FsbGVkIGBJbmRpY2F0b3JgIHRoYXQgd2lsbCBpbmRpY2F0ZSB3aGF0IGRhdGFzZXQgdGhlIGRhdGEgY2FtZSBmcm9tLgoKIyMjIyB7LnJlY2FsbF9jb2RlX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KClRyeSB0byBjb21lIHVwIHdpdGggdGhlIGNvZGUgdG8gZG8gdGhpcy4KCiMjIyMKCmBgYHtyIERXX0NvZGU2LXNldHVwfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtYWdyaXR0cikKbG9hZChoZXJlOjpoZXJlKCJ3d3ciLCAiZGF0YSIsICJleGVyY2lzZSIsICJ3aWRlX2RhdGEucmRhIikpCmBgYAoKYGBge3IgRFdfQ29kZTYsIGV4ZXJjaXNlPVRSVUV9CiMgVHJ5IHRoaXMgb3V0IQpgYGAKCmBgYHtyIERXX0NvZGU2LXNvbHV0aW9ufQpkYXRhX2xvbmcgPC0gZGF0YV93aWRlICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYygtQ291bnRyeSwgLVllYXIsIC1MYWJlbCksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkluZGljYXRvciIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJWYWx1ZSIpCmBgYAoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byByZXZlYWwgdGhlIGNvZGUuIDwvc3VtbWFyeT4KCgpgYGB7cn0KZGF0YV9sb25nIDwtIGRhdGFfd2lkZSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoLUNvdW50cnksIC1ZZWFyLCAtTGFiZWwpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJJbmRpY2F0b3IiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiVmFsdWUiKQpgYGAKCjwvZGV0YWlscz4gCioqKgoKYGBge3J9CnNldC5zZWVkKDEyMykKCmRhdGFfbG9uZyAlPiUKICBzbGljZV9zYW1wbGUobiA9IDYpCmBgYAoKCldlIHdpbGwgbm93IGNvbWJpbmUgdGhpcyBkYXRhIHdpdGggdGhlIFVTIGRhdGEgYWJvdXQgZGlzYXN0ZXJzIGFuZCB0ZW1wZXJhdHVyZXMuCgoKYGBge3J9CnVzX2Rpc2FzdGVyICU+JQogIHNsaWNlX2hlYWQobiA9IDYpCnVzX3RlbXBlcmF0dXJlICU+JQogIHNsaWNlX2hlYWQobiA9IDYpCmBgYAoKV2Ugd2lsbCBub3cgdXNlIHRoZSBgYmluZF9yb3dzKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2Ugd2hpY2ggd2lsbCBqdXN0IGFwcGVuZCB0aGUgYHVzX3RlbXBlcmF0dXJlYCBkYXRhIGFuZCB0aGUgYHVzX2Rpc2FzdGVyYCBkYXRhIGFmdGVyIHRoZSBgZGF0YV9sb25nYCBkYXRhLiAKCmBgYHtyfQpkYXRhX2xvbmcgPC0KICBsaXN0KGRhdGFfbG9uZywgdXNfZGlzYXN0ZXIsIHVzX3RlbXBlcmF0dXJlKSAlPiUKICBiaW5kX3Jvd3MoKSAlPiUKICBtdXRhdGUoQ291bnRyeSA9IGFzLmZhY3RvcihDb3VudHJ5KSkKYGBgCgpXZSBhbHNvIGNvbnZlcnRlZCB0aGUgYENvdW50cnlgIGNvbHVtbiB0byBhIGZhY3RvciBpbiB0aGUgbGFzdCBsaW5lIG9mIHRoZSBjb2RlIGNodW5rLiAKCldlIGNhbiBjaGVjayB0aGUgdG9wIGFuZCBib3R0b20gb2YgdGhlIG5ldyBgZGF0YV9sb25nYCB0aWJibGUgdG8gc2VlIHRoYXQgb3VyIGB1c190ZW1wZXJhdHVyZWAgZGF0YSBpcyBhdCB0aGUgYm90dG9tLiBUbyBzZWUgdGhlIGVuZCBvZiBvdXIgdGliYmxlIHdlIGNhbiB1c2UgYHNsaWNlX3RhaWwoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KCmBgYHtyfQpkYXRhX2xvbmcgJT4lCiAgc2xpY2VfaGVhZChuID0gNikKCmRhdGFfbG9uZyAlPiUKICBzbGljZV90YWlsKG4gPSA2KQoKc2V0LnNlZWQoMTIzKQoKZGF0YV9sb25nICU+JQogIHNsaWNlX3NhbXBsZShuID0gMTApCmBgYAoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSBmb3IgZGV0YWlscyBhYm91dCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGBmdWxsX2pvaW4oKWAgYW5kIGBiaW5kX3Jvd3MoKWAgPC9zdW1tYXJ5PgoKVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGlzIGZ1bmN0aW9uIGFuZCB0aGUgYGZ1bGxfam9pbigpYCBmdW5jdGlvbiBpcyB0aGF0IHRoZSBgYmluZF9yb3dzKClgIGZ1bmN0aW9uIHdpbGwgZXNzZW50aWFsbHkganVzdCBhcHBlbmQgZWFjaCBkYXRhc2V0IHRvIGVhY2ggb3RoZXIsIHdoZXJlYXMgdGhlIGBmdWxsX2pvaW4oKWAgZnVuY3Rpb24gY29sbGFwc2VzIGRhdGEgdGhhdCBpcyBjb21wYXJhYmxlLiAKSGVyZSwgeW91IHdpbGwgc2VlIGFuIGV4YW1wbGUgb2Ygd2hhdCB0aGUgZGF0YSB3b3VsZCBoYXZlIGJlZW4gbGlrZSBmb3IgYGRhdGFfd2lkZWAgaWYgd2UgaGFkIG1hZGUgaXQgdXNpbmcgYGJpbmRfcm93cygpYCBhbmQgaWYgYGZ1bGxfam9pbigpYCBoYWQgYmVlbiB1c2VkIGJ1dCB3YXMgbm90IGpvaW5lZCBieSB0aGUgYExhYmVsYCB2YXJpYWJsZS4KU2luY2UgdGhlIGBMYWJlbGAgdmFyaWFibGUgaGFzIHVuaXF1ZSB2YWx1ZXMgZm9yIGVhY2ggdHlwZSBvZiBgSW5kaWNhdG9yYCwgdGhpcyBjYXVzZXMgdGhlIGBmdWxsX2pvaW4oKWAgcmVzdWx0IHRvIGJlIHRoZSBzYW1lIGFzIGBiaW5kX3Jvd3MoKWAuIAoKTGV0J3MgY29uc2lkZXIgYW4gZXhhbXBsZSBhbmQgbG9vayBhdCB0aGUgdmFsdWVzIGZvciBDaGluYSBpbiB0aGUgeWVhciBvZiAxOTgwLgoKRmlyc3Qgd2Ugd2lsbCB1c2UgdGhlIGBiaW5kX3Jvd3MoKWAgZnVuY3Rpb24gd2hpY2ggYXV0b21hdGljYWxseSBjcmVhdGVzIGBOQWAgdmFsdWVzIGZvciBhbnkgdmFyaWFibGUgdGhhdCBpcyBtaXNzaW5nIGZyb20gYSBkYXRhIG9iamVjdCB0aGF0IGlzIGFkZGVkIGJ5IGNvbWJpbmluZyB0aGUgZGF0YSBvYmplY3Qgd2l0aCBhbm90aGVyIHRoYXQgY29udGFpbnMgdGhhdCBtaXNzaW5nIHZhcmlhYmxlIHVzaW5nIHRoaXMgZnVuY3Rpb24uCgpgYGB7cn0KZGF0YV93aWRlX2JyIDwtCiAgbGlzdChDTzJfZW1pc3Npb25zLCBnZHBfZ3Jvd3RoLCBlbmVyZ3lfdXNlKSAlPiUKICBiaW5kX3Jvd3MoKQoKZGF0YV93aWRlX2JyICU+JQogZmlsdGVyKENvdW50cnkgPT0gIkNoaW5hIiwKICAgICAgICAgICBZZWFyID09IDE5ODApCmBgYAoKV2Ugc2VlIHRoYXQgd2UgaGF2ZSB0aHJlZSByb3dzIG9mIGRhdGEuCgpOb3cgd2Ugd2lsbCB1c2UgdGhlIGBmdWxsX2pvaW4oKWAgZnVuY3Rpb24gdHdvIHdheXMuIEZpcnN0IHdlIHdpbGwgY29tYmluZSBieSBgQ291bnRyeWAgYW5kIGBZZWFyYCBhbmQgYExhYmVsYC4gCgpgYGB7cn0KZGF0YV93aWRlX2ZqX2xhYmVsIDwtCiAgbGlzdChDTzJfZW1pc3Npb25zLCBnZHBfZ3Jvd3RoLCBlbmVyZ3lfdXNlKSAlPiUKICByZWR1Y2UoZnVsbF9qb2luLCBieSA9IGMoIkNvdW50cnkiLCAiWWVhciIsICJMYWJlbCIpKQoKZGF0YV93aWRlX2ZqX2xhYmVsICU+JQogIGZpbHRlcihDb3VudHJ5ID09ICJDaGluYSIsIFllYXIgPT0gIjE5ODAiKQpgYGAKCkFnYWluIHdlIGhhdmUgMyByb3dzIG9mIGRhdGEuIFRoZSBkYXRhIHByb2R1Y2VkIGJ5ICBgYmluZF9yb3dzKClgIGFuZCBgZnVsbF9qb2luKClgIGlzIGlkZW50aWNhbCAod2hpY2ggd2UgY2FuIGNoZWNrIGJ5IHVzaW5nIHRoZSBgc2V0ZXF1YWwoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSkgYW5kIGhhcyB0aGUgc2FtZSBkaW1lbnNpb25zICh3aGljaCB3ZSBjYW4gY2hlY2sgYnkgdXNpbmcgdGhlIGBkaW0oKWAgYmFzZSBmdW5jdGlvbikuCgpgYGB7cn0KZGltKGRhdGFfd2lkZV9icikKZGltKGRhdGFfd2lkZV9mal9sYWJlbCkKc2V0ZXF1YWwoZGF0YV93aWRlX2ZqX2xhYmVsLCBkYXRhX3dpZGVfYnIpCmBgYAoKSG93ZXZlciwgbm93IHdlIHdpbGwgam9pbiBieSBvbmx5IGBDb3VudHJ5YCBhbmQgYFllYXJgOgoKYGBge3J9CmRhdGFfd2lkZV9maiA8LQogIGxpc3QoQ08yX2VtaXNzaW9ucywgZ2RwX2dyb3d0aCwgZW5lcmd5X3VzZSkgJT4lCiAgcmVkdWNlKGZ1bGxfam9pbiwgYnkgPSBjKCJDb3VudHJ5IiwgIlllYXIiKSkKCmRhdGFfd2lkZV9maiAlPiUKICBmaWx0ZXIoQ291bnRyeSA9PSAiQ2hpbmEiLCBZZWFyID09ICIxOTgwIikKYGBgCgpOb3cgd2Ugc2VlIHRoYXQgd2UgaGF2ZSBvbmx5IGEgc2luZ2xlIHJvdy4gVGhlIGRhdGEgdGhhdCBjb3JyZXNwb25kcyB0byB0aGUgc2FtZSB5ZWFyIGFuZCBjb3VudHJ5IGhhcyBiZWVuIGNvbGxhcHNlZCBpbnRvIGEgc2luZ2xlIGJ1dCB3aWRlciByb3cuIAoKVGhpcyBpcyBzb21ldGhpbmcgdG8ga2VlcCBpbiBtaW5kIHdoZW4geW91IGFyZSB3cmFuZ2xpbmcgeW91ciBkYXRhLiBUaGUgY2hvaWNlIG9mIHdoYXQgZnVuY3Rpb24gdG8gdXNlIGFuZCBob3cgc2hvdWxkIGRlcGVuZCBvbiBob3cgeW91IHdhbnQgdGhlIGRhdGEgdG8gYmUgYWZ0ZXIgeW91IGNvbWJpbmUgdGhlIGRpZmZlcmVudCBzb3VyY2VzIG9mIGRhdGEgdG9nZXRoZXIuCgo8L2RldGFpbHM+ICAKKioqCgpXZSBoYXZlIGEgZmV3IG1vcmUgdGhpbmdzIHRvIGRvIGJlZm9yZSB3ZSBsZWF2ZSB0aGUgZGF0YSB3cmFuZ2xpbmcgc2VjdGlvbi4gCgpXZSB3aWxsIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYFJlZ2lvbmAgdGhhdCB3aWxsIGluZGljYXRlIGlmIHRoZSBkYXRhIGlzIGFib3V0IHRoZSBVbml0ZWQgU3RhdGVzIG9yIGEgZGlmZmVyZW50IGNvdW50cnkgYmFzZWQgb24gdGhlIHZhbHVlcyBpbiB0aGUgYENvdW50cnlgIHZhcmlhYmxlLiAKVG8gZG8gdGhpcywgd2Ugd2lsbCB1c2UgdGhlIGBjYXNlX3doZW4oKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gCgpGb3IgZXhhbXBsZSwgaWYgdGhlIGBDb3VudHJ5YCB2YXJpYWJsZSBpcyBlcXVhbCB0byBgIlVuaXRlZCBTdGF0ZXMiYCB0aGUgdmFsdWUgZm9yIHRoZSBuZXcgdmFyaWFibGUgd2lsbCBhbHNvIGJlIGAiVW5pdGVkIFN0YXRlcyJgLCB3aGVyZSBhcyBpZiB0aGUgYENvdW50cnlgIHZhcmlhYmxlIGlzIG5vdCBlcXVhbCB0byBgIlVuaXRlZCBTdGF0ZXMiYCBidXQgaXMgc29tZSBvdGhlciBjaGFyYWN0ZXIgc3RyaW5nIHZhbHVlLCBzdWNoIGFzIGAiQWZnaGFuaXN0YW4iYCwgdGhlbiB0aGUgdmFsdWUgZm9yIHRoZSBuZXcgdmFyaWFibGUgd2lsbCBiZSBgIlJlc3Qgb2YgdGhlIFdvcmxkImAuIFdlIGNhbiBzcGVjaWZ5IHRoYXQgc29tZXRoaW5nIGlzIG5vdCBlcXVhbCBieSB1c2luZyB0aGUgYCE9YCBvcGVyYXRvci4KClRoZSBuZXcgdmFsdWVzIGZvciB0aGUgbmV3IHZhcmlhYmxlIGBSZWdpb25gIGFyZSBpbmRpY2F0ZWQgYWZ0ZXIgdGhlIHNwZWNpZmljIGNvbmRpdGlvbmFsIHN0YXRlbWVudHMgYnkgdXNpbmcgdGhlIGB+YCBzeW1ib2wuIAoKCmBgYHtyfQpkYXRhX2xvbmcgJTw+JQogIG11dGF0ZShSZWdpb24gPSBjYXNlX3doZW4oQ291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyIgfiAiVW5pdGVkIFN0YXRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb3VudHJ5ICE9ICJVbml0ZWQgU3RhdGVzIiB+ICJSZXN0IG9mIHRoZSBXb3JsZCIpKQoKZGF0YV9sb25nICAlPiUKICBhcnJhbmdlKENvdW50cnkpICU+JQogIHNsaWNlX2hlYWQobiA9IDYpCmBgYAoKV2UgY2FuIGFsc28gcmVtb3ZlIHJvd3MgZm9yIGNvdW50cmllcyB3aXRoIGBOQWAgdmFsdWVzIHVzaW5nIHRoZSBgZHJvcF9uYSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlIHRvIGRyb3AgYWxsIHllYXJzIHdpdGggbWlzc2luZyBkYXRhLgoKYGBge3J9CmRhdGFfbG9uZ193aXRoX21pc3MgPC0KICBkYXRhX2xvbmcgJT4lCiAgYXJyYW5nZShDb3VudHJ5KQoKZGF0YV9sb25nICU8PiUKICBkcm9wX25hKCkgJT4lCiAgYXJyYW5nZShDb3VudHJ5KQpgYGAKCllvdSBjYW4gc2VlIHRoYXQgYnkgcmVtb3ZpbmcgdGhlIE5BIHZhbHVlcyB0aGUgZGF0YSBmb3IgQWZnaGFuaXN0YW4gc3RhcnRzIGF0IDE5NDkgaW5zdGVhZCBvZiAxNzUxLgoKYGBge3J9CmRhdGFfbG9uZyAlPiUKICBzbGljZV9oZWFkKG4gPSA2KQpgYGAKCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpUYWtpbmcgdGhlIGBkYXRhX2xvbmdgIG9iamVjdCwgYW5kIHVzaW5nIG9ubHkgZGF0YSBmcm9tIHRoZSBVUywgY2FsY3VsYXRlIHRoZSBmaXJzdCBhbmQgbGFzdCB5ZWFyIHRoYXQgYSB2YWx1ZSB3YXMgcmVwb3J0ZWQgZm9yIGVhY2ggTGFiZWwgKGUuZy4gQ08yIGVtaXNzaW9ucywgZW5lcmd5IHVzZSwgZXRjKS4gRG8gbm90IHNhdmUgdGhpcyBkYXRhLCBidXQgc2ltcGx5IHZpZXcgaXQgYnV0IG5vdCByZWFzc2lnbmluZyBgZGF0YV9sb25nYC4gCgo8Yj48dT4gSGludCA8L3U+PC9iPjogVXNlIHRoZSBgZ3JvdXBfYnkoKWAgYW5kIGBzdW1tYXJpemUoKWAgZnVuY3Rpb25zIGluIHRoZSBgZHBseXJgIHBhY2thZ2UuIAoKIyMjIwoKYGBge3IgRFdfQ29kZTctc2V0dXB9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsb2FkKGhlcmU6OmhlcmUoInd3dyIsICJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX2RhdGEucmRhIikpCmBgYAoKYGBge3IgRFdfQ29kZTcsIGV4ZXJjaXNlPVRSVUV9CiMgVHJ5IHRoaXMgb3V0IQpgYGAKCgpgYGB7ciwgRFdfQ29kZTctc29sdXRpb259CmRhdGFfbG9uZyAlPiUKICBmaWx0ZXIoQ291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyIpICU+JQogICAgZ3JvdXBfYnkoTGFiZWwpICU+JSAKICAgIHN1bW1hcml6ZShmaXJzdF9yZXBvcnRlZF95ZWFyID0gbWluKFllYXIpLAogICAgICAgICAgICAgIGxhc3RfcmVwb3J0ZWRfeWVhciA9IG1heChZZWFyKSkKYGBgCgpUbyBhbGxvdyB1c2VycyB0byBza2lwIGltcG9ydCBhbmQgd3JhbmdsaW5nIHdlIHdpbGwgc2F2ZSB0aGUgZGF0YSBhcyBhbiBSREEgZmlsZSBhcyB3ZWxsIGFzIGEgQ1NWIGZpbGUgYXMgdGhpcyBpcyBvZnRlbiB1c2VmdWwgdG8gc2VuZCBvdXIgZGF0YSB0byBjb2xsYWJvcmF0b3JzLiBXZSB3aWxsIHNhdmUgdGhpcyBpbiBhICJ3cmFuZ2xlZCIgc3ViZGlyZWN0b3J5IG9mIG91ciAiZGF0YSIgZGlyZWN0b3J5IG9mIG91ciB3b3JraW5nIGRpcmVjdG9yeS4KCmBgYHtyLCBldmFsID0gRkFMU0V9CnNhdmUoZGF0YV9sb25nLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJ3cmFuZ2xlZF9kYXRhLnJkYSIpKQpyZWFkcjo6d3JpdGVfY3N2KGRhdGFfbG9uZywgcGF0aCA9IGhlcmU6OmhlcmUoImRhdGEiLCJ3cmFuZ2xlZCIsICJ3cmFuZ2xlZF9kYXRhLmNzdiIpKQpgYGAKCiMjICoqRXhlcmNpc2UqKgoqKioKCmBgYHtyIERXX1F1aXosIGVjaG8gPSBGQUxTRX0KcXVpeihjYXB0aW9uID0gIiIsCiAgcXVlc3Rpb24oIldoaWNoIG9uZSBvZiB0aGUgZm9sbG93aW5nIGZ1bmN0aW9ucyBpbiB0aGUgYGRwbHlyYCBwYWNrYWdlIGFsbG93cyB1cyB0byBzZWUgYWxsIG9mIHRoZSB2YXJpYWJsZXMgKGNvbHVtbnMpIGF0IG9uY2UsIHdoZXJlIHNldmVyYWwgdmFsdWVzIG9mIHRob3NlIGNvbHVtbnMgYXJlIHNob3duIG9uIHRoZSByaWdodCBvZiB0aGUgdmFyaWFibGUgbmFtZXM/IiwKICAgIGFuc3dlcigiYHNsaWNlX2hlYWQoKWAiLCBtZXNzYWdlID0gIlRoaXMgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIHNlZSBqdXN0IHRoZSBmaXJzdCByb3dzIG9mIHRoZSBkYXRhLiIpLAogICAgYW5zd2VyKCJgc2xpY2Vfc2FtcGxlKClgIiwgbWVzc2FnZSA9ICJUaGlzIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBzZWUgYSBzZWxlY3Rpb24gb2YgcmFuZG9tIHJvd3Mgb2YgdGhlIGRhdGEuIiksCiAgICBhbnN3ZXIoImBzbGljZV90YWlsKClgIiwgbWVzc2FnZSA9ICJUaGlzIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBzZWUgdGhlIHJvd3MgYXQgdGhlIGVuZCBvZiB0aGUgZGF0YS4iKSwKICAgIGFuc3dlcigiYGdsaW1wc2UoKWAiLCBjb3JyZWN0ID0gVFJVRSksCiAgICBhbGxvd19yZXRyeSA9IFRSVUUsCiAgICByYW5kb21fYW5zd2VyX29yZGVyID0gVFJVRQogICksCiAgcXVlc3Rpb24oIldoaWNoIG9uZSBvZiB0aGUgcGlwZSBvcGVyYXRvcnMgKGZyb20gdGhlIGBtYWdyaXR0cmAgcGFja2FnZSkgc2hvdWxkIGJlIHVzZWQgcmlnaHQgYWZ0ZXIgYSB2YXJpYWJsZSBuYW1lIGlmIHdlIHdhbnQgdG8gcGVyZm9ybSBhIHNlcXVlbmNlIG9mIG9wZXJhdGlvbnMgb24gdGhhdCB2YXJpYWJsZSwgYW5kIG1lYW53aGlsZSwgYXNzaWduIHRoZSBmaW5hbCBvdXRwdXQgdG8gdGhhdCB2YXJpYWJsZSAod2l0aG91dCByZWRlZmluaW5nIHRoYXQgdmFyaWFibGUgdXNpbmcgYDwtYCBvciBgPWApPyIsCiAgICBhbnN3ZXIoImAlPiVgIiwgbWVzc2FnZSA9ICJUaGlzIG9wZXJhdG9yIGNhbm5vdCBhc3NpZ24gdGhlIGZpbmFsIG91dHB1dCB0byB0aGF0IHZhcmlhYmxlLiIpLAogICAgYW5zd2VyKCJgJTwlYCIsIG1lc3NhZ2UgPSAiVGhpcyBpcyBub3QgYSB2YWxpZSBwaXBlIG9wZXJhdG9yLiIpLAogICAgYW5zd2VyKCJgJVQ+JWAiLCBtZXNzYWdlID0gIlRoaXMgaXMgdGhlIHNpZGUtZWZmZWN0cyBvcGVyYXRvci4iKSwKICAgIGFuc3dlcigiYCU8PiVgIiwgY29ycmVjdCA9IFRSVUUpLAogICAgYWxsb3dfcmV0cnkgPSBUUlVFLAogICAgcmFuZG9tX2Fuc3dlcl9vcmRlciA9IFRSVUUKICApLAogIHF1ZXN0aW9uKCJXaGljaCBvZiB0aGUgZm9sbG93aW5nIGRvZXMgdGhlIGBtdXRhdGUoKWAgZnVuY3Rpb24gaW4gdGhlIGBkcGx5cmAgcGFja2FnZSBoZWxwIHVzIGRvPyAobW9yZSB0aGFuIG9uZSBjb3JyZWN0IGFuc3dlcikiLAogICAgYW5zd2VyKCJTZWxlY3QgY2VydGFpbiB2YXJpYWJsZXMoY29sdW1ucykgb2YgdGhlIGRhdGEuIiwgbWVzc2FnZSA9ICJTZWxlY3RpbmcgY2VydGFpbiB2YXJpYWJsZXMoY29sdW1ucykgb2YgdGhlIGRhdGEgaXMgdGhlIGZ1bmN0aW9uIG9mIHRoZSBgc2VsZWN0KClgIGZ1bmN0aW9uLiIpLAogICAgYW5zd2VyKCJSZW5hbWUgYSB2YXJpYWJsZS4iLCBtZXNzYWdlID0gIldoaWxlIHdlIGNvdWxkIHVzZSBgbXV0YXRlYCB0byByZW5hbWUgYSB2YXJpYWJsZSB1c2luZyBtdWx0aXBsZSBzdGVwcyAoY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGJhc2VkIG9uIHRoZSBhbiBleGlzdGluZyB2YXJpYWJsZSBhbmQgdGhlbiByZW1vdmUgdGhlIG9sZCB2YXJpYWJsZSksIHJlbmFtaW5nIGEgdmFyaWFibGUgaXMgbW9yZSBlZmZpY2llbnQgd2l0aCB0aGUgYHJlbmFtZSgpYCBmdW5jdGlvbi4iKSwKICAgIGFuc3dlcigiQ3JlYXRlIGEgbmV3IHZhcmlhYmxlLiIsIGNvcnJlY3QgPSBUUlVFKSwKICAgIGFuc3dlcigiTW9kaWZ5IGFuIGV4aXN0aW5nIHZhcmlhYmxlLiIsIGNvcnJlY3QgPSBUUlVFKSwKICAgIGFsbG93X3JldHJ5ID0gVFJVRSwKICAgIHJhbmRvbV9hbnN3ZXJfb3JkZXIgPSBUUlVFCiAgKQopCmBgYAoKIyMjIyB7LmV4ZXJjaXNlX2Jsb2NrfQoKV2UgaGF2ZSBjcmVhdGVkIGEgZGF0YXNldCBjYWxsZWQgYHdpZGVfZm9ybWF0YCB0aGF0IGlzIGluICJ3aWRlIiBmb3JtYXQuIFdyaXRlIHNvbWUgY29kZSB0byBjb252ZXJ0IGl0IHRvICJsb25nIiBmb3JtYXQuIChXZSB3YW50IDMgY29sdW1ucyB3aXRoIG5hbWVzICJJRCIsICJWYXJpYWJsZSIsIGFuZCAiVmFsdWUiLikKCmBgYHtyIERXX0V4ZXJjaXNlMS1zZXR1cH0KSUQgPC0gYygxLCAyLCAzKQpZZWFyIDwtIGMoMjAxNSwgMjAxOCwgMjAxOSkKTGVuZ3RoIDwtIGMoMjAsIDIxLjUsIDE5KQp3aWRlX2Zvcm1hdCA8LSBkYXRhLmZyYW1lKElELCBZZWFyLCBMZW5ndGgpCmBgYAoKYGBge3IgRFdfRXhlcmNpc2UxLCBleGVyY2lzZT1UUlVFLCBleGVyY2lzZS5ldmFsPVRSVUUsIGV4ZXJjaXNlLmxpbmVzID0gNX0Kd2lkZV9mb3JtYXQKYGBgCgpgYGB7ciBEV19FeGVyY2lzZTEtaGludH0Kd2lkZV9mb3JtYXQgJT4lCiAgcGl2b3RfbG9uZ2VyKCkKYGBgCgpgYGB7ciBEV19FeGVyY2lzZTEtc29sdXRpb259CndpZGVfZm9ybWF0ICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLUlELCBuYW1lc190byA9ICJWYXJpYWJsZSIsIHZhbHVlc190byA9ICJWYWx1ZSIpCmBgYAoKIyMjIwoKPHA+Jm5ic3A7PC9wPgoKIyMjIyB7LmV4ZXJjaXNlX2Jsb2NrfQoKYG10Y2Fyc2AgaXMgYSBidWlsdC1pbiBSIGRhdGFzZXQgYXMgc2hvd24gYmVsb3cuIFVzZSB0aGlzIGRhdGFzZXQgdG8gY29tcGxldGUgdGhlIGZvbGxvd2luZyBleGVyY2lzZS4KCmBgYHtyfQptdGNhcnMKYGBgCgpXcml0ZSBzb21lIGNvZGUgdGhhdCB3aWxsOgoKMS4gQ3JlYXRlIGEgbmV3IGRhdGFzZXQgY2FsbGVkIGBuZXcubXRjYXJzYCBmcm9tIGBtdGNhcnNgLgoyLiBDcmVhdGUgYSBuZXcgY29sdW1uIGNhbGxlZCBgY2FyYCBpbiBgbmV3Lm10Y2Fyc2AgdGhhdCB1c2VzIHRoZSB2YWx1ZXMgZnJvbSB0aGUgcm93IG5hbWVzIG9mIGBtdGNhcnNgLiAoVXNlIHRoZSBgcm93bmFtZXNfdG9fY29sdW1uYCBmdW5jdGlvbiBmcm9tIHRoZSBgdGliYmxlYCBwYWNrYWdlLiBTZWUgZG9jdW1lbnRhdGlvbiBbaGVyZV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2Uvcm93bmFtZXMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4pCjMuIE9ubHkga2VlcCB0aGUgYGNhcmAsIGBtcGdgLCBhbmQgYGN5bGAgY29sdW1ucyBvZiB0aGlzIGBuZXcubXRjYXJzYCBkYXRhc2V0Lgo0LiBPbmx5IGtlZXAgdGhlIGNhcnMgdGhhdCBoYXZlIGBjeWxgID0gNC4KNS4gUmVhcnJhbmdlIHRoZSBkYXRhc2V0IGJ5IGBtcGdgIGluIGRlc2NlbmRpbmcgb3JkZXIuCjYuIENoZWNrIHlvdXIgZGF0YSBieSBsb29raW5nIGF0IHRoZSBmdWxsIGBuZXcubXRjYXJzYCBvYmplY3QuCgoqTm90ZTogcmVwbGFjZSB0aGUgdW5kZXJzY29yZXMoIlxfIikgd2l0aCB5b3VyIGNvZGUgd2l0aCBvbmUgY2hhcmFjdGVyIHBlciAiXF8iLiBDbGljayAiU3VibWl0IEFuc3dlciIgdG8gY2hlY2sgeW91ciBhbnN3ZXIuICoKCmBgYHtyIERXX0V4ZXJjaXNlMi1zZXR1cH0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKYGBge3IgRFdfRXhlcmNpc2UyLCBleGVyY2lzZT1UUlVFLCBldmFsPUZBTFNFfQojIHN0ZXAgMQpuZXcubXRjYXJzIDwtIG10Y2FycyAlPiUKICAjIHN0ZXAgMgogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiX19fIikgJT4lCiAgIyBzdGVwIDMKICBfX19fX18oX19fLCBfX18sIF9fXykgJT4lCiAgIyBzdGVwIDQKICBfX19fX18oX19fID09IF8pICU+JQogICMgc3RlcCA1CiAgX19fX19fXyhfX19fKG1wZykpCgpuZXcubXRjYXJzCmBgYAoKYGBge3IgRFdfRXhlcmNpc2UyLWhpbnQtMX0KIyBzdGVwIDI6CiMgVGhlICJ2YXIiIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uIHRoYXQgd2lsbCB1c2UgdGhlIHZhbHVlcyBmcm9tIHRoZSByb3cgbmFtZXMuIFdoYXQgaXMgdGhlIGNvbHVtbiBuYW1lPwpgYGAKCmBgYHtyIERXX0V4ZXJjaXNlMi1oaW50LTJ9CiMgc3RlcCAyOgojIFRoZSAidmFyIiBhcmd1bWVudCBpcyB0aGUgbmFtZSBvZiB0aGUgbmV3IGNvbHVtbiB0aGF0IHdpbGwgdXNlIHRoZSB2YWx1ZXMgZnJvbSB0aGUgcm93IG5hbWVzLiBXaGF0IGlzIHRoZSBjb2x1bW4gbmFtZT8KCiMgc3RlcCAzOgojIFdoaWNoIGZ1bmN0aW9uIG9mIHRoZSAiZHBseXIiIHBhY2thZ2Ugc2VsZWN0IGNvbHVtbnM/CmBgYAoKYGBge3IgRFdfRXhlcmNpc2UyLWhpbnQtM30KIyBzdGVwIDI6CiMgVGhlICJ2YXIiIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uIHRoYXQgd2lsbCB1c2UgdGhlIHZhbHVlcyBmcm9tIHRoZSByb3cgbmFtZXMuIFdoYXQgaXMgdGhlIGNvbHVtbiBuYW1lPwoKIyBzdGVwIDM6CiMgV2hpY2ggZnVuY3Rpb24gb2YgdGhlICJkcGx5ciIgcGFja2FnZSBzZWxlY3QgY29sdW1ucz8KCiMgc3RlcCA0OgojIFdoaWNoIGZ1bmN0aW9uIG9mIHRoZSAiZHBseXIiIHBhY2thZ2Ugc3Vic2V0IHJvd3M/CmBgYAoKYGBge3IgRFdfRXhlcmNpc2UyLWhpbnQtNH0KIyBzdGVwIDI6CiMgVGhlICJ2YXIiIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uIHRoYXQgd2lsbCB1c2UgdGhlIHZhbHVlcyBmcm9tIHRoZSByb3cgbmFtZXMuIFdoYXQgaXMgdGhlIGNvbHVtbiBuYW1lPwoKIyBzdGVwIDM6CiMgV2hpY2ggZnVuY3Rpb24gb2YgdGhlICJkcGx5ciIgcGFja2FnZSBzZWxlY3QgY29sdW1ucz8KCiMgc3RlcCA0OgojIFdoaWNoIGZ1bmN0aW9uIG9mIHRoZSAiZHBseXIiIHBhY2thZ2Ugc3Vic2V0IHJvd3M/CgojIHN0ZXAgNToKIyBXaGljaCBmdW5jdGlvbiBvZiB0aGUgImRwbHlyIiBwYWNrYWdlIHdpbGwgcmVvcmRlciB0aGUgZGF0YT8KIyBXaGF0IGFyZ3VtZW50IGRvIHdlIG5lZWQgdG8gcmVvcmRlciBpbiBkZXNjZW5kaW5nIG9yZGVyPwpgYGAKCmBgYHtyIERXX0V4ZXJjaXNlMi1oaW50LTV9CiMgTmV4dCBoaW50IHdpbGwgc2hvdyB5b3UgdGhlIHNvbHV0aW9uCmBgYAoKYGBge3IgRFdfRXhlcmNpc2UyLXNvbHV0aW9ufQpuZXcubXRjYXJzIDwtIG10Y2FycyAlPiUKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNhciIpICU+JQogIHNlbGVjdChjYXIsIG1wZywgY3lsKSAlPiUKICBmaWx0ZXIoY3lsID09IDQpICU+JQogIGFycmFuZ2UoZGVzYyhtcGcpKQoKbmV3Lm10Y2FycwpgYGAKCmBgYHtyIERXX0V4ZXJjaXNlMi1jaGVjaywgZXZhbD1GQUxTRX0KZ3JhZGVfY29kZSgpCmBgYAoKIyMjIwoKIyAqKkRhdGEgVmlzdWFsaXphdGlvbioqCioqKiAKCklmIHlvdSBoYXZlIGJlZW4gZm9sbG93aW5nIGFsb25nIGJ1dCBzdG9wcGVkLCB3ZSBjb3VsZCBsb2FkIG91ciBpbXBvcnRlZCBkYXRhIGxpa2Ugc286CgpgYGB7ciwgZXZhbD1GQUxTRX0KbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX2RhdGEucmRhIikpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CmxvYWQoInd3dy9kYXRhL3dyYW5nbGVkL3dyYW5nbGVkX2RhdGEucmRhIikKYGBgCgoqKioKPGRldGFpbHM+IDxzdW1tYXJ5PiBJZiB5b3Ugc2tpcHBlZCB0aGUgZGF0YSB3cmFuZ2xpbmcgc2VjdGlvbiBjbGljayBoZXJlLiA8L3N1bW1hcnk+CgpBbiBSREEgZmlsZSAoc3RhbmRzIGZvciBSIGRhdGEpIG9mIHRoZSBkYXRhIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tLy9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLWNvMi1lbWlzc2lvbnMvdHJlZS9tYXN0ZXIvZGF0YS93cmFuZ2xlZCkgb3Igc2xpZ2h0bHkgbW9yZSBkaXJlY3RseSBbaGVyZV0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtY28yLWVtaXNzaW9ucy9tYXN0ZXIvZGF0YS93cmFuZ2xlZC93cmFuZ2xlZF9kYXRhLnJkYSkuIERvd25sb2FkIHRoaXMgZmlsZSBhbmQgdGhlbiBwbGFjZSBpdCBpbiB5b3VyIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnkgd2l0aGluIGEgc3ViZGlyZWN0b3J5IGNhbGxlZCAid3JhbmdsZWQiIHdpdGhpbiBhIHN1YmRpcmVjdG9yeSBjYWxsZWQgImRhdGEiIHRvIGNvcHkgYW5kIHBhc3RlIG91ciBjb2RlLiBXZSB1c2VkIGFuIFJTdHVkaW8gcHJvamVjdCBhbmQgdGhlIFtgaGVyZWAgcGFja2FnZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSB0byBuYXZpZ2F0ZSB0byB0aGUgZmlsZSBtb3JlIGVhc2lseS4KCmBgYHtyLCBldmFsPUZBTFNFfQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWQiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkKYGBgCgoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgbW9yZSBhYm91dCBjcmVhdGluZyBuZXcgcHJvamVjdHMgaW4gUlN0dWRpby4gPC9zdW1tYXJ5PgoKWW91IGNhbiBjcmVhdGUgYSBwcm9qZWN0IGJ5IGdvaW5nIHRvIHRoZSBGaWxlIG1lbnUgb2YgUlN0dWRpbyBsaWtlIHNvOgoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInd3dy9pbWcvTmV3X3Byb2plY3QucG5nIikKYGBgCgpZb3UgY2FuIGFsc28gZG8gc28gYnkgY2xpY2tpbmcgdGhlIHByb2plY3QgYnV0dG9uOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygid3d3L2ltZy9wcm9qZWN0X2J1dHRvbi5wbmciKQpgYGAKClNlZSBbaGVyZV0oaHR0cHM6Ly9zdXBwb3J0LnJzdHVkaW8uY29tL2hjL2VuLXVzL2FydGljbGVzLzIwMDUyNjIwNy1Vc2luZy1Qcm9qZWN0cykgdG8gbGVhcm4gbW9yZSBhYm91dCB1c2luZyBSU3R1ZGlvIHByb2plY3RzIGFuZCBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKSB0byBsZWFybiBtb3JlIGFib3V0IHRoZSBgaGVyZWAgcGFja2FnZS4KCjwvZGV0YWlscz4KKioqCjwvZGV0YWlscz4KKioqCgpOb3cgd2Ugd2lsbCBjcmVhdGUgc29tZSBzaW1wbGUgcGxvdHMgdG8gZXhhbWluZSB0aGUgQ08yIGVtaXNzaW9ucyBvdmVyIHRpbWUgdXNpbmcgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLgoKQXMgeW91IG1heSBoYXZlIGFscmVhZHkgc2VlbiwgdGhlcmUgYXJlIG1hbnkgZnVuY3Rpb25zIGF2YWlsYWJsZSBpbiBiYXNlIFIgdGhhdCBjYW4gY3JlYXRlIHBsb3RzIChlLmcuIGBwbG90KClgLCBgYm94cGxvdCgpYCkuIApPdGhlcnMgaW5jbHVkZTogYGhpc3QoKWAsIGBxcXBsb3QoKWAsIGV0Yy4gClRoZXNlIGZ1bmN0aW9ucyBhcmUgZ3JlYXQgYmVjYXVzZSB0aGV5IGNvbWUgd2l0aCBhIGJhc2ljIGluc3RhbGxhdGlvbiBvZiBSIGFuZCBjYW4gYmUgcXVpdGUgcG93ZXJmdWwgd2hlbiB5b3UgbmVlZCBhIHF1aWNrIHZpc3VhbGl6YXRpb24gb2Ygc29tZXRoaW5nIHdoZW4geW91IGFyZSBleHBsb3JpbmcgZGF0YS4gCgpXZSBhcmUgY2hvb3NpbmcgdG8gaW50cm9kdWNlIGBnZ3Bsb3QyYCBiZWNhdXNlLCBpbiBvdXIgb3BpbmlvbiwgaXQgaXMgb25lIG9mIHRoZSBzaW1wbGVzdCB3YXlzIGZvciBiZWdpbm5lcnMgdG8gY3JlYXRlIHJlbGF0aXZlbHkgY29tcGxpY2F0ZWQgcGxvdHMgdGhhdCBhcmUgaW50dWl0aXZlIGFuZCBhZXN0aGV0aWNhbGx5IHBsZWFzaW5nLiAKCiMjICoqVGhlIGBnZ3Bsb3QyYCBSIHBhY2thZ2UqKgoqKioKClRoZSByZWFzb25zIFtgZ2dwbG90MmBdKGh0dHA6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcpIGlzIGdlbmVyYWxseSBpbnR1aXRpdmUgZm9yIGJlZ2lubmVycyBpcyB0aGUgdXNlIG9mIFtncmFtbWFyIG9mIGdyYXBoaWNzXShodHRwOi8vdml0YS5oYWQuY28ubnovcGFwZXJzL2xheWVyZWQtZ3JhbW1hci5odG1sKSBvciB0aGUgYGdnYCBpbiBgZ2dwbG90MmAuIApUaGUgaWRlYSBpcyB0aGF0IHlvdSBjYW4gY29uc3RydWN0IG1hbnkgc2VudGVuY2VzIGJ5IGxlYXJuaW5nIGp1c3QgYSBmZXcgbm91bnMsIGFkamVjdGl2ZXMsIGFuZCB2ZXJicy4gClRoZXJlIGFyZSBzcGVjaWZpYyAid29yZHMiIHRoYXQgd2Ugd2lsbCBpbnRyb2R1Y2UsIGFuZCBvbmNlIHlvdSBhcmUgY29tZm9ydGFibGUgd2l0aCB0aGVtLCB5b3Ugd2lsbCBiZSBhYmxlIHRvIGNyZWF0ZSAob3IgIndyaXRlIikgaHVuZHJlZHMgb2YgZGlmZmVyZW50IHBsb3RzLiAKClRoZSBjcml0aWNhbCBwYXJ0IHRvIG1ha2luZyBncmFwaGljcyB1c2luZyBgZ2dwbG90MmAgaXMgdGhlIGRhdGEgbmVlZHMgdG8gYmUgaW4gYSBfdGlkeV8gZm9ybWF0LiAKR2l2ZW4gdGhhdCB3ZSBoYXZlIGp1c3Qgc3BlbnQgdGltZSBwdXR0aW5nIG91ciBkYXRhIGluIF90aWR5XyBmb3JtYXQsIHdlIGFyZSBwcmltZWQgdG8gdGFrZSBhZHZhbnRhZ2Ugb2YgYWxsIHRoYXQgYGdncGxvdDJgIGhhcyB0byBvZmZlciEgCgpXZSB3aWxsIHNob3cgaG93IGl0IGlzIGVhc3kgdG8gcGlwZSBfdGlkeV8gZGF0YSAob3V0cHV0KSBhcyBpbnB1dCB0byBvdGhlciBmdW5jdGlvbnMgdGhhdCBjcmVhdGUgcGxvdHMuIApUaGlzIGFsbCB3b3JrcyBiZWNhdXNlIHdlIGFyZSB3b3JraW5nIAp3aXRoaW4gdGhlIF90aWR5dmVyc2VfLiAKCiMjIyMgV2hhdCBpcyB0aGUgYGdncGxvdCgpYCBmdW5jdGlvbj8gCgpBcyBleHBsYWluZWQgYnkgSGFkbGV5IFdpY2toYW06IAoKPiB0aGUgZ3JhbW1hciB0ZWxscyB1cyB0aGF0IGEgc3RhdGlzdGljYWwgZ3JhcGhpYyBpcyBhIG1hcHBpbmcgZnJvbSBkYXRhIHRvIGFlc3RoZXRpYyBhdHRyaWJ1dGVzIChjb2xvdXIsIHNoYXBlLCBzaXplKSBvZiBnZW9tZXRyaWMgb2JqZWN0cyAocG9pbnRzLCBsaW5lcywgYmFycykuIFRoZSBwbG90IG1heSBhbHNvIGNvbnRhaW4gc3RhdGlzdGljYWwgdHJhbnNmb3JtYXRpb25zIG9mIHRoZSBkYXRhIGFuZCBpcyBkcmF3biBvbiBhIHNwZWNpZmljIGNvb3JkaW5hdGVzIHN5c3RlbS4KCiMjIyMgYGdncGxvdDJgIFRlcm1pbm9sb2d5IAoKKiAqKmdncGxvdCoqIC0gdGhlIG1haW4gZnVuY3Rpb24gd2hlcmUgeW91IHNwZWNpZnkgdGhlIGRhdGFzZXQgYW5kIHZhcmlhYmxlcyB0byBwbG90ICh0aGlzIGlzIHdoZXJlIHdlIGRlZmluZSB0aGUgYHhgIGFuZApgeWAgdmFyaWFibGUgbmFtZXMpCiogKipnZW9tcyoqIC0gZ2VvbWV0cmljIG9iamVjdHMKICAgICogZS5nLiBgZ2VvbV9wb2ludCgpYCwgYGdlb21fYmFyKClgLCBgZ2VvbV9saW5lKClgLCBgZ2VvbV9oaXN0b2dyYW0oKWAKKiAqKmFlcyoqIC0gYWVzdGhldGljcwogICAgKiBzaGFwZSwgdHJhbnNwYXJlbmN5LCBjb2xvciwgZmlsbCwgbGluZSB0eXBlcwoqICoqc2NhbGVzKiogLSBkZWZpbmUgaG93IHlvdXIgZGF0YSB3aWxsIGJlIHBsb3R0ZWQKICAgICogY29udGludW91cywgZGlzY3JldGUsIGxvZywgZXRjCgpUaGUgZnVuY3Rpb24gYGFlcygpYCBpcyBhbiBhZXN0aGV0aWMgbWFwcGluZyBmdW5jdGlvbiBpbnNpZGUgdGhlIGBnZ3Bsb3QoKWAgb2JqZWN0LiAKV2UgdXNlIHRoaXMgZnVuY3Rpb24gdG8gc3BlY2lmeSBwbG90IGF0dHJpYnV0ZXMgKGUuZy4gYHhgIGFuZCBgeWAgdmFyaWFibGUgbmFtZXMpIHRoYXQgd2lsbCBub3QgY2hhbmdlIGFzIHdlIGFkZCBtb3JlIGxheWVycy4gIAoKQW55dGhpbmcgdGhhdCBnb2VzIGluIHRoZSBgZ2dwbG90KClgIG9iamVjdCBiZWNvbWVzIGEgZ2xvYmFsIHNldHRpbmcuIApGcm9tIHRoZXJlLCB3ZSB1c2UgdGhlIGBnZW9tYCBvYmplY3RzIHRvIGFkZCBtb3JlIGxheWVycyB0byB0aGUgYmFzZSBgZ2dwbG90KClgIG9iamVjdC4gClRoZXNlIHdpbGwgZGVmaW5lIHdoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gaWxsdXN0cmF0aW5nIHVzaW5nIHRoZSBkYXRhLiAgCgojIyAqKkNPMiBFbWlzc2lvbnMqKgoKTGV0J3Mgc3RhcnQgYnkgcGxvdHRpbmcgdGhlIENPMiBlbWlzc2lvbnMgb3ZlciB0aW1lLiAKQmVjYXVzZSBvdXIgZGF0YXNldCBjb250YWlucyBvdGhlciB2YXJpYWJsZXMsIHdlIGZpcnN0IG5lZWQgdG8gZmlsdGVyIG91ciBkYXRhIHRvIG9ubHkgaW5jbHVkZSB0aGUgQ08yIGVtaXNzaW9ucyBkYXRhIGJ5IHVzaW5nIHRoZSBgZmlsdGVyKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIApUbyB1c2UgdGhpcyBmdW5jdGlvbiB3ZSBuZWVkIHRvIHNwZWNpZnkgd2hhdCB2YWx1ZSAoZS5nLiBgRW1pc3Npb25zYCkgd2Ugd2FudCBmb3IgYSBnaXZlbiB2YXJpYWJsZSBvciBjb2x1bW4gKGUuZy4gYEluZGljYXRvcmApLiAgCgpJbiB0aGlzIGNhc2UsIHdlIGZpbHRlciB0byBrZWVwIGFsbCByb3dzIHdoZXJlIHRoZSBgSW5kaWNhdG9yYCB2YXJpYWJsZSBpcyBlcXVhbCB0byB0aGUgd29yZCBgRW1pc3Npb25zYC4gCk5vdGljZSB0aGF0IHRoaXMgbmVlZHMgdG8gYmUgaW4gcXVvdGVzLCB3aGlsZSB0aGUgdmFyaWFibGUgbmFtZSBkb2VzIG5vdC4KCmBgYHtyfQpkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKEluZGljYXRvciA9PSAiRW1pc3Npb25zIikKYGBgCgpXZSBhbHNvIG5lZWQgdG8gc3VtIHRoZSBlbWlzc2lvbnMgYWNyb3NzIGNvdW50cmllcyBmb3IgZWFjaCB5ZWFyLiAKSGVyZSwgd2UgdXNlIHRoZSBgZ3JvdXBfYnkoKWAgYW5kIGBzdW1tYXJpemUoKWAgZnVuY3Rpb24gdGhhdCB3ZSBwcmV2aW91c2x5IGxlYXJuZWQgYWJvdXQuIAoKYGBge3J9CmRhdGFfbG9uZyAlPiUKICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiKSAlPiUKICBncm91cF9ieShZZWFyKSAlPiUKICBzdW1tYXJpemUoRW1pc3Npb25zID0gc3VtKFZhbHVlKSkKYGBgCgpUaGVuLCB3ZSB1c2UgdGhlIGBhZXMoKWAgYXJndW1lbnQgb2YgdGhlIGBnZ3Bsb3QoKWAgZnVuY3Rpb24gdG8gZGVmaW5lIHRoYXQgb3VyIHgtYXhpcyB3aWxsIGJlIHRoZSBgWWVhcmAgdmFyaWFibGUsIHRoZSB5LWF4aXMgd2lsbCBiZSB0aGUgZW1pc3Npb24gYFZhbHVlYCB2YXJpYWJsZSwgYW5kIHRoYXQgb3VyIGRhdGEgc2hvdWxkIGJlIGdyb3VwZWQgb3Igc2VwYXJhdGVkIGJ5IHRoZSBgQ291bnRyeWAgdmFyaWFibGUuIAoKYGBge3J9CmRhdGFfbG9uZyAlPiUKICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiKSAlPiUKICBncm91cF9ieShZZWFyKSAlPiUKICBzdW1tYXJpemUoRW1pc3Npb25zID0gc3VtKFZhbHVlKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IEVtaXNzaW9ucykpCmBgYAoKTG9va3MgbGlrZSB3ZSBnb3QgYSBibGFuayBwbG90LiAKV2hhdCBoYXBwZW5lZD8gCldlIG5lZWQgdG8gdGVsbCBSIHdoYXQgX3R5cGUgb2YgcGxvdF8gd2Ugd2FudC4gClRvIGRvIHRoYXQsIHdlIG5lZWQgdG8gYWRkIGFub3RoZXIgbGF5ZXIgdG8gZGVmaW5lIGhvdyB3ZSB3YW50IHRoZSBwbG90IHRvIGxvb2suIApXZSBkbyBzbyBieSB1c2luZyB0aGUgYCtgIHNpZ24gaW4gYmV0d2VlbiBlYWNoIGNvbW1hbmQuIAoKIyMjIExpbmUgcGxvdHMKClRvIHRlbGwgUiB3aGF0IHR5cGUgb2YgcGxvdCB3ZSB3YW50LCB3ZSBuZWVkIHRvIGFkZCBhbm90aGVyIF9sYXllcl8gdG8gb3VyIGdncGxvdCBvYmplY3QuIApUbyBhZGQgYSB0eXBlIG9mIHBsb3QsIHdlIGNhbiB1c2Ugb25lIG9mIHRoZSBtYW55IGBnZW9tXypgIGZ1bmN0aW9ucyBpbiBgZ2dwbG90MmAuCkZvciBleGFtcGxlLCB0eXBlIGBnZW9tYCBpbnRvIHRoZSBSU3R1ZGlvIGNvbnNvbGUgYW5kIHlvdSB3aWxsIHNlZSBtYW55IG9wdGlvbnMgdG8gc2Nyb2xsIHRocm91Z2guCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInd3dy9pbWcvZ2VvbV8ucG5nIikKYGBgCgpIZXJlLCB3ZSB3aWxsIHVzZSB0aGUgYGdlb21fbGluZSgpYCBmdW5jdGlvbiBiZWNhdXNlIHdlIHdvdWxkIGxpa2UgdG8gY3JlYXRlIGEgbGluZSBwbG90LgpXZSBhbHNvIHVzZSB0aGUgYHNpemVgIGFyZ3VtZW50IGluIGBnZW9tX2xpbmUoKWAgdG8gY29udHJvbCB0aGUgc2l6ZSBvZiB0aGUgbGluZS4gCgpgYGB7cn0KZGF0YV9sb25nICU+JQogIGZpbHRlcihJbmRpY2F0b3IgPT0gIkVtaXNzaW9ucyIpICU+JQogIGdyb3VwX2J5KFllYXIpICU+JQogIHN1bW1hcml6ZShFbWlzc2lvbnMgPSBzdW0oVmFsdWUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gRW1pc3Npb25zKSkgKwogICAgZ2VvbV9saW5lKHNpemUgPSAxLjUpCmBgYApXb3csIHRoZSBDTzIgaXMgcmVhbGx5IHJpc2luZyBzaGFycGx5IQoKRmluYWxseSwgbGV0J3MgbWFrZSB0aGlzIHBsb3QgcmVhbGx5IG5pY2UgYnkgYWRkaW5nIGEgZmV3IGZpbmFsIHRvdWNoZXMuIApUbyBjaGFuZ2UgdGl0bGUsIGNhcHRpb24sIGFuZCB0aGUgYXhpcyBsYWJlbHMsIHdlIGNhbiB1c2UgdGhlIGBsYWJzKClgIGZ1bmN0aW9uLiAKQWdhaW4sIG5vdGljZSB0aGF0IGEgcGx1cyBzaWduIGlzIHVzZWQgYmV0d2VlbiBlYWNoIGxheWVyIHRoYXQgd2UgYWRkIHRvIHRoZSBwbG90LiAKVG8gbWFrZSBDTzIgYXBwZWFyIHdpdGggYSBzdWJzY3JpcHQgd2UgY2FuIHVzZSBgfkNPWzJdfmAuICAKCmBgYHtyfQpkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKEluZGljYXRvciA9PSAiRW1pc3Npb25zIikgJT4lCiAgZ3JvdXBfYnkoWWVhcikgJT4lCiAgc3VtbWFyaXplKEVtaXNzaW9ucyA9IHN1bShWYWx1ZSkpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBFbWlzc2lvbnMpKSArCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEuNSkgKwogICAgbGFicyh0aXRsZSA9ICJXb3JsZCAiIH5DT1syXX4gIiBFbWlzc2lvbnMgcGVyIFllYXIgKDE3NTEtMjAxNCkiLAogICAgICAgICBjYXB0aW9uID0gIkxpbWl0ZWQgdG8gcmVwb3J0aW5nIGNvdW50cmllcyIsCiAgICAgICAgIHkgPSAiRW1pc3Npb25zIChNZXRyaWMgVG9ubmVzKSIpCmBgYAoKTmV4dCwgd2UgdXNlIHRoZSBgdGhlbWUoKWAgZnVuY3Rpb24gdG8gY2hhbmdlIHRoZSBmb250IHNpemUgb2YgdGhlIHgtYXhpcywgeS1heGlzLCBheGlzIHRpdGxlcywgYW5kIHRoZSBjYXB0aW9uIGFzIHNob3duIGJlbG93LiAKVG8ga25vdyB3aGF0IHRvIGNhbGwgZWFjaCBlbGVtZW50IG9mIHRoZSBwbG90IGluIHRoaXMgZnVuY3Rpb24gdG8gY2hhbmdlIHRoZSBzaXplIHR5cGUgYD90aGVtZSgpYCBpbiB0aGUgY29uc29sZS4gCgpZb3Ugd2lsbCBzZWUgYSB2ZXJ5IGxhcmdlIGxpc3QgdGhhdCBpbmNsdWRlcyBvdGhlciBwbG90IGFzcGVjdHMgbGlrZSB0aGUgYmFja2dyb3VuZCBhbmQgdGhlIGxlZ2VuZC4gClRoaXMgZnVuY3Rpb24gY2FuIGJlIHVzZWQgdG8gbW9kaWZ5IHlvdXIgcGxvdCB0byB5b3VyIHNwZWNpZmljYXRpb25zLiAKCmBgYHtyfQpkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKEluZGljYXRvciA9PSAiRW1pc3Npb25zIikgJT4lCiAgZ3JvdXBfYnkoWWVhcikgJT4lCiAgc3VtbWFyaXplKEVtaXNzaW9ucyA9IHN1bShWYWx1ZSkpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBFbWlzc2lvbnMpKSArCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEuNSkgKwogICAgbGFicyh0aXRsZSA9ICJXb3JsZCAiIH5DT1syXX4gIiBFbWlzc2lvbnMgcGVyIFllYXIgKDE3NTEtMjAxNCkiLAogICAgICAgICBjYXB0aW9uID0gIkxpbWl0ZWQgdG8gcmVwb3J0aW5nIGNvdW50cmllcyIsCiAgICAgICAgIHkgPSAiRW1pc3Npb25zIChNZXRyaWMgVG9ubmVzKSIpICsKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkKYGBgCgpXZSBjYW4gY2xlYXJseSBzZWUgdGhhdCBnbG9iYWwgQ08yIGVtaXNzaW9ucyBoYXZlIGRyYW1hdGljYWxseSByaXNlbiBzaW5jZSAxOTAwLgoKTm90aWNlLCB3ZSB1c2VkIHRoZSBmdW5jdGlvbiBgdGhlbWVfbGluZWRyYXcoKWAgb2YgYGdncGxvdDJgIHRvIGNoYW5nZSB0aGUgZ2VuZXJhbCBhcHBlYXJhbmNlIG9mIHRoZSBwbG90LiAKCioqVXNlZnVsIHRpcCoqOiBZb3UgY2FuIHR5cGUgYHRoZW1lX2AgaW4gdGhlIFJTdHVkaW8gY29uc29sZSB0byBzZWUgdGhlIHZhcmlvdXMgcGxvdCB0aGVtZSBvcHRpb25zIGF2YWlsYWJsZS4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygid3d3L2ltZy90aGVtZXMucG5nIikKYGBgCgpHcmVhdCEgV2UndmUgY3JlYXRlZCBvdXIgZmlyc3QgcGxvdC4gCgpCZWZvcmUgd2UgbGVhdmUgdGhpcyBzZWN0aW9uLCBsZXQncyBzYXZlIHRoaXMgdGhlbWUgc28gd2UgZG8gbm90IGhhdmUgdG8ga2VlcCB0eXBpbmcgdGhlIHNhbWUgY29kZSBpbiBmdXR1cmUgcGxvdHMuIAoKYGBge3J9Cm15X3RoZW1lIDwtCiAgdGhlbWVfbGluZWRyYXcoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpCmBgYAoKSW4gdGhpcyB3YXksIHdlIGNhbiBqdXN0IGFkZCBhbm90aGVyIF9sYXllcl8gdG8gb3VyIHBsb3Qgd2l0aCB0aGUgYG15X3RoZW1lYCB3ZSBjcmVhdGVkIHdpdGggdGhlIHNwZWNpZmljYXRpb25zIG9mIHRoZSBzaXplcyBvZiB0aGUgdGl0bGUgYW5kIGF4aXMgbGFiZWxzLiAKCmBgYHtyfQpDTzJfd29ybGQgPC0KICBkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKEluZGljYXRvciA9PSAiRW1pc3Npb25zIikgJT4lCiAgZ3JvdXBfYnkoWWVhcikgJT4lCiAgc3VtbWFyaXplKEVtaXNzaW9ucyA9IHN1bShWYWx1ZSkpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBFbWlzc2lvbnMpKSArCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEuNSkgKwogICAgbGFicyh0aXRsZSA9ICJXb3JsZCAiIH5DT1syXX4gIiBFbWlzc2lvbnMgcGVyIFllYXIgKDE3NTEtMjAxNCkiLAogICAgICAgICBjYXB0aW9uID0gIkxpbWl0ZWQgdG8gcmVwb3J0aW5nIGNvdW50cmllcyIsCiAgICAgICAgIHkgPSAiRW1pc3Npb25zIChNZXRyaWMgVG9ubmVzKSIpICsKICBteV90aGVtZQpgYGAKCldlIGFyZSBhbHNvIHNhdmluZyB0aGUgcGxvdCB0byBhbiBvYmplY3QgY2FsbGVkIGBDTzJfd29ybGRgLiAKVG8gc2hvdyB0aGUgcGxvdCB3ZSBzaW1wbHkgdHlwZSB0aGUgbmFtZSBvZiB0aGUgb2JqZWN0OiAKCmBgYHtyfQpDTzJfd29ybGQKYGBgCk5vdyBsZXQncyBzYXkgd2Ugd2FudGVkIHRvIHNhdmUgdGhpcyBwbG90LgoKV2UgY291bGQgZG8gc28gdXNpbmcgdGhlIHVzaW5nIHRoZSAgYHNhdmUoKWAgZnVuY3Rpb24gdG8gc2F2ZSB0aGlzIHRvIGEgInBsb3QiIGRpcmVjdG9yeSBpbiBvdXIgd29ya2luZyBkaXJlY3RvcnkgYXMgYW4gUkRBIGZpbGUgYW5kIHdlIGNhbiB1c2UgdGhlIGBwbmcoKWAgZnVuY3Rpb24gdG8gc2F2ZSBhIHBuZyBmb3IgY29sbGFib3JhdG9ycy4gV2UgbmVlZCB0byB1c2UgYGRldi5vZmYoKWAgZnVuY3Rpb24gdG8gY2xvc2UgdGhlIGdyYXBoaWNhbCBkZXZpY2UgdGhhdCB3ZSB3aWxsIHVzZSB0byBjcmVhdGUgdGhlIHBuZyB2ZXJzaW9uIG9mIHRoZSBwbG90IHNvIHRoYXQgd2UgYXJlIHJlYWR5IHRvIG1ha2UgYW5vdGhlciBwbG90IGxpa2UgdGhpcy4KCmBgYHtyLCBldmFsPUZBTFNFfQpzYXZlKENPMl93b3JsZCwgZmlsZSA9aGVyZTo6aGVyZSgicGxvdHMiLCAiQ08yX3dvcmxkLnJkYSIpKQpwbmcoaGVyZTo6aGVyZSgicGxvdHMiLCAiQ08yX3dvcmxkLnBuZyIpKQpDTzJfd29ybGQKZGV2Lm9mZigpCmBgYAoKCk9uZSB0aGluZyB0aGF0IHdvdWxkIGJlIG5pY2UgdG8ga25vdyBpcyB3aGljaCBjb3VudHJpZXMgYXJlIGNvbnRyaWJ1dGluZyB0aGUgbW9zdCBvciB0aGUgbGVhc3QgdG8gQ08yIGVtaXNzaW9ucy4gCkxldCdzIGNvbnRpbnVlIHRvIGV4cGxvcmUgdGhlIGRhdGEgdG8gaW52ZXN0aWdhdGUgaG93IENPMiBlbWlzc2lvbnMgZnJvbSBpbmRpdmlkdWFsIGNvdW50cmllcyBoYXZlIGNoYW5nZWQgb3ZlciB0aW1lLiAKCk5leHQsIHdlIGdvIGJhY2sgdG8gdXNpbmcgb3VyIGBkYXRhX2xvbmdgIGRhdGFzZXQuIApIZXJlLCB3ZSB1c2UgdGhlIGBncm91cGAgYXJndW1lbnQgaW4gYGFlcygpYCB3aGljaCBjb250cm9scyB3aGV0aGVyIGEgbGluZSBzaG91bGQgYmUgZHJhd24gCgpgYGB7cn0KZGF0YV9sb25nICU+JQogIGZpbHRlcihJbmRpY2F0b3IgPT0gIkVtaXNzaW9ucyIpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBWYWx1ZSwgZ3JvdXAgPSBDb3VudHJ5KSkgKwogIGdlb21fbGluZSgpICsKICB5bGFiKCJFbWlzc2lvbnMiKSArCiAgbXlfdGhlbWUKYGBgCgpXZSBjYW4gc2VlIHRoYXQgbWFueSBjb3VudHJpZXMgc2hvdyBhIGRyYW1hdGljIGluY3JlYXNlIGluIGVtaXNzaW9ucyBvdmVyIHRpbWUgd2l0aCBhIGhhbmRmdWwgb2YgY291bnRyaWVzIHdpdGggcGFydGljdWxhcmx5IGhpZ2ggbGV2ZWxzLiAKCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgotIFdoYXQgaGFwcGVucyB3aGVuIHlvdSBkbyBub3QgdXNlIHRoZSBgZ3JvdXAgPSBDb3VudHJ5YCBhcmd1bWVudD8gCi0gV2hhdCBvdGhlciBhZXN0aGV0aWMgIChpLmUuIGBhZXMoKWAgYXJndW1lbnRzKSBjYW4gYmUgY2hhbmdlZD8KCiMjIyMKCmBgYHtyIERWX0NvZGUxLXNldHVwfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtYWdyaXR0cikKbG9hZChoZXJlOjpoZXJlKCJ3d3ciLCAiZGF0YSIsICJ3cmFuZ2xlZCIsICJ3cmFuZ2xlZF9kYXRhLnJkYSIpKQpteV90aGVtZSA8LQogIHRoZW1lX2xpbmVkcmF3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQpgYGAKCmBgYHtyIERWX0NvZGUxLCBleGVyY2lzZT1UUlVFfQojIEZpbmQgb3V0IHlvdXJzZWxmIQpgYGAKCmBgYHtyIERWX0NvZGUxLWhpbnQtMX0KZGF0YV9sb25nICU+JQogIGZpbHRlcihJbmRpY2F0b3IgPT0gIkVtaXNzaW9ucyIpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBWYWx1ZSkpICsKICBnZW9tX2xpbmUoKSArCiAgeWxhYigiRW1pc3Npb25zIikgKwogIG15X3RoZW1lCmBgYApTaW5jZSB3ZSBoYXZlIG1hbnkgb3ZlcmxhcHBpbmcgbGluZXMsIHdlIHdpbGwgbWFrZSBvdXIgbGluZXMgc2xpZ2h0bHkgdHJhbnNwYXJlbnQgYnkgdXNpbmcgdGhlIGBhbHBoYWAgYXJndW1lbnQuIAoKVGhpcyB0YWtlcyB2YWx1ZXMgZnJvbSAwIHRvIDEsIHdoZXJlIDAgaXMgY29tcGxldGVseSB0cmFuc3BhcmVudCBhbmQgMSBpcyBjb21wbGV0ZWx5IG9wYXF1ZS4gCgpXZSBhbHNvIGFkZCBvdXIgYG15X3RoZW1lYCBjb250cm9sbGluZyB0aGUgc2l6ZSBvZiB0aGUgdGl0bGUgYW5kIGF4aXMgbGFiZWxzLiAKCmBgYHtyfQpDTzJfY291bnRyaWVzIDwtCiAgZGF0YV9sb25nICU+JQogIGZpbHRlcihJbmRpY2F0b3IgPT0gIkVtaXNzaW9ucyIpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBWYWx1ZSwgZ3JvdXAgPSBDb3VudHJ5KSkgKwogIGdlb21fbGluZShhbHBoYSA9IDAuNCkgKwogIGxhYnModGl0bGUgPSAiQ291bnRyeSIgfkNPWzJdfiAiRW1pc3Npb25zIHBlciBZZWFyICgxNzUxLTIwMTQpIiwKICAgICBjYXB0aW9uID0gIkxpbWl0ZWQgdG8gcmVwb3J0aW5nIGNvdW50cmllcyIsCiAgICAgICAgICAgeSA9ICJFbWlzc2lvbnMgKE1ldHJpYyBUb25uZXMpIikgKwogIG15X3RoZW1lCgpDTzJfY291bnRyaWVzCmBgYAoKT3VyIHBsb3QgaXMgc3RhcnRpbmcgdG8gbG9vayByZWFsbHkgZ29vZC4gCk9uZSBxdWVzdGlvbiB5b3Ugc3RpbGwgbWlnaHQgaGF2ZSBpcyB3aGljaCBjb3VudHJ5IGNvcnJlc3BvbmRzIHRvIHdoaWNoIGxpbmU/IApXaGljaCBsaW5lIGluZGljYXRlcyB0aGUgZW1pc3Npb25zIGluIHRoZSBVUz8gCgoKIyMjIEFkZGluZyBjb2xvciAKCldlIGNhbiBhZGQgYW5vdGhlciAibGF5ZXIiIG9uIHRvcCBvZiBvdXIgZmlyc3QgcGxvdCB0byBhZGQgYSBibHVlIGxpbmUganVzdCBmb3IgdGhlIFVTIGRhdGEuIApUbyBkbyB0aGlzIHdlIG5lZWQgdG8gaW5kaWNhdGUgd2hhdCBkYXRhIHdlIHdvdWxkIGxpa2UgdG8gcGxvdCwgc28gd2UgbmVlZCB0byBmaWx0ZXIgZm9yIGp1c3QgdGhlIFVTIGRhdGEgYW5kIHRoZW4gd2UgbmVlZCB0byBpbmRpY2F0ZSB0aGF0IGl0IHdpbGwgYmUgY29sb3JlZCBieSBDb3VudHJ5LCBldmVuIHRob3VnaCBpbiB0aGlzIGNhc2Ugd2Ugb25seSBoYXZlIG9uZSBsaW5lIHRvIGNvbG9yLiAKVGhlIGRlZmF1bHQgY29sb3Igd291bGQgYmUgYSBzYWxtb24gcGluayBjb2xvciwgYnV0IHdlIHdvdWxkIGxpa2UgYmx1ZS4gClNvIHdlIHdpbGwgdXNlIHRoZSBgc2NhbGVfY29sb3JfbWFudWFsKClgIGZ1bmN0aW9uIHRvIG1hbnVhbGx5IGNob29zZSB0aGUgY29sb3IgdGhhdCB3ZSB3YW50IGJ5IHVzaW5nIGBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiKSlgLiBPZnRlbiB5b3UgbWlnaHQgdXNlIHJlZCB0byBoaWdobGlnaHQgYSBzdWJzZXQgb2YgdGhlIGRhdGEsIGhvd2V2ZXIsIHRoaXMgY2FuIGJlIGRpZmZpY3VsdCBmb3Igdmlld2VycyB3aXRoIGNlcnRhaW4gdHlwZXMgb2YgY29sb3JibGluZG5lc3MuIAoKTm90aWNlIGhvdyB0aGUgY29sb3IgbmFtZSBuZWVkcyB0byBiZSBpbiBxdW90ZXMgYW5kIHRoYXQgdGhlIGFyZ3VtZW50IGB2YWx1ZXMgPWAgaXMgdXNlZCB0byBzcGVjaWZ5IHdoYXQgY29sb3IgdmFsdWVzIHRvIHVzZS4KCldlIGNhbiBhZGQgdGhpcyBsaW5lIHRvIHRoZSBwbG90IGluIHR3byB3YXlzLiAKCioqVXNlZnVsIHRpcCoqOiBJbnN0ZWFkIG9mIHJldHlwaW5nIHRoZSBvcmlnaW5hbCBjb2RlIHRvIGNyZWF0ZSB0aGUgYENPMl9jb3VudHJpZXNgIHBsb3QsIHdlIGNhbiBqdXN0IHVzZSB0aGUgYCtgIG9wZXJhdG9yOiAKCmBgYHtyfQpDTzJfY291bnRyaWVzICsKICBnZW9tX2xpbmUoZGF0YSA9IGRhdGFfbG9uZyAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiLAogICAgICAgICAgICAgICAgICAgICBDb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIiksCiAgICAgICAgICAgICAgYWVzKHggPSBZZWFyLCB5ID0gVmFsdWUsIGNvbG9yID0gQ291bnRyeSkpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiKSkKYGBgCgpJdCBsb29rcyBsaWtlIHRoZSBVUyBoYXMgbG9uZyBiZWVuIHRoZSBsYXJnZXN0IENPMiBlbWlzc2lvbiBwcm9kdWNpbmcgY291bnRyeSB1bnRpbCByZWNlbnRseSwgd2hlbiB0aGUgVVMgd2FzIHN1cnBhc3NlZCBieSBhbm90aGVyIGNvdW50cnkuIAoKTGV0J3MgZmlndXJlIG91dCB3aG8gYXJlIHRoZSB0b3AgMTAgZW1pc3Npb24gcHJvZHVjaW5nIGNvdW50cmllcyBpbiAyMDE0LiAKSGVyZSwgd2UgZmlsdGVyIHRoZSBkYXRhIGZvciB0aGUgeWVhciAyMDE0LCB3aGljaCB3YXMgdGhlIGZpbmFsIHllYXIgb2YgdGhlIGRhdGEuIApUaGVuLCB3ZSBjYW4gbWFrZSBhIHJhbmsgdmFyaWFibGUgYmFzZWQgb24gdGhlIGBWYWx1ZWAgdmFyaWFibGUgZm9yIHRoZSBhbW91bnQgb2YgZW1pc3Npb25zIHByb2R1Y2VkLiAKClRoZXJlIGFyZSBtYW55IGZ1bmN0aW9ucyBpbiB0aGUgYGRwbHlyYCBwYWNrYWdlIGZvciByYW5raW5nIHZhbHVlcyB0aGF0IGFyZSBiYXNlZCBvbiB0aGUgW1NRTF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU1FMKXt0YXJnZXQ9Il9ibGFuayJ9IG9yIHNwZWNpZmljYWxseSBbU1FMIHJhbmsgZnVuY3Rpb25zXShodHRwczovL3d3dy5zcWxzaGFjay5jb20vb3ZlcnZpZXctb2Ytc3FsLXJhbmstZnVuY3Rpb25zLyl7dGFyZ2V0PSJfYmxhbmsifS4gClNRTCBpcyBhbm90aGVyIHByb2dyYW1taW5nIGxhbmd1YWdlIGZvciBtYW5hZ2luZyBsYXJnZSBhbW91bnRzIG9mIGRhdGEuIApUaGUgZGlmZmVyZW5jZSBpbiB0aGUgcmFuayBmdW5jdGlvbnMgbW9zdGx5IGhhcyB0byBkbyB3aXRoIGhvdyB0byBkZWFsIHdpdGggdGllcyBpbiB0aGUgZGF0YS4gIApXZSB3aWxsIHVzZSBgZGVuc2VfcmFuaygpYCwgYXMgd2UgZG8gbm90IHdhbnQgZ2FwcyBiZXR3ZWVuIHJhbmtzLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjYwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL3JhbmsucG5nIikKYGBgCgpXZSB3YW50IHRvIGRvIHRoaXMgaW4gZGVzY2VuZGluZyBvcmRlciBiZWNhdXNlIHdlIHdhbnQgdG8gcmFuayBieSBsYXJnZXN0IHRvIHNtYWxsZXN0LCBzbyB3ZSB3aWxsIHVzZSB0aGUgYGRlc2MoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gClRoZW4sIHdlIHdpbGwgYXJyYW5nZSB0aGUgb3V0cHV0IGJ5IHJhbmsgdXNpbmcgdGhlIGBhcnJhbmdlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIAoKYGBge3J9CnRvcF8xMF9jb3VudCA8LQogIGRhdGFfbG9uZyAlPiUKICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiLCBZZWFyID09IDIwMTQpICU+JQogIG11dGF0ZShyYW5rID0gZGVuc2VfcmFuayhkZXNjKFZhbHVlKSkpICU+JQogIGZpbHRlcihyYW5rIDw9IDEwKSAlPiUKICBhcnJhbmdlKHJhbmspCgp0b3BfMTBfY291bnQKYGBgCgpXZSBjYW4gc2VlIHRoYXQgQ2hpbmEgaXMgbm93IHRoZSB0b3AgZW1pc3Npb24gcHJvZHVjaW5nIGNvdW50cnkuCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKV2hhdCBhcmUgdGhlIGJvdHRvbSAxMCBlbWlzc2lvbiBwcm9kdWNpbmcgY291bnRyaWVzIGluIDIwMTQ/CgojIyMjCgpgYGB7ciBEVl9Db2RlMi1zZXR1cH0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobWFncml0dHIpCmxvYWQoaGVyZTo6aGVyZSgid3d3IiwgImRhdGEiLCAid3JhbmdsZWQiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkKYGBgCgpgYGB7ciBEVl9Db2RlMiwgZXhlcmNpc2U9VFJVRX0KIyBXcml0ZSBzb21lIGNvZGUgdG8gZmluZCBvdXQKYGBgCgpgYGB7ciBEVl9Db2RlMi1oaW50LTF9CiMgMXN0IHdheTogcmFuayBpbiBkZXNjZW5kaW5nIG9yZGVyIGFzIHdlIGRpZCBiZWZvcmUgCiMgMm5kIHdheTogcmFuayBpbiBhc2NlbmRpbmcgb3JkZXIKYGBgCgpgYGB7ciBEVl9Db2RlMi1oaW50LTJ9CmJvdHRvbV8xMF9jb3VudCA8LQogIGRhdGFfbG9uZyAlPiUKICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiLCBZZWFyID09IDIwMTQpCmBgYAoKYGBge3IgRFZfQ29kZTItaGludC0zfQojIDFzdCB3YXkgb2YgZG9pbmcgdGhpcwpib3R0b21fMTBfY291bnQgPC0KICBkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKEluZGljYXRvciA9PSAiRW1pc3Npb25zIiwgWWVhciA9PSAyMDE0KSAlPiUKICBtdXRhdGUocmFuayA9IGRlbnNlX3JhbmsoZGVzYyhWYWx1ZSkpKSAlPiUKICBmaWx0ZXIocmFuayA+PSBtYXgocmFuaykgLSA5KSAlPiUKICBhcnJhbmdlKHJhbmspCmJvdHRvbV8xMF9jb3VudApgYGAKCmBgYHtyIERWX0NvZGUyLWhpbnQtNH0KIyAybmQgd2F5IG9mIGRvaW5nIHRoaXMKYm90dG9tXzEwX2NvdW50IDwtCiAgZGF0YV9sb25nICU+JQogIGZpbHRlcihJbmRpY2F0b3IgPT0gIkVtaXNzaW9ucyIsIFllYXIgPT0gMjAxNCkgJT4lCiAgbXV0YXRlKHJhbmsgPSBkZW5zZV9yYW5rKFZhbHVlKSkgJT4lCiAgZmlsdGVyKHJhbmsgPD0gMTApICU+JQogIGFycmFuZ2UocmFuaykKYm90dG9tXzEwX2NvdW50CiMgQ2FuIHlvdSB0aGluayBvZiBvdGhlciB3YXlzPyBUcnkgdGhlbSBvdXQhCmBgYAoKTGV0J3MgbWFrZSBhIHBsb3Qgb2YgKmp1c3QgdGhlc2UgdG9wIHRlbiBjb3VudHJpZXMqLiAKClRvIGRvIHRoaXMsIHdlIG5lZWQgdG8gZmlsdGVyIHRoZSBkYXRhIHRvIGp1c3QgdGhlc2UgdG9wIGNvdW50cmllcyBieSB1c2luZyB0aGUgYCVpbiVgIG9wZXJhdG9yIHRvIG9ubHkga2VlcCBjb3VudHJpZXMgaW4gb3VyIGBDb3VudHJ5YCB2YXJpYWJsZSB0aGF0IGFyZSBhbHNvIGluIHRoZSBgQ291bnRyeWAgdmFyaWFibGUgd2l0aGluIGB0b3BfMTBfY291bnRgLiAKV2UgY2FuIHVzZSB0aGUgYHB1bGwoKWAgZnVuY3Rpb24gYWxzbyBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIHNwZWNpZmljYWxseSBncmFiIGp1c3QgdGhlIGBDb3VudHJ5YCBkYXRhIG91dCBvZiBgdG9wXzEwX2NvdW50YC4KClNpbmNlIHdlIGhhdmUgMTAgY291bnRyaWVzIHdlIHdpbGwgd2FudCB0byBkaWZmZXJlbnRpYXRlIHRoZW0gYnkgY29sb3IuIAoKVG8gY29sb3Igb3VyIHBsb3Qgd2Ugd2lsbCB1c2UgdGhlIGB2aXJpZGlzYCBjb2xvciBwYWxldHRlIHdoaWNoIGlzIGNvbXBhdGlibGUgd2l0aCBjb2xvci1ibGluZG5lc3MgYnkgdXNpbmcgdGhlIGBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKWAgZnVuY3Rpb24uIApUaGlzIGZ1bmN0aW9uIGlzIGF2YWlsYWJsZSBieSBsb2FkaW5nIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4gClRoZXJlIGFyZSBhIGZldyB2YXJpYXRpb25zIGZvciBkaXNjcmV0ZSB2YWx1ZXMgYXMgYF9kYCwgb3IgYmlubmVkIGNvbnRpbnVvdXMgdmFsdWVzIGFzIGBfYmAsIG9yIGNvbnRpbnVvdXMgdmFsdWVzIGFzIGBfY2AuIApTZWUgW2hlcmVdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9zY2FsZV92aXJpZGlzLmh0bWwpIGZvciBtb3JlIGluZm9ybWF0aW9uLgoKCmBgYHtyfQpUb3AxMGIgPC0gZGF0YV9sb25nICU+JQogIGZpbHRlcihDb3VudHJ5ICVpbiUgcHVsbCh0b3BfMTBfY291bnQsIENvdW50cnkpKSAlPiUKICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiKSAlPiUKICBmaWx0ZXIoWWVhciA+PSAxOTAwKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gVmFsdWUsIGNvbG9yID0gQ291bnRyeSkpICsKICAgIGdlb21fbGluZSgpICsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsKICAgIGxhYnModGl0bGUgPSAiVG9wIDEwIEVtaXNzaW9ucy1wcm9kdWNpbmcgQ291bnRyaWVzIGluIDIwMTAgKDE5MDAtMjAxNCkiLAogICAgICAgICBzdWJ0aXRsZSA9ICJPcmRlcmVkIGJ5IEVtaXNzaW9ucyBQcm9kdWNlZCBpbiAyMDE0IiwKICAgICAgICAgeSA9ICJFbWlzc2lvbnMgKE1ldHJpYyBUb25zKSIsCiAgICAgICAgIHggPSAiWWVhciIpICsKICAgIG15X3RoZW1lCgpUb3AxMGIKYGBgCgpJdCdzIHN0aWxsIGEgYml0IGRpZmZpY3VsdCB0byB0ZWxsIHdoaWNoIGxpbmUgY29ycmVzcG9uZHMgdG8gd2hpY2ggY291bnRyeS4gClNvLCBsZXQncyBhZGQgYSB0ZXh0IGxhYmVsIGRpcmVjdGx5IHRvIHRoZSBwbG90LiAuIAoKIyMjIEFkZGluZyB0ZXh0IGxhYmVscwoKT25lIHdheSB0byBkbyB0aGlzIGlzIHRvIGFkZCB0ZXh0IGxheWVyIHRvIG91ciBwbG90IHVzaW5nIHRoZSBgZ2VvbV90ZXh0KClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4gCldlIG5lZWQgdG8gZmlyc3Qgc3BlY2lmeSB3aGF0IHZhcmlhYmxlIG9yIGNvbHVtbiB3ZSB3aWxsIHVzZS4gCkhvd2V2ZXIsIHdlIG9ubHkgd2FudCB0byBwdWxsIHRoZSB0ZXh0IGxhYmVscyBmb3IgdGhlIHRvcCB0ZW4gY291bnRyaWVzIGluIHRoZSBsYXN0IHllYXIuIApUbyBkbyB0aGlzLCB3ZSB1c2UgdGhlIGBsYXN0KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuCgpUaGVuLCB3ZSBuZWVkIHRvIGluZGljYXRlIHRoYXQgb3VyIHRleHQgbGFiZWwgd2lsbCBiZSBiYXNlZCBvbiB0aGUgYENvdW50cnlgIHZhcmlhYmxlIHVzaW5nIHRoZSBgYWVzKClgIGFlc3RoZXRpY3MgbWFwcGluZyBhcmd1bWVudC4gCldlIHdpbGwgYWxzbyBnZXQgcmlkIG9mIG91ciBsZWdlbmQgc2luY2Ugd2Ugd2lsbCBub3QgbmVlZCBpdCBhbnltb3JlLCBieSB1c2luZyB0aGUgYHRoZW1lKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4KCmBgYHtyfQpUb3AxMGIgKwogIGdlb21fdGV4dChkYXRhID0gZGF0YV9sb25nICU+JQogICAgICAgICAgICAgIGZpbHRlcihDb3VudHJ5ICVpbiUgcHVsbCh0b3BfMTBfY291bnQsIENvdW50cnkpKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoWWVhciA9PSBsYXN0KFllYXIpKSwKICAgICAgICAgICAgYWVzKGxhYmVsID0gQ291bnRyeSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKTm90IGJhZCwgYnV0IHNvbWUgb2YgdGhlIGxhYmVscyBhcmUgb3ZlcmxhcHBpbmcgYW5kIGRpZmZpY3VsdCB0byByZWFkLgpXZSBjYW4gdXNlIHRoZSBgY2hlY2tfb3ZlcmxhcCA9IFRSVUVgIGFyZ3VtZW50IHdpdGhpbiB0aGUgYGdlb21fdGV4dCgpYCBmdW5jdGlvbiB0byByZW1vdmUgb3ZlcmxhcHBpbmcgdmFyaWFibGVzLiAKQWxzbywgd2UgY2FuIGV4cGFuZCB0aGUgcGxvdCBhcmVhIGhvcml6b250YWxseSBzbyB0aGF0IHRoZSBuYW1lcyBhcmUgbm90IGN1dG9mZiBieSB1c2luZyBgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4yLDApKWAuIFRoaXMgdGFrZXMgYSB2ZWN0b3Igd2l0aCB0d28gdmFsdWVzLiBUaGUgZmlyc3QgdmFsdWUgaW5kaWNhdGVzIHdoYXQgcGVyY2VudGFnZSB0byBleHBhbmQgdGhlIHggYXhpcyBpbiBib3RoIGRpcmVjdGlvbnMuIEluIG91ciBjYXNlIHdlIHdpbGwgZXhwYW5kIGJ5IDE1IHBlcmNlbnQuIFRoZSBzZWNvbmQgdmFsdWUgaW5kaWNhdGVzIHdoYXQgYWJzb2x1dGUgdmFsdWUgdG8gZXhwYW5kIHRoZSBsaW1pdCBvZiB0aGUgeCBheGlzLiBJbiBvdXIgY2FzZSBgYygwLjE1LDApYCB3aWxsIGFjaGlldmUgYSBzaW1pbGFyIHJlc3VsdCBhcyBgYygwLCAxNylgLCBhcyB0aGUgcmFuZ2Ugb2YgdmFsdWVzIGZyb20gMTk5MCB0byAyMDE0IGlzIDExNCB5ZWFycyBhbmQgMTUlIG9mIHRoaXMgaXMgMTcuIAoKYGBge3J9CgpUb3AxMGIgKwogIGdlb21fdGV4dChkYXRhID0gZGF0YV9sb25nICU+JQogICAgICAgICAgICAgIGZpbHRlcihDb3VudHJ5ICVpbiUgcHVsbCh0b3BfMTBfY291bnQsIENvdW50cnkpKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoWWVhciA9PSBsYXN0KFllYXIpKSwKICAgICAgICAgICAgYWVzKGxhYmVsID0gQ291bnRyeSksCiAgICAgICAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4xNSwgMCkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKVGhpcyBpcyBlYXNpZXIgdG8gcmVhZCBub3csIGJ1dCBpdCBhbHNvIGNhdXNlcyB1cyB0byBsb3NlIHNvbWUgb2YgdGhlIGxhYmVscy4gClRoZXJlIGFyZSBzZXZlcmFsIGFsdGVybmF0aXZlIHdheXMgd2UgY2FuIGtlZXAgYWxsIG9mIG91ciBsYWJlbHMgYW5kIG1ha2UgdGhlbSBlYXNpZXIgdG8gcmVhZC4gVGhlIGZpcnN0IHBhY2thZ2Ugd2Ugd2lsbCBzaG93IGlzIGNhbGxlZCBgZGlyZWN0bGFiZWxzYC4KClRoZSBtb3N0IHNpbXBsZSBvcHRpb24gaXMgdG8gdXNlIHRoZSBgZGlyZWN0LmxhYmVsKClgIGZ1bmN0aW9uLCB3aGljaCB3aWxsIGF1dG9tYXRpY2FsbHkgYWRkIGxhYmVscyBhdCB0aGUgZW5kIG9mIHRoZSBsaW5lcy4gCkhvd2V2ZXIsIGl0IGlzIGEgYml0IGRpZmZpY3VsdCB0byBzZWUgc29tZSBvZiBvdXIgbGFiZWxzIGFzIHRoZXkgZ2V0IGF1dG9tYXRpY2FsbHkgc2l6ZWQgdG8gZml0IHRoZSBwbG90LgoKYGBge3J9CmRpcmVjdC5sYWJlbChUb3AxMGIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjMsIDApKQpgYGAKCkFsdGVybmF0aXZlbHkgdGhpcyBjYW4gYmUgZG9uZSB3aXRoaW4gdGhlIGBnZ3Bsb3QyYCBmcmFtZXdvcmsgYnkgbGF5ZXJpbmcgdXNpbmcgdGhlIGBnZW9tX2RsKClgIGZ1bmN0aW9uLgoKYGBge3J9ClRvcDEwYiArCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4zLCAwKSkgKwogIGdlb21fZGwoYWVzKGxhYmVsID0gQ291bnRyeSksIG1ldGhvZCA9IGxpc3QoImxhc3QucG9pbnRzIiwiYnVtcHVwIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKVGhpcyBpcyBtb3JlIGxlZ2libGUgbm93LiAKV2UgaGF2ZSBhbGwgMTAgY291bnRyaWVzIG5hbWVzIGxpc3RlZCBhbmQgdGhleSBhcmUgaW4gb3JkZXIgb2YgdGhlIGxhc3QgZGF0YSBwb2ludCBhbmQgdGhleSBhcmUgcmVsYXRpdmVseSBjbG9zZSB0byB0aGUgbGluZXMgdGhhdCB0aGV5IGNvcnJlc3BvbmQgdG8uIAoKQW5vdGhlciBvcHRpb24gaXMgdG8gdXNlIGEgZGlmZmVyZW50IG1ldGhvZCBpbiB0aGUgYGRpcmVjdGxhYmxlc2AgcGFja2FnZS4gCltIZXJlXShodHRwOi8vZGlyZWN0bGFiZWxzLnItZm9yZ2Uuci1wcm9qZWN0Lm9yZy9kb2NzL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gaXMgYSBsaXN0IG9mIG9wdGlvbnMuCgpGb3IgZXhhbXBsZSwgdGhlIGAiYW5nbGVkLmJveGVzImAgbWV0aG9kIGxvb2tzIG5pY2UgZm9yIHNvbWUgcGxvdHMgYnV0IGRvZXMgbm90IHdvcmsgdmVyeSB3ZWxsIGZvciBvdXIgcGxvdDoKCmBgYHtyfQpkaXJlY3QubGFiZWwoVG9wMTBiLCBtZXRob2QgPSBsaXN0KCJhbmdsZWQuYm94ZXMiKSkgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAuMywgMCkpCmBgYAoKSG93ZXZlciB0aGUgYCJsYXN0LnBvbHlnb25zImAgbWV0aG9kIHdvcmtzIHF1aXRlIHdlbGw6CgpgYGB7cn0KZGlyZWN0LmxhYmVsKFRvcDEwYiwgbWV0aG9kID0gbGlzdCgibGFzdC5wb2x5Z29ucyIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4zLCAwKSkKYGBgCgpUaGUgc2Vjb25kIHBhY2thZ2UgaXMgdGhlIGBnZ3JlcGVsYCBwYWNrYWdlLCB3aGljaCBpcyBlc3BlY2lhbGx5IGdvb2QgZm9yIGNyb3dkZWQgbGFiZWxzIHRoYXQgbWlnaHQgb3ZlcmxhcCBvbmUgYW5vdGhlci4gCkl0IGFsbG93cyBmb3IgbW9yZSBjb250cm9sIHRoYW4gdGhlIGBkaXJlY3RsYWJlbHNgIHBhY2thZ2UuIAoKU3BlY2lmaWNhbGx5LCB3ZSB3aWxsIHVzZSB0aGUgYGdlb21fdGV4dF9yZXBlbCgpYCBmdW5jdGlvbiBmcm9tIHRoZSBgZ2dyZXBlbGAgcGFja2FnZS4gCkp1c3QgbGlrZSB3aXRoIGBnZW9tX3RleHQoKWAsIGZpcnN0IHdlIG5lZWQgdG8gc3BlY2lmeSB3aGF0IGRhdGEgd2Ugd2FudCB0byBpbmNsdWRlLiAKVGhlbiwgd2Ugc3BlY2lmeSB3aXRoIHRoZSBgYWVzKClgIGFyZ3VtZW50IHRoYXQgb3VyIGxhYmVsIHdpbGwgYmUgYmFzZWQgb24gdGhlIGBDb3VudHJ5YCB2YXJpYWJsZSBhbmQgd2UgYWdhaW4gc3BlY2lmeSB3aGF0IHZhcmlhYmxlIHRvIHVzZSBmb3Igb3VyIHggYXhpcyBhbmQgeSBheGlzLCBzbyB0aGF0IHdlIGluZGljYXRlIHdoZXJlIHRoZSBsYWJlbHMgc2hvdWxkIGJlIHBsb3R0ZWQuIAoKYGBge3J9ClRvcDEwYiArCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBkYXRhX2xvbmcgJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKENvdW50cnkgJWluJSBwdWxsKHRvcF8xMF9jb3VudCwgQ291bnRyeSkpICU+JQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihJbmRpY2F0b3IgPT0gIkVtaXNzaW9ucyIpICU+JQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihZZWFyID09IGxhc3QoWWVhcikpLAogICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBDb3VudHJ5LCB4ID0gWWVhciwgeSA9IFZhbHVlKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAuMywgMCkpCmBgYApZb3UgY2FuIHNlZSB0aGF0IHRoaXMgcGFja2FnZSBjcmVhdGVzIHNlZ21lbnRzIHRoYXQgY29ubmVjdCB0aGUgbGFiZWwgdG8gdGhlIGxpbmUuCgpUaGVyZSBhcmUgbWFueSBhcmd1bWVudHMgdG8gdXNlIHRvIHN0eWxlIHlvdXIgbGFiZWxzIGp1c3QgdGhlIHdheSB0aGF0IHlvdSB3YW50OgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjYwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL2dncmVwZWwucG5nIikKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3JlcGVsL3ZpZ25ldHRlcy9nZ3JlcGVsLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0KClNlZSBbdGhlIGdncmVwZWwgdmlnbmV0dGVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3JlcGVsL3ZpZ25ldHRlcy9nZ3JlcGVsLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgZGV0YWlscy4KCkxldCdzIHBsYXkgYXJvdW5kIHdpdGggc29tZSBvZiB0aGVzZSBvcHRpb25zIGluIHRoZSB0YWJsZSBhYm92ZS4gCmBgYHtyfQpUb3AxMGIgKwogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gZGF0YV9sb25nICU+JQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihDb3VudHJ5ICVpbiUgcHVsbCh0b3BfMTBfY291bnQsIENvdW50cnkpKSAlPiUKICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoSW5kaWNhdG9yID09ICJFbWlzc2lvbnMiKSAlPiUKICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoWWVhciA9PSBsYXN0KFllYXIpKSwKICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gQ291bnRyeSwgeCA9IFllYXIsIHkgPSBWYWx1ZSksCiAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAxMCwKICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxLAogICAgICAgICAgICAgICAgICB2anVzdCA9IDEsCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMjUsCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gMSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAuMywgMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjMsIDApKQpgYGAKCk5pY2UsIHRoYXQgbG9va3MgcHJldHR5IGdvb2QuCkZvciBmdW4sIGxldCdzIHRyeSBzaG93aW5nIG91ciBkYXRhIGluIGFuIGVudGlyZWx5IGRpZmZlcmVudCB3YXkuIAoKCiMjIyBUaWxlIHBsb3RzCgpUaGlzIHRpbWUgd2Ugd2lsbCBjcmVhdGUgYSBgZ2VvbV90aWxlYCBwbG90LgoKVG8gY3JlYXRlIHRoaXMgcGxvdCB3ZSB3aWxsIGZpbHRlciBvdXIgZGF0YSB0byBpbmNsdWRlIG9ubHkgdGhlIENvdW50cmllcyBpbmNsdWRlZCBpbiB0aGUgYENvdW50cnlgIHZhcmlhYmxlIG9mIHRoZSBgdG9wXzEwX2NvdW50YC4gCgpUaGVuLCB3ZSB3aWxsIHVzZSB0aGUgYGZjdF9yZW9yZGVyKClgIGZ1bmN0aW9uIG9mIHRoZSBgZm9yY2F0c2AgcGFja2FnZSB0byBvcmRlciBvdXIgY291bnRyaWVzIGJhc2VkIG9uIHRoZSBsYXN0IGVtaXNzaW9uIHZhbHVlIGluIDIwMTQuCgpUbyB1c2UgdGhpcyBmdW5jdGlvbiwgdGhlIHZhcmlhYmxlIHRoYXQgaXMgdG8gYmUgcmVvcmRlcmVkIGlzIGxpc3RlZCBmaXJzdC4gClRoZSB2YXJpYWJsZSB0aGF0IGlzIGJlaW5nIHVzZWQgdG8gZGV0ZXJtaW5lIHRoZSBvcmRlciBpcyBsaXN0ZWQgc2Vjb25kLiAKRmluYWxseSwgYSBmdW5jdGlvbiB0byBhcHBseSB0byB0aGUgdmFyaWFibGUgbGlzdGVkIHNlY29uZCBpcyBsaXN0ZWQgdGhpcmQuClRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBkZXRlcm1pbmUgdGhlIG9yZGVyLiAKSW4gdGhpcyBjYXNlLCB3ZSB3YW50IHRvIGRldGVybWluZSB0aGUgbGFzdCB2YWx1ZSBvZiB0aGUgYFZhbHVlYCB2YXJpYWJsZSB1c2luZyB0aGUgYGxhc3QoKWAgZnVuY3Rpb24gKHJlY2FsbCB0aGF0IHRoaXMgaXMgYWxzbyBhIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UpLiAKVGhlbiwgdGhlIGBDb3VudHJ5YCB2YXJpYWJsZSB3aWxsIGJlIG9yZGVyZWQgYnkgdGhlIGxhc3QgdmFsdWUgb2YgdGhlIGBWYWx1ZWAgdmFyaWFibGUuCgpUbyBjb2xvciBvdXIgcGxvdCB3ZSB3aWxsIHVzZSB0aGUgYHZpcmlkaXNgIGNvbG9yIHBhbGV0dGUgYWdhaW4gYnV0IHRoaXMgdGltZSB3ZSB3aWxsIHVzZSB0aGUgYHNjYWxlX2ZpbGxfdmlyaWRpc19jKClgIC0tIHJlY2FsbCB0aGF0IHRoZSBgX2NgIGluZGljYXRlcyBhIGNvbnRpbnVvdXMgc2NhbGUuIApTZWUgW3RoZSBzY2FsZV92aXJpZGlzIHJlZmVyZW5jZV0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3NjYWxlX3ZpcmlkaXMuaHRtbCkgZm9yIG1vcmUgaW5mb3JtYXRpb24uCgoKYGBge3J9ClRvcDEwdCA8LQogIGRhdGFfbG9uZyAlPiUKICBmaWx0ZXIoQ291bnRyeSAlaW4lIHB1bGwodG9wXzEwX2NvdW50LCBDb3VudHJ5KSkgJT4lCiAgZmlsdGVyKEluZGljYXRvciA9PSAiRW1pc3Npb25zIikgJT4lCiAgZmlsdGVyKFllYXIgPj0gMTkwMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IGZjdF9yZW9yZGVyKENvdW50cnksIFZhbHVlLCBsYXN0KSkpICsKICAgIGdlb21fdGlsZShhZXMoZmlsbCA9IGxvZyhWYWx1ZSkpKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpCmBgYAoKCkZpbmFsbHksIGxldCdzIGNsZWFuIHVwIHRoZSBheGVzIGFuZCB0aGUgYXhlcyBsYWJlbHM6IAoKYGBge3J9ClRvcDEwdCA8LSBUb3AxMHQgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTkwMCwgMjAxNCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2VxKDE5MDAsIDIwMTQsIGJ5ID0gNSkpICsKICBsYWJzKHRpdGxlID0gIlRvcCAxMCAiIH5DT1syXX4gIkVtaXNzaW9uLXByb2R1Y2luZyBDb3VudHJpZXMiLAogICAgICAgc3VidGl0bGUgPSAiT3JkZXJlZCBieSBFbWlzc2lvbnMgUHJvZHVjZWQgaW4gMjAxNCIsCiAgICAgICBmaWxsID0gIkxuKENPMiBFbWlzc2lvbnMgKE1ldHJpYyBUb25uZXMpKSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgYW5nbGUgPSA5MCwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpUb3AxMHQKYGBgCgpOb3cgbGV0J3Mgc2F5IHdlIHdhbnRlZCB0byBzYXZlIHRoaXMgcGxvdC4KCldlIGNvdWxkIGRvIHNvIHVzaW5nIHRoZSB1c2luZyB0aGUgIGBzYXZlKClgIGZ1bmN0aW9uIHRvIHNhdmUgdGhpcyB0byBhICJwbG90IiBkaXJlY3RvcnkgaW4gb3VyIHdvcmtpbmcgZGlyZWN0b3J5IGFzIGFuIFJEQSBmaWxlIGFuZCB3ZSBjYW4gdXNlIHRoZSBgcG5nKClgIGZ1bmN0aW9uIHRvIHNhdmUgYSBwbmcgZm9yIGNvbGxhYm9yYXRvcnMuIFdlIG5lZWQgdG8gdXNlIGBkZXYub2ZmKClgIGZ1bmN0aW9uIHRvIGNsb3NlIHRoZSBncmFwaGljYWwgZGV2aWNlIHRoYXQgd2Ugd2lsbCB1c2UgdG8gY3JlYXRlIHRoZSBwbmcgdmVyc2lvbiBvZiB0aGUgcGxvdCBzbyB0aGF0IHdlIGFyZSByZWFkeSB0byBtYWtlIGFub3RoZXIgcGxvdCBsaWtlIHRoaXMuCgpgYGB7ciwgZXZhbD1GQUxTRX0Kc2F2ZShUb3AxMHQsIGZpbGUgPWhlcmU6OmhlcmUoInBsb3RzIiwgIlRvcDEwdC5yZGEiKSkKcG5nKGhlcmU6OmhlcmUoInBsb3RzIiwgIlRvcDEwdC5wbmciKSkKVG9wMTB0CmRldi5vZmYoKQpgYGAKCldlIHNlZSB0aGF0IEdlcm1hbnkgaGFkIHZlcnkgbG93IGVtaXNzaW9uIHJhdGVzIGF0IHRoZSBlbmQgb2YgV29ybGQgV2FyIElJLiAKV2UgYWxzbyBzZWUgdGhhdCB0aGUgVVMgaGFzIGNvbnNpc3RlbnRseSBoYWQgaGlnaCBlbWlzc2lvbiByYXRlcyBzaW5jZSAxOTAwLCBidXQgdGhlIGVtaXNzaW9uIHJhdGVzIGluIENoaW5hIHJlY2VudGx5IHN1cnBhc3NlZCB0aGF0IG9mIHRoZSBVUy4gClRoZSBwb3J0aW9ucyBvZiB0aGUgcGxvdCB0aGF0IGFyZSB3aGl0ZSBpbmRpY2F0ZSB0aGF0IHRoZXJlIGlzIG5vIGVtaXNzaW9uIGRhdGEgZm9yIHRoYXQgY291bnRyeS4KCiMjIyMgey50aGlua19xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpUaGluayBhYm91dCB3aGF0IHRoZSBwcm9zIGFuZCBjb25zIGFyZSBvZiB0aWxlIGFuZCBsaW5lIHBsb3RzLiBJbiB3aGF0IHNpdHVhdGlvbnMgd291bGQgYSB0aWxlIHBsb3QgYmUgYSBiZXR0ZXIgY2hvaWNlIGZvciBlZmZlY3RpdmUgc2NpZW50aWZpYyBjb21tdW5pY2F0aW9uPyBJbiB3aGF0IHNpdHVhdGlvbnMgd291bGQgYSBsaW5lIHBsb3QgYmUgYSBiZXR0ZXIgY2hvaWNlPwoKIyMjIwoKIyMgKipNb3JlIHRoYW4gb25lIHZhcmlhYmxlKioKKioqCgpOb3csIHdlIHdpbGwgdmlzdWFsaXplIGFsbCB0aGUgdmFyaWFibGVzIGluIG91ciBkYXRhc2V0LgoKCiMjIyBGYWNldGVkIHBsb3RzCgpIZXJlLCB3ZSB1c2UgdGhlIGBmYWNldF93cmFwKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZSwgd2hpY2ggcGxvdHMgbXVsdGlwbGUgc3VicGxvdHMgc2ltdWx0YW5lb3VzbHkuIAoKVG8gdXNlIGBmYWNldF93cmFwKClgIHdpdGggdGhlIG9wdGlvbiBmb3IgYSBkaWZmZXJlbnQgeS1heGlzIHNjYWxlIGZvciBlYWNoIHN1YnBsb3QsIHdlIG5lZWQgdG8gc2V0IHRoZSBgc2NhbGVzYCBhcmd1bWVudCBlcXVhbCB0byBgImZyZWVfeSJgLiAKV2UgY2FuIGFsc28gaW5kaWNhdGUgd2hlcmUgd2Ugd291bGQgbGlrZSB0aGUgbGFiZWwgZm9yIHRoZSBzdWJwbG90cyB0byBiZSBsb2NhdGVkIGJ5IHVzaW5nIHRoZSBgc3RyaXAucG9zaXRpb25gIGFyZ3VtZW50LiAKCmBgYHtyLGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KZ2dwbG90KGRhdGFfbG9uZywgYWVzKHggPSBZZWFyLCB5ID0gVmFsdWUsIGdyb3VwID0gQ291bnRyeSkpICsKICBnZW9tX2xpbmUoYWxwaGEgPSAwLjIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGRhdGFfbG9uZyAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoQ291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyIpLAogICAgICAgICAgICAgIGFlcyh4ID0gWWVhciwgeSA9IFZhbHVlLCBjb2xvciA9IENvdW50cnkpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIikpICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBJbmRpY2F0b3JzIGJ5IFllYXIgYW5kIFZhbHVlIiwKICAgICAgIHkgPSAiSW5kaWNhdG9yIFZhbHVlIikgKwogIG15X3RoZW1lICsKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIikpICsKICBmYWNldF93cmFwKEluZGljYXRvciB+IC4sCiAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZV95IiwKICAgICAgICAgICAgIHN0cmlwLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICAgICAgIG5jb2wgPSAxKQpgYGAKCk5vdGljZSB0aGF0IHdlIGNhbiBjaGFuZ2UgdGhlIHNpemUgb3Igc3R5bGUgb2YgdGhlIGZvbnQgZm9yIHRoZXNlIGxhYmVscyB1c2luZyB0aGUgYHN0cmlwLnRleHQgPWAgYXJndW1lbnQgb2YgdGhlIGB0aGVtZSgpYCBmdW5jdGlvbi4gCldlIGNhbiBhbHNvIHNwZWNpZnkgaG93IG1hbnkgcm93cyBvciBjb2x1bW5zIHdlIHdvdWxkIGxpa2UgdGhlIHN1YnBsb3RzIHRvIGJlIHNob3duLiAKCldlIGNhbiBhbHNvIGZhY2V0IGJ5IG1vcmUgdGhhbiBvbmUgdmFyaWFibGUgKGUuZy4gYEluZGljYXRvcmAgYW5kIGBSZWdpb25gIHRvIHNob3cgdGhlIGRhdGEgZnJvbSB0aGUgVVMgY29tcGFyZWQgdG8gb3RoZXIgY291bnRyaWVzKS4KCkluIHRoaXMgY2FzZSB3ZSB3YW50IHRoZSBzYW1lIHktYXhpcyB0byBiZSB1c2VkIGFjcm9zcyB0aGUgcm93cy4gV2Ugd2lsbCB1c2UgdGhlIGBmYWNldF9ncmlkKClgIGZ1bmN0aW9uIHRoaXMgdGltZSBpbnN0ZWFkIG9mIGBmYWNldF93cmFwKClgIGJlY2F1c2Ugb2YgdGhlIHdheSB0aGF0IHRoZSB0d28gZmFjZXQgdmFyaWFibGVzIGFyZSBkaXNwbGF5ZWQuIFRoZSBgZmFjZXRfZ3JpZCgpYCBmdW5jdGlvbiB3aWxsIGFzIHlvdSBtaWdodCBleHBlY3QsIGNyZWF0ZSBhbiBvdXRwdXQgb2YgcGxvdHMgdGhhdCBhcmUgZGlzcGxheWVkIGluIGEgZ3JpZC4gCgpUaGUgc3ludGF4IGhlcmUgaXMgdG8gcHV0IHRoZSBuYW1lIG9mIHRoZSB0d28gdmFyaWFibGVzIG9uIHRoZSBsZWZ0IG9yIHJpZ2h0IHNpZGUgb2YgdGhlIGB+YCBzeW1ib2wsIHdoaWNoIHRlbGxzIHlvdSB0byBmYWNldCBieSByb3dzIChsZWZ0KSBvciBjb2x1bW5zIChyaWdodCkuICAKCkZpcnN0LCB3ZSB3aWxsIGZpbHRlciBvdXQgdGhlIGRhdGEgYWJvdXQgZGlzYXN0ZXJzIGFuZCB0ZW1wZXJhdHVyZSBhcyB0aGlzIGlzIG9ubHkgZm9yIHRoZSBVUywgYnkgdXNpbmcgdGhlIGBmaWx0ZXIoKWAgZnVuY3Rpb24gYW5kIGAhYCAgaW5kaWNhdGVzIHRoYXQgd2Ugd2FudCBvbmx5IHZhbHVlcyBvZiB0aGUgYEluZGljYXRvcmAgdmFyaWFibGUgbm90IGluIHRoZSBsaXN0IGNvbnRhaW5pbmcgYCJEaXNhc3RlcnMiYCBhbmQgYCJUZW1wZXJhdHVyZSJgLgoKYGBge3IsZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKCEoSW5kaWNhdG9yICVpbiUgYygiRGlzYXN0ZXJzIiwgIlRlbXBlcmF0dXJlIikpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZZWFyLCB5ID0gVmFsdWUsIGdyb3VwID0gQ291bnRyeSkpICsKICAgIGdlb21fbGluZSgpICsKICAgIGZhY2V0X2dyaWQoSW5kaWNhdG9yIH4gUmVnaW9uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgSW5kaWNhdG9ycyBieSBZZWFyIGFuZCBWYWx1ZSIsCiAgICAgICAgIHkgPSAiSW5kaWNhdG9yIFZhbHVlIikgKwogICAgbXlfdGhlbWUgKwogICAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpKQpgYGAKCgoKRnJvbSB0aGVzZSBwbG90cyB3ZSBjYW4gc2VlIHRoYXQgZWFjaCB0eXBlIG9mIGRhdGEgc3BhbnMgYSBkaWZmZXJlbnQgdGltZSBzcGFuLgoKCiMjIyMgey50aGlua19xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpXaGF0IGhhcHBlbnMgd2hlbiB5b3UgY3JlYXRlIHRoZSBzYW1lIHBsb3Qgd2l0aCBgZmFjZXRfd3JhcCgpYD8gCldoeSBtaWdodCB0aGlzIGJlIHByZWZlcmFibGUgaW4gY2VydGFpbiBjYXNlcz8KCiMjIyMKCmBgYHtyIERWX0NvZGUzLXNldHVwfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtYWdyaXR0cikKbG9hZChoZXJlOjpoZXJlKCJ3d3ciLCAiZGF0YSIsICJ3cmFuZ2xlZCIsICJ3cmFuZ2xlZF9kYXRhLnJkYSIpKQpteV90aGVtZSA8LQogIHRoZW1lX2xpbmVkcmF3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQpgYGAKCmBgYHtyIERWX0NvZGUzLCBleGVyY2lzZT1UUlVFfQojIFRyeSB0aGlzIG91dCEKYGBgCgojIyMjIHsucmVjYWxsX2NvZGVfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKQ2FsY3VsYXRlIHRoZSB0b3RhbCBudW1iZXIgb2YgY291bnRyaWVzIHBlciB5ZWFyIHJlcG9ydGluZyBDMDIgZW1pc3Npb25zLCBlbmVyZ3kgdXNlIGFuZCBHRFAuIApQbG90IHRoaXMgc3VtbWFyeSBzdGF0aXN0aWMgKHktYXhpcykgYWNyb3NzIHRoZSB5ZWFycyAoeC1heGlzKS4gCldoYXQgZG8geW91IHNlZT8gCgo8Yj48dT4gSGludCA8L3U+PC9iPjogVXNlIHRoZSBgdGFsbHkoKWAgZnVuY3Rpb24gaW4gdGhlIGBkcGx5cmAgcGFja2FnZS4gCgojIyMjCgpgYGB7ciBEVl9Db2RlNC1zZXR1cH0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobWFncml0dHIpCmxvYWQoaGVyZTo6aGVyZSgid3d3IiwgImRhdGEiLCAid3JhbmdsZWQiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkKYGBgCgpgYGB7ciBEVl9Db2RlNCwgZXhlcmNpc2U9VFJVRX0KIyBZb3VyIGNvZGUgaGVyZQpgYGAKCgoKIyMjIExpbmUgc2VnbWVudCBwbG90cwoKVGhlcmUgYXJlIGFsc28gc29tZSBvdGhlciBjb21tb24gdmlzdWFsaXphdGlvbiB0ZWNobmlxdWVzIHRoYXQgYXJlIGdvb2QgZm9yIHNob3dpbmcgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBhIHNldCBvZiBvYnNlcnZhdGlvbnMgYW5kIGEgbWVhbiB2YWx1ZSBhY3Jvc3MgdGltZS4gCgpPbmUgb2YgdGhvc2UgaXMgYSBsaW5lIHNlZ21lbnQgcGxvdC4KRm9yIHNpbXBsaWNpdHksIGxldCdzIGZvY3VzIG9ubHkgb24gdGhlIGRhdGEgZnJvbSB0aGUgVVMuIApMZXQncyBjYWxjdWxhdGUgdGhlIG1lYW4gYWNyb3NzIGFsbCB5ZWFycyBmb3IgdGhlIENPMiBlbWlzc2lvbiBhbmQgdGVtcGVyYXR1cmUgZnJvbSAxOTgwIHRvIDIwMTAuClJlY2FsbCB0aGF0IG91ciBgSW5kaWNhdG9yYCB2YXJpYWJsZSBkZXNjcmliZXMgd2hhdCBraW5kIG9mIGRhdGEgd2UgaGF2ZSAoRW1pc3Npb25zLCBUZW1wZXJhdHVyZSwgR0RQLCBFbmVyZ3ksIERpc2FzdGVycykuCldlIHdpbGwgY2FsY3VsYXRlIHRoZSBtZWFuIGZvciBlYWNoIGBJbmRpY2F0b3JgIHNldCBvZiBkYXRhIGJ5IGZpcnN0IGdyb3VwaW5nIGJ5IHRoaXMgdmFyaWFibGUgYW5kIHRoZW4gY2FsY3VsYXRpbmcgdGhlIG1lYW4gb2YgdGhlIHZhbHVlcyBvZiB0aGUgYFZhbHVlYCB2YXJpYWJsZSBmb3IgZWFjaCBzZXQgb2YgZGF0YS4gCldlIHdpbGwgY2FsbCB0aGlzIG5ldyB2YXJpYWJsZSBgTWVhbmAuIApUaGVuLCB3ZSBjYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBlYWNoIG9ic2VydmF0aW9uIGFuZCB0aGUgbWVhbiBhbmQgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGZvciB0aGVzZSB2YWx1ZXMgY2FsbGVkIGBEaWZmX2Zyb21fbWVhbmAuICBBZ2FpbiwgYWxsIG9mIHRoaXMgaXMgcGVyZm9ybWVkIGZvciBlYWNoIGdyb3VwIG9mIGRhdGEgc2VwYXJhdGVseS4KT25jZSB3ZSBoYXZlIGNyZWF0ZWQgdGhlIG5ldyB2YXJpYWJsZXMsIHdlIHdhbnQgdG8gdXNlIHRoZSBgdW5ncm91cCgpYCBmdW5jdGlvbiBzbyB0aGF0IHdlIG5vIGxvbmdlciBwZXJmb3JtIGZ1bmN0aW9ucyBvbiBzdWJzZXRzIG9mIHRoZSBkYXRhIGJhc2VkIG9uIHRoZSBgSW5kaWNhdG9yYCB2YXJpYWJsZS4KRmluYWxseSwgd2Ugd2lsbCBhbHNvIGNyZWF0ZSBhIGZhY3RvciB2YXJpYWJsZSBhYm91dCB0aGUgc2lnbiBvZiB0aGUgYERpZmZfZnJvbV9tZWFuYCB2YWx1ZSB0byBkaXN0aW5ndWlzaCBwb3NpdGl2ZSBvciBuZWdhdGl2ZSBjaGFuZ2VzLiAKV2Ugd2lsbCB1c2UgdGhpcyB0byBjb2xvciBvdXIgcGxvdHMuCgpgYGB7cn0KZGF0YV9sb25nX3VzIDwtCiAgZGF0YV9sb25nICU+JQogIGZpbHRlcihDb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIiwgWWVhciA+PSAxOTgwLCBZZWFyIDw9IDIwMTApICU+JQogIGdyb3VwX2J5KEluZGljYXRvcikgJT4lCiAgbXV0YXRlKE1lYW4gPSBtZWFuKFZhbHVlKSwgRGlmZl9mcm9tX21lYW4gPSBWYWx1ZSAtIE1lYW4pICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoRGlmZl9jb2xvciA9IHNpZ24oRGlmZl9mcm9tX21lYW4pKSAlPiUKICBtdXRhdGUoRGlmZl9jb2xvciA9IGFzLmZhY3RvcihEaWZmX2NvbG9yKSkKYGBgCgpgYGB7cn0KZ2xpbXBzZShkYXRhX2xvbmdfdXMpCmBgYAoKTmV4dCwgd2UgdXNlIHRoZSBgZ2VvbV9zZWdtZW50KClgIGZ1bmN0aW9uIHRvIGRyYXcgYSBzdHJhaWdodCBsaW5lIGJldHdlZW4gcG9pbnRzIChgeGAsIGB5YCkgYW5kIChgeGVuZGAsIGB5ZW5kYCkuIApJbiBvdXIgY2FzZSwgdGhpcyBjcmVhdGVzIGEgcGxvdCB0aGF0IHNob3dzIGEgYmFyIGZvciB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBvYnNlcnZhdGlvbiBhbmQgdGhlIG1lYW4gYWNyb3NzIGFsbCB0aGUgeWVhcnMuCgpgYGB7ciwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KZGF0YV9sb25nX3VzICU+JQogIGZpbHRlcihJbmRpY2F0b3IgJWluJSBjKCJFbWlzc2lvbnMiLCAiVGVtcGVyYXR1cmUiLCAiRGlzYXN0ZXJzIikpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBWYWx1ZSkpICsKICAgIGdlb21fc2VnbWVudChhZXMoeCA9IFllYXIsIHkgPSBWYWx1ZSwgeGVuZCA9IFllYXIsCiAgICAgICAgICAgICAgICAgICAgIHllbmQgPSBNZWFuLCBjb2xvciA9IERpZmZfY29sb3IpLAogICAgICAgICAgICAgICAgIHNpemUgPSAzLjI1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiLCAicmVkIikpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gTWVhbiksIGxpbmV0eXBlID0gMSwgY29sb3IgPSAiYmxhY2siKSArCiAgZmFjZXRfd3JhcChJbmRpY2F0b3IgfiAuLCBzY2FsZXMgPSAiZnJlZV95IiwgbmNvbCA9IDEpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLAogICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAgKwogIGxhYnModGl0bGUgPSAiVVMgRGlzYXN0ZXJzLCBFbWlzc2lvbnMsIGFuZCBUZW1wZXJhdHVyZXMgKDE5OTAtMjAxMCkiLAogICAgc3VidGl0bGUgPSAiSW5kaWNhdG9yIE1lYW4gb2YgMTk5MC0yMDEwIFJlcHJlc2VudGVkIGJ5IFNvbGlkIEJsYWNrIExpbmUiKQpgYGAKV2UgY2FuIHNlZSBmcm9tIHRoaXMgcGxvdCB0aGF0IG92ZXJhbGwgdGhlcmUgaGFzIGJlZW4gYW4gaW5jcmVhc2UgaW4gZGlzYXN0ZXJzLCBlbWlzc2lvbnMgYW5kIHRlbXBlcmF0dXJlIGluIHRoZSBtb3N0IHJlY2VudCB5ZWFycy4gCgojIyMjIHsudGhpbmtfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKV2hhdCB0cmVuZHMgZG8geW91IHNlZSBpbiBHRFAgYW5kIGVuZXJneSB1c2UgYWNyb3NzIHRpbWU/IAoKIyMjIwoKCiMjIyBTY2F0dGVyIHBsb3RzCgpOZXh0LCBsZXQncyB6b29tIGluIG9uIHR3byBvZiB0aGUgdmFyaWFibGVzOiBDTzIgZW1pc3Npb25zIGFuZCB0ZW1wZXJhdHVyZS4gCldlIHVzZSB5ZWFycyBiZXR3ZWVuIDE5ODAgYW5kIDIwMTQgYXMgd2UgaGF2ZSB2YWx1ZXMgZm9yIGFsbCBvZiB0aG9zZSB5ZWFycyBmb3IgdGhlc2UgdHdvIHZhcmlhYmxlcy4gCgpXZSBrbm93IHRoYXQgdGhlIGRhdGFzZXRzIGRvIG5vdCBzcGFuIHRoZSBzYW1lIGFtb3VudCBvZiB0aW1lLiAKU28gbGV0J3MgbGltaXQgdGhpcyBwbG90IHRvIG9ubHkgdGhlIHllYXJzIHdoZXJlIHRoZSBkYXRhIG92ZXJsYXBzIGZvciBib3RoIENPMiBlbWlzc2lvbnMgYW5kIHRlbXBlcmF0dXJlLgoKV2UgdXNlIHRoZSBgZ2VvbV9wb2ludCgpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSBzY2F0dGVyIHBsb3QgYmV0d2VlbiB0aGUgYHhgIGFuZCBgeWAgdmFyaWFibGUgZGVmaW5lZCBpbiBgYWVzKClgIHdoZXJlIGB4YCBpcyB0aW1lIGFuZCBgeWAgaXMgb25lIG9mIHRoZSB0d28gdmFyaWFibGVzLiAKV2UgYWxzbyBhZGQgYSBsaW5lIG9uIHRvcCBvZiB0aGUgc2NhdHRlciBwbG90IHRoYXQgc21vb3RocyB0aGUgdHJlbmQgZnJvbSB0aGUgcG9pbnRzLiBUaGUgc21vb3RoZXIgd2UgdXNlZCBoZXJlIGlzIGBsb2Vzc2AgW2xvY2FsbHkgZXN0aW1hdGVkIHNjYXR0ZXJwbG90IHNtb290aGluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTG9jYWxfcmVncmVzc2lvbil7dGFyZ2V0PSJfYmxhbmsifSwgYSB0eXBlIG9mIFtsb2NhbCBwb2x5bm9taWFsIHJlZ3Jlc3Npb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xvY2FsX3JlZ3Jlc3Npb24pe3RhcmdldD0iX2JsYW5rIn0gZml0dGluZy4gVGhpcyBpcyBhIG5vbnBhcmFtZXRyaWMgcmVncmVzc2lvbiB0aGF0IGlzIGFsc28gY2FsbGVkIGEgIm1vdmluZyByZWdyZXNzaW9uIiB3aGVyZSBzdWJzZXRzIG9mIHBvaW50cyB0aGF0IGFyZSBjbG9zZSB0byBvbmUgYW5vdGhlciAoaGVuY2UgdGhlIHRlcm0gbG9jYWwpIGFyZSB1c2VkIGluIGEgbGVhc3Qgc3F1YXJlcyAgbGluZWFyIG9yIG5vbmxpbmVhciBmaXQuIFRodXMgdGhpcyByZXN1bHRzIGluIGEgZml0IHRoYXQgbWF5IGN1cnZlIHdpdGggdGhlIGRhdGEuCgpgYGB7cn0KQ08yX3RlbXBfVVNfZmFjZXQgPC0KICBkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKENvdW50cnkgPT0gIlVuaXRlZCBTdGF0ZXMiLCBZZWFyID49IDE5ODAsIFllYXIgPD0gMjAxNCwKICAgICAgICAgSW5kaWNhdG9yICVpbiUgYygiRW1pc3Npb25zIiwgIlRlbXBlcmF0dXJlIikpICU+JQogIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBWYWx1ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5ODAsIDIwMTQsIGJ5ID0gNSksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNlcSgxOTgwLCAyMDE0LCBieSA9IDUpKSArCiAgZmFjZXRfd3JhcChMYWJlbCB+IC4sIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBhbmdsZSA9IDkwLCBjb2xvciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQogIGxhYnModGl0bGUgPSAiVVMgRW1pc3Npb25zIGFuZCBUZW1wZXJhdHVyZXMgKDE5ODAtMjAxNCkiKQoKQ08yX3RlbXBfVVNfZmFjZXQKYGBgCgpOb3RlLCB3ZSBhcmUgc2hvd2luZyBhIGRpZmZlcmVudCBgdGhlbWVgIGhlcmUsIG5hbWVseSB0aGUgYHRoZW1lX2NsYXNzaWMoKWAgdGhlbWUuIApXZSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIHNpbWlsYXIgcGF0dGVybnMgb2YgQ08yIGVtaXNzaW9uIGxldmVscyBhbmQgYXZlcmFnZSBhbm51YWwgdGVtcGVyYXR1cmVzLgoKV2Ugd2lsbCBzYXZlIHRoaXMgcGxvdCBub3cgbGlrZSBzbyB0byBvdXIgInBsb3RzIiBkaXJlY3Rvcnk6CmBgYHtyLCBldmFsPUZBTFNFfQpzYXZlKENPMl90ZW1wX1VTX2ZhY2V0LCBmaWxlID1oZXJlOjpoZXJlKCJwbG90cyIsICJDTzJfdGVtcF9VU19mYWNldC5yZGEiKSkKcG5nKGhlcmU6OmhlcmUoInBsb3RzIiwgIkNPMl90ZW1wX1VTX2ZhY2V0LnBuZyIpKQpDTzJfdGVtcF9VU19mYWNldApkZXYub2ZmKCkKYGBgCgojIyMjIHsucmVjYWxsX2NvZGVfcXVlc3Rpb25fYmxvY2t9CjxiPjx1PiBRdWVzdGlvbiBPcHBvcnR1bml0eSA8L3U+PC9iPgoKLSBUcnkgc2hvdyBhIHNpbWlsYXIgcGxvdCB3aXRob3V0IGZpbHRlcmluZyBieSB5ZWFycyBhbmQgZmFjZXRpbmcgYnkgdGhlIG90aGVyIHRocmVlIHZhcmlhYmxlczogZW5lcmd5IHVzZSwgR0RQIGFuZCBkaXNhc3RlcnMuIEFyZSB0aGVyZSBvdGhlciB2YXJpYWJsZXMgdGhhdCBsb29rIGxpa2UgdGhleSBtaWdodCBoYXZlIGEgc2ltaWxhciBwYXR0ZXJuIHRvIENPMiBlbWlzc2lvbnM/IAotIFRyeSB1c2luZyBhIGRpZmZlcmVudCBzbW9vdGhlciBpbiBgZ2VvbV9zbW9vdGgoKWAuIAoKIyMjIwoKYGBge3IgRFZfQ29kZTUtc2V0dXB9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsb2FkKGhlcmU6OmhlcmUoInd3dyIsICJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX2RhdGEucmRhIikpCmBgYAoKYGBge3IgRFZfQ29kZTUsIGV4ZXJjaXNlPVRSVUV9CiMgWW91ciBjb2RlIGhlcmUKYGBgCgpOZXh0LCBpbnN0ZWFkIG9mIGxvb2tpbmcgYXQgdGhlIHZhcmlhYmxlcyBzZXBhcmF0ZWx5IGluIGZhY2V0ZWQgcGxvdHMsIGxldCdzIGxvb2sgYXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIENPMiBlbWlzc2lvbnMgYW5kIG90aGVyIHZhcmlhYmxlcyBkaXJlY3RseS4gVGh1cywgaXQgaXMgdXNlZnVsIHRvIGhhdmUgZWFjaCBvZiB0aGVzZSBpbmRpY2F0b3JzIGFzIHRoZWlyIG93biB2YXJpYWJsZS4KCldlIGNhbiBkbyB0aGlzIGJ5IHVzaW5nIGBwaXZvdF93aWRlcigpYCB0byB0cmFuc2Zvcm0gb3VyIGxvbmcgZGF0YSB0YWJsZSBpbnRvIGEgd2lkZSBmb3JtYXQuIAoKYGBge3J9CndpZGVfVVMgPC0KICBkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKENvdW50cnkgPT0gIlVuaXRlZCBTdGF0ZXMiLCBZZWFyID49IDE5ODAsIFllYXIgPD0gMjAxNCkgJT4lCiAgc2VsZWN0KC1MYWJlbCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEluZGljYXRvciwgdmFsdWVzX2Zyb20gPSBWYWx1ZSkKYGBgCgpMZXQncyBzYXZlIHRoaXMgZGF0YSBhcyBhbiByZGEgZmlsZSBmb3IgZnV0dXJlIHVzZSBhbmQgYXMgYSBjc3YgZmlsZSwgYXMgdGhpcyBpcyBvZnRlbiB1c2VmdWwgZm9yIGNvbGxhYm9yYXRvcnMuCldlIHdpbGwgc2F2ZSB0aGlzIGluIGEgIndyYW5nbGVkIiBzdWJkaXJlY3Rvcnkgb2Ygb3VyICJkYXRhIiBkaXJlY3Rvcnkgb2Ygb3VyIHdvcmtpbmcgZGlyZWN0b3J5LgoKYGBge3IsIGV2YWwgPSBGQUxTRX0Kc2F2ZSh3aWRlX1VTLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJ3cmFuZ2xlZF9VU19kYXRhLnJkYSIpKQpyZWFkcjo6d3JpdGVfY3N2KHdpZGVfVVMsIHBhdGggPSBoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX1VTX2RhdGEuY3N2IikpCmBgYAoKTm93IHdlIGNhbiBzcGVjaWZ5IHdoaWNoIGluZGljYXRvcnMgd2Ugd2FudCB0byBsb29rIGF0LCBzbyBub3cgd2UgY2FuIHNwZWNpZmljYWxseSBsb29rIGF0IGVtaXNzaW9ucyBhbmQgdGVtcGVyYXR1cmUuCgpgYGB7cn0KQ08yX3RlbXBfVVMgPC0KICB3aWRlX1VTICU+JQogIGdncGxvdChhZXMoeCA9IEVtaXNzaW9ucywgeSA9IFRlbXBlcmF0dXJlKSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkgKwogICAgbGFicyh0aXRsZSA9ICJVUyBFbWlzc2lvbnMgYW5kIFRlbXBlcmF0dXJlICgxOTgwLTIwMTQpIiwKICAgICAgICAgeCA9ICJFbWlzc2lvbnMgKE1ldHJpYyBUb25uZXMpIiwKICAgICAgICAgeSA9ICJUZW1wZXJhdHVyZSAoRmFocmVuaGVpdCkiKQoKCkNPMl90ZW1wX1VTCmBgYAoKSXQgbWlnaHQgYmUgaGVscGZ1bCB0byBhZGQgYSB0cmVuZCBsaW5lIHRvIHRoaXMuIFdlIGNhbiBkbyBzbyBieSB1c2luZyB0aGUgYGdlb21fc21vb3RoKClgIGZ1bmN0aW9uIG9mIHRoZSBgZ2dwbG90MmAgcGFja2FnZS4KCklmIHdlIHdhbnQgdG8gbG9vayBhdCBhIGxpbmVhciB0cmVuZCB3ZSBuZWVkIHRvIHNwZWNpZnkgdGhlIG1ldGhvZCB1c2luZyB0aGUgYG1ldGhvZCA9IGxtYCBhcmd1bWVudC4gVGhpcyBhZGRzIGEgbGluZSB0byB0aGUgZGF0YSBiYXNlZCBvbiBhIGxpbmVhciBtb2RlbCBvZiB0aGUgZGF0YSB1c2luZyB0aGUgYGxtYCBmdW5jdGlvbiBvZiB0aGUgYHN0YXRzYCBwYWNrYWdlLiBXZSB3aWxsIGRpc2N1c3MgdGhlIHNlID0gRkFMU0UgYXJndW1lbnQgbGF0ZXIuIAoKV2UgY2FuIGp1c3QgYWRkIHRoaXMgdG8gdGhlIHBsb3Qgb2JqZWN0IHRoYXQgd2UganVzdCBjcmVhdGVkIHRvIGNyZWF0ZSBhIHBsb3Qgd2l0aCB0aGlzIHRyZW5kIGxpbmUuCgpgYGB7cn0KQ08yX3RlbXBfVVMgPC0gQ08yX3RlbXBfVVMgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKQpDTzJfdGVtcF9VUyAKYGBgCgpJbmRlZWQsIGl0IGRvZXMgbG9vayBsaWtlIHRoZXJlIGlzIGEgcG9zaXRpdmUsIGxpbmVhciB0cmVuZC4gCgpXZSB3aWxsIGFsc28gc2F2ZSB0aGlzIHBsb3Q6CgpgYGB7ciwgZXZhbD1GQUxTRX0Kc2F2ZShDTzJfdGVtcF9VUywgZmlsZSA9aGVyZTo6aGVyZSgicGxvdHMiLCAiQ08yX3RlbXBfVVMucmRhIikpCnBuZyhoZXJlOjpoZXJlKCJwbG90cyIsICJDTzJfdGVtcF9VUy5wbmciKSkKQ08yX3RlbXBfVVMKZGV2Lm9mZigpCmBgYAoKIyMjIyB7LnJlY2FsbF9jb2RlX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCi0gTWFrZSBzaW1pbGFyIHBsb3RzIGZvciBiZXR3ZWVuIENPMiBlbWlzc2lvbnMgYW5kIG90aGVyIHZhcmlhYmxlcy4gCi0gQXJlIHRoZXJlIG90aGVyIHBhaXJzIHZhcmlhYmxlcyB0aGF0IGxvb2sgbGlrZSB0aGV5IG1pZ2h0IGhhdmUgYSBzaW1pbGFyIHBhdHRlcm4gdG8gQ08yIGVtaXNzaW9ucz8KLSBEb2VzIHRoaXMgbWF0Y2ggd2hhdCB3ZSBzYXcgYWJvdmU/IAotIERvIHRoZXNlIHRyZW5kIGxvb2sgbGluZWFyIG9yIG5vbi1saW5lYXI/IAoKIyMjIwoKYGBge3IgRFZfQ29kZTYtc2V0dXB9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsb2FkKGhlcmU6OmhlcmUoInd3dyIsICJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX2RhdGEucmRhIikpCndpZGVfVVMgPC0KICBkYXRhX2xvbmcgJT4lCiAgZmlsdGVyKENvdW50cnkgPT0gIlVuaXRlZCBTdGF0ZXMiLCBZZWFyID49IDE5ODAsIFllYXIgPD0gMjAxNCkgJT4lCiAgc2VsZWN0KC1MYWJlbCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEluZGljYXRvciwgdmFsdWVzX2Zyb20gPSBWYWx1ZSkKYGBgCgpgYGB7ciBEVl9Db2RlNiwgZXhlcmNpc2U9VFJVRX0KIyBZb3VyIGNvZGUgaGVyZQpgYGAKCk5vdyB0aGF0IHdlIHNlZSB0aGF0IHRoZXJlIG1pZ2h0IGJlIGEgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIENPMiBlbWlzc2lvbnMgYW5kIHRlbXBlcmF0dXJlLCBsZXQncyBsZWFybiBhYm91dCBzb21lIHN0YXRpc3RpY2FsIHRlY2huaXF1ZXMgdG8gbWVhc3VyZSB0aGUgc3RyZW5ndGggb2YgdGhhdCByZWxhdGlvbnNoaXAuIAoKIyMgKipFeGVyY2lzZSoqCioqKgoKYGBgIHtyIERWX1F1aXosIGVjaG8gPSBGQUxTRX0KcXVpeihjYXB0aW9uID0gIiIsCiAgcXVlc3Rpb24oIldoaWNoIG9uZSBvZiB0aGUgZm9sbG93aW5nIHRlcm1zIGluIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uIGlzIHVzZWQgdG8gZGVmaW5lIHRoZSBzaGFwZSwgdHJhbnNwYXJlbmN5LCBjb2xvciwgZmlsbCwgYW5kIGxpbmUgdHlwZXMgb2YgdGhlIHBsb3Q/IiwKICAgIGFuc3dlcigiZ2VvbSIsIG1lc3NhZ2UgPSAiR2VvbXMgZGVmaW5lIGdlb21ldHJpYyBvYmplY3RzLiIpLAogICAgYW5zd2VyKCJzY2FsZSIsIG1lc3NhZ2UgPSAiU2NhbGVzIGRlZmluZSBob3cgeW91ciBkYXRhIHdpbGwgYmUgcGxvdHRlZC4gRm9yIGV4YW1wbGUsIGNvbnRpbnVvdXMsIGRpc2NyZXRlLCBldGMuIiksCiAgICBhbnN3ZXIoImxhYnMiLCBtZXNzYWdlID0gImBsYWJzKClgIGZ1bmN0aW9uIGRlZmluZXMgdGl0bGUsIGNhcHRpb24sIGFuZCB0aGUgYXhpcyBsYWJlbHMuIiksCiAgICBhbnN3ZXIoImFlcyIsIGNvcnJlY3QgPSBUUlVFKSwKICAgIGFsbG93X3JldHJ5ID0gVFJVRSwKICAgIHJhbmRvbV9hbnN3ZXJfb3JkZXIgPSBUUlVFCiAgKSwKICBxdWVzdGlvbigiV2hhdCBkb2VzIHRoZSBgZmlsdGVyKClgIGZ1bmN0aW9uIGRvPyIsCiAgICBhbnN3ZXIoIlNlbGVjdHMgc3BlY2lmaWVkIGNvbHVtbnMuIiwgbWVzc2FnZSA9ICJUaGlzIGlzIHRoZSBmdW5jdGlvbiBvZiBgc2VsZWN0KClgLiIpLAogICAgYW5zd2VyKCJHcm91cHMgdGhlIGRhdGEgYnkgYSB2YXJpYWJsZS4iLCBtZXNzYWdlID0gIlRoaXMgaXMgdGhlIGZ1bmN0aW9uIG9mIGBncm91cF9ieSgpYC4iKSwKICAgIGFuc3dlcigiUmVvcmRlcnMgcm93cyBvZiBkYXRhIGJ5IGEgc3BlY2lmaWVkIHZhcmlhYmxlLiIsIG1lc3NhZ2UgPSAiVGhpcyBpcyB0aGUgZnVuY3Rpb24gb2YgYGFycmFuZ2UoKWAiKSwKICAgIGFuc3dlcigiRXh0cmFjdHMgYWxsIHJvd3MgdGhhdCBzYXRpc2Z5IGEgY29uZGl0aW9uLiIsIGNvcnJlY3QgPSBUUlVFKSwKICAgIGFsbG93X3JldHJ5ID0gVFJVRSwKICAgIHJhbmRvbV9hbnN3ZXJfb3JkZXIgPSBUUlVFCiAgKSwKICBxdWVzdGlvbigiSW5zaWRlIHRoZSBgZmFjZXRfZ3JpZCgpYCBmdW5jdGlvbiwgYEEgfiBCYCB0ZWxscyB5b3UgdG8gZmFjZXQgYnkgQSAoY29sdW1ucykgYW5kIEIgKHJvd3MpLiIsCiAgICBhbnN3ZXIoIlRydWUiLCBtZXNzYWdlID0gIlZhcmlhYmxlIG9uIHRoZSBsZWZ0IHNpZGUgb2YgYH5gIHRlbGxzIHlvdSB0byBmYWNldCBieSByb3dzLiBWYXJpYWJsZSBvbiB0aGUgcmlnaHQgc2lkZSB0ZWxscyB5b3UgdG8gZmFjZXQgYnkgY29sdW1ucy4iKSwKICAgIGFuc3dlcigiRmFsc2UiLCBjb3JyZWN0ID0gVFJVRSksCiAgICBhbGxvd19yZXRyeSA9IFRSVUUsCiAgICByYW5kb21fYW5zd2VyX29yZGVyID0gVFJVRQogICkKKQpgYGAKCiMjIyMgey5leGVyY2lzZV9ibG9ja30KClN1cHBvc2UgdGhhdCB3ZSBoYXZlIGEgZGF0YXNldCBjYWxsZWQgYHdlaWdodGAuIFdyaXRlIHNvbWUgY29kZSB0byBwbG90IHdlaWdodCBjaGFuZ2UgYnkgaW5kaXZpZHVhbC5cCldlIHdhbnQgdGhlIHBsb3QgdG86CgoqIGhhdmUgdGl0bGUgYXMgIldlaWdodCBDaGFuZ2UiCiogaGF2ZSAkeCQgYXhpcyBhcyAiVGltZV9kYXkiIGFuZCAkeSQgYXhpcyBiZSAiV2VpZ2h0X2xiIgoqIGJlIGEgbGluZSBwbG90CiogaGF2ZSBkaWZmZXJlbnQgY29sb3JzIHJlcHJlc2VudGluZyBJRHMgMSwgMiwgYW5kIDMKKiBoYXZlIGxlZ2VuZCBvbiB0aGUgcmlnaHQgb2YgdGhlIHBsb3QKCipOb3RlOiBmaXJzdCB3ZSBuZWVkIHRvIHVzZSBgYXMuY2hhcmFjdGVyKClgIHRvIGNvbnZlcnQgIklEIiBmcm9tIG51bWJlciB0byBjaGFyYWN0ZXIuKgoKYGBge3IsIERWX0V4ZXJjaXNlMS1zZXR1cH0Kd2VpZ2h0IDwtIGRhdGEuZnJhbWUoIklEIiA9IGMoMSwgMSwgMSwgMiwgMiwgMiwgMywgMywgMyksCiAgICAgICAgICAgICAgICAgICAgICJUaW1lX2RheSIgPSBjKDAsIDE1LCAzMCwgMCwgMTUsIDMwLCAwLCAxNSwgMzApLAogICAgICAgICAgICAgICAgICAgICAiV2VpZ2h0X2xiIiA9IGMoMTIwLCAxMjgsIDEyMiwgMTcyLCAxNzYsIDE4MCwgMTU1LCAxNTQsIDE1NSkpCmBgYAoKYGBge3IgRFZfRXhlcmNpc2UxLCBleGVyY2lzZT1UUlVFLCBleGVyY2lzZS5ldmFsPVRSVUUsIGV4ZXJjaXNlLmxpbmVzID0gNX0Kd2VpZ2h0CmBgYAoKYGBge3IgRFZfRXhlcmNpc2UxLWhpbnQtMX0Kd2VpZ2h0JElEIDwtIGFzLmNoYXJhY3Rlcih3ZWlnaHQkSUQpCmBgYAoKYGBge3IgRFZfRXhlcmNpc2UxLWhpbnQtMn0Kd2VpZ2h0JElEIDwtIGFzLmNoYXJhY3Rlcih3ZWlnaHQkSUQpCndlaWdodCAlPiUKICBnZ3Bsb3QoYWVzKCkpCmBgYAoKYGBge3IgRFZfRXhlcmNpc2UxLXNvbHV0aW9ufQp3ZWlnaHQkSUQgPC0gYXMuY2hhcmFjdGVyKHdlaWdodCRJRCkKd2VpZ2h0ICU+JQogIGdncGxvdChhZXMoeCA9IFRpbWVfZGF5LCB5ID0gV2VpZ2h0X2xiLCBjb2xvciA9IElEKSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKHRpdGxlID0gIldlaWdodCBDaGFuZ2UiKQpgYGAKCiMjIyMKCiMgKipEYXRhIEFuYWx5c2lzKioKKioqCiAKSWYgeW91IGFyZSBmb2xsb3dpbmcgYWxvbmcgYW5kIHN0b3BwZWQgeW91IGNvdWxkIGxvYWQgdGhlIGRhdGEgeW91IHdpbGwgbmVlZCBsaWtlIHNvOgoKYGBge3IsIGV2YWw9RkFMU0V9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YSIsICJ3cmFuZ2xlZCIsICJ3cmFuZ2xlZF9VU19kYXRhLnJkYSIpKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpsb2FkKCJ3d3cvZGF0YS93cmFuZ2xlZC93cmFuZ2xlZF9VU19kYXRhLnJkYSIpCmBgYAoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT4gSWYgeW91IHNraXBwZWQgdGhlIHByZXZpb3VzIHNlY3Rpb25zIGNsaWNrIGhlcmUuIDwvc3VtbWFyeT4KCkFuIFJEQSBmaWxlIChzdGFuZHMgZm9yIFIgZGF0YSkgb2YgdGhlIGRhdGEgKGNhbGxlZCBgd3JhbmdsZWRfVVNfZGF0YS5yZGFgKSBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS8vb3BlbmNhc2VzdHVkaWVzL29jcy1icC1jbzItZW1pc3Npb25zL3RyZWUvbWFzdGVyL2RhdGEvd3JhbmdsZWQpIG9yIHNsaWdodGx5IG1vcmUgZGlyZWN0bHkgW2hlcmVdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLWNvMi1lbWlzc2lvbnMvbWFzdGVyL2RhdGEvd3JhbmdsZWQvd3JhbmdsZWRfVVNfZGF0YS5yZGEpLiBEb3dubG9hZCB0aGlzIGZpbGUgYW5kIHRoZW4gcGxhY2UgaXQgaW4geW91ciBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IHdpdGhpbiBhIHN1YmRpcmVjdG9yeSBjYWxsZWQgIndyYW5nbGVkIiB3aXRoaW4gYSBzdWJkaXJlY3RvcnkgY2FsbGVkICJkYXRhIiB0byBjb3B5IGFuZCBwYXN0ZSBvdXIgY29kZS4gV2UgdXNlZCBhbiBSU3R1ZGlvIHByb2plY3QgYW5kIHRoZSBbYGhlcmVgIHBhY2thZ2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbmF2aWdhdGUgdG8gdGhlIGZpbGUgbW9yZSBlYXNpbHkuCgpgYGB7ciwgZXZhbD1GQUxTRX0KbG9hZChoZXJlOjpoZXJlKCJkYXRhIiwgIndyYW5nbGVkIiwgIndyYW5nbGVkX1VTX2RhdGEucmRhIikpCmBgYAoKCioqKgo8ZGV0YWlscz4gPHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIG1vcmUgYWJvdXQgY3JlYXRpbmcgbmV3IHByb2plY3RzIGluIFJTdHVkaW8uIDwvc3VtbWFyeT4KCllvdSBjYW4gY3JlYXRlIGEgcHJvamVjdCBieSBnb2luZyB0byB0aGUgRmlsZSBtZW51IG9mIFJTdHVkaW8gbGlrZSBzbzoKCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL05ld19wcm9qZWN0LnBuZyIpCmBgYAoKWW91IGNhbiBhbHNvIGRvIHNvIGJ5IGNsaWNraW5nIHRoZSBwcm9qZWN0IGJ1dHRvbjoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInd3dy9pbWcvcHJvamVjdF9idXR0b24ucG5nIikKYGBgCgpTZWUgW2hlcmVdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdXNpbmcgUlN0dWRpbyBwcm9qZWN0cyBhbmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgYGhlcmVgIHBhY2thZ2UuCgo8L2RldGFpbHM+CioqKgo8L2RldGFpbHM+CioqKgoKCgpJbiB0aGlzIHNlY3Rpb24sIHdlIGFyZSBnb2luZyB0byBpbnRyb2R1Y2Ugc29tZSB3YXlzIHRvIGJldHRlciB1bmRlcnN0YW5kIGhvdyB0d28gdmFyaWFibGVzIG1vdmUgdG9nZXRoZXIuIApXZSB3aWxsIGZvY3VzIG9uIHRoZSBDTzIgZW1pc3Npb25zIGFuZCB0ZW1wZXJhdHVyZSwgYnV0IHlvdSB3aWxsIGJlIGVuY291cmFnZWQgdG8gZXhwbG9yZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gQ08yIGVtaXNzaW9ucyBhbmQgdGhlIG90aGVyIHZhcmlhYmxlcy4gCgojIyMgKipCYXNpYyBzdW1tYXJ5IHN0YXRpc3RpY3MqKgoqKioKCldlIGNhbiBhbHdheXMgY2FsY3VsYXRlIHRoZSBzYW1wbGUgbWVhbiBhbmQgdmFyaWFuY2UgZm9yIHR3byB2YXJpYWJsZXMuIAoKYGBge3J9CndpZGVfVVMgJT4lCiAgc3VtbWFyaXplKG1lYW4oRW1pc3Npb25zKSwgbWVhbihUZW1wZXJhdHVyZSksIHNkKEVtaXNzaW9ucyksIHNkKFRlbXBlcmF0dXJlKSkKYGBgCgpUaGVzZSBhcmUgdXNlZnVsLCBidXQgb24gdGhlaXIgb3duIHRoZXkgZG8gbm90IHN1bW1hcml6ZSB3aGV0aGVyIG9yIG5vdCB0aGVyZSBpcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGBFbWlzc2lvbnNgIGFuZCBgVGVtcGVyYXR1cmVgIChhbHNvIHRoZXNlIGFyZSBvbiBkaWZmZXJlbnQgc2NhbGVzIGVudGlyZWx5KS4gCgpXaGF0IGVsc2UgY291bGQgd2UgdXNlPyAKTmV4dCwgd2UgYXJlIGdvaW5nIHRvIGxlYXJuIGFib3V0IHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCwgd2hpY2ggaXMgYSBzdW1tYXJ5IHN0YXRpc3RpYyB0aGF0IGRlc2NyaWJlcyBob3cgdHdvIHZhcmlhYmxlcyBhcmUgcmVsYXRlZCBvciBtb3ZlIHRvZ2V0aGVyLiAKCiMjIyAqKkNvcnJlbGF0aW9uIGNvZWZmaWNpZW50KioKKioqCgpXZSBjYW4gdXNlIHRoZSBbY29ycmVsYXRpb24gY29lZmZpY2llbnRdKGh0dHBzOi8vcmFmYWxhYi5naXRodWIuaW8vZHNib29rL3JlZ3Jlc3Npb24uaHRtbCNjb3JyLWNvZWZsKXt0YXJnZXQ9Il9ibGFuayJ9LiAKSGVyZSwgd2UgYXJlIHVzaW5nIHRoaXMgc3VtbWFyeSBzdGF0aXN0aWMgdG8gbWVhc3VyZSB0aGUgc3RyZW5ndGggb2YgYSBfbGluZWFyXyByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gdmFyaWFibGVzLiAKCklmIHdlIHBsb3Qgb25lIHZhcmlhYmxlIG9uIHRoZSB4LWF4aXMgYW5kIHRoZSBvdGhlciB2YXJpYWJsZSBvbiB0aGUgeS1heGlzLCB3ZSBjYW4gc2VlOgoKMS4gVGhlIHN0cmVuZ3RoIG9mIHRoZSByZWxhdGlvbnNoaXAgLSBiYXNlZCBvbiBob3cgd2VsbCB0aGUgcG9pbnRzIGZvcm0gYSBsaW5lICAKMi4gVGhlIGRpcmVjdGlvbiBvZiB0aGUgcmVsYXRpb25zaGlwIC0gYmFzZWQgb24gaWYgdGhlIHBvaW50cyBwcm9ncmVzcyB1cHdhcmQgb3IgZG93bndhcmQgCgpJZiB0aGUgdmFyaWFibGVzIHBvaW50IHVwd2FyZCBpbiBhIHZlcnkgY2xlYXIgbGluZSwgdGhlbiB0aGVyZSBpcyBhIHN0cm9uZyBwb3NpdGl2ZSByZWxhdGlvbnNoaXAuIApJZiB0aGUgcG9pbnRzIGRvIG5vdCByZWFsbHkgZm9ybSBhIGxpbmUsIHRoZW4gdGhlcmUgaXMgYSB3ZWFrIGxpbmVhciByZWxhdGlvbnNoaXAgb3Igbm8gbGluZWFyIHJlbGF0aW9uc2hpcC4gVGhlcmUgbWF5IGhvd2V2ZXIgYmUgYSBub25saW5lYXIgcmVsYXRpb25zaGlwIGlmIHRoZSBwb2ludHMgY3JlYXRlIGEgZGlmZmVyZW50IGJ1dCBkZWZpbmVkIHNoYXBlLiAKClNlZSBbaGVyZV0oaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL2VzdGltYXRpbmctbm9uLWxpbmVhci1jb3JyZWxhdGlvbi1pbi1yLTYyYzY1NzFjYjFkYil7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBub25saW5lYXIgcmVsYXRpb25zaGlwcy4KCklmIHRoZSBwb2ludHMgZm9ybSBhIGRvd253YXJkIHNsb3BpbmcgbGluZSwgdGhlbiB0aGVyZSBpcyBhIG5lZ2F0aXZlIHJlbGF0aW9uc2hpcC4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnaHR0cHM6Ly93d3cubWF0aHNpc2Z1bi5jb20vZGF0YS9pbWFnZXMvY29ycmVsYXRpb24tZXhhbXBsZXMuc3ZnJykKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lm1hdGhzaXNmdW4uY29tL2RhdGEvY29ycmVsYXRpb24uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifQoKVGhlIG51bWJlcnMgYmVsb3cgZWFjaCBwbG90IGFib3ZlIGFyZSBjYWxsZWQgY29ycmVsYXRpb24gY29lZmZpY2llbnRzLiAKVGhleSByYW5nZSBmcm9tIC0xIHRvIDEuIApBIHZhbHVlIG9mIHplcm8gaW5kaWNhdGVzIHRoYXQgdGhlcmUgaXMgbm8gY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgdmFyaWFibGVzLiAKV2hpbGUgYSB2YWx1ZSBvZiAxIG9yIC0xIGluZGljYXRlcyBwZXJmZWN0IGNvcnJlbGF0aW9uLCB0aGUgY2xvc2VyIHRoZSBjb2VmZmljaWVudCBpcyB0byAxIG9yIC0xLCB0aGUgc3Ryb25nZXIgdGhlIHJlbGF0aW9uc2hpcC4gClRoZSBzaWduIG9mIHRoZSBjb2VmZmljaWVudCBpbmRpY2F0ZXMgdGhlIGRpcmVjdGlvbiBvZiB0aGUgcmVsYXRpb25zaGlwLiAKSWYgdGhlcmUgaXMgYSBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgdGhlbiB0aGUgdmFyaWFibGVzIHNob3cgb3Bwb3NpbmcgY2hhbmdlcyBmcm9tIGVhY2ggb3RoZXIgLSBhcyBvbmUgZ2V0cyBsYXJnZXIgdGhlIG90aGVyIGdldHMgc21hbGxlci4gCklmIHRoZSBzaWduIGlzIHBvc2l0aXZlLCB0aGVuIHRoZSB2YXJpYWJsZXMgaW5jcmVhc2Ugc2ltaWxhcmx5LiAKCldlIHByZXZpb3VzbHkgbWFkZSB0aGlzIHBsb3Q6CgpgYGB7ciwgZXZhbD1GQUxTRX0KbG9hZChoZXJlOjpoZXJlKCJwbG90cyIsICJDTzJfdGVtcF9VUy5yZGEiKSkKQ08yX3RlbXBfVVMKCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CmxvYWQoInd3dy9wbG90cy9DTzJfdGVtcF9VUy5yZGEiKQpDTzJfdGVtcF9VUwoKYGBgCgpMZXQncyBjYWxjdWxhdGUgdGhlIFBlYXJzb24ncyBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBjYWxsZWQgIlJobyIgJFxyaG8kIGJldHdlZW4gQ08yIGVtaXNzaW9ucyBhbmQgdGVtcGVyYXR1cmUgaW4gdGhlIFVTLiBUaGVyZSBhcmUgYSBmZXcgd2F5cyB0byBjYWxjdWxhdGUgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBhbmQgdGhpcyBpcyBvbmUgb2YgdGhlIG1vc3QgY29tbW9uLgoKRm9ybWFsbHksIGlmIHdlIGhhdmUgYSBwYWlyIG9mIG9ic2VydmF0aW9ucyAkKHhfMSwgeV8xKSwgXGRvdHMsICh4X24seV9uKSQsIHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCAkXHJobyQgYmV0d2VlbiAkeCQgYW5kICR5JCBpcyBkZWZpbmVkIGFzIAoKJCQKXHJobyA9IFxmcmFjezF9e24tMX0gXHN1bV97aT0xfV5uIFxsZWZ0KCBcZnJhY3t4X2ktXG11X3h9e1xzaWdtYV94fSBccmlnaHQpXGxlZnQoIFxmcmFje3lfaS1cbXVfeX17XHNpZ21hX3l9IFxyaWdodCkKJCQKd2hlcmUgJFxtdV94LCBcbXVfeSQgYXJlIHRoZSBtZWFucyBvZiAkeF8xLFxkb3RzLCB4X24kIGFuZCAkeV8xLCBcZG90cywgeV9uJCwgcmVzcGVjdGl2ZWx5LCBhbmQgJFxzaWdtYV94LCBcc2lnbWFfeSQgYXJlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb25zLiAKClRoZXJlZm9yZSwgd2UgY2FuIHN0YW5kYXJkaXplIHRoZSB0d28gdmFyaWFibGVzIGFuZCBlc3NlbnRpYWxseSBhdmVyYWdlICh0aGUgZGVub21pbmF0b3IgaXMgbi0xKSB0aGUgc3RhbmRhcmRpemVkIHZhbHVlcyB0byBjYWxjdWxhdGUgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGByaG9gLiAKCkhlcmUgd2Ugd2lsbCBtYW51YWxseSBwZXJmb3JtIHRoZSBjYWxjdWxhdGlvbi4gV2Ugd2lsbCB1c2UgdGhlIGB0YWxseSgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGdldCB0aGUgbnVtYmVyIG9mIHNhbXBsZXMgJG4kLiBJbiB0aGlzIGNhc2UgdGhpcyBpcyBlcXVpdmFsZW50IHRvIHRoZSBudW1iZXIgb2Ygcm93cyBpbiB0aGUgYHdpZGVfVVNgIHRpYmJsZS4gV2UgbmVlZCB0byB0aGVuIHVzZSB0aGUgYHB1bGwoKWAgZnVuY3Rpb24gdG8gc3BlY2lmaWNhbGx5IGdyYWIgdGhlIHZhbHVlIG91dCBvZiB0aGUgdGliYmxlIHRoYXQgaXMgY3JlYXRlZCBmcm9tIHVzaW5nIHRoaXMgZnVuY3Rpb24uIEFzIHlvdSBjYW4gc2VlIGZyb20gdXNpbmcgdGhlIGJhc2UgYGNsYXNzKClgIGZ1bmN0aW9uIHRoYXQgdGhpcyBpcyBhIGB0YmxfZGZgIHdoaWNoIGlzIHNob3J0IGZvciB0aWJibGUgZGF0YSBmcmFtZSAodGhlIHRpZHl2ZXJzZSB2ZXJzaW9uIG9mIGEgZGF0YSBmcmFtZSkgcmF0aGVyIHRoYW4ganVzdCBhIG51bWJlci4gCgpgYGB7cn0KdGFsbHkod2lkZV9VUykKY2xhc3ModGFsbHkod2lkZV9VUykpCmBgYAoKV2hlbiB3ZSBjaGVjayB0aGUgY2xhc3MgYWZ0ZXIgdXNpbmcgdGhlIGBwdWxsKClgIGZ1bmN0aW9uIHdlIHNlZSB0aGF0IGl0IGlzIGFuIGludGVnZXIuCgpgYGB7cn0KcHVsbCh0YWxseSh3aWRlX1VTKSwgbikKY2xhc3MocHVsbCh0YWxseSh3aWRlX1VTKSwgbikpCmBgYAoKV2Ugd2lsbCBhbHNvIHVzZSB0aGUgYmFzZSBgc2NhbGUoKWAgZnVuY3Rpb24gdG8gc3RhbmRhcmRpemUgdGhlIGBFbWlzc2lvbnNgIGFuZCBgVGVtcGVyYXR1cmVgIHZhbHVlcy4KYGBge3J9CndpZGVfVVMgJT4lCiAgc3VtbWFyaXplKHJobyA9ICgxLyhwdWxsKHRhbGx5KHdpZGVfVVMpLCBuKSAtMSkpICooc3VtKHNjYWxlKEVtaXNzaW9ucykgKiBzY2FsZShUZW1wZXJhdHVyZSkpKSkgJT4lCiAgcHVsbChyaG8pCmBgYAoKQWx0ZXJuYXRpdmVseSwgeW91IGNhbiB1c2UgdGhlIGBjb3IoKWAgZnVuY3Rpb24gaW4gYmFzZSBSIGxpa2Ugc286CgpgYGB7cn0Kd2lkZV9VUyAlPiUKICBzdW1tYXJpemUociA9IGNvcih4ID0gRW1pc3Npb25zLAogICAgICAgICAgICAgICAgICAgIHkgPSBUZW1wZXJhdHVyZSwgCiAgICAgICAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIikpICU+JQogIHB1bGwocikKYGBgCgpJZiB5b3Ugd2FudCB0byBsZWFybiBtb3JlIGFib3V0IHdoeSB0aGlzIGlzIHRoZSBjYWxjdWxhdGlvbiB0byBkZXRlcm1pbmUgdGhlIHN0cmVuZ3RoIG9mIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gdmFyaWFibGVzLCBzZWUgdGhpcyBbbGlua10oaHR0cHM6Ly9iY2hlZ2dlc2V0aC5naXRodWIuaW8vU3RhdDE1NU5vdGVzL3R3by1xdWFudGl0YXRpdmUtdmFyaWFibGVzLmh0bWwpLiAKCiMjIyMgey5yZWNhbGxfY29kZV9xdWVzdGlvbl9ibG9ja30KPGI+PHU+IFF1ZXN0aW9uIE9wcG9ydHVuaXR5IDwvdT48L2I+CgpUaGVyZSBhcmUgZGlmZmVyZW50IHR5cGVzIG9mIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cy4gTG9vayBhdCB0aGUgaGVscCBmaWxlIGZvciB0aGUgYGNvcigpYCBmdW5jdGlvbiBieSB0eXBpbmcgYD9jb3IoKWAgaW50byB0aGUgUlN0dWRpbyBDb25zb2xlIHRvIGxlYXJuIG1vcmUgYW5kIHRoZW4gdHJ5IGEgZGlmZmVyZW50IGBtZXRob2RgLiAKCldoYXQgYXJlIHRoZSBkaWZmZXJlbmNlcz8gCgojIyMjCgoKIyMjIyB7LnRoaW5rX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCi0gVHJ5IGNhbGN1bGF0aW5nIHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBiZXR3ZWVuIENPMiBlbWlzc2lvbnMgYW5kIHRoZSBvdGhlciB2YXJpYWJsZXMuIAotIFdoYXQgZG8geW91IGV4cGVjdD8gCgojIyMjCgpUbyB0ZXN0IGlmIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGEgcGFpciBvZiB2YXJpYWJsZXMgaXMgW3N0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnRdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1N0YXRpc3RpY2FsX3NpZ25pZmljYW5jZSksIHlvdSBjYW4gdXNlIHRoZSBgY29yLnRlc3QoKWAgb2YgdGhlIGBzdGF0c2AgcGFja2FnZSB0byBjYWxjdWxhdGUgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50LCBhcyB3ZWxsIGFzIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGZvciBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMuCgpXZSBjYW4gdXNlIHRoZSBgdGlkeSgpYCBmdW5jdGlvbiBvZiB0aGUgYGJyb29tYCBwYWNrYWdlIHRvIG1ha2UgdGhlIG91dHB1dCBtb3JlIHVzYWJsZSBmb3Igd29ya2luZyB3aXRoIGluIFIuIFRoZSByb2xlIG9mIHRoaXMgZnVuY3Rpb24gaXMgdG8gcHVsbCBudW1lcmljIHZhbHVlcyBmcm9tIG91dHB1dHMgYW5kIGNyZWF0ZSBhIGRhdGEgZnJhbWUgb2YgdGhlIHZhbHVlcy4KCmBgYHtyfQoKY29yLnRlc3QocHVsbCh3aWRlX1VTLCBFbWlzc2lvbnMpLAogICAgICAgICBwdWxsKHdpZGVfVVMsIFRlbXBlcmF0dXJlKSkKCmJyb29tOjp0aWR5KGNvci50ZXN0KHB1bGwod2lkZV9VUywgRW1pc3Npb25zKSwKICAgICAgICAgcHVsbCh3aWRlX1VTLCBUZW1wZXJhdHVyZSkpKQpgYGAKCldlIHNlZSB0aGF0IHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBxdWFudGlmeWluZyB0aGUgc3RyZW5ndGggb2YgdGhlIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBDMDIgZW1pc3Npb25zIGFuZCB0ZW1wZXJhdHVyZSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LgoKIyMjICoqUmVsYXRpb25zaGlwIGJldHdlZW4gY29ycmVsYXRpb24gYW5kIGxpbmVhciByZWdyZXNzaW9uKioKKioqCgpMZXQncyBicmllZmx5IGRpc2N1c3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNvcnJlbGF0aW9uIGFuZCBsaW5lYXIgcmVncmVzc2lvbiwgd2hpY2ggaXMgZnVydGhlciBkZXNjcmliZWQgaW4gdGhlIFtJbnRyb2R1Y3Rpb24gdG8gRGF0YSBTY2llbmNlIGJvb2tdKGh0dHBzOi8vcmFmYWxhYi5naXRodWIuaW8vZHNib29rL3JlZ3Jlc3Npb24uaHRtbCkuIAoKV2UgY2FuIHVzZSBhIHJlZ3Jlc3Npb24gbGluZSB0byBwcmVkaWN0IGEgcmFuZG9tIHZhcmlhYmxlICRZJCBnaXZlbiB0aGF0IHdlIGhhdmUgZ2F0aGVyZWQgb3Igb2JzZXJ2ZWQgc29tZSBkYXRhIGFib3V0IGFub3RoZXIgdmFyaWFibGUgJFg9eCQuIApUaGUgcmVncmVzc2lvbiBsaW5lIGZvcm1hbGx5IGlzIGRlZmluZWQgYXM6CgokJCBcbGVmdCggXGZyYWN7WS1cbXVfWX17XHNpZ21hX1l9IFxyaWdodCkgPSBccmhvIFxsZWZ0KCBcZnJhY3t4LVxtdV9YfXtcc2lnbWFfWH0gXHJpZ2h0KSAkJAp3aGVyZSAkXG11X1gkIGFuZCAkXHNpZ21hX1gkICgkXG11X1kkIGFuZCAkXHNpZ21hX1kkKSBhcmUgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAkWCQgKCRZJCksIGFuZCAkXHJobyQgaXMgY29ycmVsYXRpb24gYmV0d2VlbiAkWCQgYW5kICRZJC4gCklmICR4JCBpcyBsYXJnZXIgdGhhbiAkXG11X1gkLCB0aGVuIGZvciBldmVyeSAkXHNpZ21hX1gkLCB0aGVuICRZJCB3aWxsIGFsc28gaW5jcmVhc2UgJFxyaG8kIHN0YW5kYXJkIGRldmlhdGlvbnMgYWJvdmUgJFxtdV9ZJC4gCgpSZS1vcmdhbml6aW5nIHRoZSB0ZXJtcyBzbyB0aGF0ICRZJCBpcyBvbiB0aGUgbGVmdCBzaWRlIGFuZCBldmVyeXRoaW5nIGVsc2UgaXMgb24gdGhlIHJpZ2h0IHNpZGUsIHdlIGdldDoKCiQkIFkgPSBcbXVfWSArIFxyaG8gXGxlZnQoIFxmcmFje3gtXG11X1h9e1xzaWdtYV9YfSBccmlnaHQpIFxzaWdtYV9ZICQkClRoaW5raW5nIGFib3V0IHNvbWUgZXh0cmVtZSBleGFtcGxlczogCgotIElmICRccmhvJCA9IDAgKGkuZS4gbm8gY29ycmVsYXRpb24pLCB3ZSBpZ25vcmUgdGhlICR4JCB0ZXJtIGVudGlyZWx5IGFuZCBvbmx5IHByZWRpY3QgJFkkIHVzaW5nIHRoZSBtZWFuICRcbXVfWSQuIAotIElmICRccmhvJCA9IDEgKG9yIC0xKSAoaS5lLiBwZXJmZWN0IGNvcnJlbGF0aW9uKSwgdGhlIHJlZ3Jlc3Npb24gbGluZSBwcmVkaWN0cyBhbiBpbmNyZWFzZSAob3IgZGVjcmVhc2UpIHRoYXQgaXMgdGhlIHNhbWUgbnVtYmVyIG9mIFNEcy4gCi0gSWYgJFxyaG8kIGlzIGJldHdlZW4gLTEgYW5kIDEsIHRoZW4gd2UgcHJlZGljdCB1c2luZyBib3RoIHRlcm1zIG9uIHRoZSByaWdodCBoYW5kIHNpZGUuIAoKVG8gYWRkIHJlZ3Jlc3Npb24gbGluZXMgdG8gcGxvdHMsIHdlIHdpbGwgbmVlZCB0aGUgYWJvdmUgZm9ybXVsYSBpbiB0aGUgZm9ybTogCgokJAp5PSBiICsgbXggXG1ib3h7IHdpdGggc2xvcGUgfSBtID0gXHJobyBcZnJhY3tcc2lnbWFfeX17XHNpZ21hX3h9IFxtYm94eyBhbmQgaW50ZXJjZXB0IH0gYj1cbXVfeSAtIG0gXG11X3gKJCQKCkluIG91ciBleGFtcGxlLCB3ZSBjYW4gY2FsY3VsYXRlIHRoZSBzbG9wZSBhbmQgaW50ZXJjZXB0IHVzaW5nIHRoZSBmb3JtdWxhIGFib3ZlIGFuZCBwbG90IHRoZSBsaW5lLiAKYGBge3J9CndpZGVfVVNfc3VtbWFyeSA8LQogIHdpZGVfVVMgJT4lCiAgc3VtbWFyaXplKG11X3ggPSBtZWFuKEVtaXNzaW9ucyksIHNkX3ggPSBzZChFbWlzc2lvbnMpLAogICAgICAgICAgICBtdV95ID0gbWVhbihUZW1wZXJhdHVyZSksIHNkX3kgPSBzZChUZW1wZXJhdHVyZSksCiAgICAgICAgICAgIHJobyA9IGNvcihFbWlzc2lvbnMsIFRlbXBlcmF0dXJlKSwKICAgICAgICAgICAgc2xvcGUgPSByaG8gKiBzZF95IC8gc2RfeCwKICAgICAgICAgICAgaW50ZXJjZXB0ID0gbXVfeSAtIHJobyAqIHNkX3kgLyBzZF94ICogbXVfeCkKCndpZGVfVVMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRW1pc3Npb25zLCB5ID0gVGVtcGVyYXR1cmUpKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSB3aWRlX1VTX3N1bW1hcnkkc2xvcGUsCiAgICAgICAgICAgICAgICBpbnRlcmNlcHQgPSB3aWRlX1VTX3N1bW1hcnkkaW50ZXJjZXB0KSArCiAgdGhlbWVfbGluZWRyYXcoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpCmBgYAoKKipOb3RlKio6IEluIHRoZSBwbG90IGFib3ZlLCB3ZSB1c2UgdGhlIHNjYWxlIG9mIHRoZSBvcmlnaW5hbCB2YXJpYWJsZXMgKENPMiBlbWlzc2lvbiBhbmQgdGVtcGVyYXR1cmUpLCBidXQgdGhlIGZvcm11bGEgYWJvdmUgaW1wbGllcyB0aGF0IHN0YW5kYXJkaXphdGlvbiBvZiB0aGUgdmFyaWFibGVzIChpLmUuIHN1YnRyYWN0aW5nIHRoZSBtZWFuIGFuZCBkaXZpZGluZyBieSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uKSBhbGxvd3MgdGhlIHJlZ3Jlc3Npb24gbGluZSB0byBoYXZlIGFuIGludGVyY2VwdCBvZiAwIGFuZCBzbG9wZSBlcXVhbCB0byAkXHJobyQuIEEgc2ltaWxhciBwbG90IGluIHN0YW5kYXJkaXplZCB1bml0cyBpcyBnaXZlbiBiZWxvdy4gIAoKYGBge3J9IApDTzJfdGVtcF9VU19zY2FsZWQ8LXdpZGVfVVMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2NhbGUoRW1pc3Npb25zKSwgeSA9IHNjYWxlKFRlbXBlcmF0dXJlKSkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgbGFicyh0aXRsZSA9ICJVUyIgfiBDT1syXX4gIkVtaXNzaW9ucyBhbmQgVGVtcGVyYXR1cmUgKDE5ODAtMjAxNCkiLAogICAgICAgICB5ID0gIlNjYWxlZCBUZW1wZXJhdHVyZSAoRmFocmVuaGVpdCkiLAogICAgICAgICB4ID0gIlNjYWxlZCBFbWlzc2lvbnMgKE1ldHJpYyBUb25uZXMpIikgKwogIHRoZW1lX2xpbmVkcmF3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQoKQ08yX3RlbXBfVVNfc2NhbGVkCmBgYAoKTm90aWNlIHRoYXQgd2UgYWxzbyB1c2UgdGhlIGBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKWAgZnVuY3Rpb24gdGhhdCB3ZSBwcmV2aW91c2x5IHVzZWQuIEFnYWluLCB0aGlzIGFkZHMgYSBsaW5lIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHNsb3BlIGFuZCBpbnRlcmNlcHQgZnJvbSB0aGUgYGxtKClgIGZ1bmN0aW9uIGZyb20gdGhlIGBzdGF0c2AgUiBwYWNrYWdlLiAKCgoKIyMjIyB7LnRoaW5rX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gUXVlc3Rpb24gT3Bwb3J0dW5pdHkgPC91PjwvYj4KCldoYXQgZG9lcyBgc2UgPSBGQUxTRWAgbWVhbj8gVHJ5IHR1cm5pbmcgaXQgdG8gVFJVRS4gV2hhdCBoYXBwZW5zPyAKCiMjIyMKCmBgYHtyIERBX0NvZGUxLCBleGVyY2lzZT1UUlVFfQojIFRyeSB0aGlzIG91dCEKYGBgCgoqKioKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciB0aGUgYW5zd2VyLjwvc3VtbWFyeT4KYHNlYCBzdGFuZHMgZm9yIHN0YW5kYXJkIGVycm9yLiBUaGUgZ3JheSBzaGFkaW5nIHNob3dzIHRoZSBbY29uZmlkZW5jZSBpbnRlcnZhbF0oaHR0cHM6Ly9zdGF0dHJlay5jb20vcmVncmVzc2lvbi9zbG9wZS1jb25maWRlbmNlLWludGVydmFsLmFzcHgpe3RhcmdldD0iX2JsYW5rIn0gb2YgdGhlIHNtb290aCBsaW5lLgo8L2RldGFpbHM+CioqKgoKIyMjICoqTGltaXRhdGlvbnMgb2YgQ29ycmVsYXRpb24qKgoqKioKCldoaWxlIGNvcnJlbGF0aW9uIGlzIHVzZWZ1bCBpbiBtYW55IHNldHRpbmdzIHRvIHVuZGVyc3RhbmQgaG93IHR3byB2YXJpYWJsZXMgbW92ZSB0b2dldGhlciwgY29ycmVsYXRpb24gaXMgbm90IGFsd2F5cyBhIHVzZWZ1bCBzdW1tYXJ5LiAKRm9yIGV4YW1wbGUsIGhlcmUgYXJlIHdheXMgaXQgbWlnaHQgbm90IGJlIHVzZWZ1bDogCgotIEEgbGluZWFyIHJlbGF0aW9uc2hpcCBtaWdodCBub3QgYmUgdGhlIGJlc3Qgd2F5IHRvIGNhcHR1cmUgdGhlIHJlbGF0aW9uc2hpcC4KLSBJZiBhbiBpbmRpdmlkdWFsIHdlcmUgaW50ZXJlc3RlZCBpbiB1bmRlcnN0YW5kaW5nIGEgX2NhdXNhbF8gcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIHZhcmlhYmxlcywgYXMgW2NvcnJlbGF0aW9uIGRvZXMgbm90IGltcGx5IGNhdXNhdGlvbl0oaHR0cHM6Ly9kZnJpZWRzLmNvbS9tYXRoL2NvcnJlbGF0aW9uLWRvZXMtbm90LWltcGx5LWNhdXNhdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9LiBBbm90aGVyIHdheSBvZiBzdGF0aW5nIHRoaXMgaXMgdGhhdCBzaW1wbHkgc2hvd2luZyB0aGVyZSBpcyBhIGxpbmVhciB0cmVuZCBvdmVyIHRpbWUgZG9lcyBub3QgaW1wbHkgdGhlcmUgaXMgYSBjYXVzYWwgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlc2UgdHdvIHZhcmlhYmxlcy4gIAoKQXMgeW91IGNhbiBzZWUgZnJvbSB0aGlzIHBsb3QsIG9mdGVuIGRhdGEgbWF5IHNob3cgYSBzaW1pbGFyIHBhdHRlcm4gb3ZlciB0aW1lIGJ5IHJhbmRvbSBjaGFuY2UuIApTZWUgdGhpcyBbd2Vic2l0ZV0oaHR0cHM6Ly93d3cudHlsZXJ2aWdlbi5jb20vc3B1cmlvdXMtY29ycmVsYXRpb25zKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGV4YW1wbGVzLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSI2MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL2NhdXNhdGlvbi5wbmciKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cDovL3R5bGVydmlnZW4uY29tL3NwdXJpb3VzLWNvcnJlbGF0aW9ucyl7dGFyZ2V0PSJfYmxhbmsifQoKSW4gdGhpcyBleGFtcGxlIGFuZCBpbiBvdXIgY2FzZSBzdHVkeSwgZGF0YSB3YXMgY29sbGVjdGVkIG92ZXIgdGltZS4gVGhpcyB0eXBlIG9mIGRhdGEgd2lsbCBvZnRlbiBoYXZlIHdoYXQgaXMgY2FsbGVkIFthdXRvY29ycmxlYXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0F1dG9jb3JyZWxhdGlvbil7dGFyZ2V0PSJfYmxhbmsifSBvciBzZXJpYWwgY29ycmVsYXRpb24uIFRoaXMgbWVhbnMgdGhhdCBkYXRhIHBvaW50cyBmcm9tIG9uZSB5ZWFyIHRvIHRoZSBuZXh0IG1heSBiZSBzaW1pbGFyIHRvIG9uZSBhbm90aGVyIG9yIGhhdmUgc29tZSBzb3J0IG9mIGludGVybmFsIHN0cnVjdHVyZSByZWxhdGVkIHRvIHRpbWUgKHN1Y2ggYXMgc2Vhc29uYWxpdHkpLiBMZXQncyB0aGluayBhYm91dCBvdXIgQ08yIGVtaXNzaW9uIGFuZCB0ZW1wZXJhdHVyZSBkYXRhLiBZb3UgbWF5IGJlIGFibGUgdG8gc2VlIGhvdyBvbmUgeWVhciBvZiBDTzIgZW1pc3Npb25zIG1pZ2h0IGJlIGZhaXJseSBzaW1pbGFyIHRvIG5leHQgeWVhciwgYmVjYXVzZSB0aGUgbnVtYmVyIG9mIHNvdXJjZXMgKHN1Y2ggYXMgaW5kdXN0cmlhbCBmYWN0b3JpZXMgYW5kIGNhcnMpIGluIHRoZSBVUyB3aWxsIGNoYW5nZSBzbGlnaHRseSBmcm9tIHllYXIgdG8geWVhciwgYnV0IHRoZXkgd2lsbCBiZSByZWxhdGVkIHRvIHRoYXQgb2YgdGhlIHByZXZpb3VzIHllYXJzLiBBbnl0aW1lIHdlIGxvb2sgYXQgY29ycmVsYXRpb24gYmV0d2VlbiB0d28gdmFyaWFibGVzIHRoYXQgZWFjaCBoYXZlIGF1dG9jb3JyZWxhdGlvbiwgdGhpcyBjYW4gcmVzdWx0IGluIGEgaGlnaGVyIGxpa2VsaWhvb2Qgb2YgY29ycmVsYXRpb24gYmV0d2VlbiB0aGVzZSB2YXJpYWJsZXMuIAoKSW5kZWVkIGlmIHdlIGxvb2sgYXQgY29ycmVsYXRpb24gYmV0d2VlbiB0d28gcmFuZG9tIHZhcmlhYmxlcyB3aXRoIGF1dG9jb3JyZWxhdGlvbiB3ZSBjYW4gc2VlIGFuIGluZmxhdGlvbiBpbiB0aGUgY29ycmVsYXRpb24gcmhvIHZhbHVlcyBiZXR3ZWVuIHRoZSB0d28gdmFyaWFibGVzLCBhcyBjb21wYXJlZCB0byB0aGF0IG9mIHZhcmlhYmxlcyB0aGF0IGRvIG5vdCBoYXZlIGF1dG9jb3JyZWxhdGlvbi4KCmBgYHtyLCBlY2hvID0gRkFMU0V9Cmhpc3QocmVwbGljYXRlKDUwMDAsIHsgY29yKGRpZmZpbnYocm5vcm0oOTkpKSxkaWZmaW52KHJub3JtKDk5KSkpIH0pLCBicmVha3M9MTAwLCBtYWluPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIGF1dG9jb3JyZWxhdGVkIHZhcmlhYmxlcyIsIHhsYWI9InJobyIpCmhpc3QocmVwbGljYXRlKDUwMDAsIHsgY29yKHJub3JtKDEwMCkscm5vcm0oMTAwKSkgfSksIGJyZWFrcz0xMDAsIG1haW49IkNvcnJlbGF0aW9uIGJldHdlZW4gdmFyaWFibGVzIHdpdGggbm8gYXV0b2NvcnJlbGF0aW9uIiwgeGxhYj0icmhvIikKYGBgCgpUaGlzIGlzIHNvbWV0aGluZyB0byBrZWVwIGluIG1pbmQgd2hlbiB5b3UgZXZhbHVhdGUgaG93IHR3byB0aGluZ3MgYXJlIHJlbGF0ZWQgdG8gb25lIGFub3RoZXIgb3ZlciB0aW1lLiBUaGVyZSBhcmUgW21ldGhvZHNdKGh0dHBzOi8vb25saW5lLnN0YXQucHN1LmVkdS9zdGF0NDYyL25vZGUvMTg4LykgdGhhdCBoYXZlIGJlZW4gZGV2ZWxvcGVkIHRvIGFjY291bnQgZm9yIHRoaXMgaW4gW3RpbWUgc2VyaWVzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9UaW1lX3NlcmllcykgYW5hbHlzaXMgKGFuYWx5emluZyBkYXRhIG92ZXIgdGltZSkuIFRoaXMgZG9lcyBub3QgbWVhbiB0aGF0IHR3byB2YXJpYWJsZXMgKHN1Y2ggYXMgQ08yIGFuZCB0ZW1wZXJhdHVyZSkgbWF5IG5vdCBiZSBpbiBmYWN0IGNvcnJlbGF0ZWQsIGl0IGp1c3QgbWVhbnMgdGhhdCB3ZSBuZWVkIHRvIGFjY291bnQgZm9yIHRoZSBhdXRvY29ycmVsYXRpb24gd2l0aGluIGVhY2ggdmFyaWFibGUsIGhvd2V2ZXIgdGhpcyBpcyBiZXlvbmQgdGhlIHNjb3BlIG9mIHRoaXMgY2FzZSBzdHVkeS4KCiMjIyAqKkV4ZXJjaXNlKioKKioqCgpgYGAge3IgREFfUXVpeiwgZWNobyA9IEZBTFNFfQpxdWl6KGNhcHRpb24gPSAiIiwKICBxdWVzdGlvbigiUmVmZXIgdG8gdGhlIHBsb3QgYWJvdmUsIHdoYXQga2luZCBvZiBjb3JyZWxhdGlvbiBpcyB0aGlzPyIsCiAgICBhbnN3ZXIoIk5vIGNvcnJlbGF0aW9uIiksCiAgICBhbnN3ZXIoIlBvc2l0aXZlIGNvcnJlbGF0aW9uIiwgY29ycmVjdCA9IFRSVUUpLAogICAgYW5zd2VyKCJOZWdhdGl2ZSBjb3JyZWxhdGlvbiIpLAogICAgYWxsb3dfcmV0cnkgPSBUUlVFLAogICAgcmFuZG9tX2Fuc3dlcl9vcmRlciA9IFRSVUUKICApLAogIHF1ZXN0aW9uKCJDb3JyZWxhdGlvbiBjb2VmZmljaWVudCBjYW4gYmUgdXNlZCB0byBtZWFzdXJlIHN0cmVuZ3RoIG9mIGEgbm9ubGluZWFyIHJlbGF0aW9uc2hpcC4iLAogICAgYW5zd2VyKCJUcnVlIiwgbWVzc2FnZSA9ICJXZSBjYW4gdXNlIHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCB0byBtZWFzdXJlIHRoZSBzdHJlbmd0aCBvZiBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gdmFyaWFibGVzLCBidXQgbm90IG5vbmxpbmVhciByZWxhdGlvbnNoaXAuIiksCiAgICBhbnN3ZXIoIkZhbHNlIiwgY29ycmVjdCA9IFRSVUUpLAogICAgYWxsb3dfcmV0cnkgPSBUUlVFLAogICAgcmFuZG9tX2Fuc3dlcl9vcmRlciA9IFRSVUUKICApLAogIHF1ZXN0aW9uKCJDb3JyZWxhdGlvbiBiZXR3ZWVuIHR3byB2YXJpYWJsZXMgaW1wbGllcyBhIGNhdXNhbCByZWxhdGlvbnNoaXAuIiwKICAgIGFuc3dlcigiVHJ1ZSIsIG1lc3NhZ2UgPSAiQ29ycmVsYXRpb24gZG9lcyBub3QgaW1wbHkgY2F1c2F0aW9uLiIpLAogICAgYW5zd2VyKCJGYWxzZSIsIGNvcnJlY3QgPSBUUlVFKSwKICAgIGFsbG93X3JldHJ5ID0gVFJVRSwKICAgIHJhbmRvbV9hbnN3ZXJfb3JkZXIgPSBUUlVFCiAgKQopCmBgYAoKCiMgKipTdW1tYXJ5KioKKioqIAoKIyMgKipTdW1tYXJ5IFBsb3QqKgoqKioKClRoZSBsYXN0IHRoaW5nIHdlIHdpbGwgZG8gaGVyZSBpcyB0byBjcmVhdGUgYSBwbG90IHRoYXQgc3VtbWFyaXplcyBvdXIgbWFqb3IgZmluZGluZ3MuIApXZSB3aWxsIHVzZSB0aGUgYHBsb3RfbGF5b3V0KClgIGZ1bmN0aW9uIG9mIHRoZSBgcGF0Y2h3b3JrYCBSIHBhY2thZ2UuIFRoZSBgcGF0Y2h3b3JrYCBhbGxvd3MgeW91IHRvIGNyZWF0ZSBhIHBsb3QgbGF5b3V0IGJhc2VkIG9uIG1hdGhlbWF0aWNhbC1saWtlIGZvcm11bGFzLiBBcyB5b3UgY2FuIHNlZSBpbiB0aGlzIGV4YW1wbGUgd2Ugd2FudCB0aGUgYENPMl93b3JsZGAgYW5kIGBUb3AxMHRgIHBsb3Qgb24gdG9wIGFuZCB3ZSB3YW50IGFub3RoZXIgcm93IHdpdGggdGhlIGBDTzJfdGVtcF9VU19mYWNldGAgYW5kICB0aGUgYENPMl90ZW1wX1VTYCBwbG90IG9uIHRoZSBib3R0b20uIFRoZSBwbG90X2xheW91dCgpIGZ1bmN0aW9uIG9mIHRoZSBgcGF0Y2h3b3JrYCBwYWNrYWdlIHRoZW4gYWxsb3dzIHVzIHRvIHNwZWNpZnkgaGVpZ2h0cyBhbmQgd2lkdGhzIGZvciB0aGUgcGxvdHMuCgpXZSB3aWxsIGFsc28gc2F2ZSB0aGUgZmlndXJlIHVzaW5nIHRoZSBgZ3JEZXZpY2VzYCBgcG5nKClgIGZ1bmN0aW9uLiBXZSBjYW4gc3BlY2lmeSB0aGUgbmFtZSBvZiBvdXIgcGxvdCBmaWxlIGFuZCB3aGVyZSB3ZSB3YW50IGl0IHRvIGJlIHNhdmVkIHVzaW5nIHRoZSBgaGVyZSgpYCBmdW5jdGlvbiBvZiB0aGUgYGhlcmVgIHBhY2thZ2UuIEluIHRoaXMgY2FzZSBpbiB0aGUgYGltZ2Agc3ViZGlyZWN0b3J5IG9mIHRoZSBkaXJlY3RvcnkgY29udGFpbmluZyBvdXIgLlJwcm9qIGZpbGUuIFdlIGNhbiBhbHNvIHNwZWNpZnkgdGhlIHNpemUgb2YgdGhlIHBsb3QgYW5kIHRoZSByZXNvbHV0aW9uIHVzaW5nIHRoZSBgcmVzYCBhcmd1bWVudC4gIFRoZSBgZ3JEZXZpY2VzYCBgZGV2Lm9mZigpYCBmdW5jdGlvbiBpcyBuZWNlc3NhcnkgdG8gY2xvc2UgdGhlIGdyYXBoaWNzIGRldmljZS4KClRoaXMgd2lsbCBpbmNsdWRlIGEgZmV3IHBsb3RzIHRoYXQgd2UgbWFkZSBwcmV2aW91c2x5IGluIG90aGVyIHNlY3Rpb25zLiBXZSBzYXZlZCB0aGVzZSBpbiB0aGUgInBsb3RzIiBkaXJlY3RvcnkgYW5kIHdpbGwgbG9hZCB0aGVzZSBub3cgZm9yIHVzZXJzIHdobyBzdG9wcGVkIGFuZCByZXN0YXJ0ZWQgb3Igc3RhcnRlZCBhdCB0aGUgZGF0YSBhbmFseXNpcyBzZWN0aW9uLgoKYGBge3IsIGV2YWw9RkFMU0V9CmxvYWQoaGVyZTo6aGVyZSgicGxvdHMiLCAiQ08yX3dvcmxkLnJkYSIpKQpsb2FkKGhlcmU6OmhlcmUoInBsb3RzIiwgIlRvcDEwdC5yZGEiKSkKbG9hZChoZXJlOjpoZXJlKCJwbG90cyIsICJDTzJfdGVtcF9VU19mYWNldC5yZGEiKSkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0KbG9hZCgid3d3L3Bsb3RzL0NPMl93b3JsZC5yZGEiKQpsb2FkKCJ3d3cvcGxvdHMvVG9wMTB0LnJkYSIpCmxvYWQoInd3dy9wbG90cy9DTzJfdGVtcF9VU19mYWNldC5yZGEiKQpgYGAKCmBgYHtyLCBldmFsID0gRkFMU0V9CnBuZyhoZXJlOjpoZXJlKCJpbWciLCAibWFpbnBsb3QucG5nIiksIHVuaXRzID0gImluIiwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTAsIHJlcyA9IDMwMCkKKENPMl93b3JsZCB8IFRvcDEwdCkgLyAoQ08yX3RlbXBfVVNfZmFjZXQgfCBDTzJfdGVtcF9VU19zY2FsZWQpICsKICBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEsIDIpLAogICAgICAgICAgICAgIGhlaWdodHMgPSB1bml0KGMoNCwgMTApLCBjKCdjbScsICdjbScpKSkKZGV2Lm9mZigpCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMCBweCIsIGRwaT0zMDB9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJ3d3cvaW1nL21haW5wbG90LnBuZyIpCmBgYAoKCgojIyAqKlN5bm9wc2lzKioKKioqCgpJbiB0aGlzIGNhc2Ugc3R1ZHkgd2UgZXZhbHVhdGVkIENPMiBlbWlzc2lvbnMgZnJvbSBhcyBmYXIgYmFjayBhcyAxNzUxIGZvciBzb21lIGNvdW50cmllcyB0byAyMDE0LiBXZSBkaXNjb3ZlcmVkIHRoYXQgZ2xvYmFsIGxldmVscyBvZiBDTzIgZW1pc3Npb25zIGhhdmUgZHJhbWF0aWNhbGx5IGluY3JlYXNlZCBvdmVyIHRpbWUuIFdlIGFsc28gbGVhcm5lZCB0aGF0IHNvbWUgY291bnRyaWVzIGhhdmUgYmVlbiByZXNwb25zaWJsZSBmb3IgcGFydGljdWxhcmx5IGhpZ2ggbGV2ZWxzLiAKCldlIGFsc28gdG9vayBhIGxvb2sgYXQgaG93IENPMiBlbWlzc2lvbnMgbWlnaHQgcmVsYXRlIHRvIG90aGVyIGZhY3RvcnMsIHN1Y2ggYXMgdGVtcGVyYXR1cmUsIGVuZXJneSB1c2UsIGFuZCBuYXR1cmFsIGRpc2FzdGVycy4gV2UgbGVhcm5lZCB0aGF0IHdlIGNhbiBzdW1tYXJpemUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byBzZXRzIG9mIGRhdGEgdXNpbmcgKipjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMqKi4gV2UgYWxzbyBsZWFybmVkIHRoYXQgd2UgY2FuIHVzZSAqKnJlZ3Jlc3Npb24qKiB0byBwcmVkaWN0IG9yIGRlc2NyaWJlIGhvdyBjaGFuZ2VzIGluIG9uZSB2YXJpYWJsZSBtYXkgaW5mbHVlbmNlIGNoYW5nZXMgaW4gYW5vdGhlciB2YXJpYWJsZS4gSW1wb3J0YW50bHksIHdlIGFsc28gbGVhcm5lZCB0aGF0IGp1c3QgYmVjYXVzZSB0d28gdmFyaWFibGVzIHNob3cgc3Ryb25nIGNvcnJlbGF0aW9uIG9yIHNob3cgYW4gYXNzb2NpYXRpb24sIGl0IGRvZXMgbm90IG5lY2Vzc2FyaWx5IGluZGljYXRlIHRoYXQgdGhleSBhcmUgY2F1c2FsbHkgcmVsYXRlZC4gCgpIb3dldmVyLCB0aGVyZSBpcyBxdWl0ZSBhIGJpdCBvZiBzY2llbnRpZmljIGV2aWRlbmNlIHRvIGluZGljYXRlIHRoYXQgaW4gZmFjdCBDTzIgZW1pc3Npb25zIHRyYXAgaGVhdCBhbmQgbGVhZCB0byBpbmNyZWFzZWQgZ2xvYmFsIHRlbXBlcmF0dXJlcy4gWWV0LCBpdCBpcyBpbXBvcnRhbnQgdG8gcmVhbGl6ZSB0aGF0IHRoZXJlIGFyZSBvdGhlciBmYWN0b3JzIGludm9sdmVkIGluIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBVUyBDTzIgZW1pc3Npb25zIGFuZCBVUyBhbm51YWwgYXZlcmFnZSB0ZW1wZXJhdHVyZXMuIEZvciBleGFtcGxlIHRoZXJlIGFyZSBDTzIgZW1pc3Npb25zIGZyb20gb3RoZXIgY291bnRyaWVzIGluIHRoZSBhdG1vc3BoZXJlLCB0aGVyZSBhcmUgb3RoZXIgZ3JlZW5ob3VzZSBnYXNlcywgdGhlcmUgaXMgYWxyZWFkeSBleGlzdGluZyBDTzIgaW4gdGhlIGF0bW9zcGhlcmUgdGhhdCB3aWxsIGNvbnRpbnVlIHRvIHRyYXAgaGVhdCBmb3IgbWFueSB5ZWFycywgYW5kIGZpbmFsbHkgdGhlcmUgaXMgaGVhdCB0cmFwcGVkIGluIHRoZSBvY2VhbiBkdWUgdG8gcHJldmlvdXMgZW1pc3Npb25zIHRoYXQgd2lsbCBjYXVzZSBkZWxheWVkIGNoYW5nZXMgaW4gc3VyZmFjZSB0ZW1wZXJhdHVyZXMuIEhvd2V2ZXIsIGl0IGlzIHZpdGFsIHRoYXQgd2Ugd29yayBhcm91bmQgdGhlIGdsb2JlIHRvIHJlZHVjZSBmdXR1cmUgZ3JlZW5ob3VzZSBnYXMgZW1pc3Npb25zIHRvIG1pdGlnYXRlIHRoZSBpbmNyZWFzZWQgdGVtcGVyYXR1cmVzIHRoYXQgd2Ugd2lsbCBleHBlcmllbmNlIGR1ZSB0byBwcmV2aW91cyBhbmQgZXhpc3RpbmcgQ08yIGVtaXNzaW9ucywgc28gdGhhdCB0aGUgd2FybWluZyB0ZW1wZXJhdHVyZXMgYXJlbid0IGFzIGV4dHJlbWUgYXMgdGhleSBjb3VsZCBiZS4gRnVydGhlcm1vcmUsIHdlIG5lZWQgdG8gcHJlcGFyZSBmb3IgaW5jcmVhc2VkIHJhdGVzIG9mIG5hdHVyYWwgZGlzYXN0ZXJzIGFuZCBob3cgdGhlc2UgbWF5IGluZmx1ZW5jZSBwZW9wbGUgYXJvdW5kIHRoZSB3b3JsZC4gRXZpZGVuY2Ugc3VnZ2VzdHMgdGhhdCBpbXBvdmVyaXNoZWQgcGVvcGxlIGFyZSB0aGUgW21vc3QgYWZmZWN0ZWQgYnkgZGlzYXN0ZXJzXShodHRwczovL291cndvcmxkaW5kYXRhLm9yZy9uYXR1cmFsLWRpc2FzdGVycyl7dGFyZ2V0PSJfYmxhbmsifS4gV2UgbmVlZCB0byBiZSBwYXJ0aWN1bGFybHkgbWluZGZ1bCBvZiB0aGlzIGFzIHdlIHByZXBhcmUgZm9yIHRoZSBmdXR1cmUuICAKCgoKIyAqKlN1Z2dlc3RlZCBIb21ld29yayoqCioqKgoKQXNrIHN0dWRlbnRzIHRvIGNyZWF0ZSBhIHBsb3Qgd2l0aCBsYWJlbHMgc2hvd2luZyB0aGUgY291bnRyaWVzIHdpdGggdGhlIGxvd2VzdCBDTzIgZW1pc3Npb24gbGV2ZWxzLgoKQXNrIHN0dWRlbnRzIHRvIHBsb3QgQ08yIGVtaXNzaW9ucyBhbmQgb3RoZXIgdmFyaWFibGVzIChlLmcuIGVuZXJneSB1c2UpIG9uIGEgc2NhdHRlciBwbG90LCBjYWxjdWxhdGUgdGhlIFBlYXJzb24ncyBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCwgYW5kIGRpc2N1c3MgcmVzdWx0cy4gCgojICoqQWRkaXRpb25hbCBpbmZvcm1hdGlvbioqCioqKgoKIyMgKipIZWxwZnVsIExpbmtzKioKKioqCgpbVGlkeXZlcnNlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltSU3R1ZGlvIGNoZWF0c2hlZXRzXShodHRwczovL3JzdHVkaW8uY29tL3Jlc291cmNlcy9jaGVhdHNoZWV0cy8pe3RhcmdldD0iX2JsYW5rIn0KW0ludHJvZHVjdGlvbiB0byBjb3JyZWxhdGlvbl0oaHR0cHM6Ly93d3cubWF0aHNpc2Z1bi5jb20vZGF0YS9jb3JyZWxhdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9CltDb3JyZWxhdGlvbiBjb2VmZmljaWVudF0oaHR0cHM6Ly9yYWZhbGFiLmdpdGh1Yi5pby9kc2Jvb2svcmVncmVzc2lvbi5odG1sI2NvcnItY29lZmwpe3RhcmdldD0iX2JsYW5rIn0gICAKW0NvcnJlbGF0aW9uIGRvZXMgbm90IGltcGx5IGNhdXNhdGlvbl0oaHR0cHM6Ly9kZnJpZWRzLmNvbS9tYXRoL2NvcnJlbGF0aW9uLWRvZXMtbm90LWltcGx5LWNhdXNhdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1JlZ3Jlc3Npb25dKGh0dHBzOi8vcmFmYWxhYi5naXRodWIuaW8vZHNib29rL3JlZ3Jlc3Npb24uaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgCltMb2NhbGx5IGVzdGltYXRlZCBzY2F0dGVycGxvdCBzbW9vdGhpbmddKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xvY2FsX3JlZ3Jlc3Npb24pe3RhcmdldD0iX2JsYW5rIn0gIApbTG9jYWwgcG9seW5vbWlhbCByZWdyZXNzaW9uXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Mb2NhbF9yZWdyZXNzaW9uKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW0F1dG9jb3JybGVhdGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQXV0b2NvcnJlbGF0aW9uKXt0YXJnZXQ9Il9ibGFuayJ9ICAKW1RpbWUgc2VyaWVzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9UaW1lX3Nlcmllcyl7dGFyZ2V0PSJfYmxhbmsifSAgIApbTWV0aG9kcyB0byBhY2NvdW50IGZvciBhdXRvY29ycmVsYXRpb25dKGh0dHBzOi8vb25saW5lLnN0YXQucHN1LmVkdS9zdGF0NDYyL25vZGUvMTg4Lyl7dGFyZ2V0PSJfYmxhbmsifSAgCltVUyBFbnZpcm9ubWVudGFsIFByb3RlY3Rpb24gQWdlbmN5IChFUEEpIEludmVudG9yeSBvZiBVLlMuIEdyZWVuaG91c2UgR2FzIEVtaXNzaW9ucyBhbmQgU2lua3MgMjAyMCBSZXBvcnRdKGh0dHBzOi8vd3d3LmVwYS5nb3Yvc2l0ZXMvcHJvZHVjdGlvbi9maWxlcy8yMDIwLTA0L2RvY3VtZW50cy91cy1naGctaW52ZW50b3J5LTIwMjAtbWFpbi10ZXh0LnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgIApbTmF0aW9uYWwgQ2xpbWF0ZSBBc3Nlc3NtZW50IFJlcG9ydF0oaHR0cHM6Ly9kYXRhLmdsb2JhbGNoYW5nZS5nb3YvcmVwb3J0L25jYTMtb3ZlcnZpZXcpe3RhcmdldD0iX2JsYW5rIn0gICAgCltHcmVlbmhvdXNlIGdhc2VzXShodHRwczovL3d3dy5lcGEuZ292L3JlcG9ydC1lbnZpcm9ubWVudC9ncmVlbmhvdXNlLWdhc2VzKXt0YXJnZXQ9Il9ibGFuayJ9IApbQ2xpbWF0ZSBjaGFuZ2VdKGh0dHBzOi8vd29ybGQxMDEuY2ZyLm9yZy9nbG9iYWwtZXJhLWlzc3Vlcy9jbGltYXRlLWNoYW5nZS9jbGltYXRlLWNoYW5nZS1hZGFwdGF0aW9ucyl7dGFyZ2V0PSJfYmxhbmsifQoKCjx1PioqUGFja2FnZXMgdXNlZCBpbiB0aGlzIGNhc2Ugc3R1ZHk6KiogPC91PgoKIFBhY2thZ2UgICB8IFVzZSBpbiB0aGlzIGNhc2Ugc3R1ZHkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbYGhlcmVgXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpe3RhcmdldD0iX2JsYW5rIn0gICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhCltgcmVhZHhsYF0oaHR0cHM6Ly9yZWFkeGwudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gaW1wb3J0IHRoZSBleGNlbCBmaWxlIGRhdGEKW2ByZWFkcmBdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gaW1wb3J0IHRoZSBjc3YgZmlsZSBkYXRhCltgZHBseXJgXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICB8ICBvIHZpZXcgYW5kIHdyYW5nbGUgdGhlIGRhdGEsIGJ5IG1vZGlmeWluZyB2YXJpYWJsZXMsIHJlbmFtaW5nIHZhcmlhYmxlcywgc2VsZWN0aW5nIHZhcmlhYmxlcywgY3JlYXRpbmcgdmFyaWFibGVzLCBhbmQgYXJyYW5naW5nIHZhbHVlcyB3aXRoaW4gYSB2YXJpYWJsZSAgIApbYG1hZ3JpdHRyYF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICB8ICB0byB1c2UgYW5kIHJlYXNzaWduIGRhdGEgb2JqZWN0cyB1c2luZyB0aGUgYCU8PiVgcGlwZSBvcGVyYXRvcgpbYHN0cmluZ3JgXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gc2VsZWN0IG9ubHkgdGhlIGZpcnN0IDQgY2hhcmFjdGVycyBvZiBkYXRlIGRhdGEKW2BwdXJycmBdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIHwgdG8gYXBwbHkgYSBmdW5jdGlvbiBvbiBhIGxpc3Qgb2YgdGliYmxlcyAodGliYmxlcyBhcmUgdGhlIHRpZHl2ZXJzZSB2ZXJzaW9uIG9mIGEgZGF0YSBmcmFtZSkgIApbYHRpZHlyYF0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgfCB0byBkcm9wIHJvd3Mgd2l0aCBgTkFgIHZhbHVlcyBmcm9tIGEgdGliYmxlCltgZm9yY2F0c2BdKGh0dHBzOi8vZm9yY2F0cy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgfCB0byByZW9yZGVyIHRoZSBsZXZlbHMgb2YgYSBmYWN0b3IKW2BnZ3Bsb3QyYF0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gbWFrZSB2aXN1YWxpemF0aW9ucwpbYGRpcmVjdGxhYmVsc2BdKGh0dHA6Ly9kaXJlY3RsYWJlbHMuci1mb3JnZS5yLXByb2plY3Qub3JnL2RvY3MvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGFkZCBsYWJlbHMgdG8gcGxvdHMgZWFzaWx5CltgZ2dyZXBlbGBdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3JlcGVsL3ZpZ25ldHRlcy9nZ3JlcGVsLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBhZGQgbGFiZWxzIHRoYXQgZG9uJ3Qgb3ZlcmxhcCB0byBwbG90cwpbYGJyb29tYF0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy9ibG9nLzIwMTgvMDcvYnJvb20tMC01LTAvKSB8IHRvIG1ha2UgdGhlIG91dHB1dCBmb3JtIHN0YXRpc3RpY2FsIHRlc3RzIGVhc2llciB0byB3b3JrIHdpdGgKW2BwYXRjaHdvcmtgXShodHRwczovL2dpdGh1Yi5jb20vdGhvbWFzcDg1L3BhdGNod29yayl7dGFyZ2V0PSJfYmxhbmsifSAgfCB0byBjb21iaW5lIHBsb3RzCgoKIyMgKipTZXNzaW9uIEluZm8qKgoqKioKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoKIyMgKipBY2tub3dsZWRnbWVudHMqKgoqKioKCldlIHdvdWxkIGxpa2UgdG8gYWNrbm93bGVkZ2UgW01lZ2FuIExhdHNoYXddKGh0dHBzOi8vd3d3Lmpoc3BoLmVkdS9mYWN1bHR5L2RpcmVjdG9yeS9wcm9maWxlLzE3MDgvbWVnYW4td2VpbC1sYXRzaGF3KSBmb3IgYXNzaXN0aW5nIGluIGZyYW1pbmcgdGhlIG1ham9yIGRpcmVjdGlvbiBvZiB0aGUgY2FzZSBzdHVkeS4KCldlIHdvdWxkIGFsc28gbGlrZSB0byBhY2tub3dsZWRnZSB0aGUgW0Jsb29tYmVyZyBBbWVyaWNhbiBIZWFsdGggSW5pdGlhdGl2ZV0oaHR0cHM6Ly9hbWVyaWNhbmhlYWx0aC5qaHUuZWR1LykgZm9yIGZ1bmRpbmcgdGhpcyB3b3JrLiAKCgo8c2NyaXB0IHR5cGU9J3RleHQvamF2YXNjcmlwdCcgaWQ9J2NsdXN0cm1hcHMnIHNyYz0nLy9jZG4uY2x1c3RybWFwcy5jb20vbWFwX3YyLmpzP2NsPTA4MDgwOCZ3PWEmdD10dCZkPXJrZUp5N3N6UjJ6Z2tvNlN6UXZPamdTQUtQRzZhSHdmZ1AzMzh5c3FBeUUmY289ZmZmZmZmJmNtbz0zYWNjM2EmY21uPWZmNTM1MyZjdD04MDgwODAnPjwvc2NyaXB0Pg==