In this notebook, I’ll …

First we have to download the data from the web. This API is “paginated”, which means that the data can be downloaded as it was a homepage with a fixed page size (e.g. 50 book characters in a page), and you have access to ‘next’ and ‘previous’ button links. So we need to build a loop to collect data from all characters.

We collected a whooping 2134 characters from the Game of Thrones universe!

In the next block, we transform the data from the awkward hierarchical data structure into a data frame, that is easy to use. We also clean the data to get meaningful variables.

Birth and death in the world of Game of Thrones

Births show a smooth pattern without sudden increases. The number of deaths seems to show a few sudden increases around 135 AC, 210AC, 280AC and most notably around 300AC. These likely coincide with significant event - such as wars or catastrophes - in the history of ASOIF.

Of course the conclusion is not: by 300 AC more people die than was born, because the data is heavily biased by missing values. As we get closer to the events of the books, more and more birth and death dates are documented. Still, it is telling that by 300, more deaths are documented than births…

cumulative_birth <-
    got_df %>% 
    group_by(year = birth_year) %>% 
    summarise(yearly_birth = sum(!is.na(birth_year))) %>% 
    ungroup() %>% 
    transmute(year, birth = cumsum(yearly_birth))

cumulative_death <-
    got_df %>% 
    group_by(year = death_year) %>% 
    summarise(yearly_death = sum(!is.na(death_year))) %>% 
    ungroup() %>% 
    transmute(year, death = cumsum(yearly_death)) %>% 
    drop_na()
    
    tibble(year = -28:300) %>% 
    left_join(cumulative_birth, by = "year") %>% 
    left_join(cumulative_death, by = "year") %>% 
    gather(event, number, -year, na.rm = TRUE) %>% 
        ggplot() +
        aes(x = year, y = number, color = event) +
        geom_line(size = 2) +
        scale_x_continuous(labels = scales::unit_format(unit = "A.C.")) +
        scale_color_got_d(option = "Martell") +
        labs(title = "Cumulative number of births and deaths over time for named characters in ASOIF",
             y = "Cumulative number of events",
             color = "Event")

Let’s plot a map of all the deaths and births on a proper Westeros map!

# Prepare the data for the animation
continents <- readOGR("map", "continents")
## OGR data source with driver: ESRI Shapefile 
## Source: "D:\Documents\GitHub\own projects\got_analysis\map", layer: "continents"
## with 3 features
## It has 2 fields
## Integer64 fields read as strings:  id
westeros <- readOGR("map", "political") # The actual map
## OGR data source with driver: ESRI Shapefile 
## Source: "D:\Documents\GitHub\own projects\got_analysis\map", layer: "political"
## with 12 features
## It has 3 fields
## Integer64 fields read as strings:  id
islands <- readOGR("map", "islands")
## OGR data source with driver: ESRI Shapefile 
## Source: "D:\Documents\GitHub\own projects\got_analysis\map", layer: "islands"
## with 86 features
## It has 3 fields
## Integer64 fields read as strings:  id
locations <- readOGR("map", "locations") # Places data
## OGR data source with driver: ESRI Shapefile 
## Source: "D:\Documents\GitHub\own projects\got_analysis\map", layer: "locations"
## with 247 features
## It has 5 fields
## Integer64 fields read as strings:  id size
places <-
    bind_cols(locations@data, as_tibble(locations@coords)) %>% 
    as_tibble() %>%
    select(id, place = name, 
           place_size = size, place_type = type, 
           lat = coords.x1, long = coords.x2) %>% 
    mutate_if(is.factor, as.character) %>%
    mutate_at(vars(id, place_size), as.integer) %>% 
    drop_na(place)

coordinates  <-
    got_df %>%
    drop_na(name) %>% 
    # Add more precise place names as rows, this will duplicate some rows, but will make
    # it possible to match more place names
    separate_rows(birth_place, sep = ",") %>% 
    separate_rows(death_place, sep = ",") %>% 
    # Add pefixes to birth and death info and join them to this dataset
    left_join(rename_all(places, ~paste0("birth_", .)), by = "birth_place") %>% 
    left_join(rename_all(places, ~paste0("death_", .)), by = "death_place") %>% 
    # Now, fill up the non-recognized coordinates by the recognized ones
    # arrange will make sure that the recognized will be on top when there are more places
    group_by(id) %>% 
    arrange(birth_long, death_long, .by_group = TRUE) %>% 
    fill(birth_long, birth_lat, death_long, death_lat) %>% 
    ungroup() %>% 
    # Keep only unique characters
    distinct(id, .keep_all = TRUE)

# Create a dataset with all notable events by time and place
death_birth <-
    coordinates %>% 
    select(id, name, matches("_year$|_lat$|_long$|_place$")) %>% 
    gather(variable, value, -id, -name, na.rm = TRUE) %>% 
    separate(variable, c("event", "variable"), sep = "_") %>% 
    spread(variable, value, convert = TRUE) %>% 
    drop_na() %>% 
    distinct(name, event, .keep_all = TRUE) %>% 
    mutate(decade = floor(year/10)*10) %>% 
    arrange(year)

event_places <-
    death_birth %>% 
    count(event, decade, lat, long, place) %>% 
    # Need to add decades that has no data for the animation later
    full_join(crossing(decade = seq(-30, 300, 10), 
                       event = c("birth", "death")), 
              by = c("event", "decade")) %>% 
    arrange(decade)

death_places <-
    event_places %>% 
    filter(event == "death") %>% 
    group_by(lat, long, place) %>% 
    summarise(n = sum(n)) %>% 
    drop_na()
# Plot a blank map first
base_map <-
    ggplot() +
    # Adds the continents
    geom_polygon(data = continents, 
                 aes(x = long, y = lat, group = group), 
                 color = "black", fill = "wheat") +
    # Adds the islands
    geom_polygon(data = islands, 
                 aes(x = long, y = lat, group = group),
                 color = "black", fill = "wheat") +
    # Adds the kingdomes of westeros
    geom_polygon(data = westeros,
                 aes(x = long, y = lat, group = group),
                 color = "black", fill = "wheat") +
    coord_map(xlim = c(-10, 75), ylim = c(-15, 50)) +
    theme_map() +
    theme(panel.background = element_rect(fill = "lightblue"))
## Regions defined for each Polygons
## Regions defined for each Polygons
## Regions defined for each Polygons

Let’s plot all the places where each notable death happened!

base_map +
    geom_point(data = death_places, 
               aes(x = lat, y = long, size = n)) +
    scale_color_got(option = "Greyjoy", direction = 1) +
    scale_size(range = c(2, 7)) +
    geom_text_repel(data = death_places, 
              aes(x = lat, y = long, label = place)) +
    labs(title = "Deadliest places in the word of ASOIF",
         size = "All notable deaths") +
    theme(legend.position = "right")

If we also wanted to include a timeline, we could do an animated map of all deaths.

event_map <-
    base_map +
    geom_point(data = filter(event_places, event == "death"),
               aes(x = lat,
                   y = long,
                   size = n)) +
    scale_color_got_d(option = "Targaryen", direction = -1) +
    scale_size(range = c(3, 7)) +
    geom_text(data = filter(event_places, event == "death"),
                    aes(x = lat,
                        y = long,
                        label = place)) +
    labs(title = "Deaths of characters over time in the {closest_state}s",
         color = "Event",
         size = "Notable deaths by decade") +
    theme(legend.position = "right") +
    transition_states(decade) +
    ease_aes("quadratic-in-out") +
    enter_grow() +
    exit_fade()
animate(event_map, nframes = 200, end_pause = 30, fps = 10,
        width = 900, height = 500)

Analysis question: Is there a smaller chance of survival in game of thrones after marriage?

People die left and right in game of thrones, but no occasion is as deadly as a wedding. But what about marriage? How people fare if they survived their wedding? In real life, lifetime expectancy is increased by marriage, which is obviously not the case in Game of Thrones. But exactly how dangerous is to be married in GOT?

We are building a cox regression on got character data with the outcome variable that shows if the character is alive or not at particular ages. We are only looking for main effects of marital status (if the character has a spouse). Disclaimer: This is obviously a very simple minded analysis, and I only did that to show how this kind of stuff can be done in R.

got_df %>% 
    select(is_alive, has_spouse, gender) %>% 
    ftable()
##                     gender Female Male
## is_alive has_spouse                   
## FALSE    FALSE                 52  402
##          TRUE                  50   81
## TRUE     FALSE                 79  144
##          TRUE                  32   31

To explore data, we create a box plot visualization about age by gender by marital status by survival status (based on 458 characters).

got_df %>% 
    drop_na(is_alive, has_spouse, gender, age) %>% 
    ggplot() +
      aes(y = age, x = gender, fill = gender) +
      geom_boxplot() +
      facet_grid(is_alive~has_spouse, labeller = label_both)

Now we create two statistical models (Cox regression) to test the effect of the predictors on the outcome variable (survival status).

survival_df <-
  got_df %>% 
  filter(!is.na(is_alive)) %>% 
  mutate(death_year = if_else(is_alive == TRUE & birth_year >= 200, 301, death_year),
         status = if_else(is_alive == TRUE, 0, 1),
         age = death_year - birth_year) %>% 
  drop_na(death_year)

survival_model1 <- coxph(Surv(age, status) ~ has_spouse, data = survival_df)
survival_model2 <- coxph(Surv(age, status) ~ has_spouse + gender, data = survival_df)
    
AIC(survival_model1, survival_model2)

The models show that being married is a significant health risk in the world of ASOIF. Comparing the models shows that gender does not add much to this finding, therefore we will just visualize the one without gender.

We also calculate odds ratios, and confidence intervals. Odds ratios suggest that it is 1.4 95%CI[1.03 1.88] times more likely to die if a character is married.

At first, there is little difference between characters with and without spouses, and young characters with spouses have a better chance of survival but after about 35 years of age,those who have a spouse die earlier.

Not getting wed is a significant predictor of longer life. Those having a spouse die at a median age of 48 years 95%CI[54 80], while the unmarried die at 66 years 95%CI[41 53]. This is a median difference of 18 years!

summary(survival_model1)
## Call:
## coxph(formula = Surv(age, status) ~ has_spouse, data = survival_df)
## 
##   n= 458, number of events= 172 
##    (331 observations deleted due to missingness)
## 
##                  coef exp(coef) se(coef)     z Pr(>|z|)  
## has_spouseTRUE 0.3285    1.3888   0.1544 2.127   0.0334 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##                exp(coef) exp(-coef) lower .95 upper .95
## has_spouseTRUE     1.389       0.72     1.026      1.88
## 
## Concordance= 0.489  (se = 0.021 )
## Likelihood ratio test= 4.52  on 1 df,   p=0.03
## Wald test            = 4.52  on 1 df,   p=0.03
## Score (logrank) test = 4.56  on 1 df,   p=0.03

And finally, let’s plot the predictions for the survival chance over time by marital status.

survfit(Surv(age, status) ~ has_spouse, data = survival_df) %>% 
    ggsurv(.,
           cens.shape = 16, 
           size.est = 1.2) +
    scale_color_got_d(option = "Greyjoy", direction = 1) +
    scale_y_continuous(labels = scales::percent_format()) +
    labs(title = "Survival of ASOIF characters based on marital status",
         subtitle = "At first, there is little difference between characters with and without spouses, and young characters with spouses have\na better chance of survival but after about 35 years of age,those who have a spouse die earlier",
         y = "Estimated % survival", 
         x = "Age") +
    annotate("text",
             label = c("Has spouse", "No spouse"),
             x = c(100, 100),
             y = c(.1, .25),
             color = got(option = "Greyjoy", direction = 1, n = 2)) +
    guides(color = FALSE, linetype = FALSE)
## Scale for 'colour' is already present. Adding another scale for
## 'colour', which will replace the existing scale.

Conclusions

  • we looked at significant life events (births and deaths) of notable characters in ASOIF
  • Married characters die approximately 18 years sooner than unmarried characters
LS0tDQp0aXRsZTogIkFuYWx5c2lzIG9uIEdhbWUgb2YgVGhyb25lcyBtYXJyaWFnZSBzdXJ2aXZhbCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IHllcw0KICAgICAgc21vb3RoX3Njcm9sbDogeWVzDQogIGh0bWxfbm90ZWJvb2s6DQogICAgdGhlbWU6IGpvdXJuYWwNCmVkaXRvcl9vcHRpb25zOg0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCkluIHRoaXMgbm90ZWJvb2ssIEknbGwgLi4uDQoNCi0gRG93bmxvYWQgZGF0YSBmcm9tIHRoZSAiU29uZyBvZiBJY2UgYW5kIEZpcmUgQVBJIiwgaHR0cHM6Ly9hbmFwaW9maWNlYW5kZmlyZS5jb20vLiBBIHdlYiBBUEkgaXMgYSB3YXkgdG8gZG93bmxvYWQgZGF0YSBmcm9tIHRoZSBpbnRlcm5ldC4gVGhlIGFzb2lmIEFQSSBpcyBhIHJlcG9zaXRvcnkgdGhhdCBjb250YWlucyBhIGxvdCBvZiBHT1QgcmVsYXRlZCBkYXRhLiBUaGVyZSBpcyBhbiBSIHBhY2thZ2UgZm9yIHRoYXQuIGh0dHBzOi8vZ2l0aHViLmNvbS9NYW5nb1RoZUNhdC9Hb1RyDQotIE1ha2UgZGF0YSByZWN0YW5nbGluZyBhbmQgdHJhbnNmb3JtYXRpb25zIHRvIHJlYWR5IGRhdGEgZm9yIGFuYWx5c2lzIHVzaW5nIHRoZSB0aWR5dmVyc2UgaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8NCi0gSSB3aWxsIGNyZWF0ZSB2aXN1YWxpemF0aW9ucyB1c2luZyB0aGUgZmFudGFzdGljIGdhbWVvZmhyb25lcyBjb2xvciBwYWxldHRlcyBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2FtZW9mdGhyb25lcy9pbmRleC5odG1sDQotIEkgd2lsbCBjcmVhdGUgV2VzdGVyb3MgbWFwcyB1c2luZyBzaGFwZWZpbGVzIGZyb20gaGVyZTogaHR0cHM6Ly93d3cuY2FydG9ncmFwaGVyc2d1aWxkLmNvbS9zaG93dGhyZWFkLnBocD90PTMwNDcyDQotIEkgd2lsbCBtYWtlIGFuIGFuaW1hdGVkIHBsb3QgdXNpbmcgZ2dhbmltYXRlIGh0dHBzOi8vZ2dhbmltYXRlLmNvbS8NCi0gSSB3aWxsIGNvbmR1Y3QgYSBzdXJ2aXZhbCBhbmFseXNpcyB0byBzZWUgaWYgbWFycmllZCBjaGFyYWN0ZXJzIGRpZSBzb29uZXINCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCiMgTG9hZCBwYWNrYWdlcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KEdvVHIpICMgQWNjZXNzIG9mIEFTT0lGIEFQSQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkoZ2dyZXBlbCkNCmxpYnJhcnkoZ2dhbmltYXRlKSAjIEFuaW1hdGVkIGZpZ3VyZXMNCmxpYnJhcnkoZ2dtYXApDQpsaWJyYXJ5KHJnZGFsKSAjIEZvciByZWFkaW5nIHNoYXBlZmlsZXMNCmxpYnJhcnkoZ2FtZW9mdGhyb25lcykgIyBGb3IgY3VzdG9tIGNvbG9yIHBhbGV0dGVzDQpsaWJyYXJ5KHN1cnZpdmFsKSAjIEZvciBzdXJ2aXZhbCBhbmFseXNpcyBhbmQgQ294IHJlZ3Jlc3Npb24NCmxpYnJhcnkoR0dhbGx5KSAjIEZvciBwbG90dGluZyBzdXJ2aXZhbCBhbmFseXNpcw0KbGlicmFyeShicm9vbSkNCmxpYnJhcnkoc2NhbGVzKQ0KDQp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQ0KYGBgDQoNCkZpcnN0IHdlIGhhdmUgdG8gZG93bmxvYWQgdGhlIGRhdGEgZnJvbSB0aGUgd2ViLiBUaGlzIEFQSSBpcyAicGFnaW5hdGVkIiwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgZGF0YSBjYW4gYmUgZG93bmxvYWRlZCBhcyBpdCB3YXMgYSBob21lcGFnZSB3aXRoIGEgZml4ZWQgcGFnZSBzaXplIChlLmcuIDUwIGJvb2sgY2hhcmFjdGVycyBpbiBhIHBhZ2UpLCBhbmQgeW91IGhhdmUgYWNjZXNzIHRvICduZXh0JyBhbmQgJ3ByZXZpb3VzJyBidXR0b24gbGlua3MuIFNvIHdlIG5lZWQgdG8gYnVpbGQgYSBsb29wIHRvIGNvbGxlY3QgZGF0YSBmcm9tIGFsbCBjaGFyYWN0ZXJzLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCBjYWNoZSA9IFRSVUV9DQojIERvd25sb2FkIEdPVCBjaGFyYWN0ZXJzIGZyb20gYWxsIGJvb2tzIChwb3RlbnRpYWxseSAyNTAwIGNoYXJhY3RlcnMpIA0KZ290X2NoYXJhY3RlcnMgPC0gDQogICAgbWFwKDE6NTAsIH5nb3RfYXBpKHR5cGUgPSAiY2hhcmFjdGVycyIsIA0KICAgICAgICAgICAgICAgICAgICAgICBxdWVyeSA9IGxpc3QocGFnZSA9IC54LCBwYWdlU2l6ZSA9ICI1MCIpKSkgJT4lDQogICAgdW5saXN0KHJlY3Vyc2l2ZSA9IEZBTFNFKQ0KDQpgYGANCg0KV2UgY29sbGVjdGVkIGEgd2hvb3BpbmcgYHIgbGVuZ3RoKGdvdF9jaGFyYWN0ZXJzKWAgY2hhcmFjdGVycyBmcm9tIHRoZSBHYW1lIG9mIFRocm9uZXMgdW5pdmVyc2UhDQoNCkluIHRoZSBuZXh0IGJsb2NrLCB3ZSB0cmFuc2Zvcm0gdGhlIGRhdGEgZnJvbSB0aGUgYXdrd2FyZCBoaWVyYXJjaGljYWwgZGF0YSBzdHJ1Y3R1cmUgaW50byBhIGRhdGEgZnJhbWUsIHRoYXQgaXMgZWFzeSB0byB1c2UuIFdlIGFsc28gY2xlYW4gdGhlIGRhdGEgdG8gZ2V0IG1lYW5pbmdmdWwgdmFyaWFibGVzLiANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgY2FjaGU9VFJVRX0NCiMgUHV0IGxpc3QgZGF0YSBpbnRvIG5lc3RlZCBkYXRhIGZyYW1lDQojIERhdGEgcmVjdGFuZ2xpbmcNCmdvdF9kZiA8LQ0KICAgIGdvdF9jaGFyYWN0ZXJzICU+JQ0KICAgIHRpYmJsZSggIyBDcmVhdGUgYW4gYW5hbHl6YWJsZSBkYXRhIGZyYW1lIGZyb20gdGhlIGNvbXBsZXggbGlzdCBvYmplY3QNCiAgICAgICAgdXJsID0gbWFwX2NociguLCAidXJsIiksDQogICAgICAgIGlkID0gc3RyX2V4dHJhY3QodXJsLCAiXFxkKyIpICU+JSBhcy5pbnRlZ2VyKCksDQogICAgICAgIG5hbWUgPSBtYXBfY2hyKC4sICJuYW1lIiksDQogICAgICAgIGdlbmRlciA9IG1hcF9jaHIoLiwgImdlbmRlciIpLA0KICAgICAgICBjdWx0dXJlID0gbWFwX2NociguLCAiY3VsdHVyZSIpLA0KICAgICAgICBib3JuID0gbWFwX2NociguLCAiYm9ybiIpLA0KICAgICAgICBkaWVkID0gbWFwX2NociguLCAiZGllZCIpLA0KICAgICAgICB0aXRsZXMgPSBtYXAoLiwgInRpdGxlcyIpLA0KICAgICAgICBhbGlhc2VzID0gbWFwKC4sICJhbGlhc2VzIiksDQogICAgICAgIGZhdGhlciA9IG1hcF9jaHIoLiwgImZhdGhlciIpLA0KICAgICAgICBtb3RoZXIgPSBtYXBfY2hyKC4sICJtb3RoZXIiKSwNCiAgICAgICAgc3BvdXNlID0gbWFwX2NociguLCAic3BvdXNlIiksDQogICAgICAgIGFsbGVnaWFuY2VzID0gbWFwKC4sICJhbGxlZ2lhbmNlcyIpLA0KICAgICAgICBib29rcyA9IG1hcCguLCAiYm9va3MiKSwNCiAgICAgICAgcG92Qm9va3MgPSBtYXAoLiwgInBvdkJvb2tzIiksDQogICAgICAgIHR2U2VyaWVzID0gbWFwKC4sICJ0dlNlcmllcyIpLA0KICAgICAgICBwbGF5ZWRCeSA9IG1hcCguLCAicGxheWVkQnkiKQ0KICAgICkgJT4lIA0KICAgIHNlbGVjdCgtMSkgJT4lIA0KICAgIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsDQogICAgICAgICAgICAgIH5pZl9lbHNlKHN0cl90cmltKC4pID09ICIiLCBOQV9jaGFyYWN0ZXJfLCAuKSkgJT4lICMgRXhwbGljaXQgTkENCiAgICByb3d3aXNlKCkgJT4lIA0KICAgIG11dGF0ZSgNCiAgICAgICAgYWxpYXNfbGVuZ3RoID0gbGVuZ3RoKGFsaWFzZXMpLCAjIEhvdyBtYW55IGFsaWFzZXMgZG9lcyB0aGUgcGVyc29uIGhhdmUNCiAgICAgICAgYWxpYXNfbmFtZXMgPSB1bmxpc3QoYWxpYXNlcykgJT4lIHBhc3RlKGNvbGxhcHNlID0gIjsgIiksICMgQ29sbGFwc2UgYWxpYXNlcyB0byBvbmUgc3RyaW5nDQogICAgICAgIGhhc19zcG91c2UgPSBpZl9lbHNlKCFpcy5uYShzcG91c2UpLCBUUlVFLCBGQUxTRSksICMgSGF2ZSBhIHNwb3VzZT8NCiAgICAgICAgYmlydGhfZXJhID0gc3RyX3RvX3VwcGVyKGJvcm4pICU+JSBzdHJfZXh0cmFjdCgiQUN8QkMiKSwgIyBCaXJ0aCBhbmQgZGVhdGggeWVhcg0KICAgICAgICBiaXJ0aF95ZWFyID0gc3RyX2V4dHJhY3QoYm9ybiwgIlxcZCsiKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKCkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShiaXJ0aF9lcmEgPT0gIkJDIiwgYC1gKC4pLCAuKSwgICMgSWYgQkMsIG1ha2UgaXQgbmVnYXRpdmUNCiAgICAgICAgZGVhdGhfZXJhID0gc3RyX2V4dHJhY3Qoc3RyX3RvX3VwcGVyKGRpZWQpLCAiQUN8QkMiKSwNCiAgICAgICAgZGVhdGhfeWVhciA9IHN0cl9leHRyYWN0KGRpZWQsICJcXGQrIikgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYygpICU+JSANCiAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoZGVhdGhfZXJhID09ICJCQyIsIGAtYCguKSwgLiksICMgSWYgQkMsIG1ha2UgaXQgbmVnYXRpdmUNCiAgICAgICAgYmlydGhfcGxhY2UgPSBzdHJfdG9fdGl0bGUoYm9ybikgJT4lICMgQmlydGggYW5kIGRlYXRoIHBsYWNlIA0KICAgICAgICAgICAgICAgICAgICAgIHN0cl9leHRyYWN0KCIoPzw9QXQgKS4qIikgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgIHN0cl9yZW1vdmVfYWxsKCJOZWFyIHxPciAiKSwgDQogICAgICAgIGRlYXRoX3BsYWNlID0gc3RyX3RvX3RpdGxlKGRpZWQpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICBzdHJfZXh0cmFjdCgiKD88PUF0ICkuKiIpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICBzdHJfcmVtb3ZlX2FsbCgiTmVhciB8T3IgIiksDQogICAgICAgIGlzX2FsaXZlID0gaWZfZWxzZShpcy5uYShkaWVkKSAmIDMwMCAtIGJpcnRoX3llYXIgPCAxMDAsIFRSVUUsIEZBTFNFKSwgIyBBbGl2ZT8NCiAgICAgICAgYWdlID0gaWZfZWxzZShpc19hbGl2ZSwgMzAwIC0gYmlydGhfeWVhciwgZGVhdGhfeWVhciAtIGJpcnRoX3llYXIpKSAlPiUgIyBBZ2UgKG9yIGFnZSB3aGVuIGRpZWQpDQogICAgbXV0YXRlX2F0KHZhcnMoYmlydGhfcGxhY2UsIGRlYXRoX3BsYWNlKSwgfnN0cl9yZW1vdmUoLiwgIlxcKC4qXFwpIikgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfdHJpbSgpKSAlPiUNCiAgICB1bmdyb3VwKCkNCmBgYA0KIyBCaXJ0aCBhbmQgZGVhdGggaW4gdGhlIHdvcmxkIG9mIEdhbWUgb2YgVGhyb25lcw0KDQpCaXJ0aHMgc2hvdyBhIHNtb290aCBwYXR0ZXJuIHdpdGhvdXQgc3VkZGVuIGluY3JlYXNlcy4gDQpUaGUgbnVtYmVyIG9mIGRlYXRocyBzZWVtcyB0byBzaG93IGEgZmV3IHN1ZGRlbiBpbmNyZWFzZXMgYXJvdW5kIDEzNSBBQywgMjEwQUMsIDI4MEFDIGFuZCBtb3N0IG5vdGFibHkgYXJvdW5kIDMwMEFDLiBUaGVzZSBsaWtlbHkgY29pbmNpZGUgd2l0aCBzaWduaWZpY2FudCBldmVudCAtIHN1Y2ggYXMgd2FycyBvciBjYXRhc3Ryb3BoZXMgLSBpbiB0aGUgaGlzdG9yeSBvZiBBU09JRi4NCg0KT2YgY291cnNlIHRoZSBjb25jbHVzaW9uIGlzIG5vdDogYnkgMzAwIEFDIG1vcmUgcGVvcGxlIGRpZSB0aGFuIHdhcyBib3JuLCBiZWNhdXNlIHRoZSBkYXRhIGlzIGhlYXZpbHkgYmlhc2VkIGJ5IG1pc3NpbmcgdmFsdWVzLiBBcyB3ZSBnZXQgY2xvc2VyIHRvIHRoZSBldmVudHMgb2YgdGhlIGJvb2tzLCBtb3JlIGFuZCBtb3JlIGJpcnRoIGFuZCBkZWF0aCBkYXRlcyBhcmUgZG9jdW1lbnRlZC4gU3RpbGwsIGl0IGlzIHRlbGxpbmcgdGhhdCBieSAzMDAsIG1vcmUgZGVhdGhzIGFyZSBkb2N1bWVudGVkIHRoYW4gYmlydGhzLi4uDQoNCmBgYHtyfQ0KY3VtdWxhdGl2ZV9iaXJ0aCA8LQ0KICAgIGdvdF9kZiAlPiUgDQogICAgZ3JvdXBfYnkoeWVhciA9IGJpcnRoX3llYXIpICU+JSANCiAgICBzdW1tYXJpc2UoeWVhcmx5X2JpcnRoID0gc3VtKCFpcy5uYShiaXJ0aF95ZWFyKSkpICU+JSANCiAgICB1bmdyb3VwKCkgJT4lIA0KICAgIHRyYW5zbXV0ZSh5ZWFyLCBiaXJ0aCA9IGN1bXN1bSh5ZWFybHlfYmlydGgpKQ0KDQpjdW11bGF0aXZlX2RlYXRoIDwtDQogICAgZ290X2RmICU+JSANCiAgICBncm91cF9ieSh5ZWFyID0gZGVhdGhfeWVhcikgJT4lIA0KICAgIHN1bW1hcmlzZSh5ZWFybHlfZGVhdGggPSBzdW0oIWlzLm5hKGRlYXRoX3llYXIpKSkgJT4lIA0KICAgIHVuZ3JvdXAoKSAlPiUgDQogICAgdHJhbnNtdXRlKHllYXIsIGRlYXRoID0gY3Vtc3VtKHllYXJseV9kZWF0aCkpICU+JSANCiAgICBkcm9wX25hKCkNCiAgICANCiAgICB0aWJibGUoeWVhciA9IC0yODozMDApICU+JSANCiAgICBsZWZ0X2pvaW4oY3VtdWxhdGl2ZV9iaXJ0aCwgYnkgPSAieWVhciIpICU+JSANCiAgICBsZWZ0X2pvaW4oY3VtdWxhdGl2ZV9kZWF0aCwgYnkgPSAieWVhciIpICU+JSANCiAgICBnYXRoZXIoZXZlbnQsIG51bWJlciwgLXllYXIsIG5hLnJtID0gVFJVRSkgJT4lIA0KICAgICAgICBnZ3Bsb3QoKSArDQogICAgICAgIGFlcyh4ID0geWVhciwgeSA9IG51bWJlciwgY29sb3IgPSBldmVudCkgKw0KICAgICAgICBnZW9tX2xpbmUoc2l6ZSA9IDIpICsNCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6dW5pdF9mb3JtYXQodW5pdCA9ICJBLkMuIikpICsNCiAgICAgICAgc2NhbGVfY29sb3JfZ290X2Qob3B0aW9uID0gIk1hcnRlbGwiKSArDQogICAgICAgIGxhYnModGl0bGUgPSAiQ3VtdWxhdGl2ZSBudW1iZXIgb2YgYmlydGhzIGFuZCBkZWF0aHMgb3ZlciB0aW1lIGZvciBuYW1lZCBjaGFyYWN0ZXJzIGluIEFTT0lGIiwNCiAgICAgICAgICAgICB5ID0gIkN1bXVsYXRpdmUgbnVtYmVyIG9mIGV2ZW50cyIsDQogICAgICAgICAgICAgY29sb3IgPSAiRXZlbnQiKQ0KDQpgYGANCg0KDQojIExldCdzIHBsb3QgYSBtYXAgb2YgYWxsIHRoZSBkZWF0aHMgYW5kIGJpcnRocyBvbiBhIHByb3BlciBXZXN0ZXJvcyBtYXAhDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgUHJlcGFyZSB0aGUgZGF0YSBmb3IgdGhlIGFuaW1hdGlvbg0KY29udGluZW50cyA8LSByZWFkT0dSKCJtYXAiLCAiY29udGluZW50cyIpDQp3ZXN0ZXJvcyA8LSByZWFkT0dSKCJtYXAiLCAicG9saXRpY2FsIikgIyBUaGUgYWN0dWFsIG1hcA0KaXNsYW5kcyA8LSByZWFkT0dSKCJtYXAiLCAiaXNsYW5kcyIpDQpsb2NhdGlvbnMgPC0gcmVhZE9HUigibWFwIiwgImxvY2F0aW9ucyIpICMgUGxhY2VzIGRhdGENCg0KcGxhY2VzIDwtDQogICAgYmluZF9jb2xzKGxvY2F0aW9uc0BkYXRhLCBhc190aWJibGUobG9jYXRpb25zQGNvb3JkcykpICU+JSANCiAgICBhc190aWJibGUoKSAlPiUNCiAgICBzZWxlY3QoaWQsIHBsYWNlID0gbmFtZSwgDQogICAgICAgICAgIHBsYWNlX3NpemUgPSBzaXplLCBwbGFjZV90eXBlID0gdHlwZSwgDQogICAgICAgICAgIGxhdCA9IGNvb3Jkcy54MSwgbG9uZyA9IGNvb3Jkcy54MikgJT4lIA0KICAgIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLmNoYXJhY3RlcikgJT4lDQogICAgbXV0YXRlX2F0KHZhcnMoaWQsIHBsYWNlX3NpemUpLCBhcy5pbnRlZ2VyKSAlPiUgDQogICAgZHJvcF9uYShwbGFjZSkNCg0KY29vcmRpbmF0ZXMgIDwtDQogICAgZ290X2RmICU+JQ0KICAgIGRyb3BfbmEobmFtZSkgJT4lIA0KICAgICMgQWRkIG1vcmUgcHJlY2lzZSBwbGFjZSBuYW1lcyBhcyByb3dzLCB0aGlzIHdpbGwgZHVwbGljYXRlIHNvbWUgcm93cywgYnV0IHdpbGwgbWFrZQ0KICAgICMgaXQgcG9zc2libGUgdG8gbWF0Y2ggbW9yZSBwbGFjZSBuYW1lcw0KICAgIHNlcGFyYXRlX3Jvd3MoYmlydGhfcGxhY2UsIHNlcCA9ICIsIikgJT4lIA0KICAgIHNlcGFyYXRlX3Jvd3MoZGVhdGhfcGxhY2UsIHNlcCA9ICIsIikgJT4lIA0KICAgICMgQWRkIHBlZml4ZXMgdG8gYmlydGggYW5kIGRlYXRoIGluZm8gYW5kIGpvaW4gdGhlbSB0byB0aGlzIGRhdGFzZXQNCiAgICBsZWZ0X2pvaW4ocmVuYW1lX2FsbChwbGFjZXMsIH5wYXN0ZTAoImJpcnRoXyIsIC4pKSwgYnkgPSAiYmlydGhfcGxhY2UiKSAlPiUgDQogICAgbGVmdF9qb2luKHJlbmFtZV9hbGwocGxhY2VzLCB+cGFzdGUwKCJkZWF0aF8iLCAuKSksIGJ5ID0gImRlYXRoX3BsYWNlIikgJT4lIA0KICAgICMgTm93LCBmaWxsIHVwIHRoZSBub24tcmVjb2duaXplZCBjb29yZGluYXRlcyBieSB0aGUgcmVjb2duaXplZCBvbmVzDQogICAgIyBhcnJhbmdlIHdpbGwgbWFrZSBzdXJlIHRoYXQgdGhlIHJlY29nbml6ZWQgd2lsbCBiZSBvbiB0b3Agd2hlbiB0aGVyZSBhcmUgbW9yZSBwbGFjZXMNCiAgICBncm91cF9ieShpZCkgJT4lIA0KICAgIGFycmFuZ2UoYmlydGhfbG9uZywgZGVhdGhfbG9uZywgLmJ5X2dyb3VwID0gVFJVRSkgJT4lIA0KICAgIGZpbGwoYmlydGhfbG9uZywgYmlydGhfbGF0LCBkZWF0aF9sb25nLCBkZWF0aF9sYXQpICU+JSANCiAgICB1bmdyb3VwKCkgJT4lIA0KICAgICMgS2VlcCBvbmx5IHVuaXF1ZSBjaGFyYWN0ZXJzDQogICAgZGlzdGluY3QoaWQsIC5rZWVwX2FsbCA9IFRSVUUpDQoNCiMgQ3JlYXRlIGEgZGF0YXNldCB3aXRoIGFsbCBub3RhYmxlIGV2ZW50cyBieSB0aW1lIGFuZCBwbGFjZQ0KZGVhdGhfYmlydGggPC0NCiAgICBjb29yZGluYXRlcyAlPiUgDQogICAgc2VsZWN0KGlkLCBuYW1lLCBtYXRjaGVzKCJfeWVhciR8X2xhdCR8X2xvbmckfF9wbGFjZSQiKSkgJT4lIA0KICAgIGdhdGhlcih2YXJpYWJsZSwgdmFsdWUsIC1pZCwgLW5hbWUsIG5hLnJtID0gVFJVRSkgJT4lIA0KICAgIHNlcGFyYXRlKHZhcmlhYmxlLCBjKCJldmVudCIsICJ2YXJpYWJsZSIpLCBzZXAgPSAiXyIpICU+JSANCiAgICBzcHJlYWQodmFyaWFibGUsIHZhbHVlLCBjb252ZXJ0ID0gVFJVRSkgJT4lIA0KICAgIGRyb3BfbmEoKSAlPiUgDQogICAgZGlzdGluY3QobmFtZSwgZXZlbnQsIC5rZWVwX2FsbCA9IFRSVUUpICU+JSANCiAgICBtdXRhdGUoZGVjYWRlID0gZmxvb3IoeWVhci8xMCkqMTApICU+JSANCiAgICBhcnJhbmdlKHllYXIpDQoNCmV2ZW50X3BsYWNlcyA8LQ0KICAgIGRlYXRoX2JpcnRoICU+JSANCiAgICBjb3VudChldmVudCwgZGVjYWRlLCBsYXQsIGxvbmcsIHBsYWNlKSAlPiUgDQogICAgIyBOZWVkIHRvIGFkZCBkZWNhZGVzIHRoYXQgaGFzIG5vIGRhdGEgZm9yIHRoZSBhbmltYXRpb24gbGF0ZXINCiAgICBmdWxsX2pvaW4oY3Jvc3NpbmcoZGVjYWRlID0gc2VxKC0zMCwgMzAwLCAxMCksIA0KICAgICAgICAgICAgICAgICAgICAgICBldmVudCA9IGMoImJpcnRoIiwgImRlYXRoIikpLCANCiAgICAgICAgICAgICAgYnkgPSBjKCJldmVudCIsICJkZWNhZGUiKSkgJT4lIA0KICAgIGFycmFuZ2UoZGVjYWRlKQ0KDQpkZWF0aF9wbGFjZXMgPC0NCiAgICBldmVudF9wbGFjZXMgJT4lIA0KICAgIGZpbHRlcihldmVudCA9PSAiZGVhdGgiKSAlPiUgDQogICAgZ3JvdXBfYnkobGF0LCBsb25nLCBwbGFjZSkgJT4lIA0KICAgIHN1bW1hcmlzZShuID0gc3VtKG4pKSAlPiUgDQogICAgZHJvcF9uYSgpDQogICAgDQpgYGANCg0KYGBge3J9DQojIFBsb3QgYSBibGFuayBtYXAgZmlyc3QNCmJhc2VfbWFwIDwtDQogICAgZ2dwbG90KCkgKw0KICAgICMgQWRkcyB0aGUgY29udGluZW50cw0KICAgIGdlb21fcG9seWdvbihkYXRhID0gY29udGluZW50cywgDQogICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksIA0KICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAid2hlYXQiKSArDQogICAgIyBBZGRzIHRoZSBpc2xhbmRzDQogICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBpc2xhbmRzLCANCiAgICAgICAgICAgICAgICAgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gIndoZWF0IikgKw0KICAgICMgQWRkcyB0aGUga2luZ2RvbWVzIG9mIHdlc3Rlcm9zDQogICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSB3ZXN0ZXJvcywNCiAgICAgICAgICAgICAgICAgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gIndoZWF0IikgKw0KICAgIGNvb3JkX21hcCh4bGltID0gYygtMTAsIDc1KSwgeWxpbSA9IGMoLTE1LCA1MCkpICsNCiAgICB0aGVtZV9tYXAoKSArDQogICAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImxpZ2h0Ymx1ZSIpKQ0KYGBgDQoNCg0KIyBMZXQncyBwbG90IGFsbCB0aGUgcGxhY2VzIHdoZXJlIGVhY2ggbm90YWJsZSBkZWF0aCBoYXBwZW5lZCENCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmJhc2VfbWFwICsNCiAgICBnZW9tX3BvaW50KGRhdGEgPSBkZWF0aF9wbGFjZXMsIA0KICAgICAgICAgICAgICAgYWVzKHggPSBsYXQsIHkgPSBsb25nLCBzaXplID0gbikpICsNCiAgICBzY2FsZV9jb2xvcl9nb3Qob3B0aW9uID0gIkdyZXlqb3kiLCBkaXJlY3Rpb24gPSAxKSArDQogICAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMiwgNykpICsNCiAgICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGRlYXRoX3BsYWNlcywgDQogICAgICAgICAgICAgIGFlcyh4ID0gbGF0LCB5ID0gbG9uZywgbGFiZWwgPSBwbGFjZSkpICsNCiAgICBsYWJzKHRpdGxlID0gIkRlYWRsaWVzdCBwbGFjZXMgaW4gdGhlIHdvcmQgb2YgQVNPSUYiLA0KICAgICAgICAgc2l6ZSA9ICJBbGwgbm90YWJsZSBkZWF0aHMiKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikNCmBgYA0KDQpJZiB3ZSBhbHNvIHdhbnRlZCB0byBpbmNsdWRlIGEgdGltZWxpbmUsIHdlIGNvdWxkIGRvIGFuIGFuaW1hdGVkIG1hcCBvZiBhbGwgZGVhdGhzLiANCg0KYGBge3J9DQpldmVudF9tYXAgPC0NCiAgICBiYXNlX21hcCArDQogICAgZ2VvbV9wb2ludChkYXRhID0gZmlsdGVyKGV2ZW50X3BsYWNlcywgZXZlbnQgPT0gImRlYXRoIiksDQogICAgICAgICAgICAgICBhZXMoeCA9IGxhdCwNCiAgICAgICAgICAgICAgICAgICB5ID0gbG9uZywNCiAgICAgICAgICAgICAgICAgICBzaXplID0gbikpICsNCiAgICBzY2FsZV9jb2xvcl9nb3RfZChvcHRpb24gPSAiVGFyZ2FyeWVuIiwgZGlyZWN0aW9uID0gLTEpICsNCiAgICBzY2FsZV9zaXplKHJhbmdlID0gYygzLCA3KSkgKw0KICAgIGdlb21fdGV4dChkYXRhID0gZmlsdGVyKGV2ZW50X3BsYWNlcywgZXZlbnQgPT0gImRlYXRoIiksDQogICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvbmcsDQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBsYWNlKSkgKw0KICAgIGxhYnModGl0bGUgPSAiRGVhdGhzIG9mIGNoYXJhY3RlcnMgb3ZlciB0aW1lIGluIHRoZSB7Y2xvc2VzdF9zdGF0ZX1zIiwNCiAgICAgICAgIGNvbG9yID0gIkV2ZW50IiwNCiAgICAgICAgIHNpemUgPSAiTm90YWJsZSBkZWF0aHMgYnkgZGVjYWRlIikgKw0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsNCiAgICB0cmFuc2l0aW9uX3N0YXRlcyhkZWNhZGUpICsNCiAgICBlYXNlX2FlcygicXVhZHJhdGljLWluLW91dCIpICsNCiAgICBlbnRlcl9ncm93KCkgKw0KICAgIGV4aXRfZmFkZSgpDQogICAgDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0NCmFuaW1hdGUoZXZlbnRfbWFwLCBuZnJhbWVzID0gMjAwLCBlbmRfcGF1c2UgPSAzMCwgZnBzID0gMTAsDQogICAgICAgIHdpZHRoID0gOTAwLCBoZWlnaHQgPSA1MDApDQpgYGANCg0KDQoNCiMgQW5hbHlzaXMgcXVlc3Rpb246IElzIHRoZXJlIGEgc21hbGxlciBjaGFuY2Ugb2Ygc3Vydml2YWwgaW4gZ2FtZSBvZiB0aHJvbmVzIGFmdGVyIG1hcnJpYWdlPw0KDQo8Y2VudGVyPg0KIVtdKGh0dHBzOi8vbWVkaWEuZ2lwaHkuY29tL21lZGlhL1N0QUxBdE1tRTNNSk8vZ2lwaHkuZ2lmKQ0KPC9jZW50ZXI+DQoNClBlb3BsZSBkaWUgbGVmdCBhbmQgcmlnaHQgaW4gZ2FtZSBvZiB0aHJvbmVzLCBidXQgbm8gb2NjYXNpb24gaXMgYXMgZGVhZGx5IGFzIGEgd2VkZGluZy4gQnV0IHdoYXQgYWJvdXQgbWFycmlhZ2U/IEhvdyBwZW9wbGUgZmFyZSBpZiB0aGV5IHN1cnZpdmVkIHRoZWlyIHdlZGRpbmc/IEluIHJlYWwgbGlmZSwgbGlmZXRpbWUgZXhwZWN0YW5jeSBpcyBpbmNyZWFzZWQgYnkgbWFycmlhZ2UsIHdoaWNoIGlzIG9idmlvdXNseSBub3QgdGhlIGNhc2UgaW4gR2FtZSBvZiBUaHJvbmVzLiBCdXQgZXhhY3RseSBob3cgZGFuZ2Vyb3VzIGlzIHRvIGJlIG1hcnJpZWQgaW4gR09UPyANCg0KV2UgYXJlIGJ1aWxkaW5nIGEgY294IHJlZ3Jlc3Npb24gb24gZ290IGNoYXJhY3RlciBkYXRhIHdpdGggdGhlIG91dGNvbWUgdmFyaWFibGUgdGhhdCBzaG93cyBpZiB0aGUgY2hhcmFjdGVyIGlzIGFsaXZlIG9yIG5vdCBhdCBwYXJ0aWN1bGFyIGFnZXMuIA0KV2UgYXJlIG9ubHkgbG9va2luZyBmb3IgbWFpbiBlZmZlY3RzIG9mIG1hcml0YWwgc3RhdHVzIChpZiB0aGUgY2hhcmFjdGVyIGhhcyBhIHNwb3VzZSkuIA0KRGlzY2xhaW1lcjogVGhpcyBpcyBvYnZpb3VzbHkgYSB2ZXJ5IHNpbXBsZSBtaW5kZWQgYW5hbHlzaXMsIGFuZCBJIG9ubHkgZGlkIHRoYXQgdG8gc2hvdyBob3cgdGhpcyBraW5kIG9mIHN0dWZmIGNhbiBiZSBkb25lIGluIFIuDQoNCmBgYHtyfQ0KZ290X2RmICU+JSANCiAgICBzZWxlY3QoaXNfYWxpdmUsIGhhc19zcG91c2UsIGdlbmRlcikgJT4lIA0KICAgIGZ0YWJsZSgpDQpgYGANCg0KVG8gZXhwbG9yZSBkYXRhLCB3ZSBjcmVhdGUgYSBib3ggcGxvdCB2aXN1YWxpemF0aW9uIGFib3V0IGFnZSBieSBnZW5kZXIgYnkgbWFyaXRhbCBzdGF0dXMgYnkgc3Vydml2YWwgc3RhdHVzIChiYXNlZCBvbiA0NTggY2hhcmFjdGVycykuDQoNCmBgYHtyfQ0KZ290X2RmICU+JSANCiAgICBkcm9wX25hKGlzX2FsaXZlLCBoYXNfc3BvdXNlLCBnZW5kZXIsIGFnZSkgJT4lIA0KICAgIGdncGxvdCgpICsNCiAgICAgIGFlcyh5ID0gYWdlLCB4ID0gZ2VuZGVyLCBmaWxsID0gZ2VuZGVyKSArDQogICAgICBnZW9tX2JveHBsb3QoKSArDQogICAgICBmYWNldF9ncmlkKGlzX2FsaXZlfmhhc19zcG91c2UsIGxhYmVsbGVyID0gbGFiZWxfYm90aCkNCmBgYA0KDQpOb3cgd2UgY3JlYXRlIHR3byBzdGF0aXN0aWNhbCBtb2RlbHMgKENveCByZWdyZXNzaW9uKSB0byB0ZXN0IHRoZSBlZmZlY3Qgb2YgdGhlIHByZWRpY3RvcnMgb24gdGhlIG91dGNvbWUgdmFyaWFibGUgKHN1cnZpdmFsIHN0YXR1cykuDQoNCg0KYGBge3J9DQpzdXJ2aXZhbF9kZiA8LQ0KICBnb3RfZGYgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGlzX2FsaXZlKSkgJT4lIA0KICBtdXRhdGUoZGVhdGhfeWVhciA9IGlmX2Vsc2UoaXNfYWxpdmUgPT0gVFJVRSAmIGJpcnRoX3llYXIgPj0gMjAwLCAzMDEsIGRlYXRoX3llYXIpLA0KICAgICAgICAgc3RhdHVzID0gaWZfZWxzZShpc19hbGl2ZSA9PSBUUlVFLCAwLCAxKSwNCiAgICAgICAgIGFnZSA9IGRlYXRoX3llYXIgLSBiaXJ0aF95ZWFyKSAlPiUgDQogIGRyb3BfbmEoZGVhdGhfeWVhcikNCg0Kc3Vydml2YWxfbW9kZWwxIDwtIGNveHBoKFN1cnYoYWdlLCBzdGF0dXMpIH4gaGFzX3Nwb3VzZSwgZGF0YSA9IHN1cnZpdmFsX2RmKQ0Kc3Vydml2YWxfbW9kZWwyIDwtIGNveHBoKFN1cnYoYWdlLCBzdGF0dXMpIH4gaGFzX3Nwb3VzZSArIGdlbmRlciwgZGF0YSA9IHN1cnZpdmFsX2RmKQ0KICAgIA0KQUlDKHN1cnZpdmFsX21vZGVsMSwgc3Vydml2YWxfbW9kZWwyKQ0KYGBgDQoNClRoZSBtb2RlbHMgc2hvdyB0aGF0IGJlaW5nIG1hcnJpZWQgaXMgYSBzaWduaWZpY2FudCBoZWFsdGggcmlzayBpbiB0aGUgd29ybGQgb2YgQVNPSUYuDQpDb21wYXJpbmcgdGhlIG1vZGVscyBzaG93cyB0aGF0IGdlbmRlciBkb2VzIG5vdCBhZGQgbXVjaCB0byB0aGlzIGZpbmRpbmcsIHRoZXJlZm9yZSB3ZSB3aWxsIGp1c3QgdmlzdWFsaXplIHRoZSBvbmUgd2l0aG91dCBnZW5kZXIuDQoNCldlIGFsc28gY2FsY3VsYXRlIG9kZHMgcmF0aW9zLCBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMuIE9kZHMgcmF0aW9zIHN1Z2dlc3QgdGhhdCBpdCBpcyAxLjQgOTUlQ0lbMS4wMyAxLjg4XSB0aW1lcyBtb3JlIGxpa2VseSB0byBkaWUgaWYgYSBjaGFyYWN0ZXIgaXMgbWFycmllZC4NCg0KQXQgZmlyc3QsIHRoZXJlIGlzIGxpdHRsZSBkaWZmZXJlbmNlIGJldHdlZW4gY2hhcmFjdGVycyB3aXRoIGFuZCB3aXRob3V0IHNwb3VzZXMsIGFuZCB5b3VuZyBjaGFyYWN0ZXJzIHdpdGggc3BvdXNlcyBoYXZlIGEgYmV0dGVyIGNoYW5jZSBvZiBzdXJ2aXZhbCBidXQgYWZ0ZXIgYWJvdXQgMzUgeWVhcnMgb2YgYWdlLHRob3NlIHdobyBoYXZlIGEgc3BvdXNlIGRpZSBlYXJsaWVyLg0KDQpOb3QgZ2V0dGluZyB3ZWQgaXMgYSBzaWduaWZpY2FudCBwcmVkaWN0b3Igb2YgbG9uZ2VyIGxpZmUuIFRob3NlIGhhdmluZyBhIHNwb3VzZSBkaWUgYXQgYSBtZWRpYW4gYWdlIG9mIDQ4IHllYXJzIDk1JUNJWzU0IDgwXSwgd2hpbGUgdGhlIHVubWFycmllZCBkaWUgYXQgNjYgeWVhcnMgOTUlQ0lbNDEgNTNdLiBUaGlzIGlzIGEgbWVkaWFuIGRpZmZlcmVuY2Ugb2YgMTggeWVhcnMhDQoNCg0KYGBge3J9DQpzdW1tYXJ5KHN1cnZpdmFsX21vZGVsMSkNCmBgYA0KDQpBbmQgZmluYWxseSwgbGV0J3MgcGxvdCB0aGUgcHJlZGljdGlvbnMgZm9yIHRoZSBzdXJ2aXZhbCBjaGFuY2Ugb3ZlciB0aW1lIGJ5IG1hcml0YWwgc3RhdHVzLg0KDQpgYGB7ciBmaWcud2lkdGg9OSwgd2FybmluZz1GQUxTRX0NCnN1cnZmaXQoU3VydihhZ2UsIHN0YXR1cykgfiBoYXNfc3BvdXNlLCBkYXRhID0gc3Vydml2YWxfZGYpICU+JSANCiAgICBnZ3N1cnYoLiwNCiAgICAgICAgICAgY2Vucy5zaGFwZSA9IDE2LCANCiAgICAgICAgICAgc2l6ZS5lc3QgPSAxLjIpICsNCiAgICBzY2FsZV9jb2xvcl9nb3RfZChvcHRpb24gPSAiR3JleWpveSIsIGRpcmVjdGlvbiA9IDEpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpKSArDQogICAgbGFicyh0aXRsZSA9ICJTdXJ2aXZhbCBvZiBBU09JRiBjaGFyYWN0ZXJzIGJhc2VkIG9uIG1hcml0YWwgc3RhdHVzIiwNCiAgICAgICAgIHN1YnRpdGxlID0gIkF0IGZpcnN0LCB0aGVyZSBpcyBsaXR0bGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGNoYXJhY3RlcnMgd2l0aCBhbmQgd2l0aG91dCBzcG91c2VzLCBhbmQgeW91bmcgY2hhcmFjdGVycyB3aXRoIHNwb3VzZXMgaGF2ZVxuYSBiZXR0ZXIgY2hhbmNlIG9mIHN1cnZpdmFsIGJ1dCBhZnRlciBhYm91dCAzNSB5ZWFycyBvZiBhZ2UsdGhvc2Ugd2hvIGhhdmUgYSBzcG91c2UgZGllIGVhcmxpZXIiLA0KICAgICAgICAgeSA9ICJFc3RpbWF0ZWQgJSBzdXJ2aXZhbCIsIA0KICAgICAgICAgeCA9ICJBZ2UiKSArDQogICAgYW5ub3RhdGUoInRleHQiLA0KICAgICAgICAgICAgIGxhYmVsID0gYygiSGFzIHNwb3VzZSIsICJObyBzcG91c2UiKSwNCiAgICAgICAgICAgICB4ID0gYygxMDAsIDEwMCksDQogICAgICAgICAgICAgeSA9IGMoLjEsIC4yNSksDQogICAgICAgICAgICAgY29sb3IgPSBnb3Qob3B0aW9uID0gIkdyZXlqb3kiLCBkaXJlY3Rpb24gPSAxLCBuID0gMikpICsNCiAgICBndWlkZXMoY29sb3IgPSBGQUxTRSwgbGluZXR5cGUgPSBGQUxTRSkNCmBgYA0KDQojIENvbmNsdXNpb25zDQotIHdlIGxvb2tlZCBhdCBzaWduaWZpY2FudCBsaWZlIGV2ZW50cyAoYmlydGhzIGFuZCBkZWF0aHMpIG9mIG5vdGFibGUgY2hhcmFjdGVycyAgaW4gQVNPSUYNCi0gTWFycmllZCBjaGFyYWN0ZXJzIGRpZSBhcHByb3hpbWF0ZWx5IDE4IHllYXJzIHNvb25lciB0aGFuIHVubWFycmllZCBjaGFyYWN0ZXJzDQoNCg0KPGNlbnRlcj4NCiFbXShodHRwczovL21lZGlhLmdpcGh5LmNvbS9tZWRpYS9vaG9vMDMzMHNVbFRxL2dpcGh5LmdpZikNCjwvY2VudGVyPg0KDQo=