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:

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