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  <int> 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866, 18…
$ state <fct> Alabama, Arkansas, California, Connecticut, Delaware, Fl…
$ acres <dbl> 1050000, 280000, 42000, 57000, 200000, 125000, 1770000, …
$ yield <dbl> 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 = col_character(),
  `State Code` = col_character(),
  Region = col_character(),
  Division = col_character()
)
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            <int> 1866, 1866, 1866, 1866, 1866, 1866, 1866, 1866…
$ state           <chr> "Connecticut", "Illinois", "Indiana", "Iowa", …
$ acres           <dbl> 1000, 96000, 11000, 66000, 2000, 10000, 34000,…
$ yield           <dbl> 22.5, 23.4, 23.0, 22.0, 23.0, 23.5, 21.5, 25.5…
$ farmed_area_ha  <dbl> 404.6856, 38849.8217, 4451.5421, 26709.2524, 8…
$ yield_kg_per_ha <dbl> 1210.5192, 1258.9400, 1237.4197, 1183.6188, 12…
$ census_region   <chr> "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=