1 Intro notes & set up

On March 15th we spoke about how we want to have some data to work with ASAP that can be used as proof of progress at the meeting on April 12th. To make speed this process up we decided to do some of the inital implmentation of the matching by nearest neighboor in R before translating it into python with good software design, this is a team effort and because the baton will be passed between memeber here are some note, potenitally excessive notes about what is going on.

Materials

  • stitches/notebooks/produce_nearest_neighboor_inputs.py: the python script that produces target and archive data that we will be used in the matching. This is data of values and rate of change for the different chunks of smoothed CanESM data. The target data contians data from a single experiment/ ensemble realization. While the target data contains this data for all of avaiable CanESM outputs. The outputs of this script are saved as csv files in stitches/notebooks/stitches_dev/inputs to be used in the R dev stage.
  • stitches/notebooks/stitches_dev: contains the materials for the R devlopment of the mathcing based on the nearest neighboor.
    • nearest_neighboor_matching.R: the functions that are used to find the nearest neighboor based on the elcudian distance between the target and arhcive data sets. Note that this only selcts the first nearest neihboor, it ignores cases where there are equa distant ties :( but that is a problem for another day. I spent a bit of time trying to find a pacakge/existing function that would be helpful here but there was nothing in R or python that looked like what we were looking for…
    • dev_notes.Rmd: this document that walks through the matching process & the progress made on stitiching together the global mean time series so far.
    • stitching_functions.R: an attmpet at writing something that would use the information from the matched data frame to stitch together the global mean temp. It is unideal and there are probably some issues, the transition from historical to next experiment is missing data!
source(file.path(BASE_DIR, "stitches_dev.Rproj"))
Error in eval(ei, envir) : object 'Version' not found

2 Nearest Neighboor Matching

We will use the function match_nearest_neighboor to match target data to its nearest neighboog defined that the observation in the arhive that minimizes the euclidean distance. Note that this picks the first nearest neighboor it runs into, it does not account for ties,

Proof of concept, if we read in the entire archive, this function should self select the target data, noramlly the target data will not also be included in the target data.

2.1 Self Matching

self_match <- match_nearest_neighboor(target_data = target_data, archive_data = archive_data)

Let’s take a look at the output.

summary(self_match)
 target-variable    target-experiment  target-ensemble    target-model       target-start_yr
 Length:28          Length:28          Length:28          Length:28          Min.   :1850   
 Class :character   Class :character   Class :character   Class :character   1st Qu.:1911   
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Median :1972   
                                                                             Mean   :1972   
                                                                             3rd Qu.:2032   
                                                                             Max.   :2093   
 target-end_yr   target-year     target-fx          target-dx         archive-experiment
 Min.   :1858   Min.   :1854   Min.   :-1.28987   Min.   :-0.014627   Length:28         
 1st Qu.:1919   1st Qu.:1915   1st Qu.:-1.13860   1st Qu.: 0.004793   Class :character  
 Median :1980   Median :1976   Median :-0.82103   Median : 0.014369   Mode  :character  
 Mean   :1979   Mean   :1976   Mean   : 0.07303   Mean   : 0.017259                     
 3rd Qu.:2040   3rd Qu.:2036   3rd Qu.: 1.25744   3rd Qu.: 0.033800                     
 Max.   :2100   Max.   :2097   Max.   : 3.03013   Max.   : 0.051995                     
 archive-variable   archive-model      archive-ensemble   archive-start_yr archive-end_yr
 Length:28          Length:28          Length:28          Min.   :1850     Min.   :1858  
 Class :character   Class :character   Class :character   1st Qu.:1911     1st Qu.:1919  
 Mode  :character   Mode  :character   Mode  :character   Median :1972     Median :1980  
                                                          Mean   :1972     Mean   :1979  
                                                          3rd Qu.:2032     3rd Qu.:2040  
                                                          Max.   :2093     Max.   :2100  
  archive-year    archive-fx         archive-dx           distance
 Min.   :1854   Min.   :-1.28987   Min.   :-0.014627   Min.   :0  
 1st Qu.:1915   1st Qu.:-1.13860   1st Qu.: 0.004793   1st Qu.:0  
 Median :1976   Median :-0.82103   Median : 0.014369   Median :0  
 Mean   :1976   Mean   : 0.07303   Mean   : 0.017259   Mean   :0  
 3rd Qu.:2036   3rd Qu.: 1.25744   3rd Qu.: 0.033800   3rd Qu.:0  
 Max.   :2097   Max.   : 3.03013   Max.   : 0.051995   Max.   :0  

What we woudl expect is that the archive results returns data from the exact same ensemble and then the same experiment as the target data, but note that the results from the historical period will be from the ssp119 scenario because all of the scenarios have identical historical data for the ensemble memeber and because we don’t deal with tie breaks at the moment it will always select the first min it runs into.

distinct(select(self_match, contains(c("model", "experiment", "ensemble")))) %>%  
  kable() %>%  
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"))

What does this look like?

Great we do see that the with the nearest neighboor we are able to self select the target data from the archive.

2.2 Match with boundry secnarios ssp126 and ssp585

Now what happens when the archive senario only consists of the two extreeme scenarios. We should see that the different scanrios are being selected from the archive.

archive_ssp126_ssp585 <- filter(archive_data, experiment %in% c("ssp126", "ssp585"))
# let's shuffel the entries 
set.seed(42)
rows <- sample(nrow(archive_ssp126_ssp585), replace = FALSE) 
archive_ssp126_ssp585 <- archive_ssp126_ssp585[rows, ]
# Now match the target data with the limited archive 
boundary_ssps_match <- match_nearest_neighboor(target_data = target_data, 
                                               archive_data = archive_ssp126_ssp585)

When we check to see the sources of the matched entries from the archive we should see mulitple experiments and ensemble members!

distinct(select(boundary_ssps_match, contains(c("model", "experiment", "ensemble")))) %>%  
  kable() %>%  
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
target-model archive-model target-experiment archive-experiment target-ensemble archive-ensemble
CanESM5 CanESM5 ssp245 ssp585 r1i1p1f1 r1i1p1f1
CanESM5 CanESM5 ssp245 ssp126 r1i1p1f1 r1i1p1f1
CanESM5 CanESM5 ssp245 ssp585 r1i1p1f1 r8i1p1f1
CanESM5 CanESM5 ssp245 ssp126 r1i1p1f1 r25i1p1f1
CanESM5 CanESM5 ssp245 ssp126 r1i1p1f1 r16i1p1f1
CanESM5 CanESM5 ssp245 ssp126 r1i1p1f1 r20i1p1f1
CanESM5 CanESM5 ssp245 ssp585 r1i1p1f1 r12i1p1f1
CanESM5 CanESM5 ssp245 ssp585 r1i1p1f1 r2i1p1f1
CanESM5 CanESM5 ssp245 ssp585 r1i1p1f1 r14i1p1f1
CanESM5 CanESM5 ssp245 ssp585 r1i1p1f1 r7i1p1f1

Now let’s over lay the dx vs fx plots, note that lines are drawn between the pairs of data that are matched if no line is visible or the dot appears purple then it means that the matched values are stacked on top of one another.

ggplot() + 
  geom_point(data = archive_ssp126_ssp585, 
             aes(fx, dx, color = "no match"), alpha = 0.1) + 
  geom_point(data = boundary_ssps_match, aes(`archive-fx`, `archive-dx`,  
                                             color = "matched archive data")) + 
  geom_point(data = boundary_ssps_match, aes(`target-fx`, `target-dx`,  
                                             color = "target data"), alpha = 0.4) + 
  geom_segment(data = boundary_ssps_match, aes(x = `target-fx`, y = `target-dx`, 
                        xend = `archive-fx`, yend =  `archive-dx`), alpha = 0.4) +
 scale_color_manual(values = c("matched archive data" = "red", 
                               "target data" = "blue", "no match" = "grey"))+
  theme_bw() + 
  labs(y = "dx (rate of change per chunk)", 
       x = "fx (value of median time per chunk)", 
       title = "Matching target (ssp245) with archive (ssp126 and ssp585)" )

What does the distance between the matched values look like?

summary(boundary_ssps_match$distance)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.00000 0.00000 0.00000 0.01957 0.01498 0.15554 
ggplot() + 
  geom_dotplot(data = boundary_ssps_match, aes(distance), bins = 40) + 
  labs(x = "Distance between matched values", 
       title = "Matching target (ssp245) with archive (ssp126 and ssp585)")
Ignoring unknown parameters: bins

3 Stitch Global Means

out <- stitch_global_mean(data = tgav_data, match = boundary_ssps_match)
out$name <- "boundary ssp match"
# prepare the comparison data this is the data that we are trying to emulate, which we smoothed in python. 
tgav_data %>% 
  dplyr::filter(experiment %in% c(unique(target_data$experiment), "historical") & ensemble == unique(target_data$ensemble) & model == unique(target_data$model)) -> 
  comparison

The historical data is a perfect match, which is what we expected, there is the gap in the stiched data between the historical and ssp scneario which is a problem. But eye balling it looks reasonable to me….

Let’s compare when we do the matching with two different archives….

# subset the archive so that it includes data from all of the scenarios with the exception of the ssp245
archive_nonssp245 <- filter(!archive_data, experiment %in% c("ssp245"))
Error in FUN(left) : invalid argument type

Okay something really funky is going on here… why are there no matches at the end of 2040? There is clearly something going on there but the other data doesn’t look that horrible…..

4 Net Steps

  • figure out what is going on with the stitching function
  • figure out how to manage/work with the ties in the data and how it will be used to generate the ensemble of results
  • How does the distance between the matched observations change when the archive changes?
  • produce the syntheic global mean ts for the analysis for April 12th
  • translate into python?
LS0tCnRpdGxlOiAnUiBEZXZsb3BtZW50IG9mIE1hdGNoaW5nIGZvciBTdGl0Y2hlcycKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIHRvY19jb2xsYXBzZWQ6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0aGVtZTogbHVtZW4KLS0tCgoKIyBJbnRybyBub3RlcyAmIHNldCB1cCAKCk9uIE1hcmNoIDE1dGggd2Ugc3Bva2UgYWJvdXQgaG93IHdlIHdhbnQgdG8gaGF2ZSBzb21lIGRhdGEgdG8gd29yayB3aXRoIEFTQVAgdGhhdCBjYW4gYmUgdXNlZCBhcyBwcm9vZiBvZiBwcm9ncmVzcyBhdCB0aGUgbWVldGluZyBvbiBBcHJpbCAxMnRoLiBUbyBtYWtlIHNwZWVkIHRoaXMgcHJvY2VzcyB1cCB3ZSBkZWNpZGVkIHRvIGRvIHNvbWUgb2YgdGhlIGluaXRhbCBpbXBsbWVudGF0aW9uIG9mIHRoZSBtYXRjaGluZyBieSBuZWFyZXN0IG5laWdoYm9vciBpbiBSIGJlZm9yZSB0cmFuc2xhdGluZyBpdCBpbnRvIHB5dGhvbiB3aXRoIGdvb2Qgc29mdHdhcmUgZGVzaWduLCB0aGlzIGlzIGEgdGVhbSBlZmZvcnQgYW5kIGJlY2F1c2UgdGhlIGJhdG9uIHdpbGwgYmUgcGFzc2VkIGJldHdlZW4gbWVtZWJlciBoZXJlIGFyZSBzb21lIG5vdGUsIHBvdGVuaXRhbGx5IGV4Y2Vzc2l2ZSBub3RlcyBhYm91dCB3aGF0IGlzIGdvaW5nIG9uLiAKCk1hdGVyaWFscyAKCiogYHN0aXRjaGVzL25vdGVib29rcy9wcm9kdWNlX25lYXJlc3RfbmVpZ2hib29yX2lucHV0cy5weWA6IHRoZSBweXRob24gc2NyaXB0IHRoYXQgcHJvZHVjZXMgdGFyZ2V0IGFuZCBhcmNoaXZlIGRhdGEgdGhhdCB3ZSB3aWxsIGJlIHVzZWQgaW4gdGhlIG1hdGNoaW5nLiBUaGlzIGlzIGRhdGEgb2YgdmFsdWVzIGFuZCByYXRlIG9mIGNoYW5nZSBmb3IgdGhlIGRpZmZlcmVudCBjaHVua3Mgb2Ygc21vb3RoZWQgQ2FuRVNNIGRhdGEuIFRoZSB0YXJnZXQgZGF0YSBjb250aWFucyBkYXRhIGZyb20gYSBzaW5nbGUgZXhwZXJpbWVudC8gZW5zZW1ibGUgcmVhbGl6YXRpb24uIFdoaWxlIHRoZSB0YXJnZXQgZGF0YSBjb250YWlucyB0aGlzIGRhdGEgZm9yIGFsbCBvZiBhdmFpYWJsZSBDYW5FU00gb3V0cHV0cy4gVGhlIG91dHB1dHMgb2YgdGhpcyBzY3JpcHQgYXJlIHNhdmVkIGFzIGNzdiBmaWxlcyBpbiBgc3RpdGNoZXMvbm90ZWJvb2tzL3N0aXRjaGVzX2Rldi9pbnB1dHNgIHRvIGJlIHVzZWQgaW4gdGhlIFIgZGV2IHN0YWdlLgoqIGBzdGl0Y2hlcy9ub3RlYm9va3Mvc3RpdGNoZXNfZGV2YDogY29udGFpbnMgdGhlIG1hdGVyaWFscyBmb3IgdGhlIFIgZGV2bG9wbWVudCBvZiB0aGUgbWF0aGNpbmcgYmFzZWQgb24gdGhlIG5lYXJlc3QgbmVpZ2hib29yLiAKICAgICogYG5lYXJlc3RfbmVpZ2hib29yX21hdGNoaW5nLlJgOiB0aGUgZnVuY3Rpb25zIHRoYXQgYXJlIHVzZWQgdG8gZmluZCB0aGUgbmVhcmVzdCBuZWlnaGJvb3IgYmFzZWQgb24gdGhlIGVsY3VkaWFuIGRpc3RhbmNlIGJldHdlZW4gdGhlIHRhcmdldCBhbmQgYXJoY2l2ZSBkYXRhIHNldHMuIE5vdGUgdGhhdCB0aGlzIG9ubHkgc2VsY3RzIHRoZSBmaXJzdCBuZWFyZXN0IG5laWhib29yLCBpdCBpZ25vcmVzIGNhc2VzIHdoZXJlIHRoZXJlIGFyZSBlcXVhIGRpc3RhbnQgdGllcyA6KCBidXQgdGhhdCBpcyBhIHByb2JsZW0gZm9yIGFub3RoZXIgZGF5LiBJIHNwZW50IGEgYml0IG9mIHRpbWUgdHJ5aW5nIHRvIGZpbmQgYSBwYWNha2dlL2V4aXN0aW5nIGZ1bmN0aW9uIHRoYXQgd291bGQgYmUgaGVscGZ1bCBoZXJlIGJ1dCB0aGVyZSB3YXMgbm90aGluZyBpbiBSIG9yIHB5dGhvbiB0aGF0IGxvb2tlZCBsaWtlIHdoYXQgd2Ugd2VyZSBsb29raW5nIGZvci4uLiAKICAgICogYGRldl9ub3Rlcy5SbWRgOiB0aGlzIGRvY3VtZW50IHRoYXQgd2Fsa3MgdGhyb3VnaCB0aGUgbWF0Y2hpbmcgcHJvY2VzcyAmIHRoZSBwcm9ncmVzcyBtYWRlIG9uIHN0aXRpY2hpbmcgdG9nZXRoZXIgdGhlIGdsb2JhbCBtZWFuIHRpbWUgc2VyaWVzIHNvIGZhci4gCiAgICAqIGBzdGl0Y2hpbmdfZnVuY3Rpb25zLlJgOiBhbiBhdHRtcGV0IGF0IHdyaXRpbmcgc29tZXRoaW5nIHRoYXQgd291bGQgdXNlIHRoZSBpbmZvcm1hdGlvbiBmcm9tIHRoZSBtYXRjaGVkIGRhdGEgZnJhbWUgdG8gc3RpdGNoIHRvZ2V0aGVyIHRoZSBnbG9iYWwgbWVhbiB0ZW1wLiBJdCBpcyB1bmlkZWFsIGFuZCB0aGVyZSBhcmUgcHJvYmFibHkgc29tZSBpc3N1ZXMsIHRoZSB0cmFuc2l0aW9uIGZyb20gaGlzdG9yaWNhbCB0byBuZXh0IGV4cGVyaW1lbnQgaXMgbWlzc2luZyBkYXRhIQogICAgCiAgICAKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKCiMgTm90ZSB0aGlzIHdpbGwgbmVlZCB0byBjaGFuZ2VkIHRvIHJ1biBvbiB5b3VyIGxvY2FsIG1hY2hpbmUgCkJBU0VfRElSIDwtICIvVXNlcnMvZG9yaDAxMi9Eb2N1bWVudHMvMjAyMS9zdGl0Y2hlcy9ub3RlYm9va3Mvc3RpdGNoZXNfZGV2IgoKIyBMb2FkIHRoZSBmdW5jdGlvbnMgdGhhdCB3ZSB3aWxsIHVzZSEgCnNvdXJjZShmaWxlLnBhdGgoQkFTRV9ESVIsICJuZWFyZXN0X25laWdoYm9vcl9tYXRjaGluZy5SIikpCnNvdXJjZShmaWxlLnBhdGgoQkFTRV9ESVIsICJzaXRjaGluZ19mdW5jdGlvbnMuUiIpKQoKCmFyY2hpdmVfZGF0YSA8LSByZWFkLmNzdihmaWxlLnBhdGgoQkFTRV9ESVIsICJpbnB1dHMiLCAiYXJjaGl2ZV9kYXRhLmNzdiIpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCnRhcmdldF9kYXRhIDwtIHJlYWQuY3N2KGZpbGUucGF0aChCQVNFX0RJUiwgImlucHV0cyIsICJ0YXJnZXRfZGF0YS5jc3YiKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQp0Z2F2X2RhdGEgPC0gcmVhZC5jc3YoZmlsZS5wYXRoKEJBU0VfRElSLCAiaW5wdXRzIiwgInRnYXZfZGF0YS5jc3YiKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpgYGAKCgojIE5lYXJlc3QgTmVpZ2hib29yIE1hdGNoaW5nIAoKCldlIHdpbGwgdXNlIHRoZSBmdW5jdGlvbiBgbWF0Y2hfbmVhcmVzdF9uZWlnaGJvb3JgIHRvIG1hdGNoIHRhcmdldCBkYXRhIHRvIGl0cyBuZWFyZXN0IG5laWdoYm9vZyBkZWZpbmVkIHRoYXQgdGhlIG9ic2VydmF0aW9uIGluIHRoZSBhcmhpdmUgdGhhdCBtaW5pbWl6ZXMgdGhlIGV1Y2xpZGVhbiBkaXN0YW5jZS4gTm90ZSB0aGF0IHRoaXMgcGlja3MgdGhlIGZpcnN0IG5lYXJlc3QgbmVpZ2hib29yIGl0IHJ1bnMgaW50bywgaXQgZG9lcyBub3QgYWNjb3VudCBmb3IgdGllcywgCgpQcm9vZiBvZiBjb25jZXB0LCBpZiB3ZSByZWFkIGluIHRoZSBlbnRpcmUgYXJjaGl2ZSwgdGhpcyBmdW5jdGlvbiBzaG91bGQgc2VsZiBzZWxlY3QgdGhlIHRhcmdldCBkYXRhLCBub3JhbWxseSB0aGUgdGFyZ2V0IGRhdGEgd2lsbCBub3QgYWxzbyBiZSBpbmNsdWRlZCBpbiB0aGUgdGFyZ2V0IGRhdGEuIAoKIyMgU2VsZiBNYXRjaGluZwoKYGBge3J9CnNlbGZfbWF0Y2ggPC0gbWF0Y2hfbmVhcmVzdF9uZWlnaGJvb3IodGFyZ2V0X2RhdGEgPSB0YXJnZXRfZGF0YSwgYXJjaGl2ZV9kYXRhID0gYXJjaGl2ZV9kYXRhKQpgYGAKCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBvdXRwdXQuIAoKYGBge3J9CnN1bW1hcnkoc2VsZl9tYXRjaCkKYGBgCgoKV2hhdCB3ZSB3b3VkbCBleHBlY3QgaXMgdGhhdCB0aGUgYXJjaGl2ZSByZXN1bHRzIHJldHVybnMgZGF0YSBmcm9tIHRoZSBleGFjdCBzYW1lIGVuc2VtYmxlIGFuZCB0aGVuIHRoZSBzYW1lIGV4cGVyaW1lbnQgYXMgdGhlIHRhcmdldCBkYXRhLCBidXQgbm90ZSB0aGF0IHRoZSByZXN1bHRzIGZyb20gdGhlIGhpc3RvcmljYWwgcGVyaW9kIHdpbGwgYmUgZnJvbSB0aGUgc3NwMTE5IHNjZW5hcmlvIGJlY2F1c2UgYWxsIG9mIHRoZSBzY2VuYXJpb3MgaGF2ZSBpZGVudGljYWwgaGlzdG9yaWNhbCBkYXRhIGZvciB0aGUgZW5zZW1ibGUgbWVtZWJlciBhbmQgYmVjYXVzZSB3ZSBkb24ndCBkZWFsIHdpdGggdGllIGJyZWFrcyBhdCB0aGUgbW9tZW50IGl0IHdpbGwgYWx3YXlzIHNlbGVjdCB0aGUgZmlyc3QgbWluIGl0IHJ1bnMgaW50by4gCgpgYGB7cn0KZGlzdGluY3Qoc2VsZWN0KHNlbGZfbWF0Y2gsIGNvbnRhaW5zKGMoIm1vZGVsIiwgImV4cGVyaW1lbnQiLCAiZW5zZW1ibGUiKSkpKSAlPiUgIAogIGthYmxlKCkgJT4lICAKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSkKYGBgCgoKV2hhdCBkb2VzIHRoaXMgbG9vayBsaWtlPyAKCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGFyY2hpdmVfZGF0YSwgCiAgICAgICAgICAgICBhZXMoZngsIGR4LCBjb2xvciA9ICJubyBtYXRjaCIpLCBhbHBoYSA9IDAuMSkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBzZWxmX21hdGNoLCBhZXMoYGFyY2hpdmUtZnhgLCBgYXJjaGl2ZS1keGAsICBjb2xvciA9ICJtYXRjaGVkIGFyY2hpdmUgZGF0YSIpKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IHNlbGZfbWF0Y2gsIGFlcyhgdGFyZ2V0LWZ4YCwgYHRhcmdldC1keGAsICBjb2xvciA9ICJ0YXJnZXQgZGF0YSIpLCBhbHBoYSA9IDAuNCkgKyAKIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJtYXRjaGVkIGFyY2hpdmUgZGF0YSIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGFyZ2V0IGRhdGEiID0gImJsdWUiLCAibm8gbWF0Y2giID0gImdyZXkiKSkrCiAgdGhlbWVfYncoKSArIAogIGxhYnMoeSA9ICJkeCAocmF0ZSBvZiBjaGFuZ2UgcGVyIGNodW5rKSIsIAogICAgICAgeCA9ICJmeCAodmFsdWUgb2YgbWVkaWFuIHRpbWUgcGVyIGNodW5rKSIsIAogICAgICAgdGl0bGUgPSAiU2VsZiBzZWxlY3QgZnJvbSB0aGUgYXJjaGl2ZSIpCmBgYAoKIEdyZWF0IHdlIGRvIHNlZSB0aGF0IHRoZSB3aXRoIHRoZSBuZWFyZXN0IG5laWdoYm9vciB3ZSBhcmUgYWJsZSB0byBzZWxmIHNlbGVjdCB0aGUgdGFyZ2V0IGRhdGEgZnJvbSB0aGUgYXJjaGl2ZS4gCiAKIyMgTWF0Y2ggd2l0aCBib3VuZHJ5IHNlY25hcmlvcyBzc3AxMjYgYW5kIHNzcDU4NSAKCk5vdyB3aGF0IGhhcHBlbnMgd2hlbiB0aGUgYXJjaGl2ZSBzZW5hcmlvIG9ubHkgY29uc2lzdHMgb2YgdGhlIHR3byBleHRyZWVtZSBzY2VuYXJpb3MuIFdlIHNob3VsZCBzZWUgdGhhdCB0aGUgZGlmZmVyZW50IHNjYW5yaW9zIGFyZSBiZWluZyBzZWxlY3RlZCBmcm9tIHRoZSBhcmNoaXZlLiAKIApgYGB7cn0KYXJjaGl2ZV9zc3AxMjZfc3NwNTg1IDwtIGZpbHRlcihhcmNoaXZlX2RhdGEsIGV4cGVyaW1lbnQgJWluJSBjKCJzc3AxMjYiLCAic3NwNTg1IikpCiMgbGV0J3Mgc2h1ZmZlbCB0aGUgZW50cmllcyAKc2V0LnNlZWQoNDIpCnJvd3MgPC0gc2FtcGxlKG5yb3coYXJjaGl2ZV9zc3AxMjZfc3NwNTg1KSwgcmVwbGFjZSA9IEZBTFNFKSAKYXJjaGl2ZV9zc3AxMjZfc3NwNTg1IDwtIGFyY2hpdmVfc3NwMTI2X3NzcDU4NVtyb3dzLCBdCgojIE5vdyBtYXRjaCB0aGUgdGFyZ2V0IGRhdGEgd2l0aCB0aGUgbGltaXRlZCBhcmNoaXZlIApib3VuZGFyeV9zc3BzX21hdGNoIDwtIG1hdGNoX25lYXJlc3RfbmVpZ2hib29yKHRhcmdldF9kYXRhID0gdGFyZ2V0X2RhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyY2hpdmVfZGF0YSA9IGFyY2hpdmVfc3NwMTI2X3NzcDU4NSkKYGBgCgpXaGVuIHdlIGNoZWNrIHRvIHNlZSB0aGUgc291cmNlcyBvZiB0aGUgbWF0Y2hlZCBlbnRyaWVzIGZyb20gdGhlIGFyY2hpdmUgd2Ugc2hvdWxkIHNlZSBtdWxpdHBsZSBleHBlcmltZW50cyBhbmQgZW5zZW1ibGUgbWVtYmVycyEgCgpgYGB7cn0KZGlzdGluY3Qoc2VsZWN0KGJvdW5kYXJ5X3NzcHNfbWF0Y2gsIGNvbnRhaW5zKGMoIm1vZGVsIiwgImV4cGVyaW1lbnQiLCAiZW5zZW1ibGUiKSkpKSAlPiUgIAogIGthYmxlKCkgJT4lICAKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSkKYGBgCgoKTm93IGxldCdzIG92ZXIgbGF5IHRoZSBkeCB2cyBmeCBwbG90cywgbm90ZSB0aGF0IGxpbmVzIGFyZSBkcmF3biBiZXR3ZWVuIHRoZSBwYWlycyBvZiBkYXRhIHRoYXQgYXJlIG1hdGNoZWQgaWYgbm8gbGluZSBpcyB2aXNpYmxlIG9yIHRoZSBkb3QgYXBwZWFycyBwdXJwbGUgdGhlbiBpdCBtZWFucyB0aGF0IHRoZSBtYXRjaGVkIHZhbHVlcyBhcmUgc3RhY2tlZCBvbiB0b3Agb2Ygb25lIGFub3RoZXIuIAoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gYXJjaGl2ZV9zc3AxMjZfc3NwNTg1LCAKICAgICAgICAgICAgIGFlcyhmeCwgZHgsIGNvbG9yID0gIm5vIG1hdGNoIiksIGFscGhhID0gMC4xKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGJvdW5kYXJ5X3NzcHNfbWF0Y2gsIGFlcyhgYXJjaGl2ZS1meGAsIGBhcmNoaXZlLWR4YCwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJtYXRjaGVkIGFyY2hpdmUgZGF0YSIpKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGJvdW5kYXJ5X3NzcHNfbWF0Y2gsIGFlcyhgdGFyZ2V0LWZ4YCwgYHRhcmdldC1keGAsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAidGFyZ2V0IGRhdGEiKSwgYWxwaGEgPSAwLjQpICsgCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBib3VuZGFyeV9zc3BzX21hdGNoLCBhZXMoeCA9IGB0YXJnZXQtZnhgLCB5ID0gYHRhcmdldC1keGAsIAogICAgICAgICAgICAgICAgICAgICAgICB4ZW5kID0gYGFyY2hpdmUtZnhgLCB5ZW5kID0gIGBhcmNoaXZlLWR4YCksIGFscGhhID0gMC40KSArCiBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygibWF0Y2hlZCBhcmNoaXZlIGRhdGEiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRhcmdldCBkYXRhIiA9ICJibHVlIiwgIm5vIG1hdGNoIiA9ICJncmV5IikpKwogIHRoZW1lX2J3KCkgKyAKICBsYWJzKHkgPSAiZHggKHJhdGUgb2YgY2hhbmdlIHBlciBjaHVuaykiLCAKICAgICAgIHggPSAiZnggKHZhbHVlIG9mIG1lZGlhbiB0aW1lIHBlciBjaHVuaykiLCAKICAgICAgIHRpdGxlID0gIk1hdGNoaW5nIHRhcmdldCAoc3NwMjQ1KSB3aXRoIGFyY2hpdmUgKHNzcDEyNiBhbmQgc3NwNTg1KSIgKQpgYGAKCldoYXQgZG9lcyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGUgbWF0Y2hlZCB2YWx1ZXMgbG9vayBsaWtlPyAKCgpgYGB7cn0Kc3VtbWFyeShib3VuZGFyeV9zc3BzX21hdGNoJGRpc3RhbmNlKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoKSArIAogIGdlb21fZG90cGxvdChkYXRhID0gYm91bmRhcnlfc3Nwc19tYXRjaCwgYWVzKGRpc3RhbmNlKSwgYmlucyA9IDQwKSArIAogIGxhYnMoeCA9ICJEaXN0YW5jZSBiZXR3ZWVuIG1hdGNoZWQgdmFsdWVzIiwgCiAgICAgICB0aXRsZSA9ICJNYXRjaGluZyB0YXJnZXQgKHNzcDI0NSkgd2l0aCBhcmNoaXZlIChzc3AxMjYgYW5kIHNzcDU4NSkiKQpgYGAKCiMgU3RpdGNoIEdsb2JhbCBNZWFucyAKCgpgYGB7cn0Kb3V0MSA8LSBzdGl0Y2hfZ2xvYmFsX21lYW4oZGF0YSA9IHRnYXZfZGF0YSwgbWF0Y2ggPSBib3VuZGFyeV9zc3BzX21hdGNoKQpvdXQxJG5hbWUgPC0gImJvdW5kYXJ5IHNzcCBtYXRjaCIKYGBgCgoKYGBge3J9CiMgcHJlcGFyZSB0aGUgY29tcGFyaXNvbiBkYXRhIHRoaXMgaXMgdGhlIGRhdGEgdGhhdCB3ZSBhcmUgdHJ5aW5nIHRvIGVtdWxhdGUsIHdoaWNoIHdlIHNtb290aGVkIGluIHB5dGhvbi4gCnRnYXZfZGF0YSAlPiUgCiAgZHBseXI6OmZpbHRlcihleHBlcmltZW50ICVpbiUgYyh1bmlxdWUodGFyZ2V0X2RhdGEkZXhwZXJpbWVudCksICJoaXN0b3JpY2FsIikgJiBlbnNlbWJsZSA9PSB1bmlxdWUodGFyZ2V0X2RhdGEkZW5zZW1ibGUpICYgbW9kZWwgPT0gdW5pcXVlKHRhcmdldF9kYXRhJG1vZGVsKSkgLT4gCiAgY29tcGFyaXNvbgpgYGAKCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZ2dwbG90KCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IGNvbXBhcmlzb24sIGFlcyh5ZWFyLCB2YWx1ZSwgY29sb3IgPSAidGFyZ2V0IGRhdGEiKSkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IG91dDEsIGFlcyh5ZWFyLCB2YWx1ZSwgY29sb3IgPSAic3RpdGNoZWQgMSIpLCBhbHBoYSA9IDAuNikgKyAKICB0aGVtZV9idygpICsgCiAgbGFicyh5ID0gJ0dsb2JhbCBUZW1wJywgCiAgICAgICB4ID0gIlllYXIiKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJ0YXJnZXQgZGF0YSIgPSAiZ3JleSIsICJzdGl0Y2hlZCAxIiA9ICJyZWQiKSkKYGBgCgpUaGUgaGlzdG9yaWNhbCBkYXRhIGlzIGEgcGVyZmVjdCBtYXRjaCwgd2hpY2ggaXMgd2hhdCB3ZSBleHBlY3RlZCwgdGhlcmUgaXMgdGhlIGdhcCBpbiB0aGUgc3RpY2hlZCBkYXRhIGJldHdlZW4gdGhlIGhpc3RvcmljYWwgYW5kIHNzcCBzY25lYXJpbyB3aGljaCBpcyBhIHByb2JsZW0uIEJ1dCBleWUgYmFsbGluZyBpdCBsb29rcyByZWFzb25hYmxlIHRvIG1lLi4uLiAKCkxldCdzIGNvbXBhcmUgd2hlbiB3ZSBkbyB0aGUgbWF0Y2hpbmcgd2l0aCB0d28gZGlmZmVyZW50IGFyY2hpdmVzLi4uLiAKCgpgYGB7cn0KIyBzdWJzZXQgdGhlIGFyY2hpdmUgc28gdGhhdCBpdCBpbmNsdWRlcyBkYXRhIGZyb20gYWxsIG9mIHRoZSBzY2VuYXJpb3Mgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIHRoZSBzc3AyNDUKYXJjaGl2ZV9ub25zc3AyNDUgPC0gZmlsdGVyKGFyY2hpdmVfZGF0YSwgIWV4cGVyaW1lbnQgJWluJSBjKCJzc3AyNDUiKSkKIyBsZXQncyBzaHVmZmVsIHRoZSBlbnRyaWVzIApzZXQuc2VlZCg0MikKcm93cyA8LSBzYW1wbGUobnJvdyhhcmNoaXZlX25vbnNzcDI0NSksIHJlcGxhY2UgPSBGQUxTRSkgCmFyY2hpdmVfbm9uc3NwMjQ1IDwtIGFyY2hpdmVfbm9uc3NwMjQ1W3Jvd3MsIF0KCiMgTm93IG1hdGNoIHRoZSB0YXJnZXQgZGF0YSB3aXRoIHRoZSBsaW1pdGVkIGFyY2hpdmUgCm5vbnNwcDI0NV9tYXRjaCA8LSBtYXRjaF9uZWFyZXN0X25laWdoYm9vcih0YXJnZXRfZGF0YSA9IHRhcmdldF9kYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmNoaXZlX2RhdGEgPSBhcmNoaXZlX25vbnNzcDI0NSkKYGBgCgoKCmBgYHtyfQpvdXQyIDwtIHN0aXRjaF9nbG9iYWxfbWVhbihkYXRhID0gdGdhdl9kYXRhLCBtYXRjaCA9IG5vbnNwcDI0NV9tYXRjaCkKb3V0MiRuYW1lIDwtICJub24gc3NwMjQ1IG1hdGNoIgpgYGAKCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZ2dwbG90KCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IGNvbXBhcmlzb24sIGFlcyh5ZWFyLCB2YWx1ZSwgY29sb3IgPSAidGFyZ2V0IGRhdGEiKSkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IG91dDEsIGFlcyh5ZWFyLCB2YWx1ZSwgY29sb3IgPSAic3RpdGNoZWQgMSIpLCBhbHBoYSA9IDAuNikgKyAKICAgIGdlb21fbGluZShkYXRhID0gb3V0MiwgYWVzKHllYXIsIHZhbHVlLCBjb2xvciA9ICJzdGl0Y2hlZCAyIiksIGFscGhhID0gMC42KSArIAoKICB0aGVtZV9idygpICsgCiAgbGFicyh5ID0gJ0dsb2JhbCBUZW1wJywgCiAgICAgICB4ID0gIlllYXIiKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJ0YXJnZXQgZGF0YSIgPSAiZ3JleSIsICJzdGl0Y2hlZCAxIiA9ICJyZWQiLCAic3RpdGNoZWQgMiIgPSAiYmx1ZSIpKQpgYGAKCk9rYXkgc29tZXRoaW5nIHJlYWxseSBmdW5reSBpcyBnb2luZyBvbiBoZXJlLi4uIHdoeSBhcmUgdGhlcmUgbm8gbWF0Y2hlcyBhdCB0aGUgZW5kIG9mIDIwNDA/IFRoZXJlIGlzIGNsZWFybHkgc29tZXRoaW5nIGdvaW5nIG9uIHRoZXJlIGJ1dCB0aGUgb3RoZXIgZGF0YSBkb2Vzbid0IGxvb2sgdGhhdCBob3JyaWJsZS4uLi4uIAoKCiMgTmV0IFN0ZXBzIAoKKiBmaWd1cmUgb3V0IHdoYXQgaXMgZ29pbmcgb24gd2l0aCB0aGUgc3RpdGNoaW5nIGZ1bmN0aW9uCiogZmlndXJlIG91dCBob3cgdG8gbWFuYWdlL3dvcmsgd2l0aCB0aGUgdGllcyBpbiB0aGUgZGF0YSBhbmQgaG93IGl0IHdpbGwgYmUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgZW5zZW1ibGUgb2YgcmVzdWx0cyAKKiBIb3cgZG9lcyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGUgbWF0Y2hlZCBvYnNlcnZhdGlvbnMgY2hhbmdlIHdoZW4gdGhlIGFyY2hpdmUgY2hhbmdlcz8gCiogcHJvZHVjZSB0aGUgc3ludGhlaWMgZ2xvYmFsIG1lYW4gdHMgZm9yIHRoZSBhbmFseXNpcyBmb3IgQXByaWwgMTJ0aCAKKiB0cmFuc2xhdGUgaW50byBweXRob24/IAo=