We’ll be working with grain yield data from the United States Department of Agriculture, National Agricultural Statistics Service. Unfortunately, they report all areas in acres. So, the first thing you need to do is write some utility functions to convert areas in acres to areas in hectares.
To solve this exercise, you need to know the following:
- There are 4840 square yards in an acre.
- There are 36 inches in a yard and one inch is 0.0254 meters.
- There are 10000 square meters in a hectare.
Converting areas to metric
Acres to squared yards
# Write a function to convert acres to sq. yards
acres_to_sq_yards <- function(acres) {
acres * 4840
}
yard to meters
# Write a function to convert yards to meters
yards_to_meters <- function(yards) {
(yards * 36) * 0.0254
}
meters to hectares
sq_meters_to_hectares <- function(sq_meters) {
sq_meters / 10000
}
We can bring everything together to write the overall acres-to-hectares conversion function. magrittr’s raise_to_power() will be useful here.
library(magrittr)
Squared yards to squared meters
# Write a function to convert sq. yards to sq. meters
sq_yards_to_sq_meters <- function(sq_yards) {
sq_yards %>%
# Take the square root
sqrt() %>%
# Convert yards to meters
yards_to_meters() %>%
# Square it
raise_to_power(2)
}
Acres to hectares
# Write a function to convert acres to hectares
acres_to_hectares <- function(acres) {
acres %>%
# Convert acres to sq yards
acres_to_sq_yards() %>%
# Convert sq yards to sq meters
sq_yards_to_sq_meters() %>%
# Convert sq meters to hectares
sq_meters_to_hectares()
}
harmonic acres to hectares
Function to harmonically convert areas in acres to hectares. The function should get the reciprocal of the input, then convert from acres to hectares, then get the reciprocal again.
# reciprocal function
get_reciprocal <- function(x) {
1/x
}
# Define a harmonic acres to hectares function
harmonic_acres_to_hectares <- function(acres) {
acres %>%
# Get the reciprocal
get_reciprocal() %>%
# Convert acres to hectares
acres_to_hectares() %>%
# Get the reciprocal again
get_reciprocal()
}
Converting yields to metric
The yields in the NASS corn data are also given in US units, namely bushels per acre. You’ll need to write some more utility functions to convert this unit to the metric unit of kg per hectare.
Bushels historically meant a volume of 8 gallons, but in the context of grain, they are now defined as masses. This mass differs for each grain!
- One pound (lb) is 0.45359237 kilograms (kg).
- One bushel is 48 lbs of barley, 56 lbs of corn, or 60 lbs of wheat.
# Write a function to convert lb to kg
lbs_to_kgs <- function(lbs){
lbs * 0.45359237
}
# Write a function to convert bushels to lbs
bushels_to_lbs <- function(bushels, crop) {
# Define a lookup table of scale factors
c(barley = 48, corn = 56, wheat = 60) %>%
# Extract the value for the crop
extract(crop) %>%
# Multiply by the no. of bushels
multiply_by(bushels)
}
# Write a function to convert bushels to kg
bushels_to_kgs <- function(bushels, crop) {
bushels %>%
# Convert bushels to lbs for this crop
bushels_to_lbs(crop) %>%
# Convert lbs to kgs
lbs_to_kgs()
}
# Write a function to convert bushels/acre to kg/ha
bushels_per_acre_to_kgs_per_hectare <- function(bushels_per_acre, crop = c("barley", "corn", "wheat")) {
# Match the crop argument
crop <- match.arg(crop)
bushels_per_acre %>%
# Convert bushels to kgs for this crop
bushels_to_kgs(crop) %>%
# Convert harmonic acres to ha
harmonic_acres_to_hectares()
}
Applying the unit conversion
Now that we’ve written some functions, it’s time to apply them! The NASS corn dataset is available, and you can fortify it (jargon for “adding new columns”) with metrics areas and yields.
This fortification process can also be turned in to a function, so you’ll define a function for this, and test it on the NASS wheat dataset.
library(dplyr)
library(agridat)
corn <- nass.corn
wheat <- nass.wheat
barley <- nass.barley
glimpse(corn)
Rows: 6,381
Columns: 4
$ year [3m[90m<int>[39m[23m 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866, 18…
$ state [3m[90m<fct>[39m[23m Alabama, Arkansas, California, Connecticut, Delaware, Fl…
$ acres [3m[90m<dbl>[39m[23m 1050000, 280000, 42000, 57000, 200000, 125000, 1770000, …
$ yield [3m[90m<dbl>[39m[23m 9.0, 18.0, 28.0, 34.0, 23.0, 9.0, 6.0, 29.0, 36.5, 32.0,…
corn <- corn %>%
# Add some columns
mutate(
# Convert farmed area from acres to ha
farmed_area_ha = acres_to_hectares(acres),
# Convert yield from bushels/acre to kg/ha
yield_kg_per_ha = bushels_per_acre_to_kgs_per_hectare(
yield,
crop = "corn"
)
)
head(corn)
We can wrap the mutation code into a function, fortify_with_metric_units.
# Wrap this code into a function
fortify_with_metric_units <- function(data, crop) {
data %>%
mutate(
farmed_area_ha = acres_to_hectares(acres),
yield_kg_per_ha = bushels_per_acre_to_kgs_per_hectare(
yield,
crop = crop
)
)
}
# Try it on the wheat dataset
wheat <- fortify_with_metric_units(wheat, crop = "wheat")
head(wheat)
Plotting yields over time
Now that the units have been dealt with, it’s time to explore the datasets. An obvious question to ask about each crop is, “how do the yields change over time in each US state?” Let’s draw a line plot to find out.
library(ggplot2)
# Using corn, plot yield (kg/ha) vs. year
ggplot(corn, aes(x = year, y = yield_kg_per_ha)) +
# Add a line layer, grouped by state
geom_line(aes(group = state)) +
# Add a smooth trend layer
geom_smooth()

Create plotting function
# Wrap this plotting code into a function
plot_yield_vs_year <- function(data){
ggplot(data, aes(year, yield_kg_per_ha)) +
geom_line(aes(group = state)) +
geom_smooth()
}
We can now plot wheat
# Test it on the wheat dataset
plot_yield_vs_year(wheat)

Look at the huge increase in yields from the time of the Green Revolution in the 1950s.
A nation divided
The USA has a varied climate, so we might expect yields to differ between states. Rather than trying to reason about 50 states separately, we can use the USA Census Regions to get 9 groups.
The “Corn Belt”, where most US corn is grown is in the “West North Central” and “East North Central” regions. The “Wheat Belt” is in the “West South Central” region.
Let´s load the USA census region
usa_census_regions <- read_csv("us_data_census.csv")
Parsed with column specification:
cols(
State = [31mcol_character()[39m,
`State Code` = [31mcol_character()[39m,
Region = [31mcol_character()[39m,
Division = [31mcol_character()[39m
)
usa_census_regions <- usa_census_regions[ , -c(2, 3)]
colnames(usa_census_regions) <- c("state", "census_region")
usa_census_regions <- usa_census_regions[ , c(2, 1)]
head(usa_census_regions)
#creating census regions variable
census_regions <- unique(usa_census_regions[,1])
#("census_region" = region)
census_regions
# Inner join the corn dataset to usa_census_regions by state
corn <- corn %>%
inner_join(usa_census_regions, by = "state")
Column `state` joining factor and character vector, coercing into character vector
head(corn)
We can turn the code into a function
fortify_with_census_region <- function(data){
data %>%
inner_join(usa_census_regions, by = "state")
}
wheat <- fortify_with_census_region(wheat)
Column `state` joining factor and character vector, coercing into character vector
head(wheat)
With the census data incorporated into the crop datasets, we can now look at yield differences between the regions.
Plotting yields over time by region
So far, you have a function to plot yields over time for each crop, and you’ve added a census_region column to the crop datasets. Now we are ready to look at how the yields change over time in each region of the USA.
# Plot yield vs. year for the corn dataset
plot_yield_vs_year(corn) +
# Facet, wrapped by census region
facet_wrap(vars(census_region))

# Wrap this code into a function
plot_yield_vs_year_by_region <- function(data){
plot_yield_vs_year(data) +
facet_wrap(vars(census_region))
}
# Try it on the wheat dataset
plot_yield_vs_year_by_region(wheat)

Radical regional yield analysis! Reassuringly, the corn yields are highest in the West North Central region, the heart of the Corn Belt. For wheat, it looks like the yields are highest in the Wheat Belt (West South Central region) have been overtaken by some other regions.
Running a model
The smooth trend line we see in the plots of yield over time use a generalized additive model (GAM) to determine where the line should lie. This sort of model is ideal for fitting nonlinear curves. So we can make predictions about future yields, let’s explicitly run the model. The syntax for running this GAM takes the following form.
gam(response ~ s(explanatory_var1) + explanatory_var2, data = dataset)
Here, s() means “make the variable smooth”, where smooth very roughly means nonlinear.
library(mgcv)
# Run a generalized additive model of
# yield vs. smoothed year and census region
gam(yield_kg_per_ha ~ s(year) + census_region, data = corn)
Family: gaussian
Link function: identity
Formula:
yield_kg_per_ha ~ s(year) + census_region
Estimated degrees of freedom:
7.64 total = 16.64
GCV score: 836963
We can wrap the code into a function and apply to wheat as well.
# Wrap the model code into a function
run_gam_yield_vs_year_by_region <- function(data){
gam(yield_kg_per_ha ~ s(year) + census_region, data = data)
}
# Try it on the wheat dataset
run_gam_yield_vs_year_by_region(wheat)
Family: gaussian
Link function: identity
Formula:
yield_kg_per_ha ~ s(year) + census_region
Estimated degrees of freedom:
7.03 total = 16.03
GCV score: 316685.5
Making yield predictions
We can make predictions using a call to predict(), in the following form.
predict(model, cases_to_predict, type = "response")
# we can assign our model to a variable
corn_model = run_gam_yield_vs_year_by_region(corn)
wheat_model = run_gam_yield_vs_year_by_region(wheat)
# Make predictions in 2050
predict_this <- data.frame(
year = 2050,
census_region = census_regions
)
predict_this
# Predict the yield
pred_yield_kg_per_ha <- predict(corn_model,
predict_this,
type = "response")
corn_prediction <- predict_this %>%
# Add the prediction as a column of predict_this
mutate(pred_yield_kg_per_ha = c(pred_yield_kg_per_ha))
corn_prediction
We can wrap the script into a function
# Wrap this prediction code into a function
predict_yields <- function(model, year){
predict_this <- data.frame(
year = year,
census_region = census_regions
)
pred_yield_kg_per_ha <- predict(model, predict_this, type = "response")
predict_this %>%
mutate(pred_yield_kg_per_ha = c(pred_yield_kg_per_ha))
}
# Try it on the wheat dataset
wheat_prediction <- predict_yields(wheat_model,
year = 2050)
wheat_prediction
The models predict that in 2050, the highest yields will be in the Pacific region for both corn and wheat.
Do it all over again
Now you are going to rerun the whole analysis from this chapter on a new crop, barley. Since all the infrastructure is in place, that’s less effort than it sounds!
Barley prefers a cooler climate compared to corn and wheat and is commonly grown in the US mountain states of Idaho and Montana.
fortified_barley <- barley %>%
# Fortify with metric units
fortify_with_metric_units("barley") %>%
# Fortify with census regions
fortify_with_census_region()
Column `state` joining factor and character vector, coercing into character vector
# See the result
glimpse(fortified_barley)
Rows: 4,839
Columns: 7
$ year [3m[90m<int>[39m[23m 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866…
$ state [3m[90m<chr>[39m[23m "Connecticut", "Illinois", "Indiana", "Iowa", …
$ acres [3m[90m<dbl>[39m[23m 1000, 96000, 11000, 66000, 2000, 10000, 34000,…
$ yield [3m[90m<dbl>[39m[23m 22.5, 23.4, 23.0, 22.0, 23.0, 23.5, 21.5, 25.5…
$ farmed_area_ha [3m[90m<dbl>[39m[23m 404.6856, 38849.8217, 4451.5421, 26709.2524, 8…
$ yield_kg_per_ha [3m[90m<dbl>[39m[23m 1210.5192, 1258.9400, 1237.4197, 1183.6188, 12…
$ census_region [3m[90m<chr>[39m[23m "New England", "East North Central", "East Nor…
# Plot yield vs. year by region
plot_yield_vs_year_by_region(fortified_barley)

fortified_barley %>%
# Run a GAM of yield vs. year by region
run_gam_yield_vs_year_by_region %>%
# Make predictions of yields in 2050
predict_yields(2050)
Since all your analysis code was contained in functions, it was really simple to apply it to another dataset. Here you can see that yields are highest in the Mountain region, and the model predicts that this will still be the case in 2050.
LS0tCnRpdGxlOiAiUHJvamVjdDogR3JhaW4geWllbGRzIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCiAgICAKdG9jX2RlcHRoOiAzCi0tLQoKV2UnbGwgYmUgd29ya2luZyB3aXRoIGdyYWluIHlpZWxkIGRhdGEgZnJvbSB0aGUgVW5pdGVkIFN0YXRlcyBEZXBhcnRtZW50IG9mIEFncmljdWx0dXJlLCBOYXRpb25hbCBBZ3JpY3VsdHVyYWwgU3RhdGlzdGljcyBTZXJ2aWNlLiBVbmZvcnR1bmF0ZWx5LCB0aGV5IHJlcG9ydCBhbGwgYXJlYXMgaW4gYWNyZXMuIFNvLCB0aGUgZmlyc3QgdGhpbmcgeW91IG5lZWQgdG8gZG8gaXMgd3JpdGUgc29tZSB1dGlsaXR5IGZ1bmN0aW9ucyB0byBjb252ZXJ0IGFyZWFzIGluIGFjcmVzIHRvIGFyZWFzIGluIGhlY3RhcmVzLgoKVG8gc29sdmUgdGhpcyBleGVyY2lzZSwgeW91IG5lZWQgdG8ga25vdyB0aGUgZm9sbG93aW5nOgoKIC0gVGhlcmUgYXJlIDQ4NDAgc3F1YXJlIHlhcmRzIGluIGFuIGFjcmUuCiAtIFRoZXJlIGFyZSAzNiBpbmNoZXMgaW4gYSB5YXJkIGFuZCBvbmUgaW5jaCBpcyAwLjAyNTQgbWV0ZXJzLgogLSBUaGVyZSBhcmUgMTAwMDAgc3F1YXJlIG1ldGVycyBpbiBhIGhlY3RhcmUuCgojIENvbnZlcnRpbmcgYXJlYXMgdG8gbWV0cmljCgojIyBBY3JlcyB0byBzcXVhcmVkIHlhcmRzCmBgYHtyfQojIFdyaXRlIGEgZnVuY3Rpb24gdG8gY29udmVydCBhY3JlcyB0byBzcS4geWFyZHMKYWNyZXNfdG9fc3FfeWFyZHMgPC0gZnVuY3Rpb24oYWNyZXMpIHsKICBhY3JlcyAqIDQ4NDAKfQpgYGAKIyMgeWFyZCB0byBtZXRlcnMKYGBge3J9CiMgV3JpdGUgYSBmdW5jdGlvbiB0byBjb252ZXJ0IHlhcmRzIHRvIG1ldGVycwp5YXJkc190b19tZXRlcnMgPC0gZnVuY3Rpb24oeWFyZHMpIHsKICAoeWFyZHMgKiAzNikgKiAwLjAyNTQKfQpgYGAKIyMgbWV0ZXJzIHRvIGhlY3RhcmVzCmBgYHtyfQpzcV9tZXRlcnNfdG9faGVjdGFyZXMgPC0gZnVuY3Rpb24oc3FfbWV0ZXJzKSB7CiAgc3FfbWV0ZXJzIC8gMTAwMDAKfQpgYGAKV2UgY2FuIGJyaW5nIGV2ZXJ5dGhpbmcgdG9nZXRoZXIgdG8gd3JpdGUgdGhlIG92ZXJhbGwgYWNyZXMtdG8taGVjdGFyZXMgY29udmVyc2lvbiBmdW5jdGlvbi4KbWFncml0dHIncyByYWlzZV90b19wb3dlcigpIHdpbGwgYmUgdXNlZnVsIGhlcmUuCmBgYHtyfQpsaWJyYXJ5KG1hZ3JpdHRyKQpgYGAKIyMgU3F1YXJlZCB5YXJkcyB0byBzcXVhcmVkIG1ldGVycwpgYGB7cn0KIyBXcml0ZSBhIGZ1bmN0aW9uIHRvIGNvbnZlcnQgc3EuIHlhcmRzIHRvIHNxLiBtZXRlcnMKc3FfeWFyZHNfdG9fc3FfbWV0ZXJzIDwtIGZ1bmN0aW9uKHNxX3lhcmRzKSB7CiAgc3FfeWFyZHMgJT4lCiAgICAjIFRha2UgdGhlIHNxdWFyZSByb290CiAgICBzcXJ0KCkgJT4lCiAgICAjIENvbnZlcnQgeWFyZHMgdG8gbWV0ZXJzCiAgICB5YXJkc190b19tZXRlcnMoKSAlPiUKICAgICMgU3F1YXJlIGl0CiAgICByYWlzZV90b19wb3dlcigyKQp9CmBgYAojIyBBY3JlcyB0byBoZWN0YXJlcwpgYGB7cn0KIyBXcml0ZSBhIGZ1bmN0aW9uIHRvIGNvbnZlcnQgYWNyZXMgdG8gaGVjdGFyZXMKYWNyZXNfdG9faGVjdGFyZXMgPC0gZnVuY3Rpb24oYWNyZXMpIHsKICBhY3JlcyAlPiUKICAgICMgQ29udmVydCBhY3JlcyB0byBzcSB5YXJkcwogICAgYWNyZXNfdG9fc3FfeWFyZHMoKSAlPiUKICAgICMgQ29udmVydCBzcSB5YXJkcyB0byBzcSBtZXRlcnMKICAgIHNxX3lhcmRzX3RvX3NxX21ldGVycygpICU+JQogICAgIyBDb252ZXJ0IHNxIG1ldGVycyB0byBoZWN0YXJlcwogICAgc3FfbWV0ZXJzX3RvX2hlY3RhcmVzKCkKfQpgYGAKIyMgaGFybW9uaWMgYWNyZXMgdG8gaGVjdGFyZXMKCkZ1bmN0aW9uIHRvIGhhcm1vbmljYWxseSBjb252ZXJ0IGFyZWFzIGluIGFjcmVzIHRvIGhlY3RhcmVzLiBUaGUgZnVuY3Rpb24gc2hvdWxkIGdldCB0aGUgcmVjaXByb2NhbCBvZiB0aGUgaW5wdXQsIHRoZW4gY29udmVydCBmcm9tIGFjcmVzIHRvIGhlY3RhcmVzLCB0aGVuIGdldCB0aGUgcmVjaXByb2NhbCBhZ2Fpbi4KYGBge3J9CiMgcmVjaXByb2NhbCBmdW5jdGlvbgpnZXRfcmVjaXByb2NhbCA8LSBmdW5jdGlvbih4KSB7CiAxL3gKfQoKIyBEZWZpbmUgYSBoYXJtb25pYyBhY3JlcyB0byBoZWN0YXJlcyBmdW5jdGlvbgpoYXJtb25pY19hY3Jlc190b19oZWN0YXJlcyA8LSBmdW5jdGlvbihhY3JlcykgewogIGFjcmVzICU+JSAKICAgICMgR2V0IHRoZSByZWNpcHJvY2FsCiAgICBnZXRfcmVjaXByb2NhbCgpICU+JQogICAgIyBDb252ZXJ0IGFjcmVzIHRvIGhlY3RhcmVzCiAgICBhY3Jlc190b19oZWN0YXJlcygpICU+JSAKICAgICMgR2V0IHRoZSByZWNpcHJvY2FsIGFnYWluCiAgICBnZXRfcmVjaXByb2NhbCgpCn0KYGBgCiMgQ29udmVydGluZyB5aWVsZHMgdG8gbWV0cmljCgpUaGUgeWllbGRzIGluIHRoZSBOQVNTIGNvcm4gZGF0YSBhcmUgYWxzbyBnaXZlbiBpbiBVUyB1bml0cywgbmFtZWx5IGJ1c2hlbHMgcGVyIGFjcmUuIFlvdSdsbCBuZWVkIHRvIHdyaXRlIHNvbWUgbW9yZSB1dGlsaXR5IGZ1bmN0aW9ucyB0byBjb252ZXJ0IHRoaXMgdW5pdCB0byB0aGUgbWV0cmljIHVuaXQgb2Yga2cgcGVyIGhlY3RhcmUuCgpCdXNoZWxzIGhpc3RvcmljYWxseSBtZWFudCBhIHZvbHVtZSBvZiA4IGdhbGxvbnMsIGJ1dCBpbiB0aGUgY29udGV4dCBvZiBncmFpbiwgdGhleSBhcmUgbm93IGRlZmluZWQgYXMgbWFzc2VzLiBUaGlzIG1hc3MgZGlmZmVycyBmb3IgZWFjaCBncmFpbiEKCiAtIE9uZSBwb3VuZCAobGIpIGlzIDAuNDUzNTkyMzcga2lsb2dyYW1zIChrZykuCiAtIE9uZSBidXNoZWwgaXMgNDggbGJzIG9mIGJhcmxleSwgNTYgbGJzIG9mIGNvcm4sIG9yIDYwIGxicyBvZiB3aGVhdC4KYGBge3J9CiMgV3JpdGUgYSBmdW5jdGlvbiB0byBjb252ZXJ0IGxiIHRvIGtnCmxic190b19rZ3MgPC0gZnVuY3Rpb24obGJzKXsKICBsYnMgKiAwLjQ1MzU5MjM3Cn0KYGBgCmBgYHtyfQojIFdyaXRlIGEgZnVuY3Rpb24gdG8gY29udmVydCBidXNoZWxzIHRvIGxicwpidXNoZWxzX3RvX2xicyA8LSBmdW5jdGlvbihidXNoZWxzLCBjcm9wKSB7CiAgIyBEZWZpbmUgYSBsb29rdXAgdGFibGUgb2Ygc2NhbGUgZmFjdG9ycwogIGMoYmFybGV5ID0gNDgsIGNvcm4gPSA1Niwgd2hlYXQgPSA2MCkgJT4lCiAgICAjIEV4dHJhY3QgdGhlIHZhbHVlIGZvciB0aGUgY3JvcAogICAgZXh0cmFjdChjcm9wKSAlPiUKICAgICMgTXVsdGlwbHkgYnkgdGhlIG5vLiBvZiBidXNoZWxzCiAgICBtdWx0aXBseV9ieShidXNoZWxzKQp9CmBgYApgYGB7cn0KIyBXcml0ZSBhIGZ1bmN0aW9uIHRvIGNvbnZlcnQgYnVzaGVscyB0byBrZwpidXNoZWxzX3RvX2tncyA8LSBmdW5jdGlvbihidXNoZWxzLCBjcm9wKSB7CiAgYnVzaGVscyAlPiUKICAgICMgQ29udmVydCBidXNoZWxzIHRvIGxicyBmb3IgdGhpcyBjcm9wCiAgICBidXNoZWxzX3RvX2xicyhjcm9wKSAlPiUKICAgICMgQ29udmVydCBsYnMgdG8ga2dzCiAgICBsYnNfdG9fa2dzKCkKfQpgYGAKYGBge3J9CiMgV3JpdGUgYSBmdW5jdGlvbiB0byBjb252ZXJ0IGJ1c2hlbHMvYWNyZSB0byBrZy9oYQpidXNoZWxzX3Blcl9hY3JlX3RvX2tnc19wZXJfaGVjdGFyZSA8LSBmdW5jdGlvbihidXNoZWxzX3Blcl9hY3JlLCBjcm9wID0gYygiYmFybGV5IiwgImNvcm4iLCAid2hlYXQiKSkgewogICMgTWF0Y2ggdGhlIGNyb3AgYXJndW1lbnQKICBjcm9wIDwtIG1hdGNoLmFyZyhjcm9wKQogIGJ1c2hlbHNfcGVyX2FjcmUgJT4lCiAgICAjIENvbnZlcnQgYnVzaGVscyB0byBrZ3MgZm9yIHRoaXMgY3JvcAogICAgYnVzaGVsc190b19rZ3MoY3JvcCkgJT4lCiAgICAjIENvbnZlcnQgaGFybW9uaWMgYWNyZXMgdG8gaGEKICAgIGhhcm1vbmljX2FjcmVzX3RvX2hlY3RhcmVzKCkKfQpgYGAKIyBBcHBseWluZyB0aGUgdW5pdCBjb252ZXJzaW9uCgoKTm93IHRoYXQgd2UndmUgd3JpdHRlbiBzb21lIGZ1bmN0aW9ucywgaXQncyB0aW1lIHRvIGFwcGx5IHRoZW0hIFRoZSBOQVNTIGNvcm4gZGF0YXNldCBpcyBhdmFpbGFibGUsIGFuZCB5b3UgY2FuIGZvcnRpZnkgaXQgKGphcmdvbiBmb3IgImFkZGluZyBuZXcgY29sdW1ucyIpIHdpdGggbWV0cmljcyBhcmVhcyBhbmQgeWllbGRzLgoKVGhpcyBmb3J0aWZpY2F0aW9uIHByb2Nlc3MgY2FuIGFsc28gYmUgdHVybmVkIGluIHRvIGEgZnVuY3Rpb24sIHNvIHlvdSdsbCBkZWZpbmUgYSBmdW5jdGlvbiBmb3IgdGhpcywgYW5kIHRlc3QgaXQgb24gdGhlIE5BU1Mgd2hlYXQgZGF0YXNldC4KYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoYWdyaWRhdCkKY29ybiA8LSBuYXNzLmNvcm4Kd2hlYXQgPC0gbmFzcy53aGVhdApiYXJsZXkgPC0gbmFzcy5iYXJsZXkKZ2xpbXBzZShjb3JuKQpgYGAKYGBge3J9CmNvcm4gPC0gY29ybiAlPiUKICAjIEFkZCBzb21lIGNvbHVtbnMKICBtdXRhdGUoCiAgICAjIENvbnZlcnQgZmFybWVkIGFyZWEgZnJvbSBhY3JlcyB0byBoYQogICAgZmFybWVkX2FyZWFfaGEgPSBhY3Jlc190b19oZWN0YXJlcyhhY3JlcyksCiAgICAjIENvbnZlcnQgeWllbGQgZnJvbSBidXNoZWxzL2FjcmUgdG8ga2cvaGEKICAgIHlpZWxkX2tnX3Blcl9oYSA9IGJ1c2hlbHNfcGVyX2FjcmVfdG9fa2dzX3Blcl9oZWN0YXJlKAogICAgICB5aWVsZCwKICAgICAgY3JvcCA9ICJjb3JuIgogICAgKQogICkKCmhlYWQoY29ybikKYGBgCldlIGNhbiB3cmFwIHRoZSBtdXRhdGlvbiBjb2RlIGludG8gYSBmdW5jdGlvbiwgZm9ydGlmeV93aXRoX21ldHJpY191bml0cy4KYGBge3J9CiMgV3JhcCB0aGlzIGNvZGUgaW50byBhIGZ1bmN0aW9uCmZvcnRpZnlfd2l0aF9tZXRyaWNfdW5pdHMgPC0gZnVuY3Rpb24oZGF0YSwgY3JvcCkgewogIGRhdGEgJT4lCiAgICBtdXRhdGUoCiAgICAgIGZhcm1lZF9hcmVhX2hhID0gYWNyZXNfdG9faGVjdGFyZXMoYWNyZXMpLAogICAgICB5aWVsZF9rZ19wZXJfaGEgPSBidXNoZWxzX3Blcl9hY3JlX3RvX2tnc19wZXJfaGVjdGFyZSgKICAgICAgICB5aWVsZCwgCiAgICAgICAgY3JvcCA9IGNyb3AKICAgICAgKQogICAgKQp9CmBgYAoKCmBgYHtyfQojIFRyeSBpdCBvbiB0aGUgd2hlYXQgZGF0YXNldAp3aGVhdCA8LSBmb3J0aWZ5X3dpdGhfbWV0cmljX3VuaXRzKHdoZWF0LCBjcm9wID0gIndoZWF0IikKaGVhZCh3aGVhdCkKYGBgCiMgUGxvdHRpbmcgeWllbGRzIG92ZXIgdGltZQoKTm93IHRoYXQgdGhlIHVuaXRzIGhhdmUgYmVlbiBkZWFsdCB3aXRoLCBpdCdzIHRpbWUgdG8gZXhwbG9yZSB0aGUgZGF0YXNldHMuIEFuIG9idmlvdXMgcXVlc3Rpb24gdG8gYXNrIGFib3V0IGVhY2ggY3JvcCBpcywgImhvdyBkbyB0aGUgeWllbGRzIGNoYW5nZSBvdmVyIHRpbWUgaW4gZWFjaCBVUyBzdGF0ZT8iIExldCdzIGRyYXcgYSBsaW5lIHBsb3QgdG8gZmluZCBvdXQuCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKYGBge3J9CiMgVXNpbmcgY29ybiwgcGxvdCB5aWVsZCAoa2cvaGEpIHZzLiB5ZWFyCmdncGxvdChjb3JuLCBhZXMoeCA9IHllYXIsIHkgPSB5aWVsZF9rZ19wZXJfaGEpKSArCiAgIyBBZGQgYSBsaW5lIGxheWVyLCBncm91cGVkIGJ5IHN0YXRlCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHN0YXRlKSkgKwogICMgQWRkIGEgc21vb3RoIHRyZW5kIGxheWVyCiAgZ2VvbV9zbW9vdGgoKQpgYGAKIyMgQ3JlYXRlIHBsb3R0aW5nIGZ1bmN0aW9uCmBgYHtyfQojIFdyYXAgdGhpcyBwbG90dGluZyBjb2RlIGludG8gYSBmdW5jdGlvbgpwbG90X3lpZWxkX3ZzX3llYXIgPC0gZnVuY3Rpb24oZGF0YSl7CiAgZ2dwbG90KGRhdGEsIGFlcyh5ZWFyLCB5aWVsZF9rZ19wZXJfaGEpKSArCiAgICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gc3RhdGUpKSArCiAgICBnZW9tX3Ntb290aCgpCn0KYGBgCldlIGNhbiBub3cgcGxvdCB3aGVhdApgYGB7cn0KIyBUZXN0IGl0IG9uIHRoZSB3aGVhdCBkYXRhc2V0CnBsb3RfeWllbGRfdnNfeWVhcih3aGVhdCkKYGBgCkxvb2sgYXQgdGhlIGh1Z2UgaW5jcmVhc2UgaW4geWllbGRzIGZyb20gdGhlIHRpbWUgb2YgdGhlIEdyZWVuIFJldm9sdXRpb24gaW4gdGhlIDE5NTBzLgoKIyBBIG5hdGlvbiBkaXZpZGVkCgpUaGUgVVNBIGhhcyBhIHZhcmllZCBjbGltYXRlLCBzbyB3ZSBtaWdodCBleHBlY3QgeWllbGRzIHRvIGRpZmZlciBiZXR3ZWVuIHN0YXRlcy4gUmF0aGVyIHRoYW4gdHJ5aW5nIHRvIHJlYXNvbiBhYm91dCA1MCBzdGF0ZXMgc2VwYXJhdGVseSwgd2UgY2FuIHVzZSB0aGUgVVNBIENlbnN1cyBSZWdpb25zIHRvIGdldCA5IGdyb3Vwcy4KClRoZSAiQ29ybiBCZWx0Iiwgd2hlcmUgbW9zdCBVUyBjb3JuIGlzIGdyb3duIGlzIGluIHRoZSAiV2VzdCBOb3J0aCBDZW50cmFsIiBhbmQgIkVhc3QgTm9ydGggQ2VudHJhbCIgcmVnaW9ucy4gVGhlICJXaGVhdCBCZWx0IiBpcyBpbiB0aGUgIldlc3QgU291dGggQ2VudHJhbCIgcmVnaW9uLgoKTGV0wrRzIGxvYWQgdGhlIFVTQSBjZW5zdXMgcmVnaW9uCmBgYHtyfQp1c2FfY2Vuc3VzX3JlZ2lvbnMgPC0gcmVhZF9jc3YoInVzX2RhdGFfY2Vuc3VzLmNzdiIpCnVzYV9jZW5zdXNfcmVnaW9ucyA8LSB1c2FfY2Vuc3VzX3JlZ2lvbnNbICwgLWMoMiwgMyldCmNvbG5hbWVzKHVzYV9jZW5zdXNfcmVnaW9ucykgPC0gYygic3RhdGUiLCAiY2Vuc3VzX3JlZ2lvbiIpCnVzYV9jZW5zdXNfcmVnaW9ucyA8LSB1c2FfY2Vuc3VzX3JlZ2lvbnNbICwgYygyLCAxKV0KaGVhZCh1c2FfY2Vuc3VzX3JlZ2lvbnMpCmBgYApgYGB7cn0KI2NyZWF0aW5nIGNlbnN1cyByZWdpb25zIHZhcmlhYmxlCmNlbnN1c19yZWdpb25zIDwtIHVuaXF1ZSh1c2FfY2Vuc3VzX3JlZ2lvbnNbLDFdKQojKCJjZW5zdXNfcmVnaW9uIiA9IHJlZ2lvbikKY2Vuc3VzX3JlZ2lvbnMKYGBgCgpgYGB7cn0KIyBJbm5lciBqb2luIHRoZSBjb3JuIGRhdGFzZXQgdG8gdXNhX2NlbnN1c19yZWdpb25zIGJ5IHN0YXRlCmNvcm4gPC0gY29ybiAlPiUKICBpbm5lcl9qb2luKHVzYV9jZW5zdXNfcmVnaW9ucywgYnkgPSAic3RhdGUiKQoKaGVhZChjb3JuKQpgYGAKV2UgY2FuIHR1cm4gdGhlIGNvZGUgaW50byBhIGZ1bmN0aW9uCmBgYHtyfQpmb3J0aWZ5X3dpdGhfY2Vuc3VzX3JlZ2lvbiA8LSBmdW5jdGlvbihkYXRhKXsKICBkYXRhICU+JQogICAgaW5uZXJfam9pbih1c2FfY2Vuc3VzX3JlZ2lvbnMsIGJ5ID0gInN0YXRlIikKfQpgYGAKYGBge3J9CndoZWF0IDwtIGZvcnRpZnlfd2l0aF9jZW5zdXNfcmVnaW9uKHdoZWF0KQpoZWFkKHdoZWF0KQpgYGAKV2l0aCB0aGUgY2Vuc3VzIGRhdGEgaW5jb3Jwb3JhdGVkIGludG8gdGhlIGNyb3AgZGF0YXNldHMsIHdlIGNhbiBub3cgbG9vayBhdCB5aWVsZCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSByZWdpb25zLgoKIyMgUGxvdHRpbmcgeWllbGRzIG92ZXIgdGltZSBieSByZWdpb24KClNvIGZhciwgeW91IGhhdmUgYSBmdW5jdGlvbiB0byBwbG90IHlpZWxkcyBvdmVyIHRpbWUgZm9yIGVhY2ggY3JvcCwgYW5kIHlvdSd2ZSBhZGRlZCBhIGNlbnN1c19yZWdpb24gY29sdW1uIHRvIHRoZSBjcm9wIGRhdGFzZXRzLiBOb3cgd2UgYXJlIHJlYWR5IHRvIGxvb2sgYXQgaG93IHRoZSB5aWVsZHMgY2hhbmdlIG92ZXIgdGltZSBpbiBlYWNoIHJlZ2lvbiBvZiB0aGUgVVNBLgoKYGBge3J9CiMgUGxvdCB5aWVsZCB2cy4geWVhciBmb3IgdGhlIGNvcm4gZGF0YXNldApwbG90X3lpZWxkX3ZzX3llYXIoY29ybikgKwogICMgRmFjZXQsIHdyYXBwZWQgYnkgY2Vuc3VzIHJlZ2lvbgogIGZhY2V0X3dyYXAodmFycyhjZW5zdXNfcmVnaW9uKSkKYGBgCmBgYHtyfQojIFdyYXAgdGhpcyBjb2RlIGludG8gYSBmdW5jdGlvbgpwbG90X3lpZWxkX3ZzX3llYXJfYnlfcmVnaW9uIDwtIGZ1bmN0aW9uKGRhdGEpewogIHBsb3RfeWllbGRfdnNfeWVhcihkYXRhKSArCiAgICBmYWNldF93cmFwKHZhcnMoY2Vuc3VzX3JlZ2lvbikpCn0KCiMgVHJ5IGl0IG9uIHRoZSB3aGVhdCBkYXRhc2V0CnBsb3RfeWllbGRfdnNfeWVhcl9ieV9yZWdpb24od2hlYXQpCmBgYApSYWRpY2FsIHJlZ2lvbmFsIHlpZWxkIGFuYWx5c2lzISBSZWFzc3VyaW5nbHksIHRoZSBjb3JuIHlpZWxkcyBhcmUgaGlnaGVzdCBpbiB0aGUgV2VzdCBOb3J0aCBDZW50cmFsIHJlZ2lvbiwgdGhlIGhlYXJ0IG9mIHRoZSBDb3JuIEJlbHQuIEZvciB3aGVhdCwgaXQgbG9va3MgbGlrZSB0aGUgeWllbGRzIGFyZSBoaWdoZXN0IGluIHRoZSBXaGVhdCBCZWx0IChXZXN0IFNvdXRoIENlbnRyYWwgcmVnaW9uKSBoYXZlIGJlZW4gb3ZlcnRha2VuIGJ5IHNvbWUgb3RoZXIgcmVnaW9ucy4KCiMgUnVubmluZyBhIG1vZGVsCgpUaGUgc21vb3RoIHRyZW5kIGxpbmUgd2Ugc2VlIGluIHRoZSBwbG90cyBvZiB5aWVsZCBvdmVyIHRpbWUgdXNlIGEgZ2VuZXJhbGl6ZWQgYWRkaXRpdmUgbW9kZWwgKEdBTSkgdG8gZGV0ZXJtaW5lIHdoZXJlIHRoZSBsaW5lIHNob3VsZCBsaWUuIFRoaXMgc29ydCBvZiBtb2RlbCBpcyBpZGVhbCBmb3IgZml0dGluZyBub25saW5lYXIgY3VydmVzLiBTbyB3ZSBjYW4gbWFrZSBwcmVkaWN0aW9ucyBhYm91dCBmdXR1cmUgeWllbGRzLCBsZXQncyBleHBsaWNpdGx5IHJ1biB0aGUgbW9kZWwuIFRoZSBzeW50YXggZm9yIHJ1bm5pbmcgdGhpcyBHQU0gdGFrZXMgdGhlIGZvbGxvd2luZyBmb3JtLgoKICAgIGdhbShyZXNwb25zZSB+IHMoZXhwbGFuYXRvcnlfdmFyMSkgKyBleHBsYW5hdG9yeV92YXIyLCBkYXRhID0gZGF0YXNldCkKICAgIApIZXJlLCBzKCkgbWVhbnMgIm1ha2UgdGhlIHZhcmlhYmxlIHNtb290aCIsIHdoZXJlIHNtb290aCB2ZXJ5IHJvdWdobHkgbWVhbnMgbm9ubGluZWFyLgpgYGB7cn0KbGlicmFyeShtZ2N2KQojIFJ1biBhIGdlbmVyYWxpemVkIGFkZGl0aXZlIG1vZGVsIG9mIAojIHlpZWxkIHZzLiBzbW9vdGhlZCB5ZWFyIGFuZCBjZW5zdXMgcmVnaW9uCmdhbSh5aWVsZF9rZ19wZXJfaGEgfiBzKHllYXIpICsgY2Vuc3VzX3JlZ2lvbiwgZGF0YSA9IGNvcm4pCmBgYApXZSBjYW4gd3JhcCB0aGUgY29kZSBpbnRvIGEgZnVuY3Rpb24gYW5kIGFwcGx5IHRvIHdoZWF0IGFzIHdlbGwuCmBgYHtyfQojIFdyYXAgdGhlIG1vZGVsIGNvZGUgaW50byBhIGZ1bmN0aW9uCnJ1bl9nYW1feWllbGRfdnNfeWVhcl9ieV9yZWdpb24gPC0gZnVuY3Rpb24oZGF0YSl7CiAgZ2FtKHlpZWxkX2tnX3Blcl9oYSB+IHMoeWVhcikgKyBjZW5zdXNfcmVnaW9uLCBkYXRhID0gZGF0YSkKfQoKIyBUcnkgaXQgb24gdGhlIHdoZWF0IGRhdGFzZXQKcnVuX2dhbV95aWVsZF92c195ZWFyX2J5X3JlZ2lvbih3aGVhdCkKYGBgCiMjIE1ha2luZyB5aWVsZCBwcmVkaWN0aW9ucwpXZSBjYW4gbWFrZSBwcmVkaWN0aW9ucyB1c2luZyBhIGNhbGwgdG8gcHJlZGljdCgpLCBpbiB0aGUgZm9sbG93aW5nIGZvcm0uCgogICAgcHJlZGljdChtb2RlbCwgY2FzZXNfdG9fcHJlZGljdCwgdHlwZSA9ICJyZXNwb25zZSIpCgpgYGB7cn0KIyB3ZSBjYW4gYXNzaWduIG91ciBtb2RlbCB0byBhIHZhcmlhYmxlCmNvcm5fbW9kZWwgPSBydW5fZ2FtX3lpZWxkX3ZzX3llYXJfYnlfcmVnaW9uKGNvcm4pCndoZWF0X21vZGVsID0gcnVuX2dhbV95aWVsZF92c195ZWFyX2J5X3JlZ2lvbih3aGVhdCkKYGBgCgpgYGB7cn0KIyBNYWtlIHByZWRpY3Rpb25zIGluIDIwNTAgIApwcmVkaWN0X3RoaXMgPC0gZGF0YS5mcmFtZSgKICB5ZWFyID0gMjA1MCwKICBjZW5zdXNfcmVnaW9uID0gY2Vuc3VzX3JlZ2lvbnMKKQpwcmVkaWN0X3RoaXMKYGBgCgoKYGBge3J9CiMgUHJlZGljdCB0aGUgeWllbGQKcHJlZF95aWVsZF9rZ19wZXJfaGEgPC0gcHJlZGljdChjb3JuX21vZGVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWRpY3RfdGhpcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIikKYGBgCmBgYHtyfQpjb3JuX3ByZWRpY3Rpb24gPC0gcHJlZGljdF90aGlzICU+JQogICMgQWRkIHRoZSBwcmVkaWN0aW9uIGFzIGEgY29sdW1uIG9mIHByZWRpY3RfdGhpcyAKICBtdXRhdGUocHJlZF95aWVsZF9rZ19wZXJfaGEgPSBjKHByZWRfeWllbGRfa2dfcGVyX2hhKSkKY29ybl9wcmVkaWN0aW9uCmBgYApXZSBjYW4gd3JhcCB0aGUgc2NyaXB0IGludG8gYSBmdW5jdGlvbgpgYGB7cn0KIyBXcmFwIHRoaXMgcHJlZGljdGlvbiBjb2RlIGludG8gYSBmdW5jdGlvbgpwcmVkaWN0X3lpZWxkcyA8LSBmdW5jdGlvbihtb2RlbCwgeWVhcil7CiAgcHJlZGljdF90aGlzIDwtIGRhdGEuZnJhbWUoCiAgICB5ZWFyID0geWVhciwKICAgIGNlbnN1c19yZWdpb24gPSBjZW5zdXNfcmVnaW9ucwogICkgCiAgcHJlZF95aWVsZF9rZ19wZXJfaGEgPC0gcHJlZGljdChtb2RlbCwgcHJlZGljdF90aGlzLCB0eXBlID0gInJlc3BvbnNlIikKICBwcmVkaWN0X3RoaXMgJT4lCiAgICBtdXRhdGUocHJlZF95aWVsZF9rZ19wZXJfaGEgPSBjKHByZWRfeWllbGRfa2dfcGVyX2hhKSkKfQpgYGAKCgpgYGB7cn0KIyBUcnkgaXQgb24gdGhlIHdoZWF0IGRhdGFzZXQKd2hlYXRfcHJlZGljdGlvbiA8LSBwcmVkaWN0X3lpZWxkcyh3aGVhdF9tb2RlbCwKICAgICAgICAgICAgICAgeWVhciA9IDIwNTApCndoZWF0X3ByZWRpY3Rpb24KYGBgCgpUaGUgbW9kZWxzIHByZWRpY3QgdGhhdCBpbiAyMDUwLCB0aGUgaGlnaGVzdCB5aWVsZHMgd2lsbCBiZSBpbiB0aGUgUGFjaWZpYyByZWdpb24gZm9yIGJvdGggY29ybiBhbmQgd2hlYXQuCgojIyBEbyBpdCBhbGwgb3ZlciBhZ2FpbgoKTm93IHlvdSBhcmUgZ29pbmcgdG8gcmVydW4gdGhlIHdob2xlIGFuYWx5c2lzIGZyb20gdGhpcyBjaGFwdGVyIG9uIGEgbmV3IGNyb3AsIGJhcmxleS4gU2luY2UgYWxsIHRoZSBpbmZyYXN0cnVjdHVyZSBpcyBpbiBwbGFjZSwgdGhhdCdzIGxlc3MgZWZmb3J0IHRoYW4gaXQgc291bmRzIQoKQmFybGV5IHByZWZlcnMgYSBjb29sZXIgY2xpbWF0ZSBjb21wYXJlZCB0byBjb3JuIGFuZCB3aGVhdCBhbmQgaXMgY29tbW9ubHkgZ3Jvd24gaW4gdGhlIFVTIG1vdW50YWluIHN0YXRlcyBvZiBJZGFobyBhbmQgTW9udGFuYS4KYGBge3J9CmZvcnRpZmllZF9iYXJsZXkgPC0gYmFybGV5ICU+JSAKICAjIEZvcnRpZnkgd2l0aCBtZXRyaWMgdW5pdHMKICBmb3J0aWZ5X3dpdGhfbWV0cmljX3VuaXRzKCJiYXJsZXkiKSAlPiUKICAjIEZvcnRpZnkgd2l0aCBjZW5zdXMgcmVnaW9ucwogIGZvcnRpZnlfd2l0aF9jZW5zdXNfcmVnaW9uKCkKCiMgU2VlIHRoZSByZXN1bHQKZ2xpbXBzZShmb3J0aWZpZWRfYmFybGV5KQpgYGAKCmBgYHtyfQojIFBsb3QgeWllbGQgdnMuIHllYXIgYnkgcmVnaW9uCnBsb3RfeWllbGRfdnNfeWVhcl9ieV9yZWdpb24oZm9ydGlmaWVkX2JhcmxleSkKYGBgCmBgYHtyfQpmb3J0aWZpZWRfYmFybGV5ICU+JSAKICAjIFJ1biBhIEdBTSBvZiB5aWVsZCB2cy4geWVhciBieSByZWdpb24KICBydW5fZ2FtX3lpZWxkX3ZzX3llYXJfYnlfcmVnaW9uICAlPiUgCiAgIyBNYWtlIHByZWRpY3Rpb25zIG9mIHlpZWxkcyBpbiAyMDUwCiAgcHJlZGljdF95aWVsZHMoMjA1MCkKYGBgClNpbmNlIGFsbCB5b3VyIGFuYWx5c2lzIGNvZGUgd2FzIGNvbnRhaW5lZCBpbiBmdW5jdGlvbnMsIGl0IHdhcyByZWFsbHkgc2ltcGxlIHRvIGFwcGx5IGl0IHRvIGFub3RoZXIgZGF0YXNldC4gSGVyZSB5b3UgY2FuIHNlZSB0aGF0IHlpZWxkcyBhcmUgaGlnaGVzdCBpbiB0aGUgTW91bnRhaW4gcmVnaW9uLCBhbmQgdGhlIG1vZGVsIHByZWRpY3RzIHRoYXQgdGhpcyB3aWxsIHN0aWxsIGJlIHRoZSBjYXNlIGluIDIwNTAuCgo=