Prepare

Evaluation Questions

EQ1: In what ways, and to what extent, has the Learning Differences program impacted three distinct participant groups: students, parents, and educators over time?

EQ2: What components of the Learning Differences program are most efficacious over time?

Install and Load Packages

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.1.3
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5     v purrr   0.3.4
## v tibble  3.1.6     v dplyr   1.0.8
## v tidyr   1.2.0     v stringr 1.4.0
## v readr   2.1.2     v forcats 0.5.1
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(tidytext)
## Warning: package 'tidytext' was built under R version 4.1.3
library(textdata)
## Warning: package 'textdata' was built under R version 4.1.3
library(readxl)
## Warning: package 'readxl' was built under R version 4.1.3
library(wordcloud2)
## Warning: package 'wordcloud2' was built under R version 4.1.3
library(SnowballC)
library(topicmodels)
library(stm)
## stm v1.3.6 successfully loaded. See ?stm for help. 
##  Papers, resources, and other materials at structuraltopicmodel.com
library(ldatuning)
library(knitr)
library(LDAvis)

Import Data

Data was imported from th e oakcourses.csv source file and selected for the unit number, post content and poster.

raw_summer15 <- read.csv("data/oakcourses_forumposts.csv") |>
  filter(course_id == 8) |>
  select(!c(user_email,username, user_firstname, user_lastname, course_shortname, course_id, course_name, unit_name))

Wrangle

Sample Data

50 entries were randomly selected from each unit, then stitched back together into a single document. This was exported as a .csv to Dion for his analysis.

set.seed(2015)
#Unit 1
unit1 <- raw_summer15 |>
  filter(forum_id == 102) |>
  sample_n(50)
#Unit 2
unit2 <- raw_summer15 |>
  filter(forum_id == 104) |>
  sample_n(50)
#Unit 3
unit3 <- raw_summer15 |>
  filter(forum_id == 108) |>
  sample_n(50)
#Unit 4
unit4 <- raw_summer15 |>
  filter(forum_id == 114) |>
  sample_n(50)
#Unit 5
unit5 <- raw_summer15 |>
  filter(forum_id == 116) |>
  sample_n(50)
#Unit 6
unit6 <- raw_summer15 |>
  filter(forum_id == 132) |>
  sample_n(50)
#recombine into single dataframe
summer15_sample <- rbind(unit1, unit2, unit3, unit4, unit5, unit6)
rm(unit1, unit2, unit3, unit4, unit5, unit6)

Tidy Text

To prepare the text for tokenizing, HTML tags were first stripped from these samples. Then the text was tokenized, filtered for stop words, then relabeled to include a title for each unit (rather than the code number).

#strip HTML tags
summer15_sample$post_content <- gsub("<[^>]+>","", summer15_sample$post_content)
#tokenize & stop
summer15_tidy <- summer15_sample |>
  select(post_content, post_id, forum_name) |>
  unnest_tokens(output = word, 
                input = post_content) |>
  anti_join(stop_words, by = "word") |>
  select(forum_name, post_id, word)
#custom stops
summer15_top_n <- summer15_tidy |>
  select(word) |>
  count(word, sort = TRUE)
custom_stops <- data.frame(word = c("teacher","teachers","student","students","molly","molly's","travis","travis's","travis'","matt","matt's","wyatt","wyatt's","nbsp"))
summer15_tidy <- anti_join(summer15_tidy, custom_stops, by = "word")
#relabel by unit name
summer15_tidy <- summer15_tidy |> 
  mutate(forum_name = str_replace(forum_name, "Discuss: The Myth of Average", "Unit 1")) |>
  mutate(forum_name = str_replace(forum_name, "Discuss: Molly's Story", "Unit 2")) |>
  mutate(forum_name = str_replace(forum_name, "Discuss: Matt's Story", "Unit 3")) |>
  mutate(forum_name = str_replace(forum_name, "Discuss: Travis's Story", "Unit 4")) |>
  mutate(forum_name = str_replace(forum_name, "Discuss: From Your Student's Eyes", "Unit 5")) |>
  mutate(forum_name = str_replace(forum_name, "Discuss: Wyatt's Story", "Unit 6"))

Visualize

Word Clouds

Word clouds can be conducted for individual units or for the entire course. The function filter(forum_name == "Unit X") can be used to focus on a specific unit.

#entire course
summer15cloud <- summer15_tidy |>
  select(word) |>
  count(word, sort = TRUE) |>
  slice(1:50)
wordcloud2(summer15cloud)

LDA

A Latent-Dirichlet Allocation analysis revealed the following terms grouped by category, again for the entire course as well as by unit. First, we cast each sample into a document term matrix and used FindTopicsNumber to identify k, the most coherent number of topics to request the LDA algorithm to produce:

#entire course
summer15_dtm <- summer15_tidy |>
  count(post_id, word) |>
  cast_dtm(post_id, word, n)
k_metrics <- FindTopicsNumber(
  summer15_dtm,
  topics = seq(5, 20, by = 1),
  metrics = "Griffiths2004",
  method = "Gibbs",
  control = list(),
  mc.cores = NA,
  return_models = FALSE,
  verbose = FALSE,
  libpath = NULL)
FindTopicsNumber_plot(k_metrics)
## Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> =
## "none")` instead.

#unit 1
unit1_dtm <- summer15_tidy |>
  filter(forum_name == "Unit 1") |>
  count(post_id, word) |>
  cast_dtm(post_id, word, n)
k_metrics <- FindTopicsNumber(
  unit1_dtm,
  topics = seq(5, 20, by = 1),
  metrics = "Griffiths2004",
  method = "Gibbs",
  control = list(),
  mc.cores = NA,
  return_models = FALSE,
  verbose = FALSE,
  libpath = NULL)
FindTopicsNumber_plot(k_metrics)
## Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> =
## "none")` instead.

#unit 2
unit2_dtm <- summer15_tidy |>
  filter(forum_name == "Unit 2") |>
  count(post_id, word) |>
  cast_dtm(post_id, word, n)
k_metrics <- FindTopicsNumber(
  unit2_dtm,
  topics = seq(5, 20, by = 1),
  metrics = "Griffiths2004",
  method = "Gibbs",
  control = list(),
  mc.cores = NA,
  return_models = FALSE,
  verbose = FALSE,
  libpath = NULL)
FindTopicsNumber_plot(k_metrics)
## Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> =
## "none")` instead.

#unit 3
unit3_dtm <- summer15_tidy |>
  filter(forum_name == "Unit 3") |>
  count(post_id, word) |>
  cast_dtm(post_id, word, n)
k_metrics <- FindTopicsNumber(
  unit3_dtm,
  topics = seq(5, 20, by = 1),
  metrics = "Griffiths2004",
  method = "Gibbs",
  control = list(),
  mc.cores = NA,
  return_models = FALSE,
  verbose = FALSE,
  libpath = NULL)
FindTopicsNumber_plot(k_metrics)
## Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> =
## "none")` instead.

#unit 4
unit4_dtm <- summer15_tidy |>
  filter(forum_name == "Unit 4") |>
  count(post_id, word) |>
  cast_dtm(post_id, word, n)
k_metrics <- FindTopicsNumber(
  unit4_dtm,
  topics = seq(5, 20, by = 1),
  metrics = "Griffiths2004",
  method = "Gibbs",
  control = list(),
  mc.cores = NA,
  return_models = FALSE,
  verbose = FALSE,
  libpath = NULL)
FindTopicsNumber_plot(k_metrics)
## Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> =
## "none")` instead.

#unit 5
unit5_dtm <- summer15_tidy |>
  filter(forum_name == "Unit 5") |>
  count(post_id, word) |>
  cast_dtm(post_id, word, n)
k_metrics <- FindTopicsNumber(
  unit5_dtm,
  topics = seq(5, 20, by = 1),
  metrics = "Griffiths2004",
  method = "Gibbs",
  control = list(),
  mc.cores = NA,
  return_models = FALSE,
  verbose = FALSE,
  libpath = NULL)
FindTopicsNumber_plot(k_metrics)
## Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> =
## "none")` instead.

#unit 6
unit6_dtm <- summer15_tidy |>
  filter(forum_name == "Unit 6") |>
  count(post_id, word) |>
  cast_dtm(post_id, word, n)
k_metrics <- FindTopicsNumber(
  unit6_dtm,
  topics = seq(5, 20, by = 1),
  metrics = "Griffiths2004",
  method = "Gibbs",
  control = list(),
  mc.cores = NA,
  return_models = FALSE,
  verbose = FALSE,
  libpath = NULL)
FindTopicsNumber_plot(k_metrics)
## Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> =
## "none")` instead.

Having identified the variable k that is most coherent (highest on the y axis) for each unit’s sample, we then applied an LDA to each unit and plotted the resulting terms to a faceted bar chart:

#LDA
#entire course
summer15_lda <- LDA(summer15_dtm, 
                 k = 15, 
                 control = list(seed = 2015))
summer15_lda <- tidy(summer15_lda)
summer15_top_lda <- summer15_lda |>
  group_by(topic) |>
  slice_max(beta, n = 5, with_ties = FALSE) |>
  ungroup() |>
  arrange(topic, -beta)
summer15_top_lda |>
  mutate(term = reorder_within(term, beta, topic)) |>
  group_by(topic, term) |>    
  arrange(desc(beta)) |>  
  ungroup() |>
  ggplot(aes(beta, term, fill = as.factor(topic))) +
  geom_col(show.legend = FALSE) +
  scale_y_reordered() +
  labs(title = "Summer 2015: Top 5 LDA Terms",
       x = expression(beta), y = NULL) +
  facet_wrap(~ topic, ncol = 4, scales = "free")

#unit 1
unit1_lda <- LDA(unit1_dtm, 
                 k = 14, 
                 control = list(seed = 2015))
unit1_lda <- tidy(unit1_lda)
unit1_top_lda <- unit1_lda |>
  group_by(topic) |>
  slice_max(beta, n = 5, with_ties = FALSE) |>
  ungroup() |>
  arrange(topic, -beta)
unit1_top_lda |>
  mutate(term = reorder_within(term, beta, topic)) |>
  group_by(topic, term) |>    
  arrange(desc(beta)) |>  
  ungroup() |>
  ggplot(aes(beta, term, fill = as.factor(topic))) +
  geom_col(show.legend = FALSE) +
  scale_y_reordered() +
  labs(title = "Unit 1:Top 5 LDA Terms",
       x = expression(beta), y = NULL) +
  facet_wrap(~ topic, ncol = 4, scales = "free")

#unit 2
unit2_lda <- LDA(unit2_dtm, 
                     k = 18, 
                     control = list(seed = 2015))
unit2_lda <- tidy(unit2_lda)
unit2_top_lda <- unit2_lda |>
  group_by(topic) |>
  slice_max(beta, n = 5, with_ties = FALSE) |>
  ungroup() |>
  arrange(topic, -beta)
unit2_top_lda |>
  mutate(term = reorder_within(term, beta, topic)) |>
  group_by(topic, term) |>    
  arrange(desc(beta)) |>  
  ungroup() |>
  ggplot(aes(beta, term, fill = as.factor(topic))) +
  geom_col(show.legend = FALSE) +
  scale_y_reordered() +
  labs(title = "Unit 2:Top 5 LDA Terms",
       x = expression(beta), y = NULL) +
  facet_wrap(~ topic, ncol = 4, scales = "free")

#unit 3
unit3_lda <- LDA(unit3_dtm, 
                 k = 19, 
                 control = list(seed = 2015))
unit3_lda <- tidy(unit3_lda)
unit3_top_lda <- unit3_lda |>
  group_by(topic) |>
  slice_max(beta, n = 5, with_ties = FALSE) |>
  ungroup() |>
  arrange(topic, -beta)
unit3_top_lda |>
  mutate(term = reorder_within(term, beta, topic)) |>
  group_by(topic, term) |>    
  arrange(desc(beta)) |>  
  ungroup() |>
  ggplot(aes(beta, term, fill = as.factor(topic))) +
  geom_col(show.legend = FALSE) +
  scale_y_reordered() +
  labs(title = "Unit 3:Top 5 LDA Terms",
       x = expression(beta), y = NULL) +
  facet_wrap(~ topic, ncol = 4, scales = "free")

#unit 4
unit4_lda <- LDA(unit4_dtm, 
                 k = 12, 
                 control = list(seed = 2015))
unit4_lda <- tidy(unit4_lda)
unit4_top_lda <- unit4_lda |>
  group_by(topic) |>
  slice_max(beta, n = 5, with_ties = FALSE) |>
  ungroup() |>
  arrange(topic, -beta)
unit4_top_lda |>
  mutate(term = reorder_within(term, beta, topic)) |>
  group_by(topic, term) |>    
  arrange(desc(beta)) |>  
  ungroup() |>
  ggplot(aes(beta, term, fill = as.factor(topic))) +
  geom_col(show.legend = FALSE) +
  scale_y_reordered() +
  labs(title = "Unit 4:Top 5 LDA Terms",
       x = expression(beta), y = NULL) +
  facet_wrap(~ topic, ncol = 4, scales = "free")

#unit 5
unit5_lda <- LDA(unit5_dtm, 
                 k = 16, 
                 control = list(seed = 2015))
unit5_lda <- tidy(unit5_lda)
unit5_top_lda <- unit5_lda |>
  group_by(topic) |>
  slice_max(beta, n = 5, with_ties = FALSE) |>
  ungroup() |>
  arrange(topic, -beta)
unit5_top_lda |>
  mutate(term = reorder_within(term, beta, topic)) |>
  group_by(topic, term) |>    
  arrange(desc(beta)) |>  
  ungroup() |>
  ggplot(aes(beta, term, fill = as.factor(topic))) +
  geom_col(show.legend = FALSE) +
  scale_y_reordered() +
  labs(title = "Unit 5:Top 5 LDA Terms",
       x = expression(beta), y = NULL) +
  facet_wrap(~ topic, ncol = 4, scales = "free")

#unit 6
unit6_lda <- LDA(unit6_dtm, 
                 k = 18, 
                 control = list(seed = 2015))
unit6_lda <- tidy(unit6_lda)
unit6_top_lda <- unit6_lda |>
  group_by(topic) |>
  slice_max(beta, n = 5, with_ties = FALSE) |>
  ungroup() |>
  arrange(topic, -beta)
unit6_top_lda |>
  mutate(term = reorder_within(term, beta, topic)) |>
  group_by(topic, term) |>    
  arrange(desc(beta)) |>  
  ungroup() |>
  ggplot(aes(beta, term, fill = as.factor(topic))) +
  geom_col(show.legend = FALSE) +
  scale_y_reordered() +
  labs(title = "Unit 6:Top 5 LDA Terms",
       x = expression(beta), y = NULL) +
  facet_wrap(~ topic, ncol = 4, scales = "free")

Sentiment

Sentiment analysis applies a numerical value to each token according to a chosen set or spectrum of sentiments (e.g. positive, negative, fear, anger, etc.), then aggregating these scores. This analysis uses the AFINN library, which assigns negative and positive values from -5 to 5, respectively. The following code is what we used to show how sentiment changed across the six units:

#SENTIMENT
afinn <- get_sentiments("afinn")
summer15_sentiment <- inner_join(summer15_tidy, afinn, by = "word")
summer15_sentiment_summary <- summer15_sentiment |>
  group_by(forum_name) |> 
  summarise(sentiment = sum(value))
summer15_sentiment_summary |>
  ggplot(aes(x = forum_name, y = sentiment)) + 
   geom_col() +
   xlab("Unit Number") +
   ylab("AFINN Sentiment Value") +
  ggtitle("Aggregate Sentiment Value Across All Summer 2015 Units")

Note: All sentiment was net positive for this sample.

LS0tDQp0aXRsZTogIlN1bW1lciAyMDE1IFdvcmQgQ2xvdWQgJiBMREEgQW5hbHlzaXMiDQphdXRob3I6ICJEdW5jYW4gQ3VsYnJldGgiDQpkYXRlOiAiMjAyMi0wNy0yOCINCm91dHB1dDoNCiBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMgUHJlcGFyZQ0KDQojIyBFdmFsdWF0aW9uIFF1ZXN0aW9ucw0KDQpFUTE6IEluIHdoYXQgd2F5cywgYW5kIHRvIHdoYXQgZXh0ZW50LCBoYXMgdGhlIExlYXJuaW5nIERpZmZlcmVuY2VzIHByb2dyYW0gaW1wYWN0ZWQgdGhyZWUgZGlzdGluY3QgcGFydGljaXBhbnQgZ3JvdXBzOiBzdHVkZW50cywgcGFyZW50cywgYW5kIGVkdWNhdG9ycyBvdmVyIHRpbWU/DQoNCkVRMjogV2hhdCBjb21wb25lbnRzIG9mIHRoZSBMZWFybmluZyBEaWZmZXJlbmNlcyBwcm9ncmFtIGFyZSBtb3N0IGVmZmljYWNpb3VzIG92ZXIgdGltZT8NCg0KIyMgSW5zdGFsbCBhbmQgTG9hZCBQYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5dGV4dCkNCmxpYnJhcnkodGV4dGRhdGEpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkod29yZGNsb3VkMikNCmxpYnJhcnkoU25vd2JhbGxDKQ0KbGlicmFyeSh0b3BpY21vZGVscykNCmxpYnJhcnkoc3RtKQ0KbGlicmFyeShsZGF0dW5pbmcpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShMREF2aXMpDQpgYGANCg0KIyMgSW1wb3J0IERhdGENCg0KRGF0YSB3YXMgaW1wb3J0ZWQgZnJvbSB0aCBlIGBvYWtjb3Vyc2VzLmNzdmAgc291cmNlIGZpbGUgYW5kIHNlbGVjdGVkIGZvciB0aGUgdW5pdCBudW1iZXIsIHBvc3QgY29udGVudCBhbmQgcG9zdGVyLg0KDQpgYGB7cn0NCnJhd19zdW1tZXIxNSA8LSByZWFkLmNzdigiZGF0YS9vYWtjb3Vyc2VzX2ZvcnVtcG9zdHMuY3N2IikgfD4NCiAgZmlsdGVyKGNvdXJzZV9pZCA9PSA4KSB8Pg0KICBzZWxlY3QoIWModXNlcl9lbWFpbCx1c2VybmFtZSwgdXNlcl9maXJzdG5hbWUsIHVzZXJfbGFzdG5hbWUsIGNvdXJzZV9zaG9ydG5hbWUsIGNvdXJzZV9pZCwgY291cnNlX25hbWUsIHVuaXRfbmFtZSkpDQpgYGANCg0KIyBXcmFuZ2xlDQoNCiMjIFNhbXBsZSBEYXRhDQoNCjUwIGVudHJpZXMgd2VyZSByYW5kb21seSBzZWxlY3RlZCBmcm9tIGVhY2ggdW5pdCwgdGhlbiBzdGl0Y2hlZCBiYWNrIHRvZ2V0aGVyIGludG8gYSBzaW5nbGUgZG9jdW1lbnQuIFRoaXMgd2FzIGV4cG9ydGVkIGFzIGEgLmNzdiB0byBEaW9uIGZvciBoaXMgYW5hbHlzaXMuDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMjAxNSkNCiNVbml0IDENCnVuaXQxIDwtIHJhd19zdW1tZXIxNSB8Pg0KICBmaWx0ZXIoZm9ydW1faWQgPT0gMTAyKSB8Pg0KICBzYW1wbGVfbig1MCkNCiNVbml0IDINCnVuaXQyIDwtIHJhd19zdW1tZXIxNSB8Pg0KICBmaWx0ZXIoZm9ydW1faWQgPT0gMTA0KSB8Pg0KICBzYW1wbGVfbig1MCkNCiNVbml0IDMNCnVuaXQzIDwtIHJhd19zdW1tZXIxNSB8Pg0KICBmaWx0ZXIoZm9ydW1faWQgPT0gMTA4KSB8Pg0KICBzYW1wbGVfbig1MCkNCiNVbml0IDQNCnVuaXQ0IDwtIHJhd19zdW1tZXIxNSB8Pg0KICBmaWx0ZXIoZm9ydW1faWQgPT0gMTE0KSB8Pg0KICBzYW1wbGVfbig1MCkNCiNVbml0IDUNCnVuaXQ1IDwtIHJhd19zdW1tZXIxNSB8Pg0KICBmaWx0ZXIoZm9ydW1faWQgPT0gMTE2KSB8Pg0KICBzYW1wbGVfbig1MCkNCiNVbml0IDYNCnVuaXQ2IDwtIHJhd19zdW1tZXIxNSB8Pg0KICBmaWx0ZXIoZm9ydW1faWQgPT0gMTMyKSB8Pg0KICBzYW1wbGVfbig1MCkNCiNyZWNvbWJpbmUgaW50byBzaW5nbGUgZGF0YWZyYW1lDQpzdW1tZXIxNV9zYW1wbGUgPC0gcmJpbmQodW5pdDEsIHVuaXQyLCB1bml0MywgdW5pdDQsIHVuaXQ1LCB1bml0NikNCnJtKHVuaXQxLCB1bml0MiwgdW5pdDMsIHVuaXQ0LCB1bml0NSwgdW5pdDYpDQpgYGANCg0KIyMgVGlkeSBUZXh0DQoNClRvIHByZXBhcmUgdGhlIHRleHQgZm9yIHRva2VuaXppbmcsIEhUTUwgdGFncyB3ZXJlIGZpcnN0IHN0cmlwcGVkIGZyb20gdGhlc2Ugc2FtcGxlcy4gVGhlbiB0aGUgdGV4dCB3YXMgdG9rZW5pemVkLCBmaWx0ZXJlZCBmb3Igc3RvcCB3b3JkcywgdGhlbiByZWxhYmVsZWQgdG8gaW5jbHVkZSBhIHRpdGxlIGZvciBlYWNoIHVuaXQgKHJhdGhlciB0aGFuIHRoZSBjb2RlIG51bWJlcikuDQoNCmBgYHtyfQ0KI3N0cmlwIEhUTUwgdGFncw0Kc3VtbWVyMTVfc2FtcGxlJHBvc3RfY29udGVudCA8LSBnc3ViKCI8W14+XSs+IiwiIiwgc3VtbWVyMTVfc2FtcGxlJHBvc3RfY29udGVudCkNCiN0b2tlbml6ZSAmIHN0b3ANCnN1bW1lcjE1X3RpZHkgPC0gc3VtbWVyMTVfc2FtcGxlIHw+DQogIHNlbGVjdChwb3N0X2NvbnRlbnQsIHBvc3RfaWQsIGZvcnVtX25hbWUpIHw+DQogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgDQogICAgICAgICAgICAgICAgaW5wdXQgPSBwb3N0X2NvbnRlbnQpIHw+DQogIGFudGlfam9pbihzdG9wX3dvcmRzLCBieSA9ICJ3b3JkIikgfD4NCiAgc2VsZWN0KGZvcnVtX25hbWUsIHBvc3RfaWQsIHdvcmQpDQojY3VzdG9tIHN0b3BzDQpzdW1tZXIxNV90b3BfbiA8LSBzdW1tZXIxNV90aWR5IHw+DQogIHNlbGVjdCh3b3JkKSB8Pg0KICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkNCmN1c3RvbV9zdG9wcyA8LSBkYXRhLmZyYW1lKHdvcmQgPSBjKCJ0ZWFjaGVyIiwidGVhY2hlcnMiLCJzdHVkZW50Iiwic3R1ZGVudHMiLCJtb2xseSIsIm1vbGx5J3MiLCJ0cmF2aXMiLCJ0cmF2aXMncyIsInRyYXZpcyciLCJtYXR0IiwibWF0dCdzIiwid3lhdHQiLCJ3eWF0dCdzIiwibmJzcCIpKQ0Kc3VtbWVyMTVfdGlkeSA8LSBhbnRpX2pvaW4oc3VtbWVyMTVfdGlkeSwgY3VzdG9tX3N0b3BzLCBieSA9ICJ3b3JkIikNCiNyZWxhYmVsIGJ5IHVuaXQgbmFtZQ0Kc3VtbWVyMTVfdGlkeSA8LSBzdW1tZXIxNV90aWR5IHw+IA0KICBtdXRhdGUoZm9ydW1fbmFtZSA9IHN0cl9yZXBsYWNlKGZvcnVtX25hbWUsICJEaXNjdXNzOiBUaGUgTXl0aCBvZiBBdmVyYWdlIiwgIlVuaXQgMSIpKSB8Pg0KICBtdXRhdGUoZm9ydW1fbmFtZSA9IHN0cl9yZXBsYWNlKGZvcnVtX25hbWUsICJEaXNjdXNzOiBNb2xseSdzIFN0b3J5IiwgIlVuaXQgMiIpKSB8Pg0KICBtdXRhdGUoZm9ydW1fbmFtZSA9IHN0cl9yZXBsYWNlKGZvcnVtX25hbWUsICJEaXNjdXNzOiBNYXR0J3MgU3RvcnkiLCAiVW5pdCAzIikpIHw+DQogIG11dGF0ZShmb3J1bV9uYW1lID0gc3RyX3JlcGxhY2UoZm9ydW1fbmFtZSwgIkRpc2N1c3M6IFRyYXZpcydzIFN0b3J5IiwgIlVuaXQgNCIpKSB8Pg0KICBtdXRhdGUoZm9ydW1fbmFtZSA9IHN0cl9yZXBsYWNlKGZvcnVtX25hbWUsICJEaXNjdXNzOiBGcm9tIFlvdXIgU3R1ZGVudCdzIEV5ZXMiLCAiVW5pdCA1IikpIHw+DQogIG11dGF0ZShmb3J1bV9uYW1lID0gc3RyX3JlcGxhY2UoZm9ydW1fbmFtZSwgIkRpc2N1c3M6IFd5YXR0J3MgU3RvcnkiLCAiVW5pdCA2IikpDQpgYGANCg0KIyBWaXN1YWxpemUNCg0KIyMgV29yZCBDbG91ZHMNCg0KV29yZCBjbG91ZHMgY2FuIGJlIGNvbmR1Y3RlZCBmb3IgaW5kaXZpZHVhbCB1bml0cyBvciBmb3IgdGhlIGVudGlyZSBjb3Vyc2UuIFRoZSBmdW5jdGlvbiBgZmlsdGVyKGZvcnVtX25hbWUgPT0gIlVuaXQgWCIpYCBjYW4gYmUgdXNlZCB0byBmb2N1cyBvbiBhIHNwZWNpZmljIHVuaXQuDQoNCmBgYHtyfQ0KI2VudGlyZSBjb3Vyc2UNCnN1bW1lcjE1Y2xvdWQgPC0gc3VtbWVyMTVfdGlkeSB8Pg0KICBzZWxlY3Qod29yZCkgfD4NCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpIHw+DQogIHNsaWNlKDE6NTApDQp3b3JkY2xvdWQyKHN1bW1lcjE1Y2xvdWQpDQpgYGANCg0KIyMgTERBDQoNCkEgTGF0ZW50LURpcmljaGxldCBBbGxvY2F0aW9uIGFuYWx5c2lzIHJldmVhbGVkIHRoZSBmb2xsb3dpbmcgdGVybXMgZ3JvdXBlZCBieSBjYXRlZ29yeSwgYWdhaW4gZm9yIHRoZSBlbnRpcmUgY291cnNlIGFzIHdlbGwgYXMgYnkgdW5pdC4gRmlyc3QsIHdlIGNhc3QgZWFjaCBzYW1wbGUgaW50byBhIGRvY3VtZW50IHRlcm0gbWF0cml4IGFuZCB1c2VkIGBGaW5kVG9waWNzTnVtYmVyYCB0byBpZGVudGlmeSAqaywqIHRoZSBtb3N0IGNvaGVyZW50IG51bWJlciBvZiB0b3BpY3MgdG8gcmVxdWVzdCB0aGUgTERBIGFsZ29yaXRobSB0byBwcm9kdWNlOg0KDQpgYGB7cn0NCiNlbnRpcmUgY291cnNlDQpzdW1tZXIxNV9kdG0gPC0gc3VtbWVyMTVfdGlkeSB8Pg0KICBjb3VudChwb3N0X2lkLCB3b3JkKSB8Pg0KICBjYXN0X2R0bShwb3N0X2lkLCB3b3JkLCBuKQ0Ka19tZXRyaWNzIDwtIEZpbmRUb3BpY3NOdW1iZXIoDQogIHN1bW1lcjE1X2R0bSwNCiAgdG9waWNzID0gc2VxKDUsIDIwLCBieSA9IDEpLA0KICBtZXRyaWNzID0gIkdyaWZmaXRoczIwMDQiLA0KICBtZXRob2QgPSAiR2liYnMiLA0KICBjb250cm9sID0gbGlzdCgpLA0KICBtYy5jb3JlcyA9IE5BLA0KICByZXR1cm5fbW9kZWxzID0gRkFMU0UsDQogIHZlcmJvc2UgPSBGQUxTRSwNCiAgbGlicGF0aCA9IE5VTEwpDQpGaW5kVG9waWNzTnVtYmVyX3Bsb3Qoa19tZXRyaWNzKQ0KI3VuaXQgMQ0KdW5pdDFfZHRtIDwtIHN1bW1lcjE1X3RpZHkgfD4NCiAgZmlsdGVyKGZvcnVtX25hbWUgPT0gIlVuaXQgMSIpIHw+DQogIGNvdW50KHBvc3RfaWQsIHdvcmQpIHw+DQogIGNhc3RfZHRtKHBvc3RfaWQsIHdvcmQsIG4pDQprX21ldHJpY3MgPC0gRmluZFRvcGljc051bWJlcigNCiAgdW5pdDFfZHRtLA0KICB0b3BpY3MgPSBzZXEoNSwgMjAsIGJ5ID0gMSksDQogIG1ldHJpY3MgPSAiR3JpZmZpdGhzMjAwNCIsDQogIG1ldGhvZCA9ICJHaWJicyIsDQogIGNvbnRyb2wgPSBsaXN0KCksDQogIG1jLmNvcmVzID0gTkEsDQogIHJldHVybl9tb2RlbHMgPSBGQUxTRSwNCiAgdmVyYm9zZSA9IEZBTFNFLA0KICBsaWJwYXRoID0gTlVMTCkNCkZpbmRUb3BpY3NOdW1iZXJfcGxvdChrX21ldHJpY3MpDQojdW5pdCAyDQp1bml0Ml9kdG0gPC0gc3VtbWVyMTVfdGlkeSB8Pg0KICBmaWx0ZXIoZm9ydW1fbmFtZSA9PSAiVW5pdCAyIikgfD4NCiAgY291bnQocG9zdF9pZCwgd29yZCkgfD4NCiAgY2FzdF9kdG0ocG9zdF9pZCwgd29yZCwgbikNCmtfbWV0cmljcyA8LSBGaW5kVG9waWNzTnVtYmVyKA0KICB1bml0Ml9kdG0sDQogIHRvcGljcyA9IHNlcSg1LCAyMCwgYnkgPSAxKSwNCiAgbWV0cmljcyA9ICJHcmlmZml0aHMyMDA0IiwNCiAgbWV0aG9kID0gIkdpYmJzIiwNCiAgY29udHJvbCA9IGxpc3QoKSwNCiAgbWMuY29yZXMgPSBOQSwNCiAgcmV0dXJuX21vZGVscyA9IEZBTFNFLA0KICB2ZXJib3NlID0gRkFMU0UsDQogIGxpYnBhdGggPSBOVUxMKQ0KRmluZFRvcGljc051bWJlcl9wbG90KGtfbWV0cmljcykNCiN1bml0IDMNCnVuaXQzX2R0bSA8LSBzdW1tZXIxNV90aWR5IHw+DQogIGZpbHRlcihmb3J1bV9uYW1lID09ICJVbml0IDMiKSB8Pg0KICBjb3VudChwb3N0X2lkLCB3b3JkKSB8Pg0KICBjYXN0X2R0bShwb3N0X2lkLCB3b3JkLCBuKQ0Ka19tZXRyaWNzIDwtIEZpbmRUb3BpY3NOdW1iZXIoDQogIHVuaXQzX2R0bSwNCiAgdG9waWNzID0gc2VxKDUsIDIwLCBieSA9IDEpLA0KICBtZXRyaWNzID0gIkdyaWZmaXRoczIwMDQiLA0KICBtZXRob2QgPSAiR2liYnMiLA0KICBjb250cm9sID0gbGlzdCgpLA0KICBtYy5jb3JlcyA9IE5BLA0KICByZXR1cm5fbW9kZWxzID0gRkFMU0UsDQogIHZlcmJvc2UgPSBGQUxTRSwNCiAgbGlicGF0aCA9IE5VTEwpDQpGaW5kVG9waWNzTnVtYmVyX3Bsb3Qoa19tZXRyaWNzKQ0KI3VuaXQgNA0KdW5pdDRfZHRtIDwtIHN1bW1lcjE1X3RpZHkgfD4NCiAgZmlsdGVyKGZvcnVtX25hbWUgPT0gIlVuaXQgNCIpIHw+DQogIGNvdW50KHBvc3RfaWQsIHdvcmQpIHw+DQogIGNhc3RfZHRtKHBvc3RfaWQsIHdvcmQsIG4pDQprX21ldHJpY3MgPC0gRmluZFRvcGljc051bWJlcigNCiAgdW5pdDRfZHRtLA0KICB0b3BpY3MgPSBzZXEoNSwgMjAsIGJ5ID0gMSksDQogIG1ldHJpY3MgPSAiR3JpZmZpdGhzMjAwNCIsDQogIG1ldGhvZCA9ICJHaWJicyIsDQogIGNvbnRyb2wgPSBsaXN0KCksDQogIG1jLmNvcmVzID0gTkEsDQogIHJldHVybl9tb2RlbHMgPSBGQUxTRSwNCiAgdmVyYm9zZSA9IEZBTFNFLA0KICBsaWJwYXRoID0gTlVMTCkNCkZpbmRUb3BpY3NOdW1iZXJfcGxvdChrX21ldHJpY3MpDQojdW5pdCA1DQp1bml0NV9kdG0gPC0gc3VtbWVyMTVfdGlkeSB8Pg0KICBmaWx0ZXIoZm9ydW1fbmFtZSA9PSAiVW5pdCA1IikgfD4NCiAgY291bnQocG9zdF9pZCwgd29yZCkgfD4NCiAgY2FzdF9kdG0ocG9zdF9pZCwgd29yZCwgbikNCmtfbWV0cmljcyA8LSBGaW5kVG9waWNzTnVtYmVyKA0KICB1bml0NV9kdG0sDQogIHRvcGljcyA9IHNlcSg1LCAyMCwgYnkgPSAxKSwNCiAgbWV0cmljcyA9ICJHcmlmZml0aHMyMDA0IiwNCiAgbWV0aG9kID0gIkdpYmJzIiwNCiAgY29udHJvbCA9IGxpc3QoKSwNCiAgbWMuY29yZXMgPSBOQSwNCiAgcmV0dXJuX21vZGVscyA9IEZBTFNFLA0KICB2ZXJib3NlID0gRkFMU0UsDQogIGxpYnBhdGggPSBOVUxMKQ0KRmluZFRvcGljc051bWJlcl9wbG90KGtfbWV0cmljcykNCiN1bml0IDYNCnVuaXQ2X2R0bSA8LSBzdW1tZXIxNV90aWR5IHw+DQogIGZpbHRlcihmb3J1bV9uYW1lID09ICJVbml0IDYiKSB8Pg0KICBjb3VudChwb3N0X2lkLCB3b3JkKSB8Pg0KICBjYXN0X2R0bShwb3N0X2lkLCB3b3JkLCBuKQ0Ka19tZXRyaWNzIDwtIEZpbmRUb3BpY3NOdW1iZXIoDQogIHVuaXQ2X2R0bSwNCiAgdG9waWNzID0gc2VxKDUsIDIwLCBieSA9IDEpLA0KICBtZXRyaWNzID0gIkdyaWZmaXRoczIwMDQiLA0KICBtZXRob2QgPSAiR2liYnMiLA0KICBjb250cm9sID0gbGlzdCgpLA0KICBtYy5jb3JlcyA9IE5BLA0KICByZXR1cm5fbW9kZWxzID0gRkFMU0UsDQogIHZlcmJvc2UgPSBGQUxTRSwNCiAgbGlicGF0aCA9IE5VTEwpDQpGaW5kVG9waWNzTnVtYmVyX3Bsb3Qoa19tZXRyaWNzKQ0KYGBgDQoNCkhhdmluZyBpZGVudGlmaWVkIHRoZSB2YXJpYWJsZSAqayogdGhhdCBpcyBtb3N0IGNvaGVyZW50IChoaWdoZXN0IG9uIHRoZSAqeSogYXhpcykgZm9yIGVhY2ggdW5pdCdzIHNhbXBsZSwgd2UgdGhlbiBhcHBsaWVkIGFuIExEQSB0byBlYWNoIHVuaXQgYW5kIHBsb3R0ZWQgdGhlIHJlc3VsdGluZyB0ZXJtcyB0byBhIGZhY2V0ZWQgYmFyIGNoYXJ0Og0KDQpgYGB7cn0NCiNMREENCiNlbnRpcmUgY291cnNlDQpzdW1tZXIxNV9sZGEgPC0gTERBKHN1bW1lcjE1X2R0bSwgDQogICAgICAgICAgICAgICAgIGsgPSAxNSwgDQogICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KHNlZWQgPSAyMDE1KSkNCnN1bW1lcjE1X2xkYSA8LSB0aWR5KHN1bW1lcjE1X2xkYSkNCnN1bW1lcjE1X3RvcF9sZGEgPC0gc3VtbWVyMTVfbGRhIHw+DQogIGdyb3VwX2J5KHRvcGljKSB8Pg0KICBzbGljZV9tYXgoYmV0YSwgbiA9IDUsIHdpdGhfdGllcyA9IEZBTFNFKSB8Pg0KICB1bmdyb3VwKCkgfD4NCiAgYXJyYW5nZSh0b3BpYywgLWJldGEpDQpzdW1tZXIxNV90b3BfbGRhIHw+DQogIG11dGF0ZSh0ZXJtID0gcmVvcmRlcl93aXRoaW4odGVybSwgYmV0YSwgdG9waWMpKSB8Pg0KICBncm91cF9ieSh0b3BpYywgdGVybSkgfD4gICAgDQogIGFycmFuZ2UoZGVzYyhiZXRhKSkgfD4gIA0KICB1bmdyb3VwKCkgfD4NCiAgZ2dwbG90KGFlcyhiZXRhLCB0ZXJtLCBmaWxsID0gYXMuZmFjdG9yKHRvcGljKSkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBzY2FsZV95X3Jlb3JkZXJlZCgpICsNCiAgbGFicyh0aXRsZSA9ICJTdW1tZXIgMjAxNTogVG9wIDUgTERBIFRlcm1zIiwNCiAgICAgICB4ID0gZXhwcmVzc2lvbihiZXRhKSwgeSA9IE5VTEwpICsNCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBuY29sID0gNCwgc2NhbGVzID0gImZyZWUiKQ0KI3VuaXQgMQ0KdW5pdDFfbGRhIDwtIExEQSh1bml0MV9kdG0sIA0KICAgICAgICAgICAgICAgICBrID0gMTQsIA0KICAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChzZWVkID0gMjAxNSkpDQp1bml0MV9sZGEgPC0gdGlkeSh1bml0MV9sZGEpDQp1bml0MV90b3BfbGRhIDwtIHVuaXQxX2xkYSB8Pg0KICBncm91cF9ieSh0b3BpYykgfD4NCiAgc2xpY2VfbWF4KGJldGEsIG4gPSA1LCB3aXRoX3RpZXMgPSBGQUxTRSkgfD4NCiAgdW5ncm91cCgpIHw+DQogIGFycmFuZ2UodG9waWMsIC1iZXRhKQ0KdW5pdDFfdG9wX2xkYSB8Pg0KICBtdXRhdGUodGVybSA9IHJlb3JkZXJfd2l0aGluKHRlcm0sIGJldGEsIHRvcGljKSkgfD4NCiAgZ3JvdXBfYnkodG9waWMsIHRlcm0pIHw+ICAgIA0KICBhcnJhbmdlKGRlc2MoYmV0YSkpIHw+ICANCiAgdW5ncm91cCgpIHw+DQogIGdncGxvdChhZXMoYmV0YSwgdGVybSwgZmlsbCA9IGFzLmZhY3Rvcih0b3BpYykpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgc2NhbGVfeV9yZW9yZGVyZWQoKSArDQogIGxhYnModGl0bGUgPSAiVW5pdCAxOlRvcCA1IExEQSBUZXJtcyIsDQogICAgICAgeCA9IGV4cHJlc3Npb24oYmV0YSksIHkgPSBOVUxMKSArDQogIGZhY2V0X3dyYXAofiB0b3BpYywgbmNvbCA9IDQsIHNjYWxlcyA9ICJmcmVlIikNCiN1bml0IDINCnVuaXQyX2xkYSA8LSBMREEodW5pdDJfZHRtLCANCiAgICAgICAgICAgICAgICAgICAgIGsgPSAxOCwgDQogICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChzZWVkID0gMjAxNSkpDQp1bml0Ml9sZGEgPC0gdGlkeSh1bml0Ml9sZGEpDQp1bml0Ml90b3BfbGRhIDwtIHVuaXQyX2xkYSB8Pg0KICBncm91cF9ieSh0b3BpYykgfD4NCiAgc2xpY2VfbWF4KGJldGEsIG4gPSA1LCB3aXRoX3RpZXMgPSBGQUxTRSkgfD4NCiAgdW5ncm91cCgpIHw+DQogIGFycmFuZ2UodG9waWMsIC1iZXRhKQ0KdW5pdDJfdG9wX2xkYSB8Pg0KICBtdXRhdGUodGVybSA9IHJlb3JkZXJfd2l0aGluKHRlcm0sIGJldGEsIHRvcGljKSkgfD4NCiAgZ3JvdXBfYnkodG9waWMsIHRlcm0pIHw+ICAgIA0KICBhcnJhbmdlKGRlc2MoYmV0YSkpIHw+ICANCiAgdW5ncm91cCgpIHw+DQogIGdncGxvdChhZXMoYmV0YSwgdGVybSwgZmlsbCA9IGFzLmZhY3Rvcih0b3BpYykpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgc2NhbGVfeV9yZW9yZGVyZWQoKSArDQogIGxhYnModGl0bGUgPSAiVW5pdCAyOlRvcCA1IExEQSBUZXJtcyIsDQogICAgICAgeCA9IGV4cHJlc3Npb24oYmV0YSksIHkgPSBOVUxMKSArDQogIGZhY2V0X3dyYXAofiB0b3BpYywgbmNvbCA9IDQsIHNjYWxlcyA9ICJmcmVlIikNCiN1bml0IDMNCnVuaXQzX2xkYSA8LSBMREEodW5pdDNfZHRtLCANCiAgICAgICAgICAgICAgICAgayA9IDE5LCANCiAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3Qoc2VlZCA9IDIwMTUpKQ0KdW5pdDNfbGRhIDwtIHRpZHkodW5pdDNfbGRhKQ0KdW5pdDNfdG9wX2xkYSA8LSB1bml0M19sZGEgfD4NCiAgZ3JvdXBfYnkodG9waWMpIHw+DQogIHNsaWNlX21heChiZXRhLCBuID0gNSwgd2l0aF90aWVzID0gRkFMU0UpIHw+DQogIHVuZ3JvdXAoKSB8Pg0KICBhcnJhbmdlKHRvcGljLCAtYmV0YSkNCnVuaXQzX3RvcF9sZGEgfD4NCiAgbXV0YXRlKHRlcm0gPSByZW9yZGVyX3dpdGhpbih0ZXJtLCBiZXRhLCB0b3BpYykpIHw+DQogIGdyb3VwX2J5KHRvcGljLCB0ZXJtKSB8PiAgICANCiAgYXJyYW5nZShkZXNjKGJldGEpKSB8PiAgDQogIHVuZ3JvdXAoKSB8Pg0KICBnZ3Bsb3QoYWVzKGJldGEsIHRlcm0sIGZpbGwgPSBhcy5mYWN0b3IodG9waWMpKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIHNjYWxlX3lfcmVvcmRlcmVkKCkgKw0KICBsYWJzKHRpdGxlID0gIlVuaXQgMzpUb3AgNSBMREEgVGVybXMiLA0KICAgICAgIHggPSBleHByZXNzaW9uKGJldGEpLCB5ID0gTlVMTCkgKw0KICBmYWNldF93cmFwKH4gdG9waWMsIG5jb2wgPSA0LCBzY2FsZXMgPSAiZnJlZSIpDQojdW5pdCA0DQp1bml0NF9sZGEgPC0gTERBKHVuaXQ0X2R0bSwgDQogICAgICAgICAgICAgICAgIGsgPSAxMiwgDQogICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KHNlZWQgPSAyMDE1KSkNCnVuaXQ0X2xkYSA8LSB0aWR5KHVuaXQ0X2xkYSkNCnVuaXQ0X3RvcF9sZGEgPC0gdW5pdDRfbGRhIHw+DQogIGdyb3VwX2J5KHRvcGljKSB8Pg0KICBzbGljZV9tYXgoYmV0YSwgbiA9IDUsIHdpdGhfdGllcyA9IEZBTFNFKSB8Pg0KICB1bmdyb3VwKCkgfD4NCiAgYXJyYW5nZSh0b3BpYywgLWJldGEpDQp1bml0NF90b3BfbGRhIHw+DQogIG11dGF0ZSh0ZXJtID0gcmVvcmRlcl93aXRoaW4odGVybSwgYmV0YSwgdG9waWMpKSB8Pg0KICBncm91cF9ieSh0b3BpYywgdGVybSkgfD4gICAgDQogIGFycmFuZ2UoZGVzYyhiZXRhKSkgfD4gIA0KICB1bmdyb3VwKCkgfD4NCiAgZ2dwbG90KGFlcyhiZXRhLCB0ZXJtLCBmaWxsID0gYXMuZmFjdG9yKHRvcGljKSkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBzY2FsZV95X3Jlb3JkZXJlZCgpICsNCiAgbGFicyh0aXRsZSA9ICJVbml0IDQ6VG9wIDUgTERBIFRlcm1zIiwNCiAgICAgICB4ID0gZXhwcmVzc2lvbihiZXRhKSwgeSA9IE5VTEwpICsNCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBuY29sID0gNCwgc2NhbGVzID0gImZyZWUiKQ0KI3VuaXQgNQ0KdW5pdDVfbGRhIDwtIExEQSh1bml0NV9kdG0sIA0KICAgICAgICAgICAgICAgICBrID0gMTYsIA0KICAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChzZWVkID0gMjAxNSkpDQp1bml0NV9sZGEgPC0gdGlkeSh1bml0NV9sZGEpDQp1bml0NV90b3BfbGRhIDwtIHVuaXQ1X2xkYSB8Pg0KICBncm91cF9ieSh0b3BpYykgfD4NCiAgc2xpY2VfbWF4KGJldGEsIG4gPSA1LCB3aXRoX3RpZXMgPSBGQUxTRSkgfD4NCiAgdW5ncm91cCgpIHw+DQogIGFycmFuZ2UodG9waWMsIC1iZXRhKQ0KdW5pdDVfdG9wX2xkYSB8Pg0KICBtdXRhdGUodGVybSA9IHJlb3JkZXJfd2l0aGluKHRlcm0sIGJldGEsIHRvcGljKSkgfD4NCiAgZ3JvdXBfYnkodG9waWMsIHRlcm0pIHw+ICAgIA0KICBhcnJhbmdlKGRlc2MoYmV0YSkpIHw+ICANCiAgdW5ncm91cCgpIHw+DQogIGdncGxvdChhZXMoYmV0YSwgdGVybSwgZmlsbCA9IGFzLmZhY3Rvcih0b3BpYykpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgc2NhbGVfeV9yZW9yZGVyZWQoKSArDQogIGxhYnModGl0bGUgPSAiVW5pdCA1OlRvcCA1IExEQSBUZXJtcyIsDQogICAgICAgeCA9IGV4cHJlc3Npb24oYmV0YSksIHkgPSBOVUxMKSArDQogIGZhY2V0X3dyYXAofiB0b3BpYywgbmNvbCA9IDQsIHNjYWxlcyA9ICJmcmVlIikNCiN1bml0IDYNCnVuaXQ2X2xkYSA8LSBMREEodW5pdDZfZHRtLCANCiAgICAgICAgICAgICAgICAgayA9IDE4LCANCiAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3Qoc2VlZCA9IDIwMTUpKQ0KdW5pdDZfbGRhIDwtIHRpZHkodW5pdDZfbGRhKQ0KdW5pdDZfdG9wX2xkYSA8LSB1bml0Nl9sZGEgfD4NCiAgZ3JvdXBfYnkodG9waWMpIHw+DQogIHNsaWNlX21heChiZXRhLCBuID0gNSwgd2l0aF90aWVzID0gRkFMU0UpIHw+DQogIHVuZ3JvdXAoKSB8Pg0KICBhcnJhbmdlKHRvcGljLCAtYmV0YSkNCnVuaXQ2X3RvcF9sZGEgfD4NCiAgbXV0YXRlKHRlcm0gPSByZW9yZGVyX3dpdGhpbih0ZXJtLCBiZXRhLCB0b3BpYykpIHw+DQogIGdyb3VwX2J5KHRvcGljLCB0ZXJtKSB8PiAgICANCiAgYXJyYW5nZShkZXNjKGJldGEpKSB8PiAgDQogIHVuZ3JvdXAoKSB8Pg0KICBnZ3Bsb3QoYWVzKGJldGEsIHRlcm0sIGZpbGwgPSBhcy5mYWN0b3IodG9waWMpKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIHNjYWxlX3lfcmVvcmRlcmVkKCkgKw0KICBsYWJzKHRpdGxlID0gIlVuaXQgNjpUb3AgNSBMREEgVGVybXMiLA0KICAgICAgIHggPSBleHByZXNzaW9uKGJldGEpLCB5ID0gTlVMTCkgKw0KICBmYWNldF93cmFwKH4gdG9waWMsIG5jb2wgPSA0LCBzY2FsZXMgPSAiZnJlZSIpDQpgYGANCg0KIyMgU2VudGltZW50DQoNClNlbnRpbWVudCBhbmFseXNpcyBhcHBsaWVzIGEgbnVtZXJpY2FsIHZhbHVlIHRvIGVhY2ggdG9rZW4gYWNjb3JkaW5nIHRvIGEgY2hvc2VuIHNldCBvciBzcGVjdHJ1bSBvZiBzZW50aW1lbnRzIChlLmcuIHBvc2l0aXZlLCBuZWdhdGl2ZSwgZmVhciwgYW5nZXIsIGV0Yy4pLCB0aGVuIGFnZ3JlZ2F0aW5nIHRoZXNlIHNjb3Jlcy4gVGhpcyBhbmFseXNpcyB1c2VzIHRoZSBBRklOTiBsaWJyYXJ5LCB3aGljaCBhc3NpZ25zIG5lZ2F0aXZlIGFuZCBwb3NpdGl2ZSB2YWx1ZXMgZnJvbSAtNSB0byA1LCByZXNwZWN0aXZlbHkuIFRoZSBmb2xsb3dpbmcgY29kZSBpcyB3aGF0IHdlIHVzZWQgdG8gc2hvdyBob3cgc2VudGltZW50IGNoYW5nZWQgYWNyb3NzIHRoZSBzaXggdW5pdHM6DQoNCmBgYHtyfQ0KI1NFTlRJTUVOVA0KYWZpbm4gPC0gZ2V0X3NlbnRpbWVudHMoImFmaW5uIikNCnN1bW1lcjE1X3NlbnRpbWVudCA8LSBpbm5lcl9qb2luKHN1bW1lcjE1X3RpZHksIGFmaW5uLCBieSA9ICJ3b3JkIikNCnN1bW1lcjE1X3NlbnRpbWVudF9zdW1tYXJ5IDwtIHN1bW1lcjE1X3NlbnRpbWVudCB8Pg0KICBncm91cF9ieShmb3J1bV9uYW1lKSB8PiANCiAgc3VtbWFyaXNlKHNlbnRpbWVudCA9IHN1bSh2YWx1ZSkpDQpzdW1tZXIxNV9zZW50aW1lbnRfc3VtbWFyeSB8Pg0KICBnZ3Bsb3QoYWVzKHggPSBmb3J1bV9uYW1lLCB5ID0gc2VudGltZW50KSkgKyANCiAgIGdlb21fY29sKCkgKw0KICAgeGxhYigiVW5pdCBOdW1iZXIiKSArDQogICB5bGFiKCJBRklOTiBTZW50aW1lbnQgVmFsdWUiKSArDQogIGdndGl0bGUoIkFnZ3JlZ2F0ZSBTZW50aW1lbnQgVmFsdWUgQWNyb3NzIEFsbCBTdW1tZXIgMjAxNSBVbml0cyIpDQpgYGANCg0KKk5vdGU6IEFsbCBzZW50aW1lbnQgd2FzIG5ldCBwb3NpdGl2ZSBmb3IgdGhpcyBzYW1wbGUuKg0K