Introduction
One checkpoint in my data analysis journey is building proficiency in
coding. The Google Data Analytics Professional Certificate focused on
data visualization in R-Coding Language - thus I am building on skills I
am already familiar with. In this regard, I also wanted to look at a
topic that touches upon my academic interest. I recently completed my
Master’s in International Affairs, therefore I thought international
food prices would be able to satisfy both areas of interest. Considering
the current state of the world, I wanted to look at something related to
the Russo-Ukrainian War. Since February 24th 2022, the conflict in this
region has had large scale ramifications on the nature of our global
order. In this manner, I wanted to help shine a light on a more
forgotten part of this conflict. Considering the fact that Russia and
Ukraine remain significant producers of staple food products - such as
grain - I want to look at the wider effects of war of global
markets.
Throughout this project, I have largely relied on the data provided
by the United Nations Food and
Agriculture Organization (FAO) - which maintains a number of data
sets related to the global food trends. I will explore the specifics of
these data sets later in this notebook.
Context
On the 24 February 2022, the Russia conducted a full-scale invasion
of its neighbour, Ukraine. The invading force blockaded seaports. In
response, Kyiv’s western partners imposed a number of sanctions on the
Russian Federation. On the 22 July 2022, Ukraine and Russia signed an
agreement alleviating the naval blockade of Odessa Port. This agreement
allowed Ukraine to continue exporting grain to its buyers. In exchange,
sanctions against Russian agricultural exports were relaxed.
Project Goals
As previously noted, this project is designed to help me develop my
skills in R, specifically using the “GGplot2” package. As such, I’d like
to provide a clear overview of the crisis. Consequently, I state the
project task thusly:
“Identify recent trends in global food prices and provide a general
overview of the crisis”
In this regard, I want to achieve 5 objectives in the pursuit of this
goal:
- Visualize the recent trends in the global food prices, identifying
the main food groups being traded on the global stage
- Identify the most affected areas in Global Food Prices.
- Outline the largest exports of Grain/Oil products
Loading the R Packages
As demonstrated below, I have included “tidyverse” and “reshape 2”
into this project. “tidyverse” contains the GGplot2 package, which I
will use to visualize the data. Moreover, “reshape2” will allow me to
transform the data so so it may be formatted in a GGplot-friendly way.
RSQLite, dplyr, and dbplyr have been installed to wrangle some of the
larger data sets being used in this project.
install.packages ("tidyverse")
install.packages("reshape2")
install.packages("RSQLite")
install.packages("dplyr")
install.packages("dbplyr")
LOAD
library(reshape2)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.3.6 ✔ purrr 0.3.4
✔ tibble 3.1.8 ✔ dplyr 1.0.9
✔ tidyr 1.2.0 ✔ stringr 1.4.1
✔ readr 2.1.2 ✔ forcats 0.5.2── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
library(RSQLite)
library(dplyr)
library(dbplyr)
Attaching package: ‘dbplyr’
The following objects are masked from ‘package:dplyr’:
ident, sql
Assessing and Loading the Data sets
Global Food Prices
The first data set, FAOFP1990_2022.csv, is sourced directly from the
FAO
Website. It contains a monthly record of food prices from January
1990 to September 2022. Before uploading, I performed a cursory cleaning
of the data set in Google Sheets to ensure the date format was
compatible with GGPlot2. That being said, the data must be viewed in
order to understand how it needs to be transformed.
food_price <- read.csv(file = "FAO_Directory/FAOFP1990_2022.csv", head = TRUE, sep=" ")
str(food_price)
'data.frame': 390 obs. of 7 variables:
$ Date : chr "01/01/1990" "01/02/1990" "01/03/1990" "01/04/1990" ...
$ Food.Price.Index: num 64.1 64.5 63.8 65.8 64.4 63.7 62.5 61.5 61 61.1 ...
$ Meat : num 73.4 76 77.8 80.4 81 83.1 83.4 83.7 84.5 85.4 ...
$ Dairy : num 53.5 52.2 41.4 48.4 39.2 39.2 39.2 36.8 38.1 38.9 ...
$ Cereals : num 64.1 62.2 61.3 62.8 62 60.7 57.9 55.7 52.5 52.8 ...
$ Oils : num 44.6 44.5 45.8 44 45.5 ...
$ Sugar : num 87.9 90.7 95.1 94.3 90.4 80.3 74.2 67.6 68.5 60.8 ...
The data currently in a “wide” format, meaning that it will not be
read by GGPlot. Thus, the data must be transformed into a “long” format.
What is also apparent is that the “Date” column is being listed as a
string rather than a Date Format, meaning that GGplot will not recognize
this variable for what it is. These transformations will be conducted in
a later section.
Global Oil Prices
The second data set, data-7CJvd.csv, comes from outside of the FAO.
This dataset was collected by Bloomberg.This
set tracks the overall price of different food oils over the course of
the last two years. I have done some rudementary cleaning of the dataset
in order to eliminate null values in Excel.
oil_price <- read.csv("FAO_Directory/data-7CJvd.csv")
str(oil_price)
'data.frame': 298 obs. of 5 variables:
$ Date : chr "04/01/2021" "05/01/2021" "06/01/2021" "07/01/2021" ...
$ Palm.oil..Crude: num 971 972 990 995 984 ...
$ Rapeseed.oil : num 1103 1102 1181 1135 1141 ...
$ Soybean.oil : num 946 978 979 978 965 ...
$ Sunflower.oil : int 1280 1285 1310 1340 1380 1330 1345 1330 1320 1310 ...
The data currently in a “wide” format, meaning that it will not be
read by GGPlot. Thus, the data must be transformed into a “long” format.
What is also apparent is that the “Date” column is being listed as a
string rather than a Date Format, meaning that GGplot will not recognize
this variable for what it is. These transformations will be conducted in
a later section.
Global Wheat/Oil Market
The secondary data set was also acquired from the FAO Website. It
contains the value and volume of imports/exports by country from 1961 up
to and including 2020. With regards to the Metadata of this set, FAO
states the following:
“The data is mainly provided by UNSD, Eurostat, and other
national authorities as needed. This source data is checked for
outliers, trade partner data is used for non-reporting countries or
missing cells, and data on food aid is added to take into account total
cross-border trade flows. The trade database includes the following
variables: export quantity, export value, import quantity, and import
value. The trade database includes all food and agricultural products
imported/exported annually by all the countries in the world.”
FAOTradeData <- read.csv("FAO_Directory/FAOSTAT_data_en_10-19-2022.csv")
str(FAOTradeData)
'data.frame': 214862 obs. of 14 variables:
$ Domain.Code : chr "TCL" "TCL" "TCL" "TCL" ...
$ Domain : chr "Crops and livestock products" "Crops and livestock products" "Crops and livestock products" "Crops and livestock products" ...
$ Area.Code..M49. : int 4 4 4 4 4 4 4 4 4 4 ...
$ Area : chr "Afghanistan" "Afghanistan" "Afghanistan" "Afghanistan" ...
$ Element.Code : int 5910 5910 5910 5922 5922 5922 5910 5910 5910 5922 ...
$ Element : chr "Export Quantity" "Export Quantity" "Export Quantity" "Export Value" ...
$ Item.Code..CPC. : chr "1371" "1371" "1371" "1371" ...
$ Item : chr "Almonds, in shell" "Almonds, in shell" "Almonds, in shell" "Almonds, in shell" ...
$ Year.Code : int 2018 2019 2020 2018 2019 2020 2018 2019 2020 2018 ...
$ Year : int 2018 2019 2020 2018 2019 2020 2018 2019 2020 2018 ...
$ Unit : chr "tonnes" "tonnes" "tonnes" "1000 US$" ...
$ Value : num 9532 1943 2546 10855 6999 ...
$ Flag : chr "R" "R" "*" "R" ...
$ Flag.Description: chr "" "" "" "" ...
This set includes a significant amount of data that isn’t relevant to
the question at hand. My intention with this set is to lay out who is to
lay out the significance Ukraine and Russia in the Global Grain Market
The data set contain 13 variables and 17,444,859 observations. As such,
it needs to be wrangled down in order to whittle it down to focus on the
Grain Market. For this task, I chose to use SQL.
Transforming and Wrangling Data
Global Food Prices
In order to make the first data set compatible with the GGplot
Package. As such, “wide” data needs to be converted into a long format.
This can be done my utilizing the functions included in the reshape2
package - which includes “melt”. My intention with this data set is to
turn it into a line graph that tracks over the past 5 years. As such,
the graph needs to be defined by Date (on the X axis) and Value (on the
Y axis).Consequently, the data will be reshaped using the ID Variable
“Date”.
long <- reshape2::melt(food_price, id.vars = "Date")
str(long)
'data.frame': 2340 obs. of 3 variables:
$ Date : chr "01/01/1990" "01/02/1990" "01/03/1990" "01/04/1990" ...
$ variable: Factor w/ 6 levels "Food.Price.Index",..: 1 1 1 1 1 1 1 1 1 1 ...
$ value : num 64.1 64.5 63.8 65.8 64.4 63.7 62.5 61.5 61 61.1 ...
The transformed data set, “Long”, requires the variable “Date” to be
transformed from a string to a Date format. This will allow GGplot to
recognize the date it is processing.
long$Date <- as.Date(long$Date, format="%d/%m/%Y")
str(long)
'data.frame': 2340 obs. of 3 variables:
$ Date : Date, format: "1990-01-01" "1990-02-01" "1990-03-01" "1990-04-01" ...
$ variable: Factor w/ 6 levels "Food.Price.Index",..: 1 1 1 1 1 1 1 1 1 1 ...
$ value : num 64.1 64.5 63.8 65.8 64.4 63.7 62.5 61.5 61 61.1 ...
Oil Food Prices
In order to make the second data set compatible with the GGplot
Package. As such, “wide” data needs to be converted into a long format.
This can be done my utilizing the functions included in the reshape2
package - which includes “melt”. My intention with this data set is to
turn it into a line graph that tracks over the past 2 years. As such,
the graph needs to be defined by Date (on the X axis) and Value (on the
Y axis).Consequently, the data will be reshaped using the ID Variable
“Date”.
long2 <- reshape2::melt(oil_price, id.vars = "Date")
str(long2)
'data.frame': 1192 obs. of 3 variables:
$ Date : chr "04/01/2021" "05/01/2021" "06/01/2021" "07/01/2021" ...
$ variable: Factor w/ 4 levels "Palm.oil..Crude",..: 1 1 1 1 1 1 1 1 1 1 ...
$ value : num 971 972 990 995 984 ...
The transformed data set, “Long2”, requires the variable “Date” to be
transformed from a string to a Date format. This will allow GGplot to
recognize the date it is processing.
long2$Date <- as.Date(long2$Date, format="%d/%m/%Y")
str(long2)
'data.frame': 1192 obs. of 3 variables:
$ Date : Date, format: "2021-01-04" "2021-01-05" "2021-01-06" "2021-01-07" ...
$ variable: Factor w/ 4 levels "Palm.oil..Crude",..: 1 1 1 1 1 1 1 1 1 1 ...
$ value : num 971 972 990 995 984 ...
Wheat Exports
This data set needs to be wrangled in order to make the data easier
to handle.
conn <- src_memdb() # This function sets up a database through which we can write SQL queries
copy_to(conn,
FAOTradeData,
overwrite = TRUE) # This function populates the database with values using the Data Frame "FAOTradeData"
This code lays the ground work for Native SQL queries in R. The Next
step will run a query on the Export data set and find out the top 20
exporters of Wheat.
GE <- tbl(conn, sql("SELECT AREA,
VALUE
FROM FAOTradeData
WHERE
Year = 2020 AND Element = 'Export Value' AND
(Item = 'Wheat')
GROUP BY AREA
ORDER BY VALUE DESC
Limit 20
"))
Labeling will allow me to convert the query into a data frame for
visualization.
GrainExporters <- as.data.frame(GE)
str(GrainExporters)
'data.frame': 20 obs. of 2 variables:
$ Area : chr "Russian Federation" "United States of America" "Canada" "France" ...
$ Value: num 7918294 6318111 6317889 4528591 3594217 ...
Oil Exports
The Imports process will largely mirror the Wheat Export Process.
This code lays the ground work for Native SQL queries in R. The Next
step will run a query on the import data set and find out the top 20
Importers of Wheat.
OI <- tbl(conn, sql("SELECT AREA,
VALUE
FROM FAOTradeData
WHERE
Year = 2020 AND Element = 'Export Value' AND
(Item = 'Sunflower-seed oil, crude')
GROUP BY AREA
ORDER BY VALUE DESC
Limit 20
"))
Labeling will allow me to convert the query into a data frame for
visualization.
OilExporters <- as.data.frame(OI)
str(OilExporters)
'data.frame': 20 obs. of 2 variables:
$ Area : chr "Ukraine" "Russian Federation" "Netherlands" "Türkiye" ...
$ Value: num 5319878 2472067 737353 728164 480857 ...
Visualisation
Global Food Prices
I have chosen to display this data as a line graph. This format will
allow me to display data over the last 5 years.
ggplot(long, aes(x=Date, y = value, group = variable, colour = variable)) +
geom_line()+
scale_y_continuous(limits = c(0, 270))+
ggtitle("FAO Global Food Prices (2017-2022)")+
labs(colour = "Food Types", subtitle = "Acquired from the UN")+
scale_x_date(limits = as.Date(c('2017-01-01','2022-09-01')))

Considering the data outlined by the FAO, it seems that the main food
groups in question are Meat, Dairy, Cereals, Oils, Sugar. Oil and
Cereals have risen the most over the past year. It seems from the data
available that the current food price has yet to recover from the
compounded effects of the 2020 COVID Pandemic. Moreover, it is clear
that oil prices have risen sharply over the past year. Gareth Price,
expert from Chatham House, validates this hypothesis noting that global
supply chains are yet to recover from the COVID-19 pandemic.
Global Oil Prices
I have chosen to display this data as a line graph. This format will
allow me to display data over the last 5 years.
ggplot(long2, aes(x=Date, y = value, group = variable, colour = variable)) +
geom_line()+
scale_y_continuous(limits = c(0, 3000))+
ggtitle("FAO Global Food Prices (2017-2022)")+
labs(colour = "Food Types", subtitle = "Acquired from the UN")

The swing in price is largest in the sunflower oil, what will be
demonstrated later as an important export of both Russia and
Ukraine.
Wheat Export
This visual will be displayed as a bar graph. This will help compare
the exports value of the world’s 20 largest wheat exporters.
ggplot(GrainExporters, aes(x = reorder(Area, -Value), y = Value, fill=Area))+
geom_bar(stat = 'identity')+
scale_fill_manual(values = c("Ukraine" = "red",
"Russian Federation" = "red"))+
ggtitle("Largest Wheat Exporters 2020")+
theme(axis.text.x = element_text(angle = 90), legend.position = "none")+
scale_y_continuous(labels = function(x) format(x, scientific = FALSE))

What this demonstrates is the role Ukraine and Russia play in the
global grain markets. It’s clear that the blockade of Ukrainian Ports
and sanctioning of Russian exports.
Oil Exports
This visual will be displayed as a bar graph. This will help compare
the exports value of the world’s 20 largest Oil exporters.
ggplot(OilExporters, aes(x = reorder(Area, -Value), y = Value, fill=Area))+
geom_bar(stat = 'identity')+
scale_fill_manual(values = c("Ukraine" = "red",
"Russian Federation" = "red"))+
ggtitle("Largest Sunflower Oil Exporters 2020")+
theme(axis.text.x = element_text(angle = 90), legend.position = "none")+
scale_y_continuous(labels = function(x) format(x, scientific = FALSE))

What this demonstrates is the role Ukraine and Russia play in the
global grain markets. It’s clear that the blockade of Ukrainian Ports
and sanctioning of Russian exports.
LS0tCnRpdGxlOiAiVmlzdWFsaXNpbmcgdGhlIDIwMjIgRm9vZCBDcmlzaXMgVXNpbmcgR0dQbG90IgpBdXRob3I6IFJvYmVydCBDdWxsaWdhbgpEYXRlOiBUbyBiZSBkZWNpZGVkCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKIyMgSW50cm9kdWN0aW9uCgpPbmUgY2hlY2twb2ludCBpbiBteSBkYXRhIGFuYWx5c2lzIGpvdXJuZXkgaXMgYnVpbGRpbmcgcHJvZmljaWVuY3kgaW4gY29kaW5nLiBUaGUgR29vZ2xlIERhdGEgQW5hbHl0aWNzIFByb2Zlc3Npb25hbCBDZXJ0aWZpY2F0ZSBmb2N1c2VkIG9uIGRhdGEgdmlzdWFsaXphdGlvbiBpbiBSLUNvZGluZyBMYW5ndWFnZSAtIHRodXMgSSBhbSBidWlsZGluZyBvbiBza2lsbHMgSSBhbSBhbHJlYWR5IGZhbWlsaWFyIHdpdGguIEluIHRoaXMgcmVnYXJkLCBJIGFsc28gd2FudGVkIHRvIGxvb2sgYXQgYSB0b3BpYyB0aGF0IHRvdWNoZXMgdXBvbiBteSBhY2FkZW1pYyBpbnRlcmVzdC4gSSByZWNlbnRseSBjb21wbGV0ZWQgbXkgTWFzdGVyJ3MgaW4gSW50ZXJuYXRpb25hbCBBZmZhaXJzLCB0aGVyZWZvcmUgSSB0aG91Z2h0IGludGVybmF0aW9uYWwgZm9vZCBwcmljZXMgd291bGQgYmUgYWJsZSB0byBzYXRpc2Z5IGJvdGggYXJlYXMgb2YgaW50ZXJlc3QuIENvbnNpZGVyaW5nIHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSB3b3JsZCwgSSB3YW50ZWQgdG8gbG9vayBhdCBzb21ldGhpbmcgcmVsYXRlZCB0byB0aGUgUnVzc28tVWtyYWluaWFuIFdhci4gU2luY2UgRmVicnVhcnkgMjR0aCAyMDIyLCB0aGUgY29uZmxpY3QgaW4gdGhpcyByZWdpb24gaGFzIGhhZCBsYXJnZSBzY2FsZSByYW1pZmljYXRpb25zIG9uIHRoZSBuYXR1cmUgb2Ygb3VyIGdsb2JhbCBvcmRlci4gSW4gdGhpcyBtYW5uZXIsIEkgd2FudGVkIHRvIGhlbHAgc2hpbmUgYSBsaWdodCBvbiBhIG1vcmUgZm9yZ290dGVuIHBhcnQgb2YgdGhpcyBjb25mbGljdC4gQ29uc2lkZXJpbmcgdGhlIGZhY3QgdGhhdCBSdXNzaWEgYW5kIFVrcmFpbmUgcmVtYWluIHNpZ25pZmljYW50IHByb2R1Y2VycyBvZiBzdGFwbGUgZm9vZCBwcm9kdWN0cyAtIHN1Y2ggYXMgZ3JhaW4gLSBJIHdhbnQgdG8gbG9vayBhdCB0aGUgd2lkZXIgZWZmZWN0cyBvZiB3YXIgb2YgZ2xvYmFsIG1hcmtldHMuCgpUaHJvdWdob3V0IHRoaXMgcHJvamVjdCwgSSBoYXZlIGxhcmdlbHkgcmVsaWVkIG9uIHRoZSBkYXRhIHByb3ZpZGVkIGJ5IHRoZSBVbml0ZWQgTmF0aW9ucyBbRm9vZCBhbmQgQWdyaWN1bHR1cmUgT3JnYW5pemF0aW9uXShodHRwczovL3d3dy5mYW8ub3JnL2hvbWUvZW4pIChGQU8pIC0gd2hpY2ggbWFpbnRhaW5zIGEgbnVtYmVyIG9mIGRhdGEgc2V0cyByZWxhdGVkIHRvIHRoZSBnbG9iYWwgZm9vZCB0cmVuZHMuIEkgd2lsbCBleHBsb3JlIHRoZSBzcGVjaWZpY3Mgb2YgdGhlc2UgZGF0YSBzZXRzIGxhdGVyIGluIHRoaXMgbm90ZWJvb2suCgojIyBDb250ZXh0CgpPbiB0aGUgMjQgRmVicnVhcnkgMjAyMiwgdGhlIFJ1c3NpYSBjb25kdWN0ZWQgYSBmdWxsLXNjYWxlIGludmFzaW9uIG9mIGl0cyBuZWlnaGJvdXIsIFVrcmFpbmUuIFRoZSBpbnZhZGluZyBmb3JjZSBibG9ja2FkZWQgc2VhcG9ydHMuIEluIHJlc3BvbnNlLCBLeWl24oCZcyB3ZXN0ZXJuIHBhcnRuZXJzIGltcG9zZWQgYSBudW1iZXIgb2Ygc2FuY3Rpb25zIG9uIHRoZSBSdXNzaWFuIEZlZGVyYXRpb24uIE9uIHRoZSAyMiBKdWx5IDIwMjIsIFVrcmFpbmUgYW5kIFJ1c3NpYSBzaWduZWQgYW4gYWdyZWVtZW50IGFsbGV2aWF0aW5nIHRoZSBuYXZhbCBibG9ja2FkZSBvZiBPZGVzc2EgUG9ydC4gVGhpcyBhZ3JlZW1lbnQgYWxsb3dlZCBVa3JhaW5lIHRvIGNvbnRpbnVlIGV4cG9ydGluZyBncmFpbiB0byBpdHMgYnV5ZXJzLiBJbiBleGNoYW5nZSwgc2FuY3Rpb25zIGFnYWluc3QgUnVzc2lhbiBhZ3JpY3VsdHVyYWwgZXhwb3J0cyB3ZXJlIHJlbGF4ZWQuCgojIyBQcm9qZWN0IEdvYWxzCgpBcyBwcmV2aW91c2x5IG5vdGVkLCB0aGlzIHByb2plY3QgaXMgZGVzaWduZWQgdG8gaGVscCBtZSBkZXZlbG9wIG15IHNraWxscyBpbiBSLCBzcGVjaWZpY2FsbHkgdXNpbmcgdGhlICJHR3Bsb3QyIiBwYWNrYWdlLiBBcyBzdWNoLCBJJ2QgbGlrZSB0byBwcm92aWRlIGEgY2xlYXIgb3ZlcnZpZXcgb2YgdGhlIGNyaXNpcy4gQ29uc2VxdWVudGx5LCBJIHN0YXRlIHRoZSBwcm9qZWN0IHRhc2sgdGh1c2x5OgoKIyMjIyAiSWRlbnRpZnkgcmVjZW50IHRyZW5kcyBpbiBnbG9iYWwgZm9vZCBwcmljZXMgYW5kIHByb3ZpZGUgYSBnZW5lcmFsIG92ZXJ2aWV3IG9mIHRoZSBjcmlzaXMiIAoKSW4gdGhpcyByZWdhcmQsIEkgd2FudCB0byBhY2hpZXZlIDUgb2JqZWN0aXZlcyBpbiB0aGUgcHVyc3VpdCBvZiB0aGlzIGdvYWw6CgoxLiBWaXN1YWxpemUgdGhlIHJlY2VudCB0cmVuZHMgaW4gdGhlIGdsb2JhbCBmb29kIHByaWNlcywgaWRlbnRpZnlpbmcgdGhlIG1haW4gZm9vZCBncm91cHMgYmVpbmcgdHJhZGVkIG9uIHRoZSBnbG9iYWwgc3RhZ2UKMi4gSWRlbnRpZnkgdGhlIG1vc3QgYWZmZWN0ZWQgYXJlYXMgaW4gR2xvYmFsIEZvb2QgUHJpY2VzLgozLiBPdXRsaW5lIHRoZSBsYXJnZXN0IGV4cG9ydHMgb2YgR3JhaW4vT2lsIHByb2R1Y3RzCgojIyBMb2FkaW5nIHRoZSBSIFBhY2thZ2VzCgpBcyBkZW1vbnN0cmF0ZWQgYmVsb3csIEkgaGF2ZSBpbmNsdWRlZCAidGlkeXZlcnNlIiBhbmQgInJlc2hhcGUgMiIgaW50byB0aGlzIHByb2plY3QuICJ0aWR5dmVyc2UiIGNvbnRhaW5zIHRoZSBHR3Bsb3QyIHBhY2thZ2UsIHdoaWNoIEkgd2lsbCB1c2UgdG8gdmlzdWFsaXplIHRoZSBkYXRhLiBNb3Jlb3ZlciwgInJlc2hhcGUyIiB3aWxsIGFsbG93IG1lIHRvIHRyYW5zZm9ybSB0aGUgZGF0YSBzbyBzbyBpdCBtYXkgYmUgZm9ybWF0dGVkIGluIGEgR0dwbG90LWZyaWVuZGx5IHdheS4gUlNRTGl0ZSwgZHBseXIsIGFuZCBkYnBseXIgaGF2ZSBiZWVuIGluc3RhbGxlZCB0byB3cmFuZ2xlIHNvbWUgb2YgdGhlIGxhcmdlciBkYXRhIHNldHMgYmVpbmcgdXNlZCBpbiB0aGlzIHByb2plY3QuCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcyAoInRpZHl2ZXJzZSIpCmluc3RhbGwucGFja2FnZXMoInJlc2hhcGUyIikKaW5zdGFsbC5wYWNrYWdlcygiUlNRTGl0ZSIpCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikKaW5zdGFsbC5wYWNrYWdlcygiZGJwbHlyIikKYGBgCgpMT0FECgpgYGB7cn0KbGlicmFyeShyZXNoYXBlMikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoUlNRTGl0ZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShkYnBseXIpCmBgYAoKIyMgQXNzZXNzaW5nIGFuZCBMb2FkaW5nIHRoZSBEYXRhIHNldHMKCiMjIyBHbG9iYWwgRm9vZCBQcmljZXMKClRoZSBmaXJzdCBkYXRhIHNldCwgRkFPRlAxOTkwXzIwMjIuY3N2LCBpcyBzb3VyY2VkIGRpcmVjdGx5IGZyb20gdGhlIFtGQU8gV2Vic2l0ZV0oaHR0cHM6Ly93d3cuZmFvLm9yZy93b3JsZGZvb2RzaXR1YXRpb24vZm9vZHByaWNlc2luZGV4L2VuLykuIEl0IGNvbnRhaW5zIGEgbW9udGhseSByZWNvcmQgb2YgZm9vZCBwcmljZXMgZnJvbSBKYW51YXJ5IDE5OTAgdG8gU2VwdGVtYmVyIDIwMjIuIEJlZm9yZSB1cGxvYWRpbmcsIEkgcGVyZm9ybWVkIGEgY3Vyc29yeSBjbGVhbmluZyBvZiB0aGUgZGF0YSBzZXQgaW4gR29vZ2xlIFNoZWV0cyB0byBlbnN1cmUgdGhlIGRhdGUgZm9ybWF0IHdhcyBjb21wYXRpYmxlIHdpdGggR0dQbG90Mi4gVGhhdCBiZWluZyBzYWlkLCB0aGUgZGF0YSBtdXN0IGJlIHZpZXdlZCBpbiBvcmRlciB0byB1bmRlcnN0YW5kIGhvdyBpdCBuZWVkcyB0byBiZSB0cmFuc2Zvcm1lZC4KCmBgYHtyfQpmb29kX3ByaWNlIDwtIHJlYWQuY3N2KGZpbGUgPSAiRkFPX0RpcmVjdG9yeS9GQU9GUDE5OTBfMjAyMi5jc3YiLCBoZWFkID0gVFJVRSwgc2VwPSIgIikKc3RyKGZvb2RfcHJpY2UpCmBgYAoKVGhlIGRhdGEgY3VycmVudGx5IGluIGEgIndpZGUiIGZvcm1hdCwgbWVhbmluZyB0aGF0IGl0IHdpbGwgbm90IGJlIHJlYWQgYnkgR0dQbG90LiBUaHVzLCB0aGUgZGF0YSBtdXN0IGJlIHRyYW5zZm9ybWVkIGludG8gYSAibG9uZyIgZm9ybWF0LiBXaGF0IGlzIGFsc28gYXBwYXJlbnQgaXMgdGhhdCB0aGUgIkRhdGUiIGNvbHVtbiBpcyBiZWluZyBsaXN0ZWQgYXMgYSBzdHJpbmcgcmF0aGVyIHRoYW4gYSBEYXRlIEZvcm1hdCwgbWVhbmluZyB0aGF0IEdHcGxvdCB3aWxsIG5vdCByZWNvZ25pemUgdGhpcyB2YXJpYWJsZSBmb3Igd2hhdCBpdCBpcy4gVGhlc2UgdHJhbnNmb3JtYXRpb25zIHdpbGwgYmUgY29uZHVjdGVkIGluIGEgbGF0ZXIgc2VjdGlvbi4KCiMjIyBHbG9iYWwgT2lsIFByaWNlcwoKVGhlIHNlY29uZCBkYXRhIHNldCwgZGF0YS03Q0p2ZC5jc3YsIGNvbWVzIGZyb20gb3V0c2lkZSBvZiB0aGUgRkFPLiBUaGlzIGRhdGFzZXQgd2FzIGNvbGxlY3RlZCBieSBbQmxvb21iZXJnXShodHRwczovL3d3dy5pZnByaS5vcmcvYmxvZy9pbXBhY3QtdWtyYWluZS1jcmlzaXMtZ2xvYmFsLXZlZ2V0YWJsZS1vaWwtbWFya2V0KS5UaGlzIHNldCB0cmFja3MgdGhlIG92ZXJhbGwgcHJpY2Ugb2YgZGlmZmVyZW50IGZvb2Qgb2lscyBvdmVyIHRoZSBjb3Vyc2Ugb2YgdGhlIGxhc3QgdHdvIHllYXJzLiBJIGhhdmUgZG9uZSBzb21lIHJ1ZGVtZW50YXJ5IGNsZWFuaW5nIG9mIHRoZSBkYXRhc2V0IGluIG9yZGVyIHRvIGVsaW1pbmF0ZSBudWxsIHZhbHVlcyBpbiBFeGNlbC4KCmBgYHtyfQpvaWxfcHJpY2UgPC0gcmVhZC5jc3YoIkZBT19EaXJlY3RvcnkvZGF0YS03Q0p2ZC5jc3YiKQpzdHIob2lsX3ByaWNlKQpgYGAKClRoZSBkYXRhIGN1cnJlbnRseSBpbiBhICJ3aWRlIiBmb3JtYXQsIG1lYW5pbmcgdGhhdCBpdCB3aWxsIG5vdCBiZSByZWFkIGJ5IEdHUGxvdC4gVGh1cywgdGhlIGRhdGEgbXVzdCBiZSB0cmFuc2Zvcm1lZCBpbnRvIGEgImxvbmciIGZvcm1hdC4gV2hhdCBpcyBhbHNvIGFwcGFyZW50IGlzIHRoYXQgdGhlICJEYXRlIiBjb2x1bW4gaXMgYmVpbmcgbGlzdGVkIGFzIGEgc3RyaW5nIHJhdGhlciB0aGFuIGEgRGF0ZSBGb3JtYXQsIG1lYW5pbmcgdGhhdCBHR3Bsb3Qgd2lsbCBub3QgcmVjb2duaXplIHRoaXMgdmFyaWFibGUgZm9yIHdoYXQgaXQgaXMuIFRoZXNlIHRyYW5zZm9ybWF0aW9ucyB3aWxsIGJlIGNvbmR1Y3RlZCBpbiBhIGxhdGVyIHNlY3Rpb24uCgojIyMgR2xvYmFsIFdoZWF0L09pbCBNYXJrZXQKClRoZSBzZWNvbmRhcnkgZGF0YSBzZXQgd2FzIGFsc28gYWNxdWlyZWQgZnJvbSB0aGUgW0ZBTyBXZWJzaXRlXShodHRwczovL3d3dy5mYW8ub3JnL2Zhb3N0YXQvZW4vI2RhdGEvVENMKS4gSXQgY29udGFpbnMgdGhlIHZhbHVlIGFuZCB2b2x1bWUgb2YgaW1wb3J0cy9leHBvcnRzIGJ5IGNvdW50cnkgZnJvbSAxOTYxIHVwIHRvIGFuZCBpbmNsdWRpbmcgMjAyMC4gV2l0aCByZWdhcmRzIHRvIHRoZSBNZXRhZGF0YSBvZiB0aGlzIHNldCwgRkFPIHN0YXRlcyB0aGUgZm9sbG93aW5nOgoKKiJUaGUgZGF0YSBpcyBtYWlubHkgcHJvdmlkZWQgYnkgVU5TRCwgRXVyb3N0YXQsIGFuZCBvdGhlciBuYXRpb25hbCBhdXRob3JpdGllcyBhcyBuZWVkZWQuIFRoaXMgc291cmNlIGRhdGEgaXMgY2hlY2tlZCBmb3Igb3V0bGllcnMsIHRyYWRlIHBhcnRuZXIgZGF0YSBpcyB1c2VkIGZvciBub24tcmVwb3J0aW5nIGNvdW50cmllcyBvciBtaXNzaW5nIGNlbGxzLCBhbmQgZGF0YSBvbiBmb29kIGFpZCBpcyBhZGRlZCB0byB0YWtlIGludG8gYWNjb3VudCB0b3RhbCBjcm9zcy1ib3JkZXIgdHJhZGUgZmxvd3MuIFRoZSB0cmFkZSBkYXRhYmFzZSBpbmNsdWRlcyB0aGUgZm9sbG93aW5nIHZhcmlhYmxlczogZXhwb3J0IHF1YW50aXR5LCBleHBvcnQgdmFsdWUsIGltcG9ydCBxdWFudGl0eSwgYW5kIGltcG9ydCB2YWx1ZS4gVGhlIHRyYWRlIGRhdGFiYXNlIGluY2x1ZGVzIGFsbCBmb29kIGFuZCBhZ3JpY3VsdHVyYWwgcHJvZHVjdHMgaW1wb3J0ZWQvZXhwb3J0ZWQgYW5udWFsbHkgYnkgYWxsIHRoZSBjb3VudHJpZXMgaW4gdGhlIHdvcmxkLiIqCgpgYGB7cn0KRkFPVHJhZGVEYXRhIDwtIHJlYWQuY3N2KCJGQU9fRGlyZWN0b3J5L0ZBT1NUQVRfZGF0YV9lbl8xMC0xOS0yMDIyLmNzdiIpCnN0cihGQU9UcmFkZURhdGEpCmBgYAoKVGhpcyBzZXQgaW5jbHVkZXMgYSBzaWduaWZpY2FudCBhbW91bnQgb2YgZGF0YSB0aGF0IGlzbid0IHJlbGV2YW50IHRvIHRoZSBxdWVzdGlvbiBhdCBoYW5kLiBNeSBpbnRlbnRpb24gd2l0aCB0aGlzIHNldCBpcyB0byBsYXkgb3V0IHdobyBpcyB0byBsYXkgb3V0IHRoZSBzaWduaWZpY2FuY2UgVWtyYWluZSBhbmQgUnVzc2lhIGluIHRoZSBHbG9iYWwgR3JhaW4gTWFya2V0IFRoZSBkYXRhIHNldCBjb250YWluIDEzIHZhcmlhYmxlcyBhbmQgMTcsNDQ0LDg1OSBvYnNlcnZhdGlvbnMuIEFzIHN1Y2gsIGl0IG5lZWRzIHRvIGJlIHdyYW5nbGVkIGRvd24gaW4gb3JkZXIgdG8gd2hpdHRsZSBpdCBkb3duIHRvIGZvY3VzIG9uIHRoZSBHcmFpbiBNYXJrZXQuIEZvciB0aGlzIHRhc2ssIEkgY2hvc2UgdG8gdXNlIFNRTC4KCiMjIFRyYW5zZm9ybWluZyBhbmQgV3JhbmdsaW5nIERhdGEKCiMjIyBHbG9iYWwgRm9vZCBQcmljZXMKCkluIG9yZGVyIHRvIG1ha2UgdGhlIGZpcnN0IGRhdGEgc2V0IGNvbXBhdGlibGUgd2l0aCB0aGUgR0dwbG90IFBhY2thZ2UuIEFzIHN1Y2gsICJ3aWRlIiBkYXRhIG5lZWRzIHRvIGJlIGNvbnZlcnRlZCBpbnRvIGEgbG9uZyBmb3JtYXQuIFRoaXMgY2FuIGJlIGRvbmUgbXkgdXRpbGl6aW5nIHRoZSBmdW5jdGlvbnMgaW5jbHVkZWQgaW4gdGhlIHJlc2hhcGUyIHBhY2thZ2UgLSB3aGljaCBpbmNsdWRlcyAibWVsdCIuIE15IGludGVudGlvbiB3aXRoIHRoaXMgZGF0YSBzZXQgaXMgdG8gdHVybiBpdCBpbnRvIGEgbGluZSBncmFwaCB0aGF0IHRyYWNrcyBvdmVyIHRoZSBwYXN0IDUgeWVhcnMuIEFzIHN1Y2gsIHRoZSBncmFwaCBuZWVkcyB0byBiZSBkZWZpbmVkIGJ5IERhdGUgKG9uIHRoZSBYIGF4aXMpIGFuZCBWYWx1ZSAob24gdGhlIFkgYXhpcykuQ29uc2VxdWVudGx5LCB0aGUgZGF0YSB3aWxsIGJlIHJlc2hhcGVkIHVzaW5nIHRoZSBJRCBWYXJpYWJsZSAiRGF0ZSIuIAoKYGBge3J9CmxvbmcgPC0gcmVzaGFwZTI6Om1lbHQoZm9vZF9wcmljZSwgaWQudmFycyA9ICJEYXRlIikgCnN0cihsb25nKQpgYGAKClRoZSB0cmFuc2Zvcm1lZCBkYXRhIHNldCwgIkxvbmciLCByZXF1aXJlcyB0aGUgdmFyaWFibGUgIkRhdGUiIHRvIGJlIHRyYW5zZm9ybWVkIGZyb20gYSBzdHJpbmcgdG8gYSBEYXRlIGZvcm1hdC4gVGhpcyB3aWxsIGFsbG93IEdHcGxvdCB0byByZWNvZ25pemUgdGhlIGRhdGUgaXQgaXMgcHJvY2Vzc2luZy4KCmBgYHtyfQpsb25nJERhdGUgPC0gYXMuRGF0ZShsb25nJERhdGUsIGZvcm1hdD0iJWQvJW0vJVkiKQpzdHIobG9uZykKYGBgCgojIyMgT2lsIEZvb2QgUHJpY2VzCgpJbiBvcmRlciB0byBtYWtlIHRoZSBzZWNvbmQgZGF0YSBzZXQgY29tcGF0aWJsZSB3aXRoIHRoZSBHR3Bsb3QgUGFja2FnZS4gQXMgc3VjaCwgIndpZGUiIGRhdGEgbmVlZHMgdG8gYmUgY29udmVydGVkIGludG8gYSBsb25nIGZvcm1hdC4gVGhpcyBjYW4gYmUgZG9uZSBteSB1dGlsaXppbmcgdGhlIGZ1bmN0aW9ucyBpbmNsdWRlZCBpbiB0aGUgcmVzaGFwZTIgcGFja2FnZSAtIHdoaWNoIGluY2x1ZGVzICJtZWx0Ii4gTXkgaW50ZW50aW9uIHdpdGggdGhpcyBkYXRhIHNldCBpcyB0byB0dXJuIGl0IGludG8gYSBsaW5lIGdyYXBoIHRoYXQgdHJhY2tzIG92ZXIgdGhlIHBhc3QgMiB5ZWFycy4gQXMgc3VjaCwgdGhlIGdyYXBoIG5lZWRzIHRvIGJlIGRlZmluZWQgYnkgRGF0ZSAob24gdGhlIFggYXhpcykgYW5kIFZhbHVlIChvbiB0aGUgWSBheGlzKS5Db25zZXF1ZW50bHksIHRoZSBkYXRhIHdpbGwgYmUgcmVzaGFwZWQgdXNpbmcgdGhlIElEIFZhcmlhYmxlICJEYXRlIi4KCmBgYHtyfQpsb25nMiA8LSByZXNoYXBlMjo6bWVsdChvaWxfcHJpY2UsIGlkLnZhcnMgPSAiRGF0ZSIpIApzdHIobG9uZzIpCmBgYAoKVGhlIHRyYW5zZm9ybWVkIGRhdGEgc2V0LCAiTG9uZzIiLCByZXF1aXJlcyB0aGUgdmFyaWFibGUgIkRhdGUiIHRvIGJlIHRyYW5zZm9ybWVkIGZyb20gYSBzdHJpbmcgdG8gYSBEYXRlIGZvcm1hdC4gVGhpcyB3aWxsIGFsbG93IEdHcGxvdCB0byByZWNvZ25pemUgdGhlIGRhdGUgaXQgaXMgcHJvY2Vzc2luZy4KCmBgYHtyfQpsb25nMiREYXRlIDwtIGFzLkRhdGUobG9uZzIkRGF0ZSwgZm9ybWF0PSIlZC8lbS8lWSIpCnN0cihsb25nMikKYGBgCgojIyMgV2hlYXQgRXhwb3J0cwoKVGhpcyBkYXRhIHNldCBuZWVkcyB0byBiZSB3cmFuZ2xlZCBpbiBvcmRlciB0byBtYWtlIHRoZSBkYXRhIGVhc2llciB0byBoYW5kbGUuCgpgYGB7cn0KY29ubiA8LSBzcmNfbWVtZGIoKSAgIyBUaGlzIGZ1bmN0aW9uIHNldHMgdXAgYSBkYXRhYmFzZSB0aHJvdWdoIHdoaWNoIHdlIGNhbiB3cml0ZSBTUUwgcXVlcmllcwoKY29weV90byhjb25uLCAKICAgICAgICBGQU9UcmFkZURhdGEsCiAgICAgICAgb3ZlcndyaXRlICA9IFRSVUUpICMgVGhpcyBmdW5jdGlvbiBwb3B1bGF0ZXMgdGhlIGRhdGFiYXNlIHdpdGggdmFsdWVzIHVzaW5nIHRoZSBEYXRhIEZyYW1lICJGQU9UcmFkZURhdGEiCmBgYAoKVGhpcyBjb2RlIGxheXMgdGhlIGdyb3VuZCB3b3JrIGZvciBOYXRpdmUgU1FMIHF1ZXJpZXMgaW4gUi4gVGhlIE5leHQgc3RlcCB3aWxsIHJ1biBhIHF1ZXJ5IG9uIHRoZSBFeHBvcnQgZGF0YSBzZXQgYW5kIGZpbmQgb3V0IHRoZSB0b3AgMjAgZXhwb3J0ZXJzIG9mIFdoZWF0LgoKCmBgYHtyfQpHRSA8LSB0YmwoY29ubiwgc3FsKCJTRUxFQ1QgQVJFQSwKICAgICAgICAgICAgICAgICAgICAgIFZBTFVFCiAgICAgICAgICAgICAgRlJPTSBGQU9UcmFkZURhdGEgCiAgICAgICAgICAgICAgV0hFUkUgCiAgICAgICAgICAgICAgWWVhciA9IDIwMjAgQU5EIEVsZW1lbnQgPSAnRXhwb3J0IFZhbHVlJyBBTkQKICAgICAgICAgICAgICBJdGVtID0gJ1doZWF0JwogICAgICAgICAgICAgIEdST1VQIEJZIEFSRUEKICAgICAgICAgICAgICBPUkRFUiBCWSBWQUxVRSBERVNDCiAgICAgICAgICAgICAgTGltaXQgMjAKICAgICAgICAgICAgICAiKSkKYGBgCgpMYWJlbGluZyB3aWxsIGFsbG93IG1lIHRvIGNvbnZlcnQgdGhlIHF1ZXJ5IGludG8gYSBkYXRhIGZyYW1lIGZvciB2aXN1YWxpemF0aW9uLgoKYGBge3J9CkdyYWluRXhwb3J0ZXJzIDwtIGFzLmRhdGEuZnJhbWUoR0UpCnN0cihHcmFpbkV4cG9ydGVycykKYGBgCgojIyMgT2lsIEV4cG9ydHMKClRoZSBJbXBvcnRzIHByb2Nlc3Mgd2lsbCBsYXJnZWx5IG1pcnJvciB0aGUgV2hlYXQgRXhwb3J0IFByb2Nlc3MuIFRoaXMgY29kZSBsYXlzIHRoZSBncm91bmQgd29yayBmb3IgTmF0aXZlIFNRTCBxdWVyaWVzIGluIFIuIFRoZSBOZXh0IHN0ZXAgd2lsbCBydW4gYSBxdWVyeSBvbiB0aGUgaW1wb3J0IGRhdGEgc2V0IGFuZCBmaW5kIG91dCB0aGUgdG9wIDIwIEltcG9ydGVycyBvZiBXaGVhdC4KCmBgYHtyfQpPSSA8LSB0YmwoY29ubiwgc3FsKCJTRUxFQ1QgQVJFQSwKICAgICAgICAgICAgICAgICAgICAgIFZBTFVFCiAgICAgICAgICAgICAgRlJPTSBGQU9UcmFkZURhdGEKICAgICAgICAgICAgICBXSEVSRSAKICAgICAgICAgICAgICBZZWFyID0gMjAyMCBBTkQgRWxlbWVudCA9ICdFeHBvcnQgVmFsdWUnIEFORAogICAgICAgICAgICAgIChJdGVtID0gJ1N1bmZsb3dlci1zZWVkIG9pbCwgY3J1ZGUnKQogICAgICAgICAgICAgIEdST1VQIEJZIEFSRUEKICAgICAgICAgICAgICBPUkRFUiBCWSBWQUxVRSBERVNDCiAgICAgICAgICAgICAgTGltaXQgMjAKICAgICAgICAgICAgICAiKSkKYGBgCgpMYWJlbGluZyB3aWxsIGFsbG93IG1lIHRvIGNvbnZlcnQgdGhlIHF1ZXJ5IGludG8gYSBkYXRhIGZyYW1lIGZvciB2aXN1YWxpemF0aW9uLgoKYGBge3J9Ck9pbEV4cG9ydGVycyA8LSBhcy5kYXRhLmZyYW1lKE9JKQpzdHIoT2lsRXhwb3J0ZXJzKQpgYGAKCgojIyBWaXN1YWxpc2F0aW9uCgojIyMgR2xvYmFsIEZvb2QgUHJpY2VzCgpJIGhhdmUgY2hvc2VuIHRvIGRpc3BsYXkgdGhpcyBkYXRhIGFzIGEgbGluZSBncmFwaC4gVGhpcyBmb3JtYXQgd2lsbCBhbGxvdyBtZSB0byBkaXNwbGF5IGRhdGEgb3ZlciB0aGUgbGFzdCA1IHllYXJzLiAKCmBgYHtyfQpnZ3Bsb3QobG9uZywgYWVzKHg9RGF0ZSwgeSA9IHZhbHVlLCBncm91cCA9IHZhcmlhYmxlLCBjb2xvdXIgPSB2YXJpYWJsZSkpICsKICBnZW9tX2xpbmUoKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyNzApKSsKICBnZ3RpdGxlKCJGQU8gR2xvYmFsIEZvb2QgUHJpY2VzICgyMDE3LTIwMjIpIikrCiAgbGFicyhjb2xvdXIgPSAiRm9vZCBUeXBlcyIsIHN1YnRpdGxlID0gIkFjcXVpcmVkIGZyb20gdGhlIFVOIikrCiAgc2NhbGVfeF9kYXRlKGxpbWl0cyA9IGFzLkRhdGUoYygnMjAxNy0wMS0wMScsJzIwMjItMDktMDEnKSkpCmBgYApDb25zaWRlcmluZyB0aGUgZGF0YSBvdXRsaW5lZCBieSB0aGUgRkFPLCBpdCBzZWVtcyB0aGF0IHRoZSBtYWluIGZvb2QgZ3JvdXBzIGluIHF1ZXN0aW9uIGFyZSBNZWF0LCBEYWlyeSwgQ2VyZWFscywgT2lscywgU3VnYXIuIE9pbCBhbmQgQ2VyZWFscyBoYXZlIHJpc2VuIHRoZSBtb3N0IG92ZXIgdGhlIHBhc3QgeWVhci4gSXQgc2VlbXMgZnJvbSB0aGUgZGF0YSBhdmFpbGFibGUgdGhhdCB0aGUgY3VycmVudCBmb29kIHByaWNlIGhhcyB5ZXQgdG8gcmVjb3ZlciBmcm9tIHRoZSBjb21wb3VuZGVkIGVmZmVjdHMgb2YgdGhlIDIwMjAgQ09WSUQgUGFuZGVtaWMuIE1vcmVvdmVyLCBpdCBpcyBjbGVhciB0aGF0IG9pbCBwcmljZXMgaGF2ZSByaXNlbiBzaGFycGx5IG92ZXIgdGhlIHBhc3QgeWVhci4gR2FyZXRoIFByaWNlLCBleHBlcnQgZnJvbSBDaGF0aGFtIEhvdXNlLCB2YWxpZGF0ZXMgdGhpcyBoeXBvdGhlc2lzIG5vdGluZyB0aGF0IGdsb2JhbCBzdXBwbHkgY2hhaW5zIGFyZSB5ZXQgdG8gcmVjb3ZlciBmcm9tIHRoZSBDT1ZJRC0xOSBwYW5kZW1pYy4KCiMjIyBHbG9iYWwgT2lsIFByaWNlcwoKSSBoYXZlIGNob3NlbiB0byBkaXNwbGF5IHRoaXMgZGF0YSBhcyBhIGxpbmUgZ3JhcGguIFRoaXMgZm9ybWF0IHdpbGwgYWxsb3cgbWUgdG8gZGlzcGxheSBkYXRhIG92ZXIgdGhlIGxhc3QgNSB5ZWFycy4gCgpgYGB7cn0KZ2dwbG90KGxvbmcyLCBhZXMoeD1EYXRlLCB5ID0gdmFsdWUsIGdyb3VwID0gdmFyaWFibGUsIGNvbG91ciA9IHZhcmlhYmxlKSkgKwogIGdlb21fbGluZSgpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDMwMDApKSsKICBnZ3RpdGxlKCJGQU8gR2xvYmFsIEZvb2QgUHJpY2VzICgyMDE3LTIwMjIpIikrCiAgbGFicyhjb2xvdXIgPSAiRm9vZCBUeXBlcyIsIHN1YnRpdGxlID0gIkFjcXVpcmVkIGZyb20gdGhlIFVOIikKYGBgClRoZSBzd2luZyBpbiBwcmljZSBpcyBsYXJnZXN0IGluIHRoZSBzdW5mbG93ZXIgb2lsLCB3aGF0IHdpbGwgYmUgZGVtb25zdHJhdGVkIGxhdGVyIGFzIGFuIGltcG9ydGFudCBleHBvcnQgb2YgYm90aCBSdXNzaWEgYW5kIFVrcmFpbmUuCgojIyMgV2hlYXQgRXhwb3J0CgpUaGlzIHZpc3VhbCB3aWxsIGJlIGRpc3BsYXllZCBhcyBhIGJhciBncmFwaC4gVGhpcyB3aWxsIGhlbHAgY29tcGFyZSB0aGUgZXhwb3J0cyB2YWx1ZSBvZiB0aGUgd29ybGQncyAyMCBsYXJnZXN0IHdoZWF0IGV4cG9ydGVycy4KCmBgYHtyfQpnZ3Bsb3QoR3JhaW5FeHBvcnRlcnMsIGFlcyh4ID0gcmVvcmRlcihBcmVhLCAtVmFsdWUpLCB5ID0gVmFsdWUsIGZpbGw9QXJlYSkpKwogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJVa3JhaW5lIiA9ICJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJ1c3NpYW4gRmVkZXJhdGlvbiIgPSAicmVkIikpKwogIGdndGl0bGUoIkxhcmdlc3QgV2hlYXQgRXhwb3J0ZXJzIDIwMjAiKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKQpgYGAKV2hhdCB0aGlzIGRlbW9uc3RyYXRlcyBpcyB0aGUgcm9sZSBVa3JhaW5lIGFuZCBSdXNzaWEgcGxheSBpbiB0aGUgZ2xvYmFsIGdyYWluIG1hcmtldHMuIEl0J3MgY2xlYXIgdGhhdCB0aGUgYmxvY2thZGUgb2YgVWtyYWluaWFuIFBvcnRzIGFuZCBzYW5jdGlvbmluZyBvZiBSdXNzaWFuIGV4cG9ydHMuCgojIyMgT2lsIEV4cG9ydHMKClRoaXMgdmlzdWFsIHdpbGwgYmUgZGlzcGxheWVkIGFzIGEgYmFyIGdyYXBoLiBUaGlzIHdpbGwgaGVscCBjb21wYXJlIHRoZSBleHBvcnRzIHZhbHVlIG9mIHRoZSB3b3JsZCdzIDIwIGxhcmdlc3QgT2lsIGV4cG9ydGVycy4KCmBgYHtyfQpnZ3Bsb3QoT2lsRXhwb3J0ZXJzLCBhZXMoeCA9IHJlb3JkZXIoQXJlYSwgLVZhbHVlKSwgeSA9IFZhbHVlLCBmaWxsPUFyZWEpKSsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiVWtyYWluZSIgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSdXNzaWFuIEZlZGVyYXRpb24iID0gInJlZCIpKSsKICBnZ3RpdGxlKCJMYXJnZXN0IFN1bmZsb3dlciBPaWwgRXhwb3J0ZXJzIDIwMjAiKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKQpgYGAKV2hhdCB0aGlzIGRlbW9uc3RyYXRlcyBpcyB0aGUgcm9sZSBVa3JhaW5lIGFuZCBSdXNzaWEgcGxheSBpbiB0aGUgZ2xvYmFsIGdyYWluIG1hcmtldHMuIEl0J3MgY2xlYXIgdGhhdCB0aGUgYmxvY2thZGUgb2YgVWtyYWluaWFuIFBvcnRzIGFuZCBzYW5jdGlvbmluZyBvZiBSdXNzaWFuIGV4cG9ydHMuCgoK