Introduction

This file contains code and inputs for projections of temperature related moratlity based on historical data for 209 cities. The original modeling was performed by Joel Schwartz and Alina Vodonos Zilberg using data obtained directly from counties, and historical temperatures calculated by Abt.

Load in R packages

lpath <- "/home/ad.abt.local/layc/R/library" # assign library for user w/o admin priveleges on ACE3
.libPaths(lpath)

#library(chron)
library(tictoc) # for system time
library(readxl) # for reading in excel
library(readr)  # for csv
library(survival) # from original vodonos code. Loaded for compatibility
library(splines) # for splines
library(MASS)  # for mvmeta, likely
#library(nlme) 
library(mgcv) # from original vodonos code. Loaded for compatibility
Loading required package: nlme
This is mgcv 1.8-25. For overview type 'help("mgcv-package")'.
library(dlnm) # from original vodonos code. Loaded for compatibility
This is dlnm 2.3.6. For details: help(dlnm) and vignette('dlnmOverview').
library(tsModel) # from original vodonos code. Loaded for compatibility
Time Series Modeling for Air Pollution and Health (0.6)
library(mvmeta) # from original vodonos code. Loaded for compatibility
This is mvmeta 0.4.11. For an overview type: help('mvmeta-package').
library(here) # convenience for filepaths dynamic
here() starts at /media/projects/Projects/Climecon_EPA/cira3-mortality
here <- here::here # to avoid overwrite
library(data.table) # fread for faster read (read.table takes >15 min)
data.table 1.11.8  Latest news: r-datatable.com
library(tidyverse)
── Attaching packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.1.0     ✔ purrr   0.2.5
✔ tibble  2.1.3     ✔ dplyr   0.8.3
✔ tidyr   0.8.2     ✔ stringr 1.3.1
✔ ggplot2 3.1.0     ✔ forcats 0.3.0
── Conflicts ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::between()   masks data.table::between()
✖ dplyr::collapse()  masks nlme::collapse()
✖ dplyr::filter()    masks stats::filter()
✖ dplyr::first()     masks data.table::first()
✖ dplyr::lag()       masks stats::lag()
✖ dplyr::last()      masks data.table::last()
✖ dplyr::select()    masks MASS::select()
✖ purrr::transpose() masks data.table::transpose()
select <- dplyr::select # to re-assign select to specify dplyr as is more commonly used than raster and MASS functions in script below.
#library(RcppRoll) # rolling averages from vodonos? Likey not needed
library(purrr) # for iterative processing.
library(gridExtra) # for grid.arrange

Attaching package: ‘gridExtra’

The following object is masked from ‘package:dplyr’:

    combine

Source files and locations

In data folder

Identify degrees change by GCM and year (for RCP8.5): data/GCM_Period_dT_LUT.xlsx Identify cluster and county identy for each city: data/city_county_LUT.xlsx

Climate projections in: //boufile01.corp.abtassoc.com/data1/Common/ENR/Project/Climecon4/COOLIT13_RiskComm/Mortality/Output/Trim/ and Data/Trim Day of week deaths averaged over the last period (2003-2013) for cities: output/vodonos_out/historical.deaths/mean.deaths.dow.csv Day of year deaths averaged over the last period (2003-2013) for cities: output/vodonos_out/historical.deaths/mean.deaths.doy.csv Contains graphical results output and a matrix to link FIPS assigned by Schwartz lab to city: output/vodonos_out/Results-5-28-19.xlsx

Load degrees change lookup table

Use 5 years on each side of model period year to start (11 years in total for each gcm). Use RCP 85 only. Create 2 rows if the period spans 2050 and 2090 GCM periods, as these will need to have two separate Tmax projection files read in.

gcm_dt_lut <- read_xlsx(here("data/GCM_Period_dT_LUT.xlsx"), sheet = "GCM_Period_dT_LUT") 
gcm_dt_lut <- gcm_dt_lut %>% 
  rename (dt_year = model.period) %>% 
  mutate(min_dt_yr = dt_year - 5,
         max_dt_yr = dt_year + 5,
         )  

Load county and mortality lookup data.

options("object.size" = 2000000000000) # for bigger data limit
# nca_county_LUT <- fread(here("data/cira3/nca_county_LUT.csv"))
# nca_county_LUT <- nca_county_LUT %>% mutate(`FIPS_text` = FIPS)

mort_city_county_LUT <- read_xlsx(here("data/city_county_LUT.xlsx"))

head(mort_city_county_LUT)

mort_city_county_LUT <- mort_city_county_LUT %>% mutate(`FIPS_text` = paste("'", `FIPS-text`, "'", sep = ""))

cluster_LUT <-  mort_city_county_LUT%>%
  mutate (CITYNAME = casefold(CITYNAME)) %>% 
  select (Cluster,  City, CITYNAME, STATENAM , FIPS_txt = `FIPS-text`) #VALUE, COUNT, FIPS_txt = `FIPS-text`, fips_sm, FIPS,

Use the city-county-LUT to get the correct city/county values for the climate files Ron made in 2016. Those files are present on the J drive on ACE3, but require additional documentation for use. They need a description of the code used to produce them and the aggregation method. The climate model output aggregated for degrees celsius above baseline is available here on ACE3.

Load the mortality averages from the original city data (Schwartaz/vodonos)

For first projections, use observed deaths from death certificate (sum of counties included in Schwartz city boundary). These are directly tied to total populations of the counties included. Use the sum of populations from counties included in Schwartz city delimitation as basis for RR to actual deaths conversion. Later, apply the base RR and attributable RR to the overall population for cost calculations.

dow <- read_csv(here::here("output/vodonos_out/historical.deaths/mean.deaths.dow.csv")) # Day of week mortality average for last period
Parsed with column specification:
cols(
  dow = col_integer(),
  dow.names = col_character(),
  CITYNAME = col_character(),
  tot.mean = col_double()
)
glimpse (dow)
Observations: 1,456
Variables: 4
$ dow       <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ dow.names <chr> "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday", "Sunday…
$ CITYNAME  <chr> "akron", "albany", "albuquerque", "allentown", "anaheim", "annandale", "annarbor", "atlanta", "atlantic city", "atzec", "augusta", "austin", "bakersfield", "baltimore", "bangor", "barnstable", "bat…
$ tot.mean  <dbl> 13.7, 6.7, 11.0, 12.4, 42.7, 10.6, 4.9, 42.9, 6.1, 1.9, 4.6, 11.0, 12.7, 35.6, 3.5, 6.9, 2.3, 9.2, 26.9, 23.7, 5.6, 53.5, 3.5, 5.4, 24.7, 2.3, 9.9, 5.4, 4.0, 6.8, 6.0, 12.3, 7.9, 128.3, 20.2, 48.7,…
doy <- read_csv(here::here("output/vodonos_out/historical.deaths/mean.deaths.doy.csv")) # Day of year mortality average for last period
Parsed with column specification:
cols(
  doy = col_integer(),
  CITYNAME = col_character(),
  tot.mean = col_double()
)
glimpse (doy)
Observations: 76,128
Variables: 3
$ doy      <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
$ CITYNAME <chr> "akron", "albany", "albuquerque", "allentown", "anaheim", "annandale", "annarbor", "atlanta", "atlantic city", "atzec", "augusta", "austin", "bakersfield", "baltimore", "bangor", "barnstable", "bath…
$ tot.mean <dbl> 15.0, 6.7, 12.6, 13.8, 48.5, 12.6, 5.1, 52.2, 6.4, 2.1, 5.6, 12.3, 13.0, 45.9, 3.6, 6.2, 3.2, 10.0, 33.1, 24.5, 4.7, 63.6, 3.3, 7.1, 28.4, 2.8, 14.0, 6.4, 5.5, 5.5, 5.2, 14.3, 8.5, 147.2, 27.2, 51.5…
#County mean tmax (weighted by number of grid points included in each county) was used for temperature relationship. Do the same going forward
tmax_fips <- read_xlsx(here::here("output/vodonos_out/Results-5-28-19.xlsx"), "data.matrix")
tmax_fips <- tmax_fips %>%  
  select(CITYNAME, citycode) %>% 
  mutate (FIPS_txt = stringr::str_pad(as.character (citycode), 5, "left", "0"),
          # Due to county selection within cities, some towns have no value in the original city-cluster-LUT table.
          # This is only a problem for Youngstown, OH, which has no matching fips code. Due to an error in the data.matrix lut from Schwartz
          FIPS_txt = gsub("39029", "39099", FIPS_txt)) # replace Schwartz data matrix for youngstown with a youngstown FIPS

tmax_fips   %>%   anti_join(cluster_LUT , by = "FIPS_txt")

doy<- doy %>% left_join(tmax_fips) %>% 
  mutate(month = lubridate::month (as.Date(doy , origin = "2015-12-31")) ,
         day =  lubridate::day (as.Date(doy , origin = "2015-12-31"))  ) %>%
  left_join(cluster_LUT[, c("Cluster", "FIPS_txt")], by = "FIPS_txt") %>%
  select (cluster = Cluster, FIPS_txt, CITYNAME, doy, month, day, total_mort = tot.mean) 
Joining, by = "CITYNAME"
doy %>% glimpse()
Observations: 76,128
Variables: 7
$ cluster    <dbl> 2, 2, 9, 1, 5, 1, 2, 4, 1, 9, 4, 6, 8, 1, 2, 1, 2, 6, 1, 4, 9, 1, 2, 7, 2, 2, 2, 1, 2, 4, 3, 4, 4, 2, 3, 3, 2, 4, 3, 7, 4, 2, 9, 3, 7, 2, 2, 2, 2, 1, 4, 8, 1, 2, 8, 2, 1, 5, 3, 5, 2, 4, 2, 8, 2, 7…
$ FIPS_txt   <chr> "39153", "36001", "35001", "42077", "06059", "51059", "26161", "13067", "34001", "35045", "13245", "48453", "06029", "24510", "23019", "25001", "36101", "22033", "34003", "01073", "16001", "25025"…
$ CITYNAME   <chr> "akron", "albany", "albuquerque", "allentown", "anaheim", "annandale", "annarbor", "atlanta", "atlantic city", "atzec", "augusta", "austin", "bakersfield", "baltimore", "bangor", "barnstable", "ba…
$ doy        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ month      <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ day        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ total_mort <dbl> 15.0, 6.7, 12.6, 13.8, 48.5, 12.6, 5.1, 52.2, 6.4, 2.1, 5.6, 12.3, 13.0, 45.9, 3.6, 6.2, 3.2, 10.0, 33.1, 24.5, 4.7, 63.6, 3.3, 7.1, 28.4, 2.8, 14.0, 6.4, 5.5, 5.5, 5.2, 14.3, 8.5, 147.2, 27.2, 51…

Maximum daily temperature for futures data

The information regarding much of this processing is stored on J drive under J:_Indicators(on ACE3). It may be more reproducible to pull current data directly from the USGS site, but initial tests suggested that would be quite slow, and using these previoulsy developed datasets will be faster.

check_tmax <- read_csv(here("/data/Trim/CanESM2/rcp85/tasmax/tasmax_day_CanESM2_rcp85_r1i1p1_20060101-20061231.LOCA_2016-04-02.16th.csv"))
Parsed with column specification:
cols(
  date = col_date(format = ""),
  city = col_character(),
  tasmax = col_double()
)

Check for alignment between cities in doy and cities in this file.

chk_doy = doy %>%  
  dplyr::select(CITYNAME ) %>%  
  unique () %>%  
  mutate(CITYNAME = casefold (CITYNAME))

chk_city_tmax = check_tmax %>%  
  dplyr::select(city) %>%  
  unique () %>% 
  mutate (CITYNAME = casefold(city))

chk_doy %>%  anti_join(chk_city_tmax)
Joining, by = "CITYNAME"
chk_city_tmax   %>%  anti_join(chk_doy)
Joining, by = "CITYNAME"

Providence is present in tmax trimmed file, but not in doy. Santa Barbara is just missing a space. Update santa barbara in doy during processing.

doy <- doy %>%  
  mutate (CITYNAME = gsub("santabarbara", "santa barbara", CITYNAME)) %>% 
  select (-month, - day) # month and day cause leap year problems
dow <- dow %>%  
  mutate (CITYNAME = gsub("santabarbara", "santa barbara", CITYNAME))

Cluster results from Harvard model-fitting stage

Definitions of object names

Lag0 model: Daily maximum temperature

  • mv_1_clx_y1:mv_1_clx_y5
    • meta-analytical fits for lag0 model of cluster ‘x’
  • cp_0_years1: cp_0_years5
    • cros-pred output based on meta-analytical fits
  • knots_1
    • knots for Lag0 model
  • bound_1 = boundaries for Lag0 model in cluster.
    • average max and average min tmax0 for the cluster.

MA15= Moving Average; lag1-5 model

  • mv_2_clx_y1:mv_2_clx_y5
    • meta-analytical fits for lag1:5 model of cluster ‘x’
  • cp_05_years1: cp_05_years5
    • cros-pred output based on meta-analytical fits
  • knots_2= knots for MA15
    • knots for MA15 model
  • bound_2 = boundaries for cluster.
    • average max and average min MA15 for the cluster.

Year blocks for both models (all clusters)

  • years1 = year 1973-1983
  • years2 = year 1983-1993
  • years3 = year 1993-2003
  • years4 = year 2003-2013

Load and investigate the contents of the saved Rdata for a cluster

First, define the spline parameters that are the same across all places:

fun = "bs" ; degree = 2;  cen_1 = 15.6

Create a function (’cluster_load)

This finds the cluster results, and saves to a nested tibble for further use.

OPTIONS (in progress): Option 1 pulls in everything, but only keeps the coefficients, vcov, boundaries, and knots. It organizes these into two list columns (for daily and moving average arguments).

cluster_load <- function (c_cluster = 1, 
                          out_folder = "output/vodonos_out/2019-06-13_mvcl_4_time/", nsim = 1000) {
  #Load the contents of the saved Rdata for a cluster

  require(here)
  print (c_cluster)
  cp_fname <- gsub("X", c_cluster,"/mv_clX/mv_clX/cp.clusterX.years4.Rdata")
  cp_fname <- here::here(out_folder, cp_fname)
  load(cp_fname)
  mv_fname <- gsub("X", c_cluster,"/mv_clX/mv_clX/mv_clX_y4.Rdata")
  mv_fname <- here::here(out_folder, mv_fname)
  load(mv_fname)
  
  if (exists("cp_15_years4")) {cp_05_years4  <-  cp_15_years4}# corrects a naming issue in some vodonos output
  
       daily_tmax0_arg = list ( c(  
         bound =  list (c(range (cp_0_years4$predvar)  )),
         knots = list (c(knots_1)),
         coeff = list (c(cp_0_years4$coefficients)),
         varcov = list (c(cp_0_years4$vcov) )  ) )
       
        ma15_tmax05_arg =list ( c(  
         bound =  list (c(range (cp_05_years4$predvar)  )),
         knots = list (c(knots_2)),
         coeff = list (c(cp_05_years4$coefficients)),
         varcov = list (c(cp_05_years4$vcov) )  ))
       
   cluster_0_fits <- tibble (cluster = c_cluster,
       daily_tmax0_arg = daily_tmax0_arg  )

   cluster_05_fits <- tibble (cluster = c_cluster,
     ma15_tmax05_arg = ma15_tmax05_arg  )

   
   cluster_x_fits <- cluster_0_fits %>%  inner_join(cluster_05_fits)
   # change to tibble for purrr operations later
    
return (cluster_x_fits)
}

Pull in and stack all clusters (1-9)

cluster_fits <-  seq(1,9)  %>%  
  map_dfr(cluster_load, 
      out_folder = "output/vodonos_out/2019-06-13_mvcl_4_time/") 
[1] 1
Joining, by = "cluster"
[1] 2
Joining, by = "cluster"
[1] 3
Joining, by = "cluster"
[1] 4
Joining, by = "cluster"
[1] 5
Joining, by = "cluster"
[1] 6
Joining, by = "cluster"
[1] 7
Joining, by = "cluster"
[1] 8
Joining, by = "cluster"
[1] 9
Joining, by = "cluster"
cluster_fits %>%  glimpse()
Observations: 9
Variables: 3
$ cluster         <int> 1, 2, 3, 4, 5, 6, 7, 8, 9
$ daily_tmax0_arg <list> [[<-13.2, 31.0>, <-1.302139, 11.913495, 23.875105>, <0.02469060, 0.04119767, 0.10576454, 0.15605829, 0.21447051>, <0.0002373320, 0.0001821380, 0.0001965471, 0.0001674620, 0.0002109098, 0.000…
$ ma15_tmax05_arg <list> [[<-9.5, 29.1>, <-3.289712, 6.960163, 16.811502, 24.736101>, <-0.02309032, -0.05991974, -0.11095517, -0.19205325, -0.22130423, -0.20194653>, <7.596052e-05, 4.825860e-05, 6.411353e-05, 6.2144…

Join to day of year deaths

The previously processed data can be joined on city name

cluster_fits_doy <-  doy %>% 
  group_by(cluster,  FIPS_txt, CITYNAME) %>% 
  nest(.key = "doy_av_mort")  %>% 
  # ungroup() %>%  group_by (cluster) %>% 
  # nest(.key = "city_doy_av_mort")  %>% 
  left_join(cluster_fits) 
Joining, by = "cluster"
cluster_fits_doy %>%  glimpse()
Observations: 208
Variables: 6
$ cluster         <dbl> 2, 2, 9, 1, 5, 1, 2, 4, 1, 9, 4, 6, 8, 1, 2, 1, 2, 6, 1, 4, 9, 1, 2, 7, 2, 2, 2, 1, 2, 4, 3, 4, 4, 2, 3, 3, 2, 4, 3, 7, 4, 2, 9, 3, 7, 2, 2, 2, 2, 1, 4, 8, 1, 2, 8, 2, 1, 5, 3, 5, 2, 4, 2, 8,…
$ FIPS_txt        <chr> "39153", "36001", "35001", "42077", "06059", "51059", "26161", "13067", "34001", "35045", "13245", "48453", "06029", "24510", "23019", "25001", "36101", "22033", "34003", "01073", "16001", "2…
$ CITYNAME        <chr> "akron", "albany", "albuquerque", "allentown", "anaheim", "annandale", "annarbor", "atlanta", "atlantic city", "atzec", "augusta", "austin", "bakersfield", "baltimore", "bangor", "barnstable"…
$ doy_av_mort     <list> [<tbl_df[366 x 2]>, <tbl_df[366 x 2]>, <tbl_df[366 x 2]>, <tbl_df[366 x 2]>, <tbl_df[366 x 2]>, <tbl_df[366 x 2]>, <tbl_df[366 x 2]>, <tbl_df[366 x 2]>, <tbl_df[366 x 2]>, <tbl_df[366 x 2]>,…
$ daily_tmax0_arg <list> [[<-19.3, 29.6>, <1.656303, 17.759536>, <-0.02399588, 0.01688781, 0.06881664, 0.12780218>, <0.0001698283, 0.0001028722, 0.0001310583, 0.0001135017, 0.0001028722, 0.0001156094, 0.0001053619, …
$ ma15_tmax05_arg <list> [[<-15.8, 27.9>, <-4.973697, 9.766807, 22.087255>, <-0.002223833, -0.038615873, -0.096352729, -0.186909996, -0.150082280>, <0.0001845120, 0.0001403662, 0.0001586254, 0.0001548495, 0.00016076…

Load modeled temperature data

This function gets the full Tmax0 file for all gridded data, then subsets it to free up memory. It also assignes the reduced data to the global environment for further use. Updated for pre-processed by-city tmax data. Note that this may need to be updated, but it appears to be correct linkage to cities as shown above (with exception of ‘Providence RI’), and is from 2016 download of LOCA data. Not clear whether there have been updates since then. These modeled data were used for the last mortality manuscript.

# list.files(here("data/cira3/"))
# list.files(here('data'))

get_tmax <- function ( gcm = "CanESM2", rcp = "RCP85" ,  dt_yr = 2011, doy_frame = doy,
                       cira_folder =here("/data/Trim/"),...  )
{### This function loads modeled temperature data, converts dates to month/day, and converts kelvin to degrees c
  ## Updated for new input from previously processed data (too large to move to C drive project folder, and not in appropriate place for final output)
  # require (here)
  require (dplyr) # for data cleaning
  require (tidyr) # for data cleaning
  require (data.table) # for fread and %like%
  require (purrr) # for map_dfr
  yrs = seq ((dt_yr-5),(dt_yr+5) )
   
 ## Select out just the correct files
  gcm_folder <-  paste(cira_folder, gcm, "/", 
                   casefold(rcp), "/tasmax/", sep = "")
  gcm_files  <- list.files(gcm_folder, full.names =   TRUE)
  gcm_files  <- map_chr(.x = yrs, 
                        .f = function (.x) {gcm_files[gcm_files %like% paste(.x, "0101-", .x, "1231", sep = "")]})
  # print(yrs)
  fnames = tibble (dt_yr = rep(dt_yr, 11), 
                   gcm = gcm, 
                   rcp = rcp, 
                   yr = yrs) %>%  
    mutate(fname =        gcm_files )
  
  tmax_dt_yr <- map_dfr(fnames$fname, fread ) 
  
  tmax_dt_yr <- tmax_dt_yr %>%   
    mutate(CITYNAME = casefold(city),
            gcm = gcm, # may save memory to remove repeated column names, but inconvenient 
            rcp = rcp,
            dt_yr = dt_yr,
            year = lubridate::year(as.Date(date)) , 
            #month = lubridate::month(as.Date(date)),
            #day =  lubridate::day(as.Date(date)),
            doy = lubridate::yday(as.Date(date)),
            tmean0 = tasmax - 273.15)  %>% 
    group_by(year, city, CITYNAME) %>% #gcm, rcp, dt_yr, 
    nest(.key = "doy_tmean0") 
  
  return (tmax_dt_yr)
}

Climate projection processing

For each climate model and year for which an average change in temperature occurs, pull in the data with tmax_daily. Calculate lagged maximum temperature (moving average 5-day) Join to cluster fits, and create a bounded variable that replaces maximum temperature exceeding bounds with the upper and lower bounds as needed. Use cluster-specific spline values and city-specific day of year death to calcuate daily and tmax mortality values.

Function to calculate lagged (5-dy moving average)

lag_calc <- function (tmax_2lag = tmax_daily$doy_tmean0[[1]] ) {
lagged_tmax <- tmax_2lag  %>%   
  mutate(
  tmeanL1 = ifelse (is.na(lag(tmean0)), tmean0, lag(tmean0)),
  tmeanL2 = ifelse (is.na(lag(tmean0, 2)), tmean0, lag(tmean0, 2)),
  tmeanL3 = ifelse (is.na(lag(tmean0, 3)), tmean0, lag(tmean0, 3)),
  tmeanL4 = ifelse (is.na(lag(tmean0, 4)), tmean0, lag(tmean0, 4)),
  tmean15 = (tmean0 + tmeanL1 + tmeanL2 + tmeanL3 + tmeanL4) / 5
) %>% 
   select(-starts_with("tmeanL"))
return (lagged_tmax)
 }
 

Function to join to cluster fits, apply bounds, and other calculations

join_doy_proj <- function (tmax_daily = tmax_daily, 
                           cluster_param = cluster_fits_doy) {
  # join cluster paramaters to tmax and apply cluster-specific calculations
  # some unnesting for convenience in merge
  
  cl_doy <- cluster_param %>%  
    select(-ends_with("arg") ) %>%  
    unnest() # cluster_param
  
  doy_tmax <- tmax_daily %>%  #tmax_2join
    select(CITYNAME, year,  doy_tmax) %>%  
    unnest() %>% 
    right_join(cl_doy, by = c("CITYNAME", "doy"))   %>%  
    group_by(CITYNAME, year, cluster, FIPS_txt) %>%  
    nest(.key = "day_tm")
  
  cluster_param <- cluster_param %>%  
    select(-doy_av_mort)
  
  tmax_daily <- tmax_daily %>%  #SAVE MEMORY__DO column names LAST: tmax_daily <- tmax_daily %>%  select (-gcm, -rcp, -dt_yr) 
    select(-doy_tmax) %>% 
    inner_join(doy_tmax, 
               by = c("year", "CITYNAME"))  %>% 
    #To save memory, consider: ungroup() %>%  group_by(cluster) %>% nest(.key = "city_doy_tmax) %>%  inner_join(cluster_param, by = "cluster")
    inner_join(cluster_param, 
               by = c("CITYNAME", "cluster", "FIPS_txt"))  
  
  return (tmax_daily)
}

Create bounding function to truncate tmax distribution at bounds.

bound_tmax <- function(tmax, bound) {
  case_when  (tmax < bound[1] ~ bound[1],# set tmax.bound to L bound
              tmax > bound[2] ~  bound[2], # set tmax.bound to U bound
              TRUE ~ tmax)
}

Create functions for by-city calculations within a cluster

dlnm::crosspred produces just predictions for the range of the input basis. It does not produce predictions for each row. Therefore, must reproduce with onebasis and relative risk calculation. Make the basis first for the temperature series, then create a basis for the center point, then scale the basis vector by the centered basis.

Function for relative risk calculation


rr_calc <- function ( tmax = c(10, 20, 30), 
                              baseline_projected_mort = c(10,15), 
                              coef_mat = cp_0_years4$coefficients,
                              center_val = cen_1, 
                              degree_val = 2,
                              knot_vec = knots_1, 
                              bound_vec = bound_1 ){
  ## This function calculates relative risk from an uncentered basis matrix and fitted coefficients
  # Currently implemented for EACH tmax value. 
require( dlnm) ; require (splines)
bs_ce  <- bs(center_val,   degree = degree_val,  knots = knot_vec, Bound=bound_vec, intercept = FALSE)
bs_var <- suppressWarnings(bs(tmax,    degree = degree_val,  knots = knot_vec, Bound=bound_vec, intercept = FALSE ) ) # suppress repetetive warning regarding temperatures outside of original boundaries
bs_vc   <- scale(bs_var, center = bs_ce,  scale = FALSE)

RR_temp <- as.numeric ((1-exp(-bs_vc %*% coef_mat) ) )

#attr_death_n <-  RR_temp * baseline_projected_mort
return (  RR_temp   )
}

Function to loop through the projected temperatures, apply cluster coefficients, and calculate relative risk (no CI yet).


project_spline <- function (dframe =  tmax_daily [1,],
                            cen  = 15.6, deg = 2) {
 day_tm <- dframe$day_tm[[1]]
 param_t0 <- dframe$daily_tmax0_arg[[1]] # was cp_0_years4 in original scheme
 param_ma15 <- dframe$ma15_tmax05_arg[[1]] # was cp_05_years4 in original scheme
 #, fun = "bs" for rr_calc
 day_tm <- day_tm %>% 
   mutate (year = dframe$year,  city = dframe$city, 
           #CITYNAME = dframe$CITYNAME,  cluster = dframe$CITYNAME,  FIPS_txt = dframe$FIPS_txt, 
           # hacky solution, but purrr not mutating easily on nested tibble, and not clear how to resolve
           tmean0_bound = bound_tmax(tmean0, param_t0$bound),
           tmean15_bound = bound_tmax(tmean15, param_ma15$bound)  ,
           rr_tmean0 = rr_calc ( tmean0,  
                 baseline_projected_mort = total_mort, 
                 coef_mat = param_t0$coeff,
                 center_val = cen, 
                 degree_val = deg,
                 knot_vec = param_t0$knots , 
                 bound_vec = param_t0$bound),
           rr_tmean15 =  rr_calc ( tmean15,  
                 baseline_projected_mort = total_mort, 
                 coef_mat = param_ma15$coeff,
                 center_val = cen, 
                 degree_val = deg,
                 knot_vec = param_ma15$knots, 
                 bound_vec = param_ma15$bound),
           rr_tmean0_bnd = rr_calc ( tmean0_bound,  
                 baseline_projected_mort = total_mort, 
                 coef_mat = param_t0$coeff,
                 center_val = cen, 
                 degree_val = deg,
                 knot_vec = param_t0$knots , 
                 bound_vec = param_t0$bound )   ,
           rr_tmean15_bnd = rr_calc ( tmean15_bound,  
                 baseline_projected_mort = total_mort, 
                 coef_mat = param_ma15$coeff,
                 center_val = cen, 
                 degree_val = deg,
                 knot_vec = param_ma15$knots, 
                 bound_vec = param_ma15$bound)   , 
           an_tmean0 = rr_tmean0 * total_mort,
           an_tmean15= rr_tmean15 * total_mort,
           an_tmean0_bnd= rr_tmean0_bnd * total_mort,
           an_tmean15_bnd= rr_tmean15_bnd * total_mort ) %>% 
   select (year, city, everything()) #, CITYNAME, cluster, FIPS_txt
  return (day_tm)
}

Tabulate

Do two ways. For cities, aggregate AN over full 11 year period by day of year. Get a mean AN for each day for each city in the 11 year period. For clusters, first aggregate by year to get total increase in death each year.

Summarization functions for use in other functions. These functions currently do not weight values.


summarise_temp_c <- function(dframe , ...) 
  { # alllows different grouping variables defined as variable length arguments  ...  
   
  group_var <- enquos(...)
  print(group_var)
  
      dframe <- dframe %>% 
        group_by(!!! group_var) %>% #!!! group_var
        summarise(mean_daily_c = mean (tmean0),
             sd_daily_c = sd(tmean0),
             max_daily_c = max(tmean0),
             min_daily_c = min(tmean0),
             mean_ma15_c = mean(tmean15),
             sd_ma15_c =  sd(tmean15),
             max_ma15_c = max(tmean15),
             min_ma15_c = min(tmean15))
      return (dframe)
}
 
summarise_mean_rr <- function(dframe = proj_rr_daily, 
                              rr_vars = c(rr_tmean0 = "rr_tmean0", rr_tmean15 = "rr_tmean15", rr_tmean0_bnd= "rr_tmean0_bnd", rr_tmean15_bnd = "rr_tmean15_bnd"), 
                              ...) 
  { # alllows different grouping variables defined as variable length arguments  ...  
      group_var <- enquos(...)
      
       dframe <- dframe %>% rename (!!!rr_vars)
       
      if(any(!grepl("total", rr_vars)) )  {dframe <- dframe  %>% rename (!!!rr_vars)  %>%
         mutate(rr_total = rr_tmean0 + rr_tmean15,
                rr_total_bnd = rr_tmean0_bnd + rr_tmean15_bnd)
        }
 
        dframe <- dframe %>%
        group_by(!!! group_var) %>%
        summarise(
          mean_rr_total = mean(rr_total),
          sd_rr_total = sd(rr_total),
          mean_rr_total_bnd = mean(rr_total_bnd),
          sd_rr_total_bnd = sd(rr_total_bnd)
          )
      
      return (dframe)
}
summarise_mean_an <- function(dframe ,
                              an_vars = c(an_tmean0 = "an_tmean0", an_tmean15 ="an_tmean15", an_tmean0_bnd = "an_tmean0_bnd", an_tmean15_bnd ="an_tmean15_bnd") , 
                              ...) 
  { # alllows different grouping variables defined as variable length arguments  ...  
      group_var <- enquos(...)
      
      dframe <- dframe %>% rename (!!!an_vars) %>%mutate()
       
      if(any(!grepl("total", an_vars)) )  {dframe <- dframe  %>% rename (!!!an_vars)  %>%
         mutate(an_total = an_tmean0  + an_tmean15,
               an_total_bnd = an_tmean0_bnd  + an_tmean15_bnd)
        }
  
          
      dframe <- dframe %>% 
        group_by(!!! group_var) %>%
             summarise(baseline_proj_mort = mean (total_mort), # use mean to extract original projected baseline again
                       mean_an_total = mean(an_total),
                       sd_an_total = sd(an_total),
                       mean_an_total_bnd = mean(an_total_bnd),
                       sd_an_total_bnd = sd(an_total_bnd)) }
summarise_sum_an <- function(dframe , 
                             an_vars = c(total_mort = total_mort, 
                                         an_tmean0 = "an_tmean0", an_tmean15 ="an_tmean15", 
                                         an_tmean0_bnd = "an_tmean0_bnd", an_tmean15_bnd ="an_tmean15_bnd") ,  
                             ...) 
  { # alllows different grouping variables defined as variable length arguments  ...  
      group_var <- enquos(...)
      dframe <- dframe %>% rename (!!!an_vars)
       
      if(any(!grepl("an_total", an_vars)) )  {dframe <- dframe  %>% rename (!!!an_vars)  %>%
         mutate(an_total = an_tmean0  + an_tmean15,
               an_total_bnd = an_tmean0_bnd  + an_tmean15_bnd)
        }
  
          
      dframe <- dframe %>% 
        group_by(!!! group_var) %>%
             summarise(baseline_proj_mort = sum(total_mort), 
                       sum_an_total = sum(an_total),
                       sum_an_total_bnd = sum(an_total_bnd) ) }

Tabulate by city and day of year over the whole period. This function calculates the mean number of attributable deaths over the 11 year period for a particular city and climate model.

Tabulate cluster day of year attributable deaths. This function calculates a sum AN of all cities in a cluster for each year of the 11 year period for a gcm. The mean and sd temperatures are currently unweighted.

Tabulate cluster period attributable deaths. This function calculates an average AN for the whole period, using the previously calculated total AN of all cities in a cluster for each year of the 11 year period for a gcm. The mean temperatures are not currently population or area weighted.

Plotting functions

Run for all dT

dT_func_simple <- function (gcm_sel ="CCSM4" ,
          dT_c_sel = 1,
          rcp_sel = "RCP85"  ,
          dt_yr_sel = 2011,  
          cira_folder = here("/data/Trim/"),
          output_folder =  here::here ("output", format(Sys.Date(), "%F")) 
          ) {
  print (gcm_sel) ; print (dT_c_sel) ; print(rcp_sel); print(dt_yr_sel)
  # get data
  tic(msg = "get_tmax")
   tmax_daily <- get_tmax (cira_folder = cira_folder,
                          gcm = gcm_sel , rcp =  rcp_sel ,  dt_yr =  dt_yr_sel  )
  toc()

   # Lag calc   
tic(msg = "calculate lagged tmax")
tmax_daily <- tmax_daily %>% 
  mutate(dT_c = dT_c_sel ,
         doy_tmax = map(tmax_daily$doy_tmean0, lag_calc)) %>% 
  select (-doy_tmean0)
toc()

#join to cluster fits, apply bounds, and other calculations
tic(msg = "join_doy_proj")
tmax_daily <- join_doy_proj  (tmax_daily = tmax_daily , cluster_param = cluster_fits_doy) 
toc()

tic(msg = "day_tm operation")
## add projected mortality and RR to tmax_daily  (trouble with list position means this may be more complicated than needed)
tmax_daily$day_tm <- tmax_daily %>%    
  ungroup () %>% 
  group_split( city,  year )  %>% #CITYNAME, cluster, FIPS_txt, 
  map_dfr ( .f = project_spline, cen  = 15.6, deg = 2)  %>%
  group_by(city,  year) %>% #CITYNAME, cluster, FIPS_txt,
  nest(.key = "day_tm") %>%  
  pull(day_tm  )
toc()
  
return(tmax_daily)
}

Iterate through all dT for each GCM.


## Get GCM list for dt to run (minus baseline)
gcm_dt_lut_proj <- gcm_dt_lut %>%  
  mutate (gcm = gsub("_", "-", gcm) )  %>% 
  filter (gcm != "baseline")  %>%  # remove as is stored elsewhere
  mutate (rcp = "RCP85")  

  output_folder_path <- here::here("output", format(Sys.Date(), "%F") )
 if(!dir.exists(output_folder_path)) {dir.create(output_folder_path, recursive = TRUE)}

    
compiled_city_mean_out <- pmap_dfr   (.l = list (gcm_dt_lut_proj$gcm[1:2]  ,  gcm_dt_lut_proj$dT[1:2]  , gcm_dt_lut_proj$rcp[1:2]  , gcm_dt_lut_proj$dt_year[1:2] ) , 
                .f = dT_func_simple, 
                cira_folder =here("/data/Trim/"),
                output_folder =  output_folder_path )  
[1] "CanESM2"
[1] 1
[1] "RCP85"
[1] 2011
get_tmax: 6.143 sec elapsed
calculate lagged tmax: 4.632 sec elapsed
join_doy_proj: 0.75 sec elapsed
day_tm operation: 11.596 sec elapsed
[1] "CanESM2"
[1] 2
[1] "RCP85"
[1] 2033
get_tmax: 6.115 sec elapsed
calculate lagged tmax: 4.672 sec elapsed
join_doy_proj: 0.733 sec elapsed
day_tm operation: 11.769 sec elapsed
save(compiled_city_mean_out, file = file.path(output_folder_path, "compiled_city.Rdata") )

Summarize fully stacked data

Average over included GCM

mean_c_dt_city_doy <- dTc_compiled_gcm_city %>% 
  summarise_temp_c(  cluster, city,  CITYNAME, FIPS_txt, dT_c, doy)
[[1]]
<quosure>
expr: ^cluster
env:  0x55c1273d3918

[[2]]
<quosure>
expr: ^city
env:  0x55c1273d3918

[[3]]
<quosure>
expr: ^CITYNAME
env:  0x55c1273d3918

[[4]]
<quosure>
expr: ^FIPS_txt
env:  0x55c1273d3918

[[5]]
<quosure>
expr: ^dT_c
env:  0x55c1273d3918

[[6]]
<quosure>
expr: ^doy
env:  0x55c1273d3918
mean_rr_dt_city_doy <- dTc_compiled_gcm_city %>% summarise_mean_rr(rr_vars = c(rr_tmean0 = "rr_tmean0", rr_tmean15 = "rr_tmean15", rr_tmean0_bnd= "rr_tmean0_bnd", rr_tmean15_bnd = "rr_tmean15_bnd"), 
                                                                   cluster, city,  CITYNAME, FIPS_txt, dT_c, doy)

mean_an_dt_city_doy <- dTc_compiled_gcm_city %>% summarise_mean_an( an_vars = c(an_tmean0 = "an_tmean0", an_tmean15 ="an_tmean15", an_tmean0_bnd = "an_tmean0_bnd", an_tmean15_bnd ="an_tmean15_bnd") , 
                                                                    cluster, city,  CITYNAME, FIPS_txt, dT_c, doy)

city_tab_doy <- mean_c_dt_city_doy %>% inner_join(mean_rr_dt_city_doy)   %>% 
  inner_join(mean_an_dt_city_doy) 
Joining, by = c("cluster", "city", "CITYNAME", "FIPS_txt", "dT_c", "doy")
Joining, by = c("cluster", "city", "CITYNAME", "FIPS_txt", "dT_c", "doy")
city_tab_doy%>% head()
  #Calculate the mean sum of attributable deaths for a year in the 11 year period for a particular city and climate model.
  tic(msg = "Summarize AN, grouped by dT, cluster and city")
  
  sum_an_dt_city  <- summarise_sum_an(dTc_compiled_gcm_city, 
                                      an_vars = c(total_mort = "total_mort", 
                                         an_tmean0 = "an_tmean0", an_tmean15 ="an_tmean15", 
                                         an_tmean0_bnd = "an_tmean0_bnd", an_tmean15_bnd ="an_tmean15_bnd") , 
                                      cluster, city,  CITYNAME, FIPS_txt, dT_c, year, gcm)  %>% 
    ungroup() %>% 
    group_by(cluster, city,  CITYNAME, FIPS_txt, dT_c) %>% 
    summarise(baseline_proj_mort = mean(baseline_proj_mort) , sum_an_total= mean(sum_an_total), sum_an_total_bnd=mean(sum_an_total_bnd))
 
  sum_an_dt_city_fname <- file.path(output_folder_path, paste(format(Sys.Date(), "%F_"),  
                                                        "city_dT_AN_summary.csv", sep = "") )
  write_csv(sum_an_dt_city, path = sum_an_dt_city_fname)
  toc()
Summarize AN, grouped by dT, cluster and city: 0.747 sec elapsed
  
  sum_an_dt_city

Mortality

For notes on the baseline data, see the readme for the baseline mortality used in temperature mortbidity Previous mortality baselines for other (Climecon 4 Task 004) mortality work relied on calculations from BEN Map.

Information developed by Neal Fann o f U.S. EPA taking shape file of the citities and
using it to export baseline mortality informataion for the 209 US cities coverd in that analysis. Subset of these cities were addressed in the original Medina-Ramon and Schwartz paper.

Source file saved independently as
\boufile0114_8_CIRA2-mortality-mortality-rates-baseline_mortality_w_city.xlsx

original email with files sent to d. Mills on 7/2/14 from Neal Fann in Heat-Pops email directory: Population-health-baseline-data folder
— Dave Mills in Project/Climecon4/COOLIT13_RiskComm/Mortality/Mortality-temp-calcs-Excel-QAQC-2016-08-08.xlsx

Session Info

devtools::session_info()
─ Session info ────────────────────────────────────────────────────────────────────────────────────

─ Packages ────────────────────────────────────────────────────────────────────────────────────────
 package     * version  date       lib source        
 assertthat    0.2.0    2017-04-11 [2] CRAN (R 3.5.1)
 backports     1.1.2    2017-12-13 [2] CRAN (R 3.5.1)
 base64enc     0.1-3    2015-07-28 [2] CRAN (R 3.5.1)
 broom         0.5.0    2018-07-17 [2] CRAN (R 3.5.1)
 callr         3.0.0    2018-08-24 [2] CRAN (R 3.5.1)
 cellranger    1.1.0    2016-07-27 [2] CRAN (R 3.5.1)
 cli           1.0.1    2018-09-25 [2] CRAN (R 3.5.1)
 colorspace    1.3-2    2016-12-14 [2] CRAN (R 3.5.1)
 crayon        1.3.4    2017-09-16 [2] CRAN (R 3.5.1)
 data.table  * 1.11.8   2018-09-30 [2] CRAN (R 3.5.1)
 debugme       1.1.0    2017-10-22 [2] CRAN (R 3.5.1)
 desc          1.2.0    2018-05-01 [2] CRAN (R 3.5.1)
 devtools      2.0.1    2018-10-26 [2] CRAN (R 3.5.1)
 digest        0.6.18   2018-10-10 [2] CRAN (R 3.5.1)
 dlnm        * 2.3.6    2018-09-12 [2] CRAN (R 3.5.1)
 dplyr       * 0.8.3    2019-07-04 [1] CRAN (R 3.5.1)
 evaluate      0.12     2018-10-09 [2] CRAN (R 3.5.1)
 fansi         0.4.0    2018-10-05 [2] CRAN (R 3.5.1)
 forcats     * 0.3.0    2018-02-19 [2] CRAN (R 3.5.1)
 fs            1.2.6    2018-08-23 [2] CRAN (R 3.5.1)
 ggplot2     * 3.1.0    2018-10-25 [2] CRAN (R 3.5.1)
 glue          1.3.0    2018-07-17 [2] CRAN (R 3.5.1)
 gridExtra   * 2.3      2017-09-09 [2] CRAN (R 3.5.1)
 gtable        0.2.0    2016-02-26 [2] CRAN (R 3.5.1)
 haven         1.1.2    2018-06-27 [2] CRAN (R 3.5.1)
 here        * 0.1      2017-05-28 [1] CRAN (R 3.4.4)
 hms           0.4.2    2018-03-10 [2] CRAN (R 3.5.1)
 htmltools     0.3.6    2017-04-28 [2] CRAN (R 3.5.1)
 httr          1.3.1    2017-08-20 [2] CRAN (R 3.5.1)
 jsonlite      1.5      2017-06-01 [2] CRAN (R 3.5.1)
 knitr         1.20     2018-02-20 [2] CRAN (R 3.5.1)
 lattice       0.20-38  2018-11-04 [2] CRAN (R 3.5.1)
 lazyeval      0.2.1    2017-10-29 [2] CRAN (R 3.5.1)
 lubridate     1.7.4    2018-04-11 [2] CRAN (R 3.5.1)
 magrittr      1.5      2014-11-22 [2] CRAN (R 3.5.1)
 MASS        * 7.3-51.1 2018-11-01 [2] CRAN (R 3.5.1)
 Matrix        1.2-15   2018-11-01 [2] CRAN (R 3.5.1)
 memoise       1.1.0    2017-04-21 [2] CRAN (R 3.5.1)
 mgcv        * 1.8-25   2018-10-26 [2] CRAN (R 3.5.1)
 modelr        0.1.2    2018-05-11 [2] CRAN (R 3.5.1)
 munsell       0.5.0    2018-06-12 [2] CRAN (R 3.5.1)
 mvmeta      * 0.4.11   2018-03-07 [2] CRAN (R 3.5.1)
 nlme        * 3.1-137  2018-04-07 [2] CRAN (R 3.5.1)
 packrat       0.5.0    2018-11-14 [2] CRAN (R 3.5.1)
 pillar        1.4.2    2019-06-29 [1] CRAN (R 3.5.1)
 pkgbuild      1.0.2    2018-10-16 [2] CRAN (R 3.5.1)
 pkgconfig     2.0.2    2018-08-16 [2] CRAN (R 3.5.1)
 pkgload       1.0.2    2018-10-29 [2] CRAN (R 3.5.1)
 plyr          1.8.4    2016-06-08 [2] CRAN (R 3.5.1)
 prettyunits   1.0.2    2015-07-13 [2] CRAN (R 3.5.1)
 processx      3.2.0    2018-08-16 [2] CRAN (R 3.5.1)
 ps            1.2.1    2018-11-06 [2] CRAN (R 3.5.1)
 purrr       * 0.2.5    2018-05-29 [2] CRAN (R 3.5.1)
 R6            2.3.0    2018-10-04 [2] CRAN (R 3.5.1)
 Rcpp          1.0.2    2019-07-25 [1] CRAN (R 3.5.1)
 readr       * 1.1.1    2017-05-16 [2] CRAN (R 3.5.1)
 readxl      * 1.1.0    2018-04-20 [2] CRAN (R 3.5.1)
 remotes       2.0.2    2018-10-30 [2] CRAN (R 3.5.1)
 rlang         0.4.0    2019-06-25 [1] CRAN (R 3.5.1)
 rmarkdown     1.10     2018-06-11 [2] CRAN (R 3.5.1)
 rprojroot     1.3-2    2018-01-03 [2] CRAN (R 3.5.1)
 rstudioapi    0.8      2018-10-02 [2] CRAN (R 3.5.1)
 rvest         0.3.2    2016-06-17 [2] CRAN (R 3.5.1)
 scales        1.0.0    2018-08-09 [2] CRAN (R 3.5.1)
 sessioninfo   1.1.1    2018-11-05 [2] CRAN (R 3.5.1)
 stringi       1.2.4    2018-07-20 [2] CRAN (R 3.5.1)
 stringr     * 1.3.1    2018-05-10 [2] CRAN (R 3.5.1)
 survival    * 2.43-1   2018-10-29 [2] CRAN (R 3.5.1)
 testthat      2.0.1    2018-10-13 [2] CRAN (R 3.5.1)
 tibble      * 2.1.3    2019-06-06 [1] CRAN (R 3.5.1)
 tictoc      * 1.0      2014-06-17 [1] CRAN (R 3.5.1)
 tidyr       * 0.8.2    2018-10-28 [2] CRAN (R 3.5.1)
 tidyselect    0.2.5    2018-10-11 [2] CRAN (R 3.5.1)
 tidyverse   * 1.2.1    2017-11-14 [2] CRAN (R 3.5.1)
 tsModel     * 0.6      2013-06-24 [2] CRAN (R 3.5.1)
 tufte         0.4      2018-07-15 [2] CRAN (R 3.5.1)
 usethis       1.4.0    2018-08-14 [2] CRAN (R 3.5.1)
 utf8          1.1.4    2018-05-24 [2] CRAN (R 3.5.1)
 vctrs         0.2.0    2019-07-05 [1] CRAN (R 3.5.1)
 withr         2.1.2    2018-03-15 [2] CRAN (R 3.5.1)
 xml2          1.2.0    2018-01-24 [2] CRAN (R 3.5.1)
 yaml          2.2.0    2018-07-25 [2] CRAN (R 3.5.1)
 zeallot       0.1.0    2018-01-28 [1] CRAN (R 3.4.4)

[1] /home/ad.abt.local/layc/R/library
[2] /opt/R/3.5.1/lib64/R/library
LS0tCnRpdGxlOiAiQ0lSQSBtb3J0YWxpdHkgcHJvamVjdGlvbiIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUYnKWAiCmF1dGhvcjogIkNsYWlyZSBMYXkiCmtuaXQ6IChmdW5jdGlvbihpbnB1dEZpbGUsIGVuY29kaW5nKSB7IHJtYXJrZG93bjo6cmVuZGVyKGlucHV0RmlsZSwgZW5jb2RpbmcgPSBlbmNvZGluZywgb3V0cHV0X2ZpbGUgPWZpbGUucGF0aChkaXJuYW1lKGlucHV0RmlsZSksIHBhc3RlKGZvcm1hdChTeXMudGltZSgpLCAnJUYnKSwgZ3N1YignUm1kJywgJ2h0bWwnLCAgYmFzZW5hbWUoaW5wdXRGaWxlKSksIHNlcCA9ICIiKSkpIH0pCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAga2VlcF9tZDogVFJVRQogICAgc2VsZl9jb250YWluZWQ6IEZBTFNFCiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogVFJVRQogICAgdG9jX2RlcHRoOiA1IAogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZGZfcHJpbnQ6IHBhZ2VkCgotLS0KCgojIyBJbnRyb2R1Y3Rpb24KVGhpcyBmaWxlIGNvbnRhaW5zIGNvZGUgYW5kIGlucHV0cyBmb3IgcHJvamVjdGlvbnMgb2YgdGVtcGVyYXR1cmUgcmVsYXRlZCBtb3JhdGxpdHkgYmFzZWQgb24gaGlzdG9yaWNhbCBkYXRhIGZvciAyMDkgY2l0aWVzLiBUaGUgb3JpZ2luYWwgbW9kZWxpbmcgd2FzIHBlcmZvcm1lZCBieSBKb2VsIFNjaHdhcnR6IGFuZCBBbGluYSBWb2Rvbm9zIFppbGJlcmcgdXNpbmcgZGF0YSBvYnRhaW5lZCBkaXJlY3RseSBmcm9tIGNvdW50aWVzLCBhbmQgaGlzdG9yaWNhbCB0ZW1wZXJhdHVyZXMgY2FsY3VsYXRlZCBieSBBYnQuIAoKYGBge3IgaW5jbHVkZT1GQUxTRX0KI2tuaXRyOjpvcHRzX2NodW5rJHNldChjb21tZW50ID0gTkEsIHRpZHkgPSAic3R5bGVyIikgIyB3aWxsIG5vdCBrbml0IG9uIEFDRTMuIE1pc3Npbmcgc3R5bGVyID8KYGBgCiAKIyMjIExvYWQgaW4gUiBwYWNrYWdlcyAKYGBge3IgbGlicmFyeV9sb2FkfQpscGF0aCA8LSAiL2hvbWUvYWQuYWJ0LmxvY2FsL2xheWMvUi9saWJyYXJ5IiAjIGFzc2lnbiBsaWJyYXJ5IGZvciB1c2VyIHcvbyBhZG1pbiBwcml2ZWxlZ2VzIG9uIEFDRTMKLmxpYlBhdGhzKGxwYXRoKQoKI2xpYnJhcnkoY2hyb24pCmxpYnJhcnkodGljdG9jKSAjIGZvciBzeXN0ZW0gdGltZQpsaWJyYXJ5KHJlYWR4bCkgIyBmb3IgcmVhZGluZyBpbiBleGNlbApsaWJyYXJ5KHJlYWRyKSAgIyBmb3IgY3N2CmxpYnJhcnkoc3Vydml2YWwpICMgZnJvbSBvcmlnaW5hbCB2b2Rvbm9zIGNvZGUuIExvYWRlZCBmb3IgY29tcGF0aWJpbGl0eQpsaWJyYXJ5KHNwbGluZXMpICMgZm9yIHNwbGluZXMKbGlicmFyeShNQVNTKSAgIyBmb3IgbXZtZXRhLCBsaWtlbHkKI2xpYnJhcnkobmxtZSkgCmxpYnJhcnkobWdjdikgIyBmcm9tIG9yaWdpbmFsIHZvZG9ub3MgY29kZS4gTG9hZGVkIGZvciBjb21wYXRpYmlsaXR5CmxpYnJhcnkoZGxubSkgIyBmcm9tIG9yaWdpbmFsIHZvZG9ub3MgY29kZS4gTG9hZGVkIGZvciBjb21wYXRpYmlsaXR5CmxpYnJhcnkodHNNb2RlbCkgIyBmcm9tIG9yaWdpbmFsIHZvZG9ub3MgY29kZS4gTG9hZGVkIGZvciBjb21wYXRpYmlsaXR5CmxpYnJhcnkobXZtZXRhKSAjIGZyb20gb3JpZ2luYWwgdm9kb25vcyBjb2RlLiBMb2FkZWQgZm9yIGNvbXBhdGliaWxpdHkKbGlicmFyeShoZXJlKSAjIGNvbnZlbmllbmNlIGZvciBmaWxlcGF0aHMgZHluYW1pYwpoZXJlIDwtIGhlcmU6OmhlcmUgIyB0byBhdm9pZCBvdmVyd3JpdGUKbGlicmFyeShkYXRhLnRhYmxlKSAjIGZyZWFkIGZvciBmYXN0ZXIgcmVhZCAocmVhZC50YWJsZSB0YWtlcyA+MTUgbWluKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKc2VsZWN0IDwtIGRwbHlyOjpzZWxlY3QgIyB0byByZS1hc3NpZ24gc2VsZWN0IHRvIHNwZWNpZnkgZHBseXIgYXMgaXMgbW9yZSBjb21tb25seSB1c2VkIHRoYW4gcmFzdGVyIGFuZCBNQVNTIGZ1bmN0aW9ucyBpbiBzY3JpcHQgYmVsb3cuCiNsaWJyYXJ5KFJjcHBSb2xsKSAjIHJvbGxpbmcgYXZlcmFnZXMgZnJvbSB2b2Rvbm9zPyBMaWtleSBub3QgbmVlZGVkCmxpYnJhcnkocHVycnIpICMgZm9yIGl0ZXJhdGl2ZSBwcm9jZXNzaW5nLgpsaWJyYXJ5KGdyaWRFeHRyYSkgIyBmb3IgZ3JpZC5hcnJhbmdlCmBgYCAKCiMjIyBTb3VyY2UgZmlsZXMgYW5kIGxvY2F0aW9ucwoKIyMjIyBJbiBkYXRhIGZvbGRlciAKCklkZW50aWZ5IGRlZ3JlZXMgY2hhbmdlIGJ5IEdDTSBhbmQgeWVhciAoZm9yIFJDUDguNSk6ICBkYXRhL0dDTV9QZXJpb2RfZFRfTFVULnhsc3gKSWRlbnRpZnkgY2x1c3RlciBhbmQgY291bnR5IGlkZW50eSBmb3IgZWFjaCBjaXR5OiAgICAgIGRhdGEvY2l0eV9jb3VudHlfTFVULnhsc3gKCkNsaW1hdGUgcHJvamVjdGlvbnMgaW46IC8vYm91ZmlsZTAxLmNvcnAuYWJ0YXNzb2MuY29tL2RhdGExL0NvbW1vbi9FTlIvUHJvamVjdC9DbGltZWNvbjQvQ09PTElUMTNfUmlza0NvbW0vTW9ydGFsaXR5L091dHB1dC9UcmltLyBhbmQgRGF0YS9UcmltCkRheSBvZiB3ZWVrIGRlYXRocyBhdmVyYWdlZCBvdmVyIHRoZSBsYXN0IHBlcmlvZCAoMjAwMy0yMDEzKSBmb3IgY2l0aWVzOiBvdXRwdXQvdm9kb25vc19vdXQvaGlzdG9yaWNhbC5kZWF0aHMvbWVhbi5kZWF0aHMuZG93LmNzdgpEYXkgb2YgeWVhciBkZWF0aHMgYXZlcmFnZWQgb3ZlciB0aGUgbGFzdCBwZXJpb2QgKDIwMDMtMjAxMykgZm9yIGNpdGllczogb3V0cHV0L3ZvZG9ub3Nfb3V0L2hpc3RvcmljYWwuZGVhdGhzL21lYW4uZGVhdGhzLmRveS5jc3YKQ29udGFpbnMgZ3JhcGhpY2FsIHJlc3VsdHMgb3V0cHV0IGFuZCBhIG1hdHJpeCB0byBsaW5rIEZJUFMgYXNzaWduZWQgYnkgU2Nod2FydHogbGFiIHRvIGNpdHk6IG91dHB1dC92b2Rvbm9zX291dC9SZXN1bHRzLTUtMjgtMTkueGxzeAoKCiMjIExvYWQgZGVncmVlcyBjaGFuZ2UgbG9va3VwIHRhYmxlCgpVc2UgNSB5ZWFycyBvbiBlYWNoIHNpZGUgb2YgbW9kZWwgcGVyaW9kIHllYXIgdG8gc3RhcnQgKDExIHllYXJzIGluIHRvdGFsIGZvciBlYWNoIGdjbSkuIFVzZSBSQ1AgODUgb25seS4gQ3JlYXRlIDIgcm93cyBpZiB0aGUgcGVyaW9kIHNwYW5zIDIwNTAgYW5kIDIwOTAgR0NNIHBlcmlvZHMsIGFzIHRoZXNlIHdpbGwgbmVlZCB0byBoYXZlIHR3byBzZXBhcmF0ZSBUbWF4IHByb2plY3Rpb24gZmlsZXMgcmVhZCBpbi4KYGBge3J9CmdjbV9kdF9sdXQgPC0gcmVhZF94bHN4KGhlcmUoImRhdGEvR0NNX1BlcmlvZF9kVF9MVVQueGxzeCIpLCBzaGVldCA9ICJHQ01fUGVyaW9kX2RUX0xVVCIpIApnY21fZHRfbHV0IDwtIGdjbV9kdF9sdXQgJT4lIAogIHJlbmFtZSAoZHRfeWVhciA9IG1vZGVsLnBlcmlvZCkgJT4lIAogIG11dGF0ZShtaW5fZHRfeXIgPSBkdF95ZWFyIC0gNSwKICAgICAgICAgbWF4X2R0X3lyID0gZHRfeWVhciArIDUsCiAgICAgICAgICkgIApgYGAKCiMjIExvYWQgY291bnR5IGFuZCBtb3J0YWxpdHkgbG9va3VwIGRhdGEuCgpgYGB7cn0Kb3B0aW9ucygib2JqZWN0LnNpemUiID0gMjAwMDAwMDAwMDAwMCkgIyBmb3IgYmlnZ2VyIGRhdGEgbGltaXQKIyBuY2FfY291bnR5X0xVVCA8LSBmcmVhZChoZXJlKCJkYXRhL2NpcmEzL25jYV9jb3VudHlfTFVULmNzdiIpKQojIG5jYV9jb3VudHlfTFVUIDwtIG5jYV9jb3VudHlfTFVUICU+JSBtdXRhdGUoYEZJUFNfdGV4dGAgPSBGSVBTKQoKbW9ydF9jaXR5X2NvdW50eV9MVVQgPC0gcmVhZF94bHN4KGhlcmUoImRhdGEvY2l0eV9jb3VudHlfTFVULnhsc3giKSkKCmhlYWQobW9ydF9jaXR5X2NvdW50eV9MVVQpCgptb3J0X2NpdHlfY291bnR5X0xVVCA8LSBtb3J0X2NpdHlfY291bnR5X0xVVCAlPiUgbXV0YXRlKGBGSVBTX3RleHRgID0gcGFzdGUoIiciLCBgRklQUy10ZXh0YCwgIiciLCBzZXAgPSAiIikpCgpjbHVzdGVyX0xVVCA8LSAgbW9ydF9jaXR5X2NvdW50eV9MVVQlPiUKICBtdXRhdGUgKENJVFlOQU1FID0gY2FzZWZvbGQoQ0lUWU5BTUUpKSAlPiUgCiAgc2VsZWN0IChDbHVzdGVyLCAgQ2l0eSwgQ0lUWU5BTUUsIFNUQVRFTkFNICwgRklQU190eHQgPSBgRklQUy10ZXh0YCkgI1ZBTFVFLCBDT1VOVCwgRklQU190eHQgPSBgRklQUy10ZXh0YCwgZmlwc19zbSwgRklQUywKYGBgCiAKVXNlIHRoZSBjaXR5LWNvdW50eS1MVVQgdG8gZ2V0IHRoZSBjb3JyZWN0IGNpdHkvY291bnR5IHZhbHVlcyBmb3IgdGhlIGNsaW1hdGUgZmlsZXMgUm9uIG1hZGUgaW4gMjAxNi4gVGhvc2UgZmlsZXMgYXJlIHByZXNlbnQgb24gdGhlIEogZHJpdmUgb24gQUNFMywgYnV0IHJlcXVpcmUgYWRkaXRpb25hbCBkb2N1bWVudGF0aW9uIGZvciB1c2UuIFRoZXkgbmVlZCBhIGRlc2NyaXB0aW9uIG9mIHRoZSBjb2RlIHVzZWQgdG8gcHJvZHVjZSB0aGVtIGFuZCB0aGUgYWdncmVnYXRpb24gbWV0aG9kLiBUaGUgY2xpbWF0ZSBtb2RlbCBvdXRwdXQgYWdncmVnYXRlZCBmb3IgZGVncmVlcyBjZWxzaXVzIGFib3ZlIGJhc2VsaW5lIGlzIGF2YWlsYWJsZSBbaGVyZSBvbiBBQ0UzXShKOlxwcm9qZWN0c1xDSVJBNF9MYWJvclxDSVJBNF9MT0NBX0RhdGEpLgoKIyMjIExvYWQgdGhlIG1vcnRhbGl0eSBhdmVyYWdlcyBmcm9tIHRoZSBvcmlnaW5hbCBjaXR5IGRhdGEgKFNjaHdhcnRhei92b2Rvbm9zKQpGb3IgZmlyc3QgcHJvamVjdGlvbnMsIHVzZSBvYnNlcnZlZCBkZWF0aHMgZnJvbSBkZWF0aCBjZXJ0aWZpY2F0ZSAoc3VtIG9mIGNvdW50aWVzIGluY2x1ZGVkIGluIFNjaHdhcnR6IGNpdHkgYm91bmRhcnkpLiBUaGVzZSBhcmUgZGlyZWN0bHkgdGllZCB0byB0b3RhbCBwb3B1bGF0aW9ucyBvZiB0aGUgY291bnRpZXMgaW5jbHVkZWQuIFVzZSB0aGUgc3VtIG9mIHBvcHVsYXRpb25zIGZyb20gY291bnRpZXMgaW5jbHVkZWQgaW4gU2Nod2FydHogY2l0eSBkZWxpbWl0YXRpb24gYXMgYmFzaXMgZm9yIFJSIHRvIGFjdHVhbCBkZWF0aHMgY29udmVyc2lvbi4gTGF0ZXIsIGFwcGx5IHRoZSBiYXNlIFJSIGFuZCBhdHRyaWJ1dGFibGUgUlIgdG8gdGhlIG92ZXJhbGwgcG9wdWxhdGlvbiBmb3IgY29zdCBjYWxjdWxhdGlvbnMuCiAKYGBge3IgIH0KZG93IDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoIm91dHB1dC92b2Rvbm9zX291dC9oaXN0b3JpY2FsLmRlYXRocy9tZWFuLmRlYXRocy5kb3cuY3N2IikpICMgRGF5IG9mIHdlZWsgbW9ydGFsaXR5IGF2ZXJhZ2UgZm9yIGxhc3QgcGVyaW9kCmdsaW1wc2UgKGRvdykKCmRveSA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJvdXRwdXQvdm9kb25vc19vdXQvaGlzdG9yaWNhbC5kZWF0aHMvbWVhbi5kZWF0aHMuZG95LmNzdiIpKSAjIERheSBvZiB5ZWFyIG1vcnRhbGl0eSBhdmVyYWdlIGZvciBsYXN0IHBlcmlvZApnbGltcHNlIChkb3kpCgojQ291bnR5IG1lYW4gdG1heCAod2VpZ2h0ZWQgYnkgbnVtYmVyIG9mIGdyaWQgcG9pbnRzIGluY2x1ZGVkIGluIGVhY2ggY291bnR5KSB3YXMgdXNlZCBmb3IgdGVtcGVyYXR1cmUgcmVsYXRpb25zaGlwLiBEbyB0aGUgc2FtZSBnb2luZyBmb3J3YXJkCnRtYXhfZmlwcyA8LSByZWFkX3hsc3goaGVyZTo6aGVyZSgib3V0cHV0L3ZvZG9ub3Nfb3V0L1Jlc3VsdHMtNS0yOC0xOS54bHN4IiksICJkYXRhLm1hdHJpeCIpCnRtYXhfZmlwcyA8LSB0bWF4X2ZpcHMgJT4lICAKICBzZWxlY3QoQ0lUWU5BTUUsIGNpdHljb2RlKSAlPiUgCiAgbXV0YXRlIChGSVBTX3R4dCA9IHN0cmluZ3I6OnN0cl9wYWQoYXMuY2hhcmFjdGVyIChjaXR5Y29kZSksIDUsICJsZWZ0IiwgIjAiKSwKICAgICAgICAgICMgRHVlIHRvIGNvdW50eSBzZWxlY3Rpb24gd2l0aGluIGNpdGllcywgc29tZSB0b3ducyBoYXZlIG5vIHZhbHVlIGluIHRoZSBvcmlnaW5hbCBjaXR5LWNsdXN0ZXItTFVUIHRhYmxlLgogICAgICAgICAgIyBUaGlzIGlzIG9ubHkgYSBwcm9ibGVtIGZvciBZb3VuZ3N0b3duLCBPSCwgd2hpY2ggaGFzIG5vIG1hdGNoaW5nIGZpcHMgY29kZS4gRHVlIHRvIGFuIGVycm9yIGluIHRoZSBkYXRhLm1hdHJpeCBsdXQgZnJvbSBTY2h3YXJ0egogICAgICAgICAgRklQU190eHQgPSBnc3ViKCIzOTAyOSIsICIzOTA5OSIsIEZJUFNfdHh0KSkgIyByZXBsYWNlIFNjaHdhcnR6IGRhdGEgbWF0cml4IGZvciB5b3VuZ3N0b3duIHdpdGggYSB5b3VuZ3N0b3duIEZJUFMKCnRtYXhfZmlwcyAgICU+JSAgIGFudGlfam9pbihjbHVzdGVyX0xVVCAsIGJ5ID0gIkZJUFNfdHh0IikKCmRveTwtIGRveSAlPiUgbGVmdF9qb2luKHRtYXhfZmlwcykgJT4lIAogIG11dGF0ZShtb250aCA9IGx1YnJpZGF0ZTo6bW9udGggKGFzLkRhdGUoZG95ICwgb3JpZ2luID0gIjIwMTUtMTItMzEiKSkgLAogICAgICAgICBkYXkgPSAgbHVicmlkYXRlOjpkYXkgKGFzLkRhdGUoZG95ICwgb3JpZ2luID0gIjIwMTUtMTItMzEiKSkgICkgJT4lCiAgbGVmdF9qb2luKGNsdXN0ZXJfTFVUWywgYygiQ2x1c3RlciIsICJGSVBTX3R4dCIpXSwgYnkgPSAiRklQU190eHQiKSAlPiUKICBzZWxlY3QgKGNsdXN0ZXIgPSBDbHVzdGVyLCBGSVBTX3R4dCwgQ0lUWU5BTUUsIGRveSwgbW9udGgsIGRheSwgdG90YWxfbW9ydCA9IHRvdC5tZWFuKSAKZG95ICU+JSBnbGltcHNlKCkKYGBgCgojIyMgTWF4aW11bSBkYWlseSB0ZW1wZXJhdHVyZSBmb3IgZnV0dXJlcyBkYXRhCgpUaGUgaW5mb3JtYXRpb24gcmVnYXJkaW5nIG11Y2ggb2YgdGhpcyBwcm9jZXNzaW5nIGlzIHN0b3JlZCBvbiBKIGRyaXZlIHVuZGVyIEo6XHByb2plY3RzXENJUkFfSW5kaWNhdG9yc1xtZXRob2RzIChvbiBBQ0UzKS4KSXQgbWF5IGJlIG1vcmUgcmVwcm9kdWNpYmxlIHRvIHB1bGwgY3VycmVudCBkYXRhIGRpcmVjdGx5IGZyb20gdGhlIFtVU0dTIHNpdGVdKGh0dHA6Ly9jaWRhLnVzZ3MuZ292L3RocmVkZHMvZG9kc0MvbG9jYV9mdXR1cmUpLCBidXQgaW5pdGlhbCB0ZXN0cyBzdWdnZXN0ZWQgdGhhdCB3b3VsZCBiZSBxdWl0ZSBzbG93LCBhbmQgdXNpbmcgdGhlc2UgcHJldmlvdWxzeSBkZXZlbG9wZWQgZGF0YXNldHMgd2lsbCBiZSBmYXN0ZXIuIAoKYGBge3J9CmNoZWNrX3RtYXggPC0gcmVhZF9jc3YoaGVyZSgiL2RhdGEvVHJpbS9DYW5FU00yL3JjcDg1L3Rhc21heC90YXNtYXhfZGF5X0NhbkVTTTJfcmNwODVfcjFpMXAxXzIwMDYwMTAxLTIwMDYxMjMxLkxPQ0FfMjAxNi0wNC0wMi4xNnRoLmNzdiIpKQpgYGAKCkNoZWNrIGZvciBhbGlnbm1lbnQgYmV0d2VlbiBjaXRpZXMgaW4gZG95IGFuZCBjaXRpZXMgaW4gdGhpcyBmaWxlLgpgYGB7cn0KY2hrX2RveSA9IGRveSAlPiUgIAogIGRwbHlyOjpzZWxlY3QoQ0lUWU5BTUUgKSAlPiUgIAogIHVuaXF1ZSAoKSAlPiUgIAogIG11dGF0ZShDSVRZTkFNRSA9IGNhc2Vmb2xkIChDSVRZTkFNRSkpCgpjaGtfY2l0eV90bWF4ID0gY2hlY2tfdG1heCAlPiUgIAogIGRwbHlyOjpzZWxlY3QoY2l0eSkgJT4lICAKICB1bmlxdWUgKCkgJT4lIAogIG11dGF0ZSAoQ0lUWU5BTUUgPSBjYXNlZm9sZChjaXR5KSkKCmNoa19kb3kgJT4lICBhbnRpX2pvaW4oY2hrX2NpdHlfdG1heCkKY2hrX2NpdHlfdG1heCAgICU+JSAgYW50aV9qb2luKGNoa19kb3kpCmBgYApQcm92aWRlbmNlIGlzIHByZXNlbnQgaW4gdG1heCB0cmltbWVkIGZpbGUsIGJ1dCBub3QgaW4gZG95LiBTYW50YSBCYXJiYXJhIGlzIGp1c3QgbWlzc2luZyBhIHNwYWNlLiAKVXBkYXRlIHNhbnRhIGJhcmJhcmEgaW4gZG95IGR1cmluZyBwcm9jZXNzaW5nLgpgYGB7cn0KZG95IDwtIGRveSAlPiUgIAogIG11dGF0ZSAoQ0lUWU5BTUUgPSBnc3ViKCJzYW50YWJhcmJhcmEiLCAic2FudGEgYmFyYmFyYSIsIENJVFlOQU1FKSkgJT4lIAogIHNlbGVjdCAoLW1vbnRoLCAtIGRheSkgIyBtb250aCBhbmQgZGF5IGNhdXNlIGxlYXAgeWVhciBwcm9ibGVtcwpkb3cgPC0gZG93ICU+JSAgCiAgbXV0YXRlIChDSVRZTkFNRSA9IGdzdWIoInNhbnRhYmFyYmFyYSIsICJzYW50YSBiYXJiYXJhIiwgQ0lUWU5BTUUpKQpgYGAKCiMjIENsdXN0ZXIgcmVzdWx0cyBmcm9tIEhhcnZhcmQgbW9kZWwtZml0dGluZyBzdGFnZQoKIyMjIERlZmluaXRpb25zIG9mIG9iamVjdCBuYW1lcwojIyMjIExhZzAgbW9kZWw6IERhaWx5IG1heGltdW0gdGVtcGVyYXR1cmUKKiBtdl8xX2NseF95MTptdl8xX2NseF95NQogICsgbWV0YS1hbmFseXRpY2FsIGZpdHMgZm9yIGxhZzAgbW9kZWwgb2YgY2x1c3RlciAneCcKKiBjcF8wX3llYXJzMTogY3BfMF95ZWFyczUgICAgCiAgKyBjcm9zLXByZWQgb3V0cHV0IGJhc2VkIG9uIG1ldGEtYW5hbHl0aWNhbCBmaXRzCioga25vdHNfMQogICsga25vdHMgZm9yIExhZzAgbW9kZWwKKiBib3VuZF8xID0gYm91bmRhcmllcyBmb3IgTGFnMCBtb2RlbCBpbiBjbHVzdGVyLgogICsgYXZlcmFnZSBtYXggYW5kIGF2ZXJhZ2UgbWluIHRtYXgwIGZvciB0aGUgY2x1c3Rlci4KICAKIyMjIyBNQTE1PSBNb3ZpbmcgQXZlcmFnZTsgbGFnMS01IG1vZGVsCiogbXZfMl9jbHhfeTE6bXZfMl9jbHhfeTUgICAKICArIG1ldGEtYW5hbHl0aWNhbCBmaXRzIGZvciBsYWcxOjUgbW9kZWwgb2YgY2x1c3RlciAneCcKKiBjcF8wNV95ZWFyczE6IGNwXzA1X3llYXJzNSAKICArIGNyb3MtcHJlZCBvdXRwdXQgYmFzZWQgb24gbWV0YS1hbmFseXRpY2FsIGZpdHMKKiBrbm90c18yPSBrbm90cyBmb3IgTUExNQogICsga25vdHMgZm9yIE1BMTUgbW9kZWwKKiBib3VuZF8yID0gYm91bmRhcmllcyBmb3IgY2x1c3Rlci4KICArIGF2ZXJhZ2UgbWF4IGFuZCBhdmVyYWdlIG1pbiBNQTE1IGZvciB0aGUgY2x1c3Rlci4KCiMjIyMgWWVhciBibG9ja3MgZm9yIGJvdGggbW9kZWxzIChhbGwgY2x1c3RlcnMpCiogeWVhcnMxID0geWVhciAxOTczLTE5ODMKKiB5ZWFyczIgPSB5ZWFyIDE5ODMtMTk5MwoqIHllYXJzMyA9IHllYXIgMTk5My0yMDAzCiogeWVhcnM0ID0geWVhciAyMDAzLTIwMTMKIAogCgojIyMgTG9hZCBhbmQgaW52ZXN0aWdhdGUgdGhlIGNvbnRlbnRzIG9mIHRoZSBzYXZlZCBSZGF0YSBmb3IgYSBjbHVzdGVyCgpGaXJzdCwgZGVmaW5lIHRoZSBzcGxpbmUgcGFyYW1ldGVycyB0aGF0IGFyZSB0aGUgc2FtZSBhY3Jvc3MgYWxsIHBsYWNlczoKYGBge3J9CmZ1biA9ICJicyIgOyBkZWdyZWUgPSAyOyAgY2VuXzEgPSAxNS42CmBgYAoKIyMjIyBDcmVhdGUgYSBmdW5jdGlvbiAoJ2NsdXN0ZXJfbG9hZCkKVGhpcyBmaW5kcyB0aGUgY2x1c3RlciByZXN1bHRzLCBhbmQgc2F2ZXMgdG8gYSBuZXN0ZWQgdGliYmxlIGZvciBmdXJ0aGVyIHVzZS4KCk9QVElPTlMgKGluIHByb2dyZXNzKTogCk9wdGlvbiAxIHB1bGxzIGluIGV2ZXJ5dGhpbmcsIGJ1dCBvbmx5IGtlZXBzIHRoZSBjb2VmZmljaWVudHMsIHZjb3YsIGJvdW5kYXJpZXMsIGFuZCBrbm90cy4KSXQgb3JnYW5pemVzIHRoZXNlIGludG8gdHdvIGxpc3QgY29sdW1ucyAoZm9yIGRhaWx5IGFuZCBtb3ZpbmcgYXZlcmFnZSBhcmd1bWVudHMpLgpgYGB7cn0KY2x1c3Rlcl9sb2FkIDwtIGZ1bmN0aW9uIChjX2NsdXN0ZXIgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRfZm9sZGVyID0gIm91dHB1dC92b2Rvbm9zX291dC8yMDE5LTA2LTEzX212Y2xfNF90aW1lLyIsIG5zaW0gPSAxMDAwKSB7CiAgI0xvYWQgdGhlIGNvbnRlbnRzIG9mIHRoZSBzYXZlZCBSZGF0YSBmb3IgYSBjbHVzdGVyCgogIHJlcXVpcmUoaGVyZSkKICBwcmludCAoY19jbHVzdGVyKQogIGNwX2ZuYW1lIDwtIGdzdWIoIlgiLCBjX2NsdXN0ZXIsIi9tdl9jbFgvbXZfY2xYL2NwLmNsdXN0ZXJYLnllYXJzNC5SZGF0YSIpCiAgY3BfZm5hbWUgPC0gaGVyZTo6aGVyZShvdXRfZm9sZGVyLCBjcF9mbmFtZSkKICBsb2FkKGNwX2ZuYW1lKQogIG12X2ZuYW1lIDwtIGdzdWIoIlgiLCBjX2NsdXN0ZXIsIi9tdl9jbFgvbXZfY2xYL212X2NsWF95NC5SZGF0YSIpCiAgbXZfZm5hbWUgPC0gaGVyZTo6aGVyZShvdXRfZm9sZGVyLCBtdl9mbmFtZSkKICBsb2FkKG12X2ZuYW1lKQogIAogIGlmIChleGlzdHMoImNwXzE1X3llYXJzNCIpKSB7Y3BfMDVfeWVhcnM0ICA8LSAgY3BfMTVfeWVhcnM0fSMgY29ycmVjdHMgYSBuYW1pbmcgaXNzdWUgaW4gc29tZSB2b2Rvbm9zIG91dHB1dAogIAogICAgICAgZGFpbHlfdG1heDBfYXJnID0gbGlzdCAoIGMoICAKICAgICAgICAgYm91bmQgPSAgbGlzdCAoYyhyYW5nZSAoY3BfMF95ZWFyczQkcHJlZHZhcikgICkpLAogICAgICAgICBrbm90cyA9IGxpc3QgKGMoa25vdHNfMSkpLAogICAgICAgICBjb2VmZiA9IGxpc3QgKGMoY3BfMF95ZWFyczQkY29lZmZpY2llbnRzKSksCiAgICAgICAgIHZhcmNvdiA9IGxpc3QgKGMoY3BfMF95ZWFyczQkdmNvdikgKSAgKSApCiAgICAgICAKICAgICAgICBtYTE1X3RtYXgwNV9hcmcgPWxpc3QgKCBjKCAgCiAgICAgICAgIGJvdW5kID0gIGxpc3QgKGMocmFuZ2UgKGNwXzA1X3llYXJzNCRwcmVkdmFyKSAgKSksCiAgICAgICAgIGtub3RzID0gbGlzdCAoYyhrbm90c18yKSksCiAgICAgICAgIGNvZWZmID0gbGlzdCAoYyhjcF8wNV95ZWFyczQkY29lZmZpY2llbnRzKSksCiAgICAgICAgIHZhcmNvdiA9IGxpc3QgKGMoY3BfMDVfeWVhcnM0JHZjb3YpICkgICkpCiAgICAgICAKICAgY2x1c3Rlcl8wX2ZpdHMgPC0gdGliYmxlIChjbHVzdGVyID0gY19jbHVzdGVyLAogICAgICAgZGFpbHlfdG1heDBfYXJnID0gZGFpbHlfdG1heDBfYXJnICApCgogICBjbHVzdGVyXzA1X2ZpdHMgPC0gdGliYmxlIChjbHVzdGVyID0gY19jbHVzdGVyLAogICAgIG1hMTVfdG1heDA1X2FyZyA9IG1hMTVfdG1heDA1X2FyZyAgKQoKICAgCiAgIGNsdXN0ZXJfeF9maXRzIDwtIGNsdXN0ZXJfMF9maXRzICU+JSAgaW5uZXJfam9pbihjbHVzdGVyXzA1X2ZpdHMpCiAgICMgY2hhbmdlIHRvIHRpYmJsZSBmb3IgcHVycnIgb3BlcmF0aW9ucyBsYXRlcgogICAgCnJldHVybiAoY2x1c3Rlcl94X2ZpdHMpCn0KYGBgCgogCiMjIyBQdWxsIGluIGFuZCBzdGFjayBhbGwgY2x1c3RlcnMgKDEtOSkKYGBge3J9CmNsdXN0ZXJfZml0cyA8LSAgc2VxKDEsOSkgICU+JSAgCiAgbWFwX2RmcihjbHVzdGVyX2xvYWQsIAogICAgICBvdXRfZm9sZGVyID0gIm91dHB1dC92b2Rvbm9zX291dC8yMDE5LTA2LTEzX212Y2xfNF90aW1lLyIpIApjbHVzdGVyX2ZpdHMgJT4lICBnbGltcHNlKCkKCmBgYAogCiMjIyBKb2luIHRvIGRheSBvZiB5ZWFyIGRlYXRocwpUaGUgcHJldmlvdXNseSBwcm9jZXNzZWQgZGF0YSBjYW4gYmUgam9pbmVkIG9uIGNpdHkgbmFtZQpgYGB7cn0KY2x1c3Rlcl9maXRzX2RveSA8LSAgZG95ICU+JSAKICBncm91cF9ieShjbHVzdGVyLCAgRklQU190eHQsIENJVFlOQU1FKSAlPiUgCiAgbmVzdCgua2V5ID0gImRveV9hdl9tb3J0IikgICU+JSAKICAjIHVuZ3JvdXAoKSAlPiUgIGdyb3VwX2J5IChjbHVzdGVyKSAlPiUgCiAgIyBuZXN0KC5rZXkgPSAiY2l0eV9kb3lfYXZfbW9ydCIpICAlPiUgCiAgbGVmdF9qb2luKGNsdXN0ZXJfZml0cykgCgpjbHVzdGVyX2ZpdHNfZG95ICU+JSAgZ2xpbXBzZSgpCmBgYAoKIAojIyMgTG9hZCBtb2RlbGVkIHRlbXBlcmF0dXJlIGRhdGEKVGhpcyBmdW5jdGlvbiAgZ2V0cyB0aGUgZnVsbCBUbWF4MCBmaWxlIGZvciBhbGwgZ3JpZGRlZCBkYXRhLCB0aGVuIHN1YnNldHMgaXQgdG8gZnJlZSB1cCBtZW1vcnkuIEl0IGFsc28gYXNzaWduZXMgdGhlIHJlZHVjZWQgZGF0YSB0byB0aGUgZ2xvYmFsIGVudmlyb25tZW50IGZvciBmdXJ0aGVyIHVzZS4gVXBkYXRlZCBmb3IgcHJlLXByb2Nlc3NlZCBieS1jaXR5IHRtYXggZGF0YS4gTm90ZSB0aGF0IHRoaXMgbWF5IG5lZWQgdG8gYmUgdXBkYXRlZCwgYnV0IGl0IGFwcGVhcnMgdG8gYmUgY29ycmVjdCBsaW5rYWdlIHRvIGNpdGllcyBhcyBzaG93biBhYm92ZSAod2l0aCBleGNlcHRpb24gb2YgJ1Byb3ZpZGVuY2UgUkknKSwgYW5kIGlzIGZyb20gMjAxNiBkb3dubG9hZCBvZiBMT0NBIGRhdGEuIE5vdCBjbGVhciB3aGV0aGVyIHRoZXJlIGhhdmUgYmVlbiB1cGRhdGVzIHNpbmNlIHRoZW4uIFRoZXNlIG1vZGVsZWQgZGF0YSB3ZXJlIHVzZWQgZm9yIHRoZSBsYXN0IG1vcnRhbGl0eSBtYW51c2NyaXB0LgoKYGBge3J9CiMgbGlzdC5maWxlcyhoZXJlKCJkYXRhL2NpcmEzLyIpKQojIGxpc3QuZmlsZXMoaGVyZSgnZGF0YScpKQoKZ2V0X3RtYXggPC0gZnVuY3Rpb24gKCBnY20gPSAiQ2FuRVNNMiIsIHJjcCA9ICJSQ1A4NSIgLCAgZHRfeXIgPSAyMDExLCBkb3lfZnJhbWUgPSBkb3ksCiAgICAgICAgICAgICAgICAgICAgICAgY2lyYV9mb2xkZXIgPWhlcmUoIi9kYXRhL1RyaW0vIiksLi4uICApCnsjIyMgVGhpcyBmdW5jdGlvbiBsb2FkcyBtb2RlbGVkIHRlbXBlcmF0dXJlIGRhdGEsIGNvbnZlcnRzIGRhdGVzIHRvIG1vbnRoL2RheSwgYW5kIGNvbnZlcnRzIGtlbHZpbiB0byBkZWdyZWVzIGMKICAjIyBVcGRhdGVkIGZvciBuZXcgaW5wdXQgZnJvbSBwcmV2aW91c2x5IHByb2Nlc3NlZCBkYXRhICh0b28gbGFyZ2UgdG8gbW92ZSB0byBDIGRyaXZlIHByb2plY3QgZm9sZGVyLCBhbmQgbm90IGluIGFwcHJvcHJpYXRlIHBsYWNlIGZvciBmaW5hbCBvdXRwdXQpCiAgIyByZXF1aXJlIChoZXJlKQogIHJlcXVpcmUgKGRwbHlyKSAjIGZvciBkYXRhIGNsZWFuaW5nCiAgcmVxdWlyZSAodGlkeXIpICMgZm9yIGRhdGEgY2xlYW5pbmcKICByZXF1aXJlIChkYXRhLnRhYmxlKSAjIGZvciBmcmVhZCBhbmQgJWxpa2UlCiAgcmVxdWlyZSAocHVycnIpICMgZm9yIG1hcF9kZnIKICB5cnMgPSBzZXEgKChkdF95ci01KSwoZHRfeXIrNSkgKQogICAKICMjIFNlbGVjdCBvdXQganVzdCB0aGUgY29ycmVjdCBmaWxlcwogIGdjbV9mb2xkZXIgPC0gIHBhc3RlKGNpcmFfZm9sZGVyLCBnY20sICIvIiwgCiAgICAgICAgICAgICAgICAgICBjYXNlZm9sZChyY3ApLCAiL3Rhc21heC8iLCBzZXAgPSAiIikKICBnY21fZmlsZXMgIDwtIGxpc3QuZmlsZXMoZ2NtX2ZvbGRlciwgZnVsbC5uYW1lcyA9ICAgVFJVRSkKICBnY21fZmlsZXMgIDwtIG1hcF9jaHIoLnggPSB5cnMsIAogICAgICAgICAgICAgICAgICAgICAgICAuZiA9IGZ1bmN0aW9uICgueCkge2djbV9maWxlc1tnY21fZmlsZXMgJWxpa2UlIHBhc3RlKC54LCAiMDEwMS0iLCAueCwgIjEyMzEiLCBzZXAgPSAiIildfSkKICAjIHByaW50KHlycykKICBmbmFtZXMgPSB0aWJibGUgKGR0X3lyID0gcmVwKGR0X3lyLCAxMSksIAogICAgICAgICAgICAgICAgICAgZ2NtID0gZ2NtLCAKICAgICAgICAgICAgICAgICAgIHJjcCA9IHJjcCwgCiAgICAgICAgICAgICAgICAgICB5ciA9IHlycykgJT4lICAKICAgIG11dGF0ZShmbmFtZSA9ICAgICAgICBnY21fZmlsZXMgKQogIAogIHRtYXhfZHRfeXIgPC0gbWFwX2RmcihmbmFtZXMkZm5hbWUsIGZyZWFkICkgCiAgCiAgdG1heF9kdF95ciA8LSB0bWF4X2R0X3lyICU+JSAgIAogICAgbXV0YXRlKENJVFlOQU1FID0gY2FzZWZvbGQoY2l0eSksCiAgICAgICAgICAgIGdjbSA9IGdjbSwgIyBtYXkgc2F2ZSBtZW1vcnkgdG8gcmVtb3ZlIHJlcGVhdGVkIGNvbHVtbiBuYW1lcywgYnV0IGluY29udmVuaWVudCAKICAgICAgICAgICAgcmNwID0gcmNwLAogICAgICAgICAgICBkdF95ciA9IGR0X3lyLAogICAgICAgICAgICB5ZWFyID0gbHVicmlkYXRlOjp5ZWFyKGFzLkRhdGUoZGF0ZSkpICwgCiAgICAgICAgICAgICNtb250aCA9IGx1YnJpZGF0ZTo6bW9udGgoYXMuRGF0ZShkYXRlKSksCiAgICAgICAgICAgICNkYXkgPSAgbHVicmlkYXRlOjpkYXkoYXMuRGF0ZShkYXRlKSksCiAgICAgICAgICAgIGRveSA9IGx1YnJpZGF0ZTo6eWRheShhcy5EYXRlKGRhdGUpKSwKICAgICAgICAgICAgdG1lYW4wID0gdGFzbWF4IC0gMjczLjE1KSAgJT4lIAogICAgZ3JvdXBfYnkoeWVhciwgY2l0eSwgQ0lUWU5BTUUpICU+JSAjZ2NtLCByY3AsIGR0X3lyLCAKICAgIG5lc3QoLmtleSA9ICJkb3lfdG1lYW4wIikgCiAgCiAgcmV0dXJuICh0bWF4X2R0X3lyKQp9CmBgYAoKCiMjIENsaW1hdGUgcHJvamVjdGlvbiBwcm9jZXNzaW5nIAoKRm9yIGVhY2ggY2xpbWF0ZSBtb2RlbCBhbmQgeWVhciBmb3Igd2hpY2ggYW4gYXZlcmFnZSBjaGFuZ2UgaW4gdGVtcGVyYXR1cmUgb2NjdXJzLCBwdWxsIGluIHRoZSBkYXRhIHdpdGggdG1heF9kYWlseS4KQ2FsY3VsYXRlIGxhZ2dlZCBtYXhpbXVtIHRlbXBlcmF0dXJlIChtb3ZpbmcgYXZlcmFnZSA1LWRheSkKSm9pbiB0byBjbHVzdGVyIGZpdHMsIGFuZCBjcmVhdGUgYSBib3VuZGVkIHZhcmlhYmxlIHRoYXQgcmVwbGFjZXMgbWF4aW11bSB0ZW1wZXJhdHVyZSBleGNlZWRpbmcgYm91bmRzIHdpdGggdGhlIHVwcGVyIGFuZCBsb3dlciBib3VuZHMgYXMgbmVlZGVkLgpVc2UgY2x1c3Rlci1zcGVjaWZpYyBzcGxpbmUgdmFsdWVzIGFuZCBjaXR5LXNwZWNpZmljIGRheSBvZiB5ZWFyIGRlYXRoIHRvIGNhbGN1YXRlIGRhaWx5IGFuZCB0bWF4IG1vcnRhbGl0eSB2YWx1ZXMuCgojIyMjIEZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSBsYWdnZWQgKDUtZHkgbW92aW5nIGF2ZXJhZ2UpCmBgYHtyfQpsYWdfY2FsYyA8LSBmdW5jdGlvbiAodG1heF8ybGFnID0gdG1heF9kYWlseSRkb3lfdG1lYW4wW1sxXV0gKSB7CmxhZ2dlZF90bWF4IDwtIHRtYXhfMmxhZyAgJT4lICAgCiAgbXV0YXRlKAogIHRtZWFuTDEgPSBpZmVsc2UgKGlzLm5hKGxhZyh0bWVhbjApKSwgdG1lYW4wLCBsYWcodG1lYW4wKSksCiAgdG1lYW5MMiA9IGlmZWxzZSAoaXMubmEobGFnKHRtZWFuMCwgMikpLCB0bWVhbjAsIGxhZyh0bWVhbjAsIDIpKSwKICB0bWVhbkwzID0gaWZlbHNlIChpcy5uYShsYWcodG1lYW4wLCAzKSksIHRtZWFuMCwgbGFnKHRtZWFuMCwgMykpLAogIHRtZWFuTDQgPSBpZmVsc2UgKGlzLm5hKGxhZyh0bWVhbjAsIDQpKSwgdG1lYW4wLCBsYWcodG1lYW4wLCA0KSksCiAgdG1lYW4xNSA9ICh0bWVhbjAgKyB0bWVhbkwxICsgdG1lYW5MMiArIHRtZWFuTDMgKyB0bWVhbkw0KSAvIDUKKSAlPiUgCiAgIHNlbGVjdCgtc3RhcnRzX3dpdGgoInRtZWFuTCIpKQpyZXR1cm4gKGxhZ2dlZF90bWF4KQogfQogCmBgYAogCiMjIyBGdW5jdGlvbiB0byBqb2luIHRvIGNsdXN0ZXIgZml0cywgYXBwbHkgYm91bmRzLCBhbmQgb3RoZXIgY2FsY3VsYXRpb25zCgpgYGB7cn0Kam9pbl9kb3lfcHJvaiA8LSBmdW5jdGlvbiAodG1heF9kYWlseSA9IHRtYXhfZGFpbHksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3BhcmFtID0gY2x1c3Rlcl9maXRzX2RveSkgewogICMgam9pbiBjbHVzdGVyIHBhcmFtYXRlcnMgdG8gdG1heCBhbmQgYXBwbHkgY2x1c3Rlci1zcGVjaWZpYyBjYWxjdWxhdGlvbnMKICAjIHNvbWUgdW5uZXN0aW5nIGZvciBjb252ZW5pZW5jZSBpbiBtZXJnZQogIAogIGNsX2RveSA8LSBjbHVzdGVyX3BhcmFtICU+JSAgCiAgICBzZWxlY3QoLWVuZHNfd2l0aCgiYXJnIikgKSAlPiUgIAogICAgdW5uZXN0KCkgIyBjbHVzdGVyX3BhcmFtCiAgCiAgZG95X3RtYXggPC0gdG1heF9kYWlseSAlPiUgICN0bWF4XzJqb2luCiAgICBzZWxlY3QoQ0lUWU5BTUUsIHllYXIsICBkb3lfdG1heCkgJT4lICAKICAgIHVubmVzdCgpICU+JSAKICAgIHJpZ2h0X2pvaW4oY2xfZG95LCBieSA9IGMoIkNJVFlOQU1FIiwgImRveSIpKSAgICU+JSAgCiAgICBncm91cF9ieShDSVRZTkFNRSwgeWVhciwgY2x1c3RlciwgRklQU190eHQpICU+JSAgCiAgICBuZXN0KC5rZXkgPSAiZGF5X3RtIikKICAKICBjbHVzdGVyX3BhcmFtIDwtIGNsdXN0ZXJfcGFyYW0gJT4lICAKICAgIHNlbGVjdCgtZG95X2F2X21vcnQpCiAgCiAgdG1heF9kYWlseSA8LSB0bWF4X2RhaWx5ICU+JSAgI1NBVkUgTUVNT1JZX19ETyBjb2x1bW4gbmFtZXMgTEFTVDogdG1heF9kYWlseSA8LSB0bWF4X2RhaWx5ICU+JSAgc2VsZWN0ICgtZ2NtLCAtcmNwLCAtZHRfeXIpIAogICAgc2VsZWN0KC1kb3lfdG1heCkgJT4lIAogICAgaW5uZXJfam9pbihkb3lfdG1heCwgCiAgICAgICAgICAgICAgIGJ5ID0gYygieWVhciIsICJDSVRZTkFNRSIpKSAgJT4lIAogICAgI1RvIHNhdmUgbWVtb3J5LCBjb25zaWRlcjogdW5ncm91cCgpICU+JSAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIG5lc3QoLmtleSA9ICJjaXR5X2RveV90bWF4KSAlPiUgIGlubmVyX2pvaW4oY2x1c3Rlcl9wYXJhbSwgYnkgPSAiY2x1c3RlciIpCiAgICBpbm5lcl9qb2luKGNsdXN0ZXJfcGFyYW0sIAogICAgICAgICAgICAgICBieSA9IGMoIkNJVFlOQU1FIiwgImNsdXN0ZXIiLCAiRklQU190eHQiKSkgIAogIAogIHJldHVybiAodG1heF9kYWlseSkKfQoKYGBgCgoKCiMjIyBDcmVhdGUgYm91bmRpbmcgZnVuY3Rpb24gdG8gdHJ1bmNhdGUgdG1heCBkaXN0cmlidXRpb24gYXQgYm91bmRzLgpgYGB7cn0KYm91bmRfdG1heCA8LSBmdW5jdGlvbih0bWF4LCBib3VuZCkgewogIGNhc2Vfd2hlbiAgKHRtYXggPCBib3VuZFsxXSB+IGJvdW5kWzFdLCMgc2V0IHRtYXguYm91bmQgdG8gTCBib3VuZAogICAgICAgICAgICAgIHRtYXggPiBib3VuZFsyXSB+ICBib3VuZFsyXSwgIyBzZXQgdG1heC5ib3VuZCB0byBVIGJvdW5kCiAgICAgICAgICAgICAgVFJVRSB+IHRtYXgpCn0KYGBgCiAgCgoKIyMjIENyZWF0ZSBmdW5jdGlvbnMgZm9yIGJ5LWNpdHkgY2FsY3VsYXRpb25zIHdpdGhpbiBhIGNsdXN0ZXIKCmRsbm06OmNyb3NzcHJlZCBwcm9kdWNlcyBqdXN0IHByZWRpY3Rpb25zIGZvciB0aGUgcmFuZ2Ugb2YgdGhlIGlucHV0IGJhc2lzLiBJdCBkb2VzIG5vdCBwcm9kdWNlIHByZWRpY3Rpb25zIGZvciBlYWNoIHJvdy4gVGhlcmVmb3JlLCBtdXN0IHJlcHJvZHVjZSB3aXRoIG9uZWJhc2lzIGFuZCByZWxhdGl2ZSByaXNrIGNhbGN1bGF0aW9uLgpNYWtlIHRoZSBiYXNpcyBmaXJzdCBmb3IgdGhlIHRlbXBlcmF0dXJlIHNlcmllcywgdGhlbiBjcmVhdGUgYSBiYXNpcyBmb3IgdGhlIGNlbnRlciBwb2ludCwgdGhlbiBzY2FsZSB0aGUgYmFzaXMgdmVjdG9yIGJ5IHRoZSBjZW50ZXJlZCBiYXNpcy4gCgojIyMjIEZ1bmN0aW9uIGZvciByZWxhdGl2ZSByaXNrIGNhbGN1bGF0aW9uCmBgYHtyfQoKcnJfY2FsYyA8LSBmdW5jdGlvbiAoIHRtYXggPSBjKDEwLCAyMCwgMzApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZWxpbmVfcHJvamVjdGVkX21vcnQgPSBjKDEwLDE1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWZfbWF0ID0gY3BfMF95ZWFyczQkY29lZmZpY2llbnRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJfdmFsID0gY2VuXzEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWdyZWVfdmFsID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga25vdF92ZWMgPSBrbm90c18xLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm91bmRfdmVjID0gYm91bmRfMSApewogICMjIFRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyByZWxhdGl2ZSByaXNrIGZyb20gYW4gdW5jZW50ZXJlZCBiYXNpcyBtYXRyaXggYW5kIGZpdHRlZCBjb2VmZmljaWVudHMKICAjIEN1cnJlbnRseSBpbXBsZW1lbnRlZCBmb3IgRUFDSCB0bWF4IHZhbHVlLiAKcmVxdWlyZSggZGxubSkgOyByZXF1aXJlIChzcGxpbmVzKQpic19jZSAgPC0gYnMoY2VudGVyX3ZhbCwgICBkZWdyZWUgPSBkZWdyZWVfdmFsLCAga25vdHMgPSBrbm90X3ZlYywgQm91bmQ9Ym91bmRfdmVjLCBpbnRlcmNlcHQgPSBGQUxTRSkKYnNfdmFyIDwtIHN1cHByZXNzV2FybmluZ3MoYnModG1heCwgICAgZGVncmVlID0gZGVncmVlX3ZhbCwgIGtub3RzID0ga25vdF92ZWMsIEJvdW5kPWJvdW5kX3ZlYywgaW50ZXJjZXB0ID0gRkFMU0UgKSApICMgc3VwcHJlc3MgcmVwZXRldGl2ZSB3YXJuaW5nIHJlZ2FyZGluZyB0ZW1wZXJhdHVyZXMgb3V0c2lkZSBvZiBvcmlnaW5hbCBib3VuZGFyaWVzCmJzX3ZjICAgPC0gc2NhbGUoYnNfdmFyLCBjZW50ZXIgPSBic19jZSwgIHNjYWxlID0gRkFMU0UpCgpSUl90ZW1wIDwtIGFzLm51bWVyaWMgKCgxLWV4cCgtYnNfdmMgJSolIGNvZWZfbWF0KSApICkKCiNhdHRyX2RlYXRoX24gPC0gIFJSX3RlbXAgKiBiYXNlbGluZV9wcm9qZWN0ZWRfbW9ydApyZXR1cm4gKCAgUlJfdGVtcCAgICkKfQoKYGBgCgoKCiMjIyBGdW5jdGlvbiB0byBsb29wIHRocm91Z2ggdGhlIHByb2plY3RlZCB0ZW1wZXJhdHVyZXMsIGFwcGx5IGNsdXN0ZXIgY29lZmZpY2llbnRzLCBhbmQgY2FsY3VsYXRlIHJlbGF0aXZlIHJpc2sgKG5vIENJIHlldCkuCgpgYGB7cn0gCgpwcm9qZWN0X3NwbGluZSA8LSBmdW5jdGlvbiAoZGZyYW1lID0gIHRtYXhfZGFpbHkgWzEsXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbiAgPSAxNS42LCBkZWcgPSAyKSB7CiBkYXlfdG0gPC0gZGZyYW1lJGRheV90bVtbMV1dCiBwYXJhbV90MCA8LSBkZnJhbWUkZGFpbHlfdG1heDBfYXJnW1sxXV0gIyB3YXMgY3BfMF95ZWFyczQgaW4gb3JpZ2luYWwgc2NoZW1lCiBwYXJhbV9tYTE1IDwtIGRmcmFtZSRtYTE1X3RtYXgwNV9hcmdbWzFdXSAjIHdhcyBjcF8wNV95ZWFyczQgaW4gb3JpZ2luYWwgc2NoZW1lCiAjLCBmdW4gPSAiYnMiIGZvciBycl9jYWxjCiBkYXlfdG0gPC0gZGF5X3RtICU+JSAKICAgbXV0YXRlICh5ZWFyID0gZGZyYW1lJHllYXIsICBjaXR5ID0gZGZyYW1lJGNpdHksIAogICAgICAgICAgICNDSVRZTkFNRSA9IGRmcmFtZSRDSVRZTkFNRSwgIGNsdXN0ZXIgPSBkZnJhbWUkQ0lUWU5BTUUsICBGSVBTX3R4dCA9IGRmcmFtZSRGSVBTX3R4dCwgCiAgICAgICAgICAgIyBoYWNreSBzb2x1dGlvbiwgYnV0IHB1cnJyIG5vdCBtdXRhdGluZyBlYXNpbHkgb24gbmVzdGVkIHRpYmJsZSwgYW5kIG5vdCBjbGVhciBob3cgdG8gcmVzb2x2ZQogICAgICAgICAgIHRtZWFuMF9ib3VuZCA9IGJvdW5kX3RtYXgodG1lYW4wLCBwYXJhbV90MCRib3VuZCksCiAgICAgICAgICAgdG1lYW4xNV9ib3VuZCA9IGJvdW5kX3RtYXgodG1lYW4xNSwgcGFyYW1fbWExNSRib3VuZCkgICwKICAgICAgICAgICBycl90bWVhbjAgPSBycl9jYWxjICggdG1lYW4wLCAgCiAgICAgICAgICAgICAgICAgYmFzZWxpbmVfcHJvamVjdGVkX21vcnQgPSB0b3RhbF9tb3J0LCAKICAgICAgICAgICAgICAgICBjb2VmX21hdCA9IHBhcmFtX3QwJGNvZWZmLAogICAgICAgICAgICAgICAgIGNlbnRlcl92YWwgPSBjZW4sIAogICAgICAgICAgICAgICAgIGRlZ3JlZV92YWwgPSBkZWcsCiAgICAgICAgICAgICAgICAga25vdF92ZWMgPSBwYXJhbV90MCRrbm90cyAsIAogICAgICAgICAgICAgICAgIGJvdW5kX3ZlYyA9IHBhcmFtX3QwJGJvdW5kKSwKICAgICAgICAgICBycl90bWVhbjE1ID0gIHJyX2NhbGMgKCB0bWVhbjE1LCAgCiAgICAgICAgICAgICAgICAgYmFzZWxpbmVfcHJvamVjdGVkX21vcnQgPSB0b3RhbF9tb3J0LCAKICAgICAgICAgICAgICAgICBjb2VmX21hdCA9IHBhcmFtX21hMTUkY29lZmYsCiAgICAgICAgICAgICAgICAgY2VudGVyX3ZhbCA9IGNlbiwgCiAgICAgICAgICAgICAgICAgZGVncmVlX3ZhbCA9IGRlZywKICAgICAgICAgICAgICAgICBrbm90X3ZlYyA9IHBhcmFtX21hMTUka25vdHMsIAogICAgICAgICAgICAgICAgIGJvdW5kX3ZlYyA9IHBhcmFtX21hMTUkYm91bmQpLAogICAgICAgICAgIHJyX3RtZWFuMF9ibmQgPSBycl9jYWxjICggdG1lYW4wX2JvdW5kLCAgCiAgICAgICAgICAgICAgICAgYmFzZWxpbmVfcHJvamVjdGVkX21vcnQgPSB0b3RhbF9tb3J0LCAKICAgICAgICAgICAgICAgICBjb2VmX21hdCA9IHBhcmFtX3QwJGNvZWZmLAogICAgICAgICAgICAgICAgIGNlbnRlcl92YWwgPSBjZW4sIAogICAgICAgICAgICAgICAgIGRlZ3JlZV92YWwgPSBkZWcsCiAgICAgICAgICAgICAgICAga25vdF92ZWMgPSBwYXJhbV90MCRrbm90cyAsIAogICAgICAgICAgICAgICAgIGJvdW5kX3ZlYyA9IHBhcmFtX3QwJGJvdW5kICkgICAsCiAgICAgICAgICAgcnJfdG1lYW4xNV9ibmQgPSBycl9jYWxjICggdG1lYW4xNV9ib3VuZCwgIAogICAgICAgICAgICAgICAgIGJhc2VsaW5lX3Byb2plY3RlZF9tb3J0ID0gdG90YWxfbW9ydCwgCiAgICAgICAgICAgICAgICAgY29lZl9tYXQgPSBwYXJhbV9tYTE1JGNvZWZmLAogICAgICAgICAgICAgICAgIGNlbnRlcl92YWwgPSBjZW4sIAogICAgICAgICAgICAgICAgIGRlZ3JlZV92YWwgPSBkZWcsCiAgICAgICAgICAgICAgICAga25vdF92ZWMgPSBwYXJhbV9tYTE1JGtub3RzLCAKICAgICAgICAgICAgICAgICBib3VuZF92ZWMgPSBwYXJhbV9tYTE1JGJvdW5kKSAgICwgCiAgICAgICAgICAgYW5fdG1lYW4wID0gcnJfdG1lYW4wICogdG90YWxfbW9ydCwKICAgICAgICAgICBhbl90bWVhbjE1PSBycl90bWVhbjE1ICogdG90YWxfbW9ydCwKICAgICAgICAgICBhbl90bWVhbjBfYm5kPSBycl90bWVhbjBfYm5kICogdG90YWxfbW9ydCwKICAgICAgICAgICBhbl90bWVhbjE1X2JuZD0gcnJfdG1lYW4xNV9ibmQgKiB0b3RhbF9tb3J0ICkgJT4lIAogICBzZWxlY3QgKHllYXIsIGNpdHksIGV2ZXJ5dGhpbmcoKSkgIywgQ0lUWU5BTUUsIGNsdXN0ZXIsIEZJUFNfdHh0CiAgcmV0dXJuIChkYXlfdG0pCn0KCmBgYAoKCiAKICAKCiMjIyBUYWJ1bGF0ZQoKRG8gdHdvIHdheXMuIEZvciBjaXRpZXMsIGFnZ3JlZ2F0ZSBBTiBvdmVyIGZ1bGwgMTEgeWVhciBwZXJpb2QgYnkgZGF5IG9mIHllYXIuIEdldCBhIG1lYW4gQU4gZm9yIGVhY2ggZGF5IGZvciBlYWNoIGNpdHkgaW4gdGhlIDExIHllYXIgcGVyaW9kLiAgRm9yIGNsdXN0ZXJzLCBmaXJzdCBhZ2dyZWdhdGUgYnkgeWVhciB0byBnZXQgdG90YWwgaW5jcmVhc2UgaW4gZGVhdGggZWFjaCB5ZWFyLgoKU3VtbWFyaXphdGlvbiBmdW5jdGlvbnMgZm9yIHVzZSBpbiBvdGhlciBmdW5jdGlvbnMuIFRoZXNlIGZ1bmN0aW9ucyBjdXJyZW50bHkgZG8gbm90IHdlaWdodCB2YWx1ZXMuCgpgYGB7cn0KCnN1bW1hcmlzZV90ZW1wX2MgPC0gZnVuY3Rpb24oZGZyYW1lICwgLi4uKSAKICB7ICMgYWxsbG93cyBkaWZmZXJlbnQgZ3JvdXBpbmcgdmFyaWFibGVzIGRlZmluZWQgYXMgdmFyaWFibGUgbGVuZ3RoIGFyZ3VtZW50cyAgLi4uICAKICAgCiAgZ3JvdXBfdmFyIDwtIGVucXVvcyguLi4pCiAgcHJpbnQoZ3JvdXBfdmFyKQogIAogICAgICBkZnJhbWUgPC0gZGZyYW1lICU+JSAKICAgICAgICBncm91cF9ieSghISEgZ3JvdXBfdmFyKSAlPiUgIyEhISBncm91cF92YXIKICAgICAgICBzdW1tYXJpc2UobWVhbl9kYWlseV9jID0gbWVhbiAodG1lYW4wKSwKICAgICAgICAgICAgIHNkX2RhaWx5X2MgPSBzZCh0bWVhbjApLAogICAgICAgICAgICAgbWF4X2RhaWx5X2MgPSBtYXgodG1lYW4wKSwKICAgICAgICAgICAgIG1pbl9kYWlseV9jID0gbWluKHRtZWFuMCksCiAgICAgICAgICAgICBtZWFuX21hMTVfYyA9IG1lYW4odG1lYW4xNSksCiAgICAgICAgICAgICBzZF9tYTE1X2MgPSAgc2QodG1lYW4xNSksCiAgICAgICAgICAgICBtYXhfbWExNV9jID0gbWF4KHRtZWFuMTUpLAogICAgICAgICAgICAgbWluX21hMTVfYyA9IG1pbih0bWVhbjE1KSkKICAgICAgcmV0dXJuIChkZnJhbWUpCn0KIApgYGAKCmBgYHtyfQpzdW1tYXJpc2VfbWVhbl9yciA8LSBmdW5jdGlvbihkZnJhbWUgPSBwcm9qX3JyX2RhaWx5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnJfdmFycyA9IGMocnJfdG1lYW4wID0gInJyX3RtZWFuMCIsIHJyX3RtZWFuMTUgPSAicnJfdG1lYW4xNSIsIHJyX3RtZWFuMF9ibmQ9ICJycl90bWVhbjBfYm5kIiwgcnJfdG1lYW4xNV9ibmQgPSAicnJfdG1lYW4xNV9ibmQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLikgCiAgeyAjIGFsbGxvd3MgZGlmZmVyZW50IGdyb3VwaW5nIHZhcmlhYmxlcyBkZWZpbmVkIGFzIHZhcmlhYmxlIGxlbmd0aCBhcmd1bWVudHMgIC4uLiAgCiAgICAgIGdyb3VwX3ZhciA8LSBlbnF1b3MoLi4uKQogICAgICAKICAgICAgIGRmcmFtZSA8LSBkZnJhbWUgJT4lIHJlbmFtZSAoISEhcnJfdmFycykKICAgICAgIAogICAgICBpZihhbnkoIWdyZXBsKCJ0b3RhbCIsIHJyX3ZhcnMpKSApICB7ZGZyYW1lIDwtIGRmcmFtZSAgJT4lIHJlbmFtZSAoISEhcnJfdmFycykgICU+JQogICAgICAgICBtdXRhdGUocnJfdG90YWwgPSBycl90bWVhbjAgKyBycl90bWVhbjE1LAogICAgICAgICAgICAgICAgcnJfdG90YWxfYm5kID0gcnJfdG1lYW4wX2JuZCArIHJyX3RtZWFuMTVfYm5kKQogICAgICAgIH0KIAogICAgICAgIGRmcmFtZSA8LSBkZnJhbWUgJT4lCiAgICAgICAgZ3JvdXBfYnkoISEhIGdyb3VwX3ZhcikgJT4lCiAgICAgICAgc3VtbWFyaXNlKAogICAgICAgICAgbWVhbl9ycl90b3RhbCA9IG1lYW4ocnJfdG90YWwpLAogICAgICAgICAgc2RfcnJfdG90YWwgPSBzZChycl90b3RhbCksCiAgICAgICAgICBtZWFuX3JyX3RvdGFsX2JuZCA9IG1lYW4ocnJfdG90YWxfYm5kKSwKICAgICAgICAgIHNkX3JyX3RvdGFsX2JuZCA9IHNkKHJyX3RvdGFsX2JuZCkKICAgICAgICAgICkKICAgICAgCiAgICAgIHJldHVybiAoZGZyYW1lKQp9CmBgYAoKYGBge3J9CnN1bW1hcmlzZV9tZWFuX2FuIDwtIGZ1bmN0aW9uKGRmcmFtZSAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuX3ZhcnMgPSBjKGFuX3RtZWFuMCA9ICJhbl90bWVhbjAiLCBhbl90bWVhbjE1ID0iYW5fdG1lYW4xNSIsIGFuX3RtZWFuMF9ibmQgPSAiYW5fdG1lYW4wX2JuZCIsIGFuX3RtZWFuMTVfYm5kID0iYW5fdG1lYW4xNV9ibmQiKSAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4pIAogIHsgIyBhbGxsb3dzIGRpZmZlcmVudCBncm91cGluZyB2YXJpYWJsZXMgZGVmaW5lZCBhcyB2YXJpYWJsZSBsZW5ndGggYXJndW1lbnRzICAuLi4gIAogICAgICBncm91cF92YXIgPC0gZW5xdW9zKC4uLikKICAgICAgCiAgICAgIGRmcmFtZSA8LSBkZnJhbWUgJT4lIHJlbmFtZSAoISEhYW5fdmFycykgJT4lbXV0YXRlKCkKICAgICAgIAogICAgICBpZihhbnkoIWdyZXBsKCJ0b3RhbCIsIGFuX3ZhcnMpKSApICB7ZGZyYW1lIDwtIGRmcmFtZSAgJT4lIHJlbmFtZSAoISEhYW5fdmFycykgICU+JQogICAgICAgICBtdXRhdGUoYW5fdG90YWwgPSBhbl90bWVhbjAgICsgYW5fdG1lYW4xNSwKICAgICAgICAgICAgICAgYW5fdG90YWxfYm5kID0gYW5fdG1lYW4wX2JuZCAgKyBhbl90bWVhbjE1X2JuZCkKICAgICAgICB9CiAgCiAgICAgICAgICAKICAgICAgZGZyYW1lIDwtIGRmcmFtZSAlPiUgCiAgICAgICAgZ3JvdXBfYnkoISEhIGdyb3VwX3ZhcikgJT4lCiAgICAgICAgICAgICBzdW1tYXJpc2UoYmFzZWxpbmVfcHJval9tb3J0ID0gbWVhbiAodG90YWxfbW9ydCksICMgdXNlIG1lYW4gdG8gZXh0cmFjdCBvcmlnaW5hbCBwcm9qZWN0ZWQgYmFzZWxpbmUgYWdhaW4KICAgICAgICAgICAgICAgICAgICAgICBtZWFuX2FuX3RvdGFsID0gbWVhbihhbl90b3RhbCksCiAgICAgICAgICAgICAgICAgICAgICAgc2RfYW5fdG90YWwgPSBzZChhbl90b3RhbCksCiAgICAgICAgICAgICAgICAgICAgICAgbWVhbl9hbl90b3RhbF9ibmQgPSBtZWFuKGFuX3RvdGFsX2JuZCksCiAgICAgICAgICAgICAgICAgICAgICAgc2RfYW5fdG90YWxfYm5kID0gc2QoYW5fdG90YWxfYm5kKSkgfQpgYGAKCmBgYHtyfQpzdW1tYXJpc2Vfc3VtX2FuIDwtIGZ1bmN0aW9uKGRmcmFtZSAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuX3ZhcnMgPSBjKHRvdGFsX21vcnQgPSB0b3RhbF9tb3J0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbl90bWVhbjAgPSAiYW5fdG1lYW4wIiwgYW5fdG1lYW4xNSA9ImFuX3RtZWFuMTUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbl90bWVhbjBfYm5kID0gImFuX3RtZWFuMF9ibmQiLCBhbl90bWVhbjE1X2JuZCA9ImFuX3RtZWFuMTVfYm5kIikgLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKSAKICB7ICMgYWxsbG93cyBkaWZmZXJlbnQgZ3JvdXBpbmcgdmFyaWFibGVzIGRlZmluZWQgYXMgdmFyaWFibGUgbGVuZ3RoIGFyZ3VtZW50cyAgLi4uICAKICAgICAgZ3JvdXBfdmFyIDwtIGVucXVvcyguLi4pCiAgICAgIGRmcmFtZSA8LSBkZnJhbWUgJT4lIHJlbmFtZSAoISEhYW5fdmFycykKICAgICAgIAogICAgICBpZihhbnkoIWdyZXBsKCJhbl90b3RhbCIsIGFuX3ZhcnMpKSApICB7ZGZyYW1lIDwtIGRmcmFtZSAgJT4lIHJlbmFtZSAoISEhYW5fdmFycykgICU+JQogICAgICAgICBtdXRhdGUoYW5fdG90YWwgPSBhbl90bWVhbjAgICsgYW5fdG1lYW4xNSwKICAgICAgICAgICAgICAgYW5fdG90YWxfYm5kID0gYW5fdG1lYW4wX2JuZCAgKyBhbl90bWVhbjE1X2JuZCkKICAgICAgICB9CiAgCiAgICAgICAgICAKICAgICAgZGZyYW1lIDwtIGRmcmFtZSAlPiUgCiAgICAgICAgZ3JvdXBfYnkoISEhIGdyb3VwX3ZhcikgJT4lCiAgICAgICAgICAgICBzdW1tYXJpc2UoYmFzZWxpbmVfcHJval9tb3J0ID0gc3VtKHRvdGFsX21vcnQpLCAKICAgICAgICAgICAgICAgICAgICAgICBzdW1fYW5fdG90YWwgPSBzdW0oYW5fdG90YWwpLAogICAgICAgICAgICAgICAgICAgICAgIHN1bV9hbl90b3RhbF9ibmQgPSBzdW0oYW5fdG90YWxfYm5kKSApIH0KYGBgCgpUYWJ1bGF0ZSBieSBjaXR5IGFuZCBkYXkgb2YgeWVhciBvdmVyIHRoZSB3aG9sZSBwZXJpb2QuClRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyB0aGUgbWVhbiBudW1iZXIgb2YgYXR0cmlidXRhYmxlIGRlYXRocyBvdmVyIHRoZSAxMSB5ZWFyIHBlcmlvZCBmb3IgYSBwYXJ0aWN1bGFyIGNpdHkgYW5kIGNsaW1hdGUgbW9kZWwuCgpUYWJ1bGF0ZSBjbHVzdGVyIGRheSBvZiB5ZWFyIGF0dHJpYnV0YWJsZSBkZWF0aHMuIFRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyBhIHN1bSBBTiBvZiBhbGwgY2l0aWVzIGluIGEgY2x1c3RlciBmb3IgZWFjaCB5ZWFyIG9mIHRoZSAxMSB5ZWFyIHBlcmlvZCBmb3IgYSBnY20uIApUaGUgbWVhbiBhbmQgc2QgdGVtcGVyYXR1cmVzIGFyZSBjdXJyZW50bHkgdW53ZWlnaHRlZC4gCgoKVGFidWxhdGUgY2x1c3RlciBwZXJpb2QgYXR0cmlidXRhYmxlIGRlYXRocy4gClRoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyBhbiBhdmVyYWdlIEFOIGZvciB0aGUgd2hvbGUgcGVyaW9kLCB1c2luZyB0aGUgcHJldmlvdXNseSBjYWxjdWxhdGVkIHRvdGFsIEFOIG9mIGFsbCBjaXRpZXMgaW4gYSBjbHVzdGVyIGZvciBlYWNoIHllYXIgb2YgdGhlIDExIHllYXIgcGVyaW9kIGZvciBhIGdjbS4KVGhlIG1lYW4gdGVtcGVyYXR1cmVzIGFyZSBub3QgY3VycmVudGx5IHBvcHVsYXRpb24gb3IgYXJlYSB3ZWlnaHRlZC4KCiAKCgojIyMgUGxvdHRpbmcgZnVuY3Rpb25zIAoKCgoKCiMjIFJ1biBmb3IgYWxsICBkVAoKYGBge3J9CmRUX2Z1bmMgPC0gZnVuY3Rpb24gKGdjbV9zZWwgPSJDQ1NNNCIgLAogICAgICAgICAgZFRfY19zZWwgPSAxLAogICAgICAgICAgcmNwX3NlbCA9ICJSQ1A4NSIgICwKICAgICAgICAgIGR0X3lyX3NlbCA9IDIwMTEsICAKICAgICAgICAgIGNpcmFfZm9sZGVyID0gaGVyZSgiL2RhdGEvVHJpbS8iKSwKICAgICAgICAgIG91dHB1dF9mb2xkZXIgPSAgaGVyZTo6aGVyZSAoIm91dHB1dCIsIGZvcm1hdChTeXMuRGF0ZSgpLCAiJUYiKSkgCiAgICAgICAgICApIHsKICBwcmludCAoZ2NtX3NlbCkgOyBwcmludCAoZFRfY19zZWwpIDsgcHJpbnQocmNwX3NlbCk7IHByaW50KGR0X3lyX3NlbCkKICAjIGdldCBkYXRhCiAgdGljKG1zZyA9ICJnZXRfdG1heCIpCiAgIHRtYXhfZGFpbHkgPC0gZ2V0X3RtYXggKGNpcmFfZm9sZGVyID0gY2lyYV9mb2xkZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2NtID0gZ2NtX3NlbCAsIHJjcCA9ICByY3Bfc2VsICwgIGR0X3lyID0gIGR0X3lyX3NlbCAgKQogIHRvYygpCgogICAjIExhZyBjYWxjICAgCnRpYyhtc2cgPSAiY2FsY3VsYXRlIGxhZ2dlZCB0bWF4IikKdG1heF9kYWlseSA8LSB0bWF4X2RhaWx5ICU+JSAKICBtdXRhdGUoZFRfYyA9IGRUX2Nfc2VsICwKICAgICAgICAgZG95X3RtYXggPSBtYXAodG1heF9kYWlseSRkb3lfdG1lYW4wLCBsYWdfY2FsYykpICU+JSAKICBzZWxlY3QgKC1kb3lfdG1lYW4wKQp0b2MoKQoKI2pvaW4gdG8gY2x1c3RlciBmaXRzLCBhcHBseSBib3VuZHMsIGFuZCBvdGhlciBjYWxjdWxhdGlvbnMKdGljKG1zZyA9ICJqb2luX2RveV9wcm9qIikKdG1heF9kYWlseSA8LSBqb2luX2RveV9wcm9qICAodG1heF9kYWlseSA9IHRtYXhfZGFpbHkgLCBjbHVzdGVyX3BhcmFtID0gY2x1c3Rlcl9maXRzX2RveSkgCnRvYygpCgp0aWMobXNnID0gImRheV90bSBvcGVyYXRpb24iKQojIyBhZGQgcHJvamVjdGVkIG1vcnRhbGl0eSBhbmQgUlIgdG8gdG1heF9kYWlseSAgKHRyb3VibGUgd2l0aCBsaXN0IHBvc2l0aW9uIG1lYW5zIHRoaXMgbWF5IGJlIG1vcmUgY29tcGxpY2F0ZWQgdGhhbiBuZWVkZWQpCnRtYXhfZGFpbHkkZGF5X3RtIDwtIHRtYXhfZGFpbHkgJT4lICAgIAogIHVuZ3JvdXAgKCkgJT4lIAogIGdyb3VwX3NwbGl0KCBjaXR5LCAgeWVhciApICAlPiUgI0NJVFlOQU1FLCBjbHVzdGVyLCBGSVBTX3R4dCwgCiAgbWFwX2RmciAoIC5mID0gcHJvamVjdF9zcGxpbmUsIGNlbiAgPSAxNS42LCBkZWcgPSAyKSAgJT4lCiAgZ3JvdXBfYnkoY2l0eSwgIHllYXIpICU+JSAjQ0lUWU5BTUUsIGNsdXN0ZXIsIEZJUFNfdHh0LAogIG5lc3QoLmtleSA9ICJkYXlfdG0iKSAlPiUgIAogIHB1bGwoZGF5X3RtICApCnRvYygpCiAgCnJldHVybih0bWF4X2RhaWx5KQp9CmBgYAoKIyMgSXRlcmF0ZSB0aHJvdWdoIGFsbCBkVCBmb3IgZWFjaCBHQ00uCmBgYHtyfQoKIyMgR2V0IEdDTSBsaXN0IGZvciBkdCB0byBydW4gKG1pbnVzIGJhc2VsaW5lKQpnY21fZHRfbHV0X3Byb2ogPC0gZ2NtX2R0X2x1dCAlPiUgIAogIG11dGF0ZSAoZ2NtID0gZ3N1YigiXyIsICItIiwgZ2NtKSApICAlPiUgCiAgZmlsdGVyIChnY20gIT0gImJhc2VsaW5lIikgICU+JSAgIyByZW1vdmUgYXMgaXMgc3RvcmVkIGVsc2V3aGVyZQogIG11dGF0ZSAocmNwID0gIlJDUDg1IikgIAoKICBvdXRwdXRfZm9sZGVyX3BhdGggPC0gaGVyZTo6aGVyZSgib3V0cHV0IiwgZm9ybWF0KFN5cy5EYXRlKCksICIlRiIpICkKIGlmKCFkaXIuZXhpc3RzKG91dHB1dF9mb2xkZXJfcGF0aCkpIHtkaXIuY3JlYXRlKG91dHB1dF9mb2xkZXJfcGF0aCwgcmVjdXJzaXZlID0gVFJVRSl9CgoKICAgIApjb21waWxlZF9jaXR5X21lYW5fb3V0IDwtIHBtYXBfZGZyICAgKC5sID0gbGlzdCAoZ2NtX2R0X2x1dF9wcm9qJGdjbSAgICwgIGdjbV9kdF9sdXRfcHJvaiRkVCAgICwgZ2NtX2R0X2x1dF9wcm9qJHJjcCAgICwgZ2NtX2R0X2x1dF9wcm9qJGR0X3llYXIgICkgLCAKICAgICAgICAgICAgICAgIC5mID0gZFRfZnVuYywgCiAgICAgICAgICAgICAgICBjaXJhX2ZvbGRlciA9aGVyZSgiL2RhdGEvVHJpbS8iKSwKICAgICAgICAgICAgICAgIG91dHB1dF9mb2xkZXIgPSAgb3V0cHV0X2ZvbGRlcl9wYXRoICkgIApzYXZlKGNvbXBpbGVkX2NpdHlfbWVhbl9vdXQsIGZpbGUgPSBmaWxlLnBhdGgob3V0cHV0X2ZvbGRlcl9wYXRoLCAiY29tcGlsZWRfY2l0eS5SZGF0YSIpICkKCgpkVGNfY29tcGlsZWRfZ2NtX2NpdHkgPC0gY29tcGlsZWRfY2l0eV9tZWFuX291dCAlPiUgCiAgc2VsZWN0KGNsdXN0ZXIsIGNpdHksICBDSVRZTkFNRSwgRklQU190eHQsIGRUX2MsIHllYXIsIGRheV90bSkgICU+JSAKICB1bm5lc3QoKQoKZFRjX2NvbXBpbGVkX2djbV9jaXR5JT4lIHdyaXRlX2V4Y2VsX2NzdihwYXRoID0gZmlsZS5wYXRoKG91dHB1dF9mb2xkZXJfcGF0aCwgImNvbXBpbGVkX2NpdHkuY3N2IikpCgpgYGAKCiMjIyBTdW1tYXJpemUgZnVsbHkgc3RhY2tlZCBkYXRhIApBdmVyYWdlIG92ZXIgaW5jbHVkZWQgR0NNCmBgYHtyfQptZWFuX2NfZHRfY2l0eV9kb3kgPC0gZFRjX2NvbXBpbGVkX2djbV9jaXR5ICU+JSAKICBzdW1tYXJpc2VfdGVtcF9jKCAgY2x1c3RlciwgY2l0eSwgIENJVFlOQU1FLCBGSVBTX3R4dCwgZFRfYywgZG95KQoKbWVhbl9ycl9kdF9jaXR5X2RveSA8LSBkVGNfY29tcGlsZWRfZ2NtX2NpdHkgJT4lIHN1bW1hcmlzZV9tZWFuX3JyKHJyX3ZhcnMgPSBjKHJyX3RtZWFuMCA9ICJycl90bWVhbjAiLCBycl90bWVhbjE1ID0gInJyX3RtZWFuMTUiLCBycl90bWVhbjBfYm5kPSAicnJfdG1lYW4wX2JuZCIsIHJyX3RtZWFuMTVfYm5kID0gInJyX3RtZWFuMTVfYm5kIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlciwgY2l0eSwgIENJVFlOQU1FLCBGSVBTX3R4dCwgZFRfYywgZG95KQoKbWVhbl9hbl9kdF9jaXR5X2RveSA8LSBkVGNfY29tcGlsZWRfZ2NtX2NpdHkgJT4lIHN1bW1hcmlzZV9tZWFuX2FuKCBhbl92YXJzID0gYyhhbl90bWVhbjAgPSAiYW5fdG1lYW4wIiwgYW5fdG1lYW4xNSA9ImFuX3RtZWFuMTUiLCBhbl90bWVhbjBfYm5kID0gImFuX3RtZWFuMF9ibmQiLCBhbl90bWVhbjE1X2JuZCA9ImFuX3RtZWFuMTVfYm5kIikgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyLCBjaXR5LCAgQ0lUWU5BTUUsIEZJUFNfdHh0LCBkVF9jLCBkb3kpCgpjaXR5X3RhYl9kb3kgPC0gbWVhbl9jX2R0X2NpdHlfZG95ICU+JSBpbm5lcl9qb2luKG1lYW5fcnJfZHRfY2l0eV9kb3kpICAgJT4lIAogIGlubmVyX2pvaW4obWVhbl9hbl9kdF9jaXR5X2RveSkgCgpjaXR5X3RhYl9kb3klPiUgaGVhZCgpCmBgYAoKYGBge3J9CiAgI0NhbGN1bGF0ZSB0aGUgbWVhbiBzdW0gb2YgYXR0cmlidXRhYmxlIGRlYXRocyBmb3IgYSB5ZWFyIGluIHRoZSAxMSB5ZWFyIHBlcmlvZCBmb3IgYSBwYXJ0aWN1bGFyIGNpdHkgYW5kIGNsaW1hdGUgbW9kZWwuCiAgdGljKG1zZyA9ICJTdW1tYXJpemUgQU4sIGdyb3VwZWQgYnkgZFQsIGNsdXN0ZXIgYW5kIGNpdHkiKQogIAogIHN1bV9hbl9kdF9jaXR5ICA8LSBzdW1tYXJpc2Vfc3VtX2FuKGRUY19jb21waWxlZF9nY21fY2l0eSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5fdmFycyA9IGModG90YWxfbW9ydCA9ICJ0b3RhbF9tb3J0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5fdG1lYW4wID0gImFuX3RtZWFuMCIsIGFuX3RtZWFuMTUgPSJhbl90bWVhbjE1IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5fdG1lYW4wX2JuZCA9ICJhbl90bWVhbjBfYm5kIiwgYW5fdG1lYW4xNV9ibmQgPSJhbl90bWVhbjE1X2JuZCIpICwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlciwgY2l0eSwgIENJVFlOQU1FLCBGSVBTX3R4dCwgZFRfYywgeWVhciwgZ2NtKSAgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIGdyb3VwX2J5KGNsdXN0ZXIsIGNpdHksICBDSVRZTkFNRSwgRklQU190eHQsIGRUX2MpICU+JSAKICAgIHN1bW1hcmlzZShiYXNlbGluZV9wcm9qX21vcnQgPSBtZWFuKGJhc2VsaW5lX3Byb2pfbW9ydCkgLCBzdW1fYW5fdG90YWw9IG1lYW4oc3VtX2FuX3RvdGFsKSwgc3VtX2FuX3RvdGFsX2JuZD1tZWFuKHN1bV9hbl90b3RhbF9ibmQpKQogCiAgc3VtX2FuX2R0X2NpdHlfZm5hbWUgPC0gZmlsZS5wYXRoKG91dHB1dF9mb2xkZXJfcGF0aCwgcGFzdGUoZm9ybWF0KFN5cy5EYXRlKCksICIlRl8iKSwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjaXR5X2RUX0FOX3N1bW1hcnkuY3N2Iiwgc2VwID0gIiIpICkKICB3cml0ZV9jc3Yoc3VtX2FuX2R0X2NpdHksIHBhdGggPSBzdW1fYW5fZHRfY2l0eV9mbmFtZSkKICB0b2MoKQogIAogIGhlYWQoc3VtX2FuX2R0X2NpdHkpCmBgYAoKIAojIyMgTW9ydGFsaXR5CkZvciBub3RlcyBvbiB0aGUgYmFzZWxpbmUgZGF0YSwgc2VlIHRoZSByZWFkbWUgZm9yIHRoZSBbYmFzZWxpbmUgbW9ydGFsaXR5IHVzZWQgaW4gdGVtcGVyYXR1cmUgbW9ydGJpZGl0eV0oIFxcYm91ZmlsZTAxLmNvcnAuYWJ0YXNzb2MuY29tXGRhdGExXENvbW1vblxFTlJcUHJvamVjdFxDbGltZWNvbjRcVE9fMTZfQ0lSQTNcVGFzazJfVGVtcE1vcmJpZFxNb2RlbC1kYXRhXExPQ0FfaGFkX0NvdW50eV9PdXRwdXRcQmFzZWxpbmUtMTk4Ni0yMDA1XFJFQURNRV9CYXNlbGluZS50eHQpClByZXZpb3VzIG1vcnRhbGl0eSBiYXNlbGluZXMgZm9yIG90aGVyIChDbGltZWNvbiA0IFRhc2sgMDA0KSBtb3J0YWxpdHkgd29yayByZWxpZWQgb24gY2FsY3VsYXRpb25zIGZyb20gQkVOIE1hcC4gCgo+IEluZm9ybWF0aW9uIGRldmVsb3BlZCBieSBOZWFsIEZhbm4gbyBmIFUuUy4gRVBBIHRha2luZyBzaGFwZSBmaWxlIG9mIHRoZSBjaXRpdGllcyBhbmQgCQo+IHVzaW5nIGl0IHRvIGV4cG9ydCBiYXNlbGluZSBtb3J0YWxpdHkgaW5mb3JtYXRhaW9uIGZvciB0aGUgMjA5IFVTIGNpdGllcyBjb3ZlcmQgaW4gdGhhdCBhbmFseXNpcy4JCj4gU3Vic2V0IG9mIHRoZXNlIGNpdGllcyB3ZXJlIGFkZHJlc3NlZCBpbiB0aGUgb3JpZ2luYWwgTWVkaW5hLVJhbW9uIGFuZCBTY2h3YXJ0eiBwYXBlci4gCQoJCj4gU291cmNlIGZpbGUgc2F2ZWQgaW5kZXBlbmRlbnRseSBhcyAJCj4gXFxib3VmaWxlMDFcZGF0YTFcQ29tbW9uXEVOUlxQcm9qZWN0XENsaW1lY29uNFxUT184X0NJUkEyXFRlbXAtbW9ydGFsaXR5XEJhc2VsaW5lLW1vcnRhbGl0eS1yYXRlc1xCRU5NQVAtYmFzZWxpbmVfbW9ydGFsaXR5X3dfY2l0eS54bHN4CQoKPiBvcmlnaW5hbCBlbWFpbCB3aXRoIGZpbGVzIHNlbnQgdG8gZC4gTWlsbHMgb24gNy8yLzE0IGZyb20gTmVhbCBGYW5uIAo+IGluIEhlYXQtUG9wcyBlbWFpbCBkaXJlY3Rvcnk6IFBvcHVsYXRpb24taGVhbHRoLWJhc2VsaW5lLWRhdGEgZm9sZGVyCj4gYHIgdHVmdGU6OnF1b3RlX2Zvb3RlcignLS0tIERhdmUgTWlsbHMgaW4gUHJvamVjdC9DbGltZWNvbjQvQ09PTElUMTNfUmlza0NvbW0vTW9ydGFsaXR5L01vcnRhbGl0eS10ZW1wLWNhbGNzLUV4Y2VsLVFBUUMtMjAxNi0wOC0wOC54bHN4JylgCgogCiMjIFNlc3Npb24gSW5mbyAKYGBge3Igc2Vzc2lvbkluZm99CnNlc3Npb25JbmZvKCkgI2RldnRvb2xzOjpzZXNzaW9uX2luZm8oKQpgYGAKCiAK