Alright we have got our final concentration driven results!!

Whenever possible we used all of the avaiable temperature data and the avaiable future heat flux data. However when future heat flux data was unavaiable we used the cmip range for the heat flux as a an aproximation for heat flux. This notebook walks through our results.

# Load required packages. 
library(tidyr)
library(dplyr)
library(ggplot2)
library(knitr)
library(kableExtra)
library(ggrepel)
library(hectorcal)
library(GGally)
# Set up the directories. 
PROJECT_DIR <- "/Users/dorh012/Documents/2019/hectorcal"
INPUT_DIR   <- file.path(PROJECT_DIR, 'analysis', 'best_fit')
OUTPUT_DIR  <- file.path(PROJECT_DIR, 'analysis', 'best_fit', 'final_conc')
# Import the parameter data frame.
list.files(OUTPUT_DIR, pattern = '.rds', full.names = TRUE) %>%
    lapply(function(input){
        object <- readRDS(input)
        if(!is.null(object) & object$optim_rslt$convergence == 0 ){
            cbind(model = gsub('conc_|.rds', '', basename(input)),
                  data.frame(matrix(object$optim_rslt$par, nrow = 1, dimnames = list(NULL, names(object$optim_rslt$par))),
                             stringsAsFactors = FALSE),
                  min = object$optim_rslt$value) %>%
                mutate(method = if_else('comparison_plot_range' %in% names(object), 'heatflux range', 'model heatflux'))
        }
    }) %>%
    bind_rows() ->
    best_fit_params
# Save a list of all the rds files 
rds_list <- list.files(OUTPUT_DIR, pattern = '.rds', full.names = TRUE)
my_param_v_param_plot <- function(data, x, y){
    
    xmid <- 0.5*(min(data[[x]]) + max(data[[x]]))
    xrng <- 1.5*(max(data[[x]]) - min(data[[x]]))
    xlo <- xmid - 0.5*xrng
    xhi <- xmid + 0.5*xrng
    
    ggplot(data = data) +
        geom_label(aes(x = data[[x]], y = data[[y]], label = model, color = method)) +
       # geom_point(aes(x = data[[x]], y = data[[y]],  color = method)) + 
       # geom_text_repel(aes(x = data[[x]], y = data[[y]], label = model)) + 
        ggplot2::xlim(c(xlo,xhi)) + 
        labs(x = x, 
             y = y) + 
        theme_bw(base_size = 14)
}

Overview of the Runs

How many best fits convereged?

nrow(best_fit_params)
[1] 30

How many best fits converged for the two different methods?

best_fit_params %>%
    group_by(method) %>%
    summarise('model count' = n()) %>%  
     kable(digits = 2)  %>%
    kable_styling(full_width = F) 
method model count
heatflux range 11
model heatflux 19

Well I think that is pretty neat that more of our fits use their own heat flux data than the range


Parameters

Summary table of the parameters and dot plots.

best_fit_params %>%
    gather(param, value, S, diff, alpha, volscl) %>%
    select(param, method, value) %>%
    group_by(method, param) %>%
    summarise(min = min(value),
              max = max(value),
              mean = mean(value)) %>%
    arrange(param, method) %>%
    ungroup %>%
    select(param, method, min, max, mean) %>%
    kable(digits = 2)  %>%
    kable_styling(full_width = F) %>%
    column_spec(1, bold = T) %>%
    collapse_rows(columns = 1:2, valign = "top")
param method min max mean
alpha heatflux range 0.46 2.18 1.57
model heatflux 0.13 2.41 1.35
diff heatflux range 2.74 18.34 7.14
model heatflux 1.00 9.29 4.66
S heatflux range 2.59 5.58 4.03
model heatflux 2.36 7.41 3.85
volscl heatflux range 0.48 2.00 1.35
model heatflux -0.38 1.84 0.94


ggplot(data = best_fit_params) + 
    geom_dotplot(aes(x = S, fill = method), stackgroups = TRUE, binpositions = "all") + 
    theme_bw()

ggplot(data = best_fit_params) + 
    geom_dotplot(aes(x = diff, fill = method), stackgroups = TRUE, binpositions = "all") + 
    theme_bw()

ggplot(data = best_fit_params) + 
    geom_dotplot(aes(x = alpha, fill = method), stackgroups = TRUE, binpositions = "all") + 
    theme_bw()

ggplot(data = best_fit_params) + 
    geom_dotplot(aes(x = volscl, fill = method), stackgroups = TRUE, binpositions = "all") + 
    theme_bw()

What I take a way from this is that there is no obvious pattern in the parameter values with respect to the best fit method we used. Which is great, it means that the range method is not bad in a sense that it provides too little or too much information that the methodology is skeewing the best fits some how.


Param vs Param Plots

ggpairs(best_fit_params[ , c('S', 'diff', 'alpha', 'volscl')])

Looks like there are some outliers for \(S\) and \(\kappa\).


If we look at the full range of the the S and diff paramter values, notice that MIROC and CISRO-MK3L-1-2 are outliers. I wonder why that is the case, could it be related to the comparison data that was used?

my_param_v_param_plot(data = best_fit_params, x = 'S', y = 'diff')

When we exclude the outlier models we get a better picture of a relationship between S and diff. Excluding MPI-ESM-MR and EC-EARTH we see a negative correlation between \(\kappa\) and \(S\).

What is up with the models that are outliers?

What scenarios are they using? Are they missing data? Is it telling us something about the model?

CSIRO-Mk3L-1-2 has high \(\diff\) but otherwise reasonable S.

object <- readRDS(rds_list[grepl(pattern = 'CSIRO-Mk3L-1-2', x = rds_list)])
object$comparison_plot

object$comparison_plot_range

Well it looks like CSIRO-Mk3L-1-2 has comparison data for historical and future temperature. Hector underestimates the ESM temperature but alos it looks like the the temperature is ESM temp is pretty warm in 2000. The hector heat fux falls on the upper end of the rcp45 cmip heat flux range. May be the high \(\kappa\) is required to warm Hector that rapidly between 1950 to 2050.


MIROC-ESM has high S but otherwise reasonable \(\kappa\).

object <- readRDS(rds_list[grepl(pattern = 'MIROC-ESM.rds', x = rds_list)])
object$comparison_plot

Once again it looks like the ESM is has a higher temp at 2000 than I was expecting.


MIROC-ESM-CHEM has high S but otherwise reasonable \(\kappa\).

object <- readRDS(rds_list[grepl(pattern = 'MIROC-ESM-CHEM', x = rds_list)])
object$comparison_plot

Also looks pretty warm in 2000.


So I thought that if I looked at a comparison of the temperature from 1950 - 2000 vs S I might be able to see a pattern or something.

cmip_individual %>% 
    filter(model %in% best_fit_params$model & variable == 'tas') %>% 
    rename(temp = value) %>% 
    left_join(best_fit_params, by = 'model') %>% 
    filter(year %in% 1950:2005) %>%
    group_by(model, S, diff) %>% 
    summarise(temp = mean(temp)) %>% 
    ungroup %>%
    mutate(outlier = if_else(model %in% c('MIROC-ESM-CHEM', 'MIROC-ESM', 'CSIRO-Mk3L-1-2'), TRUE, FALSE)) %>% 
    ggplot(aes(temp, S, label = model, color = outlier)) + 
    geom_label() + 
    theme_bw() + 
    labs(x = 'mean temp from 1950 - 2005 in deg C')

NA

But it looks like our models with abnormal S and \(\kappa\) values (blue print) fall withtin in the middle of the temperature range. So that is still puzzeling anyways I degress if we exclude these outliers what does our \(S\) vs \(\kappa\) plot look like now?


my_param_v_param_plot(data = best_fit_params, x = 'S', y = 'diff') + 
    coord_cartesian(xlim = c(2, 6), 
                    ylim = c(0, 10))


my_param_v_param_plot(data = best_fit_params, x = 'volscl', y = 'S') + 
    coord_cartesian(ylim = c(2, 6))

Once again I have excluded the larger S values to make patterns more obvious. I wonder what the models with the negative volscl fits look like. What does the output data look like for the models that have negative values for \(volscl\) .

object <- readRDS(rds_list[grepl(pattern = 'CMCC-CM.rds', x = rds_list)])
object$comparison_plot

object <- readRDS(rds_list[grepl(pattern = 'CMCC-CMS', x = rds_list)])
object$comparison_plot

Nothing obvious jumps out at me.

Concluding Thoughts

LS0tCnRpdGxlOiAiRmluYWwgQ29uY2VudHJhdGlvbiBCZXN0IEZpdCBSZXN1bHRzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKY29kZV9mb2xkaW5nOiAiaGlkZSIKLS0tCgpBbHJpZ2h0IHdlIGhhdmUgZ290IG91ciBmaW5hbCBjb25jZW50cmF0aW9uIGRyaXZlbiByZXN1bHRzISEgCgpXaGVuZXZlciBwb3NzaWJsZSB3ZSB1c2VkIGFsbCBvZiB0aGUgYXZhaWFibGUgdGVtcGVyYXR1cmUgZGF0YSBhbmQgdGhlIGF2YWlhYmxlIGZ1dHVyZSBoZWF0IGZsdXggZGF0YS4gSG93ZXZlciB3aGVuIGZ1dHVyZSBoZWF0IGZsdXggZGF0YSB3YXMgdW5hdmFpYWJsZSB3ZSB1c2VkIHRoZSBjbWlwIHJhbmdlIGZvciB0aGUgaGVhdCBmbHV4IGFzIGEgYW4gYXByb3hpbWF0aW9uIGZvciBoZWF0IGZsdXguIFRoaXMgbm90ZWJvb2sgd2Fsa3MgdGhyb3VnaCBvdXIgcmVzdWx0cy4gCgoKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQojIExvYWQgcmVxdWlyZWQgcGFja2FnZXMuIApsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGhlY3RvcmNhbCkKbGlicmFyeShHR2FsbHkpCgojIFNldCB1cCB0aGUgZGlyZWN0b3JpZXMuIApQUk9KRUNUX0RJUiA8LSAiL1VzZXJzL2RvcmgwMTIvRG9jdW1lbnRzLzIwMTkvaGVjdG9yY2FsIgpJTlBVVF9ESVIgICA8LSBmaWxlLnBhdGgoUFJPSkVDVF9ESVIsICdhbmFseXNpcycsICdiZXN0X2ZpdCcpCk9VVFBVVF9ESVIgIDwtIGZpbGUucGF0aChQUk9KRUNUX0RJUiwgJ2FuYWx5c2lzJywgJ2Jlc3RfZml0JywgJ2ZpbmFsX2NvbmMnKQoKIyBJbXBvcnQgdGhlIHBhcmFtZXRlciBkYXRhIGZyYW1lLgpsaXN0LmZpbGVzKE9VVFBVVF9ESVIsIHBhdHRlcm4gPSAnLnJkcycsIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUKICAgIGxhcHBseShmdW5jdGlvbihpbnB1dCl7CgogICAgICAgIG9iamVjdCA8LSByZWFkUkRTKGlucHV0KQoKICAgICAgICBpZighaXMubnVsbChvYmplY3QpICYgb2JqZWN0JG9wdGltX3JzbHQkY29udmVyZ2VuY2UgPT0gMCApewoKICAgICAgICAgICAgY2JpbmQobW9kZWwgPSBnc3ViKCdjb25jX3wucmRzJywgJycsIGJhc2VuYW1lKGlucHV0KSksCiAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUobWF0cml4KG9iamVjdCRvcHRpbV9yc2x0JHBhciwgbnJvdyA9IDEsIGRpbW5hbWVzID0gbGlzdChOVUxMLCBuYW1lcyhvYmplY3Qkb3B0aW1fcnNsdCRwYXIpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSwKICAgICAgICAgICAgICAgICAgbWluID0gb2JqZWN0JG9wdGltX3JzbHQkdmFsdWUpICU+JQogICAgICAgICAgICAgICAgbXV0YXRlKG1ldGhvZCA9IGlmX2Vsc2UoJ2NvbXBhcmlzb25fcGxvdF9yYW5nZScgJWluJSBuYW1lcyhvYmplY3QpLCAnaGVhdGZsdXggcmFuZ2UnLCAnbW9kZWwgaGVhdGZsdXgnKSkKCiAgICAgICAgfQoKICAgIH0pICU+JQogICAgYmluZF9yb3dzKCkgLT4KICAgIGJlc3RfZml0X3BhcmFtcwoKIyBTYXZlIGEgbGlzdCBvZiBhbGwgdGhlIHJkcyBmaWxlcyAKcmRzX2xpc3QgPC0gbGlzdC5maWxlcyhPVVRQVVRfRElSLCBwYXR0ZXJuID0gJy5yZHMnLCBmdWxsLm5hbWVzID0gVFJVRSkKCm15X3BhcmFtX3ZfcGFyYW1fcGxvdCA8LSBmdW5jdGlvbihkYXRhLCB4LCB5KXsKICAgIAogICAgeG1pZCA8LSAwLjUqKG1pbihkYXRhW1t4XV0pICsgbWF4KGRhdGFbW3hdXSkpCiAgICB4cm5nIDwtIDEuNSoobWF4KGRhdGFbW3hdXSkgLSBtaW4oZGF0YVtbeF1dKSkKICAgIHhsbyA8LSB4bWlkIC0gMC41KnhybmcKICAgIHhoaSA8LSB4bWlkICsgMC41KnhybmcKICAgIAogICAgZ2dwbG90KGRhdGEgPSBkYXRhKSArCiAgICAgICAgZ2VvbV9sYWJlbChhZXMoeCA9IGRhdGFbW3hdXSwgeSA9IGRhdGFbW3ldXSwgbGFiZWwgPSBtb2RlbCwgY29sb3IgPSBtZXRob2QpKSArCiAgICAgICAjIGdlb21fcG9pbnQoYWVzKHggPSBkYXRhW1t4XV0sIHkgPSBkYXRhW1t5XV0sICBjb2xvciA9IG1ldGhvZCkpICsgCiAgICAgICAjIGdlb21fdGV4dF9yZXBlbChhZXMoeCA9IGRhdGFbW3hdXSwgeSA9IGRhdGFbW3ldXSwgbGFiZWwgPSBtb2RlbCkpICsgCiAgICAgICAgZ2dwbG90Mjo6eGxpbShjKHhsbyx4aGkpKSArIAogICAgICAgIGxhYnMoeCA9IHgsIAogICAgICAgICAgICAgeSA9IHkpICsgCiAgICAgICAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpCn0KCgoKYGBgCgoKIyMgT3ZlcnZpZXcgb2YgdGhlIFJ1bnMgCgpIb3cgbWFueSBiZXN0IGZpdHMgY29udmVyZWdlZD8gCmBgYHtyfQpucm93KGJlc3RfZml0X3BhcmFtcykKYGBgCgoKSG93IG1hbnkgYmVzdCBmaXRzIGNvbnZlcmdlZCBmb3IgdGhlIHR3byBkaWZmZXJlbnQgbWV0aG9kcz8gCmBgYHtyfQpiZXN0X2ZpdF9wYXJhbXMgJT4lCiAgICBncm91cF9ieShtZXRob2QpICU+JQogICAgc3VtbWFyaXNlKCdtb2RlbCBjb3VudCcgPSBuKCkpICU+JSAgCiAgICAga2FibGUoZGlnaXRzID0gMikgICU+JQogICAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRikgCmBgYAoKV2VsbCBJIHRoaW5rIHRoYXQgaXMgcHJldHR5IG5lYXQgdGhhdCBtb3JlIG9mIG91ciBmaXRzIHVzZSB0aGVpciBvd24gaGVhdCBmbHV4IGRhdGEgdGhhbiB0aGUgcmFuZ2UKCioqKioqCgoKIyMgUGFyYW1ldGVycyAKCgojIyMgU3VtbWFyeSB0YWJsZSBvZiB0aGUgcGFyYW1ldGVycyBhbmQgZG90IHBsb3RzLiAKCmBgYHtyfQpiZXN0X2ZpdF9wYXJhbXMgJT4lCiAgICBnYXRoZXIocGFyYW0sIHZhbHVlLCBTLCBkaWZmLCBhbHBoYSwgdm9sc2NsKSAlPiUKICAgIHNlbGVjdChwYXJhbSwgbWV0aG9kLCB2YWx1ZSkgJT4lCiAgICBncm91cF9ieShtZXRob2QsIHBhcmFtKSAlPiUKICAgIHN1bW1hcmlzZShtaW4gPSBtaW4odmFsdWUpLAogICAgICAgICAgICAgIG1heCA9IG1heCh2YWx1ZSksCiAgICAgICAgICAgICAgbWVhbiA9IG1lYW4odmFsdWUpKSAlPiUKICAgIGFycmFuZ2UocGFyYW0sIG1ldGhvZCkgJT4lCiAgICB1bmdyb3VwICU+JQogICAgc2VsZWN0KHBhcmFtLCBtZXRob2QsIG1pbiwgbWF4LCBtZWFuKSAlPiUKICAgIGthYmxlKGRpZ2l0cyA9IDIpICAlPiUKICAgIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYpICU+JQogICAgY29sdW1uX3NwZWMoMSwgYm9sZCA9IFQpICU+JQogICAgY29sbGFwc2Vfcm93cyhjb2x1bW5zID0gMToyLCB2YWxpZ24gPSAidG9wIikKYGBgCgo8YnI+CgoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGJlc3RfZml0X3BhcmFtcykgKyAKICAgIGdlb21fZG90cGxvdChhZXMoeCA9IFMsIGZpbGwgPSBtZXRob2QpLCBzdGFja2dyb3VwcyA9IFRSVUUsIGJpbnBvc2l0aW9ucyA9ICJhbGwiKSArIAogICAgdGhlbWVfYncoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGJlc3RfZml0X3BhcmFtcykgKyAKICAgIGdlb21fZG90cGxvdChhZXMoeCA9IGRpZmYsIGZpbGwgPSBtZXRob2QpLCBzdGFja2dyb3VwcyA9IFRSVUUsIGJpbnBvc2l0aW9ucyA9ICJhbGwiKSArIAogICAgdGhlbWVfYncoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGJlc3RfZml0X3BhcmFtcykgKyAKICAgIGdlb21fZG90cGxvdChhZXMoeCA9IGFscGhhLCBmaWxsID0gbWV0aG9kKSwgc3RhY2tncm91cHMgPSBUUlVFLCBiaW5wb3NpdGlvbnMgPSAiYWxsIikgKyAKICAgIHRoZW1lX2J3KCkKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBiZXN0X2ZpdF9wYXJhbXMpICsgCiAgICBnZW9tX2RvdHBsb3QoYWVzKHggPSB2b2xzY2wsIGZpbGwgPSBtZXRob2QpLCBzdGFja2dyb3VwcyA9IFRSVUUsIGJpbnBvc2l0aW9ucyA9ICJhbGwiKSArIAogICAgdGhlbWVfYncoKQpgYGAKCgpXaGF0IEkgdGFrZSBhIHdheSBmcm9tIHRoaXMgaXMgdGhhdCB0aGVyZSBpcyBubyBvYnZpb3VzIHBhdHRlcm4gaW4gdGhlIHBhcmFtZXRlciB2YWx1ZXMgd2l0aCByZXNwZWN0IHRvIHRoZSBiZXN0IGZpdCBtZXRob2Qgd2UgdXNlZC4gV2hpY2ggaXMgZ3JlYXQsIGl0IG1lYW5zIHRoYXQgdGhlIHJhbmdlIG1ldGhvZCBpcyBub3QgYmFkIGluIGEgc2Vuc2UgdGhhdCBpdCBwcm92aWRlcyB0b28gbGl0dGxlIG9yIHRvbyBtdWNoIGluZm9ybWF0aW9uIHRoYXQgdGhlIG1ldGhvZG9sb2d5IGlzIHNrZWV3aW5nIHRoZSBiZXN0IGZpdHMgc29tZSBob3cuIAoKCgo8YnI+CgojIyMgUGFyYW0gdnMgUGFyYW0gUGxvdHMKCmBgYHtyfQoKZ2dwYWlycyhiZXN0X2ZpdF9wYXJhbXNbICwgYygnUycsICdkaWZmJywgJ2FscGhhJywgJ3ZvbHNjbCcpXSkKYGBgCgpMb29rcyBsaWtlIHRoZXJlIGFyZSBzb21lIG91dGxpZXJzIGZvciAkUyQgYW5kICRca2FwcGEkLiAKCjxicj4KCklmIHdlIGxvb2sgYXQgdGhlIGZ1bGwgcmFuZ2Ugb2YgdGhlIHRoZSBTIGFuZCBkaWZmIHBhcmFtdGVyIHZhbHVlcywgbm90aWNlIHRoYXQgTUlST0MgYW5kIENJU1JPLU1LM0wtMS0yIGFyZSBvdXRsaWVycy4gSSB3b25kZXIgd2h5IHRoYXQgaXMgdGhlIGNhc2UsIGNvdWxkIGl0IGJlIHJlbGF0ZWQgdG8gdGhlIGNvbXBhcmlzb24gZGF0YSB0aGF0IHdhcyB1c2VkPyAKCmBgYHtyfQoKbXlfcGFyYW1fdl9wYXJhbV9wbG90KGRhdGEgPSBiZXN0X2ZpdF9wYXJhbXMsIHggPSAnUycsIHkgPSAnZGlmZicpCgpgYGAKCldoZW4gd2UgZXhjbHVkZSB0aGUgb3V0bGllciBtb2RlbHMgd2UgZ2V0IGEgYmV0dGVyIHBpY3R1cmUgb2YgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBTIGFuZCBkaWZmLiBFeGNsdWRpbmcgTVBJLUVTTS1NUiBhbmQgRUMtRUFSVEggd2Ugc2VlIGEgbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiAkXGthcHBhJCBhbmQgJFMkLgoKIyMjIFdoYXQgaXMgdXAgd2l0aCB0aGUgbW9kZWxzIHRoYXQgYXJlIG91dGxpZXJzPyAKCldoYXQgc2NlbmFyaW9zIGFyZSB0aGV5IHVzaW5nPyBBcmUgdGhleSBtaXNzaW5nIGRhdGE/IElzIGl0IHRlbGxpbmcgdXMgc29tZXRoaW5nIGFib3V0IHRoZSBtb2RlbD8gCgpgQ1NJUk8tTWszTC0xLTJgIGhhcyBoaWdoICRcZGlmZiQgYnV0IG90aGVyd2lzZSByZWFzb25hYmxlIFMuIAoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0Kb2JqZWN0IDwtIHJlYWRSRFMocmRzX2xpc3RbZ3JlcGwocGF0dGVybiA9ICdDU0lSTy1NazNMLTEtMicsIHggPSByZHNfbGlzdCldKQoKb2JqZWN0JGNvbXBhcmlzb25fcGxvdApvYmplY3QkY29tcGFyaXNvbl9wbG90X3JhbmdlCmBgYAoKCldlbGwgaXQgbG9va3MgbGlrZSBDU0lSTy1NazNMLTEtMiBoYXMgY29tcGFyaXNvbiBkYXRhIGZvciBoaXN0b3JpY2FsIGFuZCBmdXR1cmUgdGVtcGVyYXR1cmUuIEhlY3RvciB1bmRlcmVzdGltYXRlcyB0aGUgRVNNIHRlbXBlcmF0dXJlIGJ1dCBhbG9zIGl0IGxvb2tzIGxpa2UgdGhlIHRoZSB0ZW1wZXJhdHVyZSBpcyBFU00gdGVtcCBpcyBwcmV0dHkgd2FybSBpbiAyMDAwLiBUaGUgaGVjdG9yIGhlYXQgZnV4IGZhbGxzIG9uIHRoZSB1cHBlciBlbmQgb2YgdGhlIHJjcDQ1IGNtaXAgaGVhdCBmbHV4IHJhbmdlLiBNYXkgYmUgdGhlIGhpZ2ggJFxrYXBwYSQgaXMgcmVxdWlyZWQgdG8gd2FybSBIZWN0b3IgdGhhdCByYXBpZGx5IGJldHdlZW4gMTk1MCB0byAyMDUwLgoKPGJyPgoKCmBNSVJPQy1FU01gIGhhcyBoaWdoIFMgYnV0IG90aGVyd2lzZSByZWFzb25hYmxlICRca2FwcGEkLiAKCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9Cm9iamVjdCA8LSByZWFkUkRTKHJkc19saXN0W2dyZXBsKHBhdHRlcm4gPSAnTUlST0MtRVNNLnJkcycsIHggPSByZHNfbGlzdCldKQoKb2JqZWN0JGNvbXBhcmlzb25fcGxvdApgYGAKCk9uY2UgYWdhaW4gaXQgbG9va3MgbGlrZSB0aGUgRVNNIGlzIGhhcyBhIGhpZ2hlciB0ZW1wIGF0IDIwMDAgdGhhbiBJIHdhcyBleHBlY3RpbmcuIAoKPGJyPgoKCmBNSVJPQy1FU00tQ0hFTWAgaGFzIGhpZ2ggUyBidXQgb3RoZXJ3aXNlIHJlYXNvbmFibGUgJFxrYXBwYSQuIAoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0Kb2JqZWN0IDwtIHJlYWRSRFMocmRzX2xpc3RbZ3JlcGwocGF0dGVybiA9ICdNSVJPQy1FU00tQ0hFTScsIHggPSByZHNfbGlzdCldKQoKb2JqZWN0JGNvbXBhcmlzb25fcGxvdApgYGAKCgpBbHNvIGxvb2tzIHByZXR0eSB3YXJtIGluIDIwMDAuIAoKPGJyPgogCiBTbyBJIHRob3VnaHQgdGhhdCBpZiBJIGxvb2tlZCBhdCBhIGNvbXBhcmlzb24gb2YgdGhlIHRlbXBlcmF0dXJlIGZyb20gMTk1MCAtIDIwMDAgdnMgUyBJIG1pZ2h0IGJlIGFibGUgdG8gc2VlIGEgcGF0dGVybiBvciBzb21ldGhpbmcuIAogCmBgYHtyfQpjbWlwX2luZGl2aWR1YWwgJT4lIAogICAgZmlsdGVyKG1vZGVsICVpbiUgYmVzdF9maXRfcGFyYW1zJG1vZGVsICYgdmFyaWFibGUgPT0gJ3RhcycpICU+JSAKICAgIHJlbmFtZSh0ZW1wID0gdmFsdWUpICU+JSAKICAgIGxlZnRfam9pbihiZXN0X2ZpdF9wYXJhbXMsIGJ5ID0gJ21vZGVsJykgJT4lIAogICAgZmlsdGVyKHllYXIgJWluJSAxOTUwOjIwMDUpICU+JQogICAgZ3JvdXBfYnkobW9kZWwsIFMsIGRpZmYpICU+JSAKICAgIHN1bW1hcmlzZSh0ZW1wID0gbWVhbih0ZW1wKSkgJT4lIAogICAgdW5ncm91cCAlPiUKICAgIG11dGF0ZShvdXRsaWVyID0gaWZfZWxzZShtb2RlbCAlaW4lIGMoJ01JUk9DLUVTTS1DSEVNJywgJ01JUk9DLUVTTScsICdDU0lSTy1NazNMLTEtMicpLCBUUlVFLCBGQUxTRSkpICU+JSAKICAgIGdncGxvdChhZXModGVtcCwgUywgbGFiZWwgPSBtb2RlbCwgY29sb3IgPSBvdXRsaWVyKSkgKyAKICAgIGdlb21fbGFiZWwoKSArIAogICAgdGhlbWVfYncoKSArIAogICAgbGFicyh4ID0gJ21lYW4gdGVtcCBmcm9tIDE5NTAgLSAyMDA1IGluIGRlZyBDJykKIApgYGAKIAogQnV0IGl0IGxvb2tzIGxpa2Ugb3VyIG1vZGVscyB3aXRoIGFibm9ybWFsIFMgYW5kICRca2FwcGEkIHZhbHVlcyAoYmx1ZSBwcmludCkgZmFsbCB3aXRodGluIGluIHRoZSBtaWRkbGUgb2YgdGhlIHRlbXBlcmF0dXJlIHJhbmdlLiBTbyB0aGF0IGlzIHN0aWxsIHB1enplbGluZyBhbnl3YXlzIEkgZGVncmVzcyBpZiB3ZSBleGNsdWRlIHRoZXNlIG91dGxpZXJzIHdoYXQgZG9lcyBvdXIgJFMkIHZzICRca2FwcGEkIHBsb3QgbG9vayBsaWtlIG5vdz8gCiAKIAo8YnI+CiAKIApgYGB7cn0KbXlfcGFyYW1fdl9wYXJhbV9wbG90KGRhdGEgPSBiZXN0X2ZpdF9wYXJhbXMsIHggPSAnUycsIHkgPSAnZGlmZicpICsgCiAgICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMiwgNiksIAogICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIDEwKSkKCmBgYAoKPGJyPgoKYGBge3J9Cm15X3BhcmFtX3ZfcGFyYW1fcGxvdChkYXRhID0gYmVzdF9maXRfcGFyYW1zLCB4ID0gJ3ZvbHNjbCcsIHkgPSAnUycpICsgCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMiwgNikpCmBgYAoKT25jZSBhZ2FpbiBJIGhhdmUgZXhjbHVkZWQgdGhlIGxhcmdlciBTIHZhbHVlcyB0byBtYWtlIHBhdHRlcm5zIG1vcmUgb2J2aW91cy4gSSB3b25kZXIgd2hhdCB0aGUgbW9kZWxzIHdpdGggdGhlIG5lZ2F0aXZlIHZvbHNjbCBmaXRzIGxvb2sgbGlrZS4gV2hhdCBkb2VzIHRoZSBvdXRwdXQgZGF0YSBsb29rIGxpa2UgZm9yIHRoZSBtb2RlbHMgdGhhdCBoYXZlIG5lZ2F0aXZlIHZhbHVlcyBmb3IgJHZvbHNjbCQgLgoKCgpgYGB7cn0Kb2JqZWN0IDwtIHJlYWRSRFMocmRzX2xpc3RbZ3JlcGwocGF0dGVybiA9ICdDTUNDLUNNLnJkcycsIHggPSByZHNfbGlzdCldKQpvYmplY3QkY29tcGFyaXNvbl9wbG90Cm9iamVjdCA8LSByZWFkUkRTKHJkc19saXN0W2dyZXBsKHBhdHRlcm4gPSAnQ01DQy1DTVMnLCB4ID0gcmRzX2xpc3QpXSkKb2JqZWN0JGNvbXBhcmlzb25fcGxvdApgYGAKCk5vdGhpbmcgb2J2aW91cyBqdW1wcyBvdXQgYXQgbWUuIAoKCiMjIENvbmNsdWRpbmcgVGhvdWdodHMgCgoqIEkgdGhpbmsgdGhhdCB0aGVyZSBhcmUgc29tZSBwYXR0ZXJucyBtYXkgSSBkYXJlIHNheSBjbHVzdGVycyBpbiB0aGUgdGhlICRTJCBhbmQgJFxrYXBwYSQgcGxvdHMgdGhhdCBJIHRoaW5rIGNvdWxkIHJldmVhbCBpbnNpZ2h0IGludG8gdGhlIEVTTXMgdGhhdCBIZWN0b3IgaXMgY2FsaWJyYXRpbmcuIAoqIEl0IGlzIHVuY2xlYXIgdG8gbWUgd2h5IHRoZXJlIGFyZSB0aGUgbmVnYXRpdmUgdmFsdWVzIGZvciAkXGFscGhhJAoKCg==