1 Intro

Install Hector, run a simple RCP scenario, query results, and plot.

1.1 Installing Hector

# If the remotes package has not been installed on your machine install it using the 
# install.packages function 
# install.packages("remotes")
# Load the remotes library 
library("remotes")
# Install the R Hector package from github
install_github("JGCRI/hector")

Load the packages we will need for the workshop exercises. If you have not already installed the packages use install.packages("package_name").

library("hector")  # Load the model 
library("ggplot2") # Load functions we will use to plot 

1.2 Run a RCP

Start by taking a look at the input files (ini) that are included in the Hector package.

list.files(system.file("input", package = "hector"))
 [1] "constraints"                    "emissions"                     
 [3] "hector_rcp26_constrained.ini"   "hector_rcp26_histconstrain.ini"
 [5] "hector_rcp26.ini"               "hector_rcp45_constrained.ini"  
 [7] "hector_rcp45.ini"               "hector_rcp60_constrained.ini"  
 [9] "hector_rcp60.ini"               "hector_rcp85_constrained.ini"  
[11] "hector_rcp85.ini"              

There are ini files listed for the four RCP pathways (rcp 26, 45, 60, 85). For each RCP pathway, there are at least two ini files, the ini files that end in _constrained.ini run in concentration driven mode much like the Earth System Models, where the \({CO}_{2}\) concentrations are prescribed or constrained.

Being able to run Hector with emissions or prescribed concentrations is a valuable and is an important feature of SCMs.

Now select a single RCP scenario to run.

ini_file = system.file("input/hector_rcp45.ini", package = "hector")

Set up a Hector core using the ini file.

hcore = newcore(inifile = ini_file, name = "default rcp 45") 

Run Hector using the run function.

run(core = hcore)
Hector core:    default rcp 45
Start date: 1745
End date:   2300
Current date:   2300
Input file: /Users/dorh012/Library/R/3.6/library/hector/input/hector_rcp45.ini

Query the results

dates = 1850:2100
var = GLOBAL_TEMP()
data1 = fetchvars(core = hcore, dates = 1850:2100, vars = var)

And shut down the hector core.

shutdown(hcore)
Hector core (INACTIVE)

Plot results, if you want to learn more about making plots with ggplo2 check out Graphs Cookbook for R.

ggplot(data = data1) + 
  geom_line(aes(year, value, color = scenario)) + 
  labs(title = "Hector Global Mean Temp", 
       y = "deg C")

1.3 Change a Parameter

Run Hector again but let’s change the equilibrium climate sensitivity parameter.

The first step will be to set up a new hector core, give it a new name.

ini_file = system.file("input/hector_rcp45.ini", package = "hector")
hcore = newcore(inifile = ini_file, name = "ECS x 2 rcp 45") 
run(core = hcore)
Hector core:    ECS x 2 rcp 45
Start date: 1745
End date:   2300
Current date:   2300
Input file: /Users/dorh012/Library/R/3.6/library/hector/input/hector_rcp45.ini

Now figure out what the default ECS value was.

default_ECS = fetchvars(core = hcore, dates = NA, vars = ECS())
default_ECS

Increase the default ECS by a factor of 2 and get the information we will need to give the Hector core, the variable/parameter name, the unints, and value.

doubble_ECS = 2 * default_ECS$value
ECS_units = getunits(vars = ECS())

Pass the new ECS value to the Hector core.

setvar(core = hcore, dates = NA, var = ECS(), values = doubble_ECS, unit = ECS_units)

Run hector and get new results.

run(core = hcore)
Hector core:    ECS x 2 rcp 45
Start date: 1745
End date:   2300
Current date:   2300
Input file: /Users/dorh012/Library/R/3.6/library/hector/input/hector_rcp45.ini

Query the results.

data2 = fetchvars(core = hcore, dates = 1850:2100, vars = GLOBAL_TEMP())
data2

Now let’s compare the results of the two different runs.

# Combine the data frames into a single data frame, then plot it. 
single_df <- rbind(data1, data2)
ggplot(data = single_df) + 
  geom_line(aes(year, value, color = scenario)) + 
  labs(title = "Hector Global Mean Temp", 
       y = "deg C")

2 Documentation

Some basic documentation for the hector R package can be accessed with R’s help operator, which you can use on the package or an individual function.

What happens when you run help("hector") or help("newcore") in R?

If this still doesn’t answer your questions or you are looking for examples checkout out Hector’s github page, https://github.com/jgcri/hector, this has a link to the online documenation https://jgcri.github.io/hector/.

Hector’s Github home page with a red arrow pointing to the online documenation link

At the online documentation you will find the Hector manual that has installation instructions, information about the model philosphy and so on. The Vigenettes tab is a list of example problems to follow along. The reference tab has a complete list of the package functions with links to detailed descriptions.

Documenation Homepage: the Manual, Vignettes, and Reference tabs are really useful!

If you have a question, bug, or problem please open a GitHub issue! That is the best way to get in contact with the Hector team.

3 Application

ECS is the long-term temperature change after a doubling of atmospheric CO2 concentrations. For the complex ESM this is an emergent property where as it is a tunable paramters in most SCMs. The IPPC AR5 report says that the range of likely ECS is somewhere between 1.5 to 4.5 C. Let’s use Hector to see what this range of ECS could mean for future temperature in the year 2100. Does the scenario make a difference?

To do this we are going to need the ability to run a Hector core with different paramter values and query results mulitple times. The easiest way to do this is by writting an R function.

# Let's start by defining a function where we can set, run, and get results from a Hector. 
run_with_param <- function(core, value) {
  # Reset the Hector core value. 
  setvar(core = core, dates = NA, var = ECS(), value, unit = getunits(ECS()))
  run(core = core)
  
  # Query results 
  result <- fetchvars(core = core, dates = 1850:2100, vars = c(GLOBAL_TEMP(), OCEAN_SURFACE_TEMP(), NPP()))
  
  # Add a column with the parameter value. 
  result$ECS_value <- as.character(round(x = value, digits = 3))
  
  # Return the data frame.
  return(result)
}

Test out this function.

# Set up a Hetor core 
ini_file = system.file("input/hector_rcp85.ini", package = "hector")
hector_rcp85 = newcore(inifile = ini_file)
# Run Hector with some ECS value. 
data = run_with_param(core = hector_rcp85, value = 4)
data

Now set up a function that lets us run run_with_param several times.

run_with_param_range <- function(core, values){
  # the lapply function is an efficent way to apply a function to a list or vector but this will 
  # returnn a list of data frames.
  list <- lapply(values, run_with_param, core = core) 
  # format the list of data frames into a large data frame.
  out <- do.call("rbind", list) 
  return(out)
}

Now make a list of ECS values to sample.

ECS_values = seq(from = 1.5, to = 4.5, length.out = 10)
ECS_values
 [1] 1.500000 1.833333 2.166667 2.500000 2.833333 3.166667 3.500000 3.833333
 [9] 4.166667 4.500000
# Run Hector RCP 85 
ini_file = system.file("input/hector_rcp85.ini", package = "hector")
hector_rcp85 = newcore(inifile = ini_file, name = "rcp85")
data_rcp85 = run_with_param_range(core = hector_rcp85, values = ECS_values)
shutdown(hector_rcp85)
Hector core (INACTIVE)

Now let’s run another scenario.

# Run Hector RCP 26
ini_file = system.file("input/hector_rcp26.ini", package = "hector")
hector_rcp26 = newcore(inifile = ini_file, name = "rcp26")
data_rcp26 = run_with_param_range(core = hector_rcp26, values = ECS_values)

Finally let’s plot it!

data = rbind(data_rcp85, data_rcp26)
ggplot(data = data) + 
  geom_line(aes(year, value, color = ECS_value, linetype = scenario)) + 
  facet_wrap("variable", scales = "free")

LS0tCnRpdGxlOiAiUiBIZWN0b3IgV29ya3Nob3A6IFVuaXZlcmlzdHkgb2YgSW5kaWFuYSIKZGF0ZTogIjIwMjEtMDMtMDgiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRoZW1lOiBsdW1lbgoKLS0tCgoKIyBJbnRybwoKSW5zdGFsbCBIZWN0b3IsIHJ1biBhIHNpbXBsZSBSQ1Agc2NlbmFyaW8sIHF1ZXJ5IHJlc3VsdHMsIGFuZCBwbG90LiAKCiMjIEluc3RhbGxpbmcgSGVjdG9yIAoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQojIElmIHRoZSByZW1vdGVzIHBhY2thZ2UgaGFzIG5vdCBiZWVuIGluc3RhbGxlZCBvbiB5b3VyIG1hY2hpbmUgaW5zdGFsbCBpdCB1c2luZyB0aGUgCiMgaW5zdGFsbC5wYWNrYWdlcyBmdW5jdGlvbiAKIyBpbnN0YWxsLnBhY2thZ2VzKCJyZW1vdGVzIikKCiMgTG9hZCB0aGUgcmVtb3RlcyBsaWJyYXJ5IApsaWJyYXJ5KCJyZW1vdGVzIikKCiMgSW5zdGFsbCB0aGUgUiBIZWN0b3IgcGFja2FnZSBmcm9tIGdpdGh1YgppbnN0YWxsX2dpdGh1YigiSkdDUkkvaGVjdG9yIikKYGBgCgoKTG9hZCB0aGUgcGFja2FnZXMgd2Ugd2lsbCBuZWVkIGZvciB0aGUgd29ya3Nob3AgZXhlcmNpc2VzLiBJZiB5b3UgaGF2ZSBub3QgYWxyZWFkeSBpbnN0YWxsZWQgdGhlIHBhY2thZ2VzIHVzZSBgaW5zdGFsbC5wYWNrYWdlcygicGFja2FnZV9uYW1lIilgLiAgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KCJoZWN0b3IiKSAgIyBMb2FkIHRoZSBtb2RlbCAKbGlicmFyeSgiZ2dwbG90MiIpICMgTG9hZCBmdW5jdGlvbnMgd2Ugd2lsbCB1c2UgdG8gcGxvdCAKYGBgCgoKIyMgUnVuIGEgUkNQIAoKU3RhcnQgYnkgdGFraW5nIGEgbG9vayBhdCB0aGUgaW5wdXQgZmlsZXMgKGluaSkgdGhhdCBhcmUgaW5jbHVkZWQgaW4gdGhlIEhlY3RvciBwYWNrYWdlLiAgCgpgYGB7cn0KbGlzdC5maWxlcyhzeXN0ZW0uZmlsZSgiaW5wdXQiLCBwYWNrYWdlID0gImhlY3RvciIpKQpgYGAKCgpUaGVyZSBhcmUgaW5pIGZpbGVzIGxpc3RlZCBmb3IgdGhlIGZvdXIgW1JDUCBwYXRod2F5c10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVwcmVzZW50YXRpdmVfQ29uY2VudHJhdGlvbl9QYXRod2F5aHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVwcmVzZW50YXRpdmVfQ29uY2VudHJhdGlvbl9QYXRod2F5dikgKHJjcCAyNiwgNDUsIDYwLCA4NSkuIEZvciBlYWNoIFJDUCBwYXRod2F5LCB0aGVyZSBhcmUgYXQgbGVhc3QgdHdvIGluaSBmaWxlcywgdGhlIGluaSBmaWxlcyB0aGF0IGVuZCBpbiBgX2NvbnN0cmFpbmVkLmluaWAgcnVuIGluIGNvbmNlbnRyYXRpb24gZHJpdmVuIG1vZGUgbXVjaCBsaWtlIHRoZSBFYXJ0aCBTeXN0ZW0gTW9kZWxzLCB3aGVyZSB0aGUgJHtDT31fezJ9JCBjb25jZW50cmF0aW9ucyBhcmUgcHJlc2NyaWJlZCBvciBjb25zdHJhaW5lZC4gIAoKQmVpbmcgYWJsZSB0byBydW4gSGVjdG9yIHdpdGggZW1pc3Npb25zIG9yIHByZXNjcmliZWQgY29uY2VudHJhdGlvbnMgaXMgYSB2YWx1YWJsZSBhbmQgaXMgYW4gaW1wb3J0YW50IGZlYXR1cmUgb2YgU0NNcy4gCgoKTm93IHNlbGVjdCBhIHNpbmdsZSBSQ1Agc2NlbmFyaW8gdG8gcnVuLiAKYGBge3J9CmluaV9maWxlID0gc3lzdGVtLmZpbGUoImlucHV0L2hlY3Rvcl9yY3A0NS5pbmkiLCBwYWNrYWdlID0gImhlY3RvciIpCmBgYAoKClNldCB1cCBhIEhlY3RvciBjb3JlIHVzaW5nIHRoZSBpbmkgZmlsZS4gCmBgYHtyfQpoY29yZSA9IG5ld2NvcmUoaW5pZmlsZSA9IGluaV9maWxlLCBuYW1lID0gImRlZmF1bHQgcmNwIDQ1IikgCmBgYAoKUnVuIEhlY3RvciB1c2luZyB0aGUgYHJ1biBmdW5jdGlvbmAuCmBgYHtyfQpydW4oY29yZSA9IGhjb3JlKQpgYGAKClF1ZXJ5IHRoZSByZXN1bHRzCgpgYGB7cn0KZGF0ZXMgPSAxODUwOjIxMDAKdmFyID0gR0xPQkFMX1RFTVAoKQpkYXRhMSA9IGZldGNodmFycyhjb3JlID0gaGNvcmUsIGRhdGVzID0gMTg1MDoyMTAwLCB2YXJzID0gdmFyKQpgYGAKCkFuZCBzaHV0IGRvd24gdGhlIGhlY3RvciBjb3JlLiAKCmBgYHtyfQpzaHV0ZG93bihoY29yZSkKYGBgCgoKUGxvdCByZXN1bHRzLCBpZiB5b3Ugd2FudCB0byBsZWFybiBtb3JlIGFib3V0IG1ha2luZyBwbG90cyB3aXRoIGdncGxvMiBjaGVjayBvdXQgW0dyYXBocyBDb29rYm9vayBmb3IgUl0oaHR0cDovL3d3dy5jb29rYm9vay1yLmNvbS9HcmFwaHMvKS4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRhdGExKSArIAogIGdlb21fbGluZShhZXMoeWVhciwgdmFsdWUsIGNvbG9yID0gc2NlbmFyaW8pKSArIAogIGxhYnModGl0bGUgPSAiSGVjdG9yIEdsb2JhbCBNZWFuIFRlbXAiLCAKICAgICAgIHkgPSAiZGVnIEMiKQpgYGAKCgoKCgoKIyMgQ2hhbmdlIGEgUGFyYW1ldGVyCgpSdW4gSGVjdG9yIGFnYWluIGJ1dCBsZXQncyBjaGFuZ2UgdGhlIGVxdWlsaWJyaXVtIGNsaW1hdGUgc2Vuc2l0aXZpdHkgcGFyYW1ldGVyLiAKClRoZSBmaXJzdCBzdGVwIHdpbGwgYmUgdG8gc2V0IHVwIGEgbmV3IGhlY3RvciBjb3JlLCBnaXZlIGl0IGEgbmV3IG5hbWUuIAoKYGBge3J9CmluaV9maWxlID0gc3lzdGVtLmZpbGUoImlucHV0L2hlY3Rvcl9yY3A0NS5pbmkiLCBwYWNrYWdlID0gImhlY3RvciIpCmhjb3JlID0gbmV3Y29yZShpbmlmaWxlID0gaW5pX2ZpbGUsIG5hbWUgPSAiRUNTIHggMiByY3AgNDUiKSAKcnVuKGNvcmUgPSBoY29yZSkKYGBgCgpOb3cgZmlndXJlIG91dCB3aGF0IHRoZSBkZWZhdWx0IEVDUyB2YWx1ZSB3YXMuCgpgYGB7cn0KZGVmYXVsdF9FQ1MgPSBmZXRjaHZhcnMoY29yZSA9IGhjb3JlLCBkYXRlcyA9IE5BLCB2YXJzID0gRUNTKCkpCmRlZmF1bHRfRUNTCmBgYAoKSW5jcmVhc2UgdGhlIGRlZmF1bHQgRUNTIGJ5IGEgZmFjdG9yIG9mIDIgYW5kIGdldCB0aGUgaW5mb3JtYXRpb24gd2Ugd2lsbCBuZWVkIHRvIGdpdmUgdGhlIEhlY3RvciBjb3JlLCB0aGUgdmFyaWFibGUvcGFyYW1ldGVyIG5hbWUsIHRoZSB1bmludHMsIGFuZCB2YWx1ZS4gCgpgYGB7cn0KZG91YmJsZV9FQ1MgPSAyICogZGVmYXVsdF9FQ1MkdmFsdWUKRUNTX3VuaXRzID0gZ2V0dW5pdHModmFycyA9IEVDUygpKQpgYGAKClBhc3MgdGhlIG5ldyBFQ1MgdmFsdWUgdG8gdGhlIEhlY3RvciBjb3JlLiAKCmBgYHtyfQpzZXR2YXIoY29yZSA9IGhjb3JlLCBkYXRlcyA9IE5BLCB2YXIgPSBFQ1MoKSwgdmFsdWVzID0gZG91YmJsZV9FQ1MsIHVuaXQgPSBFQ1NfdW5pdHMpCmBgYAoKUnVuIGhlY3RvciBhbmQgZ2V0IG5ldyByZXN1bHRzLiAKCmBgYHtyfQpydW4oY29yZSA9IGhjb3JlKQpgYGAKClF1ZXJ5IHRoZSByZXN1bHRzLiAgCgpgYGB7cn0KZGF0YTIgPSBmZXRjaHZhcnMoY29yZSA9IGhjb3JlLCBkYXRlcyA9IDE4NTA6MjEwMCwgdmFycyA9IEdMT0JBTF9URU1QKCkpCmRhdGEyCmBgYAoKTm93IGxldCdzIGNvbXBhcmUgdGhlIHJlc3VsdHMgb2YgdGhlIHR3byBkaWZmZXJlbnQgcnVucy4gCgpgYGB7cn0KIyBDb21iaW5lIHRoZSBkYXRhIGZyYW1lcyBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUsIHRoZW4gcGxvdCBpdC4gCnNpbmdsZV9kZiA8LSByYmluZChkYXRhMSwgZGF0YTIpCgpnZ3Bsb3QoZGF0YSA9IHNpbmdsZV9kZikgKyAKICBnZW9tX2xpbmUoYWVzKHllYXIsIHZhbHVlLCBjb2xvciA9IHNjZW5hcmlvKSkgKyAKICBsYWJzKHRpdGxlID0gIkhlY3RvciBHbG9iYWwgTWVhbiBUZW1wIiwgCiAgICAgICB5ID0gImRlZyBDIikKYGBgCgoKIyBEb2N1bWVudGF0aW9uIAoKClNvbWUgYmFzaWMgZG9jdW1lbnRhdGlvbiBmb3IgdGhlIGBoZWN0b3JgIFIgcGFja2FnZSBjYW4gYmUgYWNjZXNzZWQgd2l0aCBSJ3MgYGhlbHBgIG9wZXJhdG9yLCB3aGljaCB5b3UgY2FuIHVzZSBvbiB0aGUgcGFja2FnZSBvciBhbiBpbmRpdmlkdWFsIGZ1bmN0aW9uLiAKCldoYXQgaGFwcGVucyB3aGVuIHlvdSBydW4gYGhlbHAoImhlY3RvciIpYCBvciBgaGVscCgibmV3Y29yZSIpYCBpbiBSPyAKCgpJZiB0aGlzIHN0aWxsIGRvZXNuJ3QgYW5zd2VyIHlvdXIgcXVlc3Rpb25zIG9yIHlvdSBhcmUgbG9va2luZyBmb3IgZXhhbXBsZXMgY2hlY2tvdXQgb3V0IEhlY3RvcidzIGdpdGh1YiBwYWdlLCAgW2h0dHBzOi8vZ2l0aHViLmNvbS9qZ2NyaS9oZWN0b3JdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZ2NyaS9oZWN0b3IpLCB0aGlzIGhhcyBhIGxpbmsgdG8gdGhlIG9ubGluZSBkb2N1bWVuYXRpb24gW2h0dHBzOi8vamdjcmkuZ2l0aHViLmlvL2hlY3Rvci9dKGh0dHBzOi8vamdjcmkuZ2l0aHViLmlvL2hlY3Rvci8pLiAKCgohW0hlY3RvcidzIEdpdGh1YiBob21lIHBhZ2Ugd2l0aCBhIHJlZCBhcnJvdyBwb2ludGluZyB0byB0aGUgb25saW5lIGRvY3VtZW5hdGlvbiBsaW5rXSgyMDIxMDMwOF9JbmRpYW5hL2ltZy9naXRodWJfdG9fcGtnZG93bi5wbmcpCgoKCgpBdCB0aGUgW29ubGluZSBkb2N1bWVudGF0aW9uXShodHRwczovL2pnY3JpLmdpdGh1Yi5pby9oZWN0b3IvaW5kZXguaHRtbCkgeW91IHdpbGwgZmluZCB0aGUgW0hlY3RvciBtYW51YWxdKGh0dHBzOi8vamdjcmkuZ2l0aHViLmlvL2hlY3Rvci9hcnRpY2xlcy9tYW51YWwvaW5kZXguaHRtbCkgdGhhdCBoYXMgaW5zdGFsbGF0aW9uIGluc3RydWN0aW9ucywgaW5mb3JtYXRpb24gYWJvdXQgdGhlIG1vZGVsIHBoaWxvc3BoeSBhbmQgc28gb24uIFRoZSBWaWdlbmV0dGVzIHRhYiBpcyBhIGxpc3Qgb2YgZXhhbXBsZSBwcm9ibGVtcyB0byBmb2xsb3cgYWxvbmcuIFRoZSByZWZlcmVuY2UgdGFiIGhhcyBhIGNvbXBsZXRlIGxpc3Qgb2YgdGhlIHBhY2thZ2UgZnVuY3Rpb25zIHdpdGggbGlua3MgdG8gZGV0YWlsZWQgZGVzY3JpcHRpb25zLiAKCgohW0RvY3VtZW5hdGlvbiBIb21lcGFnZTogdGhlIE1hbnVhbCwgVmlnbmV0dGVzLCBhbmQgUmVmZXJlbmNlIHRhYnMgYXJlIHJlYWxseSB1c2VmdWwhXSgyMDIxMDMwOF9JbmRpYW5hL2ltZy9wa2dkb3duX2hvbWUucG5nKQoKSWYgeW91IGhhdmUgYSBxdWVzdGlvbiwgYnVnLCBvciBwcm9ibGVtIHBsZWFzZSBvcGVuIGEgR2l0SHViIGlzc3VlISBUaGF0IGlzIHRoZSBiZXN0IHdheSB0byBnZXQgaW4gY29udGFjdCB3aXRoIHRoZSBIZWN0b3IgdGVhbS4gCgojIEFwcGxpY2F0aW9uIAoKRUNTIGlzIHRoZSBsb25nLXRlcm0gdGVtcGVyYXR1cmUgY2hhbmdlIGFmdGVyIGEgZG91Ymxpbmcgb2YgYXRtb3NwaGVyaWMgQ08yIGNvbmNlbnRyYXRpb25zLiBGb3IgdGhlIGNvbXBsZXggRVNNIHRoaXMgaXMgYW4gZW1lcmdlbnQgcHJvcGVydHkgd2hlcmUgYXMgaXQgaXMgYSB0dW5hYmxlIHBhcmFtdGVycyBpbiBtb3N0IFNDTXMuIFRoZSBJUFBDIEFSNSByZXBvcnQgc2F5cyB0aGF0IHRoZSByYW5nZSBvZiBsaWtlbHkgRUNTIGlzIHNvbWV3aGVyZSBiZXR3ZWVuIDEuNSB0byA0LjUgQy4gTGV0J3MgdXNlIEhlY3RvciB0byBzZWUgd2hhdCB0aGlzIHJhbmdlIG9mIEVDUyBjb3VsZCBtZWFuIGZvciBmdXR1cmUgdGVtcGVyYXR1cmUgaW4gdGhlIHllYXIgMjEwMC4gRG9lcyB0aGUgc2NlbmFyaW8gbWFrZSBhIGRpZmZlcmVuY2U/IAoKVG8gZG8gdGhpcyB3ZSBhcmUgZ29pbmcgdG8gbmVlZCB0aGUgYWJpbGl0eSB0byBydW4gYSBIZWN0b3IgY29yZSB3aXRoIGRpZmZlcmVudCBwYXJhbXRlciB2YWx1ZXMgYW5kIHF1ZXJ5IHJlc3VsdHMgbXVsaXRwbGUgdGltZXMuIFRoZSBlYXNpZXN0IHdheSB0byAgZG8gdGhpcyBpcyBieSB3cml0dGluZyBhbiBbUiBmdW5jdGlvbl0oaHR0cHM6Ly9uaWNlcmNvZGUuZ2l0aHViLmlvL2d1aWRlcy9mdW5jdGlvbnMvKS4gCgoKYGBge3J9CiMgTGV0J3Mgc3RhcnQgYnkgZGVmaW5pbmcgYSBmdW5jdGlvbiB3aGVyZSB3ZSBjYW4gc2V0LCBydW4sIGFuZCBnZXQgcmVzdWx0cyBmcm9tIGEgSGVjdG9yLiAKcnVuX3dpdGhfcGFyYW0gPC0gZnVuY3Rpb24oY29yZSwgdmFsdWUpIHsKCiAgIyBSZXNldCB0aGUgSGVjdG9yIGNvcmUgdmFsdWUuIAogIHNldHZhcihjb3JlID0gY29yZSwgZGF0ZXMgPSBOQSwgdmFyID0gRUNTKCksIHZhbHVlLCB1bml0ID0gZ2V0dW5pdHMoRUNTKCkpKQogIHJ1bihjb3JlID0gY29yZSkKICAKICAjIFF1ZXJ5IHJlc3VsdHMgCiAgcmVzdWx0IDwtIGZldGNodmFycyhjb3JlID0gY29yZSwgZGF0ZXMgPSAxODUwOjIxMDAsIHZhcnMgPSBjKEdMT0JBTF9URU1QKCksIE9DRUFOX1NVUkZBQ0VfVEVNUCgpLCBOUFAoKSkpCiAgCiAgIyBBZGQgYSBjb2x1bW4gd2l0aCB0aGUgcGFyYW1ldGVyIHZhbHVlLiAKICByZXN1bHQkRUNTX3ZhbHVlIDwtIGFzLmNoYXJhY3Rlcihyb3VuZCh4ID0gdmFsdWUsIGRpZ2l0cyA9IDMpKQogIAogICMgUmV0dXJuIHRoZSBkYXRhIGZyYW1lLgogIHJldHVybihyZXN1bHQpCgp9CmBgYAoKClRlc3Qgb3V0IHRoaXMgZnVuY3Rpb24uIAoKYGBge3J9CiMgU2V0IHVwIGEgSGV0b3IgY29yZSAKaW5pX2ZpbGUgPSBzeXN0ZW0uZmlsZSgiaW5wdXQvaGVjdG9yX3JjcDg1LmluaSIsIHBhY2thZ2UgPSAiaGVjdG9yIikKaGVjdG9yX3JjcDg1ID0gbmV3Y29yZShpbmlmaWxlID0gaW5pX2ZpbGUpCgojIFJ1biBIZWN0b3Igd2l0aCBzb21lIEVDUyB2YWx1ZS4gCmRhdGEgPSBydW5fd2l0aF9wYXJhbShjb3JlID0gaGVjdG9yX3JjcDg1LCB2YWx1ZSA9IDQpCmRhdGEKYGBgCgoKTm93IHNldCB1cCBhIGZ1bmN0aW9uIHRoYXQgbGV0cyB1cyBydW4gYHJ1bl93aXRoX3BhcmFtYCBzZXZlcmFsIHRpbWVzLiAKYGBge3J9CnJ1bl93aXRoX3BhcmFtX3JhbmdlIDwtIGZ1bmN0aW9uKGNvcmUsIHZhbHVlcyl7CiAgIyB0aGUgbGFwcGx5IGZ1bmN0aW9uIGlzIGFuIGVmZmljZW50IHdheSB0byBhcHBseSBhIGZ1bmN0aW9uIHRvIGEgbGlzdCBvciB2ZWN0b3IgYnV0IHRoaXMgd2lsbCAKICAjIHJldHVybm4gYSBsaXN0IG9mIGRhdGEgZnJhbWVzLgogIGxpc3QgPC0gbGFwcGx5KHZhbHVlcywgcnVuX3dpdGhfcGFyYW0sIGNvcmUgPSBjb3JlKSAKICAjIGZvcm1hdCB0aGUgbGlzdCBvZiBkYXRhIGZyYW1lcyBpbnRvIGEgbGFyZ2UgZGF0YSBmcmFtZS4KICBvdXQgPC0gZG8uY2FsbCgicmJpbmQiLCBsaXN0KSAKICByZXR1cm4ob3V0KQp9CmBgYAoKCk5vdyBtYWtlIGEgbGlzdCBvZiBFQ1MgdmFsdWVzIHRvIHNhbXBsZS4gCgpgYGB7cn0KRUNTX3ZhbHVlcyA9IHNlcShmcm9tID0gMS41LCB0byA9IDQuNSwgbGVuZ3RoLm91dCA9IDEwKQpFQ1NfdmFsdWVzCmBgYAoKCmBgYHtyfQojIFJ1biBIZWN0b3IgUkNQIDg1IAppbmlfZmlsZSA9IHN5c3RlbS5maWxlKCJpbnB1dC9oZWN0b3JfcmNwODUuaW5pIiwgcGFja2FnZSA9ICJoZWN0b3IiKQpoZWN0b3JfcmNwODUgPSBuZXdjb3JlKGluaWZpbGUgPSBpbmlfZmlsZSwgbmFtZSA9ICJyY3A4NSIpCmRhdGFfcmNwODUgPSBydW5fd2l0aF9wYXJhbV9yYW5nZShjb3JlID0gaGVjdG9yX3JjcDg1LCB2YWx1ZXMgPSBFQ1NfdmFsdWVzKQpzaHV0ZG93bihoZWN0b3JfcmNwODUpCmBgYAoKTm93IGxldCdzIHJ1biBhbm90aGVyIHNjZW5hcmlvLiAKCmBgYHtyfQojIFJ1biBIZWN0b3IgUkNQIDI2CmluaV9maWxlID0gc3lzdGVtLmZpbGUoImlucHV0L2hlY3Rvcl9yY3AyNi5pbmkiLCBwYWNrYWdlID0gImhlY3RvciIpCmhlY3Rvcl9yY3AyNiA9IG5ld2NvcmUoaW5pZmlsZSA9IGluaV9maWxlLCBuYW1lID0gInJjcDI2IikKZGF0YV9yY3AyNiA9IHJ1bl93aXRoX3BhcmFtX3JhbmdlKGNvcmUgPSBoZWN0b3JfcmNwMjYsIHZhbHVlcyA9IEVDU192YWx1ZXMpCnNodXRkb3duKGhlY3Rvcl9yY3AyNikKYGBgCgoKRmluYWxseSBsZXQncyBwbG90IGl0ISAKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTV9CmRhdGEgPSByYmluZChkYXRhX3JjcDg1LCBkYXRhX3JjcDI2KQoKZ2dwbG90KGRhdGEgPSBkYXRhKSArIAogIGdlb21fbGluZShhZXMoeWVhciwgdmFsdWUsIGNvbG9yID0gRUNTX3ZhbHVlLCBsaW5ldHlwZSA9IHNjZW5hcmlvKSkgKyAKICBmYWNldF93cmFwKCJ2YXJpYWJsZSIsIHNjYWxlcyA9ICJmcmVlIikKCmBgYAoKCgoKCgoKCgoK